[
  {
    "path": ".formatter.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n[\n  inputs: [\n    \"lib/*/{lib,scripts,unicode,test}/**/*.{ex,exs}\",\n    \"lib/*/*.exs\",\n    \"lib/ex_unit/examples/*.exs\",\n    \".formatter.exs\"\n  ],\n  locals_without_parens: [\n    # Formatter tests\n    assert_format: 2,\n    assert_format: 3,\n    assert_same: 1,\n    assert_same: 2,\n\n    # Errors tests\n    assert_eval_raise: 3,\n\n    # Float tests\n    float_assert: 1\n  ]\n]\n"
  },
  {
    "path": ".gitattributes",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nlib/elixir/test/elixir/fixtures/*.txt text eol=lf\n*.ex diff=elixir\n*.exs diff=elixir\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\n---\nblank_issues_enabled: true\n\ncontact_links:\n  - name: Ask questions, support, and general discussions\n    url: https://elixirforum.com/\n    about: Ask questions, provide support, and more on Elixir Forum\n\n  - name: Propose new features\n    url: https://github.com/elixir-lang/elixir/#proposing-new-features\n    about: Propose new features in our mailing list\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\n---\nname: Report an issue\ndescription:\n  Tell us about something that is not working the way we (probably) intend\nbody:\n  - type: markdown\n    attributes:\n      value: >\n        Thank you for contributing to Elixir! :heart:\n\n\n        Please, do not use this form for guidance, questions or support.\n        Try instead in [Elixir Forum](https://elixirforum.com),\n        the [IRC Chat](https://web.libera.chat/#elixir),\n        [Stack Overflow](https://stackoverflow.com/questions/tagged/elixir),\n        [Slack](https://elixir-slackin.herokuapp.com),\n        [Discord](https://discord.gg/elixir) or in other online communities.\n\n  - type: textarea\n    id: elixir-and-otp-version\n    attributes:\n      label: Elixir and Erlang/OTP versions\n      description: Paste the output of `elixir --version` here.\n    validations:\n      required: true\n\n  - type: input\n    id: os\n    attributes:\n      label: Operating system\n      description: The operating system that this issue is happening on.\n    validations:\n      required: true\n\n  - type: textarea\n    id: current-behavior\n    attributes:\n      label: Current behavior\n      description: >\n        Include code samples, errors, and stacktraces if appropriate.\n\n\n        If reporting a bug, please include the reproducing steps.\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected-behavior\n    attributes:\n      label: Expected behavior\n      description: A short description on how you expect the code to behave.\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nversion: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    cooldown:\n      default-days: 7\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nname: CI\n\non:\n  push:\n  pull_request:\n  workflow_dispatch:\n\nenv:\n  ELIXIR_ASSERT_TIMEOUT: 2000\n  ELIXIRC_OPTS: \"--warnings-as-errors\"\n  LANG: C.UTF-8\n\npermissions:\n  contents: read\n\njobs:\n  test_linux:\n    name: Ubuntu 24.04, OTP ${{ matrix.otp_version }}${{ matrix.deterministic && ' (deterministic)' || '' }}${{ matrix.coverage && ' (coverage)' || '' }}\n    runs-on: ubuntu-24.04\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - otp_version: \"29.0-rc1\"\n          - otp_version: \"28.1\"\n            deterministic: true\n          - otp_version: \"28.1\"\n            docs: true\n            coverage: true\n          - otp_version: \"27.3\"\n          - otp_version: \"27.0\"\n          - otp_version: master\n            development: true\n          - otp_version: maint\n            development: true\n\n    env:\n      ERLC_OPTS: \"warnings_as_errors\"\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - uses: erlef/setup-beam@e6d7c94229049569db56a7ad5a540c051a010af9 # v1.20.4\n        with:\n          otp-version: ${{ matrix.otp_version }}\n\n      - name: Set ERL_COMPILER_OPTIONS\n        if: ${{ matrix.deterministic }}\n        run: echo \"ERL_COMPILER_OPTIONS=deterministic\" >> $GITHUB_ENV\n\n      - name: Compile Elixir\n        run: |\n          make compile\n          echo \"$PWD/bin\" >> $GITHUB_PATH\n\n      - name: Build info\n        run: bin/elixir --version\n\n      - name: Check format\n        run: make test_formatted && echo \"All Elixir source code files are properly formatted.\"\n\n      - name: Erlang test suite\n        run: make test_erlang\n        continue-on-error: ${{ matrix.development == true }}\n\n      - name: Elixir test suite\n        run: make test_elixir\n        continue-on-error: ${{ matrix.development == true }}\n        env:\n          COVER: \"${{ matrix.coverage }}\"\n\n      - name: Build docs (ExDoc main)\n        if: ${{ matrix.docs }}\n        run: |\n          cd ..\n          git clone https://github.com/elixir-lang/ex_doc.git --depth 1\n          cd ex_doc\n          ../elixir/bin/mix do local.rebar --force + local.hex --force + deps.get + compile\n          cd ../elixir/\n          git fetch --tags\n          DOCS_OPTIONS=\"--warnings-as-errors\" make docs\n\n      - name: \"Calculate Coverage\"\n        if: ${{ matrix.coverage }}\n        run: make cover | tee \"$GITHUB_STEP_SUMMARY\"\n\n      - name: \"Upload Coverage Artifact\"\n        if: ${{ matrix.coverage }}\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0\n        with:\n          name: TestCoverage\n          path: cover/*\n\n      - name: Check reproducible builds\n        if: ${{ matrix.deterministic }}\n        run: taskset 1 make check_reproducible\n\n      - name: Check git is not required\n        if: ${{ matrix.deterministic }}\n        run: |\n          rm -rf .git\n          cd lib/elixir\n          elixirc --ignore-module-conflict -o ebin \"lib/**/*.ex\"\n\n  test_windows:\n    name: Windows Server 2022, OTP ${{ matrix.otp_version }}\n    runs-on: windows-2022\n\n    strategy:\n      matrix:\n        otp_version:\n          - \"29.0-rc1\"\n          - \"28.1\"\n          - \"27.3\"\n\n    steps:\n      - name: Configure Git\n        run: git config --global core.autocrlf input\n\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - uses: erlef/setup-beam@e6d7c94229049569db56a7ad5a540c051a010af9 # v1.20.4\n        with:\n          otp-version: ${{ matrix.otp_version }}\n\n      - name: Compile Elixir\n        run: |\n          Remove-Item -Recurse -Force '.git'\n          make compile\n\n      - name: Build info\n        run: bin/elixir --version\n\n      - name: Check format\n        run: make test_formatted && echo \"All Elixir source code files are properly formatted.\"\n\n      - name: Erlang test suite\n        run: make test_erlang\n\n      - name: Elixir test suite\n        run: |\n          Remove-Item 'c:/Windows/System32/drivers/etc/hosts'\n          make test_elixir\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2026 The Elixir Team\n\nname: \"CodeQL Advanced\"\n\non:\n  push:\n    branches: [\"main\"]\n  pull_request:\n    branches: [\"main\"]\n  schedule:\n    - cron: \"29 8 * * 1\"\n\npermissions:\n  contents: read\n\njobs:\n  analyze:\n    name: Analyze (${{ matrix.language }})\n    runs-on: \"ubuntu-latest\"\n    permissions:\n      security-events: write\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - language: actions\n            build-mode: none\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4\n        with:\n          languages: ${{ matrix.language }}\n          build-mode: ${{ matrix.build-mode }}\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4\n        with:\n          category: \"/language:${{matrix.language}}\"\n\n  zizmor:\n    name: Zizmor\n    runs-on: ubuntu-latest\n    permissions:\n      security-events: write\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Run zizmor\n        uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0\n"
  },
  {
    "path": ".github/workflows/license_compliance.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nname: License Compliance\n\non:\n  push:\n  pull_request:\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  LANG: C.UTF-8\n\njobs:\n  license_compliance:\n    name: Check License Compliance\n    runs-on: ubuntu-24.04\n\n    steps:\n      - name: Use HTTPS instead of SSH for Git cloning\n        id: git-config\n        shell: bash\n        run: git config --global url.https://github.com/.insteadOf ssh://git@github.com/\n\n      - name: Checkout project\n        id: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Run OSS Review Toolkit\n        id: ort\n        uses: ./.github/workflows/ort\n        with:\n          upload-reports: true\n          fail-on-violation: true\n          report-formats: \"WebApp\"\n          version: \"${{ github.sha }}\"\n"
  },
  {
    "path": ".github/workflows/markdown.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nname: Markdown Content\n\non:\n  push:\n    branches:\n      - \"main\"\n\n    paths: &paths-filter\n      - \"**/*.md\"\n      - .github/workflows/markdown.yml\n      - .markdownlint-cli2.jsonc\n\n  pull_request:\n    paths: *paths-filter\n\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  LANG: C.UTF-8\n\njobs:\n  lint:\n    name: Lint Markdown content\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Run markdownlint-cli2\n        uses: DavidAnson/markdownlint-cli2-action@07035fd053f7be764496c0f8d8f9f41f98305101 # v22.0.0\n"
  },
  {
    "path": ".github/workflows/notify.exs",
    "content": "# #!/usr/bin/env elixir\n\n# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\n[tag] = System.argv()\n\nMix.install([\n  {:req, \"~> 0.2.1\"},\n  {:jason, \"~> 1.0\"}\n])\n\n%{status: 200, body: release} =\n  Req.get!(\"https://api.github.com/repos/elixir-lang/elixir/releases/tags/#{tag}\")\n\nif release[\"draft\"] do\n  raise \"cannot notify a draft release\"\nend\n\n## Notify on elixir-lang-ann\n\nnames_and_checksums =\n  for asset <- release[\"assets\"],\n      name = asset[\"name\"],\n      name =~ ~r/.sha\\d+sum$/,\n      do: {name, Req.get!(asset[\"browser_download_url\"]).body}\n\nline_items =\n  for {name, checksum_and_name} <- Enum.sort(names_and_checksums) do\n    [checksum | _] = String.split(checksum_and_name, \" \")\n    root = Path.rootname(name)\n    \".\" <> type = Path.extname(name)\n    \"  * #{root} - #{type} - #{checksum}\\n\"\n  end\n\nbody = \"https://github.com/elixir-lang/elixir/releases/tag/#{tag}\\n\\n#{line_items}\"\n\nIO.puts([\n  \"========================================\\n\",\n  body,\n  \"\\n========================================\"\n])\n\nmail = %{\n  # The email must have access to post\n  \"From\" => \"jose.valim@dashbit.co\",\n  \"To\" => \"elixir-lang-ann@googlegroups.com\",\n  \"Subject\" => \"Elixir #{tag} released\",\n  \"HtmlBody\" => body,\n  \"MessageStream\" => \"outbound\"\n}\n\nunless System.get_env(\"DRYRUN\") do\n  headers = %{\n    \"X-Postmark-Server-Token\" => System.fetch_env!(\"ELIXIR_LANG_ANN_TOKEN\")\n  }\n\n  resp = Req.post!(\"https://api.postmarkapp.com/email\", {:json, mail}, headers: headers)\n  IO.puts(\"#{resp.status} elixir-lang-ann\\n#{inspect(resp.body)}\")\nend\n\n## Notify on Elixir Forum\n\npost = %{\n  \"title\" => \"Elixir #{tag} released\",\n  \"raw\" => \"https://github.com/elixir-lang/elixir/releases/tag/#{tag}\\n\\n#{release[\"body\"]}\",\n  # Elixir News\n  \"category\" => 28\n}\n\nunless System.get_env(\"DRYRUN\") do\n  headers = %{\n    \"api-key\" => System.fetch_env!(\"ELIXIR_FORUM_TOKEN\"),\n    \"api-username\" => \"Elixir\"\n  }\n\n  resp = Req.post!(\"https://elixirforum.com/posts.json\", {:json, post}, headers: headers)\n  IO.puts(\"#{resp.status} Elixir Forum\\n#{inspect(resp.body)}\")\nend\n"
  },
  {
    "path": ".github/workflows/ort/action.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nname: \"Run OSS Review Toolkit\"\ndescription: \"Runs OSS Review Toolkit & generates SBoMs\"\ninputs:\n  report-formats:\n    description: \"ORT Report Formats\"\n    required: true\n  fail-on-violation:\n    description: \"Whether to fail on violation.\"\n    required: false\n    default: false\n  upload-reports:\n    description: \"Whether to upload all reports\"\n    required: false\n    default: false\n  version:\n    description: \"Elixir Version (Tag / SHA)\"\n    required: true\n\noutputs:\n  results-path:\n    description: \"See oss-review-toolkit/ort-ci-github-action action\"\n    value: \"${{ steps.ort.outputs.results-path }}\"\n  results-sbom-cyclonedx-xml-path:\n    description: \"See oss-review-toolkit/ort-ci-github-action action\"\n    value: \"${{ steps.ort.outputs.results-sbom-cyclonedx-xml-path }}\"\n  results-sbom-cyclonedx-json-path:\n    description: \"See oss-review-toolkit/ort-ci-github-action action\"\n    value: \"${{ steps.ort.outputs.results-sbom-cyclonedx-json-path }}\"\n  results-sbom-spdx-yml-path:\n    description: \"See oss-review-toolkit/ort-ci-github-action action\"\n    value: \"${{ steps.ort.outputs.results-sbom-spdx-yml-path }}\"\n  results-sbom-spdx-json-path:\n    description: \"See oss-review-toolkit/ort-ci-github-action action\"\n    value: \"${{ steps.ort.outputs.results-sbom-spdx-json-path }}\"\n\nruns:\n  using: \"composite\"\n  steps:\n    - name: Fetch Default ORT Config\n      id: fetch-default-ort-config\n      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n      with:\n        repository: oss-review-toolkit/ort-config\n        ref: \"main\"\n        path: \".ort-config\"\n        persist-credentials: false\n\n    - name: Setup ORT Config\n      id: setup-ort-config\n      shell: bash\n      run: |\n        mkdir -p \"/$HOME/.ort/\"\n\n        # Move Fetched Default Config into Place\n        mv .ort-config \"$HOME/.ort/config\"\n        \n        # Append Global ORT Config\n        cat .ort/config/config.yml >> \"$HOME/.ort/config/config.yml\"\n        \n        # Override Default Evaluator Rules\n        cp .ort/config/evaluator.rules.kts \"$HOME/.ort/config/evaluator.rules.kts\"\n\n        # Add Package Configurations\n        mkdir -p \"$HOME/.ort/config/package-configurations/SpdxDocumentFile/The Elixir Team\"\n        for FILE in .ort/package-configurations/*.yml; do\n          COMPONENT=\"$(basename \"$FILE\")\"\n          cp \"$FILE\" \"$HOME/.ort/config/package-configurations/SpdxDocumentFile/The Elixir Team/$COMPONENT\"\n          sed -i -E \\\n            \"s/(\\\"SpdxDocumentFile:The Elixir Team:.+:)\\\"/\\1${ELIXIR_VERSION}\\\"/\" \\\n            \"$HOME/.ort/config/package-configurations/SpdxDocumentFile/The Elixir Team/$COMPONENT\"\n        done\n\n        # Set Version in SPDX & Config\n        sed -i \"s/# elixir-version-insert/versionInfo: '${ELIXIR_VERSION}'/\" project.spdx.yml\n        sed -i -E \"s/(\\\"SpdxDocumentFile:The Elixir Team:.+:)\\\"/\\1${ELIXIR_VERSION}\\\"/\" .ort.yml\n        sed -i \"s|https://github.com/elixir-lang/elixir.git|${ELIXIR_REPO}@${ELIXIR_VERSION}|\" project.spdx.yml\n      env:\n        ELIXIR_VERSION: \"${{ inputs.version }}\"\n        ELIXIR_REPO: \"${{ github.server_url }}/${{ github.repository }}.git\"\n\n    - name: \"Cache ScanCode\"\n      uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2\n      with:\n        path: \"~/.cache/scancode-tk\"\n        key: ${{ runner.os }}-scancode\n\n    - name: Run OSS Review Toolkit\n      id: ort\n      uses: oss-review-toolkit/ort-ci-github-action@1805edcf1f4f55f35ae6e4d2d9795ccfb29b6021 # v1.1.0\n      with:\n        image: ghcr.io/oss-review-toolkit/ort-minimal:65.0.0\n        run: >-\n          labels,\n          cache-dependencies,\n          cache-scan-results,\n          analyzer,\n          scanner,\n          advisor,\n          evaluator,\n          reporter,\n          ${{ inputs.upload-reports == 'true' && 'upload-results' || '' }}\n        fail-on: \"${{ inputs.fail-on-violation == 'true' && 'violations,issues' || '' }}\"\n        report-formats: \"${{ inputs.report-formats }}\"\n        ort-cli-report-args: >-\n          -O CycloneDX=output.file.formats=json,xml\n          -O SpdxDocument=outputFileFormats=JSON,YAML\n        sw-version: \"${{ inputs.version }}\"\n"
  },
  {
    "path": ".github/workflows/posix_compliance.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nname: POSIX Compliance\n\non:\n  push:\n    paths: &paths-filter\n      - .github/workflows/posix_compliance.yml\n      - bin/elixir\n      - bin/elixirc\n      - bin/iex\n\n  pull_request:\n    paths: *paths-filter\n\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  LANG: C.UTF-8\n\njobs:\n  check_posix_compliance:\n    name: Check POSIX compliance\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Install ShellCheck\n        run: |\n          sudo apt update\n          sudo apt install -y shellcheck\n\n      - name: Run ShellCheck on bin/ dir\n        run: |\n          shellcheck -e SC2039,2086 bin/elixir && \\\n            echo \"bin/elixir is POSIX compliant\"\n\n          shellcheck bin/elixirc && \\\n            echo \"bin/elixirc is POSIX compliant\"\n\n          shellcheck bin/iex && \\\n            echo \"bin/iex is POSIX compliant\"\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nname: Releases\n\non:\n  push:\n    branches:\n      - main\n      - v*.*\n\n    tags:\n      - v*\n\n  workflow_dispatch:\n\nenv:\n  ELIXIR_OPTS: \"--warnings-as-errors\"\n  LANG: C.UTF-8\n\npermissions:\n  contents: read\n\njobs:\n  create_draft_release:\n    name: Create draft release\n    runs-on: ubuntu-24.04\n\n    permissions:\n      contents: write\n\n    env:\n      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n    steps:\n      - name: Create draft release\n        if: github.ref_type != 'branch'\n        run: |\n          gh release create \\\n            --repo \"$GITHUB_REPOSITORY\" \\\n            --title \"$GITHUB_REF_NAME\" \\\n            --notes '' \\\n            --draft \\\n            \"$GITHUB_REF_NAME\"\n\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        # zizmor: ignore[artipacked]\n        if: github.ref_type == 'branch'\n\n      - name: Update ${{ github.ref_name }}-latest\n        if: github.ref_type == 'branch'\n        run: |\n          ref_name=\"${GITHUB_REF_NAME}-latest\"\n\n          if ! gh release view \"$ref_name\"; then\n            gh release create \\\n              --latest=false \\\n              --title \"$ref_name\" \\\n              --notes \"Automated release for latest ${GITHUB_REF_NAME}.\" \\\n              \"$ref_name\"\n          fi\n\n          git tag \"$ref_name\" --force\n          git push origin \"$ref_name\" --force\n\n  build:\n    name: Ubuntu 24.04, OTP ${{ matrix.otp_version }}${{ matrix.build_docs && ' (build docs)' || '' }}\n    runs-on: ubuntu-24.04\n\n    strategy:\n      fail-fast: true\n      matrix:\n        include:\n          - otp: 27\n            otp_version: \"27.0\"\n\n          - otp: 28\n            otp_version: \"28.0\"\n            build_docs: build_docs\n\n          - otp: 29\n            otp_version: \"29.0-rc1\"\n\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: \"Build Release\"\n        uses: ./.github/workflows/release_pre_built\n        with:\n          otp_version: ${{ matrix.otp_version }}\n          otp: ${{ matrix.otp }}\n          build_docs: ${{ matrix.build_docs }}\n\n      - name: Create Docs Hashes\n        if: matrix.build_docs\n        run: |\n          shasum -a 1   Docs.zip > Docs.zip.sha1sum\n          shasum -a 256 Docs.zip > Docs.zip.sha256sum\n\n      - name: \"Upload Linux release artifacts\"\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0\n        with:\n          name: build-linux-elixir-otp-${{ matrix.otp }}\n          path: elixir-otp-${{ matrix.otp }}.zip\n\n      - name: \"Upload Windows release artifacts\"\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0\n        with:\n          name: build-windows-elixir-otp-${{ matrix.otp }}\n          path: elixir-otp-${{ matrix.otp }}.exe\n\n      - name: \"Upload doc artifacts\"\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0\n        if: matrix.build_docs\n        with:\n          name: Docs\n          path: Docs.zip*\n\n  sign:\n    name: Sign files, ${{ matrix.flavor == 'windows' && 'Windows' || matrix.flavor == 'linux' && 'Linux' || matrix.flavor }}, OTP ${{ matrix.otp }}\n    needs: [build]\n    environment: release\n    strategy:\n      fail-fast: true\n      matrix:\n        otp: [27, 28, 29]\n        flavor: [windows, linux]\n\n    env:\n      RELEASE_FILE: elixir-otp-${{ matrix.otp }}.${{ matrix.flavor == 'linux' && 'zip' || 'exe' }}\n\n    runs-on: ${{ matrix.flavor == 'linux' && 'ubuntu-24.04' || 'windows-2022' }}\n\n    permissions:\n      contents: write\n      id-token: write\n\n    steps:\n      - name: \"Download build\"\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0\n        with:\n          name: build-${{ matrix.flavor }}-elixir-otp-${{ matrix.otp }}\n\n      - name: Log in to Azure\n        if: ${{ matrix.flavor == 'windows' && vars.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}\n        uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0\n        with:\n          client-id: ${{ secrets.AZURE_CLIENT_ID }}\n          tenant-id: ${{ secrets.AZURE_TENANT_ID }}\n          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}\n\n      - name: \"Sign files with Trusted Signing\"\n        uses: azure/trusted-signing-action@87c2e83e6868da99d3380aa309851b32ed9a8346 # v1.1.0\n        if: ${{ matrix.flavor == 'windows' && vars.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}\n        with:\n          endpoint: https://eus.codesigning.azure.net/\n          trusted-signing-account-name: ${{ vars.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}\n          certificate-profile-name: ${{ vars.AZURE_CERTIFICATE_PROFILE_NAME }}\n          files-folder: ${{ github.workspace }}\n          files-folder-filter: exe\n          file-digest: SHA256\n          timestamp-rfc3161: http://timestamp.acs.microsoft.com\n          timestamp-digest: SHA256\n\n      - name: Create Release Hashes\n        if: matrix.flavor == 'windows'\n        shell: pwsh\n        run: |\n          $sha1 = Get-FileHash \"$env:RELEASE_FILE\" -Algorithm SHA1\n          $sha1.Hash.ToLower() + \"  \" + $env:RELEASE_FILE | Out-File \"$env:RELEASE_FILE.sha1sum\"\n\n          $sha256 = Get-FileHash \"$env:RELEASE_FILE\" -Algorithm SHA256\n          $sha256.Hash.ToLower() + \"  \" + $env:RELEASE_FILE | Out-File \"$env:RELEASE_FILE.sha256sum\"\n\n      - name: Create Release Hashes\n        if: matrix.flavor == 'linux'\n        shell: bash\n        run: |\n          shasum -a 1   \"$RELEASE_FILE\" > \"${RELEASE_FILE}.sha1sum\"\n          shasum -a 256 \"$RELEASE_FILE\" > \"${RELEASE_FILE}.sha256sum\"\n\n      - name: \"Upload Linux release artifacts\"\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0\n        with:\n          name: sign-${{ matrix.flavor }}-elixir-otp-${{ matrix.otp }}\n          path: ${{ env.RELEASE_FILE }}*\n\n  sbom:\n    name: Generate SBoM\n    needs: [build, sign]\n    runs-on: ubuntu-24.04\n\n    permissions:\n      contents: write\n      id-token: write\n      attestations: write\n\n    steps:\n      - name: Use HTTPS instead of SSH for Git cloning\n        id: git-config\n        shell: bash\n        run: git config --global url.https://github.com/.insteadOf ssh://git@github.com/\n\n      - name: Checkout project\n        id: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: \"Download Build Artifacts\"\n        id: download-build-artifacts\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0\n        with:\n          pattern: \"{sign-*-elixir-otp-*,Docs}\"\n          merge-multiple: true\n          path: /tmp/build-artifacts/\n\n      - name: \"Run OSS Review Toolkit\"\n        id: ort\n        uses: ./.github/workflows/ort\n        with:\n          report-formats: \"CycloneDx,SpdxDocument\"\n          version: \"${{ github.ref_type\t== 'tag' && github.ref_name || github.sha }}\"\n\n      - name: Attest Distribution Assets with SBoM\n        id: attest-sbom\n        uses: actions/attest-sbom@07e74fc4e78d1aad915e867f9a094073a9f71527 # v4.0.0\n        with:\n          subject-path: |\n            /tmp/build-artifacts/{elixir-otp-*.*,Docs.zip}\n            ${{ steps.ort.outputs.results-sbom-cyclonedx-xml-path }}\n            ${{ steps.ort.outputs.results-sbom-cyclonedx-json-path }}\n            ${{ steps.ort.outputs.results-sbom-spdx-yml-path }}\n            ${{ steps.ort.outputs.results-sbom-spdx-json-path }}\n          sbom-path: \"${{ steps.ort.outputs.results-sbom-spdx-json-path }}\"\n\n      - name: \"Copy SBoM provenance\"\n        id: sbom-provenance\n        shell: bash\n        run: |\n          mkdir attestations\n\n          for FILE in /tmp/build-artifacts/{elixir-otp-*.*,Docs.zip}; do\n            cp \"$ATTESTATION\" \"attestations/$(basename \"$FILE\").sigstore\"\n          done\n\n          cp \"$ATTESTATION\" \"attestations/$(basename \"$SBOM_CYCLONEDX_XML\").sigstore\"\n          cp \"$ATTESTATION\" \"attestations/$(basename \"$SBOM_CYCLONEDX_JSON\").sigstore\"\n          cp \"$ATTESTATION\" \"attestations/$(basename \"$SBOM_SPDX_YML\").sigstore\"\n          cp \"$ATTESTATION\" \"attestations/$(basename \"$SBOM_SPDX_JSON\").sigstore\"\n        env:\n          ATTESTATION: \"${{ steps.attest-sbom.outputs.bundle-path }}\"\n          SBOM_CYCLONEDX_XML: \"${{ steps.ort.outputs.results-sbom-cyclonedx-xml-path }}\"\n          SBOM_CYCLONEDX_JSON: \"${{ steps.ort.outputs.results-sbom-cyclonedx-json-path }}\"\n          SBOM_SPDX_YML: \"${{ steps.ort.outputs.results-sbom-spdx-yml-path }}\"\n          SBOM_SPDX_JSON: \"${{ steps.ort.outputs.results-sbom-spdx-json-path }}\"\n\n      - name: \"Assemble Release SBoM Artifacts\"\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0\n        with:\n          name: \"SBoM\"\n          path: |\n            ${{ steps.ort.outputs.results-sbom-cyclonedx-xml-path }}\n            ${{ steps.ort.outputs.results-sbom-cyclonedx-json-path }}\n            ${{ steps.ort.outputs.results-sbom-spdx-yml-path }}\n            ${{ steps.ort.outputs.results-sbom-spdx-json-path }}\n\n      - name: \"Assemble Distribution Attestations\"\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0\n        with:\n          name: \"Attestations\"\n          path: \"attestations/*.sigstore\"\n\n  upload-release:\n    name: Upload release\n    needs: [create_draft_release, build, sign, sbom]\n    runs-on: ubuntu-24.04\n\n    permissions:\n      contents: write\n\n    steps:\n      - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0\n        with:\n          pattern: \"{sign-*-elixir-otp-*,Docs,SBoM,Attestations}\"\n          merge-multiple: true\n\n      - name: Upload Pre-build\n        shell: bash\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          if [ \"$GITHUB_REF_TYPE\" == \"branch\" ]; then\n            tag=\"${GITHUB_REF_NAME}-latest\"\n          else\n            tag=\"$GITHUB_REF_NAME\"\n          fi\n\n          gh release upload \\\n            --repo \"$GITHUB_REPOSITORY\" \\\n            --clobber \\\n            \"$tag\" \\\n            elixir-otp-*.zip \\\n            elixir-otp-*.zip.sha{1,256}sum \\\n            elixir-otp-*.zip.sigstore \\\n            elixir-otp-*.exe \\\n            elixir-otp-*.exe.sha{1,256}sum \\\n            elixir-otp-*.exe.sigstore \\\n            Docs.zip \\\n            Docs.zip.sha{1,256}sum \\\n            Docs.zip.sigstore \\\n            bom.*\n\n  upload-builds-hex-pm:\n    name: Upload builds to hex.pm\n    runs-on: ubuntu-24.04\n    needs: [build, sign]\n    concurrency: builds-hex-pm\n    environment: release\n\n    env:\n      AWS_ACCESS_KEY_ID: ${{ secrets.HEX_AWS_ACCESS_KEY_ID }}\n      AWS_SECRET_ACCESS_KEY: ${{ secrets.HEX_AWS_SECRET_ACCESS_KEY }}\n      AWS_REGION: ${{ vars.HEX_AWS_REGION }}\n      AWS_S3_BUCKET: ${{ vars.HEX_AWS_S3_BUCKET }}\n\n    steps:\n      - name: \"Check if variables are set up\"\n        if: \"${{ ! vars.HEX_AWS_REGION }}\"\n        run: |\n          echo \"Required variables for uploading to hex.pm are not set up, skipping...\"\n          exit 1\n\n      - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0\n        with:\n          pattern: \"{sign-*-elixir-otp-*,Docs}\"\n          merge-multiple: true\n\n      - name: Init purge keys file\n        run: |\n          touch purge_keys.txt\n\n      - name: Upload Precompiled to S3\n        run: |\n          oldest_otp=$(find . -type f -name 'elixir-otp-*.zip' | sed -r 's/^.*elixir-otp-([[:digit:]]+)\\.zip$/\\1/' | sort -n | head -n 1)\n\n          for zip in $(find . -type f -name 'elixir-otp-*.zip' | sed 's/^\\.\\///'); do\n            dest=${zip/elixir/${GITHUB_REF_NAME}}\n            surrogate_key=${dest/.zip$/}\n\n            aws s3 cp \"${zip}\" \"s3://${AWS_S3_BUCKET}/builds/elixir/${dest}\" \\\n              --cache-control \"public,max-age=3600\" \\\n              --metadata \"{\\\"surrogate-key\\\":\\\"builds builds/elixir builds/elixir/${surrogate_key}\\\",\\\"surrogate-control\\\":\\\"public,max-age=604800\\\"}\"\n            echo \"builds/elixir/${surrogate_key}\" >> purge_keys.txt\n\n            if [ \"$zip\" == \"elixir-otp-${oldest_otp}.zip\" ]; then\n              aws s3 cp \"${zip}\" \"s3://${AWS_S3_BUCKET}/builds/elixir/${GITHUB_REF_NAME}.zip\" \\\n                --cache-control \"public,max-age=3600\" \\\n                --metadata \"{\\\"surrogate-key\\\":\\\"builds builds/elixir builds/elixir/${GITHUB_REF_NAME}\\\",\\\"surrogate-control\\\":\\\"public,max-age=604800\\\"}\"\n              echo builds/elixir/${GITHUB_REF_NAME} >> purge_keys.txt\n            fi\n          done\n\n      - name: Upload Docs to S3\n        run: |\n          version=$(echo \"$GITHUB_REF_NAME\" | sed -e 's/^v//g')\n\n          unzip Docs.zip\n\n          for f in doc/*; do\n            if [ -d \"$f\" ]; then\n              app=$(echo \"$f\" | sed s/\"doc\\/\"//)\n              tarball=\"${app}-${version}.tar.gz\"\n              surrogate_key=\"docs/${app}-${version}\"\n\n              tar -czf \"${tarball}\" -C \"doc/${app}\" .\n              aws s3 cp \"${tarball}\" \"s3://${AWS_S3_BUCKET}/docs/${tarball}\" \\\n                --cache-control \"public,max-age=3600\" \\\n                --metadata \"{\\\"surrogate-key\\\":\\\"${surrogate_key}\\\",\\\"surrogate-control\\\":\\\"public,max-age=604800\\\"}\"\n              echo \"${surrogate_key}\" >> ../purge_keys.txt\n            fi\n          done\n\n      - name: Update builds txt\n        run: |\n          date=\"$(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\n          ref_name=\"$GITHUB_REF_NAME\"\n\n          oldest_otp=$(find . -name 'elixir-otp-*.zip.sha256sum' | sed -r 's/^.*elixir-otp-([[:digit:]]+)\\.zip\\.sha256sum$/\\1/' | sort -n | head -n 1)\n\n          aws s3 cp \"s3://${AWS_S3_BUCKET}/builds/elixir/builds.txt\" builds.txt || true\n          touch builds.txt\n\n          for sha256_file in $(find . -name 'elixir-otp-*.zip.sha256sum' | sed 's/^\\.\\///'); do\n            otp_version=$(echo \"${sha256_file}\" | sed -r 's/^elixir-otp-([[:digit:]]+)\\.zip\\.sha256sum/otp-\\1/')\n            build_sha256=$(cut -d ' ' -f 1 \"${sha256_file}\")\n\n            sed -i \"/^${ref_name}-${otp_version} /d\" builds.txt\n            echo -e \"${ref_name}-${otp_version} ${{ github.sha }} ${date} ${build_sha256} \\n$(cat builds.txt)\" > builds.txt\n\n            if [ \"${otp_version}\" == \"otp-${oldest_otp}\" ]; then\n              sed -i \"/^${ref_name} /d\" builds.txt\n              echo -e \"${ref_name} ${{ github.sha }} ${date} ${build_sha256} \\n$(cat builds.txt)\" > builds.txt\n            fi\n          done\n\n          sort -u -k1,1 -o builds.txt builds.txt\n          aws s3 cp builds.txt \"s3://${AWS_S3_BUCKET}/builds/elixir/builds.txt\" \\\n            --cache-control \"public,max-age=3600\" \\\n            --metadata '{\"surrogate-key\":\"builds builds/elixir builds/elixir/txt\",\"surrogate-control\":\"public,max-age=604800\"}'\n\n          echo 'builds/elixir/txt' >> purge_keys.txt\n\n      - name: Flush cache\n        if: github.repository == 'elixir-lang/elixir'\n        run: |\n          function purge_key() {\n            curl \\\n               -X POST \\\n               -H \"Fastly-Key: ${FASTLY_KEY}\" \\\n               -H \"Accept: application/json\" \\\n               -H \"Content-Length: 0\" \\\n               \"https://api.fastly.com/service/$1/purge/$2\"\n          }\n\n          function purge() {\n            purge_key ${FASTLY_REPO_SERVICE_ID} $1\n            purge_key ${FASTLY_BUILDS_SERVICE_ID} $1\n            sleep 2\n            purge_key ${FASTLY_REPO_SERVICE_ID} $1\n            purge_key ${FASTLY_BUILDS_SERVICE_ID} $1\n            sleep 2\n            purge_key ${FASTLY_REPO_SERVICE_ID} $1\n            purge_key ${FASTLY_BUILDS_SERVICE_ID} $1\n          }\n\n          for key in $(cat purge_keys.txt); do\n            purge \"${key}\"\n          done\n\n        env:\n          FASTLY_REPO_SERVICE_ID: ${{ secrets.HEX_FASTLY_REPO_SERVICE_ID }}\n          FASTLY_BUILDS_SERVICE_ID: ${{ secrets.HEX_FASTLY_BUILDS_SERVICE_ID }}\n          FASTLY_KEY: ${{ secrets.HEX_FASTLY_KEY }}\n"
  },
  {
    "path": ".github/workflows/release_notifications.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nname: Release Notifications\n\non:\n  release:\n    types:\n      - published\n\npermissions:\n  contents: read\n\njobs:\n  notify:\n    runs-on: ubuntu-latest\n    name: Notify\n\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - uses: erlef/setup-beam@e6d7c94229049569db56a7ad5a540c051a010af9 # v1.20.4\n        with:\n          otp-version: \"27.3\"\n          elixir-version: \"1.18.3\"\n\n      - name: Run Elixir script\n        env:\n          ELIXIR_FORUM_TOKEN: ${{ secrets.ELIXIR_FORUM_TOKEN }}\n          ELIXIR_LANG_ANN_TOKEN: ${{ secrets.ELIXIR_LANG_ANN_TOKEN }}\n        run: |\n          elixir .github/workflows/notify.exs \"$GITHUB_REF_NAME\"\n"
  },
  {
    "path": ".github/workflows/release_pre_built/action.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nname: Release Pre-build\ndescription: \"Builds Elixir release, ExDoc and generates docs\"\n\ninputs:\n  otp:\n    description: \"The major OTP version\"\n\n  otp_version:\n    description: \"The exact OTP version (major.minor[.patch])\"\n\n  build_docs:\n    description: \"Whether docs have to be built\"\n\nruns:\n  using: \"composite\"\n\n  steps:\n    - uses: erlef/setup-beam@5304e04ea2b355f03681464e683d92e3b2f18451 # v1.18.2\n      with:\n        otp-version: ${{ inputs.otp_version }}\n        version-type: strict\n\n    - name: Build Elixir Release\n      shell: bash\n      run: | # zizmor: ignore[github-env]\n        make Precompiled.zip\n        mv Precompiled.zip \"elixir-otp-${INPUT_OTP}.zip\"\n        echo \"$PWD/bin\" >> $GITHUB_PATH\n      env:\n        INPUT_OTP: ${{ inputs.otp }}\n\n    - name: Install NSIS\n      shell: bash\n      run: |\n        sudo apt update\n        sudo apt install -y nsis\n\n    - name: Build Elixir Windows Installer\n      shell: bash\n      run: |\n        export OTP_VERSION=\"$INPUT_OTP_VERSION\"\n        export ELIXIR_ZIP=\"$PWD/elixir-otp-${INPUT_OTP}.zip\"\n        (cd lib/elixir/scripts/windows_installer && ./build.sh)\n        mv \"lib/elixir/scripts/windows_installer/tmp/elixir-otp-${INPUT_OTP}.exe\" .\n      env:\n        INPUT_OTP: ${{ inputs.otp }}\n        INPUT_OTP_VERSION: ${{ inputs.otp_version }}\n    - name: Get ExDoc ref\n      if: ${{ inputs.build_docs }}\n      shell: bash\n      run: | # zizmor: ignore[github-env]\n        if [ \"$GITHUB_REF_NAME\" = \"main\" ]; then\n          ref=main\n        else\n          ref=v$(curl -s https://hex.pm/api/packages/ex_doc | jq --raw-output '.latest_stable_version')\n        fi\n        echo \"EX_DOC_REF=$ref\" >> $GITHUB_ENV\n    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n      if: ${{ inputs.build_docs }}\n      with:\n        repository: elixir-lang/ex_doc\n        ref: ${{ env.EX_DOC_REF }}\n        path: ex_doc\n        persist-credentials: false\n    - name: Build ex_doc\n      if: ${{ inputs.build_docs }}\n      shell: bash\n      run: |\n        mv ex_doc ../ex_doc\n        cd ../ex_doc\n        ../elixir/bin/mix do local.rebar --force + local.hex --force + deps.get + compile\n        cd ../elixir\n    - name: Build Docs\n      if: ${{ inputs.build_docs }}\n      shell: bash\n      run: |\n        git fetch --tags\n        make Docs.zip\n"
  },
  {
    "path": ".gitignore",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n/doc/\n/lib/*/ebin/\n/lib/*/_build/\n/lib/*/tmp/\n/lib/elixir/src/*_parser.erl\n/lib/elixir/test/ebin/\n/man/elixir.1\n/man/iex.1\n/Docs.zip\n/Precompiled.zip\n/.eunit\n.elixir.plt\nerl_crash.dump\n/cover/\n.tool-versions\n"
  },
  {
    "path": ".markdownlint-cli2.jsonc",
    "content": "// SPDX-License-Identifier: Apache-2.0\n// SPDX-FileCopyrightText: 2021 The Elixir Team\n{\n  \"globs\": [\n    \"**/*.md\"\n  ],\n  \"ignores\": [\n    \".git/**\"\n  ],\n  \"gitignore\": true,\n  \"config\": {\n    // Consecutive header levels (h1 -> h2 -> h3).\n    \"MD001\": false,\n    // Header style. We use #s.\n    \"MD003\": {\n      \"style\": \"atx\"\n    },\n    // Style of unordered lists..\n    \"MD007\": {\n      \"indent\": 2,\n      \"start_indented\": true\n    },\n    // Line length. Who cares.\n    \"MD013\": false,\n    // This warns if you have \"console\" or \"shell\" code blocks with a dollar sign $ that\n    // don't show output. We use those a lot, so this is fine for us.\n    \"MD014\": false,\n    // Multiple headings with the same content.\n    \"MD024\": {\n      // Duplication is allowed for headings with different parents.\n      \"siblings_only\": true\n    },\n    // Trailing punctuation in heading.\n    // Some headers finish with ! because it refers to a function name. Therefore we remove ! from\n    // the default values.\n    \"MD026\": {\n      \"punctuation\": \".,;:。，；：！\"\n    },\n    // Allow empty line between block quotes. Used by contiguous admonition blocks.\n    \"MD028\": false,\n    // Allowed HTML inline elements.\n    \"MD033\": {\n      \"allowed_elements\": [\n        \"h1\",\n        \"a\",\n        \"br\",\n        \"img\",\n        \"picture\",\n        \"source\",\n        \"noscript\",\n        \"p\",\n        \"script\"\n      ]\n    },\n    // This warns if you have spaces in code blocks. Sometimes, that's fine.\n    \"MD038\": false,\n    // Code block style. We don't care if it's fenced or indented.\n    \"MD046\": false,\n    // Our tables are too large to align.\n    \"MD060\": false\n  }\n}"
  },
  {
    "path": ".ort/config/config.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nort:\n  enableRepositoryPackageCurations: true\n  enableRepositoryPackageConfigurations: true\n\n  scanner:\n    skipConcluded: false\n    includeFilesWithoutFindings: true\n\n  analyzer:\n    allowDynamicVersions: true\n    enabledPackageManagers: [SpdxDocumentFile]\n\n  reporter:\n    reporters:\n      SpdxDocument:\n        options:\n          creationInfoOrganization: The Elixir Team\n          documentName: \"Elixir Source SPDX Document\"\n"
  },
  {
    "path": ".ort/config/evaluator.rules.kts",
    "content": "/*\n * Copyright (C) 2019 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)\n * Copyright (c) 2021 The Elixir Team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n // Docs: https://oss-review-toolkit.org/ort/docs/configuration/evaluator-rules\n\nval whitelistedLicenses = listOf(\n  // License for Elixir & Imported Erlang Projects\n  \"Apache-2.0\",\n  // License for the Elixir Logo\n  \"LicenseRef-elixir-trademark-policy\",\n  \"LicenseRef-scancode-elixir-trademark-policy\",\n  // License for included Unicode Files\n  \"LicenseRef-scancode-unicode\",\n  // DCO for committers\n  \"LicenseRef-scancode-dco-1.1\"\n).map { SpdxSingleLicenseExpression.parse(it) }.toSet()\n\nfun PackageRule.howToFixDefault() = \"\"\"\n      * Check if this license violation is intended\n      * Adjust evaluation rules in `.ort/config/evaluator.rules.kts`\n    \"\"\".trimIndent()\n\nfun PackageRule.LicenseRule.isHandled() =\n  object : RuleMatcher {\n    override val description = \"isHandled($license)\"\n\n    override fun matches() = license in whitelistedLicenses\n  }\n\nfun RuleSet.unhandledLicenseRule() = packageRule(\"UNHANDLED_LICENSE\") {\n  // Do not trigger this rule on packages that have been excluded in the .ort.yml.\n  require {\n    -isExcluded()\n  }\n\n  // Define a rule that is executed for each license of the package.\n  licenseRule(\"UNHANDLED_LICENSE\", LicenseView.CONCLUDED_OR_DECLARED_AND_DETECTED) {\n    require {\n      -isExcluded()\n      -isHandled()\n    }\n\n    // Throw an error message including guidance how to fix the issue.\n    error(\n      \"The license $license is currently not covered by policy rules. \" +\n        \"The license was ${licenseSource.name.lowercase()} in package \" +\n        \"${pkg.metadata.id.toCoordinates()}.\",\n      howToFixDefault()\n    )\n  }\n}\n\nfun RuleSet.unmappedDeclaredLicenseRule() = packageRule(\"UNMAPPED_DECLARED_LICENSE\") {\n  require {\n    -isExcluded()\n  }\n\n  resolvedLicenseInfo.licenseInfo.declaredLicenseInfo.processed.unmapped.forEach { unmappedLicense ->\n    warning(\n      \"The declared license '$unmappedLicense' could not be mapped to a valid license or parsed as an SPDX \" +\n        \"expression. The license was found in package ${pkg.metadata.id.toCoordinates()}.\",\n      howToFixDefault()\n    )\n  }\n}\n\nval ruleSet = ruleSet(ortResult, licenseInfoResolver, resolutionProvider) {\n  unhandledLicenseRule()\n  unmappedDeclaredLicenseRule()\n}\n\nruleViolations += ruleSet.violations\n"
  },
  {
    "path": ".ort/package-configurations/eex.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nid: \"SpdxDocumentFile:The Elixir Team:eex:\"\npath_excludes:\n  - pattern: \"lib/eex/test/**/*\"\n    reason: \"TEST_OF\"\n    comment: \"Tests\"\nlicense_finding_curations:\n  # Test Fixtures\n  - path: \"lib/eex/test/fixtures/**/*\"\n    reason: \"NOT_DETECTED\"\n    comment: \"Apply default license to test fixtures\"\n    detected_license: \"NONE\"\n    concluded_license: \"Apache-2.0\"\n"
  },
  {
    "path": ".ort/package-configurations/elixir.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nid: \"SpdxDocumentFile:The Elixir Team:elixir:\"\npath_excludes:\n  - pattern: \"lib/elixir/pages/**/*\"\n    reason: \"DOCUMENTATION_OF\"\n    comment: \"Documentation\"\n  - pattern: \"lib/elixir/scripts/**/*\"\n    reason: \"BUILD_TOOL_OF\"\n    comment: \"Build Tool\"\n  - pattern: \"lib/elixir/test/**/*\"\n    reason: \"TEST_OF\"\n    comment: \"Tests\"\nlicense_finding_curations:\n  # Logos\n  - path: \"lib/elixir/pages/images/logo.png\"\n    reason: \"NOT_DETECTED\"\n    comment: \"Apply Trademark Policy to Elixir Logo\"\n    detected_license: \"NONE\"\n    concluded_license: \"LicenseRef-elixir-trademark-policy\"\n  - path: \"lib/elixir/scripts/windows_installer/assets/Elixir.ico\"\n    reason: \"NOT_DETECTED\"\n    comment: \"Apply Trademark Policy to Elixir Logo\"\n    detected_license: \"NONE\"\n    concluded_license: \"LicenseRef-elixir-trademark-policy\"\n\n  # Documentation Images\n  - path: \"lib/elixir/pages/images/**/*.png\"\n    reason: \"NOT_DETECTED\"\n    comment: \"Apply default license to all images\"\n    detected_license: \"NONE\"\n    concluded_license: \"Apache-2.0\"\n\n  # Test Fixtures\n  - path: \"lib/elixir/test/elixir/fixtures/**/*\"\n    reason: \"NOT_DETECTED\"\n    comment: \"Apply default license to test fixtures\"\n    detected_license: \"NONE\"\n    concluded_license: \"Apache-2.0\"\n\n  # Unicode\n  - path: \"lib/elixir/unicode/*.txt\"\n    reason: \"NOT_DETECTED\"\n    comment: \"Apply default license to unicode files\"\n    detected_license: \"NONE\"\n    concluded_license: \"LicenseRef-scancode-unicode\"\n\n  # Wrongly Identified\n  - path: \"lib/elixir/pages/references/library-guidelines.md\"\n    reason: \"INCORRECT\"\n    comment: |\n      The guide mentions multiple licenses for users to choose from.\n      It however is not licensed itself by the mentioned licenses.\n    concluded_license: \"Apache-2.0\"\n  - path: \"lib/elixir/scripts/windows_installer/.gitignore\"\n    reason: \"INCORRECT\"\n    comment: \"Ignored by ScanCode\"\n    detected_license: \"NONE\"\n    concluded_license: \"Apache-2.0\"\n"
  },
  {
    "path": ".ort/package-configurations/ex_unit.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nid: \"SpdxDocumentFile:The Elixir Team:exunit:\"\npath_excludes:\n  - pattern: \"lib/ex_unit/examples/**/*\"\n    reason: \"EXAMPLE_OF\"\n    comment: \"Example\"\n  - pattern: \"lib/ex_unit/test/**/*\"\n    reason: \"TEST_OF\"\n    comment: \"Tests\"\nlicense_finding_curations:\n  # Test Fixtures\n  - path: \"lib/ex_unit/test/fixtures/**/*\"\n    reason: \"NOT_DETECTED\"\n    comment: \"Apply default license to test fixtures\"\n    detected_license: \"NONE\"\n    concluded_license: \"Apache-2.0\"\n"
  },
  {
    "path": ".ort/package-configurations/logger.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nid: \"SpdxDocumentFile:The Elixir Team:logger:\"\npath_excludes:\n  - pattern: \"lib/logger/test/**/*\"\n    reason: \"TEST_OF\"\n    comment: \"Tests\"\n"
  },
  {
    "path": ".ort/package-configurations/mix.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nid: \"SpdxDocumentFile:The Elixir Team:mix:\"\npath_excludes:\n  - pattern: \"lib/mix/test/**/*\"\n    reason: \"TEST_OF\"\n    comment: \"Tests\"\nlicense_finding_curations:\n  # Test Fixtures\n  - path: \"lib/mix/test/fixtures/**/*\"\n    reason: \"NOT_DETECTED\"\n    comment: \"Apply default license to test fixtures\"\n    detected_license: \"NONE\"\n    concluded_license: \"Apache-2.0\"\n"
  },
  {
    "path": ".ort.yml",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nexcludes:\n  paths:\n    - pattern: \"man/*\"\n      reason: \"DOCUMENTATION_OF\"\n      comment: \"Documentation\"\n    - pattern: \".github/**/*\"\n      reason: \"BUILD_TOOL_OF\"\n      comment: \"Documentation\"\n    - pattern: \".ort/**/*\"\n      reason: \"BUILD_TOOL_OF\"\n      comment: \"Documentation\"\n\n    # Unfortunately we'll have to repeat all package level excludes here\n    # Make sure to keep them in sync with the package configuration in\n    # .ort/package-configurations\n    - pattern: \"lib/*/pages/**/*\"\n      reason: \"DOCUMENTATION_OF\"\n      comment: \"Documentation\"\n    - pattern: \"lib/*/test/**/*\"\n      reason: \"TEST_OF\"\n      comment: \"Tests\"\n    - pattern: \"lib/*/scripts/**/*\"\n      reason: \"BUILD_TOOL_OF\"\n      comment: \"Build Tool\"\n    - pattern: \"lib/*/examples/**/*\"\n      reason: \"EXAMPLE_OF\"\n      comment: \"Example\"\n\ncurations:\n  license_findings:\n    # Version File\n    - path: \"VERSION\"\n      reason: \"NOT_DETECTED\"\n      comment: \"Apply Trademark Policy to VERSION file\"\n      detected_license: \"NONE\"\n      concluded_license: \"Apache-2.0\"\n\n    # Wrongly Identified\n    - path: \".gitignore\"\n      reason: \"INCORRECT\"\n      comment: \"Ignored by ScanCode\"\n      detected_license: \"NONE\"\n      concluded_license: \"Apache-2.0\"\n    - path: \".gitattributes\"\n      reason: \"INCORRECT\"\n      comment: \"Ignored by ScanCode\"\n      detected_license: \"NONE\"\n      concluded_license: \"Apache-2.0\"\n    - path: \"CONTRIBUTING.md\"\n      reason: \"INCORRECT\"\n      comment: \"Wrongly identified TSL license\"\n      detected_license: \"Apache-2.0 OR NOASSERTION OR LicenseRef-scancode-tsl-2020\"\n      concluded_license: \"Apache-2.0\"\n    - path: \"OPEN_SOURCE_POLICY.md\"\n      reason: \"INCORRECT\"\n      comment: \"Wrongly identified NOASSERTION\"\n      detected_license: \"NOASSERTION\"\n      concluded_license: \"Apache-2.0\"\n\n    # Unfortunately we'll have to repeat all package level license curations here\n    # Make sure to keep them in sync with the package configuration in\n    # .ort/package-configurations\n\n    # Test Fixtures\n    - path: \"lib/*/test/fixtures/**/*\"\n      reason: \"NOT_DETECTED\"\n      comment: \"Apply default license to test fixtures\"\n      detected_license: \"NONE\"\n      concluded_license: \"Apache-2.0\"\n\n    # Logos\n    - path: \"lib/elixir/pages/images/logo.png\"\n      reason: \"NOT_DETECTED\"\n      comment: \"Apply Trademark Policy to Elixir Logo\"\n      detected_license: \"NONE\"\n      concluded_license: \"LicenseRef-elixir-trademark-policy\"\n    - path: \"lib/elixir/scripts/windows_installer/assets/Elixir.ico\"\n      reason: \"NOT_DETECTED\"\n      comment: \"Apply Trademark Policy to Elixir Logo\"\n      detected_license: \"NONE\"\n      concluded_license: \"LicenseRef-elixir-trademark-policy\"\n\n    # Documentation Images\n    - path: \"lib/elixir/pages/images/**/*.png\"\n      reason: \"NOT_DETECTED\"\n      comment: \"Apply default license to all images\"\n      detected_license: \"NONE\"\n      concluded_license: \"Apache-2.0\"\n\n    # Test Fixtures\n    - path: \"lib/elixir/test/elixir/fixtures/**/*\"\n      reason: \"NOT_DETECTED\"\n      comment: \"Apply default license to test fixtures\"\n      detected_license: \"NONE\"\n      concluded_license: \"Apache-2.0\"\n\n    # Unicode\n    - path: \"lib/elixir/unicode/*.txt\"\n      reason: \"NOT_DETECTED\"\n      comment: \"Apply default license to unicode files\"\n      detected_license: \"NONE\"\n      concluded_license: \"LicenseRef-scancode-unicode\"\n\n    # Wrongly Identified\n    - path: \"lib/elixir/pages/references/library-guidelines.md\"\n      reason: \"INCORRECT\"\n      comment: |\n        The guide mentions multiple licenses for users to choose from.\n        It however is not licensed itself by the mentioned licenses.\n      concluded_license: \"Apache-2.0\"\n    - path: \"lib/elixir/scripts/windows_installer/.gitignore\"\n      reason: \"INCORRECT\"\n      comment: \"Ignored by ScanCode\"\n      detected_license: \"NONE\"\n      concluded_license: \"Apache-2.0\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Changelog for Elixir v1.20\n\n## Type system improvements\n\nThis release includes type inference of all constructs.\n\n### Type inference of function definitions\n\nElixir now performs inference of whole functions. The best way to show the new capabilities are with examples. Take the following code:\n\n```elixir\ndef add_foo_and_bar(data) do\n  data.foo + data.bar\nend\n```\n\nElixir now infers that the function expects a `map` as first argument, and the map must have the keys `.foo` and `.bar` whose values are either `integer()` or `float()`. The return type will be either `integer()` or `float()`.\n\nHere is another example:\n\n```elixir\ndef sum_to_string(a, b) do\n  Integer.to_string(a + b)\nend\n```\n\nEven though the `+` operator works with both integers and floats, Elixir infers that `a` and `b` must be both integers, as the result of `+` is given to a function that expects an integer. The inferred type information is then used during type checking to find possible typing errors.\n\n### Type inference of guards\n\nThis release also performs inference of guards! Let's see some examples:\n\n```elixir\ndef example(x, y) when is_list(x) and is_integer(y)\n```\n\nThe code above correctly infers `x` is a list and `y` is an integer.\n\n```elixir\ndef example({:ok, x} = y) when is_binary(x) or is_integer(x)\n```\n\nThe one above infers x is a binary or an integer, and `y` is a two element tuple with `:ok` as first element and a binary or integer as second.\n\n```elixir\ndef example(x) when is_map_key(x, :foo)\n```\n\nThe code above infers `x` is a map which has the `:foo` key, represented as `%{..., foo: dynamic()}`. Remember the leading `...` indicates the map may have other keys.\n\n```elixir\ndef example(x) when not is_map_key(x, :foo)\n```\n\nAnd the code above infers `x` does not have the `:foo` key (hence `x.foo` will raise a typing violation), which has the type: `%{..., foo: not_set()}`.\n\nYou can also have expressions that assert on the size of data structures:\n\n```elixir\ndef example(x) when tuple_size(x) < 3\n```\n\nElixir will correctly track the tuple has at most two elements, and therefore accessing `elem(x, 3)` will emit a typing violation. In other words, Elixir can look at complex guards, infer types, and use this information to find bugs in our code, without a need to introduce type signatures (yet).\n\n### Typing across clauses\n\nElixir now infers the type of a given clause based on previous clauses. Let's see an example:\n\n```elixir\ncase System.get_env(\"SOME_VAR\") do\n  nil -> :not_found\n  value -> {:ok, String.upcase(value)}\nend\n```\n\n`System.get_env(\"SOME_VAR\")` returns either `nil` or a `binary()`. Because the first clause matches on `nil`, the type system now knows `value` can no longer be `nil`, and therefore it must only be a `binary()`, which allows the second clause to also type check without violations.\n\nThis type inference across clauses also helps the type system find redundant clauses and dead code in existing codebases.\n\n### Complete typing of maps keys\n\nMaps were one of the first data-structures we implemented within the Elixir type system however, up to this point, they only supported atom keys. If they had additional keys, those keys were simply marked as `dynamic()`.\n\nAs of Elixir v1.20, we can track all possible domains as map keys. For example, the map:\n\n```elixir\n%{123 => \"hello\", 456.0 => :ok}\n```\n\nwill have the type:\n\n```elixir\n%{integer() => binary(), float() => :ok}\n```\n\nIt is also possible to mix domain keys, as above, with atom keys, yielding the following:\n\n```elixir\n%{integer() => integer(), root: integer()}\n```\n\nThis system is an implementation of [Typing Records, Maps, and Structs, by Giuseppe Castagna (2023)](https://www.irif.fr/~gc/papers/icfp23.pdf).\n\n### Typing of map operations\n\nWe have typed the majority of the functions in the `Map` module, allowing the type system to track how keys are added, updated, and removed across all possible key types.\n\nFor example, imagine we are calling the following `Map` functions with a variable `map`, which we don't know the exact shape of, and an atom key:\n\n```elixir\nMap.put(map, :key, 123)\n#=> returns type %{..., key: integer()}\n\nMap.delete(map, :key)\n#=> returns type %{..., key: not_set()}\n```\n\nAs you can see, we track when keys are set and also when they are removed.\n\nSome operations, like `Map.replace/3`, only replace the key if it exists, and that is also propagated by the type system:\n\n```elixir\nMap.replace(map, :key, 123)\n#=> returns type %{..., key: if_set(integer())}\n```\n\nIn other words, if the key exists, it would have been replaced by an integer value. Furthermore, whenever calling a function in the `Map` module and the given key is statically proven to never exist in the map, an error is emitted.\n\nBy combining full type inference with bang operations like `Map.fetch!/2`, `Map.pop!/2`, `Map.replace!/3`, and `Map.update!/3`, Elixir is able to propagate information about the desired keys. Take this module:\n\n```elixir\ndefmodule User do\n  def name(map), do: Map.fetch!(map, :name)\nend\n\ndefmodule CallsUser do\n  def calls_name do\n    User.name(%{})\n  end\nend\n```\n\nThe code above has a type violation, which is now caught by the type system:\n\n```text\n    warning: incompatible types given to User.name/1:\n\n        User.name(%{})\n\n    given types:\n\n        %{name: not_set()}\n\n    but expected one of:\n\n        dynamic(%{..., name: term()})\n\n    type warning found at:\n    │\n 16 │     User.name(%{})\n    │         ~\n    │\n    └─ lib/calls_user.ex:7:5: CallsUser.calls_name/0\n```\n\n### Acknowledgements\n\nThe type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/) and [Tidewave](https://tidewave.ai/).\n\n## v1.20.0-rc.3 (2026-03-09)\n\n### 1. Enhancements\n\n#### IEx\n\n  * [IEx] Optimize autocompleting modules\n\n### 2. Bug fixes\n\n#### Elixir\n\n  * [Enum] Fix `Enum.slice/2` for ranges with step > 1 sliced by step > 1\n  * [File] Preserve directory permissions in `File.cp_r/3`\n  * [File] Fix `File.cp_r/3` infinite loop with symlink cycles\n  * [File] Fix `File.cp_r/3` infinite loop when copying into subdirectory of source\n  * [File] Warn when defining `@type record()`, fixes CI on Erlang/OTP 29\n  * [File] Fix `File.Stream` `Enumerable.count` for files without trailing newline\n  * [Float] Fix `Float.parse/1` inconsistent error handling for non-scientific notation overflow\n  * [Kernel] Process fields even when structs are unknown (regression)\n  * [Kernel] Improve performance on several corner cases in the type system (regression)\n  * [Kernel] Fix regression when using `Kernel.in/2` in defguard (regression)\n\n## v1.20.0-rc.2 (2026-03-04)\n\n### 1. Enhancements\n\n#### Elixir\n\n  * [Code] Add `module_definition: :interpreted` option to `Code` which allows module definitions to be evaluated instead of compiled. In some applications/architectures, this can lead to drastic improvements to compilation times. Note this does not affect the generated `.beam` file, which will have the same performance/behaviour as before\n  * [Code] Make module purging opt-in and move temporary module deletion to the background to speed up compilation times\n  * [Integer] Add `Integer.popcount/1`\n  * [Kernel] Move struct validation in patterns and updates to type checker, this means adding and remove struct fields will cause fewer files to be recompiled\n  * [Kernel] Add type inference across clauses. For example, if one clause says `x when is_integer(x)`, then the next clause may no longer be an integer\n  * [Kernel] Detect and warn on redundant clauses\n  * [List] Add `List.first!/1` and `List.last!/1`\n  * Add Software Bill of Materials guide to the Documentation\n\n#### Mix\n\n  * [mix compile] Add `module_definition: :interpreted` option to `Code` which allows module definitions to be evaluated instead of compiled. In some applications/architectures, this can lead to drastic improvements to compilation times. Note this does not affect the generated `.beam` file, which will have the same performance/behaviour as before\n  * [mix deps] Parallelize dep lock status checks during `deps.loadpaths`, improving boot times in projects with many git dependencies\n\n### 2. Potential breaking changes\n\n#### Elixir\n\n  * `map.foo()` (accessing a map field with parens) and `mod.foo` (invoking a function without parens) will now raise instead of emitting runtime warnings, aligning themselves with the type system behaviour\n\n### 3. Bug fixes\n\n#### IEx\n\n  * [IEx] Ensure warnings emitted during IEx parsing are properly displayed/printed\n  * [IEx] Ensure pry works across remote nodes\n\n#### Mix\n\n  * [mix compile.erlang] Topsort Erlang modules before compilation for proper dependency resolution\n\n## v1.20.0-rc.1 (2026-01-13)\n\n### 1. Bug fixes\n\n#### Elixir\n\n  * [Kernel] Do not crash on map types with struct keys when performing type operations (regression)\n  * [Kernel] Mark the outcome of bitstring types as dynamic (regression)\n  * [Kernel] `<<expr::bitstring>>` will have type `binary` instead of `bitstring` if `expr` is a binary (regression)\n  * [Kernel] Do not crash on conditional variables when calling a function on a module which is represented by a variable (regression)\n\n## v1.20.0-rc.0 (2026-01-09)\n\n### 1. Enhancements\n\n#### Elixir\n\n  * [Calendar] Optimize `date_from_iso_days` by using the Neri-Schneider algorithm\n  * [Enum] Add `Enum.min_max` sorter\n  * [Integer] Add `Integer.ceil_div/2`\n  * [IO] Add `IO.iodata_empty?/1`\n  * [File] Skip device, named pipes, etc in `File.cp_r/3` instead of erroring with reason `:eio`\n  * [Kernel] Print intermediate results of `dbg` for pipes\n  * [Kernel] Warn on unused requires\n  * [Regex] Add `Regex.import/1` to import regexes defined with `/E`\n\n#### ExUnit\n\n  * [ExUnit.CaptureLog] Add `:formatter` option for custom log formatting\n\n#### Mix\n\n  * [mix deps] Support filtering `mix deps` output\n  * [mix compile] Enforce `:elixirc_paths` to be a list of strings to avoid paths from being discarded (the only documented type was lists of strings)\n  * [mix test] Add `mix test --dry-run`\n\n### 2. Potential breaking changes\n\n#### Elixir\n\n  * `require SomeModule` no longer expands to the given module at compile-time, but it still returns the module at runtime. Note that while Elixir does not guarantee macros will expand to certain constructs, but since this can break code relying on the previous behaviour, such as `require(SomeMod).some_macro()`, we are adding this note to the CHANGELOG\n\n### 3. Hard deprecations\n\n#### Elixir\n\n  * [File] `File.stream!(path, modes, lines_or_bytes)` is deprecated in favor of `File.stream!(path, lines_or_bytes, modes)`\n  * [Kernel] Matching on the size inside a bit pattern now requires the pin operator for consistency, such as `<<x::size(^existing_var)>>`\n  * [Kernel.ParallelCompiler] `Kernel.ParallelCompiler.async/1` is deprecated in favor of `Kernel.ParallelCompiler.pmap/2`, which is more performant and addresses known limitations\n\n#### Logger\n\n  * [Logger] `Logger.*_backend` functions are deprecated in favor of handlers. If you really want to keep on using backends, see the `:logger_backends` package\n  * [Logger] `Logger.enable/1` and `Logger.disable/1` have been deprecated in favor of `Logger.put_process_level/2` and `Logger.delete_process_level/1`\n\n## v1.19\n\nThe CHANGELOG for v1.19 releases can be found [in the v1.19 branch](https://github.com/elixir-lang/elixir/blob/v1.19/CHANGELOG.md).\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Code of Conduct\n\nContact: <elixir-lang-conduct@googlegroups.com>\n\n## Why have a Code of Conduct?\n\nAs contributors and maintainers of this project, we are committed to providing a friendly, safe and welcoming environment for all, regardless of age, disability, gender, nationality, race, religion, sexuality, or similar personal characteristic.\n\nThe goal of the Code of Conduct is to specify a baseline standard of behavior so that people with different social values and communication styles can talk about Elixir effectively, productively, and respectfully, even in face of disagreements. The Code of Conduct also provides a mechanism for resolving conflicts in the community when they arise.\n\n## Our Values\n\nThese are the values Elixir developers should aspire to:\n\n  * Be friendly and welcoming\n  * Be kind\n    * Remember that people have varying communication styles and that not everyone is using their native language. (Meaning and tone can be lost in translation.)\n    * Interpret the arguments of others in good faith, do not seek to disagree.\n    * When we do disagree, try to understand why.\n  * Be thoughtful\n    * Productive communication requires effort. Think about how your words will be interpreted.\n    * Remember that sometimes it is best to refrain entirely from commenting.\n  * Be respectful\n    * In particular, respect differences of opinion. It is important that we resolve disagreements and differing views constructively.\n  * Be constructive\n    * Avoid derailing: stay on topic; if you want to talk about something else, start a new conversation.\n    * Avoid unconstructive criticism: don't merely decry the current state of affairs; offer — or at least solicit — suggestions as to how things may be improved.\n    * Avoid harsh words and stern tone: we are all aligned towards the well-being of the community and the progress of the ecosystem. Harsh words exclude, demotivate, and lead to unnecessary conflict.\n    * Avoid snarking (pithy, unproductive, sniping comments).\n    * Avoid microaggressions (brief and commonplace verbal, behavioral and environmental indignities that communicate hostile, derogatory or negative slights and insults towards a project, person or group).\n  * Be responsible\n    * What you say and do matters. Take responsibility for your words and actions, including their consequences, whether intended or otherwise.\n\nThe following actions are explicitly forbidden:\n\n  * Insulting, demeaning, hateful, or threatening remarks.\n  * Discrimination based on age, disability, gender, nationality, race, religion, sexuality, or similar personal characteristic.\n  * Bullying or systematic harassment.\n  * Unwelcome sexual advances.\n  * Incitement to any of these.\n\n## Where does the Code of Conduct apply?\n\nIf you participate in or contribute to the Elixir ecosystem in any way, you are encouraged to follow the Code of Conduct while doing so.\n\nExplicit enforcement of the Code of Conduct applies to the official mediums operated by the Elixir project:\n\n  * The [official GitHub projects][1] and code reviews.\n  * The official elixir-lang mailing lists.\n  * The **[#elixir][2]** IRC channel on [Libera.Chat][3].\n\nOther Elixir activities (such as conferences, meetups, and unofficial forums) are encouraged to adopt this Code of Conduct. Such groups must provide their own contact information.\n\nProject maintainers may block, remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct.\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by emailing: <elixir-lang-conduct@googlegroups.com>. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. **All reports will be kept confidential**.\n\n**The goal of the Code of Conduct is to resolve conflicts in the most harmonious way possible**. We hope that in most cases issues may be resolved through polite discussion and mutual agreement. Bannings and other forceful measures are to be employed only as a last resort. **Do not** post about the issue publicly or try to rally sentiment against a particular individual or group.\n\n## Acknowledgements\n\nThis document was based on the Code of Conduct from the Go project (dated Sep/2021) and the Contributor Covenant (v1.4).\n\n[1]: https://github.com/elixir-lang/\n[2]: https://web.libera.chat/#elixir\n[3]: https://libera.chat/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Contributing to Elixir\n\nWe invite contributions to Elixir. To contribute, there are a few\nthings you need to know about the code. First, Elixir code is divided\nby each application inside the `lib` folder:\n\n  * `elixir` - Elixir's kernel and standard library\n\n  * `eex` - EEx is the template engine that allows you to embed Elixir\n\n  * `ex_unit` - ExUnit is a simple test framework that ships with Elixir\n\n  * `iex` - IEx stands for Interactive Elixir: Elixir's interactive shell\n\n  * `logger` - Logger is the built-in logger\n\n  * `mix` - Mix is Elixir's build tool\n\nYou can run all tests in the root directory with `make test`. You can\nalso run tests for a specific framework with `make test_#{APPLICATION}`, for example,\n`make test_ex_unit`. If you just changed something in Elixir's standard\nlibrary, you can run only that portion through `make test_stdlib`.\n\nIf you are only changing one file, you can choose to compile and run tests\nfor that specific file for faster development cycles. For example, if you\nare changing the String module, you can compile it and run its tests as:\n\n```sh\nbin/elixirc lib/elixir/lib/string.ex -o lib/elixir/ebin\nbin/elixir lib/elixir/test/elixir/string_test.exs\n```\n\nSome test files need their `test_helper.exs` to be explicitly required\nbefore, such as:\n\n```sh\nbin/elixir -r lib/logger/test/test_helper.exs lib/logger/test/logger_test.exs\n```\n\nYou can also use the `LINE` env var to run a single test:\n\n```sh\nLINE=123 bin/elixir lib/elixir/test/elixir/string_test.exs\n````\n\nTo recompile all (including Erlang modules):\n\n```sh\nmake compile\n```\n\nAfter your changes are done, please remember to run `make format` to guarantee\nall files are properly formatted, then run the full suite with\n`make test`.\n\nIf your contribution fails during the bootstrapping of the language,\nyou can rebuild the language from scratch with:\n\n```sh\nmake clean_elixir compile\n```\n\nSimilarly, if you can not get Elixir to compile or the tests to pass after\nupdating an existing checkout, run `make clean compile`. You can check\n[the official build status](https://github.com/elixir-lang/elixir/actions/workflows/ci.yml).\nMore tasks can be found by reading the [Makefile](Makefile).\n\nWe encourage contributors to write tests that capture both existing and newly\nintroduced behavior, especially for bug fixes and major changes:\n\n  * **Bug Fixes:** If you are fixing a bug, please try to include a test that\n    *fails* before your change and *passes* afterward. This makes it easier to\n    confirm that the fix addresses the underlying issue and helps prevent\n    regressions in the future.\n\n  * **New Features or Major Changes:** If you are adding a new feature or making\n    major changes to existing functionality, please add tests that cover the\n    major parts of that functionality. Aim to have the best code coverage possible.\n\nWith tests running and passing, you are ready to contribute to Elixir and\n[send a pull request](https://help.github.com/articles/using-pull-requests/).\nWe have saved some excellent pull requests we have received in the past in\ncase you are looking for some examples:\n\n  * [Implement Enum.member? - Pull request](https://github.com/elixir-lang/elixir/pull/992)\n\n  * [Add String.valid? - Pull request](https://github.com/elixir-lang/elixir/pull/1058)\n\n  * [Implement capture_io for ExUnit - Pull request](https://github.com/elixir-lang/elixir/pull/1059)\n\n## Reviewing changes\n\nOnce a pull request is sent, the Elixir team will review your changes.\nWe outline our process below to clarify the roles of everyone involved.\n\nAll pull requests must be approved by two committers before being merged into\nthe repository. If changes are necessary, the team will leave appropriate\ncomments requesting changes to the code. Unfortunately, we cannot guarantee a\npull request will be merged, even when modifications are requested, as the Elixir\nteam will re-evaluate the contribution as it changes.\n\nCommitters may also push style changes directly to your branch. If you would\nrather manage all changes yourself, you can disable the \"Allow edits from maintainers\"\nfeature when submitting your pull request.\n\nThe Elixir team may optionally assign someone to review a pull request.\nIf someone is assigned, they must explicitly approve the code before\nanother team member can merge it.\n\nWhen the review finishes, your pull request will be squashed and merged\ninto the repository. If you have carefully organized your commits and\nbelieve they should be merged without squashing, please mention it in\na comment.\n\n## Licensing and Compliance Requirements\n\nPlease review our [Open Source Policy](OPEN_SOURCE_POLICY.md) for complete\nguidelines on licensing and compliance. Below is a summary of the key points\naffecting **all external contributors**:\n\n  * Accepted Licenses: Any code contributed must be licensed under the\n    `Apache-2.0` license.\n\n  * SPDX License Headers: With the exception of approved test fixture files,\n    all new or modified files in a pull request must include correct SPDX\n    headers. If you are creating a new file under the `Apache-2.0` license, for\n    instance, please use:\n\n    ```elixir\n    # SPDX-License-Identifier: Apache-2.0\n    # SPDX-FileCopyrightText: 2021 The Elixir Team\n    ```\n\n  * No Executable Binaries: Contributions must **not** include any executable\n    binary files. If you require an exception (for example, certain test artifacts),\n    please see the policy on how to request approval and document exceptions.\n\n  * Preserving Copyright and License Info: If you copy code from elsewhere,\n    ensure that **all original copyright and license notices remain intact**. If\n    they are missing or incomplete, you must add them.\n\n  * Failure to Comply: Pull requests that do not meet these licensing and\n    compliance standards will be rejected or require modifications before merging.\n\n  * Developer Certificate of Origin: All contributions are subject to the\n    Developer Certificate of Origin.\n\n    ```text\n    By making a contribution to this project, I certify that:\n\n    (a) The contribution was created in whole or in part by me and I\n        have the right to submit it under the open source license\n        indicated in the file; or\n\n    (b) The contribution is based upon previous work that, to the \n        best of my knowledge, is covered under an appropriate open \n        source license and I have the right under that license to   \n        submit that work with modifications, whether created in whole\n        or in part by me, under the same open source license (unless\n        I am permitted to submit under a different license), as \n        Indicated in the file; or\n\n    (c) The contribution was provided directly to me by some other\n        person who certified (a), (b) or (c) and I have not modified\n        it.\n\n    (d) I understand and agree that this project and the contribution\n        are public and that a record of the contribution (including \n        all personal information I submit with it, including my\n        sign-off) is maintained indefinitely and may be redistributed\n        consistent with this project or the open source license(s)\n        involved.\n    ```\n\n    See <https://developercertificate.org/> for a copy of the Developer Certificate\n    of Origin license.\n\n## Building documentation\n\nBuilding the documentation requires that [ExDoc](https://github.com/elixir-lang/ex_doc)\nis installed and built alongside Elixir.\n\nAfter cloning and compiling Elixir, run:\n\n```sh\nelixir_dir=$(pwd)\ncd .. && git clone https://github.com/elixir-lang/ex_doc.git\ncd ex_doc && \"${elixir_dir}/bin/elixir\" \"${elixir_dir}/bin/mix\" do deps.get + compile\n\n# Now we will go back to Elixir's root directory,\ncd \"${elixir_dir}\"\n\n# and generate HTML and EPUB documents:\nmake docs\n```\n\nThis will produce documentation sets for `elixir`, `eex`, `ex_unit`, `iex`, `logger`,\nand `mix` under the `doc` directory. If you are planning to contribute documentation,\n[please check our best practices for writing documentation](https://hexdocs.pm/elixir/writing-documentation.html).\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "LICENSES/Apache-2.0.txt",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, \"control\" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising permissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, \"submitted\" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:\n\n     (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and\n\n     (b) You must cause any modified files to carry prominent notices stating that You changed the files; and\n\n     (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and\n\n     (d) If the Work includes a \"NOTICE\" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.\n\n     You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\nTo apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets \"[]\" replaced with your own identifying information. (Don't include the brackets!)  The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same \"printed page\" as the copyright notice for easier identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "LICENSES/LicenseRef-elixir-trademark-policy.txt",
    "content": "ELIXIR TEAM TRADEMARKS POLICY\n\nThis document outlines the policy for allowed usage of the “Elixir” word and the\nElixir logo by other parties.\n\n“Elixir” and the Elixir logo are registered trademarks of the Elixir Team. The\nElixir Team believes in a decentralized approach to growing the community and\nthe ecosystem, independent of the Elixir project and the Elixir Team.\n\nAnyone can use the Elixir trademarks if that use of the trademark is nominative.\nThe trademarks must not be used to disparage the project and its community, nor\nbe used in any way to imply ownership, endorsement, or association with the\nElixir project and the Elixir Team.\n\nYou must not visually combine the Elixir logo with any other images, or change\nthe logo in any way other than ways required by printing restrictions. If you\nwant to create your own visual identity in relation to Elixir, you might use the\nshape of an unrelated “water drop” as part of your design, as seen in many\ncommunity projects and initiatives. You must not combine or modify the Elixir\nlogo.\n\nThe Elixir logo is available in our repository in both vertical and horizontal\nversions.\n\nNominative use\nThe “nominative use” (or “nominative fair use”) is a legal doctrine that\nauthorizes everyone (even commercial companies) to use or refer to the trademark\nof another if:\n\nThe product or service in question must be one not readily identifiable without\nuse of the trademark.\n\nOnly so much of the mark or marks may be used as is reasonably necessary to\nidentify the product or service.\n\nThe organization using the mark must do nothing that would, in conjunction with\nthe mark, suggest sponsorship or endorsement by the trademark holder.\n\nOur trademarks must be used to refer to the Elixir programming language.\n\nExamples of permitted use\nAll examples listed next must strictly adhere to the terms outlined in the\nprevious sections:\n\nUsage of the Elixir logo to say a technology is “powered by Elixir” under\nnominative use. Linking back to the Elixir website, if possible, is appreciated.\n\nUsage of the Elixir logo to display it as a supported technology in a service or\nplatform. For instance, you may say “we support Elixir” and use the Elixir logo,\nbut you may not refer to yourself as “the Elixir platform” nor imply any form of\nendorsement or association with Elixir.\n\nUsage of the Elixir logo in non-commercial community meetups, in presentations,\nand in courses when referring to the language and its ecosystem under nominative\nuse.\n\nUsage of the Elixir logo in non-commercial swag (stickers, t-shirts, mugs, etc)\nto promote the Elixir programming language. The Elixir marks must be the only\nmarks featured in the product. You need permission to make swag that include\nElixir and other third party marks in them.\n\nInclusion of the Elixir logo in non-commercial icon sets. Use of the Elixir\nicons must still adhere to Elixir’s trademark policies.\n\nUsage of the “Elixir” word in book titles, meetups, conferences, and podcasts.\nYou must not use the word to imply uniqueness or endorsement from the Elixir\nteam. “The Elixir book” and “The Elixir podcast” are not permitted.\n“Elixir in Action”, “Thinking Elixir”, and “Kraków Elixir User Group” are valid\nexamples already in use today.\n\nUsage of the “Elixir” word in the names of freely distributed software and\nhardware products is allowed when referring to use with or suitability for the\nElixir programming language, such as wxElixir, Elixirsense, etc. If the product\nincludes the Elixir programming language itself, then you must also respect its\nlicense.\n\nExamples of not permitted use\nHere is a non-exhaustive list of non permitted uses of the marks:\n\nUsage of the Elixir logo in book covers, conferences, and podcasts.\n\nUsage of the Elixir logo as the mark of third party projects, even in combination\nwith other marks.\n\nNaming any company or product after Elixir, such as “The Elixir Hosting”,\n“The Elixir Consultants”, etc.\n\nExamples that require permission\nHere are some examples that may be granted permission upon request:\n\nSelling merchandise (stickers, t-shirts, mugs, etc).\nYou can request permission by emailing trademarks@elixir-lang.org.\n\nImportant note\nNothing in this page shall be interpreted to allow any third party to claim any\nassociation with the Elixir project and the Elixir Team, or to imply any\napproval or support by the Elixir project and the Elixir Team for any third\nparty products, services, or events.\n"
  },
  {
    "path": "LICENSES/LicenseRef-scancode-unicode.txt",
    "content": "UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE\n\nUnicode Data Files include all data files under the directories\nhttp://www.unicode.org/Public/, http://www.unicode.org/reports/, and\nhttp://www.unicode.org/cldr/data/ . Unicode Software includes any source\ncode published in the Unicode Standard or under the directories\nhttp://www.unicode.org/Public/, http://www.unicode.org/reports/, and\nhttp://www.unicode.org/cldr/data/.\n\nNOTICE TO USER: Carefully read the following legal agreement. BY\nDOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA\nFILES (\"DATA FILES\"), AND/OR SOFTWARE (\"SOFTWARE\"), YOU UNEQUIVOCALLY\nACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS\nAGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE\nOR USE THE DATA FILES OR SOFTWARE.\n\nCOPYRIGHT AND PERMISSION NOTICE\n\nCopyright ©  Unicode, Inc. All rights reserved. Distributed under\nthe Terms of Use in http://www.unicode.org/copyright.html.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of the Unicode data files and any associated documentation (the\n\"Data Files\") or Unicode software and any associated documentation (the\n\"Software\") to deal in the Data Files or Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge,\npublish, distribute, and/or sell copies of the Data Files or Software,\nand to permit persons to whom the Data Files or Software are furnished\nto do so, provided that\n\n(a) the above copyright notice(s) and this permission notice appear with\nall copies of the Data Files or Software,\n\n(b) both the above copyright notice(s) and this permission notice appear\nin associated documentation, and\n\n(c) there is clear notice in each modified Data File or in the Software\nas well as in the documentation associated with the Data File(s) or\nSoftware that the data or software has been modified.\n\nTHE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR\nANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER\nRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF\nCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\nCONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.\n\nExcept as contained in this notice, the name of a copyright holder shall\nnot be used in advertising or otherwise to promote the sale, use or\nother dealings in these Data Files or Software without prior written\nauthorization of the copyright holder.\n\nUnicode and the Unicode logo are trademarks of Unicode, Inc., and may be\nregistered in some jurisdictions. All other trademarks and registered\ntrademarks mentioned herein are the property of their respective owners.\n"
  },
  {
    "path": "Makefile",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nPREFIX ?= /usr/local\nTEST_FILES ?= \"*_test.exs\"\nSHARE_PREFIX ?= $(PREFIX)/share\nMAN_PREFIX ?= $(SHARE_PREFIX)/man\nCANONICAL := main/\nELIXIRC := bin/elixirc --ignore-module-conflict $(ELIXIRC_OPTS)\nELIXIRC_MIN_SIG := $(ELIXIRC) -e 'Code.put_compiler_option :infer_signatures, []'\nERLC := erlc -I lib/elixir/include\nERL_MAKE := erl -make\nERL := erl -I lib/elixir/include -noshell -pa lib/elixir/ebin\nGENERATE_APP := $(CURDIR)/lib/elixir/scripts/generate_app.escript\nVERSION := $(strip $(shell cat VERSION))\nQ := @\nLIBDIR := lib\nBINDIR := bin\nINSTALL = install\nINSTALL_DIR = $(INSTALL) -m755 -d\nINSTALL_DATA = $(INSTALL) -m644\nINSTALL_PROGRAM = $(INSTALL) -m755\nGIT_REVISION = $(strip $(shell git rev-parse HEAD 2> /dev/null ))\nGIT_TAG = $(strip $(shell head=\"$(call GIT_REVISION)\"; git tag --points-at $$head 2> /dev/null | grep -v latest | tail -1))\nSOURCE_DATE_EPOCH_PATH = lib/elixir/tmp/ebin_reproducible\nSOURCE_DATE_EPOCH_FILE = $(SOURCE_DATE_EPOCH_PATH)/SOURCE_DATE_EPOCH\n\n.PHONY: cover install install_man build_plt clean_plt dialyze test check_reproducible clean clean_elixir clean_man format docs Docs.zip Precompiled.zip zips\n.NOTPARALLEL:\n\n#==> Functions\n\ndefine CHECK_ERLANG_RELEASE\n\terl -noshell -eval '{V,_} = string:to_integer(erlang:system_info(otp_release)), io:fwrite(\"~s\", [is_integer(V) and (V >= 27)])' -s erlang halt | grep -q '^true'; \\\n\t\tif [ $$? != 0 ]; then \\\n\t\t  echo \"At least Erlang/OTP 27.0 is required to build Elixir\"; \\\n\t\t  exit 1; \\\n\t\tfi\nendef\n\ndefine APP_TEMPLATE\n$(1): lib/$(1)/ebin/Elixir.$(2).beam lib/$(1)/ebin/$(1).app\n\nlib/$(1)/ebin/$(1).app: lib/$(1)/mix.exs\n\t$(Q) cd lib/$(1) && ../../bin/elixir -e 'Mix.start(:permanent, [])' -r mix.exs -e 'Mix.Task.run(\"compile.app\", ~w[--compile-path ebin])'\n\nlib/$(1)/ebin/Elixir.$(2).beam: $(wildcard lib/$(1)/lib/*.ex) $(wildcard lib/$(1)/lib/*/*.ex) $(wildcard lib/$(1)/lib/*/*/*.ex)\n\t@ echo \"==> $(1) (compile)\"\n\t@ rm -rf lib/$(1)/ebin\n\t$(Q) cd lib/$(1) && ../../$$(ELIXIRC) \"lib/**/*.ex\" -o ebin\n\ntest_$(1): test_formatted $(1)\n\t@ echo \"==> $(1) (ex_unit)\"\n\t$(Q) cd lib/$(1) && ../../bin/elixir -r \"test/test_helper.exs\" -pr \"test/**/$(TEST_FILES)\";\n\ncover/ex_unit_$(1).coverdata:\n\t$(Q) COVER=\"1\" $(MAKE) test_$(1)\ncover/combined.coverdata: cover/ex_unit_$(1).coverdata\nendef\n\ndefine WRITE_SOURCE_DATE_EPOCH\n$(shell mkdir -p $(SOURCE_DATE_EPOCH_PATH) && bin/elixir -e \\\n  'IO.puts System.build_info()[:date] \\\n   |> DateTime.from_iso8601() \\\n   |> elem(1) \\\n   |> DateTime.to_unix()' > $(SOURCE_DATE_EPOCH_FILE))\nendef\n\ndefine READ_SOURCE_DATE_EPOCH\n$(strip $(shell cat $(SOURCE_DATE_EPOCH_FILE)))\nendef\n\n#==> Compilation tasks\n\nAPP := lib/elixir/ebin/elixir.app\nEEX := lib/eex/ebin/Elixir.EEx.beam\nELIXIR := lib/elixir/ebin/elixir.beam\nPARSER := lib/elixir/src/elixir_parser.erl\nKERNEL := lib/elixir/ebin/Elixir.Kernel.beam\nUNICODE := lib/elixir/ebin/Elixir.String.Unicode.beam\n\ndefault: compile\n\ncompile: erlang elixir\n\nerlang: $(ELIXIR)\n$(ELIXIR): $(PARSER) lib/elixir/src/*\n\t$(Q) if [ ! -f $(APP) ]; then $(call CHECK_ERLANG_RELEASE); fi\n\t$(Q) cd lib/elixir && mkdir -p ebin && $(ERL_MAKE)\n\t$(Q) $(GENERATE_APP) $(VERSION)\n\n$(PARSER): lib/elixir/src/elixir_parser.yrl\n\t$(Q) erlc -o $@ +'{verbose,true}' +'{report,true}' $<\n\n# Since Mix depends on EEx and EEx depends on Mix,\n# we first compile EEx without the .app file,\n# then Mix, and then compile EEx fully\nelixir: stdlib $(EEX) mix ex_unit logger eex iex\nstdlib: $(KERNEL) $(UNICODE) $(APP)\n\n$(KERNEL): lib/elixir/src/* lib/elixir/lib/*.ex lib/elixir/lib/*/*.ex lib/elixir/lib/*/*/*.ex VERSION\n\t$(Q) if [ ! -f $(KERNEL) ]; then \\\n\t\techo \"==> bootstrap (compile)\"; \\\n\t\t$(ERL) -s elixir_compiler bootstrap -s erlang halt; \\\n\t\t\"$(MAKE)\" unicode; \\\n\tfi\n\t@ echo \"==> elixir (compile)\";\n\t$(Q) cd lib/elixir && ../../$(ELIXIRC_MIN_SIG) \"lib/**/*.ex\" -o ebin;\n\t$(Q) $(GENERATE_APP) $(VERSION)\n\t$(Q) bin/elixir lib/elixir/scripts/infer.exs;\n\n$(APP): lib/elixir/src/elixir.app.src $(GENERATE_APP)\n\t$(Q) $(GENERATE_APP) $(VERSION)\n\nunicode: $(UNICODE)\n$(UNICODE): lib/elixir/unicode/*\n\t@ echo \"==> unicode (compile)\";\n\t$(Q) $(ELIXIRC_MIN_SIG) lib/elixir/unicode/unicode.ex -o lib/elixir/ebin;\n\t$(Q) $(ELIXIRC_MIN_SIG) lib/elixir/unicode/tokenizer.ex -o lib/elixir/ebin;\n\t$(Q) $(ELIXIRC_MIN_SIG) lib/elixir/unicode/security.ex -o lib/elixir/ebin;\n\n$(eval $(call APP_TEMPLATE,ex_unit,ExUnit))\n$(eval $(call APP_TEMPLATE,logger,Logger))\n$(eval $(call APP_TEMPLATE,eex,EEx))\n$(eval $(call APP_TEMPLATE,mix,Mix))\n$(eval $(call APP_TEMPLATE,iex,IEx))\n\ninstall: compile\n\t@ echo \"==> elixir (install)\"\n\t$(Q) for dir in lib/*; do \\\n\t\trm -rf $(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/$$dir/ebin; \\\n\t\t$(INSTALL_DIR) \"$(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/$$dir/ebin\"; \\\n\t\t$(INSTALL_DATA) $$dir/ebin/* \"$(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/$$dir/ebin\"; \\\n\tdone\n\t$(Q) $(INSTALL_DIR) \"$(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/bin\"\n\t$(Q) $(INSTALL_PROGRAM) $(filter-out %.ps1, $(filter-out %.bat, $(wildcard bin/*))) \"$(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/bin\"\n\t$(Q) $(INSTALL_DIR) \"$(DESTDIR)$(PREFIX)/$(BINDIR)\"\n\t$(Q) for file in \"$(DESTDIR)$(PREFIX)\"/$(LIBDIR)/elixir/bin/*; do \\\n\t\tln -sf \"../$(LIBDIR)/elixir/bin/$${file##*/}\" \"$(DESTDIR)$(PREFIX)/$(BINDIR)/\"; \\\n\tdone\n\t\"$(MAKE)\" install_man\n\ncheck_reproducible: compile\n\t$(Q) echo \"==> Checking for reproducible builds...\"\n\t$(Q) rm -rf lib/*/tmp/ebin_reproducible/\n\t$(call WRITE_SOURCE_DATE_EPOCH)\n\t$(Q) mkdir -p lib/elixir/tmp/ebin_reproducible/ \\\n\t              lib/eex/tmp/ebin_reproducible/ \\\n\t              lib/ex_unit/tmp/ebin_reproducible/ \\\n\t              lib/iex/tmp/ebin_reproducible/ \\\n\t              lib/logger/tmp/ebin_reproducible/ \\\n\t              lib/mix/tmp/ebin_reproducible/\n\t$(Q) mv lib/elixir/ebin/* lib/elixir/tmp/ebin_reproducible/\n\t$(Q) mv lib/eex/ebin/* lib/eex/tmp/ebin_reproducible/\n\t$(Q) mv lib/ex_unit/ebin/* lib/ex_unit/tmp/ebin_reproducible/\n\t$(Q) mv lib/iex/ebin/* lib/iex/tmp/ebin_reproducible/\n\t$(Q) mv lib/logger/ebin/* lib/logger/tmp/ebin_reproducible/\n\t$(Q) mv lib/mix/ebin/* lib/mix/tmp/ebin_reproducible/\n\t$(Q) rm -rf lib/*/ebin\n\tSOURCE_DATE_EPOCH=$(call READ_SOURCE_DATE_EPOCH) \"$(MAKE)\" compile\n\t$(Q) echo \"Diffing...\"\n\t$(Q) bin/elixir lib/elixir/scripts/diff.exs lib/elixir/ebin/ lib/elixir/tmp/ebin_reproducible/\n\t$(Q) bin/elixir lib/elixir/scripts/diff.exs lib/eex/ebin/ lib/eex/tmp/ebin_reproducible/\n\t$(Q) bin/elixir lib/elixir/scripts/diff.exs lib/ex_unit/ebin/ lib/ex_unit/tmp/ebin_reproducible/\n\t$(Q) bin/elixir lib/elixir/scripts/diff.exs lib/iex/ebin/ lib/iex/tmp/ebin_reproducible/\n\t$(Q) bin/elixir lib/elixir/scripts/diff.exs lib/logger/ebin/ lib/logger/tmp/ebin_reproducible/\n\t$(Q) bin/elixir lib/elixir/scripts/diff.exs lib/mix/ebin/ lib/mix/tmp/ebin_reproducible/\n\t$(Q) echo \"Builds are reproducible\"\n\nclean: clean_man\n\trm -rf ebin\n\trm -rf lib/*/ebin\n\trm -rf $(PARSER)\n\trm -rf lib/*/_build/\n\trm -rf lib/*/tmp/\n\trm -rf lib/elixir/test/ebin/\n\trm -rf lib/mix/test/fixtures/deps_on_git_repo/\n\trm -rf lib/mix/test/fixtures/git_rebar/\n\trm -rf lib/mix/test/fixtures/git_repo/\n\trm -rf lib/mix/test/fixtures/git_sparse_repo/\n\trm -rf lib/mix/test/fixtures/archive/ebin/\n\trm -f erl_crash.dump\n\trm -rf cover\n\nclean_elixir:\n\t$(Q) rm -f lib/*/ebin/Elixir.*.beam\n\n#==> Documentation tasks\n\nSOURCE_REF = $(shell tag=\"$(call GIT_TAG)\" revision=\"$(call GIT_REVISION)\"; echo \"$${tag:-$$revision}\")\nDOCS_COMPILE = CANONICAL=$(CANONICAL) bin/elixir ../ex_doc/bin/ex_doc \"$(1)\" \"$(VERSION)\" \"lib/$(2)/ebin\" --main \"$(3)\" --source-url \"https://github.com/elixir-lang/elixir\" --source-ref \"$(call SOURCE_REF)\" --logo lib/elixir/pages/images/logo.png --output doc/$(2) --canonical \"https://hexdocs.pm/$(2)/$(CANONICAL)\" --homepage-url \"https://elixir-lang.org/docs.html\" $(DOCS_OPTIONS) $(4)\nDOCS_CONFIG = bin/elixir lib/elixir/scripts/docs_config.exs \"$(1)\"\n\ndocs: compile ../ex_doc/bin/ex_doc docs_elixir docs_eex docs_mix docs_iex docs_ex_unit docs_logger\n\ndocs_elixir: compile ../ex_doc/bin/ex_doc\n\t@ echo \"==> ex_doc (elixir)\"\n\t$(Q) rm -rf doc/elixir\n\t$(call DOCS_COMPILE,Elixir,elixir,Kernel,--config \"lib/elixir/scripts/elixir_docs.exs\")\n\t$(call DOCS_CONFIG,elixir)\n\ndocs_eex: compile ../ex_doc/bin/ex_doc\n\t@ echo \"==> ex_doc (eex)\"\n\t$(Q) rm -rf doc/eex\n\t$(call DOCS_COMPILE,EEx,eex,EEx,--config \"lib/elixir/scripts/mix_docs.exs\")\n\t$(call DOCS_CONFIG,eex)\n\ndocs_mix: compile ../ex_doc/bin/ex_doc\n\t@ echo \"==> ex_doc (mix)\"\n\t$(Q) rm -rf doc/mix\n\t$(call DOCS_COMPILE,Mix,mix,Mix,--config \"lib/elixir/scripts/mix_docs.exs\")\n\t$(call DOCS_CONFIG,mix)\n\ndocs_iex: compile ../ex_doc/bin/ex_doc\n\t@ echo \"==> ex_doc (iex)\"\n\t$(Q) rm -rf doc/iex\n\t$(call DOCS_COMPILE,IEx,iex,IEx,--config \"lib/elixir/scripts/mix_docs.exs\")\n\t$(call DOCS_CONFIG,iex)\n\ndocs_ex_unit: compile ../ex_doc/bin/ex_doc\n\t@ echo \"==> ex_doc (ex_unit)\"\n\t$(Q) rm -rf doc/ex_unit\n\t$(call DOCS_COMPILE,ExUnit,ex_unit,ExUnit,--config \"lib/elixir/scripts/mix_docs.exs\")\n\t$(call DOCS_CONFIG,ex_unit)\n\ndocs_logger: compile ../ex_doc/bin/ex_doc\n\t@ echo \"==> ex_doc (logger)\"\n\t$(Q) rm -rf doc/logger\n\t$(call DOCS_COMPILE,Logger,logger,Logger,--config \"lib/elixir/scripts/mix_docs.exs\")\n\t$(call DOCS_CONFIG,logger)\n\n../ex_doc/bin/ex_doc:\n\t@ echo \"ex_doc is not found in ../ex_doc as expected. See CONTRIBUTING.md for more information.\"\n\t@ false\n\n#==> Zip tasks\n\nDocs.zip: docs\n\trm -f Docs.zip\n\tzip -9 -r Docs.zip CHANGELOG.md doc LICENSE README.md\n\t@ echo \"Docs file created $(CURDIR)/Docs.zip\"\n\nPrecompiled.zip: build_man compile\n\trm -f Precompiled.zip\n\tzip -9 -r Precompiled.zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE Makefile man README.md VERSION\n\t@ echo \"Precompiled file created $(CURDIR)/Precompiled.zip\"\n\n#==> Test tasks\n\ntest: test_formatted test_erlang test_elixir\n\ntest_windows: test test_taskkill\n\ntest_taskkill:\n\ttaskkill //IM erl.exe //F //T //FI \"MEMUSAGE gt 0\"\n\ttaskkill //IM epmd.exe //F //T //FI \"MEMUSAGE gt 0\"\n\nTEST_ERL = lib/elixir/test/erlang\nTEST_EBIN = lib/elixir/test/ebin\nTEST_ERLS = $(addprefix $(TEST_EBIN)/, $(addsuffix .beam, $(basename $(notdir $(wildcard $(TEST_ERL)/*.erl)))))\n\ndefine FORMAT\n\t$(Q) if [ \"$(OS)\" = \"Windows_NT\" ]; then \\\n\t\tcmd //C call ./bin/mix.bat format $(1); \\\n\telse \\\n\t\tbin/elixir bin/mix format $(1); \\\n\tfi\nendef\n\nformat: compile\n\t$(call FORMAT)\n\ntest_formatted: compile\n\t$(call FORMAT,--check-formatted)\n\ntest_erlang: compile $(TEST_ERLS)\n\t@ echo \"==> elixir (eunit)\"\n\t$(Q) $(ERL) -pa $(TEST_EBIN) -s test_helper test;\n\t@ echo \"\"\n\n$(TEST_EBIN)/%.beam: $(TEST_ERL)/%.erl\n\t$(Q) mkdir -p $(TEST_EBIN)\n\t$(Q) $(ERLC) -o $(TEST_EBIN) $<\n\ntest_elixir: test_stdlib test_ex_unit test_logger test_eex test_iex test_mix\n\ntest_stdlib: compile\n\t@ echo \"==> elixir (ex_unit)\"\n\t$(Q) exec epmd & exit\n\t$(Q) if [ \"$(OS)\" = \"Windows_NT\" ]; then \\\n\t\tcd lib/elixir && cmd //C call ../../bin/elixir.bat --sname primary -r \"test/elixir/test_helper.exs\" -pr \"test/elixir/**/$(TEST_FILES)\"; \\\n\telse \\\n\t\tcd lib/elixir && ../../bin/elixir --sname primary -r \"test/elixir/test_helper.exs\" -pr \"test/elixir/**/$(TEST_FILES)\"; \\\n\tfi\n\ncover/ex_unit_elixir.coverdata:\n\t$(Q) COVER=\"1\" $(MAKE) test_stdlib\ncover/combined.coverdata: cover/ex_unit_elixir.coverdata\n\ncover/combined.coverdata:\n\tbin/elixir ./lib/elixir/scripts/cover.exs\n\ncover: cover/combined.coverdata\n\n#==> Dialyzer tasks\n\nDIALYZER_OPTS = --no_check_plt --fullpath -Werror_handling -Wunmatched_returns -Wunderspecs\nPLT = .elixir.plt\n\n$(PLT):\n\t@ echo \"==> Building PLT with Elixir's dependencies...\"\n\t$(Q) dialyzer --output_plt $(PLT) --build_plt --apps erts kernel stdlib compiler syntax_tools parsetools tools ssl inets crypto runtime_tools ftp tftp mnesia public_key asn1 sasl\n\nclean_plt:\n\t$(Q) rm -f $(PLT)\n\nbuild_plt: clean_plt $(PLT)\n\ndialyze: compile $(PLT)\n\t@ echo \"==> Dialyzing Elixir...\"\n\t$(Q) dialyzer -pa lib/elixir/ebin --plt $(PLT) $(DIALYZER_OPTS) lib/*/ebin\n\n#==> Man page tasks\n\nbuild_man: man/iex.1 man/elixir.1\n\ndefine BUILD_MANPAGES\nman/$(APP).1:\n\t$(Q) cp man/$(APP).1.in man/$(APP).1\n\t$(Q) sed -i.bak \"/{COMMON}/r man/common\" man/$(APP).1\n\t$(Q) sed -i.bak \"/{COMMON}/d\" man/$(APP).1\n\t$(Q) rm -f man/$(APP).1.bak\nendef\n\n$(foreach APP, elixir iex, $(eval $(BUILD_MANPAGES)))\n\nclean_man:\n\trm -f man/elixir.1\n\trm -f man/elixir.1.bak\n\trm -f man/iex.1\n\trm -f man/iex.1.bak\n\ninstall_man: build_man\n\t$(Q) mkdir -p $(DESTDIR)$(MAN_PREFIX)/man1\n\t$(Q) $(INSTALL_DATA) man/elixir.1  $(DESTDIR)$(MAN_PREFIX)/man1\n\t$(Q) $(INSTALL_DATA) man/elixirc.1 $(DESTDIR)$(MAN_PREFIX)/man1\n\t$(Q) $(INSTALL_DATA) man/iex.1     $(DESTDIR)$(MAN_PREFIX)/man1\n\t$(Q) $(INSTALL_DATA) man/mix.1     $(DESTDIR)$(MAN_PREFIX)/man1\n\t\"$(MAKE)\" clean_man\n"
  },
  {
    "path": "OPEN_SOURCE_POLICY.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Open Source Policy\n\n## 1. Introduction\n\nThis Open Source Policy outlines the licensing, contribution, and compliance\nrequirements for all code released under the Elixir project. By adhering to\nthese guidelines, we ensure that our community, maintainers, and contributors\nuphold both legal and ethical standards while fostering a collaborative,\ntransparent environment.\n\nThis policy exists to support and protect the Elixir community. It aims to\nbalance openness, collaboration, and respect for all contributors’ rights,\nensuring that Elixir remains a trusted and innovative open source project.\n\n## 2. Scope\n\nThis policy applies to the Elixir Programming language, located at\n<https://github.com/elixir-lang/elixir>. It covers every file, and contribution\nmade, including documentation and any associated assets.\n\n## 3. Licensing\n\nAll code released by the Elixir team is licensed under the\n[Apache-2.0](./LICENSES/Apache-2.0.txt) license. Additionally, the following\nlicenses are recognized as permissible in this project:\n\n  - The Unicode license, as documented at\n    [LicenseRef-scancode-unicode](./LICENSES/LicenseRef-scancode-unicode.txt)\n\n  - The Elixir Trademark Policy, as documented at\n    [LicenseRef-elixir-trademark-policy](./LICENSES/LicenseRef-elixir-trademark-policy.txt)\n\nThese licenses are considered acceptable for any files or code that form part of\nan Elixir repository. If a contribution requires a different license, it must\neither be rejected or prompt an update to this policy.\n\n## 4. Contributing to the Elixir repository\n\nAny code contributed to the Elixir repository must fall under one of the accepted\nlicenses (Apache-2.0, Unicode, or Elixir Trademark). Contributions under any\nother license will be rejected unless this policy is formally revised to include\nthat license. All files except those specifically exempted (e.g., certain test\nfixture files) must contain SPDX license and copyright headers\n(`SPDX-License-Identifier` and `SPDX-FileCopyrightText`). If a file qualifies\nfor an exception, this must be configured in the ORT (Open Source Review Toolkit)\nconfiguration and undergo review.\n\nContributions must not introduce executable binary files into the codebase.\n\n## 5. Preservation of Copyright and License Information\n\nAny third-party code incorporated into the Elixir repository must retain original\ncopyright and license headers. If no such headers exist in the source, they must\nbe added. This practice ensures that original authors receive proper credit and\nthat the licensing lineage is preserved.\n\n## 6. Objectives\n\nThe Elixir project aims to promote a culture of responsible open source usage.\nSpecifically, our objectives include:\n\n### 6.1 Clearly Define and Communicate Licensing & Compliance Policies\n\nWe will identify and document all third-party dependencies, ensure that license\ninformation is communicated clearly, and maintain a project-wide license policy\nor compliance handbook.\n\n### 6.2 Implement Clear Processes for Reviewing Contributions\n\nWe will provide well-defined contribution guidelines. We implement the\nDeveloper Certificate of Origin (DCO) for additional clarity regarding\ncontributor rights and obligations.\n\n### 6.3 Track and Audit Third-Party Code Usage\n\nAll projects will implement a Software Bill of Materials (SBoM) strategy and\nregularly verify license compliance for direct and transitive dependencies.\n\n### 6.4 Monitor and Continuously Improve Open Source Compliance\n\nWe will conduct periodic internal audits, integrate compliance checks into\ncontinuous integration (CI/CD) pipelines, and regularly review and refine these\nobjectives to align with best practices.\n\n## 7. Roles and Responsibilities\n\n### 7.1 Core Team Member\n\nCore Team Members are responsible for being familiar with this policy and\nensuring it is consistently enforced. They must demonstrate sufficient\ncompetencies to understand the policy requirements and must reject or request\nchanges to any pull requests that violate these standards.\n\n### 7.2 Contributor\n\nContributors are expected to follow this policy when submitting code. If a\ncontributor submits a pull request that does not comply with the policy\n(e.g., introduces a disallowed license), Core Team Members have the authority to\nreject it or request changes. No special competencies are required for\ncontributors beyond awareness and adherence to the policy.\n\n### 7.3 EEF CISO\n\nThe CISO designated by the Erlang Ecosystem Foundation (EEF) provides oversight\non queries and guidance regarding open source compliance or legal matters for\nElixir. The CISO is responsible for checking ongoing compliance with the policy,\nescalating potential violations to the Core Team, and involving legal counsel if\nnecessary. This role does not require legal expertise but does involve\ninitiating legal or community discussions when needed.\n\n## 8. Implications of Failing to Follow the Program Requirements\n\nIf a violation of this policy is identified, the Elixir Core Team will undertake\nthe following actions:\n\n## 8.1 Review the Codebase for Additional Violations\n\nWe will investigate the codebase thoroughly to detect any similar instances of\nnon-compliance.\n\n## 8.2 Review and Update the Process or Policy\n\nIn collaboration with the EEF CISO, the Elixir Core Team will assess the policy\nand our internal workflows, making any necessary clarifications or amendments to\nreduce the likelihood of recurrence.\n\n## 8.3 Notify and Train Core Team Members\n\nWe will ensure that all active Core Team Members are informed about any policy\nchanges and understand how to apply them in everyday development.\n\n## 8.4 Remove or Replace the Offending Code\n\nIf required, we will remove or replace the non-compliant code.\n\n## 9. Contact\n\nThe project maintains a private mailing list at\n[policy@elixir-lang.org](mailto:policy@elixir-lang.org) for handling licensing\nand policy-related queries. Email is the preferred communication channel, and\nthe EEF CISO will be included on this list to provide assistance and ensure\ntimely responses. While solutions may take longer to implement, the project\ncommits to acknowledging all queries within five business days.\n\n## 10. External Contributions of Core Team Members\n\nWhen Core Team Members contribute to repositories outside Elixir, they do so in\na personal capacity or via their employer. They will not act as official\nrepresentatives of the Elixir team in those external contexts.\n\n## 11. Policy Review and Amendments\n\nThis policy will be revisited annually to address new concerns, accommodate\nchanges in community standards, or adjust to emerging legal or technical\nrequirements. Proposed amendments must be reviewed by the Core Team and, if\nnecessary, by the EEF CISO. Any significant changes will be communicated to\ncontributors and made publicly available.\n\n*Effective Date: 2025-02-20*  \n*Last Reviewed: 2025-11-20*\n"
  },
  {
    "path": "README.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n<h1>\n <picture>\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/elixir-lang/elixir-lang.github.com/raw/main/images/logo/logo-dark.png\">\n  <img alt=\"Elixir logo\" src=\"https://github.com/elixir-lang/elixir-lang.github.com/raw/main/images/logo/logo.png\" width=\"200\">\n </picture>\n</h1>\n\n[![CI](https://github.com/elixir-lang/elixir/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/elixir-lang/elixir/actions/workflows/ci.yml?query=branch%3Amain)\n[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/10187/badge)](https://www.bestpractices.dev/projects/10187)\n\nElixir is a dynamic, functional language designed for building scalable\nand maintainable applications.\n\nFor more about Elixir, installation and documentation,\n[check Elixir's website](https://elixir-lang.org/).\n\n## Policies\n\nNew releases are announced in the [announcement mailing list][8].\nYou can subscribe by sending an email to <elixir-lang-ann+subscribe@googlegroups.com>\nand replying to the confirmation email.\n\nAll security releases [will be tagged with `[security]`][10]. For more\ninformation, please read our [Security Policy][9].\n\nAll interactions in our official communication channels follow our\n[Code of Conduct][1].\n\nAll contributions are required to conform to our [Open Source Policy][11].\n\n## Bug reports\n\nFor reporting bugs, [visit our issue tracker][2] and follow the steps\nfor reporting a new issue. **Please disclose security vulnerabilities\nprivately [in our Security page](https://github.com/elixir-lang/elixir/security)**.\n\nAll currently open bugs related to Elixir are listed in the issues tracker.\nThe Elixir team uses the issues tracker to focus on *actionable items*,\nincluding planned enhancements in the short and medium term. We also do\nour best to label entries for clarity and to ease collaboration.\n\nOur *actionable item policy* has some important consequences, such as:\n\n  * Proposing new features as well as requests for support, help, and\n    guidance must be done in their own spaces, detailed next.\n\n  * Issues we have identified to be outside of Elixir's scope,\n    such as an upstream bug, will be closed (and requested to be moved\n    elsewhere if appropriate).\n\n  * We actively close unrelated and non-actionable issues to keep the\n    issues tracker tidy. If you believe we got something wrong, drop a\n    comment and we can always reopen the issue.\n\nBy keeping the overall issues tracker tidy and organized, the community\ncan easily peek at what is coming in new releases and also get involved\nby commenting on existing issues and submitting pull requests. Please\nremember to keep the tone positive and be kind! For more information,\nsee the [Code of Conduct][1].\n\n## Discussions, support, and help\n\nFor general discussions, support, and help, please use the community\nspaces [listed on the sidebar of the Elixir website](https://elixir-lang.org/),\nsuch as forums, chat platforms, etc, where the wider community will be available\nto help you.\n\n## Proposing new features\n\nWe encourage you to first propose new features in the community spaces\nlisted above. These discussions help refine ideas and gather feedback before\nsubmission. Our website also includes [a general outline of the language\nhistory and its current development focus](https://elixir-lang.org/development.html).\n\nOnce you are ready, you can submit your proposal to the [Elixir Core\nmailing list][3], either through the web interface or by subscribing to\nit at <elixir-lang-core+subscribe@googlegroups.com>. Remember to include\na clear problem description, compare the proposed solution to existing\nalternatives in the Elixir ecosystem (and in other languages if possible),\nand consider the potential impact your changes will have on the codebase and\ncommunity.\n\nOnce a proposal is accepted, it will be added to [the issue tracker][2].\nFeatures and bug fixes that have already been merged and will be included\nin the next release are then \"closed\" and added to the [changelog][7]\nbefore release.\n\n## Compiling from source\n\nFor the many different ways to install Elixir,\n[see our installation instructions on the website](https://elixir-lang.org/install.html).\nHowever, if you want to contribute to Elixir, you will need to compile from source.\n\nFirst, [install Erlang](https://elixir-lang.org/install.html#installing-erlang).\nAfter that, clone this repository to your machine, compile and test it:\n\n```sh\ngit clone https://github.com/elixir-lang/elixir.git\ncd elixir\nmake\n```\n\n> Note: if you are running on Windows,\n[this article includes important notes for compiling Elixir from source\non Windows](https://github.com/elixir-lang/elixir/wiki/Windows).\n\nIn case you want to use this Elixir version as your system version,\nyou need to add the `bin` directory to [your PATH environment variable](https://elixir-lang.org/install.html#setting-path-environment-variable).\n\nWhen updating the repository, you may want to run `make clean` before\nrecompiling. For deterministic builds, you should set the environment\nvariable `ERL_COMPILER_OPTIONS=deterministic`.\n\n## Contributing\n\nContributions to Elixir are always welcome! Before you get started, please check\nout our [CONTRIBUTING.md](CONTRIBUTING.md) file. There you will find detailed\nguidelines on how to set up your environment, run the test suite, format your\ncode, and submit pull requests. We also include information on our review\nprocess, licensing requirements, and helpful tips to ensure a smooth\ncontribution experience.\n\n## Development links\n\n  * [Elixir Documentation][6]\n  * [Elixir Core Mailing list (development)][3]\n  * [Announcement mailing list][8]\n  * [Code of Conduct][1]\n  * [Issue tracker][2]\n  * [Changelog][7]\n  * [Security Policy][9]\n  * **[#elixir][4]** on [Libera.Chat][5] IRC\n\n  [1]: CODE_OF_CONDUCT.md\n  [2]: https://github.com/elixir-lang/elixir/issues\n  [3]: https://groups.google.com/group/elixir-lang-core\n  [4]: https://web.libera.chat/#elixir\n  [5]: https://libera.chat\n  [6]: https://elixir-lang.org/docs.html\n  [7]: CHANGELOG.md\n  [8]: https://groups.google.com/group/elixir-lang-ann\n  [9]: SECURITY.md\n  [10]: https://groups.google.com/forum/#!searchin/elixir-lang-ann/%5Bsecurity%5D%7Csort:date\n  [11]: OPEN_SOURCE_POLICY.md\n\n## License\n\n\"Elixir\" and the Elixir logo are registered trademarks of The Elixir Team.\n\nElixir source code is released under Apache License 2.0.\n\nCheck [LICENSE](LICENSE) file for more information.\n"
  },
  {
    "path": "RELEASE.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Release process\n\n## Shipping a new version\n\n1. Update version in /VERSION, bin/elixir, and bin/elixir.bat\n\n2. Ensure /CHANGELOG.md is updated, versioned and add the current date\n\n3. Update \"Compatibility and Deprecations\" if a new OTP version is supported\n\n4. Commit changes above with title \"Release vVERSION\" and push it\n\n5. Once GitHub actions completes, generate a new tag, and push it\n\n6. Wait until GitHub Actions publish artifacts to the draft release\n\n7. Copy the relevant bits from /CHANGELOG.md to the GitHub release and publish it (link to the announcement if there is one)\n\n8. Update `_data/elixir-versions.yml` (except for RCs) in `elixir-lang/elixir-lang.github.com`\n\n## Creating a new vMAJOR.MINOR branch (usually before first rc)\n\n### In the new branch\n\n1. Comment out `CANONICAL := main/` in /Makefile\n\n2. Update tables in /SECURITY.md and \"Compatibility and Deprecations\"\n\n3. Commit \"Branch out vMAJOR.MINOR\"\n\n### Back in main\n\n1. Bump /VERSION file, bin/elixir, and bin/elixir.bat\n\n2. Start new /CHANGELOG.md\n\n3. Update tables in /SECURITY.md and in \"Compatibility and Deprecations\"\n\n4. Commit \"Start vMAJOR.MINOR+1\"\n\n## Changing supported Erlang/OTP versions\n\n1. Update the table in Compatibility and Deprecations\n\n2. Update `otp_release` checks in `/Makefile` and `/lib/elixir/src/elixir.erl`\n\n3. Update relevant CI workflows in `/.github/workflows/*.yml` - for release workflows, outdated/recently added Erlang/OTP versions must run conditionally\n\n4. Remove `otp_release` version checks that are no longer needed\n"
  },
  {
    "path": "SECURITY.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Security Policy\n\n## Supported versions\n\nElixir applies bug fixes only to the latest minor branch. Security patches are available for the last 5 minor branches:\n\nElixir version | Support\n:------------- | :-----------------------------\n1.20           | Development\n1.19           | Bug fixes and security patches\n1.18           | Security patches only\n1.17           | Security patches only\n1.16           | Security patches only\n1.15           | Security patches only\n\n## Announcements\n\nNew releases are announced in the read-only [announcements mailing list](https://groups.google.com/group/elixir-lang-ann). You can subscribe by sending an email to <elixir-lang-ann+subscribe@googlegroups.com> and replying to the confirmation email. Security notifications [will be tagged with `[security]`](https://groups.google.com/forum/#!searchin/elixir-lang-ann/%5Bsecurity%5D%7Csort:date).\n\nYou may also see [all releases](https://github.com/elixir-lang/elixir/releases) and [consult all disclosed vulnerabilities](https://github.com/elixir-lang/elixir/security) on GitHub.\n\n## Reporting a vulnerability\n\n[Please disclose security vulnerabilities privately via GitHub](https://github.com/elixir-lang/elixir/security).\n"
  },
  {
    "path": "VERSION",
    "content": "1.20.0-rc.3\n"
  },
  {
    "path": "bin/elixir",
    "content": "#!/bin/sh\n\n# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nset -e\n\nELIXIR_VERSION=1.20.0-rc.3\n\nif [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ \"$1\" = \"--help\" ] || [ \"$1\" = \"-h\" ]; }; }; then\n  cat <<USAGE >&2\nUsage: $(basename \"$0\") [options] [.exs file] [data]\n\n## General options\n\n  -e \"COMMAND\"                 Evaluates the given command (*)\n  -h, --help                   Prints this message (standalone)\n  -r \"FILE\"                    Requires the given files/patterns (*)\n  -S SCRIPT                    Finds and executes the given script in \\$PATH\n  -pr \"FILE\"                   Requires the given files/patterns in parallel (*)\n  -pa \"PATH\"                   Prepends the given path to Erlang code path (*)\n  -pz \"PATH\"                   Appends the given path to Erlang code path (*)\n  -v, --version                Prints Erlang/OTP and Elixir versions (standalone)\n\n  --color, --no-color          Enables or disables ANSI coloring\n  --erl \"SWITCHES\"             Switches to be passed down to Erlang (*)\n  --eval \"COMMAND\"             Evaluates the given command, same as -e (*)\n  --logger-otp-reports BOOL    Enables or disables OTP reporting\n  --logger-sasl-reports BOOL   Enables or disables SASL reporting\n  --no-halt                    Does not halt the Erlang VM after execution\n  --short-version              Prints Elixir version (standalone)\n\nOptions given after the .exs file or -- are passed down to the executed code.\nOptions can be passed to the Erlang runtime using \\$ELIXIR_ERL_OPTIONS or --erl.\n\n## Distribution options\n\nThe following options are related to node distribution.\n\n  --cookie COOKIE              Sets a cookie for this distributed node\n  --hidden                     Makes a hidden node\n  --name NAME                  Makes and assigns a name to the distributed node\n  --rpc-eval NODE \"COMMAND\"    Evaluates the given command on the given remote node (*)\n  --sname NAME                 Makes and assigns a short name to the distributed node\n\n--name and --sname may be set to undefined so one is automatically generated.\n\n## Release options\n\nThe following options are generally used under releases.\n\n  --boot \"FILE\"                Uses the given FILE.boot to start the system\n  --boot-var VAR \"VALUE\"       Makes \\$VAR available as VALUE to FILE.boot (*)\n  --erl-config \"FILE\"          Loads configuration in FILE.config written in Erlang (*)\n  --pipe-to \"PIPEDIR\" \"LOGDIR\" Starts the Erlang VM as a named PIPEDIR and LOGDIR\n  --vm-args \"FILE\"             Passes the contents in file as arguments to the VM\n\n--pipe-to starts Elixir detached from console (Unix-like only).\nIt will attempt to create PIPEDIR and LOGDIR if they don't exist.\nSee run_erl to learn more. To reattach, run: to_erl PIPEDIR.\n\n** Options marked with (*) can be given more than once.\n** Standalone options can't be combined with other options.\nUSAGE\n  exit 1\nfi\n\nreadlink_f () {\n  cd \"$(dirname \"$1\")\" > /dev/null\n  filename=\"$(basename \"$1\")\"\n  if [ -h \"$filename\" ]; then\n    readlink_f \"$(readlink \"$filename\")\"\n  else\n    echo \"$(pwd -P)/$filename\"\n  fi\n}\n\nif [ $# -eq 1 ] && [ \"$1\" = \"--short-version\" ]; then\n  echo \"$ELIXIR_VERSION\"\n  exit 0\nfi\n\n# Stores static Erlang arguments and --erl (which is passed as is)\nERL=\"\"\n\n# Stores erl arguments preserving spaces/quotes (mimics an array)\nerl_set () {\n  eval \"E${E}=\\$1\"\n  E=$((E + 1))\n}\n\n# Checks if a string starts with prefix. Usage: starts_with \"$STRING\" \"$PREFIX\"\nstarts_with () {\n  case $1 in\n    \"$2\"*) true;;\n    *) false;;\n  esac\n}\n\nERL_EXEC=\"erl\"\nMODE=\"cli\"\nI=1\nE=0\nLENGTH=$#\nset -- \"$@\" -extra\n\nwhile [ $I -le $LENGTH ]; do\n  # S counts to be shifted, C counts to be copied\n  S=0\n  C=0\n  case \"$1\" in\n    +elixirc)\n        C=1\n        ;;\n    +iex)\n        C=1\n        MODE=\"iex\"\n        ;;\n    -v|--no-halt|--color|--no-color)\n        C=1\n        ;;\n    -e|-r|-pr|-pa|-pz|--eval|--remsh|--dot-iex|--dbg)\n        C=2\n        ;;\n    --rpc-eval)\n        C=3\n        ;;\n    --hidden)\n        S=1\n        ERL=\"$ERL -hidden\"\n        ;;\n    --logger-otp-reports)\n        S=2\n        if [ \"$2\" = 'true' ] || [ \"$2\" = 'false' ]; then\n          ERL=\"$ERL -logger handle_otp_reports $2\"\n        fi\n        ;;\n    --logger-sasl-reports)\n        S=2\n        if [ \"$2\" = 'true' ] || [ \"$2\" = 'false' ]; then\n          ERL=\"$ERL -logger handle_sasl_reports $2\"\n        fi\n        ;;\n    --erl)\n        S=2\n        ERL=\"$ERL $2\"\n        ;;\n    --cookie)\n        S=2\n        erl_set \"-setcookie\"\n        erl_set \"$2\"\n        ;;\n    --sname|--name)\n        S=2\n        erl_set \"$(echo \"$1\" | cut -c 2-)\"\n        erl_set \"$2\"\n        ;;\n    --erl-config)\n        S=2\n        erl_set \"-config\"\n        erl_set \"$2\"\n        ;;\n    --vm-args)\n        S=2\n        erl_set \"-args_file\"\n        erl_set \"$2\"\n        ;;\n    --boot)\n        S=2\n        erl_set \"-boot\"\n        erl_set \"$2\"\n        ;;\n    --boot-var)\n        S=3\n        erl_set \"-boot_var\"\n        erl_set \"$2\"\n        erl_set \"$3\"\n        ;;\n    --pipe-to)\n        S=3\n        RUN_ERL_PIPE=\"$2\"\n        RUN_ERL_LOG=\"$3\"\n        if [ \"$(starts_with \"$RUN_ERL_PIPE\" \"-\")\" ]; then\n          echo \"--pipe-to : PIPEDIR cannot be a switch\" >&2 && exit 1\n        elif [ \"$(starts_with \"$RUN_ERL_LOG\" \"-\")\" ]; then\n          echo \"--pipe-to : LOGDIR cannot be a switch\" >&2 && exit 1\n        fi\n        ;;\n    *)\n        while [ $I -le $LENGTH ]; do\n          I=$((I + 1))\n          set -- \"$@\" \"$1\"\n          shift\n        done\n        break\n        ;;\n  esac\n\n  while [ $I -le $LENGTH ] && [ $C -gt 0 ]; do\n    C=$((C - 1))\n    I=$((I + 1))\n    set -- \"$@\" \"$1\"\n    shift\n  done\n\n  I=$((I + S))\n  shift $S\ndone\n\nI=$((E - 1))\nwhile [ $I -ge 0 ]; do\n  eval \"VAL=\\$E$I\"\n  set -- \"$VAL\" \"$@\"\n  I=$((I - 1))\ndone\n\nSELF=$(readlink_f \"$0\")\nSCRIPT_PATH=$(dirname \"$SELF\")\n\nif [ \"$OSTYPE\" = \"cygwin\" ]; then SCRIPT_PATH=$(cygpath -m \"$SCRIPT_PATH\"); fi\nif [ \"$MODE\" != \"iex\" ]; then ERL=\"-s elixir start_cli $ERL\"; fi\n\n# One MAY change ERTS_BIN= but you MUST NOT change\n# ERTS_BIN=$ERTS_BIN as it is handled by Elixir releases.\nERTS_BIN=\nERTS_BIN=\"$ERTS_BIN\"\n\nset -- \"$ERTS_BIN$ERL_EXEC\" -noshell -elixir_root \"$SCRIPT_PATH\"/../lib -pa \"$SCRIPT_PATH\"/../lib/elixir/ebin $ELIXIR_ERL_OPTIONS $ERL \"$@\"\n\nif [ -n \"$RUN_ERL_PIPE\" ]; then\n  ESCAPED=\"\"\n  for PART in \"$@\"; do\n    ESCAPED=\"$ESCAPED $(printf '%s' \"$PART\" | sed 's@[^a-zA-Z0-9_/-]@\\\\&@g')\"\n  done\n  mkdir -p \"$RUN_ERL_PIPE\"\n  mkdir -p \"$RUN_ERL_LOG\"\n  ERL_EXEC=\"run_erl\"\n  set -- \"$ERTS_BIN$ERL_EXEC\" -daemon \"$RUN_ERL_PIPE/\" \"$RUN_ERL_LOG/\" \"$ESCAPED\"\nfi\n\nif [ -n \"$ELIXIR_CLI_DRY_RUN\" ]; then\n  echo \"$@\"\nelse\n  exec \"$@\"\nfi\n"
  },
  {
    "path": "bin/elixir.bat",
    "content": "@echo off\n\n:: SPDX-License-Identifier: Apache-2.0\n:: SPDX-FileCopyrightText: 2021 The Elixir Team\n:: SPDX-FileCopyrightText: 2012 Plataformatec\n\nset ELIXIR_VERSION=1.20.0-rc.3\n\nif    \"\"%1\"\"==\"\"\"\"                if \"\"%2\"\"==\"\"\"\" goto documentation\nif /I \"\"%1\"\"==\"\"--help\"\"          if \"\"%2\"\"==\"\"\"\" goto documentation\nif /I \"\"%1\"\"==\"\"-h\"\"              if \"\"%2\"\"==\"\"\"\" goto documentation\nif /I \"\"%1\"\"==\"\"/h\"\"              if \"\"%2\"\"==\"\"\"\" goto documentation\nif    \"\"%1\"\"==\"\"/?\"\"              if \"\"%2\"\"==\"\"\"\" goto documentation\nif /I \"\"%1\"\"==\"\"--short-version\"\" if \"\"%2\"\"==\"\"\"\" goto shortversion\ngoto parseopts\n\n:documentation\necho Usage: %~nx0 [options] [.exs file] [data]\necho.\necho ## General options\necho.\necho   -e \"COMMAND\"                 Evaluates the given command (*)\necho   -h, --help                   Prints this message (standalone)\necho   -r \"FILE\"                    Requires the given files/patterns (*)\necho   -S SCRIPT                    Finds and executes the given script in $PATH\necho   -pr \"FILE\"                   Requires the given files/patterns in parallel (*)\necho   -pa \"PATH\"                   Prepends the given path to Erlang code path (*)\necho   -pz \"PATH\"                   Appends the given path to Erlang code path (*)\necho   -v, --version                Prints Erlang/OTP and Elixir versions (standalone)\necho.\necho   --color, --no-color          Enables or disables ANSI coloring\necho   --erl \"SWITCHES\"             Switches to be passed down to Erlang (*)\necho   --eval \"COMMAND\"             Evaluates the given command, same as -e (*)\necho   --logger-otp-reports BOOL    Enables or disables OTP reporting\necho   --logger-sasl-reports BOOL   Enables or disables SASL reporting\necho   --no-halt                    Does not halt the Erlang VM after execution\necho   --short-version              Prints Elixir version (standalone)\necho.\necho Options given after the .exs file or -- are passed down to the executed code.\necho Options can be passed to the Erlang runtime using $ELIXIR_ERL_OPTIONS or --erl.\necho.\necho ## Distribution options\necho.\necho The following options are related to node distribution.\necho.\necho   --cookie COOKIE              Sets a cookie for this distributed node\necho   --hidden                     Makes a hidden node\necho   --name NAME                  Makes and assigns a name to the distributed node\necho   --rpc-eval NODE \"COMMAND\"    Evaluates the given command on the given remote node (*)\necho   --sname NAME                 Makes and assigns a short name to the distributed node\necho.\necho --name and --sname may be set to undefined so one is automatically generated.\necho.\necho ## Release options\necho.\necho The following options are generally used under releases.\necho.\necho   --boot \"FILE\"                Uses the given FILE.boot to start the system\necho   --boot-var VAR \"VALUE\"       Makes $VAR available as VALUE to FILE.boot (*)\necho   --erl-config \"FILE\"          Loads configuration in FILE.config written in Erlang (*)\necho   --vm-args \"FILE\"             Passes the contents in file as arguments to the VM\necho.\necho --pipe-to is not supported on Windows. If set, Elixir won't boot.\necho.\necho ** Options marked with (*) can be given more than once.\necho ** Standalone options can't be combined with other options.\ngoto end\n\n:shortversion\necho %ELIXIR_VERSION%\ngoto end\n\n:parseopts\nsetlocal enabledelayedexpansion\n\nrem Parameters for Erlang\nset parsErlang=\n\nrem Optional parameters before the \"-extra\" parameter\nset beforeExtra=\n\nrem Option which determines whether the loop is over\nset endLoop=0\n\nrem Designates the path to the current script\nset SCRIPT_PATH=%~dp0\n\nrem Designates the path to the ERTS system\nset ERTS_BIN=\nset ERTS_BIN=!ERTS_BIN!\n\nrem Recursive loop called for each parameter that parses the cmd line parameters\n:startloop\nset \"par=%~1\"\nif \"!par!\"==\"\" (\n  rem skip if no parameter\n  goto run\n)\nshift\nset par=\"!par:\"=\\\"!\"\nrem ******* EXECUTION OPTIONS **********************\nif !par!==\"+iex\"     (set useIEx=1 && goto startloop)\nif !par!==\"+elixirc\" (goto startloop)\nrem ******* ELIXIR PARAMETERS **********************\nif \"\"==!par:-e=!          (shift && goto startloop)\nif \"\"==!par:--eval=!      (shift && goto startloop)\nif \"\"==!par:--rpc-eval=!  (shift && shift && goto startloop)\nif \"\"==!par:-r=!          (shift && goto startloop)\nif \"\"==!par:-pr=!         (shift && goto startloop)\nif \"\"==!par:-pa=!         (shift && goto startloop)\nif \"\"==!par:-pz=!         (shift && goto startloop)\nif \"\"==!par:-v=!          (goto startloop)\nif \"\"==!par:--version=!   (goto startloop)\nif \"\"==!par:--no-halt=!   (goto startloop)\nif \"\"==!par:--color=!     (goto startloop)\nif \"\"==!par:--no-color=!  (goto startloop)\nif \"\"==!par:--remsh=!     (shift && goto startloop)\nif \"\"==!par:--dot-iex=!   (shift && goto startloop)\nif \"\"==!par:--dbg=!       (shift && goto startloop)\nrem ******* ERLANG PARAMETERS **********************\nif \"\"==!par:--boot=!                (set \"parsErlang=!parsErlang! -boot \"%~1\"\" && shift && goto startloop)\nif \"\"==!par:--boot-var=!            (set \"parsErlang=!parsErlang! -boot_var \"%~1\" \"%~2\"\" && shift && shift && goto startloop)\nif \"\"==!par:--cookie=!              (set \"parsErlang=!parsErlang! -setcookie \"%~1\"\" && shift && goto startloop)\nif \"\"==!par:--hidden=!              (set \"parsErlang=!parsErlang! -hidden\" && goto startloop)\nif \"\"==!par:--erl-config=!          (set \"parsErlang=!parsErlang! -config \"%~1\"\" && shift && goto startloop)\nif \"\"==!par:--logger-otp-reports=!  (set \"parsErlang=!parsErlang! -logger handle_otp_reports %1\" && shift && goto startloop)\nif \"\"==!par:--logger-sasl-reports=! (set \"parsErlang=!parsErlang! -logger handle_sasl_reports %1\" && shift && goto startloop)\nif \"\"==!par:--name=!                (set \"parsErlang=!parsErlang! -name \"%~1\"\" && shift && goto startloop)\nif \"\"==!par:--sname=!               (set \"parsErlang=!parsErlang! -sname \"%~1\"\" && shift && goto startloop)\nif \"\"==!par:--vm-args=!             (set \"parsErlang=!parsErlang! -args_file \"%~1\"\" && shift && goto startloop)\nif \"\"==!par:--erl=!                 (set \"beforeExtra=!beforeExtra! %~1\" && shift && goto startloop)\nif \"\"==!par:--pipe-to=!             (echo --pipe-to : Option is not supported on Windows && goto end)\n\n:run\nsetlocal disabledelayedexpansion\nif not defined useIEx (\n  set beforeExtra=-s elixir start_cli %beforeExtra%\n)\n\nset beforeExtra=-noshell -elixir_root \"%SCRIPT_PATH%..\\lib\" -pa \"%SCRIPT_PATH%..\\lib\\elixir\\ebin\" %beforeExtra%\n\nif defined ELIXIR_CLI_DRY_RUN (\n  echo \"%ERTS_BIN%erl.exe\" %ELIXIR_ERL_OPTIONS% %parsErlang% %beforeExtra% -extra %*\n) else (\n  \"%ERTS_BIN%erl.exe\" %ELIXIR_ERL_OPTIONS% %parsErlang% %beforeExtra% -extra %*\n)\nexit /B %ERRORLEVEL%\n:end\nendlocal\n"
  },
  {
    "path": "bin/elixirc",
    "content": "#!/bin/sh\n\n# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nset -e\n\nif [ $# -eq 0 ] || [ \"$1\" = \"--help\" ] || [ \"$1\" = \"-h\" ]; then\n  cat <<USAGE >&2\nUsage: $(basename \"$0\") [elixir switches] [compiler switches] [.ex files]\n\n  -h, --help                Prints this message and exits\n  -o                        The directory to output compiled files\n  -v, --version             Prints Elixir version and exits (standalone)\n\n  --ignore-module-conflict  Does not emit warnings if a module was previously defined\n  --no-debug-info           Does not attach debug info to compiled modules\n  --no-docs                 Does not attach documentation to compiled modules\n  --profile time            Profile the time to compile modules\n  --verbose                 Prints compilation status\n  --warnings-as-errors      Treats warnings as errors and return non-zero exit status\n\nOptions given after -- are passed down to the executed code.\nOptions can be passed to the Erlang runtime using \\$ELIXIR_ERL_OPTIONS.\nOptions can be passed to the Erlang compiler using \\$ERL_COMPILER_OPTIONS.\nUSAGE\n  exit 1\nfi\n\nreadlink_f () {\n  cd \"$(dirname \"$1\")\" > /dev/null\n  filename=\"$(basename \"$1\")\"\n  if [ -h \"$filename\" ]; then\n    readlink_f \"$(readlink \"$filename\")\"\n  else\n    echo \"$(pwd -P)/$filename\"\n  fi\n}\n\nSELF=$(readlink_f \"$0\")\nSCRIPT_PATH=$(dirname \"$SELF\")\nexec \"$SCRIPT_PATH\"/elixir +elixirc \"$@\"\n"
  },
  {
    "path": "bin/elixirc.bat",
    "content": "@echo off\n\n:: SPDX-License-Identifier: Apache-2.0\n:: SPDX-FileCopyrightText: 2021 The Elixir Team\n:: SPDX-FileCopyrightText: 2012 Plataformatec\n\nsetlocal\nset argc=0\nfor %%A in (%*) do (\n  if /I \"%%A\"==\"--help\" goto documentation\n  if /I \"%%A\"==\"-h\"     goto documentation\n  if /I \"%%A\"==\"/h\"     goto documentation\n  if    \"%%A\"==\"/?\"     goto documentation\n  set /A argc+=1\n)\nif %argc%==0 goto documentation\ngoto run\n\n:documentation\necho Usage: %~nx0 [elixir switches] [compiler switches] [.ex files]\necho.\necho   -h, --help                Prints this message and exits\necho   -o                        The directory to output compiled files\necho   -v, --version             Prints Elixir version and exits (standalone)\necho.\necho   --ignore-module-conflict  Does not emit warnings if a module was previously defined\necho   --no-debug-info           Does not attach debug info to compiled modules\necho   --no-docs                 Does not attach documentation to compiled modules\necho   --profile time            Profile the time to compile modules\necho   --verbose                 Prints compilation status\necho   --warnings-as-errors      Treats warnings as errors and returns non-zero exit status\necho.\necho ** Options given after -- are passed down to the executed code\necho ** Options can be passed to the Erlang runtime using ELIXIR_ERL_OPTIONS\necho ** Options can be passed to the Erlang compiler using ERL_COMPILER_OPTIONS\ngoto end\n\n:run\ncall \"%~dp0\\elixir.bat\" +elixirc %*\n\n:end\nendlocal\n"
  },
  {
    "path": "bin/iex",
    "content": "#!/bin/sh\n\n# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nset -e\n\nif [ \"$1\" = \"--help\" ] || [ \"$1\" = \"-h\" ]; then\n  cat <<USAGE >&2\nUsage: $(basename \"$0\") [options] [.exs file] [data]\n\nThe following options are exclusive to IEx:\n\n  --dbg pry           Sets the backend for Kernel.dbg/2 to IEx.pry/0\n  --dot-iex \"FILE\"    Evaluates FILE, line by line, to set up IEx' environment.\n                      Defaults to evaluating .iex.exs or ~/.iex.exs, if any exists.\n                      If FILE is empty, then no file will be loaded.\n  --remsh NAME        Connects to a node using a remote shell.\n\nIt accepts all other options listed by \"elixir --help\".\nUSAGE\n  exit 1\nfi\n\nreadlink_f () {\n  cd \"$(dirname \"$1\")\" > /dev/null\n  filename=\"$(basename \"$1\")\"\n  if [ -h \"$filename\" ]; then\n    readlink_f \"$(readlink \"$filename\")\"\n  else\n    echo \"$(pwd -P)/$filename\"\n  fi\n}\n\nSELF=$(readlink_f \"$0\")\nSCRIPT_PATH=$(dirname \"$SELF\")\nexec \"$SCRIPT_PATH\"/elixir --no-halt --erl \"-user elixir\" +iex \"$@\"\n"
  },
  {
    "path": "bin/iex.bat",
    "content": "@echo off\n\n:: SPDX-License-Identifier: Apache-2.0\n:: SPDX-FileCopyrightText: 2021 The Elixir Team\n:: SPDX-FileCopyrightText: 2012 Plataformatec\n\nsetlocal\nif /I \"\"%1\"\"==\"\"--help\"\" goto documentation\nif /I \"\"%1\"\"==\"\"-h\"\"     goto documentation\nif /I \"\"%1\"\"==\"\"/h\"\"     goto documentation\nif    \"\"%1\"\"==\"\"/?\"\"     goto documentation\ngoto run\n\n:documentation\necho Usage: %~nx0 [options] [.exs file] [data]\necho.\necho The following options are exclusive to IEx:\necho.\necho   --dbg pry           Sets the backend for Kernel.dbg/2 to IEx.pry/0\necho   --dot-iex \"FILE\"    Evaluates FILE, line by line, to set up IEx' environment.\necho                       Defaults to evaluating .iex.exs or ~/.iex.exs, if any exists.\necho                       If FILE is empty, then no file will be loaded.\necho   --remsh NAME        Connects to a node using a remote shell\necho.\necho It accepts all other options listed by \"elixir --help\".\ngoto end\n\n:run\ncall \"%~dp0\\elixir.bat\" --no-halt --erl \"-user elixir\" +iex %*\n:end\nendlocal\n"
  },
  {
    "path": "bin/mix",
    "content": "#!/usr/bin/env elixir\n\n# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nMix.CLI.main()\n"
  },
  {
    "path": "bin/mix.bat",
    "content": "@echo off\n\n:: SPDX-License-Identifier: Apache-2.0\n:: SPDX-FileCopyrightText: 2021 The Elixir Team\n:: SPDX-FileCopyrightText: 2012 Plataformatec\n\ncall \"%~dp0\\elixir.bat\" \"%~dp0\\mix\" %*\n"
  },
  {
    "path": "bin/mix.ps1",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Store path to mix.bat as a FileInfo object\n$mixBatPath = (Get-ChildItem (((Get-ChildItem $MyInvocation.MyCommand.Path).Directory.FullName) + '\\mix.bat'))\n$newArgs = @()\n\nfor ($i = 0; $i -lt $args.length; $i++)\n{\n  if ($args[$i] -is [array])\n  {\n    # Commas created the array so we need to reintroduce those commas\n    for ($j = 0; $j -lt $args[$i].length - 1; $j++)\n    {\n      $newArgs += ($args[$i][$j] + ',')\n    }\n    $newArgs += $args[$i][-1]\n  }\n  else\n  {\n    $newArgs += $args[$i]\n  }\n}\n\n# Corrected arguments are ready to pass to batch file\n& $mixBatPath $newArgs"
  },
  {
    "path": "lib/eex/lib/eex/compiler.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule EEx.Compiler do\n  @moduledoc false\n\n  # When changing this setting, don't forget to update the docs for EEx\n  @default_engine EEx.SmartEngine\n  @h_spaces [?\\s, ?\\t]\n  @all_spaces [?\\s, ?\\t, ?\\n, ?\\r]\n\n  @doc \"\"\"\n  Tokenize EEx contents.\n  \"\"\"\n  def tokenize(contents, opts) when is_binary(contents) do\n    tokenize(String.to_charlist(contents), contents, opts)\n  end\n\n  def tokenize(contents, opts) when is_list(contents) do\n    tokenize(contents, List.to_string(contents), opts)\n  end\n\n  def tokenize(contents, source, opts) when is_list(contents) do\n    file = opts[:file] || \"nofile\"\n    line = opts[:line] || 1\n    trim = opts[:trim] || false\n    indentation = opts[:indentation] || 0\n    column = indentation + (opts[:column] || 1)\n\n    state = %{trim: trim, indentation: indentation, file: file, source: source}\n\n    {contents, line, column} =\n      (trim && trim_init(contents, line, column, state)) || {contents, line, column}\n\n    tokenize(contents, line, column, state, [{line, column}], [])\n  end\n\n  defp tokenize(~c\"<%%\" ++ t, line, column, state, buffer, acc) do\n    tokenize(t, line, column + 3, state, [?%, ?< | buffer], acc)\n  end\n\n  defp tokenize(~c\"<%!--\" ++ t, line, column, state, buffer, acc) do\n    case comment(t, line, column + 5, state, []) do\n      {:error, message} ->\n        meta = %{line: line, column: column}\n        {:error, message <> code_snippet(state.source, state.indentation, meta), meta}\n\n      {:ok, new_line, new_column, rest, comments} ->\n        token = {:comment, Enum.reverse(comments), %{line: line, column: column}}\n        trim_and_tokenize(rest, new_line, new_column, state, buffer, acc, &[token | &1])\n    end\n  end\n\n  # TODO: Remove me on Elixir v2.0\n  defp tokenize(~c\"<%#\" ++ t, line, column, state, buffer, acc) do\n    IO.warn(\"<%# is deprecated, use <%!-- or add a space between <% and # instead\",\n      line: line,\n      column: column,\n      file: state.file\n    )\n\n    case expr(t, line, column + 3, state, []) do\n      {:error, message} ->\n        {:error, message, %{line: line, column: column}}\n\n      {:ok, _, new_line, new_column, rest} ->\n        trim_and_tokenize(rest, new_line, new_column, state, buffer, acc, & &1)\n    end\n  end\n\n  defp tokenize(~c\"<%\" ++ t, line, column, state, buffer, acc) do\n    {marker, t} = retrieve_marker(t)\n    marker_length = length(marker)\n\n    case expr(t, line, column + 2 + marker_length, state, []) do\n      {:error, message} ->\n        meta = %{line: line, column: column}\n        {:error, message <> code_snippet(state.source, state.indentation, meta), meta}\n\n      {:ok, expr, new_line, new_column, rest} ->\n        {key, expr} =\n          case :elixir_tokenizer.tokenize(expr, 1, file: \"eex\", check_terminators: false) do\n            {:ok, _line, _column, _warnings, rev_tokens, []} ->\n              # We ignore warnings because the code will be tokenized\n              # again later with the right line+column info\n              token_key(rev_tokens, expr)\n\n            {:error, _, _, _, _} ->\n              {:expr, expr}\n          end\n\n        marker =\n          if key in [:middle_expr, :end_expr] and marker != ~c\"\" do\n            message =\n              \"unexpected beginning of EEx tag \\\"<%#{marker}\\\" on \\\"<%#{marker}#{expr}%>\\\", \" <>\n                \"please remove \\\"#{marker}\\\"\"\n\n            IO.warn(message, file: state.file, line: line, column: column)\n            ~c\"\"\n          else\n            marker\n          end\n\n        token = {key, marker, expr, %{line: line, column: column}}\n        trim_and_tokenize(rest, new_line, new_column, state, buffer, acc, &[token | &1])\n    end\n  end\n\n  defp tokenize([?\\n | t], line, _column, state, buffer, acc) do\n    tokenize(t, line + 1, state.indentation + 1, state, [?\\n | buffer], acc)\n  end\n\n  defp tokenize([h | t], line, column, state, buffer, acc) do\n    tokenize(t, line, column + 1, state, [h | buffer], acc)\n  end\n\n  defp tokenize([], line, column, _state, buffer, acc) do\n    eof = {:eof, %{line: line, column: column}}\n    {:ok, Enum.reverse([eof | tokenize_text(buffer, acc)])}\n  end\n\n  defp trim_and_tokenize(rest, line, column, state, buffer, acc, fun) do\n    {rest, line, column, buffer} = trim_if_needed(rest, line, column, state, buffer)\n\n    acc = tokenize_text(buffer, acc)\n    tokenize(rest, line, column, state, [{line, column}], fun.(acc))\n  end\n\n  # Retrieve marker for <%\n\n  defp retrieve_marker([marker | t]) when marker in [?=, ?/, ?|] do\n    {[marker], t}\n  end\n\n  defp retrieve_marker(t) do\n    {~c\"\", t}\n  end\n\n  # Tokenize a multi-line comment until we find --%>\n\n  defp comment([?-, ?-, ?%, ?> | t], line, column, _state, buffer) do\n    {:ok, line, column + 4, t, buffer}\n  end\n\n  defp comment([?\\n | t], line, _column, state, buffer) do\n    comment(t, line + 1, state.indentation + 1, state, [?\\n | buffer])\n  end\n\n  defp comment([head | t], line, column, state, buffer) do\n    comment(t, line, column + 1, state, [head | buffer])\n  end\n\n  defp comment([], _line, _column, _state, _buffer) do\n    {:error, \"expected closing '--%>' for EEx expression\"}\n  end\n\n  # Tokenize an expression until we find %>\n\n  defp expr([?%, ?> | t], line, column, _state, buffer) do\n    {:ok, Enum.reverse(buffer), line, column + 2, t}\n  end\n\n  defp expr([?\\n | t], line, _column, state, buffer) do\n    expr(t, line + 1, state.indentation + 1, state, [?\\n | buffer])\n  end\n\n  defp expr([h | t], line, column, state, buffer) do\n    expr(t, line, column + 1, state, [h | buffer])\n  end\n\n  defp expr([], _line, _column, _state, _buffer) do\n    {:error, \"expected closing '%>' for EEx expression\"}\n  end\n\n  # Receives tokens and check if it is a start, middle or an end token.\n  defp token_key(rev_tokens, expr) do\n    case {Enum.reverse(rev_tokens), drop_eol(rev_tokens)} do\n      {[{:end, _} | _], [{:do, _} | _]} ->\n        {:middle_expr, expr}\n\n      {_, [{:do, _} | _]} ->\n        {:start_expr, maybe_append_space(expr)}\n\n      {_, [{:block_identifier, _, _} | _]} ->\n        {:middle_expr, maybe_append_space(expr)}\n\n      {[{:end, _} | _], [{:stab_op, _, _} | _]} ->\n        {:middle_expr, expr}\n\n      {_, [{:stab_op, _, _} | reverse_tokens]} ->\n        fn_index = Enum.find_index(reverse_tokens, &match?({:fn, _}, &1)) || :infinity\n        end_index = Enum.find_index(reverse_tokens, &match?({:end, _}, &1)) || :infinity\n\n        if end_index > fn_index do\n          {:start_expr, expr}\n        else\n          {:middle_expr, expr}\n        end\n\n      {tokens, _} ->\n        case Enum.drop_while(tokens, &closing_bracket?/1) do\n          [{:end, _} | _] -> {:end_expr, expr}\n          _ -> {:expr, expr}\n        end\n    end\n  end\n\n  defp drop_eol([{:eol, _} | rest]), do: drop_eol(rest)\n  defp drop_eol(rest), do: rest\n\n  defp maybe_append_space([?\\s]), do: [?\\s]\n  defp maybe_append_space([h]), do: [h, ?\\s]\n  defp maybe_append_space([h | t]), do: [h | maybe_append_space(t)]\n\n  defp closing_bracket?({closing, _}) when closing in ~w\"( [ {\"a, do: true\n  defp closing_bracket?(_), do: false\n\n  # Tokenize the buffered text by appending\n  # it to the given accumulator.\n\n  defp tokenize_text([{_line, _column}], acc) do\n    acc\n  end\n\n  defp tokenize_text(buffer, acc) do\n    [{line, column} | buffer] = Enum.reverse(buffer)\n    [{:text, buffer, %{line: line, column: column}} | acc]\n  end\n\n  ## Trim\n\n  defp trim_if_needed(rest, line, column, state, buffer) do\n    if state.trim do\n      buffer = trim_left(buffer, 0)\n      {rest, line, column} = trim_right(rest, line, column, 0, state)\n      {rest, line, column, buffer}\n    else\n      {rest, line, column, buffer}\n    end\n  end\n\n  defp trim_init([h | t], line, column, state) when h in @h_spaces,\n    do: trim_init(t, line, column + 1, state)\n\n  defp trim_init([?\\r, ?\\n | t], line, _column, state),\n    do: trim_init(t, line + 1, state.indentation + 1, state)\n\n  defp trim_init([?\\n | t], line, _column, state),\n    do: trim_init(t, line + 1, state.indentation + 1, state)\n\n  defp trim_init([?<, ?% | _] = rest, line, column, _state),\n    do: {rest, line, column}\n\n  defp trim_init(_, _, _, _), do: false\n\n  defp trim_left(buffer, count) do\n    case trim_whitespace(buffer, 0) do\n      {[?\\n, ?\\r | rest], _} -> trim_left(rest, count + 1)\n      {[?\\n | rest], _} -> trim_left(rest, count + 1)\n      _ when count > 0 -> [?\\n | buffer]\n      _ -> buffer\n    end\n  end\n\n  defp trim_right(rest, line, column, last_column, state) do\n    case trim_whitespace(rest, column) do\n      {[?\\r, ?\\n | rest], column} ->\n        trim_right(rest, line + 1, state.indentation + 1, column + 1, state)\n\n      {[?\\n | rest], column} ->\n        trim_right(rest, line + 1, state.indentation + 1, column, state)\n\n      {[], column} ->\n        {[], line, column}\n\n      _ when last_column > 0 ->\n        {[?\\n | rest], line - 1, last_column}\n\n      _ ->\n        {rest, line, column}\n    end\n  end\n\n  defp trim_whitespace([h | t], column) when h in @h_spaces, do: trim_whitespace(t, column + 1)\n  defp trim_whitespace(list, column), do: {list, column}\n\n  @doc \"\"\"\n  This is the compilation entry point. It glues the tokenizer\n  and the engine together by handling the tokens and invoking\n  the engine every time a full expression or text is received.\n  \"\"\"\n  @spec compile([EEx.token()], String.t(), keyword) :: Macro.t()\n  def compile(tokens, source, opts) do\n    file = opts[:file] || \"nofile\"\n    line = opts[:line] || 1\n    indentation = opts[:indentation] || 0\n    parser_options = opts[:parser_options] || Code.get_compiler_option(:parser_options)\n    engine = opts[:engine] || @default_engine\n\n    state = %{\n      engine: engine,\n      file: file,\n      source: source,\n      line: line,\n      quoted: [],\n      parser_options: [indentation: indentation] ++ parser_options,\n      indentation: indentation\n    }\n\n    init = state.engine.init(opts)\n\n    if function_exported?(state.engine, :handle_text, 2) and\n         not function_exported?(state.engine, :handle_text, 3) do\n      IO.warn(\n        \"#{inspect(state.engine)}.handle_text/2 is deprecated, implement handle_text/3 instead\"\n      )\n    end\n\n    generate_buffer(tokens, init, [], state)\n  end\n\n  # Ignore tokens related to comment.\n  defp generate_buffer([{:comment, _chars, _meta} | rest], buffer, scope, state) do\n    generate_buffer(rest, buffer, scope, state)\n  end\n\n  # Generates the buffers by handling each expression from the tokenizer.\n  # It returns Macro.t/0 or it raises.\n\n  defp generate_buffer([{:text, chars, meta} | rest], buffer, scope, state) do\n    buffer =\n      if function_exported?(state.engine, :handle_text, 3) do\n        meta = [line: meta.line, column: meta.column]\n        state.engine.handle_text(buffer, meta, IO.chardata_to_string(chars))\n      else\n        # TODO: Remove this on Elixir v2.0. The deprecation is on init.\n        state.engine.handle_text(buffer, IO.chardata_to_string(chars))\n      end\n\n    generate_buffer(rest, buffer, scope, state)\n  end\n\n  defp generate_buffer([{:expr, mark, chars, meta} | rest], buffer, scope, state) do\n    options =\n      [file: state.file, line: meta.line, column: column(meta.column, mark)] ++\n        state.parser_options\n\n    expr = Code.string_to_quoted!(chars, options)\n    buffer = state.engine.handle_expr(buffer, IO.chardata_to_string(mark), expr)\n    generate_buffer(rest, buffer, scope, state)\n  end\n\n  defp generate_buffer(\n         [{:start_expr, mark, chars, meta} | rest],\n         buffer,\n         scope,\n         state\n       ) do\n    {rest, line, contents} = look_ahead_middle(rest, meta.line, chars) || {rest, meta.line, chars}\n    start_line = meta.line\n    start_column = column(meta.column, mark)\n\n    {contents, rest} =\n      generate_buffer(\n        rest,\n        state.engine.handle_begin(buffer),\n        [{contents, start_line, start_column} | scope],\n        %{state | quoted: [], line: line}\n      )\n\n    if mark == ~c\"\" and not match?({:=, _, [_, _]}, contents) do\n      message =\n        \"the contents of this expression won't be output unless the EEx block starts with \\\"<%=\\\"\"\n\n      IO.warn(message, file: state.file, line: meta.line, column: meta.column)\n    end\n\n    buffer = state.engine.handle_expr(buffer, IO.chardata_to_string(mark), contents)\n    generate_buffer(rest, buffer, scope, state)\n  end\n\n  defp generate_buffer(\n         [{:middle_expr, ~c\"\", chars, meta} | rest],\n         buffer,\n         [{current, current_line, current_column} | scope],\n         state\n       ) do\n    {wrapped, state} = wrap_expr(current, meta.line, buffer, chars, state)\n    state = %{state | line: meta.line}\n\n    generate_buffer(\n      rest,\n      state.engine.handle_begin(buffer),\n      [{wrapped, current_line, current_column} | scope],\n      state\n    )\n  end\n\n  defp generate_buffer([{:middle_expr, _, chars, meta} | _tokens], _buffer, [], state) do\n    message = \"unexpected middle of expression <%#{chars}%>\"\n    syntax_error!(message, meta, state)\n  end\n\n  defp generate_buffer(\n         [{:end_expr, ~c\"\", chars, meta} | rest],\n         buffer,\n         [{current, line, column} | _],\n         state\n       ) do\n    {wrapped, state} = wrap_expr(current, meta.line, buffer, chars, state)\n    options = [file: state.file, line: line, column: column] ++ state.parser_options\n    tuples = Code.string_to_quoted!(wrapped, options)\n    buffer = insert_quoted(tuples, state.quoted)\n    {buffer, rest}\n  end\n\n  defp generate_buffer([{:end_expr, _, chars, meta} | _], _buffer, [], state) do\n    message = \"unexpected end of expression <%#{chars}%>\"\n    syntax_error!(message, meta, state)\n  end\n\n  defp generate_buffer([{:eof, _meta}], buffer, [], state) do\n    state.engine.handle_body(buffer)\n  end\n\n  defp generate_buffer([{:eof, _meta}], _buffer, [{content, line, column} | _scope], state) do\n    message = \"expected a closing '<% end %>' for block expression in EEx\"\n    expr_meta = non_whitespace_meta(content, line, column, state)\n    syntax_error!(message, expr_meta, state)\n  end\n\n  defp non_whitespace_meta([space | rest], line, column, state) when space in @h_spaces,\n    do: non_whitespace_meta(rest, line, column + 1, state)\n\n  defp non_whitespace_meta([?\\n | rest], line, _column, state),\n    do: non_whitespace_meta(rest, line + 1, state.indentation + 1, state)\n\n  defp non_whitespace_meta(_, line, column, _),\n    do: %{line: line, column: column}\n\n  # Creates a placeholder and wrap it inside the expression block\n\n  defp wrap_expr(current, line, buffer, chars, state) do\n    new_lines = List.duplicate(?\\n, line - state.line)\n    key = length(state.quoted)\n    placeholder = ~c\"__EEX__(\" ++ Integer.to_charlist(key) ++ ~c\");\"\n    count = current ++ placeholder ++ new_lines ++ chars\n    new_state = %{state | quoted: [{key, state.engine.handle_end(buffer)} | state.quoted]}\n\n    {count, new_state}\n  end\n\n  # Look middle expressions that immediately follow a start_expr\n\n  defp look_ahead_middle([{:comment, _comment, _meta} | rest], start, contents),\n    do: look_ahead_middle(rest, start, contents)\n\n  defp look_ahead_middle([{:text, text, _meta} | rest], start, contents) do\n    if only_spaces?(text) do\n      look_ahead_middle(rest, start, contents ++ text)\n    else\n      nil\n    end\n  end\n\n  defp look_ahead_middle([{:middle_expr, _, chars, meta} | rest], _start, contents) do\n    {rest, meta.line, contents ++ chars}\n  end\n\n  defp look_ahead_middle(_tokens, _start, _contents) do\n    nil\n  end\n\n  defp only_spaces?(chars) do\n    Enum.all?(chars, &(&1 in @all_spaces))\n  end\n\n  # Changes placeholder to real expression\n\n  defp insert_quoted({:__EEX__, _, [key]}, quoted) do\n    {^key, value} = List.keyfind(quoted, key, 0)\n    value\n  end\n\n  defp insert_quoted({left, line, right}, quoted) do\n    {insert_quoted(left, quoted), line, insert_quoted(right, quoted)}\n  end\n\n  defp insert_quoted({left, right}, quoted) do\n    {insert_quoted(left, quoted), insert_quoted(right, quoted)}\n  end\n\n  defp insert_quoted(list, quoted) when is_list(list) do\n    Enum.map(list, &insert_quoted(&1, quoted))\n  end\n\n  defp insert_quoted(other, _quoted) do\n    other\n  end\n\n  defp column(column, mark) do\n    # length(~c\"<%\") == 2\n    column + 2 + length(mark)\n  end\n\n  defp syntax_error!(message, meta, state) do\n    raise EEx.SyntaxError,\n      message: message,\n      snippet: code_snippet(state.source, state.indentation, meta),\n      file: state.file,\n      line: meta.line,\n      column: meta.column\n  end\n\n  defp code_snippet(source, indentation, meta) do\n    line_start = max(meta.line - 3, 1)\n    line_end = meta.line\n    digits = line_end |> Integer.to_string() |> byte_size()\n    number_padding = String.duplicate(\" \", digits)\n    indentation = String.duplicate(\" \", indentation)\n\n    source\n    |> String.split([\"\\r\\n\", \"\\n\"])\n    |> Enum.slice((line_start - 1)..(line_end - 1))\n    |> Enum.map_reduce(line_start, fn\n      expr, line_number when line_number == line_end ->\n        arrow = String.duplicate(\" \", meta.column - 1) <> \"^\"\n        {\"#{line_number} | #{indentation}#{expr}\\n #{number_padding}| #{arrow}\", line_number + 1}\n\n      expr, line_number ->\n        line_number_padding = String.pad_leading(\"#{line_number}\", digits)\n        {\"#{line_number_padding} | #{indentation}#{expr}\", line_number + 1}\n    end)\n    |> case do\n      {[], _} -> \"\"\n      {snippet, _} -> Enum.join([\"\\n #{number_padding}|\" | snippet], \"\\n\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/eex/lib/eex/engine.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule EEx.Engine do\n  @moduledoc ~S\"\"\"\n  Basic EEx engine that ships with Elixir.\n\n  An engine needs to implement all callbacks below.\n\n  This module also ships with a default engine implementation\n  you can delegate to. See `EEx.SmartEngine` as an example.\n  \"\"\"\n\n  @type state :: term\n\n  @doc \"\"\"\n  Called at the beginning of every template.\n\n  It receives the options during compilation, including the\n  ones managed by EEx, such as `:line` and `:file`, as well\n  as custom engine options.\n\n  It must return the initial state.\n  \"\"\"\n  @callback init(opts :: keyword) :: state\n\n  @doc \"\"\"\n  Called at the end of every template.\n\n  It must return Elixir's quoted expressions for the template.\n  \"\"\"\n  @callback handle_body(state) :: Macro.t()\n\n  @doc \"\"\"\n  Called for the text/static parts of a template.\n\n  It must return the updated state.\n  \"\"\"\n  @callback handle_text(state, [line: pos_integer, column: pos_integer], text :: String.t()) ::\n              state\n\n  @doc \"\"\"\n  Called for the dynamic/code parts of a template.\n\n  The marker is what follows exactly after `<%`. For example,\n  `<% foo %>` has an empty marker, but `<%= foo %>` has `\"=\"`\n  as marker. The allowed markers so far are:\n\n    * `\"\"`\n    * `\"=\"`\n    * `\"/\"`\n    * `\"|\"`\n\n  Markers `\"/\"` and `\"|\"` are only for use in custom EEx engines\n  and are not implemented by default. Using them without an\n  appropriate implementation raises `EEx.SyntaxError`.\n\n  It must return the updated state.\n  \"\"\"\n  @callback handle_expr(state, marker :: String.t(), expr :: Macro.t()) :: state\n\n  @doc \"\"\"\n  Invoked at the beginning of every nesting.\n\n  It must return a new state that is used only inside the nesting.\n  Once the nesting terminates, the current `state` is resumed.\n  \"\"\"\n  @callback handle_begin(state) :: state\n\n  @doc \"\"\"\n  Invokes at the end of a nesting.\n\n  It must return Elixir's quoted expressions for the nesting.\n  \"\"\"\n  @callback handle_end(state) :: Macro.t()\n\n  @doc false\n  @deprecated \"Use explicit delegation to EEx.Engine instead\"\n  defmacro __using__(_) do\n    quote do\n      @behaviour EEx.Engine\n\n      def init(opts) do\n        EEx.Engine.init(opts)\n      end\n\n      def handle_body(state) do\n        EEx.Engine.handle_body(state)\n      end\n\n      def handle_begin(state) do\n        EEx.Engine.handle_begin(state)\n      end\n\n      def handle_end(state) do\n        EEx.Engine.handle_end(state)\n      end\n\n      def handle_text(state, text) do\n        EEx.Engine.handle_text(state, [], text)\n      end\n\n      def handle_expr(state, marker, expr) do\n        EEx.Engine.handle_expr(state, marker, expr)\n      end\n\n      defoverridable EEx.Engine\n    end\n  end\n\n  @doc \"\"\"\n  Handles assigns in quoted expressions.\n\n  A warning will be printed on missing assigns.\n  Future versions will raise.\n\n  This can be added to any custom engine by invoking\n  `handle_assign/1` with `Macro.prewalk/2`:\n\n      def handle_expr(state, token, expr) do\n        expr = Macro.prewalk(expr, &EEx.Engine.handle_assign/1)\n        super(state, token, expr)\n      end\n\n  \"\"\"\n  @spec handle_assign(Macro.t()) :: Macro.t()\n  def handle_assign({:@, meta, [{name, _, atom}]}) when is_atom(name) and is_atom(atom) do\n    line = meta[:line] || 0\n    quote(line: line, do: EEx.Engine.fetch_assign!(var!(assigns), unquote(name)))\n  end\n\n  def handle_assign(arg) do\n    arg\n  end\n\n  @doc false\n  # TODO: Raise on v2.0\n  @spec fetch_assign!(Access.t(), Access.key()) :: term | nil\n  def fetch_assign!(assigns, key) do\n    case Access.fetch(assigns, key) do\n      {:ok, val} ->\n        val\n\n      :error ->\n        keys = Enum.map(assigns, &elem(&1, 0))\n\n        IO.warn(\n          \"assign @#{key} not available in EEx template. \" <>\n            \"Please ensure all assigns are given as options. \" <>\n            \"Available assigns: #{inspect(keys)}\"\n        )\n\n        nil\n    end\n  end\n\n  @doc \"Default implementation for `c:init/1`.\"\n  def init(_opts) do\n    %{\n      binary: [],\n      dynamic: [],\n      vars_count: 0\n    }\n  end\n\n  @doc \"Default implementation for `c:handle_begin/1`.\"\n  def handle_begin(state) do\n    check_state!(state)\n    %{state | binary: [], dynamic: []}\n  end\n\n  @doc \"Default implementation for `c:handle_end/1`.\"\n  def handle_end(quoted) do\n    handle_body(quoted)\n  end\n\n  @doc \"Default implementation for `c:handle_body/1`.\"\n  def handle_body(state) do\n    check_state!(state)\n    %{binary: binary, dynamic: dynamic} = state\n    binary = {:<<>>, [], Enum.reverse(binary)}\n    dynamic = [binary | dynamic]\n    {:__block__, [], Enum.reverse(dynamic)}\n  end\n\n  @doc \"Default implementation for `c:handle_text/3`.\"\n  def handle_text(state, _meta, text) do\n    check_state!(state)\n    %{binary: binary} = state\n    %{state | binary: [text | binary]}\n  end\n\n  @doc \"Default implementation for `c:handle_expr/3`.\"\n  def handle_expr(state, \"=\", ast) do\n    check_state!(state)\n    %{binary: binary, dynamic: dynamic, vars_count: vars_count} = state\n    var = Macro.var(:\"arg#{vars_count}\", __MODULE__)\n\n    ast =\n      quote do\n        unquote(var) = String.Chars.to_string(unquote(ast))\n      end\n\n    segment =\n      quote do\n        unquote(var) :: binary\n      end\n\n    %{state | dynamic: [ast | dynamic], binary: [segment | binary], vars_count: vars_count + 1}\n  end\n\n  def handle_expr(state, \"\", ast) do\n    %{dynamic: dynamic} = state\n    %{state | dynamic: [ast | dynamic]}\n  end\n\n  def handle_expr(_state, marker, _ast) when marker in [\"/\", \"|\"] do\n    raise EEx.SyntaxError,\n          \"unsupported EEx syntax <%#{marker} %> (the syntax is valid but not supported by the current EEx engine)\"\n  end\n\n  defp check_state!(%{binary: _, dynamic: _, vars_count: _}), do: :ok\n\n  defp check_state!(state) do\n    raise \"unexpected EEx.Engine state: #{inspect(state)}. \" <>\n            \"This typically means a bug or an outdated EEx.Engine or tool\"\n  end\nend\n"
  },
  {
    "path": "lib/eex/lib/eex/smart_engine.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule EEx.SmartEngine do\n  @moduledoc \"\"\"\n  The default engine used by EEx.\n\n  It includes assigns (like `@foo`) and possibly other\n  conveniences in the future.\n\n  ## Examples\n\n      iex> EEx.eval_string(\"<%= @foo %>\", assigns: [foo: 1])\n      \"1\"\n\n  In the example above, we can access the value `foo` under\n  the binding `assigns` using `@foo`. This is useful because\n  a template, after being compiled, can receive different\n  assigns and would not require recompilation for each\n  variable set.\n\n  Assigns can also be used when compiled to a function:\n\n      # sample.eex\n      <%= @a + @b %>\n\n      # sample.ex\n      defmodule Sample do\n        require EEx\n        EEx.function_from_file(:def, :sample, \"sample.eex\", [:assigns])\n      end\n\n      # iex\n      Sample.sample(a: 1, b: 2)\n      #=> \"3\"\n\n  \"\"\"\n\n  @behaviour EEx.Engine\n\n  @impl true\n  defdelegate init(opts), to: EEx.Engine\n\n  @impl true\n  defdelegate handle_body(state), to: EEx.Engine\n\n  @impl true\n  defdelegate handle_begin(state), to: EEx.Engine\n\n  @impl true\n  defdelegate handle_end(state), to: EEx.Engine\n\n  @impl true\n  defdelegate handle_text(state, meta, text), to: EEx.Engine\n\n  @impl true\n  def handle_expr(state, marker, expr) do\n    expr = Macro.prewalk(expr, &EEx.Engine.handle_assign/1)\n    EEx.Engine.handle_expr(state, marker, expr)\n  end\nend\n"
  },
  {
    "path": "lib/eex/lib/eex.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule EEx.SyntaxError do\n  defexception [:file, :line, :column, :snippet, message: \"syntax error\"]\n\n  @impl true\n  def message(exception) do\n    %{file: file, line: line, column: column, message: message, snippet: snippet} = exception\n\n    Exception.format_file_line_column(file && Path.relative_to_cwd(file), line, column, \" \") <>\n      message <> (snippet || \"\")\n  end\nend\n\ndefmodule EEx do\n  @moduledoc ~S\"\"\"\n  EEx stands for Embedded Elixir.\n\n  Embedded Elixir allows you to embed Elixir code inside a string\n  in a robust way.\n\n      iex> EEx.eval_string(\"foo <%= bar %>\", bar: \"baz\")\n      \"foo baz\"\n\n  This module provides three main APIs for you to use:\n\n    1. Evaluate a string (`eval_string/3`) or a file (`eval_file/3`)\n       directly. This is the simplest API to use but also the\n       slowest, since the code is evaluated at runtime and not precompiled.\n\n    2. Define a function from a string (`function_from_string/5`)\n       or a file (`function_from_file/5`). This allows you to embed\n       the template as a function inside a module which will then\n       be compiled. This is the preferred API if you have access\n       to the template at compilation time.\n\n    3. Compile a string (`compile_string/2`) or a file (`compile_file/2`)\n       into Elixir syntax tree. This is the API used by both functions\n       above and is available to you if you want to provide your own\n       ways of handling the compiled template.\n\n  The APIs above support several options, documented below. You may\n  also pass an engine which customizes how the EEx code is compiled.\n\n  ## Options\n\n  All functions in this module, unless otherwise noted, accept EEx-related\n  options. They are:\n\n    * `:file` - the file to be used in the template. Defaults to the given\n      file the template is read from or to `\"nofile\"` when compiling from a string.\n\n    * `:line` - the line to be used as the template start. Defaults to `1`.\n\n    * `:indentation` - (since v1.11.0) an integer added to the column after every\n      new line. Defaults to `0`.\n\n    * `:engine` - the EEx engine to be used for compilation. Defaults to `EEx.SmartEngine`.\n\n    * `:trim` - if `true`, trims whitespace left and right of quotation as\n      long as at least one newline is present. All subsequent newlines and\n      spaces are removed but one newline is retained. Defaults to `false`.\n\n    * `:parser_options` - (since: 1.13.0) allow customizing the parsed code\n      that is generated. See `Code.string_to_quoted/2` for available options.\n      Note that the options `:file`, `:line` and `:column` are ignored if\n      passed in. Defaults to `Code.get_compiler_option(:parser_options)`\n      (which defaults to `[]` if not set).\n\n  ## Tags\n\n  EEx supports multiple tags, declared below:\n\n      <% Elixir expression: executes code but discards output %>\n      <%= Elixir expression: executes code and prints result %>\n      <%% EEx quotation: returns the contents inside the tag as is %>\n      <%!-- Comments: they are discarded from source --%>\n\n  EEx supports additional tags, that may be used by some engines,\n  but they do not have a meaning by default:\n\n      <%| ... %>\n      <%/ ... %>\n\n  ## Engine\n\n  EEx has the concept of engines which allows you to modify or\n  transform the code extracted from the given string or file.\n\n  By default, `EEx` uses the `EEx.SmartEngine` that provides some\n  conveniences on top of the simple `EEx.Engine`.\n\n  ### `EEx.SmartEngine`\n\n  The smart engine uses EEx default rules and adds the `@` construct\n  for reading template assigns:\n\n      iex> EEx.eval_string(\"<%= @foo %>\", assigns: [foo: 1])\n      \"1\"\n\n  In other words, `<%= @foo %>` translates to:\n\n      <%= {:ok, v} = Access.fetch(assigns, :foo); v %>\n\n  The `assigns` extension is useful when the number of variables\n  required by the template is not specified at compilation time.\n  \"\"\"\n\n  @type line :: non_neg_integer\n  @type column :: non_neg_integer\n  @type marker :: [?=] | [?/] | [?|] | []\n  @type metadata :: %{column: column, line: line}\n  @type token ::\n          {:comment, charlist, metadata}\n          | {:text, charlist, metadata}\n          | {:expr | :start_expr | :middle_expr | :end_expr, marker, charlist, metadata}\n          | {:eof, metadata}\n\n  @type tokenize_opt ::\n          {:file, binary()}\n          | {:line, line}\n          | {:column, column}\n          | {:indentation, non_neg_integer}\n          | {:trim, boolean()}\n\n  @type compile_opt ::\n          tokenize_opt\n          | {:engine, module()}\n          | {:parser_options, Code.parser_opts()}\n          | {atom(), term()}\n\n  @doc \"\"\"\n  Generates a function definition from the given string.\n\n  The first argument is the kind of the generated function (`:def` or `:defp`).\n  The `name` argument is the name that the generated function will have.\n  `template` is the string containing the EEx template. `args` is a list of arguments\n  that the generated function will accept. They will be available inside the EEx\n  template.\n\n  The supported `options` are described [in the module docs](#module-options).\n  Additional options are passed to the underlying engine.\n\n  ## Examples\n\n      iex> defmodule Sample do\n      ...>   require EEx\n      ...>   EEx.function_from_string(:def, :sample, \"<%= a + b %>\", [:a, :b])\n      ...> end\n      iex> Sample.sample(1, 2)\n      \"3\"\n\n  \"\"\"\n  defmacro function_from_string(kind, name, template, args \\\\ [], options \\\\ []) do\n    quote bind_quoted: binding() do\n      info = Keyword.merge([file: __ENV__.file, line: __ENV__.line], options)\n      args = Enum.map(args, fn arg -> {arg, [line: info[:line]], nil} end)\n      compiled = EEx.compile_string(template, info)\n\n      case kind do\n        :def -> def unquote(name)(unquote_splicing(args)), do: unquote(compiled)\n        :defp -> defp unquote(name)(unquote_splicing(args)), do: unquote(compiled)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Generates a function definition from the file contents.\n\n  The first argument is the kind of the generated function (`:def` or `:defp`).\n  The `name` argument is the name that the generated function will have.\n  `file` is the path to the EEx template file. `args` is a list of arguments\n  that the generated function will accept. They will be available inside the EEx\n  template.\n\n  This function is useful in case you have templates but\n  you want to precompile inside a module for speed.\n\n  The supported `options` are described [in the module docs](#module-options).\n\n  ## Examples\n\n      # sample.eex\n      <%= a + b %>\n\n      # sample.ex\n      defmodule Sample do\n        require EEx\n        EEx.function_from_file(:def, :sample, \"sample.eex\", [:a, :b])\n      end\n\n      # iex\n      Sample.sample(1, 2)\n      #=> \"3\"\n\n  \"\"\"\n  defmacro function_from_file(kind, name, file, args \\\\ [], options \\\\ []) do\n    quote bind_quoted: binding() do\n      info = Keyword.merge([file: IO.chardata_to_string(file), line: 1], options)\n      args = Enum.map(args, fn arg -> {arg, [line: 1], nil} end)\n      compiled = EEx.compile_file(file, info)\n\n      @external_resource file\n      @file file\n      case kind do\n        :def -> def unquote(name)(unquote_splicing(args)), do: unquote(compiled)\n        :defp -> defp unquote(name)(unquote_splicing(args)), do: unquote(compiled)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Gets a string `source` and generates a quoted expression\n  that can be evaluated by Elixir or compiled to a function.\n\n  This is useful if you want to compile a EEx template into code and inject\n  that code somewhere or evaluate it at runtime.\n\n  The generated quoted code will use variables defined in the template that\n  will be taken from the context where the code is evaluated. If you\n  have a template such as `<%= a + b %>`, then the returned quoted code\n  will use the `a` and `b` variables in the context where it's evaluated. See\n  examples below.\n\n  The supported `options` are described [in the module docs](#module-options).\n\n  ## Examples\n\n      iex> quoted = EEx.compile_string(\"<%= a + b %>\")\n      iex> {result, _bindings} = Code.eval_quoted(quoted, a: 1, b: 2)\n      iex> result\n      \"3\"\n\n  \"\"\"\n  @spec compile_string(String.t(), [compile_opt]) :: Macro.t()\n  def compile_string(source, options \\\\ []) when is_binary(source) and is_list(options) do\n    tokenize_opts = Keyword.take(options, [:file, :line, :column, :indentation, :trim])\n\n    case tokenize(source, tokenize_opts) do\n      {:ok, tokens} ->\n        EEx.Compiler.compile(tokens, source, options)\n\n      {:error, message, %{column: column, line: line}} ->\n        file = options[:file] || \"nofile\"\n        raise EEx.SyntaxError, file: file, line: line, column: column, message: message\n    end\n  end\n\n  @doc \"\"\"\n  Gets a `filename` and generates a quoted expression\n  that can be evaluated by Elixir or compiled to a function.\n\n  This is useful if you want to compile a EEx template into code and inject\n  that code somewhere or evaluate it at runtime.\n\n  The generated quoted code will use variables defined in the template that\n  will be taken from the context where the code is evaluated. If you\n  have a template such as `<%= a + b %>`, then the returned quoted code\n  will use the `a` and `b` variables in the context where it's evaluated. See\n  examples below.\n\n  The supported `options` are described [in the module docs](#module-options).\n\n  ## Examples\n\n      # sample.eex\n      <%= a + b %>\n\n      # In code:\n      quoted = EEx.compile_file(\"sample.eex\")\n      {result, _bindings} = Code.eval_quoted(quoted, a: 1, b: 2)\n      result\n      #=> \"3\"\n\n  \"\"\"\n  @spec compile_file(Path.t(), [compile_opt]) :: Macro.t()\n  def compile_file(filename, options \\\\ []) when is_list(options) do\n    filename = IO.chardata_to_string(filename)\n    options = Keyword.merge([file: filename, line: 1], options)\n    compile_string(File.read!(filename), options)\n  end\n\n  @doc \"\"\"\n  Gets a string `source` and evaluate the values using the `bindings`.\n\n  The supported `options` are described [in the module docs](#module-options).\n\n  ## Examples\n\n      iex> EEx.eval_string(\"foo <%= bar %>\", bar: \"baz\")\n      \"foo baz\"\n\n  \"\"\"\n  @spec eval_string(String.t(), keyword, [compile_opt]) :: term()\n  def eval_string(source, bindings \\\\ [], options \\\\ [])\n      when is_binary(source) and is_list(bindings) and is_list(options) do\n    compiled = compile_string(source, options)\n    do_eval(compiled, bindings, options)\n  end\n\n  @doc \"\"\"\n  Gets a `filename` and evaluate the values using the `bindings`.\n\n  The supported `options` are described [in the module docs](#module-options).\n\n  ## Examples\n\n      # sample.eex\n      foo <%= bar %>\n\n      # IEx\n      EEx.eval_file(\"sample.eex\", bar: \"baz\")\n      #=> \"foo baz\"\n\n  \"\"\"\n  @spec eval_file(Path.t(), keyword, [compile_opt]) :: String.t()\n  def eval_file(filename, bindings \\\\ [], options \\\\ [])\n      when is_list(bindings) and is_list(options) do\n    filename = IO.chardata_to_string(filename)\n    options = Keyword.put_new(options, :file, filename)\n    compiled = compile_file(filename, options)\n    do_eval(compiled, bindings, options)\n  end\n\n  @doc \"\"\"\n  Tokenize the given contents according to the given options.\n\n  ## Options\n\n    * `:line` - An integer to start as line. Default is 1.\n    * `:column` - An integer to start as column. Default is 1.\n    * `:indentation` - An integer that indicates the indentation. Default is 0.\n    * `:trim` - Tells the tokenizer to either trim the content or not. Default is false.\n    * `:file` - Can be either a file or a string \"nofile\".\n\n  ## Examples\n\n      iex> EEx.tokenize(~c\"foo\", line: 1, column: 1)\n      {:ok, [{:text, ~c\"foo\", %{column: 1, line: 1}}, {:eof, %{column: 4, line: 1}}]}\n\n  ## Result\n\n  It returns `{:ok, [token]}` where a token is one of:\n\n    * `{:text, content, %{column: column, line: line}}`\n    * `{:expr, marker, content, %{column: column, line: line}}`\n    * `{:start_expr, marker, content, %{column: column, line: line}}`\n    * `{:middle_expr, marker, content, %{column: column, line: line}}`\n    * `{:end_expr, marker, content, %{column: column, line: line}}`\n    * `{:eof, %{column: column, line: line}}`\n\n  Or `{:error, message, %{column: column, line: line}}` in case of errors.\n  Note new tokens may be added in the future.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec tokenize([char()] | String.t(), [tokenize_opt]) ::\n          {:ok, [token()]} | {:error, String.t(), metadata()}\n  def tokenize(contents, opts \\\\ []) do\n    EEx.Compiler.tokenize(contents, opts)\n  end\n\n  ### Helpers\n\n  defp do_eval(compiled, bindings, options) do\n    options = Keyword.take(options, [:file, :line, :module, :prune_binding])\n    {result, _} = Code.eval_quoted(compiled, bindings, options)\n    result\n  end\nend\n"
  },
  {
    "path": "lib/eex/mix.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule EEx.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :eex,\n      version: System.version(),\n      build_per_environment: false\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/eex/test/eex/smart_engine_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule EEx.SmartEngineTest do\n  use ExUnit.Case, async: true\n\n  test \"evaluates simple string\" do\n    assert_eval(\"foo bar\", \"foo bar\")\n  end\n\n  test \"evaluates with assigns as keywords\" do\n    assert_eval(\"1\", \"<%= @foo %>\", assigns: [foo: 1])\n  end\n\n  test \"evaluates with assigns as a map\" do\n    assert_eval(\"1\", \"<%= @foo %>\", assigns: %{foo: 1})\n  end\n\n  test \"error with missing assigns\" do\n    stderr =\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        assert_eval(\"\", \"<%= @foo %>\", assigns: %{})\n      end)\n\n    assert stderr =~ \"assign @foo not available in EEx template\"\n  end\n\n  test \"evaluates with loops\" do\n    assert_eval(\"1\\n2\\n3\\n\", \"<%= for x <- [1, 2, 3] do %><%= x %>\\n<% end %>\")\n  end\n\n  test \"preserves line numbers in assignments\" do\n    result = EEx.compile_string(\"foo\\n<%= @hello %>\", engine: EEx.SmartEngine)\n\n    Macro.prewalk(result, fn\n      {_left, meta, [_, :hello]} ->\n        assert Keyword.get(meta, :line) == 2\n        send(self(), :found)\n\n      node ->\n        node\n    end)\n\n    assert_received :found\n  end\n\n  defp assert_eval(expected, actual, binding \\\\ []) do\n    result = EEx.eval_string(actual, binding, file: __ENV__.file, engine: EEx.SmartEngine)\n    assert result == expected\n  end\nend\n"
  },
  {
    "path": "lib/eex/test/eex/tokenizer_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule EEx.TokenizerTest do\n  use ExUnit.Case, async: true\n\n  @opts [indentation: 0, trim: false]\n\n  test \"simple charlists\" do\n    assert EEx.tokenize(~c\"foo\", @opts) ==\n             {:ok, [{:text, ~c\"foo\", %{column: 1, line: 1}}, {:eof, %{column: 4, line: 1}}]}\n  end\n\n  test \"simple strings\" do\n    assert EEx.tokenize(\"foo\", @opts) ==\n             {:ok, [{:text, ~c\"foo\", %{column: 1, line: 1}}, {:eof, %{column: 4, line: 1}}]}\n  end\n\n  test \"strings with embedded code\" do\n    assert EEx.tokenize(~c\"foo <% bar %>\", @opts) ==\n             {:ok,\n              [\n                {:text, ~c\"foo \", %{column: 1, line: 1}},\n                {:expr, ~c\"\", ~c\" bar \", %{column: 5, line: 1}},\n                {:eof, %{column: 14, line: 1}}\n              ]}\n  end\n\n  test \"strings with embedded equals code\" do\n    assert EEx.tokenize(~c\"foo <%= bar %>\", @opts) ==\n             {:ok,\n              [\n                {:text, ~c\"foo \", %{column: 1, line: 1}},\n                {:expr, ~c\"=\", ~c\" bar \", %{column: 5, line: 1}},\n                {:eof, %{column: 15, line: 1}}\n              ]}\n  end\n\n  test \"strings with embedded slash code\" do\n    assert EEx.tokenize(~c\"foo <%/ bar %>\", @opts) ==\n             {:ok,\n              [\n                {:text, ~c\"foo \", %{column: 1, line: 1}},\n                {:expr, ~c\"/\", ~c\" bar \", %{column: 5, line: 1}},\n                {:eof, %{column: 15, line: 1}}\n              ]}\n  end\n\n  test \"strings with embedded pipe code\" do\n    assert EEx.tokenize(~c\"foo <%| bar %>\", @opts) ==\n             {:ok,\n              [\n                {:text, ~c\"foo \", %{column: 1, line: 1}},\n                {:expr, ~c\"|\", ~c\" bar \", %{column: 5, line: 1}},\n                {:eof, %{column: 15, line: 1}}\n              ]}\n  end\n\n  test \"strings with more than one line\" do\n    assert EEx.tokenize(~c\"foo\\n<%= bar %>\", @opts) ==\n             {:ok,\n              [\n                {:text, ~c\"foo\\n\", %{column: 1, line: 1}},\n                {:expr, ~c\"=\", ~c\" bar \", %{column: 1, line: 2}},\n                {:eof, %{column: 11, line: 2}}\n              ]}\n  end\n\n  test \"strings with more than one line and expression with more than one line\" do\n    string = ~c\"\"\"\n    foo <%= bar\n\n    baz %>\n    <% foo %>\n    \"\"\"\n\n    exprs = [\n      {:text, ~c\"foo \", %{column: 1, line: 1}},\n      {:expr, ~c\"=\", ~c\" bar\\n\\nbaz \", %{column: 5, line: 1}},\n      {:text, ~c\"\\n\", %{column: 7, line: 3}},\n      {:expr, ~c\"\", ~c\" foo \", %{column: 1, line: 4}},\n      {:text, ~c\"\\n\", %{column: 10, line: 4}},\n      {:eof, %{column: 1, line: 5}}\n    ]\n\n    assert EEx.tokenize(string, @opts) == {:ok, exprs}\n  end\n\n  test \"quotation\" do\n    assert EEx.tokenize(~c\"foo <%% true %>\", @opts) ==\n             {:ok,\n              [\n                {:text, ~c\"foo <% true %>\", %{column: 1, line: 1}},\n                {:eof, %{column: 16, line: 1}}\n              ]}\n  end\n\n  test \"quotation with do-end\" do\n    assert EEx.tokenize(~c\"foo <%% true do %>bar<%% end %>\", @opts) ==\n             {:ok,\n              [\n                {:text, ~c\"foo <% true do %>bar<% end %>\", %{column: 1, line: 1}},\n                {:eof, %{column: 32, line: 1}}\n              ]}\n  end\n\n  test \"quotation with interpolation\" do\n    exprs = [\n      {:text, ~c\"a <% b \", %{column: 1, line: 1}},\n      {:expr, ~c\"=\", ~c\" c \", %{column: 9, line: 1}},\n      {:text, ~c\" \", %{column: 17, line: 1}},\n      {:expr, ~c\"=\", ~c\" d \", %{column: 18, line: 1}},\n      {:text, ~c\" e %> f\", %{column: 26, line: 1}},\n      {:eof, %{column: 33, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"a <%% b <%= c %> <%= d %> e %> f\", @opts) == {:ok, exprs}\n  end\n\n  test \"improperly formatted quotation with interpolation\" do\n    exprs = [\n      {:text, ~c\"<%% a <%= b %> c %>\", %{column: 1, line: 1}},\n      {:eof, %{column: 22, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"<%%% a <%%= b %> c %>\", @opts) == {:ok, exprs}\n  end\n\n  test \"EEx comments\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      exprs = [\n        {:text, ~c\"foo \", %{column: 1, line: 1}},\n        {:eof, %{column: 16, line: 1}}\n      ]\n\n      assert EEx.tokenize(~c\"foo <%# true %>\", @opts) == {:ok, exprs}\n\n      exprs = [\n        {:text, ~c\"foo \", %{column: 1, line: 1}},\n        {:eof, %{column: 8, line: 2}}\n      ]\n\n      assert EEx.tokenize(~c\"foo <%#\\ntrue %>\", @opts) == {:ok, exprs}\n    end)\n  end\n\n  test \"EEx multi-line comments\" do\n    exprs = [\n      {:text, ~c\"foo \", %{column: 1, line: 1}},\n      {:comment, ~c\" true \", %{column: 5, line: 1}},\n      {:text, ~c\" bar\", %{column: 20, line: 1}},\n      {:eof, %{column: 24, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"foo <%!-- true --%> bar\", @opts) == {:ok, exprs}\n\n    exprs = [\n      {:text, ~c\"foo \", %{column: 1, line: 1}},\n      {:comment, ~c\" \\ntrue\\n \", %{column: 5, line: 1}},\n      {:text, ~c\" bar\", %{column: 6, line: 3}},\n      {:eof, %{column: 10, line: 3}}\n    ]\n\n    assert EEx.tokenize(~c\"foo <%!-- \\ntrue\\n --%> bar\", @opts) == {:ok, exprs}\n\n    exprs = [\n      {:text, ~c\"foo \", %{column: 1, line: 1}},\n      {:comment, ~c\" <%= true %> \", %{column: 5, line: 1}},\n      {:text, ~c\" bar\", %{column: 27, line: 1}},\n      {:eof, %{column: 31, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"foo <%!-- <%= true %> --%> bar\", @opts) == {:ok, exprs}\n  end\n\n  test \"Elixir comments\" do\n    exprs = [\n      {:text, ~c\"foo \", %{column: 1, line: 1}},\n      {:expr, [], ~c\" true # this is a boolean \", %{column: 5, line: 1}},\n      {:eof, %{column: 35, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"foo <% true # this is a boolean %>\", @opts) == {:ok, exprs}\n  end\n\n  test \"Elixir comments with do-end\" do\n    exprs = [\n      {:start_expr, [], ~c\" if true do # startif \", %{column: 1, line: 1}},\n      {:text, ~c\"text\", %{column: 27, line: 1}},\n      {:end_expr, [], ~c\" end # closeif \", %{column: 31, line: 1}},\n      {:eof, %{column: 50, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"<% if true do # startif %>text<% end # closeif %>\", @opts) ==\n             {:ok, exprs}\n  end\n\n  test \"strings with embedded do end\" do\n    exprs = [\n      {:text, ~c\"foo \", %{column: 1, line: 1}},\n      {:start_expr, ~c\"\", ~c\" if true do \", %{column: 5, line: 1}},\n      {:text, ~c\"bar\", %{column: 21, line: 1}},\n      {:end_expr, ~c\"\", ~c\" end \", %{column: 24, line: 1}},\n      {:eof, %{column: 33, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"foo <% if true do %>bar<% end %>\", @opts) == {:ok, exprs}\n  end\n\n  test \"strings with embedded -> end\" do\n    exprs = [\n      {:text, ~c\"foo \", %{column: 1, line: 1}},\n      {:start_expr, ~c\"\", ~c\" cond do \", %{column: 5, line: 1}},\n      {:middle_expr, ~c\"\", ~c\" false -> \", %{column: 18, line: 1}},\n      {:text, ~c\"bar\", %{column: 32, line: 1}},\n      {:middle_expr, ~c\"\", ~c\" true -> \", %{column: 35, line: 1}},\n      {:text, ~c\"baz\", %{column: 48, line: 1}},\n      {:end_expr, ~c\"\", ~c\" end \", %{column: 51, line: 1}},\n      {:eof, %{column: 60, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"foo <% cond do %><% false -> %>bar<% true -> %>baz<% end %>\", @opts) ==\n             {:ok, exprs}\n  end\n\n  test \"strings with fn-end with newline\" do\n    exprs = [\n      {:start_expr, ~c\"=\", ~c\" a fn ->\\n\", %{column: 1, line: 1}},\n      {:text, ~c\"foo\", %{column: 3, line: 2}},\n      {:end_expr, [], ~c\" end \", %{column: 6, line: 2}},\n      {:eof, %{column: 15, line: 2}}\n    ]\n\n    assert EEx.tokenize(~c\"<%= a fn ->\\n%>foo<% end %>\", @opts) ==\n             {:ok, exprs}\n  end\n\n  test \"strings with multiple fn-end\" do\n    exprs = [\n      {:start_expr, ~c\"=\", ~c\" a fn -> \", %{column: 1, line: 1}},\n      {:text, ~c\"foo\", %{column: 15, line: 1}},\n      {:middle_expr, ~c\"\", ~c\" end, fn -> \", %{column: 18, line: 1}},\n      {:text, ~c\"bar\", %{column: 34, line: 1}},\n      {:end_expr, ~c\"\", ~c\" end \", %{column: 37, line: 1}},\n      {:eof, %{column: 46, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"<%= a fn -> %>foo<% end, fn -> %>bar<% end %>\", @opts) ==\n             {:ok, exprs}\n  end\n\n  test \"strings with fn-end followed by do block\" do\n    exprs = [\n      {:start_expr, ~c\"=\", ~c\" a fn -> \", %{column: 1, line: 1}},\n      {:text, ~c\"foo\", %{column: 15, line: 1}},\n      {:middle_expr, ~c\"\", ~c\" end do \", %{column: 18, line: 1}},\n      {:text, ~c\"bar\", %{column: 30, line: 1}},\n      {:end_expr, ~c\"\", ~c\" end \", %{column: 33, line: 1}},\n      {:eof, %{column: 42, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"<%= a fn -> %>foo<% end do %>bar<% end %>\", @opts) == {:ok, exprs}\n  end\n\n  test \"strings with embedded keywords blocks\" do\n    exprs = [\n      {:text, ~c\"foo \", %{column: 1, line: 1}},\n      {:start_expr, ~c\"\", ~c\" if true do \", %{column: 5, line: 1}},\n      {:text, ~c\"bar\", %{column: 21, line: 1}},\n      {:middle_expr, ~c\"\", ~c\" else \", %{column: 24, line: 1}},\n      {:text, ~c\"baz\", %{column: 34, line: 1}},\n      {:end_expr, ~c\"\", ~c\" end \", %{column: 37, line: 1}},\n      {:eof, %{column: 46, line: 1}}\n    ]\n\n    assert EEx.tokenize(~c\"foo <% if true do %>bar<% else %>baz<% end %>\", @opts) ==\n             {:ok, exprs}\n  end\n\n  test \"trim mode\" do\n    template = ~c\"\\t<%= if true do %> \\n TRUE \\n  <% else %>\\n FALSE \\n  <% end %>  \\n\\n  \"\n\n    exprs = [\n      {:start_expr, ~c\"=\", ~c\" if true do \", %{column: 2, line: 1}},\n      {:text, ~c\"\\n TRUE \\n\", %{column: 20, line: 1}},\n      {:middle_expr, ~c\"\", ~c\" else \", %{column: 3, line: 3}},\n      {:text, ~c\"\\n FALSE \\n\", %{column: 13, line: 3}},\n      {:end_expr, ~c\"\", ~c\" end \", %{column: 3, line: 5}},\n      {:eof, %{column: 3, line: 7}}\n    ]\n\n    assert EEx.tokenize(template, [trim: true] ++ @opts) == {:ok, exprs}\n  end\n\n  test \"trim mode with multi-line comment\" do\n    exprs = [\n      {:comment, ~c\" comment \", %{column: 3, line: 1}},\n      {:text, ~c\"\\n123\", %{column: 23, line: 1}},\n      {:eof, %{column: 4, line: 2}}\n    ]\n\n    assert EEx.tokenize(~c\"  <%!-- comment --%>  \\n123\", [trim: true] ++ @opts) == {:ok, exprs}\n  end\n\n  test \"trim mode with CRLF\" do\n    exprs = [\n      {:text, ~c\"0\\n\", %{column: 1, line: 1}},\n      {:expr, ~c\"=\", ~c\" 12 \", %{column: 3, line: 2}},\n      {:text, ~c\"\\n34\", %{column: 15, line: 2}},\n      {:eof, %{column: 3, line: 3}}\n    ]\n\n    assert EEx.tokenize(~c\"0\\r\\n  <%= 12 %>  \\r\\n34\", [trim: true] ++ @opts) == {:ok, exprs}\n  end\n\n  test \"trim mode set to false\" do\n    exprs = [\n      {:text, ~c\" \", %{column: 1, line: 1}},\n      {:expr, ~c\"=\", ~c\" 12 \", %{column: 2, line: 1}},\n      {:text, ~c\" \\n\", %{column: 11, line: 1}},\n      {:eof, %{column: 1, line: 2}}\n    ]\n\n    assert EEx.tokenize(~c\" <%= 12 %> \\n\", [trim: false] ++ @opts) == {:ok, exprs}\n  end\n\n  test \"trim mode no false positives\" do\n    assert_not_trimmed = fn x ->\n      assert EEx.tokenize(x, [trim: false] ++ @opts) == EEx.tokenize(x, @opts)\n    end\n\n    assert_not_trimmed.(~c\"foo <%= \\\"bar\\\" %>  \")\n    assert_not_trimmed.(~c\"\\n  <%= \\\"foo\\\" %>bar\")\n    assert_not_trimmed.(~c\"  <%% hello %>  \")\n    assert_not_trimmed.(~c\"  <%= 01 %><%= 23 %>\\n\")\n  end\n\n  test \"returns error when there is start mark and no end mark\" do\n    message = \"\"\"\n    expected closing '%>' for EEx expression\n      |\n    1 | foo <% :bar\n      |     ^\\\n    \"\"\"\n\n    assert EEx.tokenize(~c\"foo <% :bar\", @opts) ==\n             {:error, message, %{column: 5, line: 1}}\n\n    message = \"\"\"\n    expected closing '--%>' for EEx expression\n      |\n    1 | <%!-- foo\n      | ^\\\n    \"\"\"\n\n    assert EEx.tokenize(~c\"<%!-- foo\", @opts) == {:error, message, %{column: 1, line: 1}}\n  end\n\n  test \"marks invalid expressions as regular expressions\" do\n    assert EEx.tokenize(~c\"<% 1 $ 2 %>\", @opts) ==\n             {:ok,\n              [\n                {:expr, [], ~c\" 1 $ 2 \", %{column: 1, line: 1}},\n                {:eof, %{column: 12, line: 1}}\n              ]}\n  end\nend\n"
  },
  {
    "path": "lib/eex/test/eex_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\nrequire EEx\n\ndefmodule EExTest.Compiled do\n  def before_compile do\n    {__ENV__.line, hd(tl(get_stacktrace()))}\n  end\n\n  EEx.function_from_string(:def, :string_sample, \"<%= a + b %>\", [:a, :b])\n\n  filename = Path.join(__DIR__, \"fixtures/eex_template_with_bindings.eex\")\n  EEx.function_from_file(:defp, :private_file_sample, filename, [:bar])\n\n  filename = Path.join(__DIR__, \"fixtures/eex_template_with_bindings.eex\")\n  EEx.function_from_file(:def, :public_file_sample, filename, [:bar])\n\n  def file_sample(arg), do: private_file_sample(arg)\n\n  def after_compile do\n    {__ENV__.line, hd(tl(get_stacktrace()))}\n  end\n\n  @file \"unknown\"\n  def unknown do\n    {__ENV__.line, hd(tl(get_stacktrace()))}\n  end\n\n  defp get_stacktrace do\n    try do\n      :erlang.error(\"failed\")\n    rescue\n      _ -> __STACKTRACE__\n    end\n  end\nend\n\ndefmodule Clause do\n  defmacro defclause(expr, block) do\n    quote do\n      def unquote(expr), unquote(block)\n    end\n  end\nend\n\ndefmodule EExTest do\n  use ExUnit.Case, async: true\n\n  doctest EEx\n  doctest EEx.Engine\n  doctest EEx.SmartEngine\n\n  describe \"evaluates\" do\n    test \"simple string\" do\n      assert_eval(\"foo bar\", \"foo bar\")\n    end\n\n    test \"Unicode\" do\n      template = \"\"\"\n        • <%= \"•\" %> •\n        <%= \"Jößé Vâlìm\" %> Jößé Vâlìm\n      \"\"\"\n\n      assert_eval(\"  • • •\\n  Jößé Vâlìm Jößé Vâlìm\\n\", template)\n    end\n\n    test \"no spaces\" do\n      string = \"\"\"\n      <%=cond do%>\n      <%false ->%>\n        this\n      <%true ->%>\n        that\n      <%end%>\n      \"\"\"\n\n      expected = \"\\n  that\\n\\n\"\n      assert_eval(expected, string, [])\n    end\n\n    test \"trim mode\" do\n      string = \"<%= 123 %> \\n  \\n  <%= 789 %>\"\n      expected = \"123\\n789\"\n      assert_eval(expected, string, [], trim: true)\n\n      string = \"<%= 123 %> \\n456\\n  <%= 789 %>\"\n      expected = \"123\\n456\\n789\"\n      assert_eval(expected, string, [], trim: true)\n\n      string = \"<%= 123 %> \\n\\n456\\n\\n  <%= 789 %>\"\n      expected = \"123\\n456\\n789\"\n      assert_eval(expected, string, [], trim: true)\n\n      string = \"<%= 123 %> \\n  \\n456\\n  \\n  <%= 789 %>\"\n      expected = \"123\\n456\\n789\"\n      assert_eval(expected, string, [], trim: true)\n\n      string = \"\\n  <%= 123 %> \\n  <%= 456 %>  \\n  <%= 789 %>  \\n\"\n      expected = \"123\\n456\\n789\"\n      assert_eval(expected, string, [], trim: true)\n\n      string = \"\\r\\n  <%= 123 %> \\r\\n  <%= 456 %>  \\r\\n  <%= 789 %>  \\r\\n\"\n      expected = \"123\\n456\\n789\"\n      assert_eval(expected, string, [], trim: true)\n    end\n\n    test \"trim mode with middle expression\" do\n      string = \"\"\"\n      <%= cond do %>\n      <% false -> %>\n        this\n      <% true -> %>\n        that\n      <% end %>\n      \"\"\"\n\n      expected = \"\\n  that\\n\"\n      assert_eval(expected, string, [], trim: true)\n    end\n\n    test \"trim mode with multiple lines\" do\n      string = \"\"\"\n      <%= \"First line\" %>\n      <%= \"Second line\" %>\n      <%= \"Third line\" %>\n      <%= \"Fourth line\" %>\n      \"\"\"\n\n      expected = \"First line\\nSecond line\\nThird line\\nFourth line\"\n      assert_eval(expected, string, [], trim: true)\n    end\n\n    test \"trim mode with no spaces\" do\n      string = \"\"\"\n      <%=if true do%>\n        this\n      <%else%>\n        that\n      <%end%>\n      \"\"\"\n\n      expected = \"\\n  this\\n\"\n      assert_eval(expected, string, [], trim: true)\n\n      string = \"\"\"\n      <%=cond do%>\n      <%false ->%>\n        this\n      <%true ->%>\n        that\n      <%end%>\n      \"\"\"\n\n      expected = \"\\n  that\\n\"\n      assert_eval(expected, string, [], trim: true)\n    end\n\n    test \"embedded code\" do\n      assert_eval(\"foo bar\", \"foo <%= :bar %>\")\n    end\n\n    test \"embedded code with binding\" do\n      assert EEx.eval_string(\"foo <%= bar %>\", bar: 1) == \"foo 1\"\n    end\n\n    test \"embedded code with do end when true\" do\n      assert_eval(\"foo bar\", \"foo <%= if true do %>bar<% end %>\")\n    end\n\n    test \"embedded code with do end when false\" do\n      assert_eval(\"foo \", \"foo <%= if false do %>bar<% end %>\")\n    end\n\n    test \"embedded code with do preceded by bracket\" do\n      assert_eval(\"foo bar\", \"foo <%= if {true}do %>bar<% end %>\")\n      assert_eval(\"foo bar\", \"foo <%= if (true)do %>bar<% end %>\")\n      assert_eval(\"foo bar\", \"foo <%= if [true]do %>bar<% end %>\")\n    end\n\n    test \"embedded code with do end and expression\" do\n      assert_eval(\"foo bar\", \"foo <%= if true do %><%= :bar %><% end %>\")\n    end\n\n    test \"embedded code with do end and multiple expressions\" do\n      assert_eval(\n        \"foo bar baz\",\n        \"foo <%= if true do %>bar <% Process.put(:eex_text, 1) %><%= :baz %><% end %>\"\n      )\n\n      assert Process.get(:eex_text) == 1\n    end\n\n    test \"embedded code with middle expression\" do\n      assert_eval(\"foo bar\", \"foo <%= if true do %>bar<% else %>baz<% end %>\")\n    end\n\n    test \"embedded code with evaluated middle expression\" do\n      assert_eval(\"foo baz\", \"foo <%= if false do %>bar<% else %>baz<% end %>\")\n    end\n\n    test \"embedded code with multi-line comments in do end\" do\n      assert_eval(\"foo bar\", \"foo <%= case true do %><%!-- comment --%><% true -> %>bar<% end %>\")\n\n      assert_eval(\n        \"foo\\n\\nbar\\n\",\n        \"foo\\n<%= case true do %>\\n<%!-- comment --%>\\n<% true -> %>\\nbar\\n<% end %>\"\n      )\n    end\n\n    test \"embedded code with nested do end\" do\n      assert_eval(\"foo bar\", \"foo <%= if true do %><%= if true do %>bar<% end %><% end %>\")\n    end\n\n    test \"embedded code with nested do end with middle expression\" do\n      assert_eval(\n        \"foo baz\",\n        \"foo <%= if true do %><%= if false do %>bar<% else %>baz<% end %><% end %>\"\n      )\n    end\n\n    test \"embedded code with end followed by bracket\" do\n      assert_eval(\n        \" 101  102  103 \",\n        \"<%= Enum.map([1, 2, 3], fn x -> %> <%= 100 + x %> <% end) %>\"\n      )\n\n      assert_eval(\n        \" 101  102  103 \",\n        \"<%= Enum.map([1, 2, 3], fn x ->\\n%> <%= 100 + x %> <% end) %>\"\n      )\n\n      assert_eval(\n        \" 101  102  103 \",\n        \"<%= apply Enum, :map, [[1, 2, 3], fn x -> %> <%= 100 + x %> <% end] %>\"\n      )\n\n      assert_eval(\n        \" 101  102  103 \",\n        \"<%= #{__MODULE__}.tuple_map {[1, 2, 3], fn x -> %> <%= 100 + x %> <% end} %>\"\n      )\n\n      assert_eval(\n        \" 101  102  103 \",\n        \"<%= apply(Enum, :map, [[1, 2, 3], fn x -> %> <%= 100 + x %> <% end]) %>\"\n      )\n\n      assert_eval(\n        \" 101  102  103 \",\n        \"<%= Enum.map([1, 2, 3], (fn x -> %> <%= 100 + x %> <% end) ) %>\"\n      )\n    end\n\n    test \"embedded code with variable definition\" do\n      assert_eval(\"foo 1\", \"foo <% bar = 1 %><%= bar %>\")\n    end\n\n    test \"embedded code with require\" do\n      assert_eval(\"foo 1,2,3\", \"foo <% require Enum, as: E %><%= E.join [1, 2, 3], \\\",\\\" %>\")\n    end\n\n    test \"with end of token\" do\n      assert_eval(\"foo bar %>\", \"foo bar %>\")\n    end\n  end\n\n  describe \"raises syntax errors\" do\n    test \"with relative file information\" do\n      message = \"\"\"\n      foobar.eex:1:5: expected closing '%>' for EEx expression\n        |\n      1 | foo <%= bar\n        |     ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo <%= bar\", file: Path.join(File.cwd!(), \"foobar.eex\"))\n      end\n    end\n\n    test \"when <%!-- is not closed\" do\n      message = \"\"\"\n      my_file.eex:1:5: expected closing '--%>' for EEx expression\n        |\n      1 | foo <%!-- bar\n        |     ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo <%!-- bar\", file: \"my_file.eex\")\n      end\n    end\n\n    test \"when the token is invalid\" do\n      message = \"\"\"\n      nofile:1:5: expected closing '%>' for EEx expression\n        |\n      1 | foo <%= bar\n        |     ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo <%= bar\")\n      end\n    end\n\n    test \"when middle expression is found without a start expression\" do\n      message = \"\"\"\n      nofile:5:1: unexpected middle of expression <% else %>\n        |\n      2 | <%= \"content\" %>\n      3 | <%= if true %>\n      4 |   <%= \"foo\" %>\n      5 | <% else %>\n        | ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\n          ~s(<h1>Hi!</h1>\\n<%= \"content\" %>\\n<%= if true %>\\n  <%= \"foo\" %>\\n<% else %>\\n  bar<% end %>)\n        )\n      end\n    end\n\n    test \"proper format line number of code snippet\" do\n      message = \"\"\"\n      nofile:11:1: unexpected middle of expression <% else %>\n         |\n       8 | <%= \"content\" %>\n       9 | <%= if true %>\n      10 |   <%= \"foo\" %>\n      11 | <% else %>\n         | ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\n          ~s(\\n\\n\\n\\n\\n\\n<h1>Hi!</h1>\\n<%= \"content\" %>\\n<%= if true %>\\n  <%= \"foo\" %>\\n<% else %>\\n  bar<% end %>)\n        )\n      end\n    end\n\n    test \"when there is only middle expression\" do\n      message = \"\"\"\n      nofile:1:1: unexpected middle of expression <% else %>\n        |\n      1 | <% else %>\n        | ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(~s(<% else %>))\n      end\n    end\n\n    test \"when it is missing a `do` in case expr\" do\n      message = \"\"\"\n      nofile:3:3: unexpected middle of expression <% :something -> %>\n        |\n      1 | content\n      2 | <%= case @var %>\n      3 |   <% :something -> %>\n        |   ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"content\\n<%= case @var %>\\n  <% :something -> %>\\n    bar<% end %>\")\n      end\n    end\n\n    test \"when it is a `do` in cond expr\" do\n      message = \"\"\"\n      nofile:3:3: unexpected middle of expression <% true -> %>\n        |\n      1 | content\n      2 | <%= cond %>\n      3 |   <% true -> %>\n        |   ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"content\\n<%= cond %>\\n  <% true -> %>\\n    bar<% end %>\")\n      end\n    end\n\n    test \"when end expression is found without a start expression\" do\n      message = \"\"\"\n      nofile:1:5: unexpected end of expression <% end %>\n        |\n      1 | foo <% end %>\n        |     ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo <% end %>\")\n      end\n    end\n\n    test \"when start expression is found without an end expression\" do\n      message = \"\"\"\n      nofile:2:5: expected a closing '<% end %>' for block expression in EEx\n        |\n      1 | foo\n      2 | <%= if true do %>\n        |     ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo\\n<%= if true do %>\\nfoo\\n\")\n      end\n\n      message = \"\"\"\n      nofile:3:3: expected a closing '<% end %>' for block expression in EEx\n        |\n      1 | foo\n      2 | <%=\n      3 |   if true do %>\n        |   ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo\\n<%=\\n  if true do %>\\nfoo\\n\", indentation: 0)\n      end\n\n      message = \"\"\"\n      nofile:3:6: expected a closing '<% end %>' for block expression in EEx\n        |\n      1 |    foo\n      2 |    <%=\n      3 |      if true do %>\n        |      ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo\\n<%=\\n  if true do %>\\nfoo\\n\", indentation: 3)\n      end\n    end\n\n    test \"when start expression with middle expression is found without an end expression\" do\n      message = \"\"\"\n      nofile:2:5: expected a closing '<% end %>' for block expression in EEx\n        |\n      1 | foo\n      2 | <%= if true do %>\n        |     ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo\\n<%= if true do %>\\nfoo\\n<% else %>\\n\")\n      end\n    end\n\n    test \"when multiple start expressions is found without an end expression\" do\n      message = \"\"\"\n      nofile:5:5: expected a closing '<% end %>' for block expression in EEx\n        |\n      2 | <%= if true do %>\n      3 |   <%= @something %>\n      4 |\\s\n      5 | <%= if @var do %>\n        |     ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\n          \"foo\\n<%= if true do %>\\n  <%= @something %>\\n\\n<%= if @var do %>\\nfoo\\n\"\n        )\n      end\n    end\n\n    test \"when nested end expression is found without a start expression\" do\n      message = \"\"\"\n      nofile:1:31: unexpected end of expression <% end %>\n        |\n      1 | foo <%= if true do %><% end %><% end %>\n        |                               ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo <%= if true do %><% end %><% end %>\")\n      end\n    end\n\n    test \"when trying to use marker '|' without implementation\" do\n      msg =\n        ~r/unsupported EEx syntax <%| %> \\(the syntax is valid but not supported by the current EEx engine\\)/\n\n      assert_raise EEx.SyntaxError, msg, fn ->\n        EEx.compile_string(\"<%| true %>\")\n      end\n    end\n\n    test \"when trying to use marker '/' without implementation\" do\n      msg =\n        ~r/unsupported EEx syntax <%\\/ %> \\(the syntax is valid but not supported by the current EEx engine\\)/\n\n      assert_raise EEx.SyntaxError, msg, fn ->\n        EEx.compile_string(\"<%/ true %>\")\n      end\n    end\n\n    test \"from Elixir parser\" do\n      line = __ENV__.line + 6\n\n      message =\n        assert_raise TokenMissingError, fn ->\n          EEx.compile_string(\n            \"\"\"\n            <li>\n              <strong>Some:</strong>\n              <%= true && @some[ %>\n            </li>\n            \"\"\",\n            file: __ENV__.file,\n            line: line,\n            indentation: 12\n          )\n        end\n\n      assert message |> Exception.message() |> strip_ansi() =~ \"\"\"\n                  │\n              514 │                   true && @some[\\s\n                  │                                │ └ missing closing delimiter (expected \"]\")\n                  │                                └ unclosed delimiter\n             \"\"\"\n    end\n\n    test \"from Elixir parser with line breaks\" do\n      line = __ENV__.line + 6\n\n      message =\n        assert_raise TokenMissingError, fn ->\n          EEx.compile_string(\n            \"\"\"\n            <li>\n              <strong>Some:</strong>\n              <%= true &&\n                @some[ %>\n            </li>\n            \"\"\",\n            file: __ENV__.file,\n            line: line,\n            indentation: 12\n          )\n        end\n\n      assert message |> Exception.message() |> strip_ansi() =~ \"\"\"\n                  │\n              #{line + 3} │                 @some[\\s\n                  │                      │ └ missing closing delimiter (expected \"]\")\n                  │                      └ unclosed delimiter\n             \"\"\"\n    end\n\n    test \"honor line numbers\" do\n      assert_raise EEx.SyntaxError,\n                   \"nofile:100:6: expected closing '%>' for EEx expression\",\n                   fn ->\n                     EEx.compile_string(\"foo\\n bar <%= baz\", line: 99)\n                   end\n    end\n\n    test \"honor file names\" do\n      message = \"\"\"\n      my_file.eex:1:5: expected closing '%>' for EEx expression\n        |\n      1 | foo <%= bar\n        |     ^\\\n      \"\"\"\n\n      assert_raise EEx.SyntaxError, message, fn ->\n        EEx.compile_string(\"foo <%= bar\", file: \"my_file.eex\")\n      end\n    end\n  end\n\n  describe \"warnings\" do\n    test \"when middle expression has a modifier\" do\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               EEx.compile_string(\"foo <%= if true do %>true<%= else %>false<% end %>\")\n             end) =~ ~s[unexpected beginning of EEx tag \\\"<%=\\\" on \\\"<%= else %>\\\"]\n    end\n\n    test \"when end expression has a modifier\" do\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               EEx.compile_string(\"foo <%= if true do %>true<% else %>false<%= end %>\")\n             end) =~\n               ~s[unexpected beginning of EEx tag \\\"<%=\\\" on \\\"<%= end %>\\\"]\n    end\n\n    test \"unused \\\"do\\\" block without \\\"<%=\\\" modifier\" do\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               EEx.compile_string(\"<% if true do %>I'm invisible!<% end %>\")\n             end) =~ \"the contents of this expression won't be output\"\n\n      # These are fine though\n      EEx.compile_string(\"<% foo = fn -> %>Hello<% end %>\")\n      EEx.compile_string(\"<% foo = if true do %>Hello<% end %>\")\n    end\n\n    test \"from tokenizer\" do\n      warning =\n        ExUnit.CaptureIO.capture_io(:stderr, fn ->\n          EEx.compile_string(~s'<%= :\"foo\" %>', file: \"tokenizer.ex\")\n        end)\n\n      assert warning =~ \"found quoted atom \\\"foo\\\" but the quotes are not required\"\n      assert warning =~ \"tokenizer.ex:1:5\"\n    end\n  end\n\n  describe \"environment\" do\n    test \"respects line numbers\" do\n      expected = \"\"\"\n      foo\n      2\n      \"\"\"\n\n      string = \"\"\"\n      foo\n      <%= __ENV__.line %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"respects line numbers inside nested expressions\" do\n      expected = \"\"\"\n      foo\n\n      3\n\n      5\n      \"\"\"\n\n      string = \"\"\"\n      foo\n      <%= if true do %>\n      <%= __ENV__.line %>\n      <% end %>\n      <%= __ENV__.line %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"respects line numbers inside start expression\" do\n      expected = \"\"\"\n      foo\n\n      true\n\n      5\n      \"\"\"\n\n      string = \"\"\"\n      foo\n      <%= if __ENV__.line == 2 do %>\n      <%= true %>\n      <% end %>\n      <%= __ENV__.line %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"respects line numbers inside middle expression with ->\" do\n      expected = \"\"\"\n      foo\n\n      true\n\n      7\n      \"\"\"\n\n      string = \"\"\"\n      foo\n      <%= cond do %>\n      <% false -> %> false\n      <% __ENV__.line == 4 -> %>\n      <%= true %>\n      <% end %>\n      <%= __ENV__.line %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"respects line number inside middle expressions with keywords\" do\n      expected = \"\"\"\n      foo\n\n      5\n\n      7\n      \"\"\"\n\n      string = \"\"\"\n      foo\n      <%= if false do %>\n      <%= __ENV__.line %>\n      <% else %>\n      <%= __ENV__.line %>\n      <% end %>\n      <%= __ENV__.line %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"respects files\" do\n      assert_eval(\"sample.ex\", \"<%= __ENV__.file %>\", [], file: \"sample.ex\")\n    end\n  end\n\n  describe \"clauses\" do\n    test \"inside functions\" do\n      expected = \"\"\"\n\n      Number 1\n\n      Number 2\n\n      Number 3\n\n      \"\"\"\n\n      string = \"\"\"\n      <%= Enum.map [1, 2, 3], fn x -> %>\n      Number <%= x %>\n      <% end %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"inside multiple functions\" do\n      expected = \"\"\"\n\n      A 1\n\n      B 2\n\n      A 3\n\n      \"\"\"\n\n      string = \"\"\"\n      <%= #{__MODULE__}.switching_map [1, 2, 3], fn x -> %>\n      A <%= x %>\n      <% end, fn x -> %>\n      B <%= x %>\n      <% end %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"inside callback and do block\" do\n      expected = \"\"\"\n\n\n      A 1\n\n      B 2\n\n      A 3\n\n      \"\"\"\n\n      string = \"\"\"\n      <% require #{__MODULE__} %>\n      <%= #{__MODULE__}.switching_macro [1, 2, 3], fn x -> %>\n      A <%= x %>\n      <% end do %>\n      B <%= x %>\n      <% end %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"inside cond\" do\n      expected = \"\"\"\n      foo\n\n      true\n\n      \"\"\"\n\n      string = \"\"\"\n      foo\n      <%= cond do %>\n      <% false -> %> false\n      <% fn -> 1 end -> %>\n      <%= true %>\n      <% end %>\n      \"\"\"\n\n      assert_eval(expected, string)\n    end\n\n    test \"inside cond with do end\" do\n      string = \"\"\"\n      <% y = [\"a\", \"b\", \"c\"] %>\n      <%= cond do %>\n       <% \"a\" in y -> %>\n        Good\n       <% true -> %>\n        <%= if true do %>true<% else %>false<% end %>\n        Bad\n      <% end %>\n      \"\"\"\n\n      assert_eval(\"\\n\\n  Good\\n \\n\", string)\n    end\n\n    test \"line and column meta\" do\n      indentation = 12\n\n      ast =\n        EEx.compile_string(\n          \"\"\"\n          <%= f() %> <% f() %>\n            <%= f fn -> %>\n              <%= f() %>\n            <% end %>\n          \"\"\",\n          indentation: indentation\n        )\n\n      {_, calls} =\n        Macro.prewalk(ast, [], fn\n          {:f, meta, _args} = expr, acc -> {expr, [meta | acc]}\n          other, acc -> {other, acc}\n        end)\n\n      assert Enum.reverse(calls) == [\n               [line: 1, column: indentation + 5],\n               [line: 1, column: indentation + 15],\n               [line: 2, column: indentation + 7],\n               [line: 3, column: indentation + 9]\n             ]\n    end\n  end\n\n  describe \"buffers\" do\n    test \"inside comprehensions\" do\n      string = \"\"\"\n      <%= for _name <- packages || [] do %>\n      <% end %>\n      <%= all || :done %>\n      \"\"\"\n\n      assert_eval(\"\\ndone\\n\", string, packages: nil, all: nil)\n    end\n  end\n\n  describe \"from file\" do\n    test \"evaluates the source\" do\n      filename = Path.join(__DIR__, \"fixtures/eex_template.eex\")\n      result = EEx.eval_file(filename)\n      assert_normalized_newline_equal(\"foo bar.\\n\", result)\n    end\n\n    test \"evaluates the source with bindings\" do\n      filename = Path.join(__DIR__, \"fixtures/eex_template_with_bindings.eex\")\n      result = EEx.eval_file(filename, bar: 1)\n      assert_normalized_newline_equal(\"foo 1\\n\", result)\n    end\n\n    test \"raises an Exception when file is missing\" do\n      msg = \"could not read file \\\"non-existent.eex\\\": no such file or directory\"\n\n      assert_raise File.Error, msg, fn ->\n        filename = \"non-existent.eex\"\n        EEx.compile_file(filename)\n      end\n    end\n\n    test \"sets external resource attribute\" do\n      assert EExTest.Compiled.__info__(:attributes)[:external_resource] ==\n               [Path.join(__DIR__, \"fixtures/eex_template_with_bindings.eex\")]\n    end\n\n    test \"supports t:Path.t() paths\" do\n      filename = to_charlist(Path.join(__DIR__, \"fixtures/eex_template_with_bindings.eex\"))\n      result = EEx.eval_file(filename, bar: 1)\n      assert_normalized_newline_equal(\"foo 1\\n\", result)\n    end\n\n    test \"supports overriding file and line through options\" do\n      filename = Path.join(__DIR__, \"fixtures/eex_template_with_syntax_error.eex\")\n\n      assert_raise EEx.SyntaxError,\n                   \"my_file.eex:10:5: expected closing '%>' for EEx expression\",\n                   fn ->\n                     EEx.eval_file(filename, _bindings = [], file: \"my_file.eex\", line: 10)\n                   end\n    end\n  end\n\n  describe \"precompiled\" do\n    test \"from string\" do\n      assert EExTest.Compiled.string_sample(1, 2) == \"3\"\n    end\n\n    test \"from file\" do\n      assert_normalized_newline_equal(\"foo 1\\n\", EExTest.Compiled.file_sample(1))\n      assert_normalized_newline_equal(\"foo 1\\n\", EExTest.Compiled.public_file_sample(1))\n    end\n\n    test \"from file does not affect backtrace\" do\n      file = to_charlist(Path.relative_to_cwd(__ENV__.file))\n\n      assert EExTest.Compiled.before_compile() ==\n               {11, {EExTest.Compiled, :before_compile, 0, [file: file, line: 11]}}\n\n      assert EExTest.Compiled.after_compile() ==\n               {25, {EExTest.Compiled, :after_compile, 0, [file: file, line: 25]}}\n\n      assert EExTest.Compiled.unknown() ==\n               {30, {EExTest.Compiled, :unknown, 0, [file: ~c\"unknown\", line: 30]}}\n    end\n  end\n\n  defmodule TestEngine do\n    @behaviour EEx.Engine\n\n    def init(_opts) do\n      \"INIT\"\n    end\n\n    def handle_body(body) do\n      \"BODY(#{body})\"\n    end\n\n    def handle_begin(_) do\n      \"BEGIN\"\n    end\n\n    def handle_end(buffer) do\n      buffer <> \":END\"\n    end\n\n    def handle_text(buffer, meta, text) do\n      buffer <> \":TEXT-#{meta[:line]}-#{meta[:column]}(#{String.trim(text)})\"\n    end\n\n    def handle_expr(buffer, \"/\", expr) do\n      buffer <> \":DIV(#{Macro.to_string(expr)})\"\n    end\n\n    def handle_expr(buffer, \"=\", expr) do\n      buffer <> \":EQUAL(#{Macro.to_string(expr)})\"\n    end\n\n    def handle_expr(buffer, mark, expr) do\n      EEx.Engine.handle_expr(buffer, mark, expr)\n    end\n  end\n\n  describe \"custom engines\" do\n    test \"text\" do\n      assert_eval(\"BODY(INIT:TEXT-1-1(foo))\", \"foo\", [], engine: TestEngine)\n    end\n\n    test \"custom marker\" do\n      assert_eval(\"BODY(INIT:TEXT-1-1(foo):DIV(:bar))\", \"foo <%/ :bar %>\", [], engine: TestEngine)\n    end\n\n    test \"begin/end\" do\n      assert_eval(\n        ~s[BODY(INIT:TEXT-1-1(foo):EQUAL(if do\\n  \"BEGIN:TEXT-1-17(this):END\"\\nelse\\n  \"BEGIN:TEXT-1-31(that):END\"\\nend))],\n        \"foo <%= if do %>this<% else %>that<% end %>\",\n        [],\n        engine: TestEngine\n      )\n    end\n\n    test \"not implemented custom marker\" do\n      msg =\n        ~r/unsupported EEx syntax <%| %> \\(the syntax is valid but not supported by the current EEx engine\\)/\n\n      assert_raise EEx.SyntaxError, msg, fn ->\n        assert_eval({:wrapped, \"foo baz\"}, \"foo <%| :bar %>\", [], engine: TestEngine)\n      end\n    end\n  end\n\n  describe \"parser options\" do\n    test \"customizes parsed code\" do\n      atoms_encoder = fn \"not_jose\", _ -> {:ok, :jose} end\n\n      assert_eval(\"valid\", \"<%= not_jose %>\", [jose: \"valid\"],\n        parser_options: [static_atoms_encoder: atoms_encoder]\n      )\n    end\n  end\n\n  @strip_ansi [IO.ANSI.green(), IO.ANSI.red(), IO.ANSI.reset()]\n\n  defp strip_ansi(doc) do\n    String.replace(doc, @strip_ansi, \"\")\n  end\n\n  defp assert_eval(expected, actual, binding \\\\ [], opts \\\\ []) do\n    opts = Keyword.merge([file: __ENV__.file, engine: opts[:engine] || EEx.Engine], opts)\n    result = EEx.eval_string(actual, binding, opts)\n    assert result == expected\n  end\n\n  defp assert_normalized_newline_equal(expected, actual) do\n    assert String.replace(expected, \"\\r\\n\", \"\\n\") == String.replace(actual, \"\\r\\n\", \"\\n\")\n  end\n\n  def tuple_map({list, callback}) do\n    Enum.map(list, callback)\n  end\n\n  def switching_map(list, a, b) do\n    list\n    |> Enum.with_index()\n    |> Enum.map(fn\n      {element, index} when rem(index, 2) == 0 -> a.(element)\n      {element, index} when rem(index, 2) == 1 -> b.(element)\n    end)\n  end\n\n  defmacro switching_macro(list, a, do: block) do\n    quote do\n      b = fn var!(x) ->\n        unquote(block)\n      end\n\n      unquote(__MODULE__).switching_map(unquote(list), unquote(a), b)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/eex/test/fixtures/eex_template.eex",
    "content": "foo <%= if true do %>bar.<% end %>\n"
  },
  {
    "path": "lib/eex/test/fixtures/eex_template_with_bindings.eex",
    "content": "foo <%= bar %>\n"
  },
  {
    "path": "lib/eex/test/fixtures/eex_template_with_syntax_error.eex",
    "content": "foo <%= bar\n"
  },
  {
    "path": "lib/eex/test/test_helper.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n{line_exclude, line_include} =\n  if line = System.get_env(\"LINE\"), do: {[:test], [line: line]}, else: {[], []}\n\nCode.require_file(\"../../elixir/scripts/cover_record.exs\", __DIR__)\nCoverageRecorder.maybe_record(\"eex\")\n\nmaybe_seed_opt = if seed = System.get_env(\"SEED\"), do: [seed: String.to_integer(seed)], else: []\n\nex_unit_opts =\n  [\n    trace: !!System.get_env(\"TRACE\"),\n    include: line_include,\n    exclude: line_exclude\n  ] ++ maybe_seed_opt\n\nExUnit.start(ex_unit_opts)\n"
  },
  {
    "path": "lib/elixir/Emakefile",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n{'src/*', [\n  warn_unused_vars,\n  warn_export_all,\n  warn_shadow_vars,\n  warn_unused_import,\n  warn_unused_function,\n  warn_bif_clash,\n  warn_unused_record,\n  warn_deprecated_function,\n  warn_obsolete_guard,\n  warn_exported_vars,\n  %% Enable this when we require Erlang/OTP 27+\n  %% warnings_as_errors,\n  debug_info,\n  {outdir, \"ebin/\"}\n]}.\n"
  },
  {
    "path": "lib/elixir/lib/access.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Access do\n  @moduledoc \"\"\"\n  Key-based access to data structures.\n\n  The `Access` module defines a behaviour for dynamically accessing\n  keys of any type in a data structure via the `data[key]` syntax.\n\n  `Access` supports keyword lists (`Keyword`) and maps (`Map`) out\n  of the box. Keywords supports only atoms keys, keys for maps can\n  be of any type. Both return `nil` if the key does not exist:\n\n      iex> keywords = [a: 1, b: 2]\n      iex> keywords[:a]\n      1\n      iex> keywords[:c]\n      nil\n\n      iex> map = %{a: 1, b: 2}\n      iex> map[:a]\n      1\n\n      iex> star_ratings = %{1.0 => \"★\", 1.5 => \"★☆\", 2.0 => \"★★\"}\n      iex> star_ratings[1.5]\n      \"★☆\"\n\n  This syntax is very convenient as it can be nested arbitrarily:\n\n      iex> keywords = [a: 1, b: 2]\n      iex> keywords[:c][:unknown]\n      nil\n\n  This works because accessing anything on a `nil` value, returns\n  `nil` itself:\n\n      iex> nil[:a]\n      nil\n\n  ## Maps and structs\n\n  While the access syntax is allowed in maps via `map[key]`,\n  if your map is made of predefined atom keys, you should prefer\n  to access those atom keys with `map.key` instead of `map[key]`,\n  as `map.key` will raise if the key is missing (which is not\n  supposed to happen if the keys are predefined) or if `map` is\n  `nil`.\n\n  Similarly, since structs are maps and structs have predefined\n  keys, they only allow the `struct.key` syntax and they do not\n  allow the `struct[key]` access syntax.\n\n  In other words, the `map[key]` syntax is loose, returning `nil`\n  for missing keys, while the `map.key` syntax is strict, raising\n  for both nil values and missing keys.\n\n  To bridge this gap, Elixir provides the `get_in/1` and `get_in/2`\n  functions, which are capable of traversing nested data structures,\n  even in the presence of `nil`s:\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> get_in(users[\"john\"].age)\n      27\n      iex> get_in(users[\"unknown\"].age)\n      nil\n\n  Notice how, even if no user was found, `get_in/1` returned `nil`.\n  Outside of `get_in/1`, trying to access the field `.age` on `nil`\n  would raise.\n\n  The `get_in/2` function takes one step further by allowing\n  different accessors to be mixed in. For example, given a user\n  map with the `:name` and `:languages` keys, here is how to\n  access the name of all programming languages:\n\n        iex> languages = [\n        ...>   %{name: \"elixir\", type: :functional},\n        ...>   %{name: \"c\", type: :procedural}\n        ...> ]\n        iex> user = %{name: \"john\", languages: languages}\n        iex> get_in(user, [:languages, Access.all(), :name])\n        [\"elixir\", \"c\"]\n\n  This module provides convenience functions for traversing other\n  structures, like tuples and lists. As we will see next, they can\n  even be used to update nested data structures.\n\n  If you want to learn more about the dual nature of maps in Elixir,\n  as they can be either for structured data or as a key-value store,\n  see the `Map` module.\n\n  ## Updating nested data structures\n\n  The access syntax can also be used with the `Kernel.put_in/2`,\n  `Kernel.update_in/2`, `Kernel.get_and_update_in/2`, and `Kernel.pop_in/1`\n  macros to further manipulate values in nested data structures:\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> put_in(users[\"john\"].age, 28)\n      %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n  As shown in the previous section, you can also use the\n  `Kernel.put_in/3`, `Kernel.update_in/3`, `Kernel.pop_in/2`, and\n  `Kernel.get_and_update_in/3` functions to provide nested\n  custom accessors. For instance, given a user map with the\n  `:name` and `:languages` keys, here is how to deeply traverse\n  the map and convert all language names to uppercase:\n\n      iex> languages = [\n      ...>   %{name: \"elixir\", type: :functional},\n      ...>   %{name: \"c\", type: :procedural}\n      ...> ]\n      iex> user = %{name: \"john\", languages: languages}\n      iex> update_in(user, [:languages, Access.all(), :name], &String.upcase/1)\n      %{\n        name: \"john\",\n        languages: [\n          %{name: \"ELIXIR\", type: :functional},\n          %{name: \"C\", type: :procedural}\n        ]\n      }\n\n  See the functions `key/1`, `key!/1`, `elem/1`, and `all/0` for\n  some of the available accessors.\n  \"\"\"\n\n  @type container :: keyword | struct | map\n  @type nil_container :: nil\n  @type t :: container | nil_container | any\n  @type key :: any\n  @type value :: any\n\n  @type get_fun(data) ::\n          (:get, data, (term -> term) -> new_data :: container)\n\n  @type get_and_update_fun(data, current_value) ::\n          (:get_and_update, data, (term -> term) ->\n             {current_value, new_data :: container} | :pop)\n\n  @type access_fun(data, current_value) ::\n          get_fun(data) | get_and_update_fun(data, current_value)\n\n  @doc \"\"\"\n  Invoked in order to access the value stored under `key` in the given term `term`.\n\n  This function should return `{:ok, value}` where `value` is the value under\n  `key` if the key exists in the term, or `:error` if the key does not exist in\n  the term.\n\n  Many of the functions defined in the `Access` module internally call this\n  function. This function is also used when the square-brackets access syntax\n  (`structure[key]`) is used: the `fetch/2` callback implemented by the module\n  that defines the `structure` struct is invoked and if it returns `{:ok,\n  value}` then `value` is returned, or if it returns `:error` then `nil` is\n  returned.\n\n  See the `Map.fetch/2` and `Keyword.fetch/2` implementations for examples of\n  how to implement this callback.\n  \"\"\"\n  @callback fetch(term :: t, key) :: {:ok, value} | :error\n\n  @doc \"\"\"\n  Invoked in order to access the value under `key` and update it at the same time.\n\n  The implementation of this callback should invoke `fun` with the value under\n  `key` in the passed structure `data`, or with `nil` if `key` is not present in it.\n  This function must return either `{current_value, new_value}` or `:pop`.\n\n  If the passed function returns `{current_value, new_value}`,\n  the return value of this callback should be `{current_value, new_data}`, where:\n\n    * `current_value` is the retrieved value (which can be operated on before being returned)\n\n    * `new_value` is the new value to be stored under `key`\n\n    * `new_data` is `data` after updating the value of `key` with `new_value`.\n\n  If the passed function returns `:pop`, the return value of this callback\n  must be `{value, new_data}` where `value` is the value under `key`\n  (or `nil` if not present) and `new_data` is `data` without `key`.\n\n  See the implementations of `Map.get_and_update/3` or `Keyword.get_and_update/3`\n  for more examples.\n  \"\"\"\n  @callback get_and_update(data, key, (value | nil -> {current_value, new_value :: value} | :pop)) ::\n              {current_value, new_data :: data}\n            when current_value: value, data: container\n\n  @doc \"\"\"\n  Invoked to \"pop\" the value under `key` out of the given data structure.\n\n  When `key` exists in the given structure `data`, the implementation should\n  return a `{value, new_data}` tuple where `value` is the value that was under\n  `key` and `new_data` is `term` without `key`.\n\n  When `key` is not present in the given structure, a tuple `{value, data}`\n  should be returned, where `value` is implementation-defined.\n\n  See the implementations for `Map.pop/3` or `Keyword.pop/3` for more examples.\n  \"\"\"\n  @callback pop(data, key) :: {value, data} when data: container\n\n  defmacrop raise_undefined_behaviour(exception, module, top) do\n    quote do\n      exception =\n        case __STACKTRACE__ do\n          [unquote(top) | _] ->\n            reason =\n              \"\"\"\n              #{inspect(unquote(module))} does not implement the Access behaviour\n\n              You can use the \"struct.field\" syntax to access struct fields. \\\n              You can also use Access.key!/1 to access struct fields dynamically \\\n              inside get_in/put_in/update_in\\\n              \"\"\"\n\n            %{unquote(exception) | reason: reason}\n\n          _ ->\n            unquote(exception)\n        end\n\n      reraise exception, __STACKTRACE__\n    end\n  end\n\n  @doc \"\"\"\n  Fetches the value for the given key in a container (a map, keyword\n  list, or struct that implements the `Access` behaviour).\n\n  Returns `{:ok, value}` where `value` is the value under `key` if there is such\n  a key, or `:error` if `key` is not found.\n\n  ## Examples\n\n      iex> Access.fetch(%{name: \"meg\", age: 26}, :name)\n      {:ok, \"meg\"}\n\n      iex> Access.fetch([ordered: true, on_timeout: :exit], :timeout)\n      :error\n\n  \"\"\"\n  @spec fetch(container, term) :: {:ok, term} | :error\n  @spec fetch(nil_container, any) :: :error\n  def fetch(container, key)\n\n  def fetch(%module{} = container, key) do\n    module.fetch(container, key)\n  rescue\n    exception in UndefinedFunctionError ->\n      raise_undefined_behaviour(exception, module, {^module, :fetch, [^container, ^key], _})\n  end\n\n  def fetch(map, key) when is_map(map) do\n    case map do\n      %{^key => value} -> {:ok, value}\n      _ -> :error\n    end\n  end\n\n  def fetch(list, key) when is_list(list) and is_atom(key) do\n    case :lists.keyfind(key, 1, list) do\n      {_, value} -> {:ok, value}\n      false -> :error\n    end\n  end\n\n  def fetch(list, key) when is_list(list) do\n    raise ArgumentError,\n          \"the Access calls for keywords expect the key to be an atom, got: \" <> inspect(key)\n  end\n\n  def fetch(nil, _key) do\n    :error\n  end\n\n  @doc \"\"\"\n  Same as `fetch/2` but returns the value directly,\n  or raises a `KeyError` exception if `key` is not found.\n\n  ## Examples\n\n      iex> Access.fetch!(%{name: \"meg\", age: 26}, :name)\n      \"meg\"\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec fetch!(container, term) :: term\n  def fetch!(container, key) do\n    case fetch(container, key) do\n      {:ok, value} -> value\n      :error -> raise(KeyError, key: key, term: container)\n    end\n  end\n\n  @doc \"\"\"\n  Gets the value for the given key in a container (a map, keyword\n  list, or struct that implements the `Access` behaviour).\n\n  Returns the value under `key` if there is such a key, or `default` if `key` is\n  not found.\n\n  ## Examples\n\n      iex> Access.get(%{name: \"john\"}, :name, \"default name\")\n      \"john\"\n      iex> Access.get(%{name: \"john\"}, :age, 25)\n      25\n\n      iex> Access.get([ordered: true], :timeout)\n      nil\n\n  \"\"\"\n  @spec get(container, term, term) :: term\n  @spec get(nil_container, any, default) :: default when default: var\n  def get(container, key, default \\\\ nil)\n\n  # Reimplementing the same logic as Access.fetch/2 here is done for performance, since\n  # this is called a lot and calling fetch/2 means introducing some overhead (like\n  # building the \"{:ok, _}\" tuple and deconstructing it back right away).\n\n  def get(%module{} = container, key, default) do\n    try do\n      module.fetch(container, key)\n    rescue\n      exception in UndefinedFunctionError ->\n        raise_undefined_behaviour(exception, module, {^module, :fetch, [^container, ^key], _})\n    else\n      {:ok, value} -> value\n      :error -> default\n    end\n  end\n\n  def get(map, key, default) when is_map(map) do\n    case map do\n      %{^key => value} -> value\n      _ -> default\n    end\n  end\n\n  def get(list, key, default) when is_list(list) and is_atom(key) do\n    case :lists.keyfind(key, 1, list) do\n      {_, value} -> value\n      false -> default\n    end\n  end\n\n  def get(list, key, _default) when is_list(list) and is_integer(key) do\n    raise ArgumentError, \"\"\"\n    the Access module does not support accessing lists by index, got: #{inspect(key)}\n\n    Accessing a list by index is typically discouraged in Elixir, \\\n    instead we prefer to use the Enum module to manipulate lists \\\n    as a whole. If you really must access a list element by index, \\\n    you can use Enum.at/2 or the functions in the List module\\\n    \"\"\"\n  end\n\n  def get(list, key, _default) when is_list(list) do\n    raise ArgumentError, \"\"\"\n    the Access module supports only keyword lists (with atom keys), got: #{inspect(key)}\n\n    If you want to search lists of tuples, use List.keyfind/3\\\n    \"\"\"\n  end\n\n  def get(nil, _key, default) do\n    default\n  end\n\n  @doc \"\"\"\n  Gets and updates the given key in a `container` (a map, a keyword list,\n  a struct that implements the `Access` behaviour).\n\n  The `fun` argument receives the value of `key` (or `nil` if `key` is not\n  present in `container`) and must return a two-element tuple `{current_value, new_value}`:\n  the \"get\" value `current_value` (the retrieved value, which can be operated on before\n  being returned) and the new value to be stored under `key` (`new_value`).\n  `fun` may also return `:pop`, which means the current value\n  should be removed from the container and returned.\n\n  The returned value is a two-element tuple with the \"get\" value returned by\n  `fun` and a new container with the updated value under `key`.\n\n  ## Examples\n\n      iex> Access.get_and_update([a: 1], :a, fn current_value ->\n      ...>   {current_value, current_value + 1}\n      ...> end)\n      {1, [a: 2]}\n\n  \"\"\"\n  @spec get_and_update(data, key, (value | nil -> {current_value, new_value :: value} | :pop)) ::\n          {current_value, new_data :: data}\n        when current_value: var, data: container\n  def get_and_update(container, key, fun)\n\n  def get_and_update(%module{} = container, key, fun) do\n    module.get_and_update(container, key, fun)\n  rescue\n    exception in UndefinedFunctionError ->\n      raise_undefined_behaviour(\n        exception,\n        module,\n        {^module, :get_and_update, [^container, ^key, ^fun], _}\n      )\n  end\n\n  def get_and_update(map, key, fun) when is_map(map) do\n    Map.get_and_update(map, key, fun)\n  end\n\n  def get_and_update(list, key, fun) when is_list(list) and is_atom(key) do\n    Keyword.get_and_update(list, key, fun)\n  end\n\n  def get_and_update(list, key, _fun) when is_list(list) and is_integer(key) do\n    raise ArgumentError, \"\"\"\n    the Access module does not support accessing lists by index, got: #{inspect(key)}\n\n    Accessing a list by index is typically discouraged in Elixir, \\\n    instead we prefer to use the Enum module to manipulate lists \\\n    as a whole. If you really must modify a list element by index, \\\n    you can use Access.at/1 or the functions in the List module\\\n    \"\"\"\n  end\n\n  def get_and_update(list, key, _fun) when is_list(list) do\n    raise ArgumentError,\n          \"the Access module supports only keyword lists (with atom keys), got: \" <> inspect(key)\n  end\n\n  def get_and_update(nil, key, _fun) do\n    raise ArgumentError, \"could not put/update key #{inspect(key)} on a nil value\"\n  end\n\n  @doc \"\"\"\n  Removes the entry with a given key from a container (a map, keyword\n  list, or struct that implements the `Access` behaviour).\n\n  Returns a tuple containing the value associated with the key and the\n  updated container. `nil` is returned for the value if the key isn't\n  in the container.\n\n  ## Examples\n\n  With a map:\n\n      iex> Access.pop(%{name: \"Elixir\", creator: \"Valim\"}, :name)\n      {\"Elixir\", %{creator: \"Valim\"}}\n\n  A keyword list:\n\n      iex> Access.pop([name: \"Elixir\", creator: \"Valim\"], :name)\n      {\"Elixir\", [creator: \"Valim\"]}\n\n  An unknown key:\n\n      iex> Access.pop(%{name: \"Elixir\", creator: \"Valim\"}, :year)\n      {nil, %{creator: \"Valim\", name: \"Elixir\"}}\n\n  \"\"\"\n  @spec pop(data, key) :: {value, data} when data: container\n  def pop(%module{} = container, key) do\n    module.pop(container, key)\n  rescue\n    exception in UndefinedFunctionError ->\n      raise_undefined_behaviour(exception, module, {^module, :pop, [^container, ^key], _})\n  end\n\n  def pop(map, key) when is_map(map) do\n    Map.pop(map, key)\n  end\n\n  def pop(list, key) when is_list(list) do\n    Keyword.pop(list, key)\n  end\n\n  def pop(nil, key) do\n    raise ArgumentError, \"could not pop key #{inspect(key)} on a nil value\"\n  end\n\n  ## Accessors\n\n  @doc \"\"\"\n  Returns a function that accesses the given key in a map/struct.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  The returned function uses the default value if the key does not exist.\n  This can be used to specify defaults and safely traverse missing keys:\n\n      iex> get_in(%{}, [Access.key(:user, %{}), Access.key(:name, \"meg\")])\n      \"meg\"\n\n  Such is also useful when using update functions, allowing us to introduce\n  values as we traverse the data structure for updates:\n\n      iex> put_in(%{}, [Access.key(:user, %{}), Access.key(:name)], \"Mary\")\n      %{user: %{name: \"Mary\"}}\n\n  ## Examples\n\n      iex> map = %{user: %{name: \"john\"}}\n      iex> get_in(map, [Access.key(:unknown, %{}), Access.key(:name, \"john\")])\n      \"john\"\n      iex> get_and_update_in(map, [Access.key(:user), Access.key(:name)], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {\"john\", %{user: %{name: \"JOHN\"}}}\n      iex> pop_in(map, [Access.key(:user), Access.key(:name)])\n      {\"john\", %{user: %{}}}\n\n  An error is raised if the accessed structure is not a map or a struct:\n\n      iex> get_in([], [Access.key(:foo)])\n      ** (BadMapError) expected a map, got:\n      ...\n  \"\"\"\n  @spec key(key, term) :: access_fun(data :: struct | map, current_value :: term)\n  def key(key, default \\\\ nil) do\n    fn\n      :get, data, next ->\n        next.(Map.get(data, key, default))\n\n      :get_and_update, data, next ->\n        value = Map.get(data, key, default)\n\n        case next.(value) do\n          {get, update} -> {get, Map.put(data, key, update)}\n          :pop -> {value, Map.delete(data, key)}\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Returns a function that accesses the given key in a map/struct.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  Similar to `key/2`, but the returned function raises if the key does not exist.\n\n  ## Examples\n\n      iex> map = %{user: %{name: \"john\"}}\n      iex> get_in(map, [Access.key!(:user), Access.key!(:name)])\n      \"john\"\n      iex> get_and_update_in(map, [Access.key!(:user), Access.key!(:name)], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {\"john\", %{user: %{name: \"JOHN\"}}}\n      iex> pop_in(map, [Access.key!(:user), Access.key!(:name)])\n      {\"john\", %{user: %{}}}\n      iex> get_in(map, [Access.key!(:user), Access.key!(:unknown)])\n      ** (KeyError) key :unknown not found in:\n      ...\n\n  The examples above could be partially written as:\n\n      iex> map = %{user: %{name: \"john\"}}\n      iex> map.user.name\n      \"john\"\n      iex> get_and_update_in(map.user.name, fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {\"john\", %{user: %{name: \"JOHN\"}}}\n\n  However, it is not possible to remove fields using the dot notation,\n  as it is implied those fields must also be present. In any case,\n  `Access.key!/1` is useful when the key is not known in advance\n  and must be accessed dynamically.\n\n  An error is raised if the accessed structure is not a map/struct:\n\n      iex> get_in([], [Access.key!(:foo)])\n      ** (RuntimeError) Access.key!/1 expected a map/struct, got: []\n\n  \"\"\"\n  @spec key!(key) :: access_fun(data :: struct | map, current_value :: term)\n  def key!(key) do\n    fn\n      :get, %{} = data, next ->\n        next.(Map.fetch!(data, key))\n\n      :get_and_update, %{} = data, next ->\n        value = Map.fetch!(data, key)\n\n        case next.(value) do\n          {get, update} -> {get, Map.put(data, key, update)}\n          :pop -> {value, Map.delete(data, key)}\n        end\n\n      _op, data, _next ->\n        raise \"Access.key!/1 expected a map/struct, got: #{inspect(data)}\"\n    end\n  end\n\n  @doc ~S\"\"\"\n  Returns a function that accesses the element at the given index in a tuple.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  The returned function raises if `index` is out of bounds.\n\n  Note that popping elements out of tuples is not possible and raises an\n  error.\n\n  ## Examples\n\n      iex> map = %{user: {\"john\", 27}}\n      iex> get_in(map, [:user, Access.elem(0)])\n      \"john\"\n      iex> get_and_update_in(map, [:user, Access.elem(0)], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {\"john\", %{user: {\"JOHN\", 27}}}\n      iex> pop_in(map, [:user, Access.elem(0)])\n      ** (RuntimeError) cannot pop data from a tuple\n\n  An error is raised if the accessed structure is not a tuple:\n\n      iex> get_in(%{}, [Access.elem(0)])\n      ** (RuntimeError) Access.elem/1 expected a tuple, got: %{}\n\n  \"\"\"\n  @spec elem(non_neg_integer) :: access_fun(data :: tuple, current_value :: term)\n  def elem(index) when is_integer(index) and index >= 0 do\n    pos = index + 1\n\n    fn\n      :get, data, next when is_tuple(data) ->\n        next.(:erlang.element(pos, data))\n\n      :get_and_update, data, next when is_tuple(data) ->\n        value = :erlang.element(pos, data)\n\n        case next.(value) do\n          {get, update} -> {get, :erlang.setelement(pos, data, update)}\n          :pop -> raise \"cannot pop data from a tuple\"\n        end\n\n      _op, data, _next ->\n        raise \"Access.elem/1 expected a tuple, got: #{inspect(data)}\"\n    end\n  end\n\n  @doc ~S\"\"\"\n  Returns a function that accesses all the elements in a list.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  ## Examples\n\n      iex> list = [%{name: \"john\"}, %{name: \"mary\"}]\n      iex> get_in(list, [Access.all(), :name])\n      [\"john\", \"mary\"]\n      iex> get_and_update_in(list, [Access.all(), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {[\"john\", \"mary\"], [%{name: \"JOHN\"}, %{name: \"MARY\"}]}\n      iex> pop_in(list, [Access.all(), :name])\n      {[\"john\", \"mary\"], [%{}, %{}]}\n\n  Here is an example that traverses the list dropping even\n  numbers and multiplying odd numbers by 2:\n\n      iex> require Integer\n      iex> get_and_update_in([1, 2, 3, 4, 5], [Access.all()], fn num ->\n      ...>   if Integer.is_even(num), do: :pop, else: {num, num * 2}\n      ...> end)\n      {[1, 2, 3, 4, 5], [2, 6, 10]}\n\n  An error is raised if the accessed structure is not a list:\n\n      iex> get_in(%{}, [Access.all()])\n      ** (RuntimeError) Access.all/0 expected a list, got: %{}\n\n  \"\"\"\n  @spec all() :: access_fun(data :: list, current_value :: list)\n  def all() do\n    &all/3\n  end\n\n  defp all(:get, data, next) when is_list(data) do\n    Enum.map(data, next)\n  end\n\n  defp all(:get_and_update, data, next) when is_list(data) do\n    all(data, next, _gets = [], _updates = [])\n  end\n\n  defp all(_op, data, _next) do\n    raise \"Access.all/0 expected a list, got: #{inspect(data)}\"\n  end\n\n  defp all([head | rest], next, gets, updates) do\n    case next.(head) do\n      {get, update} -> all(rest, next, [get | gets], [update | updates])\n      :pop -> all(rest, next, [head | gets], updates)\n    end\n  end\n\n  defp all([], _next, gets, updates) do\n    {:lists.reverse(gets), :lists.reverse(updates)}\n  end\n\n  @doc ~S\"\"\"\n  Returns a function that accesses the element at `index` (zero based) of a list.\n\n  Keep in mind that index lookups in lists take linear time: the larger the list,\n  the longer it will take to access its index. Therefore index-based operations\n  are generally avoided in favor of other functions in the `Enum` module.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  ## Examples\n\n      iex> list = [%{name: \"john\"}, %{name: \"mary\"}]\n      iex> get_in(list, [Access.at(1), :name])\n      \"mary\"\n      iex> get_in(list, [Access.at(-1), :name])\n      \"mary\"\n      iex> get_and_update_in(list, [Access.at(0), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {\"john\", [%{name: \"JOHN\"}, %{name: \"mary\"}]}\n      iex> get_and_update_in(list, [Access.at(-1), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {\"mary\", [%{name: \"john\"}, %{name: \"MARY\"}]}\n\n  `at/1` can also be used to pop elements out of a list or\n  a key inside of a list:\n\n      iex> list = [%{name: \"john\"}, %{name: \"mary\"}]\n      iex> pop_in(list, [Access.at(0)])\n      {%{name: \"john\"}, [%{name: \"mary\"}]}\n      iex> pop_in(list, [Access.at(0), :name])\n      {\"john\", [%{}, %{name: \"mary\"}]}\n\n  When the index is out of bounds, `nil` is returned and the update function is never called:\n\n      iex> list = [%{name: \"john\"}, %{name: \"mary\"}]\n      iex> get_in(list, [Access.at(10), :name])\n      nil\n      iex> get_and_update_in(list, [Access.at(10), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {nil, [%{name: \"john\"}, %{name: \"mary\"}]}\n\n  An error is raised if the accessed structure is not a list:\n\n      iex> get_in(%{}, [Access.at(1)])\n      ** (RuntimeError) Access.at/1 expected a list, got: %{}\n\n  \"\"\"\n  @spec at(integer) :: access_fun(data :: list, current_value :: term)\n  def at(index) when is_integer(index) do\n    fn op, data, next -> at(op, data, index, next) end\n  end\n\n  defp at(:get, data, index, next) when is_list(data) do\n    data |> Enum.at(index) |> next.()\n  end\n\n  defp at(:get_and_update, data, index, next) when is_list(data) do\n    get_and_update_at(data, index, next, [], fn -> nil end)\n  end\n\n  defp at(_op, data, _index, _next) do\n    raise \"Access.at/1 expected a list, got: #{inspect(data)}\"\n  end\n\n  defp get_and_update_at([head | rest], 0, next, updates, _default_fun) do\n    case next.(head) do\n      {get, update} -> {get, :lists.reverse([update | updates], rest)}\n      :pop -> {head, :lists.reverse(updates, rest)}\n    end\n  end\n\n  defp get_and_update_at([_ | _] = list, index, next, updates, default_fun) when index < 0 do\n    list_length = length(list)\n\n    if list_length + index >= 0 do\n      get_and_update_at(list, list_length + index, next, updates, default_fun)\n    else\n      {default_fun.(), list}\n    end\n  end\n\n  defp get_and_update_at([head | rest], index, next, updates, default_fun) when index > 0 do\n    get_and_update_at(rest, index - 1, next, [head | updates], default_fun)\n  end\n\n  defp get_and_update_at([], _index, _next, updates, default_fun) do\n    {default_fun.(), :lists.reverse(updates)}\n  end\n\n  @doc ~S\"\"\"\n  Same as `at/1` except that it raises `Enum.OutOfBoundsError`\n  if the given index is out of bounds.\n\n  ## Examples\n\n      iex> get_in([:a, :b, :c], [Access.at!(2)])\n      :c\n      iex> get_in([:a, :b, :c], [Access.at!(3)])\n      ** (Enum.OutOfBoundsError) out of bounds error at position 3 when traversing enumerable [:a, :b, :c]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec at!(integer) :: access_fun(data :: list, current_value :: term)\n  def at!(index) when is_integer(index) do\n    fn op, data, next -> at!(op, data, index, next) end\n  end\n\n  defp at!(:get, data, index, next) when is_list(data) do\n    case Enum.fetch(data, index) do\n      {:ok, value} -> next.(value)\n      :error -> raise Enum.OutOfBoundsError, index: index, enumerable: data\n    end\n  end\n\n  defp at!(:get_and_update, data, index, next) when is_list(data) do\n    get_and_update_at(data, index, next, [], fn ->\n      raise Enum.OutOfBoundsError, index: index, enumerable: data\n    end)\n  end\n\n  defp at!(_op, data, _index, _next) do\n    raise \"Access.at!/1 expected a list, got: #{inspect(data)}\"\n  end\n\n  @doc ~S\"\"\"\n  Returns a function that accesses all elements of a list that match the provided predicate.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  ## Examples\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}]\n      iex> get_in(list, [Access.filter(&(&1.salary > 20)), :name])\n      [\"francine\"]\n      iex> get_and_update_in(list, [Access.filter(&(&1.salary <= 20)), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {[\"john\"], [%{name: \"JOHN\", salary: 10}, %{name: \"francine\", salary: 30}]}\n\n  `filter/1` can also be used to pop elements out of a list or\n  a key inside of a list:\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}]\n      iex> pop_in(list, [Access.filter(&(&1.salary >= 20))])\n      {[%{name: \"francine\", salary: 30}], [%{name: \"john\", salary: 10}]}\n      iex> pop_in(list, [Access.filter(&(&1.salary >= 20)), :name])\n      {[\"francine\"], [%{name: \"john\", salary: 10}, %{salary: 30}]}\n\n  When no match is found, an empty list is returned and the update function is never called\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}]\n      iex> get_in(list, [Access.filter(&(&1.salary >= 50)), :name])\n      []\n      iex> get_and_update_in(list, [Access.filter(&(&1.salary >= 50)), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {[], [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}]}\n\n  An error is raised if the accessed structure is not a list:\n\n      iex> get_in(%{}, [Access.filter(fn a -> a == 10 end)])\n      ** (RuntimeError) Access.filter/1 expected a list, got: %{}\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec filter((term -> boolean)) :: access_fun(data :: list, current_value :: list)\n  def filter(func) when is_function(func) do\n    fn op, data, next -> filter(op, data, func, next) end\n  end\n\n  defp filter(:get, data, func, next) when is_list(data) do\n    for elem <- data, func.(elem), do: next.(elem)\n  end\n\n  defp filter(:get_and_update, data, func, next) when is_list(data) do\n    get_and_update_filter(data, func, next, [], [])\n  end\n\n  defp filter(_op, data, _func, _next) do\n    raise \"Access.filter/1 expected a list, got: #{inspect(data)}\"\n  end\n\n  defp get_and_update_filter([head | rest], func, next, updates, gets) do\n    if func.(head) do\n      case next.(head) do\n        {get, update} ->\n          get_and_update_filter(rest, func, next, [update | updates], [get | gets])\n\n        :pop ->\n          get_and_update_filter(rest, func, next, updates, [head | gets])\n      end\n    else\n      get_and_update_filter(rest, func, next, [head | updates], gets)\n    end\n  end\n\n  defp get_and_update_filter([], _func, _next, updates, gets) do\n    {:lists.reverse(gets), :lists.reverse(updates)}\n  end\n\n  @doc ~S\"\"\"\n  Returns a function that accesses all items of a list that are within the provided range.\n\n  The range will be normalized following the same rules from `Enum.slice/2`.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  ## Examples\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}, %{name: \"vitor\", salary: 25}]\n      iex> get_in(list, [Access.slice(1..2), :name])\n      [\"francine\", \"vitor\"]\n      iex> get_and_update_in(list, [Access.slice(1..3//2), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {[\"francine\"], [%{name: \"john\", salary: 10}, %{name: \"FRANCINE\", salary: 30}, %{name: \"vitor\", salary: 25}]}\n\n  `slice/1` can also be used to pop elements out of a list or\n  a key inside of a list:\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}, %{name: \"vitor\", salary: 25}]\n      iex> pop_in(list, [Access.slice(-2..-1)])\n      {[%{name: \"francine\", salary: 30}, %{name: \"vitor\", salary: 25}], [%{name: \"john\", salary: 10}]}\n      iex> pop_in(list, [Access.slice(-2..-1), :name])\n      {[\"francine\", \"vitor\"], [%{name: \"john\", salary: 10}, %{salary: 30}, %{salary: 25}]}\n\n  When no match is found, an empty list is returned and the update function is never called\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}, %{name: \"vitor\", salary: 25}]\n      iex> get_in(list, [Access.slice(5..10//2), :name])\n      []\n      iex> get_and_update_in(list, [Access.slice(5..10//2), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {[], [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}, %{name: \"vitor\", salary: 25}]}\n\n  An error is raised if the accessed structure is not a list:\n\n      iex> get_in(%{}, [Access.slice(2..10//3)])\n      ** (ArgumentError) Access.slice/1 expected a list, got: %{}\n\n  An error is raised if the step of the range is negative:\n\n      iex> get_in([], [Access.slice(2..10//-1)])\n      ** (ArgumentError) Access.slice/1 does not accept ranges with negative steps, got: 2..10//-1\n\n  \"\"\"\n  @doc since: \"1.14\"\n  @spec slice(Range.t()) :: access_fun(data :: list, current_value :: list)\n  def slice(%Range{} = range) do\n    if range.step > 0 do\n      fn op, data, next -> slice(op, data, range, next) end\n    else\n      raise ArgumentError,\n            \"Access.slice/1 does not accept ranges with negative steps, got: #{inspect(range)}\"\n    end\n  end\n\n  defp slice(:get, data, %Range{} = range, next) when is_list(data) do\n    data\n    |> Enum.slice(range)\n    |> Enum.map(next)\n  end\n\n  defp slice(:get_and_update, data, range, next) when is_list(data) do\n    range = normalize_range(range, data)\n\n    if range.first > range.last do\n      {[], data}\n    else\n      get_and_update_slice(data, range, next, [], [], 0)\n    end\n  end\n\n  defp slice(_op, data, _range, _next) do\n    raise ArgumentError, \"Access.slice/1 expected a list, got: #{inspect(data)}\"\n  end\n\n  @doc \"\"\"\n  Returns a function that accesses all values in a map or a keyword list.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> get_in(users, [Access.values(), :age]) |> Enum.sort()\n      [23, 27]\n      iex> update_in(users, [Access.values(), :age], fn age -> age + 1 end)\n      %{\"john\" => %{age: 28}, \"meg\" => %{age: 24}}\n      iex> put_in(users, [Access.values(), :planet], \"Earth\")\n      %{\"john\" => %{age: 27, planet: \"Earth\"}, \"meg\" => %{age: 23, planet: \"Earth\"}}\n\n  Values in keyword lists can be accessed as well:\n\n      iex> users = [john: %{age: 27}, meg: %{age: 23}]\n      iex> get_and_update_in(users, [Access.values(), :age], fn age -> {age, age + 1} end)\n      {[27, 23], [john: %{age: 28}, meg: %{age: 24}]}\n\n  By returning `:pop` from an accessor function, you can remove the accessed key and value\n  from the map or keyword list:\n\n      iex> require Integer\n      iex> numbers = [one: 1, two: 2, three: 3, four: 4]\n      iex> get_and_update_in(numbers, [Access.values()], fn num ->\n      ...>   if Integer.is_even(num), do: :pop, else: {num, to_string(num)}\n      ...> end)\n      {[1, 2, 3, 4], [one: \"1\", three: \"3\"]}\n\n  An error is raised if the accessed structure is not a map nor a keyword list:\n\n      iex> get_in([1, 2, 3], [Access.values()])\n      ** (RuntimeError) Access.values/0 expected a map or a keyword list, got: [1, 2, 3]\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec values() :: Access.access_fun(data :: map() | keyword(), current_value :: list())\n  def values do\n    &values/3\n  end\n\n  defp values(:get, data = %{}, next) do\n    Enum.map(data, fn {_key, value} -> next.(value) end)\n  end\n\n  defp values(:get_and_update, data = %{}, next) do\n    {reverse_gets, updated_data} =\n      Enum.reduce(data, {[], %{}}, fn {key, value}, {gets, data_acc} ->\n        case next.(value) do\n          {get, update} -> {[get | gets], Map.put(data_acc, key, update)}\n          :pop -> {[value | gets], data_acc}\n        end\n      end)\n\n    {Enum.reverse(reverse_gets), updated_data}\n  end\n\n  defp values(op, data = [], next) do\n    values_keyword(op, data, next)\n  end\n\n  defp values(op, data = [{key, _value} | _tail], next) when is_atom(key) do\n    values_keyword(op, data, next)\n  end\n\n  defp values(_op, data, _next) do\n    raise \"Access.values/0 expected a map or a keyword list, got: #{inspect(data)}\"\n  end\n\n  defp values_keyword(:get, data, next) do\n    Enum.map(data, fn {key, value} when is_atom(key) -> next.(value) end)\n  end\n\n  defp values_keyword(:get_and_update, data, next) do\n    {reverse_gets, reverse_updated_data} =\n      Enum.reduce(data, {[], []}, fn {key, value}, {gets, data_acc} when is_atom(key) ->\n        case next.(value) do\n          {get, update} -> {[get | gets], [{key, update} | data_acc]}\n          :pop -> {[value | gets], data_acc}\n        end\n      end)\n\n    {Enum.reverse(reverse_gets), Enum.reverse(reverse_updated_data)}\n  end\n\n  defp normalize_range(%Range{first: first, last: last, step: step}, list)\n       when first < 0 or last < 0 do\n    count = length(list)\n    first = if first >= 0, do: first, else: Kernel.max(first + count, 0)\n    last = if last >= 0, do: last, else: last + count\n    Range.new(first, last, step)\n  end\n\n  defp normalize_range(range, _list), do: range\n\n  defp get_and_update_slice([head | rest], range, next, updates, gets, index) do\n    if index in range do\n      case next.(head) do\n        :pop ->\n          get_and_update_slice(rest, range, next, updates, [head | gets], index + 1)\n\n        {get, update} ->\n          get_and_update_slice(\n            rest,\n            range,\n            next,\n            [update | updates],\n            [get | gets],\n            index + 1\n          )\n      end\n    else\n      get_and_update_slice(rest, range, next, [head | updates], gets, index + 1)\n    end\n  end\n\n  defp get_and_update_slice([], _range, _next, updates, gets, _index) do\n    {:lists.reverse(gets), :lists.reverse(updates)}\n  end\n\n  @doc ~S\"\"\"\n  Returns a function that accesses the first element of a list that matches the provided predicate.\n\n  The returned function is typically passed as an accessor to `Kernel.get_in/2`,\n  `Kernel.get_and_update_in/3`, and friends.\n\n  ## Examples\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}]\n      iex> get_in(list, [Access.find(&(&1.salary > 20)), :name])\n      \"francine\"\n      iex> get_and_update_in(list, [Access.find(&(&1.salary <= 40)), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {\"john\", [%{name: \"JOHN\", salary: 10}, %{name: \"francine\", salary: 30}]}\n\n  `find/1` can also be used to pop the first found element out of a list or\n  a key inside of a list:\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}]\n      iex> pop_in(list, [Access.find(&(&1.salary <= 40))])\n      {%{name: \"john\", salary: 10}, [%{name: \"francine\", salary: 30}]}\n\n  When no match is found, nil is returned and the update function is never called\n\n      iex> list = [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}]\n      iex> get_in(list, [Access.find(&(&1.salary >= 50)), :name])\n      nil\n      iex> get_and_update_in(list, [Access.find(&(&1.salary >= 50)), :name], fn prev ->\n      ...>   {prev, String.upcase(prev)}\n      ...> end)\n      {nil, [%{name: \"john\", salary: 10}, %{name: \"francine\", salary: 30}]}\n\n  An error is raised if the accessed structure is not a list:\n\n      iex> get_in(%{}, [Access.find(fn a -> a == 10 end)])\n      ** (RuntimeError) Access.find/1 expected a list, got: %{}\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec find((term -> as_boolean(term))) :: access_fun(data :: list, current_value :: term)\n  def find(predicate) when is_function(predicate, 1) do\n    fn op, data, next -> find(op, data, predicate, next) end\n  end\n\n  defp find(:get, data, predicate, next) when is_list(data) do\n    data |> Enum.find(predicate) |> next.()\n  end\n\n  defp find(:get_and_update, data, predicate, next) when is_list(data) do\n    get_and_update_find(data, [], predicate, next)\n  end\n\n  defp find(_op, data, _predicate, _next) do\n    raise \"Access.find/1 expected a list, got: #{inspect(data)}\"\n  end\n\n  defp get_and_update_find([], updates, _predicate, _next) do\n    {nil, :lists.reverse(updates)}\n  end\n\n  defp get_and_update_find([head | rest], updates, predicate, next) do\n    if predicate.(head) do\n      case next.(head) do\n        {get, update} -> {get, :lists.reverse([update | updates], rest)}\n        :pop -> {head, :lists.reverse(updates, rest)}\n      end\n    else\n      get_and_update_find(rest, [head | updates], predicate, next)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/agent/server.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Agent.Server do\n  @moduledoc false\n\n  use GenServer\n\n  def init(fun) do\n    _ = initial_call(fun)\n    {:ok, run(fun, [])}\n  end\n\n  def handle_call({:get, fun}, _from, state) do\n    {:reply, run(fun, [state]), state}\n  end\n\n  def handle_call({:get_and_update, fun}, _from, state) do\n    case run(fun, [state]) do\n      {reply, state} -> {:reply, reply, state}\n      other -> {:stop, {:bad_return_value, other}, state}\n    end\n  end\n\n  def handle_call({:update, fun}, _from, state) do\n    {:reply, :ok, run(fun, [state])}\n  end\n\n  def handle_cast({:cast, fun}, state) do\n    {:noreply, run(fun, [state])}\n  end\n\n  def code_change(_old, state, fun) do\n    {:ok, run(fun, [state])}\n  end\n\n  defp initial_call(mfa) do\n    _ = Process.put(:\"$initial_call\", get_initial_call(mfa))\n    :ok\n  end\n\n  defp get_initial_call(fun) when is_function(fun, 0) do\n    {:module, module} = Function.info(fun, :module)\n    {:name, name} = Function.info(fun, :name)\n    {module, name, 0}\n  end\n\n  defp get_initial_call({mod, fun, args}) do\n    {mod, fun, length(args)}\n  end\n\n  defp run({m, f, a}, extra), do: apply(m, f, extra ++ a)\n  defp run(fun, extra), do: apply(fun, extra)\nend\n"
  },
  {
    "path": "lib/elixir/lib/agent.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Agent do\n  @moduledoc \"\"\"\n  Agents are a simple abstraction around state.\n\n  Often in Elixir there is a need to share or store state that\n  must be accessed from different processes or by the same process\n  at different points in time.\n\n  The `Agent` module provides a basic server implementation that\n  allows state to be retrieved and updated via a simple API.\n\n  ## Examples\n\n  For example, the following agent implements a counter:\n\n      defmodule Counter do\n        use Agent\n\n        def start_link(initial_value) do\n          Agent.start_link(fn -> initial_value end, name: __MODULE__)\n        end\n\n        def value do\n          Agent.get(__MODULE__, & &1)\n        end\n\n        def increment do\n          Agent.update(__MODULE__, &(&1 + 1))\n        end\n      end\n\n  Usage would be:\n\n      Counter.start_link(0)\n      #=> {:ok, #PID<0.123.0>}\n\n      Counter.value()\n      #=> 0\n\n      Counter.increment()\n      #=> :ok\n\n      Counter.increment()\n      #=> :ok\n\n      Counter.value()\n      #=> 2\n\n  Thanks to the agent server process, the counter can be safely incremented\n  concurrently.\n\n  > #### `use Agent` {: .info}\n  >\n  > When you `use Agent`, the `Agent` module will define a\n  > `child_spec/1` function, so your module can be used\n  > as a child in a supervision tree.\n\n  Agents provide a segregation between the client and server APIs (similar to\n  `GenServer`s). In particular, the functions passed as arguments to the calls to\n  `Agent` functions are invoked inside the agent (the server). This distinction\n  is important because you may want to avoid expensive operations inside the\n  agent, as they will effectively block the agent until the request is\n  fulfilled.\n\n  Consider these two examples:\n\n      # Compute in the agent/server\n      def get_something(agent) do\n        Agent.get(agent, fn state -> do_something_expensive(state) end)\n      end\n\n      # Compute in the agent/client\n      def get_something(agent) do\n        Agent.get(agent, & &1) |> do_something_expensive()\n      end\n\n  The first function blocks the agent. The second function copies all the state\n  to the client and then executes the operation in the client. One aspect to\n  consider is whether the data is large enough to require processing in the server,\n  at least initially, or small enough to be sent to the client cheaply. Another\n  factor is whether the data needs to be processed atomically: getting the\n  state and calling `do_something_expensive(state)` outside of the agent means\n  that the agent's state can be updated in the meantime. This is specially\n  important in case of updates as computing the new state in the client rather\n  than in the server can lead to race conditions if multiple clients are trying\n  to update the same state to different values.\n\n  ## How to supervise\n\n  An `Agent` is most commonly started under a supervision tree.\n  When we invoke `use Agent`, it automatically defines a `child_spec/1`\n  function that allows us to start the agent directly under a supervisor.\n  To start an agent under a supervisor with an initial counter of 0,\n  one may do:\n\n      children = [\n        {Counter, 0}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_all)\n\n  While one could also simply pass the `Counter` as a child to the supervisor,\n  such as:\n\n      children = [\n        Counter # Same as {Counter, []}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_all)\n\n  The definition above wouldn't work for this particular example,\n  as it would attempt to start the counter with an initial value\n  of an empty list. However, this may be a viable option in your\n  own agents. A common approach is to use a keyword list, as that\n  would allow setting the initial value and giving a name to the\n  counter process, for example:\n\n      def start_link(opts) do\n        {initial_value, opts} = Keyword.pop(opts, :initial_value, 0)\n        Agent.start_link(fn -> initial_value end, opts)\n      end\n\n  and then you can use `Counter`, `{Counter, name: :my_counter}` or\n  even `{Counter, initial_value: 0, name: :my_counter}` as a child\n  specification.\n\n  `use Agent` also accepts a list of options which configures the\n  child specification and therefore how it runs under a supervisor.\n  The generated `child_spec/1` can be customized with the following options:\n\n    * `:id` - the child specification identifier, defaults to the current module\n    * `:restart` - when the child should be restarted, defaults to `:permanent`\n    * `:shutdown` - how to shut down the child, either immediately or by giving it time to shut down\n\n  For example:\n\n      use Agent, restart: :transient, shutdown: 10_000\n\n  See the \"Child specification\" section in the `Supervisor` module for more\n  detailed information. The `@doc` annotation immediately preceding\n  `use Agent` will be attached to the generated `child_spec/1` function.\n\n  ## Name registration\n\n  An agent is bound to the same name registration rules as GenServers.\n  Read more about it in the `GenServer` documentation.\n\n  ## A word on distributed agents\n\n  It is important to consider the limitations of distributed agents. Agents\n  provide two APIs, one that works with anonymous functions and another\n  that expects an explicit module, function, and arguments.\n\n  In a distributed setup with multiple nodes, the API that accepts anonymous\n  functions only works if the caller (client) and the agent have the same\n  version of the caller module.\n\n  Keep in mind this issue also shows up when performing \"rolling upgrades\"\n  with agents. By rolling upgrades we mean the following situation: you wish\n  to deploy a new version of your software by *shutting down* some of your\n  nodes and replacing them with nodes running a new version of the software.\n  In this setup, part of your environment will have one version of a given\n  module and the other part another version (the newer one) of the same module.\n\n  The best solution is to simply use the explicit module, function, and arguments\n  APIs when working with distributed agents.\n\n  ## Hot code swapping\n\n  An agent can have its code hot swapped live by simply passing a module,\n  function, and arguments tuple to the update instruction. For example, imagine\n  you have an agent named `:sample` and you want to convert its inner state\n  from a keyword list to a map. It can be done with the following\n  instruction:\n\n      {:update, :sample, {:advanced, {Enum, :into, [%{}]}}}\n\n  The agent's state will be added to the given list of arguments (`[%{}]`) as\n  the first argument.\n  \"\"\"\n\n  @typedoc \"Return values of `start*` functions\"\n  @type on_start :: {:ok, pid} | {:error, {:already_started, pid} | term}\n\n  @typedoc \"The agent name\"\n  @type name :: atom | {:global, term} | {:via, module, term}\n\n  @typedoc \"The agent reference\"\n  @type agent :: pid | {atom, node} | name\n\n  @typedoc \"The agent state\"\n  @type state :: term\n\n  @doc \"\"\"\n  Returns a specification to start an agent under a supervisor.\n\n  See the \"Child specification\" section in the `Supervisor` module for more detailed information.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  def child_spec(arg) do\n    %{\n      id: Agent,\n      start: {Agent, :start_link, [arg]}\n    }\n  end\n\n  @doc false\n  defmacro __using__(opts) do\n    quote location: :keep, bind_quoted: [opts: opts] do\n      if not Module.has_attribute?(__MODULE__, :doc) do\n        @doc \"\"\"\n        Returns a specification to start this module under a supervisor.\n\n        See `Supervisor`.\n        \"\"\"\n      end\n\n      def child_spec(arg) do\n        default = %{\n          id: __MODULE__,\n          start: {__MODULE__, :start_link, [arg]}\n        }\n\n        Supervisor.child_spec(default, unquote(Macro.escape(opts)))\n      end\n\n      defoverridable child_spec: 1\n    end\n  end\n\n  @doc \"\"\"\n  Starts an agent linked to the current process with the given function.\n\n  This is often used to start the agent as part of a supervision tree.\n\n  Once the agent is spawned, the given function `fun` is invoked in the server\n  process, and should return the initial agent state. Note that `start_link/2`\n  does not return until the given function has returned.\n\n  ## Options\n\n  The `:name` option is used for registration as described in the module\n  documentation.\n\n  If the `:timeout` option is present, the agent is allowed to spend at most\n  the given number of milliseconds on initialization or it will be terminated\n  and the start function will return `{:error, :timeout}`.\n\n  If the `:debug` option is present, the corresponding function in the\n  [`:sys` module](`:sys`) will be invoked.\n\n  If the `:spawn_opt` option is present, its value will be passed as options\n  to the underlying process as in `Process.spawn/4`.\n\n  ## Return values\n\n  If the server is successfully created and initialized, the function returns\n  `{:ok, pid}`, where `pid` is the PID of the server. If an agent with the\n  specified name already exists, the function returns\n  `{:error, {:already_started, pid}}` with the PID of that process.\n\n  If the given function callback fails, the function returns `{:error, reason}`.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start_link(fn -> 42 end)\n      iex> Agent.get(pid, fn state -> state end)\n      42\n\n      iex> {:error, {exception, _stacktrace}} = Agent.start(fn -> raise \"oops\" end)\n      iex> exception\n      %RuntimeError{message: \"oops\"}\n\n  \"\"\"\n  @spec start_link((-> term), GenServer.options()) :: on_start\n  def start_link(fun, options \\\\ []) when is_function(fun, 0) do\n    GenServer.start_link(Agent.Server, fun, options)\n  end\n\n  @doc \"\"\"\n  Starts an agent linked to the current process.\n\n  Same as `start_link/2` but a module, function, and arguments are expected\n  instead of an anonymous function; `fun` in `module` will be called with the\n  given arguments `args` to initialize the state.\n  \"\"\"\n  @spec start_link(module, atom, [term], GenServer.options()) :: on_start\n  def start_link(module, fun, args, options \\\\ []) do\n    GenServer.start_link(Agent.Server, {module, fun, args}, options)\n  end\n\n  @doc \"\"\"\n  Starts an agent process without links (outside of a supervision tree).\n\n  See `start_link/2` for more information.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start(fn -> 42 end)\n      iex> Agent.get(pid, fn state -> state end)\n      42\n\n  \"\"\"\n  @spec start((-> term), GenServer.options()) :: on_start\n  def start(fun, options \\\\ []) when is_function(fun, 0) do\n    GenServer.start(Agent.Server, fun, options)\n  end\n\n  @doc \"\"\"\n  Starts an agent without links with the given module, function, and arguments.\n\n  See `start_link/4` for more information.\n  \"\"\"\n  @spec start(module, atom, [term], GenServer.options()) :: on_start\n  def start(module, fun, args, options \\\\ []) do\n    GenServer.start(Agent.Server, {module, fun, args}, options)\n  end\n\n  @doc \"\"\"\n  Gets an agent value via the given anonymous function.\n\n  The function `fun` is sent to the `agent` which invokes the function\n  passing the agent state. The result of the function invocation is\n  returned from this function.\n\n  `timeout` is an integer greater than zero which specifies how many\n  milliseconds are allowed before the agent executes the function and returns\n  the result value, or the atom `:infinity` to wait indefinitely. If no result\n  is received within the specified time, the function call fails and the caller\n  exits.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start_link(fn -> 42 end)\n      iex> Agent.get(pid, fn state -> state end)\n      42\n\n  \"\"\"\n  @spec get(agent, (state -> a), timeout) :: a when a: var\n  def get(agent, fun, timeout \\\\ 5000) when is_function(fun, 1) do\n    GenServer.call(agent, {:get, fun}, timeout)\n  end\n\n  @doc \"\"\"\n  Gets an agent value via the given function.\n\n  Same as `get/3` but a module, function, and arguments are expected\n  instead of an anonymous function. The state is added as first\n  argument to the given list of arguments.\n  \"\"\"\n  @spec get(agent, module, atom, [term], timeout) :: term\n  def get(agent, module, fun, args, timeout \\\\ 5000) do\n    GenServer.call(agent, {:get, {module, fun, args}}, timeout)\n  end\n\n  @doc \"\"\"\n  Gets and updates the agent state in one operation via the given anonymous\n  function.\n\n  The function `fun` is sent to the `agent` which invokes the function\n  passing the agent state. The function must return a tuple with two\n  elements, the first being the value to return (that is, the \"get\" value)\n  and the second one being the new state of the agent.\n\n  `timeout` is an integer greater than zero which specifies how many\n  milliseconds are allowed before the agent executes the function and returns\n  the result value, or the atom `:infinity` to wait indefinitely. If no result\n  is received within the specified time, the function call fails and the caller\n  exits.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start_link(fn -> 42 end)\n      iex> Agent.get_and_update(pid, fn state -> {state, state + 1} end)\n      42\n      iex> Agent.get(pid, fn state -> state end)\n      43\n\n  \"\"\"\n  @spec get_and_update(agent, (state -> {a, state}), timeout) :: a when a: var\n  def get_and_update(agent, fun, timeout \\\\ 5000) when is_function(fun, 1) do\n    GenServer.call(agent, {:get_and_update, fun}, timeout)\n  end\n\n  @doc \"\"\"\n  Gets and updates the agent state in one operation via the given function.\n\n  Same as `get_and_update/3` but a module, function, and arguments are expected\n  instead of an anonymous function. The state is added as first\n  argument to the given list of arguments.\n  \"\"\"\n  @spec get_and_update(agent, module, atom, [term], timeout) :: term\n  def get_and_update(agent, module, fun, args, timeout \\\\ 5000) do\n    GenServer.call(agent, {:get_and_update, {module, fun, args}}, timeout)\n  end\n\n  @doc \"\"\"\n  Updates the agent state via the given anonymous function.\n\n  The function `fun` is sent to the `agent` which invokes the function\n  passing the agent state. The return value of `fun` becomes the new\n  state of the agent.\n\n  This function always returns `:ok`.\n\n  `timeout` is an integer greater than zero which specifies how many\n  milliseconds are allowed before the agent executes the function and returns\n  the result value, or the atom `:infinity` to wait indefinitely. If no result\n  is received within the specified time, the function call fails and the caller\n  exits.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start_link(fn -> 42 end)\n      iex> Agent.update(pid, fn state -> state + 1 end)\n      :ok\n      iex> Agent.get(pid, fn state -> state end)\n      43\n\n  \"\"\"\n  @spec update(agent, (state -> state), timeout) :: :ok\n  def update(agent, fun, timeout \\\\ 5000) when is_function(fun, 1) do\n    GenServer.call(agent, {:update, fun}, timeout)\n  end\n\n  @doc \"\"\"\n  Updates the agent state via the given function.\n\n  Same as `update/3` but a module, function, and arguments are expected\n  instead of an anonymous function. The state is added as first\n  argument to the given list of arguments.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start_link(fn -> 42 end)\n      iex> Agent.update(pid, Kernel, :+, [12])\n      :ok\n      iex> Agent.get(pid, fn state -> state end)\n      54\n\n  \"\"\"\n  @spec update(agent, module, atom, [term], timeout) :: :ok\n  def update(agent, module, fun, args, timeout \\\\ 5000) do\n    GenServer.call(agent, {:update, {module, fun, args}}, timeout)\n  end\n\n  @doc \"\"\"\n  Performs a cast (*fire and forget*) operation on the agent state.\n\n  The function `fun` is sent to the `agent` which invokes the function\n  passing the agent state. The return value of `fun` becomes the new\n  state of the agent.\n\n  Note that `cast` returns `:ok` immediately, regardless of whether `agent` (or\n  the node it should live on) exists.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start_link(fn -> 42 end)\n      iex> Agent.cast(pid, fn state -> state + 1 end)\n      :ok\n      iex> Agent.get(pid, fn state -> state end)\n      43\n\n  \"\"\"\n  @spec cast(agent, (state -> state)) :: :ok\n  def cast(agent, fun) when is_function(fun, 1) do\n    GenServer.cast(agent, {:cast, fun})\n  end\n\n  @doc \"\"\"\n  Performs a cast (*fire and forget*) operation on the agent state.\n\n  Same as `cast/2` but a module, function, and arguments are expected\n  instead of an anonymous function. The state is added as first\n  argument to the given list of arguments.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start_link(fn -> 42 end)\n      iex> Agent.cast(pid, Kernel, :+, [12])\n      :ok\n      iex> Agent.get(pid, fn state -> state end)\n      54\n\n  \"\"\"\n  @spec cast(agent, module, atom, [term]) :: :ok\n  def cast(agent, module, fun, args) do\n    GenServer.cast(agent, {:cast, {module, fun, args}})\n  end\n\n  @doc \"\"\"\n  Synchronously stops the agent with the given `reason`.\n\n  It returns `:ok` if the agent terminates with the given\n  reason. If the agent terminates with another reason, the call will\n  exit.\n\n  This function keeps OTP semantics regarding error reporting.\n  If the reason is any other than `:normal`, `:shutdown` or\n  `{:shutdown, _}`, an error report will be logged.\n\n  ## Examples\n\n      iex> {:ok, pid} = Agent.start_link(fn -> 42 end)\n      iex> Agent.stop(pid)\n      :ok\n\n  \"\"\"\n  @spec stop(agent, reason :: term, timeout) :: :ok\n  def stop(agent, reason \\\\ :normal, timeout \\\\ :infinity) do\n    GenServer.stop(agent, reason, timeout)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/application.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Application do\n  @moduledoc \"\"\"\n  A module for working with applications and defining application callbacks.\n\n  Applications are the idiomatic way to package software in Erlang/OTP. To get\n  the idea, they are similar to the \"library\" concept common in other\n  programming languages, but with some additional characteristics.\n\n  An application is a component implementing some specific functionality, with a\n  standardized directory structure, configuration, and life cycle. Applications\n  are *loaded*, *started*, and *stopped*. Each application also has its own\n  environment, which provides a unified API for configuring each application.\n\n  Developers typically interact with the application environment and its\n  callback module. Therefore those will be the topics we will cover first\n  before jumping into details about the application resource file and life cycle.\n\n  ## The application environment\n\n  Each application has its own environment. The environment is a keyword list\n  that maps atoms to terms. Note that this environment is unrelated to the\n  operating system environment.\n\n  By default, the environment of an application is an empty list. In a Mix\n  project's `mix.exs` file, you can set the `:env` key in `application/0`:\n\n      def application do\n        [env: [db_host: \"localhost\"]]\n      end\n\n  Now, in your application, you can read this environment by using functions\n  such as `fetch_env!/2` and friends:\n\n      defmodule MyApp.DBClient do\n        def start_link() do\n          SomeLib.DBClient.start_link(host: db_host())\n        end\n\n        defp db_host do\n          Application.fetch_env!(:my_app, :db_host)\n        end\n      end\n\n  In Mix projects, the environment of the application and its dependencies can\n  be overridden via the `config/config.exs` and `config/runtime.exs` files. The\n  former is loaded at build-time, before your code compiles, and the latter at\n  runtime, just before your app starts. For example, someone using your application\n  can override its `:db_host` environment variable as follows:\n\n      import Config\n      config :my_app, :db_host, \"db.local\"\n\n  See the \"Configuration\" section in the `Mix` module for more information.\n  You can also change the application environment dynamically by using functions\n  such as `put_env/3` and `delete_env/2`.\n\n  > #### Application environment in libraries {: .info}\n  >\n  > If you are writing a library to be used by other developers,\n  > it is generally recommended to avoid the application environment, as the\n  > application environment is effectively a global storage. For more information,\n  > read about this [anti-pattern](design-anti-patterns.md#using-application-configuration-for-libraries).\n\n  > #### Reading the environment of other applications {: .warning}\n  >\n  > Each application is responsible for its own environment. Do not\n  > use the functions in this module for directly accessing or modifying\n  > the environment of other applications. Whenever you change the application\n  > environment, Elixir's build tool will only recompile the files that\n  > belong to that application. So if you read the application environment\n  > of another application, there is a chance you will be depending on\n  > outdated configuration, as your file won't be recompiled as it changes.\n\n  ## Compile-time environment\n\n  In the previous example, we read the application environment at runtime:\n\n      defmodule MyApp.DBClient do\n        def start_link() do\n          SomeLib.DBClient.start_link(host: db_host())\n        end\n\n        defp db_host do\n          Application.fetch_env!(:my_app, :db_host)\n        end\n      end\n\n  In other words, the environment key `:db_host` for application `:my_app`\n  will only be read when `MyApp.DBClient` effectively starts. While reading\n  the application environment at runtime is the preferred approach, in some\n  rare occasions you may want to use the application environment to configure\n  the compilation of a certain project. However, if you try to access\n  `Application.fetch_env!/2` outside of a function:\n\n      defmodule MyApp.DBClient do\n        @db_host Application.fetch_env!(:my_app, :db_host)\n\n        def start_link() do\n          SomeLib.DBClient.start_link(host: @db_host)\n        end\n      end\n\n  You might see warnings and errors:\n\n      warning: Application.fetch_env!/2 is discouraged in the module body,\n      use Application.compile_env/3 instead\n        iex:3: MyApp.DBClient\n\n      ** (ArgumentError) could not fetch application environment :db_host\n      for application :my_app because the application was not loaded nor\n      configured\n\n  This happens because, when defining modules, the application environment\n  is not yet available. Luckily, the warning tells us how to solve this\n  issue, by using `Application.compile_env/3` instead:\n\n      defmodule MyApp.DBClient do\n        @db_host Application.compile_env(:my_app, :db_host, \"db.local\")\n\n        def start_link() do\n          SomeLib.DBClient.start_link(host: @db_host)\n        end\n      end\n\n  The difference here is that `compile_env` expects the default value to be\n  given as an argument, instead of using the `def application` function of\n  your `mix.exs`. Furthermore, by using `compile_env/3`, tools like Mix will\n  store the values used during compilation and compare the compilation values\n  with the runtime values whenever your system starts, raising an error in\n  case they differ.\n\n  In any case, compile-time environments should be avoided. Whenever possible,\n  reading the application environment at runtime should be the first choice.\n\n  ## The application callback module\n\n  Applications can be loaded, started, and stopped. Generally, build tools\n  like Mix take care of starting an application and all of its dependencies\n  for you, but you can also do it manually by calling:\n\n      {:ok, _} = Application.ensure_all_started(:some_app)\n\n  When an application starts, developers may configure a callback module\n  that executes custom code. Developers use this callback to start the\n  application supervision tree.\n\n  The first step to do so is to add a `:mod` key to the `application/0`\n  definition in your `mix.exs` file. It expects a tuple, with the application\n  callback module and start argument (commonly an empty list):\n\n      def application do\n        [mod: {MyApp, []}]\n      end\n\n  The `MyApp` module given to `:mod` needs to implement the `Application` behaviour.\n  This can be done by putting `use Application` in that module and implementing the\n  `c:start/2` callback, for example:\n\n      defmodule MyApp do\n        use Application\n\n        def start(_type, _args) do\n          children = []\n          Supervisor.start_link(children, strategy: :one_for_one)\n        end\n      end\n\n  > #### `use Application` {: .info}\n  >\n  > When you `use Application`, the `Application` module will\n  > set `@behaviour Application` and define an overridable\n  > definition for the `c:stop/1` function, which is required\n  > by Erlang/OTP.\n\n  The `c:start/2` callback has to spawn and link a supervisor and return `{:ok,\n  pid}` or `{:ok, pid, state}`, where `pid` is the PID of the supervisor, and\n  `state` is an optional application state. `args` is the second element of the\n  tuple given to the `:mod` option.\n\n  The `type` argument passed to `c:start/2` is usually `:normal` unless in a\n  distributed setup where application takeovers and failovers are configured.\n  Distributed applications are beyond the scope of this documentation.\n\n  When an application is shutting down, its `c:stop/1` callback is called after\n  the supervision tree has been stopped by the runtime. This callback allows the\n  application to do any final cleanup. The argument is the state returned by\n  `c:start/2`, if it did, or `[]` otherwise. The return value of `c:stop/1` is\n  ignored.\n\n  By using `Application`, modules get a default implementation of `c:stop/1`\n  that ignores its argument and returns `:ok`, but it can be overridden.\n\n  Application callback modules may also implement the optional callback\n  `c:prep_stop/1`. If present, `c:prep_stop/1` is invoked before the supervision\n  tree is terminated. Its argument is the state returned by `c:start/2`, if it did,\n  or `[]` otherwise, and its return value is passed to `c:stop/1`.\n\n  ## The application resource file\n\n  In the sections above, we have configured an application in the\n  `application/0` section of the `mix.exs` file. Ultimately, Mix will use\n  this configuration to create an [*application resource\n  file*](https://www.erlang.org/doc/man/app), which is a file called\n  `APP_NAME.app`. For example, the application resource file of the OTP\n  application `ex_unit` is called `ex_unit.app`.\n\n  You can learn more about the generation of application resource files in\n  the documentation of `Mix.Tasks.Compile.App`, available as well by running\n  `mix help compile.app`.\n\n  ## The application life cycle\n\n  ### Loading applications\n\n  Applications are *loaded*, which means that the runtime finds and processes\n  their resource files:\n\n      Application.load(:ex_unit)\n      #=> :ok\n\n  When an application is loaded, the environment specified in its resource file\n  is merged with any overrides from config files.\n\n  Loading an application *does not* load its modules.\n\n  In practice, you rarely load applications by hand because that is part of the\n  start process, explained next.\n\n  ### Starting applications\n\n  Applications are also *started*:\n\n      Application.start(:ex_unit)\n      #=> :ok\n\n  Once your application is compiled, running your system is a matter of starting\n  your current application and its dependencies. Differently from other languages,\n  Elixir does not have a `main` procedure that is responsible for starting your\n  system. Instead, you start one or more applications, each with their own\n  initialization and termination logic.\n\n  When an application is started, the `Application.load/1` is automatically\n  invoked if it hasn't been done yet. Then, it checks if the dependencies listed\n  in the `applications` key of the resource file are already started. Having at\n  least one dependency not started is an error condition. Functions like\n  `ensure_all_started/1` take care of starting an application and all of its\n  dependencies for you.\n\n  If the application does not have a callback module configured, starting is\n  done at this point. Otherwise, its `c:start/2` callback is invoked. The PID of\n  the top-level supervisor returned by this function is stored by the runtime\n  for later use, and the returned application state is saved too, if any.\n\n  ### Stopping applications\n\n  Started applications are, finally, *stopped*:\n\n      Application.stop(:ex_unit)\n      #=> :ok\n\n  Stopping an application without a callback module defined, is in practice a\n  no-op, except for some system tracing.\n\n  Stopping an application with a callback module has three steps:\n\n    1. If present, invoke the optional callback `c:prep_stop/1`.\n    2. Terminate the top-level supervisor.\n    3. Invoke the required callback `c:stop/1`.\n\n  The arguments passed to the callbacks are related to the state optionally\n  returned by `c:start/2`, and are documented in the section about the callback\n  module above.\n\n  It is important to highlight that step 2 is a blocking one. Termination of a\n  supervisor triggers a recursive chain of children terminations, therefore\n  orderly shutting down all descendant processes. The `c:stop/1` callback is\n  invoked only after termination of the whole supervision tree.\n\n  Shutting down a live system cleanly can be done by calling `System.stop/1`. It\n  will shut down every application in the reverse order they were started.\n\n  By default, a SIGTERM from the operating system will automatically translate to\n  `System.stop/0`. You can also have more explicit control over operating system\n  signals via the `:os.set_signal/2` function.\n\n  ## Tooling\n\n  The Mix build tool automates most of the application management tasks. For example,\n  `mix test` automatically starts your application dependencies and your application\n  itself before your test runs. `mix run --no-halt` boots your current project and\n  can be used to start a long running system. See `mix help run`.\n\n  Developers can also use `mix release` to build **releases**. Releases are able to\n  package all of your source code as well as the Erlang VM into a single directory.\n  Releases also give you explicit control over how each application is started and in\n  which order. They also provide a more streamlined mechanism for starting and\n  stopping systems, debugging, logging, as well as system monitoring.\n\n  Finally, Elixir provides tools such as escripts and archives, which are\n  different mechanisms for packaging your application. Those are typically used\n  when tools must be shared between developers and not as deployment options.\n  See `mix help archive.build` and `mix help escript.build` for more detail.\n\n  ## Further information\n\n  For further details on applications please check the documentation of the\n  [`:application` Erlang module](`:application`), and the\n  [Applications](https://www.erlang.org/doc/design_principles/applications.html)\n  section of the [OTP Design Principles User's\n  Guide](https://www.erlang.org/doc/design_principles/users_guide.html).\n  \"\"\"\n\n  @doc \"\"\"\n  Called when an application is started.\n\n  This function is called when an application is started using\n  `Application.start/2` (and functions on top of that, such as\n  `Application.ensure_started/2`). This function should start the top-level\n  process of the application (which should be the top supervisor of the\n  application's supervision tree if the application follows the OTP design\n  principles around supervision).\n\n  `start_type` defines how the application is started:\n\n    * `:normal` - used if the startup is a normal startup or if the application\n      is distributed and is started on the current node because of a failover\n      from another node and the application specification key `:start_phases`\n      is `:undefined`.\n    * `{:takeover, node}` - used if the application is distributed and is\n      started on the current node because of a failover on the node `node`.\n    * `{:failover, node}` - used if the application is distributed and is\n      started on the current node because of a failover on node `node`, and the\n      application specification key `:start_phases` is not `:undefined`.\n\n  `start_args` are the arguments passed to the application in the `:mod`\n  specification key (for example, `mod: {MyApp, [:my_args]}`).\n\n  This function should either return `{:ok, pid}` or `{:ok, pid, state}` if\n  startup is successful. `pid` should be the PID of the top supervisor. `state`\n  can be an arbitrary term, and if omitted will default to `[]`; if the\n  application is later stopped, `state` is passed to the `stop/1` callback (see\n  the documentation for the `c:stop/1` callback for more information).\n\n  `use Application` provides no default implementation for the `start/2`\n  callback.\n  \"\"\"\n  @callback start(start_type, start_args :: term) ::\n              {:ok, pid}\n              | {:ok, pid, state}\n              | {:error, reason :: term}\n\n  @doc \"\"\"\n  Called before stopping the application.\n\n  This function is called before the top-level supervisor is terminated. It\n  receives the state returned by `c:start/2`, if it did, or `[]` otherwise.\n  The return value is later passed to `c:stop/1`.\n  \"\"\"\n  @callback prep_stop(state) :: state\n\n  @doc \"\"\"\n  Called after an application has been stopped.\n\n  This function is called after an application has been stopped, i.e., after its\n  supervision tree has been stopped. It should do the opposite of what the\n  `c:start/2` callback did, and should perform any necessary cleanup. The return\n  value of this callback is ignored.\n\n  `state` is the state returned by `c:start/2`, if it did, or `[]` otherwise.\n  If the optional callback `c:prep_stop/1` is present, `state` is its return\n  value instead.\n\n  `use Application` defines a default implementation of this function which does\n  nothing and just returns `:ok`.\n  \"\"\"\n  @callback stop(state) :: term\n\n  @doc \"\"\"\n  Starts an application in synchronous phases.\n\n  This function is called after `start/2` finishes but before\n  `Application.start/2` returns. It will be called once for every start phase\n  defined in the application's (and any included applications') specification,\n  in the order they are listed in.\n  \"\"\"\n  @callback start_phase(phase :: term, start_type, phase_args :: term) ::\n              :ok | {:error, reason :: term}\n\n  @doc \"\"\"\n  Callback invoked after code upgrade, if the application environment\n  has changed.\n\n  `changed` is a keyword list of keys and their changed values in the\n  application environment. `new` is a keyword list with all new keys\n  and their values. `removed` is a list with all removed keys.\n  \"\"\"\n  @callback config_change(changed, new, removed) :: :ok\n            when changed: keyword, new: keyword, removed: [atom]\n\n  @optional_callbacks start_phase: 3, prep_stop: 1, config_change: 3\n\n  @doc false\n  defmacro __using__(_) do\n    quote location: :keep do\n      @behaviour Application\n\n      @doc false\n      def stop(_state) do\n        :ok\n      end\n\n      defoverridable Application\n    end\n  end\n\n  @application_keys [\n    :description,\n    :id,\n    :vsn,\n    :modules,\n    :maxP,\n    :maxT,\n    :registered,\n    :included_applications,\n    :optional_applications,\n    :applications,\n    :mod,\n    :start_phases\n  ]\n\n  application_key_specs = Enum.reduce(@application_keys, &{:|, [], [&1, &2]})\n\n  @type app :: atom\n  @type key :: atom\n  @type application_key :: unquote(application_key_specs)\n  @type value :: term\n  @type state :: term\n  @type start_type :: :normal | {:takeover, node} | {:failover, node}\n\n  @typedoc \"\"\"\n  Specifies the type of the application:\n\n    * `:permanent` - if `app` terminates, all other applications and the entire\n      node are also terminated.\n\n    * `:transient` - if `app` terminates with `:normal` reason, it is reported\n      but no other applications are terminated. If a transient application\n      terminates abnormally, all other applications and the entire node are\n      also terminated.\n\n    * `:temporary` - if `app` terminates, it is reported but no other\n      applications are terminated (the default).\n\n  Note that it is always possible to stop an application explicitly by calling\n  `stop/1`. Regardless of the type of the application, no other applications will\n  be affected.\n\n  Note also that the `:transient` type is of little practical use, since when a\n  supervision tree terminates, the reason is set to `:shutdown`, not `:normal`.\n  \"\"\"\n  @type restart_type :: :permanent | :transient | :temporary\n\n  @doc \"\"\"\n  Returns the spec for `app`.\n\n  The following keys are returned:\n\n    * #{Enum.map_join(@application_keys, \"\\n  * \", &\"`#{inspect(&1)}`\")}\n\n  For a description of all fields, see [Erlang's application\n  specification](https://www.erlang.org/doc/man/app).\n\n  Note the environment is not returned as it can be accessed via\n  `fetch_env/2`. Returns `nil` if the application is not loaded.\n  \"\"\"\n  @spec spec(app) :: [{application_key, value}] | nil\n  def spec(app) when is_atom(app) do\n    case :application.get_all_key(app) do\n      {:ok, info} -> :lists.keydelete(:env, 1, info)\n      :undefined -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Returns the value for `key` in `app`'s specification.\n\n  See `spec/1` for the supported keys. If the given\n  specification parameter does not exist, this function\n  will raise. Returns `nil` if the application is not loaded.\n  \"\"\"\n  @spec spec(app, application_key) :: value | nil\n  def spec(app, key) when is_atom(app) and key in @application_keys do\n    case :application.get_key(app, key) do\n      {:ok, value} -> value\n      :undefined -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Gets the application for the given module.\n\n  The application is located by analyzing the spec\n  of all loaded applications. Returns `nil` if\n  the module is not listed in any application spec.\n  \"\"\"\n  @spec get_application(module) :: app | nil\n  def get_application(module) when is_atom(module) do\n    case :application.get_application(module) do\n      {:ok, app} -> app\n      :undefined -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Returns all key-value pairs for `app`.\n  \"\"\"\n  @spec get_all_env(app) :: [{key, value}]\n  def get_all_env(app) when is_atom(app) do\n    :application.get_all_env(app)\n  end\n\n  @doc \"\"\"\n  Reads the application environment at compilation time.\n\n  Similar to `get_env/3`, except it must be used to read values\n  at compile time. This allows Elixir to track when configuration\n  values change between compile time and runtime.\n\n  The first argument is the application name. The second argument\n  `key_or_path` is either an atom key or a path to traverse in\n  search of the configuration, starting with an atom key.\n\n  For example, imagine the following configuration:\n\n      config :my_app, :key, [foo: [bar: :baz]]\n\n  We can access it during compile time as:\n\n      Application.compile_env(:my_app, :key)\n      #=> [foo: [bar: :baz]]\n\n      Application.compile_env(:my_app, [:key, :foo])\n      #=> [bar: :baz]\n\n      Application.compile_env(:my_app, [:key, :foo, :bar])\n      #=> :baz\n\n  A default value can also be given as third argument. If\n  any of the keys in the path along the way is missing, the\n  default value is used:\n\n      Application.compile_env(:my_app, [:unknown, :foo, :bar], :default)\n      #=> :default\n\n      Application.compile_env(:my_app, [:key, :unknown, :bar], :default)\n      #=> :default\n\n      Application.compile_env(:my_app, [:key, :foo, :unknown], :default)\n      #=> :default\n\n  Giving a path is useful to let Elixir know that only certain paths\n  in a large configuration are compile time dependent.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec compile_env(app, key | list, value) :: value\n  defmacro compile_env(app, key_or_path, default \\\\ nil) do\n    if __CALLER__.function do\n      raise \"Application.compile_env/3 cannot be called inside functions, only in the module body\"\n    end\n\n    key_or_path = Macro.expand_literals(key_or_path, %{__CALLER__ | function: {:__info__, 1}})\n\n    quote do\n      Application.compile_env(__ENV__, unquote(app), unquote(key_or_path), unquote(default))\n    end\n  end\n\n  @doc \"\"\"\n  Reads the application environment at compilation time from a macro.\n\n  Typically, developers will use `compile_env/3`. This function must\n  only be invoked from macros which aim to read the compilation environment\n  dynamically.\n\n  It expects a `Macro.Env` as first argument, where the `Macro.Env` is\n  typically the `__CALLER__` in a macro. It raises if `Macro.Env` comes\n  from a function.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec compile_env(Macro.Env.t(), app, key | list, value) :: value\n  def compile_env(%Macro.Env{} = env, app, key_or_path, default) do\n    case fetch_compile_env(app, key_or_path, env) do\n      {:ok, value} -> value\n      :error -> default\n    end\n  end\n\n  @doc \"\"\"\n  Reads the application environment at compilation time or raises.\n\n  This is the same as `compile_env/3` but it raises an\n  `ArgumentError` if the configuration is not available.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec compile_env!(app, key | list) :: value\n  defmacro compile_env!(app, key_or_path) do\n    if __CALLER__.function do\n      raise \"Application.compile_env!/2 cannot be called inside functions, only in the module body\"\n    end\n\n    key_or_path = Macro.expand_literals(key_or_path, %{__CALLER__ | function: {:__info__, 1}})\n\n    quote do\n      Application.compile_env!(__ENV__, unquote(app), unquote(key_or_path))\n    end\n  end\n\n  @doc \"\"\"\n  Reads the application environment at compilation time from a macro\n  or raises.\n\n  Typically, developers will use `compile_env!/2`. This function must\n  only be invoked from macros which aim to read the compilation environment\n  dynamically.\n\n  It expects a `Macro.Env` as first argument, where the `Macro.Env` is\n  typically the `__CALLER__` in a macro. It raises if `Macro.Env` comes\n  from a function.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec compile_env!(Macro.Env.t(), app, key | list) :: value\n  def compile_env!(%Macro.Env{} = env, app, key_or_path) do\n    case fetch_compile_env(app, key_or_path, env) do\n      {:ok, value} ->\n        value\n\n      :error ->\n        raise ArgumentError,\n              \"could not fetch application environment #{inspect(key_or_path)} for application \" <>\n                \"#{inspect(app)} #{fetch_env_failed_reason(app, key_or_path)}\"\n    end\n  end\n\n  defp fetch_compile_env(app, key, env) when is_atom(key) do\n    fetch_compile_env(app, key, [], env)\n  end\n\n  defp fetch_compile_env(app, [key | paths], env) when is_atom(key),\n    do: fetch_compile_env(app, key, paths, env)\n\n  defp fetch_compile_env(app, key, path, env) do\n    return = traverse_env(fetch_env(app, key), path)\n\n    for tracer <- env.tracers do\n      tracer.trace({:compile_env, app, [key | path], return}, env)\n    end\n\n    return\n  end\n\n  defp traverse_env(return, []), do: return\n  defp traverse_env(:error, _paths), do: :error\n  defp traverse_env({:ok, value}, [key | keys]), do: traverse_env(Access.fetch(value, key), keys)\n\n  @doc \"\"\"\n  Returns the value for `key` in `app`'s environment.\n\n  If the configuration parameter does not exist, the function returns the\n  `default` value.\n\n  > #### Warning {: .warning}\n  >\n  > You must use this function to read only your own application\n  > environment. Do not read the environment of other applications.\n\n  ## Examples\n\n  `get_env/3` is commonly used to read the configuration of your OTP applications.\n  Since Mix configurations are commonly used to configure applications (including\n  your dependencies), we will use this as a point of illustration.\n\n  Consider a new application `:my_app`. `:my_app` contains a database engine which\n  supports a pool of databases. The database engine needs to know the configuration for\n  each of those databases, and that configuration is supplied by key-value pairs in\n  environment of `:my_app`. For example, your `config/runtime.exs` file might have:\n\n      config :my_app, Databases.RepoOne,\n        # A database configuration\n        ip: \"localhost\",\n        port: 5433\n\n      config :my_app, Databases.RepoTwo,\n        # Another database configuration (for the same OTP app)\n        ip: \"localhost\",\n        port: 20_717\n\n      config :my_app, my_app_databases: [Databases.RepoOne, Databases.RepoTwo]\n\n  Our database engine used by `:my_app` needs to know what databases exist, and\n  what the database configurations are. The database engine can make a call to\n  `Application.get_env(:my_app, :my_app_databases, [])` to retrieve the list of\n  databases (specified by module names).\n\n  The engine can then traverse each repository in the list and call\n  `Application.get_env(:my_app, Databases.RepoOne)` and so forth to retrieve the\n  configuration of each one. In this case, each configuration will be a keyword\n  list, so you can use the functions in the `Keyword` module or even the `Access`\n  module to traverse it, for example:\n\n      config = Application.get_env(:my_app, Databases.RepoOne)\n      config[:ip]\n\n  The sample `config/runtime.exs` above could be used both for `:my_app` to\n  configure itself but also to allow any application that depends on `:my_app`\n  to configure how it works. However, one should keep in mind the caveats described\n  in the `Application` module documentation: the application environment is global\n  state which should be avoided if possible.\n  \"\"\"\n  @spec get_env(app, key, value) :: value\n  def get_env(app, key, default \\\\ nil) when is_atom(app) do\n    maybe_warn_on_app_env_key(app, key)\n    :application.get_env(app, key, default)\n  end\n\n  @doc \"\"\"\n  Returns the value for `key` in `app`'s environment in a tuple.\n\n  If the configuration parameter does not exist, the function returns `:error`.\n\n  > #### Warning {: .warning}\n  >\n  > You must use this function to read only your own application\n  > environment. Do not read the environment of other applications.\n\n  > #### Application environment in info\n  >\n  > If you are writing a library to be used by other developers,\n  > it is generally recommended to avoid the application environment, as the\n  > application environment is effectively a global storage. For more information,\n  > read our [library guidelines](library-guidelines.md).\n  \"\"\"\n  @spec fetch_env(app, key) :: {:ok, value} | :error\n  def fetch_env(app, key) when is_atom(app) do\n    maybe_warn_on_app_env_key(app, key)\n\n    case :application.get_env(app, key) do\n      {:ok, value} -> {:ok, value}\n      :undefined -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Returns the value for `key` in `app`'s environment.\n\n  If the configuration parameter does not exist, raises `ArgumentError`.\n\n  > #### Warning {: .warning}\n  >\n  > You must use this function to read only your own application\n  > environment. Do not read the environment of other applications.\n\n  > #### Application environment in info\n  >\n  > If you are writing a library to be used by other developers,\n  > it is generally recommended to avoid the application environment, as the\n  > application environment is effectively a global storage. For more information,\n  > read our [library guidelines](library-guidelines.md).\n  \"\"\"\n  @spec fetch_env!(app, key) :: value\n  def fetch_env!(app, key) when is_atom(app) do\n    case fetch_env(app, key) do\n      {:ok, value} ->\n        value\n\n      :error ->\n        raise ArgumentError,\n              \"could not fetch application environment #{inspect(key)} for application \" <>\n                \"#{inspect(app)} #{fetch_env_failed_reason(app, key)}\"\n    end\n  end\n\n  defp fetch_env_failed_reason(app, key) do\n    vsn = :application.get_key(app, :vsn)\n\n    case vsn do\n      {:ok, _} ->\n        \"because configuration at #{inspect(key)} was not set\"\n\n      :undefined ->\n        \"because the application was not loaded nor configured\"\n    end\n  end\n\n  @doc \"\"\"\n  Puts the `value` in `key` for the given `app`.\n\n  > #### Compile environment {: .warning}\n  >\n  > Do not use this function to change environment variables read\n  > via `Application.compile_env/2`. The compile environment must\n  > be exclusively set before compilation, in your config files.\n\n  ## Options\n\n    * `:timeout` - the timeout for the change (defaults to `5_000` milliseconds)\n    * `:persistent` - persists the given value on application load and reloads\n\n  If `put_env/4` is called before the application is loaded, the application\n  environment values specified in the `.app` file will override the ones\n  previously set.\n\n  The `:persistent` option can be set to `true` when there is a need to guarantee\n  parameters set with this function will not be overridden by the ones defined\n  in the application resource file on load. This means persistent values will\n  stick after the application is loaded and also on application reload.\n  \"\"\"\n  @spec put_env(app, key, value, timeout: timeout, persistent: boolean) :: :ok\n  def put_env(app, key, value, opts \\\\ []) when is_atom(app) and is_list(opts) do\n    maybe_warn_on_app_env_key(app, key)\n    :application.set_env(app, key, value, opts)\n  end\n\n  @doc \"\"\"\n  Puts the environment for multiple applications at the same time.\n\n  The given config should not:\n\n    * have the same application listed more than once\n    * have the same key inside the same application listed more than once\n\n  If those conditions are not met, this function will raise.\n\n  This function receives the same options as `put_env/4`. Returns `:ok`.\n\n  ## Examples\n\n      Application.put_all_env(\n        my_app: [\n          key: :value,\n          another_key: :another_value\n        ],\n        another_app: [\n          key: :value\n        ]\n      )\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec put_all_env([{app, [{key, value}]}], timeout: timeout, persistent: boolean) :: :ok\n  def put_all_env(config, opts \\\\ []) when is_list(config) and is_list(opts) do\n    :application.set_env(config, opts)\n  end\n\n  @doc \"\"\"\n  Deletes the `key` from the given `app` environment.\n\n  It receives the same options as `put_env/4`. Returns `:ok`.\n  \"\"\"\n  @spec delete_env(app, key, timeout: timeout, persistent: boolean) :: :ok\n  def delete_env(app, key, opts \\\\ []) when is_atom(app) and is_list(opts) do\n    maybe_warn_on_app_env_key(app, key)\n    :application.unset_env(app, key, opts)\n  end\n\n  defp maybe_warn_on_app_env_key(_app, key) when is_atom(key),\n    do: :ok\n\n  # TODO: Remove this deprecation warning on 2.0+ and allow list lookups as in compile_env.\n  defp maybe_warn_on_app_env_key(app, key) do\n    message = fn ->\n      \"passing non-atom as application env key is deprecated, got: #{inspect(key)}\"\n    end\n\n    IO.warn_once({Application, :key, app, key}, message, _stacktrace_drop_levels = 2)\n  end\n\n  @doc \"\"\"\n  Ensures the given `app` is started with `t:restart_type/0`.\n\n  Same as `start/2` but returns `:ok` if the application was already\n  started.\n  \"\"\"\n  @spec ensure_started(app, restart_type()) :: :ok | {:error, term}\n  def ensure_started(app, type \\\\ :temporary) when is_atom(app) and is_atom(type) do\n    :application.ensure_started(app, type)\n  end\n\n  @doc \"\"\"\n  Ensures the given `app` is loaded.\n\n  Same as `load/1` but returns `:ok` if the application was already\n  loaded.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec ensure_loaded(app) :: :ok | {:error, term}\n  def ensure_loaded(app) when is_atom(app) do\n    case :application.load(app) do\n      :ok -> :ok\n      {:error, {:already_loaded, ^app}} -> :ok\n      {:error, _} = error -> error\n    end\n  end\n\n  @doc \"\"\"\n  Ensures the given `app` or `apps` and their child applications are started.\n\n  The second argument is either the `t:restart_type/0` (for consistency with\n  `start/2`) or a keyword list.\n\n  ## Options\n\n    * `:type` - if the application should be started `:temporary` (default),\n      `:permanent`, or `:transient`. See `t:restart_type/0` for more information.\n\n    * `:mode` - (since v1.15.0) if the applications should be started serially\n      (`:serial`, default) or concurrently (`:concurrent`).\n\n  \"\"\"\n  @spec ensure_all_started(app | [app], type: restart_type(), mode: :serial | :concurrent) ::\n          {:ok, [app]} | {:error, term}\n  @spec ensure_all_started(app | [app], restart_type()) ::\n          {:ok, [app]} | {:error, term}\n  def ensure_all_started(app_or_apps, type_or_opts \\\\ [])\n\n  def ensure_all_started(app_or_apps, type) when is_atom(type) do\n    ensure_all_started(app_or_apps, type: type)\n  end\n\n  def ensure_all_started(app, opts) when is_atom(app) and is_list(opts) do\n    ensure_all_started([app], opts)\n  end\n\n  @compile {:no_warn_undefined, {:application, :ensure_all_started, 3}}\n\n  def ensure_all_started(apps, opts) when is_list(apps) and is_list(opts) do\n    opts = Keyword.validate!(opts, type: :temporary, mode: :serial)\n    :application.ensure_all_started(apps, opts[:type], opts[:mode])\n  end\n\n  @doc \"\"\"\n  Starts the given `app` with `t:restart_type/0`.\n\n  If the `app` is not loaded, the application will first be loaded using `load/1`.\n  Any included application, defined in the `:included_applications` key of the\n  `.app` file will also be loaded, but they won't be started.\n\n  Furthermore, all applications listed in the `:applications` key must be explicitly\n  started before this application is. If not, `{:error, {:not_started, app}}` is\n  returned, where `app` is the name of the missing application.\n\n  In case you want to automatically load **and start** all of `app`'s dependencies,\n  see `ensure_all_started/2`.\n  \"\"\"\n  @spec start(app, restart_type()) :: :ok | {:error, term}\n  def start(app, type \\\\ :temporary) when is_atom(app) and is_atom(type) do\n    :application.start(app, type)\n  end\n\n  @doc \"\"\"\n  Stops the given `app`.\n\n  When stopped, the application is still loaded.\n  \"\"\"\n  @spec stop(app) :: :ok | {:error, term}\n  def stop(app) when is_atom(app) do\n    :application.stop(app)\n  end\n\n  @doc \"\"\"\n  Loads the given `app`.\n\n  In order to be loaded, an `.app` file must be in the load paths.\n  All `:included_applications` will also be loaded.\n\n  Loading the application does not start it nor load its modules, but\n  it does load its environment.\n  \"\"\"\n  @spec load(app) :: :ok | {:error, term}\n  def load(app) when is_atom(app) do\n    :application.load(app)\n  end\n\n  @doc \"\"\"\n  Unloads the given `app`.\n\n  It will also unload all `:included_applications`.\n  Note that the function does not purge the application modules.\n  \"\"\"\n  @spec unload(app) :: :ok | {:error, term}\n  def unload(app) when is_atom(app) do\n    :application.unload(app)\n  end\n\n  @doc \"\"\"\n  Gets the directory for app.\n\n  This information is returned based on the code path. Here is an\n  example:\n\n      File.mkdir_p!(\"foo/ebin\")\n      Code.prepend_path(\"foo/ebin\")\n      Application.app_dir(:foo)\n      #=> \"foo\"\n\n  Even though the directory is empty and there is no `.app` file\n  it is considered the application directory based on the name\n  \"foo/ebin\". The name may contain a dash `-` which is considered\n  to be the app version and it is removed for the lookup purposes:\n\n      File.mkdir_p!(\"bar-123/ebin\")\n      Code.prepend_path(\"bar-123/ebin\")\n      Application.app_dir(:bar)\n      #=> \"bar-123\"\n\n  For more information on code paths, check the `Code` module in\n  Elixir and also Erlang's [`:code` module](`:code`).\n  \"\"\"\n  @spec app_dir(app) :: String.t()\n  def app_dir(app) when is_atom(app) do\n    case :code.lib_dir(app) do\n      lib when is_list(lib) -> IO.chardata_to_string(lib)\n      {:error, :bad_name} -> raise ArgumentError, \"unknown application: #{inspect(app)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Returns the given path inside `app_dir/1`.\n\n  If `path` is a string, then it will be used as the path inside `app_dir/1`. If\n  `path` is a list of strings, it will be joined (see `Path.join/1`) and the result\n  will be used as the path inside `app_dir/1`.\n\n  ## Examples\n\n      File.mkdir_p!(\"foo/ebin\")\n      Code.prepend_path(\"foo/ebin\")\n\n      Application.app_dir(:foo, \"my_path\")\n      #=> \"foo/my_path\"\n\n      Application.app_dir(:foo, [\"my\", \"nested\", \"path\"])\n      #=> \"foo/my/nested/path\"\n\n  \"\"\"\n  @spec app_dir(app, String.t() | [String.t()]) :: String.t()\n  def app_dir(app, path)\n\n  def app_dir(app, path) when is_atom(app) and is_binary(path) do\n    Path.join(app_dir(app), path)\n  end\n\n  def app_dir(app, path) when is_atom(app) and is_list(path) do\n    Path.join([app_dir(app) | path])\n  end\n\n  @doc \"\"\"\n  Returns a list with information about the applications which are currently running.\n  \"\"\"\n  @spec started_applications(timeout) :: [{app, description :: charlist(), vsn :: charlist()}]\n  def started_applications(timeout \\\\ 5000)\n      when timeout == :infinity or (is_integer(timeout) and timeout >= 0) do\n    :application.which_applications(timeout)\n  end\n\n  @doc \"\"\"\n  Returns a list with information about the applications which have been loaded.\n  \"\"\"\n  @spec loaded_applications :: [{app, description :: charlist(), vsn :: charlist()}]\n  def loaded_applications do\n    :application.loaded_applications()\n  end\n\n  @doc \"\"\"\n  Formats the error reason returned by `start/2`,\n  `ensure_started/2`, `stop/1`, `load/1` and `unload/1`,\n  returns a string.\n  \"\"\"\n  @spec format_error(any) :: String.t()\n  def format_error(reason) do\n    try do\n      do_format_error(reason)\n    catch\n      # A user could create an error that looks like a built-in one\n      # causing an error.\n      :error, _ ->\n        inspect(reason)\n    end\n  end\n\n  # exit(:normal) call is special cased, undo the special case.\n  defp do_format_error({{:EXIT, :normal}, {mod, :start, args}}) do\n    Exception.format_exit({:normal, {mod, :start, args}})\n  end\n\n  # {:error, reason} return value\n  defp do_format_error({reason, {mod, :start, args}}) do\n    Exception.format_mfa(mod, :start, args) <>\n      \" returned an error: \" <> Exception.format_exit(reason)\n  end\n\n  # error or exit(reason) call, use exit reason as reason.\n  defp do_format_error({:bad_return, {{mod, :start, args}, {:EXIT, reason}}}) do\n    Exception.format_exit({reason, {mod, :start, args}})\n  end\n\n  # bad return value\n  defp do_format_error({:bad_return, {{mod, :start, args}, return}}) do\n    Exception.format_mfa(mod, :start, args) <> \" returned a bad value: \" <> inspect(return)\n  end\n\n  defp do_format_error({:already_started, app}) when is_atom(app) do\n    \"already started application #{app}\"\n  end\n\n  defp do_format_error({:not_started, app}) when is_atom(app) do\n    \"not started application #{app}\"\n  end\n\n  defp do_format_error({:bad_application, app}) do\n    \"bad application: #{inspect(app)}\"\n  end\n\n  defp do_format_error({:already_loaded, app}) when is_atom(app) do\n    \"already loaded application #{app}\"\n  end\n\n  defp do_format_error({:not_loaded, app}) when is_atom(app) do\n    \"not loaded application #{app}\"\n  end\n\n  defp do_format_error({:invalid_restart_type, restart}) do\n    \"invalid application restart type: #{inspect(restart)}\"\n  end\n\n  defp do_format_error({:invalid_name, name}) do\n    \"invalid application name: #{inspect(name)}\"\n  end\n\n  defp do_format_error({:invalid_options, opts}) do\n    \"invalid application options: #{inspect(opts)}\"\n  end\n\n  defp do_format_error({:badstartspec, spec}) do\n    \"bad application start specs: #{inspect(spec)}\"\n  end\n\n  defp do_format_error({~c\"no such file or directory\", file}) do\n    \"could not find application file: #{file}\"\n  end\n\n  defp do_format_error(reason) do\n    Exception.format_exit(reason)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/atom.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Atom do\n  @moduledoc \"\"\"\n  Atoms are constants whose values are their own name.\n\n  They are often useful to enumerate over distinct values, such as:\n\n      iex> :apple\n      :apple\n      iex> :orange\n      :orange\n      iex> :watermelon\n      :watermelon\n\n  Atoms are equal if their names are equal.\n\n      iex> :apple == :apple\n      true\n      iex> :apple == :orange\n      false\n\n  Often they are used to express the state of an operation, by using\n  values such as `:ok` and `:error`.\n\n  The booleans `true` and `false` are also atoms:\n\n      iex> true == :true\n      true\n      iex> is_atom(false)\n      true\n      iex> is_boolean(:false)\n      true\n\n  Elixir allows you to skip the leading `:` for the atoms `false`, `true`,\n  and `nil`.\n\n  Atoms must be composed of Unicode characters such as letters, numbers,\n  underscore, and `@`. If the keyword has a character that does not\n  belong to the category above, such as spaces, you can wrap it in\n  quotes:\n\n      iex> :\"this is an atom with spaces\"\n      :\"this is an atom with spaces\"\n\n  \"\"\"\n\n  @doc \"\"\"\n  Converts an atom to a string.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Atom.to_string(:foo)\n      \"foo\"\n\n  \"\"\"\n  @spec to_string(atom) :: String.t()\n  def to_string(atom) do\n    :erlang.atom_to_binary(atom)\n  end\n\n  @doc \"\"\"\n  Converts an atom to a charlist.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Atom.to_charlist(:\"An atom\")\n      ~c\"An atom\"\n\n  \"\"\"\n  @spec to_charlist(atom) :: charlist\n  def to_charlist(atom) do\n    :erlang.atom_to_list(atom)\n  end\n\n  @doc false\n  @deprecated \"Use Atom.to_charlist/1 instead\"\n  @spec to_char_list(atom) :: charlist\n  def to_char_list(atom), do: Atom.to_charlist(atom)\nend\n"
  },
  {
    "path": "lib/elixir/lib/base.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Base do\n  import Bitwise\n\n  @moduledoc \"\"\"\n  This module provides data encoding and decoding functions\n  according to [RFC 4648](https://tools.ietf.org/html/rfc4648).\n\n  This document defines the commonly used base 16, base 32, and base\n  64 encoding schemes.\n\n  ## Base 16 alphabet\n\n  | Value | Encoding | Value | Encoding | Value | Encoding | Value | Encoding |\n  |------:|:---------|------:|:---------|------:|:---------|------:|:---------|\n  |     0 | 0        |     4 | 4        |     8 | 8        |    12 | C        |\n  |     1 | 1        |     5 | 5        |     9 | 9        |    13 | D        |\n  |     2 | 2        |     6 | 6        |    10 | A        |    14 | E        |\n  |     3 | 3        |     7 | 7        |    11 | B        |    15 | F        |\n\n  ## Base 32 alphabet\n\n  | Value | Encoding | Value | Encoding | Value | Encoding | Value | Encoding |\n  |------:|:---------|------:|:---------|------:|:---------|------:|:---------|\n  |     0 | A        |     9 | J        |    18 | S        |    27 | 3        |\n  |     1 | B        |    10 | K        |    19 | T        |    28 | 4        |\n  |     2 | C        |    11 | L        |    20 | U        |    29 | 5        |\n  |     3 | D        |    12 | M        |    21 | V        |    30 | 6        |\n  |     4 | E        |    13 | N        |    22 | W        |    31 | 7        |\n  |     5 | F        |    14 | O        |    23 | X        |       |          |\n  |     6 | G        |    15 | P        |    24 | Y        | (pad) | =        |\n  |     7 | H        |    16 | Q        |    25 | Z        |       |          |\n  |     8 | I        |    17 | R        |    26 | 2        |       |          |\n\n\n  ## Base 32 (extended hex) alphabet\n\n  | Value | Encoding | Value | Encoding | Value | Encoding | Value | Encoding |\n  |------:|:---------|------:|:---------|------:|:---------|------:|:---------|\n  |     0 | 0        |     9 | 9        |    18 | I        |    27 | R        |\n  |     1 | 1        |    10 | A        |    19 | J        |    28 | S        |\n  |     2 | 2        |    11 | B        |    20 | K        |    29 | T        |\n  |     3 | 3        |    12 | C        |    21 | L        |    30 | U        |\n  |     4 | 4        |    13 | D        |    22 | M        |    31 | V        |\n  |     5 | 5        |    14 | E        |    23 | N        |       |          |\n  |     6 | 6        |    15 | F        |    24 | O        | (pad) | =        |\n  |     7 | 7        |    16 | G        |    25 | P        |       |          |\n  |     8 | 8        |    17 | H        |    26 | Q        |       |          |\n\n  ## Base 64 alphabet\n\n  | Value |  Encoding | Value | Encoding | Value | Encoding | Value | Encoding |\n  |------:|:----------|------:|:---------|------:|:---------|------:|:---------|\n  |     0 | A         |    17 | R        |    34 | i        |    51 | z        |\n  |     1 | B         |    18 | S        |    35 | j        |    52 | 0        |\n  |     2 | C         |    19 | T        |    36 | k        |    53 | 1        |\n  |     3 | D         |    20 | U        |    37 | l        |    54 | 2        |\n  |     4 | E         |    21 | V        |    38 | m        |    55 | 3        |\n  |     5 | F         |    22 | W        |    39 | n        |    56 | 4        |\n  |     6 | G         |    23 | X        |    40 | o        |    57 | 5        |\n  |     7 | H         |    24 | Y        |    41 | p        |    58 | 6        |\n  |     8 | I         |    25 | Z        |    42 | q        |    59 | 7        |\n  |     9 | J         |    26 | a        |    43 | r        |    60 | 8        |\n  |    10 | K         |    27 | b        |    44 | s        |    61 | 9        |\n  |    11 | L         |    28 | c        |    45 | t        |    62 | +        |\n  |    12 | M         |    29 | d        |    46 | u        |    63 | /        |\n  |    13 | N         |    30 | e        |    47 | v        |       |          |\n  |    14 | O         |    31 | f        |    48 | w        | (pad) | =        |\n  |    15 | P         |    32 | g        |    49 | x        |       |          |\n  |    16 | Q         |    33 | h        |    50 | y        |       |          |\n\n  ## Base 64 (URL and filename safe) alphabet\n\n  | Value | Encoding | Value | Encoding | Value | Encoding | Value | Encoding |\n  |------:|:---------|------:|:---------|------:|:---------|------:|:---------|\n  |     0 | A        |    17 | R        |    34 | i        |    51 | z        |\n  |     1 | B        |    18 | S        |    35 | j        |    52 | 0        |\n  |     2 | C        |    19 | T        |    36 | k        |    53 | 1        |\n  |     3 | D        |    20 | U        |    37 | l        |    54 | 2        |\n  |     4 | E        |    21 | V        |    38 | m        |    55 | 3        |\n  |     5 | F        |    22 | W        |    39 | n        |    56 | 4        |\n  |     6 | G        |    23 | X        |    40 | o        |    57 | 5        |\n  |     7 | H        |    24 | Y        |    41 | p        |    58 | 6        |\n  |     8 | I        |    25 | Z        |    42 | q        |    59 | 7        |\n  |     9 | J        |    26 | a        |    43 | r        |    60 | 8        |\n  |    10 | K        |    27 | b        |    44 | s        |    61 | 9        |\n  |    11 | L        |    28 | c        |    45 | t        |    62 | -        |\n  |    12 | M        |    29 | d        |    46 | u        |    63 | _        |\n  |    13 | N        |    30 | e        |    47 | v        |       |          |\n  |    14 | O        |    31 | f        |    48 | w        | (pad) | =        |\n  |    15 | P        |    32 | g        |    49 | x        |       |          |\n  |    16 | Q        |    33 | h        |    50 | y        |       |          |\n\n  \"\"\"\n\n  @type encode_case :: :upper | :lower\n  @type decode_case :: :upper | :lower | :mixed\n\n  b16_alphabet = ~c\"0123456789ABCDEF\"\n  b64_alphabet = ~c\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n  b64url_alphabet = ~c\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\"\n  b32_alphabet = ~c\"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\"\n  b32hex_alphabet = ~c\"0123456789ABCDEFGHIJKLMNOPQRSTUV\"\n\n  to_lower_enc = &Enum.map(&1, fn c -> if c in ?A..?Z, do: c - ?A + ?a, else: c end)\n\n  to_mixed_dec =\n    &Enum.flat_map(&1, fn {encoding, value} = pair ->\n      if encoding in ?A..?Z do\n        [pair, {encoding - ?A + ?a, value}]\n      else\n        [pair]\n      end\n    end)\n\n  to_lower_dec =\n    &Enum.map(&1, fn {encoding, value} = pair ->\n      if encoding in ?A..?Z do\n        {encoding - ?A + ?a, value}\n      else\n        pair\n      end\n    end)\n\n  to_encode_list = fn alphabet ->\n    for e1 <- alphabet, e2 <- alphabet, do: bsl(e1, 8) + e2\n  end\n\n  to_decode_list = fn alphabet ->\n    alphabet = Enum.sort(alphabet)\n    map = Map.new(alphabet)\n    {min, _} = List.first(alphabet)\n    {max, _} = List.last(alphabet)\n    {min, Enum.map(min..max, &map[&1])}\n  end\n\n  defp bad_character!(byte) do\n    raise ArgumentError,\n          \"non-alphabet character found: #{inspect(<<byte>>, binaries: :as_strings)} (byte #{byte})\"\n  end\n\n  defp maybe_pad(acc, false, _count), do: acc\n  defp maybe_pad(acc, true, 6), do: acc <> \"======\"\n  defp maybe_pad(acc, true, 4), do: acc <> \"====\"\n  defp maybe_pad(acc, true, 3), do: acc <> \"===\"\n  defp maybe_pad(acc, true, 2), do: acc <> \"==\"\n  defp maybe_pad(acc, true, 1), do: acc <> \"=\"\n\n  defp remove_ignored(string, nil), do: string\n\n  defp remove_ignored(string, :whitespace) do\n    for <<char::8 <- string>>, char not in ~c\"\\s\\t\\r\\n\", into: <<>>, do: <<char::8>>\n  end\n\n  @doc \"\"\"\n  Encodes a binary string into a base 16 encoded string.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to use when encoding\n\n  The values for `:case` can be:\n\n    * `:upper` - uses upper case characters (default)\n    * `:lower` - uses lower case characters\n\n  ## Examples\n\n      iex> Base.encode16(\"foobar\")\n      \"666F6F626172\"\n\n      iex> Base.encode16(\"foobar\", case: :lower)\n      \"666f6f626172\"\n\n  \"\"\"\n  @spec encode16(binary, case: encode_case) :: binary\n  def encode16(data, opts \\\\ []) when is_binary(data) do\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> encode16upper(data, \"\")\n      :lower -> encode16lower(data, \"\")\n    end\n  end\n\n  for {base, alphabet} <- [upper: b16_alphabet, lower: to_lower_enc.(b16_alphabet)] do\n    name = :\"encode16#{base}\"\n    encoded = to_encode_list.(alphabet)\n\n    @compile {:inline, [{name, 1}]}\n    defp unquote(name)(byte) do\n      elem({unquote_splicing(encoded)}, byte)\n    end\n\n    defp unquote(name)(<<c1, c2, c3, c4, c5, c6, c7, c8, rest::binary>>, acc) do\n      unquote(name)(\n        rest,\n        <<\n          acc::binary,\n          unquote(name)(c1)::16,\n          unquote(name)(c2)::16,\n          unquote(name)(c3)::16,\n          unquote(name)(c4)::16,\n          unquote(name)(c5)::16,\n          unquote(name)(c6)::16,\n          unquote(name)(c7)::16,\n          unquote(name)(c8)::16\n        >>\n      )\n    end\n\n    defp unquote(name)(<<c1, c2, c3, c4, rest::binary>>, acc) do\n      unquote(name)(\n        rest,\n        <<\n          acc::binary,\n          unquote(name)(c1)::16,\n          unquote(name)(c2)::16,\n          unquote(name)(c3)::16,\n          unquote(name)(c4)::16\n        >>\n      )\n    end\n\n    defp unquote(name)(<<c1, c2, rest::binary>>, acc) do\n      unquote(name)(rest, <<acc::binary, unquote(name)(c1)::16, unquote(name)(c2)::16>>)\n    end\n\n    defp unquote(name)(<<c1, rest::binary>>, acc) do\n      unquote(name)(rest, <<acc::binary, unquote(name)(c1)::16>>)\n    end\n\n    defp unquote(name)(<<>>, acc) do\n      acc\n    end\n  end\n\n  @doc \"\"\"\n  Decodes a base 16 encoded string into a binary string.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to accept when decoding\n\n  The values for `:case` can be:\n\n    * `:upper` - only allows upper case characters (default)\n    * `:lower` - only allows lower case characters\n    * `:mixed` - allows mixed case characters\n\n  ## Examples\n\n      iex> Base.decode16(\"666F6F626172\")\n      {:ok, \"foobar\"}\n\n      iex> Base.decode16(\"666f6f626172\", case: :lower)\n      {:ok, \"foobar\"}\n\n      iex> Base.decode16(\"666f6F626172\", case: :mixed)\n      {:ok, \"foobar\"}\n\n  \"\"\"\n  @spec decode16(binary, case: decode_case) :: {:ok, binary} | :error\n  def decode16(string, opts \\\\ []) do\n    {:ok, decode16!(string, opts)}\n  rescue\n    ArgumentError -> :error\n  end\n\n  @doc \"\"\"\n  Decodes a base 16 encoded string into a binary string.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to accept when decoding\n\n  The values for `:case` can be:\n\n    * `:upper` - only allows upper case characters (default)\n    * `:lower` - only allows lower case characters\n    * `:mixed` - allows mixed case characters\n\n  An `ArgumentError` exception is raised if the padding is incorrect or\n  a non-alphabet character is present in the string.\n\n  ## Examples\n\n      iex> Base.decode16!(\"666F6F626172\")\n      \"foobar\"\n\n      iex> Base.decode16!(\"666f6f626172\", case: :lower)\n      \"foobar\"\n\n      iex> Base.decode16!(\"666f6F626172\", case: :mixed)\n      \"foobar\"\n\n  \"\"\"\n  @spec decode16!(binary, case: decode_case) :: binary\n  def decode16!(string, opts \\\\ [])\n\n  def decode16!(string, opts) when is_binary(string) and rem(byte_size(string), 2) == 0 do\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> decode16upper!(string, \"\")\n      :lower -> decode16lower!(string, \"\")\n      :mixed -> decode16mixed!(string, \"\")\n    end\n  end\n\n  def decode16!(string, _opts) when is_binary(string) do\n    raise ArgumentError,\n          \"string given to decode has wrong length. An even number of bytes was expected, got: #{byte_size(string)}. \" <>\n            \"Double check your string for unwanted characters or pad it accordingly\"\n  end\n\n  @doc \"\"\"\n  Checks if a string is a valid base 16 encoded string.\n\n  > #### When to use this {: .tip}\n  >\n  > Use this function when you just need to *validate* that a string is\n  > valid base 16 data, without actually producing a decoded output string.\n  > This function is both more performant and memory efficient than using\n  > `decode16/2`, checking that the result is `{:ok, ...}`, and then\n  > discarding the decoded binary.\n\n  ## Options\n\n  Accepts the same options as `decode16/2`.\n\n  ## Examples\n\n      iex> Base.valid16?(\"666F6F626172\")\n      true\n\n      iex> Base.valid16?(\"666f6f626172\", case: :lower)\n      true\n\n      iex> Base.valid16?(\"666f6F626172\", case: :mixed)\n      true\n\n      iex> Base.valid16?(\"ff\", case: :upper)\n      false\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec valid16?(binary, case: decode_case) :: boolean\n  def valid16?(string, opts \\\\ [])\n\n  def valid16?(string, opts) when is_binary(string) and rem(byte_size(string), 2) == 0 do\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> validate16upper?(string)\n      :lower -> validate16lower?(string)\n      :mixed -> validate16mixed?(string)\n    end\n  end\n\n  def valid16?(string, _opts) when is_binary(string) do\n    false\n  end\n\n  upper = Enum.with_index(b16_alphabet)\n\n  for {base, alphabet} <- [upper: upper, lower: to_lower_dec.(upper), mixed: to_mixed_dec.(upper)] do\n    decode_name = :\"decode16#{base}!\"\n    validate_name = :\"validate16#{base}?\"\n    valid_char_name = :\"valid_char16#{base}?\"\n\n    {min, decoded} = to_decode_list.(alphabet)\n\n    defp unquote(validate_name)(<<>>), do: true\n\n    defp unquote(validate_name)(<<c1, c2, rest::binary>>) do\n      unquote(valid_char_name)(c1) and\n        unquote(valid_char_name)(c2) and\n        unquote(validate_name)(rest)\n    end\n\n    defp unquote(validate_name)(<<_char, _rest::binary>>), do: false\n\n    @compile {:inline, [{valid_char_name, 1}]}\n    defp unquote(valid_char_name)(char)\n         when elem({unquote_splicing(decoded)}, char - unquote(min)) != nil,\n         do: true\n\n    defp unquote(valid_char_name)(_char), do: false\n\n    defp unquote(decode_name)(char) do\n      index = char - unquote(min)\n\n      cond do\n        index not in 0..unquote(length(decoded) - 1) -> bad_character!(char)\n        new_char = elem({unquote_splicing(decoded)}, index) -> new_char\n        true -> bad_character!(char)\n      end\n    end\n\n    defp unquote(decode_name)(<<c1, c2, c3, c4, c5, c6, c7, c8, rest::binary>>, acc) do\n      unquote(decode_name)(\n        rest,\n        <<\n          acc::binary,\n          unquote(decode_name)(c1)::4,\n          unquote(decode_name)(c2)::4,\n          unquote(decode_name)(c3)::4,\n          unquote(decode_name)(c4)::4,\n          unquote(decode_name)(c5)::4,\n          unquote(decode_name)(c6)::4,\n          unquote(decode_name)(c7)::4,\n          unquote(decode_name)(c8)::4\n        >>\n      )\n    end\n\n    defp unquote(decode_name)(<<c1, c2, c3, c4, rest::binary>>, acc) do\n      unquote(decode_name)(\n        rest,\n        <<\n          acc::binary,\n          unquote(decode_name)(c1)::4,\n          unquote(decode_name)(c2)::4,\n          unquote(decode_name)(c3)::4,\n          unquote(decode_name)(c4)::4\n        >>\n      )\n    end\n\n    defp unquote(decode_name)(<<c1::8, c2::8, rest::binary>>, acc) do\n      unquote(decode_name)(\n        rest,\n        <<acc::binary, unquote(decode_name)(c1)::4, unquote(decode_name)(c2)::4>>\n      )\n    end\n\n    defp unquote(decode_name)(<<>>, acc) do\n      acc\n    end\n  end\n\n  @doc \"\"\"\n  Encodes a binary string into a base 64 encoded string.\n\n  Accepts `padding: false` option which will omit padding from\n  the output string.\n\n  ## Examples\n\n      iex> Base.encode64(\"foobar\")\n      \"Zm9vYmFy\"\n\n      iex> Base.encode64(\"foob\")\n      \"Zm9vYg==\"\n\n      iex> Base.encode64(\"foob\", padding: false)\n      \"Zm9vYg\"\n\n  \"\"\"\n  @spec encode64(binary, padding: boolean) :: binary\n  def encode64(data, opts \\\\ []) when is_binary(data) do\n    pad? = Keyword.get(opts, :padding, true)\n    encode64base(data, \"\", pad?)\n  end\n\n  @doc \"\"\"\n  Encodes a binary string into a base 64 encoded string with URL and filename\n  safe alphabet.\n\n  Accepts `padding: false` option which will omit padding from\n  the output string.\n\n  ## Examples\n\n      iex> Base.url_encode64(<<255, 127, 254, 252>>)\n      \"_3_-_A==\"\n\n      iex> Base.url_encode64(<<255, 127, 254, 252>>, padding: false)\n      \"_3_-_A\"\n\n  \"\"\"\n  @spec url_encode64(binary, padding: boolean) :: binary\n  def url_encode64(data, opts \\\\ []) when is_binary(data) do\n    pad? = Keyword.get(opts, :padding, true)\n    encode64url(data, \"\", pad?)\n  end\n\n  for {base, alphabet} <- [base: b64_alphabet, url: b64url_alphabet] do\n    name = :\"encode64#{base}\"\n    encoded = to_encode_list.(alphabet)\n\n    @compile {:inline, [{name, 1}]}\n    defp unquote(name)(byte) do\n      elem({unquote_splicing(encoded)}, byte)\n    end\n\n    defp unquote(name)(<<c1::12, c2::12, c3::12, c4::12, rest::binary>>, acc, pad?) do\n      unquote(name)(\n        rest,\n        <<\n          acc::binary,\n          unquote(name)(c1)::16,\n          unquote(name)(c2)::16,\n          unquote(name)(c3)::16,\n          unquote(name)(c4)::16\n        >>,\n        pad?\n      )\n    end\n\n    defp unquote(name)(<<c1::12, c2::12, c3::12, c4::4>>, acc, pad?) do\n      <<\n        acc::binary,\n        unquote(name)(c1)::16,\n        unquote(name)(c2)::16,\n        unquote(name)(c3)::16,\n        c4 |> bsl(2) |> unquote(name)() |> band(0x00FF)::8\n      >>\n      |> maybe_pad(pad?, 1)\n    end\n\n    defp unquote(name)(<<c1::12, c2::12, c3::8>>, acc, pad?) do\n      <<\n        acc::binary,\n        unquote(name)(c1)::16,\n        unquote(name)(c2)::16,\n        c3 |> bsl(4) |> unquote(name)()::16\n      >>\n      |> maybe_pad(pad?, 2)\n    end\n\n    defp unquote(name)(<<c1::12, c2::12>>, acc, _pad?) do\n      <<\n        acc::binary,\n        unquote(name)(c1)::16,\n        unquote(name)(c2)::16\n      >>\n    end\n\n    defp unquote(name)(<<c1::12, c2::4>>, acc, pad?) do\n      <<\n        acc::binary,\n        unquote(name)(c1)::16,\n        c2 |> bsl(2) |> unquote(name)() |> band(0x00FF)::8\n      >>\n      |> maybe_pad(pad?, 1)\n    end\n\n    defp unquote(name)(<<c1::8>>, acc, pad?) do\n      <<\n        acc::binary,\n        c1 |> bsl(4) |> unquote(name)()::16\n      >>\n      |> maybe_pad(pad?, 2)\n    end\n\n    defp unquote(name)(<<>>, acc, _pad?) do\n      acc\n    end\n  end\n\n  @doc \"\"\"\n  Decodes a base 64 encoded string into a binary string.\n\n  Accepts `ignore: :whitespace` option which will ignore all the\n  whitespace characters in the input string.\n\n  Accepts `padding: false` option which will ignore padding from\n  the input string.\n\n  ## Examples\n\n      iex> Base.decode64(\"Zm9vYmFy\")\n      {:ok, \"foobar\"}\n\n      iex> Base.decode64(\"Zm9vYmFy\\\\n\", ignore: :whitespace)\n      {:ok, \"foobar\"}\n\n      iex> Base.decode64(\"Zm9vYg==\")\n      {:ok, \"foob\"}\n\n      iex> Base.decode64(\"Zm9vYg\", padding: false)\n      {:ok, \"foob\"}\n\n  \"\"\"\n  @spec decode64(binary, ignore: :whitespace, padding: boolean) :: {:ok, binary} | :error\n  def decode64(string, opts \\\\ []) when is_binary(string) do\n    {:ok, decode64!(string, opts)}\n  rescue\n    ArgumentError -> :error\n  end\n\n  @doc \"\"\"\n  Decodes a base 64 encoded string into a binary string.\n\n  Accepts `ignore: :whitespace` option which will ignore all the\n  whitespace characters in the input string.\n\n  Accepts `padding: false` option which will ignore padding from\n  the input string.\n\n  An `ArgumentError` exception is raised if the padding is incorrect or\n  a non-alphabet character is present in the string.\n\n  ## Examples\n\n      iex> Base.decode64!(\"Zm9vYmFy\")\n      \"foobar\"\n\n      iex> Base.decode64!(\"Zm9vYmFy\\\\n\", ignore: :whitespace)\n      \"foobar\"\n\n      iex> Base.decode64!(\"Zm9vYg==\")\n      \"foob\"\n\n      iex> Base.decode64!(\"Zm9vYg\", padding: false)\n      \"foob\"\n\n  \"\"\"\n  @spec decode64!(binary, ignore: :whitespace, padding: boolean) :: binary\n  def decode64!(string, opts \\\\ []) when is_binary(string) do\n    pad? = Keyword.get(opts, :padding, true)\n    string |> remove_ignored(opts[:ignore]) |> decode64base!(pad?)\n  end\n\n  @doc \"\"\"\n  Validates a base 64 encoded string.\n\n  > #### When to use this {: .tip}\n  >\n  > Use this function when you just need to *validate* that a string is\n  > valid base 64 data, without actually producing a decoded output string.\n  > This function is both more performant and memory efficient than using\n  > `decode64/2`, checking that the result is `{:ok, ...}`, and then\n  > discarding the decoded binary.\n\n  ## Options\n\n  Accepts the same options as `decode64/2`.\n\n  ## Examples\n\n      iex> Base.valid64?(\"Zm9vYmFy\")\n      true\n\n      iex> Base.valid64?(\"Zm9vYmFy\\\\n\", ignore: :whitespace)\n      true\n\n      iex> Base.valid64?(\"Zm9vYg==\")\n      true\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec valid64?(binary, ignore: :whitespace, padding: boolean) :: boolean\n  def valid64?(string, opts \\\\ []) when is_binary(string) do\n    pad? = Keyword.get(opts, :padding, true)\n    string |> remove_ignored(opts[:ignore]) |> validate64base?(pad?)\n  end\n\n  @doc \"\"\"\n  Decodes a base 64 encoded string with URL and filename safe alphabet\n  into a binary string.\n\n  Accepts `ignore: :whitespace` option which will ignore all the\n  whitespace characters in the input string.\n\n  Accepts `padding: false` option which will ignore padding from\n  the input string.\n\n  ## Examples\n\n      iex> Base.url_decode64(\"_3_-_A==\")\n      {:ok, <<255, 127, 254, 252>>}\n\n      iex> Base.url_decode64(\"_3_-_A==\\\\n\", ignore: :whitespace)\n      {:ok, <<255, 127, 254, 252>>}\n\n      iex> Base.url_decode64(\"_3_-_A\", padding: false)\n      {:ok, <<255, 127, 254, 252>>}\n\n  \"\"\"\n  @spec url_decode64(binary, ignore: :whitespace, padding: boolean) :: {:ok, binary} | :error\n  def url_decode64(string, opts \\\\ []) when is_binary(string) do\n    {:ok, url_decode64!(string, opts)}\n  rescue\n    ArgumentError -> :error\n  end\n\n  @doc \"\"\"\n  Decodes a base 64 encoded string with URL and filename safe alphabet\n  into a binary string.\n\n  Accepts `ignore: :whitespace` option which will ignore all the\n  whitespace characters in the input string.\n\n  Accepts `padding: false` option which will ignore padding from\n  the input string.\n\n  An `ArgumentError` exception is raised if the padding is incorrect or\n  a non-alphabet character is present in the string.\n\n  ## Examples\n\n      iex> Base.url_decode64!(\"_3_-_A==\")\n      <<255, 127, 254, 252>>\n\n      iex> Base.url_decode64!(\"_3_-_A==\\\\n\", ignore: :whitespace)\n      <<255, 127, 254, 252>>\n\n      iex> Base.url_decode64!(\"_3_-_A\", padding: false)\n      <<255, 127, 254, 252>>\n\n  \"\"\"\n  @spec url_decode64!(binary, ignore: :whitespace, padding: boolean) :: binary\n  def url_decode64!(string, opts \\\\ []) when is_binary(string) do\n    pad? = Keyword.get(opts, :padding, true)\n    string |> remove_ignored(opts[:ignore]) |> decode64url!(pad?)\n  end\n\n  @doc \"\"\"\n  Validates a base 64 encoded string with URL and filename safe alphabet.\n\n  > #### When to use this {: .tip}\n  >\n  > Use this function when you just need to *validate* that a string is\n  > valid (URL-safe) base 64 data, without actually producing a decoded\n  > output string. This function is both more performant and memory efficient\n  > than using `url_decode64/2`, checking that the result is `{:ok, ...}`,\n  > and then discarding the decoded binary.\n\n  ## Options\n\n  Accepts the same options as `url_decode64/2`.\n\n  ## Examples\n\n      iex> Base.url_valid64?(\"_3_-_A==\")\n      true\n\n      iex> Base.url_valid64?(\"_3_-_A==\\\\n\", ignore: :whitespace)\n      true\n\n      iex> Base.url_valid64?(\"_3_-_A\", padding: false)\n      true\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec url_valid64?(binary, ignore: :whitespace, padding: boolean) :: boolean\n  def url_valid64?(string, opts \\\\ []) when is_binary(string) do\n    pad? = Keyword.get(opts, :padding, true)\n    string |> remove_ignored(opts[:ignore]) |> validate64url?(pad?)\n  end\n\n  for {base, alphabet} <- [base: b64_alphabet, url: b64url_alphabet] do\n    decode_name = :\"decode64#{base}!\"\n\n    validate_name = :\"validate64#{base}?\"\n    validate_main_name = :\"validate_main64#{validate_name}?\"\n    valid_char_name = :\"valid_char64#{base}?\"\n    {min, decoded} = alphabet |> Enum.with_index() |> to_decode_list.()\n\n    defp unquote(validate_main_name)(<<>>), do: true\n\n    defp unquote(validate_main_name)(\n           <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8, rest::binary>>\n         ) do\n      unquote(valid_char_name)(c1) and\n        unquote(valid_char_name)(c2) and\n        unquote(valid_char_name)(c3) and\n        unquote(valid_char_name)(c4) and\n        unquote(valid_char_name)(c5) and\n        unquote(valid_char_name)(c6) and\n        unquote(valid_char_name)(c7) and\n        unquote(valid_char_name)(c8) and\n        unquote(validate_main_name)(rest)\n    end\n\n    defp unquote(validate_name)(<<>>, _pad?), do: true\n\n    defp unquote(validate_name)(string, pad?) do\n      segs = div(byte_size(string) + 7, 8) - 1\n      <<main::size(^segs)-binary-unit(64), rest::binary>> = string\n      main_valid? = unquote(validate_main_name)(main)\n\n      case rest do\n        _ when not main_valid? ->\n          false\n\n        <<c1::8, c2::8, ?=, ?=>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2)\n\n        <<c1::8, c2::8, c3::8, ?=>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3)\n\n        <<c1::8, c2::8, c3::8, c4::8>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, ?=, ?=>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5) and\n            unquote(valid_char_name)(c6)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, ?=>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5) and\n            unquote(valid_char_name)(c6) and\n            unquote(valid_char_name)(c7)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5) and\n            unquote(valid_char_name)(c6) and\n            unquote(valid_char_name)(c7) and\n            unquote(valid_char_name)(c8)\n\n        <<c1::8, c2::8>> when not pad? ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2)\n\n        <<c1::8, c2::8, c3::8>> when not pad? ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8>> when not pad? ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5) and\n            unquote(valid_char_name)(c6)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8>> when not pad? ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5) and\n            unquote(valid_char_name)(c6) and\n            unquote(valid_char_name)(c7)\n\n        _ ->\n          false\n      end\n    end\n\n    @compile {:inline, [{valid_char_name, 1}]}\n    defp unquote(valid_char_name)(char)\n         when elem({unquote_splicing(decoded)}, char - unquote(min)) != nil,\n         do: true\n\n    defp unquote(valid_char_name)(_char), do: false\n\n    defp unquote(decode_name)(char) do\n      index = char - unquote(min)\n\n      cond do\n        index not in 0..unquote(length(decoded) - 1) -> bad_character!(char)\n        new_char = elem({unquote_splicing(decoded)}, index) -> new_char\n        true -> bad_character!(char)\n      end\n    end\n\n    defp unquote(decode_name)(<<>>, _pad?), do: <<>>\n\n    defp unquote(decode_name)(string, pad?) do\n      segs = div(byte_size(string) + 7, 8) - 1\n      <<main::size(^segs)-binary-unit(64), rest::binary>> = string\n\n      main =\n        for <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8 <- main>>, into: <<>> do\n          <<\n            unquote(decode_name)(c1)::6,\n            unquote(decode_name)(c2)::6,\n            unquote(decode_name)(c3)::6,\n            unquote(decode_name)(c4)::6,\n            unquote(decode_name)(c5)::6,\n            unquote(decode_name)(c6)::6,\n            unquote(decode_name)(c7)::6,\n            unquote(decode_name)(c8)::6\n          >>\n        end\n\n      case rest do\n        <<c1::8, c2::8, ?=, ?=>> ->\n          <<main::bits, unquote(decode_name)(c1)::6, bsr(unquote(decode_name)(c2), 4)::2>>\n\n        <<c1::8, c2::8, c3::8, ?=>> ->\n          <<main::bits, unquote(decode_name)(c1)::6, unquote(decode_name)(c2)::6,\n            bsr(unquote(decode_name)(c3), 2)::4>>\n\n        <<c1::8, c2::8, c3::8, c4::8>> ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::6,\n            unquote(decode_name)(c2)::6,\n            unquote(decode_name)(c3)::6,\n            unquote(decode_name)(c4)::6\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, ?=, ?=>> ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::6,\n            unquote(decode_name)(c2)::6,\n            unquote(decode_name)(c3)::6,\n            unquote(decode_name)(c4)::6,\n            unquote(decode_name)(c5)::6,\n            bsr(unquote(decode_name)(c6), 4)::2\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, ?=>> ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::6,\n            unquote(decode_name)(c2)::6,\n            unquote(decode_name)(c3)::6,\n            unquote(decode_name)(c4)::6,\n            unquote(decode_name)(c5)::6,\n            unquote(decode_name)(c6)::6,\n            bsr(unquote(decode_name)(c7), 2)::4\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8>> ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::6,\n            unquote(decode_name)(c2)::6,\n            unquote(decode_name)(c3)::6,\n            unquote(decode_name)(c4)::6,\n            unquote(decode_name)(c5)::6,\n            unquote(decode_name)(c6)::6,\n            unquote(decode_name)(c7)::6,\n            unquote(decode_name)(c8)::6\n          >>\n\n        <<c1::8, c2::8>> when not pad? ->\n          <<main::bits, unquote(decode_name)(c1)::6, bsr(unquote(decode_name)(c2), 4)::2>>\n\n        <<c1::8, c2::8, c3::8>> when not pad? ->\n          <<main::bits, unquote(decode_name)(c1)::6, unquote(decode_name)(c2)::6,\n            bsr(unquote(decode_name)(c3), 2)::4>>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8>> when not pad? ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::6,\n            unquote(decode_name)(c2)::6,\n            unquote(decode_name)(c3)::6,\n            unquote(decode_name)(c4)::6,\n            unquote(decode_name)(c5)::6,\n            bsr(unquote(decode_name)(c6), 4)::2\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8>> when not pad? ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::6,\n            unquote(decode_name)(c2)::6,\n            unquote(decode_name)(c3)::6,\n            unquote(decode_name)(c4)::6,\n            unquote(decode_name)(c5)::6,\n            unquote(decode_name)(c6)::6,\n            bsr(unquote(decode_name)(c7), 2)::4\n          >>\n\n        _ ->\n          raise ArgumentError, \"incorrect padding\"\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Encodes a binary string into a base 32 encoded string.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to use when encoding\n    * `:padding` - specifies whether to apply padding\n\n  The values for `:case` can be:\n\n    * `:upper` - uses upper case characters (default)\n    * `:lower` - uses lower case characters\n\n  The values for `:padding` can be:\n\n    * `true` - pad the output string to the nearest multiple of 8 (default)\n    * `false` - omit padding from the output string\n\n  ## Examples\n\n      iex> Base.encode32(\"foobar\")\n      \"MZXW6YTBOI======\"\n\n      iex> Base.encode32(\"foobar\", case: :lower)\n      \"mzxw6ytboi======\"\n\n      iex> Base.encode32(\"foobar\", padding: false)\n      \"MZXW6YTBOI\"\n\n  \"\"\"\n  @spec encode32(binary, case: encode_case, padding: boolean) :: binary\n  def encode32(data, opts \\\\ []) when is_binary(data) do\n    pad? = Keyword.get(opts, :padding, true)\n\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> encode32upper(data, \"\", pad?)\n      :lower -> encode32lower(data, \"\", pad?)\n    end\n  end\n\n  @doc \"\"\"\n  Encodes a binary string into a base 32 encoded string with an\n  extended hexadecimal alphabet.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to use when encoding\n    * `:padding` - specifies whether to apply padding\n\n  The values for `:case` can be:\n\n    * `:upper` - uses upper case characters (default)\n    * `:lower` - uses lower case characters\n\n  The values for `:padding` can be:\n\n    * `true` - pad the output string to the nearest multiple of 8 (default)\n    * `false` - omit padding from the output string\n\n  ## Examples\n\n      iex> Base.hex_encode32(\"foobar\")\n      \"CPNMUOJ1E8======\"\n\n      iex> Base.hex_encode32(\"foobar\", case: :lower)\n      \"cpnmuoj1e8======\"\n\n      iex> Base.hex_encode32(\"foobar\", padding: false)\n      \"CPNMUOJ1E8\"\n\n  \"\"\"\n  @spec hex_encode32(binary, case: encode_case, padding: boolean) :: binary\n  def hex_encode32(data, opts \\\\ []) when is_binary(data) do\n    pad? = Keyword.get(opts, :padding, true)\n\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> encode32hexupper(data, \"\", pad?)\n      :lower -> encode32hexlower(data, \"\", pad?)\n    end\n  end\n\n  for {base, alphabet} <- [\n        upper: b32_alphabet,\n        lower: to_lower_enc.(b32_alphabet),\n        hexupper: b32hex_alphabet,\n        hexlower: to_lower_enc.(b32hex_alphabet)\n      ] do\n    name = :\"encode32#{base}\"\n    encoded = to_encode_list.(alphabet)\n\n    @compile {:inline, [{name, 1}]}\n    defp unquote(name)(byte) do\n      elem({unquote_splicing(encoded)}, byte)\n    end\n\n    defp unquote(name)(<<c1::10, c2::10, c3::10, c4::10, rest::binary>>, acc, pad?) do\n      unquote(name)(\n        rest,\n        <<\n          acc::binary,\n          unquote(name)(c1)::16,\n          unquote(name)(c2)::16,\n          unquote(name)(c3)::16,\n          unquote(name)(c4)::16\n        >>,\n        pad?\n      )\n    end\n\n    defp unquote(name)(<<c1::10, c2::10, c3::10, c4::2>>, acc, pad?) do\n      <<\n        acc::binary,\n        unquote(name)(c1)::16,\n        unquote(name)(c2)::16,\n        unquote(name)(c3)::16,\n        c4 |> bsl(3) |> unquote(name)() |> band(0x00FF)::8\n      >>\n      |> maybe_pad(pad?, 1)\n    end\n\n    defp unquote(name)(<<c1::10, c2::10, c3::4>>, acc, pad?) do\n      <<\n        acc::binary,\n        unquote(name)(c1)::16,\n        unquote(name)(c2)::16,\n        c3 |> bsl(1) |> unquote(name)() |> band(0x00FF)::8\n      >>\n      |> maybe_pad(pad?, 3)\n    end\n\n    defp unquote(name)(<<c1::10, c2::6>>, acc, pad?) do\n      <<\n        acc::binary,\n        unquote(name)(c1)::16,\n        c2 |> bsl(4) |> unquote(name)()::16\n      >>\n      |> maybe_pad(pad?, 4)\n    end\n\n    defp unquote(name)(<<c1::8>>, acc, pad?) do\n      <<acc::binary, c1 |> bsl(2) |> unquote(name)()::16>>\n      |> maybe_pad(pad?, 6)\n    end\n\n    defp unquote(name)(<<>>, acc, _pad?) do\n      acc\n    end\n  end\n\n  @doc \"\"\"\n  Decodes a base 32 encoded string into a binary string.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to accept when decoding\n    * `:padding` - specifies whether to require padding\n\n  The values for `:case` can be:\n\n    * `:upper` - only allows  upper case characters (default)\n    * `:lower` - only allows lower case characters\n    * `:mixed` - allows mixed case characters\n\n  The values for `:padding` can be:\n\n    * `true` - requires the input string to be padded to the nearest multiple of 8 (default)\n    * `false` - ignores padding from the input string\n\n  ## Examples\n\n      iex> Base.decode32(\"MZXW6YTBOI======\")\n      {:ok, \"foobar\"}\n\n      iex> Base.decode32(\"mzxw6ytboi======\", case: :lower)\n      {:ok, \"foobar\"}\n\n      iex> Base.decode32(\"mzXW6ytBOi======\", case: :mixed)\n      {:ok, \"foobar\"}\n\n      iex> Base.decode32(\"MZXW6YTBOI\", padding: false)\n      {:ok, \"foobar\"}\n\n  \"\"\"\n  @spec decode32(binary, case: decode_case, padding: boolean) :: {:ok, binary} | :error\n  def decode32(string, opts \\\\ []) do\n    {:ok, decode32!(string, opts)}\n  rescue\n    ArgumentError -> :error\n  end\n\n  @doc \"\"\"\n  Decodes a base 32 encoded string into a binary string.\n\n  An `ArgumentError` exception is raised if the padding is incorrect or\n  a non-alphabet character is present in the string.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to accept when decoding\n    * `:padding` - specifies whether to require padding\n\n  The values for `:case` can be:\n\n    * `:upper` - only allows upper case characters (default)\n    * `:lower` - only allows lower case characters\n    * `:mixed` - allows mixed case characters\n\n  The values for `:padding` can be:\n\n    * `true` - requires the input string to be padded to the nearest multiple of 8 (default)\n    * `false` - ignores padding from the input string\n\n  ## Examples\n\n      iex> Base.decode32!(\"MZXW6YTBOI======\")\n      \"foobar\"\n\n      iex> Base.decode32!(\"mzxw6ytboi======\", case: :lower)\n      \"foobar\"\n\n      iex> Base.decode32!(\"mzXW6ytBOi======\", case: :mixed)\n      \"foobar\"\n\n      iex> Base.decode32!(\"MZXW6YTBOI\", padding: false)\n      \"foobar\"\n\n  \"\"\"\n  @spec decode32!(binary, case: decode_case, padding: boolean) :: binary\n  def decode32!(string, opts \\\\ []) when is_binary(string) do\n    pad? = Keyword.get(opts, :padding, true)\n\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> decode32upper!(string, pad?)\n      :lower -> decode32lower!(string, pad?)\n      :mixed -> decode32mixed!(string, pad?)\n    end\n  end\n\n  @doc \"\"\"\n  Checks if a base 32 encoded string is valid.\n\n  > #### When to use this {: .tip}\n  >\n  > Use this function when you just need to *validate* that a string is\n  > valid base 32 data, without actually producing a decoded output string.\n  > This function is both more performant and memory efficient than using\n  > `decode32/2`, checking that the result is `{:ok, ...}`, and then\n  > discarding the decoded binary.\n\n  ## Options\n\n  Accepts the same options as `decode32/2`.\n\n  ## Examples\n\n      iex> Base.valid32?(\"MZXW6YTBOI======\")\n      true\n\n      iex> Base.valid32?(\"mzxw6ytboi======\", case: :lower)\n      true\n\n      iex> Base.valid32?(\"zzz\")\n      false\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec valid32?(binary, case: decode_case, padding: boolean) :: boolean()\n  def valid32?(string, opts \\\\ []) when is_binary(string) do\n    pad? = Keyword.get(opts, :padding, true)\n\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> validate32upper?(string, pad?)\n      :lower -> validate32lower?(string, pad?)\n      :mixed -> validate32mixed?(string, pad?)\n    end\n  end\n\n  @doc \"\"\"\n  Decodes a base 32 encoded string with extended hexadecimal alphabet\n  into a binary string.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to accept when decoding\n    * `:padding` - specifies whether to require padding\n\n  The values for `:case` can be:\n\n    * `:upper` - only allows upper case characters (default)\n    * `:lower` - only allows lower case characters\n    * `:mixed` - allows mixed case characters\n\n  The values for `:padding` can be:\n\n    * `true` - requires the input string to be padded to the nearest multiple of 8 (default)\n    * `false` - ignores padding from the input string\n\n  ## Examples\n\n      iex> Base.hex_decode32(\"CPNMUOJ1E8======\")\n      {:ok, \"foobar\"}\n\n      iex> Base.hex_decode32(\"cpnmuoj1e8======\", case: :lower)\n      {:ok, \"foobar\"}\n\n      iex> Base.hex_decode32(\"cpnMuOJ1E8======\", case: :mixed)\n      {:ok, \"foobar\"}\n\n      iex> Base.hex_decode32(\"CPNMUOJ1E8\", padding: false)\n      {:ok, \"foobar\"}\n\n  \"\"\"\n  @spec hex_decode32(binary, case: decode_case, padding: boolean) :: {:ok, binary} | :error\n  def hex_decode32(string, opts \\\\ []) do\n    {:ok, hex_decode32!(string, opts)}\n  rescue\n    ArgumentError -> :error\n  end\n\n  @doc \"\"\"\n  Decodes a base 32 encoded string with extended hexadecimal alphabet\n  into a binary string.\n\n  An `ArgumentError` exception is raised if the padding is incorrect or\n  a non-alphabet character is present in the string.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:case` - specifies the character case to accept when decoding\n    * `:padding` - specifies whether to require padding\n\n  The values for `:case` can be:\n\n    * `:upper` - only allows upper case characters (default)\n    * `:lower` - only allows lower case characters\n    * `:mixed` - allows mixed case characters\n\n  The values for `:padding` can be:\n\n    * `true` - requires the input string to be padded to the nearest multiple of 8 (default)\n    * `false` - ignores padding from the input string\n\n  ## Examples\n\n      iex> Base.hex_decode32!(\"CPNMUOJ1E8======\")\n      \"foobar\"\n\n      iex> Base.hex_decode32!(\"cpnmuoj1e8======\", case: :lower)\n      \"foobar\"\n\n      iex> Base.hex_decode32!(\"cpnMuOJ1E8======\", case: :mixed)\n      \"foobar\"\n\n      iex> Base.hex_decode32!(\"CPNMUOJ1E8\", padding: false)\n      \"foobar\"\n\n  \"\"\"\n  @spec hex_decode32!(binary, case: decode_case, padding: boolean) :: binary\n  def hex_decode32!(string, opts \\\\ []) when is_binary(string) do\n    pad? = Keyword.get(opts, :padding, true)\n\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> decode32hexupper!(string, pad?)\n      :lower -> decode32hexlower!(string, pad?)\n      :mixed -> decode32hexmixed!(string, pad?)\n    end\n  end\n\n  @doc \"\"\"\n  Checks if a base 32 encoded string with extended hexadecimal alphabet is valid.\n\n  > #### When to use this {: .tip}\n  >\n  > Use this function when you just need to *validate* that a string is\n  > valid (extended hexadecimal) base 32 data, without actually producing\n  > a decoded output string. This function is both more performant and\n  > memory efficient than using `hex_decode32/2`, checking that the result\n  > is `{:ok, ...}`, and then discarding the decoded binary.\n\n  ## Options\n\n  Accepts the same options as `hex_decode32/2`.\n\n  ## Examples\n\n      iex> Base.hex_valid32?(\"CPNMUOJ1E8======\")\n      true\n\n      iex> Base.hex_valid32?(\"cpnmuoj1e8======\", case: :lower)\n      true\n\n      iex> Base.hex_valid32?(\"zzz\", padding: false)\n      false\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec hex_valid32?(binary, case: decode_case, padding: boolean) :: boolean\n  def hex_valid32?(string, opts \\\\ []) when is_binary(string) do\n    pad? = Keyword.get(opts, :padding, true)\n\n    case Keyword.get(opts, :case, :upper) do\n      :upper -> validate32hexupper?(string, pad?)\n      :lower -> validate32hexlower?(string, pad?)\n      :mixed -> validate32hexmixed?(string, pad?)\n    end\n  end\n\n  upper = Enum.with_index(b32_alphabet)\n  hexupper = Enum.with_index(b32hex_alphabet)\n\n  for {base, alphabet} <- [\n        upper: upper,\n        lower: to_lower_dec.(upper),\n        mixed: to_mixed_dec.(upper),\n        hexupper: hexupper,\n        hexlower: to_lower_dec.(hexupper),\n        hexmixed: to_mixed_dec.(hexupper)\n      ] do\n    decode_name = :\"decode32#{base}!\"\n    validate_name = :\"validate32#{base}?\"\n    validate_main_name = :\"validate_main32#{validate_name}?\"\n    valid_char_name = :\"valid_char32#{base}?\"\n    {min, decoded} = to_decode_list.(alphabet)\n\n    defp unquote(validate_main_name)(<<>>), do: true\n\n    defp unquote(validate_main_name)(\n           <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8, rest::binary>>\n         ) do\n      unquote(valid_char_name)(c1) and\n        unquote(valid_char_name)(c2) and\n        unquote(valid_char_name)(c3) and\n        unquote(valid_char_name)(c4) and\n        unquote(valid_char_name)(c5) and\n        unquote(valid_char_name)(c6) and\n        unquote(valid_char_name)(c7) and\n        unquote(valid_char_name)(c8) and\n        unquote(validate_main_name)(rest)\n    end\n\n    defp unquote(validate_name)(<<>>, _pad?), do: true\n\n    defp unquote(validate_name)(string, pad?) do\n      segs = div(byte_size(string) + 7, 8) - 1\n      <<main::size(^segs)-binary-unit(64), rest::binary>> = string\n      main_valid? = unquote(validate_main_name)(main)\n\n      case rest do\n        _ when not main_valid? ->\n          false\n\n        <<c1::8, c2::8, ?=, ?=, ?=, ?=, ?=, ?=>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2)\n\n        <<c1::8, c2::8, c3::8, c4::8, ?=, ?=, ?=, ?=>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, ?=, ?=, ?=>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, ?=>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5) and\n            unquote(valid_char_name)(c6) and\n            unquote(valid_char_name)(c7)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8>> ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5) and\n            unquote(valid_char_name)(c6) and\n            unquote(valid_char_name)(c7) and\n            unquote(valid_char_name)(c8)\n\n        <<c1::8, c2::8>> when not pad? ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2)\n\n        <<c1::8, c2::8, c3::8, c4::8>> when not pad? ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8>> when not pad? ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5)\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8>> when not pad? ->\n          unquote(valid_char_name)(c1) and\n            unquote(valid_char_name)(c2) and\n            unquote(valid_char_name)(c3) and\n            unquote(valid_char_name)(c4) and\n            unquote(valid_char_name)(c5) and\n            unquote(valid_char_name)(c6) and\n            unquote(valid_char_name)(c7)\n\n        _ ->\n          false\n      end\n    end\n\n    @compile {:inline, [{valid_char_name, 1}]}\n    defp unquote(valid_char_name)(char)\n         when elem({unquote_splicing(decoded)}, char - unquote(min)) != nil,\n         do: true\n\n    defp unquote(valid_char_name)(_char), do: false\n\n    defp unquote(decode_name)(char) do\n      index = char - unquote(min)\n\n      cond do\n        index not in 0..unquote(length(decoded) - 1) -> bad_character!(char)\n        new_char = elem({unquote_splicing(decoded)}, index) -> new_char\n        true -> bad_character!(char)\n      end\n    end\n\n    defp unquote(decode_name)(<<>>, _), do: <<>>\n\n    defp unquote(decode_name)(string, pad?) do\n      segs = div(byte_size(string) + 7, 8) - 1\n      <<main::size(^segs)-binary-unit(64), rest::binary>> = string\n\n      main =\n        for <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8 <- main>>, into: <<>> do\n          <<\n            unquote(decode_name)(c1)::5,\n            unquote(decode_name)(c2)::5,\n            unquote(decode_name)(c3)::5,\n            unquote(decode_name)(c4)::5,\n            unquote(decode_name)(c5)::5,\n            unquote(decode_name)(c6)::5,\n            unquote(decode_name)(c7)::5,\n            unquote(decode_name)(c8)::5\n          >>\n        end\n\n      case rest do\n        <<c1::8, c2::8, ?=, ?=, ?=, ?=, ?=, ?=>> ->\n          <<main::bits, unquote(decode_name)(c1)::5, bsr(unquote(decode_name)(c2), 2)::3>>\n\n        <<c1::8, c2::8, c3::8, c4::8, ?=, ?=, ?=, ?=>> ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::5,\n            unquote(decode_name)(c2)::5,\n            unquote(decode_name)(c3)::5,\n            bsr(unquote(decode_name)(c4), 4)::1\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, ?=, ?=, ?=>> ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::5,\n            unquote(decode_name)(c2)::5,\n            unquote(decode_name)(c3)::5,\n            unquote(decode_name)(c4)::5,\n            bsr(unquote(decode_name)(c5), 1)::4\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, ?=>> ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::5,\n            unquote(decode_name)(c2)::5,\n            unquote(decode_name)(c3)::5,\n            unquote(decode_name)(c4)::5,\n            unquote(decode_name)(c5)::5,\n            unquote(decode_name)(c6)::5,\n            bsr(unquote(decode_name)(c7), 3)::2\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8>> ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::5,\n            unquote(decode_name)(c2)::5,\n            unquote(decode_name)(c3)::5,\n            unquote(decode_name)(c4)::5,\n            unquote(decode_name)(c5)::5,\n            unquote(decode_name)(c6)::5,\n            unquote(decode_name)(c7)::5,\n            unquote(decode_name)(c8)::5\n          >>\n\n        <<c1::8, c2::8>> when not pad? ->\n          <<main::bits, unquote(decode_name)(c1)::5, bsr(unquote(decode_name)(c2), 2)::3>>\n\n        <<c1::8, c2::8, c3::8, c4::8>> when not pad? ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::5,\n            unquote(decode_name)(c2)::5,\n            unquote(decode_name)(c3)::5,\n            bsr(unquote(decode_name)(c4), 4)::1\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8>> when not pad? ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::5,\n            unquote(decode_name)(c2)::5,\n            unquote(decode_name)(c3)::5,\n            unquote(decode_name)(c4)::5,\n            bsr(unquote(decode_name)(c5), 1)::4\n          >>\n\n        <<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8>> when not pad? ->\n          <<\n            main::bits,\n            unquote(decode_name)(c1)::5,\n            unquote(decode_name)(c2)::5,\n            unquote(decode_name)(c3)::5,\n            unquote(decode_name)(c4)::5,\n            unquote(decode_name)(c5)::5,\n            unquote(decode_name)(c6)::5,\n            bsr(unquote(decode_name)(c7), 3)::2\n          >>\n\n        _ ->\n          raise ArgumentError, \"incorrect padding\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/behaviour.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Behaviour do\n  @moduledoc \"\"\"\n  Mechanism for handling behaviours.\n\n  This module is deprecated. Instead of `defcallback/1` and\n  `defmacrocallback/1`, the `@callback` and `@macrocallback`\n  module attributes can be used respectively. See the\n  documentation for `Module` for more information on these\n  attributes.\n\n  Instead of `MyModule.__behaviour__(:callbacks)`,\n  `MyModule.behaviour_info(:callbacks)` can be used. `behaviour_info/1`\n  is documented in `Module`.\n  \"\"\"\n\n  @moduledoc deprecated: \"Use @callback and @macrocallback attributes instead\"\n\n  @doc \"\"\"\n  Defines a function callback according to the given type specification.\n  \"\"\"\n  @deprecated \"Use the @callback module attribute instead\"\n  defmacro defcallback(spec) do\n    do_defcallback(:def, split_spec(spec, quote(do: term)))\n  end\n\n  @doc \"\"\"\n  Defines a macro callback according to the given type specification.\n  \"\"\"\n  @deprecated \"Use the @macrocallback module attribute instead\"\n  defmacro defmacrocallback(spec) do\n    do_defcallback(:defmacro, split_spec(spec, quote(do: Macro.t())))\n  end\n\n  defp split_spec({:when, _, [{:\"::\", _, [spec, return]}, guard]}, _default) do\n    {spec, return, guard}\n  end\n\n  defp split_spec({:when, _, [spec, guard]}, default) do\n    {spec, default, guard}\n  end\n\n  defp split_spec({:\"::\", _, [spec, return]}, _default) do\n    {spec, return, []}\n  end\n\n  defp split_spec(spec, default) do\n    {spec, default, []}\n  end\n\n  defp do_defcallback(kind, {spec, return, guards}) do\n    case Macro.decompose_call(spec) do\n      {name, args} ->\n        do_callback(kind, name, args, return, guards)\n\n      _ ->\n        raise ArgumentError, \"invalid syntax in #{kind}callback #{Macro.to_string(spec)}\"\n    end\n  end\n\n  defp do_callback(kind, name, args, return, guards) do\n    fun = fn\n      {:\"::\", _, [left, right]} ->\n        ensure_not_default(left)\n        ensure_not_default(right)\n        left\n\n      other ->\n        ensure_not_default(other)\n        other\n    end\n\n    :lists.foreach(fun, args)\n\n    spec =\n      quote do\n        unquote(name)(unquote_splicing(args)) :: unquote(return) when unquote(guards)\n      end\n\n    case kind do\n      :def -> quote(do: @callback(unquote(spec)))\n      :defmacro -> quote(do: @macrocallback(unquote(spec)))\n    end\n  end\n\n  defp ensure_not_default({:\\\\, _, [_, _]}) do\n    raise ArgumentError, \"default arguments \\\\\\\\ not supported in defcallback/defmacrocallback\"\n  end\n\n  defp ensure_not_default(_), do: :ok\n\n  @doc false\n  defmacro __using__(_) do\n    quote do\n      warning =\n        \"the Behaviour module is deprecated. Instead of using this module, \" <>\n          \"use the @callback and @macrocallback module attributes. See the \" <>\n          \"documentation for Module for more information on these attributes\"\n\n      IO.warn(warning)\n\n      @doc false\n      def __behaviour__(:callbacks) do\n        __MODULE__.behaviour_info(:callbacks)\n      end\n\n      def __behaviour__(:docs) do\n        {:docs_v1, _, :elixir, _, _, _, docs} = Code.fetch_docs(__MODULE__)\n\n        for {{kind, name, arity}, line, _, doc, _} <- docs, kind in [:callback, :macrocallback] do\n          case kind do\n            :callback -> {{name, arity}, line, :def, __behaviour__doc_value(doc)}\n            :macrocallback -> {{name, arity}, line, :defmacro, __behaviour__doc_value(doc)}\n          end\n        end\n      end\n\n      defp __behaviour__doc_value(%{\"en\" => doc}), do: doc\n      defp __behaviour__doc_value(:hidden), do: false\n      defp __behaviour__doc_value(_), do: nil\n\n      import unquote(__MODULE__)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/bitwise.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Bitwise do\n  @moduledoc \"\"\"\n  A set of functions that perform calculations on bits.\n\n  All bitwise functions work only on integers, otherwise an\n  `ArithmeticError` is raised. The functions `band/2`,\n  `bor/2`, `bsl/2`, and `bsr/2` also have operators,\n  respectively: `&&&/2`, `|||/2`, `<<</2`, and `>>>/2`.\n\n  ## Guards\n\n  All bitwise functions can be used in guards:\n\n      iex> odd? = fn\n      ...>   int when Bitwise.band(int, 1) == 1 -> true\n      ...>   _ -> false\n      ...> end\n      iex> odd?.(1)\n      true\n\n  All functions in this module are inlined by the compiler.\n  \"\"\"\n\n  @doc false\n  @deprecated \"import Bitwise instead\"\n  defmacro __using__(options) do\n    except =\n      cond do\n        Keyword.get(options, :only_operators) ->\n          [bnot: 1, band: 2, bor: 2, bxor: 2, bsl: 2, bsr: 2]\n\n        Keyword.get(options, :skip_operators) ->\n          [\"~~~\": 1, &&&: 2, |||: 2, \"^^^\": 2, <<<: 2, >>>: 2]\n\n        true ->\n          []\n      end\n\n    quote do\n      import Bitwise, except: unquote(except)\n    end\n  end\n\n  @doc \"\"\"\n  Calculates the bitwise NOT of the argument.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> bnot(2)\n      -3\n\n      iex> bnot(2) &&& 3\n      1\n\n  \"\"\"\n  @doc guard: true\n  @spec bnot(integer) :: integer\n  def bnot(expr) do\n    :erlang.bnot(expr)\n  end\n\n  @doc false\n  def unquote(:\"~~~\")(expr) do\n    :erlang.bnot(expr)\n  end\n\n  @doc \"\"\"\n  Calculates the bitwise AND of its arguments.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> band(9, 3)\n      1\n\n  \"\"\"\n  @doc guard: true\n  @spec band(integer, integer) :: integer\n  def band(left, right) do\n    :erlang.band(left, right)\n  end\n\n  @doc \"\"\"\n  Bitwise AND operator.\n\n  Calculates the bitwise AND of its arguments.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 9 &&& 3\n      1\n\n  \"\"\"\n  @doc guard: true\n  @spec integer &&& integer :: integer\n  def left &&& right do\n    :erlang.band(left, right)\n  end\n\n  @doc \"\"\"\n  Calculates the bitwise OR of its arguments.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> bor(9, 3)\n      11\n\n  \"\"\"\n  @doc guard: true\n  @spec bor(integer, integer) :: integer\n  def bor(left, right) do\n    :erlang.bor(left, right)\n  end\n\n  @doc \"\"\"\n  Bitwise OR operator.\n\n  Calculates the bitwise OR of its arguments.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 9 ||| 3\n      11\n\n  \"\"\"\n  @doc guard: true\n  @spec integer ||| integer :: integer\n  def left ||| right do\n    :erlang.bor(left, right)\n  end\n\n  @doc \"\"\"\n  Calculates the bitwise XOR of its arguments.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> bxor(9, 3)\n      10\n\n  \"\"\"\n  @doc guard: true\n  @spec bxor(integer, integer) :: integer\n  def bxor(left, right) do\n    :erlang.bxor(left, right)\n  end\n\n  @doc false\n  def unquote(:\"^^^\")(left, right) do\n    :erlang.bxor(left, right)\n  end\n\n  @doc \"\"\"\n  Calculates the result of an arithmetic left bitshift.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> bsl(1, 2)\n      4\n\n      iex> bsl(1, -2)\n      0\n\n      iex> bsl(-1, 2)\n      -4\n\n      iex> bsl(-1, -2)\n      -1\n\n  \"\"\"\n  @doc guard: true\n  @spec bsl(integer, integer) :: integer\n  def bsl(left, right) do\n    :erlang.bsl(left, right)\n  end\n\n  @doc \"\"\"\n  Arithmetic left bitshift operator.\n\n  Calculates the result of an arithmetic left bitshift.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 <<< 2\n      4\n\n      iex> 1 <<< -2\n      0\n\n      iex> -1 <<< 2\n      -4\n\n      iex> -1 <<< -2\n      -1\n\n  \"\"\"\n  @doc guard: true\n  @spec integer <<< integer :: integer\n  def left <<< right do\n    :erlang.bsl(left, right)\n  end\n\n  @doc \"\"\"\n  Calculates the result of an arithmetic right bitshift.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> bsr(1, 2)\n      0\n\n      iex> bsr(1, -2)\n      4\n\n      iex> bsr(-1, 2)\n      -1\n\n      iex> bsr(-1, -2)\n      -4\n\n  \"\"\"\n  @doc guard: true\n  @spec bsr(integer, integer) :: integer\n  def bsr(left, right) do\n    :erlang.bsr(left, right)\n  end\n\n  @doc \"\"\"\n  Arithmetic right bitshift operator.\n\n  Calculates the result of an arithmetic right bitshift.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 >>> 2\n      0\n\n      iex> 1 >>> -2\n      4\n\n      iex> -1 >>> 2\n      -1\n\n      iex> -1 >>> -2\n      -4\n\n  \"\"\"\n  @doc guard: true\n  @spec integer >>> integer :: integer\n  def left >>> right do\n    :erlang.bsr(left, right)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar/date.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Date do\n  @moduledoc \"\"\"\n  A Date struct and functions.\n\n  The Date struct contains the fields year, month, day and calendar.\n  New dates can be built with the `new/3` function or using the\n  `~D` (see `sigil_D/2`) sigil:\n\n      iex> ~D[2000-01-01]\n      ~D[2000-01-01]\n\n  Both `new/3` and sigil return a struct where the date fields can\n  be accessed directly:\n\n      iex> date = ~D[2000-01-01]\n      iex> date.year\n      2000\n      iex> date.month\n      1\n\n  The functions on this module work with the `Date` struct as well\n  as any struct that contains the same fields as the `Date` struct,\n  such as `NaiveDateTime` and `DateTime`. Such functions expect\n  `t:Calendar.date/0` in their typespecs (instead of `t:t/0`).\n\n  Developers should avoid creating the Date structs directly\n  and instead rely on the functions provided by this module as well\n  as the ones in third-party calendar libraries.\n\n  ## Comparing dates\n\n  Comparisons in Elixir using `==/2`, `>/2`, `</2` and similar are structural\n  and based on the `Date` struct fields. For proper comparison between\n  dates, use the `compare/2`, `after?/2` and `before?/2` functions.\n  The existence of the `compare/2` function in this module also allows\n  using `Enum.min/2` and `Enum.max/2` functions to get the minimum and\n  maximum date of an `Enum`. For example:\n\n      iex> Enum.min([~D[2017-03-31], ~D[2017-04-01]], Date)\n      ~D[2017-03-31]\n\n  ## Using epochs\n\n  The `add/2`, `diff/2` and `shift/2` functions can be used for computing dates\n  or retrieving the number of days between instants. For example, if there\n  is an interest in computing the number of days from the Unix epoch\n  (1970-01-01):\n\n      iex> Date.diff(~D[2010-04-17], ~D[1970-01-01])\n      14716\n\n      iex> Date.add(~D[1970-01-01], 14_716)\n      ~D[2010-04-17]\n\n      iex> Date.shift(~D[1970-01-01], year: 40, month: 3, week: 2, day: 2)\n      ~D[2010-04-17]\n\n  Those functions are optimized to deal with common epochs, such\n  as the Unix Epoch above or the Gregorian Epoch (0000-01-01).\n  \"\"\"\n\n  @enforce_keys [:year, :month, :day]\n  defstruct [:year, :month, :day, calendar: Calendar.ISO]\n\n  @type t :: %__MODULE__{\n          year: Calendar.year(),\n          month: Calendar.month(),\n          day: Calendar.day(),\n          calendar: Calendar.calendar()\n        }\n\n  @doc \"\"\"\n  Returns a range of dates.\n\n  A range of dates represents a discrete number of dates where\n  the first and last values are dates with matching calendars.\n\n  Ranges of dates can be increasing (`first <= last`) and are\n  always inclusive. For a decreasing range, use `range/3` with\n  a step of -1 as first argument.\n\n  ## Examples\n\n      iex> Date.range(~D[1999-01-01], ~D[2000-01-01])\n      Date.range(~D[1999-01-01], ~D[2000-01-01])\n\n  A range of dates implements the `Enumerable` protocol, which means\n  functions in the `Enum` module can be used to work with\n  ranges:\n\n      iex> range = Date.range(~D[2001-01-01], ~D[2002-01-01])\n      iex> range\n      Date.range(~D[2001-01-01], ~D[2002-01-01])\n      iex> Enum.count(range)\n      366\n      iex> ~D[2001-02-01] in range\n      true\n      iex> Enum.take(range, 3)\n      [~D[2001-01-01], ~D[2001-01-02], ~D[2001-01-03]]\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec range(Calendar.date(), Calendar.date()) :: Date.Range.t()\n  def range(%{calendar: calendar} = first, %{calendar: calendar} = last) do\n    {first_days, _} = to_iso_days(first)\n    {last_days, _} = to_iso_days(last)\n\n    step =\n      if first_days <= last_days do\n        1\n      else\n        IO.warn(\n          \"a negative range was inferred for Date.range/2, call Date.range/3 instead with -1 as third argument\"\n        )\n\n        -1\n      end\n\n    range(first, first_days, last, last_days, calendar, step)\n  end\n\n  def range(%{calendar: _, year: _, month: _, day: _}, %{calendar: _, year: _, month: _, day: _}) do\n    raise ArgumentError, \"both dates must have matching calendars\"\n  end\n\n  @doc \"\"\"\n  Returns a range of dates with a step.\n\n  ## Examples\n\n      iex> range = Date.range(~D[2001-01-01], ~D[2002-01-01], 2)\n      iex> range\n      Date.range(~D[2001-01-01], ~D[2002-01-01], 2)\n      iex> Enum.count(range)\n      183\n      iex> ~D[2001-01-03] in range\n      true\n      iex> Enum.take(range, 3)\n      [~D[2001-01-01], ~D[2001-01-03], ~D[2001-01-05]]\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec range(Calendar.date(), Calendar.date(), step :: pos_integer | neg_integer) ::\n          Date.Range.t()\n  def range(%{calendar: calendar} = first, %{calendar: calendar} = last, step)\n      when is_integer(step) and step != 0 do\n    {first_days, _} = to_iso_days(first)\n    {last_days, _} = to_iso_days(last)\n    range(first, first_days, last, last_days, calendar, step)\n  end\n\n  def range(\n        %{calendar: _, year: _, month: _, day: _} = first,\n        %{calendar: _, year: _, month: _, day: _} = last,\n        step\n      ) do\n    raise ArgumentError,\n          \"both dates must have matching calendar and the step must be a \" <>\n            \"non-zero integer, got: #{inspect(first)}, #{inspect(last)}, #{step}\"\n  end\n\n  defp range(first, first_days, last, last_days, calendar, step) do\n    %Date.Range{\n      first: %Date{calendar: calendar, year: first.year, month: first.month, day: first.day},\n      last: %Date{calendar: calendar, year: last.year, month: last.month, day: last.day},\n      first_in_iso_days: first_days,\n      last_in_iso_days: last_days,\n      step: step\n    }\n  end\n\n  @doc \"\"\"\n  Returns the current date in UTC.\n\n  ## Examples\n\n      iex> date = Date.utc_today()\n      iex> date.year >= 2016\n      true\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec utc_today(Calendar.calendar()) :: t\n  def utc_today(calendar \\\\ Calendar.ISO)\n\n  def utc_today(Calendar.ISO) do\n    {:ok, {year, month, day}, _, _} = Calendar.ISO.from_unix(System.os_time(), :native)\n    %Date{year: year, month: month, day: day}\n  end\n\n  def utc_today(calendar) do\n    %{year: year, month: month, day: day} = DateTime.utc_now(calendar)\n    %Date{year: year, month: month, day: day, calendar: calendar}\n  end\n\n  @doc \"\"\"\n  Returns `true` if the year in the given `date` is a leap year.\n\n  ## Examples\n\n      iex> Date.leap_year?(~D[2000-01-01])\n      true\n      iex> Date.leap_year?(~D[2001-01-01])\n      false\n      iex> Date.leap_year?(~D[2004-01-01])\n      true\n      iex> Date.leap_year?(~D[1900-01-01])\n      false\n      iex> Date.leap_year?(~N[2004-01-01 01:23:45])\n      true\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec leap_year?(Calendar.date()) :: boolean()\n  def leap_year?(date)\n\n  def leap_year?(%{calendar: calendar, year: year}) do\n    calendar.leap_year?(year)\n  end\n\n  @doc \"\"\"\n  Returns the number of days in the given `date` month.\n\n  ## Examples\n\n      iex> Date.days_in_month(~D[1900-01-13])\n      31\n      iex> Date.days_in_month(~D[1900-02-09])\n      28\n      iex> Date.days_in_month(~N[2000-02-20 01:23:45])\n      29\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec days_in_month(Calendar.date()) :: Calendar.day()\n  def days_in_month(date)\n\n  def days_in_month(%{calendar: calendar, year: year, month: month}) do\n    calendar.days_in_month(year, month)\n  end\n\n  @doc \"\"\"\n  Returns the number of months in the given `date` year.\n\n  ## Example\n\n      iex> Date.months_in_year(~D[1900-01-13])\n      12\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec months_in_year(Calendar.date()) :: Calendar.month()\n  def months_in_year(date)\n\n  def months_in_year(%{calendar: calendar, year: year}) do\n    calendar.months_in_year(year)\n  end\n\n  @doc \"\"\"\n  Builds a new ISO date.\n\n  Expects all values to be integers. Returns `{:ok, date}` if each\n  entry fits its appropriate range, returns `{:error, reason}` otherwise.\n\n  ## Examples\n\n      iex> Date.new(2000, 1, 1)\n      {:ok, ~D[2000-01-01]}\n      iex> Date.new(2000, 13, 1)\n      {:error, :invalid_date}\n      iex> Date.new(2000, 2, 29)\n      {:ok, ~D[2000-02-29]}\n\n      iex> Date.new(2000, 2, 30)\n      {:error, :invalid_date}\n      iex> Date.new(2001, 2, 29)\n      {:error, :invalid_date}\n\n  \"\"\"\n  @spec new(Calendar.year(), Calendar.month(), Calendar.day(), Calendar.calendar()) ::\n          {:ok, t} | {:error, atom}\n  def new(year, month, day, calendar \\\\ Calendar.ISO) do\n    if calendar.valid_date?(year, month, day) do\n      {:ok, %Date{year: year, month: month, day: day, calendar: calendar}}\n    else\n      {:error, :invalid_date}\n    end\n  end\n\n  @doc \"\"\"\n  Builds a new ISO date.\n\n  Expects all values to be integers. Returns `date` if each\n  entry fits its appropriate range, raises if the date is invalid.\n\n  ## Examples\n\n      iex> Date.new!(2000, 1, 1)\n      ~D[2000-01-01]\n      iex> Date.new!(2000, 13, 1)\n      ** (ArgumentError) cannot build date, reason: :invalid_date\n      iex> Date.new!(2000, 2, 29)\n      ~D[2000-02-29]\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec new!(Calendar.year(), Calendar.month(), Calendar.day(), Calendar.calendar()) :: t\n  def new!(year, month, day, calendar \\\\ Calendar.ISO) do\n    case new(year, month, day, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise ArgumentError, \"cannot build date, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given date to a string according to its calendar.\n\n  ## Examples\n\n      iex> Date.to_string(~D[2000-02-28])\n      \"2000-02-28\"\n      iex> Date.to_string(~N[2000-02-28 01:23:45])\n      \"2000-02-28\"\n      iex> Date.to_string(~D[-0100-12-15])\n      \"-0100-12-15\"\n\n  \"\"\"\n  @spec to_string(Calendar.date()) :: String.t()\n  def to_string(date)\n\n  def to_string(%{calendar: calendar, year: year, month: month, day: day}) do\n    calendar.date_to_string(year, month, day)\n  end\n\n  @doc \"\"\"\n  Parses the extended \"Dates\" format described by\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  The year parsed by this function is limited to four digits.\n\n  ## Examples\n\n      iex> Date.from_iso8601(\"2015-01-23\")\n      {:ok, ~D[2015-01-23]}\n\n      iex> Date.from_iso8601(\"2015:01:23\")\n      {:error, :invalid_format}\n\n      iex> Date.from_iso8601(\"2015-01-32\")\n      {:error, :invalid_date}\n\n  \"\"\"\n  @spec from_iso8601(String.t(), Calendar.calendar()) :: {:ok, t} | {:error, atom}\n  def from_iso8601(string, calendar \\\\ Calendar.ISO) do\n    with {:ok, {year, month, day}} <- Calendar.ISO.parse_date(string) do\n      convert(%Date{year: year, month: month, day: day}, calendar)\n    end\n  end\n\n  @doc \"\"\"\n  Parses the extended \"Dates\" format described by\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  Raises if the format is invalid.\n\n  ## Examples\n\n      iex> Date.from_iso8601!(\"2015-01-23\")\n      ~D[2015-01-23]\n      iex> Date.from_iso8601!(\"2015:01:23\")\n      ** (ArgumentError) cannot parse \"2015:01:23\" as date, reason: :invalid_format\n\n  \"\"\"\n  @spec from_iso8601!(String.t(), Calendar.calendar()) :: t\n  def from_iso8601!(string, calendar \\\\ Calendar.ISO) do\n    case from_iso8601(string, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise ArgumentError, \"cannot parse #{inspect(string)} as date, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given `date` to\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  By default, `Date.to_iso8601/2` returns dates formatted in the \"extended\"\n  format, for human readability. It also supports the \"basic\" format through passing the `:basic` option.\n\n  Only supports converting dates which are in the ISO calendar,\n  or other calendars in which the days also start at midnight.\n  Attempting to convert dates from other calendars will raise an `ArgumentError`.\n\n  ## Examples\n\n      iex> Date.to_iso8601(~D[2000-02-28])\n      \"2000-02-28\"\n\n      iex> Date.to_iso8601(~D[2000-02-28], :basic)\n      \"20000228\"\n\n      iex> Date.to_iso8601(~N[2000-02-28 00:00:00])\n      \"2000-02-28\"\n\n  \"\"\"\n  @spec to_iso8601(Calendar.date(), :extended | :basic) :: String.t()\n  def to_iso8601(date, format \\\\ :extended)\n\n  def to_iso8601(%{calendar: Calendar.ISO} = date, format) when format in [:basic, :extended] do\n    %{year: year, month: month, day: day} = date\n    Calendar.ISO.date_to_string(year, month, day, format)\n  end\n\n  def to_iso8601(%{calendar: _} = date, format) when format in [:basic, :extended] do\n    date\n    |> convert!(Calendar.ISO)\n    |> to_iso8601()\n  end\n\n  @doc \"\"\"\n  Converts the given `date` to an Erlang date tuple.\n\n  Only supports converting dates which are in the ISO calendar,\n  or other calendars in which the days also start at midnight.\n  Attempting to convert dates from other calendars will raise.\n\n  ## Examples\n\n      iex> Date.to_erl(~D[2000-01-01])\n      {2000, 1, 1}\n\n      iex> Date.to_erl(~N[2000-01-01 00:00:00])\n      {2000, 1, 1}\n\n  \"\"\"\n  @spec to_erl(Calendar.date()) :: :calendar.date()\n  def to_erl(date) do\n    %{year: year, month: month, day: day} = convert!(date, Calendar.ISO)\n    {year, month, day}\n  end\n\n  @doc \"\"\"\n  Converts an Erlang date tuple to a `Date` struct.\n\n  Only supports converting dates which are in the ISO calendar,\n  or other calendars in which the days also start at midnight.\n  Attempting to convert dates from other calendars will return an error tuple.\n\n  ## Examples\n\n      iex> Date.from_erl({2000, 1, 1})\n      {:ok, ~D[2000-01-01]}\n      iex> Date.from_erl({2000, 13, 1})\n      {:error, :invalid_date}\n\n  \"\"\"\n  @spec from_erl(:calendar.date(), Calendar.calendar()) :: {:ok, t} | {:error, atom}\n  def from_erl(tuple, calendar \\\\ Calendar.ISO)\n\n  def from_erl({year, month, day}, calendar) do\n    with {:ok, date} <- new(year, month, day, Calendar.ISO), do: convert(date, calendar)\n  end\n\n  @doc \"\"\"\n  Converts an Erlang date tuple but raises for invalid dates.\n\n  ## Examples\n\n      iex> Date.from_erl!({2000, 1, 1})\n      ~D[2000-01-01]\n      iex> Date.from_erl!({2000, 13, 1})\n      ** (ArgumentError) cannot convert {2000, 13, 1} to date, reason: :invalid_date\n\n  \"\"\"\n  @spec from_erl!(:calendar.date(), Calendar.calendar()) :: t\n  def from_erl!(tuple, calendar \\\\ Calendar.ISO) do\n    case from_erl(tuple, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(tuple)} to date, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts a number of gregorian days to a `Date` struct.\n\n  ## Examples\n\n      iex> Date.from_gregorian_days(1)\n      ~D[0000-01-02]\n      iex> Date.from_gregorian_days(730_485)\n      ~D[2000-01-01]\n      iex> Date.from_gregorian_days(-1)\n      ~D[-0001-12-31]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec from_gregorian_days(integer(), Calendar.calendar()) :: t\n  def from_gregorian_days(days, calendar \\\\ Calendar.ISO) when is_integer(days) do\n    from_iso_days({days, 0}, calendar)\n  end\n\n  @doc \"\"\"\n  Converts a `date` struct to a number of gregorian days.\n\n  ## Examples\n\n      iex> Date.to_gregorian_days(~D[0000-01-02])\n      1\n      iex> Date.to_gregorian_days(~D[2000-01-01])\n      730_485\n      iex> Date.to_gregorian_days(~N[2000-01-01 00:00:00])\n      730_485\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec to_gregorian_days(Calendar.date()) :: integer()\n  def to_gregorian_days(date) do\n    {days, _} = to_iso_days(date)\n    days\n  end\n\n  @doc \"\"\"\n  Compares two date structs.\n\n  Returns `:gt` if first date is later than the second\n  and `:lt` for vice versa. If the two dates are equal\n  `:eq` is returned.\n\n  ## Examples\n\n      iex> Date.compare(~D[2016-04-16], ~D[2016-04-28])\n      :lt\n\n  This function can also be used to compare across more\n  complex calendar types by considering only the date fields:\n\n      iex> Date.compare(~D[2016-04-16], ~N[2016-04-28 01:23:45])\n      :lt\n      iex> Date.compare(~D[2016-04-16], ~N[2016-04-16 01:23:45])\n      :eq\n      iex> Date.compare(~N[2016-04-16 12:34:56], ~N[2016-04-16 01:23:45])\n      :eq\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec compare(Calendar.date(), Calendar.date()) :: :lt | :eq | :gt\n  def compare(%{calendar: calendar} = date1, %{calendar: calendar} = date2) do\n    %{year: year1, month: month1, day: day1} = date1\n    %{year: year2, month: month2, day: day2} = date2\n\n    case {{year1, month1, day1}, {year2, month2, day2}} do\n      {first, second} when first > second -> :gt\n      {first, second} when first < second -> :lt\n      _ -> :eq\n    end\n  end\n\n  def compare(%{calendar: calendar1} = date1, %{calendar: calendar2} = date2) do\n    if Calendar.compatible_calendars?(calendar1, calendar2) do\n      case {to_iso_days(date1), to_iso_days(date2)} do\n        {first, second} when first > second -> :gt\n        {first, second} when first < second -> :lt\n        _ -> :eq\n      end\n    else\n      raise ArgumentError, \"\"\"\n      cannot compare #{inspect(date1)} with #{inspect(date2)}.\n\n      This comparison would be ambiguous as their calendars have incompatible day rollover moments.\n      Specify an exact time of day (using DateTime) to resolve this ambiguity\n      \"\"\"\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if the first date is strictly earlier than the second.\n\n  ## Examples\n\n      iex> Date.before?(~D[2021-01-01], ~D[2022-02-02])\n      true\n      iex> Date.before?(~D[2021-01-01], ~D[2021-01-01])\n      false\n      iex> Date.before?(~D[2022-02-02], ~D[2021-01-01])\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec before?(Calendar.date(), Calendar.date()) :: boolean()\n  def before?(date1, date2) do\n    compare(date1, date2) == :lt\n  end\n\n  @doc \"\"\"\n  Returns `true` if the first date is strictly later than the second.\n\n  ## Examples\n\n      iex> Date.after?(~D[2022-02-02], ~D[2021-01-01])\n      true\n      iex> Date.after?(~D[2021-01-01], ~D[2021-01-01])\n      false\n      iex> Date.after?(~D[2021-01-01], ~D[2022-02-02])\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec after?(Calendar.date(), Calendar.date()) :: boolean()\n  def after?(date1, date2) do\n    compare(date1, date2) == :gt\n  end\n\n  @doc \"\"\"\n  Converts the given `date` from its calendar to the given `calendar`.\n\n  Returns `{:ok, date}` if the calendars are compatible,\n  or `{:error, :incompatible_calendars}` if they are not.\n\n  See also `Calendar.compatible_calendars?/2`.\n\n  ## Examples\n\n  Imagine someone implements `Calendar.Holocene`, a calendar based on the\n  Gregorian calendar that adds exactly 10 000 years to the current Gregorian\n  year:\n\n      iex> Date.convert(~D[2000-01-01], Calendar.Holocene)\n      {:ok, %Date{calendar: Calendar.Holocene, year: 12000, month: 1, day: 1}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec convert(Calendar.date(), Calendar.calendar()) ::\n          {:ok, t} | {:error, :incompatible_calendars}\n  def convert(%{calendar: calendar, year: year, month: month, day: day}, calendar) do\n    {:ok, %Date{calendar: calendar, year: year, month: month, day: day}}\n  end\n\n  def convert(%{calendar: calendar} = date, target_calendar) do\n    if Calendar.compatible_calendars?(calendar, target_calendar) do\n      result_date =\n        date\n        |> to_iso_days()\n        |> from_iso_days(target_calendar)\n\n      {:ok, result_date}\n    else\n      {:error, :incompatible_calendars}\n    end\n  end\n\n  @doc \"\"\"\n  Similar to `Date.convert/2`, but raises an `ArgumentError`\n  if the conversion between the two calendars is not possible.\n\n  ## Examples\n\n  Imagine someone implements `Calendar.Holocene`, a calendar based on the\n  Gregorian calendar that adds exactly 10 000 years to the current Gregorian\n  year:\n\n      iex> Date.convert!(~D[2000-01-01], Calendar.Holocene)\n      %Date{calendar: Calendar.Holocene, year: 12000, month: 1, day: 1}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec convert!(Calendar.date(), Calendar.calendar()) :: t\n  def convert!(date, calendar) do\n    case convert(date, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(date)} to target calendar #{inspect(calendar)}, \" <>\n                \"reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Adds the number of days to the given `date`.\n\n  > #### Prefer `shift/2` {: .info}\n  >\n  > Prefer `shift/2` over `add/2`, as it offers a more ergonomic API.\n  >\n  > `add/2` always considers a day to be measured according to the\n  > `Calendar.ISO`.\n\n  The days are counted as Gregorian days, independent of the underlying\n  calendar. The date is returned in the same calendar as it was given in.\n\n  ## Examples\n\n      iex> Date.add(~D[2000-01-03], -2)\n      ~D[2000-01-01]\n      iex> Date.add(~D[2000-01-01], 2)\n      ~D[2000-01-03]\n      iex> Date.add(~N[2000-01-01 09:00:00], 2)\n      ~D[2000-01-03]\n      iex> Date.add(~D[-0010-01-01], -2)\n      ~D[-0011-12-30]\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec add(Calendar.date(), integer()) :: t\n  def add(%{calendar: Calendar.ISO} = date, days) do\n    %{year: year, month: month, day: day} = date\n    {year, month, day} = Calendar.ISO.shift_days({year, month, day}, days)\n    %Date{calendar: Calendar.ISO, year: year, month: month, day: day}\n  end\n\n  def add(%{calendar: calendar} = date, days) do\n    {base_days, fraction} = to_iso_days(date)\n    from_iso_days({base_days + days, fraction}, calendar)\n  end\n\n  @doc \"\"\"\n  Calculates the difference between two dates, in a full number of days.\n\n  It returns the number of Gregorian days between the dates. Only `Date`\n  structs that follow the same or compatible calendars can be compared\n  this way. If two calendars are not compatible, it will raise.\n\n  ## Examples\n\n      iex> Date.diff(~D[2000-01-03], ~D[2000-01-01])\n      2\n      iex> Date.diff(~D[2000-01-01], ~D[2000-01-03])\n      -2\n      iex> Date.diff(~D[0000-01-02], ~D[-0001-12-30])\n      3\n      iex> Date.diff(~D[2000-01-01], ~N[2000-01-03 09:00:00])\n      -2\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec diff(Calendar.date(), Calendar.date()) :: integer\n  def diff(%{calendar: Calendar.ISO} = date1, %{calendar: Calendar.ISO} = date2) do\n    %{year: year1, month: month1, day: day1} = date1\n    %{year: year2, month: month2, day: day2} = date2\n\n    Calendar.ISO.date_to_iso_days(year1, month1, day1) -\n      Calendar.ISO.date_to_iso_days(year2, month2, day2)\n  end\n\n  def diff(%{calendar: calendar1} = date1, %{calendar: calendar2} = date2) do\n    if Calendar.compatible_calendars?(calendar1, calendar2) do\n      {days1, _} = to_iso_days(date1)\n      {days2, _} = to_iso_days(date2)\n      days1 - days2\n    else\n      raise ArgumentError,\n            \"cannot calculate the difference between #{inspect(date1)} and #{inspect(date2)} because their calendars are not compatible and thus the result would be ambiguous\"\n    end\n  end\n\n  @doc \"\"\"\n  Shifts given `date` by `duration` according to its calendar.\n\n  Allowed units are: `:year`, `:month`, `:week`, `:day`.\n\n  When using the default ISO calendar, durations are collapsed and\n  applied in the order of months and then days:\n\n  * when shifting by 1 year and 2 months the date is actually shifted by 14 months\n  * when shifting by 2 weeks and 3 days the date is shifted by 17 days\n\n  When shifting by month, days are rounded down to the nearest valid date.\n\n  Raises an `ArgumentError` when called with time scale units.\n\n  ## Examples\n\n      iex> Date.shift(~D[2016-01-03], month: 2)\n      ~D[2016-03-03]\n      iex> Date.shift(~D[2016-01-30], month: -1)\n      ~D[2015-12-30]\n      iex> Date.shift(~D[2016-01-31], year: 4, day: 1)\n      ~D[2020-02-01]\n      iex> Date.shift(~D[2016-01-03], Duration.new!(month: 2))\n      ~D[2016-03-03]\n\n      # leap years\n      iex> Date.shift(~D[2024-02-29], year: 1)\n      ~D[2025-02-28]\n      iex> Date.shift(~D[2024-02-29], year: 4)\n      ~D[2028-02-29]\n\n      # rounding down\n      iex> Date.shift(~D[2015-01-31], month: 1)\n      ~D[2015-02-28]\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec shift(Calendar.date(), Duration.t() | [unit_pair]) :: t\n        when unit_pair: {:year, integer} | {:month, integer} | {:week, integer} | {:day, integer}\n  def shift(%{calendar: calendar} = date, duration) do\n    %{year: year, month: month, day: day} = date\n    {year, month, day} = calendar.shift_date(year, month, day, __duration__!(duration))\n    %Date{calendar: calendar, year: year, month: month, day: day}\n  end\n\n  @doc false\n  def __duration__!(%Duration{} = duration) do\n    duration\n  end\n\n  # This part is inlined by the compiler on constant values\n  def __duration__!(unit_pairs) do\n    Enum.each(unit_pairs, &validate_duration_unit!/1)\n    struct!(Duration, unit_pairs)\n  end\n\n  defp validate_duration_unit!({unit, _value})\n       when unit in [:hour, :minute, :second, :microsecond] do\n    raise ArgumentError, \"unsupported unit #{inspect(unit)}. Expected :year, :month, :week, :day\"\n  end\n\n  defp validate_duration_unit!({unit, _value}) when unit not in [:year, :month, :week, :day] do\n    raise ArgumentError, \"unknown unit #{inspect(unit)}. Expected :year, :month, :week, :day\"\n  end\n\n  defp validate_duration_unit!({_unit, value}) when is_integer(value) do\n    :ok\n  end\n\n  defp validate_duration_unit!({unit, value}) do\n    raise ArgumentError,\n          \"unsupported value #{inspect(value)} for #{inspect(unit)}. Expected an integer\"\n  end\n\n  @doc false\n  def to_iso_days(%{calendar: Calendar.ISO, year: year, month: month, day: day}) do\n    {Calendar.ISO.date_to_iso_days(year, month, day), {0, 86_400_000_000}}\n  end\n\n  def to_iso_days(%{calendar: calendar, year: year, month: month, day: day}) do\n    calendar.naive_datetime_to_iso_days(year, month, day, 0, 0, 0, {0, 0})\n  end\n\n  defp from_iso_days({days, _}, Calendar.ISO) do\n    {year, month, day} = Calendar.ISO.date_from_iso_days(days)\n    %Date{year: year, month: month, day: day, calendar: Calendar.ISO}\n  end\n\n  defp from_iso_days(iso_days, target_calendar) do\n    {year, month, day, _, _, _, _} = target_calendar.naive_datetime_from_iso_days(iso_days)\n    %Date{year: year, month: month, day: day, calendar: target_calendar}\n  end\n\n  @doc \"\"\"\n  Calculates the ordinal day of the week of a given `date`.\n\n  Returns the day of the week as an integer. For the ISO 8601\n  calendar (the default), it is an integer from 1 to 7, where\n  1 is Monday and 7 is Sunday.\n\n  An optional `starting_on` value may be supplied, which\n  configures the weekday the week starts on. The default value\n  for it is `:default`, which translates to `:monday` for the\n  built-in ISO 8601 calendar. Any other weekday may be used for\n  `starting_on`, in such cases, that weekday will be considered the first\n  day of the week, and therefore it will be assigned the ordinal number 1.\n\n  The other calendars, the value returned is an ordinal day of week.\n  For example, `1` may mean \"first day of the week\" and `7` is\n  defined to mean \"seventh day of the week\". Custom calendars may\n  also accept their own variations of the `starting_on` parameter\n  with their own meaning.\n\n  ## Examples\n\n      # 2016-10-31 is a Monday and by default Monday is the first day of the week\n      iex> Date.day_of_week(~D[2016-10-31])\n      1\n      iex> Date.day_of_week(~D[2016-11-01])\n      2\n      iex> Date.day_of_week(~N[2016-11-01 01:23:45])\n      2\n      iex> Date.day_of_week(~D[-0015-10-30])\n      3\n\n      # 2016-10-31 is a Monday but, as we start the week on Sunday, now it returns 2\n      iex> Date.day_of_week(~D[2016-10-31], :sunday)\n      2\n      iex> Date.day_of_week(~D[2016-11-01], :sunday)\n      3\n      iex> Date.day_of_week(~N[2016-11-01 01:23:45], :sunday)\n      3\n      iex> Date.day_of_week(~D[-0015-10-30], :sunday)\n      4\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec day_of_week(Calendar.date(), starting_on :: :default | atom) :: Calendar.day_of_week()\n  def day_of_week(date, starting_on \\\\ :default)\n\n  def day_of_week(%{calendar: calendar, year: year, month: month, day: day}, starting_on) do\n    {day_of_week, _first, _last} = calendar.day_of_week(year, month, day, starting_on)\n    day_of_week\n  end\n\n  @doc \"\"\"\n  Calculates a date that is the first day of the week for the given `date`.\n\n  If the day is already the first day of the week, it returns the\n  day itself. For the built-in ISO calendar, the week starts on Monday.\n  A weekday rather than `:default` can be given as `starting_on`.\n\n  ## Examples\n\n      iex> Date.beginning_of_week(~D[2020-07-11])\n      ~D[2020-07-06]\n      iex> Date.beginning_of_week(~D[2020-07-06])\n      ~D[2020-07-06]\n      iex> Date.beginning_of_week(~D[2020-07-11], :sunday)\n      ~D[2020-07-05]\n      iex> Date.beginning_of_week(~D[2020-07-11], :saturday)\n      ~D[2020-07-11]\n      iex> Date.beginning_of_week(~N[2020-07-11 01:23:45])\n      ~D[2020-07-06]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec beginning_of_week(Calendar.date(), starting_on :: :default | atom) :: Date.t()\n  def beginning_of_week(date, starting_on \\\\ :default)\n\n  def beginning_of_week(%{calendar: Calendar.ISO} = date, starting_on) do\n    %{year: year, month: month, day: day} = date\n    iso_days = Calendar.ISO.date_to_iso_days(year, month, day)\n\n    {year, month, day} =\n      case Calendar.ISO.iso_days_to_day_of_week(iso_days, starting_on) do\n        1 ->\n          {year, month, day}\n\n        day_of_week ->\n          Calendar.ISO.date_from_iso_days(iso_days - day_of_week + 1)\n      end\n\n    %Date{calendar: Calendar.ISO, year: year, month: month, day: day}\n  end\n\n  def beginning_of_week(%{calendar: calendar} = date, starting_on) do\n    %{year: year, month: month, day: day} = date\n\n    case calendar.day_of_week(year, month, day, starting_on) do\n      {day_of_week, day_of_week, _} ->\n        %Date{calendar: calendar, year: year, month: month, day: day}\n\n      {day_of_week, first_day_of_week, _} ->\n        add(date, -(day_of_week - first_day_of_week))\n    end\n  end\n\n  @doc \"\"\"\n  Calculates a date that is the last day of the week for the given `date`.\n\n  If the day is already the last day of the week, it returns the\n  day itself. For the built-in ISO calendar, the week ends on Sunday.\n  A weekday rather than `:default` can be given as `starting_on`.\n\n  ## Examples\n\n      iex> Date.end_of_week(~D[2020-07-11])\n      ~D[2020-07-12]\n      iex> Date.end_of_week(~D[2020-07-05])\n      ~D[2020-07-05]\n      iex> Date.end_of_week(~D[2020-07-06], :sunday)\n      ~D[2020-07-11]\n      iex> Date.end_of_week(~D[2020-07-06], :saturday)\n      ~D[2020-07-10]\n      iex> Date.end_of_week(~N[2020-07-11 01:23:45])\n      ~D[2020-07-12]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec end_of_week(Calendar.date(), starting_on :: :default | atom) :: Date.t()\n  def end_of_week(date, starting_on \\\\ :default)\n\n  def end_of_week(%{calendar: Calendar.ISO} = date, starting_on) do\n    %{year: year, month: month, day: day} = date\n    iso_days = Calendar.ISO.date_to_iso_days(year, month, day)\n\n    {year, month, day} =\n      case Calendar.ISO.iso_days_to_day_of_week(iso_days, starting_on) do\n        7 ->\n          {year, month, day}\n\n        day_of_week ->\n          Calendar.ISO.date_from_iso_days(iso_days + 7 - day_of_week)\n      end\n\n    %Date{calendar: Calendar.ISO, year: year, month: month, day: day}\n  end\n\n  def end_of_week(%{calendar: calendar} = date, starting_on) do\n    %{year: year, month: month, day: day} = date\n\n    case calendar.day_of_week(year, month, day, starting_on) do\n      {day_of_week, _, day_of_week} ->\n        %Date{calendar: calendar, year: year, month: month, day: day}\n\n      {day_of_week, _, last_day_of_week} ->\n        add(date, last_day_of_week - day_of_week)\n    end\n  end\n\n  @doc \"\"\"\n  Calculates the day of the year of a given `date`.\n\n  Returns the day of the year as an integer. For the ISO 8601\n  calendar (the default), it is an integer from 1 to 366.\n\n  ## Examples\n\n      iex> Date.day_of_year(~D[2016-01-01])\n      1\n      iex> Date.day_of_year(~D[2016-11-01])\n      306\n      iex> Date.day_of_year(~D[-0015-10-30])\n      303\n      iex> Date.day_of_year(~D[2004-12-31])\n      366\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec day_of_year(Calendar.date()) :: Calendar.day()\n  def day_of_year(date)\n\n  def day_of_year(%{calendar: calendar, year: year, month: month, day: day}) do\n    calendar.day_of_year(year, month, day)\n  end\n\n  @doc \"\"\"\n  Calculates the quarter of the year of a given `date`.\n\n  Returns the day of the year as an integer. For the ISO 8601\n  calendar (the default), it is an integer from 1 to 4.\n\n  ## Examples\n\n      iex> Date.quarter_of_year(~D[2016-10-31])\n      4\n      iex> Date.quarter_of_year(~D[2016-01-01])\n      1\n      iex> Date.quarter_of_year(~N[2016-04-01 01:23:45])\n      2\n      iex> Date.quarter_of_year(~D[-0015-09-30])\n      3\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec quarter_of_year(Calendar.date()) :: non_neg_integer()\n  def quarter_of_year(date)\n\n  def quarter_of_year(%{calendar: calendar, year: year, month: month, day: day}) do\n    calendar.quarter_of_year(year, month, day)\n  end\n\n  @doc \"\"\"\n  Calculates the year-of-era and era for a given\n  calendar year.\n\n  Returns a tuple `{year, era}` representing the\n  year within the era and the era number.\n\n  ## Examples\n\n      iex> Date.year_of_era(~D[0001-01-01])\n      {1, 1}\n      iex> Date.year_of_era(~D[0000-12-31])\n      {1, 0}\n      iex> Date.year_of_era(~D[-0001-01-01])\n      {2, 0}\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec year_of_era(Calendar.date()) :: {Calendar.year(), non_neg_integer()}\n  def year_of_era(date)\n\n  def year_of_era(%{calendar: calendar, year: year, month: month, day: day}) do\n    calendar.year_of_era(year, month, day)\n  end\n\n  @doc \"\"\"\n  Calculates the day-of-era and era for a given\n  calendar `date`.\n\n  Returns a tuple `{day, era}` representing the\n  day within the era and the era number.\n\n  ## Examples\n\n      iex> Date.day_of_era(~D[0001-01-01])\n      {1, 1}\n\n      iex> Date.day_of_era(~D[0000-12-31])\n      {1, 0}\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec day_of_era(Calendar.date()) :: {Calendar.day(), non_neg_integer()}\n  def day_of_era(date)\n\n  def day_of_era(%{calendar: calendar, year: year, month: month, day: day}) do\n    calendar.day_of_era(year, month, day)\n  end\n\n  @doc \"\"\"\n  Calculates a date that is the first day of the month for the given `date`.\n\n  ## Examples\n\n      iex> Date.beginning_of_month(~D[2000-01-31])\n      ~D[2000-01-01]\n      iex> Date.beginning_of_month(~D[2000-01-01])\n      ~D[2000-01-01]\n      iex> Date.beginning_of_month(~N[2000-01-31 01:23:45])\n      ~D[2000-01-01]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec beginning_of_month(Calendar.date()) :: t()\n  def beginning_of_month(date)\n\n  def beginning_of_month(%{year: year, month: month, calendar: calendar}) do\n    %Date{year: year, month: month, day: 1, calendar: calendar}\n  end\n\n  @doc \"\"\"\n  Calculates a date that is the last day of the month for the given `date`.\n\n  ## Examples\n\n      iex> Date.end_of_month(~D[2000-01-01])\n      ~D[2000-01-31]\n      iex> Date.end_of_month(~D[2000-01-31])\n      ~D[2000-01-31]\n      iex> Date.end_of_month(~N[2000-01-01 01:23:45])\n      ~D[2000-01-31]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec end_of_month(Calendar.date()) :: t()\n  def end_of_month(date)\n\n  def end_of_month(%{year: year, month: month, calendar: calendar} = date) do\n    day = Date.days_in_month(date)\n    %Date{year: year, month: month, day: day, calendar: calendar}\n  end\n\n  ## Helpers\n\n  defimpl String.Chars do\n    def to_string(%{calendar: calendar, year: year, month: month, day: day}) do\n      calendar.date_to_string(year, month, day)\n    end\n  end\n\n  defimpl Inspect do\n    def inspect(%{calendar: calendar, year: year, month: month, day: day}, _)\n        when calendar != Calendar.ISO or year in -9999..9999 do\n      \"~D[\" <> calendar.date_to_string(year, month, day) <> suffix(calendar) <> \"]\"\n    end\n\n    def inspect(%{calendar: Calendar.ISO, year: year, month: month, day: day}, _) do\n      \"Date.new!(#{Integer.to_string(year)}, #{Integer.to_string(month)}, #{Integer.to_string(day)})\"\n    end\n\n    def inspect(%{calendar: calendar, year: year, month: month, day: day}, _) do\n      \"Date.new!(#{Integer.to_string(year)}, #{Integer.to_string(month)}, #{Integer.to_string(day)}, #{inspect(calendar)})\"\n    end\n\n    defp suffix(Calendar.ISO), do: \"\"\n    defp suffix(calendar), do: \" \" <> inspect(calendar)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar/date_range.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Date.Range do\n  @moduledoc \"\"\"\n  Returns an inclusive range between dates.\n\n  Ranges must be created with the `Date.range/2` or `Date.range/3` function.\n\n  The following fields are public:\n\n    * `:first` - the initial date on the range\n    * `:last` - the last date on the range\n    * `:step` - (since v1.12.0) the step\n\n  The remaining fields are private and should not be accessed.\n  \"\"\"\n\n  @type t :: %__MODULE__{\n          first: Date.t(),\n          last: Date.t(),\n          first_in_iso_days: days(),\n          last_in_iso_days: days(),\n          step: pos_integer | neg_integer\n        }\n\n  @typep days() :: integer()\n\n  @enforce_keys [:first, :last, :first_in_iso_days, :last_in_iso_days, :step]\n  defstruct [:first, :last, :first_in_iso_days, :last_in_iso_days, :step]\n\n  defimpl Enumerable do\n    def member?(\n          %Date.Range{\n            first: %{calendar: calendar},\n            first_in_iso_days: first_days,\n            last_in_iso_days: last_days,\n            step: step\n          } = range,\n          %Date{calendar: calendar} = date\n        ) do\n      {days, _} = Date.to_iso_days(date)\n\n      cond do\n        empty?(range) ->\n          {:ok, false}\n\n        first_days <= last_days ->\n          {:ok, first_days <= days and days <= last_days and rem(days - first_days, step) == 0}\n\n        true ->\n          {:ok, last_days <= days and days <= first_days and rem(days - first_days, step) == 0}\n      end\n    end\n\n    def member?(%Date.Range{step: _}, _) do\n      {:ok, false}\n    end\n\n    # TODO: Remove me on v2.0\n    member? =\n      quote generated: true do\n        member?(\n          %{\n            __struct__: Date.Range,\n            first_in_iso_days: var!(first_days),\n            last_in_iso_days: var!(last_days)\n          } =\n            var!(date_range),\n          var!(date)\n        )\n      end\n\n    def unquote(member?) do\n      step = if first_days <= last_days, do: 1, else: -1\n      member?(Map.put(date_range, :step, step), date)\n    end\n\n    def count(range) do\n      {:ok, size(range)}\n    end\n\n    def slice(\n          %Date.Range{\n            first_in_iso_days: first,\n            first: %{calendar: calendar},\n            step: step\n          } = range\n        ) do\n      {:ok, size(range), &slice(first + &1 * step, step + &3 - 1, &2, calendar)}\n    end\n\n    # TODO: Remove me on v2.0\n    def slice(\n          %{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =\n            date_range\n        ) do\n      step = if first_days <= last_days, do: 1, else: -1\n      slice(Map.put(date_range, :step, step))\n    end\n\n    defp slice(current, _step, 1, calendar) do\n      [date_from_iso_days(current, calendar)]\n    end\n\n    defp slice(current, step, remaining, calendar) when remaining > 1 do\n      [\n        date_from_iso_days(current, calendar)\n        | slice(current + step, step, remaining - 1, calendar)\n      ]\n    end\n\n    def reduce(\n          %Date.Range{\n            first_in_iso_days: first_days,\n            last_in_iso_days: last_days,\n            first: %{calendar: calendar},\n            step: step\n          },\n          acc,\n          fun\n        ) do\n      reduce(first_days, last_days, acc, fun, step, calendar)\n    end\n\n    # TODO: Remove me on v2.0\n    def reduce(\n          %{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =\n            date_range,\n          acc,\n          fun\n        ) do\n      step = if first_days <= last_days, do: 1, else: -1\n      reduce(Map.put(date_range, :step, step), acc, fun)\n    end\n\n    defp reduce(_first_days, _last_days, {:halt, acc}, _fun, _step, _calendar) do\n      {:halted, acc}\n    end\n\n    defp reduce(first_days, last_days, {:suspend, acc}, fun, step, calendar) do\n      {:suspended, acc, &reduce(first_days, last_days, &1, fun, step, calendar)}\n    end\n\n    defp reduce(first_days, last_days, {:cont, acc}, fun, step, calendar)\n         when step > 0 and first_days <= last_days\n         when step < 0 and first_days >= last_days do\n      reduce(\n        first_days + step,\n        last_days,\n        fun.(date_from_iso_days(first_days, calendar), acc),\n        fun,\n        step,\n        calendar\n      )\n    end\n\n    defp reduce(_, _, {:cont, acc}, _fun, _step, _calendar) do\n      {:done, acc}\n    end\n\n    defp date_from_iso_days(days, Calendar.ISO) do\n      {year, month, day} = Calendar.ISO.date_from_iso_days(days)\n      %Date{year: year, month: month, day: day, calendar: Calendar.ISO}\n    end\n\n    defp date_from_iso_days(days, calendar) do\n      {year, month, day, _, _, _, _} =\n        calendar.naive_datetime_from_iso_days({days, {0, 86_400_000_000}})\n\n      %Date{year: year, month: month, day: day, calendar: calendar}\n    end\n\n    defp size(%Date.Range{first_in_iso_days: first_days, last_in_iso_days: last_days, step: step})\n         when step > 0 and first_days > last_days,\n         do: 0\n\n    defp size(%Date.Range{first_in_iso_days: first_days, last_in_iso_days: last_days, step: step})\n         when step < 0 and first_days < last_days,\n         do: 0\n\n    defp size(%Date.Range{\n           first_in_iso_days: first_days,\n           last_in_iso_days: last_days,\n           step: step\n         }),\n         do: abs(div(last_days - first_days, step)) + 1\n\n    # TODO: Remove me on v2.0\n    defp size(\n           %{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =\n             date_range\n         ) do\n      step = if first_days <= last_days, do: 1, else: -1\n      size(Map.put(date_range, :step, step))\n    end\n\n    defp empty?(%Date.Range{\n           first_in_iso_days: first_days,\n           last_in_iso_days: last_days,\n           step: step\n         })\n         when step > 0 and first_days > last_days,\n         do: true\n\n    defp empty?(%Date.Range{\n           first_in_iso_days: first_days,\n           last_in_iso_days: last_days,\n           step: step\n         })\n         when step < 0 and first_days < last_days,\n         do: true\n\n    defp empty?(%Date.Range{step: _}), do: false\n\n    # TODO: Remove me on v2.0\n    defp empty?(\n           %{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =\n             date_range\n         ) do\n      step = if first_days <= last_days, do: 1, else: -1\n      empty?(Map.put(date_range, :step, step))\n    end\n  end\n\n  defimpl Inspect do\n    import Kernel, except: [inspect: 2]\n\n    def inspect(%Date.Range{first: first, last: last, step: 1}, %Inspect.Opts{}) do\n      \"Date.range(\" <> inspect(first) <> \", \" <> inspect(last) <> \")\"\n    end\n\n    def inspect(%Date.Range{first: first, last: last, step: step}, %Inspect.Opts{}) do\n      \"Date.range(\" <> inspect(first) <> \", \" <> inspect(last) <> \", #{step})\"\n    end\n\n    # TODO: Remove me on v2.0\n    def inspect(%{__struct__: Date.Range, first: first, last: last} = date_range, opts) do\n      step = if first <= last, do: 1, else: -1\n      inspect(Map.put(date_range, :step, step), opts)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar/datetime.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule DateTime do\n  @moduledoc \"\"\"\n  A datetime implementation with a time zone.\n\n  This datetime can be seen as a snapshot of a date and time\n  at a given time zone. For such purposes, it also includes both\n  UTC and Standard offsets, as well as the zone abbreviation\n  field used exclusively for formatting purposes. Note future\n  datetimes are not necessarily guaranteed to exist, as time\n  zones may change any time in the future due to geopolitical\n  reasons. See the \"Datetimes as snapshots\" section for more\n  information.\n\n  Remember, comparisons in Elixir using `==/2`, `>/2`, `</2` and friends\n  are structural and based on the DateTime struct fields. For proper\n  comparison between datetimes, use the `compare/2`, `after?/2` and `before?/2` functions.\n  The existence of the `compare/2` function in this module also allows\n  using `Enum.min/2` and `Enum.max/2` functions to get the minimum and\n  maximum datetime of an `Enum`. For example:\n\n      iex> Enum.min([~U[2022-01-12 00:01:00.00Z], ~U[2021-01-12 00:01:00.00Z]], DateTime)\n      ~U[2021-01-12 00:01:00.00Z]\n\n  Developers should avoid creating the `DateTime` struct directly\n  and instead rely on the functions provided by this module as\n  well as the ones in third-party calendar libraries.\n\n  ## Time zone database\n\n  Many functions in this module require a time zone database.\n  A time zone database is a record of the UTC offsets that its locales have\n  used at various times in the past, are using, and are expected to use in the\n  future.\n  Because those plans can change, it needs to be periodically updated.\n\n  By default, `DateTime` uses the default time zone database returned by\n  `Calendar.get_time_zone_database/0`, which defaults to\n  `Calendar.UTCOnlyTimeZoneDatabase` which only handles \"Etc/UTC\"\n  datetimes and returns `{:error, :utc_only_time_zone_database}`\n  for any other time zone.\n\n  Other time zone databases can also be configured. Here are some\n  available options and libraries:\n\n    * [`time_zone_info`](https://github.com/hrzndhrn/time_zone_info)\n    * [`tz`](https://github.com/mathieuprog/tz)\n    * [`tzdata`](https://github.com/lau/tzdata)\n    * [`zoneinfo`](https://github.com/smartrent/zoneinfo) -\n      recommended for embedded devices\n\n  To use one of them, first make sure it is added as a dependency in `mix.exs`.\n  It can then be configured either via configuration:\n\n      config :elixir, :time_zone_database, Tz.TimeZoneDatabase\n\n  or by calling `Calendar.put_time_zone_database/1`:\n\n      Calendar.put_time_zone_database(Tz.TimeZoneDatabase)\n\n  See the proper names in the library installation instructions.\n\n  ## Datetimes as snapshots\n\n  In the first section, we described datetimes as a \"snapshot of\n  a date and time at a given time zone\". To understand precisely\n  what we mean, let's see an example.\n\n  Imagine someone in Poland who wants to schedule a meeting with someone\n  in Brazil in the next year. The meeting will happen at 2:30 AM\n  in the Polish time zone. At what time will the meeting happen in\n  Brazil?\n\n  You can consult the time zone database today, one year before,\n  using the API in this module and it will give you an answer that\n  is valid right now. However, this answer may not be valid in the\n  future. Why? Because both Brazil and Poland may change their timezone\n  rules, ultimately affecting the result. For example, a country may\n  choose to enter or abandon \"Daylight Saving Time\", which is a\n  process where we adjust the clock one hour forward or one hour\n  back once per year. Whenever the rules change, the exact instant\n  that 2:30 AM in Polish time will be in Brazil may change.\n\n  In other words, whenever working with future DateTimes, there is\n  no guarantee the results you get will always be correct, until\n  the event actually happens. Therefore, when you ask for a future\n  time, the answers you get are a snapshot that reflects the current\n  state of the time zone rules. For datetimes in the past, this is\n  not a problem, because time zone rules do not change for past\n  events.\n\n  To make matters worse, it may be that 2:30 AM in Polish time\n  does not actually even exist or it is ambiguous. If a certain\n  time zone observes \"Daylight Saving Time\", they will move their\n  clock forward once a year. When this happens, there is a whole\n  hour that does not exist. Then, when they move the clock back,\n  there is a certain hour that will happen twice. So if you want to\n  schedule a meeting when this shift back happens, you would need to\n  explicitly say which occurrence of 2:30 AM you mean: the one in\n  \"Summer Time\", which occurs before the shift, or the one\n  in \"Standard Time\", which occurs after it. Applications that are\n  date and time sensitive need to take these scenarios into account\n  and correctly communicate them to users.\n\n  The good news is: Elixir contains all of the building blocks\n  necessary to tackle those problems. The default timezone database\n  used by Elixir, `Calendar.UTCOnlyTimeZoneDatabase`, only works\n  with UTC, which does not observe those issues. Once you bring\n  a proper time zone database, the functions in this module will\n  query the database and return the relevant information. For\n  example, look at how `DateTime.new/4` returns different results\n  based on the scenarios described in this section.\n\n  ## Converting between timezones\n\n  Bearing in mind the cautions above, and assuming you've brought in a full\n  timezone database, here are some examples of common shifts between time\n  zones.\n\n      # Local time to UTC\n      new_york = DateTime.from_naive!(~N[2023-06-26T09:30:00], \"America/New_York\")\n      #=> #DateTime<2023-06-26 09:30:00-04:00 EDT America/New_York>\n\n      utc = DateTime.shift_zone!(new_york, \"Etc/UTC\")\n      #=> ~U[2023-06-26 13:30:00Z]\n\n      # UTC to local time\n      DateTime.shift_zone!(utc, \"Europe/Paris\")\n      #=> #DateTime<2023-06-26 15:30:00+02:00 CEST Europe/Paris>\n\n  \"\"\"\n\n  @enforce_keys [:year, :month, :day, :hour, :minute, :second] ++\n                  [:time_zone, :zone_abbr, :utc_offset, :std_offset]\n\n  defstruct [\n    :year,\n    :month,\n    :day,\n    :hour,\n    :minute,\n    :second,\n    :time_zone,\n    :zone_abbr,\n    :utc_offset,\n    :std_offset,\n    microsecond: {0, 0},\n    calendar: Calendar.ISO\n  ]\n\n  @type t :: %__MODULE__{\n          year: Calendar.year(),\n          month: Calendar.month(),\n          day: Calendar.day(),\n          calendar: Calendar.calendar(),\n          hour: Calendar.hour(),\n          minute: Calendar.minute(),\n          second: Calendar.second(),\n          microsecond: Calendar.microsecond(),\n          time_zone: Calendar.time_zone(),\n          zone_abbr: Calendar.zone_abbr(),\n          utc_offset: Calendar.utc_offset(),\n          std_offset: Calendar.std_offset()\n        }\n\n  @unix_days :calendar.date_to_gregorian_days({1970, 1, 1})\n  @seconds_per_day 24 * 60 * 60\n\n  @doc \"\"\"\n  Returns the current datetime in UTC.\n\n  If you want the current time in Unix seconds,\n  use `System.os_time/1` instead.\n\n  You can also pass a time unit to automatically\n  truncate the resulting datetime. This is available\n  since v1.15.0.\n\n  The default unit if none gets passed is `:native`,\n  which results on a default resolution of microseconds.\n\n  ## Examples\n\n      iex> datetime = DateTime.utc_now()\n      iex> datetime.time_zone\n      \"Etc/UTC\"\n\n      iex> datetime = DateTime.utc_now(:second)\n      iex> datetime.microsecond\n      {0, 0}\n\n  \"\"\"\n  @spec utc_now(Calendar.calendar() | :native | :microsecond | :millisecond | :second) :: t\n  def utc_now(calendar_or_time_unit \\\\ Calendar.ISO) do\n    case calendar_or_time_unit do\n      unit when unit in [:microsecond, :millisecond, :second, :native] ->\n        utc_now(unit, Calendar.ISO)\n\n      calendar ->\n        System.os_time() |> from_unix!(:native, calendar)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the current datetime in UTC, supporting\n  a specific calendar and precision.\n\n  If you want the current time in Unix seconds,\n  use `System.os_time/1` instead.\n\n  ## Examples\n\n      iex> datetime = DateTime.utc_now(:microsecond, Calendar.ISO)\n      iex> datetime.time_zone\n      \"Etc/UTC\"\n\n      iex> datetime = DateTime.utc_now(:second, Calendar.ISO)\n      iex> datetime.microsecond\n      {0, 0}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec utc_now(:native | :microsecond | :millisecond | :second, Calendar.calendar()) :: t\n  def utc_now(time_unit, calendar)\n      when time_unit in [:native, :microsecond, :millisecond, :second] do\n    System.os_time(time_unit) |> from_unix!(time_unit, calendar)\n  end\n\n  @doc \"\"\"\n  Builds a datetime from date and time structs.\n\n  It expects a time zone to put the `DateTime` in.\n  If the time zone is not passed it will default to `\"Etc/UTC\"`,\n  which always succeeds. Otherwise, the `DateTime` is checked against the time zone database\n  given as `time_zone_database`. See the \"Time zone database\"\n  section in the module documentation.\n\n  ## Examples\n\n      iex> DateTime.new(~D[2016-05-24], ~T[13:26:08.003], \"Etc/UTC\")\n      {:ok, ~U[2016-05-24 13:26:08.003Z]}\n\n  When the datetime is ambiguous - for instance during changing from summer\n  to winter time - the two possible valid datetimes are returned in a tuple.\n  The first datetime is also the one which comes first chronologically, while\n  the second one comes last.\n\n      iex> {:ambiguous, first_dt, second_dt} = DateTime.new(~D[2018-10-28], ~T[02:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> first_dt\n      #DateTime<2018-10-28 02:30:00+02:00 CEST Europe/Copenhagen>\n      iex> second_dt\n      #DateTime<2018-10-28 02:30:00+01:00 CET Europe/Copenhagen>\n\n  When there is a gap in wall time - for instance in spring when the clocks are\n  turned forward - the latest valid datetime just before the gap and the first\n  valid datetime just after the gap.\n\n      iex> {:gap, just_before, just_after} = DateTime.new(~D[2019-03-31], ~T[02:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> just_before\n      #DateTime<2019-03-31 01:59:59.999999+01:00 CET Europe/Copenhagen>\n      iex> just_after\n      #DateTime<2019-03-31 03:00:00+02:00 CEST Europe/Copenhagen>\n\n  Most of the time there is one, and just one, valid datetime for a certain\n  date and time in a certain time zone.\n\n      iex> {:ok, datetime} = DateTime.new(~D[2018-07-28], ~T[12:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> datetime\n      #DateTime<2018-07-28 12:30:00+02:00 CEST Europe/Copenhagen>\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec new(Date.t(), Time.t(), Calendar.time_zone(), Calendar.time_zone_database()) ::\n          {:ok, t}\n          | {:ambiguous, first_datetime :: t, second_datetime :: t}\n          | {:gap, t, t}\n          | {:error,\n             :incompatible_calendars | :time_zone_not_found | :utc_only_time_zone_database}\n  def new(\n        date,\n        time,\n        time_zone \\\\ \"Etc/UTC\",\n        time_zone_database \\\\ Calendar.get_time_zone_database()\n      )\n\n  def new(%Date{calendar: calendar} = date, %Time{calendar: calendar} = time, \"Etc/UTC\", _db) do\n    %{year: year, month: month, day: day} = date\n    %{hour: hour, minute: minute, second: second, microsecond: microsecond} = time\n\n    datetime = %DateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      std_offset: 0,\n      utc_offset: 0,\n      zone_abbr: \"UTC\",\n      time_zone: \"Etc/UTC\"\n    }\n\n    {:ok, datetime}\n  end\n\n  def new(date, time, time_zone, time_zone_database) do\n    with {:ok, naive_datetime} <- NaiveDateTime.new(date, time) do\n      from_naive(naive_datetime, time_zone, time_zone_database)\n    end\n  end\n\n  @doc \"\"\"\n  Builds a datetime from date and time structs, raising on errors.\n\n  It expects a time zone to put the `DateTime` in.\n  If the time zone is not passed it will default to `\"Etc/UTC\"`,\n  which always succeeds. Otherwise, the DateTime is checked against the time zone database\n  given as `time_zone_database`. See the \"Time zone database\"\n  section in the module documentation.\n\n  ## Examples\n\n      iex> DateTime.new!(~D[2016-05-24], ~T[13:26:08.003], \"Etc/UTC\")\n      ~U[2016-05-24 13:26:08.003Z]\n\n  When the datetime is ambiguous - for instance during changing from summer\n  to winter time - an error will be raised.\n\n      iex> DateTime.new!(~D[2018-10-28], ~T[02:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      ** (ArgumentError) cannot build datetime with ~D[2018-10-28] and ~T[02:30:00] because such instant is ambiguous in time zone Europe/Copenhagen as there is an overlap between #DateTime<2018-10-28 02:30:00+02:00 CEST Europe/Copenhagen> and #DateTime<2018-10-28 02:30:00+01:00 CET Europe/Copenhagen>\n\n  When there is a gap in wall time - for instance in spring when the clocks are\n  turned forward - an error will be raised.\n\n      iex> DateTime.new!(~D[2019-03-31], ~T[02:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      ** (ArgumentError) cannot build datetime with ~D[2019-03-31] and ~T[02:30:00] because such instant does not exist in time zone Europe/Copenhagen as there is a gap between #DateTime<2019-03-31 01:59:59.999999+01:00 CET Europe/Copenhagen> and #DateTime<2019-03-31 03:00:00+02:00 CEST Europe/Copenhagen>\n\n  Most of the time there is one, and just one, valid datetime for a certain\n  date and time in a certain time zone.\n\n      iex> datetime = DateTime.new!(~D[2018-07-28], ~T[12:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> datetime\n      #DateTime<2018-07-28 12:30:00+02:00 CEST Europe/Copenhagen>\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec new!(Date.t(), Time.t(), Calendar.time_zone(), Calendar.time_zone_database()) :: t\n  def new!(\n        date,\n        time,\n        time_zone \\\\ \"Etc/UTC\",\n        time_zone_database \\\\ Calendar.get_time_zone_database()\n      )\n\n  def new!(date, time, time_zone, time_zone_database) do\n    case new(date, time, time_zone, time_zone_database) do\n      {:ok, datetime} ->\n        datetime\n\n      {:ambiguous, dt1, dt2} ->\n        raise ArgumentError,\n              \"cannot build datetime with #{inspect(date)} and #{inspect(time)} because such \" <>\n                \"instant is ambiguous in time zone #{time_zone} as there is an overlap \" <>\n                \"between #{inspect(dt1)} and #{inspect(dt2)}\"\n\n      {:gap, dt1, dt2} ->\n        raise ArgumentError,\n              \"cannot build datetime with #{inspect(date)} and #{inspect(time)} because such \" <>\n                \"instant does not exist in time zone #{time_zone} as there is a gap \" <>\n                \"between #{inspect(dt1)} and #{inspect(dt2)}\"\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot build datetime with #{inspect(date)} and #{inspect(time)}, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given Unix time to `DateTime`.\n\n  The integer can be given in different unit, according to `System.convert_time_unit/3`,\n  and it will be converted to microseconds internally, which is the maximum precision\n  supported by `DateTime`. In other words, any precision higher than microseconds will\n  lead to truncation.\n\n  Unix times are always in UTC. Therefore the DateTime will be returned in UTC.\n\n  ## Examples\n\n      iex> {:ok, datetime} = DateTime.from_unix(1_464_096_368)\n      iex> datetime\n      ~U[2016-05-24 13:26:08Z]\n\n      iex> {:ok, datetime} = DateTime.from_unix(1_432_560_368_868_569, :microsecond)\n      iex> datetime\n      ~U[2015-05-25 13:26:08.868569Z]\n\n      iex> {:ok, datetime} = DateTime.from_unix(253_402_300_799)\n      iex> datetime\n      ~U[9999-12-31 23:59:59Z]\n\n      iex> {:error, :invalid_unix_time} = DateTime.from_unix(253_402_300_800)\n\n  The unit can also be an integer as in `t:System.time_unit/0`:\n\n      iex> {:ok, datetime} = DateTime.from_unix(143_256_036_886_856, 1024)\n      iex> datetime\n      ~U[6403-03-17 07:05:22.320312Z]\n\n  Negative Unix times are supported up to -377705116800 seconds:\n\n      iex> {:ok, datetime} = DateTime.from_unix(-377_705_116_800)\n      iex> datetime\n      ~U[-9999-01-01 00:00:00Z]\n\n      iex> {:error, :invalid_unix_time} = DateTime.from_unix(-377_705_116_801)\n\n  \"\"\"\n  @spec from_unix(integer, :native | System.time_unit(), Calendar.calendar()) ::\n          {:ok, t} | {:error, atom}\n  def from_unix(integer, unit \\\\ :second, calendar \\\\ Calendar.ISO) when is_integer(integer) do\n    case Calendar.ISO.from_unix(integer, unit) do\n      {:ok, {year, month, day}, {hour, minute, second}, microsecond} ->\n        iso_datetime = %DateTime{\n          year: year,\n          month: month,\n          day: day,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond,\n          std_offset: 0,\n          utc_offset: 0,\n          zone_abbr: \"UTC\",\n          time_zone: \"Etc/UTC\"\n        }\n\n        convert(iso_datetime, calendar)\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given Unix time to `DateTime`.\n\n  The integer can be given in different unit\n  according to `System.convert_time_unit/3` and it will\n  be converted to microseconds internally.\n\n  Unix times are always in UTC and therefore the DateTime\n  will be returned in UTC.\n\n  ## Examples\n\n      # An easy way to get the Unix epoch is passing 0 to this function\n      iex> DateTime.from_unix!(0)\n      ~U[1970-01-01 00:00:00Z]\n\n      iex> DateTime.from_unix!(1_464_096_368)\n      ~U[2016-05-24 13:26:08Z]\n\n      iex> DateTime.from_unix!(1_432_560_368_868_569, :microsecond)\n      ~U[2015-05-25 13:26:08.868569Z]\n\n      iex> DateTime.from_unix!(143_256_036_886_856, 1024)\n      ~U[6403-03-17 07:05:22.320312Z]\n\n  \"\"\"\n  @spec from_unix!(integer, :native | System.time_unit(), Calendar.calendar()) :: t\n  def from_unix!(integer, unit \\\\ :second, calendar \\\\ Calendar.ISO) do\n    case from_unix(integer, unit, calendar) do\n      {:ok, datetime} ->\n        datetime\n\n      {:error, :invalid_unix_time} ->\n        raise ArgumentError, \"invalid Unix time #{integer}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given `NaiveDateTime` to `DateTime`.\n\n  It expects a time zone to put the `NaiveDateTime` in.\n  If the time zone is \"Etc/UTC\", it always succeeds. Otherwise,\n  the NaiveDateTime is checked against the time zone database\n  given as `time_zone_database`. See the \"Time zone database\"\n  section in the module documentation.\n\n  ## Examples\n\n      iex> DateTime.from_naive(~N[2016-05-24 13:26:08.003], \"Etc/UTC\")\n      {:ok, ~U[2016-05-24 13:26:08.003Z]}\n\n  When the datetime is ambiguous - for instance during changing from summer\n  to winter time - the two possible valid datetimes are returned in a tuple.\n  The first datetime is also the one which comes first chronologically, while\n  the second one comes last.\n\n      iex> {:ambiguous, first_dt, second_dt} = DateTime.from_naive(~N[2018-10-28 02:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> first_dt\n      #DateTime<2018-10-28 02:30:00+02:00 CEST Europe/Copenhagen>\n      iex> second_dt\n      #DateTime<2018-10-28 02:30:00+01:00 CET Europe/Copenhagen>\n\n  When there is a gap in wall time - for instance in spring when the clocks are\n  turned forward - the latest valid datetime just before the gap and the first\n  valid datetime just after the gap.\n\n      iex> {:gap, just_before, just_after} = DateTime.from_naive(~N[2019-03-31 02:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> just_before\n      #DateTime<2019-03-31 01:59:59.999999+01:00 CET Europe/Copenhagen>\n      iex> just_after\n      #DateTime<2019-03-31 03:00:00+02:00 CEST Europe/Copenhagen>\n\n  Most of the time there is one, and just one, valid datetime for a certain\n  date and time in a certain time zone.\n\n      iex> {:ok, datetime} = DateTime.from_naive(~N[2018-07-28 12:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> datetime\n      #DateTime<2018-07-28 12:30:00+02:00 CEST Europe/Copenhagen>\n\n  This function accepts any map or struct that contains at least the same fields as a `NaiveDateTime`\n  struct. The most common example of that is a `DateTime`. In this case the information about the time\n  zone of that `DateTime` is completely ignored. This is the same principle as passing a `DateTime` to\n  `Date.to_iso8601/2`. `Date.to_iso8601/2` extracts only the date-specific fields (calendar, year,\n  month and day) of the given structure and ignores all others.\n\n  This way if you have a `DateTime` in one time zone, you can get the same wall time in another time zone.\n  For instance if you have 2018-08-24 10:00:00 in Copenhagen and want a `DateTime` for 2018-08-24 10:00:00\n  in UTC you can do:\n\n      iex> cph_datetime = DateTime.from_naive!(~N[2018-08-24 10:00:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> {:ok, utc_datetime} = DateTime.from_naive(cph_datetime, \"Etc/UTC\", FakeTimeZoneDatabase)\n      iex> utc_datetime\n      ~U[2018-08-24 10:00:00Z]\n\n  If instead you want a `DateTime` for the same point time in a different time zone see the\n  `DateTime.shift_zone/3` function which would convert 2018-08-24 10:00:00 in Copenhagen\n  to 2018-08-24 08:00:00 in UTC.\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec from_naive(\n          Calendar.naive_datetime(),\n          Calendar.time_zone(),\n          Calendar.time_zone_database()\n        ) ::\n          {:ok, t}\n          | {:ambiguous, first_datetime :: t, second_datetime :: t}\n          | {:gap, t, t}\n          | {:error,\n             :incompatible_calendars | :time_zone_not_found | :utc_only_time_zone_database}\n\n  def from_naive(\n        naive_datetime,\n        time_zone,\n        time_zone_database \\\\ Calendar.get_time_zone_database()\n      )\n\n  def from_naive(naive_datetime, \"Etc/UTC\", _) do\n    utc_period = %{std_offset: 0, utc_offset: 0, zone_abbr: \"UTC\"}\n    {:ok, from_naive_with_period(naive_datetime, \"Etc/UTC\", utc_period)}\n  end\n\n  def from_naive(%{calendar: Calendar.ISO} = naive_datetime, time_zone, time_zone_database) do\n    case time_zone_database.time_zone_periods_from_wall_datetime(naive_datetime, time_zone) do\n      {:ok, period} ->\n        {:ok, from_naive_with_period(naive_datetime, time_zone, period)}\n\n      {:ambiguous, first_period, second_period} ->\n        first_datetime = from_naive_with_period(naive_datetime, time_zone, first_period)\n        second_datetime = from_naive_with_period(naive_datetime, time_zone, second_period)\n        {:ambiguous, first_datetime, second_datetime}\n\n      {:gap, {first_period, first_period_until_wall}, {second_period, second_period_from_wall}} ->\n        # `until_wall` is not valid, but any time just before is.\n        # So by subtracting a second and adding .999999 seconds\n        # we get the last microsecond just before.\n        before_naive =\n          first_period_until_wall\n          |> Map.replace!(:microsecond, {999_999, 6})\n          |> NaiveDateTime.add(-1)\n\n        after_naive = second_period_from_wall\n\n        latest_datetime_before = from_naive_with_period(before_naive, time_zone, first_period)\n        first_datetime_after = from_naive_with_period(after_naive, time_zone, second_period)\n        {:gap, latest_datetime_before, first_datetime_after}\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  def from_naive(%{calendar: calendar} = naive_datetime, time_zone, time_zone_database)\n      when calendar != Calendar.ISO do\n    # For non-ISO calendars, convert to ISO, create ISO DateTime, and then\n    # convert to original calendar\n    iso_result =\n      with {:ok, in_iso} <- NaiveDateTime.convert(naive_datetime, Calendar.ISO) do\n        from_naive(in_iso, time_zone, time_zone_database)\n      end\n\n    case iso_result do\n      {:ok, dt} ->\n        convert(dt, calendar)\n\n      {:ambiguous, dt1, dt2} ->\n        with {:ok, dt1converted} <- convert(dt1, calendar),\n             {:ok, dt2converted} <- convert(dt2, calendar),\n             do: {:ambiguous, dt1converted, dt2converted}\n\n      {:gap, dt1, dt2} ->\n        with {:ok, dt1converted} <- convert(dt1, calendar),\n             {:ok, dt2converted} <- convert(dt2, calendar),\n             do: {:gap, dt1converted, dt2converted}\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  defp from_naive_with_period(naive_datetime, time_zone, period) do\n    %{std_offset: std_offset, utc_offset: utc_offset, zone_abbr: zone_abbr} = period\n\n    %{\n      calendar: calendar,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      year: year,\n      month: month,\n      day: day\n    } = naive_datetime\n\n    %DateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      std_offset: std_offset,\n      utc_offset: utc_offset,\n      zone_abbr: zone_abbr,\n      time_zone: time_zone\n    }\n  end\n\n  @doc \"\"\"\n  Converts the given `NaiveDateTime` to `DateTime`.\n\n  It expects a time zone to put the NaiveDateTime in.\n  If the time zone is \"Etc/UTC\", it always succeeds. Otherwise,\n  the NaiveDateTime is checked against the time zone database\n  given as `time_zone_database`. See the \"Time zone database\"\n  section in the module documentation.\n\n  ## Examples\n\n      iex> DateTime.from_naive!(~N[2016-05-24 13:26:08.003], \"Etc/UTC\")\n      ~U[2016-05-24 13:26:08.003Z]\n\n      iex> DateTime.from_naive!(~N[2018-05-24 13:26:08.003], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      #DateTime<2018-05-24 13:26:08.003+02:00 CEST Europe/Copenhagen>\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec from_naive!(\n          NaiveDateTime.t(),\n          Calendar.time_zone(),\n          Calendar.time_zone_database()\n        ) :: t\n  def from_naive!(\n        naive_datetime,\n        time_zone,\n        time_zone_database \\\\ Calendar.get_time_zone_database()\n      ) do\n    case from_naive(naive_datetime, time_zone, time_zone_database) do\n      {:ok, datetime} ->\n        datetime\n\n      {:ambiguous, dt1, dt2} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(naive_datetime)} to datetime because such \" <>\n                \"instant is ambiguous in time zone #{time_zone} as there is an overlap \" <>\n                \"between #{inspect(dt1)} and #{inspect(dt2)}\"\n\n      {:gap, dt1, dt2} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(naive_datetime)} to datetime because such \" <>\n                \"instant does not exist in time zone #{time_zone} as there is a gap \" <>\n                \"between #{inspect(dt1)} and #{inspect(dt2)}\"\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(naive_datetime)} to datetime, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Changes the time zone of a `DateTime`.\n\n  Returns a `DateTime` for the same point in time, but instead at\n  the time zone provided. It assumes that `DateTime` is valid and\n  exists in the given time zone and calendar.\n\n  By default, it uses the default time zone database returned by\n  `Calendar.get_time_zone_database/0`, which defaults to\n  `Calendar.UTCOnlyTimeZoneDatabase` which only handles \"Etc/UTC\" datetimes.\n  Other time zone databases can be passed as argument or set globally.\n  See the \"Time zone database\" section in the module docs.\n\n  ## Examples\n\n      iex> {:ok, pacific_datetime} = DateTime.shift_zone(~U[2018-07-16 10:00:00Z], \"America/Los_Angeles\", FakeTimeZoneDatabase)\n      iex> pacific_datetime\n      #DateTime<2018-07-16 03:00:00-07:00 PDT America/Los_Angeles>\n\n      iex> DateTime.shift_zone(~U[2018-07-16 10:00:00Z], \"bad timezone\", FakeTimeZoneDatabase)\n      {:error, :time_zone_not_found}\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec shift_zone(t, Calendar.time_zone(), Calendar.time_zone_database()) ::\n          {:ok, t} | {:error, :time_zone_not_found | :utc_only_time_zone_database}\n  def shift_zone(datetime, time_zone, time_zone_database \\\\ Calendar.get_time_zone_database())\n\n  def shift_zone(%{time_zone: time_zone} = datetime, time_zone, _) do\n    {:ok, datetime}\n  end\n\n  def shift_zone(datetime, time_zone, time_zone_database) do\n    %{\n      std_offset: std_offset,\n      utc_offset: utc_offset,\n      calendar: calendar,\n      microsecond: {_, precision}\n    } = datetime\n\n    datetime\n    |> to_iso_days()\n    |> apply_tz_offset(utc_offset + std_offset)\n    |> shift_zone_for_iso_days_utc(calendar, precision, time_zone, time_zone_database)\n  end\n\n  defp shift_zone_for_iso_days_utc(iso_days_utc, calendar, precision, time_zone, time_zone_db) do\n    case time_zone_db.time_zone_period_from_utc_iso_days(iso_days_utc, time_zone) do\n      {:ok, %{std_offset: std_offset, utc_offset: utc_offset, zone_abbr: zone_abbr}} ->\n        {year, month, day, hour, minute, second, {microsecond_without_precision, _}} =\n          iso_days_utc\n          |> apply_tz_offset(-(utc_offset + std_offset))\n          |> calendar.naive_datetime_from_iso_days()\n\n        datetime = %DateTime{\n          calendar: calendar,\n          year: year,\n          month: month,\n          day: day,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: {microsecond_without_precision, precision},\n          std_offset: std_offset,\n          utc_offset: utc_offset,\n          zone_abbr: zone_abbr,\n          time_zone: time_zone\n        }\n\n        {:ok, datetime}\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  @doc \"\"\"\n  Changes the time zone of a `DateTime` or raises on errors.\n\n  See `shift_zone/3` for more information.\n\n  ## Examples\n\n      iex> DateTime.shift_zone!(~U[2018-07-16 10:00:00Z], \"America/Los_Angeles\", FakeTimeZoneDatabase)\n      #DateTime<2018-07-16 03:00:00-07:00 PDT America/Los_Angeles>\n\n      iex> DateTime.shift_zone!(~U[2018-07-16 10:00:00Z], \"bad timezone\", FakeTimeZoneDatabase)\n      ** (ArgumentError) cannot shift ~U[2018-07-16 10:00:00Z] to \"bad timezone\" time zone, reason: :time_zone_not_found\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec shift_zone!(t, Calendar.time_zone(), Calendar.time_zone_database()) :: t\n  def shift_zone!(datetime, time_zone, time_zone_database \\\\ Calendar.get_time_zone_database()) do\n    case shift_zone(datetime, time_zone, time_zone_database) do\n      {:ok, datetime} ->\n        datetime\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot shift #{inspect(datetime)} to #{inspect(time_zone)} time zone\" <>\n                \", reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Returns the current datetime in the provided time zone.\n\n  By default, it uses the default time_zone returned by\n  `Calendar.get_time_zone_database/0`, which defaults to\n  `Calendar.UTCOnlyTimeZoneDatabase` which only handles \"Etc/UTC\" datetimes.\n  Other time zone databases can be passed as argument or set globally.\n  See the \"Time zone database\" section in the module docs.\n\n  ## Examples\n\n      iex> {:ok, datetime} = DateTime.now(\"Etc/UTC\")\n      iex> datetime.time_zone\n      \"Etc/UTC\"\n\n      iex> DateTime.now(\"Europe/Copenhagen\")\n      {:error, :utc_only_time_zone_database}\n\n      iex> DateTime.now(\"bad timezone\", FakeTimeZoneDatabase)\n      {:error, :time_zone_not_found}\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec now(Calendar.time_zone(), Calendar.time_zone_database()) ::\n          {:ok, t} | {:error, :time_zone_not_found | :utc_only_time_zone_database}\n  def now(time_zone, time_zone_database \\\\ Calendar.get_time_zone_database())\n\n  def now(\"Etc/UTC\", _) do\n    {:ok, utc_now()}\n  end\n\n  def now(time_zone, time_zone_database) do\n    shift_zone(utc_now(), time_zone, time_zone_database)\n  end\n\n  @doc \"\"\"\n  Returns the current datetime in the provided time zone or raises on errors\n\n  See `now/2` for more information.\n\n  ## Examples\n\n      iex> datetime = DateTime.now!(\"Etc/UTC\")\n      iex> datetime.time_zone\n      \"Etc/UTC\"\n\n      iex> DateTime.now!(\"Europe/Copenhagen\")\n      ** (ArgumentError) cannot get current datetime in \"Europe/Copenhagen\" time zone, reason: :utc_only_time_zone_database\n\n      iex> DateTime.now!(\"bad timezone\", FakeTimeZoneDatabase)\n      ** (ArgumentError) cannot get current datetime in \"bad timezone\" time zone, reason: :time_zone_not_found\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec now!(Calendar.time_zone(), Calendar.time_zone_database()) :: t\n  def now!(time_zone, time_zone_database \\\\ Calendar.get_time_zone_database()) do\n    case now(time_zone, time_zone_database) do\n      {:ok, datetime} ->\n        datetime\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot get current datetime in #{inspect(time_zone)} time zone, reason: \" <>\n                inspect(reason)\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given `datetime` to Unix time.\n\n  The `datetime` is expected to be using the ISO calendar\n  with a year greater than or equal to 0.\n\n  It will return the integer with the given unit, according\n  to `System.convert_time_unit/3`. If the given unit is different\n  than microseconds, the returned value will be either truncated\n  or padded accordingly.\n\n  ## Examples\n\n      iex> 1_464_096_368 |> DateTime.from_unix!() |> DateTime.to_unix()\n      1464096368\n\n      iex> dt = %DateTime{calendar: Calendar.ISO, day: 20, hour: 18, microsecond: {273806, 6},\n      ...>                minute: 58, month: 11, second: 19, time_zone: \"America/Montevideo\",\n      ...>                utc_offset: -10800, std_offset: 3600, year: 2014, zone_abbr: \"UYST\"}\n      iex> DateTime.to_unix(dt)\n      1416517099\n\n      iex> flamel = %DateTime{calendar: Calendar.ISO, day: 22, hour: 8, microsecond: {527771, 6},\n      ...>                minute: 2, month: 3, second: 25, std_offset: 0, time_zone: \"Etc/UTC\",\n      ...>                utc_offset: 0, year: 1418, zone_abbr: \"UTC\"}\n      iex> DateTime.to_unix(flamel)\n      -17412508655\n\n  \"\"\"\n  @spec to_unix(Calendar.datetime(), :native | System.time_unit()) :: integer\n  def to_unix(datetime, unit \\\\ :second)\n\n  def to_unix(%{utc_offset: utc_offset, std_offset: std_offset} = datetime, unit) do\n    {days, fraction} = to_iso_days(datetime)\n    unix_units = Calendar.ISO.iso_days_to_unit({days - @unix_days, fraction}, unit)\n    offset_units = System.convert_time_unit(utc_offset + std_offset, :second, unit)\n    unix_units - offset_units\n  end\n\n  @doc \"\"\"\n  Converts the given `datetime` into a `NaiveDateTime`.\n\n  Because `NaiveDateTime` does not hold time zone information,\n  any time zone related data will be lost during the conversion.\n\n  ## Examples\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 1},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> DateTime.to_naive(dt)\n      ~N[2000-02-29 23:00:07.0]\n\n  \"\"\"\n  @spec to_naive(Calendar.datetime()) :: NaiveDateTime.t()\n  def to_naive(datetime)\n\n  def to_naive(%{\n        calendar: calendar,\n        year: year,\n        month: month,\n        day: day,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        time_zone: _\n      }) do\n    %NaiveDateTime{\n      year: year,\n      month: month,\n      day: day,\n      calendar: calendar,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    }\n  end\n\n  @doc \"\"\"\n  Converts a `DateTime` into a `Date`.\n\n  Because `Date` does not hold time nor time zone information,\n  data will be lost during the conversion.\n\n  ## Examples\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> DateTime.to_date(dt)\n      ~D[2000-02-29]\n\n  \"\"\"\n  @spec to_date(Calendar.datetime()) :: Date.t()\n  def to_date(datetime)\n\n  def to_date(%{\n        year: year,\n        month: month,\n        day: day,\n        calendar: calendar,\n        hour: _,\n        minute: _,\n        second: _,\n        microsecond: _,\n        time_zone: _\n      }) do\n    %Date{year: year, month: month, day: day, calendar: calendar}\n  end\n\n  @doc \"\"\"\n  Converts a `DateTime` into `Time`.\n\n  Because `Time` does not hold date nor time zone information,\n  data will be lost during the conversion.\n\n  ## Examples\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 1},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> DateTime.to_time(dt)\n      ~T[23:00:07.0]\n\n  \"\"\"\n  @spec to_time(Calendar.datetime()) :: Time.t()\n  def to_time(datetime)\n\n  def to_time(%{\n        year: _,\n        month: _,\n        day: _,\n        calendar: calendar,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        time_zone: _\n      }) do\n    %Time{\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      calendar: calendar\n    }\n  end\n\n  @doc \"\"\"\n  Converts the given datetime to\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601) format.\n\n  By default, `DateTime.to_iso8601/2` returns datetimes formatted in the \"extended\"\n  format, for human readability. It also supports the \"basic\" format through passing the `:basic` option.\n\n  You can also optionally specify an offset for the formatted string.\n  If none is given, the one in the given `datetime` is used.\n\n  Only supports converting datetimes which are in the ISO calendar.\n  If another calendar is given, it is automatically converted to ISO.\n  It raises if not possible.\n\n  WARNING: the ISO 8601 datetime format does not contain the time zone nor\n  its abbreviation, which means information is lost when converting to such\n  format.\n\n  ## Examples\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> DateTime.to_iso8601(dt)\n      \"2000-02-29T23:00:07+01:00\"\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"UTC\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 0, std_offset: 0, time_zone: \"Etc/UTC\"}\n      iex> DateTime.to_iso8601(dt)\n      \"2000-02-29T23:00:07Z\"\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> DateTime.to_iso8601(dt, :extended)\n      \"2000-02-29T23:00:07-04:00\"\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> DateTime.to_iso8601(dt, :basic)\n      \"20000229T230007-0400\"\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> DateTime.to_iso8601(dt, :extended, 3600)\n      \"2000-03-01T04:00:07+01:00\"\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> DateTime.to_iso8601(dt, :extended, 0)\n      \"2000-03-01T03:00:07+00:00\"\n\n      iex> dt = %DateTime{year: 2000, month: 3, day: 01, zone_abbr: \"UTC\",\n      ...>                hour: 03, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 0, std_offset: 0, time_zone: \"Etc/UTC\"}\n      iex> DateTime.to_iso8601(dt, :extended, 0)\n      \"2000-03-01T03:00:07Z\"\n\n      iex> {:ok, dt, offset} = DateTime.from_iso8601(\"2000-03-01T03:00:07Z\")\n      iex> \"2000-03-01T03:00:07Z\" = DateTime.to_iso8601(dt, :extended, offset)\n  \"\"\"\n  @spec to_iso8601(Calendar.datetime(), :basic | :extended, nil | integer()) :: String.t()\n  def to_iso8601(datetime, format \\\\ :extended, offset \\\\ nil)\n\n  def to_iso8601(%{calendar: Calendar.ISO} = datetime, format, offset)\n      when format in [:extended, :basic] do\n    datetime\n    |> to_iso8601_iodata(format, offset)\n    |> IO.iodata_to_binary()\n  end\n\n  def to_iso8601(%{calendar: _} = datetime, format, offset)\n      when format in [:extended, :basic] do\n    datetime\n    |> convert!(Calendar.ISO)\n    |> to_iso8601(format, offset)\n  end\n\n  defp to_iso8601_iodata(datetime, format, nil) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      time_zone: time_zone,\n      utc_offset: utc_offset,\n      std_offset: std_offset\n    } = datetime\n\n    [\n      datetime_to_iodata(year, month, day, hour, minute, second, microsecond, format),\n      Calendar.ISO.offset_to_iodata(utc_offset, std_offset, time_zone, format)\n    ]\n  end\n\n  defp to_iso8601_iodata(\n         %{microsecond: {_, precision}, time_zone: \"Etc/UTC\"} = datetime,\n         format,\n         0\n       ) do\n    {year, month, day, hour, minute, second, {microsecond, _}} = shift_by_offset(datetime, 0)\n\n    [\n      datetime_to_iodata(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        {microsecond, precision},\n        format\n      ),\n      ?Z\n    ]\n  end\n\n  defp to_iso8601_iodata(datetime, format, offset) do\n    {_, precision} = datetime.microsecond\n    {year, month, day, hour, minute, second, {microsecond, _}} = shift_by_offset(datetime, offset)\n\n    [\n      datetime_to_iodata(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        {microsecond, precision},\n        format\n      ),\n      Calendar.ISO.offset_to_iodata(offset, 0, nil, format)\n    ]\n  end\n\n  defp shift_by_offset(%{calendar: calendar} = datetime, offset) do\n    total_offset = datetime.utc_offset + datetime.std_offset\n\n    datetime\n    |> to_iso_days()\n    # Subtract total original offset in order to get UTC and add the new offset\n    |> Calendar.ISO.add_day_fraction_to_iso_days(offset - total_offset, 86400)\n    |> calendar.naive_datetime_from_iso_days()\n  end\n\n  defp datetime_to_iodata(year, month, day, hour, minute, second, microsecond, format) do\n    [\n      Calendar.ISO.date_to_iodata(year, month, day, format),\n      ?T,\n      Calendar.ISO.time_to_iodata(hour, minute, second, microsecond, format)\n    ]\n  end\n\n  @doc \"\"\"\n  Parses the extended \"Date and time of day\" format described by\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  Since ISO 8601 does not include the proper time zone, the given\n  string will be converted to UTC and its offset in seconds will be\n  returned as part of this function. Therefore offset information\n  must be present in the string.\n\n  As specified in the standard, the separator \"T\" may be omitted if\n  desired as there is no ambiguity within this function.\n\n  Note leap seconds are not supported by the built-in Calendar.ISO.\n\n  ## Examples\n\n      iex> {:ok, datetime, 0} = DateTime.from_iso8601(\"2015-01-23T23:50:07Z\")\n      iex> datetime\n      ~U[2015-01-23 23:50:07Z]\n\n      iex> {:ok, datetime, 9000} = DateTime.from_iso8601(\"2015-01-23T23:50:07.123+02:30\")\n      iex> datetime\n      ~U[2015-01-23 21:20:07.123Z]\n\n      iex> {:ok, datetime, 9000} = DateTime.from_iso8601(\"2015-01-23T23:50:07,123+02:30\")\n      iex> datetime\n      ~U[2015-01-23 21:20:07.123Z]\n\n      iex> {:ok, datetime, 0} = DateTime.from_iso8601(\"-2015-01-23T23:50:07Z\")\n      iex> datetime\n      ~U[-2015-01-23 23:50:07Z]\n\n      iex> {:ok, datetime, 9000} = DateTime.from_iso8601(\"-2015-01-23T23:50:07,123+02:30\")\n      iex> datetime\n      ~U[-2015-01-23 21:20:07.123Z]\n\n      iex> {:ok, datetime, 9000} = DateTime.from_iso8601(\"20150123T235007.123+0230\", :basic)\n      iex> datetime\n      ~U[2015-01-23 21:20:07.123Z]\n\n      iex> DateTime.from_iso8601(\"2015-01-23P23:50:07\")\n      {:error, :invalid_format}\n      iex> DateTime.from_iso8601(\"2015-01-23T23:50:07\")\n      {:error, :missing_offset}\n      iex> DateTime.from_iso8601(\"2015-01-23 23:50:61\")\n      {:error, :invalid_time}\n      iex> DateTime.from_iso8601(\"2015-01-32 23:50:07\")\n      {:error, :invalid_date}\n      iex> DateTime.from_iso8601(\"2015-01-23T23:50:07.123-00:00\")\n      {:error, :invalid_format}\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec from_iso8601(String.t(), Calendar.calendar() | :extended | :basic) ::\n          {:ok, t, Calendar.utc_offset()} | {:error, atom}\n  def from_iso8601(string, format_or_calendar \\\\ Calendar.ISO)\n\n  def from_iso8601(string, format) when format in [:basic, :extended] do\n    from_iso8601(string, Calendar.ISO, format)\n  end\n\n  def from_iso8601(string, calendar) when is_atom(calendar) do\n    from_iso8601(string, calendar, :extended)\n  end\n\n  @doc \"\"\"\n  Converts from ISO8601 specifying both a calendar and a mode.\n\n  See `from_iso8601/2` for more information.\n\n  ## Examples\n\n      iex> {:ok, datetime, 9000} = DateTime.from_iso8601(\"2015-01-23T23:50:07,123+02:30\", Calendar.ISO, :extended)\n      iex> datetime\n      ~U[2015-01-23 21:20:07.123Z]\n\n      iex> {:ok, datetime, 9000} = DateTime.from_iso8601(\"20150123T235007.123+0230\", Calendar.ISO, :basic)\n      iex> datetime\n      ~U[2015-01-23 21:20:07.123Z]\n\n  \"\"\"\n  @spec from_iso8601(String.t(), Calendar.calendar(), :extended | :basic) ::\n          {:ok, t, Calendar.utc_offset()} | {:error, atom}\n  def from_iso8601(string, calendar, format) do\n    with {:ok, {year, month, day, hour, minute, second, microsecond}, offset} <-\n           Calendar.ISO.parse_utc_datetime(string, format) do\n      datetime = %DateTime{\n        year: year,\n        month: month,\n        day: day,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        std_offset: 0,\n        utc_offset: 0,\n        zone_abbr: \"UTC\",\n        time_zone: \"Etc/UTC\"\n      }\n\n      with {:ok, converted} <- convert(datetime, calendar) do\n        {:ok, converted, offset}\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Converts a number of gregorian seconds to a `DateTime` struct.\n\n  The returned `DateTime` will have `UTC` timezone, if you want other timezone, please use\n  `DateTime.shift_zone/3`.\n\n  ## Examples\n\n      iex> DateTime.from_gregorian_seconds(1)\n      ~U[0000-01-01 00:00:01Z]\n      iex> DateTime.from_gregorian_seconds(63_755_511_991, {5000, 3})\n      ~U[2020-05-01 00:26:31.005Z]\n      iex> DateTime.from_gregorian_seconds(-1)\n      ~U[-0001-12-31 23:59:59Z]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec from_gregorian_seconds(integer(), Calendar.microsecond(), Calendar.calendar()) :: t\n  def from_gregorian_seconds(\n        seconds,\n        {microsecond, precision} \\\\ {0, 0},\n        calendar \\\\ Calendar.ISO\n      )\n      when is_integer(seconds) do\n    iso_days = Calendar.ISO.gregorian_seconds_to_iso_days(seconds, microsecond)\n\n    {year, month, day, hour, minute, second, {microsecond, _}} =\n      calendar.naive_datetime_from_iso_days(iso_days)\n\n    %DateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: {microsecond, precision},\n      std_offset: 0,\n      utc_offset: 0,\n      zone_abbr: \"UTC\",\n      time_zone: \"Etc/UTC\"\n    }\n  end\n\n  @doc \"\"\"\n  Converts a `DateTime` struct to a number of gregorian seconds and microseconds.\n\n  ## Examples\n\n      iex> dt = %DateTime{year: 0000, month: 1, day: 1, zone_abbr: \"UTC\",\n      ...>                hour: 0, minute: 0, second: 1, microsecond: {0, 0},\n      ...>                utc_offset: 0, std_offset: 0, time_zone: \"Etc/UTC\"}\n      iex> DateTime.to_gregorian_seconds(dt)\n      {1, 0}\n\n      iex> dt = %DateTime{year: 2020, month: 5, day: 1, zone_abbr: \"UTC\",\n      ...>                hour: 0, minute: 26, second: 31, microsecond: {5000, 0},\n      ...>                utc_offset: 0, std_offset: 0, time_zone: \"Etc/UTC\"}\n      iex> DateTime.to_gregorian_seconds(dt)\n      {63_755_511_991, 5000}\n\n      iex> dt = %DateTime{year: 2020, month: 5, day: 1, zone_abbr: \"CET\",\n      ...>                hour: 1, minute: 26, second: 31, microsecond: {5000, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> DateTime.to_gregorian_seconds(dt)\n      {63_755_511_991, 5000}\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec to_gregorian_seconds(Calendar.datetime()) :: {integer(), non_neg_integer()}\n  def to_gregorian_seconds(\n        %{\n          std_offset: std_offset,\n          utc_offset: utc_offset,\n          microsecond: {microsecond, _}\n        } = datetime\n      ) do\n    {days, day_fraction} =\n      datetime\n      |> to_iso_days()\n      |> apply_tz_offset(utc_offset + std_offset)\n\n    seconds_in_day = seconds_from_day_fraction(day_fraction)\n    {days * @seconds_per_day + seconds_in_day, microsecond}\n  end\n\n  @doc \"\"\"\n  Converts the given `datetime` to a string according to its calendar.\n\n  Unfortunately, there is no standard that specifies rendering of a\n  datetime with its complete time zone information, so Elixir uses a\n  custom (but relatively common) representation which appends the time\n  zone abbreviation and full name to the datetime.\n\n  ## Examples\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> DateTime.to_string(dt)\n      \"2000-02-29 23:00:07+01:00 CET Europe/Warsaw\"\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"UTC\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 0, std_offset: 0, time_zone: \"Etc/UTC\"}\n      iex> DateTime.to_string(dt)\n      \"2000-02-29 23:00:07Z\"\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> DateTime.to_string(dt)\n      \"2000-02-29 23:00:07-04:00 AMT America/Manaus\"\n\n      iex> dt = %DateTime{year: -100, month: 12, day: 19, zone_abbr: \"CET\",\n      ...>                hour: 3, minute: 20, second: 31, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Stockholm\"}\n      iex> DateTime.to_string(dt)\n      \"-0100-12-19 03:20:31+01:00 CET Europe/Stockholm\"\n\n  \"\"\"\n  @spec to_string(Calendar.datetime()) :: String.t()\n  def to_string(%{calendar: calendar} = datetime) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      time_zone: time_zone,\n      zone_abbr: zone_abbr,\n      utc_offset: utc_offset,\n      std_offset: std_offset\n    } = datetime\n\n    calendar.datetime_to_string(\n      year,\n      month,\n      day,\n      hour,\n      minute,\n      second,\n      microsecond,\n      time_zone,\n      zone_abbr,\n      utc_offset,\n      std_offset\n    )\n  end\n\n  @doc \"\"\"\n  Compares two datetime structs.\n\n  Returns `:gt` if the first datetime is later than the second\n  and `:lt` for vice versa. If the two datetimes are equal\n  `:eq` is returned.\n\n  Note that both UTC and Standard offsets will be taken into\n  account when comparison is done.\n\n  ## Examples\n\n      iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                 utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> dt2 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                 utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> DateTime.compare(dt1, dt2)\n      :gt\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec compare(Calendar.datetime(), Calendar.datetime()) :: :lt | :eq | :gt\n  def compare(\n        %{utc_offset: utc_offset1, std_offset: std_offset1} = datetime1,\n        %{utc_offset: utc_offset2, std_offset: std_offset2} = datetime2\n      ) do\n    {days1, {parts1, ppd1}} =\n      datetime1\n      |> to_iso_days()\n      |> apply_tz_offset(utc_offset1 + std_offset1)\n\n    {days2, {parts2, ppd2}} =\n      datetime2\n      |> to_iso_days()\n      |> apply_tz_offset(utc_offset2 + std_offset2)\n\n    # Ensure fraction tuples have same denominator.\n    first = {days1, parts1 * ppd2}\n    second = {days2, parts2 * ppd1}\n\n    cond do\n      first > second -> :gt\n      first < second -> :lt\n      true -> :eq\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if the first datetime is strictly earlier than the second.\n\n  ## Examples\n\n      iex> DateTime.before?(~U[2021-01-01 11:00:00Z], ~U[2022-02-02 11:00:00Z])\n      true\n      iex> DateTime.before?(~U[2021-01-01 11:00:00Z], ~U[2021-01-01 11:00:00Z])\n      false\n      iex> DateTime.before?(~U[2022-02-02 11:00:00Z], ~U[2021-01-01 11:00:00Z])\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec before?(Calendar.datetime(), Calendar.datetime()) :: boolean()\n  def before?(datetime1, datetime2) do\n    compare(datetime1, datetime2) == :lt\n  end\n\n  @doc \"\"\"\n  Returns `true` if the first datetime is strictly later than the second.\n\n  ## Examples\n\n      iex> DateTime.after?(~U[2022-02-02 11:00:00Z], ~U[2021-01-01 11:00:00Z])\n      true\n      iex> DateTime.after?(~U[2021-01-01 11:00:00Z], ~U[2021-01-01 11:00:00Z])\n      false\n      iex> DateTime.after?(~U[2021-01-01 11:00:00Z], ~U[2022-02-02 11:00:00Z])\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec after?(Calendar.datetime(), Calendar.datetime()) :: boolean()\n  def after?(datetime1, datetime2) do\n    compare(datetime1, datetime2) == :gt\n  end\n\n  @doc \"\"\"\n  Subtracts `datetime2` from `datetime1`.\n\n  The answer can be returned in any `:day`, `:hour`, `:minute`, or any `unit`\n  available from `t:System.time_unit/0`. The unit is measured according to\n  `Calendar.ISO` and defaults to `:second`.\n\n  Fractional results are not supported and are truncated.\n\n  ## Examples\n\n      iex> DateTime.diff(~U[2024-01-15 10:00:10Z], ~U[2024-01-15 10:00:00Z])\n      10\n\n  This function also considers timezone offsets:\n\n      iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                 utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> dt2 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                 utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> DateTime.diff(dt1, dt2)\n      18000\n      iex> DateTime.diff(dt2, dt1)\n      -18000\n      iex> DateTime.diff(dt1, dt2, :hour)\n      5\n      iex> DateTime.diff(dt2, dt1, :hour)\n      -5\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec diff(\n          Calendar.datetime(),\n          Calendar.datetime(),\n          :day | :hour | :minute | System.time_unit()\n        ) :: integer()\n  def diff(datetime1, datetime2, unit \\\\ :second)\n\n  def diff(datetime1, datetime2, :day) do\n    diff(datetime1, datetime2, :second) |> div(86400)\n  end\n\n  def diff(datetime1, datetime2, :hour) do\n    diff(datetime1, datetime2, :second) |> div(3600)\n  end\n\n  def diff(datetime1, datetime2, :minute) do\n    diff(datetime1, datetime2, :second) |> div(60)\n  end\n\n  def diff(\n        %{utc_offset: utc_offset1, std_offset: std_offset1} = datetime1,\n        %{utc_offset: utc_offset2, std_offset: std_offset2} = datetime2,\n        unit\n      ) do\n    if not is_integer(unit) and\n         unit not in ~w(second millisecond microsecond nanosecond)a do\n      raise ArgumentError,\n            \"unsupported time unit. Expected :day, :hour, :minute, :second, :millisecond, :microsecond, :nanosecond, or a positive integer, got #{inspect(unit)}\"\n    end\n\n    naive_diff =\n      (datetime1 |> to_iso_days() |> Calendar.ISO.iso_days_to_unit(:microsecond)) -\n        (datetime2 |> to_iso_days() |> Calendar.ISO.iso_days_to_unit(:microsecond))\n\n    offset_diff = utc_offset2 + std_offset2 - (utc_offset1 + std_offset1)\n\n    System.convert_time_unit(naive_diff, :microsecond, unit) +\n      System.convert_time_unit(offset_diff, :second, unit)\n  end\n\n  @doc \"\"\"\n  Adds a specified amount of time to a `DateTime`.\n\n  > #### Prefer `shift/2` {: .info}\n  >\n  > Prefer `shift/2` over `add/3`, as it offers a more ergonomic API.\n  >\n  > `add/3` provides a lower-level API which only supports fixed units\n  > such as `:hour` and `:second`, but not `:month` (as the exact length\n  > of a month depends on the current month). `add/3` always considers\n  > the unit to be computed according to the `Calendar.ISO`.\n\n  Accepts an `amount_to_add` in any `unit`. `unit` can be `:day`,\n  `:hour`, `:minute`, `:second` or any subsecond precision from\n  `t:System.time_unit/0` for convenience but ultimately they are\n  all converted to microseconds. Negative values will move backwards\n  in time and the default precision is `:second`.\n\n  This function relies on a contiguous representation of time,\n  ignoring timezone changes. For example, if you add one day when there\n  are summer time/daylight saving time changes, it will also change the\n  time forward or backward by one hour, so the elapsed time is precisely\n  24 hours. Similarly, adding just a few seconds to a datetime just before\n  \"spring forward\" can cause wall time to increase by more than an hour.\n\n  While this means this function is precise in terms of elapsed time,\n  its result may be confusing in certain use cases. For example, if a\n  user requests a meeting to happen every day at 15:00 and you use this\n  function to compute all future meetings by adding day after day, this\n  function may change the meeting time to 14:00 or 16:00 if there are\n  changes to the current timezone.\n\n  In case you don't want these changes to happen automatically or you\n  want to surface time zone conflicts to the user, you can add to\n  the datetime as a naive datetime and then use `from_naive/2`:\n\n      dt |> NaiveDateTime.add(1, :day) |> DateTime.from_naive(dt.time_zone)\n\n  The above will surface time jumps and ambiguous datetimes, allowing you\n  to deal with them accordingly.\n\n  ## Examples\n\n      iex> dt = DateTime.from_naive!(~N[2018-11-15 10:00:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> dt |> DateTime.add(3600, :second, FakeTimeZoneDatabase)\n      #DateTime<2018-11-15 11:00:00+01:00 CET Europe/Copenhagen>\n\n      iex> DateTime.add(~U[2018-11-15 10:00:00Z], 3600, :second)\n      ~U[2018-11-15 11:00:00Z]\n\n  When adding 3 seconds just before \"spring forward\" we go from 1:59:59 to 3:00:02:\n\n      iex> dt = DateTime.from_naive!(~N[2019-03-31 01:59:59.123], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> dt |> DateTime.add(3, :second, FakeTimeZoneDatabase)\n      #DateTime<2019-03-31 03:00:02.123+02:00 CEST Europe/Copenhagen>\n\n  When adding 1 day during \"spring forward\", the hour also changes:\n\n      iex> dt = DateTime.from_naive!(~N[2019-03-31 01:00:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      iex> dt |> DateTime.add(1, :day, FakeTimeZoneDatabase)\n      #DateTime<2019-04-01 02:00:00+02:00 CEST Europe/Copenhagen>\n\n  This operation merges the precision of the naive date time with the given unit:\n\n      iex> result = DateTime.add(~U[2014-10-02 00:29:10Z], 21, :millisecond)\n      ~U[2014-10-02 00:29:10.021Z]\n      iex> result.microsecond\n      {21000, 3}\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec add(\n          Calendar.datetime(),\n          integer,\n          :day | :hour | :minute | System.time_unit(),\n          Calendar.time_zone_database()\n        ) ::\n          t()\n  def add(\n        datetime,\n        amount_to_add,\n        unit \\\\ :second,\n        time_zone_database \\\\ Calendar.get_time_zone_database()\n      )\n\n  def add(datetime, amount_to_add, :day, time_zone_database) when is_integer(amount_to_add) do\n    add(datetime, amount_to_add * 86400, :second, time_zone_database)\n  end\n\n  def add(datetime, amount_to_add, :hour, time_zone_database) when is_integer(amount_to_add) do\n    add(datetime, amount_to_add * 3600, :second, time_zone_database)\n  end\n\n  def add(datetime, amount_to_add, :minute, time_zone_database) when is_integer(amount_to_add) do\n    add(datetime, amount_to_add * 60, :second, time_zone_database)\n  end\n\n  def add(%{calendar: calendar} = datetime, amount_to_add, unit, time_zone_database)\n      when is_integer(amount_to_add) do\n    %{\n      microsecond: {_, precision},\n      time_zone: time_zone,\n      utc_offset: utc_offset,\n      std_offset: std_offset\n    } = datetime\n\n    if not is_integer(unit) and unit not in ~w(second millisecond microsecond nanosecond)a do\n      raise ArgumentError,\n            \"unsupported time unit. Expected :day, :hour, :minute, :second, :millisecond, :microsecond, :nanosecond, or a positive integer, got #{inspect(unit)}\"\n    end\n\n    precision = max(Calendar.ISO.time_unit_to_precision(unit), precision)\n\n    result =\n      datetime\n      |> to_iso_days()\n      |> Calendar.ISO.shift_time_unit(amount_to_add, unit)\n      |> apply_tz_offset(utc_offset + std_offset)\n      |> shift_zone_for_iso_days_utc(calendar, precision, time_zone, time_zone_database)\n\n    case result do\n      {:ok, result_datetime} ->\n        result_datetime\n\n      {:error, error} ->\n        raise ArgumentError,\n              \"cannot add #{amount_to_add} #{unit} to #{inspect(datetime)} (with time zone \" <>\n                \"database #{inspect(time_zone_database)}), reason: #{inspect(error)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Shifts given `datetime` by `duration` according to its calendar.\n\n  Allowed units are: `:year`, `:month`, `:week`, `:day`, `:hour`, `:minute`, `:second`, `:microsecond`.\n\n  This operation is equivalent to shifting the datetime wall clock\n  (in other words, the value as someone in that timezone would see\n  on their watch), then applying the time zone offset to convert it\n  to UTC, and finally computing the new timezone in case of shifts.\n  This ensures `shift/3` always returns a valid datetime.\n\n  Consequently, time zones that observe \"Daylight Saving Time\"\n  or other changes, across summer/winter time will add/remove hours\n  from the resulting datetime:\n\n      dt = DateTime.new!(~D[2019-03-31], ~T[01:00:00], \"Europe/Copenhagen\")\n      DateTime.shift(dt, hour: 1)\n      #=> #DateTime<2019-03-31 03:00:00+02:00 CEST Europe/Copenhagen>\n\n      dt = DateTime.new!(~D[2018-11-04], ~T[00:00:00], \"America/Los_Angeles\")\n      DateTime.shift(dt, hour: 2)\n      #=> #DateTime<2018-11-04 01:00:00-08:00 PST America/Los_Angeles>\n\n  Although the first example shows a difference of 2 hours when\n  comparing the wall clocks of the given datetime with the returned one,\n  due to the \"spring forward\" time jump, the actual elapsed time is\n  still exactly of 1 hour.\n\n  In case you don't want these changes to happen automatically or you\n  want to surface time zone conflicts to the user, you can shift\n  the datetime as a naive datetime and then use `from_naive/2`:\n\n      dt |> NaiveDateTime.shift(duration) |> DateTime.from_naive(dt.time_zone)\n\n  The above will surface time jumps and ambiguous datetimes, allowing you\n  to deal with them accordingly.\n\n  ## ISO calendar considerations\n\n  When using the default ISO calendar, durations are collapsed and\n  applied in the order of months, then seconds and microseconds:\n\n  * when shifting by 1 year and 2 months the date is actually shifted by 14 months\n  * weeks, days and smaller units are collapsed into seconds and microseconds\n\n  When shifting by month, days are rounded down to the nearest valid date.\n\n  ## Examples\n\n      iex> DateTime.shift(~U[2016-01-01 00:00:00Z], month: 2)\n      ~U[2016-03-01 00:00:00Z]\n      iex> DateTime.shift(~U[2016-01-01 00:00:00Z], year: 1, week: 4)\n      ~U[2017-01-29 00:00:00Z]\n      iex> DateTime.shift(~U[2016-01-01 00:00:00Z], minute: -25)\n      ~U[2015-12-31 23:35:00Z]\n      iex> DateTime.shift(~U[2016-01-01 00:00:00Z], minute: 5, microsecond: {500, 4})\n      ~U[2016-01-01 00:05:00.0005Z]\n\n      # leap years\n      iex> DateTime.shift(~U[2024-02-29 00:00:00Z], year: 1)\n      ~U[2025-02-28 00:00:00Z]\n      iex> DateTime.shift(~U[2024-02-29 00:00:00Z], year: 4)\n      ~U[2028-02-29 00:00:00Z]\n\n      # rounding down\n      iex> DateTime.shift(~U[2015-01-31 00:00:00Z], month: 1)\n      ~U[2015-02-28 00:00:00Z]\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec shift(Calendar.datetime(), Duration.duration(), Calendar.time_zone_database()) :: t\n  def shift(datetime, duration, time_zone_database \\\\ Calendar.get_time_zone_database())\n\n  def shift(%{calendar: calendar, time_zone: \"Etc/UTC\"} = datetime, duration, _time_zone_database) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    } = datetime\n\n    {year, month, day, hour, minute, second, microsecond} =\n      calendar.shift_naive_datetime(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        __duration__!(duration)\n      )\n\n    %DateTime{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      time_zone: \"Etc/UTC\",\n      zone_abbr: \"UTC\",\n      std_offset: 0,\n      utc_offset: 0\n    }\n  end\n\n  def shift(%{calendar: calendar} = datetime, duration, time_zone_database) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      std_offset: std_offset,\n      utc_offset: utc_offset,\n      time_zone: time_zone\n    } = datetime\n\n    {year, month, day, hour, minute, second, {_, precision} = microsecond} =\n      calendar.shift_naive_datetime(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        __duration__!(duration)\n      )\n\n    result =\n      calendar.naive_datetime_to_iso_days(year, month, day, hour, minute, second, microsecond)\n      |> apply_tz_offset(utc_offset + std_offset)\n      |> shift_zone_for_iso_days_utc(calendar, precision, time_zone, time_zone_database)\n\n    case result do\n      {:ok, result_datetime} ->\n        result_datetime\n\n      {:error, error} ->\n        raise ArgumentError,\n              \"cannot shift #{inspect(datetime)} to #{inspect(duration)} (with time zone \" <>\n                \"database #{inspect(time_zone_database)}), reason: #{inspect(error)}\"\n    end\n  end\n\n  @doc false\n  defdelegate __duration__!(params), to: Duration, as: :new!\n\n  @doc \"\"\"\n  Returns the given datetime with the microsecond field truncated to the given\n  precision (`:microsecond`, `:millisecond` or `:second`).\n\n  The given datetime is returned unchanged if it already has lower precision than\n  the given precision.\n\n  ## Examples\n\n      iex> dt1 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: \"CET\",\n      ...>                 hour: 11, minute: 45, second: 18, microsecond: {123456, 6},\n      ...>                 utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Paris\"}\n      iex> DateTime.truncate(dt1, :microsecond)\n      #DateTime<2017-11-07 11:45:18.123456+01:00 CET Europe/Paris>\n\n      iex> dt2 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: \"CET\",\n      ...>                 hour: 11, minute: 45, second: 18, microsecond: {123456, 6},\n      ...>                 utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Paris\"}\n      iex> DateTime.truncate(dt2, :millisecond)\n      #DateTime<2017-11-07 11:45:18.123+01:00 CET Europe/Paris>\n\n      iex> dt3 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: \"CET\",\n      ...>                 hour: 11, minute: 45, second: 18, microsecond: {123456, 6},\n      ...>                 utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Paris\"}\n      iex> DateTime.truncate(dt3, :second)\n      #DateTime<2017-11-07 11:45:18+01:00 CET Europe/Paris>\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec truncate(Calendar.datetime(), :microsecond | :millisecond | :second) :: t()\n  def truncate(%DateTime{microsecond: microsecond} = datetime, precision) do\n    %{datetime | microsecond: Calendar.truncate(microsecond, precision)}\n  end\n\n  def truncate(%{} = datetime_map, precision) do\n    truncate(from_map(datetime_map), precision)\n  end\n\n  @doc \"\"\"\n  Converts a given `datetime` from one calendar to another.\n\n  If it is not possible to convert unambiguously between the calendars\n  (see `Calendar.compatible_calendars?/2`), an `{:error, :incompatible_calendars}` tuple\n  is returned.\n\n  ## Examples\n\n  Imagine someone implements `Calendar.Holocene`, a calendar based on the\n  Gregorian calendar that adds exactly 10 000 years to the current Gregorian\n  year:\n\n      iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                 utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> DateTime.convert(dt1, Calendar.Holocene)\n      {:ok, %DateTime{calendar: Calendar.Holocene, day: 29, hour: 23,\n                      microsecond: {0, 0}, minute: 0, month: 2, second: 7, std_offset: 0,\n                      time_zone: \"America/Manaus\", utc_offset: -14400, year: 12000,\n                      zone_abbr: \"AMT\"}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec convert(Calendar.datetime(), Calendar.calendar()) ::\n          {:ok, t} | {:error, :incompatible_calendars}\n\n  def convert(%DateTime{calendar: calendar} = datetime, calendar) do\n    {:ok, datetime}\n  end\n\n  def convert(%{calendar: calendar} = datetime, calendar) do\n    {:ok, from_map(datetime)}\n  end\n\n  def convert(%{calendar: dt_calendar, microsecond: {_, precision}} = datetime, calendar) do\n    if Calendar.compatible_calendars?(dt_calendar, calendar) do\n      result_datetime =\n        datetime\n        |> to_iso_days()\n        |> from_iso_days(datetime, calendar, precision)\n\n      {:ok, result_datetime}\n    else\n      {:error, :incompatible_calendars}\n    end\n  end\n\n  @doc \"\"\"\n  Converts a given `datetime` from one calendar to another.\n\n  If it is not possible to convert unambiguously between the calendars\n  (see `Calendar.compatible_calendars?/2`), an ArgumentError is raised.\n\n  ## Examples\n\n  Imagine someone implements `Calendar.Holocene`, a calendar based on the\n  Gregorian calendar that adds exactly 10 000 years to the current Gregorian\n  year:\n\n      iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"AMT\",\n      ...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                 utc_offset: -14400, std_offset: 0, time_zone: \"America/Manaus\"}\n      iex> DateTime.convert!(dt1, Calendar.Holocene)\n      %DateTime{calendar: Calendar.Holocene, day: 29, hour: 23,\n                microsecond: {0, 0}, minute: 0, month: 2, second: 7, std_offset: 0,\n                time_zone: \"America/Manaus\", utc_offset: -14400, year: 12000,\n                zone_abbr: \"AMT\"}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec convert!(Calendar.datetime(), Calendar.calendar()) :: t\n  def convert!(datetime, calendar) do\n    case convert(datetime, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, :incompatible_calendars} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(datetime)} to target calendar #{inspect(calendar)}, \" <>\n                \"reason: #{inspect(datetime.calendar)} and #{inspect(calendar)} have different \" <>\n                \"day rollover moments, making this conversion ambiguous\"\n    end\n  end\n\n  # Keep it multiline for proper function clause errors.\n  defp to_iso_days(%{\n         calendar: calendar,\n         year: year,\n         month: month,\n         day: day,\n         hour: hour,\n         minute: minute,\n         second: second,\n         microsecond: microsecond\n       }) do\n    calendar.naive_datetime_to_iso_days(year, month, day, hour, minute, second, microsecond)\n  end\n\n  defp from_iso_days(iso_days, datetime, calendar, precision) do\n    %{time_zone: time_zone, zone_abbr: zone_abbr, utc_offset: utc_offset, std_offset: std_offset} =\n      datetime\n\n    {year, month, day, hour, minute, second, {microsecond, _}} =\n      calendar.naive_datetime_from_iso_days(iso_days)\n\n    %DateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: {microsecond, precision},\n      time_zone: time_zone,\n      zone_abbr: zone_abbr,\n      utc_offset: utc_offset,\n      std_offset: std_offset\n    }\n  end\n\n  defp apply_tz_offset(iso_days, 0) do\n    iso_days\n  end\n\n  defp apply_tz_offset(iso_days, offset) do\n    Calendar.ISO.add_day_fraction_to_iso_days(iso_days, -offset, 86400)\n  end\n\n  defp from_map(%{} = datetime_map) do\n    %DateTime{\n      year: datetime_map.year,\n      month: datetime_map.month,\n      day: datetime_map.day,\n      hour: datetime_map.hour,\n      minute: datetime_map.minute,\n      second: datetime_map.second,\n      microsecond: datetime_map.microsecond,\n      time_zone: datetime_map.time_zone,\n      zone_abbr: datetime_map.zone_abbr,\n      utc_offset: datetime_map.utc_offset,\n      std_offset: datetime_map.std_offset\n    }\n  end\n\n  defp seconds_from_day_fraction({parts_in_day, @seconds_per_day}),\n    do: parts_in_day\n\n  defp seconds_from_day_fraction({parts_in_day, parts_per_day}),\n    do: div(parts_in_day * @seconds_per_day, parts_per_day)\n\n  defimpl String.Chars do\n    def to_string(datetime) do\n      %{\n        calendar: calendar,\n        year: year,\n        month: month,\n        day: day,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        time_zone: time_zone,\n        zone_abbr: zone_abbr,\n        utc_offset: utc_offset,\n        std_offset: std_offset\n      } = datetime\n\n      calendar.datetime_to_string(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        time_zone,\n        zone_abbr,\n        utc_offset,\n        std_offset\n      )\n    end\n  end\n\n  defimpl Inspect do\n    def inspect(datetime, _) do\n      %{\n        year: year,\n        month: month,\n        day: day,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        time_zone: time_zone,\n        zone_abbr: zone_abbr,\n        utc_offset: utc_offset,\n        std_offset: std_offset,\n        calendar: calendar\n      } = datetime\n\n      formatted =\n        calendar.datetime_to_string(\n          year,\n          month,\n          day,\n          hour,\n          minute,\n          second,\n          microsecond,\n          time_zone,\n          zone_abbr,\n          utc_offset,\n          std_offset\n        )\n\n      case datetime do\n        %{utc_offset: 0, std_offset: 0, time_zone: \"Etc/UTC\", year: year}\n        when calendar != Calendar.ISO or year in -9999..9999 ->\n          \"~U[\" <> formatted <> suffix(calendar) <> \"]\"\n\n        _ ->\n          \"#DateTime<\" <> formatted <> suffix(calendar) <> \">\"\n      end\n    end\n\n    defp suffix(Calendar.ISO), do: \"\"\n    defp suffix(calendar), do: \" \" <> inspect(calendar)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar/duration.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Duration do\n  @moduledoc \"\"\"\n  Struct and functions for handling durations.\n\n  A `Duration` struct represents a collection of time scale units,\n  allowing for manipulation and calculation of durations.\n\n  Date and time scale units are represented as integers, allowing for\n  both positive and negative values.\n\n  Microseconds are represented using a tuple `{microsecond, precision}`.\n  This ensures compatibility with other calendar types implementing time,\n  such as `Time`, `DateTime`, and `NaiveDateTime`.\n\n  ## Shifting\n\n  The most common use of durations in Elixir's standard library is to\n  \"shift\" the calendar types.\n\n      iex> Date.shift(~D[2016-01-03], month: 2)\n      ~D[2016-03-03]\n\n  In the example above, `Date.shift/2` automatically converts the units\n  into a `Duration` struct, although one can also be given directly:\n\n      iex> Date.shift(~D[2016-01-03], Duration.new!(month: 2))\n      ~D[2016-03-03]\n\n  It is important to note that shifting is not an arithmetic operation.\n  For example, adding `date + 1 month + 1 month` does not yield the same\n  result as `date + 2 months`. Let's see an example:\n\n      iex> ~D[2016-01-31] |> Date.shift(month: 1) |> Date.shift(month: 1)\n      ~D[2016-03-29]\n\n      iex> ~D[2016-01-31] |> Date.shift(month: 2)\n      ~D[2016-03-31]\n\n  As you can see above, the results differ, which explains why operations\n  with durations are called \"shift\" rather than \"add\". This happens because,\n  once we add one month to `2016-01-31`, we get `2016-02-29`. Then adding\n  one extra month gives us `2016-03-29` instead of `2016-03-31`.\n\n  In particular, when applying durations to `Calendar.ISO` types:\n\n    * larger units (such as years and months) are applied before\n      smaller ones (such as weeks, hours, days, and so on)\n\n    * units are collapsed into months (`:year` and `:month`),\n      seconds (`:week`, `:day`, `:hour`, `:minute`, `:second`)\n      and microseconds (`:microsecond`) before they are applied\n\n    * 1 year is equivalent to 12 months, 1 week is equivalent to 7 days.\n      Therefore, 4 weeks _are not_ equivalent to 1 month\n\n    * in case of non-existing dates, the results are rounded down to the\n      nearest valid date\n\n  As the `shift/2` functions are calendar aware, they are guaranteed to return\n  valid date/times, considering leap years as well as DST in applicable time zones.\n\n  ## Intervals\n\n  Durations in Elixir can be combined with stream operations to build intervals.\n  For example, to retrieve the next three Wednesdays starting from 17th April, 2024:\n\n      iex> ~D[2024-04-17] |> Stream.iterate(&Date.shift(&1, week: 1)) |> Enum.take(3)\n      [~D[2024-04-17], ~D[2024-04-24], ~D[2024-05-01]]\n\n  However, once again, it is important to remember that shifting a duration is not\n  arithmetic, so you may want to use the functions in this module depending on what\n  you to achieve. Compare the results of both examples below:\n\n      # Adding one month after the other\n      iex> date = ~D[2016-01-31]\n      iex> duration = Duration.new!(month: 1)\n      iex> stream = Stream.iterate(date, fn prev_date -> Date.shift(prev_date, duration) end)\n      iex> Enum.take(stream, 3)\n      [~D[2016-01-31], ~D[2016-02-29], ~D[2016-03-29]]\n\n      # Multiplying durations by an index\n      iex> date = ~D[2016-01-31]\n      iex> duration = Duration.new!(month: 1)\n      iex> stream = Stream.from_index(fn i -> Date.shift(date, Duration.multiply(duration, i)) end)\n      iex> Enum.take(stream, 3)\n      [~D[2016-01-31], ~D[2016-02-29], ~D[2016-03-31]]\n\n  The second example consistently points to the last day of the month,\n  as it performs operations on the duration, rather than shifting date\n  after date.\n\n  ## Comparing durations\n\n  In order to accurately compare durations, you need to either compare\n  only certain fields or use a reference time instant. This is because\n  some fields are relative to others. For example, you may say that\n  1 month is the same as 30 days, but if you add both of these durations\n  to `~D[2015-02-01]`, you would get different results, as that month\n  has only 28 days.\n\n  Therefore, if you wish to compare durations, one option is to use\n  `Date.shift/2` (or `DateTime.shift/2` or similar), and then compare\n  the dates:\n\n      iex> date = ~D[2015-02-01]\n      iex> Date.compare(Date.shift(date, month: 1), Date.shift(date, day: 30))\n      :lt\n\n  Or alternatively convert the durations to a fixed unit by using `to_timeout/1`,\n  which supports durations only up to weeks, raising if it has the month or year\n  fields set.\n\n      iex> to_timeout(hour: 24) == to_timeout(day: 1)\n      true\n  \"\"\"\n\n  @moduledoc since: \"1.17.0\"\n\n  @derive {Inspect, optional: [:year, :month, :week, :day, :hour, :minute, :second, :microsecond]}\n  defstruct year: 0,\n            month: 0,\n            week: 0,\n            day: 0,\n            hour: 0,\n            minute: 0,\n            second: 0,\n            microsecond: {0, 0}\n\n  @typedoc \"\"\"\n  The duration struct type.\n  \"\"\"\n  @type t :: %Duration{\n          year: integer,\n          month: integer,\n          week: integer,\n          day: integer,\n          hour: integer,\n          minute: integer,\n          second: integer,\n          microsecond: Calendar.microsecond()\n        }\n\n  @typedoc \"\"\"\n  The unit pair type specifies a pair of a valid duration unit key and value.\n  \"\"\"\n  @type unit_pair ::\n          {:year, integer}\n          | {:month, integer}\n          | {:week, integer}\n          | {:day, integer}\n          | {:hour, integer}\n          | {:minute, integer}\n          | {:second, integer}\n          | {:microsecond, Calendar.microsecond()}\n\n  @typedoc \"\"\"\n  The duration type specifies a `%Duration{}` struct or a keyword list of valid duration unit pairs.\n  \"\"\"\n  @type duration :: t | [unit_pair]\n\n  @typedoc \"\"\"\n  Options for `Duration.to_string/2`.\n  \"\"\"\n  @type to_string_opts :: [\n          units: [\n            year: String.t(),\n            month: String.t(),\n            week: String.t(),\n            day: String.t(),\n            hour: String.t(),\n            minute: String.t(),\n            second: String.t()\n          ],\n          separator: String.t()\n        ]\n\n  @microseconds_per_second 1_000_000\n\n  @doc \"\"\"\n  Creates a new `Duration` struct from given `unit_pairs`.\n\n  Raises an `ArgumentError` when called with invalid unit pairs.\n\n  ## Examples\n\n      iex> Duration.new!(year: 1, week: 3, hour: 4, second: 1)\n      %Duration{year: 1, week: 3, hour: 4, second: 1}\n      iex> Duration.new!(second: 1, microsecond: {1000, 6})\n      %Duration{second: 1, microsecond: {1000, 6}}\n      iex> Duration.new!(month: 2)\n      %Duration{month: 2}\n\n  \"\"\"\n  @spec new!(duration()) :: t\n  def new!(%Duration{} = duration) do\n    duration\n  end\n\n  def new!(unit_pairs) do\n    Enum.each(unit_pairs, &validate_unit!/1)\n    struct!(Duration, unit_pairs)\n  end\n\n  defp validate_unit!({:microsecond, {ms, precision}})\n       when is_integer(ms) and precision in 0..6 do\n    :ok\n  end\n\n  defp validate_unit!({:microsecond, microsecond}) do\n    raise ArgumentError,\n          \"unsupported value #{inspect(microsecond)} for :microsecond. Expected a tuple {ms, precision} where precision is an integer from 0 to 6\"\n  end\n\n  defp validate_unit!({unit, _value})\n       when unit not in [:year, :month, :week, :day, :hour, :minute, :second] do\n    raise ArgumentError,\n          \"unknown unit #{inspect(unit)}. Expected :year, :month, :week, :day, :hour, :minute, :second, :microsecond\"\n  end\n\n  defp validate_unit!({_unit, value}) when is_integer(value) do\n    :ok\n  end\n\n  defp validate_unit!({unit, value}) do\n    raise ArgumentError,\n          \"unsupported value #{inspect(value)} for #{inspect(unit)}. Expected an integer\"\n  end\n\n  @doc \"\"\"\n  Adds units of given durations `d1` and `d2`.\n\n  Respects the highest microsecond precision of the two.\n\n  ## Examples\n\n      iex> Duration.add(Duration.new!(week: 2, day: 1), Duration.new!(day: 2))\n      %Duration{week: 2, day: 3}\n      iex> Duration.add(Duration.new!(microsecond: {400, 3}), Duration.new!(microsecond: {600, 6}))\n      %Duration{microsecond: {1000, 6}}\n\n  \"\"\"\n  @spec add(t, t) :: t\n  def add(%Duration{} = d1, %Duration{} = d2) do\n    {m1, p1} = d1.microsecond\n    {m2, p2} = d2.microsecond\n\n    %Duration{\n      year: d1.year + d2.year,\n      month: d1.month + d2.month,\n      week: d1.week + d2.week,\n      day: d1.day + d2.day,\n      hour: d1.hour + d2.hour,\n      minute: d1.minute + d2.minute,\n      second: d1.second + d2.second,\n      microsecond: {m1 + m2, max(p1, p2)}\n    }\n  end\n\n  @doc \"\"\"\n  Subtracts units of given durations `d1` and `d2`.\n\n  Respects the highest microsecond precision of the two.\n\n  ## Examples\n\n      iex> Duration.subtract(Duration.new!(week: 2, day: 1), Duration.new!(day: 2))\n      %Duration{week: 2, day: -1}\n      iex> Duration.subtract(Duration.new!(microsecond: {400, 6}), Duration.new!(microsecond: {600, 3}))\n      %Duration{microsecond: {-200, 6}}\n\n  \"\"\"\n  @spec subtract(t, t) :: t\n  def subtract(%Duration{} = d1, %Duration{} = d2) do\n    {m1, p1} = d1.microsecond\n    {m2, p2} = d2.microsecond\n\n    %Duration{\n      year: d1.year - d2.year,\n      month: d1.month - d2.month,\n      week: d1.week - d2.week,\n      day: d1.day - d2.day,\n      hour: d1.hour - d2.hour,\n      minute: d1.minute - d2.minute,\n      second: d1.second - d2.second,\n      microsecond: {m1 - m2, max(p1, p2)}\n    }\n  end\n\n  @doc \"\"\"\n  Multiplies `duration` units by given `integer`.\n\n  ## Examples\n\n      iex> Duration.multiply(Duration.new!(day: 1, minute: 15, second: -10), 3)\n      %Duration{day: 3, minute: 45, second: -30}\n      iex> Duration.multiply(Duration.new!(microsecond: {200, 4}), 3)\n      %Duration{microsecond: {600, 4}}\n\n  \"\"\"\n  @spec multiply(t, integer) :: t\n  def multiply(%Duration{microsecond: {ms, p}} = duration, integer) when is_integer(integer) do\n    %Duration{\n      year: duration.year * integer,\n      month: duration.month * integer,\n      week: duration.week * integer,\n      day: duration.day * integer,\n      hour: duration.hour * integer,\n      minute: duration.minute * integer,\n      second: duration.second * integer,\n      microsecond: {ms * integer, p}\n    }\n  end\n\n  @doc \"\"\"\n  Negates `duration` units.\n\n  ## Examples\n\n      iex> Duration.negate(Duration.new!(day: 1, minute: 15, second: -10))\n      %Duration{day: -1, minute: -15, second: 10}\n      iex> Duration.negate(Duration.new!(microsecond: {500000, 4}))\n      %Duration{microsecond: {-500000, 4}}\n\n  \"\"\"\n  @spec negate(t) :: t\n  def negate(%Duration{microsecond: {ms, p}} = duration) do\n    %Duration{\n      year: -duration.year,\n      month: -duration.month,\n      week: -duration.week,\n      day: -duration.day,\n      hour: -duration.hour,\n      minute: -duration.minute,\n      second: -duration.second,\n      microsecond: {-ms, p}\n    }\n  end\n\n  @doc \"\"\"\n  Parses an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Durations) formatted duration string to a `Duration` struct.\n\n  Duration strings, as well as individual units, may be prefixed with plus/minus signs so that:\n\n  - `-PT6H3M` parses as `%Duration{hour: -6, minute: -3}`\n  - `-PT6H-3M` parses as `%Duration{hour: -6, minute: 3}`\n  - `+PT6H3M` parses as `%Duration{hour: 6, minute: 3}`\n  - `+PT6H-3M` parses as `%Duration{hour: 6, minute: -3}`\n\n  Duration designators must be provided in order of magnitude: `P[n]Y[n]M[n]W[n]DT[n]H[n]M[n]S`.\n\n  Only seconds may be specified with a decimal fraction, using either a comma or a full stop: `P1DT4,5S`.\n\n  ## Examples\n\n      iex> Duration.from_iso8601(\"P1Y2M3DT4H5M6S\")\n      {:ok, %Duration{year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6}}\n      iex> Duration.from_iso8601(\"P3Y-2MT3H\")\n      {:ok, %Duration{year: 3, month: -2, hour: 3}}\n      iex> Duration.from_iso8601(\"-PT10H-30M\")\n      {:ok, %Duration{hour: -10, minute: 30}}\n      iex> Duration.from_iso8601(\"PT4.650S\")\n      {:ok, %Duration{second: 4, microsecond: {650000, 3}}}\n\n  \"\"\"\n  @spec from_iso8601(String.t()) :: {:ok, t} | {:error, atom}\n  def from_iso8601(string) when is_binary(string) do\n    case Calendar.ISO.parse_duration(string) do\n      {:ok, duration} ->\n        {:ok, new!(duration)}\n\n      error ->\n        error\n    end\n  end\n\n  @doc \"\"\"\n  Same as `from_iso8601/1` but raises an `ArgumentError`.\n\n  ## Examples\n\n      iex> Duration.from_iso8601!(\"P1Y2M3DT4H5M6S\")\n      %Duration{year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6}\n      iex> Duration.from_iso8601!(\"P10D\")\n      %Duration{day: 10}\n\n  \"\"\"\n  @spec from_iso8601!(String.t()) :: t\n  def from_iso8601!(string) when is_binary(string) do\n    case from_iso8601(string) do\n      {:ok, duration} ->\n        duration\n\n      {:error, reason} ->\n        raise ArgumentError, ~s/failed to parse duration \"#{string}\". reason: #{inspect(reason)}/\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given `duration` to a human readable representation.\n\n  ## Options\n\n    * `:units` - the units to be used alongside each duration component.\n      The default units follow the ISO 80000-3 standard:\n\n          [\n            year: \"a\",\n            month: \"mo\",\n            week: \"wk\",\n            day: \"d\",\n            hour: \"h\",\n            minute: \"min\",\n            second: \"s\"\n          ]\n\n    * `:separator` - a string used to separate the distinct components. Defaults to `\" \"`.\n\n  ## Examples\n\n      iex> Duration.to_string(Duration.new!(second: 30))\n      \"30s\"\n      iex> Duration.to_string(Duration.new!(day: 40, hour: 12, minute: 42, second: 12))\n      \"40d 12h 42min 12s\"\n\n  By default, this function uses ISO 80000-3 units, which uses \"a\" for years.\n  But you can customize all units via the units option:\n\n      iex> Duration.to_string(Duration.new!(year: 3))\n      \"3a\"\n      iex> Duration.to_string(Duration.new!(year: 3), units: [year: \"y\"])\n      \"3y\"\n\n  You may also choose the separator:\n\n      iex> Duration.to_string(Duration.new!(day: 40, hour: 12, minute: 42, second: 12), separator: \", \")\n      \"40d, 12h, 42min, 12s\"\n\n  A duration without components is rendered as \"0s\":\n\n      iex> Duration.to_string(Duration.new!([]))\n      \"0s\"\n\n  Microseconds are rendered as part of seconds with the appropriate precision:\n\n      iex> Duration.to_string(Duration.new!(second: 1, microsecond: {2_200, 3}))\n      \"1.002s\"\n      iex> Duration.to_string(Duration.new!(second: 1, microsecond: {-1_200_000, 4}))\n      \"-0.2000s\"\n\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec to_string(t, to_string_opts) :: String.t()\n  def to_string(%Duration{} = duration, opts \\\\ []) do\n    units = Keyword.get(opts, :units, [])\n    separator = Keyword.get(opts, :separator, \" \")\n\n    case to_string_year(duration, [], units) do\n      [] ->\n        \"0\" <> Keyword.get(units, :second, \"s\")\n\n      [part] ->\n        IO.iodata_to_binary(part)\n\n      parts ->\n        parts |> Enum.reduce(&[&1, separator | &2]) |> IO.iodata_to_binary()\n    end\n  end\n\n  defp to_string_part(0, _units, _key, _default, acc),\n    do: acc\n\n  defp to_string_part(x, units, key, default, acc),\n    do: [[Integer.to_string(x) | Keyword.get(units, key, default)] | acc]\n\n  defp to_string_year(%{year: year} = duration, acc, units) do\n    to_string_month(duration, to_string_part(year, units, :year, \"a\", acc), units)\n  end\n\n  defp to_string_month(%{month: month} = duration, acc, units) do\n    to_string_week(duration, to_string_part(month, units, :month, \"mo\", acc), units)\n  end\n\n  defp to_string_week(%{week: week} = duration, acc, units) do\n    to_string_day(duration, to_string_part(week, units, :week, \"wk\", acc), units)\n  end\n\n  defp to_string_day(%{day: day} = duration, acc, units) do\n    to_string_hour(duration, to_string_part(day, units, :day, \"d\", acc), units)\n  end\n\n  defp to_string_hour(%{hour: hour} = duration, acc, units) do\n    to_string_minute(duration, to_string_part(hour, units, :hour, \"h\", acc), units)\n  end\n\n  defp to_string_minute(%{minute: minute} = duration, acc, units) do\n    to_string_second(duration, to_string_part(minute, units, :minute, \"min\", acc), units)\n  end\n\n  defp to_string_second(%{second: 0, microsecond: {0, _}}, acc, _units) do\n    acc\n  end\n\n  defp to_string_second(%{second: s, microsecond: {ms, p}}, acc, units) do\n    [[second_component(s, ms, p) | Keyword.get(units, :second, \"s\")] | acc]\n  end\n\n  @doc \"\"\"\n  Converts the given `duration` to an [ISO 8601-2:2019](https://en.wikipedia.org/wiki/ISO_8601) formatted string.\n\n  This function implements the extension of ISO 8601:2019, allowing weeks to appear between months and days: `P3M3W3D`.\n\n  ## Examples\n\n      iex> Duration.to_iso8601(Duration.new!(year: 3))\n      \"P3Y\"\n      iex> Duration.to_iso8601(Duration.new!(day: 40, hour: 12, minute: 42, second: 12))\n      \"P40DT12H42M12S\"\n      iex> Duration.to_iso8601(Duration.new!(second: 30))\n      \"PT30S\"\n\n      iex> Duration.to_iso8601(Duration.new!([]))\n      \"PT0S\"\n\n      iex> Duration.to_iso8601(Duration.new!(second: 1, microsecond: {2_200, 3}))\n      \"PT1.002S\"\n      iex> Duration.to_iso8601(Duration.new!(second: 1, microsecond: {-1_200_000, 4}))\n      \"PT-0.2000S\"\n  \"\"\"\n\n  @spec to_iso8601(t) :: String.t()\n  def to_iso8601(%Duration{} = duration) do\n    case {to_iso8601_duration_date(duration), to_iso8601_duration_time(duration)} do\n      {[], []} -> \"PT0S\"\n      {date, time} -> IO.iodata_to_binary([?P, date, time])\n    end\n  end\n\n  defp to_iso8601_duration_date(%{year: 0, month: 0, week: 0, day: 0}) do\n    []\n  end\n\n  defp to_iso8601_duration_date(%{year: year, month: month, week: week, day: day}) do\n    [pair(year, ?Y), pair(month, ?M), pair(week, ?W), pair(day, ?D)]\n  end\n\n  defp to_iso8601_duration_time(%{hour: 0, minute: 0, second: 0, microsecond: {0, _}}) do\n    []\n  end\n\n  defp to_iso8601_duration_time(%{hour: hour, minute: minute} = d) do\n    [?T, pair(hour, ?H), pair(minute, ?M), second_component(d)]\n  end\n\n  defp second_component(%{second: 0, microsecond: {0, _}}) do\n    []\n  end\n\n  defp second_component(%{second: second, microsecond: {ms, p}}) do\n    [second_component(second, ms, p), ?S]\n  end\n\n  defp second_component(second, _ms, 0) do\n    Integer.to_string(second)\n  end\n\n  defp second_component(second, ms, p) do\n    total_ms = second * @microseconds_per_second + ms\n    second = total_ms |> div(@microseconds_per_second) |> abs()\n    ms = total_ms |> rem(@microseconds_per_second) |> abs()\n    sign = if total_ms < 0, do: ?-, else: []\n\n    [\n      sign,\n      Integer.to_string(second),\n      ?.,\n      Calendar.ISO.microseconds_to_iodata(ms, p)\n    ]\n  end\n\n  @compile {:inline, pair: 2}\n  defp pair(0, _key), do: []\n  defp pair(num, key), do: [Integer.to_string(num), key]\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar/iso.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Calendar.ISO do\n  @moduledoc \"\"\"\n  The default calendar implementation, a Gregorian calendar following ISO 8601.\n\n  This calendar implements a proleptic Gregorian calendar and\n  is therefore compatible with the calendar used in most countries\n  today. The proleptic means the Gregorian rules for leap years are\n  applied for all time, consequently the dates give different results\n  before the year 1583 from when the Gregorian calendar was adopted.\n\n  ## ISO 8601 compliance\n\n  The ISO 8601 specification is feature-rich, but allows applications\n  to selectively implement most parts of it. The choices Elixir makes\n  are catalogued below.\n\n  ### Features\n\n  The standard library supports a minimal set of possible ISO 8601 features.\n  Specifically, the parser only supports calendar dates and does not support\n  ordinal and week formats. Additionally, it supports parsing ISO 8601\n  formatted durations, including negative time units and fractional seconds.\n\n  By default Elixir only parses extended-formatted date/times. You can opt-in\n  to parse basic-formatted date/times.\n\n  `NaiveDateTime.to_iso8601/2` and `DateTime.to_iso8601/2` allow you to produce\n  either basic or extended formatted strings, and `Calendar.strftime/2` allows\n  you to format datetimes however else you desire.\n\n  Elixir does not support reduced accuracy formats (for example, a date without\n  the day component) nor decimal precisions in the lowest component (such as\n  `10:01:25,5`).\n\n  #### Examples\n\n  Elixir expects the extended format by default when parsing:\n\n      iex> Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_naive_datetime(\"20150123T235007\")\n      {:error, :invalid_format}\n\n  Parsing can be restricted to basic if desired:\n\n      iex> Calendar.ISO.parse_naive_datetime(\"20150123T235007Z\", :basic)\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_naive_datetime(\"20150123T235007Z\", :extended)\n      {:error, :invalid_format}\n\n  Only calendar dates are supported in parsing; ordinal and week dates are not.\n\n      iex> Calendar.ISO.parse_date(\"2015-04-15\")\n      {:ok, {2015, 4, 15}}\n      iex> Calendar.ISO.parse_date(\"2015-105\")\n      {:error, :invalid_format}\n      iex> Calendar.ISO.parse_date(\"2015-W16\")\n      {:error, :invalid_format}\n      iex> Calendar.ISO.parse_date(\"2015-W016-3\")\n      {:error, :invalid_format}\n\n  Years, months, days, hours, minutes, and seconds must be fully specified:\n\n      iex> Calendar.ISO.parse_date(\"2015-04-15\")\n      {:ok, {2015, 4, 15}}\n      iex> Calendar.ISO.parse_date(\"2015-04\")\n      {:error, :invalid_format}\n      iex> Calendar.ISO.parse_date(\"2015\")\n      {:error, :invalid_format}\n\n      iex> Calendar.ISO.parse_time(\"23:50:07.0123456\")\n      {:ok, {23, 50, 7, {12345, 6}}}\n      iex> Calendar.ISO.parse_time(\"23:50:07\")\n      {:ok, {23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_time(\"23:50\")\n      {:error, :invalid_format}\n      iex> Calendar.ISO.parse_time(\"23\")\n      {:error, :invalid_format}\n\n  ### Extensions\n\n  The parser and formatter adopt one ISO 8601 extension: extended year notation.\n\n  This allows dates to be prefixed with a `+` or `-` sign, extending the range of\n  expressible years from the default (`0000..9999`) to `-9999..9999`. Elixir still\n  restricts years in this format to four digits.\n\n  #### Examples\n\n      iex> Calendar.ISO.parse_date(\"-2015-01-23\")\n      {:ok, {-2015, 1, 23}}\n      iex> Calendar.ISO.parse_date(\"+2015-01-23\")\n      {:ok, {2015, 1, 23}}\n\n      iex> Calendar.ISO.parse_naive_datetime(\"-2015-01-23 23:50:07\")\n      {:ok, {-2015, 1, 23, 23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_naive_datetime(\"+2015-01-23 23:50:07\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n\n      iex> Calendar.ISO.parse_utc_datetime(\"-2015-01-23 23:50:07Z\")\n      {:ok, {-2015, 1, 23, 23, 50, 7, {0, 0}}, 0}\n      iex> Calendar.ISO.parse_utc_datetime(\"+2015-01-23 23:50:07Z\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}, 0}\n\n  ### Additions\n\n  ISO 8601 does not allow a whitespace instead of `T` as a separator\n  between date and times, both when parsing and formatting.\n  This is a common enough representation, Elixir allows it during parsing.\n\n  The formatting of dates in `NaiveDateTime.to_iso8601/1` and `DateTime.to_iso8601/1`\n  do produce specification-compliant string representations using the `T` separator.\n\n  #### Examples\n\n      iex> Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07.0123456\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {12345, 6}}}\n      iex> Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07.0123456\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {12345, 6}}}\n\n      iex> Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07.0123456Z\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {12345, 6}}, 0}\n      iex> Calendar.ISO.parse_utc_datetime(\"2015-01-23T23:50:07.0123456Z\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {12345, 6}}, 0}\n\n  \"\"\"\n\n  @behaviour Calendar\n\n  @unix_epoch 62_167_219_200\n  unix_start = (315_537_897_600 + @unix_epoch) * -1_000_000\n  unix_end = 315_569_519_999_999_999 - @unix_epoch * 1_000_000\n  @unix_range_microseconds unix_start..unix_end\n\n  defguardp is_format(term) when term in [:basic, :extended]\n\n  @typedoc \"\"\"\n  \"Before the Current Era\" or \"Before the Common Era\" (BCE), for those years less than `1`.\n  \"\"\"\n  @type bce :: 0\n\n  @typedoc \"\"\"\n  The \"Current Era\" or the \"Common Era\" (CE) which starts in year `1`.\n  \"\"\"\n  @type ce :: 1\n\n  @typedoc \"\"\"\n  The calendar era.\n\n  The ISO calendar has two eras:\n  * [CE](`t:ce/0`) - which starts in year `1` and is defined as era `1`.\n  * [BCE](`t:bce/0`) - for those years less than `1` and is defined as era `0`.\n  \"\"\"\n  @type era :: bce | ce\n  @type year :: -9999..9999\n  @type month :: 1..12\n  @type day :: 1..31\n  @type hour :: 0..23\n  @type minute :: 0..59\n  @type second :: 0..59\n  @type weekday :: :monday | :tuesday | :wednesday | :thursday | :friday | :saturday | :sunday\n  @type utc_offset :: integer\n  @type format :: :basic | :extended\n\n  @typedoc \"\"\"\n  Microseconds with stored precision.\n\n  The precision represents the number of digits that must be used when\n  representing the microseconds to external format. If the precision is 0,\n  it means microseconds must be skipped.\n  \"\"\"\n  @type microsecond :: {0..999_999, 0..6}\n\n  @typedoc \"\"\"\n  Integer that represents the day of the week, where 1 is Monday and 7 is Sunday.\n  \"\"\"\n  @type day_of_week :: 1..7\n\n  @type day_of_year :: 1..366\n  @type quarter_of_year :: 1..4\n  @type year_of_era :: {1..10_000, era}\n\n  @seconds_per_minute 60\n  @seconds_per_hour 60 * 60\n  # Note that this does *not* handle leap seconds.\n  @seconds_per_day 24 * 60 * 60\n  @last_second_of_the_day @seconds_per_day - 1\n  @microseconds_per_second 1_000_000\n  @parts_per_day @seconds_per_day * @microseconds_per_second\n\n  @datetime_seps [?\\s, ?T]\n  @ext_date_sep ?-\n  @ext_time_sep ?:\n\n  # The ISO epoch starts, in this implementation,\n  # with ~D[0000-01-01]. Era \"1\" starts\n  # on ~D[0001-01-01] which is 366 days later.\n  @iso_epoch 366\n\n  # Constants for date calculations using 400-year era cycles.\n  # The algorithm uses a March-based year where March 1 is day 0.\n  # Reference: Neri C, Schneider L. \"Euclidean Affine Functions and\n  # their Application to Calendar Algorithms\". Softw Pract Exper. 2022.\n  @days_per_year 365\n  @years_per_era 400\n  @days_per_era @years_per_era * @days_per_year + 97\n  @days_per_4_years 4 * @days_per_year\n  @days_per_100_years 100 * @days_per_year + 24\n  @march_1_offset 31 + 29\n  @unix_epoch_days 719_528\n\n  # Month calculation constants: in a March-based year, each 5-month\n  # cycle has exactly 153 days (31+30+31+30+31 or 31+30+31+30+31).\n  @days_per_5_months 153\n  @months_per_cycle 5\n\n  [match_basic_date, match_ext_date, guard_date, read_date] =\n    quote do\n      [\n        <<y1, y2, y3, y4, m1, m2, d1, d2>>,\n        <<y1, y2, y3, y4, @ext_date_sep, m1, m2, @ext_date_sep, d1, d2>>,\n        y1 >= ?0 and y1 <= ?9 and y2 >= ?0 and y2 <= ?9 and y3 >= ?0 and y3 <= ?9 and y4 >= ?0 and\n          y4 <= ?9 and m1 >= ?0 and m1 <= ?9 and m2 >= ?0 and m2 <= ?9 and d1 >= ?0 and d1 <= ?9 and\n          d2 >= ?0 and d2 <= ?9,\n        {\n          (y1 - ?0) * 1000 + (y2 - ?0) * 100 + (y3 - ?0) * 10 + (y4 - ?0),\n          (m1 - ?0) * 10 + (m2 - ?0),\n          (d1 - ?0) * 10 + (d2 - ?0)\n        }\n      ]\n    end\n\n  [match_basic_time, match_ext_time, guard_time, read_time] =\n    quote do\n      [\n        <<h1, h2, i1, i2, s1, s2>>,\n        <<h1, h2, @ext_time_sep, i1, i2, @ext_time_sep, s1, s2>>,\n        h1 >= ?0 and h1 <= ?9 and h2 >= ?0 and h2 <= ?9 and i1 >= ?0 and i1 <= ?9 and i2 >= ?0 and\n          i2 <= ?9 and s1 >= ?0 and s1 <= ?9 and s2 >= ?0 and s2 <= ?9,\n        {\n          (h1 - ?0) * 10 + (h2 - ?0),\n          (i1 - ?0) * 10 + (i2 - ?0),\n          (s1 - ?0) * 10 + (s2 - ?0)\n        }\n      ]\n    end\n\n  defguardp is_year(year) when is_integer(year)\n  defguardp is_year_BCE(year) when year <= 0\n  defguardp is_year_CE(year) when year >= 1\n  defguardp is_month(month) when month in 1..12\n  defguardp is_day(day) when day in 1..31\n  defguardp is_hour(hour) when hour in 0..23\n  defguardp is_minute(minute) when minute in 0..59\n  defguardp is_second(second) when second in 0..59\n\n  defguardp is_microsecond(microsecond, precision)\n            when microsecond in 0..999_999 and precision in 0..6\n\n  defguardp is_time_zone(term) when is_binary(term)\n  defguardp is_zone_abbr(term) when is_binary(term)\n  defguardp is_utc_offset(offset) when is_integer(offset)\n  defguardp is_std_offset(offset) when is_integer(offset)\n\n  @doc \"\"\"\n  Converts a `t:System.time_unit/0` to precision.\n\n  Integer-based time units always get maximum precision.\n\n  ## Examples\n\n      iex> Calendar.ISO.time_unit_to_precision(:nanosecond)\n      6\n\n      iex> Calendar.ISO.time_unit_to_precision(:second)\n      0\n\n      iex> Calendar.ISO.time_unit_to_precision(1)\n      6\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec time_unit_to_precision(System.time_unit()) :: 0..6\n  def time_unit_to_precision(:nanosecond), do: 6\n  def time_unit_to_precision(:microsecond), do: 6\n  def time_unit_to_precision(:millisecond), do: 3\n  def time_unit_to_precision(:second), do: 0\n  def time_unit_to_precision(int) when is_integer(int), do: 6\n\n  @doc \"\"\"\n  Parses a time `string` in the `:extended` format.\n\n  For more information on supported strings, see how this\n  module implements [ISO 8601](#module-iso-8601-compliance).\n\n  ## Examples\n\n      iex> Calendar.ISO.parse_time(\"23:50:07\")\n      {:ok, {23, 50, 7, {0, 0}}}\n\n      iex> Calendar.ISO.parse_time(\"23:50:07Z\")\n      {:ok, {23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_time(\"T23:50:07Z\")\n      {:ok, {23, 50, 7, {0, 0}}}\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @impl true\n  @spec parse_time(String.t()) ::\n          {:ok, {hour, minute, second, microsecond}}\n          | {:error, atom}\n  def parse_time(string) when is_binary(string),\n    do: parse_time(string, :extended)\n\n  @doc \"\"\"\n  Parses a time `string` according to a given `format`.\n\n  The `format` can either be `:basic` or `:extended`.\n\n  For more information on supported strings, see how this\n  module implements [ISO 8601](#module-iso-8601-compliance).\n\n  ## Examples\n\n      iex> Calendar.ISO.parse_time(\"235007\", :basic)\n      {:ok, {23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_time(\"235007\", :extended)\n      {:error, :invalid_format}\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec parse_time(String.t(), format) ::\n          {:ok, {hour, minute, second, microsecond}}\n          | {:error, atom}\n  def parse_time(string, format) when is_binary(string) and is_format(format) do\n    case string do\n      \"T\" <> rest -> do_parse_time(rest, format)\n      _ -> do_parse_time(string, format)\n    end\n  end\n\n  defp do_parse_time(<<unquote(match_basic_time), rest::binary>>, :basic)\n       when unquote(guard_time) do\n    {hour, minute, second} = unquote(read_time)\n    parse_formatted_time(hour, minute, second, rest)\n  end\n\n  defp do_parse_time(<<unquote(match_ext_time), rest::binary>>, :extended)\n       when unquote(guard_time) do\n    {hour, minute, second} = unquote(read_time)\n    parse_formatted_time(hour, minute, second, rest)\n  end\n\n  defp do_parse_time(_, _) do\n    {:error, :invalid_format}\n  end\n\n  defp parse_formatted_time(hour, minute, second, rest) do\n    with {microsecond, rest} <- parse_microsecond(rest),\n         {_offset, \"\"} <- parse_offset(rest) do\n      if valid_time?(hour, minute, second, microsecond) do\n        {:ok, {hour, minute, second, microsecond}}\n      else\n        {:error, :invalid_time}\n      end\n    else\n      _ -> {:error, :invalid_format}\n    end\n  end\n\n  @doc \"\"\"\n  Parses a date `string` in the `:extended` format.\n\n  For more information on supported strings, see how this\n  module implements [ISO 8601](#module-iso-8601-compliance).\n\n  ## Examples\n\n      iex> Calendar.ISO.parse_date(\"2015-01-23\")\n      {:ok, {2015, 1, 23}}\n\n      iex> Calendar.ISO.parse_date(\"2015:01:23\")\n      {:error, :invalid_format}\n      iex> Calendar.ISO.parse_date(\"2015-01-32\")\n      {:error, :invalid_date}\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @impl true\n  @spec parse_date(String.t()) ::\n          {:ok, {year, month, day}}\n          | {:error, atom}\n  def parse_date(string) when is_binary(string),\n    do: parse_date(string, :extended)\n\n  @doc \"\"\"\n  Parses a date `string` according to a given `format`.\n\n  The `format` can either be `:basic` or `:extended`.\n\n  For more information on supported strings, see how this\n  module implements [ISO 8601](#module-iso-8601-compliance).\n\n  ## Examples\n\n      iex> Calendar.ISO.parse_date(\"20150123\", :basic)\n      {:ok, {2015, 1, 23}}\n      iex> Calendar.ISO.parse_date(\"20150123\", :extended)\n      {:error, :invalid_format}\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec parse_date(String.t(), format) ::\n          {:ok, {year, month, day}}\n          | {:error, atom}\n  def parse_date(string, format) when is_binary(string) and is_format(format),\n    do: parse_date_guarded(string, format)\n\n  defp parse_date_guarded(\"-\" <> string, format),\n    do: do_parse_date(string, -1, format)\n\n  defp parse_date_guarded(\"+\" <> string, format),\n    do: do_parse_date(string, 1, format)\n\n  defp parse_date_guarded(string, format),\n    do: do_parse_date(string, 1, format)\n\n  defp do_parse_date(unquote(match_basic_date), multiplier, :basic) when unquote(guard_date) do\n    {year, month, day} = unquote(read_date)\n    parse_formatted_date(year, month, day, multiplier)\n  end\n\n  defp do_parse_date(unquote(match_ext_date), multiplier, :extended) when unquote(guard_date) do\n    {year, month, day} = unquote(read_date)\n    parse_formatted_date(year, month, day, multiplier)\n  end\n\n  defp do_parse_date(_, _, _) do\n    {:error, :invalid_format}\n  end\n\n  defp parse_formatted_date(year, month, day, multiplier) do\n    year = multiplier * year\n\n    if valid_date?(year, month, day) do\n      {:ok, {year, month, day}}\n    else\n      {:error, :invalid_date}\n    end\n  end\n\n  @doc \"\"\"\n  Parses a naive datetime `string` in the `:extended` format.\n\n  For more information on supported strings, see how this\n  module implements [ISO 8601](#module-iso-8601-compliance).\n\n  ## Examples\n\n      iex> Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07Z\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07-02:30\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n\n      iex> Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07.0\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 1}}}\n      iex> Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07,0123456\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {12345, 6}}}\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @impl true\n  @spec parse_naive_datetime(String.t()) ::\n          {:ok, {year, month, day, hour, minute, second, microsecond}}\n          | {:error, atom}\n  def parse_naive_datetime(string) when is_binary(string),\n    do: parse_naive_datetime(string, :extended)\n\n  @doc \"\"\"\n  Parses a naive datetime `string` according to a given `format`.\n\n  The `format` can either be `:basic` or `:extended`.\n\n  For more information on supported strings, see how this\n  module implements [ISO 8601](#module-iso-8601-compliance).\n\n  ## Examples\n\n      iex> Calendar.ISO.parse_naive_datetime(\"20150123 235007\", :basic)\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n      iex> Calendar.ISO.parse_naive_datetime(\"20150123 235007\", :extended)\n      {:error, :invalid_format}\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec parse_naive_datetime(String.t(), format) ::\n          {:ok, {year, month, day, hour, minute, second, microsecond}}\n          | {:error, atom}\n  def parse_naive_datetime(string, format) when is_binary(string) and is_format(format),\n    do: parse_naive_datetime_guarded(string, format)\n\n  defp parse_naive_datetime_guarded(\"-\" <> string, format),\n    do: do_parse_naive_datetime(string, -1, format)\n\n  defp parse_naive_datetime_guarded(\"+\" <> string, format),\n    do: do_parse_naive_datetime(string, 1, format)\n\n  defp parse_naive_datetime_guarded(string, format),\n    do: do_parse_naive_datetime(string, 1, format)\n\n  defp do_parse_naive_datetime(\n         <<unquote(match_basic_date), datetime_sep, unquote(match_basic_time), rest::binary>>,\n         multiplier,\n         :basic\n       )\n       when unquote(guard_date) and datetime_sep in @datetime_seps and unquote(guard_time) do\n    {year, month, day} = unquote(read_date)\n    {hour, minute, second} = unquote(read_time)\n    parse_formatted_naive_datetime(year, month, day, hour, minute, second, rest, multiplier)\n  end\n\n  defp do_parse_naive_datetime(\n         <<unquote(match_ext_date), datetime_sep, unquote(match_ext_time), rest::binary>>,\n         multiplier,\n         :extended\n       )\n       when unquote(guard_date) and datetime_sep in @datetime_seps and unquote(guard_time) do\n    {year, month, day} = unquote(read_date)\n    {hour, minute, second} = unquote(read_time)\n    parse_formatted_naive_datetime(year, month, day, hour, minute, second, rest, multiplier)\n  end\n\n  defp do_parse_naive_datetime(_, _, _) do\n    {:error, :invalid_format}\n  end\n\n  defp parse_formatted_naive_datetime(year, month, day, hour, minute, second, rest, multiplier) do\n    year = multiplier * year\n\n    with {microsecond, rest} <- parse_microsecond(rest),\n         {_offset, \"\"} <- parse_offset(rest) do\n      cond do\n        not valid_date?(year, month, day) ->\n          {:error, :invalid_date}\n\n        not valid_time?(hour, minute, second, microsecond) ->\n          {:error, :invalid_time}\n\n        true ->\n          {:ok, {year, month, day, hour, minute, second, microsecond}}\n      end\n    else\n      _ -> {:error, :invalid_format}\n    end\n  end\n\n  @doc \"\"\"\n  Parses a UTC datetime `string` in the `:extended` format.\n\n  For more information on supported strings, see how this\n  module implements [ISO 8601](#module-iso-8601-compliance).\n\n  ## Examples\n\n      iex> Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07Z\")\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}, 0}\n\n      iex> Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07+02:30\")\n      {:ok, {2015, 1, 23, 21, 20, 7, {0, 0}}, 9000}\n\n      iex> Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07\")\n      {:error, :missing_offset}\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @impl true\n  @spec parse_utc_datetime(String.t()) ::\n          {:ok, {year, month, day, hour, minute, second, microsecond}, utc_offset}\n          | {:error, atom}\n  def parse_utc_datetime(string) when is_binary(string),\n    do: parse_utc_datetime(string, :extended)\n\n  @doc \"\"\"\n  Parses a UTC datetime `string` according to a given `format`.\n\n  The `format` can either be `:basic` or `:extended`.\n\n  For more information on supported strings, see how this\n  module implements [ISO 8601](#module-iso-8601-compliance).\n\n  ## Examples\n\n      iex> Calendar.ISO.parse_utc_datetime(\"20150123 235007Z\", :basic)\n      {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}, 0}\n      iex> Calendar.ISO.parse_utc_datetime(\"20150123 235007Z\", :extended)\n      {:error, :invalid_format}\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec parse_utc_datetime(String.t(), format) ::\n          {:ok, {year, month, day, hour, minute, second, microsecond}, utc_offset}\n          | {:error, atom}\n  def parse_utc_datetime(string, format) when is_binary(string) and is_format(format),\n    do: parse_utc_datetime_guarded(string, format)\n\n  defp parse_utc_datetime_guarded(\"-\" <> string, format),\n    do: do_parse_utc_datetime(string, -1, format)\n\n  defp parse_utc_datetime_guarded(\"+\" <> string, format),\n    do: do_parse_utc_datetime(string, 1, format)\n\n  defp parse_utc_datetime_guarded(string, format),\n    do: do_parse_utc_datetime(string, 1, format)\n\n  defp do_parse_utc_datetime(\n         <<unquote(match_basic_date), datetime_sep, unquote(match_basic_time), rest::binary>>,\n         multiplier,\n         :basic\n       )\n       when unquote(guard_date) and datetime_sep in @datetime_seps and unquote(guard_time) do\n    {year, month, day} = unquote(read_date)\n    {hour, minute, second} = unquote(read_time)\n    parse_formatted_utc_datetime(year, month, day, hour, minute, second, rest, multiplier)\n  end\n\n  defp do_parse_utc_datetime(\n         <<unquote(match_ext_date), datetime_sep, unquote(match_ext_time), rest::binary>>,\n         multiplier,\n         :extended\n       )\n       when unquote(guard_date) and datetime_sep in @datetime_seps and unquote(guard_time) do\n    {year, month, day} = unquote(read_date)\n    {hour, minute, second} = unquote(read_time)\n    parse_formatted_utc_datetime(year, month, day, hour, minute, second, rest, multiplier)\n  end\n\n  defp do_parse_utc_datetime(_, _, _) do\n    {:error, :invalid_format}\n  end\n\n  defp parse_formatted_utc_datetime(year, month, day, hour, minute, second, rest, multiplier) do\n    year = multiplier * year\n\n    with {microsecond, rest} <- parse_microsecond(rest),\n         {offset, \"\"} <- parse_offset(rest) do\n      cond do\n        not valid_date?(year, month, day) ->\n          {:error, :invalid_date}\n\n        not valid_time?(hour, minute, second, microsecond) ->\n          {:error, :invalid_time}\n\n        offset == 0 ->\n          {:ok, {year, month, day, hour, minute, second, microsecond}, offset}\n\n        is_nil(offset) ->\n          {:error, :missing_offset}\n\n        true ->\n          day_fraction = time_to_day_fraction(hour, minute, second, {0, 0})\n\n          {{year, month, day}, {hour, minute, second, _}} =\n            case add_day_fraction_to_iso_days({0, day_fraction}, -offset, 86_400) do\n              {0, day_fraction} ->\n                {{year, month, day}, time_from_day_fraction(day_fraction)}\n\n              {extra_days, day_fraction} ->\n                base_days = date_to_iso_days(year, month, day)\n                {date_from_iso_days(base_days + extra_days), time_from_day_fraction(day_fraction)}\n            end\n\n          {:ok, {year, month, day, hour, minute, second, microsecond}, offset}\n      end\n    else\n      _ -> {:error, :invalid_format}\n    end\n  end\n\n  @doc \"\"\"\n  Parses an ISO 8601 formatted duration string to a list of `Duration` compabitble unit pairs.\n\n  See `Duration.from_iso8601/1`.\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec parse_duration(String.t()) :: {:ok, [Duration.unit_pair()]} | {:error, atom}\n  def parse_duration(\"P\" <> string) when byte_size(string) > 0 do\n    parse_duration_date(string, [], year: ?Y, month: ?M, week: ?W, day: ?D)\n  end\n\n  def parse_duration(\"+P\" <> string) when byte_size(string) > 0 do\n    parse_duration_date(string, [], year: ?Y, month: ?M, week: ?W, day: ?D)\n  end\n\n  def parse_duration(\"-P\" <> string) when byte_size(string) > 0 do\n    with {:ok, fields} <- parse_duration_date(string, [], year: ?Y, month: ?M, week: ?W, day: ?D) do\n      {:ok,\n       Enum.map(fields, fn\n         {:microsecond, {value, precision}} -> {:microsecond, {-value, precision}}\n         {unit, value} -> {unit, -value}\n       end)}\n    end\n  end\n\n  def parse_duration(_) do\n    {:error, :invalid_duration}\n  end\n\n  defp parse_duration_date(\"\", acc, _allowed), do: {:ok, acc}\n\n  defp parse_duration_date(\"T\" <> string, acc, _allowed) when byte_size(string) > 0 do\n    parse_duration_time(string, acc, hour: ?H, minute: ?M, second: ?S)\n  end\n\n  defp parse_duration_date(string, acc, allowed) do\n    with {integer, <<next, rest::binary>>} <- Integer.parse(string),\n         {key, allowed} <- find_unit(allowed, next) do\n      parse_duration_date(rest, [{key, integer} | acc], allowed)\n    else\n      _ -> {:error, :invalid_date_component}\n    end\n  end\n\n  defp parse_duration_time(\"\", acc, _allowed), do: {:ok, acc}\n\n  defp parse_duration_time(string, acc, allowed) do\n    case Integer.parse(string) do\n      {second, <<delimiter, _::binary>> = rest} when delimiter in [?., ?,] ->\n        case parse_microsecond(rest) do\n          {{ms, precision}, \"S\"} ->\n            ms =\n              case string do\n                \"-\" <> _ ->\n                  -ms\n\n                _ ->\n                  ms\n              end\n\n            {:ok, [second: second, microsecond: {ms, precision}] ++ acc}\n\n          _ ->\n            {:error, :invalid_time_component}\n        end\n\n      {integer, <<next, rest::binary>>} ->\n        case find_unit(allowed, next) do\n          {key, allowed} -> parse_duration_time(rest, [{key, integer} | acc], allowed)\n          false -> {:error, :invalid_time_component}\n        end\n\n      _ ->\n        {:error, :invalid_time_component}\n    end\n  end\n\n  defp find_unit([{key, unit} | rest], unit), do: {key, rest}\n  defp find_unit([_ | rest], unit), do: find_unit(rest, unit)\n  defp find_unit([], _unit), do: false\n\n  @doc \"\"\"\n  Returns the `t:Calendar.iso_days/0` format of the specified date.\n\n  ## Examples\n\n      iex> Calendar.ISO.naive_datetime_to_iso_days(0, 1, 1, 0, 0, 0, {0, 6})\n      {0, {0, 86400000000}}\n      iex> Calendar.ISO.naive_datetime_to_iso_days(2000, 1, 1, 12, 0, 0, {0, 6})\n      {730485, {43200000000, 86400000000}}\n      iex> Calendar.ISO.naive_datetime_to_iso_days(2000, 1, 1, 13, 0, 0, {0, 6})\n      {730485, {46800000000, 86400000000}}\n      iex> Calendar.ISO.naive_datetime_to_iso_days(-1, 1, 1, 0, 0, 0, {0, 6})\n      {-365, {0, 86400000000}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @impl true\n  @spec naive_datetime_to_iso_days(\n          Calendar.year(),\n          Calendar.month(),\n          Calendar.day(),\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond()\n        ) :: Calendar.iso_days()\n  def naive_datetime_to_iso_days(year, month, day, hour, minute, second, microsecond) do\n    {date_to_iso_days(year, month, day), time_to_day_fraction(hour, minute, second, microsecond)}\n  end\n\n  @doc \"\"\"\n  Converts the `t:Calendar.iso_days/0` format to the datetime format specified by this calendar.\n\n  ## Examples\n\n      iex> Calendar.ISO.naive_datetime_from_iso_days({0, {0, 86_400}})\n      {0, 1, 1, 0, 0, 0, {0, 6}}\n      iex> Calendar.ISO.naive_datetime_from_iso_days({730_485, {0, 86_400}})\n      {2000, 1, 1, 0, 0, 0, {0, 6}}\n      iex> Calendar.ISO.naive_datetime_from_iso_days({730_485, {43_200, 86_400}})\n      {2000, 1, 1, 12, 0, 0, {0, 6}}\n      iex> Calendar.ISO.naive_datetime_from_iso_days({-365, {0, 86_400_000_000}})\n      {-1, 1, 1, 0, 0, 0, {0, 6}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec naive_datetime_from_iso_days(Calendar.iso_days()) :: {\n          Calendar.year(),\n          Calendar.month(),\n          Calendar.day(),\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond()\n        }\n  @impl true\n  def naive_datetime_from_iso_days({days, day_fraction}) do\n    {year, month, day} = date_from_iso_days(days)\n    {hour, minute, second, microsecond} = time_from_day_fraction(day_fraction)\n    {year, month, day, hour, minute, second, microsecond}\n  end\n\n  @doc \"\"\"\n  Returns the normalized day fraction of the specified time.\n\n  ## Examples\n\n      iex> Calendar.ISO.time_to_day_fraction(0, 0, 0, {0, 6})\n      {0, 86400000000}\n      iex> Calendar.ISO.time_to_day_fraction(12, 34, 56, {123, 6})\n      {45296000123, 86400000000}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @impl true\n  @spec time_to_day_fraction(\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond()\n        ) :: Calendar.day_fraction()\n  def time_to_day_fraction(0, 0, 0, {0, _}) do\n    {0, @parts_per_day}\n  end\n\n  def time_to_day_fraction(hour, minute, second, {microsecond, _}) do\n    combined_seconds = hour * @seconds_per_hour + minute * @seconds_per_minute + second\n    {combined_seconds * @microseconds_per_second + microsecond, @parts_per_day}\n  end\n\n  @doc \"\"\"\n  Converts a day fraction to this Calendar's representation of time.\n\n  ## Examples\n\n      iex> Calendar.ISO.time_from_day_fraction({1, 2})\n      {12, 0, 0, {0, 6}}\n      iex> Calendar.ISO.time_from_day_fraction({13, 24})\n      {13, 0, 0, {0, 6}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @impl true\n  @spec time_from_day_fraction(Calendar.day_fraction()) ::\n          {hour(), minute(), second(), microsecond()}\n  def time_from_day_fraction({0, _}) do\n    {0, 0, 0, {0, 6}}\n  end\n\n  def time_from_day_fraction({parts_in_day, parts_per_day}) do\n    total_microseconds = divide_by_parts_per_day(parts_in_day, parts_per_day)\n\n    {hours, rest_microseconds1} =\n      div_rem(total_microseconds, @seconds_per_hour * @microseconds_per_second)\n\n    {minutes, rest_microseconds2} =\n      div_rem(rest_microseconds1, @seconds_per_minute * @microseconds_per_second)\n\n    {seconds, microseconds} = div_rem(rest_microseconds2, @microseconds_per_second)\n    {hours, minutes, seconds, {microseconds, 6}}\n  end\n\n  defp divide_by_parts_per_day(parts_in_day, @parts_per_day), do: parts_in_day\n\n  defp divide_by_parts_per_day(parts_in_day, parts_per_day),\n    do: div(parts_in_day * @parts_per_day, parts_per_day)\n\n  # Converts year, month, day to count of days since 0000-01-01.\n  @doc false\n  def date_to_iso_days(0, 1, 1), do: 0\n  def date_to_iso_days(1970, 1, 1), do: @unix_epoch_days\n\n  def date_to_iso_days(year, month, day) do\n    ensure_day_in_month!(year, month, day)\n\n    y = if month <= 2, do: year - 1, else: year\n    era = if y >= 0, do: div(y, @years_per_era), else: div(y - 399, @years_per_era)\n    year_of_era = y - era * @years_per_era\n    month_prime = if month > 2, do: month - 3, else: month + 9\n    day_of_year = div(@days_per_5_months * month_prime + 2, @months_per_cycle) + day - 1\n\n    day_of_era =\n      @days_per_year * year_of_era + div(year_of_era, 4) - div(year_of_era, 100) + day_of_year\n\n    era * @days_per_era + day_of_era + @march_1_offset\n  end\n\n  # Converts count of days since 0000-01-01 to {year, month, day} tuple.\n  @doc false\n  def date_from_iso_days(days) do\n    z = days - @march_1_offset\n    era = if z >= 0, do: div(z, @days_per_era), else: div(z - @days_per_era + 1, @days_per_era)\n    day_of_era = z - era * @days_per_era\n\n    year_of_era =\n      div(\n        day_of_era - div(day_of_era, @days_per_4_years) + div(day_of_era, @days_per_100_years) -\n          div(day_of_era, @days_per_era - 1),\n        @days_per_year\n      )\n\n    day_of_year =\n      day_of_era -\n        (@days_per_year * year_of_era + div(year_of_era, 4) - div(year_of_era, 100))\n\n    month_prime = div(@months_per_cycle * day_of_year + 2, @days_per_5_months)\n    day = day_of_year - div(@days_per_5_months * month_prime + 2, @months_per_cycle) + 1\n    month = if month_prime < 10, do: month_prime + 3, else: month_prime - 9\n    year = year_of_era + era * @years_per_era\n    year = if month <= 2, do: year + 1, else: year\n\n    {year, month, day}\n  end\n\n  defp div_rem(int1, int2) do\n    div = div(int1, int2)\n    rem = int1 - div * int2\n\n    if rem >= 0 do\n      {div, rem}\n    else\n      {div - 1, rem + int2}\n    end\n  end\n\n  defp floor_div_positive_divisor(int1, int2) when int1 >= 0, do: div(int1, int2)\n  defp floor_div_positive_divisor(int1, int2), do: -div(-int1 - 1, int2) - 1\n\n  @doc \"\"\"\n  Returns how many days there are in the given year-month.\n\n  ## Examples\n\n      iex> Calendar.ISO.days_in_month(1900, 1)\n      31\n      iex> Calendar.ISO.days_in_month(1900, 2)\n      28\n      iex> Calendar.ISO.days_in_month(2000, 2)\n      29\n      iex> Calendar.ISO.days_in_month(2001, 2)\n      28\n      iex> Calendar.ISO.days_in_month(2004, 2)\n      29\n      iex> Calendar.ISO.days_in_month(2004, 4)\n      30\n      iex> Calendar.ISO.days_in_month(-1, 5)\n      31\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec days_in_month(year, month) :: 28..31\n  @impl true\n  def days_in_month(year, month) when is_year(year) and is_month(month) do\n    days_in_month_guarded(year, month)\n  end\n\n  defp days_in_month_guarded(year, 2) do\n    if leap_year?(year), do: 29, else: 28\n  end\n\n  defp days_in_month_guarded(_, month) when month in [4, 6, 9, 11], do: 30\n  defp days_in_month_guarded(_, _), do: 31\n\n  @doc \"\"\"\n  Returns how many months there are in the given year.\n\n  ## Example\n\n      iex> Calendar.ISO.months_in_year(2004)\n      12\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @impl true\n  @spec months_in_year(year) :: 12\n  def months_in_year(year) when is_year(year) do\n    12\n  end\n\n  @doc \"\"\"\n  Returns if the given year is a leap year.\n\n  ## Examples\n\n      iex> Calendar.ISO.leap_year?(2000)\n      true\n      iex> Calendar.ISO.leap_year?(2001)\n      false\n      iex> Calendar.ISO.leap_year?(2004)\n      true\n      iex> Calendar.ISO.leap_year?(1900)\n      false\n      iex> Calendar.ISO.leap_year?(-4)\n      true\n\n  \"\"\"\n  @doc since: \"1.3.0\"\n  @spec leap_year?(year) :: boolean()\n  @impl true\n  def leap_year?(year) when is_year(year) do\n    rem(year, 4) === 0 and (rem(year, 100) !== 0 or rem(year, 400) === 0)\n  end\n\n  @doc false\n  @deprecated \"Use Calendar.ISO.day_of_week/4 instead\"\n  def day_of_week(year, month, day) do\n    day_of_week(year, month, day, :default) |> elem(0)\n  end\n\n  @doc \"\"\"\n  Calculates the day of the week from the given `year`, `month`, and `day`.\n\n  It is an integer from 1 to 7, where 1 is the given `starting_on` weekday.\n  For example, if `starting_on` is set to `:monday`, then 1 is Monday and\n  7 is Sunday.\n\n  `starting_on` can also be `:default`, which is equivalent to `:monday`.\n\n  ## Examples\n\n      iex> Calendar.ISO.day_of_week(2016, 10, 31, :monday)\n      {1, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 1, :monday)\n      {2, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 2, :monday)\n      {3, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 3, :monday)\n      {4, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 4, :monday)\n      {5, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 5, :monday)\n      {6, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 6, :monday)\n      {7, 1, 7}\n      iex> Calendar.ISO.day_of_week(-99, 1, 31, :monday)\n      {4, 1, 7}\n\n      iex> Calendar.ISO.day_of_week(2016, 10, 31, :sunday)\n      {2, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 1, :sunday)\n      {3, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 2, :sunday)\n      {4, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 3, :sunday)\n      {5, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 4, :sunday)\n      {6, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 5, :sunday)\n      {7, 1, 7}\n      iex> Calendar.ISO.day_of_week(2016, 11, 6, :sunday)\n      {1, 1, 7}\n      iex> Calendar.ISO.day_of_week(-99, 1, 31, :sunday)\n      {5, 1, 7}\n\n      iex> Calendar.ISO.day_of_week(2016, 10, 31, :saturday)\n      {3, 1, 7}\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec day_of_week(year, month, day, :default | weekday) :: {day_of_week(), 1, 7}\n  @impl true\n  def day_of_week(year, month, day, starting_on) do\n    iso_days = date_to_iso_days(year, month, day)\n    {iso_days_to_day_of_week(iso_days, starting_on), 1, 7}\n  end\n\n  @doc false\n  def iso_days_to_day_of_week(iso_days, starting_on) do\n    Integer.mod(iso_days + day_of_week_offset(starting_on), 7) + 1\n  end\n\n  defp day_of_week_offset(:default), do: 5\n  defp day_of_week_offset(:wednesday), do: 3\n  defp day_of_week_offset(:thursday), do: 2\n  defp day_of_week_offset(:friday), do: 1\n  defp day_of_week_offset(:saturday), do: 0\n  defp day_of_week_offset(:sunday), do: 6\n  defp day_of_week_offset(:monday), do: 5\n  defp day_of_week_offset(:tuesday), do: 4\n\n  @doc \"\"\"\n  Calculates the day of the year from the given `year`, `month`, and `day`.\n\n  It is an integer from 1 to 366.\n\n  ## Examples\n\n      iex> Calendar.ISO.day_of_year(2016, 1, 31)\n      31\n      iex> Calendar.ISO.day_of_year(-99, 2, 1)\n      32\n      iex> Calendar.ISO.day_of_year(2018, 2, 28)\n      59\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec day_of_year(year, month, day) :: day_of_year()\n  @impl true\n  def day_of_year(year, month, day) do\n    ensure_day_in_month!(year, month, day)\n    days_before_month(month) + leap_day_offset(year, month) + day\n  end\n\n  @doc \"\"\"\n  Calculates the quarter of the year from the given `year`, `month`, and `day`.\n\n  It is an integer from 1 to 4.\n\n  ## Examples\n\n      iex> Calendar.ISO.quarter_of_year(2016, 1, 31)\n      1\n      iex> Calendar.ISO.quarter_of_year(2016, 4, 3)\n      2\n      iex> Calendar.ISO.quarter_of_year(-99, 9, 31)\n      3\n      iex> Calendar.ISO.quarter_of_year(2018, 12, 28)\n      4\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec quarter_of_year(year, month, day) :: quarter_of_year()\n  @impl true\n  def quarter_of_year(year, month, day)\n      when is_year(year) and is_month(month) and is_day(day) do\n    div(month - 1, 3) + 1\n  end\n\n  @doc \"\"\"\n  Calculates the year and era from the given `year`.\n\n  The ISO calendar has two eras: the \"current era\" (CE) which\n  starts in year `1` and is defined as era `1`. And \"before the current\n  era\" (BCE) for those years less than `1`, defined as era `0`.\n\n  ## Examples\n\n      iex> Calendar.ISO.year_of_era(1)\n      {1, 1}\n      iex> Calendar.ISO.year_of_era(2018)\n      {2018, 1}\n      iex> Calendar.ISO.year_of_era(0)\n      {1, 0}\n      iex> Calendar.ISO.year_of_era(-1)\n      {2, 0}\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec year_of_era(year) :: {1..10_000, era}\n  def year_of_era(year) when is_year_CE(year), do: {year, 1}\n  def year_of_era(year) when is_year_BCE(year), do: {abs(year) + 1, 0}\n\n  @doc \"\"\"\n  Calendar callback to compute the year and era from the\n  given `year`, `month` and `day`.\n\n  In the ISO calendar, the new year coincides with the new era,\n  so the `month` and `day` arguments are discarded. If you only\n  have the year available, you can `year_of_era/1` instead.\n\n  ## Examples\n\n      iex> Calendar.ISO.year_of_era(1, 1, 1)\n      {1, 1}\n      iex> Calendar.ISO.year_of_era(2018, 12, 1)\n      {2018, 1}\n      iex> Calendar.ISO.year_of_era(0, 1, 1)\n      {1, 0}\n      iex> Calendar.ISO.year_of_era(-1, 12, 1)\n      {2, 0}\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @impl true\n  @spec year_of_era(year, month, day) :: {1..10_000, era}\n  def year_of_era(year, _month, _day), do: year_of_era(year)\n\n  @doc \"\"\"\n  Calculates the day and era from the given `year`, `month`, and `day`.\n\n  ## Examples\n\n      iex> Calendar.ISO.day_of_era(0, 1, 1)\n      {366, 0}\n      iex> Calendar.ISO.day_of_era(1, 1, 1)\n      {1, 1}\n      iex> Calendar.ISO.day_of_era(0, 12, 31)\n      {1, 0}\n      iex> Calendar.ISO.day_of_era(0, 12, 30)\n      {2, 0}\n      iex> Calendar.ISO.day_of_era(-1, 12, 31)\n      {367, 0}\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec day_of_era(year, month, day) :: Calendar.day_of_era()\n  @impl true\n  def day_of_era(year, month, day) when is_year_CE(year) do\n    day = date_to_iso_days(year, month, day) - @iso_epoch + 1\n    {day, 1}\n  end\n\n  def day_of_era(year, month, day) when is_year_BCE(year) do\n    day = abs(date_to_iso_days(year, month, day) - @iso_epoch)\n    {day, 0}\n  end\n\n  @doc \"\"\"\n  Converts the given time into a string.\n\n  By default, returns times formatted in the \"extended\" format,\n  for human readability. It also supports the \"basic\" format\n  by passing the `:basic` option.\n\n  ## Examples\n\n      iex> Calendar.ISO.time_to_string(2, 2, 2, {2, 6})\n      \"02:02:02.000002\"\n      iex> Calendar.ISO.time_to_string(2, 2, 2, {2, 2})\n      \"02:02:02.00\"\n      iex> Calendar.ISO.time_to_string(2, 2, 2, {2, 0})\n      \"02:02:02\"\n\n      iex> Calendar.ISO.time_to_string(2, 2, 2, {2, 6}, :basic)\n      \"020202.000002\"\n      iex> Calendar.ISO.time_to_string(2, 2, 2, {2, 6}, :extended)\n      \"02:02:02.000002\"\n\n  \"\"\"\n  @impl true\n  @doc since: \"1.5.0\"\n  @spec time_to_string(\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond(),\n          :basic | :extended\n        ) :: String.t()\n  def time_to_string(\n        hour,\n        minute,\n        second,\n        microsecond,\n        format \\\\ :extended\n      ) do\n    time_to_iodata(hour, minute, second, microsecond, format)\n    |> IO.iodata_to_binary()\n  end\n\n  @doc \"\"\"\n  Converts the given time into a iodata.\n\n  See `time_to_string/5` for more information.\n\n  ## Examples\n\n      iex> data = Calendar.ISO.time_to_iodata(2, 2, 2, {2, 6})\n      iex> IO.iodata_to_binary(data)\n      \"02:02:02.000002\"\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec time_to_iodata(\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond(),\n          :basic | :extended\n        ) :: iodata\n  def time_to_iodata(\n        hour,\n        minute,\n        second,\n        {ms_value, ms_precision} = microsecond,\n        format \\\\ :extended\n      )\n      when is_hour(hour) and is_minute(minute) and is_second(second) and\n             is_microsecond(ms_value, ms_precision) and format in [:basic, :extended] do\n    time_to_iodata_guarded(hour, minute, second, microsecond, format)\n  end\n\n  defp time_to_iodata_guarded(hour, minute, second, {_, 0}, format) do\n    time_to_iodata_format(hour, minute, second, format)\n  end\n\n  defp time_to_iodata_guarded(hour, minute, second, {microsecond, precision}, format) do\n    [\n      time_to_iodata_format(hour, minute, second, format),\n      ?.\n      | microseconds_to_iodata(microsecond, precision)\n    ]\n  end\n\n  @doc false\n  def microseconds_to_iodata(_microsecond, 0), do: []\n  def microseconds_to_iodata(microsecond, 6), do: zero_pad(microsecond, 6)\n\n  def microseconds_to_iodata(microsecond, precision) do\n    num = div(microsecond, scale_factor(precision))\n    zero_pad(num, precision)\n  end\n\n  defp scale_factor(1), do: 100_000\n  defp scale_factor(2), do: 10_000\n  defp scale_factor(3), do: 1_000\n  defp scale_factor(4), do: 100\n  defp scale_factor(5), do: 10\n  defp scale_factor(6), do: 1\n\n  defp time_to_iodata_format(hour, minute, second, :extended) do\n    [zero_pad(hour, 2), ?:, zero_pad(minute, 2), ?: | zero_pad(second, 2)]\n  end\n\n  defp time_to_iodata_format(hour, minute, second, :basic) do\n    [zero_pad(hour, 2), zero_pad(minute, 2) | zero_pad(second, 2)]\n  end\n\n  @doc \"\"\"\n  Converts the given date into a string.\n\n  By default, returns dates formatted in the \"extended\" format,\n  for human readability. It also supports the \"basic\" format\n  by passing the `:basic` option.\n\n  ## Examples\n\n      iex> Calendar.ISO.date_to_string(2015, 2, 28)\n      \"2015-02-28\"\n      iex> Calendar.ISO.date_to_string(2017, 8, 1)\n      \"2017-08-01\"\n      iex> Calendar.ISO.date_to_string(-99, 1, 31)\n      \"-0099-01-31\"\n\n      iex> Calendar.ISO.date_to_string(2015, 2, 28, :basic)\n      \"20150228\"\n      iex> Calendar.ISO.date_to_string(-99, 1, 31, :basic)\n      \"-00990131\"\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec date_to_string(year, month, day, :basic | :extended) :: String.t()\n  @impl true\n  def date_to_string(year, month, day, format \\\\ :extended) do\n    date_to_iodata(year, month, day, format)\n    |> IO.iodata_to_binary()\n  end\n\n  @doc \"\"\"\n  Converts the given date into a iodata.\n\n  See `date_to_string/4` for more information.\n\n  ## Examples\n\n      iex> data = Calendar.ISO.date_to_iodata(2015, 2, 28)\n      iex> IO.iodata_to_binary(data)\n      \"2015-02-28\"\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec date_to_iodata(year, month, day, :basic | :extended) :: iodata\n  def date_to_iodata(year, month, day, format \\\\ :extended)\n      when is_integer(year) and is_integer(month) and is_integer(day) and\n             format in [:basic, :extended] do\n    date_to_iodata_guarded(year, month, day, format)\n  end\n\n  defp date_to_iodata_guarded(year, month, day, :extended) do\n    [zero_pad(year, 4), ?-, zero_pad(month, 2), ?- | zero_pad(day, 2)]\n  end\n\n  defp date_to_iodata_guarded(year, month, day, :basic) do\n    [zero_pad(year, 4), zero_pad(month, 2) | zero_pad(day, 2)]\n  end\n\n  @doc \"\"\"\n  Converts the datetime (without time zone) into a string.\n\n  By default, returns datetimes formatted in the \"extended\" format,\n  for human readability. It also supports the \"basic\" format\n  by passing the `:basic` option.\n\n  ## Examples\n\n      iex> Calendar.ISO.naive_datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 6})\n      \"2015-02-28 01:02:03.000004\"\n      iex> Calendar.ISO.naive_datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5})\n      \"2017-08-01 01:02:03.00000\"\n\n      iex> Calendar.ISO.naive_datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 6}, :basic)\n      \"20150228 010203.000004\"\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @impl true\n  @spec naive_datetime_to_string(\n          year,\n          month,\n          day,\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond(),\n          :basic | :extended\n        ) :: String.t()\n  def naive_datetime_to_string(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        format \\\\ :extended\n      ) do\n    naive_datetime_to_iodata(\n      year,\n      month,\n      day,\n      hour,\n      minute,\n      second,\n      microsecond,\n      format\n    )\n    |> IO.iodata_to_binary()\n  end\n\n  @doc \"\"\"\n  Converts the given naive_datetime into a iodata.\n\n  See `naive_datetime_to_iodata/8` for more information.\n\n  ## Examples\n\n      iex> data = Calendar.ISO.naive_datetime_to_iodata(2015, 2, 28, 1, 2, 3, {4, 6}, :basic)\n      iex> IO.iodata_to_binary(data)\n      \"20150228 010203.000004\"\n\n      iex> data = Calendar.ISO.naive_datetime_to_iodata(2015, 2, 28, 1, 2, 3, {4, 6}, :extended)\n      iex> IO.iodata_to_binary(data)\n      \"2015-02-28 01:02:03.000004\"\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec naive_datetime_to_iodata(\n          year,\n          month,\n          day,\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond(),\n          :basic | :extended\n        ) :: iodata\n  def naive_datetime_to_iodata(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        format \\\\ :extended\n      ) do\n    [\n      date_to_iodata(year, month, day, format),\n      ?\\s\n      | time_to_iodata(hour, minute, second, microsecond, format)\n    ]\n  end\n\n  @doc \"\"\"\n  Converts the datetime (with time zone) into a string.\n\n  By default, returns datetimes formatted in the \"extended\" format,\n  for human readability. It also supports the \"basic\" format\n  by passing the `:basic` option.\n\n  ## Examples\n\n      iex> time_zone = \"Etc/UTC\"\n      iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, \"UTC\", 0, 0)\n      \"2017-08-01 01:02:03.00000Z\"\n      iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, \"UTC\", 3600, 0)\n      \"2017-08-01 01:02:03.00000+01:00\"\n      iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, \"UTC\", 3600, 3600)\n      \"2017-08-01 01:02:03.00000+02:00\"\n\n      iex> time_zone = \"Europe/Berlin\"\n      iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, \"CET\", 3600, 0)\n      \"2017-08-01 01:02:03.00000+01:00 CET Europe/Berlin\"\n      iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, \"CDT\", 3600, 3600)\n      \"2017-08-01 01:02:03.00000+02:00 CDT Europe/Berlin\"\n\n      iex> time_zone = \"America/Los_Angeles\"\n      iex> Calendar.ISO.datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 5}, time_zone, \"PST\", -28800, 0)\n      \"2015-02-28 01:02:03.00000-08:00 PST America/Los_Angeles\"\n      iex> Calendar.ISO.datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 5}, time_zone, \"PDT\", -28800, 3600)\n      \"2015-02-28 01:02:03.00000-07:00 PDT America/Los_Angeles\"\n\n      iex> time_zone = \"Europe/Berlin\"\n      iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, \"CET\", 3600, 0, :basic)\n      \"20170801 010203.00000+0100 CET Europe/Berlin\"\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @impl true\n  @spec datetime_to_string(\n          year,\n          month,\n          day,\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond(),\n          Calendar.time_zone(),\n          Calendar.zone_abbr(),\n          Calendar.utc_offset(),\n          Calendar.std_offset(),\n          :basic | :extended\n        ) :: String.t()\n  def datetime_to_string(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        time_zone,\n        zone_abbr,\n        utc_offset,\n        std_offset,\n        format \\\\ :extended\n      ) do\n    datetime_to_iodata(\n      year,\n      month,\n      day,\n      hour,\n      minute,\n      second,\n      microsecond,\n      time_zone,\n      zone_abbr,\n      utc_offset,\n      std_offset,\n      format\n    )\n    |> IO.iodata_to_binary()\n  end\n\n  @doc \"\"\"\n  Converts the given datetime into a iodata.\n\n  See `datetime_to_iodata/12` for more information.\n\n  ## Examples\n\n      iex> time_zone = \"Etc/UTC\"\n      iex> data = Calendar.ISO.datetime_to_iodata(2017, 8, 1, 1, 2, 3, {4, 5}, time_zone, \"UTC\", 0, 0)\n      iex> IO.iodata_to_binary(data)\n      \"2017-08-01 01:02:03.00000Z\"\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec datetime_to_iodata(\n          year,\n          month,\n          day,\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond(),\n          Calendar.time_zone(),\n          Calendar.zone_abbr(),\n          Calendar.utc_offset(),\n          Calendar.std_offset(),\n          :basic | :extended\n        ) :: iodata\n  def datetime_to_iodata(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        time_zone,\n        zone_abbr,\n        utc_offset,\n        std_offset,\n        format \\\\ :extended\n      )\n      when is_time_zone(time_zone) and is_zone_abbr(zone_abbr) and is_utc_offset(utc_offset) and\n             is_std_offset(std_offset) do\n    [\n      date_to_iodata(year, month, day, format),\n      ?\\s,\n      time_to_iodata(hour, minute, second, microsecond, format),\n      offset_to_iodata(utc_offset, std_offset, time_zone, format),\n      zone_to_iodata(utc_offset, std_offset, zone_abbr, time_zone)\n    ]\n  end\n\n  @doc false\n  def offset_to_string(0, 0, \"Etc/UTC\", _format), do: \"Z\"\n\n  def offset_to_string(utc, std, zone, format) do\n    offset_to_iodata(utc, std, zone, format)\n    |> IO.iodata_to_binary()\n  end\n\n  @doc false\n  def offset_to_iodata(0, 0, \"Etc/UTC\", _format), do: ?Z\n\n  def offset_to_iodata(utc, std, _zone, format) do\n    total = utc + std\n    second = abs(total)\n    minute = second |> rem(3600) |> div(60)\n    hour = div(second, 3600)\n    format_offset(total, hour, minute, format)\n  end\n\n  defp format_offset(total, hour, minute, :extended) do\n    [sign(total), zero_pad(hour, 2), ?: | zero_pad(minute, 2)]\n  end\n\n  defp format_offset(total, hour, minute, :basic) do\n    [sign(total), zero_pad(hour, 2) | zero_pad(minute, 2)]\n  end\n\n  defp zone_to_iodata(_, _, _, \"Etc/UTC\"), do: []\n  defp zone_to_iodata(_, _, abbr, zone), do: [?\\s, abbr, ?\\s | zone]\n\n  @doc \"\"\"\n  Determines if the date given is valid according to the proleptic Gregorian calendar.\n\n  ## Examples\n\n      iex> Calendar.ISO.valid_date?(2015, 2, 28)\n      true\n      iex> Calendar.ISO.valid_date?(2015, 2, 30)\n      false\n      iex> Calendar.ISO.valid_date?(-1, 12, 31)\n      true\n      iex> Calendar.ISO.valid_date?(-1, 12, 32)\n      false\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @impl true\n  @spec valid_date?(year, month, day) :: boolean\n  def valid_date?(year, month, day)\n      when is_integer(year) and is_integer(month) and is_integer(day) do\n    is_month(month) and day in 1..days_in_month(year, month)\n  end\n\n  @doc \"\"\"\n  Determines if the date given is valid according to the proleptic Gregorian calendar.\n\n  Leap seconds are not supported by the built-in Calendar.ISO.\n\n  ## Examples\n\n      iex> Calendar.ISO.valid_time?(10, 50, 25, {3006, 6})\n      true\n      iex> Calendar.ISO.valid_time?(23, 59, 60, {0, 0})\n      false\n      iex> Calendar.ISO.valid_time?(24, 0, 0, {0, 0})\n      false\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @impl true\n  @spec valid_time?(Calendar.hour(), Calendar.minute(), Calendar.second(), Calendar.microsecond()) ::\n          boolean\n  def valid_time?(hour, minute, second, {ms_value, ms_precision} = _microsecond)\n      when is_integer(hour) and is_integer(minute) and is_integer(second) and is_integer(ms_value) and\n             is_integer(ms_value) do\n    is_hour(hour) and is_minute(minute) and is_second(second) and\n      is_microsecond(ms_value, ms_precision)\n  end\n\n  @doc \"\"\"\n  See `c:Calendar.day_rollover_relative_to_midnight_utc/0` for documentation.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @impl true\n  @spec day_rollover_relative_to_midnight_utc() :: {0, 1}\n  def day_rollover_relative_to_midnight_utc() do\n    {0, 1}\n  end\n\n  defp sign(total) when total < 0, do: ?-\n  defp sign(_), do: ?+\n\n  defp zero_pad(val, count) when val >= 0 and count <= 6 do\n    num = Integer.to_string(val)\n\n    case max(count - byte_size(num), 0) do\n      0 -> num\n      1 -> [\"0\" | num]\n      2 -> [\"00\" | num]\n      3 -> [\"000\" | num]\n      4 -> [\"0000\" | num]\n      5 -> [\"00000\" | num]\n    end\n  end\n\n  defp zero_pad(val, count) do\n    [?- | zero_pad(-val, count)]\n  end\n\n  @doc \"\"\"\n  Converts the `t:Calendar.iso_days/0` to the first moment of the day.\n\n  ## Examples\n\n      iex> Calendar.ISO.iso_days_to_beginning_of_day({0, {0, 86_400_000_000}})\n      {0, {0, 86400000000}}\n      iex> Calendar.ISO.iso_days_to_beginning_of_day({730_485, {43_200_000_000, 86_400_000_000}})\n      {730485, {0, 86400000000}}\n      iex> Calendar.ISO.iso_days_to_beginning_of_day({730_485, {46_800_000_000, 86_400_000_000}})\n      {730485, {0, 86400000000}}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @impl true\n  @spec iso_days_to_beginning_of_day(Calendar.iso_days()) :: Calendar.iso_days()\n  def iso_days_to_beginning_of_day({days, _day_fraction}) do\n    {days, {0, @parts_per_day}}\n  end\n\n  @doc \"\"\"\n  Converts the `t:Calendar.iso_days/0` to the last moment of the day.\n\n  ## Examples\n\n      iex> Calendar.ISO.iso_days_to_end_of_day({0, {0, 86_400_000_000}})\n      {0, {86399999999, 86400000000}}\n      iex> Calendar.ISO.iso_days_to_end_of_day({730_485, {43_200_000_000, 86_400_000_000}})\n      {730485, {86399999999, 86400000000}}\n      iex> Calendar.ISO.iso_days_to_end_of_day({730_485, {46_800_000_000, 86_400_000_000}})\n      {730485, {86399999999, 86400000000}}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @impl true\n  @spec iso_days_to_end_of_day(Calendar.iso_days()) :: Calendar.iso_days()\n  def iso_days_to_end_of_day({days, _day_fraction}) do\n    {days, {@parts_per_day - 1, @parts_per_day}}\n  end\n\n  @doc \"\"\"\n  Shifts Date by Duration according to its calendar.\n\n  ## Examples\n\n      iex> Calendar.ISO.shift_date(2016, 1, 3, Duration.new!(month: 2))\n      {2016, 3, 3}\n      iex> Calendar.ISO.shift_date(2016, 2, 29, Duration.new!(month: 1))\n      {2016, 3, 29}\n      iex> Calendar.ISO.shift_date(2016, 1, 31, Duration.new!(month: 1))\n      {2016, 2, 29}\n      iex> Calendar.ISO.shift_date(2016, 1, 31, Duration.new!(year: 4, day: 1))\n      {2020, 2, 1}\n  \"\"\"\n  @impl true\n  @spec shift_date(year, month, day, Duration.t()) :: {year, month, day}\n  def shift_date(year, month, day, duration) do\n    shift_options = shift_date_options(duration)\n\n    Enum.reduce(shift_options, {year, month, day}, fn\n      {_, 0}, date ->\n        date\n\n      {:month, value}, date ->\n        shift_months(date, value)\n\n      {:day, value}, date ->\n        shift_days(date, value)\n    end)\n  end\n\n  @doc \"\"\"\n  Shifts NaiveDateTime by Duration according to its calendar.\n\n  ## Examples\n\n      iex> Calendar.ISO.shift_naive_datetime(2016, 1, 3, 0, 0, 0, {0, 0}, Duration.new!(hour: 1))\n      {2016, 1, 3, 1, 0, 0, {0, 0}}\n      iex> Calendar.ISO.shift_naive_datetime(2016, 1, 3, 0, 0, 0, {0, 0}, Duration.new!(hour: 30))\n      {2016, 1, 4, 6, 0, 0, {0, 0}}\n      iex> Calendar.ISO.shift_naive_datetime(2016, 1, 3, 0, 0, 0, {0, 0}, Duration.new!(microsecond: {100, 6}))\n      {2016, 1, 3, 0, 0, 0, {100, 6}}\n  \"\"\"\n  @impl true\n  @spec shift_naive_datetime(\n          year,\n          month,\n          day,\n          hour,\n          minute,\n          second,\n          microsecond,\n          Duration.t()\n        ) :: {year, month, day, hour, minute, second, microsecond}\n  def shift_naive_datetime(year, month, day, hour, minute, second, microsecond, duration) do\n    shift_options = shift_datetime_options(duration)\n\n    Enum.reduce(shift_options, {year, month, day, hour, minute, second, microsecond}, fn\n      {_, 0}, naive_datetime ->\n        naive_datetime\n\n      {:month, value}, {year, month, day, hour, minute, second, microsecond} ->\n        {new_year, new_month, new_day} = shift_months({year, month, day}, value)\n        {new_year, new_month, new_day, hour, minute, second, microsecond}\n\n      {time_unit, value}, naive_datetime ->\n        shift_time_unit(naive_datetime, value, time_unit)\n    end)\n  end\n\n  @doc \"\"\"\n  Shifts Time by Duration units according to its calendar.\n\n  ## Examples\n\n      iex> Calendar.ISO.shift_time(13, 0, 0, {0, 0}, Duration.new!(hour: 2))\n      {15, 0, 0, {0, 0}}\n      iex> Calendar.ISO.shift_time(13, 0, 0, {0, 0}, Duration.new!(microsecond: {100, 6}))\n      {13, 0, 0, {100, 6}}\n  \"\"\"\n  @impl true\n  @spec shift_time(hour, minute, second, microsecond, Duration.t()) ::\n          {hour, minute, second, microsecond}\n  def shift_time(hour, minute, second, microsecond, duration) do\n    shift_options = shift_time_options(duration)\n\n    Enum.reduce(shift_options, {hour, minute, second, microsecond}, fn\n      {_, 0}, time ->\n        time\n\n      {time_unit, value}, time ->\n        shift_time_unit(time, value, time_unit)\n    end)\n  end\n\n  @doc false\n  def shift_days({year, month, day}, days) do\n    {year, month, day} =\n      date_to_iso_days(year, month, day)\n      |> Kernel.+(days)\n      |> date_from_iso_days()\n\n    {year, month, day}\n  end\n\n  defp shift_months({year, month, day}, months) do\n    months_in_year = 12\n    total_months = year * months_in_year + month + months - 1\n\n    new_year = floor_div_positive_divisor(total_months, months_in_year)\n\n    new_month =\n      case rem(total_months, months_in_year) + 1 do\n        new_month when new_month < 1 -> new_month + months_in_year\n        new_month -> new_month\n      end\n\n    new_day = min(day, days_in_month(new_year, new_month))\n\n    {new_year, new_month, new_day}\n  end\n\n  @doc false\n  def shift_time_unit({year, month, day, hour, minute, second, microsecond}, value, unit)\n      when unit in [:second, :millisecond, :microsecond, :nanosecond] or is_integer(unit) do\n    {value, precision} = shift_time_unit_values(value, microsecond)\n\n    {year, month, day, hour, minute, second, {ms_value, _}} =\n      naive_datetime_to_iso_days(year, month, day, hour, minute, second, microsecond)\n      |> shift_time_unit(value, unit)\n      |> naive_datetime_from_iso_days()\n\n    {year, month, day, hour, minute, second, {ms_value, precision}}\n  end\n\n  def shift_time_unit({hour, minute, second, microsecond}, value, unit)\n      when unit in [:second, :millisecond, :microsecond, :nanosecond] or is_integer(unit) do\n    {value, precision} = shift_time_unit_values(value, microsecond)\n\n    {_days, day_fraction} =\n      shift_time_unit({0, time_to_day_fraction(hour, minute, second, microsecond)}, value, unit)\n\n    {hour, minute, second, {microsecond, _}} = time_from_day_fraction(day_fraction)\n\n    {hour, minute, second, {microsecond, precision}}\n  end\n\n  def shift_time_unit({_days, _day_fraction} = iso_days, value, unit)\n      when unit in [:second, :millisecond, :microsecond, :nanosecond] or is_integer(unit) do\n    ppd = System.convert_time_unit(86_400, :second, unit)\n    add_day_fraction_to_iso_days(iso_days, value, ppd)\n  end\n\n  defp shift_time_unit_values({0, _}, {_, original_precision}) do\n    {0, original_precision}\n  end\n\n  defp shift_time_unit_values({ms_value, ms_precision}, {_, _}) do\n    {ms_value, ms_precision}\n  end\n\n  defp shift_time_unit_values(value, {_, original_precision}) do\n    {value, original_precision}\n  end\n\n  defp shift_date_options(%Duration{\n         year: year,\n         month: month,\n         week: week,\n         day: day,\n         hour: 0,\n         minute: 0,\n         second: 0,\n         microsecond: {0, _precision}\n       }) do\n    [\n      month: year * 12 + month,\n      day: week * 7 + day\n    ]\n  end\n\n  defp shift_date_options(_duration) do\n    raise ArgumentError,\n          \"cannot shift date by time scale unit. Expected :year, :month, :week, :day\"\n  end\n\n  defp shift_datetime_options(%Duration{\n         year: year,\n         month: month,\n         week: week,\n         day: day,\n         hour: hour,\n         minute: minute,\n         second: second,\n         microsecond: microsecond\n       }) do\n    [\n      month: year * 12 + month,\n      second: week * 7 * 86_400 + day * 86_400 + hour * 3600 + minute * 60 + second,\n      microsecond: microsecond\n    ]\n  end\n\n  defp shift_time_options(%Duration{\n         year: 0,\n         month: 0,\n         week: 0,\n         day: 0,\n         hour: hour,\n         minute: minute,\n         second: second,\n         microsecond: microsecond\n       }) do\n    [\n      second: hour * 3600 + minute * 60 + second,\n      microsecond: microsecond\n    ]\n  end\n\n  defp shift_time_options(_duration) do\n    raise ArgumentError,\n          \"cannot shift time by date scale unit. Expected :hour, :minute, :second, :microsecond\"\n  end\n\n  ## Helpers\n\n  @doc false\n  def from_unix(integer, unit) when is_integer(integer) do\n    total = System.convert_time_unit(integer, unit, :microsecond)\n\n    if total in @unix_range_microseconds do\n      microseconds = Integer.mod(total, @microseconds_per_second)\n      seconds = @unix_epoch + floor_div_positive_divisor(total, @microseconds_per_second)\n      precision = precision_for_unit(unit)\n      {date, time} = iso_seconds_to_datetime(seconds)\n      {:ok, date, time, {microseconds, precision}}\n    else\n      {:error, :invalid_unix_time}\n    end\n  end\n\n  defp precision_for_unit(unit) do\n    case System.convert_time_unit(1, :second, unit) do\n      1 -> 0\n      10 -> 1\n      100 -> 2\n      1_000 -> 3\n      10_000 -> 4\n      100_000 -> 5\n      _ -> 6\n    end\n  end\n\n  defp parse_microsecond(\".\" <> rest) do\n    case parse_microsecond(rest, 0, []) do\n      {[], 0, _} ->\n        :error\n\n      {microsecond, precision, rest} ->\n        scale = scale_factor(precision)\n        {{:erlang.list_to_integer(microsecond) * scale, precision}, rest}\n    end\n  end\n\n  defp parse_microsecond(\",\" <> rest) do\n    parse_microsecond(\".\" <> rest)\n  end\n\n  defp parse_microsecond(rest) do\n    {{0, 0}, rest}\n  end\n\n  defp parse_microsecond(<<head, tail::binary>>, 6, acc) when head in ?0..?9,\n    do: parse_microsecond(tail, 6, acc)\n\n  defp parse_microsecond(<<head, tail::binary>>, precision, acc) when head in ?0..?9,\n    do: parse_microsecond(tail, precision + 1, [head | acc])\n\n  defp parse_microsecond(rest, precision, acc) do\n    {:lists.reverse(acc), precision, rest}\n  end\n\n  defp parse_offset(\"\"), do: {nil, \"\"}\n  defp parse_offset(\"Z\"), do: {0, \"\"}\n  defp parse_offset(\"-00:00\"), do: :error\n\n  defp parse_offset(<<?+, h1, h2, ?:, m1, m2, rest::binary>>),\n    do: parse_offset(1, h1, h2, m1, m2, rest)\n\n  defp parse_offset(<<?-, h1, h2, ?:, m1, m2, rest::binary>>),\n    do: parse_offset(-1, h1, h2, m1, m2, rest)\n\n  defp parse_offset(<<?+, h1, h2, m1, m2, rest::binary>>),\n    do: parse_offset(1, h1, h2, m1, m2, rest)\n\n  defp parse_offset(<<?-, h1, h2, m1, m2, rest::binary>>),\n    do: parse_offset(-1, h1, h2, m1, m2, rest)\n\n  defp parse_offset(<<?+, h1, h2, rest::binary>>), do: parse_offset(1, h1, h2, ?0, ?0, rest)\n  defp parse_offset(<<?-, h1, h2, rest::binary>>), do: parse_offset(-1, h1, h2, ?0, ?0, rest)\n  defp parse_offset(_), do: :error\n\n  defp parse_offset(sign, h1, h2, m1, m2, rest) do\n    with true <- h1 in ?0..?2 and h2 in ?0..?9,\n         true <- m1 in ?0..?5 and m2 in ?0..?9,\n         hour = (h1 - ?0) * 10 + h2 - ?0,\n         min = (m1 - ?0) * 10 + m2 - ?0,\n         true <- hour < 24 do\n      {(hour * 60 + min) * 60 * sign, rest}\n    else\n      _ -> :error\n    end\n  end\n\n  @doc false\n  def gregorian_seconds_to_iso_days(seconds, microsecond) do\n    {days, rest_seconds} = div_rem(seconds, @seconds_per_day)\n    microseconds_in_day = rest_seconds * @microseconds_per_second + microsecond\n    day_fraction = {microseconds_in_day, @parts_per_day}\n    {days, day_fraction}\n  end\n\n  @doc false\n  def iso_days_to_unit({days, {parts, ppd}}, unit) do\n    day_microseconds = days * @parts_per_day\n    microseconds = divide_by_parts_per_day(parts, ppd)\n    System.convert_time_unit(day_microseconds + microseconds, :microsecond, unit)\n  end\n\n  @doc false\n  def add_day_fraction_to_iso_days({days, {parts, ppd}}, add, ppd) do\n    normalize_iso_days(days, parts + add, ppd)\n  end\n\n  def add_day_fraction_to_iso_days({days, {parts, ppd}}, add, add_ppd) do\n    parts = parts * add_ppd\n    add = add * ppd\n    gcd = Integer.gcd(ppd, add_ppd)\n    result_parts = div(parts + add, gcd)\n    result_ppd = div(ppd * add_ppd, gcd)\n    normalize_iso_days(days, result_parts, result_ppd)\n  end\n\n  defp normalize_iso_days(days, parts, ppd) do\n    days_offset = div(parts, ppd)\n    parts = rem(parts, ppd)\n\n    if parts < 0 do\n      {days + days_offset - 1, {parts + ppd, ppd}}\n    else\n      {days + days_offset, {parts, ppd}}\n    end\n  end\n\n  defp leap_day_offset(_year, month) when month < 3, do: 0\n\n  defp leap_day_offset(year, _month) do\n    if leap_year?(year), do: 1, else: 0\n  end\n\n  defp days_before_month(1), do: 0\n  defp days_before_month(2), do: 31\n  defp days_before_month(3), do: 59\n  defp days_before_month(4), do: 90\n  defp days_before_month(5), do: 120\n  defp days_before_month(6), do: 151\n  defp days_before_month(7), do: 181\n  defp days_before_month(8), do: 212\n  defp days_before_month(9), do: 243\n  defp days_before_month(10), do: 273\n  defp days_before_month(11), do: 304\n  defp days_before_month(12), do: 334\n\n  defp iso_seconds_to_datetime(seconds) do\n    {days, rest_seconds} = div_rem(seconds, @seconds_per_day)\n\n    date = date_from_iso_days(days)\n    time = seconds_to_time(rest_seconds)\n    {date, time}\n  end\n\n  defp seconds_to_time(seconds) when seconds in 0..@last_second_of_the_day do\n    {hour, rest_seconds} = div_rem(seconds, @seconds_per_hour)\n    {minute, second} = div_rem(rest_seconds, @seconds_per_minute)\n\n    {hour, minute, second}\n  end\n\n  defp ensure_day_in_month!(year, month, day) when is_integer(day) do\n    if day < 1 or day > days_in_month(year, month) do\n      raise ArgumentError, \"invalid date: #{date_to_string(year, month, day)}\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar/naive_datetime.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule NaiveDateTime do\n  @moduledoc \"\"\"\n  A NaiveDateTime struct (without a time zone) and functions.\n\n  The NaiveDateTime struct contains the fields year, month, day, hour,\n  minute, second, microsecond and calendar. New naive datetimes can be\n  built with the `new/2` and `new/8` functions or using the\n  `~N` (see `sigil_N/2`) sigil:\n\n      iex> ~N[2000-01-01 23:00:07]\n      ~N[2000-01-01 23:00:07]\n\n  The date and time fields in the struct can be accessed directly:\n\n      iex> naive = ~N[2000-01-01 23:00:07]\n      iex> naive.year\n      2000\n      iex> naive.second\n      7\n\n  We call them \"naive\" because this datetime representation does not\n  have a time zone. This means the datetime may not actually exist in\n  certain areas in the world even though it is valid.\n\n  For example, when daylight saving changes are applied by a region,\n  the clock typically moves forward or backward by one hour. This means\n  certain datetimes never occur or may occur more than once. Since\n  `NaiveDateTime` is not validated against a time zone, such errors\n  would go unnoticed.\n\n  Developers should avoid creating the NaiveDateTime structs directly\n  and instead, rely on the functions provided by this module as well\n  as the ones in third-party calendar libraries.\n\n  ## Comparing naive date times\n\n  Comparisons in Elixir using `==/2`, `>/2`, `</2` and similar are structural\n  and based on the `NaiveDateTime` struct fields. For proper comparison\n  between naive datetimes, use the `compare/2`, `after?/2` and `before?/2` functions.\n  The existence of the `compare/2` function in this module also allows\n  using `Enum.min/2` and `Enum.max/2` functions to get the minimum and\n  maximum naive datetime of an `Enum`. For example:\n\n      iex> Enum.min([~N[2020-01-01 23:00:07], ~N[2000-01-01 23:00:07]], NaiveDateTime)\n      ~N[2000-01-01 23:00:07]\n\n  ## Using epochs\n\n  The `add/3` and `diff/3` functions can be used for computing date\n  times or retrieving the number of seconds between instants.\n  For example, if there is an interest in computing the number of\n  seconds from the Unix epoch (1970-01-01 00:00:00):\n\n      iex> NaiveDateTime.diff(~N[2010-04-17 14:00:00], ~N[1970-01-01 00:00:00])\n      1271512800\n\n      iex> NaiveDateTime.add(~N[1970-01-01 00:00:00], 1_271_512_800)\n      ~N[2010-04-17 14:00:00]\n\n  Those functions are optimized to deal with common epochs, such\n  as the Unix Epoch above or the Gregorian Epoch (0000-01-01 00:00:00).\n  \"\"\"\n\n  @enforce_keys [:year, :month, :day, :hour, :minute, :second]\n  defstruct [\n    :year,\n    :month,\n    :day,\n    :hour,\n    :minute,\n    :second,\n    microsecond: {0, 0},\n    calendar: Calendar.ISO\n  ]\n\n  @type t :: %__MODULE__{\n          year: Calendar.year(),\n          month: Calendar.month(),\n          day: Calendar.day(),\n          calendar: Calendar.calendar(),\n          hour: Calendar.hour(),\n          minute: Calendar.minute(),\n          second: Calendar.second(),\n          microsecond: Calendar.microsecond()\n        }\n\n  @seconds_per_day 24 * 60 * 60\n\n  @doc \"\"\"\n  Returns the current naive datetime in UTC.\n\n  Prefer using `DateTime.utc_now/0` when possible as, opposite\n  to `NaiveDateTime`, it will keep the time zone information.\n\n  You can also provide a time unit to automatically truncate\n  the naive datetime. This is available since v1.15.0.\n\n  ## Examples\n\n      iex> naive_datetime = NaiveDateTime.utc_now()\n      iex> naive_datetime.year >= 2016\n      true\n\n      iex> naive_datetime = NaiveDateTime.utc_now(:second)\n      iex> naive_datetime.microsecond\n      {0, 0}\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec utc_now(Calendar.calendar() | :native | :microsecond | :millisecond | :second) :: t\n  def utc_now(calendar_or_time_unit \\\\ Calendar.ISO)\n\n  def utc_now(time_unit) when time_unit in [:microsecond, :millisecond, :second, :native] do\n    utc_now(time_unit, Calendar.ISO)\n  end\n\n  def utc_now(calendar) do\n    utc_now(:native, calendar)\n  end\n\n  @doc \"\"\"\n  Returns the current naive datetime in UTC, supporting a specific\n  calendar and precision.\n\n  Prefer using `DateTime.utc_now/2` when possible as, opposite\n  to `NaiveDateTime`, it will keep the time zone information.\n\n  ## Examples\n\n      iex> naive_datetime = NaiveDateTime.utc_now(:second, Calendar.ISO)\n      iex> naive_datetime.year >= 2016\n      true\n\n      iex> naive_datetime = NaiveDateTime.utc_now(:second, Calendar.ISO)\n      iex> naive_datetime.microsecond\n      {0, 0}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec utc_now(:native | :microsecond | :millisecond | :second, Calendar.calendar()) :: t\n  def utc_now(time_unit, calendar)\n      when time_unit in [:native, :microsecond, :millisecond, :second] do\n    {:ok, {year, month, day}, {hour, minute, second}, microsecond} =\n      Calendar.ISO.from_unix(System.os_time(time_unit), time_unit)\n\n    %NaiveDateTime{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      calendar: Calendar.ISO\n    }\n    |> convert!(calendar)\n  end\n\n  @doc \"\"\"\n  Returns the \"local time\" for the machine the Elixir program is running on.\n\n  WARNING: This function can cause insidious bugs. It depends on the time zone\n  configuration at run time. This can changed and be set to a time zone that has\n  daylight saving jumps (spring forward or fall back).\n\n  This function can be used to display what the time is right now for the time\n  zone configuration that the machine happens to have. An example would be a\n  desktop program displaying a clock to the user. For any other uses it is\n  probably a bad idea to use this function.\n\n  For most cases, use `DateTime.now/2` or `DateTime.utc_now/1` instead.\n\n  Does not include fractional seconds.\n\n  ## Examples\n\n      iex> naive_datetime = NaiveDateTime.local_now()\n      iex> naive_datetime.year >= 2019\n      true\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec local_now(Calendar.calendar()) :: t\n  def local_now(calendar \\\\ Calendar.ISO)\n\n  def local_now(Calendar.ISO) do\n    {{year, month, day}, {hour, minute, second}} = :erlang.localtime()\n    {:ok, ndt} = NaiveDateTime.new(year, month, day, hour, minute, second)\n    ndt\n  end\n\n  def local_now(calendar) do\n    naive_datetime = local_now()\n\n    case convert(naive_datetime, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, :incompatible_calendars} ->\n        raise ArgumentError,\n              ~s(cannot get \"local now\" in target calendar #{inspect(calendar)}, ) <>\n                \"reason: cannot convert from Calendar.ISO to #{inspect(calendar)}.\"\n    end\n  end\n\n  @doc \"\"\"\n  Builds a new ISO naive datetime.\n\n  Expects all values to be integers. Returns `{:ok, naive_datetime}`\n  if each entry fits its appropriate range, returns `{:error, reason}`\n  otherwise.\n\n  ## Examples\n\n      iex> NaiveDateTime.new(2000, 1, 1, 0, 0, 0)\n      {:ok, ~N[2000-01-01 00:00:00]}\n      iex> NaiveDateTime.new(2000, 13, 1, 0, 0, 0)\n      {:error, :invalid_date}\n      iex> NaiveDateTime.new(2000, 2, 29, 0, 0, 0)\n      {:ok, ~N[2000-02-29 00:00:00]}\n      iex> NaiveDateTime.new(2000, 2, 30, 0, 0, 0)\n      {:error, :invalid_date}\n      iex> NaiveDateTime.new(2001, 2, 29, 0, 0, 0)\n      {:error, :invalid_date}\n\n      iex> NaiveDateTime.new(2000, 1, 1, 23, 59, 59, {0, 1})\n      {:ok, ~N[2000-01-01 23:59:59.0]}\n      iex> NaiveDateTime.new(2000, 1, 1, 23, 59, 59, 999_999)\n      {:ok, ~N[2000-01-01 23:59:59.999999]}\n      iex> NaiveDateTime.new(2000, 1, 1, 24, 59, 59, 999_999)\n      {:error, :invalid_time}\n      iex> NaiveDateTime.new(2000, 1, 1, 23, 60, 59, 999_999)\n      {:error, :invalid_time}\n      iex> NaiveDateTime.new(2000, 1, 1, 23, 59, 60, 999_999)\n      {:error, :invalid_time}\n      iex> NaiveDateTime.new(2000, 1, 1, 23, 59, 59, 1_000_000)\n      {:error, :invalid_time}\n\n      iex> NaiveDateTime.new(2000, 1, 1, 23, 59, 59, {0, 1}, Calendar.ISO)\n      {:ok, ~N[2000-01-01 23:59:59.0]}\n\n  \"\"\"\n  @spec new(\n          Calendar.year(),\n          Calendar.month(),\n          Calendar.day(),\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond() | non_neg_integer(),\n          Calendar.calendar()\n        ) :: {:ok, t} | {:error, atom}\n  def new(year, month, day, hour, minute, second, microsecond \\\\ {0, 0}, calendar \\\\ Calendar.ISO)\n\n  def new(year, month, day, hour, minute, second, microsecond, calendar)\n      when is_integer(microsecond) do\n    new(year, month, day, hour, minute, second, {microsecond, 6}, calendar)\n  end\n\n  def new(year, month, day, hour, minute, second, microsecond, calendar) do\n    cond do\n      not calendar.valid_date?(year, month, day) ->\n        {:error, :invalid_date}\n\n      not calendar.valid_time?(hour, minute, second, microsecond) ->\n        {:error, :invalid_time}\n\n      true ->\n        naive_datetime = %NaiveDateTime{\n          calendar: calendar,\n          year: year,\n          month: month,\n          day: day,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond\n        }\n\n        {:ok, naive_datetime}\n    end\n  end\n\n  @doc \"\"\"\n  Builds a new ISO naive datetime.\n\n  Expects all values to be integers. Returns `naive_datetime`\n  if each entry fits its appropriate range, raises if\n  time or date is invalid.\n\n  ## Examples\n\n      iex> NaiveDateTime.new!(2000, 1, 1, 0, 0, 0)\n      ~N[2000-01-01 00:00:00]\n      iex> NaiveDateTime.new!(2000, 2, 29, 0, 0, 0)\n      ~N[2000-02-29 00:00:00]\n      iex> NaiveDateTime.new!(2000, 1, 1, 23, 59, 59, {0, 1})\n      ~N[2000-01-01 23:59:59.0]\n      iex> NaiveDateTime.new!(2000, 1, 1, 23, 59, 59, 999_999)\n      ~N[2000-01-01 23:59:59.999999]\n      iex> NaiveDateTime.new!(2000, 1, 1, 23, 59, 59, {0, 1}, Calendar.ISO)\n      ~N[2000-01-01 23:59:59.0]\n      iex> NaiveDateTime.new!(2000, 1, 1, 24, 59, 59, 999_999)\n      ** (ArgumentError) cannot build naive datetime, reason: :invalid_time\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec new!(\n          Calendar.year(),\n          Calendar.month(),\n          Calendar.day(),\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond() | non_neg_integer(),\n          Calendar.calendar()\n        ) :: t\n  def new!(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond \\\\ {0, 0},\n        calendar \\\\ Calendar.ISO\n      )\n\n  def new!(year, month, day, hour, minute, second, microsecond, calendar) do\n    case new(year, month, day, hour, minute, second, microsecond, calendar) do\n      {:ok, naive_datetime} ->\n        naive_datetime\n\n      {:error, reason} ->\n        raise ArgumentError, \"cannot build naive datetime, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Builds a naive datetime from date and time structs.\n\n  ## Examples\n\n      iex> NaiveDateTime.new(~D[2010-01-13], ~T[23:00:07.005])\n      {:ok, ~N[2010-01-13 23:00:07.005]}\n\n  \"\"\"\n  @spec new(Date.t(), Time.t()) :: {:ok, t}\n  def new(date, time)\n\n  def new(%Date{calendar: calendar} = date, %Time{calendar: calendar} = time) do\n    %{year: year, month: month, day: day} = date\n    %{hour: hour, minute: minute, second: second, microsecond: microsecond} = time\n\n    naive_datetime = %NaiveDateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    }\n\n    {:ok, naive_datetime}\n  end\n\n  @doc \"\"\"\n  Builds a naive datetime from date and time structs.\n\n  ## Examples\n\n      iex> NaiveDateTime.new!(~D[2010-01-13], ~T[23:00:07.005])\n      ~N[2010-01-13 23:00:07.005]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec new!(Date.t(), Time.t()) :: t\n  def new!(date, time)\n\n  def new!(%Date{calendar: calendar} = date, %Time{calendar: calendar} = time) do\n    {:ok, naive_datetime} = new(date, time)\n    naive_datetime\n  end\n\n  @doc \"\"\"\n  Adds a specified amount of time to a `NaiveDateTime`.\n\n  > #### Prefer `shift/2` {: .info}\n  >\n  > Prefer `shift/2` over `add/3`, as it offers a more ergonomic API.\n  >\n  > `add/3` provides a lower-level API which only supports fixed units\n  > such as `:hour` and `:second`, but not `:month` (as the exact length\n  > of a month depends on the current month). `add/3` always considers\n  > the unit to be computed according to the `Calendar.ISO`.\n\n  Accepts an `amount_to_add` in any `unit`. `unit` can be `:day`,\n  `:hour`, `:minute`, `:second` or any subsecond precision from\n  `t:System.time_unit/0` for convenience but ultimately they are\n  all converted to microseconds. Negative values will move backwards\n  in time and the default precision is `:second`.\n\n  ## Examples\n\n  It uses seconds by default:\n\n      # adds seconds by default\n      iex> NaiveDateTime.add(~N[2014-10-02 00:29:10], 2)\n      ~N[2014-10-02 00:29:12]\n\n      # accepts negative offsets\n      iex> NaiveDateTime.add(~N[2014-10-02 00:29:10], -2)\n      ~N[2014-10-02 00:29:08]\n\n  It can also work with subsecond precisions:\n\n      iex> NaiveDateTime.add(~N[2014-10-02 00:29:10], 2_000, :millisecond)\n      ~N[2014-10-02 00:29:12.000]\n\n  As well as days/hours/minutes:\n\n      iex> NaiveDateTime.add(~N[2015-02-28 00:29:10], 2, :day)\n      ~N[2015-03-02 00:29:10]\n      iex> NaiveDateTime.add(~N[2015-02-28 00:29:10], 36, :hour)\n      ~N[2015-03-01 12:29:10]\n      iex> NaiveDateTime.add(~N[2015-02-28 00:29:10], 60, :minute)\n      ~N[2015-02-28 01:29:10]\n\n  This operation merges the precision of the naive date time with the given unit:\n\n      iex> result = NaiveDateTime.add(~N[2014-10-02 00:29:10], 21, :millisecond)\n      ~N[2014-10-02 00:29:10.021]\n      iex> result.microsecond\n      {21000, 3}\n\n  Operations on top of gregorian seconds or the Unix epoch are optimized:\n\n      # from Gregorian seconds\n      iex> NaiveDateTime.add(~N[0000-01-01 00:00:00], 63_579_428_950)\n      ~N[2014-10-02 00:29:10]\n\n  Passing a `DateTime` automatically converts it to `NaiveDateTime`,\n  discarding the time zone information:\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> NaiveDateTime.add(dt, 21, :second)\n      ~N[2000-02-29 23:00:28]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec add(Calendar.naive_datetime(), integer, :day | :hour | :minute | System.time_unit()) :: t\n  def add(naive_datetime, amount_to_add, unit \\\\ :second)\n\n  def add(naive_datetime, amount_to_add, :day) when is_integer(amount_to_add) do\n    add(naive_datetime, amount_to_add * 86400, :second)\n  end\n\n  def add(naive_datetime, amount_to_add, :hour) when is_integer(amount_to_add) do\n    add(naive_datetime, amount_to_add * 3600, :second)\n  end\n\n  def add(naive_datetime, amount_to_add, :minute) when is_integer(amount_to_add) do\n    add(naive_datetime, amount_to_add * 60, :second)\n  end\n\n  def add(\n        %{calendar: calendar, microsecond: {_, precision}} = naive_datetime,\n        amount_to_add,\n        unit\n      )\n      when is_integer(amount_to_add) do\n    if not is_integer(unit) and unit not in ~w(second millisecond microsecond nanosecond)a do\n      raise ArgumentError,\n            \"unsupported time unit. Expected :day, :hour, :minute, :second, :millisecond, :microsecond, :nanosecond, or a positive integer, got #{inspect(unit)}\"\n    end\n\n    precision = max(Calendar.ISO.time_unit_to_precision(unit), precision)\n\n    naive_datetime\n    |> to_iso_days()\n    |> Calendar.ISO.shift_time_unit(amount_to_add, unit)\n    |> from_iso_days(calendar, precision)\n  end\n\n  @doc \"\"\"\n  Subtracts `naive_datetime2` from `naive_datetime1`.\n\n  The answer can be returned in any `:day`, `:hour`, `:minute`, or any `unit`\n  available from `t:System.time_unit/0`. The unit is measured according to\n  `Calendar.ISO` and defaults to `:second`.\n\n  Fractional results are not supported and are truncated.\n\n  ## Examples\n\n      iex> NaiveDateTime.diff(~N[2014-10-02 00:29:12], ~N[2014-10-02 00:29:10])\n      2\n      iex> NaiveDateTime.diff(~N[2014-10-02 00:29:12], ~N[2014-10-02 00:29:10], :microsecond)\n      2_000_000\n\n      iex> NaiveDateTime.diff(~N[2014-10-02 00:29:10.042], ~N[2014-10-02 00:29:10.021])\n      0\n      iex> NaiveDateTime.diff(~N[2014-10-02 00:29:10.042], ~N[2014-10-02 00:29:10.021], :millisecond)\n      21\n\n      iex> NaiveDateTime.diff(~N[2014-10-02 00:29:10], ~N[2014-10-02 00:29:12])\n      -2\n      iex> NaiveDateTime.diff(~N[-0001-10-02 00:29:10], ~N[-0001-10-02 00:29:12])\n      -2\n\n  It can also compute the difference in days, hours, or minutes:\n\n      iex> NaiveDateTime.diff(~N[2014-10-10 00:29:10], ~N[2014-10-02 00:29:10], :day)\n      8\n      iex> NaiveDateTime.diff(~N[2014-10-02 12:29:10], ~N[2014-10-02 00:29:10], :hour)\n      12\n      iex> NaiveDateTime.diff(~N[2014-10-02 00:39:10], ~N[2014-10-02 00:29:10], :minute)\n      10\n\n  But it also rounds incomplete days to zero:\n\n      iex> NaiveDateTime.diff(~N[2014-10-10 00:29:09], ~N[2014-10-02 00:29:10], :day)\n      7\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec diff(\n          Calendar.naive_datetime(),\n          Calendar.naive_datetime(),\n          :day | :hour | :minute | System.time_unit()\n        ) :: integer\n\n  def diff(naive_datetime1, naive_datetime2, unit \\\\ :second)\n\n  def diff(naive_datetime1, naive_datetime2, :day) do\n    diff(naive_datetime1, naive_datetime2, :second) |> div(86400)\n  end\n\n  def diff(naive_datetime1, naive_datetime2, :hour) do\n    diff(naive_datetime1, naive_datetime2, :second) |> div(3600)\n  end\n\n  def diff(naive_datetime1, naive_datetime2, :minute) do\n    diff(naive_datetime1, naive_datetime2, :second) |> div(60)\n  end\n\n  def diff(\n        %{calendar: calendar1} = naive_datetime1,\n        %{calendar: calendar2} = naive_datetime2,\n        unit\n      ) do\n    if not Calendar.compatible_calendars?(calendar1, calendar2) do\n      raise ArgumentError,\n            \"cannot calculate the difference between #{inspect(naive_datetime1)} and \" <>\n              \"#{inspect(naive_datetime2)} because their calendars are not compatible \" <>\n              \"and thus the result would be ambiguous\"\n    end\n\n    if not is_integer(unit) and\n         unit not in ~w(second millisecond microsecond nanosecond)a do\n      raise ArgumentError,\n            \"unsupported time unit. Expected :day, :hour, :minute, :second, :millisecond, :microsecond, :nanosecond, or a positive integer, got #{inspect(unit)}\"\n    end\n\n    units1 = naive_datetime1 |> to_iso_days() |> Calendar.ISO.iso_days_to_unit(unit)\n    units2 = naive_datetime2 |> to_iso_days() |> Calendar.ISO.iso_days_to_unit(unit)\n    units1 - units2\n  end\n\n  @doc \"\"\"\n  Shifts given `naive_datetime` by `duration` according to its calendar.\n\n  Allowed units are: `:year`, `:month`, `:week`, `:day`, `:hour`, `:minute`, `:second`, `:microsecond`.\n\n  When using the default ISO calendar, durations are collapsed and\n  applied in the order of months, then seconds and microseconds:\n\n  * when shifting by 1 year and 2 months the date is actually shifted by 14 months\n  * weeks, days and smaller units are collapsed into seconds and microseconds\n\n  When shifting by month, days are rounded down to the nearest valid date.\n\n  ## Examples\n\n      iex> NaiveDateTime.shift(~N[2016-01-31 00:00:00], month: 1)\n      ~N[2016-02-29 00:00:00]\n      iex> NaiveDateTime.shift(~N[2016-01-31 00:00:00], year: 4, day: 1)\n      ~N[2020-02-01 00:00:00]\n      iex> NaiveDateTime.shift(~N[2016-01-31 00:00:00], year: -2, day: 1)\n      ~N[2014-02-01 00:00:00]\n      iex> NaiveDateTime.shift(~N[2016-01-31 00:00:00], second: 45)\n      ~N[2016-01-31 00:00:45]\n      iex> NaiveDateTime.shift(~N[2016-01-31 00:00:00], microsecond: {100, 6})\n      ~N[2016-01-31 00:00:00.000100]\n\n      # leap years\n      iex> NaiveDateTime.shift(~N[2024-02-29 00:00:00], year: 1)\n      ~N[2025-02-28 00:00:00]\n      iex> NaiveDateTime.shift(~N[2024-02-29 00:00:00], year: 4)\n      ~N[2028-02-29 00:00:00]\n\n      # rounding down\n      iex> NaiveDateTime.shift(~N[2015-01-31 00:00:00], month: 1)\n      ~N[2015-02-28 00:00:00]\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec shift(Calendar.naive_datetime(), Duration.duration()) :: t\n  def shift(%{calendar: calendar} = naive_datetime, duration) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    } = naive_datetime\n\n    {year, month, day, hour, minute, second, microsecond} =\n      calendar.shift_naive_datetime(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        __duration__!(duration)\n      )\n\n    %NaiveDateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    }\n  end\n\n  @doc false\n  defdelegate __duration__!(params), to: Duration, as: :new!\n\n  @doc \"\"\"\n  Returns the given naive datetime with the microsecond field truncated to the\n  given precision (`:microsecond`, `:millisecond` or `:second`).\n\n  The given naive datetime is returned unchanged if it already has lower precision\n  than the given precision.\n\n  ## Examples\n\n      iex> NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :microsecond)\n      ~N[2017-11-06 00:23:51.123456]\n\n      iex> NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :millisecond)\n      ~N[2017-11-06 00:23:51.123]\n\n      iex> NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :second)\n      ~N[2017-11-06 00:23:51]\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec truncate(t(), :microsecond | :millisecond | :second) :: t()\n  def truncate(%NaiveDateTime{microsecond: microsecond} = naive_datetime, precision) do\n    %{naive_datetime | microsecond: Calendar.truncate(microsecond, precision)}\n  end\n\n  def truncate(\n        %{\n          calendar: calendar,\n          year: year,\n          month: month,\n          day: day,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond\n        },\n        precision\n      ) do\n    %NaiveDateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: Calendar.truncate(microsecond, precision)\n    }\n  end\n\n  @doc \"\"\"\n  Converts a `NaiveDateTime` into a `Date`.\n\n  Because `Date` does not hold time information,\n  data will be lost during the conversion.\n\n  ## Examples\n\n      iex> NaiveDateTime.to_date(~N[2002-01-13 23:00:07])\n      ~D[2002-01-13]\n\n  \"\"\"\n  @spec to_date(Calendar.naive_datetime()) :: Date.t()\n  def to_date(%{\n        year: year,\n        month: month,\n        day: day,\n        calendar: calendar,\n        hour: _,\n        minute: _,\n        second: _,\n        microsecond: _\n      }) do\n    %Date{year: year, month: month, day: day, calendar: calendar}\n  end\n\n  @doc \"\"\"\n  Converts a `NaiveDateTime` into `Time`.\n\n  Because `Time` does not hold date information,\n  data will be lost during the conversion.\n\n  ## Examples\n\n      iex> NaiveDateTime.to_time(~N[2002-01-13 23:00:07])\n      ~T[23:00:07]\n\n  \"\"\"\n  @spec to_time(Calendar.naive_datetime()) :: Time.t()\n  def to_time(%{\n        year: _,\n        month: _,\n        day: _,\n        calendar: calendar,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond\n      }) do\n    %Time{\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      calendar: calendar\n    }\n  end\n\n  @doc \"\"\"\n  Converts the given naive datetime to a string according to its calendar.\n\n  For readability, this function follows the RFC3339 suggestion of removing\n  the \"T\" separator between the date and time components.\n\n  ## Examples\n\n      iex> NaiveDateTime.to_string(~N[2000-02-28 23:00:13])\n      \"2000-02-28 23:00:13\"\n      iex> NaiveDateTime.to_string(~N[2000-02-28 23:00:13.001])\n      \"2000-02-28 23:00:13.001\"\n      iex> NaiveDateTime.to_string(~N[-0100-12-15 03:20:31])\n      \"-0100-12-15 03:20:31\"\n\n  This function can also be used to convert a DateTime to a string without\n  the time zone information:\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> NaiveDateTime.to_string(dt)\n      \"2000-02-29 23:00:07\"\n\n  \"\"\"\n  @spec to_string(Calendar.naive_datetime()) :: String.t()\n  def to_string(%{calendar: calendar} = naive_datetime) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    } = naive_datetime\n\n    calendar.naive_datetime_to_string(year, month, day, hour, minute, second, microsecond)\n  end\n\n  @doc \"\"\"\n  Parses the extended \"Date and time of day\" format described by\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  Time zone offset may be included in the string but they will be\n  simply discarded as such information is not included in naive date\n  times.\n\n  As specified in the standard, the separator \"T\" may be omitted if\n  desired as there is no ambiguity within this function.\n\n  Note leap seconds are not supported by the built-in Calendar.ISO.\n\n  ## Examples\n\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23 23:50:07\")\n      {:ok, ~N[2015-01-23 23:50:07]}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07\")\n      {:ok, ~N[2015-01-23 23:50:07]}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07Z\")\n      {:ok, ~N[2015-01-23 23:50:07]}\n\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23 23:50:07.0\")\n      {:ok, ~N[2015-01-23 23:50:07.0]}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23 23:50:07,0123456\")\n      {:ok, ~N[2015-01-23 23:50:07.012345]}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23 23:50:07.0123456\")\n      {:ok, ~N[2015-01-23 23:50:07.012345]}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07.123Z\")\n      {:ok, ~N[2015-01-23 23:50:07.123]}\n\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23P23:50:07\")\n      {:error, :invalid_format}\n      iex> NaiveDateTime.from_iso8601(\"2015:01:23 23-50-07\")\n      {:error, :invalid_format}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23 23:50:07A\")\n      {:error, :invalid_format}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23 23:50:61\")\n      {:error, :invalid_time}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-32 23:50:07\")\n      {:error, :invalid_date}\n\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07.123+02:30\")\n      {:ok, ~N[2015-01-23 23:50:07.123]}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07.123+00:00\")\n      {:ok, ~N[2015-01-23 23:50:07.123]}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07.123-02:30\")\n      {:ok, ~N[2015-01-23 23:50:07.123]}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07.123-00:00\")\n      {:error, :invalid_format}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07.123-00:60\")\n      {:error, :invalid_format}\n      iex> NaiveDateTime.from_iso8601(\"2015-01-23T23:50:07.123-24:00\")\n      {:error, :invalid_format}\n\n  \"\"\"\n  @spec from_iso8601(String.t(), Calendar.calendar()) :: {:ok, t} | {:error, atom}\n  def from_iso8601(string, calendar \\\\ Calendar.ISO) do\n    with {:ok, {year, month, day, hour, minute, second, microsecond}} <-\n           Calendar.ISO.parse_naive_datetime(string) do\n      convert(\n        %NaiveDateTime{\n          year: year,\n          month: month,\n          day: day,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond\n        },\n        calendar\n      )\n    end\n  end\n\n  @doc \"\"\"\n  Parses the extended \"Date and time of day\" format described by\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  Raises if the format is invalid.\n\n  ## Examples\n\n      iex> NaiveDateTime.from_iso8601!(\"2015-01-23T23:50:07.123Z\")\n      ~N[2015-01-23 23:50:07.123]\n      iex> NaiveDateTime.from_iso8601!(\"2015-01-23T23:50:07,123Z\")\n      ~N[2015-01-23 23:50:07.123]\n      iex> NaiveDateTime.from_iso8601!(\"2015-01-23P23:50:07\")\n      ** (ArgumentError) cannot parse \"2015-01-23P23:50:07\" as naive datetime, reason: :invalid_format\n\n  \"\"\"\n  @spec from_iso8601!(String.t(), Calendar.calendar()) :: t\n  def from_iso8601!(string, calendar \\\\ Calendar.ISO) do\n    case from_iso8601(string, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot parse #{inspect(string)} as naive datetime, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given naive datetime to\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  By default, `NaiveDateTime.to_iso8601/2` returns naive datetimes formatted in the \"extended\"\n  format, for human readability. It also supports the \"basic\" format through passing the `:basic` option.\n\n  Only supports converting naive datetimes which are in the ISO calendar,\n  attempting to convert naive datetimes from other calendars will raise.\n\n  ## Examples\n\n      iex> NaiveDateTime.to_iso8601(~N[2000-02-28 23:00:13])\n      \"2000-02-28T23:00:13\"\n\n      iex> NaiveDateTime.to_iso8601(~N[2000-02-28 23:00:13.001])\n      \"2000-02-28T23:00:13.001\"\n\n      iex> NaiveDateTime.to_iso8601(~N[2000-02-28 23:00:13.001], :basic)\n      \"20000228T230013.001\"\n\n  This function can also be used to convert a DateTime to ISO 8601 without\n  the time zone information:\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> NaiveDateTime.to_iso8601(dt)\n      \"2000-02-29T23:00:07\"\n\n  \"\"\"\n  @spec to_iso8601(Calendar.naive_datetime(), :basic | :extended) :: String.t()\n  def to_iso8601(naive_datetime, format \\\\ :extended)\n\n  def to_iso8601(%{calendar: Calendar.ISO} = naive_datetime, format)\n      when format in [:basic, :extended] do\n    naive_datetime\n    |> to_iso8601_iodata(format)\n    |> IO.iodata_to_binary()\n  end\n\n  def to_iso8601(%{calendar: _} = naive_datetime, format)\n      when format in [:basic, :extended] do\n    naive_datetime\n    |> convert!(Calendar.ISO)\n    |> to_iso8601(format)\n  end\n\n  defp to_iso8601_iodata(naive_datetime, format) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    } = naive_datetime\n\n    [\n      Calendar.ISO.date_to_iodata(year, month, day, format),\n      ?T,\n      Calendar.ISO.time_to_iodata(hour, minute, second, microsecond, format)\n    ]\n  end\n\n  @doc \"\"\"\n  Converts a `NaiveDateTime` struct to an Erlang datetime tuple.\n\n  Only supports converting naive datetimes which are in the ISO calendar,\n  attempting to convert naive datetimes from other calendars will raise.\n\n  WARNING: Loss of precision may occur, as Erlang time tuples only store\n  hour/minute/second.\n\n  ## Examples\n\n      iex> NaiveDateTime.to_erl(~N[2000-01-01 13:30:15])\n      {{2000, 1, 1}, {13, 30, 15}}\n\n  This function can also be used to convert a DateTime to an Erlang\n  datetime tuple without the time zone information:\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> NaiveDateTime.to_erl(dt)\n      {{2000, 2, 29}, {23, 00, 07}}\n\n  \"\"\"\n  @spec to_erl(Calendar.naive_datetime()) :: :calendar.datetime()\n  def to_erl(%{calendar: _} = naive_datetime) do\n    %{year: year, month: month, day: day, hour: hour, minute: minute, second: second} =\n      convert!(naive_datetime, Calendar.ISO)\n\n    {{year, month, day}, {hour, minute, second}}\n  end\n\n  @doc \"\"\"\n  Converts an Erlang datetime tuple to a `NaiveDateTime` struct.\n\n  Attempting to convert an invalid ISO calendar date will produce an error tuple.\n\n  ## Examples\n\n      iex> NaiveDateTime.from_erl({{2000, 1, 1}, {13, 30, 15}})\n      {:ok, ~N[2000-01-01 13:30:15]}\n      iex> NaiveDateTime.from_erl({{2000, 1, 1}, {13, 30, 15}}, 5000)\n      {:ok, ~N[2000-01-01 13:30:15.005000]}\n      iex> NaiveDateTime.from_erl({{2000, 1, 1}, {13, 30, 15}}, {5000, 3})\n      {:ok, ~N[2000-01-01 13:30:15.005]}\n      iex> NaiveDateTime.from_erl({{2000, 13, 1}, {13, 30, 15}})\n      {:error, :invalid_date}\n      iex> NaiveDateTime.from_erl({{2000, 13, 1}, {13, 30, 15}})\n      {:error, :invalid_date}\n\n  \"\"\"\n  @spec from_erl(\n          :calendar.datetime(),\n          Calendar.microsecond() | non_neg_integer(),\n          Calendar.calendar()\n        ) ::\n          {:ok, t} | {:error, atom}\n  def from_erl(tuple, microsecond \\\\ {0, 0}, calendar \\\\ Calendar.ISO)\n\n  def from_erl({{year, month, day}, {hour, minute, second}}, microsecond, calendar) do\n    with {:ok, iso_naive_dt} <- new(year, month, day, hour, minute, second, microsecond),\n         do: convert(iso_naive_dt, calendar)\n  end\n\n  @doc \"\"\"\n  Converts an Erlang datetime tuple to a `NaiveDateTime` struct.\n\n  Raises if the datetime is invalid.\n  Attempting to convert an invalid ISO calendar date will produce an error tuple.\n\n  ## Examples\n\n      iex> NaiveDateTime.from_erl!({{2000, 1, 1}, {13, 30, 15}})\n      ~N[2000-01-01 13:30:15]\n      iex> NaiveDateTime.from_erl!({{2000, 1, 1}, {13, 30, 15}}, 5000)\n      ~N[2000-01-01 13:30:15.005000]\n      iex> NaiveDateTime.from_erl!({{2000, 1, 1}, {13, 30, 15}}, {5000, 3})\n      ~N[2000-01-01 13:30:15.005]\n      iex> NaiveDateTime.from_erl!({{2000, 13, 1}, {13, 30, 15}})\n      ** (ArgumentError) cannot convert {{2000, 13, 1}, {13, 30, 15}} to naive datetime, reason: :invalid_date\n\n  \"\"\"\n  @spec from_erl!(\n          :calendar.datetime(),\n          Calendar.microsecond() | non_neg_integer(),\n          Calendar.calendar()\n        ) :: t\n  def from_erl!(tuple, microsecond \\\\ {0, 0}, calendar \\\\ Calendar.ISO) do\n    case from_erl(tuple, microsecond, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(tuple)} to naive datetime, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts a number of gregorian seconds to a `NaiveDateTime` struct.\n\n  ## Examples\n\n      iex> NaiveDateTime.from_gregorian_seconds(1)\n      ~N[0000-01-01 00:00:01]\n      iex> NaiveDateTime.from_gregorian_seconds(63_755_511_991, {5000, 3})\n      ~N[2020-05-01 00:26:31.005]\n      iex> NaiveDateTime.from_gregorian_seconds(-1)\n      ~N[-0001-12-31 23:59:59]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec from_gregorian_seconds(integer(), Calendar.microsecond(), Calendar.calendar()) :: t\n  def from_gregorian_seconds(seconds, microsecond_precision \\\\ {0, 0}, calendar \\\\ Calendar.ISO)\n\n  def from_gregorian_seconds(seconds, {microsecond, precision}, Calendar.ISO)\n      when is_integer(seconds) do\n    {days, seconds} = div_rem(seconds, 24 * 60 * 60)\n    {hours, seconds} = div_rem(seconds, 60 * 60)\n    {minutes, seconds} = div_rem(seconds, 60)\n    {year, month, day} = Calendar.ISO.date_from_iso_days(days)\n\n    %NaiveDateTime{\n      calendar: Calendar.ISO,\n      year: year,\n      month: month,\n      day: day,\n      hour: hours,\n      minute: minutes,\n      second: seconds,\n      microsecond: {microsecond, precision}\n    }\n  end\n\n  def from_gregorian_seconds(seconds, {microsecond, precision}, calendar)\n      when is_integer(seconds) do\n    iso_days = Calendar.ISO.gregorian_seconds_to_iso_days(seconds, microsecond)\n\n    {year, month, day, hour, minute, second, {microsecond, _}} =\n      calendar.naive_datetime_from_iso_days(iso_days)\n\n    %NaiveDateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: {microsecond, precision}\n    }\n  end\n\n  defp div_rem(int1, int2) do\n    div = div(int1, int2)\n    rem = int1 - div * int2\n\n    if rem >= 0 do\n      {div, rem}\n    else\n      {div - 1, rem + int2}\n    end\n  end\n\n  @doc \"\"\"\n  Converts a `NaiveDateTime` struct to a number of gregorian seconds and microseconds.\n\n  ## Examples\n\n      iex> NaiveDateTime.to_gregorian_seconds(~N[0000-01-01 00:00:01])\n      {1, 0}\n      iex> NaiveDateTime.to_gregorian_seconds(~N[2020-05-01 00:26:31.005])\n      {63_755_511_991, 5000}\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec to_gregorian_seconds(Calendar.naive_datetime()) :: {integer(), non_neg_integer()}\n  def to_gregorian_seconds(%{\n        calendar: calendar,\n        year: year,\n        month: month,\n        day: day,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: {microsecond, precision}\n      }) do\n    {days, day_fraction} =\n      calendar.naive_datetime_to_iso_days(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        {microsecond, precision}\n      )\n\n    seconds_in_day = seconds_from_day_fraction(day_fraction)\n    {days * @seconds_per_day + seconds_in_day, microsecond}\n  end\n\n  @doc \"\"\"\n  Compares two `NaiveDateTime` structs.\n\n  Returns `:gt` if first is later than the second\n  and `:lt` for vice versa. If the two NaiveDateTime\n  are equal `:eq` is returned.\n\n  ## Examples\n\n      iex> NaiveDateTime.compare(~N[2016-04-16 13:30:15], ~N[2016-04-28 16:19:25])\n      :lt\n      iex> NaiveDateTime.compare(~N[2016-04-16 13:30:15.1], ~N[2016-04-16 13:30:15.01])\n      :gt\n\n  This function can also be used to compare a DateTime without\n  the time zone information:\n\n      iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: \"CET\",\n      ...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},\n      ...>                utc_offset: 3600, std_offset: 0, time_zone: \"Europe/Warsaw\"}\n      iex> NaiveDateTime.compare(dt, ~N[2000-02-29 23:00:07])\n      :eq\n      iex> NaiveDateTime.compare(dt, ~N[2000-01-29 23:00:07])\n      :gt\n      iex> NaiveDateTime.compare(dt, ~N[2000-03-29 23:00:07])\n      :lt\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec compare(Calendar.naive_datetime(), Calendar.naive_datetime()) :: :lt | :eq | :gt\n  def compare(%{calendar: calendar1} = naive_datetime1, %{calendar: calendar2} = naive_datetime2) do\n    if Calendar.compatible_calendars?(calendar1, calendar2) do\n      case {to_iso_days(naive_datetime1), to_iso_days(naive_datetime2)} do\n        {first, second} when first > second -> :gt\n        {first, second} when first < second -> :lt\n        _ -> :eq\n      end\n    else\n      raise ArgumentError, \"\"\"\n      cannot compare #{inspect(naive_datetime1)} with #{inspect(naive_datetime2)}.\n\n      This comparison would be ambiguous as their calendars have incompatible day rollover moments.\n      Specify an exact time of day (using `DateTime`s) to resolve this ambiguity\n      \"\"\"\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if the first `NaiveDateTime` is strictly earlier than the second.\n\n  ## Examples\n\n      iex> NaiveDateTime.before?(~N[2021-01-01 11:00:00], ~N[2022-02-02 11:00:00])\n      true\n      iex> NaiveDateTime.before?(~N[2021-01-01 11:00:00], ~N[2021-01-01 11:00:00])\n      false\n      iex> NaiveDateTime.before?(~N[2022-02-02 11:00:00], ~N[2021-01-01 11:00:00])\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec before?(Calendar.naive_datetime(), Calendar.naive_datetime()) :: boolean()\n  def before?(naive_datetime1, naive_datetime2) do\n    compare(naive_datetime1, naive_datetime2) == :lt\n  end\n\n  @doc \"\"\"\n  Returns `true` if the first `NaiveDateTime` is strictly later than the second.\n\n  ## Examples\n\n      iex> NaiveDateTime.after?(~N[2022-02-02 11:00:00], ~N[2021-01-01 11:00:00])\n      true\n      iex> NaiveDateTime.after?(~N[2021-01-01 11:00:00], ~N[2021-01-01 11:00:00])\n      false\n      iex> NaiveDateTime.after?(~N[2021-01-01 11:00:00], ~N[2022-02-02 11:00:00])\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec after?(Calendar.naive_datetime(), Calendar.naive_datetime()) :: boolean()\n  def after?(naive_datetime1, naive_datetime2) do\n    compare(naive_datetime1, naive_datetime2) == :gt\n  end\n\n  @doc \"\"\"\n  Converts the given `naive_datetime` from one calendar to another.\n\n  If it is not possible to convert unambiguously between the calendars\n  (see `Calendar.compatible_calendars?/2`), an `{:error, :incompatible_calendars}` tuple\n  is returned.\n\n  ## Examples\n\n  Imagine someone implements `Calendar.Holocene`, a calendar based on the\n  Gregorian calendar that adds exactly 10 000 years to the current Gregorian\n  year:\n\n      iex> NaiveDateTime.convert(~N[2000-01-01 13:30:15], Calendar.Holocene)\n      {:ok, %NaiveDateTime{calendar: Calendar.Holocene, year: 12000, month: 1, day: 1,\n                           hour: 13, minute: 30, second: 15, microsecond: {0, 0}}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec convert(Calendar.naive_datetime(), Calendar.calendar()) ::\n          {:ok, t} | {:error, :incompatible_calendars}\n\n  # Keep it multiline for proper function clause errors.\n  def convert(%NaiveDateTime{calendar: calendar} = ndt, calendar) do\n    {:ok, ndt}\n  end\n\n  def convert(\n        %{\n          calendar: calendar,\n          year: year,\n          month: month,\n          day: day,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond\n        },\n        calendar\n      ) do\n    naive_datetime = %NaiveDateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    }\n\n    {:ok, naive_datetime}\n  end\n\n  def convert(%{calendar: ndt_calendar, microsecond: {_, precision}} = naive_datetime, calendar) do\n    if Calendar.compatible_calendars?(ndt_calendar, calendar) do\n      result_naive_datetime =\n        naive_datetime\n        |> to_iso_days()\n        |> from_iso_days(calendar, precision)\n\n      {:ok, result_naive_datetime}\n    else\n      {:error, :incompatible_calendars}\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given `naive_datetime` from one calendar to another.\n\n  If it is not possible to convert unambiguously between the calendars\n  (see `Calendar.compatible_calendars?/2`), an ArgumentError is raised.\n\n  ## Examples\n\n  Imagine someone implements `Calendar.Holocene`, a calendar based on the\n  Gregorian calendar that adds exactly 10 000 years to the current Gregorian\n  year:\n\n      iex> NaiveDateTime.convert!(~N[2000-01-01 13:30:15], Calendar.Holocene)\n      %NaiveDateTime{calendar: Calendar.Holocene, year: 12000, month: 1, day: 1,\n                     hour: 13, minute: 30, second: 15, microsecond: {0, 0}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec convert!(Calendar.naive_datetime(), Calendar.calendar()) :: t\n  def convert!(naive_datetime, calendar) do\n    case convert(naive_datetime, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, :incompatible_calendars} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(naive_datetime)} to target calendar #{inspect(calendar)}, \" <>\n                \"reason: #{inspect(naive_datetime.calendar)} and #{inspect(calendar)} \" <>\n                \"have different day rollover moments, making this conversion ambiguous\"\n    end\n  end\n\n  @doc \"\"\"\n  Calculates a `NaiveDateTime` that is the first moment for the given `NaiveDateTime`.\n\n  To calculate the beginning of day of a `DateTime`, call this function, then convert back to a `DateTime`:\n\n      datetime\n      |> NaiveDateTime.beginning_of_day()\n      |> DateTime.from_naive(datetime.time_zone)\n\n  Note that the beginning of the day may not exist or be ambiguous\n  in a given timezone, so you must handle those cases accordingly.\n\n  ## Examples\n\n      iex> NaiveDateTime.beginning_of_day(~N[2000-01-01 23:00:07.123456])\n      ~N[2000-01-01 00:00:00.000000]\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec beginning_of_day(Calendar.naive_datetime()) :: t\n  def beginning_of_day(%{calendar: calendar, microsecond: {_, precision}} = naive_datetime) do\n    naive_datetime\n    |> to_iso_days()\n    |> calendar.iso_days_to_beginning_of_day()\n    |> from_iso_days(calendar, precision)\n  end\n\n  @doc \"\"\"\n  Calculates a `NaiveDateTime` that is the last moment for the given `NaiveDateTime`.\n\n  To calculate the end of day of a `DateTime`, call this function, then convert back to a `DateTime`:\n\n      datetime\n      |> NaiveDateTime.end_of_day()\n      |> DateTime.from_naive(datetime.time_zone)\n\n  Note that the end of the day may not exist or be ambiguous\n  in a given timezone, so you must handle those cases accordingly.\n\n  ## Examples\n\n      iex> NaiveDateTime.end_of_day(~N[2000-01-01 23:00:07.123456])\n      ~N[2000-01-01 23:59:59.999999]\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec end_of_day(Calendar.naive_datetime()) :: t\n  def end_of_day(%{calendar: calendar, microsecond: {_, precision}} = naive_datetime) do\n    end_of_day =\n      naive_datetime\n      |> to_iso_days()\n      |> calendar.iso_days_to_end_of_day()\n      |> from_iso_days(calendar, precision)\n\n    %{microsecond: {microsecond, precision}} = end_of_day\n\n    multiplier = 10 ** (6 - precision)\n\n    %{end_of_day | microsecond: {div(microsecond, multiplier) * multiplier, precision}}\n  end\n\n  ## Helpers\n\n  defp seconds_from_day_fraction({parts_in_day, @seconds_per_day}),\n    do: parts_in_day\n\n  defp seconds_from_day_fraction({parts_in_day, parts_per_day}),\n    do: div(parts_in_day * @seconds_per_day, parts_per_day)\n\n  # Keep it multiline for proper function clause errors.\n  defp to_iso_days(%{\n         calendar: calendar,\n         year: year,\n         month: month,\n         day: day,\n         hour: hour,\n         minute: minute,\n         second: second,\n         microsecond: microsecond\n       }) do\n    calendar.naive_datetime_to_iso_days(year, month, day, hour, minute, second, microsecond)\n  end\n\n  defp from_iso_days(iso_days, calendar, precision) do\n    {year, month, day, hour, minute, second, {microsecond, _}} =\n      calendar.naive_datetime_from_iso_days(iso_days)\n\n    %NaiveDateTime{\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: {microsecond, precision}\n    }\n  end\n\n  defimpl String.Chars do\n    def to_string(naive_datetime) do\n      %{\n        calendar: calendar,\n        year: year,\n        month: month,\n        day: day,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond\n      } = naive_datetime\n\n      calendar.naive_datetime_to_string(year, month, day, hour, minute, second, microsecond)\n    end\n  end\n\n  defimpl Inspect do\n    def inspect(naive_datetime, _) do\n      %{\n        year: year,\n        month: month,\n        day: day,\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        calendar: calendar\n      } = naive_datetime\n\n      if calendar != Calendar.ISO or year in -9999..9999 do\n        formatted =\n          calendar.naive_datetime_to_string(year, month, day, hour, minute, second, microsecond)\n\n        \"~N[\" <> formatted <> suffix(calendar) <> \"]\"\n      else\n        \"NaiveDateTime.new!(#{Integer.to_string(year)}, #{Integer.to_string(month)}, #{Integer.to_string(day)}, \" <>\n          \"#{Integer.to_string(hour)}, #{Integer.to_string(minute)}, #{Integer.to_string(second)}, #{inspect(microsecond)})\"\n      end\n    end\n\n    defp suffix(Calendar.ISO), do: \"\"\n    defp suffix(calendar), do: \" \" <> inspect(calendar)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar/time.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Time do\n  @moduledoc \"\"\"\n  A Time struct and functions.\n\n  The Time struct contains the fields hour, minute, second and microseconds.\n  New times can be built with the `new/4` function or using the\n  `~T` (see `sigil_T/2`) sigil:\n\n      iex> ~T[23:00:07.001]\n      ~T[23:00:07.001]\n\n  Both `new/4` and sigil return a struct where the time fields can\n  be accessed directly:\n\n      iex> time = ~T[23:00:07.001]\n      iex> time.hour\n      23\n      iex> time.microsecond\n      {1000, 3}\n\n  The functions on this module work with the `Time` struct as well\n  as any struct that contains the same fields as the `Time` struct,\n  such as `NaiveDateTime` and `DateTime`. Such functions expect\n  `t:Calendar.time/0` in their typespecs (instead of `t:t/0`).\n\n  Developers should avoid creating the Time structs directly\n  and instead rely on the functions provided by this module as well\n  as the ones in third-party calendar libraries.\n\n  ## Comparing times\n\n  Comparisons in Elixir using `==/2`, `>/2`, `</2` and similar are structural\n  and based on the `Time` struct fields. For proper comparison between\n  times, use the `compare/2`, `after?/2` and `before?/2` functions.\n  The existence of the `compare/2` function in this module also allows\n  using `Enum.min/2` and `Enum.max/2` functions to get the minimum and\n  maximum time of an `Enum`. For example:\n\n      iex> Enum.min([~T[23:00:07.001], ~T[10:00:07.001]], Time)\n      ~T[10:00:07.001]\n  \"\"\"\n\n  @enforce_keys [:hour, :minute, :second]\n  defstruct [:hour, :minute, :second, microsecond: {0, 0}, calendar: Calendar.ISO]\n\n  @type t :: %__MODULE__{\n          hour: Calendar.hour(),\n          minute: Calendar.minute(),\n          second: Calendar.second(),\n          microsecond: Calendar.microsecond(),\n          calendar: Calendar.calendar()\n        }\n\n  @seconds_per_day 24 * 60 * 60\n\n  @doc \"\"\"\n  Returns the current time in UTC.\n\n  You can pass a time unit to automatically truncate the resulting time.\n\n  The default unit if none gets passed is `:native` which results on a default resolution of microseconds.\n\n  ## Examples\n\n      iex> time = Time.utc_now()\n      iex> time.hour >= 0\n      true\n\n      iex> time = Time.utc_now(:second)\n      iex> time.microsecond\n      {0, 0}\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec utc_now(Calendar.calendar() | :native | :microsecond | :millisecond | :second) :: t\n  def utc_now(calendar_or_time_unit \\\\ Calendar.ISO) do\n    case calendar_or_time_unit do\n      unit when unit in [:native, :microsecond, :millisecond, :second] ->\n        utc_now(unit, Calendar.ISO)\n\n      calendar ->\n        utc_now(:native, calendar)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the current time in UTC, supporting a precision and a specific calendar.\n\n  ## Examples\n\n      iex> time = Time.utc_now(:microsecond, Calendar.ISO)\n      iex> time.hour >= 0\n      true\n\n      iex> time = Time.utc_now(:second, Calendar.ISO)\n      iex> time.microsecond\n      {0, 0}\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec utc_now(:native | :microsecond | :millisecond | :second, Calendar.calendar()) :: t\n  def utc_now(time_unit, calendar)\n      when time_unit in [:native, :microsecond, :millisecond, :second] do\n    {:ok, _, time, microsecond} = Calendar.ISO.from_unix(System.os_time(time_unit), time_unit)\n    {hour, minute, second} = time\n\n    iso_time = %Time{\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      calendar: Calendar.ISO\n    }\n\n    convert!(iso_time, calendar)\n  end\n\n  @doc \"\"\"\n  Builds a new time.\n\n  Expects all values to be integers. Returns `{:ok, time}` if each\n  entry fits its appropriate range, returns `{:error, reason}` otherwise.\n\n  Microseconds can also be given with a precision, which must be an\n  integer between 0 and 6.\n\n  The built-in calendar does not support leap seconds.\n\n  ## Examples\n\n      iex> Time.new(0, 0, 0, 0)\n      {:ok, ~T[00:00:00.000000]}\n      iex> Time.new(23, 59, 59, 999_999)\n      {:ok, ~T[23:59:59.999999]}\n\n      iex> Time.new(24, 59, 59, 999_999)\n      {:error, :invalid_time}\n      iex> Time.new(23, 60, 59, 999_999)\n      {:error, :invalid_time}\n      iex> Time.new(23, 59, 60, 999_999)\n      {:error, :invalid_time}\n      iex> Time.new(23, 59, 59, 1_000_000)\n      {:error, :invalid_time}\n\n      # Invalid precision\n      Time.new(23, 59, 59, {999_999, 10})\n      {:error, :invalid_time}\n\n  \"\"\"\n  @spec new(\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond() | non_neg_integer(),\n          Calendar.calendar()\n        ) :: {:ok, t} | {:error, atom}\n  def new(hour, minute, second, microsecond \\\\ {0, 0}, calendar \\\\ Calendar.ISO)\n\n  def new(hour, minute, second, microsecond, calendar) when is_integer(microsecond) do\n    new(hour, minute, second, {microsecond, 6}, calendar)\n  end\n\n  def new(hour, minute, second, {microsecond, precision}, calendar)\n      when is_integer(hour) and is_integer(minute) and is_integer(second) and\n             is_integer(microsecond) and is_integer(precision) do\n    case calendar.valid_time?(hour, minute, second, {microsecond, precision}) do\n      true ->\n        time = %Time{\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: {microsecond, precision},\n          calendar: calendar\n        }\n\n        {:ok, time}\n\n      false ->\n        {:error, :invalid_time}\n    end\n  end\n\n  @doc \"\"\"\n  Builds a new time.\n\n  Expects all values to be integers. Returns `time` if each\n  entry fits its appropriate range, raises if the time is invalid.\n\n  Microseconds can also be given with a precision, which must be an\n  integer between 0 and 6.\n\n  The built-in calendar does not support leap seconds.\n\n  ## Examples\n\n      iex> Time.new!(0, 0, 0, 0)\n      ~T[00:00:00.000000]\n      iex> Time.new!(23, 59, 59, 999_999)\n      ~T[23:59:59.999999]\n      iex> Time.new!(24, 59, 59, 999_999)\n      ** (ArgumentError) cannot build time, reason: :invalid_time\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec new!(\n          Calendar.hour(),\n          Calendar.minute(),\n          Calendar.second(),\n          Calendar.microsecond() | non_neg_integer,\n          Calendar.calendar()\n        ) :: t\n  def new!(hour, minute, second, microsecond \\\\ {0, 0}, calendar \\\\ Calendar.ISO) do\n    case new(hour, minute, second, microsecond, calendar) do\n      {:ok, time} ->\n        time\n\n      {:error, reason} ->\n        raise ArgumentError, \"cannot build time, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given `time` to a string.\n\n  ## Examples\n\n      iex> Time.to_string(~T[23:00:00])\n      \"23:00:00\"\n      iex> Time.to_string(~T[23:00:00.001])\n      \"23:00:00.001\"\n      iex> Time.to_string(~T[23:00:00.123456])\n      \"23:00:00.123456\"\n\n      iex> Time.to_string(~N[2015-01-01 23:00:00.001])\n      \"23:00:00.001\"\n      iex> Time.to_string(~N[2015-01-01 23:00:00.123456])\n      \"23:00:00.123456\"\n\n  \"\"\"\n  @spec to_string(Calendar.time()) :: String.t()\n  def to_string(time)\n\n  def to_string(%{\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        calendar: calendar\n      }) do\n    calendar.time_to_string(hour, minute, second, microsecond)\n  end\n\n  @doc \"\"\"\n  Parses the extended \"Local time\" format described by\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  Time zone offset may be included in the string but they will be\n  simply discarded as such information is not included in times.\n\n  As specified in the standard, the separator \"T\" may be omitted if\n  desired as there is no ambiguity within this function.\n\n  ## Examples\n\n      iex> Time.from_iso8601(\"23:50:07\")\n      {:ok, ~T[23:50:07]}\n      iex> Time.from_iso8601(\"23:50:07Z\")\n      {:ok, ~T[23:50:07]}\n      iex> Time.from_iso8601(\"T23:50:07Z\")\n      {:ok, ~T[23:50:07]}\n\n      iex> Time.from_iso8601(\"23:50:07,0123456\")\n      {:ok, ~T[23:50:07.012345]}\n      iex> Time.from_iso8601(\"23:50:07.0123456\")\n      {:ok, ~T[23:50:07.012345]}\n      iex> Time.from_iso8601(\"23:50:07.123Z\")\n      {:ok, ~T[23:50:07.123]}\n\n      iex> Time.from_iso8601(\"2015:01:23 23-50-07\")\n      {:error, :invalid_format}\n      iex> Time.from_iso8601(\"23:50:07A\")\n      {:error, :invalid_format}\n      iex> Time.from_iso8601(\"23:50:07.\")\n      {:error, :invalid_format}\n      iex> Time.from_iso8601(\"23:50:61\")\n      {:error, :invalid_time}\n\n  \"\"\"\n  @spec from_iso8601(String.t(), Calendar.calendar()) :: {:ok, t} | {:error, atom}\n  def from_iso8601(string, calendar \\\\ Calendar.ISO) do\n    with {:ok, {hour, minute, second, microsecond}} <- Calendar.ISO.parse_time(string) do\n      convert(\n        %Time{hour: hour, minute: minute, second: second, microsecond: microsecond},\n        calendar\n      )\n    end\n  end\n\n  @doc \"\"\"\n  Parses the extended \"Local time\" format described by\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  Raises if the format is invalid.\n\n  ## Examples\n\n      iex> Time.from_iso8601!(\"23:50:07,123Z\")\n      ~T[23:50:07.123]\n      iex> Time.from_iso8601!(\"23:50:07.123Z\")\n      ~T[23:50:07.123]\n      iex> Time.from_iso8601!(\"2015:01:23 23-50-07\")\n      ** (ArgumentError) cannot parse \"2015:01:23 23-50-07\" as time, reason: :invalid_format\n\n  \"\"\"\n  @spec from_iso8601!(String.t(), Calendar.calendar()) :: t\n  def from_iso8601!(string, calendar \\\\ Calendar.ISO) do\n    case from_iso8601(string, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise ArgumentError, \"cannot parse #{inspect(string)} as time, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given time to\n  [ISO 8601:2019](https://en.wikipedia.org/wiki/ISO_8601).\n\n  By default, `Time.to_iso8601/2` returns times formatted in the \"extended\"\n  format, for human readability. It also supports the \"basic\" format through\n  passing the `:basic` option.\n\n  ## Examples\n\n      iex> Time.to_iso8601(~T[23:00:13])\n      \"23:00:13\"\n\n      iex> Time.to_iso8601(~T[23:00:13.001])\n      \"23:00:13.001\"\n\n      iex> Time.to_iso8601(~T[23:00:13.001], :basic)\n      \"230013.001\"\n\n      iex> Time.to_iso8601(~N[2010-04-17 23:00:13])\n      \"23:00:13\"\n\n  \"\"\"\n  @spec to_iso8601(Calendar.time(), :extended | :basic) :: String.t()\n  def to_iso8601(time, format \\\\ :extended)\n\n  def to_iso8601(%{calendar: Calendar.ISO} = time, format) when format in [:extended, :basic] do\n    %{\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    } = time\n\n    Calendar.ISO.time_to_string(hour, minute, second, microsecond, format)\n  end\n\n  def to_iso8601(%{calendar: _} = time, format) when format in [:extended, :basic] do\n    time\n    |> convert!(Calendar.ISO)\n    |> to_iso8601(format)\n  end\n\n  @doc \"\"\"\n  Converts given `time` to an Erlang time tuple.\n\n  WARNING: Loss of precision may occur, as Erlang time tuples\n  only contain hours/minutes/seconds.\n\n  ## Examples\n\n      iex> Time.to_erl(~T[23:30:15.999])\n      {23, 30, 15}\n\n      iex> Time.to_erl(~N[2010-04-17 23:30:15.999])\n      {23, 30, 15}\n\n  \"\"\"\n  @spec to_erl(Calendar.time()) :: :calendar.time()\n  def to_erl(time) do\n    %{hour: hour, minute: minute, second: second} = convert!(time, Calendar.ISO)\n    {hour, minute, second}\n  end\n\n  @doc \"\"\"\n  Converts an Erlang time tuple to a `Time` struct.\n\n  ## Examples\n\n      iex> Time.from_erl({23, 30, 15})\n      {:ok, ~T[23:30:15]}\n      iex> Time.from_erl({23, 30, 15}, 5000)\n      {:ok, ~T[23:30:15.005000]}\n      iex> Time.from_erl({23, 30, 15}, {5000, 3})\n      {:ok, ~T[23:30:15.005]}\n      iex> Time.from_erl({24, 30, 15})\n      {:error, :invalid_time}\n\n  \"\"\"\n  @spec from_erl(\n          :calendar.time(),\n          Calendar.microsecond() | non_neg_integer(),\n          Calendar.calendar()\n        ) ::\n          {:ok, t} | {:error, atom}\n  def from_erl(tuple, microsecond \\\\ {0, 0}, calendar \\\\ Calendar.ISO)\n\n  def from_erl({hour, minute, second}, microsecond, calendar) do\n    with {:ok, time} <- new(hour, minute, second, microsecond, Calendar.ISO),\n         do: convert(time, calendar)\n  end\n\n  @doc \"\"\"\n  Converts an Erlang time tuple to a `Time` struct.\n\n  ## Examples\n\n      iex> Time.from_erl!({23, 30, 15})\n      ~T[23:30:15]\n      iex> Time.from_erl!({23, 30, 15}, 5000)\n      ~T[23:30:15.005000]\n      iex> Time.from_erl!({23, 30, 15}, {5000, 3})\n      ~T[23:30:15.005]\n      iex> Time.from_erl!({24, 30, 15})\n      ** (ArgumentError) cannot convert {24, 30, 15} to time, reason: :invalid_time\n\n  \"\"\"\n  @spec from_erl!(:calendar.time(), Calendar.microsecond(), Calendar.calendar()) :: t\n  def from_erl!(tuple, microsecond \\\\ {0, 0}, calendar \\\\ Calendar.ISO) do\n    case from_erl(tuple, microsecond, calendar) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"cannot convert #{inspect(tuple)} to time, reason: #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts a number of seconds after midnight to a `Time` struct.\n\n  ## Examples\n\n      iex> Time.from_seconds_after_midnight(10_000)\n      ~T[02:46:40]\n      iex> Time.from_seconds_after_midnight(30_000, {5000, 3})\n      ~T[08:20:00.005]\n      iex> Time.from_seconds_after_midnight(-1)\n      ~T[23:59:59]\n      iex> Time.from_seconds_after_midnight(100_000)\n      ~T[03:46:40]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec from_seconds_after_midnight(\n          integer(),\n          Calendar.microsecond(),\n          Calendar.calendar()\n        ) :: t\n  def from_seconds_after_midnight(seconds, microsecond \\\\ {0, 0}, calendar \\\\ Calendar.ISO)\n      when is_integer(seconds) do\n    seconds_in_day = Integer.mod(seconds, @seconds_per_day)\n\n    {hour, minute, second, {_, _}} =\n      calendar.time_from_day_fraction({seconds_in_day, @seconds_per_day})\n\n    %Time{\n      calendar: calendar,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    }\n  end\n\n  @doc \"\"\"\n  Converts a `Time` struct to a number of seconds after midnight.\n\n  The returned value is a two-element tuple with the number of seconds and microseconds.\n\n  ## Examples\n\n      iex> Time.to_seconds_after_midnight(~T[23:30:15])\n      {84615, 0}\n      iex> Time.to_seconds_after_midnight(~N[2010-04-17 23:30:15.999])\n      {84615, 999000}\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec to_seconds_after_midnight(Calendar.time()) :: {integer(), non_neg_integer()}\n  def to_seconds_after_midnight(%{microsecond: {microsecond, _precision}} = time) do\n    iso_days = {0, to_day_fraction(time)}\n    {Calendar.ISO.iso_days_to_unit(iso_days, :second), microsecond}\n  end\n\n  @doc \"\"\"\n  Adds the `amount_to_add` of `unit`s to the given `time`.\n\n  > #### Prefer `shift/2` {: .info}\n  >\n  > Prefer `shift/2` over `add/3`, as it offers a more ergonomic API.\n  >\n  > `add/3` always considers the unit to be computed according to\n  > the `Calendar.ISO`.\n\n  Accepts an `amount_to_add` in any `unit`. `unit` can be\n  `:hour`, `:minute`, `:second` or any subsecond precision from\n  `t:System.time_unit/0` for convenience but ultimately they are\n  all converted to microseconds. Negative values will move backwards\n  in time and the default precision is `:second`.\n\n  Note the result value represents the time of day, meaning that it is cyclic,\n  for instance, it will never go over 24 hours for the ISO calendar.\n\n  ## Examples\n\n      iex> Time.add(~T[10:00:00], 27000)\n      ~T[17:30:00]\n      iex> Time.add(~T[11:00:00.005], 2400)\n      ~T[11:40:00.005]\n      iex> Time.add(~T[00:00:00.000], 86_399_999, :millisecond)\n      ~T[23:59:59.999]\n\n  Negative values are allowed:\n\n      iex> Time.add(~T[23:00:00], -60)\n      ~T[22:59:00]\n\n  Note that the time is cyclic:\n\n      iex> Time.add(~T[17:10:05], 86400)\n      ~T[17:10:05]\n\n  Hours and minutes are also supported:\n\n      iex> Time.add(~T[17:10:05], 2, :hour)\n      ~T[19:10:05]\n      iex> Time.add(~T[17:10:05], 30, :minute)\n      ~T[17:40:05]\n\n  This operation merges the precision of the time with the given unit:\n\n      iex> result = Time.add(~T[00:29:10], 21, :millisecond)\n      ~T[00:29:10.021]\n      iex> result.microsecond\n      {21000, 3}\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec add(Calendar.time(), integer, :hour | :minute | System.time_unit()) :: t\n  def add(time, amount_to_add, unit \\\\ :second)\n\n  def add(time, amount_to_add, :hour) when is_integer(amount_to_add) do\n    add(time, amount_to_add * 3600, :second)\n  end\n\n  def add(time, amount_to_add, :minute) when is_integer(amount_to_add) do\n    add(time, amount_to_add * 60, :second)\n  end\n\n  def add(%{calendar: calendar, microsecond: {_, precision}} = time, amount_to_add, unit)\n      when is_integer(amount_to_add) do\n    valid? =\n      if is_integer(unit),\n        do: unit > 0,\n        else: unit in ~w(second millisecond microsecond nanosecond)a\n\n    if not valid? do\n      raise ArgumentError,\n            \"unsupported time unit. Expected :hour, :minute, :second, :millisecond, :microsecond, :nanosecond, or a positive integer, got #{inspect(unit)}\"\n    end\n\n    %{hour: hour, minute: minute, second: second, microsecond: microsecond} = time\n\n    precision = max(Calendar.ISO.time_unit_to_precision(unit), precision)\n\n    {hour, minute, second, {microsecond, _precision}} =\n      Calendar.ISO.shift_time_unit(\n        {hour, minute, second, microsecond},\n        amount_to_add,\n        unit\n      )\n\n    %Time{\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: {microsecond, precision},\n      calendar: calendar\n    }\n  end\n\n  @doc \"\"\"\n  Shifts given `time` by `duration` according to its calendar.\n\n  Available duration units are: `:hour`, `:minute`, `:second`, `:microsecond`.\n\n  When using the default ISO calendar, durations are collapsed to seconds and\n  microseconds before they are applied.\n\n  Raises an `ArgumentError` when called with date scale units.\n\n  ## Examples\n\n      iex> Time.shift(~T[01:00:15], hour: 12)\n      ~T[13:00:15]\n      iex> Time.shift(~T[01:35:00], hour: 6, minute: -15)\n      ~T[07:20:00]\n      iex> Time.shift(~T[01:15:00], second: 125)\n      ~T[01:17:05]\n      iex> Time.shift(~T[01:00:15], microsecond: {100, 6})\n      ~T[01:00:15.000100]\n      iex> Time.shift(~T[01:15:00], Duration.new!(second: 65))\n      ~T[01:16:05]\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec shift(Calendar.time(), Duration.t() | [unit_pair]) :: t\n        when unit_pair:\n               {:hour, integer}\n               | {:minute, integer}\n               | {:second, integer}\n               | {:microsecond, {integer, 0..6}}\n  def shift(%{calendar: calendar} = time, duration) do\n    %{hour: hour, minute: minute, second: second, microsecond: microsecond} = time\n\n    {hour, minute, second, microsecond} =\n      calendar.shift_time(hour, minute, second, microsecond, __duration__!(duration))\n\n    %Time{\n      calendar: calendar,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    }\n  end\n\n  @doc false\n  def __duration__!(%Duration{} = duration) do\n    duration\n  end\n\n  # This part is inlined by the compiler on constant values\n  def __duration__!(unit_pairs) do\n    Enum.each(unit_pairs, &validate_duration_unit!/1)\n    struct!(Duration, unit_pairs)\n  end\n\n  defp validate_duration_unit!({:microsecond, {ms, precision}})\n       when is_integer(ms) and precision in 0..6 do\n    :ok\n  end\n\n  defp validate_duration_unit!({:microsecond, microsecond}) do\n    raise ArgumentError,\n          \"unsupported value #{inspect(microsecond)} for :microsecond. Expected a tuple {ms, precision} where precision is an integer from 0 to 6\"\n  end\n\n  defp validate_duration_unit!({unit, _value}) when unit in [:year, :month, :week, :day] do\n    raise ArgumentError,\n          \"unsupported unit #{inspect(unit)}. Expected :hour, :minute, :second, :microsecond\"\n  end\n\n  defp validate_duration_unit!({unit, _value})\n       when unit not in [:hour, :minute, :second, :microsecond] do\n    raise ArgumentError,\n          \"unknown unit #{inspect(unit)}. Expected :hour, :minute, :second, :microsecond\"\n  end\n\n  defp validate_duration_unit!({_unit, value}) when is_integer(value) do\n    :ok\n  end\n\n  defp validate_duration_unit!({unit, value}) do\n    raise ArgumentError,\n          \"unsupported value #{inspect(value)} for #{inspect(unit)}. Expected an integer\"\n  end\n\n  @doc \"\"\"\n  Compares two time structs.\n\n  Returns `:gt` if first time is later than the second\n  and `:lt` for vice versa. If the two times are equal\n  `:eq` is returned.\n\n  ## Examples\n\n      iex> Time.compare(~T[16:04:16], ~T[16:04:28])\n      :lt\n      iex> Time.compare(~T[16:04:16], ~T[16:04:16])\n      :eq\n      iex> Time.compare(~T[16:04:16.01], ~T[16:04:16.001])\n      :gt\n\n  This function can also be used to compare across more\n  complex calendar types by considering only the time fields:\n\n      iex> Time.compare(~N[1900-01-01 16:04:16], ~N[2015-01-01 16:04:16])\n      :eq\n      iex> Time.compare(~N[2015-01-01 16:04:16], ~N[2015-01-01 16:04:28])\n      :lt\n      iex> Time.compare(~N[2015-01-01 16:04:16.01], ~N[2000-01-01 16:04:16.001])\n      :gt\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec compare(Calendar.time(), Calendar.time()) :: :lt | :eq | :gt\n  def compare(%{calendar: calendar} = time1, %{calendar: calendar} = time2) do\n    %{hour: hour1, minute: minute1, second: second1, microsecond: {microsecond1, _}} = time1\n    %{hour: hour2, minute: minute2, second: second2, microsecond: {microsecond2, _}} = time2\n\n    case {{hour1, minute1, second1, microsecond1}, {hour2, minute2, second2, microsecond2}} do\n      {first, second} when first > second -> :gt\n      {first, second} when first < second -> :lt\n      _ -> :eq\n    end\n  end\n\n  def compare(time1, time2) do\n    {parts1, ppd1} = to_day_fraction(time1)\n    {parts2, ppd2} = to_day_fraction(time2)\n\n    case {parts1 * ppd2, parts2 * ppd1} do\n      {first, second} when first > second -> :gt\n      {first, second} when first < second -> :lt\n      _ -> :eq\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if the first time is strictly earlier than the second.\n\n  ## Examples\n\n      iex> Time.before?(~T[16:04:16], ~T[16:04:28])\n      true\n      iex> Time.before?(~T[16:04:16], ~T[16:04:16])\n      false\n      iex> Time.before?(~T[16:04:16.01], ~T[16:04:16.001])\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec before?(Calendar.time(), Calendar.time()) :: boolean()\n  def before?(time1, time2) do\n    compare(time1, time2) == :lt\n  end\n\n  @doc \"\"\"\n  Returns `true` if the first time is strictly later than the second.\n\n  ## Examples\n\n      iex> Time.after?(~T[16:04:28], ~T[16:04:16])\n      true\n      iex> Time.after?(~T[16:04:16], ~T[16:04:16])\n      false\n      iex> Time.after?(~T[16:04:16.001], ~T[16:04:16.01])\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec after?(Calendar.time(), Calendar.time()) :: boolean()\n  def after?(time1, time2) do\n    compare(time1, time2) == :gt\n  end\n\n  @doc \"\"\"\n  Converts given `time` to a different calendar.\n\n  Returns `{:ok, time}` if the conversion was successful,\n  or `{:error, reason}` if it was not, for some reason.\n\n  ## Examples\n\n  Imagine someone implements `Calendar.Holocene`, a calendar based on the\n  Gregorian calendar that adds exactly 10 000 years to the current Gregorian\n  year:\n\n      iex> Time.convert(~T[13:30:15], Calendar.Holocene)\n      {:ok, %Time{calendar: Calendar.Holocene, hour: 13, minute: 30, second: 15, microsecond: {0, 0}}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec convert(Calendar.time(), Calendar.calendar()) :: {:ok, t} | {:error, atom}\n\n  # Keep it multiline for proper function clause errors.\n  def convert(\n        %{\n          calendar: calendar,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond\n        },\n        calendar\n      ) do\n    time = %Time{\n      calendar: calendar,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    }\n\n    {:ok, time}\n  end\n\n  def convert(%{microsecond: {_, precision}} = time, calendar) do\n    {hour, minute, second, {microsecond, _}} =\n      time\n      |> to_day_fraction()\n      |> calendar.time_from_day_fraction()\n\n    time = %Time{\n      calendar: calendar,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: {microsecond, precision}\n    }\n\n    {:ok, time}\n  end\n\n  @doc \"\"\"\n  Similar to `Time.convert/2`, but raises an `ArgumentError`\n  if the conversion between the two calendars is not possible.\n\n  ## Examples\n\n  Imagine someone implements `Calendar.Holocene`, a calendar based on the\n  Gregorian calendar that adds exactly 10 000 years to the current Gregorian\n  year:\n\n      iex> Time.convert!(~T[13:30:15], Calendar.Holocene)\n      %Time{calendar: Calendar.Holocene, hour: 13, minute: 30, second: 15, microsecond: {0, 0}}\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec convert!(Calendar.time(), Calendar.calendar()) :: t\n  def convert!(time, calendar) do\n    {:ok, value} = convert(time, calendar)\n    value\n  end\n\n  @doc \"\"\"\n  Returns the difference between two times, considering only the hour, minute,\n  second and microsecond.\n\n  As with the `compare/2` function both `Time` structs and other structures\n  containing time can be used. If for instance a `NaiveDateTime` or `DateTime`\n  is passed, only the hour, minute, second, and microsecond is considered. Any\n  additional information about a date or time zone is ignored when calculating\n  the difference.\n\n  The answer can be returned in any `:hour`, `:minute`, `:second` or any\n  subsecond `unit` available from `t:System.time_unit/0`. If the first time\n  value is earlier than the second, a negative number is returned.\n\n  The unit is measured according to `Calendar.ISO` and defaults to `:second`.\n  Fractional results are not supported and are truncated.\n\n  ## Examples\n\n      iex> Time.diff(~T[00:29:12], ~T[00:29:10])\n      2\n\n      # When passing a `NaiveDateTime` the date part is ignored.\n      iex> Time.diff(~N[2017-01-01 00:29:12], ~T[00:29:10])\n      2\n\n      # Two `NaiveDateTime` structs could have big differences in the date\n      # but only the time part is considered.\n      iex> Time.diff(~N[2017-01-01 00:29:12], ~N[1900-02-03 00:29:10])\n      2\n\n      iex> Time.diff(~T[00:29:12], ~T[00:29:10], :microsecond)\n      2_000_000\n      iex> Time.diff(~T[00:29:10], ~T[00:29:12], :microsecond)\n      -2_000_000\n\n      iex> Time.diff(~T[02:29:10], ~T[00:29:10], :hour)\n      2\n      iex> Time.diff(~T[02:29:10], ~T[00:29:11], :hour)\n      1\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec diff(Calendar.time(), Calendar.time(), :hour | :minute | System.time_unit()) :: integer\n  def diff(time1, time2, unit \\\\ :second)\n\n  def diff(time1, time2, :hour) do\n    diff(time1, time2, :second) |> div(3600)\n  end\n\n  def diff(time1, time2, :minute) do\n    diff(time1, time2, :second) |> div(60)\n  end\n\n  def diff(\n        %{\n          calendar: Calendar.ISO,\n          hour: hour1,\n          minute: minute1,\n          second: second1,\n          microsecond: {microsecond1, _}\n        },\n        %{\n          calendar: Calendar.ISO,\n          hour: hour2,\n          minute: minute2,\n          second: second2,\n          microsecond: {microsecond2, _}\n        },\n        unit\n      ) do\n    total =\n      (hour1 - hour2) * 3_600_000_000 + (minute1 - minute2) * 60_000_000 +\n        (second1 - second2) * 1_000_000 + (microsecond1 - microsecond2)\n\n    System.convert_time_unit(total, :microsecond, unit)\n  end\n\n  def diff(time1, time2, unit) do\n    fraction1 = to_day_fraction(time1)\n    fraction2 = to_day_fraction(time2)\n\n    Calendar.ISO.iso_days_to_unit({0, fraction1}, unit) -\n      Calendar.ISO.iso_days_to_unit({0, fraction2}, unit)\n  end\n\n  @doc \"\"\"\n  Returns the given time with the microsecond field truncated to the given\n  precision (`:microsecond`, `millisecond` or `:second`).\n\n  The given time is returned unchanged if it already has lower precision than\n  the given precision.\n\n  ## Examples\n\n      iex> Time.truncate(~T[01:01:01.123456], :microsecond)\n      ~T[01:01:01.123456]\n\n      iex> Time.truncate(~T[01:01:01.123456], :millisecond)\n      ~T[01:01:01.123]\n\n      iex> Time.truncate(~T[01:01:01.123456], :second)\n      ~T[01:01:01]\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec truncate(t(), :microsecond | :millisecond | :second) :: t()\n  def truncate(%Time{microsecond: microsecond} = time, precision) do\n    %{time | microsecond: Calendar.truncate(microsecond, precision)}\n  end\n\n  ## Helpers\n\n  defp to_day_fraction(%{\n         hour: hour,\n         minute: minute,\n         second: second,\n         microsecond: {_, _} = microsecond,\n         calendar: calendar\n       }) do\n    calendar.time_to_day_fraction(hour, minute, second, microsecond)\n  end\n\n  defimpl String.Chars do\n    def to_string(time) do\n      %{\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        calendar: calendar\n      } = time\n\n      calendar.time_to_string(hour, minute, second, microsecond)\n    end\n  end\n\n  defimpl Inspect do\n    def inspect(time, _) do\n      %{\n        hour: hour,\n        minute: minute,\n        second: second,\n        microsecond: microsecond,\n        calendar: calendar\n      } = time\n\n      \"~T[\" <>\n        calendar.time_to_string(hour, minute, second, microsecond) <> suffix(calendar) <> \"]\"\n    end\n\n    defp suffix(Calendar.ISO), do: \"\"\n    defp suffix(calendar), do: \" \" <> inspect(calendar)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar/time_zone_database.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Calendar.TimeZoneDatabase do\n  @moduledoc \"\"\"\n  This module defines a behaviour for providing time zone data.\n\n  IANA provides time zone data that includes data about different\n  UTC offsets and standard offsets for time zones.\n  \"\"\"\n\n  @typedoc \"\"\"\n  A period where a certain combination of UTC offset, standard offset, and zone\n  abbreviation is in effect.\n\n  For example, one period could be the summer of 2018 in the `Europe/London` timezone,\n  where summer time/daylight saving time is in effect and lasts from spring to autumn.\n  In autumn, the `std_offset` changes along with the `zone_abbr` so a different\n  period is needed during winter.\n  \"\"\"\n  @type time_zone_period :: %{\n          optional(any) => any,\n          utc_offset: Calendar.utc_offset(),\n          std_offset: Calendar.std_offset(),\n          zone_abbr: Calendar.zone_abbr()\n        }\n\n  @typedoc \"\"\"\n  Limit for when a certain time zone period begins or ends.\n\n  A beginning is inclusive. An ending is exclusive. For example, if a period is from\n  `2015-03-29 01:00:00` and until `2015-10-25 01:00:00`, the period includes and\n  begins from the beginning of `2015-03-29 01:00:00` and lasts until just before\n  `2015-10-25 01:00:00`.\n\n  A beginning or end for certain periods are infinite, such as the latest\n  period for time zones without DST or plans to change. However, for the purpose\n  of this behaviour, they are only used for gaps in wall time where the needed\n  period limits are at a certain time.\n  \"\"\"\n  @type time_zone_period_limit :: Calendar.naive_datetime()\n\n  @doc \"\"\"\n  Time zone period for a point in time in UTC for a specific time zone.\n\n  Takes a time zone name and a point in time for UTC and returns a\n  `time_zone_period` for that point in time.\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @callback time_zone_period_from_utc_iso_days(Calendar.iso_days(), Calendar.time_zone()) ::\n              {:ok, time_zone_period}\n              | {:error, :time_zone_not_found | :utc_only_time_zone_database}\n\n  @doc \"\"\"\n  Possible time zone periods for a certain time zone and wall clock date and time.\n\n  When the provided naive datetime is ambiguous, return a tuple with `:ambiguous`\n  and the two possible periods. The periods in the tuple must be sorted with the\n  first element being the one that begins first.\n\n  When the provided naive datetime is in a gap, such as during the \"spring forward\" when going\n  from winter time to summer time, return a tuple with `:gap` and two periods with limits\n  in a nested tuple. The first nested two-tuple is the period before the gap and a naive datetime\n  with a limit for when the period ends (wall time). The second nested two-tuple is the period\n  just after the gap and a datetime (wall time) for when the period begins just after the gap.\n\n  If there is only a single possible period for the provided `datetime`, then return a tuple\n  with `:ok` and the `time_zone_period`.\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @callback time_zone_periods_from_wall_datetime(Calendar.naive_datetime(), Calendar.time_zone()) ::\n              {:ok, time_zone_period}\n              | {:ambiguous, time_zone_period, time_zone_period}\n              | {:gap, {time_zone_period, time_zone_period_limit},\n                 {time_zone_period, time_zone_period_limit}}\n              | {:error, :time_zone_not_found | :utc_only_time_zone_database}\nend\n\ndefmodule Calendar.UTCOnlyTimeZoneDatabase do\n  @moduledoc \"\"\"\n  Built-in time zone database that works only in the `Etc/UTC` timezone.\n\n  For all other time zones, it returns `{:error, :utc_only_time_zone_database}`.\n  \"\"\"\n\n  @behaviour Calendar.TimeZoneDatabase\n\n  @impl true\n  def time_zone_period_from_utc_iso_days(_, \"Etc/UTC\"),\n    do: {:ok, %{std_offset: 0, utc_offset: 0, zone_abbr: \"UTC\"}}\n\n  def time_zone_period_from_utc_iso_days(_, _),\n    do: {:error, :utc_only_time_zone_database}\n\n  @impl true\n  def time_zone_periods_from_wall_datetime(_, \"Etc/UTC\"),\n    do: {:ok, %{std_offset: 0, utc_offset: 0, zone_abbr: \"UTC\"}}\n\n  def time_zone_periods_from_wall_datetime(_, _),\n    do: {:error, :utc_only_time_zone_database}\nend\n"
  },
  {
    "path": "lib/elixir/lib/calendar.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Calendar do\n  @moduledoc \"\"\"\n  This module defines the responsibilities for working with\n  calendars, dates, times and datetimes in Elixir.\n\n  It defines types and the minimal implementation\n  for a calendar behaviour in Elixir. The goal of the calendar\n  features in Elixir is to provide a base for interoperability\n  rather than a full-featured datetime API.\n\n  For the actual date, time and datetime structs, see `Date`,\n  `Time`, `NaiveDateTime`, and `DateTime`.\n\n  Types for year, month, day, and more are *overspecified*.\n  For example, the `t:month/0` type is specified as an integer\n  instead of `1..12`. This is because different calendars may\n  have a different number of days per month.\n  \"\"\"\n\n  @type year :: integer\n  @type month :: pos_integer\n  @type day :: pos_integer\n  @type week :: pos_integer\n  @type day_of_week :: non_neg_integer\n  @type era :: non_neg_integer\n\n  @typedoc \"\"\"\n  A tuple representing the `day` and the `era`.\n  \"\"\"\n  @type day_of_era :: {day :: non_neg_integer(), era}\n\n  @type hour :: non_neg_integer\n  @type minute :: non_neg_integer\n  @type second :: non_neg_integer\n\n  @typedoc \"\"\"\n  The internal time format is used when converting between calendars.\n\n  It represents time as a fraction of a day (starting from midnight).\n  `parts_in_day` specifies how much of the day is already passed,\n  while `parts_per_day` signifies how many parts are there in a day.\n  \"\"\"\n  @type day_fraction :: {parts_in_day :: non_neg_integer, parts_per_day :: pos_integer}\n\n  @typedoc \"\"\"\n  The internal date format that is used when converting between calendars.\n\n  This is the number of days including the fractional part that has passed of\n  the last day since `0000-01-01+00:00T00:00.000000` in ISO 8601 notation (also\n  known as *midnight 1 January BC 1* of the proleptic Gregorian calendar).\n  \"\"\"\n  @type iso_days :: {days :: integer, day_fraction}\n\n  @typedoc \"\"\"\n  Microseconds with stored precision.\n\n  `value` always represents the total value in microseconds.\n\n  The `precision` represents the number of digits that must be used when\n  representing the microseconds to external format. If the precision is `0`,\n  it means microseconds must be skipped. If the precision is `6`, it means\n  that `value` represents exactly the number of microseconds to be used.\n\n  ## Examples\n\n    * `{0, 0}` means no microseconds.\n    * `{1, 6}` means 1µs.\n    * `{1000, 6}` means 1000µs (which is 1ms but measured at the microsecond precision).\n    * `{1000, 3}` means 1ms (which is measured at the millisecond precision).\n\n  \"\"\"\n  @type microsecond :: {value :: non_neg_integer, precision :: non_neg_integer}\n\n  @typedoc \"A calendar implementation.\"\n  @type calendar :: module\n\n  @typedoc \"The time zone ID according to the IANA tz database (for example, `Europe/Zurich`).\"\n  @type time_zone :: String.t()\n\n  @typedoc \"The time zone abbreviation (for example, `CET` or `CEST` or `BST`).\"\n  @type zone_abbr :: String.t()\n\n  @typedoc \"\"\"\n  The time zone UTC offset in ISO seconds for standard time.\n\n  See also `t:std_offset/0`.\n  \"\"\"\n  @type utc_offset :: integer\n\n  @typedoc \"\"\"\n  The time zone standard offset in ISO seconds (typically not zero in summer times).\n\n  It must be added to `t:utc_offset/0` to get the total offset from UTC used for \"wall time\".\n  \"\"\"\n  @type std_offset :: integer\n\n  @typedoc \"Any map or struct that contains the date fields.\"\n  @type date :: %{optional(any) => any, calendar: calendar, year: year, month: month, day: day}\n\n  @typedoc \"Any map or struct that contains the time fields.\"\n  @type time :: %{\n          optional(any) => any,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond\n        }\n\n  @typedoc \"Any map or struct that contains the naive datetime fields.\"\n  @type naive_datetime :: %{\n          optional(any) => any,\n          calendar: calendar,\n          year: year,\n          month: month,\n          day: day,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond\n        }\n\n  @typedoc \"Any map or struct that contains the datetime fields.\"\n  @type datetime :: %{\n          optional(any) => any,\n          calendar: calendar,\n          year: year,\n          month: month,\n          day: day,\n          hour: hour,\n          minute: minute,\n          second: second,\n          microsecond: microsecond,\n          time_zone: time_zone,\n          zone_abbr: zone_abbr,\n          utc_offset: utc_offset,\n          std_offset: std_offset\n        }\n\n  @typedoc \"\"\"\n  Specifies the time zone database for calendar operations.\n\n  Many functions in the `DateTime` module require a time zone database.\n  By default, this module uses the default time zone database returned by\n  `Calendar.get_time_zone_database/0`, which defaults to\n  `Calendar.UTCOnlyTimeZoneDatabase`. This database only handles `Etc/UTC`\n  datetimes and returns `{:error, :utc_only_time_zone_database}`\n  for any other time zone.\n\n  Other time zone databases (including ones provided by packages)\n  can be configured as default either via configuration:\n\n      config :elixir, :time_zone_database, CustomTimeZoneDatabase\n\n  or by calling `Calendar.put_time_zone_database/1`.\n\n  See `Calendar.TimeZoneDatabase` for more information on custom\n  time zone databases.\n  \"\"\"\n  @type time_zone_database :: module()\n\n  @typedoc \"\"\"\n  Options for formatting dates and times with `strftime/3`.\n  \"\"\"\n  @type strftime_opts :: [\n          preferred_datetime: String.t(),\n          preferred_date: String.t(),\n          preferred_time: String.t(),\n          am_pm_names: (:am | :pm -> String.t()) | (:am | :pm, map() -> String.t()),\n          month_names: (pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),\n          abbreviated_month_names:\n            (pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),\n          day_of_week_names: (pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),\n          abbreviated_day_of_week_names:\n            (pos_integer() -> String.t()) | (pos_integer(), map() -> String.t())\n        ]\n\n  @doc \"\"\"\n  Returns how many days there are in the given month of the given year.\n  \"\"\"\n  @callback days_in_month(year, month) :: day\n\n  @doc \"\"\"\n  Returns how many months there are in the given year.\n  \"\"\"\n  @callback months_in_year(year) :: month\n\n  @doc \"\"\"\n  Returns `true` if the given year is a leap year.\n\n  A leap year is a year of a longer length than normal. The exact meaning\n  is up to the calendar. A calendar must return `false` if it does not support\n  the concept of leap years.\n  \"\"\"\n  @callback leap_year?(year) :: boolean\n\n  @doc \"\"\"\n  Calculates the day of the week from the given `year`, `month`, and `day`.\n\n  `starting_on` represents the starting day of the week. All\n  calendars must support at least the `:default` value. They may\n  also support other values representing their days of the week.\n\n  The value of `day_of_week` is an ordinal number meaning that a\n  value of `1` is defined to mean \"first day of the week\". It is\n  specifically not defined to mean `1` is `Monday`.\n\n  It is a requirement that `first_day_of_week` is less than `last_day_of_week`\n  and that `day_of_week` must be within that range. Therefore it can be said\n  that `day_of_week in first_day_of_week..last_day_of_week//1` must be\n  `true` for all values of `day_of_week`.\n  \"\"\"\n  @callback day_of_week(year, month, day, starting_on :: :default | atom) ::\n              {day_of_week(), first_day_of_week :: non_neg_integer(),\n               last_day_of_week :: non_neg_integer()}\n\n  @doc \"\"\"\n  Calculates the day of the year from the given `year`, `month`, and `day`.\n  \"\"\"\n  @callback day_of_year(year, month, day) :: non_neg_integer()\n\n  @doc \"\"\"\n  Calculates the quarter of the year from the given `year`, `month`, and `day`.\n  \"\"\"\n  @callback quarter_of_year(year, month, day) :: non_neg_integer()\n\n  @doc \"\"\"\n  Calculates the year and era from the given `year`.\n  \"\"\"\n  @callback year_of_era(year, month, day) :: {year, era}\n\n  @doc \"\"\"\n  Calculates the day and era from the given `year`, `month`, and `day`.\n  \"\"\"\n  @callback day_of_era(year, month, day) :: day_of_era()\n\n  @doc \"\"\"\n  Converts the date into a string according to the calendar.\n  \"\"\"\n  @callback date_to_string(year, month, day) :: String.t()\n\n  @doc \"\"\"\n  Converts the naive datetime (without time zone) into a string according to the calendar.\n  \"\"\"\n  @callback naive_datetime_to_string(year, month, day, hour, minute, second, microsecond) ::\n              String.t()\n\n  @doc \"\"\"\n  Converts the datetime (with time zone) into a string according to the calendar.\n  \"\"\"\n  @callback datetime_to_string(\n              year,\n              month,\n              day,\n              hour,\n              minute,\n              second,\n              microsecond,\n              time_zone,\n              zone_abbr,\n              utc_offset,\n              std_offset\n            ) :: String.t()\n\n  @doc \"\"\"\n  Converts the time into a string according to the calendar.\n  \"\"\"\n  @callback time_to_string(hour, minute, second, microsecond) :: String.t()\n\n  @doc \"\"\"\n  Converts the datetime (without time zone) into the `t:iso_days/0` format.\n  \"\"\"\n  @callback naive_datetime_to_iso_days(year, month, day, hour, minute, second, microsecond) ::\n              iso_days\n\n  @doc \"\"\"\n  Converts `t:iso_days/0` to the calendar's datetime format.\n  \"\"\"\n  @callback naive_datetime_from_iso_days(iso_days) ::\n              {year, month, day, hour, minute, second, microsecond}\n\n  @doc \"\"\"\n  Converts the given time to the `t:day_fraction/0` format.\n  \"\"\"\n  @callback time_to_day_fraction(hour, minute, second, microsecond) :: day_fraction\n\n  @doc \"\"\"\n  Converts `t:day_fraction/0` to the calendar's time format.\n  \"\"\"\n  @callback time_from_day_fraction(day_fraction) :: {hour, minute, second, microsecond}\n\n  @doc \"\"\"\n  Define the rollover moment for the calendar.\n\n  This is the moment, in your calendar, when the current day ends\n  and the next day starts.\n\n  The result of this function is used to check if two calendars roll over at\n  the same time of day. If they do not, we can only convert datetimes and times\n  between them. If they do, this means that we can also convert dates as well\n  as naive datetimes between them.\n\n  This day fraction should be in its most simplified form possible, to make comparisons fast.\n\n  ## Examples\n\n    * If in your calendar a new day starts at midnight, return `{0, 1}`.\n    * If in your calendar a new day starts at sunrise, return `{1, 4}`.\n    * If in your calendar a new day starts at noon, return `{1, 2}`.\n    * If in your calendar a new day starts at sunset, return `{3, 4}`.\n\n  \"\"\"\n  @callback day_rollover_relative_to_midnight_utc() :: day_fraction\n\n  @doc \"\"\"\n  Should return `true` if the given date describes a proper date in the calendar.\n  \"\"\"\n  @callback valid_date?(year, month, day) :: boolean\n\n  @doc \"\"\"\n  Should return `true` if the given time describes a proper time in the calendar.\n  \"\"\"\n  @callback valid_time?(hour, minute, second, microsecond) :: boolean\n\n  @doc \"\"\"\n  Parses the string representation for a time returned by `c:time_to_string/4`\n  into a time tuple.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @callback parse_time(String.t()) ::\n              {:ok, {hour, minute, second, microsecond}}\n              | {:error, atom}\n\n  @doc \"\"\"\n  Parses the string representation for a date returned by `c:date_to_string/3`\n  into a date tuple.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @callback parse_date(String.t()) ::\n              {:ok, {year, month, day}}\n              | {:error, atom}\n\n  @doc \"\"\"\n  Parses the string representation for a naive datetime returned by\n  `c:naive_datetime_to_string/7` into a naive datetime tuple.\n\n  The given string may contain a timezone offset but it is ignored.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @callback parse_naive_datetime(String.t()) ::\n              {:ok, {year, month, day, hour, minute, second, microsecond}}\n              | {:error, atom}\n\n  @doc \"\"\"\n  Parses the string representation for a datetime returned by\n  `c:datetime_to_string/11` into a datetime tuple.\n\n  The returned datetime must be in UTC. The original `utc_offset`\n  it was written in must be returned in the result.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @callback parse_utc_datetime(String.t()) ::\n              {:ok, {year, month, day, hour, minute, second, microsecond}, utc_offset}\n              | {:error, atom}\n\n  @doc \"\"\"\n  Converts the given `t:iso_days/0` to the first moment of the day.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @callback iso_days_to_beginning_of_day(iso_days) :: iso_days\n\n  @doc \"\"\"\n  Converts the given `t:iso_days/0` to the last moment of the day.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @callback iso_days_to_end_of_day(iso_days) :: iso_days\n\n  @doc \"\"\"\n  Shifts date by given duration according to its calendar.\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @callback shift_date(year, month, day, Duration.t()) :: {year, month, day}\n\n  @doc \"\"\"\n  Shifts naive datetime by given duration according to its calendar.\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @callback shift_naive_datetime(\n              year,\n              month,\n              day,\n              hour,\n              minute,\n              second,\n              microsecond,\n              Duration.t()\n            ) :: {year, month, day, hour, minute, second, microsecond}\n\n  @doc \"\"\"\n  Shifts time by given duration according to its calendar.\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @callback shift_time(hour, minute, second, microsecond, Duration.t()) ::\n              {hour, minute, second, microsecond}\n\n  # General Helpers\n\n  @doc \"\"\"\n  Returns `true` if two calendars have the same moment of starting a new day,\n  `false` otherwise.\n\n  If two calendars are not compatible, we can only convert datetimes and times\n  between them. If they are compatible, this means that we can also convert\n  dates as well as naive datetimes between them.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec compatible_calendars?(Calendar.calendar(), Calendar.calendar()) :: boolean\n  def compatible_calendars?(calendar, calendar), do: true\n\n  def compatible_calendars?(calendar1, calendar2) do\n    calendar1.day_rollover_relative_to_midnight_utc() ==\n      calendar2.day_rollover_relative_to_midnight_utc()\n  end\n\n  @doc \"\"\"\n  Returns a microsecond tuple truncated to a given precision (`:microsecond`,\n  `:millisecond`, or `:second`).\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec truncate(Calendar.microsecond(), :microsecond | :millisecond | :second) ::\n          Calendar.microsecond()\n  def truncate(microsecond_tuple, :microsecond), do: microsecond_tuple\n\n  def truncate({microsecond, precision}, :millisecond) do\n    output_precision = min(precision, 3)\n    {div(microsecond, 1000) * 1000, output_precision}\n  end\n\n  def truncate(_, :second), do: {0, 0}\n\n  @doc \"\"\"\n  Sets the current time zone database.\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec put_time_zone_database(time_zone_database()) :: :ok\n  def put_time_zone_database(database) when is_atom(database) do\n    Application.put_env(:elixir, :time_zone_database, database)\n  end\n\n  @doc \"\"\"\n  Gets the current time zone database.\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec get_time_zone_database() :: time_zone_database()\n  def get_time_zone_database() do\n    Application.fetch_env!(:elixir, :time_zone_database)\n  end\n\n  @doc \"\"\"\n  Formats the given date, time, or datetime into a string.\n\n  The datetime can be any of the `Calendar` types (`Time`, `Date`,\n  `NaiveDateTime`, and `DateTime`) or any map, as long as they\n  contain all of the relevant fields necessary for formatting.\n  For example, if you use `%Y` to format the year, the datetime\n  must have the `:year` field. Therefore, if you pass a `Time`,\n  or a map without the `:year` field to a format that expects `%Y`,\n  an error will be raised.\n\n  Examples of common usage:\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06.0Z], \"%y-%m-%d %I:%M:%S %p\")\n      \"19-08-26 01:52:06 PM\"\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06.0Z], \"%a, %B %d %Y\")\n      \"Mon, August 26 2019\"\n\n  ## User Options\n\n    * `:preferred_datetime` - a string for the preferred format to show datetimes,\n      it can't contain the `%c` format and defaults to `\"%Y-%m-%d %H:%M:%S\"`\n      if the option is not received\n\n    * `:preferred_date` - a string for the preferred format to show dates,\n      it can't contain the `%x` format and defaults to `\"%Y-%m-%d\"`\n      if the option is not received\n\n    * `:preferred_time` - a string for the preferred format to show times,\n      it can't contain the `%X` format and defaults to `\"%H:%M:%S\"`\n      if the option is not received\n\n    * `:am_pm_names` - a function that receives either `:am` or `:pm`\n      (and also the datetime if the function is arity/2) and returns\n      the name of the period of the day, if the option is not received it defaults\n      to a function that returns `\"am\"` and `\"pm\"`, respectively\n\n    *  `:month_names` - a function that receives a number (and also the\n      datetime if the function is arity/2) and returns the name of\n      the corresponding month, if the option is not received it defaults to a\n      function that returns the month names in English\n\n    * `:abbreviated_month_names` - a function that receives a number (and also\n      the datetime if the function is arity/2) and returns the\n      abbreviated name of the corresponding month, if the option is not received it\n      defaults to a function that returns the abbreviated month names in English\n\n    * `:day_of_week_names` - a function that receives a number and (and also the\n      datetime if the function is arity/2) returns the name of\n      the corresponding day of week, if the option is not received it defaults to a\n      function that returns the day of week names in English\n\n    * `:abbreviated_day_of_week_names` - a function that receives a number (and also\n      the datetime if the function is arity/2) and returns the abbreviated name of\n      the corresponding day of week, if the option is not received it defaults to a\n      function that returns the abbreviated day of week names in English\n\n  ## Formatting syntax\n\n  The formatting syntax for the `string_format` argument is a sequence of characters in\n  the following format:\n\n      %<padding><width><format>\n\n  where:\n\n    * `%`: indicates the start of a formatted section\n    * `<padding>`: set the padding (see below)\n    * `<width>`: a number indicating the minimum size of the formatted section\n    * `<format>`: the format itself (see below)\n\n  ### Accepted padding options\n\n    * `-`: no padding, removes all padding from the format\n    * `_`: pad with spaces\n    * `0`: pad with zeroes\n\n  ### Accepted string formats\n\n  The accepted formats for `string_format` are:\n\n  Format | Description                                                             | Examples (in ISO)\n  :----- | :-----------------------------------------------------------------------| :------------------------\n  a      | Abbreviated name of day                                                 | Mon\n  A      | Full name of day                                                        | Monday\n  b      | Abbreviated month name                                                  | Jan\n  B      | Full month name                                                         | January\n  c      | Preferred date+time representation                                      | 2018-10-17 12:34:56\n  d      | Day of the month                                                        | 01, 31\n  f      | Microseconds (uses its precision for width and padding)                 | 000000, 999999, 0123\n  H      | Hour using a 24-hour clock                                              | 00, 23\n  I      | Hour using a 12-hour clock                                              | 01, 12\n  j      | Day of the year                                                         | 001, 366\n  m      | Month                                                                   | 01, 12\n  M      | Minute                                                                  | 00, 59\n  p      | \"AM\" or \"PM\" (noon is \"PM\", midnight as \"AM\")                           | AM, PM\n  P      | \"am\" or \"pm\" (noon is \"pm\", midnight as \"am\")                           | am, pm\n  q      | Quarter                                                                 | 1, 2, 3, 4\n  s      | Number of seconds since the Epoch, 1970-01-01 00:00:00+0000 (UTC)       | 1565888877\n  S      | Second                                                                  | 00, 59, 60\n  u      | Day of the week                                                         | 1 (Monday), 7 (Sunday)\n  x      | Preferred date (without time) representation                            | 2018-10-17\n  X      | Preferred time (without date) representation                            | 12:34:56\n  y      | Year as 2-digits                                                        | 01, 01, 86, 18\n  Y      | Year                                                                    | -0001, 0001, 1986\n  z      | +hhmm/-hhmm time zone offset from UTC (empty string if naive)           | +0300, -0530\n  Z      | Time zone abbreviation (empty string if naive)                          | CET, BRST\n  %      | Literal \"%\" character                                                   | %\n\n  Any other character will be interpreted as an invalid format and raise an error.\n\n  ### `%f` Microseconds\n\n  `%f` does not support width and padding modifiers.  It will be formatted by truncating\n  the microseconds to the precision of the `microseconds` field of the struct, with a\n  minimum precision of 1.\n\n  ## Examples\n\n  Without user options:\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06.0Z], \"%y-%m-%d %I:%M:%S %p\")\n      \"19-08-26 01:52:06 PM\"\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06.0Z], \"%a, %B %d %Y\")\n      \"Mon, August 26 2019\"\n\n      iex> Calendar.strftime(~U[2020-04-02 13:52:06.0Z], \"%B %-d, %Y\")\n      \"April 2, 2020\"\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06.0Z], \"%c\")\n      \"2019-08-26 13:52:06\"\n\n  With user options:\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06.0Z], \"%c\", preferred_datetime: \"%H:%M:%S %d-%m-%y\")\n      \"13:52:06 26-08-19\"\n\n      iex> Calendar.strftime(\n      ...>  ~U[2019-08-26 13:52:06.0Z],\n      ...>  \"%A\",\n      ...>  day_of_week_names: fn day_of_week ->\n      ...>    {\"segunda-feira\", \"terça-feira\", \"quarta-feira\", \"quinta-feira\",\n      ...>    \"sexta-feira\", \"sábado\", \"domingo\"}\n      ...>    |> elem(day_of_week - 1)\n      ...>  end\n      ...>)\n      \"segunda-feira\"\n\n      iex> Calendar.strftime(\n      ...>  ~U[2019-08-26 13:52:06.0Z],\n      ...>  \"%B\",\n      ...>  month_names: fn month ->\n      ...>    {\"січень\", \"лютий\", \"березень\", \"квітень\", \"травень\", \"червень\",\n      ...>    \"липень\", \"серпень\", \"вересень\", \"жовтень\", \"листопад\", \"грудень\"}\n      ...>    |> elem(month - 1)\n      ...>  end\n      ...>)\n      \"серпень\"\n\n   Microsecond formatting:\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06Z], \"%y-%m-%d %H:%M:%S.%f\")\n      \"19-08-26 13:52:06.0\"\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06.048Z], \"%y-%m-%d %H:%M:%S.%f\")\n      \"19-08-26 13:52:06.048\"\n\n      iex> Calendar.strftime(~U[2019-08-26 13:52:06.048531Z], \"%y-%m-%d %H:%M:%S.%f\")\n      \"19-08-26 13:52:06.048531\"\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec strftime(map(), String.t(), strftime_opts()) :: String.t()\n  def strftime(date_or_time_or_datetime, string_format, user_options \\\\ [])\n      when is_map(date_or_time_or_datetime) and is_binary(string_format) do\n    parse(\n      string_format,\n      date_or_time_or_datetime,\n      options(user_options),\n      []\n    )\n    |> IO.iodata_to_binary()\n  end\n\n  defp parse(\"\", _datetime, _format_options, acc),\n    do: Enum.reverse(acc)\n\n  defp parse(\"%\" <> rest, datetime, format_options, acc),\n    do: parse_modifiers(rest, nil, nil, {datetime, format_options, acc})\n\n  defp parse(<<char, rest::binary>>, datetime, format_options, acc),\n    do: parse(rest, datetime, format_options, [char | acc])\n\n  defp parse_modifiers(\"-\" <> rest, width, nil, parser_data) do\n    parse_modifiers(rest, width, \"\", parser_data)\n  end\n\n  defp parse_modifiers(\"0\" <> rest, nil, nil, parser_data) do\n    parse_modifiers(rest, nil, ?0, parser_data)\n  end\n\n  defp parse_modifiers(\"_\" <> rest, width, nil, parser_data) do\n    parse_modifiers(rest, width, ?\\s, parser_data)\n  end\n\n  defp parse_modifiers(<<digit, rest::binary>>, width, pad, parser_data) when digit in ?0..?9 do\n    new_width = (width || 0) * 10 + (digit - ?0)\n\n    parse_modifiers(rest, new_width, pad, parser_data)\n  end\n\n  # set default padding if none was specified\n  defp parse_modifiers(<<format, _::binary>> = rest, width, nil, parser_data) do\n    parse_modifiers(rest, width, default_pad(format), parser_data)\n  end\n\n  # set default width if none was specified\n  defp parse_modifiers(<<format, _::binary>> = rest, nil, pad, parser_data) do\n    parse_modifiers(rest, default_width(format), pad, parser_data)\n  end\n\n  defp parse_modifiers(rest, width, pad, {datetime, format_options, acc}) do\n    format_modifiers(rest, width, pad, datetime, format_options, acc)\n  end\n\n  defp am_pm(hour, format_options, datetime) when hour > 11 do\n    apply_format(:pm, format_options.am_pm_names, datetime)\n  end\n\n  defp am_pm(hour, format_options, datetime) when hour <= 11 do\n    apply_format(:am, format_options.am_pm_names, datetime)\n  end\n\n  defp default_pad(format) when format in ~c\"aAbBpPZ\", do: ?\\s\n  defp default_pad(_format), do: ?0\n\n  defp default_width(format) when format in ~c\"dHImMSy\", do: 2\n  defp default_width(?j), do: 3\n  defp default_width(format) when format in ~c\"Yz\", do: 4\n  defp default_width(_format), do: 0\n\n  # Literally just %\n  defp format_modifiers(\"%\" <> rest, width, pad, datetime, format_options, acc) do\n    parse(rest, datetime, format_options, [pad_leading(\"%\", width, pad) | acc])\n  end\n\n  # Abbreviated name of day\n  defp format_modifiers(\"a\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      datetime\n      |> Date.day_of_week()\n      |> apply_format(format_options.abbreviated_day_of_week_names, datetime)\n      |> pad_leading(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Full name of day\n  defp format_modifiers(\"A\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      datetime\n      |> Date.day_of_week()\n      |> apply_format(format_options.day_of_week_names, datetime)\n      |> pad_leading(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Abbreviated month name\n  defp format_modifiers(\"b\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      datetime.month\n      |> apply_format(format_options.abbreviated_month_names, datetime)\n      |> pad_leading(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Full month name\n  defp format_modifiers(\"B\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      datetime.month\n      |> apply_format(format_options.month_names, datetime)\n      |> pad_leading(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Preferred date+time representation\n  defp format_modifiers(\n         \"c\" <> _rest,\n         _width,\n         _pad,\n         _datetime,\n         %{preferred_datetime_invoked: true},\n         _acc\n       ) do\n    raise ArgumentError,\n          \"tried to format preferred_datetime within another preferred_datetime format\"\n  end\n\n  defp format_modifiers(\"c\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      format_options.preferred_datetime\n      |> parse(datetime, %{format_options | preferred_datetime_invoked: true}, [])\n      |> pad_preferred(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Day of the month\n  defp format_modifiers(\"d\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime.day |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Microseconds\n  defp format_modifiers(\"f\" <> rest, _width, _pad, datetime, format_options, acc) do\n    {microsecond, precision} = datetime.microsecond\n\n    result =\n      microsecond\n      |> Integer.to_string()\n      |> String.pad_leading(6, \"0\")\n      |> binary_part(0, max(precision, 1))\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Hour using a 24-hour clock\n  defp format_modifiers(\"H\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime.hour |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Hour using a 12-hour clock\n  defp format_modifiers(\"I\" <> rest, width, pad, datetime, format_options, acc) do\n    result = (rem(datetime.hour + 23, 12) + 1) |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Day of the year\n  defp format_modifiers(\"j\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime |> Date.day_of_year() |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Month\n  defp format_modifiers(\"m\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime.month |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Minute\n  defp format_modifiers(\"M\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime.minute |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # \"AM\" or \"PM\" (noon is \"PM\", midnight as \"AM\")\n  defp format_modifiers(\"p\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      datetime.hour\n      |> am_pm(format_options, datetime)\n      |> String.upcase()\n      |> pad_leading(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # \"am\" or \"pm\" (noon is \"pm\", midnight as \"am\")\n  defp format_modifiers(\"P\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      datetime.hour\n      |> am_pm(format_options, datetime)\n      |> String.downcase()\n      |> pad_leading(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Quarter\n  defp format_modifiers(\"q\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime |> Date.quarter_of_year() |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Second\n  defp format_modifiers(\"S\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime.second |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Day of the week\n  defp format_modifiers(\"u\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime |> Date.day_of_week() |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Preferred date (without time) representation\n  defp format_modifiers(\n         \"x\" <> _rest,\n         _width,\n         _pad,\n         _datetime,\n         %{preferred_date_invoked: true},\n         _acc\n       ) do\n    raise ArgumentError,\n          \"tried to format preferred_date within another preferred_date format\"\n  end\n\n  defp format_modifiers(\"x\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      format_options.preferred_date\n      |> parse(datetime, %{format_options | preferred_date_invoked: true}, [])\n      |> pad_preferred(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Preferred time (without date) representation\n  defp format_modifiers(\n         \"X\" <> _rest,\n         _width,\n         _pad,\n         _datetime,\n         %{preferred_time_invoked: true},\n         _acc\n       ) do\n    raise ArgumentError,\n          \"tried to format preferred_time within another preferred_time format\"\n  end\n\n  defp format_modifiers(\"X\" <> rest, width, pad, datetime, format_options, acc) do\n    result =\n      format_options.preferred_time\n      |> parse(datetime, %{format_options | preferred_time_invoked: true}, [])\n      |> pad_preferred(width, pad)\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Year as 2-digits\n  defp format_modifiers(\"y\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime.year |> rem(100) |> Integer.to_string() |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Year\n  defp format_modifiers(\"Y\" <> rest, width, pad, datetime, format_options, acc) do\n    {sign, year} =\n      if datetime.year < 0 do\n        {?-, -datetime.year}\n      else\n        {[], datetime.year}\n      end\n\n    result = [sign | year |> Integer.to_string() |> pad_leading(width, pad)]\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Epoch time for DateTime with time zones\n  defp format_modifiers(\n         \"s\" <> rest,\n         _width,\n         _pad,\n         datetime = %{utc_offset: _utc_offset, std_offset: _std_offset},\n         format_options,\n         acc\n       ) do\n    result =\n      datetime\n      |> DateTime.shift_zone!(\"Etc/UTC\")\n      |> NaiveDateTime.diff(~N[1970-01-01 00:00:00])\n      |> Integer.to_string()\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # Epoch time\n  defp format_modifiers(\"s\" <> rest, _width, _pad, datetime, format_options, acc) do\n    result =\n      datetime\n      |> NaiveDateTime.diff(~N[1970-01-01 00:00:00])\n      |> Integer.to_string()\n\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  # +hhmm/-hhmm time zone offset from UTC (empty string if naive)\n  defp format_modifiers(\n         \"z\" <> rest,\n         width,\n         pad,\n         datetime = %{utc_offset: utc_offset, std_offset: std_offset},\n         format_options,\n         acc\n       ) do\n    absolute_offset = abs(utc_offset + std_offset)\n\n    offset_number =\n      Integer.to_string(div(absolute_offset, 3600) * 100 + rem(div(absolute_offset, 60), 60))\n\n    sign = if utc_offset + std_offset >= 0, do: \"+\", else: \"-\"\n    result = \"#{sign}#{pad_leading(offset_number, width, pad)}\"\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  defp format_modifiers(\"z\" <> rest, _width, _pad, datetime, format_options, acc) do\n    parse(rest, datetime, format_options, [\"\" | acc])\n  end\n\n  # Time zone abbreviation (empty string if naive)\n  defp format_modifiers(\"Z\" <> rest, width, pad, datetime, format_options, acc) do\n    result = datetime |> Map.get(:zone_abbr, \"\") |> pad_leading(width, pad)\n    parse(rest, datetime, format_options, [result | acc])\n  end\n\n  defp format_modifiers(rest, _width, _pad, _datetime, _format_options, _acc) do\n    {next, _rest} = String.next_grapheme(rest) || {\"\", \"\"}\n    raise ArgumentError, \"invalid strftime format: %#{next}\"\n  end\n\n  defp pad_preferred(result, width, pad) when length(result) < width do\n    pad_preferred([pad | result], width, pad)\n  end\n\n  defp pad_preferred(result, _width, _pad), do: result\n\n  defp pad_leading(string, count, padding) do\n    to_pad = count - byte_size(string)\n    if to_pad > 0, do: do_pad_leading(to_pad, padding, string), else: string\n  end\n\n  defp do_pad_leading(0, _, acc), do: acc\n\n  defp do_pad_leading(count, padding, acc),\n    do: do_pad_leading(count - 1, padding, [padding | acc])\n\n  defp apply_format(term, formatter, _datetime) when is_function(formatter, 1) do\n    formatter.(term)\n  end\n\n  defp apply_format(term, formatter, datetime) when is_function(formatter, 2) do\n    formatter.(term, datetime)\n  end\n\n  defp apply_format(_term, formatter, _datetime) do\n    raise ArgumentError, \"formatter functions must be of arity 1 or 2, got: #{inspect(formatter)}\"\n  end\n\n  defp options(user_options) do\n    default_options = %{\n      preferred_date: \"%Y-%m-%d\",\n      preferred_time: \"%H:%M:%S\",\n      preferred_datetime: \"%Y-%m-%d %H:%M:%S\",\n      am_pm_names: fn\n        :am -> \"am\"\n        :pm -> \"pm\"\n      end,\n      month_names: fn month ->\n        {\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\",\n         \"October\", \"November\", \"December\"}\n        |> elem(month - 1)\n      end,\n      day_of_week_names: fn day_of_week ->\n        {\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\", \"Sunday\"}\n        |> elem(day_of_week - 1)\n      end,\n      abbreviated_month_names: fn month ->\n        {\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"}\n        |> elem(month - 1)\n      end,\n      abbreviated_day_of_week_names: fn day_of_week ->\n        {\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"} |> elem(day_of_week - 1)\n      end,\n      preferred_datetime_invoked: false,\n      preferred_date_invoked: false,\n      preferred_time_invoked: false\n    }\n\n    Enum.reduce(user_options, default_options, fn {key, value}, acc ->\n      if Map.has_key?(acc, key) do\n        %{acc | key => value}\n      else\n        raise ArgumentError, \"unknown option #{inspect(key)} given to Calendar.strftime/3\"\n      end\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/code/formatter.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Code.Formatter do\n  @moduledoc false\n  import Inspect.Algebra, except: [format: 2, surround: 3, surround: 4]\n\n  @double_quote \"\\\"\"\n  @double_heredoc \"\\\"\\\"\\\"\"\n  @single_quote \"'\"\n  @single_heredoc \"'''\"\n  @sigil_c_double \"~c\\\"\"\n  @sigil_c_single \"~c'\"\n  @sigil_c_heredoc \"~c\\\"\\\"\\\"\"\n  @newlines 2\n  @min_line 0\n  @max_line 9_999_999\n  @empty empty()\n  @ampersand_prec Code.Identifier.unary_op(:&) |> elem(1)\n\n  # Operators that are composed of multiple binary operators\n  @multi_binary_operators [:..//]\n\n  # Operators that do not have space between operands\n  @no_space_binary_operators [:.., :\"//\"]\n\n  # Operators that do not have newline between operands (as well as => and keywords)\n  @no_newline_binary_operators [:\\\\, :in]\n\n  # Left associative operators that start on the next line in case of breaks (always pipes)\n  @pipeline_operators [:|>, :~>>, :<<~, :~>, :<~, :<~>, :\"<|>\"]\n\n  # Right associative operators that start on the next line in case of breaks\n  @right_new_line_before_binary_operators [:|, :when]\n\n  # Operators that are logical cannot be mixed without parens\n  @required_parens_logical_binary_operands [:|||, :||, :or, :&&&, :&&, :and]\n\n  # Operators with next break fits\n  @next_break_fits_operators [:<-, :==, :!=, :=~, :===, :!==, :<, :>, :<=, :>=, :=, :\"::\"]\n\n  # Operators that always require parens even\n  # when they are their own parents as they are not semantically associative\n  @required_parens_even_when_parent [:--, :---]\n\n  # Operators that always require parens on operands\n  # when they are the parent of another operator with a difference precedence\n  # Most operators are listed, except comparison, arithmetic, and low precedence\n  @required_parens_on_binary_operands [\n    :<<<,\n    :>>>,\n    :|>,\n    :<~,\n    :~>,\n    :<<~,\n    :~>>,\n    :<~>,\n    :\"<|>\",\n    :in,\n    :\"^^^\",\n    :\"//\",\n    :++,\n    :--,\n    :+++,\n    :---,\n    :<>,\n    :..\n  ]\n\n  @locals_without_parens [\n    # Special forms\n    alias: 1,\n    alias: 2,\n    case: 2,\n    cond: 1,\n    for: :*,\n    import: 1,\n    import: 2,\n    quote: 1,\n    quote: 2,\n    receive: 1,\n    require: 1,\n    require: 2,\n    try: 1,\n    with: :*,\n\n    # Kernel\n    def: 1,\n    def: 2,\n    defp: 1,\n    defp: 2,\n    defguard: 1,\n    defguardp: 1,\n    defmacro: 1,\n    defmacro: 2,\n    defmacrop: 1,\n    defmacrop: 2,\n    defmodule: 2,\n    defdelegate: 2,\n    defexception: 1,\n    defoverridable: 1,\n    defstruct: 1,\n    destructure: 2,\n    raise: 1,\n    raise: 2,\n    reraise: 2,\n    reraise: 3,\n    if: 2,\n    unless: 2,\n    use: 1,\n    use: 2,\n\n    # Stdlib,\n    defrecord: 2,\n    defrecord: 3,\n    defrecordp: 2,\n    defrecordp: 3,\n\n    # Testing\n    assert: 1,\n    assert: 2,\n    assert_in_delta: 3,\n    assert_in_delta: 4,\n    assert_raise: 2,\n    assert_raise: 3,\n    assert_receive: 1,\n    assert_receive: 2,\n    assert_receive: 3,\n    assert_received: 1,\n    assert_received: 2,\n    doctest: 1,\n    doctest: 2,\n    refute: 1,\n    refute: 2,\n    refute_in_delta: 3,\n    refute_in_delta: 4,\n    refute_receive: 1,\n    refute_receive: 2,\n    refute_receive: 3,\n    refute_received: 1,\n    refute_received: 2,\n    setup: 1,\n    setup: 2,\n    setup_all: 1,\n    setup_all: 2,\n    test: 1,\n    test: 2,\n\n    # Mix config\n    config: 2,\n    config: 3,\n    import_config: 1\n  ]\n\n  @do_end_keywords [:rescue, :catch, :else, :after]\n\n  @doc \"\"\"\n  Converts the quoted expression into an algebra document.\n  \"\"\"\n  @spec to_algebra(Macro.t(), keyword()) :: Inspect.Algebra.t()\n  def to_algebra(quoted, opts \\\\ []) do\n    comments = Keyword.get(opts, :comments, [])\n\n    state =\n      comments\n      |> Enum.map(&format_comment/1)\n      |> gather_comments()\n      |> state(opts)\n\n    {doc, _} = block_to_algebra(quoted, @min_line, @max_line, state)\n    doc\n  end\n\n  @doc \"\"\"\n  Lists all default locals without parens.\n  \"\"\"\n  def locals_without_parens do\n    @locals_without_parens\n  end\n\n  @doc \"\"\"\n  Checks if a function is a local without parens.\n  \"\"\"\n  def local_without_parens?(fun, arity, locals_without_parens) do\n    arity > 0 and\n      Enum.any?(locals_without_parens, fn {key, val} ->\n        key == fun and (val == :* or val == arity)\n      end)\n  end\n\n  defp state(comments, opts) do\n    force_do_end_blocks = Keyword.get(opts, :force_do_end_blocks, false)\n    locals_without_parens = Keyword.get(opts, :locals_without_parens, [])\n    file = Keyword.get(opts, :file, nil)\n    sigils = Keyword.get(opts, :sigils, [])\n    migrate = Keyword.get(opts, :migrate, false)\n    migrate_bitstring_modifiers = Keyword.get(opts, :migrate_bitstring_modifiers, migrate)\n    migrate_call_parens_on_pipe = Keyword.get(opts, :migrate_call_parens_on_pipe, migrate)\n    migrate_charlists_as_sigils = Keyword.get(opts, :migrate_charlists_as_sigils, migrate)\n    migrate_unless = Keyword.get(opts, :migrate_unless, migrate)\n    syntax_colors = Keyword.get(opts, :syntax_colors, [])\n\n    sigils =\n      Map.new(sigils, fn {key, value} ->\n        with true <- is_atom(key) and is_function(value, 2),\n             name = Atom.to_charlist(key),\n             true <- Enum.all?(name, &(&1 in ?A..?Z)) do\n          {name, value}\n        else\n          _ ->\n            raise ArgumentError,\n                  \":sigils must be a keyword list with uppercased atoms as keys and an \" <>\n                    \"anonymous function expecting two arguments as value, got: #{inspect(sigils)}\"\n        end\n      end)\n\n    %{\n      force_do_end_blocks: force_do_end_blocks,\n      locals_without_parens: locals_without_parens ++ locals_without_parens(),\n      operand_nesting: 2,\n      skip_eol: false,\n      comments: comments,\n      sigils: sigils,\n      file: file,\n      migrate_bitstring_modifiers: migrate_bitstring_modifiers,\n      migrate_call_parens_on_pipe: migrate_call_parens_on_pipe,\n      migrate_charlists_as_sigils: migrate_charlists_as_sigils,\n      migrate_unless: migrate_unless,\n      inspect_opts: %Inspect.Opts{syntax_colors: syntax_colors}\n    }\n  end\n\n  defp format_comment(%{text: text} = comment) do\n    %{comment | text: format_comment_text(text)}\n  end\n\n  defp format_comment_text(\"#\"), do: \"#\"\n  defp format_comment_text(\"#!\" <> rest), do: \"#!\" <> rest\n  defp format_comment_text(\"##\" <> rest), do: \"#\" <> format_comment_text(\"#\" <> rest)\n  defp format_comment_text(\"# \" <> rest), do: \"# \" <> rest\n  defp format_comment_text(\"#\" <> rest), do: \"# \" <> rest\n\n  # If there is a no new line before, we can't gather all followup comments.\n  defp gather_comments([%{previous_eol_count: 0} = comment | comments]) do\n    comment = %{comment | previous_eol_count: @newlines}\n    [comment | gather_comments(comments)]\n  end\n\n  defp gather_comments([comment | comments]) do\n    %{line: line, next_eol_count: next_eol_count, text: doc} = comment\n\n    {next_eol_count, comments, doc} =\n      gather_followup_comments(line + 1, next_eol_count, comments, doc)\n\n    comment = %{comment | next_eol_count: next_eol_count, text: doc}\n    [comment | gather_comments(comments)]\n  end\n\n  defp gather_comments([]) do\n    []\n  end\n\n  defp gather_followup_comments(line, _, [%{line: line} = comment | comments], doc)\n       when comment.previous_eol_count != 0 do\n    %{next_eol_count: next_eol_count, text: text} = comment\n    gather_followup_comments(line + 1, next_eol_count, comments, line(doc, text))\n  end\n\n  defp gather_followup_comments(_line, next_eol_count, comments, doc) do\n    {next_eol_count, comments, doc}\n  end\n\n  # Special AST nodes from compiler feedback\n\n  defp quoted_to_algebra({{:special, :clause_args}, _meta, [args]}, _context, state) do\n    {doc, state} = clause_args_to_algebra(args, state)\n    {group(doc), state}\n  end\n\n  defp quoted_to_algebra({{:special, :bitstring_segment}, _meta, [arg, last]}, _context, state) do\n    bitstring_segment_to_algebra({arg, -1}, state, last)\n  end\n\n  defp quoted_to_algebra({var, _meta, var_context}, _context, state) when is_atom(var_context) do\n    {var |> Atom.to_string() |> string() |> color_doc(:variable, state.inspect_opts), state}\n  end\n\n  defp quoted_to_algebra({:<<>>, meta, entries}, _context, state) do\n    cond do\n      entries == [] ->\n        {\"<<>>\", state}\n\n      not interpolated?(entries) ->\n        bitstring_to_algebra(meta, entries, state)\n\n      meta[:delimiter] == ~s[\"\"\"] ->\n        {doc, state} =\n          entries\n          |> prepend_heredoc_line()\n          |> interpolation_to_algebra(~s[\"\"\"], state, @double_heredoc, @double_heredoc)\n\n        {force_unfit(doc), state}\n\n      true ->\n        interpolation_to_algebra(entries, @double_quote, state, @double_quote, @double_quote)\n    end\n  end\n\n  # TODO: Remove this clause on Elixir v2.0 once single-quoted charlists are removed\n  defp quoted_to_algebra(\n         {{:., _, [List, :to_charlist]}, meta, [entries]} = quoted,\n         context,\n         state\n       ) do\n    cond do\n      not list_interpolated?(entries) ->\n        remote_to_algebra(quoted, context, state)\n\n      meta[:delimiter] == ~s['''] ->\n        {opener, quotes} = get_charlist_quotes(:heredoc, state)\n\n        {doc, state} =\n          entries\n          |> prepend_heredoc_line()\n          |> list_interpolation_to_algebra(quotes, state, opener, quotes)\n\n        {force_unfit(doc), state}\n\n      true ->\n        {opener, quotes} = get_charlist_quotes({:regular, entries}, state)\n        list_interpolation_to_algebra(entries, quotes, state, opener, quotes)\n    end\n  end\n\n  defp quoted_to_algebra(\n         {{:., _, [:erlang, :binary_to_atom]}, _, [{:<<>>, _, entries}, :utf8]} = quoted,\n         context,\n         state\n       ) do\n    if interpolated?(entries) do\n      interpolation_to_algebra(entries, @double_quote, state, \":\\\"\", @double_quote)\n    else\n      remote_to_algebra(quoted, context, state)\n    end\n  end\n\n  # foo[bar]\n  defp quoted_to_algebra({{:., _, [Access, :get]}, meta, [target, arg]}, _context, state) do\n    {target_doc, state} = remote_target_to_algebra(target, state)\n\n    {access_doc, state} =\n      if keyword?(arg) do\n        list_to_algebra(meta, arg, state)\n      else\n        list_to_algebra(meta, [arg], state)\n      end\n\n    {concat(target_doc, access_doc), state}\n  end\n\n  # %Foo{}\n  # %name{foo: 1}\n  # %name{bar | foo: 1}\n  defp quoted_to_algebra({:%, _, [name, {:%{}, meta, args}]}, _context, state) do\n    {name_doc, state} = quoted_to_algebra(name, :parens_arg, state)\n    map_to_algebra(meta, name_doc, args, state)\n  end\n\n  # %{foo: 1}\n  # %{foo => bar}\n  # %{name | foo => bar}\n  defp quoted_to_algebra({:%{}, meta, args}, _context, state) do\n    map_to_algebra(meta, @empty, args, state)\n  end\n\n  # {}\n  # {1, 2}\n  defp quoted_to_algebra({:{}, meta, args}, _context, state) do\n    tuple_to_algebra(meta, args, :flex_break, state)\n  end\n\n  defp quoted_to_algebra({:__block__, meta, [{left, right}]}, _context, state) do\n    tuple_to_algebra(meta, [left, right], :flex_break, state)\n  end\n\n  # (left -> right)\n  defp quoted_to_algebra({:__block__, _, [[{:->, _, _} | _] = clauses]}, _context, state) do\n    paren_fun_to_algebra(clauses, @max_line, @min_line, state)\n  end\n\n  defp quoted_to_algebra({:__block__, meta, [list]}, _context, state) when is_list(list) do\n    case meta[:delimiter] do\n      ~s['''] ->\n        {opener, quotes} = get_charlist_quotes(:heredoc, state)\n        string = list |> List.to_string() |> escape_heredoc(quotes)\n        {opener |> concat(string) |> concat(quotes) |> force_unfit(), state}\n\n      ~s['] ->\n        string = list |> List.to_string()\n        {opener, quotes} = get_charlist_quotes({:regular, [string]}, state)\n        string = escape_string(string, quotes)\n        {opener |> concat(string) |> concat(quotes), state}\n\n      _other ->\n        list_to_algebra(meta, list, state)\n    end\n  end\n\n  defp quoted_to_algebra({:__block__, meta, [string]}, _context, state) when is_binary(string) do\n    if meta[:delimiter] == ~s[\"\"\"] do\n      string = escape_heredoc(string, ~s[\"\"\"])\n\n      {@double_heredoc\n       |> concat(string)\n       |> concat(@double_heredoc)\n       |> color_doc(:string, state.inspect_opts)\n       |> force_unfit(), state}\n    else\n      string = escape_string(string, @double_quote)\n\n      {@double_quote\n       |> concat(string)\n       |> concat(@double_quote)\n       |> color_doc(:string, state.inspect_opts), state}\n    end\n  end\n\n  defp quoted_to_algebra({:__block__, meta, [atom]}, _context, state) when is_atom(atom) do\n    {atom_to_algebra(atom, meta, state.inspect_opts), state}\n  end\n\n  defp quoted_to_algebra({:__block__, meta, [integer]}, _context, state)\n       when is_integer(integer) do\n    {Keyword.fetch!(meta, :token) |> integer_to_algebra(state.inspect_opts), state}\n  end\n\n  defp quoted_to_algebra({:__block__, meta, [float]}, _context, state) when is_float(float) do\n    {Keyword.fetch!(meta, :token) |> float_to_algebra(state.inspect_opts), state}\n  end\n\n  # (unquote_splicing(...))\n  defp quoted_to_algebra(\n         {:__block__, _meta, [{:unquote_splicing, meta, [_] = args}]},\n         context,\n         state\n       ) do\n    {doc, state} = local_to_algebra(:unquote_splicing, meta, args, context, state)\n    {wrap_in_parens(doc), state}\n  end\n\n  defp quoted_to_algebra({:__block__, _meta, [arg]}, context, state) do\n    quoted_to_algebra(arg, context, state)\n  end\n\n  defp quoted_to_algebra({:__block__, _meta, []}, _context, state) do\n    {color_doc(\"nil\", nil, state.inspect_opts), state}\n  end\n\n  defp quoted_to_algebra({:__block__, meta, args} = block, _context, state) when is_list(args) do\n    {block, state} = block_to_algebra(block, line(meta), closing_line(meta), state)\n    {surround(\"(\", block, \")\"), state}\n  end\n\n  defp quoted_to_algebra({:__aliases__, _meta, [head | tail]}, context, state) do\n    {doc, state} =\n      if is_atom(head) do\n        {Atom.to_string(head), state}\n      else\n        quoted_to_algebra_with_parens_if_operator(head, context, state)\n      end\n\n    {Enum.reduce(tail, doc, &concat(&2, \".\" <> Atom.to_string(&1)))\n     |> color_doc(:atom, state.inspect_opts), state}\n  end\n\n  # &1\n  # &local(&1)\n  # &local/1\n  # &Mod.remote/1\n  # & &1\n  # & &1 + &2\n  defp quoted_to_algebra({:&, _, [arg]}, context, state) do\n    capture_to_algebra(arg, context, state)\n  end\n\n  defp quoted_to_algebra({:@, meta, [arg]}, context, state) do\n    module_attribute_to_algebra(meta, arg, context, state)\n  end\n\n  # not(left in right)\n  # left not in right\n  defp quoted_to_algebra({:not, meta, [{:in, _, [left, right]}]}, context, state) do\n    binary_op_to_algebra(:in, \"not in\", meta, left, right, context, state)\n  end\n\n  # disable migrate_call_parens_on_pipe within defmacro\n  defp quoted_to_algebra(\n         {atom, _, [{:|>, _, _}, _]} = ast,\n         context,\n         %{migrate_call_parens_on_pipe: true} = state\n       )\n       when atom in [:defmacro, :defmacrop] do\n    quoted_to_algebra(ast, context, %{state | migrate_call_parens_on_pipe: false})\n  end\n\n  defp quoted_to_algebra(\n         {atom, _, [{:unless, _, _}, _]} = ast,\n         context,\n         %{migrate_unless: true} = state\n       )\n       when atom in [:defmacro, :defmacrop] do\n    quoted_to_algebra(ast, context, %{state | migrate_unless: false})\n  end\n\n  # rewrite unless as if!\n  defp quoted_to_algebra(\n         {:unless, meta, [condition, block]},\n         context,\n         %{migrate_unless: true} = state\n       ) do\n    quoted_to_algebra({:if, meta, [negate_condition(condition), block]}, context, state)\n  end\n\n  # a |> b() |> unless(...) => a |> b() |> Kernel.!() |> unless(...)\n  defp quoted_to_algebra(\n         {:|>, meta1, [{:|>, _, _} = condition, {:unless, meta2, [block]}]},\n         context,\n         %{migrate_unless: true} = state\n       ) do\n    negated_condition = {:|>, [], [condition, {{:., [], [Kernel, :!]}, [closing: []], []}]}\n\n    quoted_to_algebra(\n      {:|>, meta1, [negated_condition, {:if, meta2, [block]}]},\n      context,\n      state\n    )\n  end\n\n  # condition |> unless(...) => negated(condition) |> unless(...)\n  defp quoted_to_algebra(\n         {:|>, meta1, [condition, {:unless, meta2, [block]}]},\n         context,\n         %{migrate_unless: true} = state\n       ) do\n    quoted_to_algebra(\n      {:|>, meta1, [negate_condition(condition), {:if, meta2, [block]}]},\n      context,\n      state\n    )\n  end\n\n  # ..\n  defp quoted_to_algebra({:.., _meta, []}, context, state) do\n    if context in [:no_parens_arg, :no_parens_one_arg] do\n      {\"(..)\", state}\n    else\n      {\"..\", state}\n    end\n  end\n\n  # ...\n  defp quoted_to_algebra({:..., _meta, []}, _context, state) do\n    {\"...\", state}\n  end\n\n  # 1..2//3\n  defp quoted_to_algebra({:..//, meta, [left, middle, right]}, context, state) do\n    quoted_to_algebra({:\"//\", meta, [{:.., meta, [left, middle]}, right]}, context, state)\n  end\n\n  defp quoted_to_algebra({:fn, meta, [_ | _] = clauses}, _context, state) do\n    anon_fun_to_algebra(clauses, line(meta), closing_line(meta), state, eol?(meta, state))\n  end\n\n  defp quoted_to_algebra({fun, meta, args}, context, state) when is_atom(fun) and is_list(args) do\n    with :error <- maybe_sigil_to_algebra(fun, meta, args, state),\n         :error <- maybe_unary_op_to_algebra(fun, meta, args, context, state),\n         :error <- maybe_binary_op_to_algebra(fun, meta, args, context, state),\n         do: local_to_algebra(fun, meta, args, context, state)\n  end\n\n  defp quoted_to_algebra({_, _, args} = quoted, context, state) when is_list(args) do\n    remote_to_algebra(quoted, context, state)\n  end\n\n  # [keyword: :list] (inner part)\n  # %{:foo => :bar} (inner part)\n  defp quoted_to_algebra(list, context, state) when is_list(list) do\n    many_args_to_algebra(list, state, &quoted_to_algebra(&1, context, &2))\n  end\n\n  # keyword: :list\n  # key => value\n  defp quoted_to_algebra({left_arg, right_arg}, context, state) do\n    {left, op, right, state} =\n      if keyword_key?(left_arg) do\n        {left, state} =\n          case left_arg do\n            {:__block__, _, [atom]} when is_atom(atom) ->\n              formatted = Macro.inspect_atom(:key, atom, escape: &escape_atom/2)\n\n              {formatted\n               |> string()\n               |> color_doc(:atom, state.inspect_opts), state}\n\n            {{:., _, [:erlang, :binary_to_atom]}, _, [{:<<>>, _, entries}, :utf8]} ->\n              interpolation_to_algebra(entries, @double_quote, state, \"\\\"\", \"\\\":\")\n          end\n\n        {right, state} = quoted_to_algebra(right_arg, context, state)\n        {left, \"\", right, state}\n      else\n        {left, state} = quoted_to_algebra(left_arg, context, state)\n        {right, state} = quoted_to_algebra(right_arg, context, state)\n        left = wrap_in_parens_if_binary_operator(left, left_arg)\n        {left, \" =>\", right, state}\n      end\n\n    doc =\n      concat(\n        group(left),\n        with_next_break_fits(next_break_fits?(right_arg, state), right, fn right ->\n          nest(glue(op, right), 2, :break)\n        end)\n      )\n\n    {doc, state}\n  end\n\n  # #PID's and #Ref's may appear on regular AST\n  # Other foreign structures, such as maps and structs,\n  # may appear from Macro.to_string, so we stick a limit,\n  # although they won't be formatted accordingly.\n  defp quoted_to_algebra(unknown, _context, state) do\n    {inspect(unknown, printable_limit: :infinity), state}\n  end\n\n  ## Blocks\n\n  defp block_to_algebra([{:->, _, _} | _] = paren_fun, min_line, max_line, state) do\n    paren_fun_to_algebra(paren_fun, min_line, max_line, state)\n  end\n\n  defp block_to_algebra({:__block__, _, []}, min_line, max_line, state) do\n    block_args_to_algebra([], min_line, max_line, state)\n  end\n\n  defp block_to_algebra({:__block__, _, [_, _ | _] = args}, min_line, max_line, state) do\n    block_args_to_algebra(args, min_line, max_line, state)\n  end\n\n  defp block_to_algebra(block, min_line, max_line, state) do\n    block_args_to_algebra([block], min_line, max_line, state)\n  end\n\n  defp block_args_to_algebra(args, min_line, max_line, state) do\n    quoted_to_algebra = fn {kind, meta, _} = arg, _args, state ->\n      newlines = meta[:end_of_expression][:newlines] || 1\n      {doc, state} = quoted_to_algebra(arg, :block, state)\n      {{doc, block_next_line(kind), newlines}, state}\n    end\n\n    {args_docs, _comments?, state} =\n      quoted_to_algebra_with_comments(args, [], min_line, max_line, state, quoted_to_algebra)\n\n    case args_docs do\n      [] -> {@empty, state}\n      [line] -> {line, state}\n      lines -> {lines |> Enum.reduce(&line(&2, &1)) |> force_unfit(), state}\n    end\n  end\n\n  defp block_next_line(:@), do: @empty\n  defp block_next_line(_), do: break(\"\")\n\n  ## Operators\n\n  defp maybe_unary_op_to_algebra(fun, meta, args, context, state) do\n    with [arg] <- args,\n         {_, _} <- Code.Identifier.unary_op(fun) do\n      unary_op_to_algebra(fun, meta, arg, context, state)\n    else\n      _ -> :error\n    end\n  end\n\n  defp unary_op_to_algebra(op, _meta, arg, context, state) do\n    {doc, state} = quoted_to_algebra(arg, force_many_args_or_operand(context, :operand), state)\n\n    # not and ! are nestable, all others are not.\n    doc =\n      case arg do\n        {^op, _, [_]} when op in [:!, :not] -> doc\n        _ -> wrap_in_parens_if_operator(doc, arg)\n      end\n\n    # not requires a space unless the doc was wrapped in parens.\n    op_string =\n      if op == :not do\n        \"not \"\n      else\n        Atom.to_string(op)\n      end\n\n    {color_doc(op_string, :operator, state.inspect_opts) |> concat(doc), state}\n  end\n\n  defp maybe_binary_op_to_algebra(fun, meta, args, context, state) do\n    with [left, right] <- args,\n         {_, _} <- augmented_binary_op(fun) do\n      binary_op_to_algebra(fun, Atom.to_string(fun), meta, left, right, context, state)\n    else\n      _ -> :error\n    end\n  end\n\n  # There are five kinds of operators.\n  #\n  #   1. no space binary operators, for example,  1..2\n  #   2. no newline binary operators, for example, left in right\n  #   3. strict newlines before a left precedent operator, for example, foo |> bar |> baz\n  #   4. strict newlines before a right precedent operator, for example, foo when bar when baz\n  #   5. flex newlines after the operator, for example, foo ++ bar ++ baz\n  #\n  # Cases 1, 2 and 5 are handled fairly easily by relying on the\n  # operator precedence and making sure nesting is applied only once.\n  #\n  # Cases 3 and 4 are the complex ones, as it requires passing the\n  # strict or flex mode around.\n  defp binary_op_to_algebra(op, op_string, meta, left_arg, right_arg, context, state) do\n    %{operand_nesting: nesting} = state\n    binary_op_to_algebra(op, op_string, meta, left_arg, right_arg, context, state, nesting)\n  end\n\n  defp binary_op_to_algebra(op, op_string, meta, left_arg, right_arg, context, state, _nesting)\n       when op in @right_new_line_before_binary_operators do\n    op_info = augmented_binary_op(op)\n    op_string = op_string <> \" \"\n    left_context = left_op_context(context)\n    right_context = right_op_context(context)\n\n    min_line =\n      case left_arg do\n        {_, left_meta, _} -> line(left_meta)\n        _ -> line(meta)\n      end\n\n    {operands, max_line} =\n      unwrap_right(right_arg, op, meta, right_context, [{{:root, left_context}, left_arg}])\n\n    fun = fn\n      {{:root, context}, arg}, _args, state ->\n        {doc, state} = binary_operand_to_algebra(arg, context, state, op, op_info, :left, 2)\n        {{doc, @empty, 1}, state}\n\n      {{kind, context}, arg}, _args, state ->\n        {doc, state} = binary_operand_to_algebra(arg, context, state, op, op_info, kind, 0)\n        doc = doc |> nest_by_length(op_string) |> force_keyword(arg)\n        {{concat(op_string, doc), @empty, 1}, state}\n    end\n\n    {doc, state} =\n      operand_to_algebra_with_comments(operands, meta, min_line, max_line, context, state, fun)\n\n    if keyword?(right_arg) and context in [:parens_arg, :no_parens_arg] do\n      {wrap_in_parens(doc), state}\n    else\n      {doc, state}\n    end\n  end\n\n  defp binary_op_to_algebra(op, _, meta, left_arg, right_arg, context, state, _nesting)\n       when op in @pipeline_operators do\n    op_info = augmented_binary_op(op)\n    left_context = left_op_context(context)\n    right_context = right_op_context(context)\n    max_line = line(meta)\n\n    {pipes, min_line} =\n      unwrap_pipes(left_arg, meta, left_context, [{{op, right_context}, right_arg}])\n\n    fun = fn\n      {{:root, context}, arg}, _args, state ->\n        {doc, state} = binary_operand_to_algebra(arg, context, state, op, op_info, :left, 2)\n        {{doc, @empty, 1}, state}\n\n      {{op, context}, arg}, _args, state ->\n        op_info = augmented_binary_op(op)\n        op_string = Atom.to_string(op) <> \" \"\n        {doc, state} = binary_operand_to_algebra(arg, context, state, op, op_info, :right, 0)\n        {{concat(op_string, doc), @empty, 1}, state}\n    end\n\n    operand_to_algebra_with_comments(pipes, meta, min_line, max_line, context, state, fun)\n  end\n\n  defp binary_op_to_algebra(op, op_string, meta, left_arg, right_arg, context, state, nesting) do\n    op_info = augmented_binary_op(op)\n    left_context = left_op_context(context)\n    right_context = right_op_context(context)\n\n    {left, state} =\n      binary_operand_to_algebra(left_arg, left_context, state, op, op_info, :left, 2)\n\n    {right, state} =\n      binary_operand_to_algebra(right_arg, right_context, state, op, op_info, :right, 0)\n\n    {op_string, right} =\n      cond do\n        op in @no_space_binary_operators ->\n          {op_string, group(right)}\n\n        op in @no_newline_binary_operators ->\n          {\" \" <> op_string <> \" \", group(right)}\n\n        true ->\n          eol? = eol?(meta, state)\n\n          next_break_fits? =\n            op in @next_break_fits_operators and next_break_fits?(right_arg, state) and not eol?\n\n          {\" \" <> op_string,\n           with_next_break_fits(next_break_fits?, right, fn right ->\n             right = nest(concat(break(), right), nesting, :break)\n             if eol?, do: force_unfit(right), else: right\n           end)}\n      end\n\n    op_doc = color_doc(op_string, :operator, state.inspect_opts)\n    doc = concat(concat(group(left), op_doc), group(right))\n    {doc, state}\n  end\n\n  # TODO: We can remove this workaround once we remove\n  # ?rearrange_uop from the parser on v2.0.\n  # (! left) in right\n  # (not left) in right\n  defp binary_operand_to_algebra(\n         {:__block__, _, [{op, meta, [arg]}]},\n         context,\n         state,\n         :in,\n         _parent_info,\n         :left,\n         _nesting\n       )\n       when op in [:not, :!] do\n    {doc, state} = unary_op_to_algebra(op, meta, arg, context, state)\n    {wrap_in_parens(doc), state}\n  end\n\n  # |> var\n  # |> var()\n  defp binary_operand_to_algebra(\n         {var, meta, var_context},\n         context,\n         %{migrate_call_parens_on_pipe: true} = state,\n         :|>,\n         _parent_info,\n         :right,\n         _nesting\n       )\n       when is_atom(var) and is_atom(var_context) do\n    operand = {var, meta, []}\n    quoted_to_algebra(operand, context, state)\n  end\n\n  # |> var.fun\n  # |> var.fun()\n  defp binary_operand_to_algebra(\n         {{:., _, [_, fun]} = call, meta, []},\n         context,\n         %{migrate_call_parens_on_pipe: true} = state,\n         :|>,\n         _parent_info,\n         :right,\n         _nesting\n       )\n       when is_atom(fun) do\n    meta = Keyword.put_new_lazy(meta, :closing, fn -> [line: meta[:line]] end)\n    quoted_to_algebra({call, meta, []}, context, state)\n  end\n\n  defp binary_operand_to_algebra(operand, context, state, parent_op, parent_info, side, nesting) do\n    {parent_assoc, parent_prec} = parent_info\n\n    with {op, meta, [left, right]} <- operand,\n         op_info = augmented_binary_op(op),\n         {_assoc, prec} <- op_info do\n      op_string = Atom.to_string(op)\n\n      cond do\n        # If we have the same operator and it is in the correct side,\n        # we don't add parens unless it is explicitly required.\n        parent_assoc == side and op == parent_op and op not in @required_parens_even_when_parent ->\n          binary_op_to_algebra(op, op_string, meta, left, right, context, state, nesting)\n\n        # If the operator requires parens (most of them do) or we are mixing logical operators\n        # or the precedence is inverted or it is in the wrong side, then we *need* parenthesis.\n        (parent_op in @required_parens_on_binary_operands and op not in @no_space_binary_operators) or\n          (op in @required_parens_logical_binary_operands and\n             parent_op in @required_parens_logical_binary_operands) or parent_prec > prec or\n            (parent_prec == prec and parent_assoc != side) ->\n          {operand, state} =\n            binary_op_to_algebra(op, op_string, meta, left, right, context, state, 2)\n\n          {wrap_in_parens(operand), state}\n\n        # Otherwise, we rely on precedence but also nest.\n        true ->\n          binary_op_to_algebra(op, op_string, meta, left, right, context, state, 2)\n      end\n    else\n      {:&, _, [arg]}\n      when not is_integer(arg) and side == :left\n      when not is_integer(arg) and parent_assoc == :left and parent_prec > @ampersand_prec ->\n        {doc, state} = quoted_to_algebra(operand, context, state)\n        {wrap_in_parens(doc), state}\n\n      _ ->\n        quoted_to_algebra(operand, context, state)\n    end\n  end\n\n  defp unwrap_pipes({op, meta, [left, right]}, _meta, context, acc)\n       when op in @pipeline_operators do\n    left_context = left_op_context(context)\n    right_context = right_op_context(context)\n    unwrap_pipes(left, meta, left_context, [{{op, right_context}, right} | acc])\n  end\n\n  defp unwrap_pipes(left, meta, context, acc) do\n    min_line =\n      case left do\n        {_, meta, _} -> line(meta)\n        _ -> line(meta)\n      end\n\n    {[{{:root, context}, left} | acc], min_line}\n  end\n\n  defp unwrap_right({op, meta, [left, right]}, op, _meta, context, acc) do\n    left_context = left_op_context(context)\n    right_context = right_op_context(context)\n    unwrap_right(right, op, meta, right_context, [{{:left, left_context}, left} | acc])\n  end\n\n  defp unwrap_right(right, _op, meta, context, acc) do\n    acc = [{{:right, context}, right} | acc]\n    {Enum.reverse(acc), line(meta)}\n  end\n\n  defp operand_to_algebra_with_comments(operands, meta, min_line, max_line, context, state, fun) do\n    # If we are in a no_parens_one_arg expression, we actually cannot\n    # extract comments from the first operand, because it would rewrite:\n    #\n    #     @spec function(x) ::\n    #             # Comment\n    #             any\n    #           when x: any\n    #\n    # to:\n    #\n    #     @spec # Comment\n    #           function(x) ::\n    #             any\n    #           when x: any\n    #\n    # Instead we get:\n    #\n    #     @spec function(x) ::\n    #             any\n    #           # Comment\n    #           when x: any\n    #\n    # Which may look counter-intuitive but it actually makes sense,\n    # as the closest possible location for the comment is the when\n    # operator.\n    {operands, acc, state} =\n      if context == :no_parens_one_arg do\n        [operand | operands] = operands\n        {doc_triplet, state} = fun.(operand, :unused, state)\n        {operands, [doc_triplet], state}\n      else\n        {operands, [], state}\n      end\n\n    {docs, comments?, state} =\n      quoted_to_algebra_with_comments(operands, acc, min_line, max_line, state, fun)\n\n    if comments? or eol?(meta, state) do\n      {docs |> Enum.reduce(&line(&2, &1)) |> force_unfit(), state}\n    else\n      {docs |> Enum.reduce(&glue(&2, &1)), state}\n    end\n  end\n\n  ## Module attributes\n\n  # @Foo\n  # @Foo.Bar\n  defp module_attribute_to_algebra(_meta, {:__aliases__, _, [_, _ | _]} = quoted, _context, state) do\n    {doc, state} = quoted_to_algebra(quoted, :parens_arg, state)\n    {concat(concat(\"@(\", doc), \")\"), state}\n  end\n\n  # @foo bar\n  # @foo(bar)\n  defp module_attribute_to_algebra(meta, {name, call_meta, [_] = args} = expr, context, state)\n       when is_atom(name) and name not in [:__block__, :__aliases__] do\n    if Macro.classify_atom(name) == :identifier do\n      {{call_doc, state}, wrap_in_parens?} =\n        call_args_to_algebra(args, call_meta, context, :skip_unless_many_args, false, state)\n\n      doc =\n        \"@#{name}\"\n        |> string()\n        |> concat(call_doc)\n\n      doc = if wrap_in_parens?, do: wrap_in_parens(doc), else: doc\n      {doc, state}\n    else\n      unary_op_to_algebra(:@, meta, expr, context, state)\n    end\n  end\n\n  # @foo\n  # @(foo.bar())\n  defp module_attribute_to_algebra(meta, quoted, context, state) do\n    unary_op_to_algebra(:@, meta, quoted, context, state)\n  end\n\n  ## Capture operator\n\n  defp capture_to_algebra(integer, _context, state) when is_integer(integer) do\n    {\"&\" <> Integer.to_string(integer), state}\n  end\n\n  defp capture_to_algebra(arg, context, state) do\n    {doc, state} = capture_target_to_algebra(arg, context, state)\n\n    case format_to_string(doc) do\n      <<\"&\", _::binary>> -> {concat(\"& \", doc), state}\n      <<int, _::binary>> when int in ?0..?9 -> {concat(\"& \", doc), state}\n      _ -> {concat(\"&\", doc), state}\n    end\n  end\n\n  defp capture_target_to_algebra(\n         {:/, _, [{{:., _, [target, fun]}, _, []}, {:__block__, _, [arity]}]},\n         _context,\n         state\n       )\n       when is_atom(fun) and is_integer(arity) do\n    {target_doc, state} = remote_target_to_algebra(target, state)\n    fun = Macro.inspect_atom(:remote_call, fun, escape: &escape_atom/2)\n    {target_doc |> nest(1) |> concat(string(\".#{fun}/#{arity}\")), state}\n  end\n\n  defp capture_target_to_algebra(\n         {:/, _, [{name, _, var_context}, {:__block__, _, [arity]}]},\n         _context,\n         state\n       )\n       when is_atom(name) and is_atom(var_context) and is_integer(arity) do\n    {string(\"#{name}/#{arity}\"), state}\n  end\n\n  defp capture_target_to_algebra(arg, context, state) do\n    {doc, state} = quoted_to_algebra(arg, context, state)\n    {wrap_in_parens_if_operator(doc, arg), state}\n  end\n\n  ## Calls (local, remote and anonymous)\n\n  # expression.{arguments}\n  defp remote_to_algebra({{:., _, [target, :{}]}, meta, args}, _context, state) do\n    {target_doc, state} = remote_target_to_algebra(target, state)\n    {call_doc, state} = tuple_to_algebra(meta, args, :break, state)\n    {concat(concat(target_doc, \".\"), call_doc), state}\n  end\n\n  # expression.(arguments)\n  defp remote_to_algebra({{:., _, [target]}, meta, args}, context, state) do\n    {target_doc, state} = remote_target_to_algebra(target, state)\n\n    {{call_doc, state}, wrap_in_parens?} =\n      call_args_to_algebra(args, meta, context, :skip_if_do_end, true, state)\n\n    doc = concat(concat(target_doc, \".\"), call_doc)\n    doc = if wrap_in_parens?, do: wrap_in_parens(doc), else: doc\n    {doc, state}\n  end\n\n  # Mod.function()\n  # var.function\n  # expression.function(arguments)\n  defp remote_to_algebra({{:., _, [target, fun]}, meta, args}, context, state)\n       when is_atom(fun) do\n    {target_doc, state} = remote_target_to_algebra(target, state)\n\n    fun_doc =\n      Macro.inspect_atom(:remote_call, fun, escape: &escape_atom/2)\n      |> string()\n      |> color_doc(:call, state.inspect_opts)\n\n    remote_doc = target_doc |> concat(\".\") |> concat(fun_doc)\n\n    if args == [] and not remote_target_is_a_module?(target) and not meta?(meta, :closing) do\n      {remote_doc, state}\n    else\n      {{call_doc, state}, wrap_in_parens?} =\n        call_args_to_algebra(args, meta, context, :skip_if_do_end, true, state)\n\n      doc = concat(remote_doc, call_doc)\n      doc = if wrap_in_parens?, do: wrap_in_parens(doc), else: doc\n      {doc, state}\n    end\n  end\n\n  # call(call)(arguments)\n  defp remote_to_algebra({target, meta, args}, context, state) do\n    {target_doc, state} = quoted_to_algebra(target, :no_parens_arg, state)\n\n    {{call_doc, state}, wrap_in_parens?} =\n      call_args_to_algebra(args, meta, context, :required, true, state)\n\n    doc = concat(target_doc, call_doc)\n    doc = if wrap_in_parens?, do: wrap_in_parens(doc), else: doc\n    {doc, state}\n  end\n\n  defp remote_target_is_a_module?(target) do\n    case target do\n      {:__MODULE__, _, context} when is_atom(context) -> true\n      {:__block__, _, [atom]} when is_atom(atom) -> true\n      {:__aliases__, _, _} -> true\n      _ -> false\n    end\n  end\n\n  defp remote_target_to_algebra({:fn, _, [_ | _]} = quoted, state) do\n    # This change is not semantically required but for beautification.\n    {doc, state} = quoted_to_algebra(quoted, :no_parens_arg, state)\n    {wrap_in_parens(doc), state}\n  end\n\n  defp remote_target_to_algebra(quoted, state) do\n    quoted_to_algebra_with_parens_if_operator(quoted, :no_parens_arg, state)\n  end\n\n  # function(arguments)\n  defp local_to_algebra(fun, meta, args, context, state) when is_atom(fun) do\n    skip_parens =\n      cond do\n        meta?(meta, :closing) ->\n          :skip_if_only_do_end\n\n        local_without_parens?(fun, length(args), state.locals_without_parens) ->\n          :skip_unless_many_args\n\n        true ->\n          :skip_if_do_end\n      end\n\n    {{call_doc, state}, wrap_in_parens?} =\n      call_args_to_algebra(args, meta, context, skip_parens, true, state)\n\n    doc =\n      fun\n      |> Atom.to_string()\n      |> string()\n      |> color_doc(:call, state.inspect_opts)\n      |> concat(call_doc)\n\n    doc = if wrap_in_parens?, do: wrap_in_parens(doc), else: doc\n    {doc, state}\n  end\n\n  # parens may be one of:\n  #\n  #   * :skip_unless_many_args - skips parens unless we are the argument context\n  #   * :skip_if_only_do_end - skip parens if we are do-end and the only arg\n  #   * :skip_if_do_end - skip parens if we are do-end\n  #   * :required - never skip parens\n  #\n  defp call_args_to_algebra([], meta, _context, _parens, _list_to_keyword?, state) do\n    {args_doc, _join, state} =\n      args_to_algebra_with_comments([], meta, false, :none, :break, state, &{&1, &2})\n\n    {{surround(\"(\", args_doc, \")\"), state}, false}\n  end\n\n  defp call_args_to_algebra(args, meta, context, parens, list_to_keyword?, state) do\n    {rest, last} = split_last(args)\n\n    if blocks = do_end_blocks(meta, last, state) do\n      {call_doc, state} =\n        case rest do\n          [] when parens == :required ->\n            {\"() do\", state}\n\n          [] ->\n            {\" do\", state}\n\n          _ ->\n            no_parens? = parens not in [:required, :skip_if_only_do_end]\n            call_args_to_algebra_no_blocks(meta, rest, no_parens?, list_to_keyword?, \" do\", state)\n        end\n\n      {blocks_doc, state} = do_end_blocks_to_algebra(blocks, state)\n      call_doc = call_doc |> concat(blocks_doc) |> line(\"end\") |> force_unfit()\n      {{call_doc, state}, context in [:no_parens_arg, :no_parens_one_arg]}\n    else\n      no_parens? =\n        parens == :skip_unless_many_args and\n          context in [:block, :operand, :no_parens_one_arg, :parens_one_arg]\n\n      res =\n        call_args_to_algebra_no_blocks(meta, args, no_parens?, list_to_keyword?, @empty, state)\n\n      {res, false}\n    end\n  end\n\n  defp call_args_to_algebra_no_blocks(meta, args, skip_parens?, list_to_keyword?, extra, state) do\n    {left, right} = split_last(args)\n    {keyword?, right} = last_arg_to_keyword(right, list_to_keyword?, skip_parens?, state.comments)\n\n    context =\n      if left == [] and not keyword? do\n        if skip_parens?, do: :no_parens_one_arg, else: :parens_one_arg\n      else\n        if skip_parens?, do: :no_parens_arg, else: :parens_arg\n      end\n\n    args = if keyword?, do: left ++ right, else: left ++ [right]\n    many_eol? = match?([_, _ | _], args) and eol?(meta, state)\n    no_generators? = no_generators?(args)\n    to_algebra_fun = &quoted_to_algebra(&1, context, &2)\n\n    {args_doc, next_break_fits?, state} =\n      if left != [] and keyword? and no_generators? do\n        join = if force_args?(left) or many_eol?, do: :line, else: :break\n\n        {left_doc, _join, state} =\n          args_to_algebra_with_comments(\n            left,\n            Keyword.delete(meta, :closing),\n            skip_parens?,\n            :force_comma,\n            join,\n            state,\n            to_algebra_fun\n          )\n\n        join = if force_args?(right) or force_args?(args) or many_eol?, do: :line, else: :break\n\n        {right_doc, _join, state} =\n          args_to_algebra_with_comments(right, meta, false, :none, join, state, to_algebra_fun)\n\n        right_doc = apply(Inspect.Algebra, join, []) |> concat(right_doc)\n\n        args_doc =\n          if skip_parens? do\n            left_doc\n            |> concat(group(right_doc, :optimistic))\n            |> nest(:cursor, :break)\n          else\n            right_doc =\n              right_doc\n              |> nest(2, :break)\n              |> concat(break(\"\"))\n              |> concat(\")\")\n              |> group(:optimistic)\n\n            concat(nest(left_doc, 2, :break), right_doc)\n          end\n\n        {args_doc, true, state}\n      else\n        join = if force_args?(args) or many_eol?, do: :line, else: :break\n        next_break_fits? = join == :break and next_break_fits?(right, state)\n        last_arg_mode = if next_break_fits?, do: :next_break_fits, else: :none\n\n        {args_doc, _join, state} =\n          args_to_algebra_with_comments(\n            args,\n            meta,\n            skip_parens?,\n            last_arg_mode,\n            join,\n            state,\n            to_algebra_fun\n          )\n\n        # If we have a single argument, then we won't have an option to break\n        # before the \"extra\" part, so we ungroup it and build it later.\n        args_doc = ungroup_if_group(args_doc)\n\n        args_doc =\n          if skip_parens? do\n            nest(args_doc, :cursor, :break)\n          else\n            nest(args_doc, 2, :break) |> concat(break(\"\")) |> concat(\")\")\n          end\n\n        {args_doc, next_break_fits?, state}\n      end\n\n    doc =\n      cond do\n        left != [] and keyword? and skip_parens? and no_generators? ->\n          \" \"\n          |> concat(args_doc)\n          |> nest(2)\n          |> concat(extra)\n\n        skip_parens? ->\n          \" \"\n          |> concat(args_doc)\n          |> concat(extra)\n\n        true ->\n          \"(\"\n          |> concat(break(\"\"))\n          |> nest(2, :break)\n          |> concat(args_doc)\n          |> concat(extra)\n      end\n\n    if next_break_fits? do\n      {group(doc, :pessimistic), state}\n    else\n      {group(doc), state}\n    end\n  end\n\n  defp no_generators?(args) do\n    not Enum.any?(args, &match?({:<-, _, [_, _]}, &1))\n  end\n\n  defp do_end_blocks(meta, [{{:__block__, _, [:do]}, _} | rest] = blocks, state) do\n    if meta?(meta, :do) or can_force_do_end_blocks?(rest, state) do\n      blocks\n      |> Enum.map(fn {{:__block__, meta, [key]}, value} -> {key, line(meta), value} end)\n      |> do_end_blocks_with_range(end_line(meta))\n    end\n  end\n\n  defp do_end_blocks(_, _, _), do: nil\n\n  defp can_force_do_end_blocks?(rest, state) do\n    state.force_do_end_blocks and\n      Enum.all?(rest, fn {{:__block__, _, [key]}, _} -> key in @do_end_keywords end)\n  end\n\n  defp do_end_blocks_with_range([{key1, line1, value1}, {_, line2, _} = h | t], end_line) do\n    [{key1, line1, line2, value1} | do_end_blocks_with_range([h | t], end_line)]\n  end\n\n  defp do_end_blocks_with_range([{key, line, value}], end_line) do\n    [{key, line, end_line, value}]\n  end\n\n  defp do_end_blocks_to_algebra([{:do, line, end_line, value} | blocks], state) do\n    {acc, state} = do_end_block_to_algebra(@empty, line, end_line, value, state)\n\n    Enum.reduce(blocks, {acc, state}, fn {key, line, end_line, value}, {acc, state} ->\n      {doc, state} = do_end_block_to_algebra(Atom.to_string(key), line, end_line, value, state)\n      {line(acc, doc), state}\n    end)\n  end\n\n  defp do_end_block_to_algebra(key_doc, line, end_line, value, state) do\n    case clauses_to_algebra(value, line, end_line, state) do\n      {@empty, state} -> {key_doc, state}\n      {value_doc, state} -> {key_doc |> line(value_doc) |> nest(2), state}\n    end\n  end\n\n  ## Interpolation\n\n  defp list_interpolated?(entries) do\n    Enum.all?(entries, fn\n      {{:., _, [Kernel, :to_string]}, _, [_]} -> true\n      entry when is_binary(entry) -> true\n      _ -> false\n    end)\n  end\n\n  defp interpolated?(entries) do\n    Enum.all?(entries, fn\n      {:\"::\", _, [{{:., _, [Kernel, :to_string]}, _, [_]}, {:binary, _, _}]} -> true\n      entry when is_binary(entry) -> true\n      _ -> false\n    end)\n  end\n\n  defp prepend_heredoc_line([entry | entries]) when is_binary(entry) do\n    [\"\\n\" <> entry | entries]\n  end\n\n  defp prepend_heredoc_line(entries) do\n    [\"\\n\" | entries]\n  end\n\n  defp list_interpolation_to_algebra([entry | entries], escape, state, acc, last)\n       when is_binary(entry) do\n    acc = concat(acc, escape_string(entry, escape))\n    list_interpolation_to_algebra(entries, escape, state, acc, last)\n  end\n\n  defp list_interpolation_to_algebra([entry | entries], escape, state, acc, last) do\n    {{:., _, [Kernel, :to_string]}, _meta, [quoted]} = entry\n    {doc, state} = interpolation_to_algebra(quoted, state)\n    list_interpolation_to_algebra(entries, escape, state, concat(acc, doc), last)\n  end\n\n  defp list_interpolation_to_algebra([], _escape, state, acc, last) do\n    {concat(acc, last), state}\n  end\n\n  defp interpolation_to_algebra([entry | entries], escape, state, acc, last)\n       when is_binary(entry) do\n    acc = concat(acc, escape_string(entry, escape))\n    interpolation_to_algebra(entries, escape, state, acc, last)\n  end\n\n  defp interpolation_to_algebra([entry | entries], escape, state, acc, last) do\n    {:\"::\", _, [{{:., _, [Kernel, :to_string]}, _meta, [quoted]}, {:binary, _, _}]} = entry\n    {doc, state} = interpolation_to_algebra(quoted, state)\n    interpolation_to_algebra(entries, escape, state, concat(acc, doc), last)\n  end\n\n  defp interpolation_to_algebra([], _escape, state, acc, last) do\n    {concat(acc, last), state}\n  end\n\n  defp interpolation_to_algebra(quoted, %{skip_eol: skip_eol} = state) do\n    {doc, state} = block_to_algebra(quoted, @max_line, @min_line, %{state | skip_eol: true})\n    {no_limit(surround(\"\\#{\", doc, \"}\")), %{state | skip_eol: skip_eol}}\n  end\n\n  ## Sigils\n\n  defp maybe_sigil_to_algebra(fun, meta, args, state) do\n    with <<\"sigil_\", name::binary>> <- Atom.to_string(fun),\n         [{:<<>>, _, entries}, modifiers] when is_list(modifiers) <- args,\n         opening_delimiter when not is_nil(opening_delimiter) <- meta[:delimiter] do\n      doc = <<?~, name::binary, opening_delimiter::binary>>\n\n      entries =\n        case Map.fetch(state.sigils, String.to_charlist(name)) do\n          {:ok, callback} ->\n            metadata = [\n              file: state.file,\n              line: meta[:line],\n              sigil: String.to_atom(name),\n              modifiers: modifiers,\n              opening_delimiter: opening_delimiter\n            ]\n\n            case callback.(hd(entries), metadata) do\n              iodata when is_binary(iodata) or is_list(iodata) ->\n                [IO.iodata_to_binary(iodata)]\n\n              other ->\n                raise ArgumentError,\n                      \"expected sigil callback to return iodata, got: #{inspect(other)}\"\n            end\n\n          :error ->\n            entries\n        end\n\n      if opening_delimiter in [@double_heredoc, @single_heredoc] do\n        closing_delimiter = concat(opening_delimiter, List.to_string(modifiers))\n\n        {doc, state} =\n          entries\n          |> prepend_heredoc_line()\n          |> interpolation_to_algebra(opening_delimiter, state, doc, closing_delimiter)\n\n        {force_unfit(doc), state}\n      else\n        escape = closing_sigil_delimiter(opening_delimiter)\n        closing_delimiter = concat(escape, List.to_string(modifiers))\n        interpolation_to_algebra(entries, escape, state, doc, closing_delimiter)\n      end\n    else\n      _ ->\n        :error\n    end\n  end\n\n  defp closing_sigil_delimiter(\"(\"), do: \")\"\n  defp closing_sigil_delimiter(\"[\"), do: \"]\"\n  defp closing_sigil_delimiter(\"{\"), do: \"}\"\n  defp closing_sigil_delimiter(\"<\"), do: \">\"\n  defp closing_sigil_delimiter(other) when other in [\"\\\"\", \"'\", \"|\", \"/\"], do: other\n\n  ## Bitstrings\n\n  defp bitstring_to_algebra(meta, args, state) do\n    last = length(args) - 1\n    join = if eol?(meta, state), do: :line, else: :flex_break\n    to_algebra_fun = &bitstring_segment_to_algebra(&1, &2, last)\n\n    {args_doc, join, state} =\n      args\n      |> Enum.with_index()\n      |> args_to_algebra_with_comments(meta, false, :none, join, state, to_algebra_fun)\n\n    if join == :flex_break do\n      {\"<<\" |> concat(args_doc) |> nest(2) |> concat(\">>\") |> group(), state}\n    else\n      {surround(\"<<\", args_doc, \">>\"), state}\n    end\n  end\n\n  defp bitstring_segment_to_algebra({{:<-, meta, [left, right]}, i}, state, last) do\n    left = {{:special, :bitstring_segment}, meta, [left, last]}\n    {doc, state} = quoted_to_algebra({:<-, meta, [left, right]}, :parens_arg, state)\n    {bitstring_wrap_parens(doc, i, last), state}\n  end\n\n  defp bitstring_segment_to_algebra({{:\"::\", _, [segment, spec]}, i}, state, last) do\n    {doc, state} = quoted_to_algebra(segment, :parens_arg, state)\n\n    {spec, state} =\n      bitstring_spec_to_algebra(spec, state, state.migrate_bitstring_modifiers, :\"::\")\n\n    spec = wrap_in_parens_if_inspected_atom(spec)\n    spec = if i == last, do: bitstring_wrap_parens(spec, i, last), else: spec\n\n    doc =\n      doc\n      |> bitstring_wrap_parens(i, -1)\n      |> concat(\"::\")\n      |> concat(spec)\n\n    {doc, state}\n  end\n\n  defp bitstring_segment_to_algebra({segment, i}, state, last) do\n    {doc, state} = quoted_to_algebra(segment, :parens_arg, state)\n    {bitstring_wrap_parens(doc, i, last), state}\n  end\n\n  defp bitstring_spec_to_algebra({op, _, [left, right]}, state, normalize_modifiers, paren_op)\n       when op in [:-, :*] do\n    normalize_modifiers = normalize_modifiers && op != :*\n    {left, state} = bitstring_spec_to_algebra(left, state, normalize_modifiers, op)\n    {right, state} = bitstring_spec_element_to_algebra(right, state, normalize_modifiers)\n    doc = concat(concat(left, Atom.to_string(op)), right)\n    doc = if paren_op == :*, do: wrap_in_parens(doc), else: doc\n    {doc, state}\n  end\n\n  defp bitstring_spec_to_algebra(spec, state, normalize_modifiers, _paren_op) do\n    bitstring_spec_element_to_algebra(spec, state, normalize_modifiers)\n  end\n\n  defp bitstring_spec_element_to_algebra(\n         {atom, meta, empty_args},\n         state,\n         _normalize_modifiers = true\n       )\n       when is_atom(atom) and empty_args in [nil, []] do\n    empty_args = bitstring_spec_normalize_empty_args(atom)\n    quoted_to_algebra_with_parens_if_operator({atom, meta, empty_args}, :parens_arg, state)\n  end\n\n  defp bitstring_spec_element_to_algebra(spec_element, state, _normalize_modifiers) do\n    quoted_to_algebra_with_parens_if_operator(spec_element, :parens_arg, state)\n  end\n\n  defp bitstring_spec_normalize_empty_args(:_), do: nil\n\n  defp bitstring_spec_normalize_empty_args(atom) do\n    case :elixir_bitstring.validate_spec(atom, nil) do\n      :none -> []\n      _ -> nil\n    end\n  end\n\n  defp bitstring_wrap_parens(doc, i, last) when i == 0 or i == last do\n    string = format_to_string(doc)\n\n    if (i == 0 and String.starts_with?(string, [\"~\", \"<<\"])) or\n         (i == last and String.ends_with?(string, [\">>\"])) do\n      wrap_in_parens(doc)\n    else\n      doc\n    end\n  end\n\n  defp bitstring_wrap_parens(doc, _, _), do: doc\n\n  ## Literals\n\n  defp list_to_algebra(meta, args, state) do\n    join = if eol?(meta, state), do: :line, else: :break\n    fun = &quoted_to_algebra(&1, :parens_arg, &2)\n\n    {args_doc, _join, state} =\n      args_to_algebra_with_comments(args, meta, false, :none, join, state, fun)\n\n    left_bracket = color_doc(\"[\", :list, state.inspect_opts)\n    right_bracket = color_doc(\"]\", :list, state.inspect_opts)\n\n    {surround(left_bracket, args_doc, right_bracket), state}\n  end\n\n  defp map_to_algebra(meta, name_doc, [{:|, _, [left, right]}], state) do\n    join = if eol?(meta, state), do: :line, else: :break\n    fun = &quoted_to_algebra(&1, :parens_arg, &2)\n    {left_doc, state} = fun.(left, state)\n\n    {right_doc, _join, state} =\n      args_to_algebra_with_comments(right, meta, false, :none, join, state, fun)\n\n    args_doc =\n      left_doc\n      |> wrap_in_parens_if_binary_operator(left)\n      |> glue(concat(\"| \", nest(right_doc, 2)))\n\n    do_map_to_algebra(name_doc, args_doc, state)\n  end\n\n  defp map_to_algebra(meta, name_doc, args, state) do\n    join = if eol?(meta, state), do: :line, else: :break\n    fun = &quoted_to_algebra(&1, :parens_arg, &2)\n\n    {args_doc, _join, state} =\n      args_to_algebra_with_comments(args, meta, false, :none, join, state, fun)\n\n    do_map_to_algebra(name_doc, args_doc, state)\n  end\n\n  defp do_map_to_algebra(name_doc, args_doc, state) do\n    name_doc = \"%\" |> concat(name_doc) |> concat(\"{\") |> color_doc(:map, state.inspect_opts)\n    {surround(name_doc, args_doc, color_doc(\"}\", :map, state.inspect_opts)), state}\n  end\n\n  defp tuple_to_algebra(meta, args, join, state) do\n    join = if eol?(meta, state), do: :line, else: join\n    fun = &quoted_to_algebra(&1, :parens_arg, &2)\n\n    {args_doc, join, state} =\n      args_to_algebra_with_comments(args, meta, false, :none, join, state, fun)\n\n    left_bracket = color_doc(\"{\", :tuple, state.inspect_opts)\n    right_bracket = color_doc(\"}\", :tuple, state.inspect_opts)\n\n    if join == :flex_break do\n      {left_bracket |> concat(args_doc) |> nest(1) |> concat(right_bracket) |> group(), state}\n    else\n      {surround(left_bracket, args_doc, right_bracket), state}\n    end\n  end\n\n  defp atom_to_algebra(atom, _, inspect_opts) when atom in [true, false] do\n    Atom.to_string(atom) |> color_doc(:boolean, inspect_opts)\n  end\n\n  defp atom_to_algebra(nil, _, inspect_opts) do\n    Atom.to_string(nil) |> color_doc(nil, inspect_opts)\n  end\n\n  defp atom_to_algebra(:\\\\, meta, inspect_opts) do\n    # Since we parse strings without unescaping, the atoms\n    # :\\\\ and :\"\\\\\" have the same representation, so we need\n    # to check the delimiter and handle them accordingly.\n    string =\n      case Keyword.get(meta, :delimiter) do\n        \"\\\"\" -> \":\\\"\\\\\\\\\\\"\"\n        _ -> \":\\\\\\\\\"\n      end\n\n    string(string) |> color_doc(:atom, inspect_opts)\n  end\n\n  defp atom_to_algebra(atom, _, inspect_opts) do\n    string = Atom.to_string(atom)\n\n    iodata =\n      if Macro.classify_atom(atom) in [:unquoted, :identifier] do\n        [?:, string]\n      else\n        [?:, ?\", String.replace(string, \"\\\"\", \"\\\\\\\"\"), ?\"]\n      end\n\n    iodata |> IO.iodata_to_binary() |> string() |> color_doc(:atom, inspect_opts)\n  end\n\n  defp integer_to_algebra(text, inspect_otps) do\n    case text do\n      <<?0, ?x, rest::binary>> ->\n        \"0x\" <> String.upcase(rest)\n\n      <<?0, base, _::binary>> = digits when base in [?b, ?o] ->\n        digits\n\n      <<??, _::binary>> = char ->\n        char\n\n      decimal ->\n        insert_underscores(decimal)\n    end\n    |> color_doc(:number, inspect_otps)\n  end\n\n  defp float_to_algebra(text, inspect_otps) do\n    [int_part, decimal_part] = :binary.split(text, \".\")\n    decimal_part = String.downcase(decimal_part)\n\n    string = insert_underscores(int_part) <> \".\" <> decimal_part\n    color_doc(string, :number, inspect_otps)\n  end\n\n  defp insert_underscores(\"-\" <> digits) do\n    \"-\" <> insert_underscores(digits)\n  end\n\n  defp insert_underscores(digits) do\n    byte_size = byte_size(digits)\n\n    cond do\n      digits =~ \"_\" ->\n        digits\n\n      byte_size >= 6 ->\n        offset = rem(byte_size, 3)\n        {prefix, rest} = String.split_at(digits, offset)\n        do_insert_underscores(prefix, rest)\n\n      true ->\n        digits\n    end\n  end\n\n  defp do_insert_underscores(acc, \"\"), do: acc\n\n  defp do_insert_underscores(\"\", <<next::binary-3, rest::binary>>),\n    do: do_insert_underscores(next, rest)\n\n  defp do_insert_underscores(acc, <<next::binary-3, rest::binary>>),\n    do: do_insert_underscores(<<acc::binary, \"_\", next::binary>>, rest)\n\n  defp escape_heredoc(string, escape) do\n    string = String.replace(string, escape, \"\\\\\" <> escape)\n    heredoc_to_algebra([\"\" | String.split(string, \"\\n\")])\n  end\n\n  defp escape_string(string, <<_, _, _>> = escape) do\n    string = String.replace(string, escape, \"\\\\\" <> escape)\n    heredoc_to_algebra(String.split(string, \"\\n\"))\n  end\n\n  defp escape_string(string, escape) when is_binary(escape) do\n    string\n    |> String.replace(escape, \"\\\\\" <> escape)\n    |> String.split(\"\\n\")\n    |> Enum.reverse()\n    |> Enum.map(&string/1)\n    |> Enum.reduce(&concat(&1, concat(nest(line(), :reset), &2)))\n  end\n\n  defp heredoc_to_algebra([string]) do\n    string(string)\n  end\n\n  defp heredoc_to_algebra([\"\" | rest]) do\n    rest\n    |> heredoc_line()\n    |> concat(heredoc_to_algebra(rest))\n  end\n\n  defp heredoc_to_algebra([string | rest]) do\n    string\n    |> string()\n    |> concat(heredoc_line(rest))\n    |> concat(heredoc_to_algebra(rest))\n  end\n\n  defp heredoc_line([\"\", _ | _]), do: nest(line(), :reset)\n  defp heredoc_line([\"\\r\", _ | _]), do: nest(line(), :reset)\n  defp heredoc_line(_), do: line()\n\n  defp args_to_algebra_with_comments(args, meta, skip_parens?, last_arg_mode, join, state, fun) do\n    min_line = line(meta)\n    max_line = closing_line(meta)\n\n    arg_to_algebra = fn arg, args, state ->\n      {doc, state} = fun.(arg, state)\n\n      doc =\n        case args do\n          [_ | _] ->\n            concat_to_last_group(doc, \",\")\n\n          [] when last_arg_mode == :force_comma ->\n            concat_to_last_group(doc, \",\")\n\n          [] when last_arg_mode == :next_break_fits ->\n            doc |> ungroup_if_group() |> group(:optimistic)\n\n          [] when last_arg_mode == :none ->\n            doc\n        end\n\n      {{doc, @empty, 1}, state}\n    end\n\n    # If skipping parens, we cannot extract the comments of the first\n    # argument as there is no place to move them to, so we handle it now.\n    {args, acc, state} =\n      case args do\n        [head | tail] when skip_parens? ->\n          {doc_triplet, state} = arg_to_algebra.(head, tail, state)\n          {tail, [doc_triplet], state}\n\n        _ ->\n          {args, [], state}\n      end\n\n    {args_docs, comments?, state} =\n      quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, arg_to_algebra)\n\n    cond do\n      args_docs == [] ->\n        {@empty, :empty, state}\n\n      join == :line or comments? ->\n        {args_docs |> Enum.reduce(&line(&2, &1)) |> force_unfit(), :line, state}\n\n      join == :break ->\n        {args_docs |> Enum.reduce(&glue(&2, &1)), :break, state}\n\n      join == :flex_break ->\n        {args_docs |> Enum.reduce(&flex_glue(&2, &1)), :flex_break, state}\n    end\n  end\n\n  ## Anonymous functions\n\n  # fn -> block end\n  defp anon_fun_to_algebra(\n         [{:->, meta, [[], body]}] = clauses,\n         _min_line,\n         max_line,\n         state,\n         _multi_clauses_style\n       ) do\n    min_line = line(meta)\n    {body_doc, state} = block_to_algebra(body, min_line, max_line, state)\n    break_or_line = clause_break_or_line(clauses, state)\n\n    doc =\n      \"fn ->\"\n      |> concat(break_or_line)\n      |> concat(body_doc)\n      |> nest(2)\n      |> concat(break_or_line)\n      |> concat(\"end\")\n      |> maybe_force_clauses(clauses, state)\n      |> group()\n\n    {doc, state}\n  end\n\n  # fn x -> y end\n  # fn x ->\n  #   y\n  # end\n  defp anon_fun_to_algebra(\n         [{:->, meta, [args, body]}] = clauses,\n         _min_line,\n         max_line,\n         state,\n         false = _multi_clauses_style\n       ) do\n    min_line = line(meta)\n    {args_doc, state} = clause_args_to_algebra(args, min_line, state)\n    {body_doc, state} = block_to_algebra(body, min_line, max_line, state)\n\n    head =\n      args_doc\n      |> ungroup_if_group()\n      |> concat(\" ->\")\n      |> nest(:cursor)\n      |> group()\n\n    break_or_line = clause_break_or_line(clauses, state)\n\n    doc =\n      \"fn \"\n      |> concat(head)\n      |> concat(break_or_line)\n      |> concat(body_doc)\n      |> nest(2)\n      |> concat(break_or_line)\n      |> concat(\"end\")\n      |> maybe_force_clauses(clauses, state)\n      |> group()\n\n    {doc, state}\n  end\n\n  # fn\n  #   args1 ->\n  #     block1\n  #   args2 ->\n  #     block2\n  # end\n  defp anon_fun_to_algebra(clauses, min_line, max_line, state, _multi_clauses_style) do\n    {clauses_doc, state} = clauses_to_algebra(clauses, min_line, max_line, state)\n    {\"fn\" |> line(clauses_doc) |> nest(2) |> line(\"end\") |> force_unfit(), state}\n  end\n\n  ## Type functions\n\n  # (-> block)\n  defp paren_fun_to_algebra([{:->, meta, [[], body]}] = clauses, _min_line, max_line, state) do\n    min_line = line(meta)\n    {body_doc, state} = block_to_algebra(body, min_line, max_line, state)\n\n    doc =\n      \"(-> \"\n      |> concat(nest(body_doc, :cursor))\n      |> concat(\")\")\n      |> maybe_force_clauses(clauses, state)\n      |> group()\n\n    {doc, state}\n  end\n\n  # (x -> y)\n  # (x ->\n  #    y)\n  defp paren_fun_to_algebra([{:->, meta, [args, body]}] = clauses, _min_line, max_line, state) do\n    min_line = line(meta)\n    {args_doc, state} = clause_args_to_algebra(args, min_line, state)\n    {body_doc, state} = block_to_algebra(body, min_line, max_line, state)\n    break_or_line = clause_break_or_line(clauses, state)\n\n    doc =\n      args_doc\n      |> ungroup_if_group()\n      |> concat(\" ->\")\n      |> group()\n      |> concat(break_or_line |> concat(body_doc) |> nest(2))\n      |> wrap_in_parens()\n      |> maybe_force_clauses(clauses, state)\n      |> group()\n\n    {doc, state}\n  end\n\n  # (\n  #   args1 ->\n  #     block1\n  #   args2 ->\n  #     block2\n  # )\n  defp paren_fun_to_algebra(clauses, min_line, max_line, state) do\n    {clauses_doc, state} = clauses_to_algebra(clauses, min_line, max_line, state)\n    {\"(\" |> line(clauses_doc) |> nest(2) |> line(\")\") |> force_unfit(), state}\n  end\n\n  ## Clauses\n\n  defp multi_line_clauses?(clauses, state) do\n    Enum.any?(clauses, fn {:->, meta, [_, block]} ->\n      eol?(meta, state) or multi_line_block?(block)\n    end)\n  end\n\n  defp multi_line_block?({:__block__, _, [_, _ | _]}), do: true\n  defp multi_line_block?(_), do: false\n\n  defp clause_break_or_line(clauses, state) do\n    if multi_line_clauses?(clauses, state), do: line(), else: break()\n  end\n\n  defp maybe_force_clauses(doc, clauses, state) do\n    if multi_line_clauses?(clauses, state), do: force_unfit(doc), else: doc\n  end\n\n  defp clauses_to_algebra([{:->, _, _} | _] = clauses, min_line, max_line, state) do\n    [clause | clauses] = add_max_line_to_last_clause(clauses, max_line)\n    {clause_doc, state} = clause_to_algebra(clause, min_line, state)\n\n    {clauses_doc, state} =\n      Enum.reduce(clauses, {clause_doc, state}, fn clause, {doc_acc, state_acc} ->\n        {clause_doc, state_acc} = clause_to_algebra(clause, min_line, state_acc)\n\n        doc_acc =\n          doc_acc\n          |> concat(maybe_empty_line())\n          |> line(clause_doc)\n\n        {doc_acc, state_acc}\n      end)\n\n    {clauses_doc |> maybe_force_clauses([clause | clauses], state) |> group(), state}\n  end\n\n  defp clauses_to_algebra(other, min_line, max_line, state) do\n    case block_to_algebra(other, min_line, max_line, state) do\n      {@empty, state} -> {@empty, state}\n      {doc, state} -> {group(doc), state}\n    end\n  end\n\n  defp clause_to_algebra({:->, meta, [[], body]}, _min_line, state) do\n    {body_doc, state} = block_to_algebra(body, line(meta), closing_line(meta), state)\n    {\"() ->\" |> glue(body_doc) |> nest(2), state}\n  end\n\n  defp clause_to_algebra({:->, meta, [args, body]}, min_line, state) do\n    %{operand_nesting: nesting} = state\n\n    state = %{state | operand_nesting: nesting + 2}\n    {args_doc, state} = clause_args_to_algebra(args, min_line, state)\n\n    state = %{state | operand_nesting: nesting}\n    {body_doc, state} = block_to_algebra(body, min_line, closing_line(meta), state)\n\n    doc =\n      args_doc\n      |> ungroup_if_group()\n      |> concat(\" ->\")\n      |> group()\n      |> concat(break() |> concat(body_doc) |> nest(2))\n\n    {doc, state}\n  end\n\n  defp add_max_line_to_last_clause([{op, meta, args}], max_line) do\n    [{op, [closing: [line: max_line]] ++ meta, args}]\n  end\n\n  defp add_max_line_to_last_clause([clause | clauses], max_line) do\n    [clause | add_max_line_to_last_clause(clauses, max_line)]\n  end\n\n  defp clause_args_to_algebra(args, min_line, state) do\n    arg_to_algebra = fn arg, _args, state ->\n      {doc, state} = clause_args_to_algebra(arg, state)\n      {{doc, @empty, 1}, state}\n    end\n\n    {args_docs, comments?, state} =\n      quoted_to_algebra_with_comments([args], [], min_line, @min_line, state, arg_to_algebra)\n\n    if comments? do\n      {Enum.reduce(args_docs, &line(&2, &1)), state}\n    else\n      {Enum.reduce(args_docs, &glue(&2, &1)), state}\n    end\n  end\n\n  # fn a, b, c when d -> e end\n  defp clause_args_to_algebra([{:when, meta, args}], state) do\n    {args, right} = split_last(args)\n\n    # If there are any keywords, wrap them in lists\n    args =\n      Enum.map(args, fn\n        [_ | _] = keyword -> {:__block__, [], [keyword]}\n        other -> other\n      end)\n\n    left = {{:special, :clause_args}, meta, [args]}\n    binary_op_to_algebra(:when, \"when\", meta, left, right, :no_parens_arg, state)\n  end\n\n  # fn () -> e end\n  defp clause_args_to_algebra([], state) do\n    {\"()\", state}\n  end\n\n  # fn a, b, c -> e end\n  defp clause_args_to_algebra(args, state) do\n    many_args_to_algebra(args, state, &quoted_to_algebra(&1, :no_parens_arg, &2))\n  end\n\n  ## Quoted helpers for comments\n\n  defp quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, fun) do\n    {pre_comments, state} =\n      get_and_update_in(state.comments, fn comments ->\n        Enum.split_while(comments, fn %{line: line} -> line <= min_line end)\n      end)\n\n    {reverse_docs, comments?, state} =\n      if state.comments == [] do\n        each_quoted_to_algebra_without_comments(args, acc, state, fun)\n      else\n        each_quoted_to_algebra_with_comments(args, acc, max_line, state, false, fun)\n      end\n\n    docs = merge_algebra_with_comments(Enum.reverse(reverse_docs), @empty)\n    {docs, comments?, update_in(state.comments, &(pre_comments ++ &1))}\n  end\n\n  defp each_quoted_to_algebra_without_comments([], acc, state, _fun) do\n    {acc, false, state}\n  end\n\n  defp each_quoted_to_algebra_without_comments([arg | args], acc, state, fun) do\n    {doc_triplet, state} = fun.(arg, args, state)\n    acc = [doc_triplet | acc]\n    each_quoted_to_algebra_without_comments(args, acc, state, fun)\n  end\n\n  defp each_quoted_to_algebra_with_comments([], acc, max_line, state, comments?, _fun) do\n    {acc, comments, comments?} = extract_comments_before(max_line, acc, state.comments, comments?)\n    {acc, comments?, %{state | comments: comments}}\n  end\n\n  defp each_quoted_to_algebra_with_comments([arg | args], acc, max_line, state, comments?, fun) do\n    case traverse_line(arg, {@max_line, @min_line}) do\n      {@max_line, @min_line} ->\n        {doc_triplet, state} = fun.(arg, args, state)\n        acc = [doc_triplet | acc]\n        each_quoted_to_algebra_with_comments(args, acc, max_line, state, comments?, fun)\n\n      {doc_start, doc_end} ->\n        {acc, comments, comments?} =\n          extract_comments_before(doc_start, acc, state.comments, comments?)\n\n        {doc_triplet, state} = fun.(arg, args, %{state | comments: comments})\n\n        {acc, comments, comments?} =\n          extract_comments_trailing(doc_start, doc_end, acc, state.comments, comments?)\n\n        acc = [adjust_trailing_newlines(doc_triplet, doc_end, comments) | acc]\n        state = %{state | comments: comments}\n        each_quoted_to_algebra_with_comments(args, acc, max_line, state, comments?, fun)\n    end\n  end\n\n  defp extract_comments_before(max, acc, [%{line: line} = comment | rest], _) when line < max do\n    %{previous_eol_count: previous, next_eol_count: next, text: doc} = comment\n    acc = [{doc, @empty, next} | add_previous_to_acc(acc, previous)]\n    extract_comments_before(max, acc, rest, true)\n  end\n\n  defp extract_comments_before(_max, acc, rest, comments?) do\n    {acc, rest, comments?}\n  end\n\n  defp add_previous_to_acc([{doc, next_line, newlines} | acc], previous) when newlines < previous,\n    do: [{doc, next_line, previous} | acc]\n\n  defp add_previous_to_acc(acc, _previous),\n    do: acc\n\n  defp extract_comments_trailing(min, max, acc, [%{line: line, text: doc_comment} | rest], _)\n       when line >= min and line <= max do\n    acc = [{doc_comment, @empty, 1} | acc]\n    extract_comments_trailing(min, max, acc, rest, true)\n  end\n\n  defp extract_comments_trailing(_min, _max, acc, rest, comments?) do\n    {acc, rest, comments?}\n  end\n\n  # If the document is immediately followed by comment which is followed by newlines,\n  # its newlines wouldn't have considered the comment, so we need to adjust it.\n  defp adjust_trailing_newlines({doc, next_line, newlines}, doc_end, [%{line: line} | _])\n       when newlines > 1 and line == doc_end + 1 do\n    {doc, next_line, 1}\n  end\n\n  defp adjust_trailing_newlines(doc_triplet, _, _), do: doc_triplet\n\n  defp traverse_line({expr, meta, args}, {min, max}) do\n    # This is a hot path, so use :lists.keyfind/3 instead Keyword.fetch!/2\n    acc =\n      case :lists.keyfind(:line, 1, meta) do\n        {:line, line} -> {min(line, min), max(line, max)}\n        false -> {min, max}\n      end\n\n    traverse_line(args, traverse_line(expr, acc))\n  end\n\n  defp traverse_line({left, right}, acc) do\n    traverse_line(right, traverse_line(left, acc))\n  end\n\n  defp traverse_line(args, acc) when is_list(args) do\n    Enum.reduce(args, acc, &traverse_line/2)\n  end\n\n  defp traverse_line(_, acc) do\n    acc\n  end\n\n  # Below are the rules for line rendering in the formatter:\n  #\n  #   1. respect the user's choice\n  #   2. and add empty lines around expressions that take multiple lines\n  #      (except for module attributes)\n  #   3. empty lines are collapsed as to not exceed more than one\n  #\n  defp merge_algebra_with_comments([{doc, next_line, newlines} | docs], left) do\n    right = if newlines >= @newlines, do: line(), else: next_line\n\n    doc =\n      if left != @empty do\n        concat(left, doc)\n      else\n        doc\n      end\n\n    doc =\n      if docs != [] and right != @empty do\n        concat(doc, concat(collapse_lines(2), right))\n      else\n        doc\n      end\n\n    [group(doc) | merge_algebra_with_comments(docs, right)]\n  end\n\n  defp merge_algebra_with_comments([], _) do\n    []\n  end\n\n  ## Quoted helpers\n\n  defp left_op_context(context), do: force_many_args_or_operand(context, :parens_arg)\n  defp right_op_context(context), do: force_many_args_or_operand(context, :operand)\n\n  defp force_many_args_or_operand(:no_parens_one_arg, _choice), do: :no_parens_arg\n  defp force_many_args_or_operand(:parens_one_arg, _choice), do: :parens_arg\n  defp force_many_args_or_operand(:no_parens_arg, _choice), do: :no_parens_arg\n  defp force_many_args_or_operand(:parens_arg, _choice), do: :parens_arg\n  defp force_many_args_or_operand(:operand, choice), do: choice\n  defp force_many_args_or_operand(:block, choice), do: choice\n\n  defp quoted_to_algebra_with_parens_if_operator(ast, context, state) do\n    {doc, state} = quoted_to_algebra(ast, context, state)\n    {wrap_in_parens_if_operator(doc, ast), state}\n  end\n\n  defp wrap_in_parens_if_operator(doc, {:__block__, _, [expr]}) do\n    wrap_in_parens_if_operator(doc, expr)\n  end\n\n  defp wrap_in_parens_if_operator(doc, quoted) do\n    if operator?(quoted) and not module_attribute_read?(quoted) and not integer_capture?(quoted) do\n      wrap_in_parens(doc)\n    else\n      doc\n    end\n  end\n\n  defp wrap_in_parens_if_binary_operator(doc, quoted) do\n    if binary_operator?(quoted) do\n      wrap_in_parens(doc)\n    else\n      doc\n    end\n  end\n\n  defp wrap_in_parens_if_inspected_atom(\":\" <> _ = doc) do\n    \"(\" <> doc <> \")\"\n  end\n\n  defp wrap_in_parens_if_inspected_atom(doc) do\n    doc\n  end\n\n  defp wrap_in_parens(doc) do\n    concat(concat(\"(\", nest(doc, :cursor)), \")\")\n  end\n\n  defp many_args_to_algebra([arg | args], state, fun) do\n    Enum.reduce(args, fun.(arg, state), fn arg, {doc_acc, state_acc} ->\n      {arg_doc, state_acc} = fun.(arg, state_acc)\n      {glue(concat(doc_acc, \",\"), arg_doc), state_acc}\n    end)\n  end\n\n  defp module_attribute_read?({:@, _, [{var, _, var_context}]})\n       when is_atom(var) and is_atom(var_context) do\n    Macro.classify_atom(var) == :identifier\n  end\n\n  defp module_attribute_read?(_), do: false\n\n  defp integer_capture?({:&, _, [integer]}) when is_integer(integer), do: true\n  defp integer_capture?(_), do: false\n\n  defp operator?(quoted) do\n    unary_operator?(quoted) or binary_operator?(quoted)\n  end\n\n  # We convert ..// into two operators for simplicity,\n  # so we need to augment the binary table.\n  defp augmented_binary_op(:\"//\"), do: {:right, 190}\n  defp augmented_binary_op(op), do: Code.Identifier.binary_op(op)\n\n  defp binary_operator?(quoted) do\n    case quoted do\n      {op, _, [_, _, _]} when op in @multi_binary_operators -> true\n      {op, _, [_, _]} when is_atom(op) -> augmented_binary_op(op) != :error\n      _ -> false\n    end\n  end\n\n  defp unary_operator?(quoted) do\n    case quoted do\n      {op, _, [_]} when is_atom(op) -> Code.Identifier.unary_op(op) != :error\n      _ -> false\n    end\n  end\n\n  defp with_next_break_fits(condition, doc, fun) do\n    if condition do\n      doc\n      |> group(:optimistic)\n      |> fun.()\n      |> group(:pessimistic)\n    else\n      doc\n      |> group()\n      |> fun.()\n      |> group()\n    end\n  end\n\n  defp next_break_fits?({:{}, meta, _args}, state) do\n    eol_or_comments?(meta, state)\n  end\n\n  defp next_break_fits?({:__block__, meta, [{_, _}]}, state) do\n    eol_or_comments?(meta, state)\n  end\n\n  defp next_break_fits?({:<<>>, meta, [_ | _] = entries}, state) do\n    meta[:delimiter] == ~s[\"\"\"] or\n      (not interpolated?(entries) and eol_or_comments?(meta, state))\n  end\n\n  # TODO: Remove this clause on Elixir v2.0 once single-quoted charlists are removed\n  defp next_break_fits?({{:., _, [List, :to_charlist]}, meta, [[_ | _]]}, _state) do\n    meta[:delimiter] == ~s[''']\n  end\n\n  defp next_break_fits?({{:., _, [_left, :{}]}, _, _}, _state) do\n    true\n  end\n\n  defp next_break_fits?({:__block__, meta, [string]}, _state) when is_binary(string) do\n    meta[:delimiter] == ~s[\"\"\"]\n  end\n\n  defp next_break_fits?({:__block__, meta, [list]}, _state) when is_list(list) do\n    meta[:delimiter] != ~s[']\n  end\n\n  defp next_break_fits?({form, _, [_ | _]}, _state) when form in [:fn, :%{}, :%] do\n    true\n  end\n\n  defp next_break_fits?({fun, meta, args}, _state) when is_atom(fun) and is_list(args) do\n    meta[:delimiter] in [@double_heredoc, @single_heredoc] and\n      fun |> Atom.to_string() |> String.starts_with?(\"sigil_\")\n  end\n\n  defp next_break_fits?({{:__block__, _, [atom]}, expr}, state) when is_atom(atom) do\n    next_break_fits?(expr, state)\n  end\n\n  defp next_break_fits?(_, _state) do\n    false\n  end\n\n  defp eol_or_comments?(meta, %{comments: comments} = state) do\n    eol?(meta, state) or\n      (\n        min_line = line(meta)\n        max_line = closing_line(meta)\n        Enum.any?(comments, fn %{line: line} -> line > min_line and line < max_line end)\n      )\n  end\n\n  # A literal list is a keyword or (... -> ...)\n  defp last_arg_to_keyword([_ | _] = arg, _list_to_keyword?, _skip_parens?, _comments) do\n    {keyword?(arg), arg}\n  end\n\n  # This is a list of tuples, it can be converted to keywords.\n  defp last_arg_to_keyword(\n         {:__block__, meta, [[_ | _] = arg]} = block,\n         true,\n         skip_parens?,\n         comments\n       ) do\n    cond do\n      not keyword?(arg) ->\n        {false, block}\n\n      skip_parens? ->\n        block_line = line(meta)\n        {{_, arg_meta, _}, _} = hd(arg)\n        first_line = line(arg_meta)\n\n        case Enum.drop_while(comments, fn %{line: line} -> line <= block_line end) do\n          [%{line: line} | _] when line <= first_line ->\n            {false, block}\n\n          _ ->\n            {true, arg}\n        end\n\n      true ->\n        {true, arg}\n    end\n  end\n\n  # Otherwise we don't have a keyword.\n  defp last_arg_to_keyword(arg, _list_to_keyword?, _skip_parens?, _comments) do\n    {false, arg}\n  end\n\n  defp force_args?(args) do\n    match?([_ | _], args) and force_args?(args, %{})\n  end\n\n  defp force_args?([[arg | _] | args], lines) do\n    force_args?([arg | args], lines)\n  end\n\n  defp force_args?([arg | args], lines) do\n    line =\n      case arg do\n        {{_, meta, _}, _} -> meta[:line]\n        {_, meta, _} -> meta[:line]\n      end\n\n    cond do\n      # Line may be missing from non-formatter AST\n      is_nil(line) -> force_args?(args, lines)\n      Map.has_key?(lines, line) -> false\n      true -> force_args?(args, Map.put(lines, line, true))\n    end\n  end\n\n  defp force_args?([], lines), do: map_size(lines) >= 2\n\n  defp force_keyword(doc, arg) do\n    if force_args?(arg), do: force_unfit(doc), else: doc\n  end\n\n  defp keyword?([{_, _} | list]), do: keyword?(list)\n  defp keyword?(rest), do: rest == []\n\n  defp keyword_key?({:__block__, meta, [atom]}) when is_atom(atom),\n    do: meta[:format] == :keyword\n\n  defp keyword_key?({{:., _, [:erlang, :binary_to_atom]}, meta, [{:<<>>, _, _}, :utf8]}),\n    do: meta[:format] == :keyword\n\n  defp keyword_key?(_),\n    do: false\n\n  defp eol?(_meta, %{skip_eol: true}), do: false\n  defp eol?(meta, _state), do: Keyword.get(meta, :newlines, 0) > 0\n\n  defp meta?(meta, key) do\n    is_list(meta[key])\n  end\n\n  defp line(meta) do\n    meta[:line] || @max_line\n  end\n\n  defp end_line(meta) do\n    meta[:end][:line] || @min_line\n  end\n\n  defp closing_line(meta) do\n    meta[:closing][:line] || @min_line\n  end\n\n  defp escape_atom(string, char) do\n    String.replace(string, <<char>>, <<?\\\\, char>>)\n  end\n\n  ## Algebra helpers\n\n  # Relying on the inner document is brittle and error prone.\n  # It would be best if we had a mechanism to apply this.\n  defp concat_to_last_group([left | right], concat) do\n    [left | concat_to_last_group(right, concat)]\n  end\n\n  defp concat_to_last_group({:doc_group, group, mode}, concat) do\n    {:doc_group, concat(group, concat), mode}\n  end\n\n  defp concat_to_last_group(other, concat) do\n    concat(other, concat)\n  end\n\n  defp ungroup_if_group({:doc_group, group, _mode}), do: group\n  defp ungroup_if_group(other), do: other\n\n  defp format_to_string(doc) do\n    doc |> Inspect.Algebra.format(:infinity) |> IO.iodata_to_binary()\n  end\n\n  defp maybe_empty_line() do\n    nest(break(\"\"), :reset)\n  end\n\n  defp surround(left, doc, right) do\n    if doc == @empty do\n      concat(left, right)\n    else\n      group(glue(nest(glue(left, \"\", doc), 2, :break), \"\", right))\n    end\n  end\n\n  defp nest_by_length(doc, string) do\n    nest(doc, String.length(string))\n  end\n\n  defp split_last(list) do\n    {left, [right]} = Enum.split(list, -1)\n    {left, right}\n  end\n\n  defp get_charlist_quotes(:heredoc, state) do\n    if state.migrate_charlists_as_sigils do\n      {@sigil_c_heredoc, @double_heredoc}\n    else\n      {@single_heredoc, @single_heredoc}\n    end\n  end\n\n  defp get_charlist_quotes({:regular, chunks}, state) do\n    cond do\n      !state.migrate_charlists_as_sigils -> {@single_quote, @single_quote}\n      Enum.any?(chunks, &has_double_quote?/1) -> {@sigil_c_single, @single_quote}\n      true -> {@sigil_c_double, @double_quote}\n    end\n  end\n\n  defp has_double_quote?(chunk) do\n    is_binary(chunk) and chunk =~ @double_quote\n  end\n\n  # Migration rewrites\n\n  @bool_operators [\n    :>,\n    :>=,\n    :<,\n    :<=,\n    :in\n  ]\n  @guards [\n    :is_atom,\n    :is_boolean,\n    :is_nil,\n    :is_number,\n    :is_integer,\n    :is_float,\n    :is_binary,\n    :is_map,\n    :is_struct,\n    :is_non_struct_map,\n    :is_exception,\n    :is_list,\n    :is_tuple,\n    :is_function,\n    :is_reference,\n    :is_pid,\n    :is_port\n  ]\n\n  defp negate_condition(condition) do\n    case condition do\n      {neg, _, [condition]} when neg in [:!, :not] -> condition\n      {op, _, [_, _]} when op in @bool_operators -> {:not, [], [condition]}\n      {guard, _, [_ | _]} when guard in @guards -> {:not, [], [condition]}\n      {:==, meta, [left, right]} -> {:!=, meta, [left, right]}\n      {:===, meta, [left, right]} -> {:!==, meta, [left, right]}\n      {:!=, meta, [left, right]} -> {:==, meta, [left, right]}\n      {:!==, meta, [left, right]} -> {:===, meta, [left, right]}\n      _ -> {:!, [], [condition]}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/code/fragment.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Code.Fragment do\n  @moduledoc \"\"\"\n  This module provides conveniences for analyzing fragments of\n  textual code and extract available information whenever possible.\n\n  This module should be considered experimental.\n  \"\"\"\n\n  @type position :: {line :: pos_integer(), column :: pos_integer()}\n\n  @typedoc \"\"\"\n  Options for cursor context functions.\n\n  Currently, these options are not used but reserved for future extensibility.\n  \"\"\"\n  @type cursor_opts :: []\n\n  @typedoc \"\"\"\n  Options for converting code fragments to quoted expressions.\n  \"\"\"\n  @type container_cursor_to_quoted_opts :: [\n          file: String.t(),\n          line: pos_integer(),\n          column: pos_integer(),\n          columns: boolean(),\n          token_metadata: boolean(),\n          literal_encoder: (term(), Macro.metadata() -> term()),\n          trailing_fragment: String.t()\n        ]\n\n  @doc ~S\"\"\"\n  Returns the list of lines in the given string, preserving their line endings.\n\n  Only the line endings recognized by the Elixir compiler are\n  considered, namely `\\r\\n` and `\\n`. If you would like the retrieve\n  lines without their line endings, use `String.split(string, [\"\\r\\n\", \"\\n\"])`.\n\n  ## Examples\n\n      iex> Code.Fragment.lines(\"foo\\r\\nbar\\r\\nbaz\")\n      [\"foo\\r\\n\", \"bar\\r\\n\", \"baz\"]\n\n      iex> Code.Fragment.lines(\"foo\\nbar\\nbaz\")\n      [\"foo\\n\", \"bar\\n\", \"baz\"]\n\n      iex> Code.Fragment.lines(\"\")\n      [\"\"]\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  def lines(string) do\n    lines(string, <<>>)\n  end\n\n  defp lines(<<?\\n, rest::binary>>, acc),\n    do: [<<acc::binary, ?\\n>> | lines(rest, <<>>)]\n\n  defp lines(<<char, rest::binary>>, acc),\n    do: lines(rest, <<acc::binary, char>>)\n\n  defp lines(<<>>, acc),\n    do: [acc]\n\n  @doc \"\"\"\n  Receives a string and returns the cursor context.\n\n  This function receives a string with an Elixir code fragment,\n  representing a cursor position, and based on the string, it\n  provides contextual information about the latest token.\n  The return of this function can then be used to provide tips,\n  suggestions, and autocompletion functionality.\n\n  This function performs its analyses on tokens. This means\n  it does not understand how constructs are nested within each\n  other. See the \"Limitations\" section below.\n\n  Consider adding a catch-all clause when handling the return\n  type of this function as new cursor information may be added\n  in future releases.\n\n  ## Examples\n\n      iex> Code.Fragment.cursor_context(\"\")\n      :expr\n\n      iex> Code.Fragment.cursor_context(\"hello_wor\")\n      {:local_or_var, ~c\"hello_wor\"}\n\n  ## Return values\n\n    * `{:alias, charlist}` - the context is an alias, potentially\n      a nested one, such as `Hello.Wor` or `HelloWor`\n\n    * `{:alias, inside_alias, charlist}` - the context is an alias, potentially\n      a nested one, where `inside_alias` is an expression `{:module_attribute, charlist}`\n      or `{:local_or_var, charlist}` and `charlist` is a static part\n      Examples are `__MODULE__.Submodule` or `@hello.Submodule`\n\n    * `{:block_keyword_or_binary_operator, charlist}` - may be a block keyword (do, end, after,\n      catch, else, rescue) or a binary operator\n\n    * `{:dot, inside_dot, charlist}` - the context is a dot\n      where `inside_dot` is either a `{:var, charlist}`, `{:alias, charlist}`,\n      `{:module_attribute, charlist}`, `{:unquoted_atom, charlist}` or a `dot`\n      itself. If a var is given, this may either be a remote call or a map\n      field access. Examples are `Hello.wor`, `:hello.wor`, `hello.wor`,\n      `Hello.nested.wor`, `hello.nested.wor`, and `@hello.world`. If `charlist`\n      is empty and `inside_dot` is an alias, then the autocompletion may either\n      be an alias or a remote call.\n\n    * `{:dot_arity, inside_dot, charlist}` - the context is a dot arity\n      where `inside_dot` is either a `{:var, charlist}`, `{:alias, charlist}`,\n      `{:module_attribute, charlist}`, `{:unquoted_atom, charlist}` or a `dot`\n      itself. If a var is given, it must be a remote arity. Examples are\n      `Hello.world/`, `:hello.world/`, `hello.world/2`, and `@hello.world/2`\n\n    * `{:dot_call, inside_dot, charlist}` - the context is a dot\n      call. This means parentheses or space have been added after the expression.\n      where `inside_dot` is either a `{:var, charlist}`, `{:alias, charlist}`,\n      `{:module_attribute, charlist}`, `{:unquoted_atom, charlist}` or a `dot`\n      itself. If a var is given, it must be a remote call. Examples are\n      `Hello.world(`, `:hello.world(`, `Hello.world `, `hello.world(`, `hello.world `,\n      and `@hello.world(`\n\n    * `:expr` - may be any expression. Autocompletion may suggest an alias,\n      local or var\n\n    * `{:local_or_var, charlist}` - the context is a variable or a local\n      (import or local) call, such as `hello_wor`\n\n    * `{:local_arity, charlist}` - the context is a local (import or local)\n      arity, such as `hello_world/`\n\n    * `{:local_call, charlist}` - the context is a local (import or local)\n      call, such as `hello_world(` and `hello_world `\n\n    * `{:anonymous_call, inside_caller}` - the context is an anonymous\n      call, such as `fun.(` and `@fun.(`.\n\n    * `{:module_attribute, charlist}` - the context is a module attribute,\n      such as `@hello_wor`\n\n    * `{:operator, charlist}` - the context is an operator, such as `+` or\n      `==`. Note textual operators, such as `when` do not appear as operators\n      but rather as `:local_or_var`. `@` is never an `:operator` and always a\n      `:module_attribute`\n\n    * `{:operator_arity, charlist}` - the context is an operator arity, which\n      is an operator followed by /, such as `+/`, `not/` or `when/`\n\n    * `{:operator_call, charlist}` - the context is an operator call, which is\n      an operator followed by space, such as `left + `, `not ` or `x when `\n\n    * `:none` - no context possible\n\n    * `{:sigil, charlist}` - the context is a sigil. It may be either the beginning\n      of a sigil, such as `~` or `~s`, or an operator starting with `~`, such as\n      `~>` and `~>>`\n\n    * `{:struct, inside_struct}` - the context is a struct, such as `%`, `%UR` or `%URI`.\n      `inside_struct` can either be a `charlist` in case of a static alias or an\n      expression `{:alias, inside_alias, charlist}`, `{:module_attribute, charlist}`,\n      `{:local_or_var, charlist}`, `{:dot, inside_dot, charlist}`\n\n    * `{:unquoted_atom, charlist}` - the context is an unquoted atom. This\n      can be any atom or an atom representing a module\n\n  We recommend looking at the test suite of this function for a complete list\n  of examples and their return values.\n\n  ## Limitations\n\n  The analysis is based on the current token, by analysing the last line of\n  the input. For example, this code:\n\n      iex> Code.Fragment.cursor_context(\"%URI{\")\n      :expr\n\n  returns `:expr`, which suggests any variable, local function or alias\n  could be used. However, given we are inside a struct, the best suggestion\n  would be a struct field. In such cases, you can use\n  `container_cursor_to_quoted`, which will return the container of the AST\n  the cursor is currently within. You can then analyse this AST to provide\n  completion of field names.\n\n  As a consequence of its token-based implementation, this function considers\n  only the last line of the input. This means it will show suggestions inside\n  strings, heredocs, etc, which is intentional as it helps with doctests,\n  references, and more.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec cursor_context(List.Chars.t(), cursor_opts()) ::\n          {:alias, charlist}\n          | {:alias, inside_alias, charlist}\n          | {:block_keyword_or_binary_operator, charlist}\n          | {:dot, inside_dot, charlist}\n          | {:dot_arity, inside_dot, charlist}\n          | {:dot_call, inside_dot, charlist}\n          | :expr\n          | {:local_or_var, charlist}\n          | {:local_arity, charlist}\n          | {:local_call, charlist}\n          | {:anonymous_call, inside_caller}\n          | {:module_attribute, charlist}\n          | {:operator, charlist}\n          | {:operator_arity, charlist}\n          | {:operator_call, charlist}\n          | :none\n          | {:sigil, charlist}\n          | {:struct, inside_struct}\n          | {:unquoted_atom, charlist}\n        when inside_dot:\n               {:alias, charlist}\n               | {:alias, inside_alias, charlist}\n               | {:dot, inside_dot, charlist}\n               | {:module_attribute, charlist}\n               | {:unquoted_atom, charlist}\n               | {:var, charlist}\n               | :expr,\n             inside_alias:\n               {:local_or_var, charlist}\n               | {:module_attribute, charlist},\n             inside_struct:\n               charlist\n               | {:alias, inside_alias, charlist}\n               | {:local_or_var, charlist}\n               | {:module_attribute, charlist}\n               | {:dot, inside_dot, charlist},\n             inside_caller: {:var, charlist} | {:module_attribute, charlist}\n  def cursor_context(fragment, opts \\\\ [])\n\n  def cursor_context(fragment, opts)\n      when (is_binary(fragment) or is_list(fragment)) and is_list(opts) do\n    fragment\n    |> last_line()\n    |> :lists.reverse()\n    |> codepoint_cursor_context(opts)\n    |> elem(0)\n  end\n\n  def cursor_context(other, opts) when is_list(opts) do\n    cursor_context(to_charlist(other), opts)\n  end\n\n  @operators ~c\"\\\\<>+-*/:=|&~^%!$\"\n  @starting_punctuation ~c\",([{;\"\n  @closing_punctuation ~c\")]}\\\"'\"\n  @space ~c\"\\t\\s\"\n  @trailing_identifier ~c\"?!\"\n  @tilde_op_prefix ~c\"<=~\"\n\n  @non_identifier @trailing_identifier ++\n                    @operators ++ @starting_punctuation ++ @closing_punctuation ++ @space ++ [?.]\n\n  @textual_operators ~w(when not and or in)c\n  @keywords ~w(do end after else catch rescue fn true false nil)c\n\n  defp codepoint_cursor_context(reverse, _opts) do\n    {stripped, spaces} = strip_spaces(reverse, 0)\n\n    case stripped do\n      # It is empty\n      [] -> {:expr, 0}\n      # Structs\n      [?%, ?:, ?: | _] -> {{:struct, ~c\"\"}, 1}\n      [?%, ?: | _] -> {{:unquoted_atom, ~c\"%\"}, 2}\n      [?% | _] -> {{:struct, ~c\"\"}, 1}\n      # Token/AST only operators\n      [?>, ?= | rest] when rest == [] or hd(rest) != ?: -> {:expr, 0}\n      [?>, ?- | rest] when rest == [] or hd(rest) != ?: -> {:expr, 0}\n      # Two-digit containers\n      [?<, ?< | rest] when rest == [] or hd(rest) != ?< -> {:expr, 0}\n      # Ambiguity around :\n      [?: | rest] when rest == [] or hd(rest) != ?: -> unquoted_atom_or_expr(spaces)\n      # Dots\n      [?.] -> {:none, 0}\n      [?. | rest] when hd(rest) not in ~c\".:\" -> dot(rest, spaces + 1, ~c\"\")\n      # It is a local or remote call with parens\n      [?( | rest] -> call_to_cursor_context(strip_spaces(rest, spaces + 1))\n      # A local arity definition\n      [?/ | rest] -> arity_to_cursor_context(strip_spaces(rest, spaces + 1))\n      # Starting a new expression\n      [h | _] when h in @starting_punctuation -> {:expr, 0}\n      # It is keyword, binary operator, a local or remote call without parens\n      rest when spaces > 0 -> closing_or_call_to_cursor_context({rest, spaces})\n      # It is an identifier\n      _ -> identifier_to_cursor_context(reverse, spaces, false)\n    end\n  end\n\n  defp strip_spaces([h | rest], count) when h in @space, do: strip_spaces(rest, count + 1)\n  defp strip_spaces(rest, count), do: {rest, count}\n\n  defp unquoted_atom_or_expr(0), do: {{:unquoted_atom, ~c\"\"}, 1}\n  defp unquoted_atom_or_expr(_), do: {:expr, 0}\n\n  defp arity_to_cursor_context({reverse, spaces}) do\n    case identifier_to_cursor_context(reverse, spaces, true) do\n      {{:local_or_var, acc}, count} -> {{:local_arity, acc}, count}\n      {{:dot, base, acc}, count} -> {{:dot_arity, base, acc}, count}\n      {{:operator, acc}, count} -> {{:operator_arity, acc}, count}\n      {{:sigil, _}, _} -> {:none, 0}\n      {_, _} -> {{:operator, ~c\"/\"}, 1}\n    end\n  end\n\n  defp call_to_cursor_context({reverse, spaces}) do\n    with [?. | rest] <- reverse,\n         {rest, spaces} = strip_spaces(rest, spaces),\n         [h | _] when h not in @non_identifier <- rest do\n      case identifier_to_cursor_context(rest, spaces, true) do\n        {{:local_or_var, acc}, count} -> {{:anonymous_call, {:var, acc}}, count + 1}\n        {{:module_attribute, _} = attr, count} -> {{:anonymous_call, attr}, count + 1}\n        {_, _} -> {:none, 0}\n      end\n    else\n      _ ->\n        case identifier_to_cursor_context(reverse, spaces, true) do\n          {{:local_or_var, acc}, count} -> {{:local_call, acc}, count}\n          {{:dot, base, acc}, count} -> {{:dot_call, base, acc}, count}\n          {{:operator, acc}, count} -> {{:operator_call, acc}, count}\n          {_, _} -> {:none, 0}\n        end\n    end\n  end\n\n  defp closing_or_call_to_cursor_context({reverse, spaces}) do\n    if closing?(reverse) do\n      {{:block_keyword_or_binary_operator, ~c\"\"}, 0}\n    else\n      call_to_cursor_context({reverse, spaces})\n    end\n  end\n\n  defp identifier_to_cursor_context([?., ?., ?: | _], n, _), do: {{:unquoted_atom, ~c\"..\"}, n + 3}\n  defp identifier_to_cursor_context([?., ?., ?. | _], n, _), do: {{:operator, ~c\"...\"}, n + 3}\n  defp identifier_to_cursor_context([?., ?: | _], n, _), do: {{:unquoted_atom, ~c\".\"}, n + 2}\n  defp identifier_to_cursor_context([?., ?. | _], n, _), do: {{:operator, ~c\"..\"}, n + 2}\n\n  defp identifier_to_cursor_context(reverse, count, call_op?) do\n    case identifier(reverse, count) do\n      :none ->\n        {:none, 0}\n\n      :operator ->\n        operator(reverse, count, [], call_op?)\n\n      {:struct, {:module_attribute, acc}, count} ->\n        {{:struct, {:module_attribute, acc}}, count + 1}\n\n      {:module_attribute, acc, count} ->\n        {{:module_attribute, acc}, count}\n\n      {:sigil, acc, count} ->\n        {{:sigil, acc}, count}\n\n      {:unquoted_atom, acc, count} ->\n        {{:unquoted_atom, acc}, count}\n\n      {:alias, rest, acc, count} ->\n        case strip_spaces(rest, count) do\n          {~c\".\" ++ rest, count} when rest == [] or hd(rest) != ?. ->\n            nested_alias(rest, count + 1, acc)\n\n          {~c\"%\" ++ _, count} ->\n            {{:struct, acc}, count + 1}\n\n          _ ->\n            {{:alias, acc}, count}\n        end\n\n      {:identifier, _, acc, count} when call_op? and acc in @textual_operators ->\n        {{:operator, acc}, count}\n\n      {:identifier, [?%], acc, count} ->\n        case identifier_to_cursor_context(acc |> Enum.reverse(), count, true) do\n          {{:local_or_var, _} = identifier, _} -> {{:struct, identifier}, count + 1}\n          _ -> {:none, 0}\n        end\n\n      {:identifier, rest, acc, count} ->\n        case strip_spaces(rest, count) do\n          {~c\".\" ++ rest, count} when rest == [] or hd(rest) != ?. ->\n            dot(rest, count + 1, acc)\n\n          {rest, rest_count} ->\n            response =\n              if rest_count > count and closing?(rest),\n                do: :block_keyword_or_binary_operator,\n                else: :local_or_var\n\n            {{response, acc}, count}\n        end\n\n      {:capture_arg, acc, count} ->\n        {{:capture_arg, acc}, count}\n    end\n  end\n\n  # If it is a closing punctuation\n  defp closing?([h | _]) when h in @closing_punctuation, do: true\n  # Closing bitstring (but deal with operators)\n  defp closing?([?>, ?> | rest]), do: rest == [] or hd(rest) not in [?>, ?~]\n  # Keywords\n  defp closing?(rest) do\n    case split_non_identifier(rest, []) do\n      {~c\"nil\", _} -> true\n      {~c\"true\", _} -> true\n      {~c\"false\", _} -> true\n      {[digit | _], _} when digit in ?0..?9 -> true\n      {[upper | _], _} when upper in ?A..?Z -> true\n      {[_ | _], [?: | rest]} -> rest == [] or hd(rest) != ?:\n      {_, _} -> false\n    end\n  end\n\n  defp split_non_identifier([h | t], acc) when h not in @non_identifier,\n    do: split_non_identifier(t, [h | acc])\n\n  defp split_non_identifier(rest, acc), do: {acc, rest}\n\n  defp identifier([?? | rest], count), do: check_identifier(rest, count + 1, [??])\n  defp identifier([?! | rest], count), do: check_identifier(rest, count + 1, [?!])\n  defp identifier(rest, count), do: check_identifier(rest, count, [])\n\n  defp check_identifier([h | t], count, acc) when h not in @non_identifier,\n    do: rest_identifier(t, count + 1, [h | acc])\n\n  defp check_identifier(_, _, _), do: :operator\n\n  defp rest_identifier([h | rest], count, acc) when h not in @non_identifier do\n    rest_identifier(rest, count + 1, [h | acc])\n  end\n\n  defp rest_identifier(rest, count, [?@ | acc]) do\n    case tokenize_identifier(rest, count, acc) do\n      {:identifier, [?% | _rest], acc, count} -> {:struct, {:module_attribute, acc}, count}\n      {:identifier, _rest, acc, count} -> {:module_attribute, acc, count}\n      :none when acc == [] -> {:module_attribute, ~c\"\", count}\n      _ -> :none\n    end\n  end\n\n  defp rest_identifier([?~ | rest], count, [letter])\n       when (letter in ?A..?Z or letter in ?a..?z) and\n              (rest == [] or hd(rest) not in @tilde_op_prefix) do\n    {:sigil, [letter], count + 1}\n  end\n\n  defp rest_identifier([?: | rest], count, acc) when rest == [] or hd(rest) != ?: do\n    case String.Tokenizer.tokenize(acc) do\n      {_, _, [], _, _, _} -> {:unquoted_atom, acc, count + 1}\n      _ -> :none\n    end\n  end\n\n  defp rest_identifier([?? | _], _count, _acc) do\n    :none\n  end\n\n  defp rest_identifier([?& | tail] = rest, count, acc) when tail == [] or hd(tail) != ?& do\n    if Enum.all?(acc, &(&1 in ?0..?9)) do\n      {:capture_arg, [?& | acc], count + 1}\n    else\n      tokenize_identifier(rest, count, acc)\n    end\n  end\n\n  defp rest_identifier(rest, count, acc) do\n    tokenize_identifier(rest, count, acc)\n  end\n\n  defp tokenize_identifier(rest, count, acc) do\n    case String.Tokenizer.tokenize(acc) do\n      # Not actually an atom cause rest is not a :\n      {:atom, _, _, _, _, _} ->\n        :none\n\n      # Aliases must be ascii only\n      {:alias, _, _, _, false, _} ->\n        :none\n\n      {kind, _, [], _, _, extra} ->\n        if :at in extra do\n          :none\n        else\n          {kind, rest, acc, count}\n        end\n\n      _ ->\n        :none\n    end\n  end\n\n  defp nested_alias(rest, count, acc) do\n    {rest, count} = strip_spaces(rest, count)\n\n    case identifier_to_cursor_context(rest, count, true) do\n      {{:struct, prev}, count} when is_list(prev) ->\n        {{:struct, prev ++ ~c\".\" ++ acc}, count}\n\n      {{:struct, {:alias, parent, prev}}, count} ->\n        {{:struct, {:alias, parent, prev ++ ~c\".\" ++ acc}}, count}\n\n      {{:struct, prev}, count} ->\n        {{:struct, {:alias, prev, acc}}, count}\n\n      {{:alias, prev}, count} ->\n        {{:alias, prev ++ ~c\".\" ++ acc}, count}\n\n      {{:alias, parent, prev}, count} ->\n        {{:alias, parent, prev ++ ~c\".\" ++ acc}, count}\n\n      {{:local_or_var, prev}, count} ->\n        {{:alias, {:local_or_var, prev}, acc}, count}\n\n      {{:module_attribute, prev}, count} ->\n        {{:alias, {:module_attribute, prev}, acc}, count}\n\n      _ ->\n        {:none, 0}\n    end\n  end\n\n  defp dot(rest, count, acc) do\n    {rest, count} = strip_spaces(rest, count)\n\n    case identifier_to_cursor_context(rest, count, true) do\n      {{:local_or_var, var}, count} ->\n        {{:dot, {:var, var}, acc}, count}\n\n      {{:unquoted_atom, _} = prev, count} ->\n        {{:dot, prev, acc}, count}\n\n      {{:alias, _} = prev, count} ->\n        {{:dot, prev, acc}, count}\n\n      {{:alias, _, _} = prev, count} ->\n        {{:dot, prev, acc}, count}\n\n      {{:struct, inner}, count} when is_list(inner) ->\n        {{:struct, {:dot, {:alias, inner}, acc}}, count}\n\n      {{:struct, inner}, count} ->\n        {{:struct, {:dot, inner, acc}}, count}\n\n      {{:dot, _, _} = prev, count} ->\n        {{:dot, prev, acc}, count}\n\n      {{:module_attribute, _} = prev, count} ->\n        {{:dot, prev, acc}, count}\n\n      {:expr, count} ->\n        {{:dot, :expr, acc}, count}\n\n      {_, _} ->\n        {:none, 0}\n    end\n  end\n\n  defp operator([h | rest], count, acc, call_op?) when h in @operators do\n    operator(rest, count + 1, [h | acc], call_op?)\n  end\n\n  # If we are opening a sigil, ignore the operator.\n  defp operator([letter, ?~ | rest], _count, [op], _call_op?)\n       when op in ~c\"<|/\" and (letter in ?A..?Z or letter in ?a..?z) and\n              (rest == [] or hd(rest) not in @tilde_op_prefix) do\n    {:none, 0}\n  end\n\n  defp operator(rest, count, ~c\"~\", call_op?) do\n    {rest, _} = strip_spaces(rest, count)\n\n    if call_op? or match?([?. | rest] when rest == [] or hd(rest) != ?., rest) do\n      {:none, 0}\n    else\n      {{:sigil, ~c\"\"}, count}\n    end\n  end\n\n  defp operator([?) | rest], _, [], true) when hd(rest) != ?? do\n    {:expr, 0}\n  end\n\n  defp operator(rest, count, acc, _call_op?) do\n    case :elixir_tokenizer.tokenize(acc, 1, 1, []) do\n      {:ok, _, _, _, [{:atom, _, _}], []} ->\n        {{:unquoted_atom, tl(acc)}, count}\n\n      {:ok, _, _, _, [{_, _, op}], []} ->\n        {rest, dot_count} = strip_spaces(rest, count)\n\n        cond do\n          Code.Identifier.unary_op(op) == :error and Code.Identifier.binary_op(op) == :error ->\n            {:none, 0}\n\n          match?([?. | rest] when rest == [] or hd(rest) != ?., rest) ->\n            dot(tl(rest), dot_count + 1, acc)\n\n          true ->\n            {{:operator, acc}, count}\n        end\n\n      _ ->\n        {:none, 0}\n    end\n  end\n\n  @doc \"\"\"\n  Receives a string and returns the surround context.\n\n  This function receives a string with an Elixir code fragment\n  and a `position`. It returns a map containing the beginning\n  and ending of the identifier alongside its context, or `:none`\n  if there is nothing with a known context. This is useful to\n  provide mouse-over and highlight functionality in editors.\n\n  The difference between `cursor_context/2` and `surround_context/3`\n  is that the former assumes the expression in the code fragment\n  is incomplete. For example, `do` in `cursor_context/2` may be\n  a keyword or a variable or a local call, while `surround_context/3`\n  assumes the expression in the code fragment is complete, therefore\n  `do` would always be a keyword.\n\n  The `position` contains both the `line` and `column`, both starting\n  with the index of 1. The column must precede the surrounding expression.\n  For example, the expression `foo`, will return something for the columns\n  1, 2, and 3, but not 4:\n\n      foo\n      ^ column 1\n\n      foo\n       ^ column 2\n\n      foo\n        ^ column 3\n\n      foo\n         ^ column 4\n\n  The returned map contains the column the expression starts and the\n  first column after the expression ends.\n\n  Similar to `cursor_context/2`, this function is also token-based\n  and may not be accurate under all circumstances. See the\n  \"Return values\" and \"Limitations\" section under `cursor_context/2`\n  for more information.\n\n  ## Examples\n\n      iex> Code.Fragment.surround_context(\"foo\", {1, 1})\n      %{begin: {1, 1}, context: {:local_or_var, ~c\"foo\"}, end: {1, 4}}\n\n  ## Differences to `cursor_context/2`\n\n  Because `surround_context/3` attempts to capture complex expressions,\n  it has some differences to `cursor_context/2`:\n\n    * `dot_call`/`dot_arity` and `operator_call`/`operator_arity`\n      are collapsed into `dot` and `operator` contexts respectively\n      as there aren't any meaningful distinctions between them\n\n    * On the other hand, this function still makes a distinction between\n      `local_call`/`local_arity` and `local_or_var`, since the latter can\n      be a local or variable\n\n    * `@` when not followed by any identifier is returned as `{:operator, ~c\"@\"}`\n      (in contrast to `{:module_attribute, ~c\"\"}` in `cursor_context/2`\n\n    * This function never returns empty sigils `{:sigil, ~c\"\"}` or empty structs\n      `{:struct, ~c\"\"}` as context\n\n    * This function returns keywords as `{:keyword, ~c\"do\"}`\n\n    * This function never returns `:expr`\n\n  We recommend looking at the test suite of this function for a complete list\n  of examples and their return values.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec surround_context(List.Chars.t(), position(), cursor_opts()) ::\n          %{begin: position, end: position, context: context} | :none\n        when context:\n               {:alias, charlist}\n               | {:alias, inside_alias, charlist}\n               | {:dot, inside_dot, charlist}\n               | {:local_or_var, charlist}\n               | {:local_arity, charlist}\n               | {:local_call, charlist}\n               | {:module_attribute, charlist}\n               | {:operator, charlist}\n               | {:sigil, charlist}\n               | {:struct, inside_struct}\n               | {:unquoted_atom, charlist}\n               | {:keyword, charlist}\n               | {:key, charlist}\n               | {:capture_arg, charlist},\n             inside_dot:\n               {:alias, charlist}\n               | {:alias, inside_alias, charlist}\n               | {:dot, inside_dot, charlist}\n               | {:module_attribute, charlist}\n               | {:unquoted_atom, charlist}\n               | {:var, charlist}\n               | :expr,\n             inside_alias:\n               {:local_or_var, charlist}\n               | {:module_attribute, charlist},\n             inside_struct:\n               charlist\n               | {:alias, inside_alias, charlist}\n               | {:local_or_var, charlist}\n               | {:module_attribute, charlist}\n               | {:dot, inside_dot, charlist}\n  def surround_context(fragment, position, options \\\\ [])\n\n  def surround_context(string, {line, column}, opts)\n      when (is_binary(string) or is_list(string)) and is_list(opts) do\n    {charlist, lines_before_lengths, lines_current_and_after_lengths} =\n      surround_line(string, line, column)\n\n    prepended_columns = Enum.sum(lines_before_lengths)\n\n    charlist\n    |> position_surround_context(line, column + prepended_columns, opts)\n    |> to_multiline_range(\n      prepended_columns,\n      lines_before_lengths,\n      lines_current_and_after_lengths\n    )\n  end\n\n  def surround_context(other, {_, _} = position, opts) do\n    surround_context(to_charlist(other), position, opts)\n  end\n\n  defp position_surround_context(charlist, line, column, opts)\n       when is_integer(line) and line >= 1 and is_integer(column) and column >= 1 do\n    {reversed_pre, post} = string_reverse_at(charlist, column - 1, [])\n    {reversed_pre, post} = adjust_position(reversed_pre, post)\n\n    case take_identifier(post, []) do\n      {_, [], _} ->\n        maybe_operator(reversed_pre, post, line, opts)\n\n      {:identifier, reversed_post, rest} ->\n        {keyword_key?, rest} =\n          case rest do\n            [?: | tail] when tail == [] or hd(tail) in @space ->\n              {true, rest}\n\n            _ ->\n              {rest, _} = strip_spaces(rest, 0)\n              {false, rest}\n          end\n\n        reversed = reversed_post ++ reversed_pre\n\n        case codepoint_cursor_context(reversed, opts) do\n          {{:struct, acc}, offset} ->\n            build_surround({:struct, acc}, reversed, line, offset)\n\n          {{:alias, acc}, offset} ->\n            build_surround({:alias, acc}, reversed, line, offset)\n\n          {{:alias, parent, acc}, offset} ->\n            build_surround({:alias, parent, acc}, reversed, line, offset)\n\n          {{:dot, _, [_ | _]} = dot, offset} ->\n            build_surround(dot, reversed, line, offset)\n\n          {{:local_or_var, acc}, offset} when keyword_key? ->\n            build_surround({:key, acc}, reversed, line, offset)\n\n          {{:local_or_var, acc}, offset} when hd(rest) == ?( ->\n            build_surround({:local_call, acc}, reversed, line, offset)\n\n          {{:local_or_var, acc}, offset} when hd(rest) == ?/ ->\n            build_surround({:local_arity, acc}, reversed, line, offset)\n\n          {{:local_or_var, acc}, offset} when acc in @textual_operators ->\n            build_surround({:operator, acc}, reversed, line, offset)\n\n          {{:local_or_var, acc}, offset} when acc in @keywords ->\n            build_surround({:keyword, acc}, reversed, line, offset)\n\n          {{:local_or_var, acc}, offset} ->\n            build_surround({:local_or_var, acc}, reversed, line, offset)\n\n          {{:block_keyword_or_binary_operator, acc}, offset} when acc in @textual_operators ->\n            build_surround({:operator, acc}, reversed, line, offset)\n\n          {{:block_keyword_or_binary_operator, acc}, offset} when acc in @keywords ->\n            build_surround({:keyword, acc}, reversed, line, offset)\n\n          {{:module_attribute, ~c\"\"}, offset} ->\n            build_surround({:operator, ~c\"@\"}, reversed, line, offset)\n\n          {{:module_attribute, acc}, offset} ->\n            build_surround({:module_attribute, acc}, reversed, line, offset)\n\n          {{:sigil, acc}, offset} ->\n            build_surround({:sigil, acc}, reversed, line, offset)\n\n          {{:unquoted_atom, acc}, offset} ->\n            build_surround({:unquoted_atom, acc}, reversed, line, offset)\n\n          {{:capture_arg, acc}, offset} ->\n            build_surround({:capture_arg, acc}, reversed, line, offset)\n\n          _ ->\n            maybe_operator(reversed_pre, post, line, opts)\n        end\n\n      {:alias, reversed_post, _rest} ->\n        reversed = reversed_post ++ reversed_pre\n\n        case codepoint_cursor_context(reversed, opts) do\n          {{:alias, acc}, offset} ->\n            build_surround({:alias, acc}, reversed, line, offset)\n\n          {{:alias, parent, acc}, offset} ->\n            build_surround({:alias, parent, acc}, reversed, line, offset)\n\n          {{:struct, acc}, offset} ->\n            build_surround({:struct, acc}, reversed, line, offset)\n\n          _ ->\n            :none\n        end\n    end\n  end\n\n  defp maybe_operator(reversed_pre, post, line, opts) do\n    case take_operator(post, []) do\n      {[], _rest} ->\n        :none\n\n      {reversed_post, rest} ->\n        reversed = reversed_post ++ reversed_pre\n\n        case codepoint_cursor_context(reversed, opts) do\n          {{:operator, ~c\"&\"}, offset} when hd(rest) in ?0..?9 ->\n            arg = Enum.take_while(rest, &(&1 in ?0..?9))\n\n            build_surround(\n              {:capture_arg, ~c\"&\" ++ arg},\n              :lists.reverse(arg, reversed),\n              line,\n              offset + length(arg)\n            )\n\n          {{:operator, acc}, offset} ->\n            build_surround({:operator, acc}, reversed, line, offset)\n\n          {{:sigil, ~c\"\"}, offset} when hd(rest) in ?A..?Z or hd(rest) in ?a..?z ->\n            build_surround({:sigil, [hd(rest)]}, [hd(rest) | reversed], line, offset + 1)\n\n          {{:dot, _, [_ | _]} = dot, offset} ->\n            build_surround(dot, reversed, line, offset)\n\n          _ ->\n            :none\n        end\n    end\n  end\n\n  defp build_surround(context, reversed, line, offset) do\n    {post, reversed_pre} = enum_reverse_at(reversed, offset, [])\n    pre = :lists.reverse(reversed_pre)\n    pre_length = :string.length(pre) + 1\n\n    %{\n      context: context,\n      begin: {line, pre_length},\n      end: {line, pre_length + :string.length(post)}\n    }\n  end\n\n  defp take_identifier([h | t], acc) when h in @trailing_identifier,\n    do: {:identifier, [h | acc], t}\n\n  defp take_identifier([h | t], acc) when h not in @non_identifier,\n    do: take_identifier(t, [h | acc])\n\n  defp take_identifier(rest, acc) do\n    with {[?. | t], _} <- strip_spaces(rest, 0),\n         {[h | _], _} when h in ?A..?Z <- strip_spaces(t, 0) do\n      take_alias(rest, acc)\n    else\n      _ -> {:identifier, acc, rest}\n    end\n  end\n\n  defp take_alias([h | t], acc) when h in ?A..?Z or h in ?a..?z or h in ?0..?9 or h == ?_,\n    do: take_alias(t, [h | acc])\n\n  defp take_alias(rest, acc) do\n    with {[?. | t], acc} <- move_spaces(rest, acc),\n         {[h | t], acc} when h in ?A..?Z <- move_spaces(t, [?. | acc]) do\n      take_alias(t, [h | acc])\n    else\n      _ -> {:alias, acc, rest}\n    end\n  end\n\n  defp take_operator([h | t], acc) when h in @operators, do: take_operator(t, [h | acc])\n  defp take_operator([h | t], acc) when h == ?., do: take_operator(t, [h | acc])\n  defp take_operator(rest, acc), do: {acc, rest}\n\n  # Unquoted atom handling\n  defp adjust_position(reversed_pre, [?: | post])\n       when hd(post) != ?: and (reversed_pre == [] or hd(reversed_pre) != ?:) do\n    {[?: | reversed_pre], post}\n  end\n\n  defp adjust_position(reversed_pre, [?% | post]) do\n    adjust_position([?% | reversed_pre], post)\n  end\n\n  # Dot/struct handling\n  defp adjust_position(reversed_pre, post) do\n    case move_spaces(post, reversed_pre) do\n      # If we are between spaces and a dot, move past the dot\n      {[?. | post], reversed_pre} when hd(post) != ?. and hd(reversed_pre) != ?. ->\n        {post, reversed_pre} = move_spaces(post, [?. | reversed_pre])\n        {reversed_pre, post}\n\n      _ ->\n        case strip_spaces(reversed_pre, 0) do\n          # If there is a dot to our left, make sure to move to the first character\n          {[?. | rest], _} when rest == [] or hd(rest) not in ~c\".:\" ->\n            {post, reversed_pre} = move_spaces(post, reversed_pre)\n            {reversed_pre, post}\n\n          # If there is a % to our left, make sure to move to the first character\n          {[?% | _], _} ->\n            case move_spaces(post, reversed_pre) do\n              {[h | _] = post, reversed_pre} when h in ?A..?Z ->\n                {reversed_pre, post}\n\n              _ ->\n                {reversed_pre, post}\n            end\n\n          _ ->\n            {reversed_pre, post}\n        end\n    end\n  end\n\n  defp move_spaces([h | t], acc) when h in @space, do: move_spaces(t, [h | acc])\n  defp move_spaces(t, acc), do: {t, acc}\n\n  defp string_reverse_at(charlist, 0, acc), do: {acc, charlist}\n\n  defp string_reverse_at(charlist, n, acc) do\n    case :unicode_util.gc(charlist) do\n      [gc | cont] when is_integer(gc) -> string_reverse_at(cont, n - 1, [gc | acc])\n      [gc | cont] when is_list(gc) -> string_reverse_at(cont, n - 1, :lists.reverse(gc, acc))\n      [] -> {acc, []}\n    end\n  end\n\n  defp enum_reverse_at([h | t], n, acc) when n > 0, do: enum_reverse_at(t, n - 1, [h | acc])\n  defp enum_reverse_at(rest, _, acc), do: {acc, rest}\n\n  defp last_line(binary) when is_binary(binary) do\n    [last_line | lines_reverse] =\n      binary\n      |> String.split([\"\\r\\n\", \"\\n\"])\n      |> Enum.reverse()\n\n    prepend_cursor_lines(lines_reverse, String.to_charlist(last_line))\n  end\n\n  defp last_line(charlist) when is_list(charlist) do\n    [last_line | lines_reverse] =\n      charlist\n      |> :string.replace(~c\"\\r\\n\", ~c\"\\n\", :all)\n      |> :string.join(~c\"\")\n      |> :string.split(~c\"\\n\", :all)\n      |> Enum.reverse()\n\n    prepend_cursor_lines(lines_reverse, last_line)\n  end\n\n  defp prepend_cursor_lines(lines, last_line) do\n    with [line | lines] <- lines,\n         {trimmed_line, incomplete?} = ends_as_incomplete(to_charlist(line), [], true),\n         true <- incomplete? or starts_with_dot?(last_line) do\n      prepend_cursor_lines(lines, Enum.reverse(trimmed_line, last_line))\n    else\n      _ -> last_line\n    end\n  end\n\n  defp starts_with_dot?([?. | _]), do: true\n  defp starts_with_dot?([h | t]) when h in @space, do: starts_with_dot?(t)\n  defp starts_with_dot?(_), do: false\n\n  defp ends_as_incomplete([?# | _], acc, incomplete?),\n    do: {acc, incomplete?}\n\n  defp ends_as_incomplete([h | t], acc, _incomplete?) when h in [?(, ?.],\n    do: ends_as_incomplete(t, [h | acc], true)\n\n  defp ends_as_incomplete([h | t], acc, incomplete?) when h in @space,\n    do: ends_as_incomplete(t, [h | acc], incomplete?)\n\n  defp ends_as_incomplete([h | t], acc, _incomplete?),\n    do: ends_as_incomplete(t, [h | acc], false)\n\n  defp ends_as_incomplete([], acc, incomplete?),\n    do: {acc, incomplete?}\n\n  defp surround_line(binary, line, column) when is_binary(binary) do\n    binary\n    |> String.split([\"\\r\\n\", \"\\n\"])\n    |> Enum.map(&String.to_charlist/1)\n    |> surround_lines(line, column)\n  end\n\n  defp surround_line(charlist, line, column) when is_list(charlist) do\n    charlist\n    |> :string.replace(~c\"\\r\\n\", ~c\"\\n\", :all)\n    |> :string.join(~c\"\")\n    |> :string.split(~c\"\\n\", :all)\n    |> surround_lines(line, column)\n  end\n\n  defp surround_lines(lines, line, column) do\n    {lines_before_reverse, cursor_line, lines_after} = split_at(lines, line, [])\n    {trimmed_cursor_line, incomplete?} = ends_as_incomplete(to_charlist(cursor_line), [], true)\n\n    reversed_cursor_line =\n      if column - 1 > length(trimmed_cursor_line) do\n        # Don't strip comments if cursor is inside a comment\n        Enum.reverse(cursor_line)\n      else\n        trimmed_cursor_line\n      end\n\n    {cursor_line, after_lengths} =\n      append_surround_lines(lines_after, [], [reversed_cursor_line], incomplete?)\n\n    {cursor_line, before_lengths} = prepend_surround_lines(lines_before_reverse, [], cursor_line)\n    {cursor_line, before_lengths, [length(reversed_cursor_line) | after_lengths]}\n  end\n\n  defp split_at([line], _, acc), do: {acc, line, []}\n  defp split_at([line | lines], 1, acc), do: {acc, line, lines}\n  defp split_at([line | lines], count, acc), do: split_at(lines, count - 1, [line | acc])\n\n  defp prepend_surround_lines(lines, lengths, last_line) do\n    with [line | lines] <- lines,\n         {trimmed_line, incomplete?} = ends_as_incomplete(to_charlist(line), [], true),\n         true <- incomplete? or starts_with_dot?(last_line) do\n      lengths = [length(trimmed_line) | lengths]\n      prepend_surround_lines(lines, lengths, Enum.reverse(trimmed_line, last_line))\n    else\n      _ -> {last_line, Enum.reverse(lengths)}\n    end\n  end\n\n  defp append_surround_lines(lines, lengths, acc_lines, incomplete?) do\n    with [line | lines] <- lines,\n         line = to_charlist(line),\n         true <- incomplete? or starts_with_dot?(line) do\n      {trimmed_line, incomplete?} = ends_as_incomplete(line, [], true)\n      lengths = [length(trimmed_line) | lengths]\n      append_surround_lines(lines, lengths, [trimmed_line | acc_lines], incomplete?)\n    else\n      _ -> {Enum.reduce(acc_lines, [], &Enum.reverse/2), Enum.reverse(lengths)}\n    end\n  end\n\n  defp to_multiline_range(:none, _, _, _), do: :none\n\n  defp to_multiline_range(\n         %{begin: {begin_line, begin_column}, end: {end_line, end_column}} = context,\n         prepended,\n         lines_before_lengths,\n         lines_current_and_after_lengths\n       ) do\n    {begin_line, begin_column} =\n      Enum.reduce_while(lines_before_lengths, {begin_line, begin_column - prepended}, fn\n        line_length, {acc_line, acc_column} ->\n          if acc_column < 1 do\n            {:cont, {acc_line - 1, acc_column + line_length}}\n          else\n            {:halt, {acc_line, acc_column}}\n          end\n      end)\n\n    {end_line, end_column} =\n      Enum.reduce_while(lines_current_and_after_lengths, {end_line, end_column - prepended}, fn\n        line_length, {acc_line, acc_column} ->\n          if acc_column > line_length + 1 do\n            {:cont, {acc_line + 1, acc_column - line_length}}\n          else\n            {:halt, {acc_line, acc_column}}\n          end\n      end)\n\n    %{context | begin: {begin_line, begin_column}, end: {end_line, end_column}}\n  end\n\n  @doc \"\"\"\n  Receives a string and returns a quoted expression\n  with the cursor AST position within its parent expression.\n\n  This function receives a string with an Elixir code fragment,\n  representing a cursor position, and converts such string to\n  AST with the inclusion of special `__cursor__()` node representing\n  the cursor position within its container (i.e. its parent).\n\n  For example, take this code, which would be given as input:\n\n      max(some_value,\n\n  This function will return the AST equivalent to:\n\n      max(some_value, __cursor__())\n\n  In other words, this function is capable of closing any open\n  brackets and insert the cursor position. Other content at the\n  cursor position which is not a parent is discarded.\n  For example, if this is given as input:\n\n      max(some_value, another_val\n\n  It will return the same AST:\n\n      max(some_value, __cursor__())\n\n  Similarly, if only this is given:\n\n      max(some_va\n\n  Then it returns:\n\n      max(__cursor__())\n\n  Calls without parenthesis are also supported, as we assume the\n  brackets are implicit.\n\n  Tuples, lists, maps, and binaries all retain the cursor position:\n\n      max(some_value, [1, 2,\n\n  Returns the following AST:\n\n      max(some_value, [1, 2, __cursor__()])\n\n  Keyword lists (and do-end blocks) are also retained. The following:\n\n      if(some_value, do:\n      if(some_value, do: :token\n      if(some_value, do: 1 + val\n\n  all return:\n\n      if(some_value, do: __cursor__())\n\n  For multi-line blocks, all previous lines are preserved.\n\n  The AST returned by this function is not safe to evaluate but\n  it can be analyzed and expanded.\n\n  ## Examples\n\n  Function call:\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"max(some_value, \")\n      {:ok, {:max, [line: 1], [{:some_value, [line: 1], nil}, {:__cursor__, [line: 1], []}]}}\n\n  Containers (for example, a list):\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"[some, value\")\n      {:ok, [{:some, [line: 1], nil}, {:__cursor__, [line: 1], []}]}\n\n  If an expression is complete, then the whole expression is discarded\n  and only the parent is returned:\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"if(is_atom(var)\")\n      {:ok, {:if, [line: 1], [{:__cursor__, [line: 1], []}]}}\n\n  this means complete expressions themselves return only the cursor:\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"if(is_atom(var))\")\n      {:ok, {:__cursor__, [line: 1], []}}\n\n  Operators are also included from Elixir v1.15:\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"foo +\")\n      {:ok, {:+, [line: 1], [{:foo, [line: 1], nil}, {:__cursor__, [line: 1], []}]}}\n\n  In order to parse the left-side of `->` properly, which appears both\n  in anonymous functions and do-end blocks, the trailing fragment option\n  must be given with the rest of the contents:\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"fn x\", trailing_fragment: \" -> :ok end\")\n      {:ok, {:fn, [line: 1], [{:->, [line: 1], [[{:__cursor__, [line: 1], []}], :ok]}]}}\n\n  ## Options\n\n    * `:file` - the filename to be reported in case of parsing errors.\n      Defaults to `\"nofile\"`.\n\n    * `:line` - the starting line of the string being parsed.\n      Defaults to `1`.\n\n    * `:column` - the starting column of the string being parsed.\n      Defaults to `1`.\n\n    * `:columns` - when `true`, attach a `:column` key to the quoted\n      metadata. Defaults to `false`.\n\n    * `:token_metadata` - when `true`, includes token-related\n      metadata in the expression AST, such as metadata for `do` and `end`\n      tokens, for closing tokens, end of expressions, as well as delimiters\n      for sigils. See `t:Macro.metadata/0`. Defaults to `false`.\n\n    * `:literal_encoder` - a function to encode literals in the AST.\n      See the documentation for `Code.string_to_quoted/2` for more information.\n\n    * `:trailing_fragment` (since v1.18.0) - the rest of the contents after\n      the cursor. This is necessary to correctly complete anonymous functions\n      and the left-hand side of `->`\n\n    * `:preserve_sigils` (since v1.20.0) - preserve sigil cursor location\n      (see \"Tracking sigils\" section below)\n\n  ## Tracking sigils\n\n  The `:preserve_sigils` option can be used to track cursor positions inside\n  a sigil.\n\n  If the sigil is terminated abruptly, the `sigil_*` call will have the cursor\n  as the second argument:\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"~r/foo\", preserve_sigils: true)\n      {:ok,\n      {:sigil_r, [delimiter: \"/\", line: 1],\n        [{:<<>>, [line: 1], [\"foo\"]}, {:__cursor__, [line: 1, column: 7], []}]}}\n\n  In case the sigil is completed and has zero or more modifiers, the cursor will\n  be nested in the list, with all previous delimiters specified:\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"~r/foo/i\", preserve_sigils: true)\n      {:ok,\n       {:sigil_r, [delimiter: \"/\", line: 1],\n        [{:<<>>, [line: 1], [\"foo\"]}, [105, {:__cursor__, [line: 1, column: 9], []}]]}}\n\n  If the cursor is after the sigil, then it is discarded as everything else:\n\n      iex> Code.Fragment.container_cursor_to_quoted(\"~r/foo/i \", preserve_sigils: true)\n      {:ok, {:__cursor__, [line: 1], []}}\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec container_cursor_to_quoted(List.Chars.t(), container_cursor_to_quoted_opts()) ::\n          {:ok, Macro.t()} | {:error, {location :: keyword, binary | {binary, binary}, binary}}\n  def container_cursor_to_quoted(fragment, opts \\\\ []) do\n    {trailing_fragment, opts} = Keyword.pop(opts, :trailing_fragment)\n    {preserve_sigils?, opts} = Keyword.pop(opts, :preserve_sigils, false)\n    opts = Keyword.take(opts, [:columns, :token_metadata, :literal_encoder])\n    opts = [check_terminators: {:cursor, preserve_sigils?, []}] ++ opts\n\n    file = Keyword.get(opts, :file, \"nofile\")\n    line = Keyword.get(opts, :line, 1)\n    column = Keyword.get(opts, :column, 1)\n\n    case :elixir_tokenizer.tokenize(to_charlist(fragment), line, column, opts) do\n      {:ok, line, column, _warnings, rev_tokens, rev_terminators}\n      when trailing_fragment == nil ->\n        {rev_tokens, rev_terminators} =\n          with [close, open, {_, _, :__cursor__} = cursor | rev_tokens] <- rev_tokens,\n               {_, [_ | after_fn]} <- Enum.split_while(rev_terminators, &(elem(&1, 0) != :fn)),\n               true <- maybe_missing_stab?(rev_tokens, false),\n               [_ | rev_tokens] <- Enum.drop_while(rev_tokens, &(elem(&1, 0) != :fn)) do\n            {[close, open, cursor | rev_tokens], after_fn}\n          else\n            _ -> {rev_tokens, rev_terminators}\n          end\n\n        tokens = reverse_tokens(line, column, rev_tokens, rev_terminators)\n\n        with {:ok, forms, _warnings} <- :elixir.tokens_to_quoted(tokens, file, opts) do\n          {:ok, forms}\n        end\n\n      {:ok, line, column, _warnings, rev_tokens, rev_terminators} ->\n        tokens =\n          with {before_start, [_ | _] = after_start} <-\n                 Enum.split_while(rev_terminators, &(elem(&1, 0) not in [:do, :fn])),\n               true <- maybe_missing_stab?(rev_tokens, true),\n               opts =\n                 Keyword.put(opts, :check_terminators, {:cursor, false, before_start}),\n               {:error, {meta, _, ~c\"end\"}, _rest, _warnings, trailing_rev_tokens} <-\n                 :elixir_tokenizer.tokenize(to_charlist(trailing_fragment), line, column, opts) do\n            trailing_tokens =\n              reverse_tokens(meta[:line], meta[:column], trailing_rev_tokens, after_start)\n\n            # If the cursor has its own line, then we do not trim new lines trailing tokens.\n            # Otherwise we want to drop any newline so we drop the next tokens after eol.\n            trailing_tokens =\n              case rev_tokens do\n                [_close, _open, {_, _, :__cursor__}, {:eol, _} | _] -> trailing_tokens\n                _ -> Enum.drop_while(trailing_tokens, &match?({:eol, _}, &1))\n              end\n\n            Enum.reverse(rev_tokens, drop_tokens(trailing_tokens, 0))\n          else\n            _ -> reverse_tokens(line, column, rev_tokens, rev_terminators)\n          end\n\n        with {:ok, forms, _warnings} <- :elixir.tokens_to_quoted(tokens, file, opts) do\n          {:ok, forms}\n        end\n\n      {:error, info, _rest, _warnings, _so_far} ->\n        {:error, :elixir_tokenizer.format_error(info)}\n    end\n  end\n\n  defp reverse_tokens(line, column, tokens, terminators) do\n    {terminators, _} =\n      Enum.map_reduce(terminators, column, fn {start, _, _}, column ->\n        atom = :elixir_tokenizer.terminator(start)\n\n        {{atom, {line, column, nil}}, column + length(Atom.to_charlist(atom))}\n      end)\n\n    Enum.reverse(tokens, terminators)\n  end\n\n  # Otherwise we drop all tokens, trying to build a minimal AST\n  # for cursor completion.\n  defp drop_tokens([{:\"}\", _} | _] = tokens, 0), do: tokens\n  defp drop_tokens([{:\"]\", _} | _] = tokens, 0), do: tokens\n  defp drop_tokens([{:\")\", _} | _] = tokens, 0), do: tokens\n  defp drop_tokens([{:\">>\", _} | _] = tokens, 0), do: tokens\n  defp drop_tokens([{:end, _} | _] = tokens, 0), do: tokens\n  defp drop_tokens([{:\",\", _} | _] = tokens, 0), do: tokens\n  defp drop_tokens([{:\";\", _} | _] = tokens, 0), do: tokens\n  defp drop_tokens([{:eol, _} | _] = tokens, 0), do: tokens\n  defp drop_tokens([{:stab_op, _, :->} | _] = tokens, 0), do: tokens\n\n  defp drop_tokens([{:\"}\", _} | tokens], counter), do: drop_tokens(tokens, counter - 1)\n  defp drop_tokens([{:\"]\", _} | tokens], counter), do: drop_tokens(tokens, counter - 1)\n  defp drop_tokens([{:\")\", _} | tokens], counter), do: drop_tokens(tokens, counter - 1)\n  defp drop_tokens([{:\">>\", _} | tokens], counter), do: drop_tokens(tokens, counter - 1)\n  defp drop_tokens([{:end, _} | tokens], counter), do: drop_tokens(tokens, counter - 1)\n\n  defp drop_tokens([{:\"{\", _} | tokens], counter), do: drop_tokens(tokens, counter + 1)\n  defp drop_tokens([{:\"[\", _} | tokens], counter), do: drop_tokens(tokens, counter + 1)\n  defp drop_tokens([{:\"(\", _} | tokens], counter), do: drop_tokens(tokens, counter + 1)\n  defp drop_tokens([{:\"<<\", _} | tokens], counter), do: drop_tokens(tokens, counter + 1)\n  defp drop_tokens([{:fn, _} | tokens], counter), do: drop_tokens(tokens, counter + 1)\n  defp drop_tokens([{:do, _} | tokens], counter), do: drop_tokens(tokens, counter + 1)\n\n  defp drop_tokens([_ | tokens], counter), do: drop_tokens(tokens, counter)\n  defp drop_tokens([], _counter), do: []\n\n  defp maybe_missing_stab?([{:after, _} | _], _stab_choice?), do: true\n  defp maybe_missing_stab?([{:do, _} | _], _stab_choice?), do: true\n  defp maybe_missing_stab?([{:fn, _} | _], _stab_choice?), do: true\n  defp maybe_missing_stab?([{:else, _} | _], _stab_choice?), do: true\n  defp maybe_missing_stab?([{:catch, _} | _], _stab_choice?), do: true\n  defp maybe_missing_stab?([{:rescue, _} | _], _stab_choice?), do: true\n  defp maybe_missing_stab?([{:stab_op, _, :->} | _], stab_choice?), do: stab_choice?\n  defp maybe_missing_stab?([_ | tail], stab_choice?), do: maybe_missing_stab?(tail, stab_choice?)\n  defp maybe_missing_stab?([], _stab_choice?), do: false\nend\n"
  },
  {
    "path": "lib/elixir/lib/code/identifier.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Code.Identifier do\n  @moduledoc false\n\n  @doc \"\"\"\n  Checks if the given identifier is an unary op.\n\n  ## Examples\n\n      iex> Code.Identifier.unary_op(:+)\n      {:non_associative, 300}\n\n  \"\"\"\n  @spec unary_op(atom) :: {:non_associative, precedence :: pos_integer} | :error\n  def unary_op(op) do\n    cond do\n      op in [:&, :...] -> {:non_associative, 90}\n      op in [:!, :^, :not, :+, :-, :\"~~~\"] -> {:non_associative, 300}\n      op in [:@] -> {:non_associative, 320}\n      true -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Checks if the given identifier is a binary op.\n\n  ## Examples\n\n      iex> Code.Identifier.binary_op(:+)\n      {:left, 210}\n\n  \"\"\"\n  @spec binary_op(atom) :: {:left | :right, precedence :: pos_integer} | :error\n  def binary_op(op) do\n    cond do\n      op in [:<-, :\\\\] -> {:left, 40}\n      op in [:when] -> {:right, 50}\n      op in [:\"::\"] -> {:right, 60}\n      op in [:|] -> {:right, 70}\n      op in [:=] -> {:right, 100}\n      op in [:||, :|||, :or] -> {:left, 120}\n      op in [:&&, :&&&, :and] -> {:left, 130}\n      op in [:==, :!=, :=~, :===, :!==] -> {:left, 140}\n      op in [:<, :<=, :>=, :>] -> {:left, 150}\n      op in [:|>, :<<<, :>>>, :<~, :~>, :<<~, :~>>, :<~>, :\"<|>\"] -> {:left, 160}\n      op in [:in] -> {:left, 170}\n      op in [:\"^^^\"] -> {:left, 180}\n      op in [:++, :--, :.., :<>, :+++, :---] -> {:right, 200}\n      op in [:+, :-] -> {:left, 210}\n      op in [:*, :/] -> {:left, 220}\n      op in [:**] -> {:left, 230}\n      op in [:.] -> {:left, 310}\n      true -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Extracts the name and arity of the parent from the anonymous function identifier.\n  \"\"\"\n  # Example of this format: -NAME/ARITY-fun-COUNT-\n  def extract_anonymous_fun_parent(atom) when is_atom(atom) do\n    with \"-\" <> rest <- Atom.to_string(atom),\n         [trailing | reversed] = rest |> String.split(\"/\") |> Enum.reverse(),\n         [arity, _inner, _count, \"\"] <- String.split(trailing, \"-\") do\n      {reversed |> Enum.reverse() |> Enum.join(\"/\") |> String.to_atom(), arity}\n    else\n      _ -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Escapes the given identifier.\n  \"\"\"\n  @spec escape(binary(), char() | nil, :infinity | non_neg_integer, (char() -> iolist() | false)) ::\n          {escaped :: binary(), remaining :: binary()}\n  def escape(binary, char, limit \\\\ :infinity, fun \\\\ &escape_map/1)\n      when (is_binary(binary) and ((char in 0..0x10FFFF or is_nil(char)) and limit == :infinity)) or\n             (is_integer(limit) and limit >= 0) do\n    escape(binary, char, limit, <<>>, fun)\n  end\n\n  defp escape(<<_, _::binary>> = binary, _char, 0, acc, _fun) do\n    {acc, binary}\n  end\n\n  defp escape(<<char, t::binary>>, char, count, acc, fun) do\n    escape(t, char, decrement(count), <<acc::binary, ?\\\\, char>>, fun)\n  end\n\n  defp escape(<<?#, ?{, t::binary>>, char, count, acc, fun) do\n    escape(t, char, decrement(count), <<acc::binary, ?\\\\, ?#, ?{>>, fun)\n  end\n\n  defp escape(<<h::utf8, t::binary>>, char, count, acc, fun) do\n    if value = fun.(h) do\n      value = IO.iodata_to_binary(value)\n      escape(t, char, decrement(count), <<acc::binary, value::binary>>, fun)\n    else\n      escape(t, char, decrement(count), escape_char(h, acc), fun)\n    end\n  end\n\n  defp escape(<<a::4, b::4, t::binary>>, char, count, acc, fun) do\n    escape(t, char, decrement(count), <<acc::binary, ?\\\\, ?x, to_hex(a), to_hex(b)>>, fun)\n  end\n\n  defp escape(<<>>, _char, _count, acc, _fun) do\n    {acc, <<>>}\n  end\n\n  defp escape_char(0, acc), do: <<acc::binary, ?\\\\, ?0>>\n\n  defp escape_char(char, acc)\n       # Some characters that are confusing (zero-width / alternative spaces) are displayed\n       # using their unicode representation:\n       # https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Special-purpose_characters\n\n       # BOM\n       when char == 0xFEFF\n       # Mathematical invisibles\n       when char in 0x2061..0x2064\n       # Bidirectional neutral\n       when char in [0x061C, 0x200E, 0x200F]\n       # Bidirectional general (source of vulnerabilities)\n       when char in 0x202A..0x202E\n       when char in 0x2066..0x2069\n       # Interlinear annotations\n       when char in 0xFFF9..0xFFFC\n       # Zero-width joiners and non-joiners\n       when char in [0x200C, 0x200D, 0x034F]\n       # Non-break space / zero-width space\n       when char in [0x00A0, 0x200B, 0x2060]\n       # Line/paragraph separators\n       when char in [0x2028, 0x2029]\n       # Spaces\n       when char in 0x2000..0x200A\n       when char == 0x205F do\n    <<a::4, b::4, c::4, d::4>> = <<char::16>>\n    <<acc::binary, ?\\\\, ?u, to_hex(a), to_hex(b), to_hex(c), to_hex(d)>>\n  end\n\n  defp escape_char(char, acc)\n       when char in 0x20..0x7E\n       when char in 0xA0..0xD7FF\n       when char in 0xE000..0xFFFD\n       when char in 0x10000..0x10FFFF do\n    <<acc::binary, char::utf8>>\n  end\n\n  defp escape_char(char, acc) when char < 0x100 do\n    <<a::4, b::4>> = <<char::8>>\n    <<acc::binary, ?\\\\, ?x, to_hex(a), to_hex(b)>>\n  end\n\n  defp escape_char(char, acc) when char < 0x10000 do\n    <<a::4, b::4, c::4, d::4>> = <<char::16>>\n    <<acc::binary, ?\\\\, ?x, ?{, to_hex(a), to_hex(b), to_hex(c), to_hex(d), ?}>>\n  end\n\n  defp escape_char(char, acc) when char < 0x1000000 do\n    <<a::4, b::4, c::4, d::4, e::4, f::4>> = <<char::24>>\n\n    <<acc::binary, ?\\\\, ?x, ?{, to_hex(a), to_hex(b), to_hex(c), to_hex(d), to_hex(e), to_hex(f),\n      ?}>>\n  end\n\n  defp escape_map(?\\a), do: \"\\\\a\"\n  defp escape_map(?\\b), do: \"\\\\b\"\n  defp escape_map(?\\d), do: \"\\\\d\"\n  defp escape_map(?\\e), do: \"\\\\e\"\n  defp escape_map(?\\f), do: \"\\\\f\"\n  defp escape_map(?\\n), do: \"\\\\n\"\n  defp escape_map(?\\r), do: \"\\\\r\"\n  defp escape_map(?\\t), do: \"\\\\t\"\n  defp escape_map(?\\v), do: \"\\\\v\"\n  defp escape_map(?\\\\), do: \"\\\\\\\\\"\n  defp escape_map(_), do: false\n\n  @compile {:inline, to_hex: 1, decrement: 1}\n  defp to_hex(c) when c in 0..9, do: ?0 + c\n  defp to_hex(c) when c in 10..15, do: ?A + c - 10\n\n  defp decrement(:infinity), do: :infinity\n  defp decrement(counter), do: counter - 1\nend\n"
  },
  {
    "path": "lib/elixir/lib/code/normalizer.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Code.Normalizer do\n  @moduledoc false\n\n  defguard is_literal(x)\n           when is_integer(x) or\n                  is_float(x) or\n                  is_binary(x) or\n                  is_atom(x)\n\n  @doc \"\"\"\n  Wraps literals in the quoted expression to conform to the AST format expected\n  by the formatter.\n  \"\"\"\n  @spec normalize(Macro.t(), keyword()) :: Macro.t()\n  def normalize(quoted, opts \\\\ []) do\n    line = Keyword.get(opts, :line, nil)\n    escape = Keyword.get(opts, :escape, true)\n    locals_without_parens = Keyword.get(opts, :locals_without_parens, [])\n\n    state = %{\n      escape: escape,\n      parent_meta: [line: line],\n      locals_without_parens: locals_without_parens ++ Code.Formatter.locals_without_parens()\n    }\n\n    do_normalize(quoted, state)\n  end\n\n  # Wrapped literals should receive the block meta\n  defp do_normalize({:__block__, meta, [literal]}, state)\n       when not is_tuple(literal) or tuple_size(literal) == 2 do\n    normalize_literal(literal, meta, state)\n  end\n\n  # Only normalize the first argument of an alias if it's not an atom\n  defp do_normalize({:__aliases__, meta, [first | rest]}, state) when not is_atom(first) do\n    meta = patch_meta_line(meta, state.parent_meta)\n    first = do_normalize(first, %{state | parent_meta: meta})\n    {:__aliases__, meta, [first | rest]}\n  end\n\n  defp do_normalize({:__aliases__, _, _} = quoted, _state) do\n    quoted\n  end\n\n  # Skip captured arguments like &1\n  defp do_normalize({:&, meta, [term]}, state) when is_integer(term) do\n    meta = patch_meta_line(meta, state.parent_meta)\n    {:&, meta, [term]}\n  end\n\n  # Ranges\n  defp do_normalize(left..right//step, state) do\n    left = do_normalize(left, state)\n    right = do_normalize(right, state)\n    meta = meta_line(state)\n\n    if step == 1 do\n      {:.., meta, [left, right]}\n    else\n      step = do_normalize(step, state)\n      {:..//, meta, [left, right, step]}\n    end\n  end\n\n  # Bit containers\n  defp do_normalize({:<<>>, _, args} = quoted, state) when is_list(args) do\n    normalize_bitstring(quoted, state)\n  end\n\n  # Atoms with interpolations\n  defp do_normalize(\n         {{:., dot_meta, [:erlang, :binary_to_atom]}, call_meta,\n          [{:<<>>, _, parts} = string, :utf8]},\n         state\n       )\n       when is_list(parts) do\n    dot_meta = patch_meta_line(dot_meta, state.parent_meta)\n    call_meta = patch_meta_line(call_meta, dot_meta)\n\n    utf8 =\n      if parts == [] or binary_interpolated?(parts) do\n        # a non-normalized :utf8 atom signals an atom interpolation\n        :utf8\n      else\n        normalize_literal(:utf8, [], state)\n      end\n\n    string =\n      if state.escape do\n        normalize_bitstring(string, state, true)\n      else\n        normalize_bitstring(string, state)\n      end\n\n    {{:., dot_meta, [:erlang, :binary_to_atom]}, call_meta, [string, utf8]}\n  end\n\n  # Charlists with interpolations\n  # TODO: Remove this clause on Elixir v2.0 once single-quoted charlists are removed\n  defp do_normalize({{:., dot_meta, [List, :to_charlist]}, call_meta, [parts]} = quoted, state) do\n    if list_interpolated?(parts) do\n      parts =\n        Enum.map(parts, fn\n          {{:., part_dot_meta, [Kernel, :to_string]}, part_call_meta, args} ->\n            args = normalize_args(args, state)\n\n            {{:., part_dot_meta, [Kernel, :to_string]}, part_call_meta, args}\n\n          part when is_binary(part) ->\n            if state.escape do\n              maybe_escape_literal(part, state)\n            else\n              part\n            end\n        end)\n\n      {{:., dot_meta, [List, :to_charlist]}, call_meta, [parts]}\n    else\n      normalize_call(quoted, state)\n    end\n  end\n\n  # Don't normalize the `Access` atom in access syntax\n  defp do_normalize({:., meta, [Access, :get]}, state) do\n    meta = patch_meta_line(meta, state.parent_meta)\n    {:., meta, [Access, :get]}\n  end\n\n  # The right hand side is an atom in the AST but it's not an atom literal, so\n  # it should not be wrapped. However, it should be escaped if applicable.\n  defp do_normalize({:., meta, [left, right]}, state) when is_atom(right) do\n    meta = patch_meta_line(meta, state.parent_meta)\n\n    left = do_normalize(left, %{state | parent_meta: meta})\n    right = maybe_escape_literal(right, state)\n\n    {:., meta, [left, right]}\n  end\n\n  # left -> right\n  defp do_normalize({:->, meta, [left, right]}, state) do\n    meta = patch_meta_line(meta, state.parent_meta)\n\n    left = normalize_args(left, %{state | parent_meta: meta})\n    right = do_normalize(right, %{state | parent_meta: meta})\n    {:->, meta, [left, right]}\n  end\n\n  # Maps\n  defp do_normalize({:%{}, meta, args}, state) when is_list(args) do\n    meta =\n      if meta == [] do\n        line = state.parent_meta[:line]\n        [line: line, closing: [line: line]]\n      else\n        meta\n      end\n\n    state = %{state | parent_meta: meta}\n\n    args =\n      case args do\n        [{:|, pipe_meta, [left, right]}] ->\n          left = do_normalize(left, state)\n          right = normalize_map_args(right, state)\n          [{:|, pipe_meta, [left, right]}]\n\n        args ->\n          normalize_map_args(args, state)\n      end\n\n    {:%{}, meta, args}\n  end\n\n  # Sigils\n  defp do_normalize({sigil, meta, [{:<<>>, _, args} = string, modifiers]} = quoted, state)\n       when is_atom(sigil) and is_list(args) and is_list(modifiers) do\n    with \"sigil_\" <> _ <- Atom.to_string(sigil),\n         true <- binary_interpolated?(args),\n         true <- List.ascii_printable?(modifiers) do\n      meta =\n        meta\n        |> patch_meta_line(state.parent_meta)\n        |> Keyword.put_new(:delimiter, \"\\\"\")\n\n      {sigil, meta, [do_normalize(string, %{state | parent_meta: meta}), modifiers]}\n    else\n      _ ->\n        normalize_call(quoted, state)\n    end\n  end\n\n  # Tuples\n  defp do_normalize({:{}, meta, args} = quoted, state) when is_list(args) do\n    {last_arg, args} = List.pop_at(args, -1)\n\n    if args != [] and match?([_ | _], last_arg) and keyword?(last_arg) do\n      args = normalize_args(args, state)\n      kw_list = normalize_kw_args(last_arg, state, true)\n      {:{}, meta, args ++ kw_list}\n    else\n      normalize_call(quoted, state)\n    end\n  end\n\n  # Module attributes\n  defp do_normalize({:@, meta, [{name, name_meta, [value]}]}, state) do\n    value =\n      cond do\n        keyword?(value) and value != [] ->\n          normalize_kw_args(value, state, true)\n\n        is_list(value) ->\n          normalize_literal(value, meta, state)\n\n        true ->\n          do_normalize(value, state)\n      end\n\n    {:@, meta, [{name, name_meta, [value]}]}\n  end\n\n  # Regular blocks\n  defp do_normalize({:__block__, meta, args}, state) when is_list(args) do\n    {:__block__, meta, normalize_args(args, state)}\n  end\n\n  # Calls\n  defp do_normalize({_, _, args} = quoted, state) when is_list(args) do\n    normalize_call(quoted, state)\n  end\n\n  # Vars\n  defp do_normalize({_, _, context} = quoted, _state) when is_atom(context) do\n    quoted\n  end\n\n  # Literals\n  defp do_normalize(quoted, state) do\n    normalize_literal(quoted, [], state)\n  end\n\n  # Numbers\n  defp normalize_literal(number, meta, state) when is_number(number) do\n    meta =\n      meta\n      |> Keyword.put_new(:token, inspect(number))\n      |> patch_meta_line(state.parent_meta)\n\n    {:__block__, meta, [number]}\n  end\n\n  # Atom, Strings\n  defp normalize_literal(literal, meta, state) when is_atom(literal) or is_binary(literal) do\n    meta = patch_meta_line(meta, state.parent_meta)\n    literal = maybe_escape_literal(literal, state)\n\n    if is_atom(literal) and Macro.classify_atom(literal) == :alias and\n         is_nil(meta[:delimiter]) do\n      segments =\n        case Atom.to_string(literal) do\n          \"Elixir\" ->\n            [:\"Elixir\"]\n\n          \"Elixir.\" <> segments ->\n            segments\n            |> String.split(\".\")\n            |> Enum.map(&String.to_atom/1)\n        end\n\n      {:__aliases__, meta, segments}\n    else\n      {:__block__, meta, [literal]}\n    end\n  end\n\n  # 2-tuples\n  defp normalize_literal({left, right}, meta, state) do\n    meta = patch_meta_line(meta, state.parent_meta)\n    state = %{state | parent_meta: meta}\n\n    if match?([_ | _], right) and keyword?(right) do\n      {:__block__, meta, [{do_normalize(left, state), normalize_kw_args(right, state, true)}]}\n    else\n      {:__block__, meta, [{do_normalize(left, state), do_normalize(right, state)}]}\n    end\n  end\n\n  # Lists\n  defp normalize_literal(list, meta, state) when is_list(list) do\n    if list != [] and List.ascii_printable?(list) do\n      # It's a charlist, we normalize it as a ~C sigil\n      string =\n        if state.escape do\n          {iolist, _} = Code.Identifier.escape(IO.chardata_to_string(list), nil)\n          IO.iodata_to_binary(iolist)\n        else\n          List.to_string(list)\n        end\n\n      meta = patch_meta_line([delimiter: \"\\\"\"], state.parent_meta)\n\n      {:sigil_c, meta, [{:<<>>, [], [string]}, []]}\n    else\n      meta =\n        if line = state.parent_meta[:line] do\n          meta\n          |> Keyword.put_new(:closing, line: line)\n          |> patch_meta_line(state.parent_meta)\n        else\n          meta\n        end\n\n      {:__block__, meta, [normalize_kw_args(list, state, false)]}\n    end\n  end\n\n  # Probably an invalid value, wrap it and send it upstream\n  defp normalize_literal(quoted, meta, _state) do\n    {:__block__, meta, [quoted]}\n  end\n\n  defp normalize_call({form, meta, args}, state) do\n    meta = patch_meta_line(meta, state.parent_meta)\n    arity = length(args)\n\n    # Only normalize the form if it's a qualified call\n    form =\n      if is_atom(form) do\n        form\n      else\n        do_normalize(form, %{state | parent_meta: meta})\n      end\n\n    meta =\n      if is_nil(meta[:no_parens]) and is_nil(meta[:closing]) and is_nil(meta[:do]) and\n           not Code.Formatter.local_without_parens?(form, arity, state.locals_without_parens) do\n        [closing: [line: meta[:line]]] ++ meta\n      else\n        meta\n      end\n\n    last = List.last(args)\n\n    cond do\n      not allow_keyword?(form, arity) ->\n        args = normalize_args(args, %{state | parent_meta: meta})\n        {form, meta, args}\n\n      Keyword.has_key?(meta, :do) ->\n        # def foo do :ok end\n        # def foo, do: :ok\n        normalize_kw_blocks(form, meta, args, state)\n\n      match?([{:do, _} | _], last) and Keyword.keyword?(last) ->\n        # Non normalized kw blocks\n        line = state.parent_meta[:line] || meta[:line]\n        meta = meta ++ [do: [line: line], end: [line: line]]\n        normalize_kw_blocks(form, meta, args, state)\n\n      true ->\n        args = normalize_args(args, %{state | parent_meta: meta})\n        {last_arg, leading_args} = List.pop_at(args, -1, [])\n\n        last_args =\n          case last_arg do\n            {:__block__, _meta, [[{{:__block__, key_meta, _}, _} | _] = keyword]} ->\n              cond do\n                key_meta[:format] == :keyword ->\n                  [keyword]\n\n                block_keyword?(keyword) ->\n                  [\n                    Enum.map(keyword, fn {{:__block__, meta, args}, value} ->\n                      {{:__block__, [format: :keyword] ++ meta, args}, value}\n                    end)\n                  ]\n\n                true ->\n                  [last_arg]\n              end\n\n            [] ->\n              []\n\n            _ ->\n              [last_arg]\n          end\n\n        {form, meta, leading_args ++ last_args}\n    end\n  end\n\n  defp block_keyword?([{{:__block__, _, [key]}, _val} | tail]) when is_atom(key),\n    do: block_keyword?(tail)\n\n  defp block_keyword?([]), do: true\n  defp block_keyword?(_), do: false\n\n  defp allow_keyword?(:when, 2), do: true\n  defp allow_keyword?(:{}, _), do: false\n  defp allow_keyword?(op, arity), do: not is_atom(op) or not Macro.operator?(op, arity)\n\n  defp normalize_bitstring({:<<>>, meta, parts}, state, escape_interpolation \\\\ false) do\n    meta = patch_meta_line(meta, state.parent_meta)\n\n    parts =\n      if binary_interpolated?(parts) do\n        normalize_interpolation_parts(parts, %{state | parent_meta: meta}, escape_interpolation)\n      else\n        state = %{state | parent_meta: meta}\n\n        Enum.map(parts, fn part ->\n          with {:\"::\", meta, [left, _]} <- part,\n               true <- meta[:inferred_bitstring_spec] do\n            do_normalize(left, state)\n          else\n            _ -> do_normalize(part, state)\n          end\n        end)\n      end\n\n    {:<<>>, meta, parts}\n  end\n\n  defp normalize_interpolation_parts(parts, state, escape_interpolation) do\n    Enum.map(parts, fn\n      {:\"::\", interpolation_meta,\n       [\n         {{:., dot_meta, [Kernel, :to_string]}, middle_meta, [middle]},\n         {:binary, binary_meta, context}\n       ]} ->\n        middle = do_normalize(middle, %{state | parent_meta: dot_meta})\n\n        {:\"::\", interpolation_meta,\n         [\n           {{:., dot_meta, [Kernel, :to_string]}, middle_meta, [middle]},\n           {:binary, binary_meta, context}\n         ]}\n\n      part ->\n        if escape_interpolation do\n          maybe_escape_literal(part, state)\n        else\n          part\n        end\n    end)\n  end\n\n  defp normalize_map_args(args, state) do\n    Enum.map(normalize_kw_args(args, state, false), fn\n      {:__block__, _, [{_, _} = pair]} -> pair\n      pair -> pair\n    end)\n  end\n\n  defp normalize_kw_blocks(form, meta, args, state) do\n    {kw_blocks, leading_args} = List.pop_at(args, -1)\n\n    kw_blocks =\n      Enum.map(kw_blocks, fn {tag, block} ->\n        block = do_normalize(block, %{state | parent_meta: meta})\n\n        block =\n          case block do\n            {_, _, [[{:->, _, _} | _] = block]} -> block\n            block -> block\n          end\n\n        # Only wrap the tag if it isn't already wrapped\n        tag =\n          case tag do\n            {:__block__, _, _} -> tag\n            _ -> {:__block__, [line: meta[:line]], [tag]}\n          end\n\n        {tag, block}\n      end)\n\n    leading_args = normalize_args(leading_args, %{state | parent_meta: meta})\n    {form, meta, leading_args ++ [kw_blocks]}\n  end\n\n  defp normalize_kw_args(elems, state, keyword?)\n\n  defp normalize_kw_args(\n         [{{:__block__, key_meta, [key]}, value} = first | rest] = current,\n         state,\n         keyword?\n       )\n       when is_atom(key) do\n    keyword? = keyword? or keyword?(current)\n\n    first =\n      if key_meta[:format] == :keyword and not keyword? do\n        key_meta = Keyword.delete(key_meta, :format)\n        line = key_meta[:line] || meta_line(state)\n        {:__block__, [line: line], [{{:__block__, key_meta, [key]}, value}]}\n      else\n        first\n      end\n\n    [first | normalize_kw_args(rest, state, keyword?)]\n  end\n\n  defp normalize_kw_args([{left, right} | rest] = current, state, keyword?) do\n    keyword? = keyword? or keyword?(current)\n\n    left =\n      if keyword? do\n        meta = [format: :keyword] ++ meta_line(state)\n        {:__block__, meta, [maybe_escape_literal(left, state)]}\n      else\n        do_normalize(left, state)\n      end\n\n    right = do_normalize(right, state)\n\n    pair =\n      with {:__block__, meta, _} <- left,\n           :keyword <- meta[:format] do\n        {left, right}\n      else\n        _ -> {:__block__, meta_line(state), [{left, right}]}\n      end\n\n    [pair | normalize_kw_args(rest, state, keyword?)]\n  end\n\n  defp normalize_kw_args([first | rest], state, keyword?) do\n    [do_normalize(first, state) | normalize_kw_args(rest, state, keyword?)]\n  end\n\n  defp normalize_kw_args([], _state, _keyword?) do\n    []\n  end\n\n  defp normalize_args(args, state) do\n    Enum.map(args, &do_normalize(&1, state))\n  end\n\n  defp maybe_escape_literal(string, %{escape: true}) when is_binary(string) do\n    {string, _} = Code.Identifier.escape(string, nil)\n    IO.iodata_to_binary(string)\n  end\n\n  defp maybe_escape_literal(atom, %{escape: true} = state) when is_atom(atom) do\n    atom\n    |> Atom.to_string()\n    |> maybe_escape_literal(state)\n    |> String.to_atom()\n  end\n\n  defp maybe_escape_literal(term, _) do\n    term\n  end\n\n  defp binary_interpolated?(parts) do\n    Enum.all?(parts, fn\n      {:\"::\", _, [{{:., _, [Kernel, :to_string]}, _, [_]}, {:binary, _, _}]} -> true\n      binary when is_binary(binary) -> true\n      _ -> false\n    end)\n  end\n\n  defp list_interpolated?(parts) do\n    Enum.all?(parts, fn\n      {{:., _, [Kernel, :to_string]}, _, [_]} -> true\n      binary when is_binary(binary) -> true\n      _ -> false\n    end)\n  end\n\n  defp patch_meta_line(meta, parent_meta) do\n    with nil <- meta[:line],\n         line when is_integer(line) <- parent_meta[:line] do\n      [line: line] ++ meta\n    else\n      _ -> meta\n    end\n  end\n\n  defp meta_line(state) do\n    if line = state.parent_meta[:line] do\n      [line: line]\n    else\n      []\n    end\n  end\n\n  defp keyword?([{{:__block__, key_meta, [key]}, _} | rest]) when is_atom(key) do\n    if key_meta[:format] == :keyword do\n      keyword?(rest)\n    else\n      false\n    end\n  end\n\n  defp keyword?([{key, _value} | rest]) when is_atom(key) do\n    case Atom.to_charlist(key) do\n      ~c\"Elixir.\" ++ _ -> false\n      _ -> keyword?(rest)\n    end\n  end\n\n  defp keyword?([]), do: true\n  defp keyword?(_other), do: false\nend\n"
  },
  {
    "path": "lib/elixir/lib/code/typespec.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Code.Typespec do\n  @moduledoc false\n\n  @doc \"\"\"\n  Converts a spec clause back to Elixir quoted expression.\n  \"\"\"\n  @spec spec_to_quoted(atom, tuple) :: {atom, keyword, [Macro.t()]}\n  def spec_to_quoted(name, spec)\n\n  def spec_to_quoted(name, {:type, anno, :fun, [{:type, _, :product, args}, result]})\n      when is_atom(name) do\n    meta = meta(anno)\n    body = {name, meta, Enum.map(args, &typespec_to_quoted/1)}\n\n    vars =\n      for type_expr <- args ++ [result],\n          var <- collect_vars(type_expr),\n          uniq: true,\n          do: {var, {:var, meta, nil}}\n\n    spec = {:\"::\", meta, [body, typespec_to_quoted(result)]}\n\n    if vars == [] do\n      spec\n    else\n      {:when, meta, [spec, vars]}\n    end\n  end\n\n  def spec_to_quoted(name, {:type, anno, :bounded_fun, [type, constrs]}) when is_atom(name) do\n    meta = meta(anno)\n    {:type, _, :fun, [{:type, _, :product, args}, result]} = type\n\n    guards =\n      for {:type, _, :constraint, [{:atom, _, :is_subtype}, [{:var, _, var}, type]]} <- constrs do\n        {erl_to_ex_var(var), typespec_to_quoted(type)}\n      end\n\n    ignore_vars = Keyword.keys(guards)\n\n    vars =\n      for type_expr <- args ++ [result],\n          var <- collect_vars(type_expr),\n          var not in ignore_vars,\n          uniq: true,\n          do: {var, {:var, meta, nil}}\n\n    args = for arg <- args, do: typespec_to_quoted(arg)\n\n    when_args = [\n      {:\"::\", meta, [{name, meta, args}, typespec_to_quoted(result)]},\n      guards ++ vars\n    ]\n\n    {:when, meta, when_args}\n  end\n\n  @doc \"\"\"\n  Converts a type clause back to Elixir AST.\n  \"\"\"\n  def type_to_quoted(type)\n\n  def type_to_quoted({{:record, record}, fields, args}) when is_atom(record) do\n    fields = for field <- fields, do: typespec_to_quoted(field)\n    args = for arg <- args, do: typespec_to_quoted(arg)\n    type = {:{}, [], [record | fields]}\n    quote(do: unquote(record)(unquote_splicing(args)) :: unquote(type))\n  end\n\n  def type_to_quoted({name, type, args}) when is_atom(name) do\n    args = for arg <- args, do: typespec_to_quoted(arg)\n    quote(do: unquote(name)(unquote_splicing(args)) :: unquote(typespec_to_quoted(type)))\n  end\n\n  @doc \"\"\"\n  Returns all types available from the module's BEAM code.\n\n  The result is returned as a list of tuples where the first\n  element is the type (`:typep`, `:type` and `:opaque`).\n\n  The module must have a corresponding BEAM file which can be\n  located by the runtime system. The types will be in the Erlang\n  Abstract Format.\n  \"\"\"\n  @spec fetch_types(module | binary) :: {:ok, [tuple]} | :error\n  def fetch_types(module) when is_atom(module) or is_binary(module) do\n    case typespecs_abstract_code(module) do\n      {:ok, abstract_code} ->\n        exported_types = for {:attribute, _, :export_type, types} <- abstract_code, do: types\n        exported_types = List.flatten(exported_types)\n\n        types =\n          for {:attribute, _, kind, {name, _, args} = type} <- abstract_code,\n              kind in [:opaque, :type] do\n            cond do\n              kind == :opaque -> {:opaque, type}\n              {name, length(args)} in exported_types -> {:type, type}\n              true -> {:typep, type}\n            end\n          end\n\n        {:ok, types}\n\n      _ ->\n        :error\n    end\n  end\n\n  @doc \"\"\"\n  Returns all specs available from the module's BEAM code.\n\n  The result is returned as a list of tuples where the first\n  element is spec name and arity and the second is the spec.\n\n  The module must have a corresponding BEAM file which can be\n  located by the runtime system. The types will be in the Erlang\n  Abstract Format.\n  \"\"\"\n  @spec fetch_specs(module | binary) :: {:ok, [tuple]} | :error\n  def fetch_specs(module) when is_atom(module) or is_binary(module) do\n    case typespecs_abstract_code(module) do\n      {:ok, abstract_code} ->\n        {:ok, for({:attribute, _, :spec, value} <- abstract_code, do: value)}\n\n      :error ->\n        :error\n    end\n  end\n\n  @doc \"\"\"\n  Returns all callbacks available from the module's BEAM code.\n\n  The result is returned as a list of tuples where the first\n  element is spec name and arity and the second is the spec.\n\n  The module must have a corresponding BEAM file\n  which can be located by the runtime system. The types will be\n  in the Erlang Abstract Format.\n  \"\"\"\n  @spec fetch_callbacks(module | binary) :: {:ok, [tuple]} | :error\n  def fetch_callbacks(module) when is_atom(module) or is_binary(module) do\n    case typespecs_abstract_code(module) do\n      {:ok, abstract_code} ->\n        {:ok, for({:attribute, _, :callback, value} <- abstract_code, do: value)}\n\n      :error ->\n        :error\n    end\n  end\n\n  defp typespecs_abstract_code(module) do\n    with {module, binary} <- get_module_and_beam(module),\n         {:ok, {_, [debug_info: {:debug_info_v1, backend, data}]}} <-\n           :beam_lib.chunks(binary, [:debug_info]) do\n      case data do\n        {:elixir_v1, %{}, specs} ->\n          # Fast path to avoid translation to Erlang from Elixir.\n          {:ok, specs}\n\n        _ ->\n          case backend.debug_info(:erlang_v1, module, data, []) do\n            {:ok, abstract_code} -> {:ok, abstract_code}\n            _ -> :error\n          end\n      end\n    else\n      _ -> :error\n    end\n  end\n\n  defp get_module_and_beam(module) when is_atom(module) do\n    with {^module, beam, _filename} <- :code.get_object_code(module),\n         info_pairs when is_list(info_pairs) <- :beam_lib.info(beam),\n         {:ok, ^module} <- Keyword.fetch(info_pairs, :module) do\n      {module, beam}\n    else\n      _ -> :error\n    end\n  end\n\n  defp get_module_and_beam(beam) when is_binary(beam) do\n    case :beam_lib.info(beam) do\n      [_ | _] = info -> {info[:module], beam}\n      _ -> :error\n    end\n  end\n\n  ## To AST conversion\n\n  defp collect_vars({:ann_type, _anno, args}) when is_list(args) do\n    []\n  end\n\n  defp collect_vars({:type, _anno, _kind, args}) when is_list(args) do\n    Enum.flat_map(args, &collect_vars/1)\n  end\n\n  defp collect_vars({:remote_type, _anno, args}) when is_list(args) do\n    Enum.flat_map(args, &collect_vars/1)\n  end\n\n  defp collect_vars({:typed_record_field, _anno, type}) do\n    collect_vars(type)\n  end\n\n  defp collect_vars({:paren_type, _anno, [type]}) do\n    collect_vars(type)\n  end\n\n  defp collect_vars({:var, _anno, var}) do\n    [erl_to_ex_var(var)]\n  end\n\n  defp collect_vars(_) do\n    []\n  end\n\n  defp typespec_to_quoted({:user_type, anno, name, args}) do\n    args = for arg <- args, do: typespec_to_quoted(arg)\n    {name, meta(anno), args}\n  end\n\n  defp typespec_to_quoted({:type, anno, :tuple, :any}) do\n    {:tuple, meta(anno), []}\n  end\n\n  defp typespec_to_quoted({:type, anno, :tuple, args}) do\n    args = for arg <- args, do: typespec_to_quoted(arg)\n    {:{}, meta(anno), args}\n  end\n\n  defp typespec_to_quoted({:type, _anno, :list, [{:type, _, :union, unions} = arg]}) do\n    case unpack_typespec_kw(unions, []) do\n      {:ok, ast} -> ast\n      :error -> [typespec_to_quoted(arg)]\n    end\n  end\n\n  defp typespec_to_quoted({:type, anno, :list, []}) do\n    {:list, meta(anno), []}\n  end\n\n  defp typespec_to_quoted({:type, _anno, :list, [arg]}) do\n    [typespec_to_quoted(arg)]\n  end\n\n  defp typespec_to_quoted({:type, anno, :nonempty_list, []}) do\n    [{:..., meta(anno), nil}]\n  end\n\n  defp typespec_to_quoted({:type, anno, :nonempty_list, [arg]}) do\n    [typespec_to_quoted(arg), {:..., meta(anno), nil}]\n  end\n\n  defp typespec_to_quoted({:type, anno, :map, :any}) do\n    {:map, meta(anno), []}\n  end\n\n  defp typespec_to_quoted({:type, anno, :map, fields}) do\n    fields =\n      Enum.map(fields, fn\n        {:type, _, :map_field_assoc, :any} ->\n          {{:optional, [], [{:any, [], []}]}, {:any, [], []}}\n\n        {:type, _, :map_field_exact, [{:atom, _, k}, v]} ->\n          {k, typespec_to_quoted(v)}\n\n        {:type, _, :map_field_exact, [k, v]} ->\n          {{:required, [], [typespec_to_quoted(k)]}, typespec_to_quoted(v)}\n\n        {:type, _, :map_field_assoc, [k, v]} ->\n          {{:optional, [], [typespec_to_quoted(k)]}, typespec_to_quoted(v)}\n      end)\n\n    case List.keytake(fields, :__struct__, 0) do\n      {{:__struct__, struct}, fields_pruned} when is_atom(struct) and struct != nil ->\n        map_pruned = {:%{}, meta(anno), fields_pruned}\n        {:%, meta(anno), [struct, map_pruned]}\n\n      _ ->\n        {:%{}, meta(anno), fields}\n    end\n  end\n\n  defp typespec_to_quoted({:type, anno, :binary, [arg1, arg2]}) do\n    line = meta(anno)[:line]\n\n    case {typespec_to_quoted(arg1), typespec_to_quoted(arg2)} do\n      {arg1, 0} ->\n        quote(line: line, do: <<_::unquote(arg1)>>)\n\n      {0, arg2} ->\n        quote(line: line, do: <<_::_*unquote(arg2)>>)\n\n      {arg1, arg2} ->\n        quote(line: line, do: <<_::unquote(arg1), _::_*unquote(arg2)>>)\n    end\n  end\n\n  defp typespec_to_quoted({:type, anno, :union, args}) do\n    args = for arg <- args, do: typespec_to_quoted(arg)\n    Enum.reduce(Enum.reverse(args), fn arg, expr -> {:|, meta(anno), [arg, expr]} end)\n  end\n\n  defp typespec_to_quoted({:type, anno, :fun, [{:type, _, :product, args}, result]}) do\n    args = for arg <- args, do: typespec_to_quoted(arg)\n    [{:->, meta(anno), [args, typespec_to_quoted(result)]}]\n  end\n\n  defp typespec_to_quoted({:type, anno, :fun, [args, result]}) do\n    [{:->, meta(anno), [[typespec_to_quoted(args)], typespec_to_quoted(result)]}]\n  end\n\n  defp typespec_to_quoted({:type, anno, :range, [left, right]}) do\n    {:.., meta(anno), [typespec_to_quoted(left), typespec_to_quoted(right)]}\n  end\n\n  defp typespec_to_quoted({:type, _anno, nil, []}) do\n    []\n  end\n\n  defp typespec_to_quoted({:type, anno, name, args}) do\n    args = for arg <- args, do: typespec_to_quoted(arg)\n    {name, meta(anno), args}\n  end\n\n  defp typespec_to_quoted({:var, anno, var}) do\n    {erl_to_ex_var(var), meta(anno), nil}\n  end\n\n  defp typespec_to_quoted({:op, anno, op, arg}) when op in [:+, :-] do\n    {op, meta(anno), [typespec_to_quoted(arg)]}\n  end\n\n  defp typespec_to_quoted({:op, anno, :*, arg1, arg2}) do\n    {:*, meta(anno), [typespec_to_quoted(arg1), typespec_to_quoted(arg2)]}\n  end\n\n  defp typespec_to_quoted({:remote_type, anno, [mod, name, args]}) do\n    remote_type(anno, mod, name, args)\n  end\n\n  defp typespec_to_quoted({:ann_type, anno, [var, type]}) do\n    {:\"::\", meta(anno), [typespec_to_quoted(var), typespec_to_quoted(type)]}\n  end\n\n  defp typespec_to_quoted(\n         {:typed_record_field, {:record_field, anno1, {:atom, anno2, name}}, type}\n       ) do\n    typespec_to_quoted({:ann_type, anno1, [{:var, anno2, name}, type]})\n  end\n\n  defp typespec_to_quoted({:type, _, :any}) do\n    quote(do: ...)\n  end\n\n  defp typespec_to_quoted({:paren_type, _, [type]}) do\n    typespec_to_quoted(type)\n  end\n\n  defp typespec_to_quoted({type, _anno, atom}) when is_atom(type) do\n    atom\n  end\n\n  defp typespec_to_quoted(other), do: other\n\n  ## Helpers\n\n  defp remote_type(anno, {:atom, _, :elixir}, {:atom, _, :charlist}, []) do\n    typespec_to_quoted({:type, anno, :charlist, []})\n  end\n\n  defp remote_type(anno, {:atom, _, :elixir}, {:atom, _, :nonempty_charlist}, []) do\n    typespec_to_quoted({:type, anno, :nonempty_charlist, []})\n  end\n\n  defp remote_type(anno, {:atom, _, :elixir}, {:atom, _, :struct}, []) do\n    typespec_to_quoted({:type, anno, :struct, []})\n  end\n\n  defp remote_type(anno, {:atom, _, :elixir}, {:atom, _, :as_boolean}, [arg]) do\n    typespec_to_quoted({:type, anno, :as_boolean, [arg]})\n  end\n\n  defp remote_type(anno, {:atom, _, :elixir}, {:atom, _, :keyword}, args) do\n    typespec_to_quoted({:type, anno, :keyword, args})\n  end\n\n  defp remote_type(anno, mod, name, args) do\n    args = for arg <- args, do: typespec_to_quoted(arg)\n    dot = {:., meta(anno), [typespec_to_quoted(mod), typespec_to_quoted(name)]}\n    {dot, meta(anno), args}\n  end\n\n  defp erl_to_ex_var(var) do\n    case Atom.to_string(var) do\n      <<\"_\", c::utf8, rest::binary>> ->\n        String.to_atom(\"_#{String.downcase(<<c::utf8>>)}#{rest}\")\n\n      <<c::utf8, rest::binary>> ->\n        String.to_atom(\"#{String.downcase(<<c::utf8>>)}#{rest}\")\n    end\n  end\n\n  defp unpack_typespec_kw([{:type, _, :tuple, [{:atom, _, atom}, type]} | t], acc) do\n    unpack_typespec_kw(t, [{atom, typespec_to_quoted(type)} | acc])\n  end\n\n  defp unpack_typespec_kw([], acc) do\n    {:ok, Enum.reverse(acc)}\n  end\n\n  defp unpack_typespec_kw(_, _acc) do\n    :error\n  end\n\n  defp meta(anno) do\n    case :erl_anno.location(anno) do\n      {line, column} ->\n        [line: line, column: column]\n\n      line when is_integer(line) ->\n        [line: line]\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/code.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Code do\n  @moduledoc ~S\"\"\"\n  Utilities for managing code compilation, code evaluation, and code loading.\n\n  This module complements Erlang's [`:code` module](`:code`)\n  to add behavior which is specific to Elixir. For functions to\n  manipulate Elixir's AST (rather than evaluating it), see the\n  `Macro` module.\n\n  ## Working with files\n\n  This module contains three functions for compiling and evaluating files.\n  Here is a summary of them and their behavior:\n\n    * `require_file/2` - compiles a file and tracks its name. It does not\n      compile the file again if it has been previously required.\n\n    * `compile_file/2` - compiles a file without tracking its name. Compiles the\n      file multiple times when invoked multiple times.\n\n    * `eval_file/2` - evaluates the file contents without tracking its name. It\n      returns the result of the last expression in the file, instead of the modules\n      defined in it. Evaluated files do not trigger the compilation tracers described\n      in the next section.\n\n  In a nutshell, the first must be used when you want to keep track of the files\n  handled by the system, to avoid the same file from being compiled multiple\n  times. This is common in scripts.\n\n  `compile_file/2` must be used when you are interested in the modules defined in a\n  file, without tracking. `eval_file/2` should be used when you are interested in\n  the result of evaluating the file rather than the modules it defines.\n\n  The functions above work with Elixir source. If you want to work\n  with modules compiled to bytecode, which have the `.beam` extension\n  and are typically found below the _build directory of a Mix project,\n  see the functions in Erlang's [`:code`](`:code`) module.\n\n  ## Code loading on the Erlang VM\n\n  Erlang has two modes to load code: interactive and embedded.\n\n  By default, the Erlang VM runs in interactive mode, where modules\n  are loaded as needed. In embedded mode the opposite happens, as all\n  modules need to be loaded upfront or explicitly.\n\n  You can use `ensure_loaded/1` (as well as `ensure_loaded?/1` and\n  `ensure_loaded!/1`) to check if a module is loaded before using it and\n  act.\n\n  ## `ensure_compiled/1` and `ensure_compiled!/1`\n\n  Elixir also includes `ensure_compiled/1` and `ensure_compiled!/1`\n  functions that are a superset of `ensure_loaded/1`.\n\n  Since Elixir's compilation happens in parallel, in some situations\n  you may need to use a module that was not yet compiled, therefore\n  it can't even be loaded.\n\n  When invoked, `ensure_compiled/1` and `ensure_compiled!/1` halt the\n  compilation of the caller until the module becomes available. Note that\n  the distinction between `ensure_compiled/1` and `ensure_compiled!/1`\n  is important: if you are using `ensure_compiled!/1`, you are\n  indicating to the compiler that you can only continue if said module\n  is available.\n\n  If you are using `Code.ensure_compiled/1`, you are implying you may\n  continue without the module and therefore Elixir may return\n  `{:error, :unavailable}` for cases where the module is not yet available\n  (but may be available later on).\n\n  For those reasons, developers must typically use `Code.ensure_compiled!/1`.\n  In particular, do not do this:\n\n      case Code.ensure_compiled(module) do\n        {:module, _} -> module\n        {:error, _} -> raise ...\n      end\n\n  Finally, note you only need `ensure_compiled!/1` to check for modules\n  being defined within the same project. It does not apply to modules from\n  dependencies as dependencies are always compiled upfront.\n\n  In most cases, `ensure_loaded/1` is enough. `ensure_compiled!/1`\n  must be used in rare cases, usually involving macros that need to\n  invoke a module for callback information. The use of `ensure_compiled/1`\n  is even less likely.\n\n  ## Compilation tracers\n\n  Elixir supports compilation tracers, which allow modules to observe constructs\n  handled by the Elixir compiler when compiling files. A tracer is a module\n  that implements the `trace/2` function. The function receives the event name\n  as first argument and `Macro.Env` as second and it must return `:ok`. It is\n  very important for a tracer to do as little work as possible synchronously\n  and dispatch the bulk of the work to a separate process. **Slow tracers will\n  slow down compilation**.\n\n  You can configure your list of tracers via `put_compiler_option/2`. The\n  following events are available to tracers:\n\n    * `:start` - (since v1.11.0) invoked whenever the compiler starts to trace\n      a new lexical context. A lexical context is started when compiling a new\n      file or when defining a module within a function. Note evaluated code\n      does not start a new lexical context (because they don't track unused\n      aliases, imports, etc) but defining a module inside evaluated code will.\n\n      Note this event may be emitted in parallel, where multiple files/modules\n      invoke `:start` and run at the same time. The value of the `lexical_tracker`\n      of the macro environment, albeit opaque, can be used to uniquely identify\n      the environment.\n\n    * `:stop` - (since v1.11.0) invoked whenever the compiler stops tracing a\n      new lexical context, such as a new file.\n\n    * `{:import, meta, module, opts}` - traced whenever `module` is imported.\n      `meta` is the import AST metadata and `opts` are the import options.\n\n    * `{:imported_function, meta, module, name, arity}` and\n      `{:imported_macro, meta, module, name, arity}` - traced whenever an\n      imported function or macro is invoked. `meta` is the call AST metadata,\n      `module` is the module the import is from, followed by the `name` and `arity`\n      of the imported function/macro. A :remote_function/:remote_macro event\n      may still be emitted for the imported module/name/arity.\n\n    * `{:imported_quoted, meta, module, name, [arity]}` - traced whenever an\n      imported function or macro is processed inside a `quote/2`. `meta` is the\n      call AST metadata, `module` is the module the import is from, followed by\n      the `name` and a list of `arities` of the imported function/macro.\n\n    * `{:alias, meta, alias, as, opts}` - traced whenever `alias` is aliased\n      to `as`. `meta` is the alias AST metadata and `opts` are the alias options.\n\n    * `{:alias_expansion, meta, as, alias}` traced whenever there is an alias\n      expansion for a previously defined `alias`, i.e. when the user writes `as`\n      which is expanded to `alias`. `meta` is the alias expansion AST metadata.\n\n    * `{:alias_reference, meta, module}` - traced whenever there is an alias\n      in the code, i.e. whenever the user writes `MyModule.Foo.Bar` in the code,\n      regardless if it was expanded or not.\n\n    * `{:require, meta, module, opts}` - traced whenever `module` is required.\n      `meta` is the require AST metadata and `opts` are the require options.\n      If the `meta` option contains the `:from_macro`, then module was called\n      from within a macro and therefore must be treated as a compile-time dependency.\n\n    * `{:struct_expansion, meta, module, keys}` - traced whenever `module`'s struct\n      is expanded. `meta` is the struct AST metadata and `keys` are the keys being\n      used by expansion\n\n    * `{:remote_function, meta, module, name, arity}` and\n      `{:remote_macro, meta, module, name, arity}` - traced whenever a remote\n      function or macro is referenced. `meta` is the call AST metadata, `module`\n      is the invoked module, followed by the `name` and `arity`.\n\n    * `{:local_function, meta, name, arity}` and\n      `{:local_macro, meta, name, arity}` - traced whenever a local\n      function or macro is referenced. `meta` is the call AST metadata, followed by\n      the `name` and `arity`.\n\n    * `{:compile_env, app, path, return}` - traced whenever `Application.compile_env/3`\n      or `Application.compile_env!/2` are called. `app` is an atom, `path` is a list\n      of keys to traverse in the application environment and `return` is either\n      `{:ok, value}` or `:error`.\n\n    * `:defmodule` - (since v1.16.2) traced as soon as the definition of a module\n      starts. This is invoked early on in the module life cycle, `Module.open?/1`\n      still returns `false` for such traces\n\n    * `{:on_module, bytecode, _ignore}` - (since v1.13.0) traced whenever a module\n      is defined. This is equivalent to the `@after_compile` callback and invoked\n      after any `@after_compile` in the given module. The third element is currently\n      `:none` but it may provide more metadata in the future. It is best to ignore\n      it at the moment. Note that `Module` functions expecting not yet compiled modules\n      (such as `Module.definitions_in/1`) are still available at the time this event\n      is emitted.\n\n  The `:tracers` compiler option can be combined with the `:parser_options`\n  compiler option to enrich the metadata of the traced events above.\n\n  New events may be added at any time in the future, therefore it is advised\n  for the `trace/2` function to have a \"catch-all\" clause.\n\n  Below is an example tracer that prints all remote function invocations:\n\n      defmodule MyTracer do\n        def trace({:remote_function, _meta, module, name, arity}, env) do\n          IO.puts(\"#{env.file}:#{env.line} #{inspect(module)}.#{name}/#{arity}\")\n          :ok\n        end\n\n        def trace(_event, _env) do\n          :ok\n        end\n      end\n  \"\"\"\n\n  @typedoc \"\"\"\n  A list with all variables and their values.\n\n  The binding keys are usually atoms, but they may be a tuple for variables\n  defined in a different context.\n  \"\"\"\n  @type binding :: [{atom() | tuple(), any}]\n\n  @typedoc \"\"\"\n  Diagnostics returned by the compiler and code evaluation.\n\n  The file and position relate to where the diagnostic should be shown.\n  If there is a file and position, then the diagnostic is precise\n  and you can use the given file and position for generating snippets,\n  IDEs annotations, and so on. An optional span is available with\n  the line and column the diagnostic ends.\n\n  Otherwise, a stacktrace may be given, which you can place your own\n  heuristics to provide better reporting.\n\n  The source field points to the source file the compiler tracked\n  the error to. For example, a file `lib/foo.ex` may embed `.eex`\n  templates from `lib/foo/bar.eex`. A syntax error on the EEx template\n  will point to file `lib/foo/bar.eex` but the source is `lib/foo.ex`.\n  \"\"\"\n  @type diagnostic(severity) :: %{\n          required(:source) => Path.t() | nil,\n          required(:file) => Path.t() | nil,\n          required(:severity) => severity,\n          required(:message) => String.t(),\n          required(:position) => position(),\n          required(:stacktrace) => Exception.stacktrace(),\n          required(:span) => {line :: pos_integer(), column :: pos_integer()} | nil,\n          optional(:details) => term(),\n          optional(any()) => any()\n        }\n\n  @typedoc \"The line. 0 indicates no line.\"\n  @type line() :: non_neg_integer()\n\n  @typedoc \"\"\"\n  The position of the diagnostic.\n\n  Can be either a line number or a `{line, column}`.\n  Line and columns numbers are one-based.\n  A position of `0` represents unknown.\n  \"\"\"\n  @type position() :: line() | {line :: pos_integer(), column :: pos_integer()}\n\n  @typedoc \"\"\"\n  Options for code formatting functions.\n  \"\"\"\n  @type format_opt ::\n          {:file, binary()}\n          | {:line, pos_integer()}\n          | {:line_length, pos_integer()}\n          | {:locals_without_parens, keyword()}\n          | {:force_do_end_blocks, boolean()}\n          | {:migrate, boolean()}\n          | {:migrate_bitstring_modifiers, boolean()}\n          | {:migrate_call_parens_on_pipe, boolean()}\n          | {:migrate_charlists_as_sigils, boolean()}\n          | {:migrate_unless, boolean()}\n          | {atom(), term()}\n\n  @typedoc \"\"\"\n  Options for `quoted_to_algebra/2`.\n  \"\"\"\n  @type quoted_to_algebra_opt ::\n          {:line, pos_integer() | nil}\n          | {:escape, boolean()}\n          | {:locals_without_parens, keyword()}\n          | {:comments, [term()]}\n\n  @typedoc \"\"\"\n  Options for parsing functions that convert strings to quoted expressions.\n  \"\"\"\n  @type parser_opts :: [\n          file: binary(),\n          line: pos_integer(),\n          column: pos_integer(),\n          indentation: non_neg_integer(),\n          columns: boolean(),\n          unescape: boolean(),\n          existing_atoms_only: boolean(),\n          token_metadata: boolean(),\n          literal_encoder: (term(), Macro.metadata() -> term()),\n          static_atoms_encoder: (atom() -> term()),\n          emit_warnings: boolean()\n        ]\n\n  @typedoc \"\"\"\n  Options for evaluation environment, accepted by `env_for_eval/1`.\n  \"\"\"\n  @type env_eval_opt ::\n          {:file, binary()}\n          | {:line, pos_integer()}\n          | {:module, module()}\n\n  @typedoc \"\"\"\n  Options for evaluation functions like `eval_string/3`, `eval_quoted/3`\n  and `eval_quoted_with_env/4`.\n  \"\"\"\n  @type eval_opt ::\n          {:prune_binding, boolean()}\n          | {:dbg_callback, {module(), atom(), list()}}\n\n  @boolean_compiler_options [\n    :docs,\n    :debug_info,\n    :ignore_already_consolidated,\n    :ignore_module_conflict,\n    :relative_paths\n  ]\n\n  @list_compiler_options [:tracers, :parser_options]\n\n  @available_compiler_options @boolean_compiler_options ++\n                                @list_compiler_options ++\n                                [\n                                  :on_undefined_variable,\n                                  :infer_signatures,\n                                  :no_warn_undefined,\n                                  :module_definition\n                                ]\n\n  @doc \"\"\"\n  Lists all required files.\n\n  ## Examples\n\n      Code.require_file(\"../eex/test/eex_test.exs\")\n      List.first(Code.required_files()) =~ \"eex_test.exs\"\n      #=> true\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec required_files() :: [binary]\n  def required_files do\n    :elixir_code_server.call(:required)\n  end\n\n  @deprecated \"Use Code.required_files/0 instead\"\n  @doc false\n  def loaded_files do\n    required_files()\n  end\n\n  @doc false\n  @deprecated \"Use Code.Fragment.cursor_context/2 instead\"\n  def cursor_context(code, options \\\\ []) do\n    Code.Fragment.cursor_context(code, options)\n  end\n\n  @doc \"\"\"\n  Removes files from the required files list.\n\n  The modules defined in the file are not removed;\n  calling this function only removes them from the list,\n  allowing them to be required again.\n\n  The list of files is managed per Erlang VM node.\n\n  ## Examples\n\n      # Require EEx test code\n      Code.require_file(\"../eex/test/eex_test.exs\")\n\n      # Now unrequire all files\n      Code.unrequire_files(Code.required_files())\n\n      # Note that modules are still available\n      function_exported?(EExTest.Compiled, :before_compile, 0)\n      #=> true\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec unrequire_files([binary]) :: :ok\n  def unrequire_files(files) when is_list(files) do\n    :elixir_code_server.cast({:unrequire_files, files})\n  end\n\n  @deprecated \"Use Code.unrequire_files/1 instead\"\n  @doc false\n  def unload_files(files) do\n    unrequire_files(files)\n  end\n\n  @doc \"\"\"\n  Appends a path to the Erlang VM code path list.\n\n  This is the list of directories the Erlang VM uses for\n  finding module code. The list of files is managed per Erlang\n  VM node.\n\n  The path is expanded with `Path.expand/1` before being appended.\n  It requires the path to exist. Returns a boolean indicating if\n  the path was successfully added.\n\n  ## Examples\n\n      Code.append_path(\".\")\n      #=> true\n\n      Code.append_path(\"/does_not_exist\")\n      #=> false\n\n  ## Options\n\n    * `:cache` - (since v1.15.0) when true, the code path is cached\n      the first time it is traversed in order to reduce file system\n      operations.\n\n  \"\"\"\n  @spec append_path(Path.t(), cache: boolean()) :: true | false\n  def append_path(path, opts \\\\ []) do\n    apply(:code, :add_pathz, [to_charlist(Path.expand(path)) | cache(opts)]) == true\n  end\n\n  @doc \"\"\"\n  Prepends a path to the Erlang VM code path list.\n\n  This is the list of directories the Erlang VM uses for\n  finding module code. The list of files is managed per Erlang\n  VM node.\n\n  The path is expanded with `Path.expand/1` before being prepended.\n  It requires the path to exist. Returns a boolean indicating if\n  the path was successfully added.\n\n  ## Examples\n\n      Code.prepend_path(\".\")\n      #=> true\n\n      Code.prepend_path(\"/does_not_exist\")\n      #=> false\n\n  ## Options\n\n    * `:cache` - (since v1.15.0) when true, the code path is cached\n      the first time it is traversed in order to reduce file system\n      operations.\n\n  \"\"\"\n  @spec prepend_path(Path.t(), cache: boolean()) :: boolean()\n  def prepend_path(path, opts \\\\ []) do\n    apply(:code, :add_patha, [to_charlist(Path.expand(path)) | cache(opts)]) == true\n  end\n\n  @doc \"\"\"\n  Prepends a list of `paths` to the Erlang VM code path list.\n\n  This is the list of directories the Erlang VM uses for\n  finding module code. The list of files is managed per Erlang\n  VM node.\n\n  All paths are expanded with `Path.expand/1` before being prepended.\n  Only existing paths are prepended. This function always returns `:ok`,\n  regardless of how many paths were prepended. Use `prepend_path/1`\n  if you need more control.\n\n  ## Examples\n\n      Code.prepend_paths([\".\", \"/does_not_exist\"])\n      #=> :ok\n\n  ## Options\n\n    * `:cache` - when true, the code path is cached the first time\n      it is traversed in order to reduce file system operations.\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec prepend_paths([Path.t()], cache: boolean()) :: :ok\n  def prepend_paths(paths, opts \\\\ []) when is_list(paths) do\n    apply(:code, :add_pathsa, [Enum.map(paths, &to_charlist(Path.expand(&1))) | cache(opts)])\n  end\n\n  @doc \"\"\"\n  Appends a list of `paths` to the Erlang VM code path list.\n\n  This is the list of directories the Erlang VM uses for\n  finding module code. The list of files is managed per Erlang\n  VM node.\n\n  All paths are expanded with `Path.expand/1` before being appended.\n  Only existing paths are appended. This function always returns `:ok`,\n  regardless of how many paths were appended. Use `append_path/1`\n  if you need more control.\n\n  ## Examples\n\n      Code.append_paths([\".\", \"/does_not_exist\"])\n      #=> :ok\n\n  ## Options\n\n    * `:cache` - when true, the code path is cached the first time\n      it is traversed in order to reduce file system operations.\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec append_paths([Path.t()], cache: boolean()) :: :ok\n  def append_paths(paths, opts \\\\ []) when is_list(paths) do\n    apply(:code, :add_pathsz, [Enum.map(paths, &to_charlist(Path.expand(&1))) | cache(opts)])\n  end\n\n  defp cache(opts) do\n    if function_exported?(:code, :add_path, 2) do\n      if opts[:cache], do: [:cache], else: [:nocache]\n    else\n      []\n    end\n  end\n\n  @doc \"\"\"\n  Deletes a path from the Erlang VM code path list.\n\n  This is the list of directories the Erlang VM uses for finding\n  module code. The list of files is managed per Erlang VM node.\n\n  The path is expanded with `Path.expand/1` before being deleted. If the\n  path does not exist, this function returns `false`.\n\n  ## Examples\n\n      Code.prepend_path(\".\")\n      Code.delete_path(\".\")\n      #=> true\n\n      Code.delete_path(\"/does_not_exist\")\n      #=> false\n\n  \"\"\"\n  @spec delete_path(Path.t()) :: boolean\n  def delete_path(path) do\n    case :code.del_path(to_charlist(Path.expand(path))) do\n      result when is_boolean(result) ->\n        result\n\n      {:error, :bad_name} ->\n        raise ArgumentError,\n              \"invalid argument #{inspect(path)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Deletes a list of paths from the Erlang VM code path list.\n\n  This is the list of directories the Erlang VM uses for finding\n  module code. The list of files is managed per Erlang VM node.\n\n  The path is expanded with `Path.expand/1` before being deleted. If the\n  path does not exist, this function returns `false`.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec delete_paths([Path.t()]) :: :ok\n  def delete_paths(paths) when is_list(paths) do\n    for path <- paths do\n      _ = :code.del_path(to_charlist(Path.expand(path)))\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Evaluates the contents given by `string`.\n\n  The `binding` argument is a list of all variables and their values.\n  The `opts` argument is a keyword list of environment options.\n\n  **Warning**: `string` can be any Elixir code and will be executed with\n  the same privileges as the Erlang VM: this means that such code could\n  compromise the machine (for example by executing system commands).\n  Don't use `eval_string/3` with untrusted input (such as strings coming\n  from the network).\n\n  ## Options\n\n  It accepts the same options as both `env_for_eval/1` and\n  `eval_quoted_with_env/4`. Additionally, you may also pass an environment\n  as third argument, so the evaluation happens within that environment.\n\n  ## Return\n\n  Returns a tuple of the form `{value, binding}`, where `value` is the value\n  returned from evaluating `string`. If an error occurs while evaluating\n  `string`, an exception will be raised.\n\n  `binding` is a list with all variable names and their values after evaluating\n  `string`. The binding keys are usually atoms, but they may be a tuple for variables\n  defined in a different context. The names are in no particular order.\n\n  ## Examples\n\n      iex> {result, binding} = Code.eval_string(\"a + b\", [a: 1, b: 2], file: __ENV__.file, line: __ENV__.line)\n      iex> result\n      3\n      iex> Enum.sort(binding)\n      [a: 1, b: 2]\n\n      iex> {result, binding} = Code.eval_string(\"c = a + b\", [a: 1, b: 2], __ENV__)\n      iex> result\n      3\n      iex> Enum.sort(binding)\n      [a: 1, b: 2, c: 3]\n\n      iex> {result, binding} = Code.eval_string(\"a = a + b\", [a: 1, b: 2])\n      iex> result\n      3\n      iex> Enum.sort(binding)\n      [a: 3, b: 2]\n\n  For convenience, you can pass `__ENV__/0` as the `opts_or_env` argument and\n  all imports, requires and aliases defined in the current environment\n  will be automatically carried over:\n\n      iex> require Integer, warn: false\n      iex> {result, binding} = Code.eval_string(\"if Integer.is_odd(a), do: a + b\", [a: 1, b: 2], __ENV__)\n      iex> result\n      3\n      iex> Enum.sort(binding)\n      [a: 1, b: 2]\n\n  \"\"\"\n  @spec eval_string(List.Chars.t(), binding, Macro.Env.t() | [eval_opt | env_eval_opt]) ::\n          {term, binding}\n  def eval_string(string, binding \\\\ [], opts_or_env \\\\ [])\n\n  def eval_string(string, binding, %Macro.Env{} = env) do\n    validated_eval_string(string, validate_binding(binding), env_for_eval(env), [])\n  end\n\n  def eval_string(string, binding, opts) when is_list(opts) do\n    validated_eval_string(string, validate_binding(binding), env_for_eval(opts), opts)\n  end\n\n  defp validate_binding(binding) when is_list(binding), do: binding\n\n  defp validate_binding(binding) do\n    raise ArgumentError, \"binding must be a list, got: #{inspect(binding)}\"\n  end\n\n  defp validated_eval_string(string, binding, env, opts) do\n    %{line: line, file: file} = env\n    forms = :elixir.string_to_quoted!(to_charlist(string), line, 1, file, [])\n    {value, binding, _env} = eval_verify(:eval_forms, [forms, binding, env, opts])\n    {value, binding}\n  end\n\n  defp eval_verify(fun, args) do\n    Module.ParallelChecker.verify(fn ->\n      apply(:elixir, fun, args)\n    end)\n  end\n\n  @doc \"\"\"\n  Executes the given `fun` and capture all diagnostics.\n\n  Diagnostics are warnings and errors emitted during code\n  evaluation or single-file compilation and by functions\n  such as `IO.warn/2`.\n\n  If using `mix compile` or `Kernel.ParallelCompiler`,\n  note they already capture and return diagnostics.\n\n  ## Options\n\n    * `:log` - if the diagnostics should be logged as they happen.\n      Defaults to `false`.\n\n  > #### Rescuing errors {: .info}\n  >\n  > `with_diagnostics/2` does not automatically handle exceptions.\n  > You may capture them by adding a `try/1` in `fun`:\n  >\n  >     {result, all_errors_and_warnings} =\n  >       Code.with_diagnostics(fn ->\n  >         try do\n  >           {:ok, Code.compile_quoted(quoted)}\n  >         rescue\n  >           err -> {:error, err}\n  >         end\n  >       end)\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec with_diagnostics([log: boolean()], (-> result)) ::\n          {result, [diagnostic(:warning | :error)]}\n        when result: term()\n  def with_diagnostics(opts \\\\ [], fun) do\n    value = :erlang.get(:elixir_code_diagnostics)\n    log = Keyword.get(opts, :log, false)\n    :erlang.put(:elixir_code_diagnostics, {[], log})\n\n    try do\n      result = fun.()\n      {diagnostics, _log?} = :erlang.get(:elixir_code_diagnostics)\n      {result, Enum.reverse(diagnostics)}\n    after\n      if value == :undefined do\n        :erlang.erase(:elixir_code_diagnostics)\n      else\n        :erlang.put(:elixir_code_diagnostics, value)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Prints a diagnostic into the standard error.\n\n  A diagnostic is either returned by `Kernel.ParallelCompiler`\n  or by `Code.with_diagnostics/2`.\n\n  ## Options\n\n    * `:snippet` - whether to read the code snippet in the diagnostic location.\n      As it may impact performance, it is not recommended to be used in runtime.\n      Defaults to `true`.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec print_diagnostic(diagnostic(:warning | :error), snippet: boolean()) :: :ok\n  def print_diagnostic(diagnostic, opts \\\\ []) do\n    read_snippet? = Keyword.get(opts, :snippet, true)\n    :elixir_errors.print_diagnostic(diagnostic, read_snippet?)\n    :ok\n  end\n\n  @doc ~S\"\"\"\n  Formats the given code `string`.\n\n  The formatter receives a string representing Elixir code and\n  returns iodata representing the formatted code according to\n  pre-defined rules.\n\n  ## Options\n\n  Regular options (do not change the AST):\n\n    * `:file` - the file which contains the string, used for error\n      reporting\n\n    * `:line` - the line the string starts, used for error reporting\n\n    * `:line_length` - the line length to aim for when formatting\n      the document. Defaults to `98`. This value indicates when an expression\n      should be broken over multiple lines but it is not guaranteed\n      to do so. See the \"Line length\" section below for more information\n\n    * `:locals_without_parens` - a keyword list of name and arity\n      pairs that should be kept without parens whenever possible.\n      The arity may be the atom `:*`, which implies all arities of\n      that name. The formatter already includes a list of functions\n      and this option augments this list.\n\n    * `:force_do_end_blocks` (since v1.9.0) - when `true`, converts all\n      inline usages of `do: ...`,  `else: ...` and friends into `do`-`end`\n      blocks. Defaults to `false`. Note that this option is convergent:\n      once you set it to `true`, **all keywords** will be converted.\n      If you set it to `false` later on, `do`-`end` blocks won't be\n      converted back to keywords.\n\n  Migration options (change the AST), see the \"Migration formatting\" section below:\n\n    * `:migrate` (since v1.18.0) - when `true`, sets all other migration options\n      to `true` by default. Defaults to `false`.\n\n    * `:migrate_bitstring_modifiers` (since v1.18.0) - when `true`,\n      removes unnecessary parentheses in known bitstring\n      [modifiers](`<<>>/1`), for example `<<foo::binary()>>`\n      becomes `<<foo::binary>>`, or adds parentheses for custom\n      modifiers, where `<<foo::custom_type>>` becomes `<<foo::custom_type()>>`.\n      Defaults to the value of the `:migrate` option. This option changes the AST.\n\n    * `:migrate_call_parens_on_pipe` (since v1.19.0) - when `true`,\n      formats calls on the right-hand side of the pipe operator to always include\n      parentheses, for example `foo |> bar` becomes `foo |> bar()` and\n      `foo |> mod.fun` becomes `foo |> mod.fun()`.\n      Parentheses are always added for qualified calls like `foo |> Bar.bar` even\n      when this option is `false`.\n      Defaults to the value of the `:migrate` option. This option changes the AST.\n\n    * `:migrate_charlists_as_sigils` (since v1.18.0) - when `true`,\n      formats charlists as [`~c`](`Kernel.sigil_c/2`) sigils, for example\n      `'foo'` becomes `~c\"foo\"`.\n      Defaults to the value of the `:migrate` option. This option changes the AST.\n\n    * `:migrate_unless` (since v1.18.0) - when `true`,\n      rewrites `unless` expressions using `if` with a negated condition, for example\n      `unless foo, do:` becomes `if !foo, do:`.\n      Defaults to the value of the `:migrate` option. This option changes the AST.\n\n  ## Design principles\n\n  The formatter was designed under three principles.\n\n  First, the formatter never changes the semantics of the code by default.\n  This means the input AST and the output AST are almost always equivalent.\n\n  The second principle is to provide as little configuration as possible.\n  This eases the formatter adoption by removing contention points while\n  making sure a single style is followed consistently by the community as\n  a whole.\n\n  The formatter does not hard code names. The formatter will not behave\n  specially because a function is named `defmodule`, `def`, or the like. This\n  principle mirrors Elixir's goal of being an extensible language where\n  developers can extend the language with new constructs as if they were\n  part of the language. When it is absolutely necessary to change behavior\n  based on the name, this behavior should be configurable, such as the\n  `:locals_without_parens` option.\n\n  ## Running the formatter\n\n  The formatter attempts to fit the most it can on a single line and\n  introduces line breaks wherever possible when it cannot.\n\n  In some cases, this may lead to undesired formatting. Therefore, **some\n  code generated by the formatter may not be aesthetically pleasing and\n  may require explicit intervention from the developer**. That's why we\n  do not recommend to run the formatter blindly in an existing codebase.\n  Instead you should format and sanity check each formatted file.\n\n  For example, the formatter may break a long function definition over\n  multiple clauses:\n\n      def my_function(\n        %User{name: name, age: age, ...},\n        arg1,\n        arg2\n      ) do\n        ...\n      end\n\n  While the code above is completely valid, you may prefer to match on\n  the struct variables inside the function body in order to keep the\n  definition on a single line:\n\n      def my_function(%User{} = user, arg1, arg2) do\n        %{name: name, age: age, ...} = user\n        ...\n      end\n\n  In some situations, you can use the fact the formatter does not generate\n  elegant code as a hint for refactoring. Take this code:\n\n      def board?(board_id, %User{} = user, available_permissions, required_permissions) do\n        Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and\n          required_permissions == Enum.to_list(MapSet.intersection(MapSet.new(required_permissions), MapSet.new(available_permissions)))\n      end\n\n  The code above has very long lines and running the formatter is not going\n  to address this issue. In fact, the formatter may make it more obvious that\n  you have complex expressions:\n\n      def board?(board_id, %User{} = user, available_permissions, required_permissions) do\n        Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and\n          required_permissions ==\n            Enum.to_list(\n              MapSet.intersection(\n                MapSet.new(required_permissions),\n                MapSet.new(available_permissions)\n              )\n            )\n      end\n\n  Take such cases as a suggestion that your code should be refactored:\n\n      def board?(board_id, %User{} = user, available_permissions, required_permissions) do\n        Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and\n          matching_permissions?(required_permissions, available_permissions)\n      end\n\n      defp matching_permissions?(required_permissions, available_permissions) do\n        intersection =\n          required_permissions\n          |> MapSet.new()\n          |> MapSet.intersection(MapSet.new(available_permissions))\n          |> Enum.to_list()\n\n        required_permissions == intersection\n      end\n\n  To sum it up: since the formatter cannot change the semantics of your\n  code, sometimes it is necessary to tweak or refactor the code to get\n  optimal formatting. To help better understand how to control the formatter,\n  we describe in the next sections the cases where the formatter keeps the\n  user encoding and how to control multiline expressions.\n\n  ## Line length\n\n  Another point about the formatter is that the `:line_length` configuration\n  indicates when an expression should be broken over multiple lines but it is\n  not guaranteed to do so. In many cases, it is not possible for the formatter\n  to break your code apart, which means it will go over the line length.\n  For example, if you have a long string:\n\n      \"this is a very long string that will go over the line length\"\n\n  The formatter doesn't know how to break it apart without changing the\n  code underlying syntax representation, so it is up to you to step in:\n\n      \"this is a very long string \" <>\n         \"that will go over the line length\"\n\n  The string concatenation makes the code fit on a single line and also\n  gives more options to the formatter.\n\n  This may also appear in keywords such as do/end blocks and operators,\n  where the `do` keyword may go over the line length because there is no\n  opportunity for the formatter to introduce a line break in a readable way.\n  For example, if you do:\n\n      case very_long_expression() do\n      end\n\n  And only the `do` keyword is beyond the line length, Elixir **will not**\n  emit this:\n\n      case very_long_expression()\n      do\n      end\n\n  So it prefers to not touch the line at all and leave `do` above the\n  line limit.\n\n  ## Keeping user's formatting\n\n  The formatter respects the input format in some cases. Those are\n  listed below:\n\n    * Insignificant digits in numbers are kept as is. The formatter,\n      however, always inserts underscores for decimal numbers with more\n      than 5 digits and converts hexadecimal digits to uppercase\n\n    * Strings, charlists, atoms and sigils are kept as is. No character\n      is automatically escaped or unescaped. The choice of delimiter is\n      also respected from the input\n\n    * Newlines inside blocks are kept as in the input except for:\n      1) expressions that take multiple lines will always have an empty\n      line before and after and 2) empty lines are always squeezed\n      together into a single empty line\n\n    * The choice between `:do` keyword and `do`-`end` blocks is left\n      to the user\n\n    * Lists, tuples, bitstrings, maps, structs and function calls will be\n      broken into multiple lines if they are followed by a newline in the\n      opening bracket and preceded by a new line in the closing bracket\n\n    * Newlines before certain operators (such as the pipeline operators)\n      and before other operators (such as comparison operators)\n\n  The behaviors above are not guaranteed. We may remove or add new\n  rules in the future. The goal of documenting them is to provide better\n  understanding on what to expect from the formatter.\n\n  ### Multi-line lists, maps, tuples, and the like\n\n  You can force lists, tuples, bitstrings, maps, structs and function\n  calls to have one entry per line by adding a newline after the opening\n  bracket and a new line before the closing bracket lines. For example:\n\n      [\n        foo,\n        bar\n      ]\n\n  If there are no newlines around the brackets, then the formatter will\n  try to fit everything on a single line, such that the snippet below\n\n      [foo,\n       bar]\n\n  will be formatted as\n\n      [foo, bar]\n\n  You can also force function calls and keywords to be rendered on multiple\n  lines by having each entry on its own line:\n\n      defstruct name: nil,\n                age: 0\n\n  The code above will be kept with one keyword entry per line by the\n  formatter. To avoid that, just squash everything into a single line.\n\n  ### Parens and no parens in function calls\n\n  Elixir has two syntaxes for function calls. With parens and no parens.\n  By default, Elixir will add parens to all calls except for:\n\n    1. calls that have `do`-`end` blocks\n    2. local calls without parens where the name and arity of the local\n       call is also listed under `:locals_without_parens` (except for\n       calls with arity 0, where the compiler always require parens)\n\n  The choice of parens and no parens also affects indentation. When a\n  function call with parens doesn't fit on the same line, the formatter\n  introduces a newline around parens and indents the arguments with two\n  spaces:\n\n      some_call(\n        arg1,\n        arg2,\n        arg3\n      )\n\n  On the other hand, function calls without parens are always indented\n  by the function call length itself, like this:\n\n      some_call arg1,\n                arg2,\n                arg3\n\n  If the last argument is a data structure, such as maps and lists, and\n  the beginning of the data structure fits on the same line as the function\n  call, then no indentation happens, this allows code like this:\n\n      Enum.reduce(some_collection, initial_value, fn element, acc ->\n        # code\n      end)\n\n      some_function_without_parens %{\n        foo: :bar,\n        baz: :bat\n      }\n\n  ## Code comments\n\n  The formatter handles code comments and guarantees a space is always added\n  between the beginning of the comment (#) and the next character.\n\n  The formatter also extracts all trailing comments to their previous line.\n  For example, the code below\n\n      hello #world\n\n  will be rewritten to\n\n      # world\n      hello\n\n  While the formatter attempts to preserve comments in most situations,\n  that's not always possible, because code comments are handled apart from\n  the code representation (AST). While the formatter can preserve code\n  comments between expressions and function arguments, the formatter\n  cannot currently preserve them around operators. For example, the following\n  code:\n\n      foo() ||\n        # also check for bar\n        bar()\n\n  will move the code comments to before the operator usage:\n\n      # also check for bar\n      foo() ||\n        bar()\n\n  In some situations, code comments can be seen as ambiguous by the formatter.\n  For example, the comment in the anonymous function below\n\n      fn\n        arg1 ->\n          body1\n          # comment\n\n        arg2 ->\n          body2\n      end\n\n  and in this one\n\n      fn\n        arg1 ->\n          body1\n\n        # comment\n        arg2 ->\n          body2\n      end\n\n  are considered equivalent (the nesting is discarded alongside most of\n  user formatting). In such cases, the code formatter will always format to\n  the latter.\n\n  ## Newlines\n\n  The formatter converts all newlines in code from `\\r\\n` to `\\n`.\n\n  ## Migration formatting\n\n  As part of the Elixir release cycle, deprecations are being introduced,\n  emitting warnings which might require existing code to be changed.\n  In order to reduce the burden on developers when upgrading Elixir to the\n  next version, the formatter exposes some options, disabled by default,\n  in order to automate this process.\n\n  These options should address most of the typical use cases, but given they\n  introduce changes to the AST, there is a non-zero risk for meta-programming\n  heavy projects that relied on a specific AST, or projects that are\n  re-defining functions from the `Kernel`. In such cases, migrations cannot\n  be applied blindly and some extra changes might be needed in order to\n  address the deprecation warnings.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec format_string!(binary, [format_opt]) :: iodata\n  def format_string!(string, opts \\\\ []) when is_binary(string) and is_list(opts) do\n    {line_length, opts} = Keyword.pop(opts, :line_length, 98)\n\n    to_quoted_opts =\n      [\n        unescape: false,\n        literal_encoder: &{:ok, {:__block__, &2, [&1]}},\n        token_metadata: true,\n        emit_warnings: false\n      ] ++ opts\n\n    {forms, comments} = string_to_quoted_with_comments!(string, to_quoted_opts)\n    to_algebra_opts = [comments: comments] ++ opts\n    doc = Code.Formatter.to_algebra(forms, to_algebra_opts)\n    Inspect.Algebra.format(doc, line_length)\n  end\n\n  @doc \"\"\"\n  Formats a file.\n\n  See `format_string!/2` for more information on code formatting and\n  available options.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec format_file!(binary, [format_opt]) :: iodata\n  def format_file!(file, opts \\\\ []) when is_binary(file) and is_list(opts) do\n    string = File.read!(file)\n    formatted = format_string!(string, [file: file, line: 1] ++ opts)\n    [formatted, ?\\n]\n  end\n\n  @doc \"\"\"\n  Evaluates the quoted contents.\n\n  **Warning**: Calling this function inside a macro is considered bad\n  practice as it will attempt to evaluate runtime values at compile time.\n  Macro arguments are typically transformed by unquoting them into the\n  returned quoted expressions (instead of evaluated).\n\n  See `eval_string/3` for a description of arguments and return types.\n  It accepts the same options as both `env_for_eval/1` and\n  `eval_quoted_with_env/4`.\n\n  ## Examples\n\n      iex> contents = quote(do: var!(a) + var!(b))\n      iex> {result, binding} = Code.eval_quoted(contents, [a: 1, b: 2], file: __ENV__.file, line: __ENV__.line)\n      iex> result\n      3\n      iex> Enum.sort(binding)\n      [a: 1, b: 2]\n\n  For convenience, you can pass `__ENV__/0` as the `opts` argument and\n  all options will be automatically extracted from the current environment:\n\n      iex> contents = quote(do: var!(a) + var!(b))\n      iex> {result, binding} = Code.eval_quoted(contents, [a: 1, b: 2], __ENV__)\n      iex> result\n      3\n      iex> Enum.sort(binding)\n      [a: 1, b: 2]\n\n  \"\"\"\n  @spec eval_quoted(Macro.t(), binding, Macro.Env.t() | [eval_opt | env_eval_opt]) ::\n          {term, binding}\n  def eval_quoted(quoted, binding \\\\ [], env_or_opts \\\\ [])\n\n  def eval_quoted(quoted, binding, %Macro.Env{} = env) do\n    eval_quoted(quoted, validate_binding(binding), env_for_eval(env), [])\n  end\n\n  def eval_quoted(quoted, binding, opts) when is_list(opts) do\n    eval_quoted(quoted, validate_binding(binding), env_for_eval(opts), opts)\n  end\n\n  defp eval_quoted(quoted, binding, env, opts) do\n    {value, binding, _env} = eval_verify(:eval_quoted, [quoted, binding, env, opts])\n    {value, binding}\n  end\n\n  @doc \"\"\"\n  Returns an environment for evaluation.\n\n  It accepts either a `Macro.Env`, that is then pruned and prepared,\n  or a list of options. It returns an environment that is ready for\n  evaluation.\n\n  Most functions in this module will automatically prepare the given\n  environment for evaluation, so you don't need to explicitly call\n  this function, with the exception of `eval_quoted_with_env/3`,\n  which was designed precisely to be called in a loop, to implement\n  features such as interactive shells or anything else with multiple\n  evaluations.\n\n  ## Options\n\n  If an env is not given, the options can be:\n\n    * `:file` - the file to be considered in the evaluation\n\n    * `:line` - the line on which the script starts\n\n    * `:module` - the module to run the environment on\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec env_for_eval(Macro.Env.t() | [env_eval_opt]) :: Macro.Env.t()\n  def env_for_eval(env_or_opts), do: :elixir.env_for_eval(env_or_opts)\n\n  @doc \"\"\"\n  Evaluates the given `quoted` contents with `binding` and `env`.\n\n  This function is meant to be called in a loop, to implement features\n  such as interactive shells or anything else with multiple evaluations.\n  Therefore, the first time you call this function, you must compute\n  the initial environment with `env_for_eval/1`. The remaining calls\n  must pass the environment that was returned by this function.\n\n  ## Options\n\n    * `:prune_binding` - (since v1.14.2) prune binding to keep only\n      variables read or written by the evaluated code. Note that\n      variables used by modules are always pruned, even if later used\n      by the modules. You can submit to the `:on_module` tracer event\n      and access the variables used by the module from its environment.\n\n    * `:dbg_callback` - (since v1.20.0) overrides the behaviour of `dbg/2`\n      used in the evaluated code. It must be a `{module, function, args}`\n      tuple, see `dbg/2` for more details.\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec eval_quoted_with_env(Macro.t(), binding, Macro.Env.t(), [eval_opt]) ::\n          {term, binding, Macro.Env.t()}\n  def eval_quoted_with_env(quoted, binding, %Macro.Env{} = env, opts \\\\ [])\n      when is_list(binding) do\n    eval_verify(:eval_quoted, [quoted, binding, env, opts])\n  end\n\n  @doc ~S\"\"\"\n  Converts the given string to its quoted form.\n\n  Returns `{:ok, quoted_form}` if it succeeds,\n  `{:error, {meta, message_info, token}}` otherwise.\n\n  ## Options\n\n    * `:file` - the filename to be reported in case of parsing errors.\n      Defaults to `\"nofile\"`.\n\n    * `:line` - the starting line of the string being parsed.\n      Defaults to `1`.\n\n    * `:column` - (since v1.11.0) the starting column of the string being parsed.\n      Defaults to `1`.\n\n    * `:indentation` - (since v1.19.0) the indentation for the string being parsed.\n      This is useful when the code parsed is embedded within another document.\n      Defaults to `0`.\n\n    * `:columns` - when `true`, attach a `:column` key to the quoted\n      metadata. Defaults to `false`.\n\n    * `:unescape` (since v1.10.0) - when `false`, preserves escaped sequences.\n      For example, `\"null byte\\\\t\\\\x00\"` will be kept as is instead of being\n      converted to a bitstring literal. Note if you set this option to false, the\n      resulting AST is no longer valid, but it can be useful to analyze/transform\n      source code, typically in combination with `quoted_to_algebra/2`.\n      Defaults to `true`.\n\n    * `:existing_atoms_only` - when `true`, raises an error\n      when non-existing atoms are found by the tokenizer.\n      Defaults to `false`.\n\n    * `:token_metadata` (since v1.10.0) - when `true`, includes token-related\n      metadata in the expression AST, such as metadata for `do` and `end`\n      tokens, for closing tokens, end of expressions, as well as delimiters\n      for sigils. See `t:Macro.metadata/0`. Defaults to `false`.\n\n    * `:literal_encoder` (since v1.10.0) - how to encode literals in the AST.\n      It must be a function that receives two arguments, the literal and its\n      metadata, and it must return `{:ok, ast :: Macro.t}` or\n      `{:error, reason :: binary}`. If you return anything than the literal\n      itself as the `term`, then the AST is no longer valid. This option\n      may still useful for textual analysis of the source code.\n\n    * `:static_atoms_encoder` - the static atom encoder function, see\n      \"The `:static_atoms_encoder` function\" section below. Note this\n      option overrides the `:existing_atoms_only` behavior for static\n      atoms but `:existing_atoms_only` is still used for dynamic atoms,\n      such as atoms with interpolations.\n\n    * `:emit_warnings` (since v1.16.0) - when `false`, does not emit\n      tokenizing/parsing related warnings. Defaults to `true`.\n\n  ## `Macro.to_string/2`\n\n  The opposite of converting a string to its quoted form is\n  `Macro.to_string/2`, which converts a quoted form to a string/binary\n  representation.\n\n  ## The `:static_atoms_encoder` function\n\n  When `static_atoms_encoder: &my_encoder/2` is passed as an argument,\n  `my_encoder/2` is called every time the tokenizer needs to create a\n  \"static\" atom. Static atoms are atoms in the AST that function as\n  aliases, remote calls, local calls, variable names, regular atoms\n  and keyword lists.\n\n  The encoder function will receive the atom name (as a binary) and a\n  keyword list with the current file, line and column. It must return\n  `{:ok, token :: term} | {:error, reason :: binary}`.\n\n  The encoder function is supposed to create an atom from the given\n  string. To produce a valid AST, it is required to return `{:ok, term}`,\n  where `term` is an atom. It is possible to return something other than an atom,\n  however, in that case the AST is no longer \"valid\" in that it cannot\n  be used to compile or evaluate Elixir code. A use case for this is\n  if you want to use the Elixir parser in a user-facing situation, but\n  you don't want to exhaust the atom table.\n\n  The atom encoder is not called for *all* atoms that are present in\n  the AST. It won't be invoked for the following atoms:\n\n    * operators (`:+`, `:-`, and so on)\n\n    * syntax keywords (`fn`, `do`, `else`, and so on)\n\n    * atoms containing interpolation (`:\"#{1 + 1} is two\"`), as these\n      atoms are constructed at runtime\n\n    * atoms used to represent single-letter sigils like `:sigil_X`\n      (but multi-letter sigils like `:sigil_XYZ` are encoded).\n\n  ## Examples\n\n      iex> Code.string_to_quoted(\"1 + 3\")\n      {:ok, {:+, [line: 1], [1, 3]}}\n\n      iex> Code.string_to_quoted(\"1 \\ 3\")\n      {:error, {[line: 1, column: 4], \"syntax error before: \", \"\\\"3\\\"\"}}\n\n  \"\"\"\n  @spec string_to_quoted(List.Chars.t(), parser_opts) ::\n          {:ok, Macro.t()} | {:error, {location :: keyword, binary | {binary, binary}, binary}}\n  def string_to_quoted(string, opts \\\\ []) when is_list(opts) do\n    file = Keyword.get(opts, :file, \"nofile\")\n    line = Keyword.get(opts, :line, 1)\n    column = Keyword.get(opts, :column, 1)\n    :elixir.string_to_quoted(to_charlist(string), line, column, file, opts)\n  end\n\n  @doc \"\"\"\n  Converts the given string to its quoted form.\n\n  It returns the AST if it succeeds,\n  raises an exception otherwise. The exception is a `TokenMissingError`\n  in case a token is missing (usually because the expression is incomplete),\n  `MismatchedDelimiterError` (in case of mismatched opening and closing delimiters) and\n  `SyntaxError` otherwise.\n\n  Check `string_to_quoted/2` for options information.\n  \"\"\"\n  @spec string_to_quoted!(List.Chars.t(), parser_opts) :: Macro.t()\n  def string_to_quoted!(string, opts \\\\ []) when is_list(opts) do\n    file = Keyword.get(opts, :file, \"nofile\")\n    line = Keyword.get(opts, :line, 1)\n    column = Keyword.get(opts, :column, 1)\n    :elixir.string_to_quoted!(to_charlist(string), line, column, file, opts)\n  end\n\n  @doc \"\"\"\n  Converts the given string to its quoted form and a list of comments.\n\n  This function is useful when performing textual changes to the source code,\n  while preserving information like comments and literals position.\n\n  Returns `{:ok, quoted_form, comments}` if it succeeds,\n  `{:error, {line, error, token}}` otherwise.\n\n  Comments are maps with the following fields:\n\n    * `:line` - The line number of the source code\n\n    * `:text` - The full text of the comment, including the leading `#`\n\n    * `:previous_eol_count` - How many end of lines there are between the comment and the previous AST node or comment\n\n    * `:next_eol_count` - How many end of lines there are between the comment and the next AST node or comment\n\n  Check `string_to_quoted/2` for options information.\n\n  ## Examples\n\n      iex> Code.string_to_quoted_with_comments(\"\\\"\"\n      ...> :foo\n      ...>\n      ...> # Hello, world!\n      ...>\n      ...>\n      ...> # Some more comments!\n      ...> \"\\\"\")\n      {:ok, :foo, [\n        %{line: 3, column: 1, previous_eol_count: 2, next_eol_count: 3, text: \"\\# Hello, world!\"},\n        %{line: 6, column: 1, previous_eol_count: 3, next_eol_count: 1, text: \"\\# Some more comments!\"},\n      ]}\n\n      iex> Code.string_to_quoted_with_comments(\":foo # :bar\")\n      {:ok, :foo, [\n        %{line: 1, column: 6, previous_eol_count: 0, next_eol_count: 0, text: \"\\# :bar\"}\n      ]}\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec string_to_quoted_with_comments(List.Chars.t(), parser_opts) ::\n          {:ok, Macro.t(), list(map())} | {:error, {location :: keyword, term, term}}\n  def string_to_quoted_with_comments(string, opts \\\\ []) when is_list(opts) do\n    charlist = to_charlist(string)\n    file = Keyword.get(opts, :file, \"nofile\")\n    line = Keyword.get(opts, :line, 1)\n    column = Keyword.get(opts, :column, 1)\n\n    Process.put(:code_formatter_comments, [])\n    opts = [preserve_comments: &preserve_comments/5] ++ opts\n\n    with {:ok, forms} <- :elixir.string_to_quoted(charlist, line, column, file, opts) do\n      comments = Enum.reverse(Process.get(:code_formatter_comments))\n      {:ok, forms, comments}\n    end\n  after\n    Process.delete(:code_formatter_comments)\n  end\n\n  @doc \"\"\"\n  Converts the given string to its quoted form and a list of comments.\n\n  Returns the AST and a list of comments if it succeeds, raises an exception\n  otherwise. The exception is a `TokenMissingError` in case a token is missing\n  (usually because the expression is incomplete), `SyntaxError` otherwise.\n\n  Check `string_to_quoted/2` for options information.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec string_to_quoted_with_comments!(List.Chars.t(), parser_opts) :: {Macro.t(), list(map())}\n  def string_to_quoted_with_comments!(string, opts \\\\ []) do\n    charlist = to_charlist(string)\n\n    case string_to_quoted_with_comments(charlist, opts) do\n      {:ok, forms, comments} ->\n        {forms, comments}\n\n      {:error, {location, error, token}} ->\n        file = Keyword.get(opts, :file, \"nofile\")\n        line = Keyword.get(opts, :line, 1)\n        column = Keyword.get(opts, :column, 1)\n        input = {charlist, line, column, Keyword.get(opts, :indentation, 0)}\n        :elixir_errors.parse_error(location, file, error, token, input)\n    end\n  end\n\n  defp preserve_comments(line, column, tokens, comment, rest) do\n    comments = Process.get(:code_formatter_comments)\n\n    comment = %{\n      line: line,\n      column: column,\n      previous_eol_count: min(previous_eol_count(tokens), last_comment_distance(comments, line)),\n      next_eol_count: next_eol_count(rest, 0),\n      text: List.to_string(comment)\n    }\n\n    Process.put(:code_formatter_comments, [comment | comments])\n  end\n\n  defp next_eol_count([?\\s | rest], count), do: next_eol_count(rest, count)\n  defp next_eol_count([?\\t | rest], count), do: next_eol_count(rest, count)\n  defp next_eol_count([?\\n | rest], count), do: next_eol_count(rest, count + 1)\n  defp next_eol_count([?\\r, ?\\n | rest], count), do: next_eol_count(rest, count + 1)\n  defp next_eol_count(_, count), do: count\n\n  defp last_comment_distance([%{line: last_line} | _], line), do: line - last_line\n  defp last_comment_distance([], _line), do: :infinity\n\n  defp previous_eol_count([{token, {_, _, count}} | _])\n       when token in [:eol, :\",\", :\";\"] and count > 0 do\n    count\n  end\n\n  defp previous_eol_count([]), do: 1\n  defp previous_eol_count(_), do: 0\n\n  @doc ~S\"\"\"\n  Converts a quoted expression to an algebra document using Elixir's formatter rules.\n\n  The algebra document can be converted into a string by calling:\n\n      doc\n      |> Inspect.Algebra.format(:infinity)\n      |> IO.iodata_to_binary()\n\n  For a high-level function that does the same, see `Macro.to_string/1`.\n\n  ## Formatting considerations\n\n  The Elixir AST does not contain metadata for literals like strings, lists, or\n  tuples with two elements, which means that the produced algebra document will\n  not respect all of the user preferences and comments may be misplaced.\n  To get better results, you can use the `:token_metadata`, `:unescape` and\n  `:literal_encoder` options to `string_to_quoted/2` to provide additional\n  information to the formatter:\n\n      [\n        literal_encoder: &{:ok, {:__block__, &2, [&1]}},\n        token_metadata: true,\n        unescape: false\n      ]\n\n  This will produce an AST that contains information such as `do` blocks start\n  and end lines or sigil delimiters, and by wrapping literals in blocks they can\n  now hold metadata like line number, string delimiter and escaped sequences, or\n  integer formatting (such as `0x2a` instead of `47`). However, **note this AST is\n  not valid**. If you evaluate it, it won't have the same semantics as the regular\n  Elixir AST due to the `:unescape` and `:literal_encoder` options. However,\n  those options are useful if you're doing source code manipulation, where it's\n  important to preserve user choices and comments placing.\n\n  ## Options\n\n  This function accepts all options supported by `format_string!/2` for controlling\n  code formatting, plus these additional options:\n\n    * `:comments` - the list of comments associated with the quoted expression.\n      Defaults to `[]`. It is recommended that both `:token_metadata` and\n      `:literal_encoder` options are given to `string_to_quoted_with_comments/2`\n      in order to get proper placement for comments\n\n    * `:escape` - when `true`, escaped sequences like `\\n` will be escaped into\n      `\\\\n`. If the `:unescape` option was set to `false` when using\n      `string_to_quoted/2`, setting this option to `false` will prevent it from\n      escaping the sequences twice. Defaults to `true`.\n\n  See `format_string!/2` for the full list of formatting options including\n  `:file`, `:line`, `:line_length`, `:locals_without_parens`, `:force_do_end_blocks`,\n  `:syntax_colors`, and all migration options like `:migrate_charlists_as_sigils`.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec quoted_to_algebra(Macro.t(), [format_opt() | quoted_to_algebra_opt()]) ::\n          Inspect.Algebra.t()\n  def quoted_to_algebra(quoted, opts \\\\ []) do\n    quoted\n    |> Code.Normalizer.normalize(opts)\n    |> Code.Formatter.to_algebra(opts)\n  end\n\n  @doc \"\"\"\n  Evaluates the given file.\n\n  Accepts `relative_to` as an argument to tell where the file is located.\n\n  While `require_file/2` and `compile_file/2` return the loaded modules and their\n  bytecode, `eval_file/2` simply evaluates the file contents and returns the\n  evaluation result and its binding (exactly the same return value as `eval_string/3`).\n  \"\"\"\n  @spec eval_file(binary, nil | binary) :: {term, binding}\n  def eval_file(file, relative_to \\\\ nil) when is_binary(file) do\n    {charlist, file} = find_file!(file, relative_to)\n    eval_string(charlist, [], file: file, line: 1)\n  end\n\n  @deprecated \"Use Code.require_file/2 or Code.compile_file/2 instead\"\n  @doc false\n  def load_file(file, relative_to \\\\ nil) when is_binary(file) do\n    {charlist, file} = find_file!(file, relative_to)\n    :elixir_code_server.call({:acquire, file})\n\n    loaded =\n      Module.ParallelChecker.verify(fn ->\n        :elixir_compiler.string(charlist, file, fn _, _ -> :ok end)\n      end)\n\n    :elixir_code_server.cast({:required, file})\n    loaded\n  end\n\n  @doc \"\"\"\n  Requires the given `file`.\n\n  Accepts `relative_to` as an argument to tell where the file is located.\n  If the file was already required, `require_file/2` doesn't do anything and\n  returns `nil`.\n\n  Note that if `require_file/2` is invoked by different processes concurrently,\n  the first process to invoke `require_file/2` acquires a lock and the remaining\n  ones will block until the file is available. This means that if `require_file/2`\n  is called more than once with a given file, that file will be compiled only once.\n  The first process to call `require_file/2` will get the list of loaded modules,\n  others will get `nil`. The list of required files is managed per Erlang VM node.\n\n  See `compile_file/2` if you would like to compile a file without tracking its\n  filenames. Finally, if you would like to get the result of evaluating a file rather\n  than the modules defined in it, see `eval_file/2`.\n\n  ## Examples\n\n  If the file has not been required, it returns the list of modules:\n\n      modules = Code.require_file(\"eex_test.exs\", \"../eex/test\")\n      List.first(modules)\n      #=> {EExTest.Compiled, <<70, 79, 82, 49, ...>>}\n\n  If the file has been required, it returns `nil`:\n\n      Code.require_file(\"eex_test.exs\", \"../eex/test\")\n      #=> nil\n\n  \"\"\"\n  @spec require_file(binary, nil | binary) :: [{module, binary}] | nil\n  def require_file(file, relative_to \\\\ nil) when is_binary(file) do\n    {charlist, file} = find_file!(file, relative_to)\n\n    case :elixir_code_server.call({:acquire, file}) do\n      :required ->\n        nil\n\n      :proceed ->\n        loaded =\n          Module.ParallelChecker.verify(fn ->\n            :elixir_compiler.string(charlist, file, fn _, _ -> :ok end)\n          end)\n\n        :elixir_code_server.cast({:required, file})\n        loaded\n    end\n  end\n\n  @doc \"\"\"\n  Gets all compilation options from the code server.\n\n  To get individual options, see `get_compiler_option/1`.\n  For a description of all options, see `put_compiler_option/2`.\n\n  ## Examples\n\n      Code.compiler_options()\n      #=> %{debug_info: true, docs: true, ...}\n\n  \"\"\"\n  @spec compiler_options :: map\n  def compiler_options do\n    for key <- @available_compiler_options, into: %{} do\n      {key, :elixir_config.get(key)}\n    end\n  end\n\n  @doc \"\"\"\n  Stores all given compilation options.\n\n  Changing the compilation options affect all processes\n  running in a given Erlang VM node. To store individual\n  options and for a description of all options, see\n  `put_compiler_option/2`.\n\n  Returns a map with previous values.\n\n  ## Examples\n\n      Code.compiler_options(infer_signatures: false)\n      #=> %{infer_signatures: [:elixir]}\n\n  \"\"\"\n  @spec compiler_options(Enumerable.t({atom, term})) :: %{optional(atom) => term}\n  def compiler_options(opts) do\n    for {key, value} <- opts, into: %{} do\n      previous = get_compiler_option(key)\n      put_compiler_option(key, value)\n      {key, previous}\n    end\n  end\n\n  @doc \"\"\"\n  Returns the value of a given compiler option.\n\n  For a description of all options, see `put_compiler_option/2`.\n\n  ## Examples\n\n      Code.get_compiler_option(:debug_info)\n      #=> true\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec get_compiler_option(atom) :: term\n  def get_compiler_option(key) when key in @available_compiler_options do\n    :elixir_config.get(key)\n  end\n\n  # TODO: Remove me in Elixir v2.0\n  def get_compiler_option(:warnings_as_errors) do\n    IO.warn(\":warnings_as_errors is deprecated as part of Code.get_compiler_option/1\")\n    :ok\n  end\n\n  @doc \"\"\"\n  Returns a list with all available compiler options.\n\n  For a description of all options, see `put_compiler_option/2`.\n\n  ## Examples\n\n      Code.available_compiler_options()\n      #=> [:docs, :debug_info, ...]\n\n  \"\"\"\n  @spec available_compiler_options() :: [atom]\n  def available_compiler_options do\n    @available_compiler_options\n  end\n\n  @doc \"\"\"\n  Stores a compilation option.\n\n  Changing the compilation options affect all processes running in a\n  given Erlang VM node.\n\n  Available options are:\n\n    * `:debug_info` - when `true`, retains debug information in the compiled\n      module. This option can also be overridden per module using the `@compile`\n      directive. Defaults to `true`.\n\n      This enables tooling to partially reconstruct the original source code,\n      for instance, to perform static analysis of code. Therefore, disabling\n      `:debug_info` is not recommended as it removes the ability of the\n      Elixir compiler and other tools to provide feedback. If you want to\n      remove the `:debug_info` while deploying, tools like `mix release`\n      already do such by default.\n\n      Other environments, such as `mix test`, automatically disables this\n      via the `:test_elixirc_options` project configuration, as there is\n      typically no need to store debug chunks for test files.\n\n    * `:docs` - when `true`, retains documentation in the compiled module.\n      Defaults to `true`.\n\n    * `:ignore_already_consolidated` (since v1.10.0) - when `true`, does not warn\n      when a protocol has already been consolidated and a new implementation is added.\n      Defaults to `false`.\n\n    * `:ignore_module_conflict` - when `true`, does not warn when a module has\n      already been defined. Defaults to `false`.\n\n    * `:infer_signatures` (since v1.18.0) - a list of applications of which modules\n      should be using during type inference. When `false`, it disables module-local\n      signature inference used when type checking remote calls to the compiled\n      module. Type checking will be executed regardless of the value of this option.\n      Defaults to `true`, which is equivalent to setting it to `[:elixir]` only.\n\n      When setting this option, we recommend running `mix clean` so the modules can be\n      recompiled with the new behaviour. `mix test` automatically disables this option\n      via the `:test_elixirc_options` project configuration, as there is typically no\n      need to infer signatures for test files.\n\n    * `:module_definition` (since v1.20.0) - stores if the module definition should\n      be `:compiled` (the default) or `:interpreted`. Note this does not affect the\n      `.beam` file written to disk, only how the contents inside `defmodule` are\n      executed. Using the `:interpreted` mode may offer better compilation times for\n      large projects, especially on machines with high core count, however, it comes\n      with some downsides:\n\n      * Errors during compilation may have less precise stacktraces\n\n      * Anonymous functions within `defmodule` can have only up to 20 arguments.\n        If this is an issue, you can use maps or tuples to group the data.\n        Note the functions themselves inside `defmodule`, such as the ones defined\n        inside `def` and friends, can still have up to 255 arguments\n\n    * `:no_warn_undefined` (since v1.10.0) - list of modules and `{Mod, fun, arity}`\n      tuples that will not emit warnings that the module or function does not exist\n      at compilation time. Pass atom `:all` to skip warning for all undefined\n      functions. This can be useful when doing dynamic compilation. Defaults to `[]`.\n\n    * `:on_undefined_variable` (since v1.15.0) - either `:raise` or `:warn`.\n      When `:raise` (the default), undefined variables will trigger a compilation\n      error. You may be set it to `:warn` if you want undefined variables to\n      emit a warning and expand as to a local call to the zero-arity function\n      of the same name (for example, `node` would be expanded as `node()`).\n      This `:warn` behavior only exists for compatibility reasons when working\n      with old dependencies, its usage is discouraged and it will be removed\n      in future releases.\n\n    * `:parser_options` (since v1.10.0) - a keyword list of options to be given\n      to the parser when compiling files. It accepts the same options as\n      `string_to_quoted/2` (except by the options that change the AST itself).\n      This can be used in combination with the tracer to retrieve localized\n      information about events happening during compilation. Defaults to `[columns: true]`.\n      This option only affects code compilation functions, such as `compile_string/2`\n      and `compile_file/2` but not `string_to_quoted/2` and friends, as the\n      latter is used for other purposes beyond compilation.\n\n    * `:relative_paths` - when `true`, uses relative paths in quoted nodes,\n      warnings, and errors generated by the compiler. Note disabling this option\n      won't affect runtime warnings and errors. Defaults to `true`.\n\n    * `:tracers` (since v1.10.0) - a list of tracers (modules) to be used during\n      compilation. See the module docs for more information. Defaults to `[]`.\n\n  It always returns `:ok`. Raises an error for invalid options.\n\n  ## Examples\n\n      Code.put_compiler_option(:debug_info, true)\n      #=> :ok\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec put_compiler_option(atom, term) :: :ok\n  def put_compiler_option(key, value) when key in @boolean_compiler_options do\n    if not is_boolean(value) do\n      raise \"compiler option #{inspect(key)} should be a boolean, got: #{inspect(value)}\"\n    end\n\n    :elixir_config.put(key, value)\n    :ok\n  end\n\n  def put_compiler_option(key, value) when key in @list_compiler_options do\n    if not is_list(value) do\n      raise \"compiler option #{inspect(key)} should be a list, got: #{inspect(value)}\"\n    end\n\n    if key == :parser_options and not Keyword.keyword?(value) do\n      raise \"compiler option #{inspect(key)} should be a keyword list, \" <>\n              \"got: #{inspect(value)}\"\n    end\n\n    if key == :tracers and not Enum.all?(value, &is_atom/1) do\n      raise \"compiler option #{inspect(key)} should be a list of modules, \" <>\n              \"got: #{inspect(value)}\"\n    end\n\n    :elixir_config.put(key, value)\n    :ok\n  end\n\n  def put_compiler_option(:module_definition, value) do\n    if value not in [:interpreted, :compiled] do\n      raise \"compiler option :module_definition should be either :interpreted or :compiled, got: #{inspect(value)}\"\n    end\n\n    :elixir_config.put(:module_definition, value)\n    :ok\n  end\n\n  def put_compiler_option(:infer_signatures, value) do\n    value =\n      cond do\n        value == false ->\n          false\n\n        value == true ->\n          [:elixir]\n\n        is_list(value) and Enum.all?(value, &is_atom/1) ->\n          value\n\n        true ->\n          raise \"compiler option :infer_signatures should be a boolean or a list of applications, got: #{inspect(value)}\"\n      end\n\n    :elixir_config.put(:infer_signatures, value)\n    :ok\n  end\n\n  def put_compiler_option(:no_warn_undefined, value) do\n    if value != :all and not is_list(value) do\n      raise \"compiler option :no_warn_undefined should be a list or the atom :all, \" <>\n              \"got: #{inspect(value)}\"\n    end\n\n    :elixir_config.put(:no_warn_undefined, value)\n    :ok\n  end\n\n  # TODO: Remove me in Elixir v2.0\n  def put_compiler_option(:warnings_as_errors, _value) do\n    IO.warn(\n      \":warnings_as_errors is deprecated as part of Code.put_compiler_option/2, \" <>\n        \"instead you must pass it as a --warnings-as-errors flag. \" <>\n        \"If you need to set it as a default in a mix task, you can also set it under aliases: \" <>\n        \"[compile: \\\"compile --warnings-as-errors\\\"]\"\n    )\n\n    :ok\n  end\n\n  # TODO: Remove me in Elixir v2.0\n  def put_compiler_option(:on_undefined_variable, value) when value in [:raise, :warn] do\n    if value == :warn do\n      IO.warn_once(\n        {__MODULE__, :on_undefined_variable},\n        fn ->\n          \"setting :on_undefined_variable to :warn is deprecated. \" <>\n            \"The warning behaviour will be removed in future releases\"\n        end,\n        3\n      )\n    end\n\n    :elixir_config.put(:on_undefined_variable, value)\n    :ok\n  end\n\n  def put_compiler_option(key, _value) do\n    raise \"unknown compiler option: #{inspect(key)}\"\n  end\n\n  @doc \"\"\"\n  Purge compiler modules.\n\n  The compiler utilizes temporary modules to compile code. For example,\n  `elixir_compiler_1`, `elixir_compiler_2`, and so on. In case the compiled code\n  stores references to anonymous functions or similar, the Elixir compiler\n  may be unable to reclaim those modules, keeping an unnecessary amount of\n  code in memory and eventually leading to modules such as `elixir_compiler_12345`.\n\n  This function purges all modules currently kept by the compiler, allowing\n  old compiler module names to be reused. If there are any processes running\n  any code from such modules, they will be terminated too.\n\n  This function is only meant to be called if you have a long running node\n  that is constantly evaluating code.\n\n  It returns `{:ok, number_of_modules_purged}`.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec purge_compiler_modules() :: {:ok, non_neg_integer()}\n  def purge_compiler_modules() do\n    :elixir_code_server.call(:purge_compiler_modules)\n  end\n\n  @doc \"\"\"\n  Compiles the given string.\n\n  Returns a list of tuples where the first element is the module name\n  and the second one is its bytecode (as a binary). A `file` can be\n  given as a second argument which will be used for reporting warnings\n  and errors.\n\n  **Warning**: `string` can be any Elixir code and code can be executed with\n  the same privileges as the Erlang VM: this means that such code could\n  compromise the machine (for example by executing system commands).\n  Don't use `compile_string/2` with untrusted input (such as strings coming\n  from the network).\n  \"\"\"\n  @spec compile_string(List.Chars.t(), binary) :: [{module, binary}]\n  def compile_string(string, file \\\\ \"nofile\") when is_binary(file) do\n    Module.ParallelChecker.verify(fn ->\n      :elixir_compiler.string(to_charlist(string), file, fn _, _ -> :ok end)\n    end)\n  end\n\n  @doc \"\"\"\n  Compiles the quoted expression.\n\n  Returns a list of tuples where the first element is the module name and\n  the second one is its bytecode (as a binary). A `file` can be\n  given as second argument which will be used for reporting warnings\n  and errors.\n  \"\"\"\n  @spec compile_quoted(Macro.t(), binary) :: [{module, binary}]\n  def compile_quoted(quoted, file \\\\ \"nofile\") when is_binary(file) do\n    Module.ParallelChecker.verify(fn ->\n      :elixir_compiler.quoted(quoted, file, fn _, _ -> :ok end)\n    end)\n  end\n\n  @doc \"\"\"\n  Compiles the given file.\n\n  Accepts `relative_to` as an argument to tell where the file is located.\n\n  Returns a list of tuples where the first element is the module name and\n  the second one is its bytecode (as a binary). Opposite to `require_file/2`,\n  it does not track the filename of the compiled file.\n\n  If you would like to get the result of evaluating file rather than the\n  modules defined in it, see `eval_file/2`.\n\n  For compiling many files concurrently, see `Kernel.ParallelCompiler.compile/2`.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec compile_file(binary, nil | binary) :: [{module, binary}]\n  def compile_file(file, relative_to \\\\ nil) when is_binary(file) do\n    Module.ParallelChecker.verify(fn ->\n      {charlist, file} = find_file!(file, relative_to)\n      :elixir_compiler.string(charlist, file, fn _, _ -> :ok end)\n    end)\n  end\n\n  @doc \"\"\"\n  Ensures the given module is loaded.\n\n  If the module is already loaded, this works as no-op. If the module\n  was not yet loaded, it tries to load it.\n\n  If it succeeds in loading the module, it returns `{:module, module}`.\n  If not, returns `{:error, reason}` with the error reason.\n\n  See the module documentation for more information on code loading.\n\n  ## Examples\n\n      iex> Code.ensure_loaded(Atom)\n      {:module, Atom}\n\n      iex> Code.ensure_loaded(DoesNotExist)\n      {:error, :nofile}\n\n  \"\"\"\n  @spec ensure_loaded(module) ::\n          {:module, module} | {:error, :embedded | :badfile | :nofile | :on_load_failure}\n  def ensure_loaded(module) when is_atom(module) do\n    :code.ensure_loaded(module)\n  end\n\n  @doc \"\"\"\n  Ensures the given module is loaded.\n\n  Similar to `ensure_loaded/1`, but returns `true` if the module\n  is already loaded or was successfully loaded. Returns `false`\n  otherwise.\n\n  ## Examples\n\n      iex> Code.ensure_loaded?(String)\n      true\n\n  \"\"\"\n  @spec ensure_loaded?(module) :: boolean\n  def ensure_loaded?(module) when is_atom(module) do\n    match?({:module, ^module}, ensure_loaded(module))\n  end\n\n  @doc \"\"\"\n  Same as `ensure_loaded/1` but raises if the module cannot be loaded.\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec ensure_loaded!(module) :: module\n  def ensure_loaded!(module) do\n    case ensure_loaded(module) do\n      {:module, module} ->\n        module\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"could not load module #{inspect(module)} due to reason #{inspect(reason)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Ensures the given modules are loaded.\n\n  Similar to `ensure_loaded/1`, but accepts a list of modules instead of a single\n  module, and loads all of them.\n\n  If all modules load successfully, returns `:ok`. Otherwise, returns `{:error, errors}`\n  where `errors` is a list of tuples made of the module and the reason it failed to load.\n\n  ## Examples\n\n      iex> Code.ensure_all_loaded([Atom, String])\n      :ok\n\n      iex> Code.ensure_all_loaded([Atom, DoesNotExist])\n      {:error, [{DoesNotExist, :nofile}]}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec ensure_all_loaded([module]) :: :ok | {:error, [{module, reason}]}\n        when reason: :badfile | :nofile | :on_load_failure\n  def ensure_all_loaded(modules) when is_list(modules) do\n    :code.ensure_modules_loaded(modules)\n  end\n\n  @doc \"\"\"\n  Same as `ensure_all_loaded/1` but raises if any of the modules cannot be loaded.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec ensure_all_loaded!([module]) :: :ok\n  def ensure_all_loaded!(modules) do\n    case ensure_all_loaded(modules) do\n      :ok ->\n        :ok\n\n      {:error, errors} ->\n        formatted_errors =\n          errors\n          |> Enum.sort()\n          |> Enum.map_join(\"\\n\", fn {module, reason} ->\n            \"  * #{inspect(module)} due to reason #{inspect(reason)}\"\n          end)\n\n        raise ArgumentError, \"could not load the following modules:\\n\\n\" <> formatted_errors\n    end\n  end\n\n  @doc \"\"\"\n  Similar to `ensure_compiled!/1` but indicates you can continue without said module.\n\n  While `ensure_compiled!/1` indicates to the Elixir compiler you can\n  only continue when said module is available, this function indicates\n  you may continue compilation without said module.\n\n  If it succeeds in loading the module, it returns `{:module, module}`.\n  If not, returns `{:error, reason}` with the error reason.\n  If the module being checked is currently in a compiler deadlock,\n  this function returns `{:error, :unavailable}`. Unavailable doesn't\n  necessarily mean the module doesn't exist, just that it is not currently\n  available, but it (or may not) become available in the future.\n\n  Therefore, if you can only continue if the module is available, use\n  `ensure_compiled!/1` instead. In particular, do not do this:\n\n      case Code.ensure_compiled(module) do\n        {:module, _} -> module\n        {:error, _} -> raise ...\n      end\n\n  See the module documentation for more information on code loading.\n  \"\"\"\n  @spec ensure_compiled(module) ::\n          {:module, module}\n          | {:error, :embedded | :badfile | :nofile | :on_load_failure | :unavailable}\n  def ensure_compiled(module) when is_atom(module) do\n    ensure_compiled(module, :soft)\n  end\n\n  @doc \"\"\"\n  Ensures the given module is compiled and loaded.\n\n  If the module is already loaded, it works as no-op. If the module was\n  not compiled yet, `ensure_compiled!/1` halts the compilation of the caller\n  until the module given to `ensure_compiled!/1` becomes available or\n  all files for the current project have been compiled. If compilation\n  finishes and the module is not available or is in a deadlock, an error\n  is raised.\n\n  Given this function halts compilation, use it carefully. In particular,\n  avoid using it to guess which modules are in the system. Overuse of this\n  function can also lead to deadlocks, where two modules check at the same time\n  if the other is compiled. This returns a specific unavailable error code,\n  where we cannot successfully verify a module is available or not.\n\n  See the module documentation for more information on code loading.\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec ensure_compiled!(module) :: module\n  def ensure_compiled!(module) do\n    case ensure_compiled(module, :hard) do\n      {:module, module} ->\n        module\n\n      {:error, reason} ->\n        raise ArgumentError,\n              \"could not load module #{inspect(module)} due to reason #{inspect(reason)}\"\n    end\n  end\n\n  defp ensure_compiled(module, mode) do\n    case :code.ensure_loaded(module) do\n      {:error, :nofile} = error ->\n        if can_await_module_compilation?() do\n          case Kernel.ErrorHandler.ensure_compiled(module, :module, mode, nil) do\n            :found -> {:module, module}\n            :deadlock -> {:error, :unavailable}\n            :not_found -> {:error, :nofile}\n          end\n        else\n          error\n        end\n\n      other ->\n        other\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if the module is loaded.\n\n  This function doesn't attempt to load the module. For such behavior,\n  `ensure_loaded?/1` can be used.\n\n  ## Examples\n\n      iex> Code.loaded?(String)\n      true\n\n      iex> Code.loaded?(NotYetLoaded)\n      false\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec loaded?(module) :: boolean\n  def loaded?(module) do\n    :erlang.module_loaded(module)\n  end\n\n  @doc \"\"\"\n  Returns `true` if the current process can await for module compilation.\n\n  When compiling Elixir code via `Kernel.ParallelCompiler`, which is\n  used by Mix and `elixirc`, calling a module that has not yet been\n  compiled will block the caller until the module becomes available.\n  Executing Elixir scripts, such as passing a filename to `elixir`,\n  does not await.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec can_await_module_compilation? :: boolean\n  def can_await_module_compilation? do\n    :erlang.process_info(self(), :error_handler) == {:error_handler, Kernel.ErrorHandler}\n  end\n\n  @doc false\n  @deprecated \"Use Code.ensure_compiled/1 instead (see the proper disclaimers in its docs)\"\n  def ensure_compiled?(module) when is_atom(module) do\n    match?({:module, ^module}, ensure_compiled(module))\n  end\n\n  @doc ~S\"\"\"\n  Returns the docs for the given module or path to `.beam` file.\n\n  When given a module name, it finds its BEAM code and reads the docs from it.\n\n  When given a path to a `.beam` file, it will load the docs directly from that\n  file.\n\n  It returns the term stored in the documentation chunk in the format defined by\n  [EEP 48](https://www.erlang.org/eeps/eep-0048.html) or `{:error, reason}` if\n  the chunk is not available.\n\n  ## Examples\n\n      # Module documentation of an existing module\n      iex> {:docs_v1, _, :elixir, _, %{\"en\" => module_doc}, _, _} = Code.fetch_docs(Atom)\n      iex> module_doc |> String.split(\"\\n\") |> Enum.at(0)\n      \"Atoms are constants whose values are their own name.\"\n\n      # A module that doesn't exist\n      iex> Code.fetch_docs(ModuleNotGood)\n      {:error, :module_not_found}\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec fetch_docs(module | String.t()) ::\n          {:docs_v1, annotation, beam_language, format, module_doc :: doc_content, metadata,\n           docs :: [doc_element]}\n          | {:error,\n             :module_not_found\n             | :chunk_not_found\n             | {:invalid_chunk, binary}\n             | :invalid_beam}\n        when annotation: :erl_anno.anno(),\n             beam_language: :elixir | :erlang | atom(),\n             doc_content: %{optional(binary) => binary} | :none | :hidden,\n             doc_element:\n               {{kind :: atom, function_name :: atom, arity}, annotation, signature, doc_content,\n                metadata},\n             format: binary,\n             signature: [binary],\n             metadata: map\n  def fetch_docs(module_or_path)\n\n  def fetch_docs(module) when is_atom(module) do\n    case get_beam_and_path(module) do\n      {bin, beam_path} ->\n        case fetch_docs_from_beam(bin) do\n          {:error, :chunk_not_found} ->\n            app_root = Path.expand(Path.join([\"..\", \"..\"]), beam_path)\n            path = Path.join([app_root, \"doc\", \"chunks\", \"#{module}.chunk\"])\n            fetch_docs_from_chunk(path)\n\n          other ->\n            other\n        end\n\n      :error ->\n        case :code.is_loaded(module) do\n          {:file, :preloaded} ->\n            # The ERTS directory is not necessarily included in releases\n            # unless it is listed as an extra application.\n            case :code.lib_dir(:erts) do\n              path when is_list(path) ->\n                path = Path.join([path, \"doc\", \"chunks\", \"#{module}.chunk\"])\n                fetch_docs_from_chunk(path)\n\n              {:error, _} ->\n                {:error, :chunk_not_found}\n            end\n\n          _ ->\n            {:error, :module_not_found}\n        end\n    end\n  end\n\n  def fetch_docs(path) when is_binary(path) do\n    fetch_docs_from_beam(String.to_charlist(path))\n  end\n\n  defp get_beam_and_path(module) do\n    with {^module, beam, filename} <- :code.get_object_code(module),\n         info_pairs when is_list(info_pairs) <- :beam_lib.info(beam),\n         {:ok, ^module} <- Keyword.fetch(info_pairs, :module) do\n      {beam, filename}\n    else\n      _ -> :error\n    end\n  end\n\n  @docs_chunk [?D, ?o, ?c, ?s]\n\n  defp fetch_docs_from_beam(bin_or_path) do\n    case :beam_lib.chunks(bin_or_path, [@docs_chunk]) do\n      {:ok, {_module, [{@docs_chunk, bin}]}} ->\n        load_docs_chunk(bin)\n\n      {:error, :beam_lib, {:missing_chunk, _, @docs_chunk}} ->\n        {:error, :chunk_not_found}\n\n      {:error, :beam_lib, {:file_error, _, :enoent}} ->\n        {:error, :module_not_found}\n\n      {:error, :beam_lib, _} ->\n        {:error, :invalid_beam}\n    end\n  end\n\n  defp fetch_docs_from_chunk(path) do\n    case File.read(path) do\n      {:ok, bin} ->\n        load_docs_chunk(bin)\n\n      {:error, _} ->\n        {:error, :chunk_not_found}\n    end\n  end\n\n  defp load_docs_chunk(bin) do\n    :erlang.binary_to_term(bin)\n  rescue\n    _ ->\n      {:error, {:invalid_chunk, bin}}\n  end\n\n  @doc false\n  @deprecated \"Code.get_docs/2 always returns nil as its outdated documentation is no longer stored on BEAM files. Use Code.fetch_docs/1 instead\"\n  def get_docs(_module, _kind) do\n    nil\n  end\n\n  ## Helpers\n\n  # Finds the file given the relative_to path.\n  #\n  # If the file is found, returns its path in binary, fails otherwise.\n  defp find_file!(file, relative_to) do\n    file =\n      if relative_to do\n        Path.expand(file, relative_to)\n      else\n        Path.expand(file)\n      end\n\n    case File.read(file) do\n      {:ok, bin} -> {String.to_charlist(bin), file}\n      {:error, reason} -> raise Code.LoadError, file: file, reason: reason\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/collectable.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefprotocol Collectable do\n  @moduledoc \"\"\"\n  A protocol to traverse data structures.\n\n  The `Enum.into/2` function uses this protocol to insert an\n  enumerable into a collection:\n\n      iex> Enum.into([a: 1, b: 2], %{})\n      %{a: 1, b: 2}\n\n  ## Why Collectable?\n\n  The `Enumerable` protocol is useful to take values out of a collection.\n  In order to support a wide range of values, the functions provided by\n  the `Enumerable` protocol do not keep shape. For example, passing a\n  map to `Enum.map/2` always returns a list.\n\n  This design is intentional. `Enumerable` was designed to support infinite\n  collections, resources and other structures with fixed shape. For example,\n  it doesn't make sense to insert values into a `Range`, as it has a\n  fixed shape where only the range limits and step are stored.\n\n  The `Collectable` module was designed to fill the gap left by the\n  `Enumerable` protocol. `Collectable.into/1` can be seen as the opposite of\n  `Enumerable.reduce/3`. If the functions in `Enumerable` are about taking values out,\n  then `Collectable.into/1` is about collecting those values into a structure.\n\n  ## Examples\n\n  To show how to manually use the `Collectable` protocol, let's play with a\n  simplified implementation for `MapSet`.\n\n      iex> {initial_acc, collector_fun} = Collectable.into(MapSet.new())\n      iex> updated_acc = Enum.reduce([1, 2, 3], initial_acc, fn elem, acc ->\n      ...>   collector_fun.(acc, {:cont, elem})\n      ...> end)\n      iex> collector_fun.(updated_acc, :done)\n      MapSet.new([1, 2, 3])\n\n  To show how the protocol can be implemented, we can again look at the\n  simplified implementation for `MapSet`. In this implementation \"collecting\" elements\n  simply means inserting them in the set through `MapSet.put/2`.\n\n      defimpl Collectable, for: MapSet do\n        def into(map_set) do\n          collector_fun = fn\n            map_set_acc, {:cont, elem} ->\n              MapSet.put(map_set_acc, elem)\n\n            map_set_acc, :done ->\n              map_set_acc\n\n            _map_set_acc, :halt ->\n              :ok\n          end\n\n          initial_acc = map_set\n\n          {initial_acc, collector_fun}\n        end\n      end\n\n  So now we can call `Enum.into/2`:\n\n      iex> Enum.into([1, 2, 3], MapSet.new())\n      MapSet.new([1, 2, 3])\n\n  \"\"\"\n\n  @type command :: {:cont, term} | :done | :halt\n\n  @doc \"\"\"\n  Returns an initial accumulator and a \"collector\" function.\n\n  Receives a `collectable` which can be used as the initial accumulator that will\n  be passed to the function.\n\n  The collector function receives a term and a command and injects the term into\n  the collectable accumulator on every `{:cont, term}` command.\n\n  `:done` is passed as a command when no further values will be injected. This\n  is useful when there's a need to close resources or normalizing values. A\n  collectable must be returned when the command is `:done`.\n\n  If injection is suddenly interrupted, `:halt` is passed and the function\n  can return any value as it won't be used.\n\n  For examples on how to use the `Collectable` protocol and `into/1` see the\n  module documentation.\n  \"\"\"\n  @spec into(t) :: {initial_acc :: term, collector :: (term, command -> t | term)}\n  def into(collectable)\nend\n\ndefimpl Collectable, for: List do\n  def into(list) do\n    # TODO: Change the behavior so the into always comes last on Elixir v2.0\n    if list != [] do\n      IO.warn(\n        \"the Collectable protocol is deprecated for non-empty lists. The behavior of \" <>\n          \"Enum.into/2 and \\\"for\\\" comprehensions with an :into option is incorrect \" <>\n          \"when collecting into non-empty lists. If you're collecting into a non-empty keyword \" <>\n          \"list, consider using Keyword.merge/2 instead. If you're collecting into a non-empty \" <>\n          \"list, consider concatenating the two lists with the ++ operator.\"\n      )\n    end\n\n    fun = fn\n      list_acc, {:cont, elem} ->\n        [elem | list_acc]\n\n      list_acc, :done ->\n        list ++ :lists.reverse(list_acc)\n\n      _list_acc, :halt ->\n        :ok\n    end\n\n    {[], fun}\n  end\nend\n\ndefimpl Collectable, for: BitString do\n  def into(binary) when is_binary(binary) do\n    fun = fn\n      acc, {:cont, x} when is_binary(x) and is_list(acc) ->\n        [acc | x]\n\n      acc, {:cont, x} when is_bitstring(x) and is_bitstring(acc) ->\n        <<acc::bitstring, x::bitstring>>\n\n      acc, {:cont, x} when is_bitstring(x) ->\n        <<IO.iodata_to_binary(acc)::bitstring, x::bitstring>>\n\n      acc, :done when is_bitstring(acc) ->\n        acc\n\n      acc, :done ->\n        IO.iodata_to_binary(acc)\n\n      __acc, :halt ->\n        :ok\n\n      _acc, {:cont, other} ->\n        raise ArgumentError,\n              \"collecting into a binary requires a bitstring, got: #{inspect(other)}\"\n    end\n\n    {[binary], fun}\n  end\n\n  def into(bitstring) do\n    fun = fn\n      acc, {:cont, x} when is_bitstring(x) ->\n        <<acc::bitstring, x::bitstring>>\n\n      acc, :done ->\n        acc\n\n      _acc, :halt ->\n        :ok\n\n      _acc, {:cont, other} ->\n        raise ArgumentError,\n              \"collecting into a bitstring requires a bitstring, got: #{inspect(other)}\"\n    end\n\n    {bitstring, fun}\n  end\nend\n\ndefimpl Collectable, for: Map do\n  def into(map) do\n    fun = fn\n      map_acc, {:cont, {key, value}} ->\n        Map.put(map_acc, key, value)\n\n      map_acc, :done ->\n        map_acc\n\n      _map_acc, :halt ->\n        :ok\n\n      _map_acc, {:cont, other} ->\n        raise ArgumentError,\n              \"collecting into a map requires {key, value} tuples, got: #{inspect(other)}\"\n    end\n\n    {map, fun}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/config/provider.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Config.Provider do\n  @moduledoc \"\"\"\n  Specifies a provider API that loads configuration during boot.\n\n  Config providers are typically used during releases to load\n  external configuration while the system boots. This is done\n  by starting the VM with the minimum amount of applications\n  running, then invoking all of the providers, and then\n  restarting the system. This requires a mutable configuration\n  file on disk, as the results of the providers are written to\n  the file system. For more information on runtime configuration,\n  see `mix release`.\n\n  ## Multiple config files\n\n  One common use of config providers is to specify multiple\n  configuration files in a release. Elixir ships with one provider,\n  called `Config.Reader`, which is capable of handling Elixir's\n  built-in config files.\n\n  For example, imagine you want to list some basic configuration\n  on Mix's built-in `config/runtime.exs` file, but you also want\n  to support additional configuration files. To do so, you can add\n  this inside the `def project` portion of  your `mix.exs`:\n\n      releases: [\n        demo: [\n          config_providers: [\n            {Config.Reader, {:system, \"RELEASE_ROOT\", \"/extra_config.exs\"}}\n          ]\n        ]\n      ]\n\n  You can place this `extra_config.exs` file in your release in\n  multiple ways:\n\n    1. If it is available on the host when assembling the release,\n      you can place it on \"rel/overlays/extra_config.exs\" and it\n      will be automatically copied to the release root\n\n    2. If it is available on the target during deployment, you can\n      simply copy it to the release root as a step in your deployment\n\n  Now once the system boots, it will load both `config/runtime.exs`\n  and `extra_config.exs` early in the boot process. You can learn\n  more options on `Config.Reader`.\n\n  ## Custom config provider\n\n  You can also implement custom config providers, similar to how\n  `Config.Reader` works. For example, imagine you need to load\n  some configuration from a JSON file and load that into the system.\n  Said configuration provider would look like:\n\n      defmodule JSONConfigProvider do\n        @behaviour Config.Provider\n\n        # Let's pass the path to the JSON file as config\n        @impl true\n        def init(path) when is_binary(path), do: path\n\n        @impl true\n        def load(config, path) do\n          # We need to start any app we may depend on.\n          {:ok, _} = Application.ensure_all_started(:jason)\n\n          json = path |> File.read!() |> Jason.decode!()\n\n          Config.Reader.merge(\n            config,\n            my_app: [\n              some_value: json[\"my_app_some_value\"],\n              another_value: json[\"my_app_another_value\"],\n            ]\n          )\n        end\n      end\n\n  Then, when specifying your release, you can specify the provider in\n  the release configuration:\n\n      releases: [\n        demo: [\n          config_providers: [\n            {JSONConfigProvider, \"/etc/config.json\"}\n          ]\n        ]\n      ]\n\n  \"\"\"\n\n  @type config :: keyword\n  @type state :: term\n\n  @typedoc \"\"\"\n  A path pointing to a configuration file.\n\n  Since configuration files are often accessed on target machines,\n  it can be expressed either as:\n\n    * a binary representing an absolute path\n\n    * a `{:system, system_var, path}` tuple where the config is the\n      concatenation of the environment variable `system_var` with\n      the given `path`\n\n  \"\"\"\n  @type config_path :: {:system, binary(), binary()} | binary()\n\n  @typedoc \"\"\"\n  Options for `init/3`.\n  \"\"\"\n  @type init_opts :: [\n          extra_config: config(),\n          prune_runtime_sys_config_after_boot: boolean(),\n          reboot_system_after_config: boolean(),\n          validate_compile_env: [{atom(), [atom()], term()}]\n        ]\n\n  @doc \"\"\"\n  Invoked when initializing a config provider.\n\n  A config provider is typically initialized on the machine\n  where the system is assembled and not on the target machine.\n  The `c:init/1` callback is useful to verify the arguments\n  given to the provider and prepare the state that will be\n  given to `c:load/2`.\n\n  Furthermore, because the state returned by `c:init/1` can\n  be written to text-based config files, it should be\n  restricted only to simple data types, such as integers,\n  strings, atoms, tuples, maps, and lists. Entries such as\n  PIDs, references, and functions cannot be serialized.\n  \"\"\"\n  @callback init(term) :: state\n\n  @doc \"\"\"\n  Loads configuration (typically during system boot).\n\n  It receives the current `config` and the `state` returned by\n  `c:init/1`. Then, you typically read the extra configuration\n  from an external source and merge it into the received `config`.\n  Merging should be done with `Config.Reader.merge/2`, as it\n  performs deep merge. It should return the updated config.\n\n  Note that `c:load/2` is typically invoked very early in the\n  boot process, therefore if you need to use an application\n  in the provider, it is your responsibility to start it.\n  \"\"\"\n  @callback load(config, state) :: config\n\n  @doc false\n  defstruct [\n    :providers,\n    :config_path,\n    extra_config: [],\n    prune_runtime_sys_config_after_boot: false,\n    reboot_system_after_config: false,\n    validate_compile_env: false\n  ]\n\n  @reserved_apps [:kernel, :stdlib]\n\n  @doc \"\"\"\n  Validates a `t:config_path/0`.\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec validate_config_path!(config_path) :: :ok\n  def validate_config_path!({:system, name, path})\n      when is_binary(name) and is_binary(path),\n      do: :ok\n\n  def validate_config_path!(path) do\n    if is_binary(path) and Path.type(path) != :relative do\n      :ok\n    else\n      raise ArgumentError, \"\"\"\n      expected configuration path to be:\n\n        * a binary representing an absolute path\n        * a tuple {:system, system_var, path} where the config is the \\\n      concatenation of the `system_var` with the given `path`\n\n      Got: #{inspect(path)}\n      \"\"\"\n    end\n  end\n\n  @doc \"\"\"\n  Resolves a `t:config_path/0` to an actual path.\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec resolve_config_path!(config_path) :: binary\n  def resolve_config_path!(path) when is_binary(path), do: path\n  def resolve_config_path!({:system, name, path}), do: System.fetch_env!(name) <> path\n\n  # Private keys\n  @init_key :config_provider_init\n  @booted_key :config_provider_booted\n\n  # Public keys\n  @reboot_mode_key :config_provider_reboot_mode\n\n  @doc false\n  @spec init([{module(), term()}], config_path(), init_opts()) :: config()\n  def init(providers, config_path, opts \\\\ []) when is_list(providers) and is_list(opts) do\n    validate_config_path!(config_path)\n    providers = for {provider, init} <- providers, do: {provider, provider.init(init)}\n    init = struct!(%Config.Provider{config_path: config_path, providers: providers}, opts)\n    [elixir: [{@init_key, init}]]\n  end\n\n  @doc false\n  def boot(reboot_fun \\\\ &restart_and_sleep/0) do\n    # The config provider typically runs very early in the\n    # release process, so we need to make sure Elixir is started\n    # before we go around running Elixir code.\n    {:ok, _} = :application.ensure_all_started(:elixir)\n\n    case Application.fetch_env(:elixir, @booted_key) do\n      {:ok, {:booted, path}} ->\n        path && File.rm(path)\n\n        with {:ok, %Config.Provider{} = provider} <- Application.fetch_env(:elixir, @init_key) do\n          maybe_validate_compile_env(provider)\n        end\n\n        :booted\n\n      _ ->\n        case Application.fetch_env(:elixir, @init_key) do\n          {:ok, %Config.Provider{} = provider} ->\n            path = resolve_config_path!(provider.config_path)\n            reboot_config = [elixir: [{@booted_key, booted_value(provider, path)}]]\n            boot_providers(path, provider, reboot_config, reboot_fun)\n\n          _ ->\n            :skip\n        end\n    end\n  end\n\n  defp boot_providers(path, provider, reboot_config, reboot_fun) do\n    original_config = read_config!(path)\n\n    config =\n      original_config\n      |> Config.__merge__(provider.extra_config)\n      |> run_providers(provider)\n\n    if provider.reboot_system_after_config do\n      config\n      |> Config.__merge__(reboot_config)\n      |> write_config!(path)\n\n      reboot_fun.()\n    else\n      for app <- @reserved_apps, config[app] != original_config[app] do\n        abort(\"\"\"\n        Cannot configure #{inspect(app)} because :reboot_system_after_config has been set \\\n        to false and #{inspect(app)} has already been loaded, meaning any further \\\n        configuration won't have an effect.\n\n        The configuration for #{inspect(app)} before config providers was:\n\n        #{inspect(original_config[app])}\n\n        The configuration for #{inspect(app)} after config providers was:\n\n        #{inspect(config[app])}\n        \"\"\")\n      end\n\n      _ = Application.put_all_env(config, persistent: true)\n      maybe_validate_compile_env(provider)\n      :ok\n    end\n  end\n\n  defp maybe_validate_compile_env(provider) do\n    with [_ | _] = compile_env <- provider.validate_compile_env,\n         {:error, message} <- validate_compile_env(compile_env) do\n      abort(message)\n    end\n  end\n\n  @doc false\n  def valid_compile_env?(compile_env) do\n    Enum.all?(compile_env, fn {app, [key | path], compile_return} ->\n      try do\n        traverse_env(Application.fetch_env(app, key), path) == compile_return\n      rescue\n        _ -> false\n      end\n    end)\n  end\n\n  @doc false\n  def validate_compile_env(compile_env, ensure_loaded? \\\\ true)\n\n  def validate_compile_env([{app, [key | path], compile_return} | compile_env], ensure_loaded?) do\n    if ensure_app_loaded?(app, ensure_loaded?) do\n      try do\n        traverse_env(Application.fetch_env(app, key), path)\n      rescue\n        e ->\n          {:error,\n           \"\"\"\n           application #{inspect(app)} failed reading its compile environment #{path(key, path)}:\n\n           #{Exception.format(:error, e, __STACKTRACE__)}\n\n           Expected it to match the compile time value of #{return_to_text(compile_return)}.\n\n           #{compile_env_tips(app)}\n           \"\"\"}\n      else\n        ^compile_return ->\n          validate_compile_env(compile_env, ensure_loaded?)\n\n        runtime_return ->\n          {:error,\n           \"\"\"\n           the application #{inspect(app)} has a different value set #{path(key, path)} \\\n           during runtime compared to compile time. Since this application environment entry was \\\n           marked as compile time, this difference can lead to different behavior than expected:\n\n             * Compile time value #{return_to_text(compile_return)}\n             * Runtime value #{return_to_text(runtime_return)}\n\n           #{compile_env_tips(app)}\n           \"\"\"}\n      end\n    else\n      validate_compile_env(compile_env, ensure_loaded?)\n    end\n  end\n\n  def validate_compile_env([], _ensure_loaded?) do\n    :ok\n  end\n\n  defp ensure_app_loaded?(app, true), do: Application.ensure_loaded(app) == :ok\n  defp ensure_app_loaded?(app, false), do: Application.spec(app, :vsn) != nil\n\n  defp path(key, []), do: \"for key #{inspect(key)}\"\n  defp path(key, path), do: \"for path #{inspect(path)} inside key #{inspect(key)}\"\n\n  defp compile_env_tips(app),\n    do: \"\"\"\n    To fix this error, you might:\n\n      * Make the runtime value match the compile time one\n\n      * Recompile your project. If the misconfigured application is a dependency, \\\n    you may need to run \"mix deps.clean #{app} --build\"\n\n      * Alternatively, you can disable this check. If you are using releases, you can \\\n    set :validate_compile_env to false in your release configuration. If you are \\\n    using Mix to start your system, you can pass the --no-validate-compile-env flag\n    \"\"\"\n\n  defp return_to_text({:ok, value}), do: \"was set to: #{inspect(value)}\"\n  defp return_to_text(:error), do: \"was not set\"\n\n  defp traverse_env(return, []), do: return\n  defp traverse_env(:error, _paths), do: :error\n  defp traverse_env({:ok, value}, [key | keys]), do: traverse_env(Access.fetch(value, key), keys)\n\n  @compile {:no_warn_undefined, {:init, :restart, 1}}\n  defp restart_and_sleep() do\n    mode = Application.get_env(:elixir, @reboot_mode_key)\n\n    if mode in [:embedded, :interactive] do\n      :init.restart(mode: mode)\n    else\n      :init.restart()\n    end\n\n    Process.sleep(:infinity)\n  end\n\n  defp booted_value(%{prune_runtime_sys_config_after_boot: true}, path), do: {:booted, path}\n  defp booted_value(%{prune_runtime_sys_config_after_boot: false}, _path), do: {:booted, nil}\n\n  defp read_config!(path) do\n    case :file.consult(path) do\n      {:ok, [inner]} ->\n        inner\n\n      {:error, reason} ->\n        bad_path_abort(\n          \"Could not read runtime configuration due to reason: #{inspect(reason)}\",\n          path\n        )\n    end\n  end\n\n  defp run_providers(config, %{providers: providers}) do\n    Enum.reduce(providers, config, fn {provider, state}, acc ->\n      try do\n        provider.load(acc, state)\n      catch\n        kind, error ->\n          IO.puts(:stderr, \"ERROR! Config provider #{inspect(provider)} failed with:\")\n          IO.puts(:stderr, Exception.format(kind, error, __STACKTRACE__))\n          :erlang.raise(kind, error, __STACKTRACE__)\n      else\n        term when is_list(term) ->\n          term\n\n        term ->\n          abort(\"Expected provider #{inspect(provider)} to return a list, got: #{inspect(term)}\")\n      end\n    end)\n  end\n\n  defp write_config!(config, path) do\n    contents = :io_lib.format(\"%% coding: utf-8~n~tw.~n\", [config])\n\n    case File.write(path, IO.chardata_to_string(contents)) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        bad_path_abort(\n          \"Could not write runtime configuration due to reason: #{inspect(reason)}\",\n          path\n        )\n    end\n  end\n\n  defp bad_path_abort(msg, path) do\n    abort(\n      msg <>\n        \". Please make sure #{inspect(path)} is writable and accessible \" <>\n        \"or choose a different path\"\n    )\n  end\n\n  defp abort(msg) do\n    IO.puts(\"ERROR! \" <> msg)\n    :erlang.raise(:error, \"aborting boot\", [{Config.Provider, :boot, 2, []}])\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/config/reader.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Config.Reader do\n  @moduledoc \"\"\"\n  API for reading config files defined with `Config`.\n\n  ## As a provider\n\n  `Config.Reader` can also be used as a `Config.Provider`. A config\n  provider is used during releases to customize how applications are\n  configured. When used as a provider, it expects a single argument:\n  the configuration path (as outlined in `t:Config.Provider.config_path/0`)\n  for the file to be read and loaded during the system boot.\n\n  For example, if you expect the target system to have a config file\n  in an absolute path, you can add this inside the `def project` portion\n  of  your `mix.exs`:\n\n      releases: [\n        demo: [\n          config_providers: [\n            {Config.Reader, \"/etc/config.exs\"}\n          ]\n        ]\n      ]\n\n  Or if you want to read a custom path inside the release:\n\n      config_providers: [{Config.Reader, {:system, \"RELEASE_ROOT\", \"/config.exs\"}}]\n\n  You can also pass a keyword list of options to the reader,\n  where the `:path` is a required key:\n\n      config_providers: [\n        {Config.Reader,\n         path: \"/etc/config.exs\",\n         env: :prod,\n         imports: :disabled}\n      ]\n\n  Remember Mix already loads `config/runtime.exs` by default.\n  For more examples and scenarios, see the `Config.Provider` module.\n  \"\"\"\n\n  @behaviour Config.Provider\n\n  @type config_opts :: [\n          imports: [Path.t()] | :disabled,\n          env: atom(),\n          target: atom()\n        ]\n\n  @impl true\n  def init(opts) when is_list(opts) do\n    {path, opts} = Keyword.pop!(opts, :path)\n    Config.Provider.validate_config_path!(path)\n    {path, opts}\n  end\n\n  def init(path) do\n    init(path: path)\n  end\n\n  @impl true\n  def load(config, {path, opts}) do\n    merge(config, path |> Config.Provider.resolve_config_path!() |> read!(opts))\n  end\n\n  @doc \"\"\"\n  Evaluates the configuration `contents` for the given `file`.\n\n  Accepts the same options as `read!/2`.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec eval!(Path.t(), binary, config_opts) :: keyword\n  def eval!(file, contents, opts \\\\ [])\n      when is_binary(file) and is_binary(contents) and is_list(opts) do\n    Config.__eval__!(Path.expand(file), contents, opts) |> elem(0)\n  end\n\n  @doc \"\"\"\n  Reads the configuration file.\n\n  ## Options\n\n    * `:imports` - a list of already imported paths or `:disabled`\n      to disable imports\n\n    * `:env` - the environment the configuration file runs on.\n      See `Config.config_env/0` for sample usage\n\n    * `:target` - the target the configuration file runs on.\n      See `Config.config_target/0` for sample usage\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec read!(Path.t(), config_opts) :: keyword\n  def read!(file, opts \\\\ []) when is_binary(file) and is_list(opts) do\n    file = Path.expand(file)\n    Config.__eval__!(file, File.read!(file), opts) |> elem(0)\n  end\n\n  @doc \"\"\"\n  Reads the given configuration file and returns the configuration\n  with its imports.\n\n  Accepts the same options as `read!/2`. Although note the `:imports`\n  option cannot be disabled in `read_imports!/2`.\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec read_imports!(Path.t(), config_opts) :: {keyword, [Path.t()]}\n  def read_imports!(file, opts \\\\ []) when is_binary(file) and is_list(opts) do\n    if opts[:imports] == :disabled do\n      raise ArgumentError, \":imports must be a list of paths\"\n    end\n\n    file = Path.expand(file)\n    Config.__eval__!(file, File.read!(file), opts)\n  end\n\n  @doc \"\"\"\n  Merges two configurations.\n\n  The configurations are merged together with the values in\n  the second one having higher preference than the first in\n  case of conflicts. In case both values are set to keyword\n  lists, it deep merges them.\n\n  ## Examples\n\n      iex> Config.Reader.merge([app: [k: :v1]], [app: [k: :v2]])\n      [app: [k: :v2]]\n\n      iex> Config.Reader.merge([app: [k: [v1: 1, v2: 2]]], [app: [k: [v2: :a, v3: :b]]])\n      [app: [k: [v1: 1, v2: :a, v3: :b]]]\n\n      iex> Config.Reader.merge([app1: []], [app2: []])\n      [app1: [], app2: []]\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec merge(keyword, keyword) :: keyword\n  def merge(config1, config2) when is_list(config1) and is_list(config2) do\n    Config.__merge__(config1, config2)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/config.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Config do\n  @moduledoc ~S\"\"\"\n  A simple keyword-based configuration API.\n\n  ## Example\n\n  This module is most commonly used to define application configuration,\n  typically in `config/config.exs`:\n\n      import Config\n\n      config :some_app,\n        key1: \"value1\",\n        key2: \"value2\"\n\n      import_config \"#{config_env()}.exs\"\n\n  `import Config` will import the functions `config/2`, `config/3`\n  `config_env/0`, `config_target/0`, and `import_config/1`\n  to help you manage your configuration.\n\n  `config/2` and `config/3` are used to define key-value configuration\n  for a given application. Once Mix starts, it will automatically\n  evaluate the configuration file and persist the configuration above\n  into `:some_app`'s application environment, which can be accessed in\n  as follows:\n\n      \"value1\" = Application.fetch_env!(:some_app, :key1)\n\n  Finally, the line `import_config \"#{config_env()}.exs\"` will import\n  other config files based on the current configuration environment,\n  such as `config/dev.exs` and `config/test.exs`.\n\n  `Config` also provides a low-level API for evaluating and reading\n  configuration, under the `Config.Reader` module.\n\n  > #### Avoid application environment in libraries {: .info}\n  >\n  > If you are writing a library to be used by other developers,\n  > it is generally recommended to avoid the application environment, as the\n  > application environment is effectively a global storage. Also note that\n  > the `config/config.exs` of a library is not evaluated when the library is\n  > used as a dependency, as configuration is always meant to configure the\n  > current project. For more information, see [\"Using application configuration for\n  > libraries\"](design-anti-patterns.md#using-application-configuration-for-libraries).\n\n  ## Migrating from `use Mix.Config`\n\n  The `Config` module in Elixir was introduced in v1.9 as a replacement to\n  `use Mix.Config`, which was specific to Mix and has been deprecated.\n\n  You can leverage `Config` instead of `use Mix.Config` in three steps. The first\n  step is to replace `use Mix.Config` at the top of your config files by\n  `import Config`.\n\n  The second is to make sure your `import_config/1` calls do not have a\n  wildcard character. If so, you need to perform the wildcard lookup\n  manually. For example, if you did:\n\n      import_config \"../apps/*/config/config.exs\"\n\n  It has to be replaced by:\n\n      for config <- \"../apps/*/config/config.exs\" |> Path.expand(__DIR__) |> Path.wildcard() do\n        import_config config\n      end\n\n  The last step is to replace all `Mix.env()` calls in the config files with `config_env()`.\n\n  Keep in mind you must also avoid using `Mix.env()` inside your project files.\n  To check the environment at _runtime_, you may add a configuration key:\n\n      # config.exs\n      ...\n      config :my_app, env: config_env()\n\n  Then, in other scripts and modules, you may get the environment with\n  `Application.fetch_env!/2`:\n\n      # router.exs\n      ...\n      if Application.fetch_env!(:my_app, :env) == :prod do\n        ...\n      end\n\n  The only places where you may access functions from the `Mix` module are\n  the `mix.exs` file and inside custom Mix tasks, which are always within\n  the `Mix.Tasks` namespace.\n\n  ## `config/runtime.exs`\n\n  For runtime configuration, you can use the `config/runtime.exs` file.\n  It is executed right before applications start in both Mix and releases\n  (assembled with `mix release`).\n  \"\"\"\n\n  @type config_opts :: [\n          imports: [Path.t()] | :disabled,\n          env: atom(),\n          target: atom()\n        ]\n\n  @opts_key {__MODULE__, :opts}\n  @config_key {__MODULE__, :config}\n  @imports_key {__MODULE__, :imports}\n\n  defp get_opts!(), do: Process.get(@opts_key) || raise_improper_use!()\n  defp put_opts(value), do: Process.put(@opts_key, value)\n  defp delete_opts(), do: Process.delete(@opts_key)\n\n  defp get_config!(), do: Process.get(@config_key) || raise_improper_use!()\n  defp put_config(value), do: Process.put(@config_key, value)\n  defp delete_config(), do: Process.delete(@config_key)\n\n  defp get_imports!(), do: Process.get(@imports_key) || raise_improper_use!()\n  defp put_imports(value), do: Process.put(@imports_key, value)\n  defp delete_imports(), do: Process.delete(@imports_key)\n\n  defp raise_improper_use!() do\n    raise \"could not set configuration via Config. \" <>\n            \"This usually means you are trying to execute a configuration file \" <>\n            \"directly, instead of reading it with Config.Reader\"\n  end\n\n  @doc \"\"\"\n  Configures the given `root_key`.\n\n  Keyword lists are always deep-merged.\n\n  ## Examples\n\n  The given `opts` are merged into the existing configuration\n  for the given `root_key`. Conflicting keys are overridden by the\n  ones specified in `opts`, unless they are keywords, which are\n  deep merged recursively. For example, the application configuration\n  below\n\n      config :logger,\n        level: :warn,\n\n      config :logger,\n        level: :info,\n        truncate: 1024\n\n  will have a final configuration for `:logger` of:\n\n      [level: :info, truncate: 1024]\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  def config(root_key, opts) when is_atom(root_key) and is_list(opts) do\n    if not Keyword.keyword?(opts) do\n      raise ArgumentError, \"config/2 expected a keyword list, got: #{inspect(opts)}\"\n    end\n\n    get_config!()\n    |> __merge__([{root_key, opts}])\n    |> put_config()\n  end\n\n  @doc \"\"\"\n  Configures the given `key` for the given `root_key`.\n\n  Keyword lists are always deep merged.\n\n  ## Examples\n\n  The given `opts` are merged into the existing values for `key`\n  in the given `root_key`. Conflicting keys are overridden by the\n  ones specified in `opts`, unless they are keywords, which are\n  deep merged recursively. For example, the application configuration\n  below\n\n      config :ecto, Repo,\n        log_level: :warn,\n        adapter: Ecto.Adapters.Postgres,\n        metadata: [read_only: true]\n\n      config :ecto, Repo,\n        log_level: :info,\n        pool_size: 10,\n        metadata: [replica: true]\n\n  will have a final value of the configuration for the `Repo`\n  key in the `:ecto` application of:\n\n      Application.get_env(:ecto, Repo)\n      #=> [\n      #=>   log_level: :info,\n      #=>   pool_size: 10,\n      #=>   adapter: Ecto.Adapters.Postgres,\n      #=>   metadata: [read_only: true, replica: true]\n      #=> ]\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  def config(root_key, key, opts) when is_atom(root_key) and is_atom(key) do\n    get_config!()\n    |> __merge__([{root_key, [{key, opts}]}])\n    |> put_config()\n  end\n\n  @doc \"\"\"\n  Reads the configuration for the given root key.\n\n  This function only reads the configuration from a previous\n  `config/2` or `config/3` call. If `root_key` points to an\n  application, it does not read its actual application environment.\n  Its main use case is to make it easier to access and share\n  configuration values across files.\n\n  If the `root_key` was not configured, it returns `nil`.\n\n  ## Examples\n\n      # In config/config.exs\n      config :my_app, foo: :bar\n\n      # In config/dev.exs\n      config :another_app, foo: read_config(:my_app)[:foo] || raise \"missing parent configuration\"\n\n  \"\"\"\n  @doc since: \"1.18.0\"\n  def read_config(root_key) when is_atom(root_key) do\n    get_config!()[root_key]\n  end\n\n  @doc \"\"\"\n  Returns the environment this configuration file is executed on.\n\n  In Mix projects this function returns the environment this configuration\n  file is executed on. \n  In releases, returns the `MIX_ENV` specified when running `mix release`.\n\n  This is most often used to execute conditional code:\n\n      if config_env() == :prod do\n        config :my_app, :debug, false\n      end\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  defmacro config_env() do\n    quote do\n      Config.__env__!()\n    end\n  end\n\n  @doc false\n  @spec __env__!() :: atom()\n  def __env__!() do\n    elem(get_opts!(), 0) || raise \"no :env key was given to this configuration file\"\n  end\n\n  @doc \"\"\"\n  Returns the target this configuration file is executed on.\n\n  This is most often used to execute conditional code:\n\n      if config_target() == :host do\n        config :my_app, :debug, false\n      end\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  defmacro config_target() do\n    quote do\n      Config.__target__!()\n    end\n  end\n\n  @doc false\n  @spec __target__!() :: atom()\n  def __target__!() do\n    elem(get_opts!(), 1) || raise \"no :target key was given to this configuration file\"\n  end\n\n  @doc ~S\"\"\"\n  Imports configuration from the given file.\n\n  In case the file doesn't exist, an error is raised.\n\n  If file is a relative, it will be expanded relatively to the\n  directory the current configuration file is in.\n\n  ## Examples\n\n  This is often used to emulate configuration across environments:\n\n      import_config \"#{config_env()}.exs\"\n\n  Note, however, some configuration files, such as `config/runtime.exs`\n  does not support imports, as they are meant to be copied across\n  systems.\n  \"\"\"\n  @doc since: \"1.9.0\"\n  defmacro import_config(file) do\n    quote do\n      Config.__import__!(Path.expand(unquote(file), __DIR__))\n      :ok\n    end\n  end\n\n  @doc false\n  @spec __import__!(Path.t()) :: {term, Code.binding()}\n  def __import__!(file) when is_binary(file) do\n    import_config!(file, File.read!(file), true)\n  end\n\n  @doc false\n  @spec __eval__!(Path.t(), binary(), config_opts) :: {keyword, [Path.t()] | :disabled}\n  def __eval__!(file, content, opts \\\\ []) when is_binary(file) and is_list(opts) do\n    env = Keyword.get(opts, :env)\n    target = Keyword.get(opts, :target)\n    imports = Keyword.get(opts, :imports, [])\n\n    previous_opts = put_opts({env, target})\n    previous_config = put_config([])\n    previous_imports = put_imports(imports)\n\n    try do\n      {eval_config, _} = import_config!(file, content, false)\n\n      case get_config!() do\n        [] when is_list(eval_config) ->\n          {validate!(eval_config, file), get_imports!()}\n\n        pdict_config ->\n          {pdict_config, get_imports!()}\n      end\n    after\n      if previous_opts, do: put_opts(previous_opts), else: delete_opts()\n      if previous_config, do: put_config(previous_config), else: delete_config()\n      if previous_imports, do: put_imports(previous_imports), else: delete_imports()\n    end\n  end\n\n  defp import_config!(file, contents, raise_when_disabled?) do\n    current_imports = get_imports!()\n\n    cond do\n      current_imports == :disabled ->\n        if raise_when_disabled? do\n          raise \"import_config/1 is not enabled for this configuration file. \" <>\n                  \"Some configuration files do not allow importing other files \" <>\n                  \"as they are often copied to external systems\"\n        end\n\n      file in current_imports ->\n        raise ArgumentError,\n              \"attempting to load configuration #{Path.relative_to_cwd(file)} recursively\"\n\n      true ->\n        put_imports([file | current_imports])\n        :ok\n    end\n\n    Code.eval_string(contents, [], file: file)\n  end\n\n  @doc false\n  def __merge__(config1, config2) when is_list(config1) and is_list(config2) do\n    Keyword.merge(config1, config2, fn _, app1, app2 ->\n      Keyword.merge(app1, app2, &deep_merge/3)\n    end)\n  end\n\n  defp deep_merge(_key, value1, value2) do\n    if Keyword.keyword?(value1) and Keyword.keyword?(value2) do\n      Keyword.merge(value1, value2, &deep_merge/3)\n    else\n      value2\n    end\n  end\n\n  defp validate!(config, file) do\n    Enum.all?(config, fn\n      {app, value} when is_atom(app) ->\n        if Keyword.keyword?(value) do\n          true\n        else\n          raise ArgumentError,\n                \"expected config for app #{inspect(app)} in #{Path.relative_to_cwd(file)} \" <>\n                  \"to return keyword list, got: #{inspect(value)}\"\n        end\n\n      _ ->\n        false\n    end)\n\n    config\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/dict.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Dict do\n  @moduledoc ~S\"\"\"\n  Generic API for dictionaries.\n\n  If you need a general dictionary, use the `Map` module.\n  If you need to manipulate keyword lists, use `Keyword`.\n\n  To convert maps into keywords and vice-versa, use the\n  `new` function in the respective modules.\n  \"\"\"\n\n  @moduledoc deprecated: \"Use Map or Keyword modules instead\"\n\n  @type key :: any\n  @type value :: any\n  @type t :: list | map\n\n  message =\n    \"Use the Map module for working with maps or the Keyword module for working with keyword lists\"\n\n  defmacro __using__(_) do\n    # Use this import to guarantee proper code expansion\n    import Kernel, except: [size: 1]\n\n    if __CALLER__.module != HashDict do\n      IO.warn(\"use Dict is deprecated. \" <> unquote(message), __CALLER__)\n    end\n\n    quote do\n      message = \"Use maps and the Map module instead\"\n\n      @deprecated message\n      def get(dict, key, default \\\\ nil) do\n        case fetch(dict, key) do\n          {:ok, value} -> value\n          :error -> default\n        end\n      end\n\n      @deprecated message\n      def get_lazy(dict, key, fun) when is_function(fun, 0) do\n        case fetch(dict, key) do\n          {:ok, value} -> value\n          :error -> fun.()\n        end\n      end\n\n      @deprecated message\n      def get_and_update(dict, key, fun) do\n        current_value = get(dict, key)\n        {get, new_value} = fun.(current_value)\n        {get, put(dict, key, new_value)}\n      end\n\n      @deprecated message\n      def fetch!(dict, key) do\n        case fetch(dict, key) do\n          {:ok, value} -> value\n          :error -> raise KeyError, key: key, term: dict\n        end\n      end\n\n      @deprecated message\n      def has_key?(dict, key) do\n        match?({:ok, _}, fetch(dict, key))\n      end\n\n      @deprecated message\n      def put_new(dict, key, value) do\n        case has_key?(dict, key) do\n          true -> dict\n          false -> put(dict, key, value)\n        end\n      end\n\n      @deprecated message\n      def put_new_lazy(dict, key, fun) when is_function(fun, 0) do\n        case has_key?(dict, key) do\n          true -> dict\n          false -> put(dict, key, fun.())\n        end\n      end\n\n      @deprecated message\n      def drop(dict, keys) do\n        Enum.reduce(keys, dict, &delete(&2, &1))\n      end\n\n      @deprecated message\n      def take(dict, keys) do\n        Enum.reduce(keys, new(), fn key, acc ->\n          case fetch(dict, key) do\n            {:ok, value} -> put(acc, key, value)\n            :error -> acc\n          end\n        end)\n      end\n\n      @deprecated message\n      def to_list(dict) do\n        reduce(dict, {:cont, []}, fn kv, acc -> {:cont, [kv | acc]} end)\n        |> elem(1)\n        |> :lists.reverse()\n      end\n\n      @deprecated message\n      def keys(dict) do\n        reduce(dict, {:cont, []}, fn {k, _}, acc -> {:cont, [k | acc]} end)\n        |> elem(1)\n        |> :lists.reverse()\n      end\n\n      @deprecated message\n      def values(dict) do\n        reduce(dict, {:cont, []}, fn {_, v}, acc -> {:cont, [v | acc]} end)\n        |> elem(1)\n        |> :lists.reverse()\n      end\n\n      @deprecated message\n      def equal?(dict1, dict2) do\n        # Use this import to avoid conflicts in the user code\n        import Kernel, except: [size: 1]\n\n        case size(dict1) == size(dict2) do\n          false ->\n            false\n\n          true ->\n            reduce(dict1, {:cont, true}, fn {k, v}, _acc ->\n              case fetch(dict2, k) do\n                {:ok, ^v} -> {:cont, true}\n                _ -> {:halt, false}\n              end\n            end)\n            |> elem(1)\n        end\n      end\n\n      @deprecated message\n      def merge(dict1, dict2, fun \\\\ fn _k, _v1, v2 -> v2 end) do\n        # Use this import to avoid conflicts in the user code\n        import Kernel, except: [size: 1]\n\n        if size(dict1) < size(dict2) do\n          reduce(dict1, {:cont, dict2}, fn {k, v1}, acc ->\n            {:cont, update(acc, k, v1, &fun.(k, v1, &1))}\n          end)\n        else\n          reduce(dict2, {:cont, dict1}, fn {k, v2}, acc ->\n            {:cont, update(acc, k, v2, &fun.(k, &1, v2))}\n          end)\n        end\n        |> elem(1)\n      end\n\n      @deprecated message\n      def update(dict, key, default, fun) do\n        case fetch(dict, key) do\n          {:ok, value} ->\n            put(dict, key, fun.(value))\n\n          :error ->\n            put(dict, key, default)\n        end\n      end\n\n      @deprecated message\n      def update!(dict, key, fun) do\n        case fetch(dict, key) do\n          {:ok, value} ->\n            put(dict, key, fun.(value))\n\n          :error ->\n            raise KeyError, key: key, term: dict\n        end\n      end\n\n      @deprecated message\n      def pop(dict, key, default \\\\ nil) do\n        case fetch(dict, key) do\n          {:ok, value} ->\n            {value, delete(dict, key)}\n\n          :error ->\n            {default, dict}\n        end\n      end\n\n      @deprecated message\n      def pop_lazy(dict, key, fun) when is_function(fun, 0) do\n        case fetch(dict, key) do\n          {:ok, value} ->\n            {value, delete(dict, key)}\n\n          :error ->\n            {fun.(), dict}\n        end\n      end\n\n      @deprecated message\n      def split(dict, keys) do\n        Enum.reduce(keys, {new(), dict}, fn key, {inc, exc} = acc ->\n          case fetch(exc, key) do\n            {:ok, value} ->\n              {put(inc, key, value), delete(exc, key)}\n\n            :error ->\n              acc\n          end\n        end)\n      end\n\n      defoverridable merge: 2,\n                     merge: 3,\n                     equal?: 2,\n                     to_list: 1,\n                     keys: 1,\n                     values: 1,\n                     take: 2,\n                     drop: 2,\n                     get: 2,\n                     get: 3,\n                     fetch!: 2,\n                     has_key?: 2,\n                     put_new: 3,\n                     pop: 2,\n                     pop: 3,\n                     split: 2,\n                     update: 4,\n                     update!: 3,\n                     get_and_update: 3,\n                     get_lazy: 3,\n                     pop_lazy: 3,\n                     put_new_lazy: 3\n    end\n  end\n\n  defmacrop target(dict) do\n    quote do\n      case unquote(dict) do\n        %module{} -> module\n        %{} -> Map\n        dict when is_list(dict) -> Keyword\n        dict -> unsupported_dict(dict)\n      end\n    end\n  end\n\n  @deprecated message\n  @spec keys(t) :: [key]\n  def keys(dict) do\n    target(dict).keys(dict)\n  end\n\n  @deprecated message\n  @spec values(t) :: [value]\n  def values(dict) do\n    target(dict).values(dict)\n  end\n\n  @deprecated message\n  @spec size(t) :: non_neg_integer\n  def size(dict) do\n    target(dict).size(dict)\n  end\n\n  @deprecated message\n  @spec has_key?(t, key) :: boolean\n  def has_key?(dict, key) do\n    target(dict).has_key?(dict, key)\n  end\n\n  @deprecated message\n  @spec get(t, key, value) :: value\n  def get(dict, key, default \\\\ nil) do\n    target(dict).get(dict, key, default)\n  end\n\n  @deprecated message\n  @spec get_lazy(t, key, (-> value)) :: value\n  def get_lazy(dict, key, fun) do\n    target(dict).get_lazy(dict, key, fun)\n  end\n\n  @deprecated message\n  @spec get_and_update(t, key, (value -> {value, value})) :: {value, t}\n  def get_and_update(dict, key, fun) do\n    target(dict).get_and_update(dict, key, fun)\n  end\n\n  @deprecated message\n  @spec fetch(t, key) :: value\n  def fetch(dict, key) do\n    target(dict).fetch(dict, key)\n  end\n\n  @deprecated message\n  @spec fetch!(t, key) :: value\n  def fetch!(dict, key) do\n    target(dict).fetch!(dict, key)\n  end\n\n  @deprecated message\n  @spec put(t, key, value) :: t\n  def put(dict, key, val) do\n    target(dict).put(dict, key, val)\n  end\n\n  @deprecated message\n  @spec put_new(t, key, value) :: t\n  def put_new(dict, key, val) do\n    target(dict).put_new(dict, key, val)\n  end\n\n  @deprecated message\n  @spec put_new_lazy(t, key, (-> value)) :: t\n  def put_new_lazy(dict, key, fun) do\n    target(dict).put_new_lazy(dict, key, fun)\n  end\n\n  @deprecated message\n  @spec delete(t, key) :: t\n  def delete(dict, key) do\n    target(dict).delete(dict, key)\n  end\n\n  @deprecated message\n  @spec merge(t, t) :: t\n  def merge(dict1, dict2) do\n    target1 = target(dict1)\n    target2 = target(dict2)\n\n    if target1 == target2 do\n      target1.merge(dict1, dict2)\n    else\n      do_merge(target1, dict1, dict2, fn _k, _v1, v2 -> v2 end)\n    end\n  end\n\n  @deprecated message\n  @spec merge(t, t, (key, value, value -> value)) :: t\n  def merge(dict1, dict2, fun) do\n    target1 = target(dict1)\n    target2 = target(dict2)\n\n    if target1 == target2 do\n      target1.merge(dict1, dict2, fun)\n    else\n      do_merge(target1, dict1, dict2, fun)\n    end\n  end\n\n  defp do_merge(target1, dict1, dict2, fun) do\n    Enumerable.reduce(dict2, {:cont, dict1}, fn {k, v}, acc ->\n      {:cont, target1.update(acc, k, v, fn other -> fun.(k, other, v) end)}\n    end)\n    |> elem(1)\n  end\n\n  @deprecated message\n  @spec pop(t, key, value) :: {value, t}\n  def pop(dict, key, default \\\\ nil) do\n    target(dict).pop(dict, key, default)\n  end\n\n  @deprecated message\n  @spec pop_lazy(t, key, (-> value)) :: {value, t}\n  def pop_lazy(dict, key, fun) do\n    target(dict).pop_lazy(dict, key, fun)\n  end\n\n  @deprecated message\n  @spec update!(t, key, (value -> value)) :: t\n  def update!(dict, key, fun) do\n    target(dict).update!(dict, key, fun)\n  end\n\n  @deprecated message\n  @spec update(t, key, value, (value -> value)) :: t\n  def update(dict, key, default, fun) do\n    target(dict).update(dict, key, default, fun)\n  end\n\n  @deprecated message\n  @spec split(t, [key]) :: {t, t}\n  def split(dict, keys) do\n    target(dict).split(dict, keys)\n  end\n\n  @deprecated message\n  @spec drop(t, [key]) :: t\n  def drop(dict, keys) do\n    target(dict).drop(dict, keys)\n  end\n\n  @deprecated message\n  @spec take(t, [key]) :: t\n  def take(dict, keys) do\n    target(dict).take(dict, keys)\n  end\n\n  @deprecated message\n  @spec empty(t) :: t\n  def empty(dict) do\n    target(dict).empty(dict)\n  end\n\n  @deprecated message\n  @spec equal?(t, t) :: boolean\n  def equal?(dict1, dict2) do\n    target1 = target(dict1)\n    target2 = target(dict2)\n\n    cond do\n      target1 == target2 ->\n        target1.equal?(dict1, dict2)\n\n      target1.size(dict1) == target2.size(dict2) ->\n        Enumerable.reduce(dict2, {:cont, true}, fn {k, v}, _acc ->\n          case target1.fetch(dict1, k) do\n            {:ok, ^v} -> {:cont, true}\n            _ -> {:halt, false}\n          end\n        end)\n        |> elem(1)\n\n      true ->\n        false\n    end\n  end\n\n  @deprecated message\n  @spec to_list(t) :: list\n  def to_list(dict) do\n    target(dict).to_list(dict)\n  end\n\n  @spec unsupported_dict(t) :: no_return\n  defp unsupported_dict(dict) do\n    raise ArgumentError, \"unsupported dict: #{inspect(dict)}\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/dynamic_supervisor.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule DynamicSupervisor do\n  @moduledoc ~S\"\"\"\n  A supervisor optimized to only start children dynamically.\n\n  The `Supervisor` module was designed to handle mostly static children\n  that are started in the given order when the supervisor starts. A\n  `DynamicSupervisor` starts with no children. Instead, children are\n  started on demand via `start_child/2` and there is no ordering between\n  children. This allows the `DynamicSupervisor` to hold millions of\n  children by using efficient data structures and to execute certain\n  operations, such as shutting down, concurrently.\n\n  ## Examples\n\n  A dynamic supervisor is started with no children and often with a name:\n\n      children = [\n        {DynamicSupervisor, name: MyApp.DynamicSupervisor, strategy: :one_for_one}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_one)\n\n  The options given in the child specification are documented in `start_link/1`.\n\n  Once the dynamic supervisor is running, we can use it to start children\n  on demand. Given this sample `GenServer`:\n\n      defmodule Counter do\n        use GenServer\n\n        def start_link(initial) do\n          GenServer.start_link(__MODULE__, initial)\n        end\n\n        def inc(pid) do\n          GenServer.call(pid, :inc)\n        end\n\n        def init(initial) do\n          {:ok, initial}\n        end\n\n        def handle_call(:inc, _, count) do\n          {:reply, count, count + 1}\n        end\n      end\n\n  We can use `start_child/2` with a child specification to start a `Counter`\n  server:\n\n      {:ok, counter1} = DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Counter, 0})\n      Counter.inc(counter1)\n      #=> 0\n\n      {:ok, counter2} = DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Counter, 10})\n      Counter.inc(counter2)\n      #=> 10\n\n      DynamicSupervisor.count_children(MyApp.DynamicSupervisor)\n      #=> %{active: 2, specs: 2, supervisors: 0, workers: 2}\n\n  ## Scalability and partitioning\n\n  The `DynamicSupervisor` is a single process responsible for starting\n  other processes. In some applications, the `DynamicSupervisor` may\n  become a bottleneck. To address this, you can start multiple instances\n  of the `DynamicSupervisor` and then pick a \"random\" instance to start\n  the child on.\n\n  Instead of:\n\n      children = [\n        {DynamicSupervisor, name: MyApp.DynamicSupervisor}\n      ]\n\n  and:\n\n      DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Counter, 0})\n\n  You can do this:\n\n      children = [\n        {PartitionSupervisor,\n         child_spec: DynamicSupervisor,\n         name: MyApp.DynamicSupervisors}\n      ]\n\n  and then:\n\n      DynamicSupervisor.start_child(\n        {:via, PartitionSupervisor, {MyApp.DynamicSupervisors, self()}},\n        {Counter, 0}\n      )\n\n  In the code above, we start a partition supervisor that will by default\n  start a dynamic supervisor for each core in your machine. Then, instead\n  of calling the `DynamicSupervisor` by name, you call it through the\n  partition supervisor, using `self()` as the routing key. This means each\n  process will be assigned one of the existing dynamic supervisors.\n  Read the `PartitionSupervisor` docs for more information.\n\n  ## Module-based supervisors\n\n  Similar to `Supervisor`, dynamic supervisors also support module-based\n  supervisors.\n\n      defmodule MyApp.DynamicSupervisor do\n        # Automatically defines child_spec/1\n        use DynamicSupervisor\n\n        def start_link(init_arg) do\n          DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)\n        end\n\n        @impl true\n        def init(_init_arg) do\n          DynamicSupervisor.init(strategy: :one_for_one)\n        end\n      end\n\n  See the `Supervisor` docs for a discussion of when you may want to use\n  module-based supervisors. A `@doc` annotation immediately preceding\n  `use DynamicSupervisor` will be attached to the generated `child_spec/1`\n  function.\n\n  > #### `use DynamicSupervisor` {: .info}\n  >\n  > When you `use DynamicSupervisor`, the `DynamicSupervisor` module will\n  > set `@behaviour DynamicSupervisor` and define a `child_spec/1`\n  > function, so your module can be used as a child in a supervision tree.\n\n  ## Name registration\n\n  A supervisor is bound to the same name registration rules as a `GenServer`.\n  Read more about these rules in the documentation for `GenServer`.\n  \"\"\"\n\n  @behaviour GenServer\n\n  @doc \"\"\"\n  Callback invoked to start the supervisor and during hot code upgrades.\n\n  Developers typically invoke `DynamicSupervisor.init/1` at the end of\n  their init callback to return the proper supervision flags.\n  \"\"\"\n  @callback init(init_arg :: term) :: {:ok, sup_flags()} | :ignore\n\n  @typedoc \"The supervisor flags returned on init\"\n  @type sup_flags() :: %{\n          strategy: strategy(),\n          intensity: non_neg_integer(),\n          period: pos_integer(),\n          max_children: non_neg_integer() | :infinity,\n          extra_arguments: [term()]\n        }\n\n  @typedoc \"Options given to `start_link/1` and `init/1` functions\"\n  @type init_option ::\n          {:strategy, strategy()}\n          | {:max_restarts, non_neg_integer()}\n          | {:max_seconds, pos_integer()}\n          | {:max_children, non_neg_integer() | :infinity}\n          | {:extra_arguments, [term()]}\n\n  @typedoc \"Supported strategies\"\n  @type strategy :: :one_for_one\n\n  @typedoc \"\"\"\n  Return values of `start_child` functions.\n\n  Unlike `Supervisor`, this module ignores the child spec ids,\n  so `{:error, {:already_started, pid}}` is not returned for child specs\n  given with the same id. `{:error, {:already_started, pid}}` is returned\n  however if a duplicate name is used when using\n  [name registration](`m:GenServer#module-name-registration`).\n  \"\"\"\n  @type on_start_child ::\n          {:ok, pid}\n          | {:ok, pid, info :: term}\n          | :ignore\n          | {:error, {:already_started, pid} | :max_children | term}\n\n  # In this struct, `args` refers to the arguments passed to init/1 (the `init_arg`).\n  defstruct [\n    :args,\n    :extra_arguments,\n    :mod,\n    :name,\n    :strategy,\n    :max_children,\n    :max_restarts,\n    :max_seconds,\n    children: %{},\n    restarts: []\n  ]\n\n  @doc \"\"\"\n  Returns a specification to start a dynamic supervisor under a supervisor.\n\n  It accepts the same options as `start_link/1`.\n\n  See `Supervisor` for more information about child specifications.\n  \"\"\"\n  @doc since: \"1.6.1\"\n  @spec child_spec([init_option() | GenServer.option()]) :: Supervisor.child_spec()\n  def child_spec(options) when is_list(options) do\n    id =\n      case Keyword.get(options, :name, DynamicSupervisor) do\n        name when is_atom(name) -> name\n        {:global, name} -> name\n        {:via, _module, name} -> name\n      end\n\n    %{\n      id: id,\n      start: {DynamicSupervisor, :start_link, [options]},\n      type: :supervisor\n    }\n  end\n\n  @doc false\n  defmacro __using__(opts) do\n    quote location: :keep, bind_quoted: [opts: opts] do\n      @behaviour DynamicSupervisor\n      if not Module.has_attribute?(__MODULE__, :doc) do\n        @doc \"\"\"\n        Returns a specification to start this module under a supervisor.\n\n        See `Supervisor`.\n        \"\"\"\n      end\n\n      def child_spec(arg) do\n        default = %{\n          id: __MODULE__,\n          start: {__MODULE__, :start_link, [arg]},\n          type: :supervisor\n        }\n\n        Supervisor.child_spec(default, unquote(Macro.escape(opts)))\n      end\n\n      defoverridable child_spec: 1\n    end\n  end\n\n  @doc \"\"\"\n  Starts a supervisor with the given options.\n\n  This function is typically not invoked directly, instead it is invoked\n  when using a `DynamicSupervisor` as a child of another supervisor:\n\n      children = [\n        {DynamicSupervisor, name: MySupervisor}\n      ]\n\n  If the supervisor is successfully spawned, this function returns\n  `{:ok, pid}`, where `pid` is the PID of the supervisor. If the supervisor\n  is given a name and a process with the specified name already exists,\n  the function returns `{:error, {:already_started, pid}}`, where `pid`\n  is the PID of that process.\n\n  Note that a supervisor started with this function is linked to the parent\n  process and exits not only on crashes but also if the parent process exits\n  with `:normal` reason.\n\n  ## Options\n\n    * `:name` - registers the supervisor under the given name.\n      The supported values are described under the \"Name registration\"\n      section in the `GenServer` module docs.\n\n    * `:strategy` - the restart strategy option. The only supported\n      value is `:one_for_one` which means that no other child is\n      terminated if a child process terminates. You can learn more\n      about strategies in the `Supervisor` module docs.\n\n    * `:max_restarts` - the maximum number of restarts allowed in\n      a time frame. Defaults to `3`.\n\n    * `:max_seconds` - the time frame in which `:max_restarts` applies.\n      Defaults to `5`.\n\n    * `:max_children` - the maximum amount of children to be running\n      under this supervisor at the same time. When `:max_children` is\n      exceeded, `start_child/2` returns `{:error, :max_children}`. Defaults\n      to `:infinity`.\n\n    * `:extra_arguments` - arguments that are prepended to the arguments\n      specified in the child spec given to `start_child/2`. Defaults to\n      an empty list.\n\n    * Any of the standard [GenServer options](`t:GenServer.option/0`)\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec start_link([init_option | GenServer.option()]) :: Supervisor.on_start()\n  def start_link(options) when is_list(options) do\n    keys = [:extra_arguments, :max_children, :max_seconds, :max_restarts, :strategy]\n    {sup_opts, start_opts} = Keyword.split(options, keys)\n    start_link(Supervisor.Default, init(sup_opts), start_opts)\n  end\n\n  @doc \"\"\"\n  Starts a module-based supervisor process with the given `module` and `init_arg`.\n\n  To start the supervisor, the `c:init/1` callback will be invoked in the given\n  `module`, with `init_arg` as its argument. The `c:init/1` callback must return a\n  supervisor specification which can be created with the help of the `init/1`\n  function.\n\n  If the `c:init/1` callback returns `:ignore`, this function returns\n  `:ignore` as well and the supervisor terminates with reason `:normal`.\n  If it fails or returns an incorrect value, this function returns\n  `{:error, term}` where `term` is a term with information about the\n  error, and the supervisor terminates with reason `term`.\n\n  The `:name` option can also be given in order to register a supervisor\n  name, the supported values are described in the \"Name registration\"\n  section in the `GenServer` module docs.\n\n  If the supervisor is successfully spawned, this function returns\n  `{:ok, pid}`, where `pid` is the PID of the supervisor. If the supervisor\n  is given a name and a process with the specified name already exists,\n  the function returns `{:error, {:already_started, pid}}`, where `pid`\n  is the PID of that process.\n\n  Note that a supervisor started with this function is linked to the parent\n  process and exits not only on crashes but also if the parent process exits\n  with `:normal` reason.\n\n  ## Options\n\n  This function accepts any regular [`GenServer` options](`t:GenServer.option/0`).\n  Options specific to `DynamicSupervisor` must be returned from the `c:init/1`\n  callback.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec start_link(module, term, [GenServer.option()]) :: Supervisor.on_start()\n  def start_link(module, init_arg, opts \\\\ []) do\n    GenServer.start_link(__MODULE__, {module, init_arg, opts[:name]}, opts)\n  end\n\n  @doc \"\"\"\n  Dynamically adds a child specification to `supervisor` and starts that child.\n\n  `child_spec` should be a valid [child specification](`m:Supervisor#module-child-specification`).\n  The child process will be started as defined in the child specification. Note that while\n  the `:id` field is still required in the spec, the value is ignored and\n  therefore does not need to be unique. Unlike `Supervisor`, this module does not\n  return `{:error, {:already_started, pid}}` for child specs given with the same id.\n  `{:error, {:already_started, pid}}` is returned however if a duplicate name is\n  used when using [name registration](`m:GenServer#module-name-registration`).\n\n  This function will block the `DynamicSupervisor` until the child initializes.\n  When starting too many processes dynamically, you may want to use a\n  `PartitionSupervisor` to split the work across multiple processes.\n\n  If the child process start function returns `{:ok, child}` or `{:ok, child,\n  info}`, then child specification and PID are added to the supervisor and\n  this function returns the same value.\n\n  If the child process start function returns `:ignore`, then no child is added\n  to the supervision tree and this function returns `:ignore` too.\n\n  If the child process start function returns an error tuple or an erroneous\n  value, or if it fails, the child specification is discarded and this function\n  returns `{:error, error}` where `error` is the error or erroneous value\n  returned from child process start function, or failure reason if it fails.\n\n  If the supervisor already has N children in a way that N exceeds the amount\n  of `:max_children` set on the supervisor initialization (see `init/1`), then\n  this function returns `{:error, :max_children}`.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec start_child(\n          Supervisor.supervisor(),\n          Supervisor.child_spec()\n          | {module, term}\n          | module\n          | (old_erlang_child_spec :: :supervisor.child_spec())\n        ) ::\n          on_start_child()\n  def start_child(supervisor, {_, _, _, _, _, _} = child_spec) do\n    validate_and_start_child(supervisor, child_spec)\n  end\n\n  def start_child(supervisor, child_spec) do\n    validate_and_start_child(supervisor, Supervisor.child_spec(child_spec, []))\n  end\n\n  defp validate_and_start_child(supervisor, child_spec) do\n    case validate_child(child_spec) do\n      {:ok, child} -> call(supervisor, {:start_child, child})\n      error -> {:error, error}\n    end\n  end\n\n  defp validate_child(%{id: _, start: {mod, _, _} = start} = child) do\n    restart = Map.get(child, :restart, :permanent)\n    type = Map.get(child, :type, :worker)\n    modules = Map.get(child, :modules, [mod])\n    significant = Map.get(child, :significant, false)\n\n    shutdown =\n      case type do\n        :worker -> Map.get(child, :shutdown, 5_000)\n        :supervisor -> Map.get(child, :shutdown, :infinity)\n      end\n\n    validate_child(start, restart, shutdown, type, modules, significant)\n  end\n\n  defp validate_child({_, start, restart, shutdown, type, modules}) do\n    validate_child(start, restart, shutdown, type, modules, false)\n  end\n\n  defp validate_child(other) do\n    {:invalid_child_spec, other}\n  end\n\n  defp validate_child(start, restart, shutdown, type, modules, significant) do\n    with :ok <- validate_start(start),\n         :ok <- validate_restart(restart),\n         :ok <- validate_shutdown(shutdown),\n         :ok <- validate_type(type),\n         :ok <- validate_modules(modules),\n         :ok <- validate_significant(significant) do\n      {:ok, {start, restart, shutdown, type, modules}}\n    end\n  end\n\n  defp validate_start({m, f, args}) when is_atom(m) and is_atom(f) and is_list(args), do: :ok\n  defp validate_start(mfa), do: {:invalid_mfa, mfa}\n\n  defp validate_type(type) when type in [:supervisor, :worker], do: :ok\n  defp validate_type(type), do: {:invalid_child_type, type}\n\n  defp validate_restart(restart) when restart in [:permanent, :temporary, :transient], do: :ok\n  defp validate_restart(restart), do: {:invalid_restart_type, restart}\n\n  defp validate_shutdown(shutdown) when is_integer(shutdown) and shutdown >= 0, do: :ok\n  defp validate_shutdown(shutdown) when shutdown in [:infinity, :brutal_kill], do: :ok\n  defp validate_shutdown(shutdown), do: {:invalid_shutdown, shutdown}\n\n  defp validate_significant(false), do: :ok\n  defp validate_significant(significant), do: {:invalid_significant, significant}\n\n  defp validate_modules(:dynamic), do: :ok\n\n  defp validate_modules(mods) do\n    if is_list(mods) and Enum.all?(mods, &is_atom/1) do\n      :ok\n    else\n      {:invalid_modules, mods}\n    end\n  end\n\n  @doc \"\"\"\n  Terminates the given child identified by `pid`.\n\n  This function will block the `DynamicSupervisor` until the child\n  terminates, which may take an arbitrary amount of time if the child\n  is trapping exits and implements its own terminate callback.\n  For this reason, it is often better to ask the child process\n  itself to terminate, often by declaring in its child spec it has\n  a restart strategy of `:transient` (or `:temporary`) and then\n  sending it a message to stop with reason `:shutdown`.\n\n  If successful, this function returns `:ok`. If there is no process with\n  the given PID, this function returns `{:error, :not_found}`.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec terminate_child(Supervisor.supervisor(), pid) :: :ok | {:error, :not_found}\n  def terminate_child(supervisor, pid) when is_pid(pid) do\n    call(supervisor, {:terminate_child, pid})\n  end\n\n  @doc \"\"\"\n  Returns a list with information about all children of the given supervisor.\n\n  Note that calling this function when supervising a large number\n  of children under low memory conditions can bring the system down due to an\n  out of memory error.\n\n  This function returns a list of tuples containing:\n\n    * `id` - it is always `:undefined` for dynamic supervisors\n\n    * `child` - the PID of the corresponding child process or the\n      atom `:restarting` if the process is about to be restarted\n\n    * `type` - `:worker` or `:supervisor` as defined in the child\n      specification\n\n    * `modules` - as defined in the child specification\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec which_children(Supervisor.supervisor()) :: [\n          # module() | :dynamic here because :supervisor.modules() is not exported\n          {:undefined, pid | :restarting, :worker | :supervisor, [module()] | :dynamic}\n        ]\n  def which_children(supervisor) do\n    call(supervisor, :which_children)\n  end\n\n  @doc \"\"\"\n  Returns a map containing count values for the supervisor.\n\n  The map contains the following keys:\n\n    * `:specs` - the number of children processes\n\n    * `:active` - the count of all actively running child processes managed by\n      this supervisor\n\n    * `:supervisors` - the count of all supervisors whether or not the child\n      process is still alive\n\n    * `:workers` - the count of all workers, whether or not the child process\n      is still alive\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec count_children(Supervisor.supervisor()) :: %{\n          specs: non_neg_integer,\n          active: non_neg_integer,\n          supervisors: non_neg_integer,\n          workers: non_neg_integer\n        }\n  def count_children(supervisor) do\n    call(supervisor, :count_children) |> :maps.from_list()\n  end\n\n  @doc \"\"\"\n  Synchronously stops the given supervisor with the given `reason`.\n\n  It returns `:ok` if the supervisor terminates with the given\n  reason. If it terminates with another reason, the call exits.\n\n  This function keeps OTP semantics regarding error reporting.\n  If the reason is any other than `:normal`, `:shutdown` or\n  `{:shutdown, _}`, an error report is logged.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec stop(Supervisor.supervisor(), reason :: term, timeout) :: :ok\n  def stop(supervisor, reason \\\\ :normal, timeout \\\\ :infinity) do\n    GenServer.stop(supervisor, reason, timeout)\n  end\n\n  @doc \"\"\"\n  Receives a set of `options` that initializes a dynamic supervisor.\n\n  This is typically invoked at the end of the `c:init/1` callback of\n  module-based supervisors. See the \"Module-based supervisors\" section\n  in the module documentation for more information.\n\n  It accepts the same `options` as `start_link/1` (except for `:name`)\n  and it returns a tuple containing the supervisor options.\n\n  ## Examples\n\n      def init(_arg) do\n        DynamicSupervisor.init(max_children: 1000)\n      end\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec init([init_option]) :: {:ok, sup_flags()}\n  def init(options) when is_list(options) do\n    strategy = Keyword.get(options, :strategy, :one_for_one)\n    intensity = Keyword.get(options, :max_restarts, 3)\n    period = Keyword.get(options, :max_seconds, 5)\n    max_children = Keyword.get(options, :max_children, :infinity)\n    extra_arguments = Keyword.get(options, :extra_arguments, [])\n\n    flags = %{\n      strategy: strategy,\n      intensity: intensity,\n      period: period,\n      max_children: max_children,\n      extra_arguments: extra_arguments\n    }\n\n    {:ok, flags}\n  end\n\n  ## Callbacks\n\n  @impl true\n  def init({mod, init_arg, name}) do\n    Process.put(:\"$initial_call\", {:supervisor, mod, 1})\n    Process.flag(:trap_exit, true)\n\n    case mod.init(init_arg) do\n      {:ok, flags} when is_map(flags) ->\n        name =\n          cond do\n            is_nil(name) -> {self(), mod}\n            is_atom(name) -> {:local, name}\n            is_tuple(name) -> name\n          end\n\n        state = %DynamicSupervisor{mod: mod, args: init_arg, name: name}\n\n        case init(state, flags) do\n          {:ok, state} -> {:ok, state}\n          {:error, reason} -> {:stop, {:supervisor_data, reason}}\n        end\n\n      :ignore ->\n        :ignore\n\n      other ->\n        {:stop, {:bad_return, {mod, :init, other}}}\n    end\n  end\n\n  defp init(state, flags) do\n    extra_arguments = Map.get(flags, :extra_arguments, [])\n    max_children = Map.get(flags, :max_children, :infinity)\n    max_restarts = Map.get(flags, :intensity, 1)\n    max_seconds = Map.get(flags, :period, 5)\n    strategy = Map.get(flags, :strategy, :one_for_one)\n    auto_shutdown = Map.get(flags, :auto_shutdown, :never)\n\n    with :ok <- validate_strategy(strategy),\n         :ok <- validate_restarts(max_restarts),\n         :ok <- validate_seconds(max_seconds),\n         :ok <- validate_dynamic(max_children),\n         :ok <- validate_extra_arguments(extra_arguments),\n         :ok <- validate_auto_shutdown(auto_shutdown) do\n      {:ok,\n       %{\n         state\n         | extra_arguments: extra_arguments,\n           max_children: max_children,\n           max_restarts: max_restarts,\n           max_seconds: max_seconds,\n           strategy: strategy\n       }}\n    end\n  end\n\n  defp validate_strategy(strategy) when strategy in [:one_for_one], do: :ok\n  defp validate_strategy(strategy), do: {:error, {:invalid_strategy, strategy}}\n\n  defp validate_restarts(restart) when is_integer(restart) and restart >= 0, do: :ok\n  defp validate_restarts(restart), do: {:error, {:invalid_intensity, restart}}\n\n  defp validate_seconds(seconds) when is_integer(seconds) and seconds > 0, do: :ok\n  defp validate_seconds(seconds), do: {:error, {:invalid_period, seconds}}\n\n  defp validate_dynamic(:infinity), do: :ok\n  defp validate_dynamic(dynamic) when is_integer(dynamic) and dynamic >= 0, do: :ok\n  defp validate_dynamic(dynamic), do: {:error, {:invalid_max_children, dynamic}}\n\n  defp validate_extra_arguments(list) when is_list(list), do: :ok\n  defp validate_extra_arguments(extra), do: {:error, {:invalid_extra_arguments, extra}}\n\n  defp validate_auto_shutdown(auto_shutdown) when auto_shutdown in [:never], do: :ok\n\n  defp validate_auto_shutdown(auto_shutdown),\n    do: {:error, {:invalid_auto_shutdown, auto_shutdown}}\n\n  @impl true\n  def handle_call(:which_children, _from, state) do\n    %{children: children} = state\n\n    reply =\n      for {pid, args} <- children do\n        case args do\n          {:restarting, {_, _, _, type, modules}} ->\n            {:undefined, :restarting, type, modules}\n\n          {_, _, _, type, modules} ->\n            {:undefined, pid, type, modules}\n        end\n      end\n\n    {:reply, reply, state}\n  end\n\n  def handle_call(:count_children, _from, state) do\n    %{children: children} = state\n    specs = map_size(children)\n\n    {active, workers, supervisors} =\n      Enum.reduce(children, {0, 0, 0}, fn\n        {_pid, {:restarting, {_, _, _, :worker, _}}}, {active, worker, supervisor} ->\n          {active, worker + 1, supervisor}\n\n        {_pid, {:restarting, {_, _, _, :supervisor, _}}}, {active, worker, supervisor} ->\n          {active, worker, supervisor + 1}\n\n        {_pid, {_, _, _, :worker, _}}, {active, worker, supervisor} ->\n          {active + 1, worker + 1, supervisor}\n\n        {_pid, {_, _, _, :supervisor, _}}, {active, worker, supervisor} ->\n          {active + 1, worker, supervisor + 1}\n      end)\n\n    reply = [specs: specs, active: active, supervisors: supervisors, workers: workers]\n    {:reply, reply, state}\n  end\n\n  def handle_call({:terminate_child, pid}, _from, %{children: children} = state) do\n    case children do\n      %{^pid => info} ->\n        :ok = terminate_children(%{pid => info}, state)\n        {:reply, :ok, delete_child(pid, state)}\n\n      %{} ->\n        {:reply, {:error, :not_found}, state}\n    end\n  end\n\n  def handle_call({:start_task, args, restart, shutdown}, from, state) do\n    {init_restart, init_shutdown} = Process.get(Task.Supervisor)\n\n    if restart == nil and init_restart != :temporary do\n      {:reply, {:restart, init_restart}, state}\n    else\n      restart = restart || init_restart\n      shutdown = shutdown || init_shutdown\n\n      child =\n        {{Task.Supervised, :start_link, args}, restart, shutdown, :worker, [Task.Supervised]}\n\n      handle_call({:start_child, child}, from, state)\n    end\n  end\n\n  def handle_call({:start_child, child}, _from, state) do\n    %{children: children, max_children: max_children} = state\n\n    if map_size(children) < max_children do\n      handle_start_child(child, state)\n    else\n      {:reply, {:error, :max_children}, state}\n    end\n  end\n\n  defp handle_start_child({{m, f, args} = mfa, restart, shutdown, type, modules}, state) do\n    %{extra_arguments: extra} = state\n\n    case reply = start_child(m, f, extra ++ args) do\n      {:ok, pid, _} ->\n        {:reply, reply, save_child(pid, mfa, restart, shutdown, type, modules, state)}\n\n      {:ok, pid} ->\n        {:reply, reply, save_child(pid, mfa, restart, shutdown, type, modules, state)}\n\n      _ ->\n        {:reply, reply, state}\n    end\n  end\n\n  defp start_child(m, f, a) do\n    try do\n      apply(m, f, a)\n    catch\n      kind, reason ->\n        {:error, exit_reason(kind, reason, __STACKTRACE__)}\n    else\n      {:ok, pid, extra} when is_pid(pid) -> {:ok, pid, extra}\n      {:ok, pid} when is_pid(pid) -> {:ok, pid}\n      :ignore -> :ignore\n      {:error, _} = error -> error\n      other -> {:error, other}\n    end\n  end\n\n  defp save_child(pid, mfa, restart, shutdown, type, modules, state) do\n    mfa = mfa_for_restart(mfa, restart)\n    put_in(state.children[pid], {mfa, restart, shutdown, type, modules})\n  end\n\n  defp mfa_for_restart({m, f, _}, :temporary), do: {m, f, :undefined}\n  defp mfa_for_restart(mfa, _), do: mfa\n\n  defp exit_reason(:exit, reason, _), do: reason\n  defp exit_reason(:error, reason, stack), do: {reason, stack}\n  defp exit_reason(:throw, value, stack), do: {{:nocatch, value}, stack}\n\n  @impl true\n  def handle_cast(_msg, state) do\n    {:noreply, state}\n  end\n\n  @impl true\n  def handle_info({:EXIT, pid, reason}, state) do\n    case maybe_restart_child(pid, reason, state) do\n      {:ok, state} -> {:noreply, state}\n      {:shutdown, state} -> {:stop, :shutdown, state}\n    end\n  end\n\n  def handle_info({:\"$gen_restart\", pid}, state) do\n    %{children: children} = state\n\n    case children do\n      %{^pid => restarting_args} ->\n        {:restarting, child} = restarting_args\n\n        case restart_child(pid, child, state) do\n          {:ok, state} -> {:noreply, state}\n          {:shutdown, state} -> {:stop, :shutdown, state}\n        end\n\n      # We may hit clause if we send $gen_restart and then\n      # someone calls terminate_child, removing the child.\n      %{} ->\n        {:noreply, state}\n    end\n  end\n\n  def handle_info(msg, state) do\n    :logger.error(\n      %{\n        label: {DynamicSupervisor, :unexpected_msg},\n        report: %{\n          msg: msg\n        }\n      },\n      %{\n        domain: [:otp, :elixir],\n        error_logger: %{tag: :error_msg},\n        report_cb: &__MODULE__.format_report/1\n      }\n    )\n\n    {:noreply, state}\n  end\n\n  @impl true\n  def code_change(_, %{mod: mod, args: init_arg} = state, _) do\n    case mod.init(init_arg) do\n      {:ok, flags} when is_map(flags) ->\n        case init(state, flags) do\n          {:ok, state} -> {:ok, state}\n          {:error, reason} -> {:error, {:supervisor_data, reason}}\n        end\n\n      :ignore ->\n        {:ok, state}\n\n      error ->\n        error\n    end\n  end\n\n  @impl true\n  def terminate(_, %{children: children} = state) do\n    :ok = terminate_children(children, state)\n  end\n\n  defp terminate_children(children, state) do\n    {pids, times, stacks} = monitor_children(children)\n    size = map_size(pids)\n\n    timers =\n      Enum.reduce(times, %{}, fn {time, pids}, acc ->\n        Map.put(acc, :erlang.start_timer(time, self(), :kill), pids)\n      end)\n\n    stacks = wait_children(pids, size, timers, stacks)\n\n    for {pid, {child, reason}} <- stacks do\n      report_error(:shutdown_error, reason, pid, child, state)\n    end\n\n    :ok\n  end\n\n  defp monitor_children(children) do\n    Enum.reduce(children, {%{}, %{}, %{}}, fn\n      {_, {:restarting, _}}, acc ->\n        acc\n\n      {pid, {_, restart, _, _, _} = child}, {pids, times, stacks} ->\n        case monitor_child(pid) do\n          :ok ->\n            times = exit_child(pid, child, times)\n            {Map.put(pids, pid, child), times, stacks}\n\n          {:error, :normal} when restart != :permanent ->\n            {pids, times, stacks}\n\n          {:error, reason} ->\n            {pids, times, Map.put(stacks, pid, {child, reason})}\n        end\n    end)\n  end\n\n  defp monitor_child(pid) do\n    ref = Process.monitor(pid)\n    Process.unlink(pid)\n\n    receive do\n      {:EXIT, ^pid, reason} ->\n        receive do\n          {:DOWN, ^ref, :process, ^pid, _} -> {:error, reason}\n        end\n    after\n      0 -> :ok\n    end\n  end\n\n  defp exit_child(pid, {_, _, shutdown, _, _}, times) do\n    case shutdown do\n      :brutal_kill ->\n        Process.exit(pid, :kill)\n        times\n\n      :infinity ->\n        Process.exit(pid, :shutdown)\n        times\n\n      time ->\n        Process.exit(pid, :shutdown)\n        Map.update(times, time, [pid], &[pid | &1])\n    end\n  end\n\n  defp wait_children(_pids, 0, timers, stacks) do\n    for {timer, _} <- timers do\n      _ = :erlang.cancel_timer(timer)\n\n      receive do\n        {:timeout, ^timer, :kill} -> :ok\n      after\n        0 -> :ok\n      end\n    end\n\n    stacks\n  end\n\n  defp wait_children(pids, size, timers, stacks) do\n    receive do\n      {:DOWN, _ref, :process, pid, reason} ->\n        case pids do\n          %{^pid => child} ->\n            stacks = wait_child(pid, child, reason, stacks)\n            wait_children(pids, size - 1, timers, stacks)\n\n          %{} ->\n            wait_children(pids, size, timers, stacks)\n        end\n\n      {:timeout, timer, :kill} ->\n        for pid <- Map.fetch!(timers, timer), do: Process.exit(pid, :kill)\n        wait_children(pids, size, Map.delete(timers, timer), stacks)\n    end\n  end\n\n  defp wait_child(pid, {_, _, :brutal_kill, _, _} = child, reason, stacks) do\n    case reason do\n      :killed -> stacks\n      _ -> Map.put(stacks, pid, {child, reason})\n    end\n  end\n\n  defp wait_child(pid, {_, restart, _, _, _} = child, reason, stacks) do\n    case reason do\n      {:shutdown, _} -> stacks\n      :shutdown -> stacks\n      :normal when restart != :permanent -> stacks\n      reason -> Map.put(stacks, pid, {child, reason})\n    end\n  end\n\n  defp maybe_restart_child(pid, reason, %{children: children} = state) do\n    case children do\n      %{^pid => {_, restart, _, _, _} = child} ->\n        maybe_restart_child(restart, reason, pid, child, state)\n\n      %{} ->\n        {:ok, state}\n    end\n  end\n\n  defp maybe_restart_child(:permanent, reason, pid, child, state) do\n    report_error(:child_terminated, reason, pid, child, state)\n    restart_child(pid, child, state)\n  end\n\n  defp maybe_restart_child(_, :normal, pid, _child, state) do\n    {:ok, delete_child(pid, state)}\n  end\n\n  defp maybe_restart_child(_, :shutdown, pid, _child, state) do\n    {:ok, delete_child(pid, state)}\n  end\n\n  defp maybe_restart_child(_, {:shutdown, _}, pid, _child, state) do\n    {:ok, delete_child(pid, state)}\n  end\n\n  defp maybe_restart_child(:transient, reason, pid, child, state) do\n    report_error(:child_terminated, reason, pid, child, state)\n    restart_child(pid, child, state)\n  end\n\n  defp maybe_restart_child(:temporary, reason, pid, child, state) do\n    report_error(:child_terminated, reason, pid, child, state)\n    {:ok, delete_child(pid, state)}\n  end\n\n  defp delete_child(pid, %{children: children} = state) do\n    %{state | children: Map.delete(children, pid)}\n  end\n\n  defp restart_child(pid, child, state) do\n    case add_restart(state) do\n      {:ok, %{strategy: strategy} = state} ->\n        case restart_child(strategy, pid, child, state) do\n          {:ok, state} ->\n            {:ok, state}\n\n          {:try_again, state} ->\n            send(self(), {:\"$gen_restart\", pid})\n            {:ok, state}\n        end\n\n      {:shutdown, state} ->\n        report_error(:shutdown, :reached_max_restart_intensity, pid, child, state)\n        {:shutdown, delete_child(pid, state)}\n    end\n  end\n\n  defp add_restart(state) do\n    %{max_seconds: max_seconds, max_restarts: max_restarts, restarts: restarts} = state\n\n    now = :erlang.monotonic_time(1)\n    restarts = add_restart([now | restarts], now, max_seconds)\n    state = %{state | restarts: restarts}\n\n    if length(restarts) <= max_restarts do\n      {:ok, state}\n    else\n      {:shutdown, state}\n    end\n  end\n\n  defp add_restart(restarts, now, period) do\n    for then <- restarts, now <= then + period, do: then\n  end\n\n  defp restart_child(:one_for_one, current_pid, child, state) do\n    {{m, f, args} = mfa, restart, shutdown, type, modules} = child\n    %{extra_arguments: extra} = state\n\n    case start_child(m, f, extra ++ args) do\n      {:ok, pid, _} ->\n        state = delete_child(current_pid, state)\n        {:ok, save_child(pid, mfa, restart, shutdown, type, modules, state)}\n\n      {:ok, pid} ->\n        state = delete_child(current_pid, state)\n        {:ok, save_child(pid, mfa, restart, shutdown, type, modules, state)}\n\n      :ignore ->\n        {:ok, delete_child(current_pid, state)}\n\n      {:error, reason} ->\n        report_error(:start_error, reason, {:restarting, current_pid}, child, state)\n        state = put_in(state.children[current_pid], {:restarting, child})\n        {:try_again, state}\n    end\n  end\n\n  defp report_error(error, reason, pid, child, %{name: name, extra_arguments: extra}) do\n    :logger.error(\n      %{\n        label: {:supervisor, error},\n        report: [\n          {:supervisor, name},\n          {:errorContext, error},\n          {:reason, reason},\n          {:offender, extract_child(pid, child, extra)}\n        ]\n      },\n      %{\n        domain: [:otp, :sasl],\n        report_cb: &:logger.format_otp_report/1,\n        logger_formatter: %{title: \"SUPERVISOR REPORT\"},\n        error_logger: %{tag: :error_report, type: :supervisor_report}\n      }\n    )\n  end\n\n  defp extract_child(pid, {{m, f, args}, restart, shutdown, type, _modules}, extra) do\n    [\n      pid: pid,\n      id: :undefined,\n      mfargs: {m, f, extra ++ args},\n      restart_type: restart,\n      shutdown: shutdown,\n      child_type: type\n    ]\n  end\n\n  ## Helpers\n\n  @compile {:inline, call: 2}\n\n  defp call(supervisor, req) do\n    GenServer.call(supervisor, req, :infinity)\n  end\n\n  @doc false\n  def format_report(%{\n        label: {__MODULE__, :unexpected_msg},\n        report: %{msg: msg}\n      }) do\n    {~c\"DynamicSupervisor received unexpected message: ~p~n\", [msg]}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/enum.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefprotocol Enumerable do\n  @moduledoc \"\"\"\n  Enumerable protocol used by `Enum` and `Stream` modules.\n\n  When you invoke a function in the `Enum` module, the first argument\n  is usually a collection that must implement this protocol.\n  For example, the expression `Enum.map([1, 2, 3], &(&1 * 2))`\n  invokes `Enumerable.reduce/3` to perform the reducing operation that\n  builds a mapped list by calling the mapping function `&(&1 * 2)` on\n  every element in the collection and consuming the element with an\n  accumulated list.\n\n  Internally, `Enum.map/2` is implemented as follows:\n\n      def map(enumerable, fun) do\n        reducer = fn x, acc -> {:cont, [fun.(x) | acc]} end\n        Enumerable.reduce(enumerable, {:cont, []}, reducer) |> elem(1) |> :lists.reverse()\n      end\n\n  Note that the user-supplied function is wrapped into a `t:reducer/0` function.\n  The `t:reducer/0` function must return a tagged tuple after each step,\n  as described in the `t:acc/0` type. At the end, `Enumerable.reduce/3`\n  returns `t:result/0`.\n\n  This protocol uses tagged tuples to exchange information between the\n  reducer function and the data type that implements the protocol. This\n  allows enumeration of resources, such as files, to be done efficiently\n  while also guaranteeing the resource will be closed at the end of the\n  enumeration. This protocol also allows suspension of the enumeration,\n  which is useful when interleaving between many enumerables is required\n  (as in the `zip/1` and `zip/2` functions).\n\n  This protocol requires four functions to be implemented, `reduce/3`,\n  `count/1`, `member?/2`, and `slice/1`. The core of the protocol is the\n  `reduce/3` function. All other functions exist as optimizations paths\n  for data structures that can implement certain properties in better\n  than linear time.\n\n  ## Default implementation for lists\n\n  Sometimes you may want to implement this protocol for a list contained\n  in struct. This can be done by delegating to the `Enumerable.List` module\n  in the `reduce/3` implementation and providing a straight-forward\n  implementation for the remaining ones:\n\n      defimpl Enumerable, for: CustomStruct do\n        def count(struct), do: {:ok, length(struct.items)}\n        def member?(struct, value), do: {:ok, value in struct.items}\n        def slice(struct), do: {:error, __MODULE__}\n        def reduce(struct, acc, fun), do: Enumerable.List.reduce(struct.items, acc, fun)\n      end\n  \"\"\"\n\n  @typedoc \"\"\"\n  An enumerable of elements of type `element`.\n\n  This type is equivalent to `t:t/0` but is especially useful for documentation.\n\n  For example, imagine you define a function that expects an enumerable of\n  integers and returns an enumerable of strings:\n\n      @spec integers_to_strings(Enumerable.t(integer())) :: Enumerable.t(String.t())\n      def integers_to_strings(integers) do\n        Stream.map(integers, &Integer.to_string/1)\n      end\n\n  \"\"\"\n  @typedoc since: \"1.14.0\"\n  @type t(_element) :: t()\n\n  @typedoc \"\"\"\n  The accumulator value for each step.\n\n  It must be a tagged tuple with one of the following \"tags\":\n\n    * `:cont`    - the enumeration should continue\n    * `:halt`    - the enumeration should halt immediately\n    * `:suspend` - the enumeration should be suspended immediately\n\n  Depending on the accumulator value, the result returned by\n  `Enumerable.reduce/3` will change. Please check the `t:result/0`\n  type documentation for more information.\n\n  In case a `t:reducer/0` function returns a `:suspend` accumulator,\n  it must be explicitly handled by the caller and never leak.\n  \"\"\"\n  @type acc :: {:cont, term} | {:halt, term} | {:suspend, term}\n\n  @typedoc \"\"\"\n  The reducer function.\n\n  Should be called with the `enumerable` element and the\n  accumulator contents.\n\n  Returns the accumulator for the next enumeration step.\n  \"\"\"\n  @type reducer :: (element :: term, element_acc :: term -> acc)\n\n  @typedoc \"\"\"\n  The result of the reduce operation.\n\n  It may be *done* when the enumeration is finished by reaching\n  its end, or *halted*/*suspended* when the enumeration was halted\n  or suspended by the tagged accumulator.\n\n  In case the tagged `:halt` accumulator is given, the `:halted` tuple\n  with the accumulator must be returned. Functions like `Enum.take_while/2`\n  use `:halt` underneath and can be used to test halting enumerables.\n\n  In case the tagged `:suspend` accumulator is given, the caller must\n  return the `:suspended` tuple with the accumulator and a continuation.\n  The caller is then responsible of managing the continuation and the\n  caller must always call the continuation, eventually halting or continuing\n  until the end. `Enum.zip/2` uses suspension, so it can be used to test\n  whether your implementation handles suspension correctly. You can also use\n  `Stream.zip/2` with `Enum.take_while/2` to test the combination of\n  `:suspend` with `:halt`.\n  \"\"\"\n  @type result ::\n          {:done, term}\n          | {:halted, term}\n          | {:suspended, term, continuation}\n\n  @typedoc \"\"\"\n  A partially applied reduce function.\n\n  The continuation is the closure returned as a result when\n  the enumeration is suspended. When invoked, it expects\n  a new accumulator and it returns the result.\n\n  A continuation can be trivially implemented as long as the reduce\n  function is defined in a tail recursive fashion. If the function\n  is tail recursive, all the state is passed as arguments, so\n  the continuation is the reducing function partially applied.\n  \"\"\"\n  @type continuation :: (acc -> result)\n\n  @typedoc \"\"\"\n  A slicing function that receives the initial position,\n  the number of elements in the slice, and the step.\n\n  The `start` position is a number `>= 0` and guaranteed to\n  exist in the `enumerable`. The length is a number `>= 1`\n  in a way that `start + length * step <= count`, where\n  `count` is the maximum amount of elements in the enumerable.\n\n  The function should return a non empty list where\n  the amount of elements is equal to `length`.\n  \"\"\"\n  @type slicing_fun ::\n          (start :: non_neg_integer, length :: pos_integer, step :: pos_integer -> [term()])\n\n  @typedoc \"\"\"\n  Receives an enumerable and returns a list.\n  \"\"\"\n  @type to_list_fun :: (t -> [term()])\n\n  @doc \"\"\"\n  Reduces the `enumerable` into an element.\n\n  Most of the operations in `Enum` are implemented in terms of reduce.\n  This function should apply the given `t:reducer/0` function to each\n  element in the `enumerable` and proceed as expected by the returned\n  accumulator.\n\n  See the documentation of the types `t:result/0` and `t:acc/0` for\n  more information.\n\n  ## Examples\n\n  As an example, here is the implementation of `reduce` for lists:\n\n      def reduce(_list, {:halt, acc}, _fun), do: {:halted, acc}\n      def reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &reduce(list, &1, fun)}\n      def reduce([], {:cont, acc}, _fun), do: {:done, acc}\n      def reduce([head | tail], {:cont, acc}, fun), do: reduce(tail, fun.(head, acc), fun)\n\n  \"\"\"\n  @spec reduce(t, acc, reducer) :: result\n  def reduce(enumerable, acc, fun)\n\n  @doc \"\"\"\n  Retrieves the number of elements in the `enumerable`.\n\n  It should return `{:ok, count}` if you can count the number of elements\n  in `enumerable` in a faster way than fully traversing it.\n\n  Otherwise it should return `{:error, __MODULE__}` and a default algorithm\n  built on top of `reduce/3` that runs in linear time will be used.\n  \"\"\"\n  @spec count(t) :: {:ok, non_neg_integer} | {:error, module}\n  def count(enumerable)\n\n  @doc \"\"\"\n  Checks if an `element` exists within the `enumerable`.\n\n  It should return `{:ok, boolean}` if you can check the membership of a\n  given element in `enumerable` with `===/2` without traversing the whole\n  of it.\n\n  Otherwise it should return `{:error, __MODULE__}` and a default algorithm\n  built on top of `reduce/3` that runs in linear time will be used.\n\n  When called outside guards, the [`in`](`in/2`) and [`not in`](`in/2`)\n  operators work by using this function.\n  \"\"\"\n  @spec member?(t, term) :: {:ok, boolean} | {:error, module}\n  def member?(enumerable, element)\n\n  @doc \"\"\"\n  Returns a function that slices the data structure contiguously.\n\n  It should return either:\n\n    * `{:ok, size, slicing_fun}` - if the `enumerable` has a known\n      bound and can access a position in the `enumerable` without\n      traversing all previous elements. The `slicing_fun` will receive\n      a `start` position, the `amount` of elements to fetch, and a\n      `step`.\n\n    * `{:ok, size, to_list_fun}` - if the `enumerable` has a known bound\n      and can access a position in the `enumerable` by first converting\n      it to a list via `to_list_fun`.\n\n    * `{:error, __MODULE__}` - the enumerable cannot be sliced efficiently\n      and a default algorithm built on top of `reduce/3` that runs in\n      linear time will be used.\n\n  ## Differences to `count/1`\n\n  The `size` value returned by this function is used for boundary checks,\n  therefore it is extremely important that this function only returns `:ok`\n  if retrieving the `size` of the `enumerable` is cheap, fast, and takes\n  constant time. Otherwise the simplest of operations, such as\n  `Enum.at(enumerable, 0)`, will become too expensive.\n\n  On the other hand, the `count/1` function in this protocol should be\n  implemented whenever you can count the number of elements in the collection\n  without traversing it.\n  \"\"\"\n  @spec slice(t) ::\n          {:ok, size :: non_neg_integer(), slicing_fun() | to_list_fun()}\n          | {:error, module()}\n  def slice(enumerable)\nend\n\ndefmodule Enum do\n  import Kernel, except: [max: 2, min: 2]\n\n  @moduledoc \"\"\"\n  Functions for working with collections (known as enumerables).\n\n  In Elixir, an enumerable is any data type that implements the\n  `Enumerable` protocol. `List`s (`[1, 2, 3]`), `Map`s (`%{foo: 1, bar: 2}`)\n  and `Range`s (`1..3`) are common data types used as enumerables:\n\n      iex> Enum.map([1, 2, 3], fn x -> x * 2 end)\n      [2, 4, 6]\n\n      iex> Enum.sum([1, 2, 3])\n      6\n\n      iex> Enum.map(1..3, fn x -> x * 2 end)\n      [2, 4, 6]\n\n      iex> Enum.sum(1..3)\n      6\n\n      iex> map = %{\"a\" => 1, \"b\" => 2}\n      iex> Enum.map(map, fn {k, v} -> {k, v * 2} end)\n      [{\"a\", 2}, {\"b\", 4}]\n\n  Many other enumerables exist in the language, such as `MapSet`s\n  and the data type returned by `File.stream!/3` which allows a file to be\n  traversed as if it was an enumerable.\n\n  For a general overview of all functions in the `Enum` module, see\n  [the `Enum` cheatsheet](enum-cheat.cheatmd).\n\n  The functions in this module work in linear time. This means that, the\n  time it takes to perform an operation grows at the same rate as the length\n  of the enumerable. This is expected on operations such as `Enum.map/2`.\n  After all, if we want to traverse every element on a list, the longer the\n  list, the more elements we need to traverse, and the longer it will take.\n\n  This linear behavior should also be expected on operations like `count/1`,\n  `member?/2`, `at/2` and similar. While Elixir does allow data types to\n  provide performant variants for such operations, you should not expect it\n  to always be available, since the `Enum` module is meant to work with a\n  large variety of data types and not all data types can provide optimized\n  behavior.\n\n  Finally, note the functions in the `Enum` module are eager: they will\n  traverse the enumerable as soon as they are invoked. This is particularly\n  dangerous when working with infinite enumerables. In such cases, you should\n  use the `Stream` module, which allows you to lazily express computations,\n  without traversing collections, and work with possibly infinite collections.\n  See the `Stream` module for examples and documentation.\n  \"\"\"\n\n  @compile :inline_list_funcs\n\n  @type t :: Enumerable.t()\n  @type acc :: any\n  @type element :: any\n\n  @typedoc \"Zero-based index. It can also be a negative integer.\"\n  @type index :: integer\n\n  @type default :: any\n\n  require Stream.Reducers, as: R\n\n  defmacrop skip(acc) do\n    acc\n  end\n\n  defmacrop next(_, entry, acc) do\n    quote(do: [unquote(entry) | unquote(acc)])\n  end\n\n  defmacrop acc(head, state, _) do\n    quote(do: {unquote(head), unquote(state)})\n  end\n\n  defmacrop next_with_acc(_, entry, head, state, _) do\n    quote do\n      {[unquote(entry) | unquote(head)], unquote(state)}\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if all elements in `enumerable` are truthy.\n\n  When an element has a falsy value (`false` or `nil`) iteration stops immediately\n  and `false` is returned. In all other cases `true` is returned.\n\n  ## Examples\n\n      iex> Enum.all?([1, 2, 3])\n      true\n\n      iex> Enum.all?([1, nil, 3])\n      false\n\n      iex> Enum.all?([])\n      true\n\n  \"\"\"\n  @spec all?(t) :: boolean\n  def all?(enumerable) when is_list(enumerable) do\n    all_list(enumerable)\n  end\n\n  def all?(enumerable) do\n    Enumerable.reduce(enumerable, {:cont, true}, fn entry, _ ->\n      if entry, do: {:cont, true}, else: {:halt, false}\n    end)\n    |> elem(1)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `fun.(element)` is truthy for all elements in `enumerable`.\n\n  Iterates over `enumerable` and invokes `fun` on each element. If `fun` ever\n  returns a falsy value (`false` or `nil`), iteration stops immediately and\n  `false` is returned. Otherwise, `true` is returned.\n\n  ## Examples\n\n      iex> Enum.all?([2, 4, 6], fn x -> rem(x, 2) == 0 end)\n      true\n\n      iex> Enum.all?([2, 3, 4], fn x -> rem(x, 2) == 0 end)\n      false\n\n      iex> Enum.all?([], fn _ -> nil end)\n      true\n\n  As the last example shows, `Enum.all?/2` returns `true` if `enumerable` is\n  empty, regardless of `fun`. In an empty enumerable there is no element for\n  which `fun` returns a falsy value, so the result must be `true`. This is a\n  well-defined logical argument for empty collections.\n\n  \"\"\"\n  @spec all?(t, (element -> as_boolean(term))) :: boolean\n  def all?(enumerable, fun) when is_list(enumerable) do\n    predicate_list(enumerable, true, fun)\n  end\n\n  def all?(first..last//step, fun) do\n    predicate_range(first, last, step, true, fun)\n  end\n\n  def all?(enumerable, fun) do\n    Enumerable.reduce(enumerable, {:cont, true}, fn entry, _ ->\n      if fun.(entry), do: {:cont, true}, else: {:halt, false}\n    end)\n    |> elem(1)\n  end\n\n  @doc \"\"\"\n  Returns `true` if at least one element in `enumerable` is truthy.\n\n  When an element has a truthy value (neither `false` nor `nil`) iteration stops\n  immediately and `true` is returned. In all other cases `false` is returned.\n\n  ## Examples\n\n      iex> Enum.any?([false, false, false])\n      false\n\n      iex> Enum.any?([false, true, false])\n      true\n\n      iex> Enum.any?([])\n      false\n\n  \"\"\"\n  @spec any?(t) :: boolean\n  def any?(enumerable) when is_list(enumerable) do\n    any_list(enumerable)\n  end\n\n  def any?(enumerable) do\n    Enumerable.reduce(enumerable, {:cont, false}, fn entry, _ ->\n      if entry, do: {:halt, true}, else: {:cont, false}\n    end)\n    |> elem(1)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `fun.(element)` is truthy for at least one element in `enumerable`.\n\n  Iterates over the `enumerable` and invokes `fun` on each element. When an invocation\n  of `fun` returns a truthy value (neither `false` nor `nil`) iteration stops\n  immediately and `true` is returned. In all other cases `false` is returned.\n\n  ## Examples\n\n      iex> Enum.any?([2, 4, 6], fn x -> rem(x, 2) == 1 end)\n      false\n\n      iex> Enum.any?([2, 3, 4], fn x -> rem(x, 2) == 1 end)\n      true\n\n      iex> Enum.any?([], fn x -> x > 0 end)\n      false\n\n  \"\"\"\n  @spec any?(t, (element -> as_boolean(term))) :: boolean\n  def any?(enumerable, fun) when is_list(enumerable) do\n    predicate_list(enumerable, false, fun)\n  end\n\n  def any?(first..last//step, fun) do\n    predicate_range(first, last, step, false, fun)\n  end\n\n  def any?(enumerable, fun) do\n    Enumerable.reduce(enumerable, {:cont, false}, fn entry, _ ->\n      if fun.(entry), do: {:halt, true}, else: {:cont, false}\n    end)\n    |> elem(1)\n  end\n\n  @doc \"\"\"\n  Finds the element at the given `index` (zero-based).\n\n  Returns `default` if `index` is out of bounds.\n\n  A negative `index` can be passed, which means the `enumerable` is\n  enumerated once and the `index` is counted from the end (for example,\n  `-1` finds the last element).\n\n  ## Examples\n\n      iex> Enum.at([2, 4, 6], 0)\n      2\n\n      iex> Enum.at([2, 4, 6], 2)\n      6\n\n      iex> Enum.at([2, 4, 6], 4)\n      nil\n\n      iex> Enum.at([2, 4, 6], 4, :none)\n      :none\n\n  \"\"\"\n  @spec at(t, index, default) :: element | default\n  def at(enumerable, index, default \\\\ nil) when is_integer(index) do\n    case slice_forward(enumerable, index, 1, 1) do\n      [value] -> value\n      [] -> default\n    end\n  end\n\n  @doc false\n  @deprecated \"Use Enum.chunk_every/2 instead\"\n  def chunk(enumerable, count), do: chunk(enumerable, count, count, nil)\n\n  @doc false\n  @deprecated \"Use Enum.chunk_every/3 instead\"\n  def chunk(enum, n, step) do\n    chunk_every(enum, n, step, :discard)\n  end\n\n  @doc false\n  @deprecated \"Use Enum.chunk_every/4 instead\"\n  def chunk(enumerable, count, step, leftover) do\n    chunk_every(enumerable, count, step, leftover || :discard)\n  end\n\n  @doc \"\"\"\n  Shortcut to `chunk_every(enumerable, count, count)`.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec chunk_every(t, pos_integer) :: [list]\n  def chunk_every(enumerable, count), do: chunk_every(enumerable, count, count, [])\n\n  @doc \"\"\"\n  Returns list of lists containing `count` elements each, where\n  each new chunk starts `step` elements into the `enumerable`.\n\n  `step` is optional and, if not passed, defaults to `count`, i.e.\n  chunks do not overlap. Chunking will stop as soon as the collection\n  ends or when we emit an incomplete chunk.\n\n  If the last chunk does not have `count` elements to fill the chunk,\n  elements are taken from `leftover` to fill in the chunk. If `leftover`\n  does not have enough elements to fill the chunk, then a partial chunk\n  is returned with less than `count` elements.\n\n  If `:discard` is given in `leftover`, the last chunk is discarded\n  unless it has exactly `count` elements.\n\n  ## Examples\n\n      iex> Enum.chunk_every([1, 2, 3, 4, 5, 6], 2)\n      [[1, 2], [3, 4], [5, 6]]\n\n      iex> Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, :discard)\n      [[1, 2, 3], [3, 4, 5]]\n\n      iex> Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, [7])\n      [[1, 2, 3], [3, 4, 5], [5, 6, 7]]\n\n      iex> Enum.chunk_every([1, 2, 3, 4], 3, 3, [])\n      [[1, 2, 3], [4]]\n\n      iex> Enum.chunk_every([1, 2, 3, 4], 10)\n      [[1, 2, 3, 4]]\n\n      iex> Enum.chunk_every([1, 2, 3, 4, 5], 2, 3, [])\n      [[1, 2], [4, 5]]\n\n      iex> Enum.chunk_every([1, 2, 3, 4], 3, 3, Stream.cycle([0]))\n      [[1, 2, 3], [4, 0, 0]]\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec chunk_every(t, pos_integer, pos_integer, t | :discard) :: [list]\n  def chunk_every(enumerable, count, step, leftover \\\\ [])\n      when is_integer(count) and count > 0 and is_integer(step) and step > 0 do\n    R.chunk_every(&chunk_while/4, enumerable, count, step, leftover)\n  end\n\n  @doc \"\"\"\n  Chunks the `enumerable` with fine grained control when every chunk is emitted.\n\n  `chunk_fun` receives the current element and the accumulator and must return:\n\n    * `{:cont, chunk, acc}` to emit a chunk and continue with the accumulator\n    * `{:cont, acc}` to not emit any chunk and continue with the accumulator\n    * `{:halt, acc}` to halt chunking over the `enumerable`.\n\n  `after_fun` is invoked with the final accumulator when iteration is\n  finished (or `halt`ed) to handle any trailing elements that were returned\n  as part of an accumulator, but were not emitted as a chunk by `chunk_fun`.\n  It must return:\n\n    * `{:cont, chunk, acc}` to emit a chunk. The chunk will be appended to the\n      list of already emitted chunks.\n    * `{:cont, acc}` to not emit a chunk\n\n  The `acc` in `after_fun` is required in order to mirror the tuple format\n  from `chunk_fun` but it will be discarded since the traversal is complete.\n\n  Returns a list of emitted chunks.\n\n  ## Examples\n\n      iex> chunk_fun = fn element, acc ->\n      ...>   if rem(element, 2) == 0 do\n      ...>     {:cont, Enum.reverse([element | acc]), []}\n      ...>   else\n      ...>     {:cont, [element | acc]}\n      ...>   end\n      ...> end\n      iex> after_fun = fn\n      ...>   [] -> {:cont, []}\n      ...>   acc -> {:cont, Enum.reverse(acc), []}\n      ...> end\n      iex> Enum.chunk_while(1..10, [], chunk_fun, after_fun)\n      [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]\n      iex> Enum.chunk_while([1, 2, 3, 5, 7], [], chunk_fun, after_fun)\n      [[1, 2], [3, 5, 7]]\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec chunk_while(\n          t,\n          acc,\n          (element, acc -> {:cont, chunk, acc} | {:cont, acc} | {:halt, acc}),\n          (acc -> {:cont, chunk, acc} | {:cont, acc})\n        ) :: Enumerable.t()\n        when chunk: any\n  def chunk_while(enumerable, acc, chunk_fun, after_fun) do\n    {_, {res, acc}} =\n      Enumerable.reduce(enumerable, {:cont, {[], acc}}, fn entry, {buffer, acc} ->\n        case chunk_fun.(entry, acc) do\n          {:cont, chunk, acc} -> {:cont, {[chunk | buffer], acc}}\n          {:cont, acc} -> {:cont, {buffer, acc}}\n          {:halt, acc} -> {:halt, {buffer, acc}}\n        end\n      end)\n\n    case after_fun.(acc) do\n      {:cont, _acc} -> :lists.reverse(res)\n      {:cont, chunk, _acc} -> :lists.reverse([chunk | res])\n    end\n  end\n\n  @doc \"\"\"\n  Splits enumerable on every element for which `fun` returns a new\n  value.\n\n  Returns a list of lists.\n\n  ## Examples\n\n      iex> Enum.chunk_by([1, 2, 2, 3, 4, 4, 6, 7, 7], &(rem(&1, 2) == 1))\n      [[1], [2, 2], [3], [4, 4, 6], [7, 7]]\n\n  \"\"\"\n  @spec chunk_by(t, (element -> any)) :: [list]\n  def chunk_by(enumerable, fun) do\n    R.chunk_by(&chunk_while/4, enumerable, fun)\n  end\n\n  @doc \"\"\"\n  Given an enumerable of enumerables, concatenates the `enumerables` into\n  a single list.\n\n  ## Examples\n\n      iex> Enum.concat([1..3, 4..6, 7..9])\n      [1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n      iex> Enum.concat([[1, [2], 3], [4], [5, 6]])\n      [1, [2], 3, 4, 5, 6]\n\n  \"\"\"\n  @spec concat(t) :: t\n  def concat(enumerables)\n\n  def concat(list) when is_list(list) do\n    concat_list(list)\n  end\n\n  def concat(enums) do\n    concat_enum(enums)\n  end\n\n  @doc \"\"\"\n  Concatenates the enumerable on the `right` with the enumerable on the\n  `left`.\n\n  This function produces the same result as the `++/2` operator\n  for lists.\n\n  ## Examples\n\n      iex> Enum.concat(1..3, 4..6)\n      [1, 2, 3, 4, 5, 6]\n\n      iex> Enum.concat([1, 2, 3], [4, 5, 6])\n      [1, 2, 3, 4, 5, 6]\n\n  \"\"\"\n  @spec concat(t, t) :: t\n  def concat(left, right) when is_list(left) and is_list(right) do\n    left ++ right\n  end\n\n  def concat(left, right) do\n    concat_enum([left, right])\n  end\n\n  @doc \"\"\"\n  Returns the size of the `enumerable`.\n\n  ## Examples\n\n      iex> Enum.count([1, 2, 3])\n      3\n\n  \"\"\"\n  @spec count(t) :: non_neg_integer\n  def count(enumerable) when is_list(enumerable) do\n    length(enumerable)\n  end\n\n  def count(enumerable) do\n    case Enumerable.count(enumerable) do\n      {:ok, value} when is_integer(value) ->\n        value\n\n      {:error, module} ->\n        enumerable |> module.reduce({:cont, 0}, fn _, acc -> {:cont, acc + 1} end) |> elem(1)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the count of elements in the `enumerable` for which `fun` returns\n  a truthy value.\n\n  ## Examples\n\n      iex> Enum.count([1, 2, 3, 4, 5], fn x -> rem(x, 2) == 0 end)\n      2\n\n  \"\"\"\n  @spec count(t, (element -> as_boolean(term))) :: non_neg_integer\n  def count(enumerable, fun) do\n    reduce(enumerable, 0, fn entry, acc ->\n      if(fun.(entry), do: acc + 1, else: acc)\n    end)\n  end\n\n  @doc \"\"\"\n  Counts the enumerable stopping at `limit`.\n\n  This is useful for checking certain properties of the count of an enumerable\n  without having to actually count the entire enumerable. For example, if you\n  wanted to check that the count was exactly, at least, or more than a value.\n\n  If the enumerable implements `c:Enumerable.count/1`, the enumerable is\n  not traversed and we return the lower of the two numbers. To force\n  enumeration, use `count_until/3` with `fn _ -> true end` as the second\n  argument.\n\n  ## Examples\n\n      iex> Enum.count_until(1..20, 5)\n      5\n      iex> Enum.count_until(1..20, 50)\n      20\n      iex> Enum.count_until(1..10, 10) == 10 # At least 10\n      true\n      iex> Enum.count_until(1..11, 10 + 1) > 10 # More than 10\n      true\n      iex> Enum.count_until(1..5, 10) < 10 # Less than 10\n      true\n      iex> Enum.count_until(1..10, 10 + 1) == 10 # Exactly ten\n      true\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec count_until(t, pos_integer) :: non_neg_integer\n  def count_until(enumerable, limit) when is_integer(limit) and limit > 0 do\n    case enumerable do\n      list when is_list(list) -> count_until_list(list, limit, 0)\n      _ -> count_until_enum(enumerable, limit)\n    end\n  end\n\n  def count_until(_enumerable, limit) when is_integer(limit) do\n    raise ArgumentError, \"expected limit to be greater than 0, got: #{limit}\"\n  end\n\n  @doc \"\"\"\n  Counts the elements in the enumerable for which `fun` returns a truthy value, stopping at `limit`.\n\n  See `count/2` and `count_until/2` for more information.\n\n  ## Examples\n\n      iex> Enum.count_until(1..20, fn x -> rem(x, 2) == 0 end, 7)\n      7\n      iex> Enum.count_until(1..20, fn x -> rem(x, 2) == 0 end, 11)\n      10\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec count_until(t, (element -> as_boolean(term)), pos_integer) :: non_neg_integer\n  def count_until(enumerable, fun, limit) when is_integer(limit) and limit > 0 do\n    case enumerable do\n      list when is_list(list) -> count_until_list(list, fun, limit, 0)\n      _ -> count_until_enum(enumerable, fun, limit)\n    end\n  end\n\n  def count_until(_enumerable, _fun, limit) when is_integer(limit) do\n    raise ArgumentError, \"expected limit to be greater than 0, got: #{limit}\"\n  end\n\n  @doc \"\"\"\n  Enumerates the `enumerable`, returning a list where all consecutive\n  duplicate elements are collapsed to a single element.\n\n  Elements are compared using `===/2`.\n\n  If you want to remove all duplicate elements, regardless of order,\n  see `uniq/1`.\n\n  ## Examples\n\n      iex> Enum.dedup([1, 2, 3, 3, 2, 1])\n      [1, 2, 3, 2, 1]\n\n      iex> Enum.dedup([1, 1, 2, 2.0, :three, :three])\n      [1, 2, 2.0, :three]\n\n  \"\"\"\n  @spec dedup(t) :: list\n  def dedup(enumerable) when is_list(enumerable) do\n    dedup_list(enumerable, []) |> :lists.reverse()\n  end\n\n  def dedup(enumerable) do\n    reduce(enumerable, [], fn x, acc ->\n      case acc do\n        [^x | _] -> acc\n        _ -> [x | acc]\n      end\n    end)\n    |> :lists.reverse()\n  end\n\n  @doc \"\"\"\n  Enumerates the `enumerable`, returning a list where all consecutive\n  duplicate elements are collapsed to a single element.\n\n  The function `fun` maps every element to a term which is used to\n  determine if two elements are duplicates.\n\n  ## Examples\n\n      iex> Enum.dedup_by([{1, :a}, {2, :b}, {2, :c}, {1, :a}], fn {x, _} -> x end)\n      [{1, :a}, {2, :b}, {1, :a}]\n\n      iex> Enum.dedup_by([5, 1, 2, 3, 2, 1], fn x -> x > 2 end)\n      [5, 1, 3, 2]\n\n  \"\"\"\n  @spec dedup_by(t, (element -> term)) :: list\n  def dedup_by(enumerable, fun) do\n    {list, _} = reduce(enumerable, {[], []}, R.dedup(fun))\n    :lists.reverse(list)\n  end\n\n  @doc \"\"\"\n  Drops the `amount` of elements from the `enumerable`.\n\n  If a negative `amount` is given, the `amount` of last values will be dropped.\n  The `enumerable` will be enumerated once to retrieve the proper index and\n  the remaining calculation is performed from the end.\n\n  ## Examples\n\n      iex> Enum.drop([1, 2, 3], 2)\n      [3]\n\n      iex> Enum.drop([1, 2, 3], 10)\n      []\n\n      iex> Enum.drop([1, 2, 3], 0)\n      [1, 2, 3]\n\n      iex> Enum.drop([1, 2, 3], -1)\n      [1, 2]\n\n  \"\"\"\n  @spec drop(t, integer) :: list\n  def drop(enumerable, amount)\n      when is_list(enumerable) and is_integer(amount) and amount >= 0 do\n    drop_list(enumerable, amount)\n  end\n\n  def drop(enumerable, 0) do\n    to_list(enumerable)\n  end\n\n  def drop(enumerable, amount) when is_integer(amount) and amount > 0 do\n    {result, _} = reduce(enumerable, {[], amount}, R.drop())\n    if is_list(result), do: :lists.reverse(result), else: []\n  end\n\n  def drop(enumerable, amount) when is_integer(amount) and amount < 0 do\n    {count, fun} = slice_count_and_fun(enumerable, 1)\n    amount = Kernel.min(amount + count, count)\n\n    if amount > 0 do\n      fun.(0, amount, 1)\n    else\n      []\n    end\n  end\n\n  @doc \"\"\"\n  Returns a list of every `nth` element in the `enumerable` dropped,\n  starting with the first element.\n\n  The first element is always dropped, unless `nth` is 0.\n\n  The second argument specifying every `nth` element must be a non-negative\n  integer.\n\n  ## Examples\n\n      iex> Enum.drop_every(1..10, 2)\n      [2, 4, 6, 8, 10]\n\n      iex> Enum.drop_every(1..10, 0)\n      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n      iex> Enum.drop_every([1, 2, 3], 1)\n      []\n\n  \"\"\"\n  @spec drop_every(t, non_neg_integer) :: list\n  def drop_every(enumerable, nth)\n\n  def drop_every(_enumerable, 1), do: []\n  def drop_every(enumerable, 0), do: to_list(enumerable)\n  def drop_every([], nth) when is_integer(nth), do: []\n\n  def drop_every(enumerable, nth) when is_integer(nth) and nth > 1 do\n    {res, _} = reduce(enumerable, {[], :first}, R.drop_every(nth))\n    :lists.reverse(res)\n  end\n\n  @doc \"\"\"\n  Drops elements at the beginning of the `enumerable` while `fun` returns a\n  truthy value.\n\n  ## Examples\n\n      iex> Enum.drop_while([1, 2, 3, 2, 1], fn x -> x < 3 end)\n      [3, 2, 1]\n\n  \"\"\"\n  @spec drop_while(t, (element -> as_boolean(term))) :: list\n  def drop_while(enumerable, fun) when is_list(enumerable) do\n    drop_while_list(enumerable, fun)\n  end\n\n  def drop_while(enumerable, fun) do\n    {res, _} = reduce(enumerable, {[], true}, R.drop_while(fun))\n    :lists.reverse(res)\n  end\n\n  @doc \"\"\"\n  Invokes the given `fun` for each element in the `enumerable`.\n\n  Returns `:ok`.\n\n  ## Examples\n\n      Enum.each([\"some\", \"example\"], fn x -> IO.puts(x) end)\n      some\n      example\n      #=> :ok\n\n  \"\"\"\n  @spec each(t, (element -> any)) :: :ok\n  def each(enumerable, fun) when is_list(enumerable) do\n    :lists.foreach(fun, enumerable)\n  end\n\n  def each(enumerable, fun) do\n    reduce(enumerable, nil, fn entry, _ ->\n      fun.(entry)\n      nil\n    end)\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Determines if the `enumerable` is empty.\n\n  Returns `true` if `enumerable` is empty, otherwise `false`.\n\n  ## Examples\n\n      iex> Enum.empty?([])\n      true\n\n      iex> Enum.empty?([1, 2, 3])\n      false\n\n  \"\"\"\n  @spec empty?(t) :: boolean\n  def empty?(enumerable) when is_list(enumerable) do\n    enumerable == []\n  end\n\n  def empty?(enumerable) do\n    case Enumerable.slice(enumerable) do\n      {:ok, value, _} ->\n        value == 0\n\n      {:error, module} ->\n        enumerable\n        |> module.reduce({:cont, true}, fn _, _ -> {:halt, false} end)\n        |> elem(1)\n    end\n  end\n\n  @doc \"\"\"\n  Finds the element at the given `index` (zero-based).\n\n  Returns `{:ok, element}` if found, otherwise `:error`.\n\n  A negative `index` can be passed, which means the `enumerable` is\n  enumerated once and the `index` is counted from the end (for example,\n  `-1` fetches the last element).\n\n  ## Examples\n\n      iex> Enum.fetch([2, 4, 6], 0)\n      {:ok, 2}\n\n      iex> Enum.fetch([2, 4, 6], -3)\n      {:ok, 2}\n\n      iex> Enum.fetch([2, 4, 6], 2)\n      {:ok, 6}\n\n      iex> Enum.fetch([2, 4, 6], 4)\n      :error\n\n  \"\"\"\n  @spec fetch(t, index) :: {:ok, element} | :error\n  def fetch(enumerable, index) when is_integer(index) do\n    case slice_forward(enumerable, index, 1, 1) do\n      [value] -> {:ok, value}\n      [] -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Finds the element at the given `index` (zero-based).\n\n  Raises `OutOfBoundsError` if the given `index` is outside the range of\n  the `enumerable`.\n\n  ## Examples\n\n      iex> Enum.fetch!([2, 4, 6], 0)\n      2\n\n      iex> Enum.fetch!([2, 4, 6], 2)\n      6\n\n      iex> Enum.fetch!([2, 4, 6], 4)\n      ** (Enum.OutOfBoundsError) out of bounds error at position 4 when traversing enumerable [2, 4, 6]\n\n  \"\"\"\n  @spec fetch!(t, index) :: element\n  def fetch!(enumerable, index) when is_integer(index) do\n    case slice_forward(enumerable, index, 1, 1) do\n      [value] -> value\n      [] -> raise Enum.OutOfBoundsError, index: index, enumerable: enumerable\n    end\n  end\n\n  @doc \"\"\"\n  Filters the `enumerable`, i.e. returns only those elements\n  for which `fun` returns a truthy value.\n\n  See also `reject/2` which discards all elements where the\n  function returns a truthy value.\n\n  ## Examples\n\n      iex> Enum.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end)\n      [2]\n      iex> Enum.filter([\"apple\", \"pear\", \"banana\"], fn fruit -> String.contains?(fruit, \"a\") end)\n      [\"apple\", \"pear\", \"banana\"]\n      iex> Enum.filter([4, 21, 24, 904], fn seconds -> seconds > 1000 end)\n      []\n\n  Keep in mind that `filter` is not capable of filtering and\n  transforming an element at the same time. If you would like\n  to do so, consider using `flat_map/2`. For example, if you\n  want to convert all strings that represent an integer and\n  discard the invalid one in one pass:\n\n      strings = [\"1234\", \"abc\", \"12ab\"]\n\n      Enum.flat_map(strings, fn string ->\n        case Integer.parse(string) do\n          # transform to integer\n          {int, _rest} -> [int]\n          # skip the value\n          :error -> []\n        end\n      end)\n\n  \"\"\"\n  @spec filter(t, (element -> as_boolean(term))) :: list\n  def filter(enumerable, fun) when is_list(enumerable) do\n    filter_list(enumerable, fun)\n  end\n\n  def filter(enumerable, fun) do\n    reduce(enumerable, [], R.filter(fun)) |> :lists.reverse()\n  end\n\n  @doc false\n  @deprecated \"Use Enum.filter/2 + Enum.map/2 or for comprehensions instead\"\n  def filter_map(enumerable, filter, mapper) when is_list(enumerable) do\n    for element <- enumerable, filter.(element), do: mapper.(element)\n  end\n\n  def filter_map(enumerable, filter, mapper) do\n    enumerable\n    |> reduce([], R.filter_map(filter, mapper))\n    |> :lists.reverse()\n  end\n\n  @doc \"\"\"\n  Returns the first element for which `fun` returns a truthy value.\n  If no such element is found, returns `default`.\n\n  ## Examples\n\n      iex> Enum.find([2, 3, 4], fn x -> rem(x, 2) == 1 end)\n      3\n\n      iex> Enum.find([2, 4, 6], fn x -> rem(x, 2) == 1 end)\n      nil\n      iex> Enum.find([2, 4, 6], 0, fn x -> rem(x, 2) == 1 end)\n      0\n\n  \"\"\"\n  @spec find(t, default, (element -> any)) :: element | default\n  def find(enumerable, default \\\\ nil, fun)\n\n  def find(enumerable, default, fun) when is_list(enumerable) do\n    find_list(enumerable, default, fun)\n  end\n\n  def find(enumerable, default, fun) do\n    Enumerable.reduce(enumerable, {:cont, default}, fn entry, default ->\n      if fun.(entry), do: {:halt, entry}, else: {:cont, default}\n    end)\n    |> elem(1)\n  end\n\n  @doc \"\"\"\n  Similar to `find/3`, but returns the index (zero-based)\n  of the element instead of the element itself.\n\n  ## Examples\n\n      iex> Enum.find_index([2, 4, 6], fn x -> rem(x, 2) == 1 end)\n      nil\n\n      iex> Enum.find_index([2, 3, 4], fn x -> rem(x, 2) == 1 end)\n      1\n\n  \"\"\"\n  @spec find_index(t, (element -> any)) :: non_neg_integer | nil\n  def find_index(enumerable, fun) when is_list(enumerable) do\n    find_index_list(enumerable, 0, fun)\n  end\n\n  def find_index(enumerable, fun) do\n    result =\n      Enumerable.reduce(enumerable, {:cont, {:not_found, 0}}, fn entry, {_, index} ->\n        if fun.(entry), do: {:halt, {:found, index}}, else: {:cont, {:not_found, index + 1}}\n      end)\n\n    case elem(result, 1) do\n      {:found, index} -> index\n      {:not_found, _} -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Similar to `find/3`, but returns the value of the function\n  invocation instead of the element itself.\n\n  The return value is considered to be found when the result is truthy\n  (neither `nil` nor `false`).\n\n  ## Examples\n\n      iex> Enum.find_value([2, 3, 4], fn x ->\n      ...>   if x > 2, do: x * x\n      ...> end)\n      9\n\n      iex> Enum.find_value([2, 4, 6], fn x -> rem(x, 2) == 1 end)\n      nil\n\n      iex> Enum.find_value([2, 3, 4], fn x -> rem(x, 2) == 1 end)\n      true\n\n      iex> Enum.find_value([1, 2, 3], \"no bools!\", &is_boolean/1)\n      \"no bools!\"\n\n  \"\"\"\n  @spec find_value(t, default, (element -> found_value)) :: found_value | default\n        when found_value: term\n  def find_value(enumerable, default \\\\ nil, fun)\n\n  def find_value(enumerable, default, fun) when is_list(enumerable) do\n    find_value_list(enumerable, default, fun)\n  end\n\n  def find_value(enumerable, default, fun) do\n    Enumerable.reduce(enumerable, {:cont, default}, fn entry, default ->\n      fun_entry = fun.(entry)\n      if fun_entry, do: {:halt, fun_entry}, else: {:cont, default}\n    end)\n    |> elem(1)\n  end\n\n  @doc \"\"\"\n  Maps the given `fun` over `enumerable` and flattens the result only one level deep.\n\n  This function returns a new enumerable built by appending the result of invoking `fun`\n  on each element of `enumerable` together; conceptually, this is similar to a\n  combination of `map/2` and `concat/1`.\n\n  ## Examples\n\n      iex> Enum.flat_map([:a, :b, :c], fn x -> [x, x] end)\n      [:a, :a, :b, :b, :c, :c]\n\n      iex> Enum.flat_map([{1, 3}, {4, 6}], fn {x, y} -> x..y end)\n      [1, 2, 3, 4, 5, 6]\n\n      iex> Enum.flat_map([:a, :b, :c], fn x -> [[x]] end)\n      [[:a], [:b], [:c]]\n\n  This is frequently used to transform and filter in one pass, returning empty\n  lists to exclude results:\n\n      iex> Enum.flat_map([4, 0, 2, 0], fn x ->\n      ...>   if x != 0, do: [1 / x], else: []\n      ...> end)\n      [0.25, 0.5]\n\n  \"\"\"\n  @spec flat_map(t, (element -> t)) :: list\n  def flat_map(enumerable, fun) when is_list(enumerable) do\n    flat_map_list(enumerable, fun)\n  end\n\n  def flat_map(enumerable, fun) do\n    reduce(enumerable, [], fn entry, acc ->\n      case fun.(entry) do\n        [] -> acc\n        list when is_list(list) -> [list | acc]\n        other -> [to_list(other) | acc]\n      end\n    end)\n    |> flat_reverse([])\n  end\n\n  # the first clause is an optimization\n  defp flat_reverse([[elem] | t], acc), do: flat_reverse(t, [elem | acc])\n  defp flat_reverse([h | t], acc), do: flat_reverse(t, h ++ acc)\n  defp flat_reverse([], acc), do: acc\n\n  @doc \"\"\"\n  Maps and reduces an `enumerable`, flattening the results only one level deep.\n\n  It expects an accumulator and a function that receives each enumerable\n  element, and must return a tuple containing a new enumerable (often a list)\n  with the new accumulator or a tuple with `:halt` as first element and\n  the accumulator as second.\n\n  Returns a 2-element tuple where the first element is the results flattened one level deep and\n  the second element is the last accumulator.\n\n  ## Examples\n\n      iex> enumerable = 1..100\n      iex> n = 3\n      iex> Enum.flat_map_reduce(enumerable, 0, fn x, acc ->\n      ...>   if acc < n, do: {[x], acc + 1}, else: {:halt, acc}\n      ...> end)\n      {[1, 2, 3], 3}\n\n      iex> Enum.flat_map_reduce(1..5, 0, fn x, acc -> {[[x]], acc + x} end)\n      {[[1], [2], [3], [4], [5]], 15}\n\n  \"\"\"\n  @spec flat_map_reduce(t, acc, fun) :: {[any], acc}\n        when fun: (element, acc -> {t, acc} | {:halt, acc})\n  def flat_map_reduce(enumerable, acc, fun) do\n    {_, {list, acc}} =\n      Enumerable.reduce(enumerable, {:cont, {[], acc}}, fn entry, {list, acc} ->\n        case fun.(entry, acc) do\n          {:halt, acc} ->\n            {:halt, {list, acc}}\n\n          {[], acc} ->\n            {:cont, {list, acc}}\n\n          {[entry], acc} ->\n            {:cont, {[entry | list], acc}}\n\n          {entries, acc} ->\n            {:cont, {reduce(entries, list, &[&1 | &2]), acc}}\n        end\n      end)\n\n    {:lists.reverse(list), acc}\n  end\n\n  @doc \"\"\"\n  Returns a map with keys as unique elements of `enumerable` and values\n  as the count of every element.\n\n  ## Examples\n\n      iex> Enum.frequencies(~w{ant buffalo ant ant buffalo dingo})\n      %{\"ant\" => 3, \"buffalo\" => 2, \"dingo\" => 1}\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec frequencies(t) :: map\n  def frequencies(enumerable) do\n    reduce(enumerable, %{}, fn key, acc ->\n      case acc do\n        %{^key => value} -> %{acc | key => value + 1}\n        %{} -> Map.put(acc, key, 1)\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Returns a map with keys as unique elements given by `key_fun` and values\n  as the count of every element.\n\n  ## Examples\n\n      iex> Enum.frequencies_by(~w{aa aA bb cc}, &String.downcase/1)\n      %{\"aa\" => 2, \"bb\" => 1, \"cc\" => 1}\n\n      iex> Enum.frequencies_by(~w{aaa aA bbb cc c}, &String.length/1)\n      %{3 => 2, 2 => 2, 1 => 1}\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec frequencies_by(t, (element -> any)) :: map\n  def frequencies_by(enumerable, key_fun) when is_function(key_fun) do\n    reduce(enumerable, %{}, fn entry, acc ->\n      key = key_fun.(entry)\n\n      case acc do\n        %{^key => value} -> %{acc | key => value + 1}\n        %{} -> Map.put(acc, key, 1)\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Splits the `enumerable` into groups based on `key_fun`.\n\n  The result is a map where each key is given by `key_fun`\n  and each value is a list of elements given by `value_fun`.\n  The order of elements within each list is preserved from the `enumerable`.\n  However, like all maps, the resulting map is unordered.\n\n  ## Examples\n\n      iex> Enum.group_by(~w{ant buffalo cat dingo}, &String.length/1)\n      %{3 => [\"ant\", \"cat\"], 5 => [\"dingo\"], 7 => [\"buffalo\"]}\n\n      iex> Enum.group_by(~w{ant buffalo cat dingo}, &String.length/1, &String.first/1)\n      %{3 => [\"a\", \"c\"], 5 => [\"d\"], 7 => [\"b\"]}\n\n  The key can be any Elixir value. For example, you may use a tuple\n  to group by multiple keys:\n\n      iex> collection = [\n      ...>   %{id: 1, lang: \"Elixir\", seq: 1},\n      ...>   %{id: 1, lang: \"Java\", seq: 1},\n      ...>   %{id: 1, lang: \"Ruby\", seq: 2},\n      ...>   %{id: 2, lang: \"Python\", seq: 1},\n      ...>   %{id: 2, lang: \"C#\", seq: 2},\n      ...>   %{id: 2, lang: \"Haskell\", seq: 2},\n      ...> ]\n      iex> Enum.group_by(collection, &{&1.id, &1.seq})\n      %{\n        {1, 1} => [%{id: 1, lang: \"Elixir\", seq: 1}, %{id: 1, lang: \"Java\", seq: 1}],\n        {1, 2} => [%{id: 1, lang: \"Ruby\", seq: 2}],\n        {2, 1} => [%{id: 2, lang: \"Python\", seq: 1}],\n        {2, 2} => [%{id: 2, lang: \"C#\", seq: 2}, %{id: 2, lang: \"Haskell\", seq: 2}]\n      }\n      iex> Enum.group_by(collection, &{&1.id, &1.seq}, &{&1.id, &1.lang})\n      %{\n        {1, 1} => [{1, \"Elixir\"}, {1, \"Java\"}],\n        {1, 2} => [{1, \"Ruby\"}],\n        {2, 1} => [{2, \"Python\"}],\n        {2, 2} => [{2, \"C#\"}, {2, \"Haskell\"}]\n      }\n\n  \"\"\"\n  @spec group_by(t, (element -> any), (element -> any)) :: map\n  def group_by(enumerable, key_fun, value_fun \\\\ fn x -> x end)\n\n  def group_by(enumerable, key_fun, value_fun) when is_function(key_fun) do\n    reduce(reverse(enumerable), %{}, fn entry, acc ->\n      key = key_fun.(entry)\n      value = value_fun.(entry)\n\n      case acc do\n        %{^key => existing} -> %{acc | key => [value | existing]}\n        %{} -> Map.put(acc, key, [value])\n      end\n    end)\n  end\n\n  def group_by(enumerable, dict, fun) do\n    IO.warn(\n      \"Enum.group_by/3 with a map/dictionary as second element is deprecated. \" <>\n        \"A map is used by default and it is no longer required to pass one to this function\"\n    )\n\n    # Avoid warnings about Dict\n    dict_module = String.to_atom(\"Dict\")\n\n    reduce(reverse(enumerable), dict, fn entry, categories ->\n      dict_module.update(categories, fun.(entry), [entry], &[entry | &1])\n    end)\n  end\n\n  @doc \"\"\"\n  Intersperses `separator` between each element of the enumeration.\n\n  ## Examples\n\n      iex> Enum.intersperse([1, 2, 3], 0)\n      [1, 0, 2, 0, 3]\n\n      iex> Enum.intersperse([1], 0)\n      [1]\n\n      iex> Enum.intersperse([], 0)\n      []\n\n  \"\"\"\n  @spec intersperse(t, element) :: list\n  def intersperse(enumerable, separator) when is_list(enumerable) do\n    case enumerable do\n      [] -> []\n      list -> intersperse_non_empty_list(list, separator)\n    end\n  end\n\n  def intersperse(enumerable, separator) do\n    list =\n      enumerable\n      |> reduce([], fn x, acc -> [x, separator | acc] end)\n      |> :lists.reverse()\n\n    # Head is a superfluous separator\n    case list do\n      [] -> []\n      [_ | t] -> t\n    end\n  end\n\n  @doc \"\"\"\n  Inserts the given `enumerable` into a `collectable`.\n\n  Note that passing a non-empty list as the `collectable` is deprecated.\n  If you're collecting into a non-empty keyword list, consider using\n  `Keyword.merge(collectable, Enum.to_list(enumerable))`. If you're collecting\n  into a non-empty list, consider something like `Enum.to_list(enumerable) ++ collectable`.\n\n  ## Examples\n\n      iex> Enum.into([1, 2], [])\n      [1, 2]\n\n      iex> Enum.into([a: 1, b: 2], %{})\n      %{a: 1, b: 2}\n\n      iex> Enum.into(%{a: 1}, %{b: 2})\n      %{a: 1, b: 2}\n\n      iex> Enum.into([a: 1, a: 2], %{})\n      %{a: 2}\n\n      iex> Enum.into([a: 2], %{a: 1, b: 3})\n      %{a: 2, b: 3}\n\n  \"\"\"\n  @spec into(Enumerable.t(), Collectable.t()) :: Collectable.t()\n  def into(enumerable, collectable)\n\n  def into(enumerable, []) do\n    to_list(enumerable)\n  end\n\n  def into(enumerable, collectable) when is_struct(collectable, MapSet) do\n    if MapSet.size(collectable) == 0 do\n      MapSet.new(enumerable)\n    else\n      MapSet.new(enumerable) |> MapSet.union(collectable)\n    end\n  end\n\n  def into(%_{} = enumerable, collectable) do\n    into_protocol(enumerable, collectable)\n  end\n\n  def into(enumerable, %_{} = collectable) do\n    into_protocol(enumerable, collectable)\n  end\n\n  def into(enumerable, %{} = collectable) do\n    if map_size(collectable) == 0 do\n      into_map(enumerable)\n    else\n      into_map(enumerable, collectable)\n    end\n  end\n\n  def into(enumerable, collectable) do\n    into_protocol(enumerable, collectable)\n  end\n\n  defp into_map(%{} = enumerable), do: enumerable\n  defp into_map(enumerable) when is_list(enumerable), do: :maps.from_list(enumerable)\n  defp into_map(enumerable), do: enumerable |> Enum.to_list() |> :maps.from_list()\n\n  defp into_map(%{} = enumerable, collectable), do: Map.merge(collectable, enumerable)\n\n  defp into_map(enumerable, collectable) when is_list(enumerable),\n    do: Map.merge(collectable, :maps.from_list(enumerable))\n\n  defp into_map(enumerable, collectable),\n    do: reduce(enumerable, collectable, fn {key, val}, acc -> Map.put(acc, key, val) end)\n\n  defp into_protocol(enumerable, collectable) do\n    {initial, fun} = Collectable.into(collectable)\n\n    try do\n      reduce_into_protocol(enumerable, initial, fun)\n    catch\n      kind, reason ->\n        fun.(initial, :halt)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      acc -> fun.(acc, :done)\n    end\n  end\n\n  defp reduce_into_protocol(enumerable, initial, fun) when is_list(enumerable) do\n    :lists.foldl(fn x, acc -> fun.(acc, {:cont, x}) end, initial, enumerable)\n  end\n\n  defp reduce_into_protocol(enumerable, initial, fun) do\n    enumerable\n    |> Enumerable.reduce({:cont, initial}, fn x, acc ->\n      {:cont, fun.(acc, {:cont, x})}\n    end)\n    |> elem(1)\n  end\n\n  @doc \"\"\"\n  Inserts the given `enumerable` into a `collectable` according to the\n  transformation function.\n\n  ## Examples\n\n      iex> Enum.into([1, 2, 3], [], fn x -> x * 3 end)\n      [3, 6, 9]\n\n      iex> Enum.into(%{a: 1, b: 2}, %{c: 3}, fn {k, v} -> {k, v * 2} end)\n      %{a: 2, b: 4, c: 3}\n\n  \"\"\"\n  @spec into(Enumerable.t(), Collectable.t(), (term -> term)) :: Collectable.t()\n  def into(enumerable, [], transform) do\n    map(enumerable, transform)\n  end\n\n  def into(enumerable, collectable, transform) when is_struct(collectable, MapSet) do\n    if MapSet.size(collectable) == 0 do\n      MapSet.new(enumerable, transform)\n    else\n      MapSet.new(enumerable, transform) |> MapSet.union(collectable)\n    end\n  end\n\n  def into(enumerable, %_{} = collectable, transform) do\n    into_protocol(enumerable, collectable, transform)\n  end\n\n  def into(enumerable, %{} = collectable, transform) do\n    if map_size(collectable) == 0 do\n      enumerable |> map(transform) |> :maps.from_list()\n    else\n      reduce(enumerable, collectable, fn entry, acc ->\n        {key, val} = transform.(entry)\n        Map.put(acc, key, val)\n      end)\n    end\n  end\n\n  def into(enumerable, collectable, transform) do\n    into_protocol(enumerable, collectable, transform)\n  end\n\n  defp into_protocol(enumerable, collectable, transform) do\n    {initial, fun} = Collectable.into(collectable)\n\n    try do\n      reduce_into_protocol(enumerable, initial, transform, fun)\n    catch\n      kind, reason ->\n        fun.(initial, :halt)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      acc -> fun.(acc, :done)\n    end\n  end\n\n  defp reduce_into_protocol(enumerable, initial, transform, fun) when is_list(enumerable) do\n    :lists.foldl(fn x, acc -> fun.(acc, {:cont, transform.(x)}) end, initial, enumerable)\n  end\n\n  defp reduce_into_protocol(enumerable, initial, transform, fun) do\n    enumerable\n    |> Enumerable.reduce({:cont, initial}, fn x, acc ->\n      {:cont, fun.(acc, {:cont, transform.(x)})}\n    end)\n    |> elem(1)\n  end\n\n  @doc \"\"\"\n  Joins the given `enumerable` into a string using `joiner` as a\n  separator.\n\n  If `joiner` is not passed at all, it defaults to an empty string.\n\n  All elements in the `enumerable` must be convertible to a string\n  or be a binary, otherwise an error is raised.\n\n  ## Examples\n\n      iex> Enum.join([1, 2, 3])\n      \"123\"\n\n      iex> Enum.join([1, 2, 3], \" = \")\n      \"1 = 2 = 3\"\n\n      iex> Enum.join([[\"a\", \"b\"], [\"c\", \"d\", \"e\", [\"f\", \"g\"]], \"h\", \"i\"], \" \")\n      \"ab cdefg h i\"\n\n  \"\"\"\n  @spec join(t, binary()) :: binary()\n  def join(enumerable, joiner \\\\ \"\")\n\n  def join(enumerable, \"\") do\n    enumerable\n    |> map(&entry_to_string(&1))\n    |> IO.iodata_to_binary()\n  end\n\n  def join(enumerable, joiner) when is_list(enumerable) and is_binary(joiner) do\n    join_list(enumerable, joiner)\n  end\n\n  def join(enumerable, joiner) when is_binary(joiner) do\n    reduced =\n      reduce(enumerable, :first, fn\n        entry, :first -> entry_to_string(entry)\n        entry, acc -> [acc, joiner | entry_to_string(entry)]\n      end)\n\n    if reduced == :first do\n      \"\"\n    else\n      IO.iodata_to_binary(reduced)\n    end\n  end\n\n  @doc \"\"\"\n  Returns a list where each element is the result of invoking\n  `fun` on each corresponding element of `enumerable`.\n\n  For maps, the function expects a key-value tuple.\n\n  ## Examples\n\n      iex> Enum.map([1, 2, 3], fn x -> x * 2 end)\n      [2, 4, 6]\n\n      iex> Enum.map([a: 1, b: 2], fn {k, v} -> {k, -v} end)\n      [a: -1, b: -2]\n\n  \"\"\"\n  @spec map(t, (element -> any)) :: list\n  def map(enumerable, fun)\n\n  def map(enumerable, fun) when is_list(enumerable) do\n    :lists.map(fun, enumerable)\n  end\n\n  def map(first..last//step, fun) do\n    map_range(first, last, step, fun)\n  end\n\n  def map(enumerable, fun) do\n    reduce(enumerable, [], R.map(fun)) |> :lists.reverse()\n  end\n\n  @doc \"\"\"\n  Returns a list of results of invoking `fun` on every `nth`\n  element of `enumerable`, starting with the first element.\n\n  The first element is always passed to the given function, unless `nth` is `0`.\n\n  The second argument specifying every `nth` element must be a non-negative\n  integer.\n\n  If `nth` is `0`, then `enumerable` is directly converted to a list,\n  without `fun` being ever applied.\n\n  ## Examples\n\n      iex> Enum.map_every(1..10, 2, fn x -> x + 1000 end)\n      [1001, 2, 1003, 4, 1005, 6, 1007, 8, 1009, 10]\n\n      iex> Enum.map_every(1..10, 3, fn x -> x + 1000 end)\n      [1001, 2, 3, 1004, 5, 6, 1007, 8, 9, 1010]\n\n      iex> Enum.map_every(1..5, 0, fn x -> x + 1000 end)\n      [1, 2, 3, 4, 5]\n\n      iex> Enum.map_every([1, 2, 3], 1, fn x -> x + 1000 end)\n      [1001, 1002, 1003]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec map_every(t, non_neg_integer, (element -> any)) :: list\n  def map_every(enumerable, nth, fun)\n\n  def map_every(enumerable, 1, fun), do: map(enumerable, fun)\n  def map_every(enumerable, 0, _fun), do: to_list(enumerable)\n  def map_every([], nth, _fun) when is_integer(nth) and nth > 1, do: []\n\n  def map_every(enumerable, nth, fun) when is_integer(nth) and nth > 1 do\n    {res, _} = reduce(enumerable, {[], :first}, R.map_every(nth, fun))\n    :lists.reverse(res)\n  end\n\n  @doc \"\"\"\n  Maps and intersperses the given enumerable in one pass.\n\n  ## Examples\n\n      iex> Enum.map_intersperse([1, 2, 3], :a, &(&1 * 2))\n      [2, :a, 4, :a, 6]\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec map_intersperse(t, element(), (element -> any())) :: list()\n  def map_intersperse(enumerable, separator, mapper)\n\n  def map_intersperse(enumerable, separator, mapper) when is_list(enumerable) do\n    map_intersperse_list(enumerable, separator, mapper)\n  end\n\n  def map_intersperse(enumerable, separator, mapper) do\n    reduced =\n      reduce(enumerable, :first, fn\n        entry, :first -> [mapper.(entry)]\n        entry, acc -> [mapper.(entry), separator | acc]\n      end)\n\n    if reduced == :first do\n      []\n    else\n      :lists.reverse(reduced)\n    end\n  end\n\n  @doc \"\"\"\n  Maps and joins the given `enumerable` in one pass.\n\n  If `joiner` is not passed at all, it defaults to an empty string.\n\n  All elements returned from invoking the `mapper` must be convertible to\n  a string, otherwise an error is raised.\n\n  ## Examples\n\n      iex> Enum.map_join([1, 2, 3], &(&1 * 2))\n      \"246\"\n\n      iex> Enum.map_join([1, 2, 3], \" = \", &(&1 * 2))\n      \"2 = 4 = 6\"\n\n  \"\"\"\n  @spec map_join(t, String.t(), (element -> String.Chars.t())) :: String.t()\n  def map_join(enumerable, joiner \\\\ \"\", mapper) when is_binary(joiner) do\n    enumerable\n    |> map_intersperse(joiner, &entry_to_string(mapper.(&1)))\n    |> IO.iodata_to_binary()\n  end\n\n  @doc \"\"\"\n  Invokes the given function to each element in the `enumerable` to reduce\n  it to a single element, while keeping an accumulator.\n\n  Returns a tuple where the first element is the mapped enumerable and\n  the second one is the final accumulator.\n\n  The function, `fun`, receives two arguments: the first one is the\n  element, and the second one is the accumulator. `fun` must return\n  a tuple with two elements in the form of `{result, accumulator}`.\n\n  For maps, the first tuple element must be a `{key, value}` tuple.\n\n  ## Examples\n\n      iex> Enum.map_reduce([1, 2, 3], 0, fn x, acc -> {x * 2, x + acc} end)\n      {[2, 4, 6], 6}\n\n  \"\"\"\n  @spec map_reduce(t, acc, (element, acc -> {element, acc})) :: {list, acc}\n  def map_reduce(enumerable, acc, fun) when is_list(enumerable) do\n    :lists.mapfoldl(fun, acc, enumerable)\n  end\n\n  def map_reduce(enumerable, acc, fun) do\n    {list, acc} =\n      reduce(enumerable, {[], acc}, fn entry, {list, acc} ->\n        {new_entry, acc} = fun.(entry, acc)\n        {[new_entry | list], acc}\n      end)\n\n    {:lists.reverse(list), acc}\n  end\n\n  @doc false\n  def max(list = [_ | _]), do: :lists.max(list)\n\n  @doc false\n  def max(list = [_ | _], empty_fallback) when is_function(empty_fallback, 0) do\n    :lists.max(list)\n  end\n\n  @doc false\n  @spec max(t, (-> empty_result)) :: element | empty_result when empty_result: any\n  def max(enumerable, empty_fallback) when is_function(empty_fallback, 0) do\n    max(enumerable, &>=/2, empty_fallback)\n  end\n\n  @doc \"\"\"\n  Returns the maximal element in the `enumerable` according\n  to Erlang's term ordering.\n\n  By default, the comparison is done with the [`>=`](`>=/2`) sorter function.\n  If multiple elements are considered maximal, the first one that\n  was found is returned. If you want the last element considered\n  maximal to be returned, the sorter function should not return true\n  for equal elements.\n\n  If the enumerable is empty, the provided `empty_fallback` is called.\n  The default `empty_fallback` raises `Enum.EmptyError`.\n\n  ## Examples\n\n      iex> Enum.max([1, 2, 3])\n      3\n\n  The fact this function uses Erlang's term ordering means that the comparison\n  is structural and not semantic. For example:\n\n      iex> Enum.max([~D[2017-03-31], ~D[2017-04-01]])\n      ~D[2017-03-31]\n\n  In the example above, `max/2` returned March 31st instead of April 1st\n  because the structural comparison compares the day before the year.\n  For this reason, most structs provide a \"compare\" function, such as\n  `Date.compare/2`, which receives two structs and returns `:lt` (less-than),\n  `:eq` (equal to), and `:gt` (greater-than). If you pass a module as the\n  sorting function, Elixir will automatically use the `compare/2` function\n  of said module:\n\n      iex> Enum.max([~D[2017-03-31], ~D[2017-04-01]], Date)\n      ~D[2017-04-01]\n\n  Finally, if you don't want to raise on empty enumerables, you can pass\n  the empty fallback:\n\n      iex> Enum.max([], &>=/2, fn -> 0 end)\n      0\n\n  \"\"\"\n  @spec max(t, (element, element -> boolean) | module()) ::\n          element | empty_result\n        when empty_result: any\n  @spec max(t, (element, element -> boolean) | module(), (-> empty_result)) ::\n          element | empty_result\n        when empty_result: any\n  def max(enumerable, sorter \\\\ &>=/2, empty_fallback \\\\ fn -> raise Enum.EmptyError end) do\n    aggregate(enumerable, max_sort_fun(sorter), empty_fallback)\n  end\n\n  defp max_sort_fun(sorter) when is_function(sorter, 2), do: sorter\n  defp max_sort_fun(module) when is_atom(module), do: &(module.compare(&1, &2) != :lt)\n\n  @doc false\n  @spec max_by(\n          t,\n          (element -> any),\n          (-> empty_result) | (element, element -> boolean) | module()\n        ) :: element | empty_result\n        when empty_result: any\n  def max_by(enumerable, fun, empty_fallback)\n      when is_function(fun, 1) and is_function(empty_fallback, 0) do\n    max_by(enumerable, fun, &>=/2, empty_fallback)\n  end\n\n  @doc \"\"\"\n  Returns the maximal element in the `enumerable` as calculated\n  by the given `fun`.\n\n  By default, the comparison is done with the [`>=`](`>=/2`) sorter function.\n  If multiple elements are considered maximal, the first one that\n  was found is returned. If you want the last element considered\n  maximal to be returned, the sorter function should not return true\n  for equal elements.\n\n  Calls the provided `empty_fallback` function and returns its value if\n  `enumerable` is empty. The default `empty_fallback` raises `Enum.EmptyError`.\n\n  ## Examples\n\n      iex> Enum.max_by([\"a\", \"aa\", \"aaa\"], fn x -> String.length(x) end)\n      \"aaa\"\n\n      iex> Enum.max_by([\"a\", \"aa\", \"aaa\", \"b\", \"bbb\"], &String.length/1)\n      \"aaa\"\n\n  The fact this function uses Erlang's term ordering means that the\n  comparison is structural and not semantic. Therefore, if you want\n  to compare structs, most structs provide a \"compare\" function, such as\n  `Date.compare/2`, which receives two structs and returns `:lt` (less-than),\n  `:eq` (equal to), and `:gt` (greater-than). If you pass a module as the\n  sorting function, Elixir will automatically use the `compare/2` function\n  of said module:\n\n      iex> users = [\n      ...>   %{name: \"Ellis\", birthday: ~D[1943-05-11]},\n      ...>   %{name: \"Lovelace\", birthday: ~D[1815-12-10]},\n      ...>   %{name: \"Turing\", birthday: ~D[1912-06-23]}\n      ...> ]\n      iex> Enum.max_by(users, &(&1.birthday), Date)\n      %{name: \"Ellis\", birthday: ~D[1943-05-11]}\n\n  Finally, if you don't want to raise on empty enumerables, you can pass\n  the empty fallback:\n\n      iex> Enum.max_by([], &String.length/1, fn -> nil end)\n      nil\n\n  \"\"\"\n  @spec max_by(\n          t,\n          (element -> any),\n          (element, element -> boolean) | module(),\n          (-> empty_result)\n        ) :: element | empty_result\n        when empty_result: any\n  def max_by(enumerable, fun, sorter \\\\ &>=/2, empty_fallback \\\\ fn -> raise Enum.EmptyError end)\n      when is_function(fun, 1) do\n    aggregate_by(enumerable, fun, max_sort_fun(sorter), empty_fallback)\n  end\n\n  @doc \"\"\"\n  Checks if `element` exists within the `enumerable`.\n\n  Membership is tested with the match (`===/2`) operator.\n\n  ## Examples\n\n      iex> Enum.member?(1..10, 5)\n      true\n      iex> Enum.member?(1..10, 5.0)\n      false\n\n      iex> Enum.member?([1.0, 2.0, 3.0], 2)\n      false\n      iex> Enum.member?([1.0, 2.0, 3.0], 2.000)\n      true\n\n      iex> Enum.member?([:a, :b, :c], :d)\n      false\n\n\n  When called outside guards, the [`in`](`in/2`) and [`not in`](`in/2`)\n  operators work by using this function.\n  \"\"\"\n  @spec member?(t, element) :: boolean\n  def member?(enumerable, element) when is_list(enumerable) do\n    :lists.member(element, enumerable)\n  end\n\n  def member?(enumerable, element) do\n    case Enumerable.member?(enumerable, element) do\n      {:ok, element} when is_boolean(element) ->\n        element\n\n      {:error, module} ->\n        module.reduce(enumerable, {:cont, false}, fn\n          v, _ when v === element -> {:halt, true}\n          _, _ -> {:cont, false}\n        end)\n        |> elem(1)\n    end\n  end\n\n  @doc false\n  def min(list = [_ | _]), do: :lists.min(list)\n\n  @doc false\n  def min(list = [_ | _], empty_fallback) when is_function(empty_fallback, 0) do\n    :lists.min(list)\n  end\n\n  @doc false\n  @spec min(t, (-> empty_result)) :: element | empty_result when empty_result: any\n  def min(enumerable, empty_fallback) when is_function(empty_fallback, 0) do\n    min(enumerable, &<=/2, empty_fallback)\n  end\n\n  @doc \"\"\"\n  Returns the minimal element in the `enumerable` according\n  to Erlang's term ordering.\n\n  By default, the comparison is done with the [`<=`](`<=/2`) sorter function.\n  If multiple elements are considered minimal, the first one that\n  was found is returned. If you want the last element considered\n  minimal to be returned, the sorter function should not return true\n  for equal elements.\n\n  If the enumerable is empty, the provided `empty_fallback` is called.\n  The default `empty_fallback` raises `Enum.EmptyError`.\n\n  ## Examples\n\n      iex> Enum.min([1, 2, 3])\n      1\n\n  The fact this function uses Erlang's term ordering means that the comparison\n  is structural and not semantic. For example:\n\n      iex> Enum.min([~D[2017-03-31], ~D[2017-04-01]])\n      ~D[2017-04-01]\n\n  In the example above, `min/2` returned April 1st instead of March 31st\n  because the structural comparison compares the day before the year.\n  For this reason, most structs provide a \"compare\" function, such as\n  `Date.compare/2`, which receives two structs and returns `:lt` (less-than),\n  `:eq` (equal to), and `:gt` (greater-than). If you pass a module as the\n  sorting function, Elixir will automatically use the `compare/2` function\n  of said module:\n\n      iex> Enum.min([~D[2017-03-31], ~D[2017-04-01]], Date)\n      ~D[2017-03-31]\n\n  Finally, if you don't want to raise on empty enumerables, you can pass\n  the empty fallback:\n\n      iex> Enum.min([], fn -> 0 end)\n      0\n\n  \"\"\"\n  @spec min(t, (element, element -> boolean) | module()) ::\n          element | empty_result\n        when empty_result: any\n  @spec min(t, (element, element -> boolean) | module(), (-> empty_result)) ::\n          element | empty_result\n        when empty_result: any\n  def min(enumerable, sorter \\\\ &<=/2, empty_fallback \\\\ fn -> raise Enum.EmptyError end) do\n    aggregate(enumerable, min_sort_fun(sorter), empty_fallback)\n  end\n\n  defp min_sort_fun(sorter) when is_function(sorter, 2), do: sorter\n  defp min_sort_fun(module) when is_atom(module), do: &(module.compare(&1, &2) != :gt)\n\n  @doc false\n  @spec min_by(\n          t,\n          (element -> any),\n          (-> empty_result) | (element, element -> boolean) | module()\n        ) :: element | empty_result\n        when empty_result: any\n  def min_by(enumerable, fun, empty_fallback)\n      when is_function(fun, 1) and is_function(empty_fallback, 0) do\n    min_by(enumerable, fun, &<=/2, empty_fallback)\n  end\n\n  @doc \"\"\"\n  Returns the minimal element in the `enumerable` as calculated\n  by the given `fun`.\n\n  By default, the comparison is done with the [`<=`](`<=/2`) sorter function.\n  If multiple elements are considered minimal, the first one that\n  was found is returned. If you want the last element considered\n  minimal to be returned, the sorter function should not return true\n  for equal elements.\n\n  Calls the provided `empty_fallback` function and returns its value if\n  `enumerable` is empty. The default `empty_fallback` raises `Enum.EmptyError`.\n\n  ## Examples\n\n      iex> Enum.min_by([\"a\", \"aa\", \"aaa\"], fn x -> String.length(x) end)\n      \"a\"\n\n      iex> Enum.min_by([\"a\", \"aa\", \"aaa\", \"b\", \"bbb\"], &String.length/1)\n      \"a\"\n\n  The fact this function uses Erlang's term ordering means that the\n  comparison is structural and not semantic. Therefore, if you want\n  to compare structs, most structs provide a \"compare\" function, such as\n  `Date.compare/2`, which receives two structs and returns `:lt` (less-than),\n  `:eq` (equal to), and `:gt` (greater-than). If you pass a module as the\n  sorting function, Elixir will automatically use the `compare/2` function\n  of said module:\n\n      iex> users = [\n      ...>   %{name: \"Ellis\", birthday: ~D[1943-05-11]},\n      ...>   %{name: \"Lovelace\", birthday: ~D[1815-12-10]},\n      ...>   %{name: \"Turing\", birthday: ~D[1912-06-23]}\n      ...> ]\n      iex> Enum.min_by(users, &(&1.birthday), Date)\n      %{name: \"Lovelace\", birthday: ~D[1815-12-10]}\n\n  Finally, if you don't want to raise on empty enumerables, you can pass\n  the empty fallback:\n\n      iex> Enum.min_by([], &String.length/1, fn -> nil end)\n      nil\n\n  \"\"\"\n  @spec min_by(\n          t,\n          (element -> any),\n          (element, element -> boolean) | module(),\n          (-> empty_result)\n        ) :: element | empty_result\n        when empty_result: any\n  def min_by(enumerable, fun, sorter \\\\ &<=/2, empty_fallback \\\\ fn -> raise Enum.EmptyError end)\n      when is_function(fun, 1) do\n    aggregate_by(enumerable, fun, min_sort_fun(sorter), empty_fallback)\n  end\n\n  @doc \"\"\"\n  Returns a tuple with the minimal and the maximal elements in the\n  enumerable.\n\n  By default, the comparison is done with the [`<`](`</2`) sorter function,\n  as the function must not return true for equal elements.\n\n  ## Examples\n\n      iex> Enum.min_max([2, 3, 1])\n      {1, 3}\n\n      iex> Enum.min_max([\"foo\", \"bar\", \"baz\"])\n      {\"bar\", \"foo\"}\n\n      iex> Enum.min_max([], fn -> {nil, nil} end)\n      {nil, nil}\n\n  The fact this function uses Erlang's term ordering means that the\n  comparison is structural and not semantic. Therefore, if you want\n  to compare structs, most structs provide a \"compare\" function, such as\n  `Date.compare/2`, which receives two structs and returns `:lt` (less-than),\n  `:eq` (equal to), and `:gt` (greater-than). If you pass a module as the\n  sorting function, Elixir will automatically use the `compare/2` function\n  of said module:\n\n      iex> dates = [\n      ...>   ~D[2019-01-01],\n      ...>   ~D[2020-01-01],\n      ...>   ~D[2018-01-01]\n      ...> ]\n      iex> Enum.min_max(dates, Date)\n      {~D[2018-01-01], ~D[2020-01-01]}\n\n  You can also pass a custom sorting function:\n\n      iex> Enum.min_max([2, 3, 1], &>/2)\n      {3, 1}\n\n  Finally, if you don't want to raise on empty enumerables, you can pass\n  the empty fallback:\n\n      iex> Enum.min_max([], fn -> nil end)\n      nil\n\n  \"\"\"\n  @spec min_max(t, (element, element -> boolean) | module()) :: {element, element}\n  @spec min_max(t, (-> empty_result)) :: {element, element} | empty_result when empty_result: any\n  @spec min_max(t, (element, element -> boolean) | module(), (-> empty_result)) ::\n          {element, element} | empty_result\n        when empty_result: any\n\n  def min_max(enumerable, sorter_or_empty_fallback \\\\ fn -> raise Enum.EmptyError end)\n\n  def min_max(first..last//step = range, empty_fallback)\n      when is_function(empty_fallback, 0) do\n    case Range.size(range) do\n      0 ->\n        empty_fallback.()\n\n      _ ->\n        last = last - rem(last - first, step)\n        {Kernel.min(first, last), Kernel.max(first, last)}\n    end\n  end\n\n  def min_max(enumerable, empty_fallback)\n      when is_function(empty_fallback, 0) do\n    min_max(enumerable, &</2, empty_fallback)\n  end\n\n  def min_max(enumerable, sorter) when is_atom(sorter) do\n    min_max(enumerable, min_max_sort_fun(sorter))\n  end\n\n  def min_max(enumerable, sorter) when is_function(sorter, 2) do\n    min_max(enumerable, sorter, fn -> raise Enum.EmptyError end)\n  end\n\n  def min_max(enumerable, sorter, empty_fallback)\n      when is_atom(sorter) and is_function(empty_fallback, 0) do\n    min_max(enumerable, min_max_sort_fun(sorter), empty_fallback)\n  end\n\n  def min_max(enumerable, sorter, empty_fallback)\n      when is_function(sorter, 2) and is_function(empty_fallback, 0) do\n    first_fun = &[&1 | &1]\n\n    reduce_fun = fn entry, [min | max] = acc ->\n      cond do\n        sorter.(entry, min) ->\n          [entry | max]\n\n        sorter.(max, entry) ->\n          [min | entry]\n\n        true ->\n          acc\n      end\n    end\n\n    case reduce_by(enumerable, first_fun, reduce_fun) do\n      :empty -> empty_fallback.()\n      [min | max] -> {min, max}\n    end\n  end\n\n  @doc false\n  @spec min_max_by(t, (element -> any), (-> empty_result)) :: {element, element} | empty_result\n        when empty_result: any\n  def min_max_by(enumerable, fun, empty_fallback)\n      when is_function(fun, 1) and is_function(empty_fallback, 0) do\n    min_max_by(enumerable, fun, &</2, empty_fallback)\n  end\n\n  @doc \"\"\"\n  Returns a tuple with the minimal and the maximal elements in the\n  enumerable as calculated by the given function.\n\n  By default, the comparison is done with the [`<`](`</2`) sorter function,\n  as the function must not return `true` for equal elements.\n\n  ## Examples\n\n      iex> Enum.min_max_by([\"aaa\", \"bb\", \"c\"], fn x -> String.length(x) end)\n      {\"c\", \"aaa\"}\n\n      iex> Enum.min_max_by([\"aaa\", \"a\", \"bb\", \"c\", \"ccc\"], &String.length/1)\n      {\"a\", \"aaa\"}\n\n      iex> Enum.min_max_by([], &String.length/1, fn -> {nil, nil} end)\n      {nil, nil}\n\n  The fact this function uses Erlang's term ordering means that the\n  comparison is structural and not semantic. Therefore, if you want\n  to compare structs, most structs provide a \"compare\" function, such as\n  `Date.compare/2`, which receives two structs and returns `:lt` (less-than),\n  `:eq` (equal to), and `:gt` (greater-than). If you pass a module as the\n  sorting function, Elixir will automatically use the `compare/2` function\n  of said module:\n\n      iex> users = [\n      ...>   %{name: \"Ellis\", birthday: ~D[1943-05-11]},\n      ...>   %{name: \"Lovelace\", birthday: ~D[1815-12-10]},\n      ...>   %{name: \"Turing\", birthday: ~D[1912-06-23]}\n      ...> ]\n      iex> Enum.min_max_by(users, &(&1.birthday), Date)\n      {\n        %{name: \"Lovelace\", birthday: ~D[1815-12-10]},\n        %{name: \"Ellis\", birthday: ~D[1943-05-11]}\n      }\n\n  Finally, if you don't want to raise on empty enumerables, you can pass\n  the empty fallback:\n\n      iex> Enum.min_max_by([], &String.length/1, fn -> nil end)\n      nil\n\n  \"\"\"\n  @spec min_max_by(t, (element -> any), (element, element -> boolean) | module()) ::\n          {element, element} | empty_result\n        when empty_result: any\n  @spec min_max_by(\n          t,\n          (element -> any),\n          (element, element -> boolean) | module(),\n          (-> empty_result)\n        ) :: {element, element} | empty_result\n        when empty_result: any\n  def min_max_by(\n        enumerable,\n        fun,\n        sorter_or_empty_fallback \\\\ &</2,\n        empty_fallback \\\\ fn -> raise Enum.EmptyError end\n      )\n\n  def min_max_by(enumerable, fun, sorter, empty_fallback)\n      when is_function(fun, 1) and is_atom(sorter) and is_function(empty_fallback, 0) do\n    min_max_by(enumerable, fun, min_max_sort_fun(sorter), empty_fallback)\n  end\n\n  def min_max_by(enumerable, fun, sorter, empty_fallback)\n      when is_function(fun, 1) and is_function(sorter, 2) and is_function(empty_fallback, 0) do\n    first_fun = fn entry ->\n      fun_entry = fun.(entry)\n      {entry, entry, fun_entry, fun_entry}\n    end\n\n    reduce_fun = fn entry, {prev_min, prev_max, fun_min, fun_max} = acc ->\n      fun_entry = fun.(entry)\n\n      cond do\n        sorter.(fun_entry, fun_min) ->\n          {entry, prev_max, fun_entry, fun_max}\n\n        sorter.(fun_max, fun_entry) ->\n          {prev_min, entry, fun_min, fun_entry}\n\n        true ->\n          acc\n      end\n    end\n\n    case reduce_by(enumerable, first_fun, reduce_fun) do\n      :empty -> empty_fallback.()\n      {min, max, _, _} -> {min, max}\n    end\n  end\n\n  defp min_max_sort_fun(module) when is_atom(module), do: &(module.compare(&1, &2) == :lt)\n\n  @doc \"\"\"\n  Splits the `enumerable` in two lists according to the given function `fun`.\n\n  Splits the given `enumerable` in two lists by calling `fun` with each element\n  in the `enumerable` as its only argument. Returns a tuple with the first list\n  containing all the elements in `enumerable` for which applying `fun` returned\n  a truthy value, and a second list with all the elements for which applying\n  `fun` returned a falsy value (`false` or `nil`).\n\n  The elements in both the returned lists are in the same relative order as they\n  were in the original enumerable (if such enumerable was ordered, like a\n  list). See the examples below.\n\n  ## Examples\n\n      iex> Enum.split_with([5, 4, 3, 2, 1, 0], fn x -> rem(x, 2) == 0 end)\n      {[4, 2, 0], [5, 3, 1]}\n\n      iex> Enum.split_with([a: 1, b: -2, c: 1, d: -3], fn {_k, v} -> v < 0 end)\n      {[b: -2, d: -3], [a: 1, c: 1]}\n\n      iex> Enum.split_with([a: 1, b: -2, c: 1, d: -3], fn {_k, v} -> v > 50 end)\n      {[], [a: 1, b: -2, c: 1, d: -3]}\n\n      iex> Enum.split_with([], fn {_k, v} -> v > 50 end)\n      {[], []}\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec split_with(t, (element -> as_boolean(term))) :: {list, list}\n  def split_with(enumerable, fun) do\n    {acc1, acc2} =\n      reduce(enumerable, {[], []}, fn entry, {acc1, acc2} ->\n        if fun.(entry) do\n          {[entry | acc1], acc2}\n        else\n          {acc1, [entry | acc2]}\n        end\n      end)\n\n    {:lists.reverse(acc1), :lists.reverse(acc2)}\n  end\n\n  @doc false\n  @deprecated \"Use Enum.split_with/2 instead\"\n  def partition(enumerable, fun) do\n    split_with(enumerable, fun)\n  end\n\n  @doc \"\"\"\n  Returns a random element of an `enumerable`.\n\n  Raises `Enum.EmptyError` if `enumerable` is empty.\n\n  This function uses Erlang's [`:rand` module](`:rand`) to calculate\n  the random value. Check its documentation for setting a\n  different random algorithm or a different seed.\n\n  If a range is passed into the function, this function will pick a\n  random value between the range limits, without traversing the whole\n  range (thus executing in constant time and constant memory).\n\n  ## Examples\n\n  The examples below use the `:exsss` pseudorandom algorithm since it's\n  the default from Erlang/OTP 22:\n\n      # Although not necessary, let's seed the random algorithm\n      iex> :rand.seed(:exsss, {100, 101, 102})\n      iex> Enum.random([1, 2, 3])\n      2\n      iex> Enum.random([1, 2, 3])\n      1\n      iex> Enum.random(1..1_000)\n      309\n\n  ## Implementation\n\n  The random functions in this module implement reservoir sampling,\n  which allows them to sample infinite collections. In particular,\n  we implement Algorithm L, as described in by Kim-Hung Li in\n  \"Reservoir-Sampling Algorithms of Time Complexity O(n(1+log(N/n)))\".\n  \"\"\"\n  @spec random(t) :: element\n  def random(enumerable)\n\n  def random(enumerable) when is_list(enumerable) do\n    case length(enumerable) do\n      0 -> raise Enum.EmptyError\n      length -> enumerable |> drop_list(random_count(length)) |> hd()\n    end\n  end\n\n  def random(first.._//step = range) do\n    case Range.size(range) do\n      0 -> raise Enum.EmptyError\n      size -> first + random_count(size) * step\n    end\n  end\n\n  def random(enumerable) do\n    result =\n      case Enumerable.slice(enumerable) do\n        {:ok, 0, _} ->\n          []\n\n        {:ok, count, fun} when is_function(fun, 1) ->\n          slice_list(fun.(enumerable), random_count(count), 1, 1)\n\n        {:ok, count, fun} when is_function(fun, 3) ->\n          fun.(random_count(count), 1, 1)\n\n        # TODO: Remove me on v2.0\n        {:ok, count, fun} when is_function(fun, 2) ->\n          IO.warn(\n            \"#{inspect(Enumerable.impl_for(enumerable))} must return a three arity function on slice/1\"\n          )\n\n          fun.(random_count(count), 1)\n\n        {:error, _} ->\n          take_random(enumerable, 1)\n      end\n\n    case result do\n      [] -> raise Enum.EmptyError\n      [elem] -> elem\n    end\n  end\n\n  defp random_count(count) do\n    :rand.uniform(count) - 1\n  end\n\n  @doc \"\"\"\n  Invokes `fun` for each element in the `enumerable` with the\n  accumulator.\n\n  Raises `Enum.EmptyError` if `enumerable` is empty.\n\n  The first element of the `enumerable` is used as the initial value\n  of the accumulator. Then, the function is invoked with the next\n  element and the accumulator. The result returned by the function\n  is used as the accumulator for the next iteration, recursively.\n  When the `enumerable` is done, the last accumulator is returned.\n\n  Since the first element of the enumerable is used as the initial\n  value of the accumulator, `fun` will only be executed `n - 1` times\n  where `n` is the length of the enumerable. This function won't call\n  the specified function for enumerables that are one-element long.\n\n  If you wish to use another value for the accumulator, use\n  `Enum.reduce/3`.\n\n  ## Examples\n\n      iex> Enum.reduce([1, 2, 3, 4], fn x, acc -> x * acc end)\n      24\n\n  \"\"\"\n  @spec reduce(t, (element, acc -> acc)) :: acc\n  def reduce(enumerable, fun)\n\n  def reduce([h | t], fun) do\n    reduce(t, h, fun)\n  end\n\n  def reduce([], _fun) do\n    raise Enum.EmptyError\n  end\n\n  def reduce(enumerable, fun) do\n    Enumerable.reduce(enumerable, {:cont, :first}, fn\n      x, {:acc, acc} -> {:cont, {:acc, fun.(x, acc)}}\n      x, :first -> {:cont, {:acc, x}}\n    end)\n    |> elem(1)\n    |> case do\n      :first -> raise Enum.EmptyError\n      {:acc, acc} -> acc\n    end\n  end\n\n  @doc \"\"\"\n  Invokes `fun` for each element in the `enumerable` with the accumulator.\n\n  The initial value of the accumulator is `acc`. The function is invoked for\n  each element in the enumerable with the accumulator. The result returned\n  by the function is used as the accumulator for the next iteration.\n  The function returns the last accumulator.\n\n  ## Examples\n\n      iex> Enum.reduce([1, 2, 3], 0, fn x, acc -> x + acc end)\n      6\n\n      iex> Enum.reduce(%{a: 2, b: 3, c: 4}, 0, fn {_key, val}, acc -> acc + val end)\n      9\n\n  ## Reduce as a building block\n\n  Reduce (sometimes called `fold`) is a basic building block in functional\n  programming. Almost all of the functions in the `Enum` module can be\n  implemented on top of reduce. Those functions often rely on other operations,\n  such as `Enum.reverse/1`, which are optimized by the runtime.\n\n  For example, we could implement `map/2` in terms of `reduce/3` as follows:\n\n      def my_map(enumerable, fun) do\n        enumerable\n        |> Enum.reduce([], fn x, acc -> [fun.(x) | acc] end)\n        |> Enum.reverse()\n      end\n\n  In the example above, `Enum.reduce/3` accumulates the result of each call\n  to `fun` into a list in reverse order, which is correctly ordered at the\n  end by calling `Enum.reverse/1`.\n\n  Implementing functions like `map/2`, `filter/2` and others are a good\n  exercise for understanding the power behind `Enum.reduce/3`. When an\n  operation cannot be expressed by any of the functions in the `Enum`\n  module, developers will most likely resort to `reduce/3`.\n  \"\"\"\n  @spec reduce(t, acc, (element, acc -> acc)) :: acc\n  def reduce(enumerable, acc, fun) when is_list(enumerable) do\n    :lists.foldl(fun, acc, enumerable)\n  end\n\n  def reduce(first..last//step, acc, fun) do\n    reduce_range(first, last, step, acc, fun)\n  end\n\n  def reduce(%_{} = enumerable, acc, fun) do\n    reduce_enumerable(enumerable, acc, fun)\n  end\n\n  def reduce(%{} = enumerable, acc, fun) do\n    :maps.fold(fn k, v, acc -> fun.({k, v}, acc) end, acc, enumerable)\n  end\n\n  def reduce(enumerable, acc, fun) do\n    reduce_enumerable(enumerable, acc, fun)\n  end\n\n  @doc \"\"\"\n  Reduces `enumerable` until `fun` returns `{:halt, term}`.\n\n  The return value for `fun` is expected to be\n\n    * `{:cont, acc}` to continue the reduction with `acc` as the new\n      accumulator or\n    * `{:halt, acc}` to halt the reduction\n\n  If `fun` returns `{:halt, acc}` the reduction is halted and the function\n  returns `acc`. Otherwise, if the enumerable is exhausted, the function returns\n  the accumulator of the last `{:cont, acc}`.\n\n  ## Examples\n\n      iex> Enum.reduce_while(1..100, 0, fn x, acc ->\n      ...>   if x < 5 do\n      ...>     {:cont, acc + x}\n      ...>   else\n      ...>     {:halt, acc}\n      ...>   end\n      ...> end)\n      10\n      iex> Enum.reduce_while(1..100, 0, fn x, acc ->\n      ...>   if x > 0 do\n      ...>     {:cont, acc + x}\n      ...>   else\n      ...>     {:halt, acc}\n      ...>   end\n      ...> end)\n      5050\n\n  \"\"\"\n  @spec reduce_while(t, any, (element, any -> {:cont, any} | {:halt, any})) :: any\n  def reduce_while(enumerable, acc, fun) do\n    Enumerable.reduce(enumerable, {:cont, acc}, fun) |> elem(1)\n  end\n\n  @doc \"\"\"\n  Returns a list of elements in `enumerable` excluding those for which the function `fun` returns\n  a truthy value.\n\n  See also `filter/2`.\n\n  ## Examples\n\n      iex> Enum.reject([1, 2, 3], fn x -> rem(x, 2) == 0 end)\n      [1, 3]\n\n  \"\"\"\n  @spec reject(t, (element -> as_boolean(term))) :: list\n  def reject(enumerable, fun) when is_list(enumerable) do\n    reject_list(enumerable, fun)\n  end\n\n  def reject(enumerable, fun) do\n    reduce(enumerable, [], R.reject(fun)) |> :lists.reverse()\n  end\n\n  @doc \"\"\"\n  Returns a list of elements in `enumerable` in reverse order.\n\n  ## Examples\n\n      iex> Enum.reverse([1, 2, 3])\n      [3, 2, 1]\n\n  \"\"\"\n  @spec reverse(t) :: list\n  def reverse(enumerable)\n\n  def reverse([]), do: []\n  def reverse([_] = list), do: list\n  def reverse([element1, element2]), do: [element2, element1]\n  def reverse([element1, element2 | rest]), do: :lists.reverse(rest, [element2, element1])\n  def reverse(enumerable), do: reduce(enumerable, [], &[&1 | &2])\n\n  @doc \"\"\"\n  Reverses the elements in `enumerable`, appends the `tail`, and returns\n  it as a list.\n\n  This is an optimization for\n  `enumerable |> Enum.reverse() |> Enum.concat(tail)`.\n\n  ## Examples\n\n      iex> Enum.reverse([1, 2, 3], [4, 5, 6])\n      [3, 2, 1, 4, 5, 6]\n\n  \"\"\"\n  @spec reverse(t, t) :: list\n  def reverse(enumerable, tail) when is_list(enumerable) do\n    :lists.reverse(enumerable, to_list(tail))\n  end\n\n  def reverse(enumerable, tail) do\n    reduce(enumerable, to_list(tail), fn entry, acc ->\n      [entry | acc]\n    end)\n  end\n\n  @doc \"\"\"\n  Reverses the `enumerable` in the range from initial `start_index`\n  through `count` elements.\n\n  If `count` is greater than the size of the rest of the `enumerable`,\n  then this function will reverse the rest of the enumerable.\n\n  ## Examples\n\n      iex> Enum.reverse_slice([1, 2, 3, 4, 5, 6], 2, 4)\n      [1, 2, 6, 5, 4, 3]\n\n  \"\"\"\n  @spec reverse_slice(t, non_neg_integer, non_neg_integer) :: list\n  def reverse_slice(enumerable, start_index, count)\n      when is_integer(start_index) and start_index >= 0 and is_integer(count) and count >= 0 do\n    list = reverse(enumerable)\n    length = length(list)\n    count = Kernel.min(count, length - start_index)\n\n    if count > 0 do\n      reverse_slice(list, length, start_index + count, count, [])\n    else\n      :lists.reverse(list)\n    end\n  end\n\n  @doc \"\"\"\n  Slides a single or multiple elements given by `range_or_single_index` from `enumerable`\n  to `insertion_index`.\n\n  The semantics of the range to be moved match the semantics of `Enum.slice/2`.\n  Specifically, that means:\n\n   * Indices are normalized, meaning that negative indexes will be counted from the end\n      (for example, -1 means the last element of the enumerable). This will result in *two*\n      traversals of your enumerable on types like lists that don't provide a constant-time count.\n\n    * If the normalized index range's `last` is out of bounds, the range is truncated to the last element.\n\n    * If the normalized index range's `first` is out of bounds, the selected range for sliding\n      will be empty, so you'll get back your input list.\n\n    * Decreasing ranges (such as `5..0//1`) also select an empty range to be moved,\n      so you'll get back your input list.\n\n    * Ranges with any step but 1 will raise an error.\n\n  ## Examples\n\n      # Slide a single element\n      iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 5, 1)\n      [:a, :f, :b, :c, :d, :e, :g]\n\n      # Slide a range of elements towards the head of the list\n      iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 3..5, 1)\n      [:a, :d, :e, :f, :b, :c, :g]\n\n      # Slide a range of elements towards the tail of the list\n      iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 1..3, 5)\n      [:a, :e, :f, :b, :c, :d, :g]\n\n      # Slide with negative indices (counting from the end)\n      iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 3..-1//1, 2)\n      [:a, :b, :d, :e, :f, :g, :c]\n      iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], -4..-2, 1)\n      [:a, :d, :e, :f, :b, :c, :g]\n\n      # Insert at negative indices (counting from the end)\n      iex> Enum.slide([:a, :b, :c, :d, :e, :f, :g], 3, -1)\n      [:a, :b, :c, :e, :f, :g, :d]\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec slide(t, Range.t() | index, index) :: list\n  def slide(enumerable, range_or_single_index, insertion_index)\n\n  def slide(enumerable, single_index, insertion_index) when is_integer(single_index) do\n    slide(enumerable, single_index..single_index, insertion_index)\n  end\n\n  # This matches the behavior of Enum.slice/2\n  def slide(_, _.._//step = index_range, _insertion_index) when step != 1 do\n    raise ArgumentError,\n          \"Enum.slide/3 does not accept ranges with custom steps, got: #{inspect(index_range)}\"\n  end\n\n  # Normalize negative input ranges like Enum.slice/2\n  def slide(enumerable, first..last//_, insertion_index)\n      when first < 0 or last < 0 or insertion_index < 0 do\n    count = Enum.count(enumerable)\n    normalized_first = if first >= 0, do: first, else: Kernel.max(first + count, 0)\n    normalized_last = if last >= 0, do: last, else: last + count\n\n    normalized_insertion_index =\n      if insertion_index >= 0, do: insertion_index, else: insertion_index + count\n\n    if normalized_first < count and normalized_first != normalized_insertion_index do\n      normalized_range = normalized_first..normalized_last//1\n      slide(enumerable, normalized_range, normalized_insertion_index)\n    else\n      Enum.to_list(enumerable)\n    end\n  end\n\n  def slide(enumerable, insertion_index.._//_, insertion_index) do\n    Enum.to_list(enumerable)\n  end\n\n  def slide(_, first..last//_, insertion_index)\n      when insertion_index > first and insertion_index <= last do\n    raise ArgumentError,\n          \"insertion index for slide must be outside the range being moved \" <>\n            \"(tried to insert #{first}..#{last} at #{insertion_index})\"\n  end\n\n  def slide(enumerable, first..last//_, _insertion_index) when first > last do\n    Enum.to_list(enumerable)\n  end\n\n  # Guarantees at this point: step size == 1 and first <= last and (insertion_index < first or insertion_index > last)\n  def slide(enumerable, first..last//_, insertion_index) do\n    impl = if is_list(enumerable), do: &slide_list_start/4, else: &slide_any/4\n\n    cond do\n      insertion_index <= first -> impl.(enumerable, insertion_index, first, last)\n      insertion_index > last -> impl.(enumerable, first, last + 1, insertion_index)\n    end\n  end\n\n  # Takes the range from middle..last and moves it to be in front of index start\n  defp slide_any(enumerable, start, middle, last) do\n    # We're going to deal with 4 \"chunks\" of the enumerable:\n    # 0. \"Head,\" before the start index\n    # 1. \"Slide back,\" between start (inclusive) and middle (exclusive)\n    # 2. \"Slide front,\" between middle (inclusive) and last (inclusive)\n    # 3. \"Tail,\" after last\n    #\n    # But, we're going to accumulate these into only two lists: pre and post.\n    # We'll reverse-accumulate the head into our pre list, then \"slide back\" into post,\n    # then \"slide front\" into pre, then \"tail\" into post.\n    #\n    # Then at the end, we're going to reassemble and reverse them, and end up with the\n    # chunks in the correct order.\n    {_size, pre, post} =\n      reduce(enumerable, {0, [], []}, fn item, {index, pre, post} ->\n        {pre, post} =\n          cond do\n            index < start -> {[item | pre], post}\n            index >= start and index < middle -> {pre, [item | post]}\n            index >= middle and index <= last -> {[item | pre], post}\n            true -> {pre, [item | post]}\n          end\n\n        {index + 1, pre, post}\n      end)\n\n    :lists.reverse(pre, :lists.reverse(post))\n  end\n\n  # Like slide_any/4 above, this optimized implementation of slide for lists depends\n  # on the indices being sorted such that we're moving middle..last to be in front of start.\n  defp slide_list_start([h | t], start, middle, last)\n       when start > 0 and start <= middle and middle <= last do\n    [h | slide_list_start(t, start - 1, middle - 1, last - 1)]\n  end\n\n  defp slide_list_start(list, 0, middle, last), do: slide_list_middle(list, middle, last, [])\n  defp slide_list_start([], _start, _middle, _last), do: []\n\n  defp slide_list_middle([h | t], middle, last, acc) when middle > 0 do\n    slide_list_middle(t, middle - 1, last - 1, [h | acc])\n  end\n\n  defp slide_list_middle(list, 0, last, start_to_middle) do\n    {slid_range, tail} = slide_list_last(list, last + 1, [])\n    slid_range ++ :lists.reverse(start_to_middle, tail)\n  end\n\n  # You asked for a middle index off the end of the list... you get what we've got\n  defp slide_list_middle([], _, _, acc) do\n    :lists.reverse(acc)\n  end\n\n  defp slide_list_last([h | t], last, acc) when last > 0 do\n    slide_list_last(t, last - 1, [h | acc])\n  end\n\n  defp slide_list_last(rest, 0, acc) do\n    {:lists.reverse(acc), rest}\n  end\n\n  defp slide_list_last([], _, acc) do\n    {:lists.reverse(acc), []}\n  end\n\n  @doc \"\"\"\n  Passes each element from `enumerable` to the `fun` as the first argument,\n  stores the `fun` result in a list and passes the result as the second argument\n  for the next computation.\n\n  The `fun` isn't applied for the first element of the `enumerable`,\n  the element is taken as it is.\n\n  ## Examples\n\n      iex> Enum.scan([\"a\", \"b\", \"c\", \"d\", \"e\"], fn element, acc -> element <> String.first(acc) end)\n      [\"a\", \"ba\", \"cb\", \"dc\", \"ed\"]\n\n      iex> Enum.scan(1..5, fn element, acc -> element + acc end)\n      [1, 3, 6, 10, 15]\n\n  \"\"\"\n  @spec scan(t, (element, any -> any)) :: list\n  def scan(enumerable, fun)\n\n  def scan([], _fun), do: []\n\n  def scan([elem | rest], fun) do\n    scanned = scan_list(rest, elem, fun)\n    [elem | scanned]\n  end\n\n  def scan(enumerable, fun) do\n    {res, _} = reduce(enumerable, {[], :first}, R.scan2(fun))\n    :lists.reverse(res)\n  end\n\n  @doc \"\"\"\n  Passes each element from `enumerable` to the `fun` as the first argument,\n  stores the `fun` result in a list and passes the result as the second argument\n  for the next computation.\n\n  Passes the given `acc` as the second argument for the `fun` with the first element.\n\n  ## Examples\n\n      iex> Enum.scan([\"a\", \"b\", \"c\", \"d\", \"e\"], \"_\", fn element, acc -> element <> String.first(acc) end)\n      [\"a_\", \"ba\", \"cb\", \"dc\", \"ed\"]\n\n      iex> Enum.scan(1..5, 0, fn element, acc -> element + acc end)\n      [1, 3, 6, 10, 15]\n\n  \"\"\"\n  @spec scan(t, any, (element, any -> any)) :: list\n  def scan(enumerable, acc, fun) when is_list(enumerable) do\n    scan_list(enumerable, acc, fun)\n  end\n\n  def scan(enumerable, acc, fun) do\n    {res, _} = reduce(enumerable, {[], acc}, R.scan3(fun))\n    :lists.reverse(res)\n  end\n\n  @doc \"\"\"\n  Returns a list with the elements of `enumerable` shuffled.\n\n  This function uses Erlang's [`:rand` module](`:rand`) to calculate\n  the random value. Check its documentation for setting a\n  different random algorithm or a different seed.\n\n  ## Examples\n\n  The examples below use the `:exsss` pseudorandom algorithm since it's\n  the default from Erlang/OTP 22:\n\n      # Although not necessary, let's seed the random algorithm\n      iex> :rand.seed(:exsss, {11, 22, 33})\n      iex> Enum.shuffle([1, 2, 3])\n      [2, 1, 3]\n      iex> Enum.shuffle([1, 2, 3])\n      [2, 3, 1]\n\n  \"\"\"\n  @spec shuffle(t) :: list\n  def shuffle(enumerable) do\n    randomized =\n      reduce(enumerable, [], fn x, acc ->\n        [{:rand.uniform(), x} | acc]\n      end)\n\n    shuffle_unwrap(:lists.keysort(1, randomized))\n  end\n\n  defp shuffle_unwrap([{_, h} | rest]), do: [h | shuffle_unwrap(rest)]\n  defp shuffle_unwrap([]), do: []\n\n  @doc \"\"\"\n  Returns a subset list of the given `enumerable` by `index_range`.\n\n  `index_range` must be a `Range`. Given an `enumerable`, it drops\n  elements before `index_range.first` (zero-base), then it takes elements\n  until element `index_range.last` (inclusively).\n\n  Indexes are normalized, meaning that negative indexes will be counted\n  from the end (for example, `-1` means the last element of the `enumerable`).\n\n  If `index_range.last` is out of bounds, then it is assigned as the index\n  of the last element.\n\n  If the normalized `index_range.first` is out of bounds of the given\n  `enumerable`, or this one is greater than the normalized `index_range.last`,\n  then `[]` is returned.\n\n  If a step `n` (other than `1`) is used in `index_range`, then it takes\n  every `n`th element from `index_range.first` to `index_range.last`\n  (according to the same rules described above).\n\n  ## Examples\n\n      iex> Enum.slice([1, 2, 3, 4, 5], 1..3)\n      [2, 3, 4]\n\n      iex> Enum.slice([1, 2, 3, 4, 5], 3..10)\n      [4, 5]\n\n      # Last three elements (negative indexes)\n      iex> Enum.slice([1, 2, 3, 4, 5], -3..-1)\n      [3, 4, 5]\n\n  For ranges where `start > stop`, you need to explicit\n  mark them as increasing:\n\n      iex> Enum.slice([1, 2, 3, 4, 5], 1..-2//1)\n      [2, 3, 4]\n\n  The step can be any positive number. For example, to\n  get every 2 elements of the collection:\n\n      iex> Enum.slice([1, 2, 3, 4, 5], 0..-1//2)\n      [1, 3, 5]\n\n  To get every third element of the first ten elements:\n\n      iex> integers = Enum.to_list(1..20)\n      iex> Enum.slice(integers, 0..9//3)\n      [1, 4, 7, 10]\n\n  If the first position is after the end of the enumerable\n  or after the last position of the range, it returns an\n  empty list:\n\n      iex> Enum.slice([1, 2, 3, 4, 5], 6..10)\n      []\n\n      # first is greater than last\n      iex> Enum.slice([1, 2, 3, 4, 5], 6..5//1)\n      []\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec slice(t, Range.t()) :: list\n  def slice(enumerable, first..last//step = index_range) do\n    # TODO: Support negative steps as a reverse on Elixir v2.0.\n    cond do\n      step > 0 ->\n        slice_range(enumerable, first, last, step)\n\n      step == -1 and first > last ->\n        IO.warn(\n          \"negative steps are not supported in Enum.slice/2, pass #{first}..#{last}//1 instead\"\n        )\n\n        slice_range(enumerable, first, last, 1)\n\n      true ->\n        raise ArgumentError,\n              \"Enum.slice/2 does not accept ranges with negative steps, got: #{inspect(index_range)}\"\n    end\n  end\n\n  # TODO: Remove me on v2.0\n  def slice(enumerable, %{__struct__: Range, first: first, last: last} = index_range) do\n    step = if first <= last, do: 1, else: -1\n    slice(enumerable, Map.put(index_range, :step, step))\n  end\n\n  defp slice_range(enumerable, first, -1, step) when first >= 0 do\n    if step == 1 do\n      drop(enumerable, first)\n    else\n      enumerable |> drop(first) |> take_every_list(step - 1)\n    end\n  end\n\n  defp slice_range(enumerable, first, last, step)\n       when last >= first and last >= 0 and first >= 0 do\n    slice_forward(enumerable, first, last - first + 1, step)\n  end\n\n  defp slice_range(enumerable, first, last, step) do\n    {count, fun} = slice_count_and_fun(enumerable, step)\n    first = if first >= 0, do: first, else: Kernel.max(first + count, 0)\n    last = if last >= 0, do: last, else: last + count\n    amount = last - first + 1\n\n    if first < count and amount > 0 do\n      amount = Kernel.min(amount, count - first)\n      amount = amount_with_step(amount, step)\n      fun.(first, amount, step)\n    else\n      []\n    end\n  end\n\n  defp amount_with_step(amount, 1), do: amount\n  defp amount_with_step(amount, step), do: div(amount - 1, step) + 1\n\n  @doc \"\"\"\n  Returns a subset list of the given `enumerable`, from `start_index` (zero-based)\n  with `amount` number of elements if available.\n\n  Given an `enumerable`, it drops elements right before element `start_index`;\n  then, it takes `amount` of elements, returning as many elements as possible if\n  there are not enough elements.\n\n  A negative `start_index` can be passed, which means the `enumerable` is\n  enumerated once and the index is counted from the end (for example,\n  `-1` starts slicing from the last element).\n\n  It returns `[]` if `amount` is `0` or if `start_index` is out of bounds.\n\n  ## Examples\n\n      iex> Enum.slice(1..100, 5, 10)\n      [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]\n\n      # amount to take is greater than the number of elements\n      iex> Enum.slice(1..10, 5, 100)\n      [6, 7, 8, 9, 10]\n\n      iex> Enum.slice(1..10, 5, 0)\n      []\n\n      # using a negative start index\n      iex> Enum.slice(1..10, -6, 3)\n      [5, 6, 7]\n      iex> Enum.slice(1..10, -11, 5)\n      [1, 2, 3, 4, 5]\n\n      # out of bound start index\n      iex> Enum.slice(1..10, 10, 5)\n      []\n\n  \"\"\"\n  @spec slice(t, index, non_neg_integer) :: list\n  def slice(_enumerable, start_index, 0) when is_integer(start_index), do: []\n\n  def slice(enumerable, start_index, amount)\n      when is_integer(start_index) and start_index < 0 and is_integer(amount) and amount >= 0 do\n    {count, fun} = slice_count_and_fun(enumerable, 1)\n    start_index = Kernel.max(count + start_index, 0)\n    amount = Kernel.min(amount, count - start_index)\n\n    if amount > 0 do\n      fun.(start_index, amount, 1)\n    else\n      []\n    end\n  end\n\n  def slice(enumerable, start_index, amount)\n      when is_integer(start_index) and is_integer(amount) and amount >= 0 do\n    slice_forward(enumerable, start_index, amount, 1)\n  end\n\n  @doc \"\"\"\n  Sorts the `enumerable` according to Erlang's term ordering.\n\n  This function uses the merge sort algorithm. Do not use this\n  function to sort structs, see `sort/2` for more information.\n\n  ## Examples\n\n      iex> Enum.sort([3, 2, 1])\n      [1, 2, 3]\n\n  \"\"\"\n  @spec sort(t) :: list\n  def sort(enumerable) when is_list(enumerable) do\n    :lists.sort(enumerable)\n  end\n\n  def sort(enumerable) do\n    sort(enumerable, &(&1 <= &2))\n  end\n\n  @doc \"\"\"\n  Sorts the `enumerable` by the given function.\n\n  This function uses the merge sort algorithm. The given function should compare\n  two arguments, and return `true` if the first argument precedes or is in the\n  same place as the second one.\n\n  ## Examples\n\n      iex> Enum.sort([1, 2, 3], &(&1 >= &2))\n      [3, 2, 1]\n\n  The sorting algorithm will be stable as long as the given function\n  returns `true` for values considered equal:\n\n      iex> Enum.sort([\"some\", \"kind\", \"of\", \"monster\"], &(byte_size(&1) <= byte_size(&2)))\n      [\"of\", \"some\", \"kind\", \"monster\"]\n\n  If the function does not return `true` for equal values, the sorting\n  is not stable and the order of equal terms may be shuffled.\n  For example:\n\n      iex> Enum.sort([\"some\", \"kind\", \"of\", \"monster\"], &(byte_size(&1) < byte_size(&2)))\n      [\"of\", \"kind\", \"some\", \"monster\"]\n\n  ## Ascending and descending (since v1.10.0)\n\n  `sort/2` allows a developer to pass `:asc` or `:desc` as the sorter, which is a convenience for\n  [`&<=/2`](`<=/2`) and [`&>=/2`](`>=/2`) respectively.\n\n      iex> Enum.sort([2, 3, 1], :asc)\n      [1, 2, 3]\n      iex> Enum.sort([2, 3, 1], :desc)\n      [3, 2, 1]\n\n  ## Sorting structs\n\n  Do not use `</2`, `<=/2`, `>/2`, `>=/2` and friends when sorting structs.\n  That's because the built-in operators above perform structural comparison\n  and not a semantic one. Imagine we sort the following list of dates:\n\n      iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]\n      iex> Enum.sort(dates)\n      [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]\n\n  Note that the returned result is incorrect, because `sort/1` by default uses\n  `<=/2`, which will compare their structure. When comparing structures, the\n  fields are compared in alphabetical order, which means the dates above will\n  be compared by `day`, `month` and then `year`, which is the opposite of what\n  we want.\n\n  For this reason, most structs provide a \"compare\" function, such as\n  `Date.compare/2`, which receives two structs and returns `:lt` (less-than),\n  `:eq` (equal to), and `:gt` (greater-than). If you pass a module as the\n  sorting function, Elixir will automatically use the `compare/2` function\n  of said module:\n\n      iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]\n      iex> Enum.sort(dates, Date)\n      [~D[2019-01-01], ~D[2019-06-06], ~D[2020-03-02]]\n\n  To retrieve all dates in descending order, you can wrap the module in\n  a tuple with `:asc` or `:desc` as first element:\n\n      iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]\n      iex> Enum.sort(dates, {:asc, Date})\n      [~D[2019-01-01], ~D[2019-06-06], ~D[2020-03-02]]\n      iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]\n      iex> Enum.sort(dates, {:desc, Date})\n      [~D[2020-03-02], ~D[2019-06-06], ~D[2019-01-01]]\n\n  \"\"\"\n  @spec sort(\n          t,\n          (element, element -> boolean) | :asc | :desc | module() | {:asc | :desc, module()}\n        ) :: list\n  def sort(enumerable, sorter) when is_list(enumerable) do\n    case sorter do\n      :asc -> :lists.sort(enumerable)\n      :desc -> :lists.sort(enumerable) |> :lists.reverse()\n      _ -> :lists.sort(to_sort_fun(sorter), enumerable)\n    end\n  end\n\n  def sort(enumerable, sorter) do\n    fun = to_sort_fun(sorter)\n\n    reduce(enumerable, [], &sort_reducer(&1, &2, fun))\n    |> sort_terminator(fun)\n  end\n\n  defp to_sort_fun(sorter) when is_function(sorter, 2), do: sorter\n  defp to_sort_fun(:asc), do: &<=/2\n  defp to_sort_fun(:desc), do: &>=/2\n  defp to_sort_fun(module) when is_atom(module), do: &(module.compare(&1, &2) != :gt)\n  defp to_sort_fun({:asc, module}) when is_atom(module), do: &(module.compare(&1, &2) != :gt)\n  defp to_sort_fun({:desc, module}) when is_atom(module), do: &(module.compare(&1, &2) != :lt)\n\n  @doc \"\"\"\n  Sorts the mapped results of the `enumerable` according to the provided `sorter`\n  function.\n\n  This function maps each element of the `enumerable` using the\n  provided `mapper` function. The enumerable is then sorted by\n  the mapped elements using the `sorter`, which defaults to `:asc`\n  and sorts the elements ascendingly.\n\n  `sort_by/3` differs from `sort/2` in that it only calculates the\n  comparison value for each element in the enumerable once instead of\n  once for each element in each comparison. If the same function is\n  being called on both elements, it's more efficient to use `sort_by/3`.\n\n  ## Ascending and descending (since v1.10.0)\n\n  `sort_by/3` allows a developer to pass `:asc` or `:desc` as the sorter,\n  which is a convenience for [`&<=/2`](`<=/2`) and [`&>=/2`](`>=/2`) respectively:\n      iex> Enum.sort_by([2, 3, 1], &(&1), :asc)\n      [1, 2, 3]\n\n      iex> Enum.sort_by([2, 3, 1], &(&1), :desc)\n      [3, 2, 1]\n\n  ## Examples\n\n  Using the default `sorter` of `:asc` :\n\n      iex> Enum.sort_by([\"some\", \"kind\", \"of\", \"monster\"], &byte_size/1)\n      [\"of\", \"some\", \"kind\", \"monster\"]\n\n  Sorting by multiple properties - first by size, then by first letter\n  (this takes advantage of the fact that tuples are compared element-by-element):\n\n      iex> Enum.sort_by([\"some\", \"kind\", \"of\", \"monster\"], &{byte_size(&1), String.first(&1)})\n      [\"of\", \"kind\", \"some\", \"monster\"]\n\n  Similar to `sort/2`, you can pass a custom sorter:\n\n      iex> Enum.sort_by([\"some\", \"kind\", \"of\", \"monster\"], &byte_size/1, :desc)\n      [\"monster\", \"some\", \"kind\", \"of\"]\n\n  As in `sort/2`, avoid using the default sorting function to sort\n  structs, as by default it performs structural comparison instead of\n  a semantic one. In such cases, you shall pass a sorting function as\n  third element or any module that implements a `compare/2` function.\n  For example, to sort users by their birthday in both ascending and\n  descending order respectively:\n\n      iex> users = [\n      ...>   %{name: \"Ellis\", birthday: ~D[1943-05-11]},\n      ...>   %{name: \"Lovelace\", birthday: ~D[1815-12-10]},\n      ...>   %{name: \"Turing\", birthday: ~D[1912-06-23]}\n      ...> ]\n      iex> Enum.sort_by(users, &(&1.birthday), Date)\n      [\n        %{name: \"Lovelace\", birthday: ~D[1815-12-10]},\n        %{name: \"Turing\", birthday: ~D[1912-06-23]},\n        %{name: \"Ellis\", birthday: ~D[1943-05-11]}\n      ]\n      iex> Enum.sort_by(users, &(&1.birthday), {:desc, Date})\n      [\n        %{name: \"Ellis\", birthday: ~D[1943-05-11]},\n        %{name: \"Turing\", birthday: ~D[1912-06-23]},\n        %{name: \"Lovelace\", birthday: ~D[1815-12-10]}\n      ]\n\n  ## Performance characteristics\n\n  As detailed in the initial section, `sort_by/3` calculates the comparison\n  value for each element in the enumerable once instead of once for each\n  element in each comparison. This implies `sort_by/3` must do an initial\n  pass on the data to compute those values.\n\n  However, if those values are cheap to compute, for example, you have\n  already extracted the field you want to sort by into a tuple, then those\n  extra passes become overhead. In such cases, consider using `List.keysort/3`\n  instead.\n\n  Let's see an example. Imagine you have a list of products and you have a\n  list of IDs. You want to keep all products that are in the given IDs and\n  return their names sorted by their price. You could write it like this:\n\n      for(\n        product <- products,\n        product.id in ids,\n        do: product\n      )\n      |> Enum.sort_by(& &1.price)\n      |> Enum.map(& &1.name)\n\n  However, you could also write it like this:\n\n      for(\n        product <- products,\n        product.id in ids,\n        do: {product.name, product.price}\n      )\n      |> List.keysort(1)\n      |> Enum.map(&elem(&1, 0))\n\n  Using `List.keysort/3` will be a better choice for performance sensitive\n  code as it avoids additional traversals.\n  \"\"\"\n  @spec sort_by(\n          t,\n          (element -> mapped_element),\n          (element, element -> boolean) | :asc | :desc | module() | {:asc | :desc, module()}\n        ) ::\n          list\n        when mapped_element: element\n  def sort_by(enumerable, mapper, sorter \\\\ :asc)\n\n  def sort_by(enumerable, mapper, :desc) when is_function(mapper, 1) do\n    enumerable\n    |> reduce([], &[{&1, mapper.(&1)} | &2])\n    |> List.keysort(1, :asc)\n    |> List.foldl([], &[elem(&1, 0) | &2])\n  end\n\n  def sort_by(enumerable, mapper, sorter) when is_function(mapper, 1) do\n    enumerable\n    |> map(&{&1, mapper.(&1)})\n    |> List.keysort(1, sorter)\n    |> map(&elem(&1, 0))\n  end\n\n  @doc \"\"\"\n  Splits the `enumerable` into two enumerables, leaving `count`\n  elements in the first one.\n\n  If `count` is a negative number, it starts counting from the\n  back to the beginning of the `enumerable`.\n\n  Be aware that a negative `count` implies the `enumerable`\n  will be enumerated twice: once to calculate the position, and\n  a second time to do the actual splitting.\n\n  ## Examples\n\n      iex> Enum.split([1, 2, 3], 2)\n      {[1, 2], [3]}\n\n      iex> Enum.split([1, 2, 3], 10)\n      {[1, 2, 3], []}\n\n      iex> Enum.split([1, 2, 3], 0)\n      {[], [1, 2, 3]}\n\n      iex> Enum.split([1, 2, 3], -1)\n      {[1, 2], [3]}\n\n      iex> Enum.split([1, 2, 3], -5)\n      {[], [1, 2, 3]}\n\n  \"\"\"\n  @spec split(t, integer) :: {list, list}\n  def split(enumerable, count) when is_list(enumerable) and is_integer(count) and count >= 0 do\n    split_list(enumerable, count, [])\n  end\n\n  def split(enumerable, count) when is_integer(count) and count >= 0 do\n    {_, list1, list2} =\n      reduce(enumerable, {count, [], []}, fn entry, {counter, acc1, acc2} ->\n        if counter > 0 do\n          {counter - 1, [entry | acc1], acc2}\n        else\n          {counter, acc1, [entry | acc2]}\n        end\n      end)\n\n    {:lists.reverse(list1), :lists.reverse(list2)}\n  end\n\n  def split(enumerable, count) when is_integer(count) and count < 0 do\n    split_reverse_list(reverse(enumerable), -count, [])\n  end\n\n  @doc \"\"\"\n  Splits enumerable in two at the position of the element for which\n  `fun` returns a falsy value (`false` or `nil`) for the first time.\n\n  It returns a two-element tuple with two lists of elements.\n  The element that triggered the split is part of the second list.\n\n  ## Examples\n\n      iex> Enum.split_while([1, 2, 3, 4], fn x -> x < 3 end)\n      {[1, 2], [3, 4]}\n\n      iex> Enum.split_while([1, 2, 3, 4], fn x -> x < 0 end)\n      {[], [1, 2, 3, 4]}\n\n      iex> Enum.split_while([1, 2, 3, 4], fn x -> x > 0 end)\n      {[1, 2, 3, 4], []}\n\n  \"\"\"\n  @spec split_while(t, (element -> as_boolean(term))) :: {list, list}\n  def split_while(enumerable, fun) when is_list(enumerable) do\n    split_while_list(enumerable, fun, [])\n  end\n\n  def split_while(enumerable, fun) do\n    {list1, list2} =\n      reduce(enumerable, {[], []}, fn\n        entry, {acc1, []} ->\n          if(fun.(entry), do: {[entry | acc1], []}, else: {acc1, [entry]})\n\n        entry, {acc1, acc2} ->\n          {acc1, [entry | acc2]}\n      end)\n\n    {:lists.reverse(list1), :lists.reverse(list2)}\n  end\n\n  @doc \"\"\"\n  Returns the sum of all elements.\n\n  Raises `ArithmeticError` if `enumerable` contains a non-numeric value.\n\n  If you need to apply a transformation first, consider using `Enum.sum_by/2` instead.\n\n  ## Examples\n\n      iex> Enum.sum([1, 2, 3])\n      6\n\n      iex> Enum.sum(1..10)\n      55\n\n      iex> Enum.sum(1..10//2)\n      25\n\n  \"\"\"\n  @spec sum(t) :: number\n  def sum(enumerable)\n\n  def sum(first..last//step = range) do\n    range\n    |> Range.size()\n    |> Kernel.*(first + last - rem(last - first, step))\n    |> div(2)\n  end\n\n  def sum(enumerable) do\n    reduce(enumerable, 0, &+/2)\n  end\n\n  @doc \"\"\"\n  Maps and sums the given `enumerable` in one pass.\n\n  Raises `ArithmeticError` if `mapper` returns a non-numeric value.\n\n  ## Examples\n\n      iex> Enum.sum_by([%{count: 1}, %{count: 2}, %{count: 3}], fn x -> x.count end)\n      6\n\n      iex> Enum.sum_by(1..3, fn x -> x ** 2 end)\n      14\n\n      iex> Enum.sum_by([], fn x -> x.count end)\n      0\n\n  Filtering can be achieved by returning `0` to ignore elements:\n\n      iex> Enum.sum_by([1, -2, 3], fn x -> if x > 0, do: x, else: 0 end)\n      4\n\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec sum_by(t, (element -> number)) :: number\n  def sum_by(enumerable, mapper)\n\n  def sum_by(list, mapper) when is_list(list) and is_function(mapper, 1) do\n    sum_by_list(list, mapper, 0)\n  end\n\n  def sum_by(enumerable, mapper) when is_function(mapper, 1) do\n    reduce(enumerable, 0, fn x, acc -> acc + mapper.(x) end)\n  end\n\n  @doc \"\"\"\n  Returns the product of all elements.\n\n  Raises `ArithmeticError` if `enumerable` contains a non-numeric value.\n\n  If you need to apply a transformation first, consider using `Enum.product_by/2` instead.\n\n  ## Examples\n\n      iex> Enum.product([])\n      1\n      iex> Enum.product([2, 3, 4])\n      24\n      iex> Enum.product([2.0, 3.0, 4.0])\n      24.0\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec product(t) :: number\n  def product(enumerable) do\n    reduce(enumerable, 1, &*/2)\n  end\n\n  @doc \"\"\"\n  Maps and computes the product of the given `enumerable` in one pass.\n\n  Raises `ArithmeticError` if `mapper` returns a non-numeric value.\n\n  ## Examples\n\n      iex> Enum.product_by([%{count: 2}, %{count: 4}, %{count: 3}], fn x -> x.count end)\n      24\n\n      iex> Enum.product_by(1..3, fn x -> x ** 2 end)\n      36\n\n      iex> Enum.product_by([], fn x -> x.count end)\n      1\n\n  Filtering can be achieved by returning `1` to ignore elements:\n\n      iex> Enum.product_by([2, -1, 3], fn x -> if x > 0, do: x, else: 1 end)\n      6\n\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec product_by(t, (element -> number)) :: number\n  def product_by(enumerable, mapper)\n\n  def product_by(list, mapper) when is_list(list) and is_function(mapper, 1) do\n    product_by_list(list, mapper, 1)\n  end\n\n  def product_by(enumerable, mapper) when is_function(mapper, 1) do\n    reduce(enumerable, 1, fn x, acc -> acc * mapper.(x) end)\n  end\n\n  @doc \"\"\"\n  Takes an `amount` of elements from the beginning or the end of the `enumerable`.\n\n  If a positive `amount` is given, it takes the `amount` elements from the\n  beginning of the `enumerable`.\n\n  If a negative `amount` is given, the `amount` of elements will be taken from the end.\n  The `enumerable` will be enumerated once to retrieve the proper index and\n  the remaining calculation is performed from the end.\n\n  If amount is `0`, it returns `[]`.\n\n  ## Examples\n\n      iex> Enum.take([1, 2, 3], 2)\n      [1, 2]\n\n      iex> Enum.take([1, 2, 3], 10)\n      [1, 2, 3]\n\n      iex> Enum.take([1, 2, 3], 0)\n      []\n\n      iex> Enum.take([1, 2, 3], -1)\n      [3]\n\n  \"\"\"\n  @spec take(t, integer) :: list\n  def take(enumerable, amount)\n\n  def take(_enumerable, 0), do: []\n\n  def take(enumerable, amount)\n      when is_list(enumerable) and is_integer(amount) and amount > 0 do\n    take_list(enumerable, amount)\n  end\n\n  def take(enumerable, amount) when is_integer(amount) and amount > 0 do\n    {_, {res, _}} =\n      Enumerable.reduce(enumerable, {:cont, {[], amount}}, fn entry, {list, n} ->\n        case n do\n          1 -> {:halt, {[entry | list], n - 1}}\n          _ -> {:cont, {[entry | list], n - 1}}\n        end\n      end)\n\n    :lists.reverse(res)\n  end\n\n  def take(enumerable, amount) when is_integer(amount) and amount < 0 do\n    case slice_count_and_fun(enumerable, 1) do\n      {0, _fun} ->\n        []\n\n      {count, fun} ->\n        first = Kernel.max(amount + count, 0)\n        fun.(first, count - first, 1)\n    end\n  end\n\n  @doc \"\"\"\n  Returns a list of every `nth` element in the `enumerable`,\n  starting with the first element.\n\n  The first element is always included, unless `nth` is 0.\n\n  The second argument specifying every `nth` element must be a non-negative\n  integer.\n\n  ## Examples\n\n      iex> Enum.take_every(1..10, 2)\n      [1, 3, 5, 7, 9]\n\n      iex> Enum.take_every(1..10, 0)\n      []\n\n      iex> Enum.take_every([1, 2, 3], 1)\n      [1, 2, 3]\n\n  \"\"\"\n  @spec take_every(t, non_neg_integer) :: list\n  def take_every(enumerable, nth)\n\n  def take_every(_enumerable, 0), do: []\n  def take_every(enumerable, 1), do: to_list(enumerable)\n\n  def take_every(list, nth) when is_list(list) and is_integer(nth) and nth > 1 do\n    take_every_list(list, nth - 1)\n  end\n\n  def take_every(enumerable, nth) when is_integer(nth) and nth > 1 do\n    {res, _} = reduce(enumerable, {[], :first}, R.take_every(nth))\n    :lists.reverse(res)\n  end\n\n  @doc \"\"\"\n  Takes `count` random elements from `enumerable`.\n\n  Note that this function will traverse the whole `enumerable` to\n  get the random sublist.\n\n  See `random/1` for notes on implementation and random seed.\n\n  ## Examples\n\n      # Although not necessary, let's seed the random algorithm\n      iex> :rand.seed(:exsss, {1, 2, 3})\n      iex> Enum.take_random(1..10, 2)\n      [6, 1]\n      iex> Enum.take_random(?a..?z, 5)\n      ~c\"bkzmt\"\n\n  \"\"\"\n  @spec take_random(t, non_neg_integer) :: list\n  def take_random(enumerable, count)\n  def take_random(_enumerable, 0), do: []\n  def take_random([], _), do: []\n\n  def take_random(enumerable, 1) do\n    enumerable\n    |> reduce({0, 0, 1.0, nil}, fn\n      elem, {idx, idx, w, _current} ->\n        {jdx, w} = take_jdx_w(idx, w, 1)\n        {idx + 1, jdx, w, elem}\n\n      _elem, {idx, jdx, w, current} ->\n        {idx + 1, jdx, w, current}\n    end)\n    |> case do\n      {0, 0, 1.0, nil} -> []\n      {_idx, _jdx, _w, current} -> [current]\n    end\n  end\n\n  def take_random(enumerable, count) when count in 0..128 do\n    sample = Tuple.duplicate(nil, count)\n\n    reducer = fn\n      elem, {idx, jdx, w, sample} when idx < count ->\n        rand = take_index(idx)\n        sample = sample |> put_elem(idx, elem(sample, rand)) |> put_elem(rand, elem)\n\n        if idx == jdx do\n          {jdx, w} = take_jdx_w(idx, w, count)\n          {idx + 1, jdx, w, sample}\n        else\n          {idx + 1, jdx, w, sample}\n        end\n\n      elem, {idx, idx, w, sample} ->\n        pos = :rand.uniform(count) - 1\n        {jdx, w} = take_jdx_w(idx, w, count)\n        {idx + 1, jdx, w, put_elem(sample, pos, elem)}\n\n      _elem, {idx, jdx, w, sample} ->\n        {idx + 1, jdx, w, sample}\n    end\n\n    {size, _, _, sample} = reduce(enumerable, {0, count - 1, 1.0, sample}, reducer)\n\n    if count < size do\n      Tuple.to_list(sample)\n    else\n      take_tupled(sample, size, [])\n    end\n  end\n\n  def take_random(enumerable, count) when is_integer(count) and count >= 0 do\n    reducer = fn\n      elem, {idx, jdx, w, sample} when idx < count ->\n        rand = take_index(idx)\n        sample = sample |> Map.put(idx, Map.get(sample, rand)) |> Map.put(rand, elem)\n\n        if idx == jdx do\n          {jdx, w} = take_jdx_w(idx, w, count)\n          {idx + 1, jdx, w, sample}\n        else\n          {idx + 1, jdx, w, sample}\n        end\n\n      elem, {idx, idx, w, sample} ->\n        pos = :rand.uniform(count) - 1\n        {jdx, w} = take_jdx_w(idx, w, count)\n        {idx + 1, jdx, w, %{sample | pos => elem}}\n\n      _elem, {idx, jdx, w, sample} ->\n        {idx + 1, jdx, w, sample}\n    end\n\n    {size, _, _, sample} = reduce(enumerable, {0, count - 1, 1.0, %{}}, reducer)\n    take_mapped(sample, Kernel.min(count, size), [])\n  end\n\n  @compile {:inline, take_jdx_w: 3, take_index: 1}\n  defp take_jdx_w(idx, w, count) do\n    w = w * :math.exp(:math.log(:rand.uniform()) / count)\n    jdx = idx + floor(:math.log(:rand.uniform()) / :math.log(1 - w)) + 1\n    {jdx, w}\n  end\n\n  defp take_index(0), do: 0\n  defp take_index(idx), do: :rand.uniform(idx + 1) - 1\n\n  defp take_tupled(_sample, 0, acc), do: acc\n\n  defp take_tupled(sample, position, acc) do\n    position = position - 1\n    take_tupled(sample, position, [elem(sample, position) | acc])\n  end\n\n  defp take_mapped(_sample, 0, acc), do: acc\n\n  defp take_mapped(sample, position, acc) do\n    position = position - 1\n    take_mapped(sample, position, [Map.fetch!(sample, position) | acc])\n  end\n\n  @doc \"\"\"\n  Takes the elements from the beginning of the `enumerable` while `fun` returns\n  a truthy value.\n\n  ## Examples\n\n      iex> Enum.take_while([1, 2, 3], fn x -> x < 3 end)\n      [1, 2]\n\n  \"\"\"\n  @spec take_while(t, (element -> as_boolean(term))) :: list\n  def take_while(enumerable, fun) when is_list(enumerable) do\n    take_while_list(enumerable, fun)\n  end\n\n  def take_while(enumerable, fun) do\n    {_, res} =\n      Enumerable.reduce(enumerable, {:cont, []}, fn entry, acc ->\n        if fun.(entry) do\n          {:cont, [entry | acc]}\n        else\n          {:halt, acc}\n        end\n      end)\n\n    :lists.reverse(res)\n  end\n\n  @doc \"\"\"\n  Converts `enumerable` to a list.\n\n  ## Examples\n\n      iex> Enum.to_list(1..3)\n      [1, 2, 3]\n\n  \"\"\"\n  @spec to_list(t) :: [element]\n  def to_list(enumerable) when is_list(enumerable), do: enumerable\n  def to_list(%{__struct__: Range} = range), do: Range.to_list(range)\n  def to_list(%_{} = enumerable), do: reverse(enumerable) |> :lists.reverse()\n  def to_list(%{} = enumerable), do: Map.to_list(enumerable)\n  def to_list(enumerable), do: reverse(enumerable) |> :lists.reverse()\n\n  @doc \"\"\"\n  Enumerates the `enumerable`, removing all duplicate elements.\n\n  The first occurrence of each element is kept and all following\n  duplicates are removed. The overall order is preserved.\n\n  ## Examples\n\n      iex> Enum.uniq([1, 2, 3, 3, 2, 1])\n      [1, 2, 3]\n\n  \"\"\"\n  @spec uniq(t) :: list\n  def uniq(enumerable) do\n    uniq_by(enumerable, fn x -> x end)\n  end\n\n  @doc false\n  @deprecated \"Use Enum.uniq_by/2 instead\"\n  def uniq(enumerable, fun) do\n    uniq_by(enumerable, fun)\n  end\n\n  @doc \"\"\"\n  Enumerates the `enumerable`, by removing the elements for which\n  function `fun` returned duplicate elements.\n\n  The function `fun` maps every element to a term. Two elements are\n  considered duplicates if the return value of `fun` is equal for\n  both of them.\n\n  The first occurrence of each element is kept and all following\n  duplicates are removed. The overall order is preserved.\n\n  ## Example\n\n      iex> Enum.uniq_by([{1, :x}, {2, :y}, {1, :z}], fn {x, _} -> x end)\n      [{1, :x}, {2, :y}]\n\n      iex> Enum.uniq_by([a: {:tea, 2}, b: {:tea, 2}, c: {:coffee, 1}], fn {_, y} -> y end)\n      [a: {:tea, 2}, c: {:coffee, 1}]\n\n  \"\"\"\n  @spec uniq_by(t, (element -> term)) :: list\n\n  def uniq_by(enumerable, fun) when is_list(enumerable) do\n    uniq_list(enumerable, %{}, fun)\n  end\n\n  def uniq_by(enumerable, fun) do\n    {list, _} = reduce(enumerable, {[], %{}}, R.uniq_by(fun))\n    :lists.reverse(list)\n  end\n\n  @doc \"\"\"\n  Opposite of `zip/2`. Extracts two-element tuples from the\n  given `enumerable` and groups them together.\n\n  It takes an `enumerable` with elements being two-element tuples and returns\n  a tuple with two lists, each of which is formed by the first and\n  second element of each tuple, respectively.\n\n  This function fails unless `enumerable` is or can be converted into a\n  list of tuples with *exactly* two elements in each tuple.\n\n  ## Examples\n\n      iex> Enum.unzip([{:a, 1}, {:b, 2}, {:c, 3}])\n      {[:a, :b, :c], [1, 2, 3]}\n\n  \"\"\"\n  @spec unzip(t) :: {[element], [element]}\n  def unzip(enumerable)\n\n  def unzip([_ | _] = list) do\n    :lists.reverse(list) |> unzip([], [])\n  end\n\n  def unzip([]) do\n    {[], []}\n  end\n\n  def unzip(enumerable) do\n    {list1, list2} =\n      reduce(enumerable, {[], []}, fn {el1, el2}, {list1, list2} ->\n        {[el1 | list1], [el2 | list2]}\n      end)\n\n    {:lists.reverse(list1), :lists.reverse(list2)}\n  end\n\n  defp unzip([{el1, el2} | reversed_list], list1, list2) do\n    unzip(reversed_list, [el1 | list1], [el2 | list2])\n  end\n\n  defp unzip([], list1, list2) do\n    {list1, list2}\n  end\n\n  @doc \"\"\"\n  Returns the `enumerable` with each element wrapped in a tuple\n  alongside its index or according to a given function.\n\n  If an integer offset is given as `fun_or_offset`, it will index from the given\n  offset instead of from zero.\n\n  If a 2-arity function is given as `fun_or_offset`, the function will be invoked\n  for each element in `enumerable` as the first argument and with a zero-based\n  index as the second. `with_index/2` returns a list with the result of each invocation.\n\n  ## Examples\n\n      iex> Enum.with_index([:a, :b, :c])\n      [a: 0, b: 1, c: 2]\n\n      iex> Enum.with_index([:a, :b, :c], 3)\n      [a: 3, b: 4, c: 5]\n\n      iex> Enum.with_index([:a, :b, :c], fn element, index -> {index, element} end)\n      [{0, :a}, {1, :b}, {2, :c}]\n\n  \"\"\"\n  @spec with_index(t, integer) :: [{term, integer}]\n  @spec with_index(t, (element, index -> value)) :: [value] when value: any\n  def with_index(enumerable, fun_or_offset \\\\ 0)\n\n  def with_index(enumerable, offset) when is_list(enumerable) and is_integer(offset) do\n    with_index_list(enumerable, offset)\n  end\n\n  def with_index(enumerable, fun) when is_list(enumerable) and is_function(fun, 2) do\n    with_index_list(enumerable, 0, fun)\n  end\n\n  def with_index(enumerable, offset) when is_integer(offset) do\n    enumerable\n    |> map_reduce(offset, fn x, i -> {{x, i}, i + 1} end)\n    |> elem(0)\n  end\n\n  def with_index(enumerable, fun) when is_function(fun, 2) do\n    enumerable\n    |> map_reduce(0, fn x, i -> {fun.(x, i), i + 1} end)\n    |> elem(0)\n  end\n\n  @doc \"\"\"\n  Zips corresponding elements from two enumerables into a list\n  of tuples.\n\n  Because a list of two-element tuples with atoms as the first\n  tuple element is a keyword list (`Keyword`), zipping a first list\n  of atoms with a second list of any kind creates a keyword list.\n\n  The zipping finishes as soon as either enumerable completes.\n\n  ## Examples\n\n      iex> Enum.zip([1, 2, 3], [:a, :b, :c])\n      [{1, :a}, {2, :b}, {3, :c}]\n\n      iex> Enum.zip([:a, :b, :c], [1, 2, 3])\n      [a: 1, b: 2, c: 3]\n\n      iex> Enum.zip([1, 2, 3, 4, 5], [:a, :b, :c])\n      [{1, :a}, {2, :b}, {3, :c}]\n\n  \"\"\"\n  @spec zip(t, t) :: [{any, any}]\n  def zip(enumerable1, enumerable2) when is_list(enumerable1) and is_list(enumerable2) do\n    zip_list(enumerable1, enumerable2, [])\n  end\n\n  def zip(enumerable1, enumerable2) do\n    zip([enumerable1, enumerable2])\n  end\n\n  @doc \"\"\"\n  Zips corresponding elements from a finite collection of enumerables\n  into a list of tuples.\n\n  The zipping finishes as soon as any enumerable in the given collection completes.\n\n  ## Examples\n\n      iex> Enum.zip([[1, 2, 3], [:a, :b, :c], [\"foo\", \"bar\", \"baz\"]])\n      [{1, :a, \"foo\"}, {2, :b, \"bar\"}, {3, :c, \"baz\"}]\n\n      iex> Enum.zip([[1, 2, 3, 4, 5], [:a, :b, :c]])\n      [{1, :a}, {2, :b}, {3, :c}]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec zip(enumerables) :: [tuple()] when enumerables: [t()] | t()\n  def zip([]), do: []\n\n  def zip(enumerables) do\n    zip_reduce(enumerables, [], &[List.to_tuple(&1) | &2])\n    |> :lists.reverse()\n  end\n\n  @doc \"\"\"\n  Zips corresponding elements from two enumerables into a list, transforming them with\n  the `zip_fun` function as it goes.\n\n  The corresponding elements from each collection are passed to the provided two-arity `zip_fun`\n  function in turn. Returns a list that contains the result of calling `zip_fun` for each pair of\n  elements.\n\n  The zipping finishes as soon as either enumerable runs out of elements.\n\n  ## Zipping Maps\n\n  It's important to remember that zipping inherently relies on order.\n  If you zip two lists you get the element at the index from each list in turn.\n  If we zip two maps together it's tempting to think that you will get the given\n  key in the left map and the matching key in the right map, but there is no such\n  guarantee because map keys are not ordered! Consider the following:\n\n      left = %{:a => 1, 1 => 3}\n      right = %{:a => 1, :b => :c}\n      Enum.zip(left, right)\n      #=> [{{1, 3}, {:a, 1}}, {{:a, 1}, {:b, :c}}]\n\n  As you can see `:a` does not get paired with `:a`. If this is what you want,\n  you should use `Map.merge/3`.\n\n  ## Examples\n\n      iex> Enum.zip_with([1, 2], [3, 4], fn x, y -> x + y end)\n      [4, 6]\n\n      iex> Enum.zip_with([1, 2], [3, 4, 5, 6], fn x, y -> x + y end)\n      [4, 6]\n\n      iex> Enum.zip_with([1, 2, 5, 6], [3, 4], fn x, y -> x + y end)\n      [4, 6]\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec zip_with(t, t, (enum1_elem :: term, enum2_elem :: term -> term)) :: [term]\n  def zip_with(enumerable1, enumerable2, zip_fun)\n      when is_list(enumerable1) and is_list(enumerable2) and is_function(zip_fun, 2) do\n    zip_with_list(enumerable1, enumerable2, zip_fun)\n  end\n\n  def zip_with(enumerable1, enumerable2, zip_fun) when is_function(zip_fun, 2) do\n    zip_reduce(enumerable1, enumerable2, [], fn l, r, acc -> [zip_fun.(l, r) | acc] end)\n    |> :lists.reverse()\n  end\n\n  @doc \"\"\"\n  Zips corresponding elements from a finite collection of enumerables\n  into list, transforming them with the `zip_fun` function as it goes.\n\n  The first element from each of the enums in `enumerables` will be put\n  into a list which is then passed to the one-arity `zip_fun` function.\n  Then, the second elements from each of the enums are put into a list\n  and passed to `zip_fun`, and so on until any one of the enums in\n  `enumerables` runs out of elements.\n\n  Returns a list with all the results of calling `zip_fun`.\n\n  ## Examples\n\n      iex> Enum.zip_with([[1, 2], [3, 4], [5, 6]], fn [x, y, z] -> x + y + z end)\n      [9, 12]\n\n      iex> Enum.zip_with([[1, 2], [3, 4]], fn [x, y] -> x + y end)\n      [4, 6]\n\n  `zip_with/2` can be used to transpose lists of lists:\n\n      iex> Enum.zip_with([[1, 2,], [3, 4]], & &1)\n      [[1, 3], [2, 4]]\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec zip_with(t, ([term] -> term)) :: [term]\n  def zip_with([], _fun), do: []\n\n  def zip_with(enumerables, zip_fun) do\n    zip_reduce(enumerables, [], fn values, acc -> [zip_fun.(values) | acc] end)\n    |> :lists.reverse()\n  end\n\n  @doc \"\"\"\n  Reduces over two enumerables halting as soon as either enumerable is empty.\n\n  In practice, the behavior provided by this function can be achieved with:\n\n      Enum.reduce(Stream.zip(left, right), acc, reducer)\n\n  But `zip_reduce/4` exists for convenience purposes.\n\n  ## Examples\n\n      iex> Enum.zip_reduce([1, 2], [3, 4], 0, fn x, y, acc -> x + y + acc end)\n      10\n\n  If one of the lists has more entries than the others,\n  those entries are discarded:\n\n      iex> Enum.zip_reduce([1, 2, 3], [4, 5], [], fn x, y, acc -> [x + y | acc] end)\n      [7, 5]\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec zip_reduce(t, t, acc, (enum1_elem :: term, enum2_elem :: term, acc -> acc)) :: acc\n        when acc: term\n  def zip_reduce(left, right, acc, reducer)\n      when is_list(left) and is_list(right) and is_function(reducer, 3) do\n    zip_reduce_list(left, right, acc, reducer)\n  end\n\n  def zip_reduce(left, right, acc, reducer) when is_function(reducer, 3) do\n    reduce = fn [l, r], acc -> {:cont, reducer.(l, r, acc)} end\n    R.zip_with([left, right], & &1).({:cont, acc}, reduce) |> elem(1)\n  end\n\n  @doc \"\"\"\n  Reduces over all of the given enumerables, halting as soon as any enumerable is\n  empty.\n\n  The reducer will receive 2 args: a list of elements (one from each enum) and the\n  accumulator.\n\n  In practice, the behavior provided by this function can be achieved with:\n\n      Enum.reduce(Stream.zip(enums), acc, reducer)\n\n  But `zip_reduce/3` exists for convenience purposes.\n\n  ## Examples\n\n      iex> enums = [[1, 1], [2, 2], [3, 3]]\n      ...>  Enum.zip_reduce(enums, [], fn elements, acc ->\n      ...>    [List.to_tuple(elements) | acc]\n      ...> end)\n      [{1, 2, 3}, {1, 2, 3}]\n\n  If one of the lists has more entries than the others,\n  those entries are discarded:\n\n      iex> enums = [[1, 2], [a: 3, b: 4], [5, 6, 7]]\n      ...> Enum.zip_reduce(enums, [], fn elements, acc ->\n      ...>   [List.to_tuple(elements) | acc]\n      ...> end)\n      [{2, {:b, 4}, 6}, {1, {:a, 3}, 5}]\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec zip_reduce(t, acc, ([term], acc -> acc)) :: acc when acc: term\n  def zip_reduce([], acc, reducer) when is_function(reducer, 2), do: acc\n\n  def zip_reduce(enumerables, acc, reducer) when is_function(reducer, 2) do\n    R.zip_with(enumerables, & &1).({:cont, acc}, &{:cont, reducer.(&1, &2)}) |> elem(1)\n  end\n\n  ## Helpers\n\n  @compile {:inline,\n            entry_to_string: 1,\n            reduce: 3,\n            reduce_by: 3,\n            reduce_enumerable: 3,\n            reduce_range: 5,\n            map_range: 4}\n\n  defp entry_to_string(entry) when is_binary(entry), do: entry\n  defp entry_to_string(entry), do: String.Chars.to_string(entry)\n\n  defp aggregate([head | tail], fun, _empty) do\n    aggregate_list(tail, head, fun)\n  end\n\n  defp aggregate([], _fun, empty) do\n    empty.()\n  end\n\n  defp aggregate(first..last//step = range, fun, empty) do\n    case Range.size(range) do\n      0 ->\n        empty.()\n\n      _ ->\n        last = last - rem(last - first, step)\n\n        case fun.(first, last) do\n          true -> first\n          false -> last\n        end\n    end\n  end\n\n  defp aggregate(enumerable, fun, empty) do\n    ref = make_ref()\n\n    enumerable\n    |> reduce(ref, fn\n      element, ^ref ->\n        element\n\n      element, acc ->\n        case fun.(acc, element) do\n          true -> acc\n          false -> element\n        end\n    end)\n    |> case do\n      ^ref -> empty.()\n      result -> result\n    end\n  end\n\n  defp aggregate_list([head | tail], acc, fun) do\n    acc =\n      case fun.(acc, head) do\n        true -> acc\n        false -> head\n      end\n\n    aggregate_list(tail, acc, fun)\n  end\n\n  defp aggregate_list([], acc, _fun), do: acc\n\n  defp aggregate_by(enumerable, fun, sorter, empty_fallback) do\n    first_fun = &[&1 | fun.(&1)]\n\n    reduce_fun = fn entry, [_ | fun_ref] = old ->\n      fun_entry = fun.(entry)\n\n      case sorter.(fun_ref, fun_entry) do\n        true -> old\n        false -> [entry | fun_entry]\n      end\n    end\n\n    case reduce_by(enumerable, first_fun, reduce_fun) do\n      :empty -> empty_fallback.()\n      [entry | _] -> entry\n    end\n  end\n\n  defp reduce_by([head | tail], first, fun) do\n    :lists.foldl(fun, first.(head), tail)\n  end\n\n  defp reduce_by([], _first, _fun) do\n    :empty\n  end\n\n  defp reduce_by(enumerable, first, fun) do\n    reduce(enumerable, :empty, fn\n      element, :empty -> first.(element)\n      element, acc -> fun.(element, acc)\n    end)\n  end\n\n  ## Implementations\n\n  ## all?/1\n\n  defp all_list([h | t]) do\n    if h do\n      all_list(t)\n    else\n      false\n    end\n  end\n\n  defp all_list([]) do\n    true\n  end\n\n  ## any?/1\n\n  defp any_list([h | t]) do\n    if h do\n      true\n    else\n      any_list(t)\n    end\n  end\n\n  defp any_list([]) do\n    false\n  end\n\n  ## any?/2 all?/2\n\n  defp predicate_list([h | t], initial, fun) do\n    if !!fun.(h) == initial do\n      predicate_list(t, initial, fun)\n    else\n      not initial\n    end\n  end\n\n  defp predicate_list([], initial, _) do\n    initial\n  end\n\n  defp predicate_range(first, last, step, initial, fun)\n       when step > 0 and first <= last\n       when step < 0 and first >= last do\n    if !!fun.(first) == initial do\n      predicate_range(first + step, last, step, initial, fun)\n    else\n      not initial\n    end\n  end\n\n  defp predicate_range(_first, _last, _step, initial, _fun) do\n    initial\n  end\n\n  ## concat\n\n  defp concat_list([h | t]) when is_list(h), do: h ++ concat_list(t)\n  defp concat_list([h | t]), do: concat_enum([h | t])\n  defp concat_list([]), do: []\n\n  defp concat_enum(enum) do\n    fun = &[&1 | &2]\n    enum |> reduce([], &reduce(&1, &2, fun)) |> :lists.reverse()\n  end\n\n  # count_until\n\n  @compile {:inline, count_until_list: 3}\n\n  defp count_until_list([], _limit, acc), do: acc\n\n  defp count_until_list([_head | tail], limit, acc) do\n    case acc + 1 do\n      ^limit -> limit\n      acc -> count_until_list(tail, limit, acc)\n    end\n  end\n\n  defp count_until_enum(enumerable, limit) do\n    case Enumerable.count(enumerable) do\n      {:ok, value} ->\n        Kernel.min(value, limit)\n\n      {:error, module} ->\n        module.reduce(enumerable, {:cont, 0}, fn _entry, acc ->\n          case acc + 1 do\n            ^limit -> {:halt, limit}\n            acc -> {:cont, acc}\n          end\n        end)\n        |> elem(1)\n    end\n  end\n\n  @compile {:inline, count_until_list: 4}\n\n  defp count_until_list([], _fun, _limit, acc), do: acc\n\n  defp count_until_list([head | tail], fun, limit, acc) do\n    if fun.(head) do\n      case acc + 1 do\n        ^limit -> limit\n        acc -> count_until_list(tail, fun, limit, acc)\n      end\n    else\n      count_until_list(tail, fun, limit, acc)\n    end\n  end\n\n  defp count_until_enum(enumerable, fun, limit) do\n    Enumerable.reduce(enumerable, {:cont, 0}, fn entry, acc ->\n      if fun.(entry) do\n        case acc + 1 do\n          ^limit -> {:halt, limit}\n          acc -> {:cont, acc}\n        end\n      else\n        {:cont, acc}\n      end\n    end)\n    |> elem(1)\n  end\n\n  # dedup\n\n  defp dedup_list([value | tail], acc) do\n    acc =\n      case acc do\n        [^value | _] -> acc\n        _ -> [value | acc]\n      end\n\n    dedup_list(tail, acc)\n  end\n\n  defp dedup_list([], acc) do\n    acc\n  end\n\n  ## drop\n\n  defp drop_list(list, 0), do: list\n  defp drop_list([_ | tail], counter), do: drop_list(tail, counter - 1)\n  defp drop_list([], _), do: []\n\n  ## drop_while\n\n  defp drop_while_list([head | tail], fun) do\n    if fun.(head) do\n      drop_while_list(tail, fun)\n    else\n      [head | tail]\n    end\n  end\n\n  defp drop_while_list([], _) do\n    []\n  end\n\n  ## filter\n\n  defp filter_list([head | tail], fun) do\n    if fun.(head) do\n      [head | filter_list(tail, fun)]\n    else\n      filter_list(tail, fun)\n    end\n  end\n\n  defp filter_list([], _fun) do\n    []\n  end\n\n  ## find\n\n  defp find_list([head | tail], default, fun) do\n    if fun.(head) do\n      head\n    else\n      find_list(tail, default, fun)\n    end\n  end\n\n  defp find_list([], default, _) do\n    default\n  end\n\n  ## find_index\n\n  defp find_index_list([head | tail], counter, fun) do\n    if fun.(head) do\n      counter\n    else\n      find_index_list(tail, counter + 1, fun)\n    end\n  end\n\n  defp find_index_list([], _, _) do\n    nil\n  end\n\n  ## find_value\n\n  defp find_value_list([head | tail], default, fun) do\n    fun.(head) || find_value_list(tail, default, fun)\n  end\n\n  defp find_value_list([], default, _) do\n    default\n  end\n\n  ## flat_map\n\n  defp flat_map_list([head | tail], fun) do\n    case fun.(head) do\n      # the two first clauses are an optimization\n      [] -> flat_map_list(tail, fun)\n      [elem] -> [elem | flat_map_list(tail, fun)]\n      list when is_list(list) -> list ++ flat_map_list(tail, fun)\n      other -> to_list(other) ++ flat_map_list(tail, fun)\n    end\n  end\n\n  defp flat_map_list([], _fun) do\n    []\n  end\n\n  ## intersperse\n\n  defp intersperse_non_empty_list([head], _separator), do: [head]\n\n  defp intersperse_non_empty_list([head | rest], separator) do\n    [head, separator | intersperse_non_empty_list(rest, separator)]\n  end\n\n  ## join\n\n  defp join_list([], _joiner), do: \"\"\n\n  defp join_list(list, joiner) do\n    join_non_empty_list(list, joiner, [])\n    |> :lists.reverse()\n    |> IO.iodata_to_binary()\n  end\n\n  defp join_non_empty_list([first], _joiner, acc), do: [entry_to_string(first) | acc]\n\n  defp join_non_empty_list([first | rest], joiner, acc) do\n    join_non_empty_list(rest, joiner, [joiner, entry_to_string(first) | acc])\n  end\n\n  ## map\n\n  defp map_range(first, last, step, fun)\n       when step > 0 and first <= last\n       when step < 0 and first >= last do\n    [fun.(first) | map_range(first + step, last, step, fun)]\n  end\n\n  defp map_range(_first, _last, _step, _fun) do\n    []\n  end\n\n  ## map_intersperse\n\n  defp map_intersperse_list([], _, _),\n    do: []\n\n  defp map_intersperse_list([last], _, mapper),\n    do: [mapper.(last)]\n\n  defp map_intersperse_list([head | rest], separator, mapper),\n    do: [mapper.(head), separator | map_intersperse_list(rest, separator, mapper)]\n\n  ## reduce\n\n  defp reduce_range(first, last, step, acc, fun)\n       when step > 0 and first <= last\n       when step < 0 and first >= last do\n    reduce_range(first + step, last, step, fun.(first, acc), fun)\n  end\n\n  defp reduce_range(_first, _last, _step, acc, _fun) do\n    acc\n  end\n\n  defp reduce_enumerable(enumerable, acc, fun) do\n    Enumerable.reduce(enumerable, {:cont, acc}, fn x, acc -> {:cont, fun.(x, acc)} end) |> elem(1)\n  end\n\n  ## reject\n\n  defp reject_list([head | tail], fun) do\n    if fun.(head) do\n      reject_list(tail, fun)\n    else\n      [head | reject_list(tail, fun)]\n    end\n  end\n\n  defp reject_list([], _fun) do\n    []\n  end\n\n  ## reverse_slice\n\n  defp reverse_slice(rest, idx, idx, count, acc) do\n    {slice, rest} = head_slice(rest, count, [])\n    :lists.reverse(rest, :lists.reverse(slice, acc))\n  end\n\n  defp reverse_slice([elem | rest], idx, start, count, acc) do\n    reverse_slice(rest, idx - 1, start, count, [elem | acc])\n  end\n\n  defp head_slice(rest, 0, acc), do: {acc, rest}\n\n  defp head_slice([elem | rest], count, acc) do\n    head_slice(rest, count - 1, [elem | acc])\n  end\n\n  ## scan\n\n  defp scan_list([], _acc, _fun), do: []\n\n  defp scan_list([elem | rest], acc, fun) do\n    acc = fun.(elem, acc)\n    [acc | scan_list(rest, acc, fun)]\n  end\n\n  ## slice\n\n  defp slice_forward(enumerable, start, amount, step) when start < 0 do\n    {count, fun} = slice_count_and_fun(enumerable, step)\n    start = count + start\n\n    if start >= 0 do\n      amount = Kernel.min(amount, count - start)\n      amount = amount_with_step(amount, step)\n      fun.(start, amount, step)\n    else\n      []\n    end\n  end\n\n  defp slice_forward(list, start, amount, step) when is_list(list) do\n    amount = amount_with_step(amount, step)\n    slice_list(list, start, amount, step)\n  end\n\n  defp slice_forward(enumerable, start, amount, step) do\n    case Enumerable.slice(enumerable) do\n      {:ok, count, _} when start >= count ->\n        []\n\n      {:ok, count, fun} when is_function(fun, 1) ->\n        amount = Kernel.min(amount, count - start) |> amount_with_step(step)\n        enumerable |> fun.() |> slice_exact(start, amount, step, count)\n\n      {:ok, count, fun} when is_function(fun, 3) ->\n        amount = Kernel.min(amount, count - start) |> amount_with_step(step)\n        fun.(start, amount, step)\n\n      # TODO: Remove me on v2.0\n      {:ok, count, fun} when is_function(fun, 2) ->\n        IO.warn(\n          \"#{inspect(Enumerable.impl_for(enumerable))} must return a three arity function on slice/1\"\n        )\n\n        amount = Kernel.min(amount, count - start)\n\n        if step == 1 do\n          fun.(start, amount)\n        else\n          fun.(start, Kernel.min(amount * step, count - start))\n          |> take_every_list(amount, step - 1)\n        end\n\n      {:error, module} ->\n        slice_enum(enumerable, module, start, amount, step)\n    end\n  end\n\n  defp slice_list(list, start, amount, step) do\n    if step == 1 do\n      list |> drop_list(start) |> take_list(amount)\n    else\n      list |> drop_list(start) |> take_every_list(amount, step - 1)\n    end\n  end\n\n  defp slice_enum(enumerable, module, start, amount, 1) do\n    {_, {_, _, slice}} =\n      module.reduce(enumerable, {:cont, {start, amount, []}}, fn\n        _entry, {start, amount, _list} when start > 0 ->\n          {:cont, {start - 1, amount, []}}\n\n        entry, {start, amount, list} when amount > 1 ->\n          {:cont, {start, amount - 1, [entry | list]}}\n\n        entry, {start, amount, list} ->\n          {:halt, {start, amount, [entry | list]}}\n      end)\n\n    :lists.reverse(slice)\n  end\n\n  defp slice_enum(enumerable, module, start, amount, step) do\n    {_, {_, _, _, slice}} =\n      module.reduce(enumerable, {:cont, {start, amount, 1, []}}, fn\n        _entry, {start, amount, to_drop, _list} when start > 0 ->\n          {:cont, {start - 1, amount, to_drop, []}}\n\n        entry, {start, amount, to_drop, list} when amount > 1 ->\n          case to_drop do\n            1 -> {:cont, {start, amount - 1, step, [entry | list]}}\n            _ -> {:cont, {start, amount - 1, to_drop - 1, list}}\n          end\n\n        entry, {start, amount, to_drop, list} ->\n          case to_drop do\n            1 -> {:halt, {start, amount, to_drop, [entry | list]}}\n            _ -> {:halt, {start, amount, to_drop, list}}\n          end\n      end)\n\n    :lists.reverse(slice)\n  end\n\n  defp slice_count_and_fun(list, _step) when is_list(list) do\n    length = length(list)\n    {length, &slice_exact(list, &1, &2, &3, length)}\n  end\n\n  defp slice_count_and_fun(enumerable, step) do\n    case Enumerable.slice(enumerable) do\n      {:ok, count, fun} when is_function(fun, 1) ->\n        {count, &slice_exact(fun.(enumerable), &1, &2, &3, count)}\n\n      {:ok, count, fun} when is_function(fun, 3) ->\n        {count, fun}\n\n      # TODO: Remove me on v2.0\n      {:ok, count, fun} when is_function(fun, 2) ->\n        IO.warn(\n          \"#{inspect(Enumerable.impl_for(enumerable))} must return a three arity function on slice/1\"\n        )\n\n        if step == 1 do\n          {count, fn start, amount, 1 -> fun.(start, amount) end}\n        else\n          {count,\n           fn start, amount, step ->\n             fun.(start, Kernel.min(amount * step, count - start))\n             |> take_every_list(amount, step - 1)\n           end}\n        end\n\n      {:error, module} ->\n        {list, count} =\n          enumerable\n          |> module.reduce({:cont, {[], 0}}, fn elem, {acc, count} ->\n            {:cont, {[elem | acc], count + 1}}\n          end)\n          |> elem(1)\n\n        {count,\n         fn start, amount, step ->\n           list |> :lists.reverse() |> slice_exact(start, amount, step, count)\n         end}\n    end\n  end\n\n  # Slice a list when we know the bounds\n  defp slice_exact(_list, _start, 0, _step, _), do: []\n\n  defp slice_exact(list, start, amount, 1, size) when start + amount == size,\n    do: list |> drop_exact(start)\n\n  defp slice_exact(list, start, amount, 1, _),\n    do: list |> drop_exact(start) |> take_exact(amount)\n\n  defp slice_exact(list, start, amount, step, _),\n    do: list |> drop_exact(start) |> take_every_list(amount, step - 1)\n\n  defp drop_exact(list, 0), do: list\n  defp drop_exact([_ | tail], amount), do: drop_exact(tail, amount - 1)\n\n  defp take_exact(_list, 0), do: []\n  defp take_exact([head | tail], amount), do: [head | take_exact(tail, amount - 1)]\n\n  ## sort\n\n  defp sort_reducer(entry, {:split, y, x, r, rs, bool}, fun) do\n    cond do\n      fun.(y, entry) == bool ->\n        {:split, entry, y, [x | r], rs, bool}\n\n      fun.(x, entry) == bool ->\n        {:split, y, entry, [x | r], rs, bool}\n\n      r == [] ->\n        {:split, y, x, [entry], rs, bool}\n\n      true ->\n        {:pivot, y, x, r, rs, entry, bool}\n    end\n  end\n\n  defp sort_reducer(entry, {:pivot, y, x, r, rs, s, bool}, fun) do\n    cond do\n      fun.(y, entry) == bool ->\n        {:pivot, entry, y, [x | r], rs, s, bool}\n\n      fun.(x, entry) == bool ->\n        {:pivot, y, entry, [x | r], rs, s, bool}\n\n      fun.(s, entry) == bool ->\n        {:split, entry, s, [], [[y, x | r] | rs], bool}\n\n      true ->\n        {:split, s, entry, [], [[y, x | r] | rs], bool}\n    end\n  end\n\n  defp sort_reducer(entry, [x], fun) do\n    {:split, entry, x, [], [], fun.(x, entry)}\n  end\n\n  defp sort_reducer(entry, acc, _fun) do\n    [entry | acc]\n  end\n\n  defp sort_terminator({:split, y, x, r, rs, bool}, fun) do\n    sort_merge([[y, x | r] | rs], fun, bool)\n  end\n\n  defp sort_terminator({:pivot, y, x, r, rs, s, bool}, fun) do\n    sort_merge([[s], [y, x | r] | rs], fun, bool)\n  end\n\n  defp sort_terminator(acc, _fun) do\n    acc\n  end\n\n  defp sort_merge(list, fun, true), do: reverse_sort_merge(list, [], fun, true)\n\n  defp sort_merge(list, fun, false), do: sort_merge(list, [], fun, false)\n\n  defp sort_merge([t1, [h2 | t2] | l], acc, fun, true),\n    do: sort_merge(l, [sort_merge1(t1, h2, t2, [], fun, false) | acc], fun, true)\n\n  defp sort_merge([[h2 | t2], t1 | l], acc, fun, false),\n    do: sort_merge(l, [sort_merge1(t1, h2, t2, [], fun, false) | acc], fun, false)\n\n  defp sort_merge([l], [], _fun, _bool), do: l\n\n  defp sort_merge([l], acc, fun, bool),\n    do: reverse_sort_merge([:lists.reverse(l, []) | acc], [], fun, bool)\n\n  defp sort_merge([], acc, fun, bool), do: reverse_sort_merge(acc, [], fun, bool)\n\n  defp reverse_sort_merge([[h2 | t2], t1 | l], acc, fun, true),\n    do: reverse_sort_merge(l, [sort_merge1(t1, h2, t2, [], fun, true) | acc], fun, true)\n\n  defp reverse_sort_merge([t1, [h2 | t2] | l], acc, fun, false),\n    do: reverse_sort_merge(l, [sort_merge1(t1, h2, t2, [], fun, true) | acc], fun, false)\n\n  defp reverse_sort_merge([l], acc, fun, bool),\n    do: sort_merge([:lists.reverse(l, []) | acc], [], fun, bool)\n\n  defp reverse_sort_merge([], acc, fun, bool), do: sort_merge(acc, [], fun, bool)\n\n  defp sort_merge1([h1 | t1], h2, t2, m, fun, bool) do\n    if fun.(h1, h2) == bool do\n      sort_merge2(h1, t1, t2, [h2 | m], fun, bool)\n    else\n      sort_merge1(t1, h2, t2, [h1 | m], fun, bool)\n    end\n  end\n\n  defp sort_merge1([], h2, t2, m, _fun, _bool), do: :lists.reverse(t2, [h2 | m])\n\n  defp sort_merge2(h1, t1, [h2 | t2], m, fun, bool) do\n    if fun.(h1, h2) == bool do\n      sort_merge2(h1, t1, t2, [h2 | m], fun, bool)\n    else\n      sort_merge1(t1, h2, t2, [h1 | m], fun, bool)\n    end\n  end\n\n  defp sort_merge2(h1, t1, [], m, _fun, _bool), do: :lists.reverse(t1, [h1 | m])\n\n  ## split\n\n  defp split_list([head | tail], counter, acc) when counter > 0 do\n    split_list(tail, counter - 1, [head | acc])\n  end\n\n  defp split_list(list, 0, acc) do\n    {:lists.reverse(acc), list}\n  end\n\n  defp split_list([], _, acc) do\n    {:lists.reverse(acc), []}\n  end\n\n  defp split_reverse_list([head | tail], counter, acc) when counter > 0 do\n    split_reverse_list(tail, counter - 1, [head | acc])\n  end\n\n  defp split_reverse_list(list, 0, acc) do\n    {:lists.reverse(list), acc}\n  end\n\n  defp split_reverse_list([], _, acc) do\n    {[], acc}\n  end\n\n  ## split_while\n\n  defp split_while_list([head | tail], fun, acc) do\n    if fun.(head) do\n      split_while_list(tail, fun, [head | acc])\n    else\n      {:lists.reverse(acc), [head | tail]}\n    end\n  end\n\n  defp split_while_list([], _, acc) do\n    {:lists.reverse(acc), []}\n  end\n\n  ## sum_by\n\n  defp sum_by_list([], _, acc), do: acc\n  defp sum_by_list([h | t], mapper, acc), do: sum_by_list(t, mapper, acc + mapper.(h))\n\n  ## product_by\n\n  defp product_by_list([], _, acc), do: acc\n  defp product_by_list([h | t], mapper, acc), do: product_by_list(t, mapper, acc * mapper.(h))\n\n  ## take\n\n  defp take_list(_list, 0), do: []\n  defp take_list([head | tail], counter), do: [head | take_list(tail, counter - 1)]\n  defp take_list([], _counter), do: []\n\n  defp take_every_list([head | tail], to_drop),\n    do: [head | tail |> drop_list(to_drop) |> take_every_list(to_drop)]\n\n  defp take_every_list([], _to_drop), do: []\n\n  defp take_every_list(_list, 0, _to_drop), do: []\n\n  defp take_every_list([head | tail], counter, to_drop),\n    do: [head | tail |> drop_list(to_drop) |> take_every_list(counter - 1, to_drop)]\n\n  defp take_every_list([], _counter, _to_drop), do: []\n\n  ## take_while\n\n  defp take_while_list([head | tail], fun) do\n    if fun.(head) do\n      [head | take_while_list(tail, fun)]\n    else\n      []\n    end\n  end\n\n  defp take_while_list([], _) do\n    []\n  end\n\n  ## uniq\n\n  defp uniq_list([head | tail], set, fun) do\n    value = fun.(head)\n\n    case set do\n      %{^value => true} -> uniq_list(tail, set, fun)\n      %{} -> [head | uniq_list(tail, Map.put(set, value, true), fun)]\n    end\n  end\n\n  defp uniq_list([], _set, _fun) do\n    []\n  end\n\n  ## with_index\n\n  defp with_index_list([head | tail], offset) do\n    [{head, offset} | with_index_list(tail, offset + 1)]\n  end\n\n  defp with_index_list([], _offset), do: []\n\n  defp with_index_list([head | tail], offset, fun) do\n    [fun.(head, offset) | with_index_list(tail, offset + 1, fun)]\n  end\n\n  defp with_index_list([], _offset, _fun), do: []\n\n  ## zip\n\n  defp zip_list([head1 | next1], [head2 | next2], acc) do\n    zip_list(next1, next2, [{head1, head2} | acc])\n  end\n\n  defp zip_list([], _, acc), do: :lists.reverse(acc)\n  defp zip_list(_, [], acc), do: :lists.reverse(acc)\n\n  defp zip_with_list([head1 | next1], [head2 | next2], fun) do\n    [fun.(head1, head2) | zip_with_list(next1, next2, fun)]\n  end\n\n  defp zip_with_list(_, [], _fun), do: []\n  defp zip_with_list([], _, _fun), do: []\n\n  defp zip_reduce_list([head1 | next1], [head2 | next2], acc, fun) do\n    zip_reduce_list(next1, next2, fun.(head1, head2, acc), fun)\n  end\n\n  defp zip_reduce_list(_, [], acc, _fun), do: acc\n  defp zip_reduce_list([], _, acc, _fun), do: acc\nend\n\ndefimpl Enumerable, for: List do\n  def count(list), do: {:ok, length(list)}\n\n  def member?(list, value), do: {:ok, :lists.member(value, list)}\n\n  def slice([]), do: {:ok, 0, fn _, _, _ -> [] end}\n  def slice(_list), do: {:error, __MODULE__}\n\n  def reduce(_list, {:halt, acc}, _fun), do: {:halted, acc}\n  def reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &reduce(list, &1, fun)}\n  def reduce([], {:cont, acc}, _fun), do: {:done, acc}\n  def reduce([head | tail], {:cont, acc}, fun), do: reduce(tail, fun.(head, acc), fun)\nend\n\ndefimpl Enumerable, for: Map do\n  def count(map) do\n    {:ok, map_size(map)}\n  end\n\n  def member?(map, {key, value}) do\n    {:ok, match?(%{^key => ^value}, map)}\n  end\n\n  def member?(_map, _other) do\n    {:ok, false}\n  end\n\n  def slice(map) do\n    size = map_size(map)\n    {:ok, size, &:maps.to_list/1}\n  end\n\n  def reduce(map, acc, fun) do\n    Enumerable.List.reduce(:maps.to_list(map), acc, fun)\n  end\nend\n\ndefimpl Enumerable, for: Function do\n  def count(_function), do: {:error, __MODULE__}\n  def member?(_function, _value), do: {:error, __MODULE__}\n  def slice(_function), do: {:error, __MODULE__}\n\n  def reduce(function, acc, fun) when is_function(function, 2), do: function.(acc, fun)\n\n  def reduce(function, _acc, _fun) do\n    raise Protocol.UndefinedError,\n      protocol: @protocol,\n      value: function,\n      description: \"only anonymous functions of arity 2 are enumerable\"\n  end\nend\n\ndefimpl Enumerable, for: Range do\n  def reduce(first..last//step, acc, fun) do\n    reduce(first, last, acc, fun, step)\n  end\n\n  # TODO: Remove me on v2.0\n  reduce =\n    quote generated: true do\n      reduce(\n        %{__struct__: Range, first: var!(first), last: var!(last)} = var!(range),\n        var!(acc),\n        var!(fun)\n      )\n    end\n\n  def unquote(reduce) do\n    step = if first <= last, do: 1, else: -1\n    reduce(Map.put(range, :step, step), acc, fun)\n  end\n\n  defp reduce(_first, _last, {:halt, acc}, _fun, _step) do\n    {:halted, acc}\n  end\n\n  defp reduce(first, last, {:suspend, acc}, fun, step) do\n    {:suspended, acc, &reduce(first, last, &1, fun, step)}\n  end\n\n  defp reduce(first, last, {:cont, acc}, fun, step)\n       when step > 0 and first <= last\n       when step < 0 and first >= last do\n    reduce(first + step, last, fun.(first, acc), fun, step)\n  end\n\n  defp reduce(_, _, {:cont, acc}, _fun, _up) do\n    {:done, acc}\n  end\n\n  def member?(first..last//step, value) when is_integer(value) and step > 0 do\n    {:ok, first <= value and value <= last and rem(value - first, step) == 0}\n  end\n\n  def member?(first..last//step, value) when is_integer(value) and step < 0 do\n    {:ok, last <= value and value <= first and rem(value - first, step) == 0}\n  end\n\n  # TODO: Remove me on v2.0\n  def member?(%{__struct__: Range, first: first, last: last} = range, value)\n      when is_integer(value) do\n    step = if first <= last, do: 1, else: -1\n    member?(Map.put(range, :step, step), value)\n  end\n\n  def member?(_, _value) do\n    {:ok, false}\n  end\n\n  def count(range) do\n    {:ok, Range.size(range)}\n  end\n\n  def slice(first.._//step = range) do\n    {:ok, Range.size(range), &slice(first + &1 * step, step * &3, &2)}\n  end\n\n  # TODO: Remove me on v2.0\n\n  slice =\n    quote generated: true do\n      slice(%{__struct__: Range, first: var!(first), last: var!(last)} = var!(range))\n    end\n\n  def unquote(slice) do\n    step = if first <= last, do: 1, else: -1\n    slice(Map.put(range, :step, step))\n  end\n\n  defp slice(current, _step, 1), do: [current]\n\n  defp slice(current, step, remaining) when remaining > 1 do\n    [current | slice(current + step, step, remaining - 1)]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/exception.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Exception do\n  @moduledoc \"\"\"\n  Functions for dealing with throw/catch/exit and exceptions.\n\n  This module also defines the behaviour required by custom\n  exceptions. To define your own, see `defexception/1`.\n\n  ## Formatting functions\n\n  Several functions in this module help format exceptions.\n  Some of these functions expect the stacktrace as argument.\n  The stacktrace is typically available inside catch and\n  rescue by using the `__STACKTRACE__/0` variable.\n\n  Do not rely on the particular format returned by the\n  functions in this module. They may be changed in future releases\n  in order to better suit Elixir's tool chain. In other words,\n  by using the functions in this module it is guaranteed you will\n  format exceptions as in the current Elixir version being used.\n  \"\"\"\n\n  @typedoc \"The exception type\"\n  @type t :: %{\n          required(:__struct__) => module,\n          required(:__exception__) => true,\n          optional(atom) => any\n        }\n\n  @typedoc \"The kind handled by formatting functions\"\n  @type kind :: :error | non_error_kind\n  @type non_error_kind :: :exit | :throw | {:EXIT, pid}\n\n  @type stacktrace :: [stacktrace_entry]\n  @type stacktrace_entry ::\n          {module, atom, arity_or_args, location}\n          | {(... -> any), arity_or_args, location}\n\n  @type arity_or_args :: non_neg_integer | list\n  @type location :: keyword\n\n  @doc \"\"\"\n  Receives the arguments given to `raise/2` and returns the exception struct.\n\n  The default implementation accepts either a set of keyword arguments\n  that is merged into the struct or a string to be used as the exception's message.\n  \"\"\"\n  @callback exception(term) :: t\n\n  @doc \"\"\"\n  Receives the exception struct and must return its message.\n\n  Many exceptions have a message field which by default is accessed\n  by this function. However, if an exception does not have a message field,\n  this function must be explicitly implemented.\n  \"\"\"\n  @callback message(t) :: String.t()\n\n  @doc \"\"\"\n  Called from `Exception.blame/3` to augment the exception struct.\n\n  Can be used to collect additional information about the exception\n  or do some additional expensive computation.\n  \"\"\"\n  @callback blame(t, stacktrace) :: {t, stacktrace}\n  @optional_callbacks [blame: 2]\n\n  @doc false\n  # Callback for formatting Erlang exceptions\n  def format_error(%struct{} = exception, _stacktrace) do\n    %{general: message(exception), reason: \"#\" <> Atom.to_string(struct)}\n  end\n\n  @doc false\n  @deprecated \"Use Kernel.is_exception/1 instead\"\n  def exception?(term)\n  def exception?(%_{__exception__: true}), do: true\n  def exception?(_), do: false\n\n  @doc \"\"\"\n  Gets the message for an `exception`.\n\n  This function will invoke the `c:message/1` callback on the exception\n  module to retrieve the message. If the callback raises an exception or\n  returns a non-binary value, this function will rescue the error and\n  return a descriptive error message instead.\n  \"\"\"\n  @spec message(t) :: String.t()\n  def message(%module{__exception__: true} = exception) do\n    try do\n      module.message(exception)\n    rescue\n      caught_exception ->\n        \"got #{inspect(caught_exception.__struct__)} with message \" <>\n          \"#{inspect(message(caught_exception))} while retrieving Exception.message/1 \" <>\n          \"for #{inspect(exception)}. Stacktrace:\\n#{format_stacktrace(__STACKTRACE__)}\"\n    else\n      result when is_binary(result) ->\n        result\n\n      result ->\n        \"got #{inspect(result)} \" <>\n          \"while retrieving Exception.message/1 for #{inspect(exception)} \" <>\n          \"(expected a string)\"\n    end\n  end\n\n  @doc \"\"\"\n  Normalizes an exception, converting Erlang exceptions\n  to Elixir exceptions.\n\n  It takes the `kind` spilled by `catch` as an argument and\n  normalizes only `:error`, returning the untouched payload\n  for others.\n\n  The third argument is the stacktrace which is used to enrich\n  a normalized error with more information. It is only used when\n  the kind is an error.\n  \"\"\"\n  @spec normalize(:error, any, stacktrace) :: t\n  @spec normalize(non_error_kind, payload, stacktrace) :: payload when payload: var\n  def normalize(kind, payload, stacktrace \\\\ [])\n  def normalize(:error, %_{__exception__: true} = payload, _stacktrace), do: payload\n  def normalize(:error, payload, stacktrace), do: ErlangError.normalize(payload, stacktrace)\n  def normalize(_kind, payload, _stacktrace), do: payload\n\n  @doc \"\"\"\n  Normalizes and formats any throw/error/exit.\n\n  The message is formatted and displayed in the same\n  format as used by Elixir's CLI.\n\n  The third argument is the stacktrace which is used to enrich\n  a normalized error with more information. It is only used when\n  the kind is an error.\n  \"\"\"\n  @spec format_banner(kind, any, stacktrace) :: String.t()\n  def format_banner(kind, exception, stacktrace \\\\ [])\n\n  def format_banner(:error, exception, stacktrace) do\n    exception = normalize(:error, exception, stacktrace)\n    \"** (\" <> inspect(exception.__struct__) <> \") \" <> message(exception)\n  end\n\n  def format_banner(:throw, reason, _stacktrace) do\n    \"** (throw) \" <> inspect(reason)\n  end\n\n  def format_banner(:exit, reason, _stacktrace) do\n    \"** (exit) \" <> format_exit(reason, <<\"\\n    \">>)\n  end\n\n  def format_banner({:EXIT, pid}, reason, _stacktrace) do\n    \"** (EXIT from #{inspect(pid)}) \" <> format_exit(reason, <<\"\\n    \">>)\n  end\n\n  @doc \"\"\"\n  Normalizes and formats throws/errors/exits and stacktraces.\n\n  It relies on `format_banner/3` and `format_stacktrace/1`\n  to generate the final format.\n\n  If `kind` is `{:EXIT, pid}`, it does not generate a stacktrace,\n  as such exits are retrieved as messages without stacktraces.\n  \"\"\"\n  @spec format(kind, any, stacktrace) :: String.t()\n  def format(kind, payload, stacktrace \\\\ [])\n\n  def format({:EXIT, _} = kind, any, _) do\n    format_banner(kind, any)\n  end\n\n  def format(kind, payload, stacktrace) do\n    message = format_banner(kind, payload, stacktrace)\n\n    case stacktrace do\n      [] -> message\n      _ -> message <> \"\\n\" <> format_stacktrace(stacktrace)\n    end\n  end\n\n  @doc false\n  def __format_message_with_term__(message, term) do\n    inspected =\n      term\n      |> inspect(pretty: true)\n      |> String.split(\"\\n\")\n      |> Enum.map_intersperse(\"\\n\", fn\n        \"\" -> \"\"\n        line -> \"    \" <> line\n      end)\n\n    IO.iodata_to_binary([message, \"\\n\\n\", inspected, \"\\n\"])\n  end\n\n  @doc \"\"\"\n  Attaches information to throws/errors/exits for extra debugging.\n\n  This operation is potentially expensive, as it reads data\n  from the file system, parses beam files, evaluates code and\n  so on.\n\n  If `kind` argument is `:error` and the `error` is an Erlang exception, this function will\n  normalize it. If the `error` argument is an Elixir exception, this function will invoke\n  the optional `c:blame/2` callback on the exception module if it is implemented.\n  Unlike `message/1`, this function will not rescue errors - if the callback raises an exception,\n  the error will propagate to the caller. It is your choice if you want to rescue and return\n  the original exception, return a different exception, or let it cascade.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec blame(:error, any, stacktrace) :: {t, stacktrace}\n  @spec blame(non_error_kind, payload, stacktrace) :: {payload, stacktrace} when payload: var\n  def blame(kind, error, stacktrace)\n\n  def blame(:error, error, stacktrace) do\n    %module{} = struct = normalize(:error, error, stacktrace)\n\n    if Code.ensure_loaded?(module) and function_exported?(module, :blame, 2) do\n      module.blame(struct, stacktrace)\n    else\n      {struct, stacktrace}\n    end\n  end\n\n  def blame(_kind, reason, stacktrace) do\n    {reason, stacktrace}\n  end\n\n  @doc \"\"\"\n  Blames the invocation of the given module, function and arguments.\n\n  This function will retrieve the available clauses from bytecode\n  and evaluate them against the given arguments. The clauses are\n  returned as a list of `{args, guards}` pairs where each argument\n  and each top-level condition in a guard separated by `and`/`or`\n  is wrapped in a tuple with blame metadata.\n\n  This function returns either `{:ok, definition, clauses}` or `:error`.\n  Where `definition` is `:def`, `:defp`, `:defmacro` or `:defmacrop`.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec blame_mfa(module, function :: atom, args :: [term]) ::\n          {:ok, :def | :defp | :defmacro | :defmacrop, [{args :: [term], guards :: [term]}]}\n          | :error\n  def blame_mfa(module, function, args)\n      when is_atom(module) and is_atom(function) and is_list(args) do\n    try do\n      blame_mfa(module, function, length(args), args)\n    rescue\n      _ -> :error\n    end\n  end\n\n  defp blame_mfa(module, function, arity, call_args) do\n    with [_ | _] = path <- :code.which(module),\n         {:ok, {_, [debug_info: debug_info]}} <- :beam_lib.chunks(path, [:debug_info]),\n         {:debug_info_v1, backend, data} <- debug_info,\n         {:ok, %{definitions: defs}} <- backend.debug_info(:elixir_v1, module, data, []),\n         {_, kind, _, clauses} <- List.keyfind(defs, {function, arity}, 0) do\n      clauses =\n        for {meta, ex_args, guards, _block} <- clauses do\n          scope = :elixir_erl.scope(meta, true)\n          ann = :elixir_erl.get_ann(meta)\n\n          {erl_args, scope} =\n            :elixir_erl_clauses.match(ann, &:elixir_erl_pass.translate_args/3, ex_args, scope)\n\n          {args, binding} =\n            [call_args, ex_args, erl_args]\n            |> Enum.zip()\n            |> Enum.map_reduce([], &blame_arg/2)\n\n          guards =\n            guards\n            |> Enum.map(&blame_guard(&1, ann, scope, binding))\n            |> Enum.map(&Macro.prewalk(&1, fn guard -> translate_guard(guard) end))\n\n          {args, guards}\n        end\n\n      {:ok, kind, clauses}\n    else\n      _ -> :error\n    end\n  end\n\n  defp map_node?({:is_map, _, [_]}), do: true\n  defp map_node?(_), do: false\n  defp map_key_node?({:is_map_key, _, [_, _]}), do: true\n  defp map_key_node?(_), do: false\n\n  defp struct_validation_node?(\n         {:is_atom, _, [{{:., [], [:erlang, :map_get]}, _, [:__struct__, _]}]}\n       ),\n       do: true\n\n  defp struct_validation_node?(\n         {:==, _, [{{:., [], [:erlang, :map_get]}, _, [:__struct__, _]}, _module]}\n       ),\n       do: true\n\n  defp struct_validation_node?(_), do: false\n\n  defp struct_macro?(\n         {:and, _,\n          [\n            {:and, _, [%{node: node_1 = {_, _, [arg]}}, %{node: node_2 = {_, _, [arg, _]}}]},\n            %{node: node_3 = {_, _, [{_, _, [_, arg]}]}}\n          ]}\n       ),\n       do: map_node?(node_1) and map_key_node?(node_2) and struct_validation_node?(node_3)\n\n  defp struct_macro?(\n         {:and, _,\n          [\n            {:and, _,\n             [\n               {:and, _,\n                [\n                  %{node: node_1 = {_, _, [arg]}},\n                  {:or, _, [%{node: {:is_atom, _, [_]}}, %{node: :fail}]}\n                ]},\n               %{node: node_2 = {_, _, [arg, _]}}\n             ]},\n            %{node: node_3 = {_, _, [{_, _, [_, arg]}, _]}}\n          ]}\n       ),\n       do: map_node?(node_1) and map_key_node?(node_2) and struct_validation_node?(node_3)\n\n  defp struct_macro?(_), do: false\n\n  defp translate_guard(guard) do\n    if struct_macro?(guard) do\n      undo_is_struct_guard(guard)\n    else\n      guard\n    end\n  end\n\n  defp undo_is_struct_guard({:and, meta, [_, %{node: {_, _, [{_, _, [_, arg]} | optional]}}]}) do\n    args =\n      case optional do\n        [] -> [arg]\n        [module] -> [arg, module]\n      end\n\n    %{match?: meta[:value], node: {:is_struct, meta, args}}\n  end\n\n  defp blame_arg({call_arg, ex_arg, erl_arg}, binding) do\n    {match?, binding} = blame_arg(erl_arg, call_arg, binding)\n    {blame_wrap(match?, rewrite_arg(ex_arg)), binding}\n  end\n\n  defp blame_arg(erl_arg, call_arg, binding) do\n    binding = :orddict.store(:VAR, call_arg, binding)\n\n    try do\n      ann = :erl_anno.new(0)\n\n      {:value, _, binding} =\n        :erl_eval.expr({:match, ann, erl_arg, {:var, ann, :VAR}}, binding, :none)\n\n      {true, binding}\n    rescue\n      _ -> {false, binding}\n    end\n  end\n\n  defp rewrite_arg(arg) do\n    Macro.prewalk(arg, fn\n      {:%{}, meta, [__struct__: Range, first: first, last: last, step: step]} ->\n        {:..//, meta, [first, last, step]}\n\n      other ->\n        other\n    end)\n  end\n\n  defp blame_guard({{:., _, [:erlang, op]}, meta, [left, right]}, ann, scope, binding)\n       when op == :andalso or op == :orelse do\n    guards = [\n      blame_guard(left, ann, scope, binding),\n      blame_guard(right, ann, scope, binding)\n    ]\n\n    kernel_op =\n      case op do\n        :orelse -> :or\n        :andalso -> :and\n      end\n\n    evaluate_guard(kernel_op, meta, guards)\n  end\n\n  defp blame_guard(ex_guard, ann, scope, binding) do\n    ex_guard\n    |> blame_guard?(binding, ann, scope)\n    |> blame_wrap(rewrite_guard(ex_guard))\n  end\n\n  defp blame_guard?(ex_guard, binding, ann, scope) do\n    {erl_guard, _} = :elixir_erl_pass.translate(ex_guard, ann, scope)\n    {:value, true, _} = :erl_eval.expr(erl_guard, binding, :none)\n    true\n  rescue\n    _ -> false\n  end\n\n  defp evaluate_guard(kernel_op, meta, guards = [_, _]) do\n    [x, y] = Enum.map(guards, &evaluate_guard/1)\n\n    logic_value =\n      case kernel_op do\n        :or -> x or y\n        :and -> x and y\n      end\n\n    {kernel_op, Keyword.put(meta, :value, logic_value), guards}\n  end\n\n  defp evaluate_guard(%{match?: value}), do: value\n  defp evaluate_guard({_, meta, _}) when is_list(meta), do: meta[:value]\n\n  defp rewrite_guard(guard) do\n    Macro.prewalk(guard, fn\n      {{:., _, [mod, fun]}, meta, args} -> erl_to_ex(mod, fun, args, meta)\n      other -> other\n    end)\n  end\n\n  defp erl_to_ex(mod, fun, args, meta) do\n    case :elixir_rewrite.erl_to_ex(mod, fun, args) do\n      {Kernel, fun, args, _} -> {fun, meta, args}\n      {mod, fun, args, _} -> {{:., [], [mod, fun]}, meta, args}\n    end\n  end\n\n  defp blame_wrap(match?, ast), do: %{match?: match?, node: ast}\n\n  @doc \"\"\"\n  Formats an exit. It returns a string.\n\n  Often there are errors/exceptions inside exits. Exits are often\n  wrapped by the caller and provide stacktraces too. This function\n  formats exits in a way to nicely show the exit reason, caller\n  and stacktrace.\n  \"\"\"\n  @spec format_exit(any) :: String.t()\n  def format_exit(reason) do\n    format_exit(reason, <<\"\\n    \">>)\n  end\n\n  # 2-Tuple could be caused by an error if the second element is a stacktrace.\n  defp format_exit({exception, maybe_stacktrace} = reason, joiner)\n       when is_list(maybe_stacktrace) and maybe_stacktrace !== [] do\n    try do\n      Enum.map(maybe_stacktrace, &format_stacktrace_entry/1)\n    catch\n      :error, _ ->\n        # Not a stacktrace, was an exit.\n        format_exit_reason(reason)\n    else\n      formatted_stacktrace ->\n        # Assume a non-empty list formattable as stacktrace is a\n        # stacktrace, so exit was caused by an error.\n        message =\n          \"an exception was raised:\" <>\n            joiner <> format_banner(:error, exception, maybe_stacktrace)\n\n        Enum.join([message | formatted_stacktrace], joiner <> <<\"    \">>)\n    end\n  end\n\n  # :supervisor.start_link returns this error reason when it fails to init\n  # because a child's start_link raises.\n  defp format_exit({:shutdown, {:failed_to_start_child, child, {:EXIT, reason}}}, joiner) do\n    format_start_child(child, reason, joiner)\n  end\n\n  # :supervisor.start_link returns this error reason when it fails to init\n  # because a child's start_link returns {:error, reason}.\n  defp format_exit({:shutdown, {:failed_to_start_child, child, reason}}, joiner) do\n    format_start_child(child, reason, joiner)\n  end\n\n  # 2-Tuple could be an exit caused by mfa if second element is mfa, args\n  # must be a list of arguments - max length 255 due to max arity.\n  defp format_exit({reason2, {mod, fun, args}} = reason, joiner)\n       when length(args) < 256 do\n    try do\n      format_mfa(mod, fun, args)\n    catch\n      :error, _ ->\n        # Not an mfa, was an exit.\n        format_exit_reason(reason)\n    else\n      mfa ->\n        # Assume tuple formattable as an mfa is an mfa,\n        # so exit was caused by failed mfa.\n        \"exited in: \" <>\n          mfa <> joiner <> \"** (EXIT) \" <> format_exit(reason2, joiner <> <<\"    \">>)\n    end\n  end\n\n  defp format_exit(reason, _joiner) do\n    format_exit_reason(reason)\n  end\n\n  defp format_exit_reason(:normal), do: \"normal\"\n  defp format_exit_reason(:shutdown), do: \"shutdown\"\n\n  defp format_exit_reason({:shutdown, reason}) do\n    \"shutdown: #{inspect(reason)}\"\n  end\n\n  defp format_exit_reason(:calling_self), do: \"process attempted to call itself\"\n  defp format_exit_reason(:timeout), do: \"time out\"\n  defp format_exit_reason(:killed), do: \"killed\"\n  defp format_exit_reason(:noconnection), do: \"no connection\"\n\n  defp format_exit_reason(:noproc) do\n    \"no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started\"\n  end\n\n  defp format_exit_reason({:nodedown, node_name}) when is_atom(node_name) do\n    \"no connection to #{node_name}\"\n  end\n\n  # :gen_server exit reasons\n\n  defp format_exit_reason({:already_started, pid}) do\n    \"already started: \" <> inspect(pid)\n  end\n\n  defp format_exit_reason({:bad_return_value, value}) do\n    \"bad return value: \" <> inspect(value)\n  end\n\n  defp format_exit_reason({:bad_call, request}) do\n    \"bad call: \" <> inspect(request)\n  end\n\n  defp format_exit_reason({:bad_cast, request}) do\n    \"bad cast: \" <> inspect(request)\n  end\n\n  # :supervisor.start_link error reasons\n\n  # If value is a list will be formatted by mfa exit in format_exit/1\n  defp format_exit_reason({:bad_return, {mod, :init, value}})\n       when is_atom(mod) do\n    format_mfa(mod, :init, 1) <> \" returned a bad value: \" <> inspect(value)\n  end\n\n  defp format_exit_reason({:bad_start_spec, start_spec}) do\n    \"bad child specification, invalid children: \" <> inspect(start_spec)\n  end\n\n  defp format_exit_reason({:start_spec, start_spec}) do\n    \"bad child specification, \" <> format_sup_spec(start_spec)\n  end\n\n  defp format_exit_reason({:supervisor_data, data}) do\n    \"bad supervisor configuration, \" <> format_sup_data(data)\n  end\n\n  defp format_exit_reason(reason), do: inspect(reason)\n\n  defp format_start_child(child, reason, joiner) do\n    \"shutdown: failed to start child: \" <>\n      inspect(child) <> joiner <> \"** (EXIT) \" <> format_exit(reason, joiner <> <<\"    \">>)\n  end\n\n  defp format_sup_data({:invalid_type, type}) do\n    \"invalid type: \" <> inspect(type)\n  end\n\n  defp format_sup_data({:invalid_strategy, strategy}) do\n    \"invalid strategy: \" <> inspect(strategy)\n  end\n\n  defp format_sup_data({:invalid_intensity, intensity}) do\n    \"invalid max_restarts (intensity): \" <> inspect(intensity)\n  end\n\n  defp format_sup_data({:invalid_period, period}) do\n    \"invalid max_seconds (period): \" <> inspect(period)\n  end\n\n  defp format_sup_data({:invalid_max_children, max_children}) do\n    \"invalid max_children: \" <> inspect(max_children)\n  end\n\n  defp format_sup_data({:invalid_extra_arguments, extra}) do\n    \"invalid extra_arguments: \" <> inspect(extra)\n  end\n\n  defp format_sup_data(other), do: \"got: #{inspect(other)}\"\n\n  defp format_sup_spec({:duplicate_child_name, id}) do\n    \"\"\"\n    more than one child specification has the id: #{inspect(id)}.\n    If using maps as child specifications, make sure the :id keys are unique.\n    If using a module or {module, arg} as child, use Supervisor.child_spec/2 to change the :id, for example:\n\n        children = [\n          Supervisor.child_spec({MyWorker, arg}, id: :my_worker_1),\n          Supervisor.child_spec({MyWorker, arg}, id: :my_worker_2)\n        ]\n    \"\"\"\n  end\n\n  defp format_sup_spec({:invalid_child_spec, child_spec}) do\n    \"invalid child specification: #{inspect(child_spec)}\"\n  end\n\n  defp format_sup_spec({:invalid_child_type, type}) do\n    \"invalid child type: #{inspect(type)}. Must be :worker or :supervisor.\"\n  end\n\n  defp format_sup_spec({:invalid_mfa, mfa}) do\n    \"invalid mfa: #{inspect(mfa)}\"\n  end\n\n  defp format_sup_spec({:invalid_restart_type, restart}) do\n    \"invalid restart type: #{inspect(restart)}. Must be :permanent, :transient or :temporary.\"\n  end\n\n  defp format_sup_spec({:invalid_shutdown, shutdown}) do\n    \"invalid shutdown: #{inspect(shutdown)}. Must be an integer >= 0, :infinity or :brutal_kill.\"\n  end\n\n  defp format_sup_spec({:invalid_module, mod}) do\n    \"invalid module: #{inspect(mod)}. Must be an atom.\"\n  end\n\n  defp format_sup_spec({:invalid_modules, modules}) do\n    \"invalid modules: #{inspect(modules)}. Must be a list of atoms or :dynamic.\"\n  end\n\n  defp format_sup_spec(other), do: \"got: #{inspect(other)}\"\n\n  @doc \"\"\"\n  Receives a stacktrace entry and formats it into a string.\n  \"\"\"\n  @spec format_stacktrace_entry(stacktrace_entry) :: String.t()\n  def format_stacktrace_entry(entry)\n\n  # From Macro.Env.stacktrace\n  def format_stacktrace_entry({module, :__MODULE__, 0, location}) do\n    format_location(location) <> inspect(module) <> \" (module)\"\n  end\n\n  # From :elixir_compiler_*\n  def format_stacktrace_entry({_module, :__MODULE__, 1, location}) do\n    format_location(location) <> \"(module)\"\n  end\n\n  # From :elixir_compiler_*\n  def format_stacktrace_entry({_module, :__FILE__, 1, location}) do\n    format_location(location) <> \"(file)\"\n  end\n\n  def format_stacktrace_entry({module, fun, arity, location}) do\n    format_application(module) <> format_location(location) <> format_mfa(module, fun, arity)\n  end\n\n  def format_stacktrace_entry({fun, arity, location}) do\n    format_location(location) <> format_fa(fun, arity)\n  end\n\n  defp format_application(module) do\n    # We cannot use Application due to bootstrap issues\n    case :application.get_application(module) do\n      {:ok, app} ->\n        case :application.get_key(app, :vsn) do\n          {:ok, vsn} when is_list(vsn) ->\n            \"(\" <> Atom.to_string(app) <> \" \" <> List.to_string(vsn) <> \") \"\n\n          _ ->\n            \"(\" <> Atom.to_string(app) <> \") \"\n        end\n\n      :undefined ->\n        \"\"\n    end\n  end\n\n  @doc \"\"\"\n  Formats the stacktrace.\n\n  A stacktrace must be given as an argument. If not, the stacktrace\n  is retrieved from `Process.info/2`.\n  \"\"\"\n  @spec format_stacktrace(stacktrace | nil) :: String.t()\n  def format_stacktrace(trace \\\\ nil) do\n    trace =\n      if trace do\n        trace\n      else\n        case Process.info(self(), :current_stacktrace) do\n          {:current_stacktrace, t} -> Enum.drop(t, 3)\n        end\n      end\n\n    case trace do\n      [] -> \"\\n\"\n      _ -> \"    \" <> Enum.map_join(trace, \"\\n    \", &format_stacktrace_entry(&1)) <> \"\\n\"\n    end\n  end\n\n  @doc \"\"\"\n  Receives an anonymous function and arity and formats it as\n  shown in stacktraces. The arity may also be a list of arguments.\n\n  ## Examples\n\n      Exception.format_fa(fn -> nil end, 1)\n      #=> \"#Function<...>/1\"\n\n  \"\"\"\n  @spec format_fa(fun, arity) :: String.t()\n  def format_fa(fun, arity) when is_function(fun) do\n    \"#{inspect(fun)}#{format_arity(arity)}\"\n  end\n\n  @doc \"\"\"\n  Receives a module, fun and arity and formats it\n  as shown in stacktraces. The arity may also be a list\n  of arguments.\n\n  ## Examples\n\n      iex> Exception.format_mfa(Foo, :bar, 1)\n      \"Foo.bar/1\"\n\n      iex> Exception.format_mfa(Foo, :bar, [])\n      \"Foo.bar()\"\n\n      iex> Exception.format_mfa(nil, :bar, [])\n      \"nil.bar()\"\n\n  Anonymous functions are reported as -func/arity-anonfn-count-,\n  where func is the name of the enclosing function. Convert to\n  \"anonymous fn in func/arity\"\n  \"\"\"\n  @spec format_mfa(module, atom, arity_or_args) :: String.t()\n  def format_mfa(module, fun, arity) when is_atom(module) and is_atom(fun) do\n    case Code.Identifier.extract_anonymous_fun_parent(fun) do\n      {outer_name, outer_arity} ->\n        \"anonymous fn#{format_arity(arity)} in \" <>\n          \"#{Macro.inspect_atom(:literal, module)}.\" <>\n          \"#{Macro.inspect_atom(:remote_call, outer_name)}/#{outer_arity}\"\n\n      :error ->\n        \"#{Macro.inspect_atom(:literal, module)}.\" <>\n          \"#{Macro.inspect_atom(:remote_call, fun)}#{format_arity(arity)}\"\n    end\n  end\n\n  defp format_arity(arity) when is_list(arity) do\n    inspected = for x <- arity, do: inspect(x)\n    \"(#{Enum.join(inspected, \", \")})\"\n  end\n\n  defp format_arity(arity) when is_integer(arity) do\n    \"/\" <> Integer.to_string(arity)\n  end\n\n  @doc \"\"\"\n  Formats the given `file` and `line` as shown in stacktraces.\n\n  If any of the values are `nil`, they are omitted.\n\n  ## Examples\n\n      iex> Exception.format_file_line(\"foo\", 1)\n      \"foo:1:\"\n\n      iex> Exception.format_file_line(\"foo\", nil)\n      \"foo:\"\n\n      iex> Exception.format_file_line(nil, nil)\n      \"\"\n\n  \"\"\"\n  @spec format_file_line(String.t() | nil, non_neg_integer | nil, String.t()) :: String.t()\n  def format_file_line(file, line, suffix \\\\ \"\") do\n    cond do\n      is_nil(file) -> \"\"\n      is_nil(line) or line == 0 -> \"#{file}:#{suffix}\"\n      true -> \"#{file}:#{line}:#{suffix}\"\n    end\n  end\n\n  @doc \"\"\"\n  Formats the given `file`, `line`, and `column` as shown in stacktraces.\n\n  If any of the values are `nil`, they are omitted.\n\n  ## Examples\n\n      iex> Exception.format_file_line_column(\"foo\", 1, 2)\n      \"foo:1:2:\"\n\n      iex> Exception.format_file_line_column(\"foo\", 1, nil)\n      \"foo:1:\"\n\n      iex> Exception.format_file_line_column(\"foo\", nil, nil)\n      \"foo:\"\n\n      iex> Exception.format_file_line_column(\"foo\", nil, 2)\n      \"foo:\"\n\n      iex> Exception.format_file_line_column(nil, nil, nil)\n      \"\"\n\n  \"\"\"\n  @spec format_file_line_column(\n          String.t() | nil,\n          non_neg_integer | nil,\n          non_neg_integer | nil,\n          String.t()\n        ) :: String.t()\n  def format_file_line_column(file, line, column, suffix \\\\ \"\") do\n    cond do\n      is_nil(file) -> \"\"\n      is_nil(line) or line == 0 -> \"#{file}:#{suffix}\"\n      is_nil(column) or column == 0 -> \"#{file}:#{line}:#{suffix}\"\n      true -> \"#{file}:#{line}:#{column}:#{suffix}\"\n    end\n  end\n\n  defp format_location(opts) when is_list(opts) do\n    case opts[:column] do\n      nil -> format_file_line(Keyword.get(opts, :file), Keyword.get(opts, :line), \" \")\n      col -> format_file_line_column(Keyword.get(opts, :file), Keyword.get(opts, :line), col, \" \")\n    end\n  end\n\n  @doc false\n  def format_delimiter(delimiter) do\n    if delimiter |> Atom.to_string() |> String.contains?([\"\\\"\", \"'\"]),\n      do: delimiter,\n      else: ~s(\"#{delimiter}\")\n  end\n\n  @doc false\n  def format_snippet(\n        {start_line, _start_column} = start_pos,\n        {end_line, end_column} = end_pos,\n        description,\n        file,\n        lines,\n        start_message,\n        end_message\n      )\n      when start_line < end_line do\n    max_digits = digits(end_line)\n    general_padding = max(2, max_digits) + 1\n    padding = n_spaces(general_padding)\n\n    relevant_lines =\n      if end_line - start_line < 5 do\n        line_range(lines, start_pos, end_pos, padding, max_digits, start_message, end_message)\n      else\n        trimmed_inbetween_lines(\n          lines,\n          start_pos,\n          end_pos,\n          padding,\n          max_digits,\n          start_message,\n          end_message\n        )\n      end\n\n    \"\"\"\n     #{padding}#{red(\"error:\")} #{pad_message(description, padding)}\n     #{padding}│\n    #{relevant_lines}\n     #{padding}│\n     #{padding}└─ #{Path.relative_to_cwd(file)}:#{end_line}:#{end_column}\\\n    \"\"\"\n  end\n\n  def format_snippet(\n        {start_line, start_column},\n        {end_line, end_column},\n        description,\n        file,\n        lines,\n        start_message,\n        end_message\n      )\n      when start_line == end_line do\n    max_digits = digits(end_line)\n    general_padding = max(2, max_digits) + 1\n    padding = n_spaces(general_padding)\n    formatted_line = [line_padding(end_line, max_digits), to_string(end_line), \" │ \", hd(lines)]\n\n    mismatched_closing_line =\n      [\n        n_spaces(start_column - 1),\n        red(\"│\"),\n        format_end_message(end_column - start_column, end_message)\n      ]\n\n    unclosed_delimiter_line =\n      [padding, \" │ \", format_start_message(start_column, start_message)]\n\n    below_line = [padding, \" │ \", mismatched_closing_line, \"\\n\", unclosed_delimiter_line]\n\n    \"\"\"\n     #{padding}#{red(\"error:\")} #{pad_message(description, padding)}\n     #{padding}│\n    #{formatted_line}\n    #{below_line}\n     #{padding}│\n     #{padding}└─ #{Path.relative_to_cwd(file)}:#{end_line}:#{end_column}\\\n    \"\"\"\n  end\n\n  defp line_padding(line_number, max_digits) do\n    line_digits = digits(line_number)\n\n    spacing =\n      if line_digits == 1 do\n        max(2, max_digits)\n      else\n        max_digits - line_digits + 1\n      end\n\n    n_spaces(spacing)\n  end\n\n  defp n_spaces(n), do: String.duplicate(\" \", n)\n\n  defp digits(number, acc \\\\ 1)\n  defp digits(number, acc) when number < 10, do: acc\n  defp digits(number, acc), do: digits(div(number, 10), acc + 1)\n\n  defp trimmed_inbetween_lines(\n         lines,\n         {start_line, start_column},\n         {end_line, end_column},\n         padding,\n         max_digits,\n         start_message,\n         end_message\n       ) do\n    start_padding = line_padding(start_line, max_digits)\n    end_padding = line_padding(end_line, max_digits)\n    first_line = hd(lines)\n    last_line = List.last(lines)\n\n    \"\"\"\n    #{start_padding}#{start_line} │ #{first_line}\n     #{padding}│ #{format_start_message(start_column, start_message)}\n     ...\n    #{end_padding}#{end_line} │ #{last_line}\n     #{padding}│ #{format_end_message(end_column, end_message)}\\\n    \"\"\"\n  end\n\n  defp line_range(\n         lines,\n         {start_line, start_column},\n         {end_line, end_column},\n         padding,\n         max_digits,\n         start_message,\n         end_message\n       ) do\n    Enum.zip_with(lines, start_line..end_line, fn line, line_number ->\n      line_padding = line_padding(line_number, max_digits)\n\n      cond do\n        line_number == start_line ->\n          [\n            line_padding,\n            to_string(line_number),\n            \" │ \",\n            line,\n            \"\\n\",\n            padding,\n            \" │ \",\n            format_start_message(start_column, start_message)\n          ]\n\n        line_number == end_line ->\n          [\n            line_padding,\n            to_string(line_number),\n            \" │ \",\n            line,\n            \"\\n\",\n            padding,\n            \" │ \",\n            format_end_message(end_column, end_message)\n          ]\n\n        true ->\n          [line_padding, to_string(line_number), \" │ \", line]\n      end\n    end)\n    |> Enum.intersperse(\"\\n\")\n  end\n\n  defp format_end_message(end_column, message),\n    do: [\n      n_spaces(end_column - 1),\n      red(message)\n    ]\n\n  defp format_start_message(start_column, message),\n    do: [n_spaces(start_column - 1), red(message)]\n\n  defp pad_message(message, padding), do: String.replace(message, \"\\n\", \"\\n #{padding}\")\n\n  defp red(string) do\n    if IO.ANSI.enabled?() do\n      [IO.ANSI.red(), string, IO.ANSI.reset()]\n    else\n      string\n    end\n  end\nend\n\n# Some exceptions implement \"message/1\" instead of \"exception/1\" mostly\n# for bootstrap reasons. It is recommended for applications to implement\n# \"exception/1\" instead of \"message/1\" as described in \"defexception/1\"\n# docs.\n\ndefmodule RuntimeError do\n  @moduledoc \"\"\"\n  An exception for a generic runtime error.\n\n  This is the exception that `raise/1` raises when you pass it only a string as\n  a message:\n\n      iex> raise \"oops!\"\n      ** (RuntimeError) oops!\n\n  You should use this exceptions sparingly, since most of the time it might be\n  better to define your own exceptions specific to your application or library.\n  Sometimes, however, there are situations in which you don't expect a condition to\n  happen, but you want to give a meaningful error message if it does. In those cases,\n  `RuntimeError` can be a good choice.\n\n  ## Fields\n\n  `RuntimeError` exceptions have a single field, `:message` (a `t:String.t/0`),\n  which is public and can be accessed freely when reading or creating `RuntimeError`\n  exceptions.\n  \"\"\"\n\n  defexception message: \"runtime error\"\nend\n\ndefmodule ArgumentError do\n  @moduledoc \"\"\"\n  An exception raised when an argument to a function is invalid.\n\n  You can raise this exception when you want to signal that an argument to\n  a function is invalid. For example, this exception is raised when calling\n  `Integer.to_string/1` with an invalid argument:\n\n      iex> Integer.to_string(1.0)\n      ** (ArgumentError) errors were found at the given arguments:\n      ...\n\n  `ArgumentError` exceptions have a single field, `:message` (a `t:String.t/0`),\n  which is public and can be accessed freely when reading or creating `ArgumentError`\n  exceptions.\n  \"\"\"\n\n  defexception message: \"argument error\"\nend\n\ndefmodule ArithmeticError do\n  @moduledoc \"\"\"\n  An exception raised on invalid arithmetic operations.\n\n  For example, this exception is raised if you divide by `0`:\n\n      iex> 1 / 0\n      ** (ArithmeticError) bad argument in arithmetic expression\n  \"\"\"\n\n  defexception message: \"bad argument in arithmetic expression\"\n\n  @unary_ops [:+, :-]\n  @binary_ops [:+, :-, :*, :/]\n  @binary_funs [:div, :rem]\n  @bitwise_binary_funs [:band, :bor, :bxor, :bsl, :bsr]\n\n  @impl true\n  def blame(%{message: message} = exception, [{:erlang, fun, args, _} | _] = stacktrace) do\n    message =\n      message <>\n        case {fun, args} do\n          {op, [a]} when op in @unary_ops ->\n            \": #{op}(#{inspect(a)})\"\n\n          {op, [a, b]} when op in @binary_ops ->\n            \": #{inspect(a)} #{op} #{inspect(b)}\"\n\n          {fun, [a, b]} when fun in @binary_funs ->\n            \": #{fun}(#{inspect(a)}, #{inspect(b)})\"\n\n          {fun, [a, b]} when fun in @bitwise_binary_funs ->\n            \": Bitwise.#{fun}(#{inspect(a)}, #{inspect(b)})\"\n\n          {:bnot, [a]} ->\n            \": Bitwise.bnot(#{inspect(a)})\"\n\n          _ ->\n            \"\"\n        end\n\n    {%{exception | message: message}, stacktrace}\n  end\n\n  def blame(exception, stacktrace) do\n    {exception, stacktrace}\n  end\nend\n\ndefmodule SystemLimitError do\n  @moduledoc \"\"\"\n  An exception raised when a system limit has been reached.\n\n  For example, this can happen if you try to create an atom that is too large:\n\n      iex> String.to_atom(String.duplicate(\"a\", 100_000))\n      ** (SystemLimitError) a system limit has been reached\n  \"\"\"\n\n  defexception message: \"a system limit has been reached\"\nend\n\ndefmodule MismatchedDelimiterError do\n  @moduledoc \"\"\"\n  An exception raised when a mismatched delimiter is found when parsing code.\n\n  For example:\n\n      iex> Code.eval_string(\"[1, 2, 3}\")\n      ** (MismatchedDelimiterError) mismatched delimiter found on nofile:1:9:\n      ...\n\n  The following fields of this exceptions are public and can be accessed freely:\n\n    * `:file` (`t:Path.t/0` or `nil`) - the file where the error occurred, or `nil` if\n      the error occurred in code that did not come from a file\n    * `:line` - the line for the opening delimiter\n    * `:column` - the column for the opening delimiter\n    * `:end_line` - the line for the mismatched closing delimiter\n    * `:end_column` - the column for the mismatched closing delimiter\n    * `:opening_delimiter` - an atom representing the opening delimiter\n    * `:closing_delimiter` - an atom representing the mismatched closing delimiter\n    * `:expected_delimiter` - an atom representing the closing delimiter\n    * `:description` - a description of the mismatched delimiter error\n  \"\"\"\n\n  defexception [\n    :file,\n    :line,\n    :column,\n    :end_line,\n    :end_column,\n    :opening_delimiter,\n    :closing_delimiter,\n    :expected_delimiter,\n    :snippet,\n    description: \"mismatched delimiter error\"\n  ]\n\n  @impl true\n  def message(%{\n        line: start_line,\n        column: start_column,\n        end_line: end_line,\n        end_column: end_column,\n        description: description,\n        expected_delimiter: expected_delimiter,\n        file: file,\n        snippet: snippet\n      }) do\n    start_pos = {start_line, start_column}\n    end_pos = {end_line, end_column}\n    lines = String.split(snippet, \"\\n\")\n    expected_delimiter = Exception.format_delimiter(expected_delimiter)\n\n    start_message = \"└ unclosed delimiter\"\n    end_message = ~s/└ mismatched closing delimiter (expected #{expected_delimiter})/\n\n    snippet =\n      Exception.format_snippet(\n        start_pos,\n        end_pos,\n        description,\n        file,\n        lines,\n        start_message,\n        end_message\n      )\n\n    format_message(file, end_line, end_column, snippet)\n  end\n\n  defp format_message(file, line, column, message) do\n    location = Exception.format_file_line_column(Path.relative_to_cwd(file), line, column)\n    \"mismatched delimiter found on \" <> location <> \"\\n\" <> message\n  end\nend\n\ndefmodule SyntaxError do\n  @moduledoc \"\"\"\n  An exception raised when there's a syntax error when parsing code.\n\n  For example:\n\n      iex> Code.eval_string(\"5 + 5h\")\n      ** (SyntaxError) invalid syntax found on nofile:1:5:\n      ...\n\n  The following fields of this exceptions are public and can be accessed freely:\n\n    * `:file` (`t:Path.t/0` or `nil`) - the file where the error occurred, or `nil` if\n      the error occurred in code that did not come from a file\n    * `:line` - the line where the error occurred\n    * `:column` - the column where the error occurred\n    * `:description` - a description of the syntax error\n  \"\"\"\n\n  defexception [:file, :line, :column, :snippet, description: \"syntax error\"]\n\n  @impl true\n  def message(%{\n        file: file,\n        line: line,\n        column: column,\n        description: description,\n        snippet: snippet\n      })\n      when not is_nil(snippet) and not is_nil(column) do\n    snippet =\n      :elixir_errors.format_snippet(:error, {line, column}, file, description, snippet, %{})\n\n    format_message(file, line, column, snippet)\n  end\n\n  @impl true\n  def message(%{\n        file: file,\n        line: line,\n        column: column,\n        description: description\n      }) do\n    snippet =\n      :elixir_errors.format_snippet(:error, {line, column}, file, description, nil, %{})\n\n    padded = \"   \" <> String.replace(snippet, \"\\n\", \"\\n   \")\n    format_message(file, line, column, padded)\n  end\n\n  defp format_message(file, line, column, message) do\n    location = Exception.format_file_line_column(Path.relative_to_cwd(file), line, column)\n    \"invalid syntax found on \" <> location <> \"\\n\" <> message\n  end\nend\n\ndefmodule TokenMissingError do\n  @moduledoc \"\"\"\n  An exception raised when a token is missing when parsing code.\n\n  For example:\n\n      iex> Code.eval_string(\"[1, 2, 3\")\n      ** (TokenMissingError) token missing on nofile:1:9:\n      ...\n\n  The following fields of this exceptions are public and can be accessed freely:\n\n    * `:file` (`t:Path.t/0` or `nil`) - the file where the error occurred, or `nil` if\n      the error occurred in code that did not come from a file\n    * `:line` - the line for the opening delimiter\n    * `:column` - the column for the opening delimiter\n    * `:end_line` - the line for the end of the string\n    * `:end_column` - the column for the end of the string\n    * `:opening_delimiter` - an atom representing the opening delimiter\n    * `:expected_delimiter` - an atom representing the expected delimiter\n    * `:description` - a description of the missing token error\n\n  This is mostly raised by Elixir tooling when compiling and evaluating code.\n  \"\"\"\n\n  defexception [\n    :file,\n    :line,\n    :column,\n    :end_line,\n    :end_column,\n    :snippet,\n    :opening_delimiter,\n    :expected_delimiter,\n    description: \"expression is incomplete\"\n  ]\n\n  @impl true\n  def message(%{\n        file: file,\n        line: line,\n        column: column,\n        end_line: end_line,\n        description: description,\n        expected_delimiter: expected_delimiter,\n        snippet: snippet\n      })\n      when not is_nil(snippet) and not is_nil(column) and not is_nil(end_line) do\n    {trimmed, [last_line | _] = reversed_lines} =\n      snippet\n      |> String.split(\"\\n\")\n      |> Enum.reverse()\n      |> Enum.split_while(&(&1 == \"\"))\n\n    end_line = end_line - length(trimmed)\n    end_column = String.length(last_line) + 1\n\n    start_pos = {line, column}\n    end_pos = {end_line, end_column}\n    expected_delimiter = Exception.format_delimiter(expected_delimiter)\n\n    start_message = ~s/└ unclosed delimiter/\n    end_message = ~s/└ missing closing delimiter (expected #{expected_delimiter})/\n\n    snippet =\n      Exception.format_snippet(\n        start_pos,\n        end_pos,\n        description,\n        file,\n        Enum.reverse(reversed_lines),\n        start_message,\n        end_message\n      )\n\n    format_message(file, end_line, end_column, snippet)\n  end\n\n  @impl true\n  def message(%{\n        file: file,\n        line: line,\n        column: column,\n        snippet: snippet,\n        description: description\n      }) do\n    snippet =\n      :elixir_errors.format_snippet(:error, {line, column}, file, description, snippet, %{})\n\n    format_message(file, line, column, snippet)\n  end\n\n  defp format_message(file, line, column, message) do\n    location = Exception.format_file_line_column(Path.relative_to_cwd(file), line, column)\n    \"token missing on \" <> location <> \"\\n\" <> message\n  end\nend\n\ndefmodule CompileError do\n  @moduledoc \"\"\"\n  An exception raised when there's an error when compiling code.\n\n  For example:\n\n      1 = y\n      ** (CompileError) iex:1: undefined variable \"y\"\n\n  The following fields of this exceptions are public and can be accessed freely:\n\n    * `:file` (`t:Path.t/0` or `nil`) - the file where the error occurred, or `nil` if\n      the error occurred in code that did not come from a file\n    * `:line` (`t:non_neg_integer/0`) - the line where the error occurred\n    * `:description` (`t:String.t/0`) - a description of the compile error\n\n  This is mostly raised by Elixir tooling when compiling and evaluating code.\n  \"\"\"\n\n  defexception [:file, :line, description: \"compile error\"]\n\n  @impl true\n  def message(%{file: file, line: line, description: description}) do\n    case Exception.format_file_line(file && Path.relative_to_cwd(file), line) do\n      \"\" -> description\n      formatted -> formatted <> \" \" <> description\n    end\n  end\nend\n\ndefmodule Kernel.TypespecError do\n  @moduledoc \"\"\"\n  An exception raised when there's an error in a typespec.\n\n  For example, if your typespec definition points to an invalid type, you get an exception:\n\n      @type my_type :: intger()\n\n  will raise:\n\n      ** (Kernel.TypespecError) type intger/0 undefined\n\n  The following fields of this exceptions are public and can be accessed freely:\n\n    * `:file` (`t:Path.t/0` or `nil`) - the file where the error occurred, or `nil` if\n      the error occurred in code that did not come from a file\n    * `:line` (`t:non_neg_integer/0`) - the line where the error occurred\n  \"\"\"\n\n  defexception [:file, :line, :description]\n\n  @impl true\n  def message(%{file: file, line: line, description: description}) do\n    case Exception.format_file_line(file && Path.relative_to_cwd(file), line) do\n      \"\" -> description\n      formatted -> formatted <> \" \" <> description\n    end\n  end\nend\n\ndefmodule BadFunctionError do\n  @moduledoc \"\"\"\n  An exception raised when a function is expected, but something else was given.\n\n  For example:\n\n      iex> value = \"hello\"\n      iex> value.()\n      ** (BadFunctionError) expected a function, got: \"hello\"\n  \"\"\"\n\n  defexception [:term]\n\n  @impl true\n  def message(%{term: term}) when is_function(term) do\n    \"function #{inspect(term)} is invalid, likely because it points to an old version of the code\"\n  end\n\n  def message(exception) do\n    \"expected a function, got: #{inspect(exception.term)}\"\n  end\nend\n\ndefmodule BadMapError do\n  @moduledoc \"\"\"\n  An exception raised when a map is expected, but something else was given.\n\n  For example:\n\n      iex> value = \"hello\"\n      iex> %{value | key: \"value\"}\n      ** (BadMapError) expected a map, got:\n      ...\n  \"\"\"\n\n  defexception [:term]\n\n  @impl true\n  def message(exception) do\n    Exception.__format_message_with_term__(\n      \"expected a map, got:\",\n      exception.term\n    )\n  end\nend\n\ndefmodule BadBooleanError do\n  @moduledoc \"\"\"\n  An exception raised when a boolean is expected, but something else was given.\n\n  This exception is raised by `and` and `or` when the first argument is not a boolean:\n\n      iex> 123 and true\n      ** (BadBooleanError) expected a boolean on left-side of \"and\", got:\n      ...\n  \"\"\"\n\n  defexception [:term, :operator]\n\n  @impl true\n  def message(exception) do\n    Exception.__format_message_with_term__(\n      \"expected a boolean on left-side of \\\"#{exception.operator}\\\", got:\",\n      exception.term\n    )\n  end\nend\n\ndefmodule MatchError do\n  @moduledoc \"\"\"\n  An exception raised when a pattern match (`=/2`) fails.\n\n  For example:\n\n      iex> [_ | _] = []\n      ** (MatchError) no match of right hand side value:\n      ...\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:term` (`t:term/0`) - the term that did not match the pattern\n\n  \"\"\"\n\n  defexception [:term]\n\n  @impl true\n  def message(exception) do\n    Exception.__format_message_with_term__(\n      \"no match of right hand side value:\",\n      exception.term\n    )\n  end\nend\n\ndefmodule CaseClauseError do\n  @moduledoc \"\"\"\n  An exception raised when a term in a `case/2` expression\n  does not match any of the defined `->` clauses.\n\n  For example:\n\n      iex> case System.unique_integer() do\n      ...>   bin when is_binary(bin) -> :oops\n      ...>   :ok -> :neither_this_one\n      ...> end\n      ** (CaseClauseError) no case clause matching:\n      ...\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:term` (`t:term/0`) - the term that did not match any of the clauses\n  \"\"\"\n\n  defexception [:term]\n\n  @impl true\n  def message(exception) do\n    Exception.__format_message_with_term__(\n      \"no case clause matching:\",\n      exception.term\n    )\n  end\nend\n\ndefmodule WithClauseError do\n  @moduledoc \"\"\"\n  An exception raised when a term in a `with/1` expression\n  does not match any of the defined `->` clauses in its `else`.\n\n  For example, this exception gets raised for a `with/1` like the following, because\n  the `{:ok, 2}` term does not match the `:error` or `{:error, _}` clauses in the\n  `else`:\n\n      iex> with {:ok, 1} <- {:ok, 2} do\n      ...>   :woah\n      ...> else\n      ...>   :error -> :error\n      ...>   {:error, _} -> :error\n      ...> end\n      ** (WithClauseError) no with clause matching:\n      ...\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:term` (`t:term/0`) - the term that did not match any of the clauses\n  \"\"\"\n\n  defexception [:term]\n\n  @impl true\n  def message(exception) do\n    Exception.__format_message_with_term__(\n      \"no with clause matching:\",\n      exception.term\n    )\n  end\nend\n\ndefmodule CondClauseError do\n  @moduledoc \"\"\"\n  An exception raised when no clauses in a `cond/1` expression evaluate to a truthy value.\n\n  For example, this exception gets raised for a `cond/1` like the following:\n\n      iex> cond do\n      ...>   1 + 1 == 3 -> :woah\n      ...>   nil -> \"yeah this won't happen\"\n      ...> end\n      ** (CondClauseError) no cond clause evaluated to a truthy value\n  \"\"\"\n\n  defexception []\n\n  @impl true\n  def message(_exception) do\n    \"no cond clause evaluated to a truthy value\"\n  end\nend\n\ndefmodule TryClauseError do\n  @moduledoc \"\"\"\n  An exception raised when none of the `else` clauses in a `try/1` match.\n\n  For example:\n\n      iex> try do\n      ...>   :ok\n      ...> rescue\n      ...>   e -> e\n      ...> else\n      ...>   # :ok -> :ok is missing\n      ...>   :not_ok -> :not_ok\n      ...> end\n      ** (TryClauseError) no try clause matching:\n      ...\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:term` (`t:term/0`) - the term that did not match any of the clauses\n\n  \"\"\"\n  defexception [:term]\n\n  @impl true\n  def message(exception) do\n    Exception.__format_message_with_term__(\n      \"no try clause matching:\",\n      exception.term\n    )\n  end\nend\n\ndefmodule BadArityError do\n  @moduledoc \"\"\"\n  An exception raised when a function is called with the wrong number of arguments.\n\n  For example:\n\n      my_function = fn x, y -> x + y end\n      my_function.(42)\n      ** (BadArityError) #Function<41.39164016/2 in :erl_eval.expr/6> with arity 2 called with 1 argument (42)\n  \"\"\"\n\n  defexception [:function, :args]\n\n  @impl true\n  def message(exception) do\n    fun = exception.function\n    args = exception.args\n    insp = Enum.map_join(args, \", \", &inspect/1)\n    {:arity, arity} = Function.info(fun, :arity)\n    \"#{inspect(fun)} with arity #{arity} called with #{count(length(args), insp)}\"\n  end\n\n  defp count(0, _insp), do: \"no arguments\"\n  defp count(1, insp), do: \"1 argument (#{insp})\"\n  defp count(x, insp), do: \"#{x} arguments (#{insp})\"\nend\n\ndefmodule UndefinedFunctionError do\n  @moduledoc \"\"\"\n  An exception raised when a function is invoked that is not defined.\n\n  For example:\n\n      # Let's use apply/3 as otherwise Elixir emits a compile-time warning\n      iex> apply(String, :non_existing_fun, [\"hello\"])\n      ** (UndefinedFunctionError) function String.non_existing_fun/1 is undefined or private\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:module` (`t:module/0`) - the module name\n    * `:function` (`t:atom/0`) - the function name\n    * `:arity` (`t:non_neg_integer/0`) - the arity of the function\n  \"\"\"\n\n  @function_threshold 0.77\n  @max_suggestions 5\n  defexception [:module, :function, :arity, :reason, :message]\n\n  @impl true\n  def message(%{message: nil} = exception) do\n    %{reason: reason, module: module, function: function, arity: arity} = exception\n    {message, hint_type} = message(reason, module, function, arity)\n    message <> if(hint_type == :suggest_module, do: hint_for_missing_alias(module), else: \"\")\n  end\n\n  def message(%{message: message}) do\n    message\n  end\n\n  defp message(nil, module, function, arity) do\n    cond do\n      is_nil(function) or is_nil(arity) ->\n        {\"undefined function\", :suggest_module}\n\n      is_nil(module) ->\n        formatted_fun = Exception.format_mfa(module, function, arity)\n        {\"function #{formatted_fun} is undefined\", :suggest_module}\n\n      function_exported?(module, :module_info, 0) ->\n        message(:\"function not exported\", module, function, arity)\n\n      true ->\n        message(:\"module could not be loaded\", module, function, arity)\n    end\n  end\n\n  defp message(:\"module could not be loaded\", module, function, arity) do\n    formatted_fun = Exception.format_mfa(module, function, arity)\n\n    {\"function #{formatted_fun} is undefined (module #{inspect(module)} is not available)\",\n     :suggest_module}\n  end\n\n  defp message(:\"function not exported\", module, function, arity) do\n    formatted_fun = Exception.format_mfa(module, function, arity)\n    {\"function #{formatted_fun} is undefined or private\", :suggest_function}\n  end\n\n  defp message(:\"undefined local\", nil, function, arity) do\n    {\"function #{function}/#{arity} is undefined (there is no such import)\", :no_hint}\n  end\n\n  defp message(reason, module, function, arity) do\n    formatted_fun = Exception.format_mfa(module, function, arity)\n    {\"function #{formatted_fun} is undefined (#{reason})\", :suggest_module}\n  end\n\n  @impl true\n  def blame(exception, stacktrace) do\n    %{reason: reason, module: module, function: function, arity: arity} = exception\n    {message, hint_type} = message(reason, module, function, arity)\n    message = message <> hint(module, function, arity, hint_type)\n    {%{exception | message: message}, stacktrace}\n  end\n\n  defp hint(_, _, _, :no_hint), do: \"\"\n\n  defp hint(nil, _function, 0, _hint_type) do\n    \". If you are using the dot syntax, such as module.function(), \" <>\n      \"make sure the left-hand side of the dot is a module atom\"\n  end\n\n  defp hint(module, function, arity, :suggest_function) do\n    hint_for_behaviour(module, function, arity) <>\n      hint_for_loaded_module(module, function, arity)\n  end\n\n  defp hint(module, function, arity, :suggest_module) do\n    hint_for_missing_module(module, function, arity)\n  end\n\n  defp hint_for_missing_alias(module) do\n    with \"Elixir.\" <> rest <- Atom.to_string(module),\n         false <- rest =~ \".\" do\n      \". Make sure the module name is correct and has been specified in full (or that an alias has been defined)\"\n    else\n      _ -> \"\"\n    end\n  end\n\n  @doc false\n  def hint_for_missing_module(module, function, arity) do\n    downcased_module = downcase_module_name(module)\n    stripped_module = module |> Atom.to_string() |> String.replace_leading(\"Elixir.\", \"\")\n\n    candidates =\n      for {name, _, _} = candidate <- :code.all_available(),\n          downcase_module_name(name) == downcased_module or\n            String.ends_with?(List.to_string(name), stripped_module),\n          {:module, module} <- [load_module(candidate)],\n          function_exported?(module, function, arity),\n          do: module\n\n    if candidates != [] do\n      suggestions =\n        candidates\n        |> Enum.take(@max_suggestions)\n        |> Enum.sort(:asc)\n        |> Enum.map(fn module ->\n          [\"\\n      * \", Exception.format_mfa(module, function, arity)]\n        end)\n\n      \". Did you mean:\\n#{suggestions}\\n\"\n    else\n      hint_for_missing_alias(module)\n    end\n  end\n\n  defp load_module({name, _path, _loaded?}) do\n    name\n    |> List.to_atom()\n    |> Code.ensure_loaded()\n  end\n\n  defp downcase_module_name(module) do\n    module\n    |> to_string()\n    |> String.downcase(:ascii)\n  end\n\n  @doc false\n  def hint_for_loaded_module(module, function, arity) do\n    cond do\n      macro_exported?(module, function, arity) ->\n        \". However, there is a macro with the same name and arity. \" <>\n          \"Be sure to require #{inspect(module)} if you intend to invoke this macro\"\n\n      message = otp_obsolete(module, function, arity) ->\n        \", #{message}\"\n\n      true ->\n        IO.iodata_to_binary(did_you_mean(module, function))\n    end\n  end\n\n  defp otp_obsolete(module, function, arity) do\n    case :otp_internal.obsolete(module, function, arity) do\n      {:removed, [_ | _] = string} -> string\n      _ -> nil\n    end\n  end\n\n  defp hint_for_behaviour(module, function, arity) do\n    case behaviours_for(module) do\n      [] ->\n        \"\"\n\n      behaviours ->\n        case Enum.find(behaviours, &expects_callback?(&1, function, arity)) do\n          nil -> \"\"\n          behaviour -> \", but the behaviour #{inspect(behaviour)} expects it to be present\"\n        end\n    end\n  rescue\n    # In case the module was removed while we are computing this\n    UndefinedFunctionError -> \"\"\n  end\n\n  defp behaviours_for(module) do\n    :attributes\n    |> module.module_info()\n    |> Keyword.get(:behaviour, [])\n  end\n\n  defp expects_callback?(behaviour, function, arity) do\n    callbacks =\n      behaviour.behaviour_info(:callbacks) -- behaviour.behaviour_info(:optional_callbacks)\n\n    Enum.member?(callbacks, {function, arity})\n  end\n\n  ## Shared helpers across hints\n\n  defp did_you_mean(module, function) do\n    exports = exports_for(module)\n\n    result =\n      case Keyword.take(exports, [function]) do\n        [] ->\n          candidates = exports -- deprecated_functions_for(module)\n          base = Atom.to_string(function)\n\n          for {key, val} <- candidates,\n              dist = String.jaro_distance(base, Atom.to_string(key)),\n              dist >= @function_threshold,\n              do: {dist, key, val}\n\n        arities ->\n          for {key, val} <- arities, do: {1.0, key, val}\n      end\n      |> Enum.sort(&(elem(&1, 0) >= elem(&2, 0)))\n      |> Enum.take(@max_suggestions)\n      |> Enum.sort(&(elem(&1, 1) <= elem(&2, 1)))\n\n    case result do\n      [] -> []\n      suggestions -> [\". Did you mean:\\n\\n\" | Enum.map(suggestions, &format_fa/1)]\n    end\n  end\n\n  defp format_fa({_dist, fun, arity}) do\n    [\"    * \", Macro.inspect_atom(:remote_call, fun), ?/, Integer.to_string(arity), ?\\n]\n  end\n\n  defp exports_for(module) do\n    if function_exported?(module, :__info__, 1) do\n      module.__info__(:macros) ++ module.__info__(:functions)\n    else\n      module.module_info(:exports)\n    end\n  rescue\n    # In case the module was removed while we are computing this\n    UndefinedFunctionError -> []\n  end\n\n  defp deprecated_functions_for(module) do\n    if function_exported?(module, :__info__, 1) do\n      for {name_arity, _message} <- module.__info__(:deprecated), do: name_arity\n    else\n      []\n    end\n  rescue\n    # In case the module was removed while we are computing this\n    UndefinedFunctionError -> []\n  end\nend\n\ndefmodule FunctionClauseError do\n  @moduledoc \"\"\"\n  An exception raised when a function call doesn't match any defined clause.\n\n  For example:\n\n      iex> List.duplicate(:ok, -3)\n      ** (FunctionClauseError) no function clause matching in List.duplicate/2\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:module` (`t:module/0`) - the module name\n    * `:function` (`t:atom/0`) - the function name\n    * `:arity` (`t:non_neg_integer/0`) - the arity of the function\n  \"\"\"\n\n  defexception [:module, :function, :arity, :kind, :args, :clauses]\n\n  @clause_limit 10\n\n  @impl true\n  def message(exception) do\n    case exception do\n      %{function: nil} ->\n        \"no function clause matches\"\n\n      %{module: module, function: function, arity: arity} ->\n        formatted = Exception.format_mfa(module, function, arity)\n        blamed = blame(exception, &inspect/1, &blame_match/1)\n        \"no function clause matching in #{formatted}\" <> blamed\n    end\n  end\n\n  @impl true\n  def blame(%{module: module, function: function, arity: arity} = exception, stacktrace) do\n    case stacktrace do\n      [{^module, ^function, args, meta} | rest] when length(args) == arity ->\n        exception =\n          case Exception.blame_mfa(module, function, args) do\n            {:ok, kind, clauses} -> %{exception | args: args, kind: kind, clauses: clauses}\n            :error -> %{exception | args: args}\n          end\n\n        {exception, [{module, function, arity, meta} | rest]}\n\n      stacktrace ->\n        {exception, stacktrace}\n    end\n  end\n\n  defp blame_match(%{match?: true, node: node}), do: Macro.to_string(node)\n  defp blame_match(%{match?: false, node: node}), do: \"-\" <> Macro.to_string(node) <> \"-\"\n\n  @doc false\n  def blame(%{args: nil}, _, _) do\n    \"\"\n  end\n\n  def blame(exception, inspect_fun, fun) do\n    %{module: module, function: function, arity: arity, kind: kind, args: args, clauses: clauses} =\n      exception\n\n    mfa = Exception.format_mfa(module, function, arity)\n\n    format_clause_fun = fn {args, guards} ->\n      args = Enum.map_join(args, \", \", fun)\n      base = \"    #{kind} #{function}(#{args})\"\n      Enum.reduce(guards, base, &\"#{&2} when #{clause_to_string(&1, fun, 0)}\") <> \"\\n\"\n    end\n\n    \"\\n\\nThe following arguments were given to #{mfa}:\\n\" <>\n      \"#{format_args(args, inspect_fun)}\" <>\n      \"#{format_clauses(clauses, format_clause_fun, @clause_limit)}\"\n  end\n\n  defp clause_to_string({op, _, [left, right]} = node, fun, parent) do\n    case Code.Identifier.binary_op(op) do\n      {_side, precedence} ->\n        left = clause_to_string(left, fun, precedence)\n        right = clause_to_string(right, fun, precedence)\n\n        if parent > precedence do\n          \"(\" <> left <> \" #{op} \" <> right <> \")\"\n        else\n          left <> \" #{op} \" <> right\n        end\n\n      _ ->\n        fun.(node)\n    end\n  end\n\n  defp clause_to_string(node, fun, _precedence), do: fun.(node)\n\n  defp format_args(args, inspect_fun) do\n    args\n    |> Enum.with_index(1)\n    |> Enum.map(fn {arg, i} ->\n      [pad(\"\\n# \"), Integer.to_string(i), pad(\"\\n\"), pad(inspect_fun.(arg)), \"\\n\"]\n    end)\n  end\n\n  defp format_clauses(clauses, format_clause_fun, limit)\n  defp format_clauses(nil, _, _), do: \"\"\n  defp format_clauses([], _, _), do: \"\"\n\n  defp format_clauses(clauses, format_clause_fun, limit) do\n    top_clauses =\n      clauses\n      |> Enum.take(limit)\n      |> Enum.map(format_clause_fun)\n\n    [\n      \"\\nAttempted function clauses (showing #{length(top_clauses)} out of #{length(clauses)}):\",\n      \"\\n\\n\",\n      top_clauses,\n      non_visible_clauses(length(clauses) - limit)\n    ]\n  end\n\n  defp non_visible_clauses(n) when n <= 0, do: []\n  defp non_visible_clauses(1), do: [\"    ...\\n    (1 clause not shown)\\n\"]\n  defp non_visible_clauses(n), do: [\"    ...\\n    (#{n} clauses not shown)\\n\"]\n\n  defp pad(string) do\n    String.replace(string, \"\\n\", \"\\n    \")\n  end\nend\n\ndefmodule Code.LoadError do\n  @moduledoc \"\"\"\n  An exception raised when a file cannot be loaded.\n\n  This is typically raised by functions in the `Code` module, for example:\n\n      Code.require_file(\"missing_file.exs\")\n      ** (Code.LoadError) could not load missing_file.exs. Reason: enoent\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:file` (`t:String.t/0`) - the file name\n    * `:reason` (`t:term/0`) - the reason why the file could not be loaded\n  \"\"\"\n\n  defexception [:file, :message, :reason]\n\n  def exception(opts) do\n    file = Keyword.fetch!(opts, :file)\n    reason = Keyword.fetch!(opts, :reason)\n    message = \"could not load #{file}. Reason: #{reason}\"\n    %Code.LoadError{message: message, file: file, reason: reason}\n  end\nend\n\ndefmodule Protocol.UndefinedError do\n  @moduledoc \"\"\"\n  An exception raised when a protocol is not implemented for a given value.\n\n  For example:\n\n      iex> Enum.at(\"A string!\", 0)\n      ** (Protocol.UndefinedError) protocol Enumerable not implemented for BitString\n      ...\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:protocol` (`t:module/0`) - the protocol that is not implemented\n    * `:value` (`t:term/0`) - the value that does not implement the protocol\n  \"\"\"\n\n  defexception [:protocol, :value, description: \"\"]\n\n  @impl true\n  def message(%{protocol: protocol, value: value, description: description}) do\n    inspected =\n      value\n      |> inspect(pretty: true)\n      # Indent only lines with contents on them\n      |> String.replace(~r/^(?=.+)/m, \"    \")\n\n    \"protocol #{inspect(protocol)} not implemented for \" <>\n      value_type(value) <>\n      maybe_description(description) <>\n      maybe_available(protocol) <>\n      \"\"\"\n\n\n      Got value:\n\n      #{inspected}\n      \"\"\"\n  end\n\n  defp value_type(%{__struct__: struct}), do: \"#{inspect(struct)} (a struct)\"\n  defp value_type(value) when is_atom(value), do: \"Atom\"\n  defp value_type(value) when is_bitstring(value), do: \"BitString\"\n  defp value_type(value) when is_float(value), do: \"Float\"\n  defp value_type(value) when is_function(value), do: \"Function\"\n  defp value_type(value) when is_integer(value), do: \"Integer\"\n  defp value_type(value) when is_list(value), do: \"List\"\n  defp value_type(value) when is_map(value), do: \"Map\"\n  defp value_type(value) when is_pid(value), do: \"PID\"\n  defp value_type(value) when is_port(value), do: \"Port\"\n  defp value_type(value) when is_reference(value), do: \"Reference\"\n  defp value_type(value) when is_tuple(value), do: \"Tuple\"\n\n  defp maybe_description(\"\"), do: \"\"\n  defp maybe_description(description), do: \", \" <> description\n\n  defp maybe_available(protocol) do\n    case protocol.__protocol__(:impls) do\n      {:consolidated, []} ->\n        \". There are no implementations for this protocol.\"\n\n      {:consolidated, types} ->\n        \". This protocol is implemented for: \" <>\n          Enum.map_join(types, \", \", &inspect/1)\n\n      :not_consolidated ->\n        \"\"\n    end\n  end\nend\n\ndefmodule KeyError do\n  @moduledoc \"\"\"\n  An exception raised when a key is not found in a data structure.\n\n  For example, this is raised by `Map.fetch!/2` when the given key\n  cannot be found in the given map:\n\n      iex> map = %{name: \"Alice\", age: 25}\n      iex> Map.fetch!(map, :first_name)\n      ** (KeyError) key :first_name not found in:\n      ...\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:term` (`t:term/0`) - the data structure that was searched\n    * `:key` (`t:term/0`) - the key that was not found\n  \"\"\"\n\n  defexception [:key, :term, :message]\n\n  @impl true\n  def message(exception = %{message: nil}), do: message(exception.key, exception.term)\n  def message(%{message: message}), do: message\n\n  defp message(key, term) do\n    message = \"key #{inspect(key)} not found\"\n\n    cond do\n      term == nil ->\n        message\n\n      is_atom(term) and is_atom(key) ->\n        message <>\n          \" in: #{inspect(term)} (if instead you want to invoke #{inspect(term)}.#{key}(), \" <>\n          \"make sure to add parentheses after the function name)\"\n\n      true ->\n        Exception.__format_message_with_term__(\n          message <> \" in:\",\n          term\n        )\n    end\n  end\n\n  @impl true\n  def blame(exception = %{message: message}, stacktrace) when is_binary(message) do\n    {exception, stacktrace}\n  end\n\n  def blame(exception, stacktrace) do\n    %{term: term, key: key} = exception\n    message = message(key, term)\n\n    if is_atom(key) and (map_with_atom_keys_only?(term) or Keyword.keyword?(term)) do\n      hint = did_you_mean(key, available_keys(term))\n      message = message <> IO.iodata_to_binary(hint)\n      {%{exception | message: message}, stacktrace}\n    else\n      {%{exception | message: message}, stacktrace}\n    end\n  end\n\n  defp map_with_atom_keys_only?(term) do\n    is_map(term) and Enum.all?(Map.to_list(term), fn {k, _} -> is_atom(k) end)\n  end\n\n  defp available_keys(term) when is_map(term), do: Map.keys(term)\n  defp available_keys(term) when is_list(term), do: Keyword.keys(term)\n\n  @threshold 0.77\n  @max_suggestions 5\n  defp did_you_mean(missing_key, available_keys) do\n    stringified_key = Atom.to_string(missing_key)\n\n    suggestions =\n      for key <- available_keys,\n          distance = String.jaro_distance(stringified_key, Atom.to_string(key)),\n          distance >= @threshold,\n          do: {distance, key}\n\n    case suggestions do\n      [] -> []\n      suggestions -> [\"\\nDid you mean:\\n\\n\" | format_suggestions(suggestions)]\n    end\n  end\n\n  defp format_suggestions(suggestions) do\n    suggestions\n    |> Enum.sort(&(elem(&1, 0) >= elem(&2, 0)))\n    |> Enum.take(@max_suggestions)\n    |> Enum.sort(&(elem(&1, 1) <= elem(&2, 1)))\n    |> Enum.map(fn {_, key} -> [\"    * \", inspect(key), ?\\n] end)\n  end\nend\n\ndefmodule UnicodeConversionError do\n  @moduledoc \"\"\"\n  An exception raised when converting data to or from Unicode.\n\n  For example:\n\n      iex> String.to_charlist(<<0xFF>>)\n      ** (UnicodeConversionError) invalid encoding starting at <<255>>\n\n  \"\"\"\n  defexception [:encoded, :message]\n\n  def exception(opts) do\n    %UnicodeConversionError{\n      encoded: Keyword.fetch!(opts, :encoded),\n      message: \"#{Keyword.fetch!(opts, :kind)} #{detail(Keyword.fetch!(opts, :rest))}\"\n    }\n  end\n\n  defp detail(rest) when is_binary(rest) do\n    \"encoding starting at #{inspect(rest)}\"\n  end\n\n  defp detail([h | _]) when is_integer(h) do\n    \"code point #{h}\"\n  end\n\n  defp detail([h | _]) do\n    detail(h)\n  end\nend\n\ndefmodule MissingApplicationsError do\n  @moduledoc \"\"\"\n  An exception that is raised when an application depends on one or more\n  missing applications.\n\n  This exception is used by Mix and other tools. It can also be used by library authors\n  when their library only requires an external application (like a dependency) for a subset\n  of features.\n\n  The fields of this exception are public. See `t:t/0`.\n\n  *Available since v1.18.0.*\n\n  ## Examples\n\n      unless Application.spec(:plug, :vsn) do\n        raise MissingApplicationsError,\n          description: \"application :plug is required for testing Plug-related functionality\",\n          apps: [{:plug, \"~> 1.0\"}]\n      end\n\n  \"\"\"\n\n  @moduledoc since: \"1.18.0\"\n\n  @type t() :: %__MODULE__{\n          apps: [{Application.app(), Version.requirement()}, ...],\n          description: String.t()\n        }\n\n  defexception apps: [], description: \"missing applications found\"\n\n  @impl true\n  def message(%__MODULE__{apps: apps, description: description}) do\n    # We explicitly format these as tuples so that they're easier to copy-paste\n    # into dependencies.\n    formatted_apps =\n      Enum.map(apps, fn {app_name, requirement} ->\n        ~s(\\n  {#{inspect(app_name)}, \"#{requirement}\"})\n      end)\n\n    \"\"\"\n    #{description}\n\n    To address this, include these applications as your dependencies:\n    #{formatted_apps}\\\n    \"\"\"\n  end\nend\n\ndefmodule Enum.OutOfBoundsError do\n  @moduledoc \"\"\"\n  An exception that is raised when a function expects an enumerable to have\n  a certain size but finds that it is too small.\n\n  For example:\n\n      iex> Enum.fetch!([1, 2, 3], 5)\n      ** (Enum.OutOfBoundsError) out of bounds error at position 5 when traversing enumerable [1, 2, 3]\n  \"\"\"\n\n  defexception [:enumerable, :index, :message]\n\n  @impl true\n  def message(exception = %{message: nil}), do: message(exception.index, exception.enumerable)\n  def message(%{message: message}), do: message\n\n  def message(index, enumerable) do\n    \"out of bounds error\" <>\n      if index do\n        \" at position #{index}\"\n      else\n        \"\"\n      end <>\n      if enumerable do\n        \" when traversing enumerable #{inspect(enumerable)}\"\n      else\n        \"\"\n      end\n  end\nend\n\ndefmodule Enum.EmptyError do\n  @moduledoc \"\"\"\n  An exception that is raised when something expects a non-empty enumerable\n  but finds an empty one.\n\n  For example:\n\n      iex> Enum.min([])\n      ** (Enum.EmptyError) empty error\n\n  \"\"\"\n\n  defexception message: \"empty error\"\nend\n\ndefmodule File.Error do\n  @moduledoc \"\"\"\n  An exception that is raised when a file operation fails.\n\n  For example, this exception is raised, when trying to read a non existent file:\n\n      iex> File.read!(\"nonexistent_file.txt\")\n      ** (File.Error) could not read file \"nonexistent_file.txt\": no such file or directory\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:path` (`t:Path.t/0`) - the path of the file that caused the error\n    * `:reason` (`t:File.posix/0`) - the reason for the error\n\n  \"\"\"\n\n  defexception [:reason, :path, action: \"\"]\n\n  @impl true\n  def message(%{action: action, reason: reason, path: path}) do\n    formatted =\n      case {action, reason} do\n        {\"remove directory\", :eexist} ->\n          \"directory is not empty\"\n\n        _ ->\n          IO.iodata_to_binary(:file.format_error(reason))\n      end\n\n    \"could not #{action} #{inspect(path)}: #{formatted}\"\n  end\nend\n\ndefmodule File.CopyError do\n  @moduledoc \"\"\"\n  An exception that is raised when copying a file fails.\n\n  For example, this exception is raised when trying to copy to file or directory that isn't present:\n\n      iex> File.cp_r!(\"non_existent\", \"source_dir/subdir\")\n      ** (File.CopyError) could not copy recursively from \"non_existent\" to \"source_dir/subdir\". non_existent: no such file or directory\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:source` (`t:Path.t/0`) - the source path\n    * `:destination` (`t:Path.t/0`) - the destination path\n    * `:reason` (`t:File.posix/0`) - the reason why the file could not be copied\n\n  \"\"\"\n\n  defexception [:reason, :source, :destination, on: \"\", action: \"\"]\n\n  @impl true\n  def message(exception) do\n    formatted = IO.iodata_to_binary(:file.format_error(exception.reason))\n\n    location =\n      case exception.on do\n        \"\" -> \"\"\n        on -> \". #{on}\"\n      end\n\n    \"could not #{exception.action} from #{inspect(exception.source)} to \" <>\n      \"#{inspect(exception.destination)}#{location}: #{formatted}\"\n  end\nend\n\ndefmodule File.RenameError do\n  @moduledoc \"\"\"\n  An exception that is raised when renaming a file fails.\n\n  For example, this exception is raised when trying to rename a file that isn't present:\n\n    iex> File.rename!(\"source.txt\", \"target.txt\")\n    ** (File.RenameError) could not rename from \"source.txt\" to \"target.txt\": no such file or directory\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:source` (`t:Path.t/0`) - the source path\n    * `:destination` (`t:Path.t/0`) - the destination path\n    * `:reason` (`t:File.posix/0`) - the reason why the file could not be renamed\n\n  \"\"\"\n\n  defexception [:reason, :source, :destination, on: \"\", action: \"\"]\n\n  @impl true\n  def message(exception) do\n    formatted = IO.iodata_to_binary(:file.format_error(exception.reason))\n\n    location =\n      case exception.on do\n        \"\" -> \"\"\n        on -> \". #{on}\"\n      end\n\n    \"could not #{exception.action} from #{inspect(exception.source)} to \" <>\n      \"#{inspect(exception.destination)}#{location}: #{formatted}\"\n  end\nend\n\ndefmodule File.LinkError do\n  @moduledoc \"\"\"\n  An exception that is raised when linking a file fails.\n\n  For example, this exception is raised when trying to link to file that isn't present:\n\n      iex> File.ln!(\"existing.txt\", \"link.txt\")\n      ** (File.LinkError) could not create hard link from \"link.txt\" to \"existing.txt\": no such file or directory\n\n  The following fields of this exception are public and can be accessed freely:\n\n    * `:existing` (`t:Path.t/0`) - the existing file to link\n    * `:new` (`t:Path.t/0`) - the link destination\n    * `:reason` (`t:File.posix/0`) - the reason why the file could not be linked\n\n  \"\"\"\n\n  defexception [:reason, :existing, :new, action: \"\"]\n\n  @impl true\n  def message(exception) do\n    formatted = IO.iodata_to_binary(:file.format_error(exception.reason))\n\n    \"could not #{exception.action} from #{inspect(exception.new)} to \" <>\n      \"#{inspect(exception.existing)}: #{formatted}\"\n  end\nend\n\ndefmodule ErlangError do\n  @moduledoc \"\"\"\n  An exception raised when invoking an Erlang code that errors\n  with a value not handled by Elixir.\n\n  Most common error reasons, such as `:badarg` are automatically\n  converted into exceptions by Elixir. However, you may invoke some\n  code that emits a custom error reason and those get wrapped into\n  `ErlangError`:\n\n      iex> :erlang.error(:some_invalid_error)\n      ** (ErlangError) Erlang error: :some_invalid_error\n  \"\"\"\n\n  defexception [:original, :reason]\n\n  @impl true\n  def message(exception)\n\n  def message(%__MODULE__{original: original, reason: nil}) do\n    \"Erlang error: #{inspect(original)}\"\n  end\n\n  def message(%__MODULE__{original: original, reason: reason}) do\n    IO.iodata_to_binary([\"Erlang error: \", inspect(original), reason])\n  end\n\n  @doc false\n  def normalize(:badarg, stacktrace) do\n    case stacktrace do\n      [{:erlang, :apply, [module, function, args], _} | _] when not is_atom(module) ->\n        message =\n          cond do\n            is_map(module) and is_atom(function) and is_map_key(module, function) ->\n              \"you attempted to apply a function named #{inspect(function)} on a map/struct. \" <>\n                \"If you are using Kernel.apply/3, make sure the module is an atom. \" <>\n                if is_function(Map.get(module, function)) do\n                  \"If you are trying to invoke an anonymous function in a map/struct, \" <>\n                    \"add a dot between the function name and the parenthesis: map.#{function}.()\"\n                else\n                  \"If you are using the dot syntax, ensure there are no parentheses \" <>\n                    \"after the field name, such as map.#{function}\"\n                end\n\n            is_atom(function) and args == [] ->\n              \"you attempted to apply a function named #{inspect(function)} on #{inspect(module)}. \" <>\n                \"If you are using Kernel.apply/3, make sure the module is an atom. \" <>\n                \"If you are using the dot syntax, such as module.function(), \" <>\n                \"make sure the left-hand side of the dot is an atom representing a module\"\n\n            true ->\n              \"you attempted to apply a function on #{inspect(module)}. \" <>\n                \"Modules (the first argument of apply) must always be an atom\"\n          end\n\n        %ArgumentError{message: message}\n\n      _ ->\n        case error_info(:badarg, stacktrace, \"errors were found at the given arguments\") do\n          {:ok, reason, details} -> %ArgumentError{message: reason <> details}\n          :error -> %ArgumentError{}\n        end\n    end\n  end\n\n  def normalize(:badarith, _stacktrace) do\n    %ArithmeticError{}\n  end\n\n  def normalize(:system_limit, stacktrace) do\n    default_reason = \"a system limit has been reached due to errors at the given arguments\"\n\n    case error_info(:system_limit, stacktrace, default_reason) do\n      {:ok, reason, details} -> %SystemLimitError{message: reason <> details}\n      :error -> %SystemLimitError{}\n    end\n  end\n\n  def normalize(:cond_clause, _stacktrace) do\n    %CondClauseError{}\n  end\n\n  def normalize({:badarity, {fun, args}}, _stacktrace) do\n    %BadArityError{function: fun, args: args}\n  end\n\n  def normalize({:badfun, term}, _stacktrace) do\n    %BadFunctionError{term: term}\n  end\n\n  def normalize({:badmatch, term}, _stacktrace) do\n    %MatchError{term: term}\n  end\n\n  def normalize({:badmap, term}, _stacktrace) do\n    %BadMapError{term: term}\n  end\n\n  def normalize({:badbool, op, term}, _stacktrace) do\n    %BadBooleanError{operator: op, term: term}\n  end\n\n  def normalize({:badkey, key}, stacktrace) do\n    term =\n      case stacktrace do\n        [{Map, :get_and_update!, [map, _, _], _} | _] -> map\n        [{Map, :update!, [map, _, _], _} | _] -> map\n        [{:maps, :update, [_, _, map], _} | _] -> map\n        [{:maps, :get, [_, map], _} | _] -> map\n        [{:erlang, :map_get, [_, map], _} | _] -> map\n        _ -> nil\n      end\n\n    %KeyError{key: key, term: term}\n  end\n\n  def normalize({:badkey, key, map}, _stacktrace) when is_map(map) do\n    %KeyError{key: key, term: map}\n  end\n\n  def normalize({:badkey, key, term}, _stacktrace) do\n    message =\n      \"key #{inspect(key)} not found in: #{inspect(term, pretty: true, limit: :infinity)}\\n\\n\" <>\n        \"If you are using the dot syntax, such as map.field, \" <>\n        \"make sure the left-hand side of the dot is a map\"\n\n    %KeyError{key: key, term: term, message: message}\n  end\n\n  def normalize({:case_clause, term}, _stacktrace) do\n    %CaseClauseError{term: term}\n  end\n\n  # :else_clause is aligned on what Erlang returns for `maybe`\n  def normalize({:else_clause, term}, _stacktrace) do\n    %WithClauseError{term: term}\n  end\n\n  def normalize({:try_clause, term}, _stacktrace) do\n    %TryClauseError{term: term}\n  end\n\n  def normalize(:undef, stacktrace) do\n    {mod, fun, arity} = from_stacktrace(stacktrace)\n    %UndefinedFunctionError{module: mod, function: fun, arity: arity}\n  end\n\n  def normalize(:function_clause, stacktrace) do\n    {mod, fun, arity} = from_stacktrace(stacktrace)\n    %FunctionClauseError{module: mod, function: fun, arity: arity}\n  end\n\n  def normalize({:badarg, payload}, _stacktrace) do\n    %ArgumentError{message: \"argument error: #{inspect(payload)}\"}\n  end\n\n  def normalize(other, stacktrace) do\n    case error_info(other, stacktrace, \"\") do\n      {:ok, _reason, details} -> %ErlangError{original: other, reason: details}\n      :error -> %ErlangError{original: other}\n    end\n  end\n\n  defp from_stacktrace([{module, function, args, _} | _]) when is_list(args) do\n    {module, function, length(args)}\n  end\n\n  defp from_stacktrace([{module, function, arity, _} | _]) do\n    {module, function, arity}\n  end\n\n  defp from_stacktrace(_) do\n    {nil, nil, nil}\n  end\n\n  defp error_info(erl_exception, stacktrace, default_reason) do\n    with [{module, fun, args_or_arity, opts} | tail] <- stacktrace,\n         %{} = error_info <- opts[:error_info] do\n      error_module = Map.get(error_info, :module, module)\n      error_fun = Map.get(error_info, :function, :format_error)\n\n      error_info = Map.put(error_info, :pretty_printer, &inspect/1)\n      head = {module, fun, args_or_arity, Keyword.put(opts, :error_info, error_info)}\n\n      extra =\n        try do\n          apply(error_module, error_fun, [erl_exception, [head | tail]])\n        rescue\n          _ -> %{}\n        end\n\n      arity = if is_integer(args_or_arity), do: args_or_arity, else: length(args_or_arity)\n      args_errors = Map.take(extra, Enum.to_list(1..arity//1))\n      reason = Map.get(extra, :reason, default_reason)\n\n      cond do\n        map_size(args_errors) > 0 ->\n          {:ok, reason, IO.iodata_to_binary([\":\\n\\n\" | Enum.map(args_errors, &arg_error/1)])}\n\n        general = extra[:general] ->\n          {:ok, reason, \": \" <> IO.chardata_to_string(general)}\n\n        true ->\n          :error\n      end\n    else\n      _ -> :error\n    end\n  end\n\n  defp arg_error({n, message}), do: \"  * #{nth(n)} argument: #{message}\\n\"\n\n  defp nth(1), do: \"1st\"\n  defp nth(2), do: \"2nd\"\n  defp nth(3), do: \"3rd\"\n  defp nth(n), do: \"#{n}th\"\nend\n"
  },
  {
    "path": "lib/elixir/lib/file/stat.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nrequire Record\n\ndefmodule File.Stat do\n  @moduledoc \"\"\"\n  A struct that holds file information.\n\n  In Erlang, this struct is represented by a `:file_info` record.\n  Therefore this module also provides functions for converting\n  between the Erlang record and the Elixir struct.\n\n  Its fields are:\n\n    * `size` - size of file in bytes.\n\n    * `type` - `:device | :directory | :regular | :other | :symlink`; the type of the\n      file.\n\n    * `access` - `:read | :write | :read_write | :none`; the current system\n      access to the file.\n\n    * `atime` - the last time the file was read.\n\n    * `mtime` - the last time the file was written.\n\n    * `ctime` - the interpretation of this time field depends on the operating\n      system. On Unix-like operating systems, it is the last time the file or the inode was changed.\n      In Windows, it is the time of creation.\n\n    * `mode` - the file permissions.\n\n    * `links` - the number of links to this file. This is always 1 for file\n      systems which have no concept of links.\n\n    * `major_device` - identifies the file system where the file is located.\n      In Windows, the number indicates a drive as follows: 0 means A:, 1 means\n      B:, and so on.\n\n    * `minor_device` - only valid for character devices on Unix-like systems. In all other\n      cases, this field is zero.\n\n    * `inode` - gives the inode number. On non-Unix-like file systems, this field\n      will be zero.\n\n    * `uid` - indicates the owner of the file. Will be zero for non-Unix-like file\n      systems.\n\n    * `gid` - indicates the group that owns the file. Will be zero for\n      non-Unix-like file systems.\n\n  The time type returned in `atime`, `mtime`, and `ctime` is dependent on the\n  time type set in options. `{:time, type}` where type can be `:local`,\n  `:universal`, or `:posix`. Default is `:universal`.\n  \"\"\"\n\n  record = Record.extract(:file_info, from_lib: \"kernel/include/file.hrl\")\n  keys = :lists.map(&elem(&1, 0), record)\n  vals = :lists.map(&{&1, [], nil}, keys)\n  pairs = :lists.zip(keys, vals)\n\n  defstruct keys\n\n  @type t :: %__MODULE__{\n          size: non_neg_integer() | :undefined,\n          type: :device | :directory | :regular | :other | :symlink | :undefined,\n          access: :read | :write | :read_write | :none | :undefined,\n          atime: :calendar.datetime() | integer() | :undefined,\n          mtime: :calendar.datetime() | integer() | :undefined,\n          ctime: :calendar.datetime() | integer() | :undefined,\n          mode: non_neg_integer() | :undefined,\n          links: non_neg_integer() | :undefined,\n          major_device: non_neg_integer() | :undefined,\n          minor_device: non_neg_integer() | :undefined,\n          inode: non_neg_integer() | :undefined,\n          uid: non_neg_integer() | :undefined,\n          gid: non_neg_integer() | :undefined\n        }\n\n  @doc \"\"\"\n  Converts a `File.Stat` struct to a `:file_info` record.\n  \"\"\"\n  @spec to_record(t()) :: :file.file_info()\n  def to_record(%File.Stat{unquote_splicing(pairs)}) do\n    {:file_info, unquote_splicing(vals)}\n  end\n\n  @doc \"\"\"\n  Converts a `:file_info` record into a `File.Stat`.\n  \"\"\"\n  @spec from_record(:file.file_info()) :: t()\n  def from_record(file_info)\n\n  def from_record({:file_info, unquote_splicing(vals)}) do\n    %File.Stat{unquote_splicing(pairs)}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/file/stream.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule File.Stream do\n  @moduledoc \"\"\"\n  Defines a `File.Stream` struct returned by `File.stream!/3`.\n\n  The following fields are public:\n\n    * `path`          - the file path\n    * `modes`         - the file modes\n    * `raw`           - a boolean indicating if bin functions should be used\n    * `line_or_bytes` - if reading should read lines or a given number of bytes\n    * `node`          - the node the file belongs to\n\n  \"\"\"\n\n  defstruct path: nil, modes: [], line_or_bytes: :line, raw: true, node: nil\n\n  @type t :: %__MODULE__{}\n\n  @doc false\n  def __build__(path, line_or_bytes, modes) do\n    with {:read_offset, offset} <- :lists.keyfind(:read_offset, 1, modes),\n         false <- is_integer(offset) and offset >= 0 do\n      raise ArgumentError,\n            \"expected :read_offset to be a non-negative integer, got: #{inspect(offset)}\"\n    end\n\n    raw = :lists.keyfind(:encoding, 1, modes) == false\n\n    modes =\n      case raw do\n        true ->\n          case :lists.keyfind(:read_ahead, 1, modes) do\n            {:read_ahead, false} -> [:raw | :lists.keydelete(:read_ahead, 1, modes)]\n            {:read_ahead, _} -> [:raw | modes]\n            false -> [:raw, :read_ahead | modes]\n          end\n\n        false ->\n          modes\n      end\n\n    %File.Stream{path: path, modes: modes, raw: raw, line_or_bytes: line_or_bytes, node: node()}\n  end\n\n  @doc false\n  def __open__(%File.Stream{path: path, node: node}, modes) when node == node() do\n    :file.open(path, modes)\n  end\n\n  @doc false\n  def __open__(%File.Stream{path: path, node: node}, modes) do\n    :erpc.call(node, :file_io_server, :start, [self(), path, List.delete(modes, :raw)])\n  end\n\n  defimpl Collectable do\n    def into(%{modes: modes, raw: raw} = stream) do\n      modes = for mode <- modes, mode not in [:read], do: mode\n\n      case File.Stream.__open__(stream, [:write | modes]) do\n        {:ok, device} ->\n          {:ok, into(device, stream, raw)}\n\n        {:error, reason} ->\n          raise File.Error, reason: reason, action: \"stream\", path: stream.path\n      end\n    end\n\n    defp into(device, stream, raw) do\n      fn\n        :ok, {:cont, x} ->\n          case raw do\n            true -> IO.binwrite(device, x)\n            false -> IO.write(device, x)\n          end\n\n        :ok, :done ->\n          # If delayed_write option is used and the last write failed will\n          # MatchError here as {:error, _} is returned.\n          :ok = :file.close(device)\n          stream\n\n        :ok, :halt ->\n          # If delayed_write option is used and the last write failed will\n          # MatchError here as {:error, _} is returned.\n          :ok = :file.close(device)\n      end\n    end\n  end\n\n  defimpl Enumerable do\n    @read_ahead_size 64 * 1024\n\n    def reduce(%{modes: modes, line_or_bytes: line_or_bytes, raw: raw} = stream, acc, fun) do\n      start_fun = fn ->\n        case File.Stream.__open__(stream, read_modes(modes)) do\n          {:ok, device} ->\n            skip_bom_and_offset(device, raw, modes)\n\n          {:error, reason} ->\n            raise File.Error, reason: reason, action: \"stream\", path: stream.path\n        end\n      end\n\n      next_fun =\n        case raw do\n          true -> &IO.each_binstream(&1, line_or_bytes)\n          false -> &IO.each_stream(&1, line_or_bytes)\n        end\n\n      Stream.resource(start_fun, next_fun, &:file.close/1).(acc, fun)\n    end\n\n    def count(%{modes: modes, line_or_bytes: :line, path: path, raw: raw} = stream) do\n      pattern = :binary.compile_pattern(\"\\n\")\n\n      counter = fn device ->\n        device = skip_bom_and_offset(device, raw, modes)\n        count_lines(device, path, pattern, read_function(stream), 0, :empty)\n      end\n\n      {:ok, open!(stream, modes, counter)}\n    end\n\n    def count(%{path: path, line_or_bytes: bytes, raw: true, modes: modes, node: node} = stream) do\n      case :erpc.call(node, File, :stat, [path]) do\n        {:ok, %{size: 0}} ->\n          {:error, __MODULE__}\n\n        {:ok, %{size: size}} ->\n          bom_offset = count_raw_bom(stream, modes)\n          offset = get_read_offset(modes)\n          size = max(size - bom_offset - offset, 0)\n          remainder = if rem(size, bytes) == 0, do: 0, else: 1\n          {:ok, div(size, bytes) + remainder}\n\n        {:error, reason} ->\n          raise File.Error, reason: reason, action: \"stream\", path: path\n      end\n    end\n\n    def count(_stream) do\n      {:error, __MODULE__}\n    end\n\n    def member?(_stream, _term) do\n      {:error, __MODULE__}\n    end\n\n    def slice(_stream) do\n      {:error, __MODULE__}\n    end\n\n    defp open!(stream, modes, fun) do\n      case File.Stream.__open__(stream, read_modes(modes)) do\n        {:ok, device} ->\n          try do\n            fun.(device)\n          after\n            :file.close(device)\n          end\n\n        {:error, reason} ->\n          raise File.Error, reason: reason, action: \"stream\", path: stream.path\n      end\n    end\n\n    defp count_raw_bom(stream, modes) do\n      if :trim_bom in modes do\n        open!(stream, read_modes(modes), &(&1 |> trim_bom(true) |> elem(1)))\n      else\n        0\n      end\n    end\n\n    defp skip_bom_and_offset(device, raw, modes) do\n      device =\n        if :trim_bom in modes do\n          device |> trim_bom(raw) |> elem(0)\n        else\n          device\n        end\n\n      offset = get_read_offset(modes)\n\n      if offset > 0 do\n        {:ok, _} = :file.position(device, {:cur, offset})\n      end\n\n      device\n    end\n\n    defp trim_bom(device, true) do\n      bom_length = device |> IO.binread(4) |> bom_length()\n      {:ok, new_pos} = :file.position(device, bom_length)\n      {device, new_pos}\n    end\n\n    defp trim_bom(device, false) do\n      # Or we read the bom in the correct amount or it isn't there\n      case bom_length(IO.read(device, 1)) do\n        0 ->\n          {:ok, _} = :file.position(device, 0)\n          {device, 0}\n\n        _ ->\n          {device, 1}\n      end\n    end\n\n    defp bom_length(<<239, 187, 191, _rest::binary>>), do: 3\n    defp bom_length(<<254, 255, _rest::binary>>), do: 2\n    defp bom_length(<<255, 254, _rest::binary>>), do: 2\n    defp bom_length(<<0, 0, 254, 255, _rest::binary>>), do: 4\n    defp bom_length(<<254, 255, 0, 0, _rest::binary>>), do: 4\n    defp bom_length(_binary), do: 0\n\n    def get_read_offset(modes) do\n      case :lists.keyfind(:read_offset, 1, modes) do\n        {:read_offset, offset} -> offset\n        false -> 0\n      end\n    end\n\n    defp read_modes(modes) do\n      for mode <- modes, mode not in [:write, :append, :trim_bom], do: mode\n    end\n\n    defp count_lines(device, path, pattern, read, count, last_byte) do\n      case read.(device) do\n        data when is_binary(data) and byte_size(data) > 0 ->\n          newlines = length(:binary.matches(data, pattern))\n          last = :binary.last(data)\n          count_lines(device, path, pattern, read, count + newlines, last)\n\n        data when is_binary(data) ->\n          count_lines(device, path, pattern, read, count, last_byte)\n\n        :eof ->\n          case last_byte do\n            :empty -> 0\n            ?\\n -> count\n            _ -> count + 1\n          end\n\n        {:error, reason} ->\n          raise File.Error, reason: reason, action: \"stream\", path: path\n      end\n    end\n\n    defp read_function(%{raw: true}), do: &IO.binread(&1, @read_ahead_size)\n    defp read_function(%{raw: false}), do: &IO.read(&1, @read_ahead_size)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/file.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule File do\n  @moduledoc ~S\"\"\"\n  This module contains functions to manipulate files.\n\n  Some of those functions are low-level, allowing the user\n  to interact with files or IO devices, like `open/2`,\n  `copy/3` and others. This module also provides higher\n  level functions that work with filenames and have their naming\n  based on Unix variants. For example, one can copy a file\n  via `cp/3` and remove files and directories recursively\n  via `rm_rf/1`.\n\n  Paths given to functions in this module can be either relative to the\n  current working directory (as returned by `File.cwd/0`), or absolute\n  paths. Shell conventions like `~` are not expanded automatically.\n  To use paths like `~/Downloads`, you can use `Path.expand/1` or\n  `Path.expand/2` to expand your path to an absolute path.\n\n  ## Encoding\n\n  In order to write and read files, one must use the functions\n  in the `IO` module. By default, a file is opened in binary mode,\n  which requires the functions `IO.binread/2` and `IO.binwrite/2`\n  to interact with the file. A developer may pass `:utf8` as an\n  option when opening the file, then the slower `IO.read/2` and\n  `IO.write/2` functions must be used as they are responsible for\n  doing the proper conversions and providing the proper data guarantees.\n\n  Note that filenames when given as charlists in Elixir are\n  always treated as UTF-8. In particular, we expect that the\n  shell and the operating system are configured to use UTF-8\n  encoding. Binary filenames are considered raw and passed\n  to the operating system as is.\n\n  ## API\n\n  Most of the functions in this module return `:ok` or\n  `{:ok, result}` in case of success, `{:error, reason}`\n  otherwise. Those functions also have a variant\n  that ends with `!` which returns the result (instead of the\n  `{:ok, result}` tuple) in case of success or raises an\n  exception in case it fails. For example:\n\n      File.read(\"hello.txt\")\n      #=> {:ok, \"World\"}\n\n      File.read(\"invalid.txt\")\n      #=> {:error, :enoent}\n\n      File.read!(\"hello.txt\")\n      #=> \"World\"\n\n      File.read!(\"invalid.txt\")\n      #=> raises File.Error\n\n  In general, a developer should use the former in case they want\n  to react if the file does not exist. The latter should be used\n  when the developer expects their software to fail in case the\n  file cannot be read (i.e. it is literally an exception).\n\n  ## Processes and raw files\n\n  Every time a file is opened, Elixir spawns a new process. Writing\n  to a file is equivalent to sending messages to the process that\n  writes to the file descriptor.\n\n  This means files can be passed between nodes and message passing\n  guarantees they can write to the same file in a network.\n\n  However, you may not always want to pay the price for this abstraction.\n  In such cases, a file can be opened in `:raw` mode. The options `:read_ahead`\n  and `:delayed_write` are also useful when operating on large files or\n  working with files in tight loops.\n\n  Check `:file.open/2` for more information about such options and\n  other performance considerations.\n\n  ## Seeking within a file\n\n  You may also use any of the functions from the [`:file`](`:file`)\n  module to interact with files returned by Elixir. For example,\n  to read from a specific position in a file, use `:file.pread/3`:\n\n      File.write!(\"example.txt\", \"Eats, Shoots & Leaves\")\n      file = File.open!(\"example.txt\")\n      :file.pread(file, 15, 6)\n      #=> {:ok, \"Leaves\"}\n\n  Alternatively, if you need to keep track of the current position,\n  use `:file.position/2` and `:file.read/2`:\n\n      :file.position(file, 6)\n      #=> {:ok, 6}\n      :file.read(file, 6)\n      #=> {:ok, \"Shoots\"}\n      :file.position(file, {:cur, -12})\n      #=> {:ok, 0}\n      :file.read(file, 4)\n      #=> {:ok, \"Eats\"}\n  \"\"\"\n\n  @type posix :: :file.posix()\n  @type io_device :: :file.io_device()\n  @type file_descriptor :: :file.fd()\n  @type stat_options :: [time: :local | :universal | :posix]\n  @type mode ::\n          :append\n          | :binary\n          | :charlist\n          | :compressed\n          | :delayed_write\n          | :exclusive\n          | :raw\n          | :read\n          | :read_ahead\n          | :sync\n          | :write\n          | {:read_ahead, pos_integer}\n          | {:delayed_write, non_neg_integer, non_neg_integer}\n          | encoding_mode()\n\n  @type encoding_mode ::\n          :utf8\n          | {\n              :encoding,\n              :latin1\n              | :unicode\n              | :utf8\n              | :utf16\n              | :utf32\n              | {:utf16, :big | :little}\n              | {:utf32, :big | :little}\n            }\n\n  @type stream_mode ::\n          encoding_mode()\n          | read_offset_mode()\n          | :append\n          | :compressed\n          | :delayed_write\n          | :trim_bom\n          | {:read_ahead, pos_integer | false}\n          | {:delayed_write, non_neg_integer, non_neg_integer}\n\n  @type read_offset_mode :: {:read_offset, non_neg_integer()}\n\n  @type erlang_time ::\n          {{year :: non_neg_integer(), month :: 1..12, day :: 1..31},\n           {hour :: 0..23, minute :: 0..59, second :: 0..59}}\n\n  @type posix_time :: integer()\n\n  @type on_conflict_callback :: (Path.t(), Path.t() -> boolean)\n\n  @doc \"\"\"\n  Returns `true` if the path is a regular file.\n\n  This function follows symbolic links, so if a symbolic link points to a\n  regular file, `true` is returned.\n\n  ## Options\n\n  The supported options are:\n\n    * `:raw` - a single atom to bypass the file server and only check\n      for the file locally\n\n  ## Examples\n\n      File.regular?(__ENV__.file)\n      #=> true\n\n  \"\"\"\n  @spec regular?(Path.t(), [regular_option]) :: boolean\n        when regular_option: :raw\n  def regular?(path, opts \\\\ []) do\n    :elixir_utils.read_file_type(IO.chardata_to_string(path), opts) == {:ok, :regular}\n  end\n\n  @doc \"\"\"\n  Returns `true` if the given path is a directory.\n\n  This function follows symbolic links, so if a symbolic link points to a\n  directory, `true` is returned.\n\n  ## Options\n\n  The supported options are:\n\n    * `:raw` - a single atom to bypass the file server and only check\n      for the file locally\n\n  ## Examples\n\n      File.dir?(\"./test\")\n      #=> true\n\n      File.dir?(\"test\")\n      #=> true\n\n      File.dir?(\"/usr/bin\")\n      #=> true\n\n      File.dir?(\"~/Downloads\")\n      #=> false\n\n      \"~/Downloads\" |> Path.expand() |> File.dir?()\n      #=> true\n\n  \"\"\"\n  @spec dir?(Path.t(), [dir_option]) :: boolean\n        when dir_option: :raw\n  def dir?(path, opts \\\\ []) do\n    :elixir_utils.read_file_type(IO.chardata_to_string(path), opts) == {:ok, :directory}\n  end\n\n  @doc \"\"\"\n  Returns `true` if the given path exists.\n\n  It can be a regular file, directory, socket, symbolic link, named pipe, or device file.\n  Returns `false` for symbolic links pointing to non-existing targets.\n\n  ## Options\n\n  The supported options are:\n\n    * `:raw` - a single atom to bypass the file server and only check\n      for the file locally\n\n  ## Examples\n\n      File.exists?(\"test/\")\n      #=> true\n\n      File.exists?(\"missing.txt\")\n      #=> false\n\n      File.exists?(\"/dev/null\")\n      #=> true\n\n  \"\"\"\n  @spec exists?(Path.t(), [exists_option]) :: boolean\n        when exists_option: :raw\n  def exists?(path, opts \\\\ []) do\n    opts = [{:time, :posix}] ++ opts\n    match?({:ok, _}, :file.read_file_info(IO.chardata_to_string(path), opts))\n  end\n\n  @doc \"\"\"\n  Tries to create the directory `path`.\n\n  Missing parent directories are not created.\n  Returns `:ok` if successful, or `{:error, reason}` if an error occurs.\n\n  Typical error reasons are:\n\n    * `:eacces`  - missing search or write permissions for the parent\n      directories of `path`\n    * `:eexist`  - there is already a file or directory named `path`\n    * `:enoent`  - a component of `path` does not exist\n    * `:enospc`  - there is no space left on the device\n    * `:enotdir` - a component of `path` is not a directory;\n      on some platforms, `:enoent` is returned instead\n\n  ## Examples\n\n      File.mkdir(\"test/unit\")\n      #=> :ok\n\n      File.mkdir(\"non/existing\")\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec mkdir(Path.t()) :: :ok | {:error, posix | :badarg}\n  def mkdir(path) do\n    :file.make_dir(IO.chardata_to_string(path))\n  end\n\n  @doc \"\"\"\n  Same as `mkdir/1`, but raises a `File.Error` exception in case of failure.\n  Otherwise `:ok`.\n\n  ## Examples\n\n      File.mkdir!(\"test/unit\")\n      #=> :ok\n\n      File.mkdir!(\"non/existing\")\n      ** (File.Error) could not make directory \"non/existing\": no such file or directory\n  \"\"\"\n  @spec mkdir!(Path.t()) :: :ok\n  def mkdir!(path) do\n    case mkdir(path) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"make directory\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Tries to create the directory `path`.\n\n  Missing parent directories are created. Returns `:ok` if successful, or\n  `{:error, reason}` if an error occurs.\n\n  Typical error reasons are:\n\n    * `:eacces`  - missing search or write permissions for the parent\n      directories of `path`\n    * `:enospc`  - there is no space left on the device\n    * `:enotdir` - a component of `path` is not a directory\n    * `:eperm`   - missed required permissions\n\n  ## Examples\n\n      File.mkdir_p(\"non/existing/parents\")\n      #=> :ok\n\n      File.mkdir_p(\"/usr/sbin/temp\")\n      #=> {:error, :eperm}\n  \"\"\"\n  @spec mkdir_p(Path.t()) :: :ok | {:error, posix | :badarg}\n  def mkdir_p(path) do\n    do_mkdir_p(IO.chardata_to_string(path))\n  end\n\n  defp do_mkdir_p(\"/\") do\n    :ok\n  end\n\n  defp do_mkdir_p(path) do\n    parent = Path.dirname(path)\n\n    if parent == path do\n      :ok\n    else\n      case do_mkdir_p(parent) do\n        :ok ->\n          case :file.make_dir(path) do\n            {:error, :eexist} ->\n              if dir?(path), do: :ok, else: {:error, :enotdir}\n\n            other ->\n              other\n          end\n\n        e ->\n          e\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Same as `mkdir_p/1`, but raises a `File.Error` exception in case of failure.\n  Otherwise `:ok`.\n\n  ## Examples\n\n      File.mkdir_p!(\"non/existing/parents\")\n      #=> :ok\n\n      File.mkdir_p!(\"/usr/sbin/temp\")\n      ** (File.Error) could not make directory (with -p) \"/usr/sbin/temp\": not owner\n  \"\"\"\n  @spec mkdir_p!(Path.t()) :: :ok\n  def mkdir_p!(path) do\n    case mkdir_p(path) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"make directory (with -p)\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Returns `{:ok, binary}`, where `binary` is a binary data object that contains the contents\n  of `path`, or `{:error, reason}` if an error occurs.\n\n  Typical error reasons:\n\n    * `:enoent`  - the file does not exist\n    * `:eacces`  - missing permission for reading the file,\n      or for searching one of the parent directories\n    * `:eisdir`  - the named file is a directory\n    * `:enotdir` - a component of the file name is not a directory;\n      on some platforms, `:enoent` is returned instead\n    * `:enomem`  - there is not enough memory for the contents of the file\n\n  You can use `:file.format_error/1` to get a descriptive string of the error.\n\n  ## Options (since v1.20)\n\n  The supported options are:\n\n    * `:raw` - a single atom to bypass the file server and only check\n      for the file locally\n\n  ## Examples\n\n      File.read(\"hello.txt\")\n      #=> {:ok, \"world\"}\n\n      File.read(\"non_existing.txt\")\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec read(Path.t(), [exists_option]) ::\n          {:ok, binary} | {:error, posix | :badarg | :terminated | :system_limit}\n        when exists_option: :raw\n  def read(path, opts \\\\ []) do\n    :file.read_file(IO.chardata_to_string(path), opts)\n  end\n\n  @doc \"\"\"\n  Returns a binary with the contents of the given filename,\n  or raises a `File.Error` exception if an error occurs.\n\n  ## Options (since v1.20)\n\n  The supported options are:\n\n    * `:raw` - a single atom to bypass the file server and only check\n      for the file locally\n\n  ## Examples\n\n      File.read!(\"hello.txt\")\n      #=> \"world\"\n\n      File.read!(\"non_existing.txt\")\n      ** (File.Error) could not read file \"non_existing.txt\": no such file or directory\n  \"\"\"\n  @spec read!(Path.t(), [exists_option]) :: binary when exists_option: :raw\n  def read!(path, opts \\\\ []) do\n    case read(path, opts) do\n      {:ok, binary} ->\n        binary\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"read file\", path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Returns information about the `path`. If it exists, it\n  returns a `{:ok, info}` tuple, where info is a\n  `File.Stat` struct. Returns `{:error, reason}` with\n  the same reasons as `read/1` if a failure occurs.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:time` - configures how the file timestamps are returned\n\n  The values for `:time` can be:\n\n    * `:universal` - returns a `{date, time}` tuple in UTC (default)\n    * `:local` - returns a `{date, time}` tuple using the same time zone as the\n      machine\n    * `:posix` - returns the time as integer seconds since epoch\n\n  Note: Since file times are stored in POSIX time format on most operating systems,\n  it is faster to retrieve file information with the `time: :posix` option.\n\n  ## Examples\n\n      File.stat(\"hello.txt\")\n      #=> {:ok, %File.Stat{...}}\n\n      File.stat(\"non_existing.txt\", time: :posix)\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec stat(Path.t(), stat_options) :: {:ok, File.Stat.t()} | {:error, posix | :badarg}\n  def stat(path, opts \\\\ []) do\n    opts = Keyword.put_new(opts, :time, :universal)\n\n    case :file.read_file_info(IO.chardata_to_string(path), opts) do\n      {:ok, fileinfo} ->\n        {:ok, File.Stat.from_record(fileinfo)}\n\n      error ->\n        error\n    end\n  end\n\n  @doc \"\"\"\n  Same as `stat/2` but returns the `File.Stat` directly,\n  or raises a `File.Error` exception if an error is returned.\n\n  ## Examples\n\n      File.stat!(\"hello.txt\")\n      #=> %File.Stat{...}\n\n      File.stat!(\"non_existing.txt\", time: :posix)\n      ** (File.Error) could not read file stats \"non_existing.txt\": no such file or directory\n  \"\"\"\n  @spec stat!(Path.t(), stat_options) :: File.Stat.t()\n  def stat!(path, opts \\\\ []) do\n    case stat(path, opts) do\n      {:ok, info} ->\n        info\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"read file stats\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Returns information about the `path`. If the file is a symlink, sets\n  the `type` to `:symlink` and returns a `File.Stat` struct for the link. For any\n  other file, returns exactly the same values as `stat/2`.\n\n  For more details, see `:file.read_link_info/2`.\n\n  ## Options\n\n  The accepted options are:\n\n    * `:time` - configures how the file timestamps are returned\n\n  The values for `:time` can be:\n\n    * `:universal` - returns a `{date, time}` tuple in UTC (default)\n    * `:local` - returns a `{date, time}` tuple using the machine time\n    * `:posix` - returns the time as integer seconds since epoch\n\n  Note: Since file times are stored in POSIX time format on most operating systems,\n  it is faster to retrieve file information with the `time: :posix` option.\n\n  ## Examples\n\n      File.lstat(\"link_to_hello\")\n      #=> {:ok, %File.Stat{type: :symlink, ...}}\n\n      File.lstat(\"non_existing.txt\", time: :posix)\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec lstat(Path.t(), stat_options) :: {:ok, File.Stat.t()} | {:error, posix | :badarg}\n  def lstat(path, opts \\\\ []) do\n    opts = Keyword.put_new(opts, :time, :universal)\n\n    case :file.read_link_info(IO.chardata_to_string(path), opts) do\n      {:ok, fileinfo} ->\n        {:ok, File.Stat.from_record(fileinfo)}\n\n      error ->\n        error\n    end\n  end\n\n  @doc \"\"\"\n  Same as `lstat/2` but returns the `File.Stat` struct directly,\n  or raises a `File.Error` exception if an error is returned.\n\n  ## Examples\n\n      File.lstat!(\"link_to_hello\")\n      #=> %File.Stat{type: :symlink, ...}\n\n      File.lstat!(\"non_existing.txt\", time: :posix)\n      ** (File.Error) could not read file stats \"non_existing.txt\": no such file or directory\n  \"\"\"\n  @spec lstat!(Path.t(), stat_options) :: File.Stat.t()\n  def lstat!(path, opts \\\\ []) do\n    case lstat(path, opts) do\n      {:ok, info} ->\n        info\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"read file stats\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Reads the symbolic link at `path`.\n\n  If `path` exists and is a symlink, returns `{:ok, target}`, otherwise returns\n  `{:error, reason}`.\n\n  For more details, see `:file.read_link/1`.\n\n  Typical error reasons are:\n\n    * `:einval` - path is not a symbolic link\n    * `:enoent` - path does not exist\n    * `:enotsup` - symbolic links are not supported on the current platform\n\n  ## Examples\n\n      File.read_link(\"link_to_hello\")\n      #=> {:ok, \"hello.txt\"}\n\n      File.read_link(\"hello.txt\")\n      #=> {:error, :einval}\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec read_link(Path.t()) :: {:ok, binary} | {:error, posix | :badarg}\n  def read_link(path) do\n    case path |> IO.chardata_to_string() |> :file.read_link() do\n      {:ok, target} -> {:ok, IO.chardata_to_string(target)}\n      error -> error\n    end\n  end\n\n  @doc \"\"\"\n  Same as `read_link/1` but returns the target directly,\n  or raises a `File.Error` exception if an error is returned.\n\n  ## Examples\n\n      File.read_link!(\"link_to_hello\")\n      #=> \"hello.txt\"\n\n      File.read_link!(\"hello.txt\")\n      ** (File.Error) could not read link \"hello.txt\": invalid argument\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec read_link!(Path.t()) :: binary\n  def read_link!(path) do\n    case read_link(path) do\n      {:ok, resolved} ->\n        resolved\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"read link\", path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Writes the given `File.Stat` back to the file system at the given\n  path. Returns `:ok` or `{:error, reason}`.\n\n  ## Examples\n\n      File.write_stat(\"hello.txt\", new_stat)\n      #=> :ok\n\n      File.write_stat(\"non_existing.txt\", new_stat)\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec write_stat(Path.t(), File.Stat.t(), stat_options) :: :ok | {:error, posix | :badarg}\n  def write_stat(path, stat, opts \\\\ []) do\n    opts = Keyword.put_new(opts, :time, :universal)\n    :file.write_file_info(IO.chardata_to_string(path), File.Stat.to_record(stat), opts)\n  end\n\n  @doc \"\"\"\n  Same as `write_stat/3` but raises a `File.Error` exception if it fails.\n  Returns `:ok` otherwise.\n\n  ## Examples\n\n      File.write_stat!(\"hello.txt\", new_stat)\n      #=> :ok\n\n      File.write_stat!(\"non_existing.txt\", new_stat)\n      ** (File.Error) could not write file stats \"non_existing.txt\": no such file or directory\n  \"\"\"\n  @spec write_stat!(Path.t(), File.Stat.t(), stat_options) :: :ok\n  def write_stat!(path, stat, opts \\\\ []) do\n    case write_stat(path, stat, opts) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"write file stats\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Updates modification time (mtime) and access time (atime) of\n  the given file.\n\n  The file is created if it doesn't exist. Requires datetime in UTC\n  (as returned by `:erlang.universaltime()`) or an integer\n  representing the POSIX timestamp (as returned by `System.os_time(:second)`).\n\n  In Unix-like systems, changing the modification time may require\n  you to be either `root` or the owner of the file. Having write\n  access may not be enough. In those cases, touching the file the\n  first time (to create it) will succeed, but touching an existing\n  file with fail with `{:error, :eperm}`.\n\n  ## Examples\n\n      File.touch(\"/tmp/a.txt\", {{2018, 1, 30}, {13, 59, 59}})\n      #=> :ok\n      File.touch(\"/fakedir/b.txt\", {{2018, 1, 30}, {13, 59, 59}})\n      {:error, :enoent}\n\n      File.touch(\"/tmp/a.txt\", 1_544_519_753)\n      #=> :ok\n\n  \"\"\"\n  @spec touch(Path.t(), erlang_time() | posix_time()) ::\n          :ok | {:error, posix | :badarg | :terminated | :system_limit}\n  def touch(path, time \\\\ System.os_time(:second))\n\n  def touch(path, time) when is_tuple(time) do\n    path = IO.chardata_to_string(path)\n\n    with {:error, :enoent} <- :elixir_utils.change_universal_time(path, time),\n         :ok <- write(path, \"\", [:raw, :append]),\n         do: :elixir_utils.change_universal_time(path, time)\n  end\n\n  def touch(path, time) when is_integer(time) do\n    path = IO.chardata_to_string(path)\n\n    with {:error, :enoent} <- :elixir_utils.change_posix_time(path, time),\n         :ok <- write(path, \"\", [:raw, :append]),\n         do: :elixir_utils.change_posix_time(path, time)\n  end\n\n  @doc \"\"\"\n  Same as `touch/2` but raises a `File.Error` exception if it fails.\n  Returns `:ok` otherwise.\n\n  The file is created if it doesn't exist. Requires datetime in UTC\n  (as returned by `:erlang.universaltime()`) or an integer\n  representing the POSIX timestamp (as returned by `System.os_time(:second)`).\n\n  ## Examples\n\n      File.touch!(\"/tmp/a.txt\", {{2018, 1, 30}, {13, 59, 59}})\n      #=> :ok\n      File.touch!(\"/fakedir/b.txt\", {{2018, 1, 30}, {13, 59, 59}})\n      ** (File.Error) could not touch \"/fakedir/b.txt\": no such file or directory\n\n      File.touch!(\"/tmp/a.txt\", 1_544_519_753)\n\n  \"\"\"\n  @spec touch!(Path.t(), erlang_time() | posix_time()) :: :ok\n  def touch!(path, time \\\\ System.os_time(:second)) do\n    case touch(path, time) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"touch\", path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Creates a hard link `new` to the file `existing`.\n\n  Returns `:ok` if successful, `{:error, reason}` otherwise.\n  If the operating system does not support hard links, returns\n  `{:error, :enotsup}`.\n\n  ## Examples\n\n      File.ln(\"hello.txt\", \"hard_link_to_hello\")\n      #=> :ok\n\n      File.ln(\"non_existing.txt\", \"link\")\n      #=> {:error, :enoent}\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec ln(Path.t(), Path.t()) :: :ok | {:error, posix | :badarg}\n  def ln(existing, new) do\n    :file.make_link(IO.chardata_to_string(existing), IO.chardata_to_string(new))\n  end\n\n  @doc \"\"\"\n  Same as `ln/2` but raises a `File.LinkError` exception if it fails.\n  Returns `:ok` otherwise.\n\n  ## Examples\n\n      File.ln!(\"hello.txt\", \"hard_link_to_hello\")\n      #=> :ok\n\n      File.ln!(\"non_existing.txt\", \"link\")\n      ** (File.LinkError) could not create hard link from \"non_existing.txt\" to \"link\": no such file or directory\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec ln!(Path.t(), Path.t()) :: :ok\n  def ln!(existing, new) do\n    case ln(existing, new) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.LinkError,\n          reason: reason,\n          action: \"create hard link\",\n          existing: IO.chardata_to_string(existing),\n          new: IO.chardata_to_string(new)\n    end\n  end\n\n  @doc \"\"\"\n  Creates a symbolic link `new` to the file or directory `existing`.\n\n  Returns `:ok` if successful, `{:error, reason}` otherwise.\n  If the operating system does not support symlinks, returns\n  `{:error, :enotsup}`.\n\n  Creates a symlink even if the `existing` target actually doesn't exist\n\n  ## Examples\n\n      File.ln_s(\"hello.txt\", \"link_to_hello\")\n      #=> :ok\n\n      File.ln_s(\"non_existing.txt\", \"link\")\n      #=> :ok\n\n      # Returns error if `new` file exists\n      File.ln_s(\"non_existing.txt\", \"existed_link\")\n      #=> {:error, :eexist}\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec ln_s(Path.t(), Path.t()) :: :ok | {:error, posix | :badarg}\n  def ln_s(existing, new) do\n    :file.make_symlink(IO.chardata_to_string(existing), IO.chardata_to_string(new))\n  end\n\n  @doc \"\"\"\n  Same as `ln_s/2` but raises a `File.LinkError` exception if it fails.\n  Returns `:ok` otherwise.\n\n  ## Examples\n\n      File.ln_s!(\"hello.txt\", \"link_to_hello\")\n      #=> :ok\n\n      # Raises if `new` file exists\n      File.ln_s!(\"non_existing.txt\", \"existed_link\")\n      ** (File.LinkError) could not create symlink from \"non_existing.txt\" to \"existed_link\": file already exists\n  \"\"\"\n  @spec ln_s!(Path.t(), Path.t()) :: :ok\n  def ln_s!(existing, new) do\n    case ln_s(existing, new) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.LinkError,\n          reason: reason,\n          action: \"create symlink\",\n          existing: IO.chardata_to_string(existing),\n          new: IO.chardata_to_string(new)\n    end\n  end\n\n  @doc \"\"\"\n  Copies the contents of `source` to `destination`.\n\n  Both parameters can be a filename or an IO device opened\n  with `open/2`. `bytes_count` specifies the number of\n  bytes to copy, the default being `:infinity`.\n\n  If file `destination` already exists, it is overwritten\n  by the contents in `source`.\n\n  Returns `{:ok, bytes_copied}` if successful,\n  `{:error, reason}` otherwise.\n\n  Compared to the `cp/3`, this function is more low-level,\n  allowing a copy from device to device limited by a number of\n  bytes. On the other hand, `cp/3` performs more extensive\n  checks on both source and destination and it also preserves\n  the file mode after copy.\n\n  Typical error reasons are the same as in `open/2`,\n  `read/1` and `write/3`.\n\n  ## Examples\n\n      File.copy(\"hello.txt\", \"hello_copy.txt\")\n      #=> {:ok, 6}\n\n      File.copy(\"non_existing.txt\", \"copy.txt\")\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec copy(Path.t() | io_device, Path.t() | io_device, pos_integer | :infinity) ::\n          {:ok, non_neg_integer} | {:error, posix | :badarg | :terminated}\n  def copy(source, destination, bytes_count \\\\ :infinity) do\n    source = normalize_path_or_io_device(source)\n    destination = normalize_path_or_io_device(destination)\n\n    :file.copy(source, destination, bytes_count)\n  end\n\n  @doc \"\"\"\n  The same as `copy/3` but raises a `File.CopyError` exception if it fails.\n  Returns the `bytes_copied` otherwise.\n\n  ## Examples\n\n      File.copy!(\"hello.txt\", \"hello_copy.txt\")\n      #=> 6\n\n      File.copy!(\"non_existing.txt\", \"copy.txt\")\n      ** (File.CopyError) could not copy from \"non_existing.txt\" to \"copy.txt\": no such file or directory\n  \"\"\"\n  @spec copy!(Path.t() | io_device, Path.t() | io_device, pos_integer | :infinity) ::\n          non_neg_integer\n  def copy!(source, destination, bytes_count \\\\ :infinity) do\n    case copy(source, destination, bytes_count) do\n      {:ok, bytes_count} ->\n        bytes_count\n\n      {:error, reason} ->\n        raise File.CopyError,\n          reason: reason,\n          action: \"copy\",\n          source: normalize_path_or_io_device(source),\n          destination: normalize_path_or_io_device(destination)\n    end\n  end\n\n  @doc \"\"\"\n  Renames the `source` file to `destination` file.  It can be used to move files\n  (and directories) between directories.  If moving a file, you must fully\n  specify the `destination` filename, it is not sufficient to simply specify\n  its directory.\n\n  Returns `:ok` in case of success, `{:error, reason}` otherwise.\n\n  Note: The command `mv` in Unix-like systems behaves differently depending on\n  whether `source` is a file and the `destination` is an existing directory.\n  We have chosen to explicitly disallow this behavior.\n\n  ## Examples\n\n      # Rename file \"a.txt\" to \"b.txt\"\n      File.rename(\"a.txt\", \"b.txt\")\n      #=> :ok\n\n      # Rename directory \"samples\" to \"tmp\"\n      File.rename(\"samples\", \"tmp\")\n      #=> :ok\n\n      File.rename(\"non_existing.txt\", \"existing.txt\")\n      #=> {:error, :enoent}\n  \"\"\"\n  @doc since: \"1.1.0\"\n  @spec rename(Path.t(), Path.t()) :: :ok | {:error, posix | :badarg}\n  def rename(source, destination) do\n    source = IO.chardata_to_string(source)\n    destination = IO.chardata_to_string(destination)\n    :file.rename(source, destination)\n  end\n\n  @doc \"\"\"\n  The same as `rename/2` but raises a `File.RenameError` exception if it fails.\n  Returns `:ok` otherwise.\n\n  ## Examples\n\n      File.rename!(\"samples\", \"tmp\")\n      #=> :ok\n\n      File.rename!(\"non_existing.txt\", \"existing.txt\")\n      ** (File.RenameError) could not rename from \"non_existing.txt\" to \"existing.txt\": no such file or directory\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec rename!(Path.t(), Path.t()) :: :ok\n  def rename!(source, destination) do\n    case rename(source, destination) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.RenameError,\n          reason: reason,\n          action: \"rename\",\n          source: IO.chardata_to_string(source),\n          destination: IO.chardata_to_string(destination)\n    end\n  end\n\n  @doc ~S\"\"\"\n  Copies the contents of `source_file` to `destination_file` preserving its modes.\n\n  `source_file` must be a file or a symbolic link to one. `destination_file` must\n  be a path to a non-existent file. If either is a directory, `{:error, :eisdir}`\n  will be returned.\n\n  The function returns `:ok` in case of success. Otherwise, it returns\n  `{:error, reason}`.\n\n  If you want to copy contents from an IO device to another device\n  or do a straight copy from a source to a destination without\n  preserving modes, check `copy/3` instead.\n\n  Note: The command `cp` in Unix-like systems behaves differently depending on\n  whether the destination is an existing directory or not. We have chosen to\n  explicitly disallow copying to a destination which is a directory,\n  and an error will be returned if tried.\n\n  ## Options\n\n    * `:on_conflict` - (since v1.14.0) Invoked when a file already exists in the destination.\n      The function receives arguments for `source_file` and `destination_file`. It should\n      return `true` if the existing file should be overwritten, `false` if otherwise.\n      The default callback returns `true`. On earlier versions, this callback could be\n      given as third argument, but such behavior is now deprecated.\n\n  ## Examples\n\n      File.cp(\"hello.txt\", \"hello_copy.txt\")\n      #=> :ok\n\n      File.cp(\"hello.txt\", \"hello_copy.txt\", on_conflict: fn source, destination ->\n        IO.gets(\"Overwriting #{destination} by #{source}. Type y to confirm. \") == \"y\\n\"\n      end)\n      #=> :ok\n\n      File.cp(\"non_existing.txt\", \"copy.txt\")\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec cp(Path.t(), Path.t(), on_conflict: on_conflict_callback) ::\n          :ok | {:error, posix | :badarg | :terminated}\n  def cp(source_file, destination_file, options \\\\ [])\n\n  # TODO: Deprecate me on Elixir v1.19\n  def cp(source_file, destination_file, callback) when is_function(callback, 2) do\n    IO.warn_once(\n      {__MODULE__, :cp},\n      fn ->\n        \"passing a callback to File.cp/3 is deprecated, pass it as a on_conflict: callback option instead\"\n      end,\n      3\n    )\n\n    cp(source_file, destination_file, on_conflict: callback)\n  end\n\n  def cp(source_file, destination_file, options) when is_list(options) do\n    on_conflict = Keyword.get(options, :on_conflict, fn _, _ -> true end)\n    source_file = IO.chardata_to_string(source_file)\n    destination_file = IO.chardata_to_string(destination_file)\n\n    case do_cp_file(source_file, destination_file, on_conflict, []) do\n      {:error, reason, _} -> {:error, reason}\n      _ -> :ok\n    end\n  end\n\n  defp path_differs?(path, path), do: false\n\n  defp path_differs?(p1, p2) do\n    Path.expand(p1) !== Path.expand(p2)\n  end\n\n  @doc ~S\"\"\"\n  The same as `cp/3`, but raises a `File.CopyError` exception if it fails.\n  Returns `:ok` otherwise.\n\n  ## Examples\n\n      File.cp!(\"hello.txt\", \"hello_copy.txt\")\n      #=> :ok\n\n      File.cp!(\"hello.txt\", \"hello_copy.txt\", on_conflict: fn source, destination ->\n        IO.gets(\"Overwriting #{destination} by #{source}. Type y to confirm. \") == \"y\\n\"\n      end)\n      #=> :ok\n\n      File.cp!(\"non_existing.txt\", \"copy.txt\")\n      ** (File.CopyError) could not copy from \"non_existing.txt\" to \"copy.txt\": no such file or directory\n  \"\"\"\n  @spec cp!(Path.t(), Path.t(), on_conflict: on_conflict_callback) :: :ok\n  def cp!(source_file, destination_file, options \\\\ []) do\n    case cp(source_file, destination_file, options) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.CopyError,\n          reason: reason,\n          action: \"copy\",\n          source: IO.chardata_to_string(source_file),\n          destination: IO.chardata_to_string(destination_file)\n    end\n  end\n\n  @doc ~S\"\"\"\n  Copies the contents in `source` to `destination` recursively, maintaining the\n  source directory structure and modes.\n\n  If `source` is a file or a symbolic link to it, `destination` must be a path\n  to an existent file, a symbolic link to one, or a path to a non-existent file.\n\n  If `source` is a directory, or a symbolic link to it, then `destination` must\n  be an existent `directory` or a symbolic link to one, or a path to a non-existent directory.\n\n  If the source is a file, it copies `source` to `destination`. If the `source`\n  is a directory, it copies the contents inside source into the `destination` directory.\n\n  If a file already exists in the destination, it invokes the optional `on_conflict`\n  callback given as an option. See \"Options\" for more information.\n\n  This function may fail while copying files, in such cases, it will leave the\n  destination directory in a dirty state, where file which have already been\n  copied won't be removed.\n\n  The function returns `{:ok, files_and_directories}` in case of\n  success, `files_and_directories` lists all files and directories copied in no\n  specific order. It returns `{:error, reason, file}` otherwise.\n\n  Note: The command `cp` in Unix-like systems behaves differently depending on\n  whether `destination` is an existing directory or not. We have chosen to\n  explicitly disallow this behavior. If `source` is a `file` and `destination`\n  is a directory, `{:error, :eisdir}` will be returned.\n\n  Special files such as device files, sockets, and named pipes are not copied.\n\n  Typical error reasons are:\n\n    * `:enoent`  - `source` does not exist\n    * `:eisdir`  - `source` is a file and `destination` is a directory\n    * `:einval`  - `destination` is the same as or a subdirectory of `source`\n\n  ## Options\n\n    * `:on_conflict` - (since v1.14.0) Invoked when a file already exists in the destination.\n      The function receives arguments for `source` and `destination`. It should return\n      `true` if the existing file should be overwritten, `false` if otherwise. The default\n      callback returns `true`. On earlier versions, this callback could be given as third\n      argument, but such behavior is now deprecated.\n\n    * `:dereference_symlinks` - (since v1.14.0) By default, this function will copy symlinks\n      by creating symlinks that point to the same location. This option forces symlinks to be\n      dereferenced and have their contents copied instead when set to `true`. If the dereferenced\n      files do not exist, than the operation fails. The default is `false`.\n\n  ## Examples\n\n      # Copies file \"a.txt\" to \"b.txt\"\n      File.cp_r(\"a.txt\", \"b.txt\")\n      #=> {:ok, [\"b.txt\"]}\n\n      # Copies all files in \"samples\" to \"tmp\"\n      File.cp_r(\"samples\", \"tmp\")\n      #=> {:ok, [\"z.txt\", \"y.txt\", \"x.txt]}\n\n      # Same as before, but asks the user how to proceed in case of conflicts\n      File.cp_r(\"samples\", \"tmp\", on_conflict: fn source, destination ->\n        IO.gets(\"Overwriting #{destination} by #{source}. Type y to confirm. \") == \"y\\n\"\n      end)\n      #=> {:ok, [\"z.txt\", \"y.txt\", \"x.txt]}\n\n      File.cp_r(\"non_existing.txt\", \"copy.txt\")\n      #=> {:error, :enoent, \"non_existing.txt\"}\n\n      # Copying into a subdirectory of source is not allowed\n      File.cp_r(\"src\", \"src/dest\")\n      #=> {:error, :einval, \"src/dest\"}\n  \"\"\"\n  @spec cp_r(Path.t(), Path.t(),\n          on_conflict: on_conflict_callback,\n          dereference_symlinks: boolean()\n        ) ::\n          {:ok, [binary]} | {:error, posix | :badarg | :terminated, binary}\n\n  def cp_r(source, destination, options \\\\ [])\n\n  # TODO: Deprecate me on Elixir v1.19\n  def cp_r(source, destination, callback) when is_function(callback, 2) do\n    IO.warn_once(\n      {__MODULE__, :cp_r},\n      fn ->\n        \"passing a callback to File.cp_r/3 is deprecated, pass it as a on_conflict: callback option instead\"\n      end,\n      3\n    )\n\n    cp_r(source, destination, on_conflict: callback)\n  end\n\n  def cp_r(source, destination, options) when is_list(options) do\n    on_conflict = Keyword.get(options, :on_conflict, fn _, _ -> true end)\n    dereference? = Keyword.get(options, :dereference_symlinks, false)\n\n    source =\n      source\n      |> IO.chardata_to_string()\n      |> assert_no_null_byte!(\"File.cp_r/3\")\n\n    destination =\n      destination\n      |> IO.chardata_to_string()\n      |> assert_no_null_byte!(\"File.cp_r/3\")\n\n    source_parts = source |> Path.expand() |> Path.split()\n    dest_parts = destination |> Path.expand() |> Path.split()\n\n    if source_parts != dest_parts and List.starts_with?(dest_parts, source_parts) do\n      {:error, :einval, destination}\n    else\n      dereference = if dereference?, do: MapSet.new(), else: nil\n\n      case do_cp_r(source, destination, on_conflict, dereference, []) do\n        {:error, _, _} = error -> error\n        res -> {:ok, res}\n      end\n    end\n  end\n\n  @doc \"\"\"\n  The same as `cp_r/3`, but raises a `File.CopyError` exception if it fails.\n  Returns the list of copied files otherwise.\n\n  ## Examples\n\n      File.cp_r!(\"a.txt\", \"b.txt\")\n      #=> [\"b.txt\"]\n\n      File.cp_r!(\"samples\", \"tmp\")\n      #=> [\"z.txt\", \"y.txt\", \"x.txt]\n\n      File.cp_r!(\"non_existing.txt\", \"copy.txt\")\n      ** (File.CopyError) could not copy recursively from \"non_existing.txt\" to \"copy.txt\". non_existing.txt: no such file or directory\n  \"\"\"\n  @spec cp_r!(Path.t(), Path.t(),\n          on_conflict: on_conflict_callback,\n          dereference_symlinks: boolean()\n        ) :: [binary]\n  def cp_r!(source, destination, options \\\\ []) do\n    case cp_r(source, destination, options) do\n      {:ok, files} ->\n        files\n\n      {:error, reason, file} ->\n        raise File.CopyError,\n          reason: reason,\n          action: \"copy recursively\",\n          on: file,\n          source: IO.chardata_to_string(source),\n          destination: IO.chardata_to_string(destination)\n    end\n  end\n\n  defp do_cp_r(src, dest, on_conflict, dereference, acc) when is_list(acc) do\n    case :elixir_utils.read_link_type(src) do\n      {:ok, :regular} ->\n        case do_cp_file(src, dest, on_conflict, acc) do\n          # we don't have a way to make a distinction between a non-existing src\n          # or dest being a non-existing dir in the case of :enoent,\n          # but we already know that src exists here.\n          {:error, :enoent, _} -> {:error, :enoent, dest}\n          other -> other\n        end\n\n      {:ok, :symlink} ->\n        case :file.read_link(src) do\n          {:ok, link} when dereference != nil ->\n            resolved = Path.expand(link, Path.dirname(src))\n\n            if MapSet.member?(dereference, resolved) do\n              {:error, :eloop, src}\n            else\n              dereference = MapSet.put(dereference, resolved)\n              do_cp_r(resolved, dest, on_conflict, dereference, acc)\n            end\n\n          {:ok, link} ->\n            do_cp_link(link, src, dest, on_conflict, acc)\n\n          {:error, reason} ->\n            {:error, reason, src}\n        end\n\n      {:ok, :directory} ->\n        case :file.list_dir(src) do\n          {:ok, files} ->\n            case mkdir(dest) do\n              success when success in [:ok, {:error, :eexist}] ->\n                case copy_file_mode(src, dest) do\n                  :ok ->\n                    Enum.reduce_while(files, [dest | acc], fn x, acc ->\n                      case do_cp_r(\n                             Path.join(src, x),\n                             Path.join(dest, x),\n                             on_conflict,\n                             dereference,\n                             acc\n                           ) do\n                        {:error, _, _} = error -> {:halt, error}\n                        acc -> {:cont, acc}\n                      end\n                    end)\n\n                  {:error, reason} ->\n                    {:error, reason, src}\n                end\n\n              {:error, reason} ->\n                {:error, reason, dest}\n            end\n\n          {:error, reason} ->\n            {:error, reason, src}\n        end\n\n      {:ok, _} ->\n        acc\n\n      {:error, reason} ->\n        {:error, reason, src}\n    end\n  end\n\n  # If we reach this clause, there was an error while processing a file.\n  defp do_cp_r(_, _, _, _, acc) do\n    acc\n  end\n\n  defp copy_file_mode(src, dest) do\n    with {:ok, dest_fileinfo} <- stat(dest),\n         {:ok, src_fileinfo} <- stat(src) do\n      write_stat(dest, %{dest_fileinfo | mode: src_fileinfo.mode})\n    end\n  end\n\n  # Both src and dest are files.\n  defp do_cp_file(src, dest, on_conflict, acc) do\n    case :file.copy(src, {dest, [:exclusive]}) do\n      {:ok, _} ->\n        case copy_file_mode(src, dest) do\n          :ok ->\n            [dest | acc]\n\n          {:error, reason} ->\n            {:error, reason, src}\n        end\n\n      {:error, :eexist} ->\n        if path_differs?(src, dest) and on_conflict.(src, dest) do\n          case copy(src, dest) do\n            {:ok, _} ->\n              case copy_file_mode(src, dest) do\n                :ok ->\n                  [dest | acc]\n\n                {:error, reason} ->\n                  {:error, reason, src}\n              end\n\n            {:error, reason} ->\n              {:error, reason, src}\n          end\n        else\n          acc\n        end\n\n      {:error, reason} ->\n        {:error, reason, src}\n    end\n  end\n\n  # Both src and dest are files.\n  defp do_cp_link(link, src, dest, on_conflict, acc) do\n    case :file.make_symlink(link, dest) do\n      :ok ->\n        [dest | acc]\n\n      {:error, :eexist} ->\n        if path_differs?(src, dest) and on_conflict.(src, dest) do\n          # If rm/1 fails, :file.make_symlink/2 will fail\n          _ = rm(dest)\n\n          case :file.make_symlink(link, dest) do\n            :ok -> [dest | acc]\n            {:error, reason} -> {:error, reason, src}\n          end\n        else\n          acc\n        end\n\n      {:error, reason} ->\n        {:error, reason, src}\n    end\n  end\n\n  @doc \"\"\"\n  Writes `content` to the file `path`.\n\n  The file is created if it does not exist. If it exists, the previous\n  contents are overwritten. Returns `:ok` if successful, or `{:error, reason}`\n  if an error occurs.\n\n  `content` must be `iodata` (a list of bytes or a binary). Setting the\n  encoding for this function has no effect.\n\n  **Warning:** Every time this function is invoked, a file descriptor is opened\n  and a new process is spawned to write to the file. For this reason, if you are\n  doing multiple writes in a loop, opening the file via `File.open/2` and using\n  the functions in `IO` to write to the file will yield much better performance\n  than calling this function multiple times.\n\n  Typical error reasons are:\n\n    * `:enoent`  - a component of the file name does not exist\n    * `:enotdir` - a component of the file name is not a directory;\n      on some platforms, `:enoent` is returned instead\n    * `:enospc`  - there is no space left on the device\n    * `:eacces`  - missing permission for writing the file or searching one of\n      the parent directories\n    * `:eisdir`  - the named file is a directory\n\n  Check `File.open/2` for the list of available `modes`.\n\n  ## Examples\n\n      File.write(\"hello.txt\", \"world!\")\n      #=> :ok\n\n      File.write(\"temp\", \"world!\")\n      #=> {:error, :eisdir}\n\n  \"\"\"\n  @spec write(Path.t(), iodata, [mode]) ::\n          :ok | {:error, posix | :badarg | :terminated | :system_limit}\n  def write(path, content, modes \\\\ []) do\n    modes = normalize_modes(modes, false)\n    :file.write_file(IO.chardata_to_string(path), content, modes)\n  end\n\n  @doc \"\"\"\n  Same as `write/3` but raises a `File.Error` exception if it fails.\n  Returns `:ok` otherwise.\n\n  ## Examples\n\n      File.write!(\"hello.txt\", \"world!\")\n      #=> :ok\n\n      File.write!(\"temp\", \"world!\")\n      ** (File.Error) could not write to file \"temp\": illegal operation on a directory\n  \"\"\"\n  @spec write!(Path.t(), iodata, [mode]) :: :ok\n  def write!(path, content, modes \\\\ []) do\n    case write(path, content, modes) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"write to file\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Tries to delete the file `path`.\n\n  Returns `:ok` if successful, or `{:error, reason}` if an error occurs.\n\n  Note the file is deleted even if in read-only mode.\n\n  Typical error reasons are:\n\n    * `:enoent`  - the file does not exist\n    * `:eacces`  - missing permission for the file or one of its parents\n    * `:eperm`   - the file is a directory and user is not super-user\n    * `:enotdir` - a component of the file name is not a directory;\n      on some platforms, `:enoent` is returned instead\n    * `:einval`  - filename had an improper type, such as tuple\n\n  ## Examples\n\n      File.rm(\"file.txt\")\n      #=> :ok\n\n      File.rm(\"tmp_dir/\")\n      #=> {:error, :eperm}\n  \"\"\"\n  @spec rm(Path.t()) :: :ok | {:error, posix | :badarg}\n  def rm(path) do\n    path = IO.chardata_to_string(path)\n\n    case :file.delete(path) do\n      :ok ->\n        :ok\n\n      {:error, :eacces} = e ->\n        change_mode_windows(path) || e\n\n      {:error, _} = e ->\n        e\n    end\n  end\n\n  defp change_mode_windows(path) do\n    if match?({:win32, _}, :os.type()) do\n      case :file.read_file_info(path) do\n        {:ok, file_info} when elem(file_info, 3) in [:read, :none] ->\n          change_mode_windows(path, file_info)\n\n        _ ->\n          nil\n      end\n    end\n  end\n\n  defp change_mode_windows(path, file_info) do\n    case chmod(path, elem(file_info, 7) + 0o200) do\n      :ok -> :file.delete(path)\n      {:error, _reason} = error -> error\n    end\n  end\n\n  @doc \"\"\"\n  Same as `rm/1`, but raises a `File.Error` exception in case of failure.\n  Otherwise `:ok`.\n\n  ## Examples\n\n      File.rm!(\"file.txt\")\n      #=> :ok\n\n      File.rm!(\"non_existing/\")\n      ** (File.Error) could not remove file \"non_existing/\": no such file or directory\n  \"\"\"\n  @spec rm!(Path.t()) :: :ok\n  def rm!(path) do\n    case rm(path) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"remove file\", path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Tries to delete the dir at `path`.\n\n  Returns `:ok` if successful, or `{:error, reason}` if an error occurs.\n  It returns `{:error, :eexist}` if the directory is not empty.\n\n  ## Examples\n\n      File.rmdir(\"tmp_dir\")\n      #=> :ok\n\n      File.rmdir(\"non_empty_dir\")\n      #=> {:error, :eexist}\n\n      File.rmdir(\"file.txt\")\n      #=> {:error, :enotdir}\n  \"\"\"\n  @spec rmdir(Path.t()) :: :ok | {:error, posix | :badarg}\n  def rmdir(path) do\n    :file.del_dir(IO.chardata_to_string(path))\n  end\n\n  @doc \"\"\"\n  Same as `rmdir/1`, but raises a `File.Error` exception in case of failure.\n  Otherwise `:ok`.\n\n  ## Examples\n\n      File.rmdir!(\"tmp_dir\")\n      #=> :ok\n\n      File.rmdir!(\"non_empty_dir\")\n      ** (File.Error) could not remove directory \"non_empty_dir\": directory is not empty\n\n      File.rmdir!(\"file.txt\")\n      ** (File.Error) could not remove directory \"file.txt\": not a directory\n  \"\"\"\n  @spec rmdir!(Path.t()) :: :ok\n  def rmdir!(path) do\n    case rmdir(path) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"remove directory\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Removes files and directories recursively at the given `path`.\n  Symlinks are not followed but simply removed, non-existing\n  files are simply ignored (i.e. doesn't make this function fail).\n\n  Returns `{:ok, files_and_directories}` with all files and\n  directories removed in no specific order, `{:error, reason, file}`\n  otherwise.\n\n  ## Examples\n\n      File.rm_rf(\"samples\")\n      #=> {:ok, [\"samples\", \"samples/1.txt\"]}\n\n      File.rm_rf(\"unknown\")\n      #=> {:ok, []}\n\n      File.rm_rf(\"/tmp\")\n      #=> {:error, :eperm, \"/tmp\"}\n  \"\"\"\n  @spec rm_rf(Path.t()) :: {:ok, [binary]} | {:error, posix | :badarg, binary}\n  def rm_rf(path) do\n    {major, _} = :os.type()\n\n    path\n    |> IO.chardata_to_string()\n    |> assert_no_null_byte!(\"File.rm_rf/1\")\n    |> do_rm_rf([], major)\n  end\n\n  defp do_rm_rf(path, acc, major) do\n    case safe_list_dir(path, major) do\n      {:ok, files} when is_list(files) ->\n        acc =\n          Enum.reduce(files, acc, fn file, acc ->\n            # In case we can't delete, continue anyway, we might succeed\n            # to delete it on Windows due to how they handle symlinks.\n            case do_rm_rf(Path.join(path, file), acc, major) do\n              {:ok, acc} -> acc\n              {:error, _, _} -> acc\n            end\n          end)\n\n        case rmdir(path) do\n          :ok -> {:ok, [path | acc]}\n          {:error, :enoent} -> {:ok, acc}\n          {:error, reason} -> {:error, reason, path}\n        end\n\n      {:ok, :directory} ->\n        do_rm_directory(path, acc)\n\n      {:ok, :regular} ->\n        do_rm_regular(path, acc)\n\n      {:error, reason} when reason in [:enoent, :enotdir] ->\n        {:ok, acc}\n\n      {:error, reason} ->\n        {:error, reason, path}\n    end\n  end\n\n  defp do_rm_regular(path, acc) do\n    case rm(path) do\n      :ok -> {:ok, [path | acc]}\n      {:error, :enoent} -> {:ok, acc}\n      {:error, reason} -> {:error, reason, path}\n    end\n  end\n\n  # On Windows, symlinks are treated as directory and must be removed\n  # with rmdir/1. But on Unix-like systems, we remove them via rm/1.\n  # So we first try to remove it as a directory and, if we get :enotdir,\n  # we fall back to a file removal.\n  defp do_rm_directory(path, acc) do\n    case rmdir(path) do\n      :ok -> {:ok, [path | acc]}\n      {:error, :enotdir} -> do_rm_regular(path, acc)\n      {:error, :enoent} -> {:ok, acc}\n      {:error, reason} -> {:error, reason, path}\n    end\n  end\n\n  defp safe_list_dir(path, major) do\n    case :elixir_utils.read_link_type(path) do\n      {:ok, :directory} ->\n        # If we cannot read the files, try to delete it anyway\n        case :file.list_dir_all(path) do\n          {:ok, files} -> {:ok, files}\n          {:error, _} -> {:ok, :directory}\n        end\n\n      {:ok, :symlink} when major == :win32 ->\n        case :elixir_utils.read_file_type(path) do\n          {:ok, :directory} -> {:ok, :directory}\n          _ -> {:ok, :regular}\n        end\n\n      {:ok, _} ->\n        {:ok, :regular}\n\n      {:error, :eio} when major == :win32 ->\n        # unix domain socket returns `{:error, :eio}`\n        # on other platforms the result is `{:ok, :regular}`\n        {:ok, :regular}\n\n      {:error, reason} ->\n        {:error, reason}\n    end\n  end\n\n  @doc \"\"\"\n  Same as `rm_rf/1` but raises a `File.Error` exception in case of failures,\n  otherwise returns the list of files or directories removed.\n\n  ## Examples\n\n      File.rm_rf!(\"samples\")\n      #=> [\"samples\", \"samples/1.txt\"]\n\n      File.rm_rf!(\"unknown\")\n      #=> []\n\n      File.rm_rf!(\"/tmp\")\n      ** (File.Error) could not remove files and directories recursively from \"/tmp\": not owner\n  \"\"\"\n  @spec rm_rf!(Path.t()) :: [binary]\n  def rm_rf!(path) do\n    case rm_rf(path) do\n      {:ok, files} ->\n        files\n\n      {:error, reason, _} ->\n        raise File.Error,\n          reason: reason,\n          path: IO.chardata_to_string(path),\n          action: \"remove files and directories recursively from\"\n    end\n  end\n\n  @doc ~S\"\"\"\n  Opens the given `path`.\n\n  `modes_or_function` can either be a list of modes or a function. If it's a\n  list, it's considered to be a list of modes (that are documented below). If\n  it's a function, then it's equivalent to calling `open(path, [],\n  modes_or_function)`. See the documentation for `open/3` for more information\n  on this function.\n\n  The allowed modes:\n\n    * `:binary` - opens the file in binary mode, disabling special handling of\n      Unicode sequences (default mode).\n\n    * `:read` - the file, which must exist, is opened for reading.\n\n    * `:write` - the file is opened for writing. It is created if it does not\n      exist.\n\n      If the file does exist, and if write is not combined with read, the file\n      will be truncated.\n\n    * `:append` - the file will be opened for writing, and it will be created\n      if it does not exist. Every write operation to a file opened with append\n      will take place at the end of the file.\n\n    * `:exclusive` - the file, when opened for writing, is created if it does\n      not exist. If the file exists, open will return `{:error, :eexist}`.\n\n    * `:charlist` - when this term is given, read operations on the file will\n      return charlists rather than binaries.\n\n    * `:compressed` - makes it possible to read or write gzip compressed files.\n\n      The compressed option must be combined with either read or write, but not\n      both. Note that the file size obtained with `stat/1` will most probably\n      not match the number of bytes that can be read from a compressed file.\n\n    * `:utf8` - this option denotes how data is actually stored in the disk\n      file and makes the file perform automatic translation of characters to\n      and from UTF-8.\n\n      If data is sent to a file in a format that cannot be converted to the\n      UTF-8 or if data is read by a function that returns data in a format that\n      cannot cope with the character range of the data, an error occurs and the\n      file will be closed.\n\n    * `:delayed_write`, `:raw`, `:ram`, `:read_ahead`, `:sync`, `{:encoding, ...}`,\n      `{:read_ahead, pos_integer}`, `{:delayed_write, non_neg_integer, non_neg_integer}` -\n      for more information about these options see `:file.open/2`.\n\n  This function returns:\n\n    * `{:ok, io_device | file_descriptor}` - the file has been opened in\n      the requested mode. We explore the differences between these two results\n      in the following section\n\n    * `{:error, reason}` - the file could not be opened due to `reason`.\n\n  ## IO devices\n\n  By default, this function returns an IO device. An `io_device` is\n  a process which handles the file and you can interact with it using\n  the functions in the `IO` module. By default, a file is opened in\n  `:binary` mode, which requires the functions `IO.binread/2` and\n  `IO.binwrite/2` to interact with the file. A developer may pass `:utf8`\n  as a mode when opening the file and then all other functions from\n  `IO` are available, since they work directly with Unicode data.\n\n  Given the IO device is a file, if the owner process terminates,\n  the file is closed and the process itself terminates too. If any\n  process to which the `io_device` is linked terminates, the file\n  will be closed and the process itself will be terminated.\n\n  ## File descriptors\n\n  When the `:raw` or `:ram` modes are given, this function returns\n  a low-level file descriptors. This avoids creating a process but\n  requires using the functions in the [`:file`](`:file`) module to\n  interact with it.\n\n  ## Examples\n\n      {:ok, file} = File.open(\"foo.tar.gz\", [:read, :compressed])\n      IO.read(file, :line)\n      File.close(file)\n\n  \"\"\"\n  @spec open(Path.t(), [mode | :ram]) ::\n          {:ok, io_device | file_descriptor} | {:error, posix | :badarg | :system_limit}\n  @spec open(Path.t(), (io_device | file_descriptor -> res)) ::\n          {:ok, res} | {:error, posix | :badarg | :system_limit}\n        when res: var\n  def open(path, modes_or_function \\\\ [])\n\n  def open(path, modes) when is_list(modes) do\n    :file.open(IO.chardata_to_string(path), normalize_modes(modes, true))\n  end\n\n  def open(path, function) when is_function(function, 1) do\n    open(path, [], function)\n  end\n\n  @doc \"\"\"\n  Similar to `open/2` but expects a function as its last argument.\n\n  The file is opened, given to the function as an argument and\n  automatically closed after the function returns, regardless\n  if there was an error when executing the function.\n\n  Returns `{:ok, function_result}` in case of success,\n  `{:error, reason}` otherwise.\n\n  This function expects the file to be closed with success,\n  which is usually the case unless the `:delayed_write` option\n  is given. For this reason, we do not recommend passing\n  `:delayed_write` to this function.\n\n  See `open/2` for the list of available `modes`.\n\n  ## Examples\n\n      File.open(\"file.txt\", [:read, :write], fn file ->\n        IO.read(file, :line)\n      end)\n      #=> {:ok, \"file content\"}\n  \"\"\"\n  @spec open(Path.t(), [mode | :ram], (io_device | file_descriptor -> res)) ::\n          {:ok, res} | {:error, posix | :badarg | :system_limit}\n        when res: var\n  def open(path, modes, function) when is_list(modes) and is_function(function, 1) do\n    case open(path, modes) do\n      {:ok, io_device} ->\n        try do\n          {:ok, function.(io_device)}\n        after\n          :ok = close(io_device)\n        end\n\n      other ->\n        other\n    end\n  end\n\n  @doc \"\"\"\n  Similar to `open/2` but raises a `File.Error` exception if the file\n  could not be opened. Returns the IO device otherwise.\n\n  See `open/2` for the list of available modes.\n\n  ## Examples\n\n      File.open!(\"file.txt\", fn file ->\n        IO.read(file, :line)\n      end)\n      #=> \"file content\"\n  \"\"\"\n  @spec open!(Path.t(), [mode | :ram]) :: io_device | file_descriptor\n  @spec open!(Path.t(), (io_device | file_descriptor -> res)) :: res when res: var\n  def open!(path, modes_or_function \\\\ []) do\n    case open(path, modes_or_function) do\n      {:ok, io_device_or_function_result} ->\n        io_device_or_function_result\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"open\", path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Similar to `open/3` but raises a `File.Error` exception if the file\n  could not be opened.\n\n  If it succeeds opening the file, it returns the `function` result on the IO device.\n\n  See `open/2` for the list of available `modes`.\n\n  ## Examples\n\n      File.open!(\"file.txt\", [:read, :write], fn file ->\n        IO.read(file, :line)\n      end)\n      #=> \"file content\"\n  \"\"\"\n  @spec open!(Path.t(), [mode | :ram], (io_device | file_descriptor -> res)) :: res when res: var\n  def open!(path, modes, function) do\n    case open(path, modes, function) do\n      {:ok, function_result} ->\n        function_result\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"open\", path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Gets the current working directory.\n\n  In rare circumstances, this function can fail on Unix-like systems. It may happen\n  if read permissions do not exist for the parent directories of the\n  current directory. For this reason, returns `{:ok, cwd}` in case\n  of success, `{:error, reason}` otherwise.\n\n  ## Examples\n\n      File.cwd()\n      #=> {:ok, \"/Users/user/elixir/elixir_lang\"}\n\n      # Missing read permission for one of the parents of the current directory\n      File.cwd()\n      #=> {:error, :eacces}\n  \"\"\"\n  @spec cwd() :: {:ok, binary} | {:error, posix | :badarg}\n  def cwd() do\n    case :file.get_cwd() do\n      {:ok, base} -> {:ok, IO.chardata_to_string(fix_drive_letter(base))}\n      {:error, _} = error -> error\n    end\n  end\n\n  defp fix_drive_letter([l, ?:, ?/ | rest] = original) when l in ?A..?Z do\n    case :os.type() do\n      {:win32, _} -> [l + ?a - ?A, ?:, ?/ | rest]\n      _ -> original\n    end\n  end\n\n  defp fix_drive_letter(original), do: original\n\n  @doc \"\"\"\n  The same as `cwd/0`, but raises a `File.Error` exception if it fails.\n\n  ## Examples\n\n      File.cwd!()\n      #=> \"/Users/user/elixir/elixir_lang\"\n  \"\"\"\n  @spec cwd!() :: binary\n  def cwd!() do\n    case cwd() do\n      {:ok, cwd} ->\n        cwd\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"get current working directory\"\n    end\n  end\n\n  @doc \"\"\"\n  Sets the current working directory.\n\n  The current working directory is set for the BEAM globally. This can lead to\n  race conditions if multiple processes are changing the current working\n  directory concurrently. To run an external command in a given directory\n  without changing the global current working directory, use the `:cd` option\n  of `System.cmd/3` and `Port.open/2`.\n\n  Returns `:ok` if successful, `{:error, reason}` otherwise.\n\n  ## Examples\n\n      File.cd(\"bin\")\n      #=> :ok\n\n      File.cd(\"non_existing_dir\")\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec cd(Path.t()) :: :ok | {:error, posix | :badarg | :no_translation}\n  def cd(path) do\n    :file.set_cwd(IO.chardata_to_string(path))\n  end\n\n  @doc \"\"\"\n  The same as `cd/1`, but raises a `File.Error` exception if it fails.\n\n  ## Examples\n\n      File.cd!(\"bin\")\n      #=> :ok\n\n      File.cd!(\"non_existing_dir\")\n      ** (File.Error) could not set current working directory to \"non_existing_dir\": no such file or directory\n  \"\"\"\n  @spec cd!(Path.t()) :: :ok\n  def cd!(path) do\n    case cd(path) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"set current working directory to\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Changes the current directory to the given `path`,\n  executes the given function and then reverts back\n  to the previous path regardless of whether there is an exception.\n\n  The current working directory is temporarily set for the BEAM globally. This\n  can lead to race conditions if multiple processes are changing the current\n  working directory concurrently. To run an external command in a given\n  directory without changing the global current working directory, use the\n  `:cd` option of `System.cmd/3` and `Port.open/2`.\n\n  Raises an error if retrieving or changing the current\n  directory fails.\n\n  ## Examples\n\n      File.cd!(\"bin\", fn -> do_something() end)\n      #=> :result_of_do_something\n\n      File.cd!(\"non_existing_dir\", fn -> do_something() end)\n      ** (File.Error) could not set current working directory to \"non_existing_dir\": no such file or directory\n  \"\"\"\n  @spec cd!(Path.t(), (-> res)) :: res when res: var\n  def cd!(path, function) do\n    old = cwd!()\n    cd!(path)\n\n    try do\n      function.()\n    after\n      cd!(old)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the list of files in the given directory.\n\n  Hidden files are not ignored and the results are *not* sorted.\n\n  Since directories are considered files by the file system,\n  they are also included in the returned value.\n\n  Returns `{:ok, files}` in case of success,\n  `{:error, reason}` otherwise.\n\n  ## Examples\n\n      File.ls(\"bin\")\n      #=> {:ok, [\"iex\", \"elixir\"]}\n\n      File.ls(\"non_existing_dir\")\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec ls(Path.t()) :: {:ok, [binary]} | {:error, posix | :badarg | {:no_translation, binary}}\n  def ls(path \\\\ \".\") do\n    case :file.list_dir(IO.chardata_to_string(path)) do\n      {:ok, file_list} -> {:ok, Enum.map(file_list, &IO.chardata_to_string/1)}\n      {:error, _} = error -> error\n    end\n  end\n\n  @doc \"\"\"\n  The same as `ls/1` but raises a `File.Error` exception in case of an error.\n\n  ## Examples\n\n      File.ls!(\"bin\")\n      #=> [\"iex\", \"elixir\"]\n\n      File.ls!(\"non_existing_dir\")\n      ** (File.Error) could not list directory \"non_existing_dir\": no such file or directory\n  \"\"\"\n  @spec ls!(Path.t()) :: [binary]\n  def ls!(path \\\\ \".\") do\n    case ls(path) do\n      {:ok, value} ->\n        value\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"list directory\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Closes the file referenced by `io_device`. It mostly returns `:ok`, except\n  for some severe errors such as out of memory.\n\n  Note that if the option `:delayed_write` was used when opening the file,\n  `close/1` might return an old write error and not even try to close the file.\n  See `open/2` for more information.\n\n  ## Examples\n\n      {:ok, file} = File.open(\"hello.txt\")\n      File.close(file)\n      #=> :ok\n\n      File.close(:not_an_io_device)\n      #=> {:error, :badarg}\n  \"\"\"\n  @spec close(io_device) :: :ok | {:error, posix | :badarg | :terminated}\n  def close(io_device) do\n    :file.close(io_device)\n  end\n\n  @doc \"\"\"\n  Shortcut for `File.stream!/3`.\n  \"\"\"\n  @spec stream!(Path.t(), :line | pos_integer | [stream_mode]) :: File.Stream.t()\n  def stream!(path, line_or_bytes_modes \\\\ [])\n\n  def stream!(path, modes) when is_list(modes),\n    do: stream!(path, :line, modes)\n\n  def stream!(path, line_or_bytes) when is_integer(line_or_bytes) or line_or_bytes == :line,\n    do: stream!(path, line_or_bytes, [])\n\n  @doc ~S\"\"\"\n  Returns a `File.Stream` for the given `path` with the given `modes`.\n\n  The stream implements both `Enumerable` and `Collectable` protocols,\n  which means it can be used both for read and write.\n\n  The `line_or_bytes` argument configures how the file is read when\n  streaming, by `:line` (default) or by a given number of bytes. When\n  using the `:line` option, CRLF line breaks (`\"\\r\\n\"`) are normalized\n  to LF (`\"\\n\"`).\n\n  Similar to other file operations, a stream can be created in one node\n  and forwarded to another node. Once the stream is opened in another node,\n  a request will be sent to the creator node to spawn a process for file\n  streaming.\n\n  Operating the stream can fail on open for the same reasons as\n  `File.open!/2`. Note that the file is automatically opened each time streaming\n  begins. There is no need to pass `:read` and `:write` modes, as those are\n  automatically set by Elixir.\n\n  ## Raw files\n\n  Since Elixir controls when the streamed file is opened, the underlying\n  device cannot be shared and as such it is convenient to open the file\n  in raw mode for performance reasons. Therefore, Elixir **will** open\n  streams in `:raw` mode with the `:read_ahead` option if the stream is\n  open in the same node as it is created and no encoding has been specified.\n  This means any data streamed into the file must be converted to `t:iodata/0`\n  type. If you pass, for example, `[encoding: :utf8]` or\n  `[encoding: {:utf16, :little}]` in the modes parameter, the underlying stream\n  will use `IO.write/2` and the `String.Chars` protocol to convert the data.\n  See `IO.binwrite/2` and `IO.write/2` .\n\n  One may also consider passing the `:delayed_write` option if the stream\n  is meant to be written to under a tight loop.\n\n  ## Byte order marks and read offset\n\n  If you pass `:trim_bom` in the modes parameter, the stream will\n  trim UTF-8, UTF-16 and UTF-32 byte order marks when reading from file.\n\n  Note that this function does not try to discover the file encoding\n  based on BOM. From Elixir v1.16.0, you may also pass a `:read_offset`\n  that is skipped whenever enumerating the stream (if both `:read_offset`\n  and `:trim_bom` are given, the offset is skipped after the BOM).\n\n  See `Stream.run/1` for an example of streaming into a file.\n\n  ## Examples\n\n      # Read a utf8 text file which may include BOM\n      File.stream!(\"./test/test.txt\", [:trim_bom, encoding: :utf8])\n      #=> %File.Stream{path: \"./test/test.txt\", ...}\n\n      # Read in 2048 byte chunks rather than lines\n      File.stream!(\"./test/test.data\", 2048)\n      #=> %File.Stream{path: \"./test/test.data\", ...}\n  \"\"\"\n  @spec stream!(Path.t(), :line | pos_integer, [stream_mode]) :: File.Stream.t()\n  def stream!(path, line_or_bytes, modes)\n\n  def stream!(path, modes, line_or_bytes) when is_list(modes) do\n    # TODO: Remove me on Elixir 2.0\n    IO.warn(\n      \"File.stream!(path, modes, line_or_byte) is deprecated, \" <>\n        \"invoke File.stream!(path, line_or_bytes, modes) instead\"\n    )\n\n    stream!(path, line_or_bytes, modes)\n  end\n\n  def stream!(path, line_or_bytes, modes) do\n    modes = normalize_modes(modes, true)\n    File.Stream.__build__(IO.chardata_to_string(path), line_or_bytes, modes)\n  end\n\n  @doc \"\"\"\n  Changes the `mode` for a given `file`.\n\n  Returns `:ok` on success, or `{:error, reason}` on failure.\n\n  ## Permissions\n\n  File permissions are specified by adding together the following octal modes:\n\n    * `0o400` - read permission: owner\n    * `0o200` - write permission: owner\n    * `0o100` - execute permission: owner\n\n    * `0o040` - read permission: group\n    * `0o020` - write permission: group\n    * `0o010` - execute permission: group\n\n    * `0o004` - read permission: other\n    * `0o002` - write permission: other\n    * `0o001` - execute permission: other\n\n  For example, setting the mode `0o755` gives it\n  write, read and execute permission to the owner\n  and both read and execute permission to group\n  and others.\n\n  ## Examples\n\n      File.chmod(\"hello.txt\", 0o755)\n      #=> :ok\n\n      File.chmod(\"non_existing.txt\", 0o755)\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec chmod(Path.t(), non_neg_integer) :: :ok | {:error, posix | :badarg}\n  def chmod(path, mode) do\n    :file.change_mode(IO.chardata_to_string(path), mode)\n  end\n\n  @doc \"\"\"\n  Same as `chmod/2`, but raises a `File.Error` exception in case of failure.\n  Otherwise `:ok`.\n\n  ## Examples\n\n      File.chmod!(\"hello.txt\", 0o755)\n      #=> :ok\n\n      File.chmod!(\"non_existing.txt\", 0o755)\n      ** (File.Error) could not change mode for \"non_existing.txt\": no such file or directory\n  \"\"\"\n  @spec chmod!(Path.t(), non_neg_integer) :: :ok\n  def chmod!(path, mode) do\n    case chmod(path, mode) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"change mode for\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Changes the group given by the group ID `gid`\n  for a given `file`. Returns `:ok` on success, or\n  `{:error, reason}` on failure.\n\n  ## Examples\n\n      File.chgrp(\"hello.txt\", 10)\n      #=> :ok\n\n      File.chgrp(\"non_existing.txt\", 10)\n      #=> {:error, :enoent}\n  \"\"\"\n  @spec chgrp(Path.t(), non_neg_integer) :: :ok | {:error, posix | :badarg}\n  def chgrp(path, gid) do\n    :file.change_group(IO.chardata_to_string(path), gid)\n  end\n\n  @doc \"\"\"\n  Same as `chgrp/2`, but raises a `File.Error` exception in case of failure.\n  Otherwise `:ok`.\n\n  ## Examples\n\n    File.chgrp!(\"hello.txt\", 10)\n    #=> :ok\n\n    File.chgrp!(\"non_existing.txt\", 10)\n    ** (File.Error) could not change group for \"non_existing.txt\": no such file or directory\n  \"\"\"\n  @spec chgrp!(Path.t(), non_neg_integer) :: :ok\n  def chgrp!(path, gid) do\n    case chgrp(path, gid) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"change group for\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  @doc \"\"\"\n  Changes the owner given by the user ID `uid`\n  for a given `file`. Returns `:ok` on success,\n  or `{:error, reason}` on failure.\n\n  ## Examples\n\n      File.chown(\"hello.txt\", 15)\n      #=> :ok\n\n      File.chown(\"secret.txt\", 15)\n      #=> {:error, :eperm}\n  \"\"\"\n  @spec chown(Path.t(), non_neg_integer) :: :ok | {:error, posix | :badarg}\n  def chown(path, uid) do\n    :file.change_owner(IO.chardata_to_string(path), uid)\n  end\n\n  @doc \"\"\"\n  Same as `chown/2`, but raises a `File.Error` exception in case of failure.\n  Otherwise `:ok`.\n\n  ## Examples\n\n      File.chown!(\"hello.txt\", 15)\n      #=> :ok\n\n      File.chown!(\"secret.txt\", 15)\n      ** (File.Error) could not change owner for \"secret.txt\": not owner\n  \"\"\"\n  @spec chown!(Path.t(), non_neg_integer) :: :ok\n  def chown!(path, uid) do\n    case chown(path, uid) do\n      :ok ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error,\n          reason: reason,\n          action: \"change owner for\",\n          path: IO.chardata_to_string(path)\n    end\n  end\n\n  ## Helpers\n\n  @read_ahead_size 64 * 1024\n\n  defp assert_no_null_byte!(binary, operation) do\n    case :binary.match(binary, \"\\0\") do\n      {_, _} ->\n        raise ArgumentError,\n              \"cannot execute #{operation} for path with null byte, got: #{inspect(binary)}\"\n\n      :nomatch ->\n        binary\n    end\n  end\n\n  defp normalize_modes([:utf8 | rest], binary?) do\n    [encoding: :utf8] ++ normalize_modes(rest, binary?)\n  end\n\n  defp normalize_modes([:read_ahead | rest], binary?) do\n    [read_ahead: @read_ahead_size] ++ normalize_modes(rest, binary?)\n  end\n\n  # TODO: Remove :char_list mode on v2.0\n  defp normalize_modes([mode | rest], _binary?) when mode in [:charlist, :char_list] do\n    if mode == :char_list do\n      IO.warn(\"the :char_list mode is deprecated, use :charlist\")\n    end\n\n    normalize_modes(rest, false)\n  end\n\n  defp normalize_modes([mode | rest], binary?) do\n    [mode | normalize_modes(rest, binary?)]\n  end\n\n  defp normalize_modes([], true), do: [:binary]\n  defp normalize_modes([], false), do: []\n\n  defp normalize_path_or_io_device(path) when is_list(path), do: IO.chardata_to_string(path)\n  defp normalize_path_or_io_device(path) when is_binary(path), do: path\n  defp normalize_path_or_io_device(io_device) when is_pid(io_device), do: io_device\n  defp normalize_path_or_io_device(io_device = {:file_descriptor, _, _}), do: io_device\nend\n"
  },
  {
    "path": "lib/elixir/lib/float.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nimport Kernel, except: [round: 1]\n\ndefmodule Float do\n  @moduledoc \"\"\"\n  Functions for working with floating-point numbers.\n\n  For mathematical operations on top of floating-points,\n  see Erlang's [`:math`](`:math`) module.\n\n  ## Kernel functions\n\n  There are functions related to floating-point numbers on the `Kernel` module\n  too. Here is a list of them:\n\n    * `Kernel.round/1`: rounds a number to the nearest integer.\n    * `Kernel.trunc/1`: returns the integer part of a number.\n\n  ## Known issues\n\n  There are some very well known problems with floating-point numbers\n  and arithmetic due to the fact most decimal fractions cannot be\n  represented by a floating-point binary and most operations are not exact,\n  but operate on approximations. Those issues are not specific\n  to Elixir, they are a property of floating point representation itself.\n\n  For example, the numbers 0.1 and 0.01 are two of them, what means the result\n  of squaring 0.1 does not give 0.01 neither the closest representable. Here is\n  what happens in this case:\n\n    * The closest representable number to 0.1 is 0.1000000014\n    * The closest representable number to 0.01 is 0.0099999997\n    * Doing 0.1 * 0.1 should return 0.01, but because 0.1 is actually 0.1000000014,\n      the result is 0.010000000000000002, and because this is not the closest\n      representable number to 0.01, you'll get the wrong result for this operation\n\n  There are also other known problems like flooring or rounding numbers. See\n  `round/2` and `floor/2` for more details about them.\n\n  To learn more about floating-point arithmetic visit:\n\n    * [0.30000000000000004.com](https://0.30000000000000004.com/)\n    * [What Every Programmer Should Know About Floating-Point Arithmetic](https://floating-point-gui.de/)\n\n  \"\"\"\n\n  import Bitwise\n\n  @power_of_2_to_52 4_503_599_627_370_496\n  @precision_range 0..15\n  @type precision_range :: 0..15\n\n  @min_finite then(<<0xFFEFFFFFFFFFFFFF::64>>, fn <<num::float>> -> num end)\n  @max_finite then(<<0x7FEFFFFFFFFFFFFF::64>>, fn <<num::float>> -> num end)\n\n  @doc \"\"\"\n  Returns the maximum finite value for a float.\n\n  ## Examples\n\n      iex> Float.max_finite()\n      1.7976931348623157e308\n\n  \"\"\"\n  @spec max_finite() :: float\n  def max_finite, do: @max_finite\n\n  @doc \"\"\"\n  Returns the minimum finite value for a float.\n\n  ## Examples\n\n      iex> Float.min_finite()\n      -1.7976931348623157e308\n\n  \"\"\"\n  @spec min_finite() :: float\n  def min_finite, do: @min_finite\n\n  @doc \"\"\"\n  Computes `base` raised to power of `exponent`.\n\n  `base` must be a float and `exponent` can be any number.\n  However, if a negative base and a fractional exponent\n  are given, it raises `ArithmeticError`.\n\n  It always returns a float. See `Integer.pow/2` for\n  exponentiation that returns integers.\n\n  ## Examples\n\n      iex> Float.pow(2.0, 0)\n      1.0\n      iex> Float.pow(2.0, 1)\n      2.0\n      iex> Float.pow(2.0, 10)\n      1024.0\n      iex> Float.pow(2.0, -1)\n      0.5\n      iex> Float.pow(2.0, -3)\n      0.125\n\n      iex> Float.pow(3.0, 1.5)\n      5.196152422706632\n\n      iex> Float.pow(-2.0, 3)\n      -8.0\n      iex> Float.pow(-2.0, 4)\n      16.0\n\n      iex> Float.pow(-1.0, 0.5)\n      ** (ArithmeticError) bad argument in arithmetic expression\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec pow(float, number) :: float\n  def pow(base, exponent) when is_float(base) and is_number(exponent),\n    do: :math.pow(base, exponent)\n\n  @doc \"\"\"\n  Parses a binary into a float.\n\n  If successful, returns a tuple in the form of `{float, remainder_of_binary}`;\n  when the binary cannot be coerced into a valid float, the atom `:error` is\n  returned.\n\n  If the size of float exceeds the maximum size of `1.7976931348623157e+308`,\n  `:error` is returned even though the textual representation itself might be\n  well formed.\n\n  If you want to convert a string-formatted float directly to a float,\n  `String.to_float/1` can be used instead.\n\n  ## Examples\n\n      iex> Float.parse(\"34\")\n      {34.0, \"\"}\n      iex> Float.parse(\"34.25\")\n      {34.25, \"\"}\n      iex> Float.parse(\"56.5xyz\")\n      {56.5, \"xyz\"}\n\n      iex> Float.parse(\".12\")\n      :error\n      iex> Float.parse(\"pi\")\n      :error\n      iex> Float.parse(\"1.7976931348623159e+308\")\n      :error\n\n  \"\"\"\n  @spec parse(binary) :: {float, binary} | :error\n  def parse(\"-\" <> binary) do\n    case parse_unsigned(binary) do\n      :error -> :error\n      {number, remainder} -> {-number, remainder}\n    end\n  end\n\n  def parse(\"+\" <> binary) do\n    parse_unsigned(binary)\n  end\n\n  def parse(binary) do\n    parse_unsigned(binary)\n  end\n\n  defp parse_unsigned(<<digit, rest::binary>>) when digit in ?0..?9,\n    do: parse_unsigned(rest, false, false, [digit])\n\n  defp parse_unsigned(binary) when is_binary(binary), do: :error\n\n  defp parse_unsigned(<<digit, rest::binary>>, dot?, e?, acc) when digit in ?0..?9,\n    do: parse_unsigned(rest, dot?, e?, [digit | acc])\n\n  defp parse_unsigned(<<?., digit, rest::binary>>, false, false, acc) when digit in ?0..?9,\n    do: parse_unsigned(rest, true, false, [digit, ?. | acc])\n\n  defp parse_unsigned(<<exp_marker, digit, rest::binary>>, dot?, false, acc)\n       when exp_marker in ~c\"eE\" and digit in ?0..?9,\n       do: parse_unsigned(rest, true, true, [digit, ?e | add_dot(acc, dot?)])\n\n  defp parse_unsigned(<<exp_marker, sign, digit, rest::binary>>, dot?, false, acc)\n       when exp_marker in ~c\"eE\" and sign in ~c\"-+\" and digit in ?0..?9,\n       do: parse_unsigned(rest, true, true, [digit, sign, ?e | add_dot(acc, dot?)])\n\n  # :erlang.binary_to_float/1 can raise an ArgumentError if the e exponent is too big. For example,\n  # \"1.0e400\". Because of this, we rescue the ArgumentError here and return an error.\n  defp parse_unsigned(rest, dot?, _, acc) do\n    acc\n    |> add_dot(dot?)\n    |> :lists.reverse()\n    |> :erlang.list_to_float()\n  rescue\n    ArgumentError -> :error\n  else\n    float -> {float, rest}\n  end\n\n  defp add_dot(acc, true), do: acc\n  defp add_dot(acc, false), do: [?0, ?. | acc]\n\n  @doc \"\"\"\n  Rounds a float to the largest float less than or equal to `number`.\n\n  `floor/2` also accepts a precision to round a floating-point value down\n  to an arbitrary number of fractional digits (between 0 and 15).\n  The operation is performed on the binary floating point, without a\n  conversion to decimal.\n\n  This function always returns a float. `Kernel.trunc/1` may be used instead to\n  truncate the result to an integer afterwards.\n\n  ## Known issues\n\n  The behavior of `floor/2` for floats can be surprising. For example:\n\n      iex> Float.floor(12.52, 2)\n      12.51\n\n  One may have expected it to floor to 12.52. This is not a bug.\n  Most decimal fractions cannot be represented as a binary floating point\n  and therefore the number above is internally represented as 12.51999999,\n  which explains the behavior above.\n\n  ## Examples\n\n      iex> Float.floor(34.25)\n      34.0\n      iex> Float.floor(-56.5)\n      -57.0\n      iex> Float.floor(34.259, 2)\n      34.25\n\n  \"\"\"\n  @spec floor(float, precision_range) :: float\n  def floor(number, precision \\\\ 0)\n\n  def floor(number, 0) when is_float(number) do\n    :math.floor(number)\n  end\n\n  def floor(number, precision) when is_float(number) and precision in @precision_range do\n    round(number, precision, :floor)\n  end\n\n  def floor(number, precision) when is_float(number) do\n    raise ArgumentError, invalid_precision_message(precision)\n  end\n\n  @doc \"\"\"\n  Rounds a float to the smallest float greater than or equal to `number`.\n\n  `ceil/2` also accepts a precision to round a floating-point value down\n  to an arbitrary number of fractional digits (between 0 and 15).\n\n  The operation is performed on the binary floating point, without a\n  conversion to decimal.\n\n  The behavior of `ceil/2` for floats can be surprising. For example:\n\n      iex> Float.ceil(-12.52, 2)\n      -12.51\n\n  One may have expected it to ceil to -12.52. This is not a bug.\n  Most decimal fractions cannot be represented as a binary floating point\n  and therefore the number above is internally represented as -12.51999999,\n  which explains the behavior above.\n\n  This function always returns floats. `Kernel.trunc/1` may be used instead to\n  truncate the result to an integer afterwards.\n\n  ## Examples\n\n      iex> Float.ceil(34.25)\n      35.0\n      iex> Float.ceil(-56.5)\n      -56.0\n      iex> Float.ceil(34.251, 2)\n      34.26\n      iex> Float.ceil(-0.01)\n      -0.0\n\n  \"\"\"\n  @spec ceil(float, precision_range) :: float\n  def ceil(number, precision \\\\ 0)\n\n  def ceil(number, 0) when is_float(number) do\n    :math.ceil(number)\n  end\n\n  def ceil(number, precision) when is_float(number) and precision in @precision_range do\n    round(number, precision, :ceil)\n  end\n\n  def ceil(number, precision) when is_float(number) do\n    raise ArgumentError, invalid_precision_message(precision)\n  end\n\n  @doc \"\"\"\n  Rounds a floating-point value to an arbitrary number of fractional\n  digits (between 0 and 15).\n\n  The rounding direction always ties to half up. The operation is\n  performed on the binary floating point, without a conversion to decimal.\n\n  This function only accepts floats and always returns a float. Use\n  `Kernel.round/1` if you want a function that accepts both floats\n  and integers and always returns an integer.\n\n  ## Known issues\n\n  The behavior of `round/2` for floats can be surprising. For example:\n\n      iex> Float.round(5.5675, 3)\n      5.567\n\n  One may have expected it to round to the half up 5.568. This is not a bug.\n  Most decimal fractions cannot be represented as a binary floating point\n  and therefore the number above is internally represented as 5.567499999,\n  which explains the behavior above. If you want exact rounding for decimals,\n  you must use a decimal library. The behavior above is also in accordance\n  to reference implementations, such as \"Correctly Rounded Binary-Decimal and\n  Decimal-Binary Conversions\" by David M. Gay.\n\n  ## Examples\n\n      iex> Float.round(12.5)\n      13.0\n      iex> Float.round(5.5674, 3)\n      5.567\n      iex> Float.round(5.5675, 3)\n      5.567\n      iex> Float.round(-5.5674, 3)\n      -5.567\n      iex> Float.round(-5.5675)\n      -6.0\n      iex> Float.round(12.341444444444441, 15)\n      12.341444444444441\n      iex> Float.round(-0.01)\n      -0.0\n\n  \"\"\"\n  @spec round(float, precision_range) :: float\n  # This implementation is slow since it relies on big integers.\n  # Faster implementations are available on more recent papers\n  # and could be implemented in the future.\n  def round(float, precision \\\\ 0)\n\n  def round(float, 0) when float == 0.0, do: float\n\n  def round(float, 0) when is_float(float) do\n    case float |> :erlang.round() |> :erlang.float() do\n      zero when zero == 0.0 and float < 0.0 -> -0.0\n      rounded -> rounded\n    end\n  end\n\n  def round(float, precision) when is_float(float) and precision in @precision_range do\n    round(float, precision, :half_up)\n  end\n\n  def round(float, precision) when is_float(float) do\n    raise ArgumentError, invalid_precision_message(precision)\n  end\n\n  defp round(num, _precision, _rounding) when is_float(num) and num == 0.0, do: num\n\n  defp round(float, precision, rounding) do\n    <<sign::1, exp::11, significant::52-bitstring>> = <<float::float>>\n    {num, count} = decompose(significant, 1)\n    count = count - exp + 1023\n\n    cond do\n      # Precision beyond 15 digits\n      count >= 104 ->\n        case rounding do\n          :ceil when sign === 0 -> 1 / power_of_10(precision)\n          :floor when sign === 1 -> -1 / power_of_10(precision)\n          :ceil when sign === 1 -> -0.0\n          :half_up when sign === 1 -> -0.0\n          _ -> 0.0\n        end\n\n      # We are asking more precision than we have\n      count <= precision ->\n        float\n\n      true ->\n        # Difference in precision between float and asked precision\n        # We subtract 1 because we need to calculate the remainder too\n        diff = count - precision - 1\n\n        # Get up to latest so we calculate the remainder\n        power_of_10 = power_of_10(diff)\n\n        # Convert the numerand to decimal base\n        num = num * power_of_5(count)\n\n        # Move to the given precision - 1\n        num = div(num, power_of_10)\n        div = div(num, 10)\n        num = rounding(rounding, sign, num, div)\n\n        # Convert back to float without loss\n        # https://www.exploringbinary.com/correct-decimal-to-floating-point-using-big-integers/\n        den = power_of_10(precision)\n        boundary = den <<< 52\n\n        cond do\n          num == 0 and sign == 1 ->\n            -0.0\n\n          num == 0 ->\n            0.0\n\n          num >= boundary ->\n            {den, exp} = scale_down(num, boundary, 52)\n            decimal_to_float(sign, num, den, exp)\n\n          true ->\n            {num, exp} = scale_up(num, boundary, 52)\n            decimal_to_float(sign, num, den, exp)\n        end\n    end\n  end\n\n  defp decompose(significant, initial) do\n    decompose(significant, 1, 0, initial)\n  end\n\n  defp decompose(<<1::1, bits::bitstring>>, count, last_count, acc) do\n    decompose(bits, count + 1, count, (acc <<< (count - last_count)) + 1)\n  end\n\n  defp decompose(<<0::1, bits::bitstring>>, count, last_count, acc) do\n    decompose(bits, count + 1, last_count, acc)\n  end\n\n  defp decompose(<<>>, _count, last_count, acc) do\n    {acc, last_count}\n  end\n\n  defp scale_up(num, boundary, exp) when num >= boundary, do: {num, exp}\n  defp scale_up(num, boundary, exp), do: scale_up(num <<< 1, boundary, exp - 1)\n\n  defp scale_down(num, den, exp) do\n    new_den = den <<< 1\n\n    if num < new_den do\n      {den >>> 52, exp}\n    else\n      scale_down(num, new_den, exp + 1)\n    end\n  end\n\n  defp decimal_to_float(sign, num, den, exp) do\n    quo = div(num, den)\n    rem = num - quo * den\n\n    tmp =\n      case den >>> 1 do\n        den when rem > den -> quo + 1\n        den when rem < den -> quo\n        _ when (quo &&& 1) === 1 -> quo + 1\n        _ -> quo\n      end\n\n    tmp = tmp - @power_of_2_to_52\n    <<tmp::float>> = <<sign::1, exp + 1023::11, tmp::52>>\n    tmp\n  end\n\n  defp rounding(:floor, 1, _num, div), do: div + 1\n  defp rounding(:ceil, 0, _num, div), do: div + 1\n\n  defp rounding(:half_up, _sign, num, div) do\n    case rem(num, 10) do\n      rem when rem < 5 -> div\n      rem when rem >= 5 -> div + 1\n    end\n  end\n\n  defp rounding(_, _, _, div), do: div\n\n  Enum.reduce(0..104, 1, fn x, acc ->\n    defp power_of_10(unquote(x)), do: unquote(acc)\n    acc * 10\n  end)\n\n  Enum.reduce(0..104, 1, fn x, acc ->\n    defp power_of_5(unquote(x)), do: unquote(acc)\n    acc * 5\n  end)\n\n  @doc \"\"\"\n  Returns a pair of integers whose ratio is exactly equal\n  to the original float and with a positive denominator.\n\n  ## Examples\n\n      iex> Float.ratio(0.0)\n      {0, 1}\n      iex> Float.ratio(3.14)\n      {7070651414971679, 2251799813685248}\n      iex> Float.ratio(-3.14)\n      {-7070651414971679, 2251799813685248}\n      iex> Float.ratio(1.5)\n      {3, 2}\n      iex> Float.ratio(-1.5)\n      {-3, 2}\n      iex> Float.ratio(16.0)\n      {16, 1}\n      iex> Float.ratio(-16.0)\n      {-16, 1}\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec ratio(float) :: {integer, pos_integer}\n  def ratio(float) when is_float(float) and float == 0.0, do: {0, 1}\n\n  def ratio(float) when is_float(float) do\n    <<sign::1, exp::11, mantissa::52>> = <<float::float>>\n\n    {num, den_exp} =\n      if exp != 0 do\n        # Floats are expressed like this:\n        # (2**52 + mantissa) * 2**(-52 + exp - 1023)\n        #\n        # We compute the root factors of the mantissa so we have this:\n        # (2**52 + mantissa * 2**count) * 2**(-52 + exp - 1023)\n        {mantissa, count} = root_factors(mantissa, 0)\n\n        # Now we can move the count around so we have this:\n        # (2**(52-count) + mantissa) * 2**(count + -52 + exp - 1023)\n        if mantissa == 0 do\n          {1, exp - 1023}\n        else\n          num = (1 <<< (52 - count)) + mantissa\n          den_exp = count - 52 + exp - 1023\n          {num, den_exp}\n        end\n      else\n        # Subnormals are expressed like this:\n        # (mantissa) * 2**(-52 + 1 - 1023)\n        #\n        # So we compute it to this:\n        # (mantissa * 2**(count)) * 2**(-52 + 1 - 1023)\n        #\n        # Which becomes:\n        # mantissa * 2**(count-1074)\n        root_factors(mantissa, -1074)\n      end\n\n    if den_exp > 0 do\n      {sign(sign, num <<< den_exp), 1}\n    else\n      {sign(sign, num), 1 <<< -den_exp}\n    end\n  end\n\n  defp root_factors(mantissa, count) when mantissa != 0 and (mantissa &&& 1) == 0,\n    do: root_factors(mantissa >>> 1, count + 1)\n\n  defp root_factors(mantissa, count),\n    do: {mantissa, count}\n\n  @compile {:inline, sign: 2}\n  defp sign(0, num), do: num\n  defp sign(1, num), do: -num\n\n  @doc \"\"\"\n  Returns a charlist which corresponds to the shortest text representation\n  of the given float.\n\n  It uses the algorithm presented in \"Ryū: fast float-to-string conversion\"\n  in Proceedings of the SIGPLAN '2018 Conference on Programming Language\n  Design and Implementation.\n\n  For a configurable representation, use `:erlang.float_to_list/2`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Float.to_charlist(7.0)\n      ~c\"7.0\"\n\n  \"\"\"\n  @spec to_charlist(float) :: charlist\n  def to_charlist(float) do\n    :erlang.float_to_list(float, [:short])\n  end\n\n  @doc \"\"\"\n  Returns a binary which corresponds to the shortest text representation\n  of the given float.\n\n  The underlying algorithm changes depending on the Erlang/OTP version:\n\n    * For OTP >= 24, it uses the algorithm presented in \"Ryū: fast\n      float-to-string conversion\" in Proceedings of the SIGPLAN '2018\n      Conference on Programming Language Design and Implementation.\n\n    * For OTP < 24, it uses the algorithm presented in \"Printing Floating-Point\n      Numbers Quickly and Accurately\" in Proceedings of the SIGPLAN '1996\n      Conference on Programming Language Design and Implementation.\n\n  For a configurable representation, use `:erlang.float_to_binary/2`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Float.to_string(7.0)\n      \"7.0\"\n\n  \"\"\"\n  @spec to_string(float) :: String.t()\n  def to_string(float) do\n    :erlang.float_to_binary(float, [:short])\n  end\n\n  @doc false\n  @deprecated \"Use Float.to_charlist/1 instead\"\n  def to_char_list(float), do: Float.to_charlist(float)\n\n  @doc false\n  @deprecated \"Use :erlang.float_to_list/2 instead\"\n  def to_char_list(float, options) do\n    :erlang.float_to_list(float, expand_compact(options))\n  end\n\n  @doc false\n  @deprecated \"Use :erlang.float_to_binary/2 instead\"\n  def to_string(float, options) do\n    :erlang.float_to_binary(float, expand_compact(options))\n  end\n\n  defp invalid_precision_message(precision) do\n    \"precision #{precision} is out of valid range of #{inspect(@precision_range)}\"\n  end\n\n  defp expand_compact([{:compact, false} | t]), do: expand_compact(t)\n  defp expand_compact([{:compact, true} | t]), do: [:compact | expand_compact(t)]\n  defp expand_compact([h | t]), do: [h | expand_compact(t)]\n  defp expand_compact([]), do: []\nend\n"
  },
  {
    "path": "lib/elixir/lib/function.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Function do\n  @moduledoc \"\"\"\n  A set of functions for working with functions.\n\n  Anonymous functions are typically created by using `fn`:\n\n      iex> add = fn a, b -> a + b end\n      iex> add.(1, 2)\n      3\n\n  Anonymous functions can also have multiple clauses. All clauses\n  should expect the same number of arguments:\n\n      iex> negate = fn\n      ...>   true -> false\n      ...>   false -> true\n      ...> end\n      iex> negate.(false)\n      true\n\n  ## The capture operator\n\n  It is also possible to capture public module functions and pass them\n  around as if they were anonymous functions by using the capture\n  operator `&/1`:\n\n      iex> add = &Kernel.+/2\n      iex> add.(1, 2)\n      3\n\n      iex> length = &String.length/1\n      iex> length.(\"hello\")\n      5\n\n  To capture a definition within the current module, you can skip the\n  module prefix, such as `&my_fun/2`. In those cases, the captured\n  function can be public (`def`) or private (`defp`).\n\n  The capture operator can also be used to create anonymous functions\n  that expect at least one argument:\n\n      iex> add = &(&1 + &2)\n      iex> add.(1, 2)\n      3\n\n  In such cases, using the capture operator is no different than using `fn`.\n\n  ## Internal and external functions\n\n  We say that functions that point to definitions residing in modules, such\n  as `&String.length/1`, are **external** functions. All other functions are\n  **local** and they are always bound to the file or module that defined them.\n\n  Besides the functions in this module to work with functions, `Kernel` also\n  has an `apply/2` function that invokes a function with a dynamic number of\n  arguments, as well as `is_function/1` and `is_function/2`, to check\n  respectively if a given value is a function or a function of a given arity.\n  \"\"\"\n\n  @type information ::\n          :arity\n          | :env\n          | :index\n          | :module\n          | :name\n          | :new_index\n          | :new_uniq\n          | :pid\n          | :type\n          | :uniq\n\n  @doc \"\"\"\n  Captures the given function.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Function.capture(String, :length, 1)\n      &String.length/1\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec capture(module, atom, arity) :: fun\n  def capture(module, function_name, arity) do\n    :erlang.make_fun(module, function_name, arity)\n  end\n\n  @doc \"\"\"\n  Returns a keyword list with information about a function.\n\n  The returned keys (with the corresponding possible values) for\n  all types of functions (local and external) are the following:\n\n    * `:type` - `:local` (for anonymous functions) or `:external` (for\n      named functions).\n\n    * `:module` - an atom which is the module where the function is defined when\n    anonymous or the module which the function refers to when it's a named function.\n\n    * `:arity` - (integer) the number of arguments the function is to be called with.\n\n    * `:name` - (atom) the name of the function.\n\n    * `:env` - a list of the environment or free variables. For named\n      functions, the returned list is always empty.\n\n  When `fun` is an anonymous function (that is, the type is `:local`), the following\n  additional keys are returned:\n\n    * `:pid` - PID of the process that originally created the function.\n\n    * `:index` - (integer) an index into the module function table.\n\n    * `:new_index` - (integer) an index into the module function table.\n\n    * `:new_uniq` - (binary) a unique value for this function. It's\n      calculated from the compiled code for the entire module.\n\n    * `:uniq` - (integer) a unique value for this function. This integer is\n      calculated from the compiled code for the entire module.\n\n  **Note**: this function must be used only for debugging purposes.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> fun = fn x -> x end\n      iex> info = Function.info(fun)\n      iex> Keyword.get(info, :arity)\n      1\n      iex> Keyword.get(info, :type)\n      :local\n\n      iex> fun = &String.length/1\n      iex> info = Function.info(fun)\n      iex> Keyword.get(info, :type)\n      :external\n      iex> Keyword.get(info, :name)\n      :length\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec info(fun) :: [{information, term}]\n  def info(fun), do: :erlang.fun_info(fun)\n\n  @doc \"\"\"\n  Returns a specific information about the function.\n\n  The returned information is a two-element tuple in the shape of\n  `{info, value}`.\n\n  For any function, the information asked for can be any of the atoms\n  `:module`, `:name`, `:arity`, `:env`, or `:type`.\n\n  For anonymous functions, there is also information about any of the\n  atoms `:index`, `:new_index`, `:new_uniq`, `:uniq`, and `:pid`.\n  For a named function, the value of any of these items is always the\n  atom `:undefined`.\n\n  For more information on each of the possible returned values, see\n  `info/1`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> f = fn x -> x end\n      iex> Function.info(f, :arity)\n      {:arity, 1}\n      iex> Function.info(f, :type)\n      {:type, :local}\n\n      iex> fun = &String.length/1\n      iex> Function.info(fun, :name)\n      {:name, :length}\n      iex> Function.info(fun, :pid)\n      {:pid, :undefined}\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec info(fun, item) :: {item, term} when item: information\n  def info(fun, item), do: :erlang.fun_info(fun, item)\n\n  @doc \"\"\"\n  Returns its input `value`. This function can be passed as an anonymous function\n  to transformation functions.\n\n  ## Examples\n\n      iex> Function.identity(\"Hello world!\")\n      \"Hello world!\"\n\n      iex> ~c\"abcdaabccc\" |> Enum.sort() |> Enum.chunk_by(&Function.identity/1)\n      [~c\"aaa\", ~c\"bb\", ~c\"cccc\", ~c\"d\"]\n\n      iex> Enum.group_by(~c\"abracadabra\", &Function.identity/1)\n      %{97 => ~c\"aaaaa\", 98 => ~c\"bb\", 99 => ~c\"c\", 100 => ~c\"d\", 114 => ~c\"rr\"}\n\n      iex> Enum.map([1, 2, 3, 4], &Function.identity/1)\n      [1, 2, 3, 4]\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec identity(value) :: value when value: var\n  def identity(value), do: value\nend\n"
  },
  {
    "path": "lib/elixir/lib/gen_event/stream.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule GenEvent.Stream do\n  @moduledoc false\n  @moduledoc deprecated: \"This functionality is no longer supported\"\n  defstruct manager: nil, timeout: :infinity\n\n  @type t :: %__MODULE__{manager: GenEvent.manager(), timeout: timeout}\n\n  @doc false\n  def init({_pid, _ref} = state) do\n    {:ok, state}\n  end\n\n  @doc false\n  def handle_event(event, _state) do\n    # We do this to trick Dialyzer to not complain about non-local returns.\n    case :erlang.phash2(1, 1) do\n      0 -> exit({:bad_event, event})\n      1 -> :remove_handler\n    end\n  end\n\n  @doc false\n  def handle_call(msg, _state) do\n    # We do this to trick Dialyzer to not complain about non-local returns.\n    reason = {:bad_call, msg}\n\n    case :erlang.phash2(1, 1) do\n      0 -> exit(reason)\n      1 -> {:remove_handler, reason}\n    end\n  end\n\n  @doc false\n  def handle_info(_msg, state) do\n    {:ok, state}\n  end\n\n  @doc false\n  def terminate(_reason, _state) do\n    :ok\n  end\n\n  @doc false\n  def code_change(_old, state, _extra) do\n    {:ok, state}\n  end\nend\n\ndefimpl Enumerable, for: GenEvent.Stream do\n  @moduledoc false\n  @moduledoc deprecated: \"This functionality is no longer supported\"\n\n  def reduce(stream, acc, fun) do\n    start_fun = fn -> start(stream) end\n    next_fun = &next(stream, &1)\n    stop_fun = &stop(stream, &1)\n    Stream.resource(start_fun, next_fun, stop_fun).(acc, wrap_reducer(fun))\n  end\n\n  def count(_stream) do\n    {:error, __MODULE__}\n  end\n\n  def member?(_stream, _item) do\n    {:error, __MODULE__}\n  end\n\n  def slice(_stream) do\n    {:error, __MODULE__}\n  end\n\n  defp wrap_reducer(fun) do\n    fn\n      {:ack, manager, ref, event}, acc ->\n        send(manager, {ref, :ok})\n        fun.(event, acc)\n\n      {:async, _manager, _ref, event}, acc ->\n        fun.(event, acc)\n\n      {:sync, manager, ref, event}, acc ->\n        try do\n          fun.(event, acc)\n        after\n          send(manager, {ref, :ok})\n        end\n    end\n  end\n\n  defp start(%{manager: manager} = stream) do\n    try do\n      {:ok, {pid, ref}} =\n        :gen.call(manager, self(), {:add_process_handler, self(), self()}, :infinity)\n\n      mon_ref = Process.monitor(pid)\n      {pid, ref, mon_ref}\n    catch\n      :exit, reason -> exit({reason, {__MODULE__, :start, [stream]}})\n    end\n  end\n\n  defp next(%{timeout: timeout} = stream, {pid, ref, mon_ref} = acc) do\n    self = self()\n\n    receive do\n      # Got an async event.\n      {_from, {^pid, ^ref}, {:notify, event}} ->\n        {[{:async, pid, ref, event}], acc}\n\n      # Got a sync event.\n      {_from, {^pid, ^ref}, {:sync_notify, event}} ->\n        {[{:sync, pid, ref, event}], acc}\n\n      # Got an ack event.\n      {_from, {^pid, ^ref}, {:ack_notify, event}} ->\n        {[{:ack, pid, ref, event}], acc}\n\n      # The handler was removed. Stop iteration, resolve the\n      # event later. We need to demonitor now, otherwise DOWN\n      # appears with higher priority in the shutdown process.\n      {:gen_event_EXIT, {^pid, ^ref}, _reason} = event ->\n        Process.demonitor(mon_ref, [:flush])\n        send(self, event)\n        {:halt, {:removed, acc}}\n\n      # The manager died. Stop iteration, resolve the event later.\n      {:DOWN, ^mon_ref, _, _, _} = event ->\n        send(self, event)\n        {:halt, {:removed, acc}}\n    after\n      timeout ->\n        exit({:timeout, {__MODULE__, :next, [stream, acc]}})\n    end\n  end\n\n  # If we reach this branch, we know the handler was already\n  # removed, so we don't trigger a request for doing so.\n  defp stop(stream, {:removed, {pid, ref, mon_ref} = acc}) do\n    case wait_for_handler_removal(pid, ref, mon_ref) do\n      :ok ->\n        flush_events(ref)\n\n      {:error, reason} ->\n        exit({reason, {__MODULE__, :stop, [stream, acc]}})\n    end\n  end\n\n  # If we reach this branch, the handler was not removed yet,\n  # so we trigger a request for doing so.\n  defp stop(stream, {pid, ref, _} = acc) do\n    _ = :gen_event.delete_handler(pid, {pid, ref}, :shutdown)\n    stop(stream, {:removed, acc})\n  end\n\n  defp wait_for_handler_removal(pid, ref, mon_ref) do\n    receive do\n      {:gen_event_EXIT, {^pid, ^ref}, _reason} ->\n        Process.demonitor(mon_ref, [:flush])\n        :ok\n\n      {:DOWN, ^mon_ref, _, _, reason} ->\n        {:error, reason}\n    end\n  end\n\n  defp flush_events(ref) do\n    receive do\n      {_from, {_pid, ^ref}, {notify, _event}}\n      when notify in [:notify, :ack_notify, :sync_notify] ->\n        flush_events(ref)\n    after\n      0 -> :ok\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/gen_event.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule GenEvent do\n  # Functions from this module are deprecated in elixir_dispatch.\n\n  @moduledoc \"\"\"\n  An event manager with event handlers behaviour.\n\n  If you are interested in implementing an event manager, please read the\n  \"Alternatives\" section below. If you have to implement an event handler to\n  integrate with an existing system, such as Elixir's Logger, please use\n  [`:gen_event`](`:gen_event`) instead.\n\n  ## Alternatives\n\n  There are a few suitable alternatives to replace GenEvent. Each of them can be\n  the most beneficial based on the use case.\n\n  ### Supervisor and GenServers\n\n  One alternative to GenEvent is a very minimal solution consisting of using a\n  supervisor and multiple GenServers started under it. The supervisor acts as\n  the \"event manager\" and the children GenServers act as the \"event handlers\".\n  This approach has some shortcomings (it provides no back-pressure for example)\n  but can still replace GenEvent for low-profile usages of it. [This blog post\n  by José\n  Valim](https://dashbit.co/blog/replacing-genevent-by-a-supervisor-plus-genserver)\n  has more detailed information on this approach.\n\n  ### GenStage\n\n  If the use case where you were using GenEvent requires more complex logic,\n  [GenStage](https://github.com/elixir-lang/gen_stage) provides a great\n  alternative. GenStage is an external Elixir library maintained by the Elixir\n  team; it provides a tool to implement systems that exchange events in a\n  demand-driven way with built-in support for back-pressure. See the [GenStage\n  documentation](https://hexdocs.pm/gen_stage) for more information.\n\n  ### `:gen_event`\n\n  If your use case requires exactly what GenEvent provided, or you have to\n  integrate with an existing `:gen_event`-based system, you can still use the\n  [`:gen_event`](`:gen_event`) Erlang module.\n  \"\"\"\n\n  @moduledoc deprecated: \"Use Erlang/OTP's :gen_event module instead\"\n\n  @callback init(args :: term) ::\n              {:ok, state}\n              | {:ok, state, :hibernate}\n              | {:error, reason :: term}\n            when state: term\n\n  @callback handle_event(event :: term, state :: term) ::\n              {:ok, new_state}\n              | {:ok, new_state, :hibernate}\n              | :remove_handler\n            when new_state: term\n\n  @callback handle_call(request :: term, state :: term) ::\n              {:ok, reply, new_state}\n              | {:ok, reply, new_state, :hibernate}\n              | {:remove_handler, reply}\n            when reply: term, new_state: term\n\n  @callback handle_info(msg :: term, state :: term) ::\n              {:ok, new_state}\n              | {:ok, new_state, :hibernate}\n              | :remove_handler\n            when new_state: term\n\n  @callback terminate(reason, state :: term) :: term\n            when reason: :stop | {:stop, term} | :remove_handler | {:error, term} | term\n\n  @callback code_change(old_vsn, state :: term, extra :: term) :: {:ok, new_state :: term}\n            when old_vsn: term | {:down, term}\n\n  @type on_start :: {:ok, pid} | {:error, {:already_started, pid}}\n\n  @type name :: atom | {:global, term} | {:via, module, term}\n\n  @type options :: [name: name]\n\n  @type manager :: pid | name | {atom, node}\n\n  @type handler :: atom | {atom, term}\n\n  message = \"Use one of the alternatives described in the documentation for the GenEvent module\"\n\n  @deprecated message\n  @doc false\n  defmacro __using__(_) do\n    deprecation_message =\n      \"the GenEvent module is deprecated, see its documentation for alternatives\"\n\n    IO.warn(deprecation_message, __CALLER__)\n\n    quote location: :keep do\n      @behaviour :gen_event\n\n      @doc false\n      def init(args) do\n        {:ok, args}\n      end\n\n      @doc false\n      def handle_event(_event, state) do\n        {:ok, state}\n      end\n\n      @doc false\n      def handle_call(msg, state) do\n        proc =\n          case Process.info(self(), :registered_name) do\n            {_, []} -> self()\n            {_, name} -> name\n          end\n\n        # We do this to trick Dialyzer to not complain about non-local returns.\n        case :erlang.phash2(1, 1) do\n          0 ->\n            raise \"attempted to call GenEvent #{inspect(proc)} but no handle_call/2 clause was provided\"\n\n          1 ->\n            {:remove_handler, {:bad_call, msg}}\n        end\n      end\n\n      @doc false\n      def handle_info(_msg, state) do\n        {:ok, state}\n      end\n\n      @doc false\n      def terminate(_reason, _state) do\n        :ok\n      end\n\n      @doc false\n      def code_change(_old, state, _extra) do\n        {:ok, state}\n      end\n\n      defoverridable init: 1,\n                     handle_event: 2,\n                     handle_call: 2,\n                     handle_info: 2,\n                     terminate: 2,\n                     code_change: 3\n    end\n  end\n\n  @doc false\n  @deprecated message\n  @spec start_link(options) :: on_start\n  def start_link(options \\\\ []) when is_list(options) do\n    do_start(:link, options)\n  end\n\n  @doc false\n  @deprecated message\n  @spec start(options) :: on_start\n  def start(options \\\\ []) when is_list(options) do\n    do_start(:nolink, options)\n  end\n\n  @no_callback :\"no callback module\"\n\n  defp do_start(mode, options) do\n    case Keyword.get(options, :name) do\n      nil ->\n        :gen.start(GenEvent, mode, @no_callback, [], [])\n\n      atom when is_atom(atom) ->\n        :gen.start(GenEvent, mode, {:local, atom}, @no_callback, [], [])\n\n      {:global, _term} = tuple ->\n        :gen.start(GenEvent, mode, tuple, @no_callback, [], [])\n\n      {:via, via_module, _term} = tuple when is_atom(via_module) ->\n        :gen.start(GenEvent, mode, tuple, @no_callback, [], [])\n\n      other ->\n        raise ArgumentError, \"\"\"\n        expected :name option to be one of the following:\n\n          * nil\n          * atom\n          * {:global, term}\n          * {:via, module, term}\n\n        Got: #{inspect(other)}\n        \"\"\"\n    end\n  end\n\n  @doc false\n  @deprecated message\n  @spec stream(manager, keyword) :: GenEvent.Stream.t()\n  def stream(manager, options \\\\ []) do\n    %GenEvent.Stream{manager: manager, timeout: Keyword.get(options, :timeout, :infinity)}\n  end\n\n  @doc false\n  @deprecated message\n  @spec add_handler(manager, handler, term) :: :ok | {:error, term}\n  def add_handler(manager, handler, args) do\n    rpc(manager, {:add_handler, handler, args})\n  end\n\n  @doc false\n  @deprecated message\n  @spec add_mon_handler(manager, handler, term) :: :ok | {:error, term}\n  def add_mon_handler(manager, handler, args) do\n    rpc(manager, {:add_mon_handler, handler, args, self()})\n  end\n\n  @doc false\n  @deprecated message\n  @spec notify(manager, term) :: :ok\n  def notify(manager, event)\n\n  def notify({:global, name}, msg) do\n    try do\n      :global.send(name, {:notify, msg})\n      :ok\n    catch\n      _, _ -> :ok\n    end\n  end\n\n  def notify({:via, mod, name}, msg) when is_atom(mod) do\n    try do\n      mod.send(name, {:notify, msg})\n      :ok\n    catch\n      _, _ -> :ok\n    end\n  end\n\n  def notify(manager, msg)\n      when is_pid(manager)\n      when is_atom(manager)\n      when tuple_size(manager) == 2 and is_atom(elem(manager, 0)) and is_atom(elem(manager, 1)) do\n    send(manager, {:notify, msg})\n    :ok\n  end\n\n  @doc false\n  @deprecated message\n  @spec sync_notify(manager, term) :: :ok\n  def sync_notify(manager, event) do\n    rpc(manager, {:sync_notify, event})\n  end\n\n  @doc false\n  @deprecated message\n  @spec ack_notify(manager, term) :: :ok\n  def ack_notify(manager, event) do\n    rpc(manager, {:ack_notify, event})\n  end\n\n  @doc false\n  @deprecated message\n  @spec call(manager, handler, term, timeout) :: term | {:error, term}\n  def call(manager, handler, request, timeout \\\\ 5000) do\n    try do\n      :gen.call(manager, self(), {:call, handler, request}, timeout)\n    catch\n      :exit, reason ->\n        exit({reason, {__MODULE__, :call, [manager, handler, request, timeout]}})\n    else\n      {:ok, res} -> res\n    end\n  end\n\n  @doc false\n  @deprecated message\n  @spec remove_handler(manager, handler, term) :: term | {:error, term}\n  def remove_handler(manager, handler, args) do\n    rpc(manager, {:delete_handler, handler, args})\n  end\n\n  @doc false\n  @deprecated message\n  @spec swap_handler(manager, handler, term, handler, term) :: :ok | {:error, term}\n  def swap_handler(manager, handler1, args1, handler2, args2) do\n    rpc(manager, {:swap_handler, handler1, args1, handler2, args2})\n  end\n\n  @doc false\n  @deprecated message\n  @spec swap_mon_handler(manager, handler, term, handler, term) :: :ok | {:error, term}\n  def swap_mon_handler(manager, handler1, args1, handler2, args2) do\n    rpc(manager, {:swap_mon_handler, handler1, args1, handler2, args2, self()})\n  end\n\n  @doc false\n  @deprecated message\n  @spec which_handlers(manager) :: [handler]\n  def which_handlers(manager) do\n    rpc(manager, :which_handlers)\n  end\n\n  @doc false\n  @deprecated message\n  @spec stop(manager, reason :: term, timeout) :: :ok\n  def stop(manager, reason \\\\ :normal, timeout \\\\ :infinity) do\n    :gen.stop(manager, reason, timeout)\n  end\n\n  defp rpc(module, cmd) do\n    {:ok, reply} = :gen.call(module, self(), cmd, :infinity)\n    reply\n  end\n\n  ## Init callbacks\n\n  require Record\n  Record.defrecordp(:handler, [:module, :id, :state, :pid, :ref])\n\n  @doc false\n  def init_it(starter, :self, name, mod, args, options) do\n    init_it(starter, self(), name, mod, args, options)\n  end\n\n  def init_it(starter, parent, name, _mod, _args, options) do\n    Process.put(:\"$initial_call\", {__MODULE__, :init_it, 6})\n    debug = :gen.debug_options(name, options)\n    :proc_lib.init_ack(starter, {:ok, self()})\n    loop(parent, name(name), [], debug, false)\n  end\n\n  @doc false\n  def init_hib(parent, name, handlers, debug) do\n    fetch_msg(parent, name, handlers, debug, true)\n  end\n\n  defp name({:local, name}), do: name\n  defp name({:global, name}), do: name\n  defp name({:via, _, name}), do: name\n  defp name(pid) when is_pid(pid), do: pid\n\n  ## Loop\n\n  defp loop(parent, name, handlers, debug, true) do\n    :proc_lib.hibernate(__MODULE__, :init_hib, [parent, name, handlers, debug])\n  end\n\n  defp loop(parent, name, handlers, debug, false) do\n    fetch_msg(parent, name, handlers, debug, false)\n  end\n\n  defp fetch_msg(parent, name, handlers, debug, hib) do\n    receive do\n      {:system, from, req} ->\n        :sys.handle_system_msg(req, from, parent, __MODULE__, debug, [name, handlers, hib], hib)\n\n      {:EXIT, ^parent, reason} ->\n        server_terminate(reason, parent, handlers, name)\n\n      msg when debug == [] ->\n        handle_msg(msg, parent, name, handlers, [])\n\n      msg ->\n        debug = :sys.handle_debug(debug, &print_event/3, name, {:in, msg})\n        handle_msg(msg, parent, name, handlers, debug)\n    end\n  end\n\n  defp handle_msg(msg, parent, name, handlers, debug) do\n    case msg do\n      {:notify, event} ->\n        {hib, handlers} = server_event(:async, event, handlers, name)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, _tag, {:notify, event}} ->\n        {hib, handlers} = server_event(:async, event, handlers, name)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, tag, {:ack_notify, event}} ->\n        reply(tag, :ok)\n        {hib, handlers} = server_event(:ack, event, handlers, name)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, tag, {:sync_notify, event}} ->\n        {hib, handlers} = server_event(:sync, event, handlers, name)\n        reply(tag, :ok)\n        loop(parent, name, handlers, debug, hib)\n\n      {:DOWN, ref, :process, _pid, reason} = other ->\n        case handle_down(ref, reason, handlers, name) do\n          {:ok, handlers} ->\n            loop(parent, name, handlers, debug, false)\n\n          :error ->\n            {hib, handlers} = server_info(other, handlers, name)\n            loop(parent, name, handlers, debug, hib)\n        end\n\n      {_from, tag, {:call, handler, query}} ->\n        {hib, reply, handlers} = server_call(handler, query, handlers, name)\n        reply(tag, reply)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, tag, {:add_handler, handler, args}} ->\n        {hib, reply, handlers} = server_add_handler(handler, args, handlers)\n        reply(tag, reply)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, tag, {:add_mon_handler, handler, args, notify}} ->\n        {hib, reply, handlers} = server_add_mon_handler(handler, args, handlers, notify)\n        reply(tag, reply)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, tag, {:add_process_handler, pid, notify}} ->\n        {hib, reply, handlers} = server_add_process_handler(pid, handlers, notify)\n        reply(tag, reply)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, tag, {:delete_handler, handler, args}} ->\n        {reply, handlers} = server_remove_handler(handler, args, handlers, name)\n        reply(tag, reply)\n        loop(parent, name, handlers, debug, false)\n\n      {_from, tag, {:swap_handler, handler1, args1, handler2, args2}} ->\n        {hib, reply, handlers} =\n          server_swap_handler(handler1, args1, handler2, args2, handlers, nil, name)\n\n        reply(tag, reply)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, tag, {:swap_mon_handler, handler1, args1, handler2, args2, mon}} ->\n        {hib, reply, handlers} =\n          server_swap_handler(handler1, args1, handler2, args2, handlers, mon, name)\n\n        reply(tag, reply)\n        loop(parent, name, handlers, debug, hib)\n\n      {_from, tag, :which_handlers} ->\n        reply(tag, server_which_handlers(handlers))\n        loop(parent, name, handlers, debug, false)\n\n      {_from, tag, :get_modules} ->\n        reply(tag, server_get_modules(handlers))\n        loop(parent, name, handlers, debug, false)\n\n      other ->\n        {hib, handlers} = server_info(other, handlers, name)\n        loop(parent, name, handlers, debug, hib)\n    end\n  end\n\n  ## System callbacks\n\n  @doc false\n  def system_continue(parent, debug, [name, handlers, hib]) do\n    loop(parent, name, handlers, debug, hib)\n  end\n\n  @doc false\n  def system_terminate(reason, parent, _debug, [name, handlers, _hib]) do\n    server_terminate(reason, parent, handlers, name)\n  end\n\n  @doc false\n  def system_code_change([name, handlers, hib], module, old_vsn, extra) do\n    handlers =\n      for handler <- handlers do\n        if handler(handler, :module) == module do\n          {:ok, state} = module.code_change(old_vsn, handler(handler, :state), extra)\n          handler(handler, state: state)\n        else\n          handler\n        end\n      end\n\n    {:ok, [name, handlers, hib]}\n  end\n\n  @doc false\n  def system_get_state([_name, handlers, _hib]) do\n    tuples =\n      for handler(module: mod, id: id, state: state) <- handlers do\n        {mod, id, state}\n      end\n\n    {:ok, tuples}\n  end\n\n  @doc false\n  def system_replace_state(fun, [name, handlers, hib]) do\n    {handlers, states} =\n      :lists.unzip(\n        for handler <- handlers do\n          handler(module: mod, id: id, state: state) = handler\n          cur = {mod, id, state}\n\n          try do\n            new = {^mod, ^id, new_state} = fun.(cur)\n            {handler(handler, state: new_state), new}\n          catch\n            _, _ ->\n              {handler, cur}\n          end\n        end\n      )\n\n    {:ok, states, [name, handlers, hib]}\n  end\n\n  # Keeping deprecated format_status/2 since the current implementation is not\n  # compatible with format_status/1 and GenEvent is deprecated anyway\n  @doc false\n  def format_status(opt, status_data) do\n    [pdict, sys_state, parent, _debug, [name, handlers, _hib]] = status_data\n    header = :gen.format_status_header(~c\"Status for event handler\", name)\n\n    formatted =\n      for handler <- handlers do\n        handler(module: module, state: state) = handler\n\n        if function_exported?(module, :format_status, 2) do\n          try do\n            state = module.format_status(opt, [pdict, state])\n            handler(handler, state: state)\n          catch\n            _, _ -> handler\n          end\n        else\n          handler\n        end\n      end\n\n    [\n      header: header,\n      data: [{~c\"Status\", sys_state}, {~c\"Parent\", parent}],\n      items: {~c\"Installed handlers\", formatted}\n    ]\n  end\n\n  ## Loop helpers\n\n  defp print_event(dev, {:in, msg}, name) do\n    case msg do\n      {:notify, event} ->\n        IO.puts(dev, \"*DBG* #{inspect(name)} got event #{inspect(event)}\")\n\n      {_, _, {:call, handler, query}} ->\n        IO.puts(\n          dev,\n          \"*DBG* #{inspect(name)} (handler #{inspect(handler)}) got call #{inspect(query)}\"\n        )\n\n      _ ->\n        IO.puts(dev, \"*DBG* #{inspect(name)} got #{inspect(msg)}\")\n    end\n  end\n\n  defp print_event(dev, dbg, name) do\n    IO.puts(dev, \"*DBG* #{inspect(name)}: #{inspect(dbg)}\")\n  end\n\n  defp server_add_handler({module, id}, args, handlers) do\n    handler = handler(module: module, id: {module, id})\n    do_add_handler(module, handler, args, handlers, :ok)\n  end\n\n  defp server_add_handler(module, args, handlers) do\n    handler = handler(module: module, id: module)\n    do_add_handler(module, handler, args, handlers, :ok)\n  end\n\n  defp server_add_mon_handler({module, id}, args, handlers, notify) do\n    ref = Process.monitor(notify)\n    handler = handler(module: module, id: {module, id}, pid: notify, ref: ref)\n    do_add_handler(module, handler, args, handlers, :ok)\n  end\n\n  defp server_add_mon_handler(module, args, handlers, notify) do\n    ref = Process.monitor(notify)\n    handler = handler(module: module, id: module, pid: notify, ref: ref)\n    do_add_handler(module, handler, args, handlers, :ok)\n  end\n\n  defp server_add_process_handler(pid, handlers, notify) do\n    ref = Process.monitor(pid)\n    handler = handler(module: GenEvent.Stream, id: {self(), ref}, pid: notify, ref: ref)\n    do_add_handler(GenEvent.Stream, handler, {pid, ref}, handlers, {self(), ref})\n  end\n\n  defp server_remove_handler(module, args, handlers, name) do\n    do_take_handler(module, args, handlers, name, :remove, :normal)\n  end\n\n  defp server_swap_handler(module1, args1, module2, args2, handlers, sup, name) do\n    {state, handlers} =\n      do_take_handler(module1, args1, handlers, name, :swapped, {:swapped, module2, sup})\n\n    if sup do\n      server_add_mon_handler(module2, {args2, state}, handlers, sup)\n    else\n      server_add_handler(module2, {args2, state}, handlers)\n    end\n  end\n\n  defp server_info(event, handlers, name) do\n    handlers = :lists.reverse(handlers)\n    server_notify(event, :handle_info, handlers, name, handlers, [], false)\n  end\n\n  defp server_event(mode, event, handlers, name) do\n    {handlers, streams} = server_split_process_handlers(mode, event, handlers, [], [])\n    {hib, handlers} = server_notify(event, :handle_event, handlers, name, handlers, [], false)\n    {hib, server_collect_process_handlers(mode, event, streams, handlers, name)}\n  end\n\n  defp server_split_process_handlers(mode, event, [handler | t], handlers, streams) do\n    case handler(handler, :id) do\n      {pid, _ref} when is_pid(pid) ->\n        server_process_notify(mode, event, handler)\n        server_split_process_handlers(mode, event, t, handlers, [handler | streams])\n\n      _ ->\n        server_split_process_handlers(mode, event, t, [handler | handlers], streams)\n    end\n  end\n\n  defp server_split_process_handlers(_mode, _event, [], handlers, streams) do\n    {handlers, streams}\n  end\n\n  defp server_process_notify(mode, event, handler(state: {pid, ref})) do\n    send(pid, {self(), {self(), ref}, {mode_to_tag(mode), event}})\n  end\n\n  defp mode_to_tag(:ack), do: :ack_notify\n  defp mode_to_tag(:sync), do: :sync_notify\n  defp mode_to_tag(:async), do: :notify\n\n  defp server_notify(event, fun, [handler | t], name, handlers, acc, hib) do\n    case server_update(handler, fun, event, name, handlers) do\n      {new_hib, handler} ->\n        server_notify(event, fun, t, name, handlers, [handler | acc], hib or new_hib)\n\n      :error ->\n        server_notify(event, fun, t, name, handlers, acc, hib)\n    end\n  end\n\n  defp server_notify(_, _, [], _, _, acc, hib) do\n    {hib, acc}\n  end\n\n  defp server_update(handler, fun, event, name, _handlers) do\n    handler(module: module, state: state) = handler\n\n    case do_handler(module, fun, [event, state]) do\n      {:ok, res} ->\n        case res do\n          {:ok, state} ->\n            {false, handler(handler, state: state)}\n\n          {:ok, state, :hibernate} ->\n            {true, handler(handler, state: state)}\n\n          :remove_handler ->\n            do_terminate(handler, :remove_handler, event, name, :normal)\n            :error\n\n          other ->\n            reason = {:bad_return_value, other}\n            do_terminate(handler, {:error, reason}, event, name, reason)\n            :error\n        end\n\n      {:error, reason} ->\n        do_terminate(handler, {:error, reason}, event, name, reason)\n        :error\n    end\n  end\n\n  defp server_collect_process_handlers(:async, event, [handler | t], handlers, name) do\n    server_collect_process_handlers(:async, event, t, [handler | handlers], name)\n  end\n\n  defp server_collect_process_handlers(mode, event, [handler | t], handlers, name)\n       when mode in [:sync, :ack] do\n    handler(ref: ref, id: id) = handler\n\n    receive do\n      {^ref, :ok} ->\n        server_collect_process_handlers(mode, event, t, [handler | handlers], name)\n\n      {_from, tag, {:delete_handler, ^id, args}} ->\n        do_terminate(handler, args, :remove, name, :normal)\n        reply(tag, :ok)\n        server_collect_process_handlers(mode, event, t, handlers, name)\n\n      {:DOWN, ^ref, _, _, reason} ->\n        do_terminate(handler, {:stop, reason}, :DOWN, name, :shutdown)\n        server_collect_process_handlers(mode, event, t, handlers, name)\n    end\n  end\n\n  defp server_collect_process_handlers(_mode, _event, [], handlers, _name) do\n    handlers\n  end\n\n  defp server_call(module, query, handlers, name) do\n    case :lists.keyfind(module, handler(:id) + 1, handlers) do\n      false ->\n        {false, {:error, :not_found}, handlers}\n\n      handler ->\n        case server_call_update(handler, query, name, handlers) do\n          {{hib, handler}, reply} ->\n            {hib, reply, :lists.keyreplace(module, handler(:id) + 1, handlers, handler)}\n\n          {:error, reply} ->\n            {false, reply, :lists.keydelete(module, handler(:id) + 1, handlers)}\n        end\n    end\n  end\n\n  defp server_call_update(handler, query, name, _handlers) do\n    handler(module: module, state: state) = handler\n\n    case do_handler(module, :handle_call, [query, state]) do\n      {:ok, res} ->\n        case res do\n          {:ok, reply, state} ->\n            {{false, handler(handler, state: state)}, reply}\n\n          {:ok, reply, state, :hibernate} ->\n            {{true, handler(handler, state: state)}, reply}\n\n          {:remove_handler, reply} ->\n            do_terminate(handler, :remove_handler, query, name, :normal)\n            {:error, reply}\n\n          other ->\n            reason = {:bad_return_value, other}\n            do_terminate(handler, {:error, reason}, query, name, reason)\n            {:error, {:error, reason}}\n        end\n\n      {:error, reason} ->\n        do_terminate(handler, {:error, reason}, query, name, reason)\n        {:error, {:error, reason}}\n    end\n  end\n\n  defp server_get_modules(handlers) do\n    for(handler(module: module) <- handlers, do: module)\n    |> :ordsets.from_list()\n    |> :ordsets.to_list()\n  end\n\n  defp server_which_handlers(handlers) do\n    for handler(id: id) <- handlers, do: id\n  end\n\n  defp server_terminate(reason, _parent, handlers, name) do\n    _ =\n      for handler <- handlers do\n        do_terminate(handler, :stop, :stop, name, :shutdown)\n      end\n\n    exit(reason)\n  end\n\n  defp reply({from, ref}, msg) do\n    send(from, {ref, msg})\n  end\n\n  defp handle_down(ref, reason, handlers, name) do\n    case :lists.keyfind(ref, handler(:ref) + 1, handlers) do\n      false ->\n        :error\n\n      handler ->\n        do_terminate(handler, {:stop, reason}, :DOWN, name, :shutdown)\n        {:ok, :lists.keydelete(ref, handler(:ref) + 1, handlers)}\n    end\n  end\n\n  defp do_add_handler(module, handler, arg, handlers, succ) do\n    case :lists.keyfind(handler(handler, :id), handler(:id) + 1, handlers) do\n      false ->\n        case do_handler(module, :init, [arg]) do\n          {:ok, res} ->\n            case res do\n              {:ok, state} ->\n                {false, succ, [handler(handler, state: state) | handlers]}\n\n              {:ok, state, :hibernate} ->\n                {true, succ, [handler(handler, state: state) | handlers]}\n\n              {:error, _} = error ->\n                {false, error, handlers}\n\n              other ->\n                {false, {:error, {:bad_return_value, other}}, handlers}\n            end\n\n          {:error, _} = error ->\n            {false, error, handlers}\n        end\n\n      _ ->\n        {false, {:error, :already_present}, handlers}\n    end\n  end\n\n  defp do_take_handler(module, args, handlers, name, last_in, reason) do\n    case :lists.keytake(module, handler(:id) + 1, handlers) do\n      {:value, handler, handlers} ->\n        {do_terminate(handler, args, last_in, name, reason), handlers}\n\n      false ->\n        {{:error, :not_found}, handlers}\n    end\n  end\n\n  defp do_terminate(handler, arg, last_in, name, reason) do\n    handler(module: module, state: state) = handler\n\n    res =\n      case do_handler(module, :terminate, [arg, state]) do\n        {:ok, res} -> res\n        {:error, _} = error -> error\n      end\n\n    report_terminate(handler, reason, state, last_in, name)\n    res\n  end\n\n  defp do_handler(mod, fun, args) do\n    try do\n      apply(mod, fun, args)\n    catch\n      :throw, val -> {:ok, val}\n      :error, val -> {:error, {val, __STACKTRACE__}}\n      :exit, val -> {:error, val}\n    else\n      res -> {:ok, res}\n    end\n  end\n\n  defp report_terminate(handler, reason, state, last_in, name) do\n    report_error(handler, reason, state, last_in, name)\n\n    if ref = handler(handler, :ref) do\n      Process.demonitor(ref, [:flush])\n    end\n\n    if pid = handler(handler, :pid) do\n      send(pid, {:gen_event_EXIT, handler(handler, :id), reason})\n    end\n  end\n\n  defp report_error(_handler, :normal, _, _, _), do: :ok\n  defp report_error(_handler, :shutdown, _, _, _), do: :ok\n  defp report_error(_handler, {:swapped, _, _}, _, _, _), do: :ok\n\n  defp report_error(handler, reason, state, last_in, name) do\n    reason =\n      case reason do\n        {:undef, [{m, f, a, _} | _] = mfas} ->\n          cond do\n            :code.is_loaded(m) == false ->\n              {:\"module could not be loaded\", mfas}\n\n            function_exported?(m, f, length(a)) ->\n              reason\n\n            true ->\n              {:\"function not exported\", mfas}\n          end\n\n        _ ->\n          reason\n      end\n\n    formatted = report_status(handler, state)\n\n    :error_logger.error_msg(\n      ~c\"** gen_event handler ~p crashed.~n\" ++\n        ~c\"** Was installed in ~p~n\" ++\n        ~c\"** Last event was: ~p~n\" ++ ~c\"** When handler state == ~p~n\" ++ ~c\"** Reason == ~p~n\",\n      [handler(handler, :id), name, last_in, formatted, reason]\n    )\n  end\n\n  defp report_status(handler(module: module), state) do\n    if function_exported?(module, :format_status, 2) do\n      try do\n        module.format_status(:terminate, [Process.get(), state])\n      catch\n        _, _ -> state\n      end\n    else\n      state\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/gen_server.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule GenServer do\n  @moduledoc \"\"\"\n  A behaviour module for implementing the server of a client-server relation.\n\n  A GenServer is a process like any other Elixir process and it can be used\n  to keep state, execute code asynchronously and so on. The advantage of using\n  a generic server process (GenServer) implemented using this module is that it\n  will have a standard set of interface functions and include functionality for\n  tracing and error reporting. It will also fit into a supervision tree.\n\n  ```mermaid\n  graph BT\n      C(Client #3) ~~~ B(Client #2) ~~~ A(Client #1)\n      A & B & C -->|request| GenServer\n      GenServer -.->|reply| A & B & C\n  ```\n\n  ## Example\n\n  The GenServer behaviour abstracts the common client-server interaction.\n  Developers are only required to implement the callbacks and functionality\n  they are interested in.\n\n  Let's start with a code example and then explore the available callbacks.\n  Imagine we want to implement a service with a GenServer that works\n  like a stack, allowing us to push and pop elements. We'll customize a\n  generic GenServer with our own module by implementing three callbacks.\n\n  `c:init/1` transforms our initial argument to the initial state for the\n  GenServer. `c:handle_call/3` fires when the server receives a synchronous\n  `pop` message, popping an element from the stack and returning it to the\n  user. `c:handle_cast/2` will fire when the server receives an asynchronous\n  `push` message, pushing an element onto the stack:\n\n      defmodule Stack do\n        use GenServer\n\n        # Callbacks\n\n        @impl true\n        def init(elements) do\n          initial_state = String.split(elements, \",\", trim: true)\n          {:ok, initial_state}\n        end\n\n        @impl true\n        def handle_call(:pop, _from, state) do\n          [to_caller | new_state] = state\n          {:reply, to_caller, new_state}\n        end\n\n        @impl true\n        def handle_cast({:push, element}, state) do\n          new_state = [element | state]\n          {:noreply, new_state}\n        end\n      end\n\n  We leave the process machinery of startup, message passing, and the message\n  loop to the GenServer behaviour and focus only on the stack\n  implementation. We can now use the GenServer API to interact with\n  the service by creating a process and sending it messages:\n\n      # Start the server\n      {:ok, pid} = GenServer.start_link(Stack, \"hello,world\")\n\n      # This is the client\n      GenServer.call(pid, :pop)\n      #=> \"hello\"\n\n      GenServer.cast(pid, {:push, \"elixir\"})\n      #=> :ok\n\n      GenServer.call(pid, :pop)\n      #=> \"elixir\"\n\n  We start our `Stack` by calling `start_link/2`, passing the module\n  with the server implementation and its initial argument with a\n  comma-separated list of elements. The GenServer behaviour calls the\n  `c:init/1` callback to establish the initial GenServer state. From\n  this point on, the GenServer has control so we interact with it by\n  sending two types of messages on the client. **call** messages expect\n  a reply from the server (and are therefore synchronous) while **cast**\n  messages do not.\n\n  Each call to `GenServer.call/3` results in a message\n  that must be handled by the `c:handle_call/3` callback in the GenServer.\n  A `cast/2` message must be handled by `c:handle_cast/2`. `GenServer`\n  supports 8 callbacks, but only `c:init/1` is required.\n\n  > #### `use GenServer` {: .info}\n  >\n  > When you `use GenServer`, the `GenServer` module will\n  > set `@behaviour GenServer` and define a `child_spec/1`\n  > function, so your module can be used as a child\n  > in a supervision tree.\n\n  ## Client / Server APIs\n\n  Although in the example above we have used `GenServer.start_link/3` and\n  friends to directly start and communicate with the server, most of the\n  time we don't call the `GenServer` functions directly. Instead, we wrap\n  the calls in new functions representing the public API of the server.\n  These thin wrappers are called the **client API**.\n\n  Here is a better implementation of our Stack module:\n\n      defmodule Stack do\n        use GenServer\n\n        # Client\n\n        def start_link(default) when is_binary(default) do\n          GenServer.start_link(__MODULE__, default)\n        end\n\n        def push(pid, element) do\n          GenServer.cast(pid, {:push, element})\n        end\n\n        def pop(pid) do\n          GenServer.call(pid, :pop)\n        end\n\n        # Server (callbacks)\n\n        @impl true\n        def init(elements) do\n          initial_state = String.split(elements, \",\", trim: true)\n          {:ok, initial_state}\n        end\n\n        @impl true\n        def handle_call(:pop, _from, state) do\n          [to_caller | new_state] = state\n          {:reply, to_caller, new_state}\n        end\n\n        @impl true\n        def handle_cast({:push, element}, state) do\n          new_state = [element | state]\n          {:noreply, new_state}\n        end\n      end\n\n  In practice, it is common to have both server and client functions in\n  the same module. If the server and/or client implementations are growing\n  complex, you may want to have them in different modules.\n\n  The following diagram summarizes the interactions between client and server.\n  Both Client and Server are processes and communication happens via messages\n  (continuous line). The Server <-> Module interaction happens when the\n  GenServer process calls your code (dotted lines):\n\n  ```mermaid\n  sequenceDiagram\n      participant C as Client (Process)\n      participant S as Server (Process)\n      participant M as Module (Code)\n\n      note right of C: Typically started by a supervisor\n      C->>+S: GenServer.start_link(module, arg, options)\n      S-->>+M: init(arg)\n      M-->>-S: {:ok, state} | :ignore | {:error, reason}\n      S->>-C: {:ok, pid} | :ignore | {:error, reason}\n\n      note right of C: call is synchronous\n      C->>+S: GenServer.call(pid, message)\n      S-->>+M: handle_call(message, from, state)\n      M-->>-S: {:reply, reply, state} | {:stop, reason, reply, state}\n      S->>-C: reply\n\n      note right of C: cast is asynchronous\n      C-)S: GenServer.cast(pid, message)\n      S-->>+M: handle_cast(message, state)\n      M-->>-S: {:noreply, state} | {:stop, reason, state}\n\n      note right of C: send is asynchronous\n      C-)S: Kernel.send(pid, message)\n      S-->>+M: handle_info(message, state)\n      M-->>-S: {:noreply, state} | {:stop, reason, state}\n  ```\n\n  ## How to supervise\n\n  A `GenServer` is most commonly started under a supervision tree.\n  When we invoke `use GenServer`, it automatically defines a `child_spec/1`\n  function that allows us to start the `Stack` directly under a supervisor.\n  To start a default stack of `[\"hello\", \"world\"]` under a supervisor,\n  we can do:\n\n      children = [\n        {Stack, \"hello,world\"}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_all)\n\n  Note that specifying a module `MyServer` would be the same as specifying\n  the  tuple `{MyServer, []}`.\n\n  `use GenServer` also accepts a list of options which configures the\n  child specification and therefore how it runs under a supervisor.\n  The generated `child_spec/1` can be customized with the following options:\n\n    * `:id` - the child specification identifier, defaults to the current module\n    * [`:restart`](`m:Supervisor#module-restart-values-restart`) - when the\n      child should be restarted, defaults to `:permanent`\n    * [`:shutdown`](`m:Supervisor#module-shutdown-values-shutdown`) - how to\n      shut down the child, either immediately or by giving it time to shut down,\n      defaults to `5_000`\n\n  For example:\n\n      use GenServer, restart: :transient, shutdown: 10_000\n\n  See the [\"Child specification\"](`m:Supervisor#module-child-specification`) section in the `Supervisor` module for more\n  detailed information. The `@doc` annotation immediately preceding\n  `use GenServer` will be attached to the generated `child_spec/1` function.\n\n  When stopping the GenServer, for example by returning a `{:stop, reason, new_state}`\n  tuple from a callback, the exit reason is used by the supervisor to determine\n  whether the GenServer needs to be restarted. See the \"Exit reasons and restarts\"\n  section in the `Supervisor` module.\n\n  ## Name registration\n\n  Both `start_link/3` and `start/3` support the `GenServer` to register\n  a name on start via the `:name` option. Registered names are also\n  automatically cleaned up on termination. The supported values are:\n\n    * `nil` (default) - the GenServer is not registered with a name.\n\n    * an atom - the GenServer is registered locally (to the current node)\n      with the given name using `Process.register/2`.\n\n    * `{:global, term}` - the GenServer is registered globally with the given\n      term using the functions in the [`:global` module](`:global`).\n\n    * `{:via, module, term}` - the GenServer is registered with the given\n      mechanism and name. The `:via` option expects a module that exports\n      `register_name/2`, `unregister_name/1`, `whereis_name/1` and `send/2`.\n      One such example is the [`:global` module](`:global`) which uses these functions\n      for keeping the list of names of processes and their associated PIDs\n      that are available globally for a network of Elixir nodes. Elixir also\n      ships with a local, decentralized and scalable registry called `Registry`\n      for locally storing names that are generated dynamically.\n\n  For example, we could start and register our `Stack` server locally as follows:\n\n      # Start the server and register it locally with name MyStack\n      {:ok, _} = GenServer.start_link(Stack, \"hello\", name: MyStack)\n\n      # Now messages can be sent directly to MyStack\n      GenServer.call(MyStack, :pop)\n      #=> \"hello\"\n\n  Once the server is started, the remaining functions in this module (`call/3`,\n  `cast/2`, and friends) will also accept an atom, or any `{:global, ...}` or\n  `{:via, ...}` tuples. In general, the following formats are supported:\n\n    * a PID\n    * an atom if the server is locally registered\n    * `{atom, node}` if the server is locally registered at another node\n    * `{:global, term}` if the server is globally registered\n    * `{:via, module, name}` if the server is registered through an alternative\n      registry\n\n  If there is an interest to register dynamic names locally, do not use\n  atoms, as atoms are never garbage-collected and therefore dynamically\n  generated atoms won't be garbage-collected. For such cases, you can\n  set up your own local registry by using the `Registry` module.\n\n  For example:\n\n      {:ok, _} = Registry.start_link(keys: :unique, name: :stacks)\n      name = {:via, Registry, {:stacks, \"stack 1\"}}\n      {:ok, _pid} = GenServer.start_link(Stack, \"hello\", name: name)\n      GenServer.whereis(name)\n      #=> #PID<0.150.0>\n\n  ## Receiving \"regular\" messages\n\n  The goal of a `GenServer` is to abstract the \"receive\" loop for developers,\n  automatically handling system messages, supporting code change, synchronous\n  calls and more. Therefore, you should never call your own \"receive\" inside\n  the GenServer callbacks as doing so will cause the GenServer to misbehave.\n\n  Besides the synchronous and asynchronous communication provided by `call/3`\n  and `cast/2`, \"regular\" messages sent by functions such as `send/2`,\n  `Process.send_after/4` and similar, can be handled inside the `c:handle_info/2`\n  callback.\n\n  `c:handle_info/2` can be used in many situations, such as handling monitor\n  DOWN messages sent by `Process.monitor/1`. Another use case for `c:handle_info/2`\n  is to perform periodic work, with the help of `Process.send_after/4`:\n\n      defmodule MyApp.Periodically do\n        use GenServer\n\n        def start_link(_) do\n          GenServer.start_link(__MODULE__, %{})\n        end\n\n        @impl true\n        def init(state) do\n          # Schedule work to be performed on start\n          schedule_work()\n\n          {:ok, state}\n        end\n\n        @impl true\n        def handle_info(:work, state) do\n          # Do the desired work here\n          # ...\n\n          # Reschedule once more\n          schedule_work()\n\n          {:noreply, state}\n        end\n\n        defp schedule_work do\n          # We schedule the work to happen in 2 hours (written in milliseconds).\n          # Alternatively, one might write :timer.hours(2)\n          Process.send_after(self(), :work, 2 * 60 * 60 * 1000)\n        end\n      end\n\n  ## Timeouts\n\n  The return value of `c:init/1` or any of the `handle_*` callbacks may include\n  a timeout value in milliseconds; if not, `:infinity` is assumed.\n  The timeout can be used to detect a lull in incoming messages.\n\n  The `timeout()` value is used as follows:\n\n    * If the process has any message already waiting when the `timeout()` value\n      is returned, the timeout is ignored and the waiting message is handled as\n      usual. This means that even a timeout of `0` milliseconds is not guaranteed\n      to execute (if you want to take another action immediately and unconditionally,\n      use a `:continue` instruction instead).\n\n    * If any message arrives before the specified number of milliseconds\n      elapse, the timeout is cleared and that message is handled as usual.\n\n    * Otherwise, when the specified number of milliseconds have elapsed with no\n      message arriving, `handle_info/2` is called with `:timeout` as the first\n      argument.\n\n  For example:\n\n      defmodule Counter do\n        use GenServer\n\n        @timeout to_timeout(second: 5)\n\n        @impl true\n        def init(count) do\n          {:ok, count, @timeout}\n        end\n\n        @impl true\n        def handle_call(:increment, _from, count) do\n          new_count = count + 1\n          {:reply, new_count, new_count, @timeout}\n        end\n\n        @impl true\n        def handle_info(:timeout, count) do\n          {:stop, :normal, count}\n        end\n      end\n\n  A `Counter` server will exit with `:normal` if there are no messages in 5 seconds\n  after the initialization or after the last `:increment` call:\n\n      {:ok, counter_pid} = GenServer.start(Counter, 50)\n      GenServer.call(counter_pid, :increment)\n      #=> 51\n\n      # After 5 seconds\n      Process.alive?(counter_pid)\n      #=> false\n\n  ## When (not) to use a GenServer\n\n  So far, we have learned that a `GenServer` can be used as a supervised process\n  that handles sync and async calls. It can also handle system messages, such as\n  periodic messages and monitoring events. GenServer processes may also be named.\n\n  A GenServer, or a process in general, must be used to model runtime characteristics\n  of your system. A GenServer must never be used for code organization purposes.\n\n  In Elixir, code organization is done by modules and functions, processes are not\n  necessary. For example, imagine you are implementing a calculator and you decide\n  to put all the calculator operations behind a GenServer:\n\n      def add(a, b) do\n        GenServer.call(__MODULE__, {:add, a, b})\n      end\n\n      def subtract(a, b) do\n        GenServer.call(__MODULE__, {:subtract, a, b})\n      end\n\n      def handle_call({:add, a, b}, _from, state) do\n        {:reply, a + b, state}\n      end\n\n      def handle_call({:subtract, a, b}, _from, state) do\n        {:reply, a - b, state}\n      end\n\n  This is an anti-pattern not only because it convolutes the calculator logic but\n  also because you put the calculator logic behind a single process that will\n  potentially become a bottleneck in your system, especially as the number of\n  calls grow. Instead just define the functions directly:\n\n      def add(a, b) do\n        a + b\n      end\n\n      def subtract(a, b) do\n        a - b\n      end\n\n  If you don't need a process, then you don't need a process. Use processes only to\n  model runtime properties, such as mutable state, concurrency and failures, never\n  for code organization.\n\n  ## Debugging with the :sys module\n\n  GenServers, as [special processes](https://www.erlang.org/doc/design_principles/spec_proc.html),\n  can be debugged using the [`:sys` module](`:sys`).\n  Through various hooks, this module allows developers to introspect the state of\n  the process and trace system events that happen during its execution, such as\n  received messages, sent replies and state changes.\n\n  Let's explore the basic functions from the\n  [`:sys` module](`:sys`) used for debugging:\n\n    * `:sys.get_state/2` - allows retrieval of the state of the process.\n      In the case of a GenServer process, it will be the callback module state,\n      as passed into the callback functions as last argument.\n    * `:sys.get_status/2` - allows retrieval of the status of the process.\n      This status includes the process dictionary, if the process is running\n      or is suspended, the parent PID, the debugger state, and the state of\n      the behaviour module, which includes the callback module state\n      (as returned by `:sys.get_state/2`). It's possible to change how this\n      status is represented by defining the optional `c:GenServer.format_status/1`\n      callback.\n    * `:sys.trace/3` - prints all the system events to `:stdio`.\n    * `:sys.statistics/3` - manages collection of process statistics.\n    * `:sys.no_debug/2` - turns off all debug handlers for the given process.\n      It is very important to switch off debugging once we're done. Excessive\n      debug handlers or those that should be turned off, but weren't, can\n      seriously damage the performance of the system.\n    * `:sys.suspend/2` - allows to suspend a process so that it only\n      replies to system messages but no other messages. A suspended process\n      can be reactivated via `:sys.resume/2`.\n\n  Let's see how we could use those functions for debugging the stack server\n  we defined earlier.\n\n      iex> {:ok, pid} = Stack.start_link(\"\")\n      iex> :sys.statistics(pid, true) # turn on collecting process statistics\n      iex> :sys.trace(pid, true) # turn on event printing\n      iex> Stack.push(pid, 1)\n      *DBG* <0.122.0> got cast {push,1}\n      *DBG* <0.122.0> new state [1]\n      :ok\n\n      iex> :sys.get_state(pid)\n      [1]\n\n      iex> Stack.pop(pid)\n      *DBG* <0.122.0> got call pop from <0.80.0>\n      *DBG* <0.122.0> sent 1 to <0.80.0>, new state []\n      1\n\n      iex> :sys.statistics(pid, :get)\n      {:ok,\n       [\n         start_time: {{2016, 7, 16}, {12, 29, 41}},\n         current_time: {{2016, 7, 16}, {12, 29, 50}},\n         reductions: 117,\n         messages_in: 2,\n         messages_out: 0\n       ]}\n\n      iex> :sys.no_debug(pid) # turn off all debug handlers\n      :ok\n\n      iex> :sys.get_status(pid)\n      {:status, #PID<0.122.0>, {:module, :gen_server},\n       [\n         [\n           \"$initial_call\": {Stack, :init, 1},            # process dictionary\n           \"$ancestors\": [#PID<0.80.0>, #PID<0.51.0>]\n         ],\n         :running,                                        # :running | :suspended\n         #PID<0.80.0>,                                    # parent\n         [],                                              # debugger state\n         [\n           header: 'Status for generic server <0.122.0>', # module status\n           data: [\n             {'Status', :running},\n             {'Parent', #PID<0.80.0>},\n             {'Logged events', []}\n           ],\n           data: [{'State', [1]}]\n         ]\n       ]}\n\n  ## Learn more\n\n  If you wish to find out more about GenServers, the Elixir Getting Started\n  guide provides a tutorial-like introduction. The documentation and links\n  in Erlang can also provide extra insight.\n\n    * [GenServer - Elixir's Getting Started Guide](genservers.md)\n    * [`:gen_server` module documentation](`:gen_server`)\n    * [gen_server Behaviour - OTP Design Principles](https://www.erlang.org/doc/design_principles/gen_server_concepts.html)\n    * [Clients and Servers - Learn You Some Erlang for Great Good!](https://learnyousomeerlang.com/clients-and-servers)\n\n  \"\"\"\n\n  @doc \"\"\"\n  Invoked when the server is started. `start_link/3` or `start/3` will\n  block until it returns.\n\n  `init_arg` is the argument term (second argument) passed to `start_link/3`.\n\n  Returning `{:ok, state}` will cause `start_link/3` to return\n  `{:ok, pid}` and the process to enter its loop.\n\n  Returning `{:ok, state, timeout}` is similar to `{:ok, state}`,\n  except that it also sets a timeout. See the \"Timeouts\" section\n  in the module documentation for more information.\n\n  Returning `{:ok, state, :hibernate}` is similar to `{:ok, state}`\n  except the process is hibernated before entering the loop. See\n  `c:handle_call/3` for more information on hibernation.\n\n  Returning `{:ok, state, {:continue, continue_arg}}` is similar to\n  `{:ok, state}` except that immediately after entering the loop,\n  the `c:handle_continue/2` callback will be invoked with `continue_arg`\n  as the first argument and `state` as the second one.\n\n  Returning `:ignore` will cause `start_link/3` to return `:ignore` and\n  the process will exit normally without entering the loop or calling\n  `c:terminate/2`. If used when part of a supervision tree the parent\n  supervisor will not fail to start nor immediately try to restart the\n  `GenServer`. The remainder of the supervision tree will be started\n  and so the `GenServer` should not be required by other processes.\n  It can be started later with `Supervisor.restart_child/2` as the child\n  specification is saved in the parent supervisor. The main use cases for\n  this are:\n\n    * The `GenServer` is disabled by configuration but might be enabled later.\n    * An error occurred and it will be handled by a different mechanism than the\n     `Supervisor`. Likely this approach involves calling `Supervisor.restart_child/2`\n      after a delay to attempt a restart.\n\n  Returning `{:stop, reason}` will cause `start_link/3` to return\n  `{:error, reason}` and the process to exit with reason `reason` without\n  entering the loop or calling `c:terminate/2`.\n  \"\"\"\n  @callback init(init_arg :: term) ::\n              {:ok, state}\n              | {:ok, state, timeout | :hibernate | {:continue, continue_arg :: term}}\n              | :ignore\n              | {:stop, reason :: term}\n            when state: term\n\n  @doc \"\"\"\n  Invoked to handle synchronous `call/3` messages. `call/3` will block until a\n  reply is received (unless the call times out or nodes are disconnected).\n\n  `request` is the request message sent by a `call/3`, `from` is a 2-tuple\n  containing the caller's PID and a term that uniquely identifies the call, and\n  `state` is the current state of the `GenServer`.\n\n  Returning `{:reply, reply, new_state}` sends the response `reply` to the\n  caller and continues the loop with new state `new_state`.\n\n  Returning `{:reply, reply, new_state, timeout}` is similar to\n  `{:reply, reply, new_state}` except that it also sets a timeout.\n  See the \"Timeouts\" section in the module documentation for more information.\n\n  Returning `{:reply, reply, new_state, :hibernate}` is similar to\n  `{:reply, reply, new_state}` except the process is hibernated and will\n  continue the loop once a message is in its message queue. However, if a message is\n  already in the message queue, the process will continue the loop immediately.\n  Hibernating a `GenServer` causes garbage collection and leaves a continuous\n  heap that minimises the memory used by the process.\n\n  Hibernating should not be used aggressively as too much time could be spent\n  garbage collecting, which would delay the processing of incoming messages.\n  Normally it should only be used when you are not expecting new messages to\n  immediately arrive and minimising the memory of the process is shown to be\n  beneficial.\n\n  Returning `{:reply, reply, new_state, {:continue, continue_arg}}` is similar to\n  `{:reply, reply, new_state}` except that `c:handle_continue/2` will be invoked\n  immediately after with `continue_arg` as the first argument and\n  `state` as the second one.\n\n  Returning `{:noreply, new_state}` does not send a response to the caller and\n  continues the loop with new state `new_state`. The response must be sent with\n  `reply/2`.\n\n  There are three main use cases for not replying using the return value:\n\n    * To reply before returning from the callback because the response is known\n      before calling a slow function.\n    * To reply after returning from the callback because the response is not yet\n      available.\n    * To reply from another process, such as a task.\n\n  When replying from another process the `GenServer` should exit if the other\n  process exits without replying as the caller will be blocking awaiting a\n  reply.\n\n  Returning `{:noreply, new_state, timeout | :hibernate | {:continue, continue_arg}}`\n  is similar to `{:noreply, new_state}` except a timeout, hibernation or continue\n  occurs as with a `:reply` tuple.\n\n  Returning `{:stop, reason, reply, new_state}` stops the loop and `c:terminate/2`\n  is called with reason `reason` and state `new_state`. Then, the `reply` is sent\n  as the response to call and the process exits with reason `reason`.\n\n  Returning `{:stop, reason, new_state}` is similar to\n  `{:stop, reason, reply, new_state}` except a reply is not sent.\n\n  This callback is optional. If one is not implemented, the server will fail\n  if a call is performed against it.\n  \"\"\"\n  @callback handle_call(request :: term, from, state :: term) ::\n              {:reply, reply, new_state}\n              | {:reply, reply, new_state,\n                 timeout | :hibernate | {:continue, continue_arg :: term}}\n              | {:noreply, new_state}\n              | {:noreply, new_state, timeout | :hibernate | {:continue, continue_arg :: term}}\n              | {:stop, reason, reply, new_state}\n              | {:stop, reason, new_state}\n            when reply: term, new_state: term, reason: term\n\n  @doc \"\"\"\n  Invoked to handle asynchronous `cast/2` messages.\n\n  `request` is the request message sent by a `cast/2` and `state` is the current\n  state of the `GenServer`.\n\n  Returning `{:noreply, new_state}` continues the loop with new state `new_state`.\n\n  Returning `{:noreply, new_state, timeout}` is similar to `{:noreply, new_state}`\n  except that it also sets a timeout. See the \"Timeouts\" section in the module\n  documentation for more information.\n\n  Returning `{:noreply, new_state, :hibernate}` is similar to\n  `{:noreply, new_state}` except the process is hibernated before continuing the\n  loop. See `c:handle_call/3` for more information.\n\n  Returning `{:noreply, new_state, {:continue, continue_arg}}` is similar to\n  `{:noreply, new_state}` except `c:handle_continue/2` will be invoked\n  immediately after with `continue_arg` as the first argument and\n  `state` as the second one.\n\n  Returning `{:stop, reason, new_state}` stops the loop and `c:terminate/2` is\n  called with the reason `reason` and state `new_state`. The process exits with\n  reason `reason`.\n\n  This callback is optional. If one is not implemented, the server will fail\n  if a cast is performed against it.\n  \"\"\"\n  @callback handle_cast(request :: term, state :: term) ::\n              {:noreply, new_state}\n              | {:noreply, new_state, timeout | :hibernate | {:continue, continue_arg :: term}}\n              | {:stop, reason :: term, new_state}\n            when new_state: term\n\n  @doc \"\"\"\n  Invoked to handle all other messages.\n\n  `msg` is the message and `state` is the current state of the `GenServer`. When\n  a timeout occurs the message is `:timeout`.\n\n  Return values are the same as `c:handle_cast/2`.\n\n  This callback is optional. If one is not implemented, the received message\n  will be logged.\n  \"\"\"\n  @callback handle_info(msg :: :timeout | term, state :: term) ::\n              {:noreply, new_state}\n              | {:noreply, new_state, timeout | :hibernate | {:continue, continue_arg :: term}}\n              | {:stop, reason :: term, new_state}\n            when new_state: term\n\n  @doc \"\"\"\n  Invoked to handle continue instructions.\n\n  It is useful for performing work after initialization or for splitting the work\n  in a callback in multiple steps, updating the process state along the way.\n\n  Return values are the same as `c:handle_cast/2`.\n\n  This callback is optional. If one is not implemented, the server will fail\n  if a continue instruction is used.\n  \"\"\"\n  @callback handle_continue(continue_arg, state :: term) ::\n              {:noreply, new_state}\n              | {:noreply, new_state, timeout | :hibernate | {:continue, continue_arg}}\n              | {:stop, reason :: term, new_state}\n            when new_state: term, continue_arg: term\n\n  @doc \"\"\"\n  Invoked when the server is about to exit. It should do any cleanup required.\n\n  `reason` is exit reason and `state` is the current state of the `GenServer`.\n  The return value is ignored.\n\n  `c:terminate/2` is useful for cleanup that requires access to the\n  `GenServer`'s state. However, it is **not guaranteed** that `c:terminate/2`\n  is called when a `GenServer` exits. Therefore, important cleanup should be\n  done using process links and/or monitors. A monitoring process will receive the\n  same exit `reason` that would be passed to `c:terminate/2`.\n\n  `c:terminate/2` is called if:\n\n    * the `GenServer` traps exits (using `Process.flag/2`) *and* the parent\n    process (the one which called `start_link/1`) sends an exit signal\n\n    * a callback (except `c:init/1`) does one of the following:\n\n      * returns a `:stop` tuple\n\n      * raises (via `raise/2`) or exits (via `exit/1`)\n\n      * returns an invalid value\n\n  If part of a supervision tree, a `GenServer` will receive an exit signal from\n  its parent process (its supervisor) when the tree is shutting down. The exit\n  signal is based on the shutdown strategy in the child's specification, where\n  this value can be:\n\n    * `:brutal_kill`: the `GenServer` is killed and so `c:terminate/2` is not called.\n\n    * a timeout value, where the supervisor will send the exit signal `:shutdown` and\n      the `GenServer` will have the duration of the timeout to terminate.\n      If after duration of this timeout the process is still alive, it will be killed\n      immediately.\n\n  For a more in-depth explanation, please read the \"Shutdown values (:shutdown)\"\n  section in the `Supervisor` module.\n\n  If the `GenServer` receives an exit signal (that is not `:normal`) from any\n  process when it is not trapping exits it will exit abruptly with the same\n  reason and so not call `c:terminate/2`. Note that a process does *NOT* trap\n  exits by default and an exit signal is sent when a linked process exits or its\n  node is disconnected.\n\n  `c:terminate/2` is only called after the `GenServer` finishes processing all\n  messages which arrived in its mailbox prior to the exit signal. If it\n  receives a `:kill` signal before it finishes processing those,\n  `c:terminate/2` will not be called. If `c:terminate/2` is called, any\n  messages received after the exit signal will still be in the mailbox.\n\n  There is no cleanup needed when the `GenServer` controls a `port` (for example,\n  `:gen_tcp.socket`) or `t:File.io_device/0`, because these will be closed on\n  receiving a `GenServer`'s exit signal and do not need to be closed manually\n  in `c:terminate/2`.\n\n  If `reason` is neither `:normal`, `:shutdown`, nor `{:shutdown, term}` an error is\n  logged.\n\n  This callback is optional.\n  \"\"\"\n  @callback terminate(reason, state :: term) :: term\n            when reason: :normal | :shutdown | {:shutdown, term} | term\n\n  @doc \"\"\"\n  Invoked to change the state of the `GenServer` when a different version of a\n  module is loaded (hot code swapping) and the state's term structure should be\n  changed.\n\n  `old_vsn` is the previous version of the module (defined by the `@vsn`\n  attribute) when upgrading. When downgrading the previous version is wrapped in\n  a 2-tuple with first element `:down`. `state` is the current state of the\n  `GenServer` and `extra` is any extra data required to change the state.\n\n  Returning `{:ok, new_state}` changes the state to `new_state` and the code\n  change is successful.\n\n  Returning `{:error, reason}` fails the code change with reason `reason` and\n  the state remains as the previous state.\n\n  If `c:code_change/3` raises the code change fails and the loop will continue\n  with its previous state. Therefore this callback does not usually contain side effects.\n\n  This callback is optional.\n  \"\"\"\n  @callback code_change(old_vsn, state :: term, extra :: term) ::\n              {:ok, new_state :: term}\n              | {:error, reason :: term}\n            when old_vsn: term | {:down, term}\n\n  @doc \"\"\"\n  This function is called by a `GenServer` process in the following situations:\n\n    * [`:sys.get_status/1,2`](`:sys.get_status/1`) is invoked to get the `GenServer` status.\n    * The `GenServer` process terminates abnormally and logs an error.\n\n  This callback is used to limit the status of the process returned by\n  [`:sys.get_status/1,2`](`:sys.get_status/1`) or sent to logger.\n\n  The callback gets a map `status` describing the current status and shall return\n  a map `new_status` with the same keys, but it may transform some values.\n\n  Two possible use cases for this callback is to remove sensitive information\n  from the state to prevent it from being printed in log files, or to compact\n  large irrelevant status items that would only clutter the logs.\n\n  ## Example\n\n      @impl GenServer\n      def format_status(status) do\n        Map.new(status, fn\n          {:state, state} -> {:state, Map.delete(state, :private_key)}\n          {:message, {:password, _}} -> {:message, {:password, \"redacted\"}}\n          key_value -> key_value\n        end)\n      end\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @callback format_status(status :: :gen_server.format_status()) ::\n              new_status :: :gen_server.format_status()\n\n  # TODO: Remove this on v2.0\n  @doc deprecated: \"Use format_status/1 callback instead\"\n  @callback format_status(reason, pdict_and_state :: list) :: term\n            when reason: :normal | :terminate\n\n  @optional_callbacks code_change: 3,\n                      terminate: 2,\n                      handle_info: 2,\n                      handle_cast: 2,\n                      handle_call: 3,\n                      format_status: 1,\n                      format_status: 2,\n                      handle_continue: 2\n\n  @typedoc \"Return values of `start*` functions\"\n  @type on_start :: {:ok, pid} | :ignore | {:error, {:already_started, pid} | term}\n\n  @typedoc \"The GenServer name\"\n  @type name :: nil | atom | {:global, term} | {:via, module, term}\n\n  @typedoc \"Options used by the `start*` functions\"\n  @type options :: [option]\n\n  @typedoc \"Option values used by the `start*` functions\"\n  @type option ::\n          {:debug, debug}\n          | {:name, name}\n          | {:timeout, timeout}\n          | {:spawn_opt, [Process.spawn_opt()]}\n          | {:hibernate_after, timeout}\n\n  @typedoc \"Debug options supported by the `start*` functions\"\n  @type debug :: [:trace | :log | :statistics | {:log_to_file, Path.t()}]\n\n  @typedoc \"\"\"\n  The server reference.\n\n  This is either a plain PID or a value representing a registered name.\n  See the \"Name registration\" section of this document for more information.\n  \"\"\"\n  @type server :: pid | name | {atom, node}\n\n  @typedoc \"\"\"\n  Tuple describing the client of a call request.\n\n  `pid` is the PID of the caller and `tag` is a unique term used to identify the\n  call.\n  \"\"\"\n  @type from :: {pid, tag :: term}\n\n  @doc false\n  defmacro __using__(opts) do\n    quote location: :keep, bind_quoted: [opts: opts] do\n      @behaviour GenServer\n\n      if not Module.has_attribute?(__MODULE__, :doc) do\n        @doc \"\"\"\n        Returns a specification to start this module under a supervisor.\n\n        See `Supervisor`.\n        \"\"\"\n      end\n\n      def child_spec(init_arg) do\n        default = %{\n          id: __MODULE__,\n          start: {__MODULE__, :start_link, [init_arg]}\n        }\n\n        Supervisor.child_spec(default, unquote(Macro.escape(opts)))\n      end\n\n      defoverridable child_spec: 1\n\n      # TODO: Remove this on v2.0\n      @before_compile GenServer\n\n      @doc false\n      def handle_call(msg, _from, state) do\n        proc =\n          case Process.info(self(), :registered_name) do\n            {_, []} -> self()\n            {_, name} -> name\n          end\n\n        # We do this to trick Dialyzer to not complain about non-local returns.\n        case :erlang.phash2(1, 1) do\n          0 ->\n            raise \"attempted to call GenServer #{inspect(proc)} but no handle_call/3 clause was provided\"\n\n          1 ->\n            {:stop, {:bad_call, msg}, state}\n        end\n      end\n\n      @doc false\n      def handle_info(msg, state) do\n        proc =\n          case Process.info(self(), :registered_name) do\n            {_, []} -> self()\n            {_, name} -> name\n          end\n\n        :logger.error(\n          %{\n            label: {GenServer, :no_handle_info},\n            report: %{\n              module: __MODULE__,\n              message: msg,\n              name: proc\n            }\n          },\n          %{\n            domain: [:otp, :elixir],\n            error_logger: %{tag: :error_msg},\n            report_cb: &GenServer.format_report/1\n          }\n        )\n\n        {:noreply, state}\n      end\n\n      @doc false\n      def handle_cast(msg, state) do\n        proc =\n          case Process.info(self(), :registered_name) do\n            {_, []} -> self()\n            {_, name} -> name\n          end\n\n        # We do this to trick Dialyzer to not complain about non-local returns.\n        case :erlang.phash2(1, 1) do\n          0 ->\n            raise \"attempted to cast GenServer #{inspect(proc)} but no handle_cast/2 clause was provided\"\n\n          1 ->\n            {:stop, {:bad_cast, msg}, state}\n        end\n      end\n\n      @doc false\n      def terminate(_reason, _state) do\n        :ok\n      end\n\n      @doc false\n      def code_change(_old, state, _extra) do\n        {:ok, state}\n      end\n\n      defoverridable code_change: 3, terminate: 2, handle_info: 2, handle_cast: 2, handle_call: 3\n    end\n  end\n\n  defmacro __before_compile__(env) do\n    if not Module.defines?(env.module, {:init, 1}) do\n      message = \"\"\"\n      function init/1 required by behaviour GenServer is not implemented \\\n      (in module #{inspect(env.module)}).\n\n      We will inject a default implementation for now:\n\n          def init(init_arg) do\n            {:ok, init_arg}\n          end\n\n      You can copy the implementation above or define your own that converts \\\n      the arguments given to GenServer.start_link/3 to the server state.\n      \"\"\"\n\n      IO.warn(message, env)\n\n      quote do\n        @doc false\n        def init(init_arg) do\n          {:ok, init_arg}\n        end\n\n        defoverridable init: 1\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Starts a `GenServer` process linked to the current process.\n\n  This is often used to start the `GenServer` as part of a supervision tree.\n\n  Once the server is started, the `c:init/1` function of the given `module` is\n  called with `init_arg` as its argument to initialize the server. To ensure a\n  synchronized start-up procedure, this function does not return until `c:init/1`\n  has returned.\n\n  Note that a `GenServer` started with `start_link/3` is linked to the\n  parent process and will exit in case of crashes from the parent. The GenServer\n  will also exit due to the `:normal` reasons in case it is configured to trap\n  exits in the `c:init/1` callback.\n\n  ## Options\n\n    * `:name` - used for name registration as described in the \"Name\n      registration\" section in the documentation for `GenServer`\n\n    * `:timeout` - if present, the server is allowed to spend the given number of\n      milliseconds initializing or it will be terminated and the start function\n      will return `{:error, :timeout}`\n\n    * `:debug` - if present, the corresponding function in the [`:sys` module](`:sys`) is invoked\n\n    * `:spawn_opt` - if present, its value is passed as options to the\n      underlying process as in `Process.spawn/4`\n\n    * `:hibernate_after` - if present, the GenServer process awaits any message for\n      the given number of milliseconds and if no message is received, the process goes\n      into hibernation automatically (by calling `:proc_lib.hibernate/3`).\n\n  ## Return values\n\n  If the server is successfully created and initialized, this function returns\n  `{:ok, pid}`, where `pid` is the PID of the server. If a process with the\n  specified server name already exists, this function returns\n  `{:error, {:already_started, pid}}` with the PID of that process.\n\n  If the `c:init/1` callback fails with `reason`, this function returns\n  `{:error, reason}`. Otherwise, if it returns `{:stop, reason}`\n  or `:ignore`, the process is terminated and this function returns\n  `{:error, reason}` or `:ignore`, respectively.\n  \"\"\"\n  @spec start_link(module, term, options) :: on_start\n  def start_link(module, init_arg, options \\\\ []) when is_atom(module) and is_list(options) do\n    do_start(:link, module, init_arg, options)\n  end\n\n  @doc \"\"\"\n  Starts a `GenServer` process without links (outside of a supervision tree).\n\n  See `start_link/3` for more information.\n  \"\"\"\n  @spec start(module, term, options) :: on_start\n  def start(module, init_arg, options \\\\ []) when is_atom(module) and is_list(options) do\n    do_start(:nolink, module, init_arg, options)\n  end\n\n  defp do_start(link, module, init_arg, options) do\n    case Keyword.pop(options, :name) do\n      {nil, opts} ->\n        :gen.start(:gen_server, link, module, init_arg, opts)\n\n      {atom, opts} when is_atom(atom) ->\n        :gen.start(:gen_server, link, {:local, atom}, module, init_arg, opts)\n\n      {{:global, _term} = tuple, opts} ->\n        :gen.start(:gen_server, link, tuple, module, init_arg, opts)\n\n      {{:via, via_module, _term} = tuple, opts} when is_atom(via_module) ->\n        :gen.start(:gen_server, link, tuple, module, init_arg, opts)\n\n      {other, _} ->\n        raise ArgumentError, \"\"\"\n        expected :name option to be one of the following:\n\n          * nil\n          * atom\n          * {:global, term}\n          * {:via, module, term}\n\n        Got: #{inspect(other)}\n        \"\"\"\n    end\n  end\n\n  @doc \"\"\"\n  Synchronously stops the server with the given `reason`.\n\n  The `c:terminate/2` callback of the given `server` will be invoked before\n  exiting. This function returns `:ok` if the server terminates with the\n  given reason; if it terminates with another reason, the call exits.\n\n  This function keeps OTP semantics regarding error reporting.\n  If the reason is any other than `:normal`, `:shutdown` or\n  `{:shutdown, _}`, an error report is logged.\n  \"\"\"\n  @spec stop(server, reason :: term, timeout) :: :ok\n  def stop(server, reason \\\\ :normal, timeout \\\\ :infinity) do\n    case whereis(server) do\n      nil ->\n        exit({:noproc, {__MODULE__, :stop, [server, reason, timeout]}})\n\n      pid when pid == self() ->\n        exit({:calling_self, {__MODULE__, :stop, [server, reason, timeout]}})\n\n      pid ->\n        try do\n          :proc_lib.stop(pid, reason, timeout)\n        catch\n          :exit, err ->\n            exit({err, {__MODULE__, :stop, [server, reason, timeout]}})\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Makes a synchronous call to the `server` and waits for its reply.\n\n  The client sends the given `request` to the server and waits until a reply\n  arrives or a timeout occurs. `c:handle_call/3` will be called on the server\n  to handle the request.\n\n  `server` can be a PID or any of the other values described in the\n  \"Name registration\" section of the documentation for this module.\n\n  ## Timeouts\n\n  `timeout` is an integer greater than zero which specifies how many\n  milliseconds to wait for a reply, or the atom `:infinity` to wait\n  indefinitely. The default value is `5000`. If no reply is received within\n  the specified time, the function call fails and the caller exits. If the\n  caller catches the failure and continues running, and the server is just late\n  with the reply, it may arrive at any time later into the caller's message\n  queue. The caller must in this case be prepared for this and discard any such\n  garbage messages that are two-element tuples with a reference as the first\n  element.\n  \"\"\"\n  @spec call(server, term, timeout) :: term\n  def call(server, request, timeout \\\\ 5000)\n      when (is_integer(timeout) and timeout >= 0) or timeout == :infinity do\n    case whereis(server) do\n      nil ->\n        exit({:noproc, {__MODULE__, :call, [server, request, timeout]}})\n\n      pid ->\n        try do\n          :gen.call(pid, :\"$gen_call\", request, timeout)\n        catch\n          :exit, reason ->\n            exit({reason, {__MODULE__, :call, [server, request, timeout]}})\n        else\n          {:ok, res} -> res\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Casts a request to the `server` without waiting for a response.\n\n  This function always returns `:ok` regardless of whether\n  the destination `server` (or node) exists. Therefore it\n  is unknown whether the destination `server` successfully\n  handled the request.\n\n  `server` can be any of the values described in the \"Name registration\"\n  section of the documentation for this module.\n  \"\"\"\n  @spec cast(server, term) :: :ok\n  def cast(server, request)\n\n  def cast({:global, name}, request) do\n    try do\n      :global.send(name, cast_msg(request))\n      :ok\n    catch\n      _, _ -> :ok\n    end\n  end\n\n  def cast({:via, mod, name}, request) do\n    try do\n      mod.send(name, cast_msg(request))\n      :ok\n    catch\n      _, _ -> :ok\n    end\n  end\n\n  def cast({name, node}, request) when is_atom(name) and is_atom(node),\n    do: do_send({name, node}, cast_msg(request))\n\n  def cast(dest, request) when is_atom(dest) or is_pid(dest), do: do_send(dest, cast_msg(request))\n\n  @doc \"\"\"\n  Casts all servers locally registered as `name` at the specified nodes.\n\n  This function returns immediately and ignores nodes that do not exist, or where the\n  server name does not exist.\n\n  See `multi_call/4` for more information.\n  \"\"\"\n  @spec abcast([node], name :: atom, term) :: :abcast\n  def abcast(nodes \\\\ [node() | Node.list()], name, request)\n      when is_list(nodes) and is_atom(name) do\n    msg = cast_msg(request)\n    _ = for node <- nodes, do: do_send({name, node}, msg)\n    :abcast\n  end\n\n  defp cast_msg(req) do\n    {:\"$gen_cast\", req}\n  end\n\n  defp do_send(dest, msg) do\n    try do\n      send(dest, msg)\n      :ok\n    catch\n      _, _ -> :ok\n    end\n  end\n\n  @doc \"\"\"\n  Calls all servers locally registered as `name` at the specified `nodes`.\n\n  First, the `request` is sent to every node in `nodes`; then, the caller waits\n  for the replies. This function returns a two-element tuple `{replies,\n  bad_nodes}` where:\n\n    * `replies` - is a list of `{node, reply}` tuples where `node` is the node\n      that replied and `reply` is its reply\n    * `bad_nodes` - is a list of nodes that either did not exist or where a\n      server with the given `name` did not exist or did not reply\n\n  `nodes` is a list of node names to which the request is sent. The default\n  value is the list of all known nodes (including this node).\n\n  ## Examples\n\n  Assuming the `Stack` GenServer mentioned in the docs for the `GenServer`\n  module is registered as `Stack` in the `:\"foo@my-machine\"` and\n  `:\"bar@my-machine\"` nodes:\n\n      GenServer.multi_call(Stack, :pop)\n      #=> {[{:\"foo@my-machine\", :hello}, {:\"bar@my-machine\", :world}], []}\n\n  \"\"\"\n  @spec multi_call([node], name :: atom, term, timeout) ::\n          {replies :: [{node, term}], bad_nodes :: [node]}\n  def multi_call(nodes \\\\ [node() | Node.list()], name, request, timeout \\\\ :infinity) do\n    :gen_server.multi_call(nodes, name, request, timeout)\n  end\n\n  @doc \"\"\"\n  Replies to a client.\n\n  This function can be used to explicitly send a reply to a client that called\n  `call/3` or `multi_call/4` when the reply cannot be specified in the return\n  value of `c:handle_call/3`.\n\n  `client` must be the `from` argument (the second argument) accepted by\n  `c:handle_call/3` callbacks. `reply` is an arbitrary term which will be given\n  back to the client as the return value of the call.\n\n  Note that `reply/2` can be called from any process, not just the GenServer\n  that originally received the call (as long as that GenServer communicated the\n  `from` argument somehow).\n\n  This function always returns `:ok`.\n\n  ## Examples\n\n      def handle_call(:reply_in_one_second, from, state) do\n        Process.send_after(self(), {:reply, from}, 1_000)\n        {:noreply, state}\n      end\n\n      def handle_info({:reply, from}, state) do\n        GenServer.reply(from, :one_second_has_passed)\n        {:noreply, state}\n      end\n\n  \"\"\"\n  @spec reply(from, term) :: :ok\n  def reply(client, reply) do\n    :gen.reply(client, reply)\n  end\n\n  @doc \"\"\"\n  Returns the `pid` or `{name, node}` of a GenServer process, `nil` otherwise.\n\n  To be precise, `nil` is returned whenever a `pid` or `{name, node}` cannot\n  be returned. Note there is no guarantee the returned `pid` or `{name, node}`\n  is alive, as a process could terminate immediately after it is looked up.\n\n  ## Examples\n\n  For example, to lookup a server process, monitor it and send a cast to it:\n\n      process = GenServer.whereis(server)\n      monitor = Process.monitor(process)\n      GenServer.cast(process, :hello)\n\n  \"\"\"\n  @spec whereis(server) :: pid | {atom, node} | nil\n  def whereis(server)\n\n  def whereis(pid) when is_pid(pid), do: pid\n\n  def whereis(name) when is_atom(name) do\n    Process.whereis(name)\n  end\n\n  def whereis({:global, name}) do\n    case :global.whereis_name(name) do\n      pid when is_pid(pid) -> pid\n      :undefined -> nil\n    end\n  end\n\n  def whereis({:via, mod, name}) do\n    case apply(mod, :whereis_name, [name]) do\n      pid when is_pid(pid) -> pid\n      :undefined -> nil\n    end\n  end\n\n  def whereis({name, local}) when is_atom(name) and local == node() do\n    Process.whereis(name)\n  end\n\n  def whereis({name, node} = server) when is_atom(name) and is_atom(node) do\n    server\n  end\n\n  @doc false\n  def format_report(%{\n        label: {GenServer, :no_handle_info},\n        report: %{module: mod, message: msg, name: proc}\n      }) do\n    {~c\"~p ~p received unexpected message in handle_info/2: ~p~n\", [mod, proc, msg]}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/hash_dict.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule HashDict do\n  @moduledoc \"\"\"\n  Tuple-based HashDict implementation.\n\n  This module is deprecated. Use the `Map` module instead.\n  \"\"\"\n\n  @moduledoc deprecated: \"Use Map instead\"\n\n  use Dict\n\n  @node_bitmap 0b111\n  @node_shift 3\n  @node_size 8\n  @node_template :erlang.make_tuple(@node_size, [])\n\n  @opaque t :: %__MODULE__{size: non_neg_integer, root: term}\n  @doc false\n  defstruct size: 0, root: @node_template\n\n  # Inline common instructions\n  @compile :inline_list_funcs\n  @compile {:inline, key_hash: 1, key_mask: 1, key_shift: 1}\n\n  message = \"Use maps and the Map module instead\"\n\n  @doc \"\"\"\n  Creates a new empty dict.\n  \"\"\"\n  @spec new :: Dict.t()\n  @deprecated message\n  def new do\n    %HashDict{}\n  end\n\n  @deprecated message\n  def put(%HashDict{root: root, size: size}, key, value) do\n    {root, counter} = do_put(root, key, value, key_hash(key))\n    %HashDict{root: root, size: size + counter}\n  end\n\n  @deprecated message\n  def update!(%HashDict{root: root, size: size} = dict, key, fun) when is_function(fun, 1) do\n    {root, counter} =\n      do_update(root, key, fn -> raise KeyError, key: key, term: dict end, fun, key_hash(key))\n\n    %HashDict{root: root, size: size + counter}\n  end\n\n  @deprecated message\n  def update(%HashDict{root: root, size: size}, key, default, fun) when is_function(fun, 1) do\n    {root, counter} = do_update(root, key, fn -> default end, fun, key_hash(key))\n    %HashDict{root: root, size: size + counter}\n  end\n\n  @deprecated message\n  def fetch(%HashDict{root: root}, key) do\n    do_fetch(root, key, key_hash(key))\n  end\n\n  @deprecated message\n  def delete(dict, key) do\n    case dict_delete(dict, key) do\n      {dict, _value} -> dict\n      :error -> dict\n    end\n  end\n\n  @deprecated message\n  def pop(dict, key, default \\\\ nil) do\n    case dict_delete(dict, key) do\n      {dict, value} -> {value, dict}\n      :error -> {default, dict}\n    end\n  end\n\n  @deprecated message\n  def size(%HashDict{size: size}) do\n    size\n  end\n\n  @doc false\n  @deprecated message\n  def reduce(%HashDict{root: root}, acc, fun) do\n    do_reduce(root, acc, fun, @node_size, fn\n      {:suspend, acc} -> {:suspended, acc, &{:done, elem(&1, 1)}}\n      {:halt, acc} -> {:halted, acc}\n      {:cont, acc} -> {:done, acc}\n    end)\n  end\n\n  ## General helpers\n\n  @doc false\n  def dict_delete(%HashDict{root: root, size: size}, key) do\n    case do_delete(root, key, key_hash(key)) do\n      {root, value} -> {%HashDict{root: root, size: size - 1}, value}\n      :error -> :error\n    end\n  end\n\n  ## Dict manipulation\n\n  defp do_fetch(node, key, hash) do\n    index = key_mask(hash)\n\n    case elem(node, index) do\n      [^key | v] -> {:ok, v}\n      {^key, v, _} -> {:ok, v}\n      {_, _, n} -> do_fetch(n, key, key_shift(hash))\n      _ -> :error\n    end\n  end\n\n  defp do_put(node, key, value, hash) do\n    index = key_mask(hash)\n\n    case elem(node, index) do\n      [] ->\n        {put_elem(node, index, [key | value]), 1}\n\n      [^key | _] ->\n        {put_elem(node, index, [key | value]), 0}\n\n      [k | v] ->\n        n = put_elem(@node_template, key_mask(key_shift(hash)), [key | value])\n        {put_elem(node, index, {k, v, n}), 1}\n\n      {^key, _, n} ->\n        {put_elem(node, index, {key, value, n}), 0}\n\n      {k, v, n} ->\n        {n, counter} = do_put(n, key, value, key_shift(hash))\n        {put_elem(node, index, {k, v, n}), counter}\n    end\n  end\n\n  defp do_update(node, key, default, fun, hash) do\n    index = key_mask(hash)\n\n    case elem(node, index) do\n      [] ->\n        {put_elem(node, index, [key | default.()]), 1}\n\n      [^key | value] ->\n        {put_elem(node, index, [key | fun.(value)]), 0}\n\n      [k | v] ->\n        n = put_elem(@node_template, key_mask(key_shift(hash)), [key | default.()])\n        {put_elem(node, index, {k, v, n}), 1}\n\n      {^key, value, n} ->\n        {put_elem(node, index, {key, fun.(value), n}), 0}\n\n      {k, v, n} ->\n        {n, counter} = do_update(n, key, default, fun, key_shift(hash))\n        {put_elem(node, index, {k, v, n}), counter}\n    end\n  end\n\n  defp do_delete(node, key, hash) do\n    index = key_mask(hash)\n\n    case elem(node, index) do\n      [] ->\n        :error\n\n      [^key | value] ->\n        {put_elem(node, index, []), value}\n\n      [_ | _] ->\n        :error\n\n      {^key, value, n} ->\n        {put_elem(node, index, do_compact_node(n)), value}\n\n      {k, v, n} ->\n        case do_delete(n, key, key_shift(hash)) do\n          {@node_template, value} ->\n            {put_elem(node, index, [k | v]), value}\n\n          {n, value} ->\n            {put_elem(node, index, {k, v, n}), value}\n\n          :error ->\n            :error\n        end\n    end\n  end\n\n  Enum.each(0..(@node_size - 1), fn index ->\n    defp do_compact_node(node) when elem(node, unquote(index)) != [] do\n      case elem(node, unquote(index)) do\n        [k | v] ->\n          case put_elem(node, unquote(index), []) do\n            @node_template -> [k | v]\n            n -> {k, v, n}\n          end\n\n        {k, v, n} ->\n          {k, v, put_elem(node, unquote(index), do_compact_node(n))}\n      end\n    end\n  end)\n\n  ## Dict reduce\n\n  defp do_reduce_each(_node, {:halt, acc}, _fun, _next) do\n    {:halted, acc}\n  end\n\n  defp do_reduce_each(node, {:suspend, acc}, fun, next) do\n    {:suspended, acc, &do_reduce_each(node, &1, fun, next)}\n  end\n\n  defp do_reduce_each([], acc, _fun, next) do\n    next.(acc)\n  end\n\n  defp do_reduce_each([k | v], {:cont, acc}, fun, next) do\n    next.(fun.({k, v}, acc))\n  end\n\n  defp do_reduce_each({k, v, n}, {:cont, acc}, fun, next) do\n    do_reduce(n, fun.({k, v}, acc), fun, @node_size, next)\n  end\n\n  defp do_reduce(node, acc, fun, count, next) when count > 0 do\n    do_reduce_each(\n      :erlang.element(count, node),\n      acc,\n      fun,\n      &do_reduce(node, &1, fun, count - 1, next)\n    )\n  end\n\n  defp do_reduce(_node, acc, _fun, 0, next) do\n    next.(acc)\n  end\n\n  ## Key operations\n\n  import Bitwise\n\n  defp key_hash(key) do\n    :erlang.phash2(key)\n  end\n\n  defp key_mask(hash) do\n    hash &&& @node_bitmap\n  end\n\n  defp key_shift(hash) do\n    hash >>> @node_shift\n  end\nend\n\ndefimpl Enumerable, for: HashDict do\n  @moduledoc false\n  @moduledoc deprecated: \"Use Map instead\"\n\n  def reduce(dict, acc, fun) do\n    # Avoid warnings about HashDict being deprecated.\n    module = String.to_atom(\"HashDict\")\n    module.reduce(dict, acc, fun)\n  end\n\n  def member?(dict, {key, value}) do\n    # Avoid warnings about HashDict being deprecated.\n    module = String.to_atom(\"HashDict\")\n    {:ok, match?({:ok, ^value}, module.fetch(dict, key))}\n  end\n\n  def member?(_dict, _) do\n    {:ok, false}\n  end\n\n  def count(dict) do\n    # Avoid warnings about HashDict being deprecated.\n    module = String.to_atom(\"HashDict\")\n    {:ok, module.size(dict)}\n  end\n\n  def slice(_dict) do\n    {:error, __MODULE__}\n  end\nend\n\ndefimpl Collectable, for: HashDict do\n  @moduledoc false\n  @moduledoc deprecated: \"Use Map instead\"\n\n  def into(original) do\n    # Avoid warnings about HashDict being deprecated.\n    module = String.to_atom(\"HashDict\")\n\n    collector_fun = fn\n      dict, {:cont, {key, value}} -> module.put(dict, key, value)\n      dict, :done -> dict\n      _, :halt -> :ok\n    end\n\n    {original, collector_fun}\n  end\nend\n\ndefimpl Inspect, for: HashDict do\n  @moduledoc false\n  @moduledoc deprecated: \"Use Map instead\"\n  import Inspect.Algebra\n\n  def inspect(dict, opts) do\n    # Avoid warnings about HashDict being deprecated.\n    module = String.to_atom(\"HashDict\")\n    concat([\"#HashDict<\", Inspect.List.inspect(module.to_list(dict), opts), \">\"])\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/hash_set.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule HashSet do\n  @moduledoc \"\"\"\n  Tuple-based HashSet implementation.\n\n  This module is deprecated. Use the `MapSet` module instead.\n  \"\"\"\n\n  @moduledoc deprecated: \"Use MapSet instead\"\n\n  @node_bitmap 0b111\n  @node_shift 3\n  @node_size 8\n  @node_template :erlang.make_tuple(@node_size, [])\n\n  message = \"Use the MapSet module instead\"\n\n  @opaque t :: %__MODULE__{size: non_neg_integer, root: term}\n  @doc false\n  defstruct size: 0, root: @node_template\n\n  # Inline common instructions\n  @compile :inline_list_funcs\n  @compile {:inline, key_hash: 1, key_mask: 1, key_shift: 1}\n\n  @deprecated message\n  @spec new :: Set.t()\n  def new do\n    %HashSet{}\n  end\n\n  @deprecated message\n  def union(%HashSet{size: size1} = set1, %HashSet{size: size2} = set2) when size1 <= size2 do\n    set_fold(set1, set2, fn v, acc -> put(acc, v) end)\n  end\n\n  @deprecated message\n  def union(%HashSet{} = set1, %HashSet{} = set2) do\n    set_fold(set2, set1, fn v, acc -> put(acc, v) end)\n  end\n\n  @deprecated message\n  def intersection(%HashSet{} = set1, %HashSet{} = set2) do\n    set_fold(set1, %HashSet{}, fn v, acc ->\n      if member?(set2, v), do: put(acc, v), else: acc\n    end)\n  end\n\n  @deprecated message\n  def difference(%HashSet{} = set1, %HashSet{} = set2) do\n    set_fold(set2, set1, fn v, acc -> delete(acc, v) end)\n  end\n\n  @deprecated message\n  def to_list(set) do\n    set_fold(set, [], &[&1 | &2]) |> :lists.reverse()\n  end\n\n  @deprecated message\n  def equal?(%HashSet{size: size1} = set1, %HashSet{size: size2} = set2) do\n    case size1 do\n      ^size2 -> subset?(set1, set2)\n      _ -> false\n    end\n  end\n\n  @deprecated message\n  def subset?(%HashSet{} = set1, %HashSet{} = set2) do\n    reduce(set1, {:cont, true}, fn member, acc ->\n      case member?(set2, member) do\n        true -> {:cont, acc}\n        _ -> {:halt, false}\n      end\n    end)\n    |> elem(1)\n  end\n\n  @deprecated message\n  def disjoint?(%HashSet{} = set1, %HashSet{} = set2) do\n    reduce(set2, {:cont, true}, fn member, acc ->\n      case member?(set1, member) do\n        false -> {:cont, acc}\n        _ -> {:halt, false}\n      end\n    end)\n    |> elem(1)\n  end\n\n  @deprecated message\n  def member?(%HashSet{root: root}, term) do\n    do_member?(root, term, key_hash(term))\n  end\n\n  @deprecated message\n  def put(%HashSet{root: root, size: size}, term) do\n    {root, counter} = do_put(root, term, key_hash(term))\n    %HashSet{root: root, size: size + counter}\n  end\n\n  @deprecated message\n  def delete(%HashSet{root: root, size: size} = set, term) do\n    case do_delete(root, term, key_hash(term)) do\n      {:ok, root} -> %HashSet{root: root, size: size - 1}\n      :error -> set\n    end\n  end\n\n  @doc false\n  def reduce(%HashSet{root: root}, acc, fun) do\n    do_reduce(root, acc, fun, @node_size, fn\n      {:suspend, acc} -> {:suspended, acc, &{:done, elem(&1, 1)}}\n      {:halt, acc} -> {:halted, acc}\n      {:cont, acc} -> {:done, acc}\n    end)\n  end\n\n  @deprecated message\n  def size(%HashSet{size: size}) do\n    size\n  end\n\n  ## Set helpers\n\n  defp set_fold(%HashSet{root: root}, acc, fun) do\n    do_fold(root, acc, fun, @node_size)\n  end\n\n  ## Set manipulation\n\n  defp do_member?(node, term, hash) do\n    index = key_mask(hash)\n\n    case elem(node, index) do\n      [] -> false\n      [^term | _] -> true\n      [_] -> false\n      [_ | n] -> do_member?(n, term, key_shift(hash))\n    end\n  end\n\n  defp do_put(node, term, hash) do\n    index = key_mask(hash)\n\n    case elem(node, index) do\n      [] ->\n        {put_elem(node, index, [term]), 1}\n\n      [^term | _] ->\n        {node, 0}\n\n      [t] ->\n        n = put_elem(@node_template, key_mask(key_shift(hash)), [term])\n        {put_elem(node, index, [t | n]), 1}\n\n      [t | n] ->\n        {n, counter} = do_put(n, term, key_shift(hash))\n        {put_elem(node, index, [t | n]), counter}\n    end\n  end\n\n  defp do_delete(node, term, hash) do\n    index = key_mask(hash)\n\n    case elem(node, index) do\n      [] ->\n        :error\n\n      [^term] ->\n        {:ok, put_elem(node, index, [])}\n\n      [_] ->\n        :error\n\n      [^term | n] ->\n        {:ok, put_elem(node, index, do_compact_node(n))}\n\n      [t | n] ->\n        case do_delete(n, term, key_shift(hash)) do\n          {:ok, @node_template} ->\n            {:ok, put_elem(node, index, [t])}\n\n          {:ok, n} ->\n            {:ok, put_elem(node, index, [t | n])}\n\n          :error ->\n            :error\n        end\n    end\n  end\n\n  Enum.each(0..(@node_size - 1), fn index ->\n    defp do_compact_node(node) when elem(node, unquote(index)) != [] do\n      case elem(node, unquote(index)) do\n        [t] ->\n          case put_elem(node, unquote(index), []) do\n            @node_template -> [t]\n            n -> [t | n]\n          end\n\n        [t | n] ->\n          [t | put_elem(node, unquote(index), do_compact_node(n))]\n      end\n    end\n  end)\n\n  ## Set fold\n\n  defp do_fold_each([], acc, _fun), do: acc\n  defp do_fold_each([t], acc, fun), do: fun.(t, acc)\n  defp do_fold_each([t | n], acc, fun), do: do_fold(n, fun.(t, acc), fun, @node_size)\n\n  defp do_fold(node, acc, fun, count) when count > 0 do\n    acc = do_fold_each(:erlang.element(count, node), acc, fun)\n    do_fold(node, acc, fun, count - 1)\n  end\n\n  defp do_fold(_node, acc, _fun, 0) do\n    acc\n  end\n\n  ## Set reduce\n\n  defp do_reduce_each(_node, {:halt, acc}, _fun, _next) do\n    {:halted, acc}\n  end\n\n  defp do_reduce_each(node, {:suspend, acc}, fun, next) do\n    {:suspended, acc, &do_reduce_each(node, &1, fun, next)}\n  end\n\n  defp do_reduce_each([], acc, _fun, next) do\n    next.(acc)\n  end\n\n  defp do_reduce_each([t], {:cont, acc}, fun, next) do\n    next.(fun.(t, acc))\n  end\n\n  defp do_reduce_each([t | n], {:cont, acc}, fun, next) do\n    do_reduce(n, fun.(t, acc), fun, @node_size, next)\n  end\n\n  defp do_reduce(node, acc, fun, count, next) when count > 0 do\n    do_reduce_each(\n      :erlang.element(count, node),\n      acc,\n      fun,\n      &do_reduce(node, &1, fun, count - 1, next)\n    )\n  end\n\n  defp do_reduce(_node, acc, _fun, 0, next) do\n    next.(acc)\n  end\n\n  ## Key operations\n\n  import Bitwise\n\n  defp key_hash(key) do\n    :erlang.phash2(key)\n  end\n\n  defp key_mask(hash) do\n    hash &&& @node_bitmap\n  end\n\n  defp key_shift(hash) do\n    hash >>> @node_shift\n  end\nend\n\ndefimpl Enumerable, for: HashSet do\n  @moduledoc false\n  @moduledoc deprecated: \"Use MapSet instead\"\n\n  def reduce(set, acc, fun) do\n    # Avoid warnings about HashSet being deprecated.\n    module = String.to_atom(\"HashSet\")\n    module.reduce(set, acc, fun)\n  end\n\n  def member?(set, term) do\n    # Avoid warnings about HashSet being deprecated.\n    module = String.to_atom(\"HashSet\")\n    {:ok, module.member?(set, term)}\n  end\n\n  def count(set) do\n    # Avoid warnings about HashSet being deprecated.\n    module = String.to_atom(\"HashSet\")\n    {:ok, module.size(set)}\n  end\n\n  def slice(_set) do\n    {:error, __MODULE__}\n  end\nend\n\ndefimpl Collectable, for: HashSet do\n  @moduledoc false\n  @moduledoc deprecated: \"Use MapSet instead\"\n\n  def into(original) do\n    # Avoid warnings about HashSet being deprecated.\n    module = String.to_atom(\"HashSet\")\n\n    collector_fun = fn\n      set, {:cont, term} -> module.put(set, term)\n      set, :done -> set\n      _, :halt -> :ok\n    end\n\n    {original, collector_fun}\n  end\nend\n\ndefimpl Inspect, for: HashSet do\n  @moduledoc false\n  @moduledoc deprecated: \"Use MapSet instead\"\n  import Inspect.Algebra\n\n  def inspect(set, opts) do\n    # Avoid warnings about HashSet being deprecated.\n    module = String.to_atom(\"HashSet\")\n    concat([\"#HashSet<\", Inspect.List.inspect(module.to_list(set), opts), \">\"])\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/inspect/algebra.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Inspect.Opts do\n  @moduledoc \"\"\"\n  Defines the options used by the `Inspect` protocol.\n\n  The following fields are available:\n\n    * `:base` - prints integers and binaries as `:binary`, `:octal`, `:decimal`,\n      or `:hex`. Defaults to `:decimal`.\n\n    * `:binaries` - when `:as_binaries` all binaries will be printed in bit\n      syntax.\n\n      When `:as_strings` all binaries will be printed as strings, non-printable\n      bytes will be escaped.\n\n      When the default `:infer`, the binary will be printed as a string if `:base`\n      is `:decimal` and if it is printable, otherwise in bit syntax. See\n      `String.printable?/1` to learn when a string is printable.\n\n    * `:charlists` - when `:as_charlists` all lists will be printed as charlists,\n      non-printable elements will be escaped.\n\n      When `:as_lists` all lists will be printed as lists.\n\n      When the default `:infer`, the list will be printed as a charlist if it\n      is printable, otherwise as list. See `List.ascii_printable?/1` to learn\n      when a charlist is printable.\n\n    * `:custom_options` (since v1.9.0) - a keyword list storing custom user-defined\n      options. Useful when implementing the `Inspect` protocol for nested structs\n      to pass the custom options through.\n\n      It supports some pre-defined keys:\n\n      - `:sort_maps` (since v1.14.4) - if set to `true`, sorts key-value pairs\n        in maps. This can be helpful to make map inspection deterministic for\n        testing, given maps key order is random.\n\n    * `:inspect_fun` (since v1.9.0) - a function to build algebra documents.\n      Defaults to `Inspect.Opts.default_inspect_fun/0`.\n\n    * `:limit` - limits the number of items that are inspected for tuples,\n      bitstrings, maps, lists and any other collection of items, with the exception of\n      printable strings and printable charlists which use the `:printable_limit` option.\n      It accepts a positive integer or `:infinity`. It defaults to `100` since\n      `Elixir v1.19.0`, as it has better defaults to deal with nested collections.\n\n    * `:pretty` - if set to `true` enables pretty printing. Defaults to `false`.\n\n    * `:printable_limit` - limits the number of characters that are inspected\n      on printable strings and printable charlists. You can use `String.printable?/1`\n      and `List.ascii_printable?/1` to check if a given string or charlist is\n      printable. If you don't want to limit the number of characters to a particular\n      number, use `:infinity`. It accepts a positive integer or `:infinity`.\n      Defaults to `4096`.\n\n    * `:safe` - when `false`, failures while inspecting structs will be raised\n      as errors instead of being wrapped in the `Inspect.Error` exception. This\n      is useful when debugging failures and crashes for custom inspect\n      implementations. Defaults to `true`.\n\n    * `:structs` - when `false`, structs are not formatted by the inspect\n      protocol, they are instead printed as maps. Defaults to `true`.\n\n    * `:syntax_colors` - when set to a keyword list of colors the output is\n      colorized. The keys are types and the values are the colors to use for\n      each type (for example, `[number: :red, atom: :blue]`). Types can include\n      `:atom`, `:binary`, `:boolean`, `:list`, `:map`, `:number`, `:regex`,\n      `:string`, `:tuple`, or some types to represent AST like `:variable`,\n      `:call`, and `:operator`.\n      Custom data types may provide their own options.\n      Colors can be any `t:IO.ANSI.ansidata/0` as accepted by `IO.ANSI.format/1`.\n      A default list of colors can be retrieved from `IO.ANSI.syntax_colors/0`.\n\n    * `:width` - number of characters per line used when pretty is `true` or when\n      printing to IO devices. Set to `0` to force each item to be printed on its\n      own line. If you don't want to limit the number of items to a particular\n      number, use `:infinity`. Defaults to `80`.\n\n  \"\"\"\n\n  # TODO: Remove :char_lists key on v2.0\n  defstruct base: :decimal,\n            binaries: :infer,\n            char_lists: :infer,\n            charlists: :infer,\n            custom_options: [],\n            inspect_fun: &Inspect.inspect/2,\n            limit: 100,\n            pretty: false,\n            printable_limit: 4096,\n            safe: true,\n            structs: true,\n            syntax_colors: [],\n            width: 80\n\n  @type color_key :: atom\n\n  @type t :: %__MODULE__{\n          base: :decimal | :binary | :hex | :octal,\n          binaries: :infer | :as_binaries | :as_strings,\n          charlists: :infer | :as_lists | :as_charlists,\n          custom_options: keyword,\n          inspect_fun: (any, t -> Inspect.Algebra.t()),\n          limit: non_neg_integer | :infinity,\n          pretty: boolean,\n          printable_limit: non_neg_integer | :infinity,\n          safe: boolean,\n          structs: boolean,\n          syntax_colors: [{color_key, IO.ANSI.ansidata()}],\n          width: non_neg_integer | :infinity\n        }\n\n  @typedoc \"\"\"\n  Options for building an `Inspect.Opts` struct with `new/1`.\n  \"\"\"\n  @type new_opt ::\n          {:base, :decimal | :binary | :hex | :octal}\n          | {:binaries, :infer | :as_binaries | :as_strings}\n          | {:charlists, :infer | :as_lists | :as_charlists}\n          | {:custom_options, keyword}\n          | {:inspect_fun, (any, t -> Inspect.Algebra.t())}\n          | {:limit, non_neg_integer | :infinity}\n          | {:pretty, boolean}\n          | {:printable_limit, non_neg_integer | :infinity}\n          | {:safe, boolean}\n          | {:structs, boolean}\n          | {:syntax_colors, [{color_key, IO.ANSI.ansidata()}]}\n          | {:width, non_neg_integer | :infinity}\n\n  @doc \"\"\"\n  Builds an `Inspect.Opts` struct.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec new([new_opt()]) :: t\n  def new(opts) do\n    struct(%Inspect.Opts{inspect_fun: default_inspect_fun()}, opts)\n  end\n\n  @doc \"\"\"\n  Returns the default inspect function.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec default_inspect_fun() :: (term, t -> Inspect.Algebra.t())\n  def default_inspect_fun do\n    :persistent_term.get({__MODULE__, :inspect_fun}, &Inspect.inspect/2)\n  end\n\n  @doc \"\"\"\n  Sets the default inspect function.\n\n  Set this option with care as it will change how all values\n  in the system are inspected. The main use of this functionality\n  is to provide an entry point to filter inspected values,\n  in order for entities to comply with rules and legislations\n  on data security and data privacy.\n\n  It is **extremely discouraged** for libraries to set their own\n  function as this must be controlled by applications. Libraries\n  should instead define their own structs with custom inspect\n  implementations. If a library must change the default inspect\n  function, then it is best to ask users of your library to explicitly\n  call `default_inspect_fun/1` with your function of choice.\n\n  The default is `Inspect.inspect/2`.\n\n  ## Examples\n\n      previous_fun = Inspect.Opts.default_inspect_fun()\n\n      Inspect.Opts.default_inspect_fun(fn\n        %{address: _} = map, opts ->\n          previous_fun.(%{map | address: \"[REDACTED]\"}, opts)\n\n        value, opts ->\n          previous_fun.(value, opts)\n      end)\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec default_inspect_fun((term, t -> Inspect.Algebra.t())) :: :ok\n  def default_inspect_fun(fun) when is_function(fun, 2) do\n    :persistent_term.put({__MODULE__, :inspect_fun}, fun)\n  end\nend\n\ndefmodule Inspect.Algebra do\n  @moduledoc ~S\"\"\"\n  A set of functions for creating and manipulating algebra\n  documents.\n\n  This module implements the functionality described in\n  [\"Strictly Pretty\" (2000) by Christian Lindig][0] with small\n  additions, like support for binary nodes and a break mode that\n  maximises use of horizontal space.\n\n      iex> Inspect.Algebra.line()\n      :doc_line\n\n      iex> \"foo\"\n      \"foo\"\n\n  With the functions in this module, we can concatenate different\n  elements together and render them:\n\n      iex> doc = Inspect.Algebra.concat(Inspect.Algebra.empty(), \"foo\")\n      iex> Inspect.Algebra.format(doc, 80)\n      \"foo\"\n\n  The functions `nest/2`, `space/2` and `line/2` help you put the\n  document together into a rigid structure. However, the document\n  algebra gets interesting when using functions like `glue/3` and\n  `group/1`. A glue inserts a break between two documents. A group\n  indicates a document that must fit the current line, otherwise\n  breaks are rendered as new lines. Let's glue two docs together\n  with a break, group it and then render it:\n\n      iex> doc = Inspect.Algebra.glue(\"a\", \" \", \"b\")\n      iex> doc = Inspect.Algebra.group(doc)\n      iex> Inspect.Algebra.format(doc, 80)\n      \"a b\"\n\n  Note that the break was represented as is, because we haven't reached\n  a line limit. Once we do, it is replaced by a newline:\n\n      iex> doc = Inspect.Algebra.glue(String.duplicate(\"a\", 20), \" \", \"b\")\n      iex> doc = Inspect.Algebra.group(doc)\n      iex> Inspect.Algebra.format(doc, 10)\n      \"aaaaaaaaaaaaaaaaaaaa\\nb\"\n\n  This module uses the byte size to compute how much space there is\n  left. If your document contains strings, then those need to be\n  wrapped in `string/1`, which then relies on `String.length/1` to\n  precompute the document size.\n\n  Finally, this module also contains Elixir related functions, a bit\n  tied to Elixir formatting, such as `to_doc/2`.\n\n  ## Implementation details\n\n  The implementation of `Inspect.Algebra` is based on the Strictly Pretty\n  paper by [Lindig][0] which builds on top of previous pretty printing\n  algorithms but is tailored to strict languages, such as Elixir.\n  The core idea in the paper is the use of explicit document groups which\n  are rendered as flat (breaks as spaces) or as break (breaks as newlines).\n\n  This implementation provides two types of breaks: `:strict` and `:flex`.\n  When a group does not fit, all strict breaks are treated as newlines.\n  Flex breaks, however, are re-evaluated on every occurrence and may still\n  be rendered flat. See `break/1` and `flex_break/1` for more information.\n\n  This implementation also adds `force_unfit/1` and optimistic/pessimistic\n  groups which give more control over the document fitting.\n\n    [0]: https://lindig.github.io/papers/strictly-pretty-2000.pdf\n\n  \"\"\"\n\n  @container_separator \",\"\n  @tail_separator \" |\"\n  @newline \"\\n\"\n\n  # Functional interface to \"doc\" records\n\n  @type t ::\n          binary\n          | doc_nil\n          | doc_cons\n          | doc_line\n          | doc_break\n          | doc_collapse\n          | doc_color\n          | doc_fits\n          | doc_force\n          | doc_group\n          | doc_nest\n          | doc_string\n          | doc_limit\n\n  @typep doc_nil :: []\n  defmacrop doc_nil do\n    []\n  end\n\n  @typep doc_line :: :doc_line\n  defmacrop doc_line do\n    :doc_line\n  end\n\n  @typep doc_cons :: nonempty_improper_list(t, t)\n  defmacrop doc_cons(left, right) do\n    quote do: [unquote(left) | unquote(right)]\n  end\n\n  @typep doc_string :: {:doc_string, binary, non_neg_integer}\n  defmacrop doc_string(string, length) do\n    quote do: {:doc_string, unquote(string), unquote(length)}\n  end\n\n  @typep doc_limit :: {:doc_limit, t, pos_integer | :infinity}\n  defmacrop doc_limit(doc, limit) do\n    quote do: {:doc_limit, unquote(doc), unquote(limit)}\n  end\n\n  @typep doc_nest :: {:doc_nest, t, :cursor | :reset | non_neg_integer, :always | :break}\n  defmacrop doc_nest(doc, indent, always_or_break) do\n    quote do: {:doc_nest, unquote(doc), unquote(indent), unquote(always_or_break)}\n  end\n\n  @typep doc_break :: {:doc_break, binary, :flex | :strict}\n  defmacrop doc_break(break, mode) do\n    quote do: {:doc_break, unquote(break), unquote(mode)}\n  end\n\n  @typep doc_group :: {:doc_group, t, :normal | :optimistic | :pessimistic | :inherit}\n  defmacrop doc_group(group, mode) do\n    quote do: {:doc_group, unquote(group), unquote(mode)}\n  end\n\n  @typep doc_fits :: {:doc_fits, t, :enabled | :disabled}\n  defmacrop doc_fits(group, mode) do\n    quote do: {:doc_fits, unquote(group), unquote(mode)}\n  end\n\n  @typep doc_force :: {:doc_force, t}\n  defmacrop doc_force(group) do\n    quote do: {:doc_force, unquote(group)}\n  end\n\n  @typep doc_collapse :: {:doc_collapse, pos_integer()}\n  defmacrop doc_collapse(count) do\n    quote do: {:doc_collapse, unquote(count)}\n  end\n\n  @typep doc_color :: {:doc_color, t, IO.ANSI.ansidata()}\n  defmacrop doc_color(doc, color) do\n    quote do: {:doc_color, unquote(doc), unquote(color)}\n  end\n\n  @typedoc \"\"\"\n  Options for container documents.\n  \"\"\"\n  @type container_opts :: [\n          separator: String.t(),\n          break: :strict | :flex | :maybe\n        ]\n\n  @docs [\n    :doc_break,\n    :doc_collapse,\n    :doc_color,\n    :doc_cons,\n    :doc_fits,\n    :doc_force,\n    :doc_group,\n    :doc_nest,\n    :doc_string,\n    :doc_limit\n  ]\n\n  defguard is_doc(doc)\n           when is_list(doc) or is_binary(doc) or doc == doc_line() or\n                  (is_tuple(doc) and elem(doc, 0) in @docs)\n\n  defguardp is_width(width) when width == :infinity or (is_integer(width) and width >= 0)\n\n  # Elixir + Inspect.Opts conveniences\n  # These have the _doc suffix.\n\n  @doc \"\"\"\n  Converts an Elixir term to an algebra document\n  according to the `Inspect` protocol.\n\n  In practice, one must prefer to use `to_doc_with_opts/2`\n  over this function, as `to_doc_with_opts/2` returns the\n  updated options from inspection.\n  \"\"\"\n  @spec to_doc(any, Inspect.Opts.t()) :: t\n  def to_doc(term, opts) do\n    to_doc_with_opts(term, opts) |> elem(0)\n  end\n\n  @doc \"\"\"\n  Converts an Elixir term to an algebra document\n  according to the `Inspect` protocol, alongside the updated options.\n\n  This function is used when implementing the inspect protocol for\n  a given type and you must convert nested terms to documents too.\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec to_doc_with_opts(any, Inspect.Opts.t()) :: {t, Inspect.Opts.t()}\n  def to_doc_with_opts(term, opts)\n\n  def to_doc_with_opts(%_{} = struct, %Inspect.Opts{inspect_fun: fun} = opts) do\n    if opts.structs and valid_struct?(struct) do\n      try do\n        fun.(struct, opts)\n      rescue\n        caught_exception ->\n          # Because we try to raise a nice error message in case\n          # we can't inspect a struct, there is a chance the error\n          # message itself relies on the struct being printed, so\n          # we need to trap the inspected messages to guarantee\n          # we won't try to render any failed instruct when building\n          # the error message.\n          if Process.get(:inspect_trap) do\n            Inspect.Map.inspect_as_map(struct, opts)\n          else\n            try do\n              Process.put(:inspect_trap, true)\n\n              {doc_struct, _opts} =\n                Inspect.Map.inspect_as_map(struct, %{\n                  opts\n                  | syntax_colors: [],\n                    inspect_fun: Inspect.Opts.default_inspect_fun()\n                })\n\n              inspected_struct =\n                doc_struct\n                |> format(opts.width)\n                |> IO.iodata_to_binary()\n\n              inspect_error =\n                Inspect.Error.exception(\n                  exception: caught_exception,\n                  stacktrace: __STACKTRACE__,\n                  inspected_struct: inspected_struct\n                )\n\n              if opts.safe do\n                opts = %{opts | inspect_fun: Inspect.Opts.default_inspect_fun()}\n                Inspect.inspect(inspect_error, opts)\n              else\n                reraise(inspect_error, __STACKTRACE__)\n              end\n            after\n              Process.delete(:inspect_trap)\n            end\n          end\n      end\n    else\n      Inspect.Map.inspect_as_map(struct, opts)\n    end\n    |> pack_opts(opts)\n  end\n\n  def to_doc_with_opts(arg, %Inspect.Opts{inspect_fun: fun} = opts) do\n    fun.(arg, opts) |> pack_opts(opts)\n  end\n\n  defp valid_struct?(%module{} = struct) do\n    try do\n      module.__info__(:struct)\n    rescue\n      _ -> false\n    else\n      info ->\n        valid_struct?(info, struct, map_size(struct) - 1)\n    end\n  end\n\n  defp valid_struct?([%{field: field} | info], struct, count) when is_map_key(struct, field),\n    do: valid_struct?(info, struct, count - 1)\n\n  defp valid_struct?([], _struct, 0),\n    do: true\n\n  defp valid_struct?(_fields, _struct, _count),\n    do: false\n\n  defp pack_opts({_doc, %Inspect.Opts{}} = doc_opts, _opts), do: doc_opts\n  defp pack_opts(doc, opts), do: {doc, opts}\n\n  @doc ~S\"\"\"\n  Wraps `collection` in `left` and `right` according to limit and contents\n  and returns only the container document.\n\n  In practice, one must prefer to use `container_doc_with_opts/6`\n  over this function, as `container_doc_with_opts/6` returns the\n  updated options from inspection.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec container_doc(\n          t,\n          [term],\n          t,\n          Inspect.Opts.t(),\n          (term, Inspect.Opts.t() -> t),\n          container_opts()\n        ) ::\n          t\n  def container_doc(left, collection, right, inspect_opts, fun, opts \\\\ []) do\n    container_doc_with_opts(left, collection, right, inspect_opts, fun, opts) |> elem(0)\n  end\n\n  @doc ~S\"\"\"\n  Wraps `collection` in `left` and `right` according to limit and contents.\n\n  It uses the given `left` and `right` documents as surrounding and the\n  separator document `separator` to separate items in `docs`. If all entries\n  in the collection are simple documents (texts or strings), then this function\n  attempts to put as much as possible on the same line. If they are not simple,\n  only one entry is shown per line if they do not fit.\n\n  The limit in the given `inspect_opts` is respected and when reached this\n  function stops processing and outputs `\"...\"` instead.\n\n  It returns a tuple with the algebra document and the updated options.\n\n  ## Options\n\n    * `:separator` - the separator used between each doc\n    * `:break` - If `:strict`, always break between each element. If `:flex`,\n      breaks only when necessary. If `:maybe`, chooses `:flex` only if all\n      elements are text-based, otherwise is `:strict`\n\n  ## Examples\n\n      iex> inspect_opts = %Inspect.Opts{limit: :infinity}\n      iex> fun = fn i, _opts -> to_string(i) end\n      iex> {doc, _opts} = Inspect.Algebra.container_doc_with_opts(\"[\", Enum.to_list(1..5), \"]\", inspect_opts, fun)\n      iex> Inspect.Algebra.format(doc, 5) |> IO.iodata_to_binary()\n      \"[1,\\n 2,\\n 3,\\n 4,\\n 5]\"\n\n      iex> inspect_opts = %Inspect.Opts{limit: 3}\n      iex> fun = fn i, _opts -> to_string(i) end\n      iex> {doc, _opts} = Inspect.Algebra.container_doc_with_opts(\"[\", Enum.to_list(1..5), \"]\", inspect_opts, fun)\n      iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary()\n      \"[1, 2, 3, ...]\"\n\n      iex> inspect_opts = %Inspect.Opts{limit: 3}\n      iex> fun = fn i, _opts -> to_string(i) end\n      iex> opts = [separator: \"!\"]\n      iex> {doc, _opts} = Inspect.Algebra.container_doc_with_opts(\"[\", Enum.to_list(1..5), \"]\", inspect_opts, fun, opts)\n      iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary()\n      \"[1! 2! 3! ...]\"\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec container_doc_with_opts(\n          t,\n          [term],\n          t,\n          Inspect.Opts.t(),\n          (term, Inspect.Opts.t() -> t),\n          container_opts()\n        ) ::\n          {t, Inspect.Opts.t()}\n  def container_doc_with_opts(left, collection, right, inspect_opts, fun, opts \\\\ [])\n      when is_doc(left) and is_list(collection) and is_doc(right) and is_function(fun, 2) and\n             is_list(opts) do\n    case collection do\n      [] ->\n        {concat(left, right), inspect_opts}\n\n      _ ->\n        break = Keyword.get(opts, :break, :maybe)\n        separator = Keyword.get(opts, :separator, @container_separator)\n\n        {docs, simple?, inspect_opts} =\n          container_each(collection, inspect_opts, fun, [], break == :maybe)\n\n        flex? = simple? or break == :flex\n        docs = fold(docs, &join(&1, &2, flex?, separator))\n\n        group =\n          case flex? do\n            true -> doc_group(concat(concat(left, nest(docs, 1)), right), :normal)\n            false -> doc_group(glue(nest(glue(left, \"\", docs), 2), \"\", right), :normal)\n          end\n\n        {group, inspect_opts}\n    end\n  end\n\n  defp container_each([], opts, _fun, acc, simple?) do\n    {:lists.reverse(acc), simple?, opts}\n  end\n\n  defp container_each(_, opts, _fun, acc, simple?) when opts.limit <= 0 do\n    {:lists.reverse([\"...\" | acc]), simple?, opts}\n  end\n\n  defp container_each([term | terms], opts, fun, acc, simple?) when is_list(terms) do\n    {doc, opts} = call_container_fun(fun, term, opts)\n    container_each(terms, opts, fun, [doc | acc], simple? and simple?(doc))\n  end\n\n  defp container_each([left | right], opts, fun, acc, simple?) do\n    {left, opts} = call_container_fun(fun, left, opts)\n    {right, _opts} = call_container_fun(fun, right, opts)\n    simple? = simple? and simple?(left) and simple?(right)\n    doc = join(left, right, simple?, @tail_separator)\n    {:lists.reverse([doc | acc]), simple?, opts}\n  end\n\n  defp call_container_fun(fun, term, %{limit: bounded} = opts)\n       when bounded <= 0 or bounded == :infinity do\n    case fun.(term, opts) do\n      {doc, %Inspect.Opts{} = opts} -> {doc, opts}\n      doc -> {doc, opts}\n    end\n  end\n\n  defp call_container_fun(fun, term, %{limit: limit} = opts) do\n    changed_opts = %{opts | limit: limit - 1}\n\n    case fun.(term, changed_opts) do\n      {doc, %Inspect.Opts{} = opts} -> {doc, opts}\n      doc_nil() -> {doc_nil(), opts}\n      doc -> {doc, changed_opts}\n    end\n  end\n\n  defp join(doc_nil(), doc_nil(), _, _), do: doc_nil()\n  defp join(left, doc_nil(), _, _), do: left\n  defp join(doc_nil(), right, _, _), do: right\n  defp join(left, right, true, sep), do: flex_glue(concat(left, sep), right)\n  defp join(left, right, false, sep), do: glue(concat(left, sep), right)\n\n  defp simple?(doc_cons(left, right)), do: simple?(left) and simple?(right)\n  defp simple?(doc_color(doc, _)), do: simple?(doc)\n  defp simple?(doc_string(_, _)), do: true\n  defp simple?(doc_nil()), do: true\n  defp simple?(other), do: is_binary(other)\n\n  @doc false\n  @deprecated \"Use a combination of concat/2 and nest/2 instead\"\n  def surround(left, doc, right) when is_doc(left) and is_doc(doc) and is_doc(right) do\n    concat(concat(left, nest(doc, 1)), right)\n  end\n\n  @doc false\n  @deprecated \"Use Inspect.Algebra.container_doc/6 instead\"\n  def surround_many(\n        left,\n        docs,\n        right,\n        %Inspect.Opts{} = inspect,\n        fun,\n        separator \\\\ @container_separator\n      )\n      when is_doc(left) and is_list(docs) and is_doc(right) and is_function(fun, 2) do\n    container_doc(left, docs, right, inspect, fun, separator: separator)\n  end\n\n  # TODO: Deprecate me on Elixir v1.23\n  @doc deprecated: \"Use color_doc/3 instead\"\n  def color(doc, key, opts) do\n    color_doc(doc, key, opts)\n  end\n\n  @doc ~S\"\"\"\n  Colors a document if the `color_key` has a color in the options.\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec color_doc(t, Inspect.Opts.color_key(), Inspect.Opts.t()) :: t\n  def color_doc(doc, color_key, %Inspect.Opts{syntax_colors: syntax_colors}) when is_doc(doc) do\n    if precolor = Keyword.get(syntax_colors, color_key) do\n      postcolor = Keyword.get(syntax_colors, :reset, :reset)\n      concat(doc_color(doc, ansi(precolor)), doc_color(empty(), ansi(postcolor)))\n    else\n      doc\n    end\n  end\n\n  defp ansi(color) do\n    color\n    |> IO.ANSI.format_fragment(true)\n    |> IO.iodata_to_binary()\n  end\n\n  # Algebra API\n\n  @compile {:inline,\n            empty: 0,\n            concat: 2,\n            break: 0,\n            break: 1,\n            glue: 2,\n            glue: 3,\n            flex_break: 0,\n            flex_break: 1,\n            flex_glue: 2,\n            flex_glue: 3}\n\n  @doc \"\"\"\n  Returns a document entity used to represent nothingness.\n\n  ## Examples\n\n      iex> Inspect.Algebra.empty()\n      []\n\n  \"\"\"\n  @spec empty() :: doc_nil()\n  def empty, do: doc_nil()\n\n  @doc ~S\"\"\"\n  Creates a document represented by string.\n\n  While `Inspect.Algebra` accepts binaries as documents,\n  those are counted by binary size. On the other hand,\n  `string` documents are measured in terms of graphemes\n  towards the document size.\n\n  ## Examples\n\n  The following document has 10 bytes and therefore it\n  does not format to width 9 without breaks:\n\n      iex> doc = Inspect.Algebra.glue(\"olá\", \" \", \"mundo\")\n      iex> doc = Inspect.Algebra.group(doc)\n      iex> Inspect.Algebra.format(doc, 9)\n      \"olá\\nmundo\"\n\n  However, if we use `string`, then the string length is\n  used, instead of byte size, correctly fitting:\n\n      iex> string = Inspect.Algebra.string(\"olá\")\n      iex> doc = Inspect.Algebra.glue(string, \" \", \"mundo\")\n      iex> doc = Inspect.Algebra.group(doc)\n      iex> Inspect.Algebra.format(doc, 9)\n      \"olá mundo\"\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec string(String.t()) :: doc_string\n  def string(string) when is_binary(string) do\n    doc_string(string, String.length(string))\n  end\n\n  @doc ~S\"\"\"\n  Concatenates two document entities returning a new document.\n\n  ## Examples\n\n      iex> doc = Inspect.Algebra.concat(\"hello\", \"world\")\n      iex> Inspect.Algebra.format(doc, 80)\n      \"helloworld\"\n\n  \"\"\"\n  @spec concat(t, t) :: t\n  def concat(doc1, doc2) when is_doc(doc1) and is_doc(doc2) do\n    doc_cons(doc1, doc2)\n  end\n\n  @doc ~S\"\"\"\n  Disable any rendering limit while rendering the given document.\n\n  ## Examples\n\n      iex> doc = Inspect.Algebra.glue(\"hello\", \"world\") |> Inspect.Algebra.group()\n      iex> Inspect.Algebra.format(doc, 10)\n      \"hello\\nworld\"\n      iex> doc = Inspect.Algebra.no_limit(doc)\n      iex> Inspect.Algebra.format(doc, 10)\n      \"hello world\"\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec no_limit(t) :: t\n  def no_limit(doc) do\n    doc_limit(doc, :infinity)\n  end\n\n  @doc ~S\"\"\"\n  Concatenates a list of documents returning a new document.\n\n  ## Examples\n\n      iex> doc = Inspect.Algebra.concat([\"a\", \"b\", \"c\"])\n      iex> Inspect.Algebra.format(doc, 80)\n      \"abc\"\n\n  \"\"\"\n  @spec concat([t]) :: t\n  def concat(docs) when is_list(docs) do\n    fold(docs, &concat(&1, &2))\n  end\n\n  @doc ~S\"\"\"\n  Colors a document with the given color (preceding the document itself).\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec color(t, binary) :: t\n  def color(doc, color) when is_doc(doc) and is_binary(color) do\n    doc_color(doc, color)\n  end\n\n  @doc ~S\"\"\"\n  Nests the given document at the given `level`.\n\n  If `level` is an integer, that's the indentation appended\n  to line breaks whenever they occur. If the level is `:cursor`,\n  the current position of the \"cursor\" in the document becomes\n  the nesting. If the level is `:reset`, it is set back to 0.\n\n  `mode` can be `:always`, which means nesting always happen,\n  or `:break`, which means nesting only happens inside a group\n  that has been broken.\n\n  ## Examples\n\n      iex> doc = Inspect.Algebra.nest(Inspect.Algebra.glue(\"hello\", \"world\"), 5)\n      iex> doc = Inspect.Algebra.group(doc)\n      iex> Inspect.Algebra.format(doc, 5)\n      \"hello\\n     world\"\n\n  \"\"\"\n  @spec nest(t, non_neg_integer | :cursor | :reset, :always | :break) :: doc_nest | t\n  def nest(doc, level, mode \\\\ :always)\n\n  def nest(doc, :cursor, mode) when is_doc(doc) and mode in [:always, :break] do\n    doc_nest(doc, :cursor, mode)\n  end\n\n  def nest(doc, :reset, mode) when is_doc(doc) and mode in [:always, :break] do\n    doc_nest(doc, :reset, mode)\n  end\n\n  def nest(doc, 0, _mode) when is_doc(doc) do\n    doc\n  end\n\n  def nest(doc, level, mode)\n      when is_doc(doc) and is_integer(level) and level > 0 and mode in [:always, :break] do\n    doc_nest(doc, level, mode)\n  end\n\n  @doc ~S\"\"\"\n  Returns a break document based on the given `string`.\n\n  This break can be rendered as a linebreak or as the given `string`,\n  depending on the `mode` of the chosen layout.\n\n  ## Examples\n\n  Let's create a document by concatenating two strings with a break between\n  them:\n\n      iex> doc = Inspect.Algebra.concat([\"a\", Inspect.Algebra.break(\"\\t\"), \"b\"])\n      iex> Inspect.Algebra.format(doc, 80)\n      \"a\\tb\"\n\n  Note that the break was represented with the given string, because we didn't\n  reach a line limit. Once we do, it is replaced by a newline:\n\n      iex> break = Inspect.Algebra.break(\"\\t\")\n      iex> doc = Inspect.Algebra.concat([String.duplicate(\"a\", 20), break, \"b\"])\n      iex> doc = Inspect.Algebra.group(doc)\n      iex> Inspect.Algebra.format(doc, 10)\n      \"aaaaaaaaaaaaaaaaaaaa\\nb\"\n\n  \"\"\"\n  @spec break(binary) :: doc_break\n  def break(string \\\\ \" \") when is_binary(string) do\n    doc_break(string, :strict)\n  end\n\n  @doc \"\"\"\n  Collapse any new lines and whitespace following this\n  node, emitting up to `max` new lines.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec collapse_lines(pos_integer) :: doc_collapse\n  def collapse_lines(max) when is_integer(max) and max > 0 do\n    doc_collapse(max)\n  end\n\n  @doc \"\"\"\n  Considers the next break as fit.\n  \"\"\"\n  # TODO: Deprecate me on Elixir v1.23\n  @doc deprecated: \"Pass the optimistic/pessimistic type to group/2 instead\"\n  @spec next_break_fits(t, :enabled | :disabled) :: doc_fits\n  def next_break_fits(doc, mode \\\\ :enabled)\n      when is_doc(doc) and mode in [:enabled, :disabled] do\n    doc_fits(doc, mode)\n  end\n\n  @doc \"\"\"\n  Forces the current group to be unfit.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec force_unfit(t) :: doc_force\n  def force_unfit(doc) when is_doc(doc) do\n    doc_force(doc)\n  end\n\n  @doc \"\"\"\n  Returns a flex break document based on the given `string`.\n\n  A flex break still causes a group to break, like `break/1`,\n  but it is re-evaluated when the documented is rendered.\n\n  For example, take a group document represented as `[1, 2, 3]`\n  where the space after every comma is a break. When the document\n  above does not fit a single line, all breaks are enabled,\n  causing the document to be rendered as:\n\n      [1,\n       2,\n       3]\n\n  However, if flex breaks are used, then each break is re-evaluated\n  when rendered, so the document could be possible rendered as:\n\n      [1, 2,\n       3]\n\n  Hence the name \"flex\". they are more flexible when it comes\n  to the document fitting. On the other hand, they are more expensive\n  since each break needs to be re-evaluated.\n\n  This function is used by `container_doc/6` and friends to the\n  maximum number of entries on the same line.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec flex_break(binary) :: doc_break\n  def flex_break(string \\\\ \" \") when is_binary(string) do\n    doc_break(string, :flex)\n  end\n\n  @doc \"\"\"\n  Glues two documents (`doc1` and `doc2`) inserting a\n  `flex_break/1` given by `break_string` between them.\n\n  This function is used by `container_doc/6` and friends\n  to the maximum number of entries on the same line.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec flex_glue(t, binary, t) :: t\n  def flex_glue(doc1, break_string \\\\ \" \", doc2) when is_binary(break_string) do\n    concat(doc1, concat(flex_break(break_string), doc2))\n  end\n\n  @doc ~S\"\"\"\n  Glues two documents (`doc1` and `doc2`) inserting the given\n  break `break_string` between them.\n\n  For more information on how the break is inserted, see `break/1`.\n\n  ## Examples\n\n      iex> doc = Inspect.Algebra.glue(\"hello\", \"world\")\n      iex> Inspect.Algebra.format(doc, 80)\n      \"hello world\"\n\n      iex> doc = Inspect.Algebra.glue(\"hello\", \"\\t\", \"world\")\n      iex> Inspect.Algebra.format(doc, 80)\n      \"hello\\tworld\"\n\n  \"\"\"\n  @spec glue(t, binary, t) :: t\n  def glue(doc1, break_string \\\\ \" \", doc2) when is_binary(break_string) do\n    concat(doc1, concat(break(break_string), doc2))\n  end\n\n  @doc ~S\"\"\"\n  Returns a group containing the specified document `doc`.\n\n  Documents in a group are attempted to be rendered together\n  to the best of the renderer ability. If there are `break/1`s\n  in the group and the group does not fit the given width,\n  the breaks are converted into lines. Otherwise the breaks\n  are rendered as text based on their string contents.\n\n  There are three types of groups, described next.\n\n  ## Group modes\n\n    * `:normal` - the group fits if it fits within the given width\n\n    * `:optimistic` - the group fits if it fits within the given\n      width. However, when nested within another group, the parent\n      group will assume this group fits as long as it has a single\n      break, even if the optimistic group has a `force_unfit/1`\n      document within it. Overall, this has an effect similar\n      to swapping the order groups break. For example, if you have\n      a `parent_group(child_group)` and they do not fit, the parent\n      converts breaks into newlines first, allowing the child to compute\n      if it fits. However, if the child group is optimistic and it\n      has breaks, then the parent assumes it fits, leaving the overall\n      fitting decision to the child\n\n    * `:pessimistic` - the group fits if it fits within the given\n      width. However it disables any optimistic group within it\n\n  ## Examples\n\n      iex> doc =\n      ...>   Inspect.Algebra.group(\n      ...>     Inspect.Algebra.concat(\n      ...>       Inspect.Algebra.group(\n      ...>         Inspect.Algebra.concat(\n      ...>           \"Hello,\",\n      ...>           Inspect.Algebra.concat(\n      ...>             Inspect.Algebra.break(),\n      ...>             \"A\"\n      ...>           )\n      ...>         )\n      ...>       ),\n      ...>       Inspect.Algebra.concat(\n      ...>         Inspect.Algebra.break(),\n      ...>         \"B\"\n      ...>       )\n      ...>     )\n      ...>   )\n      iex> Inspect.Algebra.format(doc, 80)\n      \"Hello, A B\"\n      iex> Inspect.Algebra.format(doc, 6)\n      \"Hello,\\nA\\nB\"\n\n  ## Mode examples\n\n  The different groups modes are used by Elixir's code formatter\n  to avoid breaking code at some specific locations. For example,\n  consider this code:\n\n      some_function_call(%{..., key: value, ...})\n\n  Now imagine that this code does not fit its line. The code\n  formatter introduces breaks inside `(` and `)` and inside\n  `%{` and `}`, each within their own group. Therefore the\n  document would break as:\n\n      some_function_call(\n        %{\n          ...,\n          key: value,\n          ...\n        }\n      )\n\n  To address this, the formatter marks the inner group as optimistic.\n  This means the first group, which is `(...)` will consider the document\n  fits and avoids adding breaks around the parens. So overall the code\n  is formatted as:\n\n      some_function_call(%{\n        ...,\n        key: value,\n        ...\n      })\n\n  \"\"\"\n  @spec group(t, :normal | :optimistic | :pessimistic) :: doc_group\n  def group(doc, mode \\\\ :normal) when is_doc(doc) do\n    doc_group(\n      doc,\n      case mode do\n        # TODO: Deprecate :self and :inherit on Elixir v1.23\n        :self -> :normal\n        :inherit -> :inherit\n        mode when mode in [:normal, :optimistic, :pessimistic] -> mode\n      end\n    )\n  end\n\n  @doc ~S\"\"\"\n  Inserts a mandatory single space between two documents.\n\n  ## Examples\n\n      iex> doc = Inspect.Algebra.space(\"Hughes\", \"Wadler\")\n      iex> Inspect.Algebra.format(doc, 5)\n      \"Hughes Wadler\"\n\n  \"\"\"\n  @spec space(t, t) :: t\n  def space(doc1, doc2), do: concat(doc1, concat(\" \", doc2))\n\n  @doc ~S\"\"\"\n  A mandatory linebreak.\n\n  A group with linebreaks will fit if all lines in the group fit.\n\n  ## Examples\n\n      iex> doc =\n      ...>   Inspect.Algebra.concat(\n      ...>     Inspect.Algebra.concat(\n      ...>       \"Hughes\",\n      ...>       Inspect.Algebra.line()\n      ...>     ),\n      ...>     \"Wadler\"\n      ...>   )\n      iex> Inspect.Algebra.format(doc, 80)\n      \"Hughes\\nWadler\"\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec line() :: t\n  def line(), do: doc_line()\n\n  @doc ~S\"\"\"\n  Inserts a mandatory linebreak between two documents.\n\n  See `line/0`.\n\n  ## Examples\n\n      iex> doc = Inspect.Algebra.line(\"Hughes\", \"Wadler\")\n      iex> Inspect.Algebra.format(doc, 80)\n      \"Hughes\\nWadler\"\n\n  \"\"\"\n  @spec line(t, t) :: t\n  def line(doc1, doc2), do: concat(doc1, concat(line(), doc2))\n\n  # TODO: Deprecate me on Elixir v1.23\n  @doc deprecated: \"Use fold/2 instead\"\n  def fold_doc(docs, folder_fun), do: fold(docs, folder_fun)\n\n  @doc ~S\"\"\"\n  Folds a list of documents into a document using the given folder function.\n\n  The list of documents is folded \"from the right\"; in that, this function is\n  similar to `List.foldr/3`, except that it doesn't expect an initial\n  accumulator and uses the last element of `docs` as the initial accumulator.\n\n  ## Examples\n\n      iex> docs = [\"A\", \"B\", \"C\"]\n      iex> docs =\n      ...>   Inspect.Algebra.fold(docs, fn doc, acc ->\n      ...>     Inspect.Algebra.concat([doc, \"!\", acc])\n      ...>   end)\n      iex> Inspect.Algebra.format(docs, 80)\n      \"A!B!C\"\n\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec fold([t], (t, t -> t)) :: t\n  def fold(docs, folder_fun)\n\n  def fold([], _folder_fun), do: empty()\n  def fold([doc], _folder_fun), do: doc\n\n  def fold([doc | docs], folder_fun) when is_function(folder_fun, 2),\n    do: folder_fun.(doc, fold(docs, folder_fun))\n\n  @doc ~S\"\"\"\n  Formats a given document for a given width.\n\n  Takes the maximum width and a document to print as its arguments\n  and returns an IO data representation of the best layout for the\n  document to fit in the given width.\n\n  The document starts flat (without breaks) until a group is found.\n\n  ## Examples\n\n      iex> doc = Inspect.Algebra.glue(\"hello\", \" \", \"world\")\n      iex> doc = Inspect.Algebra.group(doc)\n      iex> doc |> Inspect.Algebra.format(30) |> IO.iodata_to_binary()\n      \"hello world\"\n      iex> doc |> Inspect.Algebra.format(10) |> IO.iodata_to_binary()\n      \"hello\\nworld\"\n\n  \"\"\"\n  @spec format(t, non_neg_integer | :infinity) :: iodata\n  def format(doc, width) when is_doc(doc) and is_width(width) do\n    format(width, 0, [{0, :flat, doc}], <<>>)\n  end\n\n  # Type representing the document mode to be rendered:\n  #\n  #   * flat - represents a document with breaks as flats (a break may fit, as it may break)\n  #   * break - represents a document with breaks as breaks (a break always fits, since it breaks)\n  #\n  # These other two modes only affect fitting:\n  #\n  #   * flat_no_break - represents a document with breaks as flat not allowed to enter in break mode\n  #   * break_no_flat - represents a document with breaks as breaks not allowed to enter in flat mode\n  #\n  @typep mode :: :flat | :flat_no_break | :break | :break_no_flat\n\n  @spec fits?(\n          width :: non_neg_integer() | :infinity,\n          column :: non_neg_integer(),\n          break? :: boolean(),\n          entries\n        ) :: boolean()\n        when entries:\n               maybe_improper_list(\n                 {integer(), mode(), t()} | :group_over,\n                 {:tail, boolean(), entries} | []\n               )\n\n  # We need at least a break to consider the document does not fit since a\n  # large document without breaks has no option but fitting its current line.\n  #\n  # In case we have groups and the group fits, we need to consider the group\n  # parent without the child breaks, hence {:tail, b?, t} below.\n  defp fits?(w, k, b?, _) when k > w and b?, do: false\n  defp fits?(_, _, _, []), do: true\n  defp fits?(w, k, _, {:tail, b?, t}), do: fits?(w, k, b?, t)\n\n  ## Group over\n  # If we get to the end of the group and if fits, it is because\n  # something already broke elsewhere, so we can consider the group\n  # fits. This only appears when checking if a flex break and fitting.\n\n  defp fits?(_w, _k, b?, [:group_over | _]),\n    do: b?\n\n  ## Flat no break\n\n  defp fits?(w, k, b?, [{i, _, doc_fits(x, :disabled)} | t]),\n    do: fits?(w, k, b?, [{i, :flat_no_break, x} | t])\n\n  defp fits?(w, k, b?, [{i, :flat_no_break, doc_fits(x, _)} | t]),\n    do: fits?(w, k, b?, [{i, :flat_no_break, x} | t])\n\n  defp fits?(w, k, b?, [{i, _, doc_group(x, :pessimistic)} | t]),\n    do: fits?(w, k, b?, [{i, :flat_no_break, x} | t])\n\n  defp fits?(w, k, b?, [{i, :flat_no_break, doc_group(x, _)} | t]),\n    do: fits?(w, k, b?, [{i, :flat_no_break, x} | t])\n\n  ## Breaks no flat\n\n  defp fits?(w, k, b?, [{i, _, doc_fits(x, :enabled)} | t]),\n    do: fits?(w, k, b?, [{i, :break_no_flat, x} | t])\n\n  defp fits?(w, k, b?, [{i, _, doc_group(x, :optimistic)} | t]),\n    do: fits?(w, k, b?, [{i, :break_no_flat, x} | t])\n\n  defp fits?(w, k, b?, [{i, :break_no_flat, doc_force(x)} | t]),\n    do: fits?(w, k, b?, [{i, :break_no_flat, x} | t])\n\n  defp fits?(_, _, _, [{_, :break_no_flat, doc_break(_, _)} | _]), do: true\n  defp fits?(_, _, _, [{_, :break_no_flat, doc_line()} | _]), do: true\n\n  ## Breaks\n\n  defp fits?(_, _, _, [{_, :break, doc_break(_, _)} | _]), do: true\n  defp fits?(_, _, _, [{_, :break, doc_line()} | _]), do: true\n\n  defp fits?(w, k, b?, [{i, :break, doc_group(x, _)} | t]),\n    do: fits?(w, k, b?, [{i, :flat, x} | {:tail, b?, t}])\n\n  ## Catch all\n\n  defp fits?(w, _, _, [{i, _, doc_line()} | t]), do: fits?(w, i, false, t)\n  defp fits?(w, k, b?, [{_, _, doc_nil()} | t]), do: fits?(w, k, b?, t)\n  defp fits?(w, _, b?, [{i, _, doc_collapse(_)} | t]), do: fits?(w, i, b?, t)\n  defp fits?(w, k, b?, [{i, m, doc_color(x, _)} | t]), do: fits?(w, k, b?, [{i, m, x} | t])\n  defp fits?(w, k, b?, [{_, _, doc_string(_, l)} | t]), do: fits?(w, k + l, b?, t)\n  defp fits?(w, k, b?, [{_, _, s} | t]) when is_binary(s), do: fits?(w, k + byte_size(s), b?, t)\n  defp fits?(_, _, _, [{_, _, doc_force(_)} | _]), do: false\n  defp fits?(w, k, _, [{_, _, doc_break(s, _)} | t]), do: fits?(w, k + byte_size(s), true, t)\n  defp fits?(w, k, b?, [{i, m, doc_nest(x, _, :break)} | t]), do: fits?(w, k, b?, [{i, m, x} | t])\n\n  defp fits?(w, k, b?, [{i, m, doc_nest(x, j, _)} | t]),\n    do: fits?(w, k, b?, [{apply_nesting(i, k, j), m, x} | t])\n\n  defp fits?(w, k, b?, [{i, m, doc_cons(x, y)} | t]),\n    do: fits?(w, k, b?, [{i, m, x}, {i, m, y} | t])\n\n  defp fits?(w, k, b?, [{i, m, doc_group(x, _)} | t]),\n    do: fits?(w, k, b?, [{i, m, x} | {:tail, b?, t}])\n\n  defp fits?(w, k, b?, [{i, m, doc_limit(x, :infinity)} | t]) when w != :infinity,\n    do: fits?(:infinity, k, b?, [{i, :flat, x}, {i, m, doc_limit(empty(), w)} | t])\n\n  defp fits?(_w, k, b?, [{i, m, doc_limit(x, w)} | t]),\n    do: fits?(w, k, b?, [{i, m, x} | t])\n\n  @spec format(\n          width :: non_neg_integer() | :infinity,\n          column :: non_neg_integer(),\n          [{integer, mode, t} | :group_over],\n          binary\n        ) :: iodata\n  defp format(_, _, [], acc), do: acc\n\n  defp format(w, k, [{_, _, doc_nil()} | t], acc),\n    do: format(w, k, t, acc)\n\n  defp format(w, _, [{i, _, doc_line()} | t], acc),\n    do: format(w, i, t, <<acc::binary, indent(i)::binary>>)\n\n  defp format(w, k, [{i, m, doc_cons(x, y)} | t], acc),\n    do: format(w, k, [{i, m, x}, {i, m, y} | t], acc)\n\n  defp format(w, k, [{i, m, doc_color(x, c)} | t], acc),\n    do: format(w, k, [{i, m, x} | t], <<acc::binary, c::binary>>)\n\n  defp format(w, k, [{_, _, doc_string(s, l)} | t], acc),\n    do: format(w, k + l, t, <<acc::binary, s::binary>>)\n\n  defp format(w, k, [{_, _, s} | t], acc) when is_binary(s),\n    do: format(w, k + byte_size(s), t, <<acc::binary, s::binary>>)\n\n  defp format(w, k, [{i, m, doc_force(x)} | t], acc),\n    do: format(w, k, [{i, m, x} | t], acc)\n\n  defp format(w, k, [{i, m, doc_fits(x, _)} | t], acc),\n    do: format(w, k, [{i, m, x} | t], acc)\n\n  defp format(w, _, [{i, _, doc_collapse(max)} | t], acc),\n    do: [acc | collapse(List.wrap(format(w, i, t, <<>>)), max, 0, i)]\n\n  # Flex breaks are conditional to the document and the mode\n  defp format(w, k, [{i, m, doc_break(s, :flex)} | t], acc) do\n    k = k + byte_size(s)\n\n    if w == :infinity or m == :flat or fits?(w, k, true, t) do\n      format(w, k, t, <<acc::binary, s::binary>>)\n    else\n      format(w, i, t, <<acc::binary, indent(i)::binary>>)\n    end\n  end\n\n  # Strict breaks are conditional to the mode\n  defp format(w, k, [{i, mode, doc_break(s, :strict)} | t], acc) do\n    if mode == :break do\n      format(w, i, t, <<acc::binary, indent(i)::binary>>)\n    else\n      format(w, k + byte_size(s), t, <<acc::binary, s::binary>>)\n    end\n  end\n\n  # Nesting is conditional to the mode.\n  defp format(w, k, [{i, mode, doc_nest(x, j, nest)} | t], acc) do\n    if nest == :always or (nest == :break and mode == :break) do\n      format(w, k, [{apply_nesting(i, k, j), mode, x} | t], acc)\n    else\n      format(w, k, [{i, mode, x} | t], acc)\n    end\n  end\n\n  # Groups must do the fitting decision.\n  defp format(w, k, [:group_over | t], acc) do\n    format(w, k, t, acc)\n  end\n\n  # TODO: Deprecate me in Elixir v1.23\n  defp format(w, k, [{i, :break, doc_group(x, :inherit)} | t], acc) do\n    format(w, k, [{i, :break, x} | t], acc)\n  end\n\n  defp format(w, k, [{i, :flat, doc_group(x, :optimistic)} | t], acc) do\n    if w == :infinity or fits?(w, k, false, [{i, :flat, x} | t]) do\n      format(w, k, [{i, :flat, x}, :group_over | t], acc)\n    else\n      format(w, k, [{i, :break, x}, :group_over | t], acc)\n    end\n  end\n\n  defp format(w, k, [{i, _, doc_group(x, _)} | t], acc) do\n    if w == :infinity or fits?(w, k, false, [{i, :flat, x}]) do\n      format(w, k, [{i, :flat, x}, :group_over | t], acc)\n    else\n      format(w, k, [{i, :break, x}, :group_over | t], acc)\n    end\n  end\n\n  # Limit is set to infinity and then reverts\n  defp format(w, k, [{i, m, doc_limit(x, :infinity)} | t], acc) when w != :infinity do\n    format(:infinity, k, [{i, :flat, x}, {i, m, doc_limit(empty(), w)} | t], acc)\n  end\n\n  defp format(_w, k, [{i, m, doc_limit(x, w)} | t], acc) do\n    format(w, k, [{i, m, x} | t], acc)\n  end\n\n  defp collapse([\"\\n\" <> rest | t], max, count, i) do\n    collapse([strip_whitespace(rest) | t], max, count + 1, i)\n  end\n\n  defp collapse([\"\" | t], max, count, i) do\n    collapse(t, max, count, i)\n  end\n\n  defp collapse(t, max, count, i) do\n    [:binary.copy(\"\\n\", min(max, count)), :binary.copy(\" \", i) | t]\n  end\n\n  defp strip_whitespace(\" \" <> rest), do: strip_whitespace(rest)\n  defp strip_whitespace(rest), do: rest\n\n  defp apply_nesting(_, k, :cursor), do: k\n  defp apply_nesting(_, _, :reset), do: 0\n  defp apply_nesting(i, _, j), do: i + j\n\n  defp indent(0), do: @newline\n  defp indent(i), do: @newline <> :binary.copy(\" \", i)\nend\n"
  },
  {
    "path": "lib/elixir/lib/inspect/error.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Inspect.Error do\n  @moduledoc \"\"\"\n  Raised when a struct cannot be inspected.\n  \"\"\"\n  @enforce_keys [:exception_module, :exception_message, :stacktrace, :inspected_struct]\n  defexception @enforce_keys\n\n  @impl true\n  def exception(arguments) when is_list(arguments) do\n    exception = Keyword.fetch!(arguments, :exception)\n    exception_module = exception.__struct__\n    exception_message = Exception.message(exception) |> String.trim_trailing(\"\\n\")\n    stacktrace = Keyword.fetch!(arguments, :stacktrace)\n    inspected_struct = Keyword.fetch!(arguments, :inspected_struct)\n\n    %Inspect.Error{\n      exception_module: exception_module,\n      exception_message: exception_message,\n      stacktrace: stacktrace,\n      inspected_struct: inspected_struct\n    }\n  end\n\n  @impl true\n  def message(%__MODULE__{\n        exception_module: exception_module,\n        exception_message: exception_message,\n        inspected_struct: inspected_struct\n      }) do\n    ~s'''\n    got #{inspect(exception_module)} with message:\n\n        \"\"\"\n    #{pad(exception_message, 4)}\n        \"\"\"\n\n    while inspecting:\n\n    #{pad(inspected_struct, 4)}\n    '''\n  end\n\n  @doc false\n  def pad(message, padding_length)\n      when is_binary(message) and is_integer(padding_length) and padding_length >= 0 do\n    padding = String.duplicate(\" \", padding_length)\n\n    message\n    |> String.split(\"\\n\")\n    |> Enum.map(fn\n      \"\" -> \"\\n\"\n      line -> [padding, line, ?\\n]\n    end)\n    |> IO.iodata_to_binary()\n    |> String.trim_trailing(\"\\n\")\n  end\nend\n\ndefimpl Inspect, for: Inspect.Error do\n  @impl true\n  def inspect(%{stacktrace: stacktrace} = inspect_error, _opts) do\n    message = Exception.message(inspect_error)\n    format_output(message, stacktrace)\n  end\n\n  defp format_output(message, [_ | _] = stacktrace) do\n    stacktrace = Exception.format_stacktrace(stacktrace)\n\n    \"\"\"\n    #Inspect.Error<\n    #{Inspect.Error.pad(message, 2)}\n\n      Stacktrace:\n\n    #{stacktrace}\n    >\\\n    \"\"\"\n  end\n\n  defp format_output(message, []) do\n    \"\"\"\n    #Inspect.Error<\n      #{Inspect.Error.pad(message, 2)}\n    >\\\n    \"\"\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/inspect.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nimport Kernel, except: [inspect: 1]\nimport Inspect.Algebra\n\nalias Code.Identifier\n\ndefprotocol Inspect do\n  @moduledoc \"\"\"\n  The `Inspect` protocol converts an Elixir data structure into an\n  algebra document.\n\n  This is typically done when you want to customize how your own\n  structs are inspected in logs and the terminal.\n\n  This documentation refers to implementing the `Inspect` protocol\n  for your own data structures. To learn more about using inspect,\n  see `Kernel.inspect/2` and `IO.inspect/2`.\n\n  ## Inspect representation\n\n  There are typically three choices of inspect representation. In order\n  to understand them, let's imagine we have the following `User` struct:\n\n      defmodule User do\n        defstruct [:id, :name, :address]\n      end\n\n  Our choices are:\n\n    1. Print the struct using Elixir's struct syntax, for example:\n       `%User{address: \"Earth\", id: 13, name: \"Jane\"}`. This is the\n       default representation and best choice if all struct fields\n       are public.\n\n    2. Print using the `#User<...>` notation, for example: `#User<id: 13, name: \"Jane\", ...>`.\n       This notation does not emit valid Elixir code and is typically\n       used when the struct has private fields (for example, you may want\n       to hide the field `:address` to redact person identifiable information).\n\n    3. Print the struct using the expression syntax, for example:\n       `User.new(13, \"Jane\", \"Earth\")`. This assumes there is a `User.new/3`\n       function. This option is mostly used as an alternative to option 2\n       for representing custom data structures, such as `MapSet`, `Date.Range`,\n       and others.\n\n  You can implement the Inspect protocol for your own structs while\n  adhering to the conventions above. Option 1 is the default representation\n  and you can quickly achieve option 2 by deriving the `Inspect` protocol.\n  For option 3, you need your custom implementation.\n\n  ## Deriving\n\n  The `Inspect` protocol can be derived to customize the order of fields\n  (the default is alphabetical) and hide certain fields from structs,\n  so they don't show up in logs, inspects and similar. The latter is\n  especially useful for fields containing private information.\n\n  The supported options are:\n\n    * `:only` - only include the given fields when inspecting.\n\n    * `:except` - remove the given fields when inspecting.\n\n    * `:optional` - (since v1.14.0) a list of fields that should not be\n      included when they match their default value. This can be used to\n      simplify the struct representation at the cost of hiding\n      information. Since v1.19.0, the `:all` atom can be passed to\n      mark all fields as optional.\n\n  Whenever `:only` or `:except` are used to restrict fields,\n  the struct will be printed using the `#User<...>` notation,\n  as the struct can no longer be copy and pasted as valid Elixir\n  code. Let's see an example:\n\n      defmodule User do\n        @derive {Inspect, only: [:id, :name]}\n        defstruct [:id, :name, :address]\n      end\n\n      inspect(%User{id: 1, name: \"Jane\", address: \"Earth\"})\n      #=> #User<id: 1, name: \"Jane\", ...>\n\n  If you use only the `:optional` option, the struct will still be\n  printed as a valid struct.\n\n      defmodule Point do\n        @derive {Inspect, optional: [:z]}\n        defstruct [x: 0, y: 0, z: 0]\n      end\n\n      inspect(%Point{x: 1})\n      %Point{x: 1, y: 0}\n\n  ## Custom implementation\n\n  You can also define your custom protocol implementation by\n  defining the `inspect/2` function. The function receives the\n  entity to be inspected followed by the inspecting options,\n  represented by the struct `Inspect.Opts` and it must return\n  an algebra document alongside the updated options (or, optionally,\n  just the algebra document). Building of the algebra document\n  is done with `Inspect.Algebra`.\n\n  Many times, inspecting a structure can be implemented in function\n  of existing entities. For example, here is `MapSet`'s `inspect/2`\n  implementation:\n\n      defimpl Inspect, for: MapSet do\n        import Inspect.Algebra\n\n        def inspect(map_set, opts) do\n          {doc, opts} = to_doc_with_opts(MapSet.to_list(map_set), opts)\n          {concat([\"MapSet.new(\", doc, \")\"]), opts}\n        end\n      end\n\n  First [`to_doc_with_opts/2`](`Inspect.Algebra.to_doc_with_opts/2`) is\n  used to convert another data structure into its algebra document and\n  then [`concat/1`](`Inspect.Algebra.concat/1`) concatenates algebra\n  documents together.\n\n  In the example above it is concatenating the string `\"MapSet.new(\"`,\n  the document returned by `to_doc_with_opts/2`, and the final string `\")\"`.\n  Therefore, the MapSet with the numbers 1, 2, and 3 will be printed as:\n\n      iex> MapSet.new([1, 2, 3], fn x -> x * 2 end)\n      MapSet.new([2, 4, 6])\n\n  In other words, `MapSet`'s inspect representation returns an expression\n  that, when evaluated, builds the `MapSet` itself.\n\n  ### Error handling\n\n  In case there is an error while your structure is being inspected,\n  Elixir will raise an `ArgumentError` error and will automatically fall back\n  to a raw representation for printing the structure. Furthermore, you\n  must be careful when debugging your own Inspect implementation, as calls\n  to `IO.inspect/2` or `dbg/1` may trigger an infinite loop (as in order to\n  inspect/debug the data structure, you must call `inspect` itself).\n\n  Here are some tips:\n\n    * For debugging, use `IO.inspect/2` with the `structs: false` option,\n      which disables custom printing and avoids calling the Inspect\n      implementation recursively\n\n    * To access the underlying error on your custom `Inspect` implementation,\n      you may invoke the protocol directly. For example, we could invoke the\n      `Inspect.MapSet` implementation above as:\n\n          Inspect.MapSet.inspect(MapSet.new(), %Inspect.Opts{})\n\n      Note that, from Elixir v1.19, the inspect protocol was augmented to\n      allow a two-element tuple with the document and the updated options\n      to be returned from the protocol.\n  \"\"\"\n\n  # Handle structs in Any\n  @fallback_to_any true\n\n  @impl true\n  defmacro __deriving__(module, options) do\n    info = Macro.struct_info!(module, __CALLER__)\n    fields = Enum.sort(Enum.map(info, & &1.field) -- [:__exception__, :__struct__])\n\n    only = Keyword.get(options, :only, fields)\n    except = Keyword.get(options, :except, [])\n\n    :ok = validate_option(:only, only, fields, module)\n    :ok = validate_option(:except, except, fields, module)\n\n    optional =\n      case Keyword.get(options, :optional, []) do\n        :all ->\n          fields\n\n        optional ->\n          :ok = validate_option(:optional, optional, fields, module)\n          optional\n      end\n\n    inspect_module =\n      if fields == Enum.sort(only) and except == [] do\n        Inspect.Map\n      else\n        Inspect.Any\n      end\n\n    filtered_fields =\n      fields\n      |> Enum.reject(&(&1 in except))\n      |> Enum.filter(&(&1 in only))\n\n    filtered_guard =\n      quote do\n        var!(field) in unquote(filtered_fields)\n      end\n\n    field_guard =\n      if optional == [] do\n        filtered_guard\n      else\n        optional_map =\n          for field <- optional, into: %{} do\n            default = Enum.find(info, %{}, &(&1.field == field)) |> Map.get(:default, nil)\n            {field, default}\n          end\n\n        quote do\n          unquote(filtered_guard) and\n            not case unquote(Macro.escape(optional_map)) do\n              %{^var!(field) => var!(default)} ->\n                var!(default) == Map.get(var!(struct), var!(field))\n\n              %{} ->\n                false\n            end\n        end\n      end\n\n    quote do\n      defimpl Inspect, for: unquote(module) do\n        def inspect(var!(struct), var!(opts)) do\n          var!(infos) =\n            for %{field: var!(field)} = var!(info) <- unquote(module).__info__(:struct),\n                unquote(field_guard),\n                do: var!(info)\n\n          var!(name) = Macro.inspect_atom(:literal, unquote(module))\n\n          unquote(inspect_module).inspect_as_struct(\n            var!(struct),\n            var!(name),\n            var!(infos),\n            var!(opts)\n          )\n        end\n      end\n    end\n  end\n\n  defp validate_option(option, option_list, fields, module) do\n    if not is_list(option_list) do\n      raise ArgumentError,\n            \"invalid value #{Kernel.inspect(option_list)} in #{Kernel.inspect(option)} \" <>\n              \"when deriving the Inspect protocol for #{Kernel.inspect(module)} \" <>\n              \"(expected a list)\"\n    end\n\n    case option_list -- fields do\n      [] ->\n        :ok\n\n      unknown_fields ->\n        raise ArgumentError,\n              \"unknown fields #{Kernel.inspect(unknown_fields)} in #{Kernel.inspect(option)} \" <>\n                \"when deriving the Inspect protocol for #{Kernel.inspect(module)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts `term` into an algebra document.\n\n  This function shouldn't be invoked directly, unless when implementing\n  a custom `inspect_fun` to be given to `Inspect.Opts`. Everywhere else,\n  `Inspect.Algebra.to_doc/2` should be preferred as it handles structs\n  and exceptions.\n  \"\"\"\n  @spec inspect(t, Inspect.Opts.t()) ::\n          Inspect.Algebra.t() | {Inspect.Algebra.t(), Inspect.Opts.t()}\n  def inspect(term, opts)\nend\n\ndefimpl Inspect, for: Atom do\n  def inspect(atom, opts) do\n    color_doc(Macro.inspect_atom(:literal, atom), color_key(atom), opts)\n  end\n\n  defp color_key(atom) when is_boolean(atom), do: :boolean\n  defp color_key(nil), do: nil\n  defp color_key(_), do: :atom\nend\n\ndefimpl Inspect, for: BitString do\n  def inspect(term, opts) when is_binary(term) do\n    %Inspect.Opts{binaries: bins, base: base, printable_limit: printable_limit} = opts\n\n    if bins == :as_strings or\n         (bins == :infer and String.printable?(term, printable_limit) and base == :decimal) do\n      inspected =\n        case Identifier.escape(term, ?\", printable_limit) do\n          {escaped, \"\"} -> [?\", escaped, ?\"]\n          {escaped, _} -> [?\", escaped, ?\", \" <> ...\"]\n        end\n\n      color_doc(IO.iodata_to_binary(inspected), :string, opts)\n    else\n      inspect_bitstring(term, opts)\n    end\n  end\n\n  def inspect(term, opts) do\n    inspect_bitstring(term, opts)\n  end\n\n  defp inspect_bitstring(\"\", opts) do\n    color_doc(\"<<>>\", :binary, opts)\n  end\n\n  defp inspect_bitstring(bitstring, %{limit: limit} = opts) do\n    left = color_doc(\"<<\", :binary, opts)\n    right = color_doc(\">>\", :binary, opts)\n    inner = each_bit(bitstring, limit, opts)\n    doc = group(concat(concat(left, nest(inner, 2)), right))\n    new_limit = if limit == :infinity, do: limit, else: max(0, limit - byte_size(bitstring))\n    {doc, %{opts | limit: new_limit}}\n  end\n\n  defp each_bit(_, 0, _) do\n    \"...\"\n  end\n\n  defp each_bit(<<>>, _counter, _opts) do\n    Inspect.Algebra.empty()\n  end\n\n  defp each_bit(<<h::8>>, _counter, opts) do\n    Inspect.Integer.inspect(h, opts)\n  end\n\n  defp each_bit(<<h, t::bitstring>>, counter, opts) do\n    flex_glue(\n      concat(Inspect.Integer.inspect(h, opts), \",\"),\n      each_bit(t, decrement(counter), opts)\n    )\n  end\n\n  defp each_bit(bitstring, _counter, opts) do\n    size = bit_size(bitstring)\n    <<h::size(^size)>> = bitstring\n    concat(Inspect.Integer.inspect(h, opts), \"::size(\" <> Integer.to_string(size) <> \")\")\n  end\n\n  @compile {:inline, decrement: 1}\n  defp decrement(:infinity), do: :infinity\n  defp decrement(counter), do: counter - 1\nend\n\ndefimpl Inspect, for: List do\n  def inspect([], opts) do\n    color_doc(\"[]\", :list, opts)\n  end\n\n  # TODO: Remove :char_list and :as_char_lists handling on v2.0\n  def inspect(term, opts) do\n    %Inspect.Opts{\n      charlists: lists,\n      char_lists: lists_deprecated,\n      printable_limit: printable_limit\n    } = opts\n\n    lists =\n      if lists == :infer and lists_deprecated != :infer do\n        case lists_deprecated do\n          :as_char_lists ->\n            IO.warn(\n              \"the :char_lists inspect option and its :as_char_lists \" <>\n                \"value are deprecated, use the :charlists option and its \" <>\n                \":as_charlists value instead\"\n            )\n\n            :as_charlists\n\n          _ ->\n            IO.warn(\"the :char_lists inspect option is deprecated, use :charlists instead\")\n            lists_deprecated\n        end\n      else\n        lists\n      end\n\n    open = color_doc(\"[\", :list, opts)\n    sep = color_doc(\",\", :list, opts)\n    close = color_doc(\"]\", :list, opts)\n\n    cond do\n      lists == :as_charlists or (lists == :infer and List.ascii_printable?(term, printable_limit)) ->\n        inspected =\n          case Identifier.escape(IO.chardata_to_string(term), ?\", printable_limit) do\n            {escaped, \"\"} -> [?~, ?c, ?\", escaped, ?\"]\n            {escaped, _} -> [?~, ?c, ?\", escaped, ?\", \" ++ ...\"]\n          end\n\n        color_doc(IO.iodata_to_binary(inspected), :charlist, opts)\n\n      keyword?(term) ->\n        container_doc_with_opts(open, term, close, opts, &keyword/2,\n          separator: sep,\n          break: :strict\n        )\n\n      true ->\n        container_doc_with_opts(open, term, close, opts, &to_doc_with_opts/2, separator: sep)\n    end\n  end\n\n  @doc false\n  def keyword({key, value}, opts) do\n    key = color_doc(Macro.inspect_atom(:key, key), :atom, opts)\n    {doc, opts} = to_doc_with_opts(value, opts)\n    {concat(key, concat(\" \", doc)), opts}\n  end\n\n  @doc false\n  def keyword?([{key, _value} | rest]) when is_atom(key) do\n    case Atom.to_charlist(key) do\n      [?E, ?l, ?i, ?x, ?i, ?r, ?.] ++ _ -> false\n      _ -> keyword?(rest)\n    end\n  end\n\n  def keyword?([]), do: true\n  def keyword?(_other), do: false\nend\n\ndefimpl Inspect, for: Tuple do\n  def inspect(tuple, opts) do\n    open = color_doc(\"{\", :tuple, opts)\n    sep = color_doc(\",\", :tuple, opts)\n    close = color_doc(\"}\", :tuple, opts)\n    container_opts = [separator: sep, break: :flex]\n\n    container_doc_with_opts(\n      open,\n      Tuple.to_list(tuple),\n      close,\n      opts,\n      &to_doc_with_opts/2,\n      container_opts\n    )\n  end\nend\n\ndefimpl Inspect, for: Map do\n  def inspect(map, opts) do\n    inspect_as_map(map, opts)\n  end\n\n  def inspect_as_map(map, opts) do\n    list =\n      if Keyword.get(opts.custom_options, :sort_maps) do\n        map |> Map.to_list() |> :lists.sort()\n      else\n        Map.to_list(map)\n      end\n\n    fun =\n      if Inspect.List.keyword?(list) do\n        &Inspect.List.keyword/2\n      else\n        sep = color_doc(\" => \", :map, opts)\n        &to_assoc(&1, &2, sep)\n      end\n\n    map_container_doc(list, \"\", opts, fun)\n  end\n\n  def inspect_as_struct(map, name, infos, opts) do\n    fun = fn %{field: field}, opts -> Inspect.List.keyword({field, Map.get(map, field)}, opts) end\n    map_container_doc(infos, name, opts, fun)\n  end\n\n  defp to_assoc({key, value}, opts, sep) do\n    {key_doc, opts} = to_doc_with_opts(key, opts)\n    {value_doc, opts} = to_doc_with_opts(value, opts)\n    {concat(concat(key_doc, sep), value_doc), opts}\n  end\n\n  defp map_container_doc(list, name, opts, fun) do\n    open = color_doc(\"%\" <> name <> \"{\", :map, opts)\n    sep = color_doc(\",\", :map, opts)\n    close = color_doc(\"}\", :map, opts)\n    container_doc_with_opts(open, list, close, opts, fun, separator: sep, break: :strict)\n  end\nend\n\ndefimpl Inspect, for: Integer do\n  def inspect(term, %Inspect.Opts{base: base} = opts) do\n    inspected = Integer.to_string(term, base_to_value(base)) |> prepend_prefix(base)\n    color_doc(inspected, :number, opts)\n  end\n\n  defp base_to_value(base) do\n    case base do\n      :binary -> 2\n      :decimal -> 10\n      :octal -> 8\n      :hex -> 16\n    end\n  end\n\n  defp prepend_prefix(value, :decimal), do: value\n\n  defp prepend_prefix(<<?-, value::binary>>, base) do\n    \"-\" <> prepend_prefix(value, base)\n  end\n\n  defp prepend_prefix(value, base) do\n    prefix =\n      case base do\n        :binary -> \"0b\"\n        :octal -> \"0o\"\n        :hex -> \"0x\"\n      end\n\n    prefix <> value\n  end\nend\n\ndefimpl Inspect, for: Float do\n  def inspect(float, opts) do\n    abs = abs(float)\n\n    formatted =\n      if abs >= 1.0 and abs < 1.0e16 and trunc(float) == float do\n        [Integer.to_string(trunc(float)), ?., ?0]\n      else\n        Float.to_charlist(float)\n      end\n\n    color_doc(IO.iodata_to_binary(formatted), :number, opts)\n  end\nend\n\ndefimpl Inspect, for: Regex do\n  def inspect(regex = %{opts: regex_opts}, opts) when is_list(regex_opts) do\n    case translate_options(regex_opts, []) do\n      :error ->\n        concat([\n          \"Regex.compile!(\",\n          to_doc(regex.source, opts),\n          \", \",\n          to_doc(regex_opts, opts),\n          \")\"\n        ])\n\n      translated_opts ->\n        {escaped, _} =\n          regex.source\n          |> normalize(<<>>)\n          |> Identifier.escape(?/, :infinity, &escape_map/1)\n\n        source = IO.iodata_to_binary([?~, ?r, ?/, escaped, ?/, translated_opts])\n        color_doc(source, :regex, opts)\n    end\n  end\n\n  defp translate_options([:dotall, {:newline, :anycrlf} | t], acc),\n    do: translate_options(t, [?s | acc])\n\n  defp translate_options([:unicode, :ucp | t], acc), do: translate_options(t, [?u | acc])\n  defp translate_options([:caseless | t], acc), do: translate_options(t, [?i | acc])\n  defp translate_options([:extended | t], acc), do: translate_options(t, [?x | acc])\n  defp translate_options([:firstline | t], acc), do: translate_options(t, [?f | acc])\n  defp translate_options([:ungreedy | t], acc), do: translate_options(t, [?U | acc])\n  defp translate_options([:multiline | t], acc), do: translate_options(t, [?m | acc])\n  defp translate_options([:export | t], acc), do: translate_options(t, [?E | acc])\n  defp translate_options([], acc), do: acc\n  defp translate_options(_t, _acc), do: :error\n\n  defp normalize(<<?\\\\, ?\\\\, rest::binary>>, acc), do: normalize(rest, <<acc::binary, ?\\\\, ?\\\\>>)\n  defp normalize(<<?\\\\, ?/, rest::binary>>, acc), do: normalize(rest, <<acc::binary, ?/>>)\n  defp normalize(<<?\\\\, ?#, ?{, rest::binary>>, acc), do: normalize(rest, <<acc::binary, ?#, ?{>>)\n  defp normalize(<<char, rest::binary>>, acc), do: normalize(rest, <<acc::binary, char>>)\n  defp normalize(<<>>, acc), do: acc\n\n  defp escape_map(?\\a), do: [?\\\\, ?a]\n  defp escape_map(?\\f), do: [?\\\\, ?f]\n  defp escape_map(?\\n), do: [?\\\\, ?n]\n  defp escape_map(?\\r), do: [?\\\\, ?r]\n  defp escape_map(?\\t), do: [?\\\\, ?t]\n  defp escape_map(?\\v), do: [?\\\\, ?v]\n  defp escape_map(_), do: false\nend\n\ndefimpl Inspect, for: Function do\n  @elixir_compiler :binary.bin_to_list(\"elixir_compiler_\")\n\n  def inspect(function, _opts) do\n    fun_info = Function.info(function)\n    mod = fun_info[:module]\n    name = fun_info[:name]\n\n    cond do\n      not is_atom(mod) ->\n        \"#Function<#{uniq(fun_info)}/#{fun_info[:arity]}>\"\n\n      fun_info[:type] == :external and fun_info[:env] == [] ->\n        inspected_as_atom = Macro.inspect_atom(:literal, mod)\n        inspected_as_function = Macro.inspect_atom(:remote_call, name)\n        \"&#{inspected_as_atom}.#{inspected_as_function}/#{fun_info[:arity]}\"\n\n      match?(@elixir_compiler ++ _, Atom.to_charlist(mod)) ->\n        if function_exported?(mod, :__RELATIVE__, 0) do\n          \"#Function<#{uniq(fun_info)} in file:#{mod.__RELATIVE__()}>\"\n        else\n          default_inspect(mod, fun_info)\n        end\n\n      true ->\n        default_inspect(mod, fun_info)\n    end\n  end\n\n  defp default_inspect(mod, fun_info) do\n    inspected_as_atom = Macro.inspect_atom(:literal, mod)\n    extracted_name = extract_name(fun_info[:name])\n    \"#Function<#{uniq(fun_info)}/#{fun_info[:arity]} in #{inspected_as_atom}#{extracted_name}>\"\n  end\n\n  defp extract_name([]) do\n    \"\"\n  end\n\n  defp extract_name(name) do\n    case Identifier.extract_anonymous_fun_parent(name) do\n      {name, arity} ->\n        \".\" <> Macro.inspect_atom(:remote_call, name) <> \"/\" <> arity\n\n      :error ->\n        \".\" <> Macro.inspect_atom(:remote_call, name)\n    end\n  end\n\n  defp uniq(fun_info) do\n    Integer.to_string(fun_info[:new_index]) <> \".\" <> Integer.to_string(fun_info[:uniq])\n  end\nend\n\ndefimpl Inspect, for: PID do\n  def inspect(pid, _opts) do\n    \"#PID\" <> IO.iodata_to_binary(:erlang.pid_to_list(pid))\n  end\nend\n\ndefimpl Inspect, for: Port do\n  def inspect(port, _opts) do\n    IO.iodata_to_binary(:erlang.port_to_list(port))\n  end\nend\n\ndefimpl Inspect, for: Reference do\n  def inspect(ref, _opts) do\n    [?#, ?R, ?e, ?f] ++ rest = :erlang.ref_to_list(ref)\n    \"#Reference\" <> IO.iodata_to_binary(rest)\n  end\nend\n\ndefimpl Inspect, for: Any do\n  def inspect(%module{} = struct, opts) do\n    info =\n      for %{field: field} = map <- module.__info__(:struct),\n          field != :__exception__,\n          do: map\n\n    Inspect.Map.inspect_as_struct(struct, Macro.inspect_atom(:literal, module), info, opts)\n  end\n\n  def inspect_as_struct(map, name, infos, opts) do\n    open = color_doc(\"#\" <> name <> \"<\", :map, opts)\n    sep = color_doc(\",\", :map, opts)\n    close = color_doc(\">\", :map, opts)\n\n    fun = fn\n      %{field: field}, opts -> Inspect.List.keyword({field, Map.get(map, field)}, opts)\n      :..., _opts -> \"...\"\n    end\n\n    container_doc(open, infos ++ [:...], close, opts, fun, separator: sep, break: :strict)\n  end\nend\n\ndefimpl Inspect, for: Range do\n  import Inspect.Algebra\n  import Kernel, except: [inspect: 2]\n\n  def inspect(first..last//1, opts) when last >= first do\n    concat([to_doc(first, opts), \"..\", to_doc(last, opts)])\n  end\n\n  def inspect(first..last//step, opts) do\n    concat([to_doc(first, opts), \"..\", to_doc(last, opts), \"//\", to_doc(step, opts)])\n  end\n\n  # TODO: Remove me on v2.0\n  inspect =\n    quote generated: true do\n      inspect(\n        %{__struct__: Range, first: var!(first), last: var!(last)} = var!(range),\n        var!(opts)\n      )\n    end\n\n  def unquote(inspect) do\n    step = if first <= last, do: 1, else: -1\n    inspect(Map.put(range, :step, step), opts)\n  end\nend\n\nrequire Protocol\n\nProtocol.derive(\n  Inspect,\n  Macro.Env,\n  only: [\n    :module,\n    :file,\n    :line,\n    :function,\n    :context,\n    :aliases,\n    :requires,\n    :functions,\n    :macros,\n    :macro_aliases,\n    :context_modules,\n    :lexical_tracker\n  ]\n)\n"
  },
  {
    "path": "lib/elixir/lib/integer.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Integer do\n  @moduledoc \"\"\"\n  Functions for working with integers.\n\n  Some functions that work on integers are found in `Kernel`:\n\n    * `Kernel.abs/1`\n    * `Kernel.div/2`\n    * `Kernel.max/2`\n    * `Kernel.min/2`\n    * `Kernel.rem/2`\n\n  \"\"\"\n\n  import Bitwise\n\n  @doc \"\"\"\n  Counts the number of set bits (1) in the binary representation of a non-negative `integer`.\n\n  This operation is known as the Hamming weight or population count.\n\n  Raises an `ArithmeticError` if `integer` is negative.\n\n  ## Examples\n\n      iex> Integer.popcount(0)\n      0\n\n      iex> Integer.popcount(1)\n      1\n\n      iex> Integer.popcount(0b10110101)\n      5\n\n      iex> Integer.popcount(255)\n      8\n\n      iex> Integer.popcount(0b1111111111111111)\n      16\n\n      iex> Integer.popcount(-1)\n      ** (ArithmeticError) bad argument in arithmetic expression\n\n  \"\"\"\n  @doc since: \"1.20.0\"\n  @spec popcount(non_neg_integer) :: non_neg_integer\n  def popcount(integer) when is_integer(integer) and integer < 0,\n    do: :erlang.error(:badarith, [integer])\n\n  def popcount(integer) when is_integer(integer),\n    do: popcount(integer, 0)\n\n  defp popcount(0, acc), do: acc\n  defp popcount(n, acc), do: popcount(n &&& n - 1, acc + 1)\n\n  @doc \"\"\"\n  Determines if `integer` is odd.\n\n  Returns `true` if the given `integer` is an odd number,\n  otherwise it returns `false`.\n\n  Allowed in guard clauses.\n\n  ## Examples\n\n      iex> Integer.is_odd(5)\n      true\n\n      iex> Integer.is_odd(6)\n      false\n\n      iex> Integer.is_odd(-5)\n      true\n\n      iex> Integer.is_odd(0)\n      false\n\n  \"\"\"\n  defguard is_odd(integer) when is_integer(integer) and (integer &&& 1) == 1\n\n  @doc \"\"\"\n  Determines if an `integer` is even.\n\n  Returns `true` if the given `integer` is an even number,\n  otherwise it returns `false`.\n\n  Allowed in guard clauses.\n\n  ## Examples\n\n      iex> Integer.is_even(10)\n      true\n\n      iex> Integer.is_even(5)\n      false\n\n      iex> Integer.is_even(-10)\n      true\n\n      iex> Integer.is_even(0)\n      true\n\n  \"\"\"\n  defguard is_even(integer) when is_integer(integer) and (integer &&& 1) == 0\n\n  @doc \"\"\"\n  Computes `base` raised to power of `exponent`.\n\n  Both `base` and `exponent` must be integers.\n  The exponent must be zero or positive.\n\n  See `Float.pow/2` for exponentiation of negative\n  exponents as well as floats.\n\n  ## Examples\n\n      iex> Integer.pow(2, 0)\n      1\n      iex> Integer.pow(2, 1)\n      2\n      iex> Integer.pow(2, 10)\n      1024\n      iex> Integer.pow(2, 11)\n      2048\n      iex> Integer.pow(2, 64)\n      0x10000000000000000\n\n      iex> Integer.pow(3, 4)\n      81\n      iex> Integer.pow(4, 3)\n      64\n\n      iex> Integer.pow(-2, 3)\n      -8\n      iex> Integer.pow(-2, 4)\n      16\n\n      iex> Integer.pow(2, -2)\n      ** (ArithmeticError) bad argument in arithmetic expression\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec pow(integer, non_neg_integer) :: integer\n  def pow(base, exponent) when is_integer(base) and is_integer(exponent) do\n    if exponent < 0, do: :erlang.error(:badarith, [base, exponent])\n    base ** exponent\n  end\n\n  @doc \"\"\"\n  Computes the modulo remainder of an integer division.\n\n  This function performs a [floored division](`floor_div/2`), which means that\n  the result will always have the sign of the `divisor`.\n\n  Raises an `ArithmeticError` exception if one of the arguments is not an\n  integer, or when the `divisor` is `0`.\n\n  ## Examples\n\n      iex> Integer.mod(5, 2)\n      1\n      iex> Integer.mod(6, -4)\n      -2\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec mod(integer, neg_integer | pos_integer) :: integer\n  def mod(dividend, divisor) do\n    remainder = rem(dividend, divisor)\n\n    if remainder * divisor < 0 do\n      remainder + divisor\n    else\n      remainder\n    end\n  end\n\n  @doc \"\"\"\n  Performs a floored integer division.\n\n  Raises an `ArithmeticError` exception if one of the arguments is not an\n  integer, or when the `divisor` is `0`.\n\n  This function performs a *floored* integer division, which means that\n  the result will always be rounded towards negative infinity.\n\n  If you want to perform truncated integer division (rounding towards zero),\n  use `Kernel.div/2` instead.\n\n  ## Examples\n\n      iex> Integer.floor_div(5, 2)\n      2\n      iex> Integer.floor_div(6, -4)\n      -2\n      iex> Integer.floor_div(-99, 2)\n      -50\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec floor_div(integer, neg_integer | pos_integer) :: integer\n  def floor_div(dividend, divisor) do\n    if :erlang.xor(dividend < 0, divisor < 0) and rem(dividend, divisor) != 0 do\n      div(dividend, divisor) - 1\n    else\n      div(dividend, divisor)\n    end\n  end\n\n  @doc \"\"\"\n  Performs a ceiled integer division.\n\n  Raises an `ArithmeticError` exception if one of the arguments is not an\n  integer, or when the `divisor` is `0`.\n\n  This function performs a *ceiled* integer division, which means that\n  the result will always be rounded towards positive infinity.\n\n  ## Examples\n\n      iex> Integer.ceil_div(5, 2)\n      3\n      iex> Integer.ceil_div(6, -4)\n      -1\n      iex> Integer.ceil_div(-99, 2)\n      -49\n\n  \"\"\"\n  @doc since: \"1.20.0\"\n  @spec ceil_div(integer, neg_integer | pos_integer) :: integer\n  def ceil_div(dividend, divisor) do\n    if not :erlang.xor(dividend < 0, divisor < 0) and rem(dividend, divisor) != 0 do\n      div(dividend, divisor) + 1\n    else\n      div(dividend, divisor)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the ordered digits for the given `integer`.\n\n  An optional `base` value may be provided representing the radix for the returned\n  digits. This one must be an integer >= 2.\n\n  ## Examples\n\n      iex> Integer.digits(123)\n      [1, 2, 3]\n\n      iex> Integer.digits(170, 2)\n      [1, 0, 1, 0, 1, 0, 1, 0]\n\n      iex> Integer.digits(-170, 2)\n      [-1, 0, -1, 0, -1, 0, -1, 0]\n\n  \"\"\"\n  @spec digits(integer, pos_integer) :: [integer, ...]\n  def digits(integer, base \\\\ 10)\n      when is_integer(integer) and is_integer(base) and base >= 2 do\n    case integer do\n      0 -> [0]\n      _integer -> digits(integer, base, [])\n    end\n  end\n\n  defp digits(0, _base, acc), do: acc\n\n  defp digits(integer, base, acc),\n    do: digits(div(integer, base), base, [rem(integer, base) | acc])\n\n  @doc \"\"\"\n  Returns the integer represented by the ordered `digits`.\n\n  An optional `base` value may be provided representing the radix for the `digits`.\n  Base has to be an integer greater than or equal to `2`.\n\n  ## Examples\n\n      iex> Integer.undigits([1, 2, 3])\n      123\n\n      iex> Integer.undigits([1, 4], 16)\n      20\n\n      iex> Integer.undigits([])\n      0\n\n  \"\"\"\n  @spec undigits([integer], pos_integer) :: integer\n  def undigits(digits, base \\\\ 10) when is_list(digits) and is_integer(base) and base >= 2 do\n    undigits(digits, base, 0)\n  end\n\n  defp undigits([], _base, acc), do: acc\n\n  defp undigits([digit | _], base, _)\n       when is_integer(digit) and (digit >= base or digit <= -base),\n       do: raise(ArgumentError, \"invalid digit #{digit} in base #{base}\")\n\n  defp undigits([digit | tail], base, acc) when is_integer(digit),\n    do: undigits(tail, base, acc * base + digit)\n\n  @doc \"\"\"\n  Parses a text representation of an integer.\n\n  An optional `base` to the corresponding integer can be provided.\n  If `base` is not given, 10 will be used.\n\n  If successful, returns a tuple in the form of `{integer, remaining_string}`.\n  Otherwise `:error`.\n\n  Raises an error if `base` is less than 2 or more than 36.\n\n  If you want to convert a string-formatted integer directly to an integer,\n  `String.to_integer/1` or `String.to_integer/2` can be used instead.\n\n  ## Examples\n\n      iex> Integer.parse(\"34\")\n      {34, \"\"}\n\n      iex> Integer.parse(\"34.5\")\n      {34, \".5\"}\n\n      iex> Integer.parse(\"three\")\n      :error\n\n      iex> Integer.parse(\"404 not found\")\n      {404, \" not found\"}\n\n      iex> Integer.parse(\"34\", 10)\n      {34, \"\"}\n\n      iex> Integer.parse(\"f4\", 16)\n      {244, \"\"}\n\n      iex> Integer.parse(\"Awww++\", 36)\n      {509216, \"++\"}\n\n      iex> Integer.parse(\"fab\", 10)\n      :error\n\n      iex> Integer.parse(\"a2\", 38)\n      ** (ArgumentError) invalid base 38\n\n  \"\"\"\n  @spec parse(binary, 2..36) :: {integer, remainder_of_binary :: binary} | :error\n  def parse(binary, base \\\\ 10)\n\n  def parse(_binary, base) when base not in 2..36 do\n    raise ArgumentError, \"invalid base #{inspect(base)}\"\n  end\n\n  def parse(binary, base) when is_binary(binary) do\n    case count_digits(binary, base) do\n      0 ->\n        :error\n\n      count ->\n        {digits, rem} = :erlang.split_binary(binary, count)\n        {:erlang.binary_to_integer(digits, base), rem}\n    end\n  end\n\n  defp count_digits(<<sign, rest::bits>>, base) when sign in ~c\"+-\" do\n    case count_digits_nosign(rest, base, 1) do\n      1 -> 0\n      count -> count\n    end\n  end\n\n  defp count_digits(<<rest::bits>>, base) do\n    count_digits_nosign(rest, base, 0)\n  end\n\n  digits = [{?0..?9, -?0}, {?A..?Z, 10 - ?A}, {?a..?z, 10 - ?a}]\n\n  for {chars, diff} <- digits,\n      char <- chars do\n    digit = char + diff\n\n    defp count_digits_nosign(<<unquote(char), rest::bits>>, base, count)\n         when base > unquote(digit) do\n      count_digits_nosign(rest, base, count + 1)\n    end\n  end\n\n  defp count_digits_nosign(<<_::bits>>, _, count), do: count\n\n  @doc \"\"\"\n  Returns a binary which corresponds to the text representation\n  of `integer` in the given `base`.\n\n  `base` can be an integer between 2 and 36. If no `base` is given,\n  it defaults to `10`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Integer.to_string(123)\n      \"123\"\n\n      iex> Integer.to_string(+456)\n      \"456\"\n\n      iex> Integer.to_string(-789)\n      \"-789\"\n\n      iex> Integer.to_string(0123)\n      \"123\"\n\n      iex> Integer.to_string(100, 16)\n      \"64\"\n\n      iex> Integer.to_string(-100, 16)\n      \"-64\"\n\n      iex> Integer.to_string(882_681_651, 36)\n      \"ELIXIR\"\n\n  \"\"\"\n  @spec to_string(integer, 2..36) :: String.t()\n  def to_string(integer, base \\\\ 10) do\n    :erlang.integer_to_binary(integer, base)\n  end\n\n  @doc \"\"\"\n  Returns a charlist which corresponds to the text representation\n  of `integer` in the given `base`.\n\n  `base` can be an integer between 2 and 36. If no `base` is given,\n  it defaults to `10`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Integer.to_charlist(123)\n      ~c\"123\"\n\n      iex> Integer.to_charlist(+456)\n      ~c\"456\"\n\n      iex> Integer.to_charlist(-789)\n      ~c\"-789\"\n\n      iex> Integer.to_charlist(0123)\n      ~c\"123\"\n\n      iex> Integer.to_charlist(100, 16)\n      ~c\"64\"\n\n      iex> Integer.to_charlist(-100, 16)\n      ~c\"-64\"\n\n      iex> Integer.to_charlist(882_681_651, 36)\n      ~c\"ELIXIR\"\n\n  \"\"\"\n  @spec to_charlist(integer, 2..36) :: charlist\n  def to_charlist(integer, base \\\\ 10) do\n    :erlang.integer_to_list(integer, base)\n  end\n\n  @doc \"\"\"\n  Returns the greatest common divisor of the two given integers.\n\n  The greatest common divisor (GCD) of `integer1` and `integer2` is the largest positive\n  integer that divides both `integer1` and `integer2` without leaving a remainder.\n\n  By convention, `gcd(0, 0)` returns `0`.\n\n  ## Examples\n\n      iex> Integer.gcd(2, 3)\n      1\n\n      iex> Integer.gcd(8, 12)\n      4\n\n      iex> Integer.gcd(8, -12)\n      4\n\n      iex> Integer.gcd(10, 0)\n      10\n\n      iex> Integer.gcd(7, 7)\n      7\n\n      iex> Integer.gcd(0, 0)\n      0\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec gcd(integer, integer) :: non_neg_integer\n  def gcd(integer1, integer2) when is_integer(integer1) and is_integer(integer2) do\n    gcd_positive(abs(integer1), abs(integer2))\n  end\n\n  defp gcd_positive(0, integer2), do: integer2\n  defp gcd_positive(integer1, 0), do: integer1\n  defp gcd_positive(integer1, integer2), do: gcd_positive(integer2, rem(integer1, integer2))\n\n  @doc \"\"\"\n  Returns the extended greatest common divisor of the two given integers.\n\n  This function uses the extended Euclidean algorithm to return a three-element tuple with the `gcd`\n  and the coefficients `m` and `n` of Bézout's identity such that:\n\n      gcd(a, b) = m*a + n*b\n\n  By convention, `extended_gcd(0, 0)` returns `{0, 0, 0}`.\n\n  ## Examples\n\n      iex> Integer.extended_gcd(240, 46)\n      {2, -9, 47}\n      iex> Integer.extended_gcd(46, 240)\n      {2, 47, -9}\n      iex> Integer.extended_gcd(-46, 240)\n      {2, -47, -9}\n      iex> Integer.extended_gcd(-46, -240)\n      {2, -47, 9}\n\n      iex> Integer.extended_gcd(14, 21)\n      {7, -1, 1}\n\n      iex> Integer.extended_gcd(10, 0)\n      {10, 1, 0}\n      iex> Integer.extended_gcd(-10, 0)\n      {10, -1, 0}\n      iex> Integer.extended_gcd(0, 10)\n      {10, 0, 1}\n      iex> Integer.extended_gcd(0, -10)\n      {10, 0, -1}\n      iex> Integer.extended_gcd(0, 0)\n      {0, 0, 0}\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec extended_gcd(integer, integer) :: {non_neg_integer, integer, integer}\n  def extended_gcd(0, 0), do: {0, 0, 0}\n  def extended_gcd(0, b) when b > 0, do: {b, 0, 1}\n  def extended_gcd(0, b) when b < 0, do: {-b, 0, -1}\n  def extended_gcd(a, 0) when a > 0, do: {a, 1, 0}\n  def extended_gcd(a, 0) when a < 0, do: {-a, -1, 0}\n\n  def extended_gcd(integer1, integer2) when is_integer(integer1) and is_integer(integer2) do\n    extended_gcd(integer2, integer1, 0, 1, 1, 0)\n  end\n\n  defp extended_gcd(r1, r0, s1, s0, t1, t0) do\n    div = div(r0, r1)\n\n    case r0 - div * r1 do\n      0 when r1 > 0 -> {r1, s1, t1}\n      0 when r1 < 0 -> {-r1, -s1, -t1}\n      r2 -> extended_gcd(r2, r1, s0 - div * s1, s1, t0 - div * t1, t1)\n    end\n  end\n\n  @doc false\n  @deprecated \"Use Integer.to_charlist/1 instead\"\n  def to_char_list(integer), do: Integer.to_charlist(integer)\n\n  @doc false\n  @deprecated \"Use Integer.to_charlist/2 instead\"\n  def to_char_list(integer, base), do: Integer.to_charlist(integer, base)\nend\n"
  },
  {
    "path": "lib/elixir/lib/io/ansi/docs.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IO.ANSI.Docs do\n  @moduledoc false\n\n  @type print_opts :: [\n          enabled: boolean(),\n          doc_bold: [IO.ANSI.ansicode()],\n          doc_code: [IO.ANSI.ansicode()],\n          doc_headings: [IO.ANSI.ansicode()],\n          doc_metadata: [IO.ANSI.ansicode()],\n          doc_quote: [IO.ANSI.ansicode()],\n          doc_inline_code: [IO.ANSI.ansicode()],\n          doc_table_heading: [IO.ANSI.ansicode()],\n          doc_title: [IO.ANSI.ansicode()],\n          doc_underline: [IO.ANSI.ansicode()],\n          width: pos_integer()\n        ]\n\n  @bullet_text_unicode \"• \"\n  @bullet_text_ascii \"* \"\n  @bullets [?*, ?-, ?+]\n  @spaces [\" \", \"\\n\", \"\\t\"]\n\n  @doc \"\"\"\n  The default options used by this module.\n\n  The supported keys are:\n\n    * `:enabled`           - toggles coloring on and off (true)\n    * `:doc_bold`          - bold text (bright)\n    * `:doc_code`          - code blocks (cyan)\n    * `:doc_headings`      - h1, h2, h3, h4, h5, h6 headings (yellow)\n    * `:doc_metadata`      - documentation metadata keys (yellow)\n    * `:doc_quote`         - leading quote character `> ` (light black)\n    * `:doc_inline_code`   - inline code (cyan)\n    * `:doc_table_heading` - the style for table headings\n    * `:doc_title`         - top level heading (reverse, yellow)\n    * `:doc_underline`     - underlined text (underline)\n    * `:width`             - the width to format the text (80)\n\n  Values for the color settings are strings with\n  comma-separated ANSI values.\n  \"\"\"\n  @spec default_options() :: print_opts\n  def default_options do\n    [\n      enabled: true,\n      doc_bold: [:bright],\n      doc_code: [:cyan],\n      doc_headings: [:yellow],\n      doc_metadata: [:yellow],\n      doc_quote: [:light_black],\n      doc_inline_code: [:cyan],\n      doc_table_heading: [:reverse],\n      doc_title: [:reverse, :yellow],\n      doc_underline: [:underline],\n      width: 80\n    ]\n  end\n\n  @doc \"\"\"\n  Prints the head of the documentation (i.e. the function signature).\n\n  See `default_options/0` for docs on the supported options.\n  \"\"\"\n  @spec print_headings([String.t()], print_opts) :: :ok\n  def print_headings(headings, options \\\\ []) do\n    # It's possible for some of the headings to contain newline characters (`\\n`), so in order to prevent it from\n    # breaking the output from `print_headings/2`, as `print_headings/2` tries to pad the whole heading, we first split\n    # any heading containgin newline characters into multiple headings, that way each one is padded on its own.\n    headings = Enum.flat_map(headings, fn heading -> String.split(heading, \"\\n\") end)\n    options = Keyword.merge(default_options(), options)\n    newline_after_block(options)\n    width = options[:width]\n\n    for heading <- headings do\n      padding = div(width + String.length(heading), 2)\n      heading = String.pad_leading(heading, padding)\n      heading = if options[:enabled], do: String.pad_trailing(heading, width), else: heading\n      write(:doc_title, heading, options)\n    end\n\n    newline_after_block(options)\n  end\n\n  @doc \"\"\"\n  Prints documentation metadata (only `delegate_to`, `deprecated`, `guard`, and `since` for now).\n\n  See `default_options/0` for docs on the supported options.\n  \"\"\"\n  @spec print_metadata(map, print_opts) :: :ok\n  def print_metadata(metadata, options \\\\ []) when is_map(metadata) do\n    options = Keyword.merge(default_options(), options)\n    print_each_metadata(metadata, options) && IO.write(\"\\n\")\n  end\n\n  @metadata_filter [:deprecated, :guard, :since]\n\n  defp print_each_metadata(metadata, options) do\n    metadata\n    |> Enum.sort()\n    |> Enum.reduce(false, fn\n      {key, value}, _printed when is_binary(value) and key in @metadata_filter ->\n        label = metadata_label(key, options)\n        indent = String.duplicate(\" \", length_without_escape(label, 0) + 1)\n        write_with_wrap([label | String.split(value, @spaces)], options[:width], indent, true, \"\")\n\n      {key, value}, _printed when is_boolean(value) and key in @metadata_filter ->\n        IO.puts([metadata_label(key, options), ?\\s, to_string(value)])\n\n      {:delegate_to, {m, f, a}}, _printed ->\n        label = metadata_label(:delegate_to, options)\n        IO.puts([label, ?\\s, Exception.format_mfa(m, f, a)])\n\n      _metadata, printed ->\n        printed\n    end)\n  end\n\n  defp metadata_label(key, options) do\n    \"#{color(:doc_metadata, options)}#{key}:#{maybe_reset(options)}\"\n  end\n\n  @doc \"\"\"\n  Prints the documentation body `doc` according to `format`.\n\n  It takes a set of `options` defined in `default_options/0`.\n  \"\"\"\n  @spec print(term(), String.t(), print_opts) :: :ok\n  def print(doc, format, options \\\\ [])\n\n  def print(doc, \"text/markdown\", options) when is_binary(doc) and is_list(options) do\n    print_markdown(doc, options)\n  end\n\n  def print(_doc, format, options) when is_binary(format) and is_list(options) do\n    IO.puts(\"\\nUnknown documentation format #{inspect(format)}\\n\")\n  end\n\n  ## Markdown\n\n  def print_markdown(doc, options) do\n    options = Keyword.merge(default_options(), options)\n\n    doc\n    |> String.split([\"\\r\\n\", \"\\n\"], trim: false)\n    |> Enum.map(&String.trim_trailing/1)\n    |> process([], \"\", options)\n  end\n\n  defp process([], text, indent, options) do\n    write_text(text, indent, options)\n  end\n\n  defp process([\"# \" <> _ = heading | rest], text, indent, options) do\n    write_heading(heading, rest, text, indent, options)\n  end\n\n  defp process([\"## \" <> _ = heading | rest], text, indent, options) do\n    write_heading(heading, rest, text, indent, options)\n  end\n\n  defp process([\"### \" <> _ = heading | rest], text, indent, options) do\n    write_heading(heading, rest, text, indent, options)\n  end\n\n  defp process([\"#### \" <> _ = heading | rest], text, indent, options) do\n    write_heading(heading, rest, text, indent, options)\n  end\n\n  defp process([\"##### \" <> _ = heading | rest], text, indent, options) do\n    write_heading(heading, rest, text, indent, options)\n  end\n\n  defp process([\"###### \" <> _ = heading | rest], text, indent, options) do\n    write_heading(heading, rest, text, indent, options)\n  end\n\n  defp process([\">\" <> line | rest], text, indent, options) do\n    write_text(text, indent, options)\n    process_quote(rest, [line], indent, options)\n  end\n\n  defp process([\"\" | rest], text, indent, options) do\n    write_text(text, indent, options)\n    process(rest, [], indent, options)\n  end\n\n  defp process([\"    \" <> line | rest], text, indent, options) do\n    write_text(text, indent, options)\n    process_code(rest, [line], indent, options)\n  end\n\n  defp process([\"```mermaid\" <> _line | rest], text, indent, options) do\n    write_text(text, indent, options)\n\n    rest\n    |> Enum.drop_while(&(&1 != \"```\"))\n    |> Enum.drop(1)\n    |> process([], indent, options)\n  end\n\n  defp process([\"```\" <> _line | rest], text, indent, options) do\n    process_fenced_code_block(rest, text, indent, options, _delimiter = \"```\")\n  end\n\n  defp process([\"<!--\" <> line | rest], text, indent, options) do\n    process(drop_comment([line | rest]), text, indent, options)\n  end\n\n  defp process(all = [line | rest], text, indent, options) do\n    {stripped, count} = strip_spaces(line, 0, :infinity)\n\n    cond do\n      link_label?(stripped, count) ->\n        write_text([line], indent, options, true)\n        process(rest, text, indent, options)\n\n      table_line?(stripped) and rest != [] and table_line?(hd(rest)) ->\n        write_text(text, indent, options)\n        process_table(all, indent, options)\n\n      true ->\n        process_rest(stripped, rest, count, text, indent, options)\n    end\n  end\n\n  ### Headings\n\n  defp write_heading(heading, rest, text, indent, options) do\n    write_text(text, indent, options)\n    write(:doc_headings, heading, options)\n    newline_after_block(options)\n    process(rest, [], \"\", options)\n  end\n\n  ### Quotes\n\n  defp process_quote([\">\", \">\" <> line | rest], lines, indent, options) do\n    write_quote(lines, indent, options, true)\n    write_empty_quote_line(options)\n    process_quote(rest, [line], indent, options)\n  end\n\n  defp process_quote([\">\" <> line | rest], lines, indent, options) do\n    process_quote(rest, [line | lines], indent, options)\n  end\n\n  defp process_quote(rest, lines, indent, options) do\n    write_quote(lines, indent, options, false)\n    process(rest, [], indent, options)\n  end\n\n  defp write_quote(lines, indent, options, no_wrap) do\n    lines\n    |> Enum.map(&String.trim/1)\n    |> Enum.reverse()\n    |> write_lines(\n      indent,\n      options,\n      no_wrap,\n      quote_prefix(options)\n    )\n  end\n\n  defp write_empty_quote_line(options) do\n    options\n    |> quote_prefix()\n    |> IO.puts()\n  end\n\n  ### Lists\n\n  defp process_rest(stripped, rest, count, text, indent, options) do\n    case stripped do\n      <<bullet, ?\\s, item::binary>> when bullet in @bullets ->\n        write_text(text, indent, options)\n        process_list(bullet_text(options), item, rest, count, indent, options)\n\n      <<d1, ?., ?\\s, item::binary>> when d1 in ?0..?9 ->\n        write_text(text, indent, options)\n        process_list(<<d1, ?., ?\\s>>, item, rest, count, indent, options)\n\n      <<d1, d2, ?., ?\\s, item::binary>> when d1 in ?0..?9 and d2 in ?0..?9 ->\n        write_text(text, indent, options)\n        process_list(<<d1, d2, ?., ?\\s>>, item, rest, count, indent, options)\n\n      _ ->\n        process(rest, [stripped | text], indent, options)\n    end\n  end\n\n  defp process_list(entry, line, rest, count, indent, options) do\n    # The first list always win some extra padding\n    entry = if indent == \"\", do: \"  \" <> entry, else: entry\n    new_indent = indent <> String.duplicate(\" \", String.length(entry))\n\n    {contents, rest, done} =\n      process_list_next(rest, count, byte_size(new_indent) - byte_size(indent), [])\n\n    process(contents, [indent <> entry <> line, :no_wrap], new_indent, options)\n\n    if done, do: newline_after_block(options)\n    process(rest, [], indent, options)\n  end\n\n  defp process_list_next([line | rest], count, max, acc) do\n    {stripped, next_count} = strip_spaces(line, 0, max)\n\n    case process_list_next_kind(stripped, rest, count, next_count) do\n      :next -> process_list_next(rest, count, max, [stripped | acc])\n      :done -> {Enum.reverse(acc), [line | rest], true}\n      :list -> {Enum.reverse(acc), [line | rest], false}\n    end\n  end\n\n  defp process_list_next([], _count, _max, acc) do\n    {Enum.reverse(acc), [], true}\n  end\n\n  defp process_list_next_kind(stripped, rest, count, next_count) do\n    case {stripped, rest} do\n      {<<bullet, ?\\s, _::binary>>, _} when bullet in @bullets and next_count <= count ->\n        :list\n\n      {<<d1, ?., ?\\s, _::binary>>, _} when d1 in ?0..?9 and next_count <= count ->\n        :list\n\n      {<<d1, d2, ?., ?\\s, _::binary>>, _}\n      when d1 in ?0..?9 and d2 in ?0..?9 and next_count <= count ->\n        :list\n\n      {\"\", [\" \" <> _ | _]} ->\n        :next\n\n      {\"\", _} ->\n        :done\n\n      _ ->\n        :next\n    end\n  end\n\n  ### Text\n\n  defp write_text(text, indent, options) do\n    case Enum.reverse(text) do\n      [:no_wrap | rest] -> write_text(rest, indent, options, true)\n      rest -> write_text(rest, indent, options, false)\n    end\n  end\n\n  defp write_text([], _indent, _options, _no_wrap) do\n    :ok\n  end\n\n  defp write_text(lines, indent, options, no_wrap) do\n    write_lines(lines, indent, options, no_wrap, \"\")\n  end\n\n  defp write_lines(lines, indent, options, no_wrap, prefix) do\n    lines\n    |> Enum.join(\" \")\n    |> format_text(options)\n    |> String.split(@spaces)\n    |> write_with_wrap(options[:width] - byte_size(indent), indent, no_wrap, prefix)\n\n    if !no_wrap, do: newline_after_block(options)\n  end\n\n  defp format_text(text, options) do\n    text\n    |> handle_links()\n    |> handle_inline(options)\n  end\n\n  ### Code blocks\n\n  # Blank line between code blocks\n  defp process_code([\"\", \"    \" <> line | rest], code, indent, options) do\n    process_code(rest, [line, \"\" | code], indent, options)\n  end\n\n  defp process_code([\"    \" <> line | rest], code, indent, options) do\n    process_code(rest, [line | code], indent, options)\n  end\n\n  defp process_code(rest, code, indent, options) do\n    write_code(code, indent, options)\n    process(rest, [], indent, options)\n  end\n\n  defp process_fenced_code_block(rest, text, indent, options, delimiter) do\n    write_text(text, indent, options)\n    process_fenced_code(rest, [], indent, options, delimiter)\n  end\n\n  defp process_fenced_code([], code, indent, options, _delimiter) do\n    write_code(code, indent, options)\n  end\n\n  defp process_fenced_code([line | rest], code, indent, options, delimiter) do\n    if line == delimiter do\n      process_code(rest, code, indent, options)\n    else\n      process_fenced_code(rest, [line | code], indent, options, delimiter)\n    end\n  end\n\n  defp write_code(code, indent, options) do\n    write(:doc_code, \"#{indent}    #{Enum.join(Enum.reverse(code), \"\\n#{indent}    \")}\", options)\n    newline_after_block(options)\n  end\n\n  ### Tables\n\n  defp process_table(lines, indent, options) do\n    {table, rest} = Enum.split_while(lines, &table_line?/1)\n    table_lines(table, options)\n    newline_after_block(options)\n    process(rest, [], indent, options)\n  end\n\n  defp table_lines(lines, options) do\n    lines = Enum.map(lines, &split_into_columns(&1, options))\n    count = Enum.map(lines, &length/1) |> Enum.max()\n    lines = Enum.map(lines, &pad_to_number_of_columns(&1, count))\n\n    widths =\n      for line <- lines do\n        if table_header?(line) do\n          for _ <- line, do: 0\n        else\n          for {_col, length} <- line, do: length\n        end\n      end\n\n    col_widths = Enum.reduce(widths, List.duplicate(0, count), &max_column_widths/2)\n    render_table(lines, col_widths, options)\n  end\n\n  defp split_into_columns(line, options) do\n    line\n    |> String.trim(\" \")\n    |> String.trim(\"|\")\n    |> String.split(~r{(?<!\\\\)\\|})\n    |> Enum.map(&render_column(&1, options))\n  end\n\n  defp render_column(col, options) do\n    col =\n      col\n      |> String.trim()\n      |> String.replace(\"\\\\\\|\", \"|\")\n      |> handle_links()\n      |> handle_inline(options)\n\n    {col, length_without_escape(col, 0)}\n  end\n\n  defp pad_to_number_of_columns(cols, col_count),\n    do: cols ++ List.duplicate({\"\", 0}, col_count - length(cols))\n\n  defp max_column_widths(cols, widths),\n    do: Enum.zip(cols, widths) |> Enum.map(fn {a, b} -> max(a, b) end)\n\n  # If second line is heading separator, use the heading style on the first\n  defp render_table([first, second | rest], widths, options) do\n    combined = Enum.zip(first, widths)\n\n    if table_header?(second) do\n      alignments = Enum.map(second, &column_alignment/1)\n      options = Keyword.put_new(options, :alignments, alignments)\n      draw_table_row(combined, options, :heading)\n      render_table(rest, widths, options)\n    else\n      draw_table_row(combined, options)\n      render_table([second | rest], widths, options)\n    end\n  end\n\n  defp render_table([first | rest], widths, options) do\n    combined = Enum.zip(first, widths)\n    draw_table_row(combined, options)\n    render_table(rest, widths, options)\n  end\n\n  defp render_table([], _, _), do: nil\n\n  defp column_alignment({line, _}) do\n    cond do\n      String.starts_with?(line, \":\") and String.ends_with?(line, \":\") -> :center\n      String.ends_with?(line, \":\") -> :right\n      true -> :left\n    end\n  end\n\n  defp table_header?(line) do\n    Enum.all?(line, fn {col, _} -> table_header_column?(col) end)\n  end\n\n  defp table_header_column?(\":\" <> rest), do: table_header_contents?(rest)\n  defp table_header_column?(col), do: table_header_contents?(col)\n\n  defp table_header_contents?(\"-\" <> rest), do: table_header_contents?(rest)\n  defp table_header_contents?(\":\"), do: true\n  defp table_header_contents?(\"\"), do: true\n  defp table_header_contents?(_), do: false\n\n  defp draw_table_row(cols_and_widths, options, heading \\\\ false) do\n    default_alignments = List.duplicate(:left, length(cols_and_widths))\n    alignments = Keyword.get(options, :alignments, default_alignments)\n\n    columns =\n      cols_and_widths\n      |> Enum.zip(alignments)\n      |> Enum.map_join(\" | \", &generate_table_cell/1)\n\n    if heading do\n      write(:doc_table_heading, columns, options)\n    else\n      IO.puts(columns)\n    end\n  end\n\n  defp generate_table_cell({{{col, length}, width}, :center}) do\n    ansi_diff = byte_size(col) - length\n    width = width + ansi_diff\n\n    col\n    |> String.pad_leading(div(width, 2) - div(length, 2) + length)\n    |> String.pad_trailing(width + 1 - rem(width, 2))\n  end\n\n  defp generate_table_cell({{{col, length}, width}, :right}) do\n    ansi_diff = byte_size(col) - length\n    String.pad_leading(col, width + ansi_diff)\n  end\n\n  defp generate_table_cell({{{col, length}, width}, :left}) do\n    ansi_diff = byte_size(col) - length\n    String.pad_trailing(col, width + ansi_diff)\n  end\n\n  defp table_line?(line) do\n    line =~ ~r/[:\\ -]\\|[:\\ -]/\n  end\n\n  ## Helpers\n\n  defp link_label?(\"[\" <> rest, count) when count <= 3, do: link_label?(rest)\n  defp link_label?(_, _), do: false\n\n  defp link_label?(\"]: \" <> _), do: true\n  defp link_label?(\"]\" <> _), do: false\n  defp link_label?(\"\"), do: false\n  defp link_label?(<<_>> <> rest), do: link_label?(rest)\n\n  defp strip_spaces(\" \" <> line, acc, max) when acc < max, do: strip_spaces(line, acc + 1, max)\n  defp strip_spaces(rest, acc, _max), do: {rest, acc}\n\n  defp write(style, string, options) do\n    IO.puts([color(style, options), string, maybe_reset(options)])\n  end\n\n  defp write_with_wrap([], _available, _indent, _first, _prefix) do\n    :ok\n  end\n\n  defp write_with_wrap(words, available, indent, first, prefix) do\n    words\n    |> wrap_text(available, indent, first, prefix, [])\n    |> tl()\n    |> IO.puts()\n  end\n\n  defp wrap_text([], _available, _indent, _first, _prefix, wrapped_lines) do\n    Enum.reverse(wrapped_lines)\n  end\n\n  defp wrap_text(words, available, indent, first, prefix, wrapped_lines) do\n    prefix_length = length_without_escape(prefix, 0)\n    {words, rest} = take_words(words, available - prefix_length, [])\n    line = [if(first, do: \"\", else: indent), prefix, Enum.join(words, \" \")]\n\n    wrap_text(rest, available, indent, false, prefix, [line, ?\\n | wrapped_lines])\n  end\n\n  defp take_words([word | words], available, acc) do\n    available = available - length_without_escape(word, 0)\n\n    cond do\n      # It fits, take one for space and continue decreasing\n      available > 0 ->\n        take_words(words, available - 1, [word | acc])\n\n      # No space but we got no words\n      acc == [] ->\n        {[word], words}\n\n      # Otherwise\n      true ->\n        {Enum.reverse(acc), [word | words]}\n    end\n  end\n\n  defp take_words([], _available, acc) do\n    {Enum.reverse(acc), []}\n  end\n\n  defp length_without_escape(<<?\\e, ?[, _, _, ?m>> <> rest, count) do\n    length_without_escape(rest, count)\n  end\n\n  defp length_without_escape(<<?\\e, ?[, _, ?m>> <> rest, count) do\n    length_without_escape(rest, count)\n  end\n\n  defp length_without_escape(rest, count) do\n    case String.next_grapheme(rest) do\n      {_, rest} -> length_without_escape(rest, count + 1)\n      nil -> count\n    end\n  end\n\n  defp handle_links(text) do\n    text\n    |> remove_square_brackets_in_link()\n    |> escape_underlines_in_link()\n  end\n\n  defp escape_underlines_in_link(text) do\n    # Regular expression adapted from https://tools.ietf.org/html/rfc3986#appendix-B\n    Regex.replace(~r{[a-z][a-z0-9\\+\\-\\.]*://\\S*}i, text, &String.replace(&1, \"_\", \"\\\\_\"))\n  end\n\n  defp remove_square_brackets_in_link(text) do\n    Regex.replace(~r{\\[([^\\]]*?)\\]\\((.*?)\\)}, text, \"\\\\1 (\\\\2)\")\n  end\n\n  defp drop_comment(line) when is_binary(line) do\n    [_comment, rest] = :binary.split(line, \"-->\")\n    rest\n  end\n\n  defp drop_comment([line | rest]) do\n    case :binary.split(line, \"-->\") do\n      [_] -> drop_comment(rest)\n      [_, line] -> [line | rest]\n    end\n  end\n\n  defp drop_comment([]) do\n    []\n  end\n\n  # We have four entries: **, __, *, _ and `.\n  #\n  # The first four behave the same while the last one is simpler\n  # when it comes to delimiters as it ignores spaces and escape\n  # characters. But, since the first two has two characters,\n  # we need to handle 3 cases:\n  #\n  # 1. __ and **\n  # 2. _ and *\n  # 3. `\n  #\n  # Where the first two should have the same code but match differently.\n  @single [?_, ?*]\n\n  # Characters that can mark the beginning or the end of a word.\n  # Only support the most common ones at this moment.\n  @delimiters [?\\s, ?', ?\", ?!, ?@, ?#, ?$, ?%, ?^, ?&] ++\n                [?-, ?+, ?(, ?), ?[, ?], ?{, ?}, ?<, ?>, ?.]\n\n  ### Inline start\n\n  defp handle_inline(<<mark, mark, rest::binary>>, options) when mark in @single do\n    handle_inline(rest, [mark | mark], [<<mark, mark>>], [], options)\n  end\n\n  defp handle_inline(<<mark, rest::binary>>, options) when mark in @single do\n    handle_inline(rest, mark, [<<mark>>], [], options)\n  end\n\n  defp handle_inline(rest, options) do\n    handle_inline(rest, nil, [], [], options)\n  end\n\n  ### Inline delimiters\n\n  defp handle_inline(\"<!--\" <> rest, nil, buffer, acc, options) do\n    rest = drop_comment(rest)\n    handle_inline(rest, [], buffer, acc, options)\n  end\n\n  defp handle_inline(<<delimiter, mark, mark, rest::binary>>, nil, buffer, acc, options)\n       when rest != \"\" and delimiter in @delimiters and mark in @single do\n    acc = [delimiter, Enum.reverse(buffer) | acc]\n    handle_inline(rest, [mark | mark], [<<mark, mark>>], acc, options)\n  end\n\n  defp handle_inline(<<delimiter, mark, rest::binary>>, nil, buffer, acc, options)\n       when rest != \"\" and delimiter in @delimiters and mark in @single do\n    handle_inline(rest, mark, [<<mark>>], [delimiter, Enum.reverse(buffer) | acc], options)\n  end\n\n  defp handle_inline(<<?`, rest::binary>>, nil, buffer, acc, options)\n       when rest != \"\" do\n    handle_inline(rest, ?`, [\"`\"], [Enum.reverse(buffer) | acc], options)\n  end\n\n  ### Clauses for handling escape\n\n  defp handle_inline(<<?\\\\, ?\\\\, mark, mark, rest::binary>>, nil, buffer, acc, options)\n       when rest != \"\" and mark in @single do\n    acc = [?\\\\, Enum.reverse(buffer) | acc]\n    handle_inline(rest, [mark | mark], [<<mark, mark>>], acc, options)\n  end\n\n  defp handle_inline(<<?\\\\, ?\\\\, mark, rest::binary>>, nil, buffer, acc, options)\n       when rest != \"\" and mark in @single do\n    handle_inline(rest, mark, [<<mark>>], [?\\\\, Enum.reverse(buffer) | acc], options)\n  end\n\n  defp handle_inline(<<?\\\\, ?\\\\, rest::binary>>, limit, buffer, acc, options) do\n    handle_inline(rest, limit, [?\\\\ | buffer], acc, options)\n  end\n\n  # An escape is not valid inside `\n  defp handle_inline(<<?\\\\, mark, rest::binary>>, limit, buffer, acc, options) when limit != ?` do\n    handle_inline(rest, limit, [mark | buffer], acc, options)\n  end\n\n  ### Inline end\n\n  defp handle_inline(<<mark, mark, delimiter, rest::binary>>, [mark | mark], buffer, acc, options)\n       when delimiter in @delimiters and mark in @single do\n    inline_buffer = inline_buffer(buffer, options)\n    handle_inline(<<delimiter, rest::binary>>, nil, [], [inline_buffer | acc], options)\n  end\n\n  defp handle_inline(<<mark, delimiter, rest::binary>>, mark, buffer, acc, options)\n       when delimiter in @delimiters and mark in @single do\n    inline_buffer = inline_buffer(buffer, options)\n    handle_inline(<<delimiter, rest::binary>>, nil, [], [inline_buffer | acc], options)\n  end\n\n  defp handle_inline(<<mark, mark, rest::binary>>, [mark | mark], buffer, acc, options)\n       when rest == \"\" and mark in @single do\n    handle_inline(<<>>, nil, [], [inline_buffer(buffer, options) | acc], options)\n  end\n\n  defp handle_inline(<<mark, rest::binary>>, mark, buffer, acc, options)\n       when rest == \"\" and mark in @single do\n    handle_inline(<<>>, nil, [], [inline_buffer(buffer, options) | acc], options)\n  end\n\n  defp handle_inline(<<?`, rest::binary>>, ?`, buffer, acc, options) do\n    handle_inline(rest, nil, [], [inline_buffer(buffer, options) | acc], options)\n  end\n\n  ### Catch all\n\n  defp handle_inline(<<char, rest::binary>>, mark, buffer, acc, options) do\n    handle_inline(rest, mark, [char | buffer], acc, options)\n  end\n\n  defp handle_inline(<<>>, _mark, buffer, acc, _options) do\n    IO.iodata_to_binary(Enum.reverse([Enum.reverse(buffer) | acc]))\n  end\n\n  defp inline_buffer(buffer, options) do\n    [mark | t] = Enum.reverse(buffer)\n    inline_text(mark, t, options)\n  end\n\n  ## Helpers\n\n  defp quote_prefix(options), do: \"#{color(:doc_quote, options)}> #{maybe_reset(options)}\"\n\n  defp inline_text(mark, text, options) do\n    if options[:enabled] do\n      [[color_for(mark, options) | text] | IO.ANSI.reset()]\n    else\n      [[mark | text] | mark]\n    end\n  end\n\n  defp color_for(mark, colors) do\n    case mark do\n      \"__\" -> color(:doc_bold, colors)\n      \"**\" -> color(:doc_bold, colors)\n      \"_\" -> color(:doc_underline, colors)\n      \"*\" -> color(:doc_underline, colors)\n      \"`\" -> color(:doc_inline_code, colors)\n    end\n  end\n\n  defp bullet_text(options) do\n    if options[:enabled], do: @bullet_text_unicode, else: @bullet_text_ascii\n  end\n\n  defp color(style, colors) do\n    IO.ANSI.format_fragment(colors[style], colors[:enabled])\n  end\n\n  defp newline_after_block(options) do\n    IO.puts(maybe_reset(options))\n  end\n\n  defp maybe_reset(options) do\n    if options[:enabled], do: IO.ANSI.reset(), else: \"\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/io/ansi.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IO.ANSI do\n  @moduledoc \"\"\"\n  Functionality to render ANSI escape sequences.\n\n  [ANSI escape sequences](https://en.wikipedia.org/wiki/ANSI_escape_code)\n  are characters embedded in text used to control formatting, color, and\n  other output options on video text terminals.\n\n  ANSI escapes are typically enabled on all Unix terminals. They are also\n  available on Windows consoles from Windows 10, although it must be\n  explicitly enabled for the current user in the registry by running the\n  following command:\n\n      reg add HKCU\\\\Console /v VirtualTerminalLevel /t REG_DWORD /d 1\n\n  After running the command above, you must restart your current console.\n\n  ## Examples\n\n  Because the ANSI escape sequences are embedded in text, the normal usage of\n  these functions is to concatenate their output with text.\n\n      formatted_text = IO.ANSI.blue_background() <> \"Example\" <> IO.ANSI.reset()\n      IO.puts(formatted_text)\n\n  A higher level and more convenient API is also available via `IO.ANSI.format/1`,\n  where you use atoms to represent each ANSI escape sequence and by default\n  checks if ANSI is enabled:\n\n      IO.puts(IO.ANSI.format([:blue_background, \"Example\"]))\n\n  In case ANSI is disabled, the ANSI escape sequences are simply discarded.\n  \"\"\"\n\n  @type ansicode :: atom\n  @type ansilist ::\n          maybe_improper_list(char | ansicode | binary | ansilist, binary | ansicode | [])\n  @type ansidata :: ansilist | ansicode | binary\n\n  @doc \"\"\"\n  Checks if ANSI coloring is supported and enabled on this machine.\n\n  This function simply reads the configuration value for\n  `:ansi_enabled` in the `:elixir` application. The value is by\n  default `false` unless Elixir can detect during startup that\n  both `stdout` and `stderr` are terminals.\n  \"\"\"\n  @spec enabled? :: boolean\n  def enabled? do\n    Application.get_env(:elixir, :ansi_enabled, false)\n  end\n\n  @doc \"\"\"\n  Syntax colors to be used by `Inspect`.\n\n  Those colors are used throughout Elixir's standard library,\n  such as `dbg/2` and `IEx`.\n\n  The colors can be changed by setting the `:ansi_syntax_colors`\n  in the `:elixir` application configuration. Configuration for\n  most built-in data types are supported: `:atom`, `:binary`,\n  `:boolean`, `:charlist`, `:list`, `:map`, `:nil`, `:number`,\n  `:string`, and `:tuple`. The default is:\n\n      [\n        atom: :cyan\n        boolean: :magenta,\n        charlist: :yellow,\n        nil: :magenta,\n        number: :yellow,\n        string: :green\n      ]\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec syntax_colors :: Keyword.t(ansidata)\n  def syntax_colors do\n    Application.fetch_env!(:elixir, :ansi_syntax_colors)\n  end\n\n  @doc \"Sets foreground color.\"\n  @spec color(0..255) :: String.t()\n  def color(code) when code in 0..255, do: \"\\e[38;5;#{code}m\"\n\n  @doc ~S\"\"\"\n  Sets the foreground color from individual RGB values.\n\n  Valid values for each color are in the range 0 to 5.\n  \"\"\"\n  @spec color(0..5, 0..5, 0..5) :: String.t()\n  def color(r, g, b) when r in 0..5 and g in 0..5 and b in 0..5 do\n    color(16 + 36 * r + 6 * g + b)\n  end\n\n  @doc \"Sets background color.\"\n  @spec color_background(0..255) :: String.t()\n  def color_background(code) when code in 0..255, do: \"\\e[48;5;#{code}m\"\n\n  @doc ~S\"\"\"\n  Sets the background color from individual RGB values.\n\n  Valid values for each color are in the range 0 to 5.\n  \"\"\"\n  @spec color_background(0..5, 0..5, 0..5) :: String.t()\n  def color_background(r, g, b) when r in 0..5 and g in 0..5 and b in 0..5 do\n    color_background(16 + 36 * r + 6 * g + b)\n  end\n\n  defsequence = fn name, code, terminator ->\n    @spec unquote(name)() :: String.t()\n    def unquote(name)() do\n      \"\\e[#{unquote(code)}#{unquote(terminator)}\"\n    end\n\n    defp format_sequence(unquote(name)) do\n      unquote(name)()\n    end\n  end\n\n  @doc \"Resets all attributes.\"\n  defsequence.(:reset, 0, \"m\")\n\n  @doc \"Bright (increased intensity) or bold.\"\n  defsequence.(:bright, 1, \"m\")\n\n  @doc \"Faint (decreased intensity). Not widely supported.\"\n  defsequence.(:faint, 2, \"m\")\n\n  @doc \"Italic: on. Not widely supported. Sometimes treated as inverse.\"\n  defsequence.(:italic, 3, \"m\")\n\n  @doc \"Underline: single.\"\n  defsequence.(:underline, 4, \"m\")\n\n  @doc \"Blink: slow. Less than 150 per minute.\"\n  defsequence.(:blink_slow, 5, \"m\")\n\n  @doc \"Blink: rapid. MS-DOS ANSI.SYS; 150 per minute or more; not widely supported.\"\n  defsequence.(:blink_rapid, 6, \"m\")\n\n  @doc \"Image: negative. Swap foreground and background.\"\n  defsequence.(:inverse, 7, \"m\")\n\n  @doc \"Image: negative. Swap foreground and background.\"\n  defsequence.(:reverse, 7, \"m\")\n\n  @doc \"Conceal. Not widely supported.\"\n  defsequence.(:conceal, 8, \"m\")\n\n  @doc \"Crossed-out. Characters legible, but marked for deletion. Not widely supported.\"\n  defsequence.(:crossed_out, 9, \"m\")\n\n  @doc \"Sets primary (default) font.\"\n  defsequence.(:primary_font, 10, \"m\")\n\n  for font_n <- [1, 2, 3, 4, 5, 6, 7, 8, 9] do\n    @doc \"Sets alternative font #{font_n}.\"\n    defsequence.(:\"font_#{font_n}\", font_n + 10, \"m\")\n  end\n\n  @doc \"Normal color or intensity.\"\n  defsequence.(:normal, 22, \"m\")\n\n  @doc \"Not italic.\"\n  defsequence.(:not_italic, 23, \"m\")\n\n  @doc \"Underline: none.\"\n  defsequence.(:no_underline, 24, \"m\")\n\n  @doc \"Blink: off.\"\n  defsequence.(:blink_off, 25, \"m\")\n\n  @doc \"Image: positive. Normal foreground and background.\"\n  defsequence.(:inverse_off, 27, \"m\")\n\n  @doc \"Image: positive. Normal foreground and background.\"\n  defsequence.(:reverse_off, 27, \"m\")\n\n  @doc \"Reveal: Not concealed.\"\n  defsequence.(:reveal, 28, \"m\")\n\n  @doc \"Not crossed-out.\"\n  defsequence.(:not_crossed_out, 29, \"m\")\n\n  colors = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]\n\n  for {color, code} <- Enum.with_index(colors) do\n    @doc \"Sets foreground color to #{color}.\"\n    defsequence.(color, code + 30, \"m\")\n\n    @doc \"Sets foreground color to light #{color}.\"\n    defsequence.(:\"light_#{color}\", code + 90, \"m\")\n\n    @doc \"Sets background color to #{color}.\"\n    defsequence.(:\"#{color}_background\", code + 40, \"m\")\n\n    @doc \"Sets background color to light #{color}.\"\n    defsequence.(:\"light_#{color}_background\", code + 100, \"m\")\n  end\n\n  @doc \"Default text color.\"\n  defsequence.(:default_color, 39, \"m\")\n\n  @doc \"Default background color.\"\n  defsequence.(:default_background, 49, \"m\")\n\n  @doc \"Framed.\"\n  defsequence.(:framed, 51, \"m\")\n\n  @doc \"Encircled.\"\n  defsequence.(:encircled, 52, \"m\")\n\n  @doc \"Overlined.\"\n  defsequence.(:overlined, 53, \"m\")\n\n  @doc \"Not framed or encircled.\"\n  defsequence.(:not_framed_encircled, 54, \"m\")\n\n  @doc \"Not overlined.\"\n  defsequence.(:not_overlined, 55, \"m\")\n\n  @doc \"Clears screen.\"\n  defsequence.(:clear, \"2\", \"J\")\n\n  @doc \"Clears line.\"\n  defsequence.(:clear_line, \"2\", \"K\")\n\n  @doc \"Sends cursor home.\"\n  defsequence.(:home, \"\", \"H\")\n\n  @doc \"\"\"\n  Sends cursor to the absolute position specified by `line` and `column`.\n\n  Line `0` and column `0` would mean the top left corner.\n  \"\"\"\n  @spec cursor(non_neg_integer, non_neg_integer) :: String.t()\n  def cursor(line, column)\n      when is_integer(line) and line >= 0 and is_integer(column) and column >= 0 do\n    \"\\e[#{line};#{column}H\"\n  end\n\n  @doc \"Sends cursor `lines` up.\"\n  @spec cursor_up(pos_integer) :: String.t()\n  def cursor_up(lines \\\\ 1) when is_integer(lines) and lines >= 1, do: \"\\e[#{lines}A\"\n\n  @doc \"Sends cursor `lines` down.\"\n  @spec cursor_down(pos_integer) :: String.t()\n  def cursor_down(lines \\\\ 1) when is_integer(lines) and lines >= 1, do: \"\\e[#{lines}B\"\n\n  @doc \"Sends cursor `columns` to the right.\"\n  @spec cursor_right(pos_integer) :: String.t()\n  def cursor_right(columns \\\\ 1) when is_integer(columns) and columns >= 1, do: \"\\e[#{columns}C\"\n\n  @doc \"Sends cursor `columns` to the left.\"\n  @spec cursor_left(pos_integer) :: String.t()\n  def cursor_left(columns \\\\ 1) when is_integer(columns) and columns >= 1, do: \"\\e[#{columns}D\"\n\n  defp format_sequence(other) do\n    raise ArgumentError, \"invalid ANSI sequence specification: #{inspect(other)}\"\n  end\n\n  @doc ~S\"\"\"\n  Formats a chardata-like argument by converting named ANSI sequences into actual\n  ANSI codes.\n\n  The named sequences are represented by atoms.\n\n  It will also append an `IO.ANSI.reset/0` to the chardata when a conversion is\n  performed. If you don't want this behavior, use `format_fragment/2`.\n\n  An optional boolean parameter can be passed to enable or disable\n  emitting actual ANSI codes. When `false`, no ANSI codes will be emitted.\n  By default checks if ANSI is enabled using the `enabled?/0` function.\n\n  An `ArgumentError` will be raised if an invalid ANSI code is provided.\n\n  ## Examples\n\n      iex> IO.ANSI.format([\"Hello, \", :red, :bright, \"world!\"], true)\n      [[[[[[], \"Hello, \"] | \"\\e[31m\"] | \"\\e[1m\"], \"world!\"] | \"\\e[0m\"]\n\n  \"\"\"\n  @spec format(ansidata, boolean) :: IO.chardata()\n  def format(ansidata, emit? \\\\ enabled?()) when is_boolean(emit?) do\n    do_format(ansidata, [], [], emit?, :maybe)\n  end\n\n  @doc ~S\"\"\"\n  Formats a chardata-like argument by converting named ANSI sequences into actual\n  ANSI codes.\n\n  The named sequences are represented by atoms.\n\n  An optional boolean parameter can be passed to enable or disable\n  emitting actual ANSI codes. When `false`, no ANSI codes will be emitted.\n  By default checks if ANSI is enabled using the `enabled?/0` function.\n\n  ## Examples\n\n      iex> IO.ANSI.format_fragment([:bright, ~c\"Word\"], true)\n      [[[[[[] | \"\\e[1m\"], 87], 111], 114], 100]\n\n  \"\"\"\n  @spec format_fragment(ansidata, boolean) :: IO.chardata()\n  def format_fragment(ansidata, emit? \\\\ enabled?()) when is_boolean(emit?) do\n    do_format(ansidata, [], [], emit?, false)\n  end\n\n  defp do_format([term | rest], rem, acc, emit?, append_reset) do\n    do_format(term, [rest | rem], acc, emit?, append_reset)\n  end\n\n  defp do_format(term, rem, acc, true, append_reset) when is_atom(term) do\n    do_format([], rem, [acc | format_sequence(term)], true, !!append_reset)\n  end\n\n  defp do_format(term, rem, acc, false, append_reset) when is_atom(term) do\n    format_sequence(term)\n    do_format([], rem, acc, false, append_reset)\n  end\n\n  defp do_format(term, rem, acc, emit?, append_reset) when not is_list(term) do\n    do_format([], rem, [acc, term], emit?, append_reset)\n  end\n\n  defp do_format([], [next | rest], acc, emit?, append_reset) do\n    do_format(next, rest, acc, emit?, append_reset)\n  end\n\n  defp do_format([], [], acc, true, true) do\n    [acc | IO.ANSI.reset()]\n  end\n\n  defp do_format([], [], acc, _emit?, _append_reset) do\n    acc\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/io/stream.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IO.StreamError do\n  defexception [:reason]\n\n  @impl true\n  def message(%{reason: reason}) do\n    \"error during streaming: #{inspect(reason)}\"\n  end\nend\n\ndefmodule IO.Stream do\n  @moduledoc \"\"\"\n  Defines an `IO.Stream` struct returned by `IO.stream/2` and `IO.binstream/2`.\n\n  The following fields are public:\n\n    * `device`        - the IO device\n    * `raw`           - a boolean indicating if bin functions should be used\n    * `line_or_bytes` - if reading should read lines or a given number of bytes\n\n  It is worth noting that an IO stream has side effects and every time you go\n  over the stream you may get different results.\n\n  \"\"\"\n\n  defstruct device: nil, raw: true, line_or_bytes: :line\n\n  @type t :: %__MODULE__{\n          device: IO.device(),\n          raw: boolean(),\n          line_or_bytes: :line | non_neg_integer()\n        }\n\n  @doc false\n  def __build__(device, raw, line_or_bytes) do\n    %IO.Stream{device: device, raw: raw, line_or_bytes: line_or_bytes}\n  end\n\n  defimpl Collectable do\n    def into(%{device: device, raw: raw} = stream) do\n      {:ok, into(stream, device, raw)}\n    end\n\n    defp into(stream, device, raw) do\n      fn\n        :ok, {:cont, x} ->\n          case raw do\n            true -> IO.binwrite(device, x)\n            false -> IO.write(device, x)\n          end\n\n        :ok, _ ->\n          stream\n      end\n    end\n  end\n\n  defimpl Enumerable do\n    def reduce(%{device: device, raw: raw, line_or_bytes: line_or_bytes}, acc, fun) do\n      next_fun =\n        case raw do\n          true -> &IO.each_binstream(&1, line_or_bytes)\n          false -> &IO.each_stream(&1, line_or_bytes)\n        end\n\n      Stream.resource(fn -> device end, next_fun, & &1).(acc, fun)\n    end\n\n    def count(_stream) do\n      {:error, __MODULE__}\n    end\n\n    def member?(_stream, _term) do\n      {:error, __MODULE__}\n    end\n\n    def slice(_stream) do\n      {:error, __MODULE__}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/io.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IO do\n  @moduledoc ~S\"\"\"\n  Functions handling input/output (IO).\n\n  Many functions in this module expect an IO device as an argument.\n  An IO device must be a PID or an atom representing a process.\n  For convenience, Elixir provides `:stdio` and `:stderr` as\n  shortcuts to Erlang's `:standard_io` and `:standard_error`.\n\n  The majority of the functions expect chardata. In case another type is given,\n  functions will convert those types to string via the `String.Chars` protocol\n  (as shown in typespecs). For more information on chardata, see the\n  \"IO data\" section below.\n\n  The functions of this module use UNIX-style naming where possible.\n\n  ## IO devices\n\n  An IO device may be an atom or a PID. In case it is an atom,\n  the atom must be the name of a registered process. In addition,\n  Elixir provides two shortcuts:\n\n    * `:stdio` - a shortcut for `:standard_io`, which maps to\n      the current `Process.group_leader/0` in Erlang\n\n    * `:stderr` - a shortcut for the named process `:standard_error`\n      provided in Erlang\n\n  IO devices maintain their position, which means subsequent calls to any\n  reading or writing functions will start from the place where the device\n  was last accessed. The position of files can be changed using the\n  `:file.position/2` function.\n\n  ## IO data\n\n  IO data is a data type that can be used as a more efficient alternative to binaries\n  in certain situations.\n\n  A term of type **IO data** is a binary or a list containing bytes (integers within the `0..255` range)\n  or nested IO data. The type is recursive. Let's see an example of one of\n  the possible IO data representing the binary `\"hello\"`:\n\n      [?h, \"el\", [\"l\", [?o]]]\n\n  The built-in `t:iodata/0` type is defined in terms of `t:iolist/0`. An IO list is\n  the same as IO data but it doesn't allow for a binary at the top level (but binaries\n  are still allowed in the list itself).\n\n  ### Use cases for IO data\n\n  IO data exists because often you need to do many append operations\n  on smaller chunks of binaries in order to create a bigger binary. However, in\n  Erlang and Elixir concatenating binaries will copy the concatenated binaries\n  into a new binary.\n\n      def email(username, domain) do\n        username <> \"@\" <> domain\n      end\n\n  In this function, creating the email address will copy the `username` and `domain`\n  binaries. Now imagine you want to use the resulting email inside another binary:\n\n      def welcome_message(name, username, domain) do\n        \"Welcome #{name}, your email is: #{email(username, domain)}\"\n      end\n\n      IO.puts(welcome_message(\"Meg\", \"meg\", \"example.com\"))\n      #=> \"Welcome Meg, your email is: meg@example.com\"\n\n  Every time you concatenate binaries or use interpolation (`#{}`) you are making\n  copies of those binaries. However, in many cases you don't need the complete\n  binary while you create it, but only at the end to print it out or send it\n  somewhere. In such cases, you can construct the binary by creating IO data:\n\n      def email(username, domain) do\n        [username, ?@, domain]\n      end\n\n      def welcome_message(name, username, domain) do\n        [\"Welcome \", name, \", your email is: \", email(username, domain)]\n      end\n\n      IO.puts(welcome_message(\"Meg\", \"meg\", \"example.com\"))\n      #=> \"Welcome Meg, your email is: meg@example.com\"\n\n  Building IO data is cheaper than concatenating binaries. Concatenating multiple\n  pieces of IO data just means putting them together inside a list since IO data\n  can be arbitrarily nested, and that's a cheap and efficient operation. Most of\n  the IO-based APIs, such as `:gen_tcp` and `IO`, receive IO data and write it\n  to the socket directly without converting it to binary.\n\n  One drawback of IO data is that you can't do things like pattern match on the\n  first part of a piece of IO data like you can with a binary, because you usually\n  don't know the shape of the IO data. In those cases, you may need to convert it\n  to a binary by calling `iodata_to_binary/1`, which is reasonably efficient\n  since it's implemented natively in C. Other functionality, like computing the\n  length of IO data, can be computed directly on the iodata by calling `iodata_length/1`.\n\n  ### Chardata\n\n  Erlang and Elixir also have the idea of `t:chardata/0`. Chardata is very\n  similar to IO data: the only difference is that integers in IO data represent\n  bytes while integers in chardata represent Unicode code points. Bytes\n  (`t:byte/0`) are integers within the `0..255` range, while Unicode code points\n  (`t:char/0`) are integers within the `0..0x10FFFF` range. The `IO` module provides\n  the `chardata_to_string/1` function for chardata as the \"counter-part\" of the\n  `iodata_to_binary/1` function for IO data.\n\n  If you try to use `iodata_to_binary/1` on chardata, it will result in an\n  argument error. For example, let's try to put a code point that is not\n  representable with one byte, like `?π`, inside IO data:\n\n      IO.iodata_to_binary([\"The symbol for pi is: \", ?π])\n      #=> ** (ArgumentError) argument error\n\n  If we use chardata instead, it will work as expected:\n\n      iex> IO.chardata_to_string([\"The symbol for pi is: \", ?π])\n      \"The symbol for pi is: π\"\n\n  \"\"\"\n\n  @type device :: atom | pid\n  @type nodata :: {:error, term} | :eof\n  @type chardata :: String.t() | maybe_improper_list(char | chardata, String.t() | [])\n\n  @type inspect_opts :: [Inspect.Opts.new_opt() | {:label, term}]\n\n  @typedoc \"\"\"\n  Stacktrace information as keyword options for `warn/2`.\n\n  At least `:file` is required. Other options are optional and used\n  to provide more precise location information.\n  \"\"\"\n  @type warn_stacktrace_opts :: [\n          file: String.t(),\n          line: pos_integer(),\n          column: pos_integer(),\n          module: module(),\n          function: {atom(), arity()}\n        ]\n\n  defguardp is_device(term) when is_atom(term) or is_pid(term)\n  defguardp is_iodata(data) when is_list(data) or is_binary(data)\n\n  @doc ~S\"\"\"\n  Reads from the IO `device`.\n\n  The `device` is iterated as specified by the `line_or_chars` argument:\n\n    * if `line_or_chars` is an integer, it represents a number of bytes. The device is\n      iterated by that number of bytes. This should be the preferred mode for reading\n      non-textual inputs.\n\n    * if `line_or_chars` is `:line`, the device is iterated line by line.\n      CRLF newlines  (\"\\r\\n\") are automatically normalized to \"\\n\".\n\n    * if `line_or_chars` is `:eof` (since v1.13), the device is iterated until `:eof`.\n      If the device is already at the end, it returns `:eof` itself.\n\n  It returns:\n\n    * `data` - the output characters\n\n    * `:eof` - end of file was encountered\n\n    * `{:error, reason}` - other (rare) error condition;\n      for instance, `{:error, :estale}` if reading from an\n      NFS volume\n\n  \"\"\"\n  @spec read(device, :eof | :line | non_neg_integer) :: chardata | nodata\n  def read(device \\\\ :stdio, line_or_chars)\n\n  # TODO: Remove me on v2.0\n  def read(device, :all) do\n    IO.warn(\"IO.read(device, :all) is deprecated, use IO.read(device, :eof) instead\")\n\n    with :eof <- read(device, :eof) do\n      with [_ | _] = opts <- :io.getopts(device),\n           false <- Keyword.get(opts, :binary, true) do\n        ~c\"\"\n      else\n        _ -> \"\"\n      end\n    end\n  end\n\n  def read(device, :eof) do\n    getn(device, ~c\"\", :eof)\n  end\n\n  def read(device, :line) do\n    :io.get_line(map_dev(device), ~c\"\")\n  end\n\n  def read(device, count) when is_integer(count) and count >= 0 do\n    :io.get_chars(map_dev(device), ~c\"\", count)\n  end\n\n  @doc ~S\"\"\"\n  Reads from the IO `device`. The operation is Unicode unsafe.\n\n  The `device` is iterated as specified by the `line_or_chars` argument:\n\n    * if `line_or_chars` is an integer, it represents a number of bytes. The device is\n      iterated by that number of bytes. This should be the preferred mode for reading\n      non-textual inputs.\n\n    * if `line_or_chars` is `:line`, the device is iterated line by line.\n      CRLF newlines  (\"\\r\\n\") are automatically normalized to \"\\n\".\n\n    * if `line_or_chars` is `:eof` (since v1.13), the device is iterated until `:eof`.\n      If the device is already at the end, it returns `:eof` itself.\n\n  It returns:\n\n    * `data` - the output bytes\n\n    * `:eof` - end of file was encountered\n\n    * `{:error, reason}` - other (rare) error condition;\n      for instance, `{:error, :estale}` if reading from an\n      NFS volume\n\n  Note: do not use this function on IO devices in Unicode mode\n  as it will return the wrong result.\n  \"\"\"\n  @spec binread(device, :eof | :line | non_neg_integer) :: iodata | nodata\n  def binread(device \\\\ :stdio, line_or_chars)\n\n  # TODO: Remove me on v2.0\n  def binread(device, :all) do\n    IO.warn(\"IO.binread(device, :all) is deprecated, use IO.binread(device, :eof) instead\")\n    with :eof <- binread(device, :eof), do: \"\"\n  end\n\n  def binread(device, :eof) do\n    binread_eof(map_dev(device), \"\")\n  end\n\n  def binread(device, :line) do\n    case :file.read_line(map_dev(device)) do\n      {:ok, data} -> data\n      other -> other\n    end\n  end\n\n  def binread(device, count) when is_integer(count) and count >= 0 do\n    case :file.read(map_dev(device), count) do\n      {:ok, data} -> data\n      other -> other\n    end\n  end\n\n  @read_all_size 4096\n  defp binread_eof(mapped_dev, acc) do\n    case :file.read(mapped_dev, @read_all_size) do\n      {:ok, data} -> binread_eof(mapped_dev, acc <> data)\n      :eof -> if acc == \"\", do: :eof, else: acc\n      other -> other\n    end\n  end\n\n  @doc \"\"\"\n  Writes `chardata` to the given `device`.\n\n  By default, the `device` is the standard output.\n\n  ## Examples\n\n      IO.write(\"sample\")\n      #=> sample\n\n      IO.write(:stderr, \"error\")\n      #=> error\n\n  \"\"\"\n  @spec write(device, chardata | String.Chars.t()) :: :ok\n  def write(device \\\\ :stdio, chardata) do\n    :io.put_chars(map_dev(device), to_chardata(chardata))\n  end\n\n  @doc \"\"\"\n  Writes `iodata` to the given `device`.\n\n  This operation is meant to be used with \"raw\" devices\n  that are started without an encoding. The given `iodata`\n  is written as is to the device, without conversion. For\n  more information on IO data, see the \"IO data\" section in\n  the module documentation.\n\n  Use `write/2` for devices with encoding.\n\n  Important: do **not** use this function on IO devices in\n  Unicode mode as it will write the wrong data. In particular,\n  the standard IO device is set to Unicode by default, so writing\n  to stdio with this function will likely result in the wrong data\n  being sent down the wire.\n  \"\"\"\n  @spec binwrite(device, iodata) :: :ok\n  def binwrite(device \\\\ :stdio, iodata) when is_iodata(iodata) do\n    with {:error, reason} <- :file.write(map_dev(device), iodata) do\n      :erlang.error(reason)\n    end\n  end\n\n  @doc \"\"\"\n  Writes `item` to the given `device`, similar to `write/2`,\n  but adds a newline at the end.\n\n  By default, the `device` is the standard output. It returns `:ok`\n  if it succeeds.\n\n  Trivia: `puts` is shorthand for `put string`.\n\n  ## Examples\n\n      IO.puts(\"Hello World!\")\n      #=> Hello World!\n\n      IO.puts(:stderr, \"error\")\n      #=> error\n\n  \"\"\"\n  @spec puts(device, chardata | String.Chars.t()) :: :ok\n  def puts(device \\\\ :stdio, item) when is_device(device) do\n    :io.put_chars(map_dev(device), [to_chardata(item), ?\\n])\n  end\n\n  @doc \"\"\"\n  Writes a `message` to stderr, along with the given `stacktrace_info`.\n\n  The `stacktrace_info` must be one of:\n\n    * a `__STACKTRACE__`, where all entries in the stacktrace will be\n      included in the error message\n\n    * a `Macro.Env` structure (since v1.14.0), where a single stacktrace\n      entry from the compilation environment will be used\n\n    * a keyword list with at least the `:file` option representing\n      a single stacktrace entry (since v1.14.0). The `:line`, `:column`,\n      `:module`, and `:function` options are also supported\n\n  This function notifies the compiler a warning was printed\n  and emits a compiler diagnostic (`t:Code.diagnostic/1`).\n  The diagnostic will include precise file and location information\n  if a `Macro.Env` is given or those values have been passed as\n  keyword list, but not for stacktraces, as they are often imprecise.\n\n  It returns `:ok` if it succeeds.\n\n  ## Examples\n\n      IO.warn(\"variable bar is unused\", module: MyApp, function: {:main, 1}, line: 4, file: \"my_app.ex\")\n      #=> warning: variable bar is unused\n      #=>   my_app.ex:4: MyApp.main/1\n\n  \"\"\"\n  @spec warn(\n          chardata | String.Chars.t(),\n          Exception.stacktrace() | warn_stacktrace_opts() | Macro.Env.t()\n        ) ::\n          :ok\n  def warn(message, stacktrace_info)\n\n  def warn(message, %Macro.Env{line: line, file: file} = env) do\n    message = to_chardata(message)\n\n    :elixir_errors.emit_diagnostic(:warning, line, file, message, Macro.Env.stacktrace(env),\n      read_snippet: true\n    )\n  end\n\n  def warn(message, [{_, _} | _] = keyword) do\n    if file = keyword[:file] do\n      line = keyword[:line]\n      column = keyword[:column]\n      position = if line && column, do: {line, column}, else: line\n      message = to_chardata(message)\n\n      stacktrace =\n        Macro.Env.stacktrace(%{\n          __ENV__\n          | module: keyword[:module],\n            function: keyword[:function],\n            line: line,\n            file: file\n        })\n\n      :elixir_errors.emit_diagnostic(:warning, position, file, message, stacktrace,\n        read_snippet: true\n      )\n    else\n      warn(message, [])\n    end\n  end\n\n  def warn(message, []) do\n    message = to_chardata(message)\n    :elixir_errors.emit_diagnostic(:warning, 0, nil, message, [], read_snippet: false)\n  end\n\n  def warn(message, [{_, _, _, _} | _] = stacktrace) do\n    message = to_chardata(message)\n    :elixir_errors.emit_diagnostic(:warning, 0, nil, message, stacktrace, read_snippet: false)\n  end\n\n  @doc false\n  def warn_once(key, message, stacktrace_drop_levels) do\n    {:current_stacktrace, stacktrace} = Process.info(self(), :current_stacktrace)\n    stacktrace = Enum.drop(stacktrace, stacktrace_drop_levels)\n\n    if :elixir_config.warn(key, stacktrace) do\n      warn(message.(), stacktrace)\n    else\n      :ok\n    end\n  end\n\n  @doc \"\"\"\n  Writes a `message` to stderr, along with the current stacktrace.\n\n  It returns `:ok` if it succeeds.\n\n  Do not call this function at the tail of another function. Due to tail\n  call optimization, a stacktrace entry would not be added and the\n  stacktrace would be incorrectly trimmed. Therefore make sure at least\n  one expression (or an atom such as `:ok`) follows the `IO.warn/1` call.\n\n  ## Examples\n\n      IO.warn(\"variable bar is unused\")\n      #=> warning: variable bar is unused\n      #=>   (iex) evaluator.ex:108: IEx.Evaluator.eval/4\n\n  \"\"\"\n  @spec warn(chardata | String.Chars.t()) :: :ok\n  def warn(message) do\n    {:current_stacktrace, stacktrace} = Process.info(self(), :current_stacktrace)\n    warn(message, Enum.drop(stacktrace, 2))\n  end\n\n  @doc \"\"\"\n  Inspects and writes the given `item` to the standard output.\n\n  It's important to note that it returns the given `item` unchanged.\n  This makes it possible to \"spy\" on values by inserting an\n  `IO.inspect/2` call almost anywhere in your code, for example,\n  in the middle of a pipeline.\n\n  It enables pretty printing by default with width of\n  80 characters. The width can be changed by explicitly\n  passing the `:width` option.\n\n  The output can be decorated with a label, by providing the `:label`\n  option to easily distinguish it from other `IO.inspect/2` calls.\n  The label will be printed before the inspected `item`.\n\n  See `Inspect.Opts` for a full list of remaining formatting options.\n  To print to other IO devices, see `IO.inspect/3`\n\n  ## Examples\n\n  The following code:\n\n      IO.inspect(<<0, 1, 2>>, width: 40)\n\n  Prints:\n\n      <<0, 1, 2>>\n\n  You can use the `:label` option to decorate the output:\n\n      IO.inspect(1..100, label: \"a wonderful range\")\n\n  Prints:\n\n      a wonderful range: 1..100\n\n  Inspect truncates large inputs by default. The `:printable_limit` controls\n  the limit for strings and other string-like constructs (such as charlists):\n\n      \"abc\"\n      |> String.duplicate(9001)\n      |> IO.inspect(printable_limit: :infinity)\n\n  For containers such as lists, maps, and tuples, the number of entries\n  is managed by the `:limit` option:\n\n      1..100\n      |> Enum.map(& {&1, &1})\n      |> Enum.into(%{})\n      |> IO.inspect(limit: :infinity)\n\n  \"\"\"\n  @spec inspect(item, inspect_opts) :: item when item: var\n  def inspect(item, opts \\\\ []) do\n    inspect(:stdio, item, opts)\n  end\n\n  @doc \"\"\"\n  Inspects `item` according to the given options using the IO `device`.\n\n  See `inspect/2` for a full list of options.\n  \"\"\"\n  @spec inspect(device, item, inspect_opts) :: item when item: var\n  def inspect(device, item, opts) when is_device(device) and is_list(opts) do\n    {label, opts} = Keyword.pop(opts, :label)\n    label = if label, do: [to_chardata(label), \": \"], else: []\n    opts = Inspect.Opts.new(opts)\n    doc = Inspect.Algebra.group(Inspect.Algebra.to_doc(item, opts))\n    chardata = Inspect.Algebra.format(doc, opts.width)\n    puts(device, [label, chardata])\n    item\n  end\n\n  @doc \"\"\"\n  Gets a number of bytes from IO device `:stdio`.\n\n  If `:stdio` is a Unicode device, `count` implies\n  the number of Unicode code points to be retrieved.\n  Otherwise, `count` is the number of raw bytes to be retrieved.\n\n  See `IO.getn/3` for a description of return values.\n  \"\"\"\n  @spec getn(\n          device | chardata | String.Chars.t(),\n          pos_integer | :eof | chardata | String.Chars.t()\n        ) ::\n          chardata | nodata\n  def getn(prompt, count \\\\ 1)\n\n  def getn(prompt, :eof) do\n    getn(:stdio, prompt, :eof)\n  end\n\n  def getn(prompt, count) when is_integer(count) and count > 0 do\n    getn(:stdio, prompt, count)\n  end\n\n  def getn(device, prompt) when not is_integer(prompt) do\n    getn(device, prompt, 1)\n  end\n\n  @doc \"\"\"\n  Gets a number of bytes from the IO `device`.\n\n  If the IO `device` is a Unicode device, `count` implies\n  the number of Unicode code points to be retrieved.\n  Otherwise, `count` is the number of raw bytes to be retrieved.\n\n  It returns:\n\n    * `data` - the input characters\n\n    * `:eof` - end of file was encountered\n\n    * `{:error, reason}` - other (rare) error condition;\n      for instance, `{:error, :estale}` if reading from an\n      NFS volume\n\n  \"\"\"\n  @spec getn(device, chardata | String.Chars.t(), pos_integer | :eof) :: chardata | nodata\n  def getn(device, prompt, :eof) do\n    getn_eof(map_dev(device), to_chardata(prompt), [])\n  end\n\n  def getn(device, prompt, count) when is_integer(count) and count > 0 do\n    :io.get_chars(map_dev(device), to_chardata(prompt), count)\n  end\n\n  defp getn_eof(device, prompt, acc) do\n    case :io.get_line(device, prompt) do\n      line when is_binary(line) or is_list(line) -> getn_eof(device, ~c\"\", [line | acc])\n      :eof -> wrap_eof(:lists.reverse(acc))\n      other -> other\n    end\n  end\n\n  defp wrap_eof([h | _] = acc) when is_binary(h), do: IO.iodata_to_binary(acc)\n  defp wrap_eof([h | _] = acc) when is_list(h), do: :lists.flatten(acc)\n  defp wrap_eof([]), do: :eof\n\n  @doc ~S\"\"\"\n  Reads a line from the IO `device`.\n\n  It returns:\n\n    * `data` - the characters in the line terminated\n      by a line-feed (LF) or end of file (EOF)\n\n    * `:eof` - end of file was encountered\n\n    * `{:error, reason}` - other (rare) error condition;\n      for instance, `{:error, :estale}` if reading from an\n      NFS volume\n\n  Trivia: `gets` is shorthand for `get string`.\n\n  ## Examples\n\n  To display \"What is your name?\" as a prompt and await user input:\n\n      IO.gets(\"What is your name?\\n\")\n\n  \"\"\"\n  @spec gets(device, chardata | String.Chars.t()) :: chardata | nodata\n  def gets(device \\\\ :stdio, prompt) do\n    :io.get_line(map_dev(device), to_chardata(prompt))\n  end\n\n  @doc \"\"\"\n  Returns a line-based `IO.Stream` on `:stdio`.\n\n  This is equivalent to:\n\n      IO.stream(:stdio, :line)\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec stream() :: Enumerable.t(String.t())\n  def stream, do: stream(:stdio, :line)\n\n  @doc ~S\"\"\"\n  Converts the IO `device` into an `IO.Stream`.\n\n  An `IO.Stream` implements both `Enumerable` and\n  `Collectable`, allowing it to be used for both read\n  and write.\n\n  The `device` is iterated by the given number of characters\n  or line by line if `:line` is given. In case `:line` is given,\n  \"\\r\\n\" is automatically normalized to \"\\n\".\n\n  This reads from the IO as UTF-8. Check out\n  `IO.binstream/2` to handle the IO as a raw binary.\n\n  Note that an IO stream has side effects and every time\n  you go over the stream you may get different results.\n\n  `stream/0` has been introduced in Elixir v1.12.0,\n  while `stream/2` has been available since v1.0.0.\n\n  ## Examples\n\n  Here is an example on how we mimic an echo server\n  from the command line:\n\n      Enum.each(IO.stream(:stdio, :line), &IO.write(&1))\n\n  Another example where you might want to collect a user input\n  every new line and break on an empty line, followed by removing\n  redundant new line characters (`\"\\n\"`):\n\n      IO.stream(:stdio, :line)\n      |> Enum.take_while(&(&1 != \"\\n\"))\n      |> Enum.map(&String.replace(&1, \"\\n\", \"\"))\n\n  \"\"\"\n  @spec stream(device, :line | pos_integer) :: Enumerable.t()\n  def stream(device \\\\ :stdio, line_or_codepoints)\n      when line_or_codepoints == :line\n      when is_integer(line_or_codepoints) and line_or_codepoints > 0 do\n    IO.Stream.__build__(map_dev(device), false, line_or_codepoints)\n  end\n\n  @doc \"\"\"\n  Returns a raw, line-based `IO.Stream` on `:stdio`. The operation is Unicode unsafe.\n\n  This is equivalent to:\n\n      IO.binstream(:stdio, :line)\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec binstream() :: Enumerable.t(binary)\n  def binstream, do: binstream(:stdio, :line)\n\n  @doc ~S\"\"\"\n  Converts the IO `device` into an `IO.Stream`. The operation is Unicode unsafe.\n\n  An `IO.Stream` implements both `Enumerable` and\n  `Collectable`, allowing it to be used for both read\n  and write.\n\n  The `device` is iterated by the given number of bytes or line\n  by line if `:line` is given. In case `:line` is given, \"\\r\\n\"\n  is automatically normalized to \"\\n\". Passing the number of bytes\n  should be the preferred mode for reading non-textual inputs.\n\n  Note that an IO stream has side effects and every time\n  you go over the stream you may get different results.\n\n  This reads from the IO device as a raw binary. Therefore,\n  do not use this function on IO devices in Unicode mode as\n  it will return the wrong result.\n\n  `binstream/0` has been introduced in Elixir v1.12.0,\n  while `binstream/2` has been available since v1.0.0.\n  \"\"\"\n  @spec binstream(device, :line | pos_integer) :: Enumerable.t()\n  def binstream(device \\\\ :stdio, line_or_bytes)\n      when line_or_bytes == :line\n      when is_integer(line_or_bytes) and line_or_bytes > 0 do\n    IO.Stream.__build__(map_dev(device), true, line_or_bytes)\n  end\n\n  @doc \"\"\"\n  Converts chardata into a string.\n\n  For more information about chardata, see the [\"Chardata\"](#module-chardata)\n  section in the module documentation.\n\n  In case the conversion fails, it raises an `UnicodeConversionError`.\n  If a string is given, it returns the string itself.\n\n  ## Examples\n\n      iex> IO.chardata_to_string([0x00E6, 0x00DF])\n      \"æß\"\n\n      iex> IO.chardata_to_string([0x0061, \"bc\"])\n      \"abc\"\n\n      iex> IO.chardata_to_string(\"string\")\n      \"string\"\n\n  \"\"\"\n  @spec chardata_to_string(chardata) :: String.t()\n  def chardata_to_string(chardata)\n\n  def chardata_to_string(string) when is_binary(string) do\n    string\n  end\n\n  def chardata_to_string(list) when is_list(list) do\n    List.to_string(list)\n  end\n\n  @doc \"\"\"\n  Converts IO data into a binary\n\n  The operation is Unicode unsafe.\n\n  Note that this function treats integers in the given IO data as\n  raw bytes and does not perform any kind of encoding conversion.\n  If you want to convert from a charlist to a UTF-8-encoded string,\n  use `chardata_to_string/1` instead. For more information about\n  IO data and chardata, see the [\"IO data\"](#module-io-data) section in the\n  module documentation.\n\n  If this function receives a binary, the same binary is returned.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> bin1 = <<1, 2, 3>>\n      iex> bin2 = <<4, 5>>\n      iex> bin3 = <<6>>\n      iex> IO.iodata_to_binary([bin1, 1, [2, 3, bin2], 4 | bin3])\n      <<1, 2, 3, 1, 2, 3, 4, 5, 4, 6>>\n\n      iex> bin = <<1, 2, 3>>\n      iex> IO.iodata_to_binary(bin)\n      <<1, 2, 3>>\n\n  \"\"\"\n  @spec iodata_to_binary(iodata) :: binary\n  def iodata_to_binary(iodata) do\n    :erlang.iolist_to_binary(iodata)\n  end\n\n  @doc \"\"\"\n  Returns the size of an IO data.\n\n  For more information about IO data, see the [\"IO data\"](#module-io-data)\n  section in the module documentation.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> IO.iodata_length([1, 2 | <<3, 4>>])\n      4\n\n  \"\"\"\n  @spec iodata_length(iodata) :: non_neg_integer\n  def iodata_length(iodata) do\n    :erlang.iolist_size(iodata)\n  end\n\n  @doc \"\"\"\n  Checks if an IO data (the length is zero).\n\n  For more information about IO data, see the [\"IO data\"](#module-io-data)\n  section in the module documentation.\n\n  ## Examples\n\n      iex> IO.iodata_empty?([])\n      true\n      iex> IO.iodata_empty?([\"\"])\n      true\n      iex> IO.iodata_empty?([1, 2 | <<3, 4>>])\n      false\n\n  \"\"\"\n  @doc since: \"1.20.0\"\n  @spec iodata_empty?(iodata) :: boolean\n  def iodata_empty?(\"\"), do: true\n  def iodata_empty?([]), do: true\n  def iodata_empty?([head | tail]), do: iodata_empty?(head) and iodata_empty?(tail)\n  def iodata_empty?(_), do: false\n\n  @doc false\n  def each_stream(device, line_or_codepoints) do\n    case read(device, line_or_codepoints) do\n      :eof ->\n        {:halt, device}\n\n      {:error, reason} ->\n        raise IO.StreamError, reason: reason\n\n      data ->\n        {[data], device}\n    end\n  end\n\n  @doc false\n  def each_binstream(device, line_or_chars) do\n    case binread(device, line_or_chars) do\n      :eof ->\n        {:halt, device}\n\n      {:error, reason} ->\n        raise IO.StreamError, reason: reason\n\n      data ->\n        {[data], device}\n    end\n  end\n\n  @compile {:inline, map_dev: 1, to_chardata: 1}\n\n  # Map the Elixir names for standard IO and error to Erlang names\n  defp map_dev(:stdio), do: :standard_io\n  defp map_dev(:stderr), do: :standard_error\n  defp map_dev(other) when is_atom(other) or is_pid(other) or is_tuple(other), do: other\n\n  defp to_chardata(list) when is_list(list), do: list\n  defp to_chardata(other), do: to_string(other)\nend\n"
  },
  {
    "path": "lib/elixir/lib/json.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefprotocol JSON.Encoder do\n  @moduledoc \"\"\"\n  A protocol for custom JSON encoding of data structures.\n\n  If you have a struct, you can derive the implementation of this protocol\n  by specifying which fields should be encoded to JSON:\n\n      @derive {JSON.Encoder, only: [...]}\n      defstruct ...\n\n  Additionally, you can exclude specific fields using the `:except` option or\n  encode all fields by omitting both options entirely, but these should be used\n  with caution:\n\n      @derive {JSON.Encoder, except: [...]}\n      defstruct ...\n\n      @derive JSON.Encoder\n      defstruct ...\n\n  > #### Leaking Private Information {: .error}\n  >\n  > Prefer using `:only` to avoid accidentally leaking private information when\n  > new fields are added. Other approaches should be used with auction.\n\n  You can also use `Protocol.derive/3` if you don't own the struct that you want\n  to encode to JSON:\n\n      Protocol.derive(JSON.Encoder, NameOfTheStruct, only: [...])\n      Protocol.derive(JSON.Encoder, NameOfTheStruct, except: [...])\n      Protocol.derive(JSON.Encoder, NameOfTheStruct)\n\n  \"\"\"\n\n  @undefined_impl_description \"\"\"\n  the protocol must be explicitly implemented.\n\n  If you have a struct, you can derive the implementation specifying \\\n  which fields should be encoded to JSON:\n\n      @derive {JSON.Encoder, only: [....]}\n      defstruct ...\n\n  It is also possible to encode all fields, although this should be \\\n  used carefully to avoid accidentally leaking private information \\\n  when new fields are added:\n\n      @derive JSON.Encoder\n      defstruct ...\n\n  Finally, if you don't own the struct you want to encode to JSON, \\\n  you may use Protocol.derive/3 placed outside of any module:\n\n      Protocol.derive(JSON.Encoder, NameOfTheStruct, only: [...])\n      Protocol.derive(JSON.Encoder, NameOfTheStruct)\\\n  \"\"\"\n\n  @impl true\n  defmacro __deriving__(module, opts) do\n    fields = module |> Macro.struct_info!(__CALLER__) |> Enum.map(& &1.field)\n    fields = fields_to_encode(fields, opts)\n    vars = Macro.generate_arguments(length(fields), __MODULE__)\n    kv = Enum.zip(fields, vars)\n\n    {io, _prefix} =\n      Enum.flat_map_reduce(kv, ?{, fn {field, value}, prefix ->\n        key = IO.iodata_to_binary([prefix, :json.encode_binary(Atom.to_string(field)), ?:])\n        {[key, quote(do: encoder.(unquote(value), encoder))], ?,}\n      end)\n\n    io = if io == [], do: \"{}\", else: io ++ [?}]\n\n    quote do\n      defimpl JSON.Encoder, for: unquote(module) do\n        def encode(%{unquote_splicing(kv)}, encoder) do\n          unquote(io)\n        end\n      end\n    end\n  end\n\n  defp fields_to_encode(fields, opts) do\n    cond do\n      only = Keyword.get(opts, :only) ->\n        case only -- fields do\n          [] ->\n            only\n\n          error_keys ->\n            raise ArgumentError,\n                  \"unknown struct fields #{inspect(error_keys)} specified in :only. Expected one of: \" <>\n                    \"#{inspect(fields -- [:__struct__])}\"\n        end\n\n      except = Keyword.get(opts, :except) ->\n        case except -- fields do\n          [] ->\n            fields -- [:__struct__ | except]\n\n          error_keys ->\n            raise ArgumentError,\n                  \"unknown struct fields #{inspect(error_keys)} specified in :except. Expected one of: \" <>\n                    \"#{inspect(fields -- [:__struct__])}\"\n        end\n\n      true ->\n        fields -- [:__struct__]\n    end\n  end\n\n  @doc \"\"\"\n  A function invoked to encode the given term to `t:iodata/0`.\n  \"\"\"\n  def encode(term, encoder)\nend\n\ndefimpl JSON.Encoder, for: Atom do\n  def encode(value, encoder) do\n    case value do\n      nil -> \"null\"\n      true -> \"true\"\n      false -> \"false\"\n      _ -> encoder.(Atom.to_string(value), encoder)\n    end\n  end\nend\n\ndefimpl JSON.Encoder, for: BitString do\n  def encode(value, _encoder) do\n    :json.encode_binary(value)\n  end\nend\n\ndefimpl JSON.Encoder, for: List do\n  def encode(value, encoder) do\n    :json.encode_list(value, encoder)\n  end\nend\n\ndefimpl JSON.Encoder, for: Integer do\n  def encode(value, _encoder) do\n    :json.encode_integer(value)\n  end\nend\n\ndefimpl JSON.Encoder, for: Float do\n  def encode(value, _encoder) do\n    :json.encode_float(value)\n  end\nend\n\ndefimpl JSON.Encoder, for: Map do\n  def encode(value, encoder) do\n    case :maps.next(:maps.iterator(value)) do\n      :none ->\n        \"{}\"\n\n      {key, value, iterator} ->\n        [?{, key(key, encoder), ?:, encoder.(value, encoder) | next(iterator, encoder)]\n    end\n  end\n\n  defp next(iterator, encoder) do\n    case :maps.next(iterator) do\n      :none ->\n        \"}\"\n\n      {key, value, iterator} ->\n        [?,, key(key, encoder), ?:, encoder.(value, encoder) | next(iterator, encoder)]\n    end\n  end\n\n  # Erlang supports only numbers, binaries, and atoms as keys,\n  # we support anything that implements the String.Chars protocol.\n  defp key(key, encoder) when is_atom(key), do: encoder.(Atom.to_string(key), encoder)\n  defp key(key, encoder) when is_binary(key), do: encoder.(key, encoder)\n  defp key(key, encoder), do: encoder.(String.Chars.to_string(key), encoder)\nend\n\ndefimpl JSON.Encoder, for: Duration do\n  def encode(value, _encoder) do\n    [?\", Duration.to_iso8601(value), ?\"]\n  end\nend\n\ndefimpl JSON.Encoder, for: Date do\n  def encode(%{calendar: Calendar.ISO} = date, _encoder) do\n    %{year: year, month: month, day: day} = date\n    [?\", Calendar.ISO.date_to_iodata(year, month, day), ?\"]\n  end\n\n  def encode(value, _encoder) do\n    [?\", Date.to_iso8601(value), ?\"]\n  end\nend\n\ndefimpl JSON.Encoder, for: Time do\n  def encode(%{calendar: Calendar.ISO} = time, _encoder) do\n    %{\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    } = time\n\n    [?\", Calendar.ISO.time_to_iodata(hour, minute, second, microsecond), ?\"]\n  end\n\n  def encode(value, _encoder) do\n    [?\", Time.to_iso8601(value), ?\"]\n  end\nend\n\ndefimpl JSON.Encoder, for: NaiveDateTime do\n  def encode(%{calendar: Calendar.ISO} = naive_datetime, _encoder) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    } = naive_datetime\n\n    [\n      ?\",\n      Calendar.ISO.date_to_iodata(year, month, day),\n      ?T,\n      Calendar.ISO.time_to_iodata(hour, minute, second, microsecond),\n      ?\"\n    ]\n  end\n\n  def encode(value, _encoder) do\n    [?\", NaiveDateTime.to_iso8601(value), ?\"]\n  end\nend\n\ndefimpl JSON.Encoder, for: DateTime do\n  def encode(%{calendar: Calendar.ISO} = datetime, _encoder) do\n    %{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      time_zone: time_zone,\n      utc_offset: utc_offset,\n      std_offset: std_offset\n    } = datetime\n\n    [\n      ?\",\n      Calendar.ISO.date_to_iodata(year, month, day),\n      ?T,\n      Calendar.ISO.time_to_iodata(hour, minute, second, microsecond),\n      Calendar.ISO.offset_to_iodata(utc_offset, std_offset, time_zone, :extended),\n      ?\"\n    ]\n  end\n\n  def encode(value, _encoder) do\n    [?\", DateTime.to_iso8601(value), ?\"]\n  end\nend\n\ndefmodule JSON.DecodeError do\n  @moduledoc \"\"\"\n  The exception raised by `JSON.decode!/1`.\n  \"\"\"\n  defexception [:message, :offset, :data]\nend\n\ndefmodule JSON do\n  @moduledoc ~S\"\"\"\n  JSON encoding and decoding.\n\n  Both encoder and decoder fully conform to [RFC 8259](https://tools.ietf.org/html/rfc8259) and\n  [ECMA 404](https://ecma-international.org/publications-and-standards/standards/ecma-404/)\n  standards.\n\n  ## Encoding\n\n  Elixir primitive types are encoded to JSON as follows:\n\n  | **Elixir**                 | **JSON** |\n  |----------------------------|----------|\n  | `integer() \\| float()`     | Number   |\n  | `true \\| false `           | Boolean  |\n  | `nil`                      | Null     |\n  | `binary()`                 | String   |\n  | `atom()`                   | String   |\n  | `list()`                   | Array    |\n  | `%{String.Chars.t() => _}` | Object   |\n\n  You may also implement the `JSON.Encoder` protocol for custom data structures.\n  Some built-in data-structures already derive the `JSON.Encoder` protocol:\n\n  | **Elixir**             | **JSON**        |\n  |------------------------|-----------------|\n  | `Date.t()`             | ISO 8601 string |\n  | `Time.t()`             | ISO 8601 string |\n  | `DateTime.t()`         | ISO 8601 string |\n  | `NaiveDateTime.t()`    | ISO 8601 string |\n  | `Duration.t()`         | ISO 8601 string |\n\n  ## Decoding\n\n  Elixir types are decoded from JSON as follows:\n\n  | **JSON** | **Elixir**             |\n  |----------|------------------------|\n  | Number   | `integer() \\| float()` |\n  | Boolean  | `true \\| false`        |\n  | Null     | `nil`                  |\n  | String   | `binary()`             |\n  | Object   | `%{binary() => _}`     |\n\n  \"\"\"\n\n  @moduledoc since: \"1.18.0\"\n\n  @type encoder :: (term(), encoder() -> iodata())\n\n  @type decode_error_reason ::\n          {:unexpected_end, non_neg_integer()}\n          | {:invalid_byte, non_neg_integer(), byte()}\n          | {:unexpected_sequence, non_neg_integer(), binary()}\n\n  @typedoc \"\"\"\n  Decoders for customizing JSON decoding behavior.\n  \"\"\"\n  @type decoders :: [\n          array_start: (term() -> term()),\n          array_push: (term(), term() -> term()),\n          array_finish: (term(), term() -> {term(), term()}),\n          object_start: (term() -> term()),\n          object_push: (term(), term(), term() -> term()),\n          object_finish: (term(), term() -> {term(), term()}),\n          float: (String.t() -> term()),\n          integer: (String.t() -> term()),\n          string: (String.t() -> term()),\n          null: term()\n        ]\n\n  @doc ~S\"\"\"\n  Decodes the given JSON.\n\n  Returns `{:ok, decoded}` or `{:error, reason}`.\n\n  ## Examples\n\n      iex> JSON.decode(\"[null,123,\\\"string\\\",{\\\"key\\\":\\\"value\\\"}]\")\n      {:ok, [nil, 123, \"string\", %{\"key\" => \"value\"}]}\n\n  ## Error reasons\n\n  The error tuple will have one of the following reasons.\n\n    * `{:unexpected_end, offset}` if `binary` contains incomplete JSON value\n    * `{:invalid_byte, offset, byte}` if `binary` contains unexpected byte or invalid UTF-8 byte\n    * `{:unexpected_sequence, offset, bytes}` if `binary` contains invalid UTF-8 escape\n  \"\"\"\n  @spec decode(binary()) :: {:ok, term()} | {:error, decode_error_reason()}\n  def decode(binary) when is_binary(binary) do\n    with {decoded, :ok, rest} <- decode(binary, :ok, []) do\n      if rest == \"\" do\n        {:ok, decoded}\n      else\n        {:error, {:invalid_byte, byte_size(binary) - byte_size(rest), :binary.at(rest, 0)}}\n      end\n    end\n  end\n\n  @doc ~S\"\"\"\n  Decodes the given JSON with the given decoders.\n\n  Returns `{decoded, acc, rest}` or `{:error, reason}`.\n  See `decode/1` for the error reasons.\n\n  ## Decoders\n\n  All decoders are optional. If not provided, they will fall back to\n  implementations used by the `decode/1` function:\n\n    * for `array_start`: `fn _ -> [] end`\n    * for `array_push`: `fn elem, acc -> [elem | acc] end`\n    * for `array_finish`: `fn acc, old_acc -> {Enum.reverse(acc), old_acc} end`\n    * for `object_start`: `fn _ -> [] end`\n    * for `object_push`: `fn key, value, acc -> [{key, value} | acc] end`\n    * for `object_finish`: `fn acc, old_acc -> {Map.new(acc), old_acc} end`\n    * for `float`: `&String.to_float/1`\n    * for `integer`: `&String.to_integer/1`\n    * for `string`: `&Function.identity/1`\n    * for `null`: the atom `nil`\n\n  For streaming decoding, see Erlang's [`:json`](`:json`) module.\n  \"\"\"\n  @spec decode(binary(), term(), decoders()) ::\n          {term(), term(), binary()} | {:error, decode_error_reason()}\n  def decode(binary, acc, decoders) when is_binary(binary) and is_list(decoders) do\n    decoders = Keyword.put_new(decoders, :null, nil)\n\n    try do\n      :json.decode(binary, acc, Map.new(decoders))\n    catch\n      :error, :unexpected_end ->\n        {:error, {:unexpected_end, byte_size(binary)}}\n\n      :error, {:invalid_byte, byte} ->\n        {:error, {:invalid_byte, offset(__STACKTRACE__), byte}}\n\n      :error, {:unexpected_sequence, bytes} ->\n        {:error, {:unexpected_sequence, offset(__STACKTRACE__), bytes}}\n    end\n  end\n\n  defp offset(stacktrace) do\n    with [{_, _, _, opts} | _] <- stacktrace,\n         %{cause: %{position: position}} <- opts[:error_info] do\n      position\n    else\n      _ -> 0\n    end\n  end\n\n  @doc ~S\"\"\"\n  Decodes the given JSON but raises an exception in case of errors.\n\n  Returns the decoded content. See `decode/1` for possible errors.\n\n  ## Examples\n\n      iex> JSON.decode!(\"[null,123,\\\"string\\\",{\\\"key\\\":\\\"value\\\"}]\")\n      [nil, 123, \"string\", %{\"key\" => \"value\"}]\n  \"\"\"\n  @spec decode!(binary()) :: term()\n  def decode!(binary) when is_binary(binary) do\n    case decode(binary) do\n      {:ok, decoded} ->\n        decoded\n\n      {:error, {:unexpected_end, offset}} ->\n        raise JSON.DecodeError,\n          message: \"unexpected end of JSON binary at position (byte offset) #{offset}\",\n          data: binary,\n          offset: offset\n\n      {:error, {:invalid_byte, offset, byte}} ->\n        raise JSON.DecodeError,\n          message: \"invalid byte #{byte} at position (byte offset) #{offset}\",\n          data: binary,\n          offset: offset\n\n      {:error, {:unexpected_sequence, offset, bytes}} ->\n        raise JSON.DecodeError,\n          message: \"unexpected sequence #{inspect(bytes)} at position (byte offset) #{offset}\",\n          data: binary,\n          offset: offset\n    end\n  end\n\n  @doc ~S\"\"\"\n  Encodes the given term to JSON as a binary.\n\n  The second argument is a function that is recursively\n  invoked to encode a term.\n\n  > #### IO and performance {: .tip}\n  >\n  > If you need to encode data to be sent over the network\n  > or written to the filesystem, consider using the more\n  > efficient `encode_to_iodata!/2`.\n\n  ## Examples\n\n      iex> JSON.encode!([123, \"string\", %{key: \"value\"}])\n      \"[123,\\\"string\\\",{\\\"key\\\":\\\"value\\\"}]\"\n\n  \"\"\"\n  @spec encode!(term(), encoder()) :: binary()\n  def encode!(term, encoder \\\\ &protocol_encode/2) do\n    IO.iodata_to_binary(encoder.(term, encoder))\n  end\n\n  @doc ~S\"\"\"\n  Encodes the given term to JSON as an iodata.\n\n  This is the most efficient format if the JSON is going to be\n  used for IO purposes.\n\n  The second argument is a function that is recursively\n  invoked to encode a term.\n\n  ## Examples\n\n      iex> data = JSON.encode_to_iodata!([123, \"string\", %{key: \"value\"}])\n      iex> IO.iodata_to_binary(data)\n      \"[123,\\\"string\\\",{\\\"key\\\":\\\"value\\\"}]\"\n\n  \"\"\"\n  @spec encode_to_iodata!(term(), encoder()) :: iodata()\n  def encode_to_iodata!(term, encoder \\\\ &protocol_encode/2) do\n    encoder.(term, encoder)\n  end\n\n  @doc \"\"\"\n  This is the default encode implementation passed to `encode!/1`.\n\n  This function is most typically passed as second argument to\n  `encode!/2` and `encode_to_iodata!/2`. The default implementation\n  is an optimized dispatch to the `JSON.Encoder` protocol.\n  \"\"\"\n  @spec protocol_encode(term(), encoder()) :: iodata()\n  def protocol_encode(value, encoder) when is_atom(value) do\n    case value do\n      nil -> \"null\"\n      true -> \"true\"\n      false -> \"false\"\n      _ -> encoder.(Atom.to_string(value), encoder)\n    end\n  end\n\n  def protocol_encode(value, _encoder) when is_binary(value),\n    do: :json.encode_binary(value)\n\n  def protocol_encode(value, _encoder) when is_integer(value),\n    do: :json.encode_integer(value)\n\n  def protocol_encode(value, _encoder) when is_float(value),\n    do: :json.encode_float(value)\n\n  def protocol_encode(value, encoder) when is_list(value),\n    do: :json.encode_list(value, encoder)\n\n  def protocol_encode(%{} = value, encoder) when not is_map_key(value, :__struct__),\n    do: JSON.Encoder.Map.encode(value, encoder)\n\n  def protocol_encode(value, encoder),\n    do: JSON.Encoder.encode(value, encoder)\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel/cli.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Kernel.CLI do\n  @moduledoc false\n\n  @compile {:no_warn_undefined, [Logger, IEx]}\n\n  @blank_config %{\n    commands: [],\n    output: \".\",\n    compile: [],\n    no_halt: false,\n    compiler_options: [],\n    warnings_as_errors: false,\n    errors: [],\n    verbose_compile: false,\n    profile: nil,\n    pry: false,\n    mode: :elixir\n  }\n\n  @standalone_opts [~c\"-h\", ~c\"--help\", ~c\"--short-version\"]\n\n  @doc \"\"\"\n  This is the API invoked by Elixir boot process.\n  \"\"\"\n  def main(argv) do\n    {config, argv} = parse_argv(argv)\n    System.argv(Enum.map(argv, &IO.chardata_to_string/1))\n    System.no_halt(config.no_halt)\n\n    if config.pry do\n      Application.put_env(:elixir, :dbg_callback, {IEx.Pry, :dbg, []})\n    end\n\n    fun = fn _ ->\n      errors = process_commands(config)\n\n      if errors != [] do\n        Enum.each(errors, &IO.puts(:stderr, &1))\n        System.halt(1)\n      end\n    end\n\n    run(fun)\n  end\n\n  @doc \"\"\"\n  Runs the given function by catching any failure\n  and printing them to stdout. `at_exit` hooks are\n  also invoked before exiting.\n\n  This function is used by Elixir's CLI and also\n  by escripts generated by Elixir.\n  \"\"\"\n  def run(fun) do\n    {ok_or_shutdown, status} = exec_fun(fun, {:ok, 0})\n\n    if ok_or_shutdown == :shutdown or not System.no_halt() do\n      {_, status} = at_exit({ok_or_shutdown, status})\n\n      # Ensure Logger messages are flushed before halting\n      if Code.loaded?(Logger) do\n        Logger.flush()\n      end\n\n      System.halt(status)\n    end\n  end\n\n  @doc \"\"\"\n  Parses the CLI arguments. Made public for testing.\n  \"\"\"\n  def parse_argv(argv) do\n    parse_argv(argv, @blank_config)\n  end\n\n  @doc \"\"\"\n  Process CLI commands. Made public for testing.\n  \"\"\"\n  def process_commands(config) do\n    commands =\n      case config do\n        %{mode: :elixirc, compile: compile, commands: commands} ->\n          [{:compile, compile} | commands]\n\n        %{commands: commands} ->\n          commands\n      end\n\n    results = Enum.map(Enum.reverse(commands), &process_command(&1, config))\n    errors = for {:error, msg} <- results, do: msg\n    Enum.reverse(config.errors, errors)\n  end\n\n  @doc \"\"\"\n  Shared helper for error formatting on CLI tools.\n  \"\"\"\n  def format_error(kind, reason, stacktrace) do\n    {blamed, stacktrace} = Exception.blame(kind, reason, stacktrace)\n\n    iodata =\n      case blamed do\n        %FunctionClauseError{} ->\n          formatted = Exception.format_banner(kind, reason, stacktrace)\n          padded_blame = pad(FunctionClauseError.blame(blamed, &inspect/1, &blame_match/1))\n          [formatted, padded_blame]\n\n        _ ->\n          Exception.format_banner(kind, blamed, stacktrace)\n      end\n\n    [iodata, ?\\n, Exception.format_stacktrace(prune_stacktrace(stacktrace))]\n  end\n\n  @doc \"\"\"\n  Function invoked across nodes for `--rpc-eval`.\n  \"\"\"\n  def rpc_eval(expr) do\n    wrapper(fn -> Code.eval_string(expr) end)\n  catch\n    kind, reason -> {kind, reason, __STACKTRACE__}\n  end\n\n  ## Helpers\n\n  defp at_exit(res) do\n    hooks = :elixir_config.get_and_put(:at_exit, [])\n    res = Enum.reduce(hooks, res, &exec_fun/2)\n    if hooks == [], do: res, else: at_exit(res)\n  end\n\n  defp exec_fun(fun, res) when is_function(fun, 1) and is_tuple(res) do\n    parent = self()\n\n    {pid, ref} =\n      spawn_monitor(fn ->\n        try do\n          fun.(elem(res, 1))\n        catch\n          :exit, {:shutdown, int} when is_integer(int) ->\n            send(parent, {self(), {:shutdown, int}})\n            exit({:shutdown, int})\n\n          :exit, reason\n          when reason == :normal\n          when reason == :shutdown\n          when tuple_size(reason) == 2 and elem(reason, 0) == :shutdown ->\n            send(parent, {self(), {:shutdown, 0}})\n            exit(reason)\n\n          kind, reason ->\n            print_error(kind, reason, __STACKTRACE__)\n            send(parent, {self(), {:shutdown, 1}})\n            exit(to_exit(kind, reason, __STACKTRACE__))\n        else\n          _ ->\n            send(parent, {self(), res})\n        end\n      end)\n\n    receive do\n      {^pid, res} ->\n        :erlang.demonitor(ref, [:flush])\n        res\n\n      {:DOWN, ^ref, _, _, other} ->\n        print_error({:EXIT, pid}, other, [])\n        {:shutdown, 1}\n    end\n  end\n\n  defp to_exit(:throw, reason, stack), do: {{:nocatch, reason}, stack}\n  defp to_exit(:error, reason, stack), do: {reason, stack}\n  defp to_exit(:exit, reason, _stack), do: reason\n\n  ## Error handling\n\n  defp print_error(kind, reason, stacktrace) do\n    IO.write(:stderr, format_error(kind, reason, stacktrace))\n  end\n\n  defp blame_match(%{match?: true, node: node}), do: blame_ansi(:normal, \"+\", node)\n  defp blame_match(%{match?: false, node: node}), do: blame_ansi(:red, \"-\", node)\n\n  defp blame_ansi(color, no_ansi, node) do\n    if IO.ANSI.enabled?() do\n      [color | Macro.to_string(node)]\n      |> IO.ANSI.format(true)\n      |> IO.iodata_to_binary()\n    else\n      no_ansi <> Macro.to_string(node) <> no_ansi\n    end\n  end\n\n  defp pad(string) do\n    \"    \" <> String.replace(string, \"\\n\", \"\\n    \")\n  end\n\n  @elixir_internals [:elixir, :elixir_aliases, :elixir_clauses, :elixir_compiler, :elixir_def] ++\n                      [:elixir_def, :elixir_dispatch, :elixir_expand, :elixir_lexical] ++\n                      [:elixir_map, :elixir_module] ++\n                      [:elixir_erl, :elixir_erl_clauses, :elixir_erl_compiler, :elixir_erl_pass] ++\n                      [Kernel.ErrorHandler, Module.ParallelChecker]\n\n  defp prune_stacktrace([{mod, _, _, _} | t]) when mod in @elixir_internals do\n    prune_stacktrace(t)\n  end\n\n  defp prune_stacktrace([{__MODULE__, :wrapper, 1, _} | _]) do\n    []\n  end\n\n  defp prune_stacktrace([h | t]) do\n    [h | prune_stacktrace(t)]\n  end\n\n  defp prune_stacktrace([]) do\n    []\n  end\n\n  # Process init options\n\n  defp parse_argv([~c\"--\" | t], config) do\n    {config, t}\n  end\n\n  defp parse_argv([~c\"+elixirc\" | t], config) do\n    parse_argv(t, %{config | mode: :elixirc})\n  end\n\n  defp parse_argv([~c\"+iex\" | t], config) do\n    parse_argv(t, %{config | mode: :iex})\n  end\n\n  defp parse_argv([~c\"-S\", h | t], config) do\n    {%{config | commands: [{:script, h} | config.commands]}, t}\n  end\n\n  defp parse_argv([opt | _], _config) when opt in @standalone_opts do\n    halt_standalone(opt)\n  end\n\n  defp parse_argv([opt | t], config) when opt in [~c\"-v\", ~c\"--version\"] do\n    if config.mode == :iex do\n      IO.puts(\"IEx \" <> System.build_info()[:build])\n    else\n      IO.puts(:erlang.system_info(:system_version))\n      IO.puts(\"Elixir \" <> System.build_info()[:build])\n    end\n\n    if t != [] do\n      halt_standalone(opt)\n    else\n      System.halt(0)\n    end\n  end\n\n  defp parse_argv([~c\"-pa\", h | t], config) do\n    paths = expand_code_path(h)\n    Code.prepend_paths(paths)\n    parse_argv(t, config)\n  end\n\n  defp parse_argv([~c\"-pz\", h | t], config) do\n    paths = expand_code_path(h)\n    Code.append_paths(paths)\n    parse_argv(t, config)\n  end\n\n  defp parse_argv([~c\"--no-halt\" | t], config) do\n    parse_argv(t, %{config | no_halt: true})\n  end\n\n  defp parse_argv([~c\"-e\", h | t], config) do\n    parse_argv(t, %{config | commands: [{:eval, h} | config.commands]})\n  end\n\n  defp parse_argv([~c\"--eval\", h | t], config) do\n    parse_argv(t, %{config | commands: [{:eval, h} | config.commands]})\n  end\n\n  defp parse_argv([~c\"--rpc-eval\", node, h | t], config) do\n    node = append_hostname(node)\n    parse_argv(t, %{config | commands: [{:rpc_eval, node, h} | config.commands]})\n  end\n\n  defp parse_argv([~c\"--rpc-eval\" | _], config) do\n    new_config = %{config | errors: [\"--rpc-eval : wrong number of arguments\" | config.errors]}\n    {new_config, []}\n  end\n\n  defp parse_argv([~c\"-r\", h | t], config) do\n    parse_argv(t, %{config | commands: [{:require, h} | config.commands]})\n  end\n\n  defp parse_argv([~c\"-pr\", h | t], config) do\n    parse_argv(t, %{config | commands: [{:parallel_require, h} | config.commands]})\n  end\n\n  defp parse_argv([~c\"--color\" | t], config) do\n    Application.put_env(:elixir, :ansi_enabled, true)\n    parse_argv(t, config)\n  end\n\n  defp parse_argv([~c\"--no-color\" | t], config) do\n    Application.put_env(:elixir, :ansi_enabled, false)\n    parse_argv(t, config)\n  end\n\n  ## Compiler\n\n  defp parse_argv([~c\"-o\", h | t], %{mode: :elixirc} = config) do\n    parse_argv(t, %{config | output: h})\n  end\n\n  defp parse_argv([~c\"--no-docs\" | t], %{mode: :elixirc} = config) do\n    parse_argv(t, %{config | compiler_options: [{:docs, false} | config.compiler_options]})\n  end\n\n  defp parse_argv([~c\"--no-debug-info\" | t], %{mode: :elixirc} = config) do\n    compiler_options = [{:debug_info, false} | config.compiler_options]\n    parse_argv(t, %{config | compiler_options: compiler_options})\n  end\n\n  defp parse_argv([~c\"--ignore-module-conflict\" | t], %{mode: :elixirc} = config) do\n    compiler_options = [{:ignore_module_conflict, true} | config.compiler_options]\n    parse_argv(t, %{config | compiler_options: compiler_options})\n  end\n\n  defp parse_argv([~c\"--warnings-as-errors\" | t], %{mode: :elixirc} = config) do\n    parse_argv(t, %{config | warnings_as_errors: true})\n  end\n\n  defp parse_argv([~c\"--verbose\" | t], %{mode: :elixirc} = config) do\n    parse_argv(t, %{config | verbose_compile: true})\n  end\n\n  defp parse_argv([~c\"--profile\", \"time\" | t], %{mode: :elixirc} = config) do\n    parse_argv(t, %{config | profile: :time})\n  end\n\n  ## IEx\n\n  defp parse_argv([~c\"--dbg\", backend | t], %{mode: :iex} = config) do\n    case backend do\n      ~c\"pry\" ->\n        parse_argv(t, %{config | pry: true})\n\n      ~c\"kernel\" ->\n        parse_argv(t, %{config | pry: false})\n\n      _ ->\n        error = \"--dbg : Unknown dbg backend #{inspect(backend)}\"\n        parse_argv(t, %{config | errors: [error | config.errors]})\n    end\n  end\n\n  defp parse_argv([~c\"--dot-iex\", _ | t], %{mode: :iex} = config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--remsh\", _ | t], %{mode: :iex} = config), do: parse_argv(t, config)\n\n  ## Erlang flags\n\n  defp parse_argv([~c\"--boot\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--boot-var\", _, _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--cookie\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--hidden\" | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--erl-config\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--logger-otp-reports\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--logger-sasl-reports\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--name\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--sname\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--vm-args\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--erl\", _ | t], config), do: parse_argv(t, config)\n  defp parse_argv([~c\"--pipe-to\", _, _ | t], config), do: parse_argv(t, config)\n\n  ## Fallback\n\n  defp parse_argv([h | t], %{mode: :elixirc} = config) do\n    pattern = if File.dir?(h), do: \"#{h}/**/*.ex\", else: h\n    parse_argv(t, %{config | compile: [pattern | config.compile]})\n  end\n\n  defp parse_argv([h | t], config) do\n    if List.keymember?(config.commands, :eval, 0) do\n      {config, [h | t]}\n    else\n      {%{config | commands: [{:file, h} | config.commands]}, t}\n    end\n  end\n\n  defp parse_argv([], config) do\n    {config, []}\n  end\n\n  # Parse helpers\n\n  defp halt_standalone(opt) do\n    IO.puts(:stderr, \"#{opt} : Standalone options can't be combined with other options\")\n    System.halt(1)\n  end\n\n  defp append_hostname(node) do\n    with false <- ?@ in node,\n         [_ | _] = suffix <- :string.find(Atom.to_charlist(:net_kernel.nodename()), ~c\"@\") do\n      node ++ suffix\n    else\n      _ -> node\n    end\n  end\n\n  defp expand_code_path(path) do\n    path = Path.expand(path)\n\n    case Path.wildcard(path) do\n      [] -> [to_charlist(path)]\n      list -> Enum.map(list, &to_charlist/1)\n    end\n  end\n\n  # Process commands\n\n  defp process_command({:eval, expr}, _config) when is_list(expr) do\n    wrapper(fn -> Code.eval_string(expr, []) end)\n  end\n\n  defp process_command({:rpc_eval, node, expr}, _config) when is_list(expr) do\n    node = List.to_atom(node)\n\n    # Explicitly connect the node in case the rpc node was started with --sname/--name undefined.\n    _ = :net_kernel.connect_node(node)\n\n    try do\n      :erpc.call(node, __MODULE__, :rpc_eval, [expr])\n    catch\n      :error, {:erpc, reason} ->\n        if reason == :noconnection and :net_kernel.nodename() == :ignored do\n          {:error,\n           \"--rpc-eval : Cannot run --rpc-eval if the node is not alive (set --name or --sname)\"}\n        else\n          {:error, \"--rpc-eval : RPC failed with reason #{inspect(reason)}\"}\n        end\n\n      :exit, {kind, exit} when kind in [:exception, :signal] ->\n        Process.exit(self(), exit)\n    else\n      :ok -> :ok\n      {kind, reason, stack} -> :erlang.raise(kind, reason, stack)\n    end\n  end\n\n  defp process_command({:script, file}, _config) when is_list(file) do\n    if exec = find_elixir_executable(file) do\n      wrapper(fn -> Code.require_file(IO.chardata_to_string(exec)) end)\n    else\n      {:error, \"-S : Could not find executable #{file}\"}\n    end\n  end\n\n  defp process_command({:file, file}, _config) when is_list(file) do\n    if File.regular?(file) do\n      wrapper(fn -> Code.require_file(IO.chardata_to_string(file)) end)\n    else\n      {:error, \"No file named #{file}\"}\n    end\n  end\n\n  defp process_command({:require, pattern}, _config) when is_list(pattern) do\n    files = filter_patterns(pattern)\n\n    if files != [] do\n      wrapper(fn -> Enum.map(files, &Code.require_file/1) end)\n    else\n      {:error, \"-r : No files matched pattern #{pattern}\"}\n    end\n  end\n\n  defp process_command({:parallel_require, pattern}, _config) when is_list(pattern) do\n    files = filter_patterns(pattern)\n\n    if files != [] do\n      wrapper(fn ->\n        case Kernel.ParallelCompiler.require(files, return_diagnostics: true) do\n          {:ok, _, _} -> :ok\n          {:error, _, _} -> exit({:shutdown, 1})\n        end\n      end)\n    else\n      {:error, \"-pr : No files matched pattern #{pattern}\"}\n    end\n  end\n\n  defp process_command({:compile, patterns}, config) do\n    # If ensuring the dir returns an error no files will be found.\n    _ = :filelib.ensure_path(config.output)\n\n    case filter_multiple_patterns(patterns) do\n      {:ok, []} ->\n        {:error, \"No files matched provided patterns\"}\n\n      {:ok, files} ->\n        wrapper(fn ->\n          Code.compiler_options(config.compiler_options)\n\n          verbose_opts =\n            if config.verbose_compile do\n              [each_file: &IO.puts(\"Compiling #{Path.relative_to_cwd(&1)}\")]\n            else\n              [\n                each_long_compilation:\n                  &IO.puts(\"Compiling #{Path.relative_to_cwd(&1)} (it's taking more than 10s)\")\n              ]\n            end\n\n          output = IO.chardata_to_string(config.output)\n\n          opts =\n            verbose_opts ++\n              [\n                profile: config.profile,\n                warnings_as_errors: config.warnings_as_errors,\n                return_diagnostics: true\n              ]\n\n          case Kernel.ParallelCompiler.compile_to_path(files, output, opts) do\n            {:ok, _, _} -> :ok\n            {:error, _, _} -> exit({:shutdown, 1})\n          end\n        end)\n\n      {:missing, missing} ->\n        {:error, \"No files matched pattern(s) #{Enum.join(missing, \",\")}\"}\n    end\n  end\n\n  defp filter_patterns(pattern) do\n    pattern\n    |> Path.expand()\n    |> Path.wildcard()\n    |> :lists.usort()\n    |> Enum.filter(&File.regular?/1)\n  end\n\n  defp filter_multiple_patterns(patterns) do\n    {files, missing} =\n      Enum.reduce(patterns, {[], []}, fn pattern, {files, missing} ->\n        case filter_patterns(pattern) do\n          [] -> {files, [pattern | missing]}\n          match -> {match ++ files, missing}\n        end\n      end)\n\n    case missing do\n      [] -> {:ok, :lists.usort(files)}\n      _ -> {:missing, :lists.usort(missing)}\n    end\n  end\n\n  defp wrapper(fun) do\n    _ = fun.()\n    :ok\n  end\n\n  defp find_elixir_executable(file) do\n    if exec = :os.find_executable(file) do\n      # If we are on Windows, the executable is going to be\n      # a .bat file that must be in the same directory as\n      # the actual Elixir executable.\n      case :os.type() do\n        {:win32, _} ->\n          base = :filename.rootname(exec)\n          if File.regular?(base), do: base, else: exec\n\n        _ ->\n          exec\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel/error_handler.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Implement error_handler pattern for Erlang\n# which is integrated with Kernel.ParallelCompiler\ndefmodule Kernel.ErrorHandler do\n  @moduledoc false\n\n  @spec undefined_function(module, atom, list) :: term\n  def undefined_function(module, fun, args) do\n    ensure_loaded(module) or ensure_compiled(module, :module, :raise, nil)\n    :error_handler.undefined_function(module, fun, args)\n  end\n\n  @spec undefined_lambda(module, fun, list) :: term\n  def undefined_lambda(module, fun, args) do\n    ensure_loaded(module) or ensure_compiled(module, :module, :raise, nil)\n    :error_handler.undefined_lambda(module, fun, args)\n  end\n\n  @spec ensure_loaded(module) :: boolean\n  def ensure_loaded(module) do\n    case :code.ensure_loaded(module) do\n      {:module, _} -> true\n      {:error, _} -> false\n    end\n  end\n\n  @spec ensure_compiled(module, atom, atom, nil | integer()) :: :found | :not_found | :deadlock\n  # Never wait on nil because it should never be defined.\n  def ensure_compiled(nil, _kind, _deadlock, _position) do\n    :not_found\n  end\n\n  def ensure_compiled(module, kind, deadlock, position) do\n    {compiler_pid, file_pid} = :erlang.get(:elixir_compiler_info)\n    ref = :erlang.make_ref()\n    modules = :elixir_module.compiler_modules()\n\n    send(\n      compiler_pid,\n      {:waiting, kind, self(), ref, file_pid, position, module, modules, deadlock}\n    )\n\n    :erlang.garbage_collect(self())\n\n    receive do\n      {^ref, {:loading, pid}} ->\n        ref = :erlang.monitor(:process, pid)\n\n        receive do\n          {:DOWN, ^ref, _, _, _} -> :found\n        end\n\n      {^ref, value} ->\n        value\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel/lexical_tracker.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# This is an Elixir module responsible for tracking references\n# to modules, remote dispatches, and the usage of\n# aliases/imports/requires in the Elixir scope.\n#\n# Note that since this is required for bootstrap, we can't use\n# any of the `GenServer.Behaviour` conveniences.\ndefmodule Kernel.LexicalTracker do\n  @moduledoc false\n  @timeout :infinity\n  @behaviour :gen_server\n  @warn_key 0\n\n  @doc \"\"\"\n  Returns all references in this lexical scope.\n  \"\"\"\n  def references(pid) do\n    :gen_server.call(pid, :references, @timeout)\n  end\n\n  @doc \"\"\"\n  Invoked during module expansion to annotate a require\n  must be warned if unused.\n  \"\"\"\n  def warn_require(pid, meta, module, alias) do\n    :gen_server.cast(pid, {:warn_require, module, meta, alias})\n    module\n  end\n\n  @doc \"\"\"\n  Invoked during module expansion to annotate an alias\n  must be warned if unused.\n  \"\"\"\n  def warn_alias(pid, meta, alias, module) do\n    :gen_server.cast(pid, {:warn_alias, alias, meta})\n    module\n  end\n\n  @doc \"\"\"\n  Invoked during module expansion to annotate an import\n  must be warned if unused.\n  \"\"\"\n  def warn_import(pid, module) do\n    :gen_server.cast(pid, {:warn_import, module})\n    module\n  end\n\n  # Internal API\n\n  # Starts the tracker and returns its PID.\n  @doc false\n  def start_link() do\n    :gen_server.start_link(__MODULE__, :ok, [])\n  end\n\n  @doc false\n  def stop(pid) do\n    :gen_server.call(pid, :stop)\n  end\n\n  @doc false\n  def add_export(pid, module) when is_atom(module) do\n    :gen_server.cast(pid, {:add_export, module})\n  end\n\n  @doc false\n  def add_require(pid, module, meta) when is_atom(module) do\n    :gen_server.cast(pid, {:add_require, module, meta})\n  end\n\n  @doc false\n  def add_import(pid, module, fas, meta, warn) when is_atom(module) do\n    :gen_server.cast(pid, {:add_import, module, fas, meta, warn})\n  end\n\n  @doc false\n  def remote_dispatch(pid, module, mode) when is_atom(module) do\n    :gen_server.cast(pid, {:remote_dispatch, module, mode})\n  end\n\n  @doc false\n  def import_dispatch(pid, module, fa, mode) when is_atom(module) do\n    :gen_server.cast(pid, {:import_dispatch, module, fa, mode})\n  end\n\n  @doc false\n  def alias_dispatch(pid, module) when is_atom(module) do\n    :gen_server.cast(pid, {:alias_dispatch, module})\n  end\n\n  @doc false\n  def import_quoted(pid, module, function, arities) when is_atom(module) do\n    :gen_server.cast(pid, {:import_quoted, module, function, arities})\n  end\n\n  @doc false\n  def add_compile_env(pid, app, path, return) do\n    :gen_server.cast(pid, {:compile_env, app, path, return})\n  end\n\n  @doc false\n  def set_file(pid, file) do\n    :gen_server.cast(pid, {:set_file, file})\n  end\n\n  @doc false\n  def reset_file(pid) do\n    :gen_server.cast(pid, :reset_file)\n  end\n\n  @doc false\n  def write_cache(pid, value) do\n    key = :erlang.unique_integer()\n    :gen_server.cast(pid, {:write_cache, key, value})\n    key\n  end\n\n  @doc false\n  def read_cache(pid, key) do\n    :gen_server.call(pid, {:read_cache, key}, @timeout)\n  end\n\n  @doc false\n  def collect_unused_imports(pid) do\n    :gen_server.call(pid, :unused_imports, @timeout)\n  end\n\n  @doc false\n  def collect_unused_aliases(pid) do\n    :gen_server.call(pid, :unused_aliases, @timeout)\n  end\n\n  @doc false\n  def collect_unused_requires(pid) do\n    :gen_server.call(pid, :unused_requires, @timeout)\n  end\n\n  # Callbacks\n\n  def init(:ok) do\n    state = %{\n      aliases: %{},\n      imports: %{},\n      requires: %{},\n      references: %{},\n      exports: %{},\n      cache: %{},\n      compile_env: :ordsets.new(),\n      file: nil\n    }\n\n    {:ok, state}\n  end\n\n  @doc false\n  def handle_call(:unused_aliases, _from, state) do\n    aliases = for {alias, meta} when is_list(meta) <- state.aliases, do: {alias, meta}\n    {:reply, Enum.sort(aliases), state}\n  end\n\n  def handle_call(:unused_imports, _from, state) do\n    imports =\n      for {module, %{@warn_key => _} = map} <- state.imports do\n        {module, Map.delete(map, @warn_key)}\n      end\n\n    {:reply, Enum.sort(imports), state}\n  end\n\n  def handle_call(:unused_requires, _from, state) do\n    %{references: references, aliases: aliases} = state\n\n    unused_requires =\n      for {module, {meta, alias}} <- state.requires,\n          Map.get(references, module) != :compile do\n        {module, meta, alias, Map.get(aliases, alias) == :used}\n      end\n\n    {:reply, Enum.sort(unused_requires), state}\n  end\n\n  def handle_call(:references, _from, state) do\n    {compile, runtime} = partition(Map.to_list(state.references), [], [])\n    {:reply, {compile, Map.keys(state.exports), runtime, state.compile_env}, state}\n  end\n\n  def handle_call({:read_cache, key}, _from, %{cache: cache} = state) do\n    {:reply, Map.get(cache, key), state}\n  end\n\n  def handle_call(:stop, _from, state) do\n    {:stop, :normal, :ok, state}\n  end\n\n  def handle_cast({:write_cache, key, value}, %{cache: cache} = state) do\n    {:noreply, %{state | cache: Map.put(cache, key, value)}}\n  end\n\n  def handle_cast({:remote_dispatch, module, mode}, state) do\n    references = add_reference(state.references, module, mode)\n    {:noreply, %{state | references: references}}\n  end\n\n  def handle_cast({:import_dispatch, module, {function, arity}, mode}, state) do\n    %{imports: imports, references: references} = state\n\n    imports =\n      case imports do\n        %{^module => modules_and_fas} ->\n          modules_and_fas\n          |> Map.delete(module)\n          |> Map.delete({function, arity})\n          |> then(&Map.put(imports, module, &1))\n\n        %{} ->\n          imports\n      end\n\n    references = add_reference(references, module, mode)\n    {:noreply, %{state | imports: imports, references: references}}\n  end\n\n  def handle_cast({:alias_dispatch, module}, state) do\n    {:noreply, put_in(state.aliases[module], :used)}\n  end\n\n  def handle_cast({:import_quoted, module, function, arities}, state) do\n    %{imports: imports} = state\n\n    imports =\n      case imports do\n        %{^module => modules_and_fas} ->\n          arities\n          |> Enum.reduce(modules_and_fas, &Map.delete(&2, {function, &1}))\n          |> Map.delete(module)\n          |> then(&Map.put(imports, module, &1))\n\n        %{} ->\n          imports\n      end\n\n    {:noreply, %{state | imports: imports}}\n  end\n\n  def handle_cast({:set_file, file}, state) do\n    {:noreply, %{state | file: file}}\n  end\n\n  def handle_cast(:reset_file, state) do\n    {:noreply, %{state | file: nil}}\n  end\n\n  def handle_cast({:compile_env, app, path, return}, state) do\n    {:noreply, update_in(state.compile_env, &:ordsets.add_element({app, path, return}, &1))}\n  end\n\n  def handle_cast({:add_export, module}, state) do\n    {:noreply, put_in(state.exports[module], true)}\n  end\n\n  def handle_cast({:add_import, module, fas, meta, warn}, state) do\n    keys = if warn, do: [@warn_key, module | fas], else: [module | fas]\n    {:noreply, put_in(state.imports[module], Map.from_keys(keys, meta))}\n  end\n\n  def handle_cast({:warn_alias, alias, meta}, %{aliases: aliases} = state) do\n    case aliases do\n      %{^alias => :used} -> {:noreply, state}\n      %{} -> {:noreply, %{state | aliases: Map.put(aliases, alias, meta)}}\n    end\n  end\n\n  def handle_cast({:warn_import, module}, state) do\n    {:noreply, put_in(state.imports[module][@warn_key], true)}\n  end\n\n  def handle_cast({:warn_require, module, meta, alias}, state) do\n    {:noreply, put_in(state.requires[module], {meta, alias})}\n  end\n\n  @doc false\n  def handle_info(_msg, state) do\n    {:noreply, state}\n  end\n\n  @doc false\n  def terminate(_reason, _state) do\n    :ok\n  end\n\n  @doc false\n  def code_change(_old, state, _extra) do\n    {:ok, state}\n  end\n\n  defp partition([{remote, :compile} | t], compile, runtime),\n    do: partition(t, [remote | compile], runtime)\n\n  defp partition([{remote, :runtime} | t], compile, runtime),\n    do: partition(t, compile, [remote | runtime])\n\n  defp partition([], compile, runtime), do: {compile, runtime}\n\n  # Callbacks helpers\n\n  defp add_reference(references, module, :compile) when is_atom(module),\n    do: Map.put(references, module, :compile)\n\n  defp add_reference(references, module, :runtime) when is_atom(module) do\n    case references do\n      %{^module => _} -> references\n      %{} -> Map.put(references, module, :runtime)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel/parallel_compiler.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Kernel.ParallelCompiler do\n  @moduledoc \"\"\"\n  A module responsible for compiling and requiring files in parallel.\n  \"\"\"\n\n  @type info :: %{\n          runtime_warnings: [Code.diagnostic(:warning)],\n          compile_warnings: [Code.diagnostic(:warning)]\n        }\n\n  # Deprecated types\n  @type warning() :: {file :: Path.t(), Code.position(), message :: String.t()}\n  @type error() :: {file :: Path.t(), Code.position(), message :: String.t()}\n\n  @typedoc \"\"\"\n  Options for parallel compilation functions.\n  \"\"\"\n  @type compile_opts :: [\n          after_compile: (-> term()),\n          each_file: (Path.t() -> term()),\n          each_long_compilation: (Path.t() -> term()) | (Path.t(), pid() -> term()),\n          each_long_verification: (module() -> term()) | (module(), pid() -> term()),\n          each_module: (Path.t(), module(), binary() -> term()),\n          each_cycle: ([module()], [Code.diagnostic(:warning)] ->\n                         {:compile, [module()], [Code.diagnostic(:warning)]}\n                         | {:runtime, [module()], [Code.diagnostic(:warning)]}),\n          long_compilation_threshold: pos_integer(),\n          long_verification_threshold: pos_integer(),\n          verification: boolean(),\n          profile: :time,\n          dest: Path.t(),\n          beam_timestamp: term(),\n          return_diagnostics: boolean(),\n          max_concurrency: pos_integer(),\n          purge_compiler_modules: boolean()\n        ]\n\n  @typedoc \"\"\"\n  Options for requiring files in parallel.\n  \"\"\"\n  @type require_opts :: [\n          each_file: (Path.t() -> term()),\n          each_module: (Path.t(), module(), binary() -> term()),\n          max_concurrency: pos_integer(),\n          return_diagnostics: boolean()\n        ]\n\n  @doc \"\"\"\n  Starts a task for parallel compilation.\n  \"\"\"\n  # TODO: Remove me on Elixir 2.0\n  @deprecated \"Use `pmap/2` instead\"\n  def async(fun) when is_function(fun, 0) do\n    {ref, task} = inner_async(fun)\n    send(task.pid, ref)\n    task\n  end\n\n  defp inner_async(fun) do\n    case :erlang.get(:elixir_compiler_info) do\n      {compiler_pid, file_pid} ->\n        ref = make_ref()\n        file = :erlang.get(:elixir_compiler_file)\n        dest = :erlang.get(:elixir_compiler_dest)\n\n        {:error_handler, error_handler} = :erlang.process_info(self(), :error_handler)\n        {_parent, cache} = Module.ParallelChecker.get()\n\n        task =\n          Task.async(fn ->\n            Module.ParallelChecker.put(compiler_pid, cache)\n            :erlang.put(:elixir_compiler_info, {compiler_pid, file_pid})\n            :erlang.put(:elixir_compiler_file, file)\n            dest != :undefined and :erlang.put(:elixir_compiler_dest, dest)\n            :erlang.process_flag(:error_handler, error_handler)\n\n            receive do\n              ^ref -> fun.()\n            end\n          end)\n\n        send(compiler_pid, {:async, task.pid})\n        {ref, task}\n\n      :undefined ->\n        raise ArgumentError,\n              \"cannot spawn parallel compiler task because \" <>\n                \"the current file is not being compiled/required\"\n    end\n  end\n\n  @doc \"\"\"\n  Perform parallel compilation of `collection` with `fun`.\n\n  If you have a file that needs to compile other modules in parallel,\n  the spawned processes need to be aware of the compiler environment.\n  This function allows a developer to perform such tasks.\n  \"\"\"\n  @doc since: \"1.16.0\"\n  def pmap(collection, fun) when is_function(fun, 1) do\n    ref = make_ref()\n\n    # We spawn a series of tasks for parallel processing.\n    # The tasks are waiting until we give the go ahead.\n    refs_tasks =\n      Enum.map(collection, fn item ->\n        inner_async(fn -> fun.(item) end)\n      end)\n\n    # Notify the compiler we are waiting on the tasks.\n    {compiler_pid, file_pid} = :erlang.get(:elixir_compiler_info)\n    defining = :elixir_module.compiler_modules()\n    on = Enum.map(refs_tasks, fn {_ref, %{pid: pid}} -> pid end)\n    send(compiler_pid, {:waiting, :pmap, self(), ref, file_pid, nil, on, defining, :raise})\n\n    # Now we allow the tasks to run. This step is not strictly\n    # necessary but it makes compilation more deterministic by\n    # only allowing tasks to run once we are waiting.\n    tasks =\n      Enum.map(refs_tasks, fn {ref, task} ->\n        send(task.pid, ref)\n        task\n      end)\n\n    # Await tasks and notify the compiler they are done. We could\n    # have the tasks report directly to the compiler, which in turn\n    # would notify us, but that would require reimplementing await_many,\n    # and copying the results across boundaries, so we don't.\n    res = Task.await_many(tasks, :infinity)\n    send(compiler_pid, {:available, :pmap, on})\n\n    # Only run once the compiler lets us, to avoid unbounded parallelism.\n    receive do\n      {^ref, _result} -> res\n    end\n  end\n\n  @doc \"\"\"\n  Compiles the given files.\n\n  Those files are compiled in parallel and can automatically\n  detect dependencies between them. Once a dependency is found,\n  the current file stops being compiled until the dependency is\n  resolved.\n\n  It must be invoked with `return_diagnostics: true` as option, so it returns\n  `{:ok, modules, warnings_info}` or `{:error, errors, warnings_info}`,\n  where `warnings_info` has the shape:\n\n      %{\n        runtime_warnings: [warning],\n        compile_warnings: [warning]\n      }\n\n  ## Options\n\n    * `:after_compile` - invoked after all modules are compiled, but before\n      they are verified. If the files are being written to disk, such as in\n      `compile_to_path/3`, this will be invoked after the files are written\n\n    * `:each_file` - for each file compiled, invokes the callback passing the\n      file\n\n    * `:each_long_compilation` - for each file that takes more than a given\n      timeout (see the `:long_compilation_threshold` option) to compile, invoke\n      this callback passing the file as its argument (and optionally the PID\n      of the process compiling the file)\n\n    * `:each_long_verification` (since v1.19.0) - for each file that takes more\n      than a given timeout (see the `:long_verification_threshold` option) to\n      compile, invoke this callback passing the module as its argument (and\n      optionally the PID of the process verifying the module)\n\n    * `:each_module` - for each module compiled, invokes the callback passing\n      the file, module and the module bytecode\n\n    * `:each_cycle` - after the given files are compiled, invokes this function\n      that should return the following values:\n      * `{:compile, modules, warnings}` - to continue compilation with a list of\n        further modules to compile\n      * `{:runtime, modules, warnings}` - to stop compilation and verify the list\n        of modules because dependent modules have changed\n\n    * `:long_compilation_threshold` - the timeout (in seconds) to check for files\n      taking too long to compile. For each file that exceeds the threshold, the\n      `:each_long_compilation` callback is invoked. Defaults to `10` seconds.\n\n    * `:long_verification_threshold` (since v1.19.0) - the timeout (in seconds) to\n      check for modules taking too long to compile. For each module that exceeds the\n      threshold, the `:each_long_verification` callback is invoked. Defaults to\n      `10` seconds.\n\n    * `:verification` (since v1.19.0) - if code verification, such as unused functions,\n      deprecation warnings, and type checking should run. Defaults to `true`.\n      We recommend disabling it only for debugging purposes.\n\n    * `:profile` - if set to `:time` measure the compilation time of each compilation cycle\n       and group pass checker\n\n    * `:purge_compiler_modules` - if set to `true`, automatically purge compilation modules\n      after compilation (see `Code.purge_compiler_modules/0`)\n\n    * `:dest` - the destination directory for the BEAM files. When using `compile/2`,\n      this information is only used to properly annotate the BEAM files before\n      they are loaded into memory. If you want a file to actually be written to\n      `dest`, use `compile_to_path/3` instead.\n\n    * `:beam_timestamp` - the modification timestamp to give all BEAM files\n\n    * `:return_diagnostics` (since v1.15.0) - returns maps with information instead of\n      a list of warnings and returns diagnostics as maps instead of tuples.\n      This option must be set to true, except for backwards compatibibility reasons.\n\n    * `:max_concurrency` - the maximum number of files to compile in parallel.\n      Setting this option to 1 will compile files sequentially.\n      Defaults to the number of schedulers online, or at least `2`.\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec compile([Path.t()], compile_opts()) ::\n          {:ok, [atom], [warning] | info()}\n          | {:error, [error] | [Code.diagnostic(:error)], [warning] | info()}\n  def compile(files, options \\\\ []) when is_list(options) do\n    spawn_workers(files, :compile, options)\n  end\n\n  @doc \"\"\"\n  Compiles the given files and writes resulting BEAM files into path.\n\n  See `compile/2` for more information.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec compile_to_path([Path.t()], Path.t(), compile_opts()) ::\n          {:ok, [atom], [warning] | info()}\n          | {:error, [error] | [Code.diagnostic(:error)], [warning] | info()}\n  def compile_to_path(files, path, options \\\\ []) when is_binary(path) and is_list(options) do\n    spawn_workers(files, {:compile, path}, Keyword.put(options, :dest, path))\n  end\n\n  @doc \"\"\"\n  Requires the given files in parallel.\n\n  Opposite to compile, dependencies are not attempted to be\n  automatically solved between files.\n\n  It must be invoked with `return_diagnostics: true` as option, so it returns\n  `{:ok, modules, warnings_info}` or `{:error, errors, warnings_info}`,\n  where `warnings_info` has the shape:\n\n      %{\n        runtime_warnings: [warning],\n        compile_warnings: [warning]\n      }\n\n  ## Options\n\n    * `:each_file` - for each file compiled, invokes the callback passing the\n      file\n\n    * `:each_module` - for each module compiled, invokes the callback passing\n      the file, module and the module bytecode\n\n    * `:max_concurrency` - the maximum number of files to compile in parallel.\n      Setting this option to 1 will compile files sequentially.\n      Defaults to the number of schedulers online, or at least `2`.\n\n    * `:return_diagnostics` (since v1.15.0) - returns maps with information instead of\n      a list of warnings and returns diagnostics as maps instead of tuples.\n      This option must be set to true, except for backwards compatibibility reasons.\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec require([Path.t()], require_opts()) ::\n          {:ok, [atom], [warning] | info()}\n          | {:error, [error] | [Code.diagnostic(:error)], [warning] | info()}\n  def require(files, options \\\\ []) when is_list(options) do\n    spawn_workers(files, :require, options)\n  end\n\n  @doc false\n  @deprecated \"Use Code.print_diagnostic/2 instead\"\n  def print_warning({file, location, warning}) do\n    :elixir_errors.print_warning(location, file, warning)\n  end\n\n  @doc false\n  @deprecated \"Use Kernel.ParallelCompiler.compile/2 instead\"\n  def files(files, options \\\\ []) when is_list(options) do\n    case spawn_workers(files, :compile, options) do\n      {:ok, modules, _} -> modules\n      {:error, _, _} -> exit({:shutdown, 1})\n    end\n  end\n\n  @doc false\n  @deprecated \"Use Kernel.ParallelCompiler.compile_to_path/2 instead\"\n  def files_to_path(files, path, options \\\\ []) when is_binary(path) and is_list(options) do\n    case spawn_workers(files, {:compile, path}, options) do\n      {:ok, modules, _} -> modules\n      {:error, _, _} -> exit({:shutdown, 1})\n    end\n  end\n\n  defp spawn_workers(files, output, options) do\n    {:module, _} = :code.ensure_loaded(Kernel.ErrorHandler)\n\n    schedulers =\n      Keyword.get_lazy(options, :max_concurrency, fn ->\n        max(:erlang.system_info(:schedulers_online), 2)\n      end)\n\n    {:ok, cache} = Module.ParallelChecker.start_link(options)\n\n    {status, modules_or_errors, info} =\n      try do\n        spawn_workers(schedulers, cache, files, output, options)\n      after\n        Module.ParallelChecker.stop(cache)\n      end\n\n    if Keyword.get(options, :return_diagnostics, false) do\n      {status, modules_or_errors, info}\n    else\n      IO.warn(\n        \"you must pass return_diagnostics: true when invoking Kernel.ParallelCompiler functions\"\n      )\n\n      to_tuples = &Enum.map(&1, fn diag -> {diag.file, diag.position, diag.message} end)\n\n      modules_or_errors =\n        if status == :ok, do: modules_or_errors, else: to_tuples.(modules_or_errors)\n\n      {status, modules_or_errors, to_tuples.(info.runtime_warnings ++ info.compile_warnings)}\n    end\n  end\n\n  defp spawn_workers(schedulers, checker, files, output, options) do\n    threshold = Keyword.get(options, :long_compilation_threshold, 10) * 1000\n    timer_ref = Process.send_after(self(), :threshold_check, threshold)\n\n    purge_compiler_modules =\n      if Keyword.get(options, :purge_compiler_modules, false) do\n        fn -> :elixir_code_server.cast(:purge_compiler_modules) end\n      else\n        fn -> :ok end\n      end\n\n    {outcome, state} =\n      spawn_workers(files, %{}, %{}, [], %{}, [], [], %{\n        beam_timestamp: Keyword.get(options, :beam_timestamp),\n        dest: Keyword.get(options, :dest),\n        after_compile: Keyword.get(options, :after_compile, fn -> :ok end),\n        each_cycle: Keyword.get(options, :each_cycle, fn -> {:runtime, [], []} end),\n        each_file: Keyword.get(options, :each_file, fn _, _ -> :ok end) |> each_file(),\n        each_long_compilation: Keyword.get(options, :each_long_compilation, fn _file -> :ok end),\n        each_module: Keyword.get(options, :each_module, fn _file, _module, _binary -> :ok end),\n        profile: profile_init(Keyword.get(options, :profile)),\n        output: output,\n        timer_ref: timer_ref,\n        long_compilation_threshold: threshold,\n        schedulers: schedulers,\n        checker: checker,\n        verification?: Keyword.get(options, :verification, true),\n        purge_compiler_modules: purge_compiler_modules\n      })\n\n    Process.cancel_timer(state.timer_ref)\n\n    receive do\n      :threshold_check -> :ok\n    after\n      0 -> :ok\n    end\n\n    outcome\n  end\n\n  defp each_file(fun) when is_function(fun, 1), do: fn file, _ -> fun.(file) end\n  defp each_file(fun) when is_function(fun, 2), do: fun\n\n  defp each_file(file, lexical, parent) do\n    ref = Process.monitor(parent)\n    send(parent, {:file_ok, self(), ref, file, lexical})\n\n    receive do\n      ^ref -> :ok\n      {:DOWN, ^ref, _, _, _} -> :ok\n    end\n  end\n\n  defp write_module_binaries(result, {:compile, path}, state) when map_size(result) > 0 do\n    profile(state, \"writing modules to disk\", fn ->\n      File.mkdir_p!(path)\n      Code.prepend_path(path)\n      timestamp = state.beam_timestamp\n\n      # We fan-out the writes as that improves performance\n      # when writing hundreds of beam files. This is cheap as\n      # we only transfer atoms and binaries across processes.\n      pool_size = min(map_size(result), state.schedulers)\n\n      pool_list =\n        for _ <- 1..pool_size do\n          spawn_link(fn -> write_loop(path, timestamp) end)\n        end\n\n      pool_tuple = List.to_tuple(pool_list)\n\n      {modules, _} =\n        Enum.flat_map_reduce(result, 0, fn\n          {{:module, module}, {binary, _}}, scheduler when is_binary(binary) ->\n            send(elem(pool_tuple, scheduler), {:write, module, binary})\n            {[module], rem(scheduler + 1, pool_size)}\n\n          _, scheduler ->\n            {[], scheduler}\n        end)\n\n      pool_refs =\n        for pid <- pool_list do\n          ref = Process.monitor(pid)\n          send(pid, :done)\n          ref\n        end\n\n      for ref <- pool_refs do\n        receive do\n          {:DOWN, ^ref, _, _, _} -> :ok\n        end\n      end\n\n      modules\n    end)\n  end\n\n  defp write_module_binaries(result, _output, _state) do\n    for {{:module, module}, {binary, _}} when is_binary(binary) <- result, do: module\n  end\n\n  defp write_loop(path, timestamp) do\n    receive do\n      {:write, module, binary} ->\n        full_path = Path.join(path, Atom.to_string(module) <> \".beam\")\n        File.write!(full_path, binary, [:raw])\n        if timestamp, do: File.touch!(full_path, timestamp)\n        write_loop(path, timestamp)\n\n      :done ->\n        :ok\n    end\n  end\n\n  ## Verification\n\n  defp verify_modules(result, compile_warnings, dependent_modules, state) do\n    modules = write_module_binaries(result, state.output, state)\n    profile(state, \"after compile callback\", state.after_compile)\n\n    {runtime_warnings, errors} =\n      if state.verification? do\n        profile(\n          state,\n          fn ->\n            num_modules = length(modules) + length(dependent_modules)\n            \"group pass check of #{num_modules} modules\"\n          end,\n          fn -> Module.ParallelChecker.verify(state.checker, dependent_modules) end\n        )\n      else\n        {[], []}\n      end\n\n    info = %{compile_warnings: Enum.reverse(compile_warnings), runtime_warnings: runtime_warnings}\n\n    case errors do\n      [] ->\n        {{:ok, modules, info}, state}\n\n      _ ->\n        IO.puts(:stderr, \"== Type checking failed with errors ==\")\n        {{:error, errors, info}, state}\n    end\n  end\n\n  defp profile_init(:time), do: {:time, System.monotonic_time(), 0}\n  defp profile_init(nil), do: :none\n\n  defp profile(%{profile: :none}, _what, fun), do: fun.()\n\n  defp profile(%{profile: {:time, _, _}}, what, fun) do\n    {time, result} = :timer.tc(fun)\n    time = div(time, 1000)\n    what = if is_binary(what), do: what, else: what.()\n    IO.puts(:stderr, \"[profile] Finished #{what} in #{time}ms\")\n    result\n  end\n\n  ## Compiler worker spawning\n\n  # We already have n=schedulers currently running, don't spawn new ones\n  defp spawn_workers(\n         queue,\n         spawned,\n         waiting,\n         files,\n         result,\n         warnings,\n         errors,\n         %{schedulers: schedulers} = state\n       )\n       when map_size(spawned) - map_size(waiting) >= schedulers do\n    wait_for_messages(queue, spawned, waiting, files, result, warnings, errors, state)\n  end\n\n  # Release waiting processes\n  defp spawn_workers([{pid, found} | t], spawned, waiting, files, result, warnings, errors, state) do\n    {files, waiting} =\n      case Map.pop(waiting, pid) do\n        {%{kind: kind, ref: ref, file_pid: file_pid, on: on}, waiting} ->\n          send(pid, {ref, found})\n          {update_timing(files, file_pid, {:waiting, kind, on}), waiting}\n\n        {nil, waiting} ->\n          # In case the waiting process died (for example, it was an async process),\n          # it will no longer be on the list. So we need to take it into account here.\n          {files, waiting}\n      end\n\n    spawn_workers(t, spawned, waiting, files, result, warnings, errors, state)\n  end\n\n  defp spawn_workers([file | queue], spawned, waiting, files, result, warnings, errors, state) do\n    %{output: output, dest: dest, checker: cache} = state\n    parent = self()\n    file = Path.expand(file)\n\n    {pid, ref} =\n      :erlang.spawn_monitor(fn ->\n        Module.ParallelChecker.put(parent, cache)\n        :erlang.put(:elixir_compiler_info, {parent, self()})\n        :erlang.put(:elixir_compiler_file, file)\n\n        try do\n          case output do\n            {:compile, _} -> compile_file(file, dest, false, parent)\n            :compile -> compile_file(file, dest, true, parent)\n            :require -> require_file(file, parent)\n          end\n        catch\n          kind, reason ->\n            send(parent, {:file_error, self(), file, {kind, reason, __STACKTRACE__}})\n        end\n\n        exit(:shutdown)\n      end)\n\n    file_data = %{\n      pid: pid,\n      ref: ref,\n      file: file,\n      timestamp: System.monotonic_time(),\n      compiling: 0,\n      waiting: [],\n      warned: false\n    }\n\n    new_files = [file_data | files]\n    new_spawned = Map.put(spawned, ref, pid)\n    spawn_workers(queue, new_spawned, waiting, new_files, result, warnings, errors, state)\n  end\n\n  # No more queue, nothing waiting, this cycle is done\n  defp spawn_workers([], spawned, waiting, files, result, warnings, errors, state)\n       when map_size(spawned) == 0 and map_size(waiting) == 0 do\n    # Print any spurious error that we may have found\n    Enum.map(errors, fn {diagnostic, read_snippet} ->\n      :elixir_errors.print_diagnostic(diagnostic, read_snippet)\n    end)\n\n    [] = files\n\n    cycle_return =\n      profile(state, \"cycle resolution\", fn -> each_cycle_return(state.each_cycle.()) end)\n\n    state = cycle_timing(result, state)\n\n    case cycle_return do\n      {:runtime, dependent_modules, extra_warnings} ->\n        state.purge_compiler_modules.()\n        verify_modules(result, extra_warnings ++ warnings, dependent_modules, state)\n\n      {:compile, [], extra_warnings} ->\n        state.purge_compiler_modules.()\n        verify_modules(result, extra_warnings ++ warnings, [], state)\n\n      {:compile, more, extra_warnings} ->\n        spawn_workers(more, %{}, %{}, [], result, extra_warnings ++ warnings, errors, state)\n    end\n  end\n\n  # spawned 1, waiting for 1: Release it!\n  defp spawn_workers([], spawned, waiting, files, result, warnings, errors, state)\n       when map_size(waiting) == map_size(spawned) and map_size(waiting) == 1 do\n    {pid, _, _iterator} = :maps.next(:maps.iterator(waiting))\n    spawn_workers([{pid, :not_found}], spawned, waiting, files, result, warnings, errors, state)\n  end\n\n  # spawned x, waiting for x: POSSIBLE ERROR! Release processes so we get the failures\n  defp spawn_workers([], spawned, waiting, files, result, warnings, errors, state)\n       when map_size(waiting) == map_size(spawned) do\n    # There is potentially a deadlock. We will release modules with\n    # the following order:\n    #\n    #   1. Code.ensure_compiled/1 checks without a known definition (deadlock = soft)\n    #   2. Code.ensure_compiled/1 checks with a known definition (deadlock = soft)\n    #   3. Struct/import/require/ensure_compiled! checks without a known definition (deadlock = hard)\n    #   4. Modules without a known definition\n    #   5. Code invocation (deadlock = raise)\n    #\n    # The reason for step 3 and 4 is to not treat typos as deadlocks and\n    # help developers handle those sooner. However, this can have false\n    # positives in case multiple modules are defined in the same file\n    # and the module we are waiting for is defined later on.\n    #\n    # Finally, note there is no difference between hard and raise, the\n    # difference is where the raise is happening, inside the compiler\n    # or in the caller.\n    deadlocked =\n      profile(state, \"deadlock resolution\", fn ->\n        waiting_list = Map.to_list(waiting)\n\n        deadlocked(waiting_list, :soft, false) ||\n          deadlocked(waiting_list, :soft, true) ||\n          deadlocked(waiting_list, :hard, false) ||\n          without_definition(waiting_list, files)\n      end)\n\n    if deadlocked do\n      spawn_workers(deadlocked, spawned, waiting, files, result, warnings, errors, state)\n    else\n      return_error(warnings, errors, state, fn ->\n        handle_deadlock(waiting, files)\n      end)\n    end\n  end\n\n  # No more queue, but spawned and map_size(waiting) do not match\n  defp spawn_workers([], spawned, waiting, files, result, warnings, errors, state) do\n    wait_for_messages([], spawned, waiting, files, result, warnings, errors, state)\n  end\n\n  defp compile_file(file, path, force_load?, parent) do\n    :erlang.process_flag(:error_handler, Kernel.ErrorHandler)\n    :erlang.put(:elixir_compiler_dest, {path, force_load?})\n    :elixir_compiler.file(file, &each_file(&1, &2, parent))\n  end\n\n  defp require_file(file, parent) do\n    case :elixir_code_server.call({:acquire, file}) do\n      :required ->\n        send(parent, {:file_cancel, self()})\n\n      :proceed ->\n        :elixir_compiler.file(file, &each_file(&1, &2, parent))\n        :elixir_code_server.cast({:required, file})\n    end\n  end\n\n  defp cycle_timing(_result, %{profile: :none} = state) do\n    state\n  end\n\n  defp cycle_timing(result, %{profile: {:time, cycle_start, module_counter}} = state) do\n    num_modules = count_modules(result)\n    diff_modules = num_modules - module_counter\n    now = System.monotonic_time()\n    time = System.convert_time_unit(now - cycle_start, :native, :millisecond)\n\n    IO.puts(\n      :stderr,\n      \"[profile] Finished compilation cycle of #{diff_modules} modules in #{time}ms\"\n    )\n\n    %{state | profile: {:time, now, num_modules}}\n  end\n\n  defp count_modules(result) do\n    Enum.count(result, &match?({{:module, _}, {binary, _}} when is_binary(binary), &1))\n  end\n\n  defp each_cycle_return({kind, modules, warnings}), do: {kind, modules, warnings}\n\n  defp each_cycle_return(other) do\n    IO.warn(\n      \"the :each_cycle callback must return a tuple of format {:compile | :runtime, modules, warnings}\"\n    )\n\n    case other do\n      {kind, modules} -> {kind, modules, []}\n      modules when is_list(modules) -> {:compile, modules, []}\n    end\n  end\n\n  # The goal of this function is to find leaves in the dependency graph,\n  # i.e. to find code that depends on code that we know is not being defined.\n  # Note that not all files have been compiled yet, so they may not be in waiting.\n  defp without_definition(waiting_list, files) do\n    nilify_empty_or_sort(\n      for %{pid: file_pid} <- files,\n          {pid, %{file_pid: ^file_pid, on: on}} <- waiting_list,\n          is_atom(on) and not defining?(on, waiting_list),\n          do: {pid, :not_found}\n    )\n  end\n\n  defp deadlocked(waiting_list, type, defining?) do\n    nilify_empty_or_sort(\n      for {pid, %{on: on, deadlock: ^type}} <- waiting_list,\n          is_atom(on) and defining?(on, waiting_list) == defining?,\n          do: {pid, :deadlock}\n    )\n  end\n\n  defp defining?(on, waiting_list) do\n    Enum.any?(waiting_list, fn {_, %{defining: defining}} -> on in defining end)\n  end\n\n  defp nilify_empty_or_sort([]), do: nil\n  defp nilify_empty_or_sort([_ | _] = list), do: Enum.sort(list)\n\n  # Wait for messages from child processes\n  defp wait_for_messages(queue, spawned, waiting, files, result, warnings, errors, state) do\n    %{output: output} = state\n\n    receive do\n      {:async, pid} ->\n        ref = Process.monitor(pid)\n        new_spawned = Map.put(spawned, ref, pid)\n        wait_for_messages(queue, new_spawned, waiting, files, result, warnings, errors, state)\n\n      {:available, kind, on} ->\n        {available, result} = update_result(result, kind, on, :done)\n\n        spawn_workers(\n          available ++ queue,\n          spawned,\n          waiting,\n          files,\n          result,\n          warnings,\n          errors,\n          state\n        )\n\n      {{:module_loaded, module}, _ref, _type, _pid, _reason} ->\n        result =\n          Map.update!(result, {:module, module}, fn {binary, _loader} -> {binary, true} end)\n\n        spawn_workers(queue, spawned, waiting, files, result, warnings, errors, state)\n\n      {:module_available, child, ref, file, module, binary, loaded?} ->\n        state.each_module.(file, module, binary)\n        send(child, {ref, :ack})\n\n        {available, load_status} =\n          case Map.get(result, {:module, module}) do\n            [_ | _] = pids when loaded? ->\n              {Enum.map(pids, &{&1, :found}), loaded?}\n\n            # When compiling files to disk, we only load the module\n            # if other modules are waiting for it.\n            [_ | _] = pids ->\n              pid = load_module(module, binary, state.dest)\n              {Enum.map(pids, &{&1, {:loading, pid}}), pid}\n\n            _ ->\n              {[], loaded?}\n          end\n\n        spawn_workers(\n          available ++ queue,\n          spawned,\n          waiting,\n          files,\n          Map.put(result, {:module, module}, {binary, load_status}),\n          warnings,\n          errors,\n          state\n        )\n\n      # If we are simply requiring files, we do not add to waiting.\n      {:waiting, _kind, child, ref, _file_pid, _position, _on, _defining, _deadlock}\n      when output == :require ->\n        send(child, {ref, :not_found})\n        spawn_workers(queue, spawned, waiting, files, result, warnings, errors, state)\n\n      {:waiting, kind, child_pid, ref, file_pid, position, on, defining, deadlock} ->\n        # If we already got what we were waiting for, do not put it on waiting.\n        # If we're waiting on ourselves, send :found so that we can crash with\n        # a better error.\n        available_or_pending = Map.get(result, {kind, on}, [])\n\n        {waiting, files, result} =\n          if not is_list(available_or_pending) or on in defining do\n            # If what we are waiting on was defined but not loaded, we do it now.\n            {reply, result} = load_pending(kind, on, result, state)\n            send(child_pid, {ref, reply})\n            {waiting, files, result}\n          else\n            waiting =\n              Map.put(waiting, child_pid, %{\n                kind: kind,\n                ref: ref,\n                file_pid: file_pid,\n                position: position,\n                on: on,\n                defining: defining,\n                deadlock: deadlock\n              })\n\n            files = update_timing(files, file_pid, :compiling)\n            result = Map.put(result, {kind, on}, [child_pid | available_or_pending])\n            {waiting, files, result}\n          end\n\n        spawn_workers(queue, spawned, waiting, files, result, warnings, errors, state)\n\n      :threshold_check ->\n        files =\n          for data <- files do\n            if data.warned or Map.has_key?(waiting, data.pid) do\n              data\n            else\n              data = update_timing(data, :compiling)\n              data = maybe_warn_long_compilation(data, state)\n              data\n            end\n          end\n\n        timer_ref = Process.send_after(self(), :threshold_check, state.long_compilation_threshold)\n        state = %{state | timer_ref: timer_ref}\n        spawn_workers(queue, spawned, waiting, files, result, warnings, errors, state)\n\n      {:diagnostic, %{severity: :warning, file: file} = diagnostic, read_snippet} ->\n        :elixir_errors.print_diagnostic(diagnostic, read_snippet)\n        warnings = [%{diagnostic | file: file && Path.absname(file)} | warnings]\n        wait_for_messages(queue, spawned, waiting, files, result, warnings, errors, state)\n\n      {:diagnostic, %{severity: :error} = diagnostic, read_snippet} ->\n        errors = [{diagnostic, read_snippet} | errors]\n        wait_for_messages(queue, spawned, waiting, files, result, warnings, errors, state)\n\n      {:file_ok, child_pid, ref, file, lexical} ->\n        state.each_file.(file, lexical)\n        send(child_pid, ref)\n\n        {file, new_spawned, new_files} = discard_file_pid(spawned, files, child_pid)\n        file && maybe_log_file_profile(file, state)\n\n        # We may have spurious entries in the waiting list\n        # if someone invoked try/rescue UndefinedFunctionError\n        new_waiting = Map.delete(waiting, child_pid)\n        spawn_workers(queue, new_spawned, new_waiting, new_files, result, warnings, errors, state)\n\n      {:file_cancel, child_pid} ->\n        {_file, new_spawned, new_files} = discard_file_pid(spawned, files, child_pid)\n        spawn_workers(queue, new_spawned, waiting, new_files, result, warnings, errors, state)\n\n      {:file_error, child_pid, file, {kind, reason, stack}} ->\n        {_file, _new_spawned, new_files} = discard_file_pid(spawned, files, child_pid)\n        terminate(new_files)\n\n        return_error(warnings, errors, state, fn ->\n          print_error(file, nil, kind, reason, stack)\n          [to_error(file, kind, reason, stack)]\n        end)\n\n      {:DOWN, ref, :process, pid, reason} when is_map_key(spawned, ref) ->\n        # async spawned processes have no file, so we always have to delete the ref directly\n        spawned = Map.delete(spawned, ref)\n        waiting = Map.delete(waiting, pid)\n        {file, spawned, files} = discard_file_pid(spawned, files, pid)\n\n        if file do\n          terminate(files)\n\n          return_error(warnings, errors, state, fn ->\n            print_error(file.file, nil, :exit, reason, [])\n            [to_error(file.file, :exit, reason, [])]\n          end)\n        else\n          wait_for_messages(queue, spawned, waiting, files, result, warnings, errors, state)\n        end\n    end\n  end\n\n  defp return_error(warnings, errors, state, fun) do\n    state.purge_compiler_modules.()\n\n    errors =\n      Enum.map(errors, fn {%{file: file} = diagnostic, read_snippet} ->\n        :elixir_errors.print_diagnostic(diagnostic, read_snippet)\n        %{diagnostic | file: file && Path.absname(file)}\n      end)\n\n    info = %{compile_warnings: Enum.reverse(warnings), runtime_warnings: []}\n    {{:error, Enum.reverse(errors, fun.()), info}, state}\n  end\n\n  defp load_pending(kind, module, result, state) do\n    case result do\n      %{{:module, ^module} => {binary, load_status}}\n      when kind in [:module, :struct] and is_binary(binary) ->\n        case load_status do\n          true ->\n            {:found, result}\n\n          false ->\n            pid = load_module(module, binary, state.dest)\n            result = Map.put(result, {:module, module}, {binary, pid})\n            {{:loading, pid}, result}\n\n          pid when is_pid(pid) ->\n            {{:loading, pid}, result}\n        end\n\n      _ ->\n        {:found, result}\n    end\n  end\n\n  # We load modules in a separate process to avoid blocking\n  # the parallel compiler. We store the PID of this process and\n  # all entries monitor it to know once the module is loaded.\n  defp load_module(module, binary, dest) do\n    {pid, _ref} =\n      :erlang.spawn_opt(\n        fn ->\n          beam_location =\n            case dest do\n              nil ->\n                []\n\n              dest ->\n                :filename.join(\n                  :elixir_utils.characters_to_list(dest),\n                  Atom.to_charlist(module) ++ ~c\".beam\"\n                )\n            end\n\n          :code.load_binary(module, beam_location, binary)\n        end,\n        monitor: [tag: {:module_loaded, module}]\n      )\n\n    pid\n  end\n\n  defp update_result(result, kind, module, value) do\n    available =\n      case Map.get(result, {kind, module}) do\n        [_ | _] = pids -> Enum.map(pids, &{&1, :found})\n        _ -> []\n      end\n\n    {available, Map.put(result, {kind, module}, value)}\n  end\n\n  defp update_timing(files, pid, key) do\n    Enum.map(files, fn data ->\n      if data.pid == pid, do: update_timing(data, key), else: data\n    end)\n  end\n\n  defp update_timing(data, :compiling) do\n    time = System.monotonic_time()\n    %{data | compiling: data.compiling + time - data.timestamp, timestamp: time}\n  end\n\n  defp update_timing(data, {:waiting, kind, on}) do\n    time = System.monotonic_time()\n    %{data | waiting: [{kind, on, time - data.timestamp} | data.waiting], timestamp: time}\n  end\n\n  defp maybe_warn_long_compilation(data, state) do\n    compiling = System.convert_time_unit(data.compiling, :native, :millisecond)\n\n    if not data.warned and compiling >= state.long_compilation_threshold do\n      if is_function(state.each_long_compilation, 2) do\n        state.each_long_compilation.(data.file, data.pid)\n      else\n        state.each_long_compilation.(data.file)\n      end\n\n      %{data | warned: true}\n    else\n      data\n    end\n  end\n\n  defp discard_file_pid(spawned, files, pid) do\n    case Enum.split_with(files, &(&1.pid == pid)) do\n      {[file], files} ->\n        Process.demonitor(file.ref, [:flush])\n        {file, Map.delete(spawned, file.ref), files}\n\n      {[], files} ->\n        {nil, spawned, files}\n    end\n  end\n\n  defp maybe_log_file_profile(data, state) do\n    data = update_timing(data, :compiling)\n    data = maybe_warn_long_compilation(data, state)\n\n    if state.profile != :none do\n      compiling = to_padded_ms(data.compiling)\n      relative = Path.relative_to_cwd(data.file)\n\n      messages =\n        case List.pop_at(data.waiting, 0) do\n          {nil, []} ->\n            \"[profile] #{compiling}ms compiling +      0ms waiting while compiling #{relative}\"\n\n          {{kind, on, time}, rest} ->\n            initial_message = [\n              \"[profile] #{compiling}ms compiling + \",\n              format_waiting_message(time, kind, on, relative)\n            ]\n\n            waiting_details =\n              Enum.map(rest, fn {kind, on, time} ->\n                [\n                  \"\\n[profile]                    | \",\n                  format_waiting_message(time, kind, on, relative)\n                ]\n              end)\n\n            [initial_message | waiting_details]\n        end\n\n      IO.puts(:stderr, messages)\n    end\n  end\n\n  defp format_waiting_message(time, kind, on, relative),\n    do: \"#{to_padded_ms(time)}ms waiting for #{kind} #{inspect(on)} while compiling #{relative}\"\n\n  defp to_padded_ms(time) do\n    time\n    |> System.convert_time_unit(:native, :millisecond)\n    |> Integer.to_string()\n    |> String.pad_leading(6, \" \")\n  end\n\n  defp handle_deadlock(waiting, files) do\n    deadlock =\n      for %{pid: pid, file: file} <- files do\n        {:current_stacktrace, stacktrace} = Process.info(pid, :current_stacktrace)\n        Process.exit(pid, :kill)\n\n        %{kind: kind, on: on, position: position} = Map.fetch!(waiting, pid)\n        description = \"deadlocked waiting on #{kind} #{inspect(on)}\"\n        error = CompileError.exception(description: description, file: nil, line: nil)\n        print_error(file, position, :error, error, stacktrace)\n        {Path.relative_to_cwd(file), position, on, description, stacktrace}\n      end\n\n    IO.puts(:stderr, \"\"\"\n\n    Compilation failed because of a deadlock between files.\n    The following files depended on the following modules:\n    \"\"\")\n\n    max =\n      deadlock\n      |> Enum.map(&(&1 |> elem(0) |> String.length()))\n      |> Enum.max()\n\n    for {file, _, mod, _, _} <- deadlock do\n      IO.puts(:stderr, [\"  \", String.pad_leading(file, max), \" => \" | inspect(mod)])\n    end\n\n    IO.puts(\n      :stderr,\n      \"\\nEnsure there are no compile-time dependencies between those files \" <>\n        \"(such as structs or macros) and that the modules they reference exist \" <>\n        \"and are correctly named\\n\"\n    )\n\n    for {file, position, _, description, stacktrace} <- deadlock do\n      file = Path.absname(file)\n\n      %{\n        severity: :error,\n        file: file,\n        source: file,\n        position: position,\n        message: description,\n        stacktrace: stacktrace,\n        span: nil\n      }\n    end\n  end\n\n  defp terminate(files) do\n    for %{pid: pid} <- files, do: Process.exit(pid, :kill)\n\n    for %{pid: pid} <- files do\n      receive do\n        {:DOWN, _, :process, ^pid, _} -> :ok\n      end\n    end\n\n    :ok\n  end\n\n  defp print_error(file, position, kind, reason, stack) do\n    position = if is_integer(position), do: \":#{position}\", else: \"\"\n\n    IO.write(:stderr, [\n      \"\\n== Compilation error in file #{Path.relative_to_cwd(file)}#{position} ==\\n\",\n      Kernel.CLI.format_error(kind, reason, stack)\n    ])\n  end\n\n  defp to_error(source, kind, reason, stack) do\n    {file, line, span} = get_snippet_info(source, reason, stack)\n    source = Path.absname(source)\n    message = :unicode.characters_to_binary(Kernel.CLI.format_error(kind, reason, stack))\n\n    %{\n      file: file || source,\n      source: source,\n      position: line || 0,\n      message: message,\n      severity: :error,\n      stacktrace: stack,\n      span: span,\n      details: {kind, reason}\n    }\n  end\n\n  defp get_snippet_info(\n         _file,\n         %{file: file, line: line, column: column, end_line: end_line, end_column: end_column},\n         _stack\n       )\n       when is_integer(line) and line > 0 and is_integer(column) and column >= 0 and\n              is_integer(end_line) and end_line > 0 and is_integer(end_column) and end_column >= 0 do\n    {Path.absname(file), {line, column}, {end_line, end_column}}\n  end\n\n  defp get_snippet_info(_file, %{file: file, line: line, column: column}, _stack)\n       when is_integer(line) and line > 0 and is_integer(column) and column >= 0 do\n    {Path.absname(file), {line, column}, nil}\n  end\n\n  defp get_snippet_info(_file, %{line: line}, _stack) when is_integer(line) and line > 0 do\n    {nil, line, nil}\n  end\n\n  defp get_snippet_info(file, :undef, [{_, _, _, []}, {_, _, _, info} | _]) do\n    get_snippet_info_from_stacktrace_info(info, file)\n  end\n\n  defp get_snippet_info(file, _reason, [{_, _, _, [file: expanding]}, {_, _, _, info} | _])\n       when expanding in [~c\"expanding macro\", ~c\"expanding struct\"] do\n    get_snippet_info_from_stacktrace_info(info, file)\n  end\n\n  defp get_snippet_info(file, _reason, [{_, _, _, info} | _]) do\n    get_snippet_info_from_stacktrace_info(info, file)\n  end\n\n  defp get_snippet_info(_, _, _) do\n    {nil, nil, nil}\n  end\n\n  defp get_snippet_info_from_stacktrace_info(info, file) do\n    if Keyword.get(info, :file) == to_charlist(Path.relative_to_cwd(file)) do\n      {nil, Keyword.get(info, :line), nil}\n    else\n      {nil, nil, nil}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel/parallel_require.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Kernel.ParallelRequire do\n  @moduledoc false\n  @moduledoc deprecated: \"Use the Kernel.ParallelCompiler module instead\"\n\n  @deprecated \"Use Kernel.ParallelCompiler.require/2 instead\"\n  def files(files, callbacks \\\\ [])\n\n  def files(files, callback) when is_function(callback, 1) do\n    files(files, each_file: callback)\n  end\n\n  def files(files, options) when is_list(options) do\n    case Kernel.ParallelCompiler.require(files, options) do\n      {:ok, modules, _} -> modules\n      {:error, _, _} -> exit({:shutdown, 1})\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel/special_forms.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Kernel.SpecialForms do\n  @moduledoc \"\"\"\n  Special forms are the basic building blocks of Elixir, and therefore\n  cannot be overridden by the developer.\n\n  The `Kernel.SpecialForms` module consists solely of macros that can be\n  invoked anywhere in Elixir code without the use of the\n  `Kernel.SpecialForms.` prefix. This is possible because they all have\n  been automatically imported, in the same fashion as the functions and\n  macros from the `Kernel` module.\n\n  These building blocks are defined in this module. Some of these special forms are lexical (such as\n  `alias/2` and `case/2`). The macros `{}/1` and `<<>>/1` are also special\n  forms used to define tuple and binary data structures respectively.\n\n  This module also documents macros that return information about Elixir's\n  compilation environment, such as (`__ENV__/0`, `__MODULE__/0`, `__DIR__/0`,\n  `__STACKTRACE__/0`, and `__CALLER__/0`).\n\n  Additionally, it documents two special forms, `__block__/1` and\n  `__aliases__/1`, which are not intended to be called directly by the\n  developer but they appear in quoted contents since they are essential\n  in Elixir's constructs.\n  \"\"\"\n\n  defmacrop error!(args) do\n    quote do\n      _ = unquote(args)\n\n      message =\n        \"Elixir's special forms are expanded by the compiler and must not be invoked directly\"\n\n      :erlang.error(RuntimeError.exception(message))\n    end\n  end\n\n  @doc \"\"\"\n  Creates a tuple.\n\n  More information about the tuple data type and about functions to manipulate\n  tuples can be found in the `Tuple` module; some functions for working with\n  tuples are also available in `Kernel` (such as `Kernel.elem/2` or\n  `Kernel.tuple_size/1`).\n\n  ## AST representation\n\n  Only two-element tuples are considered literals in Elixir and return themselves\n  when quoted. Therefore, all other tuples are represented in the AST as calls to\n  the `:{}` special form.\n\n      iex> quote do\n      ...>   {1, 2}\n      ...> end\n      {1, 2}\n\n      iex> quote do\n      ...>   {1, 2, 3}\n      ...> end\n      {:{}, [], [1, 2, 3]}\n\n  \"\"\"\n  defmacro unquote(:{})(args), do: error!([args])\n\n  @doc \"\"\"\n  Creates a map.\n\n  See the `Map` module for more information about maps, their syntax, and ways to\n  access and manipulate them.\n\n  ## AST representation\n\n  Regardless of whether `=>` or the keyword syntax is used, key-value pairs in\n  maps are always represented internally as a list of two-element tuples for\n  simplicity:\n\n      iex> quote do\n      ...>   %{\"a\" => :b, c: :d}\n      ...> end\n      {:%{}, [], [{\"a\", :b}, {:c, :d}]}\n\n  \"\"\"\n  defmacro unquote(:%{})(args), do: error!([args])\n\n  @doc \"\"\"\n  Matches on or builds a struct.\n\n  A struct is a tagged map that allows developers to provide\n  default values for keys, tags to be used in polymorphic\n  dispatches and compile time assertions.\n\n  Structs are usually defined with the `Kernel.defstruct/1` macro:\n\n      defmodule User do\n        defstruct name: \"john\", age: 27\n      end\n\n  Now a struct can be created as follows:\n\n      %User{}\n\n  Underneath a struct is a map with a `:__struct__` key pointing\n  to the `User` module, where the keys are validated at compile-time:\n\n      %User{} == %{__struct__: User, name: \"john\", age: 27}\n\n  The struct fields can be given when building the struct:\n\n      %User{age: 31}\n      #=> %{__struct__: User, name: \"john\", age: 31}\n\n  Or also on pattern matching to extract values out:\n\n      %User{age: age} = user\n\n  The advantage of structs is that they validate that the given\n  keys are part of the defined struct. The example below will fail\n  because there is no key `:full_name` in the `User` struct:\n\n      %User{full_name: \"john doe\"}\n\n  The map update syntax can also be used for updating structs:\n\n      %{user | age: 28}\n\n  ## Pattern matching on struct names\n\n  Besides allowing pattern matching on struct fields, such as:\n\n      %User{age: age} = user\n\n  Structs also allow pattern matching on the struct name:\n\n      %struct_name{} = user\n      struct_name #=> User\n\n  You can also assign the struct name to `_` when you want to\n  check if something is a struct but you are not interested in\n  its name:\n\n      %_{} = user\n\n  \"\"\"\n  defmacro unquote(:%)(struct, map), do: error!([struct, map])\n\n  @doc \"\"\"\n  Defines a new bitstring.\n\n  ## Examples\n\n      iex> <<1, 2, 3>>\n      <<1, 2, 3>>\n\n  ## Types\n\n  A bitstring is made of many segments and each segment has a\n  type. There are 9 types used in bitstrings:\n\n  - `integer`\n  - `float`\n  - `bits` (alias for `bitstring`)\n  - `bitstring`\n  - `binary`\n  - `bytes` (alias for `binary`)\n  - `utf8`\n  - `utf16`\n  - `utf32`\n\n  When no type is specified, the default is `integer`:\n\n      iex> <<1, 2, 3>>\n      <<1, 2, 3>>\n\n  Elixir also accepts by default the segment to be a literal\n  string which expands to integers:\n\n      iex> <<0, \"foo\">>\n      <<0, 102, 111, 111>>\n\n  You can use one of `utf8` (the default), `utf16`, and `utf32` to\n  control how the string is encoded:\n\n      iex> <<\"foo\"::utf16>>\n      <<0, 102, 0, 111, 0, 111>>\n\n  Which is equivalent to writing:\n\n      iex> <<?f::utf16, ?o::utf16, ?o::utf16>>\n      <<0, 102, 0, 111, 0, 111>>\n\n  At runtime, binaries need to be explicitly tagged as `binary`:\n\n      iex> rest = \"oo\"\n      iex> <<102, rest::binary>>\n      \"foo\"\n\n  Otherwise we get an `ArgumentError` when constructing the binary:\n\n      rest = \"oo\"\n      <<102, rest>>\n      ** (ArgumentError) argument error\n\n  ## Options\n\n  Many options can be given by using `-` as separator. Order is\n  arbitrary, so the following are all equivalent:\n\n      <<102::integer-native, rest::binary>>\n      <<102::native-integer, rest::binary>>\n      <<102::unsigned-big-integer, rest::binary>>\n      <<102::unsigned-big-integer-size(8), rest::binary>>\n      <<102::unsigned-big-integer-8, rest::binary>>\n      <<102::8-integer-big-unsigned, rest::binary>>\n      <<102, rest::binary>>\n\n  ### Unit and Size\n\n  The length of the match is equal to the `unit` (a number of bits) times the\n  `size` (the number of repeated segments of length `unit`).\n\n  Type      | Default Unit\n  --------- | ------------\n  `integer` | 1 bit\n  `float`   | 1 bit\n  `binary`  | 8 bits\n\n  Sizes for types are a bit more nuanced. The default size for integers is 8.\n\n  For floats, it is 64. For floats, `size * unit` must result in 16, 32, or 64,\n  corresponding to [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point)\n  binary16, binary32, and binary64, respectively.\n\n  For binaries, the default is the size of the binary. Only the last binary in a\n  match can use the default size. All others must have their size specified\n  explicitly, even if the match is unambiguous. For example:\n\n      iex> <<name::binary-size(5), \" the \", species::binary>> = <<\"Frank the Walrus\">>\n      \"Frank the Walrus\"\n      iex> {name, species}\n      {\"Frank\", \"Walrus\"}\n\n  The size can be a variable or any valid guard expression:\n\n      iex> name_size = 5\n      iex> <<name::binary-size(^name_size), \" the \", species::binary>> = <<\"Frank the Walrus\">>\n      iex> {name, species}\n      {\"Frank\", \"Walrus\"}\n\n  The size can access prior variables defined in the binary itself:\n\n      iex> <<name_size::size(8), name::binary-size(name_size), \" the \", species::binary>> = <<5, \"Frank the Walrus\">>\n      iex> {name, species}\n      {\"Frank\", \"Walrus\"}\n\n  However, it cannot access variables defined in the match outside of the binary/bitstring:\n\n      {name_size, <<name::binary-size(name_size), _rest::binary>>} = {5, <<\"Frank the Walrus\">>}\n      ** (CompileError): undefined variable \"name_size\" in bitstring segment\n\n  Failing to specify the size for the non-last causes compilation to fail:\n\n      <<name::binary, \" the \", species::binary>> = <<\"Frank the Walrus\">>\n      ** (CompileError): a binary field without size is only allowed at the end of a binary pattern\n\n  #### Shortcut Syntax\n\n  Size and unit can also be specified using a syntax shortcut\n  when passing integer values:\n\n      iex> x = 1\n      iex> <<x::8>> == <<x::size(8)>>\n      true\n      iex> <<x::8*4>> == <<x::size(8)-unit(4)>>\n      true\n\n  This syntax reflects the fact the effective size is given by\n  multiplying the size by the unit.\n\n  ### Modifiers\n\n  Some types have associated modifiers to clear up ambiguity in byte\n  representation.\n\n  Modifier             | Relevant Type(s)\n  -------------------- | ----------------\n  `signed`             | `integer`\n  `unsigned` (default) | `integer`\n  `little`             | `integer`, `float`, `utf16`, `utf32`\n  `big` (default)      | `integer`, `float`, `utf16`, `utf32`\n  `native`             | `integer`, `float`, `utf16`, `utf32`\n\n  ### Sign\n\n  Integers can be `signed` or `unsigned`, defaulting to `unsigned`.\n\n      iex> <<int::integer>> = <<-100>>\n      <<156>>\n      iex> int\n      156\n      iex> <<int::integer-signed>> = <<-100>>\n      <<156>>\n      iex> int\n      -100\n\n  `signed` and `unsigned` are only used for matching binaries (see below) and\n  are only used for integers.\n\n      iex> <<-100::signed, _rest::binary>> = <<-100, \"foo\">>\n      <<156, 102, 111, 111>>\n\n  ### Endianness\n\n  Elixir has three options for endianness: `big`, `little`, and `native`.\n  The default is `big`:\n\n      iex> <<number::little-integer-size(16)>> = <<0, 1>>\n      <<0, 1>>\n      iex> number\n      256\n      iex> <<number::big-integer-size(16)>> = <<0, 1>>\n      <<0, 1>>\n      iex> number\n      1\n\n  `native` is determined by the VM at startup and will depend on the\n  host operating system.\n\n  ## Binary/Bitstring Matching\n\n  Binary matching is a powerful feature in Elixir that is useful for extracting\n  information from binaries as well as pattern matching.\n\n  Binary matching can be used by itself to extract information from binaries:\n\n      iex> <<\"Hello, \", place::binary>> = \"Hello, World\"\n      \"Hello, World\"\n      iex> place\n      \"World\"\n\n  Or as a part of function definitions to pattern match:\n\n      defmodule ImageType do\n        @png_signature <<137::size(8), 80::size(8), 78::size(8), 71::size(8),\n                         13::size(8), 10::size(8), 26::size(8), 10::size(8)>>\n        @jpg_signature <<255::size(8), 216::size(8)>>\n\n        def type(<<@png_signature, _rest::binary>>), do: :png\n        def type(<<@jpg_signature, _rest::binary>>), do: :jpg\n        def type(_), do: :unknown\n      end\n\n  ### Performance & Optimizations\n\n  The Erlang compiler can provide a number of optimizations on binary creation\n  and matching. To see optimization output, set the `bin_opt_info` compiler\n  option:\n\n      ERL_COMPILER_OPTIONS=bin_opt_info mix compile\n\n  To learn more about specific optimizations and performance considerations,\n  check out the\n  [\"Constructing and matching binaries\" chapter of the Erlang's Efficiency Guide](https://www.erlang.org/doc/efficiency_guide/binaryhandling.html).\n  \"\"\"\n  defmacro unquote(:<<>>)(args), do: error!([args])\n\n  @doc \"\"\"\n  Dot operator. Defines a remote call, a call to an anonymous function, or an alias.\n\n  The dot (`.`) in Elixir can be used for remote calls:\n\n      iex> String.downcase(\"FOO\")\n      \"foo\"\n\n  In this example above, we have used `.` to invoke `downcase` in the\n  `String` module, passing `\"FOO\"` as argument.\n\n  The dot may be used to invoke anonymous functions too:\n\n      iex> (fn n -> n end).(7)\n      7\n\n  in which case there is a function on the left hand side.\n\n  We can also use the dot for creating aliases:\n\n      iex> Hello.World\n      Hello.World\n\n  This time, we have joined two aliases, defining the final alias\n  `Hello.World`.\n\n  ## Syntax\n\n  The right side of `.` may be a word starting with an uppercase letter, which represents\n  an alias, a word starting with lowercase or underscore, any valid language\n  operator or any name wrapped in single- or double-quotes. Those are all valid\n  examples:\n\n      iex> Kernel.Sample\n      Kernel.Sample\n\n      iex> Kernel.length([1, 2, 3])\n      3\n\n      iex> Kernel.+(1, 2)\n      3\n\n      iex> Kernel.\"+\"(1, 2)\n      3\n\n  Wrapping the function name in single- or double-quotes is always a\n  remote call. Therefore `Kernel.\"Foo\"` will attempt to call the function \"Foo\"\n  and not return the alias `Kernel.Foo`. This is done by design as module names\n  are more strict than function names.\n\n  When the dot is used to invoke an anonymous function there is only one\n  operand, but it is still written using a postfix notation:\n\n      iex> negate = fn n -> -n end\n      iex> negate.(7)\n      -7\n\n  ## Quoted expression\n\n  When `.` is used, the quoted expression may take two distinct\n  forms. When the right side starts with a lowercase letter (or\n  underscore):\n\n      iex> quote do\n      ...>   String.downcase(\"FOO\")\n      ...> end\n      {{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}, [], [\"FOO\"]}\n\n  Note that we have an inner tuple, containing the atom `:.` representing\n  the dot as first element:\n\n      {:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}\n\n  This tuple follows the general quoted expression structure in Elixir,\n  with the name as first argument, some keyword list as metadata as second,\n  and the list of arguments as third. In this case, the arguments are the\n  alias `String` and the atom `:downcase`. The second argument in a remote call\n  is **always** an atom.\n\n  In the case of calls to anonymous functions, the inner tuple with the dot\n  special form has only one argument, reflecting the fact that the operator is\n  unary:\n\n      iex> quote do\n      ...>   negate.(0)\n      ...> end\n      {{:., [], [{:negate, [], __MODULE__}]}, [], [0]}\n\n  When the right side is an alias (i.e. starts with uppercase), we get instead:\n\n      iex> quote do\n      ...>   Hello.World\n      ...> end\n      {:__aliases__, [alias: false], [:Hello, :World]}\n\n  We go into more details about aliases in the `__aliases__/1` special form\n  documentation.\n\n  ## Unquoting\n\n  We can also use unquote to generate a remote call in a quoted expression:\n\n      iex> x = :downcase\n      iex> quote do\n      ...>   String.unquote(x)(\"FOO\")\n      ...> end\n      {{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}, [], [\"FOO\"]}\n\n  Similar to `Kernel.\"FUNCTION_NAME\"`, `unquote(x)` will always generate a remote call,\n  independent of the value of `x`. To generate an alias via the quoted expression,\n  one needs to rely on `Module.concat/2`:\n\n      iex> x = Sample\n      iex> quote do\n      ...>   Module.concat(String, unquote(x))\n      ...> end\n      {{:., [], [{:__aliases__, [alias: false], [:Module]}, :concat]}, [],\n       [{:__aliases__, [alias: false], [:String]}, Sample]}\n\n  \"\"\"\n  defmacro unquote(:.)(left, right), do: error!([left, right])\n\n  @doc \"\"\"\n  `alias/2` is used to set up aliases, often useful with modules' names.\n\n  ## Examples\n\n  `alias/2` can be used to set up an alias for any module:\n\n      defmodule Math do\n        alias MyKeyword, as: Keyword\n      end\n\n  In the example above, we have set up `MyKeyword` to be aliased\n  as `Keyword`. So now, any reference to `Keyword` will be\n  automatically replaced by `MyKeyword`.\n\n  In case one wants to access the original `Keyword`, it can be done\n  by accessing `Elixir`:\n\n      Keyword.values #=> uses MyKeyword.values\n      Elixir.Keyword.values #=> uses Keyword.values\n\n  Note that calling `alias` without the `:as` option automatically\n  sets an alias based on the last part of the module. For example:\n\n      alias Foo.Bar.Baz\n\n  Is the same as:\n\n      alias Foo.Bar.Baz, as: Baz\n\n  We can also alias multiple modules in one line:\n\n      alias Foo.{Bar, Baz, Biz}\n\n  Is the same as:\n\n      alias Foo.Bar\n      alias Foo.Baz\n      alias Foo.Biz\n\n  ## Lexical scope\n\n  `import/2`, `require/2` and `alias/2` are called directives and all\n  have lexical scope. This means you can set up aliases inside\n  specific functions and it won't affect the overall scope.\n\n  ## Warnings\n\n  If you alias a module and you don't use the alias, Elixir is\n  going to issue a warning implying the alias is not being used.\n\n  In case the alias is generated automatically by a macro,\n  Elixir won't emit any warnings though, since the alias\n  was not explicitly defined.\n\n  Both warning behaviors could be changed by explicitly\n  setting the `:warn` option to `true` or `false`.\n\n  \"\"\"\n  defmacro alias(module, opts), do: error!([module, opts])\n\n  @doc \"\"\"\n  Requires a module in order to use its macros.\n\n  ## Examples\n\n  Public functions in modules are globally available, but in order to use\n  macros, you need to opt-in by requiring the module they are defined in.\n\n  Let's suppose you created your own `if/2` implementation in the module\n  `MyMacros`. If you want to invoke it, you need to first explicitly\n  require the `MyMacros`:\n\n      defmodule Math do\n        require MyMacros\n        MyMacros.if do_something, it_works\n      end\n\n  An attempt to call a macro that was not loaded will raise an error.\n\n  ## Alias shortcut\n\n  `require/2` also accepts `:as` as an option so it automatically sets\n  up an alias. Please check `alias/2` for more information.\n\n  \"\"\"\n  defmacro require(module, opts), do: error!([module, opts])\n\n  @doc \"\"\"\n  Imports functions and macros from other modules.\n\n  `import/2` allows one to easily access functions or macros from\n  other modules without using the qualified name.\n\n  ## Examples\n\n  If you are using several functions from a given module, you can\n  import those functions and reference them as local functions,\n  for example:\n\n      iex> import List\n      iex> flatten([1, [2], 3])\n      [1, 2, 3]\n\n  ## Selector\n\n  By default, Elixir imports functions and macros from the given\n  module, except the ones starting with an underscore (which are\n  usually callbacks):\n\n      import List\n\n  A developer can filter to import only functions, macros, or sigils\n  (which can be functions or macros) via the `:only` option:\n\n      import List, only: :functions\n      import List, only: :macros\n      import Kernel, only: :sigils\n\n  Alternatively, Elixir allows a developer to pass pairs of\n  name/arities to `:only` or `:except` as a fine grained control\n  on what to import (or not):\n\n      import List, only: [flatten: 1]\n      import String, except: [split: 2]\n\n  Importing the same module again will erase the previous imports,\n  except when the `except` option is used, which is always exclusive\n  on a previously declared `import/2`. If there is no previous import,\n  then it applies to all functions and macros in the module. For\n  example:\n\n      import List, only: [flatten: 1, keyfind: 4]\n      import List, except: [flatten: 1]\n\n  After the two import calls above, only `List.keyfind/4` will be\n  imported.\n\n  ## Underscore functions\n\n  By default functions starting with `_` are not imported. If you really want\n  to import a function starting with `_` you must explicitly include it in the\n  `:only` selector.\n\n      import File.Stream, only: [__build__: 3]\n\n  ## Lexical scope\n\n  It is important to note that `import/2` is lexical. This means you\n  can import specific macros inside specific functions:\n\n      defmodule Math do\n        def some_function do\n          # 1) Disable \"if/2\" from Kernel\n          import Kernel, except: [if: 2]\n\n          # 2) Require the new \"if/2\" macro from MyMacros\n          import MyMacros\n\n          # 3) Use the new macro\n          if do_something, it_works\n        end\n      end\n\n  In the example above, we imported macros from `MyMacros`,\n  replacing the original `if/2` implementation by our own\n  within that specific function. All other functions in that\n  module will still be able to use the original one.\n\n  ## Warnings\n\n  If you import a module and you don't use any of the imported\n  functions or macros from this module, Elixir is going to issue\n  a warning implying the import is not being used.\n\n  In case the import is generated automatically by a macro,\n  Elixir won't emit any warnings though, since the import\n  was not explicitly defined.\n\n  Both warning behaviors could be changed by explicitly\n  setting the `:warn` option to `true` or `false`.\n\n  ## Ambiguous function/macro names\n\n  If two modules `A` and `B` are imported and they both contain\n  a `foo` function with an arity of `1`, an error is only emitted\n  if an ambiguous call to `foo/1` is actually made; that is, the\n  errors are emitted lazily, not eagerly.\n  \"\"\"\n  defmacro import(module, opts), do: error!([module, opts])\n\n  @doc \"\"\"\n  Returns the current environment information as a `Macro.Env` struct.\n\n  In the environment you can access the current filename,\n  line numbers, set up aliases, the current function and others.\n  \"\"\"\n  defmacro __ENV__, do: error!([])\n\n  @doc \"\"\"\n  Returns the current module name as an atom or `nil` otherwise.\n\n  Although the module can be accessed in the `__ENV__/0`, this macro\n  is a convenient shortcut.\n  \"\"\"\n  defmacro __MODULE__, do: error!([])\n\n  @doc \"\"\"\n  Returns the absolute path of the directory of the current file as a binary.\n\n  Although the directory can be accessed as `Path.dirname(__ENV__.file)`,\n  this macro is a convenient shortcut.\n  \"\"\"\n  defmacro __DIR__, do: error!([])\n\n  @doc \"\"\"\n  Returns the current calling environment as a `Macro.Env` struct.\n\n  In the environment you can access the filename, line numbers,\n  set up aliases, the function and others.\n  \"\"\"\n  defmacro __CALLER__, do: error!([])\n\n  @doc \"\"\"\n  Returns the stacktrace for the currently handled exception.\n\n  It is available only in the `catch` and `rescue` clauses of `try/1`\n  expressions and function definitions.\n\n  To retrieve the stacktrace of the current process, use\n  `Process.info(self(), :current_stacktrace)` instead.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  defmacro __STACKTRACE__, do: error!([])\n\n  @doc \"\"\"\n  Pin operator. Accesses an already bound variable in match clauses.\n\n  ## Examples\n\n  Elixir allows variables to be rebound via static single assignment:\n\n      iex> x = 1\n      iex> x = x + 1\n      iex> x\n      2\n\n  However, in some situations, it is useful to match against an existing\n  value, instead of rebinding. This can be done with the `^` special form,\n  colloquially known as the pin operator:\n\n      iex> x = 1\n      iex> ^x = List.first([1])\n      iex> ^x = List.first([2])\n      ** (MatchError) no match of right hand side value:\n      ...\n\n  Note that `^x` always refers to the value of `x` prior to the match. The\n  following example will match:\n\n      iex> x = 0\n      iex> {x, ^x} = {1, 0}\n      iex> x\n      1\n\n  \"\"\"\n  defmacro ^var, do: error!([var])\n\n  @doc \"\"\"\n  Match operator. Matches the value on the right against the pattern on the left.\n  \"\"\"\n  defmacro left = right, do: error!([left, right])\n\n  @doc \"\"\"\n  Type operator. Used by types and bitstrings to specify types.\n\n  This operator is used in two distinct occasions in Elixir.\n  It is used in typespecs to specify the type of a variable,\n  function or of a type itself:\n\n      @type number :: integer | float\n      @spec add(number, number) :: number\n\n  It may also be used in bit strings to specify the type\n  of a given bit segment:\n\n      <<int::integer-little, rest::bits>> = bits\n\n  Read the documentation on the [Typespecs page](typespecs.md) and\n  `<<>>/1` for more information on typespecs and\n  bitstrings respectively.\n  \"\"\"\n  defmacro left :: right, do: error!([left, right])\n\n  @doc ~S\"\"\"\n  Gets the representation of any expression.\n\n  ## Examples\n\n      iex> quote do\n      ...>   sum(1, 2, 3)\n      ...> end\n      {:sum, [], [1, 2, 3]}\n\n  ## Elixir's AST (Abstract Syntax Tree)\n\n  Any Elixir code can be represented using Elixir data structures.\n  The building block of Elixir macros is a tuple with three elements,\n  for example:\n\n      {:sum, [], [1, 2, 3]}\n\n  The tuple above represents a function call to `sum` passing 1, 2 and\n  3 as arguments. The tuple elements are:\n\n    * The first element of the tuple is always an atom or\n      another tuple in the same representation.\n\n    * The second element of the tuple represents [metadata](`t:Macro.metadata/0`).\n\n    * The third element of the tuple are the arguments for the\n      function call. The third argument may be an atom, which is\n      usually a variable (or a local call).\n\n  Besides the tuple described above, Elixir has a few literals that\n  are also part of its AST. Those literals return themselves when\n  quoted. They are:\n\n      :sum         #=> Atoms\n      1            #=> Integers\n      2.0          #=> Floats\n      [1, 2]       #=> Lists\n      \"strings\"    #=> Strings\n      {key, value} #=> Tuples with two elements\n\n  Any other value, such as a map or a four-element tuple, must be escaped\n  (`Macro.escape/1`) before being introduced into an AST.\n\n  ## Options\n\n    * `:bind_quoted` - passes a binding to the macro. Whenever a binding is\n      given, `unquote/1` is automatically disabled.\n\n    * `:context` - sets the resolution context.\n\n    * `:generated` - marks the given chunk as generated so it does not emit warnings.\n      It is also useful to prevent the type system or dialyzer from reporting errors\n      when macros generate unused clauses.\n\n    * `:file` - sets the quoted expressions to have the given file.\n\n    * `:line` - sets the quoted expressions to have the given line.\n\n    * `:location` - when set to `:keep`, keeps the current line and file from\n      quote. Read the \"Stacktrace information\" section below for more information.\n\n    * `:unquote` - when `false`, disables unquoting. This means any `unquote`\n      call will be kept as is in the AST, instead of replaced by the `unquote`\n      arguments. For example:\n\n          iex> quote do\n          ...>   unquote(\"hello\")\n          ...> end\n          \"hello\"\n\n          iex> quote unquote: false do\n          ...>   unquote(\"hello\")\n          ...> end\n          {:unquote, [], [\"hello\"]}\n\n  ## Quote and macros\n\n  `quote/2` is commonly used with macros for code generation. As an exercise,\n  let's define a macro that multiplies a number by itself (squared). In practice,\n  there is no reason to define such a macro (and it would actually be\n  seen as a bad practice), but it is simple enough that it allows us to focus\n  on the important aspects of quotes and macros:\n\n      defmodule Math do\n        defmacro squared(x) do\n          quote do\n            unquote(x) * unquote(x)\n          end\n        end\n      end\n\n  We can invoke it as:\n\n      import Math\n      IO.puts(\"Got #{squared(5)}\")\n\n  At first, there is nothing in this example that actually reveals it is a\n  macro. But what is happening is that, at compilation time, `squared(5)`\n  becomes `5 * 5`. The argument `5` is duplicated in the produced code, we\n  can see this behavior in practice though because our macro actually has\n  a bug:\n\n      import Math\n      my_number = fn ->\n        IO.puts(\"Returning 5\")\n        5\n      end\n      IO.puts(\"Got #{squared(my_number.())}\")\n\n  The example above will print:\n\n      Returning 5\n      Returning 5\n      Got 25\n\n  Notice how \"Returning 5\" was printed twice, instead of just once. This is\n  because a macro receives an expression and not a value (which is what we\n  would expect in a regular function). This means that:\n\n      squared(my_number.())\n\n  Actually expands to:\n\n      my_number.() * my_number.()\n\n  Which invokes the function twice, explaining why we get the printed value\n  twice! In the majority of the cases, this is actually unexpected behavior,\n  and that's why one of the first things you need to keep in mind when it\n  comes to macros is to **not unquote the same value more than once**.\n\n  Let's fix our macro:\n\n      defmodule Math do\n        defmacro squared(x) do\n          quote do\n            x = unquote(x)\n            x * x\n          end\n        end\n      end\n\n  Now invoking `squared(my_number.())` as before will print the value just\n  once.\n\n  In fact, this pattern is so common that most of the times you will want\n  to use the `bind_quoted` option with `quote/2`:\n\n      defmodule Math do\n        defmacro squared(x) do\n          quote bind_quoted: [x: x] do\n            x * x\n          end\n        end\n      end\n\n  `:bind_quoted` will translate to the same code as the example above.\n  `:bind_quoted` can be used in many cases and is seen as good practice,\n  not only because it helps prevent us from running into common mistakes, but also\n  because it allows us to leverage other tools exposed by macros, such as\n  unquote fragments discussed in some sections below.\n\n  Before we finish this brief introduction, you will notice that, even though\n  we defined a variable `x` inside our quote:\n\n      quote do\n        x = unquote(x)\n        x * x\n      end\n\n  When we call:\n\n      import Math\n      squared(5)\n      x\n      ** (CompileError) undefined variable \"x\"\n\n  We can see that `x` did not leak to the user context. This happens\n  because Elixir macros are hygienic, a topic we will discuss at length\n  in the next sections as well.\n\n  ## Hygiene in variables\n\n  Consider the following example:\n\n      defmodule Hygiene do\n        defmacro no_interference do\n          quote do\n            a = 1\n          end\n        end\n      end\n\n      require Hygiene\n\n      a = 10\n      Hygiene.no_interference()\n      a\n      #=> 10\n\n  In the example above, `a` returns 10 even if the macro\n  is apparently setting it to 1 because variables defined\n  in the macro do not affect the context the macro is executed in.\n  If you want to set or get a variable in the caller's context, you\n  can do it with the help of the `var!` macro:\n\n      defmodule NoHygiene do\n        defmacro interference do\n          quote do\n            var!(a) = 1\n          end\n        end\n      end\n\n      require NoHygiene\n\n      a = 10\n      NoHygiene.interference()\n      a\n      #=> 1\n\n  You cannot even access variables defined in the same module unless\n  you explicitly give it a context:\n\n      defmodule Hygiene do\n        defmacro write do\n          quote do\n            a = 1\n          end\n        end\n\n        defmacro read do\n          quote do\n            a\n          end\n        end\n      end\n\n      require Hygiene\n      Hygiene.write()\n      Hygiene.read()\n      ** (CompileError) undefined variable \"a\" (context Hygiene)\n\n  For such, you can explicitly pass the current module scope as\n  argument:\n\n      defmodule ContextHygiene do\n        defmacro write do\n          quote do\n            var!(a, ContextHygiene) = 1\n          end\n        end\n\n        defmacro read do\n          quote do\n            var!(a, ContextHygiene)\n          end\n        end\n      end\n\n      require ContextHygiene\n      ContextHygiene.write()\n      ContextHygiene.read()\n      #=> 1\n\n  The contexts of a variable is identified by the third element of the tuple.\n  The default context is `nil` and `quote` assigns another context to all\n  variables within:\n\n      quote(do: var)\n      #=> {:var, [], Elixir}\n\n  In case of variables returned by macros, there may also be a `:counter` key\n  in the metadata, which is used to further refine its contexts and guarantee\n  isolation between macro invocations as seen in the previous example.\n\n  ## Hygiene in aliases\n\n  Aliases inside quote are hygienic by default.\n  Consider the following example:\n\n      defmodule Hygiene do\n        alias Map, as: M\n\n        defmacro no_interference do\n          quote do\n            M.new()\n          end\n        end\n      end\n\n      require Hygiene\n      Hygiene.no_interference()\n      #=> %{}\n\n  Note that, even though the alias `M` is not available\n  in the context the macro is expanded, the code above works\n  because `M` still expands to `Map`.\n\n  Similarly, even if we defined an alias with the same name\n  before invoking a macro, it won't affect the macro's result:\n\n      defmodule Hygiene do\n        alias Map, as: M\n\n        defmacro no_interference do\n          quote do\n            M.new()\n          end\n        end\n      end\n\n      require Hygiene\n      alias SomethingElse, as: M\n      Hygiene.no_interference()\n      #=> %{}\n\n  In some cases, you want to access an alias or a module defined\n  in the caller. For such, you can use the `alias!` macro:\n\n      defmodule Hygiene do\n        # This will expand to Elixir.Nested.hello()\n        defmacro no_interference do\n          quote do\n            Nested.hello()\n          end\n        end\n\n        # This will expand to Nested.hello() for\n        # whatever is Nested in the caller\n        defmacro interference do\n          quote do\n            alias!(Nested).hello()\n          end\n        end\n      end\n\n      defmodule Parent do\n        defmodule Nested do\n          def hello, do: \"world\"\n        end\n\n        require Hygiene\n        Hygiene.no_interference()\n        ** (UndefinedFunctionError) ...\n\n        Hygiene.interference()\n        #=> \"world\"\n      end\n\n  ## Hygiene in imports\n\n  Similar to aliases, imports in Elixir are hygienic. Consider the\n  following code:\n\n      defmodule Hygiene do\n        defmacrop get_length do\n          quote do\n            length([1, 2, 3])\n          end\n        end\n\n        def return_length do\n          import Kernel, except: [length: 1]\n          get_length\n        end\n      end\n\n      Hygiene.return_length()\n      #=> 3\n\n  Notice how `Hygiene.return_length/0` returns `3` even though the `Kernel.length/1`\n  function is not imported. In fact, even if `return_length/0`\n  imported a function with the same name and arity from another\n  module, it wouldn't affect the function result:\n\n      def return_length do\n        import String, only: [length: 1]\n        get_length\n      end\n\n  Calling this new `return_length/0` will still return `3` as result.\n\n  Elixir is smart enough to delay the resolution to the latest\n  possible moment. So, if you call `length([1, 2, 3])` inside quote,\n  but no `length/1` function is available, it is then expanded in\n  the caller:\n\n      defmodule Lazy do\n        defmacrop get_length do\n          import Kernel, except: [length: 1]\n\n          quote do\n            length(\"hello\")\n          end\n        end\n\n        def return_length do\n          import Kernel, except: [length: 1]\n          import String, only: [length: 1]\n          get_length\n        end\n      end\n\n      Lazy.return_length()\n      #=> 5\n\n  ## Stacktrace information\n\n  When defining functions via macros, developers have the option of\n  choosing if runtime errors will be reported from the caller or from\n  inside the quote. Let's see an example:\n\n      # adder.ex\n      defmodule Adder do\n        @doc \"Defines a function that adds two numbers\"\n        defmacro defadd do\n          quote location: :keep do\n            def add(a, b), do: a + b\n          end\n        end\n      end\n\n      # sample.ex\n      defmodule Sample do\n        import Adder\n        defadd\n      end\n\n      require Sample\n      Sample.add(:one, :two)\n      ** (ArithmeticError) bad argument in arithmetic expression\n          adder.ex:5: Sample.add/2\n\n  When using `location: :keep` and invalid arguments are given to\n  `Sample.add/2`, the stacktrace information will point to the file\n  and line inside the quote. Without `location: :keep`, the error is\n  reported to where `defadd` was invoked. `location: :keep` affects\n  only definitions inside the quote.\n\n  > #### `location: :keep` and unquote {: .warning}\n  >\n  > Do not use `location: :keep` if the function definition\n  > also `unquote`s some of the macro arguments. If you do so, Elixir\n  > will store the file definition of the current location but the\n  > unquoted arguments may contain line information of the macro caller,\n  > leading to erroneous stacktraces.\n\n  ## Binding and unquote fragments\n\n  Elixir quote/unquote mechanisms provide a functionality called\n  unquote fragments. Unquote fragments provide an easy way to generate\n  functions on the fly. Consider this example:\n\n      kv = [foo: 1, bar: 2]\n      Enum.each(kv, fn {k, v} ->\n        def unquote(k)(), do: unquote(v)\n      end)\n\n  In the example above, we have generated the functions `foo/0` and\n  `bar/0` dynamically. Note the parentheses in `unquote(k)()` are important,\n  otherwise we would try to define a function as `def :foo` instead of\n  `def foo()`.\n\n  Now, imagine that we want to convert this functionality into a macro:\n\n      defmacro defkv(kv) do\n        Enum.map(kv, fn {k, v} ->\n          quote do\n            def unquote(k)(), do: unquote(v)\n          end\n        end)\n      end\n\n  We can invoke this macro as:\n\n      defkv [foo: 1, bar: 2]\n\n  However, we can't invoke it as follows:\n\n      kv = [foo: 1, bar: 2]\n      defkv kv\n\n  This is because the macro is expecting its arguments to be a\n  keyword list at **compilation** time. Since in the example above\n  we are passing the representation of the variable `kv`, our\n  code fails.\n\n  This is actually a common pitfall when developing macros. We are\n  assuming a particular shape at compilation time, within the macro\n  implementation. One may try to work around it by unquoting the\n  variable inside the quoted expression:\n\n      defmacro defkv(kv) do\n        quote do\n          Enum.each(unquote(kv), fn {k, v} ->\n            def unquote(k)(), do: unquote(v)\n          end)\n        end\n      end\n\n  If you try to run our new macro, you will notice it won't\n  even compile, complaining that the variables `k` and `v`\n  do not exist. This is because the two `unquote`s in the call\n  above are meant to run at distinct moments: `unquote(kv)`\n  applies to the immediate quote, `unquote(k)` is an unquote\n  fragment.\n\n  One solution to this problem is to disable unquoting in the\n  macro, however, doing that would make it impossible to inject the\n  `kv` representation into the tree. That's when the `:bind_quoted`\n  option comes to the rescue (again!). By using `:bind_quoted`, we\n  can automatically disable unquoting while still injecting the\n  desired variables into the tree:\n\n      defmacro defkv(kv) do\n        quote bind_quoted: [kv: kv] do\n          Enum.each(kv, fn {k, v} ->\n            def unquote(k)(), do: unquote(v)\n          end)\n        end\n      end\n\n  In fact, the `:bind_quoted` option is recommended every time\n  one desires to inject a value into the quote.\n  \"\"\"\n  defmacro quote(opts, block), do: error!([opts, block])\n\n  @doc \"\"\"\n  Unquotes the given expression inside a quoted expression.\n\n  This function expects a valid Elixir AST, also known as\n  quoted expression, as argument. If you would like to `unquote`\n  any value, such as a map or a four-element tuple, you should\n  call `Macro.escape/1` before unquoting.\n\n  ## Examples\n\n  Imagine the situation you have a quoted expression and\n  you want to inject it inside some quote. The first attempt\n  would be:\n\n      value =\n        quote do\n          13\n        end\n\n      quote do\n        sum(1, value, 3)\n      end\n\n\n  Which the argument for the `:sum` function call is not the\n  expected result:\n\n      {:sum, [], [1, {:value, [], Elixir}, 3]}\n\n  For this, we use `unquote`:\n\n      iex> value =\n      ...>   quote do\n      ...>     13\n      ...>   end\n      iex> quote do\n      ...>   sum(1, unquote(value), 3)\n      ...> end\n      {:sum, [], [1, 13, 3]}\n\n  If you want to unquote a value that is not a quoted expression,\n  such as a map, you need to call `Macro.escape/1` before:\n\n      iex> value = %{foo: :bar}\n      iex> quote do\n      ...>   process_map(unquote(Macro.escape(value)))\n      ...> end\n      {:process_map, [], [{:%{}, [], [foo: :bar]}]}\n\n  If you forget to escape it, Elixir will raise an error\n  when compiling the code.\n  \"\"\"\n  defmacro unquote(:unquote)(expr), do: error!([expr])\n\n  @doc \"\"\"\n  Unquotes the given list expanding its arguments.\n\n  Similar to `unquote/1`.\n\n  ## Examples\n\n      iex> values = [2, 3, 4]\n      iex> quote do\n      ...>   sum(1, unquote_splicing(values), 5)\n      ...> end\n      {:sum, [], [1, 2, 3, 4, 5]}\n\n  Also can be used in block context, outside of function arguments.\n  Though, it is still required to be wrapped into parentheses.\n\n      iex> requires = for module <- [Integer, Logger] do\n      ...>   quote do\n      ...>     require unquote(module)\n      ...>   end\n      ...> end\n      iex> block = quote do: (unquote_splicing(requires))\n      iex> Macro.to_string(block)\n      \"require Integer\\\\nrequire Logger\"\n\n  \"\"\"\n  defmacro unquote(:unquote_splicing)(expr), do: error!([expr])\n\n  @doc ~S\"\"\"\n  Comprehensions allow you to quickly build a data structure from\n  an enumerable or a bitstring.\n\n  Let's start with an example:\n\n      iex> for n <- [1, 2, 3, 4], do: n * 2\n      [2, 4, 6, 8]\n\n  A comprehension accepts many generators and filters. `for` uses\n  the `<-` operator to extract values from the enumerable on its\n  right side and match them against the pattern on the left.\n  We call them generators:\n\n      # A list generator:\n      iex> for n <- [1, 2, 3, 4], do: n * 2\n      [2, 4, 6, 8]\n\n      # A comprehension with two generators\n      iex> for x <- [1, 2], y <- [2, 3], do: x * y\n      [2, 3, 4, 6]\n\n  Filters can also be given:\n\n      # A comprehension with a generator and a filter\n      iex> for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n\n      [2, 4, 6]\n\n  Filters must evaluate to truthy values (everything but `nil`\n  and `false`). If a filter is falsy, then the current value is\n  discarded.\n\n  Generators can also be used to filter as it removes any value\n  that doesn't match the pattern on the left side of `<-`:\n\n      iex> users = [user: \"john\", admin: \"meg\", guest: \"barbara\"]\n      iex> for {type, name} when type != :guest <- users do\n      ...>   String.upcase(name)\n      ...> end\n      [\"JOHN\", \"MEG\"]\n\n  Bitstring generators are also supported and are very useful when you\n  need to organize bitstring streams:\n\n      iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>\n      iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}\n      [{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]\n\n  Variable assignments inside the comprehension, be it in generators,\n  filters or inside the block, are not reflected outside of the\n  comprehension.\n\n  Variable assignments inside filters must still return a truthy value,\n  otherwise values are discarded. Let's see an example. Imagine you have\n  a keyword list where the key is a programming language and the value\n  is its direct parent. Then let's try to compute the grandparent of each\n  language. You could try this:\n\n      iex> languages = [elixir: :erlang, erlang: :prolog, prolog: nil]\n      iex> for {language, parent} <- languages, grandparent = languages[parent], do: {language, grandparent}\n      [elixir: :prolog]\n\n  Given the grandparents of Erlang and Prolog were nil, those values were\n  filtered out. If you don't want this behavior, a simple option is to\n  move the filter inside the do-block:\n\n      iex> languages = [elixir: :erlang, erlang: :prolog, prolog: nil]\n      iex> for {language, parent} <- languages do\n      ...>   grandparent = languages[parent]\n      ...>   {language, grandparent}\n      ...> end\n      [elixir: :prolog, erlang: nil, prolog: nil]\n\n  However, such option is not always available, as you may have further\n  filters. An alternative is to convert the filter into a generator by\n  wrapping the right side of `=` in a list:\n\n      iex> languages = [elixir: :erlang, erlang: :prolog, prolog: nil]\n      iex> for {language, parent} <- languages, grandparent <- [languages[parent]], do: {language, grandparent}\n      [elixir: :prolog, erlang: nil, prolog: nil]\n\n  ## The `:into` and `:uniq` options\n\n  In the examples above, the result returned by the comprehension was\n  always a list. The returned result can be configured by passing an\n  `:into` option, that accepts any structure as long as it implements\n  the `Collectable` protocol.\n\n  For example, we can use bitstring generators with the `:into` option\n  to easily remove all spaces in a string:\n\n      iex> for <<c <- \" hello world \">>, c != ?\\s, into: \"\", do: <<c>>\n      \"helloworld\"\n\n  The `IO` module provides streams, that are both `Enumerable` and\n  `Collectable`, here is an upcase echo server using comprehensions:\n\n      for line <- IO.stream(), into: IO.stream() do\n        String.upcase(line)\n      end\n\n  Similarly, `uniq: true` can also be given to comprehensions to guarantee\n  the results are only added to the collection if they were not returned\n  before. For example:\n\n      iex> for x <- [1, 1, 2, 3], uniq: true, do: x * 2\n      [2, 4, 6]\n\n      iex> for <<x <- \"abcabc\">>, uniq: true, into: \"\", do: <<x - 32>>\n      \"ABC\"\n\n  ## The `:reduce` option\n\n  *Available since Elixir v1.8*.\n\n  While the `:into` option allows us to customize the comprehension behavior\n  to a given data type, such as putting all of the values inside a map or inside\n  a binary, it is not always enough.\n\n  For example, imagine that you have a binary with letters where you want to\n  count how many times each lowercase letter happens, ignoring all uppercase\n  ones. For instance, for the string `\"AbCabCABc\"`, we want to return the map\n  `%{\"a\" => 1, \"b\" => 2, \"c\" => 1}`.\n\n  If we were to use `:into`, we would need a data type that computes the\n  frequency of each element it holds. While there is no such data type in\n  Elixir, you could implement one yourself.\n\n  A simpler option would be to use comprehensions for the mapping and\n  filtering of letters, and then we invoke `Enum.reduce/3` to build a map,\n  for example:\n\n      iex> letters = for <<x <- \"AbCabCABc\">>, x in ?a..?z, do: <<x>>\n      iex> Enum.reduce(letters, %{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)\n      %{\"a\" => 1, \"b\" => 2, \"c\" => 1}\n\n  While the above is straight-forward, it has the downside of traversing the\n  data at least twice. If you are expecting long strings as inputs, this can\n  be quite expensive.\n\n  Luckily, comprehensions also support the `:reduce` option, which would allow\n  us to fuse both steps above into a single step:\n\n      iex> for <<x <- \"AbCabCABc\">>, x in ?a..?z, reduce: %{} do\n      ...>   acc -> Map.update(acc, <<x>>, 1, & &1 + 1)\n      ...> end\n      %{\"a\" => 1, \"b\" => 2, \"c\" => 1}\n\n  When the `:reduce` key is given, its value is used as the initial accumulator\n  and the `do` block must be changed to use `->` clauses, where the left side\n  of `->` receives the accumulated value of the previous iteration and the\n  expression on the right side must return the new accumulator value. Once there are no more\n  elements, the final accumulated value is returned. If there are no elements\n  at all, then the initial accumulator value is returned.\n  \"\"\"\n  defmacro for(args), do: error!([args])\n\n  @doc \"\"\"\n  Combine matching clauses.\n\n  One of the ways to understand `with` is to show which code\n  patterns it improves. Imagine you have a map where the fields\n  `width` and `height` are optional and you want to compute its\n  area, as `{:ok, area}` or return `:error`. We could implement\n  this function as:\n\n      def area(opts) do\n        case Map.fetch(opts, :width) do\n          {:ok, width} ->\n            case Map.fetch(opts, :height) do\n              {:ok, height} -> {:ok, width * height}\n              :error -> :error\n            end\n\n          :error ->\n            :error\n        end\n      end\n\n  when called as `area(%{width: 10, height: 15})`, it should return\n  `{:ok, 150}`. If any of the fields are missing, it returns `:error`.\n\n  While the code above works, it is quite verbose. Using `with`,\n  we could rewrite it as:\n\n      def area(opts) do\n        with {:ok, width} <- Map.fetch(opts, :width),\n             {:ok, height} <- Map.fetch(opts, :height) do\n          {:ok, width * height}\n        end\n      end\n\n  Instead of defining nested `case`s with clauses, we use `with`\n  alongside the `PATTERN <- EXPRESSION` operator to match\n  expressions on its right side against the pattern on the left.\n  Consider `<-` as a sibling to `=`, except that, while `=` raises\n  in case of not matches, `<-` will simply abort the `with` chain\n  and return the non-matched value.\n\n  Let's give it a try on IEx:\n\n      iex> opts = %{\"width\" => 10, \"height\" => 15}\n      iex> with {:ok, width} <- Map.fetch(opts, \"width\"),\n      ...>      {:ok, height} <- Map.fetch(opts, \"height\") do\n      ...>   {:ok, width * height}\n      ...> end\n      {:ok, 150}\n\n  If all clauses match, the `do` block is executed, returning its result.\n  Otherwise the chain is aborted and the non-matched value is returned:\n\n      iex> opts = %{\"width\" => 10}\n      iex> with {:ok, width} <- Map.fetch(opts, \"width\"),\n      ...>      {:ok, height} <- Map.fetch(opts, \"height\") do\n      ...>   {:ok, width * height}\n      ...> end\n      :error\n\n  As in `for/1`, variables bound inside `with/1` won't be accessible\n  outside of `with/1`.\n\n  Expressions without `<-` may also be used in clauses. For instance,\n  you can perform regular matches with the `=` operator:\n\n      iex> width = nil\n      iex> opts = %{width: 10, height: 15}\n      iex> with {:ok, width} <- Map.fetch(opts, :width),\n      ...>      double_width = width * 2,\n      ...>      {:ok, height} <- Map.fetch(opts, :height) do\n      ...>   {:ok, double_width * height}\n      ...> end\n      {:ok, 300}\n      iex> width\n      nil\n\n  The behavior of any expression in a clause is the same as if it was\n  written outside of `with`. For example, `=` will raise a `MatchError`\n  instead of returning the non-matched value:\n\n      with :foo = :bar, do: :ok\n      ** (MatchError) no match of right hand side value: :bar\n\n  As with any other function or macro call in Elixir, explicit parens can\n  also be used around the arguments before the `do`-`end` block:\n\n      iex> opts = %{width: 10, height: 15}\n      iex> with(\n      ...>   {:ok, width} <- Map.fetch(opts, :width),\n      ...>   {:ok, height} <- Map.fetch(opts, :height)\n      ...> ) do\n      ...>   {:ok, width * height}\n      ...> end\n      {:ok, 150}\n\n  The choice between parens and no parens is a matter of preference.\n\n  ## Else clauses\n\n  An `else` option can be given to modify what is being returned from\n  `with` in the case of a failed match:\n\n      with {:ok, content} <- File.read(path),\n           :ok <- File.write(path, [content, \"!\"]) do\n        :ok\n      else\n        {:error, reason} ->\n          Logger.error(\"could not append ! to \\#{path} with reason: \\#{reason}\")\n          :error\n      end\n\n  The `else` block works like a `case`: it can have multiple clauses,\n  and the first match will be used. Variables bound inside `with`\n  (such as `content` in this example) are not available in the `else` block.\n\n  If an `else` block is used and there are no matching clauses, a `WithClauseError`\n  exception is raised.\n\n  ### Beware!\n\n  Keep in mind that, one of potential drawback of `with` is that all\n  failure clauses are flattened into a single `else` block. For example,\n  take this code that checks if a given path points to an Elixir file\n  and that it exists before creating a backup copy:\n\n      with \".ex\" <- Path.extname(path),\n           true <- File.exists?(path) do\n        backup_path = path <> \".backup\"\n        File.cp!(path, backup_path)\n        {:ok, backup_path}\n      else\n        binary when is_binary(binary) ->\n          {:error, :invalid_extension}\n\n        false ->\n          {:error, :missing_file}\n      end\n\n  Note how we are having to reconstruct the result types of `Path.extname/1`\n  and `File.exists?/1` to build error messages. In this case, it is better\n  to refactor the code so each `<-` already return the desired format in case\n  of errors, like this:\n\n      with :ok <- validate_extension(path),\n           :ok <- validate_exists(path) do\n        backup_path = path <> \".backup\"\n        File.cp!(path, backup_path)\n        {:ok, backup_path}\n      end\n\n      defp validate_extension(path) do\n        if Path.extname(path) == \".ex\", do: :ok, else: {:error, :invalid_extension}\n      end\n\n      defp validate_exists(path) do\n        if File.exists?(path), do: :ok, else: {:error, :missing_file}\n      end\n\n  Note how the code above is better organized and clearer once we\n  make sure each `<-` in `with` returns a normalized format.\n  \"\"\"\n  defmacro with(args), do: error!([args])\n\n  @doc \"\"\"\n  Defines an anonymous function.\n\n  See `Function` for more information.\n\n  ## Examples\n\n      iex> add = fn a, b -> a + b end\n      iex> add.(1, 2)\n      3\n\n  Anonymous functions can also have multiple clauses. All clauses\n  should expect the same number of arguments:\n\n      iex> negate = fn\n      ...>   true -> false\n      ...>   false -> true\n      ...> end\n      iex> negate.(false)\n      true\n\n  \"\"\"\n  defmacro unquote(:fn)(clauses), do: error!([clauses])\n\n  @doc \"\"\"\n  Internal special form for block expressions.\n\n  This is the special form used whenever we have a block\n  of expressions in Elixir. This special form is private\n  and should not be invoked directly:\n\n      iex> quote do\n      ...>   1\n      ...>   2\n      ...>   3\n      ...> end\n      {:__block__, [], [1, 2, 3]}\n\n  \"\"\"\n  defmacro unquote(:__block__)(args), do: error!([args])\n\n  @doc \"\"\"\n  Internal special form for cursor position.\n\n  This is the special form used whenever we need to represent\n  the cursor position in Elixir's AST. See `Code.Fragment` for\n  more information.\n  \"\"\"\n  defmacro unquote(:__cursor__)(args), do: error!([args])\n\n  @doc \"\"\"\n  Capture operator. Captures or creates an anonymous function.\n\n  ## Capture\n\n  The capture operator is most commonly used to capture a\n  function with given name and arity from a module:\n\n      iex> fun = &Kernel.is_atom/1\n      iex> fun.(:atom)\n      true\n      iex> fun.(\"string\")\n      false\n\n  In the example above, we captured `Kernel.is_atom/1` as an\n  anonymous function and then invoked it.\n\n  The capture operator can also be used to capture local functions,\n  including private ones, and imported functions by omitting the\n  module name:\n\n      &local_function/1\n\n  Note that `&local_function/1` creates a local capture, but\n  `&__MODULE__.local_function/1` or `&imported_function/1` create a remote\n  capture. For more information, refer to the [\"Functions\" section in the Erlang Reference Manual](https://www.erlang.org/doc/system/eff_guide_functions.html#function-calls).\n\n  Whether a capture is local or remote has implications when using hot code\n  reloading: local captures dispatch to the version of the module that existed\n  at the time they were created, while remote captures dispatch to the current\n  version of the module.\n\n  See also `Function.capture/3`.\n\n  ## Anonymous functions\n\n  The capture operator can also be used to partially apply\n  functions, where `&1`, `&2` and so on can be used as value\n  placeholders. For example:\n\n      iex> double = &(&1 * 2)\n      iex> double.(2)\n      4\n\n  In other words, `&(&1 * 2)` is equivalent to `fn x -> x * 2 end`.\n\n  We can partially apply a remote function with placeholder:\n\n      iex> take_five = &Enum.take(&1, 5)\n      iex> take_five.(1..10)\n      [1, 2, 3, 4, 5]\n\n  Another example while using an imported or local function:\n\n      iex> first_elem = &elem(&1, 0)\n      iex> first_elem.({0, 1})\n      0\n\n  The `&` operator can be used with more complex expressions:\n\n      iex> fun = &(&1 + &2 + &3)\n      iex> fun.(1, 2, 3)\n      6\n\n  As well as with lists and tuples:\n\n      iex> fun = &{&1, &2}\n      iex> fun.(1, 2)\n      {1, 2}\n\n      iex> fun = &[&1 | &2]\n      iex> fun.(1, [2, 3])\n      [1, 2, 3]\n\n  The only restrictions when creating anonymous functions is that at\n  least one placeholder must be present, i.e. it must contain at least\n  `&1`, and that block expressions are not supported:\n\n      # No placeholder, fails to compile.\n      &(:foo)\n\n      # Block expression, fails to compile.\n      &(&1; &2)\n\n  \"\"\"\n  defmacro unquote(:&)(expr), do: error!([expr])\n\n  @doc \"\"\"\n  Internal special form to hold aliases information.\n\n  It is usually compiled to an atom:\n\n      iex> quote do\n      ...>   Foo.Bar\n      ...> end\n      {:__aliases__, [alias: false], [:Foo, :Bar]}\n\n  Elixir represents `Foo.Bar` as `__aliases__` so calls can be\n  unambiguously identified by the operator `:.`. For example:\n\n      iex> quote do\n      ...>   Foo.bar()\n      ...> end\n      {{:., [], [{:__aliases__, [alias: false], [:Foo]}, :bar]}, [], []}\n\n  Whenever an expression iterator sees a `:.` as the tuple key,\n  it can be sure that it represents a call and the second argument\n  in the list is an atom.\n\n  On the other hand, aliases hold some properties:\n\n    1. The head element of aliases can be any term that must expand to\n       an atom at compilation time.\n\n    2. The tail elements of aliases are guaranteed to always be atoms.\n\n    3. When the head element of aliases is the atom `:Elixir`, no expansion happens.\n\n  \"\"\"\n  defmacro unquote(:__aliases__)(args), do: error!([args])\n\n  @doc \"\"\"\n  Calls the overridden function when overriding it with `Kernel.defoverridable/1`.\n\n  See `Kernel.defoverridable/1` for more information and documentation.\n  \"\"\"\n  defmacro super(args), do: error!([args])\n\n  @doc ~S\"\"\"\n  Matches the given expression against the given clauses.\n\n  `case/2` relies on pattern matching and guards to choose\n  which clause to execute. If your logic cannot be expressed\n  within patterns and guards, consider using `if/2` or `cond/1`\n  instead.\n\n  ## Examples\n\n      iex> string_date = \"2015-01-23\"\n      iex> case Date.from_iso8601(string_date) do\n      ...>   {:ok, date} -> date\n      ...>   {:error, _reason} -> Date.utc_today()\n      ...> end\n      ~D[2015-01-23]\n\n  In the example above, we match the result of `Date.from_iso8601/1`\n  against each clause \"head\" and execute the clause \"body\"\n  corresponding to the first clause that matches. In our case\n  `string_date` contains a string with a valid ISO 8601 representation\n  of date. The function returns `{:ok, ~D[2015-01-23]}`, so the\n  `{:ok, date}` clause is matched.\n\n  If no clause matches, an error is raised. For this reason,\n  it may be necessary to add a final catch-all clause (like `_`)\n  which will always match.\n\n      iex> x = 10\n      iex> case x do\n      ...>   0 -> \"This clause won't match\"\n      ...>   _ -> \"This clause would match any value (x = #{x})\"\n      ...> end\n      \"This clause would match any value (x = 10)\"\n\n  If you find yourself nesting `case` expressions inside\n  `case` expressions, consider using `with/1`.\n\n  ## Variable handling\n\n  Note that variables bound in a clause do not leak to the outer context:\n\n      iex> case {:ok, 7} do\n      ...>   {:ok, value} -> value\n      ...>   :error -> nil\n      ...> end\n\n      ...> value\n      ** (CompileError) undefined variable \"value\"\n\n  Variables in the outer context cannot be overridden either:\n\n      iex> value = 7\n      iex> case 3 > 5 do\n      ...>   false ->\n      ...>     value = 3\n      ...>     value + 2\n      ...>   true ->\n      ...>     3\n      ...> end\n      iex> value\n      7\n\n  In the example above, `value` is going to be `7` regardless of\n  which clause matched. The variable `value` bound in the clause\n  and the variable `value` bound in the outer context are two\n  entirely separate variables.\n\n  If you want to pattern match against an existing variable,\n  you need to use the `^/1` operator:\n\n      iex> x = 1\n      iex> case 10 do\n      ...>   ^x -> \"Won't match\"\n      ...>   _ -> \"Will match\"\n      ...> end\n      \"Will match\"\n\n  ## Using guards to match against multiple values\n\n  While it is not possible to match against multiple patterns in a single\n  clause, it's possible to match against multiple values by using guards:\n\n      iex> case 2 do\n      ...>   value when value in [1, 2] ->\n      ...>     \"#{value} has been matched\"\n      ...>   3 ->\n      ...>     \"3 has been matched\"\n      ...> end\n      \"2 has been matched\"\n  \"\"\"\n  defmacro case(condition, clauses), do: error!([condition, clauses])\n\n  @doc \"\"\"\n  Evaluates the expression corresponding to the first clause that\n  evaluates to a truthy value.\n\n  ## Examples\n\n  The following example has a single clause that always evaluates\n  to true:\n\n      iex> cond do\n      ...>   hd([1, 2, 3]) -> \"1 is considered as true\"\n      ...> end\n      \"1 is considered as true\"\n\n  If all clauses evaluate to `nil` or `false`, `cond` raises an error.\n  For this reason, it may be necessary to add a final always-truthy condition\n  (anything non-`false` and non-`nil`), which will always match:\n\n      iex> cond do\n      ...>   1 + 1 == 1 -> \"This will never match\"\n      ...>   2 * 2 != 4 -> \"Nor this\"\n      ...>   true -> \"This will\"\n      ...> end\n      \"This will\"\n\n\n  If your `cond` has two clauses, and the last one falls back to\n  `true`, you may consider using `if/2` instead.\n  \"\"\"\n  defmacro cond(clauses), do: error!([clauses])\n\n  @doc ~S\"\"\"\n  Evaluates the given expressions and handles any error, exit,\n  or throw that may have happened.\n\n  ## Examples\n\n      try do\n        do_something_that_may_fail(some_arg)\n      rescue\n        ArgumentError ->\n          IO.puts(\"Invalid argument given\")\n      catch\n        value ->\n          IO.puts(\"Caught #{inspect(value)}\")\n      else\n        value ->\n          IO.puts(\"Success! The result was #{inspect(value)}\")\n      after\n        IO.puts(\"This is printed regardless if it failed or succeeded\")\n      end\n\n  The `rescue` clause is used to handle exceptions while the `catch`\n  clause can be used to catch thrown values and exits.\n  The `else` clause can be used to control flow based on the result of\n  the expression. `catch`, `rescue`, and `else` clauses work based on\n  pattern matching (similar to the `case` special form).\n\n  Calls inside `try/1` are not tail recursive since the VM needs to keep\n  the stacktrace in case an exception happens. To retrieve the stacktrace,\n  access `__STACKTRACE__/0` inside the `rescue` or `catch` clause.\n\n  ## `rescue` clauses\n\n  Besides relying on pattern matching, `rescue` clauses provide some\n  conveniences around exceptions that allow one to rescue an\n  exception by its name. All the following formats are valid patterns\n  in `rescue` clauses:\n\n  Rescue a single exception without binding the exception to a variable:\n\n      iex> try do\n      ...>   1 / 0\n      ...> rescue\n      ...>   ArithmeticError -> :rescued\n      ...> end\n      :rescued\n\n  Rescue any of the given exception without binding:\n\n      iex> try do\n      ...>   1 / 0\n      ...> rescue\n      ...>   [ArithmeticError, ArgumentError] -> :rescued\n      ...> end\n      :rescued\n\n  Rescue and bind the exception to the variable `x`:\n\n      iex> try do\n      ...>   1 / 0\n      ...> rescue\n      ...>   x in [ArithmeticError] -> [:rescued, is_exception(x)]\n      ...> end\n      [:rescued, true]\n\n  Rescue different errors with separate clauses:\n\n      iex> try do\n      ...>   1 / 0\n      ...> rescue\n      ...>   ArgumentError -> :rescued_argument_error\n      ...>   ArithmeticError -> :rescued_arithmetic_error\n      ...> end\n      :rescued_arithmetic_error\n\n  Rescue all kinds of exceptions and bind the rescued exception\n  to the variable `x`:\n\n      iex> try do\n      ...>   1 / 0\n      ...> rescue\n      ...>   x -> [:rescued, is_exception(x)]\n      ...> end\n      [:rescued, true]\n\n\n  ### Erlang errors\n\n  Erlang errors are transformed into Elixir ones when rescuing:\n\n      iex> try do\n      ...>   :erlang.error(:badarg)\n      ...> rescue\n      ...>   ArgumentError -> :rescued\n      ...> end\n      :rescued\n\n  The most common Erlang errors will be transformed into their\n  Elixir counterpart. Those which are not will be transformed\n  into the more generic `ErlangError`:\n\n      iex> try do\n      ...>   :erlang.error(:unknown)\n      ...> rescue\n      ...>   ErlangError -> :rescued\n      ...> end\n      :rescued\n\n  In fact, `ErlangError` can be used to rescue any error that is\n  not a proper Elixir error. For example, it can be used to rescue\n  the earlier `:badarg` error too, prior to transformation:\n\n      iex> try do\n      ...>   :erlang.error(:badarg)\n      ...> rescue\n      ...>   ErlangError -> :rescued\n      ...> end\n      :rescued\n\n  ## `catch` clauses\n\n  The `catch` clause can be used to catch thrown values, exits, and errors.\n\n  ### Catching thrown values\n\n  `catch` can be used to catch values thrown by `Kernel.throw/1`:\n\n      iex> try do\n      ...>   throw(:some_value)\n      ...> catch\n      ...>   thrown_value ->\n      ...>     \"Thrown value: #{inspect(thrown_value)}\"\n      ...> end\n      \"Thrown value: :some_value\"\n\n  ### Catching values of any kind\n\n  The `catch` clause also supports catching exits and errors. To do that, it\n  allows matching on both the *kind* of the caught value as well as the value\n  itself:\n\n      iex> try do\n      ...>   exit(:shutdown)\n      ...> catch\n      ...>   :exit, value ->\n      ...>     \"Exited with value #{inspect(value)}\"\n      ...> end\n      \"Exited with value :shutdown\"\n\n      iex> try do\n      ...>   exit(:shutdown)\n      ...> catch\n      ...>   kind, value when kind in [:exit, :throw] ->\n      ...>     \"Caught exit or throw with value #{inspect(value)}\"\n      ...> end\n      \"Caught exit or throw with value :shutdown\"\n\n  The `catch` clause also supports `:error` alongside `:exit` and `:throw` as\n  in Erlang, although this is commonly avoided in favor of `raise`/`rescue` control\n  mechanisms. One reason for this is that when catching `:error`, the error is\n  not automatically transformed into an Elixir error:\n\n      iex> try do\n      ...>   :erlang.error(:badarg)\n      ...> catch\n      ...>   :error, :badarg -> :rescued\n      ...> end\n      :rescued\n\n  ## `after` clauses\n\n  An `after` clause allows you to define cleanup logic that will be invoked both\n  when the block of code passed to `try/1` succeeds and also when an error is raised. Note\n  that the process will exit as usual when receiving an exit signal that causes\n  it to exit abruptly and so the `after` clause is not guaranteed to be executed.\n  Luckily, most resources in Elixir (such as open files, ETS tables, ports, sockets,\n  and so on) are linked to or monitor the owning process and will automatically clean\n  themselves up if that process exits.\n\n      File.write!(\"tmp/story.txt\", \"Hello, World\")\n      try do\n        do_something_with(\"tmp/story.txt\")\n      after\n        File.rm(\"tmp/story.txt\")\n      end\n\n  Although `after` clauses are invoked whether or not there was an error, they do not\n  modify the return value. Both of the following examples print a message to STDOUT\n  and return `:returned`:\n\n      try do\n        :returned\n      after\n        IO.puts(\"This message will be printed\")\n        :not_returned\n      end\n      #=> :returned\n\n      try do\n        raise \"boom\"\n      rescue\n        _ -> :returned\n      after\n        IO.puts(\"This message will be printed\")\n        :not_returned\n      end\n      #=> :returned\n\n  ## `else` clauses\n\n  `else` clauses allow the result of the body passed to `try/1` to be pattern\n  matched on:\n\n      iex> x = 2\n      ...> try do\n      ...>   1 / x\n      ...> rescue\n      ...>   ArithmeticError -> :infinity\n      ...> else\n      ...>   y when y < 1 and y > -1 -> :small\n      ...>   _ -> :large\n      ...> end\n      :small\n\n  If an `else` clause is not present and no exceptions are raised,\n  the result of the expression will be returned:\n\n      iex> x = 5\n      iex> try do\n      ...>   1 / x\n      ...> rescue\n      ...>   ArithmeticError -> :infinity\n      ...> end\n      0.2\n\n  However, when an `else` clause is present but the result of the expression\n  does not match any of the patterns then an exception will be raised. This\n  exception will not be caught by a `catch` or `rescue` in the same `try`:\n\n      iex> x = 1\n      iex> try do\n      ...>   try do\n      ...>     1 / x\n      ...>   rescue\n      ...>     # The TryClauseError cannot be rescued here:\n      ...>     TryClauseError -> :error_a\n      ...>   else\n      ...>      0.5 -> :small\n      ...>   end\n      ...> rescue\n      ...>   # The TryClauseError is rescued here:\n      ...>   TryClauseError -> :error_b\n      ...> end\n      :error_b\n\n  Similarly, an exception inside an `else` clause is not caught or rescued\n  inside the same `try`:\n\n      iex> x = 1\n      iex> try do\n      ...>   try do\n      ...>     1 / x\n      ...>   catch\n      ...>     # The exit(1) call below can not be caught here:\n      ...>     :exit, _ -> :exit_a\n      ...>   else\n      ...>     _ -> exit(1)\n      ...>   end\n      ...> catch\n      ...>   # The exit is caught here:\n      ...>   :exit, _ -> :exit_b\n      ...> end\n      :exit_b\n\n  This means the VM no longer needs to keep the stacktrace once inside\n  an `else` clause and so tail recursion is possible when using a `try`\n  with a tail call as the final call inside an `else` clause. The same\n  is true for `rescue` and `catch` clauses.\n\n  Only the result of the tried expression falls down to the `else` clause.\n  If the `try` ends up in the `rescue` or `catch` clauses, their result\n  will not fall down to `else`:\n\n      iex> try do\n      ...>   throw(:catch_this)\n      ...> catch\n      ...>   :throw, :catch_this -> :it_was_caught\n      ...> else\n      ...>   # :it_was_caught will not fall down to this \"else\" clause.\n      ...>   other -> {:else, other}\n      ...> end\n      :it_was_caught\n\n  ## Variable handling\n\n  Since an expression inside `try` may not have been evaluated\n  due to an exception, any variable created inside `try` cannot\n  be accessed externally. For instance:\n\n      try do\n        x = 1\n        do_something_that_may_fail(same_arg)\n        :ok\n      catch\n        _, _ -> :failed\n      end\n\n      x\n      #=> unbound variable \"x\"\n\n  In the example above, `x` cannot be accessed since it was defined\n  inside the `try` clause. A common practice to address this issue\n  is to return the variables defined inside `try`:\n\n      x =\n        try do\n          x = 1\n          do_something_that_may_fail(same_arg)\n          x\n        catch\n          _, _ -> :failed\n        end\n\n  \"\"\"\n  defmacro try(args), do: error!([args])\n\n  @doc \"\"\"\n  Consumes the first message matching any of the given clauses in the current\n  process mailbox.\n\n  If there is no matching message, the current process waits until a matching\n  message arrives or until after a given timeout value.\n\n  Any new and existing messages that do not match will remain in the mailbox.\n\n  ## Examples\n      iex> send(self(), {:selector, 5, :quantity})\n      iex> receive do\n      ...>   {:selector, number, name} when is_integer(number) ->\n      ...>     name\n      ...>   name when is_atom(name) ->\n      ...>     name\n      ...>   _ ->\n      ...>     IO.puts(:stderr, \"Unexpected message received\")\n      ...> end\n      :quantity\n\n  An optional `after` clause can be given in case no matching message is\n  received during the given timeout period, specified in milliseconds:\n\n      iex> receive do\n      ...>   {:selector, number, name} when is_integer(number) ->\n      ...>     name\n      ...>   name when is_atom(name) ->\n      ...>     name\n      ...>   _ ->\n      ...>     IO.puts(:stderr, \"Unexpected message received\")\n      ...> after\n      ...>   10 ->\n      ...>     \"No message in 10 milliseconds\"\n      ...> end\n      \"No message in 10 milliseconds\"\n\n  The `after` clause can be specified even if there are no match clauses.\n  The timeout value given to `after` can be any expression evaluating to\n  one of the allowed values:\n\n    * `:infinity` - the process should wait indefinitely for a matching\n      message, this is the same as not using the after clause\n\n    * `0` - if there is no matching message in the mailbox, the timeout\n      will occur immediately\n\n    * positive integer smaller than or equal to `4_294_967_295` (`0xFFFFFFFF`\n      in hexadecimal notation) - it should be possible to represent the timeout\n      value as an unsigned 32-bit integer.\n\n  ## Variable handling\n\n  The `receive/1` special form handles variables exactly as the `case/2`\n  special macro. For more information, check the docs for `case/2`.\n  \"\"\"\n  defmacro receive(args), do: error!([args])\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel/typespec.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Kernel.Typespec do\n  @moduledoc false\n\n  ## Deprecated API moved to Code.Typespec\n\n  @doc false\n  @deprecated \"Use Code.Typespec.spec_to_quoted/2 instead\"\n  def spec_to_ast(name, spec) do\n    Code.Typespec.spec_to_quoted(name, spec)\n  end\n\n  @doc false\n  @deprecated \"Use Code.Typespec.type_to_quoted/1 instead\"\n  def type_to_ast(type) do\n    Code.Typespec.type_to_quoted(type)\n  end\n\n  @doc false\n  @deprecated \"Use Code.fetch_docs/1 instead\"\n  def beam_typedocs(module) when is_atom(module) or is_binary(module) do\n    case Code.fetch_docs(module) do\n      {:docs_v1, _, _, _, _, _, docs} ->\n        for {{:type, name, arity}, _, _, doc, _} <- docs do\n          case doc do\n            %{\"en\" => doc_string} -> {{name, arity}, doc_string}\n            :hidden -> {{name, arity}, false}\n            _ -> {{name, arity}, nil}\n          end\n        end\n\n      {:error, _} ->\n        nil\n    end\n  end\n\n  @doc false\n  @deprecated \"Use Code.Typespec.fetch_types/1 instead\"\n  def beam_types(module) when is_atom(module) or is_binary(module) do\n    case Code.Typespec.fetch_types(module) do\n      {:ok, types} -> types\n      :error -> nil\n    end\n  end\n\n  @doc false\n  @deprecated \"Use Code.Typespec.fetch_specs/1 instead\"\n  def beam_specs(module) when is_atom(module) or is_binary(module) do\n    case Code.Typespec.fetch_specs(module) do\n      {:ok, specs} -> specs\n      :error -> nil\n    end\n  end\n\n  @doc false\n  @deprecated \"Use Code.Typespec.fetch_callbacks/1 instead\"\n  def beam_callbacks(module) when is_atom(module) or is_binary(module) do\n    case Code.Typespec.fetch_callbacks(module) do\n      {:ok, callbacks} -> callbacks\n      :error -> nil\n    end\n  end\n\n  ## Hooks for Module functions\n\n  def defines_type?(module, {name, arity} = signature)\n      when is_atom(module) and is_atom(name) and arity in 0..255 do\n    {_set, bag} = :elixir_module.data_tables(module)\n\n    finder = fn {_kind, expr, _caller} ->\n      type_to_signature(expr) == signature\n    end\n\n    :lists.any(finder, get_typespecs(bag, [:type, :opaque, :typep]))\n  end\n\n  def spec_to_callback(module, {name, arity} = signature)\n      when is_atom(module) and is_atom(name) and arity in 0..255 do\n    {set, bag} = :elixir_module.data_tables(module)\n\n    filter = fn {:spec, expr, pos} ->\n      if spec_to_signature(expr) == signature do\n        kind = :callback\n        store_typespec(bag, kind, expr, pos)\n\n        case :ets.lookup(set, {:function, name, arity}) do\n          [{{:function, ^name, ^arity}, _, line, _, doc, doc_meta}] ->\n            store_doc(set, kind, name, arity, line, :doc, doc, doc_meta)\n\n          _ ->\n            nil\n        end\n\n        true\n      else\n        false\n      end\n    end\n\n    :lists.filter(filter, get_typespecs(bag, :spec)) != []\n  end\n\n  ## Typespec definition and storage\n\n  @doc \"\"\"\n  Defines a typespec.\n\n  Invoked by `@/1` expansion.\n  \"\"\"\n  def deftypespec(:spec, expr, _line, _file, module, pos) do\n    {_set, bag} = :elixir_module.data_tables(module)\n    store_typespec(bag, :spec, expr, pos)\n  end\n\n  def deftypespec(kind, expr, line, _file, module, pos)\n      when kind in [:callback, :macrocallback] do\n    {set, bag} = :elixir_module.data_tables(module)\n\n    case spec_to_signature(expr) do\n      {name, arity} ->\n        # store doc only once in case callback has multiple clauses\n        if not :ets.member(set, {kind, name, arity}) do\n          {line, doc} = get_doc_info(set, :doc, line)\n          store_doc(set, kind, name, arity, line, :doc, doc, %{})\n        end\n\n      :error ->\n        :error\n    end\n\n    store_typespec(bag, kind, expr, pos)\n  end\n\n  @reserved_signatures [required: 1, optional: 1]\n  def deftypespec(kind, expr, line, file, module, pos)\n      when kind in [:type, :typep, :opaque] do\n    {set, bag} = :elixir_module.data_tables(module)\n\n    case type_to_signature(expr) do\n      {name, arity} = signature when signature in @reserved_signatures ->\n        compile_error(\n          :elixir_module.get_cached_env(pos),\n          \"type #{name}/#{arity} is a reserved type and it cannot be defined\"\n        )\n\n      {name, arity} when kind == :typep ->\n        {line, doc} = get_doc_info(set, :typedoc, line)\n\n        if doc do\n          warning =\n            \"type #{name}/#{arity} is private, @typedoc's are always discarded for private types\"\n\n          IO.warn(warning, file: file, line: line)\n        end\n\n      {name, arity} ->\n        {line, doc} = get_doc_info(set, :typedoc, line)\n        spec_meta = if kind == :opaque, do: %{opaque: true}, else: %{}\n        store_doc(set, :type, name, arity, line, :typedoc, doc, spec_meta)\n\n      :error ->\n        :error\n    end\n\n    store_typespec(bag, kind, expr, pos)\n  end\n\n  defp get_typespecs(bag, keys) when is_list(keys) do\n    :lists.flatmap(&get_typespecs(bag, &1), keys)\n  end\n\n  defp get_typespecs(bag, key) do\n    :ets.lookup_element(bag, {:accumulate, key}, 2)\n  catch\n    :error, :badarg -> []\n  end\n\n  defp take_typespecs(bag, keys) when is_list(keys) do\n    :lists.flatmap(&take_typespecs(bag, &1), keys)\n  end\n\n  defp take_typespecs(bag, key) do\n    :lists.map(&elem(&1, 1), :ets.take(bag, {:accumulate, key}))\n  end\n\n  defp store_typespec(bag, key, expr, pos) do\n    :ets.insert(bag, {{:accumulate, key}, {key, expr, pos}})\n    :ok\n  end\n\n  defp store_doc(set, kind, name, arity, line, doc_kind, doc, spec_meta) do\n    doc_meta = get_doc_meta(spec_meta, doc_kind, set)\n    :ets.insert(set, {{kind, name, arity}, line, doc, doc_meta})\n  end\n\n  defp get_doc_info(set, attr, line) do\n    case :ets.take(set, attr) do\n      [{^attr, {line, doc}, _, _}] -> {line, doc}\n      [] -> {line, nil}\n    end\n  end\n\n  defp get_doc_meta(spec_meta, doc_kind, set) do\n    case :ets.take(set, {doc_kind, :meta}) do\n      [{{^doc_kind, :meta}, metadata}] -> Map.merge(metadata, spec_meta)\n      [] -> spec_meta\n    end\n  end\n\n  defp spec_to_signature({:when, _, [spec, _]}), do: type_to_signature(spec)\n  defp spec_to_signature(other), do: type_to_signature(other)\n\n  defp type_to_signature({:\"::\", _, [{name, _, context}, _]})\n       when is_atom(name) and name != :\"::\" and is_atom(context),\n       do: {name, 0}\n\n  defp type_to_signature({:\"::\", _, [{name, _, args}, _]}) when is_atom(name) and name != :\"::\",\n    do: {name, length(args)}\n\n  defp type_to_signature(_), do: :error\n\n  ## Translation from Elixir AST to typespec AST\n\n  @doc false\n  def translate_typespecs_for_module(_set, bag) do\n    type_typespecs = take_typespecs(bag, [:type, :opaque, :typep])\n    defined_type_pairs = collect_defined_type_pairs(type_typespecs)\n\n    state = %{\n      defined_type_pairs: defined_type_pairs,\n      used_type_pairs: [],\n      local_vars: %{},\n      undefined_type_error_enabled?: true\n    }\n\n    {types, state} = :lists.mapfoldl(&translate_type/2, state, type_typespecs)\n    {specs, state} = :lists.mapfoldl(&translate_spec/2, state, take_typespecs(bag, :spec))\n    {callbacks, state} = :lists.mapfoldl(&translate_spec/2, state, take_typespecs(bag, :callback))\n\n    {macrocallbacks, state} =\n      :lists.mapfoldl(&translate_spec/2, state, take_typespecs(bag, :macrocallback))\n\n    optional_callbacks = :lists.flatten(get_typespecs(bag, :optional_callbacks))\n    used_types = filter_used_types(types, state)\n\n    {used_types, specs, callbacks, macrocallbacks, optional_callbacks}\n  end\n\n  defp collect_defined_type_pairs(type_typespecs) do\n    fun = fn {_kind, expr, pos}, type_pairs ->\n      %{file: file, line: line} = env = :elixir_module.get_cached_env(pos)\n\n      case type_to_signature(expr) do\n        {name, arity} = type_pair ->\n          cond do\n            # This is a built-in type since OTP 29 but it just generates a warning for now\n            {name, arity} == {:record, 0} ->\n              IO.warn(\"type #{name}/#{arity} is overriding a built-in type\",\n                file: file,\n                line: line\n              )\n\n            built_in_type?(name, arity) ->\n              message = \"type #{name}/#{arity} is a built-in type and it cannot be redefined\"\n              compile_error(env, message)\n\n            true ->\n              :ok\n          end\n\n          if Map.has_key?(type_pairs, type_pair) do\n            {error_full_path, error_line} = type_pairs[type_pair]\n            error_relative_path = Path.relative_to_cwd(error_full_path)\n\n            compile_error(\n              env,\n              \"type #{name}/#{arity} is already defined in #{error_relative_path}:#{error_line}\"\n            )\n          end\n\n          Map.put(type_pairs, type_pair, {file, line})\n\n        :error ->\n          compile_error(env, \"invalid type specification: #{Macro.to_string(expr)}\")\n      end\n    end\n\n    :lists.foldl(fun, %{}, type_typespecs)\n  end\n\n  defp filter_used_types(types, state) do\n    fun = fn {_kind, {name, arity} = type_pair, _line, _type, export} ->\n      if not export and not :lists.member(type_pair, state.used_type_pairs) do\n        %{^type_pair => {file, line}} = state.defined_type_pairs\n        IO.warn(\"type #{name}/#{arity} is unused\", file: file, line: line)\n        false\n      else\n        true\n      end\n    end\n\n    :lists.filter(fun, types)\n  end\n\n  defp translate_type({kind, {:\"::\", _, [{name, meta, args}, definition]}, pos}, state)\n       when is_list(meta) do\n    caller = :elixir_module.get_cached_env(pos)\n    state = clean_local_state(state)\n\n    args =\n      if is_atom(args) do\n        []\n      else\n        :lists.map(&variable/1, args)\n      end\n\n    vars = :lists.filter(&match?({:var, _, _}, &1), args)\n    var_names = :lists.map(&elem(&1, 2), vars)\n    state = :lists.foldl(&update_local_vars(&2, &1), state, var_names)\n    {spec, state} = typespec(definition, var_names, caller, state)\n    type = {name, spec, vars}\n    arity = length(args)\n\n    ensure_no_underscore_local_vars!(caller, var_names)\n    ensure_no_unused_local_vars!(caller, state.local_vars)\n\n    {kind, export} =\n      case kind do\n        :type -> {:type, true}\n        :typep -> {:type, false}\n        :opaque -> {:opaque, true}\n      end\n\n    invalid_args = :lists.filter(&(not valid_variable_ast?(&1)), args)\n\n    if invalid_args != [] do\n      invalid_args = :lists.join(\", \", :lists.map(&Macro.to_string/1, invalid_args))\n\n      message =\n        \"@type definitions expect all arguments to be variables. The type \" <>\n          \"#{name}/#{arity} has an invalid argument(s): #{invalid_args}\"\n\n      compile_error(caller, message)\n    end\n\n    if underspecified?(kind, arity, spec) do\n      message = \"@#{kind} type #{name}/#{arity} is underspecified and therefore meaningless\"\n      IO.warn(message, caller)\n    end\n\n    {{kind, {name, arity}, meta, type, export}, state}\n  end\n\n  defp valid_variable_ast?({variable_name, _, context})\n       when is_atom(variable_name) and is_atom(context),\n       do: true\n\n  defp valid_variable_ast?(_), do: false\n\n  defp underspecified?(:opaque, 0, {:type, _, type, []}) when type in [:any, :term], do: true\n  defp underspecified?(_kind, _arity, _spec), do: false\n\n  defp translate_spec({kind, {:when, _meta, [spec, guard]}, pos}, state) do\n    caller = :elixir_module.get_cached_env(pos)\n    translate_spec(kind, spec, guard, caller, state)\n  end\n\n  defp translate_spec({kind, spec, pos}, state) do\n    caller = :elixir_module.get_cached_env(pos)\n    translate_spec(kind, spec, [], caller, state)\n  end\n\n  defp translate_spec(kind, {:\"::\", _, [{name, meta, args}, return]}, guard, caller, state)\n       when is_atom(name) and name != :\"::\" and is_list(meta) and (is_list(args) or is_atom(args)) do\n    translate_spec(kind, meta, name, args, return, guard, caller, state)\n  end\n\n  defp translate_spec(_kind, {name, _meta, _args} = spec, _guard, caller, _state)\n       when is_atom(name) and name != :\"::\" do\n    spec = Macro.to_string(spec)\n    compile_error(caller, \"type specification missing return type: #{spec}\")\n  end\n\n  defp translate_spec(_kind, spec, _guard, caller, _state) do\n    spec = Macro.to_string(spec)\n    compile_error(caller, \"invalid type specification: #{spec}\")\n  end\n\n  defp translate_spec(kind, meta, name, args, return, guard, caller, state) when is_atom(args),\n    do: translate_spec(kind, meta, name, [], return, guard, caller, state)\n\n  defp translate_spec(kind, meta, name, args, return, guard, caller, state) do\n    ensure_no_defaults!(args)\n    state = clean_local_state(state)\n\n    if not Keyword.keyword?(guard) do\n      error = \"expected keywords as guard in type specification, got: #{Macro.to_string(guard)}\"\n      compile_error(caller, error)\n    end\n\n    location = location(meta)\n    vars = Keyword.keys(guard)\n\n    {args, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, args)\n    {return, state} = typespec(return, vars, caller, state)\n    spec = {:type, location, :fun, [{:type, location, :product, args}, return]}\n\n    {spec, state} =\n      case guard_to_constraints(guard, vars, meta, caller, state) do\n        {[], state} -> {spec, state}\n        {constraints, state} -> {{:type, location, :bounded_fun, [spec, constraints]}, state}\n      end\n\n    ensure_no_unused_local_vars!(caller, state.local_vars)\n\n    arity = length(args)\n    {{kind, {name, arity}, meta, spec}, state}\n  end\n\n  # TODO: Remove char_list type by v2.0\n  defp built_in_type?(:char_list, 0), do: true\n  defp built_in_type?(:charlist, 0), do: true\n  defp built_in_type?(:as_boolean, 1), do: true\n  defp built_in_type?(:struct, 0), do: true\n  defp built_in_type?(:nonempty_charlist, 0), do: true\n  defp built_in_type?(:keyword, 0), do: true\n  defp built_in_type?(:keyword, 1), do: true\n  defp built_in_type?(:var, 0), do: true\n  defp built_in_type?(name, arity), do: :erl_internal.is_type(name, arity)\n\n  defp ensure_no_defaults!(args) do\n    fun = fn\n      {:\"::\", _, [left, right]} ->\n        ensure_not_default(left)\n        ensure_not_default(right)\n        left\n\n      other ->\n        ensure_not_default(other)\n        other\n    end\n\n    :lists.foreach(fun, args)\n  end\n\n  defp ensure_not_default({:\\\\, _, [_, _]}) do\n    raise ArgumentError, \"default arguments \\\\\\\\ not supported in typespecs\"\n  end\n\n  defp ensure_not_default(_), do: :ok\n\n  defp guard_to_constraints(guard, vars, meta, caller, state) do\n    location = location(meta)\n\n    fun = fn\n      {_name, {:var, _, context}}, {constraints, state} when is_atom(context) ->\n        {constraints, state}\n\n      {name, type}, {constraints, state} ->\n        {spec, state} = typespec(type, vars, caller, state)\n        constraint = [{:atom, location, :is_subtype}, [{:var, location, name}, spec]]\n        state = update_local_vars(state, name)\n        {[{:type, location, :constraint, constraint} | constraints], state}\n    end\n\n    {constraints, state} = :lists.foldl(fun, {[], state}, guard)\n    {:lists.reverse(constraints), state}\n  end\n\n  ## To typespec conversion\n\n  defp location(meta) do\n    line = Keyword.get(meta, :line, 0)\n\n    if column = Keyword.get(meta, :column) do\n      {line, column}\n    else\n      line\n    end\n  end\n\n  # Handle unions\n  defp typespec({:|, meta, [_, _]} = exprs, vars, caller, state) do\n    exprs = collect_union(exprs)\n    {union, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, exprs)\n    {{:type, location(meta), :union, union}, state}\n  end\n\n  # Handle binaries\n  defp typespec({:<<>>, meta, []}, _, _, state) do\n    location = location(meta)\n    {{:type, location, :binary, [{:integer, location, 0}, {:integer, location, 0}]}, state}\n  end\n\n  defp typespec(\n         {:<<>>, meta, [{:\"::\", unit_meta, [{:_, _, ctx1}, {:*, _, [{:_, _, ctx2}, unit]}]}]},\n         _,\n         _,\n         state\n       )\n       when is_atom(ctx1) and is_atom(ctx2) and unit in 1..256 do\n    location = location(meta)\n\n    {{:type, location, :binary, [{:integer, location, 0}, {:integer, location(unit_meta), unit}]},\n     state}\n  end\n\n  defp typespec(\n         {:<<>>, meta, [{:\"::\", _, [{:_, _, ctx1}, {:*, prod_meta, [size, unit]}]}]},\n         _,\n         _,\n         state\n       )\n       when is_atom(ctx1) and is_integer(size) and size >= 0 and unit in 1..256 do\n    location = location(meta)\n    prod_location = location(prod_meta)\n\n    {{:type, location, :binary,\n      [\n        {:op, prod_location, :*, {:integer, prod_location, size},\n         {:integer, prod_location, unit}},\n        {:integer, location, 0}\n      ]}, state}\n  end\n\n  defp typespec({:<<>>, meta, [{:\"::\", size_meta, [{:_, _, ctx}, size]}]}, _, _, state)\n       when is_atom(ctx) and is_integer(size) and size >= 0 do\n    location = location(meta)\n\n    {{:type, location, :binary, [{:integer, location(size_meta), size}, {:integer, location, 0}]},\n     state}\n  end\n\n  defp typespec(\n         {\n           :<<>>,\n           meta,\n           [\n             {:\"::\", size_meta, [{:_, _, ctx1}, size]},\n             {:\"::\", unit_meta, [{:_, _, ctx2}, {:*, _, [{:_, _, ctx3}, unit]}]}\n           ]\n         },\n         _,\n         _,\n         state\n       )\n       when is_atom(ctx1) and is_atom(ctx2) and is_atom(ctx3) and is_integer(size) and\n              size >= 0 and unit in 1..256 do\n    args = [{:integer, location(size_meta), size}, {:integer, location(unit_meta), unit}]\n    {{:type, location(meta), :binary, args}, state}\n  end\n\n  defp typespec({:<<>>, _meta, _args}, _vars, caller, _state) do\n    message =\n      \"invalid binary specification, expected <<_::size>>, <<_::_*unit>>, \" <>\n        \"or <<_::size, _::_*unit>> with size being non-negative integers, and unit being an integer between 1 and 256\"\n\n    compile_error(caller, message)\n  end\n\n  ## Handle maps and structs\n  defp typespec({:map, meta, args}, _vars, _caller, state) when args == [] or is_atom(args) do\n    {{:type, location(meta), :map, :any}, state}\n  end\n\n  defp typespec({:%{}, meta, fields} = map, vars, caller, state) do\n    fun = fn\n      {{:required, meta2, [k]}, v}, state ->\n        {arg1, state} = typespec(k, vars, caller, state)\n        {arg2, state} = typespec(v, vars, caller, state)\n        {{:type, location(meta2), :map_field_exact, [arg1, arg2]}, state}\n\n      {{:optional, meta2, [k]}, v}, state ->\n        {arg1, state} = typespec(k, vars, caller, state)\n        {arg2, state} = typespec(v, vars, caller, state)\n        {{:type, location(meta2), :map_field_assoc, [arg1, arg2]}, state}\n\n      {k, v}, state ->\n        {arg1, state} = typespec(k, vars, caller, state)\n        {arg2, state} = typespec(v, vars, caller, state)\n        {{:type, location(meta), :map_field_exact, [arg1, arg2]}, state}\n\n      {:|, _, [_, _]}, _state ->\n        error =\n          \"invalid map specification. When using the | operator in the map key, \" <>\n            \"make sure to wrap the key type in parentheses: #{Macro.to_string(map)}\"\n\n        compile_error(caller, error)\n\n      _, _state ->\n        compile_error(caller, \"invalid map specification: #{Macro.to_string(map)}\")\n    end\n\n    {fields, state} = :lists.mapfoldl(fun, state, fields)\n    {{:type, location(meta), :map, fields}, state}\n  end\n\n  defp typespec({:%, _, [name, {:%{}, meta, fields}]} = node, vars, caller, state) do\n    case Macro.expand(name, %{caller | function: {:__info__, 1}}) do\n      module when is_atom(module) ->\n        struct_info = Macro.struct_info!(module, caller)\n\n        if not Keyword.keyword?(fields) do\n          compile_error(caller, \"expected key-value pairs in struct #{Macro.to_string(name)}\")\n        end\n\n        types =\n          :lists.map(\n            fn %{field: field} ->\n              default_type = if field == :__exception__, do: true, else: quote(do: term())\n              {field, Keyword.get(fields, field, default_type)}\n            end,\n            struct_info\n          )\n\n        fun = fn {field, _} ->\n          if not Enum.any?(struct_info, &(&1.field == field)) do\n            compile_error(\n              caller,\n              \"undefined field #{inspect(field)} on struct #{inspect(module)}\"\n            )\n          end\n        end\n\n        :lists.foreach(fun, fields)\n        typespec({:%{}, meta, [__struct__: module] ++ :lists.usort(types)}, vars, caller, state)\n\n      _ ->\n        compile_error(\n          caller,\n          \"unexpected expression in typespec: #{Macro.to_string(node)}\"\n        )\n    end\n  end\n\n  # Handle records\n  defp typespec({:record, meta, [atom]}, vars, caller, state) do\n    typespec({:record, meta, [atom, []]}, vars, caller, state)\n  end\n\n  defp typespec({:record, meta, [name, field_specs]}, vars, caller, state)\n       when is_atom(name) and is_list(field_specs) do\n    # We cannot set a function name to avoid tracking\n    # as a compile time dependency because for records it actually is one.\n    case Macro.expand({name, [], [{:{}, [], []}]}, caller) do\n      {_, _, [tag, fields | _]} when is_list(fields) ->\n        types =\n          :lists.map(\n            fn {field, _} ->\n              {:\"::\", [],\n               [\n                 {field, [], nil},\n                 Keyword.get(field_specs, field, quote(do: term()))\n               ]}\n            end,\n            fields\n          )\n\n        fun = fn {field, _} ->\n          if not Keyword.has_key?(fields, field) do\n            compile_error(caller, \"undefined field #{field} on record #{inspect(name)}\")\n          end\n        end\n\n        :lists.foreach(fun, field_specs)\n        typespec({:{}, meta, [tag | types]}, vars, caller, state)\n\n      _ ->\n        compile_error(caller, \"unknown record #{inspect(name)}\")\n    end\n  end\n\n  defp typespec({:record, _meta, [_name, _field_specs]}, _vars, caller, _state) do\n    message = \"invalid record specification, expected the record name to be an atom literal\"\n    compile_error(caller, message)\n  end\n\n  # Handle ranges\n  defp typespec({:.., meta, [left, right]}, vars, caller, state) do\n    {left, state} = typespec(left, vars, caller, state)\n    {right, state} = typespec(right, vars, caller, state)\n    :ok = validate_range(left, right, caller)\n\n    {{:type, location(meta), :range, [left, right]}, state}\n  end\n\n  # Handle special forms\n  defp typespec({:__MODULE__, _, atom}, vars, caller, state) when is_atom(atom) do\n    typespec(caller.module, vars, caller, state)\n  end\n\n  defp typespec({:__aliases__, _, _} = alias, vars, caller, state) do\n    typespec(expand_remote(alias, caller), vars, caller, state)\n  end\n\n  # Handle funs\n  defp typespec([{:->, meta, [args, return]}], vars, caller, state)\n       when is_list(args) do\n    {args, state} = fn_args(meta, args, vars, caller, state)\n    {spec, state} = typespec(return, vars, caller, state)\n    {{:type, location(meta), :fun, [args, spec]}, state}\n  end\n\n  # Handle type operator\n  defp typespec(\n         {:\"::\", meta, [{var_name, var_meta, context}, expr]} = ann_type,\n         vars,\n         caller,\n         state\n       )\n       when is_atom(var_name) and is_atom(context) do\n    case typespec(expr, vars, caller, state) do\n      {{:ann_type, _, _}, _state} ->\n        message =\n          \"invalid type annotation. Type annotations cannot be nested: \" <>\n            \"#{Macro.to_string(ann_type)}\"\n\n        # TODO: Make this an error on v2.0 and remove the code below\n        IO.warn(message, caller)\n\n        # This may be generating an invalid typespec but we need to generate it\n        # to avoid breaking existing code that was valid but only broke Dialyzer\n        {right, state} = typespec(expr, vars, caller, state)\n        {{:ann_type, location(meta), [{:var, location(var_meta), var_name}, right]}, state}\n\n      {right, state} ->\n        {{:ann_type, location(meta), [{:var, location(var_meta), var_name}, right]}, state}\n    end\n  end\n\n  defp typespec({:\"::\", meta, [left, right]}, vars, caller, state) do\n    message =\n      \"invalid type annotation. The left side of :: must be a variable, got: #{Macro.to_string(left)}\"\n\n    message =\n      case left do\n        {:|, _, _} ->\n          message <>\n            \". Note \\\"left | right :: ann\\\" is the same as \\\"(left | right) :: ann\\\". \" <>\n            \"To solve this, use parentheses around the union operands: \\\"left | (right :: ann)\\\"\"\n\n        _ ->\n          message\n      end\n\n    # TODO: Make this an error on v2.0, and remove the code below and\n    # the :undefined_type_error_enabled? key from the state\n    IO.warn(message, caller)\n\n    # This may be generating an invalid typespec but we need to generate it\n    # to avoid breaking existing code that was valid but only broke Dialyzer\n    state = %{state | undefined_type_error_enabled?: false}\n    {left, state} = typespec(left, vars, caller, state)\n    state = %{state | undefined_type_error_enabled?: true}\n    {right, state} = typespec(right, vars, caller, state)\n    {{:ann_type, location(meta), [left, right]}, state}\n  end\n\n  # Handle unary ops\n  defp typespec({op, meta, [integer]}, _, _, state) when op in [:+, :-] and is_integer(integer) do\n    location = location(meta)\n    {{:op, location, op, {:integer, location, integer}}, state}\n  end\n\n  # Handle remote calls in the form of @module_attribute.type.\n  # These are not handled by the general remote type clause as calling\n  # Macro.expand/2 on the remote does not expand module attributes (but expands\n  # things like __MODULE__).\n  defp typespec(\n         {{:., meta, [{:@, _, [{attr, _, _}]}, name]}, _, args} = orig,\n         vars,\n         caller,\n         state\n       ) do\n    remote = Module.get_attribute(caller.module, attr)\n\n    if not (is_atom(remote) and remote != nil) do\n      message =\n        \"invalid remote in typespec: #{Macro.to_string(orig)} (@#{attr} is #{inspect(remote)})\"\n\n      compile_error(caller, message)\n    end\n\n    {remote_spec, state} = typespec(remote, vars, caller, state)\n    {name_spec, state} = typespec(name, vars, caller, state)\n    type = {remote_spec, meta, name_spec, args}\n    remote_type(type, vars, caller, state)\n  end\n\n  # Handle remote calls\n  defp typespec({{:., meta, [remote, name]}, _, args} = orig, vars, caller, state) do\n    remote = expand_remote(remote, caller)\n\n    cond do\n      not is_atom(remote) ->\n        compile_error(caller, \"invalid remote in typespec: #{Macro.to_string(orig)}\")\n\n      remote == caller.module ->\n        typespec({name, meta, args}, vars, caller, state)\n\n      true ->\n        {remote_spec, state} = typespec(remote, vars, caller, state)\n        {name_spec, state} = typespec(name, vars, caller, state)\n        type = {remote_spec, meta, name_spec, args}\n        remote_type(type, vars, caller, state)\n    end\n  end\n\n  # Handle tuples\n  defp typespec({:tuple, meta, []}, _vars, _caller, state) do\n    {{:type, location(meta), :tuple, :any}, state}\n  end\n\n  defp typespec({:{}, meta, t}, vars, caller, state) when is_list(t) do\n    {args, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, t)\n    {{:type, location(meta), :tuple, args}, state}\n  end\n\n  defp typespec({left, right}, vars, caller, state) do\n    typespec({:{}, [], [left, right]}, vars, caller, state)\n  end\n\n  # Handle blocks\n  defp typespec({:__block__, _meta, [arg]}, vars, caller, state) do\n    typespec(arg, vars, caller, state)\n  end\n\n  # Handle variables or local calls\n  defp typespec({name, meta, atom}, vars, caller, state) when is_atom(atom) do\n    if :lists.member(name, vars) do\n      state = update_local_vars(state, name)\n      {{:var, location(meta), name}, state}\n    else\n      typespec({name, meta, []}, vars, caller, state)\n    end\n  end\n\n  # Handle local calls\n  defp typespec({:string, meta, args}, vars, caller, state) do\n    warning =\n      \"string() type use is discouraged. \" <>\n        \"For character lists, use charlist() type, for strings, String.t()\\n\" <>\n        Exception.format_stacktrace(Macro.Env.stacktrace(caller))\n\n    IO.warn(warning, caller)\n    {args, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, args)\n    {{:type, location(meta), :string, args}, state}\n  end\n\n  defp typespec({:nonempty_string, meta, args}, vars, caller, state) do\n    warning =\n      \"nonempty_string() type use is discouraged. \" <>\n        \"For non-empty character lists, use nonempty_charlist() type, for strings, String.t()\\n\" <>\n        Exception.format_stacktrace(Macro.Env.stacktrace(caller))\n\n    IO.warn(warning, caller)\n    {args, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, args)\n    {{:type, location(meta), :nonempty_string, args}, state}\n  end\n\n  defp typespec({type, _meta, []}, vars, caller, state) when type in [:charlist, :char_list] do\n    if type == :char_list do\n      warning = \"the char_list() type is deprecated, use charlist()\"\n      IO.warn(warning, caller)\n    end\n\n    typespec(quote(do: :elixir.charlist()), vars, caller, state)\n  end\n\n  defp typespec({:nonempty_charlist, _meta, []}, vars, caller, state) do\n    typespec(quote(do: :elixir.nonempty_charlist()), vars, caller, state)\n  end\n\n  defp typespec({:struct, _meta, []}, vars, caller, state) do\n    typespec(quote(do: :elixir.struct()), vars, caller, state)\n  end\n\n  defp typespec({:as_boolean, _meta, [arg]}, vars, caller, state) do\n    typespec(quote(do: :elixir.as_boolean(unquote(arg))), vars, caller, state)\n  end\n\n  defp typespec({:keyword, _meta, args}, vars, caller, state) when length(args) <= 1 do\n    typespec(quote(do: :elixir.keyword(unquote_splicing(args))), vars, caller, state)\n  end\n\n  defp typespec({:fun, meta, args}, vars, caller, state) do\n    {args, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, args)\n\n    if args != [] do\n      IO.warn(\n        \"fun/#{length(args)} is not valid in typespecs. Either specify fun() or use (... -> return) instead\",\n        caller\n      )\n    end\n\n    {{:type, location(meta), :fun, []}, state}\n  end\n\n  defp typespec({:..., _meta, _args}, _vars, caller, _state) do\n    compile_error(\n      caller,\n      \"... in typespecs is only allowed inside lists, as in [term(), ...], \" <>\n        \"or inside functions, as in (... -> term())\"\n    )\n  end\n\n  defp typespec({name, meta, args}, vars, caller, state) when is_atom(name) do\n    {args, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, args)\n    arity = length(args)\n\n    case :erl_internal.is_type(name, arity) do\n      true ->\n        {{:type, location(meta), name, args}, state}\n\n      false ->\n        if state.undefined_type_error_enabled? and\n             not Map.has_key?(state.defined_type_pairs, {name, arity}) do\n          compile_error(\n            caller,\n            \"type #{name}/#{arity} undefined (no such type in #{inspect(caller.module)})\"\n          )\n        end\n\n        state =\n          if :lists.member({name, arity}, state.used_type_pairs) do\n            state\n          else\n            %{state | used_type_pairs: [{name, arity} | state.used_type_pairs]}\n          end\n\n        {{:user_type, location(meta), name, args}, state}\n    end\n  end\n\n  # Handle literals\n  defp typespec(atom, _, _, state) when is_atom(atom) do\n    {{:atom, 0, atom}, state}\n  end\n\n  defp typespec(integer, _, _, state) when is_integer(integer) do\n    {{:integer, 0, integer}, state}\n  end\n\n  defp typespec([], vars, caller, state) do\n    typespec({nil, [], []}, vars, caller, state)\n  end\n\n  defp typespec([{:..., _, _}], vars, caller, state) do\n    typespec({:nonempty_list, [], []}, vars, caller, state)\n  end\n\n  defp typespec([spec, {:..., _, _}], vars, caller, state) do\n    typespec({:nonempty_list, [], [spec]}, vars, caller, state)\n  end\n\n  defp typespec([spec], vars, caller, state) do\n    typespec({:list, [], [spec]}, vars, caller, state)\n  end\n\n  defp typespec(list, vars, caller, state) when is_list(list) do\n    [head | tail] = :lists.reverse(list)\n\n    union =\n      :lists.foldl(\n        fn elem, acc -> {:|, [], [validate_kw(elem, list, caller), acc]} end,\n        validate_kw(head, list, caller),\n        tail\n      )\n\n    typespec({:list, [], [union]}, vars, caller, state)\n  end\n\n  defp typespec(other, _vars, caller, _state) do\n    compile_error(caller, \"unexpected expression in typespec: #{Macro.to_string(other)}\")\n  end\n\n  ## Helpers\n\n  # This is a modified backport of Macro.expand/2 because we want to expand\n  # aliases but we don't them to become compile-time references.\n  defp expand_remote({:__aliases__, meta, list} = alias, env) do\n    case :elixir_aliases.expand_or_concat(meta, list, env, true) do\n      receiver when is_atom(receiver) ->\n        receiver\n\n      [head | tail] ->\n        case Macro.expand(head, env) do\n          head when is_atom(head) ->\n            :elixir_aliases.concat([head | tail])\n\n          _ ->\n            compile_error(env, \"unexpected expression in typespec: #{Macro.to_string(alias)}\")\n        end\n    end\n  end\n\n  defp expand_remote(other, env), do: Macro.expand(other, env)\n\n  defp compile_error(caller, desc) do\n    raise Kernel.TypespecError, file: caller.file, line: caller.line, description: desc\n  end\n\n  defp remote_type({remote, meta, name, args}, vars, caller, state) do\n    {args, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, args)\n    {{:remote_type, location(meta), [remote, name, args]}, state}\n  end\n\n  defp collect_union({:|, _, [a, b]}), do: [a | collect_union(b)]\n  defp collect_union(v), do: [v]\n\n  defp validate_kw({key, _} = t, _, _caller) when is_atom(key), do: t\n\n  defp validate_kw(_, original, caller) do\n    compile_error(caller, \"unexpected list in typespec: #{Macro.to_string(original)}\")\n  end\n\n  defp validate_range({:op, _, :-, {:integer, meta, first}}, last, caller) do\n    validate_range({:integer, meta, -first}, last, caller)\n  end\n\n  defp validate_range(first, {:op, _, :-, {:integer, meta, last}}, caller) do\n    validate_range(first, {:integer, meta, -last}, caller)\n  end\n\n  defp validate_range({:integer, _, first}, {:integer, _, last}, _caller) when first < last do\n    :ok\n  end\n\n  defp validate_range(_, _, caller) do\n    message =\n      \"invalid range specification, expected both sides to be integers, \" <>\n        \"with the left side lower than the right side\"\n\n    compile_error(caller, message)\n  end\n\n  defp fn_args(meta, [{:..., _, _}], _vars, _caller, state) do\n    {{:type, location(meta), :any}, state}\n  end\n\n  defp fn_args(meta, args, vars, caller, state) do\n    {args, state} = :lists.mapfoldl(&typespec(&1, vars, caller, &2), state, args)\n    {{:type, location(meta), :product, args}, state}\n  end\n\n  defp variable({name, meta, args}) when is_atom(name) and is_atom(args) do\n    {:var, location(meta), name}\n  end\n\n  defp variable(expr), do: expr\n\n  defp clean_local_state(state) do\n    %{state | local_vars: %{}}\n  end\n\n  defp update_local_vars(%{local_vars: local_vars} = state, var_name) do\n    case Map.fetch(local_vars, var_name) do\n      {:ok, :used_once} -> %{state | local_vars: Map.put(local_vars, var_name, :used_multiple)}\n      {:ok, :used_multiple} -> state\n      :error -> %{state | local_vars: Map.put(local_vars, var_name, :used_once)}\n    end\n  end\n\n  defp ensure_no_underscore_local_vars!(caller, var_names) do\n    case :lists.member(:_, var_names) do\n      true ->\n        compile_error(caller, \"type variable '_' is invalid\")\n\n      false ->\n        :ok\n    end\n  end\n\n  defp ensure_no_unused_local_vars!(caller, local_vars) do\n    fun = fn {name, used_times} ->\n      case {:erlang.atom_to_list(name), used_times} do\n        {[?_ | _], :used_once} ->\n          :ok\n\n        {[?_ | _], :used_multiple} ->\n          warning =\n            \"the underscored type variable \\\"#{name}\\\" is used more than once in the \" <>\n              \"type specification. A leading underscore indicates that the value of the \" <>\n              \"variable should be ignored. If this is intended please rename the variable to \" <>\n              \"remove the underscore\"\n\n          IO.warn(warning, caller)\n\n        {_, :used_once} ->\n          compile_error(\n            caller,\n            \"type variable #{name} is used only once. Type variables in typespecs \" <>\n              \"must be referenced at least twice, otherwise it is equivalent to term()\"\n          )\n\n        _ ->\n          :ok\n      end\n    end\n\n    :lists.foreach(fun, :maps.to_list(local_vars))\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel/utils.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nimport Kernel, except: [destructure: 2, defdelegate: 2, defstruct: 2]\n\ndefmodule Kernel.Utils do\n  @moduledoc false\n\n  @doc \"\"\"\n  Callback for destructure.\n  \"\"\"\n  def destructure(list, count)\n      when is_list(list) and is_integer(count) and count >= 0,\n      do: destructure_list(list, count)\n\n  def destructure(nil, count)\n      when is_integer(count) and count >= 0,\n      do: destructure_nil(count)\n\n  defp destructure_list(_, 0), do: []\n  defp destructure_list([], count), do: destructure_nil(count)\n  defp destructure_list([h | t], count), do: [h | destructure_list(t, count - 1)]\n\n  defp destructure_nil(0), do: []\n  defp destructure_nil(count), do: [nil | destructure_nil(count - 1)]\n\n  @doc \"\"\"\n  Callback for defdelegate entry point.\n  \"\"\"\n  def defdelegate_all(funs, opts, env) do\n    to = Keyword.get(opts, :to) || raise ArgumentError, \"expected to: to be given as argument\"\n    as = Keyword.get(opts, :as)\n\n    if to == env.module and is_nil(as) do\n      raise ArgumentError,\n            \"defdelegate function is calling itself, which will lead to an infinite loop. You should either change the value of the :to option or specify the :as option\"\n    end\n\n    if is_list(funs) do\n      IO.warn(\n        \"passing a list to Kernel.defdelegate/2 is deprecated, please define each delegate separately\",\n        env\n      )\n    end\n\n    if Keyword.has_key?(opts, :append_first) do\n      IO.warn(\n        \"Kernel.defdelegate/2 :append_first option is deprecated\",\n        env\n      )\n    end\n\n    to\n  end\n\n  @doc \"\"\"\n  Callback for each function in defdelegate.\n  \"\"\"\n  def defdelegate_each(fun, opts) when is_list(opts) do\n    # TODO: Remove on v2.0\n    append_first? = Keyword.get(opts, :append_first, false)\n\n    {name, args} =\n      case fun do\n        {:when, _, [_left, right]} ->\n          raise ArgumentError,\n                \"guards are not allowed in defdelegate/2, got: when #{Macro.to_string(right)}\"\n\n        _ ->\n          case Macro.decompose_call(fun) do\n            {_, _} = pair -> pair\n            _ -> raise ArgumentError, \"invalid syntax in defdelegate #{Macro.to_string(fun)}\"\n          end\n      end\n\n    as = Keyword.get(opts, :as, name)\n    as_args = build_as_args(args, append_first?)\n\n    {name, args, as, as_args}\n  end\n\n  defp build_as_args(args, append_first?) do\n    as_args = :lists.map(&build_as_arg/1, args)\n\n    case append_first? do\n      true -> tl(as_args) ++ [hd(as_args)]\n      false -> as_args\n    end\n  end\n\n  defp build_as_arg({:\\\\, _, [arg, _default_arg]}), do: validate_arg(arg)\n  defp build_as_arg(arg), do: validate_arg(arg)\n\n  defp validate_arg({name, _, mod} = arg) when is_atom(name) and is_atom(mod) do\n    arg\n  end\n\n  defp validate_arg(ast) do\n    raise ArgumentError,\n          \"defdelegate/2 only accepts function parameters, got: #{Macro.to_string(ast)}\"\n  end\n\n  @doc \"\"\"\n  Callback for defstruct.\n  \"\"\"\n  def defstruct(module, fields, bootstrapped?, env) do\n    {set, bag} = :elixir_module.data_tables(module)\n\n    if :ets.member(set, {:elixir, :struct}) do\n      raise ArgumentError,\n            \"defstruct has already been called for \" <>\n              \"#{Kernel.inspect(module)}, defstruct can only be called once per module\"\n    end\n\n    case fields do\n      fs when is_list(fs) ->\n        :ok\n\n      other ->\n        raise ArgumentError, \"struct fields definition must be list, got: #{inspect(other)}\"\n    end\n\n    mapper = fn\n      {key, val} when is_atom(key) ->\n        key == :__struct__ and raise(ArgumentError, \"cannot set :__struct__ in struct definition\")\n\n        try do\n          :elixir_quote.escape(val, {:struct, module}, false)\n        rescue\n          e in [ArgumentError] ->\n            raise ArgumentError,\n                  \"invalid default value for struct field #{key}, \" <> Exception.message(e)\n        else\n          _ -> {key, val}\n        end\n\n      key when is_atom(key) ->\n        key == :__struct__ and raise(ArgumentError, \"cannot set :__struct__ in struct definition\")\n        {key, nil}\n\n      other ->\n        raise ArgumentError, \"struct field names must be atoms, got: #{inspect(other)}\"\n    end\n\n    fields = :lists.map(mapper, fields)\n\n    enforce_keys =\n      case :ets.lookup(set, :enforce_keys) do\n        [{_, enforce_keys, _, _}] when is_list(enforce_keys) ->\n          :ets.update_element(set, :enforce_keys, {3, :used})\n          enforce_keys\n\n        [{_, enforce_key, _, _}] ->\n          :ets.update_element(set, :enforce_keys, {3, :used})\n          [enforce_key]\n\n        [] ->\n          []\n      end\n\n    # TODO: Make it raise on v2.0\n    warn_on_duplicate_struct_key(:lists.keysort(1, fields), env)\n\n    foreach = fn\n      key when is_atom(key) ->\n        :ok\n\n      key ->\n        raise ArgumentError, \"keys given to @enforce_keys must be atoms, got: #{inspect(key)}\"\n    end\n\n    :lists.foreach(foreach, enforce_keys)\n    struct = :maps.from_list([__struct__: module] ++ fields)\n    escaped_struct = :elixir_quote.escape(struct, {:struct, module}, false)\n\n    body =\n      case bootstrapped? do\n        true ->\n          case enforce_keys do\n            [] ->\n              quote line: 0, generated: true do\n                Enum.reduce(kv, unquote(escaped_struct), fn {key, val}, map ->\n                  %{map | key => val}\n                end)\n              end\n\n            _ ->\n              quote line: 0, generated: true do\n                {map, keys} =\n                  Enum.reduce(kv, {unquote(escaped_struct), unquote(enforce_keys)}, fn\n                    {key, val}, {map, keys} ->\n                      {%{map | key => val}, List.delete(keys, key)}\n                  end)\n\n                case keys do\n                  [] ->\n                    map\n\n                  _ ->\n                    raise ArgumentError,\n                          \"the following keys must also be given when building \" <>\n                            \"struct #{inspect(__MODULE__)}: #{inspect(keys)}\"\n                end\n              end\n          end\n\n        false ->\n          quote line: 0, generated: true do\n            :lists.foldl(\n              fn {key, val}, acc -> %{acc | key => val} end,\n              unquote(escaped_struct),\n              kv\n            )\n          end\n      end\n\n    case enforce_keys -- :maps.keys(struct) do\n      [] ->\n        mapper = fn {key, val} ->\n          %{field: key, default: val, required: :lists.member(key, enforce_keys)}\n        end\n\n        :ets.insert(set, {{:elixir, :struct}, :lists.map(mapper, fields)})\n        derive = :lists.map(fn {_, value} -> value end, :ets.take(bag, {:accumulate, :derive}))\n        {struct, :lists.reverse(derive), escaped_struct, quote(do: kv), body}\n\n      error_keys ->\n        raise ArgumentError,\n              \"@enforce_keys required keys (#{inspect(error_keys)}) that are not defined in defstruct: \" <>\n                \"#{inspect(fields)}\"\n    end\n  end\n\n  defp warn_on_duplicate_struct_key([], _) do\n    :ok\n  end\n\n  defp warn_on_duplicate_struct_key([{key, _} | [{key, _} | _] = rest], env) do\n    IO.warn(\"duplicate key #{inspect(key)} found in struct\", env)\n    warn_on_duplicate_struct_key(rest, env)\n  end\n\n  defp warn_on_duplicate_struct_key([_ | rest], env) do\n    warn_on_duplicate_struct_key(rest, env)\n  end\n\n  @doc \"\"\"\n  Announcing callback for defstruct.\n  \"\"\"\n  def announce_struct(module) do\n    case :erlang.get(:elixir_compiler_info) do\n      :undefined -> :ok\n      {pid, _} -> send(pid, {:available, :struct, module})\n    end\n  end\n\n  @doc \"\"\"\n  Callback for raise.\n  \"\"\"\n  def raise(msg) when is_binary(msg) do\n    RuntimeError.exception(msg)\n  end\n\n  def raise(module) when is_atom(module) do\n    module.exception([])\n  end\n\n  def raise(%_{__exception__: true} = exception) do\n    exception\n  end\n\n  def raise(other) do\n    ArgumentError.exception(\n      \"raise/1 and reraise/2 expect a module name, string or exception \" <>\n        \"as the first argument, got: #{inspect(other)}\"\n    )\n  end\n\n  @doc \"\"\"\n  Callback for defguard.\n\n  Rewrites an expression so it can be used both inside and outside a guard.\n\n  Take, for example, the expression:\n\n      is_integer(value) and rem(value, 2) == 0\n\n  If we wanted to create a macro, `is_even`, from this expression, that could be\n  used in guards, we'd have to take several things into account.\n\n  First, if this expression is being used inside a guard, `value` needs to be\n  unquoted each place it occurs, since it has not yet been at that point in our\n  macro.\n\n  Secondly, if the expression is being used outside of a guard, we want to unquote\n  `value`, but only once, and then reuse the unquoted form throughout the expression.\n\n  This helper does exactly that: takes the AST for an expression and a list of\n  variable references it should be aware of, and rewrites it into a new expression\n  that checks for its presence in a guard, then unquotes the variable references as\n  appropriate.\n\n  The following code\n\n      expression = quote do: is_integer(value) and rem(value, 2) == 0\n      variable_references = [value: Elixir]\n      Kernel.Utils.defguard(expression, variable_references) |> Macro.to_string() |> IO.puts()\n\n  would print a code similar to:\n\n      case Macro.Env.in_guard?(__CALLER__) do\n        true ->\n          quote do\n            is_integer(unquote(value)) and rem(unquote(value), 2) == 0\n          end\n\n        false ->\n          quote do\n            value = unquote(value)\n            is_integer(value) and rem(value, 2) == 0\n          end\n      end\n\n  \"\"\"\n  defmacro defguard(args, expr) do\n    defguard(args, expr, __CALLER__)\n  end\n\n  @spec defguard([Macro.t()], Macro.t(), Macro.Env.t()) :: Macro.t()\n  def defguard(args, expr, env) do\n    {^args, vars} = extract_refs_from_args(args)\n    env = :elixir_env.with_vars(%{env | context: :guard}, vars)\n    {expr, _, _} = :elixir_expand.expand(expr, :elixir_env.env_to_ex(env), env)\n\n    quote do\n      case Macro.Env.in_guard?(__CALLER__) do\n        true ->\n          unquote(literal_quote(unquote_every_ref(expr, vars), []))\n\n        false ->\n          unquote(literal_quote(unquote_refs_once(expr, vars, env.module), generated: true))\n      end\n    end\n  end\n\n  defp extract_refs_from_args(args) do\n    Macro.postwalk(args, [], fn\n      {ref, meta, context} = var, acc when is_atom(ref) and is_atom(context) ->\n        {var, [{ref, var_context(meta, context)} | acc]}\n\n      node, acc ->\n        {node, acc}\n    end)\n  end\n\n  # Finds every reference to `refs` in `guard` and wraps them in an unquote.\n  defp unquote_every_ref(guard, refs) do\n    Macro.postwalk(guard, fn\n      {ref, meta, context} = var when is_atom(ref) and is_atom(context) ->\n        case {ref, var_context(meta, context)} in refs do\n          true -> literal_unquote(var)\n          false -> var\n        end\n\n      node ->\n        node\n    end)\n  end\n\n  # Prefaces `guard` with unquoted versions of `refs`.\n  defp unquote_refs_once(guard, refs, module) do\n    {guard, used_refs} =\n      Macro.postwalk(guard, %{}, fn\n        {ref, meta, context} = var, acc when is_atom(ref) and is_atom(context) ->\n          pair = {ref, var_context(meta, context)}\n\n          case pair in refs do\n            true ->\n              case acc do\n                %{^pair => {new_var, _}} ->\n                  {new_var, acc}\n\n                %{} ->\n                  generated = String.to_atom(\"arg\" <> Integer.to_string(map_size(acc) + 1))\n                  new_var = Macro.unique_var(generated, module)\n                  {new_var, Map.put(acc, pair, {new_var, var})}\n              end\n\n            false ->\n              {var, acc}\n          end\n\n        node, acc ->\n          {node, acc}\n      end)\n\n    all_used = for ref <- :lists.reverse(refs), used = :maps.get(ref, used_refs, nil), do: used\n    {vars, exprs} = :lists.unzip(all_used)\n\n    quote do\n      {unquote_splicing(vars)} = {unquote_splicing(Enum.map(exprs, &literal_unquote/1))}\n      unquote(guard)\n    end\n  end\n\n  defp literal_quote(ast, args) do\n    {:quote, [], [args, [do: ast]]}\n  end\n\n  defp literal_unquote(ast) do\n    {:unquote, [], List.wrap(ast)}\n  end\n\n  defp var_context(meta, kind) do\n    case :lists.keyfind(:counter, 1, meta) do\n      {:counter, counter} -> counter\n      false -> kind\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/kernel.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Use elixir_bootstrap module to be able to bootstrap Kernel.\n# The bootstrap module provides simpler implementations of the\n# functions removed, simple enough to bootstrap.\nimport Kernel,\n  except: [@: 1, defmodule: 2, def: 1, def: 2, defp: 2, defmacro: 1, defmacro: 2, defmacrop: 2]\n\nimport :elixir_bootstrap\n\ndefmodule Kernel do\n  @moduledoc \"\"\"\n  `Kernel` is Elixir's default environment.\n\n  It mainly consists of:\n\n    * basic language primitives, such as arithmetic operators, spawning of processes,\n      data type handling, and others\n    * macros for control-flow and defining new functionality (modules, functions, and the like)\n    * guard checks for augmenting pattern matching\n\n  You can invoke `Kernel` functions and macros anywhere in Elixir code\n  without the use of the `Kernel.` prefix since they have all been\n  automatically imported. For example, in IEx, you can call:\n\n      iex> is_number(13)\n      true\n\n  If you don't want to import a function or macro from `Kernel`, use the `:except`\n  option and then list the function/macro by arity:\n\n      import Kernel, except: [if: 2, is_number: 1]\n\n  See `import/2` for more information on importing.\n\n  Elixir also has special forms that are always imported and\n  cannot be skipped. These are described in `Kernel.SpecialForms`.\n\n  ## The standard library\n\n  `Kernel` provides the basic capabilities the Elixir standard library\n  is built on top of. It is recommended to explore the standard library\n  for advanced functionality. Here are the main groups of modules in the\n  standard library (this list is not a complete reference, see the\n  documentation sidebar for all entries).\n\n  ### Built-in types\n\n  The following modules handle Elixir built-in data types:\n\n    * `Atom` - literal constants with a name (`true`, `false`, and `nil` are atoms)\n    * `Float` - numbers with floating point precision\n    * `Function` - a reference to code chunk, created with the `fn/1` special form\n    * `Integer` - whole numbers (not fractions)\n    * `List` - collections of a variable number of elements (linked lists)\n    * `Map` - collections of key-value pairs\n    * `Process` - light-weight threads of execution\n    * `Port` - mechanisms to interact with the external world\n    * `Tuple` - collections of a fixed number of elements\n\n  There are two data types without an accompanying module:\n\n    * Bitstring - a sequence of bits, created with `<<>>/1`.\n      When the number of bits is divisible by 8, they are called binaries and can\n      be manipulated with Erlang's [`:binary`](`:binary`) module\n    * Reference - a unique value in the runtime system, created with `make_ref/0`\n\n  ### Data types\n\n  Elixir also provides other data types that are built on top of the types\n  listed above. Some of them are:\n\n    * `Date` - `year-month-day` structs in a given calendar\n    * `DateTime` - date and time with time zone in a given calendar\n    * `Exception` - data raised from errors and unexpected scenarios\n    * `MapSet` - unordered collections of unique elements\n    * `NaiveDateTime` - date and time without time zone in a given calendar\n    * `Keyword` - lists of two-element tuples, often representing optional values\n    * `Range` - inclusive ranges between two integers\n    * `Regex` - regular expressions\n    * `String` - UTF-8 encoded binaries representing characters\n    * `Time` - `hour:minute:second` structs in a given calendar\n    * `URI` - representation of URIs that identify resources\n    * `Version` - representation of versions and requirements\n\n  ### System modules\n\n  Modules that interface with the underlying system, such as:\n\n    * `IO` - handles input and output\n    * `File` - interacts with the underlying file system\n    * `Path` - manipulates file system paths\n    * `System` - reads and writes system information\n\n  ### Protocols\n\n  Protocols add polymorphic dispatch to Elixir. They are contracts\n  implementable by data types. See `Protocol` for more information on\n  protocols. Elixir provides the following protocols in the standard library:\n\n    * `Collectable` - collects data into a data type\n    * `Enumerable` - handles collections in Elixir. The `Enum` module\n      provides eager functions for working with collections, the `Stream`\n      module provides lazy functions\n    * `Inspect` - converts data types into their programming language\n      representation\n    * `List.Chars` - converts data types to their outside world\n      representation as charlists (non-programming based)\n    * `String.Chars` - converts data types to their outside world\n      representation as strings (non-programming based)\n\n  ### Process-based and application-centric functionality\n\n  The following modules build on top of processes to provide concurrency,\n  fault-tolerance, and more.\n\n    * `Agent` - a process that encapsulates mutable state\n    * `Application` - functions for starting, stopping and configuring\n      applications\n    * `GenServer` - a generic client-server API\n    * `Registry` - a key-value process-based storage\n    * `Supervisor` - a process that is responsible for starting,\n      supervising and shutting down other processes\n    * `Task` - a process that performs computations\n    * `Task.Supervisor` - a supervisor for managing tasks exclusively\n\n  ### Supporting documents\n\n  Under the \"Pages\" section in sidebar you will find tutorials, guides,\n  and reference documents that outline Elixir semantics and behaviors\n  in more detail. Those are:\n\n    * [Compatibility and deprecations](compatibility-and-deprecations.md) - lists\n      compatibility between every Elixir version and Erlang/OTP, release schema;\n      lists all deprecated functions, when they were deprecated and alternatives\n    * [Library guidelines](library-guidelines.md) - general guidelines, anti-patterns,\n      and rules for those writing libraries\n    * [Naming conventions](naming-conventions.md) - naming conventions for Elixir code\n    * [Operators reference](operators.md) - lists all Elixir operators and their precedences\n    * [Patterns and guards](patterns-and-guards.md) - an introduction to patterns,\n      guards, and extensions\n    * [Syntax reference](syntax-reference.md) - the language syntax reference\n    * [Typespecs reference](typespecs.md)- types and function specifications, including list of types\n    * [Unicode syntax](unicode-syntax.md) - outlines Elixir support for Unicode\n\n  ## Guards\n\n  This module includes the built-in guards used by Elixir developers.\n  They are a predefined set of functions and macros that augment pattern\n  matching, typically invoked after the `when` operator. For example:\n\n      def drive(%User{age: age}) when age >= 16 do\n        ...\n      end\n\n  The clause above will only be invoked if the user's age is more than\n  or equal to 16. Guards also support joining multiple conditions with\n  `and` and `or`. The whole guard is true if all guard expressions will\n  evaluate to `true`. A more complete introduction to guards is available\n  in the [Patterns and guards](patterns-and-guards.md) page.\n\n  ## Truthy and falsy values\n\n  Besides the booleans `true` and `false`, Elixir has the\n  concept of a \"truthy\" or \"falsy\" value.\n\n    *  a value is truthy when it is neither `false` nor `nil`\n    *  a value is falsy when it is either `false` or `nil`\n\n  Elixir has functions, like `and/2`, that *only* work with\n  booleans, but also functions that work with these\n  truthy/falsy values, like `&&/2` and `!/1`.\n\n  ## Structural comparison\n\n  The functions in this module perform structural comparison. This allows\n  different data types to be compared using comparison operators:\n\n      1 < :an_atom\n\n  This is possible so Elixir developers can create collections, such as\n  dictionaries and ordered sets, that store a mixture of data types in them.\n  To understand why this matters, let's discuss the two types of comparisons\n  we find in software: _structural_ and _semantic_.\n\n  Structural means we are comparing the underlying data structures and we often\n  want those operations to be as fast as possible, because it is used to power\n  several algorithms and data structures in the language. A semantic comparison\n  worries about what each data type represents. For example, semantically\n  speaking, it doesn't make sense to compare `Time` with `Date`.\n\n  One example that shows the differences between structural and semantic\n  comparisons are strings: \"alien\" sorts less than \"office\" (`\"alien\" < \"office\"`)\n  but \"álien\" is greater than \"office\". This happens because `<` compares the\n  underlying bytes that form the string. If you were doing alphabetical listing,\n  you may want \"álien\" to also appear before \"office\".\n\n  This means **comparisons in Elixir are structural**, as it has the goal\n  of comparing data types as efficiently as possible to create flexible\n  and performant data structures. This distinction is specially important\n  for functions that provide ordering, such as `>/2`, `</2`, `>=/2`,\n  `<=/2`, `min/2`, and `max/2`. For example:\n\n      ~D[2017-03-31] > ~D[2017-04-01]\n\n  will return `true` because structural comparison compares the `:day`\n  field before `:month` or `:year`. Luckily, the Elixir compiler will\n  detect whenever comparing structs or whenever comparing code that is\n  either always true or false, and emit a warning accordingly.\n\n  In order to perform semantic comparisons, the relevant data-types\n  provide a `compare/2` function, such as `Date.compare/2`:\n\n      iex> Date.compare(~D[2017-03-31], ~D[2017-04-01])\n      :lt\n\n  Alternatively, you can use the functions in the `Enum` module to\n  sort or compute a maximum/minimum:\n\n      iex> Enum.sort([~D[2017-03-31], ~D[2017-04-01]], Date)\n      [~D[2017-03-31], ~D[2017-04-01]]\n      iex> Enum.max([~D[2017-03-31], ~D[2017-04-01]], Date)\n      ~D[2017-04-01]\n\n  The second argument is precisely the module to be used for semantic\n  comparison. Keeping this distinction is important, because if semantic\n  comparison was used by default for implementing data structures and\n  algorithms, they could become orders of magnitude slower!\n\n  Finally, note there is an overall structural sorting order, called\n  \"Term Ordering\", defined below. This order is provided for reference\n  purposes, it is not required for Elixir developers to know it by heart.\n\n  ### Term ordering\n\n  ```\n  number < atom < reference < function < port < pid < tuple < map < list < bitstring\n  ```\n\n  When comparing two numbers of different types (a number being either\n  an integer or a float), a conversion to the type with greater precision\n  will always occur, unless the comparison operator used is either `===/2`\n  or `!==/2`. A float will be considered more precise than an integer, unless\n  the float is greater/less than +/-9007199254740992.0 respectively,\n  at which point all the significant figures of the float are to the left\n  of the decimal point. This behavior exists so that the comparison of large\n  numbers remains transitive.\n\n  The collection types are compared using the following rules:\n\n  * Tuples are compared by size, then element by element.\n  * Maps are compared by size, then by key-value pairs.\n  * Lists are compared element by element.\n  * Bitstrings are compared byte by byte, incomplete bytes are compared bit by bit.\n  * Atoms are compared using their string value, codepoint by codepoint.\n\n  ### Examples\n\n  We can check the truthiness of a value by using the `!/1`\n  function twice.\n\n  Truthy values:\n\n      iex> !!true\n      true\n      iex> !!5\n      true\n      iex> !![1,2]\n      true\n      iex> !!\"foo\"\n      true\n\n  Falsy values (of which there are exactly two):\n\n      iex> !!false\n      false\n      iex> !!nil\n      false\n\n  ## Inlining\n\n  Some of the functions described in this module are inlined by\n  the Elixir compiler into their Erlang counterparts in the\n  [`:erlang`](`:erlang`) module.\n  Those functions are called BIFs (built-in internal functions)\n  in Erlang-land and they exhibit interesting properties, as some\n  of them are allowed in guards and others are used for compiler\n  optimizations.\n\n  Most of the inlined functions can be seen in effect when\n  capturing the function:\n\n      iex> &Kernel.is_atom/1\n      &:erlang.is_atom/1\n\n  Those functions will be explicitly marked in their docs as\n  \"inlined by the compiler\".\n  \"\"\"\n\n  # We need this check only for bootstrap purposes.\n  # Once Kernel is loaded and we recompile, it is a no-op.\n  @compile {:inline, bootstrapped?: 1}\n  case :code.ensure_loaded(Kernel) do\n    {:module, _} ->\n      defp bootstrapped?(module), do: is_atom(module)\n\n    {:error, _} ->\n      defp bootstrapped?(module), do: :code.ensure_loaded(module) == {:module, module}\n  end\n\n  ## Delegations to Erlang with inlining (macros)\n\n  @doc \"\"\"\n  Returns an integer or float which is the arithmetical absolute value of `number`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> abs(-3.33)\n      3.33\n\n      iex> abs(-3)\n      3\n\n  \"\"\"\n  @doc guard: true\n  @spec abs(number) :: number\n  def abs(number) do\n    :erlang.abs(number)\n  end\n\n  @doc \"\"\"\n  Invokes the given anonymous function `fun` with the list of\n  arguments `args`.\n\n  If the number of arguments is known at compile time, prefer\n  `fun.(arg_1, arg_2, ..., arg_n)` as it is clearer than\n  `apply(fun, [arg_1, arg_2, ..., arg_n])`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> apply(fn x -> x * 2 end, [2])\n      4\n\n  \"\"\"\n  @spec apply(fun, [any]) :: any\n  def apply(fun, args) do\n    :erlang.apply(fun, args)\n  end\n\n  @doc \"\"\"\n  Invokes the given function from `module` with the list of\n  arguments `args`.\n\n  `apply/3` is used to invoke functions where the module, function\n  name or arguments are defined dynamically at runtime. For this\n  reason, you can't invoke macros using `apply/3`, only functions.\n\n  If the number of arguments and the function name are known at compile time,\n  prefer `module.function(arg_1, arg_2, ..., arg_n)` as it is clearer than\n  `apply(module, :function, [arg_1, arg_2, ..., arg_n])`.\n\n  `apply/3` cannot be used to call private functions.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> apply(Enum, :reverse, [[1, 2, 3]])\n      [3, 2, 1]\n\n  \"\"\"\n  @spec apply(module, function_name :: atom, [any]) :: any\n  def apply(module, function_name, args) do\n    :erlang.apply(module, function_name, args)\n  end\n\n  @doc \"\"\"\n  Extracts the part of the binary at `start` with `size`.\n\n  If `start` or `size` reference in any way outside the binary,\n  an `ArgumentError` exception is raised.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> binary_part(\"foo\", 1, 2)\n      \"oo\"\n\n  A negative `size` can be used to extract bytes that come *before* the byte\n  at `start`:\n\n      iex> binary_part(\"Hello\", 5, -3)\n      \"llo\"\n\n  An `ArgumentError` is raised when the `size` is outside of the binary:\n\n      binary_part(\"Hello\", 0, 10)\n      ** (ArgumentError) argument error\n\n  \"\"\"\n  @doc guard: true\n  @spec binary_part(binary, non_neg_integer, integer) :: binary\n  def binary_part(binary, start, size) do\n    :erlang.binary_part(binary, start, size)\n  end\n\n  @doc \"\"\"\n  Returns an integer which is the size in bits of `bitstring`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> bit_size(<<433::16, 3::3>>)\n      19\n\n      iex> bit_size(<<1, 2, 3>>)\n      24\n\n  \"\"\"\n  @doc guard: true\n  @spec bit_size(bitstring) :: non_neg_integer\n  def bit_size(bitstring) do\n    :erlang.bit_size(bitstring)\n  end\n\n  @doc \"\"\"\n  Returns the number of bytes needed to contain `bitstring`.\n\n  That is, if the number of bits in `bitstring` is not divisible by 8, the\n  resulting number of bytes will be rounded up (by excess). This operation\n  happens in constant time.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> byte_size(<<433::16, 3::3>>)\n      3\n\n      iex> byte_size(<<1, 2, 3>>)\n      3\n\n  \"\"\"\n  @doc guard: true\n  @spec byte_size(bitstring) :: non_neg_integer\n  def byte_size(bitstring) do\n    :erlang.byte_size(bitstring)\n  end\n\n  @doc \"\"\"\n  Returns the smallest integer greater than or equal to `number`.\n\n  If you want to perform ceil operation on other decimal places,\n  use `Float.ceil/2` instead.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> ceil(10)\n      10\n\n      iex> ceil(10.1)\n      11\n\n      iex> ceil(-10.1)\n      -10\n\n  \"\"\"\n  @doc since: \"1.8.0\", guard: true\n  @spec ceil(number) :: integer\n  def ceil(number) do\n    :erlang.ceil(number)\n  end\n\n  @doc \"\"\"\n  Performs an integer division.\n\n  Raises an `ArithmeticError` exception if one of the arguments is not an\n  integer, or when the `divisor` is `0`.\n\n  `div/2` performs *truncated* integer division. This means that\n  the result is always rounded towards zero.\n\n  If you want to perform floored integer division (rounding towards negative infinity),\n  use `Integer.floor_div/2` instead.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> div(5, 2)\n      2\n\n      iex> div(6, -4)\n      -1\n\n      iex> div(-99, 2)\n      -49\n\n      div(100, 0)\n      ** (ArithmeticError) bad argument in arithmetic expression\n\n  \"\"\"\n  @doc guard: true\n  @spec div(integer, neg_integer | pos_integer) :: integer\n  def div(dividend, divisor) do\n    :erlang.div(dividend, divisor)\n  end\n\n  @doc \"\"\"\n  Stops the execution of the calling process with the given reason.\n\n  Since evaluating this function causes the process to terminate,\n  it has no return value.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n  When a process reaches its end, by default it exits with\n  reason `:normal`. You can also call `exit/1` explicitly if you\n  want to terminate a process but not signal any failure:\n\n      exit(:normal)\n\n  In case something goes wrong, you can also use `exit/1` with\n  a different reason:\n\n      exit(:seems_bad)\n\n  If the exit reason is not `:normal`, all the processes linked to the process\n  that exited will crash (unless they are trapping exits).\n\n  ## OTP exits\n\n  Exits are used by the OTP to determine if a process exited abnormally\n  or not. The following exits are considered \"normal\":\n\n    * `exit(:normal)`\n    * `exit(:shutdown)`\n    * `exit({:shutdown, term})`\n\n  Exiting with any other reason is considered abnormal and treated\n  as a crash. This means the default supervisor behavior kicks in,\n  error reports are emitted, and so forth.\n\n  This behavior is relied on in many different places. For example,\n  `ExUnit` uses `exit(:shutdown)` when exiting the test process to\n  signal linked processes, supervision trees and so on to politely\n  shut down too.\n\n  ## CLI exits\n\n  Building on top of the exit signals mentioned above, if the\n  process started by the command line exits with any of the three\n  reasons above, its exit is considered normal and the Operating\n  System process will exit with status 0.\n\n  It is, however, possible to customize the operating system exit\n  signal by invoking:\n\n      exit({:shutdown, integer})\n\n  This will cause the operating system process to exit with the status given by\n  `integer` while signaling all linked Erlang processes to politely\n  shut down.\n\n  Any other exit reason will cause the operating system process to exit with\n  status `1` and linked Erlang processes to crash.\n  \"\"\"\n  @spec exit(term) :: no_return\n  def exit(reason) do\n    :erlang.exit(reason)\n  end\n\n  @doc \"\"\"\n  Returns the largest integer smaller than or equal to `number`.\n\n  If you want to perform floor operation on other decimal places,\n  use `Float.floor/2` instead.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> floor(10)\n      10\n\n      iex> floor(9.7)\n      9\n\n      iex> floor(-9.7)\n      -10\n\n  \"\"\"\n  @doc since: \"1.8.0\", guard: true\n  @spec floor(number) :: integer\n  def floor(number) do\n    :erlang.floor(number)\n  end\n\n  @doc \"\"\"\n  Returns the head of a list. Raises `ArgumentError` if the list is empty.\n\n  The head of a list is its first element.\n\n  It works with improper lists.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> hd([1, 2, 3, 4])\n      1\n\n      iex> hd([1 | 2])\n      1\n\n  Giving it an empty list raises:\n\n      hd([])\n      ** (ArgumentError) argument error\n\n  \"\"\"\n  @doc guard: true\n  @spec hd(nonempty_maybe_improper_list(elem, term)) :: elem when elem: term\n  def hd(list) do\n    :erlang.hd(list)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is an atom, otherwise returns `false`.\n\n  Note `true`, `false`, and `nil` are atoms in Elixir, as well as\n  module names. Therefore this function will return `true` to all\n  of those values.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_atom(:name)\n      true\n\n      iex> is_atom(false)\n      true\n\n      iex> is_atom(AnAtom)\n      true\n\n      iex> is_atom(\"string\")\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec is_atom(term) :: boolean\n  def is_atom(term) do\n    :erlang.is_atom(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a binary, otherwise returns `false`.\n\n  A binary always contains a complete number of bytes.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_binary(\"foo\")\n      true\n      iex> is_binary(<<1::3>>)\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec is_binary(term) :: boolean\n  def is_binary(term) do\n    :erlang.is_binary(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a bitstring (including a binary), otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_bitstring(\"foo\")\n      true\n      iex> is_bitstring(<<1::3>>)\n      true\n\n  \"\"\"\n  @doc guard: true\n  @spec is_bitstring(term) :: boolean\n  def is_bitstring(term) do\n    :erlang.is_bitstring(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is either the atom `true` or the atom `false` (i.e.,\n  a boolean), otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_boolean(false)\n      true\n\n      iex> is_boolean(true)\n      true\n\n      iex> is_boolean(:test)\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec is_boolean(term) :: boolean\n  def is_boolean(term) do\n    :erlang.is_boolean(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a floating-point number, otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_float(2.15)\n      true\n\n      iex> is_float(3.45e5)\n      true\n\n      iex> is_float(5)\n      false\n  \"\"\"\n  @doc guard: true\n  @spec is_float(term) :: boolean\n  def is_float(term) do\n    :erlang.is_float(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a function, otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_function(fn x -> x + x end)\n      true\n\n      iex> is_function(\"not a function\")\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec is_function(term) :: boolean\n  def is_function(term) do\n    :erlang.is_function(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a function that can be applied with `arity` number of arguments;\n  otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_function(fn x -> x * 2 end, 1)\n      true\n      iex> is_function(fn x -> x * 2 end, 2)\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec is_function(term, non_neg_integer) :: boolean\n  def is_function(term, arity) do\n    :erlang.is_function(term, arity)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is an integer, otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_integer(5)\n      true\n\n      iex> is_integer(5.0)\n      false\n  \"\"\"\n  @doc guard: true\n  @spec is_integer(term) :: boolean\n  def is_integer(term) do\n    :erlang.is_integer(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a list with zero or more elements, otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_list([1, 2, 3])\n      true\n\n      iex> is_list(key: :sum, value: 3)\n      true\n\n      iex> is_list({1, 2, 3})\n      false\n  \"\"\"\n  @doc guard: true\n  @spec is_list(term) :: boolean\n  def is_list(term) do\n    :erlang.is_list(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is either an integer or a floating-point number;\n  otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_number(2.15)\n      true\n\n      iex> is_number(5)\n      true\n\n      iex> is_number(:one)\n      false\n  \"\"\"\n  @doc guard: true\n  @spec is_number(term) :: boolean\n  def is_number(term) do\n    :erlang.is_number(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a PID (process identifier), otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> {:ok, agent_pid} = Agent.start_link(fn -> 0 end)\n      iex> is_pid(agent_pid)\n      true\n\n      iex> is_pid(self())\n      true\n\n      iex> is_pid(:pid)\n      false\n  \"\"\"\n  @doc guard: true\n  @spec is_pid(term) :: boolean\n  def is_pid(term) do\n    :erlang.is_pid(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a port identifier, otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> [port | _] = Port.list()\n      iex> is_port(port)\n      true\n\n      iex> is_port(:port)\n      false\n  \"\"\"\n  @doc guard: true\n  @spec is_port(term) :: boolean\n  def is_port(term) do\n    :erlang.is_port(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a reference, otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> ref = make_ref()\n      iex> is_reference(ref)\n      true\n\n      iex> is_reference(:ref)\n      false\n  \"\"\"\n  @doc guard: true\n  @spec is_reference(term) :: boolean\n  def is_reference(term) do\n    :erlang.is_reference(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a tuple, otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_tuple({1, 2, 3})\n      true\n\n      iex> is_tuple({})\n      true\n\n      iex> is_tuple(true)\n      false\n  \"\"\"\n  @doc guard: true\n  @spec is_tuple(term) :: boolean\n  def is_tuple(term) do\n    :erlang.is_tuple(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a map, otherwise returns `false`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  > #### Structs are maps {: .info}\n  >\n  > Structs are also maps, and many of Elixir data structures are implemented\n  > using structs: `Range`s, `Regex`es, `Date`s...\n  >\n  >     iex> is_map(1..10)\n  >     true\n  >     iex> is_map(~D[2024-04-18])\n  >     true\n  >\n  > If you mean to specifically check for non-struct maps, use\n  > `is_non_struct_map/1` instead.\n  >\n  >     iex> is_non_struct_map(1..10)\n  >     false\n  \"\"\"\n  @doc guard: true\n  @spec is_map(term) :: boolean\n  def is_map(term) do\n    :erlang.is_map(term)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `key` is a key in `map`, otherwise returns `false`.\n\n  It raises `BadMapError` if the first element is not a map.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> is_map_key(%{a: \"foo\", b: \"bar\"}, :a)\n      true\n\n      iex> is_map_key(%{a: \"foo\", b: \"bar\"}, :c)\n      false\n  \"\"\"\n  @doc guard: true, since: \"1.10.0\"\n  @spec is_map_key(map, term) :: boolean\n  def is_map_key(map, key) do\n    :erlang.is_map_key(key, map)\n  end\n\n  @doc \"\"\"\n  Returns the length of `list`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> length([1, 2, 3, 4, 5, 6, 7, 8, 9])\n      9\n\n  \"\"\"\n  @doc guard: true\n  @spec length(list) :: non_neg_integer\n  def length(list) do\n    :erlang.length(list)\n  end\n\n  @doc \"\"\"\n  Returns an almost unique reference.\n\n  The returned reference will re-occur after approximately 2^82 calls;\n  therefore it is unique enough for practical purposes.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      make_ref()\n      #=> #Reference<0.0.0.135>\n\n  \"\"\"\n  @spec make_ref() :: reference\n  def make_ref() do\n    :erlang.make_ref()\n  end\n\n  @doc \"\"\"\n  Returns the size of a map.\n\n  The size of a map is the number of key-value pairs that the map contains.\n\n  This operation happens in constant time.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> map_size(%{a: \"foo\", b: \"bar\"})\n      2\n\n  \"\"\"\n  @doc guard: true\n  @spec map_size(map) :: non_neg_integer\n  def map_size(map) do\n    :erlang.map_size(map)\n  end\n\n  @doc \"\"\"\n  Returns the biggest of the two given terms according to\n  their structural comparison.\n\n  If the terms compare equal, the first one is returned.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> max(1, 2)\n      2\n      iex> max(\"a\", \"b\")\n      \"b\"\n\n  \"\"\"\n  @doc guard: true\n  @spec max(first, second) :: first | second when first: term, second: term\n  def max(first, second) do\n    :erlang.max(first, second)\n  end\n\n  @doc \"\"\"\n  Returns the smallest of the two given terms according to\n  their structural comparison.\n\n  If the terms compare equal, the first one is returned.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> min(1, 2)\n      1\n      iex> min(\"foo\", \"bar\")\n      \"bar\"\n\n  \"\"\"\n  @doc guard: true\n  @spec min(first, second) :: first | second when first: term, second: term\n  def min(first, second) do\n    :erlang.min(first, second)\n  end\n\n  @doc \"\"\"\n  Returns an atom representing the name of the local node.\n  If the node is not alive, `:nonode@nohost` is returned instead.\n\n  Allowed in guard tests. Inlined by the compiler.\n  \"\"\"\n  @doc guard: true\n  @spec node() :: node\n  def node do\n    :erlang.node()\n  end\n\n  @doc \"\"\"\n  Returns the node where the given argument is located.\n  The argument can be a PID, a reference, or a port.\n  If the local node is not alive, `:nonode@nohost` is returned.\n\n  Allowed in guard tests. Inlined by the compiler.\n  \"\"\"\n  @doc guard: true\n  @spec node(pid | reference | port) :: node\n  def node(arg) do\n    :erlang.node(arg)\n  end\n\n  @doc \"\"\"\n  Computes the remainder of an integer division.\n\n  `rem/2` uses truncated division, which means that\n  the result will always have the sign of the `dividend`.\n\n  Raises an `ArithmeticError` exception if one of the arguments is not an\n  integer, or when the `divisor` is `0`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> rem(5, 2)\n      1\n      iex> rem(6, -4)\n      2\n\n  \"\"\"\n  @doc guard: true\n  @spec rem(integer, neg_integer | pos_integer) :: integer\n  def rem(dividend, divisor) do\n    :erlang.rem(dividend, divisor)\n  end\n\n  @doc \"\"\"\n  Rounds a number to the nearest integer.\n\n  If the number is equidistant to the two nearest integers, rounds away from zero.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> round(5.6)\n      6\n\n      iex> round(5.2)\n      5\n\n      iex> round(-9.9)\n      -10\n\n      iex> round(-9)\n      -9\n\n      iex> round(2.5)\n      3\n\n      iex> round(-2.5)\n      -3\n\n  \"\"\"\n  @doc guard: true\n  @spec round(number) :: integer\n  def round(number) do\n    :erlang.round(number)\n  end\n\n  @doc \"\"\"\n  Sends a message to the given `dest` and returns the message.\n\n  `dest` may be a remote or local PID, a local port, a locally\n  registered name, or a tuple in the form of `{registered_name, node}` for a\n  registered name at another node.\n\n  For additional documentation, see the [`!` operator Erlang\n  documentation](https://www.erlang.org/doc/reference_manual/expressions#send).\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> send(self(), :hello)\n      :hello\n\n  \"\"\"\n  @spec send(dest :: Process.dest(), message) :: message when message: any\n  def send(dest, message) do\n    :erlang.send(dest, message)\n  end\n\n  @doc \"\"\"\n  Returns the PID (process identifier) of the calling process.\n\n  Allowed in guard clauses. Inlined by the compiler.\n  \"\"\"\n  @doc guard: true\n  @spec self() :: pid\n  def self() do\n    :erlang.self()\n  end\n\n  @doc \"\"\"\n  Spawns the given function and returns its PID.\n\n  Typically developers do not use the `spawn` functions, instead they use\n  abstractions such as `Task`, `GenServer` and `Agent`, built on top of\n  `spawn`, that spawns processes with more conveniences in terms of\n  introspection and debugging.\n\n  Check the `Process` module for more process-related functions.\n\n  The anonymous function receives 0 arguments, and may return any value.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> current = self()\n      iex> child = spawn(fn -> send(current, {self(), 1 + 2}) end)\n      iex> receive do\n      ...>   {^child, 3} -> :ok\n      ...> end\n      :ok\n\n  \"\"\"\n  @spec spawn((-> any)) :: pid\n  def spawn(fun) do\n    :erlang.spawn(fun)\n  end\n\n  @doc \"\"\"\n  Spawns the given function `fun` from the given `module` passing it the given\n  `args` and returns its PID.\n\n  Typically developers do not use the `spawn` functions, instead they use\n  abstractions such as `Task`, `GenServer` and `Agent`, built on top of\n  `spawn`, that spawns processes with more conveniences in terms of\n  introspection and debugging.\n\n  Check the `Process` module for more process-related functions.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      spawn(SomeModule, :function, [1, 2, 3])\n\n  \"\"\"\n  @spec spawn(module, atom, list) :: pid\n  def spawn(module, fun, args) do\n    :erlang.spawn(module, fun, args)\n  end\n\n  @doc \"\"\"\n  Spawns the given function, links it to the current process, and returns its PID.\n\n  Typically developers do not use the `spawn` functions, instead they use\n  abstractions such as `Task`, `GenServer` and `Agent`, built on top of\n  `spawn`, that spawns processes with more conveniences in terms of\n  introspection and debugging.\n\n  Check the `Process` module for more process-related functions. For more\n  information on linking, check `Process.link/1`.\n\n  The anonymous function receives 0 arguments, and may return any value.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> current = self()\n      iex> child = spawn_link(fn -> send(current, {self(), 1 + 2}) end)\n      iex> receive do\n      ...>   {^child, 3} -> :ok\n      ...> end\n      :ok\n\n  \"\"\"\n  @spec spawn_link((-> any)) :: pid\n  def spawn_link(fun) do\n    :erlang.spawn_link(fun)\n  end\n\n  @doc \"\"\"\n  Spawns the given function `fun` from the given `module` passing it the given\n  `args`, links it to the current process, and returns its PID.\n\n  Typically developers do not use the `spawn` functions, instead they use\n  abstractions such as `Task`, `GenServer` and `Agent`, built on top of\n  `spawn`, that spawns processes with more conveniences in terms of\n  introspection and debugging.\n\n  Check the `Process` module for more process-related functions. For more\n  information on linking, check `Process.link/1`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      spawn_link(SomeModule, :function, [1, 2, 3])\n\n  \"\"\"\n  @spec spawn_link(module, atom, list) :: pid\n  def spawn_link(module, fun, args) do\n    :erlang.spawn_link(module, fun, args)\n  end\n\n  @doc \"\"\"\n  Spawns the given function, monitors it and returns its PID\n  and monitoring reference.\n\n  Typically developers do not use the `spawn` functions, instead they use\n  abstractions such as `Task`, `GenServer` and `Agent`, built on top of\n  `spawn`, that spawns processes with more conveniences in terms of\n  introspection and debugging.\n\n  Check the `Process` module for more process-related functions.\n\n  The anonymous function receives 0 arguments, and may return any value.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> current = self()\n      iex> {child, _ref} = spawn_monitor(fn -> send(current, {self(), 1 + 2}) end)\n      iex> receive do\n      ...>   {^child, 3} -> :ok\n      ...> end\n      :ok\n\n  \"\"\"\n  @spec spawn_monitor((-> any)) :: {pid, reference}\n  def spawn_monitor(fun) do\n    :erlang.spawn_monitor(fun)\n  end\n\n  @doc \"\"\"\n  Spawns the given module and function passing the given args,\n  monitors it and returns its PID and monitoring reference.\n\n  Typically developers do not use the `spawn` functions, instead they use\n  abstractions such as `Task`, `GenServer` and `Agent`, built on top of\n  `spawn`, that spawns processes with more conveniences in terms of\n  introspection and debugging.\n\n  Check the `Process` module for more process-related functions.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      spawn_monitor(SomeModule, :function, [1, 2, 3])\n\n  \"\"\"\n  @spec spawn_monitor(module, atom, list) :: {pid, reference}\n  def spawn_monitor(module, fun, args) do\n    :erlang.spawn_monitor(module, fun, args)\n  end\n\n  @doc \"\"\"\n  Pipes the first argument, `value`, into the second argument, a function `fun`,\n  and returns `value` itself.\n\n  Useful for running synchronous side effects in a pipeline, using the `|>/2` operator.\n\n  ## Examples\n\n      iex> tap(1, fn x -> x + 1 end)\n      1\n\n  Most commonly, this is used in pipelines, using the `|>/2` operator.\n  For example, let's suppose you want to inspect part of a data structure.\n  You could write:\n\n      %{a: 1}\n      |> Map.update!(:a, & &1 + 2)\n      |> tap(&IO.inspect(&1.a))\n      |> Map.update!(:a, & &1 * 2)\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  defmacro tap(value, fun) do\n    quote bind_quoted: [fun: fun, value: value] do\n      _ = fun.(value)\n      value\n    end\n  end\n\n  @doc \"\"\"\n  A non-local return from a function.\n\n  Using `throw/1` is generally discouraged, as it allows a function\n  to escape from its regular execution flow, which can make the code\n  harder to read. Furthermore, all thrown values must be caught by\n  `try/catch`. See `try/1` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec throw(term) :: no_return\n  def throw(term) do\n    :erlang.throw(term)\n  end\n\n  @doc \"\"\"\n  Returns the tail of a list. Raises `ArgumentError` if the list is empty.\n\n  The tail of a list is the list without its first element.\n\n  It works with improper lists.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> tl([1, 2, 3, :go])\n      [2, 3, :go]\n\n      iex> tl([:one])\n      []\n\n      iex> tl([:a, :b | :improper_end])\n      [:b | :improper_end]\n\n      iex> tl([:a | %{b: 1}])\n      %{b: 1}\n\n  Giving it an empty list raises:\n\n      tl([])\n      ** (ArgumentError) argument error\n\n  \"\"\"\n  @doc guard: true\n  @spec tl(nonempty_maybe_improper_list(elem, last)) :: maybe_improper_list(elem, last) | last\n        when elem: term, last: term\n  def tl(list) do\n    :erlang.tl(list)\n  end\n\n  @doc \"\"\"\n  Returns the integer part of `number`.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> trunc(5.4)\n      5\n\n      iex> trunc(-5.99)\n      -5\n\n      iex> trunc(-5)\n      -5\n\n  \"\"\"\n  @doc guard: true\n  @spec trunc(number) :: integer\n  def trunc(number) do\n    :erlang.trunc(number)\n  end\n\n  @doc \"\"\"\n  Returns the size of a tuple.\n\n  This operation happens in constant time.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> tuple_size({:a, :b, :c})\n      3\n\n  \"\"\"\n  @doc guard: true\n  @spec tuple_size(tuple) :: non_neg_integer\n  def tuple_size(tuple) do\n    :erlang.tuple_size(tuple)\n  end\n\n  @doc \"\"\"\n  Arithmetic addition operator.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 + 2\n      3\n\n  \"\"\"\n  @doc guard: true\n  @spec integer + integer :: integer\n  @spec float + float :: float\n  @spec integer + float :: float\n  @spec float + integer :: float\n  def left + right do\n    :erlang.+(left, right)\n  end\n\n  @doc \"\"\"\n  Arithmetic subtraction operator.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 - 2\n      -1\n\n  \"\"\"\n  @doc guard: true\n  @spec integer - integer :: integer\n  @spec float - float :: float\n  @spec integer - float :: float\n  @spec float - integer :: float\n  def left - right do\n    :erlang.-(left, right)\n  end\n\n  @doc \"\"\"\n  Arithmetic positive unary operator.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> +1\n      1\n\n  \"\"\"\n  @doc guard: true\n  @spec +integer :: integer\n  @spec +float :: float\n  def +value do\n    :erlang.+(value)\n  end\n\n  @doc \"\"\"\n  Arithmetic negative unary operator.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> -2\n      -2\n\n  \"\"\"\n  @doc guard: true\n  @spec -0 :: 0\n  @spec -pos_integer :: neg_integer\n  @spec -neg_integer :: pos_integer\n  @spec -float :: float\n  def -value do\n    :erlang.-(value)\n  end\n\n  @doc \"\"\"\n  Arithmetic multiplication operator.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 * 2\n      2\n\n  \"\"\"\n  @doc guard: true\n  @spec integer * integer :: integer\n  @spec float * float :: float\n  @spec integer * float :: float\n  @spec float * integer :: float\n  def left * right do\n    :erlang.*(left, right)\n  end\n\n  @doc \"\"\"\n  Arithmetic division operator.\n\n  The result is always a float. Use `div/2` and `rem/2` if you want\n  an integer division or the remainder.\n\n  Raises `ArithmeticError` if `right` is 0 or 0.0.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 / 2\n      0.5\n\n      iex> -3.0 / 2.0\n      -1.5\n\n      iex> 5 / 1\n      5.0\n\n      7 / 0\n      ** (ArithmeticError) bad argument in arithmetic expression\n\n  \"\"\"\n  @doc guard: true\n  @spec number / number :: float\n  def left / right do\n    :erlang./(left, right)\n  end\n\n  @doc \"\"\"\n  List concatenation operator. Concatenates a proper list and a term, returning a list.\n\n  The complexity of `a ++ b` is proportional to `length(a)`, so avoid repeatedly\n  appending to lists of arbitrary length, for example, `list ++ [element]`.\n  Instead, consider prepending via `[element | rest]` and then reversing.\n\n  If the `right` operand is not a proper list, it returns an improper list.\n  If the `left` operand is not a proper list, it raises `ArgumentError`.\n  If the `left` operand is an empty list, it returns the `right` operand.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> [1] ++ [2, 3]\n      [1, 2, 3]\n\n      iex> ~c\"foo\" ++ ~c\"bar\"\n      ~c\"foobar\"\n\n      # a non-list on the right will return an improper list\n      # with said element at the end\n      iex> [1, 2] ++ 3\n      [1, 2 | 3]\n      iex> [1, 2] ++ {3, 4}\n      [1, 2 | {3, 4}]\n\n      # improper list on the right will return an improper list\n      iex> [1] ++ [2 | 3]\n      [1, 2 | 3]\n\n      # empty list on the left will return the right operand\n      iex> [] ++ 1\n      1\n\n  The `++/2` operator is right associative, meaning:\n\n      iex> [1, 2, 3] -- [1] ++ [2]\n      [3]\n\n  As it is equivalent to:\n\n      iex> [1, 2, 3] -- ([1] ++ [2])\n      [3]\n\n  \"\"\"\n  @spec [] ++ a :: a when a: term()\n  @spec nonempty_list() ++ term() :: maybe_improper_list()\n  def left ++ right do\n    :erlang.++(left, right)\n  end\n\n  @doc \"\"\"\n  List subtraction operator. Removes the first occurrence of an element\n  on the left list for each element on the right.\n\n  This function is optimized so the complexity of `a -- b` is proportional\n  to `length(a) * log(length(b))`. See also the [Erlang efficiency\n  guide](https://www.erlang.org/doc/system/efficiency_guide.html).\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> [1, 2, 3] -- [1, 2]\n      [3]\n\n      iex> [1, 2, 3, 2, 1] -- [1, 2, 2]\n      [3, 1]\n\n  The `--/2` operator is right associative, meaning:\n\n      iex> [1, 2, 3] -- [2] -- [3]\n      [1, 3]\n\n  As it is equivalent to:\n\n      iex> [1, 2, 3] -- ([2] -- [3])\n      [1, 3]\n\n  \"\"\"\n  @spec list -- list :: list\n  def left -- right do\n    :erlang.--(left, right)\n  end\n\n  @doc \"\"\"\n  Strictly boolean \"not\" operator.\n\n  `value` must be a boolean; if it's not, an `ArgumentError` exception is raised.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> not false\n      true\n\n  \"\"\"\n  @doc guard: true\n  @spec not true :: false\n  @spec not false :: true\n  def not value do\n    :erlang.not(value)\n  end\n\n  @doc \"\"\"\n  Less-than operator.\n\n  Returns `true` if `left` is less than `right`.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 < 2\n      true\n\n  \"\"\"\n  @doc guard: true\n  @spec term < term :: boolean\n  def left < right do\n    :erlang.<(left, right)\n  end\n\n  @doc \"\"\"\n  Greater-than operator.\n\n  Returns `true` if `left` is more than `right`.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 > 2\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec term > term :: boolean\n  def left > right do\n    :erlang.>(left, right)\n  end\n\n  @doc \"\"\"\n  Less-than or equal to operator.\n\n  Returns `true` if `left` is less than or equal to `right`.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 <= 2\n      true\n\n  \"\"\"\n  @doc guard: true\n  @spec term <= term :: boolean\n  def left <= right do\n    :erlang.\"=<\"(left, right)\n  end\n\n  @doc \"\"\"\n  Greater-than or equal to operator.\n\n  Returns `true` if `left` is more than or equal to `right`.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 >= 2\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec term >= term :: boolean\n  def left >= right do\n    :erlang.>=(left, right)\n  end\n\n  @doc \"\"\"\n  Equal to operator. Returns `true` if the two terms are equal.\n\n  This operator considers 1 and 1.0 to be equal. For stricter\n  semantics, use `===/2` instead.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 == 2\n      false\n\n      iex> 1 == 1.0\n      true\n\n  \"\"\"\n  @doc guard: true\n  @spec term == term :: boolean\n  def left == right do\n    :erlang.==(left, right)\n  end\n\n  @doc \"\"\"\n  Not equal to operator.\n\n  Returns `true` if the two terms are not equal.\n\n  This operator considers 1 and 1.0 to be equal. For match\n  comparison, use `!==/2` instead.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 != 2\n      true\n\n      iex> 1 != 1.0\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec term != term :: boolean\n  def left != right do\n    :erlang.\"/=\"(left, right)\n  end\n\n  @doc \"\"\"\n  Strictly equal to operator.\n\n  Returns `true` if the two terms are exactly equal.\n\n  The terms are only considered to be exactly equal if they\n  have the same value and are of the same type. For example,\n  `1 == 1.0` returns `true`, but since they are of different\n  types, `1 === 1.0` returns `false`.\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 === 2\n      false\n\n      iex> 1 === 1.0\n      false\n\n  \"\"\"\n  @doc guard: true\n  @spec term === term :: boolean\n  def left === right do\n    :erlang.\"=:=\"(left, right)\n  end\n\n  @doc \"\"\"\n  Strictly not equal to operator.\n\n  Returns `true` if the two terms are not exactly equal.\n  See `===/2` for a definition of what is considered \"exactly equal\".\n\n  This performs a structural comparison where all Elixir\n  terms can be compared with each other. See the [\"Structural\n  comparison\"](#module-structural-comparison) section\n  for more information.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> 1 !== 2\n      true\n\n      iex> 1 !== 1.0\n      true\n\n  \"\"\"\n  @doc guard: true\n  @spec term !== term :: boolean\n  def left !== right do\n    :erlang.\"=/=\"(left, right)\n  end\n\n  @doc \"\"\"\n  Gets the element at the zero-based `index` in `tuple`.\n\n  It raises `ArgumentError` when index is negative or it is out of range of the tuple elements.\n\n  Allowed in guard tests. Inlined by the compiler.\n\n  ## Examples\n\n      iex> tuple = {:foo, :bar, 3}\n      iex> elem(tuple, 1)\n      :bar\n\n      elem({}, 0)\n      ** (ArgumentError) argument error\n\n      elem({:foo, :bar}, 2)\n      ** (ArgumentError) argument error\n\n  \"\"\"\n  @doc guard: true\n  @spec elem(tuple, non_neg_integer) :: term\n  def elem(tuple, index) do\n    :erlang.element(index + 1, tuple)\n  end\n\n  @doc \"\"\"\n  Puts `value` at the given zero-based `index` in `tuple`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> tuple = {:foo, :bar, 3}\n      iex> put_elem(tuple, 0, :baz)\n      {:baz, :bar, 3}\n\n  \"\"\"\n  @spec put_elem(tuple, non_neg_integer, term) :: tuple\n  def put_elem(tuple, index, value) do\n    :erlang.setelement(index + 1, tuple, value)\n  end\n\n  ## Implemented in Elixir\n\n  defp annotate_case(extra, {:case, meta, args}) do\n    {:case, extra ++ meta, args}\n  end\n\n  defp x_is_false_or_nil do\n    quote generated: true do\n      :erlang.orelse(:erlang.\"=:=\"(x, false), :erlang.\"=:=\"(x, nil))\n    end\n  end\n\n  @doc \"\"\"\n  Strictly boolean \"or\" operator.\n\n  If `left` is `true`, returns `true`, otherwise returns `right`.\n\n  Requires only the `left` operand to be a boolean since it short-circuits.\n  If the `left` operand is not a boolean, a `BadBooleanError` exception is\n  raised.\n\n  Allowed in guard tests.\n\n  ## Examples\n\n      iex> true or false\n      true\n\n      iex> false or 42\n      42\n\n      iex> 42 or false\n      ** (BadBooleanError) expected a boolean on left-side of \"or\", got: 42\n\n  \"\"\"\n  @doc guard: true\n  defmacro left or right do\n    case __CALLER__.context do\n      nil -> build_boolean_check(:or, left, true, right)\n      :match -> invalid_match!(:or)\n      :guard -> quote(do: :erlang.orelse(unquote(left), unquote(right)))\n    end\n  end\n\n  @doc \"\"\"\n  Strictly boolean \"and\" operator.\n\n  If `left` is `false`, returns `false`, otherwise returns `right`.\n\n  Requires only the `left` operand to be a boolean since it short-circuits. If\n  the `left` operand is not a boolean, a `BadBooleanError` exception is raised.\n\n  Allowed in guard tests.\n\n  ## Examples\n\n      iex> true and false\n      false\n\n      iex> true and \"yay!\"\n      \"yay!\"\n\n      iex> \"yay!\" and true\n      ** (BadBooleanError) expected a boolean on left-side of \"and\", got: \"yay!\"\n\n  \"\"\"\n  @doc guard: true\n  defmacro left and right do\n    case __CALLER__.context do\n      nil -> build_boolean_check(:and, left, right, false)\n      :match -> invalid_match!(:and)\n      :guard -> quote(do: :erlang.andalso(unquote(left), unquote(right)))\n    end\n  end\n\n  defp build_boolean_check(operator, check, true_clause, false_clause) do\n    bools =\n      quote do\n        false -> unquote(false_clause)\n        true -> unquote(true_clause)\n      end\n\n    error =\n      quote generated: true do\n        other -> :erlang.error({:badbool, unquote(operator), other})\n      end\n\n    annotate_case(\n      [optimize_boolean: true, type_check: {:case, operator}],\n      {:case, [], [check, [do: bools ++ error]]}\n    )\n  end\n\n  @doc \"\"\"\n  Boolean \"not\" operator.\n\n  Receives any value (not just booleans) and returns `true` if `value`\n  is `false` or `nil`; returns `false` otherwise.\n\n  Not allowed in guard clauses.\n\n  ## Examples\n\n      iex> !Enum.empty?([])\n      false\n\n      iex> !List.first([])\n      true\n\n  \"\"\"\n  defmacro !value\n\n  defmacro !{:!, _, [value]} do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"!\")\n\n    annotate_case(\n      [optimize_boolean: true, type_check: {:case, :!}],\n      quote do\n        case unquote(value) do\n          x when unquote(x_is_false_or_nil()) -> false\n          _ -> true\n        end\n      end\n    )\n  end\n\n  defmacro !value do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"!\")\n\n    annotate_case(\n      [optimize_boolean: true, type_check: {:case, :!}],\n      quote do\n        case unquote(value) do\n          x when unquote(x_is_false_or_nil()) -> true\n          _ -> false\n        end\n      end\n    )\n  end\n\n  @doc \"\"\"\n  Binary concatenation operator. Concatenates two binaries.\n\n  Raises an `ArgumentError` if one of the sides aren't binaries.\n\n  ## Examples\n\n      iex> \"foo\" <> \"bar\"\n      \"foobar\"\n\n  The `<>/2` operator can also be used in pattern matching (and guard clauses) as\n  long as the left argument is a literal binary:\n\n      iex> \"foo\" <> x = \"foobar\"\n      iex> x\n      \"bar\"\n\n  `x <> \"bar\" = \"foobar\"` would result in an `ArgumentError` exception.\n\n  \"\"\"\n  defmacro left <> right do\n    concats = extract_concatenations({:<>, [], [left, right]}, __CALLER__)\n    quote(do: <<unquote_splicing(concats)>>)\n  end\n\n  # Extracts concatenations in order to optimize many\n  # concatenations into one single clause.\n  defp extract_concatenations({:<>, _, [left, right]}, caller) do\n    [wrap_concatenation(left, :left, caller) | extract_concatenations(right, caller)]\n  end\n\n  defp extract_concatenations(other, caller) do\n    [wrap_concatenation(other, :right, caller)]\n  end\n\n  defp wrap_concatenation(binary, _side, _caller) when is_binary(binary) do\n    binary\n  end\n\n  defp wrap_concatenation(literal, _side, _caller)\n       when is_list(literal) or is_atom(literal) or is_integer(literal) or is_float(literal) do\n    :erlang.error(\n      ArgumentError.exception(\n        \"expected binary argument in <> operator but got: #{Macro.to_string(literal)}\"\n      )\n    )\n  end\n\n  defp wrap_concatenation(other, side, caller) do\n    expanded = expand_concat_argument(other, side, caller)\n    {:\"::\", [], [expanded, {:binary, [], nil}]}\n  end\n\n  defp expand_concat_argument(arg, :left, %{context: :match} = caller) do\n    expanded_arg =\n      case bootstrapped?(Macro) do\n        true -> Macro.expand(arg, caller)\n        false -> arg\n      end\n\n    case expanded_arg do\n      {var, _, nil} when is_atom(var) ->\n        invalid_concat_left_argument_error(Atom.to_string(var))\n\n      _ ->\n        expanded_arg\n    end\n  end\n\n  defp expand_concat_argument(arg, _, _) do\n    arg\n  end\n\n  defp invalid_concat_left_argument_error(arg) do\n    :erlang.error(\n      ArgumentError.exception(\n        \"cannot perform prefix match because the left operand of <> has unknown size. \" <>\n          \"The left operand of <> inside a match should either be a literal binary or \" <>\n          \"an existing variable with the pin operator (such as ^some_var). Got: #{arg}\"\n      )\n    )\n  end\n\n  @doc \"\"\"\n  Raises an exception.\n\n  If `message` is a string, it raises a `RuntimeError` exception with it.\n\n  If `message` is an atom, it just calls `raise/2` with the atom as the first\n  argument and `[]` as the second one.\n\n  If `message` is an exception struct, it is raised as is.\n\n  If `message` is anything else, `raise` will fail with an `ArgumentError`\n  exception.\n\n  ## Examples\n\n      iex> raise \"oops\"\n      ** (RuntimeError) oops\n\n      try do\n        1 + :foo\n      rescue\n        x in [ArithmeticError] ->\n          IO.puts(\"that was expected\")\n          raise x\n      end\n\n  \"\"\"\n  defmacro raise(message) do\n    # Try to figure out the type at compilation time\n    # to avoid dead code and make Dialyzer happy.\n    message =\n      case not is_binary(message) and bootstrapped?(Macro) do\n        true -> Macro.expand(message, __CALLER__)\n        false -> message\n      end\n\n    erlang_error =\n      fn x ->\n        quote do\n          :erlang.error(unquote(x), :none, error_info: %{module: Exception})\n        end\n      end\n\n    case message do\n      message when is_binary(message) ->\n        erlang_error.(quote do: RuntimeError.exception(unquote(message)))\n\n      {:<<>>, _, _} = message ->\n        erlang_error.(quote do: RuntimeError.exception(unquote(message)))\n\n      alias when is_atom(alias) ->\n        erlang_error.(quote do: unquote(alias).exception([]))\n\n      _ ->\n        erlang_error.(quote do: Kernel.Utils.raise(unquote(message)))\n    end\n  end\n\n  @doc \"\"\"\n  Raises an exception.\n\n  Calls the `exception/1` function on the given argument (which has to be a\n  module name like `ArgumentError` or `RuntimeError`) passing `attributes`\n  in order to retrieve the exception struct.\n\n  Any module that contains a call to the `defexception/1` macro automatically\n  implements the `c:Exception.exception/1` callback expected by `raise/2`.\n  For more information, see `defexception/1`.\n\n  ## Examples\n\n      iex> raise(ArgumentError, \"Sample\")\n      ** (ArgumentError) Sample\n\n  \"\"\"\n  defmacro raise(exception, attributes) do\n    quote do\n      :erlang.error(unquote(exception).exception(unquote(attributes)))\n    end\n  end\n\n  @doc \"\"\"\n  Raises an exception preserving a previous stacktrace.\n\n  Works like `raise/1` but does not generate a new stacktrace.\n\n  Note that `__STACKTRACE__` can be used inside catch/rescue\n  to retrieve the current stacktrace.\n\n  ## Examples\n\n      iex> try do\n      ...>  raise \"oops\"\n      ...> rescue\n      ...>  exception ->\n      ...>    reraise exception, __STACKTRACE__\n      ...> end\n      ** (RuntimeError) oops\n\n  \"\"\"\n  defmacro reraise(message, stacktrace) do\n    # Try to figure out the type at compilation time\n    # to avoid dead code and make Dialyzer happy.\n    case Macro.expand(message, __CALLER__) do\n      message when is_binary(message) ->\n        quote do\n          :erlang.raise(:error, RuntimeError.exception(unquote(message)), unquote(stacktrace))\n        end\n\n      {:<<>>, _, _} = message ->\n        quote do\n          :erlang.raise(:error, RuntimeError.exception(unquote(message)), unquote(stacktrace))\n        end\n\n      alias when is_atom(alias) ->\n        quote do\n          :erlang.raise(:error, unquote(alias).exception([]), unquote(stacktrace))\n        end\n\n      message ->\n        quote do\n          :erlang.raise(:error, Kernel.Utils.raise(unquote(message)), unquote(stacktrace))\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Raises an exception preserving a previous stacktrace.\n\n  `reraise/3` works like `reraise/2`, except it passes arguments to the\n  `exception/1` function as explained in `raise/2`.\n\n  ## Examples\n\n      try do\n        raise \"oops\"\n      rescue\n        exception ->\n          reraise WrapperError, [exception: exception], __STACKTRACE__\n      end\n\n  \"\"\"\n  defmacro reraise(exception, attributes, stacktrace) do\n    quote do\n      :erlang.raise(\n        :error,\n        unquote(exception).exception(unquote(attributes)),\n        unquote(stacktrace)\n      )\n    end\n  end\n\n  @doc \"\"\"\n  Text-based match operator. Matches the string on the `left`\n  against the regular expression or string on the `right`.\n\n  If `right` is a regular expression, returns `true` if `left` matches right.\n\n  If `right` is a string, returns `true` if `left` contains `right`.\n\n  ## Examples\n\n      iex> \"abcd\" =~ ~r/c(d)/\n      true\n\n      iex> \"abcd\" =~ ~r/e/\n      false\n\n      iex> \"abcd\" =~ ~r//\n      true\n\n      iex> \"abcd\" =~ \"bc\"\n      true\n\n      iex> \"abcd\" =~ \"ad\"\n      false\n\n      iex> \"abcd\" =~ \"abcd\"\n      true\n\n      iex> \"abcd\" =~ \"\"\n      true\n\n  For more information about regular expressions, please check the `Regex` module.\n  \"\"\"\n  @spec String.t() =~ (String.t() | Regex.t()) :: boolean\n  def left =~ \"\" when is_binary(left), do: true\n\n  def left =~ right when is_binary(left) and is_binary(right) do\n    :binary.match(left, right) != :nomatch\n  end\n\n  def left =~ right when is_binary(left) do\n    Regex.match?(right, left)\n  end\n\n  @doc ~S\"\"\"\n  Inspects the given argument according to the `Inspect` protocol.\n  The second argument is a keyword list with options to control\n  inspection.\n\n  ## Options\n\n  `inspect/2` accepts a list of options that are internally\n  translated to an `Inspect.Opts` struct. Check the docs for\n  `Inspect.Opts` to see the supported options.\n\n  ## Examples\n\n      iex> inspect(:foo)\n      \":foo\"\n\n      iex> inspect([1, 2, 3, 4, 5], limit: 3)\n      \"[1, 2, 3, ...]\"\n\n      iex> inspect([1, 2, 3], pretty: true, width: 0)\n      \"[1,\\n 2,\\n 3]\"\n\n      iex> inspect(\"olá\" <> <<0>>)\n      \"<<111, 108, 195, 161, 0>>\"\n\n      iex> inspect(\"olá\" <> <<0>>, binaries: :as_strings)\n      \"\\\"olá\\\\0\\\"\"\n\n      iex> inspect(\"olá\", binaries: :as_binaries)\n      \"<<111, 108, 195, 161>>\"\n\n      iex> inspect(~c\"bar\")\n      \"~c\\\"bar\\\"\"\n\n      iex> inspect([0 | ~c\"bar\"])\n      \"[0, 98, 97, 114]\"\n\n      iex> inspect(100, base: :octal)\n      \"0o144\"\n\n      iex> inspect(100, base: :hex)\n      \"0x64\"\n\n  Note that the `Inspect` protocol does not necessarily return a valid\n  representation of an Elixir term. In such cases, the inspected result\n  must start with `#`. For example, inspecting a function will return:\n\n      inspect(fn a, b -> a + b end)\n      #=> #Function<...>\n\n  The `Inspect` protocol can be derived to hide certain fields\n  from structs, so they don't show up in logs, inspects and similar.\n  See the \"Deriving\" section of the documentation of the `Inspect`\n  protocol for more information.\n  \"\"\"\n  @spec inspect(Inspect.t(), [Inspect.Opts.new_opt()]) :: String.t()\n  def inspect(term, opts \\\\ []) when is_list(opts) do\n    opts = Inspect.Opts.new(opts)\n\n    limit =\n      case opts.pretty do\n        true -> opts.width\n        false -> :infinity\n      end\n\n    doc = Inspect.Algebra.group(Inspect.Algebra.to_doc(term, opts))\n    IO.iodata_to_binary(Inspect.Algebra.format(doc, limit))\n  end\n\n  @doc \"\"\"\n  Creates and updates a struct.\n\n  The `struct` argument may be an atom (which defines `defstruct`)\n  or a `struct` itself. The second argument is any `Enumerable` that\n  emits two-element tuples (key-value pairs) during enumeration.\n\n  Keys in the `Enumerable` that don't exist in the struct are automatically\n  discarded. Note that keys must be atoms, as only atoms are allowed when\n  defining a struct. If there are duplicate keys in the `Enumerable`, the last\n  entry will be taken (same behavior as `Map.new/1`).\n\n  This function is useful for dynamically creating and updating structs, as\n  well as for converting maps to structs; in the latter case, just inserting\n  the appropriate `:__struct__` field into the map may not be enough and\n  `struct/2` should be used instead.\n\n  ## Examples\n\n      defmodule User do\n        defstruct name: \"john\"\n      end\n\n      struct(User)\n      #=> %User{name: \"john\"}\n\n      opts = [name: \"meg\"]\n      user = struct(User, opts)\n      #=> %User{name: \"meg\"}\n\n      struct(user, unknown: \"value\")\n      #=> %User{name: \"meg\"}\n\n      struct(User, %{name: \"meg\"})\n      #=> %User{name: \"meg\"}\n\n      # String keys are ignored\n      struct(User, %{\"name\" => \"meg\"})\n      #=> %User{name: \"john\"}\n\n  \"\"\"\n  @spec struct(module | struct, Enumerable.t()) :: struct\n  def struct(struct, fields \\\\ []) do\n    struct(struct, fields, fn\n      {:__struct__, _val}, acc ->\n        acc\n\n      {key, val}, acc ->\n        case acc do\n          %{^key => _} -> %{acc | key => val}\n          _ -> acc\n        end\n    end)\n  end\n\n  @doc \"\"\"\n  Similar to `struct/2` but checks for key validity.\n\n  The function `struct!/2` emulates the compile time behavior\n  of structs. This means that:\n\n    * when building a struct, as in `struct!(SomeStruct, key: :value)`,\n      it is equivalent to `%SomeStruct{key: :value}` and therefore this\n      function will check if every given key-value belongs to the struct.\n      If the struct is enforcing any key via `@enforce_keys`, those will\n      be enforced as well;\n\n    * when updating a struct, as in `struct!(%SomeStruct{}, key: :value)`,\n      it is equivalent to `%SomeStruct{struct | key: :value}` and therefore this\n      function will check if every given key-value belongs to the struct.\n\n  \"\"\"\n  @spec struct!(module | struct, Enumerable.t()) :: struct\n  def struct!(struct, fields \\\\ [])\n\n  def struct!(struct, fields) when is_atom(struct) do\n    validate_struct!(struct.__struct__(fields), struct, 1)\n  end\n\n  def struct!(struct, fields) when is_map(struct) do\n    struct(struct, fields, fn\n      {:__struct__, _}, acc ->\n        acc\n\n      {key, val}, acc ->\n        Map.replace!(acc, key, val)\n    end)\n  end\n\n  defp struct(struct, [], _fun) when is_atom(struct) do\n    validate_struct!(struct.__struct__(), struct, 0)\n  end\n\n  defp struct(struct, fields, fun) when is_atom(struct) do\n    struct(validate_struct!(struct.__struct__(), struct, 0), fields, fun)\n  end\n\n  defp struct(%_{} = struct, [], _fun) do\n    struct\n  end\n\n  defp struct(%_{} = struct, fields, fun) do\n    Enum.reduce(fields, struct, fun)\n  end\n\n  defp validate_struct!(%{__struct__: module} = struct, module, _arity) do\n    struct\n  end\n\n  defp validate_struct!(%{__struct__: struct_name}, module, arity) when is_atom(struct_name) do\n    error_message =\n      \"expected struct name returned by #{inspect(module)}.__struct__/#{arity} to be \" <>\n        \"#{inspect(module)}, got: #{inspect(struct_name)}\"\n\n    :erlang.error(ArgumentError.exception(error_message))\n  end\n\n  defp validate_struct!(expr, module, arity) do\n    error_message =\n      \"expected #{inspect(module)}.__struct__/#{arity} to return a map with a :__struct__ \" <>\n        \"key that holds the name of the struct (atom), got: #{inspect(expr)}\"\n\n    :erlang.error(ArgumentError.exception(error_message))\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a struct, otherwise returns `false`.\n\n  Allowed in guard tests.\n\n  ## Examples\n\n      iex> is_struct(URI.parse(\"/\"))\n      true\n\n      iex> is_struct(%{})\n      false\n\n  \"\"\"\n  @doc since: \"1.10.0\", guard: true\n  defmacro is_struct(term) do\n    case __CALLER__.context do\n      nil ->\n        quote do\n          case unquote(term) do\n            %_{} -> true\n            _ -> false\n          end\n        end\n\n      :match ->\n        invalid_match!(:is_struct)\n\n      :guard ->\n        quote do\n          is_map(unquote(term)) and :erlang.is_map_key(:__struct__, unquote(term)) and\n            is_atom(:erlang.map_get(:__struct__, unquote(term)))\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a struct of `name`, otherwise returns `false`.\n\n  `is_struct/2` does not check that `name` exists and is a valid struct.\n  If you want such validations, you must pattern match on the struct\n  instead, such as `match?(%URI{}, arg)`.\n\n  Allowed in guard tests.\n\n  ## Examples\n\n      iex> is_struct(URI.parse(\"/\"), URI)\n      true\n\n      iex> is_struct(URI.parse(\"/\"), Macro.Env)\n      false\n\n  \"\"\"\n  @doc since: \"1.11.0\", guard: true\n  defmacro is_struct(term, name) do\n    case __CALLER__.context do\n      nil ->\n        quote generated: true do\n          case unquote(name) do\n            name when is_atom(name) ->\n              case unquote(term) do\n                %{__struct__: ^name} -> true\n                _ -> false\n              end\n\n            _ ->\n              raise ArgumentError\n          end\n        end\n\n      :match ->\n        invalid_match!(:is_struct)\n\n      :guard ->\n        quote do\n          is_map(unquote(term)) and\n            (is_atom(unquote(name)) or :fail) and\n            :erlang.is_map_key(:__struct__, unquote(term)) and\n            :erlang.map_get(:__struct__, unquote(term)) == unquote(name)\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a map that is not a struct, otherwise\n  returns `false`.\n\n  Allowed in guard tests.\n\n  ## Examples\n\n      iex> is_non_struct_map(%{})\n      true\n\n      iex> is_non_struct_map(URI.parse(\"/\"))\n      false\n\n      iex> is_non_struct_map(nil)\n      false\n\n  \"\"\"\n  @doc since: \"1.17.0\", guard: true\n  defmacro is_non_struct_map(term) do\n    case __CALLER__.context do\n      nil ->\n        quote do\n          case unquote(term) do\n            %_{} -> false\n            %{} -> true\n            _ -> false\n          end\n        end\n\n      :match ->\n        invalid_match!(:is_non_struct_map)\n\n      :guard ->\n        quote do\n          is_map(unquote(term)) and\n            not (:erlang.is_map_key(:__struct__, unquote(term)) and\n                   is_atom(:erlang.map_get(:__struct__, unquote(term))))\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is an exception, otherwise returns `false`.\n\n  Allowed in guard tests.\n\n  ## Examples\n\n      iex> is_exception(%RuntimeError{})\n      true\n\n      iex> is_exception(%{})\n      false\n\n  \"\"\"\n  @doc since: \"1.11.0\", guard: true\n  defmacro is_exception(term) do\n    case __CALLER__.context do\n      nil ->\n        quote do\n          case unquote(term) do\n            %_{__exception__: true} -> true\n            _ -> false\n          end\n        end\n\n      :match ->\n        invalid_match!(:is_exception)\n\n      :guard ->\n        quote do\n          is_map(unquote(term)) and :erlang.is_map_key(:__struct__, unquote(term)) and\n            is_atom(:erlang.map_get(:__struct__, unquote(term))) and\n            :erlang.is_map_key(:__exception__, unquote(term)) and\n            :erlang.map_get(:__exception__, unquote(term)) == true\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is an exception of `name`, otherwise returns `false`.\n\n  Allowed in guard tests.\n\n  ## Examples\n\n      iex> is_exception(%RuntimeError{}, RuntimeError)\n      true\n\n      iex> is_exception(%RuntimeError{}, Macro.Env)\n      false\n\n  \"\"\"\n  @doc since: \"1.11.0\", guard: true\n  defmacro is_exception(term, name) do\n    case __CALLER__.context do\n      nil ->\n        quote do\n          case unquote(name) do\n            name when is_atom(name) ->\n              case unquote(term) do\n                %{__struct__: ^name, __exception__: true} -> true\n                _ -> false\n              end\n\n            _ ->\n              raise ArgumentError\n          end\n        end\n\n      :match ->\n        invalid_match!(:is_exception)\n\n      :guard ->\n        quote do\n          is_map(unquote(term)) and\n            (is_atom(unquote(name)) or :fail) and\n            :erlang.is_map_key(:__struct__, unquote(term)) and\n            :erlang.map_get(:__struct__, unquote(term)) == unquote(name) and\n            :erlang.is_map_key(:__exception__, unquote(term)) and\n            :erlang.map_get(:__exception__, unquote(term)) == true\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Pipes the first argument, `value`, into the second argument, a function `fun`,\n  and returns the result of calling `fun`.\n\n  In other words, it invokes the function `fun` with `value` as argument,\n  and returns its result.\n\n  This is most commonly used in pipelines, using the `|>/2` operator, allowing you\n  to pipe a value to a function outside of its first argument.\n\n  ## Examples\n\n      iex> 1 |> then(fn x -> x * 2 end)\n      2\n\n      iex> 1 |> then(fn x -> Enum.drop([\"a\", \"b\", \"c\"], x) end)\n      [\"b\", \"c\"]\n  \"\"\"\n  @doc since: \"1.12.0\"\n  defmacro then(value, fun) do\n    quote do\n      unquote(fun).(unquote(value))\n    end\n  end\n\n  @doc \"\"\"\n  Gets a value from a nested structure with nil-safe handling.\n\n  Uses the `Access` module to traverse the structures\n  according to the given `keys`, unless the `key` is a\n  function, which is detailed in a later section.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> get_in(users, [\"john\", :age])\n      27\n      iex> # Equivalent to:\n      iex> users[\"john\"][:age]\n      27\n\n  `get_in/2` can also use the accessors in the `Access` module\n  to traverse more complex data structures. For example, here we\n  use `Access.all/0` to traverse a list:\n\n      iex> users = [%{name: \"john\", age: 27}, %{name: \"meg\", age: 23}]\n      iex> get_in(users, [Access.all(), :age])\n      [27, 23]\n\n  In case any of the components returns `nil`, `nil` will be returned\n  and `get_in/2` won't traverse any further:\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> get_in(users, [\"unknown\", :age])\n      nil\n      iex> # Equivalent to:\n      iex> users[\"unknown\"][:age]\n      nil\n\n  ## Functions as keys\n\n  If a key given to `get_in/2` is a function, the function will be invoked\n  passing three arguments:\n\n    * the operation (`:get`)\n    * the data to be accessed\n    * a function to be invoked next\n\n  This means `get_in/2` can be extended to provide custom lookups.\n  That's precisely how the `Access.all/0` key in the previous section\n  behaves. For example, we can manually implement such traversal as\n  follows:\n\n      iex> users = [%{name: \"john\", age: 27}, %{name: \"meg\", age: 23}]\n      iex> all = fn :get, data, next -> Enum.map(data, next) end\n      iex> get_in(users, [all, :age])\n      [27, 23]\n\n  The `Access` module ships with many convenience accessor functions.\n  See `Access.all/0`, `Access.key/2`, and others as examples.\n\n  ## Working with structs\n\n  By default, structs do not implement the `Access` behaviour required\n  by this function. Therefore, you can't do this:\n\n      get_in(some_struct, [:some_key, :nested_key])\n\n  There are two alternatives. Given structs have predefined keys,\n  we can use the `struct.field` notation:\n\n      some_struct.some_key.nested_key\n\n  However, the code above will fail if any of the values return `nil`.\n  If you also want to handle nil values, you can use `get_in/1`:\n\n      get_in(some_struct.some_key.nested_key)\n\n  Pattern-matching is another option for handling such cases,\n  which can be especially useful if you want to match on several\n  fields at once or provide custom return values:\n\n      case some_struct do\n        %{some_key: %{nested_key: value}} -> value\n        %{} -> nil\n      end\n\n  \"\"\"\n  @spec get_in(Access.t(), nonempty_list(term)) :: term\n  def get_in(data, keys)\n\n  def get_in(nil, [_ | _]), do: nil\n\n  def get_in(data, [h]) when is_function(h), do: h.(:get, data, & &1)\n  def get_in(data, [h | t]) when is_function(h), do: h.(:get, data, &get_in(&1, t))\n\n  def get_in(data, [h]), do: Access.get(data, h)\n  def get_in(data, [h | t]), do: get_in(Access.get(data, h), t)\n\n  @doc \"\"\"\n  Puts a value in a nested structure.\n\n  Uses the `Access` module to traverse the structures\n  according to the given `keys`, unless the `key` is a\n  function. If the key is a function, it will be invoked\n  as specified in `get_and_update_in/3`.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> put_in(users, [\"john\", :age], 28)\n      %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n  If any of the intermediate values are nil, it will raise:\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> put_in(users, [\"jane\", :age], \"oops\")\n      ** (ArgumentError) could not put/update key :age on a nil value\n\n  \"\"\"\n  @spec put_in(Access.t(), nonempty_list(term), term) :: Access.t()\n  def put_in(data, [_ | _] = keys, value) do\n    elem(get_and_update_in(data, keys, fn _ -> {nil, value} end), 1)\n  end\n\n  @doc \"\"\"\n  Updates a key in a nested structure.\n\n  Uses the `Access` module to traverse the structures\n  according to the given `keys`, unless the `key` is a\n  function. If the key is a function, it will be invoked\n  as specified in `get_and_update_in/3`.\n\n  `data` is a nested structure (that is, a map, keyword\n  list, or struct that implements the `Access` behaviour).\n  The `fun` argument receives the value of `key` (or `nil`\n  if `key` is not present) and the result replaces the value\n  in the structure.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> update_in(users, [\"john\", :age], &(&1 + 1))\n      %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n  Note the current value given to the anonymous function may be `nil`.\n  If any of the intermediate values are nil, it will raise:\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> update_in(users, [\"jane\", :age], & &1 + 1)\n      ** (ArgumentError) could not put/update key :age on a nil value\n\n  \"\"\"\n  @spec update_in(Access.t(), nonempty_list(term), (term -> term)) :: Access.t()\n  def update_in(data, [_ | _] = keys, fun) when is_function(fun) do\n    elem(get_and_update_in(data, keys, fn x -> {nil, fun.(x)} end), 1)\n  end\n\n  @doc \"\"\"\n  Gets a value and updates a nested structure.\n\n  `data` is a nested structure (that is, a map, keyword\n  list, or struct that implements the `Access` behaviour).\n\n  The `fun` argument receives the value of `key` (or `nil` if `key`\n  is not present) and must return one of the following values:\n\n    * a two-element tuple `{current_value, new_value}`. In this case,\n      `current_value` is the retrieved value which can possibly be operated on before\n      being returned. `new_value` is the new value to be stored under `key`.\n\n    * `:pop`, which implies that the current value under `key`\n      should be removed from the structure and returned.\n\n  This function uses the `Access` module to traverse the structures\n  according to the given `keys`, unless the `key` is a function,\n  which is detailed in a later section.\n\n  ## Examples\n\n  This function is useful when there is a need to retrieve the current\n  value (or something calculated in function of the current value) and\n  update it at the same time. For example, it could be used to read the\n  current age of a user while increasing it by one in one pass:\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> get_and_update_in(users, [\"john\", :age], &{&1, &1 + 1})\n      {27, %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}}\n\n  Note the current value given to the anonymous function may be `nil`.\n  If any of the intermediate values are nil, it will raise:\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> get_and_update_in(users, [\"jane\", :age], &{&1, &1 + 1})\n      ** (ArgumentError) could not put/update key :age on a nil value\n\n  ## Functions as keys\n\n  If a key is a function, the function will be invoked passing three\n  arguments:\n\n    * the operation (`:get_and_update`)\n    * the data to be accessed\n    * a function to be invoked next\n\n  This means `get_and_update_in/3` can be extended to provide custom\n  lookups. The downside is that functions cannot be stored as keys\n  in the accessed data structures.\n\n  When one of the keys is a function, the function is invoked.\n  In the example below, we use a function to get and increment all\n  ages inside a list:\n\n      iex> users = [%{name: \"john\", age: 27}, %{name: \"meg\", age: 23}]\n      iex> all = fn :get_and_update, data, next ->\n      ...>   data |> Enum.map(next) |> Enum.unzip()\n      ...> end\n      iex> get_and_update_in(users, [all, :age], &{&1, &1 + 1})\n      {[27, 23], [%{name: \"john\", age: 28}, %{name: \"meg\", age: 24}]}\n\n  If the previous value before invoking the function is `nil`,\n  the function *will* receive `nil` as a value and must handle it\n  accordingly (be it by failing or providing a sane default).\n\n  The `Access` module ships with many convenience accessor functions,\n  like the `all` anonymous function defined above. See `Access.all/0`,\n  `Access.key/2`, and others as examples.\n  \"\"\"\n  @spec get_and_update_in(\n          structure,\n          keys,\n          (term | nil -> {current_value, new_value} | :pop)\n        ) :: {current_value, new_structure :: structure}\n        when structure: Access.t(),\n             keys: nonempty_list(term),\n             current_value: Access.value(),\n             new_value: Access.value()\n  def get_and_update_in(data, keys, fun)\n\n  def get_and_update_in(data, [head], fun) when is_function(head, 3),\n    do: head.(:get_and_update, data, fun)\n\n  def get_and_update_in(data, [head | tail], fun) when is_function(head, 3),\n    do: head.(:get_and_update, data, &get_and_update_in(&1, tail, fun))\n\n  def get_and_update_in(data, [head], fun) when is_function(fun, 1),\n    do: Access.get_and_update(data, head, fun)\n\n  def get_and_update_in(data, [head | tail], fun) when is_function(fun, 1),\n    do: Access.get_and_update(data, head, &get_and_update_in(&1, tail, fun))\n\n  @doc \"\"\"\n  Pops a key from the given nested structure.\n\n  Uses the `Access` protocol to traverse the structures\n  according to the given `keys`, unless the `key` is a\n  function. If the key is a function, it will be invoked\n  as specified in `get_and_update_in/3`.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> pop_in(users, [\"john\", :age])\n      {27, %{\"john\" => %{}, \"meg\" => %{age: 23}}}\n\n  In case any entry returns `nil`, its key will be removed\n  and the deletion will be considered a success.\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> pop_in(users, [\"jane\", :age])\n      {nil, %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}}\n\n  \"\"\"\n  @spec pop_in(data, nonempty_list(Access.get_and_update_fun(term, data) | term)) :: {term, data}\n        when data: Access.container()\n  def pop_in(data, keys)\n\n  def pop_in(nil, [key | _]) do\n    raise ArgumentError, \"could not pop key #{inspect(key)} on a nil value\"\n  end\n\n  def pop_in(data, [_ | _] = keys) do\n    pop_in_data(data, keys)\n  end\n\n  defp pop_in_data(nil, [_ | _]), do: :pop\n\n  defp pop_in_data(data, [fun]) when is_function(fun),\n    do: fun.(:get_and_update, data, fn _ -> :pop end)\n\n  defp pop_in_data(data, [fun | tail]) when is_function(fun),\n    do: fun.(:get_and_update, data, &pop_in_data(&1, tail))\n\n  defp pop_in_data(data, [key]), do: Access.pop(data, key)\n\n  defp pop_in_data(data, [key | tail]),\n    do: Access.get_and_update(data, key, &pop_in_data(&1, tail))\n\n  @doc \"\"\"\n  Gets a key from the nested structure via the given `path`, with\n  nil-safe handling.\n\n  This is similar to `get_in/2`, except the path is extracted via\n  a macro rather than passing a list. For example:\n\n      get_in(opts[:foo][:bar])\n\n  Is equivalent to:\n\n      get_in(opts, [:foo, :bar])\n\n  Additionally, this macro can traverse structs:\n\n      get_in(struct.foo.bar)\n\n  In case any of the keys returns `nil`, then `nil` will be returned\n  and `get_in/1` won't traverse any further.\n\n  Note that in order for this macro to work, the complete path must always\n  be visible by this macro. For more information about the supported path\n  expressions, please check `get_and_update_in/2` docs.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> get_in(users[\"john\"].age)\n      27\n      iex> get_in(users[\"unknown\"].age)\n      nil\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  defmacro get_in(path) do\n    {[h | t], _} = unnest(path, [], true, \"get_in/1\")\n    nest_get_in(h, quote(do: x), t)\n  end\n\n  defp nest_get_in(h, _var, []) do\n    h\n  end\n\n  defp nest_get_in(h, var, [{:map, key} | tail]) do\n    quote generated: true do\n      case unquote(h) do\n        %{unquote(key) => unquote(var)} -> unquote(nest_get_in(var, var, tail))\n        nil -> nil\n        unquote(var) -> :erlang.error({:badkey, unquote(key), unquote(var)})\n      end\n    end\n  end\n\n  defp nest_get_in(h, var, [{:access, key} | tail]) do\n    h = quote do: Access.get(unquote(h), unquote(key))\n    nest_get_in(h, var, tail)\n  end\n\n  @doc \"\"\"\n  Puts a value in a nested structure via the given `path`.\n\n  This is similar to `put_in/3`, except the path is extracted via\n  a macro rather than passing a list. For example:\n\n      put_in(opts[:foo][:bar], :baz)\n\n  Is equivalent to:\n\n      put_in(opts, [:foo, :bar], :baz)\n\n  This also works with nested structs and the `struct.path.to.value` way to specify\n  paths:\n\n      put_in(struct.foo.bar, :baz)\n\n  Note that in order for this macro to work, the complete path must always\n  be visible by this macro. For more information about the supported path\n  expressions, please check `get_and_update_in/2` docs.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> put_in(users[\"john\"][:age], 28)\n      %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> put_in(users[\"john\"].age, 28)\n      %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n  \"\"\"\n  defmacro put_in(path, value) do\n    case unnest(path, [], true, \"put_in/2\") do\n      {[h | t], true} ->\n        nest_map_update_in(h, t, quote(do: fn _ -> unquote(value) end))\n\n      {[h | t], false} ->\n        expr = nest_get_and_update_in(h, t, quote(do: fn _ -> {nil, unquote(value)} end))\n        quote(do: :erlang.element(2, unquote(expr)))\n    end\n  end\n\n  @doc \"\"\"\n  Pops a key from the nested structure via the given `path`.\n\n  This is similar to `pop_in/2`, except the path is extracted via\n  a macro rather than passing a list. For example:\n\n      pop_in(opts[:foo][:bar])\n\n  Is equivalent to:\n\n      pop_in(opts, [:foo, :bar])\n\n  Note that in order for this macro to work, the complete path must always\n  be visible by this macro. For more information about the supported path\n  expressions, please check `get_and_update_in/2` docs.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> pop_in(users[\"john\"][:age])\n      {27, %{\"john\" => %{}, \"meg\" => %{age: 23}}}\n\n      iex> users = %{john: %{age: 27}, meg: %{age: 23}}\n      iex> pop_in(users.john[:age])\n      {27, %{john: %{}, meg: %{age: 23}}}\n\n  In case any entry returns `nil`, its key will be removed\n  and the deletion will be considered a success.\n  \"\"\"\n  defmacro pop_in(path) do\n    {[h | t], _} = unnest(path, [], true, \"pop_in/1\")\n    nest_pop_in(:map, h, t)\n  end\n\n  @doc \"\"\"\n  Updates a nested structure via the given `path`.\n\n  This is similar to `update_in/3`, except the path is extracted via\n  a macro rather than passing a list. For example:\n\n      update_in(opts[:foo][:bar], &(&1 + 1))\n\n  Is equivalent to:\n\n      update_in(opts, [:foo, :bar], &(&1 + 1))\n\n  This also works with nested structs and the `struct.path.to.value` way to specify\n  paths:\n\n      update_in(struct.foo.bar, &(&1 + 1))\n\n  Note that in order for this macro to work, the complete path must always\n  be visible by this macro. For more information about the supported path\n  expressions, please check `get_and_update_in/2` docs.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> update_in(users[\"john\"][:age], &(&1 + 1))\n      %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> update_in(users[\"john\"].age, &(&1 + 1))\n      %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n  \"\"\"\n  defmacro update_in(path, fun) do\n    case unnest(path, [], true, \"update_in/2\") do\n      {[h | t], true} ->\n        nest_map_update_in(h, t, fun)\n\n      {[h | t], false} ->\n        expr = nest_get_and_update_in(h, t, quote(do: fn x -> {nil, unquote(fun).(x)} end))\n        quote(do: :erlang.element(2, unquote(expr)))\n    end\n  end\n\n  @doc \"\"\"\n  Gets a value and updates a nested data structure via the given `path`.\n\n  This is similar to `get_and_update_in/3`, except the path is extracted\n  via a macro rather than passing a list. For example:\n\n      get_and_update_in(opts[:foo][:bar], &{&1, &1 + 1})\n\n  Is equivalent to:\n\n      get_and_update_in(opts, [:foo, :bar], &{&1, &1 + 1})\n\n  This also works with nested structs and the `struct.path.to.value` way to specify\n  paths:\n\n      get_and_update_in(struct.foo.bar, &{&1, &1 + 1})\n\n  Note that in order for this macro to work, the complete path must always\n  be visible by this macro. See the \"Paths\" section below.\n\n  ## Examples\n\n      iex> users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      iex> get_and_update_in(users[\"john\"].age, &{&1, &1 + 1})\n      {27, %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}}\n\n  ## Paths\n\n  A path may start with a variable, local or remote call, and must be\n  followed by one or more:\n\n    * `foo[bar]` - accesses the key `bar` in `foo`; in case `foo` is nil,\n      `nil` is returned\n\n    * `foo.bar` - accesses a map/struct field; in case the field is not\n      present, an error is raised\n\n  Here are some valid paths:\n\n      users[\"john\"][:age]\n      users[\"john\"].age\n      User.all()[\"john\"].age\n      all_users()[\"john\"].age\n\n  Here are some invalid ones:\n\n      # Does a remote call after the initial value\n      users[\"john\"].do_something(arg1, arg2)\n\n      # Does not access any key or field\n      users\n\n  \"\"\"\n  defmacro get_and_update_in(path, fun) do\n    {[h | t], _} = unnest(path, [], true, \"get_and_update_in/2\")\n    nest_get_and_update_in(h, t, fun)\n  end\n\n  defp nest_map_update_in([], fun), do: fun\n\n  defp nest_map_update_in(list, fun) do\n    quote do\n      fn x -> unquote(nest_map_update_in(quote(do: x), list, fun)) end\n    end\n  end\n\n  defp nest_map_update_in(h, [{:map, key} | t], fun) do\n    quote do\n      Map.update!(unquote(h), unquote(key), unquote(nest_map_update_in(t, fun)))\n    end\n  end\n\n  defp nest_get_and_update_in([], fun), do: fun\n\n  defp nest_get_and_update_in(list, fun) do\n    quote do\n      fn x -> unquote(nest_get_and_update_in(quote(do: x), list, fun)) end\n    end\n  end\n\n  defp nest_get_and_update_in(h, [{:access, key} | t], fun) do\n    quote do\n      Access.get_and_update(unquote(h), unquote(key), unquote(nest_get_and_update_in(t, fun)))\n    end\n  end\n\n  defp nest_get_and_update_in(h, [{:map, key} | t], fun) do\n    quote do\n      Map.get_and_update!(unquote(h), unquote(key), unquote(nest_get_and_update_in(t, fun)))\n    end\n  end\n\n  defp nest_pop_in(kind, list) do\n    quote do\n      fn x -> unquote(nest_pop_in(kind, quote(do: x), list)) end\n    end\n  end\n\n  defp nest_pop_in(:map, h, [{:access, key}]) do\n    quote generated: true do\n      case unquote(h) do\n        nil -> {nil, nil}\n        h -> Access.pop(h, unquote(key))\n      end\n    end\n  end\n\n  defp nest_pop_in(_, _, [{:map, key}]) do\n    raise ArgumentError,\n          \"cannot use pop_in when the last segment is a map/struct field. \" <>\n            \"This would effectively remove the field #{inspect(key)} from the map/struct\"\n  end\n\n  defp nest_pop_in(_, h, [{:map, key} | t]) do\n    quote do\n      Map.get_and_update!(unquote(h), unquote(key), unquote(nest_pop_in(:map, t)))\n    end\n  end\n\n  defp nest_pop_in(_, h, [{:access, key}]) do\n    quote generated: true do\n      case unquote(h) do\n        nil -> :pop\n        h -> Access.pop(h, unquote(key))\n      end\n    end\n  end\n\n  defp nest_pop_in(_, h, [{:access, key} | t]) do\n    quote do\n      Access.get_and_update(unquote(h), unquote(key), unquote(nest_pop_in(:access, t)))\n    end\n  end\n\n  defp unnest({{:., _, [Access, :get]}, _, [expr, key]}, acc, _all_map?, kind) do\n    unnest(expr, [{:access, key} | acc], false, kind)\n  end\n\n  defp unnest({{:., _, [expr, key]}, _, []}, acc, all_map?, kind)\n       when is_tuple(expr) and :erlang.element(1, expr) != :__aliases__ and\n              :erlang.element(1, expr) != :__MODULE__ do\n    unnest(expr, [{:map, key} | acc], all_map?, kind)\n  end\n\n  defp unnest(other, [], _all_map?, kind) do\n    raise ArgumentError,\n          \"expected expression given to #{kind} to access at least one element, \" <>\n            \"got: #{Macro.to_string(other)}\"\n  end\n\n  defp unnest(other, acc, all_map?, kind) do\n    case proper_start?(other) do\n      true ->\n        {[other | acc], all_map?}\n\n      false ->\n        raise ArgumentError,\n              \"expression given to #{kind} must start with a variable, local or remote call \" <>\n                \"and be followed by an element access, got: #{Macro.to_string(other)}\"\n    end\n  end\n\n  defp proper_start?({{:., _, [expr, _]}, _, _args})\n       when is_atom(expr)\n       when :erlang.element(1, expr) == :__aliases__\n       when :erlang.element(1, expr) == :__MODULE__,\n       do: true\n\n  defp proper_start?({atom, _, _args})\n       when is_atom(atom),\n       do: true\n\n  defp proper_start?(other), do: not is_tuple(other)\n\n  @doc \"\"\"\n  Converts the argument to a string according to the\n  `String.Chars` protocol.\n\n  This is invoked when there is string interpolation.\n\n  ## Examples\n\n      iex> to_string(:foo)\n      \"foo\"\n\n  \"\"\"\n  defmacro to_string(term) do\n    quote(do: :\"Elixir.String.Chars\".to_string(unquote(term)))\n  end\n\n  @doc \"\"\"\n  Converts the given term to a charlist according to the `List.Chars` protocol.\n\n  ## Examples\n\n      iex> to_charlist(:foo)\n      ~c\"foo\"\n\n  \"\"\"\n  defmacro to_charlist(term) do\n    quote(do: :\"Elixir.List.Chars\".to_charlist(unquote(term)))\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is `nil`, `false` otherwise.\n\n  Allowed in guard clauses.\n\n  ## Examples\n\n      iex> is_nil(1 + 2)\n      false\n\n      iex> is_nil(nil)\n      true\n\n  \"\"\"\n  @doc guard: true\n  defmacro is_nil(term) do\n    quote(do: unquote(term) == nil)\n  end\n\n  @doc \"\"\"\n  A convenience macro that checks if the result of `expression` matches `pattern`.\n\n  ## Examples\n\n      iex> match?(1, 1)\n      true\n\n      iex> match?({1, _}, {1, 2})\n      true\n\n      iex> map = %{a: 1, b: 2}\n      iex> match?(%{a: _}, map)\n      true\n\n      iex> a = 1\n      iex> match?(^a, 1)\n      true\n\n  `match?/2` is very useful when filtering or finding a value in an enumerable:\n\n      iex> list = [a: 1, b: 2, a: 3]\n      iex> Enum.filter(list, &match?({:a, _}, &1))\n      [a: 1, a: 3]\n\n  Guard clauses can also be given to the match:\n\n      iex> list = [a: 1, b: 2, a: 3]\n      iex> Enum.filter(list, &match?({:a, x} when x < 2, &1))\n      [a: 1]\n\n  Variables assigned in the match will not be available outside of the\n  function call (unlike regular pattern matching with the `=` operator):\n\n      iex> match?(_x, 1)\n      true\n      iex> binding()\n      []\n\n  ## Values vs patterns\n\n  Remember the pin operator matches _values_, not _patterns_.\n  Passing a variable as the pattern will always return `true` and will\n  result in a warning that the variable is unused. Don't do this:\n\n      pattern = %{a: :a}\n      match?(pattern, %{b: :b})\n      #=> true\n\n  Similarly, moving an expression out the pattern may no longer preserve\n  its semantics. For example:\n\n      iex> match?([_ | _], [1, 2, 3])\n      true\n\n      pattern = [_ | _]\n      match?(pattern, [1, 2, 3])\n      ** (CompileError) invalid use of _. _ can only be used inside patterns to ignore values and cannot be used in expressions. Make sure you are inside a pattern or change it accordingly\n\n  Another example is that a map as a pattern performs a subset match, but not\n  once assigned to a variable:\n\n      iex> match?(%{x: 1}, %{x: 1, y: 2})\n      true\n\n      iex> attrs = %{x: 1}\n      iex> match?(^attrs, %{x: 1, y: 2})\n      false\n\n  The pin operator will check if the values are equal, using `===/2`, while\n  patterns have their own rules when matching maps, lists, and so forth.\n  Such behavior is not specific to `match?/2`. The following code also\n  throws an exception:\n\n      attrs = %{x: 1}\n      ^attrs = %{x: 1, y: 2}\n      #=> (MatchError) no match of right hand side value: %{x: 1, y: 2}\n\n  \"\"\"\n  defmacro match?(pattern, expression) do\n    success =\n      quote do\n        unquote(pattern) -> true\n      end\n\n    failure =\n      quote generated: true do\n        _ -> false\n      end\n\n    {:case, [], [expression, [do: success ++ failure]]}\n  end\n\n  @doc \"\"\"\n  Module attribute unary operator.\n\n  Reads and writes attributes in the current module.\n\n  The canonical example for attributes is annotating that a module\n  implements an OTP behaviour, such as `GenServer`:\n\n      defmodule MyServer do\n        @behaviour GenServer\n        # ... callbacks ...\n      end\n\n  By default Elixir supports all the module attributes supported by Erlang, but\n  custom attributes can be used as well:\n\n      defmodule MyServer do\n        @my_data 13\n        IO.inspect(@my_data)\n        #=> 13\n      end\n\n  Unlike Erlang, such attributes are not stored in the module by default since\n  it is common in Elixir to use custom attributes to store temporary data that\n  will be available at compile-time. Custom attributes may be configured to\n  behave closer to Erlang by using `Module.register_attribute/3`.\n\n  > #### Prefixing module attributes {: .tip}\n  >\n  > Libraries and frameworks should consider prefixing any\n  > module attributes that are private by underscore, such as `@_my_data`,\n  > so code completion tools do not show them on suggestions and prompts.\n\n  Finally, note that attributes can also be read inside functions:\n\n      defmodule MyServer do\n        @my_data 11\n        def first_data, do: @my_data\n        @my_data 13\n        def second_data, do: @my_data\n      end\n\n      MyServer.first_data()\n      #=> 11\n\n      MyServer.second_data()\n      #=> 13\n\n  It is important to note that reading an attribute takes a snapshot of\n  its current value. In other words, the value is read at compilation\n  time and not at runtime. Check the `Module` module for other functions\n  to manipulate module attributes.\n\n  ## Attention! Multiple references of the same attribute\n\n  As mentioned above, every time you read a module attribute, a snapshot\n  of its current value is taken. Therefore, if you are storing large\n  values inside module attributes (for example, embedding external files\n  in module attributes), you should avoid referencing the same attribute\n  multiple times. For example, don't do this:\n\n      @files %{\n        example1: File.read!(\"lib/example1.data\"),\n        example2: File.read!(\"lib/example2.data\")\n      }\n\n      def example1, do: @files[:example1]\n      def example2, do: @files[:example2]\n\n  In the above, each reference to `@files` may end-up with a complete\n  and individual copy of the whole `@files` module attribute. Instead,\n  reference the module attribute once in a private function:\n\n      @files %{\n        example1: File.read!(\"lib/example1.data\"),\n        example2: File.read!(\"lib/example2.data\")\n      }\n\n      defp files(), do: @files\n      def example1, do: files()[:example1]\n      def example2, do: files()[:example2]\n\n  \"\"\"\n  defmacro @expr\n\n  defmacro @{:__aliases__, _meta, _args} do\n    raise ArgumentError, \"module attributes set via @ cannot start with an uppercase letter\"\n  end\n\n  defmacro @{name, meta, args} do\n    assert_module_scope(__CALLER__, :@, 1)\n    function? = __CALLER__.function != nil\n\n    cond do\n      # Check for Macro as it is compiled later than Kernel\n      not bootstrapped?(Macro) ->\n        nil\n\n      not function? and (__CALLER__.context == :match or __CALLER__.context == :guard) ->\n        raise ArgumentError,\n              \"\"\"\n              invalid usage of module attributes. Module attributes cannot be used inside \\\n              pattern matching (and guards) outside of a function. If you are trying to \\\n              define an attribute, do not do this:\n\n                  @foo = :value\n\n              Instead, do this:\n\n                  @foo :value\n              \"\"\"\n\n      # Typespecs attributes are currently special cased by the compiler\n      is_list(args) and typespec?(name) ->\n        case bootstrapped?(Kernel.Typespec) do\n          false ->\n            :ok\n\n          true ->\n            pos = :elixir_module.cache_env(__CALLER__)\n            %{line: line, file: file, module: module} = __CALLER__\n\n            quote do\n              Kernel.Typespec.deftypespec(\n                unquote(name),\n                unquote(Macro.escape(hd(args), unquote: true)),\n                unquote(line),\n                unquote(file),\n                unquote(module),\n                unquote(pos)\n              )\n            end\n        end\n\n      true ->\n        do_at(args, meta, name, function?, __CALLER__)\n    end\n  end\n\n  # @attribute(value)\n  defp do_at([arg], meta, name, function?, env) do\n    line =\n      case :lists.keymember(:context, 1, meta) do\n        true -> nil\n        false -> env.line\n      end\n\n    cond do\n      function? ->\n        raise ArgumentError, \"cannot set attribute @#{name} inside function/macro\"\n\n      name == :behavior ->\n        raise ArgumentError, \"@behavior attribute is not supported, please use @behaviour instead\"\n\n      :lists.member(name, [:moduledoc, :typedoc, :doc]) ->\n        arg = {env.line, arg}\n\n        quote do\n          Module.__put_attribute__(__MODULE__, unquote(name), unquote(arg), unquote(line), [])\n        end\n\n      true ->\n        {arg, traces} = collect_traces(name, arg, env)\n\n        quote do\n          Module.__put_attribute__(\n            __MODULE__,\n            unquote(name),\n            unquote(arg),\n            unquote(line),\n            unquote(Macro.escape(traces))\n          )\n        end\n    end\n  end\n\n  # @attribute()\n  defp do_at([], meta, name, function?, env) do\n    IO.warn(\n      \"the @#{name}() notation (with parentheses) is deprecated, please use @#{name} (without parentheses) instead\",\n      env\n    )\n\n    do_at(nil, meta, name, function?, env)\n  end\n\n  # @attribute\n  defp do_at(args, _meta, name, function?, env) when is_atom(args) do\n    line = env.line\n    doc_attr? = :lists.member(name, [:moduledoc, :typedoc, :doc])\n\n    case function? do\n      true ->\n        case Module.__get_attribute__(env.module, name, line, false) do\n          {_, doc} when doc_attr? ->\n            do_at_escape(name, doc)\n\n          value ->\n            do_at_escape(name, value)\n        end\n\n      false when doc_attr? ->\n        quote do\n          case Module.__get_attribute__(__MODULE__, unquote(name), unquote(line), false) do\n            {_, doc} -> doc\n            value -> value\n          end\n        end\n\n      false ->\n        quote do\n          Module.__get_attribute__(__MODULE__, unquote(name), unquote(line), true)\n        end\n    end\n  end\n\n  # Error cases\n  defp do_at([{call, meta, ctx_or_args}, [{:do, _} | _] = kw], _meta, name, _function?, _env) do\n    args =\n      case is_atom(ctx_or_args) do\n        true -> []\n        false -> ctx_or_args\n      end\n\n    code = \"\\n@#{name} (#{Macro.to_string({call, meta, args ++ [kw]})})\"\n\n    raise ArgumentError, \"\"\"\n    expected 0 or 1 argument for @#{name}, got 2.\n\n    It seems you are trying to use the do-syntax with @module attributes \\\n    but the do-block binds to the attribute name. You probably want \\\n    to wrap the argument value in parentheses, like this:\n    #{String.replace(code, \"\\n\", \"\\n    \")}\n    \"\"\"\n  end\n\n  defp do_at(args, _meta, name, _function?, _env) do\n    raise ArgumentError, \"expected 0 or 1 argument for @#{name}, got: #{length(args)}\"\n  end\n\n  defp do_at_escape(name, value) do\n    try do\n      # mark module attrs as shallow-generated since the ast for their representation\n      # might contain opaque terms\n      Macro.escape(value, generated: true)\n    rescue\n      ex in [ArgumentError] ->\n        raise ArgumentError,\n              \"cannot inject attribute @#{name} into function/macro because \" <>\n                Exception.message(ex)\n    end\n  end\n\n  # Those are always compile-time dependencies, so we can skip the trace.\n  defp collect_traces(:before_compile, arg, _env), do: {arg, []}\n  defp collect_traces(:after_compile, arg, _env), do: {arg, []}\n  defp collect_traces(:after_verify, arg, _env), do: {arg, []}\n  defp collect_traces(:on_definition, arg, _env), do: {arg, []}\n\n  defp collect_traces(_name, arg, %{lexical_tracker: pid} = env) when is_pid(pid) do\n    env = %{env | function: {:__info__, 1}}\n\n    {arg, aliases} =\n      Macro.expand_literals(arg, %{}, fn\n        {:__aliases__, _, _} = alias, acc ->\n          case Macro.expand(alias, env) do\n            atom when is_atom(atom) -> {atom, Map.put(acc, atom, [])}\n            _ -> {alias, acc}\n          end\n\n        node, acc ->\n          {Macro.expand(node, env), acc}\n      end)\n\n    case map_size(aliases) do\n      0 -> {arg, []}\n      _ -> {arg, [{env.line, env.lexical_tracker, env.tracers, :maps.keys(aliases)}]}\n    end\n  end\n\n  defp collect_traces(_name, arg, _env) do\n    {arg, []}\n  end\n\n  defp typespec?(:type), do: true\n  defp typespec?(:typep), do: true\n  defp typespec?(:opaque), do: true\n  defp typespec?(:spec), do: true\n  defp typespec?(:callback), do: true\n  defp typespec?(:macrocallback), do: true\n  defp typespec?(_), do: false\n\n  @doc \"\"\"\n  Returns the binding for the given context as a keyword list.\n\n  In the returned result, keys are variable names and values are the\n  corresponding variable values.\n\n  If the given `context` is `nil` (by default it is), the binding for the\n  current context is returned.\n\n  ## Examples\n\n      iex> x = 1\n      iex> binding()\n      [x: 1]\n      iex> x = 2\n      iex> binding()\n      [x: 2]\n\n      iex> binding(:foo)\n      []\n      iex> var!(x, :foo) = 1\n      1\n      iex> binding(:foo)\n      [x: 1]\n\n  \"\"\"\n  defmacro binding(context \\\\ nil) do\n    in_match? = Macro.Env.in_match?(__CALLER__)\n\n    bindings =\n      for {v, c} <- Macro.Env.vars(__CALLER__), c == context do\n        {v, wrap_binding(in_match?, {v, [generated: true], c})}\n      end\n\n    :lists.usort(bindings)\n  end\n\n  defp wrap_binding(true, var) do\n    quote(do: ^unquote(var))\n  end\n\n  defp wrap_binding(_, var) do\n    var\n  end\n\n  @doc \"\"\"\n  Provides an `if/2` macro.\n\n  This macro expects the first argument to be a condition and the second\n  argument to be a keyword list. Generally speaking, Elixir developers\n  prefer to use pattern matching and guards in function definitions and\n  `case/2`, as they are succinct and precise. However, not all conditions\n  can be expressed through patterns and guards, which makes `if/2` a viable\n  alternative.\n\n  Similar to `case/2`, any assignment in the condition will be available\n  on both clauses, as well as after the `if` expression.\n\n  ## One-liner examples\n\n      iex> if 7 > 5, do: \"yes\"\n      \"yes\"\n\n      iex> if \"truthy value\", do: \"yes\"\n      \"yes\"\n\n  In the examples above, the `do` clause is evaluated and `\"yes\"` will be returned\n  because the condition evaluates to a truthy value (neither `false` nor `nil`).\n  Otherwise, the clause is not evaluated and `nil` will be returned:\n\n      iex> if 3 > 5, do: \"yes\"\n      nil\n\n      iex> if nil, do: IO.puts(\"this won't be printed\")\n      nil\n\n  An `else` option can be given to specify the opposite:\n\n      iex> if 3 > 5, do: \"yes\", else: \"no\"\n      \"no\"\n\n  ## Blocks examples\n\n  It's also possible to pass a block to the `if/2` macro. The first\n  example above would be translated to:\n\n      iex> if 7 > 5 do\n      ...>   \"yes\"\n      ...> end\n      \"yes\"\n\n  Note that `do`-`end` become delimiters. The third example would\n  translate to:\n\n      iex> if 3 > 5 do\n      ...>   \"yes\"\n      ...> else\n      ...>   \"no\"\n      ...> end\n      \"no\"\n\n  If you find yourself nesting conditionals inside conditionals,\n  consider using `cond/1`.\n\n  ## Variables scope\n\n  Variables set within `do`/`else` blocks do not leak to the outer context:\n\n      x = 1\n      if x > 0 do\n        x = x + 1\n        IO.puts(x)  # prints 2\n      end\n      x  # 1\n\n  Variables set in the condition are available in the outer context:\n\n      fruits = %{oranges: 3}\n      if count = fruits[:apples] do\n        # won't be evaluated\n        IO.puts(count + 1)\n      end\n      count  # nil\n\n  \"\"\"\n  defmacro if(condition, clauses) do\n    build_if(condition, clauses)\n  end\n\n  defp build_if(condition, do: do_clause) do\n    build_if(condition, do: do_clause, else: nil)\n  end\n\n  defp build_if(condition, do: do_clause, else: else_clause) do\n    annotate_case(\n      [optimize_boolean: true, type_check: {:case, :if}],\n      quote do\n        case unquote(condition) do\n          x when unquote(x_is_false_or_nil()) -> unquote(else_clause)\n          _ -> unquote(do_clause)\n        end\n      end\n    )\n  end\n\n  defp build_if(_condition, _arguments) do\n    raise ArgumentError,\n          \"invalid or duplicate keys for if, only \\\"do\\\" and an optional \\\"else\\\" are permitted\"\n  end\n\n  @doc \"\"\"\n  Provides an `unless` macro.\n\n  This macro evaluates and returns the `do` block passed in as the second\n  argument if `condition` evaluates to a falsy value (`false` or `nil`).\n  Otherwise, it returns the value of the `else` block if present or `nil` if not.\n\n  See also `if/2`.\n\n  ## Examples\n\n      iex> unless(Enum.empty?([]), do: \"Hello\")\n      nil\n\n      iex> unless(Enum.empty?([1, 2, 3]), do: \"Hello\")\n      \"Hello\"\n\n      iex> unless Enum.sum([2, 2]) == 5 do\n      ...>   \"Math still works\"\n      ...> else\n      ...>   \"Math is broken\"\n      ...> end\n      \"Math still works\"\n\n  \"\"\"\n  # TODO: Deprecate this on Elixir v1.22.\n  @doc deprecated: \"Use if/2 instead\"\n  defmacro unless(condition, clauses) do\n    build_unless(condition, clauses)\n  end\n\n  defp build_unless(condition, do: do_clause) do\n    build_unless(condition, do: do_clause, else: nil)\n  end\n\n  defp build_unless(condition, do: do_clause, else: else_clause) do\n    annotate_case(\n      [optimize_boolean: true, type_check: {:case, :unless}],\n      quote do\n        case unquote(condition) do\n          x when unquote(x_is_false_or_nil()) -> unquote(do_clause)\n          _ -> unquote(else_clause)\n        end\n      end\n    )\n  end\n\n  defp build_unless(_condition, _arguments) do\n    raise ArgumentError,\n          \"invalid or duplicate keys for unless, \" <>\n            \"only \\\"do\\\" and an optional \\\"else\\\" are permitted\"\n  end\n\n  @doc \"\"\"\n  Destructures two lists, assigning each term in the\n  right one to the matching term in the left one.\n\n  Unlike pattern matching via `=`, if the sizes of the left\n  and right lists don't match, destructuring simply stops\n  instead of raising an error.\n\n  ## Examples\n\n      iex> destructure([x, y, z], [1, 2, 3, 4, 5])\n      iex> {x, y, z}\n      {1, 2, 3}\n\n  In the example above, even though the right list has more entries than the\n  left one, destructuring works fine. If the right list is smaller, the\n  remaining elements are simply set to `nil`:\n\n      iex> destructure([x, y, z], [1])\n      iex> {x, y, z}\n      {1, nil, nil}\n\n  The left-hand side supports any expression you would use\n  on the left-hand side of a match:\n\n      iex> x = 1\n      iex> destructure([^x, y, z], [1, 2, 3])\n      iex> {x, y, z}\n      {1, 2, 3}\n\n  The example above will only work if `x` matches the first value in the right\n  list. Otherwise, it will raise a `MatchError` (like the `=` operator would\n  do).\n  \"\"\"\n  defmacro destructure(left, right) when is_list(left) do\n    quote do\n      unquote(left) = Kernel.Utils.destructure(unquote(right), unquote(length(left)))\n    end\n  end\n\n  @doc \"\"\"\n  Creates a range from `first` to `last`.\n\n  If first is less than last, the range will be increasing from\n  first to last. If first is equal to last, the range will contain\n  one element, which is the number itself.\n\n  If first is more than last, the range will be decreasing from first\n  to last, albeit this behavior is deprecated. Instead prefer to\n  explicitly list the step with `first..last//-1`.\n\n  See the `Range` module for more information.\n\n  ## Examples\n\n      iex> 0 in 1..3\n      false\n      iex> 2 in 1..3\n      true\n\n      iex> Enum.to_list(1..3)\n      [1, 2, 3]\n\n  \"\"\"\n  defmacro first..last do\n    case bootstrapped?(Macro) do\n      true ->\n        first = Macro.expand(first, __CALLER__)\n        last = Macro.expand(last, __CALLER__)\n        validate_range!(first, last)\n        stepless_range(__CALLER__.context, first, last, __CALLER__)\n\n      false ->\n        stepless_range(__CALLER__.context, first, last, __CALLER__)\n    end\n  end\n\n  defp stepless_range(_context, first, last, caller)\n       when is_integer(first) and is_integer(last) do\n    step =\n      if first <= last do\n        1\n      else\n        # TODO: Always use 1 as an step in Elixir v2.0\n        IO.warn(\n          \"#{first}..#{last} has a default step of -1, please write #{first}..#{last}//-1 instead\",\n          Macro.Env.stacktrace(caller)\n        )\n\n        -1\n      end\n\n    {:%, [], [Elixir.Range, {:%{}, [], [first: first, last: last, step: step]}]}\n  end\n\n  defp stepless_range(nil, first, last, _caller) do\n    quote(do: Elixir.Range.new(unquote(first), unquote(last)))\n  end\n\n  defp stepless_range(:guard, first, last, caller) do\n    # We need to compute the step using guards. We don't have conditionals,\n    # but we can emulate them using a map access.\n    step =\n      quote do\n        :erlang.map_get(\n          :erlang.>(unquote(first), unquote(last)),\n          %{false: unquote(1), true: unquote(-1)}\n        )\n      end\n\n    # TODO: Always assume step 1 in Elixir v2.0\n    range = \"#{Macro.to_string(first)}..#{Macro.to_string(last)}\"\n\n    IO.warn(\n      \"#{range} inside guards requires an explicit step, please write #{range}//1 or #{range}//-1 instead\",\n      Macro.Env.stacktrace(caller)\n    )\n\n    {:%, [], [Elixir.Range, {:%{}, [], [first: first, last: last, step: step]}]}\n  end\n\n  defp stepless_range(:match, first, last, caller) do\n    # TODO: Make me an error in Elixir v2.0\n    range = \"#{Macro.to_string(first)}..#{Macro.to_string(last)}\"\n\n    IO.warn(\n      \"#{range} inside match is deprecated, \" <>\n        \"you must always match on the step: #{range}//var or #{range}//_ if you want to ignore it\",\n      Macro.Env.stacktrace(caller)\n    )\n\n    {:%, [], [Elixir.Range, {:%{}, [], [first: first, last: last]}]}\n  end\n\n  @doc \"\"\"\n  Creates a range from `first` to `last` with `step`.\n\n  See the `Range` module for more information.\n\n  ## Examples\n\n      iex> 0 in 1..3//1\n      false\n      iex> 2 in 1..3//1\n      true\n      iex> 2 in 1..3//2\n      false\n\n      iex> Enum.to_list(1..3//1)\n      [1, 2, 3]\n      iex> Enum.to_list(1..3//2)\n      [1, 3]\n      iex> Enum.to_list(3..1//-1)\n      [3, 2, 1]\n      iex> Enum.to_list(1..0//1)\n      []\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  defmacro first..last//step do\n    case bootstrapped?(Macro) do\n      true ->\n        first = Macro.expand(first, __CALLER__)\n        last = Macro.expand(last, __CALLER__)\n        step = Macro.expand(step, __CALLER__)\n        validate_range!(first, last)\n        validate_step!(step)\n        range(__CALLER__.context, first, last, step)\n\n      false ->\n        {:%{}, [], [__struct__: Elixir.Range, first: first, last: last, step: step]}\n    end\n  end\n\n  defp range(context, first, last, step)\n       when is_integer(first) and is_integer(last) and is_integer(step)\n       when context != nil do\n    {:%, [], [Elixir.Range, {:%{}, [], [first: first, last: last, step: step]}]}\n  end\n\n  defp range(nil, first, last, step) do\n    quote(do: Elixir.Range.new(unquote(first), unquote(last), unquote(step)))\n  end\n\n  defp validate_range!(first, last)\n       when is_float(first) or is_float(last) or is_atom(first) or is_atom(last) or\n              is_binary(first) or is_binary(last) or is_list(first) or is_list(last) do\n    raise ArgumentError,\n          \"ranges (first..last//step) expect both sides to be integers, \" <>\n            \"got: #{Macro.to_string({:.., [], [first, last]})}\"\n  end\n\n  defp validate_range!(_, _), do: :ok\n\n  defp validate_step!(step)\n       when is_float(step) or is_atom(step) or is_binary(step) or is_list(step) or step == 0 do\n    raise ArgumentError,\n          \"ranges (first..last//step) expect the step to be a non-zero integer, \" <>\n            \"got: #{Macro.to_string(step)}\"\n  end\n\n  defp validate_step!(_), do: :ok\n\n  @doc \"\"\"\n  Creates the full-slice range `0..-1//1`.\n\n  This macro returns a range with the following properties:\n\n    * When enumerated, it is empty\n\n    * When used as a `slice`, it returns the sliced element as is\n\n  See `..///3` and the `Range` module for more information.\n\n  ## Examples\n\n      iex> Enum.to_list(..)\n      []\n\n      iex> String.slice(\"Hello world!\", ..)\n      \"Hello world!\"\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  defmacro (..) do\n    range(__CALLER__.context, 0, -1, 1)\n  end\n\n  @doc \"\"\"\n  Boolean \"and\" operator.\n\n  Provides a short-circuit operator that evaluates and returns\n  the second expression only if the first one evaluates to a truthy value\n  (neither `false` nor `nil`). Returns the first expression\n  otherwise.\n\n  Not allowed in guard clauses.\n\n  ## Examples\n\n      iex> Enum.empty?([]) && Enum.empty?([])\n      true\n\n      iex> List.first([]) && true\n      nil\n\n      iex> Enum.empty?([]) && List.first([1])\n      1\n\n      iex> false && throw(:bad)\n      false\n\n  Note that, unlike `and/2`, this operator accepts any expression\n  as the first argument, not only booleans.\n  \"\"\"\n  defmacro left && right do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"&&\")\n\n    annotate_case(\n      [type_check: {:case, :&&}],\n      quote do\n        case unquote(left) do\n          x when unquote(x_is_false_or_nil()) ->\n            x\n\n          _ ->\n            unquote(right)\n        end\n      end\n    )\n  end\n\n  @doc \"\"\"\n  Boolean \"or\" operator.\n\n  Provides a short-circuit operator that evaluates and returns the second\n  expression only if the first one does not evaluate to a truthy value (that is,\n  it is either `nil` or `false`). Returns the first expression otherwise.\n\n  Not allowed in guard clauses.\n\n  ## Examples\n\n      iex> Enum.empty?([1]) || Enum.empty?([1])\n      false\n\n      iex> List.first([]) || true\n      true\n\n      iex> Enum.empty?([1]) || 1\n      1\n\n      iex> Enum.empty?([]) || throw(:bad)\n      true\n\n  Note that, unlike `or/2`, this operator accepts any expression\n  as the first argument, not only booleans.\n  \"\"\"\n  defmacro left || right do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"||\")\n\n    annotate_case(\n      [type_check: {:case, :||}],\n      quote do\n        case unquote(left) do\n          x when unquote(x_is_false_or_nil()) ->\n            unquote(right)\n\n          x ->\n            x\n        end\n      end\n    )\n  end\n\n  @doc \"\"\"\n  Pipe operator.\n\n  This operator introduces the expression on the left-hand side as\n  the first argument to the function call on the right-hand side.\n\n  ## Examples\n\n      iex> [1, [2], 3] |> List.flatten()\n      [1, 2, 3]\n\n  The example above is the same as calling `List.flatten([1, [2], 3])`.\n\n  The `|>/2` operator is mostly useful when there is a desire to execute a series\n  of operations resembling a pipeline:\n\n      iex> [1, [2], 3] |> List.flatten() |> Enum.map(fn x -> x * 2 end)\n      [2, 4, 6]\n\n  In the example above, the list `[1, [2], 3]` is passed as the first argument\n  to the `List.flatten/1` function, then the flattened list is passed as the\n  first argument to the `Enum.map/2` function which doubles each element of the\n  list.\n\n  In other words, the expression above simply translates to:\n\n      Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end)\n\n  ## Pitfalls\n\n  There are two common pitfalls when using the pipe operator.\n\n  The first one is related to operator precedence. For example,\n  the following expression:\n\n      String.graphemes \"Hello\" |> Enum.reverse\n\n  Translates to:\n\n      String.graphemes(\"Hello\" |> Enum.reverse())\n\n  which results in an error as the `Enumerable` protocol is not defined\n  for binaries. Adding explicit parentheses resolves the ambiguity:\n\n      String.graphemes(\"Hello\") |> Enum.reverse()\n\n  Or, even better:\n\n      \"Hello\" |> String.graphemes() |> Enum.reverse()\n\n  The second limitation is that Elixir always pipes to a function\n  call. Therefore, to pipe into an anonymous function, you need to\n  invoke it:\n\n      iex> some_fun = &Regex.replace(~r/l/, &1, \"L\")\n      iex> \"Hello\" |> some_fun.()\n      \"HeLLo\"\n\n  Alternatively, you can use `then/2` for the same effect:\n\n      iex> some_fun = &Regex.replace(~r/l/, &1, \"L\")\n      iex> \"Hello\" |> then(some_fun)\n      \"HeLLo\"\n\n  `then/2` is most commonly used when you want to pipe to a function\n  but the value is expected outside of the first argument, such as\n  above. By replacing `some_fun` by its value, we get:\n\n      iex> \"Hello\" |> then(&Regex.replace(~r/l/, &1, \"L\"))\n      \"HeLLo\"\n  \"\"\"\n  defmacro left |> right do\n    fun = fn {x, pos}, acc ->\n      Macro.pipe(acc, x, pos)\n    end\n\n    :lists.foldl(fun, left, Macro.unpipe(right))\n  end\n\n  @doc \"\"\"\n  Returns `true` if `module` is loaded and contains a\n  public `function` with the given `arity`, otherwise `false`.\n\n  > ### Unloaded modules {: .warning}\n  >\n  > This function does *not* load the module in case it is not loaded\n  > and Elixir lazily loads modules by default (except on releases).\n  >\n  > This may lead to unexpected behaviour as the result of this function\n  > may depend if another code has happened to load the given module\n  > as argument beforehand. For example, this could manifest in `mix test`\n  > by having tests that fail when running in isolation or depending on the\n  > test seed. For those reasons, it is recommended to always check for\n  > `Code.ensure_loaded?/1` before `function_exported?/3`, unless you are\n  > certain the module has been loaded before.\n  >\n  > See `Code.ensure_loaded/1` for more information.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Code.ensure_loaded?(Enum) and function_exported?(Enum, :map, 2)\n      true\n\n      iex> Code.ensure_loaded?(Enum) and function_exported?(Enum, :map, 10)\n      false\n\n      iex> Code.ensure_loaded?(List) and function_exported?(List, :to_string, 1)\n      true\n  \"\"\"\n  @spec function_exported?(module, atom, arity) :: boolean\n  def function_exported?(module, function, arity) do\n    :erlang.function_exported(module, function, arity)\n  end\n\n  @doc \"\"\"\n  Returns `true` if `module` is loaded and contains a\n  public `macro` with the given `arity`, otherwise `false`.\n\n  Note that this function does not load the module in case\n  it is not loaded. See the notes under `function_exported?/3`\n  for more information.\n\n  If `module` is an Erlang module (as opposed to an Elixir module), this\n  function always returns `false`.\n\n  ## Examples\n\n      iex> Code.ensure_loaded?(Kernel) and macro_exported?(Kernel, :use, 2)\n      true\n\n      iex> Code.ensure_loaded?(:erlang) and macro_exported?(:erlang, :abs, 1)\n      false\n\n  \"\"\"\n  @spec macro_exported?(module, atom, arity) :: boolean\n  def macro_exported?(module, macro, arity)\n      when is_atom(module) and is_atom(macro) and is_integer(arity) and\n             (arity >= 0 and arity <= 255) do\n    function_exported?(module, :__info__, 1) and\n      :lists.member({macro, arity}, module.__info__(:macros))\n  end\n\n  @doc \"\"\"\n  Power operator.\n\n  It takes two numbers for input. If both are integers and the right-hand\n  side (the `exponent`) is also greater than or equal to 0, then the result\n  will also be an integer. Otherwise it returns a float.\n\n  ## Examples\n\n      iex> 2 ** 2\n      4\n      iex> 2 ** -4\n      0.0625\n\n      iex> 2.0 ** 2\n      4.0\n      iex> 2 ** 2.0\n      4.0\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec integer ** non_neg_integer :: integer\n  @spec integer ** neg_integer :: float\n  @spec float ** float :: float\n  @spec integer ** float :: float\n  @spec float ** integer :: float\n  def base ** exponent when is_integer(base) and is_integer(exponent) and exponent >= 0 do\n    integer_pow(base, 1, exponent)\n  end\n\n  def base ** exponent when is_number(base) and is_number(exponent) do\n    :math.pow(base, exponent)\n  end\n\n  # https://en.wikipedia.org/wiki/Exponentiation_by_squaring\n  defp integer_pow(_, _, 0),\n    do: 1\n\n  defp integer_pow(b, a, 1),\n    do: b * a\n\n  defp integer_pow(b, a, e) when :erlang.band(e, 1) == 0,\n    do: integer_pow(b * b, a, :erlang.bsr(e, 1))\n\n  defp integer_pow(b, a, e),\n    do: integer_pow(b * b, a * b, :erlang.bsr(e, 1))\n\n  @doc \"\"\"\n  Membership operator.\n\n  Checks if the element on the left-hand side is a member of the\n  collection on the right-hand side.\n\n  ## Examples\n\n      iex> x = 1\n      iex> x in [1, 2, 3]\n      true\n\n  This operator (which is a macro) simply translates to a call to\n  `Enum.member?/2`. The example above would translate to:\n\n      Enum.member?([1, 2, 3], x)\n\n  Elixir also supports `left not in right`, which evaluates to\n  `not(left in right)`:\n\n      iex> x = 1\n      iex> x not in [1, 2, 3]\n      false\n\n  ## Guards\n\n  The `in/2` operator (as well as `not in`) can be used in guard clauses as\n  long as the right-hand side is a range or a list.\n\n  If the right-hand side is a list, Elixir will expand the operator to a valid\n  guard expression which needs to check each value. For example:\n\n      when x in [1, 2, 3]\n\n  translates to:\n\n      when x === 1 or x === 2 or x === 3\n\n  However, this construct will be inefficient for large lists. In such cases, it\n  is best to stop using guards and use a more appropriate data structure, such\n  as `MapSet`.\n\n  If the right-hand side is a range, a more efficient comparison check will be\n  done. For example:\n\n      when x in 1..1000\n\n  translates roughly to:\n\n      when x >= 1 and x <= 1000\n\n  ### AST considerations\n\n  `left not in right` is parsed by the compiler into the AST:\n\n      {:not, _, [{:in, _, [left, right]}]}\n\n  This is the same AST as `not(left in right)`.\n\n  Additionally, `Macro.to_string/2` and `Code.format_string!/2`\n  will translate all occurrences of this AST to `left not in right`.\n  \"\"\"\n  @doc guard: true\n  defmacro left in right do\n    in_body? = __CALLER__.context == nil\n\n    expand =\n      case bootstrapped?(Macro) do\n        true -> &Macro.expand(&1, __CALLER__)\n        false -> & &1\n      end\n\n    case expand.(right) do\n      [] when not in_body? ->\n        false\n\n      [] ->\n        quote do\n          _ = unquote(left)\n          false\n        end\n\n      [head | tail] = list ->\n        case in_body? do\n          false -> in_list(left, head, tail, expand, list)\n          true -> quote(do: :lists.member(unquote(left), unquote(right)))\n        end\n\n      %{} = right ->\n        raise ArgumentError, \"found unescaped value on the right side of in/2: #{inspect(right)}\"\n\n      right ->\n        case range_fields(right) do\n          [first: first, last: last, step: step] ->\n            in_var(in_body?, left, &in_range(&1, expand.(first), expand.(last), expand.(step)))\n\n          _ when in_body? ->\n            quote(do: Elixir.Enum.member?(unquote(right), unquote(left)))\n\n          _ ->\n            raise_on_invalid_args_in_2(right)\n        end\n    end\n  end\n\n  defp range_fields({:%, _, [Elixir.Range, {:%{}, _, fields}]}), do: :lists.usort(fields)\n  defp range_fields({:%{}, _, [__struct__: Elixir.Range] ++ fields}), do: :lists.usort(fields)\n  defp range_fields(_), do: []\n\n  defp raise_on_invalid_args_in_2(right) do\n    raise ArgumentError, <<\n      \"invalid right argument for operator \\\"in\\\", it expects a compile-time proper list \",\n      \"or compile-time range on the right side when used in guard expressions, got: \",\n      Macro.to_string(right)::binary\n    >>\n  end\n\n  defp in_var(false, ast, fun), do: fun.(ast)\n\n  defp in_var(true, {atom, _, context} = var, fun) when is_atom(atom) and is_atom(context),\n    do: fun.(var)\n\n  defp in_var(true, var, fun) when is_atom(var) or is_binary(var) or is_number(var),\n    do: fun.(var)\n\n  defp in_var(true, ast, fun) do\n    quote do\n      var = unquote(ast)\n      unquote(fun.(quote(do: var)))\n    end\n  end\n\n  defp in_range(left, first, last, step) when is_integer(step) do\n    in_range_literal(left, first, last, step)\n  end\n\n  defp in_range(left, first, last, step) do\n    quoted =\n      quote do\n        unquote(generated_is_integer(left)) and unquote(generated_is_integer(first)) and\n          unquote(generated_is_integer(last)) and\n          ((:erlang.>(unquote(step), 0) and\n              unquote(increasing_compare(left, first, last))) or\n             (:erlang.<(unquote(step), 0) and\n                unquote(decreasing_compare(left, first, last))))\n      end\n\n    in_range_step(quoted, left, first, step)\n  end\n\n  defp in_range_literal(left, first, first, _step) when is_integer(first) do\n    quote do: :erlang.\"=:=\"(unquote(left), unquote(first))\n  end\n\n  defp in_range_literal(left, first, last, step) when step > 0 do\n    quoted =\n      quote generated: true do\n        Kernel.and(\n          unquote(generated_is_integer(left)),\n          unquote(increasing_compare(left, first, last))\n        )\n      end\n\n    in_range_step(quoted, left, first, step)\n  end\n\n  defp in_range_literal(left, first, last, step) when step < 0 do\n    quoted =\n      quote generated: true do\n        Kernel.and(\n          unquote(generated_is_integer(left)),\n          unquote(decreasing_compare(left, first, last))\n        )\n      end\n\n    in_range_step(quoted, left, first, step)\n  end\n\n  defp in_range_step(quoted, _left, _first, step) when step == 1 or step == -1 do\n    quoted\n  end\n\n  defp in_range_step(quoted, left, first, step) do\n    quote do\n      Kernel.and(\n        unquote(quoted),\n        :erlang.\"=:=\"(:erlang.rem(unquote(left) - unquote(first), unquote(step)), 0)\n      )\n    end\n  end\n\n  defp in_list(left, head, tail, expand, right) do\n    [head | tail] = :lists.map(&comp(left, &1, expand, right), [head | tail])\n    :lists.foldl(&quote(do: Kernel.or(unquote(&2), unquote(&1))), head, tail)\n  end\n\n  defp comp(left, {:|, _, [head, tail]}, expand, right) do\n    case expand.(tail) do\n      [] ->\n        quote(do: :erlang.\"=:=\"(unquote(left), unquote(head)))\n\n      [tail_head | tail] ->\n        quote do\n          Kernel.or(\n            :erlang.\"=:=\"(unquote(left), unquote(head)),\n            unquote(in_list(left, tail_head, tail, expand, right))\n          )\n        end\n\n      _ ->\n        raise_on_invalid_args_in_2(right)\n    end\n  end\n\n  defp comp(left, right, _expand, _right) do\n    quote(do: :erlang.\"=:=\"(unquote(left), unquote(right)))\n  end\n\n  defp generated_is_integer(arg) do\n    quote generated: true, do: :erlang.is_integer(unquote(arg))\n  end\n\n  defp increasing_compare(var, first, last) do\n    quote do\n      Kernel.and(\n        :erlang.>=(unquote(var), unquote(first)),\n        :erlang.\"=<\"(unquote(var), unquote(last))\n      )\n    end\n  end\n\n  defp decreasing_compare(var, first, last) do\n    quote do\n      Kernel.and(\n        :erlang.\"=<\"(unquote(var), unquote(first)),\n        :erlang.>=(unquote(var), unquote(last))\n      )\n    end\n  end\n\n  @doc \"\"\"\n  Marks that the given variable should not be hygienized.\n\n  This macro expects a variable and it is typically invoked\n  inside `quote/2` to mark that a variable\n  should not be hygienized. See `quote/2` for more information.\n\n  ## Examples\n\n      iex> Kernel.var!(example) = 1\n      1\n      iex> Kernel.var!(example)\n      1\n\n  \"\"\"\n  defmacro var!(var, context \\\\ nil)\n\n  defmacro var!({name, meta, atom}, context) when is_atom(name) and is_atom(atom) do\n    # Remove counter and force them to be vars\n    meta = :lists.keydelete(:counter, 1, meta)\n    meta = :lists.keystore(:if_undefined, 1, meta, {:if_undefined, :raise})\n\n    case Macro.expand(context, __CALLER__) do\n      context when is_atom(context) ->\n        {name, meta, context}\n\n      other ->\n        raise ArgumentError,\n              \"expected var! context to expand to an atom, got: #{Macro.to_string(other)}\"\n    end\n  end\n\n  defmacro var!(other, _context) do\n    raise ArgumentError, \"expected a variable to be given to var!, got: #{Macro.to_string(other)}\"\n  end\n\n  @doc \"\"\"\n  When used inside quoting, marks that the given alias should not\n  be hygienized. This means the alias will be expanded when\n  the macro is expanded.\n\n  Check `quote/2` for more information.\n  \"\"\"\n  defmacro alias!(alias) when is_atom(alias) do\n    alias\n  end\n\n  defmacro alias!({:__aliases__, meta, args}) do\n    # Simply remove the alias metadata from the node\n    # so it does not affect expansion.\n    {:__aliases__, :lists.keydelete(:alias, 1, meta), args}\n  end\n\n  @doc \"\"\"\n  Returns a binary starting at the offset `start` and of the given `size`.\n\n  This is similar to `binary_part/3` except that if `start + size`\n  is greater than the binary size, it automatically clips it to\n  the binary size instead of raising. Opposite to `binary_part/3`,\n  this function is not allowed in guards.\n\n  This function works with bytes. For a slicing operation that\n  considers characters, see `String.slice/3`.\n\n  ## Examples\n\n      iex> binary_slice(\"elixir\", 0, 6)\n      \"elixir\"\n      iex> binary_slice(\"elixir\", 0, 5)\n      \"elixi\"\n      iex> binary_slice(\"elixir\", 1, 4)\n      \"lixi\"\n      iex> binary_slice(\"elixir\", 0, 10)\n      \"elixir\"\n\n  If `start` is negative, it is normalized against the binary\n  size and clamped to 0:\n\n      iex> binary_slice(\"elixir\", -3, 10)\n      \"xir\"\n      iex> binary_slice(\"elixir\", -10, 10)\n      \"elixir\"\n\n  If the `size` is zero, an empty binary is returned:\n\n      iex> binary_slice(\"elixir\", 1, 0)\n      \"\"\n\n  If `start` is greater than or equal to the binary size,\n  an empty binary is returned:\n\n      iex> binary_slice(\"elixir\", 10, 10)\n      \"\"\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  def binary_slice(binary, start, size)\n      when is_binary(binary) and is_integer(start) and is_integer(size) and size >= 0 do\n    total = byte_size(binary)\n    start = if start < 0, do: max(total + start, 0), else: start\n\n    case start < total do\n      true -> :erlang.binary_part(binary, start, min(size, total - start))\n      false -> \"\"\n    end\n  end\n\n  @doc \"\"\"\n  Returns a binary from the offset given by the start of the\n  range to the offset given by the end of the range.\n\n  If the start or end of the range are negative, they are converted\n  into positive indices based on the binary size. For example,\n  `-1` means the last byte of the binary.\n\n  This is similar to `binary_part/3` except that it works with ranges\n  and it is not allowed in guards.\n\n  This function works with bytes. For a slicing operation that\n  considers characters, see `String.slice/2`.\n\n  ## Examples\n\n      iex> binary_slice(\"elixir\", 0..5)\n      \"elixir\"\n      iex> binary_slice(\"elixir\", 1..3)\n      \"lix\"\n      iex> binary_slice(\"elixir\", 1..10)\n      \"lixir\"\n\n      iex> binary_slice(\"elixir\", -4..-1)\n      \"ixir\"\n      iex> binary_slice(\"elixir\", -4..6)\n      \"ixir\"\n      iex> binary_slice(\"elixir\", -10..10)\n      \"elixir\"\n\n  For ranges where `start > stop`, you need to explicitly\n  mark them as increasing:\n\n      iex> binary_slice(\"elixir\", 2..-1//1)\n      \"ixir\"\n      iex> binary_slice(\"elixir\", 1..-2//1)\n      \"lixi\"\n\n  You can use `../0` as a shortcut for `0..-1//1`, which returns\n  the whole binary as is:\n\n      iex> binary_slice(\"elixir\", ..)\n      \"elixir\"\n\n  The step can be any positive number. For example, to\n  get every 2 characters of the binary:\n\n      iex> binary_slice(\"elixir\", 0..-1//2)\n      \"eii\"\n\n  If the first position is after the string ends or after\n  the last position of the range, it returns an empty string:\n\n      iex> binary_slice(\"elixir\", 10..3//1)\n      \"\"\n      iex> binary_slice(\"elixir\", -10..-7)\n      \"\"\n      iex> binary_slice(\"a\", 1..1500)\n      \"\"\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  def binary_slice(binary, first..last//step)\n      when is_binary(binary) and step > 0 do\n    total = byte_size(binary)\n\n    first = if first < 0, do: max(first + total, 0), else: first\n    last = if last < 0, do: last + total, else: last\n\n    amount = last - first + 1\n\n    if first < total and amount > 0 do\n      part = binary_part(binary, first, min(amount, total - first))\n\n      if step == 1 do\n        part\n      else\n        <<first_byte, rest::binary>> = part\n        for <<_::size(^step - 1)-bytes, byte <- rest>>, into: <<first_byte>>, do: <<byte>>\n      end\n    else\n      \"\"\n    end\n  end\n\n  def binary_slice(binary, _.._//_ = range) when is_binary(binary) do\n    raise ArgumentError,\n          \"binary_slice/2 does not accept ranges with negative steps, got: #{inspect(range)}\"\n  end\n\n  ## Definitions implemented in Elixir\n\n  @doc ~S\"\"\"\n  Defines a module given by name with the given contents.\n\n  This macro defines a module with the given `alias` as its name and with the\n  given contents. It returns a tuple with four elements:\n\n    * `:module`\n    * the module name\n    * the binary contents of the module\n    * the result of evaluating the contents block\n\n  ## Examples\n\n      defmodule Number do\n        def one, do: 1\n        def two, do: 2\n      end\n      #=> {:module, Number, <<70, 79, 82, ...>>, {:two, 0}}\n\n      Number.one()\n      #=> 1\n\n      Number.two()\n      #=> 2\n\n  ## Module names and aliases\n\n  Module names (and aliases) must start with an ASCII uppercase character which\n  may be followed by any ASCII letter, number, or underscore. Elixir's\n  [Naming Conventions](naming-conventions.md) suggest for module names and aliases\n  to be written in the `CamelCase` format.\n\n  You can also use atoms as the module name, although they must only contain ASCII\n  characters.\n\n  ## Nesting\n\n  Nesting a module inside another module affects the name of the nested module:\n\n      defmodule Foo do\n        defmodule Bar do\n        end\n      end\n\n  In the example above, two modules - `Foo` and `Foo.Bar` - are created.\n  When nesting, Elixir automatically creates an alias to the inner module,\n  allowing the second module `Foo.Bar` to be accessed as `Bar` in the same\n  lexical scope where it's defined (the `Foo` module). This only happens\n  if the nested module is defined via an alias.\n\n  If the `Foo.Bar` module is moved somewhere else, the references to `Bar` in\n  the `Foo` module need to be updated to the fully-qualified name (`Foo.Bar`) or\n  an alias has to be explicitly set in the `Foo` module with the help of\n  `alias/2`.\n\n      defmodule Foo.Bar do\n        # code\n      end\n\n      defmodule Foo do\n        alias Foo.Bar\n        # code here can refer to \"Foo.Bar\" as just \"Bar\"\n      end\n\n  ## Dynamic names\n\n  Elixir module names can be dynamically generated. This is very\n  useful when working with macros. For instance, one could write:\n\n      defmodule Module.concat([\"Foo\", \"Bar\"]) do\n        # contents ...\n      end\n\n  Elixir will accept any module name as long as the expression passed as the\n  first argument to `defmodule/2` evaluates to an atom.\n  Note that, when a dynamic name is used, Elixir won't nest the name under\n  the current module nor automatically set up an alias.\n\n  ## Reserved module names\n\n  If you attempt to define a module that already exists, you will get a\n  warning saying that a module has been redefined.\n\n  There are some modules that Elixir does not currently implement but it\n  may be implement in the future. Those modules are reserved and defining\n  them will result in a compilation error:\n\n      defmodule Any do\n        # code\n      end\n      ** (CompileError) iex:1: module Any is reserved and cannot be defined\n\n  Elixir reserves the following module names: `Elixir`, `Any`, `BitString`,\n  `PID`, and `Reference`.\n  \"\"\"\n  defmacro defmodule(alias, do_block)\n\n  defmacro defmodule(alias, do: block) do\n    env = __CALLER__\n    assert_no_match_or_guard_scope(env.context, \"defmodule/2\")\n    expanded = expand_module_alias(alias, env)\n\n    module_meta = module_meta(alias)\n\n    {expanded, with_alias} =\n      case is_atom(expanded) do\n        true ->\n          {full, old, opts} = alias_defmodule(alias, expanded, env)\n          # Expand the module considering the current environment/nesting\n          meta = [defined: full] ++ module_meta\n          {full, {:require, meta, [old, opts]}}\n\n        false ->\n          {expanded, nil}\n      end\n\n    escaped =\n      case env do\n        %{function: nil, lexical_tracker: pid} when is_pid(pid) ->\n          integer = Kernel.LexicalTracker.write_cache(pid, block)\n          quote(do: Kernel.LexicalTracker.read_cache(unquote(pid), unquote(integer)))\n\n        %{} ->\n          :elixir_quote.escape(block, :escape, false)\n      end\n\n    versioned_vars = env.versioned_vars\n    prune = :erlang.is_map_key({:elixir, :prune_binding}, versioned_vars)\n\n    var_meta =\n      case prune do\n        true -> [generated: true, keep_unused: true]\n        false -> [generated: true]\n      end\n\n    module_vars = :lists.map(&module_var(&1, var_meta), :maps.keys(versioned_vars))\n\n    quote do\n      unquote(with_alias)\n\n      :elixir_module.compile(\n        unquote(module_meta),\n        unquote(expanded),\n        unquote(escaped),\n        unquote(module_vars),\n        unquote(prune),\n        __ENV__\n      )\n    end\n  end\n\n  defmacro defmodule(alias, [{:do, _block}, {atom, _} | _]) when is_atom(atom) do\n    raise ArgumentError,\n          \"unexpected reserved word at the top-level of the \\\"defmodule #{Macro.to_string(alias)}\\\" do-block: #{atom}\"\n  end\n\n  defp module_meta({_, meta, _}), do: meta\n  defp module_meta(_), do: []\n\n  # We don't want to trace :alias_reference since we are defining the alias\n  defp expand_module_alias({:__aliases__, meta, list} = alias, env) do\n    case :elixir_aliases.expand_or_concat(meta, list, env, true) do\n      receiver when is_atom(receiver) ->\n        receiver\n\n      [head | tail] ->\n        case Macro.expand(head, env) do\n          head when is_atom(head) -> :elixir_aliases.concat([head | tail])\n          _ -> alias\n        end\n    end\n  end\n\n  defp expand_module_alias(other, env), do: Macro.expand(other, env)\n\n  # defmodule Elixir.Alias\n  defp alias_defmodule({:__aliases__, _, [:\"Elixir\", _ | _]}, module, _env),\n    do: {module, module, []}\n\n  # defmodule Alias in root\n  defp alias_defmodule({:__aliases__, _, _}, module, %{module: nil}), do: {module, module, []}\n\n  # defmodule Alias nested\n  defp alias_defmodule({:__aliases__, _, [h | t]}, _module, env) when is_atom(h) do\n    module = :elixir_aliases.concat([env.module, h])\n    alias = String.to_atom(\"Elixir.\" <> Atom.to_string(h))\n    opts = [as: alias, warn: false]\n\n    case t do\n      [] -> {module, module, opts}\n      _ -> {String.to_atom(Enum.join([module | t], \".\")), module, opts}\n    end\n  end\n\n  # defmodule _\n  defp alias_defmodule(_raw, module, _env) do\n    {module, module, []}\n  end\n\n  defp module_var({name, kind}, meta) when is_atom(kind), do: {name, meta, kind}\n  defp module_var({name, kind}, meta), do: {name, [counter: kind] ++ meta, nil}\n\n  @doc ~S\"\"\"\n  Defines a public function with the given name and body.\n\n  ## Examples\n\n      defmodule Foo do\n        def bar, do: :baz\n      end\n\n      Foo.bar()\n      #=> :baz\n\n  A function that expects arguments can be defined as follows:\n\n      defmodule Foo do\n        def sum(a, b) do\n          a + b\n        end\n      end\n\n  In the example above, a `sum/2` function is defined; this function receives\n  two arguments and returns their sum.\n\n  ## Default arguments\n\n  `\\\\` is used to specify a default value for a parameter of a function. For\n  example:\n\n      defmodule MyMath do\n        def multiply_by(number, factor \\\\ 2) do\n          number * factor\n        end\n      end\n\n      MyMath.multiply_by(4, 3)\n      #=> 12\n\n      MyMath.multiply_by(4)\n      #=> 8\n\n  The compiler translates this into multiple functions with different arities,\n  here `MyMath.multiply_by/1` and `MyMath.multiply_by/2`, that represent cases when\n  arguments for parameters with default values are passed or not passed.\n\n  When defining a function with default arguments as well as multiple\n  explicitly declared clauses, you must write a function head that declares the\n  defaults. For example:\n\n      defmodule MyString do\n        def join(string1, string2 \\\\ nil, separator \\\\ \" \")\n\n        def join(string1, nil, _separator) do\n          string1\n        end\n\n        def join(string1, string2, separator) do\n          string1 <> separator <> string2\n        end\n      end\n\n  Note that `\\\\` can't be used with anonymous functions because they\n  can only have a sole arity.\n\n  ### Keyword lists with default arguments\n\n  Functions containing many arguments can benefit from using `Keyword`\n  lists to group and pass attributes as a single value.\n\n      defmodule MyConfiguration do\n        @default_opts [storage: \"local\"]\n\n        def configure(resource, opts \\\\ []) do\n          opts = Keyword.merge(@default_opts, opts)\n          storage = opts[:storage]\n          # ...\n        end\n      end\n\n  The difference between using `Map` and `Keyword` to store many\n  arguments is `Keyword`'s keys:\n\n    * must be atoms\n    * can be given more than once\n    * ordered, as specified by the developer\n\n  ## Function names\n\n  Function and variable names in Elixir must start with an underscore or a\n  Unicode letter that is not in uppercase or titlecase. They may continue\n  using a sequence of Unicode letters, numbers, and underscores. They may\n  end in `?` or `!`. Elixir's [Naming Conventions](naming-conventions.md)\n  suggest for function and variable names to be written in the `snake_case`\n  format.\n\n  ## `rescue`/`catch`/`after`/`else`\n\n  Function bodies support `rescue`, `catch`, `after`, and `else` as `try/1`\n  does (known as \"implicit try\"). For example, the following two functions are equivalent:\n\n      def convert(number) do\n        try do\n          String.to_integer(number)\n        rescue\n          e in ArgumentError -> {:error, e.message}\n        end\n      end\n\n      def convert(number) do\n        String.to_integer(number)\n      rescue\n        e in ArgumentError -> {:error, e.message}\n      end\n\n  \"\"\"\n  defmacro def(call, expr \\\\ nil) do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"def/2\")\n    define(:def, call, expr, __CALLER__)\n  end\n\n  @doc \"\"\"\n  Defines a private function with the given name and body.\n\n  Private functions are only accessible from within the module in which they are\n  defined. Trying to access a private function from outside the module it's\n  defined in results in an `UndefinedFunctionError` exception.\n\n  Check `def/2` for more information.\n\n  ## Examples\n\n      defmodule Foo do\n        def bar do\n          sum(1, 2)\n        end\n\n        defp sum(a, b), do: a + b\n      end\n\n      Foo.bar()\n      #=> 3\n\n      Foo.sum(1, 2)\n      ** (UndefinedFunctionError) undefined function Foo.sum/2\n\n  \"\"\"\n  defmacro defp(call, expr \\\\ nil) do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"defp/2\")\n    define(:defp, call, expr, __CALLER__)\n  end\n\n  @doc \"\"\"\n  Defines a public macro with the given name and body.\n\n  Macros must be defined before its usage.\n\n  Check `def/2` for rules on naming and default arguments.\n\n  ## Examples\n\n      defmodule MyLogic do\n        defmacro unless(expr, opts) do\n          quote do\n            if !unquote(expr), unquote(opts)\n          end\n        end\n      end\n\n      require MyLogic\n\n      MyLogic.unless false do\n        IO.puts(\"It works\")\n      end\n\n  \"\"\"\n  defmacro defmacro(call, expr \\\\ nil) do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"defmacro/2\")\n    define(:defmacro, call, expr, __CALLER__)\n  end\n\n  @doc \"\"\"\n  Defines a private macro with the given name and body.\n\n  Private macros are only accessible from the same module in which they are\n  defined.\n\n  Private macros must be defined before its usage.\n\n  Check `defmacro/2` for more information, and check `def/2` for rules on\n  naming and default arguments.\n\n  \"\"\"\n  defmacro defmacrop(call, expr \\\\ nil) do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"defmacrop/2\")\n    define(:defmacrop, call, expr, __CALLER__)\n  end\n\n  defp define(kind, call, expr, env) do\n    module = assert_module_scope(env, kind, 2)\n    assert_no_function_scope(env, kind, 2)\n\n    unquoted_call = :elixir_quote.has_unquotes(call)\n    unquoted_expr = :elixir_quote.has_unquotes(expr)\n\n    store =\n      case unquoted_expr or unquoted_call do\n        true ->\n          :elixir_quote.escape({call, expr}, :escape, true)\n\n        false ->\n          key = :erlang.unique_integer()\n          :elixir_module.write_cache(module, key, {call, expr})\n          key\n      end\n\n    pos = :elixir_module.cache_env(env)\n\n    quote do\n      :elixir_def.store_definition(unquote(kind), unquote(store), unquote(pos))\n    end\n  end\n\n  @doc \"\"\"\n  Defines a struct.\n\n  A struct is a tagged map that allows developers to provide\n  default values for keys, tags to be used in polymorphic\n  dispatches and compile time assertions.\n\n  It is only possible to define a struct per module, as the\n  struct is tied to the module itself.\n\n  ## Examples\n\n      defmodule User do\n        defstruct name: nil, age: nil\n      end\n\n  Struct fields are evaluated at compile-time, which allows\n  them to be dynamic. In the example below, `10 + 11` is\n  evaluated at compile-time and the age field is stored\n  with value `21`:\n\n      defmodule User do\n        defstruct name: nil, age: 10 + 11\n      end\n\n  The `fields` argument is usually a keyword list with field names\n  as atom keys and default values as corresponding values. `defstruct/1`\n  also supports a list of atoms as its argument: in that case, the atoms\n  in the list will be used as the struct's field names and they will all\n  default to `nil`.\n\n      defmodule Post do\n        defstruct [:title, :content, :author]\n      end\n\n  Add documentation to a struct with the `@doc` attribute, like a function.\n\n      defmodule Post do\n        @doc \"A post. The content should be valid Markdown.\"\n        defstruct [:title, :content, :author]\n      end\n\n  Once a struct is defined, it is possible to create them as follows:\n\n      %Post{title: \"Hello world!\"}\n\n  For more information on creating, updating, and pattern matching on\n  structs, please check `%/2`.\n\n  ## Deriving\n\n  Although structs are maps, by default structs do not implement\n  any of the protocols implemented for maps. For example, attempting\n  to use a protocol with the `User` struct leads to an error:\n\n      john = %User{name: \"John\"}\n      MyProtocol.call(john)\n      ** (Protocol.UndefinedError) protocol MyProtocol not implemented for User (a struct)\n\n  `defstruct/1`, however, allows protocol implementations to be\n  *derived*. This can be done by defining a `@derive` attribute as a\n  list before invoking `defstruct/1`:\n\n      defmodule User do\n        @derive MyProtocol\n        defstruct name: nil, age: nil\n      end\n\n      MyProtocol.call(john) # it works!\n\n  A common example is to `@derive` the `Inspect` protocol to hide certain fields\n  when the struct is printed:\n\n      defmodule User do\n        @derive {Inspect, only: :name}\n        defstruct name: nil, age: nil\n      end\n\n  For each protocol in `@derive`, Elixir will verify if the protocol\n  has implemented the `c:Protocol.__deriving__/2` callback. If so,\n  the callback will be invoked and it should define the implementation\n  module. Otherwise an implementation that simply points to the `Any`\n  implementation is automatically derived. For more information, see\n  `Protocol.derive/3`.\n\n  ## Enforcing keys\n\n  When building a struct, Elixir will automatically guarantee all keys\n  belong to the struct:\n\n      %User{name: \"john\", unknown: :key}\n      ** (KeyError) key :unknown not found in: %User{age: 21, name: nil}\n\n  Elixir also allows developers to enforce that certain keys must always be\n  given when building the struct:\n\n      defmodule User do\n        @enforce_keys [:name]\n        defstruct name: nil, age: 10 + 11\n      end\n\n  Now trying to build a struct without the name key will fail:\n\n      %User{age: 21}\n      ** (ArgumentError) the following keys must also be given when building struct User: [:name]\n\n  Keep in mind `@enforce_keys` is a simple compile-time guarantee\n  to aid developers when building structs. It is not enforced on\n  updates and it does not provide any sort of value-validation.\n\n  ## Types\n\n  It is recommended to define types for structs. By convention, such a type\n  is called `t`. To define a type for a struct, the struct literal syntax is\n  used:\n\n      defmodule User do\n        defstruct name: \"John\", age: 25\n        @type t :: %__MODULE__{name: String.t(), age: non_neg_integer}\n      end\n\n  It is recommended to only use the struct syntax when defining the struct's\n  type. When referring to another struct, it's better to use `User.t()` instead of\n  `%User{}`.\n\n  The types of the struct fields that are not included in `%User{}` default to\n  `term()` (see `t:term/0`).\n\n  Structs whose internal structure is private to the local module (pattern\n  matching them or directly accessing their fields should not be allowed) should\n  use the `@opaque` attribute. Structs whose internal structure is public should\n  use `@type`.\n  \"\"\"\n  defmacro defstruct(fields) do\n    quote bind_quoted: [fields: fields, bootstrapped?: bootstrapped?(Enum)] do\n      {struct, derive, escaped_struct, kv, body} =\n        Kernel.Utils.defstruct(__MODULE__, fields, bootstrapped?, __ENV__)\n\n      case derive do\n        [] -> :ok\n        _ -> Protocol.__derive__(derive, __MODULE__, __ENV__)\n      end\n\n      def __struct__(), do: unquote(escaped_struct)\n      def __struct__(unquote(kv)), do: unquote(body)\n\n      Kernel.Utils.announce_struct(__MODULE__)\n      struct\n    end\n  end\n\n  @doc ~S\"\"\"\n  Defines an exception.\n\n  Exceptions are structs backed by a module that implements\n  the `Exception` behaviour. The `Exception` behaviour requires\n  two functions to be implemented:\n\n    * [`exception/1`](`c:Exception.exception/1`) - receives the arguments given to `raise/2`\n      and returns the exception struct. The default implementation\n      accepts either a set of keyword arguments that is merged into\n      the struct or a string to be used as the exception's message.\n\n    * [`message/1`](`c:Exception.message/1`) - receives the exception struct and must return its\n      message. Most commonly exceptions have a message field which\n      by default is accessed by this function. However, if an exception\n      does not have a message field, this function must be explicitly\n      implemented.\n\n  Since exceptions are structs, the API supported by `defstruct/1`\n  is also available in `defexception/1`.\n\n  ## Raising exceptions\n\n  The most common way to raise an exception is via `raise/2`:\n\n      defmodule MyAppError do\n        defexception [:message]\n      end\n\n      value = [:hello]\n\n      raise MyAppError,\n        message: \"did not get what was expected, got: #{inspect(value)}\"\n\n  In many cases it is more convenient to pass the expected value to\n  `raise/2` and generate the message in the `c:Exception.exception/1` callback:\n\n      defmodule MyAppError do\n        defexception [:message]\n\n        @impl true\n        def exception(value) do\n          msg = \"did not get what was expected, got: #{inspect(value)}\"\n          %MyAppError{message: msg}\n        end\n      end\n\n      raise MyAppError, value\n\n  The example above shows the preferred strategy for customizing\n  exception messages.\n  \"\"\"\n  defmacro defexception(fields) do\n    quote bind_quoted: [fields: fields] do\n      Elixir.Kernel.@(behaviour(Exception))\n      struct = defstruct([__exception__: true] ++ fields)\n\n      if Map.has_key?(struct, :message) do\n        Elixir.Kernel.@(impl(true))\n\n        def message(exception) do\n          exception.message\n        end\n\n        defoverridable message: 1\n\n        Elixir.Kernel.@(impl(true))\n\n        def exception(msg) when Kernel.is_binary(msg) do\n          exception(message: msg)\n        end\n      end\n\n      # Calls to Kernel functions must be fully-qualified to ensure\n      # reproducible builds, otherwise, this macro will generate ASTs\n      # with different metadata (:imports, :context) depending on if\n      # it is the bootstrapped version or not.\n      Elixir.Kernel.@(impl(true))\n\n      def exception(args) when Kernel.is_list(args) do\n        struct!(__MODULE__, args)\n      end\n\n      defoverridable exception: 1\n    end\n  end\n\n  @doc \"\"\"\n  Defines a protocol.\n\n  See the `Protocol` module for more information.\n  \"\"\"\n  defmacro defprotocol(name, do_block)\n\n  defmacro defprotocol(name, do: block) do\n    Protocol.__protocol__(name, do: block)\n  end\n\n  @doc \"\"\"\n  Defines an implementation for the given protocol.\n\n  See the `Protocol` module for more information.\n  \"\"\"\n  defmacro defimpl(name, opts, do_block \\\\ []) do\n    Protocol.__impl__(name, opts, do_block, __CALLER__)\n  end\n\n  @doc \"\"\"\n  Makes the given definitions in the current module overridable.\n\n  If the user defines a new function or macro with the same name\n  and arity, then the overridable ones are discarded. Otherwise, the\n  original definitions are used.\n\n  It is possible for the overridden definition to have a different\n  visibility than the original: a public function can be overridden\n  by a private function and vice-versa. Macros cannot be overridden\n  as functions and vice-versa.\n\n  ## Example\n\n      defmodule DefaultMod do\n        defmacro __using__(_opts) do\n          quote do\n            def test(x, y) do\n              x + y\n            end\n\n            defoverridable test: 2\n          end\n        end\n      end\n\n      defmodule ChildMod do\n        use DefaultMod\n\n        def test(x, y) do\n          x * y + super(x, y)\n        end\n      end\n\n  As seen as in the example above, `super` can be used to call the default\n  implementation.\n\n  ## Example with behaviour\n\n  `defoverridable` is commonly used with behaviours. The behaviours use\n  `@callback` definitions to define the general module API and the\n  `__using__` callback is used to define default implementations of\n  functions, which can then be overridable.\n\n  For convenience, you can pass a behaviour to `defoverridable` and it\n  will mark all of the callbacks in the behaviour as overridable:\n\n      defmodule Behaviour do\n        @callback test(number(), number()) :: number()\n      end\n\n      defmodule DefaultMod do\n        defmacro __using__(_opts) do\n          quote do\n            @behaviour Behaviour\n\n            def test(x, y) do\n              x + y\n            end\n\n            defoverridable Behaviour\n          end\n        end\n      end\n\n      defmodule ChildMod do\n        use DefaultMod\n\n        def test(x, y) do\n          x * y + super(x, y)\n        end\n      end\n\n  > #### Narrow behaviours and entry points {: .tip}\n  >\n  > When defining behaviours, a general rule of thumb is to define narrow\n  > behaviours, with the minimum amount of callbacks, to facilitate maintenance\n  > over time. Fewer callbacks minimize the points of contact between different\n  > parts of the system and reduces the risk of breaking changes and of different\n  > implementations having inconsistent behaviour. However, when using `defoverridable`\n  > with behaviours, you may accidentally define broad interfaces as all default\n  > behaviour is provided via `defoverridable`. Furthermore, `defoverridable`\n  > necessarily relies on meta-programming, which complicates debugging. `super` is\n  > also hard to troubleshoot, as it by definition relies on calling an implicitly\n  > defined function.\n  >\n  > A possible alternative to `defoverridable` is to use optional callbacks and\n  > move the default implementation to the caller. Then you can check if a callback\n  > exists via `Code.ensure_loaded?/1` and `function_exported?/3`. For instance,\n  > in the example above, imagine there is a module that calls the `test/2` function.\n  > This module could be defined as such:\n  >\n  >     defmodule CallsTest do\n  >       def receives_module_and_calls_test(module, x, y) do\n  >         if Code.ensure_loaded?(module) and function_exported?(module, :test, 2) do\n  >           module.test(x, y)\n  >         else\n  >           x + y\n  >         end\n  >       end\n  >     end\n  >\n  > The downside of the above code is that it must call `Code.ensure_loaded?/1` and\n  > `function_exported?/3` on every invocation of the behaviour, which may impact\n  > runtime performance. For this reason, this approach works best when the behaviour\n  > has an entry point, such as a `init` callback (as seen in `GenServer`), which you\n  > invoke once to guarantee the module is loaded, and from that moment, you only need\n  > to perform `function_exported?/3` checks.\n  >\n  > To recap:\n  >\n  >   * Prefer narrow behaviours\n  >\n  >   * If your behaviour has an entry point, consider using optional callbacks\n  >     followed by `Code.ensure_loaded?/1` and `function_exported?/3` checks\n  >\n  >   * If using `defoverridable`, avoid relying on `super` to trigger the default\n  >     behaviour, suggesting users to invoke well-defined APIs instead.\n  >\n  \"\"\"\n  defmacro defoverridable(keywords_or_behaviour) do\n    quote do\n      Module.make_overridable(__MODULE__, unquote(keywords_or_behaviour))\n    end\n  end\n\n  @doc \"\"\"\n  Defines a macro suitable for use in guard expressions.\n\n  It raises at compile time if the `guard` uses expressions that aren't\n  allowed in [guard clauses](patterns-and-guards.html#guards),\n  and otherwise creates a macro that can be used both inside or outside guards.\n\n  When defining your own guards, consider the\n  [naming conventions](naming-conventions.html#is_-prefix-is_foo)\n  around boolean-returning guards.\n\n  ## Example\n\n      defmodule Integer.Guards do\n        defguard is_even(value) when is_integer(value) and rem(value, 2) == 0\n      end\n\n      defmodule Collatz do\n        @moduledoc \"Tools for working with the Collatz sequence.\"\n        import Integer.Guards\n\n        @doc \"Determines the number of steps `n` takes to reach `1`.\"\n        # If this function never converges, please let me know what `n` you used.\n        def converge(n) when n > 0, do: step(n, 0)\n\n        defp step(1, step_count) do\n          step_count\n        end\n\n        defp step(n, step_count) when is_even(n) do\n          step(div(n, 2), step_count + 1)\n        end\n\n        defp step(n, step_count) do\n          step(3 * n + 1, step_count + 1)\n        end\n      end\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec defguard(Macro.t()) :: Macro.t()\n  defmacro defguard(guard) do\n    define_guard(:defmacro, guard, __CALLER__)\n  end\n\n  @doc \"\"\"\n  Defines a private macro suitable for use in guard expressions.\n\n  It raises at compile time if the `guard` uses expressions that aren't\n  allowed in [guard clauses](patterns-and-guards.html#guards),\n  and otherwise creates a private macro that can be used\n  both inside or outside guards in the current module.\n\n  When defining your own guards, consider the\n  [naming conventions](naming-conventions.html#is_-prefix-is_foo)\n  around boolean-returning guards.\n\n  Similar to `defmacrop/2`, `defguardp/1` must be defined before its use\n  in the current module.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec defguardp(Macro.t()) :: Macro.t()\n  defmacro defguardp(guard) do\n    define_guard(:defmacrop, guard, __CALLER__)\n  end\n\n  defp define_guard(kind, guard, env) do\n    case :elixir_utils.extract_guards(guard) do\n      {call, [_, _ | _]} ->\n        raise ArgumentError,\n              \"invalid syntax in defguard #{Macro.to_string(call)}, \" <>\n                \"only a single when clause is allowed\"\n\n      {call, impls} ->\n        case decompose_args(call) do\n          :error ->\n            raise ArgumentError, \"invalid syntax in defguard #{Macro.to_string(call)}\"\n\n          args ->\n            validate_variable_only_args!(call, args)\n\n            macro_definition =\n              case impls do\n                [] ->\n                  define(kind, call, nil, env)\n\n                [guard] ->\n                  quoted =\n                    quote do\n                      require Kernel.Utils\n                      Kernel.Utils.defguard(unquote(args), unquote(guard))\n                    end\n\n                  define(kind, call, [do: quoted], env)\n              end\n\n            quote do\n              Elixir.Kernel.@(doc(guard: true))\n              unquote(macro_definition)\n            end\n        end\n    end\n  end\n\n  defp decompose_args({name, _, args}) when is_atom(name) and is_atom(args), do: []\n\n  defp decompose_args({name, _, args}) when is_atom(name) and is_list(args), do: args\n\n  defp decompose_args({{:unquote, _, _}, _, args}) when is_atom(args), do: []\n\n  defp decompose_args({{:unquote, _, _}, _, args}) when is_list(args), do: args\n\n  defp decompose_args(_), do: :error\n\n  defp validate_variable_only_args!(call, args) do\n    Enum.each(args, fn\n      {ref, _meta, context} when is_atom(ref) and is_atom(context) ->\n        :ok\n\n      {:\\\\, _m1, [{ref, _m2, context}, _default]} when is_atom(ref) and is_atom(context) ->\n        :ok\n\n      _match ->\n        raise ArgumentError, \"invalid syntax in defguard #{Macro.to_string(call)}\"\n    end)\n  end\n\n  @doc \"\"\"\n  Uses the given module in the current context.\n\n  When calling:\n\n      use MyModule, some: :options\n\n  Elixir will invoke `MyModule.__using__/1` passing the second argument of\n  `use` as its argument. Since `__using__/1` is typically a macro, all\n  the usual macro rules apply, and its return value should be quoted code\n  that is then inserted where `use/2` is called.\n\n  > #### Code injection {: .warning}\n  >\n  > `use MyModule` works as a **code-injection point** in the caller.\n  > Given the caller of `use MyModule` has little control over how the\n  > code is injected, `use/2` should be used with care. If you can,\n  > avoid use in favor of `import/2` or `alias/2` whenever possible.\n\n  ## Examples\n\n  For example, to write test cases using the `ExUnit` framework provided\n  with Elixir, a developer should `use` the `ExUnit.Case` module:\n\n      defmodule AssertionTest do\n        use ExUnit.Case, async: true\n\n        test \"always pass\" do\n          assert true\n        end\n      end\n\n  In this example, Elixir will call the `__using__/1` macro in the\n  `ExUnit.Case` module with the keyword list `[async: true]` as its\n  argument.\n\n  In other words, `use/2` translates to:\n\n      defmodule AssertionTest do\n        require ExUnit.Case\n        ExUnit.Case.__using__(async: true)\n\n        test \"always pass\" do\n          assert true\n        end\n      end\n\n  where `ExUnit.Case` defines the `__using__/1` macro:\n\n      defmodule ExUnit.Case do\n        defmacro __using__(opts) do\n          # do something with opts\n          quote do\n            # return some code to inject in the caller\n          end\n        end\n      end\n\n  ## Best practices\n\n  `__using__/1` is typically used when there is a need to set some state\n  (via module attributes) or callbacks (like `@before_compile`, see the\n  documentation for `Module` for more information) into the caller.\n\n  `__using__/1` may also be used to alias, require, or import functionality\n  from different modules:\n\n      defmodule MyModule do\n        defmacro __using__(_opts) do\n          quote do\n            import MyModule.Foo\n            import MyModule.Bar\n            import MyModule.Baz\n\n            alias MyModule.Repo\n          end\n        end\n      end\n\n  However, do not provide `__using__/1` if all it does is to import,\n  alias or require the module itself. For example, avoid this:\n\n      defmodule MyModule do\n        defmacro __using__(_opts) do\n          quote do\n            import MyModule\n          end\n        end\n      end\n\n  In such cases, developers should instead import or alias the module\n  directly, so that they can customize those as they wish,\n  without the indirection behind `use/2`. Developers must also avoid\n  defining functions inside `__using__/1`.\n\n  Given `use MyModule` can generate any code, it may not be easy for\n  developers to understand the impact of `use MyModule`.\n\n  For this reason, to provide guidance and clarity, we recommend developers\n  to include an admonition block in their `@moduledoc` that explains how\n  `use MyModule` impacts their code. As an example, the `GenServer` documentation\n  outlines:\n\n  > #### `use GenServer` {: .info}\n  >\n  > When you `use GenServer`, the `GenServer` module will\n  > set `@behaviour GenServer` and define a `child_spec/1`\n  > function, so your module can be used as a child\n  > in a supervision tree.\n\n  This provides a quick summary of how using a module impacts the user code.\n  Keep in mind to only list changes made to the public API of the module.\n  For example, if `use MyModule` sets an internal attribute called\n  `@_my_module_info` and this attribute is never meant to be public,\n  it must not be listed.\n\n  For convenience, the markup notation to generate the admonition block\n  above is:\n\n  ```\n  > #### `use GenServer` {: .info}\n  >\n  > When you `use GenServer`, the GenServer module will\n  > set `@behaviour GenServer` and define a `child_spec/1`\n  > function, so your module can be used as a child\n  > in a supervision tree.\n  ```\n  \"\"\"\n  defmacro use(module, opts \\\\ []) do\n    calls =\n      Enum.map(expand_aliases(module, __CALLER__), fn\n        expanded when is_atom(expanded) ->\n          quote do\n            require unquote(expanded)\n            unquote(expanded).__using__(unquote(opts))\n          end\n\n        _otherwise ->\n          raise ArgumentError,\n                \"invalid arguments for use, \" <>\n                  \"expected a compile time atom or alias, got: #{Macro.to_string(module)}\"\n      end)\n\n    quote(do: (unquote_splicing(calls)))\n  end\n\n  defp expand_aliases({{:., _, [base, :{}]}, _, refs}, env) do\n    base = Macro.expand(base, env)\n\n    Enum.map(refs, fn\n      {:__aliases__, _, ref} ->\n        Module.concat([base | ref])\n\n      ref when is_atom(ref) ->\n        Module.concat(base, ref)\n\n      other ->\n        other\n    end)\n  end\n\n  defp expand_aliases(module, env) do\n    [Macro.expand(module, env)]\n  end\n\n  @doc \"\"\"\n  Defines a function that delegates to another module.\n\n  Functions defined with `defdelegate/2` are public and can be invoked from\n  outside the module they're defined in, as if they were defined using `def/2`.\n  Therefore, `defdelegate/2` is about extending the current module's public API.\n  If what you want is to invoke a function defined in another module without\n  using its full module name, then use `alias/2` to shorten the module name or use\n  `import/2` to be able to invoke the function without the module name altogether.\n\n  Delegation only works with functions; delegating macros is not supported.\n\n  Check `def/2` for rules on naming and default arguments.\n\n  ## Options\n\n    * `:to` - the module to dispatch to.\n\n    * `:as` - the function to call on the target given in `:to`.\n      This parameter is optional and defaults to the name being\n      delegated (`funs`).\n\n  ## Examples\n\n      defmodule MyList do\n        defdelegate reverse(list), to: Enum\n        defdelegate other_reverse(list), to: Enum, as: :reverse\n      end\n\n      MyList.reverse([1, 2, 3])\n      #=> [3, 2, 1]\n\n      MyList.other_reverse([1, 2, 3])\n      #=> [3, 2, 1]\n\n  \"\"\"\n  defmacro defdelegate(funs, opts) do\n    funs = Macro.escape(funs, unquote: true)\n    opts = Macro.expand_literals(opts, %{__CALLER__ | function: {:__info__, 1}})\n\n    quote bind_quoted: [funs: funs, opts: opts] do\n      target = Kernel.Utils.defdelegate_all(funs, opts, __ENV__)\n\n      # TODO: Remove List.wrap when multiple funs are no longer supported\n      for fun <- List.wrap(funs) do\n        {name, args, as, as_args} = Kernel.Utils.defdelegate_each(fun, opts)\n        Elixir.Kernel.@(doc(delegate_to: {target, as, :erlang.length(as_args)}))\n\n        # Build the call AST by hand so it doesn't get a\n        # context and it warns on things like missing @impl\n        def unquote({name, [line: __ENV__.line], args}) do\n          unquote(target).unquote(as)(unquote_splicing(as_args))\n        end\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Debugs the given `code`.\n\n  `dbg/2` can be used to debug the given `code` through a configurable debug function.\n  It returns the result of the given code.\n\n  ## Examples\n\n  Let's take this call to `dbg/2`:\n\n      dbg(Atom.to_string(:debugging))\n      #=> \"debugging\"\n\n  It returns the string `\"debugging\"`, which is the result of the `Atom.to_string/1` call.\n  Additionally, the call above prints:\n\n      [my_file.ex:10: MyMod.my_fun/0]\n      Atom.to_string(:debugging) #=> \"debugging\"\n\n  The default debugging function prints additional debugging info when dealing with\n  pipelines. It prints the values at every \"step\" of the pipeline.\n\n      \"Elixir is cool!\"\n      |> String.trim_trailing(\"!\")\n      |> String.split()\n      |> List.first()\n      |> dbg()\n      #=> \"Elixir\"\n\n  The code above prints:\n\n      [my_file.ex:10: MyMod.my_fun/0]\n      \"Elixir is cool!\" #=> \"Elixir is cool!\"\n      |> String.trim_trailing(\"!\") #=> \"Elixir is cool\"\n      |> String.split() #=> [\"Elixir\", \"is\", \"cool\"]\n      |> List.first() #=> \"Elixir\"\n\n  With no arguments, `dbg()` debugs information about the current binding. See `binding/1`.\n\n  ## `dbg` inside IEx\n\n  You can enable IEx to replace `dbg` with its `IEx.pry/0` backend by calling:\n\n      $ iex --dbg pry\n\n  In such cases, `dbg` will start a `pry` session where you can interact with\n  the imports, aliases, and variables of the current environment at the location\n  of the `dbg` call.\n\n  If you call `dbg` at the end of a pipeline (using `|>`) within IEx, you are able\n  to go through each step of the pipeline one by one by entering \"next\" (or \"n\").\n\n  Note `dbg` only supports stepping for pipelines (in other words, it can only\n  step through the code it sees). For general stepping, you can set breakpoints\n  using `IEx.break!/4`.\n\n  For more information, [see IEx documentation](https://hexdocs.pm/iex/IEx.html#module-dbg-and-breakpoints).\n\n  ## Configuring the debug function\n\n  One of the benefits of `dbg/2` is that its debugging logic is configurable,\n  allowing tools to extend `dbg` with enhanced behaviour. This is done, for\n  example, by `IEx` which extends `dbg` with an interactive shell where you\n  can directly inspect and access values.\n\n  The debug function can be configured at compile time through the `:dbg_callback`\n  key of the `:elixir` application. The debug function must be a\n  `{module, function, args}` tuple. The `function` function in `module` will be\n  invoked with three arguments *prepended* to `args`:\n\n    1. The AST of `code`\n    2. The AST of `options`\n    3. The `Macro.Env` environment of where `dbg/2` is invoked\n\n  The debug function is invoked at compile time and it must also return an AST.\n  The AST is expected to ultimately return the result of evaluating the debugged\n  expression.\n\n  Here's a simple example:\n\n      defmodule MyMod do\n        def debug_fun(code, options, caller, device) do\n          quote do\n            result = unquote(code)\n            IO.inspect(unquote(device), result, label: unquote(Macro.to_string(code)))\n          end\n        end\n      end\n\n  To configure the debug function:\n\n      # In config/config.exs\n      config :elixir, :dbg_callback, {MyMod, :debug_fun, [:stdio]}\n\n  ### Default debug function\n\n  By default, the debug function we use is `Macro.dbg/3`. It just prints\n  information about the code to standard output and returns the value\n  returned by evaluating `code`. `options` are used to control how terms\n  are inspected. They are the same options accepted by `inspect/2`.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  defmacro dbg(code \\\\ quote(do: binding()), options \\\\ []) do\n    # The compiling process may override the callback by putting it in\n    # the process dictionary.\n    dbg_callback =\n      case :erlang.get({:elixir, :dbg_callback}) do\n        :undefined -> Application.compile_env!(__CALLER__, :elixir, :dbg_callback)\n        value -> value\n      end\n\n    {mod, fun, args} = dbg_callback\n    Macro.compile_apply(mod, fun, [code, options, __CALLER__ | args], __CALLER__)\n  end\n\n  hour_in_ms = 1000 * 60 * 60\n  day_in_ms = 24 * hour_in_ms\n  week_in_ms = 7 * day_in_ms\n\n  @doc \"\"\"\n  Constructs a millisecond timeout from the given components, duration, or timeout.\n\n  This function is useful for constructing timeouts to use in functions that\n  expect `t:timeout/0` values (such as `Process.send_after/4` and many others).\n\n  ## Argument\n\n  The `duration` argument can be one of a `Duration`, a `t:timeout/0`, or a list\n  of components. Each of these is described below.\n\n  ### Passing `Duration`s\n\n  `t:Duration.t/0` structs can be converted to timeouts. The given duration must have\n  `year` and `month` fields set to `0`, since those cannot be reliably converted to\n  milliseconds (due to the varying number of days in a month and year).\n\n  Microseconds in durations are converted to milliseconds (through `System.convert_time_unit/3`).\n\n  ### Passing components\n\n  The `duration` argument can also be keyword list which can contain the following\n  keys, each appearing at most once with a non-negative integer value:\n\n    * `:week` - the number of weeks (a week is always 7 days)\n    * `:day` - the number of days (a day is always 24 hours)\n    * `:hour` - the number of hours\n    * `:minute` - the number of minutes\n    * `:second` - the number of seconds\n    * `:millisecond` - the number of milliseconds\n\n  The timeout is calculated as the sum of the components, each multiplied by\n  the corresponding factor.\n\n  ### Passing timeouts\n\n  You can also pass timeouts directly to this functions, that is, milliseconds or\n  the atom `:infinity`. In this case, this function just returns the given argument.\n\n  ## Examples\n\n  With a keyword list:\n\n      iex> to_timeout(hour: 1, minute: 30)\n      5400000\n\n  With a duration:\n\n      iex> to_timeout(%Duration{hour: 1, minute: 30})\n      5400000\n\n  With a timeout:\n\n      iex> to_timeout(5_400_000)\n      5400000\n      iex> to_timeout(:infinity)\n      :infinity\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec to_timeout([{unit, non_neg_integer()}] | timeout() | Duration.t()) :: timeout()\n        when unit: :week | :day | :hour | :minute | :second | :millisecond\n  def to_timeout(duration)\n\n  def to_timeout(:infinity), do: :infinity\n  def to_timeout(timeout) when is_integer(timeout) and timeout >= 0, do: timeout\n\n  def to_timeout(%{__struct__: Duration} = duration) do\n    case duration do\n      %{year: year} when year != 0 ->\n        raise ArgumentError,\n              \"duration with a non-zero year cannot be reliably converted to timeouts\"\n\n      %{month: month} when month != 0 ->\n        raise ArgumentError,\n              \"duration with a non-zero month cannot be reliably converted to timeouts\"\n\n      _other ->\n        {microsecond, _precision} = duration.microsecond\n        millisecond = :erlang.convert_time_unit(microsecond, :microsecond, :millisecond)\n\n        duration.week * unquote(week_in_ms) +\n          duration.day * unquote(day_in_ms) +\n          duration.hour * unquote(hour_in_ms) +\n          duration.minute * 60_000 +\n          duration.second * 1000 +\n          millisecond\n    end\n  end\n\n  def to_timeout(components) when is_list(components) do\n    reducer = fn\n      {key, value}, {acc, seen_keys} when is_integer(value) and value >= 0 ->\n        case :lists.member(key, seen_keys) do\n          true ->\n            raise ArgumentError, \"timeout component #{inspect(key)} is duplicated\"\n\n          false ->\n            :ok\n        end\n\n        factor =\n          case key do\n            :week ->\n              unquote(week_in_ms)\n\n            :day ->\n              unquote(day_in_ms)\n\n            :hour ->\n              unquote(hour_in_ms)\n\n            :minute ->\n              60_000\n\n            :second ->\n              1000\n\n            :millisecond ->\n              1\n\n            other ->\n              raise ArgumentError, \"\"\"\n              timeout component #{inspect(other)} is not a valid timeout component, valid \\\n              values are: :week, :day, :hour, :minute, :second, :millisecond\\\n              \"\"\"\n          end\n\n        {acc + value * factor, [key | seen_keys]}\n\n      {key, value}, {_acc, _seen_keys} ->\n        raise ArgumentError,\n              \"timeout component #{inspect(key)} must be a non-negative \" <>\n                \"integer, got: #{inspect(value)}\"\n    end\n\n    elem(:lists.foldl(reducer, {0, _seen_keys = []}, components), 0)\n  end\n\n  ## Sigils\n\n  @doc ~S\"\"\"\n  Handles the sigil `~S` for strings.\n\n  It returns a string without interpolations and without escape\n  characters.\n\n  ## Examples\n\n      iex> ~S(foo)\n      \"foo\"\n      iex> ~S(f#{o}o)\n      \"f\\#{o}o\"\n      iex> ~S(\\o/)\n      \"\\\\o/\"\n\n  \"\"\"\n  defmacro sigil_S(term, modifiers)\n  defmacro sigil_S({:<<>>, _, [binary]}, []) when is_binary(binary), do: binary\n\n  @doc ~S\"\"\"\n  Handles the sigil `~s` for strings.\n\n  It returns a string as if it was a double quoted string, unescaping characters\n  and replacing interpolations.\n\n  ## Examples\n\n      iex> ~s(foo)\n      \"foo\"\n\n      iex> ~s(f#{:o}o)\n      \"foo\"\n\n      iex> ~s(f\\#{:o}o)\n      \"f\\#{:o}o\"\n\n  \"\"\"\n  defmacro sigil_s(term, modifiers)\n\n  defmacro sigil_s({:<<>>, _, [piece]}, []) when is_binary(piece) do\n    :elixir_interpolation.unescape_string(piece)\n  end\n\n  defmacro sigil_s({:<<>>, line, pieces}, []) do\n    {:<<>>, line, unescape_tokens(pieces)}\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~C` for charlists.\n\n  It returns a charlist without interpolations and without escape\n  characters.\n\n  A charlist is a list of integers where all the integers are valid code points.\n  The three expressions below are equivalent:\n\n      ~C\"foo\\n\"\n      [?f, ?o, ?o, ?\\\\, ?n]\n      [102, 111, 111, 92, 110]\n\n  In practice, charlists are mostly used in specific scenarios such as\n  interfacing with older Erlang libraries that do not accept binaries as arguments.\n\n  ## Examples\n\n      iex> ~C(foo)\n      ~c\"foo\"\n\n      iex> ~C(f#{o}o)\n      ~c\"f\\#{o}o\"\n\n      iex> ~C(foo\\n)\n      ~c\"foo\\\\n\"\n\n  \"\"\"\n  defmacro sigil_C(term, modifiers)\n\n  defmacro sigil_C({:<<>>, _meta, [string]}, []) when is_binary(string) do\n    String.to_charlist(string)\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~c` for charlists.\n\n  It returns a charlist, unescaping characters and replacing interpolations.\n\n  A charlist is a list of integers where all the integers are valid code points.\n  The three expressions below are equivalent:\n\n      ~c\"foo\"\n      [?f, ?o, ?o]\n      [102, 111, 111]\n\n  In practice, charlists are mostly used in specific scenarios such as\n  interfacing with older Erlang libraries that do not accept binaries as arguments.\n\n  ## Examples\n\n      iex> ~c(foo)\n      ~c\"foo\"\n\n      iex> ~c(f#{:o}o)\n      ~c\"foo\"\n\n      iex> ~c(f\\#{:o}o)\n      ~c\"f\\#{:o}o\"\n\n  The list is only printed as a `~c` sigil if all code points are within the\n  ASCII range:\n\n      iex> ~c\"hełło\"\n      [104, 101, 322, 322, 111]\n\n      iex> [104, 101, 108, 108, 111]\n      ~c\"hello\"\n\n  See `Inspect.Opts` for more information.\n  \"\"\"\n  defmacro sigil_c(term, modifiers)\n\n  # We can skip the runtime conversion if we are\n  # creating a binary made solely of series of chars.\n  defmacro sigil_c({:<<>>, _meta, [string]}, []) when is_binary(string) do\n    String.to_charlist(:elixir_interpolation.unescape_string(string))\n  end\n\n  defmacro sigil_c({:<<>>, _meta, pieces}, []) do\n    quote(do: List.to_charlist(unquote(unescape_list_tokens(pieces))))\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~r` for regular expressions.\n\n  It returns a regular expression pattern, unescaping characters and replacing\n  interpolations.\n\n  More information on regular expressions can be found in the `Regex` module.\n\n  ## Examples\n\n      iex> Regex.match?(~r/foo/, \"foo\")\n      true\n\n      iex> Regex.match?(~r/a#{:b}c/, \"abc\")\n      true\n\n  While the `~r` sigil allows parens and brackets to be used as delimiters,\n  it is preferred to use `\"` or `/` to avoid escaping conflicts with reserved\n  regex characters.\n  \"\"\"\n  defmacro sigil_r(term, modifiers)\n\n  defmacro sigil_r({:<<>>, _meta, [binary]}, options) when is_binary(binary) do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"the ~r sigil\")\n    binary = :elixir_interpolation.unescape_string(binary, &regex_unescape_map/1)\n    compile_regex(binary, options)\n  end\n\n  defmacro sigil_r({:<<>>, meta, pieces}, options) do\n    assert_no_match_or_guard_scope(__CALLER__.context, \"the ~r sigil\")\n    tuple = {:<<>>, meta, unescape_tokens(pieces, &regex_unescape_map/1)}\n    compile_regex(tuple, options)\n  end\n\n  defp regex_unescape_map(:newline), do: true\n  defp regex_unescape_map(_), do: false\n\n  @doc false\n  defmacro sigil_R({:<<>>, _meta, [binary]}, options) when is_binary(binary) do\n    IO.warn(\n      \"~R/.../ is deprecated, use ~r/.../ instead\",\n      Macro.Env.stacktrace(__CALLER__)\n    )\n\n    compile_regex(binary, options)\n  end\n\n  defp compile_regex(binary_or_tuple, options) do\n    bin_opts = :binary.list_to_bin(options)\n\n    case is_binary(binary_or_tuple) do\n      true ->\n        Macro.escape(Regex.compile!(binary_or_tuple, bin_opts))\n\n      false ->\n        quote(do: Regex.compile!(unquote(binary_or_tuple), unquote(bin_opts)))\n    end\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~D` for dates.\n\n  By default, this sigil uses the built-in `Calendar.ISO`, which\n  requires dates to be written in the ISO8601 format:\n\n      ~D[yyyy-mm-dd]\n\n  such as:\n\n      ~D[2015-01-13]\n\n  If you are using alternative calendars, any representation can\n  be used as long as you follow the representation by a single space\n  and the calendar name:\n\n      ~D[SOME-REPRESENTATION My.Alternative.Calendar]\n\n  The lower case `~d` variant does not exist as interpolation\n  and escape characters are not useful for date sigils.\n\n  More information on dates can be found in the `Date` module.\n\n  ## Examples\n\n      iex> ~D[2015-01-13]\n      ~D[2015-01-13]\n\n  \"\"\"\n  defmacro sigil_D(date_string, modifiers)\n\n  defmacro sigil_D({:<<>>, _, [string]}, []) do\n    {{:ok, {year, month, day}}, calendar} = parse_with_calendar!(string, :parse_date, \"Date\")\n    to_calendar_struct(Date, calendar: calendar, year: year, month: month, day: day)\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~T` for times.\n\n  By default, this sigil uses the built-in `Calendar.ISO`, which\n  requires times to be written in the ISO8601 format:\n\n      ~T[hh:mm:ss]\n      ~T[hh:mm:ss.ssssss]\n\n  such as:\n\n      ~T[13:00:07]\n      ~T[13:00:07.123]\n\n  If you are using alternative calendars, any representation can\n  be used as long as you follow the representation by a single space\n  and the calendar name:\n\n      ~T[SOME-REPRESENTATION My.Alternative.Calendar]\n\n  The lower case `~t` variant does not exist as interpolation\n  and escape characters are not useful for time sigils.\n\n  More information on times can be found in the `Time` module.\n\n  ## Examples\n\n      iex> ~T[13:00:07]\n      ~T[13:00:07]\n      iex> ~T[13:00:07.001]\n      ~T[13:00:07.001]\n\n  \"\"\"\n  defmacro sigil_T(time_string, modifiers)\n\n  defmacro sigil_T({:<<>>, _, [string]}, []) do\n    {{:ok, {hour, minute, second, microsecond}}, calendar} =\n      parse_with_calendar!(string, :parse_time, \"Time\")\n\n    to_calendar_struct(Time,\n      calendar: calendar,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    )\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~N` for naive date times.\n\n  By default, this sigil uses the built-in `Calendar.ISO`, which\n  requires naive date times to be written in the ISO8601 format:\n\n      ~N[yyyy-mm-dd hh:mm:ss]\n      ~N[yyyy-mm-dd hh:mm:ss.ssssss]\n      ~N[yyyy-mm-ddThh:mm:ss.ssssss]\n\n  such as:\n\n      ~N[2015-01-13 13:00:07]\n      ~N[2015-01-13T13:00:07.123]\n\n  If you are using alternative calendars, any representation can\n  be used as long as you follow the representation by a single space\n  and the calendar name:\n\n      ~N[SOME-REPRESENTATION My.Alternative.Calendar]\n\n  The lower case `~n` variant does not exist as interpolation\n  and escape characters are not useful for date time sigils.\n\n  More information on naive date times can be found in the\n  `NaiveDateTime` module.\n\n  ## Examples\n\n      iex> ~N[2015-01-13 13:00:07]\n      ~N[2015-01-13 13:00:07]\n      iex> ~N[2015-01-13T13:00:07.001]\n      ~N[2015-01-13 13:00:07.001]\n\n  \"\"\"\n  defmacro sigil_N(naive_datetime_string, modifiers)\n\n  defmacro sigil_N({:<<>>, _, [string]}, []) do\n    {{:ok, {year, month, day, hour, minute, second, microsecond}}, calendar} =\n      parse_with_calendar!(string, :parse_naive_datetime, \"NaiveDateTime\")\n\n    to_calendar_struct(NaiveDateTime,\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond\n    )\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~U` to create a UTC `DateTime`.\n\n  By default, this sigil uses the built-in `Calendar.ISO`, which\n  requires UTC date times to be written in the ISO8601 format:\n\n      ~U[yyyy-mm-dd hh:mm:ssZ]\n      ~U[yyyy-mm-dd hh:mm:ss.ssssssZ]\n      ~U[yyyy-mm-ddThh:mm:ss.ssssss+00:00]\n\n  such as:\n\n      ~U[2015-01-13 13:00:07Z]\n      ~U[2015-01-13T13:00:07.123+00:00]\n\n  If you are using alternative calendars, any representation can\n  be used as long as you follow the representation by a single space\n  and the calendar name:\n\n      ~U[SOME-REPRESENTATION My.Alternative.Calendar]\n\n  The given `datetime_string` must include \"Z\" or \"00:00\" offset\n  which marks it as UTC, otherwise an error is raised.\n\n  The lower case `~u` variant does not exist as interpolation\n  and escape characters are not useful for date time sigils.\n\n  More information on date times can be found in the `DateTime` module.\n\n  ## Examples\n\n      iex> ~U[2015-01-13 13:00:07Z]\n      ~U[2015-01-13 13:00:07Z]\n      iex> ~U[2015-01-13T13:00:07.001+00:00]\n      ~U[2015-01-13 13:00:07.001Z]\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  defmacro sigil_U(datetime_string, modifiers)\n\n  defmacro sigil_U({:<<>>, _, [string]}, []) do\n    {{:ok, {year, month, day, hour, minute, second, microsecond}, offset}, calendar} =\n      parse_with_calendar!(string, :parse_utc_datetime, \"UTC DateTime\")\n\n    if offset != 0 do\n      raise ArgumentError,\n            \"cannot parse #{inspect(string)} as UTC DateTime for #{inspect(calendar)}, reason: :non_utc_offset\"\n    end\n\n    to_calendar_struct(DateTime,\n      calendar: calendar,\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      time_zone: \"Etc/UTC\",\n      zone_abbr: \"UTC\",\n      utc_offset: 0,\n      std_offset: 0\n    )\n  end\n\n  defp parse_with_calendar!(string, fun, context) do\n    {calendar, string} = extract_calendar(string)\n    result = apply(calendar, fun, [string])\n    {maybe_raise!(result, calendar, context, string), calendar}\n  end\n\n  defp extract_calendar(string) do\n    case :binary.split(string, \" \", [:global]) do\n      [_] -> {Calendar.ISO, string}\n      parts -> maybe_atomize_calendar(List.last(parts), string)\n    end\n  end\n\n  defp maybe_atomize_calendar(<<alias, _::binary>> = last_part, string)\n       when alias >= ?A and alias <= ?Z do\n    string = binary_part(string, 0, byte_size(string) - byte_size(last_part) - 1)\n    {String.to_atom(\"Elixir.\" <> last_part), string}\n  end\n\n  defp maybe_atomize_calendar(_last_part, string) do\n    {Calendar.ISO, string}\n  end\n\n  defp maybe_raise!({:error, reason}, calendar, type, string) do\n    raise ArgumentError,\n          \"cannot parse #{inspect(string)} as #{type} for #{inspect(calendar)}, \" <>\n            \"reason: #{inspect(reason)}\"\n  end\n\n  defp maybe_raise!(other, _calendar, _type, _string), do: other\n\n  defp to_calendar_struct(type, fields) do\n    quote do\n      %unquote(type){unquote_splicing(fields)}\n    end\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~w` for list of words.\n\n  It returns a list of \"words\" split by whitespace. Character unescaping and\n  interpolation happens for each word.\n\n  ## Modifiers\n\n    * `s`: words in the list are strings (default)\n    * `a`: words in the list are atoms\n    * `c`: words in the list are charlists\n\n  ## Examples\n\n      iex> ~w(foo #{:bar} baz)\n      [\"foo\", \"bar\", \"baz\"]\n\n      iex> ~w(foo #{\" bar baz \"})\n      [\"foo\", \"bar\", \"baz\"]\n\n      iex> ~w(--source test/enum_test.exs)\n      [\"--source\", \"test/enum_test.exs\"]\n\n      iex> ~w(foo bar baz)a\n      [:foo, :bar, :baz]\n\n      iex> ~w(foo bar baz)c\n      [~c\"foo\", ~c\"bar\", ~c\"baz\"]\n\n  \"\"\"\n  defmacro sigil_w(term, modifiers)\n\n  defmacro sigil_w({:<<>>, _meta, [string]}, modifiers) when is_binary(string) do\n    split_words(:elixir_interpolation.unescape_string(string), modifiers, __CALLER__)\n  end\n\n  defmacro sigil_w({:<<>>, meta, pieces}, modifiers) do\n    binary = {:<<>>, meta, unescape_tokens(pieces)}\n    split_words(binary, modifiers, __CALLER__)\n  end\n\n  @doc ~S\"\"\"\n  Handles the sigil `~W` for list of words.\n\n  It returns a list of \"words\" split by whitespace without interpolations\n  and without escape characters.\n\n  ## Modifiers\n\n    * `s`: words in the list are strings (default)\n    * `a`: words in the list are atoms\n    * `c`: words in the list are charlists\n\n  ## Examples\n\n      iex> ~W(foo #{bar} baz)\n      [\"foo\", \"\\#{bar}\", \"baz\"]\n\n  \"\"\"\n  defmacro sigil_W(term, modifiers)\n\n  defmacro sigil_W({:<<>>, _meta, [string]}, modifiers) when is_binary(string) do\n    split_words(string, modifiers, __CALLER__)\n  end\n\n  defp split_words(string, [], caller) do\n    split_words(string, [?s], caller)\n  end\n\n  defp split_words(string, [mod], caller)\n       when mod == ?s or mod == ?a or mod == ?c do\n    case is_binary(string) do\n      true ->\n        parts = String.split(string)\n\n        parts_with_trailing_comma =\n          :lists.filter(&(byte_size(&1) > 1 and :binary.last(&1) == ?,), parts)\n\n        if parts_with_trailing_comma != [] do\n          stacktrace = Macro.Env.stacktrace(caller)\n\n          IO.warn(\n            \"the sigils ~w/~W do not allow trailing commas at the end of each word. \" <>\n              \"If the comma is necessary, define a regular list with [...], otherwise remove the comma.\",\n            stacktrace\n          )\n        end\n\n        case mod do\n          ?s -> parts\n          ?a -> :lists.map(&String.to_atom/1, parts)\n          ?c -> :lists.map(&String.to_charlist/1, parts)\n        end\n\n      false ->\n        parts = quote(do: String.split(unquote(string)))\n\n        case mod do\n          ?s -> parts\n          ?a -> quote(do: :lists.map(&String.to_atom/1, unquote(parts)))\n          ?c -> quote(do: :lists.map(&String.to_charlist/1, unquote(parts)))\n        end\n    end\n  end\n\n  defp split_words(_string, _mods, _caller) do\n    raise ArgumentError, \"modifier must be one of: s, a, c\"\n  end\n\n  ## Shared functions\n\n  defp assert_module_scope(env, fun, arity) do\n    case env.module do\n      nil -> raise ArgumentError, \"cannot invoke #{fun}/#{arity} outside module\"\n      mod -> mod\n    end\n  end\n\n  defp assert_no_function_scope(env, fun, arity) do\n    case env.function do\n      nil -> :ok\n      _ -> raise ArgumentError, \"cannot invoke #{fun}/#{arity} inside function/macro\"\n    end\n  end\n\n  defp assert_no_match_or_guard_scope(context, exp) do\n    case context do\n      :match ->\n        invalid_match!(exp)\n\n      :guard ->\n        raise ArgumentError,\n              \"invalid expression in guard, #{exp} is not allowed in guards. \" <>\n                \"To learn more about guards, visit: https://hexdocs.pm/elixir/patterns-and-guards.html\"\n\n      _ ->\n        :ok\n    end\n  end\n\n  defp invalid_match!(exp) do\n    raise ArgumentError,\n          \"invalid expression in match, #{exp} is not allowed in patterns \" <>\n            \"such as function clauses, case clauses or on the left side of the = operator\"\n  end\n\n  # Helper to handle the :ok | :error tuple returned from :elixir_interpolation.unescape_tokens\n  # We need to do this for bootstrapping purposes, actual code can use Macro.unescape_string.\n  defp unescape_tokens(tokens) do\n    :lists.map(\n      fn token ->\n        case is_binary(token) do\n          true -> :elixir_interpolation.unescape_string(token)\n          false -> token\n        end\n      end,\n      tokens\n    )\n  end\n\n  defp unescape_tokens(tokens, unescape_map) do\n    :lists.map(\n      fn token ->\n        case is_binary(token) do\n          true -> :elixir_interpolation.unescape_string(token, unescape_map)\n          false -> token\n        end\n      end,\n      tokens\n    )\n  end\n\n  defp unescape_list_tokens(tokens) do\n    escape = fn\n      {:\"::\", _, [expr, _]} -> expr\n      binary when is_binary(binary) -> :elixir_interpolation.unescape_string(binary)\n    end\n\n    :lists.map(escape, tokens)\n  end\n\n  @doc false\n  defmacro to_char_list(arg) do\n    IO.warn(\n      \"Kernel.to_char_list/1 is deprecated, use Kernel.to_charlist/1 instead\",\n      Macro.Env.stacktrace(__CALLER__)\n    )\n\n    quote(do: Kernel.to_charlist(unquote(arg)))\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/keyword.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Keyword do\n  @moduledoc \"\"\"\n  A keyword list is a list that consists exclusively of two-element tuples.\n\n  The first element of these tuples is known as the *key*, and it must be an atom.\n  The second element, known as the *value*, can be any term.\n\n  Keywords are mostly used to work with optional values. For a general introduction\n  to keywords and how they compare with maps, see our [Keyword and Maps](keywords-and-maps.md)\n  guide.\n\n  ## Examples\n\n  For example, the following is a keyword list:\n\n      [{:exit_on_close, true}, {:active, :once}, {:packet_size, 1024}]\n\n  Elixir provides a special and more concise syntax for keyword lists:\n\n      [exit_on_close: true, active: :once, packet_size: 1024]\n\n  The two syntaxes return the exact same value.\n\n  A *key* can be any atom, consisting of Unicode letters, numbers,\n  an underscore or the `@` sign. If the *key* should have any other\n  characters, such as spaces, you can wrap it in quotes:\n\n      iex> [\"exit on close\": true]\n      [\"exit on close\": true]\n\n  Wrapping an atom in quotes does not make it a string. Keyword list\n  *keys* are always atoms. Quotes should only be used when necessary\n  or Elixir will issue a warning.\n\n  ## Duplicate keys and ordering\n\n  A keyword may have duplicate keys so it is not strictly a key-value\n  data type. However, most of the functions in this module work on a\n  key-value structure and behave similar to the functions you would\n  find in the `Map` module. For example, `Keyword.get/3` will get the first\n  entry matching the given key, regardless if duplicate entries exist.\n  Similarly, `Keyword.put/3` and `Keyword.delete/2` ensure all duplicate\n  entries for a given key are removed when invoked. Note, however, that\n  keyword list operations need to traverse the whole list in order to find\n  keys, so these operations are slower than their map counterparts.\n\n  A handful of functions exist to handle duplicate keys, for example,\n  `get_values/2` returns all values for a given key and `delete_first/2`\n  deletes just the first entry of the existing ones.\n\n  Even though lists preserve the existing order, the functions in\n  `Keyword` do not guarantee any ordering. For example, if you invoke\n  `Keyword.put(opts, new_key, new_value)`, there is no guarantee for\n  where `new_key` will be added to (the front, the end or anywhere else).\n\n  Given ordering is not guaranteed, it is not recommended to pattern\n  match on keyword lists either. For example, a function such as:\n\n      def my_function([some_key: value, another_key: another_value])\n\n  will match\n\n      my_function([some_key: :foo, another_key: :bar])\n\n  but it won't match\n\n      my_function([another_key: :bar, some_key: :foo])\n\n  Most of the functions in this module work in linear time. This means\n  that the time it takes to perform an operation grows at the same\n  rate as the length of the list.\n\n  ## Call syntax\n\n  When keyword lists are passed as the last argument to a function,\n  the square brackets around the keyword list can be omitted. For\n  example, the keyword list syntax:\n\n      String.split(\"1-0\", \"-\", [trim: true, parts: 2])\n\n  can be written without the enclosing brackets whenever it is the last\n  argument of a function call:\n\n      String.split(\"1-0\", \"-\", trim: true, parts: 2)\n\n  Since tuples, lists and maps are treated similarly to function\n  arguments in Elixir syntax, this property is also available to them:\n\n      iex> {1, 2, foo: :bar}\n      {1, 2, [{:foo, :bar}]}\n\n      iex> [1, 2, foo: :bar]\n      [1, 2, {:foo, :bar}]\n\n      iex> %{1 => 2, foo: :bar}\n      %{1 => 2, :foo => :bar}\n\n  \"\"\"\n\n  @compile :inline_list_funcs\n\n  @type key :: atom\n  @type value :: any\n\n  @typedoc since: \"1.17.0\"\n  @type default :: any\n\n  @type t :: [{key, value}]\n  @type t(value) :: [{key, value}]\n\n  @doc \"\"\"\n  Builds a keyword from the given `keys` and the fixed `value`.\n\n  ## Examples\n\n      iex> Keyword.from_keys([:foo, :bar, :baz], :atom)\n      [foo: :atom, bar: :atom, baz: :atom]\n\n      iex> Keyword.from_keys([], :atom)\n      []\n\n      iex> Keyword.from_keys([\"foo\"], :bar)\n      ** (ArgumentError) expected a list of atoms as keys, got: \"foo\"\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec from_keys([key], value) :: t(value)\n  def from_keys(keys, value) when is_list(keys) do\n    :lists.map(\n      fn\n        key when is_atom(key) -> {key, value}\n        other -> raise ArgumentError, \"expected a list of atoms as keys, got: #{inspect(other)}\"\n      end,\n      keys\n    )\n  end\n\n  @doc \"\"\"\n  Returns `true` if `term` is a keyword list, otherwise `false`.\n\n  When `term` is a list it is traversed to the end.\n\n  ## Examples\n\n      iex> Keyword.keyword?([])\n      true\n      iex> Keyword.keyword?(a: 1)\n      true\n      iex> Keyword.keyword?([{Foo, 1}])\n      true\n      iex> Keyword.keyword?([{}])\n      false\n      iex> Keyword.keyword?([:key])\n      false\n      iex> Keyword.keyword?(%{})\n      false\n\n  \"\"\"\n  @spec keyword?(term) :: boolean\n  def keyword?(term)\n\n  def keyword?([{key, _value} | rest]) when is_atom(key), do: keyword?(rest)\n  def keyword?([]), do: true\n  def keyword?(_other), do: false\n\n  @doc \"\"\"\n  Returns an empty keyword list, i.e. an empty list.\n\n  ## Examples\n\n      iex> Keyword.new()\n      []\n\n  \"\"\"\n  @spec new :: []\n  def new, do: []\n\n  @doc \"\"\"\n  Creates a keyword list from an enumerable.\n\n  Removes duplicate entries and the last one prevails.\n  Unlike `Enum.into(enumerable, [])`, `Keyword.new(enumerable)`\n  guarantees the keys are unique.\n\n  ## Examples\n\n      iex> Keyword.new([{:b, 1}, {:a, 2}])\n      [b: 1, a: 2]\n\n      iex> Keyword.new([{:a, 1}, {:a, 2}, {:a, 3}])\n      [a: 3]\n\n  \"\"\"\n  @spec new(Enumerable.t()) :: t\n  def new(pairs) do\n    new(pairs, fn pair -> pair end)\n  end\n\n  @doc \"\"\"\n  Creates a keyword list from an enumerable via the transformation function.\n\n  Removes duplicate entries and the last one prevails.\n  Unlike `Enum.into(enumerable, [], fun)`,\n  `Keyword.new(enumerable, fun)` guarantees the keys are unique.\n\n  ## Examples\n\n      iex> Keyword.new([:a, :b], fn x -> {x, x} end)\n      [a: :a, b: :b]\n\n  \"\"\"\n  @spec new(Enumerable.t(), (term -> {key, value})) :: t\n  def new(pairs, transform) when is_function(transform, 1) do\n    fun = fn el, acc ->\n      {k, v} = transform.(el)\n      put_new(acc, k, v)\n    end\n\n    :lists.foldl(fun, [], Enum.reverse(pairs))\n  end\n\n  @doc \"\"\"\n  Ensures the given `keyword` has only the keys given in `values`.\n\n  The second argument must be a list of atoms, specifying\n  a given key, or tuples specifying a key and a default value.\n\n  If the keyword list has only the given keys, it returns\n  `{:ok, keyword}` with default values applied. Otherwise it\n  returns `{:error, invalid_keys}` with invalid keys.\n\n  See also: `validate!/2`.\n\n  ## Examples\n\n      iex> {:ok, result} = Keyword.validate([], [one: 1, two: 2])\n      iex> Enum.sort(result)\n      [one: 1, two: 2]\n\n      iex> {:ok, result} = Keyword.validate([two: 3], [one: 1, two: 2])\n      iex> Enum.sort(result)\n      [one: 1, two: 3]\n\n  If atoms are given, they are supported as keys but do not\n  provide a default value:\n\n      iex> {:ok, result} = Keyword.validate([], [:one, two: 2])\n      iex> Enum.sort(result)\n      [two: 2]\n\n      iex> {:ok, result} = Keyword.validate([one: 1], [:one, two: 2])\n      iex> Enum.sort(result)\n      [one: 1, two: 2]\n\n  Passing unknown keys returns an error:\n\n      iex> Keyword.validate([three: 3, four: 4], [one: 1, two: 2])\n      {:error, [:four, :three]}\n\n  Passing the same key multiple times also errors:\n\n      iex> Keyword.validate([one: 1, two: 2, one: 1], [:one, :two])\n      {:error, [:one]}\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec validate(keyword(), values :: [atom() | {atom(), term()}]) ::\n          {:ok, keyword()} | {:error, [atom]}\n  def validate(keyword, values) when is_list(keyword) and is_list(values) do\n    validate(keyword, values, [], [], [])\n  end\n\n  defp validate([{key, _} = pair | keyword], values1, values2, acc, bad_keys) when is_atom(key) do\n    case find_key!(key, values1, values2) do\n      {values1, values2} ->\n        validate(keyword, values1, values2, [pair | acc], bad_keys)\n\n      :error ->\n        case find_key!(key, values2, values1) do\n          {values1, values2} ->\n            validate(keyword, values1, values2, [pair | acc], bad_keys)\n\n          :error ->\n            validate(keyword, values1, values2, acc, [key | bad_keys])\n        end\n    end\n  end\n\n  defp validate([], values1, values2, acc, []) do\n    {:ok, move_pairs!(values1, move_pairs!(values2, acc))}\n  end\n\n  defp validate([], _values1, _values2, _acc, bad_keys) do\n    {:error, bad_keys}\n  end\n\n  defp validate([pair | _], _values1, _values2, _acc, []) do\n    raise ArgumentError,\n          \"expected a keyword list as first argument, got invalid entry: #{inspect(pair)}\"\n  end\n\n  defp find_key!(key, [key | rest], acc), do: {rest, acc}\n  defp find_key!(key, [{key, _} | rest], acc), do: {rest, acc}\n  defp find_key!(key, [head | tail], acc), do: find_key!(key, tail, [head | acc])\n  defp find_key!(_key, [], _acc), do: :error\n\n  defp move_pairs!([key | rest], acc) when is_atom(key),\n    do: move_pairs!(rest, acc)\n\n  defp move_pairs!([{key, _} = pair | rest], acc) when is_atom(key),\n    do: move_pairs!(rest, [pair | acc])\n\n  defp move_pairs!([], acc),\n    do: acc\n\n  defp move_pairs!([other | _], _) do\n    raise ArgumentError,\n          \"expected the second argument to be a list of atoms or tuples, got: #{inspect(other)}\"\n  end\n\n  @doc \"\"\"\n  Similar to `validate/2` but returns the keyword or raises an error.\n\n  ## Examples\n\n      iex> Keyword.validate!([], [one: 1, two: 2]) |> Enum.sort()\n      [one: 1, two: 2]\n      iex> Keyword.validate!([two: 3], [one: 1, two: 2]) |> Enum.sort()\n      [one: 1, two: 3]\n\n  If atoms are given, they are supported as keys but do not\n  provide a default value:\n\n      iex> Keyword.validate!([], [:one, two: 2]) |> Enum.sort()\n      [two: 2]\n      iex> Keyword.validate!([one: 1], [:one, two: 2]) |> Enum.sort()\n      [one: 1, two: 2]\n\n  Passing unknown keys raises an error:\n\n      iex> Keyword.validate!([three: 3], [one: 1, two: 2])\n      ** (ArgumentError) unknown keys [:three] in [three: 3], the allowed keys are: [:one, :two]\n\n  Passing the same key multiple times also errors:\n\n      iex> Keyword.validate!([one: 1, two: 2, one: 1], [:one, :two])\n      ** (ArgumentError) duplicate keys [:one] in [one: 1, two: 2, one: 1]\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec validate!(keyword(), values :: [atom() | {atom(), term()}]) :: keyword()\n  def validate!(keyword, values) do\n    case validate(keyword, values) do\n      {:ok, kw} ->\n        kw\n\n      {:error, invalid_keys} ->\n        keys =\n          for value <- values,\n              do: if(is_atom(value), do: value, else: elem(value, 0))\n\n        message =\n          case Enum.split_with(invalid_keys, &(&1 in keys)) do\n            {_, [_ | _] = unknown} ->\n              \"unknown keys #{inspect(unknown)} in #{inspect(keyword)}, \" <>\n                \"the allowed keys are: #{inspect(keys)}\"\n\n            {[_ | _] = known, _} ->\n              \"duplicate keys #{inspect(known)} in #{inspect(keyword)}\"\n          end\n\n        raise ArgumentError, message\n    end\n  end\n\n  @doc \"\"\"\n  Gets the value under the given `key`.\n\n  Returns the default value if `key` does not exist\n  (`nil` if no default value is provided).\n\n  If duplicate entries exist, it returns the first one.\n  Use `get_values/2` to retrieve all entries.\n\n  ## Examples\n\n      iex> Keyword.get([], :a)\n      nil\n      iex> Keyword.get([a: 1], :a)\n      1\n      iex> Keyword.get([a: 1], :b)\n      nil\n      iex> Keyword.get([a: 1], :b, 3)\n      3\n\n  With duplicate keys:\n\n      iex> Keyword.get([a: 1, a: 2], :a, 3)\n      1\n      iex> Keyword.get([a: 1, a: 2], :b, 3)\n      3\n\n  \"\"\"\n  @spec get(t, key, default) :: value | default\n  def get(keywords, key, default \\\\ nil) when is_list(keywords) and is_atom(key) do\n    case :lists.keyfind(key, 1, keywords) do\n      {^key, value} -> value\n      false -> default\n    end\n  end\n\n  @doc \"\"\"\n  Gets the value under the given `key`.\n\n  If `key` does not exist, lazily evaluates `fun` and returns its result.\n\n  This is useful if the default value is very expensive to calculate or\n  generally difficult to set up and tear down again.\n\n  If duplicate entries exist, it returns the first one.\n  Use `get_values/2` to retrieve all entries.\n\n  ## Examples\n\n      iex> keyword = [a: 1]\n      iex> fun = fn ->\n      ...>   # some expensive operation here\n      ...>   13\n      ...> end\n      iex> Keyword.get_lazy(keyword, :a, fun)\n      1\n      iex> Keyword.get_lazy(keyword, :b, fun)\n      13\n\n  \"\"\"\n  @spec get_lazy(t, key, (-> value)) :: value\n  def get_lazy(keywords, key, fun)\n      when is_list(keywords) and is_atom(key) and is_function(fun, 0) do\n    case :lists.keyfind(key, 1, keywords) do\n      {^key, value} -> value\n      false -> fun.()\n    end\n  end\n\n  @doc \"\"\"\n  Gets the value for `key` and updates it in one pass, deleting duplicate keys.\n\n  The `fun` argument receives the value of `key` (or `nil` if `key`\n  is not present) and must return a two-element tuple: the current value\n  (the retrieved value, which can be operated on before being returned)\n  and the new value to be stored under `key`. The `fun` may also\n  return `:pop`, implying the current value shall be removed from the\n  keyword list and returned.\n\n  Returns a tuple that contains the current value returned by\n  `fun` and a new keyword list with the updated value under `key`.\n\n  ## Examples\n\n      iex> Keyword.get_and_update([a: 1], :a, fn current_value ->\n      ...>   {current_value, \"new value!\"}\n      ...> end)\n      {1, [a: \"new value!\"]}\n\n      iex> Keyword.get_and_update([a: 1], :b, fn current_value ->\n      ...>   {current_value, \"new value!\"}\n      ...> end)\n      {nil, [b: \"new value!\", a: 1]}\n\n      iex> Keyword.get_and_update([a: 2], :a, fn number ->\n      ...>   {2 * number, 3 * number}\n      ...> end)\n      {4, [a: 6]}\n\n      iex> Keyword.get_and_update([a: 1], :a, fn _ -> :pop end)\n      {1, []}\n\n      iex> Keyword.get_and_update([a: 1], :b, fn _ -> :pop end)\n      {nil, [a: 1]}\n\n  \"\"\"\n  @spec get_and_update(t, key, (value | nil -> {current_value, new_value :: value} | :pop)) ::\n          {current_value, new_keywords :: t}\n        when current_value: value\n  def get_and_update(keywords, key, fun)\n      when is_list(keywords) and is_atom(key),\n      do: get_and_update(keywords, [], key, fun)\n\n  defp get_and_update([{key, current} | t], acc, key, fun) do\n    case fun.(current) do\n      {get, value} ->\n        {get, :lists.reverse(acc, [{key, value} | delete(t, key)])}\n\n      :pop ->\n        {current, :lists.reverse(acc, t)}\n\n      other ->\n        raise \"the given function must return a two-element tuple or :pop, got: #{inspect(other)}\"\n    end\n  end\n\n  defp get_and_update([{_, _} = h | t], acc, key, fun), do: get_and_update(t, [h | acc], key, fun)\n\n  defp get_and_update([], acc, key, fun) do\n    case fun.(nil) do\n      {get, update} ->\n        {get, [{key, update} | :lists.reverse(acc)]}\n\n      :pop ->\n        {nil, :lists.reverse(acc)}\n\n      other ->\n        raise \"the given function must return a two-element tuple or :pop, got: #{inspect(other)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Gets the value for `key` and updates it in one pass, deleting duplicate keys,\n  raising if `key` can't be found in `keywords`.\n\n  The `fun` argument receives the value under `key` and must return a\n  two-element tuple: the current value (the retrieved value, which can be\n  operated on before being returned) and the new value to be stored under\n  `key`.\n\n  Returns a tuple that contains the current value returned by\n  `fun` and a new keyword list with the updated value under `key`.\n\n  ## Examples\n\n      iex> Keyword.get_and_update!([a: 1], :a, fn current_value ->\n      ...>   {current_value, \"new value!\"}\n      ...> end)\n      {1, [a: \"new value!\"]}\n\n      iex> Keyword.get_and_update!([a: 1], :b, fn current_value ->\n      ...>   {current_value, \"new value!\"}\n      ...> end)\n      ** (KeyError) key :b not found in:\n      ...\n\n      iex> Keyword.get_and_update!([a: 1], :a, fn _ ->\n      ...>   :pop\n      ...> end)\n      {1, []}\n\n  \"\"\"\n  @spec get_and_update!(t, key, (value -> {current_value, new_value :: value} | :pop)) ::\n          {current_value, new_keywords :: t}\n        when current_value: value\n  def get_and_update!(keywords, key, fun) do\n    get_and_update!(keywords, key, fun, [])\n  end\n\n  defp get_and_update!([{key, value} | t], key, fun, acc) do\n    case fun.(value) do\n      {get, value} ->\n        {get, :lists.reverse(acc, [{key, value} | delete(t, key)])}\n\n      :pop ->\n        {value, :lists.reverse(acc, t)}\n\n      other ->\n        raise \"the given function must return a two-element tuple or :pop, got: #{inspect(other)}\"\n    end\n  end\n\n  defp get_and_update!([{_, _} = h | t], key, fun, acc) do\n    get_and_update!(t, key, fun, [h | acc])\n  end\n\n  defp get_and_update!([], key, _fun, acc) when is_atom(key) do\n    raise KeyError, key: key, term: acc\n  end\n\n  @doc \"\"\"\n  Fetches the value for a specific `key` and returns it in a tuple.\n\n  If the `key` does not exist, it returns `:error`.\n\n  ## Examples\n\n      iex> Keyword.fetch([a: 1], :a)\n      {:ok, 1}\n      iex> Keyword.fetch([a: 1], :b)\n      :error\n\n  \"\"\"\n  @spec fetch(t, key) :: {:ok, value} | :error\n  def fetch(keywords, key) when is_list(keywords) and is_atom(key) do\n    case :lists.keyfind(key, 1, keywords) do\n      {^key, value} -> {:ok, value}\n      false -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Fetches the value for specific `key`.\n\n  If the `key` does not exist, it raises a `KeyError`.\n\n  ## Examples\n\n      iex> Keyword.fetch!([a: 1], :a)\n      1\n      iex> Keyword.fetch!([a: 1], :b)\n      ** (KeyError) key :b not found in:\n      ...\n\n  \"\"\"\n  @spec fetch!(t, key) :: value\n  def fetch!(keywords, key) when is_list(keywords) and is_atom(key) do\n    case :lists.keyfind(key, 1, keywords) do\n      {^key, value} -> value\n      false -> raise KeyError, key: key, term: keywords\n    end\n  end\n\n  @doc \"\"\"\n  Gets all values under a specific `key`.\n\n  ## Examples\n\n      iex> Keyword.get_values([], :a)\n      []\n      iex> Keyword.get_values([a: 1], :a)\n      [1]\n      iex> Keyword.get_values([a: 1, a: 2], :a)\n      [1, 2]\n\n  \"\"\"\n  @spec get_values(t, key) :: [value]\n  def get_values(keywords, key) when is_list(keywords) and is_atom(key) do\n    get_values(keywords, key, [])\n  end\n\n  defp get_values([{key, value} | tail], key, values), do: get_values(tail, key, [value | values])\n  defp get_values([{_, _} | tail], key, values), do: get_values(tail, key, values)\n  defp get_values([], _key, values), do: :lists.reverse(values)\n\n  @doc \"\"\"\n  Returns all keys from the keyword list.\n\n  Keeps duplicate keys in the resulting list of keys.\n\n  ## Examples\n\n      iex> Keyword.keys(a: 1, b: 2)\n      [:a, :b]\n\n      iex> Keyword.keys(a: 1, b: 2, a: 3)\n      [:a, :b, :a]\n\n      iex> Keyword.keys([{:a, 1}, {\"b\", 2}, {:c, 3}])\n      ** (ArgumentError) expected a keyword list, but an entry in the list is not a two-element tuple with an atom as its first element, got: {\"b\", 2}\n\n  \"\"\"\n  @spec keys(t) :: [key]\n  def keys(keywords) when is_list(keywords) do\n    :lists.map(\n      fn\n        {key, _} when is_atom(key) -> key\n        element -> throw(element)\n      end,\n      keywords\n    )\n  catch\n    element ->\n      raise ArgumentError,\n            \"expected a keyword list, but an entry in the list is not a two-element tuple \" <>\n              \"with an atom as its first element, got: #{inspect(element)}\"\n  end\n\n  @doc \"\"\"\n  Returns all values from the keyword list.\n\n  Keeps values from duplicate keys in the resulting list of values.\n\n  ## Examples\n\n      iex> Keyword.values(a: 1, b: 2)\n      [1, 2]\n      iex> Keyword.values(a: 1, b: 2, a: 3)\n      [1, 2, 3]\n\n  \"\"\"\n  @spec values(t) :: [value]\n  def values(keywords) when is_list(keywords) do\n    :lists.map(fn {_, v} -> v end, keywords)\n  end\n\n  @doc false\n  @deprecated \"Use Keyword.fetch/2 + Keyword.delete/2 instead\"\n  def delete(keywords, key, value) when is_list(keywords) and is_atom(key) do\n    case :lists.keymember(key, 1, keywords) do\n      true -> delete_key_value(keywords, key, value)\n      _ -> keywords\n    end\n  end\n\n  defp delete_key_value([{key, value} | tail], key, value) do\n    delete_key_value(tail, key, value)\n  end\n\n  defp delete_key_value([{_, _} = pair | tail], key, value) do\n    [pair | delete_key_value(tail, key, value)]\n  end\n\n  defp delete_key_value([], _key, _value) do\n    []\n  end\n\n  @doc \"\"\"\n  Deletes the entries in the keyword list under a specific `key`.\n\n  If the `key` does not exist, it returns the keyword list unchanged.\n  Use `delete_first/2` to delete just the first entry in case of\n  duplicate keys.\n\n  ## Examples\n\n      iex> Keyword.delete([a: 1, b: 2], :a)\n      [b: 2]\n      iex> Keyword.delete([a: 1, b: 2, a: 3], :a)\n      [b: 2]\n      iex> Keyword.delete([b: 2], :a)\n      [b: 2]\n\n  \"\"\"\n  @spec delete(t, key) :: t\n  @compile {:inline, delete: 2}\n  def delete(keywords, key) when is_list(keywords) and is_atom(key) do\n    case :lists.keymember(key, 1, keywords) do\n      true -> delete_key(keywords, key)\n      _ -> keywords\n    end\n  end\n\n  defp delete_key([{key, _} | tail], key), do: delete_key(tail, key)\n  defp delete_key([{_, _} = pair | tail], key), do: [pair | delete_key(tail, key)]\n  defp delete_key([], _key), do: []\n\n  @doc \"\"\"\n  Deletes the first entry in the keyword list under a specific `key`.\n\n  If the `key` does not exist, it returns the keyword list unchanged.\n\n  ## Examples\n\n      iex> Keyword.delete_first([a: 1, b: 2, a: 3], :a)\n      [b: 2, a: 3]\n\n      iex> Keyword.delete_first([a: 1, b: 2, b: 3], :b)\n      [a: 1, b: 3]\n\n      iex> Keyword.delete_first([b: 2], :a)\n      [b: 2]\n\n  \"\"\"\n  @spec delete_first(t, key) :: t\n  def delete_first(keywords, key) when is_list(keywords) and is_atom(key) do\n    case :lists.keymember(key, 1, keywords) do\n      true -> delete_first_key(keywords, key)\n      _ -> keywords\n    end\n  end\n\n  defp delete_first_key([{key, _} | tail], key) do\n    tail\n  end\n\n  defp delete_first_key([{_, _} = pair | tail], key) do\n    [pair | delete_first_key(tail, key)]\n  end\n\n  @doc \"\"\"\n  Puts the given `value` under the specified `key`.\n\n  If a value under `key` already exists, it overrides the value\n  and removes all duplicate entries.\n\n  ## Examples\n\n      iex> Keyword.put([a: 1], :b, 2)\n      [b: 2, a: 1]\n      iex> Keyword.put([a: 1, b: 2], :a, 3)\n      [a: 3, b: 2]\n      iex> Keyword.put([a: 1, b: 2, a: 4], :a, 3)\n      [a: 3, b: 2]\n\n  \"\"\"\n  @spec put(t, key, value) :: t\n  def put(keywords, key, value) when is_list(keywords) and is_atom(key) do\n    [{key, value} | delete(keywords, key)]\n  end\n\n  @doc \"\"\"\n  Evaluates `fun` and puts the result under `key`\n  in keyword list unless `key` is already present.\n\n  This is useful if the value is very expensive to calculate or\n  generally difficult to set up and tear down again.\n\n  ## Examples\n\n      iex> keyword = [a: 1]\n      iex> fun = fn ->\n      ...>   # some expensive operation here\n      ...>   13\n      ...> end\n      iex> Keyword.put_new_lazy(keyword, :a, fun)\n      [a: 1]\n      iex> Keyword.put_new_lazy(keyword, :b, fun)\n      [b: 13, a: 1]\n\n  \"\"\"\n  @spec put_new_lazy(t, key, (-> value)) :: t\n  def put_new_lazy(keywords, key, fun)\n      when is_list(keywords) and is_atom(key) and is_function(fun, 0) do\n    case :lists.keyfind(key, 1, keywords) do\n      {^key, _} -> keywords\n      false -> [{key, fun.()} | keywords]\n    end\n  end\n\n  @doc \"\"\"\n  Puts the given `value` under `key`, unless the entry `key` already exists.\n\n  ## Examples\n\n      iex> Keyword.put_new([a: 1], :b, 2)\n      [b: 2, a: 1]\n      iex> Keyword.put_new([a: 1, b: 2], :a, 3)\n      [a: 1, b: 2]\n\n  \"\"\"\n  @spec put_new(t, key, value) :: t\n  def put_new(keywords, key, value) when is_list(keywords) and is_atom(key) do\n    case :lists.keyfind(key, 1, keywords) do\n      {^key, _} -> keywords\n      false -> [{key, value} | keywords]\n    end\n  end\n\n  @doc \"\"\"\n  Puts a value under `key` only if the `key` already exists in `keywords`.\n\n  In case a key exists multiple times in the keyword list,\n  it removes later occurrences.\n\n  ## Examples\n\n      iex> Keyword.replace([a: 1, b: 2, a: 4], :a, 3)\n      [a: 3, b: 2]\n\n      iex> Keyword.replace([a: 1], :b, 2)\n      [a: 1]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec replace(t, key, value) :: t\n  def replace(keywords, key, value) when is_list(keywords) and is_atom(key) do\n    do_replace(keywords, key, value)\n  end\n\n  defp do_replace([{key, _} | keywords], key, value) do\n    [{key, value} | delete(keywords, key)]\n  end\n\n  defp do_replace([{_, _} = e | keywords], key, value) do\n    [e | do_replace(keywords, key, value)]\n  end\n\n  defp do_replace([], _key, _value) do\n    []\n  end\n\n  @doc \"\"\"\n  Puts a value under `key` only if the `key` already exists in `keywords`.\n\n  If `key` is not present in `keywords`, it raises a `KeyError`.\n\n  ## Examples\n\n      iex> Keyword.replace!([a: 1, b: 2, a: 3], :a, :new)\n      [a: :new, b: 2]\n      iex> Keyword.replace!([a: 1, b: 2, c: 3, b: 4], :b, :new)\n      [a: 1, b: :new, c: 3]\n\n      iex> Keyword.replace!([a: 1], :b, 2)\n      ** (KeyError) key :b not found in:\n      ...\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec replace!(t, key, value) :: t\n  def replace!(keywords, key, value) when is_list(keywords) and is_atom(key) do\n    replace!(keywords, key, value, keywords)\n  end\n\n  defp replace!([{key, _} | keywords], key, value, _original) do\n    [{key, value} | delete(keywords, key)]\n  end\n\n  defp replace!([{_, _} = e | keywords], key, value, original) do\n    [e | replace!(keywords, key, value, original)]\n  end\n\n  defp replace!([], key, _value, original) do\n    raise KeyError, key: key, term: original\n  end\n\n  @doc \"\"\"\n  Replaces the value under `key` using the given function only if\n  `key` already exists in `keywords`.\n\n  In comparison to `replace/3`, this can be useful when it's expensive to calculate the value.\n\n  If `key` does not exist, the original keyword list is returned unchanged.\n\n  ## Examples\n\n      iex> Keyword.replace_lazy([a: 1, b: 2], :a, fn v -> v * 4 end)\n      [a: 4, b: 2]\n\n      iex> Keyword.replace_lazy([a: 2, b: 2, a: 1], :a, fn v -> v * 4 end)\n      [a: 8, b: 2]\n\n      iex> Keyword.replace_lazy([a: 1, b: 2], :c, fn v -> v * 4 end)\n      [a: 1, b: 2]\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec replace_lazy(t, key, (existing_value :: value -> new_value :: value)) :: t\n  def replace_lazy(keywords, key, fun)\n      when is_list(keywords) and is_atom(key) and is_function(fun, 1) do\n    do_replace_lazy(keywords, key, fun)\n  end\n\n  defp do_replace_lazy([{key, value} | keywords], key, fun) do\n    [{key, fun.(value)} | delete(keywords, key)]\n  end\n\n  defp do_replace_lazy([{_, _} = e | keywords], key, fun) do\n    [e | do_replace_lazy(keywords, key, fun)]\n  end\n\n  defp do_replace_lazy([], _key, _value), do: []\n\n  @doc \"\"\"\n  Checks if two keywords are equal.\n\n  Considers two keywords to be equal if they contain\n  the same keys and those keys contain the same values.\n\n  ## Examples\n\n      iex> Keyword.equal?([a: 1, b: 2], [b: 2, a: 1])\n      true\n      iex> Keyword.equal?([a: 1, b: 2], [b: 1, a: 2])\n      false\n      iex> Keyword.equal?([a: 1, b: 2, a: 3], [b: 2, a: 3, a: 1])\n      true\n\n  Comparison between values is done with `===/3`,\n  which means integers are not equivalent to floats:\n\n      iex> Keyword.equal?([a: 1.0], [a: 1])\n      false\n\n  \"\"\"\n  @spec equal?(t, t) :: boolean\n  def equal?(left, right) when is_list(left) and is_list(right) do\n    :lists.sort(left) === :lists.sort(right)\n  end\n\n  @doc \"\"\"\n  Intersects two keyword lists, returning a keyword with the common keys.\n\n  By default, it returns the values of the intersected keys in `keyword2`.\n  The keys are returned in the order found in `keyword1`.\n\n  ## Examples\n\n      iex> Keyword.intersect([a: 1, b: 2], [b: \"b\", c: \"c\"])\n      [b: \"b\"]\n\n      iex> Keyword.intersect([a: 1, b: 2], [b: 2, c: 3], fn _k, v1, v2 ->\n      ...>   v1 + v2\n      ...> end)\n      [b: 4]\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec intersect(keyword, keyword, (key, value, value -> value)) :: keyword\n  def intersect(keyword1, keyword2, fun \\\\ fn _key, _v1, v2 -> v2 end)\n\n  def intersect([{k, v1} | keyword1], keyword2, fun) do\n    case :lists.keyfind(k, 1, keyword2) do\n      {_, v2} -> [{k, fun.(k, v1, v2)} | intersect(keyword1, keyword2, fun)]\n      false -> intersect(keyword1, keyword2, fun)\n    end\n  end\n\n  def intersect([], _keyword2, _fun), do: []\n\n  @doc \"\"\"\n  Merges two keyword lists into one.\n\n  Adds all keys, including duplicate keys, given in `keywords2`\n  to `keywords1`, overriding any existing ones.\n\n  There are no guarantees about the order of the keys in the returned keyword.\n\n  ## Examples\n\n      iex> Keyword.merge([a: 1, b: 2], [a: 3, d: 4])\n      [b: 2, a: 3, d: 4]\n\n      iex> Keyword.merge([a: 1, b: 2], [a: 3, d: 4, a: 5])\n      [b: 2, a: 3, d: 4, a: 5]\n\n      iex> Keyword.merge([a: 1], [2, 3])\n      ** (ArgumentError) expected a keyword list as the second argument, got: [2, 3]\n\n  \"\"\"\n  @spec merge(t, t) :: t\n  def merge(keywords1, keywords2)\n\n  def merge(keywords1, []) when is_list(keywords1), do: keywords1\n  def merge([], keywords2) when is_list(keywords2), do: keywords2\n\n  def merge(keywords1, keywords2) when is_list(keywords1) and is_list(keywords2) do\n    if keyword?(keywords2) do\n      fun = fn\n        {key, _value} when is_atom(key) ->\n          not has_key?(keywords2, key)\n\n        _ ->\n          raise ArgumentError,\n                \"expected a keyword list as the first argument, got: #{inspect(keywords1)}\"\n      end\n\n      :lists.filter(fun, keywords1) ++ keywords2\n    else\n      raise ArgumentError,\n            \"expected a keyword list as the second argument, got: #{inspect(keywords2)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Merges two keyword lists into one.\n\n  Adds all keys, including duplicate keys, given in `keywords2`\n  to `keywords1`. Invokes the given function to solve conflicts.\n\n  If `keywords2` has duplicate keys, it invokes the given function\n  for each matching pair in `keywords1`.\n\n  There are no guarantees about the order of the keys in the returned keyword.\n\n  ## Examples\n\n      iex> Keyword.merge([a: 1, b: 2], [a: 3, d: 4], fn _k, v1, v2 ->\n      ...>   v1 + v2\n      ...> end)\n      [b: 2, a: 4, d: 4]\n\n      iex> Keyword.merge([a: 1, b: 2], [a: 3, d: 4, a: 5], fn :a, v1, v2 ->\n      ...>   v1 + v2\n      ...> end)\n      [b: 2, a: 4, d: 4, a: 5]\n\n      iex> Keyword.merge([a: 1, b: 2, a: 3], [a: 3, d: 4, a: 5], fn :a, v1, v2 ->\n      ...>   v1 + v2\n      ...> end)\n      [b: 2, a: 4, d: 4, a: 8]\n\n      iex> Keyword.merge([a: 1, b: 2], [:a, :b], fn :a, v1, v2 ->\n      ...>   v1 + v2\n      ...> end)\n      ** (ArgumentError) expected a keyword list as the second argument, got: [:a, :b]\n\n  \"\"\"\n  @spec merge(t, t, (key, value, value -> value)) :: t\n  def merge(keywords1, keywords2, fun)\n      when is_list(keywords1) and is_list(keywords2) and is_function(fun, 3) do\n    if keyword?(keywords1) do\n      do_merge(keywords2, [], keywords1, keywords1, fun, keywords2)\n    else\n      raise ArgumentError,\n            \"expected a keyword list as the first argument, got: #{inspect(keywords1)}\"\n    end\n  end\n\n  defp do_merge([{key, value2} | tail], acc, rest, original, fun, keywords2) when is_atom(key) do\n    case :lists.keyfind(key, 1, original) do\n      {^key, value1} ->\n        acc = [{key, fun.(key, value1, value2)} | acc]\n        original = :lists.keydelete(key, 1, original)\n        do_merge(tail, acc, delete(rest, key), original, fun, keywords2)\n\n      false ->\n        do_merge(tail, [{key, value2} | acc], rest, original, fun, keywords2)\n    end\n  end\n\n  defp do_merge([], acc, rest, _original, _fun, _keywords2) do\n    rest ++ :lists.reverse(acc)\n  end\n\n  defp do_merge(_other, _acc, _rest, _original, _fun, keywords2) do\n    raise ArgumentError,\n          \"expected a keyword list as the second argument, got: #{inspect(keywords2)}\"\n  end\n\n  @doc \"\"\"\n  Returns whether a given `key` exists in the given `keywords`.\n\n  ## Examples\n\n      iex> Keyword.has_key?([a: 1], :a)\n      true\n      iex> Keyword.has_key?([a: 1], :b)\n      false\n\n  \"\"\"\n  @spec has_key?(t, key) :: boolean\n  def has_key?(keywords, key) when is_list(keywords) and is_atom(key) do\n    :lists.keymember(key, 1, keywords)\n  end\n\n  @doc \"\"\"\n  Updates the value under `key` using the given function.\n\n  Raises `KeyError` if the `key` does not exist.\n\n  Removes all duplicate keys and only updates the first one.\n\n  ## Examples\n\n      iex> Keyword.update!([a: 1, b: 2, a: 3], :a, &(&1 * 2))\n      [a: 2, b: 2]\n      iex> Keyword.update!([a: 1, b: 2, c: 3], :b, &(&1 * 2))\n      [a: 1, b: 4, c: 3]\n\n      iex> Keyword.update!([a: 1], :b, &(&1 * 2))\n      ** (KeyError) key :b not found in:\n      ...\n\n  \"\"\"\n  @spec update!(t, key, (current_value :: value -> new_value :: value)) :: t\n  def update!(keywords, key, fun)\n      when is_list(keywords) and is_atom(key) and is_function(fun, 1) do\n    update!(keywords, key, fun, keywords)\n  end\n\n  defp update!([{key, value} | keywords], key, fun, _original) do\n    [{key, fun.(value)} | delete(keywords, key)]\n  end\n\n  defp update!([{_, _} = pair | keywords], key, fun, original) do\n    [pair | update!(keywords, key, fun, original)]\n  end\n\n  defp update!([], key, _fun, original) do\n    raise KeyError, key: key, term: original\n  end\n\n  @doc \"\"\"\n  Updates the value under `key` in `keywords` using the given function.\n\n  If the `key` does not exist, it inserts the given `default` value.\n  Does not pass the `default` value through the update function.\n\n  Removes all duplicate keys and only updates the first one.\n\n  ## Examples\n\n      iex> Keyword.update([a: 1], :a, 13, fn existing_value -> existing_value * 2 end)\n      [a: 2]\n\n      iex> Keyword.update([a: 1, a: 2], :a, 13, fn existing_value -> existing_value * 2 end)\n      [a: 2]\n\n      iex> Keyword.update([a: 1], :b, 11, fn existing_value -> existing_value * 2 end)\n      [a: 1, b: 11]\n\n  \"\"\"\n  @spec update(t, key, default :: value, (existing_value :: value -> new_value :: value)) :: t\n  def update(keywords, key, default, fun)\n      when is_list(keywords) and is_atom(key) and is_function(fun, 1) do\n    update_guarded(keywords, key, default, fun)\n  end\n\n  defp update_guarded([{key, value} | keywords], key, _default, fun) do\n    [{key, fun.(value)} | delete(keywords, key)]\n  end\n\n  defp update_guarded([{_, _} = pair | keywords], key, default, fun) do\n    [pair | update_guarded(keywords, key, default, fun)]\n  end\n\n  defp update_guarded([], key, default, _fun) do\n    [{key, default}]\n  end\n\n  @doc \"\"\"\n  Takes all entries corresponding to the given `keys` and extracts them into a\n  separate keyword list.\n\n  Returns a tuple with the new list and the old list with removed keys.\n\n  Ignores keys for which there are no entries in the keyword list.\n\n  Entries with duplicate keys end up in the same keyword list.\n\n  ## Examples\n\n      iex> Keyword.split([a: 1, b: 2, c: 3], [:a, :c, :e])\n      {[a: 1, c: 3], [b: 2]}\n      iex> Keyword.split([a: 1, b: 2, c: 3, a: 4], [:a, :c, :e])\n      {[a: 1, c: 3, a: 4], [b: 2]}\n\n  \"\"\"\n  @spec split(t, [key]) :: {t, t}\n  def split(keywords, keys) when is_list(keywords) and is_list(keys) do\n    fun = fn {k, v}, {take, drop} ->\n      case k in keys do\n        true -> {[{k, v} | take], drop}\n        false -> {take, [{k, v} | drop]}\n      end\n    end\n\n    acc = {[], []}\n    {take, drop} = :lists.foldl(fun, acc, keywords)\n    {:lists.reverse(take), :lists.reverse(drop)}\n  end\n\n  @doc \"\"\"\n  Splits the `keywords` into two keyword lists according to the given function\n  `fun`.\n\n  The provided `fun` receives each `{key, value}` pair in the `keywords` as its only\n  argument. Returns a tuple with the first keyword list containing all the\n  elements in `keywords` for which applying `fun` returned a truthy value, and\n  a second keyword list with all the elements for which applying `fun` returned\n  a falsy value (`false` or `nil`).\n\n  ## Examples\n\n      iex> Keyword.split_with([a: 1, b: 2, c: 3], fn {_k, v} -> rem(v, 2) == 0 end)\n      {[b: 2], [a: 1, c: 3]}\n\n      iex> Keyword.split_with([a: 1, b: 2, c: 3, b: 4], fn {_k, v} -> rem(v, 2) == 0 end)\n      {[b: 2, b: 4], [a: 1, c: 3]}\n\n      iex> Keyword.split_with([a: 1, b: 2, c: 3, b: 4], fn {k, v} -> k in [:a, :c] and rem(v, 2) == 0 end)\n      {[], [a: 1, b: 2, c: 3, b: 4]}\n\n      iex> Keyword.split_with([], fn {_k, v} -> rem(v, 2) == 0 end)\n      {[], []}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec split_with(t, ({key, value} -> as_boolean(term))) :: {t, t}\n  def split_with(keywords, fun) when is_list(keywords) and is_function(fun, 1) do\n    fun = fn key_value_pair, {while_true, while_false} ->\n      if fun.(key_value_pair) do\n        {[key_value_pair | while_true], while_false}\n      else\n        {while_true, [key_value_pair | while_false]}\n      end\n    end\n\n    :lists.foldr(fun, {[], []}, keywords)\n  end\n\n  @doc \"\"\"\n  Takes all entries corresponding to the given `keys` and returns them as a new\n  keyword list.\n\n  Preserves duplicate keys in the new keyword list.\n\n  ## Examples\n\n      iex> Keyword.take([a: 1, b: 2, c: 3], [:a, :c, :e])\n      [a: 1, c: 3]\n      iex> Keyword.take([a: 1, b: 2, c: 3, a: 5], [:a, :c, :e])\n      [a: 1, c: 3, a: 5]\n\n  \"\"\"\n  @spec take(t, [key]) :: t\n  def take(keywords, keys) when is_list(keywords) and is_list(keys) do\n    :lists.filter(fn {k, _} -> :lists.member(k, keys) end, keywords)\n  end\n\n  @doc \"\"\"\n  Drops the given `keys` from the keyword list.\n\n  Removes duplicate keys from the new keyword list.\n\n  ## Examples\n\n      iex> Keyword.drop([a: 1, a: 2], [:a])\n      []\n      iex> Keyword.drop([a: 1, b: 2, c: 3], [:b, :d])\n      [a: 1, c: 3]\n      iex> Keyword.drop([a: 1, b: 2, b: 3, c: 3, a: 5], [:b, :d])\n      [a: 1, c: 3, a: 5]\n\n  \"\"\"\n  @spec drop(t, [key]) :: t\n  def drop(keywords, keys) when is_list(keywords) and is_list(keys) do\n    :lists.filter(fn {k, _} -> k not in keys end, keywords)\n  end\n\n  @doc \"\"\"\n  Returns the first value for `key` and removes all associated entries in the keyword list.\n\n  It returns a tuple where the first element is the first value for `key` and the\n  second element is a keyword list with all entries associated with `key` removed.\n  If the `key` is not present in the keyword list, it returns `{default, keyword_list}`.\n\n  If you don't want to remove all the entries associated with `key` use `pop_first/3`\n  instead, which will remove only the first entry.\n\n  ## Examples\n\n      iex> Keyword.pop([a: 1], :a)\n      {1, []}\n      iex> Keyword.pop([a: 1], :b)\n      {nil, [a: 1]}\n      iex> Keyword.pop([a: 1], :b, 3)\n      {3, [a: 1]}\n      iex> Keyword.pop([a: 1, a: 2], :a)\n      {1, []}\n\n  \"\"\"\n  @spec pop(t, key, default) :: {value | default, t}\n  def pop(keywords, key, default \\\\ nil) when is_list(keywords) and is_atom(key) do\n    case fetch(keywords, key) do\n      {:ok, value} -> {value, delete(keywords, key)}\n      :error -> {default, keywords}\n    end\n  end\n\n  @doc \"\"\"\n  Returns the first value for `key` and removes all associated entries in the keyword list,\n  raising if `key` is not present.\n\n  This function behaves like `pop/3`, but raises in case the `key` is not present in the\n  given `keywords`.\n\n  ## Examples\n\n      iex> Keyword.pop!([a: 1], :a)\n      {1, []}\n      iex> Keyword.pop!([a: 1, a: 2], :a)\n      {1, []}\n      iex> Keyword.pop!([a: 1], :b)\n      ** (KeyError) key :b not found in:\n      ...\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec pop!(t, key) :: {value, t}\n  def pop!(keywords, key) when is_list(keywords) and is_atom(key) do\n    case fetch(keywords, key) do\n      {:ok, value} -> {value, delete(keywords, key)}\n      :error -> raise KeyError, key: key, term: keywords\n    end\n  end\n\n  @doc \"\"\"\n  Returns all values for `key` and removes all associated entries in the keyword list.\n\n  It returns a tuple where the first element is a list of values for `key` and the\n  second element is a keyword list with all entries associated with `key` removed.\n  If the `key` is not present in the keyword list, it returns `{[], keyword_list}`.\n\n  If you don't want to remove all the entries associated with `key` use `pop_first/3`\n  instead, which will remove only the first entry.\n\n  ## Examples\n\n      iex> Keyword.pop_values([a: 1], :a)\n      {[1], []}\n      iex> Keyword.pop_values([a: 1], :b)\n      {[], [a: 1]}\n      iex> Keyword.pop_values([a: 1, a: 2], :a)\n      {[1, 2], []}\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec pop_values(t, key) :: {[value], t}\n  def pop_values(keywords, key) when is_list(keywords) and is_atom(key) do\n    pop_values(:lists.reverse(keywords), key, [], [])\n  end\n\n  defp pop_values([{key, value} | tail], key, values, acc),\n    do: pop_values(tail, key, [value | values], acc)\n\n  defp pop_values([{_, _} = pair | tail], key, values, acc),\n    do: pop_values(tail, key, values, [pair | acc])\n\n  defp pop_values([], _key, values, acc),\n    do: {values, acc}\n\n  @doc \"\"\"\n  Lazily returns and removes all values associated with `key` in the keyword list.\n\n  This is useful if the default value is very expensive to calculate or\n  generally difficult to set up and tear down again.\n\n  Removes all duplicate keys. See `pop_first/3` for removing only the first entry.\n\n  ## Examples\n\n      iex> keyword = [a: 1]\n      iex> fun = fn ->\n      ...>   # some expensive operation here\n      ...>   13\n      ...> end\n      iex> Keyword.pop_lazy(keyword, :a, fun)\n      {1, []}\n      iex> Keyword.pop_lazy(keyword, :b, fun)\n      {13, [a: 1]}\n\n  \"\"\"\n  @spec pop_lazy(t, key, (-> value)) :: {value, t}\n  def pop_lazy(keywords, key, fun)\n      when is_list(keywords) and is_atom(key) and is_function(fun, 0) do\n    case fetch(keywords, key) do\n      {:ok, value} -> {value, delete(keywords, key)}\n      :error -> {fun.(), keywords}\n    end\n  end\n\n  @doc \"\"\"\n  Returns and removes the first value associated with `key` in the keyword list.\n\n  Keeps duplicate keys in the resulting keyword list.\n\n  ## Examples\n\n      iex> Keyword.pop_first([a: 1], :a)\n      {1, []}\n      iex> Keyword.pop_first([a: 1], :b)\n      {nil, [a: 1]}\n      iex> Keyword.pop_first([a: 1], :b, 3)\n      {3, [a: 1]}\n      iex> Keyword.pop_first([a: 1, a: 2], :a)\n      {1, [a: 2]}\n\n  \"\"\"\n  @spec pop_first(t, key, default) :: {value | default, t}\n  def pop_first(keywords, key, default \\\\ nil) when is_list(keywords) and is_atom(key) do\n    case :lists.keytake(key, 1, keywords) do\n      {:value, {^key, value}, rest} -> {value, rest}\n      false -> {default, keywords}\n    end\n  end\n\n  @doc \"\"\"\n  Returns the keyword list itself.\n\n  ## Examples\n\n      iex> Keyword.to_list(a: 1)\n      [a: 1]\n\n  \"\"\"\n  @spec to_list(t) :: t\n  def to_list(keywords) when is_list(keywords) do\n    keywords\n  end\n\n  @doc false\n  @deprecated \"Use Kernel.length/1 instead\"\n  def size(keywords) do\n    length(keywords)\n  end\n\n  @doc \"\"\"\n  Returns a keyword list containing only the entries from `keywords`\n  for which the function `fun` returns a truthy value.\n\n  See also `reject/2` which discards all entries where the function\n  returns a truthy value.\n\n  ## Examples\n\n      iex> Keyword.filter([one: 1, two: 2, three: 3], fn {_key, val} -> rem(val, 2) == 1 end)\n      [one: 1, three: 3]\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec filter(t, ({key, value} -> as_boolean(term))) :: t\n  def filter(keywords, fun) when is_list(keywords) and is_function(fun, 1) do\n    do_filter(keywords, fun)\n  end\n\n  defp do_filter([], _fun), do: []\n\n  defp do_filter([{_, _} = entry | entries], fun) do\n    if fun.(entry) do\n      [entry | do_filter(entries, fun)]\n    else\n      do_filter(entries, fun)\n    end\n  end\n\n  @doc \"\"\"\n  Returns a keyword list excluding the entries from `keywords`\n  for which the function `fun` returns a truthy value.\n\n  See also `filter/2`.\n\n  ## Examples\n\n      iex> Keyword.reject([one: 1, two: 2, three: 3], fn {_key, val} -> rem(val, 2) == 1 end)\n      [two: 2]\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec reject(t, ({key, value} -> as_boolean(term))) :: t\n  def reject(keywords, fun) when is_list(keywords) and is_function(fun, 1) do\n    do_reject(keywords, fun)\n  end\n\n  defp do_reject([], _fun), do: []\n\n  defp do_reject([{_, _} = entry | entries], fun) do\n    if fun.(entry) do\n      do_reject(entries, fun)\n    else\n      [entry | do_reject(entries, fun)]\n    end\n  end\n\n  @doc false\n  @deprecated \"Use Keyword.new/2 instead\"\n  def map(keywords, fun) when is_list(keywords) do\n    Enum.map(keywords, fn {k, v} -> {k, fun.({k, v})} end)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/list/chars.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefprotocol List.Chars do\n  @moduledoc ~S\"\"\"\n  The `List.Chars` protocol is responsible for\n  converting a structure to a charlist (only if applicable).\n\n  The only function that must be implemented is\n  `to_charlist/1` which does the conversion.\n\n  The `to_charlist/1` function automatically imported\n  by `Kernel` invokes this protocol.\n  \"\"\"\n\n  @doc \"\"\"\n  Converts `term` to a charlist.\n  \"\"\"\n  @spec to_charlist(t) :: charlist\n  def to_charlist(term)\nend\n\ndefimpl List.Chars, for: Atom do\n  def to_charlist(nil), do: ~c\"\"\n\n  def to_charlist(atom), do: Atom.to_charlist(atom)\nend\n\ndefimpl List.Chars, for: BitString do\n  @doc \"\"\"\n  Returns the given binary `term` converted to a charlist.\n  \"\"\"\n  def to_charlist(term) when is_binary(term) do\n    String.to_charlist(term)\n  end\n\n  def to_charlist(term) do\n    raise Protocol.UndefinedError,\n      protocol: @protocol,\n      value: term,\n      description: \"cannot convert a bitstring to a charlist\"\n  end\nend\n\ndefimpl List.Chars, for: List do\n  # Note that same inlining is used for the rewrite rule.\n  def to_charlist(list), do: list\nend\n\ndefimpl List.Chars, for: Integer do\n  def to_charlist(term) do\n    Integer.to_charlist(term)\n  end\nend\n\ndefimpl List.Chars, for: Float do\n  def to_charlist(term) do\n    Float.to_charlist(term)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/list.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule List do\n  @moduledoc \"\"\"\n  Linked lists hold zero, one, or more elements in the chosen order.\n\n  Lists in Elixir are specified between square brackets:\n\n      iex> [1, \"two\", 3, :four]\n      [1, \"two\", 3, :four]\n\n  Two lists can be concatenated and subtracted using the\n  `++/2` and `--/2` operators:\n\n      iex> [1, 2, 3] ++ [4, 5, 6]\n      [1, 2, 3, 4, 5, 6]\n      iex> [1, true, 2, false, 3, true] -- [true, false]\n      [1, 2, 3, true]\n\n  An element can be prepended to a list using `|`:\n\n      iex> new = 0\n      iex> list = [1, 2, 3]\n      iex> [new | list]\n      [0, 1, 2, 3]\n\n  Lists in Elixir are effectively linked lists, which means\n  they are internally represented in pairs containing the\n  head and the tail of a list:\n\n      iex> [head | tail] = [1, 2, 3]\n      iex> head\n      1\n      iex> tail\n      [2, 3]\n\n  Similarly, we could write the list `[1, 2, 3]` using only\n  such pairs (called cons cells):\n\n      iex> [1 | [2 | [3 | []]]]\n      [1, 2, 3]\n\n  Some lists, called improper lists, do not have an empty list as\n  the second element in the last cons cell:\n\n      iex> [1 | [2 | [3 | 4]]]\n      [1, 2, 3 | 4]\n\n  Although improper lists are generally avoided, they are used in some\n  special circumstances like iodata and chardata entities (see the `IO` module).\n\n  Due to their cons cell based representation, prepending an element\n  to a list is always fast (constant time), while appending becomes\n  slower as the list grows in size (linear time):\n\n      iex> list = [1, 2, 3]\n      iex> [0 | list] # fast\n      [0, 1, 2, 3]\n      iex> list ++ [4] # slow\n      [1, 2, 3, 4]\n\n  Most of the functions in this module work in linear time. This means that\n  the time it takes to perform an operation grows at the same rate as the\n  length of the list. For example `length/1` and `last/1` will run in linear\n  time because they need to iterate through every element of the list, but\n  `first/1` will run in constant time because it only needs the first element.\n\n  Lists also implement the `Enumerable` protocol, so many functions to work with\n  lists are found in the `Enum` module. Additionally, the following functions and\n  operators for lists are found in `Kernel`:\n\n    * `++/2`\n    * `--/2`\n    * `hd/1`\n    * `tl/1`\n    * `in/2`\n    * `length/1`\n\n  ## Charlists\n\n  If a list is made of non-negative integers, where each integer represents a\n  Unicode code point, the list can also be called a charlist. These integers\n  must:\n\n    * be within the range `0..0x10FFFF` (`0..1_114_111`);\n    * and be out of the range `0xD800..0xDFFF` (`55_296..57_343`), which is\n      reserved in Unicode for UTF-16 surrogate pairs.\n\n  Elixir uses the [`~c` sigil](`sigil_c/2`) to define charlists:\n\n      iex> ~c\"héllo\"\n      [104, 233, 108, 108, 111]\n\n  In particular, charlists will be printed back by default with the `~c`\n  sigil if they contain only printable ASCII characters:\n\n      iex> ~c\"abc\"\n      ~c\"abc\"\n\n  Even though the representation changed, the raw data does remain a list of\n  integers, which can be handled as such:\n\n      iex> inspect(~c\"abc\", charlists: :as_list)\n      \"[97, 98, 99]\"\n      iex> Enum.map(~c\"abc\", fn num -> 1000 + num end)\n      [1097, 1098, 1099]\n\n  You can use the `IEx.Helpers.i/1` helper to get a condensed rundown on\n  charlists in IEx when you encounter them, which shows you the type, description\n  and also the raw representation in one single summary.\n\n  The rationale behind this behavior is to better support\n  Erlang libraries which may return text as charlists\n  instead of Elixir strings. In Erlang, charlists are the default\n  way of handling strings, while in Elixir it's binaries. One\n  example of such functions is `Application.loaded_applications/0`:\n\n      Application.loaded_applications()\n      #=>  [\n      #=>    {:stdlib, ~c\"ERTS  CXC 138 10\", ~c\"2.6\"},\n      #=>    {:compiler, ~c\"ERTS  CXC 138 10\", ~c\"6.0.1\"},\n      #=>    {:elixir, ~c\"elixir\", ~c\"1.0.0\"},\n      #=>    {:kernel, ~c\"ERTS  CXC 138 10\", ~c\"4.1\"},\n      #=>    {:logger, ~c\"logger\", ~c\"1.0.0\"}\n      #=>  ]\n\n  A list can be checked if it is made of only printable ASCII\n  characters with `ascii_printable?/2`.\n\n  Improper lists are never deemed as charlists.\n  \"\"\"\n\n  @compile :inline_list_funcs\n\n  @doc \"\"\"\n  Deletes the given `element` from the `list`. Returns a new list without\n  the element.\n\n  If the `element` occurs more than once in the `list`, just\n  the first occurrence is removed.\n\n  ## Examples\n\n      iex> List.delete([:a, :b, :c], :a)\n      [:b, :c]\n\n      iex> List.delete([:a, :b, :c], :d)\n      [:a, :b, :c]\n\n      iex> List.delete([:a, :b, :b, :c], :b)\n      [:a, :b, :c]\n\n      iex> List.delete([], :b)\n      []\n\n  \"\"\"\n  @spec delete([], any) :: []\n  @spec delete([...], any) :: list\n  def delete(list, element)\n  def delete([element | list], element), do: list\n  def delete([other | list], element), do: [other | delete(list, element)]\n  def delete([], _element), do: []\n\n  @doc \"\"\"\n  Duplicates the given element `n` times in a list.\n\n  `n` is an integer greater than or equal to `0`.\n\n  If `n` is `0`, an empty list is returned.\n\n  ## Examples\n\n      iex> List.duplicate(\"hello\", 0)\n      []\n\n      iex> List.duplicate(\"hi\", 1)\n      [\"hi\"]\n\n      iex> List.duplicate(\"bye\", 2)\n      [\"bye\", \"bye\"]\n\n      iex> List.duplicate([1, 2], 3)\n      [[1, 2], [1, 2], [1, 2]]\n\n  \"\"\"\n  @spec duplicate(any, 0) :: []\n  @spec duplicate(elem, pos_integer) :: [elem, ...] when elem: var\n  def duplicate(elem, n) when is_integer(n) and n >= 0, do: duplicate(n, elem, [])\n\n  defp duplicate(0, _elem, acc), do: acc\n  defp duplicate(n, elem, acc), do: duplicate(n - 1, elem, [elem | acc])\n\n  @doc \"\"\"\n  Flattens the given `list` of nested lists.\n\n  Empty list elements are discarded.\n\n  ## Examples\n\n      iex> List.flatten([1, [[2], 3]])\n      [1, 2, 3]\n\n      iex> List.flatten([[], [[], []]])\n      []\n\n  \"\"\"\n  @spec flatten(deep_list) :: list when deep_list: [any | deep_list]\n  def flatten(list) do\n    :lists.flatten(list)\n  end\n\n  @doc \"\"\"\n  Flattens the given `list` of nested lists.\n  The list `tail` will be added at the end of\n  the flattened list.\n\n  Empty list elements from `list` are discarded,\n  but not the ones from `tail`.\n\n  ## Examples\n\n      iex> List.flatten([1, [[2], 3]], [4, 5])\n      [1, 2, 3, 4, 5]\n\n      iex> List.flatten([1, [], 2], [3, [], 4])\n      [1, 2, 3, [], 4]\n\n  \"\"\"\n  @spec flatten(deep_list, [elem]) :: [elem] when elem: var, deep_list: [elem | deep_list]\n  def flatten(list, tail) do\n    :lists.flatten(list, tail)\n  end\n\n  @doc \"\"\"\n  Folds (reduces) the given list from the left with\n  a function. Requires an accumulator, which can be any value.\n\n  ## Examples\n\n      iex> List.foldl([5, 5], 10, fn x, acc -> x + acc end)\n      20\n\n      iex> List.foldl([1, 2, 3, 4], 0, fn x, acc -> x - acc end)\n      2\n\n      iex> List.foldl([1, 2, 3], {0, 0}, fn x, {a1, a2} -> {a1 + x, a2 - x} end)\n      {6, -6}\n\n  \"\"\"\n  @spec foldl([elem], acc, (elem, acc -> acc)) :: acc when elem: var, acc: var\n  def foldl(list, acc, fun) when is_list(list) and is_function(fun) do\n    :lists.foldl(fun, acc, list)\n  end\n\n  @doc \"\"\"\n  Folds (reduces) the given list from the right with\n  a function. Requires an accumulator, which can be any value.\n\n  ## Examples\n\n      iex> List.foldr([1, 2, 3, 4], 0, fn x, acc -> x - acc end)\n      -2\n\n      iex> List.foldr([1, 2, 3, 4], %{sum: 0, product: 1}, fn x, %{sum: a1, product: a2} -> %{sum: a1 + x, product: a2 * x} end)\n      %{product: 24, sum: 10}\n\n  \"\"\"\n  @spec foldr([elem], acc, (elem, acc -> acc)) :: acc when elem: var, acc: var\n  def foldr(list, acc, fun) when is_list(list) and is_function(fun) do\n    :lists.foldr(fun, acc, list)\n  end\n\n  @doc \"\"\"\n  Returns the first element in `list` or `default` if `list` is empty.\n\n  `first/2` has been introduced in Elixir v1.12.0, while `first/1` has been available since v1.0.0.\n\n  ## Examples\n\n      iex> List.first([])\n      nil\n\n      iex> List.first([], 1)\n      1\n\n      iex> List.first([1])\n      1\n\n      iex> List.first([1, 2, 3])\n      1\n\n  \"\"\"\n  @spec first([], any) :: any\n  @spec first([elem, ...], any) :: elem when elem: var\n  def first(list, default \\\\ nil)\n  def first([], default), do: default\n  def first([head | _], _default), do: head\n\n  @doc \"\"\"\n  Returns the first element in `list`.\n\n  If `list` is empty, an error is raised.\n\n  ## Examples\n\n      iex> List.first!([1])\n      1\n\n      iex> List.first!([1, 2, 3])\n      1\n\n      iex> List.first!([])\n      ** (ArgumentError) attempted to get the first element of an empty list\n\n  \"\"\"\n  @doc since: \"1.20.0\"\n  @spec first!([elem, ...]) :: elem when elem: var\n  def first!(list)\n\n  def first!([head | _]), do: head\n\n  def first!([]) do\n    raise ArgumentError, \"attempted to get the first element of an empty list\"\n  end\n\n  @doc \"\"\"\n  Returns the last element in `list` or `default` if `list` is empty.\n\n  `last/2` has been introduced in Elixir v1.12.0, while `last/1` has been available since v1.0.0.\n\n  ## Examples\n\n      iex> List.last([])\n      nil\n\n      iex> List.last([], 1)\n      1\n\n      iex> List.last([1])\n      1\n\n      iex> List.last([1, 2, 3])\n      3\n\n  \"\"\"\n  @spec last([], any) :: any\n  @spec last([elem, ...], any) :: elem when elem: var\n  @compile {:inline, last: 2}\n  def last(list, default \\\\ nil)\n  def last([], default), do: default\n  def last([head], _default), do: head\n  def last([_ | tail], default), do: last(tail, default)\n\n  @doc \"\"\"\n  Returns the last element in `list`.\n\n  If `list` is empty, an error is raised.\n\n  ## Examples\n\n      iex> List.last!([1])\n      1\n\n      iex> List.last!([1, 2, 3])\n      3\n\n      iex> List.last!([])\n      ** (ArgumentError) attempted to get the last element of an empty list\n\n  \"\"\"\n  @doc since: \"1.20.0\"\n  @spec last!([elem, ...]) :: elem when elem: var\n  def last!(list)\n\n  def last!([head]), do: head\n  def last!([_ | tail]), do: last!(tail)\n\n  def last!([]) do\n    raise ArgumentError, \"attempted to get the last element of an empty list\"\n  end\n\n  @doc \"\"\"\n  Receives a list of tuples and returns the first tuple\n  where the element at `position` in the tuple matches the\n  given `key`.\n\n  If no matching tuple is found, `default` is returned.\n\n  ## Examples\n\n      iex> List.keyfind([a: 1, b: 2], :a, 0)\n      {:a, 1}\n\n      iex> List.keyfind([a: 1, b: 2], 2, 1)\n      {:b, 2}\n\n      iex> List.keyfind([a: 1, b: 2], :c, 0)\n      nil\n\n  This function works for any list of tuples:\n\n      iex> List.keyfind([{22, \"SSH\"}, {80, \"HTTP\"}], 22, 0)\n      {22, \"SSH\"}\n\n  \"\"\"\n  @spec keyfind([tuple], any, non_neg_integer, any) :: any\n  def keyfind(list, key, position, default \\\\ nil) when is_integer(position) do\n    :lists.keyfind(key, position + 1, list) || default\n  end\n\n  @doc \"\"\"\n  Receives a list of tuples and returns the first tuple\n  where the element at `position` in the tuple matches the\n  given `key`.\n\n  If no matching tuple is found, an error is raised.\n\n  ## Examples\n\n      iex> List.keyfind!([a: 1, b: 2], :a, 0)\n      {:a, 1}\n\n      iex> List.keyfind!([a: 1, b: 2], 2, 1)\n      {:b, 2}\n\n      iex> List.keyfind!([a: 1, b: 2], :c, 0)\n      ** (KeyError) key :c at position 0 not found in: [a: 1, b: 2]\n\n  This function works for any list of tuples:\n\n      iex> List.keyfind!([{22, \"SSH\"}, {80, \"HTTP\"}], 22, 0)\n      {22, \"SSH\"}\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec keyfind!([tuple], any, non_neg_integer) :: any\n  def keyfind!(list, key, position) when is_integer(position) do\n    :lists.keyfind(key, position + 1, list) ||\n      raise KeyError,\n        key: key,\n        term: list,\n        message:\n          \"key #{inspect(key)} at position #{inspect(position)} not found in: #{inspect(list)}\"\n  end\n\n  @doc \"\"\"\n  Receives a list of tuples and returns `true` if there is\n  a tuple where the element at `position` in the tuple matches\n  the given `key`.\n\n  ## Examples\n\n      iex> List.keymember?([a: 1, b: 2], :a, 0)\n      true\n\n      iex> List.keymember?([a: 1, b: 2], 2, 1)\n      true\n\n      iex> List.keymember?([a: 1, b: 2], :c, 0)\n      false\n\n  This function works for any list of tuples:\n\n      iex> List.keymember?([{22, \"SSH\"}, {80, \"HTTP\"}], 22, 0)\n      true\n\n  \"\"\"\n  @spec keymember?([tuple], any, non_neg_integer) :: boolean\n  def keymember?(list, key, position) when is_integer(position) do\n    :lists.keymember(key, position + 1, list)\n  end\n\n  @doc \"\"\"\n  Receives a list of tuples and if the identified element by `key` at `position`\n  exists, it is replaced with `new_tuple`.\n\n  ## Examples\n\n      iex> List.keyreplace([a: 1, b: 2], :a, 0, {:a, 3})\n      [a: 3, b: 2]\n\n      iex> List.keyreplace([a: 1, b: 2], :a, 1, {:a, 3})\n      [a: 1, b: 2]\n\n  This function works for any list of tuples:\n\n      iex> List.keyreplace([{22, \"SSH\"}, {80, \"HTTP\"}], 22, 0, {22, \"Secure Shell\"})\n      [{22, \"Secure Shell\"}, {80, \"HTTP\"}]\n\n  \"\"\"\n  @spec keyreplace([tuple], any, non_neg_integer, tuple) :: [tuple]\n  def keyreplace(list, key, position, new_tuple) when is_integer(position) do\n    :lists.keyreplace(key, position + 1, list, new_tuple)\n  end\n\n  @doc \"\"\"\n  Receives a list of tuples and sorts the elements\n  at `position` of the tuples.\n\n  The sort is stable.\n\n  A `sorter` argument is available since Elixir v1.14.0. Similar to\n  `Enum.sort/2`, the sorter can be an anonymous function, the atoms\n  `:asc` or `:desc`, or module that implements a compare function.\n\n  ## Examples\n\n      iex> List.keysort([a: 5, b: 1, c: 3], 1)\n      [b: 1, c: 3, a: 5]\n\n      iex> List.keysort([a: 5, c: 1, b: 3], 0)\n      [a: 5, b: 3, c: 1]\n\n  To sort in descending order:\n\n      iex> List.keysort([a: 5, c: 1, b: 3], 0, :desc)\n      [c: 1, b: 3, a: 5]\n\n  As in `Enum.sort/2`, avoid using the default sorting function to sort\n  structs, as by default it performs structural comparison instead of a\n  semantic one. In such cases, you shall pass a sorting function as third\n  element or any module that implements a `compare/2` function. For example,\n  if you have tuples with user names and their birthday, and you want to\n  sort on their birthday, in both ascending and descending order, you should\n  do:\n\n      iex> users = [\n      ...>   {\"Ellis\", ~D[1943-05-11]},\n      ...>   {\"Lovelace\", ~D[1815-12-10]},\n      ...>   {\"Turing\", ~D[1912-06-23]}\n      ...> ]\n      iex> List.keysort(users, 1, Date)\n      [\n        {\"Lovelace\", ~D[1815-12-10]},\n        {\"Turing\", ~D[1912-06-23]},\n        {\"Ellis\", ~D[1943-05-11]}\n      ]\n      iex> List.keysort(users, 1, {:desc, Date})\n      [\n        {\"Ellis\", ~D[1943-05-11]},\n        {\"Turing\", ~D[1912-06-23]},\n        {\"Lovelace\", ~D[1815-12-10]}\n      ]\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec keysort(\n          [tuple],\n          non_neg_integer,\n          (any, any -> boolean) | :asc | :desc | module() | {:asc | :desc, module()}\n        ) :: [tuple]\n  def keysort(list, position, sorter \\\\ :asc)\n\n  def keysort(list, position, :asc) when is_list(list) and is_integer(position) do\n    :lists.keysort(position + 1, list)\n  end\n\n  def keysort(list, position, sorter) when is_list(list) and is_integer(position) do\n    :lists.sort(keysort_fun(sorter, position + 1), list)\n  end\n\n  defp keysort_fun(sorter, position) when is_function(sorter, 2),\n    do: &sorter.(:erlang.element(position, &1), :erlang.element(position, &2))\n\n  defp keysort_fun(:desc, position),\n    do: &(:erlang.element(position, &1) >= :erlang.element(position, &2))\n\n  defp keysort_fun(module, position) when is_atom(module),\n    do: &(module.compare(:erlang.element(position, &1), :erlang.element(position, &2)) != :gt)\n\n  defp keysort_fun({:asc, module}, position) when is_atom(module),\n    do: &(module.compare(:erlang.element(position, &1), :erlang.element(position, &2)) != :gt)\n\n  defp keysort_fun({:desc, module}, position) when is_atom(module),\n    do: &(module.compare(:erlang.element(position, &1), :erlang.element(position, &2)) != :lt)\n\n  @doc \"\"\"\n  Receives a `list` of tuples and replaces the element\n  identified by `key` at `position` with `new_tuple`.\n\n  If the element does not exist, it is added to the end of the `list`.\n\n  ## Examples\n\n      iex> List.keystore([a: 1, b: 2], :a, 0, {:a, 3})\n      [a: 3, b: 2]\n\n      iex> List.keystore([a: 1, b: 2], :c, 0, {:c, 3})\n      [a: 1, b: 2, c: 3]\n\n  This function works for any list of tuples:\n\n      iex> List.keystore([{22, \"SSH\"}], 80, 0, {80, \"HTTP\"})\n      [{22, \"SSH\"}, {80, \"HTTP\"}]\n\n  \"\"\"\n  @spec keystore([tuple], any, non_neg_integer, tuple) :: [tuple, ...]\n  def keystore(list, key, position, new_tuple) when is_integer(position) do\n    :lists.keystore(key, position + 1, list, new_tuple)\n  end\n\n  @doc \"\"\"\n  Receives a `list` of tuples and deletes the first tuple\n  where the element at `position` matches the\n  given `key`. Returns the new list.\n\n  ## Examples\n\n      iex> List.keydelete([a: 1, b: 2], :a, 0)\n      [b: 2]\n\n      iex> List.keydelete([a: 1, b: 2], 2, 1)\n      [a: 1]\n\n      iex> List.keydelete([a: 1, b: 2], :c, 0)\n      [a: 1, b: 2]\n\n  This function works for any list of tuples:\n\n      iex> List.keydelete([{22, \"SSH\"}, {80, \"HTTP\"}], 80, 0)\n      [{22, \"SSH\"}]\n\n  \"\"\"\n  @spec keydelete([tuple], any, non_neg_integer) :: [tuple]\n  def keydelete(list, key, position) when is_integer(position) do\n    :lists.keydelete(key, position + 1, list)\n  end\n\n  @doc \"\"\"\n  Receives a `list` of tuples and returns the first tuple\n  where the element at `position` in the tuple matches the\n  given `key`, as well as the `list` without found tuple.\n\n  If such a tuple is not found, `nil` will be returned.\n\n  ## Examples\n\n      iex> List.keytake([a: 1, b: 2], :a, 0)\n      {{:a, 1}, [b: 2]}\n\n      iex> List.keytake([a: 1, b: 2], 2, 1)\n      {{:b, 2}, [a: 1]}\n\n      iex> List.keytake([a: 1, b: 2], :c, 0)\n      nil\n\n  This function works for any list of tuples:\n\n      iex> List.keytake([{22, \"SSH\"}, {80, \"HTTP\"}], 80, 0)\n      {{80, \"HTTP\"}, [{22, \"SSH\"}]}\n\n  \"\"\"\n  @spec keytake([tuple], any, non_neg_integer) :: {tuple, [tuple]} | nil\n  def keytake(list, key, position) when is_integer(position) do\n    case :lists.keytake(key, position + 1, list) do\n      {:value, element, list} -> {element, list}\n      false -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Wraps `term` in a list if this is not list.\n\n  If `term` is already a list, it returns the list.\n  If `term` is `nil`, it returns an empty list.\n\n  ## Examples\n\n      iex> List.wrap(\"hello\")\n      [\"hello\"]\n\n      iex> List.wrap([1, 2, 3])\n      [1, 2, 3]\n\n      iex> List.wrap(nil)\n      []\n\n  \"\"\"\n  @spec wrap(term) :: maybe_improper_list()\n  def wrap(term)\n\n  def wrap(list) when is_list(list) do\n    list\n  end\n\n  def wrap(nil) do\n    []\n  end\n\n  def wrap(other) do\n    [other]\n  end\n\n  @deprecated \"Use Enum.zip/1 instead\"\n  # We keep the old implementation because it also supported lists\n  # of tuples, even though this was not included in its @spec.\n  def zip([]), do: []\n  def zip(list_of_lists) when is_list(list_of_lists), do: do_zip(list_of_lists, [])\n\n  defp do_zip(list, acc) do\n    converter = fn x, acc -> do_zip_each(to_list(x), acc) end\n\n    case :lists.mapfoldl(converter, [], list) do\n      {_, nil} ->\n        :lists.reverse(acc)\n\n      {mlist, heads} ->\n        do_zip(mlist, [to_tuple(:lists.reverse(heads)) | acc])\n    end\n  end\n\n  defp do_zip_each(_, nil) do\n    {nil, nil}\n  end\n\n  defp do_zip_each([head | tail], acc) do\n    {tail, [head | acc]}\n  end\n\n  defp do_zip_each([], _) do\n    {nil, nil}\n  end\n\n  defp to_list(tuple) when is_tuple(tuple), do: Tuple.to_list(tuple)\n  defp to_list(list) when is_list(list), do: list\n\n  @doc ~S\"\"\"\n  Checks if `list` is a charlist made only of printable ASCII characters.\n\n  Takes an optional `limit` as a second argument. `ascii_printable?/2` only\n  checks the printability of the list up to the `limit`.\n\n  A printable charlist in Elixir contains only the printable characters in the\n  standard seven-bit ASCII character encoding, which are characters ranging from\n  32 to 126 in decimal notation, plus the following control characters:\n\n    * `?\\a` - Bell\n    * `?\\b` - Backspace\n    * `?\\t` - Horizontal tab\n    * `?\\n` - Line feed\n    * `?\\v` - Vertical tab\n    * `?\\f` - Form feed\n    * `?\\r` - Carriage return\n    * `?\\e` - Escape\n\n  For more information read the [Character groups](https://en.wikipedia.org/wiki/ASCII#Character_groups)\n  section in the Wikipedia article of the [ASCII](https://en.wikipedia.org/wiki/ASCII) standard.\n\n  ## Examples\n\n      iex> List.ascii_printable?(~c\"abc\")\n      true\n\n      iex> List.ascii_printable?(~c\"abc\" ++ [0])\n      false\n\n      iex> List.ascii_printable?(~c\"abc\" ++ [0], 2)\n      true\n\n  Improper lists are not printable, even if made only of ASCII characters:\n\n      iex> List.ascii_printable?(~c\"abc\" ++ ?d)\n      false\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec ascii_printable?(list, 0) :: true\n  @spec ascii_printable?([], limit) :: true\n        when limit: :infinity | pos_integer\n  @spec ascii_printable?([...], limit) :: boolean\n        when limit: :infinity | pos_integer\n  def ascii_printable?(list, limit \\\\ :infinity)\n      when is_list(list) and (limit == :infinity or (is_integer(limit) and limit >= 0)) do\n    ascii_printable_guarded?(list, limit)\n  end\n\n  defp ascii_printable_guarded?(_, 0) do\n    true\n  end\n\n  defp ascii_printable_guarded?([char | rest], counter)\n       # 7..13 is the range '\\a\\b\\t\\n\\v\\f\\r'. 32..126 are ASCII printables.\n       when is_integer(char) and\n              ((char >= 7 and char <= 13) or char == ?\\e or (char >= 32 and char <= 126)) do\n    ascii_printable_guarded?(rest, decrement(counter))\n  end\n\n  defp ascii_printable_guarded?([], _counter), do: true\n  defp ascii_printable_guarded?(_, _counter), do: false\n\n  @compile {:inline, decrement: 1}\n  defp decrement(:infinity), do: :infinity\n  defp decrement(counter), do: counter - 1\n\n  @doc \"\"\"\n  Returns `true` if `list` is an improper list. Otherwise returns `false`.\n\n  ## Examples\n\n      iex> List.improper?([1, 2 | 3])\n      true\n\n      iex> List.improper?([1, 2, 3])\n      false\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec improper?(maybe_improper_list) :: boolean\n  def improper?(list) when is_list(list) and length(list) >= 0, do: false\n  def improper?(list) when is_list(list), do: true\n\n  @doc \"\"\"\n  Returns a list with `value` inserted at the specified `index`.\n\n  Note that `index` is capped at the list length. Negative indices\n  indicate an offset from the end of the `list`.\n\n  ## Examples\n\n      iex> List.insert_at([1, 2, 3, 4], 2, 0)\n      [1, 2, 0, 3, 4]\n\n      iex> List.insert_at([1, 2, 3], 10, 0)\n      [1, 2, 3, 0]\n\n      iex> List.insert_at([1, 2, 3], -1, 0)\n      [1, 2, 3, 0]\n\n      iex> List.insert_at([1, 2, 3], -10, 0)\n      [0, 1, 2, 3]\n\n  \"\"\"\n  @spec insert_at(list, integer, any) :: list\n  def insert_at(list, index, value) when is_list(list) and is_integer(index) do\n    case index do\n      -1 ->\n        list ++ [value]\n\n      _ when index < 0 ->\n        case length(list) + index + 1 do\n          index when index < 0 -> [value | list]\n          index -> do_insert_at(list, index, value)\n        end\n\n      _ ->\n        do_insert_at(list, index, value)\n    end\n  end\n\n  @doc \"\"\"\n  Returns a list with a replaced value at the specified `index`.\n\n  Negative indices indicate an offset from the end of the `list`.\n  If `index` is out of bounds, the original `list` is returned.\n\n  ## Examples\n\n      iex> List.replace_at([1, 2, 3], 0, 0)\n      [0, 2, 3]\n\n      iex> List.replace_at([1, 2, 3], 10, 0)\n      [1, 2, 3]\n\n      iex> List.replace_at([1, 2, 3], -1, 0)\n      [1, 2, 0]\n\n      iex> List.replace_at([1, 2, 3], -10, 0)\n      [1, 2, 3]\n\n  \"\"\"\n  @spec replace_at(list, integer, any) :: list\n  def replace_at(list, index, value) when is_list(list) and is_integer(index) do\n    if index < 0 do\n      case length(list) + index do\n        index when index < 0 -> list\n        index -> do_replace_at(list, index, value)\n      end\n    else\n      do_replace_at(list, index, value)\n    end\n  end\n\n  @doc \"\"\"\n  Returns a list with an updated value at the specified `index`.\n\n  Negative indices indicate an offset from the end of the `list`.\n  If `index` is out of bounds, the original `list` is returned.\n\n  ## Examples\n\n      iex> List.update_at([1, 2, 3], 0, &(&1 + 10))\n      [11, 2, 3]\n\n      iex> List.update_at([1, 2, 3], 10, &(&1 + 10))\n      [1, 2, 3]\n\n      iex> List.update_at([1, 2, 3], -1, &(&1 + 10))\n      [1, 2, 13]\n\n      iex> List.update_at([1, 2, 3], -10, &(&1 + 10))\n      [1, 2, 3]\n\n  \"\"\"\n  @spec update_at([elem], integer, (elem -> any)) :: list when elem: var\n  def update_at(list, index, fun) when is_list(list) and is_function(fun) and is_integer(index) do\n    if index < 0 do\n      case length(list) + index do\n        index when index < 0 -> list\n        index -> do_update_at(list, index, fun)\n      end\n    else\n      do_update_at(list, index, fun)\n    end\n  end\n\n  @doc \"\"\"\n  Produces a new list by removing the value at the specified `index`.\n\n  Negative indices indicate an offset from the end of the `list`.\n  If `index` is out of bounds, the original `list` is returned.\n\n  ## Examples\n\n      iex> List.delete_at([1, 2, 3], 0)\n      [2, 3]\n\n      iex> List.delete_at([1, 2, 3], 10)\n      [1, 2, 3]\n\n      iex> List.delete_at([1, 2, 3], -1)\n      [1, 2]\n\n  \"\"\"\n  @spec delete_at(list, integer) :: list\n  def delete_at(list, index) when is_integer(index) do\n    elem(pop_at(list, index), 1)\n  end\n\n  @doc \"\"\"\n  Returns and removes the value at the specified `index` in the `list`.\n\n  Negative indices indicate an offset from the end of the `list`.\n  If `index` is out of bounds, the original `list` is returned.\n\n  ## Examples\n\n      iex> List.pop_at([1, 2, 3], 0)\n      {1, [2, 3]}\n      iex> List.pop_at([1, 2, 3], 5)\n      {nil, [1, 2, 3]}\n      iex> List.pop_at([1, 2, 3], 5, 10)\n      {10, [1, 2, 3]}\n      iex> List.pop_at([1, 2, 3], -1)\n      {3, [1, 2]}\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec pop_at(list, integer, any) :: {any, list}\n  def pop_at(list, index, default \\\\ nil) when is_integer(index) do\n    if index < 0 do\n      do_pop_at(list, length(list) + index, default, [])\n    else\n      do_pop_at(list, index, default, [])\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if `list` starts with the given `prefix` list, otherwise returns `false`.\n\n  If `prefix` is an empty list, it returns `true`.\n\n  ## Examples\n\n      iex> List.starts_with?([1, 2, 3], [1, 2])\n      true\n\n      iex> List.starts_with?([1, 2], [1, 2, 3])\n      false\n\n      iex> List.starts_with?([:alpha], [])\n      true\n\n      iex> List.starts_with?([], [:alpha])\n      false\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec starts_with?(nonempty_list, nonempty_list) :: boolean\n  @spec starts_with?(list, []) :: true\n  @spec starts_with?([], nonempty_list) :: false\n  def starts_with?(list, prefix)\n\n  def starts_with?([head | tail], [head | prefix_tail]), do: starts_with?(tail, prefix_tail)\n  def starts_with?(list, []) when is_list(list), do: true\n  def starts_with?(list, [_ | _]) when is_list(list), do: false\n\n  @doc \"\"\"\n  Returns `true` if `list` ends with the given `suffix` list, otherwise returns `false`.\n\n  If `suffix` is an empty list, it returns `true`.\n\n  ## Examples\n\n      iex> List.ends_with?([1, 2, 3], [2, 3])\n      true\n\n      iex> List.ends_with?([1, 2], [1, 2, 3])\n      false\n\n      iex> List.ends_with?([:alpha], [])\n      true\n\n      iex> List.ends_with?([], [:alpha])\n      false\n\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec ends_with?(nonempty_list, nonempty_list) :: boolean\n  @spec ends_with?(list, []) :: true\n  @spec ends_with?([], nonempty_list) :: false\n  def ends_with?(list, suffix) do\n    :lists.suffix(suffix, list)\n  end\n\n  @doc \"\"\"\n  Converts a charlist to an atom.\n\n  Elixir supports conversions from charlists which contain any Unicode\n  code point.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> List.to_atom(~c\"Elixir\")\n      :Elixir\n\n      iex> List.to_atom(~c\"🌢 Elixir\")\n      :\"🌢 Elixir\"\n\n  \"\"\"\n  @spec to_atom(charlist) :: atom\n  def to_atom(charlist) do\n    :erlang.list_to_atom(charlist)\n  end\n\n  @doc \"\"\"\n  Converts a charlist to an existing atom.\n\n  Elixir supports conversions from charlists which contain any Unicode\n  code point. Raises an `ArgumentError` if the atom does not exist.\n\n  Inlined by the compiler.\n\n  > #### Atoms and modules {: .info}\n  >\n  > Since Elixir is a compiled language, the atoms defined in a module\n  > will only exist after said module is loaded, which typically happens\n  > whenever a function in the module is executed. Therefore, it is\n  > generally recommended to call `List.to_existing_atom/1` only to\n  > convert atoms defined within the module making the function call\n  > to `to_existing_atom/1`.\n\n  ## Examples\n\n      iex> _ = :my_atom\n      iex> List.to_existing_atom(~c\"my_atom\")\n      :my_atom\n\n      iex> _ = :\"🌢 Elixir\"\n      iex> List.to_existing_atom(~c\"🌢 Elixir\")\n      :\"🌢 Elixir\"\n\n  \"\"\"\n  @spec to_existing_atom(charlist) :: atom\n  def to_existing_atom(charlist) do\n    :erlang.list_to_existing_atom(charlist)\n  end\n\n  @doc \"\"\"\n  Returns the float whose text representation is `charlist`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> List.to_float(~c\"2.2017764e+0\")\n      2.2017764\n\n  \"\"\"\n  @spec to_float(charlist) :: float\n  def to_float(charlist) do\n    :erlang.list_to_float(charlist)\n  end\n\n  @doc \"\"\"\n  Returns an integer whose text representation is `charlist`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> List.to_integer(~c\"123\")\n      123\n\n  \"\"\"\n  @spec to_integer(charlist) :: integer\n  def to_integer(charlist) do\n    :erlang.list_to_integer(charlist)\n  end\n\n  @doc \"\"\"\n  Returns an integer whose text representation is `charlist` in base `base`.\n\n  Inlined by the compiler.\n\n  The base needs to be between `2` and `36`.\n\n  ## Examples\n\n      iex> List.to_integer(~c\"3FF\", 16)\n      1023\n\n  \"\"\"\n  @spec to_integer(charlist, 2..36) :: integer\n  def to_integer(charlist, base) do\n    :erlang.list_to_integer(charlist, base)\n  end\n\n  @doc \"\"\"\n  Converts a list to a tuple.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> List.to_tuple([:share, [:elixir, 163]])\n      {:share, [:elixir, 163]}\n\n  \"\"\"\n  @spec to_tuple(list) :: tuple\n  def to_tuple(list) do\n    :erlang.list_to_tuple(list)\n  end\n\n  @doc \"\"\"\n  Converts a list of integers representing code points, lists or\n  strings into a string.\n\n  To be converted to a string, a list must either be empty or only\n  contain the following elements:\n\n    * strings\n    * integers representing Unicode code points\n    * a list containing one of these three elements\n\n  Note that this function expects a list of integers representing\n  Unicode code points. If you have a list of bytes, you must instead use\n  the [`:binary` module](`:binary`).\n\n  ## Examples\n\n      iex> List.to_string([0x00E6, 0x00DF])\n      \"æß\"\n\n      iex> List.to_string([0x0061, \"bc\"])\n      \"abc\"\n\n      iex> List.to_string([0x0064, \"ee\", [~c\"p\"]])\n      \"deep\"\n\n      iex> List.to_string([])\n      \"\"\n\n  \"\"\"\n  @spec to_string(:unicode.charlist()) :: String.t()\n  def to_string(list) when is_list(list) do\n    try do\n      :unicode.characters_to_binary(list)\n    rescue\n      ArgumentError ->\n        raise ArgumentError, \"\"\"\n        cannot convert the given list to a string.\n\n        To be converted to a string, a list must either be empty or only\n        contain the following elements:\n\n          * strings\n          * integers representing Unicode code points\n          * a list containing one of these three elements\n\n        Please check the given list or call inspect/1 to get the list representation, got:\n\n        #{inspect(list)}\n        \"\"\"\n    else\n      result when is_binary(result) ->\n        result\n\n      {:error, encoded, rest} ->\n        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :invalid\n\n      {:incomplete, encoded, rest} ->\n        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :incomplete\n    end\n  end\n\n  @doc \"\"\"\n  Converts a list of integers representing Unicode code points, lists or\n  strings into a charlist.\n\n  Note that this function expects a list of integers representing\n  Unicode code points. If you have a list of bytes, you must instead use\n  the [`:binary` module](`:binary`).\n\n  ## Examples\n\n      iex> ~c\"æß\" = List.to_charlist([0x00E6, 0x00DF])\n      [230, 223]\n\n      iex> List.to_charlist([0x0061, \"bc\"])\n      ~c\"abc\"\n\n      iex> List.to_charlist([0x0064, \"ee\", [~c\"p\"]])\n      ~c\"deep\"\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec to_charlist(:unicode.charlist()) :: charlist()\n  def to_charlist(list) when is_list(list) do\n    try do\n      :unicode.characters_to_list(list)\n    rescue\n      ArgumentError ->\n        raise ArgumentError, \"\"\"\n        cannot convert the given list to a charlist.\n\n        To be converted to a charlist, a list must contain only:\n\n          * strings\n          * integers representing Unicode code points\n          * or a list containing one of these three elements\n\n        Please check the given list or call inspect/1 to get the list representation, got:\n\n        #{inspect(list)}\n        \"\"\"\n    else\n      result when is_list(result) ->\n        result\n\n      {:error, encoded, rest} ->\n        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :invalid\n\n      {:incomplete, encoded, rest} ->\n        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :incomplete\n    end\n  end\n\n  @doc \"\"\"\n  Returns a keyword list that represents an *edit script*.\n\n  The algorithm is outlined in the\n  \"An O(ND) Difference Algorithm and Its Variations\" paper by E. Myers.\n\n  An *edit script* is a keyword list. Each key describes the \"editing action\" to\n  take in order to bring `list1` closer to being equal to `list2`; a key can be\n  `:eq`, `:ins`, or `:del`. Each value is a sublist of either `list1` or `list2`\n  that should be inserted (if the corresponding key is `:ins`), deleted (if the\n  corresponding key is `:del`), or left alone (if the corresponding key is\n  `:eq`) in `list1` in order to be closer to `list2`.\n\n  See `myers_difference/3` if you want to handle nesting in the diff scripts.\n\n  ## Examples\n\n      iex> List.myers_difference([1, 4, 2, 3], [1, 2, 3, 4])\n      [eq: [1], del: [4], eq: [2, 3], ins: [4]]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec myers_difference(list, list) :: [{:eq | :ins | :del, list}]\n  def myers_difference(list1, list2) when is_list(list1) and is_list(list2) do\n    myers_difference_with_diff_script(list1, list2, nil)\n  end\n\n  @doc \"\"\"\n  Returns a keyword list that represents an *edit script* with nested diffs.\n\n  This is an extension of `myers_difference/2` where a `diff_script` function\n  can be given in case it is desired to compute nested differences. The function\n  may return a list with the inner edit script or `nil` in case there is no\n  such script. The returned inner edit script will be under the `:diff` key.\n\n  ## Examples\n\n      iex> List.myers_difference([\"a\", \"db\", \"c\"], [\"a\", \"bc\"], &String.myers_difference/2)\n      [eq: [\"a\"], diff: [del: \"d\", eq: \"b\", ins: \"c\"], del: [\"c\"]]\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec myers_difference(list, list, (term, term -> script | nil)) :: script\n        when script: [{:eq | :ins | :del | :diff, list}]\n  def myers_difference(list1, list2, diff_script)\n      when is_list(list1) and is_list(list2) and is_function(diff_script) do\n    myers_difference_with_diff_script(list1, list2, diff_script)\n  end\n\n  defp myers_difference_with_diff_script(list1, list2, diff_script) do\n    path = {0, list1, list2, []}\n    find_script(0, length(list1) + length(list2), [path], diff_script)\n  end\n\n  defp find_script(envelope, max, paths, diff_script) do\n    case each_diagonal(-envelope, envelope, paths, [], diff_script) do\n      {:done, edits} -> compact_reverse(edits, [])\n      {:next, paths} -> find_script(envelope + 1, max, paths, diff_script)\n    end\n  end\n\n  defp compact_reverse([], acc), do: acc\n\n  defp compact_reverse([{:diff, _} = fragment | rest], acc) do\n    compact_reverse(rest, [fragment | acc])\n  end\n\n  defp compact_reverse([{kind, elem} | rest], [{kind, result} | acc]) do\n    compact_reverse(rest, [{kind, [elem | result]} | acc])\n  end\n\n  defp compact_reverse(rest, [{:eq, elem}, {:ins, elem}, {:eq, other} | acc]) do\n    compact_reverse(rest, [{:ins, elem}, {:eq, elem ++ other} | acc])\n  end\n\n  defp compact_reverse([{kind, elem} | rest], acc) do\n    compact_reverse(rest, [{kind, [elem]} | acc])\n  end\n\n  defp each_diagonal(diag, limit, _paths, next_paths, _diff_script) when diag > limit do\n    {:next, :lists.reverse(next_paths)}\n  end\n\n  defp each_diagonal(diag, limit, paths, next_paths, diff_script) do\n    {path, rest} = proceed_path(diag, limit, paths, diff_script)\n\n    case follow_snake(path) do\n      {:cont, path} -> each_diagonal(diag + 2, limit, rest, [path | next_paths], diff_script)\n      {:done, edits} -> {:done, edits}\n    end\n  end\n\n  defp proceed_path(0, 0, [path], _diff_script), do: {path, []}\n\n  defp proceed_path(diag, limit, [path | _] = paths, diff_script) when diag == -limit do\n    {move_down(path, diff_script), paths}\n  end\n\n  defp proceed_path(diag, limit, [path], diff_script) when diag == limit do\n    {move_right(path, diff_script), []}\n  end\n\n  defp proceed_path(_diag, _limit, [path1, path2 | rest], diff_script) do\n    if elem(path1, 0) > elem(path2, 0) do\n      {move_right(path1, diff_script), [path2 | rest]}\n    else\n      {move_down(path2, diff_script), [path2 | rest]}\n    end\n  end\n\n  defp move_right({y, [elem1 | rest1] = list1, [elem2 | rest2], edits}, diff_script)\n       when diff_script != nil do\n    if diff = diff_script.(elem1, elem2) do\n      {y + 1, rest1, rest2, [{:diff, diff} | edits]}\n    else\n      {y, list1, rest2, [{:ins, elem2} | edits]}\n    end\n  end\n\n  defp move_right({y, list1, [elem | rest], edits}, _diff_script) do\n    {y, list1, rest, [{:ins, elem} | edits]}\n  end\n\n  defp move_right({y, list1, [], edits}, _diff_script) do\n    {y, list1, [], edits}\n  end\n\n  defp move_down({y, [elem1 | rest1], [elem2 | rest2] = list2, edits}, diff_script)\n       when diff_script != nil do\n    if diff = diff_script.(elem1, elem2) do\n      {y + 1, rest1, rest2, [{:diff, diff} | edits]}\n    else\n      {y + 1, rest1, list2, [{:del, elem1} | edits]}\n    end\n  end\n\n  defp move_down({y, [elem | rest], list2, edits}, _diff_script) do\n    {y + 1, rest, list2, [{:del, elem} | edits]}\n  end\n\n  defp move_down({y, [], list2, edits}, _diff_script) do\n    {y + 1, [], list2, edits}\n  end\n\n  defp follow_snake({y, [elem | rest1], [elem | rest2], edits}) do\n    follow_snake({y + 1, rest1, rest2, [{:eq, elem} | edits]})\n  end\n\n  defp follow_snake({_y, [], [], edits}) do\n    {:done, edits}\n  end\n\n  defp follow_snake(path) do\n    {:cont, path}\n  end\n\n  ## Helpers\n\n  # replace_at\n\n  defp do_replace_at([], _index, _value) do\n    []\n  end\n\n  defp do_replace_at([_old | rest], 0, value) do\n    [value | rest]\n  end\n\n  defp do_replace_at([head | tail], index, value) do\n    [head | do_replace_at(tail, index - 1, value)]\n  end\n\n  # insert_at\n\n  defp do_insert_at([], _index, value) do\n    [value]\n  end\n\n  defp do_insert_at(list, 0, value) do\n    [value | list]\n  end\n\n  defp do_insert_at([head | tail], index, value) do\n    [head | do_insert_at(tail, index - 1, value)]\n  end\n\n  # update_at\n\n  defp do_update_at([value | list], 0, fun) do\n    [fun.(value) | list]\n  end\n\n  defp do_update_at([head | tail], index, fun) do\n    [head | do_update_at(tail, index - 1, fun)]\n  end\n\n  defp do_update_at([], _index, _fun) do\n    []\n  end\n\n  # pop_at\n\n  defp do_pop_at([], _index, default, acc) do\n    {default, :lists.reverse(acc)}\n  end\n\n  defp do_pop_at([head | tail], 0, _default, acc) do\n    {head, :lists.reverse(acc, tail)}\n  end\n\n  defp do_pop_at([head | tail], index, default, acc) do\n    do_pop_at(tail, index - 1, default, [head | acc])\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/macro/env.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Macro.Env do\n  @moduledoc \"\"\"\n  A struct that holds compile time environment information.\n\n  The current environment can be accessed at any time as\n  `__ENV__/0`. Inside macros, the caller environment can be\n  accessed as `__CALLER__/0`.\n\n  The majority of the functions in this module are provided\n  for low-level tools, which need to integrate with the Elixir\n  compiler, such as language servers and embedded languages.\n  For regular usage in Elixir code and macros, you must use\n  the `Macro` module instead. In particular, avoid modifying\n  the `Macro.Env` struct directly and prefer to use high-level\n  constructs, such as a `import`, `aliases`, and so forth to\n  build your own environment. For example, to build a custom\n  environment, you can define a function such as:\n\n      def make_custom_env do\n        import SomeModule, only: [some_function: 2], warn: false\n        alias A.B.C, warn: false\n        __ENV__\n      end\n\n  ## Struct fields\n\n  The `Macro.Env` struct contains the following fields:\n\n    * `context` - the context of the environment; it can be `nil`\n      (default context), `:guard` (inside a guard) or `:match` (inside a match)\n    * `context_modules` - a list of modules defined in the current context\n    * `file` - the current absolute file name as a binary\n    * `function` - a tuple as `{atom, integer}`, where the first\n      element is the function name and the second its arity; returns\n      `nil` if not inside a function\n    * `line` - the current line as an integer\n    * `module` - the current module name\n\n  The following fields are private to Elixir's macro expansion mechanism and\n  must not be accessed directly:\n\n    * `aliases`\n    * `functions`\n    * `macro_aliases`\n    * `macros`\n    * `lexical_tracker`\n    * `requires`\n    * `tracers`\n    * `versioned_vars`\n\n  \"\"\"\n\n  @type context :: :match | :guard | nil\n  @type context_modules :: [module]\n  @type file :: binary\n  @type line :: non_neg_integer\n  @type name_arity :: {atom, arity}\n  @type variable :: {atom, atom | term}\n\n  @typep aliases :: [{module, module}]\n  @typep functions :: [{module, [name_arity]}]\n  @typep lexical_tracker :: pid | nil\n  @typep macro_aliases :: [{module, {term, module}}]\n  @typep macros :: [{module, [name_arity]}]\n  @typep requires :: [module]\n  @typep tracers :: [module]\n  @typep versioned_vars :: %{optional(variable) => var_version :: non_neg_integer}\n\n  @type define_import_opts :: [\n          trace: boolean(),\n          emit_warnings: boolean(),\n          info_callback: (atom() -> [{atom(), arity()}]),\n          only: :functions | :macros | [{atom(), arity()}],\n          except: [{atom(), arity()}],\n          warn: boolean()\n        ]\n\n  @type define_alias_opts :: [\n          trace: boolean(),\n          as: atom(),\n          warn: boolean()\n        ]\n\n  @type define_require_opts :: [\n          trace: boolean(),\n          as: atom(),\n          warn: boolean()\n        ]\n\n  @type expand_alias_opts :: [\n          trace: boolean()\n        ]\n\n  @type expand_import_opts :: [\n          allow_locals: boolean() | (-> function() | false),\n          check_deprecations: boolean(),\n          trace: boolean()\n        ]\n\n  @type expand_require_opts :: [\n          check_deprecations: boolean(),\n          trace: boolean()\n        ]\n\n  @type t :: %{\n          __struct__: __MODULE__,\n          aliases: aliases,\n          context: context,\n          context_modules: context_modules,\n          file: file,\n          function: name_arity | nil,\n          functions: functions,\n          lexical_tracker: lexical_tracker,\n          line: line,\n          macro_aliases: macro_aliases,\n          macros: macros,\n          module: module,\n          requires: requires,\n          tracers: tracers,\n          versioned_vars: versioned_vars\n        }\n\n  fields = [\n    aliases: [],\n    context: nil,\n    context_modules: [],\n    file: \"nofile\",\n    function: nil,\n    functions: [],\n    lexical_tracker: nil,\n    line: 0,\n    macro_aliases: [],\n    macros: [],\n    module: nil,\n    requires: [],\n    tracers: [],\n    versioned_vars: %{}\n  ]\n\n  # Define the __struct__ callbacks by hand for bootstrap reasons.\n  {_struct, [], escaped_struct, kv, body} =\n    Kernel.Utils.defstruct(__MODULE__, fields, false, __ENV__)\n\n  def __struct__(), do: unquote(escaped_struct)\n  def __struct__(unquote(kv)), do: unquote(body)\n\n  @doc \"\"\"\n  Prunes compile information from the environment.\n\n  This happens when the environment is captured at compilation\n  time, for example, in the module body, and then used to\n  evaluate code after the module has been defined.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec prune_compile_info(t) :: t\n  def prune_compile_info(env) do\n    %{env | lexical_tracker: nil, tracers: []}\n  end\n\n  @doc \"\"\"\n  Returns a list of variables in the current environment.\n\n  Each variable is identified by a tuple of two elements,\n  where the first element is the variable name as an atom\n  and the second element is its context, which may be an\n  atom or an integer.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec vars(t) :: [variable]\n  def vars(env)\n\n  def vars(%{__struct__: Macro.Env, versioned_vars: vars}) do\n    Map.keys(vars)\n  end\n\n  @doc \"\"\"\n  Checks if a variable belongs to the environment.\n\n  ## Examples\n\n      iex> x = 13\n      iex> x\n      13\n      iex> Macro.Env.has_var?(__ENV__, {:x, nil})\n      true\n      iex> Macro.Env.has_var?(__ENV__, {:unknown, nil})\n      false\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec has_var?(t, variable) :: boolean()\n  def has_var?(env, var)\n\n  def has_var?(%{__struct__: Macro.Env, versioned_vars: vars}, var) do\n    Map.has_key?(vars, var)\n  end\n\n  @doc \"\"\"\n  Returns a keyword list containing the file and line\n  information as keys.\n  \"\"\"\n  @spec location(t) :: keyword\n  def location(env)\n\n  def location(%{__struct__: Macro.Env, file: file, line: line}) do\n    [file: file, line: line]\n  end\n\n  # TODO: Deprecate on Elixir 1.21 in favor of expand_alias/4\n  @doc false\n  def fetch_alias(%{__struct__: Macro.Env, aliases: aliases}, atom) when is_atom(atom),\n    do: Keyword.fetch(aliases, :\"Elixir.#{atom}\")\n\n  # TODO: Deprecate on Elixir 1.21 in favor of expand_alias/4\n  @doc false\n  def fetch_macro_alias(%{__struct__: Macro.Env, macro_aliases: aliases}, atom)\n      when is_atom(atom),\n      do: Keyword.fetch(aliases, :\"Elixir.#{atom}\")\n\n  @doc \"\"\"\n  Returns the modules from which the given `{name, arity}` was\n  imported.\n\n  It returns a list of two element tuples in the shape of\n  `{:function | :macro, module}`. The elements in the list\n  are in no particular order and the order is not guaranteed.\n\n  > #### Use only for introspection {: .warning}\n  >\n  > This function does not emit compiler tracing events,\n  > which may block the compiler from correctly tracking\n  > dependencies. Use this function for reflection purposes\n  > but to do not use it to expand imports into qualified\n  > calls. Instead, use `expand_import/5`.\n\n  ## Examples\n\n      iex> Macro.Env.lookup_import(__ENV__, {:duplicate, 2})\n      []\n      iex> import Tuple, only: [duplicate: 2], warn: false\n      iex> Macro.Env.lookup_import(__ENV__, {:duplicate, 2})\n      [{:function, Tuple}]\n      iex> import List, only: [duplicate: 2], warn: false\n      iex> Macro.Env.lookup_import(__ENV__, {:duplicate, 2})\n      [{:function, List}, {:function, Tuple}]\n\n      iex> Macro.Env.lookup_import(__ENV__, {:def, 1})\n      [{:macro, Kernel}]\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec lookup_import(t, name_arity) :: [{:function | :macro, module}]\n  def lookup_import(env, name_arity)\n\n  def lookup_import(\n        %{__struct__: Macro.Env, functions: functions, macros: macros},\n        {name, arity} = pair\n      )\n      when is_atom(name) and is_integer(arity) do\n    f = for {mod, pairs} <- functions, :ordsets.is_element(pair, pairs), do: {:function, mod}\n    m = for {mod, pairs} <- macros, :ordsets.is_element(pair, pairs), do: {:macro, mod}\n    f ++ m\n  end\n\n  @doc \"\"\"\n  Returns the names of any aliases for the given module or atom.\n\n  ## Examples\n\n      iex> alias Foo.Bar\n      iex> Bar\n      Foo.Bar\n      iex> Macro.Env.lookup_alias_as(__ENV__, Foo.Bar)\n      [Elixir.Bar]\n      iex> alias Foo.Bar, as: Baz\n      iex> Baz\n      Foo.Bar\n      iex> Macro.Env.lookup_alias_as(__ENV__, Foo.Bar)\n      [Elixir.Bar, Elixir.Baz]\n      iex> Macro.Env.lookup_alias_as(__ENV__, Unknown)\n      []\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec lookup_alias_as(t, atom) :: [atom]\n  def lookup_alias_as(env, atom)\n\n  def lookup_alias_as(%{__struct__: Macro.Env, aliases: aliases}, atom) when is_atom(atom) do\n    for {name, ^atom} <- aliases, do: name\n  end\n\n  @doc \"\"\"\n  Returns `true` if the given module has been required.\n\n  ## Examples\n\n      iex> Macro.Env.required?(__ENV__, Integer)\n      false\n      iex> require Integer, warn: false\n      iex> Macro.Env.required?(__ENV__, Integer)\n      true\n\n      iex> Macro.Env.required?(__ENV__, Kernel)\n      true\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec required?(t, module) :: boolean\n  def required?(env, module)\n\n  def required?(%{__struct__: Macro.Env, requires: requires}, mod) when is_atom(mod),\n    do: mod in requires\n\n  @doc \"\"\"\n  Prepend a tracer to the list of tracers in the environment.\n\n  ## Examples\n\n      Macro.Env.prepend_tracer(__ENV__, MyCustomTracer)\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec prepend_tracer(t, module) :: t\n  def prepend_tracer(%{__struct__: Macro.Env, tracers: tracers} = env, tracer) do\n    %{env | tracers: [tracer | tracers]}\n  end\n\n  trace_option = \"\"\"\n  `:trace` - when set to `false`, it disables compilation tracers and\n  lexical tracker. This option must only be used by language servers and\n  other tools that need to introspect code without affecting how it is compiled.\n  Disabling tracer inside macros or regular code expansion is extremely\n  discouraged as it blocks the compiler from accurately tracking dependencies\\\n  \"\"\"\n\n  @doc \"\"\"\n  Defines the given `module` as required in the environment.\n\n  It does not check or assert the module is available.\n  This is used by tools which need to mimic the Elixir compiler.\n  The appropriate `:require` compiler tracing event will be emitted.\n\n  ## Additional options\n\n  It accepts the same options as `Kernel.SpecialForm.require/2` plus:\n\n    * #{trace_option}\n\n  ## Examples\n\n      iex> env = __ENV__\n      iex> Macro.Env.required?(env, Integer)\n      false\n      iex> {:ok, env} = Macro.Env.define_require(env, [line: 10], Integer)\n      iex> Macro.Env.required?(env, Integer)\n      true\n\n  If the `:as` option is given, it will also define an alias:\n\n      iex> env = __ENV__\n      iex> {:ok, env} = Macro.Env.define_require(env, [line: 10], Foo.Bar, as: Baz)\n      iex> Macro.Env.expand_alias(env, [], [:Baz])\n      {:alias, Foo.Bar}\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec define_require(t, Macro.metadata(), module, define_require_opts) :: {:ok, t}\n  def define_require(env, meta, module, opts \\\\ [])\n      when is_list(meta) and is_atom(module) and is_list(opts) do\n    {trace, opts} = Keyword.pop(opts, :trace, true)\n    env = :elixir_aliases.require(meta, module, opts, env, trace)\n    result = :elixir_aliases.alias(meta, module, false, opts, env, trace)\n    maybe_define_error(result, :elixir_aliases)\n  end\n\n  @doc \"\"\"\n  Defines the given `module` as imported in the environment.\n\n  It assumes `module` is available. This is used by tools which\n  need to mimic the Elixir compiler. The appropriate `:import`\n  compiler tracing event will be emitted.\n\n  ## Additional options\n\n  It accepts the same options as `Kernel.SpecialForm.import/2` plus:\n\n    * `:emit_warnings` - emit warnings found when defining imports\n\n    * #{trace_option}\n\n    * `:info_callback` - a function to use instead of `c:Module.__info__/1`.\n      The function will be invoked with `:functions` or `:macros` argument.\n      It has to return a list of `{function, arity}` key value pairs.\n      If it fails, it defaults to using module metadata based on `module_info/1`.\n\n  ## Examples\n\n      iex> env = __ENV__\n      iex> Macro.Env.lookup_import(env, {:flatten, 1})\n      []\n      iex> {:ok, env} = Macro.Env.define_import(env, [line: 10], List)\n      iex> Macro.Env.lookup_import(env, {:flatten, 1})\n      [{:function, List}]\n\n  It accepts the same options as `Kernel.SpecialForm.import/2`:\n\n      iex> env = __ENV__\n      iex> Macro.Env.lookup_import(env, {:is_odd, 1})\n      []\n      iex> {:ok, env} = Macro.Env.define_import(env, [line: 10], Integer, only: :macros)\n      iex> Macro.Env.lookup_import(env, {:is_odd, 1})\n      [{:macro, Integer}]\n\n  ## Info callback override\n\n      iex> env = __ENV__\n      iex> Macro.Env.lookup_import(env, {:flatten, 1})\n      []\n      iex> {:ok, env} = Macro.Env.define_import(env, [line: 10], SomeModule, [info_callback: fn :functions -> [{:flatten, 1}]; :macros -> [{:some, 2}]; end])\n      iex> Macro.Env.lookup_import(env, {:flatten, 1})\n      [{:function, SomeModule}]\n      iex> Macro.Env.lookup_import(env, {:some, 2})\n      [{:macro, SomeModule}]\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec define_import(t, Macro.metadata(), module, define_import_opts) ::\n          {:ok, t} | {:error, String.t()}\n  def define_import(env, meta, module, opts \\\\ [])\n      when is_list(meta) and is_atom(module) and is_list(opts) do\n    {trace, opts} = Keyword.pop(opts, :trace, true)\n    {warnings, opts} = Keyword.pop(opts, :emit_warnings, true)\n    {info_callback, opts} = Keyword.pop(opts, :info_callback, &module.__info__/1)\n\n    result = :elixir_import.import(meta, module, opts, env, warnings, trace, info_callback)\n    maybe_define_error(result, :elixir_import)\n  end\n\n  @doc \"\"\"\n  Defines the given `as` an alias to `module` in the environment.\n\n  This is used by tools which need to mimic the Elixir compiler.\n  The appropriate `:alias` compiler tracing event will be emitted.\n\n  ## Additional options\n\n  It accepts the same options as `Kernel.SpecialForm.alias/2` plus:\n\n    * #{trace_option}\n\n  ## Examples\n\n      iex> env = __ENV__\n      iex> Macro.Env.expand_alias(env, [], [:Baz])\n      :error\n      iex> {:ok, env} = Macro.Env.define_alias(env, [line: 10], Foo.Bar, as: Baz)\n      iex> Macro.Env.expand_alias(env, [], [:Baz])\n      {:alias, Foo.Bar}\n      iex> Macro.Env.expand_alias(env, [], [:Baz, :Bat])\n      {:alias, Foo.Bar.Bat}\n\n  If no `:as` option is given, the alias will be inferred from the module:\n\n      iex> env = __ENV__\n      iex> {:ok, env} = Macro.Env.define_alias(env, [line: 10], Foo.Bar)\n      iex> Macro.Env.expand_alias(env, [], [:Bar])\n      {:alias, Foo.Bar}\n\n  If it is not possible to infer one, an error is returned:\n\n      iex> Macro.Env.define_alias(__ENV__, [line: 10], :an_atom)\n      {:error,\n       \"alias cannot be inferred automatically for module: :an_atom, \" <>\n         \"please use the :as option. Implicit aliasing is only supported with Elixir modules\"}\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec define_alias(t, Macro.metadata(), module, define_alias_opts) ::\n          {:ok, t} | {:error, String.t()}\n  def define_alias(env, meta, module, opts \\\\ [])\n      when is_list(meta) and is_atom(module) and is_list(opts) do\n    {trace, opts} = Keyword.pop(opts, :trace, true)\n    result = :elixir_aliases.alias(meta, module, true, opts, env, trace)\n    maybe_define_error(result, :elixir_aliases)\n  end\n\n  defp maybe_define_error({:ok, _info, env}, _mod),\n    do: {:ok, env}\n\n  defp maybe_define_error({:error, reason}, mod),\n    do: {:error, Kernel.to_string(mod.format_error(reason))}\n\n  @doc \"\"\"\n  Expands an alias given by the alias segments.\n\n  It returns `{:alias, alias}` if the segments is a list\n  of atoms and an alias was found. Returns `:error` otherwise.\n\n  This expansion may emit the `:alias_expansion` trace event\n  but it does not emit the `:alias_reference` one.\n\n  ## Options\n\n    * #{trace_option}\n\n  ## Examples\n\n      iex> alias List, as: MyList\n      iex> Macro.Env.expand_alias(__ENV__, [], [:MyList])\n      {:alias, List}\n      iex> Macro.Env.expand_alias(__ENV__, [], [:MyList, :Nested])\n      {:alias, List.Nested}\n\n  If there is no alias or the alias starts with `Elixir.`\n  (which disables aliasing), then `:error` is returned:\n\n      iex> alias List, as: MyList\n      iex> Macro.Env.expand_alias(__ENV__, [], [:Elixir, MyList])\n      :error\n      iex> Macro.Env.expand_alias(__ENV__, [], [:AnotherList])\n      :error\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec expand_alias(t, keyword, [atom()], expand_alias_opts) ::\n          {:alias, atom()} | :error\n  def expand_alias(env, meta, list, opts \\\\ [])\n      when is_list(meta) and is_list(list) and is_list(opts) do\n    trace = Keyword.get(opts, :trace, true)\n\n    case :elixir_aliases.expand(meta, list, env, trace) do\n      atom when is_atom(atom) -> {:alias, atom}\n      [_ | _] -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Expands an import given by `name` and `arity`.\n\n  If the import points to a macro, it returns a tuple\n  with the module and a function that expands the macro.\n  The function expects the metadata to be attached to the\n  expansion and the arguments of the macro.\n\n  If the import points to a function, it returns a tuple\n  with the module and the function name.\n\n  If any import is found, the appropriate compiler tracing\n  event will be emitted.\n\n  Otherwise returns `{:error, reason}`.\n\n  ## Options\n\n    * `:allow_locals` - controls how local macros are resolved.\n      Defaults to `true`.\n\n      - When `false`, does not attempt to capture local macros defined in the\n        current module in `env`\n      - When `true`, uses a default resolver that looks for public macros in\n        the current module\n      - When a function, it will be invoked to lazily compute a local function\n        (or return false). It has signature `(-> function() | false)`\n\n    * `:check_deprecations` - when set to `false`, does not check for deprecations\n      when expanding macros\n\n    * #{trace_option}\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec expand_import(t, keyword, atom(), arity(), expand_import_opts) ::\n          {:macro, module(), (Macro.metadata(), args :: [Macro.t()] -> Macro.t())}\n          | {:function, module(), atom()}\n          | {:error, :not_found | {:conflict, module()} | {:ambiguous, [module()]}}\n  def expand_import(env, meta, name, arity, opts \\\\ [])\n      when is_list(meta) and is_atom(name) and is_integer(arity) and is_list(opts) do\n    case :elixir_import.special_form(name, arity) do\n      true ->\n        {:error, :not_found}\n\n      false ->\n        allow_locals = Keyword.get(opts, :allow_locals, true)\n        trace = Keyword.get(opts, :trace, true)\n        module = env.module\n\n        # When allow_locals is a callback, we don't need to pass module macros as extra\n        # because the callback will handle local macro resolution\n        extra =\n          if is_function(allow_locals, 0) do\n            []\n          else\n            case allow_locals and function_exported?(module, :__info__, 1) do\n              true -> [{module, module.__info__(:macros)}]\n              false -> []\n            end\n          end\n\n        case :elixir_dispatch.expand_import(meta, name, arity, env, extra, allow_locals, trace) do\n          {:macro, receiver, expander} ->\n            {:macro, receiver, wrap_expansion(receiver, expander, meta, name, arity, env, opts)}\n\n          {:function, receiver, name} ->\n            {:function, receiver, name}\n\n          error ->\n            {:error, error}\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Expands a require given by `module`, `name`, and `arity`.\n\n  If the require points to a macro and the module has been\n  required, it returns a tuple with the module and a function\n  that expands the macro. The function expects the metadata\n  to be attached to the expansion and the arguments of the macro.\n  The appropriate `:remote_macro` compiler tracing event will\n  be emitted if a macro is found (note a `:remote_function`\n  event is not emitted in `:error` cases).\n\n  Otherwise returns `:error`.\n\n  ## Options\n\n    * `:check_deprecations` - when set to `false`, does not check for deprecations\n      when expanding macros\n\n    * #{trace_option}\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec expand_require(t, keyword, module(), atom(), arity(), expand_require_opts) ::\n          {:macro, module(), (Macro.metadata(), args :: [Macro.t()] -> Macro.t())}\n          | :error\n  def expand_require(env, meta, module, name, arity, opts \\\\ [])\n      when is_list(meta) and is_atom(module) and is_atom(name) and is_integer(arity) and\n             is_list(opts) do\n    trace = Keyword.get(opts, :trace, true)\n\n    case :elixir_dispatch.expand_require(meta, module, name, arity, env, trace) do\n      {:macro, receiver, expander} ->\n        {:macro, receiver, wrap_expansion(receiver, expander, meta, name, arity, env, opts)}\n\n      :error ->\n        :error\n    end\n  end\n\n  defp wrap_expansion(receiver, expander, meta, name, arity, env, opts) do\n    fn expansion_meta, args ->\n      if Keyword.get(opts, :check_deprecations, true) do\n        :elixir_dispatch.check_deprecated(:macro, meta, receiver, name, arity, env)\n      end\n\n      quoted = expander.(:elixir_dispatch.stop_generated(args), env)\n      next = :elixir_module.next_counter(env.module)\n      :elixir_quote.linify_with_context_counter(expansion_meta, {receiver, next}, quoted)\n    end\n  end\n\n  @doc \"\"\"\n  Returns an environment in the guard context.\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec to_guard(t) :: t\n  def to_guard(%{__struct__: Macro.Env} = env) do\n    %{env | context: :guard}\n  end\n\n  @doc \"\"\"\n  Returns an environment in the match context.\n  \"\"\"\n  @spec to_match(t) :: t\n  def to_match(%{__struct__: Macro.Env} = env) do\n    %{env | context: :match}\n  end\n\n  @doc \"\"\"\n  Returns whether the compilation environment is currently\n  inside a guard.\n  \"\"\"\n  @spec in_guard?(t) :: boolean\n  def in_guard?(env)\n  def in_guard?(%{__struct__: Macro.Env, context: context}), do: context == :guard\n\n  @doc \"\"\"\n  Returns whether the compilation environment is currently\n  inside a match clause.\n  \"\"\"\n  @spec in_match?(t) :: boolean\n  def in_match?(env)\n  def in_match?(%{__struct__: Macro.Env, context: context}), do: context == :match\n\n  @doc \"\"\"\n  Returns the environment stacktrace.\n  \"\"\"\n  @spec stacktrace(t) :: list\n  def stacktrace(%{__struct__: Macro.Env} = env) do\n    cond do\n      is_nil(env.module) ->\n        [{:elixir_compiler, :__FILE__, 1, relative_location(env)}]\n\n      is_nil(env.function) ->\n        [{env.module, :__MODULE__, 0, relative_location(env)}]\n\n      true ->\n        {name, arity} = env.function\n        [{env.module, name, arity, relative_location(env)}]\n    end\n  end\n\n  defp relative_location(env) do\n    [file: String.to_charlist(Path.relative_to_cwd(env.file)), line: env.line]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/macro.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nimport Kernel, except: [to_string: 1]\n\ndefmodule Macro do\n  @moduledoc ~S\"\"\"\n  Functions for manipulating AST and implementing macros.\n\n  Macros are compile-time constructs that receive Elixir's AST as input\n  and return Elixir's AST as output.\n\n  Many of the functions in this module exist precisely to work with Elixir\n  AST, to traverse, query, and transform it.\n\n  Let's see a simple example that shows the difference between functions\n  and macros:\n\n      defmodule Example do\n        defmacro macro_inspect(value) do\n          IO.inspect(value)\n          value\n        end\n\n        def fun_inspect(value) do\n          IO.inspect(value)\n          value\n        end\n      end\n\n  Now let's give it a try:\n\n      import Example\n\n      macro_inspect(1)\n      #=> 1\n      #=> 1\n\n      fun_inspect(1)\n      #=> 1\n      #=> 1\n\n  So far they behave the same, as we are passing an integer as argument.\n  But let's see what happens when we pass an expression:\n\n      macro_inspect(1 + 2)\n      #=> {:+, [line: 3], [1, 2]}\n      #=> 3\n\n      fun_inspect(1 + 2)\n      #=> 3\n      #=> 3\n\n  The macro receives the representation of the code given as argument,\n  while a function receives the result of the code given as argument.\n  A macro must return a superset of the code representation. See\n  `t:input/0` and `t:output/0` for more information.\n\n  To learn more about Elixir's AST and how to build them programmatically,\n  see `quote/2`.\n\n  > #### Evaluating code {: .tip}\n  >\n  > The functions in this module do not evaluate code. In fact,\n  > evaluating code from macros is often an anti-pattern. For code\n  > evaluation, see the `Code` module.\n  \"\"\"\n\n  alias Code.Identifier\n\n  @typedoc \"Abstract Syntax Tree (AST)\"\n  @type t :: input\n\n  @typedoc \"The inputs of a macro\"\n  @type input ::\n          input_expr\n          | {input, input}\n          | [input]\n          | atom\n          | number\n          | binary\n\n  @typep input_expr :: {input_expr | atom, metadata, atom | [input]}\n\n  @typedoc \"The output of a macro\"\n  @type output ::\n          output_expr\n          | {output, output}\n          | [output]\n          | atom\n          | number\n          | binary\n          | captured_remote_function\n          | pid\n\n  @typep output_expr :: {output_expr | atom, metadata, atom | [output]}\n\n  @typedoc \"\"\"\n  A keyword list of AST metadata.\n\n  The metadata in Elixir AST is a keyword list of values. Any key can be used\n  and different parts of the compiler may use different keys. For example,\n  the AST received by a macro will always include the `:line` annotation,\n  while the AST emitted by `quote/2` will only have the `:line` annotation if\n  the `:line` option is provided.\n\n  The following metadata keys are public:\n\n    * `:context` - Defines the context in which the AST was generated.\n      For example, `quote/2` will include the module calling `quote/2`\n      as the context. This is often used to distinguish regular code from code\n      generated by a macro or by `quote/2`.\n\n    * `:counter` - The variable counter used for variable hygiene. In terms of\n      the compiler, each variable is identified by the combination of either\n      `name` and `metadata[:counter]`, or `name` and `context`.\n\n    * `:from_brackets` - Used to determine whether a call to `Access.get/3` is from\n      bracket syntax.\n\n    * `:from_interpolation` - Used to determine whether a call to `Kernel.to_string/1` is\n      from interpolation.\n\n    * `:generated` - Whether the code should be considered as generated by\n      the compiler or not. This means the compiler and tools like Dialyzer may not\n      emit certain warnings.\n\n    * `:if_undefined` - How to expand a variable that is undefined. Set it to\n      `:apply` if you want a variable to become a nullary call without warning\n      or `:raise`\n\n    * `:keep` - Used by `quote/2` with the option `location: :keep` to annotate\n      the file and the line number of the quoted source.\n\n    * `:line` - The line number of the AST node. Note line information is discarded\n      from quoted code but can be enabled back via the `:line` option.\n\n  The following metadata keys are enabled by `Code.string_to_quoted/2`:\n\n    * `:assoc` - contains metadata about the `=>` operator location in a\n      map key-value AST node (when `:token_metadata` is true). This entry\n      appears on map key nodes only\n\n    * `:closing` - contains metadata about the closing pair, such as a `}`\n      in a tuple or in a map, or such as the closing `)` in a function call\n      with parens (when `:token_metadata` is true). If the function call\n      has a do-end block attached to it, its metadata is found under the\n      `:do` and `:end` metadata\n\n    * `:column` - the column number of the AST node (when `:columns` is true).\n      Note column information is always discarded from quoted code.\n\n    * `:delimiter` - contains the opening delimiter for sigils, strings,\n      and charlists as a string (such as `\"{\"`, `\"/\"`, `\"'\"`, and the like)\n\n    * `:do` - contains metadata about the `do` location in a function call with\n      `do`-`end` blocks (when `:token_metadata` is true)\n\n    * `:end` - contains metadata about the `end` location in a function call with\n      `do`-`end` blocks (when `:token_metadata` is true)\n\n    * `:end_of_expression` - denotes when the end of expression effectively\n      happens (when `:token_metadata` is true). This is only available for\n      expressions inside \"blocks of code\", which are either direct children\n      of a `__block__` or the right side of `->`. The last expression of the\n      block does not have metadata if it is not followed by an end of line\n      character (either a newline or `;`). This entry may appear multiple times\n      in the same metadata if the expression is surround by parens\n\n    * `:format` - set to `:keyword` when an atom is defined as a keyword.\n      It may also be set to `:atom` to distinguish `nil`, `false`, and `true`\n\n    * `:indentation` - indentation of a sigil heredoc\n\n    * `:parens` - denotes a node was surrounded by parens for grouping.\n      This entry may appear multiple times in the same metadata if\n      multiple pairs are used for grouping\n\n  The following metadata keys are private:\n\n    * `:alias` - Used for alias hygiene.\n    * `:ambiguous_op` - Used for improved error messages in the compiler.\n    * `:imports` - Used for import hygiene.\n    * `:var` - Used for improved error messages on undefined variables.\n\n  Do not rely on them as they may change or be fully removed in future versions\n  of the language. They are often used by `quote/2` and the compiler to provide\n  features like hygiene, better error messages, and so forth.\n\n  If you introduce custom keys into the AST metadata, please make sure to prefix\n  them with the name of your library or application, so that they will not conflict\n  with keys that could potentially be introduced by the compiler in the future.\n  \"\"\"\n  @type metadata :: keyword\n\n  @typedoc \"A captured remote function in the format of &Mod.fun/arity\"\n  @type captured_remote_function :: fun\n\n  @type escape_opts :: [\n          unquote: boolean(),\n          prune_metadata: boolean(),\n          generated: boolean()\n        ]\n\n  @type inspect_atom_opts :: [\n          escape: (binary(), char() -> binary())\n        ]\n\n  @doc \"\"\"\n  Breaks a pipeline expression into a list.\n\n  The AST for a pipeline (a sequence of applications of `|>/2`) is similar to the\n  AST of a sequence of binary operators or function applications: the top-level\n  expression is the right-most `:|>` (which is the last one to be executed), and\n  its left-hand and right-hand sides are its arguments:\n\n      quote do: 100 |> div(5) |> div(2)\n      #=> {:|>, _, [arg1, arg2]}\n\n  In the example above, the `|>/2` pipe is the right-most pipe; `arg1` is the AST\n  for `100 |> div(5)`, and `arg2` is the AST for `div(2)`.\n\n  It's often useful to have the AST for such a pipeline as a list of function\n  applications. This function does exactly that:\n\n      Macro.unpipe(quote do: 100 |> div(5) |> div(2))\n      #=> [{100, 0}, {{:div, [], [5]}, 0}, {{:div, [], [2]}, 0}]\n\n  We get a list that follows the pipeline directly: first the `100`, then the\n  `div(5)` (more precisely, its AST), then `div(2)`. The `0` as the second\n  element of the tuples is the position of the previous element in the pipeline\n  inside the current function application: `{{:div, [], [5]}, 0}` means that the\n  previous element (`100`) will be inserted as the 0th (first) argument to the\n  `div/2` function, so that the AST for that function will become `{:div, [],\n  [100, 5]}` (`div(100, 5)`).\n  \"\"\"\n  @spec unpipe(t()) :: [t()]\n  def unpipe(expr) do\n    :lists.reverse(unpipe(expr, []))\n  end\n\n  defp unpipe({:|>, _, [left, right]}, acc) do\n    unpipe(right, unpipe(left, acc))\n  end\n\n  defp unpipe(other, acc) do\n    [{other, 0} | acc]\n  end\n\n  @doc \"\"\"\n  Pipes `expr` into the `call_args` at the given `position`.\n\n  This function can be used to implement `|>` like functionality. For example,\n  `|>` itself is implemented as:\n\n      defmacro left |> right do\n        Macro.pipe(left, right, 0)\n      end\n\n  `expr` is the AST of an expression. `call_args` must be the AST *of a call*,\n  otherwise this function will raise an error. As an example, consider the pipe\n  operator `|>/2`, which uses this function to build pipelines.\n\n  Even if the expression is piped into the AST, it doesn't necessarily mean that\n  the AST is valid. For example, you could pipe an argument to `div/2`, effectively\n  turning it into a call to `div/3`, which is a function that doesn't exist by\n  default. The code will raise unless a `div/3` function is locally defined.\n  \"\"\"\n  @spec pipe(t(), t(), integer) :: t()\n  def pipe(expr, call_args, position)\n\n  def pipe(expr, {:&, _, _} = call_args, _integer) do\n    raise ArgumentError, bad_pipe(expr, call_args)\n  end\n\n  def pipe(expr, {tuple_or_map, _, _} = call_args, _integer) when tuple_or_map in [:{}, :%{}] do\n    raise ArgumentError, bad_pipe(expr, call_args)\n  end\n\n  # Without this, `Macro |> Env == Macro.Env`.\n  def pipe(expr, {:__aliases__, _, _} = call_args, _integer) do\n    raise ArgumentError, bad_pipe(expr, call_args)\n  end\n\n  def pipe(expr, {:<<>>, _, _} = call_args, _integer) do\n    raise ArgumentError, bad_pipe(expr, call_args)\n  end\n\n  def pipe(expr, {unquote, _, []}, _integer) when unquote in [:unquote, :unquote_splicing] do\n    raise ArgumentError,\n          \"cannot pipe #{to_string(expr)} into the special form #{unquote}/1 \" <>\n            \"since #{unquote}/1 is used to build the Elixir AST itself\"\n  end\n\n  # {:fn, _, _} is what we get when we pipe into an anonymous function without\n  # calling it, for example, `:foo |> (fn x -> x end)`.\n  def pipe(expr, {:fn, _, _}, _integer) do\n    raise ArgumentError,\n          \"cannot pipe #{to_string(expr)} into an anonymous function without\" <>\n            \" calling the function; use Kernel.then/2 instead or\" <>\n            \" define the anonymous function as a regular private function\"\n  end\n\n  def pipe(expr, {call, line, atom}, integer) when is_atom(atom) do\n    {call, line, List.insert_at([], integer, expr)}\n  end\n\n  def pipe(_expr, {op, _line, [arg]}, _integer) when op == :+ or op == :- do\n    raise ArgumentError,\n          \"piping into a unary operator is not supported, please use the qualified name: \" <>\n            \"Kernel.#{op}(#{to_string(arg)}), instead of #{op}#{to_string(arg)}\"\n  end\n\n  # Piping to an Access.get/2,3 call in the form of brackets\n  # (foo |> bar[]) raises a nice error.\n  def pipe(\n        expr,\n        {{_, meta, [Access, :get] = op}, _meta, [first, second]} = _op_args,\n        integer\n      ) do\n    if {:from_brackets, true} in meta do\n      raise ArgumentError, \"\"\"\n      wrong operator precedence when piping into bracket-based access\n\n       Instead of:\n\n           #{to_string(expr)} |> #{to_string(first)}[#{to_string(second)}]\n\n       You should write:\n\n           (#{to_string(expr)} |> #{to_string(first)})[#{to_string(second)}]\n      \"\"\"\n    else\n      {op, meta, List.insert_at([first, second], integer, expr)}\n    end\n  end\n\n  def pipe(expr, {op, line, args} = op_args, integer) when is_list(args) do\n    cond do\n      is_atom(op) and operator?(op, 1) ->\n        raise ArgumentError,\n              \"cannot pipe #{to_string(expr)} into #{to_string(op_args)}, \" <>\n                \"the #{to_string(op)} operator can only take one argument\"\n\n      is_atom(op) and operator?(op, 2) ->\n        raise ArgumentError,\n              \"cannot pipe #{to_string(expr)} into #{to_string(op_args)}, \" <>\n                \"the #{to_string(op)} operator can only take two arguments\"\n\n      true ->\n        {op, line, List.insert_at(args, integer, expr)}\n    end\n  end\n\n  def pipe(expr, call_args, _integer) do\n    raise ArgumentError, bad_pipe(expr, call_args)\n  end\n\n  defp bad_pipe(expr, call_args) do\n    \"cannot pipe #{to_string(expr)} into #{to_string(call_args)}, \" <>\n      \"can only pipe into local calls foo(), remote calls Foo.bar() or anonymous function calls foo.()\"\n  end\n\n  @doc \"\"\"\n  Applies the given function to the node metadata if it contains one.\n\n  This is often useful when used with `Macro.prewalk/2` to remove\n  information like lines and hygienic counters from the expression\n  for either storage or comparison.\n\n  ## Examples\n\n      iex> quoted = quote line: 10, do: sample()\n      {:sample, [line: 10], []}\n      iex> Macro.update_meta(quoted, &Keyword.delete(&1, :line))\n      {:sample, [], []}\n\n  \"\"\"\n  @spec update_meta(t, (keyword -> keyword)) :: t\n  def update_meta(quoted, fun)\n\n  def update_meta({left, meta, right}, fun) when is_list(meta) do\n    {left, fun.(meta), right}\n  end\n\n  def update_meta(other, _fun) do\n    other\n  end\n\n  @doc \"\"\"\n  Generates AST nodes for a given number of required argument\n  variables using `Macro.var/2`.\n\n  Note the arguments are not unique. If you later on want\n  to access the same variables, you can invoke this function\n  with the same inputs. Use `generate_unique_arguments/2` to\n  generate unique arguments that can't be overridden.\n\n  ## Examples\n\n      iex> Macro.generate_arguments(2, __MODULE__)\n      [{:arg1, [], __MODULE__}, {:arg2, [], __MODULE__}]\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec generate_arguments(0, context :: atom) :: []\n  @spec generate_arguments(pos_integer, context) :: [{atom, [], context}, ...] when context: atom\n  def generate_arguments(amount, context), do: generate_arguments(amount, context, &var/2)\n\n  @doc \"\"\"\n  Returns the path to the node in `ast` for which `fun` returns a truthy value.\n\n  The path is a list, starting with the node in which `fun` returns\n  a truthy value, followed by all of its parents.\n\n  Returns `nil` if `fun` returns only falsy values.\n\n  Computing the path can be an efficient operation when you want\n  to find a particular node in the AST within its context and then\n  assert something about it.\n\n  ## Examples\n\n      iex> Macro.path(quote(do: [1, 2, 3]), & &1 == 3)\n      [3, [1, 2, 3]]\n\n      iex> Macro.path(quote(do: [1, 2]), & &1 == 5)\n      nil\n\n      iex> Macro.path(quote(do: Foo.bar(3)), & &1 == 3)\n      [3, quote(do: Foo.bar(3))]\n\n      iex> Macro.path(quote(do: %{foo: [bar: :baz]}), & &1 == :baz)\n      [\n        :baz,\n        {:bar, :baz},\n        [bar: :baz],\n        {:foo, [bar: :baz]},\n        {:%{}, [], [foo: [bar: :baz]]}\n      ]\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec path(t, (t -> as_boolean(term))) :: [t] | nil\n  def path(ast, fun) when is_function(fun, 1) do\n    path(ast, [], fun)\n  end\n\n  defp path({form, _, args} = ast, acc, fun) when is_atom(form) do\n    acc = [ast | acc]\n\n    if fun.(ast) do\n      acc\n    else\n      path_args(args, acc, fun)\n    end\n  end\n\n  defp path({form, _meta, args} = ast, acc, fun) do\n    acc = [ast | acc]\n\n    if fun.(ast) do\n      acc\n    else\n      path(form, acc, fun) || path_args(args, acc, fun)\n    end\n  end\n\n  defp path({left, right} = ast, acc, fun) do\n    acc = [ast | acc]\n\n    if fun.(ast) do\n      acc\n    else\n      path(left, acc, fun) || path(right, acc, fun)\n    end\n  end\n\n  defp path(list, acc, fun) when is_list(list) do\n    acc = [list | acc]\n\n    if fun.(list) do\n      acc\n    else\n      path_list(list, acc, fun)\n    end\n  end\n\n  defp path(ast, acc, fun) do\n    if fun.(ast) do\n      [ast | acc]\n    end\n  end\n\n  defp path_args(atom, _acc, _fun) when is_atom(atom), do: nil\n  defp path_args(list, acc, fun) when is_list(list), do: path_list(list, acc, fun)\n\n  defp path_list([], _acc, _fun) do\n    nil\n  end\n\n  defp path_list([arg | args], acc, fun) do\n    path(arg, acc, fun) || path_list(args, acc, fun)\n  end\n\n  @doc \"\"\"\n  Generates AST nodes for a given number of required argument\n  variables using `Macro.unique_var/2`.\n\n  The second argument is generally the macro caller's module.\n\n  ## Examples\n\n      [var1, var2] = Macro.generate_unique_arguments(2, __CALLER__.module)\n\n  \"\"\"\n  @doc since: \"1.11.3\"\n  @spec generate_unique_arguments(0, context :: atom) :: []\n  @spec generate_unique_arguments(pos_integer, context) ::\n          [{atom, [counter: integer], context}, ...]\n        when context: atom\n  def generate_unique_arguments(amount, context),\n    do: generate_arguments(amount, context, &unique_var/2)\n\n  defp generate_arguments(0, context, _fun) when is_atom(context), do: []\n\n  defp generate_arguments(amount, context, fun)\n       when is_integer(amount) and amount > 0 and is_atom(context) do\n    for id <- 1..amount, do: fun.(String.to_atom(\"arg\" <> Integer.to_string(id)), context)\n  end\n\n  @doc \"\"\"\n  Generates an AST node representing the variable given\n  by the atoms `var` and `context`.\n\n  Note this variable is not unique. If you later on want\n  to access this same variable, you can invoke `var/2`\n  again with the same arguments. Use `unique_var/2` to\n  generate a unique variable that can't be overridden.\n\n  ## Examples\n\n  In order to build a variable, a context is expected.\n  Most of the times, in order to preserve hygiene, the\n  context must be `__MODULE__/0`:\n\n      iex> Macro.var(:foo, __MODULE__)\n      {:foo, [], __MODULE__}\n\n  However, if there is a need to access the user variable,\n  nil can be given:\n\n      iex> Macro.var(:foo, nil)\n      {:foo, [], nil}\n\n  \"\"\"\n  @spec var(var, context) :: {var, [], context} when var: atom, context: atom\n  def var(var, context) when is_atom(var) and is_atom(context) do\n    {var, [], context}\n  end\n\n  @doc \"\"\"\n  Generates an AST node representing a unique variable\n  given by the atoms `var` and `context`.\n\n  Calling this function with the same arguments will\n  generate another variable, with its own unique counter.\n  See `var/2` for an alternative.\n\n  The second argument is generally the macro caller's module.\n\n  ## Examples\n\n      var = Macro.unique_var(:foo, __CALLER__.module)\n\n  \"\"\"\n  @doc since: \"1.11.3\"\n  @spec unique_var(var, context) :: {var, [counter: integer], context}\n        when var: atom, context: atom\n  def unique_var(var, context) when is_atom(var) and is_atom(context) do\n    {var, [counter: :elixir_module.next_counter(context)], context}\n  end\n\n  @doc \"\"\"\n  Performs a depth-first traversal of quoted expressions\n  using an accumulator.\n\n  Returns a tuple where the first element is a new AST and the second one is\n  the final accumulator. The new AST is the result of invoking `pre` on each\n  node of `ast` during the pre-order phase and `post` during the post-order\n  phase.\n\n  ## Examples\n\n      iex> ast = quote do: 5 + 3 * 7\n      iex> {:+, _, [5, {:*, _, [3, 7]}]} = ast\n      iex> {new_ast, acc} =\n      ...>  Macro.traverse(\n      ...>    ast,\n      ...>    [],\n      ...>    fn\n      ...>      {:+, meta, children}, acc -> {{:-, meta, children}, [:- | acc]}\n      ...>      {:*, meta, children}, acc -> {{:/, meta, children}, [:/ | acc]}\n      ...>      other, acc -> {other, acc}\n      ...>    end,\n      ...>    fn\n      ...>      {:-, meta, children}, acc -> {{:min, meta, children}, [:min | acc]}\n      ...>      {:/, meta, children}, acc -> {{:max, meta, children}, [:max | acc]}\n      ...>      other, acc -> {other, acc}\n      ...>    end\n      ...>  )\n      iex> {:min, _, [5, {:max, _, [3, 7]}]} = new_ast\n      iex> [:min, :max, :/, :-] = acc\n      iex> Code.eval_quoted(new_ast)\n      {5, []}\n\n  \"\"\"\n  @spec traverse(t, any, (t, any -> {t, any}), (t, any -> {t, any})) :: {t, any}\n  def traverse(ast, acc, pre, post) when is_function(pre, 2) and is_function(post, 2) do\n    {ast, acc} = pre.(ast, acc)\n    do_traverse(ast, acc, pre, post)\n  end\n\n  defp do_traverse({form, meta, args}, acc, pre, post) when is_atom(form) do\n    {args, acc} = do_traverse_args(args, acc, pre, post)\n    post.({form, meta, args}, acc)\n  end\n\n  defp do_traverse({form, meta, args}, acc, pre, post) do\n    {form, acc} = pre.(form, acc)\n    {form, acc} = do_traverse(form, acc, pre, post)\n    {args, acc} = do_traverse_args(args, acc, pre, post)\n    post.({form, meta, args}, acc)\n  end\n\n  defp do_traverse({left, right}, acc, pre, post) do\n    {left, acc} = pre.(left, acc)\n    {left, acc} = do_traverse(left, acc, pre, post)\n    {right, acc} = pre.(right, acc)\n    {right, acc} = do_traverse(right, acc, pre, post)\n    post.({left, right}, acc)\n  end\n\n  defp do_traverse(list, acc, pre, post) when is_list(list) do\n    {list, acc} = do_traverse_args(list, acc, pre, post)\n    post.(list, acc)\n  end\n\n  defp do_traverse(x, acc, _pre, post) do\n    post.(x, acc)\n  end\n\n  defp do_traverse_args(args, acc, _pre, _post) when is_atom(args) do\n    {args, acc}\n  end\n\n  defp do_traverse_args(args, acc, pre, post) when is_list(args) do\n    :lists.mapfoldl(\n      fn x, acc ->\n        {x, acc} = pre.(x, acc)\n        do_traverse(x, acc, pre, post)\n      end,\n      acc,\n      args\n    )\n  end\n\n  @doc \"\"\"\n  Performs a depth-first, pre-order traversal of quoted expressions.\n\n  Returns a new AST where each node is the result of invoking `fun` on each\n  corresponding node of `ast`.\n\n  ## Examples\n\n      iex> ast = quote do: 5 + 3 * 7\n      iex> {:+, _, [5, {:*, _, [3, 7]}]} = ast\n      iex> new_ast = Macro.prewalk(ast, fn\n      ...>   {:+, meta, children} -> {:*, meta, children}\n      ...>   {:*, meta, children} -> {:+, meta, children}\n      ...>   other -> other\n      ...> end)\n      iex> {:*, _, [5, {:+, _, [3, 7]}]} = new_ast\n      iex> Code.eval_quoted(ast)\n      {26, []}\n      iex> Code.eval_quoted(new_ast)\n      {50, []}\n\n  \"\"\"\n  @spec prewalk(t, (t -> t)) :: t\n  def prewalk(ast, fun) when is_function(fun, 1) do\n    elem(prewalk(ast, nil, fn x, nil -> {fun.(x), nil} end), 0)\n  end\n\n  @doc \"\"\"\n  Performs a depth-first, pre-order traversal of quoted expressions\n  using an accumulator.\n\n  Returns a tuple where the first element is a new AST where each node is the\n  result of invoking `fun` on each corresponding node and the second one is the\n  final accumulator.\n\n  ## Examples\n\n      iex> ast = quote do: 5 + 3 * 7\n      iex> {:+, _, [5, {:*, _, [3, 7]}]} = ast\n      iex> {new_ast, acc} = Macro.prewalk(ast, [], fn\n      ...>   {:+, meta, children}, acc -> {{:*, meta, children}, [:+ | acc]}\n      ...>   {:*, meta, children}, acc -> {{:+, meta, children}, [:* | acc]}\n      ...>   other, acc -> {other, acc}\n      ...> end)\n      iex> {{:*, _, [5, {:+, _, [3, 7]}]}, [:*, :+]} = {new_ast, acc}\n      iex> Code.eval_quoted(ast)\n      {26, []}\n      iex> Code.eval_quoted(new_ast)\n      {50, []}\n\n  \"\"\"\n  @spec prewalk(t, any, (t, any -> {t, any})) :: {t, any}\n  def prewalk(ast, acc, fun) when is_function(fun, 2) do\n    traverse(ast, acc, fun, fn x, a -> {x, a} end)\n  end\n\n  @doc \"\"\"\n  This function behaves like `prewalk/2`, but performs a depth-first,\n  post-order traversal of quoted expressions.\n  \"\"\"\n  @spec postwalk(t, (t -> t)) :: t\n  def postwalk(ast, fun) when is_function(fun, 1) do\n    elem(postwalk(ast, nil, fn x, nil -> {fun.(x), nil} end), 0)\n  end\n\n  @doc \"\"\"\n  This functions behaves like `prewalk/3`, but performs a depth-first,\n  post-order traversal of quoted expressions using an accumulator.\n  \"\"\"\n  @spec postwalk(t, any, (t, any -> {t, any})) :: {t, any}\n  def postwalk(ast, acc, fun) when is_function(fun, 2) do\n    traverse(ast, acc, fn x, a -> {x, a} end, fun)\n  end\n\n  @doc \"\"\"\n  Decomposes a local or remote call into its remote part (when provided),\n  function name and argument list.\n\n  Returns `:error` when an invalid call syntax is provided.\n\n  ## Examples\n\n      iex> Macro.decompose_call(quote(do: foo))\n      {:foo, []}\n\n      iex> Macro.decompose_call(quote(do: foo()))\n      {:foo, []}\n\n      iex> Macro.decompose_call(quote(do: foo(1, 2, 3)))\n      {:foo, [1, 2, 3]}\n\n      iex> Macro.decompose_call(quote(do: Elixir.M.foo(1, 2, 3)))\n      {{:__aliases__, [], [:Elixir, :M]}, :foo, [1, 2, 3]}\n\n      iex> Macro.decompose_call(quote(do: 42))\n      :error\n\n      iex> Macro.decompose_call(quote(do: {:foo, [], []}))\n      :error\n\n  \"\"\"\n  @spec decompose_call(t()) :: {atom, [t()]} | {t(), atom, [t()]} | :error\n  def decompose_call(ast)\n\n  def decompose_call({:{}, _, args}) when is_list(args), do: :error\n\n  def decompose_call({{:., _, [remote, function]}, _, args})\n      when is_tuple(remote) or is_atom(remote),\n      do: {remote, function, args}\n\n  def decompose_call({name, _, args}) when is_atom(name) and is_atom(args), do: {name, []}\n\n  def decompose_call({name, _, args}) when is_atom(name) and is_list(args), do: {name, args}\n\n  def decompose_call(_), do: :error\n\n  @doc \"\"\"\n  Recursively escapes a value so it can be inserted into a syntax tree.\n\n  ## Examples\n\n      iex> Macro.escape(:foo)\n      :foo\n\n      iex> Macro.escape({:a, :b, :c})\n      {:{}, [], [:a, :b, :c]}\n\n      iex> Macro.escape({:unquote, [], [1]}, unquote: true)\n      1\n\n  ## Options\n\n    * `:unquote` - when `true`, this function leaves `unquote/1` and\n      `unquote_splicing/1` expressions unescaped, effectively unquoting\n      the contents on escape. This option is useful only when escaping\n      ASTs which may have quoted fragments in them. Note this option\n      will give a special meaning to `quote`/`unquote` nodes, which need\n      to be valid AST before escaping. Defaults to `false`.\n\n    * `:prune_metadata` - when `true`, removes most metadata from escaped AST\n      nodes. Note this option changes the semantics of escaped code and\n      it should only be used when escaping ASTs. Defaults to `false`.\n\n    * `:generated` - (since v1.19.0) Whether the AST should be considered as generated\n      by the compiler or not. This means the compiler and tools like Dialyzer may not\n      emit certain warnings.\n\n      As an example for `:prune_metadata`, `ExUnit` stores the AST of every\n      assertion, so when an assertion fails we can show code snippets to users.\n      Without this option, each time the test module is compiled, we would get a\n      different MD5 of the module bytecode, because the AST contains metadata,\n      such as counters, specific to the compilation environment. By pruning\n      the metadata, we ensure that the module is deterministic and reduce\n      the amount of data `ExUnit` needs to keep around. Only the minimal\n      amount of metadata is kept, such as `:line`, `:no_parens` and `:delimiter`.\n\n  ## Comparison to `quote/2`\n\n  The `escape/2` function is sometimes confused with `quote/2`,\n  because the above examples behave the same with both. The key difference is\n  best illustrated when the value to escape is stored in a variable.\n\n      iex> Macro.escape({:a, :b, :c})\n      {:{}, [], [:a, :b, :c]}\n      iex> quote do: {:a, :b, :c}\n      {:{}, [], [:a, :b, :c]}\n\n      iex> value = {:a, :b, :c}\n      iex> Macro.escape(value)\n      {:{}, [], [:a, :b, :c]}\n\n      iex> quote do: value\n      {:value, [], __MODULE__}\n\n      iex> value = {:a, :b, :c}\n      iex> quote do: unquote(value)\n      ** (ArgumentError) tried to unquote invalid AST: {:a, :b, :c}\n      Did you forget to escape term using Macro.escape/1?\n\n  `escape/2` is used to escape *values* (either directly passed or variable\n  bound), while `quote/2` produces syntax trees for\n  expressions.\n\n  ## Dealing with references and other runtime values\n\n  Macros work at compile-time and therefore `Macro.escape/1` can only escape values\n  that are valid during compilation, such as numbers, atoms, tuples, maps, binaries,\n  etc.\n\n  However, you may have values at compile-time which cannot be escaped, such as\n  `reference`s and `pid`s, since the process or memory address they point to will\n  no longer exist once compilation completes. Attempting to escape said values will\n  raise an exception. This is a common issue when working with NIFs.\n\n  Luckily, Elixir v1.19 introduces a mechanism that allows those values to be escaped,\n  as long as they are encapsulated by a struct within a module that defines the\n  `__escape__/1` function. This is possible as long as the reference has a natural\n  text or binary representation that can be serialized during compilation.\n\n  Let's imagine we have the following struct:\n\n      defmodule WrapperStruct do\n        defstruct [:ref]\n\n        def new(...), do: %WrapperStruct{ref: ...}\n\n        # efficiently dump to / load from binaries\n        def dump_to_binary(%WrapperStruct{ref: ref}), do: ...\n        def load_from_binary(binary), do: %WrapperStruct{ref: ...}\n      end\n\n  Such a struct could not be used in module attributes or escaped with `Macro.escape/2`:\n\n      defmodule Foo do\n        @my_struct WrapperStruct.new(...)\n        def my_struct, do: @my_struct\n      end\n\n      ** (ArgumentError) cannot inject attribute @my_struct into function/macro because cannot escape #Reference<...>\n\n  To address this, structs can re-define how they should be escaped by defining a custom\n  `__escape__/1` function which returns the AST. In our example:\n\n      defmodule WrapperStruct do\n        # ...\n\n        def __escape__(struct) do\n          # dump to a binary representation at compile-time\n          binary = dump_to_binary(struct)\n          quote do\n            # load from the binary representation at runtime\n            WrapperStruct.load_from_binary(unquote(Macro.escape(binary)))\n          end\n        end\n      end\n\n  Now, our example above will be expanded as:\n\n      def my_struct, do: WrapperStruct.load_from_binary(<<...>>)\n\n  When implementing `__escape__/1`, you must ensure that the quoted expression\n  will evaluate to a struct that represents the one given as argument.\n  \"\"\"\n  @spec escape(term, escape_opts) :: t()\n  def escape(expr, opts \\\\ []) do\n    unquote = Keyword.get(opts, :unquote, false)\n    kind = if Keyword.get(opts, :prune_metadata, false), do: :escape_and_prune, else: :escape\n    generated = Keyword.get(opts, :generated, false)\n\n    case :elixir_quote.escape(expr, kind, unquote) do\n      # mark module attrs as shallow-generated since the ast for their representation\n      # might contain opaque terms\n      {caller, meta, args} when generated and is_list(meta) ->\n        {caller, [generated: true] ++ meta, args}\n\n      ast ->\n        ast\n    end\n  end\n\n  # TODO: Deprecate me on Elixir v1.22\n  @doc deprecated: \"Use Macro.struct_info!/2 instead\"\n  def struct!(module, env) when is_atom(module) do\n    pairs =\n      for %{field: field, default: default} <- struct_info!(module, env), do: {field, default}\n\n    :maps.from_list([__struct__: module] ++ pairs)\n  end\n\n  @doc \"\"\"\n  Extracts the struct information.\n\n  This is useful when a struct needs to be expanded at\n  compilation time and the struct being expanded may or may\n  not have been compiled (including structs in the defined\n  under the module being compiled). For compiled modules,\n  it will invoke `module.__info__(:struct)`.\n\n  Calling this function also adds an export dependency on the\n  given struct.\n\n  It will raise `ArgumentError` if the struct is not available.\n\n  ## Compatibility considerations\n\n  This function currently returns both `:required` and `:default`\n  entries for each field. While this naming is inconsistent\n  (a required field should not have a default), this is done for\n  backwards compatibility purposes.\n\n  In future releases, Elixir may introduce truly required struct\n  fields, the required field will be removed and default will be\n  present only if the field is optional. Your code should prepare\n  for such scenario accordingly.\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec struct_info!(module(), Macro.Env.t()) ::\n          [\n            %{\n              required(:field) => atom(),\n              optional(:required) => boolean(),\n              optional(:default) => term()\n            }\n          ]\n  def struct_info!(module, env) when is_atom(module) do\n    meta = [line: env.line]\n\n    case :elixir_map.maybe_load_struct_info(meta, module, env) do\n      {:ok, info} ->\n        :elixir_env.trace({:struct_expansion, meta, module, []}, env)\n        info\n\n      {:error, desc} ->\n        raise ArgumentError, List.to_string(:elixir_map.format_error(desc))\n    end\n  end\n\n  @doc \"\"\"\n  Validates the given expressions are valid quoted expressions.\n\n  Check the type `t:Macro.t/0` for a complete specification of a\n  valid quoted expression.\n\n  It returns `:ok` if the expression is valid. Otherwise it returns\n  a tuple in the form of `{:error, remainder}` where `remainder` is\n  the invalid part of the quoted expression.\n\n  ## Examples\n\n      iex> Macro.validate({:two_element, :tuple})\n      :ok\n      iex> Macro.validate({:three, :element, :tuple})\n      {:error, {:three, :element, :tuple}}\n\n      iex> Macro.validate([1, 2, 3])\n      :ok\n      iex> Macro.validate([1, 2, 3, {4}])\n      {:error, {4}}\n\n  \"\"\"\n  @spec validate(term) :: :ok | {:error, term}\n  def validate(expr) do\n    find_invalid(expr) || :ok\n  end\n\n  defp find_invalid({left, right}), do: find_invalid(left) || find_invalid(right)\n\n  defp find_invalid({left, meta, right})\n       when is_list(meta) and (is_atom(right) or is_list(right)),\n       do: find_invalid(left) || find_invalid(right)\n\n  defp find_invalid(list) when is_list(list), do: Enum.find_value(list, &find_invalid/1)\n\n  defp find_invalid(pid) when is_pid(pid), do: nil\n  defp find_invalid(atom) when is_atom(atom), do: nil\n  defp find_invalid(num) when is_number(num), do: nil\n  defp find_invalid(bin) when is_binary(bin), do: nil\n\n  defp find_invalid(fun) when is_function(fun) do\n    if Function.info(fun, :env) != {:env, []} or\n         Function.info(fun, :type) != {:type, :external} do\n      {:error, fun}\n    end\n  end\n\n  defp find_invalid(other), do: {:error, other}\n\n  @doc \"\"\"\n  Returns an enumerable that traverses the  `ast` in depth-first,\n  pre-order traversal.\n\n  ## Examples\n\n      iex> ast = quote do: foo(1, \"abc\")\n      iex> Enum.map(Macro.prewalker(ast), & &1)\n      [{:foo, [], [1, \"abc\"]}, 1, \"abc\"]\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec prewalker(t()) :: Enumerable.t()\n  def prewalker(ast) do\n    &prewalker([ast], &1, &2)\n  end\n\n  defp prewalker(_buffer, {:halt, acc}, _fun) do\n    {:halted, acc}\n  end\n\n  defp prewalker(buffer, {:suspend, acc}, fun) do\n    {:suspended, acc, &prewalker(buffer, &1, fun)}\n  end\n\n  defp prewalker([], {:cont, acc}, _fun) do\n    {:done, acc}\n  end\n\n  defp prewalker([{left, right} = node | tail], {:cont, acc}, fun) do\n    prewalker([left, right | tail], fun.(node, acc), fun)\n  end\n\n  defp prewalker([{left, meta, right} = node | tail], {:cont, acc}, fun)\n       when is_atom(left) and is_list(meta) do\n    if is_atom(right) do\n      prewalker(tail, fun.(node, acc), fun)\n    else\n      prewalker(right ++ tail, fun.(node, acc), fun)\n    end\n  end\n\n  defp prewalker([{left, meta, right} = node | tail], {:cont, acc}, fun) when is_list(meta) do\n    if is_atom(right) do\n      prewalker([left | tail], fun.(node, acc), fun)\n    else\n      prewalker([left | right] ++ tail, fun.(node, acc), fun)\n    end\n  end\n\n  defp prewalker([list | tail], {:cont, acc}, fun) when is_list(list) do\n    prewalker(list ++ tail, fun.(list, acc), fun)\n  end\n\n  defp prewalker([head | tail], {:cont, acc}, fun) do\n    prewalker(tail, fun.(head, acc), fun)\n  end\n\n  @doc \"\"\"\n  Returns an enumerable that traverses the  `ast` in depth-first,\n  post-order traversal.\n\n  ## Examples\n\n      iex> ast = quote do: foo(1, \"abc\")\n      iex> Enum.map(Macro.postwalker(ast), & &1)\n      [1, \"abc\", {:foo, [], [1, \"abc\"]}]\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec postwalker(t()) :: Enumerable.t()\n  def postwalker(ast) do\n    &postwalker([ast], make_ref(), &1, &2)\n  end\n\n  defp postwalker(_buffer, _ref, {:halt, acc}, _fun) do\n    {:halted, acc}\n  end\n\n  defp postwalker(buffer, ref, {:suspend, acc}, fun) do\n    {:suspended, acc, &postwalker(buffer, ref, &1, fun)}\n  end\n\n  defp postwalker([], _ref, {:cont, acc}, _fun) do\n    {:done, acc}\n  end\n\n  defp postwalker([{ref, head} | tail], ref, {:cont, acc}, fun) do\n    postwalker(tail, ref, fun.(head, acc), fun)\n  end\n\n  defp postwalker([{left, right} = node | tail], ref, {:cont, acc}, fun) do\n    postwalker([right, {ref, node} | tail], ref, fun.(left, acc), fun)\n  end\n\n  defp postwalker([{left, meta, right} = node | tail], ref, {:cont, acc}, fun)\n       when is_atom(left) and is_list(meta) do\n    if is_atom(right) do\n      postwalker(tail, ref, fun.(node, acc), fun)\n    else\n      postwalker(right ++ [{ref, node} | tail], ref, {:cont, acc}, fun)\n    end\n  end\n\n  defp postwalker([{left, meta, right} = node | tail], ref, cont_acc, fun)\n       when is_list(meta) do\n    if is_atom(right) do\n      postwalker([left, {ref, node} | tail], ref, cont_acc, fun)\n    else\n      postwalker([left | right] ++ [{ref, node} | tail], ref, cont_acc, fun)\n    end\n  end\n\n  defp postwalker([list | tail], ref, cont_acc, fun) when is_list(list) do\n    postwalker(list ++ [{ref, list} | tail], ref, cont_acc, fun)\n  end\n\n  defp postwalker([head | tail], ref, {:cont, acc}, fun) do\n    postwalker(tail, ref, fun.(head, acc), fun)\n  end\n\n  @doc ~S\"\"\"\n  Unescapes characters in a string.\n\n  This is the unescaping behaviour used by default in Elixir\n  single- and double-quoted strings. Check `unescape_string/2`\n  for information on how to customize the escaping map.\n\n  In this setup, Elixir will escape the following: `\\0`, `\\a`, `\\b`,\n  `\\d`, `\\e`, `\\f`, `\\n`, `\\r`, `\\s`, `\\t` and `\\v`. Bytes can be\n  given as hexadecimals via `\\xNN` and Unicode code points as\n  `\\uNNNN` escapes.\n\n  This function is commonly used on sigil implementations\n  (like `~r`, `~s` and others), which receive a raw, unescaped\n  string, and it can be used anywhere that needs to mimic how\n  Elixir parses strings.\n\n  ## Examples\n\n      iex> Macro.unescape_string(\"example\\\\n\")\n      \"example\\n\"\n\n  In the example above, we pass a string with `\\n` escaped\n  and return a version with it unescaped.\n  \"\"\"\n  @spec unescape_string(String.t()) :: String.t()\n  def unescape_string(string) do\n    :elixir_interpolation.unescape_string(string)\n  end\n\n  @doc ~S\"\"\"\n  Unescapes characters in a string according to the given mapping.\n\n  Check `unescape_string/1` if you want to use the same mapping\n  as Elixir single- and double-quoted strings.\n\n  ## Mapping function\n\n  The mapping function receives an integer representing the code point\n  of the character it wants to unescape. There are also the special atoms\n  `:newline`, `:unicode`, and `:hex`, which control newline, unicode,\n  and escaping respectively.\n\n  Here is the default mapping function implemented by Elixir:\n\n      def unescape_map(:newline), do: true\n      def unescape_map(:unicode), do: true\n      def unescape_map(:hex), do: true\n      def unescape_map(?0), do: ?0\n      def unescape_map(?a), do: ?\\a\n      def unescape_map(?b), do: ?\\b\n      def unescape_map(?d), do: ?\\d\n      def unescape_map(?e), do: ?\\e\n      def unescape_map(?f), do: ?\\f\n      def unescape_map(?n), do: ?\\n\n      def unescape_map(?r), do: ?\\r\n      def unescape_map(?s), do: ?\\s\n      def unescape_map(?t), do: ?\\t\n      def unescape_map(?v), do: ?\\v\n      def unescape_map(e), do: e\n\n  If the `unescape_map/1` function returns `false`, the char is\n  not escaped and the backslash is kept in the string.\n\n  ## Examples\n\n  Using the `unescape_map/1` function defined above is easy:\n\n      Macro.unescape_string(\"example\\\\n\", &unescape_map(&1))\n\n  \"\"\"\n  @spec unescape_string(String.t(), (non_neg_integer -> non_neg_integer | false)) :: String.t()\n  def unescape_string(string, map) do\n    :elixir_interpolation.unescape_string(string, map)\n  end\n\n  @doc false\n  @deprecated \"Traverse over the arguments using Enum.map/2 instead\"\n  def unescape_tokens(tokens) do\n    for token <- tokens do\n      if is_binary(token), do: unescape_string(token), else: token\n    end\n  end\n\n  @doc false\n  @deprecated \"Traverse over the arguments using Enum.map/2 instead\"\n  def unescape_tokens(tokens, map) do\n    for token <- tokens do\n      if is_binary(token), do: unescape_string(token, map), else: token\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given expression AST to a string.\n\n  This is a convenience function for converting AST into\n  a string, which discards all formatting of the original\n  code and wraps newlines around 98 characters. See\n  `Code.quoted_to_algebra/2` as a lower level function\n  with more control around formatting.\n\n  If the AST contains invalid nodes, this function will\n  attempt to inspect them, to aid debugging, although\n  the elements won't be formatted accordingly.\n\n  ## Examples\n\n      iex> Macro.to_string(quote(do: foo.bar(1, 2, 3)))\n      \"foo.bar(1, 2, 3)\"\n\n  \"\"\"\n  @spec to_string(t()) :: String.t()\n  def to_string(tree) do\n    doc =\n      Inspect.Algebra.format(Code.quoted_to_algebra(tree, migrate_charlists_as_sigils: true), 98)\n\n    IO.iodata_to_binary(doc)\n  end\n\n  @doc \"\"\"\n  Converts the given expression AST to a string.\n\n  The given `fun` is called for every node in the AST with two arguments: the\n  AST of the node being printed and the string representation of that same\n  node. The return value of this function is used as the final string\n  representation for that AST node.\n\n  This function discards all formatting of the original code.\n\n  ## Examples\n\n      Macro.to_string(quote(do: 1 + 2), fn\n        1, _string -> \"one\"\n        2, _string -> \"two\"\n        _ast, string -> string\n      end)\n      #=> \"one + two\"\n\n  \"\"\"\n  @deprecated \"Use Macro.to_string/1 instead\"\n  @spec to_string(t(), (t(), String.t() -> String.t())) :: String.t()\n  def to_string(tree, fun)\n\n  # Variables\n  def to_string({var, _, context} = ast, fun) when is_atom(var) and is_atom(context) do\n    fun.(ast, Atom.to_string(var))\n  end\n\n  # Aliases\n  def to_string({:__aliases__, _, refs} = ast, fun) do\n    fun.(ast, Enum.map_join(refs, \".\", &call_to_string(&1, fun)))\n  end\n\n  # Blocks\n  def to_string({:__block__, _, [expr]} = ast, fun) do\n    fun.(ast, to_string(expr, fun))\n  end\n\n  def to_string({:__block__, _, _} = ast, fun) do\n    block = adjust_new_lines(block_to_string(ast, fun), \"\\n  \")\n    fun.(ast, \"(\\n  \" <> block <> \"\\n)\")\n  end\n\n  # Bits containers\n  def to_string({:<<>>, _, parts} = ast, fun) do\n    if interpolated?(ast) do\n      fun.(ast, interpolate(ast, fun))\n    else\n      result =\n        Enum.map_join(parts, \", \", fn part ->\n          str = bitpart_to_string(part, fun)\n\n          if :binary.first(str) == ?< or :binary.last(str) == ?> do\n            \"(\" <> str <> \")\"\n          else\n            str\n          end\n        end)\n\n      fun.(ast, \"<<\" <> result <> \">>\")\n    end\n  end\n\n  # Tuple containers\n  def to_string({:{}, _, args} = ast, fun) do\n    tuple = \"{\" <> Enum.map_join(args, \", \", &to_string(&1, fun)) <> \"}\"\n    fun.(ast, tuple)\n  end\n\n  # Map containers\n  def to_string({:%{}, _, args} = ast, fun) do\n    map = \"%{\" <> map_to_string(args, fun) <> \"}\"\n    fun.(ast, map)\n  end\n\n  def to_string({:%, _, [struct_name, map]} = ast, fun) do\n    {:%{}, _, args} = map\n    struct = \"%\" <> to_string(struct_name, fun) <> \"{\" <> map_to_string(args, fun) <> \"}\"\n    fun.(ast, struct)\n  end\n\n  # Fn keyword\n  def to_string({:fn, _, [{:->, _, [_, tuple]}] = arrow} = ast, fun)\n      when not is_tuple(tuple) or elem(tuple, 0) != :__block__ do\n    fun.(ast, \"fn \" <> arrow_to_string(arrow, fun) <> \" end\")\n  end\n\n  def to_string({:fn, _, [{:->, _, _}] = block} = ast, fun) do\n    fun.(ast, \"fn \" <> block_to_string(block, fun) <> \"\\nend\")\n  end\n\n  def to_string({:fn, _, block} = ast, fun) do\n    block = adjust_new_lines(block_to_string(block, fun), \"\\n  \")\n    fun.(ast, \"fn\\n  \" <> block <> \"\\nend\")\n  end\n\n  # left -> right\n  def to_string([{:->, _, _} | _] = ast, fun) do\n    fun.(ast, \"(\" <> arrow_to_string(ast, fun, true) <> \")\")\n  end\n\n  # left when right\n  def to_string({:when, _, [left, right]} = ast, fun) do\n    right =\n      if right != [] and Keyword.keyword?(right) do\n        kw_list_to_string(right, fun)\n      else\n        fun.(ast, op_to_string(right, fun, :when, :right))\n      end\n\n    fun.(ast, op_to_string(left, fun, :when, :left) <> \" when \" <> right)\n  end\n\n  # Splat when\n  def to_string({:when, _, args} = ast, fun) do\n    {left, right} = split_last(args)\n\n    result =\n      \"(\" <> Enum.map_join(left, \", \", &to_string(&1, fun)) <> \") when \" <> to_string(right, fun)\n\n    fun.(ast, result)\n  end\n\n  # Capture\n  def to_string({:&, _, [{:/, _, [{name, _, ctx}, arity]}]} = ast, fun)\n      when is_atom(name) and is_atom(ctx) and is_integer(arity) do\n    result = \"&\" <> Atom.to_string(name) <> \"/\" <> to_string(arity, fun)\n    fun.(ast, result)\n  end\n\n  def to_string({:&, _, [{:/, _, [{{:., _, [mod, name]}, _, []}, arity]}]} = ast, fun)\n      when is_atom(name) and is_integer(arity) do\n    result =\n      \"&\" <> to_string(mod, fun) <> \".\" <> Atom.to_string(name) <> \"/\" <> to_string(arity, fun)\n\n    fun.(ast, result)\n  end\n\n  def to_string({:&, _, [arg]} = ast, fun) when not is_integer(arg) do\n    fun.(ast, \"&(\" <> to_string(arg, fun) <> \")\")\n  end\n\n  # left not in right\n  def to_string({:not, _, [{:in, _, [left, right]}]} = ast, fun) do\n    fun.(ast, to_string(left, fun) <> \" not in \" <> to_string(right, fun))\n  end\n\n  # Access\n  def to_string({{:., _, [Access, :get]}, _, [left, right]} = ast, fun) do\n    if op_expr?(left) do\n      fun.(ast, \"(\" <> to_string(left, fun) <> \")\" <> to_string([right], fun))\n    else\n      fun.(ast, to_string(left, fun) <> to_string([right], fun))\n    end\n  end\n\n  # foo.{bar, baz}\n  def to_string({{:., _, [left, :{}]}, _, args} = ast, fun) do\n    fun.(ast, to_string(left, fun) <> \".{\" <> args_to_string(args, fun) <> \"}\")\n  end\n\n  # All other calls\n  def to_string({{:., _, [left, _]} = target, meta, []} = ast, fun) do\n    to_string = call_to_string(target, fun)\n\n    if is_tuple(left) && meta[:no_parens] do\n      fun.(ast, to_string)\n    else\n      fun.(ast, to_string <> \"()\")\n    end\n  end\n\n  def to_string({target, _, args} = ast, fun) when is_list(args) do\n    with :error <- unary_call(ast, fun),\n         :error <- op_call(ast, fun),\n         :error <- sigil_call(ast, fun) do\n      {list, last} = split_last(args)\n\n      result =\n        if kw_blocks?(last) do\n          case list do\n            [] -> call_to_string(target, fun) <> kw_blocks_to_string(last, fun)\n            _ -> call_to_string_with_args(target, list, fun) <> kw_blocks_to_string(last, fun)\n          end\n        else\n          call_to_string_with_args(target, args, fun)\n        end\n\n      fun.(ast, result)\n    else\n      {:ok, value} -> value\n    end\n  end\n\n  # Two-element tuples\n  def to_string({left, right}, fun) do\n    to_string({:{}, [], [left, right]}, fun)\n  end\n\n  # Lists\n  def to_string(list, fun) when is_list(list) do\n    result =\n      cond do\n        list == [] ->\n          \"[]\"\n\n        :io_lib.printable_list(list) ->\n          {escaped, _} = Identifier.escape(IO.chardata_to_string(list), ?\")\n          IO.iodata_to_binary([?~, ?c, ?\", escaped, ?\"])\n\n        Inspect.List.keyword?(list) ->\n          \"[\" <> kw_list_to_string(list, fun) <> \"]\"\n\n        true ->\n          \"[\" <> Enum.map_join(list, \", \", &to_string(&1, fun)) <> \"]\"\n      end\n\n    fun.(list, result)\n  end\n\n  # All other structures\n  def to_string(other, fun) do\n    fun.(other, inspect_no_limit(other))\n  end\n\n  defp inspect_no_limit(value) do\n    Kernel.inspect(value, limit: :infinity, printable_limit: :infinity)\n  end\n\n  defp bitpart_to_string({:\"::\", meta, [left, right]} = ast, fun) do\n    result =\n      if meta[:inferred_bitstring_spec] do\n        to_string(left, fun)\n      else\n        op_to_string(left, fun, :\"::\", :left) <>\n          \"::\" <> bitmods_to_string(right, fun, :\"::\", :right)\n      end\n\n    fun.(ast, result)\n  end\n\n  defp bitpart_to_string(ast, fun) do\n    to_string(ast, fun)\n  end\n\n  defp bitmods_to_string({op, _, [left, right]} = ast, fun, _, _) when op in [:*, :-] do\n    result =\n      bitmods_to_string(left, fun, op, :left) <>\n        Atom.to_string(op) <> bitmods_to_string(right, fun, op, :right)\n\n    fun.(ast, result)\n  end\n\n  defp bitmods_to_string(other, fun, parent_op, side) do\n    op_to_string(other, fun, parent_op, side)\n  end\n\n  # Block keywords\n  kw_keywords = [:do, :rescue, :catch, :else, :after]\n\n  defp kw_blocks?([{:do, _} | _] = kw) do\n    Enum.all?(kw, &match?({x, _} when x in unquote(kw_keywords), &1))\n  end\n\n  defp kw_blocks?(_), do: false\n\n  # Check if we have an interpolated string.\n  defp interpolated?({:<<>>, _, [_ | _] = parts}) do\n    Enum.all?(parts, fn\n      {:\"::\", _, [{{:., _, [Kernel, :to_string]}, _, [_]}, {:binary, _, _}]} -> true\n      binary when is_binary(binary) -> true\n      _ -> false\n    end)\n  end\n\n  defp interpolated?(_) do\n    false\n  end\n\n  defp interpolate(ast, fun), do: interpolate(ast, \"\\\"\", \"\\\"\", fun)\n\n  defp interpolate({:<<>>, _, [parts]}, left, right, _) when left in [~s[\"\"\"\\n], ~s['''\\n]] do\n    <<left::binary, parts::binary, right::binary>>\n  end\n\n  defp interpolate({:<<>>, _, parts}, left, right, fun) do\n    parts =\n      Enum.map_join(parts, \"\", fn\n        {:\"::\", _, [{{:., _, [Kernel, :to_string]}, _, [arg]}, {:binary, _, _}]} ->\n          \"\\#{\" <> to_string(arg, fun) <> \"}\"\n\n        binary when is_binary(binary) ->\n          escape_sigil(binary, left)\n      end)\n\n    <<left::binary, parts::binary, right::binary>>\n  end\n\n  defp escape_sigil(parts, \"(\"), do: String.replace(parts, \")\", ~S\"\\)\")\n  defp escape_sigil(parts, \"{\"), do: String.replace(parts, \"}\", ~S\"\\}\")\n  defp escape_sigil(parts, \"[\"), do: String.replace(parts, \"]\", ~S\"\\]\")\n  defp escape_sigil(parts, \"<\"), do: String.replace(parts, \">\", ~S\"\\>\")\n  defp escape_sigil(parts, delimiter), do: String.replace(parts, delimiter, \"\\\\#{delimiter}\")\n\n  defp module_to_string(atom, _fun) when is_atom(atom) do\n    inspect_no_limit(atom)\n  end\n\n  defp module_to_string({:&, _, [val]} = expr, fun) when not is_integer(val) do\n    \"(\" <> to_string(expr, fun) <> \")\"\n  end\n\n  defp module_to_string({:fn, _, _} = expr, fun) do\n    \"(\" <> to_string(expr, fun) <> \")\"\n  end\n\n  defp module_to_string({_, _, [_ | _] = args} = expr, fun) do\n    if kw_blocks?(List.last(args)) do\n      \"(\" <> to_string(expr, fun) <> \")\"\n    else\n      to_string(expr, fun)\n    end\n  end\n\n  defp module_to_string(expr, fun) do\n    to_string(expr, fun)\n  end\n\n  defp unary_call({op, _, [arg]} = ast, fun) when is_atom(op) do\n    if operator?(op, 1) do\n      if op == :not or op_expr?(arg) do\n        {:ok, fun.(ast, Atom.to_string(op) <> \"(\" <> to_string(arg, fun) <> \")\")}\n      else\n        {:ok, fun.(ast, Atom.to_string(op) <> to_string(arg, fun))}\n      end\n    else\n      :error\n    end\n  end\n\n  defp unary_call(_, _) do\n    :error\n  end\n\n  defp op_call({:..//, _, [left, middle, right]} = ast, fun) do\n    left = op_to_string(left, fun, :.., :left)\n    middle = op_to_string(middle, fun, :.., :right)\n    right = op_to_string(right, fun, :\"//\", :right)\n    {:ok, fun.(ast, left <> \"..\" <> middle <> \"//\" <> right)}\n  end\n\n  defp op_call({op, _, [left, right]} = ast, fun) when is_atom(op) do\n    if operator?(op, 2) do\n      left = op_to_string(left, fun, op, :left)\n      right = op_to_string(right, fun, op, :right)\n      op = if op in [:..], do: \"#{op}\", else: \" #{op} \"\n      {:ok, fun.(ast, left <> op <> right)}\n    else\n      :error\n    end\n  end\n\n  defp op_call(_, _) do\n    :error\n  end\n\n  defp sigil_call({sigil, meta, [{:<<>>, _, _} = parts, args]} = ast, fun)\n       when is_atom(sigil) and is_list(args) do\n    delimiter = Keyword.get(meta, :delimiter, \"\\\"\")\n    {left, right} = delimiter_pair(delimiter)\n\n    case Atom.to_string(sigil) do\n      <<\"sigil_\", first, rest::binary>> when first >= ?A and first <= ?Z ->\n        if upcase_letters?(rest) do\n          args = sigil_args(args, fun)\n          {:<<>>, _, [binary]} = parts\n\n          formatted =\n            <<?~, first, rest::binary, left::binary, binary::binary, right::binary, args::binary>>\n\n          {:ok, fun.(ast, formatted)}\n        else\n          :error\n        end\n\n      <<\"sigil_\", name>> when name >= ?a and name <= ?z ->\n        args = sigil_args(args, fun)\n        formatted = \"~\" <> <<name>> <> interpolate(parts, left, right, fun) <> args\n        {:ok, fun.(ast, formatted)}\n\n      _ ->\n        :error\n    end\n  end\n\n  defp sigil_call(_other, _fun) do\n    :error\n  end\n\n  defp upcase_letters?(<<letter, rest::binary>>) when letter >= ?A and letter <= ?Z,\n    do: upcase_letters?(rest)\n\n  defp upcase_letters?(<<_>>),\n    do: false\n\n  defp upcase_letters?(<<>>),\n    do: true\n\n  defp delimiter_pair(\"[\"), do: {\"[\", \"]\"}\n  defp delimiter_pair(\"{\"), do: {\"{\", \"}\"}\n  defp delimiter_pair(\"(\"), do: {\"(\", \")\"}\n  defp delimiter_pair(\"<\"), do: {\"<\", \">\"}\n  defp delimiter_pair(\"\\\"\\\"\\\"\"), do: {\"\\\"\\\"\\\"\\n\", \"\\\"\\\"\\\"\"}\n  defp delimiter_pair(\"'''\"), do: {\"'''\\n\", \"'''\"}\n  defp delimiter_pair(str), do: {str, str}\n\n  defp sigil_args([], _fun), do: \"\"\n  defp sigil_args(args, fun), do: fun.(args, List.to_string(args))\n\n  defp op_expr?(expr) do\n    case expr do\n      {op, _, [_, _]} -> operator?(op, 2)\n      {op, _, [_]} -> operator?(op, 1)\n      _ -> false\n    end\n  end\n\n  defp call_to_string(atom, _fun) when is_atom(atom), do: Atom.to_string(atom)\n  defp call_to_string({:., _, [arg]}, fun), do: module_to_string(arg, fun) <> \".\"\n\n  defp call_to_string({:., _, [left, right]}, fun) when is_atom(right),\n    do: module_to_string(left, fun) <> \".\" <> call_to_string_for_atom(right)\n\n  defp call_to_string({:., _, [left, right]}, fun),\n    do: module_to_string(left, fun) <> \".\" <> call_to_string(right, fun)\n\n  defp call_to_string(other, fun), do: to_string(other, fun)\n\n  defp call_to_string_with_args(target, args, fun) do\n    target = call_to_string(target, fun)\n    args = args_to_string(args, fun)\n    target <> \"(\" <> args <> \")\"\n  end\n\n  defp call_to_string_for_atom(atom) do\n    Macro.inspect_atom(:remote_call, atom)\n  end\n\n  defp args_to_string(args, fun) do\n    {list, last} = split_last(args)\n\n    if last != [] and Inspect.List.keyword?(last) do\n      prefix =\n        case list do\n          [] -> \"\"\n          _ -> Enum.map_join(list, \", \", &to_string(&1, fun)) <> \", \"\n        end\n\n      prefix <> kw_list_to_string(last, fun)\n    else\n      Enum.map_join(args, \", \", &to_string(&1, fun))\n    end\n  end\n\n  defp kw_blocks_to_string(kw, fun) do\n    Enum.reduce(unquote(kw_keywords), \" \", fn x, acc ->\n      case Keyword.has_key?(kw, x) do\n        true -> acc <> kw_block_to_string(x, Keyword.get(kw, x), fun)\n        false -> acc\n      end\n    end) <> \"end\"\n  end\n\n  defp kw_block_to_string(key, value, fun) do\n    block = adjust_new_lines(block_to_string(value, fun), \"\\n  \")\n    Atom.to_string(key) <> \"\\n  \" <> block <> \"\\n\"\n  end\n\n  defp block_to_string([{:->, _, _} | _] = block, fun) do\n    Enum.map_join(block, \"\\n\", fn {:->, _, [left, right]} ->\n      left = comma_join_or_empty_paren(left, fun, false)\n      left <> \"->\\n  \" <> adjust_new_lines(block_to_string(right, fun), \"\\n  \")\n    end)\n  end\n\n  defp block_to_string({:__block__, _, exprs}, fun) do\n    Enum.map_join(exprs, \"\\n\", &to_string(&1, fun))\n  end\n\n  defp block_to_string(other, fun), do: to_string(other, fun)\n\n  defp map_to_string([{:|, _, [update_map, update_args]}], fun) do\n    to_string(update_map, fun) <> \" | \" <> map_to_string(update_args, fun)\n  end\n\n  defp map_to_string(list, fun) do\n    cond do\n      Inspect.List.keyword?(list) -> kw_list_to_string(list, fun)\n      true -> map_list_to_string(list, fun)\n    end\n  end\n\n  defp kw_list_to_string(list, fun) do\n    Enum.map_join(list, \", \", fn {key, value} ->\n      Macro.inspect_atom(:key, key) <> \" \" <> to_string(value, fun)\n    end)\n  end\n\n  defp map_list_to_string(list, fun) do\n    Enum.map_join(list, \", \", fn\n      {key, value} -> to_string(key, fun) <> \" => \" <> to_string(value, fun)\n      other -> to_string(other, fun)\n    end)\n  end\n\n  defp wrap_in_parenthesis(expr, fun) do\n    \"(\" <> to_string(expr, fun) <> \")\"\n  end\n\n  defp op_to_string({op, _, [_, _]} = expr, fun, parent_op, side) when is_atom(op) do\n    case Identifier.binary_op(op) do\n      {_, prec} ->\n        {parent_assoc, parent_prec} = Identifier.binary_op(parent_op)\n\n        cond do\n          parent_prec < prec -> to_string(expr, fun)\n          parent_prec > prec -> wrap_in_parenthesis(expr, fun)\n          parent_assoc == side -> to_string(expr, fun)\n          true -> wrap_in_parenthesis(expr, fun)\n        end\n\n      :error ->\n        to_string(expr, fun)\n    end\n  end\n\n  defp op_to_string(expr, fun, _, _), do: to_string(expr, fun)\n\n  defp arrow_to_string(pairs, fun, paren \\\\ false) do\n    Enum.map_join(pairs, \"; \", fn {:->, _, [left, right]} ->\n      left = comma_join_or_empty_paren(left, fun, paren)\n      left <> \"-> \" <> to_string(right, fun)\n    end)\n  end\n\n  defp comma_join_or_empty_paren([], _fun, true), do: \"() \"\n  defp comma_join_or_empty_paren([], _fun, false), do: \"\"\n\n  defp comma_join_or_empty_paren(left, fun, _) do\n    Enum.map_join(left, \", \", &to_string(&1, fun)) <> \" \"\n  end\n\n  defp split_last([]) do\n    {[], []}\n  end\n\n  defp split_last(args) do\n    {left, [right]} = Enum.split(args, -1)\n    {left, right}\n  end\n\n  defp adjust_new_lines(block, replacement) do\n    for <<x <- block>>, into: \"\" do\n      case x == ?\\n do\n        true -> replacement\n        false -> <<x>>\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Applies a `mod`, `function`, and `args` at compile-time in `caller`.\n\n  This is used when you want to dynamically invoke a function at\n  compile-time and force it to be tracked as a compile-time dependency.\n  For example, this is used by `dbg/1` to force the `dbg_callback`\n  configuration to be a compile-time dependency.\n\n  If you want to \"invoke\" a macro instead, remember macros are by\n  definition compile-time, and you can use `Macro.expand/2`.\n  \"\"\"\n  @doc since: \"1.16.0\"\n  def compile_apply(mod, fun, args, caller) do\n    :elixir_env.trace({:remote_function, [], mod, fun, length(args)}, %{caller | function: nil})\n    Kernel.apply(mod, fun, args)\n  end\n\n  @doc \"\"\"\n  Receives an AST node and expands it once.\n\n  The following contents are expanded:\n\n    * Macros (local or remote)\n    * Aliases are expanded (if possible) and return atoms\n    * Compilation environment macros (`__CALLER__/0`, `__DIR__/0`, `__ENV__/0` and `__MODULE__/0`)\n    * Module attributes reader (`@foo`)\n\n  If the expression cannot be expanded, it returns the expression\n  itself. This function does not traverse the AST, only the root\n  node is expanded. The expansion happens as if it was expanded by\n  the Elixir compiler and therefore compilation tracers will be invoked\n  and deprecation warnings will be emitted during the expansion.\n\n  `expand_once/2` performs the expansion just once. Check `expand/2`\n  to perform expansion until the node can no longer be expanded.\n\n  ## Examples\n\n  In the example below, we have a macro that generates a module\n  with a function named `name_length` that returns the length\n  of the module name. The value of this function will be calculated\n  at compilation time and not at runtime.\n\n  Consider the implementation below:\n\n      defmacro defmodule_with_length(name, do: block) do\n        length = length(Atom.to_charlist(name))\n\n        quote do\n          defmodule unquote(name) do\n            def name_length, do: unquote(length)\n            unquote(block)\n          end\n        end\n      end\n\n  When invoked like this:\n\n      defmodule_with_length My.Module do\n        def other_function, do: ...\n      end\n\n  The compilation will fail because `My.Module` when quoted\n  is not an atom, but a syntax tree as follows:\n\n      {:__aliases__, [], [:My, :Module]}\n\n  That said, we need to expand the aliases node above to an\n  atom, so we can retrieve its length. Expanding the node is\n  not straightforward because we also need to expand the\n  caller aliases. For example:\n\n      alias MyHelpers, as: My\n\n      defmodule_with_length My.Module do\n        def other_function, do: ...\n      end\n\n  The final module name will be `MyHelpers.Module` and not\n  `My.Module`. With `Macro.expand/2`, such aliases are taken\n  into consideration. Local and remote macros are also\n  expanded. We could rewrite our macro above to use this\n  function as:\n\n      defmacro defmodule_with_length(name, do: block) do\n        expanded = Macro.expand(name, __CALLER__)\n        length = length(Atom.to_charlist(expanded))\n\n        quote do\n          defmodule unquote(name) do\n            def name_length, do: unquote(length)\n            unquote(block)\n          end\n        end\n      end\n\n  \"\"\"\n  @spec expand_once(input(), Macro.Env.t()) :: output()\n  def expand_once(ast, env) do\n    elem(do_expand_once(ast, env), 0)\n  end\n\n  defp do_expand_once({:__aliases__, meta, list} = alias, env) do\n    case :elixir_aliases.expand_or_concat(meta, list, env, true) do\n      receiver when is_atom(receiver) ->\n        :elixir_env.trace({:alias_reference, meta, receiver}, env)\n        {receiver, true}\n\n      [head | tail] ->\n        {head, _} = do_expand_once(head, env)\n\n        case is_atom(head) do\n          true ->\n            receiver = :elixir_aliases.concat([head | tail])\n            :elixir_env.trace({:alias_reference, meta, receiver}, env)\n            {receiver, true}\n\n          false ->\n            {alias, false}\n        end\n    end\n  end\n\n  # Expand compilation environment macros\n  defp do_expand_once({:__MODULE__, _, atom}, env) when is_atom(atom), do: {env.module, true}\n\n  defp do_expand_once({:__DIR__, _, atom}, env) when is_atom(atom),\n    do: {:filename.dirname(env.file), true}\n\n  defp do_expand_once({:__ENV__, _, atom}, env) when is_atom(atom) and env.context != :match do\n    env = update_in(env.versioned_vars, &maybe_escape_map/1)\n    {maybe_escape_map(env), true}\n  end\n\n  defp do_expand_once({{:., _, [{:__ENV__, _, atom}, field]}, _, []} = original, env)\n       when is_atom(atom) and is_atom(field) and env.context != :match do\n    if Map.has_key?(env, field) do\n      {maybe_escape_map(Map.get(env, field)), true}\n    else\n      {original, false}\n    end\n  end\n\n  defp do_expand_once({name, meta, context} = original, _env)\n       when is_atom(name) and is_list(meta) and is_atom(context) do\n    {original, false}\n  end\n\n  defp do_expand_once({name, meta, args} = original, env)\n       when is_atom(name) and is_list(args) and is_list(meta) do\n    arity = length(args)\n\n    case Macro.Env.expand_import(env, meta, name, arity) do\n      {:macro, _receiver, expander} ->\n        # We don't want the line to propagate yet, but generated might!\n        {expander.(Keyword.take(meta, [:generated]), args), true}\n\n      {:function, Kernel, op} when op in [:+, :-] and arity == 1 ->\n        case expand_once(hd(args), env) do\n          integer when is_integer(integer) -> {apply(Kernel, op, [integer]), true}\n          _ -> {original, false}\n        end\n\n      {:function, _receiver, _name} ->\n        {original, false}\n\n      {:error, :not_found} ->\n        {original, false}\n\n      {:error, other} ->\n        :elixir_errors.file_error(meta, env, :elixir_dispatch, {:import, other, name, arity})\n    end\n  end\n\n  # Expand possible macro require invocation\n  defp do_expand_once({{:., _, [left, name]}, meta, args} = original, env) when is_atom(name) do\n    {receiver, _} = do_expand_once(left, env)\n\n    case is_atom(receiver) do\n      false ->\n        {original, false}\n\n      true ->\n        case Macro.Env.expand_require(env, meta, receiver, name, length(args)) do\n          {:macro, _receiver, expander} ->\n            # We don't want the line to propagate yet, but generated might!\n            {expander.(Keyword.take(meta, [:generated]), args), true}\n\n          :error ->\n            {original, false}\n        end\n    end\n  end\n\n  # Anything else is just returned\n  defp do_expand_once(other, _env), do: {other, false}\n\n  defp maybe_escape_map(map) when is_map(map), do: {:%{}, [], Map.to_list(map)}\n  defp maybe_escape_map(other), do: other\n\n  @doc \"\"\"\n  Returns `true` if the given name and arity is a special form.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec special_form?(name :: atom(), arity()) :: boolean()\n  def special_form?(name, arity) when is_atom(name) and is_integer(arity) do\n    :elixir_import.special_form(name, arity)\n  end\n\n  @doc \"\"\"\n  Returns `true` if the given name and arity is an operator.\n\n  ## Examples\n\n      iex> Macro.operator?(:not_an_operator, 3)\n      false\n      iex> Macro.operator?(:.., 0)\n      true\n      iex> Macro.operator?(:+, 1)\n      true\n      iex> Macro.operator?(:++, 2)\n      true\n      iex> Macro.operator?(:..//, 3)\n      true\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec operator?(name :: atom(), arity()) :: boolean()\n  def operator?(name, arity)\n\n  def operator?(:..//, 3),\n    do: true\n\n  # Code.Identifier treats :// as a binary operator for precedence\n  # purposes but it isn't really one, so we explicitly skip it.\n  def operator?(name, 2) when is_atom(name),\n    do: Identifier.binary_op(name) != :error and name != :\"//\"\n\n  def operator?(name, 1) when is_atom(name),\n    do: Identifier.unary_op(name) != :error\n\n  def operator?(:.., 0), do: true\n  def operator?(:..., 0), do: true\n\n  def operator?(name, arity) when is_atom(name) and is_integer(arity), do: false\n\n  @doc \"\"\"\n  Returns `true` if the given quoted expression represents a quoted literal.\n\n  Atoms and numbers are always literals. Binaries, lists, tuples,\n  maps, and structs are only literals if all of their terms are also literals.\n\n  ## Examples\n\n      iex> Macro.quoted_literal?(quote(do: \"foo\"))\n      true\n      iex> Macro.quoted_literal?(quote(do: {\"foo\", 1}))\n      true\n      iex> Macro.quoted_literal?(quote(do: {\"foo\", 1, :baz}))\n      true\n      iex> Macro.quoted_literal?(quote(do: %{foo: \"bar\"}))\n      true\n      iex> Macro.quoted_literal?(quote(do: %URI{path: \"/\"}))\n      true\n      iex> Macro.quoted_literal?(quote(do: URI.parse(\"/\")))\n      false\n      iex> Macro.quoted_literal?(quote(do: {foo, var}))\n      false\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec quoted_literal?(t) :: boolean\n  def quoted_literal?(term)\n\n  def quoted_literal?({:__aliases__, _, args}),\n    do: quoted_literal?(args)\n\n  def quoted_literal?({:%, _, [left, right]}),\n    do: quoted_literal?(left) and quoted_literal?(right)\n\n  def quoted_literal?({:%{}, _, args}), do: quoted_literal?(args)\n  def quoted_literal?({:{}, _, args}), do: quoted_literal?(args)\n  def quoted_literal?({:__MODULE__, _, ctx}) when is_atom(ctx), do: true\n  def quoted_literal?({:<<>>, _, segments}), do: Enum.all?(segments, &quoted_bitstring_segment?/1)\n  def quoted_literal?({left, right}), do: quoted_literal?(left) and quoted_literal?(right)\n  def quoted_literal?(list) when is_list(list), do: :lists.all(&quoted_literal?/1, list)\n  def quoted_literal?(term), do: is_atom(term) or is_number(term) or is_binary(term)\n\n  defp quoted_bitstring_segment?(term) when is_integer(term) or is_binary(term), do: true\n\n  defp quoted_bitstring_segment?({:\"::\", _, [term, modifier]})\n       when is_integer(term) or is_binary(term),\n       do: quoted_bitstring_modifier?(modifier)\n\n  defp quoted_bitstring_segment?(_other), do: false\n\n  defp quoted_bitstring_modifier?({:-, _, [left, right]}),\n    do: quoted_bitstring_modifier?(left) and quoted_bitstring_modifier?(right)\n\n  defp quoted_bitstring_modifier?({atom, _, [size]})\n       when atom in [:size, :unit] and is_integer(size),\n       do: true\n\n  defp quoted_bitstring_modifier?({:*, _, [left, right]})\n       when is_integer(left) and is_integer(right),\n       do: true\n\n  defp quoted_bitstring_modifier?({modifier, _, ctx}) when is_atom(ctx) or ctx == [],\n    do: :elixir_bitstring.validate_spec(modifier, nil) != :none\n\n  defp quoted_bitstring_modifier?(_other), do: false\n\n  @doc false\n  @deprecated \"Use Macro.expand_literals/2 instead\"\n  def expand_literal(ast, env) do\n    expand_literals(ast, env)\n  end\n\n  @doc \"\"\"\n  Expands all literals in `ast` with the given `env`.\n\n  This function is mostly used to remove compile-time dependencies\n  from AST nodes. In such cases, the given environment is usually\n  manipulated to represent a function:\n\n      Macro.expand_literals(ast, %{env | function: {:my_code, 1}})\n\n  At the moment, the only expandable literal nodes in an AST are\n  aliases, so this function only expands aliases (and it does so\n  anywhere in a literal).\n\n  However, be careful when removing compile-time dependencies between\n  modules. If you remove them but you still invoke the module at\n  compile-time, Elixir will be unable to properly recompile modules\n  when they change.\n  \"\"\"\n  @doc since: \"1.14.1\"\n  @spec expand_literals(input(), Macro.Env.t()) :: output()\n  def expand_literals(ast, env) do\n    {ast, :ok} = expand_literals(ast, :ok, fn node, :ok -> {expand(node, env), :ok} end)\n    ast\n  end\n\n  @doc \"\"\"\n  Expands all literals in `ast` with the given `acc` and `fun`.\n\n  `fun` will be invoked with an expandable AST node and `acc` and\n  must return a new node with `acc`. This is a general version of\n  `expand_literals/2` which supports a custom expansion function.\n  Please check `expand_literals/2` for use cases and pitfalls.\n  \"\"\"\n  @doc since: \"1.14.1\"\n  @spec expand_literals(t(), acc, (t(), acc -> {t(), acc})) :: t() when acc: term()\n  def expand_literals(ast, acc, fun)\n\n  def expand_literals({:__aliases__, meta, args}, acc, fun) do\n    {args, acc} = expand_literals(args, acc, fun)\n\n    if :lists.all(&is_atom/1, args) do\n      fun.({:__aliases__, meta, args}, acc)\n    else\n      {{:__aliases__, meta, args}, acc}\n    end\n  end\n\n  def expand_literals({:__MODULE__, _meta, ctx} = node, acc, fun) when is_atom(ctx) do\n    fun.(node, acc)\n  end\n\n  def expand_literals({:%, meta, [left, right]}, acc, fun) do\n    {left, acc} = expand_literals(left, acc, fun)\n    {right, acc} = expand_literals(right, acc, fun)\n    {{:%, meta, [left, right]}, acc}\n  end\n\n  def expand_literals({:%{}, meta, args}, acc, fun) do\n    {args, acc} = expand_literals(args, acc, fun)\n    {{:%{}, meta, args}, acc}\n  end\n\n  def expand_literals({:{}, meta, args}, acc, fun) do\n    {args, acc} = expand_literals(args, acc, fun)\n    {{:{}, meta, args}, acc}\n  end\n\n  def expand_literals({left, right}, acc, fun) do\n    {left, acc} = expand_literals(left, acc, fun)\n    {right, acc} = expand_literals(right, acc, fun)\n    {{left, right}, acc}\n  end\n\n  def expand_literals(list, acc, fun) when is_list(list) do\n    :lists.mapfoldl(&expand_literals(&1, &2, fun), acc, list)\n  end\n\n  def expand_literals(\n        {{:., _, [{:__aliases__, _, [:Application]}, :compile_env]} = node, meta,\n         [app, key, default]},\n        acc,\n        fun\n      ) do\n    {default, acc} = expand_literals(default, acc, fun)\n    {{node, meta, [app, key, default]}, acc}\n  end\n\n  def expand_literals(term, acc, _fun), do: {term, acc}\n\n  @doc \"\"\"\n  Receives an AST node and expands it until it can no longer\n  be expanded.\n\n  Note this function does not traverse the AST, only the root\n  node is expanded.\n\n  This function uses `expand_once/2` under the hood. Check\n  it out for more information and examples.\n  \"\"\"\n  @spec expand(input(), Macro.Env.t()) :: output()\n  def expand(ast, env) do\n    expand_until({ast, true}, env)\n  end\n\n  defp expand_until({ast, true}, env) do\n    expand_until(do_expand_once(ast, env), env)\n  end\n\n  defp expand_until({ast, false}, _env) do\n    ast\n  end\n\n  @doc \"\"\"\n  Converts the given argument to a string with the underscore-slash format.\n\n  The argument must either be an atom, representing an Elixir module,\n  or a string representing a module without the `Elixir.` prefix.\n\n  This function was designed to format language identifiers/tokens with the underscore-slash format,\n  that's why it belongs to the `Macro` module. Do not use it as a general\n  mechanism for underscoring strings as it does not support Unicode or\n  characters that are not valid in Elixir identifiers.\n\n  ## Examples\n\n      iex> Macro.underscore(\"FooBar\")\n      \"foo_bar\"\n\n      iex> Macro.underscore(\"Foo.Bar\")\n      \"foo/bar\"\n\n      iex> Macro.underscore(Foo.Bar)\n      \"foo/bar\"\n\n  In general, `underscore` can be thought of as the reverse of\n  `camelize`, however, in some cases formatting may be lost:\n\n      iex> Macro.underscore(\"SAPExample\")\n      \"sap_example\"\n\n      iex> Macro.camelize(\"sap_example\")\n      \"SapExample\"\n\n      iex> Macro.camelize(\"hello_10\")\n      \"Hello10\"\n\n      iex> Macro.camelize(\"foo/bar\")\n      \"Foo.Bar\"\n\n  \"\"\"\n  @spec underscore(atom() | String.t()) :: String.t()\n  def underscore(atom_or_string)\n\n  def underscore(atom) when is_atom(atom) do\n    \"Elixir.\" <> rest = Atom.to_string(atom)\n    underscore(rest)\n  end\n\n  def underscore(<<h, t::binary>>) do\n    <<to_lower_char(h)>> <> do_underscore(t, h)\n  end\n\n  def underscore(\"\") do\n    \"\"\n  end\n\n  defp do_underscore(<<h, t, rest::binary>>, _)\n       when h >= ?A and h <= ?Z and not (t >= ?A and t <= ?Z) and not (t >= ?0 and t <= ?9) and\n              t != ?. and t != ?_ do\n    <<?_, to_lower_char(h), t>> <> do_underscore(rest, t)\n  end\n\n  defp do_underscore(<<h, t::binary>>, prev)\n       when h >= ?A and h <= ?Z and not (prev >= ?A and prev <= ?Z) and prev != ?_ do\n    <<?_, to_lower_char(h)>> <> do_underscore(t, h)\n  end\n\n  defp do_underscore(<<?., t::binary>>, _) do\n    <<?/>> <> underscore(t)\n  end\n\n  defp do_underscore(<<h, t::binary>>, _) do\n    <<to_lower_char(h)>> <> do_underscore(t, h)\n  end\n\n  defp do_underscore(<<>>, _) do\n    <<>>\n  end\n\n  @doc \"\"\"\n  Converts the given string to CamelCase format.\n\n  This function was designed to camelize language identifiers/tokens,\n  that's why it belongs to the `Macro` module. Do not use it as a general\n  mechanism for camelizing strings as it does not support Unicode or\n  characters that are not valid in Elixir identifiers.\n\n  ## Examples\n\n      iex> Macro.camelize(\"foo_bar\")\n      \"FooBar\"\n\n      iex> Macro.camelize(\"foo/bar\")\n      \"Foo.Bar\"\n\n  If uppercase characters are present, they are not modified in any way\n  as a mechanism to preserve acronyms:\n\n      iex> Macro.camelize(\"API.V1\")\n      \"API.V1\"\n      iex> Macro.camelize(\"API_SPEC\")\n      \"API_SPEC\"\n\n  \"\"\"\n  @spec camelize(String.t()) :: String.t()\n  def camelize(string)\n\n  def camelize(\"\"), do: \"\"\n  def camelize(<<?_, t::binary>>), do: camelize(t)\n  def camelize(<<h, t::binary>>), do: <<to_upper_char(h)>> <> do_camelize(t)\n\n  defp do_camelize(<<?_, ?_, t::binary>>), do: do_camelize(<<?_, t::binary>>)\n\n  defp do_camelize(<<?_, h, t::binary>>) when h >= ?a and h <= ?z,\n    do: <<to_upper_char(h)>> <> do_camelize(t)\n\n  defp do_camelize(<<?_, h, t::binary>>) when h >= ?0 and h <= ?9, do: <<h>> <> do_camelize(t)\n  defp do_camelize(<<?_>>), do: <<>>\n  defp do_camelize(<<?/, t::binary>>), do: <<?.>> <> camelize(t)\n  defp do_camelize(<<h, t::binary>>), do: <<h>> <> do_camelize(t)\n  defp do_camelize(<<>>), do: <<>>\n\n  defp to_upper_char(char) when char >= ?a and char <= ?z, do: char - 32\n  defp to_upper_char(char), do: char\n\n  defp to_lower_char(char) when char >= ?A and char <= ?Z, do: char + 32\n  defp to_lower_char(char), do: char\n\n  ## Atom handling\n\n  @doc \"\"\"\n  Classifies an `atom` based on its possible AST placement.\n\n  It returns one of the following atoms:\n\n    * `:alias` - the atom represents an alias\n\n    * `:identifier` - the atom can be used as a variable or local function\n      call (as well as be an unquoted atom)\n\n    * `:unquoted` - the atom can be used in its unquoted form,\n      includes operators and atoms with `@` in them\n\n    * `:quoted` - all other atoms which can only be used in their quoted form\n\n  Most operators are going to be `:unquoted`, such as `:+`, with\n  some exceptions returning `:quoted` due to ambiguity, such as\n  `:\"::\"`. Use `operator?/2` to check if a given atom is an operator.\n\n  ## Examples\n\n      iex> Macro.classify_atom(:foo)\n      :identifier\n      iex> Macro.classify_atom(Foo)\n      :alias\n      iex> Macro.classify_atom(:foo@bar)\n      :unquoted\n      iex> Macro.classify_atom(:+)\n      :unquoted\n      iex> Macro.classify_atom(:Foo)\n      :unquoted\n      iex> Macro.classify_atom(:\"with spaces\")\n      :quoted\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec classify_atom(atom) :: :alias | :identifier | :quoted | :unquoted\n  def classify_atom(atom) do\n    case inner_classify(atom) do\n      :alias -> :alias\n      :identifier -> :identifier\n      type when type in [:unquoted_operator, :not_callable] -> :unquoted\n      _ -> :quoted\n    end\n  end\n\n  @doc ~S\"\"\"\n  Inspects `atom` according to different source formats.\n\n  The atom can be inspected according to the three different\n  formats it appears in the AST: as a literal (`:literal`),\n  as a key (`:key`), or as the function name of a remote call\n  (`:remote_call`).\n\n  ## Options\n\n    * `:escape` - a two-arity function used to escape a quoted\n      atom content, if necessary. The function receives the atom\n      content as string and a quote delimiter character, which\n      should always be escaped. By default the content is escaped\n      such that the inspected sequence would be parsed as the\n      given atom.\n\n  ## Examples\n\n  ### As a literal\n\n  Literals include regular atoms, quoted atoms, operators,\n  aliases, and the special `nil`, `true`, and `false` atoms.\n\n      iex> Macro.inspect_atom(:literal, nil)\n      \"nil\"\n      iex> Macro.inspect_atom(:literal, :foo)\n      \":foo\"\n      iex> Macro.inspect_atom(:literal, :<>)\n      \":<>\"\n      iex> Macro.inspect_atom(:literal, :Foo)\n      \":Foo\"\n      iex> Macro.inspect_atom(:literal, Foo.Bar)\n      \"Foo.Bar\"\n      iex> Macro.inspect_atom(:literal, :\"with spaces\")\n      \":\\\"with spaces\\\"\"\n\n  ### As a key\n\n  Inspect an atom as a key of a keyword list or a map.\n\n      iex> Macro.inspect_atom(:key, :foo)\n      \"foo:\"\n      iex> Macro.inspect_atom(:key, :<>)\n      \"<>:\"\n      iex> Macro.inspect_atom(:key, :Foo)\n      \"Foo:\"\n      iex> Macro.inspect_atom(:key, :\"with spaces\")\n      \"\\\"with spaces\\\":\"\n\n  ### As a remote call\n\n  Inspect an atom the function name of a remote call.\n\n      iex> Macro.inspect_atom(:remote_call, :foo)\n      \"foo\"\n      iex> Macro.inspect_atom(:remote_call, :<>)\n      \"<>\"\n      iex> Macro.inspect_atom(:remote_call, :Foo)\n      \"\\\"Foo\\\"\"\n      iex> Macro.inspect_atom(:remote_call, :\"with spaces\")\n      \"\\\"with spaces\\\"\"\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec inspect_atom(:literal | :key | :remote_call, atom, inspect_atom_opts) :: binary\n  def inspect_atom(source_format, atom, opts \\\\ [])\n\n  def inspect_atom(:literal, atom, _opts) when is_nil(atom) or is_boolean(atom) do\n    Atom.to_string(atom)\n  end\n\n  def inspect_atom(:literal, atom, opts) when is_atom(atom) do\n    binary = Atom.to_string(atom)\n\n    case classify_atom(atom) do\n      :alias ->\n        case binary do\n          binary when binary in [\"Elixir\", \"Elixir.Elixir\"] -> binary\n          \"Elixir.Elixir.\" <> _rest -> binary\n          \"Elixir.\" <> rest -> rest\n        end\n\n      :quoted ->\n        escaped = inspect_atom_escape(opts, binary, ?\")\n        IO.iodata_to_binary([?:, ?\", escaped, ?\"])\n\n      _ ->\n        \":\" <> binary\n    end\n  end\n\n  def inspect_atom(:key, atom, opts) when is_atom(atom) do\n    binary = Atom.to_string(atom)\n\n    case classify_atom(atom) do\n      :alias ->\n        IO.iodata_to_binary([?\", binary, ?\", ?:])\n\n      :quoted ->\n        escaped = inspect_atom_escape(opts, binary, ?\")\n        IO.iodata_to_binary([?\", escaped, ?\", ?:])\n\n      _ ->\n        IO.iodata_to_binary([binary, ?:])\n    end\n  end\n\n  def inspect_atom(:remote_call, atom, opts) when is_atom(atom) do\n    binary = Atom.to_string(atom)\n\n    case inner_classify(atom) do\n      type when type in [:identifier, :unquoted_operator, :quoted_operator] ->\n        binary\n\n      type ->\n        escaped =\n          if type in [:not_callable, :alias] do\n            binary\n          else\n            inspect_atom_escape(opts, binary, ?\")\n          end\n\n        IO.iodata_to_binary([?\", escaped, ?\"])\n    end\n  end\n\n  defp inspect_atom_escape(opts, string, char) do\n    if escape = opts[:escape] do\n      escape.(string, char)\n    else\n      {escaped, _} = Code.Identifier.escape(string, char)\n      escaped\n    end\n  end\n\n  # Classifies the given atom into one of the following categories:\n  #\n  #   * `:alias` - a valid Elixir alias, like `Foo`, `Foo.Bar` and so on\n  #\n  #   * `:identifier` - an atom that can be used as a variable/local call;\n  #     this category includes identifiers like `:foo`\n  #\n  #   * `:unquoted_operator` - all callable operators, such as `:<>`. Note\n  #     operators such as `:..` are not callable because of ambiguity\n  #\n  #   * `:quoted_operator` - callable operators that must be wrapped in quotes when\n  #     defined as an atom. For example, `::` must be written as `:\"::\"` to avoid\n  #     the ambiguity between the atom and the keyword identifier\n  #\n  #   * `:not_callable` - an atom that cannot be used as a function call after the\n  #     `.` operator. Those are typically AST nodes that are special forms (such as\n  #     `:%{}` and `:<<>>>`) as well as nodes that are ambiguous in calls (such as\n  #     `:..` and `:...`). This category also includes atoms like `:Foo`, since\n  #     they are valid identifiers but they need quotes to be used in function\n  #     calls (`Foo.\"Bar\"`)\n  #\n  #   * `:other` - any other atom (these are usually escaped when inspected, like\n  #     `:\"foo and bar\"`)\n  #\n  defp inner_classify(atom) when is_atom(atom) do\n    cond do\n      atom in [:%, :%{}, :{}, :<<>>, :..., :.., :., :..//, :->] ->\n        :not_callable\n\n      # <|>, ^^^, and ~~~ are deprecated\n      atom in [:\"::\", :\"^^^\", :\"~~~\", :\"<|>\"] ->\n        :quoted_operator\n\n      operator?(atom, 1) or operator?(atom, 2) ->\n        :unquoted_operator\n\n      true ->\n        charlist = Atom.to_charlist(atom)\n\n        if valid_alias?(charlist) do\n          :alias\n        else\n          case :elixir_config.identifier_tokenizer().tokenize(charlist) do\n            {kind, _acc, [], _, _, special} ->\n              cond do\n                kind != :identifier or :lists.member(:at, special) ->\n                  :not_callable\n\n                # identifier_tokenizer used to return errors for non-nfc, but\n                # now it nfc-normalizes everything. However, lack of nfc is\n                # still a good reason to quote an atom when printing.\n                :lists.member(:nfkc, special) ->\n                  :other\n\n                true ->\n                  :identifier\n              end\n\n            _ ->\n              :other\n          end\n        end\n    end\n  end\n\n  defp valid_alias?([?E, ?l, ?i, ?x, ?i, ?r] ++ rest), do: valid_alias_piece?(rest)\n  defp valid_alias?(_other), do: false\n\n  defp valid_alias_piece?([?., char | rest]) when char >= ?A and char <= ?Z,\n    do: valid_alias_piece?(trim_leading_while_valid_identifier(rest))\n\n  defp valid_alias_piece?([]), do: true\n  defp valid_alias_piece?(_other), do: false\n\n  defp trim_leading_while_valid_identifier([char | rest])\n       when char >= ?a and char <= ?z\n       when char >= ?A and char <= ?Z\n       when char >= ?0 and char <= ?9\n       when char == ?_ do\n    trim_leading_while_valid_identifier(rest)\n  end\n\n  defp trim_leading_while_valid_identifier(other) do\n    other\n  end\n\n  @doc \"\"\"\n  Default backend for `Kernel.dbg/2`.\n\n  This function provides a default backend for `Kernel.dbg/2`. See the\n  `Kernel.dbg/2` documentation for more information.\n\n  This function:\n\n    * prints information about the given `env`\n    * prints information about `code` and its returned value (using `opts` to inspect terms)\n    * returns the value returned by evaluating `code`\n\n  You can call this function directly to build `Kernel.dbg/2` backends that fall back\n  to this function.\n\n  This function raises if the context of the given `env` is `:match` or `:guard`.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec dbg(t, t, Macro.Env.t()) :: t\n  def dbg(code, options, %Macro.Env{} = env) do\n    case env.context do\n      :match ->\n        raise ArgumentError,\n              \"invalid expression in match, dbg is not allowed in patterns \" <>\n                \"such as function clauses, case clauses or on the left side of the = operator\"\n\n      :guard ->\n        raise ArgumentError,\n              \"invalid expression in guard, dbg is not allowed in guards. \" <>\n                \"To learn more about guards, visit: https://hexdocs.pm/elixir/patterns-and-guards.html\"\n\n      _ ->\n        :ok\n    end\n\n    prelude = quote do: options = unquote(options)\n    acc = {prelude, dbg_format_header(env)}\n\n    {acc, nil} =\n      Enum.reduce(dbg_ast_to_debuggable(code, env), acc, fn entry, {acc, header} ->\n        acc =\n          quote do\n            unquote(acc)\n            to_debug = unquote(entry)\n            unquote(__MODULE__).__dbg__(to_debug, unquote(header), options)\n          end\n\n        {acc, nil}\n      end)\n\n    acc\n  end\n\n  # Pipelines.\n  defp dbg_ast_to_debuggable({:|>, _meta, _args} = pipe_ast, _env) do\n    value_var = unique_var(:value, __MODULE__)\n\n    [start_ast | rest_asts] = for {ast, 0} <- unpipe(pipe_ast), do: ast\n    piped_rest_asts = Enum.map(rest_asts, &{&1, pipe(value_var, &1, 0)})\n\n    first_entry =\n      quote do\n        unquote(value_var) = unquote(start_ast)\n        {:multi_value, unquote(escape(start_ast)), unquote(value_var)}\n      end\n\n    len = length(piped_rest_asts)\n\n    pipe_entries =\n      Enum.with_index(piped_rest_asts, fn {original_ast, step_ast}, i ->\n        tag = if i + 1 == len, do: :pipe_end, else: :pipe\n\n        quote do\n          unquote(value_var) = unquote(step_ast)\n          {unquote(tag), unquote(escape(original_ast)), unquote(value_var)}\n        end\n      end)\n\n    [first_entry | pipe_entries]\n  end\n\n  dbg_decomposed_binary_operators = [:&&, :||, :and, :or]\n\n  # Logic operators.\n  defp dbg_ast_to_debuggable({op, _meta, [_left, _right]} = ast, _env)\n       when op in unquote(dbg_decomposed_binary_operators) do\n    result_var = unique_var(:result, __MODULE__)\n    dbg_boolean_tree(ast, result_var, [])\n  end\n\n  defp dbg_ast_to_debuggable({:__block__, _meta, exprs}, _env) when exprs != [] do\n    result_var = unique_var(:result, __MODULE__)\n    count = length(exprs)\n\n    Enum.with_index(exprs, fn expr, i ->\n      tag = if i + 1 == count, do: :value, else: :multi_value\n\n      quote do\n        unquote(result_var) = unquote(expr)\n        {unquote(tag), unquote(Macro.escape(expr)), unquote(result_var)}\n      end\n    end)\n  end\n\n  defp dbg_ast_to_debuggable({:case, _meta, [expr, [do: clauses]]} = ast, _env) do\n    clauses_returning_index =\n      Enum.with_index(clauses, fn {:->, meta, [left, right]}, index ->\n        {:->, meta, [left, {right, index}]}\n      end)\n\n    [\n      quote do\n        expr = unquote(expr)\n        {:case_argument, unquote(escape(expr)), expr}\n      end,\n      quote do\n        {result, clause_index} =\n          case expr do\n            unquote(clauses_returning_index)\n          end\n\n        {:case_expression, unquote(escape(ast)), clause_index, result}\n      end\n    ]\n  end\n\n  defp dbg_ast_to_debuggable({:cond, _meta, [[do: clauses]]} = ast, _env) do\n    modified_clauses =\n      Enum.with_index(clauses, fn {:->, _meta, [[left], right]}, index ->\n        hd(\n          quote do\n            clause_value = unquote(left) ->\n              {unquote(escape(left)), clause_value, unquote(index), unquote(right)}\n          end\n        )\n      end)\n\n    [\n      quote do\n        {clause_ast, clause_value, clause_index, value} =\n          cond do\n            unquote(modified_clauses)\n          end\n\n        {:cond, unquote(escape(ast)), clause_ast, clause_value, clause_index, value}\n      end\n    ]\n  end\n\n  defp dbg_ast_to_debuggable({:if, meta, [condition_ast, clauses]} = ast, env) do\n    case Macro.Env.lookup_import(env, {:if, 2}) do\n      [macro: Kernel] ->\n        condition_result_var = unique_var(:condition_result, __MODULE__)\n\n        [\n          quote do\n            unquote(condition_result_var) = unquote(condition_ast)\n            {:if_condition, unquote(escape(condition_ast)), unquote(condition_result_var)}\n          end,\n          quote do\n            result = unquote({:if, meta, [condition_result_var, clauses]})\n            {:if_result, unquote(escape(ast)), result}\n          end\n        ]\n\n      _ ->\n        [quote(do: {:value, unquote(escape(ast)), unquote(ast)})]\n    end\n  end\n\n  defp dbg_ast_to_debuggable({:with, meta, args} = ast, _env) do\n    {opts, clauses} = List.pop_at(args, -1)\n\n    acc_var = unique_var(:acc, __MODULE__)\n\n    modified_clauses =\n      Enum.flat_map(clauses, fn\n        # We only detail assignments and pattern-matching clauses that\n        # can be helpful to understand how the result is constructed.\n        {:<-, _meta, [left, right]} ->\n          modified_left =\n            case left do\n              {:when, meta, [pattern, guard]} -> {:when, meta, [{pattern, quote(do: _)}, guard]}\n              pattern -> {pattern, quote(do: _)}\n            end\n\n          quote do\n            [\n              value = unquote(right),\n              unquote(acc_var) = [{unquote(escape(right)), value} | unquote(acc_var)],\n              unquote(modified_left) <- {value, unquote(acc_var)}\n            ]\n          end\n\n        {:=, _meta, [left, right]} ->\n          quote do\n            [\n              value = unquote(right),\n              unquote(acc_var) = [{unquote(escape(right)), value} | unquote(acc_var)],\n              unquote(left) = value\n            ]\n          end\n\n        # Other expressions like side effects are omitted.\n        expr ->\n          [expr]\n      end)\n\n    modified_opts =\n      Enum.map(opts, fn\n        {:do, do_block} ->\n          {:do, {do_block, acc_var}}\n\n        {:else, else_block} ->\n          clauses =\n            Enum.map(else_block, fn\n              {:->, meta, [[{:when, meta2, [pattern, guard]}], right]} ->\n                {:->, meta, [[{:when, meta2, [{pattern, acc_var}, guard]}], {right, acc_var}]}\n\n              {:->, meta, [[left], right]} ->\n                {:->, meta, [[{left, acc_var}], {right, acc_var}]}\n\n              invalid ->\n                invalid\n            end)\n\n          error_clause =\n            quote generated: true do\n              {other, _acc} -> raise WithClauseError, term: other\n            end\n\n          {:else, clauses ++ error_clause}\n\n        invalid ->\n          invalid\n      end)\n\n    modified_with_ast = {:with, meta, modified_clauses ++ [modified_opts]}\n\n    [\n      quote do\n        unquote(acc_var) = []\n\n        {value, acc} = unquote(modified_with_ast)\n\n        {:with, unquote(escape(ast)), Enum.reverse(acc), value}\n      end\n    ]\n  end\n\n  # Any other AST.\n  defp dbg_ast_to_debuggable(ast, _env) do\n    [quote(do: {:value, unquote(escape(ast)), unquote(ast)})]\n  end\n\n  # This is a binary operator. We replace the left side with a recursive call to\n  # this function to decompose it\n  defp dbg_boolean_tree({op, _meta, [left, right]} = ast, result_var, nodes)\n       when op in unquote(dbg_decomposed_binary_operators) do\n    tag = if nodes == [], do: :value, else: :multi_value\n\n    node =\n      quote do\n        unquote(result_var) = unquote(op)(unquote(result_var), unquote(right))\n        {unquote(tag), unquote(escape(ast)), unquote(result_var)}\n      end\n\n    dbg_boolean_tree(left, result_var, [node | nodes])\n  end\n\n  defp dbg_boolean_tree(ast, result_var, nodes) do\n    node =\n      quote do\n        {:multi_value, unquote(escape(ast)), unquote(result_var) = unquote(ast)}\n      end\n\n    [node | nodes]\n  end\n\n  # Made public to be called from Macro.dbg/3, so that we generate as little code\n  # as possible and call out into a function as soon as we can.\n  @doc false\n  def __dbg__(to_debug, header, options) do\n    {print_location?, options} = Keyword.pop(options, :print_location, true)\n    ansi_enabled? = options[:syntax_colors] != []\n\n    if print_location? and is_binary(header) do\n      formatted = [:cyan, :italic, header, :reset, \"\\n\"]\n      :ok = IO.write(IO.ANSI.format(formatted, ansi_enabled?))\n    end\n\n    syntax_colors = if IO.ANSI.enabled?(), do: IO.ANSI.syntax_colors(), else: []\n    options = Keyword.merge([width: 80, pretty: true, syntax_colors: syntax_colors], options)\n    {formatted, result} = dbg_format_ast_to_debug(to_debug, options)\n    :ok = IO.write(IO.ANSI.format([formatted, ?\\n], ansi_enabled?))\n    result\n  end\n\n  defp dbg_format_ast_to_debug({:pipe, code_ast, value}, options) do\n    formatted = [\n      [:faint, \"|> \", :reset],\n      dbg_format_ast_with_value_no_newline(code_ast, value, options)\n    ]\n\n    {formatted, value}\n  end\n\n  defp dbg_format_ast_to_debug({:pipe_end, code_ast, value}, options) do\n    {formatted, value} = dbg_format_ast_to_debug({:pipe, code_ast, value}, options)\n\n    {[formatted, ?\\n], value}\n  end\n\n  defp dbg_format_ast_to_debug({:case_argument, expr_ast, expr_value}, options) do\n    formatted = [\n      dbg_maybe_underline(\"Case argument\", options),\n      \":\\n\",\n      dbg_format_ast_with_value(expr_ast, expr_value, options)\n    ]\n\n    {formatted, expr_value}\n  end\n\n  defp dbg_format_ast_to_debug({:case_expression, ast, clause_index, value}, options) do\n    formatted = [\n      dbg_maybe_underline(\"Case expression\", options),\n      \" (clause ##{clause_index + 1} matched):\\n\",\n      dbg_format_ast_with_value(ast, value, options)\n    ]\n\n    {formatted, value}\n  end\n\n  defp dbg_format_ast_to_debug(\n         {:cond, ast, clause_ast, clause_value, clause_index, value},\n         options\n       ) do\n    formatted = [\n      dbg_maybe_underline(\"Cond clause\", options),\n      \" (clause ##{clause_index + 1} matched):\\n\",\n      dbg_format_ast_with_value(clause_ast, clause_value, options),\n      ?\\n,\n      dbg_maybe_underline(\"Cond expression\", options),\n      \":\\n\",\n      dbg_format_ast_with_value(ast, value, options)\n    ]\n\n    {formatted, value}\n  end\n\n  defp dbg_format_ast_to_debug({:if_condition, condition_ast, condition_result}, options) do\n    formatted = [\n      dbg_maybe_underline(\"If condition\", options),\n      \":\\n\",\n      dbg_format_ast_with_value(condition_ast, condition_result, options)\n    ]\n\n    {formatted, condition_result}\n  end\n\n  defp dbg_format_ast_to_debug({:if_result, ast, result}, options) do\n    formatted = [\n      dbg_maybe_underline(\"If expression\", options),\n      \":\\n\",\n      dbg_format_ast_with_value(ast, result, options)\n    ]\n\n    {formatted, result}\n  end\n\n  defp dbg_format_ast_to_debug({:with, ast, clauses, result}, options) do\n    formatted_clauses =\n      Enum.map(clauses, fn {clause_ast, clause_result} ->\n        dbg_format_ast_with_value(clause_ast, clause_result, options)\n      end)\n\n    formatted = [\n      dbg_maybe_underline(\"With clauses\", options),\n      \":\\n\",\n      formatted_clauses,\n      ?\\n,\n      dbg_maybe_underline(\"With expression\", options),\n      \":\\n\",\n      dbg_format_ast_with_value(ast, result, options)\n    ]\n\n    {formatted, result}\n  end\n\n  defp dbg_format_ast_to_debug({:multi_value, code_ast, value}, options) do\n    {dbg_format_ast_with_value_no_newline(code_ast, value, options), value}\n  end\n\n  defp dbg_format_ast_to_debug({:value, code_ast, value}, options) do\n    {dbg_format_ast_with_value(code_ast, value, options), value}\n  end\n\n  defp dbg_format_ast_with_value_no_newline(ast, value, options) do\n    [dbg_format_ast(to_string_with_colors(ast, options)), \" \", inspect(value, options)]\n  end\n\n  defp dbg_format_ast_with_value(ast, value, options) do\n    [dbg_format_ast_with_value_no_newline(ast, value, options), ?\\n]\n  end\n\n  defp to_string_with_colors(ast, options) do\n    options = Keyword.take(options, [:syntax_colors])\n\n    algebra = Code.quoted_to_algebra(ast, options)\n    IO.iodata_to_binary(Inspect.Algebra.format(algebra, 98))\n  end\n\n  defp dbg_format_header(env) do\n    env = Map.update!(env, :file, &(&1 && Path.relative_to_cwd(&1)))\n    [stacktrace_entry] = Macro.Env.stacktrace(env)\n    \"[\" <> Exception.format_stacktrace_entry(stacktrace_entry) <> \"]\"\n  end\n\n  defp dbg_maybe_underline(string, options) do\n    if options[:syntax_colors] != [] do\n      IO.ANSI.format([:underline, string, :reset])\n    else\n      string\n    end\n  end\n\n  defp dbg_format_ast(ast) do\n    [ast, :faint, \" #=>\", :reset]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/map.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Map do\n  @moduledoc \"\"\"\n  Maps are the \"go to\" key-value data structure in Elixir.\n\n  Maps can be created with the `%{}` syntax, and key-value pairs can be\n  expressed as `key => value`:\n\n      iex> %{}\n      %{}\n      iex> %{\"one\" => :two, 3 => \"four\"}\n      %{3 => \"four\", \"one\" => :two}\n\n  Key-value pairs in a map do not follow any order (that's why the printed map\n  in the example above has a different order than the map that was created).\n\n  Maps do not impose any restriction on the key type: anything can be a key in a\n  map. As a key-value structure, maps do not allow duplicate keys. Keys are\n  compared using the exact-equality operator (`===/2`). If colliding keys are defined\n  in a map literal, the last one prevails.\n\n  When the key in a key-value pair is an atom, the `key: value` shorthand syntax\n  can be used (as in many other special forms):\n\n      iex> %{a: 1, b: 2}\n      %{a: 1, b: 2}\n\n  If you want to mix the shorthand syntax with `=>`, the shorthand syntax must come\n  at the end:\n\n      iex> %{\"hello\" => \"world\", a: 1, b: 2}\n      %{:a => 1, :b => 2, \"hello\" => \"world\"}\n\n  Keys in maps can be accessed through some of the functions in this module\n  (such as `Map.get/3` or `Map.fetch/2`) or through the `map[]` syntax provided\n  by the `Access` module:\n\n      iex> map = %{a: 1, b: 2}\n      iex> Map.fetch(map, :a)\n      {:ok, 1}\n      iex> map[:b]\n      2\n      iex> map[\"non_existing_key\"]\n      nil\n\n  To access atom keys, one may also use the `map.key` notation. Note that `map.key`\n  will raise a `KeyError` if the `map` doesn't contain the key `:key`, compared to\n  `map[:key]`, that would return `nil`.\n\n      map = %{foo: \"bar\", baz: \"bong\"}\n      map.foo\n      #=> \"bar\"\n      map.non_existing_key\n      ** (KeyError) key :non_existing_key not found in:\n      ...\n\n  > #### Avoid parentheses {: .warning}\n  >\n  > Do not add parentheses when accessing fields, such as in `data.key()`.\n  > If parentheses are used, Elixir will expect `data` to be an atom representing\n  > a module and attempt to call the *function* `key/0` in it.\n\n  The two syntaxes for accessing keys reveal the dual nature of maps. The `map[key]`\n  syntax is used for dynamically created maps that may have any key, of any type.\n  `map.key` is used with maps that hold a predetermined set of atoms keys, which are\n  expected to always be present. Structs, defined via `defstruct/1`, are one example\n  of such \"static maps\", where the keys can also be checked during compile time.\n\n  Maps can be pattern matched on. When a map is on the left-hand side of a\n  pattern match, it will match if the map on the right-hand side contains the\n  keys on the left-hand side and their values match the ones on the left-hand\n  side. This means that an empty map matches every map.\n\n      iex> %{} = %{foo: \"bar\"}\n      %{foo: \"bar\"}\n      iex> %{a: a} = %{:a => 1, \"b\" => 2, [:c, :e, :e] => 3}\n      iex> a\n      1\n\n  But this will raise a `MatchError` exception:\n\n      %{:c => 3} = %{:a => 1, 2 => :b}\n\n  Variables can be used as map keys both when writing map literals as well as\n  when matching:\n\n      iex> n = 1\n      1\n      iex> %{n => :one}\n      %{1 => :one}\n      iex> %{^n => :one} = %{1 => :one, 2 => :two, 3 => :three}\n      %{1 => :one, 2 => :two, 3 => :three}\n\n  Maps also support a specific update syntax to update the value stored under\n  *existing* keys. You can update using the atom keys syntax:\n\n      iex> map = %{one: 1, two: 2}\n      iex> %{map | one: \"one\"}\n      %{one: \"one\", two: 2}\n\n  Or any other keys:\n\n      iex> other_map = %{\"three\" => 3, \"four\" => 4, \"five\" => 5}\n      iex> %{other_map | \"three\" => \"three\", \"four\" => \"four\"}\n      %{\"five\" => 5, \"four\" => \"four\", \"three\" => \"three\"}\n\n  When a key that does not exist in the map is updated a `KeyError` exception will be raised:\n\n      %{map | three: 3}\n\n  The functions in this module that need to find a specific key work in logarithmic time.\n  This means that the time it takes to find keys grows as the map grows, but it's not\n  directly proportional to the map size. In comparison to finding an element in a list,\n  it performs better because lists have a linear time complexity. Some functions,\n  such as `keys/1` and `values/1`, run in linear time because they need to get to every\n  element in the map.\n\n  Maps also implement the `Enumerable` protocol, so many functions to work with maps\n  are found in the `Enum` module. Additionally, the following functions for maps are\n  found in `Kernel`:\n\n    * `map_size/1`\n\n  \"\"\"\n\n  @type key :: any\n  @type value :: any\n  @compile {:inline, fetch: 2, fetch!: 2, get: 2, put: 3, delete: 2, has_key?: 2, replace!: 3}\n\n  @doc \"\"\"\n  Builds a map from the given `keys` and the fixed `value`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.from_keys([1, 2, 3], :number)\n      %{1 => :number, 2 => :number, 3 => :number}\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec from_keys([key], value) :: map\n  defdelegate from_keys(keys, value), to: :maps\n\n  @doc \"\"\"\n  Returns all keys from `map`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      Map.keys(%{a: 1, b: 2})\n      [:a, :b]\n\n  \"\"\"\n  @spec keys(map) :: [key]\n  defdelegate keys(map), to: :maps\n\n  @doc \"\"\"\n  Returns all values from `map`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      Map.values(%{a: 1, b: 2})\n      [1, 2]\n\n  \"\"\"\n  @spec values(map) :: [value]\n  defdelegate values(map), to: :maps\n\n  @doc \"\"\"\n  Converts `map` to a list.\n\n  Each key-value pair in the map is converted to a two-element tuple `{key,\n  value}` in the resulting list.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.to_list(%{a: 1})\n      [a: 1]\n      iex> Map.to_list(%{1 => 2})\n      [{1, 2}]\n\n  \"\"\"\n  @spec to_list(map) :: [{term, term}]\n  defdelegate to_list(map), to: :maps\n\n  @doc \"\"\"\n  Returns a new empty map.\n\n  ## Examples\n\n      iex> Map.new()\n      %{}\n\n  \"\"\"\n  @spec new :: map\n  def new, do: %{}\n\n  @doc \"\"\"\n  Creates a map from an `enumerable`.\n\n  Duplicated keys are removed; the latest one prevails.\n\n  ## Examples\n\n      iex> Map.new([{:b, 1}, {:a, 2}])\n      %{a: 2, b: 1}\n      iex> Map.new(a: 1, a: 2, a: 3)\n      %{a: 3}\n\n  \"\"\"\n  @spec new(Enumerable.t()) :: map\n  def new(enumerable)\n  def new(list) when is_list(list), do: :maps.from_list(list)\n  def new(%_{} = struct), do: new_from_enum(struct)\n  def new(%{} = map), do: map\n  def new(enum), do: new_from_enum(enum)\n\n  defp new_from_enum(enumerable) do\n    enumerable\n    |> Enum.to_list()\n    |> :maps.from_list()\n  end\n\n  @doc \"\"\"\n  Creates a map from an `enumerable` via the given transformation function.\n\n  Duplicated keys are removed; the latest one prevails.\n\n  ## Examples\n\n      iex> Map.new([:a, :b], fn x -> {x, x} end)\n      %{a: :a, b: :b}\n\n      iex> Map.new(%{a: 2, b: 3, c: 4}, fn {key, val} -> {key, val * 2} end)\n      %{a: 4, b: 6, c: 8}\n\n  \"\"\"\n  @spec new(Enumerable.t(), (term -> {key, value})) :: map\n  def new(enumerable, transform)\n  def new(%_{} = enumerable, transform), do: new_from_enum(enumerable, transform)\n  def new(%{} = map, transform), do: new_from_map(map, transform)\n  def new(enumerable, transform), do: new_from_enum(enumerable, transform)\n\n  defp new_from_map(map, transform) when is_function(transform, 1) do\n    iter = :maps.iterator(map)\n    next = :maps.next(iter)\n    :maps.from_list(do_map(next, transform))\n  end\n\n  defp do_map(:none, _fun), do: []\n\n  defp do_map({key, value, iter}, transform) do\n    [transform.({key, value}) | do_map(:maps.next(iter), transform)]\n  end\n\n  defp new_from_enum(enumerable, transform) when is_function(transform, 1) do\n    enumerable\n    |> Enum.map(transform)\n    |> :maps.from_list()\n  end\n\n  @doc \"\"\"\n  Returns whether the given `key` exists in the given `map`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.has_key?(%{a: 1}, :a)\n      true\n      iex> Map.has_key?(%{a: 1}, :b)\n      false\n\n  \"\"\"\n  @spec has_key?(map, key) :: boolean\n  def has_key?(map, key), do: :maps.is_key(key, map)\n\n  @doc \"\"\"\n  Fetches the value for a specific `key` in the given `map`.\n\n  If `map` contains the given `key` then its value is returned\n  in the shape of `{:ok, value}`. If `map` doesn't contain `key`,\n  `:error` is returned.\n\n  If the type system can verify `:error` is always returned\n  (which means key is never available in the map), it will emit\n  an error.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.fetch(%{a: 1}, :a)\n      {:ok, 1}\n      iex> Map.fetch(%{\"foo\" => \"bar\"}, \"unknown\")\n      :error\n\n  \"\"\"\n  @spec fetch(map, key) :: {:ok, value} | :error\n  def fetch(map, key), do: :maps.find(key, map)\n\n  @doc \"\"\"\n  Fetches the value for a specific `key` in the given `map`, erroring out if\n  `map` doesn't contain `key`.\n\n  The exclamation mark (`!`) implies this function can raise a `KeyError`\n  exception at runtime if `map` doesn't contain `key`. If the type system\n  can verify this function will always raise (which means the key is never\n  available), then it will emit a warning at compile-time. See the \"Type\n  checking\" section below.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.fetch!(%{a: 1}, :a)\n      1\n\n  When the key is missing, an exception is raised:\n\n      Map.fetch!(%{a: 1}, :b)\n      ** (KeyError) key :b not found in: %{a: 1}\n\n  ## Type checking\n\n  The compiler will emit a warning if it can verify that\n  none of the keys given are available in the map.\n\n  When the key is an atom, because only single key is given,\n  a warning will be emitted in case the type system proves\n  the key is not present.\n\n  However, this behaviour matters when the type of the key\n  represents multiple values. For example:\n\n      key = returns_foo_or_bar() #=> :foo or :bar\n      Map.fetch!(%{foo: 123}, key)\n\n  Although the key can be `:foo` or `:bar`, there is no\n  warning emitted, as `:foo` will succeed. This is by design:\n  the exclamation mark in Elixir denotes precisely that a\n  runtime exception may be raised.\n\n  In case you are looking up multiple keys and you don't know\n  if they may be present, you can use `Map.fetch/2` instead\n  and deal with the error case accordingly:\n\n      case Map.fetch(%{foo: 123}, key) do\n        {:ok, value} -> ...\n        :error -> ...\n      end\n\n  Both `Map.fetch!/2` and `Map.fetch/2` will emit a warning if\n  it proves that both `:foo` or `:bar` are absent in the map.\n\n  Alternatively, if you want to statically prove that all of keys\n  are in the map, you can match on the possible values and access\n  them directly:\n\n      case returns_foo_or_bar() do\n        :foo -> map.foo\n        :bar -> map.bar\n      end\n  \"\"\"\n  @spec fetch!(map, key) :: value\n  def fetch!(map, key), do: :maps.get(key, map)\n\n  @doc \"\"\"\n  Puts the given `value` under `key` unless the entry `key`\n  already exists in `map`.\n\n  ## Examples\n\n      iex> Map.put_new(%{a: 1}, :b, 2)\n      %{a: 1, b: 2}\n      iex> Map.put_new(%{a: 1, b: 2}, :a, 3)\n      %{a: 1, b: 2}\n\n  \"\"\"\n  @spec put_new(map, key, value) :: map\n  def put_new(map, key, value) do\n    case map do\n      %{^key => _value} ->\n        map\n\n      %{} ->\n        put(map, key, value)\n\n      other ->\n        :erlang.error({:badmap, other})\n    end\n  end\n\n  @doc \"\"\"\n  Puts a value under `key` only if the `key` already exists in `map`.\n\n  ## Examples\n\n      iex> Map.replace(%{a: 1, b: 2}, :a, 3)\n      %{a: 3, b: 2}\n\n      iex> Map.replace(%{\"a\" => 1}, \"b\", 2)\n      %{\"a\" => 1}\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec replace(map, key, value) :: map\n  def replace(map, key, value) do\n    case map do\n      %{^key => _value} ->\n        %{map | key => value}\n\n      %{} ->\n        map\n\n      other ->\n        :erlang.error({:badmap, other})\n    end\n  end\n\n  @doc \"\"\"\n  Puts a value under `key` only if the `key` already exists in `map`.\n\n  The exclamation mark (`!`) implies this function can raise a `KeyError`\n  exception at runtime if `map` doesn't contain `key`. If the type system\n  can verify this function will always raise (which means the key is never\n  available), then it will emit a warning at compile-time. See the \"Type\n  checking\" section in `Map.fetch!/2` for more information.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.replace!(%{a: 1, b: 2}, :a, 3)\n      %{a: 3, b: 2}\n\n      iex> Map.replace!(%{\"foo\" => \"bar\"}, \"unknown\", \"new_bar\")\n      ** (KeyError) key \"unknown\" not found in:\n      ...\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec replace!(map, key, value) :: map\n  def replace!(map, key, value) do\n    :maps.update(key, value, map)\n  end\n\n  @doc \"\"\"\n  Replaces the value under `key` using the given function only if\n  `key` already exists in `map`.\n\n  In comparison to `replace/3`, this can be useful when it's expensive to calculate the value.\n\n  If `key` does not exist, the original map is returned unchanged.\n\n  ## Examples\n\n      iex> Map.replace_lazy(%{a: 1, b: 2}, :a, fn v -> v * 4 end)\n      %{a: 4, b: 2}\n\n      iex> Map.replace_lazy(%{\"a\" => 1, \"b\" => 2}, \"c\", fn v -> v * 4 end)\n      %{\"a\" => 1, \"b\" => 2}\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec replace_lazy(map, key, (existing_value :: value -> new_value :: value)) :: map\n  def replace_lazy(map, key, fun) when is_map(map) and is_function(fun, 1) do\n    case map do\n      %{^key => val} -> %{map | key => fun.(val)}\n      %{} -> map\n    end\n  end\n\n  @doc \"\"\"\n  Evaluates `fun` and puts the result under `key`\n  in `map` unless `key` is already present.\n\n  This function is useful in case you want to compute the value to put under\n  `key` only if `key` is not already present, as for example, when the value is expensive to\n  calculate or generally difficult to setup and teardown again.\n\n  ## Examples\n\n      iex> map = %{a: 1}\n      iex> fun = fn ->\n      ...>   # some expensive operation here\n      ...>   3\n      ...> end\n      iex> Map.put_new_lazy(map, :a, fun)\n      %{a: 1}\n      iex> Map.put_new_lazy(map, :b, fun)\n      %{a: 1, b: 3}\n\n  \"\"\"\n  @spec put_new_lazy(map, key, (-> value)) :: map\n  def put_new_lazy(map, key, fun) when is_function(fun, 0) do\n    case map do\n      %{^key => _value} ->\n        map\n\n      %{} ->\n        put(map, key, fun.())\n\n      other ->\n        :erlang.error({:badmap, other})\n    end\n  end\n\n  @doc \"\"\"\n  Returns a new map with all the key-value pairs in `map` where the key\n  is in `keys`.\n\n  If `keys` contains keys that are not in `map`, they're simply ignored.\n\n  ## Examples\n\n      iex> Map.take(%{a: 1, b: 2, c: 3}, [:a, :c, :e])\n      %{a: 1, c: 3}\n\n  \"\"\"\n  @spec take(map, [key]) :: map\n  def take(map, keys)\n\n  def take(map, keys) when is_map(map) and is_list(keys) do\n    take(keys, map, _acc = [])\n  end\n\n  def take(map, keys) when is_map(map) do\n    IO.warn(\n      \"Map.take/2 with an Enumerable of keys that is not a list is deprecated. \" <>\n        \" Use a list of keys instead.\"\n    )\n\n    take(map, Enum.to_list(keys))\n  end\n\n  def take(non_map, _keys) do\n    :erlang.error({:badmap, non_map})\n  end\n\n  defp take([], _map, []), do: %{}\n\n  defp take([], _map, acc) do\n    :maps.from_list(acc)\n  end\n\n  defp take([key | rest], map, acc) do\n    acc =\n      case map do\n        %{^key => value} -> [{key, value} | acc]\n        %{} -> acc\n      end\n\n    take(rest, map, acc)\n  end\n\n  @doc \"\"\"\n  Gets the value for a specific `key` in `map`.\n\n  If `key` is present in `map` then its value `value` is\n  returned. Otherwise, `default` is returned.\n\n  If `default` is not provided, `nil` is used.\n\n  ## Examples\n\n      iex> Map.get(%{\"a\" => 1}, \"a\")\n      1\n      iex> Map.get(%{\"a\" => 1}, \"b\")\n      nil\n      iex> Map.get(%{\"a\" => 1}, \"b\", 3)\n      3\n      iex> Map.get(%{\"a\" => nil}, \"a\", 1)\n      nil\n\n  \"\"\"\n  @spec get(map, key, value) :: value\n  def get(map, key, default \\\\ nil) do\n    case map do\n      %{^key => value} ->\n        value\n\n      %{} ->\n        default\n\n      other ->\n        :erlang.error({:badmap, other}, [map, key, default])\n    end\n  end\n\n  @doc \"\"\"\n  Gets the value for a specific `key` in `map`.\n\n  If `key` is present in `map` then its value `value` is\n  returned. Otherwise, `fun` is evaluated and its result is returned.\n\n  This is useful if the default value is very expensive to calculate or\n  generally difficult to setup and teardown again.\n\n  ## Examples\n\n      iex> Map.get_lazy(%{a: 1}, :a, fn -> :expensive_value end)\n      1\n\n      iex> Map.get_lazy(%{\"a\" => 1}, \"b\", fn -> :expensive_value end)\n      :expensive_value\n\n  \"\"\"\n  @spec get_lazy(map, key, (-> value)) :: value\n  def get_lazy(map, key, fun) when is_function(fun, 0) do\n    case map do\n      %{^key => value} ->\n        value\n\n      %{} ->\n        fun.()\n\n      other ->\n        :erlang.error({:badmap, other}, [map, key, fun])\n    end\n  end\n\n  @doc \"\"\"\n  Puts the given `value` under `key` in `map`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.put(%{a: 1}, :b, 2)\n      %{a: 1, b: 2}\n      iex> Map.put(%{a: 1, b: 2}, :a, 3)\n      %{a: 3, b: 2}\n\n  \"\"\"\n  @spec put(map, key, value) :: map\n  def put(map, key, value) do\n    :maps.put(key, value, map)\n  end\n\n  @doc \"\"\"\n  Deletes the entry in `map` for a specific `key`.\n\n  If the `key` does not exist, returns `map` unchanged.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.delete(%{a: 1, b: 2}, :a)\n      %{b: 2}\n      iex> Map.delete(%{b: 2}, :a)\n      %{b: 2}\n\n  \"\"\"\n  @spec delete(map, key) :: map\n  def delete(map, key), do: :maps.remove(key, map)\n\n  @doc \"\"\"\n  Merges two maps into one.\n\n  All keys in `map2` will be added to `map1`, overriding any existing one\n  (i.e., the keys in `map2` \"have precedence\" over the ones in `map1`).\n\n  If you have a struct and you would like to merge a set of keys into the\n  struct, do not use this function, as it would merge all keys on the right\n  side into the struct, even if the key is not part of the struct. Instead,\n  use `struct/2`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.merge(%{a: 1, b: 2}, %{a: 3, d: 4})\n      %{a: 3, b: 2, d: 4}\n\n  \"\"\"\n  @spec merge(map, map) :: map\n  defdelegate merge(map1, map2), to: :maps\n\n  @doc \"\"\"\n  Merges two maps into one, resolving conflicts through the given `fun`.\n\n  All keys in `map2` will be added to `map1`. The given function will be invoked\n  when there are duplicate keys; its arguments are `key` (the duplicate key),\n  `value1` (the value of `key` in `map1`), and `value2` (the value of `key` in\n  `map2`). The value returned by `fun` is used as the value under `key` in\n  the resulting map.\n\n  ## Examples\n\n      iex> Map.merge(%{a: 1, b: 2}, %{a: 3, d: 4}, fn _k, v1, v2 ->\n      ...>   v1 + v2\n      ...> end)\n      %{a: 4, b: 2, d: 4}\n\n  \"\"\"\n  @spec merge(map, map, (key, value, value -> value)) :: map\n  def merge(map1, map2, fun) when is_function(fun, 3) do\n    :maps.merge_with(fun, map1, map2)\n  end\n\n  @doc \"\"\"\n  Updates the `key` in `map` with the given function.\n\n  If `key` is present in `map` then the existing value is passed to `fun` and its result is\n  used as the updated value of `key`. If `key` is\n  not present in `map`, `default` is inserted as the value of `key`. The default\n  value will not be passed through the update function.\n\n  ## Examples\n\n      iex> Map.update(%{a: 1}, :a, 13, fn existing_value -> existing_value * 2 end)\n      %{a: 2}\n      iex> Map.update(%{a: 1}, :b, 11, fn existing_value -> existing_value * 2 end)\n      %{a: 1, b: 11}\n\n  \"\"\"\n  @spec update(map, key, default :: value, (existing_value :: value -> new_value :: value)) ::\n          map\n  def update(map, key, default, fun) when is_function(fun, 1) do\n    case map do\n      %{^key => value} ->\n        %{map | key => fun.(value)}\n\n      %{} ->\n        put(map, key, default)\n\n      other ->\n        :erlang.error({:badmap, other}, [map, key, default, fun])\n    end\n  end\n\n  @doc \"\"\"\n  Removes the value associated with `key` in `map` and returns the value and the updated map.\n\n  If `key` is present in `map`, it returns `{value, updated_map}` where `value` is the value of\n  the key and `updated_map` is the result of removing `key` from `map`. If `key`\n  is not present in `map`, `{default, map}` is returned.\n\n  ## Examples\n\n      iex> Map.pop(%{a: 1}, :a)\n      {1, %{}}\n      iex> Map.pop(%{\"a\" => 1}, \"b\")\n      {nil, %{\"a\" => 1}}\n      iex> Map.pop(%{\"a\" => 1}, \"b\", 3)\n      {3, %{\"a\" => 1}}\n\n  \"\"\"\n  @spec pop(map, key, default) :: {value, updated_map :: map} | {default, map} when default: value\n  def pop(map, key, default \\\\ nil) do\n    case :maps.take(key, map) do\n      {_, _} = tuple -> tuple\n      :error -> {default, map}\n    end\n  end\n\n  @doc \"\"\"\n  Removes and returns the value associated with `key` in `map` alongside\n  the updated map, or raises if `key` is not present.\n\n  Behaves the same as `pop/3` but raises a `KeyError` exception if `key` is not present in `map`.\n\n  ## Examples\n\n      iex> Map.pop!(%{a: 1}, :a)\n      {1, %{}}\n      iex> Map.pop!(%{a: 1, b: 2}, :a)\n      {1, %{b: 2}}\n      iex> Map.pop!(%{\"a\" => 1}, \"b\")\n      ** (KeyError) key \"b\" not found in:\n      ...\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec pop!(map, key) :: {value, updated_map :: map}\n  def pop!(map, key) do\n    case :maps.take(key, map) do\n      {_, _} = tuple -> tuple\n      :error -> raise KeyError, key: key, term: map\n    end\n  end\n\n  @doc \"\"\"\n  Lazily returns and removes the value associated with `key` in `map`.\n\n  If `key` is present in `map`, it returns `{value, new_map}` where `value` is the value of\n  the key and `new_map` is the result of removing `key` from `map`. If `key`\n  is not present in `map`, `{fun_result, map}` is returned, where `fun_result`\n  is the result of applying `fun`.\n\n  This is useful if the default value is very expensive to calculate or\n  generally difficult to setup and teardown again.\n\n  ## Examples\n\n      iex> Map.pop_lazy(%{a: 1}, :a, fn -> :expensive_value end)\n      {1, %{}}\n\n      iex> Map.pop_lazy(%{\"a\" => 1}, \"b\", fn -> :expensive_value end)\n      {:expensive_value, %{\"a\" => 1}}\n\n  \"\"\"\n  @spec pop_lazy(map, key, (-> value)) :: {value, map}\n  def pop_lazy(map, key, fun) when is_function(fun, 0) do\n    case :maps.take(key, map) do\n      {_, _} = tuple -> tuple\n      :error -> {fun.(), map}\n    end\n  end\n\n  @doc \"\"\"\n  Drops the given `keys` from `map`.\n\n  If `keys` contains keys that are not in `map`, they're simply ignored.\n\n  ## Examples\n\n      iex> Map.drop(%{a: 1, b: 2, c: 3}, [:b, :d])\n      %{a: 1, c: 3}\n\n  \"\"\"\n  @spec drop(map, [key]) :: map\n  def drop(map, keys)\n\n  def drop(map, keys) when is_map(map) and is_list(keys) do\n    drop_keys(keys, map)\n  end\n\n  def drop(map, keys) when is_map(map) do\n    IO.warn(\n      \"Map.drop/2 with an Enumerable of keys that is not a list is deprecated. \" <>\n        \" Use a list of keys instead.\"\n    )\n\n    drop(map, Enum.to_list(keys))\n  end\n\n  def drop(non_map, keys) do\n    :erlang.error({:badmap, non_map}, [non_map, keys])\n  end\n\n  defp drop_keys([], acc), do: acc\n\n  defp drop_keys([key | rest], acc) do\n    drop_keys(rest, delete(acc, key))\n  end\n\n  @doc \"\"\"\n  Takes all entries corresponding to the given `keys` in `map` and extracts\n  them into a separate map.\n\n  Returns a tuple with the new map and the old map with removed keys.\n\n  Keys for which there are no entries in `map` are ignored.\n\n  ## Examples\n\n      iex> Map.split(%{a: 1, b: 2, c: 3}, [:a, :c, :e])\n      {%{a: 1, c: 3}, %{b: 2}}\n\n  \"\"\"\n  @spec split(map, [key]) :: {map, map}\n  def split(map, keys)\n\n  def split(map, keys) when is_map(map) and is_list(keys) do\n    split(keys, [], map)\n  end\n\n  def split(map, keys) when is_map(map) do\n    IO.warn(\n      \"Map.split/2 with an Enumerable of keys that is not a list is deprecated. \" <>\n        \" Use a list of keys instead.\"\n    )\n\n    split(map, Enum.to_list(keys))\n  end\n\n  def split(non_map, keys) do\n    :erlang.error({:badmap, non_map}, [non_map, keys])\n  end\n\n  defp split([], included, excluded) do\n    {:maps.from_list(included), excluded}\n  end\n\n  defp split([key | rest], included, excluded) do\n    case excluded do\n      %{^key => value} ->\n        split(rest, [{key, value} | included], delete(excluded, key))\n\n      _other ->\n        split(rest, included, excluded)\n    end\n  end\n\n  @doc \"\"\"\n  Splits the `map` into two maps according to the given function `fun`.\n\n  `fun` receives each `{key, value}` pair in the `map` as its only argument. Returns\n  a tuple with the first map containing all the elements in `map` for which\n  applying `fun` returned a truthy value, and a second map with all the elements\n  for which applying `fun` returned a falsy value (`false` or `nil`).\n\n  ## Examples\n\n      iex> Map.split_with(%{a: 1, b: 2, c: 3, d: 4}, fn {_k, v} -> rem(v, 2) == 0 end)\n      {%{b: 2, d: 4}, %{a: 1, c: 3}}\n\n      iex> Map.split_with(%{a: 1, b: -2, c: 1, d: -3}, fn {k, _v} -> k in [:b, :d] end)\n      {%{b: -2, d: -3}, %{a: 1, c: 1}}\n\n      iex> Map.split_with(%{a: 1, b: -2, c: 1, d: -3}, fn {_k, v} -> v > 50 end)\n      {%{}, %{a: 1, b: -2, c: 1, d: -3}}\n\n      iex> Map.split_with(%{}, fn {_k, v} -> v > 50 end)\n      {%{}, %{}}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec split_with(map, ({key, value} -> as_boolean(term))) :: {map, map}\n  def split_with(map, fun) when is_map(map) and is_function(fun, 1) do\n    iter = :maps.iterator(map)\n    next = :maps.next(iter)\n\n    do_split_with(next, [], [], fun)\n  end\n\n  defp do_split_with(:none, while_true, while_false, _fun) do\n    {:maps.from_list(while_true), :maps.from_list(while_false)}\n  end\n\n  defp do_split_with({key, value, iter}, while_true, while_false, fun) do\n    if fun.({key, value}) do\n      do_split_with(:maps.next(iter), [{key, value} | while_true], while_false, fun)\n    else\n      do_split_with(:maps.next(iter), while_true, [{key, value} | while_false], fun)\n    end\n  end\n\n  @doc \"\"\"\n  Updates `key` with the given function.\n\n  If `key` is present in `map` then the existing value is passed to `fun` and its result is\n  used as the updated value of `key`. If `key` is\n  not present in `map`, a `KeyError` exception is raised.\n\n  ## Examples\n\n      iex> Map.update!(%{a: 1}, :a, &(&1 * 2))\n      %{a: 2}\n\n      iex> Map.update!(%{\"a\" => 1}, \"b\", &(&1 * 2))\n      ** (KeyError) key \"b\" not found in:\n      ...\n\n  \"\"\"\n  @spec update!(map, key, (existing_value :: value -> new_value :: value)) :: map\n  def update!(map, key, fun) when is_function(fun, 1) do\n    value = fetch!(map, key)\n    %{map | key => fun.(value)}\n  end\n\n  @doc \"\"\"\n  Gets the value from `key` and updates it, all in one pass.\n\n  `fun` is called with the current value under `key` in `map` (or `nil` if `key`\n  is not present in `map`) and must return a two-element tuple: the current value\n  (the retrieved value, which can be operated on before being returned) and the\n  new value to be stored under `key` in the resulting new map. `fun` may also\n  return `:pop`, which means the current value shall be removed from `map` and\n  returned (making this function behave like `Map.pop(map, key)`).\n\n  The returned value is a two-element tuple with the current value returned by\n  `fun` and a new map with the updated value under `key`.\n\n  ## Examples\n\n      iex> Map.get_and_update(%{a: 1}, :a, fn current_value ->\n      ...>   {current_value, \"new value!\"}\n      ...> end)\n      {1, %{a: \"new value!\"}}\n\n      iex> Map.get_and_update(%{a: 1}, :b, fn current_value ->\n      ...>   {current_value, \"new value!\"}\n      ...> end)\n      {nil, %{a: 1, b: \"new value!\"}}\n\n      iex> Map.get_and_update(%{a: 1}, :a, fn _ -> :pop end)\n      {1, %{}}\n\n      iex> Map.get_and_update(%{a: 1}, :b, fn _ -> :pop end)\n      {nil, %{a: 1}}\n\n  \"\"\"\n  @spec get_and_update(map, key, (value | nil -> {current_value, new_value :: value} | :pop)) ::\n          {current_value, new_map :: map}\n        when current_value: value\n  def get_and_update(map, key, fun) when is_function(fun, 1) do\n    current = get(map, key)\n\n    case fun.(current) do\n      {get, update} ->\n        {get, put(map, key, update)}\n\n      :pop ->\n        {current, delete(map, key)}\n\n      other ->\n        raise \"the given function must return a two-element tuple or :pop, got: #{inspect(other)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Gets the value from `key` and updates it, all in one pass. Raises if there is no `key`.\n\n  Behaves exactly like `get_and_update/3`, but raises a `KeyError` exception if\n  `key` is not present in `map`.\n\n  ## Examples\n\n      iex> Map.get_and_update!(%{a: 1}, :a, fn current_value ->\n      ...>   {current_value, \"new value!\"}\n      ...> end)\n      {1, %{a: \"new value!\"}}\n\n      iex> Map.get_and_update!(%{a: 1}, :b, fn current_value ->\n      ...>   {current_value, \"new value!\"}\n      ...> end)\n      ** (KeyError) key :b not found in:\n      ...\n\n      iex> Map.get_and_update!(%{a: 1}, :a, fn _ ->\n      ...>   :pop\n      ...> end)\n      {1, %{}}\n\n  \"\"\"\n  @spec get_and_update!(map, key, (value -> {current_value, new_value :: value} | :pop)) ::\n          {current_value, map}\n        when current_value: value\n  def get_and_update!(map, key, fun) when is_function(fun, 1) do\n    value = fetch!(map, key)\n\n    case fun.(value) do\n      {get, update} ->\n        {get, %{map | key => update}}\n\n      :pop ->\n        {value, delete(map, key)}\n\n      other ->\n        raise \"the given function must return a two-element tuple or :pop, got: #{inspect(other)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Converts a `struct` to map.\n\n  It accepts a struct and simply removes the `__struct__` field\n  from the given struct.\n\n  ## Example\n\n      defmodule User do\n        defstruct [:name]\n      end\n\n      Map.from_struct(%User{name: \"john\"})\n      #=> %{name: \"john\"}\n\n  \"\"\"\n  # TODO: implement this using row polymorphism\n  @spec from_struct(atom | struct) :: map\n  def from_struct(struct) when is_atom(struct) do\n    IO.warn(\"Map.from_struct/1 with a module is deprecated, please pass a struct instead\")\n    delete(struct.__struct__(), :__struct__)\n  end\n\n  def from_struct(%_{} = struct) do\n    delete(struct, :__struct__)\n  end\n\n  @doc \"\"\"\n  Checks if two maps are equal.\n\n  Two maps are considered to be equal if they contain\n  the same keys and those keys contain the same values.\n\n  Note this function exists for completeness so the `Map`\n  and `Keyword` modules provide similar APIs. In practice,\n  developers often compare maps using `==/2` or `===/2`\n  directly.\n\n  ## Examples\n\n      iex> Map.equal?(%{a: 1, b: 2}, %{b: 2, a: 1})\n      true\n      iex> Map.equal?(%{a: 1, b: 2}, %{b: 1, a: 2})\n      false\n\n  Comparison between keys and values is done with `===/3`,\n  which means integers are not equivalent to floats:\n\n      iex> Map.equal?(%{a: 1.0}, %{a: 1})\n      false\n\n  \"\"\"\n  @spec equal?(map, map) :: boolean\n  def equal?(%{} = map1, %{} = map2), do: map1 === map2\n\n  @doc false\n  @deprecated \"Use Kernel.map_size/1 instead\"\n  def size(map) do\n    map_size(map)\n  end\n\n  @doc \"\"\"\n  Returns a map containing only those pairs from `map`\n  for which `fun` returns a truthy value.\n\n  `fun` receives the key and value of each of the\n  elements in the map as a key-value pair.\n\n  See also `reject/2` which discards all elements where the\n  function returns a truthy value.\n\n  > #### Performance considerations {: .tip}\n  >\n  > If you find yourself doing multiple calls to `Map.filter/2`\n  > and `Map.reject/2` in a pipeline, it is likely more efficient\n  > to use `Enum.map/2` and `Enum.filter/2` instead and convert to\n  > a map at the end using `Map.new/1`.\n\n  ## Examples\n\n      iex> Map.filter(%{one: 1, two: 2, three: 3}, fn {_key, val} -> rem(val, 2) == 1 end)\n      %{one: 1, three: 3}\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec filter(map, ({key, value} -> as_boolean(term))) :: map\n  def filter(map, fun) when is_map(map) and is_function(fun, 1) do\n    iter = :maps.iterator(map)\n    next = :maps.next(iter)\n    :maps.from_list(do_filter(next, fun))\n  end\n\n  defp do_filter(:none, _fun), do: []\n\n  defp do_filter({key, value, iter}, fun) do\n    if fun.({key, value}) do\n      [{key, value} | do_filter(:maps.next(iter), fun)]\n    else\n      do_filter(:maps.next(iter), fun)\n    end\n  end\n\n  @doc \"\"\"\n  Returns map excluding the pairs from `map` for which `fun` returns\n  a truthy value.\n\n  See also `filter/2`.\n\n  ## Examples\n\n      iex> Map.reject(%{one: 1, two: 2, three: 3}, fn {_key, val} -> rem(val, 2) == 1 end)\n      %{two: 2}\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec reject(map, ({key, value} -> as_boolean(term))) :: map\n  def reject(map, fun) when is_map(map) and is_function(fun, 1) do\n    iter = :maps.iterator(map)\n    next = :maps.next(iter)\n    :maps.from_list(do_reject(next, fun))\n  end\n\n  defp do_reject(:none, _fun), do: []\n\n  defp do_reject({key, value, iter}, fun) do\n    if fun.({key, value}) do\n      do_reject(:maps.next(iter), fun)\n    else\n      [{key, value} | do_reject(:maps.next(iter), fun)]\n    end\n  end\n\n  @doc \"\"\"\n  Intersects two maps, returning a map with the common keys.\n\n  The values in the returned map are the values of the intersected keys in `map2`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Map.intersect(%{a: 1, b: 2}, %{b: \"b\", c: \"c\"})\n      %{b: \"b\"}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec intersect(map, map) :: map\n  defdelegate intersect(map1, map2), to: :maps\n\n  @doc \"\"\"\n  Intersects two maps, returning a map with the common keys and resolving conflicts through a function.\n\n  The given function will be invoked when there are duplicate keys; its\n  arguments are `key` (the duplicate key), `value1` (the value of `key` in\n  `map1`), and `value2` (the value of `key` in `map2`). The value returned by\n  `fun` is used as the value under `key` in the resulting map.\n\n  ## Examples\n\n      iex> Map.intersect(%{a: 1, b: 2}, %{b: 2, c: 3}, fn _k, v1, v2 ->\n      ...>   v1 + v2\n      ...> end)\n      %{b: 4}\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec intersect(map, map, (key, value, value -> value)) :: map\n  def intersect(map1, map2, fun) when is_function(fun, 3) do\n    :maps.intersect_with(fun, map1, map2)\n  end\n\n  @doc false\n  @deprecated \"Use Map.new/2 instead (invoke Map.from_struct/1 before if you have a struct)\"\n  def map(map, fun) when is_map(map) do\n    :maps.map(fn k, v -> fun.({k, v}) end, map)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/map_set.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule MapSet do\n  @moduledoc \"\"\"\n  Functions that work on sets.\n\n  A set is a data structure that can contain unique elements of any kind,\n  without any particular order. `MapSet` is the \"go to\" set data structure in Elixir.\n\n  A set can be constructed using `MapSet.new/0`:\n\n      iex> MapSet.new()\n      MapSet.new([])\n\n  Elements in a set don't have to be of the same type and they can be\n  populated from an [enumerable](`t:Enumerable.t/0`) using `MapSet.new/1`:\n\n      iex> MapSet.new([1, :two, {\"three\"}])\n      MapSet.new([1, :two, {\"three\"}])\n\n  Elements can be inserted using `MapSet.put/2`:\n\n      iex> MapSet.new([2]) |> MapSet.put(4) |> MapSet.put(0)\n      MapSet.new([0, 2, 4])\n\n  By definition, sets can't contain duplicate elements: when\n  inserting an element in a set where it's already present, the insertion is\n  simply a no-op.\n\n      iex> map_set = MapSet.new()\n      iex> MapSet.put(map_set, \"foo\")\n      MapSet.new([\"foo\"])\n      iex> map_set |> MapSet.put(\"foo\") |> MapSet.put(\"foo\")\n      MapSet.new([\"foo\"])\n\n  A `MapSet` is represented internally using the `%MapSet{}` struct. This struct\n  can be used whenever there's a need to pattern match on something being a `MapSet`:\n\n      iex> match?(%MapSet{}, MapSet.new())\n      true\n\n  Note that, however, the struct fields are private and must not be accessed\n  directly; use the functions in this module to perform operations on sets.\n\n  `MapSet`s can also be constructed starting from other collection-type data\n  structures: for example, see `MapSet.new/1` or `Enum.into/2`.\n\n  `MapSet` is built on top of Erlang's [`:sets`](`:sets`) (version 2). This means\n  that they share many properties, including logarithmic time complexity. Erlang\n  `:sets` (version 2) are implemented on top of maps, so see the documentation\n  for `Map` for more information on its execution time complexity.\n  \"\"\"\n\n  @type value :: term\n\n  # We don't use @opaque (or `:sets.set` which is opaque) because MapSets can be inlined,\n  # either via module attributes or by the compiler.\n  @typep internal(value) :: %{optional(value) => term()}\n\n  @type t(value) :: %__MODULE__{map: internal(value)}\n  @type t :: t(term)\n\n  # The key name is :map because the MapSet implementation used to be based on top of maps before\n  # Elixir 1.15 (and Erlang/OTP 24, which introduced :sets version 2). :sets v2's internal\n  # representation is, anyways, exactly the same as MapSet's previous implementation. We cannot\n  # change the :map key name here because we'd break backwards compatibility with code compiled\n  # with Elixir 1.14 and earlier and executed on Elixir 1.15+.\n  defstruct map: :sets.new(version: 2)\n\n  @doc \"\"\"\n  Returns a new set.\n\n  ## Examples\n\n      iex> MapSet.new()\n      MapSet.new([])\n\n  \"\"\"\n  @spec new :: t\n  def new(), do: %MapSet{}\n\n  @doc \"\"\"\n  Creates a set from an enumerable.\n\n  ## Examples\n\n      iex> MapSet.new([:b, :a, 3])\n      MapSet.new([3, :a, :b])\n      iex> MapSet.new([3, 3, 3, 2, 2, 1])\n      MapSet.new([1, 2, 3])\n\n  \"\"\"\n  @spec new(Enumerable.t()) :: t\n  def new(enumerable)\n\n  def new(%__MODULE__{} = map_set), do: map_set\n\n  def new(enumerable) do\n    set =\n      enumerable\n      |> Enum.to_list()\n      |> :sets.from_list(version: 2)\n\n    %MapSet{map: set}\n  end\n\n  @doc \"\"\"\n  Creates a set from an enumerable via the transformation function.\n\n  ## Examples\n\n      iex> MapSet.new([1, 2, 1], fn x -> 2 * x end)\n      MapSet.new([2, 4])\n\n  \"\"\"\n  @spec new(Enumerable.t(), (term -> val)) :: t(val) when val: value\n  def new(enumerable, transform) when is_function(transform, 1) do\n    set =\n      enumerable\n      |> Enum.map(transform)\n      |> :sets.from_list(version: 2)\n\n    %MapSet{map: set}\n  end\n\n  @doc \"\"\"\n  Deletes `value` from `map_set`.\n\n  Returns a new set which is a copy of `map_set` but without `value`.\n\n  ## Examples\n\n      iex> map_set = MapSet.new([1, 2, 3])\n      iex> MapSet.delete(map_set, 4)\n      MapSet.new([1, 2, 3])\n      iex> MapSet.delete(map_set, 2)\n      MapSet.new([1, 3])\n\n  \"\"\"\n  @spec delete(t(val1), val2) :: t(val1) when val1: value, val2: value\n  def delete(%MapSet{map: set} = map_set, value) do\n    %{map_set | map: :sets.del_element(value, set)}\n  end\n\n  @doc \"\"\"\n  Returns a set that is `map_set1` without the members of `map_set2`.\n\n  ## Examples\n\n      iex> MapSet.difference(MapSet.new([1, 2]), MapSet.new([2, 3, 4]))\n      MapSet.new([1])\n\n  \"\"\"\n  @spec difference(t(val1), t(val2)) :: t(val1) when val1: value, val2: value\n  def difference(%MapSet{map: set1} = map_set1, %MapSet{map: set2} = _map_set2) do\n    %{map_set1 | map: :sets.subtract(set1, set2)}\n  end\n\n  @doc \"\"\"\n  Returns a set with elements that are present in only one but not both sets.\n\n  ## Examples\n\n      iex> MapSet.symmetric_difference(MapSet.new([1, 2, 3]), MapSet.new([2, 3, 4]))\n      MapSet.new([1, 4])\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec symmetric_difference(t(val1), t(val2)) :: t(val1 | val2) when val1: value, val2: value\n  def symmetric_difference(%MapSet{map: set1} = map_set1, %MapSet{map: set2} = _map_set2) do\n    {small, large} = if :sets.size(set1) <= :sets.size(set2), do: {set1, set2}, else: {set2, set1}\n\n    disjointer_fun = fn elem, {small, acc} ->\n      if :sets.is_element(elem, small) do\n        {:sets.del_element(elem, small), acc}\n      else\n        {small, [elem | acc]}\n      end\n    end\n\n    {new_small, list} = :sets.fold(disjointer_fun, {small, []}, large)\n    %{map_set1 | map: :sets.union(new_small, :sets.from_list(list, version: 2))}\n  end\n\n  @doc \"\"\"\n  Checks if `map_set1` and `map_set2` have no members in common.\n\n  ## Examples\n\n      iex> MapSet.disjoint?(MapSet.new([1, 2]), MapSet.new([3, 4]))\n      true\n      iex> MapSet.disjoint?(MapSet.new([1, 2]), MapSet.new([2, 3]))\n      false\n\n  \"\"\"\n  @spec disjoint?(t, t) :: boolean\n  def disjoint?(%MapSet{map: set1}, %MapSet{map: set2}) do\n    :sets.is_disjoint(set1, set2)\n  end\n\n  @doc \"\"\"\n  Checks if two sets are equal.\n\n  The comparison between elements is done using `===/2`,\n  which a set with `1` is not equivalent to a set with\n  `1.0`.\n\n  ## Examples\n\n      iex> MapSet.equal?(MapSet.new([1, 2]), MapSet.new([2, 1, 1]))\n      true\n      iex> MapSet.equal?(MapSet.new([1, 2]), MapSet.new([3, 4]))\n      false\n      iex> MapSet.equal?(MapSet.new([1]), MapSet.new([1.0]))\n      false\n\n  \"\"\"\n  @spec equal?(t, t) :: boolean\n  def equal?(%MapSet{map: set1}, %MapSet{map: set2}) do\n    set1 === set2\n  end\n\n  @doc \"\"\"\n  Returns a set containing only members that `map_set1` and `map_set2` have in common.\n\n  ## Examples\n\n      iex> MapSet.intersection(MapSet.new([1, 2]), MapSet.new([2, 3, 4]))\n      MapSet.new([2])\n\n      iex> MapSet.intersection(MapSet.new([1, 2]), MapSet.new([3, 4]))\n      MapSet.new([])\n\n  \"\"\"\n  @spec intersection(t(val), t(val)) :: t(val) when val: value\n  def intersection(%MapSet{map: set1} = map_set1, %MapSet{map: set2} = _map_set2) do\n    %{map_set1 | map: :sets.intersection(set1, set2)}\n  end\n\n  @doc \"\"\"\n  Checks if `map_set` contains `value`.\n\n  ## Examples\n\n      iex> MapSet.member?(MapSet.new([1, 2, 3]), 2)\n      true\n      iex> MapSet.member?(MapSet.new([1, 2, 3]), 4)\n      false\n\n  \"\"\"\n  @spec member?(t, value) :: boolean\n  def member?(%MapSet{map: set}, value) do\n    :sets.is_element(value, set)\n  end\n\n  @doc \"\"\"\n  Inserts `value` into `map_set` if `map_set` doesn't already contain it.\n\n  ## Examples\n\n      iex> MapSet.put(MapSet.new([1, 2, 3]), 3)\n      MapSet.new([1, 2, 3])\n      iex> MapSet.put(MapSet.new([1, 2, 3]), 4)\n      MapSet.new([1, 2, 3, 4])\n\n  \"\"\"\n  @spec put(t(val), new_val) :: t(val | new_val) when val: value, new_val: value\n  def put(%MapSet{map: set} = map_set, value) do\n    %{map_set | map: :sets.add_element(value, set)}\n  end\n\n  @doc \"\"\"\n  Returns the number of elements in `map_set`.\n\n  ## Examples\n\n      iex> MapSet.size(MapSet.new([1, 2, 3]))\n      3\n\n  \"\"\"\n  @spec size(t) :: non_neg_integer\n  def size(%MapSet{map: set}) do\n    :sets.size(set)\n  end\n\n  @doc \"\"\"\n  Checks if `map_set1`'s members are all contained in `map_set2`.\n\n  This function checks if `map_set1` is a subset of `map_set2`.\n\n  ## Examples\n\n      iex> MapSet.subset?(MapSet.new([1, 2]), MapSet.new([1, 2, 3]))\n      true\n      iex> MapSet.subset?(MapSet.new([1, 2, 3]), MapSet.new([1, 2]))\n      false\n\n  \"\"\"\n  @spec subset?(t, t) :: boolean\n  def subset?(%MapSet{map: set1}, %MapSet{map: set2}) do\n    :sets.is_subset(set1, set2)\n  end\n\n  @doc \"\"\"\n  Converts `map_set` to a list.\n\n  ## Examples\n\n      iex> MapSet.to_list(MapSet.new([1, 2, 3]))\n      [1, 2, 3]\n\n  \"\"\"\n  @spec to_list(t(val)) :: [val] when val: value\n  def to_list(%MapSet{map: set}) do\n    :sets.to_list(set)\n  end\n\n  @doc \"\"\"\n  Returns a set containing all members of `map_set1` and `map_set2`.\n\n  ## Examples\n\n      iex> MapSet.union(MapSet.new([1, 2]), MapSet.new([2, 3, 4]))\n      MapSet.new([1, 2, 3, 4])\n\n  \"\"\"\n  @spec union(t(val1), t(val2)) :: t(val1 | val2) when val1: value, val2: value\n  def union(%MapSet{map: set1} = map_set1, %MapSet{map: set2} = _map_set2) do\n    %{map_set1 | map: :sets.union(set1, set2)}\n  end\n\n  @doc \"\"\"\n  Filters the set by returning only the elements from `map_set` for which invoking\n  `fun` returns a truthy value.\n\n  Also see `reject/2` which discards all elements where the function returns\n  a truthy value.\n\n  > #### Performance considerations {: .tip}\n  >\n  > If you find yourself doing multiple calls to `MapSet.filter/2`\n  > and `MapSet.reject/2` in a pipeline, it is likely more efficient\n  > to use `Enum.map/2` and `Enum.filter/2` instead and convert to\n  > a map at the end using `MapSet.new/1`.\n\n  ## Examples\n\n      iex> MapSet.filter(MapSet.new(1..5), fn x -> x > 3 end)\n      MapSet.new([4, 5])\n\n      iex> MapSet.filter(MapSet.new([\"a\", :b, \"c\"]), &is_atom/1)\n      MapSet.new([:b])\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec filter(t(a), (a -> as_boolean(term))) :: t(a) when a: value\n  def filter(%MapSet{map: set} = map_set, fun) when is_function(fun) do\n    pred = fn element -> !!fun.(element) end\n    %{map_set | map: :sets.filter(pred, set)}\n  end\n\n  @doc \"\"\"\n  Returns a set by excluding the elements from `map_set` for which invoking `fun`\n  returns a truthy value.\n\n  See also `filter/2`.\n\n  ## Examples\n\n      iex> MapSet.reject(MapSet.new(1..5), fn x -> rem(x, 2) != 0 end)\n      MapSet.new([2, 4])\n\n      iex> MapSet.reject(MapSet.new([\"a\", :b, \"c\"]), &is_atom/1)\n      MapSet.new([\"a\", \"c\"])\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec reject(t(a), (a -> as_boolean(term))) :: t(a) when a: value\n  def reject(%MapSet{map: set} = map_set, fun) when is_function(fun) do\n    pred = fn element -> !fun.(element) end\n    %{map_set | map: :sets.filter(pred, set)}\n  end\n\n  @doc \"\"\"\n  Splits the `map_set` into two `MapSet`s according to the given function `fun`.\n\n  `fun` receives each element in the `map_set` as its only argument. Returns\n  a tuple with the first `MapSet` containing all the elements in `map_set` for which\n  applying `fun` returned a truthy value, and a second `MapSet` with all the elements\n  for which applying `fun` returned a falsy value (`false` or `nil`).\n\n  ## Examples\n\n      iex> {while_true, while_false} = MapSet.split_with(MapSet.new([1, 2, 3, 4]), fn v -> rem(v, 2) == 0 end)\n      iex> while_true\n      MapSet.new([2, 4])\n      iex> while_false\n      MapSet.new([1, 3])\n\n      iex> {while_true, while_false} = MapSet.split_with(MapSet.new(), fn {_k, v} -> v > 50 end)\n      iex> while_true\n      MapSet.new([])\n      iex> while_false\n      MapSet.new([])\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec split_with(MapSet.t(), (term() -> as_boolean(term))) :: {MapSet.t(), MapSet.t()}\n  def split_with(%MapSet{map: map}, fun) when is_function(fun, 1) do\n    {while_true, while_false} = Map.split_with(map, fn {key, _} -> fun.(key) end)\n    {%MapSet{map: while_true}, %MapSet{map: while_false}}\n  end\n\n  defimpl Enumerable do\n    def count(map_set) do\n      {:ok, MapSet.size(map_set)}\n    end\n\n    def member?(map_set, val) do\n      {:ok, MapSet.member?(map_set, val)}\n    end\n\n    def slice(map_set) do\n      size = MapSet.size(map_set)\n      {:ok, size, &MapSet.to_list/1}\n    end\n\n    def reduce(map_set, acc, fun) do\n      Enumerable.List.reduce(MapSet.to_list(map_set), acc, fun)\n    end\n  end\n\n  defimpl Collectable do\n    def into(%@for{map: set} = map_set) do\n      fun = fn\n        list, {:cont, x} -> [x | list]\n        list, :done -> %{map_set | map: :sets.union(set, :sets.from_list(list, version: 2))}\n        _, :halt -> :ok\n      end\n\n      {[], fun}\n    end\n  end\n\n  defimpl Inspect do\n    import Inspect.Algebra\n\n    def inspect(map_set, %Inspect.Opts{} = opts) do\n      {doc, %{limit: limit}} =\n        map_set\n        |> MapSet.to_list()\n        |> to_doc_with_opts(%{opts | charlists: :as_lists})\n\n      {concat([\"MapSet.new(\", doc, \")\"]), %{opts | limit: limit}}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/behaviour.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Module.Behaviour do\n  # Checking functionality for @behaviours and @impl\n  @moduledoc false\n\n  @doc false\n  def callbacks(behaviour) do\n    for callback <- behaviour.behaviour_info(:callbacks) do\n      {pair, _kind} = normalize_macro_or_function_callback(callback)\n      pair\n    end\n  end\n\n  @doc false\n  def check_behaviours_and_impls(module, file, line, behaviours, impls, all_definitions) do\n    context = check_behaviours(context(module, file, line), behaviours)\n\n    context =\n      if impls != [] do\n        {context, impl_contexts} = check_impls(context, behaviours, impls)\n\n        warn_missing_impls(context, impl_contexts, all_definitions)\n      else\n        context\n      end\n\n    context = check_callbacks(context, all_definitions)\n\n    context.warnings\n  end\n\n  defp context(module, file, line) do\n    %{\n      module: module,\n      file: file,\n      line: line,\n      callbacks: %{},\n      warnings: []\n    }\n  end\n\n  defp warn(context, warning, meta \\\\ []) do\n    meta = Keyword.put_new(meta, :line, context.line)\n    location = {meta[:file] || context.file, meta, context.module}\n\n    update_in(context.warnings, &[{__MODULE__, warning, location} | &1])\n  end\n\n  defp check_behaviours(context, behaviours) do\n    Enum.reduce(behaviours, context, fn behaviour, context ->\n      cond do\n        not Code.ensure_loaded?(behaviour) ->\n          warn(context, {:undefined_behaviour, context.module, behaviour})\n\n        not function_exported?(behaviour, :behaviour_info, 1) ->\n          warn(context, {:module_does_not_define_behaviour, context.module, behaviour})\n\n        true ->\n          optional_callbacks = behaviour.behaviour_info(:optional_callbacks)\n          callbacks = behaviour.behaviour_info(:callbacks)\n          Enum.reduce(callbacks, context, &add_callback(&2, &1, behaviour, optional_callbacks))\n      end\n    end)\n  end\n\n  defp add_callback(context, original, behaviour, optional_callbacks) do\n    {callback, kind} = normalize_macro_or_function_callback(original)\n\n    context =\n      case context.callbacks do\n        %{^callback => [{_kind, conflict, _optional?} | _]} ->\n          warn(\n            context,\n            {:duplicate_behaviour, context.module, behaviour, conflict, kind, callback}\n          )\n\n        %{} ->\n          context\n      end\n\n    new_callback = {kind, behaviour, original in optional_callbacks}\n    callbacks = context.callbacks[callback] || []\n\n    put_in(context.callbacks[callback], [new_callback | callbacks])\n  end\n\n  defp check_callbacks(context, all_definitions) do\n    for {callback, callbacks} <- context.callbacks,\n        {kind, behaviour, optional?} <- callbacks,\n        reduce: context do\n      context ->\n        case :lists.keyfind(callback, 1, all_definitions) do\n          false when not optional? ->\n            warn(context, {:missing_callback, context.module, callback, kind, behaviour})\n\n          {_, wrong_kind, _, _} when kind != wrong_kind ->\n            warn(\n              context,\n              {:callback_mismatch, context.module, callback, kind, wrong_kind, behaviour}\n            )\n\n          _ ->\n            context\n        end\n    end\n  end\n\n  defp format_callback(callback, kind, module) do\n    protocol_or_behaviour = if protocol?(module), do: \"protocol \", else: \"behaviour \"\n\n    format_definition(kind, callback) <>\n      \" required by \" <> protocol_or_behaviour <> inspect(module)\n  end\n\n  defp protocol?(module) do\n    Code.ensure_loaded?(module) and function_exported?(module, :__protocol__, 1) and\n      module.__protocol__(:module) == module\n  end\n\n  defp check_impls(context, behaviours, impls) do\n    all_callbacks = context.callbacks\n    acc = {context, %{}}\n\n    Enum.reduce(impls, acc, fn {fa, impl_context, defaults, kind, line, file, value},\n                               {context, impl_contexts} = acc ->\n      case impl_behaviours(fa, defaults, kind, value, behaviours, all_callbacks) do\n        {:ok, impl_behaviours} ->\n          Enum.reduce(impl_behaviours, acc, fn {fa, behaviour}, {context, impl_contexts} ->\n            {_, context} = pop_in(context.callbacks[fa])\n\n            impl_contexts =\n              Map.update(impl_contexts, behaviour, [impl_context], &[impl_context | &1])\n\n            {context, impl_contexts}\n          end)\n\n        {:error, message} ->\n          warning = message |> Tuple.insert_at(1, kind) |> Tuple.insert_at(1, fa)\n          context = warn(context, warning, line: line, file: file)\n          {context, impl_contexts}\n      end\n    end)\n  end\n\n  defp impl_behaviours({function, arity}, defaults, kind, value, behaviours, callbacks) do\n    impls = for n <- (arity - defaults)..arity, do: {function, n}\n    impl_behaviours(impls, kind, value, behaviours, callbacks)\n  end\n\n  defp impl_behaviours(_, kind, _, _, _) when kind in [:defp, :defmacrop] do\n    {:error, {:private_function}}\n  end\n\n  defp impl_behaviours(_, _, value, [], _) do\n    {:error, {:no_behaviours, value}}\n  end\n\n  defp impl_behaviours(impls, _, false, _, callbacks) do\n    case callbacks_for_impls(impls, callbacks) do\n      [] -> {:ok, []}\n      [impl | _] -> {:error, {:impl_not_defined, impl}}\n    end\n  end\n\n  defp impl_behaviours(impls, _, true, _, callbacks) do\n    case callbacks_for_impls(impls, callbacks) do\n      [] -> {:error, {:impl_defined, callbacks}}\n      impls -> {:ok, impls}\n    end\n  end\n\n  defp impl_behaviours(impls, _, behaviour, behaviours, callbacks) do\n    filtered = behaviour_callbacks_for_impls(impls, behaviour, callbacks)\n\n    cond do\n      filtered != [] ->\n        {:ok, filtered}\n\n      behaviour not in behaviours ->\n        {:error, {:behaviour_not_declared, behaviour}}\n\n      not Code.ensure_loaded?(behaviour) ->\n        # Module does not exist, but we have already warned about it.\n        {:ok, []}\n\n      not behaviour_defined?(callbacks, behaviour) ->\n        # Module does not define behaviour, but we have already warned about it.\n        {:ok, []}\n\n      true ->\n        {:error, {:callback_not_defined, behaviour, callbacks}}\n    end\n  end\n\n  defp behaviour_callbacks_for_impls([], _behaviour, _callbacks) do\n    []\n  end\n\n  defp behaviour_callbacks_for_impls([fa | tail], behaviour, callbacks) do\n    with list when is_list(list) <- callbacks[fa],\n         true <- Enum.any?(list, &match?({_, ^behaviour, _}, &1)) do\n      [{fa, behaviour} | behaviour_callbacks_for_impls(tail, behaviour, callbacks)]\n    else\n      _ ->\n        behaviour_callbacks_for_impls(tail, behaviour, callbacks)\n    end\n  end\n\n  defp callbacks_for_impls([], _) do\n    []\n  end\n\n  defp callbacks_for_impls([fa | tail], callbacks) do\n    case callbacks[fa] do\n      list when is_list(list) ->\n        Enum.map(list, fn {_, behaviour, _} -> {fa, behaviour} end) ++\n          callbacks_for_impls(tail, callbacks)\n\n      nil ->\n        callbacks_for_impls(tail, callbacks)\n    end\n  end\n\n  # Determines whether there is at least one callback defined for the given behaviour.\n  # If not, that means that the behaviour has not been defined.\n  defp behaviour_defined?(callbacks, behaviour) do\n    callbacks\n    |> Map.values()\n    |> List.flatten()\n    |> Enum.any?(fn\n      {_kind, ^behaviour, _optional?} -> true\n      {_kind, _behaviour, _optional?} -> false\n    end)\n  end\n\n  defp warn_missing_impls(%{callbacks: callbacks} = context, _impl_contexts, _defs)\n       when map_size(callbacks) == 0 do\n    context\n  end\n\n  defp warn_missing_impls(context, impl_contexts, defs) do\n    for {pair, kind, meta, _clauses} <- defs, kind in [:def, :defmacro], reduce: context do\n      context ->\n        with {:ok, callbacks} <- Map.fetch(context.callbacks, pair),\n             {_, behaviour, _} <-\n               Enum.find(callbacks, fn {_, behaviour, _} ->\n                 missing_impl_in_context?(meta, behaviour, impl_contexts)\n               end) do\n          warn(context, {:missing_impl, pair, kind, behaviour},\n            line: :elixir_utils.get_line(meta)\n          )\n        else\n          _ -> context\n        end\n    end\n  end\n\n  defp missing_impl_in_context?(meta, behaviour, impl_contexts) do\n    case impl_contexts do\n      %{^behaviour => known} -> Keyword.get(meta, :context) in known\n      %{} -> not Keyword.has_key?(meta, :context)\n    end\n  end\n\n  defp format_definition(kind, {name, arity}) do\n    format_definition(kind) <> \" #{name}/#{arity}\"\n  end\n\n  defp format_definition(:defmacro), do: \"macro\"\n  defp format_definition(:defmacrop), do: \"macro\"\n  defp format_definition(:def), do: \"function\"\n  defp format_definition(:defp), do: \"function\"\n\n  defp known_callbacks(callbacks) when map_size(callbacks) == 0 do\n    \". There are no known callbacks, please specify the proper @behaviour \" <>\n      \"and make sure it defines callbacks\"\n  end\n\n  defp known_callbacks(callbacks) do\n    formatted_callbacks =\n      for {{name, arity}, list} <- callbacks, {kind, module, _} <- list do\n        \"\\n  * \" <> Exception.format_mfa(module, name, arity) <> \" (#{format_definition(kind)})\"\n      end\n\n    \". The known callbacks are:\\n#{formatted_callbacks}\\n\"\n  end\n\n  defp normalize_macro_or_function_callback({function_name, arity}) do\n    case :erlang.atom_to_list(function_name) do\n      # Macros are always provided one extra argument in behaviour_info/1\n      [?M, ?A, ?C, ?R, ?O, ?-] ++ tail ->\n        {{:erlang.list_to_atom(tail), arity - 1}, :defmacro}\n\n      _ ->\n        {{function_name, arity}, :def}\n    end\n  end\n\n  def format_diagnostic(warning) do\n    %{message: IO.iodata_to_binary(format_warning(warning))}\n  end\n\n  defp format_warning({:undefined_behaviour, module, behaviour}) do\n    [\n      \"@behaviour \",\n      inspect(behaviour),\n      \" does not exist (in module \",\n      inspect(module),\n      \")\"\n    ]\n  end\n\n  defp format_warning({:module_does_not_define_behaviour, module, behaviour}) do\n    [\"module \", inspect(behaviour), \" is not a behaviour (in module \", inspect(module), \")\"]\n  end\n\n  defp format_warning({:duplicate_behaviour, module, behaviour, conflict, kind, callback})\n       when conflict == behaviour do\n    [\n      \"the behaviour \",\n      inspect(behaviour),\n      \" has been declared twice (conflict in \",\n      format_definition(kind, callback),\n      \" in module \",\n      inspect(module),\n      \")\"\n    ]\n  end\n\n  defp format_warning({:duplicate_behaviour, module, behaviour, conflict, kind, callback}) do\n    [\n      \"conflicting behaviours found. Callback \",\n      format_definition(kind, callback),\n      \" is defined by both \",\n      inspect(conflict),\n      \" and \",\n      inspect(behaviour),\n      \" (in module \",\n      inspect(module),\n      \")\"\n    ]\n  end\n\n  defp format_warning({:missing_callback, module, callback, kind, behaviour}) do\n    [\n      format_callback(callback, kind, behaviour),\n      \" is not implemented (in module \",\n      inspect(module),\n      \")\"\n    ]\n  end\n\n  defp format_warning({:callback_mismatch, module, callback, kind, wrong_kind, behaviour}) do\n    [\n      format_callback(callback, kind, behaviour),\n      \" was implemented as \\\"\",\n      to_string(wrong_kind),\n      \"\\\" but should have been \\\"\",\n      to_string(kind),\n      \"\\\" (in module \",\n      inspect(module),\n      \")\"\n    ]\n  end\n\n  defp format_warning({:private_function, callback, kind}) do\n    [\n      format_definition(kind, callback),\n      \" is private, @impl attribute is always discarded for private functions/macros\"\n    ]\n  end\n\n  defp format_warning({:no_behaviours, callback, kind, value}) do\n    [\n      \"got \\\"@impl \",\n      inspect(value),\n      \"\\\" for \",\n      format_definition(kind, callback),\n      \" but no behaviour was declared\"\n    ]\n  end\n\n  defp format_warning({:impl_not_defined, callback, kind, {_fa, behaviour}}) do\n    [\n      \"got \\\"@impl false\\\" for \",\n      format_definition(kind, callback),\n      \" but it is a callback specified in \",\n      inspect(behaviour)\n    ]\n  end\n\n  defp format_warning({:impl_defined, callback, kind, callbacks}) do\n    [\n      \"got \\\"@impl true\\\" for \",\n      format_definition(kind, callback),\n      \" but no behaviour specifies such callback\",\n      known_callbacks(callbacks)\n    ]\n  end\n\n  defp format_warning({:behaviour_not_declared, callback, kind, behaviour}) do\n    [\n      \"got \\\"@impl \",\n      inspect(behaviour),\n      \"\\\" for \",\n      format_definition(kind, callback),\n      \" but this behaviour was not declared with @behaviour\"\n    ]\n  end\n\n  defp format_warning({:callback_not_defined, callback, kind, behaviour, callbacks}) do\n    behaviour_string = inspect(behaviour)\n\n    [\n      \"got \\\"@impl \",\n      behaviour_string,\n      \"\\\" for \",\n      format_definition(kind, callback),\n      \" but \",\n      behaviour_string,\n      \" does not specify such callback\",\n      known_callbacks(callbacks)\n    ]\n  end\n\n  defp format_warning({:missing_impl, callback, kind, behaviour}) do\n    [\n      \"module attribute @impl was not set for \",\n      format_definition(kind, callback),\n      \" callback (specified in \",\n      inspect(behaviour),\n      \"). \" <>\n        \"This either means you forgot to add the \\\"@impl true\\\" annotation before the \" <>\n        \"definition or that you are accidentally overriding this callback\"\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/parallel_checker.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Module.ParallelChecker do\n  @moduledoc false\n  @elixir_checker_version :elixir_erl.checker_version()\n\n  import Kernel, except: [spawn: 3]\n\n  @type cache() :: {pid(), :ets.tid()}\n  @type warning() :: term()\n  @type error() :: term()\n  @type mode() :: :erlang | :elixir | :protocol\n\n  @typedoc \"\"\"\n  Options for `start_link/1`.\n  \"\"\"\n  @type start_link_opts :: [\n          {:max_concurrency, pos_integer()}\n          | {:long_verification_threshold, pos_integer()}\n          | {:each_long_verification, (module() -> term()) | (module(), pid() -> term())}\n          | {atom(), term()}\n        ]\n\n  @doc \"\"\"\n  Initializes the parallel checker process.\n  \"\"\"\n  @spec start_link(start_link_opts()) :: {:ok, cache()}\n  def start_link(opts \\\\ []) do\n    :proc_lib.start_link(__MODULE__, :init, [opts])\n  end\n\n  @doc \"\"\"\n  Stops the parallel checker process.\n  \"\"\"\n  def stop({checker, _table}) do\n    send(checker, {__MODULE__, :stop})\n    :ok\n  end\n\n  @doc \"\"\"\n  Gets the parallel checker data from pdict.\n  \"\"\"\n  def get do\n    case :erlang.get(:elixir_checker_info) do\n      {parent, nil} ->\n        {:ok, cache} = start_link()\n        put(parent, cache)\n        {parent, cache}\n\n      {parent, cache} ->\n        {parent, cache}\n    end\n  end\n\n  @doc \"\"\"\n  Stores the parallel checker information.\n  \"\"\"\n  def put(pid, {checker, table}) when is_pid(pid) do\n    :erlang.put(:elixir_checker_info, {pid, {checker, table}})\n  end\n\n  @doc \"\"\"\n  Spawns a process that runs the parallel checker.\n  \"\"\"\n  def spawn({pid, {checker, table}}, module, module_map, signatures, beam_location, log?) do\n    # Protocols may have been consolidated. So if we know their beam location,\n    # we discard their module map on purpose and start from file.\n    info =\n      if beam_location != [] and Keyword.has_key?(module_map.attributes, :__protocol__) do\n        List.to_string(beam_location)\n      else\n        cache_from_module_map(table, module_map, signatures)\n      end\n\n    inner_spawn(pid, checker, table, module, info, log?)\n  end\n\n  defp inner_spawn(pid, checker, table, module, info, log?) do\n    ref = make_ref()\n\n    spawned =\n      spawn(fn ->\n        mon_ref = Process.monitor(pid)\n\n        receive do\n          {^ref, :cache} ->\n            Process.link(pid)\n\n            {mode, module_tuple} =\n              cond do\n                is_binary(info) ->\n                  location =\n                    case :code.which(module) do\n                      [_ | _] = path -> path\n                      _ -> info\n                    end\n\n                  with {:ok, binary} <- File.read(location),\n                       {:ok,\n                        {_, [{:debug_info, {:debug_info_v1, backend, data}}, {~c\"ExCk\", checker}]}} <-\n                         :beam_lib.chunks(binary, [:debug_info, ~c\"ExCk\"]),\n                       {:ok, module_map} <- backend.debug_info(:elixir_v1, module, data, []),\n                       {@elixir_checker_version, contents} <- :erlang.binary_to_term(checker) do\n                    {cache_chunk(table, module, contents), module_map_to_module_tuple(module_map)}\n                  else\n                    _ -> {:uncached, nil}\n                  end\n\n                is_tuple(info) ->\n                  info\n              end\n\n            # We only make the module available now, so they are not visible during inference\n            :ets.insert(table, {module, mode})\n            send(checker, {ref, :cached})\n\n            receive do\n              {^ref, :check} ->\n                # Set the compiler info so we can collect warnings\n                :erlang.put(:elixir_compiler_info, {pid, self()})\n\n                {warnings, errors} =\n                  if module_tuple do\n                    check_module(module_tuple, {checker, table}, log?)\n                  else\n                    {[], []}\n                  end\n\n                send(pid, {__MODULE__, module, warnings, errors})\n                send(checker, {__MODULE__, :done, module})\n            end\n\n          {:DOWN, ^mon_ref, _, _, _} ->\n            :ok\n        end\n      end)\n\n    register(checker, module, spawned, ref)\n    :ok\n  end\n\n  @doc \"\"\"\n  Verifies the given compilation function\n  by starting a checker if one does not exist.\n\n  See `verify/3`.\n  \"\"\"\n  def verify(fun) do\n    case :erlang.get(:elixir_compiler_info) do\n      :undefined ->\n        previous = :erlang.put(:elixir_checker_info, {self(), nil})\n\n        try do\n          result = fun.()\n\n          case :erlang.get(:elixir_checker_info) do\n            {_, nil} -> :ok\n            {_, cache} -> verify(cache, [])\n          end\n\n          result\n        after\n          {_, cache} = :erlang.get(:elixir_checker_info)\n\n          if previous != :undefined do\n            :erlang.put(:elixir_checker_info, previous)\n          else\n            :erlang.erase(:elixir_checker_info)\n          end\n\n          cache && stop(cache)\n        end\n\n      _ ->\n        # If we are during compilation, then they will be\n        # reported to the compiler, which will validate them.\n        fun.()\n    end\n  end\n\n  @doc \"\"\"\n  Receives pairs of module maps and BEAM binaries.\n\n  Returns the updated list of warnings from the verification.\n  \"\"\"\n  @spec verify(cache(), [{module(), Path.t()}]) :: {[warning()], [error()]}\n  def verify({checker, table}, runtime_files) do\n    value = :erlang.get(:elixir_code_diagnostics)\n    log? = not match?({_, false}, value)\n\n    for {module, file} <- runtime_files do\n      inner_spawn(self(), checker, table, module, file, log?)\n    end\n\n    count = :gen_server.call(checker, :start, :infinity)\n    {warnings, errors} = collect_results(count, [], [])\n\n    case :erlang.get(:elixir_code_diagnostics) do\n      :undefined -> :ok\n      {tail, log?} -> :erlang.put(:elixir_code_diagnostics, {errors ++ warnings ++ tail, log?})\n    end\n\n    {warnings, errors}\n  end\n\n  defp collect_results(0, warnings, errors) do\n    {warnings, errors}\n  end\n\n  defp collect_results(count, warnings, errors) do\n    receive do\n      {:diagnostic, %{file: file} = diagnostic, read_snippet} ->\n        :elixir_errors.print_diagnostic(diagnostic, read_snippet)\n        diagnostic = %{diagnostic | file: file && Path.absname(file)}\n\n        if Map.get(diagnostic, :severity, :warning) == :error do\n          collect_results(count, warnings, [diagnostic | errors])\n        else\n          collect_results(count, [diagnostic | warnings], errors)\n        end\n\n      {__MODULE__, _module, new_warnings, new_errors} ->\n        collect_results(count - 1, new_warnings ++ warnings, new_errors ++ errors)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the export kind and deprecation reason for the given MFA from\n  the cache. If the module does not exist return `:badmodule`,\n  or if the function does not exist return `{:badfunction, mode}`.\n  \"\"\"\n  @spec fetch_export(cache(), module(), atom(), arity(), boolean()) ::\n          {:ok, mode(), binary() | nil, {:infer, [term()] | nil, [term()]} | :none}\n          | :badmodule\n          | {:badfunction, mode()}\n  def fetch_export({checker, table}, module, fun, arity, force?) do\n    case :ets.lookup(table, module) do\n      [] ->\n        if force? do\n          cache_module({checker, table}, module)\n          fetch_export({checker, table}, module, fun, arity, false)\n        else\n          :badmodule\n        end\n\n      [{_key, :uncached}] ->\n        cache_module({checker, table}, module)\n        fetch_export({checker, table}, module, fun, arity, false)\n\n      [{_key, :not_found}] ->\n        :badmodule\n\n      [{_key, mode}] ->\n        case :ets.lookup(table, {module, {fun, arity}}) do\n          [{_key, reason, signature}] -> {:ok, mode, reason, signature}\n          [] -> {:badfunction, mode}\n        end\n    end\n  end\n\n  ## Module checking\n\n  defp check_module(module_tuple, cache, log?) do\n    {module, file, line, definitions, no_warn_undefined, behaviours, impls, attrs, after_verify} =\n      module_tuple\n\n    behaviour_warnings =\n      Module.Behaviour.check_behaviours_and_impls(\n        module,\n        file,\n        line,\n        behaviours,\n        impls,\n        definitions\n      )\n\n    {warnings, errors} =\n      module\n      |> Module.Types.warnings(file, attrs, definitions, no_warn_undefined, cache)\n      |> Kernel.++(behaviour_warnings)\n      |> group_diagnostics()\n      |> emit_diagnostics(file, log?)\n      |> Enum.split_with(&(&1.severity == :warning))\n\n    Enum.each(after_verify, fn {verify_mod, verify_fun} ->\n      apply(verify_mod, verify_fun, [module])\n    end)\n\n    {warnings, errors}\n  end\n\n  defp module_map_to_module_tuple(module_map) do\n    %{\n      module: module,\n      file: file,\n      compile_opts: compile_opts,\n      definitions: definitions,\n      attributes: attributes,\n      impls: impls,\n      after_verify: after_verify\n    } = module_map\n\n    # TODO: Match on anno directly in Elixir v1.22+\n    line =\n      case module_map do\n        %{anno: anno} -> :erl_anno.line(anno)\n        %{line: line} -> line\n      end\n\n    behaviours = for {:behaviour, module} <- attributes, do: module\n\n    no_warn_undefined =\n      compile_opts\n      |> extract_no_warn_undefined()\n      |> merge_compiler_no_warn_undefined()\n\n    attributes = Keyword.take(attributes, [:__protocol__, :__impl__])\n\n    {module, file, line, definitions, no_warn_undefined, behaviours, impls, attributes,\n     after_verify}\n  end\n\n  defp extract_no_warn_undefined(compile_opts) do\n    for(\n      {:no_warn_undefined, values} <- compile_opts,\n      value <- List.wrap(values),\n      do: value\n    )\n  end\n\n  defp merge_compiler_no_warn_undefined(no_warn_undefined) do\n    case Code.get_compiler_option(:no_warn_undefined) do\n      :all -> :all\n      list when is_list(list) -> no_warn_undefined ++ list\n    end\n  end\n\n  ## Warning helpers\n\n  defp group_diagnostics(triplets) do\n    {ungrouped, grouped} =\n      Enum.reduce(triplets, {[], %{}}, fn {module, term, location}, {ungrouped, grouped} ->\n        %{message: _} = diagnostic = module.format_diagnostic(term)\n\n        if Map.get(diagnostic, :group, false) do\n          locations = MapSet.new([location])\n\n          grouped =\n            Map.update(grouped, term, {locations, diagnostic}, fn\n              {locations, diagnostic} -> {MapSet.put(locations, location), diagnostic}\n            end)\n\n          {ungrouped, grouped}\n        else\n          {[{[location], diagnostic} | ungrouped], grouped}\n        end\n      end)\n\n    grouped =\n      Enum.map(grouped, fn {_warning, {locations, diagnostic}} ->\n        {Enum.sort(locations), diagnostic}\n      end)\n\n    Enum.sort(ungrouped ++ grouped)\n  end\n\n  defp emit_diagnostics(warnings, file, log?) do\n    Enum.flat_map(warnings, fn {locations, diagnostic} ->\n      diagnostics = Enum.map(locations, &to_diagnostic(diagnostic, file, &1))\n      log? and print_diagnostics(diagnostics)\n      diagnostics\n    end)\n  end\n\n  defp print_diagnostics([diagnostic]) do\n    :elixir_errors.print_diagnostic(diagnostic, true)\n  end\n\n  defp print_diagnostics(diagnostics) do\n    :elixir_errors.print_diagnostics(diagnostics)\n  end\n\n  defp to_diagnostic(diagnostic, source, {file, position, mfa}) when is_list(position) do\n    file = Path.absname(file)\n\n    %{\n      severity: :warning,\n      source: source,\n      file: file,\n      position: position_to_tuple(position),\n      stacktrace: [to_stacktrace(file, position, mfa)],\n      span: nil\n    }\n    |> Map.merge(diagnostic)\n  end\n\n  defp position_to_tuple(position) do\n    case position[:column] do\n      nil -> position[:line] || 0\n      col -> {position[:line], col}\n    end\n  end\n\n  defp to_stacktrace(file, pos, {module, fun, arity}),\n    do: {module, fun, arity, location(file, pos)}\n\n  defp to_stacktrace(file, pos, nil),\n    do: {:elixir_compiler, :__FILE__, 1, location(file, pos)}\n\n  defp to_stacktrace(file, pos, module),\n    do: {module, :__MODULE__, 0, location(file, pos)}\n\n  defp location(file, position) do\n    [{:file, String.to_charlist(Path.relative_to_cwd(file))} | position]\n  end\n\n  ## Cache\n\n  defp cache_module({checker, table}, module) do\n    if lock(checker, module) do\n      object_code = :code.get_object_code(module)\n\n      mode =\n        with {^module, binary, _filename} <- object_code,\n             {:ok, {^module, [{~c\"ExCk\", chunk}]}} <- :beam_lib.chunks(binary, [~c\"ExCk\"]),\n             {@elixir_checker_version, contents} <- :erlang.binary_to_term(chunk) do\n          # The chunk has more information, so that's our preference\n          cache_chunk(table, module, contents)\n        else\n          _ ->\n            # Otherwise, if the module is loaded, use its info\n            case :erlang.module_loaded(module) do\n              true ->\n                {mode, exports} = info_exports(module)\n                deprecated = info_deprecated(module)\n                cache_info(table, module, exports, deprecated, %{})\n                mode\n\n              false ->\n                # Or load exports from chunk\n                with {^module, binary, _filename} <- object_code,\n                     {:ok, {^module, [exports: exports]}} <- :beam_lib.chunks(binary, [:exports]) do\n                  cache_info(table, module, exports, %{}, %{})\n                  :erlang\n                else\n                  _ -> :not_found\n                end\n            end\n        end\n\n      :ets.insert(table, {module, mode})\n      unlock(checker, module, mode)\n    end\n  end\n\n  defp info_exports(module) do\n    try do\n      module.__info__(:functions)\n    rescue\n      _ -> {:erlang, module.module_info(:exports)}\n    else\n      functions ->\n        {elixir_mode(module.module_info(:attributes)), behaviour_exports(module) ++ functions}\n    end\n  end\n\n  defp info_deprecated(module) do\n    Map.new(module.__info__(:deprecated))\n  rescue\n    _ -> %{}\n  end\n\n  defp elixir_mode(attributes) do\n    if Keyword.has_key?(attributes, :__protocol__), do: :protocol, else: :elixir\n  end\n\n  defp cache_from_module_map(table, map, signatures) do\n    exports =\n      behaviour_exports(map) ++\n        for({function, :def, _meta, _clauses} <- map.definitions, do: function)\n\n    cache_info(table, map.module, exports, Map.new(map.deprecated), signatures)\n    {elixir_mode(map.attributes), module_map_to_module_tuple(map)}\n  end\n\n  defp cache_info(table, module, exports, deprecated, sigs) do\n    Enum.each(exports, fn fa ->\n      reason = Map.get(deprecated, fa)\n      :ets.insert(table, {{module, fa}, reason, Map.get(sigs, fa, :none)})\n    end)\n  end\n\n  defp cache_chunk(table, module, contents) do\n    Enum.each(contents.exports, fn {{fun, arity}, info} ->\n      sig =\n        case info do\n          %{sig: {key, _, _} = sig} when key in [:infer, :strong] -> sig\n          _ -> :none\n        end\n\n      :ets.insert(\n        table,\n        {{module, {fun, arity}}, Map.get(info, :deprecated), sig}\n      )\n    end)\n\n    Map.get(contents, :mode, :elixir)\n  end\n\n  defp behaviour_exports(%{defines_behaviour: true}), do: [{:behaviour_info, 1}]\n  defp behaviour_exports(%{defines_behaviour: false}), do: []\n\n  defp behaviour_exports(module) when is_atom(module) do\n    if function_exported?(module, :behaviour_info, 1) do\n      [{:behaviour_info, 1}]\n    else\n      []\n    end\n  end\n\n  defp lock(server, module) do\n    :gen_server.call(server, {:lock, module}, :infinity)\n  end\n\n  defp unlock(server, module, mode) do\n    :gen_server.call(server, {:unlock, module, mode}, :infinity)\n  end\n\n  defp register(server, module, pid, ref) do\n    :gen_server.cast(server, {:register, module, pid, ref})\n  end\n\n  ## Server callbacks\n\n  def init(options) do\n    table = :ets.new(__MODULE__, [:set, :public, {:read_concurrency, true}])\n    :proc_lib.init_ack({:ok, {self(), table}})\n\n    case :elixir_config.get(:infer_signatures) do\n      false ->\n        false\n\n      applications ->\n        for application <- applications do\n          case :application.get_key(application, :modules) do\n            {:ok, modules} ->\n              :ets.insert(table, Enum.map(modules, &{&1, :uncached}))\n\n            :undefined ->\n              IO.warn(\n                \"cannot infer signatures from #{inspect(application)} because it is not loaded\",\n                []\n              )\n          end\n        end\n    end\n\n    schedulers =\n      Keyword.get_lazy(options, :max_concurrency, fn ->\n        max(:erlang.system_info(:schedulers_online), 2)\n      end)\n\n    threshold = Keyword.get(options, :long_verification_threshold, 10) * 1000\n\n    callback =\n      case Keyword.get(options, :each_long_verification, fn _module, _pid -> :ok end) do\n        fun when is_function(fun, 1) -> fn module, _pid -> fun.(module) end\n        fun when is_function(fun, 2) -> fun\n      end\n\n    state = %{\n      waiting: %{},\n      modules: [],\n      spawned: %{},\n      schedulers: schedulers,\n      threshold: threshold,\n      callback: callback,\n      protocols: [],\n      table: table\n    }\n\n    :gen_server.enter_loop(__MODULE__, [], state)\n  end\n\n  def handle_call(:start, _from, %{modules: modules, protocols: protocols, table: table} = state) do\n    :ets.insert(table, Enum.map(protocols, &{&1, :uncached}))\n\n    for {_module, pid, ref} <- modules do\n      send(pid, {ref, :cache})\n    end\n\n    for {_module, _pid, ref} <- modules do\n      receive do\n        {^ref, :cached} -> :ok\n      end\n    end\n\n    {:reply, length(modules), run_checkers(%{state | protocols: []})}\n  end\n\n  def handle_call({:lock, module}, from, %{waiting: waiting} = state) do\n    case waiting do\n      %{^module => from_list} ->\n        waiting = Map.put(state.waiting, module, [from | from_list])\n        {:noreply, %{state | waiting: waiting}}\n\n      %{} ->\n        waiting = Map.put(state.waiting, module, [])\n        {:reply, true, %{state | waiting: waiting}}\n    end\n  end\n\n  def handle_call({:unlock, module, mode}, _from, state) do\n    %{waiting: waiting, protocols: protocols} = state\n    from_list = Map.fetch!(waiting, module)\n    Enum.each(from_list, &:gen_server.reply(&1, false))\n\n    waiting = Map.delete(waiting, module)\n    protocols = if mode == :protocol, do: [module | protocols], else: protocols\n    {:reply, :ok, %{state | waiting: waiting, protocols: protocols}}\n  end\n\n  def handle_info({__MODULE__, :timeout, module, pid}, state) do\n    state.callback.(module, pid)\n    {:noreply, state}\n  end\n\n  def handle_info({__MODULE__, :done, module}, state) do\n    # Unfortunately we cannot assume uniqueness because the same module\n    # may be defined by mistake several times\n    {timer, spawned} = Map.pop(state.spawned, module)\n    timer && Process.cancel_timer(timer)\n    {:noreply, run_checkers(%{state | spawned: spawned})}\n  end\n\n  def handle_info({__MODULE__, :stop}, state) do\n    {:stop, :normal, state}\n  end\n\n  def handle_cast({:register, module, pid, ref}, %{modules: modules} = state) do\n    {:noreply, %{state | modules: [{module, pid, ref} | modules]}}\n  end\n\n  defp run_checkers(%{modules: []} = state) do\n    state\n  end\n\n  defp run_checkers(%{spawned: spawned, schedulers: schedulers} = state)\n       when map_size(spawned) >= schedulers do\n    state\n  end\n\n  defp run_checkers(%{modules: [{module, pid, ref} | modules]} = state) do\n    send(pid, {ref, :check})\n    timer = Process.send_after(self(), {__MODULE__, :timeout, module, pid}, state.threshold)\n    spawned = Map.put(state.spawned, module, timer)\n    run_checkers(%{state | modules: modules, spawned: spawned})\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/types/apply.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Module.Types.Apply do\n  # Typing functionality shared between Expr and Pattern.\n  # Generic AST and Enum helpers go to Module.Types.Helpers.\n  @moduledoc false\n\n  alias Module.ParallelChecker\n  import Module.Types.{Helpers, Descr}\n\n  # We limit the size of the union for two reasons:\n  # To avoid really large outputs in reports and to\n  # reduce the computation cost of inferred code.\n  @max_clauses 16\n\n  @atom_true atom([true])\n  @atom_false atom([false])\n\n  ## Signatures\n\n  # Define strong arrows found in the standard library.\n  # A strong arrow means that, if a type outside of its\n  # domain is given, an error is raised. We are also\n  # ensuring that domains for the same function have\n  # no overlaps.\n\n  # Remote for callback info functions\n\n  kw = fn kw ->\n    kw\n    |> Enum.map(fn {key, type} when is_atom(key) ->\n      tuple([atom([key]), type])\n    end)\n    |> Enum.reduce(&union/2)\n    |> list()\n  end\n\n  fas = list(tuple([atom(), integer()]))\n  struct_info = list(closed_map(default: if_set(term()), field: atom()))\n\n  shared_info = [\n    attributes: list(tuple([atom(), list(term())])),\n    compile: kw.(version: list(integer()), source: list(integer()), options: list(term())),\n    exports: fas,\n    md5: binary(),\n    module: atom()\n  ]\n\n  module_info = [functions: fas, nifs: fas] ++ shared_info\n\n  elixir_info =\n    [\n      deprecated: list(tuple([tuple([atom(), integer()]), binary()])),\n      exports_md5: binary(),\n      functions: fas,\n      macros: fas,\n      struct: struct_info |> union(atom([nil]))\n    ] ++ shared_info\n\n  infos =\n    [\n      # We have a special key that tracks if something is a struct or not\n      {{:__info__, true}, Keyword.put(elixir_info, :struct, struct_info)},\n      {{:__info__, false}, Keyword.put(elixir_info, :struct, atom([nil]))},\n      {:__info__, elixir_info},\n      {:behaviour_info, callbacks: fas, optional_callbacks: fas},\n      {:module_info, module_info},\n      # TODO: Move this to a type signature declared by `defprotocol` (or perhaps part of the behaviour)\n      {:__protocol__,\n       module: atom(),\n       functions: fas,\n       consolidated?: boolean(),\n       impls: union(atom([:not_consolidated]), tuple([atom([:consolidated]), list(atom())]))}\n    ]\n\n  for {name, clauses} <- infos do\n    domain = atom(Keyword.keys(clauses))\n    clauses = Enum.map(clauses, fn {key, return} -> {[atom([key])], return} end)\n\n    def signature(unquote(name), 1) do\n      {:strong, [unquote(Macro.escape(domain))], unquote(Macro.escape(clauses))}\n    end\n  end\n\n  def signature(:module_info, 0) do\n    {:strong, nil, [{[], unquote(Macro.escape(kw.(module_info)))}]}\n  end\n\n  def signature(_, _), do: :none\n\n  # Remote for compiler functions\n\n  mfargs = [atom(), atom(), list(term())]\n\n  send_destination =\n    pid()\n    |> union(reference())\n    |> union(port())\n    |> union(atom())\n    |> union(tuple([atom(), atom()]))\n\n  basic_arith_2_args_clauses = [\n    {[integer(), integer()], integer()},\n    {[integer(), float()], float()},\n    {[float(), integer()], float()},\n    {[float(), float()], float()}\n  ]\n\n  args_or_arity = union(list(term()), integer())\n  args_or_none = union(list(term()), atom([:none]))\n  extra_info = kw.(file: list(integer()), line: integer(), error_info: open_map())\n\n  raise_stacktrace =\n    list(\n      tuple([atom(), atom(), args_or_arity, extra_info])\n      |> union(tuple([atom(), atom(), args_or_arity]))\n      |> union(tuple([fun(), args_or_arity, extra_info]))\n      |> union(tuple([fun(), args_or_arity]))\n    )\n\n  not_signature =\n    for bool <- [true, false] do\n      {[atom([bool])], atom([not bool])}\n    end\n\n  and_signature =\n    for left <- [true, false], right <- [true, false] do\n      {[atom([left]), atom([right])], atom([left and right])}\n    end\n\n  or_signature =\n    for left <- [true, false], right <- [true, false] do\n      {[atom([left]), atom([right])], atom([left or right])}\n    end\n\n  for {mod, fun, clauses} <- [\n        # :binary\n        {:binary, :copy, [{[binary(), integer()], binary()}]},\n\n        # :erlang\n        {:erlang, :+, [{[integer()], integer()}, {[float()], float()}]},\n        {:erlang, :+, basic_arith_2_args_clauses},\n        {:erlang, :-, [{[integer()], integer()}, {[float()], float()}]},\n        {:erlang, :-, basic_arith_2_args_clauses},\n        {:erlang, :*, basic_arith_2_args_clauses},\n        {:erlang, :/, [{[union(integer(), float()), union(integer(), float())], float()}]},\n        {:erlang, :\"/=\", [{[term(), term()], boolean()}]},\n        {:erlang, :\"=/=\", [{[term(), term()], boolean()}]},\n        {:erlang, :<, [{[term(), term()], boolean()}]},\n        {:erlang, :\"=<\", [{[term(), term()], boolean()}]},\n        {:erlang, :==, [{[term(), term()], boolean()}]},\n        {:erlang, :\"=:=\", [{[term(), term()], boolean()}]},\n        {:erlang, :>, [{[term(), term()], boolean()}]},\n        {:erlang, :>=, [{[term(), term()], boolean()}]},\n        {:erlang, :abs, [{[integer()], integer()}, {[float()], float()}]},\n        # TODO: Decide if it returns dynamic() or term()\n        {:erlang, :apply, [{[fun(), list(term())], dynamic()}]},\n        {:erlang, :apply, [{[atom(), atom(), list(term())], dynamic()}]},\n        {:erlang, :and, and_signature},\n        {:erlang, :atom_to_binary, [{[atom()], binary()}]},\n        {:erlang, :atom_to_list, [{[atom()], list(integer())}]},\n        {:erlang, :band, [{[integer(), integer()], integer()}]},\n        {:erlang, :binary_part, [{[binary(), integer(), integer()], binary()}]},\n        {:erlang, :binary_to_atom, [{[binary()], atom()}]},\n        {:erlang, :binary_to_existing_atom, [{[binary()], atom()}]},\n        {:erlang, :binary_to_integer, [{[binary()], integer()}]},\n        {:erlang, :binary_to_integer, [{[binary(), integer()], integer()}]},\n        {:erlang, :binary_to_float, [{[binary()], float()}]},\n        {:erlang, :bit_size, [{[bitstring()], integer()}]},\n        {:erlang, :bnot, [{[integer()], integer()}]},\n        {:erlang, :bor, [{[integer(), integer()], integer()}]},\n        {:erlang, :bsl, [{[integer(), integer()], integer()}]},\n        {:erlang, :bsr, [{[integer(), integer()], integer()}]},\n        {:erlang, :bxor, [{[integer(), integer()], integer()}]},\n        {:erlang, :byte_size, [{[bitstring()], integer()}]},\n        {:erlang, :ceil, [{[union(integer(), float())], integer()}]},\n        {:erlang, :div, [{[integer(), integer()], integer()}]},\n        {:erlang, :error, [{[term()], none()}]},\n        {:erlang, :error, [{[term(), args_or_none], none()}]},\n        {:erlang, :error, [{[term(), args_or_none, kw.(error_info: open_map())], none()}]},\n        {:erlang, :floor, [{[union(integer(), float())], integer()}]},\n        {:erlang, :function_exported, [{[atom(), atom(), integer()], boolean()}]},\n        {:erlang, :integer_to_binary, [{[integer()], binary()}]},\n        {:erlang, :integer_to_binary, [{[integer(), integer()], binary()}]},\n        {:erlang, :integer_to_list, [{[integer()], non_empty_list(integer())}]},\n        {:erlang, :integer_to_list, [{[integer(), integer()], non_empty_list(integer())}]},\n        {:erlang, :is_function, [{[term(), integer()], boolean()}]},\n        {:erlang, :is_map_key, [{[term(), open_map()], boolean()}]},\n        {:erlang, :length, [{[list(term())], integer()}]},\n        {:erlang, :list_to_atom, [{[list(integer())], atom()}]},\n        {:erlang, :list_to_existing_atom, [{[list(integer())], atom()}]},\n        {:erlang, :list_to_float, [{[non_empty_list(integer())], float()}]},\n        {:erlang, :list_to_integer, [{[non_empty_list(integer())], integer()}]},\n        {:erlang, :list_to_integer, [{[non_empty_list(integer()), integer()], integer()}]},\n        {:erlang, :make_ref, [{[], reference()}]},\n        {:erlang, :make_tuple, [{[integer(), term()], tuple()}]},\n        {:erlang, :map_size, [{[open_map()], integer()}]},\n        {:erlang, :node, [{[], atom()}]},\n        {:erlang, :node, [{[pid() |> union(reference()) |> union(port())], atom()}]},\n        {:erlang, :not, not_signature},\n        {:erlang, :or, or_signature},\n        {:erlang, :raise, [{[atom([:error, :exit, :throw]), term(), raise_stacktrace], none()}]},\n        {:erlang, :rem, [{[integer(), integer()], integer()}]},\n        {:erlang, :round, [{[union(integer(), float())], integer()}]},\n        {:erlang, :self, [{[], pid()}]},\n        {:erlang, :spawn, [{[fun(0)], pid()}]},\n        {:erlang, :spawn, [{mfargs, pid()}]},\n        {:erlang, :spawn_link, [{[fun(0)], pid()}]},\n        {:erlang, :spawn_link, [{mfargs, pid()}]},\n        {:erlang, :spawn_monitor, [{[fun(0)], tuple([pid(), reference()])}]},\n        {:erlang, :spawn_monitor, [{mfargs, tuple([pid(), reference()])}]},\n        {:erlang, :split_binary, [{[binary(), integer()], tuple([binary(), binary()])}]},\n        {:erlang, :tuple_size, [{[open_tuple([])], integer()}]},\n        {:erlang, :trunc, [{[union(integer(), float())], integer()}]},\n\n        # TODO: Replace term()/dynamic() by parametric types\n        {:erlang, :++,\n         [\n           {[empty_list(), term()], dynamic(term())},\n           {[non_empty_list(term()), term()], dynamic(non_empty_list(term(), term()))}\n         ]},\n        {:erlang, :--, [{[list(term()), list(term())], dynamic(list(term()))}]},\n        {:erlang, :delete_element, [{[integer(), open_tuple([])], dynamic(open_tuple([]))}]},\n        {:erlang, :hd, [{[non_empty_list(term(), term())], dynamic()}]},\n        {:erlang, :element, [{[integer(), open_tuple([])], dynamic()}]},\n        {:erlang, :insert_element,\n         [{[integer(), open_tuple([]), term()], dynamic(open_tuple([]))}]},\n        {:erlang, :list_to_tuple, [{[list(term())], dynamic(open_tuple([]))}]},\n        {:erlang, :map_get, [{[term(), open_map()], term()}]},\n        {:erlang, :max, [{[term(), term()], dynamic()}]},\n        {:erlang, :min, [{[term(), term()], dynamic()}]},\n        {:erlang, :send, [{[send_destination, term()], dynamic()}]},\n        {:erlang, :setelement, [{[integer(), open_tuple([]), term()], dynamic(open_tuple([]))}]},\n        {:erlang, :tl, [{[non_empty_list(term(), term())], dynamic()}]},\n        {:erlang, :tuple_to_list, [{[open_tuple([])], dynamic(list(term()))}]},\n\n        ## Lists\n        {:lists, :member, [{[term(), list(term())], boolean()}]},\n\n        ## Map\n        {Map, :from_struct, [{[open_map()], open_map(__struct__: not_set())}]},\n        {Map, :get, [{[open_map(), term()], term()}]},\n        {Map, :get, [{[open_map(), term(), term()], term()}]},\n        {Map, :get_lazy, [{[open_map(), term(), fun(0)], term()}]},\n        {Map, :pop, [{[open_map(), term()], tuple([term(), open_map()])}]},\n        {Map, :pop, [{[open_map(), term(), term()], tuple([term(), open_map()])}]},\n        {Map, :pop!, [{[open_map(), term()], tuple([term(), open_map()])}]},\n        {Map, :pop_lazy, [{[open_map(), term(), fun(0)], tuple([term(), open_map()])}]},\n        {Map, :put_new, [{[open_map(), term(), term()], open_map()}]},\n        {Map, :put_new_lazy, [{[open_map(), term(), fun(0)], open_map()}]},\n        {Map, :replace, [{[open_map(), term(), term()], open_map()}]},\n        {Map, :replace_lazy, [{[open_map(), term(), fun(1)], open_map()}]},\n        {Map, :update, [{[open_map(), term(), term(), fun(1)], open_map()}]},\n        {Map, :update!, [{[open_map(), term(), fun(1)], open_map()}]},\n        {:maps, :from_keys, [{[list(term()), term()], open_map()}]},\n        {:maps, :find,\n         [{[term(), open_map()], tuple([atom([:ok]), term()]) |> union(atom([:error]))}]},\n        {:maps, :get, [{[term(), open_map()], term()}]},\n        {:maps, :is_key, [{[term(), open_map()], boolean()}]},\n        {:maps, :keys, [{[open_map()], list(term())}]},\n        {:maps, :put, [{[term(), term(), open_map()], open_map()}]},\n        {:maps, :remove, [{[term(), open_map()], open_map()}]},\n        {:maps, :take,\n         [{[term(), open_map()], tuple([term(), open_map()]) |> union(atom([:error]))}]},\n        {:maps, :to_list, [{[open_map()], list(tuple([term(), term()]))}]},\n        {:maps, :update, [{[term(), term(), open_map()], open_map()}]},\n        {:maps, :values, [{[open_map()], list(term())}]}\n      ] do\n    [arity] = Enum.map(clauses, fn {args, _return} -> length(args) end) |> Enum.uniq()\n\n    true = Code.ensure_loaded?(mod)\n\n    domain_clauses =\n      case clauses do\n        [_] ->\n          {:strong, nil, clauses}\n\n        _ ->\n          domain =\n            clauses\n            |> Enum.map(fn {args, _} -> args end)\n            |> Enum.zip_with(fn types -> Enum.reduce(types, &union/2) end)\n\n          {:strong, domain, clauses}\n      end\n\n    def signature(unquote(mod), unquote(fun), unquote(arity)),\n      do: unquote(Macro.escape(domain_clauses))\n  end\n\n  is_guards = [\n    is_atom: atom(),\n    is_binary: binary(),\n    is_bitstring: bitstring(),\n    is_boolean: boolean(),\n    is_float: float(),\n    is_function: fun(),\n    is_integer: integer(),\n    is_list: union(empty_list(), non_empty_list(term(), term())),\n    is_map: open_map(),\n    is_number: union(float(), integer()),\n    is_pid: pid(),\n    is_port: port(),\n    is_reference: reference(),\n    is_tuple: tuple()\n  ]\n\n  for {guard, type} <- is_guards do\n    domain_clauses =\n      {:strong, [term()],\n       [\n         {[type], atom([true])},\n         {[negation(type)], atom([false])}\n       ]}\n\n    def signature(:erlang, unquote(guard), 1),\n      do: unquote(Macro.escape(domain_clauses))\n  end\n\n  def signature(:erlang, :is_integer, 3),\n    do:\n      unquote(\n        Macro.escape(\n          {:strong, [term(), integer(), integer()],\n           [\n             {[integer(), integer(), integer()], boolean()},\n             {[negation(integer()), integer(), integer()], atom([false])}\n           ]}\n        )\n      )\n\n  def signature(_mod, _fun, _arity), do: :none\n\n  @doc \"\"\"\n  Entry point for applying functions without a known module.\n\n  Builds on top of remote_domain/4 + remote_apply/7.\n  \"\"\"\n  def remote(fun, args, expected, expr, stack, context, of_fun) do\n    {info, domain} = remote_domain(fun, args, expected, stack)\n\n    {args_types, context} =\n      zip_map_reduce(args, domain, context, &of_fun.(&1, &2, expr, stack, &3))\n\n    remote_apply(info, nil, fun, args_types, expr, stack, context)\n  end\n\n  @doc \"\"\"\n  Entry point for applying functions.\n\n  Shared between expression and guards. Builds on top of remote_domain/7 + remote_apply/7\n  \"\"\"\n  def remote(mod, fun, args, expected, expr, stack, context, of_fun) do\n    arity = length(args)\n\n    case :elixir_rewrite.inline(mod, fun, arity) do\n      {new_mod, new_fun} ->\n        do_remote(new_mod, new_fun, args, expected, expr, stack, context, of_fun)\n\n      false ->\n        do_remote(mod, fun, args, expected, expr, stack, context, of_fun)\n    end\n    |> case do\n      {info, domain, context} ->\n        {args_types, context} =\n          zip_map_reduce(args, domain, context, &of_fun.(&1, &2, expr, stack, &3))\n\n        remote_apply(info, mod, fun, args_types, expr, stack, context)\n\n      {type, context} ->\n        {type, context}\n    end\n  end\n\n  # The functions implemented with custom do_remote functions work on values,\n  # rather on types, hence the custom behaviour.\n  defp do_remote(:erlang, name, [left, right], expected, expr, stack, context, of_fun)\n       when name in [:==, :\"/=\", :\"=:=\", :\"=/=\"] do\n    left_literal? = Macro.quoted_literal?(left)\n    right_literal? = Macro.quoted_literal?(right)\n\n    case {left_literal?, right_literal?} do\n      {true, false} -> custom_compare(name, right, left, expected, expr, stack, context, of_fun)\n      {false, true} -> custom_compare(name, left, right, expected, expr, stack, context, of_fun)\n      {literal?, _} -> compare(name, left, right, literal?, expr, stack, context, of_fun)\n    end\n  end\n\n  defp do_remote(:erlang, name, [left, right], expected, expr, stack, context, of_fun)\n       when name in [:>=, :\"=<\", :>, :<, :min, :max] do\n    case sized_order(name, left, right, expected) do\n      {arg, expected, precise?, return} ->\n        {actual, context} = of_fun.(arg, expected, expr, stack, context)\n        result = if precise? and subtype?(actual, expected), do: return, else: boolean()\n        {result, context}\n\n      :none ->\n        {left_type, context} = of_fun.(left, term(), expr, stack, context)\n        {right_type, context} = of_fun.(right, term(), expr, stack, context)\n\n        result =\n          if name in [:min, :max] do\n            union(left_type, right_type)\n          else\n            return(boolean(), [left_type, right_type], stack)\n          end\n\n        if is_warning(stack) do\n          common = intersection(left_type, right_type)\n\n          cond do\n            # This check is incomplete. After all, we could have the number type nested\n            # inside a tuple or a list and the comparison would still be valid.\n            # However, nested comparison between distinct numbers is very uncommon,\n            # so we only check the direct value here.\n            empty?(common) and not (number_type?(left_type) and number_type?(right_type)) ->\n              error = {:mismatched_comparison, left_type, right_type}\n              remote_error(error, :erlang, name, 2, expr, stack, context)\n\n            match?({false, _}, map_fetch_key(dynamic(common), :__struct__)) ->\n              error = {:struct_comparison, left_type, right_type}\n              remote_error(error, :erlang, name, 2, expr, stack, context)\n\n            true ->\n              {result, context}\n          end\n        else\n          {result, context}\n        end\n    end\n  end\n\n  defp do_remote(:erlang, :element, [index, tuple], expected, expr, stack, context, of_fun)\n       when is_integer(index) do\n    tuple_type = open_tuple(List.duplicate(term(), max(index - 1, 0)) ++ [expected])\n    {tuple_type, context} = of_fun.(tuple, tuple_type, expr, stack, context)\n\n    case tuple_fetch(tuple_type, index - 1) do\n      {_optional?, value_type} ->\n        {return(value_type, [tuple_type], stack), context}\n\n      :badtuple ->\n        remote_error(:erlang, :element, [integer(), tuple_type], expr, stack, context)\n\n      :badindex ->\n        remote_error({:badindex, index, tuple_type}, :erlang, :element, 2, expr, stack, context)\n    end\n  end\n\n  defp do_remote(:erlang, :make_tuple, [size, elem], _, expr, stack, context, of_fun)\n       when is_integer(size) and size >= 0 do\n    {elem_type, context} = of_fun.(elem, term(), expr, stack, context)\n    {return(tuple(List.duplicate(elem_type, size)), [elem_type], stack), context}\n  end\n\n  defp do_remote(:erlang, :insert_element, [index, tuple, elem], _, expr, stack, context, of_fun)\n       when is_integer(index) do\n    tuple_type = open_tuple(List.duplicate(term(), max(index - 1, 0)))\n\n    {tuple_type, context} = of_fun.(tuple, tuple_type, expr, stack, context)\n    {elem_type, context} = of_fun.(elem, term(), expr, stack, context)\n\n    case tuple_insert_at(tuple_type, index - 1, elem_type) do\n      value_type when is_descr(value_type) ->\n        {return(value_type, [tuple_type, elem_type], stack), context}\n\n      :badtuple ->\n        args_types = [integer(), tuple_type, elem_type]\n        remote_error(:erlang, :insert_element, args_types, expr, stack, context)\n\n      :badindex ->\n        error = {:badindex, index - 1, tuple_type}\n        remote_error(error, :erlang, :insert_element, 3, expr, stack, context)\n    end\n  end\n\n  defp do_remote(:erlang, :delete_element, [index, tuple], _, expr, stack, context, of_fun)\n       when is_integer(index) do\n    tuple_type = open_tuple(List.duplicate(term(), max(index, 1)))\n    {tuple_type, context} = of_fun.(tuple, tuple_type, expr, stack, context)\n\n    case tuple_delete_at(tuple_type, index - 1) do\n      value_type when is_descr(value_type) ->\n        {return(value_type, [tuple_type], stack), context}\n\n      :badtuple ->\n        remote_error(:erlang, :delete_element, [integer(), tuple_type], expr, stack, context)\n\n      :badindex ->\n        error = {:badindex, index, tuple_type}\n        remote_error(error, :erlang, :delete_element, 2, expr, stack, context)\n    end\n  end\n\n  defp do_remote(:lists, :member, [arg, list] = args, expected, expr, stack, context, of_fun)\n       when is_list(list) and list != [] do\n    case booleaness(expected) do\n      {polarity, _maybe_or_always} ->\n        {return, acc} =\n          case polarity do\n            true -> {@atom_true, none()}\n            false -> {@atom_false, term()}\n          end\n\n        {expected, singleton?, context} =\n          Enum.reduce(list, {acc, true, context}, fn literal, {acc, all_singleton?, context} ->\n            {type, context} = of_fun.(literal, term(), expr, stack, context)\n\n            if singleton?(type) do\n              acc = if polarity, do: union(acc, type), else: intersection(acc, negation(type))\n              {acc, all_singleton?, context}\n            else\n              acc = if polarity, do: union(acc, type), else: acc\n              {acc, false, context}\n            end\n          end)\n\n        {arg_type, context} = of_fun.(arg, expected, expr, stack, context)\n\n        cond do\n          # Return a precise result\n          singleton? and subtype?(arg_type, expected) ->\n            {return(return, [arg_type, expected], stack), context}\n\n          # Singleton types with reverse polarity are negated, so we don't check for disjoint\n          (singleton? and not polarity) or not is_warning(stack) ->\n            {return(boolean(), [arg_type, expected], stack), context}\n\n          # Nothing in common between left and right, emit a warning\n          disjoint?(arg_type, expected) ->\n            error = {:mismatched_comparison, arg_type, list(expected)}\n            remote_error(error, :lists, :member, 2, expr, stack, context)\n\n          true ->\n            {return(boolean(), [arg_type, expected], stack), context}\n        end\n\n      _ ->\n        remote_domain(:lists, :member, args, expected, elem(expr, 1), stack, context)\n    end\n  end\n\n  defp do_remote(mod, fun, args, expected, expr, stack, context, _of_fun) do\n    remote_domain(mod, fun, args, expected, elem(expr, 1), stack, context)\n  end\n\n  @empty_list empty_list()\n  @non_empty_list non_empty_list(term())\n  @list union(empty_list(), non_empty_list(term()))\n  @empty_map empty_map()\n  @non_empty_map difference(open_map(), empty_map())\n\n  # Limit the size of tuples to 16 entries\n  # as otherwise we may create large nodes\n  defguardp is_data_size(fun, literal)\n            when (fun in [:length, :map_size] and is_integer(literal) and literal >= 0) or\n                   (fun in [:tuple_size] and literal in 0..15)\n\n  defp custom_compare(\n         name,\n         {{:., _, [:erlang, fun]}, _, [arg]} = left,\n         literal,\n         expected,\n         expr,\n         stack,\n         context,\n         of_fun\n       )\n       when is_data_size(fun, literal) do\n    case booleaness(expected) do\n      booleaness when booleaness in [:maybe_both, :none] ->\n        compare(name, left, literal, false, expr, stack, context, of_fun)\n\n      {boolean, _maybe_or_always} ->\n        {polarity, return} =\n          case boolean do\n            true -> {name in [:==, :\"=:=\"], @atom_true}\n            false -> {name in [:\"/=\", :\"=/=\"], @atom_false}\n          end\n\n        {expected, precise?} =\n          case fun do\n            :length when :erlang.xor(polarity, literal > 0) ->\n              {@empty_list, literal == 0}\n\n            :length ->\n              {@non_empty_list, literal == 0}\n\n            :map_size when :erlang.xor(polarity, literal > 0) ->\n              {@empty_map, literal == 0}\n\n            :map_size ->\n              {@non_empty_map, literal == 0}\n\n            :tuple_size when polarity ->\n              {tuple(List.duplicate(term(), literal)), true}\n\n            :tuple_size ->\n              {difference(open_tuple([]), tuple(List.duplicate(term(), literal))), true}\n          end\n\n        {actual, context} = of_fun.(arg, expected, expr, stack, context)\n        result = if precise? and subtype?(actual, expected), do: return, else: boolean()\n\n        # We can skip return compare because literal is always an integer,\n        # so it cannot be a disjoint comparison\n        {result, context}\n    end\n  end\n\n  defp custom_compare(name, arg, literal, expected, expr, stack, context, of_fun) do\n    case booleaness(expected) do\n      booleaness when booleaness in [:maybe_both, :none] ->\n        compare(name, arg, literal, false, expr, stack, context, of_fun)\n\n      {boolean, _maybe_or_always} ->\n        {type, context} = of_fun.(literal, term(), expr, stack, context)\n\n        {polarity, return} =\n          case boolean do\n            true -> {name in [:==, :\"=:=\"], @atom_true}\n            false -> {name in [:\"/=\", :\"=/=\"], @atom_false}\n          end\n\n        # This logic mirrors the code in `Pattern.of_pattern_tree`\n        # If it is a singleton, we can always be precise\n        if singleton?(type) do\n          expected = if polarity, do: type, else: negation(type)\n          {arg_type, context} = of_fun.(arg, expected, expr, stack, context)\n          result = if subtype?(arg_type, expected), do: return, else: boolean()\n\n          # Because reverse polarity means we will infer negated types\n          # (which are naturally disjoint), we skip checks in such cases\n          skip_check? = not polarity\n          return_compare(name, arg_type, type, result, skip_check?, expr, stack, context)\n        else\n          expected =\n            cond do\n              # We are checking for `not x == 1` or similar, we can't say anything about x\n              polarity == false -> term()\n              # We are checking for `x == 1`, make sure x is integer or float\n              name in [:==, :\"/=\"] -> numberize(type)\n              # Otherwise we have the literal type as is\n              true -> type\n            end\n\n          {arg_type, context} = of_fun.(arg, expected, expr, stack, context)\n          return_compare(name, arg_type, type, boolean(), false, expr, stack, context)\n        end\n    end\n  end\n\n  defp compare(name, left, right, both_literal?, expr, stack, context, of_fun) do\n    {left_type, context} = of_fun.(left, term(), expr, stack, context)\n    {right_type, context} = of_fun.(right, term(), expr, stack, context)\n    return_compare(name, left_type, right_type, boolean(), both_literal?, expr, stack, context)\n  end\n\n  @doc \"\"\"\n  Computes the return type of the comparison application.\n  \"\"\"\n  def return_compare(name, left_type, right_type, result, skip_check?, expr, stack, context) do\n    result = return(result, [left_type, right_type], stack)\n\n    cond do\n      skip_check? or not is_warning(stack) ->\n        {result, context}\n\n      name in [:==, :\"/=\"] and number_type?(left_type) and number_type?(right_type) ->\n        {result, context}\n\n      # This check is incomplete. After all, we could have the number type nested\n      # inside a tuple or a list and the comparison would still be valid.\n      # However, nested comparison between distinct numbers is very uncommon,\n      # so we only check the direct value here.\n      disjoint?(left_type, right_type) ->\n        error = {:mismatched_comparison, left_type, right_type}\n        remote_error(error, :erlang, name, 2, expr, stack, context)\n\n      true ->\n        {result, context}\n    end\n  end\n\n  defp sized_order(name, left, right, expected) do\n    if name in [:>=, :\"=<\", :>, :<] do\n      case {left, right} do\n        {{{:., _, [:erlang, fun]}, _, [arg]}, size} when is_data_size(fun, size) ->\n          case booleaness(expected) do\n            {true, _} -> sized_order(name, fun, size, arg, @atom_true)\n            {false, _} -> sized_order(invert_order(name), fun, size, arg, @atom_false)\n            _ -> :none\n          end\n\n        {size, {{:., _, [:erlang, fun]}, _, [arg]}} when is_data_size(fun, size) ->\n          case booleaness(expected) do\n            {true, _} -> sized_order(invert_order(name), fun, size, arg, @atom_true)\n            {false, _} -> sized_order(name, fun, size, arg, @atom_false)\n            _ -> :none\n          end\n\n        _ ->\n          :none\n      end\n    else\n      :none\n    end\n  end\n\n  defp sized_order(name, fun, size, arg, return) do\n    case expected_order(fun, name, size) do\n      :none -> :none\n      {expected, precise?} -> {arg, expected, precise?, return}\n    end\n  end\n\n  defp expected_order(_, :<, 0), do: :none\n\n  defp expected_order(:tuple_size, :<, size),\n    do: {difference(open_tuple([]), open_tuple(List.duplicate(term(), size))), true}\n\n  defp expected_order(:tuple_size, :\"=<\", 0),\n    do: {tuple([]), true}\n\n  defp expected_order(:tuple_size, :\"=<\", size),\n    do: {difference(open_tuple([]), open_tuple(List.duplicate(term(), size + 1))), true}\n\n  defp expected_order(:tuple_size, :>, size),\n    do: {open_tuple(List.duplicate(term(), size + 1)), true}\n\n  defp expected_order(:tuple_size, :>=, size),\n    do: {open_tuple(List.duplicate(term(), size)), true}\n\n  defp expected_order(:map_size, :<, 1), do: {@empty_map, true}\n  defp expected_order(:map_size, :\"=<\", 0), do: {@empty_map, true}\n  defp expected_order(:map_size, :>, size), do: {@non_empty_map, size == 0}\n  defp expected_order(:map_size, :>=, 0), do: {open_map(), true}\n  defp expected_order(:map_size, :>=, _), do: {@non_empty_map, false}\n\n  defp expected_order(:length, :<, 1), do: {@empty_list, true}\n  defp expected_order(:length, :\"=<\", 0), do: {@empty_list, true}\n  defp expected_order(:length, :>, size), do: {@non_empty_list, size == 0}\n  defp expected_order(:length, :>=, 0), do: {@list, true}\n  defp expected_order(:length, :>=, _), do: {@non_empty_list, false}\n\n  defp expected_order(_, _, _), do: :none\n\n  defp invert_order(:>=), do: :<\n  defp invert_order(:\"=<\"), do: :>\n  defp invert_order(:>), do: :\"=<\"\n  defp invert_order(:<), do: :>=\n\n  @doc \"\"\"\n  Returns the domain of an unknown module.\n\n  Used only by info functions.\n  \"\"\"\n  def remote_domain(fun, args, expected, _stack) do\n    arity = length(args)\n    info = signature(fun, arity)\n    {info, filter_domain(info, expected, arity)}\n  end\n\n  @doc \"\"\"\n  Returns the domain of a remote function with info to apply it.\n\n  Note this does not consider rewrites done by the compiler, `remote/8` does.\n  \"\"\"\n  def remote_domain(:erlang, :is_function, [_, arity], expected, _meta, _stack, context)\n      when is_integer(arity) and arity >= 0 do\n    type = fun(arity)\n\n    info =\n      {:strong, [term(), integer()],\n       [\n         {[type, integer()], atom([true])},\n         {[negation(type), integer()], atom([false])}\n       ]}\n\n    {info, filter_domain(info, expected, 2), context}\n  end\n\n  def remote_domain(:erlang, :is_map_key, [key, _map], expected, _meta, _stack, context)\n      when is_atom(key) do\n    info =\n      {:strong, [term(), open_map()],\n       [\n         {[term(), open_map([{key, term()}])], atom([true])},\n         {[term(), open_map([{key, not_set()}])], atom([false])}\n       ]}\n\n    {info, filter_domain(info, expected, 2), context}\n  end\n\n  def remote_domain(:erlang, :map_get, [key, _], expected, _meta, _stack, context)\n      when is_atom(key) do\n    domain = [term(), open_map([{key, expected}])]\n    {{:strong, nil, [{domain, term()}]}, domain, context}\n  end\n\n  def remote_domain(:maps, :get, [key, _], expected, _meta, _stack, context) when is_atom(key) do\n    domain = [term(), open_map([{key, expected}])]\n    {{:strong, nil, [{domain, term()}]}, domain, context}\n  end\n\n  def remote_domain(:maps, :update, [key, _, _], _expected, _meta, _stack, context)\n      when is_atom(key) do\n    domain = [term(), term(), open_map([{key, term()}])]\n    {{:strong, nil, [{domain, open_map()}]}, domain, context}\n  end\n\n  def remote_domain(Map, :pop!, [_, key], _expected, _meta, _stack, context) when is_atom(key) do\n    domain = [open_map([{key, term()}]), term()]\n    {{:strong, nil, [{domain, tuple([term(), open_map()])}]}, domain, context}\n  end\n\n  def remote_domain(Map, :update!, [_, key, _], _expected, _meta, _stack, context)\n      when is_atom(key) do\n    domain = [open_map([{key, term()}]), term(), fun(1)]\n    {{:strong, nil, [{domain, open_map()}]}, domain, context}\n  end\n\n  def remote_domain(mod, fun, args, expected, meta, stack, context) do\n    arity = length(args)\n    {info, context} = signature(mod, fun, arity, meta, stack, context)\n    {info, filter_domain(info, expected, arity), context}\n  end\n\n  defp remote_error(mod, fun, args, expr, stack, context) do\n    remote_error(badremote(mod, fun, args), mod, fun, length(args), expr, stack, context)\n  end\n\n  defp remote_error(error, mod, fun, arity, expr, stack, context) do\n    mfac = mfac(expr, mod, fun, arity)\n    error = {error, mfac, expr, context}\n    {error_type(), error(error, elem(expr, 1), stack, context)}\n  end\n\n  @doc \"\"\"\n  Applies a previously collected domain from `remote_domain/7`.\n  \"\"\"\n  def remote_apply(info, mod, fun, args_types, expr, stack, context) do\n    case remote_apply(mod, fun, info, args_types, stack) do\n      {:ok, type} ->\n        {type, context}\n\n      {:error, error} ->\n        remote_error(error, mod, fun, length(args_types), expr, stack, context)\n    end\n  end\n\n  defp remote_apply(:erlang, :hd, _info, [list], stack) do\n    case list_hd(list) do\n      {:ok, value_type} -> {:ok, return(value_type, [list], stack)}\n      :badnonemptylist -> {:error, badremote(:erlang, :hd, [list])}\n    end\n  end\n\n  defp remote_apply(:erlang, :map_get, _info, [key, map] = args_types, stack) do\n    case map_get(map, key) do\n      {:ok, value} -> {:ok, return(value, args_types, stack)}\n      :badmap -> {:error, badremote(:erlang, :map_get, args_types)}\n      :error -> {:error, {:badkeydomain, map, key, \"raise\"}}\n    end\n  end\n\n  defp remote_apply(:erlang, :tl, _info, [list], stack) do\n    case list_tl(list) do\n      {:ok, value_type} -> {:ok, return(value_type, [list], stack)}\n      :badnonemptylist -> {:error, badremote(:erlang, :tl, [list])}\n    end\n  end\n\n  @struct_key atom([:__struct__])\n  @nil_atom atom([nil])\n\n  defp remote_apply(Map, :from_struct, _info, [map] = args_types, stack) do\n    case map_update(map, @struct_key, not_set(), false, true) do\n      {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}\n      :badmap -> {:error, badremote(Map, :from_struct, args_types)}\n      {:error, _errors} -> {:ok, map}\n    end\n  end\n\n  defp remote_apply(Map, :get, _info, [map, key] = args_types, stack) do\n    case map_get(map, key) do\n      {:ok, value} -> {:ok, return(union(value, @nil_atom), args_types, stack)}\n      :badmap -> {:error, badremote(Map, :get, args_types)}\n      :error -> {:error, {:badkeydomain, map, key, @nil_atom}}\n    end\n  end\n\n  defp remote_apply(Map, :get, _info, [map, key, default] = args_types, stack) do\n    case map_get(map, key) do\n      {:ok, value} -> {:ok, return(union(value, default), args_types, stack)}\n      :badmap -> {:error, badremote(Map, :get, args_types)}\n      :error -> {:error, {:badkeydomain, map, key, default}}\n    end\n  end\n\n  defp remote_apply(Map, :get_lazy, _info, [map, key, fun] = args_types, stack) do\n    case fun_apply(fun, []) do\n      {:ok, default} ->\n        case map_get(map, key) do\n          {:ok, value} -> {:ok, return(union(value, default), args_types, stack)}\n          :badmap -> {:error, badremote(Map, :get_lazy, args_types)}\n          :error -> {:error, {:badkeydomain, map, key, default}}\n        end\n\n      reason ->\n        {:error, {:badapply, fun, [], reason}}\n    end\n  end\n\n  defp remote_apply(Map, :put_new, _info, [map, key, value] = args_types, stack) do\n    map_put_new(map, key, value, :put_new, args_types, stack)\n  end\n\n  defp remote_apply(Map, :put_new_lazy, _info, [map, key, fun] = args_types, stack) do\n    case fun_apply(fun, []) do\n      {:ok, value} -> map_put_new(map, key, value, :put_new_lazy, args_types, stack)\n      reason -> {:error, {:badapply, fun, [], reason}}\n    end\n  end\n\n  defp remote_apply(Map, :pop, _info, args_types, stack) do\n    [map, key, default] =\n      case args_types do\n        [map, key] -> [map, key, @nil_atom]\n        _ -> args_types\n      end\n\n    case map_update(map, key, not_set(), true, false) do\n      {value, descr, _errors} ->\n        value = union(value, default)\n        {:ok, return(tuple([value, descr]), args_types, stack)}\n\n      :badmap ->\n        {:error, badremote(Map, :pop, args_types)}\n\n      {:error, _errors} ->\n        {:error, {:badkeydomain, map, key, tuple([default, map])}}\n    end\n  end\n\n  defp remote_apply(Map, :pop_lazy, _info, [map, key, fun] = args_types, stack) do\n    case fun_apply(fun, []) do\n      {:ok, default} ->\n        case map_update(map, key, not_set(), true, false) do\n          {value, descr, _errors} ->\n            value = union(value, default)\n            {:ok, return(tuple([value, descr]), args_types, stack)}\n\n          :badmap ->\n            {:error, badremote(Map, :pop_lazy, args_types)}\n\n          {:error, _errors} ->\n            {:error, {:badkeydomain, map, key, tuple([default, map])}}\n        end\n\n      reason ->\n        {:error, {:badapply, fun, [], reason}}\n    end\n  end\n\n  defp remote_apply(Map, :pop!, _info, [map, key] = args_types, stack) do\n    case map_update(map, key, not_set(), true, false) do\n      {value, descr, _errors} -> {:ok, return(tuple([value, descr]), args_types, stack)}\n      :badmap -> {:error, badremote(Map, :pop!, args_types)}\n      {:error, _errors} -> {:error, {:badkeydomain, map, key, \"raise\"}}\n    end\n  end\n\n  defp remote_apply(Map, :replace, _info, [map, key, value] = args_types, stack) do\n    fun = fn optional?, _type -> if optional?, do: if_set(value), else: value end\n\n    case map_update_fun(map, key, fun, false, false) do\n      {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}\n      :badmap -> {:error, badremote(Map, :replace, args_types)}\n      {:error, _errors} -> {:error, {:badkeydomain, map, key, \"do nothing\"}}\n    end\n  end\n\n  defp remote_apply(Map, :replace_lazy, _info, args_types, stack) do\n    map_update_or_replace_lazy(:replace_lazy, args_types, stack, \"do nothing\")\n  end\n\n  defp remote_apply(Map, :update, _info, [map, key, default, fun] = args_types, stack) do\n    try do\n      {map, default} =\n        case default do\n          %{dynamic: default} -> {dynamic(map), default}\n          _ -> {map, default}\n        end\n\n      map =\n        case fun do\n          %{dynamic: _} -> dynamic(map)\n          _ -> map\n        end\n\n      fun_apply = fn optional?, arg_type ->\n        if empty?(arg_type) do\n          default\n        else\n          case fun_apply(fun, [arg_type]) do\n            {:ok, res} -> if optional?, do: union(res, default), else: res\n            reason -> throw({:badapply, reason, [arg_type]})\n          end\n        end\n      end\n\n      map_update_fun(map, key, fun_apply, false, true)\n    catch\n      {:badapply, reason, args_types} ->\n        {:error, {:badapply, fun, args_types, reason}}\n    else\n      {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}\n      :badmap -> {:error, badremote(Map, :update, args_types)}\n      {:error, _errors} -> {:ok, map}\n    end\n  end\n\n  defp remote_apply(Map, :update!, _info, args_types, stack) do\n    map_update_or_replace_lazy(:update!, args_types, stack, \"raise\")\n  end\n\n  defp remote_apply(:maps, :find, _info, [key, map] = args_types, stack) do\n    case map_get(map, key) do\n      {_, value} ->\n        result = tuple([atom([:ok]), value]) |> union(atom([:error]))\n        {:ok, return(result, args_types, stack)}\n\n      :badmap ->\n        {:error, badremote(:maps, :find, args_types)}\n\n      :error ->\n        {:error, {:badkeydomain, map, key, atom([:error])}}\n    end\n  end\n\n  defp remote_apply(:maps, :from_keys, _info, [list, value_type] = args_types, stack) do\n    case list_of(list) do\n      {true, nil} ->\n        {:ok, return(empty_map(), args_types, stack)}\n\n      {empty_list?, key_type} ->\n        if key_type == dynamic() or key_type == term() do\n          {:ok, return(open_map(), args_types, stack)}\n        else\n          value_type = if_set(value_type)\n          domain_keys = to_domain_keys(key_type)\n\n          keys =\n            case atom_fetch(key_type) do\n              {:finite, atom_keys} -> [List.delete(domain_keys, :atom) | atom_keys]\n              _ -> [domain_keys]\n            end\n\n          map = closed_map(Enum.map(keys, &{&1, value_type}))\n\n          map_and_maybe_empty_map =\n            case empty_list? do\n              true -> map\n              false -> difference(map, empty_map())\n            end\n\n          {:ok, return(map_and_maybe_empty_map, args_types, stack)}\n        end\n\n      :badproperlist ->\n        {:error, badremote(:maps, :from_keys, args_types)}\n    end\n  end\n\n  defp remote_apply(:maps, :get, _info, [key, map] = args_types, stack) do\n    case map_get(map, key) do\n      {:ok, value} -> {:ok, return(value, args_types, stack)}\n      :badmap -> {:error, badremote(:maps, :get, args_types)}\n      :error -> {:error, {:badkeydomain, map, key, \"raise\"}}\n    end\n  end\n\n  defp remote_apply(:maps, :keys, _info, [map], stack) do\n    case map_to_list(map, fn key, _value -> key end) do\n      {:ok, list_type} -> {:ok, return(list_type, [map], stack)}\n      :badmap -> {:error, badremote(:maps, :keys, [map])}\n    end\n  end\n\n  defp remote_apply(:maps, :put, _info, [key, value, map] = args_types, stack) do\n    case map_update(map, key, value, false, true) do\n      {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}\n      :badmap -> {:error, badremote(:maps, :put, args_types)}\n      {:error, _errors} -> {:ok, map}\n    end\n  end\n\n  defp remote_apply(:maps, :remove, _info, [key, map] = args_types, stack) do\n    case map_update(map, key, not_set(), false, true) do\n      {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}\n      :badmap -> {:error, badremote(:maps, :remove, args_types)}\n      {:error, _errors} -> {:ok, map}\n    end\n  end\n\n  defp remote_apply(:maps, :take, _info, [key, map] = args_types, stack) do\n    case map_update(map, key, not_set(), true, false) do\n      {value, descr, _errors} ->\n        result = union(tuple([value, descr]), atom([:error]))\n        {:ok, return(result, args_types, stack)}\n\n      :badmap ->\n        {:error, badremote(:maps, :take, args_types)}\n\n      {:error, _errors} ->\n        {:error, {:badkeydomain, map, key, atom([:error])}}\n    end\n  end\n\n  defp remote_apply(:maps, :to_list, _info, [map], stack) do\n    case map_to_list(map) do\n      {:ok, list_type} -> {:ok, return(list_type, [map], stack)}\n      :badmap -> {:error, badremote(:maps, :to_list, [map])}\n    end\n  end\n\n  defp remote_apply(:maps, :update, _info, [key, value, map] = args_types, stack) do\n    fun = fn optional?, _type -> if optional?, do: if_set(value), else: value end\n\n    case map_update_fun(map, key, fun, false, false) do\n      {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}\n      :badmap -> {:error, badremote(:maps, :update, args_types)}\n      {:error, _errors} -> {:error, {:badkeydomain, map, key, \"raise\"}}\n    end\n  end\n\n  defp remote_apply(:maps, :values, _info, [map], stack) do\n    case map_to_list(map, fn _key, value -> value end) do\n      {:ok, list_type} -> {:ok, return(list_type, [map], stack)}\n      :badmap -> {:error, badremote(:maps, :keys, [map])}\n    end\n  end\n\n  defp remote_apply(_mod, _fun, info, args_types, stack) do\n    remote_apply(info, args_types, stack)\n  end\n\n  defp remote_apply(:none, _args_types, _stack) do\n    {:ok, dynamic()}\n  end\n\n  defp remote_apply({:infer, _domain, clauses} = sig, args_types, _stack) do\n    case apply_infer(clauses, args_types) do\n      {_used, type} -> {:ok, type}\n      :error -> {:error, {:badremote, sig, args_types}}\n    end\n  end\n\n  defp remote_apply({:strong, domain, clauses} = sig, args_types, stack) do\n    case apply_strong(domain, clauses, args_types, stack) do\n      {_used, type} -> {:ok, type}\n      :error -> {:error, {:badremote, sig, args_types}}\n    end\n  end\n\n  defp badremote(mod, fun, args) do\n    {:badremote, signature(mod, fun, length(args)), args}\n  end\n\n  @doc \"\"\"\n  Returns the type of a remote capture.\n  \"\"\"\n  def remote_capture(modules, fun, arity, meta, stack, context) do\n    case modules do\n      [] ->\n        {dynamic(fun(arity)), context}\n\n      [_ | _] ->\n        {type, fallback?, context} =\n          Enum.reduce(modules, {none(), false, context}, fn module, {type, fallback?, context} ->\n            case signature(module, fun, arity, meta, stack, context) do\n              {{:strong, _, clauses}, context} ->\n                {union(type, fun_from_non_overlapping_clauses(clauses)), fallback?, context}\n\n              {{:infer, _, clauses}, context} when length(clauses) <= @max_clauses ->\n                {union(type, fun_from_inferred_clauses(clauses)), fallback?, context}\n\n              {_, context} ->\n                {type, true, context}\n            end\n          end)\n\n        if fallback? do\n          {dynamic(fun(arity)), context}\n        else\n          {type, context}\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Gets a mfa signature.\n\n  It returns either a tuple with the remote information and the context.\n  The remote information may be one of:\n\n    * `:none` - no typing information found.\n\n    * `{:infer, domain or nil, clauses}` - clauses from inferences.\n      You must check all clauses and return the union between them.\n      They are dynamic and they can only be converted into arrows by\n      computing the union of all arguments.\n\n    * `{:strong, domain or nil, clauses}` - clauses from signatures. So far\n      these are strong arrows with non-overlapping domains\n\n  \"\"\"\n  def signature(module, fun, arity, meta, stack, context) when is_atom(module) do\n    if Keyword.get(meta, :runtime_module, false) do\n      {:none, context}\n    else\n      case signature(module, fun, arity) do\n        :none -> export(module, fun, arity, meta, stack, context)\n        clauses -> {clauses, context}\n      end\n    end\n  end\n\n  defp export(_module, :module_info, arity, _meta, _stack, context) when arity in [0, 1] do\n    {signature(:module_info, arity), context}\n  end\n\n  defp export(module, fun, arity, meta, %{cache: cache} = stack, context) do\n    cond do\n      cache == nil ->\n        {:none, context}\n\n      stack.mode == :infer ->\n        case ParallelChecker.fetch_export(stack.cache, module, fun, arity, false) do\n          {:ok, mode, _, info} when info == :none or mode == :protocol ->\n            {signature(fun, arity), context}\n\n          {:ok, _mode, _, info} ->\n            {info, context}\n\n          _ ->\n            {:none, context}\n        end\n\n      true ->\n        case ParallelChecker.fetch_export(stack.cache, module, fun, arity, true) do\n          {:ok, mode, reason, info} ->\n            info = if info == :none, do: signature(fun, arity), else: info\n            {info, check_deprecated(mode, module, fun, arity, reason, meta, stack, context)}\n\n          {:badfunction, mode} when mode != :erlang and fun == :__info__ and arity == 1 ->\n            key =\n              cond do\n                not Code.ensure_loaded?(module) -> :__info__\n                module.__info__(:struct) != nil -> {:__info__, true}\n                true -> {:__info__, false}\n              end\n\n            {signature(key, arity), context}\n\n          error ->\n            context =\n              if warn_undefined?(module, fun, arity, stack) do\n                warn(__MODULE__, {:undefined, error, module, fun, arity}, meta, stack, context)\n              else\n                context\n              end\n\n            {:none, context}\n        end\n    end\n  end\n\n  defp check_deprecated(:erlang, module, fun, arity, _reason, meta, stack, context) do\n    case :otp_internal.obsolete(module, fun, arity) do\n      {:deprecated, string} when is_list(string) ->\n        reason = string |> List.to_string() |> :string.titlecase()\n        warn(__MODULE__, {:deprecated, module, fun, arity, reason}, meta, stack, context)\n\n      {:deprecated, string, removal} when is_list(string) and is_list(removal) ->\n        reason = string |> List.to_string() |> :string.titlecase()\n        reason = \"It will be removed in #{removal}. #{reason}\"\n        warn(__MODULE__, {:deprecated, module, fun, arity, reason}, meta, stack, context)\n\n      _ ->\n        context\n    end\n  end\n\n  defp check_deprecated(_elixir_or_protocol, module, fun, arity, reason, meta, stack, context) do\n    if reason do\n      warn(__MODULE__, {:deprecated, module, fun, arity, reason}, meta, stack, context)\n    else\n      context\n    end\n  end\n\n  defp warn_undefined?(_, _, _, %{no_warn_undefined: %Macro.Env{}}) do\n    false\n  end\n\n  defp warn_undefined?(_, _, _, %{no_warn_undefined: :all}) do\n    false\n  end\n\n  defp warn_undefined?(module, fun, arity, stack) do\n    not Enum.any?(stack.no_warn_undefined, &(&1 == module or &1 == {module, fun, arity}))\n  end\n\n  ## Funs\n\n  def fun(fun_type, args_types, call, stack, context) do\n    case fun_apply(fun_type, args_types) do\n      {:ok, res} ->\n        {res, context}\n\n      reason ->\n        error = {{:badapply, fun_type, args_types, reason}, nil, call, context}\n        {error_type(), error(__MODULE__, error, elem(call, 1), stack, context)}\n    end\n  end\n\n  ## Local\n\n  def local(fun, args, expected, {_, meta, _} = expr, stack, context, of_fun) do\n    {local_info, domain, context} = local_domain(fun, args, expected, meta, stack, context)\n\n    {args_types, context} =\n      zip_map_reduce(args, domain, context, &of_fun.(&1, &2, expr, stack, &3))\n\n    local_apply(local_info, fun, args_types, expr, stack, context)\n  end\n\n  defp local_domain(fun, args, expected, meta, stack, context) do\n    arity = length(args)\n\n    case stack.local_handler.(meta, {fun, arity}, stack, context) do\n      false ->\n        {{false, :none}, List.duplicate(term(), arity), context}\n\n      {kind, info, context} ->\n        update_used? = is_warning(stack) and kind == :defp\n\n        if info == :none do\n          {{update_used?, :none}, List.duplicate(term(), arity), context}\n        else\n          {{update_used?, info}, filter_domain(info, expected, arity), context}\n        end\n    end\n  end\n\n  defp local_apply({update_used?, :none}, fun, args_types, _expr, _stack, context) do\n    if update_used? do\n      {dynamic(), put_in(context.local_used[{fun, length(args_types)}], [])}\n    else\n      {dynamic(), context}\n    end\n  end\n\n  defp local_apply({update_used?, info}, fun, args_types, expr, stack, context) do\n    case local_apply(info, args_types, stack) do\n      {indexes, type} ->\n        context =\n          if update_used? do\n            update_in(context.local_used[{fun, length(args_types)}], fn current ->\n              (current || used_from_clauses(info)) -- indexes\n            end)\n          else\n            context\n          end\n\n        {type, context}\n\n      :error ->\n        error = {:badlocal, info, args_types, expr, context}\n        {error_type(), error(error, with_span(elem(expr, 1), fun), stack, context)}\n    end\n  end\n\n  defp local_apply({:infer, _domain, clauses}, args_types, _stack) do\n    apply_infer(clauses, args_types)\n  end\n\n  defp local_apply({:strong, domain, clauses}, args_types, stack) do\n    apply_strong(domain, clauses, args_types, stack)\n  end\n\n  defp used_from_clauses({_strong_or_infer, _domain, clauses}),\n    do: Enum.with_index(clauses, fn _, i -> i end)\n\n  @doc \"\"\"\n  Deal with local captures.\n  \"\"\"\n  def local_capture(fun, arity, meta, stack, context) do\n    fun_arity = {fun, arity}\n\n    case stack.local_handler.(meta, fun_arity, stack, context) do\n      false ->\n        {dynamic(fun(arity)), context}\n\n      {kind, info, context} ->\n        result =\n          case info do\n            {:infer, _, clauses} when length(clauses) <= @max_clauses ->\n              fun_from_inferred_clauses(clauses)\n\n            _ ->\n              dynamic(fun(arity))\n          end\n\n        context =\n          if stack.mode != :infer and kind == :defp do\n            # Mark all clauses as used, as the function is being exported.\n            put_in(context.local_used[fun_arity], [])\n          else\n            context\n          end\n\n        {result, context}\n    end\n  end\n\n  @doc \"\"\"\n  Computes the return type of an application.\n  \"\"\"\n  def return(type, args_types, stack) do\n    # An argument being gradual does not imply the return type\n    # is gradual in static mode. However, we do wrap in dynamic\n    # in :dynamic / :gradual mode to avoid false positives.\n    cond do\n      stack.mode == :static -> type\n      Enum.any?(args_types, &gradual?/1) -> dynamic(type)\n      true -> type\n    end\n  end\n\n  ## Map helpers\n\n  defp map_put_new(map, key, value, name, args_types, stack) do\n    fun = fn\n      true, type -> union(type, value)\n      false, type -> if empty?(type), do: value, else: type\n    end\n\n    case map_update_fun(map, key, fun, false, true) do\n      {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}\n      :badmap -> {:error, badremote(Map, name, args_types)}\n      {:error, _errors} -> {:ok, map}\n    end\n  end\n\n  def map_update_or_replace_lazy(name, [map, key, fun] = args_types, stack, error) do\n    try do\n      map =\n        case fun do\n          %{dynamic: _} -> dynamic(map)\n          _ -> map\n        end\n\n      fun_apply = fn optional?, arg_type ->\n        case fun_apply(fun, [arg_type]) do\n          {:ok, res} -> if optional?, do: if_set(res), else: res\n          reason -> throw({:badapply, reason, [arg_type]})\n        end\n      end\n\n      map_update_fun(map, key, fun_apply, false, false)\n    catch\n      {:badapply, reason, args_types} ->\n        {:error, {:badapply, fun, args_types, reason}}\n    else\n      {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}\n      :badmap -> {:error, badremote(Map, name, args_types)}\n      {:error, _errors} -> {:error, {:badkeydomain, map, key, error}}\n    end\n  end\n\n  ## Application helpers\n\n  defp domain(nil, [{domain, _}]), do: domain\n  defp domain(domain, _clauses), do: domain\n\n  @term_or_dynamic [term(), dynamic()]\n\n  defp filter_domain(:none, _expected, arity) do\n    List.duplicate(term(), arity)\n  end\n\n  defp filter_domain({_, domain, clauses}, expected, _arity) when expected in @term_or_dynamic do\n    domain(domain, clauses)\n  end\n\n  defp filter_domain({_type, domain, clauses}, expected, _arity) do\n    case filter_domain(clauses, expected, [], true) do\n      :none -> domain(domain, clauses)\n      :all -> domain(domain, clauses)\n      args -> Enum.zip_with(args, fn types -> Enum.reduce(types, &union/2) end)\n    end\n  end\n\n  defp filter_domain([{args, return} | clauses], expected, acc, all_compatible?) do\n    case disjoint?(return, expected) do\n      false -> filter_domain(clauses, expected, [args | acc], all_compatible?)\n      true -> filter_domain(clauses, expected, acc, false)\n    end\n  end\n\n  defp filter_domain([], _expected, [], _all_compatible?), do: :none\n  defp filter_domain([], _expected, _acc, true), do: :all\n  defp filter_domain([], _expected, acc, false), do: acc\n\n  defp apply_infer(clauses, args_types) do\n    case apply_clauses(clauses, args_types, 0, 0, [], []) do\n      {0, [], []} ->\n        :error\n\n      {count, used, _returns} when count > @max_clauses ->\n        {used, dynamic()}\n\n      {_count, used, returns} ->\n        {used, returns |> Enum.reduce(&union/2) |> dynamic()}\n    end\n  end\n\n  defp apply_strong(_domain, [{expected, return}], args_types, stack) do\n    # Optimize single clauses as the domain is the single clause args.\n    case zip_compatible?(args_types, expected) do\n      true -> {[0], return(return, args_types, stack)}\n      false -> :error\n    end\n  end\n\n  defp apply_strong(domain, clauses, args_types, stack) do\n    # If the type is only gradual, the compatibility check is the same\n    # as a non disjoint check. So we skip checking compatibility twice.\n    with true <- zip_compatible_or_only_gradual?(args_types, domain),\n         {count, used, returns} when count > 0 <- apply_clauses(clauses, args_types, 0, 0, [], []) do\n      {used, returns |> Enum.reduce(&union/2) |> return(args_types, stack)}\n    else\n      _ -> :error\n    end\n  end\n\n  defp apply_clauses([{expected, return} | clauses], args_types, index, count, used, returns) do\n    if zip_not_disjoint?(args_types, expected) do\n      apply_clauses(clauses, args_types, index + 1, count + 1, [index | used], [return | returns])\n    else\n      apply_clauses(clauses, args_types, index + 1, count, used, returns)\n    end\n  end\n\n  defp apply_clauses([], _args_types, _index, count, used, returns) do\n    {count, used, returns}\n  end\n\n  defp zip_compatible_or_only_gradual?([actual | actuals], [expected | expecteds]) do\n    (only_gradual?(actual) or compatible?(actual, expected)) and\n      zip_compatible_or_only_gradual?(actuals, expecteds)\n  end\n\n  defp zip_compatible_or_only_gradual?([], []), do: true\n\n  defp zip_compatible?([actual | actuals], [expected | expecteds]) do\n    compatible?(actual, expected) and zip_compatible?(actuals, expecteds)\n  end\n\n  defp zip_compatible?([], []), do: true\n\n  defp zip_not_disjoint?([actual | actuals], [expected | expecteds]) do\n    not disjoint?(actual, expected) and zip_not_disjoint?(actuals, expecteds)\n  end\n\n  defp zip_not_disjoint?([], []), do: true\n\n  ## Error handling\n\n  defp error(warning, meta, stack, context) do\n    error(__MODULE__, warning, meta, stack, context)\n  end\n\n  ## Diagnostics\n\n  def format_diagnostic({{:badapply, fun_type, args_types, reason}, mfac, expr, context}) do\n    mfa_or_call =\n      case mfac do\n        {mod, fun, arity, _converter} ->\n          \"function call within #{Exception.format_mfa(mod, fun, arity)}\"\n\n        nil ->\n          \"function call\"\n      end\n\n    {message, to_trace, hints} =\n      case reason do\n        {:badarg, domain} ->\n          message = \"\"\"\n          incompatible types given on #{mfa_or_call}:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          given types:\n\n              #{args_to_quoted_string(args_types, domain, &Function.identity/1) |> indent(4)}\n\n          but function has type:\n\n              #{to_quoted_string(fun_type) |> indent(4)}\n          \"\"\"\n\n          hints =\n            cond do\n              not empty?(args_to_domain(domain)) -> []\n              match?({:or, _, _}, to_quoted(fun_type)) -> [:empty_union_domain]\n              true -> [:empty_domain]\n            end\n\n          # When there is an argument error, we trace the arguments\n          {message, elem(expr, 2), hints}\n\n        {:badarity, arities} ->\n          info =\n            case arities do\n              [arity] -> \"function with arity #{arity}\"\n              _ -> \"function with arities #{Enum.join(arities, \",\")}\"\n            end\n\n          message = \"\"\"\n          expected a #{length(args_types)}-arity function on #{mfa_or_call}:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          but got #{info}:\n\n              #{to_quoted_string(fun_type) |> indent(4)}\n          \"\"\"\n\n          {message, elem(expr, 0), []}\n\n        :badfun ->\n          message = \"\"\"\n          expected a #{length(args_types)}-arity function on #{mfa_or_call}:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          but got type:\n\n              #{to_quoted_string(fun_type) |> indent(4)}\n          \"\"\"\n\n          {message, elem(expr, 0), []}\n      end\n\n    traces = collect_traces(to_trace, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message: IO.iodata_to_binary([message, format_traces(traces), format_hints(hints)])\n    }\n  end\n\n  def format_diagnostic({:badlocal, {_, domain, clauses}, args_types, expr, context}) do\n    domain = domain(domain, clauses)\n    traces = collect_traces(expr, context)\n    converter = &Function.identity/1\n    {fun, meta, _} = expr\n\n    explanation =\n      empty_arg_reason(args_types) ||\n        \"\"\"\n        but expected one of:\n        #{clauses_args_to_quoted_string(clauses, converter, [])}\n        \"\"\"\n\n    banner =\n      case fun == :super && meta[:default] && meta[:super] do\n        {_kind, fun} ->\n          \"\"\"\n          incompatible types given as default arguments to #{fun}/#{length(args_types)}:\n          \"\"\"\n\n        _ ->\n          \"\"\"\n          incompatible types given to #{fun}/#{length(args_types)}:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          given types:\n          \"\"\"\n      end\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          banner,\n          \"\"\"\n\n              #{args_to_quoted_string(args_types, domain, converter) |> indent(4)}\n\n          \"\"\",\n          explanation,\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({{:badindex, index, type}, mfac, expr, context}) do\n    traces = collect_traces(expr, context)\n    {mod, fun, arity, _converter} = mfac\n    mfa = Exception.format_mfa(mod, fun, arity)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected a tuple with at least #{pluralize(index, \"element\", \"elements\")} in #{mfa}:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          the given type does not have the given index:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({{:badkeydomain, map, key, error}, mfac, expr, context}) do\n    {mod, fun, arity, _converter} = mfac\n    mfa = Exception.format_mfa(mod, fun, arity)\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          incompatible types given to #{mfa}:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          the map:\n\n              #{to_quoted_string(map) |> indent(4)}\n\n          does not have all required keys:\n\n              #{to_quoted_string(key) |> indent(4)}\n\n          therefore this function will always #{if is_binary(error) do\n            error\n          else\n            \"return #{to_quoted_string(error)}\"\n          end}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({{:badremote, {_, domain, clauses}, args_types}, mfac, expr, context}) do\n    domain = domain(domain, clauses)\n    {mod, fun, arity, converter} = mfac\n    meta = elem(expr, 1)\n\n    {banner, traces} =\n      case Keyword.get(meta, :type_check) do\n        :interpolation ->\n          {_, _, [arg]} = expr\n\n          {\"\"\"\n           incompatible value given to string interpolation:\n\n               #{expr_to_string(arg) |> indent(4)}\n\n           it has type:\n           \"\"\", collect_traces(expr, context)}\n\n        :generator ->\n          {:<-, _, [_, arg]} = expr\n\n          {\"\"\"\n           incompatible value given to for-comprehension:\n\n               #{expr_to_string(expr) |> indent(4)}\n\n           it has type:\n           \"\"\", collect_traces(arg, context)}\n\n        :into ->\n          {\"\"\"\n           incompatible value given to :into option in for-comprehension:\n\n               into: #{expr_to_string(expr) |> indent(4)}\n\n           it has type:\n           \"\"\", collect_traces(expr, context)}\n\n        _ ->\n          mfa_or_fa = if mod, do: Exception.format_mfa(mod, fun, arity), else: \"#{fun}/#{arity}\"\n\n          {\"\"\"\n           incompatible types given to #{mfa_or_fa}:\n\n               #{expr_to_string(expr) |> indent(4)}\n\n           given types:\n           \"\"\", collect_traces(expr, context)}\n      end\n\n    {explanation, impls} =\n      cond do\n        reason = empty_arg_reason(converter.(args_types)) ->\n          {reason, \"\"}\n\n        Code.ensure_loaded?(mod) and\n            Keyword.has_key?(mod.module_info(:attributes), :__protocol__) ->\n          if function_exported?(mod, :__protocol__, 1) and\n               mod.__protocol__(:impls) == {:consolidated, []} do\n            {\"\"\"\n             but the #{inspect(mod)} protocol was not yet implemented \\\n             for any type and therefore will always fail.\n\n             This message will disappear once you define an implementation. \\\n             If the protocol is part of a library, you may define a dummy \\\n             implementation for development/test.\n             \"\"\", \"\"}\n          else\n            fix =\n              case mod do\n                String.Chars ->\n                  \"\"\"\n                  You either passed the wrong value or you must:\n\n                  1. convert the given value to a string explicitly\n                     (use inspect/1 if you want to convert any data structure to a string)\n                  2. implement the String.Chars protocol\n                  \"\"\"\n\n                Enumerable ->\n                  \"\"\"\n                  You either passed the wrong value or you must:\n\n                  1. convert the given value to an Enumerable explicitly\n                  2. implement the Enumerable protocol\n                  \"\"\"\n\n                _ ->\n                  \"\"\"\n                  You either passed the wrong value or you forgot to implement the protocol.\n                  \"\"\"\n              end\n\n            # The protocol has, at the moment, simplified clauses, so we build the complete one\n            clauses =\n              case mod.__protocol__(:impls) do\n                {:consolidated, mods} ->\n                  domain = mods |> Enum.map(&Module.Types.Of.impl/1) |> Enum.reduce(&union/2)\n                  [{[domain], dynamic()}]\n\n                _ ->\n                  clauses\n              end\n\n            {\"\"\"\n             but expected a type that implements the #{inspect(mod)} protocol.\n             #{fix}\\\n             \"\"\",\n             \"\"\"\n\n             #{hint()} the #{inspect(mod)} protocol is implemented for the following types:\n             #{clauses_args_to_quoted_string(clauses, converter, collapse_structs: true)}\n             \"\"\"}\n          end\n\n        true ->\n          {\"\"\"\n           but expected one of:\n           #{clauses_args_to_quoted_string(clauses, converter, [])}\n           \"\"\", \"\"}\n      end\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          banner,\n          \"\"\"\n\n              #{args_to_quoted_string(args_types, domain, converter) |> indent(4)}\n\n          \"\"\",\n          explanation,\n          format_traces(traces),\n          impls\n        ])\n    }\n  end\n\n  def format_diagnostic({{:mismatched_comparison, left, right}, mfac, expr, context}) do\n    {mod, name, _, _} = mfac\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          comparison between distinct types found:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          given types:\n\n              #{type_comparison_to_string(mod, name, left, right) |> indent(4)}\n          \"\"\",\n          format_traces(traces),\n          \"\"\"\n\n          While Elixir can compare across all types, you are comparing \\\n          across types which are always disjoint, and the result is either \\\n          always true or always false\n          \"\"\"\n        ])\n    }\n  end\n\n  def format_diagnostic({{:struct_comparison, left, right}, mfac, expr, context}) do\n    {mod, name, _, _} = mfac\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          comparison with structs found:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          given types:\n\n              #{type_comparison_to_string(mod, name, left, right) |> indent(4)}\n          \"\"\",\n          format_traces(traces),\n          \"\"\"\n\n          Comparison operators (>, <, >=, <=, min, and max) perform structural \\\n          and not semantic comparison. Comparing with a struct won't give meaningful \\\n          results. Structs that can be compared typically define a compare/2 function \\\n          within their modules that can be used for semantic comparison.\n          \"\"\"\n        ])\n    }\n  end\n\n  def format_diagnostic({:undefined, :badmodule, module, fun, arity}) do\n    %{\n      message:\n        IO.iodata_to_binary([\n          Exception.format_mfa(module, fun, arity),\n          \" is undefined (module \",\n          inspect(module),\n          \" is not available or is yet to be defined)\",\n          UndefinedFunctionError.hint_for_missing_module(module, fun, arity)\n        ]),\n      group: true\n    }\n  end\n\n  def format_diagnostic({:undefined, {:badfunction, _}, module, fun, arity}) do\n    _ = Code.ensure_loaded(module)\n\n    %{\n      message:\n        IO.iodata_to_binary([\n          Exception.format_mfa(module, fun, arity),\n          \" is undefined or private\",\n          UndefinedFunctionError.hint_for_loaded_module(module, fun, arity)\n        ]),\n      group: true\n    }\n  end\n\n  def format_diagnostic({:deprecated, module, fun, arity, reason}) do\n    %{\n      message:\n        IO.iodata_to_binary([\n          Exception.format_mfa(module, fun, arity),\n          \" is deprecated. \",\n          reason\n        ]),\n      group: true\n    }\n  end\n\n  defp empty_arg_reason(args_types) do\n    if i = Enum.find_index(args_types, &empty?/1) do\n      \"\"\"\n      the #{integer_to_ordinal(i + 1)} argument is empty (often represented as none()), \\\n      most likely because it is the result of an expression that always fails, such as \\\n      a `raise` or a previous invalid call. This causes any function called with this \\\n      value to fail\n      \"\"\"\n    end\n  end\n\n  defp pluralize(1, singular, _), do: \"1 #{singular}\"\n  defp pluralize(i, _, plural), do: \"#{i} #{plural}\"\n\n  defp mfac({{:., _, [mod, fun]}, _, args}, _mod, _fun, _arity)\n       when is_atom(mod) and is_atom(fun) do\n    {mod, fun, args, converter} = :elixir_rewrite.erl_to_ex(mod, fun, args)\n    {mod, fun, length(args), converter}\n  end\n\n  defp mfac(_, mod, fun, arity)\n       when is_atom(mod) and is_atom(fun) and is_integer(arity) do\n    {mod, fun, arity, & &1}\n  end\n\n  ## Algebra helpers\n\n  alias Inspect.Algebra, as: IA\n\n  defp type_comparison_to_string(:lists, :member, left, right) do\n    type_comparison_to_string(Kernel, :in, left, right)\n  end\n\n  defp type_comparison_to_string(mod, fun, left, right) do\n    {_, fun, _, _} = :elixir_rewrite.erl_to_ex(mod, fun, [left, right])\n\n    {fun, [], [to_quoted(left, collapse_structs: true), to_quoted(right, collapse_structs: true)]}\n    |> Code.Formatter.to_algebra()\n    |> Inspect.Algebra.format(98)\n    |> IO.iodata_to_binary()\n  end\n\n  defp clauses_args_to_quoted_string([{args, _return}], converter, opts) do\n    \"\\n    \" <> (clause_args_to_quoted_string(args, converter, opts) |> indent(4))\n  end\n\n  defp clauses_args_to_quoted_string(clauses, converter, opts) do\n    clauses\n    |> Enum.with_index(fn {args, _return}, index ->\n      \"\"\"\n\n      ##{index + 1}\n      #{clause_args_to_quoted_string(args, converter, opts)}\\\n      \"\"\"\n      |> indent(4)\n    end)\n    |> Enum.join(\"\\n\")\n  end\n\n  defp clause_args_to_quoted_string(args, converter, opts) do\n    docs = Enum.map(args, &(&1 |> to_quoted(opts) |> Code.Formatter.to_algebra()))\n    args_docs_to_quoted_string(converter.(docs))\n  end\n\n  defp args_to_quoted_string(args_types, domain, converter) do\n    docs =\n      Enum.zip_with(args_types, domain, fn actual, expected ->\n        if compatible?(actual, expected) or not has_simple_difference?(actual, expected) do\n          actual |> to_quoted() |> Code.Formatter.to_algebra()\n        else\n          common = intersection(actual, expected)\n\n          uncommon_doc =\n            difference(actual, expected)\n            |> to_quoted()\n            |> Code.Formatter.to_algebra()\n            |> ansi_red()\n\n          if empty?(common) do\n            uncommon_doc\n          else\n            common_doc = common |> to_quoted() |> Code.Formatter.to_algebra()\n            IA.glue(IA.concat(uncommon_doc, \" or\"), IA.nest(common_doc, 2))\n          end\n        end\n      end)\n\n    args_docs_to_quoted_string(converter.(docs))\n  end\n\n  @composite_types non_empty_list(term(), term())\n                   |> union(tuple())\n                   |> union(open_map())\n                   |> union(fun())\n\n  # If actual/expected have a composite type, computing the\n  # `intersection(actual, expected) or difference(actual, expected)`\n  # can lead to an explosion of terms that actually make debugging\n  # harder. So we check that at least one of the two operations\n  # return none() (i.e. actual is a subtype or they are disjoint).\n  defp has_simple_difference?(actual, expected) do\n    composite_types = intersection(actual, @composite_types)\n    subtype?(composite_types, expected) or disjoint?(composite_types, expected)\n  end\n\n  defp ansi_red(doc) do\n    if IO.ANSI.enabled?() do\n      IA.concat(IA.color(doc, IO.ANSI.red()), IA.color(IA.empty(), IO.ANSI.reset()))\n    else\n      IA.concat([\"-\", doc, \"-\"])\n    end\n  end\n\n  defp args_docs_to_quoted_string(docs) do\n    doc = IA.fold(docs, fn doc, acc -> IA.glue(IA.concat(doc, \",\"), acc) end)\n\n    wrapped_docs =\n      case docs do\n        [_] -> IA.concat(\"(\", IA.concat(doc, \")\"))\n        _ -> IA.group(IA.glue(IA.nest(IA.glue(\"(\", \"\", doc), 2), \"\", \")\"))\n      end\n\n    wrapped_docs\n    |> IA.format(98)\n    |> IO.iodata_to_binary()\n    |> case do\n      \"(\\n\" <> _ = multiple_lines -> multiple_lines\n      single_line -> binary_slice(single_line, 1..-2//1)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/types/descr.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Module.Types.Descr do\n  @moduledoc false\n\n  # The descr contains a set-theoretic implementation of types.\n  # Types are represented as maps of non-overlapping unions.\n  # A bitmap is used to represent non-divisible types. All other\n  # types require specific data structures.\n\n  # Vocabulary:\n  #\n  # * DNF - disjunctive normal form which is a pair of unions and negations\n  # * BDD - binary decision diagram which is a set-theoretic representation of types as a tree\n\n  import Bitwise\n\n  @bit_binary 0b1\n  @bit_bitstring_no_binary 0b10\n  @bit_empty_list 0b100\n  @bit_integer 0b1000\n  @bit_float 0b10000\n  @bit_pid 0b100000\n  @bit_port 0b1000000\n  @bit_reference 0b10000000\n  @bit_top 0b11111111\n\n  # We use two bits to represent bitstrings and binaries,\n  # which must be looked at together\n  # bitstring = 0b11\n  # bitstring and not binary = 0b10\n  # binary = 0b01\n  # none = 0b00\n  @bit_bitstring @bit_binary ||| @bit_bitstring_no_binary\n  @bit_number @bit_integer ||| @bit_float\n\n  defmacro bdd_leaf(arg1, arg2), do: {arg1, arg2}\n\n  # Map fields and domains are stored as orddicts (sorted key-value lists).\n  @fields_new []\n  defguardp is_fields_empty(fields) when fields == []\n  defguardp fields_size(fields) when length(fields)\n\n  @domain_key_types :lists.sort(\n                      [:binary, :integer, :float, :pid, :port, :reference] ++\n                        [:fun, :atom, :tuple, :map, :list]\n                    )\n\n  # Remark: those are explicit BDD constructors. The functional constructors are `bdd_new/1` and `bdd_new/3`.\n  @fun_top {:negation, %{}}\n  @atom_top {:negation, :sets.new(version: 2)}\n  @map_top {:open, @fields_new}\n  @non_empty_list_top {:term, :term}\n  @tuple_top {:open, []}\n  @map_empty {:closed, @fields_new}\n\n  # The top BDD for each arity.\n  @fun_bdd_top :bdd_top\n\n  @none %{}\n  @term %{\n    bitmap: @bit_top,\n    atom: @atom_top,\n    tuple: @tuple_top,\n    map: @map_top,\n    list: @non_empty_list_top,\n    fun: @fun_top\n  }\n  @list_top %{bitmap: @bit_empty_list, list: @non_empty_list_top}\n  @empty_list %{bitmap: @bit_empty_list}\n  @not_non_empty_list Map.delete(@term, :list)\n\n  @not_set %{optional: 1}\n  @term_or_optional Map.put(@term, :optional, 1)\n  @term_or_dynamic_optional Map.put(@term, :dynamic, %{optional: 1})\n  @not_atom_or_optional Map.delete(@term_or_optional, :atom)\n\n  @empty_intersection [0, :bdd_bot]\n  @empty_difference [0, :bdd_bot]\n\n  defguard is_descr(descr) when is_map(descr) or descr == :term\n\n  defp descr_key?(:term, _key), do: true\n  defp descr_key?(descr, key), do: is_map_key(descr, key)\n\n  def dynamic(), do: %{dynamic: :term}\n  def none(), do: @none\n  def term(), do: :term\n\n  @compile {:inline, unfold: 1}\n  defp unfold(:term), do: unfolded_term()\n  defp unfold(other), do: other\n  defp unfolded_term, do: @term\n\n  def atom(as), do: %{atom: atom_new(as)}\n  def atom(), do: %{atom: @atom_top}\n  def binary(), do: %{bitmap: @bit_binary}\n  def bitstring(), do: %{bitmap: @bit_bitstring}\n  def bitstring_no_binary(), do: %{bitmap: @bit_bitstring_no_binary}\n  def closed_map(pairs), do: map_descr(:closed, pairs)\n  def empty_list(), do: %{bitmap: @bit_empty_list}\n  def empty_map(), do: %{map: @map_empty}\n  def integer(), do: %{bitmap: @bit_integer}\n  def float(), do: %{bitmap: @bit_float}\n  def list(type), do: list_descr(type, @empty_list, true)\n  def non_empty_list(type, tail \\\\ @empty_list), do: list_descr(type, tail, false)\n  def open_map(), do: %{map: @map_top}\n  def open_map(pairs), do: map_descr(:open, pairs)\n  def open_tuple(elements, _fallback \\\\ term()), do: tuple_descr(:open, elements)\n  def pid(), do: %{bitmap: @bit_pid}\n  def port(), do: %{bitmap: @bit_port}\n  def reference(), do: %{bitmap: @bit_reference}\n  def tuple(), do: %{tuple: @tuple_top}\n  def tuple(elements), do: tuple_descr(:closed, elements)\n\n  @boolset :sets.from_list([true, false], version: 2)\n  def boolean(), do: %{atom: {:union, @boolset}}\n\n  @doc \"\"\"\n  Gets the upper bound of a gradual type.\n\n  This is the same as removing the gradual type.\n  \"\"\"\n  def upper_bound(%{dynamic: dynamic}), do: dynamic\n  def upper_bound(static), do: static\n\n  @doc \"\"\"\n  Gets the lower bound of a gradual type.\n\n  This is the same as getting the static part.\n  Note this is not generally safe and changes the representation of the type.\n  \"\"\"\n  def lower_bound(:term), do: :term\n  def lower_bound(type), do: Map.delete(type, :dynamic)\n\n  ## Function constructors\n\n  @doc \"\"\"\n  The top function type.\n  \"\"\"\n  def fun(), do: %{fun: @fun_top}\n\n  @doc \"\"\"\n  Creates a function type with the given arguments and return type.\n\n  ## Examples\n\n      fun([integer()], atom())\n      #=> (integer -> atom)\n\n      fun([integer(), float()], boolean())\n      #=> (integer, float -> boolean)\n  \"\"\"\n  def fun(args, return) when is_list(args), do: fun_descr(args, return)\n\n  @doc \"\"\"\n  Creates the top function type for the given arity,\n  where all arguments are none() and return is term().\n\n  This function cannot be applied to, unless it is made dynamic.\n\n  ## Examples\n\n      fun(1)\n      #=> (none -> term)\n\n      fun(2)\n      #=> Creates (none, none -> term)\n  \"\"\"\n  def fun(arity) when is_integer(arity) and arity >= 0 do\n    %{fun: {:union, %{arity => @fun_bdd_top}}}\n  end\n\n  @doc \"\"\"\n  Creates a function from non-overlapping function clauses.\n  \"\"\"\n  def fun_from_non_overlapping_clauses([{args, return} | clauses]) do\n    Enum.reduce(clauses, fun(args, return), fn {args, return}, acc ->\n      intersection(acc, fun(args, return))\n    end)\n  end\n\n  @doc \"\"\"\n  Creates a function from overlapping function clauses.\n  \"\"\"\n  def fun_from_inferred_clauses(args_clauses) do\n    domain_clauses =\n      Enum.reduce(args_clauses, [], fn {args, return}, acc ->\n        domain = args |> Enum.map(&upper_bound/1) |> args_to_domain()\n        return = upper_bound(return)\n        pivot_overlapping_clause(domain, return, return, acc)\n      end)\n\n    funs =\n      for {domain, _return, union} <- domain_clauses,\n          args <- domain_to_args(domain),\n          do: fun(args, dynamic(union))\n\n    Enum.reduce(funs, &intersection/2)\n  end\n\n  # If you have a function with multiple clauses, they may overlap,\n  # and we need to find the correct return type. This can be done\n  # in two different algorithms: a precise and a fast one.\n  # Consider the inferred clauses:\n  #\n  #     (integer() or atom() -> :foo) and (integer() or float() -> :bar)\n  #\n  # The precise algorithm works by finding the intersections between\n  # domains, assigning it the union, and then computing the leftovers\n  # on each side. The trouble of this approach is that it builds\n  # differences, which can be expensive, and can lead to several new\n  # clauses. For example, the clause above would emit:\n  #\n  #     (integer() -> :foo or :bar) and (atom() -> :foo) and (float() -> :bar)\n  #\n  # Due to performance constraints, we chose the fast approach, which\n  # leads to broad return types, but this is acceptable because we mark\n  # all return types as dynamic anyway. Therefore we infer the type:\n  #\n  #     (integer() or atom() -> :foo or :bar) and (integer() or float() -> :foo or :bar)\n  #\n  defp pivot_overlapping_clause(domain, return, union, [{acc_domain, acc_return, acc_union} | acc]) do\n    if disjoint?(domain, acc_domain) do\n      [\n        {acc_domain, acc_return, acc_union}\n        | pivot_overlapping_clause(domain, return, union, acc)\n      ]\n    else\n      [\n        {acc_domain, acc_return, union(return, acc_union)}\n        | pivot_overlapping_clause(domain, return, union(acc_return, union), acc)\n      ]\n    end\n  end\n\n  defp pivot_overlapping_clause(domain, return, union, []) do\n    [{domain, return, union}]\n  end\n\n  @doc \"\"\"\n  Converts a list of arguments into a domain.\n\n  Tuples represent function domains, using unions to combine parameters.\n\n  Example: for functions (integer(), float() -> :ok) and (float(), integer() -> :error)\n  domain isn't `{integer() or float(), integer() or float()}` as that would incorrectly\n  accept `{float(), float()}`, instead it is `{integer(), float()} or {float(), integer()}`.\n  \"\"\"\n  def args_to_domain(types) when is_list(types), do: tuple(types)\n\n  @doc \"\"\"\n  Converts a list of arguments into a static domain.\n\n  If a dynamic type is given, we get its upper bound.\n  \"\"\"\n  def args_to_static_domain(types) when is_list(types) do\n    %{tuple: tuple_new(:closed, Enum.map(types, &upper_bound/1))}\n  end\n\n  @doc \"\"\"\n  Converts the domain to a list of arguments.\n\n  The domain is expected to be closed tuples. They may have complex negations\n  which are then simplified to a union of positive tuple literals only.\n\n  * For static tuple types: eliminates all negations from the DNF representation.\n\n  * For gradual tuple types: processes both dynamic and static components separately,\n    then combines them.\n\n  \"\"\"\n  def domain_to_args(descr) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        unwrap_domain_tuple(descr, fn {:closed, elems} -> elems end)\n\n      {dynamic, static} ->\n        unwrap_domain_tuple(static, fn {:closed, elems} -> elems end) ++\n          unwrap_domain_tuple(dynamic, fn {:closed, elems} -> Enum.map(elems, &dynamic/1) end)\n    end\n  end\n\n  @doc \"\"\"\n  Converts the domain to a flatten list of arguments.\n  \"\"\"\n  def domain_to_flat_args(domain, arity_or_args) do\n    case domain_to_args(domain) do\n      [] when is_integer(arity_or_args) -> List.duplicate(none(), arity_or_args)\n      [] when is_list(arity_or_args) -> Enum.map(arity_or_args, fn _ -> none() end)\n      args -> Enum.zip_with(args, fn types -> Enum.reduce(types, &union/2) end)\n    end\n  end\n\n  defp unwrap_domain_tuple(%{tuple: bdd} = descr, transform) when map_size(descr) == 1 do\n    tuple_bdd_to_dnf_no_negations(bdd) |> Enum.map(transform)\n  end\n\n  defp unwrap_domain_tuple(descr, _transform) when descr == %{}, do: []\n\n  ## Optional\n\n  # `not_set()` is a special base type that represents a not_set field in a map.\n  # E.g., `%{a: integer(), b: not_set(), ...}` represents a map with an integer\n  # field `a` and an not_set field `b`, and possibly other fields.\n  #\n  # The `if_set()` modifier is syntactic sugar for specifying the key as a union\n  # of the key type and `not_set()`. For example, `%{:foo => if_set(integer())}`\n  # is equivalent to `%{:foo => integer() or not_set()}`.\n  #\n  # `not_set()` has no meaning outside of map types.\n  def not_set(), do: @not_set\n\n  def if_set(:term), do: term_or_optional()\n\n  # If type contains a :dynamic part, :optional gets added there.\n  def if_set(type) do\n    case type do\n      %{dynamic: :term} -> %{dynamic: term_or_optional()}\n      %{dynamic: dyn} -> Map.put(%{type | dynamic: Map.put(dyn, :optional, 1)}, :optional, 1)\n      _ -> Map.put(type, :optional, 1)\n    end\n  end\n\n  defp term_or_optional(), do: @term_or_optional\n\n  @compile {:inline,\n            keep_optional: 1, remove_optional: 1, remove_optional_static: 1, optional_to_term: 1}\n  defp keep_optional(descr) do\n    case descr do\n      %{dynamic: %{optional: 1}} -> %{dynamic: %{optional: 1}}\n      %{optional: 1} -> %{optional: 1}\n      _ -> @none\n    end\n  end\n\n  defp remove_optional(descr) do\n    case descr do\n      %{dynamic: %{optional: _} = dynamic} when map_size(dynamic) == 1 ->\n        Map.delete(descr, :dynamic)\n\n      %{dynamic: %{optional: _} = dynamic} ->\n        %{descr | dynamic: Map.delete(dynamic, :optional)}\n\n      _ ->\n        remove_optional_static(descr)\n    end\n  end\n\n  defp remove_optional_static(%{} = descr), do: Map.delete(descr, :optional)\n  defp remove_optional_static(descr), do: descr\n\n  defp optional_to_term(descr) do\n    case descr do\n      %{dynamic: %{optional: _}} -> @term_or_dynamic_optional\n      %{optional: _} -> term_or_optional()\n      _ -> :term\n    end\n  end\n\n  defp pop_optional_static(:term), do: {false, :term}\n\n  defp pop_optional_static(type) do\n    case :maps.take(:optional, type) do\n      :error -> {false, type}\n      {1, type} -> {true, type}\n    end\n  end\n\n  ## Set operations\n\n  @doc \"\"\"\n  Returns true if the type has a gradual part.\n  \"\"\"\n  def gradual?(:term), do: false\n  def gradual?(descr), do: is_map_key(descr, :dynamic)\n\n  @doc \"\"\"\n  Returns true if the type only has a gradual part.\n  \"\"\"\n  def only_gradual?(%{dynamic: _} = descr), do: map_size(descr) == 1\n  def only_gradual?(_), do: false\n\n  @doc \"\"\"\n  Make a whole type dynamic.\n\n  It is an optimized version of `intersection(dynamic(), type)`.\n  \"\"\"\n  @compile {:inline, dynamic: 1}\n  def dynamic(descr) do\n    case descr do\n      %{dynamic: dynamic} -> %{dynamic: dynamic}\n      _ -> %{dynamic: descr}\n    end\n  end\n\n  @compile {:inline, pop_dynamic: 1}\n  defp pop_dynamic(:term), do: {:term, :term}\n  defp pop_dynamic(descr), do: Map.pop(descr, :dynamic, descr)\n\n  @compile {:inline, maybe_union: 2}\n  defp maybe_union(nil, _fun), do: nil\n  defp maybe_union(descr, fun), do: union(descr, fun.())\n\n  @doc \"\"\"\n  Computes the union of two descrs.\n  \"\"\"\n  def union(:term, other), do: optional_to_term(other)\n  def union(other, :term), do: optional_to_term(other)\n  def union(none, other) when none == @none, do: other\n  def union(other, none) when none == @none, do: other\n\n  def union(left, right) do\n    is_gradual_left = gradual?(left)\n    is_gradual_right = gradual?(right)\n\n    cond do\n      is_gradual_left and not is_gradual_right ->\n        right_with_dynamic = Map.put(unfold(right), :dynamic, right)\n        union_static(left, right_with_dynamic)\n\n      is_gradual_right and not is_gradual_left ->\n        left_with_dynamic = Map.put(unfold(left), :dynamic, left)\n        union_static(left_with_dynamic, right)\n\n      true ->\n        union_static(left, right)\n    end\n  end\n\n  @compile {:inline, union_static: 2}\n  defp union_static(left, right) do\n    symmetrical_merge(left, right, &union/3)\n  end\n\n  defp union(:atom, v1, v2), do: atom_union(v1, v2)\n  defp union(:bitmap, v1, v2), do: v1 ||| v2\n  defp union(:dynamic, v1, v2), do: dynamic_union(v1, v2)\n  defp union(:list, v1, v2), do: list_union(v1, v2)\n  defp union(:map, v1, v2), do: map_union(v1, v2)\n  defp union(:optional, 1, 1), do: 1\n  defp union(:tuple, v1, v2), do: tuple_union(v1, v2)\n  defp union(:fun, v1, v2), do: fun_union(v1, v2)\n\n  @doc \"\"\"\n  Computes the intersection of two descrs.\n  \"\"\"\n  def intersection(:term, other), do: remove_optional(other)\n  def intersection(other, :term), do: remove_optional(other)\n  def intersection(%{dynamic: :term}, other), do: dynamic(remove_optional(other))\n  def intersection(other, %{dynamic: :term}), do: dynamic(remove_optional(other))\n\n  def intersection(left, right) do\n    is_gradual_left = gradual?(left)\n    is_gradual_right = gradual?(right)\n\n    cond do\n      is_gradual_left and not is_gradual_right ->\n        right_with_dynamic = Map.put(unfold(right), :dynamic, right)\n        intersection_static(left, right_with_dynamic)\n\n      is_gradual_right and not is_gradual_left ->\n        left_with_dynamic = Map.put(unfold(left), :dynamic, left)\n        intersection_static(left_with_dynamic, right)\n\n      true ->\n        intersection_static(left, right)\n    end\n  end\n\n  @compile {:inline, intersection_static: 2}\n  defp intersection_static(left, right) do\n    symmetrical_intersection(left, right, &intersection/3)\n  end\n\n  # Returning 0 from the callback is taken as none() for that subtype.\n  defp intersection(:atom, v1, v2), do: atom_intersection(v1, v2)\n  defp intersection(:bitmap, v1, v2), do: v1 &&& v2\n  defp intersection(:list, v1, v2), do: list_intersection(v1, v2)\n  defp intersection(:map, v1, v2), do: map_intersection(v1, v2)\n  defp intersection(:optional, 1, 1), do: 1\n  defp intersection(:tuple, v1, v2), do: tuple_intersection(v1, v2)\n  defp intersection(:fun, v1, v2), do: fun_intersection(v1, v2)\n\n  defp intersection(:dynamic, v1, v2) do\n    descr = dynamic_intersection(v1, v2)\n    if descr == @none, do: 0, else: descr\n  end\n\n  @doc \"\"\"\n  Computes the difference between two types.\n  \"\"\"\n  def difference(left, :term), do: keep_optional(left)\n  def difference(left, none) when none == @none, do: left\n\n  def difference(left, right) do\n    if gradual?(left) or gradual?(right) do\n      {left_dynamic, left_static} = pop_dynamic(left)\n      {right_dynamic, right_static} = pop_dynamic(right)\n      dynamic_part = difference_static(left_dynamic, right_static)\n\n      Map.put(difference_static(left_static, right_dynamic), :dynamic, dynamic_part)\n    else\n      difference_static(left, right)\n    end\n  end\n\n  # For static types, the difference is component-wise\n  defp difference_static(left, descr) when descr == %{}, do: left\n  defp difference_static(left, :term), do: keep_optional(left)\n\n  defp difference_static(left, right) do\n    iterator_difference_static(:maps.next(:maps.iterator(unfold(right))), unfold(left))\n  end\n\n  defp iterator_difference_static({key, v2, iterator}, map) do\n    acc =\n      case map do\n        %{^key => v1} ->\n          value = difference(key, v1, v2)\n\n          if value in @empty_difference do\n            Map.delete(map, key)\n          else\n            %{map | key => value}\n          end\n\n        %{} ->\n          map\n      end\n\n    iterator_difference_static(:maps.next(iterator), acc)\n  end\n\n  defp iterator_difference_static(:none, map), do: map\n\n  # This function is designed to compute the difference during subtyping efficiently.\n  # Do not use it for anything else.\n  defp empty_difference_subtype?(%{dynamic: dyn_left} = left, %{dynamic: dyn_right} = right) do\n    # Dynamic will either exist on both sides or on none\n    empty_difference_subtype?(dyn_left, dyn_right) and\n      empty_difference_subtype?(Map.delete(left, :dynamic), Map.delete(right, :dynamic))\n  end\n\n  defp empty_difference_subtype?(left, :term), do: keep_optional(left) == @none\n\n  defp empty_difference_subtype?(left, right) do\n    iterator_empty_difference_subtype?(:maps.next(:maps.iterator(unfold(left))), unfold(right))\n  end\n\n  defp iterator_empty_difference_subtype?({key, v1, iterator}, map) do\n    case map do\n      %{^key => v2} ->\n        value = difference(key, v1, v2)\n        value in @empty_difference or empty_key?(key, value)\n\n      %{} ->\n        empty_key?(key, v1)\n    end and\n      iterator_empty_difference_subtype?(:maps.next(iterator), map)\n  end\n\n  defp iterator_empty_difference_subtype?(:none, _map), do: true\n\n  # Returning 0 from the callback is taken as none() for that subtype.\n  defp difference(:atom, v1, v2), do: atom_difference(v1, v2)\n  defp difference(:bitmap, v1, v2), do: v1 - (v1 &&& v2)\n  defp difference(:list, v1, v2), do: list_difference(v1, v2)\n  defp difference(:map, v1, v2), do: map_difference(v1, v2)\n  defp difference(:optional, 1, 1), do: 0\n  defp difference(:tuple, v1, v2), do: tuple_difference(v1, v2)\n  defp difference(:fun, v1, v2), do: fun_difference(v1, v2)\n\n  @doc \"\"\"\n  Compute the negation of a type.\n  \"\"\"\n  def negation(:term), do: none()\n  def negation(%{} = descr), do: difference(term(), descr)\n\n  @doc \"\"\"\n  Check if a type is empty.\n\n  For gradual types, check that the upper bound (the dynamic part) is empty.\n  Stop as soon as one non-empty component is found. Simpler components\n  (bitmap, atom) are checked first for speed since, if they are present,\n  the type is non-empty as we normalize then during construction.\n  \"\"\"\n  def empty?(:term), do: false\n\n  def empty?(%{} = descr) do\n    case :maps.get(:dynamic, descr, descr) do\n      :term ->\n        false\n\n      value when value == @none ->\n        true\n\n      descr ->\n        not Map.has_key?(descr, :atom) and\n          not Map.has_key?(descr, :bitmap) and\n          not Map.has_key?(descr, :optional) and\n          (not Map.has_key?(descr, :tuple) or tuple_empty?(descr.tuple)) and\n          (not Map.has_key?(descr, :map) or map_empty?(descr.map)) and\n          (not Map.has_key?(descr, :list) or list_empty?(descr.list)) and\n          (not Map.has_key?(descr, :fun) or fun_empty?(descr.fun))\n    end\n  end\n\n  defp empty_or_optional?(type), do: empty?(remove_optional(type))\n\n  # For atom, bitmap, tuple, and optional, if the key is present,\n  # then they are not empty,\n  defp empty_key?(:fun, value), do: fun_empty?(value)\n  defp empty_key?(:map, value), do: map_empty?(value)\n  defp empty_key?(:list, value), do: list_empty?(value)\n  defp empty_key?(:tuple, value), do: tuple_empty?(value)\n  defp empty_key?(_, _value), do: false\n\n  @doc \"\"\"\n  Converts all floats or integers into numbers.\n  \"\"\"\n  def numberize(:term), do: :term\n  def numberize(descr), do: numberize_each(descr, [:bitmap, :tuple, :map, :list, :dynamic])\n\n  defp numberize_each(descr, [key | keys]) do\n    case descr do\n      %{^key => val} -> %{descr | key => numberize(key, val)}\n      %{} -> descr\n    end\n    |> numberize_each(keys)\n  end\n\n  defp numberize_each(descr, []) do\n    descr\n  end\n\n  defp numberize(:dynamic, descr), do: numberize(descr)\n  defp numberize(:bitmap, bitmap) when (bitmap &&& @bit_number) != 0, do: bitmap ||| @bit_number\n  defp numberize(:bitmap, bitmap), do: bitmap\n\n  defp numberize(:map, bdd) do\n    bdd_map(bdd, fn {tag, fields} ->\n      {tag, fields_map(fn _key, value -> numberize(value) end, fields)}\n    end)\n  end\n\n  defp numberize(:tuple, bdd) do\n    bdd_map(bdd, fn {tag, fields} -> {tag, Enum.map(fields, &numberize/1)} end)\n  end\n\n  defp numberize(:list, bdd) do\n    bdd_map(bdd, fn {head, tail} -> {numberize(head), numberize(tail)} end)\n  end\n\n  @doc \"\"\"\n  Returns if the type is a singleton.\n  \"\"\"\n  def singleton?(:term), do: false\n  def singleton?(descr), do: static_singleton?(Map.get(descr, :dynamic, descr))\n\n  defp static_singleton?(:term), do: false\n  defp static_singleton?(%{optional: _}), do: false\n  defp static_singleton?(%{list: _}), do: false\n  defp static_singleton?(%{fun: _}), do: false\n  defp static_singleton?(descr), do: each_singleton?(descr, [:atom, :bitmap, :map, :tuple], false)\n\n  defp each_singleton?(descr, [key | keys], acc) do\n    case descr do\n      %{^key => value} ->\n        case each_singleton?(key, value) do\n          true when acc == true -> false\n          true -> each_singleton?(descr, keys, true)\n          false -> false\n          :empty -> each_singleton?(descr, keys, acc)\n        end\n\n      %{} ->\n        each_singleton?(descr, keys, acc)\n    end\n  end\n\n  defp each_singleton?(_descr, [], acc), do: acc\n\n  # Implement for each type\n  defp each_singleton?(:bitmap, bitmap), do: bitmap == @bit_empty_list\n\n  defp each_singleton?(:atom, atoms), do: match?({:union, set} when map_size(set) == 1, atoms)\n\n  defp each_singleton?(:tuple, bdd) do\n    case tuple_bdd_to_dnf_no_negations(bdd) do\n      [] -> :empty\n      [{:closed, entries}] -> Enum.all?(entries, &static_singleton?/1)\n      _ -> false\n    end\n  end\n\n  defp each_singleton?(:map, bdd) do\n    case map_bdd_to_dnf_remove_empty(bdd) do\n      [] ->\n        :empty\n\n      [{:closed, fields, _negs}] ->\n        Enum.all?(fields_to_list(fields), fn {_, v} -> static_singleton?(v) end)\n\n      _ ->\n        false\n    end\n  end\n\n  @doc \"\"\"\n  Converts a descr to its quoted representation.\n\n  ## Options\n\n    * `:collapse_structs` - do not show struct fields that match\n      their default type\n  \"\"\"\n  def to_quoted(descr, opts \\\\ []) do\n    if term_type?(descr) do\n      {:term, [], []}\n    else\n      non_term_type_to_quoted(descr, opts)\n    end\n  end\n\n  defp non_term_type_to_quoted(descr, opts) do\n    {dynamic, static, extra} =\n      case :maps.take(:dynamic, descr) do\n        :error ->\n          {%{}, descr, []}\n\n        {:term, static} ->\n          {:term, static, []}\n\n        {dynamic, static} ->\n          cond do\n            # Computing term_type?(difference(dynamic, static)) can be\n            # expensive, so we check for term type before hand and check\n            # for :term exclusively in dynamic_to_quoted/2.\n            term_type?(dynamic) ->\n              {:term, static, []}\n\n            # We need to check for quoted here before we compute the difference below\n            quoted = maybe_negated_term_type_to_quoted(static, opts) ->\n              {dynamic, %{}, [quoted]}\n\n            # Denormalize functions (only unions) before we do the difference\n            true ->\n              {static, dynamic, extra} = fun_denormalize(static, dynamic, opts)\n              {difference(dynamic, static), static, extra}\n          end\n      end\n\n    {static, extra} =\n      if quoted = maybe_negated_term_type_to_quoted(static, opts) do\n        {%{}, [quoted | extra]}\n      else\n        {static, extra}\n      end\n\n    # Dynamic always come first for visibility\n    unions =\n      to_quoted(:dynamic, dynamic, opts) ++ static_non_term_type_to_quoted(static, extra, opts)\n\n    case unions do\n      [] -> {:none, [], []}\n      unions -> Enum.reduce(unions, &{:or, [], [&2, &1]})\n    end\n  end\n\n  defp static_non_term_type_to_quoted(static, extra, opts) do\n    # Merge empty list and list together if they both exist\n    {extra, static} =\n      case static do\n        %{list: list, bitmap: bitmap} when (bitmap &&& @bit_empty_list) != 0 ->\n          static =\n            static\n            |> Map.delete(:list)\n            |> Map.replace!(:bitmap, bitmap - @bit_empty_list)\n\n          {list_to_quoted(list, true, opts) ++ extra, static}\n\n        %{} ->\n          {extra, static}\n      end\n\n    Enum.sort(extra ++ Enum.flat_map(static, fn {key, value} -> to_quoted(key, value, opts) end))\n  end\n\n  defp to_quoted(:atom, val, _opts), do: atom_to_quoted(val)\n  defp to_quoted(:bitmap, val, _opts), do: bitmap_to_quoted(val)\n  defp to_quoted(:dynamic, descr, opts), do: dynamic_to_quoted(descr, opts)\n  defp to_quoted(:map, bdd, opts), do: map_to_quoted(bdd, opts)\n  defp to_quoted(:list, bdd, opts), do: list_to_quoted(bdd, false, opts)\n  defp to_quoted(:tuple, bdd, opts), do: tuple_to_quoted(bdd, opts)\n  defp to_quoted(:fun, bdd, opts), do: fun_to_quoted(bdd, opts)\n\n  defp maybe_negated_term_type_to_quoted(static, opts) do\n    if print_as_negated_type?(static) do\n      static\n      |> negation()\n      |> unfold()\n      |> static_non_term_type_to_quoted([], opts)\n      |> case do\n        [] ->\n          nil\n\n        [head | tail] ->\n          Enum.reduce(tail, {:not, [], [head]}, &{:and, [], [&2, {:not, [], [&1]}]})\n      end\n    end\n  end\n\n  # Unions would be printed as negations within negations\n  defp print_as_negated_type?(%{atom: {:union, _}}), do: false\n  defp print_as_negated_type?(%{fun: {:union, _}}), do: false\n\n  defp print_as_negated_type?(descr) do\n    # In here we compute the score of negations.\n    # If we have more than 6, we print it as a negated type.\n    result =\n      Enum.sum_by(Map.to_list(descr), fn\n        {:tuple, bdd} -> print_as_negated_bdd(bdd, @tuple_top)\n        {:map, bdd} -> print_as_negated_bdd(bdd, @map_top)\n        {:list, bdd} -> print_as_negated_bdd(bdd, @non_empty_list_top)\n        {:bitmap, bitmap} -> Integer.popcount(bitmap)\n        {:atom, {:union, _}} -> -100\n        {:fun, {:union, _}} -> -100\n        {_, _} -> 1\n      end)\n\n    result > 8\n  end\n\n  # A bdd leaf can be trivially printed in negated format\n  # but we don't count it towards the amount of negatives.\n  defp print_as_negated_bdd(top, top), do: 1\n  defp print_as_negated_bdd(bdd_leaf(_, _), _top), do: 0\n  defp print_as_negated_bdd(bdd, top), do: if(negated_bdd?(bdd, top), do: 1, else: -100)\n\n  defp negated_bdd?({top, bdd, :bdd_bot, :bdd_bot}, top),\n    do: negated_bdd?(bdd, top)\n\n  defp negated_bdd?({_, :bdd_bot, :bdd_bot, bdd}, top),\n    do: bdd in [:bdd_top, top] or negated_bdd?(bdd, top)\n\n  defp negated_bdd?(_, _), do: false\n\n  @doc \"\"\"\n  Converts a descr to its quoted string representation.\n\n  ## Options\n\n    * `:collapse_structs` - do not show struct fields that match\n      their default type\n  \"\"\"\n  def to_quoted_string(descr, opts \\\\ []) do\n    descr\n    |> to_quoted(opts)\n    |> Code.Formatter.to_algebra()\n    |> Inspect.Algebra.format(98)\n    |> IO.iodata_to_binary()\n  end\n\n  ## Type relations\n\n  @doc \"\"\"\n  Check if a type is a subtype of another.\n\n  If     `left  = (left_dyn  and dynamic()) or left_static`\n  and    `right = (right_dyn and dynamic()) or right_static`\n\n  then the gradual subtyping relation defined in Definition 6.5 page 125 of\n  the thesis https://vlanvin.fr/papers/thesis.pdf is:\n\n  `left <= right` if and only if\n    - `left_static <= right_static`\n    - `left_dyn <= right_dyn`\n\n  Because of the dynamic/static invariant in the `descr`, subtyping can be\n  simplified in several cases according to which type is gradual or not.\n  \"\"\"\n  def subtype?(left, right) do\n    left = unfold(left)\n    right = unfold(right)\n    is_grad_left = gradual?(left)\n    is_grad_right = gradual?(right)\n\n    cond do\n      is_grad_left and not is_grad_right ->\n        left_dynamic = Map.get(left, :dynamic)\n        subtype_static?(left_dynamic, right)\n\n      is_grad_right and not is_grad_left ->\n        right_static = Map.delete(right, :dynamic)\n        subtype_static?(left, right_static)\n\n      true ->\n        subtype_static?(left, right)\n    end\n  end\n\n  defp subtype_static?(same, same), do: true\n  defp subtype_static?(left, right), do: empty_difference_subtype?(left, right)\n\n  @doc \"\"\"\n  Check if a type is equal to another.\n\n  It is currently not optimized. Only to be used in tests.\n  \"\"\"\n  def equal?(left, right) do\n    left == right or (subtype?(left, right) and subtype?(right, left))\n  end\n\n  @doc \"\"\"\n  Check if two types are disjoint.\n\n  This reimplements intersection/2 but aborts as it finds a disjoint part.\n  \"\"\"\n  def disjoint?(:term, other), do: empty?(remove_optional(other))\n  def disjoint?(other, :term), do: empty?(remove_optional(other))\n  def disjoint?(%{dynamic: :term}, other), do: empty?(remove_optional(other))\n  def disjoint?(other, %{dynamic: :term}), do: empty?(remove_optional(other))\n\n  # Two gradual types are disjoint if their upper bounds are disjoint.\n  def disjoint?(left, right) do\n    left_upper = unfold(left) |> Map.get(:dynamic, left)\n    right_upper = unfold(right) |> Map.get(:dynamic, right)\n\n    not non_disjoint_intersection?(left_upper, right_upper)\n  end\n\n  @doc \"\"\"\n  Checks if a type is a compatible subtype of another.\n\n  If `input_type` has a static part (i.e., values that are known to appear and\n  need to be handled), then to be compatible it should be a subtype of the\n  the dynamic part of `expected_type` (that is, the largest allowed type at\n  runtime).\n\n  If `input_type` is a dynamic type, then we check that the two can intersect\n  at runtime, i.e. it is possible to get valid inputs at runtime.\n\n  The function is used, in gradual mode, to type an operator that expects a given\n  type. For instance, `+` expects `integer() or float()` inputs. Compatible inputs\n  include `dynamic()`, `integer()`, but also `dynamic() and (integer() or atom())`.\n  Incompatible subtypes include `integer() or list()`, `dynamic() and atom()`.\n  \"\"\"\n  def compatible?(left, right) do\n    {left_dynamic, left_static} = pop_dynamic(left)\n\n    right_dynamic =\n      case right do\n        %{dynamic: dynamic} -> dynamic\n        _ -> right\n      end\n\n    if empty?(left_static) do\n      not disjoint?(left_dynamic, right_dynamic)\n    else\n      subtype_static?(left_static, right_dynamic)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the intersection between two types\n  only if they are compatible. Otherwise returns `:error`.\n\n  This finds the intersection between the arguments and the\n  domain of a function. It is used to refine dynamic types\n  as we traverse the program.\n  \"\"\"\n  def compatible_intersection(left, right) do\n    {left_dynamic, left_static} = pop_dynamic(left)\n\n    right_dynamic =\n      case right do\n        %{dynamic: dynamic} -> dynamic\n        _ -> right\n      end\n\n    cond do\n      empty?(left_static) ->\n        dynamic = intersection_static(unfold(left_dynamic), unfold(right_dynamic))\n        if empty?(dynamic), do: {:error, left}, else: {:ok, dynamic(dynamic)}\n\n      subtype_static?(left_static, right_dynamic) ->\n        dynamic = intersection_static(unfold(left_dynamic), unfold(right_dynamic))\n        {:ok, union(dynamic(dynamic), left_static)}\n\n      true ->\n        {:error, left}\n    end\n  end\n\n  @doc \"\"\"\n  Optimized version of `not empty?(term(), type)`.\n  \"\"\"\n  def term_type?(:term), do: true\n  def term_type?(descr), do: subtype_static?(unfolded_term(), Map.delete(descr, :dynamic))\n\n  @doc \"\"\"\n  Optimized version of `not empty?(intersection(empty_list(), type))`.\n  \"\"\"\n  def empty_list_type?(:term), do: true\n  def empty_list_type?(%{dynamic: :term}), do: true\n\n  def empty_list_type?(%{dynamic: %{bitmap: bitmap}}) when (bitmap &&& @bit_empty_list) != 0,\n    do: true\n\n  def empty_list_type?(%{bitmap: bitmap}) when (bitmap &&& @bit_empty_list) != 0, do: true\n  def empty_list_type?(_), do: false\n\n  @doc \"\"\"\n  Optimized version of `not empty?(intersection(bitstring(), type))`.\n  \"\"\"\n  def bitstring_type?(:term), do: true\n  def bitstring_type?(%{dynamic: :term}), do: true\n\n  def bitstring_type?(%{dynamic: %{bitmap: bitmap}}) when (bitmap &&& @bit_bitstring) != 0,\n    do: true\n\n  def bitstring_type?(%{bitmap: bitmap}) when (bitmap &&& @bit_bitstring) != 0, do: true\n  def bitstring_type?(_), do: false\n\n  @doc \"\"\"\n  Optimized version of `not empty?(intersection(difference(bitstring(), binary()), type))`.\n\n  Notice that this does not mean it is not a binary.\n  It only means the bitstring bit is up, regardless of the binary bit.\n  \"\"\"\n  def bitstring_no_binary_type?(:term), do: true\n  def bitstring_no_binary_type?(%{dynamic: :term}), do: true\n\n  def bitstring_no_binary_type?(%{dynamic: %{bitmap: bitmap}})\n      when (bitmap &&& @bit_bitstring_no_binary) != 0, do: true\n\n  def bitstring_no_binary_type?(%{bitmap: bitmap})\n      when (bitmap &&& @bit_bitstring_no_binary) != 0, do: true\n\n  def bitstring_no_binary_type?(_), do: false\n\n  @doc \"\"\"\n  Optimized version of `not empty?(intersection(integer() or float(), type))`.\n  \"\"\"\n  def number_type?(:term), do: true\n  def number_type?(%{dynamic: :term}), do: true\n  def number_type?(%{dynamic: %{bitmap: bitmap}}) when (bitmap &&& @bit_number) != 0, do: true\n  def number_type?(%{bitmap: bitmap}) when (bitmap &&& @bit_number) != 0, do: true\n  def number_type?(_), do: false\n\n  ## Bitmaps\n\n  defp bitmap_to_quoted(val) do\n    pairs =\n      [\n        empty_list: @bit_empty_list,\n        integer: @bit_integer,\n        float: @bit_float,\n        pid: @bit_pid,\n        port: @bit_port,\n        reference: @bit_reference\n      ]\n\n    quoted =\n      for {type, mask} <- pairs,\n          (mask &&& val) !== 0,\n          do: {type, [], []}\n\n    case val &&& @bit_bitstring do\n      0 -> quoted\n      1 -> [{:binary, [], []} | quoted]\n      2 -> [{:and, [], [{:bitstring, [], []}, {:not, [], [{:binary, [], []}]}]} | quoted]\n      3 -> [{:bitstring, [], []} | quoted]\n    end\n  end\n\n  ## Atoms\n\n  # The atom component of a type consists of pairs `{tag, set}` where `set` is a\n  # set of atoms.\n  # If `tag = :union` the pair represents the union of the atoms in `set`.\n  # Else, if `tag = :negation`, it represents every atom except those in `set`.\n  #\n  # Example:\n  #   - `{:union, :sets.from_list([:a, :b])}` represents type `:a or :b`\n  #   - `{:negation, :sets.from_list([:c, :d])}` represents type `atom() \\ (:c or :d)\n  #\n  # `{:negation, :sets.new()}` is the `atom()` top type, as it is the difference\n  # of `atom()` with an empty list.\n  #\n  # `{:union, :sets.new()}` is the empty type for atoms, as it is the union of\n  # an empty list of atoms. It is simplified to `0` in set operations, and the key\n  # is removed from the map.\n\n  @doc \"\"\"\n  Compute the booleaness of an element.\n\n  It is either `:none`, `:maybe_true` (therefore never false),\n  `:maybe_false` (therefore never true), or `:maybe_both`.\n\n  This is an optimization against checking if a term is\n  not disjoint on either true or false.\n  \"\"\"\n  def booleaness(:term), do: :maybe_both\n\n  def booleaness(%{} = descr) do\n    descr = Map.get(descr, :dynamic, descr)\n\n    case descr do\n      :term ->\n        :maybe_both\n\n      %{atom: {:union, %{true: _, false: _}}} ->\n        :maybe_both\n\n      %{atom: {:union, %{true: _} = union}} when map_size(descr) == 1 and map_size(union) == 1 ->\n        {true, :always}\n\n      %{atom: {:union, %{false: _} = union}} when map_size(descr) == 1 and map_size(union) == 1 ->\n        {false, :always}\n\n      %{atom: {:union, %{true: _}}} ->\n        {true, :maybe}\n\n      %{atom: {:union, %{false: _}}} ->\n        {false, :maybe}\n\n      %{atom: {:union, _}} ->\n        :none\n\n      %{atom: {:negation, %{true: _, false: _}}} ->\n        :none\n\n      %{atom: {:negation, %{true: _}}} ->\n        {false, :maybe}\n\n      %{atom: {:negation, %{false: _}}} ->\n        {true, :maybe}\n\n      %{atom: {:negation, _}} ->\n        :maybe_both\n\n      _ ->\n        :none\n    end\n  end\n\n  @false_or_nil_atoms [\n    :sets.from_list([false, nil], version: 2),\n    :sets.from_list([nil], version: 2),\n    :sets.from_list([false], version: 2)\n  ]\n\n  @doc \"\"\"\n  Compute the truthiness of an element.\n\n  It is either :undefined, :always_true, or :always_false.\n  \"\"\"\n  def truthiness(:term), do: :undefined\n\n  def truthiness(%{} = descr) do\n    descr = Map.get(descr, :dynamic, descr)\n\n    case descr do\n      :term ->\n        :undefined\n\n      %{atom: {:union, set}}\n      when map_size(descr) == 1 and set in @false_or_nil_atoms ->\n        :always_false\n\n      %{atom: {:union, set}}\n      when map_size(descr) == 1 and not is_map_key(set, false) and not is_map_key(set, nil) ->\n        :always_true\n\n      %{atom: {:negation, %{nil => _, false => _}}} ->\n        :always_true\n\n      %{atom: _} ->\n        :undefined\n\n      _ when map_size(descr) == 0 ->\n        :undefined\n\n      _ ->\n        :always_true\n    end\n  end\n\n  @doc \"\"\"\n  Returns a set of all known atoms.\n\n  Returns `{:finite or :infinite, known_set}` if it is an atom,\n  `:error` otherwise. Notice `known_set` may be empty in infinite\n  cases, due to negations.\n  \"\"\"\n  def atom_fetch(:term), do: :error\n\n  def atom_fetch(%{} = descr) do\n    {static_or_dynamic, static} = pop_dynamic(descr)\n\n    if atom_only?(static) do\n      case static_or_dynamic do\n        :term -> {:infinite, []}\n        %{atom: {:union, set}} -> {:finite, :sets.to_list(set)}\n        %{atom: {:negation, set}} -> {:infinite, :sets.to_list(set)}\n        %{} -> :error\n      end\n    else\n      :error\n    end\n  end\n\n  defp atom_only?(descr), do: empty?(Map.delete(descr, :atom))\n  defp atom_new(as) when is_list(as), do: {:union, :sets.from_list(as, version: 2)}\n\n  defp atom_intersection({tag1, s1}, {tag2, s2}) do\n    {tag, s} =\n      case {tag1, tag2} do\n        {:union, :union} -> {:union, :sets.intersection(s1, s2)}\n        {:negation, :negation} -> {:negation, :sets.union(s1, s2)}\n        {:union, :negation} -> {:union, :sets.subtract(s1, s2)}\n        {:negation, :union} -> {:union, :sets.subtract(s2, s1)}\n      end\n\n    if tag == :union and :sets.size(s) == 0, do: 0, else: {tag, s}\n  end\n\n  defp atom_union({:union, s1}, {:union, s2}), do: {:union, :sets.union(s1, s2)}\n  defp atom_union({:negation, s1}, {:negation, s2}), do: {:negation, :sets.intersection(s1, s2)}\n  defp atom_union({:union, s1}, {:negation, s2}), do: {:negation, :sets.subtract(s2, s1)}\n  defp atom_union({:negation, s1}, {:union, s2}), do: {:negation, :sets.subtract(s1, s2)}\n\n  defp atom_difference({tag1, s1}, {tag2, s2}) do\n    {tag, s} =\n      case {tag1, tag2} do\n        {:union, :union} -> {:union, :sets.subtract(s1, s2)}\n        {:negation, :negation} -> {:union, :sets.subtract(s2, s1)}\n        {:union, :negation} -> {:union, :sets.intersection(s1, s2)}\n        {:negation, :union} -> {:negation, :sets.union(s1, s2)}\n      end\n\n    if tag == :union and :sets.size(s) == 0, do: 0, else: {tag, s}\n  end\n\n  defp literal_to_quoted(lit) do\n    if is_atom(lit) and Macro.classify_atom(lit) == :alias do\n      segments =\n        case Atom.to_string(lit) do\n          \"Elixir\" ->\n            [:\"Elixir\"]\n\n          \"Elixir.\" <> segments ->\n            segments\n            |> String.split(\".\")\n            |> Enum.map(&String.to_atom/1)\n        end\n\n      {:__aliases__, [], segments}\n    else\n      {:__block__, [], [lit]}\n    end\n  end\n\n  defp atom_to_quoted({:union, a}) do\n    if :sets.is_subset(@boolset, a) do\n      entries =\n        :sets.subtract(a, @boolset)\n        |> :sets.to_list()\n        |> Enum.map(&literal_to_quoted/1)\n\n      [{:boolean, [], []} | entries]\n    else\n      :sets.to_list(a)\n      |> Enum.map(&literal_to_quoted/1)\n    end\n  end\n\n  defp atom_to_quoted({:negation, a}) do\n    if :sets.size(a) == 0 do\n      {:atom, [], []}\n    else\n      atom_to_quoted({:union, a})\n      |> Kernel.then(&{:and, [], [{:atom, [], []}, {:not, [], &1}]})\n    end\n    |> List.wrap()\n  end\n\n  ## Functions\n\n  # Function types are represented using Binary Decision Diagrams (BDDs) for efficient\n  # handling of unions, intersections, and negations.\n  #\n  # Currently, they only represent weak types. It is yet to be decided how all of the\n  # types will be encoded in the descr.\n\n  ### Key concepts:\n\n  # * BDD structure: A tree with function nodes and :bdd_top/:bdd_bot leaves.\n  #   Paths to :bdd_top represent valid function types. Nodes are positive when\n  #   following a left branch (e.g. (int, float -> bool) and negative otherwise.\n\n  # * Function variance:\n  #   - Contravariance in arguments: If s <: t, then (t → r) <: (s → r)\n  #   - Covariance in returns: If s <: t, then (u → s) <: (u → t)\n\n  # * Representation:\n  #   - fun(): Top function type (leaf 1)\n  #   - Function literals: {[t1, ..., tn], t} where [t1, ..., tn] are argument types and t is return type\n  #   - Normalized form for function applications: {domain, arrows} is produced by `fun_normalize/2`\n\n  # * Examples:\n  #   - fun([integer()], atom()): A function from integer to atom\n  #   - intersection(fun([integer()], atom()), fun([float()], boolean())): A function handling both signatures\n\n  # Note: Function domains are expressed as tuple types. We use separate representations\n  # rather than unary functions with tuple domains to handle special cases like representing\n  # functions of a specific arity (e.g., (none,none->term) for arity 2).\n  defp fun_new(arity, inputs, output), do: {:union, %{arity => bdd_leaf(inputs, output)}}\n\n  # Creates a function type from a list of inputs and an output\n  # where the inputs and/or output may be dynamic.\n  #\n  # For function (t → s) with dynamic components:\n  # - Static part: (upper_bound(t) → lower_bound(s))\n  # - Dynamic part: dynamic(lower_bound(t) → upper_bound(s))\n  #\n  # When handling dynamic types:\n  # - `upper_bound(t)` extracts the upper bound (most general type) of a gradual type.\n  #   For `dynamic(integer())`, it is `integer()`.\n  # - `lower_bound(t)` extracts the lower bound (most specific type) of a gradual type.\n  defp fun_descr(args, output) when is_list(args) do\n    arity = length(args)\n    dynamic_arguments? = Enum.any?(args, &gradual?/1)\n    dynamic_output? = gradual?(output)\n\n    if dynamic_arguments? or dynamic_output? do\n      input_static = if dynamic_arguments?, do: Enum.map(args, &upper_bound/1), else: args\n      input_dynamic = if dynamic_arguments?, do: Enum.map(args, &lower_bound/1), else: args\n\n      output_static = if dynamic_output?, do: lower_bound(output), else: output\n      output_dynamic = if dynamic_output?, do: upper_bound(output), else: output\n\n      %{\n        fun: fun_new(arity, input_static, output_static),\n        dynamic: %{fun: fun_new(arity, input_dynamic, output_dynamic)}\n      }\n    else\n      # No dynamic components, use standard function type\n      %{fun: fun_new(arity, args, output)}\n    end\n  end\n\n  @doc \"\"\"\n  Applies a function type to a list of argument types.\n\n  Returns `{:ok, result}` if the application is valid\n  or one `{:badarg, to_succeed_domain}`, `:badfun`,\n  `{:badarity, arities}` if not.\n\n  Note the domain returned by `:badarg` is not the strong\n  domain, but the domain that must be satisfied for the\n  function application to succeed.\n\n  Handles both static and dynamic function types:\n\n  1. For static functions: checks exact argument types\n  2. For dynamic functions: computes result based on both static and dynamic parts\n  3. For mixed static/dynamic: computes all valid combinations\n\n  ## Function application formula for dynamic types\n\n      τ◦τ′ = (lower_bound(τ) ◦ upper_bound(τ′)) or (dynamic(upper_bound(τ) ◦ upper_bound(τ′)))\n\n  Where:\n\n  - τ is a dynamic function type\n  - τ′ are the arguments\n  - ◦ is function application\n\n  For more details, see Section 13.2 of\n  https://gldubc.github.io/assets/duboc-phd-thesis-typing-elixir.pdf\n\n  ## Examples\n\n      iex> fun_apply(fun([integer()], atom()), [integer()])\n      {:ok, atom()}\n\n      iex> fun_apply(fun([integer()], atom()), [float()])\n      :badarg\n\n      iex> fun_apply(fun([dynamic()], atom()), [dynamic()])\n      {:ok, atom()}\n  \"\"\"\n  def fun_apply(:term, _arguments), do: :badfun\n\n  def fun_apply(fun, arguments) do\n    case :maps.take(:dynamic, fun) do\n      :error ->\n        if fun_only?(fun) do\n          fun_apply_with_strategy(fun, nil, arguments)\n        else\n          :badfun\n        end\n\n      {fun_dynamic, fun_static} ->\n        cond do\n          fun_static == %{} and dynamic_fun_top?(fun_dynamic) ->\n            {:ok, dynamic()}\n\n          fun_only?(fun_static) ->\n            fun_apply_with_strategy(fun_static, fun_dynamic, arguments)\n\n          true ->\n            :badfun\n        end\n    end\n  end\n\n  defp fun_only?(descr), do: empty?(Map.delete(descr, :fun))\n  defp dynamic_fun_top?(:term), do: true\n  defp dynamic_fun_top?(%{fun: {:negation, map}}), do: map == %{}\n  defp dynamic_fun_top?(_), do: false\n\n  # Gradual function application algorithm.\n  #\n  # 1. Domain check against the extended gradual domain (see fun_normalize_both/3):\n  #    - If the argument is a subtype of the domain, proceed to application.\n  #    - Otherwise, in gradual mode, check compatibility (see below). If\n  #      compatible, the application may succeed at runtime but we have no\n  #      static information about the result, so we return dynamic().\n  #    - Otherwise, error.\n  # 2. Compute the application result in three cases:\n  #    - Fully static: apply static arrows to the arguments directly.\n  #    - Purely dynamic function (no static arrows): wrap the result of\n  #      applying dynamic arrows to upper-bounded arguments in dynamic().\n  #    - Mixed: union the static result with the dynamic-wrapped dynamic result.\n  defp fun_apply_with_strategy(fun_static, fun_dynamic, arguments) do\n    args_domain = args_to_domain(arguments)\n    static? = fun_dynamic == nil and Enum.all?(arguments, fn arg -> not gradual?(arg) end)\n    arity = length(arguments)\n\n    with {:ok, domain, static_arrows, dynamic_arrows} <-\n           fun_normalize_both(fun_static, fun_dynamic, arity) do\n      cond do\n        Enum.any?(arguments, &empty?/1) ->\n          {:badarg, domain_to_flat_args(domain, arity)}\n\n        # The domain here is the extended gradual domain computed by\n        # fun_normalize_both/3. If the argument does not satisfy it, we\n        # check compatibility before rejecting.\n        #\n        # Compatibility has two cases to avoid a degenerate situation.\n        # If the argument is purely dynamic (e.g. dynamic() and bool()),\n        # its static part (lower bound) is none(). We do not want\n        # none() <= domain to trivially succeed, because that would mean\n        # \"a diverging argument is accepted by any function\", which is true but\n        # useless. So when the static part is empty, we instead check\n        # that the upper bound overlaps with the domain. When the static\n        # part is non-empty, we check it is a subtype of the domain.\n        not subtype?(args_domain, domain) ->\n          if static? or not compatible?(args_domain, domain),\n            do: {:badarg, domain_to_flat_args(domain, arity)},\n            else: {:ok, dynamic()}\n\n        static? ->\n          {:ok, fun_apply_static(arguments, static_arrows)}\n\n        static_arrows == [] ->\n          # Purely dynamic function (e.g. dynamic() and (integer() -> integer())).\n          # There are no static arrows, so the general mixed formula simplifies:\n          # applying none() to anything yields none(), so the static branch\n          # vanishes and only the dynamic branch remains.\n          # The result is wrapped in dynamic(), so it is safe regardless of argument precision.\n          # If the upper-bounded arguments escape the domain, fun_apply_static returns term(),\n          # and dynamic(term()) = dynamic(), which brings back to the compatible case.\n          arguments = Enum.map(arguments, &upper_bound/1)\n          {:ok, dynamic(fun_apply_static(arguments, dynamic_arrows))}\n\n        true ->\n          # Mixed case: union of the static and dynamic results.\n          # static_arrows (lower materialization) contain only arrows that are\n          # guaranteed to exist at runtime. Static guarantees about the result\n          # come from these alone.\n          # dynamic_arrows (upper materialization) include dynamically uncertain\n          # arrows, so their result is wrapped in dynamic().\n          # We use upper_bound on the arguments for both branches. This is sound\n          # because the dynamic branch wraps its result in dynamic().\n          # It is more strict and informative than using lower_bound in the static part,\n          # as it amounts to assuming the worst case of using the statically present arrows.\n          arguments = Enum.map(arguments, &upper_bound/1)\n\n          {:ok,\n           union(\n             fun_apply_static(arguments, static_arrows),\n             dynamic(fun_apply_static(arguments, dynamic_arrows))\n           )}\n      end\n    end\n  end\n\n  # Normalizes a gradual function type into static and dynamic arrow\n  # components, and computes the extended gradual domain.\n  #\n  # The extended gradual domain is:\n  #   dom(upper_bound and fun_top) or dynamic(dom(lower_bound))\n  #\n  # fun_normalize/3 implicitly performs the \"and fun_top\" projection\n  # because it only looks at the :fun component, so any non-function\n  # parts of the type are automatically discarded.\n  #\n  # Fallback cases:\n  #\n  # - Static normalization succeeds but dynamic fails (e.g. the dynamic\n  #   part has no arrows at the given arity): we discard the dynamic\n  #   arrows and use the static arrows for both branches, degenerating\n  #   to the fully static case. This is sound because ignoring unusable\n  #   dynamic information cannot produce incorrect static results.\n  #\n  # - Static normalization fails (:badfun): only the dynamic arrows\n  #   contribute. The domain becomes dom(upper_bound) or dynamic(),\n  #   reflecting that the lower bound has no function type at this arity.\n  #   The application proceeds as purely dynamic (static_arrows = []).\n  defp fun_normalize_both(fun_static, fun_dynamic, arity) do\n    case fun_normalize(fun_static, arity) do\n      {:ok, static_domain, static_arrows} ->\n        # A static function with arrows at other arities is a mixed-arity union:\n        # we cannot safely apply it because at runtime the value may have a\n        # different arity than the one being called with.\n        case fun_other_non_empty_arities(fun_static, arity) do\n          [] when fun_dynamic == nil ->\n            {:ok, static_domain, static_arrows, static_arrows}\n\n          [] ->\n            case fun_normalize(fun_dynamic, arity) do\n              {:ok, dynamic_domain, dynamic_arrows} ->\n                domain = union(dynamic_domain, dynamic(static_domain))\n                {:ok, domain, static_arrows, dynamic_arrows}\n\n              _ ->\n                # Dynamic normalization failed: fall back to static-only.\n                {:ok, static_domain, static_arrows, static_arrows}\n            end\n\n          other ->\n            {:badarity, [arity | other]}\n        end\n\n      :badfun ->\n        # No static arrows: dynamic-only path. Mixed-arity in the dynamic\n        # component is fine — we pick the matching-arity arrows and the\n        # result is wrapped in dynamic(), reflecting the uncertainty.\n        case fun_normalize(fun_dynamic, arity) do\n          {:ok, dynamic_domain, dynamic_arrows} ->\n            {:ok, union(dynamic_domain, dynamic()), [], dynamic_arrows}\n\n          error ->\n            error\n        end\n\n      error ->\n        error\n    end\n  end\n\n  defp fun_other_non_empty_arities(%{fun: {:union, bdds}}, arity) do\n    case :maps.take(arity, bdds) do\n      {_bdd, rest} ->\n        for {a, b} <- rest,\n            not Enum.all?(bdd_to_dnf(b), fn {pos, neg} -> fun_line_empty?(pos, neg) end),\n            do: a\n\n      :error ->\n        []\n    end\n  end\n\n  defp fun_other_non_empty_arities(_, _), do: []\n\n  # Transforms a binary decision diagram (BDD) into the canonical `domain-arrows` pair:\n  #\n  # 1. **domain**: The union of all domains from positive functions in the BDD\n  # 2. **arrows**: List of lists, where each inner list contains an intersection of function arrows\n  #\n  # ## Return Values\n  #\n  # - `{:ok, domain, arrows}` for valid function BDDs\n  # - `{:badarity, supported_arities}` if the given arity is not supported\n  # - `:badfun` if the BDD represents an empty function type\n  #\n  # ## Internal Use\n  #\n  # This function is used internally by `fun_apply_*`, and others to\n  # ensure consistent handling of function types in all operations.\n  defp fun_normalize(:term, arity), do: fun_normalize(fun(arity), arity)\n\n  # In that case, we transform the {:negation, _} into a single union\n  # where we add the previous negatives into the specified arity.\n  defp fun_normalize(%{fun: {:negation, _}} = neg_fun, arity) do\n    fun_normalize(intersection(fun(arity), neg_fun), arity)\n  end\n\n  defp fun_normalize(%{fun: {:union, bdds}}, arity) do\n    case :maps.take(arity, bdds) do\n      {bdd, _rest} ->\n        {domain, arrows} =\n          Enum.reduce(fun_bdd_to_pos_dnf(arity, bdd), {term(), []}, fn pos_funs,\n                                                                       {domain, arrows} ->\n            {intersection(domain, fetch_domain(pos_funs)), [pos_funs | arrows]}\n          end)\n\n        if arrows == [] do\n          {:badarity, :maps.keys(bdds)}\n        else\n          {:ok, domain, arrows}\n        end\n\n      :error ->\n        {:badarity, :maps.keys(bdds)}\n    end\n  end\n\n  defp fun_normalize(%{}, _arity), do: :badfun\n\n  # Applies a static function type to arguments by reducing over the\n  # function's DNF clauses. Each clause is an intersection of arrows,\n  # processed by aux_apply/4 with rets_reached initialized to term().\n  #\n  # When the arguments are within the domain, this is the standard\n  # application operator. When the arguments escape the domain, the\n  # result is term() (see aux_apply/4).\n  defp fun_apply_static(arguments, arrows) do\n    type_args = args_to_domain(arguments)\n\n    Enum.reduce(arrows, none(), fn intersection_of_arrows, acc ->\n      aux_apply(acc, type_args, term(), intersection_of_arrows)\n    end)\n  end\n\n  # A fast way to do function application when the arguments of the function are disjoint.\n  # Just build the union of all the return types of arrows that match the input.\n  defp apply_disjoint(input_arguments, arrows) do\n    type_input = args_to_domain(input_arguments)\n\n    Enum.reduce(arrows, none(), fn {args, ret}, acc_return ->\n      if empty?(intersection(args_to_domain(args), type_input)),\n        do: acc_return,\n        else: union(acc_return, ret)\n    end)\n  end\n\n  # Helper function for function application that handles the application of\n  # function arrows to input types.\n\n  # This function recursively processes a list of function arrows (an intersection),\n  # applying each arrow to the input type and accumulating the result.\n\n  # ## Parameters\n\n  # - result: The accumulated result type so far\n  # - input: The input type being applied to the function\n  # - rets_reached: The intersection of return types reached so far\n  # - arrow_intersections: The list of function arrows to process\n  #\n  # Domain escape: if the input is not covered by the union of all the\n  # arrow domains in the clause, the result is term(). This is because\n  # rets_reached starts at term() and is only refined (intersected) when\n  # an arrow's domain covers the input, which is check by dom_subtract.\n  # Along a path where no arrow covers the input, rets_reached stays\n  # term() and gets unioned into the result at the base case. Since\n  # term() is maximal, the overall result for that clause is term().\n\n  # For more details, see Definitions 2.20 or 6.11 in https://vlanvin.fr/papers/thesis.pdf\n  # For the escape case, see Section 13.2 of\n  # https://gldubc.github.io/assets/duboc-phd-thesis-typing-elixir.pdf\n  defp aux_apply(result, _input, rets_reached, []) do\n    if subtype?(rets_reached, result), do: result, else: union(result, rets_reached)\n  end\n\n  defp aux_apply(result, input, returns_reached, [{args, ret} | arrow_intersections]) do\n    # Calculate the part of the input not covered by this arrow's domain\n    dom_subtract = difference(input, args_to_domain(args))\n\n    # Refine the return type by intersecting with this arrow's return type\n    ret_refine = intersection(returns_reached, ret)\n\n    # Phase 1: Domain partitioning\n    # If the input is not fully covered by the arrow's domain, then the result type should be\n    # _augmented_ with the outputs obtained by applying the remaining arrows to the non-covered\n    # parts of the domain.\n    #\n    # e.g. (integer()->atom()) and (float()->pid()) when applied to number() should unite\n    # both atoms and pids in the result.\n    result =\n      if empty?(dom_subtract),\n        do: result,\n        else: aux_apply(result, dom_subtract, returns_reached, arrow_intersections)\n\n    # 2. Return type refinement\n    # The result type is also refined (intersected) in the sense that, if several arrows match\n    # the same part of the input, then the result type is an intersection of the return types of\n    # those arrows.\n\n    # e.g. (integer()->atom()) and (integer()->pid()) when applied to integer()\n    # should result in (atom() ∩ pid()), which is none().\n    aux_apply(result, input, ret_refine, arrow_intersections)\n  end\n\n  # Takes all the paths from the root to the leaves finishing with a 1,\n  # and compile into tuples of positive and negative nodes. Positive nodes are\n  # those followed by a left path, negative nodes are those followed by a right path.\n  defp fun_bdd_to_dnf(bdd),\n    do: bdd_to_dnf(bdd) |> Enum.filter(fn {pos, neg} -> not fun_line_empty?(pos, neg) end)\n\n  # Check if all functions types for all arities are empty.\n  defp fun_empty?({:negation, _}), do: false\n\n  defp fun_empty?({:union, repr}) do\n    Enum.all?(repr, fn {_ar, bdd} ->\n      Enum.all?(bdd_to_dnf(bdd), fn {pos, neg} -> fun_line_empty?(pos, neg) end)\n    end)\n  end\n\n  # A function type {positives, negatives} is empty if there exists a negative\n  # function that negates the whole positive intersection\n  #\n  ## Examples\n  #\n  # - `{[fun(1)], []}` is not empty\n  # - `{[fun(integer() -> atom())], [fun(none() -> term())]}` is empty\n  defp fun_line_empty?([], _), do: false\n\n  defp fun_line_empty?(positives, negatives) do\n    # Check if any negative function negates the whole positive intersection\n    # e.g. (integer() -> atom()) is negated by:\n    #\n    # * (none() -> term())\n    # * (none() -> atom())\n    # * (integer() -> term())\n    # * (integer() -> atom())\n    Enum.any?(negatives, fn {neg_arguments, neg_return} ->\n      # Check if the negative function's domain is a supertype of the positive\n      # domain and if the phi function determines emptiness.\n      subtype?(args_to_domain(neg_arguments), fetch_domain(positives)) and\n        phi_starter(neg_arguments, neg_return, positives)\n    end)\n  end\n\n  # Returns the union of all domains of the arrows in the intersection of positives.\n  defp fetch_domain(positives) do\n    Enum.reduce(positives, none(), fn {args, _}, acc -> union(acc, args_to_domain(args)) end)\n  end\n\n  # Implements the Φ (phi) function for determining function subtyping relationships.\n  #\n  # ## Algorithm\n  #\n  # For inputs t₁...tₙ, booleans b₁...bₙ, negated return type t, and set of arrow types P:\n  #\n  # Φ((b₁,t₁)...(bₙ,tₙ), (b,t), ∅) = (∃j ∈ [1,n]. bⱼ and tⱼ ≤ ∅) ∨ (b and t ≤ ∅)\n  #\n  # Φ((b₁,t₁)...(bₙ,tₙ), t, {(t'₁...t'ₙ) → t'} ∪ P) =\n  #       Φ((b₁,t₁)...(bₙ,tₙ), (true,t ∧ t'), P) ∧\n  #         ∀j ∈ [1,n]. Φ((b₁,t₁)...(true,tⱼ∖t'ⱼ)...(bₙ,tₙ), (b,t), P)\n  #\n  # Returns true if the intersection of the positives is a subtype of (t1,...,tn)->(not t).\n  #\n  # See [Castagna and Lanvin (2024)](https://arxiv.org/abs/2408.14345), Theorem 4.2.\n  defp phi_starter(arguments, return, positives) do\n    # Optimization: When all positive functions have non-empty domains,\n    # we can simplify the phi function check to a direct subtyping test.\n    # This avoids the expensive recursive phi computation by checking only that applying the\n    # input to the positive intersection yields a subtype of the return\n    case disjoint_non_empty_domains?({arguments, return}, positives) do\n      :disjoint_non_empty ->\n        apply_disjoint(arguments, positives) |> subtype?(return)\n\n      :non_empty ->\n        fun_apply_static(arguments, [positives]) |> subtype?(return)\n\n      _ ->\n        # Initialize memoization cache for the recursive phi computation\n        arguments = Enum.map(arguments, &{false, &1})\n        {result, _cache} = phi(arguments, {false, negation(return)}, positives, %{})\n        result\n    end\n  end\n\n  defp phi(args, {b, t}, [], cache) do\n    result = Enum.any?(args, fn {bool, typ} -> bool and empty?(typ) end) or (b and empty?(t))\n    {result, Map.put(cache, {args, {b, t}, []}, result)}\n  end\n\n  defp phi(args, {b, ret}, [{arguments, return} | rest_positive], cache) do\n    # Create cache key from function arguments\n    cache_key = {args, {b, ret}, [{arguments, return} | rest_positive]}\n\n    case cache do\n      %{^cache_key => value} ->\n        {value, cache}\n\n      %{} ->\n        # Compute result and cache it\n        {result1, cache} = phi(args, {true, intersection(ret, return)}, rest_positive, cache)\n\n        if not result1 do\n          cache = Map.put(cache, cache_key, false)\n          {false, cache}\n        else\n          {_index, result2, cache} =\n            Enum.reduce_while(arguments, {0, true, cache}, fn\n              type, {index, acc_result, acc_cache} ->\n                {new_result, new_cache} =\n                  args\n                  |> List.update_at(index, fn {_, arg} -> {true, difference(arg, type)} end)\n                  |> phi({b, ret}, rest_positive, acc_cache)\n\n                if new_result do\n                  {:cont, {index + 1, acc_result and new_result, new_cache}}\n                else\n                  {:halt, {index + 1, false, new_cache}}\n                end\n            end)\n\n          result = result1 and result2\n          cache = Map.put(cache, cache_key, result)\n          {result, cache}\n        end\n    end\n  end\n\n  defp disjoint_non_empty_domains?({arguments, return}, positives) do\n    b1 = all_disjoint_arguments?(positives)\n    b2 = all_non_empty_arguments?([{arguments, return} | positives])\n\n    cond do\n      b1 and b2 -> :disjoint_non_empty\n      b2 -> :non_empty\n      true -> nil\n    end\n  end\n\n  defp all_non_empty_arguments?(positives) do\n    Enum.all?(positives, fn {args, _ret} ->\n      Enum.all?(args, fn arg -> not empty?(arg) end)\n    end)\n  end\n\n  # For two arguments to be disjoint, one of their types must be disjoint.\n  defp disjoint_arguments?(args1, args2) do\n    Enum.any?(Enum.zip(args1, args2), fn {t1, t2} -> disjoint?(t1, t2) end)\n  end\n\n  defp all_disjoint_arguments?([]), do: true\n\n  defp all_disjoint_arguments?([{args, _} | rest]) do\n    Enum.all?(rest, fn {args_rest, _} -> disjoint_arguments?(args, args_rest) end) and\n      all_disjoint_arguments?(rest)\n  end\n\n  # For all integers keys in fun_repr1, fun_repr2, call fun_bdd_union on the values that are in\n  # both, else return the single value.\n  defp fun_union({tag1, repr1}, {tag2, repr2}) do\n    case {tag1, tag2} do\n      {:union, :union} -> {:union, fun_repr_union(repr1, repr2)}\n      {:negation, :negation} -> {:negation, fun_repr_intersection(repr1, repr2)}\n      {:union, :negation} -> {:negation, fun_repr_difference(repr2, repr1)}\n      {:negation, :union} -> {:negation, fun_repr_difference(repr1, repr2)}\n    end\n  end\n\n  # For all integer keys that are both in fun_repr1 and fun_repr2, call fun_bdd_intersection\n  # on the values that are in both, else discard.\n  defp fun_intersection({tag1, repr1}, {tag2, repr2}) do\n    {tag, repr} =\n      case {tag1, tag2} do\n        {:union, :union} -> {:union, fun_repr_intersection(repr1, repr2)}\n        {:negation, :negation} -> {:negation, fun_repr_union(repr1, repr2)}\n        {:union, :negation} -> {:union, fun_repr_difference(repr1, repr2)}\n        {:negation, :union} -> {:union, fun_repr_difference(repr2, repr1)}\n      end\n\n    if tag == :union and map_size(repr) == 0, do: 0, else: {tag, repr}\n  end\n\n  defp fun_difference({tag1, repr1}, {tag2, repr2}) do\n    {tag, repr} =\n      case {tag1, tag2} do\n        {:union, :union} -> {:union, fun_repr_difference(repr1, repr2)}\n        {:negation, :negation} -> {:union, fun_repr_difference(repr2, repr1)}\n        {:union, :negation} -> {:union, fun_repr_intersection(repr1, repr2)}\n        {:negation, :union} -> {:negation, fun_repr_union(repr1, repr2)}\n      end\n\n    if tag == :union and map_size(repr) == 0, do: 0, else: {tag, repr}\n  end\n\n  defp fun_repr_union(repr1, repr2) do\n    symmetrical_merge(repr1, repr2, fn _arity, v1, v2 -> bdd_union(v1, v2) end)\n  end\n\n  defp fun_repr_intersection(repr1, repr2) do\n    symmetrical_intersection(repr1, repr2, fn _arity, v1, v2 -> bdd_intersection(v1, v2) end)\n  end\n\n  defp fun_repr_difference(repr1, repr2) do\n    :maps.fold(\n      fn arity, bdd2, acc ->\n        case acc do\n          %{^arity => bdd1} ->\n            diff = bdd_difference(bdd1, bdd2)\n            if diff in @empty_difference, do: Map.delete(acc, arity), else: %{acc | arity => diff}\n\n          %{} ->\n            acc\n        end\n      end,\n      repr1,\n      repr2\n    )\n  end\n\n  # Converts the static and dynamic parts of descr to its quoted\n  # representation. The goal here is to do the opposite of fun_descr\n  # and put static and dynamic parts back together to improve\n  # pretty printing.\n  defp fun_denormalize(%{fun: {:union, static_repr}}, %{fun: {:union, dynamic_repr}}, opts) do\n    # Denormalize each arity\n    for {arity, static_bdd} <- static_repr,\n        {^arity, dynamic_bdd} <- dynamic_repr,\n        reduce: {static_repr, dynamic_repr, []} do\n      {statics, dynamics, acc} ->\n        with {:ok, quoted} <- fun_denormalize_arity(arity, static_bdd, dynamic_bdd, opts) do\n          {Map.delete(statics, arity), Map.delete(dynamics, arity), [quoted | acc]}\n        else\n          _ -> {statics, dynamics, acc}\n        end\n    end\n  end\n\n  # If not unions of functions, do not try to denormalize.\n  defp fun_denormalize(static_repr, dynamic_repr, _opts) do\n    {static_repr, dynamic_repr, []}\n  end\n\n  defp fun_denormalize_arity(arity, static_bdd, dynamic_bdd, opts) do\n    static_pos = fun_bdd_to_pos_dnf(arity, static_bdd)\n    dynamic_pos = fun_bdd_to_pos_dnf(arity, dynamic_bdd)\n\n    cond do\n      static_pos == [] or dynamic_pos == [] ->\n        :error\n\n      true ->\n        {static_pos, dynamic_pos} = fun_denormalize_pos(static_pos, dynamic_pos)\n\n        quoted =\n          case dynamic_pos do\n            [] ->\n              fun_pos_to_quoted(static_pos, opts)\n\n            _ ->\n              {:or, [],\n               [\n                 {:dynamic, [], [fun_pos_to_quoted(dynamic_pos, opts)]},\n                 fun_pos_to_quoted(static_pos, opts)\n               ]}\n          end\n\n        {:ok, quoted}\n    end\n  end\n\n  defp fun_denormalize_pos(static_unions, dynamic_unions) do\n    Enum.map_reduce(static_unions, dynamic_unions, fn\n      # Handle fun() types accordingly\n      [], dynamic_unions ->\n        {[], List.delete(dynamic_unions, [])}\n\n      static_intersections, dynamic_unions ->\n        case pivot(dynamic_unions, [], &fun_denormalize_intersections(static_intersections, &1)) do\n          {match, dynamic_unions} -> {match, dynamic_unions}\n          :error -> {static_intersections, dynamic_unions}\n        end\n    end)\n  end\n\n  defp fun_denormalize_intersections(statics, dynamics) do\n    if length(statics) == length(dynamics) do\n      fun_denormalize_intersections(statics, dynamics, [])\n    else\n      :error\n    end\n  end\n\n  defp fun_denormalize_intersections([{static_args, static_return} | statics], dynamics, acc) do\n    dynamics\n    |> Enum.split_while(fn {dynamic_args, dynamic_return} ->\n      not arrow_subtype?(static_args, static_return, dynamic_args, dynamic_return)\n    end)\n    |> case do\n      {_dynamics, []} ->\n        :error\n\n      {pre, [{dynamic_args, dynamic_return} | post]} ->\n        args =\n          Enum.zip_with(static_args, dynamic_args, fn static_arg, dynamic_arg ->\n            union(dynamic(static_arg), dynamic_arg)\n          end)\n\n        return = union(dynamic(dynamic_return), static_return)\n        fun_denormalize_intersections(statics, pre ++ post, [{args, return} | acc])\n    end\n  end\n\n  defp fun_denormalize_intersections([], [], acc), do: {:ok, acc}\n\n  defp arrow_subtype?(left_args, left_return, right_args, right_return) do\n    subtype?(left_return, right_return) and args_subtype?(right_args, left_args)\n  end\n\n  defp args_subtype?(left_args, right_args) do\n    Enum.zip_reduce(left_args, right_args, true, fn left, right, acc ->\n      acc and subtype?(left, right)\n    end)\n  end\n\n  defp pivot([head | tail], acc, fun) do\n    case fun.(head) do\n      {:ok, value} -> {value, acc ++ tail}\n      :error -> pivot(tail, [head | acc], fun)\n    end\n  end\n\n  defp pivot([], _acc, _fun), do: :error\n\n  # Converts a function BDD (Binary Decision Diagram) to its quoted representation\n  defp fun_to_quoted({:negation, bdds}, opts) do\n    case fun_to_quoted({:union, bdds}, opts) do\n      [] ->\n        [{:fun, [], []}]\n\n      parts ->\n        ors = Enum.reduce(parts, &{:or, [], [&2, &1]})\n        [{:and, [], [{:fun, [], []}, {:not, [], [ors]}]}]\n    end\n  end\n\n  defp fun_to_quoted({:union, bdds}, opts) do\n    for {arity, bdd} <- bdds,\n        pos = fun_bdd_to_pos_dnf(arity, bdd),\n        pos != [],\n        do: fun_pos_to_quoted(pos, opts)\n  end\n\n  defp fun_bdd_to_pos_dnf(arity, :bdd_top) do\n    args = List.duplicate(none(), arity)\n    ret = term()\n    [[{args, ret}]]\n  end\n\n  defp fun_bdd_to_pos_dnf(_arity, bdd) do\n    fun_bdd_to_dnf(bdd)\n    |> Enum.map(fn {pos, _negs} -> pos end)\n    |> fun_eliminate_unions([])\n  end\n\n  defp fun_eliminate_unions([], acc), do: acc\n\n  defp fun_eliminate_unions([[{args, return}] | tail], acc) do\n    # If another arrow is a superset of the current one, we skip it\n    superset = fn\n      [{other_args, other_return}] ->\n        arrow_subtype?(args, return, other_args, other_return)\n\n      _ ->\n        false\n    end\n\n    if Enum.any?(tail, superset) or Enum.any?(acc, superset) do\n      fun_eliminate_unions(tail, acc)\n    else\n      fun_eliminate_unions(tail, [[{args, return}] | acc])\n    end\n  end\n\n  defp fun_eliminate_unions([head | tail], acc) do\n    fun_eliminate_unions(tail, [head | acc])\n  end\n\n  defp fun_pos_to_quoted([_ | _] = pos, opts) do\n    opts = Keyword.put(opts, :skip_dynamic_for_indivisible, false)\n\n    pos\n    |> Enum.sort()\n    |> Enum.map(&fun_intersection_to_quoted(&1, opts))\n    |> Enum.reduce(&{:or, [], [&2, &1]})\n  end\n\n  defp fun_intersection_to_quoted(intersection, opts) do\n    intersection\n    |> Enum.sort()\n    |> Enum.map(fn {args, ret} ->\n      {:__block__, [],\n       [[{:->, [], [Enum.map(args, &to_quoted(&1, opts)), to_quoted(ret, opts)]}]]}\n    end)\n    |> case do\n      [] -> {:fun, [], []}\n      multiple -> Enum.reduce(multiple, &{:and, [], [&2, &1]})\n    end\n  end\n\n  ## List\n\n  # Represents list and improper list simultaneously as a BDD with nodes of the form\n  # `{list_type, last_type}`, where `list_type` is the type of elements in the list,\n  # and `last_type` is the type of the last element (so `[]` if the list is proper,\n  # and anything else but a list if the list is improper).\n\n  # The last_type may be stored as `:term` for optimization purposes. This is ok\n  # because operations like `tl` effectively return the list itself plus the union of\n  # the tail (and if the tail includes the list itself, they are equivalent). And, for other\n  # operations like difference, we expand the tail_type back into\n  # `not non_empty_list()` via `list_tail_unfold/1`. Overall, this simplifies\n  # the code because we don't need to special case `not non_empty_list()`.\n  #\n  # none() types can be given and, while stored, it means the list type is empty.\n  defp list_descr(list_type, last_type, empty?) do\n    {list_dynamic?, list_type} = list_pop_dynamic(list_type)\n    {last_dynamic?, last_type} = list_pop_dynamic(last_type)\n\n    list_part =\n      if last_type == :term do\n        list_new(:term, :term)\n      else\n        case :maps.take(:list, last_type) do\n          :error ->\n            list_new(list_type, last_type)\n\n          {bdd, last_type_no_list} ->\n            # `last_type` may itself represent one or more list types.\n            # Our goal is to fold those list types into `list_type` while retaining the\n            # possible type of the final element (which can be `[]` or any non-list value).\n            #\n            # The list types inside `last_type` are stored in a BDD that includes possible\n            # negations, so we must evaluate each node with its sign taken into account.\n            #\n            # A negation only matters when the negated list type is a supertype of the\n            # corresponding positive list type; in that case we subtract the negated\n            # variant from the positive one. This is done in list_bdd_to_pos_dnf/1.\n            {list_type, last_type} =\n              list_bdd_to_pos_dnf(bdd)\n              |> Enum.reduce({list_type, last_type_no_list}, fn\n                {list, last, _negs}, {acc_list, acc_last} ->\n                  {union(list, acc_list), union(last, acc_last)}\n              end)\n\n            list_new(list_type, last_type)\n        end\n      end\n\n    list_descr =\n      if empty?, do: %{list: list_part, bitmap: @bit_empty_list}, else: %{list: list_part}\n\n    case list_dynamic? or last_dynamic? do\n      true -> %{dynamic: list_descr}\n      false -> list_descr\n    end\n  end\n\n  defp list_new(list_type, last_type), do: bdd_leaf(list_type, last_type)\n\n  defp non_empty_list_literals_intersection(list_literals) do\n    try do\n      Enum.reduce(list_literals, {:term, :term}, fn {next_list, next_last}, {list, last} ->\n        {non_empty_intersection!(list, next_list), non_empty_intersection!(last, next_last)}\n      end)\n    catch\n      :empty -> :empty\n    end\n  end\n\n  # Takes all the lines from the root to the leaves finishing with a 1,\n  # and compile into tuples of positive and negative nodes. Keep only the non-empty positives,\n  # and include the impact of negations on the last type.\n  # To see if a negation changes the last type or the list type, we just need to check\n  # if the negative list type is a supertype of the positive list type. In that case,\n  # we can remove the negative last type from the positive one.\n\n  # (If this subtracted type was empty, the whole type would be empty)\n  defp list_bdd_to_pos_dnf(bdd) do\n    bdd_to_dnf(bdd)\n    |> Enum.reduce([], fn {pos_list, negs}, acc ->\n      case non_empty_list_literals_intersection(pos_list) do\n        :empty ->\n          acc\n\n        {list, last} ->\n          Enum.reduce_while(negs, {last, []}, fn {neg_type, neg_last}, {acc_last, acc_negs} ->\n            if subtype?(list, neg_type) do\n              difference = difference(acc_last, neg_last)\n              if empty?(difference), do: {:halt, nil}, else: {:cont, {difference, acc_negs}}\n            else\n              {:cont, {acc_last, [{neg_type, neg_last} | acc_negs]}}\n            end\n          end)\n          |> case do\n            nil -> acc\n            {last, negs} -> [{list, last, Enum.reverse(negs)} | acc]\n          end\n      end\n    end)\n  end\n\n  defp list_pop_dynamic(:term), do: {false, :term}\n\n  defp list_pop_dynamic(descr) do\n    case :maps.take(:dynamic, descr) do\n      :error -> {false, descr}\n      {dynamic, _} -> {true, dynamic}\n    end\n  end\n\n  defp list_tail_unfold(:term), do: @not_non_empty_list\n  defp list_tail_unfold(other), do: Map.delete(other, :list)\n\n  @compile {:inline, list_union: 2}\n  defp list_union(bdd1, bdd2), do: bdd_union(bdd1, bdd2)\n\n  defp list_top?(bdd_leaf(:term, :term)), do: true\n  defp list_top?(_), do: false\n\n  @doc \"\"\"\n  Returns the element type of a list, assuming the list is proper.\n\n  It returns a two-element tuple. The first element dictates the\n  empty list type. The second element returns the value type.\n\n      {boolean(), t() or nil}\n\n  If the value is `nil`, it means that component is missing.\n  Note `{false, nil}` is not a valid return type, instead it\n  returns `:badproperlist`.\n  \"\"\"\n  def list_of(:term), do: :badproperlist\n\n  def list_of(descr) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        with {empty_list?, value} <- list_of_static(descr) do\n          if empty?(value) and empty_list? == false do\n            :badproperlist\n          else\n            {empty_list?, value}\n          end\n        end\n\n      {dynamic, static} ->\n        with {empty_list?, static_value} <- list_of_static(static) do\n          empty_list? =\n            empty_list? or\n              match?(\n                %{bitmap: bitmap} when (bitmap &&& @bit_empty_list) != 0,\n                dynamic\n              )\n\n          dynamic_value =\n            case dynamic do\n              :term ->\n                dynamic()\n\n              %{list: bdd} ->\n                Enum.reduce(list_bdd_to_pos_dnf(bdd), none(), fn {list, last, _negs}, acc ->\n                  if last == @empty_list or subtype?(last, @empty_list) do\n                    union(acc, list)\n                  else\n                    acc\n                  end\n                end)\n\n              %{} ->\n                none()\n            end\n\n          if empty?(dynamic_value) do\n            # list_bdd_to_pos_dnf guarantees the lists actually exists,\n            # so we can match on none() rather than empty.\n            case empty_list? do\n              false -> :badproperlist\n              true -> {empty_list?, nil}\n            end\n          else\n            {empty_list?, union(static_value, dynamic(dynamic_value))}\n          end\n        end\n    end\n  end\n\n  defp list_of_static(descr) do\n    case descr do\n      %{bitmap: @bit_empty_list} ->\n        case empty?(Map.drop(descr, [:bitmap, :list])) do\n          true -> list_of_static(descr, true)\n          false -> :badproperlist\n        end\n\n      %{bitmap: _} ->\n        :badproperlist\n\n      %{} ->\n        case empty?(Map.delete(descr, :list)) do\n          true -> list_of_static(descr, false)\n          false -> :badproperlist\n        end\n    end\n  end\n\n  # A list is proper if it's either the empty list alone, or all non-empty\n  # list types have tails that are subtypes of empty list.\n  defp list_of_static(%{list: bdd}, empty_list) do\n    try do\n      result =\n        Enum.reduce(list_bdd_to_pos_dnf(bdd), none(), fn {list, last, _negs}, acc ->\n          if last == @empty_list or subtype?(last, @empty_list) do\n            union(acc, list)\n          else\n            throw(:badproperlist)\n          end\n        end)\n\n      {empty_list, result}\n    catch\n      :badproperlist -> :badproperlist\n    end\n  end\n\n  defp list_of_static(%{}, empty_list) do\n    {empty_list, none()}\n  end\n\n  defp list_intersection(bdd1, bdd2) do\n    cond do\n      list_top?(bdd1) and is_tuple(bdd2) -> bdd2\n      list_top?(bdd2) and is_tuple(bdd1) -> bdd1\n      true -> bdd_intersection(bdd1, bdd2, &list_leaf_intersection/2)\n    end\n  end\n\n  defp list_leaf_intersection(bdd_leaf(list1, last1), bdd_leaf(list2, last2)) do\n    try do\n      list = non_empty_intersection!(list1, list2)\n      last = non_empty_intersection!(last1, last2)\n      bdd_leaf(list, last)\n    catch\n      :empty -> :bdd_bot\n    end\n  end\n\n  defp list_difference(bdd_leaf(:term, :term), bdd_leaf(:term, :term)),\n    do: :bdd_bot\n\n  defp list_difference(bdd_leaf(:term, :term), bdd2),\n    do: bdd_negation(bdd2)\n\n  # Computes the difference between two BDD (Binary Decision Diagram) list types.\n  # It progressively subtracts each type in bdd2 from all types in bdd1.\n  # The algorithm handles three cases:\n  # 1. Disjoint types: keeps the original type from bdd1\n  # 2. Subtype relationship:\n  #    a) If bdd2 type is a supertype, keeps only the negations\n  #    b) If only the last type differs, subtracts it\n  # 3. Base case: adds bdd2 type to negations of bdd1 type\n  # The result may be larger than the initial bdd1, which is maintained in the accumulator.\n  defp list_difference(bdd_leaf(list1, last1) = bdd1, bdd_leaf(list2, last2) = bdd2) do\n    if subtype?(list1, list2) do\n      if subtype?(last1, last2),\n        do: :bdd_bot,\n        else: bdd_leaf(list1, difference(last1, last2))\n    else\n      bdd_difference(bdd1, bdd2, &list_leaf_difference/3)\n    end\n  end\n\n  defp list_difference(bdd1, bdd2),\n    do: bdd_difference(bdd1, bdd2, &list_leaf_difference/3)\n\n  defp list_leaf_difference(bdd_leaf(list1, last1), bdd_leaf(list2, last2), _) do\n    if disjoint?(list1, list2) or disjoint?(last1, last2) do\n      :disjoint\n    else\n      :none\n    end\n  end\n\n  defp list_empty?(@non_empty_list_top), do: false\n\n  defp list_empty?(bdd) do\n    bdd_to_dnf(bdd)\n    |> Enum.all?(fn {pos, negs} ->\n      case non_empty_list_literals_intersection(pos) do\n        :empty -> true\n        {list, last} -> list_line_empty?(list, last, negs)\n      end\n    end)\n  end\n\n  defp list_line_empty?(list_type, last_type, negs) do\n    last_type = list_tail_unfold(last_type)\n    # To make a list {list, last} empty with some negative lists:\n    # 1. Ignore negative lists which do not have a list type that is a supertype of the positive one.\n    # 2. Each of the list supertypes:\n    #     a. either completely covers the type, if its last type is a supertype of the positive one,\n    #     b. or it removes part of the last type.\n    empty?(list_type) or empty?(last_type) or\n      Enum.reduce_while(negs, last_type, fn {neg_type, neg_last}, acc_last_type ->\n        if subtype?(list_type, neg_type) do\n          d = difference(acc_last_type, neg_last)\n          if empty?(d), do: {:halt, nil}, else: {:cont, d}\n        else\n          {:cont, acc_last_type}\n        end\n      end)\n      |> is_nil()\n  end\n\n  defp non_empty_list_only?(descr), do: empty?(Map.delete(descr, :list))\n\n  @doc \"\"\"\n  Returns the head of a list.\n\n  Errors on an empty list.\n  On a non empty list of integers, it returns the first integer.\n  On a non empty list of integers, with an atom head element, it returns the atom.\n  \"\"\"\n  def list_hd(:term), do: :badnonemptylist\n\n  def list_hd(%{} = descr) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        static_value = list_hd_static(descr)\n\n        if non_empty_list_only?(descr) and not empty?(static_value) do\n          {:ok, static_value}\n        else\n          :badnonemptylist\n        end\n\n      {dynamic, static} ->\n        dynamic_value = list_hd_static(dynamic)\n\n        if non_empty_list_only?(static) and not empty?(dynamic_value) do\n          {:ok, union(dynamic(dynamic_value), list_hd_static(static))}\n        else\n          :badnonemptylist\n        end\n    end\n  end\n\n  defp list_hd_static(:term), do: :term\n\n  defp list_hd_static(%{list: bdd}) do\n    list_bdd_to_pos_dnf(bdd)\n    |> Enum.reduce(none(), fn {list, _last, _negs}, acc -> union(acc, list) end)\n  end\n\n  defp list_hd_static(%{}), do: none()\n\n  @doc \"\"\"\n  Returns the tail of a list.\n\n  For a `non_empty_list(t)`, the tail type is `list(t)`.\n  For an improper list `non_empty_list(t, s)`, the tail type is\n  `list(t, s) or s` (either the rest of the list or the terminator)\n  \"\"\"\n  def list_tl(:term), do: :badnonemptylist\n\n  def list_tl(descr) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        static_value = list_tl_static(descr)\n\n        if non_empty_list_only?(descr) and not empty?(static_value) do\n          {:ok, static_value}\n        else\n          :badnonemptylist\n        end\n\n      {dynamic, static} ->\n        dynamic_value = list_tl_static(dynamic)\n\n        if non_empty_list_only?(static) and not empty?(dynamic_value) do\n          {:ok, union(dynamic(dynamic_value), list_tl_static(static))}\n        else\n          :badnonemptylist\n        end\n    end\n  end\n\n  defp list_tl_static(:term), do: :term\n\n  defp list_tl_static(%{list: bdd} = descr) do\n    initial =\n      case descr do\n        %{bitmap: bitmap} when (bitmap &&& @bit_empty_list) != 0 ->\n          %{list: bdd, bitmap: @bit_empty_list}\n\n        %{} ->\n          %{list: bdd}\n      end\n\n    list_bdd_to_pos_dnf(bdd)\n    |> Enum.reduce(initial, fn {_list, last, _negs}, acc -> union(acc, last) end)\n  end\n\n  defp list_tl_static(%{}), do: none()\n\n  defp list_to_quoted(bdd, empty?, opts) do\n    dnf = list_normalize(bdd)\n\n    {unions, list_rendered?} =\n      dnf\n      |> Enum.reduce({[], false}, fn {list_type, last_type, negs}, {acc, list_rendered?} ->\n        {name, arguments, list_rendered?} =\n          cond do\n            subtype?(last_type, @empty_list) ->\n              name = if empty?, do: :list, else: :non_empty_list\n              {name, [to_quoted(list_type, opts)], empty?}\n\n            # Sugar: print the last type as term() if it only misses non empty lists.\n            subtype?(@not_non_empty_list, last_type) ->\n              args = [to_quoted(list_type, opts), {:term, [], []}]\n              {:non_empty_list, args, list_rendered?}\n\n            true ->\n              args = [to_quoted(list_type, opts), to_quoted(last_type, opts)]\n              {:non_empty_list, args, list_rendered?}\n          end\n\n        acc =\n          if negs == [] do\n            [{name, [], arguments} | acc]\n          else\n            negs\n            |> non_empty_map_or(fn {ty, lst} ->\n              args =\n                if subtype?(lst, @empty_list) do\n                  [to_quoted(ty, opts)]\n                else\n                  [to_quoted(ty, opts), to_quoted(lst, opts)]\n                end\n\n              {name, [], args}\n            end)\n            |> Kernel.then(\n              &[\n                {:and, [], [{name, [], arguments}, {:not, [], [&1]}]}\n                | acc\n              ]\n            )\n          end\n\n        {acc, list_rendered?}\n      end)\n\n    if empty? and not list_rendered? do\n      [{:empty_list, [], []} | unions]\n    else\n      unions\n    end\n  end\n\n  # Eliminate empty lists from the union, and redundant types (that are subtypes of others,\n  # or that can be merged with others). List_bdd_to_pos_dnf already takes into account the\n  # impact of negations on the last type.\n  defp list_normalize(bdd) do\n    list_bdd_to_pos_dnf(bdd)\n    |> Enum.reduce([], fn {list, last, negs}, acc ->\n      # Prune negations from those with empty intersections.\n      negs =\n        Enum.uniq(negs)\n        |> Enum.filter(fn {nlist, nlast} ->\n          not empty?(intersection(list, nlist)) and not empty?(intersection(last, nlast))\n        end)\n\n      add_to_list_normalize(acc, list, last, negs)\n    end)\n  end\n\n  # List of possible union merges:\n  # Case 1: when a list is a subtype of another\n  # Case 2: when two lists have the same list type, then the last types are united\n  defp add_to_list_normalize([{t, l, []} = cur | rest], list, last, []) do\n    cond do\n      subtype?(list, t) and subtype?(last, l) -> [cur | rest]\n      subtype?(t, list) and subtype?(l, last) -> [{list, last, []} | rest]\n      equal?(t, list) -> [{t, union(l, last), []} | rest]\n      true -> [cur | add_to_list_normalize(rest, list, last, [])]\n    end\n  end\n\n  # Case 3: when a list with negations is united with one of its negations\n  defp add_to_list_normalize([{t, l, n} = cur | rest], list, last, []) do\n    case pop_elem(n, {list, last}, []) do\n      {true, n1} -> [{t, l, n1} | rest]\n      {false, _} -> [cur | add_to_list_normalize(rest, list, last, n)]\n    end\n  end\n\n  defp add_to_list_normalize(rest, list, last, negs), do: [{list, last, negs} | rest]\n\n  defp pop_elem([key | t], key, acc), do: {true, :lists.reverse(acc, t)}\n  defp pop_elem([h | t], key, acc), do: pop_elem(t, key, [h | acc])\n  defp pop_elem([], _key, acc), do: {false, :lists.reverse(acc)}\n\n  ## Dynamic\n  #\n  # A type with a dynamic component is a gradual type; without, it is a static\n  # type. The dynamic component itself is a static type; hence, any gradual type\n  # can be written using a pair of static types as the union:\n  #\n  # `type = (dynamic_component and dynamic()) or static_component`\n  #\n  # where the `static_component` is simply the rest of the `descr`, and `dynamic()`\n  # is the base type that can represent any value at runtime. The dynamic and\n  # static parts can be considered separately for a mixed-typed analysis. For\n  # example, the type\n  #\n  # `type = (dynamic() and integer()) or boolean()`\n  #\n  # denotes an expression that evaluates to booleans or integers; however, there is\n  # uncertainty about the source of these integers. In static mode, the\n  # type-checker refuses to apply a function of type `boolean() -> boolean()` to\n  # this argument (since the argument may turn out to be an integer()), but in\n  # dynamic mode, it considers the type obtained by replacing `dynamic()` with\n  # `none()` (that is, `boolean()`), accepts the application, but types it with a\n  # type that contains `dynamic()`.\n  #\n  # When pattern matching on an expression of type `type`, the static part (here,\n  # booleans) has to be handled exhaustively. In contrast, the dynamic part can\n  # produce potential warnings in specific user-induced conditions, such as asking\n  # for stronger enforcement of static types.\n  #\n  # During construction and through set operations, we maintain the invariant that\n  # the dynamic component is a supertype of the static one, formally\n  # `dynamic_component >= static_component`\n  #\n  # With this invariant, the dynamic component always represents every value that\n  # a given gradual type can take at runtime, allowing us to simplify set operations,\n  # compared, for example, to keeping only the extra dynamic type that can obtained\n  # on top of the static type. Though, the latter may be used for printing purposes.\n  #\n  # There are two ways for a descr to represent a static type: either the\n  # `:dynamic` field is not_set, or it contains a type equal to the static component\n  # (that is, there are no extra dynamic values).\n\n  defp dynamic_union(:term, other), do: optional_to_term(other)\n  defp dynamic_union(other, :term), do: optional_to_term(other)\n\n  defp dynamic_union(left, right),\n    do: symmetrical_merge(unfold(left), unfold(right), &union/3)\n\n  defp dynamic_intersection(:term, other), do: remove_optional_static(other)\n  defp dynamic_intersection(other, :term), do: remove_optional_static(other)\n\n  defp dynamic_intersection(left, right),\n    do: symmetrical_intersection(unfold(left), unfold(right), &intersection/3)\n\n  defp dynamic_to_quoted(descr, opts) do\n    cond do\n      # We check for :term literally instead of using term_type?\n      # because we check for term_type? in to_quoted before we\n      # compute the difference(dynamic, static).\n      descr == :term ->\n        [{:dynamic, [], []}]\n\n      single = indivisible_bitmap(descr, opts) ->\n        [single]\n\n      empty?(descr) ->\n        []\n\n      true ->\n        case non_term_type_to_quoted(descr, opts) do\n          {:none, _meta, []} = none -> [none]\n          descr -> [{:dynamic, [], [descr]}]\n        end\n    end\n  end\n\n  defp indivisible_bitmap(descr, opts) do\n    with true <- Keyword.get(opts, :skip_dynamic_for_indivisible, true),\n         %{bitmap: bitmap} when map_size(descr) == 1 and bitmap != @bit_bitstring <- descr,\n         [single] <- bitmap_to_quoted(bitmap) do\n      single\n    else\n      _ -> nil\n    end\n  end\n\n  ## Map\n  #\n  # Maps are represented as BDDs, that is, a tree of pairs `{tag_or_domain, fields}`\n  # where `tag_or_domain` is either :closed or :open, or a map from domain keys\n  # (@domain_key_types) to types, and `fields` is a map of atom keys (:foo, :bar, ...)\n  # to types.\n  #\n  # For instance, the type `%{atom() => if_set(integer())}` is the type of maps where atom keys\n  # map to integers, without any non-atom keys. It is represented using the map literal\n  # `{%{atom: if_set(integer())}, %{}}`, with no defined keys.\n  #\n  # The type `%{..., atom() => integer()}` represents maps with atom keys bound to integers,\n  # and other keys bound to any type. It will be represented using a map domain that maps\n  # atom to `if_set(integer())`, and every other domain key to `term_or_optional()`.\n\n  @doc \"\"\"\n  Converts a type into domain keys.\n  \"\"\"\n  def to_domain_keys(:term), do: @domain_key_types\n\n  def to_domain_keys(%{dynamic: dynamic}), do: to_domain_keys(dynamic)\n\n  def to_domain_keys(key_descr) do\n    for {type_kind, type} <- key_descr, reduce: [] do\n      acc ->\n        cond do\n          type_kind == :list and\n              match?(%{bitmap: bitmap} when (bitmap &&& @bit_empty_list) != 0, key_descr) ->\n            acc\n\n          type_kind == :atom and match?({:union, _}, type) ->\n            acc\n\n          type_kind == :bitmap ->\n            bitmap_to_domain_keys(type, acc)\n\n          not empty?(%{type_kind => type}) ->\n            [type_kind | acc]\n\n          true ->\n            acc\n        end\n    end\n  end\n\n  defp bitmap_to_domain_keys(bitmap, acc) do\n    acc = if (bitmap &&& @bit_binary) != 0, do: [:binary | acc], else: acc\n    acc = if (bitmap &&& @bit_bitstring_no_binary) != 0, do: [:bitstring | acc], else: acc\n    acc = if (bitmap &&& @bit_empty_list) != 0, do: [:list | acc], else: acc\n    acc = if (bitmap &&& @bit_integer) != 0, do: [:integer | acc], else: acc\n    acc = if (bitmap &&& @bit_float) != 0, do: [:float | acc], else: acc\n    acc = if (bitmap &&& @bit_pid) != 0, do: [:pid | acc], else: acc\n    acc = if (bitmap &&& @bit_port) != 0, do: [:port | acc], else: acc\n    acc = if (bitmap &&& @bit_reference) != 0, do: [:reference | acc], else: acc\n    acc\n  end\n\n  defp domain_key_to_descr(:atom), do: atom()\n  defp domain_key_to_descr(:bitstring), do: bitstring_no_binary()\n  defp domain_key_to_descr(:binary), do: binary()\n  defp domain_key_to_descr(:integer), do: integer()\n  defp domain_key_to_descr(:float), do: float()\n  defp domain_key_to_descr(:pid), do: pid()\n  defp domain_key_to_descr(:port), do: port()\n  defp domain_key_to_descr(:reference), do: reference()\n  defp domain_key_to_descr(:fun), do: fun()\n  defp domain_key_to_descr(:tuple), do: tuple()\n  defp domain_key_to_descr(:map), do: open_map()\n  defp domain_key_to_descr(:list), do: @list_top\n\n  defp map_descr(tag, pairs) do\n    {fields, domains, dynamic?} = map_descr_pairs(pairs, [], @fields_new, false)\n\n    map_new =\n      if not is_fields_empty(domains) do\n        domains =\n          if tag == :open do\n            value = term_or_optional()\n            fields_put_all_new(domains, @domain_key_types, value)\n          else\n            domains\n          end\n\n        map_new(domains, fields)\n      else\n        map_new(tag, fields)\n      end\n\n    case dynamic? do\n      true -> %{dynamic: %{map: map_new}}\n      false -> %{map: map_new}\n    end\n  end\n\n  defp map_put_domain(domain, domain_keys, value) when is_list(domain_keys) do\n    map_put_domain(domain, :lists.usort(domain_keys), if_set(value), value)\n  end\n\n  defp map_put_domain([{k1, v1} | t1], [k2 | _] = keys, initial, value) when k1 < k2 do\n    [{k1, v1} | map_put_domain(t1, keys, initial, value)]\n  end\n\n  defp map_put_domain([{k1, v1} | t1], [k1 | keys], _initial, value) do\n    [{k1, union(v1, value)} | map_put_domain(t1, keys, if_set(value), value)]\n  end\n\n  defp map_put_domain(domain, [k2 | keys], initial, value) do\n    [{k2, initial} | map_put_domain(domain, keys, initial, value)]\n  end\n\n  defp map_put_domain(domain, [], _initial, _value), do: domain\n\n  defp map_descr_pairs([{key, :term} | rest], fields, domain, dynamic?) do\n    case is_atom(key) do\n      true -> map_descr_pairs(rest, [{key, :term} | fields], domain, dynamic?)\n      false -> map_descr_pairs(rest, fields, map_put_domain(domain, key, :term), dynamic?)\n    end\n  end\n\n  defp map_descr_pairs([{key, value} | rest], fields, domain, dynamic?) do\n    {value, dynamic?} =\n      case :maps.take(:dynamic, value) do\n        :error -> {value, dynamic?}\n        {dynamic, _static} -> {dynamic, true}\n      end\n\n    case is_atom(key) do\n      true -> map_descr_pairs(rest, [{key, value} | fields], domain, dynamic?)\n      false -> map_descr_pairs(rest, fields, map_put_domain(domain, key, value), dynamic?)\n    end\n  end\n\n  defp map_descr_pairs([], fields, domain, dynamic?) do\n    {fields_from_reverse_list(fields), domain, dynamic?}\n  end\n\n  # Gets the default type associated to atom keys in a map.\n  defp map_key_tag_to_type(:open), do: term_or_optional()\n  defp map_key_tag_to_type(:closed), do: not_set()\n  defp map_key_tag_to_type(domains), do: fields_get(domains, :atom, not_set())\n\n  # Gets the domain type association to a map.\n  # In this case, we already remove the optional to simplify upstream.\n  @compile {:inline, map_domain_tag_to_type: 1}\n  defp map_domain_tag_to_type(:open), do: term()\n  defp map_domain_tag_to_type(:closed), do: none()\n\n  defp map_domain_tag_to_type(domain, key) when is_list(domain) do\n    remove_optional(fields_get(domain, key, none()))\n  end\n\n  defp map_domain_tag_to_type(domain, _key) do\n    map_domain_tag_to_type(domain)\n  end\n\n  defguardp is_optional_static(map)\n            when is_map(map) and is_map_key(map, :optional)\n\n  defp map_new(tag, fields), do: bdd_leaf(tag, fields)\n\n  defp map_only?(descr), do: empty?(Map.delete(descr, :map))\n\n  defp non_empty_map_only?(descr) do\n    case :maps.take(:map, descr) do\n      :error -> false\n      {map_bdd, rest} -> empty?(rest) and not map_empty?(map_bdd)\n    end\n  end\n\n  defp map_union(bdd_leaf(tag1, fields1), bdd_leaf(tag2, fields2)) do\n    case maybe_optimize_map_union(tag1, fields1, tag2, fields2) do\n      {tag, fields} -> bdd_leaf(tag, fields)\n      nil -> bdd_union(bdd_leaf(tag1, fields1), bdd_leaf(tag2, fields2))\n    end\n  end\n\n  defp map_union(bdd1, bdd2), do: bdd_union(bdd1, bdd2)\n\n  defp maybe_optimize_map_union(:open, empty, _, _) when is_fields_empty(empty),\n    do: {:open, @fields_new}\n\n  defp maybe_optimize_map_union(_, _, :open, empty) when is_fields_empty(empty),\n    do: {:open, @fields_new}\n\n  defp maybe_optimize_map_union(tag1, pos1, tag2, pos2)\n       when is_atom(tag1) and is_atom(tag2) do\n    case map_union_strategy(pos1, pos2, tag1, tag2, :all_equal) do\n      :all_equal when tag1 == :open -> {tag1, pos1}\n      :all_equal -> {tag2, pos2}\n      {:one_key_difference, key, v1, v2} -> {tag1, fields_store(key, union(v1, v2), pos1)}\n      :left_subtype_of_right -> {tag2, pos2}\n      :right_subtype_of_left -> {tag1, pos1}\n      :none -> nil\n    end\n  end\n\n  defp maybe_optimize_map_union(_, _, _, _), do: nil\n\n  defp map_union_strategy([{k1, _} | t1], [{k2, _} | _] = l2, tag1, tag2, status)\n       when k1 < k2 do\n    # Left side has a key the right side does not have,\n    # left can only be a subtype if the right side is open.\n    case status do\n      _ when tag2 != :open ->\n        :none\n\n      :all_equal ->\n        map_union_strategy(t1, l2, tag1, tag2, :left_subtype_of_right)\n\n      {:one_key_difference, _, p1, p2} ->\n        if subtype?(p1, p2),\n          do: map_union_strategy(t1, l2, tag1, tag2, :left_subtype_of_right),\n          else: :none\n\n      :left_subtype_of_right ->\n        map_union_strategy(t1, l2, tag1, tag2, :left_subtype_of_right)\n\n      _ ->\n        :none\n    end\n  end\n\n  defp map_union_strategy([{k1, _} | _] = l1, [{k2, _} | t2], tag1, tag2, status)\n       when k1 > k2 do\n    # Right side has a key the left side does not have,\n    # right can only be a subtype if the left side is open.\n    case status do\n      _ when tag1 != :open ->\n        :none\n\n      :all_equal ->\n        map_union_strategy(l1, t2, tag1, tag2, :right_subtype_of_left)\n\n      {:one_key_difference, _, p1, p2} ->\n        if subtype?(p2, p1),\n          do: map_union_strategy(l1, t2, tag1, tag2, :right_subtype_of_left),\n          else: :none\n\n      :right_subtype_of_left ->\n        map_union_strategy(l1, t2, tag1, tag2, :right_subtype_of_left)\n\n      _ ->\n        :none\n    end\n  end\n\n  defp map_union_strategy([{_, v} | t1], [{_, v} | t2], tag1, tag2, status) do\n    # Same key and same value, nothing changes\n    map_union_strategy(t1, t2, tag1, tag2, status)\n  end\n\n  defp map_union_strategy([{k1, v1} | t1], [{_, v2} | t2], tag1, tag2, status) do\n    # They have the same key but different values\n    case status do\n      :all_equal ->\n        cond do\n          # Don't do difference on struct keys\n          k1 != :__struct__ and tag1 == tag2 ->\n            map_union_strategy(t1, t2, tag1, tag2, {:one_key_difference, k1, v1, v2})\n\n          subtype?(v1, v2) ->\n            map_union_strategy(t1, t2, tag1, tag2, :left_subtype_of_right)\n\n          subtype?(v2, v1) ->\n            map_union_strategy(t1, t2, tag1, tag2, :right_subtype_of_left)\n\n          true ->\n            :none\n        end\n\n      :left_subtype_of_right ->\n        if subtype?(v1, v2), do: map_union_strategy(t1, t2, tag1, tag2, status), else: :none\n\n      :right_subtype_of_left ->\n        if subtype?(v2, v1), do: map_union_strategy(t1, t2, tag1, tag2, status), else: :none\n\n      {:one_key_difference, _key, p1, p2} ->\n        cond do\n          subtype?(p1, p2) and subtype?(v1, v2) ->\n            map_union_strategy(t1, t2, tag1, tag2, :left_subtype_of_right)\n\n          subtype?(p2, p1) and subtype?(v2, v1) ->\n            map_union_strategy(t1, t2, tag1, tag2, :right_subtype_of_left)\n\n          true ->\n            :none\n        end\n\n      _ ->\n        :none\n    end\n  end\n\n  defp map_union_strategy([], [], _tag1, _tag2, status) do\n    status\n  end\n\n  defp map_union_strategy(l1, l2, tag1, tag2, status) do\n    lhs? = tag2 == :open and l2 == []\n    rhs? = tag1 == :open and l1 == []\n\n    case status do\n      :all_equal when lhs? ->\n        :left_subtype_of_right\n\n      :all_equal when rhs? ->\n        :right_subtype_of_left\n\n      {:one_key_difference, _, p1, p2} ->\n        cond do\n          lhs? and subtype?(p1, p2) -> :left_subtype_of_right\n          rhs? and subtype?(p2, p1) -> :right_subtype_of_left\n          true -> :none\n        end\n\n      :left_subtype_of_right when lhs? ->\n        :left_subtype_of_right\n\n      :right_subtype_of_left when rhs? ->\n        :right_subtype_of_left\n\n      _ ->\n        :none\n    end\n  end\n\n  defp map_intersection(bdd_leaf(:open, []), bdd), do: bdd\n  defp map_intersection(bdd, bdd_leaf(:open, [])), do: bdd\n  defp map_intersection(bdd1, bdd2), do: map_bdd_intersection(bdd1, bdd2)\n\n  # A variant of bdd_intersection/3 that only continues if the maps are closed\n  # or both sides are leafs.\n  #\n  # This is necessary because the intersection of open maps end-up accumulating\n  # fields and it is unlikely to eliminate, which would lead to explosions.\n  # However, note this optimization only works because closed nodes come first\n  # in the BDD representation. If that was not the case, open nodes would come\n  # first and this optimization would not happen if they were mixed.\n  defp map_bdd_intersection(bdd_leaf(_, _) = leaf1, bdd_leaf(_, _) = leaf2) do\n    map_leaf_intersection(leaf1, leaf2)\n  end\n\n  defp map_bdd_intersection(bdd_leaf(:closed, _) = leaf, bdd) do\n    bdd_leaf_intersection(leaf, bdd, &map_leaf_intersection/2)\n  end\n\n  defp map_bdd_intersection(bdd, bdd_leaf(:closed, _) = leaf) do\n    bdd_leaf_intersection(leaf, bdd, &map_leaf_intersection/2)\n  end\n\n  defp map_bdd_intersection({bdd_leaf(:closed, _) = leaf, :bdd_top, u, d}, bdd) do\n    bdd_leaf_intersection(leaf, bdd, &map_leaf_intersection/2)\n    |> bdd_union(map_bdd_intersection(u, bdd))\n    |> case do\n      result when d == :bdd_bot -> result\n      result -> bdd_union(result, bdd_intersection(bdd, {leaf, :bdd_bot, :bdd_bot, d}))\n    end\n  end\n\n  defp map_bdd_intersection(bdd, {bdd_leaf(:closed, _) = leaf, :bdd_top, u, d}) do\n    bdd_leaf_intersection(leaf, bdd, &map_leaf_intersection/2)\n    |> bdd_union(map_bdd_intersection(u, bdd))\n    |> case do\n      result when d == :bdd_bot -> result\n      result -> bdd_union(result, bdd_intersection(bdd, {leaf, :bdd_bot, :bdd_bot, d}))\n    end\n  end\n\n  defp map_bdd_intersection(bdd1, bdd2) do\n    bdd_intersection(bdd1, bdd2)\n  end\n\n  defp map_leaf_intersection(bdd_leaf(tag1, fields1), bdd_leaf(tag2, fields2)) do\n    try do\n      {tag, fields} = map_literal_intersection(tag1, fields1, tag2, fields2)\n      bdd_leaf(tag, fields)\n    catch\n      :empty -> :bdd_bot\n    end\n  end\n\n  defp map_difference(_, bdd_leaf(:open, [])),\n    do: :bdd_bot\n\n  defp map_difference(bdd1, bdd2),\n    do: bdd_difference(bdd1, bdd2, &map_leaf_difference/3)\n\n  # We only apply this particular optimization when comparing leafs (type == :none).\n  # Applying it in other scenarios lead to slow compilation, likely because the\n  # introduction of `a_int` and `a_union` lead to additional nodes and large rehashes\n  # of the tree.\n  #\n  # Outside of this particular scenario, the `a_int` optimization has been useful,\n  # but we haven't measured benefits for `a_union`.\n  defp map_leaf_difference(bdd_leaf(tag, fields), bdd_leaf(:open, [{key, v2}]), type) do\n    {found?, v1} =\n      case fields_find(key, fields) do\n        {:ok, value} -> {true, value}\n        :error -> {false, map_key_tag_to_type(tag)}\n      end\n\n    cond do\n      tag == :closed and not found? and not is_optional_static(v2) ->\n        :disjoint\n\n      tag == :open and not found? ->\n        # In case the left-side is open, we will only be adding new keys\n        # to the open map, which makes future eliminations harder.\n        :none\n\n      true ->\n        map_leaf_one_key_difference(tag, fields, key, v1, v2, type)\n    end\n  end\n\n  defp map_leaf_difference(bdd_leaf(tag, fields), bdd_leaf(neg_tag, neg_fields), type) do\n    case map_difference_strategy(fields, neg_fields, tag, neg_tag) do\n      :disjoint ->\n        :disjoint\n\n      :left_subtype_of_right ->\n        :subtype\n\n      {:one_key_difference, key, v1, v2} ->\n        map_leaf_one_key_difference(tag, fields, key, v1, v2, type)\n\n      :none ->\n        :none\n    end\n  end\n\n  defp map_leaf_one_key_difference(tag, fields, key, v1, v2, type) do\n    v_diff = difference(v1, v2)\n\n    if empty?(v_diff) do\n      :subtype\n    else\n      a_diff = bdd_leaf(tag, fields_store(key, v_diff, fields))\n\n      a_type =\n        case type do\n          :none ->\n            :bdd_bot\n\n          :union ->\n            bdd_leaf(tag, fields_store(key, union(v1, v2), fields))\n\n          :intersection ->\n            v_int = intersection(v1, v2)\n\n            if empty?(v_int),\n              do: :bdd_bot,\n              else: bdd_leaf(tag, fields_store(key, v_int, fields))\n        end\n\n      {:one_key_difference, a_diff, a_type}\n    end\n  end\n\n  # Intersects two map literals; throws if their intersection is empty.\n  # Both open: the result is open.\n  defp map_literal_intersection(:open, map1, :open, map2) do\n    new_fields =\n      fields_merge(\n        fn _, type1, type2 -> non_empty_intersection!(type1, type2) end,\n        map1,\n        map2\n      )\n\n    {:open, new_fields}\n  end\n\n  # Both closed: the result is closed.\n  defp map_literal_intersection(:closed, map1, :closed, map2) do\n    {:closed, map_literal_intersection_closed(map1, map2)}\n  end\n\n  # Open and closed: result is closed, all fields from open should be in closed, except not_set ones.\n  defp map_literal_intersection(:open, open, :closed, closed) do\n    {:closed, map_literal_intersection_open_closed(open, closed)}\n  end\n\n  defp map_literal_intersection(:closed, closed, :open, open) do\n    {:closed, map_literal_intersection_open_closed(open, closed)}\n  end\n\n  # At least one tag is a tag-domain pair.\n  defp map_literal_intersection(tag_or_domains1, map1, tag_or_domains2, map2) do\n    # For a closed map with domains intersected with an open map with domains:\n    # 1. The result is closed (more restrictive)\n    # 2. We need to check each domain in the open map against the closed map\n    default1 = map_key_tag_to_type(tag_or_domains1)\n    default2 = map_key_tag_to_type(tag_or_domains2)\n\n    # Compute the new domain\n    tag_or_domains = map_domain_intersection(tag_or_domains1, tag_or_domains2)\n\n    # Go over all fields in map1 and map2 with default atom types atom1 and atom2\n    # 1. If key is in both maps, compute non empty intersection (:error if it is none)\n    # 2. If key is only in map1, compute non empty intersection with atom2\n    # 3. If key is only in map2, compute non empty intersection with atom1\n    # We do that by computing intersection on all key labels in both map1 and map2,\n    # using default values when a key is not present.\n    {tag_or_domains,\n     fields_merge_with_defaults(map1, default1, map2, default2, fn _key, v1, v2 ->\n       non_empty_intersection!(v1, v2)\n     end)}\n  end\n\n  # Compute the intersection of two tags or tag-domain pairs.\n  defp map_domain_intersection(:closed, _), do: :closed\n  defp map_domain_intersection(_, :closed), do: :closed\n  defp map_domain_intersection(:open, tag_or_domains), do: tag_or_domains\n  defp map_domain_intersection(tag_or_domains, :open), do: tag_or_domains\n\n  defp map_domain_intersection(domains1, domains2) do\n    # If the explicit domains are empty, use simple atom tags\n    case map_domain_intersection_fields(domains1, domains2) do\n      [] -> :closed\n      new_domains -> new_domains\n    end\n  end\n\n  defp map_domain_intersection_fields([{k1, _} | t1], [{k2, _} | _] = l2) when k1 < k2 do\n    map_domain_intersection_fields(t1, l2)\n  end\n\n  defp map_domain_intersection_fields([{k1, _} | _] = l1, [{k2, _} | t2]) when k1 > k2 do\n    map_domain_intersection_fields(l1, t2)\n  end\n\n  defp map_domain_intersection_fields([{k, type1} | t1], [{_, type2} | t2]) do\n    inter = intersection(type1, type2)\n\n    if empty_or_optional?(inter) do\n      map_domain_intersection_fields(t1, t2)\n    else\n      [{k, inter} | map_domain_intersection_fields(t1, t2)]\n    end\n  end\n\n  defp map_domain_intersection_fields(_, _), do: []\n\n  defp map_literal_intersection_open_closed([{k1, v1} | t1], [{k2, _} | _] = l2) when k1 < k2 do\n    # If the type in the open map is optional, we continue\n    case v1 do\n      %{optional: 1} -> map_literal_intersection_open_closed(t1, l2)\n      _ -> throw(:empty)\n    end\n  end\n\n  defp map_literal_intersection_open_closed([{k1, _} | _] = l1, [{k2, v2} | t2]) when k1 > k2 do\n    # Anything in the closed map not in open is preserved\n    [{k2, v2} | map_literal_intersection_open_closed(l1, t2)]\n  end\n\n  defp map_literal_intersection_open_closed([{key, v1} | t1], [{_, v2} | t2]) do\n    [{key, non_empty_intersection!(v1, v2)} | map_literal_intersection_open_closed(t1, t2)]\n  end\n\n  defp map_literal_intersection_open_closed(t1, t2) do\n    if Enum.all?(t1, fn {_, v} -> match?(%{optional: 1}, v) end) do\n      t2\n    else\n      throw(:empty)\n    end\n  end\n\n  defp map_literal_intersection_closed([{k1, v1} | t1], [{k2, _} | _] = l2) when k1 < k2 do\n    if v1 == @not_set do\n      map_literal_intersection_closed(t1, l2)\n    else\n      throw(:empty)\n    end\n  end\n\n  defp map_literal_intersection_closed([{k1, _} | _] = l1, [{k2, v2} | t2]) when k1 > k2 do\n    if v2 == @not_set do\n      map_literal_intersection_closed(l1, t2)\n    else\n      throw(:empty)\n    end\n  end\n\n  defp map_literal_intersection_closed([{key, v1} | t1], [{_, v2} | t2]) do\n    [{key, non_empty_intersection!(v1, v2)} | map_literal_intersection_closed(t1, t2)]\n  end\n\n  defp map_literal_intersection_closed(t1, t2) do\n    if Enum.any?(t1, fn {_, v} -> v != @not_set end) or\n         Enum.any?(t2, fn {_, v} -> v != @not_set end) do\n      throw(:empty)\n    end\n\n    []\n  end\n\n  defp non_empty_intersection!(type1, type2) do\n    type = intersection(type1, type2)\n    if empty?(type), do: throw(:empty), else: type\n  end\n\n  defp map_bdd_to_dnf_remove_empty(bdd) do\n    bdd_to_dnf(bdd)\n    |> Enum.reduce([], fn {pos, negs}, acc ->\n      case non_empty_map_literals_intersection(pos) do\n        :empty ->\n          acc\n\n        {tag, fields} ->\n          if init_map_line_empty?(tag, fields, negs) do\n            acc\n          else\n            [{tag, fields, negs} | acc]\n          end\n      end\n    end)\n  end\n\n  defp map_bdd_to_dnf_with_empty(bdd) do\n    bdd_to_dnf(bdd)\n    |> Enum.reduce([], fn {pos, negs}, acc ->\n      case non_empty_map_literals_intersection(pos) do\n        :empty -> acc\n        {tag, fields} -> [{tag, fields, negs} | acc]\n      end\n    end)\n  end\n\n  ## Map key functions\n\n  @doc \"\"\"\n  Fetches the type of the value returned by accessing `key` on `map`\n  with the assumption that the descr is exclusively a map (or dynamic).\n\n  It returns a two element tuple or `:error`. The first element says\n  if the type is dynamically optional or not, the second element is\n  the type. In static mode, optional keys are not allowed.\n\n  Being dynamically optional means that the field may be present\n  (while statically optional means we need to consider the field as\n  both present and absent).\n  \"\"\"\n  def map_fetch_key(:term, _key), do: :badmap\n\n  def map_fetch_key(%{} = descr, key) when is_atom(key) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        if descr_key?(descr, :map) and non_empty_map_only?(descr) do\n          {static_optional?, static_type} = map_fetch_key_static(descr, key)\n\n          if static_optional? or empty?(static_type) do\n            :badkey\n          else\n            {false, static_type}\n          end\n        else\n          :badmap\n        end\n\n      {dynamic, static} ->\n        if descr_key?(dynamic, :map) and map_only?(static) do\n          {dynamic_optional?, dynamic_type} = map_fetch_key_static(dynamic, key)\n          {static_optional?, static_type} = map_fetch_key_static(static, key)\n\n          if static_optional? or empty?(dynamic_type) do\n            :badkey\n          else\n            {dynamic_optional?, union(dynamic(dynamic_type), static_type)}\n          end\n        else\n          :badmap\n        end\n    end\n  end\n\n  # Optimization for bdd leafs\n  defp map_fetch_key_static(%{map: bdd_leaf(tag, fields)}, key) do\n    case fields_find(key, fields) do\n      {:ok, value} -> pop_optional_static(value)\n      :error when tag == :open -> {true, term()}\n      :error when tag == :closed -> {true, none()}\n      :error -> tag |> map_key_tag_to_type() |> pop_optional_static()\n    end\n  end\n\n  defp map_fetch_key_static(%{map: bdd}, key) do\n    bdd |> map_bdd_to_dnf_with_empty() |> map_dnf_fetch_static(key)\n  end\n\n  defp map_fetch_key_static(%{}, _key), do: {false, none()}\n  defp map_fetch_key_static(:term, _key), do: {true, term()}\n\n  # Takes a map DNF and returns the union of types it can take for a given key.\n  # If the key may be undefined, it will contain the `not_set()` type.\n  defp map_dnf_fetch_static(dnf, key) do\n    Enum.reduce(dnf, none(), fn\n      # Optimization: if there are no negatives\n      {tag, fields, []}, acc ->\n        case fields_find(key, fields) do\n          {:ok, value} -> union(value, acc)\n          :error when tag == :open -> throw(:open)\n          :error -> map_key_tag_to_type(tag) |> union(acc)\n        end\n\n      {tag, fields, negs}, acc ->\n        {value, bdd} = map_pop_key_bdd(tag, fields, key)\n\n        negs\n        |> map_split_negative_key(key, value, bdd)\n        |> Enum.reduce(acc, fn {value, _}, acc -> union(value, acc) end)\n    end)\n  catch\n    :open -> {true, term()}\n  else\n    value ->\n      pop_optional_static(value)\n  end\n\n  defp map_split_negative_key(negs, key, value, bdd) do\n    map_split_negative(negs, value, bdd, fn neg_tag, neg_fields ->\n      case fields_take(key, neg_fields) do\n        {neg_value, neg_fields} -> {true, neg_value, map_new(neg_tag, neg_fields)}\n        :error -> {false, map_key_tag_to_type(neg_tag), map_new(neg_tag, neg_fields)}\n      end\n    end)\n  end\n\n  # Remove negatives:\n  # {t, s} \\ {t₁, s₁} = {t \\ t₁, s} ∪ {t ∩ t₁, s \\ s₁}\n  defp map_split_negative(negs, value, bdd, take_fun) do\n    Enum.reduce(negs, [{value, bdd}], fn\n      {:open, empty}, _acc when is_fields_empty(empty) ->\n        throw(:empty)\n\n      {neg_tag, neg_fields}, acc ->\n        {found?, neg_value, neg_bdd} = take_fun.(neg_tag, neg_fields)\n\n        if not found? and neg_tag == :open do\n          # In case the map is open, t \\ t₁ is always empty,\n          # t ∩ t₁ is always t, so we just need to deal with the bdd.\n          Enum.reduce(acc, [], fn {value, bdd}, acc ->\n            diff_bdd = map_difference(bdd, neg_bdd)\n\n            if map_empty?(diff_bdd) do\n              acc\n            else\n              [{value, diff_bdd} | acc]\n            end\n          end)\n        else\n          Enum.reduce(acc, [], fn {value, bdd}, acc ->\n            # If the negative tag is closed, then they are likely disjoint,\n            # so we can drastically cut down the amount of operations.\n            if neg_tag == :closed and map_empty?(map_intersection(bdd, neg_bdd)) do\n              [{value, bdd} | acc]\n            else\n              intersection_value = intersection(value, neg_value)\n\n              if empty?(intersection_value) do\n                [{value, bdd} | acc]\n              else\n                diff_bdd = map_difference(bdd, neg_bdd)\n\n                if map_empty?(diff_bdd) do\n                  prepend_pair_unless_empty_diff(value, neg_value, bdd, acc)\n                else\n                  acc = [{intersection_value, diff_bdd} | acc]\n                  prepend_pair_unless_empty_diff(value, neg_value, bdd, acc)\n                end\n              end\n            end\n          end)\n        end\n    end)\n  catch\n    :empty -> []\n  end\n\n  defp map_pop_key_bdd(tag, fields, key) do\n    case fields_take(key, fields) do\n      {value, fields} -> {value, map_new(tag, fields)}\n      :error -> {map_key_tag_to_type(tag), map_new(tag, fields)}\n    end\n  end\n\n  defp prepend_pair_unless_empty_diff(value, neg_value, bdd, acc) do\n    diff_value = difference(value, neg_value)\n    if empty?(diff_value), do: acc, else: [{diff_value, bdd} | acc]\n  end\n\n  @doc \"\"\"\n  Returns the map converted into a list.\n  \"\"\"\n  def map_to_list(descr, fun \\\\ &tuple([&1, &2]))\n\n  def map_to_list(:term, _fun), do: :badmap\n\n  def map_to_list(descr, fun) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        if map_only?(descr) do\n          map_to_list_static(descr, fun)\n        else\n          :badmap\n        end\n\n      {dynamic, static} ->\n        if map_only?(static) do\n          with {:ok, dynamic_type} <- map_to_list_static(dynamic, fun) do\n            if descr_key?(static, :map) do\n              with {:ok, static_type} <- map_to_list_static(static, fun) do\n                {:ok, union(static_type, dynamic(dynamic_type))}\n              end\n            else\n              {:ok, dynamic(dynamic_type)}\n            end\n          end\n        else\n          :badmap\n        end\n    end\n  end\n\n  defp map_to_list_static(%{map: bdd}, fun) do\n    case map_bdd_to_dnf_remove_empty(bdd) do\n      [] ->\n        :badmap\n\n      dnf ->\n        case map_to_list_static(bdd, dnf, fun) do\n          value when value == @none ->\n            {:ok, empty_list()}\n\n          inner ->\n            if has_empty_map?(dnf) do\n              {:ok, list(inner)}\n            else\n              {:ok, non_empty_list(inner)}\n            end\n        end\n    end\n  end\n\n  defp map_to_list_static(%{}, _fun) do\n    :badmap\n  end\n\n  defp map_to_list_static(:term, fun) do\n    {:ok, list(fun.(term(), term()))}\n  end\n\n  defp has_empty_map?(dnf) do\n    Enum.any?(dnf, fn {_, fields, negs} ->\n      Enum.all?(fields_to_list(fields), fn {_key, value} -> is_optional_static(value) end) and\n        Enum.all?(negs, fn {_, fields} ->\n          not Enum.all?(fields_to_list(fields), fn {_key, value} -> is_optional_static(value) end)\n        end)\n    end)\n  end\n\n  defp map_to_list_static(bdd, dnf, fun) do\n    try do\n      # Check if any line in the DNF represents an open map or compute the union of domain keys types\n      Enum.reduce(dnf, none(), fn\n        {tag_or_domains, _fields, _negs}, acc ->\n          case tag_or_domains do\n            :open ->\n              # A negation cannot make an open map closed without cancelling it completely,\n              # which is filtered by `map_bdd_to_dnf_*/1`.\n              throw(:open)\n\n            domains when is_list(domains) ->\n              fields_fold(domains, acc, fn domain_key, value, acc ->\n                value = remove_optional(value)\n\n                if empty?(value) do\n                  acc\n                else\n                  union(acc, fun.(domain_key_to_descr(domain_key), value))\n                end\n              end)\n\n            _ ->\n              acc\n          end\n      end)\n    catch\n      :open -> fun.(term(), term())\n    else\n      domain_keys_type ->\n        {_seen, acc} =\n          bdd_reduce(bdd, {%{}, domain_keys_type}, fn {_tag, fields}, seen_acc ->\n            fields_fold(fields, seen_acc, fn key, _type, {seen, acc} ->\n              if Map.has_key?(seen, key) do\n                {seen, acc}\n              else\n                {_, value} = map_dnf_fetch_static(dnf, key)\n                seen = Map.put(seen, key, [])\n\n                if empty?(value) do\n                  {seen, acc}\n                else\n                  {seen, union(acc, fun.(atom([key]), value))}\n                end\n              end\n            end)\n          end)\n\n        acc\n    end\n  end\n\n  @doc \"\"\"\n  Updates `key_descr` in `descr` with `type`.\n\n  `key_descr` is split into optional and required keys and tracked accordingly.\n  The gradual aspect of `key_descr` does not impact the return type.\n\n  It returns `{type, descr, errors}`, `:badmap`, `{:error, errors}`.\n  The list of `errors` may be empty, which implies a bad domain.\n  The `return_type?` flag is used for optimizations purposes. If set to false,\n  the returned `type` should not be used, as it will be imprecise.\n  \"\"\"\n  def map_update(descr, key_descr, type, return_type? \\\\ true, force? \\\\ false)\n\n  def map_update(descr, key_descr, :term, return_type?, force?),\n    do: map_update_unchecked(descr, key_descr, fn _ -> :term end, return_type?, force?)\n\n  def map_update(descr, key_descr, type, return_type?, force?) do\n    case type do\n      %{dynamic: dynamic} ->\n        fun = fn _, _ -> dynamic end\n        map_update_unchecked(dynamic(descr), key_descr, fun, return_type?, force?)\n\n      %{} ->\n        fun = fn _, _ -> type end\n        map_update_unchecked(descr, key_descr, fun, return_type?, force?)\n    end\n  end\n\n  @doc \"\"\"\n  Updates `key_descr` in `descr` with `type`.\n\n  `key_descr` is split into optional and required keys and tracked accordingly.\n  The gradual aspect of `key_descr` does not impact the return type.\n\n  This is a more general version of `map_update/5` and has the same return values.\n  However, the third argument is an anonymous function that receives the current\n  value and returns `type_fun`. Note the value returned by `type_fun` cannot hold\n  dynamic. Any dynamic conversion must happen before invoking this function.\n  \"\"\"\n  def map_update_fun(descr, key_descr, type_fun, return_type? \\\\ true, force? \\\\ false) do\n    gradual? = gradual?(descr)\n\n    type_fun = fn optional?, value ->\n      if is_function(type_fun, 1) do\n        case type_fun.(if gradual?, do: dynamic(value), else: value) do\n          %{dynamic: dynamic} -> dynamic\n          descr -> descr\n        end\n      else\n        value = if gradual?, do: dynamic(value), else: value\n\n        case type_fun.(optional?, value) do\n          %{dynamic: dynamic} -> dynamic\n          descr -> descr\n        end\n      end\n    end\n\n    map_update_unchecked(descr, key_descr, type_fun, return_type?, force?)\n  end\n\n  def map_update_unchecked(:term, _key_descr, _type_fun, _return_type?, _force?), do: :badmap\n\n  def map_update_unchecked(descr, key_descr, type_fun, return_type?, force?) do\n    split_keys = map_split_keys_and_domains(key_descr)\n\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        if descr_key?(descr, :map) and map_only?(descr) do\n          {type, descr, errors, found?} =\n            map_update_static(descr, split_keys, type_fun, return_type?, force?, true)\n\n          if found? do\n            {type, descr, errors}\n          else\n            {:error, errors}\n          end\n        else\n          :badmap\n        end\n\n      {dynamic, static} ->\n        if descr_key?(dynamic, :map) and map_only?(static) do\n          {static_value, static_descr, static_errors, _static_found?} =\n            map_update_static(static, split_keys, type_fun, return_type?, force?, true)\n\n          {dynamic_value, dynamic_descr, dynamic_errors, dynamic_found?} =\n            map_update_static(dynamic, split_keys, type_fun, return_type?, force?, false)\n\n          # We can exceptionally check for none() here because\n          # we already check for empty downstream\n          if dynamic_found? do\n            {union(static_value, dynamic(dynamic_value)),\n             union(static_descr, dynamic(dynamic_descr)), static_errors ++ dynamic_errors}\n          else\n            {:error, static_errors ++ dynamic_errors}\n          end\n        else\n          :badmap\n        end\n    end\n  end\n\n  defp map_update_static(%{map: bdd}, split_keys, type_fun, return_type?, force?, static?) do\n    {required_keys, optional_keys, maybe_negated_set, required_domains, optional_domains} =\n      split_keys\n\n    optional_keys =\n      ((map_keys_from_negated_set(maybe_negated_set, bdd) -- optional_keys) -- required_keys) ++\n        optional_keys\n\n    dnf = map_bdd_to_dnf_with_empty(bdd)\n\n    {found?, value, domains, errors} =\n      if force? and not return_type? do\n        {false, none(), required_domains ++ optional_domains, []}\n      else\n        callback =\n          if return_type? do\n            fn -> map_update_merge_atom_key(bdd, dnf) end\n          else\n            fn ->\n              # If we have required keys, we can assume domain_atom always work\n              if required_keys != [] or map_update_any_atom_key?(bdd, dnf) do\n                term()\n              else\n                none()\n              end\n            end\n          end\n\n        # Required domains must be found\n        {found_required?, matched_required_domains, missing_domains, value} =\n          map_update_get_domains(dnf, required_domains, none(), return_type?, callback)\n\n        # Optional domains can be missing\n        {found_optional?, matched_optional_domains, _, value} =\n          map_update_get_domains(dnf, optional_domains, value, return_type?, callback)\n\n        errors = Enum.map(missing_domains, &{:baddomain, domain_key_to_descr(&1)})\n\n        domains =\n          if force?,\n            do: required_domains ++ optional_domains,\n            else: matched_required_domains ++ matched_optional_domains\n\n        {found_required? or found_optional?, value, domains, errors}\n      end\n\n    acc =\n      if found? or (force? and domains != []) do\n        # If any of required or optional domains are satisfied, then we compute the\n        # initial return type. `map_update_keys_static` will then union into the\n        # computed type below, using the original bdd/dnf, not the one with updated domains.\n        descr = map_update_put_domains(bdd, domains, type_fun)\n        {remove_optional(value), descr, errors, true}\n      else\n        {remove_optional(value), none(), errors, false}\n      end\n\n    map_update_keys_static(dnf, required_keys, optional_keys, type_fun, force?, static?, acc)\n  end\n\n  defp map_update_static(%{}, _split_keys, _type_fun, _return_type?, _force?, _static?) do\n    {none(), none(), [], false}\n  end\n\n  defp map_update_static(:term, split_keys, type_fun, _return_type?, force?, static?) do\n    # Since it is an open map, we don't need to check the domains.\n    # The negated set will also be empty, because there are no fields.\n    # Finally, merged required_keys into optional_keys.\n    {required_keys, optional_keys, _maybe_negated_set, required_domains, optional_domains} =\n      split_keys\n\n    if required_domains != [] or optional_domains != [] do\n      {term(), open_map(), [], true}\n    else\n      acc = {none(), none(), [], false}\n      dnf = map_bdd_to_dnf_with_empty(@map_top)\n      map_update_keys_static(dnf, required_keys, optional_keys, type_fun, force?, static?, acc)\n    end\n  end\n\n  defp map_update_keys_static(dnf, required, optional, type_fun, force?, static?, acc) do\n    acc = map_update_keys(dnf, required, type_fun, true, force?, static?, acc)\n    acc = map_update_keys(dnf, optional, type_fun, false, force?, static?, acc)\n    acc\n  end\n\n  defp map_update_keys(dnf, keys, type_fun, required_key?, force?, static?, acc) do\n    Enum.reduce(keys, acc, fn key, {acc_value, acc_descr, acc_errors, acc_found?} ->\n      {{optional?, value}, descr} =\n        case dnf do\n          # Optimization: avoid creating term types when updating open maps\n          [{:open, fields, []}] ->\n            if fields_is_key(key, fields) do\n              {value, descr} = map_dnf_pop_key_static(dnf, key, none())\n              {pop_optional_static(value), descr}\n            else\n              {{true, term()}, %{map: map_new(:open, fields)}}\n            end\n\n          _ ->\n            {value, descr} = map_dnf_pop_key_static(dnf, key, none())\n            {pop_optional_static(value), descr}\n        end\n\n      if not force? and empty?(value) do\n        acc_errors = if required_key?, do: [{:badkey, key} | acc_errors], else: acc_errors\n        {acc_value, acc_descr, acc_errors, acc_found?}\n      else\n        acc_value = union(value, acc_value)\n        acc_descr = union(map_put_key_static(descr, key, type_fun.(optional?, value)), acc_descr)\n\n        # The field will be missing if we are not forcing,\n        # we are in static mode and the value is optional.\n        missing? = not force? and static? and optional?\n\n        if required_key? and missing? do\n          {acc_value, acc_descr, [{:badkey, key} | acc_errors], acc_found?}\n        else\n          {acc_value, acc_descr, acc_errors, acc_found? or not missing?}\n        end\n      end\n    end)\n  end\n\n  # Directly inserts a key of a given type into every positive and negative map.\n  defp map_put_key_static(%{map: bdd} = descr, key, type) do\n    bdd =\n      bdd_map(bdd, fn\n        {:closed, fields} when type == @not_set -> {:closed, fields}\n        {tag, fields} -> {tag, fields_store(key, type, fields)}\n      end)\n\n    %{descr | map: bdd}\n  end\n\n  defp map_put_key_static(descr, _key, _type), do: descr\n\n  # Removes a key from a map type and return its type.\n  #\n  # ## Algorithm\n  #\n  # 1. Split the map type based on the presence of the key.\n  # 2. Take the second part of the split, which represents the union of all\n  #    record types where the key has been explicitly removed.\n  # 3. Intersect this with an open record type where the key is explicitly absent.\n  #    This step eliminates the key from open record types where it was implicitly present.\n  #\n  # Note: if initial is nil, it means the value is not required.\n  # So we don't compute it for performance.\n  defp map_dnf_pop_key_static(dnf, key, initial) do\n    {value, bdd} =\n      Enum.reduce(dnf, {initial, :bdd_bot}, fn\n        # Optimization: if there are no negatives, we can directly remove the key.\n        {tag, fields, []}, {value, bdd} ->\n          {fst, snd} = map_pop_key_bdd(tag, fields, key)\n          {maybe_union(value, fn -> fst end), map_union(bdd, snd)}\n\n        {tag, fields, negs}, {value, bdd} ->\n          {fst, snd} = map_pop_key_bdd(tag, fields, key)\n          pairs = map_split_negative_key(negs, key, fst, snd)\n\n          {maybe_union(value, fn -> Enum.reduce(pairs, none(), &union(elem(&1, 0), &2)) end),\n           Enum.reduce(pairs, bdd, &map_union(elem(&1, 1), &2))}\n      end)\n\n    if bdd == :bdd_bot do\n      {value, %{}}\n    else\n      {value, %{map: bdd}}\n    end\n  end\n\n  defp map_update_merge_atom_key(bdd, dnf) do\n    {_seen, acc} =\n      bdd_reduce(bdd, {%{}, none()}, fn {_tag, fields}, seen_acc ->\n        fields_fold(fields, seen_acc, fn key, _type, {seen, acc} ->\n          if Map.has_key?(seen, key) do\n            {seen, acc}\n          else\n            {_, value} = map_dnf_fetch_static(dnf, key)\n            {Map.put(seen, key, []), union(acc, value)}\n          end\n        end)\n      end)\n\n    acc\n  end\n\n  defp map_update_any_atom_key?(bdd, dnf) do\n    bdd_reduce(bdd, %{}, fn {_tag, fields}, acc ->\n      fields_fold(fields, acc, fn key, _type, acc ->\n        if Map.has_key?(acc, key) do\n          acc\n        else\n          {_, value} = map_dnf_fetch_static(dnf, key)\n          not empty?(value) and throw(:found_key)\n          Map.put(acc, key, [])\n        end\n      end)\n    end)\n  catch\n    :found_key -> true\n  end\n\n  defp map_update_get_domains(dnf, domain_keys, acc, require_type?, any_atom_key) do\n    Enum.reduce(domain_keys, {false, [], [], acc}, fn domain_key, {found?, valid, invalid, acc} ->\n      value = map_get_domain_no_optional(dnf, domain_key, none())\n\n      cond do\n        domain_key == :atom ->\n          atom_acc = any_atom_key.()\n\n          cond do\n            not empty?(value) ->\n              acc = if require_type?, do: union(union(atom_acc, acc), value), else: acc\n              {true, [:atom | valid], invalid, acc}\n\n            not empty?(atom_acc) ->\n              acc = if require_type?, do: union(atom_acc, acc), else: acc\n              {true, valid, [:atom | invalid], acc}\n\n            true ->\n              {found?, valid, [:atom | invalid], acc}\n          end\n\n        not empty?(value) ->\n          acc = if require_type?, do: union(acc, value), else: acc\n          {true, [domain_key | valid], invalid, acc}\n\n        true ->\n          {found?, valid, [domain_key | invalid], acc}\n      end\n    end)\n  end\n\n  # For negations, we count on the idea that a negation will not remove any\n  # type from a domain unless it completely cancels out the type.\n  #\n  # So for any non-empty map bdd, we just update the domain with the new type,\n  # as well as its negations to keep them accurate.\n  #\n  # Note we store all domain_keys at once. Therefore, this operation:\n  #\n  #    map = %{integer() => if_set(:foo), float() => if_set(:bar)}\n  #    Map.put(map, integer() or float(), pid())\n  #\n  # will return:\n  #\n  #    %{integer() => if_set(:foo or pid()), float() => if_set(:bar or pid())}\n  #\n  # We could instead have returned:\n  #\n  #    %{integer() => if_set(:foo or pid()), float() => if_set(:bar)} or\n  #      %{integer() => if_set(:foo), float() => if_set(:bar or pid())}\n  #\n  # But that would not be helpful, as we can't distinguish between these two\n  # in Elixir code. It only makes sense to build the union for domain keys\n  # that do not exist.\n  defp map_update_put_domains(bdd, [], _type_fun), do: %{map: bdd}\n\n  defp map_update_put_domains(bdd, domain_keys, type_fun) do\n    bdd =\n      bdd_map(bdd, fn {tag, fields} ->\n        {map_update_put_domain(tag, domain_keys, type_fun), fields}\n      end)\n\n    %{map: bdd}\n  end\n\n  defp map_update_put_domain(tag_or_domains, domain_keys, type_fun) do\n    case tag_or_domains do\n      :open ->\n        :open\n\n      :closed ->\n        fields_from_keys(domain_keys, if_set(type_fun.(true, none())))\n\n      # Note: domain_keys may contain duplicates, so we cannot\n      # do a side-by-side traversal here.\n      domains when is_list(domains) ->\n        Enum.reduce(domain_keys, domains, fn domain_key, acc ->\n          case fields_find(domain_key, acc) do\n            {:ok, value} ->\n              fields_store(domain_key, union(value, type_fun.(true, remove_optional(value))), acc)\n\n            :error ->\n              fields_store(domain_key, if_set(type_fun.(true, none())), acc)\n          end\n        end)\n    end\n  end\n\n  @doc \"\"\"\n  Puts a static key into `descr`.\n\n  Shortcut around `map_put/3`.\n  \"\"\"\n  def map_put_key(:term, key, _) when is_atom(key),\n    do: :badmap\n\n  def map_put_key(descr, key, type) when is_atom(key),\n    do: map_put_shared(descr, {[key], [], nil, [], []}, type)\n\n  @doc \"\"\"\n  Puts the `key_descr` with `type`.\n\n  `key_descr` is split into optional and required keys and tracked accordingly.\n\n  Returns `{:ok, descr}` or `:badmap`.\n  \"\"\"\n  def map_put(:term, _, _), do: :badmap\n\n  def map_put(descr, key_descr, type) do\n    if key_descr in [:term, %{dynamic: :term}] and type in [:term, %{dynamic: :term}] do\n      {:ok, if(gradual?(type) or gradual?(descr), do: dynamic(open_map()), else: open_map())}\n    else\n      map_put_shared(descr, map_split_keys_and_domains(key_descr), type)\n    end\n  end\n\n  defp map_put_shared(%{} = descr, split_keys, :term),\n    do: map_put_static_value(descr, split_keys, :term)\n\n  defp map_put_shared(%{} = descr, split_keys, type) do\n    case :maps.take(:dynamic, type) do\n      :error -> map_put_static_value(descr, split_keys, type)\n      {dynamic, _static} -> map_put_static_value(dynamic(descr), split_keys, dynamic)\n    end\n  end\n\n  defp map_put_static_value(descr, split_keys, type) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        if descr_key?(descr, :map) and map_only?(descr) do\n          {:ok, map_put_static(descr, split_keys, type)}\n        else\n          :badmap\n        end\n\n      {dynamic, static} ->\n        if descr_key?(dynamic, :map) and map_only?(static) do\n          static_descr = map_put_static(static, split_keys, type)\n          dynamic_descr = map_put_static(dynamic, split_keys, type)\n          {:ok, union(static_descr, dynamic(dynamic_descr))}\n        else\n          :badmap\n        end\n    end\n  end\n\n  defp map_put_static(%{map: bdd}, split_keys, type) do\n    {required_keys, optional_keys, maybe_negated_set, required_domains, optional_domains} =\n      split_keys\n\n    optional_keys =\n      ((map_keys_from_negated_set(maybe_negated_set, bdd) -- optional_keys) -- required_keys) ++\n        optional_keys\n\n    type_fun = fn _, _ -> type end\n\n    descr =\n      case required_domains ++ optional_domains do\n        [] -> none()\n        domains -> map_update_put_domains(bdd, domains, type_fun)\n      end\n\n    dnf = map_bdd_to_dnf_with_empty(bdd)\n    map_put_keys_static(dnf, required_keys ++ optional_keys, type, descr)\n  end\n\n  defp map_put_static(%{}, _split_keys, _type) do\n    none()\n  end\n\n  defp map_put_static(:term, split_keys, type) do\n    # Since it is an open map, we don't need to check the domains.\n    # The negated set will also be empty, because there are no fields.\n    # Finally, merged required_keys into optional_keys.\n    {required_keys, optional_keys, _maybe_negated_set, required_domains, optional_domains} =\n      split_keys\n\n    if required_domains != [] or optional_domains != [] do\n      open_map()\n    else\n      dnf = map_bdd_to_dnf_with_empty(@map_top)\n      map_put_keys_static(dnf, required_keys ++ optional_keys, type, none())\n    end\n  end\n\n  defp map_put_keys_static(dnf, keys, type, acc) do\n    Enum.reduce(keys, acc, fn key, acc ->\n      {nil, descr} = map_dnf_pop_key_static(dnf, key, nil)\n      union(map_put_key_static(descr, key, type), acc)\n    end)\n  end\n\n  @doc \"\"\"\n  Computes the union of types for keys matching `key_type` within the `map_type`.\n\n  Returns `{:ok, descr}`, `:error` (if no value across the whole domain is found),\n  or `:badmap`.\n\n  This is called `map_get/2` but it can be used to power `Map.fetch`, `Map.fetch!`,\n  `Map.get`, etc. except `map.key`.\n  \"\"\"\n  def map_get(:term, _key_descr), do: :badmap\n\n  def map_get(%{} = descr, key_descr) do\n    split_keys = map_split_keys_and_domains(key_descr)\n\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        if descr_key?(descr, :map) and map_only?(descr) do\n          type_selected = map_get_static(descr, split_keys)\n\n          if empty?(type_selected) do\n            :error\n          else\n            {:ok, type_selected}\n          end\n        else\n          :badmap\n        end\n\n      {dynamic, static} ->\n        if descr_key?(dynamic, :map) and map_only?(static) do\n          static_type = map_get_static(static, split_keys)\n          dynamic_type = map_get_static(dynamic, split_keys)\n\n          if empty?(dynamic_type) do\n            :error\n          else\n            {:ok, union(dynamic(dynamic_type), static_type)}\n          end\n        else\n          :badmap\n        end\n    end\n  end\n\n  defp map_get_static(%{map: bdd}, split_keys) do\n    {required_keys, optional_keys, maybe_negated_set, required_domains, optional_domains} =\n      split_keys\n\n    dnf = map_bdd_to_dnf_with_empty(bdd)\n\n    acc = none()\n    acc = map_get_keys(dnf, required_keys, acc)\n    acc = map_get_keys(dnf, optional_keys, acc)\n    acc = map_get_keys(dnf, map_keys_from_negated_set(maybe_negated_set, bdd), acc)\n    acc = Enum.reduce(required_domains, acc, &map_get_domain_no_optional(dnf, &1, &2))\n    acc = Enum.reduce(optional_domains, acc, &map_get_domain_no_optional(dnf, &1, &2))\n    remove_optional(acc)\n  end\n\n  defp map_get_static(%{}, _split_keys), do: none()\n  defp map_get_static(:term, _split_keys), do: term()\n\n  defp map_get_keys(dnf, keys, acc) do\n    Enum.reduce(keys, acc, fn atom, acc ->\n      {_, value} = map_dnf_fetch_static(dnf, atom)\n      union(value, acc)\n    end)\n  end\n\n  # Take a map bdd and return the union of types for the given key domain.\n  # Notice this already removes the optional field from the domain.\n  defp map_get_domain_no_optional(dnf, domain_key, acc) when is_atom(domain_key) do\n    Enum.reduce(dnf, acc, fn\n      # Optimization: if there are no negatives, get the domain tag directly\n      {tag, _fields, []}, acc ->\n        map_domain_tag_to_type(tag, domain_key) |> union(acc)\n\n      {tag_or_domains, fields, negs}, acc ->\n        {_found, value, bdd} = map_pop_domain_bdd(tag_or_domains, fields, domain_key)\n\n        negs\n        |> map_split_negative(value, bdd, fn neg_tag, neg_fields ->\n          map_pop_domain_bdd(neg_tag, neg_fields, domain_key)\n        end)\n        |> Enum.reduce(acc, fn {value, _}, acc -> union(value, acc) end)\n    end)\n  end\n\n  defp map_keys_from_negated_set(nil, _bdd), do: []\n\n  defp map_keys_from_negated_set(set, bdd) do\n    bdd\n    |> bdd_reduce(%{}, fn {_, fields}, acc ->\n      fields_fold(fields, acc, fn atom, _, acc ->\n        if :sets.is_element(atom, set), do: acc, else: Map.put(acc, atom, true)\n      end)\n    end)\n    |> Map.keys()\n  end\n\n  # Compute which keys are optional, which ones are required, as well as domain keys\n  defp map_split_keys_and_domains(%{dynamic: dynamic} = static) do\n    {required_keys, optional_keys, maybe_negated_set} =\n      case {static, unfold(dynamic)} do\n        {%{atom: {:union, static_union}}, %{atom: {:union, dynamic_union}}} ->\n          # The static union is required, extract them from optional\n          {:sets.to_list(static_union),\n           :sets.to_list(:sets.subtract(dynamic_union, static_union)), nil}\n\n        {%{atom: {:union, static_union}}, %{atom: {:negation, dynamic_negation}}} ->\n          # The static union will already be checked, merge them into the negation\n          {:sets.to_list(static_union), [], :sets.union(dynamic_negation, static_union)}\n\n        {%{atom: {:union, static_union}}, _} ->\n          {:sets.to_list(static_union), [], nil}\n\n        {%{atom: {:negation, static_negation}}, %{atom: {:union, dynamic_union}}} ->\n          # The dynamic union will already be checked, merge them into the negation\n          {[], :sets.to_list(dynamic_union), :sets.union(static_negation, dynamic_union)}\n\n        {%{atom: {:negation, static_negation}}, %{atom: {:negation, dynamic_negation}}} ->\n          {[], [], :sets.union(dynamic_negation, static_negation)}\n\n        {%{}, %{atom: {:union, dynamic_union}}} ->\n          {[], :sets.to_list(dynamic_union), nil}\n\n        {%{}, %{atom: {:negation, dynamic_negation}}} ->\n          {[], [], dynamic_negation}\n\n        {%{}, %{}} ->\n          {[], [], nil}\n      end\n\n    required_domains = to_domain_keys(Map.delete(static, :dynamic))\n    optional_domains = to_domain_keys(dynamic) -- required_domains\n    {required_keys, optional_keys, maybe_negated_set, required_domains, optional_domains}\n  end\n\n  defp map_split_keys_and_domains(%{atom: {:union, atoms}} = key_descr) do\n    {:sets.to_list(atoms), [], nil, to_domain_keys(key_descr), []}\n  end\n\n  defp map_split_keys_and_domains(%{atom: {:negation, atoms}} = key_descr) do\n    {[], [], atoms, to_domain_keys(key_descr), []}\n  end\n\n  defp map_split_keys_and_domains(key_descr) do\n    {[], [], nil, to_domain_keys(key_descr), []}\n  end\n\n  defp non_empty_map_literals_intersection(maps) do\n    try do\n      Enum.reduce(maps, {:open, @fields_new}, fn {next_tag, next_fields}, {tag, fields} ->\n        map_literal_intersection(tag, fields, next_tag, next_fields)\n      end)\n    catch\n      :empty -> :empty\n    end\n  end\n\n  # Short-circuits if it finds a non-empty map literal in the union.\n  # Since the algorithm is recursive, we implement the short-circuiting\n  # as throw/catch.\n  defp map_empty?(bdd) do\n    bdd_to_dnf(bdd)\n    |> Enum.all?(fn {pos, negs} ->\n      case non_empty_map_literals_intersection(pos) do\n        :empty ->\n          true\n\n        {tag, fields} ->\n          # We check the emptiness of the fields because non_empty_map_literal_intersection\n          # will not return :empty on fields that are set to none() and that exist\n          # just in one map, but not the other.\n          init_map_line_empty?(tag, fields, negs)\n      end\n    end)\n  end\n\n  defp init_map_line_empty?(tag, fields, negs) do\n    Enum.any?(fields_to_list(fields), fn {_key, type} -> empty?(type) end) or\n      map_line_empty?(tag, fields, negs)\n  end\n\n  # These positives get checked once when calling init_map_line_empty?, and then every time\n  # an intersection or difference is computed, its emptiness is checked again.\n  # So they are all necessarily non-empty.\n  defp map_line_empty?(_, _pos, []), do: false\n  defp map_line_empty?(_, _, [{:open, neg_fields} | _]) when is_fields_empty(neg_fields), do: true\n  defp map_line_empty?(:open, fs, [{:closed, _} | negs]), do: map_line_empty?(:open, fs, negs)\n\n  defp map_line_empty?(tag, fields, [{neg_tag, neg_fields} | negs]) do\n    if map_check_domain_keys?(tag, neg_tag) do\n      if tag == :closed or neg_tag == :open do\n        # This implements the same map line check as tuples\n        map_line_meet_empty?(fields, neg_fields, tag, neg_tag, [], negs)\n      else\n        map_line_fields_empty?(fields, neg_fields, tag, neg_tag, fields, negs)\n      end\n    else\n      map_line_empty?(tag, fields, negs)\n    end\n  catch\n    :closed -> map_line_empty?(tag, fields, negs)\n  end\n\n  defp map_line_meet_empty?([{k1, v1} | t1], [{k2, _} | _] = l2, tag, neg_tag, acc_meet, negs)\n       when k1 < k2 do\n    cond do\n      # The key is only in the positive map, which means the difference\n      # with a negative open tag (all possible types) tag will surely be empty.\n      neg_tag == :open ->\n        map_line_meet_empty?(t1, l2, tag, neg_tag, [{k1, v1} | acc_meet], negs)\n\n      # In this case the difference will never be empty, so we can skip ahead.\n      neg_tag == :closed and not is_optional_static(v1) ->\n        throw(:closed)\n\n      true ->\n        v2 = map_key_tag_to_type(neg_tag)\n        map_line_meet_empty?(k1, v1, v2, t1, l2, tag, neg_tag, acc_meet, negs)\n    end\n  end\n\n  defp map_line_meet_empty?([{k1, _} | _] = l1, [{k2, v2} | t2], tag, neg_tag, acc_meet, negs)\n       when k1 > k2 do\n    # The keys is only in the negative map and the positive map is closed,\n    # in that case, this field is not_set(), and its difference with the\n    # negative map type is empty iff the negative type is optional.\n    if tag == :closed and not is_optional_static(v2) do\n      throw(:closed)\n    else\n      v1 = map_key_tag_to_type(tag)\n      map_line_meet_empty?(k2, v1, v2, l1, t2, tag, neg_tag, acc_meet, negs)\n    end\n  end\n\n  defp map_line_meet_empty?([{k, v1} | t1], [{_, v2} | t2], tag, neg_tag, acc_meet, negs) do\n    map_line_meet_empty?(k, v1, v2, t1, t2, tag, neg_tag, acc_meet, negs)\n  end\n\n  defp map_line_meet_empty?([{k1, v1} | t1], [], tag, neg_tag, acc_meet, negs) do\n    v2 = map_key_tag_to_type(neg_tag)\n    map_line_meet_empty?(k1, v1, v2, t1, [], tag, neg_tag, acc_meet, negs)\n  end\n\n  defp map_line_meet_empty?([], [{k2, v2} | t2], tag, neg_tag, acc_meet, negs) do\n    v1 = map_key_tag_to_type(tag)\n    map_line_meet_empty?(k2, v1, v2, [], t2, tag, neg_tag, acc_meet, negs)\n  end\n\n  defp map_line_meet_empty?([], [], _tag, _neg_tag, _acc_meet, _negs) do\n    true\n  end\n\n  defp map_line_meet_empty?(key, type, neg_type, t1, t2, tag, neg_tag, acc_meet, negs) do\n    diff = difference(type, neg_type)\n    meet = intersection(type, neg_type)\n\n    (empty?(diff) or map_line_empty?(tag, Enum.reverse(acc_meet, [{key, diff} | t1]), negs)) and\n      (empty?(meet) or map_line_meet_empty?(t1, t2, tag, neg_tag, [{key, meet} | acc_meet], negs))\n  end\n\n  defp map_line_fields_empty?([{k1, v1} | t1], [{k2, _} | _] = l2, tag, neg_tag, fields, negs)\n       when k1 < k2 do\n    cond do\n      # The key is only in the positive map, which means the difference\n      # with a negative open tag (all possible types) tag will surely be empty.\n      neg_tag == :open ->\n        map_line_fields_empty?(t1, l2, tag, neg_tag, fields, negs)\n\n      # In this case the difference will never be empty, so we can skip ahead.\n      neg_tag == :closed and not is_optional_static(v1) ->\n        throw(:closed)\n\n      true ->\n        map_line_fields_empty_recur?(k1, v1, map_key_tag_to_type(neg_tag), tag, fields, negs) and\n          map_line_fields_empty?(t1, l2, tag, neg_tag, fields, negs)\n    end\n  end\n\n  defp map_line_fields_empty?([{k1, _} | _] = l1, [{k2, v2} | t2], tag, neg_tag, fields, negs)\n       when k1 > k2 do\n    # The keys is only in the negative map and the positive map is closed,\n    # in that case, this field is not_set(), and its difference with the\n    # negative map type is empty iff the negative type is optional.\n    if tag == :closed do\n      if is_optional_static(v2) do\n        map_line_fields_empty?(l1, t2, tag, neg_tag, fields, negs)\n      else\n        throw(:closed)\n      end\n    else\n      map_line_fields_empty_recur?(k2, map_key_tag_to_type(tag), v2, tag, fields, negs) and\n        map_line_fields_empty?(l1, t2, tag, neg_tag, fields, negs)\n    end\n  end\n\n  defp map_line_fields_empty?([{key, v1} | t1], [{_, v2} | t2], tag, neg_tag, fields, negs) do\n    map_line_fields_empty_recur?(key, v1, v2, tag, fields, negs) and\n      map_line_fields_empty?(t1, t2, tag, neg_tag, fields, negs)\n  end\n\n  defp map_line_fields_empty?(t1, t2, tag, neg_tag, fields, negs) do\n    Enum.all?(t1, fn {key, v1} ->\n      map_line_fields_empty_recur?(key, v1, map_key_tag_to_type(neg_tag), tag, fields, negs)\n    end) and\n      Enum.all?(t2, fn {key, v2} ->\n        map_line_fields_empty_recur?(key, map_key_tag_to_type(tag), v2, tag, fields, negs)\n      end)\n  end\n\n  defp map_line_fields_empty_recur?(key, v1, v2, tag, fields, negs) do\n    diff = difference(v1, v2)\n    empty?(diff) or map_line_empty?(tag, fields_store(key, diff, fields), negs)\n  end\n\n  # Verify the domain condition from equation (22) in paper ICFP'23 https://www.irif.fr/~gc/papers/icfp23.pdf\n  # which is that every domain key type in the positive map is a subtype\n  # of the corresponding domain key type in the negative map.\n  defp map_check_domain_keys?(:closed, _), do: true\n  defp map_check_domain_keys?(_, :open), do: true\n\n  # An open map is a subtype iff the negative domains are all present as term_or_optional()\n  defp map_check_domain_keys?(:open, neg_domains) do\n    fields_size(neg_domains) == length(@domain_key_types) and\n      Enum.all?(fields_to_list(neg_domains), fn {_domain_key, type} ->\n        subtype?(term_or_optional(), type)\n      end)\n  end\n\n  # A positive domains is smaller than a closed map iff all its keys are empty or optional\n  defp map_check_domain_keys?(pos_domains, :closed) do\n    Enum.all?(fields_to_list(pos_domains), fn {_domain_key, type} -> empty_or_optional?(type) end)\n  end\n\n  # Component-wise comparison of domains\n  defp map_check_domain_keys?(pos_domains, neg_domains) do\n    Enum.all?(fields_to_list(pos_domains), fn {domain_key, type} ->\n      subtype?(type, fields_get(neg_domains, domain_key, not_set()))\n    end)\n  end\n\n  # Pop a domain type, already removing non optional.\n  defp map_pop_domain_bdd(domains, fields, domain_key) when is_list(domains) do\n    case fields_take(domain_key, domains) do\n      {value, domains} -> {true, value, map_new(domains, fields)}\n      :error -> {false, none(), map_new(domains, fields)}\n    end\n  end\n\n  # Open/close key\n  defp map_pop_domain_bdd(tag, fields, _domain_key),\n    do: {false, map_domain_tag_to_type(tag), map_new(tag, fields)}\n\n  # Continue to eliminate negations while length of list of negs decreases\n  defp map_eliminate_while_negs_decrease(tag, fields, []), do: [{tag, fields, []}]\n\n  defp map_eliminate_while_negs_decrease(tag, fields, negs) do\n    try do\n      maybe_eliminate_map_negations(tag, fields, negs)\n    catch\n      :empty -> []\n    else\n      {fields, new_negs} ->\n        if length(new_negs) < length(negs) do\n          map_eliminate_while_negs_decrease(tag, fields, new_negs)\n        else\n          [{tag, fields, new_negs}]\n        end\n    end\n  end\n\n  defp maybe_eliminate_map_negations(tag, fields, negs) do\n    Enum.reduce(negs, {fields, []}, fn neg = {neg_tag, neg_fields}, {acc_fields, acc_negs} ->\n      # If the intersection with the negative is empty, we can remove the negative.\n      empty_intersection? =\n        try do\n          _ = map_literal_intersection(tag, acc_fields, neg_tag, neg_fields)\n          false\n        catch\n          :empty -> true\n        end\n\n      if empty_intersection? do\n        {acc_fields, acc_negs}\n      else\n        case map_difference_strategy(acc_fields, neg_fields, tag, neg_tag) do\n          {:one_key_difference, key, v1, v2} ->\n            {fields_store(key, difference(v1, v2), acc_fields), acc_negs}\n\n          :disjoint ->\n            {acc_fields, acc_negs}\n\n          :left_subtype_of_right ->\n            throw(:empty)\n\n          :none ->\n            {acc_fields, [neg | acc_negs]}\n        end\n      end\n    end)\n  end\n\n  defp map_difference_strategy(fields1, fields2, tag1, tag2) do\n    if is_atom(tag1) and is_atom(tag2) do\n      status = if tag1 == tag2 or tag2 == :open, do: :all_equal, else: :none\n      map_difference_strategy(fields1, fields2, tag1, tag2, status)\n    else\n      :none\n    end\n  end\n\n  defp map_difference_strategy([{k1, value} | t1], [{k2, _} | _] = l2, tag1, tag2, status)\n       when k1 < k2 do\n    # Left side has a key the right side does not have,\n    # left can only be a subtype if the right side is open.\n    # If the right side is closed and the key is not optional, they are disjoint.\n    case status do\n      _ when tag2 == :closed ->\n        if not is_optional_static(value) do\n          :disjoint\n        else\n          map_difference_strategy(t1, l2, tag1, tag2, :none)\n        end\n\n      :all_equal ->\n        map_difference_strategy(t1, l2, tag1, tag2, :left_subtype_of_right)\n\n      {:one_key_difference, _, p1, p2} ->\n        if subtype?(p1, p2),\n          do: map_difference_strategy(t1, l2, tag1, tag2, :left_subtype_of_right),\n          else: :none\n\n      :left_subtype_of_right ->\n        map_difference_strategy(t1, l2, tag1, tag2, :left_subtype_of_right)\n\n      _ ->\n        :none\n    end\n  end\n\n  defp map_difference_strategy([{k1, _} | _] = l1, [{k2, value} | t2], tag1, tag2, _status)\n       when k1 > k2 do\n    # Right side has a key the left side does not have,\n    # if left-side is closed, they are disjoint.\n    if tag1 == :closed and not is_optional_static(value) do\n      :disjoint\n    else\n      map_difference_strategy(l1, t2, tag1, tag2, :none)\n    end\n  end\n\n  defp map_difference_strategy([{_, v} | t1], [{_, v} | t2], tag1, tag2, status) do\n    # Same key and same value, nothing changes\n    map_difference_strategy(t1, t2, tag1, tag2, status)\n  end\n\n  defp map_difference_strategy([{k1, v1} | t1], [{_, v2} | t2], tag1, tag2, status) do\n    # They have the same key but different values\n    if disjoint?(v1, v2) do\n      :disjoint\n    else\n      case status do\n        :all_equal when tag1 == tag2 ->\n          map_difference_strategy(t1, t2, tag1, tag2, {:one_key_difference, k1, v1, v2})\n\n        {:one_key_difference, _key, p1, p2} ->\n          if subtype?(p1, p2) and subtype?(v1, v2) do\n            map_difference_strategy(t1, t2, tag1, tag2, :left_subtype_of_right)\n          else\n            :none\n          end\n\n        _ ->\n          if status in [:all_equal, :left_subtype_of_right] and subtype?(v1, v2),\n            do: map_difference_strategy(t1, t2, tag1, tag2, :left_subtype_of_right),\n            else: map_difference_strategy(t1, t2, tag1, tag2, :none)\n      end\n    end\n  end\n\n  defp map_difference_strategy([], [], _tag1, _tag2, status) do\n    if status == :all_equal, do: :left_subtype_of_right, else: status\n  end\n\n  defp map_difference_strategy(l1, l2, tag1, tag2, status) do\n    cond do\n      tag2 == :open and l2 == [] ->\n        case status do\n          :all_equal ->\n            :left_subtype_of_right\n\n          {:one_key_difference, _, p1, p2} ->\n            if subtype?(p1, p2), do: :left_subtype_of_right, else: :none\n\n          :left_subtype_of_right ->\n            :left_subtype_of_right\n\n          :none ->\n            :none\n        end\n\n      tag1 == :closed and l2 != [] and Enum.all?(l2, fn {_, v} -> not is_optional_static(v) end) ->\n        :disjoint\n\n      tag2 == :closed and l1 != [] and Enum.all?(l1, fn {_, v} -> not is_optional_static(v) end) ->\n        :disjoint\n\n      true ->\n        :none\n    end\n  end\n\n  # Given a dnf, fuse maps when possible\n  # e.g. %{a: integer(), b: atom()} or %{a: float(), b: atom()} into %{a: number(), b: atom()}\n  defp map_fusion(dnf) do\n    # Steps:\n    # 1. Group maps by tags and keys\n    # 2. Try fusions for each group until no fusion is found\n    # 3. Merge the groups back into a dnf\n    {without_negs, with_negs} = Enum.split_with(dnf, fn {_tag, _fields, negs} -> negs == [] end)\n\n    without_negs =\n      without_negs\n      |> Enum.group_by(fn {tag, fields, _} -> {tag, fields_keys(fields)} end)\n      |> Enum.flat_map(fn {_, maps} -> map_non_negated_fuse(maps) end)\n\n    without_negs ++ with_negs\n  end\n\n  defp map_non_negated_fuse(maps) do\n    Enum.reduce(maps, [], fn map, acc ->\n      map_fuse_with_first_fusible(map, acc)\n    end)\n  end\n\n  defp map_fuse_with_first_fusible(map, []), do: [map]\n\n  defp map_fuse_with_first_fusible(map, [candidate | rest]) do\n    {tag1, fields1, []} = map\n    {tag2, fields2, []} = candidate\n\n    case maybe_optimize_map_union(tag1, fields1, tag2, fields2) do\n      nil -> [candidate | map_fuse_with_first_fusible(map, rest)]\n      # we found a fusible candidate, we're done\n      {tag, fields} -> [{tag, fields, []} | rest]\n    end\n  end\n\n  defp map_to_quoted(bdd, opts) do\n    bdd\n    |> map_bdd_to_dnf_with_empty()\n    |> Enum.flat_map(fn {tag, fields, negs} ->\n      map_eliminate_while_negs_decrease(tag, fields, negs)\n    end)\n    |> map_fusion()\n    |> Enum.map(&map_each_to_quoted(&1, opts))\n  end\n\n  defp map_each_to_quoted({tag, positive_map, negative_maps}, opts) do\n    case negative_maps do\n      [] ->\n        map_literal_to_quoted({tag, positive_map}, opts)\n\n      _ ->\n        negative_maps\n        |> non_empty_map_or(&map_literal_to_quoted(&1, opts))\n        |> Kernel.then(\n          &{:and, [], [map_literal_to_quoted({tag, positive_map}, opts), {:not, [], [&1]}]}\n        )\n    end\n  end\n\n  defp map_literal_to_quoted({:closed, empty}, _opts) when is_fields_empty(empty) do\n    {:empty_map, [], []}\n  end\n\n  defp map_literal_to_quoted({:open, empty}, _opts) when is_fields_empty(empty) do\n    {:map, [], []}\n  end\n\n  defp map_literal_to_quoted({domains, empty}, _opts)\n       when is_fields_empty(domains) and is_fields_empty(empty) do\n    {:empty_map, [], []}\n  end\n\n  defp map_literal_to_quoted({:open, [{:__struct__, @not_atom_or_optional}]}, _opts) do\n    {:non_struct_map, [], []}\n  end\n\n  defp map_literal_to_quoted({domains, fields}, opts) when is_list(domains) do\n    domain_fields =\n      for {domain_key, value_type} <- fields_to_list(domains) do\n        non_optional = remove_optional_static(value_type)\n\n        value_quoted =\n          if empty?(non_optional) do\n            {:not_set, [], []}\n          else\n            map_value_to_quoted(non_optional, opts)\n          end\n\n        {{domain_key, [], []}, value_quoted}\n      end\n\n    regular_fields_quoted = map_fields_to_quoted(:closed, fields, opts)\n    {:%{}, [], domain_fields ++ regular_fields_quoted}\n  end\n\n  defp map_literal_to_quoted({tag, fields}, opts) do\n    case tag do\n      :closed ->\n        with {:ok, struct_descr} <- fields_find(:__struct__, fields),\n             {:finite, [struct]} <- atom_fetch(struct_descr),\n             info when is_list(info) <- maybe_struct(struct),\n             true <- fields_size(fields) == length(info) + 1,\n             true <- Enum.all?(info, &fields_is_key(&1.field, fields)) do\n          collapse? = Keyword.get(opts, :collapse_structs, true)\n\n          fields =\n            for %{field: field} <- info,\n                type = fields_fetch!(field, fields),\n                # TODO: This should consider the struct default type\n                not collapse? or type != term(),\n                do: {field, type}\n\n          {:%, [],\n           [\n             literal_to_quoted(struct),\n             {:%{}, [], map_fields_to_quoted(tag, fields, opts)}\n           ]}\n        else\n          _ ->\n            {:%{}, [], map_fields_to_quoted(tag, fields, opts)}\n        end\n\n      :open ->\n        {:%{}, [], [{:..., [], nil} | map_fields_to_quoted(tag, fields, opts)]}\n    end\n  end\n\n  defp maybe_struct(struct) do\n    try do\n      struct.__info__(:struct)\n    rescue\n      _ -> nil\n    end\n  end\n\n  defp map_fields_to_quoted(tag, sorted, opts) do\n    keyword? = Inspect.List.keyword?(sorted)\n\n    for {key, type} <- sorted,\n        not (tag == :open and is_optional_static(type) and term_type?(type)) do\n      key =\n        if keyword? do\n          {:__block__, [format: :keyword], [key]}\n        else\n          literal_to_quoted(key)\n        end\n\n      {key, map_value_to_quoted(type, opts)}\n    end\n  end\n\n  defp map_value_to_quoted(type, opts) do\n    {optional?, type} = pop_optional_static(type)\n\n    cond do\n      not optional? -> to_quoted(type, opts)\n      empty?(type) -> {:not_set, [], []}\n      true -> {:if_set, [], [to_quoted(type, opts)]}\n    end\n  end\n\n  ## Map fields helpers\n  #\n  # Map fields and domains are stored as orddicts (sorted key-value lists).\n  # These helpers wrap :orddict operations so the representation\n  # can be changed without modifying every call site.\n\n  @compile {:inline,\n            fields_from_reverse_list: 1,\n            fields_from_keys: 2,\n            fields_to_list: 1,\n            fields_fold: 3,\n            fields_keys: 1,\n            fields_store: 3,\n            fields_find: 2,\n            fields_take: 2,\n            fields_get: 3,\n            fields_fetch!: 2,\n            fields_is_key: 2,\n            fields_merge: 3,\n            fields_map: 2}\n\n  defp fields_from_reverse_list(list), do: :lists.ukeysort(1, list)\n  defp fields_from_keys(keys, value), do: Enum.map(:lists.usort(keys), &{&1, value})\n  defp fields_to_list(fields), do: fields\n  defp fields_fold(fields, acc, fun), do: :orddict.fold(fun, acc, fields)\n  defp fields_keys(fields), do: :orddict.fetch_keys(fields)\n  defp fields_store(key, value, fields), do: :orddict.store(key, value, fields)\n  defp fields_find(key, fields), do: :orddict.find(key, fields)\n  defp fields_take(key, fields), do: :orddict.take(key, fields)\n  defp fields_fetch!(key, fields), do: :orddict.fetch(key, fields)\n  defp fields_is_key(key, fields), do: :orddict.is_key(key, fields)\n\n  defp fields_merge(fun, fields1, fields2), do: :orddict.merge(fun, fields1, fields2)\n  defp fields_map(fun, fields), do: :orddict.map(fun, fields)\n\n  defp fields_get(fields, key, default) do\n    case :orddict.find(key, fields) do\n      {:ok, value} -> value\n      :error -> default\n    end\n  end\n\n  defp fields_put_all_new(fields, [], _value), do: fields\n  defp fields_put_all_new([], keys, value), do: Enum.map(keys, &{&1, value})\n\n  defp fields_put_all_new([{k1, _} = h | t1], [k2 | _] = keys, value) when k1 < k2 do\n    [h | fields_put_all_new(t1, keys, value)]\n  end\n\n  defp fields_put_all_new([{k1, _} | _] = fields, [k2 | keys], value) when k1 > k2 do\n    [{k2, value} | fields_put_all_new(fields, keys, value)]\n  end\n\n  defp fields_put_all_new([h | t1], [_ | keys], value) do\n    [h | fields_put_all_new(t1, keys, value)]\n  end\n\n  defp fields_merge_with_defaults([{k1, v1} | rest1] = f1, d1, [{k2, v2} | rest2] = f2, d2, fun) do\n    cond do\n      k1 < k2 ->\n        [{k1, fun.(k1, v1, d2)} | fields_merge_with_defaults(rest1, d1, f2, d2, fun)]\n\n      k1 > k2 ->\n        [{k2, fun.(k2, d1, v2)} | fields_merge_with_defaults(f1, d1, rest2, d2, fun)]\n\n      true ->\n        [{k1, fun.(k1, v1, v2)} | fields_merge_with_defaults(rest1, d1, rest2, d2, fun)]\n    end\n  end\n\n  defp fields_merge_with_defaults([], d1, f2, _d2, fun),\n    do: Enum.map(f2, fn {k, v2} -> {k, fun.(k, d1, v2)} end)\n\n  defp fields_merge_with_defaults(f1, _d1, [], d2, fun),\n    do: Enum.map(f1, fn {k, v1} -> {k, fun.(k, v1, d2)} end)\n\n  ## Tuple\n\n  # Represents tuple types as a BDD with nodes of the following forms:\n  # 1. Closed tuples: Fixed-length tuples with specific element types\n  #    Example: {integer(), atom()}\n  # 2. Open tuples: Variable-length tuples with a minimum set of element types\n  #    Example: {atom(), boolean(), ...}\n  #\n  # Internal representation:\n  # - Closed tuple: {:closed, [element_type, ...]}\n  # - Open tuple:   {:open, [element_type, ...]}\n  #\n  # Examples:\n  # - {integer(), atom()} is encoded as {:closed, [integer(), atom()]}\n  # - {atom(), boolean(), ...} is encoded as {:open, [atom(), boolean()]}\n\n  defp tuple_descr(tag, fields) do\n    case tuple_descr(fields, [], false) do\n      :empty -> %{}\n      {fields, true} -> %{dynamic: %{tuple: tuple_new(tag, Enum.reverse(fields))}}\n      {_, false} -> %{tuple: tuple_new(tag, fields)}\n    end\n  end\n\n  defp tuple_descr([:term | rest], acc, dynamic?) do\n    tuple_descr(rest, [:term | acc], dynamic?)\n  end\n\n  defp tuple_descr([value | rest], acc, dynamic?) do\n    # Check if the static part is empty\n    static_empty? =\n      case value do\n        # Has dynamic component, check static separately\n        %{dynamic: _} -> false\n        _ -> empty?(value)\n      end\n\n    if static_empty? do\n      :empty\n    else\n      case :maps.take(:dynamic, value) do\n        :error ->\n          tuple_descr(rest, [value | acc], dynamic?)\n\n        {dynamic, _static} ->\n          # Check if dynamic component is empty\n          if empty?(dynamic) do\n            :empty\n          else\n            tuple_descr(rest, [dynamic | acc], true)\n          end\n      end\n    end\n  end\n\n  defp tuple_descr([], acc, dynamic?) do\n    {acc, dynamic?}\n  end\n\n  defp tuple_new(tag, elements), do: bdd_leaf(tag, elements)\n\n  defp tuple_intersection(bdd_leaf(:open, []), bdd), do: bdd\n  defp tuple_intersection(bdd, bdd_leaf(:open, [])), do: bdd\n\n  defp tuple_intersection(bdd1, bdd2) do\n    bdd_intersection(bdd1, bdd2, &tuple_leaf_intersection/2)\n  end\n\n  defp tuple_leaf_intersection(bdd_leaf(tag1, elements1), bdd_leaf(tag2, elements2)) do\n    case tuple_literal_intersection(tag1, elements1, tag2, elements2) do\n      {tag, elements} -> bdd_leaf(tag, elements)\n      :empty -> :bdd_bot\n    end\n  end\n\n  defp tuple_literal_intersection(:open, [], tag, elements), do: {tag, elements}\n\n  defp tuple_literal_intersection(tag1, elements1, tag2, elements2) do\n    case tuple_sizes_strategy(tag1, length(elements1), tag2, length(elements2)) do\n      :disjoint ->\n        :empty\n\n      _ ->\n        try do\n          zip_non_empty_intersection!(elements1, elements2, [])\n        catch\n          :empty -> :empty\n        else\n          elements when tag1 == :open and tag2 == :open -> {:open, elements}\n          elements -> {:closed, elements}\n        end\n    end\n  end\n\n  defp tuple_sizes_strategy(:closed, n1, :closed, n2) when n1 != n2, do: :disjoint\n  defp tuple_sizes_strategy(:closed, n1, :closed, n2) when n1 == n2, do: :left_subtype_of_right\n  defp tuple_sizes_strategy(:closed, n1, :open, n2) when n1 < n2, do: :disjoint\n  defp tuple_sizes_strategy(_, n1, :open, n2) when n1 >= n2, do: :left_subtype_of_right\n  defp tuple_sizes_strategy(:open, n1, :closed, n2) when n1 > n2, do: :disjoint\n  defp tuple_sizes_strategy(_, _, _, _), do: :none\n\n  # Intersects two lists of types, and _appends_ the extra elements to the result.\n  defp zip_non_empty_intersection!([], types2, acc), do: Enum.reverse(acc, types2)\n  defp zip_non_empty_intersection!(types1, [], acc), do: Enum.reverse(acc, types1)\n\n  defp zip_non_empty_intersection!([type1 | rest1], [type2 | rest2], acc) do\n    zip_non_empty_intersection!(rest1, rest2, [non_empty_intersection!(type1, type2) | acc])\n  end\n\n  defp zip_empty_intersection?([], _types2), do: false\n  defp zip_empty_intersection?(_types1, []), do: false\n\n  defp zip_empty_intersection?([type1 | rest1], [type2 | rest2]) do\n    case empty?(intersection(type1, type2)) do\n      true -> true\n      false -> zip_empty_intersection?(rest1, rest2)\n    end\n  end\n\n  defp tuple_difference(bdd_leaf(:open, []), bdd_leaf(:open, [])),\n    do: :bdd_bot\n\n  defp tuple_difference(bdd_leaf(:open, []), bdd2),\n    do: bdd_negation(bdd2)\n\n  defp tuple_difference(bdd1, bdd2),\n    do: bdd_difference(bdd1, bdd2, &tuple_leaf_difference/3)\n\n  defp tuple_leaf_difference(bdd_leaf(tag1, elements1), bdd_leaf(tag2, elements2), _) do\n    case tuple_sizes_strategy(tag1, length(elements1), tag2, length(elements2)) do\n      :disjoint -> :disjoint\n      other -> tuple_leaf_difference(elements1, elements2, other == :left_subtype_of_right)\n    end\n  end\n\n  defp tuple_leaf_difference([head1 | tail1], [head2 | tail2], subtype?) do\n    cond do\n      disjoint?(head1, head2) -> :disjoint\n      subtype? and subtype?(head1, head2) -> tuple_leaf_difference(tail1, tail2, subtype?)\n      true -> :none\n    end\n  end\n\n  defp tuple_leaf_difference(_tail1, _tail2, subtype?) do\n    if subtype?, do: :subtype, else: :none\n  end\n\n  defp non_empty_tuple_literals_intersection(tuples) do\n    try do\n      Enum.reduce(tuples, {:open, []}, fn {next_tag, next_elements}, {tag, elements} ->\n        case tuple_literal_intersection(tag, elements, next_tag, next_elements) do\n          :empty -> throw(:empty)\n          next -> next\n        end\n      end)\n    catch\n      :empty -> :empty\n    end\n  end\n\n  defp tuple_empty?(bdd) do\n    bdd_to_dnf(bdd)\n    |> Enum.all?(fn {pos, negs} ->\n      case non_empty_tuple_literals_intersection(pos) do\n        :empty -> true\n        {tag, fields} -> tuple_line_empty?(tag, fields, negs)\n      end\n    end)\n  end\n\n  # No negations, so not empty unless there's an empty type\n  # Note: since the extraction from the BDD is done in a way that guarantees that\n  # the elements are non-empty, we can avoid checking for empty types there.\n  # Otherwise, tuple_empty?(_, elements, []) would be Enum.any?(elements, &empty?/1)\n  defp tuple_line_empty?(_, _, []), do: false\n  # Open empty negation makes it empty\n  defp tuple_line_empty?(_, _, [{:open, []} | _]), do: true\n  # Open positive can't be emptied by a single closed negative\n  defp tuple_line_empty?(:open, _pos, [{:closed, _}]), do: false\n\n  defp tuple_line_empty?(tag, elements, [{neg_tag, neg_elements} | negs]) do\n    n = length(elements)\n    m = length(neg_elements)\n\n    # Scenarios where the difference is guaranteed to be empty:\n    # 1. When removing larger tuples from a fixed-size positive tuple\n    # 2. When removing smaller tuples from larger tuples\n    if (tag == :closed and n < m) or (neg_tag == :closed and n > m) do\n      tuple_line_empty?(tag, elements, negs)\n    else\n      tuple_elements_empty?([], tag, elements, neg_elements, negs) and\n        tuple_empty_arity?(n, m, tag, elements, neg_tag, negs)\n    end\n  end\n\n  # Recursively check elements for emptiness\n  defp tuple_elements_empty?(_, _, _, [], _), do: true\n\n  defp tuple_elements_empty?(acc_meet, tag, elements, [neg_type | neg_elements], negs) do\n    # Handles the case where {tag, elements} is an open tuple, like {:open, []}\n    {ty, elements} = List.pop_at(elements, 0, term())\n    diff = difference(ty, neg_type)\n    meet = intersection(ty, neg_type)\n\n    # In this case, there is no intersection between the positive and this negative.\n    # So we should just \"go next\"\n    (empty?(diff) or tuple_line_empty?(tag, Enum.reverse(acc_meet, [diff | elements]), negs)) and\n      (empty?(meet) or tuple_elements_empty?([meet | acc_meet], tag, elements, neg_elements, negs))\n  end\n\n  # Determines if the set difference is empty when:\n  # - Positive tuple: {tag, elements} of size n\n  # - Negative tuple: open or closed tuples of size m\n  defp tuple_empty_arity?(n, m, tag, elements, neg_tag, negs) do\n    # The tuples to consider are all those of size n to m - 1, and if the negative tuple is\n    # closed, we also need to consider tuples of size greater than m + 1.\n    tag == :closed or\n      (Enum.all?(n..(m - 1)//1, &tuple_line_empty?(:closed, tuple_fill(elements, &1), negs)) and\n         (neg_tag == :open or tuple_line_empty?(:open, tuple_fill(elements, m + 1), negs)))\n  end\n\n  defp tuple_eliminate_negations(tag, elements, negs) do\n    Enum.reduce(negs, [{tag, elements}], fn {neg_tag, neg_elements}, acc ->\n      Enum.flat_map(acc, fn {tag, elements} ->\n        tuple_eliminate_single_negation(tag, elements, {neg_tag, neg_elements})\n      end)\n    end)\n  end\n\n  # Important: this generates DISJOINT tuples.\n  defp tuple_eliminate_single_negation(tag, elements, {neg_tag, neg_elements}) do\n    n = length(elements)\n    m = length(neg_elements)\n\n    # Scenarios where the difference is guaranteed to be empty:\n    # 1. When removing larger tuples from a fixed-size positive tuple\n    # 2. When removing smaller tuples from larger tuples\n    # 3. When there is no intersection between the elements of the two tuples\n    if (tag == :closed and n < m) or (neg_tag == :closed and n > m) or\n         zip_empty_intersection?(elements, neg_elements) do\n      [{tag, elements}]\n    else\n      tuple_dnf_union(\n        tuple_elim_size(n, m, tag, elements, neg_tag),\n        tuple_elim_content([], tag, elements, neg_elements)\n      )\n    end\n  end\n\n  # Build a disjoint disjunction for {t1,...,tn} /\\ not {u1,...,un}\n  # by splitting on the *earliest* index where they differ.\n  #\n  # Invariant:\n  # - `acc` holds the prefix we've already forced to *match* the negative tuple,\n  #   stored in reverse order (so we can `Enum.reverse/2` at the end when we emit).\n  # - `elements` are the yet-unprocessed positive tuple element types.\n  # - `neg_elements` are the corresponding negative tuple element types.\n  #\n  # For position i:\n  #   - One branch mismatches here:  (ti \\ ui), with earlier positions fixed to intersection(tj, uj).\n  #   - The other recursive path forces match here: intersection(ti, ui) and continues to i+1.\n  #\n  # This yields disjoint branches like:\n  #   {t1 /\\ not u1, t2, t3, ...} OR {t1 /\\ u1, t2 /\\ not u2, t3, ...} OR {t1/\\u1, t2/\\u2, t3/\\ not u3, ...} ...\n  defp tuple_elim_content(acc, tag, elements, [neg_type | neg_elements]) do\n    # If `elements` is shorter, default to top type `term()` (as in your example).\n    [ty | rest] =\n      case elements do\n        [] -> [term()]\n        [_ | _] -> elements\n      end\n\n    # ti \\ ui  (i.e., ti and not ui)\n    diff = difference(ty, neg_type)\n    # ti /\\ ui\n    meet = intersection(ty, neg_type)\n\n    # Branch where the earliest difference is *here*.\n    # Earlier positions are the accumulated matches in `acc`;\n    # later positions remain unconstrained (`rest` as-is).\n    here_branch =\n      if empty?(diff) do\n        []\n      else\n        [{tag, Enum.reverse(acc, [diff | rest])}]\n      end\n\n    # Branches where we force equality here and defer the first difference to later positions.\n    later_branches =\n      if empty?(meet) do\n        []\n      else\n        tuple_elim_content([meet | acc], tag, rest, neg_elements)\n      end\n\n    here_branch ++ later_branches\n  end\n\n  # No more negative elements to process: there is no \"all-equal\" branch to add,\n  # because we're constructing {t} ant not {u}, which must differ somewhere.\n  defp tuple_elim_content(_acc, _tag, _elements, []) do\n    []\n  end\n\n  # Eliminates negations according to size\n  # Example: {integer(), ...} and not {term(), term(), ...} contains {integer()}\n  # The tuples to consider are all those of size n to m - 1, and if the negative tuple is\n  # closed, we also need to consider tuples of size greater than m + 1.\n  defp tuple_elim_size(_, _, :closed, _, _), do: []\n\n  defp tuple_elim_size(n, m, :open, elements, neg_tag) do\n    acc =\n      if neg_tag == :open do\n        []\n      else\n        [{:open, tuple_fill(elements, m + 1)}]\n      end\n\n    Enum.reduce(n..(m - 1)//1, acc, fn i, acc ->\n      [{:closed, tuple_fill(elements, i)} | acc]\n    end)\n  end\n\n  # Prefer the smaller on the left\n  defp tuple_dnf_union(dnf1, dnf2) do\n    # Union of tuple DNFs is just concatenation,\n    # but we do our best to remove duplicates.\n    with [tuple1] <- dnf1,\n         [tuple2] <- dnf2,\n         optimized when optimized != nil <- maybe_optimize_tuple_union(tuple1, tuple2) do\n      [optimized]\n    else\n      _ -> dnf1 ++ (dnf2 -- dnf1)\n    end\n  end\n\n  defp tuple_union(\n         bdd_leaf(tag1, elements1) = tuple1,\n         bdd_leaf(tag2, elements2) = tuple2\n       ) do\n    case maybe_optimize_tuple_union({tag1, elements1}, {tag2, elements2}) do\n      {tag, elements} -> bdd_leaf(tag, elements)\n      nil -> bdd_union(tuple1, tuple2)\n    end\n  end\n\n  @compile {:inline, tuple_union: 2}\n  defp tuple_union(bdd1, bdd2), do: bdd_union(bdd1, bdd2)\n\n  defp maybe_optimize_tuple_union({tag1, pos1} = tuple1, {tag2, pos2} = tuple2) do\n    case tuple_union_strategy(tag1, pos1, tag2, pos2) do\n      :all_equal ->\n        tuple1\n\n      {:one_index_difference, index, v1, v2} ->\n        new_pos = List.replace_at(pos1, index, union(v1, v2))\n        {tag1, new_pos}\n\n      :left_subtype_of_right ->\n        tuple2\n\n      :right_subtype_of_left ->\n        tuple1\n\n      :none ->\n        nil\n    end\n  end\n\n  defp tuple_union_strategy(tag1, pos1, tag2, pos2) do\n    case {tag1, tag2} do\n      {tag, tag} when length(pos1) == length(pos2) ->\n        tuple_union_strategy_index(pos1, pos2, 0, :all_equal)\n\n      {:open, _} when length(pos1) <= length(pos2) ->\n        tuple_union_strategy_index(pos1, pos2, 0, :right_subtype_of_left)\n\n      {_, :open} when length(pos1) >= length(pos2) ->\n        tuple_union_strategy_index(pos1, pos2, 0, :left_subtype_of_right)\n\n      {_, _} ->\n        :none\n    end\n  end\n\n  defp tuple_union_strategy_index([v | pos1], [v | pos2], i, status) do\n    tuple_union_strategy_index(pos1, pos2, i + 1, status)\n  end\n\n  defp tuple_union_strategy_index([v1 | pos1], [v2 | pos2], i, status) do\n    case status do\n      :all_equal ->\n        tuple_union_strategy_index(pos1, pos2, i + 1, {:one_index_difference, i, v1, v2})\n\n      {:one_index_difference, _, d1, d2} ->\n        cond do\n          subtype?(d1, d2) and subtype?(v1, v2) ->\n            tuple_union_strategy_index(pos1, pos2, i + 1, :left_subtype_of_right)\n\n          subtype?(d2, d1) and subtype?(v2, v1) ->\n            tuple_union_strategy_index(pos1, pos2, i + 1, :right_subtype_of_left)\n\n          true ->\n            :none\n        end\n\n      :left_subtype_of_right ->\n        if subtype?(v1, v2),\n          do: tuple_union_strategy_index(pos1, pos2, i + 1, :left_subtype_of_right),\n          else: :none\n\n      :right_subtype_of_left ->\n        if subtype?(v2, v1),\n          do: tuple_union_strategy_index(pos1, pos2, i + 1, :right_subtype_of_left),\n          else: :none\n    end\n  end\n\n  defp tuple_union_strategy_index(_pos1, _pos2, _i, status) do\n    status\n  end\n\n  defp tuple_to_quoted(bdd, opts) do\n    tuple_bdd_to_dnf_with_negations(bdd)\n    |> tuple_fusion()\n    |> Enum.map(&tuple_literal_to_quoted(&1, opts))\n  end\n\n  # Transforms a bdd into a union of tuples with no negations.\n  # Note: it is important to compose the results with\n  # tuple_dnf_union/2 to avoid duplicates\n  defp tuple_bdd_to_dnf_no_negations(bdd) do\n    bdd_to_dnf(bdd)\n    |> Enum.reduce([], fn {pos, negs}, acc ->\n      case non_empty_tuple_literals_intersection(pos) do\n        :empty ->\n          acc\n\n        {tag, elements} ->\n          if tuple_line_empty?(tag, elements, negs) do\n            acc\n          else\n            tuple_eliminate_negations(tag, elements, negs) |> tuple_dnf_union(acc)\n          end\n      end\n    end)\n  end\n\n  defp tuple_bdd_to_dnf_with_negations(bdd) do\n    bdd_to_dnf(bdd)\n    |> Enum.reduce([], fn {pos, negs}, acc ->\n      case non_empty_tuple_literals_intersection(pos) do\n        :empty ->\n          acc\n\n        {tag, elements} ->\n          if tuple_line_empty?(tag, elements, negs) do\n            acc\n          else\n            [{tag, elements, negs} | acc]\n          end\n      end\n    end)\n  end\n\n  # Given a union of tuples, fuses the tuple unions when possible,\n  # e.g. {integer(), atom()} or {float(), atom()} into {number(), atom()}\n  # The negations of two fused tuples are just concatenated.\n  #\n  # Steps:\n  # 1. Consider tuples without negations apart from those with\n  # 2. Group tuples by size and tag\n  # 3. Try fusions for each group until no fusion is found\n  # 4. Merge the groups back into a dnf\n  defp tuple_fusion(dnf) do\n    {with_negs, without_negs} =\n      Enum.reduce(dnf, {[], %{}}, fn\n        {tag, elements, []}, {with, without} ->\n          key = {tag, length(elements)}\n          value = {tag, elements}\n          {with, Map.update(without, key, [value], &[value | &1])}\n\n        triplet, {with, without} ->\n          {[triplet | with], without}\n      end)\n\n    Enum.reduce(without_negs, with_negs, fn {_, tuples}, with_negs ->\n      tuples\n      |> Enum.reduce([], fn tuple, acc ->\n        tuple_fuse_with_first_fusible(tuple, acc)\n      end)\n      |> Enum.reduce(with_negs, fn {tag, elements}, with_negs ->\n        [{tag, elements, []} | with_negs]\n      end)\n    end)\n  end\n\n  defp tuple_fuse_with_first_fusible(tuple, []), do: [tuple]\n\n  defp tuple_fuse_with_first_fusible(tuple, [candidate | rest]) do\n    if fused = maybe_optimize_tuple_union(tuple, candidate) do\n      # we found a fusible candidate, we're done\n      [fused | rest]\n    else\n      [candidate | tuple_fuse_with_first_fusible(tuple, rest)]\n    end\n  end\n\n  defp tuple_literal_to_quoted({:closed, [], []}, _opts), do: {:{}, [], []}\n\n  defp tuple_literal_to_quoted({tag, elements, negs}, opts) do\n    pos = tuple_fields_to_quoted(tag, elements, opts)\n\n    Enum.reduce(negs, pos, fn {tag, elements}, acc ->\n      {:and, [], [acc, {:not, [], [tuple_fields_to_quoted(tag, elements, opts)]}]}\n    end)\n  end\n\n  defp tuple_fields_to_quoted(tag, elements, opts) do\n    case tag do\n      :closed -> {:{}, [], Enum.map(elements, &to_quoted(&1, opts))}\n      :open -> {:{}, [], Enum.map(elements, &to_quoted(&1, opts)) ++ [{:..., [], nil}]}\n    end\n  end\n\n  # Pads a list of elements with term().\n  defp tuple_fill(elements, desired_length) do\n    pad_length = desired_length - length(elements)\n\n    if pad_length < 0 do\n      raise ArgumentError, \"tuple_fill: elements are longer than the desired length\"\n    else\n      elements ++ List.duplicate(term(), pad_length)\n    end\n  end\n\n  @doc \"\"\"\n  Fetches the type of the value returned by accessing `index` on `tuple`\n  with the assumption that the descr is exclusively a tuple (or dynamic).\n\n  Returns one of:\n\n  - `{false, type}` if the element is always accessible and has the given `type`.\n  - `{true, type}` if the element is dynamically optional and has the given `type`.\n  - `:badindex` if the index is never accessible in the tuple type.\n  - `:badtuple` if the descr is not a tuple type.\n\n  ## Examples\n\n      iex> tuple_fetch(tuple([integer(), atom()]), 0)\n      {false, integer()}\n\n      iex> tuple_fetch(union(tuple([integer()]), tuple([integer(), atom()])), 1)\n      {true, atom()}\n\n      iex> tuple_fetch(dynamic(), 0)\n      {true, dynamic()}\n\n      iex> tuple_fetch(integer(), 0)\n      :badtuple\n\n  \"\"\"\n  def tuple_fetch(_, index) when index < 0, do: :badindex\n  def tuple_fetch(:term, _key), do: :badtuple\n\n  def tuple_fetch(%{} = descr, key) when is_integer(key) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        if descr_key?(descr, :tuple) and non_empty_tuple_only?(descr) do\n          {static_optional?, static_type} = tuple_fetch_static(descr, key)\n\n          # If I access a static tuple at a \"open position\", we have two options:\n          #\n          # 1. Do not allow the access and return :badindex,\n          #    you must use dynamic for these cases (this is what we chose for maps)\n          #\n          # 2. Allow the access and return the static type\n          #\n          # The trouble with allowing the access is that it is a potential runtime\n          # error not being caught by the type system.\n          #\n          # Furthermore, our choice here, needs to be consistent with elem/put_elem\n          # when the index is the `integer()` type. If we choose to return `:badindex`,\n          # then all elem/put_elem with an `integer()` and the tuple is not dynamic\n          # should also be a static typing error. We chose to go with 1.\n          if static_optional? or empty?(static_type) do\n            :badindex\n          else\n            {false, static_type}\n          end\n        else\n          :badtuple\n        end\n\n      {dynamic, static} ->\n        if descr_key?(dynamic, :tuple) and tuple_only?(static) do\n          {dynamic_optional?, dynamic_type} = tuple_fetch_static(dynamic, key)\n          {static_optional?, static_type} = tuple_fetch_static(static, key)\n\n          if empty?(dynamic_type) do\n            :badindex\n          else\n            {static_optional? or dynamic_optional?, union(dynamic(dynamic_type), static_type)}\n          end\n        else\n          :badtuple\n        end\n    end\n  end\n\n  defp tuple_only?(descr), do: empty?(Map.delete(descr, :tuple))\n\n  defp non_empty_tuple_only?(descr) do\n    case :maps.take(:tuple, descr) do\n      :error -> false\n      {tuple_bdd, rest} -> empty?(rest) and not tuple_empty?(tuple_bdd)\n    end\n  end\n\n  defp tuple_fetch_static(descr, index) when is_integer(index) do\n    case descr do\n      :term -> {true, term()}\n      %{tuple: bdd_leaf(tag, elements)} -> tuple_fetch_element(elements, index, tag)\n      %{tuple: bdd} -> tuple_bdd_fetch_static(bdd, index)\n      %{} -> {false, none()}\n    end\n  end\n\n  defp tuple_bdd_fetch_static(bdd, index) do\n    bdd\n    |> tuple_bdd_to_dnf_with_negations()\n    |> Enum.reduce({false, none()}, fn\n      # Optimization: if there are no negatives\n      {tag, elements, []}, {acc_optional?, acc_descr} ->\n        {optional?, descr} = tuple_fetch_element(elements, index, tag)\n        {optional? or acc_optional?, union(descr, acc_descr)}\n\n      {tag, elements, negs}, acc ->\n        {_, value, bdd} = tuple_take_element(elements, index, tag)\n\n        negs\n        |> tuple_split_negative(index, value, bdd)\n        |> Enum.reduce(acc, fn {value, _}, {acc_optional?, acc_descr} ->\n          {optional?, descr} = pop_optional_static(value)\n          {optional? or acc_optional?, union(descr, acc_descr)}\n        end)\n    end)\n  catch\n    :open -> {true, term()}\n  end\n\n  # Remove negatives:\n  # {t, s} \\ {t₁, s₁} = {t \\ t₁, s} ∪ {t ∩ t₁, s \\ s₁}\n  defp tuple_split_negative(negs, index, value, bdd) do\n    Enum.reduce(negs, [{value, bdd}], fn\n      {:open, []}, _acc ->\n        throw(:empty)\n\n      {neg_tag, neg_elements}, acc ->\n        {found?, neg_value, neg_bdd} = tuple_take_element(neg_elements, index, neg_tag)\n\n        if not found? and neg_tag == :open do\n          # In case the tuple is open, t \\ t₁ is always empty,\n          # t ∩ t₁ is always t, so we just need to deal with the bdd.\n          Enum.reduce(acc, [], fn {value, bdd}, acc ->\n            diff_bdd = tuple_difference(bdd, neg_bdd)\n\n            if tuple_empty?(diff_bdd) do\n              acc\n            else\n              [{value, diff_bdd} | acc]\n            end\n          end)\n        else\n          Enum.reduce(acc, [], fn {value, bdd}, acc ->\n            # If the negative tag is closed, then they are likely disjoint,\n            # so we can drastically cut down the amount of operations.\n            if neg_tag == :closed and tuple_empty?(tuple_intersection(bdd, neg_bdd)) do\n              [{value, bdd} | acc]\n            else\n              intersection_value = intersection(value, neg_value)\n\n              if empty?(intersection_value) do\n                [{value, bdd} | acc]\n              else\n                diff_bdd = tuple_difference(bdd, neg_bdd)\n\n                if tuple_empty?(diff_bdd) do\n                  prepend_pair_unless_empty_diff(value, neg_value, bdd, acc)\n                else\n                  acc = [{intersection_value, diff_bdd} | acc]\n                  prepend_pair_unless_empty_diff(value, neg_value, bdd, acc)\n                end\n              end\n            end\n          end)\n        end\n    end)\n  catch\n    :empty -> []\n  end\n\n  defp tuple_fetch_element([], _, :open), do: {true, term()}\n  defp tuple_fetch_element([], _, :closed), do: {true, none()}\n  defp tuple_fetch_element([h | _], 0, _tag), do: {false, h}\n  defp tuple_fetch_element([_ | t], i, tag), do: tuple_fetch_element(t, i - 1, tag)\n\n  defp tuple_take_element(elements, index, tag) do\n    case do_tuple_take_element(elements, index, []) do\n      :error -> {false, tuple_tag_to_type(tag), tuple_new(tag, elements)}\n      {value, elements} -> {true, value, tuple_new(tag, elements)}\n    end\n  end\n\n  defp do_tuple_take_element([], _, _), do: :error\n  defp do_tuple_take_element([h | t], 0, acc), do: {h, Enum.reverse(acc, t)}\n  defp do_tuple_take_element([h | t], i, acc), do: do_tuple_take_element(t, i - 1, [h | acc])\n\n  defp tuple_tag_to_type(:open), do: term_or_optional()\n  defp tuple_tag_to_type(:closed), do: none()\n\n  @doc \"\"\"\n  Returns all of the values that are part of a tuple.\n  \"\"\"\n  def tuple_values(descr) when descr == %{}, do: :badtuple\n\n  def tuple_values(descr) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        if tuple_only?(descr) do\n          process_tuples_values(Map.get(descr, :tuple, :bdd_bot))\n        else\n          :badtuple\n        end\n\n      {dynamic, static} ->\n        if tuple_only?(static) and descr_key?(dynamic, :tuple) do\n          dynamic(process_tuples_values(Map.get(dynamic, :tuple, :bdd_bot)))\n          |> union(process_tuples_values(Map.get(static, :tuple, :bdd_bot)))\n        else\n          :badtuple\n        end\n    end\n  end\n\n  defp process_tuples_values(bdd) do\n    tuple_bdd_to_dnf_no_negations(bdd)\n    |> Enum.reduce(none(), fn {tag, elements}, acc ->\n      cond do\n        Enum.any?(elements, &empty?/1) -> none()\n        tag == :open -> term()\n        tag == :closed -> Enum.reduce(elements, none(), &union/2)\n      end\n      |> union(acc)\n    end)\n  end\n\n  @doc \"\"\"\n  Delete an element from the tuple.\n\n  It returns the same as `tuple_fetch/2`.\n  \"\"\"\n  # Same as tuple_delete but checks if the index is out of range.\n  def tuple_delete_at(:term, _key), do: :badtuple\n\n  def tuple_delete_at(descr, index) when is_integer(index) and index >= 0 do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        # Note: the empty type is not a valid input\n        is_proper_tuple? = descr_key?(descr, :tuple) and tuple_only?(descr)\n        is_proper_size? = tuple_of_size_at_least_static?(descr, index + 1)\n\n        cond do\n          is_proper_tuple? and is_proper_size? -> tuple_delete_static(descr, index)\n          is_proper_tuple? -> :badindex\n          true -> :badtuple\n        end\n\n      {dynamic, static} ->\n        is_proper_tuple? = descr_key?(dynamic, :tuple) and tuple_only?(static)\n        is_proper_size? = tuple_of_size_at_least_static?(static, index + 1)\n\n        cond do\n          is_proper_tuple? and is_proper_size? ->\n            static_result = tuple_delete_static(static, index)\n\n            # Prune for dynamic values make the intersection succeed\n            dynamic_result =\n              intersection(dynamic, tuple_of_size_at_least(index))\n              |> tuple_delete_static(index)\n\n            union(dynamic(dynamic_result), static_result)\n\n          # Highlight the case where the issue is an index out of range from the tuple\n          is_proper_tuple? ->\n            :badindex\n\n          true ->\n            :badtuple\n        end\n    end\n  end\n\n  def tuple_delete_at(_, _), do: :badindex\n\n  # Takes a static map type and removes an index from it.\n  defp tuple_delete_static(%{tuple: bdd}, index) do\n    %{tuple: bdd_map(bdd, fn {tag, elements} -> {tag, List.delete_at(elements, index)} end)}\n  end\n\n  # If there is no map part to this static type, there is nothing to delete.\n  defp tuple_delete_static(_type, _key), do: none()\n\n  @doc \"\"\"\n  Insert an element at the tuple.\n\n  It returns the same as `tuple_fetch/2`. Notice, however, the range for indexes is inclusive.\n  \"\"\"\n  def tuple_insert_at(:term, _key, _type), do: :badtuple\n\n  def tuple_insert_at(descr, index, type) when is_integer(index) and index >= 0 do\n    case :maps.take(:dynamic, unfold(type)) do\n      :error -> tuple_insert_at_checked(descr, index, type)\n      {dynamic, _static} -> dynamic(tuple_insert_at_checked(descr, index, dynamic))\n    end\n  end\n\n  def tuple_insert_at(_, _, _), do: :badindex\n\n  defp tuple_insert_at_checked(descr, index, type) do\n    case :maps.take(:dynamic, descr) do\n      :error ->\n        # Note: the empty type is not a valid input\n        is_proper_tuple? = descr_key?(descr, :tuple) and tuple_only?(descr)\n        is_proper_size? = index == 0 or tuple_of_size_at_least_static?(descr, index)\n\n        cond do\n          is_proper_tuple? and is_proper_size? -> tuple_insert_static(descr, index, type)\n          is_proper_tuple? -> :badindex\n          true -> :badtuple\n        end\n\n      {dynamic, static} ->\n        is_proper_tuple? = descr_key?(dynamic, :tuple) and tuple_only?(static)\n        is_proper_size? = index == 0 or tuple_of_size_at_least_static?(static, index)\n\n        cond do\n          is_proper_tuple? and is_proper_size? ->\n            static_result = tuple_insert_static(static, index, type)\n\n            # Prune for dynamic values that make the intersection succeed\n            dynamic_result =\n              intersection(dynamic, tuple_of_size_at_least(index))\n              |> tuple_insert_static(index, type)\n\n            union(dynamic(dynamic_result), static_result)\n\n          # Highlight the case where the issue is an index out of range from the tuple\n          is_proper_tuple? ->\n            :badindex\n\n          true ->\n            :badtuple\n        end\n    end\n  end\n\n  defp tuple_insert_static(descr, _, _) when descr == @none, do: none()\n\n  defp tuple_insert_static(descr, index, type) do\n    Map.update!(descr, :tuple, fn bdd ->\n      bdd_map(bdd, fn {tag, elements} ->\n        {tag, List.insert_at(elements, index, type)}\n      end)\n    end)\n  end\n\n  defp tuple_of_size_at_least(n) when is_integer(n) and n >= 0 do\n    %{tuple: tuple_new(:open, List.duplicate(term(), n))}\n  end\n\n  defp tuple_of_size_at_least_static?(descr, index) do\n    case descr do\n      %{tuple: bdd} ->\n        tuple_bdd_to_dnf_no_negations(bdd)\n        |> Enum.all?(fn {_, elements} -> length(elements) >= index end)\n\n      %{} ->\n        true\n    end\n  end\n\n  ## BDD helpers\n\n  def bdd_union(bdd1, bdd2) do\n    case {bdd1, bdd2} do\n      {:bdd_top, _bdd} ->\n        :bdd_top\n\n      {_bdd, :bdd_top} ->\n        :bdd_top\n\n      {:bdd_bot, bdd} ->\n        bdd\n\n      {bdd, :bdd_bot} ->\n        bdd\n\n      _ ->\n        case bdd_compare(bdd1, bdd2) do\n          {:lt, {lit1, c1, u1, d1}, bdd2} ->\n            {lit1, c1, bdd_union(u1, bdd2), d1}\n\n          {:gt, bdd1, {lit2, c2, u2, d2}} ->\n            {lit2, c2, bdd_union(bdd1, u2), d2}\n\n          {:eq, {lit, c1, u1, d1}, {_, c2, u2, d2}} ->\n            {lit, bdd_union(c1, c2), bdd_union(u1, u2), bdd_union(d1, d2)}\n\n          {:eq, {lit, _, u1, d1}, _} ->\n            {lit, :bdd_top, u1, d1}\n\n          {:eq, _, {lit, _, u2, d2}} ->\n            {lit, :bdd_top, u2, d2}\n\n          {:eq, _, _} ->\n            bdd1\n        end\n        |> case do\n          {_, :bdd_top, _, :bdd_top} -> :bdd_top\n          other -> other\n        end\n    end\n  end\n\n  def bdd_difference(bdd1, bdd2) do\n    case {bdd1, bdd2} do\n      {_bdd, :bdd_top} ->\n        :bdd_bot\n\n      {:bdd_bot, _bdd} ->\n        :bdd_bot\n\n      {bdd, :bdd_bot} ->\n        bdd\n\n      {:bdd_top, bdd} ->\n        bdd_negation(bdd)\n\n      _ ->\n        case bdd_compare(bdd1, bdd2) do\n          {:lt, {lit1, c1, u1, d1}, bdd2} ->\n            {lit1, bdd_difference(c1, bdd2), bdd_difference(u1, bdd2), bdd_difference(d1, bdd2)}\n\n          {:gt, bdd1, {lit2, c2, u2, d2}} ->\n            # The proper formula is:\n            #\n            #     b1 and not (c2 or u2) : bdd_bot : b1 and not (d2 or u2)\n            #\n            # Both extremes have (b1 and not u2), so we compute it once.\n            bdd1_minus_u2 = bdd_difference(bdd1, u2)\n            {lit2, bdd_difference(bdd1_minus_u2, c2), :bdd_bot, bdd_difference(bdd1_minus_u2, d2)}\n\n          {:eq, {lit, c1, u1, d1}, {_, c2, u2, d2}} ->\n            # The formula is:\n            # {a1, (C1 or U1) and not (C2 or U2), :bdd_bot, (D1 or U1) and not (D2 or U2)} when a1 == a2\n            #\n            # Constrained: (C1 and not C2 and not U2) or (U1 and not C2 and not U2)\n            # Dual: (D1 and not D2 and not U2) or (U1 and not D2 and not U2)\n            #\n            # We can optimize the cases below.\n            if u1 == :bdd_bot or u1 == u2 do\n              # Constrained = (C1 and not C2 and not U2)\n              # Dual = (D1 and not D2 and not U2)\n              # Hence:\n              {lit, bdd_difference_union(c1, c2, u2), :bdd_bot, bdd_difference_union(d1, d2, u2)}\n            else\n              c =\n                if c2 == :bdd_top,\n                  do: :bdd_bot,\n                  else: bdd_difference(bdd_union(c1, u1), bdd_union(c2, u2))\n\n              d =\n                if d2 == :bdd_top,\n                  do: :bdd_bot,\n                  else: bdd_difference(bdd_union(d1, u1), bdd_union(d2, u2))\n\n              {lit, c, :bdd_bot, d}\n            end\n\n          {:eq, _, {lit, c2, u2, _d2}} ->\n            {lit, bdd_negation(bdd_union(c2, u2)), :bdd_bot, :bdd_bot}\n\n          {:eq, {lit, _c1, u1, d1}, _} ->\n            {lit, :bdd_bot, :bdd_bot, bdd_union(d1, u1)}\n\n          {:eq, _, _} ->\n            :bdd_bot\n        end\n        |> case do\n          {_, :bdd_bot, u, :bdd_bot} -> u\n          other -> other\n        end\n    end\n  end\n\n  # Version of i \\ (u1 v u2) that only computes the union if i is not bottom\n  defp bdd_difference_union(:bdd_bot, _u1, _u2),\n    do: :bdd_bot\n\n  defp bdd_difference_union(i, u1, u2),\n    do: bdd_difference(i, bdd_union(u1, u2))\n\n  ## Optimize differences\n\n  # For the right-side being a leaf, we have:\n  #\n  #     ((a1 and C1) or U1 or (not a1 and D1)) and not a2\n  #\n  # If disjoint?(a1, a2), we end up with:\n  #\n  #     (a1 and C1) or (U1 and not a2) or (not a1 and D1 and not a2)\n  #\n  # If subtype?(a1, a2), we end up with:\n  #\n  #     (U1 and not a2) or (D1 and not a2)\n  #\n  # If one key difference, then we compute the difference\n  # and the union of said keys, returning a_union and a_diff:\n  #\n  #     ((a1 and C1) or U1 or (not a1 and D1)) and not a2\n  #     (a_diff and C1) or (U1 and not a2) or (not a_union and D1)\n  #\n  defp bdd_difference({a1, c1, u1, d1} = bdd1, bdd_leaf(_, _) = bdd2, leaf_compare)\n       when is_tuple(bdd2) do\n    case leaf_compare.(a1, bdd2, :union) do\n      :disjoint ->\n        res =\n          bdd_union(\n            bdd_difference(u1, bdd2, leaf_compare),\n            bdd_difference({a1, :bdd_bot, :bdd_bot, d1}, bdd2)\n          )\n\n        if c1 == :bdd_bot, do: res, else: bdd_union(res, {a1, c1, :bdd_bot, :bdd_bot})\n\n      {:one_key_difference, a_diff, a_union} ->\n        bdd_intersection(a_diff, c1)\n        |> bdd_union(bdd_difference(u1, bdd2, leaf_compare))\n        |> bdd_union(bdd_difference(d1, a_union, leaf_compare))\n\n      :subtype ->\n        bdd_union(bdd_difference(u1, bdd2, leaf_compare), bdd_difference(d1, bdd2, leaf_compare))\n\n      :none ->\n        bdd_difference(bdd1, bdd2)\n    end\n  end\n\n  # For the left-side being a leaf, we have:\n  #\n  #     a1 and not ((a2 and C2) or U2 or (not a2 and D2))\n  #     a1 and not (a2 and C2) and not U2 and (a2 or not D2)\n  #\n  # If disjoint?(a1, a2):\n  #\n  #     a1 and not (a2 and C2) = a1            (a2 and C2 is subset of a2, disjoint from a1)\n  #     a1 and (a2 or not D2) = a1 and not D2  (a1 and a2 = bottom)\n  #\n  # Result: a1 and not D2 and not U2\n  #\n  # If subtype?(a1, a2):\n  #\n  #     a1 and not (a2 and C2) = a1 and not C2 (a1 and not a2 = bottom)\n  #     a1 and (a2 or not D2) = a1             (a1 and a2 = a1)\n  #\n  # Result: a1 and not C2 and not U2\n  #\n  # If one key difference, then we compute the difference\n  # and the intersection of said keys, returning a_int and a_diff:\n  #\n  #     a1 and not (a2 and C2) and not U2 and (a2 or not D2)\n  #     ((a1 and not a2) or (a1 and not C2)) and not U2 and (a2 or not D2)\n  #     (a_diff or (a1 and not C2)) and not U2 and (a2 or not D2)\n  #\n  # Now distribute into (a2 or not D2):\n  #\n  #     ((a_diff and (a2 or not D2)) or\n  #      ((a1 and not C2) and (a2 or not D2))) and not U2\n  #     ((a_diff and not D2) or\n  #      (a_int and not C2) or\n  #      (a1 and not C2 and not D2)) and not U2\n  #\n  # Now, we know that a1 is a_diff or a_int, which means\n  # (a1 and not C2 and not D2) is a subset of the other two\n  # expressions, so we end up with:\n  #\n  #     ((a_diff and not D2) or (a_int and not C2)) and not U2\n  #\n  defp bdd_difference(bdd_leaf(_, _) = bdd1, bdd2, leaf_compare) when is_tuple(bdd2) do\n    {a2, c2, u2, d2} = bdd_expand(bdd2)\n    type = if c2 == :bdd_top, do: :none, else: :intersection\n\n    case leaf_compare.(bdd1, a2, type) do\n      :disjoint ->\n        bdd1 |> bdd_difference(d2, leaf_compare) |> bdd_difference(u2, leaf_compare)\n\n      {:one_key_difference, a_diff, a_int} ->\n        bdd_union(\n          a_diff |> bdd_difference(d2, leaf_compare) |> bdd_difference(u2, leaf_compare),\n          a_int |> bdd_difference(c2, leaf_compare) |> bdd_difference(u2, leaf_compare)\n        )\n\n      :subtype ->\n        bdd1 |> bdd_difference(c2, leaf_compare) |> bdd_difference(u2, leaf_compare)\n\n      :none ->\n        bdd_difference(bdd1, bdd2)\n    end\n  end\n\n  defp bdd_difference(bdd1, bdd2, _leaf_compare) do\n    bdd_difference(bdd1, bdd2)\n  end\n\n  def bdd_intersection(bdd1, bdd2) do\n    case {bdd1, bdd2} do\n      {:bdd_top, bdd} ->\n        bdd\n\n      {bdd, :bdd_top} ->\n        bdd\n\n      {:bdd_bot, _bdd} ->\n        :bdd_bot\n\n      {_, :bdd_bot} ->\n        :bdd_bot\n\n      _ ->\n        case bdd_compare(bdd1, bdd2) do\n          {:lt, {lit1, c1, u1, d1}, bdd2} ->\n            {lit1, bdd_intersection(c1, bdd2), bdd_intersection(u1, bdd2),\n             bdd_intersection(d1, bdd2)}\n\n          {:gt, bdd1, {lit2, c2, u2, d2}} ->\n            {lit2, bdd_intersection(bdd1, c2), bdd_intersection(bdd1, u2),\n             bdd_intersection(bdd1, d2)}\n\n          # Notice that (a, c1, u1, d1) and (a, c2, u2, d2) is described as:\n          #\n          #     {a, (C1 or U1) and (C2 or U2), :bdd_bot, (D1 or U1) and (D2 or U2)}\n          #\n          # However, if we distribute the intersection over the unions, we find a\n          # common term, U1 and U2, leading to:\n          #\n          #     {a1,\n          #      (C1 and (C2 or U2)) or (U1 and C2),\n          #      (U1 and U2),\n          #      (D1 and (D2 or U2)) or (U1 and D2)}\n          #\n          # This formula is longer, meaning more operations, but it does preserve\n          # unions in place whenever possible. This change has reduced the algorithmic\n          # complexity in the past, but perhaps it is rendered less useful now due to\n          # the eager literal intersections.\n          {:eq, {lit, c1, u1, d1}, {_, c2, u2, d2}} ->\n            {lit, bdd_intersection_eq(c1, c2, u1, u2), bdd_intersection(u1, u2),\n             bdd_intersection_eq(d1, d2, u1, u2)}\n\n          {:eq, {lit, c1, u1, _}, _} ->\n            {lit, bdd_union(c1, u1), :bdd_bot, :bdd_bot}\n\n          {:eq, _, {lit, c2, u2, _}} ->\n            {lit, bdd_union(c2, u2), :bdd_bot, :bdd_bot}\n\n          {:eq, bdd, _} ->\n            bdd\n        end\n        |> case do\n          {_, :bdd_bot, u, :bdd_bot} -> u\n          other -> other\n        end\n    end\n  end\n\n  # The arms of bdd_intersect equal have shape:\n  #\n  # (C1 and C2) or (C1 and U2) or (U1 and C2)\n  # (D1 and D2) or (D1 and U2) or (U1 and D2)\n  #\n  # They are symmetrical, so we optimize it using the formula below,\n  # which also deals with cases that lead to large eliminations.\n  #\n  # The final clause reduces the amount of operations by rewriting it to:\n  # (C1 and (C2 or U2)) or (U1 and C2)\n  defp bdd_intersection_eq(:bdd_top, :bdd_top, _u1, _u2), do: :bdd_top\n\n  defp bdd_intersection_eq(:bdd_bot, cd2, u1, _u2), do: bdd_intersection(u1, cd2)\n  defp bdd_intersection_eq(cd1, :bdd_bot, _u1, u2), do: bdd_intersection(u2, cd1)\n  defp bdd_intersection_eq(cd1, cd2, :bdd_bot, u2), do: bdd_intersection(cd1, bdd_union(cd2, u2))\n  defp bdd_intersection_eq(cd1, cd2, u1, :bdd_bot), do: bdd_intersection(cd2, bdd_union(cd1, u1))\n\n  defp bdd_intersection_eq(cd1, cd2, u1, u2) do\n    bdd_union(bdd_intersection(cd1, bdd_union(cd2, u2)), bdd_intersection(u1, cd2))\n  end\n\n  # Intersections are great because they allow us to cut down\n  # the number of nodes in the tree. So whenever we have a leaf,\n  # we actually propagate it throughout the whole tree, cutting\n  # down nodes.\n  defp bdd_intersection(bdd_leaf(_, _) = leaf, bdd, leaf_intersection) do\n    bdd_leaf_intersection(leaf, bdd, leaf_intersection)\n  end\n\n  defp bdd_intersection(bdd, bdd_leaf(_, _) = leaf, leaf_intersection) do\n    bdd_leaf_intersection(leaf, bdd, leaf_intersection)\n  end\n\n  # Take two BDDs, B1 = {a1, C1, U2, D2} and B2.\n  # We can treat a1 as a leaf if C1 = :bdd_top.\n  # Then we have:\n  #\n  #     ((a1 and C1) or U2 or (not a1 and D2)) and B2\n  #\n  # Which is equivalent to:\n  #\n  #     (a1 and B2) or (B2 and U2) or (B2 and not a1 and D2)\n  defp bdd_intersection({leaf, :bdd_top, u, d}, bdd, leaf_intersection) do\n    bdd_leaf_intersection(leaf, bdd, leaf_intersection)\n    |> bdd_union(bdd_intersection(u, bdd, leaf_intersection))\n    |> case do\n      result when d == :bdd_bot -> result\n      result -> bdd_union(result, bdd_intersection(bdd, {leaf, :bdd_bot, :bdd_bot, d}))\n    end\n  end\n\n  defp bdd_intersection(bdd, {leaf, :bdd_top, u, d}, leaf_intersection) do\n    bdd_leaf_intersection(leaf, bdd, leaf_intersection)\n    |> bdd_union(bdd_intersection(u, bdd, leaf_intersection))\n    |> case do\n      result when d == :bdd_bot -> result\n      result -> bdd_union(result, bdd_intersection(bdd, {leaf, :bdd_bot, :bdd_bot, d}))\n    end\n  end\n\n  defp bdd_intersection(bdd1, bdd2, _leaf_intersection) do\n    bdd_intersection(bdd1, bdd2)\n  end\n\n  defp bdd_leaf_intersection(leaf, bdd, intersection) do\n    case bdd do\n      :bdd_top ->\n        leaf\n\n      :bdd_bot ->\n        :bdd_bot\n\n      bdd_leaf(_, _) ->\n        intersection.(leaf, bdd)\n\n      {lit, c, u, _} when lit == leaf ->\n        case bdd_union(c, u) do\n          :bdd_bot -> :bdd_bot\n          cu -> {lit, cu, :bdd_bot, :bdd_bot}\n        end\n\n      {lit, c, u, d} ->\n        rest =\n          bdd_union(\n            bdd_leaf_intersection(leaf, u, intersection),\n            bdd_difference(bdd_leaf_intersection(leaf, d, intersection), lit)\n          )\n\n        with true <- c != :bdd_bot,\n             new_leaf = intersection.(leaf, lit),\n             true <- new_leaf != :bdd_bot do\n          bdd_union(bdd_leaf_intersection(new_leaf, c, intersection), rest)\n        else\n          _ -> rest\n        end\n    end\n  end\n\n  # Lazy negation: eliminate the union, then perform normal negation (switching leaves)\n  def bdd_negation(:bdd_top), do: :bdd_bot\n  def bdd_negation(:bdd_bot), do: :bdd_top\n  def bdd_negation({_, _} = pair), do: {pair, :bdd_bot, :bdd_bot, :bdd_top}\n\n  def bdd_negation({lit, c, u, d}) do\n    {lit, bdd_negation(bdd_union(c, u)), :bdd_bot, bdd_negation(bdd_union(d, u))}\n  end\n\n  def bdd_to_dnf(bdd), do: bdd_to_dnf([], [], [], bdd)\n\n  defp bdd_to_dnf(acc, _pos, _neg, :bdd_bot), do: acc\n  defp bdd_to_dnf(acc, pos, neg, :bdd_top), do: [{pos, neg} | acc]\n\n  defp bdd_to_dnf(acc, pos, neg, {_, _} = lit) do\n    [{[lit | pos], neg} | acc]\n  end\n\n  # Lazy node: {lit, C, U, D}  ≡  (lit ∧ C) ∪ U ∪ (¬lit ∧ D)\n  defp bdd_to_dnf(acc, pos, neg, {lit, c, u, d}) do\n    # U is a bdd in itself, we accumulate its lines first\n    bdd_to_dnf(acc, pos, neg, u)\n    # C-part\n    |> bdd_to_dnf([lit | pos], neg, c)\n    # D-part\n    |> bdd_to_dnf(pos, [lit | neg], d)\n  end\n\n  defp bdd_compare(bdd1, bdd2) do\n    case {bdd_head(bdd1), bdd_head(bdd2)} do\n      {lit1, lit2} when lit1 < lit2 -> {:lt, bdd_expand(bdd1), bdd2}\n      {lit1, lit2} when lit1 > lit2 -> {:gt, bdd1, bdd_expand(bdd2)}\n      _ -> {:eq, bdd1, bdd2}\n    end\n  end\n\n  defp bdd_map(bdd, fun) do\n    case bdd do\n      :bdd_bot ->\n        :bdd_bot\n\n      :bdd_top ->\n        :bdd_top\n\n      {_, _} ->\n        fun.(bdd)\n\n      {literal, left, union, right} ->\n        {fun.(literal), bdd_map(left, fun), bdd_map(union, fun), bdd_map(right, fun)}\n    end\n  end\n\n  defp bdd_reduce(bdd, acc, fun) do\n    case bdd do\n      :bdd_bot ->\n        acc\n\n      :bdd_top ->\n        acc\n\n      {_, _} ->\n        fun.(bdd, acc)\n\n      {literal, left, union, right} ->\n        acc = fun.(literal, acc)\n        acc = bdd_reduce(left, acc, fun)\n        acc = bdd_reduce(union, acc, fun)\n        acc = bdd_reduce(right, acc, fun)\n        acc\n    end\n  end\n\n  @compile {:inline, bdd_expand: 1, bdd_head: 1}\n  defp bdd_expand({_, _} = pair), do: {pair, :bdd_top, :bdd_bot, :bdd_bot}\n  defp bdd_expand(bdd), do: bdd\n\n  defp bdd_head({lit, _, _, _}), do: lit\n  defp bdd_head(pair), do: pair\n\n  ## Map helpers\n\n  # Erlang maps:merge_with/3 has to preserve the order in combiner.\n  # We don't care about the order, so we have a faster implementation.\n  defp symmetrical_merge(left, right, fun) do\n    if map_size(left) > map_size(right) do\n      iterator_merge(:maps.next(:maps.iterator(right)), left, fun)\n    else\n      iterator_merge(:maps.next(:maps.iterator(left)), right, fun)\n    end\n  end\n\n  defp iterator_merge({key, v1, iterator}, map, fun) do\n    acc =\n      case map do\n        %{^key => v2} -> %{map | key => fun.(key, v1, v2)}\n        %{} -> Map.put(map, key, v1)\n      end\n\n    iterator_merge(:maps.next(iterator), acc, fun)\n  end\n\n  defp iterator_merge(:none, map, _fun), do: map\n\n  # Erlang maps:intersect_with/3 has to preserve the order in combiner.\n  # We don't care about the order, so we have a faster implementation.\n  defp symmetrical_intersection(left, right, fun) do\n    if map_size(left) > map_size(right) do\n      iterator_intersection(:maps.next(:maps.iterator(right)), left, [], fun)\n    else\n      iterator_intersection(:maps.next(:maps.iterator(left)), right, [], fun)\n    end\n  end\n\n  defp iterator_intersection({key, v1, iterator}, map, acc, fun) do\n    acc =\n      case map do\n        %{^key => v2} ->\n          value = fun.(key, v1, v2)\n\n          if value in @empty_intersection do\n            acc\n          else\n            [{key, value} | acc]\n          end\n\n        %{} ->\n          acc\n      end\n\n    iterator_intersection(:maps.next(iterator), map, acc, fun)\n  end\n\n  defp iterator_intersection(:none, _map, acc, _fun), do: :maps.from_list(acc)\n\n  defp non_disjoint_intersection?(left, right) do\n    # Erlang maps:intersect_with/3 has to preserve the order in combiner.\n    # We don't care about the order, so we have a faster implementation.\n    if map_size(left) > map_size(right) do\n      iterator_non_disjoint_intersection?(:maps.next(:maps.iterator(right)), left)\n    else\n      iterator_non_disjoint_intersection?(:maps.next(:maps.iterator(left)), right)\n    end\n  end\n\n  defp iterator_non_disjoint_intersection?({key, v1, iterator}, map) do\n    with %{^key => v2} <- map,\n         value when value not in @empty_intersection <- intersection(key, v1, v2),\n         false <- empty_key?(key, value) do\n      true\n    else\n      _ -> iterator_non_disjoint_intersection?(:maps.next(iterator), map)\n    end\n  end\n\n  defp iterator_non_disjoint_intersection?(:none, _map), do: false\n\n  defp non_empty_map_or([head | tail], fun) do\n    Enum.reduce(tail, fun.(head), &{:or, [], [&2, fun.(&1)]})\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/types/expr.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Module.Types.Expr do\n  @moduledoc false\n\n  alias Module.Types.{Apply, Of, Pattern}\n  import Module.Types.{Helpers, Descr}\n\n  14 = length(Macro.Env.__info__(:struct))\n\n  aliases = list(tuple([atom(), atom()]))\n  functions_and_macros = list(tuple([atom(), list(tuple([atom(), integer()]))]))\n  list_of_modules = list(atom())\n\n  @try_catch atom([:error, :exit, :throw])\n  @atom_true atom([true])\n\n  @caller closed_map(\n            __struct__: atom([Macro.Env]),\n            aliases: aliases,\n            context: atom([:match, :guard, nil]),\n            context_modules: list_of_modules,\n            file: binary(),\n            function: union(tuple([atom(), integer()]), atom([nil])),\n            functions: functions_and_macros,\n            lexical_tracker: union(pid(), atom([nil])),\n            line: integer(),\n            macro_aliases: aliases,\n            macros: functions_and_macros,\n            module: atom(),\n            requires: list_of_modules,\n            tracers: list_of_modules,\n            versioned_vars: open_map()\n          )\n\n  # An annotation for terms where the reverse arrow is not yet fully defined.\n  # Also revisit all users of dynamic() in this module in a later date.\n  @pending term()\n\n  # We do not make exception dynamic on purpose. If you do a blank rescue,\n  # then we will assume you need to statically handle all possible exceptions.\n  @exception open_map(__struct__: atom(), __exception__: @atom_true)\n\n  args_or_arity = union(list(term()), integer())\n\n  extra_info =\n    list(\n      tuple([atom([:file]), list(integer())])\n      |> union(tuple([atom([:line]), integer()]))\n      |> union(tuple([atom([:error_info]), open_map()]))\n    )\n\n  @stacktrace list(\n                union(\n                  tuple([atom(), atom(), args_or_arity, extra_info]),\n                  tuple([fun(), args_or_arity, extra_info])\n                )\n              )\n\n  # :atom\n  def of_expr(atom, _expected, _expr, _stack, context) when is_atom(atom),\n    do: {atom([atom]), context}\n\n  # 12\n  def of_expr(literal, _expected, _expr, _stack, context) when is_integer(literal),\n    do: {integer(), context}\n\n  # 1.2\n  def of_expr(literal, _expected, _expr, _stack, context) when is_float(literal),\n    do: {float(), context}\n\n  # \"...\"\n  def of_expr(literal, _expected, _expr, _stack, context) when is_binary(literal),\n    do: {binary(), context}\n\n  # #PID<...>\n  def of_expr(literal, _expected, _expr, _stack, context) when is_pid(literal),\n    do: {pid(), context}\n\n  # []\n  def of_expr([], _expected, _expr, _stack, context),\n    do: {empty_list(), context}\n\n  # [expr, ...]\n  def of_expr(list, expected, expr, stack, context) when is_list(list) do\n    {prefix, suffix} = unpack_list(list, [])\n\n    hd_type =\n      case list_hd(expected) do\n        {:ok, type} -> type\n        _ -> term()\n      end\n\n    {prefix, context} = Enum.map_reduce(prefix, context, &of_expr(&1, hd_type, expr, stack, &2))\n\n    {suffix, context} =\n      if suffix == [] do\n        {empty_list(), context}\n      else\n        tl_type =\n          case list_tl(expected) do\n            {:ok, type} -> type\n            :badnonemptylist -> term()\n          end\n\n        of_expr(suffix, tl_type, expr, stack, context)\n      end\n\n    {non_empty_list(Enum.reduce(prefix, &union/2), suffix), context}\n  end\n\n  # {left, right}\n  def of_expr({left, right}, expected, expr, stack, context) do\n    of_tuple([left, right], expected, expr, stack, context)\n  end\n\n  # {...}\n  def of_expr({:{}, _meta, exprs}, expected, expr, stack, context) do\n    of_tuple(exprs, expected, expr, stack, context)\n  end\n\n  # <<...>>>\n  def of_expr({:<<>>, _meta, args}, _expected, _expr, stack, context) do\n    args\n    |> Of.bitstring(:expr, stack, context)\n    |> dynamic_unless_static(stack)\n  end\n\n  def of_expr({:__CALLER__, _meta, var_context}, _expected, _expr, _stack, context)\n      when is_atom(var_context) do\n    {@caller, context}\n  end\n\n  def of_expr({:__STACKTRACE__, _meta, var_context}, _expected, _expr, _stack, context)\n      when is_atom(var_context) do\n    {@stacktrace, context}\n  end\n\n  # left = right\n  def of_expr({:=, _, [left_expr, right_expr]} = match, expected, expr, stack, context) do\n    {left_expr, right_expr} = repack_match(left_expr, right_expr)\n\n    case left_expr do\n      # We do not raise on underscore in case someone writes _ = raise \"omg\"\n      {:_, _, ctx} when is_atom(ctx) ->\n        of_expr(right_expr, expected, expr, stack, context)\n\n      _ ->\n        type_fun = fn pattern_type, context ->\n          # See if we can use the expected type to further refine the pattern type,\n          # if we cannot, use the pattern type as that will fail later on.\n          {_ok_or_error, type} = compatible_intersection(dynamic(pattern_type), expected)\n          of_expr(right_expr, type, expr, stack, context)\n        end\n\n        Pattern.of_match(left_expr, type_fun, match, stack, context)\n    end\n  end\n\n  # %{map | ...}\n  # TODO: Once we support typed structs, we need to type check them here.\n  def of_expr({:%{}, meta, [{:|, _, [map, args]}]} = update, expected, expr, stack, context) do\n    # Theoretically we cannot process entries out of order but,\n    # because all variables are versioned, and Elixir does not\n    # allow variables defined on the left side of | to be available\n    # on the right side, this is safe.\n    {pairs_types, context} =\n      Enum.map_reduce(args, context, fn {key, value}, context ->\n        {key_type, context} = of_expr(key, term(), expr, stack, context)\n        {value_type, context} = of_expr(value, term(), expr, stack, context)\n        {{key_type, value_type}, context}\n      end)\n\n    # The only information we can attach to the expected types is that\n    # certain keys are expected.\n    expected_pairs =\n      Enum.flat_map(pairs_types, fn {key_type, _value_type} ->\n        case atom_fetch(key_type) do\n          {:finite, [key]} -> [{key, term()}]\n          _ -> []\n        end\n      end)\n\n    expected = intersection(expected, open_map(expected_pairs))\n    {map_type, context} = of_expr(map, expected, expr, stack, context)\n\n    try do\n      Enum.reduce(pairs_types, map_type, fn {key_type, value_type}, acc ->\n        case literal_map_update(acc, key_type, value_type) do\n          {:ok, descr} -> descr\n          {:badkey, key} -> throw({:badkey, map_type, key, update, context})\n          {:baddomain, domain} -> throw({:baddomain, map_type, domain, update, context})\n          :badmap -> throw({:badmap, map_type, update, context})\n        end\n      end)\n    catch\n      error -> {error_type(), error(__MODULE__, error, meta, stack, context)}\n    else\n      map -> {map, context}\n    end\n  end\n\n  # %Struct{map | ...}\n  def of_expr(\n        {:%, meta, [module, {:%{}, _, [{:|, _, [map, pairs]}]}]} = struct,\n        _expected,\n        expr,\n        stack,\n        context\n      ) do\n    {info, context} = Of.struct_info(module, :expr, meta, stack, context)\n\n    if info do\n      # We pass the expected type as `term()` because the struct update\n      # operator already expects it to be a map at this point.\n      {map_type, context} = of_expr(map, term(), struct, stack, context)\n\n      context =\n        with {false, struct_key_type} <- map_fetch_key(map_type, :__struct__),\n             {:finite, [^module]} <- atom_fetch(struct_key_type) do\n          context\n        else\n          _ ->\n            error(__MODULE__, {:badupdate, map_type, struct, context}, meta, stack, context)\n        end\n\n      Enum.reduce(pairs, {map_type, context}, fn {key, value}, {acc, context} ->\n        context =\n          if Enum.any?(info, &(&1.field == key)) do\n            context\n          else\n            Of.unknown_struct_field(module, key, :expr, meta, stack, context)\n          end\n\n        # TODO: Once we support typed structs, we need to type check them here\n        {type, context} = of_expr(value, term(), expr, stack, context)\n\n        case map_put_key(acc, key, type) do\n          {:ok, acc} -> {acc, context}\n          _ -> {acc, context}\n        end\n      end)\n    else\n      context =\n        Enum.reduce(pairs, context, fn {_key, value}, context ->\n          {_type, context} = of_expr(value, term(), expr, stack, context)\n          context\n        end)\n\n      {error_type(), context}\n    end\n  end\n\n  # %{...}\n  def of_expr({:%{}, _meta, args}, expected, expr, stack, context) do\n    Of.closed_map(args, expected, stack, context, &of_expr(&1, &2, expr, &3, &4))\n  end\n\n  # %Struct{}\n  def of_expr({:%, meta, [module, {:%{}, _, args}]}, expected, expr, stack, context) do\n    fun = &of_expr(&1, &2, expr, &3, &4)\n    Of.struct_instance(module, args, expected, meta, stack, context, fun)\n  end\n\n  # ()\n  def of_expr({:__block__, _meta, []}, _expected, _expr, _stack, context) do\n    {atom([nil]), context}\n  end\n\n  # (expr; expr)\n  def of_expr({:__block__, _meta, exprs}, expected, _expr, stack, context) do\n    {pre, [post]} = Enum.split(exprs, -1)\n\n    context =\n      Enum.reduce(pre, context, fn expr, context ->\n        {_, context} = of_expr(expr, term(), expr, stack, context)\n        context\n      end)\n\n    of_expr(post, expected, post, stack, context)\n  end\n\n  def of_expr({:cond, _meta, [[{:do, clauses}]]}, expected, expr, stack, original) do\n    clauses\n    |> reduce_non_empty({none(), original}, fn\n      {:->, meta, [[head], body]}, {acc, context}, last? ->\n        {head_type, context} = of_expr(head, @pending, head, stack, context)\n\n        context =\n          if is_warning(stack) do\n            case truthiness(head_type) do\n              :always_true when not last? ->\n                warning = {:badcond, \"always match\", head_type, head, context}\n                warn(__MODULE__, warning, meta, stack, context)\n\n              :always_false ->\n                warning = {:badcond, \"never match\", head_type, head, context}\n                warn(__MODULE__, warning, meta, stack, context)\n\n              _ ->\n                context\n            end\n          else\n            context\n          end\n\n        {body_type, context} = of_expr(body, expected, expr, stack, context)\n        {union(body_type, acc), Of.reset_vars(context, original)}\n    end)\n    |> dynamic_unless_static(stack)\n  end\n\n  def of_expr({:case, meta, [case_expr, [{:do, clauses}]]}, expected, _expr, stack, context) do\n    {case_type, context} = of_expr(case_expr, @pending, case_expr, stack, context)\n    info = {:case, meta, case_expr, case_type}\n\n    added_meta =\n      if Macro.quoted_literal?(case_expr) do\n        [generated: true]\n      else\n        case_expr |> get_meta() |> Keyword.take([:generated])\n      end\n\n    # If the expression is generated or the construct is a literal,\n    # it is most likely a macro code. However, if no clause is matched,\n    # we should still check for that.\n    if added_meta != [] do\n      for {:->, meta, args} <- clauses, do: {:->, [generated: true] ++ meta, args}\n    else\n      clauses\n    end\n    |> of_clauses([case_type], expected, info, stack, context, none())\n    |> dynamic_unless_static(stack)\n  end\n\n  # fn pat -> expr end\n  def of_expr({:fn, _meta, clauses}, _expected, _expr, stack, context) do\n    [{:->, _, [head, _]} | _] = clauses\n    {patterns, _guards} = extract_head(head)\n    domain = Enum.map(patterns, fn _ -> dynamic() end)\n\n    {acc, context} =\n      of_clauses_fun(clauses, domain, @pending, :fn, stack, context, [], fn\n        trees, body, context, acc ->\n          args_types = Pattern.of_domain(trees, stack, context)\n          add_inferred(acc, args_types, body)\n      end)\n\n    {fun_from_inferred_clauses(acc), context}\n  end\n\n  def of_expr({:try, meta, [[do: body] ++ blocks]}, expected, expr, stack, original) do\n    {after_block, blocks} = Keyword.pop(blocks, :after)\n    {else_block, blocks} = Keyword.pop(blocks, :else)\n\n    {type, context} =\n      if else_block do\n        {type, context} = of_expr(body, @pending, body, stack, original)\n        info = {:try_else, meta, body, type}\n        of_clauses(else_block, [type], expected, info, stack, context, none())\n      else\n        of_expr(body, expected, expr, stack, original)\n      end\n\n    {type, context} =\n      blocks\n      |> Enum.reduce({type, Of.reset_vars(context, original)}, fn\n        {:rescue, clauses}, acc_context ->\n          Enum.reduce(clauses, acc_context, fn\n            {:->, _, [[{:in, meta, [var, exceptions]} = expr], body]}, {acc, context} ->\n              {type, context} =\n                of_rescue(var, exceptions, body, expr, :rescue, meta, stack, context)\n\n              {union(type, acc), context}\n\n            {:->, meta, [[var], body]}, {acc, context} ->\n              {type, context} =\n                of_rescue(var, [], body, var, :anonymous_rescue, meta, stack, context)\n\n              {union(type, acc), context}\n          end)\n\n        {:catch, clauses}, {acc, context} ->\n          args = [@try_catch, dynamic()]\n          of_clauses(clauses, args, expected, :try_catch, stack, context, acc)\n      end)\n      |> dynamic_unless_static(stack)\n\n    if after_block do\n      {_type, context} = of_expr(after_block, term(), after_block, stack, context)\n      {type, context}\n    else\n      {type, context}\n    end\n  end\n\n  @timeout_type union(integer(), atom([:infinity]))\n\n  def of_expr({:receive, _meta, [blocks]}, expected, expr, stack, original) do\n    blocks\n    |> Enum.reduce({none(), original}, fn\n      {:do, {:__block__, _, []}}, acc_context ->\n        acc_context\n\n      {:do, clauses}, {acc, context} ->\n        of_clauses(clauses, [dynamic()], expected, :receive, stack, context, acc)\n\n      {:after, [{:->, meta, [[timeout], body]}] = after_expr}, {acc, context} ->\n        {timeout_type, context} = of_expr(timeout, @timeout_type, after_expr, stack, context)\n        {body_type, context} = of_expr(body, expected, expr, stack, context)\n\n        if compatible?(timeout_type, @timeout_type) do\n          {union(body_type, acc), Of.reset_vars(context, original)}\n        else\n          error = {:badtimeout, timeout_type, timeout, context}\n          {union(body_type, acc), error(__MODULE__, error, meta, stack, context)}\n        end\n    end)\n    |> dynamic_unless_static(stack)\n  end\n\n  def of_expr({:for, meta, [_ | _] = args}, expected, expr, stack, context) do\n    {clauses, [[{:do, block} | opts]]} = Enum.split(args, -1)\n    context = Enum.reduce(clauses, context, &for_clause(&1, stack, &2))\n\n    # We don't need to type check uniq, as it is a compile-time boolean.\n    # We handle reduce and into accordingly instead.\n    if Keyword.has_key?(opts, :reduce) do\n      reduce = Keyword.fetch!(opts, :reduce)\n      {reduce_type, context} = of_expr(reduce, expected, expr, stack, context)\n      # TODO: We need to type check against dynamic() instead of using reduce_type\n      # because this is recursive. We need to infer the block type first.\n      args = [dynamic()]\n      of_clauses(block, args, expected, :for_reduce, stack, context, reduce_type)\n    else\n      # TODO: Use the collectable protocol for the output\n      into = Keyword.get(opts, :into, [])\n      {into_type, into_kind, context} = for_into(into, meta, stack, context)\n      {block_type, context} = of_expr(block, @pending, block, stack, context)\n\n      case into_kind do\n        :bitstring ->\n          case compatible_intersection(block_type, bitstring()) do\n            {:ok, intersection} ->\n              {return_union(into_type, intersection, stack), context}\n\n            {:error, _} ->\n              error = {:badbitbody, block_type, block, context}\n              {error_type(), error(__MODULE__, error, meta, stack, context)}\n          end\n\n        :non_empty_list ->\n          {return_union(into_type, non_empty_list(block_type), stack), context}\n\n        :none ->\n          {into_type, context}\n      end\n    end\n  end\n\n  # TODO: with pat <- expr do expr end\n  def of_expr({:with, _meta, [_ | _] = clauses}, _expected, _expr, stack, original) do\n    {clauses, [options]} = Enum.split(clauses, -1)\n    context = Enum.reduce(clauses, original, &with_clause(&1, stack, &2))\n    context = Enum.reduce(options, context, &with_option(&1, stack, &2, original))\n    {dynamic(), context}\n  end\n\n  def of_expr({{:., _, [fun]}, _, args} = call, _expected, _expr, stack, context) do\n    {fun_type, context} = of_expr(fun, dynamic(fun(length(args))), call, stack, context)\n\n    # TODO: Perform inference based on the strong domain of a function\n    {args_types, context} =\n      Enum.map_reduce(args, context, &of_expr(&1, @pending, &1, stack, &2))\n\n    Apply.fun(fun_type, args_types, call, stack, context)\n  end\n\n  def of_expr({{:., _, [callee, key_or_fun]}, meta, []} = call, expected, expr, stack, context)\n      when not is_atom(callee) and is_atom(key_or_fun) do\n    if Keyword.get(meta, :no_parens, false) do\n      {type, context} = of_expr(callee, open_map([{key_or_fun, expected}]), expr, stack, context)\n      Of.map_fetch(call, type, key_or_fun, stack, context)\n    else\n      {type, context} = of_expr(callee, atom(), call, stack, context)\n      {mods, context} = Of.modules(type, key_or_fun, 0, [:dot], call, meta, stack, context)\n      apply_many(mods, key_or_fun, [], expected, call, stack, context)\n    end\n  end\n\n  def of_expr({{:., _, [remote, name]}, meta, args} = call, expected, _expr, stack, context) do\n    {remote_type, context} = of_expr(remote, atom(), call, stack, context)\n    {mods, context} = Of.modules(remote_type, name, length(args), call, meta, stack, context)\n    apply_many(mods, name, args, expected, call, stack, context)\n  end\n\n  # &Foo.bar/1\n  def of_expr(\n        {:&, _, [{:/, _, [{{:., _, [remote, name]}, meta, []}, arity]}]} = call,\n        _expected,\n        _expr,\n        stack,\n        context\n      )\n      when is_atom(name) and is_integer(arity) do\n    {remote_type, context} = of_expr(remote, atom(), call, stack, context)\n    {mods, context} = Of.modules(remote_type, name, arity, call, meta, stack, context)\n    Apply.remote_capture(mods, name, arity, meta, stack, context)\n  end\n\n  # &foo/1\n  def of_expr({:&, _meta, [{:/, _, [{fun, meta, _}, arity]}]}, _expected, _expr, stack, context) do\n    Apply.local_capture(fun, arity, meta, stack, context)\n  end\n\n  # Super\n  def of_expr({:super, meta, args} = call, expected, _expr, stack, context) when is_list(args) do\n    {_kind, fun} = Keyword.fetch!(meta, :super)\n    Apply.local(fun, args, expected, call, stack, context, &of_expr/5)\n  end\n\n  # Local calls\n  def of_expr({fun, _meta, args} = call, expected, _expr, stack, context)\n      when is_atom(fun) and is_list(args) do\n    Apply.local(fun, args, expected, call, stack, context, &of_expr/5)\n  end\n\n  # var\n  def of_expr({_, meta, _} = var, expected, expr, stack, context) when is_var(var) do\n    version = Keyword.fetch!(meta, :version)\n    {type, context} = Of.refine_body_var(version, expected, expr, stack, context)\n    {type, Pattern.of_changed([version], stack, context)}\n  end\n\n  ## Tuples\n\n  defp of_tuple(elems, expected, expr, stack, context) do\n    of_tuple(elems, 0, [], expected, expr, stack, context)\n  end\n\n  defp of_tuple([elem | elems], index, acc, expected, expr, stack, context) do\n    expr_expected =\n      case tuple_fetch(expected, index) do\n        {_, type} -> type\n        _ -> term()\n      end\n\n    {type, context} = of_expr(elem, expr_expected, expr, stack, context)\n    of_tuple(elems, index + 1, [type | acc], expected, expr, stack, context)\n  end\n\n  defp of_tuple([], _index, acc, _expected, _expr, _stack, context) do\n    {tuple(Enum.reverse(acc)), context}\n  end\n\n  ## Try\n\n  defp of_rescue(var, exceptions, body, expr, info, meta, stack, original) do\n    args = [__exception__: @atom_true]\n\n    {structs, context} =\n      Enum.map_reduce(exceptions, original, fn exception, context ->\n        # Exceptions are not validated in the compiler,\n        # to avoid export dependencies. So we do it here.\n        {info, context} = Of.struct_info(exception, :expr, meta, stack, context)\n\n        if info do\n          {Of.struct_type(exception, info, args), context}\n        else\n          {error_type(), context}\n        end\n      end)\n\n    context =\n      case var do\n        {:_, _, _} ->\n          context\n\n        _ ->\n          expected = if structs == [], do: @exception, else: Enum.reduce(structs, &union/2)\n          expr = {:__block__, [type_check: info], [expr]}\n          context = Of.declare_var(var, context)\n          {_ok?, _type, context} = Of.refine_head_var(var, expected, expr, stack, context)\n          context\n      end\n\n    {type, context} = of_expr(body, @pending, body, stack, context)\n    {type, Of.reset_vars(context, original)}\n  end\n\n  ## Comprehensions\n\n  defp for_clause({:<-, meta, [left, right]}, stack, context) do\n    expr = {:<-, [type_check: :generator] ++ meta, [left, right]}\n    {pattern, guards} = extract_head([left])\n\n    {_type, context} =\n      Apply.remote(Enumerable, :count, [right], dynamic(), expr, stack, context, &of_expr/5)\n\n    Pattern.of_generator(pattern, guards, dynamic(), :for, expr, stack, context)\n  end\n\n  defp for_clause({:<<>>, _, [{:<-, meta, [left, right]}]} = expr, stack, context) do\n    {right_type, context} = of_expr(right, bitstring(), expr, stack, context)\n    info = {:for, expr, dynamic()}\n    context = Pattern.of_generator(left, [], bitstring(), info, expr, stack, context)\n\n    if compatible?(right_type, bitstring()) do\n      context\n    else\n      error = {:badbitgenerator, right_type, right, context}\n      error(__MODULE__, error, meta, stack, context)\n    end\n  end\n\n  defp for_clause(expr, stack, context) do\n    {_type, context} = of_expr(expr, term(), expr, stack, context)\n    context\n  end\n\n  @into_compile union(bitstring(), empty_list())\n\n  defp for_into([], _meta, _stack, context),\n    do: {empty_list(), :non_empty_list, context}\n\n  defp for_into(binary, _meta, _stack, context) when is_binary(binary),\n    do: {binary(), :bitstring, context}\n\n  defp for_into(into, meta, stack, context) do\n    meta =\n      case into do\n        {_, meta, _} -> meta\n        _ -> meta\n      end\n\n    expr = {:__block__, [type_check: :into] ++ meta, [into]}\n\n    {info, [domain], context} =\n      Apply.remote_domain(Collectable, :into, [into], term(), meta, stack, context)\n\n    {type, context} = of_expr(into, domain, expr, stack, context)\n\n    # We use subtype? instead of compatible because we want to handle\n    # only bitstring/list, even if a dynamic with something else is given.\n    if subtype?(type, @into_compile) do\n      case {bitstring_type?(type), empty_list_type?(type)} do\n        # If they can be both be true, then we don't know\n        # what the contents of the block are for\n        {true, true} ->\n          type = union(bitstring(), list(term()))\n          {if(gradual?(type), do: dynamic(type), else: type), :none, context}\n\n        {false, true} ->\n          {type, :non_empty_list, context}\n\n        {true, false} ->\n          {type, :bitstring, context}\n      end\n    else\n      {_type, context} =\n        Apply.remote_apply(info, Collectable, :into, [type], expr, stack, context)\n\n      {dynamic(), :none, context}\n    end\n  end\n\n  defp return_union(left, right, stack) do\n    Apply.return(union(left, right), [left, right], stack)\n  end\n\n  ## With\n\n  defp with_clause({:<-, _meta, [left, right]} = expr, stack, context) do\n    {pattern, guards} = extract_head([left])\n    {_type, context} = of_expr(right, @pending, right, stack, context)\n    info = {:with, expr, dynamic()}\n    Pattern.of_generator(pattern, guards, dynamic(), info, expr, stack, context)\n  end\n\n  defp with_clause(expr, stack, context) do\n    {_type, context} = of_expr(expr, @pending, expr, stack, context)\n    context\n  end\n\n  defp with_option({:do, body}, stack, context, original) do\n    {_type, context} = of_expr(body, @pending, body, stack, context)\n    Of.reset_vars(context, original)\n  end\n\n  defp with_option({:else, clauses}, stack, context, _original) do\n    {_, context} =\n      of_clauses(clauses, [dynamic()], @pending, :with_else, stack, context, none())\n\n    context\n  end\n\n  ## General helpers\n\n  defp apply_many([], fun, args, expected, expr, stack, context) do\n    Apply.remote(fun, args, expected, expr, stack, context, &of_expr/5)\n  end\n\n  defp apply_many([mod], fun, args, expected, expr, stack, context) do\n    Apply.remote(mod, fun, args, expected, expr, stack, context, &of_expr/5)\n  end\n\n  defp apply_many(mods, fun, args, expected, call, stack, context) do\n    {remote, meta, _} = call\n\n    Of.with_conditional_vars(mods, none(), call, stack, context, fn mod, acc, context ->\n      expr = {remote, [type_check: {:invoked_as, mod, fun, length(args)}] ++ meta, args}\n      {type, context} = Apply.remote(mod, fun, args, expected, expr, stack, context, &of_expr/5)\n      {union(acc, type), context}\n    end)\n  end\n\n  defp reduce_non_empty([last], acc, fun),\n    do: fun.(last, acc, true)\n\n  defp reduce_non_empty([head | tail], acc, fun),\n    do: reduce_non_empty(tail, fun.(head, acc, false), fun)\n\n  defp dynamic_unless_static({_, _} = output, %{mode: :static}), do: output\n  defp dynamic_unless_static({type, context}, %{mode: _}), do: {dynamic(type), context}\n\n  defp of_clauses(clauses, domain, expected, base_info, stack, context, acc) do\n    fun = fn _args_types, result, _context, acc -> union(result, acc) end\n    of_clauses_fun(clauses, domain, expected, base_info, stack, context, acc, fun)\n  end\n\n  defp of_clauses_fun(clauses, domain, expected, base_info, stack, original, acc, fun) do\n    %{failed: failed?} = original\n\n    {result, _previous, context} =\n      Enum.reduce(clauses, {acc, Pattern.init_previous(), original}, fn\n        {:->, meta, [head, body]}, {acc, previous, context} ->\n          {failed?, context} = reset_failed(context, failed?)\n          {patterns, guards} = extract_head(head)\n          info = {base_info, head}\n\n          {trees, previous, context} =\n            Pattern.of_head(patterns, guards, domain, previous, info, meta, stack, context)\n\n          {result, context} = of_expr(body, expected, body, stack, context)\n\n          {fun.(trees, result, context, acc), previous,\n           context |> set_failed(failed?) |> Of.reset_vars(original)}\n      end)\n\n    {result, context}\n  end\n\n  defp reset_failed(%{failed: true} = context, false), do: {true, %{context | failed: false}}\n  defp reset_failed(context, _), do: {false, context}\n\n  defp set_failed(%{failed: false} = context, true), do: %{context | failed: true}\n  defp set_failed(context, _bool), do: context\n\n  defp extract_head([{:when, _meta, args}]) do\n    case Enum.split(args, -1) do\n      {patterns, [guards]} -> {patterns, flatten_when(guards)}\n      {patterns, []} -> {patterns, []}\n    end\n  end\n\n  defp extract_head(other) do\n    {other, []}\n  end\n\n  defp flatten_when({:when, _meta, [left, right]}), do: [left | flatten_when(right)]\n  defp flatten_when(other), do: [other]\n\n  defp repack_match(left_expr, {:=, meta, [new_left, new_right]}),\n    do: repack_match({:=, meta, [left_expr, new_left]}, new_right)\n\n  defp repack_match(left_expr, right_expr),\n    do: {left_expr, right_expr}\n\n  defp add_inferred([{args, existing_return} | tail], args, return),\n    do: [{args, union(existing_return, return)} | tail]\n\n  defp add_inferred([head | tail], args, return),\n    do: [head | add_inferred(tail, args, return)]\n\n  defp add_inferred([], args, return),\n    do: [{args, return}]\n\n  defp literal_map_update(descr, key_descr, value_descr) do\n    case map_update(descr, key_descr, value_descr, false, false) do\n      {_type, descr, []} -> {:ok, descr}\n      {_, _, [error | _]} -> error\n      :badmap -> :badmap\n      {:error, [error | _]} -> error\n      {:error, []} -> {:baddomain, key_descr}\n    end\n  end\n\n  ## Warning formatting\n\n  def format_diagnostic({:badupdate, type, expr, context}) do\n    {:%, _, [module, {:%{}, _, [{:|, _, [map, _]}]}]} = expr\n    traces = collect_traces(map, context)\n\n    fix =\n      case map do\n        {var, meta, context} when is_atom(var) and is_atom(context) ->\n          if capture = meta[:capture] do\n            \"instead of using &#{capture}, you must define an anonymous function, define a variable and pattern match on \\\"%#{inspect(module)}{}\\\"\"\n          else\n            \"when defining the variable \\\"#{Macro.to_string(map)}\\\", you must also pattern match on \\\"%#{inspect(module)}{}\\\"\"\n          end\n\n        _ ->\n          \"you must assign \\\"#{Macro.to_string(map)}\\\" to variable and pattern match on \\\"%#{inspect(module)}{}\\\"\"\n      end\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          a struct for #{inspect(module)} is expected on struct update:\n\n              #{expr_to_string(expr, collapse_structs: false) |> indent(4)}\n\n          but got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces),\n          \"\"\"\n\n          #{fix}\n          \"\"\"\n        ])\n    }\n  end\n\n  def format_diagnostic({:badmap, type, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected a map within map update syntax:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          but got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badkey, type, key, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected a map with key #{inspect(key)} in map update syntax:\n\n              #{expr_to_string(expr, collapse_structs: false) |> indent(4)}\n\n          but got type:\n\n              #{to_quoted_string(type, collapse_structs: false) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:baddomain, type, key_type, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected a map with key of type #{to_quoted_string(key_type)} in map update syntax:\n\n              #{expr_to_string(expr, collapse_structs: false) |> indent(4)}\n\n          but got type:\n\n              #{to_quoted_string(type, collapse_structs: false) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badbitgenerator, type, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected the right side of <- in a binary generator to be a binary (or bitstring):\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          but got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badbitbody, type, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected the body of a for-comprehension with into: binary() (or bitstring()) to be a binary (or bitstring):\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          but got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badtimeout, type, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected \"after\" timeout given to receive to be an integer:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          but got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badcond, explain, type, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          this clause in cond will #{explain}:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          since it has type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/types/helpers.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Module.Types.Helpers do\n  # AST and enumeration helpers.\n  @moduledoc false\n\n  ## AST helpers\n\n  @doc \"\"\"\n  Returns true if the mode cares about warnings.\n  \"\"\"\n  defguard is_warning(stack) when stack.mode != :infer\n\n  @doc \"\"\"\n  Guard function to check if an AST node is a variable.\n  \"\"\"\n  defmacro is_var(expr) do\n    quote do\n      is_tuple(unquote(expr)) and\n        tuple_size(unquote(expr)) == 3 and\n        is_atom(elem(unquote(expr), 0)) and\n        is_atom(elem(unquote(expr), 2))\n    end\n  end\n\n  @doc \"\"\"\n  Unpacks a list into head elements and tail.\n  \"\"\"\n  def unpack_list([{:|, _, [head, tail]}], acc), do: {Enum.reverse([head | acc]), tail}\n  def unpack_list([head], acc), do: {Enum.reverse([head | acc]), []}\n  def unpack_list([head | tail], acc), do: unpack_list(tail, [head | acc])\n\n  @doc \"\"\"\n  Unpacks a match into several matches.\n  \"\"\"\n  def unpack_match({:=, _, [left, right]}, acc),\n    do: unpack_match(left, unpack_match(right, acc))\n\n  def unpack_match(node, acc),\n    do: [node | acc]\n\n  @doc \"\"\"\n  Returns the AST metadata.\n  \"\"\"\n  def get_meta({_, meta, _}), do: meta\n  def get_meta(_other), do: []\n\n  @doc \"\"\"\n  Attaches span information.\n  \"\"\"\n  def with_span(meta, name) do\n    :elixir_env.calculate_span(meta, name)\n  end\n\n  ## Warnings\n\n  @doc \"\"\"\n  Converts an itneger into ordinal.\n  \"\"\"\n  def integer_to_ordinal(i) do\n    case rem(i, 10) do\n      1 when rem(i, 100) != 11 -> \"#{i}st\"\n      2 when rem(i, 100) != 12 -> \"#{i}nd\"\n      3 when rem(i, 100) != 13 -> \"#{i}rd\"\n      _ -> \"#{i}th\"\n    end\n  end\n\n  @doc \"\"\"\n  Formatted hints in typing errors.\n  \"\"\"\n  def format_hints(hints) do\n    hints\n    |> Enum.uniq()\n    |> Enum.map(fn\n      :inferred_bitstring_spec ->\n        \"\"\"\n\n        #{hint()} all expressions given to binaries are assumed to be of type \\\n        integer() unless said otherwise. For example, <<expr>> assumes \"expr\" \\\n        is an integer. Pass a modifier, such as <<expr::float>> or <<expr::binary>>, \\\n        to change the default behavior.\n        \"\"\"\n\n      :dot ->\n        \"\"\"\n\n        #{hint()} \"var.field\" (without parentheses) means \"var\" is a map() while \\\n        \"var.fun()\" (with parentheses) means \"var\" is an atom()\n        \"\"\"\n\n      :anonymous_rescue ->\n        \"\"\"\n\n        #{hint()} when you rescue without specifying exception names, \\\n        the variable is assigned a type of a struct but all of its fields are unknown. \\\n        If you are trying to access an exception's :message key, either specify the \\\n        exception names or use `Exception.message/1`.\n        \"\"\"\n\n      :empty_union_domain ->\n        \"\"\"\n\n        #{hint()} the function has an empty domain and therefore cannot be applied to \\\n        any argument. This may happen when you have a union of functions, which means \\\n        the only valid argument to said function are types that satisfy all sides of \\\n        the union (which may be none)\n        \"\"\"\n\n      {:impl, for} ->\n        # Get the type without dynamic for better pretty printing\n        type =\n          for\n          |> Module.Types.Of.impl()\n          |> Module.Types.Descr.dynamic()\n          |> Map.fetch!(:dynamic)\n          |> Module.Types.Descr.to_quoted_string(collapse_structs: true)\n\n        \"\"\"\n\n        #{hint()} defimpl for #{inspect(for)} requires its callbacks to match exclusively on #{type}\n        \"\"\"\n\n      :empty_domain ->\n        \"\"\"\n\n        #{hint()} the function has an empty domain and therefore cannot be applied to \\\n        any argument\n        \"\"\"\n    end)\n  end\n\n  @doc \"The hint prefix\"\n  def hint, do: :elixir_errors.prefix(:hint)\n\n  @doc \"\"\"\n  Collect traces from variables in expression.\n\n  This information is exposed to language servers and\n  therefore must remain backwards compatible.\n  \"\"\"\n  def collect_traces(expr, %{vars: vars}) do\n    {_, versions} =\n      Macro.prewalk(expr, %{}, fn node, versions ->\n        with {var_name, meta, var_context} when is_atom(var_name) and is_atom(var_context) <- node,\n             false <- String.starts_with?(Atom.to_string(var_name), \"_\") do\n          version = meta[:version]\n\n          case vars do\n            %{^version => %{off_traces: [_ | _] = off_traces, name: name, context: context}} ->\n              {:ok,\n               Map.put(versions, version, %{\n                 type: :variable,\n                 name: name,\n                 context: context,\n                 traces: collect_var_traces(expr, off_traces)\n               })}\n\n            _ ->\n              {:ok, versions}\n          end\n        else\n          _ -> {node, versions}\n        end\n      end)\n\n    versions\n    |> Map.values()\n    |> Enum.sort_by(& &1.name)\n  end\n\n  defp collect_var_traces(parent_expr, traces) do\n    traces\n    |> Enum.reject(fn {expr, _file, type} ->\n      # As an optimization do not care about dynamic terms\n      type == %{dynamic: :term} or expr == parent_expr\n    end)\n    |> case do\n      [] -> traces\n      filtered -> filtered\n    end\n    |> Enum.reverse()\n    |> Enum.map(fn {expr, file, type} ->\n      meta = get_meta(expr)\n\n      # This information is exposed to language servers and\n      # therefore must remain backwards compatible.\n      %{\n        file: file,\n        meta: meta,\n        formatted_expr: expr_to_string(expr),\n        formatted_hints: format_hints(expr_hints(expr)),\n        formatted_type: Module.Types.Descr.to_quoted_string(type, collapse_structs: true)\n      }\n    end)\n    |> Enum.sort_by(&{&1.meta[:line], &1.meta[:column]})\n    |> Enum.dedup()\n  end\n\n  defp expr_hints(expr) do\n    case expr do\n      {:<<>>, [inferred_bitstring_spec: true] ++ _meta, _} ->\n        [:inferred_bitstring_spec]\n\n      {_, meta, _} ->\n        case meta[:type_check] do\n          :anonymous_rescue -> [:anonymous_rescue]\n          _ -> []\n        end\n\n      _ ->\n        []\n    end\n  end\n\n  @doc \"\"\"\n  Format previously collected traces.\n  \"\"\"\n  def format_traces(traces) do\n    Enum.map(traces, &format_trace/1)\n  end\n\n  defp format_trace(%{type: :variable, name: name, context: context, traces: traces}) do\n    traces =\n      for trace <- traces do\n        location =\n          trace.file\n          |> Path.relative_to_cwd()\n          |> Exception.format_file_line(trace.meta[:line], trace.meta[:column])\n          |> String.replace_suffix(\":\", \"\")\n\n        [\n          \"\"\"\n\n              # type: #{indent(trace.formatted_type, 4)}\n              # from: #{location}\n              \\\n          \"\"\",\n          indent(trace.formatted_expr, 4),\n          ?\\n,\n          trace.formatted_hints\n        ]\n      end\n\n    type_or_types = pluralize(traces, \"type\", \"types\")\n    [\"\\nwhere #{format_var(name, context)} was given the #{type_or_types}:\\n\" | traces]\n  end\n\n  @doc \"\"\"\n  Formats a var for pretty printing.\n  \"\"\"\n  def format_var({var, _, context}), do: format_var(var, context)\n  def format_var(var, nil), do: \"\\\"#{var}\\\"\"\n  def format_var(var, context), do: \"\\\"#{var}\\\" (context #{inspect(context)})\"\n\n  defp pluralize([_], singular, _plural), do: singular\n  defp pluralize(_, _singular, plural), do: plural\n\n  @doc \"\"\"\n  Converts the given expression to a string,\n  translating inlined Erlang calls back to Elixir.\n\n  We also undo some macro expressions done by the Kernel module\n  and collapse complex expressions.\n\n  ## Options\n\n    * `:collapse_structs` - when false, show structs full representation\n  \"\"\"\n  def expr_to_string(expr, opts \\\\ []) do\n    string = prewalk_expr_to_string(expr, opts)\n\n    case expr do\n      {_, meta, _} ->\n        case meta[:type_check] do\n          :anonymous_rescue ->\n            \"rescue \" <> string\n\n          :rescue ->\n            \"rescue \" <> string\n\n          {:invoked_as, mod, fun, arity} ->\n            string <> \"\\n#=> invoked as \" <> Exception.format_mfa(mod, fun, arity)\n\n          _ ->\n            string\n        end\n\n      _ ->\n        string\n    end\n  end\n\n  defp prewalk_expr_to_string(expr, opts) do\n    collapse_structs? = Keyword.get(opts, :collapse_structs, true)\n\n    expr\n    |> Macro.prewalk(fn\n      {:%, _, [Range, {:%{}, _, fields}]} = node ->\n        case :lists.usort(fields) do\n          [first: first, last: last, step: step] ->\n            quote do\n              unquote(first)..unquote(last)//unquote(step)\n            end\n\n          _ ->\n            node\n        end\n\n      {:%, struct_meta, [struct, {:%{}, map_meta, fields}]} = node\n      when collapse_structs? ->\n        try do\n          struct.__info__(:struct)\n        rescue\n          _ -> node\n        else\n          infos ->\n            filtered =\n              for {field, value} <- fields, not matches_default?(infos, field, value) do\n                {field, value}\n              end\n\n            if length(fields) != length(filtered) do\n              {:%, struct_meta, [struct, {:%{}, map_meta, [{:..., [], []} | filtered]}]}\n            else\n              node\n            end\n        end\n\n      {{:., _, [:lists, :member]}, meta, [expr, [_ | _] = args]} = call ->\n        if Enum.any?(args, &match?({:|, _, [_, _]}, &1)) do\n          call\n        else\n          {:in, meta, [expr, args]}\n        end\n\n      {{:., _, [Elixir.String.Chars, :to_string]}, meta, [arg]} ->\n        {:to_string, meta, [arg]}\n\n      {{:., _, [Elixir.List.Chars, :to_charlist]}, meta, [arg]} ->\n        {:to_charlist, meta, [arg]}\n\n      {{:., _, [mod, fun]}, meta, args} ->\n        erl_to_ex(mod, fun, args, meta)\n\n      {:fn, meta, [{:->, _, [_args, return]}]} = expr ->\n        if meta[:capture] do\n          {:&, meta, [return]}\n        else\n          expr\n        end\n\n      {:&, amp_meta, [{:/, slash_meta, [{{:., dot_meta, [mod, fun]}, call_meta, []}, arity]}]} ->\n        {mod, fun} =\n          case :elixir_rewrite.erl_to_ex(mod, fun, arity) do\n            {mod, fun} -> {mod, fun}\n            false -> {mod, fun}\n          end\n\n        {:&, amp_meta, [{:/, slash_meta, [{{:., dot_meta, [mod, fun]}, call_meta, []}, arity]}]}\n\n      {:case, meta, [expr, [do: clauses]]} ->\n        case meta[:type_check] do\n          {:case, _} ->\n            case clauses do\n              [\n                {:->, _,\n                 [\n                   [\n                     {:when, _,\n                      [\n                        {var, _, Kernel},\n                        {{:., _, [:erlang, :orelse]}, _,\n                         [\n                           {{:., _, [:erlang, :\"=:=\"]}, _, [{var, _, Kernel}, false]},\n                           {{:., _, [:erlang, :\"=:=\"]}, _, [{var, _, Kernel}, nil]}\n                         ]}\n                      ]}\n                   ],\n                   true\n                 ]},\n                {:->, _, [[{:_, _, Kernel}], false]}\n              ] ->\n                {:!, meta, [expr]}\n\n              [\n                {:->, _,\n                 [\n                   [\n                     {:when, _,\n                      [\n                        {var, _, Kernel},\n                        {{:., _, [:erlang, :orelse]}, _,\n                         [\n                           {{:., _, [:erlang, :\"=:=\"]}, _, [{var, _, Kernel}, false]},\n                           {{:., _, [:erlang, :\"=:=\"]}, _, [{var, _, Kernel}, nil]}\n                         ]}\n                      ]}\n                   ],\n                   right_side\n                 ]},\n                {:->, _, [[{var, _, Kernel}], {var, _, Kernel}]}\n              ] ->\n                {:||, meta, [expr, right_side]}\n\n              [\n                {:->, _,\n                 [\n                   [\n                     {:when, _,\n                      [\n                        {var, _, Kernel},\n                        {{:., _, [:erlang, :orelse]}, _,\n                         [\n                           {{:., _, [:erlang, :\"=:=\"]}, _, [{var, _, Kernel}, false]},\n                           {{:., _, [:erlang, :\"=:=\"]}, _, [{var, _, Kernel}, nil]}\n                         ]}\n                      ]}\n                   ],\n                   {var, _, Kernel}\n                 ]},\n                {:->, _, [[{:_, _, Kernel}], right_side]}\n              ] ->\n                {:&&, meta, [expr, right_side]}\n\n              [\n                {:->, _,\n                 [\n                   [\n                     {:when, _,\n                      [\n                        {var, _, Kernel},\n                        {{:., _, [:erlang, :orelse]}, _,\n                         [\n                           {{:., _, [:erlang, :\"=:=\"]}, _, [{var, _, Kernel}, false]},\n                           {{:., _, [:erlang, :\"=:=\"]}, _, [{var, _, Kernel}, nil]}\n                         ]}\n                      ]}\n                   ],\n                   else_block\n                 ]},\n                {:->, _, [[{:_, _, Kernel}], do_block]}\n              ] ->\n                {:if, meta, [expr, [do: do_block, else: else_block]]}\n\n              [\n                {:->, _, [[false], else_block]},\n                {:->, _, [[true], do_block]}\n              ] ->\n                {:if, meta, [expr, [do: do_block, else: else_block]]}\n\n              _ ->\n                {:case, meta, [expr, [do: {:..., [], []}]]}\n            end\n\n          _ ->\n            {:case, meta, [expr, [do: {:..., [], []}]]}\n        end\n\n      {:try, meta, [[do: _] ++ _]} ->\n        {:try, meta, [[do: {:..., [], []}]]}\n\n      {:cond, meta, [[do: _]]} ->\n        {:cond, meta, [[do: {:..., [], []}]]}\n\n      {:receive, meta, [[do: _] ++ _]} ->\n        {:receive, meta, [[do: {:..., [], []}]]}\n\n      {var, meta, context} = expr when is_atom(var) and is_atom(context) ->\n        if is_integer(meta[:capture]) do\n          {:&, meta, [meta[:capture]]}\n        else\n          expr\n        end\n\n      other ->\n        other\n    end)\n    |> Macro.to_string()\n  end\n\n  defp matches_default?(infos, field, value) do\n    case Enum.find(infos, &(&1.field == field)) do\n      %{default: default} -> Macro.escape(default) == value\n      _ -> false\n    end\n  end\n\n  defp erl_to_ex(\n         :erlang,\n         :error,\n         [expr, :none, [error_info: {:%{}, _, [module: Exception]}]],\n         meta\n       ) do\n    {:raise, meta, [expr]}\n  end\n\n  defp erl_to_ex(mod, fun, args, meta) do\n    case :elixir_rewrite.erl_to_ex(mod, fun, args) do\n      {Kernel, fun, args, _} -> {fun, meta, args}\n      {mod, fun, args, _} -> {{:., [], [mod, fun]}, meta, args}\n    end\n  end\n\n  @doc \"\"\"\n  Indents new lines.\n  \"\"\"\n  def indent(content, count) do\n    String.replace(content, \"\\n\", \"\\n\" <> String.duplicate(\" \", count))\n  end\n\n  @doc \"\"\"\n  Emits a warning.\n  \"\"\"\n  def warn(module, warning, meta, stack, context) do\n    if Keyword.get(meta, :generated, false) do\n      context\n    else\n      effectively_warn(module, warning, meta, stack, context)\n    end\n  end\n\n  defp effectively_warn(module, warning, meta, stack, context) do\n    {fun, arity} = stack.function\n    location = {stack.file, meta, {stack.module, fun, arity}}\n    %{context | warnings: [{module, warning, location} | context.warnings]}\n  end\n\n  @doc \"\"\"\n  Emits an error.\n\n  In practice an error is a warning that halts other errors from being collected.\n  \"\"\"\n  def error(module, warning, meta, stack, context) do\n    case context do\n      %{failed: true} ->\n        context\n\n      %{failed: false} ->\n        if Keyword.get(meta, :generated, false) do\n          context\n        else\n          effectively_warn(module, warning, meta, stack, %{context | failed: true})\n        end\n    end\n  end\n\n  @doc \"\"\"\n  The type to return when there is an error.\n  \"\"\"\n  def error_type, do: Module.Types.Descr.dynamic()\n\n  ## Enum helpers\n\n  def zip_map_reduce(args1, args2, acc, fun) do\n    zip_map_reduce(args1, args2, [], acc, fun)\n  end\n\n  defp zip_map_reduce([arg1 | args1], [arg2 | args2], list, acc, fun) do\n    {item, acc} = fun.(arg1, arg2, acc)\n    zip_map_reduce(args1, args2, [item | list], acc, fun)\n  end\n\n  defp zip_map_reduce([], [], list, acc, _fun) do\n    {Enum.reverse(list), acc}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/types/of.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Module.Types.Of do\n  # Typing functionality shared between Expr and Pattern.\n  # Generic AST and Enum helpers go to Module.Types.Helpers.\n  @moduledoc false\n  import Module.Types.{Helpers, Descr}\n\n  @prefix quote(do: ...)\n  @suffix quote(do: ...)\n\n  @integer_or_float union(integer(), float())\n  @integer integer()\n  @float float()\n  @binary binary()\n  @bitstring bitstring()\n\n  ## Variables\n\n  @doc \"\"\"\n  Fetches the type of a defined variable.\n  \"\"\"\n  def var({_name, meta, _context}, context) do\n    version = Keyword.fetch!(meta, :version)\n    %{vars: %{^version => %{type: type}}} = context\n    type\n  end\n\n  @doc \"\"\"\n  Marks a variable with error.\n\n  This purposedly deletes all traces of the variable,\n  as it is often invoked when the cause for error is elsewhere.\n  \"\"\"\n  def error_var({_, meta, _}, context) do\n    error_var(Keyword.fetch!(meta, :version), context)\n  end\n\n  def error_var(version, context) do\n    update_in(context.vars[version], fn\n      %{errored: true} = data -> data\n      data -> Map.put(%{data | type: error_type(), off_traces: []}, :errored, true)\n    end)\n  end\n\n  @doc \"\"\"\n  Declares a variable.\n  \"\"\"\n  def declare_var(var, type \\\\ term(), context) do\n    {var_name, meta, var_context} = var\n    version = Keyword.fetch!(meta, :version)\n\n    case context.vars do\n      %{^version => _} ->\n        context\n\n      vars ->\n        data = %{\n          type: type,\n          name: var_name,\n          context: var_context,\n          off_traces: [],\n          paths: [],\n          deps: %{}\n        }\n\n        %{context | vars: Map.put(vars, version, data)}\n    end\n  end\n\n  @doc \"\"\"\n  Tracks metadata about variables dependencies and paths.\n  \"\"\"\n  def track_var(version, new_deps, new_paths, context) do\n    update_in(context.vars[version], fn %{paths: paths, deps: deps} = data ->\n      %{data | paths: new_paths ++ paths, deps: Enum.reduce(new_deps, deps, &Map.put(&2, &1, []))}\n    end)\n  end\n\n  @doc \"\"\"\n  Refines a variable that already exists (in a body).\n\n  This only happens if the var contains a gradual type,\n  or if we are doing a guard analysis or occurrence typing.\n  Returns `true` if there was a refinement, `false` otherwise.\n  \"\"\"\n  @skip_refinement_for [term(), dynamic()]\n  def refine_body_var(var_or_version, type, expr, stack, context)\n\n  def refine_body_var({_, meta, _}, type, expr, stack, context) do\n    refine_body_var(Keyword.fetch!(meta, :version), type, expr, stack, context)\n  end\n\n  def refine_body_var(version, type, expr, stack, context)\n      when is_integer(version) or is_reference(version) do\n    %{vars: %{^version => %{type: old_type, off_traces: off_traces} = data} = vars} = context\n\n    context =\n      case context.conditional_vars do\n        %{} = conditional_vars ->\n          %{context | conditional_vars: Map.put(conditional_vars, version, true)}\n\n        nil ->\n          context\n      end\n\n    case context do\n      _ when type in @skip_refinement_for or is_map_key(data, :errored) ->\n        {old_type, context}\n\n      %{pattern_info: %{guard_context: guard_context}} ->\n        new_type = intersection(old_type, type)\n\n        case empty?(new_type) do\n          true when guard_context == :orelse ->\n            data = %{\n              data\n              | type: none(),\n                off_traces: new_trace(expr, none(), stack, off_traces)\n            }\n\n            {none(), %{context | vars: %{vars | version => data}}}\n\n          false when new_type != old_type ->\n            data = %{\n              data\n              | type: new_type,\n                off_traces: new_trace(expr, new_type, stack, off_traces)\n            }\n\n            {new_type, %{context | vars: %{vars | version => data}}}\n\n          _ ->\n            {old_type, context}\n        end\n\n      _ ->\n        case gradual?(old_type) and compatible_intersection(old_type, type) do\n          {:ok, new_type} when new_type != old_type ->\n            data = %{\n              data\n              | type: new_type,\n                off_traces: new_trace(expr, new_type, stack, off_traces)\n            }\n\n            {new_type, %{context | vars: %{vars | version => data}}}\n\n          _ ->\n            {old_type, context}\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Refines the type of a variable.\n\n  Since this happens in a head, we use intersection\n  because we want to refine types. Otherwise we should\n  use compatibility.\n  \"\"\"\n  def refine_head_var({_, meta, _}, type, expr, stack, context) do\n    refine_head_var(Keyword.fetch!(meta, :version), type, expr, stack, context)\n  end\n\n  def refine_head_var(version, type, expr, stack, context)\n      when is_integer(version) or is_reference(version) do\n    case context.vars do\n      %{^version => %{errored: true}} ->\n        {:ok, error_type(), context}\n\n      %{^version => %{type: old_type, off_traces: off_traces} = data} = vars ->\n        new_type = intersection(type, old_type)\n\n        data = %{\n          data\n          | type: new_type,\n            off_traces: new_trace(expr, type, stack, off_traces)\n        }\n\n        if empty?(new_type) do\n          data = Map.put(%{data | type: error_type()}, :errored, true)\n          context = %{context | vars: %{vars | version => data}}\n          {:error, old_type, context}\n        else\n          context = %{context | vars: %{vars | version => data}}\n          {:ok, new_type, context}\n        end\n    end\n  end\n\n  defp new_trace(nil, _type, _stack, traces),\n    do: traces\n\n  defp new_trace(expr, type, stack, traces),\n    do: [{expr, stack.file, type} | traces]\n\n  @doc \"\"\"\n  Preserves `context` in first argument while\n  resetting it to the vars in the second argument.\n  \"\"\"\n  def reset_vars(context, %{\n        subpatterns: subpatterns,\n        vars: vars,\n        conditional_vars: conditional_vars\n      }),\n      do: %{context | subpatterns: subpatterns, vars: vars, conditional_vars: conditional_vars}\n\n  @doc \"\"\"\n  Returns true if all entries have the same conditional vars.\n  \"\"\"\n  def all_same_conditional_vars?([{_, cond} | tail]) do\n    Enum.all?(tail, fn {_, tail_cond} -> cond == tail_cond end)\n  end\n\n  @doc \"\"\"\n  Executes the args with acc using conditional variables.\n  \"\"\"\n  def with_conditional_vars(args, acc, expr, stack, context, fun) do\n    %{vars: vars, conditional_vars: conditional_vars} = context\n\n    {vars_conds, {acc, context}} =\n      Enum.map_reduce(args, {acc, context}, fn arg, {acc, context} ->\n        {acc, context} = fun.(arg, acc, %{context | vars: vars, conditional_vars: %{}})\n        %{vars: vars, conditional_vars: cond_vars} = context\n        {{vars, cond_vars}, {acc, context}}\n      end)\n\n    context = %{context | vars: vars, conditional_vars: conditional_vars}\n    {acc, reduce_conditional_vars(vars_conds, expr, stack, context)}\n  end\n\n  @doc \"\"\"\n  Reduces conditional variables collected separately.\n  \"\"\"\n  def reduce_conditional_vars([{vars, cond} | vars_conds], expr, stack, context) do\n    %{vars: pre_vars} = context\n\n    Enum.reduce(Map.keys(cond), context, fn version, context ->\n      if is_map_key(pre_vars, version) and\n           Enum.all?(vars_conds, fn {_vars, cond} -> is_map_key(cond, version) end) do\n        %{^version => %{type: type}} = vars\n\n        type =\n          Enum.reduce(vars_conds, type, fn {vars, _cond}, acc ->\n            %{^version => %{type: type}} = vars\n            union(acc, type)\n          end)\n\n        {_, context} = refine_body_var(version, type, expr, stack, context)\n        context\n      else\n        context\n      end\n    end)\n  end\n\n  ## Implementations\n\n  impls = [\n    {Atom, atom()},\n    {BitString, bitstring()},\n    {Float, float()},\n    {Function, fun()},\n    {Integer, integer()},\n    {List, union(empty_list(), non_empty_list(term(), term()))},\n    {Map, open_map(__struct__: if_set(negation(atom())))},\n    {Port, port()},\n    {PID, pid()},\n    {Reference, reference()},\n    {Tuple, tuple()},\n    {Any, term()}\n  ]\n\n  @doc \"\"\"\n  Currently, for protocol implementations, we only store\n  the open struct definition. This is because we don't want\n  to reconsolidate whenever the struct changes, but at the\n  moment we can't store references either. Ideally struct\n  types on protocol dispatches would be lazily resolved.\n  \"\"\"\n  def impl(for, mode \\\\ :closed)\n\n  for {for, type} <- impls do\n    def impl(unquote(for), _mode), do: unquote(Macro.escape(type))\n  end\n\n  def impl(struct, mode) do\n    # Elixir did not strictly require the implementation to be available,\n    # so we need to deal with such cases accordingly.\n    # TODO: Assume implementation is available on Elixir v2.0.\n    # A warning is emitted since v1.19+.\n    if info = mode == :closed && Code.ensure_loaded?(struct) && struct.__info__(:struct) do\n      struct_type(struct, info)\n    else\n      open_map(__struct__: atom([struct]))\n    end\n  end\n\n  ## Map/structs\n\n  @doc \"\"\"\n  Handles fetching a map key.\n  \"\"\"\n  def map_fetch(expr, type, field, stack, context) when is_atom(field) do\n    case map_fetch_key(type, field) do\n      {_optional?, value_type} ->\n        {value_type, context}\n\n      reason ->\n        {error_type(), error({reason, expr, type, field, context}, elem(expr, 1), stack, context)}\n    end\n  end\n\n  @doc \"\"\"\n  Builds a closed map.\n  \"\"\"\n  def closed_map(pairs, expected, stack, context, of_fun) do\n    {pairs_types, context} = pairs(pairs, expected, stack, context, of_fun)\n\n    {dynamic?, domain, single, multiple} =\n      Enum.reduce(pairs_types, {false, [], [], []}, fn\n        {pos_neg_domain, dynamic_pair?, value_type}, {dynamic?, domain, single, multiple} ->\n          dynamic? = dynamic? or dynamic_pair?\n\n          case pos_neg_domain do\n            # If atom is included in domain keys, it unions all previous\n            # single and multiple, except the ones negated:\n            #\n            #     %{foo: :bar, term() => :baz}\n            #     #=> %{foo: :bar or :baz, term() => :baz}\n            #\n            #     %{foo: :bar, not :foo => :baz}\n            #     #=> %{foo: :bar, term() => :baz}\n            #\n            # In case the negated term does not appear, we set it to none():\n            #\n            #     %{foo: :bar, term() => :baz}\n            #     #=> %{term() => :baz, foo: :bar or :baz}\n            #\n            #     %{not :foo => :baz}\n            #     #=> %{term() => :baz, foo: none()}\n            #\n            # In case we are dealing with multiple keys, we always merge the\n            # domain. A more precise approach would be to postpone doing so\n            # until the cartesian map is distributed but those should be very\n            # uncommon.\n            {[], negs, domain_keys} ->\n              if :atom in domain_keys do\n                {single, multiple} = union_negated(negs, value_type, single, multiple)\n                {dynamic?, [{domain_keys, value_type} | domain], single, multiple}\n              else\n                {dynamic?, [{domain_keys, value_type} | domain], single, multiple}\n              end\n\n            {pos, [], domain_keys} ->\n              domain =\n                case domain_keys do\n                  [] -> domain\n                  _ -> [{domain_keys, value_type} | domain]\n                end\n\n              case pos do\n                # Because a multiple key may override single keys, we can only\n                # collect single keys while there are no multiples.\n                [key] when multiple == [] ->\n                  {dynamic?, domain, [{key, value_type} | single], multiple}\n\n                _ ->\n                  {dynamic?, domain, single, [{pos, value_type} | multiple]}\n              end\n          end\n      end)\n\n    non_multiple = Enum.reverse(single, domain)\n\n    map =\n      case Enum.reverse(multiple) do\n        [] ->\n          closed_map(non_multiple)\n\n        [{keys, type} | tail] ->\n          for key <- keys, t <- cartesian_map(tail) do\n            closed_map(non_multiple ++ [{key, type} | t])\n          end\n          |> Enum.reduce(&union/2)\n      end\n\n    {if(dynamic?, do: dynamic(map), else: map), context}\n  end\n\n  defp union_negated([], new_type, single, multiple) do\n    single = Enum.map(single, fn {key, old_type} -> {key, union(old_type, new_type)} end)\n    multiple = Enum.map(multiple, fn {keys, old_type} -> {keys, union(old_type, new_type)} end)\n    {single, multiple}\n  end\n\n  defp union_negated(negated, new_type, single, multiple) do\n    {single, matched} =\n      Enum.map_reduce(single, [], fn {key, old_type}, matched ->\n        if key in negated do\n          {{key, old_type}, [key | matched]}\n        else\n          {{key, union(old_type, new_type)}, matched}\n        end\n      end)\n\n    multiple =\n      Enum.map(multiple, fn {keys, old_type} ->\n        {keys, union(old_type, new_type)}\n      end)\n\n    {Enum.map(negated -- matched, fn key -> {key, not_set()} end) ++ single, multiple}\n  end\n\n  defp pairs(pairs, expected, stack, context, of_fun) do\n    Enum.map_reduce(pairs, context, fn {key, value}, context ->\n      {pos_neg_domain, dynamic_key?, context} = map_key_type(key, stack, context, of_fun)\n\n      expected_value_type =\n        with {[key], [], []} <- pos_neg_domain,\n             {_, expected_value_type} <- map_fetch_key(expected, key) do\n          expected_value_type\n        else\n          _ -> term()\n        end\n\n      {value_type, context} = of_fun.(value, expected_value_type, stack, context)\n      {{pos_neg_domain, dynamic_key? or gradual?(value_type), value_type}, context}\n    end)\n  end\n\n  defp map_key_type(key, _stack, context, _of_fun) when is_atom(key) do\n    {{[key], [], []}, false, context}\n  end\n\n  defp map_key_type(key, stack, context, of_fun) do\n    {key_type, context} = of_fun.(key, term(), stack, context)\n    domain_keys = to_domain_keys(key_type)\n\n    pos_neg_domain =\n      case atom_fetch(key_type) do\n        {:finite, list} -> {list, [], List.delete(domain_keys, :atom)}\n        {:infinite, list} -> {[], list, domain_keys}\n        :error -> {[], [], domain_keys}\n      end\n\n    {pos_neg_domain, gradual?(key_type), context}\n  end\n\n  defp cartesian_map(lists) do\n    case lists do\n      [] ->\n        [[]]\n\n      [{keys, type} | tail] ->\n        for key <- keys, t <- cartesian_map(tail), do: [{key, type} | t]\n    end\n  end\n\n  @doc \"\"\"\n  Handles instantiation of a new struct.\n\n  This is expanded and validated by the compiler, so don't need to check the fields.\n  \"\"\"\n  # TODO: Type check the fields match the struct\n  def struct_instance(struct, args, expected, meta, stack, context, of_fun)\n      when is_atom(struct) do\n    {info, context} = struct_info(struct, :expr, meta, stack, context)\n\n    if is_nil(info) do\n      raise \"expected #{inspect(struct)} to return struct metadata, but got none\"\n    end\n\n    # The compiler has already checked the keys are atoms and which ones are required.\n    {args_types, context} =\n      Enum.map_reduce(args, context, fn {key, value}, context when is_atom(key) ->\n        value_type =\n          case map_fetch_key(expected, key) do\n            {_, expected_value_type} -> expected_value_type\n            _ -> term()\n          end\n\n        {type, context} = of_fun.(value, value_type, stack, context)\n        {{key, type}, context}\n      end)\n\n    {closed_map([{:__struct__, atom([struct])} | args_types]), context}\n  end\n\n  @doc \"\"\"\n  Returns `__info__(:struct)` information about a struct.\n  \"\"\"\n  def struct_info(struct, kind, meta, stack, context) do\n    case stack.no_warn_undefined do\n      %Macro.Env{} = env ->\n        case :elixir_map.maybe_load_struct_info(meta, struct, env) do\n          {:ok, info} -> {info, context}\n          {:error, _desc} -> {nil, context}\n        end\n\n      _ ->\n        info =\n          Code.ensure_loaded?(struct) and function_exported?(struct, :__info__, 1) and\n            struct.__info__(:struct)\n\n        if info do\n          {_, context} =\n            Module.Types.Apply.signature(struct, :__struct__, 0, meta, stack, context)\n\n          {info, context}\n        else\n          error = {:unknown_struct, kind, struct}\n          {nil, error(error, meta, stack, context)}\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Builds a type from the struct info.\n  \"\"\"\n  # TODO: This function should not receive args_types once\n  # we introduce typed structs. They are only used by exceptions.\n  def struct_type(struct, info, args_types \\\\ []) do\n    term = dynamic()\n    pairs = for %{field: field} <- info, do: {field, term}\n    pairs = [{:__struct__, atom([struct])} | pairs]\n    pairs = if args_types == [], do: pairs, else: pairs ++ args_types\n    closed_map(pairs)\n  end\n\n  @doc \"\"\"\n  Returns shared error for unknown struct field.\n  \"\"\"\n  def unknown_struct_field(struct, field, kind, meta, stack, context) do\n    error = {:unknown_struct_field, kind, struct, field}\n    error(error, meta, stack, context)\n  end\n\n  ## Bitstrings\n\n  @doc \"\"\"\n  Handles bitstrings.\n\n  In the stack, we add nodes such as <<expr>>, <<..., expr>>, etc,\n  based on the position of the expression within the binary.\n  \"\"\"\n  def bitstring([], _kind, _stack, context) do\n    {binary(), context}\n  end\n\n  def bitstring([head], kind, stack, context) do\n    {alignment, context} = bitstring_segment(head, kind, [head], stack, context)\n    {alignment_to_type(alignment), context}\n  end\n\n  def bitstring([head | tail], kind, stack, context) do\n    {alignment, context} = bitstring_segment(head, kind, [head, @suffix], stack, context)\n    bitstring_tail(tail, alignment, kind, stack, context)\n  end\n\n  defp bitstring_tail([last], alignment, kind, stack, context) do\n    {seg_alignment, context} = bitstring_segment(last, kind, [@prefix, last], stack, context)\n    {alignment_to_type(alignment(seg_alignment, alignment)), context}\n  end\n\n  defp bitstring_tail([head | tail], alignment, kind, stack, context) do\n    {seg_alignment, context} =\n      bitstring_segment(head, kind, [@prefix, head, @suffix], stack, context)\n\n    bitstring_tail(tail, alignment(seg_alignment, alignment), kind, stack, context)\n  end\n\n  defp alignment(left, right) when is_integer(left) and is_integer(right), do: left + right\n  defp alignment(_left, _right), do: :unknown\n\n  defp alignment_to_type(:unknown), do: bitstring()\n  defp alignment_to_type(integer) when rem(integer, 8) == 0, do: binary()\n  defp alignment_to_type(_integer), do: bitstring_no_binary()\n\n  # If the segment is a literal, the compiler has already checked its validity,\n  # so we just check the size.\n  defp bitstring_segment({:\"::\", _meta, [left, right]}, kind, _args, stack, context)\n       when is_binary(left) or is_number(left) do\n    {_type, alignment_type} = specifier_type(kind, right)\n    {alignment_value, context} = specifier_size(kind, right, stack, {:default, context})\n\n    # We don't need to check for bitstrings because the left side\n    # is either a binary (aligned), float (aligned), or integer\n    # (which we check below).\n    if alignment_type == :integer and alignment_value != :default do\n      {alignment_value, context}\n    else\n      {0, context}\n    end\n  end\n\n  defp bitstring_segment({:\"::\", meta, [left, right]}, kind, args, stack, context) do\n    {type, alignment_type} = specifier_type(kind, right)\n    expr = {:<<>>, meta, args}\n\n    {actual, context} =\n      case kind do\n        :match ->\n          Module.Types.Pattern.of_match_var(left, type, expr, stack, context)\n\n        :guard ->\n          Module.Types.Pattern.of_guard(left, type, expr, stack, context)\n\n        :expr ->\n          left = annotate_interpolation(left, right)\n          Module.Types.Expr.of_expr(left, type, expr, stack, context)\n      end\n\n    if compatible?(actual, type) do\n      {alignment_value, context} = specifier_size(kind, right, stack, {:default, context})\n\n      case alignment_type do\n        :aligned ->\n          {0, context}\n\n        :integer when alignment_value == :default ->\n          {0, context}\n\n        # There is no size, so the alignment depends on the type.\n        # If the type is exclusively a binary, then it is aligned.\n        :bitstring when alignment_value == :default ->\n          if bitstring_no_binary_type?(actual), do: {:unknown, context}, else: {0, context}\n\n        _ ->\n          {alignment_value, context}\n      end\n    else\n      error = {:badbinary, kind, meta, expr, type, actual, context}\n      {:unknown, error(error, meta, stack, context)}\n    end\n  end\n\n  defp annotate_interpolation(\n         {{:., _, [String.Chars, :to_string]} = dot, meta, [arg]},\n         {:binary, _, nil}\n       ) do\n    {dot, [type_check: :interpolation] ++ meta, [arg]}\n  end\n\n  defp annotate_interpolation(left, _right) do\n    left\n  end\n\n  defp specifier_type(kind, {:-, _, [left, _right]}), do: specifier_type(kind, left)\n  defp specifier_type(:match, {:utf8, _, _}), do: {@integer, :aligned}\n  defp specifier_type(:match, {:utf16, _, _}), do: {@integer, :aligned}\n  defp specifier_type(:match, {:utf32, _, _}), do: {@integer, :aligned}\n  defp specifier_type(:match, {:float, _, _}), do: {@float, :aligned}\n  defp specifier_type(_kind, {:float, _, _}), do: {@integer_or_float, :aligned}\n  defp specifier_type(_kind, {:utf8, _, _}), do: {@integer, :aligned}\n  defp specifier_type(_kind, {:utf16, _, _}), do: {@integer, :aligned}\n  defp specifier_type(_kind, {:utf32, _, _}), do: {@integer, :aligned}\n  defp specifier_type(_kind, {:integer, _, _}), do: {@integer, :integer}\n  defp specifier_type(_kind, {:bits, _, _}), do: {@bitstring, :bitstring}\n  defp specifier_type(_kind, {:bitstring, _, _}), do: {@bitstring, :bitstring}\n  defp specifier_type(_kind, {:bytes, _, _}), do: {@binary, :aligned}\n  defp specifier_type(_kind, {:binary, _, _}), do: {@binary, :aligned}\n  defp specifier_type(_kind, _specifier), do: {@integer, :integer}\n\n  defp specifier_size(kind, {:-, _, [left, right]}, stack, align_context) do\n    specifier_size(kind, right, stack, specifier_size(kind, left, stack, align_context))\n  end\n\n  defp specifier_size(_, {:size, _, [arg]}, _stack, {unit, context})\n       when is_integer(arg) do\n    size = if unit == :default, do: arg, else: arg * unit\n    {size, context}\n  end\n\n  defp specifier_size(:expr, {:size, _, [arg]} = expr, stack, {_, context}) do\n    {actual, context} = Module.Types.Expr.of_expr(arg, integer(), expr, stack, context)\n    {:unknown, compatible_size(actual, expr, stack, context)}\n  end\n\n  defp specifier_size(_match_or_guard, {:size, _, [arg]} = expr, stack, {_, context}) do\n    {actual, context} = Module.Types.Pattern.of_guard(arg, integer(), expr, stack, context)\n    {:unknown, compatible_size(actual, expr, stack, context)}\n  end\n\n  # We currently assume the unit always comes before size\n  defp specifier_size(_, {:unit, _, [unit]}, _stack, {:default, context}) do\n    {unit, context}\n  end\n\n  defp specifier_size(_kind, _specifier, _stack, align_context) do\n    align_context\n  end\n\n  defp compatible_size(actual, expr, stack, context) do\n    if compatible?(actual, integer()) do\n      context\n    else\n      error = {:badsize, expr, actual, context}\n      error(error, elem(expr, 1), stack, context)\n    end\n  end\n\n  ## Modules\n\n  @doc \"\"\"\n  Returns modules in a type.\n\n  The call information is used on report reporting.\n  \"\"\"\n  def modules(type, fun, arity, hints \\\\ [], expr, meta, stack, context) do\n    case atom_fetch(type) do\n      {:finite, mods} ->\n        {mods, context}\n\n      {:infinite, _} ->\n        {[], context}\n\n      :error ->\n        warning = {:badmodule, expr, type, fun, arity, hints, context}\n        {[], error(warning, meta, stack, context)}\n    end\n  end\n\n  ## Warning\n\n  defp error(warning, meta, stack, context) do\n    error(__MODULE__, warning, meta, stack, context)\n  end\n\n  def format_diagnostic({:badbinary, kind, meta, expr, expected_type, actual_type, context}) do\n    type = if kind == :match, do: \"matching\", else: \"construction\"\n    hints = if meta[:inferred_bitstring_spec], do: [:inferred_bitstring_spec], else: []\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          incompatible types in binary #{type}:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          got type:\n\n              #{to_quoted_string(actual_type) |> indent(4)}\n\n          but expected type:\n\n              #{to_quoted_string(expected_type) |> indent(4)}\n          \"\"\",\n          format_traces(traces),\n          format_hints(hints)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badsize, expr, type, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected an integer in binary size:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badmodule, expr, type, fun, arity, hints, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected a module (an atom) when invoking #{fun}/#{arity} in expression:\n\n              #{expr_to_string(expr) |> indent(4)}\n          \"\"\",\n          empty_if(dot_var?(expr), \"\"\"\n\n          but got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\"),\n          format_traces(traces),\n          format_hints(hints)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badmap, expr, type, key, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected a map or struct when accessing .#{key} in expression:\n\n              #{expr_to_string(expr) |> indent(4)}\n          \"\"\",\n          empty_if(dot_var?(expr), \"\"\"\n\n          but got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\"),\n          format_traces(traces),\n          format_hints([:dot])\n        ])\n    }\n  end\n\n  def format_diagnostic({:badkey, expr, type, key, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      span: expr |> get_meta() |> :elixir_env.calculate_span(key) |> Keyword.get(:span),\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          unknown key .#{key} in expression:\n\n              #{expr_to_string(expr, collapse_structs: false) |> indent(4)}\n\n          the given type does not have the given key:\n\n              #{to_quoted_string(type, collapse_structs: false) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:unknown_struct, kind, module}) do\n    message =\n      if Code.ensure_loaded?(module) do\n        \"struct #{inspect(module)} is undefined (there is such module but it does not define a struct)\"\n      else\n        \"struct #{inspect(module)} is undefined \" <>\n          \"(module #{inspect(module)} is not available or is yet to be defined)\"\n      end\n\n    %{\n      message: message,\n      group: true,\n      severity: if(kind == :pattern, do: :error, else: :warning)\n    }\n  end\n\n  def format_diagnostic({:unknown_struct_field, kind, module, field}) do\n    %{\n      message: \"unknown key #{inspect(field)} for struct #{inspect(module)}\",\n      group: true,\n      severity: if(kind == :pattern, do: :error, else: :warning)\n    }\n  end\n\n  defp dot_var?(expr) do\n    match?({{:., _, [var, _fun]}, _, _args} when is_var(var), expr)\n  end\n\n  defp empty_if(condition, content) do\n    if condition, do: \"\", else: content\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/types/pattern.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Module.Types.Pattern do\n  @moduledoc false\n\n  alias Module.Types.{Apply, Of}\n  import Module.Types.{Helpers, Descr}\n\n  @doc \"\"\"\n  Returns the initial value for previous clause information.\n  \"\"\"\n  def init_previous do\n    {[], none()}\n  end\n\n  defp empty_previous?({[], _}), do: true\n  defp empty_previous?({[_ | _], _}), do: false\n\n  defp previous_subtype?(_, {[], _}), do: false\n  defp previous_subtype?([], _), do: true\n  defp previous_subtype?(args, {_, descr}), do: subtype?(args_to_previous(args), descr)\n\n  defp concat_previous([], previous),\n    do: previous\n\n  defp concat_previous(types, {list, descr}),\n    do: {[types | list], union(descr, args_to_previous(types))}\n\n  defp args_to_previous([type]), do: upper_bound(type)\n  defp args_to_previous(types), do: args_to_static_domain(types)\n\n  defp of_pattern_previous(types, {[], _}, _stack) do\n    {types, false}\n  end\n\n  defp of_pattern_previous(types, {_, descr}, stack) do\n    refined_types =\n      case types do\n        [type] -> [difference(type, descr)]\n        [_ | _] -> args_to_domain(types) |> difference(descr) |> domain_to_flat_args(types)\n      end\n\n    # check_previous? is an optimization. If types have not changed,\n    # it means args_types and previous are disjoint, and any further\n    # refinement will keep them disjoint, so no need to check for previous.\n    {refined_types, stack.mode != :infer and types != refined_types}\n  end\n\n  defp previous_to_string({list, _}) do\n    Enum.map_join(list, \"\\n    \", fn types ->\n      types\n      |> Enum.map_join(\", \", &(&1 |> upper_bound() |> to_quoted_string()))\n      |> indent(4)\n    end)\n  end\n\n  @doc \"\"\"\n  Refine the dependencies of variables represented by version.\n  \"\"\"\n  def of_changed([], _stack, context) do\n    context\n  end\n\n  def of_changed([_ | _] = versions, stack, %{vars: vars} = context) do\n    {changed, seen} =\n      Enum.reduce(versions, {[], []}, fn version, changed_seen ->\n        %{^version => %{deps: deps}} = vars\n\n        # An optimized version for of_changed_seen for the first pass\n        deps\n        |> Map.keys()\n        |> Enum.reduce(changed_seen, fn dep_version, {changed, seen} ->\n          {[{dep_version, version} | changed], [[version | dep_version] | seen]}\n        end)\n      end)\n\n    of_changed_deps(:maps.from_list(changed), Map.from_keys(seen, true), stack, context)\n  end\n\n  defp of_changed_seen(deps, version, source_version, changed_seen) do\n    deps\n    |> Map.keys()\n    |> Enum.reduce(changed_seen, fn\n      # We don't point back to the thing that caused us to change.\n      # In case both changed at once, the other side will be pointed\n      # to naturally. Otherwise it has to be pointed to through other nodes.\n      ^source_version, {changed, seen} ->\n        {changed, seen}\n\n      dep_version, {changed, seen} ->\n        edge = [version | dep_version]\n\n        case seen do\n          %{^edge => _} -> {changed, seen}\n          %{} -> {Map.put(changed, dep_version, version), Map.put(seen, edge, true)}\n        end\n    end)\n  end\n\n  defp of_changed_deps(changed, _seen, _stack, context) when changed == %{} do\n    context\n  end\n\n  defp of_changed_deps(previous_changed, seen, stack, context) do\n    {{changed, seen}, context} =\n      Enum.reduce(previous_changed, {{%{}, seen}, context}, fn\n        {version, source_version}, {changed_seen, context} ->\n          {deps, context} = of_changed_var(version, stack, context)\n          {of_changed_seen(deps, version, source_version, changed_seen), context}\n      end)\n\n    of_changed_deps(changed, seen, stack, context)\n  end\n\n  defp of_changed_var(version, stack, context) do\n    case context.vars do\n      %{^version => %{type: old_type, deps: deps, paths: paths} = data}\n      when not is_map_key(data, :errored) ->\n        try do\n          Enum.reduce(paths, {%{}, context}, fn\n            %{var: var, expr: expr, root: root, path: path}, {new_deps, context} ->\n              actual = of_pattern_tree(root, stack, context)\n\n              case of_pattern_var(path, actual, context) do\n                {:ok, new_type} ->\n                  # Optimization: if current type is already a subtype,\n                  # there is nothing to refine\n                  if old_type != term() and subtype?(old_type, new_type) do\n                    {new_deps, context}\n                  else\n                    case Of.refine_head_var(version, new_type, expr, stack, context) do\n                      {:ok, _type, context} ->\n                        # Return the actual deps to be recomputed\n                        {deps, context}\n\n                      {:error, _old_type, error_context} ->\n                        if match_error?(var, new_type) do\n                          throw(badmatch_error(var, expr, stack, context))\n                        else\n                          throw(badvar_error(var, old_type, new_type, stack, error_context))\n                        end\n                    end\n                  end\n\n                :error ->\n                  throw(badmatch_error(var, expr, stack, context))\n              end\n          end)\n        catch\n          context -> {%{}, context}\n        end\n\n      _ ->\n        {%{}, context}\n    end\n  end\n\n  @doc \"\"\"\n  Handles patterns and guards at once.\n\n  The algorithm works as follows:\n\n  1. First we traverse the patterns and build a pattern tree\n     (which tells how to compute the type of a pattern) alongside\n     the variable dependencies (which tells us how to compute the type\n     of a variable).\n\n  2. Then we traverse the pattern tree and compute the intersection\n     between the pattern and the expected types (which is currently dynamic).\n\n  3. Then we compute the guards and propagate new dependencies\n\n  4. Then we propagate all dependencies to refine variables\n\n  Every step we deduct previous clauses from the current ones and,\n  in case of failures, we try to break down the root cause.\n  \"\"\"\n  def of_head(patterns, guards, expected, previous, tag, meta, stack, original) do\n    stack = %{stack | meta: meta}\n\n    {trees, precise?, check_previous?, args_types, context} =\n      of_precise_head(patterns, guards, expected, previous, tag, stack, original)\n\n    if context.failed and stack.mode != :infer and not empty_previous?(previous) and\n         Keyword.get(meta, :generated, false) != true do\n      # If it failed, let's try to break it down to a better error message.\n      # First we check if it fails without previous, if it doesn't, check if it is redundant.\n      case of_precise_head(patterns, guards, expected, init_previous(), tag, stack, original) do\n        {other_trees, _, _, _, %{failed: true} = other_context} ->\n          {other_trees, previous, other_context}\n\n        {other_trees, _, _, args_types, other_context} ->\n          if previous_subtype?(args_types, previous) do\n            warning = {:redundant, tag, expected, args_types, previous, other_context}\n            {other_trees, previous, warn(__MODULE__, warning, meta, stack, other_context)}\n          else\n            {trees, previous, context}\n          end\n      end\n    else\n      cond do\n        check_previous? and previous_subtype?(args_types, previous) ->\n          warning = {:redundant, tag, expected, args_types, previous, context}\n          {trees, previous, warn(__MODULE__, warning, meta, stack, context)}\n\n        precise? ->\n          {trees, concat_previous(args_types, previous), context}\n\n        true ->\n          {trees, previous, context}\n      end\n    end\n  end\n\n  defp of_precise_head([], guards, _expected, _previous, _tag, stack, context) do\n    %{vars: vars} = context\n    {guard_precise?, changed, context} = of_guards(guards, vars, stack, context)\n    {[], guard_precise?, false, [], of_changed(Map.keys(changed), stack, context)}\n  end\n\n  defp of_precise_head(patterns, guards, expected, previous, tag, stack, context) do\n    %{vars: vars} = context\n    context = init_pattern_info(context, [])\n\n    {trees, pattern_precise?, context} =\n      of_pattern_args_zip(patterns, expected, 0, [], true, stack, context)\n\n    {pattern_info, context} = pop_pattern_info(context)\n    {guard_precise?, changed, context} = of_guards(guards, vars, stack, context)\n\n    with {:ok, types} <-\n           of_pattern_intersect(trees, 0, [], pattern_info, tag, stack, context),\n         # We compute the args types before we do the intersection with previous clauses\n         args_types =\n           (with [_ | _] <- previous,\n                 {:ok, _types, context} <-\n                   of_pattern_refine(types, changed, pattern_info, tag, stack, context) do\n              trees_to_args_types(trees, stack, context)\n            else\n              _ -> nil\n            end),\n         {types, check_previous?} = of_pattern_previous(types, previous, stack),\n         {:ok, _types, context} <-\n           of_pattern_refine(types, changed, pattern_info, tag, stack, context) do\n      {trees, pattern_precise? and guard_precise?, check_previous?,\n       args_types || trees_to_args_types(trees, stack, context), context}\n    else\n      {:error, context} ->\n        {trees, false, false, trees_to_args_types(trees, stack, context), context}\n    end\n  end\n\n  defp trees_to_args_types(trees, stack, context) do\n    Enum.map(trees, fn {tree, _, _} ->\n      of_pattern_tree(tree, stack, context)\n    end)\n  end\n\n  @doc \"\"\"\n  Computes the domain from the pattern tree and expected types.\n\n  Note we use `upper_bound` because the user of dynamic in the signature\n  won't make a difference.\n  \"\"\"\n  def of_domain([{tree, expected, _pattern} | trees], stack, context) do\n    [\n      intersection(of_pattern_tree(tree, stack, context), expected) |> upper_bound()\n      | of_domain(trees, stack, context)\n    ]\n  end\n\n  def of_domain([], _stack, _context) do\n    []\n  end\n\n  defp of_pattern_args_zip(\n         [pattern | tail],\n         [expected | types],\n         index,\n         acc,\n         precise?,\n         stack,\n         context\n       ) do\n    {tree, pattern_precise?, context} =\n      of_pattern(pattern, [%{root: {:arg, index}, expr: pattern}], stack, context)\n\n    precise? = pattern_precise? and precise?\n    acc = [{tree, expected, pattern} | acc]\n    of_pattern_args_zip(tail, types, index + 1, acc, precise?, stack, context)\n  end\n\n  defp of_pattern_args_zip([], _types, _index, acc, precise?, _stack, context),\n    do: {Enum.reverse(acc), precise?, context}\n\n  @doc \"\"\"\n  Handles the match operator.\n  \"\"\"\n  def of_match(pattern, expected_fun, expr, stack, context) do\n    context = init_pattern_info(context, [])\n\n    {tree, _precise?, context} =\n      of_pattern(pattern, [%{root: {:arg, 0}, expr: expr}], stack, context)\n\n    {pattern_info, context} = pop_pattern_info(context)\n    {expected, context} = expected_fun.(of_pattern_tree(tree, stack, context), context)\n\n    args = [{tree, expected, expr}]\n    tag = {:match, expr, expected}\n\n    with {:ok, types} <-\n           of_pattern_intersect(args, 0, [], pattern_info, tag, stack, context),\n         {:ok, [type], context} <-\n           of_pattern_refine(types, %{}, pattern_info, tag, stack, context) do\n      {type, context}\n    else\n      {:error, context} -> {expected, context}\n    end\n  end\n\n  @doc \"\"\"\n  Handles matches in generators.\n  \"\"\"\n  def of_generator(pattern, guards, expected, tag, expr, stack, %{vars: vars} = context) do\n    context = init_pattern_info(context, [])\n\n    {tree, _precise?, context} =\n      of_pattern(pattern, [%{root: {:arg, 0}, expr: expr}], stack, context)\n\n    {pattern_info, context} = pop_pattern_info(context)\n    args = [{tree, expected, pattern}]\n    {_precise?, changed, context} = of_guards(guards, vars, stack, context)\n\n    with {:ok, types} <-\n           of_pattern_intersect(args, 0, [], pattern_info, tag, stack, context),\n         {:ok, _types, context} <-\n           of_pattern_refine(types, changed, pattern_info, tag, stack, context) do\n      context\n    else\n      {:error, context} -> context\n    end\n  end\n\n  defp of_pattern_intersect([head | tail], index, acc, pattern_info, tag, stack, context) do\n    {tree, expected, pattern} = head\n    actual = of_pattern_tree(tree, stack, context)\n    type = intersection(actual, expected)\n\n    if empty?(type) do\n      context = badpattern_error(pattern, index, tag, stack, context)\n      {:error, error_vars(pattern_info, context)}\n    else\n      acc = [type | acc]\n      of_pattern_intersect(tail, index + 1, acc, pattern_info, tag, stack, context)\n    end\n  end\n\n  defp of_pattern_intersect([], _index, acc, _pattern_info, _tag, _stack, _context) do\n    {:ok, Enum.reverse(acc)}\n  end\n\n  defp of_pattern_refine(types, changed, pattern_info, tag, stack, context) do\n    pattern_info\n    |> Enum.reverse()\n    |> Enum.reduce({changed, context}, fn {version, _pinned, node}, {changed, context} ->\n      %{var: var, expr: expr, root: root, path: path} = node\n\n      {actual, index} =\n        case root do\n          {:arg, index} -> {Enum.fetch!(types, index), index}\n          _ -> {of_pattern_tree(root, stack, context), nil}\n        end\n\n      context =\n        case of_pattern_var(path, actual, context) do\n          {:ok, new_type} ->\n            case Of.refine_head_var(var, new_type, expr, stack, context) do\n              {:ok, _type, context} ->\n                context\n\n              {:error, old_type, error_context} ->\n                if match_error?(var, new_type) do\n                  throw(badpattern_error(expr, index, tag, stack, context))\n                else\n                  throw(badvar_error(var, old_type, new_type, stack, error_context))\n                end\n            end\n\n          :error ->\n            throw(badpattern_error(expr, index, tag, stack, context))\n        end\n\n      {Map.put(changed, version, true), context}\n    end)\n  catch\n    context -> {:error, error_vars(pattern_info, context)}\n  else\n    {changed, context} ->\n      {:ok, types, of_changed(Map.keys(changed), stack, context)}\n  end\n\n  defp error_vars(pattern_info, context) do\n    Enum.reduce(pattern_info, context, fn\n      {_version, true, _}, context -> context\n      {version, false, _}, context -> Of.error_var(version, context)\n    end)\n  end\n\n  defp match_var do\n    version = make_ref()\n    {version, {:match, [version: version], __MODULE__}}\n  end\n\n  defp match_error?({:match, _, __MODULE__}, _type), do: true\n  defp match_error?(_var, type), do: empty?(type)\n\n  defp badvar_error(var, old_type, new_type, stack, context) do\n    error = {:badvar, old_type, new_type, var, context}\n    error(__MODULE__, error, error_meta(var, stack), stack, context)\n  end\n\n  defp badmatch_error(var, expr, stack, context) do\n    meta = error_meta(expr, stack)\n    context = Of.error_var(var, context)\n    error = {:badmatch, meta, expr, context}\n    error(__MODULE__, error, meta, stack, context)\n  end\n\n  defp badpattern_error(expr, index, tag, stack, context) do\n    meta = error_meta(expr, stack)\n\n    error =\n      if is_integer(index) do\n        {:badpattern, meta, index, tag, context}\n      else\n        {:badmatch, meta, expr, context}\n      end\n\n    error(__MODULE__, error, meta, stack, context)\n  end\n\n  defp error_meta(expr, stack) do\n    if meta = get_meta(expr) do\n      meta ++ Keyword.take(stack.meta, [:generated, :line, :type_check])\n    else\n      stack.meta\n    end\n  end\n\n  defp init_pattern_info(context, value) do\n    %{context | pattern_info: value}\n  end\n\n  defp pop_pattern_info(%{pattern_info: pattern_info} = context) do\n    {pattern_info, %{context | pattern_info: nil}}\n  end\n\n  defp of_pattern_var([], type, _context) do\n    {:ok, type}\n  end\n\n  defp of_pattern_var([{:elem, index} | rest], type, context)\n       when is_integer(index) do\n    case tuple_fetch(type, index) do\n      {_optional?, type} -> of_pattern_var(rest, type, context)\n      _reason -> :error\n    end\n  end\n\n  defp of_pattern_var([{:key, field} | rest], type, context)\n       when is_atom(field) do\n    case map_fetch_key(type, field) do\n      {_optional?, type} -> of_pattern_var(rest, type, context)\n      _reason -> :error\n    end\n  end\n\n  defp of_pattern_var([{:domain, domain} | rest], type, context) do\n    case map_get(type, domain) do\n      {:ok, type} -> of_pattern_var(rest, type, context)\n      _ -> :error\n    end\n  end\n\n  defp of_pattern_var([:head | rest], type, context) do\n    case list_hd(type) do\n      {:ok, head} -> of_pattern_var(rest, head, context)\n      _ -> :error\n    end\n  end\n\n  defp of_pattern_var([{:subpattern, key} | rest], type, context) do\n    %{^key => subpattern} = context.subpatterns\n    of_pattern_var(rest, intersection(type, subpattern), context)\n  end\n\n  defp of_pattern_var([:tail | rest], type, context) do\n    case list_tl(type) do\n      {:ok, tail} -> of_pattern_var(rest, tail, context)\n      :badnonemptylist -> :error\n    end\n  end\n\n  # Receives the pattern tree and the context and returns a concrete type.\n  defp of_pattern_tree(descr, _stack, _context) when is_descr(descr),\n    do: descr\n\n  defp of_pattern_tree({:guard, name, polarity, guard, expr}, stack, context) do\n    {type, _context} = of_guard(guard, term(), expr, stack, context)\n\n    # This logic mirrors the code in `Apply.compare`\n    cond do\n      # If it is a singleton, we can always be precise\n      singleton?(type) -> if polarity, do: type, else: negation(type)\n      # We are checking for `not x == 1` or similar, we can't say anything about x\n      polarity == false -> term()\n      # We are checking for `x == 1`, make sure x is integer or float\n      name in [:==, :\"/=\"] -> numberize(type)\n      # Otherwise we have the literal type as is\n      true -> type\n    end\n  end\n\n  defp of_pattern_tree({:tuple, entries}, stack, context) do\n    tuple(Enum.map(entries, &of_pattern_tree(&1, stack, context)))\n  end\n\n  defp of_pattern_tree({:open_map, static, dynamic}, stack, context) do\n    dynamic =\n      Enum.map(dynamic, fn {key, value} -> {key, of_pattern_tree(value, stack, context)} end)\n\n    open_map(static ++ dynamic)\n  end\n\n  defp of_pattern_tree({:closed_map, static, dynamic}, stack, context) do\n    dynamic =\n      Enum.map(dynamic, fn {key, value} -> {key, of_pattern_tree(value, stack, context)} end)\n\n    closed_map(static ++ dynamic)\n  end\n\n  defp of_pattern_tree({:non_empty_list, [head | tail], suffix}, stack, context) do\n    tail\n    |> Enum.reduce(\n      of_pattern_tree(head, stack, context),\n      &union(of_pattern_tree(&1, stack, context), &2)\n    )\n    |> non_empty_list(of_pattern_tree(suffix, stack, context))\n  end\n\n  defp of_pattern_tree({:intersection, entries}, stack, context) do\n    entries\n    |> Enum.map(&of_pattern_tree(&1, stack, context))\n    |> Enum.reduce(&intersection/2)\n  end\n\n  defp of_pattern_tree({:var, version}, _stack, context) do\n    case context do\n      %{vars: %{^version => %{type: type}}} -> type\n      _ -> term()\n    end\n  end\n\n  defp of_pattern_tree(:key, _stack, _context) do\n    term()\n  end\n\n  @doc \"\"\"\n  Function used to assign a type to a variable. Used by %struct{}\n  and binary patterns.\n\n  Given those values are actually checked at compile-time,\n  except for the variables, that's the only scenario we need to handle.\n  \"\"\"\n  def of_match_var({:_, _, _}, expected, _expr, _stack, context) do\n    {expected, context}\n  end\n\n  def of_match_var(var, expected, expr, stack, context) when is_var(var) do\n    context = Of.declare_var(var, context)\n\n    case Of.refine_head_var(var, expected, expr, stack, context) do\n      {:ok, type, context} ->\n        {type, context}\n\n      {:error, old_type, error_context} ->\n        {error_type(), badvar_error(var, old_type, expected, stack, error_context)}\n    end\n  end\n\n  def of_match_var({:<<>>, _meta, args}, _expected, _expr, stack, context) do\n    Of.bitstring(args, :match, stack, context)\n  end\n\n  def of_match_var({:^, _meta, [{_, meta, _}]}, expected, expr, stack, context) do\n    version = Keyword.fetch!(meta, :version)\n    Of.refine_body_var(version, expected, expr, stack, context)\n  end\n\n  def of_match_var(atom, _expected, _expr, _stack, context) when is_atom(atom) do\n    {atom(), context}\n  end\n\n  def of_match_var(binary, _expected, _expr, _stack, context) when is_binary(binary) do\n    {binary(), context}\n  end\n\n  def of_match_var(integer, _expected, _expr, _stack, context) when is_integer(integer) do\n    {integer(), context}\n  end\n\n  def of_match_var(float, _expected, _expr, _stack, context) when is_float(float) do\n    {float(), context}\n  end\n\n  ## Patterns\n\n  # :atom\n  defp of_pattern(atom, _path, _stack, context) when is_atom(atom),\n    do: {atom([atom]), true, context}\n\n  # 12\n  defp of_pattern(literal, _path, _stack, context) when is_integer(literal),\n    do: {integer(), false, context}\n\n  # 1.2\n  defp of_pattern(literal, _path, _stack, context) when is_float(literal),\n    do: {float(), false, context}\n\n  # \"...\"\n  defp of_pattern(literal, _path, _stack, context) when is_binary(literal),\n    do: {binary(), false, context}\n\n  # []\n  defp of_pattern([], _path, _stack, context),\n    do: {empty_list(), true, context}\n\n  # [expr, ...]\n  defp of_pattern(list, path, stack, context) when is_list(list) do\n    {prefix, suffix} = unpack_list(list, [])\n    of_list(prefix, suffix, path, stack, context)\n  end\n\n  # {left, right}\n  defp of_pattern({left, right}, path, stack, context) do\n    of_tuple([left, right], path, stack, context)\n  end\n\n  # left = right\n  defp of_pattern({:=, _meta, [_, _]} = match, path, stack, context) do\n    {precise?, matches, version, var} =\n      match\n      |> unpack_match([])\n      |> Enum.split_while(&(not is_versioned_var(&1)))\n      |> case do\n        {matches, []} ->\n          {version, var} = match_var()\n          {true, matches, version, var}\n\n        {pre, [{_, meta, _} = var | post]} ->\n          version = Keyword.fetch!(meta, :version)\n          {not is_map_key(context.vars, version), pre ++ post, version, var}\n      end\n\n    # Pass the current path to build the current var\n    context = of_var(var, version, path, context)\n    root = %{root: {:var, version}, expr: match}\n\n    {precise?, static, dynamic, context} =\n      Enum.reduce(matches, {precise?, [], [{:var, version}], context}, fn\n        pattern, {precise?, static, dynamic, context} ->\n          {type, pattern_precise?, context} = of_pattern(pattern, [root], stack, context)\n          precise? = precise? and pattern_precise?\n\n          if is_descr(type) do\n            {precise?, [type | static], dynamic, context}\n          else\n            {precise?, static, [type | dynamic], context}\n          end\n      end)\n\n    return =\n      if static == [] do\n        {:intersection, dynamic}\n      else\n        {:intersection, [Enum.reduce(static, &intersection/2) | dynamic]}\n      end\n\n    context = of_var(var, version, [%{root: return, expr: match}], context)\n    {return, precise?, context}\n  end\n\n  # %Struct{...}\n  defp of_pattern({:%, meta, [struct, {:%{}, _, args}]}, path, stack, context)\n       when is_atom(struct) do\n    {info, context} = Of.struct_info(struct, :pattern, meta, stack, context)\n\n    if info do\n      {pairs, {precise?, context}} =\n        Enum.map_reduce(args, {true, context}, fn {key, value}, {precise?, context} ->\n          {value_type, value_precise?, context} =\n            of_pattern(value, [{:key, key} | path], stack, context)\n\n          context =\n            if Enum.any?(info, &(&1.field == key)) do\n              context\n            else\n              Of.unknown_struct_field(struct, key, :pattern, meta, stack, context)\n            end\n\n          # TODO: We need to assume that these are dynamic until we have typed structs.\n          {{key, value_type}, {precise? and value_precise?, context}}\n        end)\n\n      pairs = Map.new(pairs)\n      term = term()\n      static = [__struct__: atom([struct])]\n      dynamic = []\n\n      {static, dynamic} =\n        Enum.reduce(info, {static, dynamic}, fn %{field: field}, {static, dynamic} ->\n          case pairs do\n            %{^field => value_type} when is_descr(value_type) ->\n              {[{field, value_type} | static], dynamic}\n\n            %{^field => value_type} ->\n              {static, [{field, value_type} | dynamic]}\n\n            _ ->\n              {[{field, term} | static], dynamic}\n          end\n        end)\n\n      if dynamic == [] do\n        {closed_map(static), precise?, context}\n      else\n        {{:closed_map, static, dynamic}, precise?, context}\n      end\n    else\n      context =\n        Enum.reduce(args, context, fn {key, value}, context ->\n          {_, _, context} = of_pattern(value, [{:key, key} | path], stack, context)\n          context\n        end)\n\n      {error_type(), false, context}\n    end\n  end\n\n  # %var{...}\n  defp of_pattern({:%, _, [{name, _, ctx} = var, {:%{}, _, args}]}, path, stack, context)\n       when is_atom(name) and is_atom(ctx) and name != :_ do\n    {var, precise?, context} = of_pattern(var, [{:key, :__struct__} | path], stack, context)\n    dynamic = [__struct__: {:intersection, [atom(), var]}]\n    of_open_map(args, precise?, [], dynamic, path, stack, context)\n  end\n\n  # %^var{...} and %_{...}\n  defp of_pattern(\n         {:%, meta, [var, {:%{}, _meta2, args}]} = expr,\n         path,\n         stack,\n         context\n       ) do\n    {refined, context} = of_match_var(var, atom(), expr, stack, context)\n\n    if compatible?(refined, atom()) do\n      of_open_map(args, singleton?(refined), [__struct__: refined], [], path, stack, context)\n    else\n      error = {:badstruct, refined, expr, context}\n      {error_type(), false, error(__MODULE__, error, meta, stack, context)}\n    end\n  end\n\n  # %{...}\n  defp of_pattern({:%{}, _meta, args}, path, stack, context) do\n    of_open_map(args, true, [], [], path, stack, context)\n  end\n\n  # <<...>>>\n  defp of_pattern({:<<>>, _meta, args} = node, _path, stack, context) do\n    {type, context} = Of.bitstring(args, :match, stack, context)\n    {type, of_precise_bitstring?(node), context}\n  end\n\n  # left ++ right\n  defp of_pattern({{:., _meta1, [:erlang, :++]}, _meta2, [left, right]}, path, stack, context) do\n    of_list(left, right, path, stack, context)\n  end\n\n  # {...}\n  defp of_pattern({:{}, _meta, args}, path, stack, context) do\n    of_tuple(args, path, stack, context)\n  end\n\n  # ^var\n  defp of_pattern({:^, _meta, [{_, meta, _} = var]}, reverse_path, _stack, context) do\n    version = Keyword.fetch!(meta, :version)\n\n    case Enum.reverse(reverse_path) do\n      [%{root: :key} | _] -> {Of.var(var, context), false, context}\n      path -> {{:var, version}, false, of_shared_var(var, version, true, path, context)}\n    end\n  end\n\n  # _\n  defp of_pattern({:_, _meta, _var_context}, _path, _stack, context) do\n    {term(), true, context}\n  end\n\n  # var\n  defp of_pattern({name, meta, ctx} = var, path, _stack, context)\n       when is_atom(name) and is_atom(ctx) do\n    version = Keyword.fetch!(meta, :version)\n    {{:var, version}, not is_map_key(context.vars, version), of_var(var, version, path, context)}\n  end\n\n  defp is_versioned_var({name, _meta, ctx}) when is_atom(name) and is_atom(ctx) and name != :_,\n    do: true\n\n  defp is_versioned_var(_), do: false\n\n  defp of_var(var, version, reverse_path, context) do\n    of_shared_var(var, version, false, Enum.reverse(reverse_path), Of.declare_var(var, context))\n  end\n\n  defp of_shared_var(var, version, pinned, path, %{pattern_info: pattern_info} = context)\n       when is_list(pattern_info) do\n    [%{root: root, expr: expr} | path] = path\n    node = path_node(root, var, expr, path)\n    context = %{context | pattern_info: [{version, pinned, node} | pattern_info]}\n\n    case root do\n      {:arg, _} ->\n        context\n\n      {:var, other} ->\n        context = Of.track_var(version, [other], [node], context)\n        Of.track_var(other, [version], [], context)\n\n      _ ->\n        Of.track_var(version, [], [node], context)\n    end\n  end\n\n  @compile {:inline, path_node: 4}\n  defp path_node(root, var, expr, path) do\n    %{root: root, var: var, expr: expr, path: path}\n  end\n\n  defp of_open_map(args, precise?, static, dynamic, path, stack, context) do\n    {precise?, static, dynamic, context} =\n      Enum.reduce(args, {precise?, static, dynamic, context}, fn\n        {key, value}, {precise?, static, dynamic, context} when is_atom(key) ->\n          {value_type, value_precise?, context} =\n            of_pattern(value, [{:key, key} | path], stack, context)\n\n          precise? = precise? and value_precise?\n\n          if is_descr(value_type) do\n            {precise?, [{key, value_type} | static], dynamic, context}\n          else\n            {precise?, static, [{key, value_type} | dynamic], context}\n          end\n\n        {key, value}, {_precise?, static, dynamic, context} ->\n          {key_type, _, context} = of_pattern(key, [%{root: :key, expr: key}], stack, context)\n          true = is_descr(key_type)\n\n          {_value_type, _precise?, context} =\n            of_subpattern(value, [{:domain, key_type} | path], stack, context)\n\n          # A domain key cannot restrict the map in any way,\n          # because we are matching only on one possible value\n          # and we cannot assert anything about any of the others.\n          {false, static, dynamic, context}\n      end)\n\n    case dynamic do\n      [] -> {open_map(static), precise?, context}\n      _ -> {{:open_map, static, dynamic}, precise?, context}\n    end\n  end\n\n  defp of_tuple(args, path, stack, context) do\n    {_index, precise?, static?, entries, context} =\n      Enum.reduce(args, {0, true, true, [], context}, fn arg,\n                                                         {index, precise?, static?, acc, context} ->\n        {type, elem_precise?, context} = of_pattern(arg, [{:elem, index} | path], stack, context)\n        precise? = precise? and elem_precise?\n        static? = static? and is_descr(type)\n        {index + 1, precise?, static?, [type | acc], context}\n      end)\n\n    case static? do\n      true -> {tuple(Enum.reverse(entries)), precise?, context}\n      false -> {{:tuple, Enum.reverse(entries)}, precise?, context}\n    end\n  end\n\n  # [] ++ []\n  defp of_list([], [], _path, _stack, context) do\n    {empty_list(), true, context}\n  end\n\n  # [] ++ suffix\n  defp of_list([], suffix, path, stack, context) do\n    of_pattern(suffix, path, stack, context)\n  end\n\n  # [prefix | suffix]\n  defp of_list([prefix], suffix, path, stack, context) when is_var(prefix) and is_var(suffix) do\n    {suffix_type, suffix_precise?, context} =\n      of_pattern(suffix, [:tail | path], stack, context)\n\n    context = annotate_list_subpattern(suffix, context)\n\n    {prefix_type, prefix_precise?, context} =\n      of_subpattern(prefix, [:head | path], stack, context)\n\n    context = annotate_list_subpattern(prefix, context)\n\n    type =\n      if is_descr(prefix_type) and is_descr(suffix_type) do\n        non_empty_list(prefix_type, suffix_type)\n      else\n        {:non_empty_list, [prefix_type], suffix_type}\n      end\n\n    {type, prefix_precise? and suffix_precise?, context}\n  end\n\n  # [prefix1, prefix2, prefix3], [prefix1, prefix2 | suffix]\n  defp of_list(prefix, suffix, path, stack, context) do\n    {suffix_type, _precise?, context} = of_pattern(suffix, [:tail | path], stack, context)\n\n    {static, dynamic, context} =\n      Enum.reduce(prefix, {[], [], context}, fn arg, {static, dynamic, context} ->\n        {type, _precise?, context} = of_subpattern(arg, [:head | path], stack, context)\n\n        if is_descr(type) do\n          {[type | static], dynamic, context}\n        else\n          {static, [type | dynamic], context}\n        end\n      end)\n\n    type =\n      case {static, dynamic} do\n        {static, []} when is_descr(suffix_type) ->\n          non_empty_list(Enum.reduce(static, &union/2), suffix_type)\n\n        {[], dynamic} ->\n          {:non_empty_list, dynamic, suffix_type}\n\n        {static, dynamic} ->\n          {:non_empty_list, [Enum.reduce(static, &union/2) | dynamic], suffix_type}\n      end\n\n    {type, false, context}\n  end\n\n  defp list_subpattern?(version, context) do\n    is_map_key(context.subpatterns, {:list, version})\n  end\n\n  defp annotate_list_subpattern({name, meta, _}, context) do\n    if name != :_ do\n      put_in(context.subpatterns[{:list, Keyword.fetch!(meta, :version)}], true)\n    else\n      context\n    end\n  end\n\n  # These cases don't need to store information because they have no intersection\n  defp of_subpattern(arg, path, stack, context)\n       when is_number(arg) or is_binary(arg) or is_atom(arg) or arg == [] or is_var(arg) do\n    of_pattern(arg, path, stack, context)\n  end\n\n  defp of_subpattern(arg, path, stack, %{subpatterns: subpatterns} = context) do\n    key = map_size(subpatterns)\n    context = %{context | subpatterns: Map.put(subpatterns, key, nil)}\n    {type, precise?, context} = of_pattern(arg, [{:subpattern, key} | path], stack, context)\n    {type, precise?, put_in(context.subpatterns[key], of_pattern_tree(type, stack, context))}\n  end\n\n  defp of_precise_bitstring?({:<<>>, _meta, [{:\"::\", _, [expr, {type, _, _}]}]})\n       when type in [:binary, :bitstring, :bytes, :bits] do\n    is_var(expr) or of_precise_bitstring?(expr)\n  end\n\n  defp of_precise_bitstring?(_), do: false\n\n  ## Guards\n  #\n  # Whenever we have a or/orelse, we need to build multiple environments\n  # and we only preserve intersections of those environments. However,\n  # when building those environments, domain checks are always passed\n  # upstream, except when they are on the right-side of `orelse`.\n  #\n  # Therefore, in addition to `conditional_vars`, we have to track:\n  #\n  # 1. Should we process type checks? We always do so at the root of guards.\n  #    Inside or/orelse, we also need to check the environments.\n  #\n  # 2. Should we process domain checks? We always process it, except that, if\n  #    on the right-side of orelse, it is only kept if it is shared across\n  #    the environment vars.\n\n  @atom_true atom([true])\n  @atom_false atom([false])\n\n  defp of_guards([], _vars, _stack, context) do\n    {true, %{}, context}\n  end\n\n  defp of_guards(guards, vars, stack, context) do\n    context =\n      init_pattern_info(context, %{\n        guard_context: :andalso,\n        parent_version: nil,\n        vars: vars,\n        changed: %{},\n        subpatterns: %{}\n      })\n\n    {precise?, context} = of_guards(guards, stack, context)\n    {%{vars: vars, changed: changed}, context} = pop_pattern_info(context)\n    {is_map(vars) and precise?, changed, context}\n  end\n\n  defp of_guards([guard], stack, context) do\n    {type, context} = of_guard(guard, stack, context)\n    maybe_badguard(type, guard, stack, context)\n  end\n\n  defp of_guards(guards, stack, context) do\n    %{vars: vars, conditional_vars: conditional_vars} = context\n\n    {vars_conds, {precise?, context}} =\n      Enum.map_reduce(guards, {true, context}, fn guard, {precise?, context} ->\n        {type, context} = of_guard(guard, stack, %{context | vars: vars, conditional_vars: %{}})\n        {guard_precise?, context} = maybe_badguard(type, guard, stack, context)\n        %{vars: vars, conditional_vars: cond_vars} = context\n        {{vars, cond_vars}, {guard_precise? and precise?, context}}\n      end)\n\n    expr = Enum.reduce(guards, {:_, [], []}, &{:when, [], [&2, &1]})\n    context = %{context | vars: vars, conditional_vars: conditional_vars}\n\n    {precise? and Of.all_same_conditional_vars?(vars_conds),\n     Of.reduce_conditional_vars(vars_conds, expr, stack, context)}\n  end\n\n  defp update_parent_version(parent_version, %{pattern_info: pattern_info} = context) do\n    {pattern_info.parent_version,\n     %{context | pattern_info: %{pattern_info | parent_version: parent_version}}}\n  end\n\n  defp enable_conditional_mode(%{pattern_info: pattern_info} = context) do\n    %{context | pattern_info: %{pattern_info | guard_context: :orelse}, conditional_vars: %{}}\n  end\n\n  defp maybe_badguard(type, guard, stack, context) do\n    case booleaness(type) do\n      :maybe_both ->\n        {false, context}\n\n      {true, maybe_or_always} ->\n        {maybe_or_always == :always and context.pattern_info.subpatterns == %{}, context}\n\n      _false_tuple_or_none ->\n        error = {:badguard, type, guard, context}\n        {false, error(__MODULE__, error, error_meta(guard, stack), stack, context)}\n    end\n  end\n\n  defp of_guard(guard, stack, context) do\n    of_guard(guard, @atom_true, guard, stack, context)\n  end\n\n  # :atom\n  def of_guard(atom, _expected, _expr, _stack, context) when is_atom(atom) do\n    {atom([atom]), context}\n  end\n\n  # 12\n  def of_guard(literal, _expected, _expr, _stack, context) when is_integer(literal) do\n    {integer(), context}\n  end\n\n  # 1.2\n  def of_guard(literal, _expected, _expr, _stack, context) when is_float(literal) do\n    {float(), context}\n  end\n\n  # \"...\"\n  def of_guard(literal, _expected, _expr, _stack, context) when is_binary(literal) do\n    {binary(), context}\n  end\n\n  # []\n  def of_guard([], _expected, _expr, _stack, context) do\n    {empty_list(), context}\n  end\n\n  # [expr, ...]\n  def of_guard(list, _expected, expr, stack, context) when is_list(list) do\n    {prefix, suffix} = unpack_list(list, [])\n\n    {prefix, context} =\n      Enum.map_reduce(prefix, context, &of_guard(&1, term(), expr, stack, &2))\n\n    {suffix, context} = of_guard(suffix, term(), expr, stack, context)\n    {non_empty_list(Enum.reduce(prefix, &union/2), suffix), context}\n  end\n\n  # {left, right}\n  def of_guard({left, right}, expected, expr, stack, context) do\n    of_guard({:{}, [], [left, right]}, expected, expr, stack, context)\n  end\n\n  # %Struct{...}\n  def of_guard({:%, meta, [module, {:%{}, _, args}]} = struct, expected, _expr, stack, context)\n      when is_atom(module) do\n    fun = &of_guard(&1, &2, struct, &3, &4)\n    Of.struct_instance(module, args, expected, meta, stack, context, fun)\n  end\n\n  # %{...}\n  def of_guard({:%{}, _meta, args}, expected, expr, stack, context) do\n    Of.closed_map(args, expected, stack, context, &of_guard(&1, &2, expr, &3, &4))\n  end\n\n  # <<>>\n  def of_guard({:<<>>, _meta, args}, _expected, _expr, stack, context) do\n    Of.bitstring(args, :guard, stack, context)\n  end\n\n  # ^var\n  def of_guard({:^, _meta, [var]}, expected, expr, stack, context) do\n    # This is used by binary size, which behaves as a mixture of match and guard\n    of_guard(var, expected, expr, stack, context)\n  end\n\n  # {...}\n  def of_guard({:{}, _meta, args}, _expected, expr, stack, context) do\n    {types, context} = Enum.map_reduce(args, context, &of_guard(&1, term(), expr, stack, &2))\n    {tuple(types), context}\n  end\n\n  # var.field\n  def of_guard({{:., _, [callee, key]}, _, []} = map_fetch, expected, expr, stack, context)\n      when not is_atom(callee) do\n    {type, context} = of_guard(callee, open_map([{key, expected}]), expr, stack, context)\n    Of.map_fetch(map_fetch, type, key, stack, context)\n  end\n\n  # Remote\n  def of_guard({{:., _, [:erlang, fun]}, _meta, args} = call, expected, _, stack, context)\n      when is_atom(fun) do\n    of_remote(fun, args, call, expected, stack, context)\n  end\n\n  # The only possible case right now is the rewritten :lists.member/2 checks\n  def of_guard({{:., _, [mod, fun]}, _meta, args} = call, expected, _, stack, context)\n      when is_atom(mod) and is_atom(fun) do\n    Apply.remote(mod, fun, args, expected, call, stack, context, &of_guard/5)\n  end\n\n  # var\n  def of_guard({_, meta, _} = var, expected, expr, stack, context) when is_var(var) do\n    version = Keyword.fetch!(meta, :version)\n\n    # of_guard is also invoked inside patterns in case of bitstrings,\n    # and also when vars change, so we need to deal with all possibilities\n    # for pattern_info.\n    case context.pattern_info do\n      %{vars: vars, parent_version: parent_version, changed: changed} = pattern_info ->\n        vars =\n          is_map(vars) and not is_map_key(vars, version) and\n            not list_subpattern?(version, context) and vars\n\n        changed = Map.put(changed, version, [])\n        pattern_info = %{pattern_info | vars: vars, changed: changed}\n        context = %{context | pattern_info: pattern_info}\n\n        context =\n          if parent_version != nil,\n            do: Of.track_var(version, [parent_version], [], context),\n            else: context\n\n        Of.refine_body_var(version, expected, expr, stack, context)\n\n      list when is_list(list) ->\n        node = path_node(expected, var, expr, [])\n        {Of.var(var, context), %{context | pattern_info: [{version, false, node} | list]}}\n\n      nil ->\n        {Of.var(var, context), context}\n    end\n  end\n\n  defp of_compare(fun, polarity, {_, meta, _} = var, other_side, call, stack, context)\n       when is_var(var) do\n    version = Keyword.fetch!(meta, :version)\n\n    # Add a new path node to the current variable\n    node = path_node({:guard, fun, polarity, other_side, call}, var, call, [])\n    context = Of.track_var(version, [], [node], context)\n\n    # Make any variable on the other side propagate the change to this one\n    {parent_version, context} = update_parent_version(version, context)\n    {guard_type, context} = of_guard(other_side, term(), call, stack, context)\n\n    # Revert and return parent version\n    {^version, context} = update_parent_version(parent_version, context)\n    {guard_type, context}\n  end\n\n  defp of_compare(_fun, _polarity, _var, other_side, call, stack, context) do\n    of_guard(other_side, term(), call, stack, context)\n  end\n\n  @comp_op [:==, :\"/=\", :\"=:=\", :\"=/=\"]\n\n  defp of_remote(fun, [left, right] = args, call, expected, stack, context)\n       when fun in @comp_op do\n    with false <- Macro.quoted_literal?(left) or Macro.quoted_literal?(right),\n         true <- is_var(left) or is_var(right),\n         {boolean, _maybe_or_always} <- booleaness(expected),\n         %{pattern_info: %{}} <- context do\n      polarity =\n        case boolean do\n          true -> fun in [:==, :\"=:=\"]\n          false -> fun in [:\"/=\", :\"=/=\"]\n        end\n\n      {left_type, context} = of_compare(fun, polarity, right, left, call, stack, context)\n      {right_type, context} = of_compare(fun, polarity, left, right, call, stack, context)\n      Apply.return_compare(fun, left_type, right_type, boolean(), false, call, stack, context)\n    else\n      _ -> Apply.remote(:erlang, fun, args, expected, call, stack, context, &of_guard/5)\n    end\n  end\n\n  @dynamic_fail dynamic(atom([:fail]))\n\n  # `x or :fail` is a pattern used in Elixir to make guards fail.\n  # For example, `not is_struct(x, Foo)` checks if `Foo` is an atom\n  # or fails, but in the negation case `:fail` becomes a possible\n  # return type leading to a violation, we don't want. So we mark\n  # `:fail` as dynamic as its whole purpose is to cause failures.\n  defp of_remote(:orelse, [left, :fail], _call, expected, stack, context) do\n    {type, context} = of_guard(left, expected, left, stack, context)\n    {union(type, @dynamic_fail), context}\n  end\n\n  defp of_remote(fun, _args, call, expected, stack, context)\n       when fun in [:and, :or, :andalso, :orelse] do\n    {both_domain, abort_domain, always_rhs?} =\n      case fun do\n        :andalso -> {@atom_true, @atom_false, false}\n        :orelse -> {@atom_false, @atom_true, false}\n        :and -> {@atom_true, @atom_false, true}\n        :or -> {@atom_false, @atom_true, true}\n      end\n\n    # If we have multiple operations in a row,\n    # we unpack them into a single pass, to avoid\n    # building nested conditional environments.\n    [left | right] =\n      case unpack_op(call, fun, []) do\n        entries when fun == :orelse -> reconstruct_lists_member(entries)\n        entries -> entries\n      end\n\n    # For example, if the expected type is true for andalso, then it can\n    # only be true if both clauses are executed, so we know the first\n    # argument has to be true and the second has to be expected.\n    cond do\n      subtype?(expected, both_domain) ->\n        of_logical_all([left | right], true, both_domain, abort_domain, stack, context)\n\n      right == [] ->\n        of_guard(left, expected, left, stack, context)\n\n      true ->\n        cond_context = enable_conditional_mode(context)\n\n        # Compute the sure types, which are stored directly in the context\n        {_type, context} = of_guard(left, boolean(), left, stack, context)\n\n        # andalso/orelse may not execute the rhs, so we cannot get sure types from it\n        context =\n          case always_rhs? do\n            true ->\n              Enum.reduce(right, context, fn expr, context ->\n                {_, context} = of_guard(expr, boolean(), expr, stack, context)\n                context\n              end)\n\n            false ->\n              context\n          end\n\n        {type, vars_conds} =\n          of_logical_cond([left | right], none(), [], expected, stack, cond_context)\n\n        # We will be precise if all branches changed the same variable\n        context =\n          update_in(context.pattern_info.vars, fn\n            false -> false\n            vars -> Of.all_same_conditional_vars?(vars_conds) and vars\n          end)\n\n        {type, Of.reduce_conditional_vars(vars_conds, call, stack, context)}\n    end\n  end\n\n  # We cannot track precision for lists, so we assign match variables\n  # to hd/tl and refine them accordingly.\n  defp of_remote(\n         fun,\n         [arg],\n         call,\n         expected,\n         stack,\n         %{pattern_info: %{subpatterns: subpatterns}} = context\n       )\n       when fun in [:hd, :tl] do\n    arg_key =\n      Macro.prewalk(arg, fn\n        {left, meta, right} -> {left, Keyword.take(meta, [:version]), right}\n        node -> node\n      end)\n\n    subpattern_key = {fun, arg_key}\n\n    {var, context} =\n      case subpatterns do\n        %{^subpattern_key => var} ->\n          {var, context}\n\n        %{} ->\n          {type, context} =\n            Apply.remote(:erlang, fun, [arg], expected, call, stack, context, &of_guard/5)\n\n          {_, var} = match_var()\n          context = Of.declare_var(var, type, context)\n          {var, put_in(context.pattern_info.subpatterns[subpattern_key], var)}\n      end\n\n    of_guard(var, expected, call, stack, context)\n  end\n\n  defp of_remote(fun, args, call, expected, stack, context) do\n    Apply.remote(:erlang, fun, args, expected, call, stack, context, &of_guard/5)\n  end\n\n  defp unpack_op({{:., _, [:erlang, fun]}, _, [left, right]}, fun, acc) do\n    unpack_op(left, fun, unpack_op(right, fun, acc))\n  end\n\n  defp unpack_op(other, _fun, acc) do\n    [other | acc]\n  end\n\n  # Reconstruct left in right operations but only when the right-side is a literal.\n  # When the right-side is not a literal, we need to track dependencies between\n  # left and right-side, which is currently not done for the `:lists.member/2` handling.\n  defp reconstruct_lists_member([head | tail]) do\n    with {{:., dot_meta, [:erlang, :\"=:=\"]}, meta, [left, right]} <- head,\n         true <- Macro.quoted_literal?(right),\n         false <- data_size_op?(left),\n         {[_ | _] = entries, tail} <- reconstruct_lists_member(tail, left, []) do\n      in_args = [left, [right | entries]]\n      [{{:., dot_meta, [:lists, :member]}, meta, in_args} | reconstruct_lists_member(tail)]\n    else\n      _ -> [head | reconstruct_lists_member(tail)]\n    end\n  end\n\n  defp reconstruct_lists_member([]), do: []\n\n  defp reconstruct_lists_member(list, left, acc) do\n    with [{{:., _, [:erlang, :\"=:=\"]}, _, [^left, right]} | tail] <- list,\n         true <- Macro.quoted_literal?(right) do\n      reconstruct_lists_member(tail, left, [right | acc])\n    else\n      _ -> {Enum.reverse(acc), list}\n    end\n  end\n\n  defp data_size_op?({{:., _, [:erlang, op]}, _, [_]})\n       when op in [:length, :tuple_size, :map_size],\n       do: true\n\n  defp data_size_op?(_),\n    do: false\n\n  defp of_logical_all([head], disjoint?, expected, to_abort, stack, context) do\n    {type, context} = of_guard(head, expected, head, stack, context)\n\n    case disjoint? do\n      true -> {type, context}\n      false -> {union(to_abort, type), context}\n    end\n  end\n\n  defp of_logical_all([head | tail], disjoint?, expected, to_abort, stack, context) do\n    {type, context} = of_guard(head, expected, head, stack, context)\n    disjoint? = disjoint? and disjoint?(type, to_abort)\n    of_logical_all(tail, disjoint?, expected, to_abort, stack, context)\n  end\n\n  defp of_logical_cond([head | tail], acc_type, acc_vars, expected, stack, context) do\n    {type, %{vars: vars, conditional_vars: cond_vars}} =\n      of_guard(head, expected, head, stack, context)\n\n    acc_vars = [{vars, cond_vars} | acc_vars]\n    of_logical_cond(tail, union(acc_type, type), acc_vars, expected, stack, context)\n  end\n\n  defp of_logical_cond([], acc_type, acc_vars, _expected, _stack, _context) do\n    {acc_type, acc_vars}\n  end\n\n  ## Helpers\n\n  def format_diagnostic({:badstruct, type, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          expected an atom as struct name:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          got type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badguard, type, expr, context}) do\n    traces = collect_traces(expr, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          this guard will never succeed:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          because it returns type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic({:badvar, old_type, new_type, var, context}) do\n    traces = collect_traces(var, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          incompatible types assigned to #{format_var(var)}:\n\n              #{to_quoted_string(old_type)} !~ #{to_quoted_string(new_type)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  def format_diagnostic(\n        {:redundant, {{:def, kind, fun, _}, args, guards}, _expected, types, previous, _context}\n      ) do\n    call = Enum.reduce(guards, {fun, [], args}, &{:when, [], [&2, &1]})\n\n    %{\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          the following clause is redundant:\n\n              #{expr_to_string({kind, [], [call]}) |> indent(4)}\n\n          it has type:\n\n              #{args_to_quoted_string(types) |> indent(4)}\n\n          previous clauses have already matched on the following types:\n\n              #{previous_to_string(previous)}\n          \"\"\"\n        ])\n    }\n  end\n\n  def format_diagnostic({:redundant, {info, args}, expected, _types, previous, context}) do\n    traces = collect_traces(args, context)\n\n    message =\n      with {_op, meta, expr, type} <- info,\n           true <- previous_subtype?(expected, previous) do\n        if match?({:case, :||}, meta[:type_check]) do\n          \"\"\"\n          the right-hand side of || will always execute:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          because the left-hand side always evaluates to:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\"\n        else\n          \"\"\"\n          the following clause cannot match because the previous clauses already matched all possible values:\n\n              #{args_to_string(args) |> indent(4)} ->\n\n          it attempts to match on the result of:\n\n              #{expr_to_string(expr) |> indent(4)}\n\n          which has the already matched type:\n\n              #{to_quoted_string(type) |> indent(4)}\n          \"\"\"\n        end\n      else\n        _ ->\n          \"\"\"\n          the following clause is redundant:\n\n              #{args_to_string(args) |> indent(4)} ->\n\n          previous clauses have already matched on the following types:\n\n              #{previous_to_string(previous)}\n          \"\"\"\n      end\n\n    %{\n      details: %{typing_traces: traces},\n      message: IO.iodata_to_binary([message, format_traces(traces)])\n    }\n  end\n\n  def format_diagnostic({:badmatch, _meta, pattern, context}) do\n    traces = collect_traces(pattern, context)\n\n    %{\n      details: %{typing_traces: traces},\n      message:\n        IO.iodata_to_binary([\n          \"\"\"\n          the following pattern will never match:\n\n              #{expr_to_string(pattern) |> indent(4)}\n          \"\"\",\n          format_traces(traces)\n        ])\n    }\n  end\n\n  # $ type tag = head_pattern() or match_pattern()\n  #\n  # $ typep head_pattern =\n  #     {{:def, kind, fun, types}, args, guards} or\n  #     {{:case | :try_else, meta, expr, type}, [arg]} or\n  #     {:for_reduce | :receive | :try_catch | :with_else | :fn, [arg]}\n  #\n  # $ typep match_pattern =\n  #     {:with or :for or :match, pattern, type}\n  def format_diagnostic({:badpattern, meta, index, tag, context}) do\n    {to_trace, message} = badpattern(tag, index)\n    traces = collect_traces(to_trace, context)\n\n    hints =\n      case Keyword.get(meta, :type_check) do\n        {:impl, _} = impl -> [impl]\n        _ -> []\n      end\n\n    %{\n      details: %{typing_traces: traces},\n      message: IO.iodata_to_binary([message, format_traces(traces), format_hints(hints)])\n    }\n  end\n\n  defp badpattern({{:def, _kind, _fun, types}, args, _guards}, index) when is_integer(index) do\n    arg = Enum.fetch!(args, index)\n    type = Enum.fetch!(types, index)\n\n    if type == dynamic() do\n      {arg,\n       \"\"\"\n       the #{integer_to_ordinal(index + 1)} pattern in clause will never match:\n\n           #{expr_to_string(arg) |> indent(4)}\n       \"\"\"}\n    else\n      # This can only happen in protocol implementations for now\n      {arg,\n       \"\"\"\n       the #{integer_to_ordinal(index + 1)} pattern in clause will never match:\n\n           #{expr_to_string(arg) |> indent(4)}\n\n       because it is expected to receive type:\n\n           #{to_quoted_string(type) |> indent(4)}\n       \"\"\"}\n    end\n  end\n\n  defp badpattern({{op, meta, expr, type}, args}, _index) when op in [:case, :try_else] do\n    with {:case, op} <- meta[:type_check] do\n      message =\n        cond do\n          op == :|| ->\n            additional =\n              with {:case, meta, [_, _]} <- expr,\n                   {:case, :||} <- meta[:type_check] do\n                \"(shown as ... below) \"\n              else\n                _ -> \"\"\n              end\n\n            \"\"\"\n            the right-hand side of || #{additional}will never be executed:\n\n                #{expr_to_string({:||, [], [expr, {:..., [], []}]}) |> indent(4)}\n\n            because the left-hand side always evaluates to:\n\n                #{to_quoted_string(type) |> indent(4)}\n            \"\"\"\n\n          op in [:and, :or] ->\n            {first_message, second_message} =\n              case booleaness(type) do\n                {true, _} -> {\" will always succeed\", \"because it evaluates to\"}\n                {false, _} -> {\" will never succeed\", \"because it evaluates to\"}\n                :none -> {\" will always fail\", \"because it evaluates to\"}\n                _ -> {\"\", \"will always evaluate to\"}\n              end\n\n            \"\"\"\n            the following conditional expression#{first_message}:\n\n                #{expr_to_string(expr) |> indent(4)}\n\n            #{second_message}:\n\n                #{to_quoted_string(type) |> indent(4)}\n            \"\"\"\n\n          true ->\n            \"\"\"\n            the following conditional expression:\n\n                #{expr_to_string(expr) |> indent(4)}\n\n            will always evaluate to:\n\n                #{to_quoted_string(type) |> indent(4)}\n            \"\"\"\n        end\n\n      {expr, message}\n    else\n      _ ->\n        {args,\n         \"\"\"\n         the following clause will never match:\n\n             #{args_to_string(args) |> indent(4)} ->\n\n         because it attempts to match on the result of:\n\n             #{expr_to_string(expr) |> indent(4)}\n\n         which has type:\n\n             #{to_quoted_string(type) |> indent(4)}\n         \"\"\"}\n    end\n  end\n\n  defp badpattern({op, args}, index)\n       when op in [:for_reduce, :receive, :try_catch, :with_else, :fn] do\n    arg = Enum.fetch!(args, index)\n\n    {arg,\n     \"\"\"\n     the following pattern will never match:\n\n         #{expr_to_string(arg) |> indent(4)}\n     \"\"\"}\n  end\n\n  defp badpattern({op, pattern, type}, _index) when op in [:match, :for, :with] do\n    message =\n      if type == dynamic() do\n        \"\"\"\n        the following pattern will never match:\n\n            #{expr_to_string(pattern) |> indent(4)}\n        \"\"\"\n      else\n        \"\"\"\n        the following pattern will never match:\n\n            #{expr_to_string(pattern) |> indent(4)}\n\n        because the right-hand side has type:\n\n            #{to_quoted_string(type) |> indent(4)}\n        \"\"\"\n      end\n\n    {pattern, message}\n  end\n\n  defp args_to_string(args) do\n    args\n    |> Enum.map_join(\", \", &expr_to_string/1)\n    |> indent(4)\n  end\n\n  defp args_to_quoted_string(args) do\n    args\n    |> Enum.map_join(\", \", &to_quoted_string/1)\n    |> indent(4)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/types/traverse.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Module.Types.Traverse do\n  @moduledoc false\n\n  # Traverses expressions to find local calls when inference is disabled.\n\n  # Literals\n  def of_expr(literal, _stack, context)\n      when is_atom(literal) or is_integer(literal) or is_float(literal) or is_binary(literal) or\n             is_pid(literal) or literal == [] do\n    context\n  end\n\n  # [expr, ...]\n  def of_expr(list, stack, context) when is_list(list) do\n    Enum.reduce(list, context, &of_expr(&1, stack, &2))\n  end\n\n  # {left, right}\n  def of_expr({left, right}, stack, context) do\n    context = of_expr(left, stack, context)\n    of_expr(right, stack, context)\n  end\n\n  # <<...>>\n  def of_expr({:<<>>, _meta, args}, stack, context) do\n    Enum.reduce(args, context, fn\n      {:\"::\", _meta, [left, _right]}, context ->\n        of_expr(left, stack, context)\n\n      expr, context ->\n        of_expr(expr, stack, context)\n    end)\n  end\n\n  def of_expr({:%, meta, [module, {:%{}, _, [{:|, _, [map, pairs]}]}]}, stack, context) do\n    context = of_expr(map, stack, context)\n    context = of_expr(pairs, stack, context)\n    of_struct(module, pairs, :expr, meta, stack, context)\n  end\n\n  def of_expr({:%, meta, [module, {:%{}, _, pairs}]}, stack, context) do\n    context = of_expr(pairs, stack, context)\n    of_struct(module, pairs, :expr, meta, stack, context)\n  end\n\n  # Map update, tail operator\n  def of_expr({:|, _meta, [left, right]}, stack, context) do\n    context = of_expr(left, stack, context)\n    of_expr(right, stack, context)\n  end\n\n  # Tuples, maps\n  def of_expr({container, _meta, exprs}, stack, context) when container in [:{}, :%{}] do\n    Enum.reduce(exprs, context, &of_expr(&1, stack, &2))\n  end\n\n  # left = right, left <- right\n  def of_expr({op, _meta, [left, right]}, stack, context) when op in [:=, :<-] do\n    context = of_pattern(left, stack, context)\n    of_expr(right, stack, context)\n  end\n\n  # Blocks\n  def of_expr({:__block__, _, args}, stack, context) do\n    Enum.reduce(args, context, &of_expr(&1, stack, &2))\n  end\n\n  # cond do ... end\n  def of_expr({:cond, _meta, [[{:do, clauses}]]}, stack, context) do\n    Enum.reduce(clauses, context, fn {:->, _meta, [[head], body]}, context ->\n      context = of_expr(head, stack, context)\n      of_expr(body, stack, context)\n    end)\n  end\n\n  # All non-handled -> are patterns\n  def of_expr({:->, _, [head, body]}, stack, context) do\n    context = of_pattern(head, stack, context)\n    of_expr(body, stack, context)\n  end\n\n  # case expr do ... end\n  def of_expr({:case, _meta, [case_expr, [{:do, clauses}]]}, stack, context) do\n    context = of_expr(case_expr, stack, context)\n    of_expr(clauses, stack, context)\n  end\n\n  # fn pat -> expr end\n  def of_expr({:fn, _meta, clauses}, stack, context) do\n    of_expr(clauses, stack, context)\n  end\n\n  # try do ... end\n  def of_expr({:try, _meta, [blocks]}, stack, context) do\n    Enum.reduce(blocks, context, fn {_, clauses_or_body}, context ->\n      of_expr(clauses_or_body, stack, context)\n    end)\n  end\n\n  # receive do ... end\n  def of_expr({:receive, _meta, [blocks]}, stack, context) do\n    Enum.reduce(blocks, context, fn\n      {:do, clauses_or_empty_body}, context ->\n        of_expr(clauses_or_empty_body, stack, context)\n\n      {:after, [{:->, _meta, [[timeout], body]}]}, context ->\n        context = of_expr(timeout, stack, context)\n        of_expr(body, stack, context)\n    end)\n  end\n\n  # for, with\n  def of_expr({op, _meta, [_ | _] = args}, stack, context) when op in [:for, :with] do\n    Enum.reduce(args, context, &of_expr(&1, stack, &2))\n  end\n\n  # fun.(args)\n  def of_expr({{:., _meta, [fun]}, _call_meta, args}, stack, context) do\n    context = of_expr(fun, stack, context)\n    Enum.reduce(args, context, &of_expr(&1, stack, &2))\n  end\n\n  # remote.fun(args)\n  def of_expr({{:., _, [remote, name]}, _meta, args}, stack, context)\n      when is_atom(name) do\n    context = of_expr(remote, stack, context)\n    Enum.reduce(args, context, &of_expr(&1, stack, &2))\n  end\n\n  # &Mod.fun/arity\n  def of_expr({:&, _, [{:/, _, [{{:., _, [_remote, name]}, _, []}, arity]}]}, _stack, context)\n      when is_atom(name) and is_integer(arity) do\n    context\n  end\n\n  # &fun/arity\n  def of_expr({:&, meta, [{:/, _, [{name, _, _ctx}, arity]}]}, stack, context)\n      when is_atom(name) and is_integer(arity) do\n    local_fun(meta, name, arity, stack, context)\n  end\n\n  # super(args)\n  def of_expr({:super, meta, args}, stack, context) when is_list(args) do\n    {_kind, name} = Keyword.fetch!(meta, :super)\n    context = local_fun(meta, name, length(args), stack, context)\n    Enum.reduce(args, context, &of_expr(&1, stack, &2))\n  end\n\n  # local_fun(args)\n  def of_expr({name, meta, args}, stack, context)\n      when is_atom(name) and is_list(args) do\n    context = local_fun(meta, name, length(args), stack, context)\n    Enum.reduce(args, context, &of_expr(&1, stack, &2))\n  end\n\n  # var\n  def of_expr({name, _meta, ctx}, _stack, context)\n      when is_atom(name) and is_atom(ctx) do\n    context\n  end\n\n  defp of_pattern({:%, meta, [module, {:%{}, _, pairs}]}, stack, context) when is_atom(module) do\n    context = of_pattern(pairs, stack, context)\n    of_struct(module, pairs, :expr, meta, stack, context)\n  end\n\n  defp of_pattern({left, _meta, right}, stack, context) do\n    context = of_pattern(left, stack, context)\n    of_pattern(right, stack, context)\n  end\n\n  defp of_pattern({left, right}, stack, context) do\n    context = of_pattern(left, stack, context)\n    of_pattern(right, stack, context)\n  end\n\n  defp of_pattern([_ | _] = list, stack, context) do\n    Enum.reduce(list, context, &of_pattern(&1, stack, &2))\n  end\n\n  defp of_pattern(_, _stack, context) do\n    context\n  end\n\n  defp of_struct(module, pairs, kind, meta, stack, context) do\n    {info, context} = Module.Types.Of.struct_info(module, kind, meta, stack, context)\n\n    if info do\n      Enum.reduce(pairs, context, fn {key, _value}, context ->\n        if Enum.any?(info, &(&1.field == key)) do\n          context\n        else\n          Module.Types.Of.unknown_struct_field(module, key, kind, meta, stack, context)\n        end\n      end)\n    else\n      context\n    end\n  end\n\n  defp local_fun(meta, fun, arity, stack, context) do\n    case stack.local_handler.(meta, {fun, arity}, stack, context) do\n      false -> context\n      {_kind, _info, context} -> context\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/module/types.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Module.Types do\n  @moduledoc false\n  alias Module.Types.{Descr, Expr, Pattern, Helpers}\n\n  # The mode controls what happens on function application when\n  # there are gradual arguments. Non-gradual arguments always\n  # perform subtyping and return its output (OUT).\n  #\n  #   * :strict - Requires types signatures (not implemented).\n  #     * Strong arrows with gradual performs subtyping and returns OUT\n  #     * Weak arrows with gradual performs subtyping and returns OUT\n  #\n  #   * :static - Type signatures have been given.\n  #     * Strong arrows with gradual performs compatibility and returns OUT\n  #     * Weak arrows with gradual performs compatibility and returns dynamic()\n  #\n  #   * :dynamic - Type signatures have not been given.\n  #     * Strong arrows with gradual performs compatibility and returns dynamic(OUT)\n  #     * Weak arrows with gradual performs compatibility and returns dynamic()\n  #\n  #   * :infer - Same as :dynamic but skips remote calls.\n  #\n  # The mode may also control exhaustiveness checks in the future (to be decided).\n  # We may also want for applications with subtyping in dynamic mode to always\n  # intersect with dynamic, but this mode may be too lax (to be decided based on\n  # feedback).\n  @modes [:static, :dynamic, :infer]\n\n  # These functions are not inferred because they are added/managed by the compiler\n  @no_infer [behaviour_info: 1]\n\n  @doc false\n  def infer(module, file, attrs, defs, used_private, env, {_, cache}) do\n    # We don't care about inferring signatures for protocols,\n    # those will be replaced anyway. There is also nothing to\n    # infer if there is no cache system, we only do traversals.\n    infer_signatures? =\n      :elixir_config.get(:infer_signatures) != false and cache != nil and not protocol?(attrs)\n\n    impl = impl_for(attrs)\n\n    finder =\n      fn fun_arity ->\n        case :lists.keyfind(fun_arity, 1, defs) do\n          {_, kind, _, _} = def ->\n            default_domain(infer_mode(kind, infer_signatures?), def, fun_arity, impl)\n\n          false ->\n            false\n        end\n      end\n\n    handler = fn meta, fun_arity, stack, context ->\n      case local_handler(meta, fun_arity, stack, context, finder) do\n        false ->\n          undefined_function!(:undefined_function, meta, fun_arity, stack, env)\n          false\n\n        {kind, _, _} = triplet ->\n          if (kind == :defmacro or kind == :defmacrop) and not Keyword.has_key?(meta, :super) do\n            undefined_function!(:incorrect_dispatch, meta, fun_arity, stack, env)\n            false\n          else\n            triplet\n          end\n      end\n    end\n\n    stack = stack(:infer, file, module, {:__info__, 1}, env, cache, handler)\n\n    # In case there are loops, the other we traverse matters,\n    # so we sort the definitions for determinism\n    {types, private, %{local_sigs: reachable_sigs} = context} =\n      for {fun_arity, kind, meta, _clauses} = def <- Enum.sort(defs),\n          reduce: {[], [], context()} do\n        {types, private, context} when kind in [:def, :defmacro] ->\n          # Optimized version of finder, since we already have the definition\n          finder = fn _ ->\n            default_domain(infer_mode(kind, infer_signatures?), def, fun_arity, impl)\n          end\n\n          {_kind, inferred, context} = local_handler(meta, fun_arity, stack, context, finder)\n\n          if infer_signatures? and kind == :def and fun_arity not in @no_infer do\n            {[{fun_arity, inferred} | types], private, context}\n          else\n            {types, private, context}\n          end\n\n        {types, private, context} ->\n          {types, [def | private], context}\n      end\n\n    # Now traverse all used privates to find any other private that have been used by them.\n    context =\n      %{local_sigs: used_sigs} =\n      for fun_arity <- used_private, reduce: context do\n        context ->\n          {_kind, _inferred, context} = local_handler([], fun_arity, stack, context, finder)\n          context\n      end\n\n    {unreachable, _context} =\n      Enum.reduce(private, {[], context}, fn\n        {fun_arity, kind, meta, _clauses}, {unreachable, context} ->\n          warn_unused_def(fun_arity, kind, meta, used_sigs, env)\n\n          # Find anything undefined within unused functions\n          {_kind, _inferred, context} = local_handler([], fun_arity, stack, context, finder)\n\n          # defp is reachable if used, defmacrop only if directly invoked\n          private_sigs = if kind == :defp, do: used_sigs, else: reachable_sigs\n\n          if is_map_key(private_sigs, fun_arity) do\n            {unreachable, context}\n          else\n            {[fun_arity | unreachable], context}\n          end\n      end)\n\n    {Map.new(types), unreachable}\n  end\n\n  defp infer_mode(kind, infer_signatures?) do\n    if infer_signatures? and kind in [:def, :defp], do: :infer, else: :traverse\n  end\n\n  defp protocol?(attrs) do\n    List.keymember?(attrs, :__protocol__, 0)\n  end\n\n  defp impl_for(attrs) do\n    case List.keyfind(attrs, :__impl__, 0) do\n      {:__impl__, [protocol: protocol, for: for]} ->\n        if Code.ensure_loaded?(protocol) and function_exported?(protocol, :behaviour_info, 1) do\n          {for, protocol.behaviour_info(:callbacks)}\n        else\n          nil\n        end\n\n      _ ->\n        nil\n    end\n  end\n\n  defp default_domain(mode, def, {_, arity} = fun_arity, impl) do\n    with {for, callbacks} <- impl,\n         true <- fun_arity in callbacks do\n      args = [\n        Descr.dynamic(Module.Types.Of.impl(for))\n        | List.duplicate(Descr.dynamic(), arity - 1)\n      ]\n\n      {_fun_arity, kind, meta, clauses} = def\n\n      clauses =\n        for {meta, args, guards, body} <- clauses do\n          {[type_check: {:impl, for}] ++ meta, args, guards, body}\n        end\n\n      {mode, {fun_arity, kind, meta, clauses}, args}\n    else\n      _ -> {mode, def, List.duplicate(Descr.dynamic(), arity)}\n    end\n  end\n\n  defp undefined_function!(reason, meta, {fun, arity}, stack, env) do\n    env = %{env | function: stack.function, file: stack.file}\n    tuple = {reason, {fun, arity}, stack.module}\n    :elixir_errors.module_error(Helpers.with_span(meta, fun), env, __MODULE__, tuple)\n  end\n\n  defp warn_unused_def(fun_arity, kind, meta, used, env) do\n    default = Keyword.get(meta, :defaults, 0)\n\n    cond do\n      Keyword.get(meta, :context) != nil or Keyword.get(meta, :from_super) == true ->\n        :ok\n\n      default == 0 ->\n        case is_map_key(used, fun_arity) do\n          true -> :ok\n          false -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_def, fun_arity, kind})\n        end\n\n      default > 0 ->\n        {name, arity} = fun_arity\n        min = arity - default\n        max = arity\n\n        case min_reachable_default(max, min, :none, name, used) do\n          :none -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_def, fun_arity, kind})\n          ^min -> :ok\n          ^max -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_args, fun_arity})\n          diff -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_args, fun_arity, diff})\n        end\n    end\n\n    :ok\n  end\n\n  defp min_reachable_default(max, min, last, name, used) when max >= min do\n    fun_arity = {name, max}\n\n    case is_map_key(used, fun_arity) do\n      true -> min_reachable_default(max - 1, min, max, name, used)\n      false -> min_reachable_default(max - 1, min, last, name, used)\n    end\n  end\n\n  defp min_reachable_default(_max, _min, last, _name, _used) do\n    last\n  end\n\n  @doc false\n  def warnings(module, file, attrs, defs, no_warn_undefined, cache) do\n    impl = impl_for(attrs)\n\n    finder = fn fun_arity ->\n      case :lists.keyfind(fun_arity, 1, defs) do\n        {_, _, _, _} = def -> default_domain(:dynamic, def, fun_arity, impl)\n        false -> false\n      end\n    end\n\n    handler = &local_handler(&1, &2, &3, &4, finder)\n    stack = stack(:dynamic, file, module, {:__info__, 1}, no_warn_undefined, cache, handler)\n\n    context =\n      Enum.reduce(defs, context(), fn {fun_arity, _kind, meta, _clauses} = def, context ->\n        # Optimized version of finder, since we already the definition\n        finder = fn _ -> default_domain(:dynamic, def, fun_arity, impl) end\n        {_kind, _inferred, context} = local_handler(meta, fun_arity, stack, context, finder)\n        context\n      end)\n\n    context = warn_unused_clauses(defs, stack, context)\n    context.warnings\n  end\n\n  defp warn_unused_clauses(defs, stack, context) do\n    for {fun_arity, pending} <- context.local_used,\n        pending != [],\n        {_fun_arity, kind, meta, clauses} = List.keyfind(defs, fun_arity, 0),\n        not Keyword.get(meta, :from_super, false),\n        reduce: context do\n      context ->\n        {_kind, info, mapping} = Map.fetch!(context.local_sigs, fun_arity)\n\n        clauses_indexes =\n          for type_index <- pending,\n              not skip_unused_clause?(info, type_index),\n              {clause_index, ^type_index} <- mapping,\n              do: clause_index\n\n        Enum.reduce(clauses_indexes, context, fn clause_index, context ->\n          {meta, _args, _guards, _body} = Enum.fetch!(clauses, clause_index)\n          stack = %{stack | function: fun_arity}\n          Helpers.warn(__MODULE__, {:unused_clause, kind, fun_arity}, meta, stack, context)\n        end)\n    end\n  end\n\n  defp skip_unused_clause?(info, type_index) do\n    case info do\n      # If an inferred clause returns an empty type, then the reverse arrow\n      # will never propagate its domain up, which may lead to the clause never\n      # being invoked.\n      {:infer, _, inferred} ->\n        {_args_types, return} = Enum.fetch!(inferred, type_index)\n        Descr.empty?(return)\n\n      _ ->\n        false\n    end\n  end\n\n  defp local_handler(_meta, fun_arity, stack, context, finder) do\n    case context.local_sigs do\n      %{^fun_arity => {kind, inferred, _mapping}} ->\n        {kind, inferred, context}\n\n      %{^fun_arity => kind} when is_atom(kind) ->\n        {kind, :none, context}\n\n      local_sigs ->\n        case finder.(fun_arity) do\n          {mode, {fun_arity, kind, meta, clauses}, expected} ->\n            context = put_in(context.local_sigs, Map.put(local_sigs, fun_arity, kind))\n\n            {inferred, mapping, context} =\n              local_handler(mode, fun_arity, kind, meta, clauses, expected, stack, context)\n\n            context =\n              update_in(context.local_sigs, &Map.put(&1, fun_arity, {kind, inferred, mapping}))\n\n            {kind, inferred, context}\n\n          false ->\n            false\n        end\n    end\n  end\n\n  defp local_handler(:traverse, {_, arity}, _kind, _meta, clauses, _expected, stack, context) do\n    context =\n      Enum.reduce(clauses, context, fn {_meta, _args, _guards, body}, context ->\n        Module.Types.Traverse.of_expr(body, stack, context)\n      end)\n\n    inferred = {:infer, nil, [{List.duplicate(Descr.term(), arity), Descr.dynamic()}]}\n    {inferred, [{0, 0}], context}\n  end\n\n  defp local_handler(mode, fun_arity, kind, meta, clauses, expected, stack, context) do\n    {fun, _arity} = fun_arity\n    stack = stack |> fresh_stack(mode, fun_arity) |> with_file_meta(meta)\n    base_info = {:def, kind, fun, expected}\n\n    {_, _, _, mapping, clauses_types, clauses_context} =\n      Enum.reduce(clauses, {0, 0, Pattern.init_previous(), [], [], context}, fn\n        {meta, args, guards, body}, {index, total, previous, mapping, inferred, acc_context} ->\n          fresh_context = fresh_context(acc_context)\n          info = {base_info, args, guards}\n\n          try do\n            {trees, previous, context} =\n              Pattern.of_head(args, guards, expected, previous, info, meta, stack, fresh_context)\n\n            {return_type, context} =\n              Expr.of_expr(body, Descr.term(), body, stack, context)\n\n            args_types = Pattern.of_domain(trees, stack, context)\n\n            {type_index, inferred} =\n              add_inferred(inferred, args_types, return_type, total - 1, [])\n\n            if type_index == -1 do\n              {index + 1, total + 1, previous, [{index, total} | mapping], inferred, context}\n            else\n              {index + 1, total, previous, [{index, type_index} | mapping], inferred, context}\n            end\n          rescue\n            e ->\n              internal_error!(e, __STACKTRACE__, kind, meta, fun, args, guards, body, stack)\n          end\n      end)\n\n    domain =\n      case clauses_types do\n        [_] ->\n          nil\n\n        _ ->\n          clauses_types\n          |> Enum.map(fn {args, _} -> args end)\n          |> Enum.zip_with(fn types -> Enum.reduce(types, &Descr.union/2) end)\n      end\n\n    inferred = {:infer, domain, Enum.reverse(clauses_types)}\n    {inferred, mapping, restore_context(clauses_context, context)}\n  end\n\n  # We check for term equality of types as an optimization\n  # to reduce the amount of check we do at runtime.\n  defp add_inferred([{args, existing_return} | tail], args, return, index, acc),\n    do: {index, Enum.reverse(acc, [{args, Descr.union(existing_return, return)} | tail])}\n\n  defp add_inferred([head | tail], args, return, index, acc),\n    do: add_inferred(tail, args, return, index - 1, [head | acc])\n\n  defp add_inferred([], args, return, -1, acc),\n    do: {-1, [{args, return} | Enum.reverse(acc)]}\n\n  defp with_file_meta(stack, meta) do\n    case Keyword.fetch(meta, :file) do\n      {:ok, {meta_file, _}} -> %{stack | file: meta_file}\n      :error -> stack\n    end\n  end\n\n  defp internal_error!(e, trace, kind, meta, fun, args, guards, body, stack) do\n    def_expr = {kind, meta, [guards_to_expr(guards, {fun, [], args}), [do: body]]}\n\n    exception =\n      RuntimeError.exception(\"\"\"\n      found error while checking types for #{Exception.format_mfa(stack.module, fun, length(args))}:\n\n      #{Exception.format_banner(:error, e, trace)}\\\n\n      The exception happened while checking this code:\n\n      #{Macro.to_string(def_expr)}\n\n      Please report this bug at: https://github.com/elixir-lang/elixir/issues\n      \"\"\")\n\n    reraise exception, trace\n  end\n\n  defp guards_to_expr([], left) do\n    left\n  end\n\n  defp guards_to_expr([guard | guards], left) do\n    guards_to_expr(guards, {:when, [], [left, guard]})\n  end\n\n  @doc false\n  def stack(mode, file, module, function, no_warn_undefined, cache, handler)\n      when mode in @modes do\n    %{\n      # The fallback meta used for literals in patterns and guards\n      meta: [],\n      # File of module\n      file: file,\n      # Module of definitions\n      module: module,\n      # Current function\n      function: function,\n      # Handling of undefined remote calls. May be one of:\n      #\n      # * List of calls to not warn on as undefined\n      #\n      # * The atom `:all` to not mark anything as undefined\n      #\n      # * A Macro.Env struct to not mark anything as undefined\n      #   also used to extract structs from\n      #\n      no_warn_undefined: no_warn_undefined,\n      # A tuple with cache information (may be nil)\n      cache: cache,\n      # The mode to be used, see the @modes attribute\n      mode: mode,\n      # The function for handling local calls\n      local_handler: handler\n    }\n  end\n\n  @doc false\n  def context() do\n    %{\n      # A list of all warnings found so far\n      warnings: [],\n      # All vars and their types\n      vars: %{},\n      # Stores special metadata used by list heads and domain keys in patterns\n      subpatterns: %{},\n      # Variables that are specific to the current environment/conditional\n      conditional_vars: nil,\n      # Track metadata specific to patterns and guards\n      pattern_info: nil,\n      # If type checking has found an error/failure\n      failed: false,\n      # Local signatures used by local handler\n      local_sigs: %{},\n      # Track which clauses have been used across private local calls\n      local_used: %{}\n    }\n  end\n\n  defp fresh_stack(stack, mode, function) when mode in @modes do\n    %{stack | mode: mode, function: function}\n  end\n\n  defp fresh_context(context) do\n    %{context | vars: %{}, failed: false}\n  end\n\n  defp restore_context(later_context, %{vars: vars, failed: failed}) do\n    %{later_context | vars: vars, failed: failed}\n  end\n\n  ## Diagnostics\n\n  def format_diagnostic({:unused_clause, kind, {fun, arity}}) do\n    %{\n      message:\n        \"this clause of #{kind} #{fun}/#{arity} is never used (or it will always fail when invoked)\"\n    }\n  end\n\n  ## Module errors\n\n  def format_error({:unused_args, {name, arity}}),\n    do:\n      \"default values for the optional arguments in the private function #{name}/#{arity} are never used\"\n\n  def format_error({:unused_args, {name, arity}, count}) when arity - count == 1,\n    do:\n      \"the default value for the last optional argument in the private function #{name}/#{arity} is never used\"\n\n  def format_error({:unused_args, {name, arity}, count}),\n    do:\n      \"the default values for the last #{arity - count} optional arguments in the private function #{name}/#{arity} are never used\"\n\n  def format_error({:unused_def, {name, arity}, :defp}),\n    do: \"function #{name}/#{arity} is unused\"\n\n  def format_error({:unused_def, {name, arity}, :defmacrop}),\n    do: \"macro #{name}/#{arity} is unused\"\n\n  def format_error({:undefined_function, {f, a}, _})\n      when {f, a} in [__info__: 1, behaviour_info: 1, module_info: 1, module_info: 0],\n      do:\n        \"undefined function #{f}/#{a} (this function is auto-generated by the compiler and must always be called as a remote, as in __MODULE__.#{f}/#{a})\"\n\n  def format_error({:undefined_function, {f, a}, module}),\n    do:\n      \"undefined function #{f}/#{a} (expected #{inspect(module)} to define such a function or for it to be imported, but none are available)\"\n\n  def format_error({:incorrect_dispatch, {f, a}, _module}),\n    do: \"cannot invoke macro #{f}/#{a} before its definition\"\nend\n"
  },
  {
    "path": "lib/elixir/lib/module.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Module do\n  @moduledoc ~S'''\n  Provides functions to deal with modules during compilation time.\n\n  It allows a developer to dynamically add, delete and register\n  attributes, attach documentation and so forth.\n\n  After a module is compiled, using many of the functions in\n  this module will raise errors, since it is out of their scope\n  to inspect runtime data. Most of the runtime data can be inspected\n  via the [`__info__/1`](`c:Module.__info__/1`) function attached to\n  each compiled module.\n\n  ## Module attributes\n\n  Each module can be decorated with one or more attributes. The following ones\n  are currently defined by Elixir:\n\n  ### `@after_compile`\n\n  A hook that will be invoked right after the current module is compiled.\n  Accepts a module or a `{module, function_name}`. See the [\"Compile callbacks\"](#module-compile-callbacks)\n  section below.\n\n  ### `@after_verify` (since v1.14.0)\n\n  A hook that will be invoked right after the current module is verified for\n  undefined functions, deprecations, etc. Accepts a module or a `{module, function_name}`.\n  See the [\"Compile callbacks\"](#module-compile-callbacks) section below.\n\n  ### `@before_compile`\n\n  A hook that will be invoked before the module is compiled.\n  Accepts a module or a `{module, function_or_macro_name}` tuple.\n  See the [\"Compile callbacks\"](#module-compile-callbacks) section below.\n\n  ### `@behaviour`\n\n  Note the British spelling!\n\n  Behaviours can be referenced by modules to ensure they implement\n  required specific function signatures defined by `@callback`.\n\n  For example, you could specify a `URI.Parser` behaviour as follows:\n\n      defmodule URI.Parser do\n        @doc \"Defines a default port\"\n        @callback default_port() :: integer\n\n        @doc \"Parses the given URL\"\n        @callback parse(uri_info :: URI.t()) :: URI.t()\n      end\n\n  And then a module may use it as:\n\n      defmodule URI.HTTP do\n        @behaviour URI.Parser\n        def default_port(), do: 80\n        def parse(info), do: info\n      end\n\n  If the behaviour changes or `URI.HTTP` does not implement\n  one of the callbacks, a warning will be raised.\n\n  For detailed documentation, see the\n  [behaviour typespec documentation](typespecs.md#behaviours).\n\n  ### `@impl` (since v1.5.0)\n\n  To aid in the correct implementation of behaviours, you may optionally declare\n  `@impl` for implemented callbacks of a behaviour. This makes callbacks\n  explicit and can help you to catch errors in your code. The compiler will warn\n  in these cases:\n\n    * if you mark a function with `@impl` when that function is not a callback.\n\n    * if you don't mark a function with `@impl` when other functions are marked\n      with `@impl`. If you mark one function with `@impl`, you must mark all\n      other callbacks for that behaviour as `@impl`.\n\n  `@impl` works on a per-context basis. If you generate a function through a macro\n  and mark it with `@impl`, that won't affect the module where that function is\n  generated in.\n\n  `@impl` also helps with maintainability by making it clear to other developers\n  that the function is implementing a callback.\n\n  Using `@impl`, the example above can be rewritten as:\n\n      defmodule URI.HTTP do\n        @behaviour URI.Parser\n\n        @impl true\n        def default_port(), do: 80\n\n        @impl true\n        def parse(info), do: info\n      end\n\n  You may pass either `false`, `true`, or a specific behaviour to `@impl`.\n\n      defmodule Foo do\n        @behaviour Bar\n        @behaviour Baz\n\n        # Will warn if neither Bar nor Baz specify a callback named bar/0.\n        @impl true\n        def bar(), do: :ok\n\n        # Will warn if Baz does not specify a callback named baz/0.\n        @impl Baz\n        def baz(), do: :ok\n      end\n\n  The code is now more readable, as it is now clear which functions are\n  part of your API and which ones are callback implementations. To reinforce this\n  idea, `@impl true` automatically marks the function as `@doc false`, disabling\n  documentation unless `@doc` is explicitly set.\n\n  ### `@compile`\n\n  Defines options for module compilation. This is used to configure\n  both Elixir and Erlang compilers, as well as any other compilation pass\n  added by external tools. For example:\n\n      defmodule MyModule do\n        @compile {:inline, my_fun: 1}\n\n        def my_fun(arg) do\n          to_string(arg)\n        end\n      end\n\n  Multiple uses of `@compile` will accumulate instead of overriding\n  previous ones. See the [\"Compile options\"](#module-compile-options) section below.\n\n  ### `@deprecated` (since v1.6.0)\n\n  Provides the deprecation reason for a function. For example:\n\n      defmodule Keyword do\n        @deprecated \"Use Kernel.length/1 instead\"\n        def size(keyword) do\n          length(keyword)\n        end\n      end\n\n  The Mix compiler automatically looks for calls to deprecated modules\n  and emit warnings during compilation.\n\n  Using the `@deprecated` attribute will also be reflected in the\n  documentation of the given function and macro. You can choose between\n  the `@deprecated` attribute and the documentation metadata to provide\n  hard-deprecations (with warnings) and soft-deprecations (without warnings):\n\n  This is a soft-deprecation as it simply annotates the documentation\n  as deprecated:\n\n      @doc deprecated: \"Use Kernel.length/1 instead\"\n      def size(keyword)\n\n  This is a hard-deprecation as it emits warnings and annotates the\n  documentation as deprecated:\n\n      @deprecated \"Use Kernel.length/1 instead\"\n      def size(keyword)\n\n  Currently `@deprecated` only supports functions and macros. However\n  you can use the `:deprecated` key in the annotation metadata to\n  annotate the docs of modules, types and callbacks too.\n\n  We recommend using this feature with care, especially library authors.\n  Deprecating code always pushes the burden towards library users. We\n  also recommend for deprecated functionality to be maintained for long\n  periods of time, even after deprecation, giving developers plenty of\n  time to update (except for cases where keeping the deprecated API is\n  undesired, such as in the presence of security issues).\n\n  ### `@doc` and `@typedoc`\n\n  Provides documentation for the entity that follows the attribute.\n  `@doc` is to be used with a function, macro, callback, or\n  macrocallback, while `@typedoc` with a type (public or opaque).\n\n  Accepts one of these:\n\n    * a string (often a heredoc)\n    * `false`, which will make the entity invisible to documentation-extraction\n      tools like [`ExDoc`](https://hexdocs.pm/ex_doc/)\n    * a keyword list, since Elixir 1.7.0\n\n  For example:\n\n      defmodule MyModule do\n        @typedoc \"This type\"\n        @typedoc since: \"1.1.0\"\n        @type t :: term\n\n        @doc \"Hello world\"\n        @doc since: \"1.1.0\"\n        def hello do\n          \"world\"\n        end\n\n        @doc \"\"\"\n        Sums `a` to `b`.\n        \"\"\"\n        def sum(a, b) do\n          a + b\n        end\n      end\n\n  As can be seen in the example above, since Elixir 1.7.0 `@doc` and `@typedoc`\n  also accept a keyword list that serves as a way to provide arbitrary metadata\n  about the entity. Tools like [`ExDoc`](https://hexdocs.pm/ex_doc/) and\n  `IEx` may use this information to display annotations. A common use\n  case is the `:since` key, which may be used to annotate in which version the\n  function was introduced.\n\n  As illustrated in the example, it is possible to use these attributes\n  more than once before an entity. However, the compiler will warn if\n  used twice with binaries as that replaces the documentation text from\n  the preceding use. Multiple uses with keyword lists will merge the\n  lists into one.\n\n  Note that since the compiler also defines some additional metadata,\n  there are a few reserved keys that will be ignored and warned if used.\n  Currently these are: `:opaque` and `:defaults`.\n\n  Once this module is compiled, this information becomes available via\n  the `Code.fetch_docs/1` function.\n\n  ### `@dialyzer`\n\n  Defines warnings to request or suppress when using `:dialyzer`.\n\n  Accepts an atom, a tuple, or a list of atoms and tuples. For example:\n\n      defmodule MyModule do\n        @dialyzer {:nowarn_function, [my_fun: 1]}\n\n        def my_fun(arg) do\n          M.not_a_function(arg)\n        end\n      end\n\n  For the list of supported warnings, see [`:dialyzer` module](`:dialyzer`).\n\n  Multiple uses of `@dialyzer` will accumulate instead of overriding\n  previous ones.\n\n  ### `@external_resource`\n\n  Specifies an external resource for the current module.\n\n  Sometimes a module embeds information from an external file. This\n  attribute allows the module to annotate which external resources\n  have been used.\n\n  Tools may use this information to ensure the module is recompiled\n  in case any of the external resources change, see for example:\n  [`mix compile.elixir`](https://hexdocs.pm/mix/Mix.Tasks.Compile.Elixir.html).\n\n  The specified file path provided is interpreted as relative to\n  the folder containing the project's `mix.exs`, which is the\n  current working directory, not the file where `@external_resource`\n  is declared.\n\n  If the external resource does not exist, the module still has\n  a dependency on it, causing the module to be recompiled as soon\n  as the file is added.\n\n  For more control over when a module is recompiled, see\n  [`__mix_recompile__?/0`](`m:Mix.Tasks.Compile.Elixir#module-__mix_recompile__-0`).\n\n  ### `@file`\n\n  Changes the filename used in stacktraces for the function or macro that\n  follows the attribute, such as:\n\n      defmodule MyModule do\n        @doc \"Hello world\"\n        @file \"hello.ex\"\n        def hello do\n          \"world\"\n        end\n      end\n\n  Note that this is only valid for exceptions/diagnostics that come from the\n  definition inner scope (which includes its patterns and guards). For example:\n\n      defmodule MyModule do # <---- module definition\n        @file \"hello.ex\"\n        defp unused(a) do # <---- function definition\n          \"world\" # <---- function scope\n        end\n\n        @file \"bye.ex\"\n        def unused(_), do: true\n      end\n\n  If you run this code with the second \"unused\" definition commented, you will\n  see that `hello.ex` is used as the stacktrace when reporting warnings, but if\n  you uncomment it you'll see that the error will not mention `bye.ex`, because\n  it's a module-level error rather than an expression-level error.\n\n  ### `@moduledoc`\n\n  Provides documentation for the current module.\n\n      defmodule MyModule do\n        @moduledoc \"\"\"\n        A very useful module.\n        \"\"\"\n        @moduledoc authors: [\"Alice\", \"Bob\"]\n      end\n\n  Accepts a string (often a heredoc) or `false` where `@moduledoc false`\n  will make the module invisible to documentation extraction tools like\n  [`ExDoc`](https://hexdocs.pm/ex_doc/).\n\n  Similarly to `@doc` also accepts a keyword list to provide metadata\n  about the module. For more details, see the documentation of `@doc`\n  above.\n\n  Once this module is compiled, this information becomes available via\n  the `Code.fetch_docs/1` function.\n\n  ### `@nifs` (since v1.16.0)\n\n  A list of functions and their arities which will be overridden\n  by a native implementation (NIF).\n\n      defmodule MyLibrary.MyModule do\n        @nifs [foo: 1, bar: 2]\n\n        def foo(arg1), do: :erlang.nif_error(:not_loaded)\n        def bar(arg1, arg2), do: :erlang.nif_error(:not_loaded)\n      end\n\n  See the Erlang documentation for more information:\n  https://www.erlang.org/doc/man/erl_nif\n\n  ### `@on_definition`\n\n  A hook that will be invoked when each function or macro in the current\n  module is defined. Useful when annotating functions.\n\n  Accepts a module or a `{module, function_name}` tuple. The function\n  must take 6 arguments:\n\n    * the module environment\n    * the kind of the function/macro: `:def`, `:defp`, `:defmacro`, or `:defmacrop`\n    * the function/macro name\n    * the list of quoted arguments\n    * the list of quoted guards\n    * the quoted function body\n\n  If the function/macro being defined has multiple clauses, the hook will\n  be called for each clause.\n\n  Unlike other hooks, `@on_definition` will only invoke functions and\n  never macros. This is to avoid `@on_definition` callbacks from\n  redefining functions that have just been defined in favor of more\n  explicit approaches.\n\n  When just a module is provided, the function is assumed to be\n  `__on_definition__/6`.\n\n  #### Example\n\n      defmodule Hooks do\n        def on_def(_env, kind, name, args, guards, body) do\n          IO.puts(\"Defining #{kind} named #{name} with args:\")\n          IO.inspect(args)\n          IO.puts(\"and guards\")\n          IO.inspect(guards)\n          IO.puts(\"and body\")\n          IO.puts(Macro.to_string(body))\n        end\n      end\n\n      defmodule MyModule do\n        @on_definition {Hooks, :on_def}\n\n        def hello(arg) when is_binary(arg) or is_list(arg) do\n          \"Hello\" <> to_string(arg)\n        end\n\n        def hello(_) do\n          :ok\n        end\n      end\n\n  ### `@on_load`\n\n  A hook that will be invoked whenever the module is loaded.\n\n  Accepts the function name (as an atom) of a function in the current module.\n  The function must have an arity of 0 (no arguments). If the function does\n  not return `:ok`, the loading of the module will be aborted. Its primary\n  use case is to load [NIFs](https://www.erlang.org/doc/man/erl_nif):\n\n      defmodule MyModule do\n        @on_load :load_external_code\n\n        def load_external_code do\n          :erlang.load_nif(~c\"path/to/extension.so_or_dll\")\n        end\n      end\n\n  The function given to `on_load` should avoid calling functions from\n  other modules. This is because, when running a `mix release`,\n  `on_load` runs extremely early, before any application starts running,\n  and therefore even systems like the `Logger` and `IO` are not yet available.\n\n  ### `@vsn`\n\n  Specify the module version. Accepts any valid Elixir value, for example:\n\n      defmodule MyModule do\n        @vsn \"1.0\"\n      end\n\n  ### Struct attributes\n\n    * `@derive` - derives an implementation for the given protocol for the\n      struct defined in the current module\n\n    * `@enforce_keys` - ensures the given keys are always set when building\n      the struct defined in the current module\n\n  See `defstruct/1` for more information on building and using structs.\n\n  ### Typespec attributes\n\n  The following attributes are part of typespecs and are also built-in in\n  Elixir:\n\n    * `@type` - defines a type to be used in `@spec`\n    * `@typep` - defines a private type to be used in `@spec`\n    * `@opaque` - defines an opaque type to be used in `@spec`\n    * `@spec` - provides a specification for a function\n    * `@callback` - provides a specification for a behaviour callback (and generates\n      a `behaviour_info/1` function in the module, see below)\n    * `@macrocallback` - provides a specification for a macro behaviour callback\n    * `@optional_callbacks` - specifies which behaviour callbacks and macro\n      behaviour callbacks are optional\n    * `@impl` - declares an implementation of a callback function or macro\n\n  For detailed documentation, see the [typespec documentation](typespecs.md).\n\n  ### Custom attributes\n\n  In addition to the built-in attributes outlined above, custom attributes may\n  also be added. Custom attributes are expressed using the `@/1` operator followed\n  by a valid variable name. The value given to the custom attribute must be a valid\n  Elixir value:\n\n      defmodule MyModule do\n        @custom_attr [some: \"stuff\"]\n      end\n\n  For more advanced options available when defining custom attributes, see\n  `register_attribute/3`.\n\n  ## Compile callbacks\n\n  There are three compilation callbacks, invoked in this order:\n  `@before_compile`, `@after_compile`, and `@after_verify`.\n  They are described next.\n\n  ### `@before_compile`\n\n  A hook that will be invoked before the module is compiled. This is\n  often used to change how the current module is being compiled.\n\n  Accepts a module or a `{module, function_or_macro_name}` tuple. The\n  function/macro must take one argument: the module environment. If\n  it's a macro, its returned value will be injected at the end of the\n  module definition before the compilation starts.\n\n  When just a module is provided, the function/macro is assumed to be\n  `__before_compile__/1`.\n\n  Callbacks will run in the order they are registered. Any overridable\n  definition will be made concrete before the first callback runs.\n  A definition may be made overridable again in another before compile\n  callback and it will be made concrete one last time after all callbacks\n  run.\n\n  *Note*: the callback function/macro must be placed in a separate module\n  (because when the callback is invoked, the current module does not yet exist).\n\n  #### Example\n\n      defmodule A do\n        defmacro __before_compile__(_env) do\n          quote do\n            def hello, do: \"world\"\n          end\n        end\n      end\n\n      defmodule B do\n        @before_compile A\n      end\n\n      B.hello()\n      #=> \"world\"\n\n  ### `@after_compile`\n\n  A hook that will be invoked with the bytecode of the current module.\n  Although the module has already been compiled, its bytecode may not have\n  been loaded to memory nor written to disk. For those reasons, prefer to\n  use `@after_verify` callbacks or use `Code.ensure_compiled!/1` to wait\n  until the module is fully available for introspection/invocation.\n\n  Accepts a module or a `{module, function_name}` tuple. The function\n  must take two arguments: the module environment and its bytecode.\n  When just a module is provided, the function is assumed to be\n  `__after_compile__/2`.\n\n  Callbacks will run in the order they are registered.\n\n  `Module` functions expecting not yet compiled modules (such as `definitions_in/1`)\n  are still available at the time `@after_compile` is invoked.\n\n  #### Example\n\n      defmodule MyModule do\n        @after_compile __MODULE__\n\n        def __after_compile__(env, _bytecode) do\n          IO.inspect(env)\n        end\n      end\n\n  ### `@after_verify`\n\n  A hook that will be invoked right after the current module is verified for\n  undefined functions, deprecations, etc. A module is always verified after\n  it is compiled. In Mix projects, a module is also verified when any of its\n  runtime dependencies change. Therefore this is useful to perform verification\n  of the current module while avoiding compile-time dependencies. Given the\n  callback is invoked under different scenarios, Elixir provides no guarantees\n  of when in the compilation cycle nor in which process the callback runs.\n\n  Furthermore, after verification callbacks are not expected to raise.\n  Given they run after the code is compiled, artifacts have already been\n  written to disk, and therefore raising does not effectively halt compilation\n  and may leave unused artifacts on disk. If you must raise, use `@after_compile`\n  or other callback. Given modules have already been compiled, functions in\n  this module, such as `get_attribute/2`, which expect modules to not have been\n  yet compiled, do not work on `@after_verify` callback.\n\n  Accepts a module or a `{module, function_name}` tuple. The function\n  must take one argument: the module name. When just a module is provided,\n  the function is assumed to be `__after_verify__/1`.\n\n  Callbacks will run in the order they are registered.\n\n  #### Example\n\n      defmodule MyModule do\n        @after_verify __MODULE__\n\n        def __after_verify__(module) do\n          IO.inspect(module)\n          :ok\n        end\n      end\n\n  ## Compile options\n\n  The `@compile` attribute accepts different options that are used by both\n  Elixir and Erlang compilers. Some of the common use cases are documented\n  below:\n\n    * `@compile :debug_info` - includes `:debug_info` regardless of the\n      corresponding setting in `Code.get_compiler_option/1`\n\n    * `@compile {:debug_info, false}` - disables `:debug_info` regardless\n      of the corresponding setting in `Code.get_compiler_option/1`. Note\n      disabling `:debug_info` is not recommended as it removes the ability\n      of the Elixir compiler and other tools to static analyse the code.\n      If you want to remove the `:debug_info` while deploying, tools like\n      `mix release` already do such by default.\n\n    * `@compile {:inline, some_fun: 2, other_fun: 3}` - inlines the given\n      name/arity pairs. Inlining is applied locally, calls from another\n      module are not affected by this option\n\n    * `@compile {:autoload, true}` - configures if modules are automatically\n      loaded after definition. It defaults to `false` when compiling modules\n      to `.beam` files in disk (as the modules are then lazily loaded from\n      disk). If modules are not compiled to disk, then they are always loaded,\n      regardless of this flag\n\n    * `@compile {:no_warn_undefined, Mod}` or\n      `@compile {:no_warn_undefined, {Mod, fun, arity}}` - does not warn if\n      the given module or the given `Mod.fun/arity` are not defined\n\n  ## Generated functions\n\n  Sometimes the compiler will generate public functions within modules. These\n  are documented below.\n\n  ### `behaviour_info/1`\n\n  This function is generated for modules that define a behaviour, that is,\n  that have one or more `@callback` definitions. The signature for this function,\n  expressed as a spec, is:\n\n      @spec behaviour_info(:callbacks) :: [function_info]\n        when function_info: {function_name :: atom(), arity :: non_neg_integer()}\n\n      @spec behaviour_info(:optional_callbacks) :: [function_info]\n        when function_info: {function_name :: atom(), arity :: non_neg_integer()}\n\n  `behaviour_info(:callbacks)` includes optional callbacks.\n\n  For example:\n\n      iex> Enum.sort(GenServer.behaviour_info(:callbacks))\n      [\n        code_change: 3,\n        format_status: 1,\n        format_status: 2,\n        handle_call: 3,\n        handle_cast: 2,\n        handle_continue: 2,\n        handle_info: 2,\n        init: 1,\n        terminate: 2\n      ]\n\n  ### `module_info/0`\n\n  This function is generated for all modules. It returns all the attributes\n  returned by `module_info/1` (see below), but as a single keyword list. See also the\n  [Erlang documentation](https://www.erlang.org/doc/system/modules.html#module_info-0).\n\n  ### `module_info/1`\n\n  This function is generated for all modules and returns\n  information about the module. The signature for this function,\n  expressed as a spec, is:\n\n      @spec module_info(:module) :: module() # Returns the module itself\n      @spec module_info(:attributes) :: keyword()\n      @spec module_info(:compile) :: keyword()\n      @spec module_info(:md5) :: binary()\n      @spec module_info(:nifs) :: [function_info]\n        when function_info: {function_name :: atom(), arity :: non_neg_integer()}\n      @spec module_info(:exports) :: [function_info]\n        when function_info: {function_name :: atom(), arity :: non_neg_integer()}\n      @spec module_info(:functions) :: [function_info]\n        when function_info: {function_name :: atom(), arity :: non_neg_integer()}\n\n  For example:\n\n      iex> URI.module_info(:module)\n      URI\n      iex> {:decode_www_form, 1} in URI.module_info(:exports)\n      true\n\n  For more information about `module_info/1`, also check out the [Erlang\n  documentation](https://www.erlang.org/doc/system/modules.html#module_info-1).\n\n  ### `__info__/1`\n\n  This function is generated for all modules. It's similar to `module_info/1` but\n  includes some additional Elixir-specific information, such as struct and macro\n  information. For documentation, see `c:Module.__info__/1`.\n  '''\n\n  @type definition :: {atom, arity}\n  @type def_kind :: :def | :defp | :defmacro | :defmacrop\n\n  @type create_opts :: [\n          file: binary(),\n          line: pos_integer(),\n          generated: boolean()\n        ]\n\n  @type get_definition_opts :: [\n          skip_clauses: boolean()\n        ]\n\n  @extra_error_msg_defines? \"Use Kernel.function_exported?/3 and Kernel.macro_exported?/3 \" <>\n                              \"to check for public functions and macros instead\"\n\n  @extra_error_msg_definitions_in \"Use the Module.__info__/1 callback to get public functions and macros instead\"\n\n  @doc \"\"\"\n  Provides runtime information about functions, macros, and other information\n  defined by the module.\n\n  Each module gets an `__info__/1` function when it's compiled. The function\n  takes one of the following items:\n\n    * `:attributes` - a keyword list with all persisted attributes\n\n    * `:compile` - a list with compiler metadata\n\n    * `:functions` - a keyword list of public functions and their arities\n\n    * `:macros` - a keyword list of public macros and their arities\n\n    * `:md5` - the MD5 of the module\n\n    * `:module` - the module atom name\n\n    * `:struct` - (since v1.14.0) if the module defines a struct and if so each field in order.\n      See `Macro.struct_info!/2` for more information\n\n  \"\"\"\n  @callback __info__(:attributes) :: keyword()\n  @callback __info__(:compile) :: [term()]\n  @callback __info__(:functions) :: keyword()\n  @callback __info__(:macros) :: keyword()\n  @callback __info__(:md5) :: binary()\n  @callback __info__(:module) :: module()\n  @callback __info__(:struct) ::\n              [\n                %{\n                  required(:field) => atom(),\n                  optional(:required) => boolean(),\n                  optional(:default) => term()\n                }\n              ]\n              | nil\n\n  @doc \"\"\"\n  Returns information about module attributes used by Elixir.\n\n  See the [\"Module attributes\"](#module-module-attributes) section in the module documentation for more\n  information on each attribute.\n\n  ## Examples\n\n      iex> map = Module.reserved_attributes()\n      iex> Map.has_key?(map, :moduledoc)\n      true\n      iex> Map.has_key?(map, :doc)\n      true\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec reserved_attributes() :: map\n  def reserved_attributes() do\n    %{\n      after_compile: %{\n        doc: \"A hook that will be invoked right after the current module is compiled.\"\n      },\n      after_verify: %{\n        doc: \"A hook that will be invoked right after the current module is verified.\"\n      },\n      before_compile: %{\n        doc: \"A hook that will be invoked before the module is compiled.\"\n      },\n      behaviour: %{\n        doc: \"Specifies that the current module implements a given behaviour.\"\n      },\n      enforce_keys: %{\n        doc:\n          \"Ensures the given keys are always set when building the struct defined in the current module.\"\n      },\n      fallback_to_any: %{\n        doc:\n          \"If set to `true` generates a default protocol implementation for all types (inside `defprotocol`).\"\n      },\n      undefined_impl_description: %{\n        doc:\n          \"A string with additional description to be used on `Protocol.UndefinedError` when looking up the implementation fails.\"\n      },\n      for: %{\n        doc:\n          \"The current module/type a protocol implementation is being defined for (inside `defimpl`).\"\n      },\n      protocol: %{\n        doc: \"The current protocol being implemented (inside `defimpl`).\"\n      },\n      on_definition: %{\n        doc:\n          \"A hook that will be invoked when each function or macro in the current module is defined.\"\n      },\n      impl: %{\n        doc: \"Declares an implementation of a callback function or macro.\"\n      },\n      compile: %{\n        doc: \"Defines options for module compilation.\"\n      },\n      deprecated: %{\n        doc: \"Provides the deprecation reason for a function.\"\n      },\n      moduledoc: %{\n        doc: \"Provides documentation for the current module.\"\n      },\n      doc: %{\n        doc: \"Provides documentation for a function/macro/callback.\"\n      },\n      typedoc: %{\n        doc: \"Provides documentation for a type.\"\n      },\n      dialyzer: %{\n        doc: \"Defines Dialyzer warnings to request or suppress.\"\n      },\n      external_resource: %{\n        doc: \"Specifies an external resource for the current module.\"\n      },\n      file: %{\n        doc:\n          \"Changes the filename used in stacktraces for the function or macro that follows the attribute.\"\n      },\n      on_load: %{\n        doc: \"A hook that will be invoked whenever the module is loaded.\"\n      },\n      vsn: %{\n        doc: \"Specify the module version.\"\n      },\n      type: %{\n        doc: \"Defines a type to be used in `@spec`.\"\n      },\n      typep: %{\n        doc: \"Defines a private type to be used in `@spec`.\"\n      },\n      opaque: %{\n        doc: \"Defines an opaque type to be used in `@spec`.\"\n      },\n      spec: %{\n        doc: \"Provides a specification for a function.\"\n      },\n      callback: %{\n        doc: \"Provides a specification for a behaviour callback.\"\n      },\n      macrocallback: %{\n        doc: \"Provides a specification for a macro behaviour callback.\"\n      },\n      optional_callbacks: %{\n        doc: \"Specifies which behaviour callbacks and macro behaviour callbacks are optional.\"\n      },\n      derive: %{\n        doc:\n          \"Derives an implementation for the given protocol for the struct defined in the current module.\"\n      }\n    }\n  end\n\n  @doc \"\"\"\n  Checks if a module is open.\n\n  A module is \"open\" if it is currently being defined and its attributes and\n  functions can be modified.\n  \"\"\"\n  @spec open?(module) :: boolean\n  def open?(module) when is_atom(module) do\n    :elixir_module.is_open(module)\n  end\n\n  @deprecated \"Use Code.eval_quoted/3 instead\"\n  def eval_quoted(module_or_env, quoted, binding \\\\ [], opts \\\\ [])\n\n  def eval_quoted(%Macro.Env{} = env, quoted, binding, opts)\n      when is_list(binding) and is_list(opts) do\n    validated_eval_quoted(env.module, quoted, binding, struct!(env, opts))\n  end\n\n  def eval_quoted(module, quoted, binding, %Macro.Env{} = env)\n      when is_atom(module) and is_list(binding) do\n    validated_eval_quoted(module, quoted, binding, env)\n  end\n\n  def eval_quoted(module, quoted, binding, opts)\n      when is_atom(module) and is_list(binding) and is_list(opts) do\n    validated_eval_quoted(module, quoted, binding, opts)\n  end\n\n  defp validated_eval_quoted(module, quoted, binding, env_or_opts) do\n    assert_not_compiled!({:eval_quoted, 4}, module, :all)\n    :elixir_def.reset_last(module)\n    env = :elixir.env_for_eval(env_or_opts)\n    {value, binding, _env} = :elixir.eval_quoted(quoted, binding, %{env | module: module})\n    {value, binding}\n  end\n\n  @doc \"\"\"\n  Creates a module with the given name and defined by\n  the given quoted expressions.\n\n  The line where the module is defined and its file **must**\n  be passed as options. See `Code.env_for_eval/1` for a complete\n  list of options.\n\n  It returns a tuple of shape `{:module, module, binary, term}`\n  where `module` is the module name, `binary` is the module\n  bytecode and `term` is the result of the last expression in\n  `quoted`.\n\n  Similar to `Kernel.defmodule/2`, the binary will only be\n  written to disk as a `.beam` file if `Module.create/3` is\n  invoked in a file that is currently being compiled.\n\n  ## Examples\n\n      contents =\n        quote do\n          def world, do: true\n        end\n\n      Module.create(Hello, contents, Macro.Env.location(__ENV__))\n\n      Hello.world()\n      #=> true\n\n  ## Differences from `defmodule`\n\n  `Module.create/3` works similarly to `Kernel.defmodule/2`\n  and return the same results. While one could also use\n  `Kernel.defmodule/2` to define modules dynamically, this function\n  is preferred when the module body is given by a quoted\n  expression.\n\n  Another important distinction is that `Module.create/3`\n  allows you to control the environment variables used\n  when defining the module, while `Kernel.defmodule/2`\n  automatically uses the environment it is invoked at.\n  \"\"\"\n  @spec create(module, Macro.t(), Macro.Env.t() | create_opts) :: {:module, module, binary, term}\n  def create(module, quoted, opts)\n\n  def create(module, quoted, %Macro.Env{} = env) when is_atom(module) do\n    create([line: env.line], module, quoted, env)\n  end\n\n  def create(module, quoted, opts) when is_atom(module) and is_list(opts) do\n    if not Keyword.has_key?(opts, :file) do\n      raise ArgumentError, \"expected :file to be given as option\"\n    end\n\n    meta = Keyword.take(opts, [:line, :generated])\n    create(meta, module, quoted, :elixir.env_for_eval(opts))\n  end\n\n  defp create(meta, module, quoted, env_or_opts) do\n    next = :elixir_module.next_counter(nil)\n    quoted = :elixir_quote.linify_with_context_counter(meta, {module, next}, quoted)\n    :elixir_module.compile(meta, module, quoted, [], false, :elixir.env_for_eval(env_or_opts))\n  end\n\n  @doc \"\"\"\n  Concatenates a list of aliases and returns a new alias.\n\n  It handles binaries and atoms.\n\n  > #### Untracked compile-time dependencies {: .warning}\n  >\n  > Use this function with care, as dynamically defining\n  > module names at compilation time may lead to\n  > [untracked compile-time dependencies](macro-anti-patterns.md#untracked-compile-time-dependencies).\n\n  ## Examples\n\n      iex> Module.concat([Foo, Bar])\n      Foo.Bar\n\n      iex> Module.concat([Foo, \"Bar\"])\n      Foo.Bar\n\n  \"\"\"\n  @spec concat([binary | atom]) :: atom\n  def concat(list) when is_list(list) do\n    :elixir_aliases.concat(list)\n  end\n\n  @doc \"\"\"\n  Concatenates two aliases and returns a new alias.\n\n  It handles binaries and atoms. If one of the aliases\n  is nil, it is discarded.\n\n  > #### Untracked compile-time dependencies {: .warning}\n  >\n  > Use this function with care, as dynamically defining\n  > module names at compilation time may lead to\n  > [untracked compile-time dependencies](macro-anti-patterns.md#untracked-compile-time-dependencies).\n\n  ## Examples\n\n      iex> Module.concat(Foo, Bar)\n      Foo.Bar\n\n      iex> Module.concat(Foo, \"Bar\")\n      Foo.Bar\n\n      iex> Module.concat(Foo, nil)\n      Foo\n\n  \"\"\"\n  @spec concat(binary | atom, binary | atom) :: atom\n  def concat(left, right)\n      when (is_binary(left) or is_atom(left)) and (is_binary(right) or is_atom(right)) do\n    :elixir_aliases.concat([left, right])\n  end\n\n  @doc \"\"\"\n  Concatenates a list of aliases and returns a new alias only if the alias\n  was already referenced.\n\n  If the alias was not referenced yet, fails with `ArgumentError`.\n  It handles binaries and atoms.\n\n  > #### Untracked compile-time dependencies {: .warning}\n  >\n  > Use this function with care, as dynamically defining\n  > module names at compilation time may lead to\n  > [untracked compile-time dependencies](macro-anti-patterns.md#untracked-compile-time-dependencies).\n\n  ## Examples\n\n      iex> Module.safe_concat([List, Chars])\n      List.Chars\n\n  \"\"\"\n  @spec safe_concat([binary | atom]) :: atom\n  def safe_concat(list) when is_list(list) do\n    :elixir_aliases.safe_concat(list)\n  end\n\n  @doc \"\"\"\n  Concatenates two aliases and returns a new alias only if the alias was\n  already referenced.\n\n  If the alias was not referenced yet, fails with `ArgumentError`.\n  It handles binaries and atoms.\n\n  > #### Untracked compile-time dependencies {: .warning}\n  >\n  > Use this function with care, as dynamically defining\n  > module names at compilation time may lead to\n  > [untracked compile-time dependencies](macro-anti-patterns.md#untracked-compile-time-dependencies).\n\n  ## Examples\n\n      iex> Module.safe_concat(List, Chars)\n      List.Chars\n\n  \"\"\"\n  @spec safe_concat(binary | atom, binary | atom) :: atom\n  def safe_concat(left, right)\n      when (is_binary(left) or is_atom(left)) and (is_binary(right) or is_atom(right)) do\n    :elixir_aliases.safe_concat([left, right])\n  end\n\n  # Build signatures to be stored in docs\n\n  defp build_signature(args, env) do\n    {reverse_args, counters} = simplify_args(args, %{}, [], env)\n    expand_keys(reverse_args, counters, [])\n  end\n\n  defp simplify_args([arg | args], counters, acc, env) do\n    {arg, counters} = simplify_arg(arg, counters, env)\n    simplify_args(args, counters, [arg | acc], env)\n  end\n\n  defp simplify_args([], counters, reverse_args, _env) do\n    {reverse_args, counters}\n  end\n\n  defp simplify_arg({:\\\\, _, [left, right]}, counters, env) do\n    {left, counters} = simplify_arg(left, counters, env)\n\n    right =\n      Macro.prewalk(right, fn\n        {:@, _, _} = attr -> Macro.expand_once(attr, env)\n        other -> other\n      end)\n\n    {{:\\\\, [], [left, right]}, counters}\n  end\n\n  # If the variable is being used explicitly for naming,\n  # we always give it a higher priority (nil) even if it\n  # starts with underscore.\n  defp simplify_arg({:=, _, [{var, _, atom}, _]}, counters, _env) when is_atom(atom) do\n    {simplify_var(var, nil), counters}\n  end\n\n  defp simplify_arg({:=, _, [_, {var, _, atom}]}, counters, _env) when is_atom(atom) do\n    {simplify_var(var, nil), counters}\n  end\n\n  # If we have only the variable as argument, it also gets\n  # higher priority. However, if the variable starts with an\n  # underscore, we give it a secondary context (Elixir) with\n  # lower priority.\n  defp simplify_arg({var, _, atom}, counters, _env) when is_atom(atom) do\n    {simplify_var(var, Elixir), counters}\n  end\n\n  defp simplify_arg({:%, _, [left, _]}, counters, env) do\n    case Macro.expand_once(left, env) do\n      module when is_atom(module) -> autogenerated_key(counters, simplify_module_name(module))\n      _ -> autogenerated_key(counters, :struct)\n    end\n  end\n\n  defp simplify_arg({:%{}, _, _}, counters, _env) do\n    autogenerated_key(counters, :map)\n  end\n\n  defp simplify_arg({:@, _, _} = attr, counters, env) do\n    simplify_arg(Macro.expand_once(attr, env), counters, env)\n  end\n\n  defp simplify_arg({:var!, _, [{var, _, atom} | _]}, counters, _env) when is_atom(atom) do\n    {simplify_var(var, Elixir), counters}\n  end\n\n  defp simplify_arg(other, counters, _env) when is_integer(other),\n    do: autogenerated_key(counters, :int)\n\n  defp simplify_arg(other, counters, _env) when is_boolean(other),\n    do: autogenerated_key(counters, :bool)\n\n  defp simplify_arg(other, counters, _env) when is_atom(other),\n    do: autogenerated_key(counters, :atom)\n\n  defp simplify_arg(other, counters, _env) when is_list(other),\n    do: autogenerated_key(counters, :list)\n\n  defp simplify_arg(other, counters, _env) when is_float(other),\n    do: autogenerated_key(counters, :float)\n\n  defp simplify_arg(other, counters, _env) when is_binary(other),\n    do: autogenerated_key(counters, :binary)\n\n  defp simplify_arg(_, counters, _env), do: autogenerated_key(counters, :arg)\n\n  defp simplify_var(var, guess_priority) do\n    case Atom.to_string(var) do\n      \"_\" -> {:_, [], guess_priority}\n      \"_\" <> rest -> {String.to_atom(rest), [], guess_priority}\n      _ -> {var, [], nil}\n    end\n  end\n\n  defp simplify_module_name(module) when is_atom(module) do\n    try do\n      split(module)\n    rescue\n      ArgumentError -> module\n    else\n      module_name -> String.to_atom(Macro.underscore(List.last(module_name)))\n    end\n  end\n\n  defp autogenerated_key(counters, key) do\n    case counters do\n      %{^key => :once} -> {key, %{counters | key => 2}}\n      %{^key => value} -> {key, %{counters | key => value + 1}}\n      %{} -> {key, Map.put(counters, key, :once)}\n    end\n  end\n\n  defp expand_keys([{:\\\\, meta, [key, default]} | keys], counters, acc) when is_atom(key) do\n    {var, counters} = expand_key(key, counters)\n    expand_keys(keys, counters, [{:\\\\, meta, [var, default]} | acc])\n  end\n\n  defp expand_keys([key | keys], counters, acc) when is_atom(key) do\n    {var, counters} = expand_key(key, counters)\n    expand_keys(keys, counters, [var | acc])\n  end\n\n  defp expand_keys([arg | args], counters, acc) do\n    expand_keys(args, counters, [arg | acc])\n  end\n\n  defp expand_keys([], _counters, acc) do\n    acc\n  end\n\n  defp expand_key(key, counters) do\n    case counters do\n      %{^key => count} when is_integer(count) and count >= 1 ->\n        {{:\"#{key}#{count}\", [], Elixir}, Map.put(counters, key, count - 1)}\n\n      _ ->\n        {{key, [], Elixir}, counters}\n    end\n  end\n\n  # Merge\n\n  defp merge_signatures([h1 | t1], [h2 | t2], i) do\n    [merge_signature(h1, h2, i) | merge_signatures(t1, t2, i + 1)]\n  end\n\n  defp merge_signatures([], [], _) do\n    []\n  end\n\n  defp merge_signature({:\\\\, meta, [left, right]}, newer, i) do\n    {:\\\\, meta, [merge_signature(left, newer, i), right]}\n  end\n\n  defp merge_signature(older, {:\\\\, _, [left, _]}, i) do\n    merge_signature(older, left, i)\n  end\n\n  # The older signature, when given, always have higher precedence\n  defp merge_signature({_, _, nil} = older, _newer, _), do: older\n  defp merge_signature(_older, {_, _, nil} = newer, _), do: newer\n\n  # Both are a guess, so check if they are the same guess\n  defp merge_signature({var, _, _} = older, {var, _, _}, _), do: older\n\n  # Otherwise, returns a generic guess\n  defp merge_signature({_, meta, _}, _newer, i), do: {:\"arg#{i}\", meta, Elixir}\n\n  @doc \"\"\"\n  Checks if the module defines the given function or macro.\n\n  Use `defines?/3` to assert for a specific type.\n\n  This function can only be used on modules that have not yet been compiled.\n  Use `Kernel.function_exported?/3` and `Kernel.macro_exported?/3` to check for\n  public functions and macros respectively in compiled modules.\n\n  Note that `defines?` returns `false` for functions and macros that have\n  been defined but then marked as overridable and no other implementation\n  has been provided. You can check the overridable status by calling\n  `overridable?/2`.\n\n  ## Examples\n\n      defmodule Example do\n        Module.defines?(__MODULE__, {:version, 0}) #=> false\n        def version, do: 1\n        Module.defines?(__MODULE__, {:version, 0}) #=> true\n      end\n\n  \"\"\"\n  @spec defines?(module, definition) :: boolean\n  def defines?(module, {name, arity} = tuple)\n      when is_atom(module) and is_atom(name) and is_integer(arity) and arity >= 0 and arity <= 255 do\n    {set, _bag} = data_tables_for!(module, __ENV__.function, @extra_error_msg_defines?)\n    :ets.member(set, {:def, tuple})\n  end\n\n  @doc \"\"\"\n  Checks if the module defines a function or macro of the\n  given `kind`.\n\n  `kind` can be any of `:def`, `:defp`, `:defmacro`, or `:defmacrop`.\n\n  This function can only be used on modules that have not yet been compiled.\n  Use `Kernel.function_exported?/3` and `Kernel.macro_exported?/3` to check for\n  public functions and macros respectively in compiled modules.\n\n  ## Examples\n\n      defmodule Example do\n        Module.defines?(__MODULE__, {:version, 0}, :def) #=> false\n        def version, do: 1\n        Module.defines?(__MODULE__, {:version, 0}, :def) #=> true\n      end\n\n  \"\"\"\n  @spec defines?(module, definition, def_kind) :: boolean\n  def defines?(module, {name, arity} = tuple, def_kind)\n      when is_atom(module) and is_atom(name) and is_integer(arity) and arity >= 0 and arity <= 255 and\n             def_kind in [:def, :defp, :defmacro, :defmacrop] do\n    {set, _bag} = data_tables_for!(module, __ENV__.function, @extra_error_msg_defines?)\n\n    case :ets.lookup(set, {:def, tuple}) do\n      [{_, ^def_kind, _, _, _, _}] -> true\n      _ -> false\n    end\n  end\n\n  @doc \"\"\"\n  Checks if the current module defines the given type (private, opaque or not).\n\n  This function is only available for modules being compiled.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec defines_type?(module, definition) :: boolean\n  def defines_type?(module, definition) when is_atom(module) do\n    Kernel.Typespec.defines_type?(module, definition)\n  end\n\n  @doc \"\"\"\n  Copies the given spec as a callback.\n\n  Returns `true` if there is such a spec and it was copied as a callback.\n  If the function associated to the spec has documentation defined prior to\n  invoking this function, the docs are copied too.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec spec_to_callback(module, definition) :: boolean\n  def spec_to_callback(module, definition) do\n    Kernel.Typespec.spec_to_callback(module, definition)\n  end\n\n  @doc \"\"\"\n  Returns all module attributes names defined in `module`.\n\n  This function can only be used on modules that have not yet been compiled.\n\n  ## Examples\n\n      defmodule Example do\n        @foo 1\n        Module.register_attribute(__MODULE__, :bar, accumulate: true)\n\n        :foo in Module.attributes_in(__MODULE__)\n        #=> true\n\n        :bar in Module.attributes_in(__MODULE__)\n        #=> true\n      end\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec attributes_in(module) :: [atom]\n  def attributes_in(module) when is_atom(module) do\n    {set, _} = data_tables_for!(module, __ENV__.function, \"\")\n    :ets.select(set, [{{:\"$1\", :_, :_, :_}, [{:is_atom, :\"$1\"}], [:\"$1\"]}])\n  end\n\n  @doc \"\"\"\n  Returns all overridable definitions in `module`.\n\n  Note a definition is included even if it was already overridden.\n  You can use `defines?/2` to see if a definition exists or one is pending.\n\n  This function can only be used on modules that have not yet been compiled.\n\n  ## Examples\n\n      defmodule Example do\n        def foo, do: 1\n        def bar, do: 2\n\n        defoverridable foo: 0, bar: 0\n        def foo, do: 3\n\n        [bar: 0, foo: 0] = Module.overridables_in(__MODULE__) |> Enum.sort()\n      end\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec overridables_in(module) :: [definition]\n  def overridables_in(module) when is_atom(module) do\n    assert_not_compiled!(__ENV__.function, module, :all)\n    :elixir_overridable.overridables_for(module)\n  end\n\n  @doc \"\"\"\n  Returns all functions and macros defined in `module`.\n\n  It returns a list with all defined functions and macros, public and private,\n  in the shape of `[{name, arity}, ...]`.\n\n  This function can only be used on modules that have not yet been compiled.\n  Use the `c:Module.__info__/1` callback to get the public functions and macros in\n  compiled modules.\n\n  ## Examples\n\n      defmodule Example do\n        def version, do: 1\n        defmacrop test(arg), do: arg\n        Module.definitions_in(__MODULE__) #=> [{:version, 0}, {:test, 1}]\n      end\n\n  \"\"\"\n  @spec definitions_in(module) :: [definition]\n  def definitions_in(module) when is_atom(module) do\n    {_, bag} = data_tables_for!(module, __ENV__.function, @extra_error_msg_definitions_in)\n    bag_lookup_element(bag, :defs, 2)\n  end\n\n  @doc \"\"\"\n  Returns all functions defined in `module`, according\n  to its kind.\n\n  This function can only be used on modules that have not yet been compiled.\n  Use the `c:Module.__info__/1` callback to get the public functions and macros in\n  compiled modules.\n\n  ## Examples\n\n      defmodule Example do\n        def version, do: 1\n        Module.definitions_in(__MODULE__, :def)  #=> [{:version, 0}]\n        Module.definitions_in(__MODULE__, :defp) #=> []\n      end\n\n  \"\"\"\n  @spec definitions_in(module, def_kind) :: [definition]\n  def definitions_in(module, kind)\n      when is_atom(module) and kind in [:def, :defp, :defmacro, :defmacrop] do\n    {set, _} = data_tables_for!(module, __ENV__.function, @extra_error_msg_definitions_in)\n    :ets.select(set, [{{{:def, :\"$1\"}, kind, :_, :_, :_, :_}, [], [:\"$1\"]}])\n  end\n\n  @doc \"\"\"\n  Returns the definition for the given name-arity pair.\n\n  It returns a tuple with the `version`, the `kind`,\n  the definition `metadata`, and a list with each clause.\n  Each clause is a four-element tuple with metadata,\n  the arguments, the guards, and the clause AST.\n\n  The clauses are returned in the Elixir AST but a subset\n  that has already been expanded and normalized. This makes\n  it useful for analyzing code but it cannot be reinjected\n  into the module as it will have lost some of its original\n  context. Given this AST representation is mostly internal,\n  it is versioned and it may change at any time. Therefore,\n  **use this API with caution**.\n\n  ## Options\n\n    * `:skip_clauses` (since v1.14.0) - returns `[]` instead\n      of returning the clauses. This is useful when there is\n      only an interest in fetching the kind and the metadata\n\n  \"\"\"\n  @spec get_definition(module, definition, get_definition_opts) ::\n          {:v1, def_kind, meta :: keyword,\n           [{meta :: keyword, arguments :: [Macro.t()], guards :: [Macro.t()], Macro.t()}]}\n          | nil\n  @doc since: \"1.12.0\"\n  def get_definition(module, {name, arity}, options \\\\ [])\n      when is_atom(module) and is_atom(name) and is_integer(arity) and is_list(options) do\n    {set, bag} = data_tables_for!(module, __ENV__.function, \"\")\n\n    case :ets.lookup(set, {:def, {name, arity}}) do\n      [{_key, kind, meta, _, _, _}] ->\n        clauses =\n          if options[:skip_clauses],\n            do: [],\n            else: bag_lookup_element(bag, {:clauses, {name, arity}}, 2)\n\n        {:v1, kind, meta, clauses}\n\n      [] ->\n        nil\n    end\n  end\n\n  @doc \"\"\"\n  Deletes a definition from a module.\n\n  It returns `true` if the definition exists and it was removed,\n  otherwise it returns `false`.\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec delete_definition(module, definition) :: boolean()\n  def delete_definition(module, {name, arity})\n      when is_atom(module) and is_atom(name) and is_integer(arity) do\n    assert_not_compiled!(__ENV__.function, module, :writeable)\n    :elixir_def.take_definition(module, {name, arity}) != false\n  end\n\n  @doc \"\"\"\n  Makes the given functions in `module` overridable.\n\n  An overridable function is lazily defined, allowing a\n  developer to customize it. See `Kernel.defoverridable/1` for\n  more information and documentation.\n\n  Once a function or a macro is marked as overridable, it will\n  no longer be listed under `definitions_in/1` or return true\n  when given to `defines?/2` until another implementation is\n  given.\n  \"\"\"\n  @spec make_overridable(module, [definition]) :: :ok\n  def make_overridable(module, tuples) when is_atom(module) and is_list(tuples) do\n    assert_not_compiled!(__ENV__.function, module, :writeable)\n\n    func = fn\n      {function_name, arity} = tuple\n      when is_atom(function_name) and is_integer(arity) and arity >= 0 and arity <= 255 ->\n        case :elixir_def.take_definition(module, tuple) do\n          false ->\n            raise ArgumentError,\n                  \"cannot make function #{function_name}/#{arity} \" <>\n                    \"overridable because it was not defined\"\n\n          clause ->\n            :elixir_overridable.record_overridable(module, tuple, clause)\n        end\n\n      other ->\n        raise ArgumentError,\n              \"each element in tuple list has to be a \" <>\n                \"{function_name :: atom, arity :: 0..255} tuple, got: #{inspect(other)}\"\n    end\n\n    :lists.foreach(func, tuples)\n  end\n\n  @spec make_overridable(module, module) :: :ok\n  def make_overridable(module, behaviour) when is_atom(module) and is_atom(behaviour) do\n    {_, bag} = data_tables_for!(module, __ENV__.function, \"\")\n\n    case check_module_for_overridable(bag, behaviour) do\n      :ok ->\n        :ok\n\n      {:error, error_explanation} ->\n        raise ArgumentError,\n              \"cannot pass module #{inspect(behaviour)} as argument \" <>\n                \"to defoverridable/1 because #{error_explanation}\"\n    end\n\n    behaviour_callbacks = Module.Behaviour.callbacks(behaviour)\n\n    tuples =\n      for definition <- definitions_in(module),\n          definition in behaviour_callbacks,\n          do: definition\n\n    make_overridable(module, tuples)\n  end\n\n  defp check_module_for_overridable(bag, behaviour) do\n    behaviour_definitions = bag_lookup_element(bag, {:accumulate, :behaviour}, 2)\n\n    cond do\n      not Code.ensure_loaded?(behaviour) ->\n        {:error, \"it was not defined\"}\n\n      not function_exported?(behaviour, :behaviour_info, 1) ->\n        {:error, \"it does not define any callbacks\"}\n\n      behaviour not in behaviour_definitions ->\n        error_message =\n          \"its corresponding behaviour is missing. Did you forget to \" <>\n            \"add @behaviour #{inspect(behaviour)}?\"\n\n        {:error, error_message}\n\n      true ->\n        :ok\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if `tuple` in `module` was marked as overridable\n  at some point.\n\n  Note `overridable?/2` returns `true` even if the definition was\n  already overridden. You can use `defines?/2` to see if a definition\n  exists or one is pending.\n  \"\"\"\n  @spec overridable?(module, definition) :: boolean\n  def overridable?(module, {function_name, arity} = tuple)\n      when is_atom(function_name) and is_integer(arity) and arity >= 0 and arity <= 255 do\n    :elixir_overridable.overridable_for(module, tuple) != :not_overridable\n  end\n\n  @doc \"\"\"\n  Puts a module attribute with `key` and `value` in the given `module`.\n\n  ## Examples\n\n      defmodule MyModule do\n        Module.put_attribute(__MODULE__, :custom_threshold_for_lib, 10)\n      end\n\n  \"\"\"\n  @spec put_attribute(module, atom, term) :: :ok\n  def put_attribute(module, key, value) when is_atom(module) and is_atom(key) do\n    __put_attribute__(module, key, value, nil, [])\n  end\n\n  @doc \"\"\"\n  Gets the given attribute from a module.\n\n  If the attribute was marked with `accumulate` with\n  `Module.register_attribute/3`, a list is always returned.\n  `nil` is returned if the attribute has not been marked with\n  `accumulate` and has not been set to any value.\n\n  The `@` macro compiles to a call to this function. For example,\n  the following code:\n\n      @foo\n\n  Expands to something akin to:\n\n      Module.get_attribute(__MODULE__, :foo)\n\n  This function can only be used on modules that have not yet been compiled.\n  Use the `c:Module.__info__/1` callback to get all persisted attributes, or\n  `Code.fetch_docs/1` to retrieve all documentation related attributes in\n  compiled modules.\n\n  ## Examples\n\n      defmodule Foo do\n        Module.put_attribute(__MODULE__, :value, 1)\n        Module.get_attribute(__MODULE__, :value) #=> 1\n\n        Module.get_attribute(__MODULE__, :value, :default) #=> 1\n        Module.get_attribute(__MODULE__, :not_found, :default) #=> :default\n\n        Module.register_attribute(__MODULE__, :value, accumulate: true)\n        Module.put_attribute(__MODULE__, :value, 1)\n        Module.get_attribute(__MODULE__, :value) #=> [1]\n      end\n\n  \"\"\"\n  @spec get_attribute(module, atom, term) :: term\n  def get_attribute(module, key, default \\\\ nil) when is_atom(module) and is_atom(key) do\n    get_attribute(module, key, nil, true, false, default, {:get_attribute, 2})\n  end\n\n  @doc \"\"\"\n  Gets the last set value of a given attribute from a module.\n\n  If the attribute was marked with `accumulate` with\n  `Module.register_attribute/3`, the previous value to have been set will be\n  returned. If the attribute does not accumulate, this call is the same as\n  calling `Module.get_attribute/3`.\n\n  This function can only be used on modules that have not yet been compiled.\n  Use the `c:Module.__info__/1` callback to get all persisted attributes, or\n  `Code.fetch_docs/1` to retrieve all documentation related attributes in\n  compiled modules.\n\n  ## Examples\n\n      defmodule Foo do\n        Module.put_attribute(__MODULE__, :value, 1)\n        Module.get_last_attribute(__MODULE__, :value) #=> 1\n\n        Module.get_last_attribute(__MODULE__, :not_found, :default) #=> :default\n\n        Module.register_attribute(__MODULE__, :acc, accumulate: true)\n        Module.put_attribute(__MODULE__, :acc, 1)\n        Module.get_last_attribute(__MODULE__, :acc) #=> 1\n        Module.put_attribute(__MODULE__, :acc, 2)\n        Module.get_last_attribute(__MODULE__, :acc) #=> 2\n      end\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec get_last_attribute(module, atom, term) :: term\n  def get_last_attribute(module, key, default \\\\ nil) when is_atom(module) and is_atom(key) do\n    get_attribute(module, key, nil, true, true, default, {:get_last_attribute, 2})\n  end\n\n  @doc \"\"\"\n  Checks if the given attribute has been defined.\n\n  An attribute is defined if it has been registered with `register_attribute/3`\n  or assigned a value. If an attribute has been deleted with `delete_attribute/2`\n  it is no longer considered defined.\n\n  This function can only be used on modules that have not yet been compiled.\n\n  ## Examples\n\n      defmodule MyModule do\n        @value 1\n        Module.register_attribute(__MODULE__, :other_value)\n        Module.put_attribute(__MODULE__, :another_value, 1)\n\n        Module.has_attribute?(__MODULE__, :value) #=> true\n        Module.has_attribute?(__MODULE__, :other_value) #=> true\n        Module.has_attribute?(__MODULE__, :another_value) #=> true\n\n        Module.has_attribute?(__MODULE__, :undefined) #=> false\n\n        Module.delete_attribute(__MODULE__, :value)\n        Module.has_attribute?(__MODULE__, :value) #=> false\n      end\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec has_attribute?(module, atom) :: boolean\n  def has_attribute?(module, key) when is_atom(module) and is_atom(key) do\n    {set, _bag} = data_tables_for!(module, __ENV__.function, \"\")\n    :ets.member(set, key)\n  end\n\n  @doc \"\"\"\n  Deletes the entry (or entries) for the given module attribute.\n\n  It returns the deleted attribute value. If the attribute has not\n  been set nor configured to accumulate, it returns `nil`.\n\n  If the attribute is set to accumulate, then this function always\n  returns a list. Deleting the attribute removes existing entries\n  but the attribute will still accumulate.\n\n  ## Examples\n\n      defmodule MyModule do\n        Module.put_attribute(__MODULE__, :custom_threshold_for_lib, 10)\n        Module.delete_attribute(__MODULE__, :custom_threshold_for_lib)\n      end\n\n  \"\"\"\n  @spec delete_attribute(module, atom) :: term\n  def delete_attribute(module, key) when is_atom(module) and is_atom(key) do\n    {set, bag} = data_tables_for!(module, __ENV__.function, \"\")\n\n    case :ets.lookup(set, key) do\n      [{_, _, :accumulate, traces}] ->\n        trace_attribute(true, module, traces, set, key, nil, [])\n        reverse_values(:ets.take(bag, {:accumulate, key}), [])\n\n      [{_, value, _, traces}] ->\n        trace_attribute(module, key, nil, traces)\n        :ets.delete(set, key)\n        value\n\n      [] ->\n        nil\n    end\n  end\n\n  defp reverse_values([{_, value} | tail], acc), do: reverse_values(tail, [value | acc])\n  defp reverse_values([], acc), do: acc\n\n  @doc \"\"\"\n  Registers an attribute.\n\n  By registering an attribute, a developer is able to customize\n  how Elixir will store and accumulate the attribute values.\n\n  ## Options\n\n  When registering an attribute, two options can be given:\n\n    * `:accumulate` - several calls to the same attribute will\n      accumulate instead of overriding the previous one. New attributes\n      are always added to the top of the accumulated list.\n\n    * `:persist` - the attribute will be persisted in the Erlang\n      Abstract Format. Useful when interfacing with Erlang libraries.\n\n  By default, both options are `false`. Once an attribute has been\n  set to accumulate or persist, the behaviour cannot be reverted.\n\n  ## Examples\n\n      defmodule MyModule do\n        Module.register_attribute(__MODULE__, :custom_threshold_for_lib, accumulate: true)\n\n        @custom_threshold_for_lib 10\n        @custom_threshold_for_lib 20\n        @custom_threshold_for_lib #=> [20, 10]\n      end\n\n  \"\"\"\n  @spec register_attribute(module, atom, [{:accumulate, boolean}, {:persist, boolean}]) :: :ok\n  def register_attribute(module, attribute, options)\n      when is_atom(module) and is_atom(attribute) and is_list(options) do\n    {set, bag} = data_tables_for!(module, __ENV__.function, \"\")\n\n    if Keyword.get(options, :persist) do\n      :ets.insert(bag, {:persisted_attributes, attribute})\n    end\n\n    if Keyword.get(options, :accumulate) do\n      :ets.insert_new(set, {attribute, [], :accumulate, []}) ||\n        :ets.update_element(set, attribute, {3, :accumulate})\n    else\n      :ets.insert_new(bag, {:warn_attributes, attribute})\n      :ets.insert_new(set, {attribute, nil, :unset, []})\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Splits the given module name into binary parts.\n\n  `module` has to be an Elixir module, as `split/1` won't work with Erlang-style\n  modules (for example, `split(:lists)` raises an error).\n\n  `split/1` also supports splitting the string representation of Elixir modules\n  (that is, the result of calling `Atom.to_string/1` with the module name).\n\n  ## Examples\n\n      iex> Module.split(Very.Long.Module.Name.And.Even.Longer)\n      [\"Very\", \"Long\", \"Module\", \"Name\", \"And\", \"Even\", \"Longer\"]\n      iex> Module.split(\"Elixir.String.Chars\")\n      [\"String\", \"Chars\"]\n\n  \"\"\"\n  @spec split(module | String.t()) :: [String.t(), ...]\n  def split(module)\n\n  def split(module) when is_atom(module) do\n    split(Atom.to_string(module), _original = module)\n  end\n\n  def split(module) when is_binary(module) do\n    split(module, _original = module)\n  end\n\n  defp split(\"Elixir.\" <> name, _original) do\n    String.split(name, \".\")\n  end\n\n  defp split(_module, original) do\n    raise ArgumentError, \"expected an Elixir module, got: #{inspect(original)}\"\n  end\n\n  @doc false\n  @deprecated \"Use @doc instead\"\n  def add_doc(module, line, kind, {name, arity}, signature \\\\ [], doc) do\n    if kind in [:defp, :defmacrop, :typep] do\n      if doc, do: {:error, :private_doc}, else: :ok\n    else\n      {set, _bag} = data_tables_for!(module, __ENV__.function, \"\")\n      compile_doc(set, nil, line, kind, name, arity, signature, nil, doc, %{}, __ENV__, false)\n      :ok\n    end\n  end\n\n  @doc false\n  # Used internally to compile documentation.\n  # This function is private and must be used only internally.\n  def compile_definition_attributes(env, kind, name, args, _guards, body) do\n    %{module: module} = env\n    {set, bag} = data_tables_for!(module, __ENV__.function, \"\")\n    {arity, defaults} = args_count(args, 0, 0)\n\n    context = Keyword.get(:ets.lookup_element(set, {:def, {name, arity}}, 3), :context)\n    impl = compile_impl(set, bag, context, name, env, kind, arity, defaults)\n    doc_meta = compile_doc_meta(set, bag, name, arity, defaults)\n\n    {line, doc} = get_doc_info(set, env)\n    compile_doc(set, context, line, kind, name, arity, args, body, doc, doc_meta, env, impl)\n\n    :ok\n  end\n\n  defp compile_doc(_table, _ctx, line, kind, name, arity, _args, _body, doc, _meta, env, _impl)\n       when kind in [:defp, :defmacrop] do\n    if doc do\n      message =\n        \"#{kind} #{name}/#{arity} is private, \" <>\n          \"@doc attribute is always discarded for private functions/macros/types\"\n\n      IO.warn(message, %{env | line: line})\n    end\n  end\n\n  defp compile_doc(table, ctx, line, kind, name, arity, args, body, doc, doc_meta, env, impl) do\n    key = {doc_key(kind), name, arity}\n    signature = build_signature(args, env)\n\n    case :ets.lookup(table, key) do\n      [] ->\n        doc = if is_nil(doc) && impl, do: false, else: doc\n        :ets.insert(table, {key, ctx, line, signature, doc, doc_meta})\n\n      [{_, current_ctx, current_line, current_sign, current_doc, current_doc_meta}] ->\n        if is_binary(current_doc) and is_binary(doc) and body != nil and is_nil(current_ctx) do\n          message = ~s'''\n          redefining @doc attribute previously set at line #{current_line}.\n\n          Please remove the duplicate docs. If instead you want to override a \\\n          previously defined @doc, attach the @doc attribute to a function head \\\n          (the function signature not followed by any do-block). For example:\n\n              @doc \"\"\"\n              new docs\n              \"\"\"\n              def #{name}(...)\n          '''\n\n          IO.warn(message, %{env | line: line})\n        end\n\n        signature = merge_signatures(current_sign, signature, 1)\n        doc = if is_nil(doc), do: current_doc, else: doc\n        doc = if is_nil(doc) && impl, do: false, else: doc\n        doc_meta = Map.merge(current_doc_meta, doc_meta)\n        :ets.insert(table, {key, ctx, current_line, signature, doc, doc_meta})\n    end\n  end\n\n  defp doc_key(:def), do: :function\n  defp doc_key(:defmacro), do: :macro\n\n  defp compile_doc_meta(set, bag, name, arity, defaults) do\n    doc_meta = compile_deprecated(%{}, set, bag, name, arity, defaults)\n    doc_meta = get_doc_meta(doc_meta, set)\n    add_defaults_count(doc_meta, defaults)\n  end\n\n  defp get_doc_meta(existing_meta, set) do\n    case :ets.take(set, {:doc, :meta}) do\n      [{{:doc, :meta}, metadata}] -> Map.merge(existing_meta, metadata)\n      [] -> existing_meta\n    end\n  end\n\n  defp compile_deprecated(doc_meta, set, bag, name, arity, defaults) do\n    case :ets.take(set, :deprecated) do\n      [{:deprecated, reason, _, _}] when is_binary(reason) ->\n        :ets.insert(bag, deprecated_reasons(defaults, name, arity, reason))\n        Map.put(doc_meta, :deprecated, reason)\n\n      _ ->\n        doc_meta\n    end\n  end\n\n  defp add_defaults_count(doc_meta, 0), do: doc_meta\n  defp add_defaults_count(doc_meta, n), do: Map.put(doc_meta, :defaults, n)\n\n  defp deprecated_reasons(0, name, arity, reason) do\n    [deprecated_reason(name, arity, reason)]\n  end\n\n  defp deprecated_reasons(defaults, name, arity, reason) do\n    [\n      deprecated_reason(name, arity - defaults, reason)\n      | deprecated_reasons(defaults - 1, name, arity, reason)\n    ]\n  end\n\n  defp deprecated_reason(name, arity, reason),\n    do: {:deprecated, {{name, arity}, reason}}\n\n  defp compile_impl(set, bag, context, name, env, kind, arity, defaults) do\n    %{line: line, file: file} = env\n\n    case :ets.take(set, :impl) do\n      [{:impl, value, _, _}] ->\n        impl = {{name, arity}, context, defaults, kind, line, file, value}\n        :ets.insert(bag, {:impls, impl})\n        value\n\n      [] ->\n        false\n    end\n  end\n\n  defp args_count([{:\\\\, _, _} | tail], total, defaults) do\n    args_count(tail, total + 1, defaults + 1)\n  end\n\n  defp args_count([_head | tail], total, defaults) do\n    args_count(tail, total + 1, defaults)\n  end\n\n  defp args_count([], total, defaults), do: {total, defaults}\n\n  @doc false\n  def __check_attributes__(env, set, bag) do\n    check_derive(env, set, bag)\n\n    behaviours = bag_lookup_element(bag, {:accumulate, :behaviour}, 2)\n    force_behaviour_dependencies(behaviours, env)\n\n    :ok\n  end\n\n  defp check_derive(env, set, bag) do\n    case bag_lookup_element(bag, {:accumulate, :derive}, 2) do\n      [] ->\n        :ok\n\n      _ ->\n        message =\n          case :ets.lookup(set, {:elixir, :struct}) do\n            [] ->\n              \"warning: module attribute @derive was set but never used (it must come before defstruct)\"\n\n            _ ->\n              \"warning: module attribute @derive was set after defstruct, all @derive calls must come before defstruct\"\n          end\n\n        IO.warn(message, env)\n    end\n  end\n\n  # While `@behaviour MyBehaviour` will naturally introduce a runtime dependency,\n  # `@behaviour :\"Elixir.MyBehaviour\"` or similar would not.\n  # We force this dependency by adding the call to `MyBehaviour.behaviour_info/1`\n  defp force_behaviour_dependencies(behaviours, env) do\n    info_env = %{env | function: {:__info__, 1}}\n\n    for behaviour <- behaviours do\n      :elixir_env.trace({:remote_function, [], behaviour, :behaviour_info, 1}, info_env)\n    end\n\n    :ok\n  end\n\n  @doc false\n  # Used internally by Kernel's @.\n  # This function is private and must be used only internally.\n  def __get_attribute__(module, key, caller_line, trace?) when is_atom(key) do\n    get_attribute(module, key, caller_line, trace?, false, nil, {:get_attribute, 2})\n  end\n\n  defp get_attribute(\n         module,\n         key,\n         caller_line,\n         trace?,\n         last_accumulated?,\n         default,\n         function_name_arity\n       ) do\n    {set, bag} =\n      data_tables_for!(\n        module,\n        function_name_arity,\n        \"Use the Module.__info__/1 callback or Code.fetch_docs/1 instead\"\n      )\n\n    case :ets.lookup(set, key) do\n      [{_, _, :unset, _}] ->\n        default\n\n      [{_, _, :accumulate, traces}] ->\n        trace_attribute(trace?, module, traces, set, key, caller_line, [])\n        lookup_accumulate_attribute(bag, key, default, last_accumulated?)\n\n      [{_, value, warn_line, traces}] when is_integer(warn_line) ->\n        trace_attribute(trace?, module, traces, set, key, caller_line, [{3, :used}])\n        value\n\n      [{_, value, _, traces}] ->\n        trace_attribute(trace?, module, traces, set, key, caller_line, [])\n        value\n\n      [] when is_integer(caller_line) ->\n        # TODO: Consider raising instead of warning on v2.0 as it usually cascades\n        error_message =\n          \"undefined module attribute @#{key}, \" <>\n            \"please remove access to @#{key} or explicitly set it before access\"\n\n        IO.warn(error_message, attribute_stack(module, caller_line))\n        default\n\n      [] ->\n        default\n    end\n  end\n\n  defp lookup_accumulate_attribute(bag, key, _default, false) do\n    :lists.reverse(bag_lookup_element(bag, {:accumulate, key}, 2))\n  end\n\n  defp lookup_accumulate_attribute(bag, key, default, true) do\n    case :ets.select(bag, [{{{:accumulate, key}, :\"$1\"}, [], [:\"$1\"]}], 1) do\n      {[value], _} -> value\n      _ -> default\n    end\n  end\n\n  defp trace_attribute(module, key, caller_line, traces) do\n    :lists.foreach(\n      fn {line, lexical_tracker, tracers, aliases} ->\n        line = caller_line || line\n\n        env = %{\n          Macro.Env.__struct__()\n          | line: line,\n            file: \"@#{key}\",\n            lexical_tracker: lexical_tracker,\n            module: module,\n            tracers: tracers\n        }\n\n        :lists.foreach(\n          fn alias ->\n            :elixir_env.trace({:alias_reference, [line: line], alias}, env)\n          end,\n          aliases\n        )\n      end,\n      traces\n    )\n  end\n\n  defp trace_attribute(trace?, module, traces, set, key, caller_line, updates) do\n    updates =\n      if trace? and traces != [] do\n        trace_attribute(module, key, caller_line, traces)\n        updates ++ [{4, []}]\n      else\n        updates\n      end\n\n    case updates do\n      [] -> :ok\n      _ -> :ets.update_element(set, key, updates)\n    end\n\n    :ok\n  end\n\n  @doc false\n  # Used internally by Kernel's @.\n  # This function is private and must be used only internally.\n  def __put_attribute__(module, key, value, warn_line, traces) when is_atom(key) do\n    assert_not_compiled!({:put_attribute, 3}, module, :writeable)\n    {set, bag} = data_tables_for!(module, {:put_attribute, 3}, \"\")\n    put_attribute(module, key, value, warn_line, traces, set, bag)\n    :ok\n  end\n\n  defp put_attribute(_module, :on_load, value, warn_line, traces, set, bag) do\n    value =\n      case value do\n        _ when is_atom(value) ->\n          {value, 0}\n\n        {atom, 0} = tuple when is_atom(atom) ->\n          tuple\n\n        _ ->\n          raise ArgumentError,\n                \"@on_load is a built-in module attribute that annotates a function to be invoked \" <>\n                  \"when the module is loaded. It should be an atom or an {atom, 0} tuple, \" <>\n                  \"got: #{inspect(value)}\"\n      end\n\n    try do\n      :ets.lookup_element(set, :on_load, 3)\n    catch\n      :error, :badarg ->\n        :ets.insert(set, {:on_load, value, warn_line, traces})\n        :ets.insert(bag, {:warn_attributes, :on_load})\n    else\n      _ -> raise ArgumentError, \"the @on_load attribute can only be set once per module\"\n    end\n  end\n\n  # If any of the doc attributes are called with a keyword list that\n  # will become documentation metadata. Multiple calls will be merged\n  # into the same map overriding duplicate keys.\n  defp put_attribute(module, key, {_, metadata}, warn_line, _traces, set, _bag)\n       when key in [:doc, :typedoc, :moduledoc] and is_list(metadata) do\n    metadata_map = preprocess_doc_meta(metadata, module, warn_line, %{})\n\n    case :ets.insert_new(set, {{key, :meta}, metadata_map}) do\n      true ->\n        :ok\n\n      false ->\n        current_metadata = :ets.lookup_element(set, {key, :meta}, 2)\n        :ets.update_element(set, {key, :meta}, {2, Map.merge(current_metadata, metadata_map)})\n    end\n  end\n\n  # Optimize some attributes by avoiding writing to the attributes key\n  # in the bag table since we handle them internally.\n  defp put_attribute(module, key, value, warn_line, traces, set, _bag)\n       when key in [:doc, :typedoc, :moduledoc, :impl, :deprecated] do\n    value = preprocess_attribute(key, value)\n\n    try do\n      :ets.lookup_element(set, key, 3)\n    catch\n      :error, :badarg -> :ok\n    else\n      unread_line when is_integer(warn_line) and is_integer(unread_line) ->\n        message = \"redefining @#{key} attribute previously set at line #{unread_line}\"\n        IO.warn(message, attribute_stack(module, warn_line))\n\n      _ ->\n        :ok\n    end\n\n    :ets.insert(set, {key, value, warn_line, traces})\n  end\n\n  defp put_attribute(_module, key, value, warn_line, traces, set, bag) do\n    value = preprocess_attribute(key, value)\n\n    try do\n      :ets.lookup_element(set, key, 3)\n    catch\n      :error, :badarg ->\n        :ets.insert(set, {key, value, warn_line, traces})\n        :ets.insert(bag, {:warn_attributes, key})\n    else\n      :accumulate ->\n        if traces != [] do\n          :ets.update_element(set, key, {4, traces ++ :ets.lookup_element(set, key, 4)})\n        end\n\n        :ets.insert(bag, {{:accumulate, key}, value})\n\n      _ ->\n        :ets.insert(set, {key, value, warn_line, traces})\n    end\n  end\n\n  defp attribute_stack(module, line) do\n    struct!(Macro.Env, module: module, file: :elixir_module.file(module), line: line)\n  end\n\n  ## Helpers\n\n  defp preprocess_attribute(key, value) when key in [:moduledoc, :typedoc, :doc] do\n    case value do\n      {line, doc} when is_integer(line) and (is_binary(doc) or doc == false or is_nil(doc)) ->\n        value\n\n      {line, doc} when is_integer(line) ->\n        raise ArgumentError,\n              \"@#{key} is a built-in module attribute for documentation. It should be either \" <>\n                \"false, nil, a string, or a keyword list, got: #{inspect(doc)}\"\n\n      _other ->\n        raise ArgumentError,\n              \"@#{key} is a built-in module attribute for documentation. When set dynamically, \" <>\n                \"it should be {line, doc} (where \\\"doc\\\" is either false, nil, a string, or a keyword list), \" <>\n                \"got: #{inspect(value)}\"\n    end\n  end\n\n  defp preprocess_attribute(:behaviour, value) do\n    if is_atom(value) do\n      Code.ensure_compiled(value)\n      value\n    else\n      raise ArgumentError, \"@behaviour expects a module, got: #{inspect(value)}\"\n    end\n  end\n\n  defp preprocess_attribute(:impl, value) do\n    if is_boolean(value) or (is_atom(value) and value != nil) do\n      value\n    else\n      raise ArgumentError,\n            \"@impl is a built-in module attribute that marks the next definition \" <>\n              \"as a callback implementation. It should be a module or a boolean, \" <>\n              \"got: #{inspect(value)}\"\n    end\n  end\n\n  defp preprocess_attribute(:before_compile, atom) when is_atom(atom),\n    do: {atom, :__before_compile__}\n\n  defp preprocess_attribute(:after_compile, atom) when is_atom(atom),\n    do: {atom, :__after_compile__}\n\n  defp preprocess_attribute(:after_verify, atom) when is_atom(atom),\n    do: {atom, :__after_verify__}\n\n  defp preprocess_attribute(:on_definition, atom) when is_atom(atom),\n    do: {atom, :__on_definition__}\n\n  defp preprocess_attribute(key, _value)\n       when key in [:type, :typep, :opaque, :spec, :callback, :macrocallback] do\n    raise ArgumentError,\n          \"attributes type, typep, opaque, spec, callback, and macrocallback \" <>\n            \"must be set directly via the @ notation\"\n  end\n\n  defp preprocess_attribute(:external_resource, value) when not is_binary(value) do\n    raise ArgumentError,\n          \"@external_resource is a built-in module attribute used for specifying file \" <>\n            \"dependencies. It should be a string path to a file, got: #{inspect(value)}\"\n  end\n\n  defp preprocess_attribute(:deprecated, value) when not is_binary(value) do\n    raise ArgumentError,\n          \"@deprecated is a built-in module attribute that annotates a definition as deprecated. \" <>\n            \"It should be a string with the reason for the deprecation, got: #{inspect(value)}\"\n  end\n\n  defp preprocess_attribute(:file, value) do\n    case value do\n      _ when is_binary(value) ->\n        value\n\n      {file, line} when is_binary(file) and is_integer(line) ->\n        value\n\n      _ ->\n        raise ArgumentError,\n              \"@file is a built-in module attribute that annotates the file and line the next \" <>\n                \"definition comes from. It should be a string or {string, line} tuple as value, \" <>\n                \"got: #{inspect(value)}\"\n    end\n  end\n\n  defp preprocess_attribute(:nifs, value) do\n    if not function_arity_list?(value) do\n      raise ArgumentError,\n            \"@nifs is a built-in module attribute for specifying a list \" <>\n              \"of functions and their arities that are NIFs, got: #{inspect(value)}\"\n    end\n\n    value\n  end\n\n  defp preprocess_attribute(:dialyzer, value) do\n    # From https://github.com/erlang/otp/blob/master/lib/stdlib/src/erl_lint.erl\n    :lists.foreach(\n      fn attr ->\n        if not valid_dialyzer_attribute?(attr) do\n          raise ArgumentError, \"invalid value for @dialyzer attribute: #{inspect(attr)}\"\n        end\n      end,\n      List.wrap(value)\n    )\n\n    value\n  end\n\n  defp preprocess_attribute(_key, value) do\n    value\n  end\n\n  defp function_arity_list?(fun_arities) do\n    is_list(fun_arities) and\n      :lists.all(\n        fn\n          {fun, arity} when is_atom(fun) and is_integer(arity) -> true\n          _ -> false\n        end,\n        fun_arities\n      )\n  end\n\n  defp valid_dialyzer_attribute?({key, fun_arities}) when is_atom(key) do\n    (key == :nowarn_function or valid_dialyzer_attribute?(key)) and\n      function_arity_list?(List.wrap(fun_arities))\n  end\n\n  defp valid_dialyzer_attribute?(attr) do\n    :lists.member(\n      attr,\n      [:no_return, :no_unused, :no_improper_lists, :no_fun_app] ++\n        [:no_match, :no_opaque, :no_fail_call, :no_contracts] ++\n        [:no_behaviours, :no_undefined_callbacks, :unmatched_returns] ++\n        [:error_handling, :race_conditions, :no_missing_calls] ++\n        [:specdiffs, :overspecs, :underspecs, :unknown, :no_underspecs] ++\n        [:extra_return, :no_extra_return, :no_missing_return] ++\n        [:missing_return, :no_unknown]\n    )\n  end\n\n  defp preprocess_doc_meta([], _module, _line, map), do: map\n\n  defp preprocess_doc_meta([{key, _} | tail], module, line, map)\n       when key in [:opaque, :defaults] do\n    message = \"ignoring reserved documentation metadata key: #{inspect(key)}\"\n    IO.warn(message, attribute_stack(module, line))\n    preprocess_doc_meta(tail, module, line, map)\n  end\n\n  defp preprocess_doc_meta([{key, value} | tail], module, line, map) when is_atom(key) do\n    validate_doc_meta(key, value)\n    preprocess_doc_meta(tail, module, line, Map.put(map, key, value))\n  end\n\n  defp validate_doc_meta(:since, value) when not is_binary(value) do\n    raise ArgumentError,\n          \":since is a built-in documentation metadata key. It should be a string representing \" <>\n            \"the version in which the documented entity was added, got: #{inspect(value)}\"\n  end\n\n  defp validate_doc_meta(:deprecated, value) when not is_binary(value) do\n    raise ArgumentError,\n          \":deprecated is a built-in documentation metadata key. It should be a string \" <>\n            \"representing the replacement for the deprecated entity, got: #{inspect(value)}\"\n  end\n\n  defp validate_doc_meta(:delegate_to, value) do\n    case value do\n      {m, f, a} when is_atom(m) and is_atom(f) and is_integer(a) and a >= 0 ->\n        :ok\n\n      _ ->\n        raise ArgumentError,\n              \":delegate_to is a built-in documentation metadata key. It should be a three-element \" <>\n                \"tuple in the form of {module, function, arity}, got: #{inspect(value)}\"\n    end\n  end\n\n  defp validate_doc_meta(_, _), do: :ok\n\n  defp get_doc_info(table, env) do\n    case :ets.take(table, :doc) do\n      [{:doc, {_, _} = pair, _, _}] ->\n        pair\n\n      [] ->\n        {env.line, nil}\n    end\n  end\n\n  defp data_tables_for!(module, function_name_arity, message) do\n    try do\n      :elixir_module.data_tables(module)\n    catch\n      :error, :badarg ->\n        raise ArgumentError, assert_not_compiled_message(function_name_arity, module, message)\n    end\n  end\n\n  defp bag_lookup_element(table, key, pos) do\n    :ets.lookup_element(table, key, pos)\n  catch\n    :error, :badarg -> []\n  end\n\n  defp assert_not_compiled!({function_name, arity}, module, mode) do\n    case :elixir_module.mode(module) do\n      :all ->\n        :ok\n\n      :readonly when mode == :all ->\n        :ok\n\n      :readonly when mode == :writeable ->\n        raise ArgumentError,\n              \"could not call Module.#{function_name}/#{arity} because the module \" <>\n                \"#{inspect(module)} is in read-only mode (@after_compile)\"\n\n      :closed ->\n        raise ArgumentError,\n              assert_not_compiled_message({function_name, arity}, module, \"\")\n    end\n  end\n\n  defp assert_not_compiled_message({function_name, arity}, module, extra_msg) do\n    mfa = \"Module.#{function_name}/#{arity}\"\n\n    \"could not call #{mfa} because the module #{inspect(module)} is already compiled\" <>\n      case extra_msg do\n        \"\" -> \"\"\n        _ -> \". \" <> extra_msg\n      end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/node.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Node do\n  @moduledoc \"\"\"\n  Functions related to VM nodes.\n\n  Some of the functions in this module are inlined by the compiler,\n  similar to functions in the `Kernel` module and they are explicitly\n  marked in their docs as \"inlined by the compiler\". For more information\n  about inlined functions, check out the `Kernel` module.\n  \"\"\"\n\n  @type t :: node\n\n  @doc \"\"\"\n  Turns a non-distributed node into a distributed node.\n\n  This functionality starts the `:net_kernel` and other related\n  processes.\n\n  This function is rarely invoked in practice. Instead, nodes are\n  named and started via the command line by using the `--sname` and\n  `--name` flags. If you need to use this function to dynamically\n  name a node, please make sure the `epmd` operating system process\n  is running by calling `epmd -daemon`, such as `System.cmd(\"epmd\", [\"-daemon\"])`.\n\n  Invoking this function when the distribution has already been started,\n  either via the command line interface or dynamically, will return an\n  error.\n\n  ## Examples\n\n      {:ok, pid} = Node.start(:example, name_domain: :shortnames, hidden: true)\n\n  ## Options\n\n  Currently supported options are:\n\n  * `:name_domain` - determines the host name part of the node name. If `:longnames`,\n    fully qualified domain names will be   used which also is the default.\n    If `:shortnames`, only the short name of the host will be used.\n\n  * `:net_ticktime` - The tick time to use in seconds. Defaults to the value of the\n    `net_ticktime` configuration under Erlang's `kernel` application.\n    See [the `kernel` documentation](https://www.erlang.org/doc/apps/kernel/kernel_app.html)\n    for more information.\n\n  * `net_tickintensity` - The tick intensity to use. Defaults to the value of the\n    `net_tickintensity` configuration under Erlang's `kernel` application.\n    See [the `kernel` documentation](https://www.erlang.org/doc/apps/kernel/kernel_app.html)\n    for more information.\n\n  * `:dist_listen` - Enable or disable listening for incoming connections.\n    Defaults to the value given to the `--erl` flag, otherwise it defaults to `true`.\n    Note that `dist_listen: false` implies `hidden: true`.\n\n  * `:hidden` - Enable or disable hidden node. Defaults to `true` if the `--hidden`\n    flag is given to `elixir`'s CLI (or via the `--erl` flag), otherwise it\n    defaults to `false`.\n\n  If `name` is set to `:undefined`, the distribution will be started to request a\n  dynamic node name from the first node it connects to. Setting `name` to\n  `:undefined` also implies options `dist_listen: false, hidden: true`.\n  \"\"\"\n  @spec start(node,\n          name_domain: :shortnames | :longnames,\n          net_ticktime: pos_integer(),\n          net_tickintensity: 4..1000,\n          dist_listen: boolean(),\n          hidden: boolean()\n        ) :: {:ok, pid} | {:error, term}\n  def start(name, opts \\\\ [])\n\n  def start(name, opts) when is_list(opts) do\n    :net_kernel.start(name, Map.new(opts))\n  end\n\n  # TODO: Deprecate me on Elixir v1.23\n  def start(name, type) when is_atom(type) do\n    :net_kernel.start([name, type, 15_000])\n  end\n\n  # TODO: Deprecate me on Elixir v1.23\n  @doc false\n  def start(name, type, tick_time) do\n    :net_kernel.start([name, type, tick_time])\n  end\n\n  @doc \"\"\"\n  Turns a distributed node into a non-distributed node.\n\n  For other nodes in the network, this is the same as the node going down.\n  Only possible when the node was started with `Node.start/2`, otherwise\n  returns `{:error, :not_allowed}`. Returns `{:error, :not_found}` if the\n  local node is not alive.\n  \"\"\"\n  @spec stop() :: :ok | {:error, :not_allowed | :not_found}\n  def stop() do\n    :net_kernel.stop()\n  end\n\n  @doc \"\"\"\n  Returns the current node.\n\n  It returns the same as the built-in `node()`.\n  \"\"\"\n  @spec self :: t\n  def self do\n    :erlang.node()\n  end\n\n  @doc \"\"\"\n  Returns `true` if the local node is alive.\n\n  That is, if the node can be part of a distributed system.\n  \"\"\"\n  @spec alive? :: boolean\n  def alive? do\n    :erlang.is_alive()\n  end\n\n  @doc \"\"\"\n  Returns a list of all visible nodes in the system, excluding\n  the local node.\n\n  Same as `list(:visible)`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec list :: [t]\n  def list do\n    :erlang.nodes()\n  end\n\n  @doc \"\"\"\n  Returns a list of nodes according to argument given.\n\n  The result returned when the argument is a list, is the list of nodes\n  satisfying the disjunction(s) of the list elements.\n\n  For more information, see `:erlang.nodes/1`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @type state :: :visible | :hidden | :connected | :this | :known\n  @spec list(state | [state]) :: [t]\n  def list(args) do\n    :erlang.nodes(args)\n  end\n\n  @doc \"\"\"\n  Monitors the status of the node.\n\n  If `flag` is `true`, monitoring is turned on.\n  If `flag` is `false`, monitoring is turned off.\n\n  For more information, see `:erlang.monitor_node/2`.\n\n  For monitoring status changes of all nodes, see `:net_kernel.monitor_nodes/2`.\n  \"\"\"\n  @spec monitor(t, boolean) :: true\n  def monitor(node, flag) do\n    :erlang.monitor_node(node, flag)\n  end\n\n  @doc \"\"\"\n  Behaves as `monitor/2` except that it allows an extra\n  option to be given, namely `:allow_passive_connect`.\n\n  For more information, see `:erlang.monitor_node/3`.\n\n  For monitoring status changes of all nodes, see `:net_kernel.monitor_nodes/2`.\n  \"\"\"\n  @spec monitor(t, boolean, [:allow_passive_connect]) :: true\n  def monitor(node, flag, options) do\n    :erlang.monitor_node(node, flag, options)\n  end\n\n  @doc \"\"\"\n  Tries to set up a connection to node.\n\n  Returns `:pang` if it fails, or `:pong` if it is successful.\n\n  ## Examples\n\n      iex> Node.ping(:unknown_node)\n      :pang\n\n  \"\"\"\n  @spec ping(t) :: :pong | :pang\n  def ping(node) do\n    :net_adm.ping(node)\n  end\n\n  @doc \"\"\"\n  Forces the disconnection of a node.\n\n  This will appear to the `node` as if the local node has crashed.\n  This function is mainly used in the Erlang network authentication\n  protocols. Returns `true` if disconnection succeeds, otherwise `false`.\n  If the local node is not alive, the function returns `:ignored`.\n\n  For more information, see `:erlang.disconnect_node/1`.\n  \"\"\"\n  @spec disconnect(t) :: boolean | :ignored\n  def disconnect(node) do\n    :erlang.disconnect_node(node)\n  end\n\n  @doc \"\"\"\n  Establishes a connection to `node`.\n\n  Returns `true` if successful, `false` if not, and the atom\n  `:ignored` if the local node is not alive.\n\n  For more information, see `:net_kernel.connect_node/1`.\n  \"\"\"\n  @spec connect(t) :: boolean | :ignored\n  def connect(node) do\n    :net_kernel.connect_node(node)\n  end\n\n  @doc \"\"\"\n  Returns the PID of a new process started by the application of `fun`\n  on `node`. If `node` does not exist, a useless PID is returned.\n\n  For the list of available options, see `:erlang.spawn/2`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec spawn(t, (-> any)) :: pid\n  def spawn(node, fun) do\n    :erlang.spawn(node, fun)\n  end\n\n  @doc \"\"\"\n  Returns the PID of a new process started by the application of `fun`\n  on `node`.\n\n  If `node` does not exist, a useless PID is returned.\n\n  For the list of available options, see `:erlang.spawn_opt/3`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec spawn(t, (-> any), Process.spawn_opts()) :: pid | {pid, reference}\n  def spawn(node, fun, opts) do\n    :erlang.spawn_opt(node, fun, opts)\n  end\n\n  @doc \"\"\"\n  Returns the PID of a new process started by the application of\n  `module.function(args)` on `node`.\n\n  If `node` does not exist, a useless PID is returned.\n\n  For the list of available options, see `:erlang.spawn/4`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec spawn(t, module, atom, [any]) :: pid\n  def spawn(node, module, fun, args) do\n    :erlang.spawn(node, module, fun, args)\n  end\n\n  @doc \"\"\"\n  Returns the PID of a new process started by the application of\n  `module.function(args)` on `node`.\n\n  If `node` does not exist, a useless PID is returned.\n\n  For the list of available options, see `:erlang.spawn_opt/5`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec spawn(t, module, atom, [any], Process.spawn_opts()) :: pid | {pid, reference}\n  def spawn(node, module, fun, args, opts) do\n    :erlang.spawn_opt(node, module, fun, args, opts)\n  end\n\n  @doc \"\"\"\n  Returns the PID of a new linked process started by the application of `fun` on `node`.\n\n  A link is created between the calling process and the new process, atomically.\n  If `node` does not exist, a useless PID is returned (and due to the link, an exit\n  signal with exit reason `:noconnection` will be received).\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec spawn_link(t, (-> any)) :: pid\n  def spawn_link(node, fun) do\n    :erlang.spawn_link(node, fun)\n  end\n\n  @doc \"\"\"\n  Returns the PID of a new linked process started by the application of\n  `module.function(args)` on `node`.\n\n  A link is created between the calling process and the new process, atomically.\n  If `node` does not exist, a useless PID is returned (and due to the link, an exit\n  signal with exit reason `:noconnection` will be received).\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec spawn_link(t, module, atom, [any]) :: pid\n  def spawn_link(node, module, fun, args) do\n    :erlang.spawn_link(node, module, fun, args)\n  end\n\n  @doc \"\"\"\n  Spawns the given function on a node, monitors it and returns its PID\n  and monitoring reference.\n\n  Inlined by the compiler.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec spawn_monitor(t, (-> any)) :: {pid, reference}\n  def spawn_monitor(node, fun) do\n    :erlang.spawn_monitor(node, fun)\n  end\n\n  @doc \"\"\"\n  Spawns the given module and function passing the given args on a node,\n  monitors it and returns its PID and monitoring reference.\n\n  Inlined by the compiler.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec spawn_monitor(t, module, atom, [any]) :: {pid, reference}\n  def spawn_monitor(node, module, fun, args) do\n    :erlang.spawn_monitor(node, module, fun, args)\n  end\n\n  @doc \"\"\"\n  Sets the magic cookie of `node` to the atom `cookie`.\n\n  The default node is `Node.self/0`, the local node. If `node` is the local node,\n  the function also sets the cookie of all other unknown nodes to `cookie`.\n\n  This function will raise `FunctionClauseError` if the given `node` is not alive.\n  \"\"\"\n  @spec set_cookie(t, atom) :: true\n  def set_cookie(node \\\\ Node.self(), cookie) when is_atom(cookie) do\n    :erlang.set_cookie(node, cookie)\n  end\n\n  @doc \"\"\"\n  Returns the magic cookie of the local node.\n\n  Returns the cookie if the node is alive, otherwise `:nocookie`.\n  \"\"\"\n  @spec get_cookie() :: atom\n  def get_cookie() do\n    :erlang.get_cookie()\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/option_parser.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule OptionParser do\n  @moduledoc \"\"\"\n  Functions for parsing command line arguments.\n\n  When calling a command, it's possible to pass command line options\n  to modify what the command does. In this documentation, those are\n  called \"switches\", in other situations they may be called \"flags\"\n  or simply \"options\". A switch can be given a value, also called an\n  \"argument\".\n\n  The main function in this module is `parse/2`, which parses a list\n  of command line options and arguments into a keyword list:\n\n      iex> OptionParser.parse([\"--debug\"], strict: [debug: :boolean])\n      {[debug: true], [], []}\n\n  `OptionParser` provides some conveniences out of the box,\n  such as aliases and automatic handling of negation switches.\n\n  The `parse_head/2` function is an alternative to `parse/2`\n  which stops parsing as soon as it finds a value that is not\n  a switch nor a value for a previous switch.\n\n  This module also provides low-level functions, such as `next/2`,\n  for parsing switches manually, as well as `split/1` and `to_argv/1`\n  for parsing from and converting switches to strings.\n  \"\"\"\n\n  @type argv :: [String.t()]\n  @type parsed :: keyword\n  @type errors :: [{String.t(), String.t() | nil}]\n  @type options :: [\n          switches: keyword,\n          strict: keyword,\n          aliases: keyword,\n          allow_nonexistent_atoms: boolean,\n          return_separator: boolean\n        ]\n\n  defmodule ParseError do\n    @moduledoc \"\"\"\n    An exception raised when parsing option fails.\n\n    For example, see `OptionParser.parse!/2`.\n    \"\"\"\n\n    defexception [:message]\n  end\n\n  @doc \"\"\"\n  Parses `argv` into a keyword list.\n\n  It returns a three-element tuple with the form `{parsed, args, invalid}`, where:\n\n    * `parsed` is a keyword list of parsed switches with `{switch_name, value}`\n      tuples in it; `switch_name` is the atom representing the switch name while\n      `value` is the value for that switch parsed according to `opts` (see the\n      \"Examples\" section for more information)\n    * `args` is a list of the remaining arguments in `argv` as strings\n    * `invalid` is a list of invalid options as `{option_name, value}` where\n      `option_name` is the raw option and `value` is `nil` if the option wasn't\n      expected or the string value if the value didn't have the expected type for\n      the corresponding option\n\n  Elixir converts switches to underscored atoms, so `--source-path` becomes\n  `:source_path`. This is done to better suit Elixir conventions. However, this\n  means that switches can't contain underscores and switches that do contain\n  underscores are always returned in the list of invalid switches.\n\n  When parsing, it is common to list switches and their expected types:\n\n      iex> OptionParser.parse([\"--debug\"], strict: [debug: :boolean])\n      {[debug: true], [], []}\n\n      iex> OptionParser.parse([\"--source\", \"lib\"], strict: [source: :string])\n      {[source: \"lib\"], [], []}\n\n      iex> OptionParser.parse(\n      ...>   [\"--source-path\", \"lib\", \"test/enum_test.exs\", \"--verbose\"],\n      ...>   strict: [source_path: :string, verbose: :boolean]\n      ...> )\n      {[source_path: \"lib\", verbose: true], [\"test/enum_test.exs\"], []}\n\n  We will explore the valid switches and operation modes of option parser below.\n\n  ## Options\n\n  The following options are supported:\n\n    * `:switches` or `:strict` - see the \"Switch definitions\" section below\n    * `:allow_nonexistent_atoms` - see the \"Parsing unknown switches\" section below\n    * `:aliases` - see the \"Aliases\" section below\n    * `:return_separator` - see the \"Return separator\" section below\n\n  ## Switch definitions\n\n  Switches can be specified via one of two options:\n\n    * `:strict` - defines strict switches and their types. Any switch\n      in `argv` that is not specified in the list is returned in the\n      invalid options list. This is the preferred way to parse options.\n\n    * `:switches` - defines switches and their types. This function\n      still attempts to parse switches that are not in this list.\n\n  Both these options accept a keyword list where the key is an atom\n  defining the name of the switch and value is the `type` of the\n  switch (see the \"Types\" section below for more information).\n\n  Note that you should only supply the `:switches` or the `:strict` option.\n  If you supply both, an `ArgumentError` exception will be raised.\n\n  ### Types\n\n  Switches parsed by `OptionParser` may take zero or one arguments.\n\n  The following switches types take no arguments:\n\n    * `:boolean` - sets the value to `true` when given (see also the\n      \"Negation switches\" section below)\n    * `:count` - counts the number of times the switch is given\n\n  The following switches take one argument:\n\n    * `:integer` - parses the value as an integer\n    * `:float` - parses the value as a float\n    * `:string` - parses the value as a string\n    * `:regex` - parses the value as a regular expression with Unicode support\n\n  If a switch can't be parsed according to the given type, it is\n  returned in the invalid options list.\n\n  ### Modifiers\n\n  Switches can be specified with modifiers, which change how\n  they behave. The following modifiers are supported:\n\n    * `:keep` - keeps duplicate elements instead of overriding them;\n      works with all types except `:count`. Specifying `switch_name: :keep`\n      assumes the type of `:switch_name` will be `:string`.\n\n  To use `:keep` with a type other than `:string`, use a list as the type\n  for the switch. For example: `[foo: [:integer, :keep]]`.\n\n  ### Negation switches\n\n  In case a switch `SWITCH` is specified to have type `:boolean`, it may be\n  passed as `--no-SWITCH` as well which will set the option to `false`:\n\n      iex> OptionParser.parse([\"--no-op\", \"path/to/file\"], switches: [op: :boolean])\n      {[op: false], [\"path/to/file\"], []}\n\n  ### Parsing unknown switches\n\n  When the `:switches` option is given, `OptionParser` will attempt to parse\n  unknown switches.\n\n  Switches without an argument will be set to `true`:\n\n      iex> OptionParser.parse([\"--debug\"], switches: [key: :string])\n      {[debug: true], [], []}\n\n  Even though we haven't specified `--debug` in the list of switches, it is part\n  of the returned options. The same happens for switches followed by another switch:\n\n      iex> OptionParser.parse([\"--debug\", \"--ok\"], switches: [])\n      {[debug: true, ok: true], [], []}\n\n  Switches followed by a value will be assigned the value, as a string:\n\n      iex> OptionParser.parse([\"--debug\", \"value\"], switches: [key: :string])\n      {[debug: \"value\"], [], []}\n\n  Since we cannot assert the type of the switch value, it is preferred to use the\n  `:strict` option that accepts only known switches and always verify their types.\n\n  If you do want to parse unknown switches, remember that Elixir converts switches\n  to atoms. Since atoms are not garbage-collected, to avoid creating new ones,\n  OptionParser by default only parses switches that translate to existing atoms.\n  The code below discards the `--option-parser-example` switch because the\n  `:option_parser_example` atom is never used anywhere:\n\n      iex> OptionParser.parse([\"--option-parser-example\"], switches: [])\n      {[], [], []}\n\n  If a switch corresponds to an existing Elixir atom, whether from your\n  code, a dependency or from Elixir itself, it will be accepted. However,\n  it is best to not rely on external code, and always define the atoms\n  you want to parse in the same module that calls `OptionParser` itself,\n  as direct arguments to the `:switches` or `:strict` options.\n\n  If you would like to parse all switches, regardless if they exist or not,\n  you can force creation of atoms by passing `allow_nonexistent_atoms: true`\n  as option. Use this option with care. It is only useful when you are building\n  command-line applications that receive dynamically-named arguments and must\n  be avoided in long-running systems.\n\n  ## Aliases\n\n  A set of aliases can be specified in the `:aliases` option:\n\n      iex> OptionParser.parse([\"-d\"], aliases: [d: :debug], strict: [debug: :boolean])\n      {[debug: true], [], []}\n\n  ## Examples\n\n  Here are some examples of working with different types and modifiers:\n\n      iex> OptionParser.parse([\"--unlock\", \"path/to/file\"], strict: [unlock: :boolean])\n      {[unlock: true], [\"path/to/file\"], []}\n\n      iex> OptionParser.parse(\n      ...>   [\"--unlock\", \"--limit\", \"0\", \"path/to/file\"],\n      ...>   strict: [unlock: :boolean, limit: :integer]\n      ...> )\n      {[unlock: true, limit: 0], [\"path/to/file\"], []}\n\n      iex> OptionParser.parse([\"--limit\", \"3\"], strict: [limit: :integer])\n      {[limit: 3], [], []}\n\n      iex> OptionParser.parse([\"--limit\", \"xyz\"], strict: [limit: :integer])\n      {[], [], [{\"--limit\", \"xyz\"}]}\n\n      iex> OptionParser.parse([\"--verbose\"], switches: [verbose: :count])\n      {[verbose: 1], [], []}\n\n      iex> OptionParser.parse([\"-v\", \"-v\"], aliases: [v: :verbose], strict: [verbose: :count])\n      {[verbose: 2], [], []}\n\n      iex> OptionParser.parse([\"--unknown\", \"xyz\"], strict: [])\n      {[], [\"xyz\"], [{\"--unknown\", nil}]}\n\n      iex> OptionParser.parse(\n      ...>   [\"--limit\", \"3\", \"--unknown\", \"xyz\"],\n      ...>   switches: [limit: :integer]\n      ...> )\n      {[limit: 3, unknown: \"xyz\"], [], []}\n\n      iex> OptionParser.parse(\n      ...>   [\"--unlock\", \"path/to/file\", \"--unlock\", \"path/to/another/file\"],\n      ...>   strict: [unlock: :keep]\n      ...> )\n      {[unlock: \"path/to/file\", unlock: \"path/to/another/file\"], [], []}\n\n  ## Return separator\n\n  The separator `--` implies options should no longer be processed.\n  By default, the separator is not returned as parts of the arguments,\n  but that can be changed via the `:return_separator` option:\n\n      iex> OptionParser.parse([\"--\", \"lib\"], return_separator: true, strict: [])\n      {[], [\"--\", \"lib\"], []}\n\n      iex> OptionParser.parse([\"--no-halt\", \"--\", \"lib\"], return_separator: true, switches: [halt: :boolean])\n      {[halt: false], [\"--\", \"lib\"], []}\n\n      iex> OptionParser.parse([\"script.exs\", \"--no-halt\", \"--\", \"foo\"], return_separator: true, switches: [halt: :boolean])\n      {[{:halt, false}], [\"script.exs\", \"--\", \"foo\"], []}\n\n  \"\"\"\n  @spec parse(argv, options) :: {parsed, argv, errors}\n  def parse(argv, opts \\\\ []) when is_list(argv) and is_list(opts) do\n    do_parse(argv, build_config(opts), [], [], [], true)\n  end\n\n  @doc \"\"\"\n  The same as `parse/2` but raises an `OptionParser.ParseError`\n  exception if any invalid options are given.\n\n  If there are no errors, returns a `{parsed, rest}` tuple where:\n\n    * `parsed` is the list of parsed switches (same as in `parse/2`)\n    * `rest` is the list of arguments (same as in `parse/2`)\n\n  ## Examples\n\n      iex> OptionParser.parse!([\"--debug\", \"path/to/file\"], strict: [debug: :boolean])\n      {[debug: true], [\"path/to/file\"]}\n\n      iex> OptionParser.parse!([\"--limit\", \"xyz\"], strict: [limit: :integer])\n      ** (OptionParser.ParseError) 1 error found!\n      --limit : Expected type integer, got \"xyz\"...\n\n      iex> OptionParser.parse!([\"--unknown\", \"xyz\"], strict: [])\n      ** (OptionParser.ParseError) 1 error found!\n      --unknown : Unknown option...\n\n      iex> OptionParser.parse!(\n      ...>   [\"-l\", \"xyz\", \"-f\", \"bar\"],\n      ...>   switches: [limit: :integer, foo: :integer],\n      ...>   aliases: [l: :limit, f: :foo]\n      ...> )\n      ** (OptionParser.ParseError) 2 errors found!\n      -l : Expected type integer, got \"xyz\"\n      -f : Expected type integer, got \"bar\"...\n\n  \"\"\"\n  @spec parse!(argv, options) :: {parsed, argv}\n  def parse!(argv, opts \\\\ []) when is_list(argv) and is_list(opts) do\n    case parse(argv, opts) do\n      {parsed, args, []} -> {parsed, args}\n      {_, _, errors} -> raise ParseError, format_errors(errors, opts)\n    end\n  end\n\n  @doc \"\"\"\n  Similar to `parse/2` but only parses the head of `argv`;\n  as soon as it finds a non-switch, it stops parsing.\n\n  See `parse/2` for more information.\n\n  ## Example\n\n      iex> OptionParser.parse_head(\n      ...>   [\"--source\", \"lib\", \"test/enum_test.exs\", \"--verbose\"],\n      ...>   switches: [source: :string, verbose: :boolean]\n      ...> )\n      {[source: \"lib\"], [\"test/enum_test.exs\", \"--verbose\"], []}\n\n      iex> OptionParser.parse_head(\n      ...>   [\"--verbose\", \"--source\", \"lib\", \"test/enum_test.exs\", \"--unlock\"],\n      ...>   switches: [source: :string, verbose: :boolean, unlock: :boolean]\n      ...> )\n      {[verbose: true, source: \"lib\"], [\"test/enum_test.exs\", \"--unlock\"], []}\n\n  \"\"\"\n  @spec parse_head(argv, options) :: {parsed, argv, errors}\n  def parse_head(argv, opts \\\\ []) when is_list(argv) and is_list(opts) do\n    do_parse(argv, build_config(opts), [], [], [], false)\n  end\n\n  @doc \"\"\"\n  The same as `parse_head/2` but raises an `OptionParser.ParseError`\n  exception if any invalid options are given.\n\n  If there are no errors, returns a `{parsed, rest}` tuple where:\n\n    * `parsed` is the list of parsed switches (same as in `parse_head/2`)\n    * `rest` is the list of arguments (same as in `parse_head/2`)\n\n  ## Examples\n\n      iex> OptionParser.parse_head!(\n      ...>   [\"--source\", \"lib\", \"path/to/file\", \"--verbose\"],\n      ...>   switches: [source: :string, verbose: :boolean]\n      ...> )\n      {[source: \"lib\"], [\"path/to/file\", \"--verbose\"]}\n\n      iex> OptionParser.parse_head!(\n      ...>   [\"--number\", \"lib\", \"test/enum_test.exs\", \"--verbose\"],\n      ...>   strict: [number: :integer]\n      ...> )\n      ** (OptionParser.ParseError) 1 error found!\n      --number : Expected type integer, got \"lib\"...\n\n      iex> OptionParser.parse_head!(\n      ...>   [\"--verbose\", \"--source\", \"lib\", \"test/enum_test.exs\", \"--unlock\"],\n      ...>   strict: [verbose: :integer, source: :integer]\n      ...> )\n      ** (OptionParser.ParseError) 2 errors found!\n      --verbose : Missing argument of type integer\n      --source : Expected type integer, got \"lib\"...\n\n  \"\"\"\n  @spec parse_head!(argv, options) :: {parsed, argv}\n  def parse_head!(argv, opts \\\\ []) when is_list(argv) and is_list(opts) do\n    case parse_head(argv, opts) do\n      {parsed, args, []} -> {parsed, args}\n      {_, _, errors} -> raise ParseError, format_errors(errors, opts)\n    end\n  end\n\n  defp do_parse([], _config, opts, args, invalid, _all?) do\n    {Enum.reverse(opts), Enum.reverse(args), Enum.reverse(invalid)}\n  end\n\n  defp do_parse(argv, %{switches: switches} = config, opts, args, invalid, all?) do\n    case next_with_config(argv, config) do\n      {:ok, option, value, rest} ->\n        # the option exists and it was successfully parsed\n        kinds = List.wrap(Keyword.get(switches, option))\n        new_opts = store_option(opts, option, value, kinds)\n        do_parse(rest, config, new_opts, args, invalid, all?)\n\n      {:invalid, option, value, rest} ->\n        # the option exist but it has wrong value\n        do_parse(rest, config, opts, args, [{option, value} | invalid], all?)\n\n      {:undefined, option, _value, rest} ->\n        invalid = if config.strict?, do: [{option, nil} | invalid], else: invalid\n        do_parse(rest, config, opts, args, invalid, all?)\n\n      {:error, [\"--\" | rest] = remaining_args} ->\n        args =\n          if config.return_separator? do\n            Enum.reverse(args, remaining_args)\n          else\n            Enum.reverse(args, rest)\n          end\n\n        {Enum.reverse(opts), args, Enum.reverse(invalid)}\n\n      {:error, [arg | rest] = remaining_args} ->\n        # there is no option\n        if all? do\n          do_parse(rest, config, opts, [arg | args], invalid, all?)\n        else\n          {Enum.reverse(opts), Enum.reverse(args, remaining_args), Enum.reverse(invalid)}\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Low-level function that parses one option.\n\n  It accepts the same options as `parse/2` and `parse_head/2`\n  as both functions are built on top of this function. This function\n  may return:\n\n    * `{:ok, key, value, rest}` - the option `key` with `value` was\n      successfully parsed\n\n    * `{:invalid, key, value, rest}` - the option `key` is invalid with `value`\n      (returned when the value cannot be parsed according to the switch type)\n\n    * `{:undefined, key, value, rest}` - the option `key` is undefined\n      (returned in strict mode when the switch is unknown or on nonexistent atoms)\n\n    * `{:error, rest}` - there are no switches at the head of the given `argv`\n\n  \"\"\"\n  @spec next(argv, options) ::\n          {:ok, key :: atom, value :: term, argv}\n          | {:invalid, String.t(), String.t() | nil, argv}\n          | {:undefined, String.t(), String.t() | nil, argv}\n          | {:error, argv}\n\n  def next(argv, opts \\\\ []) when is_list(argv) and is_list(opts) do\n    next_with_config(argv, build_config(opts))\n  end\n\n  defp next_with_config([], _config) do\n    {:error, []}\n  end\n\n  defp next_with_config([\"--\" | _] = argv, _config) do\n    {:error, argv}\n  end\n\n  defp next_with_config([\"-\" | _] = argv, _config) do\n    {:error, argv}\n  end\n\n  defp next_with_config([\"- \" <> _ | _] = argv, _config) do\n    {:error, argv}\n  end\n\n  # Handles --foo or --foo=bar\n  defp next_with_config([\"--\" <> option | rest], config) do\n    {option, value} = split_option(option)\n\n    if String.contains?(option, [\"_\"]) do\n      {:undefined, \"--\" <> option, value, rest}\n    else\n      tagged = tag_option(option, config)\n      next_tagged(tagged, value, \"--\" <> option, rest, config)\n    end\n  end\n\n  # Handles -a, -abc, -abc=something, -n2\n  defp next_with_config([\"-\" <> option | rest] = argv, config) do\n    {option, value} = split_option(option)\n    original = \"-\" <> option\n\n    cond do\n      is_nil(value) and starts_with_number?(option) ->\n        {:error, argv}\n\n      String.contains?(option, [\"-\", \"_\"]) ->\n        {:undefined, original, value, rest}\n\n      String.length(option) == 1 ->\n        # We have a regular one-letter alias here\n        tagged = tag_oneletter_alias(option, config)\n        next_tagged(tagged, value, original, rest, config)\n\n      true ->\n        key = get_option_key(option, config.allow_nonexistent_atoms?)\n        option_key = config.aliases[key]\n\n        if key && option_key do\n          IO.warn(\"multi-letter aliases are deprecated, got: #{inspect(key)}\")\n          next_tagged({:default, option_key}, value, original, rest, config)\n        else\n          next_with_config(expand_multiletter_alias(option, value) ++ rest, config)\n        end\n    end\n  end\n\n  defp next_with_config(argv, _config) do\n    {:error, argv}\n  end\n\n  defp next_tagged(:unknown, value, original, rest, _) do\n    {value, _kinds, rest} = normalize_value(value, [], rest)\n    {:undefined, original, value, rest}\n  end\n\n  defp next_tagged({tag, option}, value, original, rest, %{switches: switches, strict?: strict?}) do\n    if strict? and not Keyword.has_key?(switches, option) do\n      {:undefined, original, value, rest}\n    else\n      {kinds, value} = normalize_tag(tag, option, value, switches)\n      {value, kinds, rest} = normalize_value(value, kinds, rest)\n\n      case validate_option(value, kinds) do\n        {:ok, new_value} -> {:ok, option, new_value, rest}\n        :invalid -> {:invalid, original, value, rest}\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Receives a key-value enumerable and converts it to `t:argv/0`.\n\n  Keys must be atoms. Keys with `nil` value are discarded,\n  boolean values are converted to `--key` or `--no-key`\n  (if the value is `true` or `false`, respectively),\n  and all other values are converted using `to_string/1`.\n\n  It is advised to pass to `to_argv/2` the same set of `options`\n  given to `parse/2`. Some switches can only be reconstructed\n  correctly with the `:switches` information in hand.\n\n  ## Examples\n\n      iex> OptionParser.to_argv(foo_bar: \"baz\")\n      [\"--foo-bar\", \"baz\"]\n      iex> OptionParser.to_argv(bool: true, bool: false, discarded: nil)\n      [\"--bool\", \"--no-bool\"]\n\n  Some switches will output different values based on the switches\n  types:\n\n      iex> OptionParser.to_argv([number: 2], switches: [])\n      [\"--number\", \"2\"]\n      iex> OptionParser.to_argv([number: 2], switches: [number: :count])\n      [\"--number\", \"--number\"]\n\n  \"\"\"\n  @spec to_argv(Enumerable.t(), options) :: argv\n  def to_argv(enum, options \\\\ []) do\n    switches = Keyword.get(options, :switches, [])\n\n    Enum.flat_map(enum, fn\n      {_key, nil} -> []\n      {key, true} -> [to_switch(key)]\n      {key, false} -> [to_switch(key, \"--no-\")]\n      {key, value} -> to_argv(key, value, switches)\n    end)\n  end\n\n  defp to_argv(key, value, switches) do\n    if switches[key] == :count do\n      List.duplicate(to_switch(key), value)\n    else\n      [to_switch(key), to_string(value)]\n    end\n  end\n\n  defp to_switch(key, prefix \\\\ \"--\") when is_atom(key) do\n    prefix <> String.replace(Atom.to_string(key), \"_\", \"-\")\n  end\n\n  @doc ~S\"\"\"\n  Splits a string into `t:argv/0` chunks.\n\n  This function splits the given `string` into a list of strings in a similar\n  way to many shells.\n\n  ## Examples\n\n      iex> OptionParser.split(\"foo bar\")\n      [\"foo\", \"bar\"]\n\n      iex> OptionParser.split(\"foo \\\"bar baz\\\"\")\n      [\"foo\", \"bar baz\"]\n\n  \"\"\"\n  @spec split(String.t()) :: argv\n  def split(string) when is_binary(string) do\n    do_split(String.trim_leading(string, \" \"), \"\", [], nil)\n  end\n\n  # If we have an escaped quote, simply remove the escape\n  defp do_split(<<?\\\\, quote, t::binary>>, buffer, acc, quote),\n    do: do_split(t, <<buffer::binary, quote>>, acc, quote)\n\n  # If we have a quote and we were not in a quote, start one\n  defp do_split(<<quote, t::binary>>, buffer, acc, nil) when quote in [?\", ?'],\n    do: do_split(t, buffer, acc, quote)\n\n  # If we have a quote and we were inside it, close it\n  defp do_split(<<quote, t::binary>>, buffer, acc, quote), do: do_split(t, buffer, acc, nil)\n\n  # If we have an escaped quote/space, simply remove the escape as long as we are not inside a quote\n  defp do_split(<<?\\\\, h, t::binary>>, buffer, acc, nil) when h in [?\\s, ?', ?\"],\n    do: do_split(t, <<buffer::binary, h>>, acc, nil)\n\n  # If we have space and we are outside of a quote, start new segment\n  defp do_split(<<?\\s, t::binary>>, buffer, acc, nil),\n    do: do_split(String.trim_leading(t, \" \"), \"\", [buffer | acc], nil)\n\n  # All other characters are moved to buffer\n  defp do_split(<<h, t::binary>>, buffer, acc, quote) do\n    do_split(t, <<buffer::binary, h>>, acc, quote)\n  end\n\n  # Finish the string expecting a nil marker\n  defp do_split(<<>>, \"\", acc, nil), do: Enum.reverse(acc)\n\n  defp do_split(<<>>, buffer, acc, nil), do: Enum.reverse([buffer | acc])\n\n  # Otherwise raise\n  defp do_split(<<>>, _, _acc, marker) do\n    raise \"argv string did not terminate properly, a #{<<marker>>} was opened but never closed\"\n  end\n\n  ## Helpers\n\n  defp build_config(opts) do\n    {switches, strict?} =\n      cond do\n        opts[:switches] && opts[:strict] ->\n          raise ArgumentError, \":switches and :strict cannot be given together\"\n\n        switches = opts[:switches] ->\n          validate_switches(switches)\n          {switches, false}\n\n        strict = opts[:strict] ->\n          validate_switches(strict)\n          {strict, true}\n\n        true ->\n          IO.warn(\"not passing the :switches or :strict option to OptionParser is deprecated\")\n          {[], false}\n      end\n\n    %{\n      aliases: opts[:aliases] || [],\n      allow_nonexistent_atoms?: opts[:allow_nonexistent_atoms] || false,\n      return_separator?: opts[:return_separator] || false,\n      strict?: strict?,\n      switches: switches\n    }\n  end\n\n  defp validate_switches(switches) do\n    Enum.map(switches, &validate_switch/1)\n  end\n\n  defp validate_switch({_name, type_or_type_and_modifiers}) do\n    valid = [:boolean, :count, :integer, :float, :string, :regex, :keep]\n    invalid = List.wrap(type_or_type_and_modifiers) -- valid\n\n    if invalid != [] do\n      raise ArgumentError,\n            \"invalid switch types/modifiers: \" <> Enum.map_join(invalid, \", \", &inspect/1)\n    end\n  end\n\n  defp validate_option(value, kinds) do\n    {invalid?, value} =\n      cond do\n        :invalid in kinds ->\n          {true, value}\n\n        :boolean in kinds ->\n          case value do\n            t when t in [true, \"true\"] -> {false, true}\n            f when f in [false, \"false\"] -> {false, false}\n            _ -> {true, value}\n          end\n\n        :count in kinds ->\n          case value do\n            nil -> {false, 1}\n            _ -> {true, value}\n          end\n\n        :integer in kinds ->\n          case Integer.parse(value) do\n            {value, \"\"} -> {false, value}\n            _ -> {true, value}\n          end\n\n        :float in kinds ->\n          case Float.parse(value) do\n            {value, \"\"} -> {false, value}\n            _ -> {true, value}\n          end\n\n        :regex in kinds ->\n          case Regex.compile(value, \"u\") do\n            {:ok, regex} -> {false, regex}\n            {:error, _} -> {true, value}\n          end\n\n        true ->\n          {false, value}\n      end\n\n    if invalid? do\n      :invalid\n    else\n      {:ok, value}\n    end\n  end\n\n  defp store_option(dict, option, value, kinds) do\n    cond do\n      :count in kinds ->\n        Keyword.update(dict, option, value, &(&1 + 1))\n\n      :keep in kinds ->\n        [{option, value} | dict]\n\n      true ->\n        [{option, value} | Keyword.delete(dict, option)]\n    end\n  end\n\n  defp tag_option(\"no-\" <> option = original, config) do\n    %{switches: switches, allow_nonexistent_atoms?: allow_nonexistent_atoms?} = config\n\n    cond do\n      (negated = get_option_key(option, allow_nonexistent_atoms?)) &&\n          :boolean in List.wrap(switches[negated]) ->\n        {:negated, negated}\n\n      option_key = get_option_key(original, allow_nonexistent_atoms?) ->\n        {:default, option_key}\n\n      true ->\n        :unknown\n    end\n  end\n\n  defp tag_option(option, config) do\n    %{allow_nonexistent_atoms?: allow_nonexistent_atoms?} = config\n\n    if option_key = get_option_key(option, allow_nonexistent_atoms?) do\n      {:default, option_key}\n    else\n      :unknown\n    end\n  end\n\n  defp tag_oneletter_alias(alias, config) when is_binary(alias) do\n    %{aliases: aliases, allow_nonexistent_atoms?: allow_nonexistent_atoms?} = config\n\n    if option_key = aliases[to_existing_key(alias, allow_nonexistent_atoms?)] do\n      {:default, option_key}\n    else\n      :unknown\n    end\n  end\n\n  defp expand_multiletter_alias(options, value) do\n    {options, maybe_integer} =\n      options\n      |> String.to_charlist()\n      |> Enum.split_while(&(&1 not in ?0..?9))\n\n    {last, expanded} =\n      options\n      |> List.to_string()\n      |> String.graphemes()\n      |> Enum.map(&(\"-\" <> &1))\n      |> List.pop_at(-1)\n\n    expanded ++\n      [\n        last <>\n          if(maybe_integer != [], do: \"=#{maybe_integer}\", else: \"\") <>\n          if(value, do: \"=#{value}\", else: \"\")\n      ]\n  end\n\n  defp normalize_tag(:negated, option, value, switches) do\n    if value do\n      {[:invalid], value}\n    else\n      {List.wrap(switches[option]), false}\n    end\n  end\n\n  defp normalize_tag(:default, option, value, switches) do\n    {List.wrap(switches[option]), value}\n  end\n\n  defp normalize_value(nil, kinds, t) do\n    cond do\n      :boolean in kinds ->\n        {true, kinds, t}\n\n      :count in kinds ->\n        {nil, kinds, t}\n\n      value_in_tail?(t) ->\n        [h | t] = t\n        {h, kinds, t}\n\n      kinds == [] ->\n        {true, kinds, t}\n\n      true ->\n        {nil, [:invalid], t}\n    end\n  end\n\n  defp normalize_value(value, kinds, t) do\n    {value, kinds, t}\n  end\n\n  defp value_in_tail?([\"-\" | _]), do: true\n  defp value_in_tail?([\"- \" <> _ | _]), do: true\n  defp value_in_tail?([\"-\" <> arg | _]), do: starts_with_number?(arg)\n  defp value_in_tail?([]), do: false\n  defp value_in_tail?(_), do: true\n\n  defp split_option(option) do\n    case :binary.split(option, \"=\") do\n      [h] -> {h, nil}\n      [h, t] -> {h, t}\n    end\n  end\n\n  defp to_underscore(option), do: to_underscore(option, <<>>)\n  defp to_underscore(\"-\" <> rest, acc), do: to_underscore(rest, acc <> \"_\")\n  defp to_underscore(<<c>> <> rest, acc), do: to_underscore(rest, <<acc::binary, c>>)\n  defp to_underscore(<<>>, acc), do: acc\n\n  defp get_option_key(option, allow_nonexistent_atoms?) do\n    option\n    |> to_underscore()\n    |> to_existing_key(allow_nonexistent_atoms?)\n  end\n\n  defp to_existing_key(option, true), do: String.to_atom(option)\n\n  defp to_existing_key(option, false) do\n    try do\n      String.to_existing_atom(option)\n    rescue\n      ArgumentError -> nil\n    end\n  end\n\n  defp starts_with_number?(<<char, _::binary>>) when char in ?0..?9, do: true\n  defp starts_with_number?(_), do: false\n\n  defp format_errors([_ | _] = errors, opts) do\n    types = opts[:switches] || opts[:strict]\n    error_count = length(errors)\n    error = if error_count == 1, do: \"error\", else: \"errors\"\n\n    slogan =\n      \"#{error_count} #{error} found!\\n\" <>\n        Enum.map_join(errors, \"\\n\", &format_error(&1, opts, types))\n\n    case format_available_options(opts, types) do\n      \"\" -> slogan\n      available_options -> slogan <> \"\\n\\n#{available_options}\"\n    end\n  end\n\n  defp format_error({option, nil}, opts, types) do\n    if type = get_type(option, opts, types) do\n      if String.contains?(option, \"_\") do\n        msg = \"#{option} : Unknown option\"\n        msg <> \". Did you mean #{String.replace(option, \"_\", \"-\")}?\"\n      else\n        \"#{option} : Missing argument of type #{type}\"\n      end\n    else\n      msg = \"#{option} : Unknown option\"\n\n      case did_you_mean(option, types) do\n        {similar, score} when score > 0.8 ->\n          msg <> \". Did you mean --#{similar}?\"\n\n        _ ->\n          msg\n      end\n    end\n  end\n\n  defp format_error({option, value}, opts, types) do\n    type = get_type(option, opts, types)\n\n    with :regex <- type,\n         {:error, {reason, position}} <- Regex.compile(value, \"u\") do\n      \"#{option} : Invalid regular expression #{inspect(value)}: #{reason} at position #{position}\"\n    else\n      _ -> \"#{option} : Expected type #{type}, got #{inspect(value)}\"\n    end\n  end\n\n  defp get_type(option, opts, types) do\n    allow_nonexistent_atoms? = opts[:allow_nonexistent_atoms] || false\n    key = option |> String.trim_leading(\"-\") |> get_option_key(allow_nonexistent_atoms?)\n\n    if option_key = opts[:aliases][key] do\n      types[option_key]\n    else\n      types[key]\n    end\n  end\n\n  defp did_you_mean(option, types) do\n    key = option |> String.trim_leading(\"-\") |> String.replace(\"-\", \"_\")\n    Enum.reduce(types, {nil, 0}, &max_similar(&1, key, &2))\n  end\n\n  defp max_similar({source, _}, target, {_, current} = best) do\n    source = Atom.to_string(source)\n\n    score = String.jaro_distance(source, target)\n    option = String.replace(source, \"_\", \"-\")\n    if score < current, do: best, else: {option, score}\n  end\n\n  defp format_available_options(opts, switches) do\n    reverse_aliases =\n      opts\n      |> Keyword.get(:aliases, [])\n      |> Enum.reduce(%{}, fn {alias, target}, acc ->\n        Map.update(acc, target, [alias], &[alias | &1])\n      end)\n\n    formatted_options =\n      switches\n      |> Enum.sort()\n      |> Enum.map(fn {name, types} ->\n        types = List.wrap(types)\n\n        case types |> List.delete(:keep) |> List.first(:string) do\n          :boolean ->\n            base = \"#{to_switch(name)}, #{to_switch(name, \"--no-\")}\"\n            add_aliases(base, name, reverse_aliases)\n\n          type ->\n            base = \"#{to_switch(name)} #{String.upcase(Atom.to_string(type))}\"\n            base = add_aliases(base, name, reverse_aliases)\n\n            if :keep in types do\n              base <> \" (may be given more than once)\"\n            else\n              base\n            end\n        end\n      end)\n\n    if formatted_options == [] do\n      \"\"\n    else\n      \"Supported options:\\n\" <> Enum.map_join(formatted_options, \"\\n\", &(\"  \" <> &1))\n    end\n  end\n\n  defp add_aliases(base, name, reverse_aliases) do\n    case Map.get(reverse_aliases, name, []) do\n      [] ->\n        base\n\n      alias_list ->\n        alias_str =\n          alias_list\n          |> Enum.sort()\n          |> Enum.map_join(\", \", &(\"-\" <> Atom.to_string(&1)))\n\n        base <> \" (alias: #{alias_str})\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/partition_supervisor.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule PartitionSupervisor do\n  @moduledoc \"\"\"\n  A supervisor that starts multiple partitions of the same child.\n\n  Certain processes may become bottlenecks in large systems.\n  If those processes can have their state trivially partitioned,\n  in a way there is no dependency between them, then they can use\n  the `PartitionSupervisor` to create multiple isolated and\n  independent partitions.\n\n  Once the `PartitionSupervisor` starts, you can dispatch to its\n  children using `{:via, PartitionSupervisor, {name, key}}`, where\n  `name` is the name of the `PartitionSupervisor` and key is used\n  for routing.\n\n  This module was introduced in Elixir v1.14.0.\n\n  ## Simple Example\n\n  Let's start with an example which is not useful per se, but shows how the\n  partitions are started and how messages are routed to them.\n\n  Here's a toy GenServer that simply collects the messages it's given.\n  It prints them for easy illustration.\n\n      defmodule Collector do\n        use GenServer\n\n        def start_link(args) do\n          GenServer.start_link(__MODULE__, args)\n        end\n\n        def init(args) do\n          IO.inspect([__MODULE__, \" got args \", args, \" in \", self()])\n          {:ok, _initial_state = []}\n        end\n\n        def collect(server, msg) do\n          GenServer.call(server, {:collect, msg})\n        end\n\n        def handle_call({:collect, msg}, _from, state) do\n          new_state = [msg | state]\n          IO.inspect([\"current messages:\", new_state, \" in process\", self()])\n          {:reply, :ok, new_state}\n        end\n      end\n\n  To run multiple of these, we can start them under a `PartitionSupervisor` by placing\n  this in our supervision tree:\n\n      {PartitionSupervisor,\n        child_spec: Collector.child_spec([some: :arg]),\n        name: MyApp.PartitionSupervisor\n      }\n\n  We can send messages to them using a \"via tuple\":\n\n      # The key is used to route our message to a particular instance.\n      key = 1\n      Collector.collect({:via, PartitionSupervisor, {MyApp.PartitionSupervisor, key}}, :hi)\n      # [\"current messages:\", [:hi], \" in process\", #PID<0.602.0>]\n      :ok\n      Collector.collect({:via, PartitionSupervisor, {MyApp.PartitionSupervisor, key}}, :ho)\n      # [\"current messages:\", [:ho, :hi], \" in process\", #PID<0.602.0>]\n      :ok\n\n      # With a different key, the message will be routed to a different instance.\n      key = 2\n      Collector.collect({:via, PartitionSupervisor, {MyApp.PartitionSupervisor, key}}, :a)\n      # [\"current messages:\", [:a], \" in process\", #PID<0.603.0>]\n      :ok\n      Collector.collect({:via, PartitionSupervisor, {MyApp.PartitionSupervisor, key}}, :b)\n      # [\"current messages:\", [:b, :a], \" in process\", #PID<0.603.0>]\n      :ok\n\n  Now let's move on to a useful example.\n\n  ## `DynamicSupervisor` Example\n\n  The `DynamicSupervisor` is a single process responsible for starting\n  other processes. In some applications, the `DynamicSupervisor` may\n  become a bottleneck. To address this, you can start multiple instances\n  of the `DynamicSupervisor` through a `PartitionSupervisor`, and then\n  pick a \"random\" instance to start the child on.\n\n  Instead of starting a single `DynamicSupervisor`:\n\n      children = [\n        {DynamicSupervisor, name: MyApp.DynamicSupervisor}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_one)\n\n  and starting children on that dynamic supervisor directly:\n\n      DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Agent, fn -> %{} end})\n\n  You can start the dynamic supervisors under a `PartitionSupervisor`:\n\n      children = [\n        {PartitionSupervisor,\n         child_spec: DynamicSupervisor,\n         name: MyApp.DynamicSupervisors}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_one)\n\n  and then:\n\n      DynamicSupervisor.start_child(\n        {:via, PartitionSupervisor, {MyApp.DynamicSupervisors, self()}},\n        {Agent, fn -> %{} end}\n      )\n\n  In the code above, we start a partition supervisor that will by default\n  start a dynamic supervisor for each core in your machine. Then, instead\n  of calling the `DynamicSupervisor` by name, you call it through the\n  partition supervisor using the `{:via, PartitionSupervisor, {name, key}}`\n  format. We picked `self()` as the routing key, which means each process\n  will be assigned one of the existing dynamic supervisors. See `start_link/1`\n  to see all options supported by the `PartitionSupervisor`.\n\n  ## Implementation notes\n\n  The `PartitionSupervisor` uses either an ETS table or a `Registry` to\n  manage all of the partitions. Under the hood, the `PartitionSupervisor`\n  generates a child spec for each partition and then acts as a regular\n  supervisor. The ID of each child spec is the partition number.\n\n  For routing, two strategies are used. If `key` is an integer, it is routed\n  using `rem(abs(key), partitions)` where `partitions` is the number of\n  partitions. Otherwise it uses `:erlang.phash2(key, partitions)`.\n  The particular routing may change in the future, and therefore must not\n  be relied on. If you want to retrieve a particular PID for a certain key,\n  you can use `GenServer.whereis({:via, PartitionSupervisor, {name, key}})`.\n  \"\"\"\n\n  @moduledoc since: \"1.14.0\"\n\n  @behaviour Supervisor\n\n  @registry PartitionSupervisor.Registry\n\n  @typedoc \"\"\"\n  The name of the `PartitionSupervisor`.\n  \"\"\"\n  @typedoc since: \"1.14.0\"\n  @type name :: atom() | {:via, module(), term()}\n\n  @typedoc \"\"\"\n  The \"identifier\" of a partition.\n  \"\"\"\n  @typedoc since: \"1.19.0\"\n  @type partition() :: non_neg_integer()\n\n  @typedoc \"\"\"\n  The possible options to give to `start_link/0`.\n  \"\"\"\n  @typedoc since: \"1.19.0\"\n  @type start_link_option ::\n          {:name, name}\n          | {:child_spec, Supervisor.child_spec() | Supervisor.module_spec()}\n          | {:partitions, pos_integer()}\n          | {:strategy, Supervisor.strategy()}\n          | {:max_restarts, non_neg_integer()}\n          | {:max_seconds, non_neg_integer()}\n          | {:with_arguments, (args :: [term()], partition() -> updated_args :: [term()])}\n\n  defguardp is_name(name) when is_atom(name) or elem(name, 0) == :via\n\n  @doc false\n  def child_spec(opts) when is_list(opts) do\n    id =\n      case Keyword.get(opts, :name, PartitionSupervisor) do\n        name when is_atom(name) -> name\n        {:via, _module, name} -> name\n      end\n\n    %{\n      id: id,\n      start: {PartitionSupervisor, :start_link, [opts]},\n      type: :supervisor\n    }\n  end\n\n  @doc \"\"\"\n  Starts a partition supervisor with the given options.\n\n  This function is typically not invoked directly, instead it is invoked\n  when using a `PartitionSupervisor` as a child of another supervisor:\n\n      children = [\n        {PartitionSupervisor, child_spec: SomeChild, name: MyPartitionSupervisor}\n      ]\n\n  If the supervisor is successfully spawned, this function returns\n  `{:ok, pid}`, where `pid` is the PID of the supervisor. If the given name\n  for the partition supervisor is already assigned to a process,\n  the function returns `{:error, {:already_started, pid}}`, where `pid`\n  is the PID of that process.\n\n  Note that a supervisor started with this function is linked to the parent\n  process and exits not only on crashes but also if the parent process exits\n  with `:normal` reason.\n\n  ## Options\n\n  See `t:start_link_option/0` for the type of each option.\n\n    * `:name` - an atom or via tuple representing the name of the partition\n      supervisor. *Required*.\n\n    * `:child_spec` - the child spec to be used when starting the partitions. *Required*.\n\n    * `:partitions` - the number of partitions.\n      Defaults to `System.schedulers_online/0` (typically the number of cores).\n\n    * `:strategy` - the restart strategy option.\n      You can learn more about strategies in the `Supervisor` module docs.\n      Defaults to `:one_for_one`.\n\n    * `:max_restarts` - the maximum number of restarts allowed in\n      a time frame. Defaults to `3`.\n\n    * `:max_seconds` - the time frame in which `:max_restarts` applies.\n      Defaults to `5`.\n\n    * `:with_arguments` - a two-argument anonymous function that allows\n      the partition to be given to the child starting function. It takes the list of arguments\n      passed to the child start function and the partition itself, and must return\n      possibly-updated arguments to give to the child start function. See the\n      `:with_arguments` section below.\n\n  ## `:with_arguments`\n\n  Sometimes you want each partition to know their partition assigned number.\n  This can be done with the `:with_arguments` option. This function receives\n  the value of the `:child_spec` option and an integer for the partition\n  number. It must return a new list of arguments that will be used to start the\n  partition process.\n\n  For example, most processes are started by calling `start_link(opts)`,\n  where `opts` is a keyword list. You could inject the partition into the\n  options given to the child:\n\n      with_arguments: fn [opts], partition ->\n        [Keyword.put(opts, :partition, partition)]\n      end\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec start_link([start_link_option()]) :: Supervisor.on_start()\n  def start_link(opts) when is_list(opts) do\n    name = opts[:name]\n\n    if !name do\n      raise ArgumentError, \"the :name option must be given to PartitionSupervisor\"\n    end\n\n    {child_spec, opts} = Keyword.pop(opts, :child_spec)\n\n    if !child_spec do\n      raise ArgumentError, \"the :child_spec option must be given to PartitionSupervisor\"\n    end\n\n    {partitions, opts} = Keyword.pop(opts, :partitions, System.schedulers_online())\n\n    if not (is_integer(partitions) and partitions >= 1) do\n      raise ArgumentError,\n            \"the :partitions option must be a positive integer, got: #{inspect(partitions)}\"\n    end\n\n    {with_arguments, opts} = Keyword.pop(opts, :with_arguments, fn args, _partition -> args end)\n\n    if not is_function(with_arguments, 2) do\n      raise ArgumentError,\n            \"the :with_arguments option must be a function that receives two arguments, \" <>\n              \"the current call arguments and the partition, got: #{inspect(with_arguments)}\"\n    end\n\n    %{start: {mod, fun, args}} = map = Supervisor.child_spec(child_spec, [])\n    modules = map[:modules] || [mod]\n\n    children =\n      for partition <- 0..(partitions - 1) do\n        args = with_arguments.(args, partition)\n\n        if not is_list(args) do\n          raise \"the call to the function in :with_arguments must return a list, got: #{inspect(args)}\"\n        end\n\n        start = {__MODULE__, :start_child, [mod, fun, args, partition]}\n        Map.merge(map, %{id: partition, start: start, modules: modules})\n      end\n\n    auto_shutdown = Keyword.get(opts, :auto_shutdown, :never)\n\n    if auto_shutdown != :never do\n      raise ArgumentError,\n            \"the :auto_shutdown option must be :never, got: #{inspect(auto_shutdown)}\"\n    end\n\n    {init_opts, start_opts} =\n      Keyword.split(opts, [:strategy, :max_seconds, :max_restarts, :auto_shutdown])\n\n    Supervisor.start_link(__MODULE__, {name, partitions, children, init_opts}, start_opts)\n  end\n\n  @doc false\n  def start_child(mod, fun, args, partition) do\n    case apply(mod, fun, args) do\n      {:ok, pid} ->\n        register_child(partition, pid)\n        {:ok, pid}\n\n      {:ok, pid, info} ->\n        register_child(partition, pid)\n        {:ok, pid, info}\n\n      other ->\n        other\n    end\n  end\n\n  defp register_child(partition, pid) do\n    :ets.insert(Process.get(:ets_table), {partition, pid})\n  end\n\n  @impl true\n  def init({name, partitions, children, init_opts}) do\n    table = init_table(name)\n    :ets.insert(table, {:partitions, partitions, partitions})\n    Process.put(:ets_table, table)\n    Supervisor.init(children, Keyword.put_new(init_opts, :strategy, :one_for_one))\n  end\n\n  defp init_table(name) when is_atom(name) do\n    :ets.new(name, [:set, :named_table, :public, read_concurrency: true])\n  end\n\n  defp init_table({:via, _, _}) do\n    table = :ets.new(__MODULE__, [:set, :public, read_concurrency: true])\n    ensure_registry()\n    Registry.register(@registry, self(), table)\n    table\n  end\n\n  defp ensure_registry do\n    if Process.whereis(@registry) == nil do\n      Supervisor.start_child(:elixir_sup, {Registry, keys: :unique, name: @registry})\n    end\n  end\n\n  @doc \"\"\"\n  Resizes the number of partitions in the PartitionSupervisor.\n\n  This is done by starting or stopping a given number of\n  partitions in the supervisor. All of the child specifications\n  are kept in the `PartitionSupervisor` itself.\n\n  The final number of partitions cannot be less than zero and\n  cannot be more than the number of partitions the supervisor\n  started with.\n  \"\"\"\n  @doc since: \"1.18.0\"\n  @spec resize!(name(), non_neg_integer()) :: non_neg_integer()\n  def resize!(name, partitions) when is_name(name) and is_integer(partitions) do\n    supervisor =\n      GenServer.whereis(name) || exit({:noproc, {__MODULE__, :resize!, [name, partitions]}})\n\n    table = table(name)\n    ensure_registry()\n\n    Registry.lock(@registry, supervisor, fn ->\n      case :ets.lookup(table, :partitions) do\n        [{:partitions, _current, max}] when partitions not in 0..max//1 ->\n          raise ArgumentError,\n                \"the number of partitions to resize to must be a number between 0 and #{max}, got: #{partitions}\"\n\n        [{:partitions, current, max}] when partitions > current ->\n          for id <- current..(partitions - 1) do\n            case Supervisor.restart_child(supervisor, id) do\n              {:ok, _} ->\n                :ok\n\n              {:ok, _, _} ->\n                :ok\n\n              {:error, reason} ->\n                raise \"cannot restart partition #{id} of PartitionSupervisor #{inspect(name)} due to reason #{inspect(reason)}\"\n            end\n          end\n\n          :ets.insert(table, {:partitions, partitions, max})\n          current\n\n        [{:partitions, current, max}] when partitions < current ->\n          :ets.insert(table, {:partitions, partitions, max})\n\n          for id <- partitions..(current - 1) do\n            case Supervisor.terminate_child(supervisor, id) do\n              :ok ->\n                :ok\n\n              {:error, reason} ->\n                raise \"cannot terminate partition #{id} of PartitionSupervisor #{inspect(name)} due to reason #{inspect(reason)}\"\n            end\n          end\n\n          current\n\n        [{:partitions, current, _max}] ->\n          current\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Returns the number of partitions for the partition supervisor.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec partitions(name()) :: non_neg_integer()\n  def partitions(name) when is_name(name) do\n    name |> table() |> partitions(name)\n  end\n\n  defp partitions(table, name) do\n    try do\n      :ets.lookup_element(table, :partitions, 2)\n    rescue\n      _ -> exit({:noproc, {__MODULE__, :partitions, [name]}})\n    end\n  end\n\n  defp table(name) when is_atom(name) do\n    name\n  end\n\n  # For whereis_name, we want to lookup on GenServer.whereis/1\n  # just once, so we lookup the name and partitions together.\n  defp table(name) when is_tuple(name) do\n    with pid when is_pid(pid) <- GenServer.whereis(name),\n         [{_, table}] <- Registry.lookup(@registry, pid) do\n      table\n    else\n      _ -> exit({:noproc, {__MODULE__, :partitions, [name]}})\n    end\n  end\n\n  @doc \"\"\"\n  Returns a list with information about all children of the given supervisor.\n\n  This function returns a list of tuples containing:\n\n    * `id` - the partition number\n\n    * `child` - the PID of the corresponding child process or the\n      atom `:restarting` if the process is about to be restarted\n\n    * `type` - `:worker` or `:supervisor` as defined in the child\n      specification\n\n    * `modules` - as defined in the child specification\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec which_children(name()) :: [\n          # Inlining [module()] | :dynamic here because :supervisor.modules() is not exported\n          {integer(), pid | :restarting, :worker | :supervisor, [module()] | :dynamic}\n        ]\n  def which_children(name) when is_name(name) do\n    Supervisor.which_children(name)\n  end\n\n  @doc \"\"\"\n  Returns a map containing count values for the supervisor.\n\n  The map contains the following keys:\n\n    * `:specs` - the number of partitions (children processes)\n\n    * `:active` - the count of all actively running child processes managed by\n      this supervisor\n\n    * `:supervisors` - the count of all supervisors whether or not the child\n      process is still alive\n\n    * `:workers` - the count of all workers, whether or not the child process\n      is still alive\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec count_children(name()) :: %{\n          specs: non_neg_integer,\n          active: non_neg_integer,\n          supervisors: non_neg_integer,\n          workers: non_neg_integer\n        }\n  def count_children(supervisor) when is_name(supervisor) do\n    Supervisor.count_children(supervisor)\n  end\n\n  @doc \"\"\"\n  Synchronously stops the given partition supervisor with the given `reason`.\n\n  It returns `:ok` if the supervisor terminates with the given\n  reason. If it terminates with another reason, the call exits.\n\n  This function keeps OTP semantics regarding error reporting.\n  If the reason is any other than `:normal`, `:shutdown` or\n  `{:shutdown, _}`, an error report is logged.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec stop(name(), reason :: term, timeout) :: :ok\n  def stop(supervisor, reason \\\\ :normal, timeout \\\\ :infinity) when is_name(supervisor) do\n    Supervisor.stop(supervisor, reason, timeout)\n  end\n\n  ## Via callbacks\n\n  @doc false\n  def whereis_name({name, key}) when is_atom(name) or is_tuple(name) do\n    table = table(name)\n    partitions = partitions(table, name)\n\n    if partitions == 0 do\n      raise ArgumentError, \"PartitionSupervisor #{inspect(name)} has zero partitions\"\n    end\n\n    partition =\n      if is_integer(key), do: rem(abs(key), partitions), else: :erlang.phash2(key, partitions)\n\n    :ets.lookup_element(table, partition, 2)\n  end\n\n  @doc false\n  def send(name_key, msg) do\n    Kernel.send(whereis_name(name_key), msg)\n  end\n\n  @doc false\n  def register_name(_, _) do\n    raise \"{:via, PartitionSupervisor, _} cannot be given on registration\"\n  end\n\n  @doc false\n  def unregister_name(_) do\n    raise \"{:via, PartitionSupervisor, _} cannot be given on unregistration\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/path.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Path do\n  @moduledoc \"\"\"\n  This module provides conveniences for manipulating or\n  retrieving file system paths.\n\n  The functions in this module may receive chardata as\n  arguments and will always return a string encoded in UTF-8. Chardata\n  is a string or a list of characters and strings, see `t:IO.chardata/0`.\n  If a binary is given, in whatever encoding, its encoding will be kept.\n\n  The majority of the functions in this module do not\n  interact with the file system, except for a few functions\n  that require it (like `wildcard/2` and `expand/1`).\n  \"\"\"\n\n  @typedoc \"\"\"\n  A path.\n  \"\"\"\n  @type t :: IO.chardata()\n\n  @type relative_to_opts :: [force: boolean()]\n\n  @doc \"\"\"\n  Converts the given path to an absolute one.\n\n  Unlike `expand/1`, no attempt is made to resolve `..`, `.`, or `~`.\n\n  ## Examples\n\n  ### Unix-like operating systems\n\n      Path.absname(\"foo\")\n      #=> \"/usr/local/foo\"\n\n      Path.absname(\"../x\")\n      #=> \"/usr/local/../x\"\n\n  ### Windows\n\n      Path.absname(\"foo\")\n      #=> \"D:/usr/local/foo\"\n\n      Path.absname(\"../x\")\n      #=> \"D:/usr/local/../x\"\n\n  \"\"\"\n  @spec absname(t) :: binary\n  def absname(path) do\n    absname(path, &File.cwd!/0)\n  end\n\n  @doc \"\"\"\n  Builds a path from `relative_to` to `path`.\n\n  If `path` is already an absolute path, `relative_to` is ignored. See also\n  `relative_to/3`. `relative_to` is either a path or an anonymous function,\n  which is invoked only when necessary, that returns a path.\n\n  Unlike `expand/2`, no attempt is made to resolve `..`, `.` or `~`.\n\n  ## Examples\n\n      iex> Path.absname(\"foo\", \"bar\")\n      \"bar/foo\"\n\n      iex> Path.absname(\"../x\", \"bar\")\n      \"bar/../x\"\n\n      iex> Path.absname(\"foo\", fn -> \"lazy\" end)\n      \"lazy/foo\"\n\n  \"\"\"\n  @spec absname(t, t | (-> t)) :: binary\n  def absname(path, relative_to) do\n    path = IO.chardata_to_string(path)\n\n    case type(path) do\n      :relative ->\n        relative_to =\n          if is_function(relative_to, 0) do\n            relative_to.()\n          else\n            relative_to\n          end\n\n        absname_join([relative_to, path])\n\n      :absolute ->\n        absname_join([path])\n\n      :volumerelative ->\n        relative_to =\n          if is_function(relative_to, 0) do\n            relative_to.()\n          else\n            relative_to\n          end\n          |> IO.chardata_to_string()\n\n        absname_vr(split(path), split(relative_to), relative_to)\n    end\n  end\n\n  # Absolute path on current drive\n  defp absname_vr([\"/\" | rest], [volume | _], _relative), do: absname_join([volume | rest])\n\n  # Relative to current directory on current drive\n  defp absname_vr([<<x, ?:>> | rest], [<<x, _::binary>> | _], relative),\n    do: absname(absname_join(rest), relative)\n\n  # Relative to current directory on another drive\n  defp absname_vr([<<x, ?:>> | name], _, _relative) do\n    cwd =\n      case :file.get_cwd([x, ?:]) do\n        {:ok, dir} -> IO.chardata_to_string(dir)\n        {:error, _} -> <<x, ?:, ?/>>\n      end\n\n    absname(absname_join(name), cwd)\n  end\n\n  @slash [?/, ?\\\\]\n\n  defp absname_join([]), do: \"\"\n  defp absname_join(list), do: absname_join(list, major_os_type())\n\n  defp absname_join([name1, name2 | rest], os_type) do\n    joined = do_absname_join(IO.chardata_to_string(name1), relative(name2), [], os_type)\n    absname_join([joined | rest], os_type)\n  end\n\n  defp absname_join([name], os_type) do\n    do_absname_join(IO.chardata_to_string(name), <<>>, [], os_type)\n  end\n\n  defp do_absname_join(<<uc_letter, ?:, rest::binary>>, relativename, [], :win32)\n       when uc_letter in ?A..?Z,\n       do: do_absname_join(rest, relativename, [?:, uc_letter + ?a - ?A], :win32)\n\n  defp do_absname_join(<<c1, c2, rest::binary>>, relativename, [], :win32)\n       when c1 in @slash and c2 in @slash,\n       do: do_absname_join(rest, relativename, ~c\"//\", :win32)\n\n  defp do_absname_join(<<?\\\\, rest::binary>>, relativename, result, :win32),\n    do: do_absname_join(<<?/, rest::binary>>, relativename, result, :win32)\n\n  defp do_absname_join(<<?/, rest::binary>>, relativename, [?., ?/ | result], os_type),\n    do: do_absname_join(rest, relativename, [?/ | result], os_type)\n\n  defp do_absname_join(<<?/, rest::binary>>, relativename, [?/ | result], os_type),\n    do: do_absname_join(rest, relativename, [?/ | result], os_type)\n\n  defp do_absname_join(<<>>, <<>>, result, os_type),\n    do: IO.iodata_to_binary(reverse_maybe_remove_dir_sep(result, os_type))\n\n  defp do_absname_join(<<>>, relativename, [?: | rest], :win32),\n    do: do_absname_join(relativename, <<>>, [?: | rest], :win32)\n\n  defp do_absname_join(<<>>, relativename, [?/ | result], os_type),\n    do: do_absname_join(relativename, <<>>, [?/ | result], os_type)\n\n  defp do_absname_join(<<>>, relativename, result, os_type),\n    do: do_absname_join(relativename, <<>>, [?/ | result], os_type)\n\n  defp do_absname_join(<<char, rest::binary>>, relativename, result, os_type),\n    do: do_absname_join(rest, relativename, [char | result], os_type)\n\n  defp reverse_maybe_remove_dir_sep([?/, ?:, letter], :win32), do: [letter, ?:, ?/]\n  defp reverse_maybe_remove_dir_sep([?/], _), do: [?/]\n  defp reverse_maybe_remove_dir_sep([?/ | name], _), do: :lists.reverse(name)\n  defp reverse_maybe_remove_dir_sep(name, _), do: :lists.reverse(name)\n\n  @doc \"\"\"\n  Converts the path to an absolute one, expanding\n  any `.` and `..` components and a leading `~`.\n\n  If a relative path is provided it is expanded relatively to\n  the current working directory.\n\n  ## Examples\n\n      Path.expand(\"/foo/bar/../baz\")\n      #=> \"/foo/baz\"\n\n      Path.expand(\"foo/bar/../baz\")\n      #=> \"$PWD/foo/baz\"\n\n  \"\"\"\n  @spec expand(t) :: binary\n  def expand(path) do\n    expand_dot(absname(expand_home(path), &File.cwd!/0))\n  end\n\n  @doc \"\"\"\n  Expands the path relative to the path given as the second argument\n  expanding any `.` and `..` characters.\n\n  If the path is already an absolute path, `relative_to` is ignored.\n\n  Note that this function treats a `path` with a leading `~` as\n  an absolute one.\n\n  The second argument is first expanded to an absolute path.\n\n  ## Examples\n\n      # Assuming that the absolute path to baz is /quux/baz\n      Path.expand(\"foo/bar/../bar\", \"baz\")\n      #=> \"/quux/baz/foo/bar\"\n\n      Path.expand(\"foo/bar/../bar\", \"/baz\")\n      #=> \"/baz/foo/bar\"\n\n      Path.expand(\"/foo/bar/../bar\", \"/baz\")\n      #=> \"/foo/bar\"\n\n  \"\"\"\n  @spec expand(t, t) :: binary\n  def expand(path, relative_to) do\n    expand_dot(absname(absname(expand_home(path), expand_home(relative_to)), &File.cwd!/0))\n  end\n\n  @doc \"\"\"\n  Returns the path type.\n\n  ## Examples\n\n  ### Unix-like operating systems\n\n      Path.type(\"/\")                #=> :absolute\n      Path.type(\"/usr/local/bin\")   #=> :absolute\n      Path.type(\"usr/local/bin\")    #=> :relative\n      Path.type(\"../usr/local/bin\") #=> :relative\n      Path.type(\"~/file\")           #=> :relative\n\n  ### Windows\n\n      Path.type(\"D:/usr/local/bin\") #=> :absolute\n      Path.type(\"usr/local/bin\")    #=> :relative\n      Path.type(\"D:bar.ex\")         #=> :volumerelative\n      Path.type(\"/bar/foo.ex\")      #=> :volumerelative\n\n  \"\"\"\n  @spec type(t) :: :absolute | :relative | :volumerelative\n  def type(name)\n      when is_list(name)\n      when is_binary(name) do\n    pathtype(name, major_os_type()) |> elem(0)\n  end\n\n  @doc \"\"\"\n  Forces the path to be a relative path.\n\n  If an absolute path is given, it is stripped from its root component.\n\n  ## Examples\n\n  ### Unix-like operating systems\n\n      Path.relative(\"/usr/local/bin\")   #=> \"usr/local/bin\"\n      Path.relative(\"usr/local/bin\")    #=> \"usr/local/bin\"\n      Path.relative(\"../usr/local/bin\") #=> \"../usr/local/bin\"\n\n  ### Windows\n\n      Path.relative(\"D:/usr/local/bin\") #=> \"usr/local/bin\"\n      Path.relative(\"usr/local/bin\")    #=> \"usr/local/bin\"\n      Path.relative(\"D:bar.ex\")         #=> \"bar.ex\"\n      Path.relative(\"/bar/foo.ex\")      #=> \"bar/foo.ex\"\n\n  \"\"\"\n  # Note this function does not expand paths because the behavior\n  # is ambiguous. If we expand it before converting to relative, then\n  # \"/usr/../../foo\" means \"/foo\". If we expand it after, it means \"../foo\".\n  # We could expand only relative paths but it is best to say it never\n  # expands and then provide a `Path.expand_relative` function (or an\n  # option) if desired.\n  @spec relative(t) :: binary\n  def relative(name) do\n    relative(name, major_os_type())\n  end\n\n  defp relative(name, os_type) do\n    pathtype(name, os_type)\n    |> elem(1)\n    |> IO.chardata_to_string()\n  end\n\n  defp pathtype(name, os_type) do\n    case os_type do\n      :win32 -> win32_pathtype(name)\n      _ -> unix_pathtype(name)\n    end\n  end\n\n  defp unix_pathtype(path) when path in [\"/\", ~c\"/\"], do: {:absolute, \".\"}\n  defp unix_pathtype(<<?/, relative::binary>>), do: {:absolute, relative}\n  defp unix_pathtype([?/ | relative]), do: {:absolute, relative}\n  defp unix_pathtype([list | rest]) when is_list(list), do: unix_pathtype(list ++ rest)\n  defp unix_pathtype(relative), do: {:relative, relative}\n\n  defp win32_pathtype([list | rest]) when is_list(list), do: win32_pathtype(list ++ rest)\n\n  defp win32_pathtype([char, list | rest]) when is_list(list),\n    do: win32_pathtype([char | list ++ rest])\n\n  defp win32_pathtype(<<c1, c2, relative::binary>>) when c1 in @slash and c2 in @slash,\n    do: {:absolute, relative}\n\n  defp win32_pathtype(<<char, relative::binary>>) when char in @slash,\n    do: {:volumerelative, relative}\n\n  defp win32_pathtype(<<_letter, ?:, char, relative::binary>>) when char in @slash,\n    do: {:absolute, relative}\n\n  defp win32_pathtype(<<_letter, ?:, relative::binary>>), do: {:volumerelative, relative}\n\n  defp win32_pathtype([c1, c2 | relative]) when c1 in @slash and c2 in @slash,\n    do: {:absolute, relative}\n\n  defp win32_pathtype([char | relative]) when char in @slash, do: {:volumerelative, relative}\n\n  defp win32_pathtype([c1, c2, list | rest]) when is_list(list),\n    do: win32_pathtype([c1, c2 | list ++ rest])\n\n  defp win32_pathtype([_letter, ?:, char | relative]) when char in @slash,\n    do: {:absolute, relative}\n\n  defp win32_pathtype([_letter, ?: | relative]), do: {:volumerelative, relative}\n  defp win32_pathtype(relative), do: {:relative, relative}\n\n  @doc \"\"\"\n  Returns the direct relative path from `path` in relation to `cwd`.\n\n  In other words, this function attempts to return a path such that\n  `Path.expand(result, cwd)` points to `path`. This function aims\n  to return a relative path whenever possible, but that's not guaranteed:\n\n    * If both paths are relative, a relative path is always returned\n\n    * If both paths are absolute, a relative path may be returned if\n      they share a common prefix. You can pass the `:force` option to\n      force this function to traverse up, but even then a relative\n      path is not guaranteed (for example, if the absolute paths\n      belong to different drives on Windows)\n\n    * If a mixture of paths are given, the result will always match\n      the given `path` (the first argument)\n\n  This function expands `.` and `..` entries without traversing the\n  file system, so it assumes no symlinks between the paths. See\n  `safe_relative_to/2` for a safer alternative.\n\n  ## Options\n\n    * `:force` - (boolean since v1.16.0) if `true` forces a relative\n    path to be returned by traversing the path up. Except if the paths\n    are in different volumes on Windows. Defaults to `false`.\n\n  ## Examples\n\n  ### With relative `cwd`\n\n  If both paths are relative, a minimum path is computed:\n\n      Path.relative_to(\"tmp/foo/bar\", \"tmp\")      #=> \"foo/bar\"\n      Path.relative_to(\"tmp/foo/bar\", \"tmp/foo\")  #=> \"bar\"\n      Path.relative_to(\"tmp/foo/bar\", \"tmp/bat\")  #=> \"../foo/bar\"\n\n  If an absolute path is given with relative `cwd`, it is returned as:\n\n      Path.relative_to(\"/usr/foo/bar\", \"tmp/bat\")  #=> \"/usr/foo/bar\"\n\n  ### With absolute `cwd`\n\n  If both paths are absolute, a relative is computed if possible,\n  without traversing up:\n\n      Path.relative_to(\"/usr/local/foo\", \"/usr/local\")      #=> \"foo\"\n      Path.relative_to(\"/usr/local/foo\", \"/\")               #=> \"usr/local/foo\"\n      Path.relative_to(\"/usr/local/foo\", \"/etc\")            #=> \"/usr/local/foo\"\n      Path.relative_to(\"/usr/local/foo\", \"/usr/local/foo\")  #=> \".\"\n      Path.relative_to(\"/usr/local/../foo\", \"/usr/foo\")     #=> \".\"\n      Path.relative_to(\"/usr/local/../foo/bar\", \"/usr/foo\") #=> \"bar\"\n\n  If `:force` is set to `true` paths are traversed up:\n\n      Path.relative_to(\"/usr\", \"/usr/local\", force: true)          #=> \"..\"\n      Path.relative_to(\"/usr/foo\", \"/usr/local\", force: true)      #=> \"../foo\"\n      Path.relative_to(\"/usr/../foo/bar\", \"/etc/foo\", force: true) #=> \"../../foo/bar\"\n\n  If a relative path is given, it is assumed to be relative to the\n  given path, so the path is returned with \".\" and \"..\" expanded:\n\n      Path.relative_to(\".\", \"/usr/local\")          #=> \".\"\n      Path.relative_to(\"foo\", \"/usr/local\")        #=> \"foo\"\n      Path.relative_to(\"foo/../bar\", \"/usr/local\") #=> \"bar\"\n      Path.relative_to(\"foo/..\", \"/usr/local\")     #=> \".\"\n      Path.relative_to(\"../foo\", \"/usr/local\")     #=> \"../foo\"\n\n  \"\"\"\n  @spec relative_to(t, t, relative_to_opts) :: binary\n  def relative_to(path, cwd, opts \\\\ []) when is_list(opts) do\n    os_type = major_os_type()\n    split_path = split(path)\n    split_cwd = split(cwd)\n    force = Keyword.get(opts, :force, false)\n\n    case {split_absolute?(split_path, os_type), split_absolute?(split_cwd, os_type)} do\n      {true, true} ->\n        split_path = expand_split(split_path)\n        split_cwd = expand_split(split_cwd)\n\n        case force do\n          true -> relative_to_forced(split_path, split_cwd, split_path)\n          false -> relative_to_unforced(split_path, split_cwd, split_path)\n        end\n\n      {false, false} ->\n        split_path = expand_relative(split_path, [], [])\n        split_cwd = expand_relative(split_cwd, [], [])\n        relative_to_forced(split_path, split_cwd, [])\n\n      {_, _} ->\n        join(expand_relative(split_path, [], []))\n    end\n  end\n\n  defp relative_to_unforced(path, path, _original), do: \".\"\n\n  defp relative_to_unforced([h | t1], [h | t2], original),\n    do: relative_to_unforced(t1, t2, original)\n\n  defp relative_to_unforced([_ | _] = l1, [], _original), do: join(l1)\n  defp relative_to_unforced(_, _, original), do: join(original)\n\n  defp relative_to_forced(path, path, _original), do: \".\"\n  defp relative_to_forced([\".\"], _path, _original), do: \".\"\n  defp relative_to_forced(path, [\".\"], _original), do: join(path)\n  defp relative_to_forced([h | t1], [h | t2], original), do: relative_to_forced(t1, t2, original)\n\n  # this should only happen if we have two paths on different drives on windows\n  defp relative_to_forced(original, _, original), do: join(original)\n\n  defp relative_to_forced(l1, l2, _original) do\n    base = List.duplicate(\"..\", length(l2))\n    join(base ++ l1)\n  end\n\n  defp expand_relative([\"..\" | t], [_ | acc], up), do: expand_relative(t, acc, up)\n  defp expand_relative([\"..\" | t], acc, up), do: expand_relative(t, acc, [\"..\" | up])\n  defp expand_relative([\".\" | t], acc, up), do: expand_relative(t, acc, up)\n  defp expand_relative([h | t], acc, up), do: expand_relative(t, [h | acc], up)\n  defp expand_relative([], [], []), do: [\".\"]\n  defp expand_relative([], acc, up), do: up ++ :lists.reverse(acc)\n\n  defp expand_split([head | tail]), do: expand_split(tail, [head])\n  defp expand_split([\"..\" | t], [_, last | acc]), do: expand_split(t, [last | acc])\n  defp expand_split([\"..\" | t], acc), do: expand_split(t, acc)\n  defp expand_split([\".\" | t], acc), do: expand_split(t, acc)\n  defp expand_split([h | t], acc), do: expand_split(t, [h | acc])\n  defp expand_split([], acc), do: :lists.reverse(acc)\n\n  defp split_absolute?(split, :win32), do: win32_split_absolute?(split)\n  defp split_absolute?(split, _), do: match?([\"/\" | _], split)\n\n  defp win32_split_absolute?([\"//\" | _]), do: true\n  defp win32_split_absolute?([<<_, \":/\">> | _]), do: true\n  defp win32_split_absolute?(_), do: false\n\n  @doc \"\"\"\n  Convenience to get the path relative to the current working\n  directory.\n\n  If, for some reason, the current working directory\n  cannot be retrieved, this function returns the given `path`.\n\n  Check `relative_to/3` for the supported options.\n  \"\"\"\n  @spec relative_to_cwd(t, relative_to_opts) :: binary\n  def relative_to_cwd(path, opts \\\\ []) when is_list(opts) do\n    case :file.get_cwd() do\n      {:ok, base} -> relative_to(path, IO.chardata_to_string(base), opts)\n      _ -> path\n    end\n  end\n\n  @doc \"\"\"\n  Returns the last component of the path or the path\n  itself if it does not contain any directory separators.\n\n  ## Examples\n\n      iex> Path.basename(\"foo\")\n      \"foo\"\n\n      iex> Path.basename(\"foo/bar\")\n      \"bar\"\n\n      iex> Path.basename(\"lib/module/submodule.ex\")\n      \"submodule.ex\"\n\n      iex> Path.basename(\"/\")\n      \"\"\n\n  \"\"\"\n  @spec basename(t) :: binary\n  def basename(path) do\n    :filename.basename(IO.chardata_to_string(path))\n  end\n\n  @doc \"\"\"\n  Returns the last component of `path` with the `extension`\n  stripped.\n\n  This function should be used to remove a specific\n  extension which may or may not be there.\n\n  ## Examples\n\n      iex> Path.basename(\"~/foo/bar.ex\", \".ex\")\n      \"bar\"\n\n      iex> Path.basename(\"~/foo/bar.exs\", \".ex\")\n      \"bar.exs\"\n\n      iex> Path.basename(\"~/foo/bar.old.ex\", \".ex\")\n      \"bar.old\"\n\n  \"\"\"\n  @spec basename(t, t) :: binary\n  def basename(path, extension) do\n    :filename.basename(IO.chardata_to_string(path), IO.chardata_to_string(extension))\n  end\n\n  @doc \"\"\"\n  Returns the directory component of `path`.\n\n  ## Examples\n\n      iex> Path.dirname(\"/foo/bar.ex\")\n      \"/foo\"\n\n      iex> Path.dirname(\"/foo/bar/baz.ex\")\n      \"/foo/bar\"\n\n      iex> Path.dirname(\"/foo/bar/\")\n      \"/foo/bar\"\n\n      iex> Path.dirname(\"bar.ex\")\n      \".\"\n\n  \"\"\"\n  @spec dirname(t) :: binary\n  def dirname(path) do\n    :filename.dirname(IO.chardata_to_string(path))\n  end\n\n  @doc \"\"\"\n  Returns the extension of the last component of `path`.\n\n  For filenames starting with a dot and without an extension, it returns\n  an empty string.\n\n  See `basename/1` and `rootname/1` for related functions to extract\n  information from paths.\n\n  ## Examples\n\n      iex> Path.extname(\"foo.erl\")\n      \".erl\"\n\n      iex> Path.extname(\"~/foo/bar\")\n      \"\"\n\n      iex> Path.extname(\".gitignore\")\n      \"\"\n\n  \"\"\"\n  @spec extname(t) :: binary\n  def extname(path) do\n    :filename.extension(IO.chardata_to_string(path))\n  end\n\n  @doc \"\"\"\n  Returns the `path` with the `extension` stripped.\n\n  ## Examples\n\n      iex> Path.rootname(\"/foo/bar\")\n      \"/foo/bar\"\n\n      iex> Path.rootname(\"/foo/bar.ex\")\n      \"/foo/bar\"\n\n  \"\"\"\n  @spec rootname(t) :: binary\n  def rootname(path) do\n    :filename.rootname(IO.chardata_to_string(path))\n  end\n\n  @doc \"\"\"\n  Returns the `path` with the `extension` stripped.\n\n  This function should be used to remove a specific extension which may\n  or may not be there.\n\n  ## Examples\n\n      iex> Path.rootname(\"/foo/bar.erl\", \".erl\")\n      \"/foo/bar\"\n\n      iex> Path.rootname(\"/foo/bar.erl\", \".ex\")\n      \"/foo/bar.erl\"\n\n  \"\"\"\n  @spec rootname(t, t) :: binary\n  def rootname(path, extension) do\n    :filename.rootname(IO.chardata_to_string(path), IO.chardata_to_string(extension))\n  end\n\n  @doc \"\"\"\n  Joins a list of paths.\n\n  This function should be used to convert a list of paths to a path.\n  Note that any trailing slash is removed when joining.\n\n  Raises an error if the given list of paths is empty.\n\n  ## Examples\n\n      iex> Path.join([\"~\", \"foo\"])\n      \"~/foo\"\n\n      iex> Path.join([\"foo\"])\n      \"foo\"\n\n      iex> Path.join([\"/\", \"foo\", \"bar/\"])\n      \"/foo/bar\"\n\n  \"\"\"\n  @spec join(nonempty_list(t)) :: binary\n  def join([name1, name2 | rest]), do: join([join(name1, name2) | rest])\n  def join([name]), do: IO.chardata_to_string(name)\n\n  @doc \"\"\"\n  Joins two paths.\n\n  The right path will always be expanded to its relative format\n  and any trailing slash will be removed when joining.\n\n  ## Examples\n\n      iex> Path.join(\"foo\", \"bar\")\n      \"foo/bar\"\n\n      iex> Path.join(\"/foo\", \"/bar/\")\n      \"/foo/bar\"\n\n  The functions in this module support chardata, so giving a list will\n  treat it as a single entity:\n\n      iex> Path.join(\"foo\", [\"bar\", \"fiz\"])\n      \"foo/barfiz\"\n\n      iex> Path.join([\"foo\", \"bar\"], \"fiz\")\n      \"foobar/fiz\"\n\n  Use `join/1` if you need to join a list of paths instead.\n  \"\"\"\n  @spec join(t, t) :: binary\n  def join(left, right) do\n    left = IO.chardata_to_string(left)\n    os_type = major_os_type()\n    do_join(left, right, os_type) |> remove_dir_sep(os_type)\n  end\n\n  defp do_join(left, \"/\", os_type), do: remove_dir_sep(left, os_type)\n  defp do_join(\"\", right, os_type), do: relative(right, os_type)\n  defp do_join(\"/\", right, os_type), do: \"/\" <> relative(right, os_type)\n\n  defp do_join(left, right, os_type),\n    do: remove_dir_sep(left, os_type) <> \"/\" <> relative(right, os_type)\n\n  defp remove_dir_sep(\"\", _os_type), do: \"\"\n  defp remove_dir_sep(\"/\", _os_type), do: \"/\"\n\n  defp remove_dir_sep(bin, os_type) do\n    last = :binary.last(bin)\n\n    if last == ?/ or (last == ?\\\\ and os_type == :win32) do\n      binary_part(bin, 0, byte_size(bin) - 1)\n    else\n      bin\n    end\n  end\n\n  @doc ~S\"\"\"\n  Splits the path into a list at the path separator.\n\n  If an empty string is given, returns an empty list.\n\n  On Windows, path is split on both `\"\\\"` and `\"/\"` separators\n  and the driver letter, if there is one, is always returned\n  in lowercase.\n\n  ## Examples\n\n      iex> Path.split(\"\")\n      []\n\n      iex> Path.split(\"foo\")\n      [\"foo\"]\n\n      iex> Path.split(\"/foo/bar\")\n      [\"/\", \"foo\", \"bar\"]\n\n  \"\"\"\n  @spec split(t) :: [binary]\n  def split(path) do\n    :filename.split(IO.chardata_to_string(path))\n  end\n\n  defmodule Wildcard do\n    @moduledoc false\n\n    def read_link_info(file) do\n      :file.read_link_info(file)\n    end\n\n    def read_file_info(file) do\n      :file.read_file_info(file)\n    end\n\n    def list_dir(dir) do\n      case :file.list_dir(dir) do\n        {:ok, files} -> {:ok, for(file <- files, hd(file) != ?., do: file)}\n        other -> other\n      end\n    end\n  end\n\n  @doc ~S\"\"\"\n  Traverses paths according to the given `glob` expression and returns a\n  list of matches.\n\n  The wildcard looks like an ordinary path, except that the following\n  \"wildcard characters\" are interpreted in a special way:\n\n    * `?` - matches one character.\n\n    * `*` - matches any number of characters up to the end of the filename, the\n      next dot, or the next slash.\n\n    * `**` - two adjacent `*`'s used as a single pattern will match all\n      files and zero or more directories and subdirectories.\n\n    * `[char1,char2,...]` - matches any of the characters listed; two\n      characters separated by a hyphen will match a range of characters.\n      Do not add spaces before and after the comma as it would then match\n      paths containing the space character itself.\n\n    * `{item1,item2,...}` - matches one of the alternatives.\n      Do not add spaces before and after the comma as it would then match\n      paths containing the space character itself.\n\n  Other characters represent themselves. Only paths that have\n  exactly the same character in the same position will match. Note\n  that matching is case-sensitive: `\"a\"` will not match `\"A\"`.\n\n  Directory separators must always be written as `/`, even on Windows.\n  You may call `Path.expand/1` to normalize the path before invoking\n  this function.\n\n  A character preceded by `\\\\` loses its special meaning.\n  Note that `\\\\` must be written as `\\\\\\\\` in a string literal.\n  For example, `\"\\\\\\\\?*\"` will match any filename starting with `?.`.\n\n  By default, the patterns `*` and `?` do not match files starting\n  with a dot `.`. See the `:match_dot` option in the \"Options\" section\n  below.\n\n  ## Options\n\n    * `:match_dot` - (boolean) if `false`, the special wildcard characters `*` and `?`\n      will not match files starting with a dot (`.`). If `true`, files starting with\n      a `.` will not be treated specially. Defaults to `false`.\n\n  ## Examples\n\n  Imagine you have a directory called `projects` with three Elixir projects\n  inside of it: `elixir`, `ex_doc`, and `plug`. You can find all `.beam` files\n  inside the `ebin` directory of each project as follows:\n\n      Path.wildcard(\"projects/*/ebin/**/*.beam\")\n\n  If you want to search for both `.beam` and `.app` files, you could do:\n\n      Path.wildcard(\"projects/*/ebin/**/*.{beam,app}\")\n\n  \"\"\"\n  @spec wildcard(t, match_dot: boolean()) :: [binary]\n  def wildcard(glob, opts \\\\ []) when is_list(opts) do\n    mod = if Keyword.get(opts, :match_dot), do: :file, else: Path.Wildcard\n\n    glob\n    |> chardata_to_list!()\n    |> :filelib.wildcard(mod)\n    |> Enum.map(&IO.chardata_to_string/1)\n  end\n\n  defp chardata_to_list!(chardata) do\n    case :unicode.characters_to_list(chardata) do\n      result when is_list(result) ->\n        if 0 in result do\n          raise ArgumentError,\n                \"cannot execute Path.wildcard/2 for path with null byte, got: #{inspect(chardata)}\"\n        else\n          result\n        end\n\n      {:error, encoded, rest} ->\n        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :invalid\n\n      {:incomplete, encoded, rest} ->\n        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :incomplete\n    end\n  end\n\n  defp expand_home(type) do\n    case IO.chardata_to_string(type) do\n      \"~\" <> rest -> resolve_home(rest)\n      rest -> rest\n    end\n  end\n\n  defp resolve_home(\"\"), do: System.user_home!()\n\n  defp resolve_home(rest) do\n    case {rest, major_os_type()} do\n      {\"\\\\\" <> _, :win32} -> System.user_home!() <> rest\n      {\"/\" <> _, _} -> System.user_home!() <> rest\n      _ -> \"~\" <> rest\n    end\n  end\n\n  # expands dots in an absolute path represented as a string\n  defp expand_dot(path) do\n    [head | tail] = :binary.split(path, \"/\", [:global])\n    IO.iodata_to_binary(expand_dot(tail, [head <> \"/\"]))\n  end\n\n  defp expand_dot([\"..\" | t], [_, _ | acc]), do: expand_dot(t, acc)\n  defp expand_dot([\"..\" | t], acc), do: expand_dot(t, acc)\n  defp expand_dot([\".\" | t], acc), do: expand_dot(t, acc)\n  defp expand_dot([h | t], acc), do: expand_dot(t, [\"/\", h | acc])\n  defp expand_dot([], [\"/\", head | acc]), do: :lists.reverse([head | acc])\n  defp expand_dot([], acc), do: :lists.reverse(acc)\n\n  defp major_os_type do\n    :os.type() |> elem(0)\n  end\n\n  @doc \"\"\"\n  Returns a relative path that is protected from directory-traversal attacks.\n\n  See `safe_relative/2` for a non-deprecated version of this API.\n  \"\"\"\n  # TODO: Deprecate me on Elixir v1.19\n  @doc since: \"1.14.0\", deprecated: \"Use safe_relative/2 instead\"\n  @spec safe_relative_to(t, t) :: {:ok, binary} | :error\n  def safe_relative_to(path, cwd) do\n    safe_relative(path, cwd)\n  end\n\n  @doc \"\"\"\n  Returns a relative path that is protected from directory-traversal attacks.\n\n  The given relative path is sanitized by eliminating `..` and `.` components.\n\n  This function checks that, after expanding those components, the path is still \"safe\".\n  Paths are considered unsafe if either of these is true:\n\n    * The path is not relative, such as `\"/foo/bar\"`.\n\n    * A `..` component would make it so that the path would traverse up above\n      the root of `relative_to`.\n\n    * A symbolic link in the path points to something above the root of `relative_to`.\n\n  ## Examples\n\n      iex> Path.safe_relative(\"foo\")\n      {:ok, \"foo\"}\n\n      iex> Path.safe_relative(\"deps/my_dep/app.beam\")\n      {:ok, \"deps/my_dep/app.beam\"}\n\n      iex> Path.safe_relative(\"deps/my_dep/./build/../app.beam\", File.cwd!())\n      {:ok, \"deps/my_dep/app.beam\"}\n\n      iex> Path.safe_relative(\"my_dep/../..\")\n      :error\n\n      iex> Path.safe_relative(\"/usr/local\", File.cwd!())\n      :error\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec safe_relative(t, t) :: {:ok, binary} | :error\n  def safe_relative(path, relative_to \\\\ File.cwd!()) do\n    path = IO.chardata_to_string(path)\n\n    case :filelib.safe_relative_path(path, relative_to) do\n      :unsafe -> :error\n      relative_path -> {:ok, IO.chardata_to_string(relative_path)}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/port.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Port do\n  @moduledoc ~S\"\"\"\n  Functions for interacting with the external world through ports.\n\n  Ports provide a mechanism to start operating system processes external\n  to the Erlang VM and communicate with them via message passing.\n\n  ## Example\n\n      iex> port = Port.open({:spawn, \"cat\"}, [:binary])\n      iex> send(port, {self(), {:command, \"hello\"}})\n      iex> send(port, {self(), {:command, \"world\"}})\n      iex> flush()\n      {#Port<0.1444>, {:data, \"hello\"}}\n      {#Port<0.1444>, {:data, \"world\"}}\n      iex> send(port, {self(), :close})\n      :ok\n      iex> flush()\n      {#Port<0.1444>, :closed}\n      :ok\n\n  In the example above, we have created a new port that executes the\n  program `cat`. `cat` is a program available on Unix-like operating systems that\n  receives data from multiple inputs and concatenates them in the output.\n\n  After the port was created, we sent it two commands in the form of\n  messages using `send/2`. The first command has the binary payload\n  of \"hello\" and the second has \"world\".\n\n  After sending those two messages, we invoked the IEx helper `flush()`,\n  which printed all messages received from the port, in this case we got\n  \"hello\" and \"world\" back. Note that the messages are in binary because we\n  passed the `:binary` option when opening the port in `Port.open/2`. Without\n  such option, it would have yielded a list of bytes.\n\n  Once everything was done, we closed the port.\n\n  Elixir provides many conveniences for working with ports and some drawbacks.\n  We will explore those below.\n\n  ## Message and function APIs\n\n  There are two APIs for working with ports. It can be either asynchronous via\n  message passing, as in the example above, or by calling the functions on this\n  module.\n\n  The messages supported by ports and their counterpart function APIs are\n  listed below:\n\n    * `{pid, {:command, binary}}` - sends the given data to the port.\n      See `command/3`.\n\n    * `{pid, :close}` - closes the port. Unless the port is already closed,\n      the port will reply with `{port, :closed}` message once it has flushed\n      its buffers and effectively closed. See `close/1`.\n\n    * `{pid, {:connect, new_pid}}` - sets the `new_pid` as the new owner of\n      the port. Once a port is opened, the port is linked and connected to the\n      caller process and communication to the port only happens through the\n      connected process. This message makes `new_pid` the new connected processes.\n      Unless the port is dead, the port will reply to the old owner with\n      `{port, :connected}`. See `connect/2`.\n\n  On its turn, the port will send the connected process the following messages:\n\n    * `{port, {:data, data}}` - data sent by the port\n    * `{port, :closed}` - reply to the `{pid, :close}` message\n    * `{port, :connected}` - reply to the `{pid, {:connect, new_pid}}` message\n    * `{:EXIT, port, reason}` - exit signals in case the port crashes. If reason\n      is not `:normal`, this message will only be received if the owner process\n      is trapping exits\n\n  ## Open mechanisms\n\n  The port can be opened through four main mechanisms.\n\n  As a short summary, prefer to use the `:spawn` and `:spawn_executable`\n  options mentioned below. The other two options, `:spawn_driver` and `:fd`\n  are for advanced usage within the VM. Also consider using `System.cmd/3`\n  if all you want is to execute a program and retrieve its return value.\n\n  > #### Windows argument splitting and untrusted arguments {: .warning}\n  >\n  > On Unix systems, arguments are passed to a new operating system\n  > process as an array of strings but on Windows it is up to the child\n  > process to parse them and some Windows programs may apply their own\n  > rules, which are inconsistent with the standard C runtime `argv` parsing\n  >\n  > This is particularly troublesome when invoking `.bat` or `.com` files\n  > as these run implicitly through `cmd.exe`, whose argument parsing is\n  > vulnerable to malicious input and can be used to run arbitrary shell\n  > commands.\n  >\n  > Therefore, if you are running on Windows and you execute batch\n  > files or `.com` applications, you must not pass untrusted input as\n  > arguments to the program. You may avoid accidentally executing them\n  > by explicitly passing the extension of the program you want to run,\n  > such as `.exe`, and double check the program is indeed not a batch\n  > file or `.com` application.\n  >\n  > This affects both `spawn` and `spawn_executable`.\n\n  ### spawn\n\n  The `:spawn` tuple receives a binary that is going to be executed as a\n  full invocation. For example, we can use it to invoke \"echo hello\" directly:\n\n      iex> port = Port.open({:spawn, \"echo hello\"}, [:binary])\n      iex> flush()\n      {#Port<0.1444>, {:data, \"hello\\n\"}}\n\n  `:spawn` will retrieve the program name from the argument and traverse your\n  operating system `$PATH` environment variable looking for a matching program.\n\n  Although the above is handy, it means it is impossible to invoke an executable\n  that has whitespaces on its name or in any of its arguments. For those reasons,\n  most times it is preferable to execute `:spawn_executable`.\n\n  ### spawn_executable\n\n  Spawn executable is a more restricted and explicit version of spawn. It expects\n  full file paths to the executable you want to execute. If they are in your `$PATH`,\n  they can be retrieved by calling `System.find_executable/1`:\n\n      iex> path = System.find_executable(\"echo\")\n      iex> port = Port.open({:spawn_executable, path}, [:binary, args: [\"hello world\"]])\n      iex> flush()\n      {#Port<0.1380>, {:data, \"hello world\\n\"}}\n\n  When using `:spawn_executable`, the list of arguments can be passed via\n  the `:args` option as done above. For the full list of options, see the\n  documentation for the Erlang function `:erlang.open_port/2`.\n\n  ### fd\n\n  The `:fd` name option allows developers to access `in` and `out` file\n  descriptors used by the Erlang VM. You would use those only if you are\n  reimplementing core part of the Runtime System, such as the `:user` and\n  `:shell` processes.\n\n  ## Orphan operating system processes\n\n  A port can be closed via the `close/1` function or by sending a `{pid, :close}`\n  message. However, if the VM crashes, a long-running program started by the port\n  will have its stdin and stdout channels closed but **it won't be automatically\n  terminated**.\n\n  While some Unix command line tools will exit once its parent process\n  terminates, not all command line applications will do so. You can easily check\n  this by starting the port and then shutting down the VM and inspecting your\n  operating system to see if the port process is still running.\n\n  We do not always have control over how third-party software terminates.\n  If necessary, one workaround is to wrap the child application in a script that\n  checks whether stdin has been closed.  Here is such a script that has been\n  verified to work on bash shells:\n\n      #!/usr/bin/env bash\n\n      # Start the program in the background\n      exec \"$@\" &\n      pid1=$!\n\n      # Silence warnings from here on\n      exec >/dev/null 2>&1\n\n      # Read from stdin in the background and\n      # kill running program when stdin closes\n      exec 0<&0 $(\n        while read; do :; done\n        kill -KILL $pid1\n      ) &\n      pid2=$!\n\n      # Clean up\n      wait $pid1\n      ret=$?\n      kill -KILL $pid2\n      exit $ret\n\n  Note the program above hijacks stdin, so you won't be able to communicate\n  with the underlying software via stdin (on the positive side, software that\n  reads from stdin typically terminates when stdin closes).\n\n  Now instead of:\n\n      Port.open(\n        {:spawn_executable, \"/path/to/program\"},\n        args: [\"a\", \"b\", \"c\"]\n      )\n\n  You may invoke:\n\n      Port.open(\n        {:spawn_executable, \"/path/to/wrapper\"},\n        args: [\"/path/to/program\", \"a\", \"b\", \"c\"]\n      )\n\n  \"\"\"\n\n  @type name ::\n          {:spawn, charlist | binary}\n          | {:spawn_driver, charlist | binary}\n          | {:spawn_executable, :file.name_all()}\n          | {:fd, non_neg_integer, non_neg_integer}\n\n  @doc \"\"\"\n  Opens a port given a tuple `name` and a list of `options`.\n\n  The module documentation above contains documentation and examples\n  for the supported `name` values, summarized below:\n\n    * `{:spawn, command}` - runs an external program. `command` must contain\n      the program name and optionally a list of arguments separated by space.\n      If passing programs or arguments with space in their name, use the next option.\n    * `{:spawn_executable, filename}` - runs the executable given by the absolute\n      file name `filename`. Arguments can be passed via the `:args` option.\n    * `{:spawn_driver, command}` - spawns so-called port drivers.\n    * `{:fd, fd_in, fd_out}` - accesses file descriptors, `fd_in` and `fd_out`\n      opened by the VM.\n\n  For more information and the list of options, see `:erlang.open_port/2`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec open(name, list) :: port\n  def open(name, options) do\n    :erlang.open_port(name, options)\n  end\n\n  @doc \"\"\"\n  Closes the `port`.\n\n  For more information, see `:erlang.port_close/1`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec close(port) :: true\n  def close(port) do\n    :erlang.port_close(port)\n  end\n\n  @doc \"\"\"\n  Sends `data` to the port driver `port`.\n\n  For more information, see `:erlang.port_command/3`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec command(port, iodata, [:force | :nosuspend]) :: boolean\n  def command(port, data, options \\\\ []) do\n    :erlang.port_command(port, data, options)\n  end\n\n  @doc \"\"\"\n  Associates the `port` identifier with a `pid`.\n\n  For more information, see `:erlang.port_connect/2`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec connect(port, pid) :: true\n  def connect(port, pid) do\n    :erlang.port_connect(port, pid)\n  end\n\n  @doc \"\"\"\n  Returns information about the `port` (or `nil` if the port is closed).\n\n  For more information, see `:erlang.port_info/1`.\n  \"\"\"\n  @spec info(port) :: keyword | nil\n  def info(port) do\n    nilify(:erlang.port_info(port))\n  end\n\n  @doc \"\"\"\n  Returns information about a specific field within\n  the `port` (or `nil` if the port is closed).\n\n  For more information, see `:erlang.port_info/2`.\n  \"\"\"\n  @spec info(port, atom) :: {atom, term} | nil\n  def info(port, spec)\n\n  def info(port, :registered_name) do\n    case :erlang.port_info(port, :registered_name) do\n      :undefined -> nil\n      [] -> {:registered_name, []}\n      other -> other\n    end\n  end\n\n  def info(port, item) do\n    nilify(:erlang.port_info(port, item))\n  end\n\n  @doc \"\"\"\n  Starts monitoring the given `port` from the calling process.\n\n  Once the monitored port process dies, a message is delivered to the\n  monitoring process in the shape of:\n\n      {:DOWN, ref, :port, object, reason}\n\n  where:\n\n    * `ref` is a monitor reference returned by this function;\n    * `object` is either the `port` being monitored (when monitoring by port ID)\n    or `{name, node}` (when monitoring by a port name);\n    * `reason` is the exit reason.\n\n  See `:erlang.monitor/2` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec monitor(port | {name, node} | name) :: reference when name: atom\n  def monitor(port) do\n    :erlang.monitor(:port, port)\n  end\n\n  @doc \"\"\"\n  Demonitors the monitor identified by the given `reference`.\n\n  If `monitor_ref` is a reference which the calling process\n  obtained by calling `monitor/1`, that monitoring is turned off.\n  If the monitoring is already turned off, nothing happens.\n\n  See `:erlang.demonitor/2` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec demonitor(reference, options :: [:flush | :info]) :: boolean\n  defdelegate demonitor(monitor_ref, options \\\\ []), to: :erlang\n\n  @doc \"\"\"\n  Returns a list of all ports in the current node.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec list :: [port]\n  def list do\n    :erlang.ports()\n  end\n\n  @compile {:inline, nilify: 1}\n  defp nilify(:undefined), do: nil\n  defp nilify(other), do: other\nend\n"
  },
  {
    "path": "lib/elixir/lib/process.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Process do\n  @moduledoc \"\"\"\n  Conveniences for working with processes and the process dictionary.\n\n  Besides the functions available in this module, the `Kernel` module\n  exposes and auto-imports some basic functionality related to processes\n  available through the following functions:\n\n    * `Kernel.spawn/1` and `Kernel.spawn/3`\n    * `Kernel.spawn_link/1` and `Kernel.spawn_link/3`\n    * `Kernel.spawn_monitor/1` and `Kernel.spawn_monitor/3`\n    * `Kernel.self/0`\n    * `Kernel.send/2`\n\n  While this module provides low-level conveniences to work with processes,\n  developers typically use abstractions such as `Agent`, `GenServer`,\n  `Registry`, `Supervisor` and `Task` for building their systems and\n  resort to this module for gathering information, trapping exits, links\n  and monitoring.\n\n  ## Aliases\n\n  Aliases are a feature introduced in Erlang/OTP 24. An alias is a way\n  to refer to a PID in order to send messages to it. The advantage of using\n  aliases is that they can be deactivated even if the aliased process is still\n  running. If you send a message to a deactivated alias, nothing will happen.\n  This makes request/response scenarios easier to implement.\n\n  You can use `alias/0` or `alias/1` to set an alias, and then you can send\n  messages to that alias like you do with PIDs using `send/2`. To deactivate\n  an alias, you can use `unalias/1`. If you send a message to a deactivated alias,\n  nothing will happen.\n\n  For example, you could have a process that listens for `:ping` messages:\n\n      def server do\n        receive do\n          {:ping, source_alias} ->\n            send(source_alias, :pong)\n            server()\n        end\n      end\n\n  Now, another process might ping this process:\n\n      server = spawn(&server/0)\n\n      source_alias = Process.alias()\n      send(server, {:ping, source_alias})\n\n      receive do\n        :pong -> :pong\n      end\n      #=> :pong\n\n  If now you deactivate the `source_alias` and ping the server again, you\n  won't receive any response since the server will `send/2` the `:pong` response\n  to a deactivated alias.\n\n      Process.unalias(source_alias)\n      send(server, {:ping, source_alias})\n\n      receive do\n        :pong -> :pong\n      after\n        1000 -> :timeout\n      end\n      #=> :timeout\n\n  See also the [Process Aliases\n  section](https://www.erlang.org/doc/reference_manual/processes.html#process-aliases)\n  of the *Erlang reference manual*.\n  \"\"\"\n\n  @typedoc \"\"\"\n  A process destination.\n\n  A remote or local PID, a local port, a locally registered name, or a tuple in\n  the form of `{registered_name, node}` for a registered name at another node.\n  \"\"\"\n  @type dest :: pid | port | (registered_name :: atom) | {registered_name :: atom, node}\n\n  @doc \"\"\"\n  Tells whether the given process is alive on the local node.\n\n  If the process identified by `pid` is alive (that is, it's not exiting and has\n  not exited yet) then this function returns `true`. Otherwise, it returns\n  `false`.\n\n  `pid` must refer to a process running on the local node or `ArgumentError` is raised.\n  To check whether a process on any node is alive you can use the [`:erpc`](`:erpc`) module.\n\n      :erpc.call(node(pid), Process, :alive?, [pid])\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec alive?(pid) :: boolean\n  defdelegate alive?(pid), to: :erlang, as: :is_process_alive\n\n  @doc \"\"\"\n  Returns all key-value pairs in the process dictionary.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec get() :: [{term, term}]\n  defdelegate get(), to: :erlang\n\n  @doc \"\"\"\n  Returns the value for the given `key` in the process dictionary,\n  or `default` if `key` is not set.\n\n  ## Examples\n\n      # Assuming :locale was not set\n      iex> Process.get(:locale, \"pt\")\n      \"pt\"\n      iex> Process.put(:locale, \"fr\")\n      nil\n      iex> Process.get(:locale, \"pt\")\n      \"fr\"\n\n  \"\"\"\n  @spec get(term, default :: term) :: term\n  def get(key, default \\\\ nil) do\n    case :erlang.get(key) do\n      :undefined -> default\n      value -> value\n    end\n  end\n\n  @doc \"\"\"\n  Returns all keys in the process dictionary.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      # Assuming :locale was not set\n      iex> :locale in Process.get_keys()\n      false\n      iex> Process.put(:locale, \"pt\")\n      nil\n      iex> :locale in Process.get_keys()\n      true\n\n  \"\"\"\n  @spec get_keys() :: [term]\n  defdelegate get_keys(), to: :erlang\n\n  @doc \"\"\"\n  Returns all keys in the process dictionary that have the given `value`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec get_keys(term) :: [term]\n  defdelegate get_keys(value), to: :erlang\n\n  @doc \"\"\"\n  Stores the given `key`-`value` pair in the process dictionary.\n\n  The return value of this function is the value that was previously stored\n  under `key`, or `nil` in case no value was stored under it.\n\n  ## Examples\n\n      # Assuming :locale was not set\n      iex> Process.put(:locale, \"en\")\n      nil\n      iex> Process.put(:locale, \"fr\")\n      \"en\"\n\n  \"\"\"\n  @spec put(term, term) :: term | nil\n  def put(key, value) do\n    nilify(:erlang.put(key, value))\n  end\n\n  @doc \"\"\"\n  Deletes the given `key` from the process dictionary.\n\n  Returns the value that was under `key` in the process dictionary,\n  or `nil` if `key` was not stored in the process dictionary.\n\n  ## Examples\n\n      iex> Process.put(:comments, [\"comment\", \"other comment\"])\n      iex> Process.delete(:comments)\n      [\"comment\", \"other comment\"]\n      iex> Process.delete(:comments)\n      nil\n\n  \"\"\"\n  @spec delete(term) :: term | nil\n  def delete(key) do\n    nilify(:erlang.erase(key))\n  end\n\n  @doc \"\"\"\n  Sends an exit signal with the given `reason` to `pid`.\n\n  Exit behavior differs based on the value of `reason`:\n\n    - If `:normal`, `pid` will not exit unless it is the calling process, in\n      which case it will exit with the reason `:normal`. If it is trapping exits,\n      the exit signal is transformed into a message `{:EXIT, from, :normal}` and\n      delivered to its message queue.\n\n    - If `:kill`, which occurs when `Process.exit(pid, :kill)` is called, an\n      untrappable exit signal is sent to `pid` which will unconditionally exit\n      with reason `:killed`.\n\n    - If any other term and `pid` is not trapping exits, `pid` will exit with\n      the given `reason`.\n\n    - If any other term and `pid` is trapping exits, the exit signal is\n      transformed into a message `{:EXIT, from, reason}` and delivered to its\n      message queue.\n\n  Inlined by the compiler.\n\n  > #### Differences to `Kernel.exit/1` {: .info }\n  >\n  > The functions `Kernel.exit/1` and `Process.exit/2` are\n  > named similarly but provide very different functionalities. The\n  > `Kernel:exit/1` function should be used when the intent is to stop the current\n  > process while `Process.exit/2` should be used when the intent is to send an\n  > exit signal to another process. Note also that `Kernel.exit/1` can be caught\n  > with `try/1` while `Process.exit/2` can only be handled by trapping exits and\n  > when the signal is different than `:kill`.\n\n  ## Examples\n\n      Process.exit(pid, :kill)\n      #=> true\n\n  \"\"\"\n  @spec exit(pid, term) :: true\n  defdelegate exit(pid, reason), to: :erlang\n\n  @doc \"\"\"\n  Sleeps the current process for the given `timeout`.\n\n  `timeout` is either the number of milliseconds to sleep as an\n  integer or the atom `:infinity`. When `:infinity` is given,\n  the current process will sleep forever, and not\n  consume or reply to messages.\n\n  > #### Sleeping limit {: .info }\n  >\n  > Before Elixir v1.18, `sleep/1` did not accept integer timeout values greater\n  > than `16#ffffffff`, that is, `2^32-1`. Since Elixir v1.18, arbitrarily-high integer\n  > values are accepted.\n\n  **Use this function with extreme care**. For almost all situations\n  where you would use `sleep/1` in Elixir, there is likely a\n  more correct, faster and precise way of achieving the same with\n  message passing.\n\n  For example, if you are waiting for a process to perform some\n  action, it is better to communicate the progress of such action\n  with messages.\n\n  In other words, **do not**:\n\n      Task.start_link(fn ->\n        do_something()\n        ...\n      end)\n\n      # Wait until work is done\n      Process.sleep(2000)\n\n  But **do**:\n\n      parent = self()\n\n      Task.start_link(fn ->\n        do_something()\n        send(parent, :work_is_done)\n        ...\n      end)\n\n      receive do\n        :work_is_done -> :ok\n      after\n        # Optional timeout\n        30_000 -> :timeout\n      end\n\n  For cases like the one above, `Task.async/1` and `Task.await/2` are\n  preferred.\n\n  Similarly, if you are waiting for a process to terminate,\n  monitor that process instead of sleeping. **Do not**:\n\n      Task.start_link(fn ->\n        ...\n      end)\n\n      # Wait until task terminates\n      Process.sleep(2000)\n\n  Instead **do**:\n\n      {:ok, pid} =\n        Task.start_link(fn ->\n          ...\n        end)\n\n      ref = Process.monitor(pid)\n\n      receive do\n        {:DOWN, ^ref, _, _, _} -> :task_is_down\n      after\n        # Optional timeout\n        30_000 -> :timeout\n      end\n\n  \"\"\"\n\n  # Max value for a receive's after clause\n  @max_receive_after 0xFFFFFFFF\n\n  @spec sleep(timeout) :: :ok\n  def sleep(timeout) when is_integer(timeout) and timeout > @max_receive_after do\n    receive after: (@max_receive_after -> sleep(timeout - @max_receive_after))\n  end\n\n  def sleep(timeout)\n      when is_integer(timeout) and timeout >= 0\n      when timeout == :infinity do\n    receive after: (timeout -> :ok)\n  end\n\n  @doc \"\"\"\n  Sends a message to the given `dest`.\n\n  `dest` may be a remote or local PID, a local port, a locally\n  registered name, or a tuple in the form of `{registered_name, node}` for a\n  registered name at another node.\n\n  Inlined by the compiler.\n\n  ## Options\n\n    * `:noconnect` - when used, if sending the message would require an\n      auto-connection to another node the message is not sent and `:noconnect` is\n      returned.\n\n    * `:nosuspend` - when used, if sending the message would cause the sender to\n      be suspended the message is not sent and `:nosuspend` is returned.\n\n  Otherwise the message is sent and `:ok` is returned.\n\n  ## Examples\n\n      iex> Process.send({:name, :node_that_does_not_exist}, :hi, [:noconnect])\n      :noconnect\n\n  \"\"\"\n  @spec send(dest, msg, [option]) :: :ok | :noconnect | :nosuspend\n        when dest: dest(),\n             msg: any,\n             option: :noconnect | :nosuspend\n  defdelegate send(dest, msg, options), to: :erlang\n\n  @doc \"\"\"\n  Sends `msg` to `dest` after `time` milliseconds.\n\n  If `dest` is a PID, it must be the PID of a local process, dead or alive.\n  If `dest` is an atom, it must be the name of a registered process\n  which is looked up at the time of delivery. No error is produced if the name does\n  not refer to a process.\n\n  The message is not sent immediately. Therefore, `dest` can receive other messages\n  in-between even when `time` is `0`.\n\n  This function returns a timer reference, which can be read with `read_timer/1`\n  or canceled with `cancel_timer/1`.\n\n  The timer will be automatically canceled if the given `dest` is a PID\n  which is not alive or when the given PID exits. Note that timers will not be\n  automatically canceled when `dest` is an atom (as the atom resolution is done\n  on delivery).\n\n  Inlined by the compiler.\n\n  ## Options\n\n    * `:abs` - (boolean) when `false`, `time` is treated as relative to the\n    current monotonic time. When `true`, `time` is the absolute value of the\n    Erlang monotonic time at which `msg` should be delivered to `dest`.\n    To read more about Erlang monotonic time and other time-related concepts,\n    look at the documentation for the `System` module. Defaults to `false`.\n\n  ## Examples\n\n      timer_ref = Process.send_after(pid, :hi, 1000)\n\n  \"\"\"\n  @spec send_after(pid | atom, term, non_neg_integer, [option]) :: reference\n        when option: {:abs, boolean}\n  def send_after(dest, msg, time, opts \\\\ []) do\n    :erlang.send_after(time, dest, msg, opts)\n  end\n\n  @doc \"\"\"\n  Cancels a timer returned by `send_after/3`.\n\n  When the result is an integer, it represents the time in milliseconds\n  left until the timer would have expired.\n\n  When the result is `false`, a timer corresponding to `timer_ref` could not be\n  found. This can happen either because the timer expired, because it has\n  already been canceled, or because `timer_ref` never corresponded to a timer.\n\n  Even if the timer had expired and the message was sent, this function does not\n  tell you if the timeout message has arrived at its destination yet.\n\n  Inlined by the compiler.\n\n  ## Options\n\n    * `:async` - (boolean) when `false`, the request for cancellation is\n      synchronous. When `true`, the request for cancellation is asynchronous,\n      meaning that the request to cancel the timer is issued and `:ok` is\n      returned right away. Defaults to `false`.\n\n    * `:info` - (boolean) whether to return information about the timer being\n      cancelled. When the `:async` option is `false` and `:info` is `true`, then\n      either an integer or `false` (like described above) is returned. If\n      `:async` is `false` and `:info` is `false`, `:ok` is returned. If `:async`\n      is `true` and `:info` is `true`, a message in the form `{:cancel_timer,\n      timer_ref, result}` (where `result` is an integer or `false` like\n      described above) is sent to the caller of this function when the\n      cancellation has been performed. If `:async` is `true` and `:info` is\n      `false`, no message is sent. Defaults to `true`.\n\n  \"\"\"\n  @spec cancel_timer(reference, options) :: non_neg_integer | false | :ok\n        when options: [async: boolean, info: boolean]\n  defdelegate cancel_timer(timer_ref, options \\\\ []), to: :erlang\n\n  @doc \"\"\"\n  Reads a timer created by `send_after/3`.\n\n  When the result is an integer, it represents the time in milliseconds\n  left until the timer will expire.\n\n  When the result is `false`, a timer corresponding to `timer_ref` could not be\n  found. This can be either because the timer expired, because it has already\n  been canceled, or because `timer_ref` never corresponded to a timer.\n\n  Even if the timer had expired and the message was sent, this function does not\n  tell you if the timeout message has arrived at its destination yet.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec read_timer(reference) :: non_neg_integer | false\n  defdelegate read_timer(timer_ref), to: :erlang\n\n  @type spawn_opt ::\n          :link\n          | :monitor\n          | {:monitor, :erlang.monitor_option()}\n          | {:priority, :low | :normal | :high}\n          | {:fullsweep_after, non_neg_integer}\n          | {:min_heap_size, non_neg_integer}\n          | {:min_bin_vheap_size, non_neg_integer}\n          | {:max_heap_size, heap_size}\n          | {:message_queue_data, :off_heap | :on_heap}\n  @type spawn_opts :: [spawn_opt]\n\n  @doc \"\"\"\n  Spawns the given function according to the given options.\n\n  The result depends on the given options. In particular,\n  if `:monitor` is given as an option, it will return a tuple\n  containing the PID and the monitoring reference, otherwise\n  just the spawned process PID.\n\n  More options are available; for the comprehensive list of available options\n  check `:erlang.spawn_opt/4`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      Process.spawn(fn -> 1 + 2 end, [:monitor])\n      #=> {#PID<0.93.0>, #Reference<0.18808174.1939079169.202418>}\n      Process.spawn(fn -> 1 + 2 end, [:link])\n      #=> #PID<0.95.0>\n\n  \"\"\"\n  @spec spawn((-> any), spawn_opts) :: pid | {pid, reference}\n  defdelegate spawn(fun, opts), to: :erlang, as: :spawn_opt\n\n  @doc \"\"\"\n  Spawns the given function `fun` from module `mod`, passing the given `args`\n  according to the given options.\n\n  The result depends on the given options. In particular,\n  if `:monitor` is given as an option, it will return a tuple\n  containing the PID and the monitoring reference, otherwise\n  just the spawned process PID.\n\n  It also accepts extra options, for the list of available options\n  check `:erlang.spawn_opt/4`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec spawn(module, atom, list, spawn_opts) :: pid | {pid, reference}\n  defdelegate spawn(mod, fun, args, opts), to: :erlang, as: :spawn_opt\n\n  @doc \"\"\"\n  Starts monitoring the given `item` from the calling process.\n\n  Once the monitored process dies, a message is delivered to the\n  monitoring process in the shape of:\n\n      {:DOWN, ref, :process, object, reason}\n\n  where:\n\n    * `ref` is a monitor reference returned by this function;\n    * `object` is either a `pid` of the monitored process (if monitoring\n      a PID) or `{name, node}` (if monitoring a remote or local name);\n    * `reason` is the exit reason.\n\n  If the process is already dead when calling `Process.monitor/1`, a\n  `:DOWN` message is delivered immediately.\n\n  See [\"Links and monitors\"](genservers.md#links-and-monitors)\n  for an example. See `:erlang.monitor/2` for more information.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      pid = spawn(fn -> 1 + 2 end)\n      #=> #PID<0.118.0>\n      Process.monitor(pid)\n      #=> #Reference<0.906660723.3006791681.40191>\n      Process.exit(pid, :kill)\n      #=> true\n      receive do\n        msg -> msg\n      end\n      #=> {:DOWN, #Reference<0.906660723.3006791681.40191>, :process, #PID<0.118.0>, :noproc}\n\n  \"\"\"\n  @spec monitor(pid | {name, node} | name) :: reference when name: atom\n  def monitor(item) do\n    :erlang.monitor(:process, item)\n  end\n\n  @doc \"\"\"\n  Starts monitoring the given `item` from the calling process.\n\n  This function is similar to `monitor/1`, but accepts options to customize how\n  `item` is monitored. See `:erlang.monitor/3` for documentation on those\n  options.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      pid =\n        spawn(fn ->\n          receive do\n            {:ping, source_alias} -> send(source_alias, :pong)\n          end\n        end)\n      #=> #PID<0.118.0>\n\n      ref_and_alias = Process.monitor(pid, alias: :reply_demonitor)\n      #=> #Reference<0.906660723.3006791681.40191>\n\n      send(pid, {:ping, ref_and_alias})\n\n      receive do: (msg -> msg)\n      #=> :pong\n\n      ref_and_alias = Process.monitor(pid, alias: :reply_demonitor)\n      #=> #Reference<0.906660723.3006791681.40191>\n\n      send(pid, {:ping, ref_and_alias})\n\n      receive do: (msg -> msg)\n      #=> {:DOWN, #Reference<0.906660723.3006791681.40191>, :process, #PID<0.118.0>, :noproc}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec monitor(pid | {name, node} | name, [:erlang.monitor_option()]) :: reference\n        when name: atom\n  def monitor(item, options) do\n    :erlang.monitor(:process, item, options)\n  end\n\n  @doc \"\"\"\n  Demonitors the monitor identified by the given `reference`.\n\n  If `monitor_ref` is a reference which the calling process\n  obtained by calling `monitor/1`, that monitoring is turned off.\n  If the monitoring is already turned off, nothing happens.\n\n  See `:erlang.demonitor/2` for more information.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      pid = spawn(fn -> 1 + 2 end)\n      ref = Process.monitor(pid)\n      Process.demonitor(ref)\n      #=> true\n\n  \"\"\"\n  @spec demonitor(reference, options :: [:flush | :info]) :: boolean\n  defdelegate demonitor(monitor_ref, options \\\\ []), to: :erlang\n\n  @doc \"\"\"\n  Returns a list of PIDs corresponding to all the\n  processes currently existing on the local node.\n\n  Note that if a process is exiting, it is considered to exist but not be\n  alive. This means that for such process, `alive?/1` will return `false` but\n  its PID will be part of the list of PIDs returned by this function.\n\n  See `:erlang.processes/0` for more information.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      Process.list()\n      #=> [#PID<0.0.0>, #PID<0.1.0>, #PID<0.2.0>, #PID<0.3.0>, ...]\n\n  \"\"\"\n  @spec list() :: [pid]\n  defdelegate list(), to: :erlang, as: :processes\n\n  @doc \"\"\"\n  Creates a link between the calling process and the given item (process or\n  port).\n\n  Links are bidirectional. Linked processes can be unlinked by using `unlink/1`.\n\n  If such a link exists already, this function does nothing since there can only\n  be one link between two given processes. If a process tries to create a link\n  to itself, nothing will happen.\n\n  When two processes are linked, each one receives exit signals from the other\n  (see also `exit/2`). Let's assume `pid1` and `pid2` are linked. If `pid2`\n  exits with a reason other than `:normal` (which is also the exit reason used\n  when a process finishes its job) and `pid1` is not trapping exits (see\n  `flag/2`), then `pid1` will exit with the same reason as `pid2` and in turn\n  emit an exit signal to all its other linked processes. The behavior when\n  `pid1` is trapping exits is described in `exit/2`.\n\n  See `:erlang.link/1` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec link(pid | port) :: true\n  defdelegate link(pid_or_port), to: :erlang\n\n  @doc \"\"\"\n  Removes the link between the calling process and the given item (process or\n  port).\n\n  If there is no such link, this function does nothing. If `pid_or_port` does\n  not exist, this function does not produce any errors and simply does nothing.\n\n  The return value of this function is always `true`.\n\n  See `:erlang.unlink/1` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec unlink(pid | port) :: true\n  defdelegate unlink(pid_or_port), to: :erlang\n\n  @doc \"\"\"\n  Registers the given `pid_or_port` under the given `name` on the local node.\n\n  `name` must be an atom and can then be used instead of the\n  PID/port identifier when sending messages with `Kernel.send/2`.\n\n  `register/2` will fail with `ArgumentError` in any of the following cases:\n\n    * the PID/Port is not existing locally and alive\n    * the name is already registered\n    * the `pid_or_port` is already registered under a different `name`\n\n  The following names are reserved and cannot be assigned to\n  processes nor ports:\n\n    * `nil`\n    * `false`\n    * `true`\n    * `:undefined`\n\n  ## Examples\n\n      Process.register(self(), :test)\n      #=> true\n      send(:test, :hello)\n      #=> :hello\n      send(:wrong_name, :hello)\n      ** (ArgumentError) argument error\n\n  \"\"\"\n  @spec register(pid | port, atom) :: true\n  def register(pid_or_port, name)\n      when is_atom(name) and name not in [nil, false, true, :undefined] do\n    :erlang.register(name, pid_or_port)\n  catch\n    :error, :badarg when node(pid_or_port) != node() ->\n      message = \"could not register #{inspect(pid_or_port)} because it belongs to another node\"\n      :erlang.error(ArgumentError.exception(message), [pid_or_port, name])\n\n    :error, :badarg ->\n      message =\n        \"could not register #{inspect(pid_or_port)} with \" <>\n          \"name #{inspect(name)} because it is not alive, the name is already \" <>\n          \"taken, or it has already been given another name\"\n\n      :erlang.error(ArgumentError.exception(message), [pid_or_port, name])\n  end\n\n  @doc \"\"\"\n  Removes the registered `name`, associated with a PID\n  or a port identifier.\n\n  Fails with `ArgumentError` if the name is not registered\n  to any PID or port.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      Process.register(self(), :test)\n      #=> true\n      Process.unregister(:test)\n      #=> true\n      Process.unregister(:wrong_name)\n      ** (ArgumentError) argument error\n\n  \"\"\"\n  @spec unregister(atom) :: true\n  defdelegate unregister(name), to: :erlang\n\n  @doc \"\"\"\n  Returns the PID or port identifier registered under `name` or `nil` if the\n  name is not registered.\n\n  See `:erlang.whereis/1` for more information.\n\n  ## Examples\n\n      Process.register(self(), :test)\n      Process.whereis(:test)\n      #=> #PID<0.84.0>\n      Process.whereis(:wrong_name)\n      #=> nil\n\n  \"\"\"\n  @spec whereis(atom) :: pid | port | nil\n  def whereis(name) do\n    nilify(:erlang.whereis(name))\n  end\n\n  @doc \"\"\"\n  Returns the PID of the group leader for the calling process.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      Process.group_leader()\n      #=> #PID<0.53.0>\n\n  \"\"\"\n  @spec group_leader() :: pid\n  defdelegate group_leader(), to: :erlang\n\n  @doc \"\"\"\n  Sets the group leader of the given `pid` to `leader`.\n\n  Typically, this is used when a process started from a certain shell should\n  have a group leader other than `:init`.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec group_leader(pid, leader :: pid) :: true\n  def group_leader(pid, leader) do\n    :erlang.group_leader(leader, pid)\n  end\n\n  @doc \"\"\"\n  Returns a list of names which have been registered using `register/2`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      Process.register(self(), :test)\n      Process.registered()\n      #=> [:test, :elixir_config, :inet_db, ...]\n\n  \"\"\"\n  @spec registered() :: [atom]\n  defdelegate registered(), to: :erlang\n\n  @typep heap_size ::\n           non_neg_integer\n           | %{size: non_neg_integer, kill: boolean, error_logger: boolean}\n\n  @typep priority_level :: :low | :normal | :high | :max\n\n  @doc \"\"\"\n  Sets the given `flag` to `value` for the calling process.\n\n  Returns the old value of `flag`.\n\n  See `:erlang.process_flag/2` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec flag(:error_handler, module) :: module\n  @spec flag(:max_heap_size, heap_size) :: heap_size\n  # :off_heap | :on_heap twice because :erlang.message_queue_data() is not exported\n  @spec flag(:message_queue_data, :off_heap | :on_heap) :: :off_heap | :on_heap\n  @spec flag(:min_bin_vheap_size, non_neg_integer) :: non_neg_integer\n  @spec flag(:min_heap_size, non_neg_integer) :: non_neg_integer\n  @spec flag(:priority, priority_level) :: priority_level\n  @spec flag(:save_calls, 0..10_000) :: 0..10_000\n  @spec flag(:sensitive, boolean) :: boolean\n  @spec flag(:trap_exit, boolean) :: boolean\n  defdelegate flag(flag, value), to: :erlang, as: :process_flag\n\n  @doc \"\"\"\n  Sets the given `flag` to `value` for the given process `pid`.\n\n  Returns the old value of `flag`.\n\n  It raises `ArgumentError` if `pid` is not a local process.\n\n  The allowed values for `flag` are only a subset of those allowed in `flag/2`,\n  namely `:save_calls`.\n\n  See `:erlang.process_flag/3` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec flag(pid, :save_calls, 0..10_000) :: 0..10_000\n  defdelegate flag(pid, flag, value), to: :erlang, as: :process_flag\n\n  @doc \"\"\"\n  Returns information about the process identified by `pid`, or returns `nil` if the process\n  is not alive.\n\n  Use this only for debugging information.\n\n  See `:erlang.process_info/1` for more information.\n  \"\"\"\n  @spec info(pid) :: keyword | nil\n  def info(pid) do\n    nilify(:erlang.process_info(pid))\n  end\n\n  @type process_info_item :: atom | {:dictionary, term}\n  @type process_info_result_item :: {process_info_item, term}\n\n  @doc \"\"\"\n  Returns information about the process identified by `pid`,\n  or returns `nil` if the process is not alive.\n\n  See `:erlang.process_info/2` for more information.\n  \"\"\"\n  @spec info(pid, process_info_item) :: process_info_result_item | nil\n  @spec info(pid, [process_info_item]) :: [process_info_result_item] | nil\n  def info(pid, spec)\n\n  def info(pid, :registered_name) do\n    case :erlang.process_info(pid, :registered_name) do\n      :undefined -> nil\n      [] -> {:registered_name, []}\n      other -> other\n    end\n  end\n\n  def info(pid, spec) do\n    nilify(:erlang.process_info(pid, spec))\n  end\n\n  @doc \"\"\"\n  Puts the calling process into a \"hibernation\" state.\n\n  The calling process is put into a waiting state\n  where its memory allocation has been reduced as much as possible,\n  which is useful if the process does not expect to receive any messages\n  in the near future.\n\n  See `:erlang.hibernate/3` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec hibernate(module, atom, list) :: no_return\n  defdelegate hibernate(mod, fun_name, args), to: :erlang\n\n  @type alias_opt :: :explicit_unalias | :reply\n\n  @typedoc \"\"\"\n  An alias returned by `alias/0` or `alias/1`.\n\n  See [the module documentation](#module-aliases) for more information about aliases.\n  \"\"\"\n  @type alias :: reference\n\n  @doc \"\"\"\n  Creates a process alias.\n\n  This is the same as calling `alias/1` as `alias([:explicit_unalias])`. See\n  also `:erlang.alias/0`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      alias = Process.alias()\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec alias() :: alias\n  defdelegate alias(), to: :erlang\n\n  @doc \"\"\"\n  Creates a process alias.\n\n  See [the module documentation](#module-aliases) for more information about aliases.\n  See also `:erlang.alias/1`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      alias = Process.alias([:reply])\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec alias([alias_opt]) :: alias\n  defdelegate alias(options), to: :erlang\n\n  @doc \"\"\"\n  Explicitly deactivates a process alias.\n\n  Returns `true` if `alias` was a currently-active alias for current processes,\n  or `false` otherwise.\n\n  See [the module documentation](#module-aliases) for more information about aliases.\n  See also `:erlang.unalias/1`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      alias = Process.alias()\n      Process.unalias(alias)\n      #=> true\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec unalias(alias) :: boolean\n  defdelegate unalias(alias), to: :erlang\n\n  @doc \"\"\"\n  Returns the label set for the process `pid` as set with `set_label/1`\n  or `:proc_lib.set_label/1`.\n\n  Defaults to the current process when `pid` is not passed.\n\n  ## Examples\n\n      Process.set_label({:any, \"term\"})\n      Process.get_label()\n      #=> {:any, \"term\"}\n\n  Returns `nil` when not set:\n\n      Process.get_label(pid)\n      #=> nil\n\n  \"\"\"\n  @doc since: \"1.20.0\"\n  @spec get_label(pid()) :: term()\n  def get_label(pid \\\\ self()) do\n    nilify(:proc_lib.get_label(pid))\n  end\n\n  @doc \"\"\"\n  Add a descriptive term to the current process.\n\n  The term does not need to be unique, and will be shown in Observer and in\n  crash logs.\n  This label may be useful for identifying a process as one of multiple in a\n  given role, such as `:queue_worker` or `{:live_chat, user_id}`.\n\n  ## Examples\n\n      Process.set_label(:worker)\n      #=> :ok\n\n      Process.set_label({:any, \"term\"})\n      #=> :ok\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec set_label(term()) :: :ok\n  defdelegate set_label(label), to: :proc_lib\n\n  @compile {:inline, nilify: 1}\n  defp nilify(:undefined), do: nil\n  defp nilify(other), do: other\nend\n"
  },
  {
    "path": "lib/elixir/lib/protocol.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Protocol do\n  @moduledoc ~S\"\"\"\n  Reference and functions for working with protocols.\n\n  A protocol specifies an API that should be defined by its\n  implementations. A protocol is defined with `Kernel.defprotocol/2`\n  and its implementations with `Kernel.defimpl/3`.\n\n  ## Example\n\n  In Elixir, we have two nouns for checking how many items there\n  are in a data structure: `length` and `size`.  `length` means the\n  information must be computed. For example, `length(list)` needs to\n  traverse the whole list to calculate its length. On the other hand,\n  `tuple_size(tuple)` and `byte_size(binary)` do not depend on the\n  tuple and binary size as the size information is precomputed in\n  the data structure.\n\n  Although Elixir includes specific functions such as `tuple_size`,\n  `byte_size` and `map_size`, sometimes we want to be able to\n  retrieve the size of a data structure regardless of its type.\n  In Elixir we can write polymorphic code, i.e. code that works\n  with different shapes/types, by using protocols. A size protocol\n  could be implemented as follows:\n\n      defprotocol Size do\n        @doc \"Calculates the size (and not the length!) of a data structure\"\n        def size(data)\n      end\n\n  Now that the protocol can be implemented for every data structure\n  the protocol may have a compliant implementation for:\n\n      defimpl Size, for: BitString do\n        def size(binary), do: byte_size(binary)\n      end\n\n      defimpl Size, for: Map do\n        def size(map), do: map_size(map)\n      end\n\n      defimpl Size, for: Tuple do\n        def size(tuple), do: tuple_size(tuple)\n      end\n\n  Finally, we can use the `Size` protocol to call the correct implementation:\n\n      Size.size({1, 2})\n      # => 2\n      Size.size(%{key: :value})\n      # => 1\n\n  Note that we didn't implement it for lists as we don't have the\n  `size` information on lists, rather its value needs to be\n  computed with `length`.\n\n  The data structure you are implementing the protocol for\n  must be the first argument to all functions defined in the\n  protocol.\n\n  It is possible to implement protocols for all Elixir types:\n\n    * Structs (see the \"Protocols and Structs\" section below)\n    * `Tuple`\n    * `Atom`\n    * `List`\n    * `BitString`\n    * `Integer`\n    * `Float`\n    * `Function`\n    * `PID`\n    * `Map`\n    * `Port`\n    * `Reference`\n    * `Any` (see the \"Fallback to `Any`\" section below)\n\n  ## Protocols and Structs\n\n  The real benefit of protocols comes when mixed with structs.\n  For instance, Elixir ships with many data types implemented as\n  structs, like `MapSet`. We can implement the `Size` protocol\n  for those types as well:\n\n      defimpl Size, for: MapSet do\n        def size(map_set), do: MapSet.size(map_set)\n      end\n\n  When implementing a protocol for a struct, the `:for` option can\n  be omitted if the `defimpl/3` call is inside the module that defines\n  the struct:\n\n      defmodule User do\n        defstruct [:email, :name]\n\n        defimpl Size do\n          # two fields\n          def size(%User{}), do: 2\n        end\n      end\n\n  If a protocol implementation is not found for a given type,\n  invoking the protocol will raise unless it is configured to\n  fall back to `Any`. Conveniences for building implementations\n  on top of existing ones are also available, look at `defstruct/1`\n  for more information about deriving protocols.\n\n  ## Fallback to `Any`\n\n  In some cases, it may be convenient to provide a default\n  implementation for all types. This can be achieved by setting\n  the `@fallback_to_any` attribute to `true` in the protocol\n  definition:\n\n      defprotocol Size do\n        @fallback_to_any true\n        def size(data)\n      end\n\n  The `Size` protocol can now be implemented for `Any`:\n\n      defimpl Size, for: Any do\n        def size(_), do: 0\n      end\n\n  Although the implementation above is arguably not a reasonable\n  one. For example, it makes no sense to say a PID or an integer\n  have a size of `0`. That's one of the reasons why `@fallback_to_any`\n  is an opt-in behavior. For the majority of protocols, raising\n  an error when a protocol is not implemented is the proper behavior.\n\n  ## Multiple implementations\n\n  Protocols can also be implemented for multiple types at once:\n\n      defprotocol Reversible do\n        def reverse(term)\n      end\n\n      defimpl Reversible, for: [Map, List] do\n        def reverse(term), do: Enum.reverse(term)\n      end\n\n  Inside `defimpl/3`, you can use `@protocol` to access the protocol\n  being implemented and `@for` to access the module it is being\n  defined for.\n\n  ## Types\n\n  Defining a protocol automatically defines a zero-arity type named `t`, which\n  can be used as follows:\n\n      @spec print_size(Size.t()) :: :ok\n      def print_size(data) do\n        result =\n          case Size.size(data) do\n            0 -> \"data has no items\"\n            1 -> \"data has one item\"\n            n -> \"data has #{n} items\"\n          end\n\n        IO.puts(result)\n      end\n\n  The `@spec` above expresses that all types allowed to implement the\n  given protocol are valid argument types for the given function.\n\n  ## Configuration\n\n  The following module attributes are available to configure a protocol:\n\n    * `@fallback_to_any` - when true, enables protocol dispatch to\n      fallback to any\n\n    * `@undefined_impl_description` - a string with additional description\n      to be used on `Protocol.UndefinedError` when looking up the implementation\n      fails. This option is only applied if `@fallback_to_any` is not set to true\n\n  ## Consolidation\n\n  In order to speed up protocol dispatching, whenever all protocol implementations\n  are known up-front, typically after all Elixir code in a project is compiled,\n  Elixir provides a feature called *protocol consolidation*. Consolidation directly\n  links protocols to their implementations in a way that invoking a function from a\n  consolidated protocol is equivalent to invoking two remote functions - one to\n  identify the correct implementation, and another to call the implementation.\n\n  Protocol consolidation is applied by default to all Mix projects during compilation.\n  This may be an issue during test. For instance, if you want to implement a protocol\n  during test, the implementation will have no effect, as the protocol has already been\n  consolidated. One possible solution is to include compilation directories that are\n  specific to your test environment in your mix.exs:\n\n      def project do\n        ...\n        elixirc_paths: elixirc_paths(Mix.env())\n        ...\n      end\n\n      defp elixirc_paths(:test), do: [\"lib\", \"test/support\"]\n      defp elixirc_paths(_), do: [\"lib\"]\n\n  And then you can define the implementations specific to the test environment\n  inside `test/support/some_file.ex`.\n\n  Another approach is to disable protocol consolidation during tests in your\n  mix.exs:\n\n      def project do\n        ...\n        consolidate_protocols: Mix.env() != :test\n        ...\n      end\n\n  If you are using `Mix.install/2`, you can do by passing the `consolidate_protocols`\n  option:\n\n      Mix.install(\n        deps,\n        consolidate_protocols: false\n      )\n\n  Although doing so is not recommended as it may affect the performance of\n  your code.\n\n  Finally, note all protocols are compiled with `debug_info` set to `true`,\n  regardless of the option set by the `elixirc` compiler. The debug info is\n  used for consolidation and it is removed after consolidation unless\n  globally set.\n  \"\"\"\n\n  @doc \"\"\"\n  A function available in all protocol definitions that returns protocol metadata.\n  \"\"\"\n  @callback __protocol__(:consolidated?) :: boolean()\n  @callback __protocol__(:functions) :: [{atom(), arity()}]\n  @callback __protocol__(:impls) :: {:consolidated, [module()]} | :not_consolidated\n  @callback __protocol__(:module) :: module()\n\n  @doc \"\"\"\n  A function available in all protocol definitions that returns the implementation\n  for the given `term` or nil.\n\n  If `@fallback_to_any` is true, `nil` is never returned.\n  \"\"\"\n  @callback impl_for(term) :: module() | nil\n\n  @doc \"\"\"\n  A function available in all protocol definitions that returns the implementation\n  for the given `term` or raises.\n\n  If `@fallback_to_any` is true, it never raises.\n  \"\"\"\n  @callback impl_for!(term) :: module()\n\n  @doc \"\"\"\n  An optional callback to be implemented by protocol authors for custom deriving.\n\n  It must return a quoted expression that implements the protocol for the given module.\n\n  See `Protocol.derive/3` for an example.\n  \"\"\"\n  @macrocallback __deriving__(module(), term()) :: Macro.t()\n\n  @optional_callbacks __deriving__: 2\n\n  @elixir_checker_version :elixir_erl.checker_version()\n\n  @doc false\n  defmacro def(signature)\n\n  defmacro def({_, _, args}) when args == [] or is_atom(args) do\n    raise ArgumentError, \"protocol functions expect at least one argument\"\n  end\n\n  defmacro def({name, _, args}) when is_atom(name) and is_list(args) do\n    arity = length(args)\n\n    type_args = :lists.map(fn _ -> quote(do: term) end, :lists.seq(2, arity))\n    type_args = [quote(do: t) | type_args]\n\n    to_var = fn pos -> Macro.var(String.to_atom(\"arg\" <> Integer.to_string(pos)), __MODULE__) end\n\n    call_args = :lists.map(to_var, :lists.seq(2, arity))\n    call_args = [quote(do: term) | call_args]\n\n    # TODO: Raise in Elixir v2.0\n    if :lists.any(&match?({:\\\\, _, [_, _]}, &1), args) do\n      IO.warn(\"default arguments in protocol definitions is deprecated\", __CALLER__)\n    end\n\n    quote generated: true do\n      name = unquote(name)\n      arity = unquote(arity)\n\n      @__functions__ [{name, arity} | @__functions__]\n\n      # Generate a fake definition with the user\n      # signature that will be used by docs\n      Kernel.def(unquote(name)(unquote_splicing(args)))\n\n      # Generate the actual implementation\n      Kernel.def unquote(name)(unquote_splicing(call_args)) do\n        impl_for!(term).unquote(name)(unquote_splicing(call_args))\n      end\n\n      # Copy spec as callback if possible,\n      # otherwise generate a dummy callback\n      Module.spec_to_callback(__MODULE__, {name, arity}) ||\n        @callback unquote(name)(unquote_splicing(type_args)) :: term\n    end\n  end\n\n  defmacro def(_) do\n    raise ArgumentError, \"invalid arguments for def inside defprotocol\"\n  end\n\n  @doc \"\"\"\n  Checks if the given module is loaded and is protocol.\n\n  Returns `:ok` if so, otherwise raises `ArgumentError`.\n  \"\"\"\n  @spec assert_protocol!(module) :: :ok\n  def assert_protocol!(module) do\n    assert_protocol!(module, \"\")\n  end\n\n  defp assert_protocol!(module, extra) do\n    try do\n      Code.ensure_compiled!(module)\n    rescue\n      e in ArgumentError ->\n        raise ArgumentError, e.message <> extra\n    end\n\n    try do\n      module.__protocol__(:module)\n    rescue\n      UndefinedFunctionError ->\n        raise ArgumentError, \"#{inspect(module)} is not a protocol\" <> extra\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Checks if the given module is loaded and is an implementation\n  of the given protocol.\n\n  Returns `:ok` if so, otherwise raises `ArgumentError`.\n  \"\"\"\n  @spec assert_impl!(module, module) :: :ok\n  def assert_impl!(protocol, base) do\n    assert_impl!(protocol, base, \"\")\n  end\n\n  defp assert_impl!(protocol, base, extra) do\n    impl = __concat__(protocol, base)\n\n    try do\n      Code.ensure_compiled!(impl)\n    rescue\n      e in ArgumentError ->\n        raise ArgumentError, e.message <> extra\n    end\n\n    try do\n      impl.__impl__(:protocol)\n    rescue\n      UndefinedFunctionError ->\n        raise ArgumentError, \"#{inspect(impl)} is not an implementation of a protocol\" <> extra\n    else\n      ^protocol ->\n        :ok\n\n      other ->\n        raise ArgumentError,\n              \"expected #{inspect(impl)} to be an implementation of #{inspect(protocol)}\" <>\n                \", got: #{inspect(other)}\" <> extra\n    end\n  end\n\n  @doc \"\"\"\n  Derives the `protocol` for `module` with the given options.\n\n  Every time you derive a protocol, Elixir will verify if the protocol\n  has implemented the `c:Protocol.__deriving__/2` callback. If so,\n  the callback will be invoked and it should define the implementation\n  module. Otherwise an implementation that simply points to the `Any`\n  implementation is automatically derived.\n\n  ## Examples\n\n      defprotocol Derivable do\n        @impl true\n        defmacro __deriving__(module, options) do\n          # If you need to load struct metadata, you may call:\n          # struct_info = Macro.struct_info!(module, __CALLER__)\n\n          quote do\n            defimpl Derivable, for: unquote(module) do\n              def ok(arg) do\n                {:ok, arg, unquote(options)}\n              end\n            end\n          end\n        end\n\n        def ok(arg)\n      end\n\n  Once the protocol is defined, there are two ways it can be\n  derived. The first is by using the `@derive` module attribute\n  by the time you define the struct:\n\n      defmodule ImplStruct do\n        @derive [Derivable]\n        defstruct a: 0, b: 0\n      end\n\n      Derivable.ok(%ImplStruct{})\n      #=> {:ok, %ImplStruct{a: 0, b: 0}, []}\n\n  If the struct has already been defined, you can call this macro:\n\n      require Protocol\n      Protocol.derive(Derivable, ImplStruct, :oops)\n      Derivable.ok(%ImplStruct{a: 1, b: 1})\n      #=> {:ok, %ImplStruct{a: 1, b: 1}, :oops}\n\n  \"\"\"\n  defmacro derive(protocol, module, options \\\\ []) do\n    quote do\n      Protocol.__derive__([{unquote(protocol), unquote(options)}], unquote(module), __ENV__)\n    end\n  end\n\n  ## Consolidation\n\n  @doc \"\"\"\n  Extracts all protocols from the given paths.\n\n  The paths can be either a charlist or a string. Internally\n  they are worked on as charlists, so passing them as lists\n  avoid extra conversion.\n\n  Does not load any of the protocols.\n\n  ## Examples\n\n      # Get Elixir's ebin directory path and retrieve all protocols\n      iex> path = Application.app_dir(:elixir, \"ebin\")\n      iex> mods = Protocol.extract_protocols([path])\n      iex> Enumerable in mods\n      true\n\n  \"\"\"\n  @spec extract_protocols([charlist | String.t() | {charlist, [charlist]}]) :: [atom]\n  def extract_protocols(paths) do\n    extract_matching_by_attribute(paths, [?E, ?l, ?i, ?x, ?i, ?r, ?.], fn module, attributes ->\n      case attributes[:__protocol__] do\n        [fallback_to_any: _] -> module\n        _ -> nil\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Extracts all types implemented for the given protocol from\n  the given paths.\n\n  The paths can be either a charlist or a string. Internally\n  they are worked on as charlists, so passing them as lists\n  avoid extra conversion.\n\n  Does not load any of the implementations.\n\n  ## Examples\n\n      # Get Elixir's ebin directory path and retrieve all protocols\n      iex> path = Application.app_dir(:elixir, \"ebin\")\n      iex> mods = Protocol.extract_impls(Enumerable, [path])\n      iex> List in mods\n      true\n\n  \"\"\"\n  @spec extract_impls(module, [charlist | String.t() | {charlist, [charlist]}]) :: [atom]\n  def extract_impls(protocol, paths) when is_atom(protocol) do\n    prefix = Atom.to_charlist(protocol) ++ [?.]\n\n    extract_matching_by_attribute(paths, prefix, fn _mod, attributes ->\n      case attributes[:__impl__] do\n        [protocol: ^protocol, for: for] -> for\n        _ -> nil\n      end\n    end)\n  end\n\n  defp extract_matching_by_attribute(paths, prefix, callback) do\n    for path <- paths,\n        {path, files} = list_dir(path),\n        file <- files,\n        mod = extract_from_file(path, file, prefix, callback),\n        do: mod\n  end\n\n  # Do not use protocols as they may be consolidating\n  defp list_dir({path, files}) when is_list(path) and is_list(files) do\n    {path, files}\n  end\n\n  defp list_dir(path) when is_binary(path) do\n    list_dir(String.to_charlist(path))\n  end\n\n  defp list_dir(path) when is_list(path) do\n    case :file.list_dir(path) do\n      {:ok, files} -> {path, files}\n      _ -> {path, []}\n    end\n  end\n\n  defp extract_from_file(path, file, prefix, callback) do\n    if :lists.prefix(prefix, file) and :filename.extension(file) == [?., ?b, ?e, ?a, ?m] do\n      extract_from_beam(:filename.join(path, file), callback)\n    end\n  end\n\n  defp extract_from_beam(file, callback) do\n    case :beam_lib.chunks(file, [:attributes]) do\n      {:ok, {module, [attributes: attributes]}} ->\n        callback.(module, attributes)\n\n      _ ->\n        nil\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if the protocol was consolidated.\n  \"\"\"\n  @spec consolidated?(module) :: boolean\n  def consolidated?(protocol) do\n    protocol.__protocol__(:consolidated?)\n  end\n\n  @doc \"\"\"\n  Receives a protocol and a list of implementations and\n  consolidates the given protocol.\n\n  Consolidation happens by changing the protocol `impl_for`\n  in the abstract format to have fast lookup rules. Usually\n  the list of implementations to use during consolidation\n  are retrieved with the help of `extract_impls/2`.\n\n  It returns the updated version of the protocol bytecode.\n  If the first element of the tuple is `:ok`, it means\n  the protocol was consolidated.\n\n  A given bytecode or protocol implementation can be checked\n  to be consolidated or not by analyzing the protocol\n  attribute:\n\n      Protocol.consolidated?(Enumerable)\n\n  This function does not load the protocol at any point\n  nor loads the new bytecode for the compiled module.\n  However, each implementation must be available and\n  it will be loaded.\n  \"\"\"\n  @spec consolidate(module, [module]) ::\n          {:ok, binary}\n          | {:error, :not_a_protocol}\n          | {:error, :no_beam_info}\n  def consolidate(protocol, types) when is_atom(protocol) do\n    # Ensure the types are sorted so the compiled beam is deterministic\n    types = Enum.sort(types)\n\n    with {:ok, any, definitions, checker, compile_info} <- beam_protocol(protocol),\n         {:ok, definitions, checker} <-\n           consolidate(protocol, any, definitions, checker, types),\n         do: compile(definitions, checker, compile_info)\n  end\n\n  defp beam_protocol(protocol) do\n    chunk_ids = [:debug_info, [?E, ?x, ?C, ?k], [?D, ?o, ?c, ?s]]\n    opts = [:allow_missing_chunks]\n\n    case :beam_lib.chunks(beam_file(protocol), chunk_ids, opts) do\n      {:ok, {^protocol, [{:debug_info, debug_info}, {_, checker} | chunks]}} ->\n        {:debug_info_v1, _backend, {:elixir_v1, module_map, specs}} = debug_info\n        %{attributes: attributes, definitions: definitions} = module_map\n\n        case attributes[:__protocol__] do\n          [fallback_to_any: any] ->\n            checker =\n              with true <- is_binary(checker),\n                   {@elixir_checker_version, contents} <- :erlang.binary_to_term(checker) do\n                contents\n              else\n                _ -> nil\n              end\n\n            chunks = :lists.filter(fn {_name, value} -> value != :missing_chunk end, chunks)\n            chunks = :lists.map(fn {name, value} -> {List.to_string(name), value} end, chunks)\n            {:ok, any, definitions, checker, {module_map, specs, chunks}}\n\n          _ ->\n            {:error, :not_a_protocol}\n        end\n\n      _ ->\n        {:error, :no_beam_info}\n    end\n  end\n\n  defp beam_file(module) when is_atom(module) do\n    case :code.which(module) do\n      [_ | _] = file -> file\n      _ -> module\n    end\n  end\n\n  # Consolidate the protocol for faster implementations and fine-grained type information.\n  defp consolidate(protocol, fallback_to_any?, definitions, checker, types) do\n    case List.keytake(definitions, {:__protocol__, 1}, 0) do\n      {protocol_def, definitions} ->\n        types = if fallback_to_any?, do: types, else: List.delete(types, Any)\n        built_in_plus_any = [Any] ++ for {mod, _guard} <- built_in(), do: mod\n        structs = types -- built_in_plus_any\n\n        {impl_for, definitions} = List.keytake(definitions, {:impl_for, 1}, 0)\n        {impl_for!, definitions} = List.keytake(definitions, {:impl_for!, 1}, 0)\n        {struct_impl_for, definitions} = List.keytake(definitions, {:struct_impl_for, 1}, 0)\n\n        protocol_funs = get_protocol_functions(protocol_def)\n\n        protocol_def = change_protocol(protocol_def, types)\n        impl_for = change_impl_for(impl_for, protocol, types)\n        struct_impl_for = change_struct_impl_for(struct_impl_for, protocol, types, structs)\n        definitions = [protocol_def, impl_for, impl_for!, struct_impl_for] ++ definitions\n\n        checker =\n          if checker do\n            update_in(checker.exports, fn exports ->\n              signatures = new_signatures(definitions, protocol_funs, protocol, types, structs)\n\n              for {fun, info} <- exports do\n                if sig = Map.get(signatures, fun) do\n                  {fun, %{info | sig: sig}}\n                else\n                  {fun, info}\n                end\n              end\n            end)\n          end\n\n        {:ok, definitions, checker}\n\n      nil ->\n        {:error, :not_a_protocol}\n    end\n  end\n\n  defp new_signatures(definitions, protocol_funs, protocol, types, structs) do\n    alias Module.Types.Descr\n    types_minus_any = List.delete(types, Any)\n\n    clauses =\n      Enum.map(types_minus_any, fn impl ->\n        {[Module.Types.Of.impl(impl, :open)], Descr.atom([__concat__(protocol, impl)])}\n      end)\n\n    {domain, impl_for, impl_for!} =\n      case clauses do\n        [] ->\n          if Any in types do\n            clauses = [{[Descr.term()], Descr.atom([__concat__(protocol, Any)])}]\n            {Descr.term(), clauses, clauses}\n          else\n            {Descr.none(), [{[Descr.term()], Descr.atom([nil])}],\n             [{[Descr.none()], Descr.none()}]}\n          end\n\n        _ ->\n          structs_domain =\n            case structs do\n              [] -> Descr.none()\n              _ -> Descr.open_map(__struct__: Descr.atom(structs))\n            end\n\n          domain =\n            Enum.reduce(types_minus_any -- structs, structs_domain, fn impl, acc ->\n              Descr.union(Module.Types.Of.impl(impl, :open), acc)\n            end)\n\n          not_domain = Descr.negation(domain)\n\n          if Any in types do\n            clauses =\n              clauses ++ [{[not_domain], Descr.atom([__concat__(protocol, Any)])}]\n\n            {Descr.term(), clauses, clauses}\n          else\n            {domain, clauses ++ [{[not_domain], Descr.atom([nil])}], clauses}\n          end\n      end\n\n    new_signatures =\n      for {{_fun, arity} = fun_arity, :def, _, _} <- definitions,\n          fun_arity in protocol_funs do\n        rest = List.duplicate(Descr.term(), arity - 1)\n        {fun_arity, {:strong, nil, [{[domain | rest], Descr.dynamic()}]}}\n      end\n\n    Map.new(\n      [\n        {{:impl_for, 1}, {:strong, [Descr.term()], impl_for}},\n        {{:impl_for!, 1}, {:strong, [domain], impl_for!}}\n      ] ++ new_signatures\n    )\n  end\n\n  defp get_protocol_functions({_name, _kind, _meta, clauses}) do\n    Enum.find_value(clauses, fn\n      {_meta, [:functions], [], clauses} -> clauses\n      _ -> nil\n    end) || raise \"could not find protocol functions\"\n  end\n\n  defp change_protocol({_name, _kind, meta, clauses}, types) do\n    clauses =\n      Enum.map(clauses, fn\n        {meta, [:consolidated?], [], _} -> {meta, [:consolidated?], [], true}\n        {meta, [:impls], [], _} -> {meta, [:impls], [], {:consolidated, types}}\n        clause -> clause\n      end)\n\n    {{:__protocol__, 1}, :def, meta, clauses}\n  end\n\n  defp change_impl_for({_name, _kind, meta, _clauses}, protocol, types) do\n    fallback = if Any in types, do: __concat__(protocol, Any)\n    line = meta[:line]\n\n    clauses =\n      for {mod, guard} <- built_in(),\n          mod in types,\n          do: built_in_clause_for(mod, guard, protocol, meta, line)\n\n    struct_clause = struct_clause_for(meta, line)\n    fallback_clause = fallback_clause_for(fallback, protocol, meta)\n    clauses = [struct_clause] ++ clauses ++ [fallback_clause]\n\n    {{:impl_for, 1}, :def, meta, clauses}\n  end\n\n  defp change_struct_impl_for({_name, _kind, meta, _clauses}, protocol, types, structs) do\n    fallback = if Any in types, do: __concat__(protocol, Any)\n    clauses = for struct <- structs, do: each_struct_clause_for(struct, protocol, meta)\n    clauses = clauses ++ [fallback_clause_for(fallback, protocol, meta)]\n\n    {{:struct_impl_for, 1}, :defp, meta, clauses}\n  end\n\n  defp built_in_clause_for(mod, guard, protocol, meta, line) do\n    x = {:x, [line: line, version: -1], __MODULE__}\n    guard = quote(line: line, do: :erlang.unquote(guard)(unquote(x)))\n    body = __concat__(protocol, mod)\n    {meta, [x], [guard], body}\n  end\n\n  defp struct_clause_for(meta, line) do\n    x = {:x, [line: line, version: -1], __MODULE__}\n    head = quote(line: line, do: %{__struct__: unquote(x)})\n    guard = quote(line: line, do: :erlang.is_atom(unquote(x)))\n    body = quote(line: line, do: struct_impl_for(unquote(x)))\n    {meta, [head], [guard], body}\n  end\n\n  defp each_struct_clause_for(struct, protocol, meta) do\n    {meta, [struct], [], __concat__(protocol, struct)}\n  end\n\n  defp fallback_clause_for(value, _protocol, meta) do\n    {meta, [quote(do: _)], [], value}\n  end\n\n  # Finally compile the module and emit its bytecode.\n  defp compile(definitions, checker, {module_map, specs, docs_chunk}) do\n    module_map = %{module_map | definitions: definitions}\n    {:ok, :elixir_erl.consolidate(module_map, checker, specs, docs_chunk)}\n  end\n\n  ## Definition callbacks\n\n  @doc false\n  def __protocol__(name, do: block) do\n    quote do\n      defmodule unquote(name) do\n        @behaviour Protocol\n        @before_compile Protocol\n\n        # We don't allow function definition inside protocols\n        import Kernel, except: [def: 1, def: 2]\n\n        # Import the new `def` that is used by protocols\n        import Protocol, only: [def: 1]\n\n        # Compile with debug info for consolidation\n        @compile :debug_info\n\n        # Set up a clear slate to store defined functions\n        @__functions__ []\n        @fallback_to_any false\n        @undefined_impl_description \"\"\n\n        res = unquote(block)\n        unquote(after_defprotocol())\n        res\n      end\n    end\n  end\n\n  defp callback_ast_to_fa({_kind, {:\"::\", meta, [{name, _, args}, _return]}, _pos}) do\n    [{{name, length(List.wrap(args))}, meta}]\n  end\n\n  defp callback_ast_to_fa(\n         {_kind, {:when, _, [{:\"::\", meta, [{name, _, args}, _return]}, _vars]}, _pos}\n       ) do\n    [{{name, length(List.wrap(args))}, meta}]\n  end\n\n  defp callback_ast_to_fa({_kind, _clause, _pos}) do\n    []\n  end\n\n  defp callback_metas(module, kind)\n       when kind in [:callback, :macrocallback] do\n    :lists.flatmap(&callback_ast_to_fa/1, Module.get_attribute(module, kind))\n    |> :maps.from_list()\n  end\n\n  defp get_callback_line(fa, metas),\n    do: :maps.get(fa, metas, [])[:line]\n\n  defp warn(message, env, nil) do\n    IO.warn(message, env)\n  end\n\n  defp warn(message, env, line) when is_integer(line) do\n    IO.warn(message, %{env | line: line})\n  end\n\n  def __before_compile__(env) do\n    functions = Module.get_attribute(env.module, :__functions__)\n\n    if functions == [] do\n      warn(\n        \"protocols must define at least one function, but none was defined\",\n        env,\n        nil\n      )\n    end\n\n    extra =\n      ((Module.definitions_in(env.module, :def) ++ Module.definitions_in(env.module, :defmacro)) --\n         functions) --\n        [impl_for: 1, impl_for!: 1, __protocol__: 1, __deriving__: 2, __deriving__: 3]\n\n    # TODO: Make an error on Elixir v2.0\n    if extra != [] do\n      warn(\n        \"protocols can only define functions without implementation via def/1, found: \" <>\n          Enum.map_join(extra, \", \", fn {name, arity} -> \"#{name}/#{arity}\" end),\n        env,\n        nil\n      )\n    end\n\n    callback_metas = callback_metas(env.module, :callback)\n    callbacks = :maps.keys(callback_metas)\n\n    # TODO: Make an error on Elixir v2.0\n    :lists.foreach(\n      fn {name, arity} = fa ->\n        warn(\n          \"cannot define @callback #{name}/#{arity} inside protocol, use def/1 to outline your protocol definition\",\n          env,\n          get_callback_line(fa, callback_metas)\n        )\n      end,\n      callbacks -- functions\n    )\n\n    # Macro Callbacks\n    macrocallback_metas = callback_metas(env.module, :macrocallback)\n    macrocallbacks = :maps.keys(macrocallback_metas)\n\n    # TODO: Make an error on Elixir v2.0\n    :lists.foreach(\n      fn {name, arity} = fa ->\n        warn(\n          \"cannot define @macrocallback #{name}/#{arity} inside protocol, use def/1 to outline your protocol definition\",\n          env,\n          get_callback_line(fa, macrocallback_metas)\n        )\n      end,\n      macrocallbacks\n    )\n\n    # Optional Callbacks\n    optional_callbacks = Module.get_attribute(env.module, :optional_callbacks)\n\n    if optional_callbacks != [] do\n      warn(\n        \"cannot define @optional_callbacks inside protocol, all of the protocol definitions are required\",\n        env,\n        nil\n      )\n    end\n  end\n\n  defp after_defprotocol do\n    prefix =\n      quote bind_quoted: [built_in: built_in()] do\n        any_impl_for =\n          if @fallback_to_any do\n            Protocol.__concat__(__MODULE__, \"Any\")\n          else\n            nil\n          end\n\n        # Disable Dialyzer checks - before and after consolidation\n        # the types could be more strict\n        @dialyzer {:nowarn_function, __protocol__: 1, impl_for: 1, impl_for!: 1}\n\n        @doc false\n        @spec impl_for(term) :: atom | nil\n        Kernel.def(impl_for(data))\n\n        # Define the implementation for structs.\n        #\n        # It simply delegates to struct_impl_for which is then\n        # optimized during protocol consolidation.\n        Kernel.def impl_for(%struct{}) do\n          struct_impl_for(struct)\n        end\n\n        # Define the implementation for built-ins\n        :lists.foreach(\n          fn {mod, guard} ->\n            target = Protocol.__concat__(__MODULE__, mod)\n\n            Kernel.def impl_for(data) when :erlang.unquote(guard)(data) do\n              case Code.ensure_compiled(unquote(target)) do\n                {:module, module} -> module\n                {:error, _} -> unquote(any_impl_for)\n              end\n            end\n          end,\n          built_in\n        )\n\n        # Internal handler for Structs\n        Kernel.defp struct_impl_for(struct) do\n          case Code.ensure_compiled(Protocol.__concat__(__MODULE__, struct)) do\n            {:module, module} -> module\n            {:error, _} -> unquote(any_impl_for)\n          end\n        end\n\n        # Inline struct implementation for performance\n        @compile {:inline, struct_impl_for: 1}\n\n        if not Module.defines_type?(__MODULE__, {:t, 0}) do\n          @typedoc \"\"\"\n          All the types that implement this protocol.\n          \"\"\"\n          @type t :: term\n        end\n\n        # Store information as an attribute so it\n        # can be read without loading the module.\n        Module.register_attribute(__MODULE__, :__protocol__, persist: true)\n        @__protocol__ [fallback_to_any: !!@fallback_to_any]\n\n        @doc false\n        @spec __protocol__(:module) :: __MODULE__\n        @spec __protocol__(:functions) :: [{atom(), arity()}]\n        @spec __protocol__(:consolidated?) :: boolean()\n        @spec __protocol__(:impls) :: :not_consolidated | {:consolidated, [module()]}\n        Kernel.def(__protocol__(:module), do: __MODULE__)\n        Kernel.def(__protocol__(:functions), do: unquote(:lists.sort(@__functions__)))\n        Kernel.def(__protocol__(:consolidated?), do: false)\n        Kernel.def(__protocol__(:impls), do: :not_consolidated)\n      end\n\n    raise =\n      quote do\n        raise(Protocol.UndefinedError,\n          protocol: __MODULE__,\n          value: data,\n          description: @undefined_impl_description\n        )\n      end\n\n    # Define a catch-all impl_for/1 clause to pacify Dialyzer (since\n    # destructuring opaque types is illegal, Dialyzer will think none of the\n    # previous clauses matches opaque types, and without this clause, will\n    # conclude that impl_for can't handle an opaque argument). This is a hack\n    # since it relies on Dialyzer not being smart enough to conclude that all\n    # opaque types will get the any_impl_for/0 implementation.\n    impl_for_fallback =\n      quote generated: true, bind_quoted: [] do\n        Kernel.def impl_for(_) do\n          unquote(any_impl_for)\n        end\n      end\n\n    quote generated: true do\n      unquote(prefix)\n      unquote(impl_for_fallback)\n\n      @doc false\n      @spec impl_for!(term) :: atom\n      if any_impl_for do\n        Kernel.def impl_for!(data) do\n          impl_for(data)\n        end\n      else\n        Kernel.def impl_for!(data) do\n          impl_for(data) || unquote(raise)\n        end\n      end\n    end\n  end\n\n  @doc false\n  def __impl__(protocol, opts, do_block, env) do\n    opts = Keyword.merge(opts, do_block)\n\n    {for, opts} =\n      Keyword.pop_lazy(opts, :for, fn ->\n        env.module ||\n          raise ArgumentError, \"defimpl/3 expects a :for option when declared outside a module\"\n      end)\n\n    expansion_env = %{env | module: env.module || Elixir, function: {:__impl__, 1}}\n    protocol = Macro.expand_literals(protocol, expansion_env)\n    for = Macro.expand_literals(for, expansion_env)\n\n    case opts do\n      [] -> raise ArgumentError, \"defimpl expects a do-end block\"\n      [do: block] -> __impl__(protocol, for, block)\n      _ -> raise ArgumentError, \"unknown options given to defimpl, got: #{Macro.to_string(opts)}\"\n    end\n  end\n\n  defp __impl__(protocol, for, block) when is_list(for) do\n    for f <- for, do: __impl__(protocol, f, block)\n  end\n\n  defp __impl__(protocol, for, block) do\n    # Unquote the implementation just later\n    # when all variables will already be injected\n    # into the module body.\n    impl =\n      quote unquote: false do\n        @doc false\n        @spec __impl__(:for) :: unquote(for)\n        @spec __impl__(:protocol) :: unquote(protocol)\n        def __impl__(:for), do: unquote(for)\n        def __impl__(:protocol), do: unquote(protocol)\n      end\n\n    # If the protocol is an atom, we will add an export dependency,\n    # since it was expanded before-hand. Otherwise it is a dynamic\n    # expression (and therefore most likely a compile-time one).\n    behaviour =\n      if is_atom(protocol) do\n        quote(do: require(unquote(protocol)))\n      else\n        quote(do: protocol)\n      end\n\n    quote do\n      protocol = unquote(protocol)\n      for = unquote(for)\n      name = Protocol.__concat__(protocol, for)\n\n      Protocol.assert_protocol!(protocol)\n      Protocol.__impl__!(protocol, for, __ENV__)\n\n      defmodule name do\n        @moduledoc false\n        @behaviour unquote(behaviour)\n        @protocol protocol\n        @for for\n\n        res = unquote(block)\n        Module.register_attribute(__MODULE__, :__impl__, persist: true)\n        @__impl__ [protocol: @protocol, for: @for]\n\n        unquote(impl)\n        res\n      end\n    end\n  end\n\n  @doc false\n  def __derive__(derives, for, %Macro.Env{} = env) when is_atom(for) do\n    foreach = fn\n      proto when is_atom(proto) ->\n        derive(proto, for, [], env)\n\n      {proto, opts} when is_atom(proto) ->\n        derive(proto, for, opts, env)\n    end\n\n    :lists.foreach(foreach, :lists.flatten(derives))\n\n    :ok\n  end\n\n  defp derive(protocol, for, opts, env) do\n    extra = \", cannot derive #{inspect(protocol)} for #{inspect(for)}\"\n    assert_protocol!(protocol, extra)\n\n    {mod, args} =\n      if macro_exported?(protocol, :__deriving__, 2) do\n        {protocol, [for, opts]}\n      else\n        # TODO: Deprecate this on Elixir v1.22+\n        assert_impl!(protocol, Any, extra)\n        {__concat__(protocol, Any), [for, Macro.struct!(for, env), opts]}\n      end\n\n    # Clean up variables from eval context\n    env = :elixir_env.reset_vars(env)\n\n    :elixir_module.expand_callback(env.line, mod, :__deriving__, args, env, fn mod, fun, args ->\n      if function_exported?(mod, fun, length(args)) do\n        apply(mod, fun, args)\n      else\n        __impl__!(protocol, for, env)\n        assert_impl!(protocol, Any, extra)\n        impl = __concat__(protocol, Any)\n\n        funs =\n          for {fun, arity} <- protocol.__protocol__(:functions) do\n            args = Macro.generate_arguments(arity, nil)\n\n            quote do\n              def unquote(fun)(unquote_splicing(args)),\n                do: unquote(impl).unquote(fun)(unquote_splicing(args))\n            end\n          end\n\n        quoted =\n          quote do\n            @behaviour unquote(protocol)\n            Module.register_attribute(__MODULE__, :__impl__, persist: true)\n            @__impl__ [protocol: unquote(protocol), for: unquote(for)]\n\n            @doc false\n            @spec __impl__(:protocol) :: unquote(protocol)\n            @spec __impl__(:for) :: unquote(for)\n            def __impl__(:protocol), do: unquote(protocol)\n            def __impl__(:for), do: unquote(for)\n          end\n\n        Module.create(__concat__(protocol, for), [quoted | funs], Macro.Env.location(env))\n      end\n    end)\n  end\n\n  @doc false\n  def __impl__!(protocol, for, env) do\n    if not Code.get_compiler_option(:ignore_already_consolidated) and\n         Protocol.consolidated?(protocol) do\n      message =\n        \"the #{inspect(protocol)} protocol has already been consolidated, an \" <>\n          \"implementation for #{inspect(for)} has no effect. If you want to \" <>\n          \"implement protocols after compilation or during tests, check the \" <>\n          \"\\\"Consolidation\\\" section in the Protocol module documentation\"\n\n      IO.warn(message, env)\n    end\n\n    # TODO: Make this an error on Elixir v2.0\n    if for != Any and not Keyword.has_key?(built_in(), for) and for != env.module and\n         for not in env.context_modules and Code.ensure_compiled(for) != {:module, for} do\n      IO.warn(\n        \"you are implementing a protocol for #{inspect(for)} but said module is not available. \" <>\n          \"Make sure the module name is correct. If #{inspect(for)} is an optional dependency, \" <>\n          \"please wrap the protocol implementation in a Code.ensure_loaded?(#{inspect(for)}) check\",\n        env\n      )\n    end\n\n    :ok\n  end\n\n  defp built_in do\n    [\n      {Tuple, :is_tuple},\n      {Atom, :is_atom},\n      {List, :is_list},\n      {Map, :is_map},\n      {BitString, :is_bitstring},\n      {Integer, :is_integer},\n      {Float, :is_float},\n      {Function, :is_function},\n      {PID, :is_pid},\n      {Port, :is_port},\n      {Reference, :is_reference}\n    ]\n  end\n\n  @doc false\n  def __concat__(left, right) when is_atom(right) do\n    __concat__(left, remove_prefix(Atom.to_string(right)))\n  end\n\n  def __concat__(left, right) when is_binary(right) do\n    String.to_atom(ensure_prefix(Atom.to_string(left)) <> \".\" <> right)\n  end\n\n  defp ensure_prefix(\"Elixir.\" <> _ = left), do: left\n  defp ensure_prefix(left), do: \"Elixir.\" <> left\n\n  defp remove_prefix(\"Elixir.\" <> right), do: right\n  defp remove_prefix(right), do: right\nend\n"
  },
  {
    "path": "lib/elixir/lib/range.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Range do\n  @moduledoc \"\"\"\n  Ranges represent a sequence of zero, one or many, ascending\n  or descending integers with a common difference called step.\n\n  The most common form of creating and matching on ranges is\n  via the [`first..last`](`../2`) and [`first..last//step`](`..///3`)\n  notations, auto-imported from `Kernel`:\n\n      iex> 1 in 1..10\n      true\n      iex> 5 in 1..10\n      true\n      iex> 10 in 1..10\n      true\n\n  Ranges are always inclusive in Elixir. When a step is defined,\n  integers will only belong to the range if they match the step:\n\n      iex> 5 in 1..10//2\n      true\n      iex> 4 in 1..10//2\n      false\n\n  When defining a range without a step, the step will be\n  defined based on the first and last position of the\n  range, If `last >= first`, it will be an increasing range\n  with a step of 1. Otherwise, it is a decreasing range.\n  Note, however, implicit decreasing ranges are deprecated.\n  Therefore, if you need a decreasing range from `3` to `1`,\n  prefer to write `3..1//-1` instead.\n\n  `../0` can also be used as a shortcut to create the range `0..-1//1`,\n  also known as the full-slice range:\n\n      iex> ..\n      0..-1//1\n\n  ## Use cases\n\n  Ranges typically have two uses in Elixir: as a collection or\n  to represent a slice of another data structure.\n\n  ### Ranges as collections\n\n  Ranges in Elixir are enumerables and therefore can be used\n  with the `Enum` module:\n\n      iex> Enum.to_list(1..3)\n      [1, 2, 3]\n      iex> Enum.to_list(3..1//-1)\n      [3, 2, 1]\n      iex> Enum.to_list(1..5//2)\n      [1, 3, 5]\n\n  Ranges may also have a single element:\n\n      iex> Enum.to_list(1..1)\n      [1]\n      iex> Enum.to_list(1..1//2)\n      [1]\n\n  Or even no elements at all:\n\n      iex> Enum.to_list(10..0//1)\n      []\n      iex> Enum.to_list(0..10//-1)\n      []\n\n  The full-slice range, returned by `../0`, is an empty collection:\n\n      iex> Enum.to_list(..)\n      []\n\n  ### Ranges as slices\n\n  Ranges are also frequently used to slice collections.\n  You can slice strings or any enumerable:\n\n      iex> String.slice(\"elixir\", 1..4)\n      \"lixi\"\n      iex> Enum.slice([0, 1, 2, 3, 4, 5], 1..4)\n      [1, 2, 3, 4]\n\n  In those cases, the first and last values of the range\n  are mapped to positions in the collections.\n\n  If a negative number is given, it maps to a position\n  from the back:\n\n      iex> String.slice(\"elixir\", 1..-2//1)\n      \"lixi\"\n      iex> Enum.slice([0, 1, 2, 3, 4, 5], 1..-2//1)\n      [1, 2, 3, 4]\n\n  The range `0..-1//1`, returned by `../0`, returns the\n  collection as is, which is why it is called the full-slice\n  range:\n\n      iex> String.slice(\"elixir\", ..)\n      \"elixir\"\n      iex> Enum.slice([0, 1, 2, 3, 4, 5], ..)\n      [0, 1, 2, 3, 4, 5]\n\n  ## Definition\n\n  An increasing range `first..last//step` is a range from `first`\n  to `last` increasing by `step` where  `step` must be a positive\n  integer and all values `v` must be `first <= v and v <= last`.\n  Therefore, a range `10..0//1` is an empty range because there\n  is no value `v` that is `10 <= v and v <= 0`.\n\n  Similarly, a decreasing range `first..last//step` is a range\n  from `first` to `last` decreasing by `step` where `step` must\n  be a negative integer and  values `v` must be `first >= v and v >= last`.\n  Therefore, a range `0..10//-1` is an empty range because there\n  is no value `v` that is `0 >= v and v >= 10`.\n\n  ## Representation\n\n  Internally, ranges are represented as structs:\n\n      iex> range = 1..9//2\n      1..9//2\n      iex> first..last//step = range\n      iex> first\n      1\n      iex> last\n      9\n      iex> step\n      2\n      iex> range.step\n      2\n\n  You can access the range fields (`first`, `last`, and `step`)\n  directly but you should not modify nor create ranges by hand.\n  Instead use the proper operators or `new/2` and `new/3`.\n\n  Ranges implement the `Enumerable` protocol with memory\n  efficient versions of all `Enumerable` callbacks:\n\n      iex> range = 1..10\n      1..10\n      iex> Enum.reduce(range, 0, fn i, acc -> i * i + acc end)\n      385\n      iex> Enum.count(range)\n      10\n      iex> Enum.member?(range, 11)\n      false\n      iex> Enum.member?(range, 8)\n      true\n\n  Such function calls are efficient memory-wise no matter the\n  size of the range. The implementation of the `Enumerable`\n  protocol uses logic based solely on the endpoints and does\n  not materialize the whole list of integers.\n  \"\"\"\n\n  @enforce_keys [:first, :last, :step]\n  defstruct first: nil, last: nil, step: nil\n\n  @type limit :: integer\n  @type step :: pos_integer | neg_integer\n  @type t :: %__MODULE__{first: limit, last: limit, step: step}\n  @type t(first, last) :: %__MODULE__{first: first, last: last, step: step}\n\n  @doc \"\"\"\n  Creates a new range.\n\n  If `first` is less than `last`, the range will be increasing from\n  `first` to `last`. If `first` is equal to `last`, the range will contain\n  one element, which is the number itself.\n\n  If `first` is greater than `last`, the range will be decreasing from `first`\n  to `last`, albeit this behavior is deprecated. Therefore, it is advised to\n  explicitly list the step with `new/3`.\n\n  ## Examples\n\n      iex> Range.new(-100, 100)\n      -100..100\n\n  \"\"\"\n\n  @spec new(limit, limit) :: t\n  def new(first, last) when is_integer(first) and is_integer(last) do\n    step =\n      if first <= last do\n        1\n      else\n        # TODO: Remove me on v2.0\n        IO.warn_once(\n          {__MODULE__, :new},\n          fn ->\n            \"Range.new/2 and first..last default to a step of -1 when last < first. Use Range.new(first, last, -1) or first..last//-1, or pass 1 if that was your intention\"\n          end,\n          3\n        )\n\n        -1\n      end\n\n    %Range{first: first, last: last, step: step}\n  end\n\n  @doc \"\"\"\n  Creates a new range with `step`.\n\n  ## Examples\n\n      iex> Range.new(-100, 100, 2)\n      -100..100//2\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec new(limit, limit, step) :: t\n  def new(first, last, step)\n      when is_integer(first) and is_integer(last) and is_integer(step) and step != 0 do\n    %Range{first: first, last: last, step: step}\n  end\n\n  def new(first, last, step) do\n    raise ArgumentError,\n          \"ranges (first..last//step) expect both sides to be integers and the step to be a \" <>\n            \"non-zero integer, got: #{inspect(first)}..#{inspect(last)}//#{inspect(step)}\"\n  end\n\n  @doc \"\"\"\n  Returns the size of `range`.\n\n  ## Examples\n\n      iex> Range.size(1..10)\n      10\n      iex> Range.size(1..10//2)\n      5\n      iex> Range.size(1..10//3)\n      4\n      iex> Range.size(1..10//-1)\n      0\n\n      iex> Range.size(10..1//-1)\n      10\n      iex> Range.size(10..1//-2)\n      5\n      iex> Range.size(10..1//-3)\n      4\n      iex> Range.size(10..1//1)\n      0\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec size(t) :: non_neg_integer\n  def size(range)\n  def size(first..last//step) when step > 0 and first > last, do: 0\n  def size(first..last//step) when step < 0 and first < last, do: 0\n  def size(first..last//step), do: abs(div(last - first, step)) + 1\n\n  # TODO: Remove me on v2.0\n  def size(%{__struct__: Range, first: first, last: last} = range) do\n    step = if first <= last, do: 1, else: -1\n    size(Map.put(range, :step, step))\n  end\n\n  @doc \"\"\"\n  Shifts a range by the given number of steps.\n\n  ## Examples\n\n      iex> Range.shift(0..10, 1)\n      1..11\n      iex> Range.shift(0..10, 2)\n      2..12\n\n      iex> Range.shift(0..10//2, 2)\n      4..14//2\n      iex> Range.shift(10..0//-2, 2)\n      6..-4//-2\n\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec shift(t, integer) :: t\n  def shift(%Range{} = range, 0), do: range\n\n  def shift(first..last//step, steps_to_shift) when is_integer(steps_to_shift) do\n    shift = steps_to_shift * step\n\n    new(first + shift, last + shift, step)\n  end\n\n  @doc \"\"\"\n  Splits a range in two.\n\n  It returns a tuple of two elements.\n\n  If `split` is less than the number of elements in the range, the first\n  element in the range will have `split` entries and the second will have\n  all remaining entries.\n\n  If `split` is more than the number of elements in the range, the second\n  range in the tuple will emit zero elements.\n\n  ## Examples\n\n  Increasing ranges:\n\n      iex> Range.split(1..5, 2)\n      {1..2, 3..5}\n\n      iex> Range.split(1..5//2, 2)\n      {1..3//2, 5..5//2}\n\n      iex> Range.split(1..5//2, 0)\n      {1..-1//2, 1..5//2}\n\n      iex> Range.split(1..5//2, 10)\n      {1..5//2, 7..5//2}\n\n  Decreasing ranges can also be split:\n\n      iex> Range.split(5..1//-1, 2)\n      {5..4//-1, 3..1//-1}\n\n      iex> Range.split(5..1//-2, 2)\n      {5..3//-2, 1..1//-2}\n\n      iex> Range.split(5..1//-2, 0)\n      {5..7//-2, 5..1//-2}\n\n      iex> Range.split(5..1//-2, 10)\n      {5..1//-2, -1..1//-2}\n\n  Empty ranges preserve their property but still return empty ranges:\n\n      iex> Range.split(2..5//-1, 2)\n      {2..3//-1, 4..5//-1}\n\n      iex> Range.split(2..5//-1, 10)\n      {2..3//-1, 4..5//-1}\n\n      iex> Range.split(5..2//1, 2)\n      {5..4//1, 3..2//1}\n\n      iex> Range.split(5..2//1, 10)\n      {5..4//1, 3..2//1}\n\n  If the number to split is negative, it splits from the back:\n\n      iex> Range.split(1..5, -2)\n      {1..3, 4..5}\n\n      iex> Range.split(5..1//-1, -2)\n      {5..3//-1, 2..1//-1}\n\n  If it is negative and greater than the elements in the range,\n  the first element of the tuple will be an empty range:\n\n      iex> Range.split(1..5, -10)\n      {1..0//1, 1..5}\n\n      iex> Range.split(5..1//-1, -10)\n      {5..6//-1, 5..1//-1}\n\n  ## Properties\n\n  When a range is split, the following properties are observed.\n  Given `split(input)` returns `{left, right}`, we have:\n\n      assert input.first == left.first\n      assert input.last == right.last\n      assert input.step == left.step\n      assert input.step == right.step\n      assert Range.size(input) == Range.size(left) + Range.size(right)\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec split(t, integer) :: {t, t}\n  def split(first..last//step = range, split) when is_integer(split) do\n    if split >= 0 do\n      split(first, last, step, split)\n    else\n      split(first, last, step, size(range) + split)\n    end\n  end\n\n  defp split(first, last, step, split) when first < last or (first == last and step > 0) do\n    if step > 0 do\n      mid = max(min(first + step * (split - 1), last), first - step)\n      {first..mid//step, (mid + step)..last//step}\n    else\n      {first..(first - step)//step, (last + step)..last//step}\n    end\n  end\n\n  defp split(last, first, step, split) do\n    if step < 0 do\n      mid = min(max(last + step * (split - 1), first), last - step)\n      {last..mid//step, (mid + step)..first//step}\n    else\n      {last..(last - step)//step, (first + step)..first//step}\n    end\n  end\n\n  @doc \"\"\"\n  Converts a range to a list.\n\n  ## Examples\n\n      iex> Range.to_list(0..5)\n      [0, 1, 2, 3, 4, 5]\n      iex> Range.to_list(-3..0)\n      [-3, -2, -1, 0]\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec to_list(t) :: list(integer)\n  def to_list(first..last//step)\n      when step > 0 and first <= last\n      when step < 0 and first >= last do\n    :lists.seq(first, last, step)\n  end\n\n  def to_list(_first.._last//_step) do\n    []\n  end\n\n  # TODO: Remove me on v2.0\n  def to_list(%{__struct__: Range, first: first, last: last}) do\n    step = if first <= last, do: 1, else: -1\n    :lists.seq(first, last, step)\n  end\n\n  @doc \"\"\"\n  Checks if two ranges are disjoint.\n\n  ## Examples\n\n      iex> Range.disjoint?(1..5, 6..9)\n      true\n      iex> Range.disjoint?(5..1//-1, 6..9)\n      true\n      iex> Range.disjoint?(1..5, 5..9)\n      false\n      iex> Range.disjoint?(1..5, 2..7)\n      false\n\n  Steps are also considered when computing the ranges to be disjoint:\n\n      iex> Range.disjoint?(1..10//2, 2..10//2)\n      true\n\n      # First element in common is 29\n      iex> Range.disjoint?(1..100//14, 8..100//21)\n      false\n      iex> Range.disjoint?(57..-1//-14, 8..100//21)\n      false\n      iex> Range.disjoint?(1..100//14, 50..8//-21)\n      false\n      iex> Range.disjoint?(1..28//14, 8..28//21)\n      true\n\n      # First element in common is 14\n      iex> Range.disjoint?(2..28//3, 9..28//5)\n      false\n      iex> Range.disjoint?(26..2//-3, 29..9//-5)\n      false\n\n      # Starting from the back without alignment\n      iex> Range.disjoint?(27..11//-3, 30..0//-7)\n      true\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec disjoint?(t, t) :: boolean\n  def disjoint?(first1..last1//step1 = range1, first2..last2//step2 = range2) do\n    if size(range1) == 0 or size(range2) == 0 do\n      true\n    else\n      {first1, last1, step1} = normalize(first1, last1, step1)\n      {first2, last2, step2} = normalize(first2, last2, step2)\n\n      cond do\n        last2 < first1 or last1 < first2 ->\n          true\n\n        abs(step1) == 1 and abs(step2) == 1 ->\n          false\n\n        true ->\n          # We need to find the first intersection of two arithmetic\n          # progressions and see if they belong within the ranges\n          # https://math.stackexchange.com/questions/1656120/formula-to-find-the-first-intersection-of-two-arithmetic-progressions\n          {gcd, u, v} = Integer.extended_gcd(-step1, step2)\n\n          if rem(first2 - first1, gcd) == 0 do\n            c = first1 - first2 + step2 - step1\n            t1 = -c / step2 * u\n            t2 = -c / step1 * v\n            t = max(floor(t1) + 1, floor(t2) + 1)\n            x = div(c * u + t * step2, gcd) - 1\n            y = div(c * v + t * step1, gcd) - 1\n\n            x < 0 or first1 + x * step1 > last1 or\n              y < 0 or first2 + y * step2 > last2\n          else\n            true\n          end\n      end\n    end\n  end\n\n  @compile inline: [normalize: 3]\n  defp normalize(first, last, step) when first > last,\n    do: {first - abs(div(first - last, step) * step), first, -step}\n\n  defp normalize(first, last, step), do: {first, last, step}\n\n  @doc false\n  @deprecated \"Pattern match on first..last//step instead\"\n  def range?(%{__struct__: Range, first: first, last: last})\n      when is_integer(first) and is_integer(last),\n      do: true\n\n  def range?(_), do: false\nend\n"
  },
  {
    "path": "lib/elixir/lib/record/extractor.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Record.Extractor do\n  @moduledoc false\n\n  def extract(name, opts) do\n    extract_record(name, from_or_from_lib_file(opts))\n  end\n\n  def extract_all(opts) do\n    extract_all_records(from_or_from_lib_file(opts))\n  end\n\n  defp from_or_from_lib_file(opts) do\n    cond do\n      file = opts[:from] ->\n        {from_file(file), Keyword.delete(opts, :from)}\n\n      file = opts[:from_lib] ->\n        {from_lib_file(file), Keyword.delete(opts, :from_lib)}\n\n      true ->\n        raise ArgumentError, \"expected :from or :from_lib to be given as option\"\n    end\n  end\n\n  # Find file using the same lookup as the *include* attribute from Erlang modules.\n  defp from_file(file) do\n    file = String.to_charlist(file)\n\n    case :code.where_is_file(file) do\n      :non_existing -> file\n      realfile -> realfile\n    end\n  end\n\n  # Find file using the same lookup as the *include_lib* attribute from Erlang modules.\n  defp from_lib_file(file) do\n    [app | path] = :filename.split(String.to_charlist(file))\n\n    case :code.lib_dir(List.to_atom(app)) do\n      {:error, _} ->\n        raise ArgumentError, \"lib file #{file} could not be found\"\n\n      libpath ->\n        :filename.join([libpath | path])\n    end\n  end\n\n  # Retrieve the record with the given name from the given file\n  defp extract_record(name, {file, opts}) do\n    form = read_file(file, opts)\n    records = extract_records(form)\n\n    if record = List.keyfind(records, name, 0) do\n      parse_record(record, form)\n    else\n      raise ArgumentError,\n            \"no record #{name} found at #{file}. Or the record does not exist or \" <>\n              \"its entry is malformed or depends on other include files\"\n    end\n  end\n\n  # Retrieve all records from the given file\n  defp extract_all_records({file, opts}) do\n    form = read_file(file, opts)\n    records = extract_records(form)\n    for rec = {name, _fields} <- records, do: {name, parse_record(rec, form)}\n  end\n\n  # Parse the given file and extract all existent records.\n  defp extract_records(form) do\n    for {:attribute, _, :record, record} <- form, do: record\n  end\n\n  # Read a file and return its abstract syntax form that also\n  # includes record but with macros and other attributes expanded,\n  # such as \"-include(...)\" and \"-include_lib(...)\". This is done\n  # by using Erlang's epp.\n  defp read_file(file, opts) do\n    case :epp.parse_file(file, opts) do\n      {:ok, form} ->\n        form\n\n      other ->\n        raise \"error parsing file #{file}, got: #{inspect(other)}\"\n    end\n  end\n\n  # Parse a tuple with name and fields and returns a\n  # list of tuples where the first element is the field\n  # and the second is its default value.\n  defp parse_record({_name, fields}, form) do\n    cons = List.foldr(fields, {nil, 0}, fn f, acc -> {:cons, 0, parse_field(f), acc} end)\n    eval_record(cons, form)\n  end\n\n  defp parse_field({:typed_record_field, record_field, _type}) do\n    parse_field(record_field)\n  end\n\n  defp parse_field({:record_field, _, key}) do\n    {:tuple, 0, [key, {:atom, 0, :undefined}]}\n  end\n\n  defp parse_field({:record_field, _, key, value}) do\n    {:tuple, 0, [key, value]}\n  end\n\n  defp eval_record(cons, form) do\n    form = form ++ [{:function, 0, :hello, 0, [{:clause, 0, [], [], [cons]}]}]\n\n    {:function, 0, :hello, 0, [{:clause, 0, [], [], [record_ast]}]} =\n      :erl_expand_records.module(form, []) |> List.last()\n\n    {:value, record, _} = :erl_eval.expr(record_ast, [])\n    record\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/record.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Record do\n  @moduledoc \"\"\"\n  Module to work with, define, and import records.\n\n  Records are simply tuples where the first element is an atom:\n\n      iex> Record.is_record({User, \"john\", 27})\n      true\n\n  This module provides conveniences for working with records at\n  compilation time, where compile-time field names are used to\n  manipulate the tuples, providing fast operations on top of\n  the tuples' compact structure.\n\n  In Elixir, records are used mostly in two situations:\n\n    1. to work with short, internal data\n    2. to interface with Erlang records\n\n  The macros `defrecord/3` and `defrecordp/3` can be used to create records\n  while `extract/2` and `extract_all/1` can be used to extract records from\n  Erlang files.\n\n  ## Types\n\n  Types can be defined for tuples with the `record/2` construct (which is only\n  available in typespecs), with the record name as an atom and a keyword list\n  of fields and their types as argument:\n\n      defmodule MyModule do\n        require Record\n        Record.defrecord(:user, name: \"john\", age: 25)\n\n        @type user :: record(:user, name: String.t(), age: integer)\n        # expands to: \"@type user :: {:user, String.t(), integer}\"\n      end\n\n  ## Reflection\n\n  The record tag and its fields are stored as metadata in the \"Docs\" chunk\n  of the record definition macro. You can retrieve the documentation for\n  a module by calling `Code.fetch_docs/1`.\n  \"\"\"\n\n  @type extract_opts :: [\n          from: binary(),\n          from_lib: binary(),\n          includes: [binary()],\n          macros: keyword()\n        ]\n\n  @doc \"\"\"\n  Extracts record information from an Erlang file.\n\n  Returns a quoted expression containing the fields as a list\n  of tuples.\n\n  `name`, which is the name of the extracted record, is expected to be an atom\n  *at compile time*.\n\n  ## Options\n\n  This function requires one of the following options, which are exclusive to each\n  other (i.e., only one of them can be used in the same call):\n\n    * `:from` - (binary representing a path to a file) path to the Erlang file\n      that contains the record definition to extract; with this option, this\n      function uses the same path lookup used by the `-include` attribute used in\n      Erlang modules.\n\n    * `:from_lib` - (binary representing a path to a file) path to the Erlang\n      file that contains the record definition to extract; with this option,\n      this function uses the same path lookup used by the `-include_lib`\n      attribute used in Erlang modules.\n\n  It additionally accepts the following optional, non-exclusive options:\n\n    * `:includes` - (a list of directories as binaries) if the record being\n      extracted depends on relative includes, this option allows developers\n      to specify the directory where those relative includes exist.\n\n    * `:macros` - (keyword list of macro names and values) if the record\n      being extracted depends on the values of macros, this option allows\n      the value of those macros to be set.\n\n  These options are expected to be literals (including the binary values) at\n  compile time.\n\n  ## Examples\n\n      iex> Record.extract(:file_info, from_lib: \"kernel/include/file.hrl\")\n      [\n        size: :undefined,\n        type: :undefined,\n        access: :undefined,\n        atime: :undefined,\n        mtime: :undefined,\n        ctime: :undefined,\n        mode: :undefined,\n        links: :undefined,\n        major_device: :undefined,\n        minor_device: :undefined,\n        inode: :undefined,\n        uid: :undefined,\n        gid: :undefined\n      ]\n\n  \"\"\"\n  @spec extract(name :: atom, extract_opts) :: keyword\n  def extract(name, opts) when is_atom(name) and is_list(opts) do\n    Record.Extractor.extract(name, opts)\n  end\n\n  @doc \"\"\"\n  Extracts all records information from an Erlang file.\n\n  Returns a keyword list of `{record_name, fields}` tuples where `record_name`\n  is the name of an extracted record and `fields` is a list of `{field, value}`\n  tuples representing the fields for that record.\n\n  ## Options\n\n  Accepts the same options as listed for `Record.extract/2`.\n\n  \"\"\"\n  @spec extract_all(extract_opts) :: [{name :: atom, keyword}]\n  def extract_all(opts) when is_list(opts) do\n    Record.Extractor.extract_all(opts)\n  end\n\n  @doc \"\"\"\n  Checks if the given `data` is a record of kind `kind`.\n\n  This is implemented as a macro so it can be used in guard clauses.\n\n  ## Examples\n\n      iex> record = {User, \"john\", 27}\n      iex> Record.is_record(record, User)\n      true\n\n  \"\"\"\n  defguard is_record(data, kind)\n           when is_atom(kind) and is_tuple(data) and tuple_size(data) > 0 and\n                  elem(data, 0) == kind\n\n  @doc \"\"\"\n  Checks if the given `data` is a record.\n\n  This is implemented as a macro so it can be used in guard clauses.\n\n  ## Examples\n\n      Record.is_record({User, \"john\", 27})\n      #=> true\n\n      Record.is_record({})\n      #=> false\n\n  \"\"\"\n  defguard is_record(data)\n           when is_tuple(data) and tuple_size(data) > 0 and is_atom(elem(data, 0))\n\n  @doc \"\"\"\n  Defines a set of macros to create, access, and pattern match\n  on a record.\n\n  The name of the generated macros will be `name` (which has to be an\n  atom). `tag` is also an atom and is used as the \"tag\" for the record (i.e.,\n  the first element of the record tuple); by default (if `nil`), it's the same\n  as `name`. `kv` is a keyword list of `name: default_value` fields for the\n  new record.\n\n  The following macros are generated:\n\n    * `name/0` to create a new record with default values for all fields\n    * `name/1` to create a new record with the given fields and values,\n      to get the zero-based index of the given field in a record or to\n      convert the given record to a keyword list\n    * `name/2` to update an existing record with the given fields and values\n      or to access a given field in a given record\n\n  All these macros are public macros (as defined by `defmacro`).\n\n  See the \"Examples\" section for examples on how to use these macros.\n\n  ## Examples\n\n      defmodule User do\n        require Record\n        Record.defrecord(:user, name: \"meg\", age: \"25\")\n      end\n\n  In the example above, a set of macros named `user` but with different\n  arities will be defined to manipulate the underlying record.\n\n      # Import the module to make the user macros locally available\n      import User\n\n      # To create records\n      record = user()        #=> {:user, \"meg\", 25}\n      record = user(age: 26) #=> {:user, \"meg\", 26}\n\n      # To get a field from the record\n      user(record, :name) #=> \"meg\"\n\n      # To update the record\n      user(record, age: 26) #=> {:user, \"meg\", 26}\n\n      # To get the zero-based index of the field in record tuple\n      # (index 0 is occupied by the record \"tag\")\n      user(:name) #=> 1\n\n      # Convert a record to a keyword list\n      user(record) #=> [name: \"meg\", age: 26]\n\n  The generated macros can also be used in order to pattern match on records and\n  to bind variables during the match:\n\n      record = user() #=> {:user, \"meg\", 25}\n\n      user(name: name) = record\n      name #=> \"meg\"\n\n  By default, Elixir uses the record name as the first element of the tuple (the \"tag\").\n  However, a different tag can be specified when defining a record,\n  as in the following example, in which we use `Customer` as the second argument of `defrecord/3`:\n\n      defmodule User do\n        require Record\n        Record.defrecord(:user, Customer, name: nil)\n      end\n\n      require User\n      User.user() #=> {Customer, nil}\n\n  ## Defining extracted records with anonymous functions in the values\n\n  If a record defines an anonymous function in the default values, an\n  `ArgumentError` will be raised. This can happen unintentionally when defining\n  a record after extracting it from an Erlang library that uses anonymous\n  functions for defaults.\n\n      Record.defrecord(:my_rec, Record.extract(...))\n      ** (ArgumentError) invalid value for record field fun_field,\n          cannot escape #Function<12.90072148/2 in :erl_eval.expr/5>.\n\n  To work around this error, redefine the field with your own &M.f/a function,\n  like so:\n\n      defmodule MyRec do\n        require Record\n        Record.defrecord(:my_rec, Record.extract(...) |> Keyword.merge(fun_field: &__MODULE__.foo/2))\n        def foo(bar, baz), do: IO.inspect({bar, baz})\n      end\n\n  \"\"\"\n  defmacro defrecord(name, tag \\\\ nil, kv) do\n    quote bind_quoted: [name: name, tag: tag, kv: kv] do\n      tag = tag || name\n      fields = Record.__record__(__MODULE__, :defrecord, name, tag, kv)\n\n      @doc record: {tag, fields}\n      defmacro unquote(name)(args \\\\ []) do\n        Record.__access__(unquote(tag), unquote(fields), args, __CALLER__)\n      end\n\n      defmacro unquote(name)(record, args) do\n        Record.__access__(unquote(tag), unquote(fields), record, args, __CALLER__)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Same as `defrecord/3` but generates private macros.\n  \"\"\"\n  defmacro defrecordp(name, tag \\\\ nil, kv) do\n    quote bind_quoted: [name: name, tag: tag, kv: kv] do\n      tag = tag || name\n      fields = Record.__record__(__MODULE__, :defrecordp, name, tag, kv)\n\n      defmacrop unquote(name)(args \\\\ []) do\n        Record.__access__(unquote(tag), unquote(fields), args, __CALLER__)\n      end\n\n      defmacrop unquote(name)(record, args) do\n        Record.__access__(unquote(tag), unquote(fields), record, args, __CALLER__)\n      end\n    end\n  end\n\n  defp error_on_duplicate_record(module, name) do\n    defined_arity =\n      Enum.find(0..2, fn arity ->\n        Module.defines?(module, {name, arity})\n      end)\n\n    if defined_arity do\n      raise ArgumentError,\n            \"cannot define record #{inspect(name)} because a definition #{name}/#{defined_arity} already exists\"\n    end\n  end\n\n  defp warn_on_duplicate_key([]) do\n    :ok\n  end\n\n  defp warn_on_duplicate_key([{key, _} | [{key, _} | _] = rest]) do\n    IO.warn(\"duplicate key #{inspect(key)} found in record\")\n    warn_on_duplicate_key(rest)\n  end\n\n  defp warn_on_duplicate_key([_ | rest]) do\n    warn_on_duplicate_key(rest)\n  end\n\n  # Callback invoked from the record/2 macro.\n  @doc false\n  def __record__(module, kind, name, tag, kv) do\n    error_on_duplicate_record(module, name)\n\n    fields = fields(kind, kv)\n\n    # TODO: Remove me on Elixir v2.0\n    Module.register_attribute(module, :__records__, accumulate: true)\n\n    Module.put_attribute(module, :__records__, %{\n      kind: kind,\n      name: name,\n      tag: tag,\n      fields: :lists.map(&elem(&1, 0), fields)\n    })\n\n    # TODO: Make it raise on v2.0\n    warn_on_duplicate_key(:lists.keysort(1, fields))\n    fields\n  end\n\n  # Normalizes of record fields to have default values.\n  defp fields(kind, fields) do\n    normalizer_fun = fn\n      {key, value} when is_atom(key) ->\n        try do\n          Macro.escape(value)\n        rescue\n          e in [ArgumentError] ->\n            raise ArgumentError, \"invalid value for record field #{key}, \" <> Exception.message(e)\n        else\n          value -> {key, value}\n        end\n\n      key when is_atom(key) ->\n        {key, nil}\n\n      other ->\n        raise ArgumentError, \"#{kind} fields must be atoms, got: #{inspect(other)}\"\n    end\n\n    :lists.map(normalizer_fun, fields)\n  end\n\n  # Callback invoked from record/0 and record/1 macros.\n  @doc false\n  def __access__(tag, fields, args, caller) do\n    cond do\n      is_atom(args) ->\n        index(tag, fields, args)\n\n      Keyword.keyword?(args) ->\n        create(tag, fields, args, caller)\n\n      true ->\n        fields = Macro.escape(fields)\n\n        case Macro.expand(args, caller) do\n          {:{}, _, [^tag | list]} when length(list) == length(fields) ->\n            record = List.to_tuple([tag | list])\n            Record.__keyword__(tag, fields, record)\n\n          {^tag, arg} when length(fields) == 1 ->\n            Record.__keyword__(tag, fields, {tag, arg})\n\n          _ ->\n            quote(do: Record.__keyword__(unquote(tag), unquote(fields), unquote(args)))\n        end\n    end\n  end\n\n  # Callback invoked from the record/2 macro.\n  @doc false\n  def __access__(tag, fields, record, args, caller) do\n    cond do\n      is_atom(args) ->\n        get(tag, fields, record, args)\n\n      Keyword.keyword?(args) ->\n        update(tag, fields, record, args, caller)\n\n      true ->\n        raise ArgumentError,\n              \"expected arguments to be a compile time atom or a keyword list, got: \" <>\n                Macro.to_string(args)\n    end\n  end\n\n  # Gets the index of field.\n  defp index(tag, fields, field) do\n    find_index(fields, field, 1) ||\n      raise ArgumentError, \"record #{inspect(tag)} does not have the key: #{inspect(field)}\"\n  end\n\n  # Creates a new record with the given default fields and keyword values.\n  defp create(tag, fields, keyword, caller) do\n    # Using {} here is safe, since it's not valid AST\n    default = if Macro.Env.in_match?(caller), do: {:_, [], nil}, else: {}\n    {default, keyword} = Keyword.pop(keyword, :_, default)\n    {keyword, exprs} = hoist_expressions(keyword, caller)\n\n    {elements, remaining} =\n      Enum.map_reduce(fields, keyword, fn {key, field_default}, remaining ->\n        case Keyword.pop(remaining, key, default) do\n          {{}, remaining} -> {Macro.escape(field_default), remaining}\n          {default, remaining} -> {default, remaining}\n        end\n      end)\n\n    case remaining do\n      [] ->\n        quote(do: {unquote(tag), unquote_splicing(elements)})\n        |> maybe_prepend_reversed_exprs(exprs)\n\n      [{key, _} | _] ->\n        raise ArgumentError, \"record #{inspect(tag)} does not have the key: #{inspect(key)}\"\n    end\n  end\n\n  # Updates a record given by var with the given keyword.\n  defp update(tag, fields, var, keyword, caller) do\n    if Macro.Env.in_match?(caller) do\n      raise ArgumentError, \"cannot invoke update style macro inside match\"\n    end\n\n    {keyword, exprs} = hoist_expressions(keyword, caller)\n\n    if Keyword.has_key?(keyword, :_) do\n      message = \"updating a record with a default (:_) is equivalent to creating a new record\"\n      IO.warn(message, caller)\n      create(tag, fields, keyword, caller)\n    else\n      updates =\n        Enum.map(keyword, fn {key, value} ->\n          if index = find_index(fields, key, 2) do\n            {index, value}\n          else\n            raise ArgumentError, \"record #{inspect(tag)} does not have the key: #{inspect(key)}\"\n          end\n        end)\n\n      build_update(updates, var) |> maybe_prepend_reversed_exprs(exprs)\n    end\n  end\n\n  defp hoist_expressions(keyword, %{context: nil, module: module}) do\n    Enum.map_reduce(keyword, [], fn {key, expr}, acc ->\n      if simple_argument?(expr) do\n        {{key, expr}, acc}\n      else\n        var = Macro.unique_var(key, module)\n        {{key, var}, [{:=, [], [var, expr]} | acc]}\n      end\n    end)\n  end\n\n  defp hoist_expressions(keyword, _), do: {keyword, []}\n\n  defp maybe_prepend_reversed_exprs(expr, []),\n    do: expr\n\n  defp maybe_prepend_reversed_exprs(expr, exprs),\n    do: {:__block__, [], :lists.reverse([expr | exprs])}\n\n  defp build_update(updates, initial) do\n    updates\n    |> Enum.sort(fn {left, _}, {right, _} -> right <= left end)\n    |> Enum.reduce(initial, fn {key, value}, acc ->\n      quote(do: :erlang.setelement(unquote(key), unquote(acc), unquote(value)))\n    end)\n  end\n\n  defp simple_argument?({name, _, ctx}) when is_atom(name) and is_atom(ctx), do: true\n  defp simple_argument?(other), do: Macro.quoted_literal?(other)\n\n  # Gets a record key from the given var.\n  defp get(tag, fields, var, key) do\n    index =\n      find_index(fields, key, 2) ||\n        raise ArgumentError, \"record #{inspect(tag)} does not have the key: #{inspect(key)}\"\n\n    quote do\n      :erlang.element(unquote(index), unquote(var))\n    end\n  end\n\n  defp find_index([{k, _} | _], k, i), do: i\n  defp find_index([{_, _} | t], k, i), do: find_index(t, k, i + 1)\n  defp find_index([], _k, _i), do: nil\n\n  # Returns a keyword list of the record\n  @doc false\n  def __keyword__(tag, fields, record) do\n    if is_record(record, tag) do\n      [_tag | values] = Tuple.to_list(record)\n\n      case join_keyword(fields, values, []) do\n        kv when is_list(kv) ->\n          kv\n\n        expected_fields ->\n          raise ArgumentError,\n                \"expected argument to be a #{inspect(tag)} record with \" <>\n                  \"#{expected_fields} fields, got: \" <> inspect(record)\n      end\n    else\n      raise ArgumentError,\n            \"expected argument to be a literal atom, literal keyword or \" <>\n              \"a #{inspect(tag)} record, got runtime: \" <> inspect(record)\n    end\n  end\n\n  # Returns a keyword list, or expected number of fields on size mismatch\n  defp join_keyword([{field, _default} | fields], [value | values], acc),\n    do: join_keyword(fields, values, [{field, value} | acc])\n\n  defp join_keyword([], [], acc), do: :lists.reverse(acc)\n  defp join_keyword(rest_fields, _rest_values, acc), do: length(acc) + length(rest_fields)\nend\n"
  },
  {
    "path": "lib/elixir/lib/regex.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Regex do\n  # TODO: Remove the \"Starting from Erlang/OTP 28\" part in the Modifiers'\n  #       section once Erlang/OTP 28+ is exclusively supported.\n  @moduledoc ~S\"\"\"\n  Provides regular expressions for Elixir.\n\n  Regex is based on PCRE (Perl Compatible Regular Expressions) and\n  built on top of Erlang's `:re` module. More information can be found\n  in the [`:re` module documentation](`:re`).\n\n  Regular expressions in Elixir can be created using the sigils\n  `~r` (see `sigil_r/2`):\n\n      # A simple regular expression that matches foo anywhere in the string\n      ~r/foo/\n\n      # A regular expression with case insensitive and Unicode options\n      ~r/foo/iu\n\n  A Regex is represented internally as the `Regex` struct. Therefore,\n  `%Regex{}` can be used whenever there is a need to match on them.\n  Keep in mind that all of the structs fields are private. And since\n  regexes are compiled, there is no guarantee two regular expressions\n  from the same source are equal, for example:\n\n      ~r/(?<foo>.)(?<bar>.)/ == ~r/(?<foo>.)(?<bar>.)/\n\n  may return `true` or `false` depending on your machine, endianness,\n  available optimizations and others. You can, however, retrieve the source\n  of a compiled regular expression by accessing the `source` field, and then\n  compare those directly:\n\n      ~r/(?<foo>.)(?<bar>.)/.source == ~r/(?<foo>.)(?<bar>.)/.source\n\n  ## Escapes\n\n  Escape sequences are split into two categories.\n\n  ### Non-printing characters\n\n    * `\\a` - Alarm, that is, the BEL character (hex 07)\n    * `\\e` - Escape (hex 1B)\n    * `\\f` - Form feed (hex 0C)\n    * `\\n` - Line feed (hex 0A)\n    * `\\r` - Carriage return (hex 0D)\n    * `\\t` - Tab (hex 09)\n    * `\\xhh` - Character with hex code hh\n    * `\\x{hhh..}` - Character with hex code hhh..\n\n  `\\u` and `\\U` are not supported. Other escape sequences, such as `\\ddd`\n  for octals, are supported but discouraged.\n\n  ### Generic character types\n\n    * `\\d` - Any decimal digit\n    * `\\D` - Any character that is not a decimal digit\n    * `\\h` - Any horizontal whitespace character\n    * `\\H` - Any character that is not a horizontal whitespace character\n    * `\\s` - Any whitespace character\n    * `\\S` - Any character that is not a whitespace character\n    * `\\v` - Any vertical whitespace character\n    * `\\V` - Any character that is not a vertical whitespace character\n    * `\\w` - Any \"word\" character\n    * `\\W` - Any \"non-word\" character\n\n  ## Modifiers\n\n  The modifiers available when creating a Regex are:\n\n    * `:unicode` (u) - enables Unicode specific patterns like `\\p` and causes\n      character classes like `\\w`, `\\W`, `\\s`, and the like to also match on Unicode\n      (see examples below in \"Character classes\"). It expects valid Unicode\n      strings to be given on match\n\n    * `:caseless` (i) - adds case insensitivity\n\n    * `:dotall` (s) - causes dot to match newlines and also sets newline to\n      `(*ANYCRLF)`.\\\n      The new line setting, as described in the [`:re` documentation](`:re`),\n      can be overridden by starting the regular expression pattern with:\n      * `(*CR)` - carriage return\n      * `(*LF)` - line feed\n      * `(*CRLF)` - carriage return, followed by line feed\n      * `(*ANYCRLF)` - any of the three above\n      * `(*ANY)` - all Unicode newline sequences\n      * _Starting from Erlang/OTP 28, `(*NUL)` - the NUL character (binary zero)_\n\n    * `:multiline` (m) - causes `^` and `$` to mark the beginning and end of\n      each line; use `\\A` and `\\z` to match the end or beginning of the string\n\n    * `:extended` (x) - whitespace characters are ignored except when escaped\n      or within `[..]`, and allow `#` to delimit comments\n\n    * `:firstline` (f) - forces the unanchored pattern to match before or at the\n      first newline, though the matched text may continue over the newline\n\n    * `:ungreedy` (U) - inverts the \"greediness\" of the regexp\n      (the previous `r` option is deprecated in favor of `U`)\n\n    * `:export` (E) (since Elixir 1.19.3) - uses an exported pattern\n      which can be shared across nodes or passed through config, at the cost of a runtime\n      overhead to re-import it every time it is executed.\n      This modifier only has an effect starting on Erlang/OTP 28, and it is ignored\n      on older versions (i.e. `~r/foo/E == ~r/foo/`). This is because patterns cannot\n      and do not need to be exported in order to be shared in these versions.\n\n  ## Captures\n\n  Many functions in this module handle what to capture in a regex\n  match via the `:capture` option. The supported values are:\n\n    * `:all` - all captured subpatterns including the complete matching string\n      (this is the default)\n\n    * `:first` - only the first captured subpattern, which is always the\n      complete matching part of the string; all explicitly captured subpatterns\n      are discarded\n\n    * `:all_but_first` - all but the first matching subpattern, i.e. all\n      explicitly captured subpatterns, but not the complete matching part of\n      the string\n\n    * `:none` - does not return matching subpatterns at all\n\n    * `:all_names` - captures all named subpattern matches in the Regex as a list\n      ordered **alphabetically** by the names of the subpatterns\n\n    * `list(binary | atom)` - a list of named captures to capture\n\n  ## Character classes\n\n  Regex supports several built in named character classes. These are used by\n  enclosing the class name in `[: :]` inside a group. For example:\n\n      iex> String.match?(\"123\", ~r/^[[:alnum:]]+$/)\n      true\n      iex> String.match?(\"123 456\", ~r/^[[:alnum:][:blank:]]+$/)\n      true\n\n  The supported class names are:\n\n    * alnum - Letters and digits\n    * alpha - Letters\n    * blank - Space or tab only\n    * cntrl - Control characters\n    * digit - Decimal digits (same as \\\\d)\n    * graph - Printing characters, excluding space\n    * lower - Lowercase letters\n    * print - Printing characters, including space\n    * punct - Printing characters, excluding letters, digits, and space\n    * space - Whitespace (the same as \\s from PCRE 8.34)\n    * upper - Uppercase letters\n    * word  - \"Word\" characters (same as \\w)\n    * xdigit - Hexadecimal digits\n\n  There is another character class, `ascii`, that erroneously matches\n  Latin-1 characters instead of the 0-127 range specified by POSIX. This\n  cannot be fixed without altering the behavior of other classes, so we\n  recommend matching the range with `[\\\\0-\\x7f]` instead.\n\n  Note the behavior of those classes may change according to the Unicode\n  and other modifiers:\n\n      iex> String.match?(\"josé\", ~r/^[[:lower:]]+$/)\n      false\n      iex> String.match?(\"josé\", ~r/^[[:lower:]]+$/u)\n      true\n      iex> Regex.replace(~r/\\s/, \"Unicode\\u00A0spaces\", \"-\")\n      \"Unicode spaces\"\n      iex> Regex.replace(~r/\\s/u, \"Unicode\\u00A0spaces\", \"-\")\n      \"Unicode-spaces\"\n\n  \"\"\"\n\n  defstruct re_pattern: nil, source: \"\", opts: []\n\n  @type t :: %__MODULE__{re_pattern: term, source: binary, opts: [term]}\n\n  @type named_captures_opts :: [\n          return: :binary | :index,\n          offset: non_neg_integer()\n        ]\n\n  defmodule CompileError do\n    @moduledoc \"\"\"\n    An exception raised when a regular expression could not be compiled.\n    \"\"\"\n\n    defexception message: \"regex could not be compiled\"\n  end\n\n  @doc \"\"\"\n  Compiles the regular expression.\n\n  The given options can either be a binary with the characters\n  representing the same regex options given to the\n  `~r` (see `sigil_r/2`) sigil, or a list of options, as\n  expected by the Erlang's [`:re`](`:re`) module.\n\n  It returns `{:ok, regex}` in case of success,\n  `{:error, reason}` otherwise.\n\n  ## Examples\n\n      Regex.compile(\"foo\")\n      #=> {:ok, ~r/foo/}\n\n      Regex.compile(\"foo\", \"i\")\n      #=> {:ok, ~r/foo/i}\n\n      Regex.compile(\"*foo\")\n      #=> {:error, {~c\"quantifier does not follow a repeatable item\", 0}}\n\n  \"\"\"\n  @spec compile(binary, binary | [term]) :: {:ok, t} | {:error, term}\n  def compile(source, opts \\\\ \"\") when is_binary(source) do\n    do_compile(source, opts)\n  end\n\n  defp do_compile(source, opts) when is_binary(opts) do\n    case translate_options(opts, []) do\n      {:error, rest} ->\n        {:error, {:invalid_option, rest}}\n\n      translated_opts ->\n        do_compile(source, translated_opts)\n    end\n  end\n\n  defp do_compile(source, opts) when is_list(opts) do\n    case :re.compile(source, opts) do\n      {:ok, re_pattern} ->\n        {:ok, %Regex{re_pattern: re_pattern, source: source, opts: opts}}\n\n      error ->\n        error\n    end\n  end\n\n  @doc \"\"\"\n  Compiles the regular expression and raises `Regex.CompileError` in case of errors.\n  \"\"\"\n  @spec compile!(binary, binary | [term]) :: t\n  def compile!(source, options \\\\ \"\") when is_binary(source) do\n    case compile(source, options) do\n      {:ok, regex} -> regex\n      {:error, {reason, at}} -> raise Regex.CompileError, \"#{reason} at position #{at}\"\n    end\n  end\n\n  @doc \"\"\"\n  Recompiles the existing regular expression if necessary.\n\n  This checks the version stored in the regular expression\n  and recompiles the regex in case of version mismatch.\n  \"\"\"\n  # TODO: Deprecate on Elixir v1.22\n  @doc deprecated: \"It can be removed and it has no effect\"\n  @doc since: \"1.4.0\"\n  def recompile(%Regex{} = regex) do\n    {:ok, regex}\n  end\n\n  @doc \"\"\"\n  Recompiles the existing regular expression and raises `Regex.CompileError` in case of errors.\n  \"\"\"\n  # TODO: Deprecate on Elixir v1.22\n  @doc deprecated: \"It can be removed and it has no effect\"\n  @doc since: \"1.4.0\"\n  def recompile!(regex) do\n    regex\n  end\n\n  @doc \"\"\"\n  Imports a `regex` that has been exported, otherwise returns the `regex` unchanged.\n\n  This means it will lose the ability to be sent across nodes or passed through config,\n  but will be faster since it won't need to be imported on the fly every time it is executed.\n\n  Exported regexes only exist on OTP 28, so this has no effect on older versions.\n\n  ## Examples\n\n      Regex.import(~r/foo/E)\n      ~r/foo/\n\n      Regex.import(~r/foo/)\n      ~r/foo/\n\n  \"\"\"\n  @doc since: \"1.20.0\"\n  @spec import(t) :: t\n  def import(%Regex{re_pattern: re_pattern} = regex) do\n    case re_pattern do\n      {:re_exported_pattern, _, _, _, _} ->\n        %{regex | re_pattern: :re.import(re_pattern), opts: regex.opts -- [:export]}\n\n      _ ->\n        regex\n    end\n  end\n\n  @doc \"\"\"\n  Returns the version of the underlying Regex engine.\n  \"\"\"\n  # TODO: Deprecate on Elixir v1.22\n  @doc deprecated: \"Use :re.version() instead\"\n  @doc since: \"1.4.0\"\n  def version do\n    {:re.version(), :erlang.system_info(:endian)}\n  end\n\n  @doc \"\"\"\n  Returns a boolean indicating whether there was a match or not.\n\n  ## Examples\n\n      iex> Regex.match?(~r/foo/, \"foo\")\n      true\n\n      iex> Regex.match?(~r/foo/, \"bar\")\n      false\n\n  Elixir also provides text-based match operator `=~/2` and function `String.match?/2` as\n  an alternative to test strings against regular expressions and\n  strings.\n  \"\"\"\n  @spec match?(t, String.t()) :: boolean\n  def match?(%Regex{} = regex, string) when is_binary(string) do\n    safe_run(regex, string, [{:capture, :none}]) == :match\n  end\n\n  @doc false\n  @deprecated \"Use Kernel.is_struct(term, Regex) or pattern match on %Regex{} instead\"\n  def regex?(term)\n  def regex?(%Regex{}), do: true\n  def regex?(_), do: false\n\n  @doc \"\"\"\n  Runs the regular expression against the given string until the first match.\n  It returns a list with all captures or `nil` if no match occurred.\n\n  ## Options\n\n    * `:return` - when set to `:index`, returns byte index and match length.\n      Defaults to `:binary`.\n    * `:capture` - what to capture in the result. See the [\"Captures\" section](#module-captures)\n      to see the possible capture values.\n    * `:offset` - (since v1.12.0) specifies the starting offset to match in the given string.\n      Defaults to `0`.\n\n  ## Examples\n\n      iex> Regex.run(~r/c(d)/, \"abcd\")\n      [\"cd\", \"d\"]\n\n      iex> Regex.run(~r/e/, \"abcd\")\n      nil\n\n      iex> Regex.run(~r/c(d)/, \"abcd\", return: :index)\n      [{2, 2}, {3, 1}]\n\n      iex> Regex.run(~r/c(d)/, \"abcd\", capture: :first)\n      [\"cd\"]\n\n      iex> Regex.run(~r/c(?<foo>d)/, \"abcd\", capture: [\"foo\", \"bar\"])\n      [\"d\", \"\"]\n\n  \"\"\"\n  @spec run(t, binary, capture_opts) :: nil | [binary] | [{integer, integer}]\n  def run(regex, string, options \\\\ [])\n\n  def run(%Regex{} = regex, string, options) when is_binary(string) do\n    return = Keyword.get(options, :return, :binary)\n    captures = Keyword.get(options, :capture, :all)\n    offset = Keyword.get(options, :offset, 0)\n\n    case safe_run(regex, string, [{:capture, captures, return}, {:offset, offset}]) do\n      :nomatch -> nil\n      :match -> []\n      {:match, results} -> results\n    end\n  end\n\n  @doc \"\"\"\n  Returns the given captures as a map or `nil` if no captures are found.\n\n  ## Options\n\n    * `:return` - when set to `:index`, returns byte index and match length.\n      Defaults to `:binary`.\n    * `:offset` - (since v1.12.0) specifies the starting offset to match in the given string.\n      Defaults to `0`.\n\n  ## Examples\n\n      iex> Regex.named_captures(~r/c(?<foo>d)/, \"abcd\")\n      %{\"foo\" => \"d\"}\n\n      iex> Regex.named_captures(~r/a(?<foo>b)c(?<bar>d)/, \"abcd\")\n      %{\"bar\" => \"d\", \"foo\" => \"b\"}\n\n      iex> Regex.named_captures(~r/a(?<foo>b)c(?<bar>d)/, \"efgh\")\n      nil\n\n  You can also retrieve indexes from the named captures. This is particularly\n  useful if you want to know if a named capture matched or not:\n\n      iex> Regex.named_captures(~r/a(?<foo>b)c(?<bar>d)?/, \"abc\", return: :index)\n      %{\"bar\" => {-1, 0}, \"foo\" => {1, 1}}\n\n  You can then use `binary_part/3` to fetch the relevant part from the given string.\n  \"\"\"\n  @spec named_captures(t, String.t(), named_captures_opts) :: map | nil\n  def named_captures(regex, string, options \\\\ []) when is_binary(string) do\n    names = names(regex)\n    options = Keyword.put(options, :capture, names)\n    results = run(regex, string, options)\n    if results, do: Enum.zip(names, results) |> Enum.into(%{})\n  end\n\n  @doc \"\"\"\n  Returns the underlying `re_pattern` in the regular expression.\n  \"\"\"\n  @spec re_pattern(t) :: term\n  def re_pattern(%Regex{re_pattern: compiled}) do\n    compiled\n  end\n\n  @doc \"\"\"\n  Returns the regex source as a binary.\n\n  ## Examples\n\n      iex> Regex.source(~r/foo/)\n      \"foo\"\n\n  \"\"\"\n  @spec source(t) :: String.t()\n  def source(%Regex{source: source}) do\n    source\n  end\n\n  @doc \"\"\"\n  Returns the regex options.\n\n  See the documentation of `Regex.compile/2` for more information.\n\n  ## Examples\n\n      iex> Regex.opts(~r/foo/m)\n      [:multiline]\n\n      iex> Regex.opts(Regex.compile!(\"foo\", [:caseless]))\n      [:caseless]\n\n  \"\"\"\n  @spec opts(t) :: [term]\n  def opts(%Regex{opts: opts}) do\n    opts\n  end\n\n  @doc \"\"\"\n  Returns the pattern as an embeddable string.\n\n  If the pattern was compiled with an option which cannot be represented\n  as an embeddable modifier in the current version of PCRE and strict is true\n  (the default) then an ArgumentError exception will be raised.\n\n  When the `:strict` option is false the pattern will be returned as though\n  any offending options had not be used and the function will not raise any\n  exceptions.\n\n  Embeddable modifiers/options are currently:\n\n    * 'i' - `:caseless`\n    * 'm' - `:multiline`\n    * 's' - `:dotall, {:newline, :anycrlf}`\n    * 'x' - `:extended`\n\n  Unembeddable modifiers are:\n\n    * 'f' - `:firstline`\n    * 'U' - `:ungreedy`\n    * 'u' - `:unicode, :ucp`\n\n  Any other regex compilation option not listed here is considered unembeddable\n  and will raise an exception unless the `:strict` option is false.\n\n  ## Examples\n      iex> Regex.to_embed(~r/foo/)\n      \"(?-imsx:foo)\"\n\n      iex> Regex.to_embed(~r/^foo/m)\n      \"(?m-isx:^foo)\"\n\n      iex> Regex.to_embed(~r/foo # comment/ix)\n      \"(?ix-ms:foo # comment\\\\n)\"\n\n      iex> Regex.to_embed(~r/foo/iu)\n      ** (ArgumentError) regex compiled with options [:ucp, :unicode] which cannot be represented as an embedded pattern in this version of PCRE\n\n      iex> Regex.to_embed(~r/foo/imsxu, strict: false)\n      \"(?imsx:foo\\\\n)\"\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec to_embed(t, strict: boolean()) :: String.t()\n  def to_embed(%Regex{source: source, opts: regex_opts}, embed_opts \\\\ []) do\n    strict = Keyword.get(embed_opts, :strict, true)\n\n    modifiers =\n      case embeddable_modifiers(regex_opts) do\n        {:ok, modifiers} ->\n          modifiers\n\n        {:error, modifiers, untranslatable} ->\n          if strict do\n            raise ArgumentError,\n                  \"regex compiled with options #{inspect(untranslatable)} which cannot be \" <>\n                    \"represented as an embedded pattern in this version of PCRE\"\n          else\n            modifiers\n          end\n      end\n\n    disabled = [?i, ?m, ?s, ?x] -- modifiers\n\n    disabled = if disabled != [], do: \"-#{disabled}\", else: \"\"\n\n    # Future proof option ordering consistency by sorting\n    modifiers = Enum.sort(modifiers)\n\n    nl = if Enum.member?(regex_opts, :extended), do: \"\\n\", else: \"\"\n\n    \"(?#{modifiers}#{disabled}:#{source}#{nl})\"\n  end\n\n  @doc \"\"\"\n  Returns a list of names in the regex.\n\n  ## Examples\n\n      iex> Regex.names(~r/(?<foo>bar)/)\n      [\"foo\"]\n\n  \"\"\"\n  @spec names(t) :: [String.t()]\n  def names(%Regex{re_pattern: re_pattern}) do\n    {:namelist, names} = :re.inspect(maybe_import_pattern(re_pattern), :namelist)\n    names\n  end\n\n  @doc ~S\"\"\"\n  Same as `run/3` but returns all non-overlapping matches of the regular expression.\n\n  A list of lists is returned, where each entry in the primary list represents a\n  match and each entry in the secondary list represents the captured contents.\n\n  ## Options\n\n    * `:return` - when set to `:index`, returns byte index and match length.\n      Defaults to `:binary`.\n    * `:capture` - what to capture in the result. See the [\"Captures\" section](#module-captures)\n      to see the possible capture values.\n    * `:offset` - (since v1.12.0) specifies the starting offset to match in the given string.\n      Defaults to `0`.\n\n  ## Examples\n\n      iex> Regex.scan(~r/c(d|e)/, \"abcd abce\")\n      [[\"cd\", \"d\"], [\"ce\", \"e\"]]\n\n      iex> Regex.scan(~r/c(?:d|e)/, \"abcd abce\")\n      [[\"cd\"], [\"ce\"]]\n\n      iex> Regex.scan(~r/e/, \"abcd\")\n      []\n\n      iex> Regex.scan(~r/ab|bc|cd/, \"abcd\")\n      [[\"ab\"], [\"cd\"]]\n\n      iex> Regex.scan(~r/ab|bc|cd/, \"abbccd\")\n      [[\"ab\"], [\"bc\"], [\"cd\"]]\n\n      iex> Regex.scan(~r/\\p{Sc}/u, \"$, £, and €\")\n      [[\"$\"], [\"£\"], [\"€\"]]\n\n      iex> Regex.scan(~r/=+/, \"=ü†ƒ8===\", return: :index)\n      [[{0, 1}], [{9, 3}]]\n\n      iex> Regex.scan(~r/c(d|e)/, \"abcd abce\", capture: :first)\n      [[\"cd\"], [\"ce\"]]\n\n  \"\"\"\n  @spec scan(t(), String.t(), capture_opts) :: [[String.t()]] | [[{integer(), integer()}]]\n  def scan(regex, string, options \\\\ [])\n\n  def scan(%Regex{} = regex, string, options) when is_binary(string) do\n    return = Keyword.get(options, :return, :binary)\n    captures = Keyword.get(options, :capture, :all)\n    offset = Keyword.get(options, :offset, 0)\n    options = [{:capture, captures, return}, :global, {:offset, offset}]\n\n    case safe_run(regex, string, options) do\n      :match -> []\n      :nomatch -> []\n      {:match, results} -> results\n    end\n  end\n\n  defp safe_run(%Regex{re_pattern: re_pattern} = regex, string, options) do\n    # TODO: Remove me when Erlang/OTP 28+ is required\n    # This allows regexes precompiled on Erlang/OTP 27- to work on Erlang/OTP 28+\n    with true <- :erlang.system_info(:otp_release) >= [?2, ?8],\n         {:re_pattern, _, _, _, <<_::bitstring>>} <- re_pattern do\n      %Regex{source: source, opts: compile_opts} = regex\n      :re.run(string, source, compile_opts ++ options)\n    else\n      _ -> :re.run(string, maybe_import_pattern(re_pattern), options)\n    end\n  end\n\n  @compile {:inline, maybe_import_pattern: 1}\n  @compile {:no_warn_undefined, {:re, :import, 1}}\n  defp maybe_import_pattern({:re_exported_pattern, _, _, _, _} = exported),\n    do: :re.import(exported)\n\n  defp maybe_import_pattern(pattern), do: pattern\n\n  @typedoc \"\"\"\n  Options for regex functions that capture matches.\n  \"\"\"\n  @type capture_opts :: [\n          return: :binary | :index,\n          capture: :all | :first | :all_but_first | :none | :all_names | [binary() | atom()],\n          offset: non_neg_integer()\n        ]\n\n  @typedoc \"\"\"\n  Options for `split/3`.\n  \"\"\"\n  @type split_opts :: [\n          parts: pos_integer() | :infinity,\n          trim: boolean(),\n          on: :first | :all | :all_but_first | :none | :all_names | [atom() | integer()],\n          include_captures: boolean()\n        ]\n\n  @doc \"\"\"\n  Splits the given target based on the given pattern and in the given number of\n  parts.\n\n  ## Options\n\n    * `:parts` - when specified, splits the string into the given number of\n      parts. If not specified, `:parts` defaults to `:infinity`, which will\n      split the string into the maximum number of parts possible based on the\n      given pattern.\n\n    * `:trim` - when `true`, removes empty strings (`\"\"`) from the result.\n      Defaults to `false`.\n\n    * `:on` - specifies which captures to split the string on, and in what\n      order. Defaults to `:first` which means captures inside the regex do not\n      affect the splitting process. See the [\"Captures\" section](#module-captures)\n      to see the possible capture values.\n\n    * `:include_captures` - when `true`, includes in the result the matches of\n      the regular expression. The matches are not counted towards the maximum\n      number of parts if combined with the `:parts` option. Defaults to `false`.\n\n  ## Examples\n\n      iex> Regex.split(~r/-/, \"a-b-c\")\n      [\"a\", \"b\", \"c\"]\n\n      iex> Regex.split(~r/-/, \"a-b-c\", parts: 2)\n      [\"a\", \"b-c\"]\n\n      iex> Regex.split(~r/-/, \"abc\")\n      [\"abc\"]\n\n      iex> Regex.split(~r//, \"abc\")\n      [\"\", \"a\", \"b\", \"c\", \"\"]\n\n      iex> Regex.split(~r/a(?<second>b)c/, \"abc\")\n      [\"\", \"\"]\n\n      iex> Regex.split(~r/a(?<second>b)c/, \"abc\", on: [:second])\n      [\"a\", \"c\"]\n\n      iex> Regex.split(~r/(x)/, \"Elixir\", include_captures: true)\n      [\"Eli\", \"x\", \"ir\"]\n\n      iex> Regex.split(~r/a(?<second>b)c/, \"abc\", on: [:second], include_captures: true)\n      [\"a\", \"b\", \"c\"]\n\n      iex> Regex.split(~r/-/, \"-a-b--c\", trim: true)\n      [\"a\", \"b\", \"c\"]\n\n  \"\"\"\n  @spec split(t, String.t(), split_opts) :: [String.t()]\n  def split(regex, string, options \\\\ [])\n\n  def split(%Regex{}, \"\", opts) do\n    if Keyword.get(opts, :trim, false) do\n      []\n    else\n      [\"\"]\n    end\n  end\n\n  def split(%Regex{} = regex, string, opts)\n      when is_binary(string) and is_list(opts) do\n    on = Keyword.get(opts, :on, :first)\n\n    case safe_run(regex, string, [:global, capture: on]) do\n      {:match, matches} ->\n        index = parts_to_index(Keyword.get(opts, :parts, :infinity))\n        trim = Keyword.get(opts, :trim, false)\n        include_captures = Keyword.get(opts, :include_captures, false)\n        do_split(matches, string, 0, index, trim, include_captures)\n\n      :match ->\n        [string]\n\n      :nomatch ->\n        [string]\n    end\n  end\n\n  defp parts_to_index(:infinity), do: 0\n  defp parts_to_index(n) when is_integer(n) and n > 0, do: n\n\n  defp do_split(_, string, offset, _counter, true, _with_captures)\n       when byte_size(string) <= offset do\n    []\n  end\n\n  defp do_split(_, string, offset, 1, _trim, _with_captures),\n    do: [binary_part(string, offset, byte_size(string) - offset)]\n\n  defp do_split([], string, offset, _counter, _trim, _with_captures),\n    do: [binary_part(string, offset, byte_size(string) - offset)]\n\n  defp do_split([[{pos, _} | h] | t], string, offset, counter, trim, with_captures)\n       when pos - offset < 0 do\n    do_split([h | t], string, offset, counter, trim, with_captures)\n  end\n\n  defp do_split([[] | t], string, offset, counter, trim, with_captures),\n    do: do_split(t, string, offset, counter, trim, with_captures)\n\n  defp do_split([[{pos, length} | h] | t], string, offset, counter, trim, true) do\n    new_offset = pos + length\n    keep = pos - offset\n\n    <<_::binary-size(^offset), part::binary-size(^keep), match::binary-size(^length), _::binary>> =\n      string\n\n    cond do\n      keep == 0 and (offset != 0 and length == 0) ->\n        do_split([h | t], string, new_offset, counter - 1, trim, true)\n\n      keep == 0 and trim ->\n        [match | do_split([h | t], string, new_offset, counter - 1, trim, true)]\n\n      true ->\n        [part, match | do_split([h | t], string, new_offset, counter - 1, trim, true)]\n    end\n  end\n\n  defp do_split([[{pos, length} | h] | t], string, offset, counter, trim, false) do\n    new_offset = pos + length\n    keep = pos - offset\n\n    if keep == 0 and (trim or (offset != 0 and length == 0)) do\n      do_split([h | t], string, new_offset, counter, trim, false)\n    else\n      <<_::binary-size(^offset), part::binary-size(^keep), _::binary>> = string\n      [part | do_split([h | t], string, new_offset, counter - 1, trim, false)]\n    end\n  end\n\n  @doc ~S\"\"\"\n  Receives a regex, a binary and a replacement, returns a new\n  binary where all matches are replaced by the replacement.\n\n  The replacement can be either a string or a function that returns a string.\n  The resulting string is used as a replacement for every match.\n\n  When the replacement is a string, it allows specific captures of the match\n  using brackets at the regex expression and accessing them in the replacement\n  via `\\N` or `\\g{N}`, where `N` is the number of the capture. In case `\\0` is\n  used, the whole match is inserted. Note that in regexes the backslash needs\n  to be escaped, hence in practice you'll need to use `\\\\N` and `\\\\g{N}`.\n\n  When the replacement is a function, it allows specific captures too.\n  The function may have arity N where each argument maps to a capture,\n  with the first argument being the whole match. If the function expects more\n  arguments than captures found, the remaining arguments will receive `\"\"`.\n\n  ## Options\n\n    * `:global` - when `false`, replaces only the first occurrence\n      (defaults to `true`)\n\n  ## Examples\n\n      iex> Regex.replace(~r/d/, \"abc\", \"d\")\n      \"abc\"\n\n      iex> Regex.replace(~r/b/, \"abc\", \"d\")\n      \"adc\"\n\n      iex> Regex.replace(~r/b/, \"abc\", \"[\\\\0]\")\n      \"a[b]c\"\n\n      iex> Regex.replace(~r/a(b|d)c/, \"abcadc\", \"[\\\\1]\")\n      \"[b][d]\"\n\n      iex> Regex.replace(~r/\\.(\\d)$/, \"500.5\", \".\\\\g{1}0\")\n      \"500.50\"\n\n      iex> Regex.replace(~r/a(b|d)c/, \"abcadc\", fn _, x -> \"[#{x}]\" end)\n      \"[b][d]\"\n\n      iex> Regex.replace(~r/(\\w+)@(\\w+).(\\w+)/, \"abc@def.com\", fn _full, _c1, _c2, c3 -> \"TLD: #{c3}\" end)\n      \"TLD: com\"\n\n      iex> Regex.replace(~r/a/, \"abcadc\", \"A\", global: false)\n      \"Abcadc\"\n\n  \"\"\"\n  @spec replace(t, String.t(), String.t() | (... -> String.t()), global: boolean()) ::\n          String.t()\n  def replace(%Regex{} = regex, string, replacement, options \\\\ [])\n      when is_binary(string) and is_list(options) do\n    opts = if Keyword.get(options, :global) != false, do: [:global], else: []\n    opts = [{:capture, :all, :index} | opts]\n\n    case safe_run(regex, string, opts) do\n      :nomatch ->\n        string\n\n      {:match, [mlist | t]} when is_list(mlist) ->\n        apply_list(string, precompile_replacement(replacement), [mlist | t])\n        |> IO.iodata_to_binary()\n\n      {:match, slist} ->\n        apply_list(string, precompile_replacement(replacement), [slist])\n        |> IO.iodata_to_binary()\n    end\n  end\n\n  defp precompile_replacement(replacement) when is_function(replacement) do\n    {:arity, arity} = Function.info(replacement, :arity)\n    {replacement, arity}\n  end\n\n  defp precompile_replacement(\"\"), do: []\n\n  defp precompile_replacement(<<?\\\\, ?g, ?{, rest::binary>>) when byte_size(rest) > 0 do\n    {ns, <<?}, rest::binary>>} = pick_int(rest)\n    [List.to_integer(ns) | precompile_replacement(rest)]\n  end\n\n  defp precompile_replacement(<<?\\\\, ?\\\\, rest::binary>>) do\n    [<<?\\\\>> | precompile_replacement(rest)]\n  end\n\n  defp precompile_replacement(<<?\\\\, x, rest::binary>>) when x in ?0..?9 do\n    {ns, rest} = pick_int(rest)\n    [List.to_integer([x | ns]) | precompile_replacement(rest)]\n  end\n\n  defp precompile_replacement(<<x, rest::binary>>) do\n    case precompile_replacement(rest) do\n      [head | t] when is_binary(head) ->\n        [<<x, head::binary>> | t]\n\n      other ->\n        [<<x>> | other]\n    end\n  end\n\n  defp pick_int(<<x, rest::binary>>) when x in ?0..?9 do\n    {found, rest} = pick_int(rest)\n    {[x | found], rest}\n  end\n\n  defp pick_int(bin) do\n    {[], bin}\n  end\n\n  defp apply_list(string, replacement, list) do\n    apply_list(string, string, 0, replacement, list)\n  end\n\n  defp apply_list(_, \"\", _, _, []) do\n    []\n  end\n\n  defp apply_list(_, string, _, _, []) do\n    string\n  end\n\n  defp apply_list(whole, string, pos, replacement, [[{mpos, _} | _] | _] = list)\n       when mpos > pos do\n    length = mpos - pos\n    <<untouched::binary-size(^length), rest::binary>> = string\n    [untouched | apply_list(whole, rest, mpos, replacement, list)]\n  end\n\n  defp apply_list(whole, string, pos, replacement, [[{pos, length} | _] = head | tail]) do\n    <<_::size(^length)-binary, rest::binary>> = string\n    new_data = apply_replace(whole, replacement, head)\n    [new_data | apply_list(whole, rest, pos + length, replacement, tail)]\n  end\n\n  defp apply_replace(string, {fun, arity}, indexes) do\n    apply(fun, get_indexes(string, indexes, arity))\n  end\n\n  defp apply_replace(_, [bin], _) when is_binary(bin) do\n    bin\n  end\n\n  defp apply_replace(string, repl, indexes) do\n    indexes = List.to_tuple(indexes)\n\n    for part <- repl do\n      cond do\n        is_binary(part) ->\n          part\n\n        part >= tuple_size(indexes) ->\n          \"\"\n\n        true ->\n          get_index(string, elem(indexes, part))\n      end\n    end\n  end\n\n  defp get_index(_string, {pos, _length}) when pos < 0 do\n    \"\"\n  end\n\n  defp get_index(string, {pos, length}) do\n    <<_::size(^pos)-binary, res::size(^length)-binary, _::binary>> = string\n    res\n  end\n\n  defp get_indexes(_string, _, 0) do\n    []\n  end\n\n  defp get_indexes(string, [], arity) do\n    [\"\" | get_indexes(string, [], arity - 1)]\n  end\n\n  defp get_indexes(string, [h | t], arity) do\n    [get_index(string, h) | get_indexes(string, t, arity - 1)]\n  end\n\n  @doc ~S\"\"\"\n  Escapes a string to be literally matched in a regex.\n\n  ## Examples\n\n      iex> Regex.escape(\".\")\n      \"\\\\.\"\n\n      iex> Regex.escape(\"\\\\what if\")\n      \"\\\\\\\\what\\\\ if\"\n\n  \"\"\"\n  @spec escape(String.t()) :: String.t()\n  def escape(string) when is_binary(string) do\n    string\n    |> escape(_length = 0, string)\n    |> IO.iodata_to_binary()\n  end\n\n  @escapable :binary.bin_to_list(\".^$*+?()[]{}|#-\\\\\\t\\n\\v\\f\\r\\s\")\n\n  defp escape(<<char, rest::binary>>, length, original) when char in @escapable do\n    escape_char(rest, length, original, char)\n  end\n\n  defp escape(<<_, rest::binary>>, length, original) do\n    escape(rest, length + 1, original)\n  end\n\n  defp escape(<<>>, _length, original) do\n    original\n  end\n\n  defp escape_char(<<rest::binary>>, 0, _original, char) do\n    [?\\\\, char | escape(rest, 0, rest)]\n  end\n\n  defp escape_char(<<rest::binary>>, length, original, char) do\n    [binary_part(original, 0, length), ?\\\\, char | escape(rest, 0, rest)]\n  end\n\n  # Helpers\n\n  # translate options to modifiers as required for emedding\n  defp embeddable_modifiers(list), do: embeddable_modifiers(list, [], [])\n\n  defp embeddable_modifiers([:dotall, {:newline, :anycrlf} | t], acc, err),\n    do: embeddable_modifiers(t, [?s | acc], err)\n\n  defp embeddable_modifiers([:caseless | t], acc, err),\n    do: embeddable_modifiers(t, [?i | acc], err)\n\n  defp embeddable_modifiers([:extended | t], acc, err),\n    do: embeddable_modifiers(t, [?x | acc], err)\n\n  defp embeddable_modifiers([:multiline | t], acc, err),\n    do: embeddable_modifiers(t, [?m | acc], err)\n\n  defp embeddable_modifiers([option | t], acc, err),\n    do: embeddable_modifiers(t, acc, [option | err])\n\n  defp embeddable_modifiers([], acc, []), do: {:ok, acc}\n  defp embeddable_modifiers([], acc, err), do: {:error, acc, err}\n\n  # translate modifiers to options\n\n  defp translate_options(<<?s, t::binary>>, acc),\n    do: translate_options(t, [:dotall, {:newline, :anycrlf} | acc])\n\n  defp translate_options(<<?u, t::binary>>, acc), do: translate_options(t, [:unicode, :ucp | acc])\n  defp translate_options(<<?i, t::binary>>, acc), do: translate_options(t, [:caseless | acc])\n  defp translate_options(<<?x, t::binary>>, acc), do: translate_options(t, [:extended | acc])\n  defp translate_options(<<?f, t::binary>>, acc), do: translate_options(t, [:firstline | acc])\n  defp translate_options(<<?U, t::binary>>, acc), do: translate_options(t, [:ungreedy | acc])\n  defp translate_options(<<?m, t::binary>>, acc), do: translate_options(t, [:multiline | acc])\n\n  defp translate_options(<<?r, t::binary>>, acc) do\n    IO.warn(\"the /r modifier in regular expressions is deprecated, please use /U instead\")\n    translate_options(t, [:ungreedy | acc])\n  end\n\n  defp translate_options(<<?E, t::binary>>, acc) do\n    # on OTP 27-, the E modifier is a no-op since the feature doesn't exist but isn't needed\n    # (regexes aren't using references and can be shared across nodes or stored in config)\n    # TODO: remove this check on Erlang/OTP 28+ and update docs\n    case Code.ensure_loaded?(:re) and function_exported?(:re, :import, 1) do\n      true -> translate_options(t, [:export | acc])\n      false -> translate_options(t, acc)\n    end\n  end\n\n  defp translate_options(<<>>, acc), do: acc\n  defp translate_options(t, _acc), do: {:error, t}\n\n  @doc false\n  def __escape__(%{__struct__: Regex} = regex) do\n    # OTP 28.0 introduced refs in patterns, which can't be used in AST anymore\n    # OTP 28.1 introduced :re.import/1 which allows us to work with pre-compiled binaries again\n\n    pattern_ast =\n      cond do\n        # TODO: Remove this when we require Erlang/OTP 28+\n        # Before OTP 28.0, patterns did not contain any refs and could be safely be escaped\n        :erlang.system_info(:otp_release) < [?2, ?8] ->\n          Macro.escape(regex.re_pattern)\n\n        :lists.member(:export, regex.opts) ->\n          Macro.escape(regex.re_pattern)\n\n        # OTP 28.1+ introduced the ability to export and import regexes from compiled binaries\n        Code.ensure_loaded?(:re) and function_exported?(:re, :import, 1) ->\n          {:ok, exported} = :re.compile(regex.source, [:export] ++ regex.opts)\n\n          quote do\n            Regex.__import_pattern__(unquote(Macro.escape(exported)))\n          end\n          # we now that the Regex module is defined at this stage, so this macro can be safely called\n          |> Macro.update_meta(&([required: true] ++ &1))\n\n        # TODO: Remove this when we require Erlang/OTP 28.1+\n        # OTP 28.0 works in degraded mode performance-wise, we need to recompile from the source\n        true ->\n          quote do\n            {:ok, pattern} =\n              :re.compile(unquote(Macro.escape(regex.source)), unquote(Macro.escape(regex.opts)))\n\n            pattern\n          end\n      end\n\n    quote do\n      %{\n        __struct__: unquote(Regex),\n        re_pattern: unquote(pattern_ast),\n        source: unquote(Macro.escape(regex.source)),\n        opts: unquote(Macro.escape(regex.opts))\n      }\n    end\n  end\n\n  @doc false\n  defmacro __import_pattern__(pattern) do\n    if __CALLER__.context in [:match, :guard] do\n      raise ArgumentError, \"escaped Regex structs are not allowed in match or guards\"\n    end\n\n    quote do\n      :re.import(unquote(pattern))\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/registry.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Registry do\n  @moduledoc ~S\"\"\"\n  A local, decentralized and scalable key-value process storage.\n\n  It allows developers to lookup one or more processes with a given key.\n  If the registry has `:unique` keys, a key points to 0 or 1 process.\n  If the registry allows `:duplicate` keys, a single key may point to any\n  number of processes. In both cases, different keys could identify the\n  same process.\n\n  Each entry in the registry is associated to the process that has\n  registered the key. If the process crashes, the keys associated to that\n  process are automatically removed. All key comparisons in the registry\n  are done using the match operation (`===/2`).\n\n  The registry can be used for different purposes, such as name lookups (using\n  the `:via` option), storing properties, custom dispatching rules, or a pubsub\n  implementation. We explore some of those use cases below.\n\n  The registry may also be transparently partitioned, which provides\n  more scalable behavior for running registries on highly concurrent\n  environments with thousands or millions of entries.\n\n  ## Using in `:via`\n\n  Once the registry is started with a given name using\n  `Registry.start_link/1`, it can be used to register and access named\n  processes using the `{:via, Registry, {registry, key}}` tuple:\n\n      {:ok, _} = Registry.start_link(keys: :unique, name: MyApp.Registry)\n      name = {:via, Registry, {MyApp.Registry, \"agent\"}}\n      {:ok, _} = Agent.start_link(fn -> 0 end, name: name)\n      Agent.get(name, & &1)\n      #=> 0\n      Agent.update(name, &(&1 + 1))\n      Agent.get(name, & &1)\n      #=> 1\n\n  In the previous example, we were not interested in associating a value to the\n  process:\n\n      Registry.lookup(MyApp.Registry, \"agent\")\n      #=> [{self(), nil}]\n\n  However, in some cases it may be desired to associate a value to the process\n  using the alternate `{:via, Registry, {registry, key, value}}` tuple:\n\n      {:ok, _} = Registry.start_link(keys: :unique, name: MyApp.Registry)\n      name = {:via, Registry, {MyApp.Registry, \"agent\", :hello}}\n      {:ok, agent_pid} = Agent.start_link(fn -> 0 end, name: name)\n\n      Registry.lookup(MyApp.Registry, \"agent\")\n      #=> [{agent_pid, :hello}]\n\n      name_without_meta = {:via, Registry, {MyApp.Registry, \"agent\"}}\n      Agent.update(name_without_meta, fn x -> x + 1 end)\n      Agent.get(name_without_meta, & &1)\n      #=> 1\n\n  > #### With *and* without metadata {: .tip}\n  >\n  > When using the version of `:via` tuples with *metadata*, you can still use the version\n  > **without** metadata to look up the process.\n\n  To this point, we have been starting `Registry` using `start_link/1`.\n  Typically the registry is started as part of a supervision tree though:\n\n      {Registry, keys: :unique, name: MyApp.Registry}\n\n  Only registries with unique keys can be used in `:via`. If the name is\n  already taken, the case-specific `start_link` function (`Agent.start_link/2`\n  in the example above) will return `{:error, {:already_started, current_pid}}`.\n\n  ## Using as a dispatcher\n\n  `Registry` has a dispatch mechanism that allows developers to implement custom\n  dispatch logic triggered from the caller. For example, let's say we have a\n  duplicate registry started as so:\n\n      {:ok, _} = Registry.start_link(keys: :duplicate, name: Registry.DispatcherTest)\n\n  By calling `register/3`, different processes can register under a given key\n  and associate any value under that key. In this case, let's register the\n  current process under the key `\"hello\"` and attach the `{IO, :inspect}` tuple\n  to it:\n\n      {:ok, _} = Registry.register(Registry.DispatcherTest, \"hello\", {IO, :inspect})\n\n  Now, an entity interested in dispatching events for a given key may call\n  `dispatch/3` passing in the key and a callback. This callback will be invoked\n  with a list of all the values registered under the requested key, alongside\n  the PID of the process that registered each value, in the form of `{pid,\n  value}` tuples. In our example, `value` will be the `{module, function}` tuple\n  in the code above:\n\n      Registry.dispatch(Registry.DispatcherTest, \"hello\", fn entries ->\n        for {pid, {module, function}} <- entries, do: apply(module, function, [pid])\n      end)\n      # Prints #PID<...> where the PID is for the process that called register/3 above\n      #=> :ok\n\n  Dispatching happens in the process that calls `dispatch/3` either serially or\n  concurrently in case of multiple partitions (via spawned tasks). The\n  registered processes are not involved in dispatching unless involving them is\n  done explicitly (for example, by sending them a message in the callback).\n\n  Furthermore, if there is a failure when dispatching, due to a bad\n  registration, dispatching will always fail and the registered process will not\n  be notified. Therefore let's make sure we at least wrap and report those\n  errors:\n\n      require Logger\n\n      Registry.dispatch(Registry.DispatcherTest, \"hello\", fn entries ->\n        for {pid, {module, function}} <- entries do\n          try do\n            apply(module, function, [pid])\n          catch\n            kind, reason ->\n              formatted = Exception.format(kind, reason, __STACKTRACE__)\n              Logger.error(\"Registry.dispatch/3 failed with #{formatted}\")\n          end\n        end\n      end)\n      # Prints #PID<...>\n      #=> :ok\n\n  You could also replace the whole `apply` system by explicitly sending\n  messages. That's the example we will see next.\n\n  ## Using as a PubSub\n\n  Registries can also be used to implement a local, non-distributed, scalable\n  PubSub by relying on the `dispatch/3` function, similarly to the previous\n  section: in this case, however, we will send messages to each associated\n  process, instead of invoking a given module-function.\n\n  In this example, we will also set the number of partitions to the number of\n  schedulers online, which will make the registry more performant on highly\n  concurrent environments:\n\n      {:ok, _} =\n        Registry.start_link(\n          keys: :duplicate,\n          name: Registry.PubSubTest,\n          partitions: System.schedulers_online()\n        )\n\n      {:ok, _} = Registry.register(Registry.PubSubTest, \"hello\", [])\n\n      Registry.dispatch(Registry.PubSubTest, \"hello\", fn entries ->\n        for {pid, _} <- entries, do: send(pid, {:broadcast, \"world\"})\n      end)\n      #=> :ok\n\n  The example above broadcasted the message `{:broadcast, \"world\"}` to all\n  processes registered under the \"topic\" (or \"key\" as we called it until now)\n  `\"hello\"`.\n\n  The third argument given to `register/3` is a value associated to the\n  current process. While in the previous section we used it when dispatching,\n  in this particular example we are not interested in it, so we have set it\n  to an empty list. You could store a more meaningful value if necessary.\n\n  ## Registrations\n\n  Looking up, dispatching and registering are efficient and immediate at\n  the cost of delayed unsubscription. For example, if a process crashes,\n  its keys are automatically removed from the registry but the change may\n  not propagate immediately. This means certain operations may return processes\n  that are already dead. When such may happen, it will be explicitly stated\n  in the function documentation.\n\n  However, keep in mind those cases are typically not an issue. After all, a\n  process referenced by a PID may crash at any time, including between getting\n  the value from the registry and sending it a message. Many parts of the standard\n  library are designed to cope with that, such as `Process.monitor/1` which will\n  deliver the `:DOWN` message immediately if the monitored process is already dead\n  and `send/2` which acts as a no-op for dead processes.\n\n  ## ETS\n\n  Note that the registry uses one ETS table plus two ETS tables per partition.\n  \"\"\"\n\n  @keys [:unique, :duplicate, {:duplicate, :key}, {:duplicate, :pid}]\n  @all_info -1\n  @key_info -2\n\n  @typedoc \"The registry identifier\"\n  @type registry :: atom\n\n  @typedoc \"The type of the registry\"\n  @type keys :: :unique | :duplicate | {:duplicate, :key} | {:duplicate, :pid}\n\n  @typedoc \"The type of keys allowed on registration\"\n  @type key :: term\n\n  @typedoc \"The type of values allowed on registration\"\n  @type value :: term\n\n  @typedoc \"The type of registry metadata keys\"\n  @type meta_key :: atom | tuple\n\n  @typedoc \"The type of registry metadata values\"\n  @type meta_value :: term\n\n  @typedoc \"A pattern to match on objects in a registry\"\n  @type match_pattern :: atom | term\n\n  @typedoc \"A guard to be evaluated when matching on objects in a registry\"\n  @type guard :: atom | tuple\n\n  @typedoc \"A list of guards to be evaluated when matching on objects in a registry\"\n  @type guards :: [guard]\n\n  @typedoc \"A pattern used to representing the output format part of a match spec\"\n  @type body :: [term]\n\n  @typedoc \"A full match spec used when selecting objects in the registry\"\n  @type spec :: [{match_pattern, guards, body}]\n\n  @typedoc \"Options used for `child_spec/1` and `start_link/1`\"\n  @type start_option ::\n          {:keys, keys}\n          | {:name, registry}\n          | {:partitions, pos_integer}\n          | {:listeners, [atom]}\n          | {:meta, [{meta_key, meta_value}]}\n\n  @typedoc \"\"\"\n  The message that the registry sends to listeners when a process registers or unregisters.\n\n  See the `:listeners` option in `start_link/1`.\n  \"\"\"\n  @typedoc since: \"1.15.0\"\n  @type listener_message ::\n          {:register, registry, key, registry_partition :: pid, value}\n          | {:unregister, registry, key, registry_partition :: pid}\n\n  @typedoc \"\"\"\n  Options used for `dispatch/4`.\n  \"\"\"\n  @type dispatch_opts :: [parallel: boolean()]\n\n  ## Via callbacks\n\n  @doc false\n  def whereis_name({registry, key}), do: whereis_name(registry, key)\n  def whereis_name({registry, key, _value}), do: whereis_name(registry, key)\n\n  defp whereis_name(registry, key) do\n    case key_info!(registry) do\n      {:unique, partitions, key_ets} ->\n        key_ets = key_ets || key_ets!(registry, key, partitions)\n\n        case safe_lookup_second(key_ets, key) do\n          {pid, _} ->\n            if Process.alive?(pid), do: pid, else: :undefined\n\n          _ ->\n            :undefined\n        end\n\n      {{:duplicate, _}, _, _} ->\n        raise ArgumentError, \":via is not supported for duplicate registries\"\n    end\n  end\n\n  @doc false\n  def register_name({registry, key}, pid), do: register_name(registry, key, nil, pid)\n  def register_name({registry, key, value}, pid), do: register_name(registry, key, value, pid)\n\n  defp register_name(registry, key, value, pid) when pid == self() do\n    case register(registry, key, value) do\n      {:ok, _} -> :yes\n      {:error, _} -> :no\n    end\n  end\n\n  @doc false\n  def send({registry, key}, msg) do\n    case lookup(registry, key) do\n      [{pid, _}] -> Kernel.send(pid, msg)\n      [] -> :erlang.error(:badarg, [{registry, key}, msg])\n    end\n  end\n\n  def send({registry, key, _value}, msg) do\n    Registry.send({registry, key}, msg)\n  end\n\n  @doc false\n  def unregister_name({registry, key}), do: unregister(registry, key)\n  def unregister_name({registry, key, _value}), do: unregister(registry, key)\n\n  ## Registry API\n\n  @doc \"\"\"\n  Starts the registry as a supervisor process.\n\n  Manually it can be started as:\n\n      Registry.start_link(keys: :unique, name: MyApp.Registry)\n\n  In your supervisor tree, you would write:\n\n      Supervisor.start_link([\n        {Registry, keys: :unique, name: MyApp.Registry}\n      ], strategy: :one_for_one)\n\n  For intensive workloads, the registry may also be partitioned (by specifying\n  the `:partitions` option). If partitioning is required then a good default is to\n  set the number of partitions to the number of schedulers available:\n\n      Registry.start_link(\n        keys: :unique,\n        name: MyApp.Registry,\n        partitions: System.schedulers_online()\n      )\n\n  or:\n\n      Supervisor.start_link([\n        {Registry, keys: :unique, name: MyApp.Registry, partitions: System.schedulers_online()}\n      ], strategy: :one_for_one)\n\n  For `:duplicate` registries with many different keys (e.g., many topics with\n  few subscribers each), you can optimize key-based lookups by partitioning by key:\n\n      Registry.start_link(\n        keys: {:duplicate, :key},\n        name: MyApp.TopicRegistry,\n        partitions: System.schedulers_online()\n      )\n\n  This allows key-based lookups to check only a single partition instead of\n  searching all partitions. Use the default `:pid` partitioning when you have\n  fewer keys with many entries each (e.g., one topic with many subscribers).\n\n  ## Options\n\n  The registry requires the following keys:\n\n    * `:keys` - chooses if keys are `:unique`, `:duplicate`,\n      `{:duplicate, :key}`, or `{:duplicate, :pid}`\n    * `:name` - the name of the registry and its tables\n\n  The following keys are optional:\n\n    * `:partitions` - the number of partitions in the registry. Defaults to `1`.\n    * `:listeners` - a list of named processes which are notified of register\n      and unregister events. The registered process must be monitored by the\n      listener if the listener wants to be notified if the registered process\n      crashes. Messages sent to listeners are of type `t:listener_message/0`.\n    * `:meta` - a keyword list of metadata to be attached to the registry.\n\n  For `:duplicate` registries, you can specify the partitioning strategy\n  directly in the `:keys` option:\n\n    * `:duplicate` or `{:duplicate, :pid}` - Use `:pid` partitioning (default)\n      when you have keys with many entries (e.g., one topic with many subscribers).\n      This is the traditional behavior and groups all entries from the same process together.\n\n    * `{:duplicate, :key}` - Use `:key` partitioning when entries are spread across\n      many different keys (e.g., many topics with few subscribers each). This makes\n      key-based lookups more efficient as they only need to check a single partition\n      instead of all partitions.\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec start_link([start_option]) :: {:ok, pid} | {:error, term}\n  def start_link(options) do\n    keys = Keyword.get(options, :keys)\n\n    # Validate and normalize keys format\n    kind =\n      case keys do\n        {:duplicate, partition_strategy} when partition_strategy in [:key, :pid] ->\n          {:duplicate, partition_strategy}\n\n        :unique ->\n          :unique\n\n        :duplicate ->\n          {:duplicate, :pid}\n\n        _ ->\n          raise ArgumentError,\n                \"expected :keys to be given and be one of :unique, :duplicate, {:duplicate, :key}, or {:duplicate, :pid}, got: #{inspect(keys)}\"\n      end\n\n    name =\n      case Keyword.fetch(options, :name) do\n        {:ok, name} when is_atom(name) ->\n          name\n\n        {:ok, other} ->\n          raise ArgumentError, \"expected :name to be an atom, got: #{inspect(other)}\"\n\n        :error ->\n          raise ArgumentError, \"expected :name option to be present\"\n      end\n\n    meta = Keyword.get(options, :meta, [])\n\n    if not Keyword.keyword?(meta) do\n      raise ArgumentError, \"expected :meta to be a keyword list, got: #{inspect(meta)}\"\n    end\n\n    partitions = Keyword.get(options, :partitions, 1)\n\n    if not (is_integer(partitions) and partitions >= 1) do\n      raise ArgumentError,\n            \"expected :partitions to be a positive integer, got: #{inspect(partitions)}\"\n    end\n\n    listeners = Keyword.get(options, :listeners, [])\n\n    if not (is_list(listeners) and Enum.all?(listeners, &is_atom/1)) do\n      raise ArgumentError,\n            \"expected :listeners to be a list of named processes, got: #{inspect(listeners)}\"\n    end\n\n    compressed = Keyword.get(options, :compressed, false)\n\n    if not is_boolean(compressed) do\n      raise ArgumentError,\n            \"expected :compressed to be a boolean, got: #{inspect(compressed)}\"\n    end\n\n    # The @info format must be kept in sync with Registry.Partition optimization.\n    entries = [\n      {@all_info, {kind, partitions, nil, nil, listeners}},\n      {@key_info, {kind, partitions, nil}} | meta\n    ]\n\n    Registry.Supervisor.start_link(\n      kind,\n      name,\n      partitions,\n      listeners,\n      entries,\n      compressed\n    )\n  end\n\n  @doc false\n  @deprecated \"Use Registry.start_link/1 instead\"\n  def start_link(keys, name, options \\\\ []) when keys in @keys and is_atom(name) do\n    start_link([keys: keys, name: name] ++ options)\n  end\n\n  @doc \"\"\"\n  Returns a specification to start a registry under a supervisor.\n\n  See `Supervisor`.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec child_spec([start_option]) :: Supervisor.child_spec()\n  def child_spec(options) do\n    %{\n      id: Keyword.get(options, :name, Registry),\n      start: {Registry, :start_link, [options]},\n      type: :supervisor\n    }\n  end\n\n  @doc \"\"\"\n  Updates the value for `key` for the current process in the unique `registry`.\n\n  Returns a `{new_value, old_value}` tuple or `:error` if there\n  is no such key assigned to the current process.\n\n  If a non-unique registry is given, an error is raised.\n\n  ## Examples\n\n      iex> Registry.start_link(keys: :unique, name: Registry.UpdateTest)\n      iex> {:ok, _} = Registry.register(Registry.UpdateTest, \"hello\", 1)\n      iex> Registry.lookup(Registry.UpdateTest, \"hello\")\n      [{self(), 1}]\n      iex> Registry.update_value(Registry.UpdateTest, \"hello\", &(&1 + 1))\n      {2, 1}\n      iex> Registry.lookup(Registry.UpdateTest, \"hello\")\n      [{self(), 2}]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec update_value(registry, key, (value -> value)) ::\n          {new_value :: term, old_value :: term} | :error\n  def update_value(registry, key, callback) when is_atom(registry) and is_function(callback, 1) do\n    case key_info!(registry) do\n      {:unique, partitions, key_ets} ->\n        key_ets = key_ets || key_ets!(registry, key, partitions)\n\n        try do\n          :ets.lookup_element(key_ets, key, 2)\n        catch\n          :error, :badarg -> :error\n        else\n          {pid, old_value} when pid == self() ->\n            new_value = callback.(old_value)\n            :ets.insert(key_ets, {key, {pid, new_value}})\n            {new_value, old_value}\n\n          {_, _} ->\n            :error\n        end\n\n      {kind, _, _} ->\n        raise ArgumentError,\n              \"Registry.update_value/3 is not supported for #{inspect(kind)} registries\"\n    end\n  end\n\n  @doc \"\"\"\n  Invokes the callback with all entries under `key` in each partition\n  for the given `registry`.\n\n  The list of `entries` is a non-empty list of two-element tuples where\n  the first element is the PID and the second element is the value\n  associated to the PID. If there are no entries for the given key,\n  the callback is never invoked.\n\n  If the registry is partitioned, the callback is invoked multiple times\n  per partition. If the registry is partitioned and `parallel: true` is\n  given as an option, the dispatching happens in parallel. In both cases,\n  the callback is only invoked if there are entries for that partition.\n\n  See the module documentation for examples of using the `dispatch/3`\n  function for building custom dispatching or a pubsub system.\n\n  ## Options\n\n    * `:parallel` - if `true`, the dispatching is done in parallel\n      across all partitions. Defaults to `false`.\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec dispatch(registry, key, dispatcher, dispatch_opts) :: :ok\n        when dispatcher: (entries :: [{pid, value}] -> term) | {module(), atom(), [term()]}\n  def dispatch(registry, key, mfa_or_fun, opts \\\\ [])\n      when is_atom(registry) and is_function(mfa_or_fun, 1)\n      when is_atom(registry) and tuple_size(mfa_or_fun) == 3 do\n    case key_info!(registry) do\n      {:unique, partitions, key_ets} ->\n        (key_ets || key_ets!(registry, key, partitions))\n        |> safe_lookup_second(key)\n        |> List.wrap()\n        |> apply_non_empty_to_mfa_or_fun(mfa_or_fun)\n\n      {{:duplicate, _}, 1, key_ets} ->\n        key_ets\n        |> safe_lookup_second(key)\n        |> apply_non_empty_to_mfa_or_fun(mfa_or_fun)\n\n      {{:duplicate, _}, partitions, _} ->\n        if Keyword.get(opts, :parallel, false) do\n          registry\n          |> dispatch_parallel(key, mfa_or_fun, partitions)\n          |> Enum.each(&Task.await(&1, :infinity))\n        else\n          dispatch_serial(registry, key, mfa_or_fun, partitions)\n        end\n    end\n\n    :ok\n  end\n\n  defp dispatch_serial(_registry, _key, _mfa_or_fun, 0) do\n    :ok\n  end\n\n  defp dispatch_serial(registry, key, mfa_or_fun, partition) do\n    partition = partition - 1\n\n    registry\n    |> key_ets!(partition)\n    |> safe_lookup_second(key)\n    |> apply_non_empty_to_mfa_or_fun(mfa_or_fun)\n\n    dispatch_serial(registry, key, mfa_or_fun, partition)\n  end\n\n  defp dispatch_parallel(_registry, _key, _mfa_or_fun, 0) do\n    []\n  end\n\n  defp dispatch_parallel(registry, key, mfa_or_fun, partition) do\n    partition = partition - 1\n    parent = self()\n\n    task =\n      Task.async(fn ->\n        registry\n        |> key_ets!(partition)\n        |> safe_lookup_second(key)\n        |> apply_non_empty_to_mfa_or_fun(mfa_or_fun)\n\n        Process.unlink(parent)\n        :ok\n      end)\n\n    [task | dispatch_parallel(registry, key, mfa_or_fun, partition)]\n  end\n\n  defp apply_non_empty_to_mfa_or_fun([], _mfa_or_fun) do\n    :ok\n  end\n\n  defp apply_non_empty_to_mfa_or_fun(entries, {module, function, args}) do\n    apply(module, function, [entries | args])\n  end\n\n  defp apply_non_empty_to_mfa_or_fun(entries, fun) do\n    fun.(entries)\n  end\n\n  @doc \"\"\"\n  Finds the `{pid, value}` pair for the given `key` in `registry` in no particular order.\n\n  An empty list if there is no match.\n\n  For unique registries, a single partition lookup is necessary. For\n  duplicate registries, all partitions must be looked up.\n\n  ## Examples\n\n  In the example below we register the current process and look it up\n  both from itself and other processes:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.UniqueLookupTest)\n      iex> Registry.lookup(Registry.UniqueLookupTest, \"hello\")\n      []\n      iex> {:ok, _} = Registry.register(Registry.UniqueLookupTest, \"hello\", :world)\n      iex> Registry.lookup(Registry.UniqueLookupTest, \"hello\")\n      [{self(), :world}]\n      iex> Task.async(fn -> Registry.lookup(Registry.UniqueLookupTest, \"hello\") end) |> Task.await()\n      [{self(), :world}]\n\n  The same applies to duplicate registries:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateLookupTest)\n      iex> Registry.lookup(Registry.DuplicateLookupTest, \"hello\")\n      []\n      iex> {:ok, _} = Registry.register(Registry.DuplicateLookupTest, \"hello\", :world)\n      iex> Registry.lookup(Registry.DuplicateLookupTest, \"hello\")\n      [{self(), :world}]\n      iex> {:ok, _} = Registry.register(Registry.DuplicateLookupTest, \"hello\", :another)\n      iex> Enum.sort(Registry.lookup(Registry.DuplicateLookupTest, \"hello\"))\n      [{self(), :another}, {self(), :world}]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec lookup(registry, key) :: [{pid, value}]\n  def lookup(registry, key) when is_atom(registry) do\n    case key_info!(registry) do\n      {:unique, partitions, key_ets} ->\n        key_ets = key_ets || key_ets!(registry, key, partitions)\n\n        case safe_lookup_second(key_ets, key) do\n          {_, _} = pair ->\n            [pair]\n\n          _ ->\n            []\n        end\n\n      {{:duplicate, _}, 1, key_ets} ->\n        safe_lookup_second(key_ets, key)\n\n      {{:duplicate, :key}, partitions, _key_ets} ->\n        partition = hash(key, partitions)\n        safe_lookup_second(key_ets!(registry, partition), key)\n\n      {{:duplicate, :pid}, partitions, _key_ets} ->\n        for partition <- 0..(partitions - 1),\n            pair <- safe_lookup_second(key_ets!(registry, partition), key),\n            do: pair\n    end\n  end\n\n  @doc \"\"\"\n  Out-of-band locking of the given `lock_key` for the duration of `function`.\n\n  Only one function can execute under the same `lock_key` at a given\n  time. The given function always runs in the caller process.\n\n  The `lock_key` has its own namespace and therefore does not clash or\n  overlap with the regular registry keys. In other words, locking works\n  out-of-band from the regular Registry operations. See the \"Use cases\"\n  section below.\n\n  Locking behaves the same regardless of the registry type.\n\n  ## Use cases\n\n  The Registry is safe and concurrent out-of-the-box. You are not required\n  to use this function when interacting with the Registry. Furthermore,\n  `Registry` with `:unique` keys can already act as a process-lock for any\n  given key. For example, you can ensure only one process runs at a given\n  time for a given `:key` by doing:\n\n      name = {:via, Registry, {MyApp.Registry, :key, :value}}\n\n      # Do not attempt to start if we are already running\n      if pid = GenServer.whereis(name) do\n        pid\n      else\n        case GenServer.start_link(__MODULE__, :ok, name: name) do\n          {:ok, pid} -> pid\n          {:error, {:already_started, pid}} -> pid\n        end\n      end\n\n  Process locking gives you plenty of flexibility and fault isolation and\n  is enough for most cases.\n\n  This function is useful only when spawning processes is not an option,\n  for example, when copying the data to another process could be too\n  expensive. Or when the work must be done within the current process\n  for other reasons. In such cases, this function provides a scalable\n  mechanism for managing locks on top of the registry's infrastructure.\n\n  ## Examples\n\n      iex> Registry.start_link(keys: :unique, name: Registry.LockTest)\n      iex> Registry.lock(Registry.LockTest, :hello, fn -> :ok end)\n      :ok\n      iex> Registry.lock(Registry.LockTest, :world, fn -> self() end)\n      self()\n\n  \"\"\"\n  @doc since: \"1.18.0\"\n  def lock(registry, lock_key, function)\n      when is_atom(registry) and is_function(function, 0) do\n    {_kind, partitions, _, pid_ets, _} = info!(registry)\n    {pid_server, _pid_ets} = pid_ets || pid_ets!(registry, lock_key, partitions)\n    Registry.Partition.lock(pid_server, lock_key, function)\n  end\n\n  @doc \"\"\"\n  Returns `{pid, value}` pairs under the given `key` in `registry` that match `pattern`.\n\n  Pattern must be an atom or a tuple that will match the structure of the\n  value stored in the registry. The atom `:_` can be used to ignore a given\n  value or tuple element, while the atom `:\"$1\"` can be used to temporarily assign part\n  of pattern to a variable for a subsequent comparison.\n\n  Optionally, it is possible to pass a list of guard conditions for more precise matching.\n  Each guard is a tuple, which describes checks that should be passed by assigned part of pattern.\n  For example the `$1 > 1` guard condition would be expressed as the `{:>, :\"$1\", 1}` tuple.\n  Please note that guard conditions will work only for assigned\n  variables like `:\"$1\"`, `:\"$2\"`, and so forth.\n  Avoid usage of special match variables `:\"$_\"` and `:\"$$\"`, because it might not work as expected.\n\n  An empty list will be returned if there is no match.\n\n  For unique registries, a single partition lookup is necessary. For\n  duplicate registries, all partitions must be looked up.\n\n  ## Examples\n\n  In the example below we register the current process under the same\n  key in a duplicate registry but with different values:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.MatchTest)\n      iex> {:ok, _} = Registry.register(Registry.MatchTest, \"hello\", {1, :atom, 1})\n      iex> {:ok, _} = Registry.register(Registry.MatchTest, \"hello\", {2, :atom, 2})\n      iex> Registry.match(Registry.MatchTest, \"hello\", {1, :_, :_})\n      [{self(), {1, :atom, 1}}]\n      iex> Registry.match(Registry.MatchTest, \"hello\", {2, :_, :_})\n      [{self(), {2, :atom, 2}}]\n      iex> Registry.match(Registry.MatchTest, \"hello\", {:_, :atom, :_}) |> Enum.sort()\n      [{self(), {1, :atom, 1}}, {self(), {2, :atom, 2}}]\n      iex> Registry.match(Registry.MatchTest, \"hello\", {:\"$1\", :_, :\"$1\"}) |> Enum.sort()\n      [{self(), {1, :atom, 1}}, {self(), {2, :atom, 2}}]\n      iex> guards = [{:>, :\"$1\", 1}]\n      iex> Registry.match(Registry.MatchTest, \"hello\", {:_, :_, :\"$1\"}, guards)\n      [{self(), {2, :atom, 2}}]\n      iex> guards = [{:is_atom, :\"$1\"}]\n      iex> Registry.match(Registry.MatchTest, \"hello\", {:_, :\"$1\", :_}, guards) |> Enum.sort()\n      [{self(), {1, :atom, 1}}, {self(), {2, :atom, 2}}]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec match(registry, key, match_pattern, guards) :: [{pid, term}]\n  def match(registry, key, pattern, guards \\\\ []) when is_atom(registry) and is_list(guards) do\n    guards = [{:\"=:=\", {:element, 1, :\"$_\"}, {:const, key}} | guards]\n    spec = [{{:_, {:_, pattern}}, guards, [{:element, 2, :\"$_\"}]}]\n\n    case key_info!(registry) do\n      {:unique, partitions, key_ets} ->\n        key_ets = key_ets || key_ets!(registry, key, partitions)\n        :ets.select(key_ets, spec)\n\n      {{:duplicate, _}, 1, key_ets} ->\n        :ets.select(key_ets, spec)\n\n      {{:duplicate, _}, partitions, _key_ets} ->\n        for partition <- 0..(partitions - 1),\n            pair <- :ets.select(key_ets!(registry, partition), spec),\n            do: pair\n    end\n  end\n\n  @doc \"\"\"\n  Returns the known keys for the given `pid` in `registry` in no particular order.\n\n  If the registry is unique, the keys are unique. Otherwise\n  they may contain duplicates if the process was registered\n  under the same key multiple times. The list will be empty\n  if the process is dead or it has no keys in this registry.\n\n  ## Examples\n\n  Registering under a unique registry does not allow multiple entries:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.UniqueKeysTest)\n      iex> Registry.keys(Registry.UniqueKeysTest, self())\n      []\n      iex> {:ok, _} = Registry.register(Registry.UniqueKeysTest, \"hello\", :world)\n      iex> Registry.register(Registry.UniqueKeysTest, \"hello\", :later) # registry is :unique\n      {:error, {:already_registered, self()}}\n      iex> Registry.keys(Registry.UniqueKeysTest, self())\n      [\"hello\"]\n\n  Such is possible for duplicate registries though:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateKeysTest)\n      iex> Registry.keys(Registry.DuplicateKeysTest, self())\n      []\n      iex> {:ok, _} = Registry.register(Registry.DuplicateKeysTest, \"hello\", :world)\n      iex> {:ok, _} = Registry.register(Registry.DuplicateKeysTest, \"hello\", :world)\n      iex> Registry.keys(Registry.DuplicateKeysTest, self())\n      [\"hello\", \"hello\"]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec keys(registry, pid) :: [key]\n  def keys(registry, pid) when is_atom(registry) and is_pid(pid) do\n    {kind, partitions, _, pid_ets, _} = info!(registry)\n\n    pid_etses =\n      if pid_ets do\n        {_, pid_ets} = pid_ets\n        [pid_ets]\n      else\n        case kind do\n          {:duplicate, :key} ->\n            for partition <- 0..(partitions - 1) do\n              {_, pid_ets} = pid_ets!(registry, partition)\n              pid_ets\n            end\n\n          _ ->\n            {_, pid_ets} = pid_ets!(registry, pid, partitions)\n            [pid_ets]\n        end\n      end\n\n    keys =\n      Enum.flat_map(pid_etses, fn pid_ets ->\n        try do\n          spec = [{{pid, :\"$1\", :\"$2\", :_}, [], [{{:\"$1\", :\"$2\"}}]}]\n          :ets.select(pid_ets, spec)\n        catch\n          :error, :badarg -> []\n        end\n      end)\n\n    # Handle the possibility of fake keys\n    keys = gather_keys(keys, [], false)\n\n    cond do\n      kind == :unique -> Enum.uniq(keys)\n      true -> keys\n    end\n  end\n\n  defp gather_keys([{key, {_, remaining}} | rest], acc, _fake) do\n    gather_keys(rest, [key | acc], {key, remaining})\n  end\n\n  defp gather_keys([{key, _} | rest], acc, fake) do\n    gather_keys(rest, [key | acc], fake)\n  end\n\n  defp gather_keys([], acc, {key, remaining}) do\n    List.duplicate(key, remaining) ++ Enum.reject(acc, &(&1 === key))\n  end\n\n  defp gather_keys([], acc, false) do\n    acc\n  end\n\n  @doc \"\"\"\n  Reads the values for the given `key` for `pid` in `registry`.\n\n  For unique registries, it is either an empty list or a list\n  with a single element. For duplicate registries, it is a list\n  with zero, one, or multiple elements.\n\n  ## Examples\n\n  In the example below we register the current process and look it up\n  both from itself and other processes:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.UniqueValuesTest)\n      iex> Registry.values(Registry.UniqueValuesTest, \"hello\", self())\n      []\n      iex> {:ok, _} = Registry.register(Registry.UniqueValuesTest, \"hello\", :world)\n      iex> Registry.values(Registry.UniqueValuesTest, \"hello\", self())\n      [:world]\n      iex> Task.async(fn -> Registry.values(Registry.UniqueValuesTest, \"hello\", self()) end) |> Task.await()\n      []\n      iex> parent = self()\n      iex> Task.async(fn -> Registry.values(Registry.UniqueValuesTest, \"hello\", parent) end) |> Task.await()\n      [:world]\n\n  The same applies to duplicate registries:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateValuesTest)\n      iex> Registry.values(Registry.DuplicateValuesTest, \"hello\", self())\n      []\n      iex> {:ok, _} = Registry.register(Registry.DuplicateValuesTest, \"hello\", :world)\n      iex> Registry.values(Registry.DuplicateValuesTest, \"hello\", self())\n      [:world]\n      iex> {:ok, _} = Registry.register(Registry.DuplicateValuesTest, \"hello\", :another)\n      iex> Enum.sort(Registry.values(Registry.DuplicateValuesTest, \"hello\", self()))\n      [:another, :world]\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec values(registry, key, pid) :: [value]\n  def values(registry, key, pid) when is_atom(registry) do\n    case key_info!(registry) do\n      {:unique, partitions, key_ets} ->\n        key_ets = key_ets || key_ets!(registry, key, partitions)\n\n        case safe_lookup_second(key_ets, key) do\n          {^pid, value} ->\n            [value]\n\n          _ ->\n            []\n        end\n\n      {{:duplicate, _}, 1, key_ets} ->\n        for {^pid, value} <- safe_lookup_second(key_ets, key), do: value\n\n      {{:duplicate, :key}, partitions, _key_ets} ->\n        partition = hash(key, partitions)\n        key_ets = key_ets!(registry, partition)\n        for {^pid, value} <- safe_lookup_second(key_ets, key), do: value\n\n      {{:duplicate, :pid}, partitions, _key_ets} ->\n        partition = hash(pid, partitions)\n        key_ets = key_ets!(registry, partition)\n        for {^pid, value} <- safe_lookup_second(key_ets, key), do: value\n    end\n  end\n\n  @doc \"\"\"\n  Unregisters all entries for the given `key` associated to the current\n  process in `registry`.\n\n  Always returns `:ok` and automatically unlinks the current process from\n  the owner if there are no more keys associated to the current process. See\n  also `register/3` to read more about the \"owner\".\n\n  If the registry has listeners specified via the `:listeners` option in `start_link/1`,\n  those listeners will be notified of the unregistration and will receive a\n  message of type `t:listener_message/0`.\n\n  ## Examples\n\n  For unique registries:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.UniqueUnregisterTest)\n      iex> Registry.register(Registry.UniqueUnregisterTest, \"hello\", :world)\n      iex> Registry.keys(Registry.UniqueUnregisterTest, self())\n      [\"hello\"]\n      iex> Registry.unregister(Registry.UniqueUnregisterTest, \"hello\")\n      :ok\n      iex> Registry.keys(Registry.UniqueUnregisterTest, self())\n      []\n\n  For duplicate registries:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateUnregisterTest)\n      iex> Registry.register(Registry.DuplicateUnregisterTest, \"hello\", :world)\n      iex> Registry.register(Registry.DuplicateUnregisterTest, \"hello\", :world)\n      iex> Registry.keys(Registry.DuplicateUnregisterTest, self())\n      [\"hello\", \"hello\"]\n      iex> Registry.unregister(Registry.DuplicateUnregisterTest, \"hello\")\n      :ok\n      iex> Registry.keys(Registry.DuplicateUnregisterTest, self())\n      []\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec unregister(registry, key) :: :ok\n  def unregister(registry, key) when is_atom(registry) do\n    self = self()\n    {kind, partitions, key_ets, pid_ets, listeners} = info!(registry)\n    {key_partition, pid_partition} = partitions(kind, key, self, partitions)\n    key_ets = key_ets || key_ets!(registry, key_partition)\n    {pid_server, pid_ets} = pid_ets || pid_ets!(registry, pid_partition)\n\n    # Remove first from the key_ets because in case of crashes\n    # the pid_ets will still be able to clean up. The last step is\n    # to clean if we have no more entries.\n    true = __unregister__(key_ets, {key, {self, :_}}, 1)\n    true = __unregister__(pid_ets, {self, key, key_ets, :_}, 2)\n\n    unlink_if_unregistered(pid_server, pid_ets, self)\n\n    for listener <- listeners do\n      Kernel.send(listener, {:unregister, registry, key, self})\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Unregisters entries for keys matching a pattern associated to the current\n  process in `registry`.\n\n  ## Examples\n\n  For unique registries it can be used to conditionally unregister a key on\n  the basis of whether or not it matches a particular value.\n\n      iex> Registry.start_link(keys: :unique, name: Registry.UniqueUnregisterMatchTest)\n      iex> Registry.register(Registry.UniqueUnregisterMatchTest, \"hello\", :world)\n      iex> Registry.keys(Registry.UniqueUnregisterMatchTest, self())\n      [\"hello\"]\n      iex> Registry.unregister_match(Registry.UniqueUnregisterMatchTest, \"hello\", :foo)\n      :ok\n      iex> Registry.keys(Registry.UniqueUnregisterMatchTest, self())\n      [\"hello\"]\n      iex> Registry.unregister_match(Registry.UniqueUnregisterMatchTest, \"hello\", :world)\n      :ok\n      iex> Registry.keys(Registry.UniqueUnregisterMatchTest, self())\n      []\n\n  For duplicate registries:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateUnregisterMatchTest)\n      iex> Registry.register(Registry.DuplicateUnregisterMatchTest, \"hello\", :world_a)\n      iex> Registry.register(Registry.DuplicateUnregisterMatchTest, \"hello\", :world_b)\n      iex> Registry.register(Registry.DuplicateUnregisterMatchTest, \"hello\", :world_c)\n      iex> Registry.keys(Registry.DuplicateUnregisterMatchTest, self())\n      [\"hello\", \"hello\", \"hello\"]\n      iex> Registry.unregister_match(Registry.DuplicateUnregisterMatchTest, \"hello\", :world_a)\n      :ok\n      iex> Registry.keys(Registry.DuplicateUnregisterMatchTest, self())\n      [\"hello\", \"hello\"]\n      iex> Registry.lookup(Registry.DuplicateUnregisterMatchTest, \"hello\")\n      [{self(), :world_b}, {self(), :world_c}]\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec unregister_match(registry, key, match_pattern, guards) :: :ok\n  def unregister_match(registry, key, pattern, guards \\\\ []) when is_list(guards) do\n    self = self()\n\n    {kind, partitions, key_ets, pid_ets, listeners} = info!(registry)\n    {key_partition, pid_partition} = partitions(kind, key, self, partitions)\n    key_ets = key_ets || key_ets!(registry, key_partition)\n    {pid_server, pid_ets} = pid_ets || pid_ets!(registry, pid_partition)\n\n    # Remove first from the key_ets because in case of crashes\n    # the pid_ets will still be able to clean up. The last step is\n    # to clean if we have no more entries.\n\n    # Here we want to count all entries for this pid under this key, regardless of pattern.\n    underscore_guard = {:\"=:=\", {:element, 1, :\"$_\"}, {:const, key}}\n    total_spec = [{{:_, {self, :_}}, [underscore_guard], [true]}]\n    total = :ets.select_count(key_ets, total_spec)\n\n    # We only want to delete things that match the pattern\n    delete_spec = [{{:_, {self, pattern}}, [underscore_guard | guards], [true]}]\n\n    case :ets.select_delete(key_ets, delete_spec) do\n      # We deleted everything, we can just delete the object\n      ^total ->\n        true = __unregister__(pid_ets, {self, key, key_ets, :_}, 2)\n        unlink_if_unregistered(pid_server, pid_ets, self)\n\n        for listener <- listeners do\n          Kernel.send(listener, {:unregister, registry, key, self})\n        end\n\n      0 ->\n        :ok\n\n      deleted ->\n        # There are still entries remaining for this pid. delete_object/2 with\n        # duplicate_bag tables will remove every entry, but we only want to\n        # remove those we have deleted. The solution is to introduce a temp_entry\n        # that indicates how many keys WILL be remaining after the delete operation.\n        counter = System.unique_integer()\n        remaining = total - deleted\n        temp_entry = {self, key, {key_ets, remaining}, counter}\n        true = :ets.insert(pid_ets, temp_entry)\n        true = __unregister__(pid_ets, {self, key, key_ets, :_}, 2)\n        real_keys = List.duplicate({self, key, key_ets, counter}, remaining)\n        true = :ets.insert(pid_ets, real_keys)\n        # We've recreated the real remaining key entries, so we can now delete\n        # our temporary entry.\n        true = :ets.delete_object(pid_ets, temp_entry)\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Registers the current process under the given `key` in `registry`.\n\n  A value to be associated with this registration must also be given.\n  This value will be retrieved whenever dispatching or doing a key\n  lookup.\n\n  This function returns `{:ok, owner}` or `{:error, reason}`.\n  The `owner` is the PID in the registry partition responsible for\n  the PID. The owner is automatically linked to the caller.\n\n  If the registry has unique keys, it will return `{:ok, owner}` unless\n  the key is already associated to a PID, in which case it returns\n  `{:error, {:already_registered, pid}}`.\n\n  If the registry has duplicate keys, multiple registrations from the\n  current process under the same key are allowed.\n\n  If the registry has listeners specified via the `:listeners` option in `start_link/1`,\n  those listeners will be notified of the registration and will receive a\n  message of type `t:listener_message/0`.\n\n  ## Examples\n\n  Registering under a unique registry does not allow multiple entries:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.UniqueRegisterTest)\n      iex> {:ok, _} = Registry.register(Registry.UniqueRegisterTest, \"hello\", :world)\n      iex> Registry.register(Registry.UniqueRegisterTest, \"hello\", :later)\n      {:error, {:already_registered, self()}}\n      iex> Registry.keys(Registry.UniqueRegisterTest, self())\n      [\"hello\"]\n\n  Such is possible for duplicate registries though:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateRegisterTest)\n      iex> {:ok, _} = Registry.register(Registry.DuplicateRegisterTest, \"hello\", :world)\n      iex> {:ok, _} = Registry.register(Registry.DuplicateRegisterTest, \"hello\", :world)\n      iex> Registry.keys(Registry.DuplicateRegisterTest, self())\n      [\"hello\", \"hello\"]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec register(registry, key, value) :: {:ok, pid} | {:error, {:already_registered, pid}}\n  def register(registry, key, value) when is_atom(registry) do\n    self = self()\n    {kind, partitions, key_ets, pid_ets, listeners} = info!(registry)\n    {key_partition, pid_partition} = partitions(kind, key, self, partitions)\n    key_ets = key_ets || key_ets!(registry, key_partition)\n    {pid_server, pid_ets} = pid_ets || pid_ets!(registry, pid_partition)\n\n    # Note that we write first to the pid_ets table because it will\n    # always be able to do the cleanup. If we register first to the\n    # key one and the process crashes, the key will stay there forever.\n    Process.link(pid_server)\n\n    counter = System.unique_integer()\n    true = :ets.insert(pid_ets, {self, key, key_ets, counter})\n\n    case register_key(kind, key_ets, key, {key, {self, value}}) do\n      :ok ->\n        for listener <- listeners do\n          Kernel.send(listener, {:register, registry, key, self, value})\n        end\n\n        {:ok, pid_server}\n\n      {:error, {:already_registered, ^self}} = error ->\n        true = :ets.delete_object(pid_ets, {self, key, key_ets, counter})\n        error\n\n      {:error, _} = error ->\n        true = :ets.delete_object(pid_ets, {self, key, key_ets, counter})\n        unlink_if_unregistered(pid_server, pid_ets, self)\n        error\n    end\n  end\n\n  defp register_key({:duplicate, _}, key_ets, _key, entry) do\n    true = :ets.insert(key_ets, entry)\n    :ok\n  end\n\n  defp register_key(:unique, key_ets, key, entry) do\n    if :ets.insert_new(key_ets, entry) do\n      :ok\n    else\n      # Note that we have to call register_key recursively\n      # because we are always at odds of a race condition.\n      case :ets.lookup(key_ets, key) do\n        [{^key, {pid, _}} = current] ->\n          if Process.alive?(pid) do\n            {:error, {:already_registered, pid}}\n          else\n            :ets.delete_object(key_ets, current)\n            register_key(:unique, key_ets, key, entry)\n          end\n\n        [] ->\n          register_key(:unique, key_ets, key, entry)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Reads registry metadata given on `start_link/1`.\n\n  Atoms and tuples are allowed as keys.\n\n  ## Examples\n\n      iex> Registry.start_link(keys: :unique, name: Registry.MetaTest, meta: [custom_key: \"custom_value\"])\n      iex> Registry.meta(Registry.MetaTest, :custom_key)\n      {:ok, \"custom_value\"}\n      iex> Registry.meta(Registry.MetaTest, :unknown_key)\n      :error\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec meta(registry, meta_key) :: {:ok, meta_value} | :error\n  def meta(registry, key) when is_atom(registry) and (is_atom(key) or is_tuple(key)) do\n    try do\n      :ets.lookup(registry, key)\n    catch\n      :error, :badarg ->\n        raise ArgumentError,\n              \"unknown registry: #{inspect(registry)}. Either the registry name is invalid or \" <>\n                \"the registry is not running, possibly because its application isn't started\"\n    else\n      [{^key, value}] -> {:ok, value}\n      _ -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Stores registry metadata.\n\n  Atoms and tuples are allowed as keys.\n\n  ## Examples\n\n      iex> Registry.start_link(keys: :unique, name: Registry.PutMetaTest)\n      iex> Registry.put_meta(Registry.PutMetaTest, :custom_key, \"custom_value\")\n      :ok\n      iex> Registry.meta(Registry.PutMetaTest, :custom_key)\n      {:ok, \"custom_value\"}\n      iex> Registry.put_meta(Registry.PutMetaTest, {:tuple, :key}, \"tuple_value\")\n      :ok\n      iex> Registry.meta(Registry.PutMetaTest, {:tuple, :key})\n      {:ok, \"tuple_value\"}\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec put_meta(registry, meta_key, meta_value) :: :ok\n  def put_meta(registry, key, value) when is_atom(registry) and (is_atom(key) or is_tuple(key)) do\n    try do\n      :ets.insert(registry, {key, value})\n      :ok\n    catch\n      :error, :badarg ->\n        raise ArgumentError, \"unknown registry: #{inspect(registry)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Deletes registry metadata for the given `key` in `registry`.\n\n  ## Examples\n\n      iex> Registry.start_link(keys: :unique, name: Registry.DeleteMetaTest)\n      iex> Registry.put_meta(Registry.DeleteMetaTest, :custom_key, \"custom_value\")\n      :ok\n      iex> Registry.meta(Registry.DeleteMetaTest, :custom_key)\n      {:ok, \"custom_value\"}\n      iex> Registry.delete_meta(Registry.DeleteMetaTest, :custom_key)\n      :ok\n      iex> Registry.meta(Registry.DeleteMetaTest, :custom_key)\n      :error\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec delete_meta(registry, meta_key) :: :ok\n  def delete_meta(registry, key) when is_atom(registry) and (is_atom(key) or is_tuple(key)) do\n    try do\n      :ets.delete(registry, key)\n      :ok\n    catch\n      :error, :badarg ->\n        raise ArgumentError, \"unknown registry: #{inspect(registry)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Returns the number of registered keys in a registry.\n  It runs in constant time.\n\n  ## Examples\n  In the example below we register the current process and ask for the\n  number of keys in the registry:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.UniqueCountTest)\n      iex> Registry.count(Registry.UniqueCountTest)\n      0\n      iex> {:ok, _} = Registry.register(Registry.UniqueCountTest, \"hello\", :world)\n      iex> {:ok, _} = Registry.register(Registry.UniqueCountTest, \"world\", :world)\n      iex> Registry.count(Registry.UniqueCountTest)\n      2\n\n  The same applies to duplicate registries:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateCountTest)\n      iex> Registry.count(Registry.DuplicateCountTest)\n      0\n      iex> {:ok, _} = Registry.register(Registry.DuplicateCountTest, \"hello\", :world)\n      iex> {:ok, _} = Registry.register(Registry.DuplicateCountTest, \"hello\", :world)\n      iex> Registry.count(Registry.DuplicateCountTest)\n      2\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec count(registry) :: non_neg_integer()\n  def count(registry) when is_atom(registry) do\n    case key_info!(registry) do\n      {_kind, partitions, nil} ->\n        Enum.sum_by(0..(partitions - 1), fn partition_index ->\n          safe_size(key_ets!(registry, partition_index))\n        end)\n\n      {_kind, 1, key_ets} ->\n        safe_size(key_ets)\n    end\n  end\n\n  defp safe_size(ets) do\n    try do\n      :ets.info(ets, :size)\n    catch\n      :error, :badarg -> 0\n    end\n  end\n\n  @doc \"\"\"\n  Returns the number of `{pid, value}` pairs under the given `key` in `registry`\n  that match `pattern`.\n\n  Pattern must be an atom or a tuple that will match the structure of the\n  value stored in the registry. The atom `:_` can be used to ignore a given\n  value or tuple element, while the atom `:\"$1\"` can be used to temporarily assign part\n  of pattern to a variable for a subsequent comparison.\n\n  Optionally, it is possible to pass a list of guard conditions for more precise matching.\n  Each guard is a tuple, which describes checks that should be passed by assigned part of pattern.\n  For example the `$1 > 1` guard condition would be expressed as the `{:>, :\"$1\", 1}` tuple.\n  Please note that guard conditions will work only for assigned\n  variables like `:\"$1\"`, `:\"$2\"`, and so forth.\n  Avoid usage of special match variables `:\"$_\"` and `:\"$$\"`, because it might not work as expected.\n\n  Zero will be returned if there is no match.\n\n  For unique registries, a single partition lookup is necessary. For\n  duplicate registries, all partitions must be looked up.\n\n  ## Examples\n\n  In the example below we register the current process under the same\n  key in a duplicate registry but with different values:\n\n      iex> Registry.start_link(keys: :duplicate, name: Registry.CountMatchTest)\n      iex> {:ok, _} = Registry.register(Registry.CountMatchTest, \"hello\", {1, :atom, 1})\n      iex> {:ok, _} = Registry.register(Registry.CountMatchTest, \"hello\", {2, :atom, 2})\n      iex> Registry.count_match(Registry.CountMatchTest, \"hello\", {1, :_, :_})\n      1\n      iex> Registry.count_match(Registry.CountMatchTest, \"hello\", {2, :_, :_})\n      1\n      iex> Registry.count_match(Registry.CountMatchTest, \"hello\", {:_, :atom, :_})\n      2\n      iex> Registry.count_match(Registry.CountMatchTest, \"hello\", {:\"$1\", :_, :\"$1\"})\n      2\n      iex> Registry.count_match(Registry.CountMatchTest, \"hello\", {:_, :_, :\"$1\"}, [{:>, :\"$1\", 1}])\n      1\n      iex> Registry.count_match(Registry.CountMatchTest, \"hello\", {:_, :\"$1\", :_}, [{:is_atom, :\"$1\"}])\n      2\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec count_match(registry, key, match_pattern, guards) :: non_neg_integer()\n  def count_match(registry, key, pattern, guards \\\\ [])\n      when is_atom(registry) and is_list(guards) do\n    guards = [{:\"=:=\", {:element, 1, :\"$_\"}, {:const, key}} | guards]\n    spec = [{{:_, {:_, pattern}}, guards, [true]}]\n\n    case key_info!(registry) do\n      {:unique, partitions, key_ets} ->\n        key_ets = key_ets || key_ets!(registry, key, partitions)\n        :ets.select_count(key_ets, spec)\n\n      {{:duplicate, _}, 1, key_ets} ->\n        :ets.select_count(key_ets, spec)\n\n      {{:duplicate, _}, partitions, _key_ets} ->\n        Enum.sum_by(0..(partitions - 1), fn partition_index ->\n          :ets.select_count(key_ets!(registry, partition_index), spec)\n        end)\n    end\n  end\n\n  @doc \"\"\"\n  Select key, pid, and values registered using full match specs.\n\n  The `spec` consists of a list of three part tuples, in the shape of `[{match_pattern, guards, body}]`.\n\n  The first part, the match pattern, must be a tuple that will match the structure of the\n  the data stored in the registry, which is `{key, pid, value}`. The atom `:_` can be used to\n  ignore a given value or tuple element, while the atom `:\"$1\"` can be used to temporarily\n  assign part of pattern to a variable for a subsequent comparison. This can be combined\n  like `{:\"$1\", :_, :_}`.\n\n  The second part, the guards, is a list of conditions that allow filtering the results.\n  Each guard is a tuple, which describes checks that should be passed by assigned part of pattern.\n  For example the `$1 > 1` guard condition would be expressed as the `{:>, :\"$1\", 1}` tuple.\n  Please note that guard conditions will work only for assigned\n  variables like `:\"$1\"`, `:\"$2\"`, and so forth.\n\n  The third part, the body, is a list of shapes of the returned entries. Like guards, you have access to\n  assigned variables like `:\"$1\"`, which you can combine with hard-coded values to freely shape entries\n  Note that tuples have to be wrapped in an additional tuple. To get a result format like\n  `%{key: key, pid: pid, value: value}`, assuming you bound those variables in order in the match part,\n  you would provide a body like `[%{key: :\"$1\", pid: :\"$2\", value: :\"$3\"}]`. Like guards, you can use\n  some operations like `:element` to modify the output format.\n\n  Do not use special match variables `:\"$_\"` and `:\"$$\"`, because they might not work as expected.\n\n  Note that for large registries with many partitions this will be costly as it builds the result by\n  concatenating all the partitions.\n\n  ## Examples\n\n  This example shows how to get everything from the registry:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.SelectAllTest)\n      iex> {:ok, _} = Registry.register(Registry.SelectAllTest, \"hello\", :value)\n      iex> {:ok, _} = Registry.register(Registry.SelectAllTest, \"world\", :value)\n      iex> Registry.select(Registry.SelectAllTest, [{{:\"$1\", :\"$2\", :\"$3\"}, [], [{{:\"$1\", :\"$2\", :\"$3\"}}]}]) |> Enum.sort()\n      [{\"hello\", self(), :value}, {\"world\", self(), :value}]\n\n  If you want to get keys, you can pass a separate selector:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.SelectKeysTest)\n      iex> {:ok, _} = Registry.register(Registry.SelectKeysTest, \"hello\", :value)\n      iex> {:ok, _} = Registry.register(Registry.SelectKeysTest, \"world\", :value)\n      iex> Registry.select(Registry.SelectKeysTest, [{{:\"$1\", :_, :_}, [], [:\"$1\"]}]) |> Enum.sort()\n      [\"hello\", \"world\"]\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec select(registry, spec) :: [term]\n  def select(registry, spec)\n      when is_atom(registry) and is_list(spec) do\n    spec = group_match_headers(spec, __ENV__.function)\n\n    case key_info!(registry) do\n      {_kind, partitions, nil} ->\n        Enum.flat_map(0..(partitions - 1), fn partition_index ->\n          :ets.select(key_ets!(registry, partition_index), spec)\n        end)\n\n      {_kind, 1, key_ets} ->\n        :ets.select(key_ets, spec)\n    end\n  end\n\n  @doc \"\"\"\n  Works like `select/2`, but only returns the number of matching records.\n\n  ## Examples\n\n  In the example below we register the current process under different\n  keys in a unique registry but with the same value:\n\n      iex> Registry.start_link(keys: :unique, name: Registry.CountSelectTest)\n      iex> {:ok, _} = Registry.register(Registry.CountSelectTest, \"hello\", :value)\n      iex> {:ok, _} = Registry.register(Registry.CountSelectTest, \"world\", :value)\n      iex> Registry.count_select(Registry.CountSelectTest, [{{:_, :_, :value}, [], [true]}])\n      2\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec count_select(registry, spec) :: non_neg_integer()\n  def count_select(registry, spec)\n      when is_atom(registry) and is_list(spec) do\n    spec = group_match_headers(spec, __ENV__.function)\n\n    case key_info!(registry) do\n      {_kind, partitions, nil} ->\n        Enum.sum_by(0..(partitions - 1), fn partition_index ->\n          :ets.select_count(key_ets!(registry, partition_index), spec)\n        end)\n\n      {_kind, 1, key_ets} ->\n        :ets.select_count(key_ets, spec)\n    end\n  end\n\n  defp group_match_headers(spec, {fun, arity}) do\n    for part <- spec do\n      case part do\n        {{key, pid, value}, guards, select} ->\n          {{key, {pid, value}}, guards, select}\n\n        _ ->\n          raise ArgumentError,\n                \"invalid match specification in Registry.#{fun}/#{arity}: #{inspect(spec)}\"\n      end\n    end\n  end\n\n  ## Helpers\n\n  @compile {:inline, hash: 2}\n\n  defp hash(term, limit) do\n    :erlang.phash2(term, limit)\n  end\n\n  defp info!(registry) do\n    try do\n      :ets.lookup_element(registry, @all_info, 2)\n    catch\n      :error, :badarg ->\n        raise ArgumentError, \"unknown registry: #{inspect(registry)}\"\n    end\n  end\n\n  defp key_info!(registry) do\n    try do\n      :ets.lookup_element(registry, @key_info, 2)\n    catch\n      :error, :badarg ->\n        raise ArgumentError, \"unknown registry: #{inspect(registry)}\"\n    end\n  end\n\n  defp key_ets!(registry, key, partitions) do\n    :ets.lookup_element(registry, hash(key, partitions), 2)\n  end\n\n  defp key_ets!(registry, partition) do\n    :ets.lookup_element(registry, partition, 2)\n  end\n\n  defp pid_ets!(registry, key, partitions) do\n    :ets.lookup_element(registry, hash(key, partitions), 3)\n  end\n\n  defp pid_ets!(registry, partition) do\n    :ets.lookup_element(registry, partition, 3)\n  end\n\n  defp safe_lookup_second(ets, key) do\n    try do\n      :ets.lookup_element(ets, key, 2)\n    catch\n      :error, :badarg -> []\n    end\n  end\n\n  defp partitions(:unique, key, pid, partitions) do\n    {hash(key, partitions), hash(pid, partitions)}\n  end\n\n  defp partitions({:duplicate, :key}, key, _pid, partitions) do\n    partition = hash(key, partitions)\n    {partition, partition}\n  end\n\n  defp partitions({:duplicate, :pid}, _key, pid, partitions) do\n    partition = hash(pid, partitions)\n    {partition, partition}\n  end\n\n  defp unlink_if_unregistered(pid_server, pid_ets, self) do\n    if not :ets.member(pid_ets, self) do\n      Process.unlink(pid_server)\n    end\n  end\n\n  @doc false\n  def __unregister__(table, match, pos) do\n    key = :erlang.element(pos, match)\n\n    # We need to perform an element comparison if we have a special atom key.\n    if is_atom(key) and reserved_atom?(Atom.to_string(key)) do\n      match = :erlang.setelement(pos, match, :_)\n      guard = {:\"=:=\", {:element, pos, :\"$_\"}, {:const, key}}\n      :ets.select_delete(table, [{match, [guard], [true]}]) >= 0\n    else\n      :ets.match_delete(table, match)\n    end\n  end\n\n  defp reserved_atom?(\"_\"), do: true\n  defp reserved_atom?(\"$\" <> _), do: true\n  defp reserved_atom?(_), do: false\nend\n\ndefmodule Registry.Supervisor do\n  @moduledoc false\n  use Supervisor\n\n  def start_link(kind, registry, partitions, listeners, entries, compressed) do\n    arg = {kind, registry, partitions, listeners, entries, compressed}\n    Supervisor.start_link(__MODULE__, arg, name: registry)\n  end\n\n  def init({kind, registry, partitions, listeners, entries, compressed}) do\n    ^registry = :ets.new(registry, [:set, :public, :named_table, read_concurrency: true])\n    true = :ets.insert(registry, entries)\n\n    children =\n      for i <- 0..(partitions - 1) do\n        key_partition = Registry.Partition.key_name(registry, i)\n        pid_partition = Registry.Partition.pid_name(registry, i)\n        arg = {kind, registry, i, partitions, key_partition, pid_partition, listeners, compressed}\n\n        %{\n          id: pid_partition,\n          start: {Registry.Partition, :start_link, [pid_partition, arg]}\n        }\n      end\n\n    Supervisor.init(children, strategy: strategy_for_kind(kind))\n  end\n\n  # Unique registries have their key partition hashed by key.\n  # This means that, if a PID partition crashes, it may have\n  # entries from all key partitions, so we need to crash all.\n  defp strategy_for_kind(:unique), do: :one_for_all\n\n  # Duplicate registries have both key and pid partitions hashed\n  # by key ({:duplicate, :key}) or pid ({:duplicate, :pid}).\n  # This means that, if a PID or key partition crashes, all of\n  # its associated entries are in its sibling table, so we crash one.\n  defp strategy_for_kind({:duplicate, _}), do: :one_for_one\nend\n\ndefmodule Registry.Partition do\n  @moduledoc false\n\n  # This process owns the equivalent key and pid ETS tables\n  # and is responsible for linking to processes that map to\n  # its own pid table.\n  use GenServer\n  @all_info -1\n  @key_info -2\n\n  @doc \"\"\"\n  Returns the name of key partition table.\n  \"\"\"\n  @spec key_name(atom, non_neg_integer) :: atom\n  def key_name(registry, partition) do\n    Module.concat(registry, \"KeyPartition\" <> Integer.to_string(partition))\n  end\n\n  @doc \"\"\"\n  Returns the name of pid partition table.\n  \"\"\"\n  @spec pid_name(atom, non_neg_integer) :: atom\n  def pid_name(name, partition) do\n    Module.concat(name, \"PIDPartition\" <> Integer.to_string(partition))\n  end\n\n  @doc \"\"\"\n  Starts the registry partition.\n\n  The process is only responsible for linking and cleaning up when processes crash.\n  \"\"\"\n  def start_link(registry, arg) do\n    GenServer.start_link(__MODULE__, arg, name: registry)\n  end\n\n  @doc \"\"\"\n  Runs function with a lock.\n  \"\"\"\n  def lock(pid, key, lock) do\n    ref = GenServer.call(pid, {:lock, key})\n\n    try do\n      lock.()\n    after\n      send(pid, {:unlock, key, ref})\n    end\n  end\n\n  ## Callbacks\n\n  def init({kind, registry, i, partitions, key_partition, pid_partition, listeners, compressed}) do\n    Process.flag(:trap_exit, true)\n\n    key_ets = init_key_ets(kind, key_partition, compressed)\n    pid_ets = init_pid_ets(kind, pid_partition)\n\n    # If we have only one partition, we do an optimization which\n    # is to write the table information alongside the registry info.\n    if partitions == 1 do\n      entries = [\n        {@key_info, {kind, partitions, key_ets}},\n        {@all_info, {kind, partitions, key_ets, {self(), pid_ets}, listeners}}\n      ]\n\n      true = :ets.insert(registry, entries)\n    else\n      true = :ets.insert(registry, {i, key_ets, {self(), pid_ets}})\n    end\n\n    {:ok, {pid_ets, %{}}}\n  end\n\n  # The key partition is a set for unique keys,\n  # duplicate bag for duplicate ones.\n  defp init_key_ets(:unique, key_partition, compressed) do\n    opts = [:set, :public, read_concurrency: true, write_concurrency: true]\n    :ets.new(key_partition, compression_opt(opts, compressed))\n  end\n\n  defp init_key_ets({:duplicate, _}, key_partition, compressed) do\n    opts = [:duplicate_bag, :public, read_concurrency: true, write_concurrency: true]\n    :ets.new(key_partition, compression_opt(opts, compressed))\n  end\n\n  defp compression_opt(opts, compressed) do\n    if compressed, do: [:compressed] ++ opts, else: opts\n  end\n\n  # A process can always have multiple keys, so the\n  # pid partition is always a duplicate bag.\n  defp init_pid_ets(_, pid_partition) do\n    :ets.new(pid_partition, [\n      :duplicate_bag,\n      :public,\n      read_concurrency: true,\n      write_concurrency: true\n    ])\n  end\n\n  def handle_call(:sync, _, state) do\n    {:reply, :ok, state}\n  end\n\n  def handle_call({:lock, key}, from, {ets, lock}) do\n    lock =\n      case lock do\n        %{^key => queue} ->\n          Map.put(lock, key, :queue.in(from, queue))\n\n        %{} ->\n          go(from, key)\n          Map.put(lock, key, :queue.new())\n      end\n\n    {:noreply, {ets, lock}}\n  end\n\n  def handle_info({:EXIT, pid, _reason}, {ets, lock}) do\n    entries = :ets.take(ets, pid)\n\n    for {_pid, key, key_ets, _counter} <- entries do\n      key_ets =\n        case key_ets do\n          # In case the fake key_ets is being used. See unregister_match/2.\n          {key_ets, _} ->\n            key_ets\n\n          _ ->\n            key_ets\n        end\n\n      try do\n        Registry.__unregister__(key_ets, {key, {pid, :_}}, 1)\n      catch\n        :error, :badarg -> :badarg\n      end\n    end\n\n    {:noreply, {ets, lock}}\n  end\n\n  def handle_info({{:unlock, key}, _ref, :process, _pid, _reason}, state) do\n    unlock(key, state)\n  end\n\n  def handle_info({:unlock, key, ref}, state) do\n    Process.demonitor(ref, [:flush])\n    unlock(key, state)\n  end\n\n  defp unlock(key, {ets, lock}) do\n    %{^key => queue} = lock\n\n    lock =\n      case dequeue(queue, key) do\n        :empty -> Map.delete(lock, key)\n        {:not_empty, queue} -> Map.put(lock, key, queue)\n      end\n\n    {:noreply, {ets, lock}}\n  end\n\n  defp dequeue(queue, key) do\n    case :queue.out(queue) do\n      {:empty, _} ->\n        :empty\n\n      {{:value, {pid, _tag} = from}, queue} ->\n        if node(pid) != node() or Process.alive?(pid) do\n          go(from, key)\n          {:not_empty, queue}\n        else\n          dequeue(queue, key)\n        end\n    end\n  end\n\n  defp go({pid, _tag} = from, key) do\n    ref = Process.monitor(pid, tag: {:unlock, key})\n    GenServer.reply(from, ref)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/set.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Set do\n  @moduledoc ~S\"\"\"\n  Generic API for sets.\n\n  This module is deprecated, use the `MapSet` module instead.\n  \"\"\"\n\n  @moduledoc deprecated: \"Use MapSet instead\"\n\n  @type value :: any\n  @type values :: [value]\n  @type t :: map\n\n  message = \"Use the MapSet module for working with sets\"\n\n  defmacrop target(set) do\n    quote do\n      case unquote(set) do\n        %module{} -> module\n        set -> unsupported_set(set)\n      end\n    end\n  end\n\n  @deprecated message\n  def delete(set, value) do\n    target(set).delete(set, value)\n  end\n\n  @deprecated message\n  def difference(set1, set2) do\n    target1 = target(set1)\n    target2 = target(set2)\n\n    if target1 == target2 do\n      target1.difference(set1, set2)\n    else\n      Enumerable.reduce(set2, {:cont, set1}, fn v, acc ->\n        {:cont, target1.delete(acc, v)}\n      end)\n      |> elem(1)\n    end\n  end\n\n  @deprecated message\n  def disjoint?(set1, set2) do\n    target1 = target(set1)\n    target2 = target(set2)\n\n    if target1 == target2 do\n      target1.disjoint?(set1, set2)\n    else\n      Enumerable.reduce(set2, {:cont, true}, fn member, acc ->\n        case target1.member?(set1, member) do\n          false -> {:cont, acc}\n          _ -> {:halt, false}\n        end\n      end)\n      |> elem(1)\n    end\n  end\n\n  @deprecated message\n  def empty(set) do\n    target(set).empty(set)\n  end\n\n  @deprecated message\n  def equal?(set1, set2) do\n    target1 = target(set1)\n    target2 = target(set2)\n\n    cond do\n      target1 == target2 ->\n        target1.equal?(set1, set2)\n\n      target1.size(set1) == target2.size(set2) ->\n        do_subset?(target1, target2, set1, set2)\n\n      true ->\n        false\n    end\n  end\n\n  @deprecated message\n  def intersection(set1, set2) do\n    target1 = target(set1)\n    target2 = target(set2)\n\n    if target1 == target2 do\n      target1.intersection(set1, set2)\n    else\n      Enumerable.reduce(set1, {:cont, target1.new()}, fn v, acc ->\n        {:cont, if(target2.member?(set2, v), do: target1.put(acc, v), else: acc)}\n      end)\n      |> elem(1)\n    end\n  end\n\n  @deprecated message\n  def member?(set, value) do\n    target(set).member?(set, value)\n  end\n\n  @deprecated message\n  def put(set, value) do\n    target(set).put(set, value)\n  end\n\n  @deprecated message\n  def size(set) do\n    target(set).size(set)\n  end\n\n  @deprecated message\n  def subset?(set1, set2) do\n    target1 = target(set1)\n    target2 = target(set2)\n\n    if target1 == target2 do\n      target1.subset?(set1, set2)\n    else\n      do_subset?(target1, target2, set1, set2)\n    end\n  end\n\n  @deprecated message\n  def to_list(set) do\n    target(set).to_list(set)\n  end\n\n  @deprecated message\n  def union(set1, set2) do\n    target1 = target(set1)\n    target2 = target(set2)\n\n    if target1 == target2 do\n      target1.union(set1, set2)\n    else\n      Enumerable.reduce(set2, {:cont, set1}, fn v, acc ->\n        {:cont, target1.put(acc, v)}\n      end)\n      |> elem(1)\n    end\n  end\n\n  defp do_subset?(_target1, target2, set1, set2) do\n    Enumerable.reduce(set1, {:cont, true}, fn member, acc ->\n      case target2.member?(set2, member) do\n        true -> {:cont, acc}\n        _ -> {:halt, false}\n      end\n    end)\n    |> elem(1)\n  end\n\n  defp unsupported_set(set) do\n    raise ArgumentError, \"unsupported set: #{inspect(set)}\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/stream/reducers.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Stream.Reducers do\n  # Collection of reducers and utilities shared by Enum and Stream.\n  @moduledoc false\n\n  def zip_with(enumerables, zip_fun) when is_function(zip_fun, 1) do\n    if is_list(enumerables) and :lists.all(&is_list/1, enumerables) do\n      &zip_list(enumerables, &1, &2, zip_fun)\n    else\n      &zip_enum(enumerables, &1, &2, zip_fun)\n    end\n  end\n\n  defp zip_list(_enumerables, {:halt, acc}, _fun, _zip_fun) do\n    {:halted, acc}\n  end\n\n  defp zip_list(enumerables, {:suspend, acc}, fun, zip_fun) do\n    {:suspended, acc, &zip_list(enumerables, &1, fun, zip_fun)}\n  end\n\n  defp zip_list([], {:cont, acc}, _fun, _zip_fun), do: {:done, acc}\n\n  defp zip_list(enumerables, {:cont, acc}, fun, zip_fun) do\n    case zip_list_heads_tails(enumerables, [], []) do\n      {heads, tails} -> zip_list(tails, fun.(zip_fun.(heads), acc), fun, zip_fun)\n      :error -> {:done, acc}\n    end\n  end\n\n  defp zip_list_heads_tails([[head | tail] | rest], heads, tails) do\n    zip_list_heads_tails(rest, [head | heads], [tail | tails])\n  end\n\n  defp zip_list_heads_tails([[] | _rest], _heads, _tails) do\n    :error\n  end\n\n  defp zip_list_heads_tails([], heads, tails) do\n    {:lists.reverse(heads), :lists.reverse(tails)}\n  end\n\n  defp zip_enum(enumerables, acc, fun, zip_fun) do\n    step = fn x, acc ->\n      {:suspend, :lists.reverse([x | acc])}\n    end\n\n    enum_funs =\n      Enum.map(enumerables, fn enum ->\n        {&Enumerable.reduce(enum, &1, step), [], :cont}\n      end)\n\n    do_zip_enum(enum_funs, acc, fun, zip_fun)\n  end\n\n  # This implementation of do_zip_enum/4 works for any number of streams to zip\n  defp do_zip_enum(zips, {:halt, acc}, _fun, _zip_fun) do\n    do_zip_close(zips)\n    {:halted, acc}\n  end\n\n  defp do_zip_enum(zips, {:suspend, acc}, fun, zip_fun) do\n    {:suspended, acc, &do_zip_enum(zips, &1, fun, zip_fun)}\n  end\n\n  defp do_zip_enum([], {:cont, acc}, _callback, _zip_fun) do\n    {:done, acc}\n  end\n\n  defp do_zip_enum(zips, {:cont, acc}, callback, zip_fun) do\n    try do\n      do_zip_next(zips, acc, callback, [], [], zip_fun)\n    catch\n      kind, reason ->\n        do_zip_close(zips)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {:next, buffer, acc} ->\n        do_zip_enum(buffer, acc, callback, zip_fun)\n\n      {:done, _acc} = other ->\n        other\n    end\n  end\n\n  # do_zip_next/6 computes the next tuple formed by\n  # the next element of each zipped stream.\n  defp do_zip_next(\n         [{_, [], :halt} | zips],\n         acc,\n         _callback,\n         _yielded_elems,\n         buffer,\n         _zip_fun\n       ) do\n    do_zip_close(:lists.reverse(buffer, zips))\n    {:done, acc}\n  end\n\n  defp do_zip_next([{fun, [], :cont} | zips], acc, callback, yielded_elems, buffer, zip_fun) do\n    case fun.({:cont, []}) do\n      {:suspended, [elem | next_acc], fun} ->\n        next_buffer = [{fun, next_acc, :cont} | buffer]\n        do_zip_next(zips, acc, callback, [elem | yielded_elems], next_buffer, zip_fun)\n\n      {_, [elem | next_acc]} ->\n        next_buffer = [{fun, next_acc, :halt} | buffer]\n        do_zip_next(zips, acc, callback, [elem | yielded_elems], next_buffer, zip_fun)\n\n      {_, []} ->\n        # The current zipped stream terminated, so we close all the streams\n        # and return {:halted, acc} (which is returned as is by do_zip/3).\n        do_zip_close(:lists.reverse(buffer, zips))\n        {:done, acc}\n    end\n  end\n\n  defp do_zip_next(\n         [{fun, zip_acc, zip_op} | zips],\n         acc,\n         callback,\n         yielded_elems,\n         buffer,\n         zip_fun\n       ) do\n    [elem | rest] = zip_acc\n    next_buffer = [{fun, rest, zip_op} | buffer]\n    do_zip_next(zips, acc, callback, [elem | yielded_elems], next_buffer, zip_fun)\n  end\n\n  defp do_zip_next([] = _zips, acc, callback, yielded_elems, buffer, zip_fun) do\n    # \"yielded_elems\" is a reversed list of results for the current iteration of\n    # zipping. That is to say, the nth element from each of the enums being zipped.\n    # It needs to be reversed and passed to the zipping function so it can do it's thing.\n    {:next, :lists.reverse(buffer), callback.(zip_fun.(:lists.reverse(yielded_elems)), acc)}\n  end\n\n  defp do_zip_close(zips) do\n    :lists.foreach(fn {fun, _, _} -> fun.({:halt, []}) end, zips)\n  end\n\n  def chunk_every(chunk_by, enumerable, count, step, leftover) do\n    limit = :erlang.max(count, step)\n\n    chunk_fun = fn entry, {acc_buffer, acc_count} ->\n      acc_buffer = [entry | acc_buffer]\n      acc_count = acc_count + 1\n\n      new_state =\n        if acc_count >= limit do\n          remaining = acc_count - step\n          {Enum.take(acc_buffer, remaining), remaining}\n        else\n          {acc_buffer, acc_count}\n        end\n\n      if acc_count == count do\n        {:cont, :lists.reverse(acc_buffer), new_state}\n      else\n        {:cont, new_state}\n      end\n    end\n\n    after_fun = fn {acc_buffer, acc_count} ->\n      if leftover == :discard or acc_count == 0 or acc_count >= count do\n        {:cont, []}\n      else\n        {:cont, :lists.reverse(acc_buffer, Enum.take(leftover, count - acc_count)), []}\n      end\n    end\n\n    chunk_by.(enumerable, {[], 0}, chunk_fun, after_fun)\n  end\n\n  def chunk_by(chunk_by, enumerable, fun) do\n    chunk_fun = fn\n      entry, nil ->\n        {:cont, {[entry], fun.(entry)}}\n\n      entry, {acc, value} ->\n        case fun.(entry) do\n          ^value -> {:cont, {[entry | acc], value}}\n          new_value -> {:cont, :lists.reverse(acc), {[entry], new_value}}\n        end\n    end\n\n    after_fun = fn\n      nil -> {:cont, :done}\n      {acc, _value} -> {:cont, :lists.reverse(acc), :done}\n    end\n\n    chunk_by.(enumerable, nil, chunk_fun, after_fun)\n  end\n\n  defmacro dedup(callback, fun \\\\ nil) do\n    quote do\n      fn entry, acc(head, prev, tail) = acc ->\n        value = unquote(callback).(entry)\n\n        case prev do\n          {:value, ^value} -> skip(acc)\n          _ -> next_with_acc(unquote(fun), entry, head, {:value, value}, tail)\n        end\n      end\n    end\n  end\n\n  defmacro drop(fun \\\\ nil) do\n    quote do\n      fn\n        _entry, acc(head, amount, tail) when amount > 0 ->\n          skip(acc(head, amount - 1, tail))\n\n        entry, acc(head, amount, tail) ->\n          next_with_acc(unquote(fun), entry, head, amount, tail)\n      end\n    end\n  end\n\n  defmacro drop_every(nth, fun \\\\ nil) do\n    quote do\n      fn\n        entry, acc(head, curr, tail) when curr in [unquote(nth), :first] ->\n          skip(acc(head, 1, tail))\n\n        entry, acc(head, curr, tail) ->\n          next_with_acc(unquote(fun), entry, head, curr + 1, tail)\n      end\n    end\n  end\n\n  defmacro drop_while(callback, fun \\\\ nil) do\n    quote do\n      fn entry, acc(head, bool, tail) = original ->\n        if bool and unquote(callback).(entry) do\n          skip(original)\n        else\n          next_with_acc(unquote(fun), entry, head, false, tail)\n        end\n      end\n    end\n  end\n\n  defmacro filter(callback, fun \\\\ nil) do\n    quote do\n      fn entry, acc ->\n        if unquote(callback).(entry) do\n          next(unquote(fun), entry, acc)\n        else\n          skip(acc)\n        end\n      end\n    end\n  end\n\n  defmacro filter_map(filter, mapper, fun \\\\ nil) do\n    quote do\n      fn entry, acc ->\n        if unquote(filter).(entry) do\n          next(unquote(fun), unquote(mapper).(entry), acc)\n        else\n          skip(acc)\n        end\n      end\n    end\n  end\n\n  defmacro map(callback, fun \\\\ nil) do\n    quote do\n      fn entry, acc ->\n        next(unquote(fun), unquote(callback).(entry), acc)\n      end\n    end\n  end\n\n  defmacro map_every(nth, mapper, fun \\\\ nil) do\n    quote do\n      fn\n        entry, acc(head, curr, tail) when curr in [unquote(nth), :first] ->\n          next_with_acc(unquote(fun), unquote(mapper).(entry), head, 1, tail)\n\n        entry, acc(head, curr, tail) ->\n          next_with_acc(unquote(fun), entry, head, curr + 1, tail)\n      end\n    end\n  end\n\n  defmacro reject(callback, fun \\\\ nil) do\n    quote do\n      fn entry, acc ->\n        if unquote(callback).(entry) do\n          skip(acc)\n        else\n          next(unquote(fun), entry, acc)\n        end\n      end\n    end\n  end\n\n  defmacro scan2(callback, fun \\\\ nil) do\n    quote do\n      fn\n        entry, acc(head, :first, tail) ->\n          next_with_acc(unquote(fun), entry, head, {:ok, entry}, tail)\n\n        entry, acc(head, {:ok, acc}, tail) ->\n          value = unquote(callback).(entry, acc)\n          next_with_acc(unquote(fun), value, head, {:ok, value}, tail)\n      end\n    end\n  end\n\n  defmacro scan3(callback, fun \\\\ nil) do\n    quote do\n      fn entry, acc(head, acc, tail) ->\n        value = unquote(callback).(entry, acc)\n        next_with_acc(unquote(fun), value, head, value, tail)\n      end\n    end\n  end\n\n  defmacro take(fun \\\\ nil) do\n    quote do\n      fn entry, acc(head, curr, tail) = original ->\n        case curr do\n          0 ->\n            {:halt, original}\n\n          1 ->\n            {_, acc} = next_with_acc(unquote(fun), entry, head, 0, tail)\n            {:halt, acc}\n\n          _ ->\n            next_with_acc(unquote(fun), entry, head, curr - 1, tail)\n        end\n      end\n    end\n  end\n\n  defmacro take_every(nth, fun \\\\ nil) do\n    quote do\n      fn\n        entry, acc(head, curr, tail) when curr in [unquote(nth), :first] ->\n          next_with_acc(unquote(fun), entry, head, 1, tail)\n\n        entry, acc(head, curr, tail) ->\n          skip(acc(head, curr + 1, tail))\n      end\n    end\n  end\n\n  defmacro take_while(callback, fun \\\\ nil) do\n    quote do\n      fn entry, acc ->\n        if unquote(callback).(entry) do\n          next(unquote(fun), entry, acc)\n        else\n          {:halt, acc}\n        end\n      end\n    end\n  end\n\n  defmacro uniq_by(callback, fun \\\\ nil) do\n    quote do\n      fn entry, acc(head, prev, tail) = original ->\n        value = unquote(callback).(entry)\n\n        if Map.has_key?(prev, value) do\n          skip(original)\n        else\n          next_with_acc(unquote(fun), entry, head, Map.put(prev, value, true), tail)\n        end\n      end\n    end\n  end\n\n  defmacro with_index(fun) do\n    quote do\n      fn entry, acc(head, counter, tail) ->\n        next_with_acc(unquote(fun), {entry, counter}, head, counter + 1, tail)\n      end\n    end\n  end\n\n  defmacro with_index(callback, fun) do\n    quote do\n      fn entry, acc(head, counter, tail) ->\n        next_with_acc(unquote(fun), unquote(callback).(entry, counter), head, counter + 1, tail)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/stream.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Stream do\n  @moduledoc \"\"\"\n  Functions for creating and composing streams.\n\n  Streams are composable, lazy enumerables (for an introduction on\n  enumerables, see the `Enum` module). Any enumerable that generates\n  elements one by one during enumeration is called a stream. For example,\n  Elixir's `Range` is a stream:\n\n      iex> range = 1..5\n      1..5\n      iex> Enum.map(range, &(&1 * 2))\n      [2, 4, 6, 8, 10]\n\n  In the example above, as we mapped over the range, the elements being\n  enumerated were created one by one, during enumeration. The `Stream`\n  module allows us to map the range, without triggering its enumeration:\n\n      iex> range = 1..3\n      iex> stream = Stream.map(range, &(&1 * 2))\n      iex> Enum.map(stream, &(&1 + 1))\n      [3, 5, 7]\n\n  Note that we started with a range and then we created a stream that is\n  meant to multiply each element in the range by 2. At this point, no\n  computation was done. Only when `Enum.map/2` is called we actually\n  enumerate over each element in the range, multiplying it by 2 and adding 1.\n  We say the functions in `Stream` are *lazy* and the functions in `Enum`\n  are *eager*.\n\n  Due to their laziness, streams are useful when working with large\n  (or even infinite) collections. When chaining many operations with `Enum`,\n  intermediate lists are created, while `Stream` creates a recipe of\n  computations that are executed at a later moment. Then when the\n  stream is consumed later on, most commonly by using a function in\n  the `Enum` module, the stream will emit its elements one by one.\n\n  Let's see another example:\n\n      1..3\n      |> Enum.map(&IO.inspect(&1))\n      |> Enum.map(&(&1 * 2))\n      |> Enum.map(&IO.inspect(&1))\n      1\n      2\n      3\n      2\n      4\n      6\n      #=> [2, 4, 6]\n\n  Note that we first printed each element in the list, then multiplied each\n  element by 2 and finally printed each new value. In this example, the list\n  was enumerated three times. Let's see an example with streams:\n\n      stream = 1..3\n      |> Stream.map(&IO.inspect(&1))\n      |> Stream.map(&(&1 * 2))\n      |> Stream.map(&IO.inspect(&1))\n      Enum.to_list(stream)\n      1\n      2\n      2\n      4\n      3\n      6\n      #=> [2, 4, 6]\n\n  Although the end result is the same, the order in which the elements were\n  printed changed! With streams, we print the first element and then print\n  its double. In this example, the list was enumerated just once!\n\n  That's what we meant when we said earlier that streams are composable,\n  lazy enumerables. Note that we could call `Stream.map/2` multiple times,\n  effectively composing the streams and keeping them lazy. The computations\n  are only performed when you call a function from the `Enum` module.\n\n  Like with `Enum`, the functions in this module work in linear time. This\n  means that, the time it takes to perform an operation grows at the same\n  rate as the length of the list. This is expected on operations such as\n  `Stream.map/2`. After all, if we want to traverse every element on a\n  stream, the longer the stream, the more elements we need to traverse,\n  and the longer it will take.\n\n  ## Creating Streams\n\n  There are many functions in Elixir's standard library that return\n  streams, some examples are:\n\n    * `IO.stream/2`         - streams input lines, one by one\n    * `URI.query_decoder/1` - decodes a query string, pair by pair\n\n  This module also provides many convenience functions for creating streams,\n  like `Stream.cycle/1`, `Stream.unfold/2`, `Stream.resource/3` and more.\n\n  > #### Do not check for `Stream` structs\n  >\n  > While some functions in this module may return the `Stream` struct,\n  > you must never explicitly check for the `Stream` struct, as streams\n  > may come in several shapes, such as `IO.Stream`, `File.Stream`, or\n  > even `Range`s.\n  >\n  > The functions in this module only guarantee to return enumerables\n  > and their implementation (structs, anonymous functions, etc) may\n  > change at any time. For example, a function that returns an anonymous\n  > function today may return a struct in future releases.\n  >\n  > Instead of checking for a particular type, you must instead write\n  > assertive code that assumes you have an enumerable, using the functions\n  > in the `Enum` or `Stream` module accordingly.\n  \"\"\"\n\n  @doc false\n  defstruct enum: nil, funs: [], accs: [], done: nil\n\n  @type acc :: any\n  @type element :: any\n\n  @typedoc \"Zero-based index.\"\n  @type index :: non_neg_integer\n\n  @type default :: any\n  @type timer :: non_neg_integer | :infinity\n\n  # Require Stream.Reducers and its callbacks\n  require Stream.Reducers, as: R\n\n  defmacrop skip(acc) do\n    {:cont, acc}\n  end\n\n  defmacrop next(fun, entry, acc) do\n    quote(do: unquote(fun).(unquote(entry), unquote(acc)))\n  end\n\n  defmacrop acc(head, state, tail) do\n    quote(do: [unquote(head), unquote(state) | unquote(tail)])\n  end\n\n  defmacrop next_with_acc(fun, entry, head, state, tail) do\n    quote do\n      {reason, [head | tail]} = unquote(fun).(unquote(entry), [unquote(head) | unquote(tail)])\n      {reason, [head, unquote(state) | tail]}\n    end\n  end\n\n  ## Transformers\n\n  @doc false\n  @deprecated \"Use Stream.chunk_every/2 instead\"\n  def chunk(enum, n), do: chunk(enum, n, n, nil)\n\n  @doc false\n  @deprecated \"Use Stream.chunk_every/3 instead\"\n  def chunk(enum, n, step) do\n    chunk_every(enum, n, step, nil)\n  end\n\n  @doc false\n  @deprecated \"Use Stream.chunk_every/4 instead\"\n  def chunk(enum, n, step, leftover)\n      when is_integer(n) and n > 0 and is_integer(step) and step > 0 do\n    chunk_every(enum, n, step, leftover || :discard)\n  end\n\n  @doc \"\"\"\n  Shortcut to `chunk_every(enum, count, count)`.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec chunk_every(Enumerable.t(), pos_integer) :: Enumerable.t()\n  def chunk_every(enum, count), do: chunk_every(enum, count, count, [])\n\n  @doc \"\"\"\n  Streams the enumerable in chunks, containing `count` elements each,\n  where each new chunk starts `step` elements into the enumerable.\n\n  `step` is optional and, if not passed, defaults to `count`, i.e.\n  chunks do not overlap. Chunking will stop as soon as the collection\n  ends or when we emit an incomplete chunk.\n\n  If the last chunk does not have `count` elements to fill the chunk,\n  elements are taken from `leftover` to fill in the chunk. If `leftover`\n  does not have enough elements to fill the chunk, then a partial chunk\n  is returned with less than `count` elements.\n\n  If `:discard` is given in `leftover`, the last chunk is discarded\n  unless it has exactly `count` elements.\n\n  ## Examples\n\n      iex> Stream.chunk_every([1, 2, 3, 4, 5, 6], 2) |> Enum.to_list()\n      [[1, 2], [3, 4], [5, 6]]\n\n      iex> Stream.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, :discard) |> Enum.to_list()\n      [[1, 2, 3], [3, 4, 5]]\n\n      iex> Stream.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, [7]) |> Enum.to_list()\n      [[1, 2, 3], [3, 4, 5], [5, 6, 7]]\n\n      iex> Stream.chunk_every([1, 2, 3, 4, 5, 6], 3, 3, []) |> Enum.to_list()\n      [[1, 2, 3], [4, 5, 6]]\n\n      iex> Stream.chunk_every([1, 2, 3, 4], 3, 3, Stream.cycle([0])) |> Enum.to_list()\n      [[1, 2, 3], [4, 0, 0]]\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec chunk_every(Enumerable.t(), pos_integer, pos_integer, Enumerable.t() | :discard) ::\n          Enumerable.t()\n  def chunk_every(enum, count, step, leftover \\\\ [])\n      when is_integer(count) and count > 0 and is_integer(step) and step > 0 do\n    R.chunk_every(&chunk_while/4, enum, count, step, leftover)\n  end\n\n  @doc \"\"\"\n  Chunks the `enum` by buffering elements for which `fun` returns the same value.\n\n  Elements are only emitted when `fun` returns a new value or the `enum` finishes.\n\n  ## Examples\n\n      iex> stream = Stream.chunk_by([1, 2, 2, 3, 4, 4, 6, 7, 7], &(rem(&1, 2) == 1))\n      iex> Enum.to_list(stream)\n      [[1], [2, 2], [3], [4, 4, 6], [7, 7]]\n\n  \"\"\"\n  @spec chunk_by(Enumerable.t(), (element -> any)) :: Enumerable.t()\n  def chunk_by(enum, fun) when is_function(fun, 1) do\n    R.chunk_by(&chunk_while/4, enum, fun)\n  end\n\n  @doc \"\"\"\n  Chunks the `enum` with fine grained control when every chunk is emitted.\n\n  `chunk_fun` receives the current element and the accumulator and\n  must return `{:cont, element, acc}` to emit the given chunk and\n  continue with accumulator or `{:cont, acc}` to not emit any chunk\n  and continue with the return accumulator.\n\n  `after_fun` is invoked when iteration is done and must also return\n  `{:cont, element, acc}` or `{:cont, acc}`.\n\n  ## Examples\n\n      iex> chunk_fun = fn element, acc ->\n      ...>   if rem(element, 2) == 0 do\n      ...>     {:cont, Enum.reverse([element | acc]), []}\n      ...>   else\n      ...>     {:cont, [element | acc]}\n      ...>   end\n      ...> end\n      iex> after_fun = fn\n      ...>   [] -> {:cont, []}\n      ...>   acc -> {:cont, Enum.reverse(acc), []}\n      ...> end\n      iex> stream = Stream.chunk_while(1..10, [], chunk_fun, after_fun)\n      iex> Enum.to_list(stream)\n      [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec chunk_while(\n          Enumerable.t(),\n          acc,\n          (element, acc -> {:cont, chunk, acc} | {:cont, acc} | {:halt, acc}),\n          (acc -> {:cont, chunk, acc} | {:cont, acc})\n        ) :: Enumerable.t()\n        when chunk: any\n  def chunk_while(enum, acc, chunk_fun, after_fun)\n      when is_function(chunk_fun, 2) and is_function(after_fun, 1) do\n    lazy(\n      enum,\n      [acc | after_fun],\n      fn f1 -> chunk_while_fun(chunk_fun, f1) end,\n      &after_chunk_while/2\n    )\n  end\n\n  defp chunk_while_fun(callback, fun) do\n    fn entry, acc(head, [acc | after_fun], tail) ->\n      case callback.(entry, acc) do\n        {:cont, emit, acc} ->\n          # If we emit an element and then we have to halt,\n          # we need to disable the after_fun callback to\n          # avoid emitting even more elements.\n          case next(fun, emit, [head | tail]) do\n            {:halt, [head | tail]} -> {:halt, acc(head, [acc | &{:cont, &1}], tail)}\n            {command, [head | tail]} -> {command, acc(head, [acc | after_fun], tail)}\n          end\n\n        {:cont, acc} ->\n          skip(acc(head, [acc | after_fun], tail))\n\n        {:halt, acc} ->\n          {:halt, acc(head, [acc | after_fun], tail)}\n      end\n    end\n  end\n\n  defp after_chunk_while(acc(h, [acc | after_fun], t), f1) do\n    case after_fun.(acc) do\n      {:cont, emit, acc} -> next_with_acc(f1, emit, h, [acc | after_fun], t)\n      {:cont, acc} -> {:cont, acc(h, [acc | after_fun], t)}\n    end\n  end\n\n  @doc \"\"\"\n  Creates a stream that only emits elements if they are different from the last emitted element.\n\n  This function only ever needs to store the last emitted element.\n\n  Elements are compared using `===/2`.\n\n  ## Examples\n\n      iex> Stream.dedup([1, 2, 3, 3, 2, 1]) |> Enum.to_list()\n      [1, 2, 3, 2, 1]\n\n  \"\"\"\n  @spec dedup(Enumerable.t()) :: Enumerable.t()\n  def dedup(enum) do\n    dedup_by(enum, fn x -> x end)\n  end\n\n  @doc \"\"\"\n  Creates a stream that only emits elements if the result of calling `fun` on the element is\n  different from the (stored) result of calling `fun` on the last emitted element.\n\n  ## Examples\n\n      iex> Stream.dedup_by([{1, :x}, {2, :y}, {2, :z}, {1, :x}], fn {x, _} -> x end) |> Enum.to_list()\n      [{1, :x}, {2, :y}, {1, :x}]\n\n  \"\"\"\n  @spec dedup_by(Enumerable.t(), (element -> term)) :: Enumerable.t()\n  def dedup_by(enum, fun) when is_function(fun, 1) do\n    lazy(enum, nil, fn f1 -> R.dedup(fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Lazily drops the next `n` elements from the enumerable.\n\n  If a negative `n` is given, it will drop the last `n` elements from\n  the collection. Note that the mechanism by which this is implemented\n  will delay the emission of any element until `n` additional elements have\n  been emitted by the enum.\n\n  ## Examples\n\n      iex> stream = Stream.drop(1..10, 5)\n      iex> Enum.to_list(stream)\n      [6, 7, 8, 9, 10]\n\n      iex> stream = Stream.drop(1..10, -5)\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 4, 5]\n\n  \"\"\"\n  @spec drop(Enumerable.t(), integer) :: Enumerable.t()\n  def drop(enum, n) when is_integer(n) and n >= 0 do\n    lazy(enum, n, fn f1 -> R.drop(f1) end)\n  end\n\n  def drop(enum, n) when is_integer(n) and n < 0 do\n    n = abs(n)\n\n    lazy(enum, {0, [], []}, fn f1 ->\n      fn\n        entry, [h, {count, buf1, []} | t] ->\n          do_drop(:cont, n, entry, h, count, buf1, [], t)\n\n        entry, [h, {count, buf1, [next | buf2]} | t] ->\n          {reason, [h | t]} = f1.(next, [h | t])\n          do_drop(reason, n, entry, h, count, buf1, buf2, t)\n      end\n    end)\n  end\n\n  defp do_drop(reason, n, entry, h, count, buf1, buf2, t) do\n    buf1 = [entry | buf1]\n    count = count + 1\n\n    if count == n do\n      {reason, [h, {0, [], :lists.reverse(buf1)} | t]}\n    else\n      {reason, [h, {count, buf1, buf2} | t]}\n    end\n  end\n\n  @doc \"\"\"\n  Creates a stream that drops every `nth` element from the enumerable.\n\n  The first element is always dropped, unless `nth` is 0.\n\n  `nth` must be a non-negative integer.\n\n  ## Examples\n\n      iex> stream = Stream.drop_every(1..10, 2)\n      iex> Enum.to_list(stream)\n      [2, 4, 6, 8, 10]\n\n      iex> stream = Stream.drop_every(1..1000, 1)\n      iex> Enum.to_list(stream)\n      []\n\n      iex> stream = Stream.drop_every([1, 2, 3, 4, 5], 0)\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 4, 5]\n\n  \"\"\"\n  @spec drop_every(Enumerable.t(), non_neg_integer) :: Enumerable.t()\n  def drop_every(enum, nth)\n  def drop_every(enum, 0), do: %Stream{enum: enum}\n  def drop_every([], _nth), do: %Stream{enum: []}\n\n  def drop_every(enum, nth) when is_integer(nth) and nth > 0 do\n    lazy(enum, nth, fn f1 -> R.drop_every(nth, f1) end)\n  end\n\n  @doc \"\"\"\n  Lazily drops elements of the enumerable while the given\n  function returns a truthy value.\n\n  ## Examples\n\n      iex> stream = Stream.drop_while(1..10, &(&1 <= 5))\n      iex> Enum.to_list(stream)\n      [6, 7, 8, 9, 10]\n\n  \"\"\"\n  @spec drop_while(Enumerable.t(), (element -> as_boolean(term))) :: Enumerable.t()\n  def drop_while(enum, fun) when is_function(fun, 1) do\n    lazy(enum, true, fn f1 -> R.drop_while(fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Duplicates the given element `n` times in a stream.\n\n  `n` is an integer greater than or equal to `0`.\n\n  If `n` is `0`, an empty stream is returned.\n\n  ## Examples\n\n      iex> stream = Stream.duplicate(\"hello\", 0)\n      iex> Enum.to_list(stream)\n      []\n\n      iex> stream = Stream.duplicate(\"hi\", 1)\n      iex> Enum.to_list(stream)\n      [\"hi\"]\n\n      iex> stream = Stream.duplicate(\"bye\", 2)\n      iex> Enum.to_list(stream)\n      [\"bye\", \"bye\"]\n\n      iex> stream = Stream.duplicate([1, 2], 3)\n      iex> Enum.to_list(stream)\n      [[1, 2], [1, 2], [1, 2]]\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec duplicate(any, non_neg_integer) :: Enumerable.t()\n  def duplicate(value, n) when is_integer(n) and n >= 0 do\n    unfold(n, fn\n      0 -> nil\n      remaining -> {value, remaining - 1}\n    end)\n  end\n\n  @doc \"\"\"\n  Executes the given function for each element.\n\n  The values in the stream do not change, therefore this\n  function is useful for adding side effects (like printing)\n  to a stream. See `map/2` if producing a different stream\n  is desired.\n\n  ## Examples\n\n      iex> stream = Stream.each([1, 2, 3], fn x -> send(self(), x) end)\n      iex> Enum.to_list(stream)\n      iex> receive do: (x when is_integer(x) -> x)\n      1\n      iex> receive do: (x when is_integer(x) -> x)\n      2\n      iex> receive do: (x when is_integer(x) -> x)\n      3\n\n  \"\"\"\n  @spec each(Enumerable.t(), (element -> term)) :: Enumerable.t()\n  def each(enum, fun) when is_function(fun, 1) do\n    lazy(enum, fn f1 ->\n      fn x, acc ->\n        fun.(x)\n        f1.(x, acc)\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Maps the given `fun` over `enumerable` and flattens the result.\n\n  This function returns a new stream built by appending the result of invoking `fun`\n  on each element of `enumerable` together.\n\n  ## Examples\n\n      iex> stream = Stream.flat_map([1, 2, 3], fn x -> [x, x * 2] end)\n      iex> Enum.to_list(stream)\n      [1, 2, 2, 4, 3, 6]\n\n      iex> stream = Stream.flat_map([1, 2, 3], fn x -> [[x]] end)\n      iex> Enum.to_list(stream)\n      [[1], [2], [3]]\n\n  \"\"\"\n  @spec flat_map(Enumerable.t(), (element -> Enumerable.t())) :: Enumerable.t()\n  def flat_map(enum, mapper) when is_function(mapper, 1) do\n    transform(enum, nil, fn val, nil -> {mapper.(val), nil} end)\n  end\n\n  @doc \"\"\"\n  Creates a stream that filters elements according to\n  the given function on enumeration.\n\n  ## Examples\n\n      iex> stream = Stream.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end)\n      iex> Enum.to_list(stream)\n      [2]\n\n  \"\"\"\n  @spec filter(Enumerable.t(), (element -> as_boolean(term))) :: Enumerable.t()\n  def filter(enum, fun) when is_function(fun, 1) do\n    lazy(enum, fn f1 -> R.filter(fun, f1) end)\n  end\n\n  @doc false\n  @deprecated \"Use Stream.filter/2 + Stream.map/2 instead\"\n  def filter_map(enum, filter, mapper) do\n    lazy(enum, fn f1 -> R.filter_map(filter, mapper, f1) end)\n  end\n\n  @doc \"\"\"\n  Creates a stream that emits a value after the given period `n`\n  in milliseconds.\n\n  The values emitted are an increasing counter starting at `0`.\n  This operation will block the caller by the given interval\n  every time a new element is streamed.\n\n  Do not use this function to generate a sequence of numbers.\n  If blocking the caller process is not necessary, use\n  `Stream.iterate(0, & &1 + 1)` instead.\n\n  ## Examples\n\n      iex> Stream.interval(10) |> Enum.take(10)\n      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n  \"\"\"\n  @spec interval(timer()) :: Enumerable.t()\n  def interval(n)\n      when is_integer(n) and n >= 0\n      when n == :infinity do\n    unfold(0, fn count ->\n      Process.sleep(n)\n      {count, count + 1}\n    end)\n  end\n\n  @doc \"\"\"\n  Injects the stream values into the given collectable as a side-effect.\n\n  This function is often used with `run/1` since any evaluation\n  is delayed until the stream is executed. See `run/1` for an example.\n  \"\"\"\n  @spec into(Enumerable.t(), Collectable.t(), (term -> term)) :: Enumerable.t()\n  def into(enum, collectable, transform \\\\ fn x -> x end) when is_function(transform, 1) do\n    &do_into(enum, collectable, transform, &1, &2)\n  end\n\n  defp do_into(enum, collectable, transform, acc, fun) do\n    {initial, into} = Collectable.into(collectable)\n\n    composed = fn x, [acc | collectable] ->\n      collectable = into.(collectable, {:cont, transform.(x)})\n      {reason, acc} = fun.(x, acc)\n      {reason, [acc | collectable]}\n    end\n\n    do_into(&Enumerable.reduce(enum, &1, composed), initial, into, acc)\n  end\n\n  defp do_into(reduce, collectable, into, {command, acc}) do\n    try do\n      reduce.({command, [acc | collectable]})\n    catch\n      kind, reason ->\n        into.(collectable, :halt)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {:suspended, [acc | collectable], continuation} ->\n        {:suspended, acc, &do_into(continuation, collectable, into, &1)}\n\n      {reason, [acc | collectable]} ->\n        into.(collectable, :done)\n        {reason, acc}\n    end\n  end\n\n  @doc \"\"\"\n  Creates a stream that will apply the given function on\n  enumeration.\n\n  ## Examples\n\n      iex> stream = Stream.map([1, 2, 3], fn x -> x * 2 end)\n      iex> Enum.to_list(stream)\n      [2, 4, 6]\n\n  \"\"\"\n  @spec map(Enumerable.t(), (element -> any)) :: Enumerable.t()\n  def map(enum, fun) when is_function(fun, 1) do\n    lazy(enum, fn f1 -> R.map(fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Creates a stream that will apply the given function on\n  every `nth` element from the enumerable.\n\n  The first element is always passed to the given function.\n\n  `nth` must be a non-negative integer.\n\n  ## Examples\n\n      iex> stream = Stream.map_every(1..10, 2, fn x -> x * 2 end)\n      iex> Enum.to_list(stream)\n      [2, 2, 6, 4, 10, 6, 14, 8, 18, 10]\n\n      iex> stream = Stream.map_every([1, 2, 3, 4, 5], 1, fn x -> x * 2 end)\n      iex> Enum.to_list(stream)\n      [2, 4, 6, 8, 10]\n\n      iex> stream = Stream.map_every(1..5, 0, fn x -> x * 2 end)\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 4, 5]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec map_every(Enumerable.t(), non_neg_integer, (element -> any)) :: Enumerable.t()\n  def map_every(enum, nth, fun) when is_integer(nth) and nth >= 0 and is_function(fun, 1) do\n    map_every_after_guards(enum, nth, fun)\n  end\n\n  defp map_every_after_guards(enum, 1, fun), do: map(enum, fun)\n  defp map_every_after_guards(enum, 0, _fun), do: %Stream{enum: enum}\n  defp map_every_after_guards([], _nth, _fun), do: %Stream{enum: []}\n\n  defp map_every_after_guards(enum, nth, fun) do\n    lazy(enum, nth, fn f1 -> R.map_every(nth, fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Creates a stream that will reject elements according to\n  the given function on enumeration.\n\n  ## Examples\n\n      iex> stream = Stream.reject([1, 2, 3], fn x -> rem(x, 2) == 0 end)\n      iex> Enum.to_list(stream)\n      [1, 3]\n\n  \"\"\"\n  @spec reject(Enumerable.t(), (element -> as_boolean(term))) :: Enumerable.t()\n  def reject(enum, fun) when is_function(fun, 1) do\n    lazy(enum, fn f1 -> R.reject(fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Runs the given stream.\n\n  This is useful when a stream needs to be run, for side effects,\n  and there is no interest in its return result.\n\n  ## Examples\n\n  Open up a file, replace all `#` by `%` and stream to another file\n  without loading the whole file in memory:\n\n      File.stream!(\"/path/to/file\")\n      |> Stream.map(&String.replace(&1, \"#\", \"%\"))\n      |> Stream.into(File.stream!(\"/path/to/other/file\"))\n      |> Stream.run()\n\n  No computation will be done until we call one of the `Enum` functions\n  or `run/1`.\n  \"\"\"\n  @spec run(Enumerable.t()) :: :ok\n  def run(stream) do\n    _ = Enumerable.reduce(stream, {:cont, nil}, fn _, _ -> {:cont, nil} end)\n    :ok\n  end\n\n  @doc \"\"\"\n  Creates a stream that applies the given function to each\n  element, emits the result and uses the same result as the accumulator\n  for the next computation. Uses the first element in the enumerable\n  as the starting value.\n\n  ## Examples\n\n      iex> stream = Stream.scan(1..5, &(&1 + &2))\n      iex> Enum.to_list(stream)\n      [1, 3, 6, 10, 15]\n\n  \"\"\"\n  @spec scan(Enumerable.t(), (element, acc -> any)) :: Enumerable.t()\n  def scan(enum, fun) when is_function(fun, 2) do\n    lazy(enum, :first, fn f1 -> R.scan2(fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Creates a stream that applies the given function to each\n  element, emits the result and uses the same result as the accumulator\n  for the next computation. Uses the given `acc` as the starting value.\n\n  ## Examples\n\n      iex> stream = Stream.scan(1..5, 0, &(&1 + &2))\n      iex> Enum.to_list(stream)\n      [1, 3, 6, 10, 15]\n\n  \"\"\"\n  @spec scan(Enumerable.t(), acc, (element, acc -> any)) :: Enumerable.t()\n  def scan(enum, acc, fun) when is_function(fun, 2) do\n    lazy(enum, acc, fn f1 -> R.scan3(fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Lazily takes the next `count` elements from the enumerable and stops\n  enumeration.\n\n  If a negative `count` is given, the last `count` values will be taken.\n  For such, the collection is fully enumerated keeping up to `2 * count`\n  elements in memory. Once the end of the collection is reached,\n  the last `count` elements will be executed. Therefore, using\n  a negative `count` on an infinite collection will never return.\n\n  ## Examples\n\n      iex> stream = Stream.take(1..100, 5)\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 4, 5]\n\n      iex> stream = Stream.take(1..100, -5)\n      iex> Enum.to_list(stream)\n      [96, 97, 98, 99, 100]\n\n      iex> stream = Stream.cycle([1, 2, 3]) |> Stream.take(5)\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 1, 2]\n\n  \"\"\"\n  @spec take(Enumerable.t(), integer) :: Enumerable.t()\n  def take(enum, count) when is_integer(count) do\n    take_after_guards(enum, count)\n  end\n\n  defp take_after_guards(_enum, 0), do: %Stream{enum: []}\n\n  defp take_after_guards([], _count), do: %Stream{enum: []}\n\n  defp take_after_guards(enum, count) when count > 0 do\n    lazy(enum, count, fn f1 -> R.take(f1) end)\n  end\n\n  defp take_after_guards(enum, count) when count < 0 do\n    &Enumerable.reduce(Enum.take(enum, count), &1, &2)\n  end\n\n  @doc \"\"\"\n  Creates a stream that takes every `nth` element from the enumerable.\n\n  The first element is always included, unless `nth` is 0.\n\n  `nth` must be a non-negative integer.\n\n  ## Examples\n\n      iex> stream = Stream.take_every(1..10, 2)\n      iex> Enum.to_list(stream)\n      [1, 3, 5, 7, 9]\n\n      iex> stream = Stream.take_every([1, 2, 3, 4, 5], 1)\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 4, 5]\n\n      iex> stream = Stream.take_every(1..1000, 0)\n      iex> Enum.to_list(stream)\n      []\n\n  \"\"\"\n  @spec take_every(Enumerable.t(), non_neg_integer) :: Enumerable.t()\n  def take_every(enum, nth) when is_integer(nth) and nth >= 0 do\n    take_every_after_guards(enum, nth)\n  end\n\n  defp take_every_after_guards(_enum, 0), do: %Stream{enum: []}\n\n  defp take_every_after_guards([], _nth), do: %Stream{enum: []}\n\n  defp take_every_after_guards(enum, nth) do\n    lazy(enum, nth, fn f1 -> R.take_every(nth, f1) end)\n  end\n\n  @doc \"\"\"\n  Lazily takes elements of the enumerable while the given\n  function returns a truthy value.\n\n  ## Examples\n\n      iex> stream = Stream.take_while(1..100, &(&1 <= 5))\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 4, 5]\n\n  \"\"\"\n  @spec take_while(Enumerable.t(), (element -> as_boolean(term))) :: Enumerable.t()\n  def take_while(enum, fun) when is_function(fun, 1) do\n    lazy(enum, fn f1 -> R.take_while(fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Creates a stream that emits a single value after `n` milliseconds.\n\n  The value emitted is `0`. This operation will block the caller by\n  the given time until the element is streamed.\n\n  ## Examples\n\n      iex> Stream.timer(10) |> Enum.to_list()\n      [0]\n\n  \"\"\"\n  @spec timer(timer()) :: Enumerable.t()\n  def timer(n)\n      when is_integer(n) and n >= 0\n      when n == :infinity do\n    take(interval(n), 1)\n  end\n\n  @doc \"\"\"\n  Transforms an existing stream.\n\n  It expects an accumulator and a function that receives two arguments,\n  the stream element and the updated accumulator. It must return a tuple,\n  where the first element is a new stream (often a list) or the atom `:halt`,\n  and the second element is the accumulator to be used by the next element.\n\n  Note: this function is equivalent to `Enum.flat_map_reduce/3`, except this\n  function does not return the accumulator once the stream is processed.\n\n  ## Examples\n\n  `Stream.transform/3` is useful as it can be used as the basis to implement\n  many of the functions defined in this module. For example, we can implement\n  `Stream.take(enum, n)` as follows:\n\n      iex> enum = 1001..9999\n      iex> n = 3\n      iex> stream = Stream.transform(enum, 0, fn i, acc ->\n      ...>   if acc < n, do: {[i], acc + 1}, else: {:halt, acc}\n      ...> end)\n      iex> Enum.to_list(stream)\n      [1001, 1002, 1003]\n\n  `Stream.transform/5` further generalizes this function to allow wrapping\n  around resources.\n  \"\"\"\n  @spec transform(Enumerable.t(), acc, fun) :: Enumerable.t()\n        when fun: (element, acc -> {Enumerable.t(), acc} | {:halt, acc}),\n             acc: term\n  def transform(enum, acc, reducer) when is_function(reducer, 2) do\n    &do_transform(enum, fn -> acc end, reducer, &1, &2, nil, fn acc -> acc end)\n  end\n\n  @doc \"\"\"\n  Similar to `Stream.transform/5`, except `last_fun` is not supplied.\n\n  This function can be seen as a combination of `Stream.resource/3` with\n  `Stream.transform/3`.\n  \"\"\"\n  @spec transform(Enumerable.t(), start_fun, reducer, after_fun) :: Enumerable.t()\n        when start_fun: (-> acc),\n             reducer: (element, acc -> {Enumerable.t(), acc} | {:halt, acc}),\n             after_fun: (acc -> term),\n             acc: term\n  def transform(enum, start_fun, reducer, after_fun)\n      when is_function(start_fun, 0) and is_function(reducer, 2) and is_function(after_fun, 1) do\n    &do_transform(enum, start_fun, reducer, &1, &2, nil, after_fun)\n  end\n\n  @doc \"\"\"\n  Transforms an existing stream with function-based start, last, and after\n  callbacks.\n\n  Once transformation starts, `start_fun` is invoked to compute the initial\n  accumulator. Then, for each element in the enumerable, the `reducer` function\n  is invoked with the element and the accumulator, returning new elements and a\n  new accumulator, as in `transform/3`.\n\n  Once the collection is done, `last_fun` is invoked with the accumulator to\n  emit any remaining items. Then `after_fun` is invoked, to close any resource,\n  but not emitting any new items. `last_fun` is only invoked if the given\n  enumerable terminates successfully (either because it is done or it halted\n  itself). `after_fun` is always invoked, therefore `after_fun` must be the\n  one used for closing resources.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec transform(Enumerable.t(), start_fun, reducer, last_fun, after_fun) :: Enumerable.t()\n        when start_fun: (-> acc),\n             reducer: (element, acc -> {Enumerable.t(), acc} | {:halt, acc}),\n             last_fun: (acc -> {Enumerable.t(), acc} | {:halt, acc}),\n             after_fun: (acc -> term),\n             acc: term\n  def transform(enum, start_fun, reducer, last_fun, after_fun)\n      when is_function(start_fun, 0) and is_function(reducer, 2) and is_function(last_fun, 1) and\n             is_function(after_fun, 1) do\n    &do_transform(enum, start_fun, reducer, &1, &2, last_fun, after_fun)\n  end\n\n  defp do_transform(enumerables, user_acc, user, inner_acc, fun, last_fun, after_fun) do\n    inner = &do_transform_each(&1, &2, fun)\n    step = &do_transform_step(&1, &2)\n    next = &Enumerable.reduce(enumerables, &1, step)\n    funs = {user, fun, inner, last_fun, after_fun}\n    do_transform(user_acc.(), :cont, next, inner_acc, funs)\n  end\n\n  defp do_transform(user_acc, _next_op, next, {:halt, inner_acc}, funs) do\n    {_, _, _, _, after_fun} = funs\n    next.({:halt, []})\n    after_fun.(user_acc)\n    {:halted, inner_acc}\n  end\n\n  defp do_transform(user_acc, next_op, next, {:suspend, inner_acc}, funs) do\n    {:suspended, inner_acc, &do_transform(user_acc, next_op, next, &1, funs)}\n  end\n\n  defp do_transform(user_acc, :cont, next, inner_acc, funs) do\n    {_, _, _, _, after_fun} = funs\n\n    try do\n      next.({:cont, []})\n    catch\n      kind, reason ->\n        after_fun.(user_acc)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {:suspended, vals, next} ->\n        do_transform_user(:lists.reverse(vals), user_acc, :cont, next, inner_acc, funs)\n\n      {_, vals} ->\n        # Do not attempt to call the resource again, it has either done or halted\n        next = fn _ -> {:done, []} end\n        do_transform_user(:lists.reverse(vals), user_acc, :last, next, inner_acc, funs)\n    end\n  end\n\n  defp do_transform(user_acc, :last, next, inner_acc, funs) do\n    {_, _, _, last_fun, after_fun} = funs\n\n    if last_fun do\n      try do\n        last_fun.(user_acc)\n      catch\n        kind, reason ->\n          after_fun.(user_acc)\n          :erlang.raise(kind, reason, __STACKTRACE__)\n      else\n        result -> do_transform_result(result, [], :halt, next, inner_acc, funs)\n      end\n    else\n      do_transform(user_acc, :halt, next, inner_acc, funs)\n    end\n  end\n\n  defp do_transform(user_acc, :halt, _next, inner_acc, funs) do\n    {_, _, _, _, after_fun} = funs\n    after_fun.(user_acc)\n    {:halted, elem(inner_acc, 1)}\n  end\n\n  defp do_transform_user([], user_acc, next_op, next, inner_acc, funs) do\n    do_transform(user_acc, next_op, next, inner_acc, funs)\n  end\n\n  defp do_transform_user([val | vals], user_acc, next_op, next, inner_acc, funs) do\n    {user, _, _, _, after_fun} = funs\n\n    try do\n      user.(val, user_acc)\n    catch\n      kind, reason ->\n        next.({:halt, []})\n        after_fun.(user_acc)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      result -> do_transform_result(result, vals, next_op, next, inner_acc, funs)\n    end\n  end\n\n  defp do_transform_result(result, vals, next_op, next, inner_acc, funs) do\n    {_, fun, inner, _, after_fun} = funs\n\n    case result do\n      {[], user_acc} ->\n        do_transform_user(vals, user_acc, next_op, next, inner_acc, funs)\n\n      {list, user_acc} when is_list(list) ->\n        reduce = &Enumerable.List.reduce(list, &1, fun)\n        do_transform_inner_list(vals, user_acc, next_op, next, inner_acc, reduce, funs)\n\n      {:halt, user_acc} ->\n        next.({:halt, []})\n        after_fun.(user_acc)\n        {:halted, elem(inner_acc, 1)}\n\n      {other, user_acc} ->\n        reduce = &Enumerable.reduce(other, &1, inner)\n        do_transform_inner_enum(vals, user_acc, next_op, next, inner_acc, reduce, funs)\n    end\n  end\n\n  defp do_transform_inner_list(vals, user_acc, next_op, next, inner_acc, reduce, funs) do\n    {_, _, _, _, after_fun} = funs\n\n    try do\n      reduce.(inner_acc)\n    catch\n      kind, reason ->\n        next.({:halt, []})\n        after_fun.(user_acc)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {:done, acc} ->\n        do_transform_user(vals, user_acc, next_op, next, {:cont, acc}, funs)\n\n      {:halted, acc} ->\n        next.({:halt, []})\n        after_fun.(user_acc)\n        {:halted, acc}\n\n      {:suspended, acc, continuation} ->\n        resume = &do_transform_inner_list(vals, user_acc, next_op, next, &1, continuation, funs)\n        {:suspended, acc, resume}\n    end\n  end\n\n  defp do_transform_inner_enum(vals, user_acc, next_op, next, {op, inner_acc}, reduce, funs) do\n    {_, _, _, _, after_fun} = funs\n\n    try do\n      reduce.({op, [:cont | inner_acc]})\n    catch\n      kind, reason ->\n        next.({:halt, []})\n        after_fun.(user_acc)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      # The user wanted to cont/suspend but the stream halted,\n      # so we continue with the user intention.\n      {:halted, [inner_op | acc]} when op != :halt and inner_op != :halt ->\n        do_transform_user(vals, user_acc, next_op, next, {inner_op, acc}, funs)\n\n      {:halted, [_ | acc]} ->\n        next.({:halt, []})\n        after_fun.(user_acc)\n        {:halted, acc}\n\n      {:done, [_ | acc]} ->\n        do_transform_user(vals, user_acc, next_op, next, {:cont, acc}, funs)\n\n      {:suspended, [_ | acc], continuation} ->\n        resume = &do_transform_inner_enum(vals, user_acc, next_op, next, &1, continuation, funs)\n        {:suspended, acc, resume}\n    end\n  end\n\n  defp do_transform_each(x, [:cont | acc], f) do\n    case f.(x, acc) do\n      {op, res} -> {op, [op | res]}\n    end\n  end\n\n  defp do_transform_step(x, acc) do\n    {:suspend, [x | acc]}\n  end\n\n  @doc \"\"\"\n  Creates a stream that only emits elements if they are unique.\n\n  Keep in mind that, in order to know if an element is unique\n  or not, this function needs to store all unique values emitted\n  by the stream. Therefore, if the stream is infinite, the number\n  of elements stored will grow infinitely, never being garbage-collected.\n\n  ## Examples\n\n      iex> Stream.uniq([1, 2, 3, 3, 2, 1]) |> Enum.to_list()\n      [1, 2, 3]\n\n  \"\"\"\n  @spec uniq(Enumerable.t()) :: Enumerable.t()\n  def uniq(enum) do\n    uniq_by(enum, fn x -> x end)\n  end\n\n  @doc false\n  @deprecated \"Use Stream.uniq_by/2 instead\"\n  def uniq(enum, fun) do\n    uniq_by(enum, fun)\n  end\n\n  @doc \"\"\"\n  Creates a stream that only emits elements if they are unique, by removing the\n  elements for which function `fun` returned duplicate elements.\n\n  The function `fun` maps every element to a term which is used to\n  determine if two elements are duplicates.\n\n  Keep in mind that, in order to know if an element is unique\n  or not, this function needs to store all unique values emitted\n  by the stream. Therefore, if the stream is infinite, the number\n  of elements stored will grow infinitely, never being garbage-collected.\n\n  ## Example\n\n      iex> Stream.uniq_by([{1, :x}, {2, :y}, {1, :z}], fn {x, _} -> x end) |> Enum.to_list()\n      [{1, :x}, {2, :y}]\n\n      iex> Stream.uniq_by([a: {:tea, 2}, b: {:tea, 2}, c: {:coffee, 1}], fn {_, y} -> y end) |> Enum.to_list()\n      [a: {:tea, 2}, c: {:coffee, 1}]\n\n  \"\"\"\n  @spec uniq_by(Enumerable.t(), (element -> term)) :: Enumerable.t()\n  def uniq_by(enum, fun) when is_function(fun, 1) do\n    lazy(enum, %{}, fn f1 -> R.uniq_by(fun, f1) end)\n  end\n\n  @doc \"\"\"\n  Builds a stream from an index, either starting from offset, or given by function.\n\n  May receive a function or an integer offset.\n\n  If an `offset` is given, it will emit elements from offset.\n\n  If a `function` is given, it will invoke the function with\n  elements from offset.\n\n  ## Examples\n\n      iex> Stream.from_index() |> Enum.take(3)\n      [0, 1, 2]\n\n      iex> Stream.from_index(1) |> Enum.take(3)\n      [1, 2, 3]\n\n      iex> Stream.from_index(fn x -> x * 10 end) |> Enum.take(3)\n      [0, 10, 20]\n\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec from_index(integer) :: Enumerable.t(integer)\n  @spec from_index((integer -> return_value)) :: Enumerable.t(return_value)\n        when return_value: term\n  def from_index(fun_or_offset \\\\ 0)\n\n  def from_index(offset) when is_integer(offset) do\n    unfold(offset, &{&1, &1 + 1})\n  end\n\n  def from_index(fun) when is_function(fun) do\n    unfold(0, &{fun.(&1), &1 + 1})\n  end\n\n  @doc \"\"\"\n  Creates a stream where each element in the enumerable will\n  be wrapped in a tuple alongside its index or according to a given function.\n\n  May receive a function or an integer offset.\n\n  If an `offset` is given, it will index from the given offset instead of from\n  zero.\n\n  If a `function` is given, it will index by invoking the function for each\n  element and index (zero-based) of the enumerable.\n\n  ## Examples\n\n      iex> stream = Stream.with_index([1, 2, 3])\n      iex> Enum.to_list(stream)\n      [{1, 0}, {2, 1}, {3, 2}]\n\n      iex> stream = Stream.with_index([1, 2, 3], 3)\n      iex> Enum.to_list(stream)\n      [{1, 3}, {2, 4}, {3, 5}]\n\n      iex> stream = Stream.with_index([1, 2, 3], fn x, index -> x + index end)\n      iex> Enum.to_list(stream)\n      [1, 3, 5]\n\n  \"\"\"\n  @spec with_index(Enumerable.t(), integer) :: Enumerable.t({element, integer})\n  @spec with_index(Enumerable.t(), (element, index -> return_value)) :: Enumerable.t(return_value)\n        when return_value: term\n  def with_index(enum, fun_or_offset \\\\ 0)\n\n  def with_index(enum, offset) when is_integer(offset) do\n    lazy(enum, offset, fn f1 -> R.with_index(f1) end)\n  end\n\n  def with_index(enum, fun) when is_function(fun, 2) do\n    lazy(enum, 0, fn f1 -> R.with_index(fun, f1) end)\n  end\n\n  ## Combiners\n\n  @doc \"\"\"\n  Creates a stream that enumerates each enumerable in an enumerable.\n\n  ## Examples\n\n      iex> stream = Stream.concat([1..3, 4..6, 7..9])\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n  \"\"\"\n  @spec concat(Enumerable.t()) :: Enumerable.t()\n  def concat(enumerables) do\n    flat_map(enumerables, & &1)\n  end\n\n  @doc \"\"\"\n  Creates a stream that enumerates the first argument, followed by the second.\n\n  ## Examples\n\n      iex> stream = Stream.concat(1..3, 4..6)\n      iex> Enum.to_list(stream)\n      [1, 2, 3, 4, 5, 6]\n\n      iex> stream1 = Stream.cycle([1, 2, 3])\n      iex> stream2 = Stream.cycle([4, 5, 6])\n      iex> stream = Stream.concat(stream1, stream2)\n      iex> Enum.take(stream, 6)\n      [1, 2, 3, 1, 2, 3]\n\n  \"\"\"\n  @spec concat(Enumerable.t(), Enumerable.t()) :: Enumerable.t()\n  def concat(first, second) do\n    flat_map([first, second], & &1)\n  end\n\n  @doc \"\"\"\n  Zips two enumerables together, lazily.\n\n  Because a list of two-element tuples with atoms as the first\n  tuple element is a keyword list (`Keyword`), zipping a first `Stream`\n  of atoms with a second `Stream` of any kind creates a `Stream`\n  that generates a keyword list.\n\n  The zipping finishes as soon as either enumerable completes.\n\n  ## Examples\n\n      iex> concat = Stream.concat(1..3, 4..6)\n      iex> cycle = Stream.cycle([:a, :b, :c])\n      iex> Stream.zip(concat, cycle) |> Enum.to_list()\n      [{1, :a}, {2, :b}, {3, :c}, {4, :a}, {5, :b}, {6, :c}]\n      iex> Stream.zip(cycle, concat) |> Enum.to_list()\n      [a: 1, b: 2, c: 3, a: 4, b: 5, c: 6]\n\n  \"\"\"\n  @spec zip(Enumerable.t(), Enumerable.t()) :: Enumerable.t()\n  def zip(enumerable1, enumerable2) do\n    zip_with(enumerable1, enumerable2, fn left, right -> {left, right} end)\n  end\n\n  @doc \"\"\"\n  Zips corresponding elements from a finite collection of enumerables\n  into one stream of tuples.\n\n  The zipping finishes as soon as any enumerable in the given collection completes.\n\n  ## Examples\n\n      iex> concat = Stream.concat(1..3, 4..6)\n      iex> cycle = Stream.cycle([\"foo\", \"bar\", \"baz\"])\n      iex> Stream.zip([concat, [:a, :b, :c], cycle]) |> Enum.to_list()\n      [{1, :a, \"foo\"}, {2, :b, \"bar\"}, {3, :c, \"baz\"}]\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec zip(enumerables) :: Enumerable.t() when enumerables: [Enumerable.t()] | Enumerable.t()\n  def zip(enumerables) do\n    zip_with(enumerables, &List.to_tuple(&1))\n  end\n\n  @doc \"\"\"\n  Lazily zips corresponding elements from two enumerables into a new one, transforming them with\n  the `zip_fun` function as it goes.\n\n  The `zip_fun` will be called with the first element from `enumerable1` and the first\n  element from `enumerable2`, then with the second element from each, and so on until\n  either one of the enumerables completes.\n\n  ## Examples\n\n      iex> concat = Stream.concat(1..3, 4..6)\n      iex> Stream.zip_with(concat, concat, fn a, b -> a + b end) |> Enum.to_list()\n      [2, 4, 6, 8, 10, 12]\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec zip_with(Enumerable.t(), Enumerable.t(), (term, term -> term)) :: Enumerable.t()\n  def zip_with(enumerable1, enumerable2, zip_fun)\n      when is_list(enumerable1) and is_list(enumerable2) and is_function(zip_fun, 2) do\n    &zip_pair(enumerable1, enumerable2, &1, &2, zip_fun)\n  end\n\n  def zip_with(enumerable1, enumerable2, zip_fun) when is_function(zip_fun, 2) do\n    zip_with([enumerable1, enumerable2], fn [left, right] -> zip_fun.(left, right) end)\n  end\n\n  defp zip_pair(_list1, _list2, {:halt, acc}, _fun, _zip_fun) do\n    {:halted, acc}\n  end\n\n  defp zip_pair(list1, list2, {:suspend, acc}, fun, zip_fun) do\n    {:suspended, acc, &zip_pair(list1, list2, &1, fun, zip_fun)}\n  end\n\n  defp zip_pair([], _list2, {:cont, acc}, _fun, _zip_fun), do: {:done, acc}\n  defp zip_pair(_list1, [], {:cont, acc}, _fun, _zip_fun), do: {:done, acc}\n\n  defp zip_pair([head1 | tail1], [head2 | tail2], {:cont, acc}, fun, zip_fun) do\n    zip_pair(tail1, tail2, fun.(zip_fun.(head1, head2), acc), fun, zip_fun)\n  end\n\n  @doc \"\"\"\n  Lazily zips corresponding elements from a finite collection of enumerables into a new\n  enumerable, transforming them with the `zip_fun` function as it goes.\n\n  The first element from each of the enums in `enumerables` will be put into a list which is then passed to\n  the one-arity `zip_fun` function. Then, the second elements from each of the enums are put into a list and passed to\n  `zip_fun`, and so on until any one of the enums in `enumerables` completes.\n\n  Returns a new enumerable with the results of calling `zip_fun`.\n\n  ## Examples\n\n      iex> concat = Stream.concat(1..3, 4..6)\n      iex> Stream.zip_with([concat, concat], fn [a, b] -> a + b end) |> Enum.to_list()\n      [2, 4, 6, 8, 10, 12]\n\n      iex> concat = Stream.concat(1..3, 4..6)\n      iex> Stream.zip_with([concat, concat, 1..3], fn [a, b, c] -> a + b + c end) |> Enum.to_list()\n      [3, 6, 9]\n\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec zip_with(enumerables, (Enumerable.t() -> term)) :: Enumerable.t()\n        when enumerables: [Enumerable.t()] | Enumerable.t()\n  def zip_with(enumerables, zip_fun) do\n    R.zip_with(enumerables, zip_fun)\n  end\n\n  ## Sources\n\n  @doc \"\"\"\n  Creates a stream that cycles through the given enumerable,\n  infinitely.\n\n  ## Examples\n\n      iex> stream = Stream.cycle([1, 2, 3])\n      iex> Enum.take(stream, 5)\n      [1, 2, 3, 1, 2]\n\n  \"\"\"\n  @spec cycle(Enumerable.t()) :: Enumerable.t()\n  def cycle(enumerable)\n\n  def cycle([]) do\n    raise ArgumentError, \"cannot cycle over an empty enumerable\"\n  end\n\n  def cycle(enumerable) when is_list(enumerable) do\n    unfold({enumerable, enumerable}, fn\n      {source, [h | t]} -> {h, {source, t}}\n      {source = [h | t], []} -> {h, {source, t}}\n    end)\n  end\n\n  def cycle(enumerable) do\n    fn acc, fun ->\n      step = &do_cycle_step(&1, &2)\n      cycle = &Enumerable.reduce(enumerable, &1, step)\n      reduce = check_cycle_first_element(cycle)\n      do_cycle(reduce, [], cycle, acc, fun)\n    end\n  end\n\n  defp do_cycle(reduce, inner_acc, _cycle, {:halt, acc}, _fun) do\n    reduce.({:halt, inner_acc})\n    {:halted, acc}\n  end\n\n  defp do_cycle(reduce, inner_acc, cycle, {:suspend, acc}, fun) do\n    {:suspended, acc, &do_cycle(reduce, inner_acc, cycle, &1, fun)}\n  end\n\n  defp do_cycle(reduce, inner_acc, cycle, {:cont, acc}, fun) do\n    case reduce.({:cont, inner_acc}) do\n      {:suspended, [element], new_reduce} ->\n        do_cycle(new_reduce, inner_acc, cycle, fun.(element, acc), fun)\n\n      {_, [element]} ->\n        do_cycle(cycle, [], cycle, fun.(element, acc), fun)\n\n      {_, []} ->\n        do_cycle(cycle, [], cycle, {:cont, acc}, fun)\n    end\n  end\n\n  defp do_cycle_step(x, acc) do\n    {:suspend, [x | acc]}\n  end\n\n  defp check_cycle_first_element(reduce) do\n    fn acc ->\n      case reduce.(acc) do\n        {state, []} when state in [:done, :halted] and elem(acc, 0) != :halt ->\n          raise ArgumentError, \"cannot cycle over an empty enumerable\"\n\n        other ->\n          other\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Emits a sequence of values, starting with `start_value`.\n\n  Successive values are generated by calling `next_fun`\n  on the previous value.\n\n  ## Examples\n\n      iex> Stream.iterate(1, &(&1 * 2)) |> Enum.take(5)\n      [1, 2, 4, 8, 16]\n\n  \"\"\"\n  @spec iterate(element, (element -> element)) :: Enumerable.t()\n  def iterate(start_value, next_fun) when is_function(next_fun, 1) do\n    unfold({:ok, start_value}, fn\n      {:ok, value} ->\n        {value, {:next, value}}\n\n      {:next, value} ->\n        next = next_fun.(value)\n        {next, {:next, next}}\n    end)\n  end\n\n  @doc \"\"\"\n  Returns a stream generated by calling `generator_fun` repeatedly.\n\n  ## Examples\n\n      # Although not necessary, let's seed the random algorithm\n      iex> :rand.seed(:exsss, {1, 2, 3})\n      iex> Stream.repeatedly(&:rand.uniform/0) |> Enum.take(3)\n      [0.5455598952593053, 0.6039309974353404, 0.6684893034823949]\n\n  \"\"\"\n  @spec repeatedly((-> element)) :: Enumerable.t()\n  def repeatedly(generator_fun) when is_function(generator_fun, 0) do\n    &do_repeatedly(generator_fun, &1, &2)\n  end\n\n  defp do_repeatedly(generator_fun, {:suspend, acc}, fun) do\n    {:suspended, acc, &do_repeatedly(generator_fun, &1, fun)}\n  end\n\n  defp do_repeatedly(_generator_fun, {:halt, acc}, _fun) do\n    {:halted, acc}\n  end\n\n  defp do_repeatedly(generator_fun, {:cont, acc}, fun) do\n    do_repeatedly(generator_fun, fun.(generator_fun.(), acc), fun)\n  end\n\n  @doc \"\"\"\n  Emits a sequence of values for the given resource.\n\n  Similar to `transform/3` but the initial accumulated value is\n  computed lazily via `start_fun` and executes an `after_fun` at\n  the end of enumeration (both in cases of success and failure).\n\n  Successive values are generated by calling `next_fun` with the\n  previous accumulator (the initial value being the result returned\n  by `start_fun`) and it must return a tuple containing a list\n  of elements to be emitted and the next accumulator. The enumeration\n  finishes if it returns `{:halt, acc}`.\n\n  As the function name suggests, this function is useful to stream values from\n  resources.\n\n  ## Examples\n\n      Stream.resource(\n        fn -> File.open!(\"sample\") end,\n        fn file ->\n          case IO.read(file, :line) do\n            data when is_binary(data) -> {[data], file}\n            _ -> {:halt, file}\n          end\n        end,\n        fn file -> File.close(file) end\n      )\n\n      iex> Stream.resource(\n      ...>  fn ->\n      ...>    {:ok, pid} = StringIO.open(\"string\")\n      ...>    pid\n      ...>  end,\n      ...>  fn pid ->\n      ...>    case IO.getn(pid, \"\", 1) do\n      ...>      :eof -> {:halt, pid}\n      ...>      char -> {[char], pid}\n      ...>    end\n      ...>  end,\n      ...>  fn pid -> StringIO.close(pid) end\n      ...> ) |> Enum.to_list()\n      [\"s\", \"t\", \"r\", \"i\", \"n\", \"g\"]\n\n  \"\"\"\n  @spec resource((-> acc), (acc -> {[element], acc} | {:halt, acc}), (acc -> term)) ::\n          Enumerable.t()\n  def resource(start_fun, next_fun, after_fun)\n      when is_function(start_fun, 0) and is_function(next_fun, 1) and is_function(after_fun, 1) do\n    &do_resource(start_fun.(), next_fun, &1, &2, after_fun)\n  end\n\n  defp do_resource(next_acc, next_fun, {:suspend, acc}, fun, after_fun) do\n    {:suspended, acc, &do_resource(next_acc, next_fun, &1, fun, after_fun)}\n  end\n\n  defp do_resource(next_acc, _next_fun, {:halt, acc}, _fun, after_fun) do\n    after_fun.(next_acc)\n    {:halted, acc}\n  end\n\n  defp do_resource(next_acc, next_fun, {:cont, acc}, fun, after_fun) do\n    try do\n      next_fun.(next_acc)\n    catch\n      kind, reason ->\n        after_fun.(next_acc)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {:halt, next_acc} ->\n        do_resource(next_acc, next_fun, {:halt, acc}, fun, after_fun)\n\n      {[], next_acc} ->\n        do_resource(next_acc, next_fun, {:cont, acc}, fun, after_fun)\n\n      {[v], next_acc} ->\n        do_element_resource(next_acc, next_fun, acc, fun, after_fun, v)\n\n      {list, next_acc} when is_list(list) ->\n        reduce = &Enumerable.List.reduce(list, &1, fun)\n        do_list_resource(next_acc, next_fun, {:cont, acc}, fun, after_fun, reduce)\n\n      {enum, next_acc} ->\n        inner = &do_resource_each(&1, &2, fun)\n        reduce = &Enumerable.reduce(enum, &1, inner)\n        do_enum_resource(next_acc, next_fun, {:cont, acc}, fun, after_fun, reduce)\n    end\n  end\n\n  defp do_element_resource(next_acc, next_fun, acc, fun, after_fun, v) do\n    try do\n      fun.(v, acc)\n    catch\n      kind, reason ->\n        after_fun.(next_acc)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      acc ->\n        do_resource(next_acc, next_fun, acc, fun, after_fun)\n    end\n  end\n\n  defp do_list_resource(next_acc, next_fun, acc, fun, after_fun, reduce) do\n    try do\n      reduce.(acc)\n    catch\n      kind, reason ->\n        after_fun.(next_acc)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {:done, acc} ->\n        do_resource(next_acc, next_fun, {:cont, acc}, fun, after_fun)\n\n      {:halted, acc} ->\n        do_resource(next_acc, next_fun, {:halt, acc}, fun, after_fun)\n\n      {:suspended, acc, c} ->\n        {:suspended, acc, &do_list_resource(next_acc, next_fun, &1, fun, after_fun, c)}\n    end\n  end\n\n  defp do_enum_resource(next_acc, next_fun, {op, acc}, fun, after_fun, reduce) do\n    try do\n      reduce.({op, [:cont | acc]})\n    catch\n      kind, reason ->\n        after_fun.(next_acc)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {:halted, [inner_op | acc]} ->\n        do_resource(next_acc, next_fun, {inner_op, acc}, fun, after_fun)\n\n      {:done, [_ | acc]} ->\n        do_resource(next_acc, next_fun, {:cont, acc}, fun, after_fun)\n\n      {:suspended, [_ | acc], c} ->\n        {:suspended, acc, &do_enum_resource(next_acc, next_fun, &1, fun, after_fun, c)}\n    end\n  end\n\n  defp do_resource_each(x, [:cont | acc], f) do\n    case f.(x, acc) do\n      {op, res} -> {op, [op | res]}\n    end\n  end\n\n  @doc \"\"\"\n  Emits a sequence of values for the given accumulator.\n\n  Successive values are generated by calling `next_fun` with the previous\n  accumulator and it must return a tuple with the current value and next\n  accumulator. The enumeration finishes if it returns `nil`.\n\n  ## Examples\n\n  To create a stream that counts down and stops before zero:\n\n      iex> Stream.unfold(5, fn\n      ...>   0 -> nil\n      ...>   n -> {n, n - 1}\n      ...> end) |> Enum.to_list()\n      [5, 4, 3, 2, 1]\n\n  If `next_fun` never returns `nil`, the returned stream is *infinite*:\n\n      iex> Stream.unfold(0, fn\n      ...>   n -> {n, n + 1}\n      ...> end) |> Enum.take(10)\n      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n      iex> Stream.unfold(1, fn\n      ...>   n -> {n, n * 2}\n      ...> end) |> Enum.take(10)\n      [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]\n\n  \"\"\"\n  @spec unfold(acc, (acc -> {element, acc} | nil)) :: Enumerable.t()\n  def unfold(next_acc, next_fun) when is_function(next_fun, 1) do\n    &do_unfold(next_acc, next_fun, &1, &2)\n  end\n\n  defp do_unfold(next_acc, next_fun, {:suspend, acc}, fun) do\n    {:suspended, acc, &do_unfold(next_acc, next_fun, &1, fun)}\n  end\n\n  defp do_unfold(_next_acc, _next_fun, {:halt, acc}, _fun) do\n    {:halted, acc}\n  end\n\n  defp do_unfold(next_acc, next_fun, {:cont, acc}, fun) do\n    case next_fun.(next_acc) do\n      nil -> {:done, acc}\n      {v, next_acc} -> do_unfold(next_acc, next_fun, fun.(v, acc), fun)\n    end\n  end\n\n  @doc \"\"\"\n  Lazily intersperses `intersperse_element` between each element of the enumeration.\n\n  ## Examples\n\n      iex> Stream.intersperse([1, 2, 3], 0) |> Enum.to_list()\n      [1, 0, 2, 0, 3]\n\n      iex> Stream.intersperse([1], 0) |> Enum.to_list()\n      [1]\n\n      iex> Stream.intersperse([], 0) |> Enum.to_list()\n      []\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec intersperse(Enumerable.t(), any) :: Enumerable.t()\n  def intersperse(enumerable, intersperse_element) do\n    Stream.transform(enumerable, false, fn\n      element, true -> {[intersperse_element, element], true}\n      element, false -> {[element], true}\n    end)\n  end\n\n  ## Helpers\n\n  @compile {:inline, lazy: 2, lazy: 3, lazy: 4}\n\n  defp lazy(%Stream{done: nil, funs: funs} = lazy, fun), do: %{lazy | funs: [fun | funs]}\n  defp lazy(enum, fun), do: %Stream{enum: enum, funs: [fun]}\n\n  defp lazy(%Stream{done: nil, funs: funs, accs: accs} = lazy, acc, fun),\n    do: %{lazy | funs: [fun | funs], accs: [acc | accs]}\n\n  defp lazy(enum, acc, fun), do: %Stream{enum: enum, funs: [fun], accs: [acc]}\n\n  defp lazy(%Stream{done: nil, funs: funs, accs: accs} = lazy, acc, fun, done),\n    do: %{lazy | funs: [fun | funs], accs: [acc | accs], done: done}\n\n  defp lazy(enum, acc, fun, done), do: %Stream{enum: enum, funs: [fun], accs: [acc], done: done}\nend\n\ndefimpl Enumerable, for: Stream do\n  @compile :inline_list_funcs\n\n  def count(_lazy), do: {:error, __MODULE__}\n\n  def member?(_lazy, _value), do: {:error, __MODULE__}\n\n  def slice(_lazy), do: {:error, __MODULE__}\n\n  def reduce(lazy, acc, fun) do\n    do_reduce(lazy, acc, fn x, [acc] ->\n      {reason, acc} = fun.(x, acc)\n      {reason, [acc]}\n    end)\n  end\n\n  defp do_reduce(%Stream{enum: enum, funs: funs, accs: accs, done: done}, acc, fun) do\n    composed = :lists.foldl(fn entry_fun, acc -> entry_fun.(acc) end, fun, funs)\n    reduce = &Enumerable.reduce(enum, &1, composed)\n    do_each(reduce, done && {done, fun}, :lists.reverse(accs), acc)\n  end\n\n  defp do_each(reduce, done, accs, {command, acc}) do\n    case reduce.({command, [acc | accs]}) do\n      {:suspended, [acc | accs], continuation} ->\n        {:suspended, acc, &do_each(continuation, done, accs, &1)}\n\n      {:halted, accs} ->\n        do_done({:halted, accs}, done)\n\n      {:done, accs} ->\n        do_done({:done, accs}, done)\n    end\n  end\n\n  defp do_done({reason, [acc | _]}, nil), do: {reason, acc}\n\n  defp do_done({reason, [acc | t]}, {done, fun}) do\n    [h | _] = :lists.reverse(t)\n\n    case done.([acc, h], fun) do\n      {:cont, [acc | _]} -> {reason, acc}\n      {:halt, [acc | _]} -> {:halted, acc}\n      {:suspend, [acc | _]} -> {:suspended, acc, &{:done, elem(&1, 1)}}\n    end\n  end\nend\n\ndefimpl Inspect, for: Stream do\n  import Inspect.Algebra\n\n  def inspect(%{enum: enum, funs: funs}, opts) do\n    inner = [enum: enum, funs: :lists.reverse(funs)]\n    {doc, opts} = to_doc_with_opts(inner, opts)\n    {concat([\"#Stream<\", doc, \">\"]), opts}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/string/chars.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nimport Kernel, except: [to_string: 1]\n\ndefprotocol String.Chars do\n  @moduledoc ~S\"\"\"\n  The `String.Chars` protocol is responsible for\n  converting a structure to a binary (only if applicable).\n\n  The only function required to be implemented is\n  `to_string/1`, which does the conversion.\n\n  The `to_string/1` function automatically imported\n  by `Kernel` invokes this protocol. String\n  interpolation also invokes `to_string/1` in its\n  arguments. For example, `\"foo#{bar}\"` is the same\n  as `\"foo\" <> to_string(bar)`.\n  \"\"\"\n\n  @doc \"\"\"\n  Converts `term` to a string.\n  \"\"\"\n  @spec to_string(t) :: String.t()\n  def to_string(term)\nend\n\ndefimpl String.Chars, for: Atom do\n  def to_string(nil) do\n    \"\"\n  end\n\n  def to_string(atom) do\n    Atom.to_string(atom)\n  end\nend\n\ndefimpl String.Chars, for: BitString do\n  def to_string(term) when is_binary(term) do\n    term\n  end\n\n  def to_string(term) do\n    raise Protocol.UndefinedError,\n      protocol: @protocol,\n      value: term,\n      description: \"cannot convert a bitstring to a string\"\n  end\nend\n\ndefimpl String.Chars, for: List do\n  def to_string(charlist), do: List.to_string(charlist)\nend\n\ndefimpl String.Chars, for: Integer do\n  def to_string(term) do\n    Integer.to_string(term)\n  end\nend\n\ndefimpl String.Chars, for: Float do\n  def to_string(term) do\n    Float.to_string(term)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/string.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nimport Kernel, except: [length: 1]\n\ndefmodule String do\n  @moduledoc ~S\"\"\"\n  Strings in Elixir are UTF-8 encoded binaries.\n\n  Strings in Elixir are a sequence of Unicode characters,\n  typically written between double quoted strings, such\n  as `\"hello\"` and `\"héllò\"`.\n\n  In case a string must have a double-quote in itself,\n  the double quotes must be escaped with a backslash,\n  for example: `\"this is a string with \\\"double quotes\\\"\"`.\n\n  You can concatenate two strings with the `<>/2` operator:\n\n      iex> \"hello\" <> \" \" <> \"world\"\n      \"hello world\"\n\n  The functions in this module act according to\n  [The Unicode Standard, Version 17.0.0](https://www.unicode.org/versions/Unicode17.0.0/).\n\n  ## Interpolation\n\n  Strings in Elixir also support interpolation. This allows\n  you to place some value in the middle of a string by using\n  the `#{}` syntax:\n\n      iex> name = \"joe\"\n      iex> \"hello #{name}\"\n      \"hello joe\"\n\n  Any Elixir expression is valid inside the interpolation.\n  If a string is given, the string is interpolated as is.\n  If any other value is given, Elixir will attempt to convert\n  it to a string using the `String.Chars` protocol. This\n  allows, for example, to output an integer from the interpolation:\n\n      iex> \"2 + 2 = #{2 + 2}\"\n      \"2 + 2 = 4\"\n\n  In case the value you want to interpolate cannot be\n  converted to a string, because it doesn't have a human\n  textual representation, a protocol error will be raised.\n\n  ## Escape characters\n\n  Besides allowing double-quotes to be escaped with a backslash,\n  strings also support the following escape characters:\n\n    * `\\0` - Null byte\n    * `\\a` - Bell\n    * `\\b` - Backspace\n    * `\\t` - Horizontal tab\n    * `\\n` - Line feed (New lines)\n    * `\\v` - Vertical tab\n    * `\\f` - Form feed\n    * `\\r` - Carriage return\n    * `\\e` - Command Escape\n    * `\\s` - Space\n    * `\\#` - Returns the `#` character itself, skipping interpolation\n    * `\\\\` - Single backslash\n    * `\\xNN` - A byte represented by the hexadecimal `NN`\n    * `\\uNNNN` - A Unicode code point represented by `NNNN`\n    * `\\u{NNNNNN}` - A Unicode code point represented by `NNNNNN`\n\n  Note it is generally not advised to use `\\xNN` in Elixir\n  strings, as introducing an invalid byte sequence would\n  make the string invalid. If you have to introduce a\n  character by its hexadecimal representation, it is best\n  to work with Unicode code points, such as `\\uNNNN`. In fact,\n  understanding Unicode code points can be essential when doing\n  low-level manipulations of string, so let's explore them in\n  detail next.\n\n  ## Unicode and code points\n\n  In order to facilitate meaningful communication between computers\n  across multiple languages, a standard is required so that the ones\n  and zeros on one machine mean the same thing when they are transmitted\n  to another. The Unicode Standard acts as an official registry of\n  virtually all the characters we know: this includes characters from\n  classical and historical texts, emoji, and formatting and control\n  characters as well.\n\n  Unicode organizes all of the characters in its repertoire into code\n  charts, and each character is given a unique numerical index. This\n  numerical index is known as a Code Point.\n\n  In Elixir you can use a `?` in front of a character literal to reveal\n  its code point:\n\n      iex> ?a\n      97\n      iex> ?ł\n      322\n\n  Note that most Unicode code charts will refer to a code point by its\n  hexadecimal (hex) representation, e.g. `97` translates to `0061` in hex,\n  and we can represent any Unicode character in an Elixir string by\n  using the `\\u` escape character followed by its code point number:\n\n      iex> \"\\u0061\" === \"a\"\n      true\n      iex> 0x0061 = 97 = ?a\n      97\n\n  The hex representation will also help you look up information about a\n  code point, e.g. [https://codepoints.net/U+0061](https://codepoints.net/U+0061)\n  has a data sheet all about the lower case `a`, a.k.a. code point 97.\n  Remember you can get the hex presentation of a number by calling\n  `Integer.to_string/2`:\n\n      iex> Integer.to_string(?a, 16)\n      \"61\"\n\n  ## UTF-8 encoded and encodings\n\n  Now that we understand what the Unicode standard is and what code points\n  are, we can finally talk about encodings. Whereas the code point is **what**\n  we store, an encoding deals with **how** we store it: encoding is an\n  implementation. In other words, we need a mechanism to convert the code\n  point numbers into bytes so they can be stored in memory, written to disk, and such.\n\n  Elixir uses UTF-8 to encode its strings, which means that code points are\n  encoded as a series of 8-bit bytes. UTF-8 is a **variable width** character\n  encoding that uses one to four bytes to store each code point. It is capable\n  of encoding all valid Unicode code points. Let's see an example:\n\n      iex> string = \"héllo\"\n      \"héllo\"\n      iex> String.length(string)\n      5\n      iex> byte_size(string)\n      6\n\n  Although the string above has 5 characters, it uses 6 bytes, as two bytes\n  are used to represent the character `é`.\n\n  ## Grapheme clusters\n\n  This module also works with the concept of grapheme cluster\n  (from now on referenced as graphemes). Graphemes can consist\n  of multiple code points that may be perceived as a single character\n  by readers. For example, \"é\" can be represented either as a single\n  \"e with acute\" code point, as seen above in the string `\"héllo\"`,\n  or as the letter \"e\" followed by a \"combining acute accent\"\n  (two code points):\n\n      iex> string = \"\\u0065\\u0301\"\n      \"é\"\n      iex> byte_size(string)\n      3\n      iex> String.length(string)\n      1\n      iex> String.codepoints(string)\n      [\"e\", \"́\"]\n      iex> String.graphemes(string)\n      [\"é\"]\n\n  Although it looks visually the same as before, the example above\n  is made of two characters, it is perceived by users as one.\n\n  Graphemes can also be two characters that are interpreted as one\n  by some languages. For example, some languages may consider \"ch\"\n  as a single character. However, since this information depends on\n  the locale, it is not taken into account by this module.\n\n  In general, the functions in this module rely on the Unicode\n  Standard, but do not contain any of the locale specific behavior.\n  More information about graphemes can be found in the [Unicode\n  Standard Annex #29](https://www.unicode.org/reports/tr29/).\n\n  For converting a binary to a different encoding and for Unicode\n  normalization mechanisms, see Erlang's [`:unicode`](`:unicode`) module.\n\n  ## String and binary operations\n\n  To act according to the Unicode Standard, many functions\n  in this module run in linear time, as they need to traverse\n  the whole string considering the proper Unicode code points.\n\n  For example, `String.length/1` will take longer as\n  the input grows. On the other hand, `Kernel.byte_size/1` always runs\n  in constant time (i.e. regardless of the input size).\n\n  This means often there are performance costs in using the\n  functions in this module, compared to the more low-level\n  operations that work directly with binaries:\n\n    * `Kernel.binary_part/3` - retrieves part of the binary\n    * `Kernel.bit_size/1` and `Kernel.byte_size/1` - size related functions\n    * `Kernel.is_bitstring/1` and `Kernel.is_binary/1` - type-check function\n    * Plus a number of functions for working with binaries (bytes)\n      in the [`:binary` module](`:binary`)\n\n  A `utf8` modifier is also available inside the binary syntax `<<>>`.\n  It can be used to match code points out of a binary/string:\n\n      iex> <<eacute::utf8>> = \"é\"\n      iex> eacute\n      233\n\n  See the [*Patterns and Guards* guide](patterns-and-guards.md) and the documentation for\n  [`<<>>`](`<<>>/1`) for more information on binary pattern matching.\n\n  You can also fully convert a string into a list of integer code points,\n  known as \"charlists\" in Elixir, by calling `String.to_charlist/1`:\n\n      iex> String.to_charlist(\"héllo\")\n      [104, 233, 108, 108, 111]\n\n  If you would rather see the underlying bytes of a string, instead of\n  its codepoints, a common trick is to concatenate the null byte `<<0>>`\n  to it:\n\n      iex> \"héllo\" <> <<0>>\n      <<104, 195, 169, 108, 108, 111, 0>>\n\n  Alternatively, you can view a string's binary representation by\n  passing an option to `IO.inspect/2`:\n\n      IO.inspect(\"héllo\", binaries: :as_binaries)\n      #=> <<104, 195, 169, 108, 108, 111>>\n\n  ## Self-synchronization\n\n  The UTF-8 encoding is self-synchronizing. This means that\n  if malformed data (i.e., data that is not possible according\n  to the definition of the encoding) is encountered, only one\n  code point needs to be rejected.\n\n  This module relies on this behavior to ignore such invalid\n  characters. For example, `length/1` will return\n  a correct result even if an invalid code point is fed into it.\n\n  In other words, this module expects invalid data to be detected\n  elsewhere, usually when retrieving data from the external source.\n  For example, a driver that reads strings from a database will be\n  responsible to check the validity of the encoding. `String.chunk/2`\n  can be used for breaking a string into valid and invalid parts.\n\n  ## Compile binary patterns\n\n  Many functions in this module work with patterns. For example,\n  `String.split/3` can split a string into multiple strings given\n  a pattern. This pattern can be a string, a list of strings or\n  a compiled pattern:\n\n      iex> String.split(\"foo bar\", \" \")\n      [\"foo\", \"bar\"]\n\n      iex> String.split(\"foo bar!\", [\" \", \"!\"])\n      [\"foo\", \"bar\", \"\"]\n\n      iex> pattern = :binary.compile_pattern([\" \", \"!\"])\n      iex> String.split(\"foo bar!\", pattern)\n      [\"foo\", \"bar\", \"\"]\n\n  The compiled pattern is useful when the same match will\n  be done over and over again. Note though that the compiled\n  pattern cannot be stored in a module attribute as the pattern\n  is generated at runtime and does not survive compile time.\n  \"\"\"\n\n  @typedoc \"\"\"\n  A UTF-8 encoded binary.\n\n  The types `String.t()` and `binary()` are equivalent to analysis tools.\n  Although, for those reading the documentation, `String.t()` implies\n  it is a UTF-8 encoded binary.\n  \"\"\"\n  @type t :: binary\n\n  @typedoc \"A single Unicode code point encoded in UTF-8. It may be one or more bytes.\"\n  @type codepoint :: t\n\n  @typedoc \"Multiple code points that may be perceived as a single character by readers\"\n  @type grapheme :: t\n\n  @typedoc \"\"\"\n  Pattern used in functions like `replace/4` and `split/3`.\n\n  It must be one of:\n\n    * a string\n    * an empty list\n    * a list containing non-empty strings\n    * a compiled search pattern created by `:binary.compile_pattern/1`\n\n  \"\"\"\n  @type pattern ::\n          t()\n          | [nonempty_binary]\n          | (compiled_search_pattern :: :binary.cp())\n\n  @type split_opts :: [\n          parts: pos_integer() | :infinity,\n          trim: boolean()\n        ]\n\n  @type splitter_opts :: [trim: boolean()]\n\n  @type replace_opts :: [global: boolean()]\n\n  @conditional_mappings [:greek, :turkic]\n\n  @doc \"\"\"\n  Checks if a string contains only printable characters up to `character_limit`.\n\n  Takes an optional `character_limit` as a second argument. If `character_limit` is `0`, this\n  function will return `true`.\n\n  ## Examples\n\n      iex> String.printable?(\"abc\")\n      true\n\n      iex> String.printable?(\"abc\" <> <<0>>)\n      false\n\n      iex> String.printable?(\"abc\" <> <<0>>, 2)\n      true\n\n      iex> String.printable?(\"abc\" <> <<0>>, 0)\n      true\n\n  \"\"\"\n  @spec printable?(t, 0) :: true\n  @spec printable?(t, pos_integer | :infinity) :: boolean\n  def printable?(string, character_limit \\\\ :infinity)\n      when is_binary(string) and\n             (character_limit == :infinity or\n                (is_integer(character_limit) and character_limit >= 0)) do\n    recur_printable?(string, character_limit)\n  end\n\n  defp recur_printable?(<<_::binary>>, 0), do: true\n  defp recur_printable?(<<>>, _character_limit), do: true\n\n  for char <- 0x20..0x7E do\n    defp recur_printable?(<<unquote(char), rest::binary>>, character_limit) do\n      recur_printable?(rest, decrement(character_limit))\n    end\n  end\n\n  for char <- [?\\n, ?\\r, ?\\t, ?\\v, ?\\b, ?\\f, ?\\e, ?\\d, ?\\a] do\n    defp recur_printable?(<<unquote(char), rest::binary>>, character_limit) do\n      recur_printable?(rest, decrement(character_limit))\n    end\n  end\n\n  defp recur_printable?(<<char::utf8, rest::binary>>, character_limit)\n       when char in 0xA0..0xD7FF\n       when char in 0xE000..0xFFFD\n       when char in 0x10000..0x10FFFF do\n    recur_printable?(rest, decrement(character_limit))\n  end\n\n  defp recur_printable?(_string, _character_limit) do\n    false\n  end\n\n  defp decrement(:infinity), do: :infinity\n  defp decrement(character_limit), do: character_limit - 1\n\n  @doc ~S\"\"\"\n  Divides a string into substrings at each Unicode whitespace\n  occurrence with leading and trailing whitespace ignored.\n\n  Groups of whitespace are treated as a single occurrence.\n  Divisions do not occur on non-breaking whitespace.\n\n  ## Examples\n\n      iex> String.split(\"foo bar\")\n      [\"foo\", \"bar\"]\n\n      iex> String.split(\"foo\" <> <<194, 133>> <> \"bar\")\n      [\"foo\", \"bar\"]\n\n      iex> String.split(\" foo   bar \")\n      [\"foo\", \"bar\"]\n\n      iex> String.split(\"no\\u00a0break\")\n      [\"no\\u00a0break\"]\n\n  Removes empty strings, like when using `trim: true` in `String.split/3`.\n\n      iex> String.split(\" \")\n      []\n\n  \"\"\"\n  @spec split(t) :: [t]\n  defdelegate split(binary), to: String.Break\n\n  @doc ~S\"\"\"\n  Divides a string into parts based on a pattern.\n\n  Returns a list of these parts.\n\n  The `pattern` may be a string, a list of strings, a regular expression, or a\n  compiled pattern.\n\n  The string is split into as many parts as possible by\n  default, but can be controlled via the `:parts` option.\n\n  Empty strings are only removed from the result if the\n  `:trim` option is set to `true`.\n\n  When the pattern used is a regular expression, the string is\n  split using `Regex.split/3`.\n\n  If the pattern cannot be found, a list containing the original\n  string will be returned.\n\n  ## Options\n\n    * `:parts` (positive integer or `:infinity`) - the string\n      is split into at most as many parts as this option specifies.\n      If `:infinity`, the string will be split into all possible\n      parts. Defaults to `:infinity`.\n\n    * `:trim` (boolean) - if `true`, empty strings are removed from\n      the resulting list.\n\n  This function also accepts all options accepted by `Regex.split/3`\n  if `pattern` is a regular expression.\n\n  ## Examples\n\n  Splitting with a string pattern:\n\n      iex> String.split(\"a,b,c\", \",\")\n      [\"a\", \"b\", \"c\"]\n\n      iex> String.split(\"a,b,c\", \",\", parts: 2)\n      [\"a\", \"b,c\"]\n\n      iex> String.split(\" a b c \", \" \", trim: true)\n      [\"a\", \"b\", \"c\"]\n\n  A list of patterns:\n\n      iex> String.split(\"1,2 3,4\", [\" \", \",\"])\n      [\"1\", \"2\", \"3\", \"4\"]\n\n  A regular expression:\n\n      iex> String.split(\"a,b,c\", ~r{,})\n      [\"a\", \"b\", \"c\"]\n\n      iex> String.split(\"a,b,c\", ~r{,}, parts: 2)\n      [\"a\", \"b,c\"]\n\n      iex> String.split(\" a b c \", ~r{\\s}, trim: true)\n      [\"a\", \"b\", \"c\"]\n\n      iex> String.split(\"abc\", ~r{b}, include_captures: true)\n      [\"a\", \"b\", \"c\"]\n\n  A compiled pattern:\n\n      iex> pattern = :binary.compile_pattern([\" \", \",\"])\n      iex> String.split(\"1,2 3,4\", pattern)\n      [\"1\", \"2\", \"3\", \"4\"]\n\n  Splitting on empty string returns graphemes:\n\n      iex> String.split(\"abc\", \"\")\n      [\"\", \"a\", \"b\", \"c\", \"\"]\n\n      iex> String.split(\"abc\", \"\", trim: true)\n      [\"a\", \"b\", \"c\"]\n\n      iex> String.split(\"abc\", \"\", parts: 1)\n      [\"abc\"]\n\n      iex> String.split(\"abc\", \"\", parts: 3)\n      [\"\", \"a\", \"bc\"]\n\n  Splitting on a non-existing pattern returns the original string:\n\n      iex> String.split(\"abc\", \",\")\n      [\"abc\"]\n\n  Be aware that this function can split within or across grapheme boundaries.\n  For example, take the grapheme \"é\" which is made of the characters\n  \"e\" and the acute accent. The following will split the string into two parts:\n\n      iex> String.split(String.normalize(\"é\", :nfd), \"e\")\n      [\"\", \"́\"]\n\n  However, if \"é\" is represented by the single character \"e with acute\"\n  accent, then it will split the string into just one part:\n\n      iex> String.split(String.normalize(\"é\", :nfc), \"e\")\n      [\"é\"]\n\n  When using both the `:trim` and the `:parts` option, the empty values\n  are removed as the parts are computed (if any). No trimming happens\n  after all parts are computed:\n\n      iex> String.split(\" a  b  c  \", \" \", trim: true, parts: 2)\n      [\"a\", \" b  c  \"]\n      iex> String.split(\" a  b  c  \", \" \", trim: true, parts: 3)\n      [\"a\", \"b\", \" c  \"]\n\n  \"\"\"\n  @spec split(t, pattern, split_opts()) :: [t]\n  @spec split(t, Regex.t(), Regex.split_opts()) :: [t]\n  def split(string, pattern, options \\\\ [])\n\n  def split(string, %Regex{} = pattern, options) when is_binary(string) and is_list(options) do\n    Regex.split(pattern, string, options)\n  end\n\n  def split(string, \"\", options) when is_binary(string) and is_list(options) do\n    parts = Keyword.get(options, :parts, :infinity)\n    index = parts_to_index(parts)\n    trim = Keyword.get(options, :trim, false)\n\n    if trim == false and index != 1 do\n      [\"\" | split_empty(string, trim, index - 1)]\n    else\n      split_empty(string, trim, index)\n    end\n  end\n\n  def split(string, [], options) when is_binary(string) and is_list(options) do\n    if string == \"\" and Keyword.get(options, :trim, false) do\n      []\n    else\n      [string]\n    end\n  end\n\n  def split(string, pattern, options) when is_binary(string) and is_list(options) do\n    parts = Keyword.get(options, :parts, :infinity)\n    trim = Keyword.get(options, :trim, false)\n\n    case {parts, trim} do\n      {:infinity, false} ->\n        :binary.split(string, pattern, [:global])\n\n      {:infinity, true} ->\n        :binary.split(string, pattern, [:global, :trim_all])\n\n      {2, false} ->\n        :binary.split(string, pattern)\n\n      _ ->\n        pattern = maybe_compile_pattern(pattern)\n        split_each(string, pattern, trim, parts_to_index(parts))\n    end\n  end\n\n  defp parts_to_index(:infinity), do: 0\n  defp parts_to_index(n) when is_integer(n) and n > 0, do: n\n\n  defp split_empty(\"\", true, 1), do: []\n  defp split_empty(string, _, 1), do: [IO.iodata_to_binary(string)]\n\n  defp split_empty(string, trim, count) do\n    case :unicode_util.gc(string) do\n      [gc] -> [grapheme_to_binary(gc) | split_empty(\"\", trim, 1)]\n      [gc | rest] -> [grapheme_to_binary(gc) | split_empty(rest, trim, count - 1)]\n      [] -> split_empty(\"\", trim, 1)\n      {:error, <<byte, rest::bits>>} -> [<<byte>> | split_empty(rest, trim, count - 1)]\n    end\n  end\n\n  defp split_each(\"\", _pattern, true, 1), do: []\n  defp split_each(string, _pattern, _trim, 1) when is_binary(string), do: [string]\n\n  defp split_each(string, pattern, trim, count) do\n    case do_splitter(string, pattern, trim) do\n      {h, t} -> [h | split_each(t, pattern, trim, count - 1)]\n      nil -> []\n    end\n  end\n\n  @doc \"\"\"\n  Returns an enumerable that splits a string on demand.\n\n  This is in contrast to `split/3` which splits the\n  entire string upfront.\n\n  This function does not support regular expressions\n  by design. When using regular expressions, it is often\n  more efficient to have the regular expressions traverse\n  the string at once than in parts, like this function does.\n\n  ## Options\n\n    * :trim - when `true`, does not emit empty patterns\n\n  ## Examples\n\n      iex> String.splitter(\"1,2 3,4 5,6 7,8,...,99999\", [\" \", \",\"]) |> Enum.take(4)\n      [\"1\", \"2\", \"3\", \"4\"]\n\n      iex> String.splitter(\"abcd\", \"\") |> Enum.take(10)\n      [\"\", \"a\", \"b\", \"c\", \"d\", \"\"]\n\n      iex> String.splitter(\"abcd\", \"\", trim: true) |> Enum.take(10)\n      [\"a\", \"b\", \"c\", \"d\"]\n\n  A compiled pattern can also be given:\n\n      iex> pattern = :binary.compile_pattern([\" \", \",\"])\n      iex> String.splitter(\"1,2 3,4 5,6 7,8,...,99999\", pattern) |> Enum.take(4)\n      [\"1\", \"2\", \"3\", \"4\"]\n\n  \"\"\"\n  @spec splitter(t, pattern, splitter_opts) :: Enumerable.t()\n  def splitter(string, pattern, options \\\\ [])\n\n  def splitter(string, \"\", options) when is_binary(string) and is_list(options) do\n    if Keyword.get(options, :trim, false) do\n      Stream.unfold(string, &next_grapheme/1)\n    else\n      Stream.unfold(:match, &do_empty_splitter(&1, string))\n    end\n  end\n\n  def splitter(string, [], options) when is_binary(string) and is_list(options) do\n    if string == \"\" and Keyword.get(options, :trim, false) do\n      Stream.duplicate(string, 0)\n    else\n      Stream.duplicate(string, 1)\n    end\n  end\n\n  def splitter(string, pattern, options) when is_binary(string) and is_list(options) do\n    pattern = maybe_compile_pattern(pattern)\n    trim = Keyword.get(options, :trim, false)\n    Stream.unfold(string, &do_splitter(&1, pattern, trim))\n  end\n\n  defp do_empty_splitter(:match, string), do: {\"\", string}\n  defp do_empty_splitter(:nomatch, _string), do: nil\n  defp do_empty_splitter(\"\", _), do: {\"\", :nomatch}\n  defp do_empty_splitter(string, _), do: next_grapheme(string)\n\n  defp do_splitter(:nomatch, _pattern, _), do: nil\n  defp do_splitter(\"\", _pattern, false), do: {\"\", :nomatch}\n  defp do_splitter(\"\", _pattern, true), do: nil\n\n  defp do_splitter(bin, pattern, trim) do\n    case :binary.split(bin, pattern) do\n      [\"\", second] when trim -> do_splitter(second, pattern, trim)\n      [first, second] -> {first, second}\n      [first] -> {first, :nomatch}\n    end\n  end\n\n  defp maybe_compile_pattern(pattern) when is_tuple(pattern), do: pattern\n  defp maybe_compile_pattern(pattern), do: :binary.compile_pattern(pattern)\n\n  @doc \"\"\"\n  Splits a string into two at the specified offset. When the offset given is\n  negative, location is counted from the end of the string.\n\n  The offset is capped to the length of the string. Returns a tuple with\n  two elements.\n\n  > #### Linear Access {: .warning}\n  >\n  > This function splits on graphemes and for such it has to linearly traverse\n  > the string.\n  > If you want to split a string or a binary based on the number of bytes,\n  > use `Kernel.binary_part/3` instead.\n\n  ## Examples\n\n      iex> String.split_at(\"sweetelixir\", 5)\n      {\"sweet\", \"elixir\"}\n\n      iex> String.split_at(\"sweetelixir\", -6)\n      {\"sweet\", \"elixir\"}\n\n      iex> String.split_at(\"abc\", 0)\n      {\"\", \"abc\"}\n\n      iex> String.split_at(\"abc\", 1000)\n      {\"abc\", \"\"}\n\n      iex> String.split_at(\"abc\", -1000)\n      {\"\", \"abc\"}\n\n  \"\"\"\n  @spec split_at(t, integer) :: {t, t}\n  def split_at(string, position)\n\n  def split_at(string, position)\n      when is_binary(string) and is_integer(position) and position >= 0 do\n    do_split_at(string, position)\n  end\n\n  def split_at(string, position)\n      when is_binary(string) and is_integer(position) and position < 0 do\n    position = length(string) + position\n\n    case position >= 0 do\n      true -> do_split_at(string, position)\n      false -> {\"\", string}\n    end\n  end\n\n  defp do_split_at(string, position) do\n    remaining = byte_size_remaining_at(string, position)\n    start = byte_size(string) - remaining\n    <<left::size(^start)-binary, right::size(^remaining)-binary>> = string\n    {left, right}\n  end\n\n  @doc ~S\"\"\"\n  Counts the number of non-overlapping occurrences of a `pattern` in a `string`.\n\n  In case the pattern is an empty string, the function returns 1 + the number of graphemes\n  in the string.\n\n  ## Examples\n\n      iex> String.count(\"hello world\", \"o\")\n      2\n\n      iex> String.count(\"hello world\", \"l\")\n      3\n\n      iex> String.count(\"hello world\", \"x\")\n      0\n\n      iex> String.count(\"hello world\", ~r/o/)\n      2\n\n      iex> String.count(\"Hellooo\", \"oo\")\n      1\n\n      iex> String.count(\"hello world\", \"\")\n      12\n\n  The `pattern` can also be a compiled pattern:\n\n      iex> pattern = :binary.compile_pattern([\" \", \"!\"])\n      iex> String.count(\"foo bar baz!!\", pattern)\n      4\n\n  \"\"\"\n  @spec count(t, pattern | Regex.t()) :: non_neg_integer\n  @doc since: \"1.19.0\"\n  def count(string, <<>>), do: length(string) + 1\n\n  def count(string, pattern) when is_struct(pattern, Regex) do\n    Kernel.length(Regex.scan(pattern, string, return: :index))\n  end\n\n  def count(string, pattern) do\n    Kernel.length(:binary.matches(string, pattern))\n  end\n\n  @doc ~S\"\"\"\n  Returns `true` if `string1` is canonically equivalent to `string2`.\n\n  It performs Normalization Form Canonical Decomposition (NFD) on the\n  strings before comparing them. This function is equivalent to:\n\n      String.normalize(string1, :nfd) == String.normalize(string2, :nfd)\n\n  If you plan to compare multiple strings, multiple times in a row, you\n  may normalize them upfront and compare them directly to avoid multiple\n  normalization passes.\n\n  ## Examples\n\n      iex> String.equivalent?(\"abc\", \"abc\")\n      true\n\n      iex> String.equivalent?(\"man\\u0303ana\", \"mañana\")\n      true\n\n      iex> String.equivalent?(\"abc\", \"ABC\")\n      false\n\n      iex> String.equivalent?(\"nø\", \"nó\")\n      false\n\n  \"\"\"\n  @spec equivalent?(t, t) :: boolean\n  def equivalent?(string1, string2) when is_binary(string1) and is_binary(string2) do\n    normalize(string1, :nfd) == normalize(string2, :nfd)\n  end\n\n  @doc \"\"\"\n  Converts all characters in `string` to Unicode normalization\n  form identified by `form`.\n\n  Invalid Unicode codepoints are skipped and the remaining of\n  the string is converted. If you want the algorithm to stop\n  and return on invalid codepoint, use `:unicode.characters_to_nfd_binary/1`,\n  `:unicode.characters_to_nfc_binary/1`, `:unicode.characters_to_nfkd_binary/1`,\n  and `:unicode.characters_to_nfkc_binary/1` instead.\n\n  Normalization forms `:nfkc` and `:nfkd` should not be blindly applied\n  to arbitrary text. Because they erase many formatting distinctions,\n  they will prevent round-trip conversion to and from many legacy\n  character sets.\n\n  ## Forms\n\n  The supported forms are:\n\n    * `:nfd` - Normalization Form Canonical Decomposition.\n      Characters are decomposed by canonical equivalence, and\n      multiple combining characters are arranged in a specific\n      order.\n\n    * `:nfc` - Normalization Form Canonical Composition.\n      Characters are decomposed and then recomposed by canonical equivalence.\n\n    * `:nfkd` - Normalization Form Compatibility Decomposition.\n      Characters are decomposed by compatibility equivalence, and\n      multiple combining characters are arranged in a specific\n      order.\n\n    * `:nfkc` - Normalization Form Compatibility Composition.\n      Characters are decomposed and then recomposed by compatibility equivalence.\n\n  ## Examples\n\n      iex> String.normalize(\"yêṩ\", :nfd)\n      \"yêṩ\"\n\n      iex> String.normalize(\"leña\", :nfc)\n      \"leña\"\n\n      iex> String.normalize(\"ﬁ\", :nfkd)\n      \"fi\"\n\n      iex> String.normalize(\"fi\", :nfkc)\n      \"fi\"\n\n  \"\"\"\n  @spec normalize(t, :nfd | :nfc | :nfkd | :nfkc) :: t\n  def normalize(string, form)\n\n  def normalize(string, :nfd) when is_binary(string) do\n    case :unicode.characters_to_nfd_binary(string) do\n      string when is_binary(string) -> string\n      {:error, good, <<head, rest::binary>>} -> good <> <<head>> <> normalize(rest, :nfd)\n    end\n  end\n\n  def normalize(string, :nfc) when is_binary(string) do\n    case :unicode.characters_to_nfc_binary(string) do\n      string when is_binary(string) -> string\n      {:error, good, <<head, rest::binary>>} -> good <> <<head>> <> normalize(rest, :nfc)\n    end\n  end\n\n  def normalize(string, :nfkd) when is_binary(string) do\n    case :unicode.characters_to_nfkd_binary(string) do\n      string when is_binary(string) -> string\n      {:error, good, <<head, rest::binary>>} -> good <> <<head>> <> normalize(rest, :nfkd)\n    end\n  end\n\n  def normalize(string, :nfkc) when is_binary(string) do\n    case :unicode.characters_to_nfkc_binary(string) do\n      string when is_binary(string) -> string\n      {:error, good, <<head, rest::binary>>} -> good <> <<head>> <> normalize(rest, :nfkc)\n    end\n  end\n\n  @doc \"\"\"\n  Converts all characters in the given string to uppercase according to `mode`.\n\n  `mode` may be `:default`, `:ascii`, `:greek` or `:turkic`. The `:default` mode considers\n  all non-conditional transformations outlined in the Unicode standard. `:ascii`\n  uppercases only the letters a to z. `:greek` includes the context sensitive\n  mappings found in Greek. `:turkic` properly handles the letter i with the dotless variant.\n\n  ## Examples\n\n      iex> String.upcase(\"abcd\")\n      \"ABCD\"\n\n      iex> String.upcase(\"ab 123 xpto\")\n      \"AB 123 XPTO\"\n\n      iex> String.upcase(\"olá\")\n      \"OLÁ\"\n\n  The `:ascii` mode ignores Unicode characters and provides a more\n  performant implementation when you know the string contains only\n  ASCII characters:\n\n      iex> String.upcase(\"olá\", :ascii)\n      \"OLá\"\n\n  And `:turkic` properly handles the letter i with the dotless variant:\n\n      iex> String.upcase(\"ıi\")\n      \"II\"\n\n      iex> String.upcase(\"ıi\", :turkic)\n      \"Iİ\"\n\n  Also see `downcase/2` and `capitalize/2` for other conversions.\n  \"\"\"\n  @spec upcase(t, :default | :ascii | :greek | :turkic) :: t\n  def upcase(string, mode \\\\ :default)\n\n  def upcase(\"\", _mode) do\n    \"\"\n  end\n\n  def upcase(string, :default) when is_binary(string) do\n    String.Unicode.upcase(string, [], :default)\n  end\n\n  def upcase(string, :ascii) when is_binary(string) do\n    IO.iodata_to_binary(upcase_ascii(string))\n  end\n\n  def upcase(string, mode) when is_binary(string) and mode in @conditional_mappings do\n    String.Unicode.upcase(string, [], mode)\n  end\n\n  defp upcase_ascii(<<char, rest::bits>>) when char >= ?a and char <= ?z,\n    do: [char - 32 | upcase_ascii(rest)]\n\n  defp upcase_ascii(<<char, rest::bits>>), do: [char | upcase_ascii(rest)]\n  defp upcase_ascii(<<>>), do: []\n\n  @doc \"\"\"\n  Converts all characters in the given string to lowercase according to `mode`.\n\n  `mode` may be `:default`, `:ascii`, `:greek` or `:turkic`. The `:default` mode considers\n  all non-conditional transformations outlined in the Unicode standard. `:ascii`\n  lowercases only the letters A to Z. `:greek` includes the context sensitive\n  mappings found in Greek. `:turkic` properly handles the letter i with the dotless variant.\n\n  Also see `upcase/2` and `capitalize/2` for other conversions.\n\n  ## Examples\n\n      iex> String.downcase(\"ABCD\")\n      \"abcd\"\n\n      iex> String.downcase(\"AB 123 XPTO\")\n      \"ab 123 xpto\"\n\n      iex> String.downcase(\"OLÁ\")\n      \"olá\"\n\n  The `:ascii` mode ignores Unicode characters and provides a more\n  performant implementation when you know the string contains only\n  ASCII characters:\n\n      iex> String.downcase(\"OLÁ\", :ascii)\n      \"olÁ\"\n\n  The `:greek` mode properly handles the context sensitive sigma in Greek:\n\n      iex> String.downcase(\"ΣΣ\")\n      \"σσ\"\n\n      iex> String.downcase(\"ΣΣ\", :greek)\n      \"σς\"\n\n  And `:turkic` properly handles the letter i with the dotless variant:\n\n      iex> String.downcase(\"Iİ\")\n      \"ii̇\"\n\n      iex> String.downcase(\"Iİ\", :turkic)\n      \"ıi\"\n\n  \"\"\"\n  @spec downcase(t, :default | :ascii | :greek | :turkic) :: t\n  def downcase(string, mode \\\\ :default)\n\n  def downcase(\"\", _mode) do\n    \"\"\n  end\n\n  def downcase(string, :default) when is_binary(string) do\n    String.Unicode.downcase(string, [], :default)\n  end\n\n  def downcase(string, :ascii) when is_binary(string) do\n    IO.iodata_to_binary(downcase_ascii(string))\n  end\n\n  def downcase(string, mode) when is_binary(string) and mode in @conditional_mappings do\n    String.Unicode.downcase(string, [], mode)\n  end\n\n  defp downcase_ascii(<<char, rest::bits>>) when char >= ?A and char <= ?Z,\n    do: [char + 32 | downcase_ascii(rest)]\n\n  defp downcase_ascii(<<char, rest::bits>>), do: [char | downcase_ascii(rest)]\n  defp downcase_ascii(<<>>), do: []\n\n  @doc \"\"\"\n  Converts the first character in the given string to\n  uppercase and the remainder to lowercase according to `mode`.\n\n  `mode` may be `:default`, `:ascii`, `:greek` or `:turkic`. The `:default` mode\n  considers all non-conditional transformations outlined in the Unicode standard.\n  `:ascii` capitalizes only the letters A to Z. `:greek` includes the context\n  sensitive mappings found in Greek. `:turkic` properly handles the letter `i`\n  with the dotless variant.\n\n  Also see `upcase/2` and `capitalize/2` for other conversions. If you want\n  a variation of this function that does not lowercase the rest of string,\n  see Erlang's `:string.titlecase/1`.\n\n  ## Examples\n\n      iex> String.capitalize(\"abcd\")\n      \"Abcd\"\n      iex> String.capitalize(\"ABCD\")\n      \"Abcd\"\n\n      iex> String.capitalize(\"ﬁn\")\n      \"Fin\"\n      iex> String.capitalize(\"olá\")\n      \"Olá\"\n\n  \"\"\"\n  @spec capitalize(t, :default | :ascii | :greek | :turkic) :: t\n  def capitalize(string, mode \\\\ :default)\n\n  def capitalize(<<char, rest::binary>>, :ascii) do\n    char = if char >= ?a and char <= ?z, do: char - 32, else: char\n    <<char>> <> downcase(rest, :ascii)\n  end\n\n  @letter_I <<0x0049::utf8>>\n  @letter_i <<0x0069::utf8>>\n  @letter_I_dot_above <<0x0130::utf8>>\n\n  def capitalize(<<@letter_i, right::binary>>, mode) do\n    if(mode == :turkic, do: @letter_I_dot_above, else: @letter_I) <> downcase(right, mode)\n  end\n\n  def capitalize(string, mode) when is_binary(string) do\n    case :unicode_util.gc(string) do\n      [gc] -> grapheme_to_binary(:string.titlecase([gc]))\n      [gc, rest] -> grapheme_to_binary(:string.titlecase([gc])) <> downcase(rest, mode)\n      [gc | rest] -> grapheme_to_binary(:string.titlecase([gc])) <> downcase(rest, mode)\n      [] -> \"\"\n      {:error, <<byte, rest::bits>>} -> <<byte>> <> downcase(rest, mode)\n    end\n  end\n\n  @doc false\n  @deprecated \"Use String.trim_trailing/1 instead\"\n  defdelegate rstrip(binary), to: String.Break, as: :trim_trailing\n\n  @doc false\n  @deprecated \"Use String.trim_trailing/2 with a binary as second argument instead\"\n  def rstrip(string, char) when is_integer(char) do\n    replace_trailing(string, <<char::utf8>>, \"\")\n  end\n\n  @doc \"\"\"\n  Replaces all leading occurrences of `match` by `replacement` of `match` in `string`.\n\n  Returns the string untouched if there are no occurrences.\n\n  If `match` is `\"\"`, this function raises an `ArgumentError` exception: this\n  happens because this function replaces **all** the occurrences of `match` at\n  the beginning of `string`, and it's impossible to replace \"multiple\"\n  occurrences of `\"\"`.\n\n  ## Examples\n\n      iex> String.replace_leading(\"hello world\", \"hello \", \"\")\n      \"world\"\n      iex> String.replace_leading(\"hello hello world\", \"hello \", \"\")\n      \"world\"\n\n      iex> String.replace_leading(\"hello world\", \"hello \", \"ola \")\n      \"ola world\"\n      iex> String.replace_leading(\"hello hello world\", \"hello \", \"ola \")\n      \"ola ola world\"\n\n  This function can replace across grapheme boundaries. See `replace/3`\n  for more information and examples.\n  \"\"\"\n  @spec replace_leading(t, t, t) :: t\n  def replace_leading(string, match, replacement)\n      when is_binary(string) and is_binary(match) and is_binary(replacement) do\n    if match == \"\" do\n      raise ArgumentError, \"cannot use an empty string as the match to replace\"\n    end\n\n    prefix_size = byte_size(match)\n    suffix_size = byte_size(string) - prefix_size\n    replace_leading(string, match, replacement, prefix_size, suffix_size, 0)\n  end\n\n  defp replace_leading(string, match, replacement, prefix_size, suffix_size, acc)\n       when suffix_size >= 0 do\n    case string do\n      <<prefix::size(^prefix_size)-binary, suffix::binary>> when prefix == match ->\n        replace_leading(\n          suffix,\n          match,\n          replacement,\n          prefix_size,\n          suffix_size - prefix_size,\n          acc + 1\n        )\n\n      _ ->\n        prepend_unless_empty(duplicate(replacement, acc), string)\n    end\n  end\n\n  defp replace_leading(string, _match, replacement, _prefix_size, _suffix_size, acc) do\n    prepend_unless_empty(duplicate(replacement, acc), string)\n  end\n\n  @doc \"\"\"\n  Replaces all trailing occurrences of `match` by `replacement` in `string`.\n\n  Returns the string untouched if there are no occurrences.\n\n  If `match` is `\"\"`, this function raises an `ArgumentError` exception: this\n  happens because this function replaces **all** the occurrences of `match` at\n  the end of `string`, and it's impossible to replace \"multiple\" occurrences of\n  `\"\"`.\n\n  ## Examples\n\n      iex> String.replace_trailing(\"hello world\", \" world\", \"\")\n      \"hello\"\n      iex> String.replace_trailing(\"hello world world\", \" world\", \"\")\n      \"hello\"\n\n      iex> String.replace_trailing(\"hello world\", \" world\", \" mundo\")\n      \"hello mundo\"\n      iex> String.replace_trailing(\"hello world world\", \" world\", \" mundo\")\n      \"hello mundo mundo\"\n\n  This function can replace across grapheme boundaries. See `replace/3`\n  for more information and examples.\n  \"\"\"\n  @spec replace_trailing(t, t, t) :: t\n  def replace_trailing(string, match, replacement)\n      when is_binary(string) and is_binary(match) and is_binary(replacement) do\n    if match == \"\" do\n      raise ArgumentError, \"cannot use an empty string as the match to replace\"\n    end\n\n    suffix_size = byte_size(match)\n    prefix_size = byte_size(string) - suffix_size\n    replace_trailing(string, match, replacement, prefix_size, suffix_size, 0)\n  end\n\n  defp replace_trailing(string, match, replacement, prefix_size, suffix_size, acc)\n       when prefix_size >= 0 do\n    case string do\n      <<prefix::size(^prefix_size)-binary, suffix::binary>> when suffix == match ->\n        replace_trailing(\n          prefix,\n          match,\n          replacement,\n          prefix_size - suffix_size,\n          suffix_size,\n          acc + 1\n        )\n\n      _ ->\n        append_unless_empty(string, duplicate(replacement, acc))\n    end\n  end\n\n  defp replace_trailing(string, _match, replacement, _prefix_size, _suffix_size, acc) do\n    append_unless_empty(string, duplicate(replacement, acc))\n  end\n\n  @doc \"\"\"\n  Replaces prefix in `string` by `replacement` if it matches `match`.\n\n  Returns the string untouched if there is no match. If `match` is an empty\n  string (`\"\"`), `replacement` is just prepended to `string`.\n\n  ## Examples\n\n      iex> String.replace_prefix(\"world\", \"hello \", \"\")\n      \"world\"\n      iex> String.replace_prefix(\"hello world\", \"hello \", \"\")\n      \"world\"\n      iex> String.replace_prefix(\"hello hello world\", \"hello \", \"\")\n      \"hello world\"\n\n      iex> String.replace_prefix(\"world\", \"hello \", \"ola \")\n      \"world\"\n      iex> String.replace_prefix(\"hello world\", \"hello \", \"ola \")\n      \"ola world\"\n      iex> String.replace_prefix(\"hello hello world\", \"hello \", \"ola \")\n      \"ola hello world\"\n\n      iex> String.replace_prefix(\"world\", \"\", \"hello \")\n      \"hello world\"\n\n  This function can replace across grapheme boundaries. See `replace/3`\n  for more information and examples.\n  \"\"\"\n  @spec replace_prefix(t, t, t) :: t\n  def replace_prefix(string, match, replacement)\n      when is_binary(string) and is_binary(match) and is_binary(replacement) do\n    prefix_size = byte_size(match)\n\n    case string do\n      <<prefix::size(^prefix_size)-binary, suffix::binary>> when prefix == match ->\n        prepend_unless_empty(replacement, suffix)\n\n      _ ->\n        string\n    end\n  end\n\n  @doc \"\"\"\n  Replaces suffix in `string` by `replacement` if it matches `match`.\n\n  Returns the string untouched if there is no match. If `match` is an empty\n  string (`\"\"`), `replacement` is just appended to `string`.\n\n  ## Examples\n\n      iex> String.replace_suffix(\"hello\", \" world\", \"\")\n      \"hello\"\n      iex> String.replace_suffix(\"hello world\", \" world\", \"\")\n      \"hello\"\n      iex> String.replace_suffix(\"hello world world\", \" world\", \"\")\n      \"hello world\"\n\n      iex> String.replace_suffix(\"hello\", \" world\", \" mundo\")\n      \"hello\"\n      iex> String.replace_suffix(\"hello world\", \" world\", \" mundo\")\n      \"hello mundo\"\n      iex> String.replace_suffix(\"hello world world\", \" world\", \" mundo\")\n      \"hello world mundo\"\n\n      iex> String.replace_suffix(\"hello\", \"\", \" world\")\n      \"hello world\"\n\n  This function can replace across grapheme boundaries. See `replace/3`\n  for more information and examples.\n  \"\"\"\n  @spec replace_suffix(t, t, t) :: t\n  def replace_suffix(string, match, replacement)\n      when is_binary(string) and is_binary(match) and is_binary(replacement) do\n    suffix_size = byte_size(match)\n    prefix_size = byte_size(string) - suffix_size\n\n    case string do\n      <<prefix::size(^prefix_size)-binary, suffix::binary>> when suffix == match ->\n        append_unless_empty(prefix, replacement)\n\n      _ ->\n        string\n    end\n  end\n\n  @compile {:inline, prepend_unless_empty: 2, append_unless_empty: 2}\n\n  defp prepend_unless_empty(\"\", suffix), do: suffix\n  defp prepend_unless_empty(prefix, suffix), do: prefix <> suffix\n\n  defp append_unless_empty(prefix, \"\"), do: prefix\n  defp append_unless_empty(prefix, suffix), do: prefix <> suffix\n\n  @doc false\n  @deprecated \"Use String.trim_leading/1 instead\"\n  defdelegate lstrip(binary), to: String.Break, as: :trim_leading\n\n  @doc false\n  @deprecated \"Use String.trim_leading/2 with a binary as second argument instead\"\n  def lstrip(string, char) when is_integer(char) do\n    replace_leading(string, <<char::utf8>>, \"\")\n  end\n\n  @doc false\n  @deprecated \"Use String.trim/1 instead\"\n  def strip(string) do\n    trim(string)\n  end\n\n  @doc false\n  @deprecated \"Use String.trim/2 with a binary second argument instead\"\n  def strip(string, char) do\n    trim(string, <<char::utf8>>)\n  end\n\n  @doc ~S\"\"\"\n  Returns a string where all leading Unicode whitespaces\n  have been removed.\n\n  ## Examples\n\n      iex> String.trim_leading(\"\\n  abc   \")\n      \"abc   \"\n\n  \"\"\"\n  @spec trim_leading(t) :: t\n  defdelegate trim_leading(string), to: String.Break\n\n  @doc \"\"\"\n  Returns a string where all leading `to_trim` characters have been removed.\n\n  ## Examples\n\n      iex> String.trim_leading(\"__ abc _\", \"_\")\n      \" abc _\"\n\n      iex> String.trim_leading(\"1 abc\", \"11\")\n      \"1 abc\"\n\n  \"\"\"\n  @spec trim_leading(t, t) :: t\n  def trim_leading(string, to_trim)\n      when is_binary(string) and is_binary(to_trim) do\n    replace_leading(string, to_trim, \"\")\n  end\n\n  @doc ~S\"\"\"\n  Returns a string where all trailing Unicode whitespaces\n  have been removed.\n\n  ## Examples\n\n      iex> String.trim_trailing(\"   abc\\n  \")\n      \"   abc\"\n\n  \"\"\"\n  @spec trim_trailing(t) :: t\n  defdelegate trim_trailing(string), to: String.Break\n\n  @doc \"\"\"\n  Returns a string where all trailing `to_trim` characters have been removed.\n\n  ## Examples\n\n      iex> String.trim_trailing(\"_ abc __\", \"_\")\n      \"_ abc \"\n\n      iex> String.trim_trailing(\"abc 1\", \"11\")\n      \"abc 1\"\n\n  \"\"\"\n  @spec trim_trailing(t, t) :: t\n  def trim_trailing(string, to_trim)\n      when is_binary(string) and is_binary(to_trim) do\n    replace_trailing(string, to_trim, \"\")\n  end\n\n  @doc ~S\"\"\"\n  Returns a string where all leading and trailing Unicode whitespaces\n  have been removed.\n\n  ## Examples\n\n      iex> String.trim(\"\\n  abc\\n  \")\n      \"abc\"\n\n  \"\"\"\n  @spec trim(t) :: t\n  def trim(string) when is_binary(string) do\n    string\n    |> trim_leading()\n    |> trim_trailing()\n  end\n\n  @doc \"\"\"\n  Returns a string where all leading and trailing `to_trim` characters have been\n  removed.\n\n  ## Examples\n\n      iex> String.trim(\"a  abc  a\", \"a\")\n      \"  abc  \"\n\n  \"\"\"\n  @spec trim(t, t) :: t\n  def trim(string, to_trim) when is_binary(string) and is_binary(to_trim) do\n    string\n    |> trim_leading(to_trim)\n    |> trim_trailing(to_trim)\n  end\n\n  @doc ~S\"\"\"\n  Returns a new string padded with a leading filler\n  which is made of elements from the `padding`.\n\n  Passing a list of strings as `padding` will take one element of the list\n  for every missing entry. If the list is shorter than the number of inserts,\n  the filling will start again from the beginning of the list.\n  Passing a string `padding` is equivalent to passing the list of graphemes in it.\n  If no `padding` is given, it defaults to whitespace.\n\n  When `count` is less than or equal to the length of `string`,\n  given `string` is returned.\n\n  Raises `ArgumentError` if the given `padding` contains a non-string element.\n\n  ## Examples\n\n      iex> String.pad_leading(\"abc\", 5)\n      \"  abc\"\n\n      iex> String.pad_leading(\"abc\", 4, \"12\")\n      \"1abc\"\n\n      iex> String.pad_leading(\"abc\", 6, \"12\")\n      \"121abc\"\n\n      iex> String.pad_leading(\"abc\", 5, [\"1\", \"23\"])\n      \"123abc\"\n\n  \"\"\"\n  @spec pad_leading(t, non_neg_integer, t | [t]) :: t\n  def pad_leading(string, count, padding \\\\ [\" \"])\n\n  def pad_leading(string, count, padding) when is_binary(padding) do\n    pad_leading(string, count, graphemes(padding))\n  end\n\n  def pad_leading(string, count, [_ | _] = padding)\n      when is_binary(string) and is_integer(count) and count >= 0 do\n    pad(:leading, string, count, padding)\n  end\n\n  @doc ~S\"\"\"\n  Returns a new string padded with a trailing filler\n  which is made of elements from the `padding`.\n\n  Passing a list of strings as `padding` will take one element of the list\n  for every missing entry. If the list is shorter than the number of inserts,\n  the filling will start again from the beginning of the list.\n  Passing a string `padding` is equivalent to passing the list of graphemes in it.\n  If no `padding` is given, it defaults to whitespace.\n\n  When `count` is less than or equal to the length of `string`,\n  given `string` is returned.\n\n  Raises `ArgumentError` if the given `padding` contains a non-string element.\n\n  ## Examples\n\n      iex> String.pad_trailing(\"abc\", 5)\n      \"abc  \"\n\n      iex> String.pad_trailing(\"abc\", 4, \"12\")\n      \"abc1\"\n\n      iex> String.pad_trailing(\"abc\", 6, \"12\")\n      \"abc121\"\n\n      iex> String.pad_trailing(\"abc\", 5, [\"1\", \"23\"])\n      \"abc123\"\n\n  \"\"\"\n  @spec pad_trailing(t, non_neg_integer, t | [t]) :: t\n  def pad_trailing(string, count, padding \\\\ [\" \"])\n\n  def pad_trailing(string, count, padding) when is_binary(padding) do\n    pad_trailing(string, count, graphemes(padding))\n  end\n\n  def pad_trailing(string, count, [_ | _] = padding)\n      when is_binary(string) and is_integer(count) and count >= 0 do\n    pad(:trailing, string, count, padding)\n  end\n\n  defp pad(kind, string, count, padding) do\n    string_length = length(string)\n\n    if string_length >= count do\n      string\n    else\n      filler = build_filler(count - string_length, padding, padding, 0, [])\n\n      case kind do\n        :leading -> [filler | string]\n        :trailing -> [string | filler]\n      end\n      |> IO.iodata_to_binary()\n    end\n  end\n\n  defp build_filler(0, _source, _padding, _size, filler), do: filler\n\n  defp build_filler(count, source, [], size, filler) do\n    rem_filler =\n      rem(count, size)\n      |> build_filler(source, source, 0, [])\n\n    filler =\n      filler\n      |> IO.iodata_to_binary()\n      |> duplicate(div(count, size) + 1)\n\n    [filler | rem_filler]\n  end\n\n  defp build_filler(count, source, [elem | rest], size, filler)\n       when is_binary(elem) do\n    build_filler(count - 1, source, rest, size + 1, [filler | elem])\n  end\n\n  defp build_filler(_count, _source, [elem | _rest], _size, _filler) do\n    raise ArgumentError, \"expected a string padding element, got: #{inspect(elem)}\"\n  end\n\n  @doc false\n  @deprecated \"Use String.pad_leading/2 instead\"\n  def rjust(subject, length) do\n    rjust(subject, length, ?\\s)\n  end\n\n  @doc false\n  @deprecated \"Use String.pad_leading/3 with a binary padding instead\"\n  def rjust(subject, length, pad) when is_integer(pad) and is_integer(length) and length >= 0 do\n    pad(:leading, subject, length, [<<pad::utf8>>])\n  end\n\n  @doc false\n  @deprecated \"Use String.pad_trailing/2 instead\"\n  def ljust(subject, length) do\n    ljust(subject, length, ?\\s)\n  end\n\n  @doc false\n  @deprecated \"Use String.pad_trailing/3 with a binary padding instead\"\n  def ljust(subject, length, pad) when is_integer(pad) and is_integer(length) and length >= 0 do\n    pad(:trailing, subject, length, [<<pad::utf8>>])\n  end\n\n  @doc ~S\"\"\"\n  Returns a new string created by replacing occurrences of `pattern` in\n  `subject` with `replacement`.\n\n  The `subject` is always a string.\n\n  The `pattern` may be a string, a list of strings, a regular expression, or a\n  compiled pattern.\n\n  The `replacement` may be a string or a function that receives the matched\n  pattern and must return the replacement as a string or iodata.\n\n  By default it replaces all occurrences but this behavior can be controlled\n  through the `:global` option; see the \"Options\" section below.\n\n  ## Options\n\n    * `:global` - (boolean) if `true`, all occurrences of `pattern` are replaced\n      with `replacement`, otherwise only the first occurrence is\n      replaced. Defaults to `true`\n\n  ## Examples\n\n      iex> String.replace(\"a,b,c\", \",\", \"-\")\n      \"a-b-c\"\n\n      iex> String.replace(\"a,b,c\", \",\", \"-\", global: false)\n      \"a-b,c\"\n\n  The pattern may also be a list of strings and the replacement may also\n  be a function that receives the matches:\n\n      iex> String.replace(\"a,b,c\", [\"a\", \"c\"], fn <<char>> -> <<char + 1>> end)\n      \"b,b,d\"\n\n  When the pattern is a regular expression, one can give `\\N` or\n  `\\g{N}` in the `replacement` string to access a specific capture in the\n  regular expression:\n\n      iex> String.replace(\"a,b,c\", ~r/,(.)/, \",\\\\1\\\\g{1}\")\n      \"a,bb,cc\"\n\n  Note that we had to escape the backslash escape character (i.e., we used `\\\\N`\n  instead of just `\\N` to escape the backslash; same thing for `\\\\g{N}`). By\n  giving `\\0`, one can inject the whole match in the replacement string.\n\n  A compiled pattern can also be given:\n\n      iex> pattern = :binary.compile_pattern(\",\")\n      iex> String.replace(\"a,b,c\", pattern, \"[]\")\n      \"a[]b[]c\"\n\n  When an empty string is provided as a `pattern`, the function will treat it as\n  an implicit empty string between each grapheme and the string will be\n  interspersed. If an empty string is provided as `replacement` the `subject`\n  will be returned:\n\n      iex> String.replace(\"ELIXIR\", \"\", \".\")\n      \".E.L.I.X.I.R.\"\n\n      iex> String.replace(\"ELIXIR\", \"\", \"\")\n      \"ELIXIR\"\n\n  Be aware that this function can replace within or across grapheme boundaries.\n  For example, take the grapheme \"é\" which is made of the characters\n  \"e\" and the acute accent. The following will replace only the letter \"e\",\n  moving the accent to the letter \"o\":\n\n      iex> String.replace(String.normalize(\"é\", :nfd), \"e\", \"o\")\n      \"ó\"\n\n  However, if \"é\" is represented by the single character \"e with acute\"\n  accent, then it won't be replaced at all:\n\n      iex> String.replace(String.normalize(\"é\", :nfc), \"e\", \"o\")\n      \"é\"\n\n  \"\"\"\n  @spec replace(t, pattern | Regex.t(), t | (t -> t | iodata), replace_opts) :: t\n  def replace(subject, pattern, replacement, options \\\\ [])\n      when is_binary(subject) and\n             (is_binary(replacement) or is_function(replacement, 1)) and\n             is_list(options) do\n    replace_guarded(subject, pattern, replacement, options)\n  end\n\n  defp replace_guarded(subject, %{__struct__: Regex} = regex, replacement, options) do\n    Regex.replace(regex, subject, replacement, options)\n  end\n\n  defp replace_guarded(subject, \"\", \"\", _) do\n    subject\n  end\n\n  defp replace_guarded(subject, [], _, _) do\n    subject\n  end\n\n  defp replace_guarded(subject, \"\", replacement_binary, options)\n       when is_binary(replacement_binary) do\n    if Keyword.get(options, :global, true) do\n      intersperse_bin(subject, replacement_binary, [replacement_binary])\n    else\n      replacement_binary <> subject\n    end\n  end\n\n  defp replace_guarded(subject, \"\", replacement_fun, options) do\n    if Keyword.get(options, :global, true) do\n      intersperse_fun(subject, replacement_fun, [replacement_fun.(\"\")])\n    else\n      IO.iodata_to_binary([replacement_fun.(\"\") | subject])\n    end\n  end\n\n  defp replace_guarded(subject, pattern, replacement, options) do\n    if insert = Keyword.get(options, :insert_replaced) do\n      IO.warn(\n        \"String.replace/4 with :insert_replaced option is deprecated. \" <>\n          \"Please use :binary.replace/4 instead or pass an anonymous function as replacement\"\n      )\n\n      binary_options = if Keyword.get(options, :global) != false, do: [:global], else: []\n      :binary.replace(subject, pattern, replacement, [insert_replaced: insert] ++ binary_options)\n    else\n      matches =\n        if Keyword.get(options, :global, true) do\n          :binary.matches(subject, pattern)\n        else\n          case :binary.match(subject, pattern) do\n            :nomatch -> []\n            match -> [match]\n          end\n        end\n\n      IO.iodata_to_binary(do_replace(subject, matches, replacement, 0))\n    end\n  end\n\n  defp intersperse_bin(subject, replacement, acc) do\n    case :unicode_util.gc(subject) do\n      [current | rest] ->\n        intersperse_bin(rest, replacement, [replacement, current | acc])\n\n      [] ->\n        reverse_characters_to_binary(acc)\n\n      {:error, <<byte, rest::bits>>} ->\n        reverse_characters_to_binary(acc) <>\n          <<byte>> <> intersperse_bin(rest, replacement, [replacement])\n    end\n  end\n\n  defp intersperse_fun(subject, replacement, acc) do\n    case :unicode_util.gc(subject) do\n      [current | rest] ->\n        intersperse_fun(rest, replacement, [replacement.(\"\"), current | acc])\n\n      [] ->\n        reverse_characters_to_binary(acc)\n\n      {:error, <<byte, rest::bits>>} ->\n        reverse_characters_to_binary(acc) <>\n          <<byte>> <> intersperse_fun(rest, replacement, [replacement.(\"\")])\n    end\n  end\n\n  defp do_replace(subject, [], _, n) do\n    [binary_part(subject, n, byte_size(subject) - n)]\n  end\n\n  defp do_replace(subject, [{start, length} | matches], replacement, n) do\n    prefix = binary_part(subject, n, start - n)\n\n    middle =\n      if is_binary(replacement) do\n        replacement\n      else\n        replacement.(binary_part(subject, start, length))\n      end\n\n    [prefix, middle | do_replace(subject, matches, replacement, start + length)]\n  end\n\n  @doc ~S\"\"\"\n  Reverses the graphemes in given string.\n\n  ## Examples\n\n      iex> String.reverse(\"abcd\")\n      \"dcba\"\n\n      iex> String.reverse(\"hello world\")\n      \"dlrow olleh\"\n\n      iex> String.reverse(\"hello ∂og\")\n      \"go∂ olleh\"\n\n  Keep in mind reversing the same string twice does\n  not necessarily yield the original string:\n\n      iex> \"̀e\"\n      \"̀e\"\n      iex> String.reverse(\"̀e\")\n      \"è\"\n      iex> String.reverse(String.reverse(\"̀e\"))\n      \"è\"\n\n  In the first example the accent is before the vowel, so\n  it is considered two graphemes. However, when you reverse\n  it once, you have the vowel followed by the accent, which\n  becomes one grapheme. Reversing it again will keep it as\n  one single grapheme.\n  \"\"\"\n  @spec reverse(t) :: t\n  def reverse(string) when is_binary(string) do\n    do_reverse(:unicode_util.gc(string), [])\n  end\n\n  defp do_reverse([grapheme | rest], acc),\n    do: do_reverse(:unicode_util.gc(rest), [grapheme | acc])\n\n  defp do_reverse([], acc),\n    do: :unicode.characters_to_binary(acc)\n\n  defp do_reverse({:error, <<byte, rest::bits>>}, acc),\n    do: :unicode.characters_to_binary(acc) <> <<byte>> <> do_reverse(:unicode_util.gc(rest), [])\n\n  @doc \"\"\"\n  Returns a string `subject` repeated `n` times.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> String.duplicate(\"abc\", 0)\n      \"\"\n\n      iex> String.duplicate(\"abc\", 1)\n      \"abc\"\n\n      iex> String.duplicate(\"abc\", 2)\n      \"abcabc\"\n\n  \"\"\"\n  @compile {:inline, duplicate: 2}\n  @spec duplicate(t, non_neg_integer) :: t\n  def duplicate(subject, n) when is_binary(subject) and is_integer(n) and n >= 0 do\n    :binary.copy(subject, n)\n  end\n\n  @doc ~S\"\"\"\n  Returns a list of code points encoded as strings.\n\n  To retrieve code points in their natural integer\n  representation, see `to_charlist/1`. For details about\n  code points and graphemes, see the `String` module\n  documentation.\n\n  ## Examples\n\n      iex> String.codepoints(\"olá\")\n      [\"o\", \"l\", \"á\"]\n\n      iex> String.codepoints(\"оптимі зації\")\n      [\"о\", \"п\", \"т\", \"и\", \"м\", \"і\", \" \", \"з\", \"а\", \"ц\", \"і\", \"ї\"]\n\n      iex> String.codepoints(\"ἅἪῼ\")\n      [\"ἅ\", \"Ἢ\", \"ῼ\"]\n\n      iex> String.codepoints(\"\\u00e9\")\n      [\"é\"]\n\n      iex> String.codepoints(\"\\u0065\\u0301\")\n      [\"e\", \"́\"]\n\n  \"\"\"\n  @spec codepoints(t) :: [codepoint]\n  def codepoints(string) when is_binary(string) do\n    do_codepoints(string)\n  end\n\n  defp do_codepoints(<<codepoint::utf8, rest::bits>>) do\n    [<<codepoint::utf8>> | do_codepoints(rest)]\n  end\n\n  defp do_codepoints(<<byte, rest::bits>>) do\n    [<<byte>> | do_codepoints(rest)]\n  end\n\n  defp do_codepoints(<<>>), do: []\n\n  @doc ~S\"\"\"\n  Returns the next code point in a string.\n\n  The result is a tuple with the code point and the\n  remainder of the string or `nil` in case\n  the string reached its end.\n\n  As with other functions in the `String` module, `next_codepoint/1`\n  works with binaries that are invalid UTF-8. If the string starts\n  with a sequence of bytes that is not valid in UTF-8 encoding, the\n  first element of the returned tuple is a binary with the first byte.\n\n  ## Examples\n\n      iex> String.next_codepoint(\"olá\")\n      {\"o\", \"lá\"}\n\n      iex> invalid = \"\\x80\\x80OK\" # first two bytes are invalid in UTF-8\n      iex> {_, rest} = String.next_codepoint(invalid)\n      {<<128>>, <<128, 79, 75>>}\n      iex> String.next_codepoint(rest)\n      {<<128>>, \"OK\"}\n\n  ## Comparison with binary pattern matching\n\n  Binary pattern matching provides a similar way to decompose\n  a string:\n\n      iex> <<codepoint::utf8, rest::binary>> = \"Elixir\"\n      \"Elixir\"\n      iex> codepoint\n      69\n      iex> rest\n      \"lixir\"\n\n  though not entirely equivalent because `codepoint` comes as\n  an integer, and the pattern won't match invalid UTF-8.\n\n  Binary pattern matching, however, is simpler and more efficient,\n  so pick the option that better suits your use case.\n  \"\"\"\n  @spec next_codepoint(t) :: {codepoint, t} | nil\n  def next_codepoint(<<cp::utf8, rest::binary>>), do: {<<cp::utf8>>, rest}\n  def next_codepoint(<<byte, rest::binary>>), do: {<<byte>>, rest}\n  def next_codepoint(<<>>), do: nil\n\n  @doc ~S\"\"\"\n  Checks whether `string` contains only valid characters.\n\n  `algorithm` may be `:default` or `:fast_ascii`. Both algorithms are equivalent\n  from a validation perspective (they will always produce the same output), but\n  `:fast_ascii` can yield significant performance benefits in specific scenarios.\n\n  If anything else but a string is given as argument, it raises.\n\n  ## Fast ASCII\n\n  If all of the following conditions are true, you may want to experiment with\n  the `:fast_ascii` algorithm to see if it yields performance benefits in your\n  specific scenario:\n\n  * You expect most of your strings to be longer than ~64 bytes\n  * You expect most of your strings to contain mostly ASCII codepoints\n\n  Note that the `:fast_ascii` algorithm does not affect correctness, you can\n  expect the output of `String.valid?/2` to be the same regardless of algorithm.\n  The only difference to be expected is one of performance, which can be\n  expected to improve roughly linearly in string length compared to the\n  `:default` algorithm.\n\n  ## Examples\n\n      iex> String.valid?(\"a\")\n      true\n\n      iex> String.valid?(\"ø\")\n      true\n\n      iex> String.valid?(<<0xFFFF::16>>)\n      false\n\n      iex> String.valid?(<<0xEF, 0xB7, 0x90>>)\n      true\n\n      iex> String.valid?(\"asd\" <> <<0xFFFF::16>>)\n      false\n\n      iex> String.valid?(\"a\", :fast_ascii)\n      true\n\n  \"\"\"\n  @spec valid?(t, :default | :fast_ascii) :: boolean\n  def valid?(string, algorithm \\\\ :default)\n\n  def valid?(<<string::binary>>, :default), do: valid_utf8?(string)\n  def valid?(<<string::binary>>, :fast_ascii), do: valid_utf8_fast_ascii?(string)\n\n  defp valid_utf8?(<<_::utf8, rest::bits>>), do: valid_utf8?(rest)\n  defp valid_utf8?(<<>>), do: true\n  defp valid_utf8?(_), do: false\n\n  defp valid_utf8_fast_ascii?(<<a::56, rest::bits>>)\n       when Bitwise.band(0x80808080808080, a) == 0 do\n    valid_utf8_fast_ascii?(rest)\n  end\n\n  defp valid_utf8_fast_ascii?(<<_::utf8, rest::bits>>), do: valid_utf8_fast_ascii?(rest)\n  defp valid_utf8_fast_ascii?(<<>>), do: true\n  defp valid_utf8_fast_ascii?(_), do: false\n\n  @doc false\n  @deprecated \"Use String.valid?/1 instead\"\n  def valid_character?(string) do\n    case string do\n      <<_::utf8>> -> valid?(string)\n      _ -> false\n    end\n  end\n\n  defguardp replace_invalid_ii_of_iii(i, ii)\n            when Bitwise.bor(Bitwise.bsl(i, 6), ii) in 32..863 or\n                   Bitwise.bor(Bitwise.bsl(i, 6), ii) in 896..1023\n\n  defguardp replace_invalid_ii_of_iv(i, ii)\n            when Bitwise.bor(Bitwise.bsl(i, 6), ii) in 16..271\n\n  defguardp replace_invalid_iii_of_iv(i, ii, iii)\n            when Bitwise.bor(Bitwise.bor(Bitwise.bsl(i, 12), Bitwise.bsl(ii, 6)), iii) in 1024..17407\n\n  defguardp replace_invalid_is_next(next) when Bitwise.bsr(next, 6) !== 0b10\n\n  @doc ~S\"\"\"\n  Returns a new string created by replacing all invalid bytes with `replacement` (`\"�\"` by default).\n\n  ## Examples\n\n      iex> String.replace_invalid(\"asd\" <> <<0xFF::8>>)\n      \"asd�\"\n\n      iex> String.replace_invalid(\"nem rán bề bề\")\n      \"nem rán bề bề\"\n\n      iex> String.replace_invalid(\"nem rán b\" <> <<225, 187>> <> \" bề\")\n      \"nem rán b� bề\"\n\n      iex> String.replace_invalid(\"nem rán b\" <> <<225, 187>> <> \" bề\", \"ERROR!\")\n      \"nem rán bERROR! bề\"\n  \"\"\"\n  @doc since: \"1.16.0\"\n  @spec replace_invalid(binary, t) :: t\n  def replace_invalid(bytes, replacement \\\\ \"�\")\n      when is_binary(bytes) and is_binary(replacement) do\n    do_replace_invalid(bytes, replacement, <<>>)\n  end\n\n  # Valid ASCII (for better average speed)\n  defp do_replace_invalid(<<ascii::8, next::8, _::binary>> = rest, rep, acc)\n       when ascii in 0..127 and replace_invalid_is_next(next) do\n    <<_::8, rest::binary>> = rest\n    do_replace_invalid(rest, rep, acc <> <<ascii::8>>)\n  end\n\n  # Valid UTF-8\n  defp do_replace_invalid(<<grapheme::utf8, rest::binary>>, rep, acc) do\n    do_replace_invalid(rest, rep, acc <> <<grapheme::utf8>>)\n  end\n\n  # 2/3 truncated sequence\n  defp do_replace_invalid(<<0b1110::4, i::4, 0b10::2, ii::6>>, rep, acc)\n       when replace_invalid_ii_of_iii(i, ii) do\n    acc <> rep\n  end\n\n  defp do_replace_invalid(\n         <<0b1110::4, i::4, 0b10::2, ii::6, next::8, _::binary>> = rest,\n         rep,\n         acc\n       )\n       when replace_invalid_ii_of_iii(i, ii) and replace_invalid_is_next(next) do\n    <<_::16, rest::binary>> = rest\n    do_replace_invalid(rest, rep, acc <> rep)\n  end\n\n  # 2/4\n  defp do_replace_invalid(<<0b11110::5, i::3, 0b10::2, ii::6>>, rep, acc)\n       when replace_invalid_ii_of_iv(i, ii) do\n    acc <> rep\n  end\n\n  defp do_replace_invalid(\n         <<0b11110::5, i::3, 0b10::2, ii::6, next::8, _::binary>> = rest,\n         rep,\n         acc\n       )\n       when replace_invalid_ii_of_iv(i, ii) and replace_invalid_is_next(next) do\n    <<_::16, rest::binary>> = rest\n    do_replace_invalid(rest, rep, acc <> rep)\n  end\n\n  # 3/4\n  defp do_replace_invalid(<<0b11110::5, i::3, 0b10::2, ii::6, 0b10::2, iii::6>>, rep, acc)\n       when replace_invalid_iii_of_iv(i, ii, iii) do\n    acc <> rep\n  end\n\n  defp do_replace_invalid(\n         <<0b11110::5, i::3, 0b10::2, ii::6, 0b10::2, iii::6, next::8, _::binary>> = rest,\n         rep,\n         acc\n       )\n       when replace_invalid_iii_of_iv(i, ii, iii) and replace_invalid_is_next(next) do\n    <<_::24, rest::binary>> = rest\n    do_replace_invalid(rest, rep, acc <> rep)\n  end\n\n  # Everything else\n  defp do_replace_invalid(<<_, rest::binary>>, rep, acc),\n    do: do_replace_invalid(rest, rep, acc <> rep)\n\n  # Final\n  defp do_replace_invalid(<<>>, _, acc), do: acc\n\n  @doc ~S\"\"\"\n  Splits the string into chunks of characters that share a common trait.\n\n  The trait can be one of two options:\n\n    * `:valid` - the string is split into chunks of valid and invalid\n      character sequences\n\n    * `:printable` - the string is split into chunks of printable and\n      non-printable character sequences\n\n  Returns a list of binaries each of which contains only one kind of\n  characters.\n\n  If the given string is empty, an empty list is returned.\n\n  ## Examples\n\n      iex> String.chunk(<<?a, ?b, ?c, 0>>, :valid)\n      [<<97, 98, 99, 0>>]\n\n      iex> String.chunk(<<?a, ?b, ?c, 0, 0xFFFF::utf16>>, :valid)\n      [<<97, 98, 99, 0>>, <<255, 255>>]\n\n      iex> String.chunk(<<?a, ?b, ?c, 0, 0x0FFFF::utf8>>, :printable)\n      [\"abc\", <<0, 239, 191, 191>>]\n\n  \"\"\"\n  @spec chunk(t, :valid | :printable) :: [t]\n\n  def chunk(string, trait)\n\n  def chunk(\"\", _), do: []\n\n  def chunk(string, trait) when is_binary(string) and trait in [:valid, :printable] do\n    {cp, _} = next_codepoint(string)\n    pred_fn = make_chunk_pred(trait)\n    do_chunk(string, pred_fn.(cp), pred_fn)\n  end\n\n  defp do_chunk(string, flag, pred_fn), do: do_chunk(string, [], <<>>, flag, pred_fn)\n\n  defp do_chunk(<<>>, acc, <<>>, _, _), do: Enum.reverse(acc)\n\n  defp do_chunk(<<>>, acc, chunk, _, _), do: Enum.reverse(acc, [chunk])\n\n  defp do_chunk(string, acc, chunk, flag, pred_fn) do\n    {cp, rest} = next_codepoint(string)\n\n    if pred_fn.(cp) != flag do\n      do_chunk(rest, [chunk | acc], cp, not flag, pred_fn)\n    else\n      do_chunk(rest, acc, chunk <> cp, flag, pred_fn)\n    end\n  end\n\n  defp make_chunk_pred(:valid), do: &valid?/1\n  defp make_chunk_pred(:printable), do: &printable?/1\n\n  @doc ~S\"\"\"\n  Returns Unicode graphemes in the string as per Extended Grapheme\n  Cluster algorithm.\n\n  The algorithm is outlined in the [Unicode Standard Annex #29,\n  Unicode Text Segmentation](https://www.unicode.org/reports/tr29/).\n\n  For details about code points and graphemes, see the `String` module documentation.\n\n  ## Examples\n\n      iex> String.graphemes(\"Ńaïve\")\n      [\"Ń\", \"a\", \"ï\", \"v\", \"e\"]\n\n      iex> String.graphemes(\"\\u00e9\")\n      [\"é\"]\n\n      iex> String.graphemes(\"\\u0065\\u0301\")\n      [\"é\"]\n\n  \"\"\"\n  @compile {:inline, graphemes: 1}\n  @spec graphemes(t) :: [grapheme]\n  def graphemes(string) when is_binary(string), do: do_graphemes(string)\n\n  defp do_graphemes(gcs) do\n    case :unicode_util.gc(gcs) do\n      [gc | rest] -> [grapheme_to_binary(gc) | do_graphemes(rest)]\n      [] -> []\n      {:error, <<byte, rest::bits>>} -> [<<byte>> | do_graphemes(rest)]\n    end\n  end\n\n  @doc \"\"\"\n  Returns the next grapheme in a string.\n\n  The result is a tuple with the grapheme and the\n  remainder of the string or `nil` in case\n  the String reached its end.\n\n  ## Examples\n\n      iex> String.next_grapheme(\"olá\")\n      {\"o\", \"lá\"}\n\n      iex> String.next_grapheme(\"\")\n      nil\n\n  \"\"\"\n  @compile {:inline, next_grapheme: 1}\n  @spec next_grapheme(t) :: {grapheme, t} | nil\n  def next_grapheme(string) when is_binary(string) do\n    case :unicode_util.gc(string) do\n      [gc] -> {grapheme_to_binary(gc), <<>>}\n      [gc, rest] -> {grapheme_to_binary(gc), rest}\n      [gc | rest] -> {grapheme_to_binary(gc), rest}\n      [] -> nil\n      {:error, <<byte, rest::bits>>} -> {<<byte>>, rest}\n    end\n  end\n\n  @doc \"\"\"\n  Returns the size (in bytes) of the next grapheme.\n\n  The result is a tuple with the next grapheme size in bytes and\n  the remainder of the string or `nil` in case the string\n  reached its end.\n\n  ## Examples\n\n      iex> String.next_grapheme_size(\"olá\")\n      {1, \"lá\"}\n\n      iex> String.next_grapheme_size(\"\")\n      nil\n\n  \"\"\"\n  @spec next_grapheme_size(t) :: {pos_integer, t} | nil\n  def next_grapheme_size(string) when is_binary(string) do\n    case :unicode_util.gc(string) do\n      [gc] -> {grapheme_byte_size(gc), <<>>}\n      [gc, rest] -> {grapheme_byte_size(gc), rest}\n      [gc | rest] -> {grapheme_byte_size(gc), rest}\n      [] -> nil\n      {:error, <<_, rest::bits>>} -> {1, rest}\n    end\n  end\n\n  @doc \"\"\"\n  Returns the first grapheme from a UTF-8 string,\n  `nil` if the string is empty.\n\n  ## Examples\n\n      iex> String.first(\"elixir\")\n      \"e\"\n\n      iex> String.first(\"եոգլի\")\n      \"ե\"\n\n      iex> String.first(\"\")\n      nil\n\n  \"\"\"\n  @spec first(t) :: grapheme | nil\n  def first(string) when is_binary(string) do\n    case :unicode_util.gc(string) do\n      [gc | _] -> grapheme_to_binary(gc)\n      [] -> nil\n      {:error, <<byte, _::bits>>} -> <<byte>>\n    end\n  end\n\n  @doc \"\"\"\n  Returns the last grapheme from a UTF-8 string,\n  `nil` if the string is empty.\n\n  It traverses the whole string to find its last grapheme.\n\n  ## Examples\n\n      iex> String.last(\"\")\n      nil\n\n      iex> String.last(\"elixir\")\n      \"r\"\n\n      iex> String.last(\"եոգլի\")\n      \"ի\"\n\n  \"\"\"\n  @spec last(t) :: grapheme | nil\n  def last(\"\"), do: nil\n  def last(string) when is_binary(string), do: do_last(:unicode_util.gc(string), nil)\n\n  defp do_last([gc | rest], _), do: do_last(:unicode_util.gc(rest), gc)\n  defp do_last([], acc) when is_binary(acc), do: acc\n  defp do_last([], acc), do: :unicode.characters_to_binary([acc])\n  defp do_last({:error, <<byte, rest::bits>>}, _), do: do_last(:unicode_util.gc(rest), <<byte>>)\n\n  @doc \"\"\"\n  Returns the number of Unicode graphemes in a UTF-8 string.\n\n  ## Examples\n\n      iex> String.length(\"elixir\")\n      6\n\n      iex> String.length(\"եոգլի\")\n      5\n\n  \"\"\"\n  @spec length(t) :: non_neg_integer\n  def length(string) when is_binary(string), do: length(string, 0)\n\n  defp length(<<byte1, byte2, rest::binary>> = binary, acc)\n       when byte1 <= 127 and byte1 != ?\\r and byte2 <= 127 and byte2 != ?\\r do\n    skip = skip_length(rest, 1)\n    length(binary_part(binary, skip, byte_size(binary) - skip), acc + skip)\n  end\n\n  defp length(gcs, acc) do\n    case :unicode_util.gc(gcs) do\n      [_ | rest] -> length(rest, acc + 1)\n      [] -> acc\n      {:error, <<_, rest::bits>>} -> length(rest, acc + 1)\n    end\n  end\n\n  defp skip_length(<<byte, rest::binary>>, acc)\n       when byte <= 127 and byte != ?\\r,\n       do: skip_length(rest, acc + 1)\n\n  defp skip_length(_binary, acc),\n    do: acc\n\n  @doc \"\"\"\n  Returns the grapheme at the `position` of the given UTF-8 `string`.\n  If `position` is greater than `string` length, then it returns `nil`.\n\n  > #### Linear Access {: .warning}\n  >\n  > This function has to linearly traverse the string.\n  > If you want to access a string or a binary in constant time based on the\n  > number of bytes, use `Kernel.binary_slice/3` or `:binary.at/2` instead.\n\n  ## Examples\n\n      iex> String.at(\"elixir\", 0)\n      \"e\"\n\n      iex> String.at(\"elixir\", 1)\n      \"l\"\n\n      iex> String.at(\"elixir\", 10)\n      nil\n\n      iex> String.at(\"elixir\", -1)\n      \"r\"\n\n      iex> String.at(\"elixir\", -10)\n      nil\n\n  \"\"\"\n  @spec at(t, integer) :: grapheme | nil\n\n  def at(string, position) when is_binary(string) and is_integer(position) and position >= 0 do\n    do_at(string, position)\n  end\n\n  def at(string, position) when is_binary(string) and is_integer(position) and position < 0 do\n    position = length(string) + position\n\n    case position >= 0 do\n      true -> do_at(string, position)\n      false -> nil\n    end\n  end\n\n  defp do_at(string, position) do\n    left = byte_size_remaining_at(string, position)\n\n    string\n    |> binary_part(byte_size(string) - left, left)\n    |> first()\n  end\n\n  @doc \"\"\"\n  Returns a substring starting at the offset `start`, and of the given `length`.\n\n  This function works on Unicode graphemes. For example, slicing the first\n  three characters of the string \"héllo\" will return \"hél\", which internally\n  is represented by more than three bytes. Use `String.byte_slice/3` if you\n  want to slice by a given number of bytes, while respecting the codepoint\n  boundaries. If you want to work on raw bytes, check `Kernel.binary_part/3`\n  or `Kernel.binary_slice/3` instead.\n\n  If the offset is greater than string length, then it returns `\"\"`.\n\n  ## Examples\n\n      iex> String.slice(\"elixir\", 1, 3)\n      \"lix\"\n\n      iex> String.slice(\"elixir\", 1, 10)\n      \"lixir\"\n\n      iex> String.slice(\"elixir\", 10, 3)\n      \"\"\n\n  If the start position is negative, it is normalized\n  against the string length and clamped to 0:\n\n      iex> String.slice(\"elixir\", -4, 4)\n      \"ixir\"\n\n      iex> String.slice(\"elixir\", -10, 3)\n      \"eli\"\n\n  If start is more than the string length, an empty\n  string is returned:\n\n      iex> String.slice(\"elixir\", 10, 1500)\n      \"\"\n\n  \"\"\"\n  @spec slice(t, integer, non_neg_integer) :: grapheme\n\n  def slice(_, _, 0) do\n    \"\"\n  end\n\n  def slice(string, start, length)\n      when is_binary(string) and is_integer(start) and is_integer(length) and start >= 0 and\n             length >= 0 do\n    do_slice(string, start, length)\n  end\n\n  def slice(string, start, length)\n      when is_binary(string) and is_integer(start) and is_integer(length) and start < 0 and\n             length >= 0 do\n    start = max(length(string) + start, 0)\n    do_slice(string, start, length)\n  end\n\n  defp do_slice(string, start, length) do\n    from_start = byte_size_remaining_at(string, start)\n    rest = binary_part(string, byte_size(string) - from_start, from_start)\n\n    from_end = byte_size_remaining_at(rest, length)\n    binary_part(rest, 0, from_start - from_end)\n  end\n\n  @doc \"\"\"\n  Returns a substring from the offset given by the start of the\n  range to the offset given by the end of the range.\n\n  This function works on Unicode graphemes. For example, slicing the first\n  three characters of the string \"héllo\" will return \"hél\", which internally\n  is represented by more than three bytes. Use `String.byte_slice/3` if you\n  want to slice by a given number of bytes, while respecting the codepoint\n  boundaries. If you want to work on raw bytes, check `Kernel.binary_part/3`\n  or `Kernel.binary_slice/3` instead.\n\n  If the start of the range is not a valid offset for the given\n  string or if the range is in reverse order, returns `\"\"`.\n\n  If the start or end of the range is negative, the whole string\n  is traversed first in order to convert the negative indices into\n  positive ones.\n\n  ## Examples\n\n      iex> String.slice(\"elixir\", 1..3)\n      \"lix\"\n      iex> String.slice(\"elixir\", 1..10)\n      \"lixir\"\n\n      iex> String.slice(\"elixir\", -4..-1)\n      \"ixir\"\n      iex> String.slice(\"elixir\", -4..6)\n      \"ixir\"\n      iex> String.slice(\"elixir\", -100..100)\n      \"elixir\"\n\n  For ranges where `start > stop`, you need to explicitly\n  mark them as increasing:\n\n      iex> String.slice(\"elixir\", 2..-1//1)\n      \"ixir\"\n      iex> String.slice(\"elixir\", 1..-2//1)\n      \"lixi\"\n\n  You can use `../0` as a shortcut for `0..-1//1`, which returns\n  the whole string as is:\n\n      iex> String.slice(\"elixir\", ..)\n      \"elixir\"\n\n  The step can be any positive number. For example, to\n  get every 2 characters of the string:\n\n      iex> String.slice(\"elixir\", 0..-1//2)\n      \"eii\"\n\n  If the first position is after the string ends or after\n  the last position of the range, it returns an empty string:\n\n      iex> String.slice(\"elixir\", 10..3//1)\n      \"\"\n      iex> String.slice(\"a\", 1..1500)\n      \"\"\n\n  \"\"\"\n  @spec slice(t, Range.t()) :: t\n  def slice(string, first..last//step = range) when is_binary(string) do\n    # TODO: Support negative steps as a reverse on Elixir v2.0.\n    cond do\n      step > 0 ->\n        slice_range(string, first, last, step)\n\n      step == -1 and first > last ->\n        IO.warn(\n          \"negative steps are not supported in String.slice/2, pass #{first}..#{last}//1 instead\"\n        )\n\n        slice_range(string, first, last, 1)\n\n      true ->\n        raise ArgumentError,\n              \"String.slice/2 does not accept ranges with negative steps, got: #{inspect(range)}\"\n    end\n  end\n\n  # TODO: Remove me on v2.0\n  def slice(string, %{__struct__: Range, first: first, last: last} = range)\n      when is_binary(string) do\n    step = if first <= last, do: 1, else: -1\n    slice(string, Map.put(range, :step, step))\n  end\n\n  defp slice_range(\"\", _, _, _), do: \"\"\n\n  defp slice_range(_string, first, last, _step) when first >= 0 and last >= 0 and first > last do\n    \"\"\n  end\n\n  defp slice_range(string, first, last, step) when first >= 0 do\n    from_start = byte_size_remaining_at(string, first)\n    rest = binary_part(string, byte_size(string) - from_start, from_start)\n\n    cond do\n      last == -1 ->\n        slice_every(rest, byte_size(rest), step)\n\n      last >= 0 and step == 1 ->\n        from_end = byte_size_remaining_at(rest, last - first + 1)\n        binary_part(rest, 0, from_start - from_end)\n\n      last >= 0 ->\n        slice_every(rest, last - first + 1, step)\n\n      true ->\n        rest\n        |> slice_range_negative(0, last)\n        |> slice_every(byte_size(string), step)\n    end\n  end\n\n  defp slice_range(string, first, last, step) do\n    string\n    |> slice_range_negative(first, last)\n    |> slice_every(byte_size(string), step)\n  end\n\n  defp slice_range_negative(string, first, last) do\n    {reversed_bytes, length} = acc_bytes(string, [], 0)\n    first = add_if_negative(first, length) |> max(0)\n    last = add_if_negative(last, length)\n\n    if first > last or first > length do\n      \"\"\n    else\n      last = min(last + 1, length)\n      reversed_bytes = Enum.drop(reversed_bytes, length - last)\n      {length_bytes, start_bytes} = split_bytes(reversed_bytes, 0, last - first)\n      binary_part(string, start_bytes, length_bytes)\n    end\n  end\n\n  defp slice_every(string, _count, 1), do: string\n  defp slice_every(string, count, step), do: slice_every(string, count, step, [])\n\n  defp slice_every(string, count, to_drop, acc) when count > 0 do\n    case :unicode_util.gc(string) do\n      [current | rest] ->\n        rest\n        |> drop(to_drop)\n        |> slice_every(count - to_drop, to_drop, [current | acc])\n\n      [] ->\n        reverse_characters_to_binary(acc)\n\n      {:error, <<byte, rest::bits>>} ->\n        reverse_characters_to_binary(acc) <>\n          <<byte>> <> slice_every(drop(rest, to_drop), count - to_drop, to_drop, [])\n    end\n  end\n\n  defp slice_every(_string, _count, _to_drop, acc) do\n    reverse_characters_to_binary(acc)\n  end\n\n  defp drop(string, 1), do: string\n\n  defp drop(string, count) do\n    case :unicode_util.gc(string) do\n      [_ | rest] -> drop(rest, count - 1)\n      [] -> \"\"\n      {:error, <<_, rest::bits>>} -> drop(rest, count - 1)\n    end\n  end\n\n  defp acc_bytes(string, bytes, length) do\n    case :unicode_util.gc(string) do\n      [gc | rest] -> acc_bytes(rest, [grapheme_byte_size(gc) | bytes], length + 1)\n      [] -> {bytes, length}\n      {:error, <<_, rest::bits>>} -> acc_bytes(rest, [1 | bytes], length + 1)\n    end\n  end\n\n  defp add_if_negative(value, to_add) when value < 0, do: value + to_add\n  defp add_if_negative(value, _to_add), do: value\n\n  defp split_bytes(rest, acc, 0), do: {acc, Enum.sum(rest)}\n  defp split_bytes([], acc, _), do: {acc, 0}\n  defp split_bytes([head | tail], acc, count), do: split_bytes(tail, head + acc, count - 1)\n\n  @doc \"\"\"\n  Returns a substring starting at (or after) `start_bytes` and of at most\n  the given `size_bytes`.\n\n  This function works on bytes and then adjusts the string to eliminate\n  truncated codepoints. This is useful when you have a string and you need\n  to guarantee it does not exceed a certain amount of bytes.\n\n  If the offset is greater than the number of bytes in the string, then it\n  returns `\"\"`. Similar to `String.slice/2`, a negative `start_bytes`\n  will be adjusted to the end of the string (but in bytes).\n\n  This function does not guarantee the string won't have invalid codepoints,\n  it only guarantees to remove truncated codepoints immediately at the beginning\n  or the end of the slice.\n\n  ## Examples\n\n  Consider the string \"héllo\". Let's see its representation:\n\n      iex> inspect(\"héllo\", binaries: :as_binaries)\n      \"<<104, 195, 169, 108, 108, 111>>\"\n\n  Although the string has 5 characters, it is made of 6 bytes. Now imagine\n  we want to get only the first two bytes. To do so, let's use `binary_slice/3`,\n  which is unaware of codepoints:\n\n      iex> binary_slice(\"héllo\", 0, 2)\n      <<104, 195>>\n\n  As you can see, this operation is unsafe and returns an invalid string.\n  That's because we cut the string in the middle of the bytes representing\n  \"é\". On the other hand, we could use `String.slice/3`:\n\n      iex> String.slice(\"héllo\", 0, 2)\n      \"hé\"\n\n  While the above is correct, it has 3 bytes. If you have a requirement where\n  you need *at most* 2 bytes, the result would also be invalid. In such scenarios,\n  you can use this function, which will slice the given bytes, but clean up\n  the truncated codepoints:\n\n      iex> String.byte_slice(\"héllo\", 0, 2)\n      \"h\"\n\n  Truncated codepoints at the beginning are also cleaned up:\n\n      iex> String.byte_slice(\"héllo\", 2, 3)\n      \"llo\"\n\n  Note that, if you want to work on raw bytes, then you must use `binary_slice/3`\n  instead.\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec byte_slice(t, integer, non_neg_integer) :: t\n  def byte_slice(string, start_bytes, size_bytes)\n      when is_binary(string) and is_integer(start_bytes) and is_integer(size_bytes) and\n             size_bytes >= 0 do\n    total = byte_size(string)\n    start_bytes = if start_bytes < 0, do: max(total + start_bytes, 0), else: start_bytes\n\n    if start_bytes < total do\n      :erlang.binary_part(string, start_bytes, total - start_bytes)\n      |> invalid_prefix()\n      |> invalid_suffix(size_bytes)\n    else\n      \"\"\n    end\n  end\n\n  defp invalid_prefix(<<0b10::2, _::6, rest::binary>>), do: invalid_prefix(rest)\n  defp invalid_prefix(rest), do: rest\n\n  defp invalid_suffix(string, size) do\n    last = invalid_suffix(string, min(size, byte_size(string)) - 1, 0)\n    :erlang.binary_part(string, 0, last)\n  end\n\n  defp invalid_suffix(string, last, truncated) when last >= 0 do\n    byte = :binary.at(string, last)\n\n    cond do\n      # ASCII byte, discard all truncated entries\n      byte <= 127 ->\n        last + 1\n\n      # In the middle of a codepoint\n      byte <= 191 ->\n        invalid_suffix(string, last - 1, truncated + 1)\n\n      # 2 bytes codepoint start\n      byte <= 223 ->\n        if truncated == 1, do: last + truncated + 1, else: last\n\n      # 3 bytes codepoint start\n      byte <= 239 ->\n        if truncated == 2, do: last + truncated + 1, else: last\n\n      # 4 bytes codepoint start\n      byte <= 247 ->\n        if truncated == 3, do: last + truncated + 1, else: last\n\n      # Invalid codepoint, discard it, stop checking\n      true ->\n        last + 1\n    end\n  end\n\n  defp invalid_suffix(_string, _last, _truncated), do: 0\n\n  @doc \"\"\"\n  Returns `true` if `string` starts with any of the prefixes given.\n\n  `prefix` can be either a string, a list of strings, or a compiled\n  pattern.\n\n  ## Examples\n\n      iex> String.starts_with?(\"elixir\", \"eli\")\n      true\n      iex> String.starts_with?(\"elixir\", [\"erlang\", \"elixir\"])\n      true\n      iex> String.starts_with?(\"elixir\", [\"erlang\", \"ruby\"])\n      false\n\n  An empty string will always match:\n\n      iex> String.starts_with?(\"elixir\", \"\")\n      true\n      iex> String.starts_with?(\"elixir\", [\"\", \"other\"])\n      true\n\n  An empty list will never match:\n\n      iex> String.starts_with?(\"elixir\", [])\n      false\n\n      iex> String.starts_with?(\"\", [])\n      false\n\n  \"\"\"\n  @spec starts_with?(t, t | [t]) :: boolean\n  def starts_with?(string, prefix) when is_binary(string) and is_binary(prefix) do\n    starts_with_string?(string, byte_size(string), prefix)\n  end\n\n  def starts_with?(string, prefix) when is_binary(string) and is_list(prefix) do\n    string_size = byte_size(string)\n    Enum.any?(prefix, &starts_with_string?(string, string_size, &1))\n  end\n\n  def starts_with?(string, prefix) when is_binary(string) do\n    IO.warn(\"compiled patterns are deprecated in starts_with?\")\n    Kernel.match?({0, _}, :binary.match(string, prefix))\n  end\n\n  @compile {:inline, starts_with_string?: 3}\n  defp starts_with_string?(string, string_size, prefix) when is_binary(prefix) do\n    prefix_size = byte_size(prefix)\n\n    if prefix_size <= string_size do\n      prefix == binary_part(string, 0, prefix_size)\n    else\n      false\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if `string` ends with any of the suffixes given.\n\n  `suffixes` can be either a single suffix or a list of suffixes.\n\n  ## Examples\n\n      iex> String.ends_with?(\"language\", \"age\")\n      true\n      iex> String.ends_with?(\"language\", [\"youth\", \"age\"])\n      true\n      iex> String.ends_with?(\"language\", [\"youth\", \"elixir\"])\n      false\n\n  An empty suffix will always match:\n\n      iex> String.ends_with?(\"language\", \"\")\n      true\n      iex> String.ends_with?(\"language\", [\"\", \"other\"])\n      true\n\n  \"\"\"\n  @spec ends_with?(t, t | [t]) :: boolean\n  def ends_with?(string, suffix) when is_binary(string) and is_binary(suffix) do\n    ends_with_string?(string, byte_size(string), suffix)\n  end\n\n  def ends_with?(string, suffix) when is_binary(string) and is_list(suffix) do\n    string_size = byte_size(string)\n    Enum.any?(suffix, &ends_with_string?(string, string_size, &1))\n  end\n\n  @compile {:inline, ends_with_string?: 3}\n  defp ends_with_string?(string, string_size, suffix) when is_binary(suffix) do\n    suffix_size = byte_size(suffix)\n\n    if suffix_size <= string_size do\n      suffix == binary_part(string, string_size - suffix_size, suffix_size)\n    else\n      false\n    end\n  end\n\n  @doc \"\"\"\n  Checks if `string` matches the given regular expression.\n\n  ## Examples\n\n      iex> String.match?(\"foo\", ~r/foo/)\n      true\n\n      iex> String.match?(\"bar\", ~r/foo/)\n      false\n\n  Elixir also provides text-based match operator `=~/2` and function `Regex.match?/2` as\n  alternatives to test strings against regular expressions.\n  \"\"\"\n  @spec match?(t, Regex.t()) :: boolean\n  def match?(string, regex) when is_binary(string) do\n    Regex.match?(regex, string)\n  end\n\n  @doc \"\"\"\n  Searches if `string` contains any of the given `contents`.\n\n  `contents` can be either a string, a list of strings,\n  or a compiled pattern. If `contents` is a list, this\n  function will search if any of the strings in `contents`\n  are part of `string`.\n\n  > #### Searching for a string in a list {: .tip}\n  >\n  > If you want to check if `string` is listed in `contents`,\n  > where `contents` is a list, use `Enum.member?(contents, string)`\n  > instead.\n\n  ## Examples\n\n      iex> String.contains?(\"elixir of life\", \"of\")\n      true\n      iex> String.contains?(\"elixir of life\", [\"life\", \"death\"])\n      true\n      iex> String.contains?(\"elixir of life\", [\"death\", \"mercury\"])\n      false\n\n  The argument can also be a compiled pattern:\n\n      iex> pattern = :binary.compile_pattern([\"life\", \"death\"])\n      iex> String.contains?(\"elixir of life\", pattern)\n      true\n\n  An empty string will always match:\n\n      iex> String.contains?(\"elixir of life\", \"\")\n      true\n      iex> String.contains?(\"elixir of life\", [\"\", \"other\"])\n      true\n\n  An empty list will never match:\n\n      iex> String.contains?(\"elixir of life\", [])\n      false\n\n      iex> String.contains?(\"\", [])\n      false\n\n  Be aware that this function can match within or across grapheme boundaries.\n  For example, take the grapheme \"é\" which is made of the characters\n  \"e\" and the acute accent. The following returns `true`:\n\n      iex> String.contains?(String.normalize(\"é\", :nfd), \"e\")\n      true\n\n  However, if \"é\" is represented by the single character \"e with acute\"\n  accent, then it will return `false`:\n\n      iex> String.contains?(String.normalize(\"é\", :nfc), \"e\")\n      false\n\n  \"\"\"\n  @spec contains?(t, [t] | pattern) :: boolean\n  def contains?(string, contents) when is_binary(string) and is_list(contents) do\n    list_contains?(string, byte_size(string), contents, [])\n  end\n\n  def contains?(string, contents) when is_binary(string) do\n    \"\" == contents or :binary.match(string, contents) != :nomatch\n  end\n\n  defp list_contains?(string, size, [head | tail], acc) do\n    case byte_size(head) do\n      0 -> true\n      head_size when head_size > size -> list_contains?(string, size, tail, acc)\n      _ -> list_contains?(string, size, tail, [head | acc])\n    end\n  end\n\n  defp list_contains?(_string, _size, [], []),\n    do: false\n\n  defp list_contains?(string, _size, [], contents),\n    do: :binary.match(string, contents) != :nomatch\n\n  @doc \"\"\"\n  Converts a string into a charlist.\n\n  Specifically, this function takes a UTF-8 encoded binary and returns a list of its integer\n  code points. It is similar to `codepoints/1` except that the latter returns a list of code points as\n  strings.\n\n  In case you need to work with bytes, take a look at the\n  [`:binary` module](`:binary`).\n\n  ## Examples\n\n      iex> String.to_charlist(\"foo\")\n      ~c\"foo\"\n\n  \"\"\"\n  @spec to_charlist(t) :: charlist\n  def to_charlist(string) when is_binary(string) do\n    case :unicode.characters_to_list(string) do\n      result when is_list(result) ->\n        result\n\n      {:error, encoded, rest} ->\n        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :invalid\n\n      {:incomplete, encoded, rest} ->\n        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :incomplete\n    end\n  end\n\n  @doc \"\"\"\n  Converts a string to an existing atom or creates a new one.\n\n  Warning: this function creates atoms dynamically and atoms are\n  not garbage-collected. Therefore, `string` should not be an\n  untrusted value, such as input received from a socket or during\n  a web request. Consider using `to_existing_atom/1` instead.\n\n  By default, the maximum number of atoms is `1_048_576`. This limit\n  can be raised or lowered using the VM option `+t`.\n\n  The maximum atom size is of 255 Unicode code points.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> String.to_atom(\"my_atom\")\n      :my_atom\n\n  \"\"\"\n  @spec to_atom(String.t()) :: atom\n  def to_atom(string) when is_binary(string) do\n    :erlang.binary_to_atom(string, :utf8)\n  end\n\n  @doc \"\"\"\n  Converts a string to an existing atom or raises if\n  the atom does not exist.\n\n  The maximum atom size is of 255 Unicode code points.\n  Raises an `ArgumentError` if the atom does not exist.\n\n  Inlined by the compiler.\n\n  > #### Atoms and modules {: .info}\n  >\n  > Since Elixir is a compiled language, the atoms defined in a module\n  > will only exist after said module is loaded, which typically happens\n  > whenever a function in the module is executed. Therefore, it is\n  > generally recommended to call `String.to_existing_atom/1` only to\n  > convert atoms defined within the module making the function call\n  > to `to_existing_atom/1`.\n  >\n  > To create a module name itself from a string safely,\n  > it is recommended to use `Module.safe_concat/1`.\n\n  ## Examples\n\n      iex> _ = :my_atom\n      iex> String.to_existing_atom(\"my_atom\")\n      :my_atom\n\n  \"\"\"\n  @spec to_existing_atom(String.t()) :: atom\n  def to_existing_atom(string) when is_binary(string) do\n    :erlang.binary_to_existing_atom(string, :utf8)\n  end\n\n  @doc \"\"\"\n  Returns an integer whose text representation is `string`.\n\n  `string` must be the string representation of an integer.\n  Otherwise, an `ArgumentError` will be raised. If you want\n  to parse a string that may contain an ill-formatted integer,\n  use `Integer.parse/1`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> String.to_integer(\"123\")\n      123\n\n  Passing a string that does not represent an integer leads to an error:\n\n      String.to_integer(\"invalid data\")\n      ** (ArgumentError) argument error\n\n  \"\"\"\n  @spec to_integer(String.t()) :: integer\n  def to_integer(string) when is_binary(string) do\n    :erlang.binary_to_integer(string)\n  end\n\n  @doc \"\"\"\n  Returns an integer whose text representation is `string` in base `base`.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> String.to_integer(\"3FF\", 16)\n      1023\n\n  \"\"\"\n  @spec to_integer(String.t(), 2..36) :: integer\n  def to_integer(string, base) when is_binary(string) and is_integer(base) do\n    :erlang.binary_to_integer(string, base)\n  end\n\n  @doc \"\"\"\n  Returns a float whose text representation is `string`.\n\n  `string` must be the string representation of a float including leading digits and a decimal\n  point. To parse a string without decimal point as a float, refer to `Float.parse/1`. Otherwise,\n  an `ArgumentError` will be raised.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> String.to_float(\"2.2017764e+0\")\n      2.2017764\n\n      iex> String.to_float(\"3.0\")\n      3.0\n\n      String.to_float(\"3\")\n      ** (ArgumentError) argument error\n\n      String.to_float(\".3\")\n      ** (ArgumentError) argument error\n\n  \"\"\"\n  @spec to_float(String.t()) :: float\n  def to_float(string) when is_binary(string) do\n    :erlang.binary_to_float(string)\n  end\n\n  @doc \"\"\"\n  Computes the bag distance between two strings.\n\n  Returns a float value between 0 and 1 representing the bag\n  distance between `string1` and `string2`.\n\n  The bag distance is meant to be an efficient approximation\n  of the distance between two strings to quickly rule out strings\n  that are largely different.\n\n  The algorithm is outlined in the \"String Matching with Metric\n  Trees Using an Approximate Distance\" paper by Ilaria Bartolini,\n  Paolo Ciaccia, and Marco Patella.\n\n  ## Examples\n\n      iex> String.bag_distance(\"abc\", \"\")\n      0.0\n      iex> String.bag_distance(\"abcd\", \"a\")\n      0.25\n      iex> String.bag_distance(\"abcd\", \"ab\")\n      0.5\n      iex> String.bag_distance(\"abcd\", \"abc\")\n      0.75\n      iex> String.bag_distance(\"abcd\", \"abcd\")\n      1.0\n\n  \"\"\"\n  @spec bag_distance(t, t) :: float\n  @doc since: \"1.8.0\"\n  def bag_distance(_string, \"\"), do: 0.0\n  def bag_distance(\"\", _string), do: 0.0\n\n  def bag_distance(string1, string2) when is_binary(string1) and is_binary(string2) do\n    {bag1, length1} = string_to_bag(string1, %{}, 0)\n    {bag2, length2} = string_to_bag(string2, %{}, 0)\n\n    diff1 = bag_difference(bag1, bag2)\n    diff2 = bag_difference(bag2, bag1)\n\n    1 - max(diff1, diff2) / max(length1, length2)\n  end\n\n  defp string_to_bag(string, bag, length) do\n    case :unicode_util.gc(string) do\n      [gc | rest] -> string_to_bag(rest, bag_store(bag, gc), length + 1)\n      [] -> {bag, length}\n      {:error, <<byte, rest::bits>>} -> string_to_bag(rest, bag_store(bag, <<byte>>), length + 1)\n    end\n  end\n\n  defp bag_store(bag, gc) do\n    case bag do\n      %{^gc => current} -> %{bag | gc => current + 1}\n      %{} -> Map.put(bag, gc, 1)\n    end\n  end\n\n  defp bag_difference(bag1, bag2) do\n    Enum.sum_by(bag1, fn {char, count1} ->\n      case bag2 do\n        %{^char => count2} -> max(count1 - count2, 0)\n        %{} -> count1\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Computes the Jaro distance (similarity) between two strings.\n\n  Returns a float value between `0.0` (equates to no similarity) and `1.0`\n  (is an exact match) representing [Jaro](https://en.wikipedia.org/wiki/Jaro-Winkler_distance)\n  distance between `string1` and `string2`.\n\n  The Jaro distance metric is designed and best suited for short\n  strings such as person names. Elixir itself uses this function\n  to provide the \"did you mean?\" functionality. For instance, when you\n  are calling a function in a module and you have a typo in the\n  function name, we attempt to suggest the most similar function\n  name available, if any, based on the `jaro_distance/2` score.\n\n  ## Examples\n\n      iex> String.jaro_distance(\"Dwayne\", \"Duane\")\n      0.8222222222222223\n      iex> String.jaro_distance(\"even\", \"odd\")\n      0.0\n      iex> String.jaro_distance(\"same\", \"same\")\n      1.0\n\n  \"\"\"\n  @spec jaro_distance(t, t) :: float\n  def jaro_distance(string1, string2)\n\n  def jaro_distance(string, string) when is_binary(string), do: 1.0\n  def jaro_distance(_string, \"\"), do: 0.0\n  def jaro_distance(\"\", _string), do: 0.0\n\n  def jaro_distance(string1, string2) when is_binary(string1) and is_binary(string2) do\n    :string.jaro_similarity(string1, string2)\n  end\n\n  @doc \"\"\"\n  Returns a keyword list that represents an edit script.\n\n  Check `List.myers_difference/2` for more information.\n\n  ## Examples\n\n      iex> string1 = \"fox hops over the dog\"\n      iex> string2 = \"fox jumps over the lazy cat\"\n      iex> String.myers_difference(string1, string2)\n      [eq: \"fox \", del: \"ho\", ins: \"jum\", eq: \"ps over the \", del: \"dog\", ins: \"lazy cat\"]\n\n  \"\"\"\n  @doc since: \"1.3.0\"\n  @spec myers_difference(t, t) :: [{:eq | :ins | :del, t}]\n  def myers_difference(string1, string2) when is_binary(string1) and is_binary(string2) do\n    graphemes(string1)\n    |> List.myers_difference(graphemes(string2))\n    |> Enum.map(fn {kind, chars} -> {kind, IO.iodata_to_binary(chars)} end)\n  end\n\n  @doc false\n  @deprecated \"Use String.to_charlist/1 instead\"\n  @spec to_char_list(t) :: charlist\n  def to_char_list(string), do: String.to_charlist(string)\n\n  ## Helpers\n\n  @compile {:inline,\n            codepoint_byte_size: 1,\n            grapheme_byte_size: 1,\n            grapheme_to_binary: 1,\n            reverse_characters_to_binary: 1}\n\n  defp byte_size_unicode(binary) when is_binary(binary), do: byte_size(binary)\n  defp byte_size_unicode([head]), do: byte_size_unicode(head)\n  defp byte_size_unicode([head | tail]), do: byte_size_unicode(head) + byte_size_unicode(tail)\n\n  defp byte_size_remaining_at(unicode, 0) do\n    byte_size_unicode(unicode)\n  end\n\n  defp byte_size_remaining_at(unicode, n) do\n    case :unicode_util.gc(unicode) do\n      [_] -> 0\n      [_ | rest] -> byte_size_remaining_at(rest, n - 1)\n      [] -> 0\n      {:error, <<_, bin::bits>>} -> byte_size_remaining_at(bin, n - 1)\n    end\n  end\n\n  defp codepoint_byte_size(cp) when cp <= 0x007F, do: 1\n  defp codepoint_byte_size(cp) when cp <= 0x07FF, do: 2\n  defp codepoint_byte_size(cp) when cp <= 0xFFFF, do: 3\n  defp codepoint_byte_size(_), do: 4\n\n  defp grapheme_to_binary(cp) when is_integer(cp), do: <<cp::utf8>>\n  defp grapheme_to_binary(gc) when is_list(gc), do: for(cp <- gc, do: <<cp::utf8>>, into: \"\")\n\n  defp grapheme_byte_size(cp) when is_integer(cp), do: codepoint_byte_size(cp)\n  defp grapheme_byte_size(cps), do: grapheme_byte_size(cps, 0)\n\n  defp grapheme_byte_size([cp | cps], acc),\n    do: grapheme_byte_size(cps, acc + codepoint_byte_size(cp))\n\n  defp grapheme_byte_size([], acc),\n    do: acc\n\n  defp reverse_characters_to_binary(acc),\n    do: acc |> :lists.reverse() |> :unicode.characters_to_binary()\nend\n"
  },
  {
    "path": "lib/elixir/lib/string_io.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule StringIO do\n  @moduledoc \"\"\"\n  Controls an IO device process that wraps a string.\n\n  A `StringIO` IO device can be passed as a \"device\" to\n  most of the functions in the `IO` module.\n\n  ## Examples\n\n      iex> {:ok, pid} = StringIO.open(\"foo\")\n      iex> IO.read(pid, 2)\n      \"fo\"\n\n  \"\"\"\n\n  @type open_opts :: [\n          capture_prompt: boolean(),\n          encoding: :unicode | :latin1\n        ]\n\n  # We're implementing the GenServer behaviour instead of using the\n  # `use GenServer` macro, because we don't want the `child_spec/1`\n  # function as it doesn't make sense to be started under a supervisor.\n  @behaviour GenServer\n\n  @doc ~S\"\"\"\n  Creates an IO device.\n\n  `string` will be the initial input of the newly created\n  device.\n\n  The device will be created and sent to the function given.\n  When the function returns, the device will be closed. The final\n  result will be a tuple with `:ok` and the result of the function.\n\n  ## Options\n\n    * `:capture_prompt` - if set to `true`, prompts (specified as\n      arguments to `IO.get*` functions) are captured in the output.\n      Defaults to `false`.\n\n    * `:encoding` (since v1.10.0) - encoding of the IO device. Allowed\n      values are `:unicode` (default) and `:latin1`.\n\n  ## Examples\n\n      iex> StringIO.open(\"foo\", [], fn pid ->\n      ...>   input = IO.gets(pid, \">\")\n      ...>   IO.write(pid, \"The input was #{input}\")\n      ...>   StringIO.contents(pid)\n      ...> end)\n      {:ok, {\"\", \"The input was foo\"}}\n\n      iex> StringIO.open(\"foo\", [capture_prompt: true], fn pid ->\n      ...>   input = IO.gets(pid, \">\")\n      ...>   IO.write(pid, \"The input was #{input}\")\n      ...>   StringIO.contents(pid)\n      ...> end)\n      {:ok, {\"\", \">The input was foo\"}}\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec open(binary, open_opts, (pid -> res)) :: {:ok, res} when res: var\n  def open(string, options, function)\n      when is_binary(string) and is_list(options) and is_function(function, 1) do\n    {:ok, pid} = GenServer.start(__MODULE__, {self(), string, options}, [])\n\n    try do\n      {:ok, function.(pid)}\n    after\n      {:ok, {_input, _output}} = close(pid)\n    end\n  end\n\n  @doc ~S\"\"\"\n  Creates an IO device.\n\n  `string` will be the initial input of the newly created\n  device.\n\n  `options_or_function` can be a keyword list of options or\n  a function.\n\n  If options are provided, the result will be `{:ok, pid}`, returning the\n  IO device created. The option `:capture_prompt`, when set to `true`, causes\n  prompts (which are specified as arguments to `IO.get*` functions) to be\n  included in the device's output. See `options/3` for the list of supported\n  options.\n\n  If a function is provided, the device will be created and sent to the\n  function. When the function returns, the device will be closed. The final\n  result will be a tuple with `:ok` and the result of the function.\n\n  ## Examples\n\n      iex> {:ok, pid} = StringIO.open(\"foo\")\n      iex> IO.gets(pid, \">\")\n      \"foo\"\n      iex> StringIO.contents(pid)\n      {\"\", \"\"}\n\n      iex> {:ok, pid} = StringIO.open(\"foo\", capture_prompt: true)\n      iex> IO.gets(pid, \">\")\n      \"foo\"\n      iex> StringIO.contents(pid)\n      {\"\", \">\"}\n\n      iex> StringIO.open(\"foo\", fn pid ->\n      ...>   input = IO.gets(pid, \">\")\n      ...>   IO.write(pid, \"The input was #{input}\")\n      ...>   StringIO.contents(pid)\n      ...> end)\n      {:ok, {\"\", \"The input was foo\"}}\n\n  \"\"\"\n  @spec open(binary, open_opts) :: {:ok, pid}\n  @spec open(binary, (pid -> res)) :: {:ok, res} when res: var\n  def open(string, options_or_function \\\\ [])\n\n  def open(string, options_or_function) when is_binary(string) and is_list(options_or_function) do\n    GenServer.start(__MODULE__, {self(), string, options_or_function}, [])\n  end\n\n  def open(string, options_or_function)\n      when is_binary(string) and is_function(options_or_function, 1) do\n    open(string, [], options_or_function)\n  end\n\n  @doc \"\"\"\n  Returns the current input/output buffers for the given IO\n  device.\n\n  ## Examples\n\n      iex> {:ok, pid} = StringIO.open(\"in\")\n      iex> IO.write(pid, \"out\")\n      iex> StringIO.contents(pid)\n      {\"in\", \"out\"}\n\n  \"\"\"\n  @spec contents(pid) :: {binary, binary}\n  def contents(pid) when is_pid(pid) do\n    GenServer.call(pid, :contents)\n  end\n\n  @doc \"\"\"\n  Flushes the output buffer and returns its current contents.\n\n  ## Examples\n\n      iex> {:ok, pid} = StringIO.open(\"in\")\n      iex> IO.write(pid, \"out\")\n      iex> StringIO.flush(pid)\n      \"out\"\n      iex> StringIO.contents(pid)\n      {\"in\", \"\"}\n\n  \"\"\"\n  @spec flush(pid) :: binary\n  def flush(pid) when is_pid(pid) do\n    GenServer.call(pid, :flush)\n  end\n\n  @doc \"\"\"\n  Stops the IO device and returns the remaining input/output\n  buffers.\n\n  ## Examples\n\n      iex> {:ok, pid} = StringIO.open(\"in\")\n      iex> IO.write(pid, \"out\")\n      iex> StringIO.close(pid)\n      {:ok, {\"in\", \"out\"}}\n\n  \"\"\"\n  @spec close(pid) :: {:ok, {binary, binary}}\n  def close(pid) when is_pid(pid) do\n    GenServer.call(pid, :close)\n  end\n\n  ## callbacks\n\n  @impl true\n  def init({pid, string, options}) do\n    _ = Process.monitor(pid)\n    capture_prompt = options[:capture_prompt] || false\n    encoding = options[:encoding] || :unicode\n    {:ok, %{encoding: encoding, input: string, output: \"\", capture_prompt: capture_prompt}}\n  end\n\n  @impl true\n  def handle_info({:io_request, from, reply_as, req}, state) do\n    state = io_request(from, reply_as, req, state)\n    {:noreply, state}\n  end\n\n  # Fail fast if someone tries to use it with a File API\n  def handle_info({:file_request, from, reply_as, _req}, state) do\n    send(from, {:file_reply, reply_as, {:error, :enotsup}})\n    {:noreply, state}\n  end\n\n  def handle_info({:DOWN, _, _, _, _}, state) do\n    {:stop, :shutdown, state}\n  end\n\n  def handle_info(_message, state) do\n    {:noreply, state}\n  end\n\n  @impl true\n  def handle_call(:contents, _from, %{input: input, output: output} = state) do\n    {:reply, {input, output}, state}\n  end\n\n  def handle_call(:flush, _from, %{output: output} = state) do\n    {:reply, output, %{state | output: \"\"}}\n  end\n\n  def handle_call(:close, _from, %{input: input, output: output} = state) do\n    {:stop, :normal, {:ok, {input, output}}, state}\n  end\n\n  defp io_request(from, reply_as, req, state) do\n    {reply, state} = io_request(req, state)\n    io_reply(from, reply_as, reply)\n    state\n  end\n\n  defp io_request({:put_chars, chars} = req, state) do\n    put_chars(:latin1, chars, req, state)\n  end\n\n  defp io_request({:put_chars, mod, fun, args} = req, state) do\n    put_chars(:latin1, apply(mod, fun, args), req, state)\n  end\n\n  defp io_request({:put_chars, encoding, chars} = req, state) do\n    put_chars(encoding, chars, req, state)\n  end\n\n  defp io_request({:put_chars, encoding, mod, fun, args} = req, state) do\n    put_chars(encoding, apply(mod, fun, args), req, state)\n  end\n\n  defp io_request({:get_chars, prompt, count}, state) when count >= 0 do\n    io_request({:get_chars, :latin1, prompt, count}, state)\n  end\n\n  defp io_request({:get_chars, encoding, prompt, count}, state) when count >= 0 do\n    get_chars(encoding, prompt, count, state)\n  end\n\n  defp io_request({:get_line, prompt}, state) do\n    io_request({:get_line, :latin1, prompt}, state)\n  end\n\n  defp io_request({:get_line, encoding, prompt}, state) do\n    get_line(encoding, prompt, state)\n  end\n\n  defp io_request({:get_until, prompt, mod, fun, args}, state) do\n    io_request({:get_until, :latin1, prompt, mod, fun, args}, state)\n  end\n\n  defp io_request({:get_until, encoding, prompt, mod, fun, args}, state) do\n    get_until(encoding, prompt, mod, fun, args, state)\n  end\n\n  defp io_request({:get_password, encoding}, state) do\n    get_line(encoding, \"\", state)\n  end\n\n  defp io_request({:setopts, [encoding: encoding]}, state) when encoding in [:latin1, :unicode] do\n    {:ok, %{state | encoding: encoding}}\n  end\n\n  defp io_request({:setopts, _opts}, state) do\n    {{:error, :enotsup}, state}\n  end\n\n  defp io_request(:getopts, state) do\n    {[binary: true, encoding: state.encoding], state}\n  end\n\n  defp io_request({:get_geometry, :columns}, state) do\n    {{:error, :enotsup}, state}\n  end\n\n  defp io_request({:get_geometry, :rows}, state) do\n    {{:error, :enotsup}, state}\n  end\n\n  defp io_request({:requests, reqs}, state) do\n    io_requests(reqs, {:ok, state})\n  end\n\n  defp io_request(_, state) do\n    {{:error, :request}, state}\n  end\n\n  ## put_chars\n\n  defp put_chars(encoding, chars, req, state) do\n    case :unicode.characters_to_binary(chars, encoding, state.encoding) do\n      string when is_binary(string) ->\n        {:ok, %{state | output: state.output <> string}}\n\n      {_, _, _} ->\n        {{:error, {:no_translation, encoding, state.encoding}}, state}\n    end\n  rescue\n    ArgumentError -> {{:error, req}, state}\n  end\n\n  ## get_chars\n\n  defp get_chars(encoding, prompt, count, %{input: input} = state) do\n    case get_chars(input, encoding, count) do\n      {:error, _} = error ->\n        {error, state}\n\n      {result, input} ->\n        {result, state_after_read(state, input, prompt, 1)}\n    end\n  end\n\n  defp get_chars(\"\", _encoding, _count) do\n    {:eof, \"\"}\n  end\n\n  defp get_chars(input, :latin1, count) when byte_size(input) < count do\n    {input, \"\"}\n  end\n\n  defp get_chars(input, :latin1, count) do\n    <<chars::binary-size(^count), rest::binary>> = input\n    {chars, rest}\n  end\n\n  defp get_chars(input, :unicode, count) do\n    with {:ok, count} <- split_at(input, count, 0) do\n      <<chars::binary-size(^count), rest::binary>> = input\n      {chars, rest}\n    end\n  end\n\n  defp split_at(_, 0, acc),\n    do: {:ok, acc}\n\n  defp split_at(<<h::utf8, t::binary>>, count, acc),\n    do: split_at(t, count - 1, acc + byte_size(<<h::utf8>>))\n\n  defp split_at(<<_, _::binary>>, _count, _acc),\n    do: {:error, :invalid_unicode}\n\n  defp split_at(<<>>, _count, acc),\n    do: {:ok, acc}\n\n  ## get_line\n\n  defp get_line(encoding, prompt, %{input: input} = state) do\n    case bytes_until_eol(input, encoding, 0) do\n      {:split, 0} ->\n        {:eof, state_after_read(state, \"\", prompt, 1)}\n\n      {:split, count} ->\n        {result, remainder} = :erlang.split_binary(input, count)\n        {result, state_after_read(state, remainder, prompt, 1)}\n\n      {:replace_split, count} ->\n        {result, remainder} = :erlang.split_binary(input, count)\n        result = binary_part(result, 0, byte_size(result) - 2) <> \"\\n\"\n        {result, state_after_read(state, remainder, prompt, 1)}\n\n      :error ->\n        {{:error, :collect_line}, state}\n    end\n  end\n\n  ## get_until\n\n  defp get_until(encoding, prompt, mod, fun, args, %{input: input} = state) do\n    case get_until(input, encoding, mod, fun, args, [], 0) do\n      {result, input, count} ->\n        # Convert :eof to \"\" as they are both treated the same\n        input =\n          case input do\n            :eof -> \"\"\n            _ -> list_to_binary(input, encoding)\n          end\n\n        {get_until_result(result, encoding), state_after_read(state, input, prompt, count)}\n\n      :error ->\n        {:error, state}\n    end\n  end\n\n  defp get_until(\"\", encoding, mod, fun, args, continuation, count) do\n    case apply(mod, fun, [continuation, :eof | args]) do\n      {:done, result, rest} ->\n        {result, rest, count + 1}\n\n      {:more, next_continuation} ->\n        get_until(\"\", encoding, mod, fun, args, next_continuation, count + 1)\n    end\n  end\n\n  defp get_until(chars, encoding, mod, fun, args, continuation, count) do\n    case bytes_until_eol(chars, encoding, 0) do\n      {kind, size} when kind in [:split, :replace_split] ->\n        <<line::binary-size(^size), rest::binary>> = chars\n\n        case apply(mod, fun, [continuation, binary_to_list(line, encoding) | args]) do\n          {:done, result, :eof} ->\n            {result, rest, count + 1}\n\n          {:done, result, extra} ->\n            {result, extra ++ binary_to_list(rest, encoding), count + 1}\n\n          {:more, next_continuation} ->\n            get_until(rest, encoding, mod, fun, args, next_continuation, count + 1)\n        end\n\n      :error ->\n        :error\n    end\n  end\n\n  defp binary_to_list(data, :unicode) when is_binary(data), do: String.to_charlist(data)\n  defp binary_to_list(data, :latin1) when is_binary(data), do: :erlang.binary_to_list(data)\n\n  defp list_to_binary(data, _) when is_binary(data), do: data\n  defp list_to_binary(data, :unicode) when is_list(data), do: List.to_string(data)\n  defp list_to_binary(data, :latin1) when is_list(data), do: :erlang.list_to_binary(data)\n\n  # From https://www.erlang.org/doc/apps/stdlib/io_protocol.html: result can be any\n  # Erlang term, but if it is a list(), the I/O server can convert it to a binary().\n  defp get_until_result(data, encoding) when is_list(data), do: list_to_binary(data, encoding)\n  defp get_until_result(data, _), do: data\n\n  ## io_requests\n\n  defp io_requests([req | rest], {:ok, state}) do\n    io_requests(rest, io_request(req, state))\n  end\n\n  defp io_requests(_, result) do\n    result\n  end\n\n  ## helpers\n\n  defp state_after_read(%{capture_prompt: false} = state, remainder, _prompt, _count) do\n    %{state | input: remainder}\n  end\n\n  defp state_after_read(%{capture_prompt: true, output: output} = state, remainder, prompt, count) do\n    output = <<output::binary, :binary.copy(IO.chardata_to_string(prompt), count)::binary>>\n    %{state | input: remainder, output: output}\n  end\n\n  defp bytes_until_eol(\"\", _, count), do: {:split, count}\n  defp bytes_until_eol(<<\"\\r\\n\"::binary, _::binary>>, _, count), do: {:replace_split, count + 2}\n  defp bytes_until_eol(<<\"\\n\"::binary, _::binary>>, _, count), do: {:split, count + 1}\n\n  defp bytes_until_eol(<<head::utf8, tail::binary>>, :unicode, count) do\n    bytes_until_eol(tail, :unicode, count + byte_size(<<head::utf8>>))\n  end\n\n  defp bytes_until_eol(<<_, tail::binary>>, :latin1, count) do\n    bytes_until_eol(tail, :latin1, count + 1)\n  end\n\n  defp bytes_until_eol(<<_::binary>>, _, _), do: :error\n\n  defp io_reply(from, reply_as, reply) do\n    send(from, {:io_reply, reply_as, reply})\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/supervisor/default.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Supervisor.Default do\n  @moduledoc false\n\n  def init(args) do\n    args\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/supervisor/spec.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Supervisor.Spec do\n  @moduledoc \"\"\"\n  Outdated functions for building child specifications.\n\n  The functions in this module are deprecated and they do not work\n  with the module-based child specs introduced in Elixir v1.5.\n  Please see the `Supervisor` documentation instead.\n\n  Convenience functions for defining supervisor specifications.\n\n  ## Example\n\n  By using the functions in this module one can specify the children\n  to be used under a supervisor, started with `Supervisor.start_link/2`:\n\n      import Supervisor.Spec\n\n      children = [\n        worker(MyWorker, [arg1, arg2, arg3]),\n        supervisor(MySupervisor, [arg1])\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_one)\n\n  Sometimes, it may be handy to define supervisors backed\n  by a module:\n\n      defmodule MySupervisor do\n        use Supervisor\n\n        def start_link(arg) do\n          Supervisor.start_link(__MODULE__, arg)\n        end\n\n        def init(arg) do\n          children = [\n            worker(MyWorker, [arg], restart: :temporary)\n          ]\n\n          supervise(children, strategy: :simple_one_for_one)\n        end\n      end\n\n  Note that in this case we don't have to explicitly import\n  `Supervisor.Spec` since `use Supervisor` automatically does so.\n  Defining a module-based supervisor can be useful, for example,\n  to perform initialization tasks in the `c:Supervisor.init/1` callback.\n\n  ## Supervisor and worker options\n\n  In the example above, we defined specs for workers and supervisors.\n  These specs (both for workers as well as supervisors) accept the\n  following options:\n\n    * `:id` - a name used to identify the child specification\n      internally by the supervisor; defaults to the given module\n      name for the child worker/supervisor\n\n    * `:function` - the function to invoke on the child to start it\n\n    * `:restart` - an atom that defines when a terminated child process should\n      be restarted (see the \"Restart values\" section below)\n\n    * `:shutdown` - an atom that defines how a child process should be\n      terminated (see the \"Shutdown values\" section below)\n\n    * `:modules` - it should be a list with one element `[module]`,\n      where module is the name of the callback module only if the\n      child process is a `Supervisor` or `GenServer`; if the child\n      process is a `GenEvent`, `:modules` should be `:dynamic`\n\n  ### Restart values (:restart)\n\n  The following restart values are supported in the `:restart` option:\n\n    * `:permanent` - the child process is always restarted\n\n    * `:temporary` - the child process is never restarted (not even\n      when the supervisor's strategy is `:rest_for_one` or `:one_for_all`)\n\n    * `:transient` - the child process is restarted only if it\n      terminates abnormally, i.e., with an exit reason other than\n      `:normal`, `:shutdown` or `{:shutdown, term}`\n\n  Note that supervisor that reached maximum restart intensity will exit with `:shutdown` reason.\n  In this case the supervisor will only restart if its child specification was defined with\n  the `:restart` option set to `:permanent` (the default).\n\n  ### Shutdown values (`:shutdown`)\n\n  The following shutdown values are supported in the `:shutdown` option:\n\n    * `:brutal_kill` - the child process is unconditionally terminated\n      using `Process.exit(child, :kill)`\n\n    * `:infinity` - if the child process is a supervisor, this is a mechanism\n      to give the subtree enough time to shut down; it can also be used with\n      workers with care\n\n    * a non-negative integer - the amount of time in milliseconds\n      that the supervisor tells the child process to terminate by calling\n      `Process.exit(child, :shutdown)` and then waits for an exit signal back.\n      If no exit signal is received within the specified time,\n      the child process is unconditionally terminated\n      using `Process.exit(child, :kill)`\n\n  \"\"\"\n\n  @moduledoc deprecated:\n               \"Use the new child specifications outlined in the Supervisor module instead\"\n\n  @typedoc \"Supported strategies\"\n  @type strategy :: :simple_one_for_one | :one_for_one | :one_for_all | :rest_for_one\n\n  @typedoc \"Supported restart values\"\n  @type restart :: :permanent | :transient | :temporary\n\n  @typedoc \"Supported shutdown values\"\n  @type shutdown :: timeout | :brutal_kill\n\n  @typedoc \"Supported worker values\"\n  @type worker :: :worker | :supervisor\n\n  @typedoc \"Supported module values\"\n  @type modules :: :dynamic | [module]\n\n  @typedoc \"Supported ID values\"\n  @type child_id :: term\n\n  @typedoc \"The supervisor specification\"\n  @type spec ::\n          {child_id, start_fun :: {module, atom, [term]}, restart, shutdown, worker, modules}\n\n  @doc \"\"\"\n  Receives a list of `children` (workers or supervisors) to\n  supervise and a set of `options`.\n\n  Returns a tuple containing the supervisor specification. This tuple can be\n  used as the return value of the `c:Supervisor.init/1` callback when implementing a\n  module-based supervisor.\n\n  ## Examples\n\n      supervise(children, strategy: :one_for_one)\n\n  ## Options\n\n    * `:strategy` - the restart strategy option. It can be either\n      `:one_for_one`, `:rest_for_one`, `:one_for_all`, or\n      `:simple_one_for_one`. You can learn more about strategies\n      in the `Supervisor` module docs.\n\n    * `:max_restarts` - the maximum number of restarts allowed in\n      a time frame. Defaults to `3`.\n\n    * `:max_seconds` - the time frame in which `:max_restarts` applies.\n      Defaults to `5`.\n\n  The `:strategy` option is required and by default a maximum of 3 restarts is\n  allowed within 5 seconds. Check the `Supervisor` module for a detailed\n  description of the available strategies.\n  \"\"\"\n  @spec supervise(\n          [spec],\n          strategy: strategy,\n          max_restarts: non_neg_integer,\n          max_seconds: pos_integer\n        ) :: {:ok, tuple}\n  @deprecated \"Use the new child specifications outlined in the Supervisor module instead\"\n  def supervise(children, options) do\n    if !(strategy = options[:strategy]) do\n      raise ArgumentError, \"expected :strategy option to be given\"\n    end\n\n    maxR = Keyword.get(options, :max_restarts, 3)\n    maxS = Keyword.get(options, :max_seconds, 5)\n\n    assert_unique_ids(Enum.map(children, &get_id/1))\n    {:ok, {{strategy, maxR, maxS}, children}}\n  end\n\n  defp get_id({id, _, _, _, _, _}) do\n    id\n  end\n\n  defp get_id(other) do\n    raise ArgumentError,\n          \"invalid tuple specification given to supervise/2. If you are trying to use \" <>\n            \"the map child specification that is part of the Elixir v1.5, use Supervisor.init/2 \" <>\n            \"instead of Supervisor.Spec.supervise/2. See the Supervisor module for more information. \" <>\n            \"Got: #{inspect(other)}\"\n  end\n\n  defp assert_unique_ids([id | rest]) do\n    if id in rest do\n      raise ArgumentError,\n            \"duplicate ID #{inspect(id)} found in the supervisor specification, \" <>\n              \"please explicitly pass the :id option when defining this worker/supervisor\"\n    else\n      assert_unique_ids(rest)\n    end\n  end\n\n  defp assert_unique_ids([]) do\n    :ok\n  end\n\n  @doc \"\"\"\n  Defines the given `module` as a worker which will be started\n  with the given arguments.\n\n      worker(ExUnit.Runner, [], restart: :permanent)\n\n  By default, the function `start_link` is invoked on the given\n  module. Overall, the default values for the options are:\n\n      [\n        id: module,\n        function: :start_link,\n        restart: :permanent,\n        shutdown: 5000,\n        modules: [module]\n      ]\n\n  See the \"Supervisor and worker options\" section in the `Supervisor.Spec` module for more\n  information on the available options.\n  \"\"\"\n  @spec worker(\n          module,\n          [term],\n          restart: restart,\n          shutdown: shutdown,\n          id: term,\n          function: atom,\n          modules: modules\n        ) :: spec\n  @deprecated \"Use the new child specifications outlined in the Supervisor module instead\"\n  def worker(module, args, options \\\\ []) do\n    child(:worker, module, args, options)\n  end\n\n  @doc \"\"\"\n  Defines the given `module` as a supervisor which will be started\n  with the given arguments.\n\n      supervisor(module, [], restart: :permanent)\n\n  By default, the function `start_link` is invoked on the given\n  module. Overall, the default values for the options are:\n\n      [\n        id: module,\n        function: :start_link,\n        restart: :permanent,\n        shutdown: :infinity,\n        modules: [module]\n      ]\n\n  See the \"Supervisor and worker options\" section in the `Supervisor.Spec` module for more\n  information on the available options.\n  \"\"\"\n  @spec supervisor(\n          module,\n          [term],\n          restart: restart,\n          shutdown: shutdown,\n          id: term,\n          function: atom,\n          modules: modules\n        ) :: spec\n  @deprecated \"Use the new child specifications outlined in the Supervisor module instead\"\n  def supervisor(module, args, options \\\\ []) do\n    options = Keyword.put_new(options, :shutdown, :infinity)\n    child(:supervisor, module, args, options)\n  end\n\n  defp child(type, module, args, options) do\n    id = Keyword.get(options, :id, module)\n    modules = Keyword.get(options, :modules, modules(module))\n    function = Keyword.get(options, :function, :start_link)\n    restart = Keyword.get(options, :restart, :permanent)\n    shutdown = Keyword.get(options, :shutdown, 5000)\n\n    {id, {module, function, args}, restart, shutdown, type, modules}\n  end\n\n  defp modules(GenEvent), do: :dynamic\n  defp modules(module), do: [module]\nend\n"
  },
  {
    "path": "lib/elixir/lib/supervisor.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Supervisor do\n  @moduledoc ~S\"\"\"\n  A behaviour module for implementing supervisors.\n\n  A supervisor is a process which supervises other processes, which we\n  refer to as *child processes*. Supervisors are used to build a hierarchical\n  process structure called a *supervision tree*. Supervision trees provide\n  fault-tolerance and encapsulate how our applications start and shutdown.\n\n  A supervisor may be started directly with a list of child specifications via\n  `start_link/2` or you may define a module-based supervisor that implements\n  the required callbacks. The sections below use `start_link/2` to start\n  supervisors in most examples, but it also includes a specific section\n  on module-based ones.\n\n  ## Examples\n\n  In order to start a supervisor, we need to first define a child process\n  that will be supervised. As an example, we will define a `GenServer`,\n  a generic server, that keeps a counter. Other processes can then send\n  messages to this process to read the counter and bump its value.\n\n  > #### Disclaimer {: .neutral}\n  >\n  > In practice you would not define a counter as a GenServer. Instead,\n  > if you need a counter, you would pass it around as inputs and outputs to\n  > the functions that need it. The reason we picked a counter in this example\n  > is due to its simplicity, as it allows us to focus on how supervisors work.\n\n      defmodule Counter do\n        use GenServer\n\n        def start_link(arg) when is_integer(arg) do\n          GenServer.start_link(__MODULE__, arg, name: __MODULE__)\n        end\n\n        ## Callbacks\n\n        @impl true\n        def init(counter) do\n          {:ok, counter}\n        end\n\n        @impl true\n        def handle_call(:get, _from, counter) do\n          {:reply, counter, counter}\n        end\n\n        def handle_call({:bump, value}, _from, counter) do\n          {:reply, counter, counter + value}\n        end\n      end\n\n  The `Counter` receives an argument on `start_link`. This argument\n  is passed to the `init/1` callback which becomes the initial value\n  of the counter. Our counter handles two operations (known as calls):\n  `:get`, to get the current counter value, and `:bump`, that bumps\n  the counter by the given `value` and returns the old counter.\n\n  We can now start a supervisor that will start and supervise our\n  counter process. The first step is to define a list of **child\n  specifications** that control how each child behaves. Each child\n  specification is a map, as shown below:\n\n      children = [\n        # The Counter is a child started via Counter.start_link(0)\n        %{\n          id: Counter,\n          start: {Counter, :start_link, [0]}\n        }\n      ]\n\n      # Now we start the supervisor with the children and a strategy\n      {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)\n\n      # After started, we can query the supervisor for information\n      Supervisor.count_children(pid)\n      #=> %{active: 1, specs: 1, supervisors: 0, workers: 1}\n\n  Note that when starting the GenServer, we are registering it\n  with name `Counter` via the `name: __MODULE__` option. This allows\n  us to call it directly and get its value:\n\n      GenServer.call(Counter, :get)\n      #=> 0\n\n      GenServer.call(Counter, {:bump, 3})\n      #=> 0\n\n      GenServer.call(Counter, :get)\n      #=> 3\n\n  However, there is a bug in our counter server. If we call `:bump` with\n  a non-numeric value, it is going to crash:\n\n      GenServer.call(Counter, {:bump, \"oops\"})\n      ** (exit) exited in: GenServer.call(Counter, {:bump, \"oops\"}, 5000)\n\n  Luckily, since the server is being supervised by a supervisor, the\n  supervisor will automatically start a new one, reset back to its initial\n  value of `0`:\n\n      GenServer.call(Counter, :get)\n      #=> 0\n\n  Supervisors support different strategies; in the example above, we\n  have chosen `:one_for_one`. Furthermore, each supervisor can have many\n  workers and/or supervisors as children, with each one having its own\n  configuration (as outlined in the \"Child specification\" section).\n\n  The rest of this document will cover how child processes are specified,\n  how they can be started and stopped, different supervision strategies\n  and more.\n\n  ## Child specification\n\n  The child specification describes how the supervisor starts, shuts down,\n  and restarts child processes.\n\n  The child specification is a map containing up to 6 elements. The first two keys\n  in the following list are required, and the remaining ones are optional:\n\n    * `:id` - any term used to identify the child specification internally by\n      the supervisor; defaults to the given module. This key is required.\n      For supervisors, in the case of conflicting `:id` values, the supervisor\n      will refuse to initialize and require explicit IDs. This is not the case\n      for [dynamic supervisors](`DynamicSupervisor`) though.\n\n    * `:start` - a tuple with the module-function-args to be invoked\n      to start the child process. This key is required.\n\n    * `:restart` - an atom that defines when a terminated child process\n       should be restarted (see the [\"Restart values\"](#module-restart-values-restart) section below).\n       This key is optional and defaults to `:permanent`.\n\n    * `:shutdown` - an integer or atom that defines how a child process should\n      be terminated (see the [\"Shutdown values\"](#module-shutdown-values-shutdown) section below). This key\n      is optional and defaults to `5_000` if the type is `:worker` or\n      `:infinity` if the type is `:supervisor`.\n\n    * `:type` - specifies that the child process is a `:worker` or a\n      `:supervisor`. This key is optional and defaults to `:worker`.\n\n    * `:modules` - a list of modules used by hot code upgrade mechanisms\n      to determine which processes are using certain modules. It is typically\n      set to the callback module of behaviours like `GenServer`, `Supervisor`,\n      and such. It is set automatically based on the `:start` value and it is rarely\n      changed in practice.\n\n    * `:significant` - a boolean indicating if the child process should be\n      considered significant with regard to automatic shutdown.  Only `:transient`\n      and `:temporary` child processes can be marked as significant. This key is\n      optional and defaults to `false`. See section \"Automatic shutdown\" below\n      for more details.\n\n  Let's understand what the `:shutdown` and `:restart` options control.\n\n  ### Shutdown values (:shutdown)\n\n  The following shutdown values are supported in the `:shutdown` option:\n\n    * `:brutal_kill` - the child process is unconditionally and immediately\n      terminated using `Process.exit(child, :kill)`.\n\n    * any integer >= 0 - the amount of time in milliseconds that the\n      supervisor will wait for its children to terminate after emitting a\n      `Process.exit(child, :shutdown)` signal. If the child process is\n      not trapping exits, the initial `:shutdown` signal will terminate\n      the child process immediately. If the child process is trapping\n      exits, it has the given amount of time to terminate.\n      If it doesn't terminate within the specified time, the child process\n      is unconditionally terminated by the supervisor via\n      `Process.exit(child, :kill)`.\n\n    * `:infinity` - works as an integer except the supervisor will wait\n      indefinitely for the child to terminate. If the child process is a\n      supervisor, the recommended value is `:infinity` to give the supervisor\n      and its children enough time to shut down. This option can be used with\n      regular workers but doing so is discouraged and requires extreme care.\n      If not used carefully, the child process will never terminate,\n      preventing your application from terminating as well.\n\n  ### Restart values (:restart)\n\n  The `:restart` option controls what the supervisor should consider to\n  be a successful termination or not. If the termination is successful,\n  the supervisor won't restart the child. If the child process crashed,\n  the supervisor will start a new one.\n\n  The following restart values are supported in the `:restart` option:\n\n    * `:permanent` - the child process is always restarted.\n\n    * `:temporary` - the child process is never restarted, regardless\n      of the supervision strategy: any termination (even abnormal) is\n      considered successful.\n\n    * `:transient` - the child process is restarted only if it\n      terminates abnormally, i.e., with an exit reason other than\n      `:normal`, `:shutdown`, or `{:shutdown, term}`.\n\n  For a more complete understanding of the exit reasons and their\n  impact, see the \"Exit reasons and restarts\" section.\n\n  ## `child_spec/1` function\n\n  When starting a supervisor, we may pass a list of child specifications. Those\n  specifications are maps that tell how the supervisor should start, stop and\n  restart each of its children:\n\n      %{\n        id: Counter,\n        start: {Counter, :start_link, [0]}\n      }\n\n  The map above defines a child with `:id` of `Counter` that is started\n  by calling `Counter.start_link(0)`.\n\n  However, defining the child specification for each child as a map can be\n  quite error prone, as we may change the `Counter` implementation and forget\n  to update its specification. That's why Elixir allows you to pass a tuple with\n  the module name and the `start_link` argument instead of the specification:\n\n      children = [\n        {Counter, 0}\n      ]\n\n  The supervisor will then invoke `Counter.child_spec(0)` to retrieve a child\n  specification. Now the `Counter` module is responsible for building its own\n  specification, for example, we could write:\n\n      def child_spec(arg) do\n        %{\n          id: Counter,\n          start: {Counter, :start_link, [arg]}\n        }\n      end\n\n  Then the supervisor will call `Counter.start_link(arg)` to start the child\n  process. This flow is summarized in the diagram below. Caller is a process\n  which spawns the Supervisor process. The Supervisor then proceeds to call\n  your code (Module) to spawn its child process:\n\n  ```mermaid\n  sequenceDiagram\n      participant C as Caller (Process)\n      participant S as Supervisor (Process)\n      participant M as Module (Code)\n\n      note right of C: child is a {module, arg} specification\n      C->>+S: Supervisor.start_link([child])\n      S-->>+M: module.child_spec(arg)\n      M-->>-S: %{id: term, start: {module, :start_link, [arg]}}\n      S-->>+M: module.start_link(arg)\n      M->>M: Spawns child process (child_pid)\n      M-->>-S: {:ok, child_pid} | :ignore | {:error, reason}\n      S->>-C: {:ok, supervisor_pid} | {:error, reason}\n  ```\n\n  Luckily for us, `use GenServer` already defines a `Counter.child_spec/1`\n  exactly like above, so you don't need to write the definition above yourself.\n  If you want to customize the automatically generated `child_spec/1` function,\n  you can pass the options directly to `use GenServer`:\n\n      use GenServer, restart: :transient\n\n  Finally, note it is also possible to simply pass the `Counter` module as\n  a child:\n\n      children = [\n        Counter\n      ]\n\n  When only the module name is given, it is equivalent to `{Counter, []}`,\n  which in our case would be invalid, which is why we always pass the initial\n  counter explicitly.\n\n  By replacing the child specification with `{Counter, 0}`, we keep it\n  encapsulated in the `Counter` module. We could now share our\n  `Counter` implementation with other developers and they can add it directly\n  to their supervision tree without worrying about the low-level details of\n  the counter.\n\n  Overall, a child specification can be one of the following:\n\n    * a map representing the child specification itself - as outlined in the\n      \"Child specification\" section\n\n    * a tuple with a module as first element and the start argument as second -\n      such as `{Counter, 0}`. In this case, `Counter.child_spec(0)` is called\n      to retrieve the child specification\n\n    * a module - such as `Counter`. In this case, `Counter.child_spec([])`\n      would be called, which is invalid for the counter, but it is useful in\n      many other cases, especially when you want to pass a list of options\n      to the child process\n\n  If you need to convert a `{module, arg}` tuple or a module child specification to a\n  [child specification](`t:child_spec/0`) or modify a child specification itself,\n  you can use the `Supervisor.child_spec/2` function.\n  For example, to run the counter with a different `:id` and a `:shutdown` value of\n  10 seconds (10_000 milliseconds):\n\n      children = [\n        Supervisor.child_spec({Counter, 0}, id: MyCounter, shutdown: 10_000)\n      ]\n\n  ## Supervisor strategies and options\n\n  So far we have started the supervisor passing a single child as a tuple\n  as well as a strategy called `:one_for_one`:\n\n      children = [\n        {Counter, 0}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_one)\n\n  The first argument given to `start_link/2` is a list of child\n  specifications as defined in the \"child_spec/1\" section above.\n\n  The second argument is a keyword list of options:\n\n    * `:strategy` - the supervision strategy option. It can be either\n      `:one_for_one`, `:rest_for_one` or `:one_for_all`. Required.\n      See the \"Strategies\" section.\n\n    * `:max_restarts` - the maximum number of restarts allowed in\n      a time frame. Defaults to `3`.\n\n    * `:max_seconds` - the time frame in which `:max_restarts` applies.\n      Defaults to `5`.\n\n    * `:auto_shutdown` - the automatic shutdown option. It can be\n      `:never`, `:any_significant`, or `:all_significant`. Optional.\n      See the \"Automatic shutdown\" section.\n\n    * `:name` - a name to register the supervisor process. Supported values are\n      explained in the \"Name registration\" section in the documentation for\n      `GenServer`. Optional.\n\n  ### Strategies\n\n  Supervisors support different supervision strategies (through the\n  `:strategy` option, as seen above):\n\n    * `:one_for_one` - if a child process terminates, only that\n      process is restarted.\n\n    * `:one_for_all` - if a child process terminates, all other child\n      processes are terminated and then all child processes (including\n      the terminated one) are restarted.\n\n    * `:rest_for_one` - if a child process terminates, the terminated child\n      process and the rest of the children started after it, are terminated and\n      restarted.\n\n  In the above, process termination refers to unsuccessful termination, which\n  is determined by the `:restart` option.\n\n  To efficiently supervise children started dynamically, see `DynamicSupervisor`.\n\n  ### Automatic shutdown\n\n  Supervisors have the ability to automatically shut themselves down when child\n  processes marked as `:significant` exit.\n\n  Supervisors support different automatic shutdown options (through\n  the `:auto_shutdown` option, as seen above):\n\n    * `:never` - this is the default, automatic shutdown is disabled.\n\n    * `:any_significant` - if any significant child process exits, the supervisor\n    will automatically shut down its children, then itself.\n\n    * `:all_significant` - when all significant child processes have exited,\n    the supervisor will automatically shut down its children, then itself.\n\n  Only `:transient` and `:temporary` child processes can be marked as significant,\n  and this configuration affects the behavior. Significant `:transient` child\n  processes must exit normally for automatic shutdown to be considered, where\n  `:temporary` child processes may exit for any reason.\n\n  ### Name registration\n\n  A supervisor is bound to the same name registration rules as a `GenServer`.\n  Read more about these rules in the documentation for `GenServer`.\n\n  ## Module-based supervisors\n\n  In the example so far, the supervisor was started by passing the supervision\n  structure to `start_link/2`. However, supervisors can also be created by\n  explicitly defining a supervision module:\n\n      defmodule MyApp.Supervisor do\n        # Automatically defines child_spec/1\n        use Supervisor\n\n        def start_link(init_arg) do\n          Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)\n        end\n\n        @impl true\n        def init(_init_arg) do\n          children = [\n            {Counter, 0}\n          ]\n\n          Supervisor.init(children, strategy: :one_for_one)\n        end\n      end\n\n  The difference between the two approaches is that a module-based\n  supervisor gives you more direct control over how the supervisor\n  is initialized. Instead of calling `Supervisor.start_link/2` with\n  a list of child specifications that are implicitly initialized for us,\n  we must explicitly initialize the children by calling `Supervisor.init/2`\n  inside its `c:init/1` callback. `Supervisor.init/2` accepts the same\n  `:strategy`, `:max_restarts`, and `:max_seconds` options as `start_link/2`.\n\n  > #### `use Supervisor` {: .info}\n  >\n  > When you `use Supervisor`, the `Supervisor` module will\n  > set `@behaviour Supervisor` and define a `child_spec/1`\n  > function, so your module can be used as a child\n  > in a supervision tree.\n\n  `use Supervisor` also defines a `child_spec/1` function which allows\n  us to run `MyApp.Supervisor` as a child of another supervisor or\n  at the top of your supervision tree as:\n\n      children = [\n        MyApp.Supervisor\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_one)\n\n  A general guideline is to use the supervisor without a callback\n  module only at the top of your supervision tree, generally in the\n  `c:Application.start/2` callback. We recommend using module-based\n  supervisors for any other supervisor in your application, so they\n  can run as a child of another supervisor in the tree. The `child_spec/1`\n  generated automatically by `Supervisor` can be customized with the\n  following options:\n\n    * `:id` - the child specification identifier, defaults to the current module\n    * `:restart` - when the supervisor should be restarted, defaults to `:permanent`\n\n  The `@doc` annotation immediately preceding `use Supervisor` will be\n  attached to the generated `child_spec/1` function.\n\n  ## Start and shutdown\n\n  When the supervisor starts, it traverses all child specifications and\n  then starts each child in the order they are defined. This is done by\n  calling the function defined under the `:start` key in the child\n  specification and typically defaults to `start_link/1`.\n\n  The `start_link/1` (or a custom) is then called for each child process.\n  The `start_link/1` function must return `{:ok, pid}` where `pid` is the\n  process identifier of a new process that is linked to the supervisor.\n  The child process usually starts its work by executing the `c:init/1`\n  callback. Generally speaking, the `init` callback is where we initialize\n  and configure the child process.\n\n  The shutdown process happens in reverse order.\n\n  When a supervisor shuts down, it terminates all children in the opposite\n  order they are listed. The termination happens by sending a shutdown exit\n  signal, via `Process.exit(child_pid, :shutdown)`, to the child process and\n  then awaiting for a time interval for the child process to terminate. This\n  interval defaults to 5000 milliseconds. If the child process does not\n  terminate in this interval, the supervisor abruptly terminates the child\n  with reason `:kill`. The shutdown time can be configured in the child\n  specification which is fully detailed in the next section.\n\n  If the child process is not trapping exits, it will shutdown immediately\n  when it receives the first exit signal. If the child process is trapping\n  exits, then the `terminate` callback is invoked, and the child process\n  must terminate in a reasonable time interval before being abruptly\n  terminated by the supervisor.\n\n  In other words, if it is important that a process cleans after itself\n  when your application or the supervision tree is shutting down, then\n  this process must trap exits and its child specification should specify\n  the proper `:shutdown` value, ensuring it terminates within a reasonable\n  interval.\n\n  ## Exit reasons and restarts\n\n  A supervisor restarts a child process depending on its `:restart` configuration.\n  For example, when `:restart` is set to `:transient`, the supervisor does not\n  restart the child in case it exits with reason `:normal`, `:shutdown` or\n  `{:shutdown, term}`.\n\n  Those exits also impact logging. By default, behaviours such as GenServers\n  do not emit error logs when the exit reason is `:normal`, `:shutdown` or\n  `{:shutdown, term}`.\n\n  So one may ask: which exit reason should I choose? There are three options:\n\n    * `:normal` - in such cases, the exit won't be logged, there is no restart\n      in transient mode, and linked processes do not exit\n\n    * `:shutdown` or `{:shutdown, term}` - in such cases, the exit won't be\n      logged, there is no restart in transient mode, and linked processes exit\n      with the same reason unless they're trapping exits\n\n    * any other term - in such cases, the exit will be logged, there are\n      restarts in transient mode, and linked processes exit with the same\n      reason unless they're trapping exits\n\n  Generally speaking, if you are exiting for expected reasons, you want to use\n  `:shutdown` or `{:shutdown, term}`.\n\n  Note that the supervisor that reaches maximum restart intensity will exit with\n  `:shutdown` reason. In this case the supervisor will only be restarted if its\n  child specification was defined with the `:restart` option set to `:permanent`\n  (the default).\n  \"\"\"\n\n  @doc false\n  defmacro __using__(opts) do\n    quote location: :keep, bind_quoted: [opts: opts] do\n      import Supervisor.Spec\n      @behaviour Supervisor\n\n      if not Module.has_attribute?(__MODULE__, :doc) do\n        @doc \"\"\"\n        Returns a specification to start this module under a supervisor.\n\n        See `Supervisor`.\n        \"\"\"\n      end\n\n      def child_spec(init_arg) do\n        default = %{\n          id: __MODULE__,\n          start: {__MODULE__, :start_link, [init_arg]},\n          type: :supervisor\n        }\n\n        Supervisor.child_spec(default, unquote(Macro.escape(opts)))\n      end\n\n      defoverridable child_spec: 1\n    end\n  end\n\n  @doc \"\"\"\n  Callback invoked to start the supervisor and during hot code upgrades.\n\n  Developers typically invoke `Supervisor.init/2` at the end of their\n  init callback to return the proper supervision flags.\n  \"\"\"\n  @callback init(init_arg :: term) ::\n              {:ok,\n               {sup_flags(), [child_spec() | (old_erlang_child_spec :: :supervisor.child_spec())]}}\n              | :ignore\n\n  @typedoc \"Return values of `start_link/2` and `start_link/3`.\"\n  @type on_start ::\n          {:ok, pid}\n          | :ignore\n          | {:error, {:already_started, pid} | {:shutdown, term} | term}\n\n  @typedoc \"Return values of `start_child/2`.\"\n  @type on_start_child ::\n          {:ok, child}\n          | {:ok, child, info :: term}\n          | {:error, {:already_started, child} | :already_present | term}\n\n  @typedoc \"\"\"\n  A child process.\n\n  It can be a PID when the child process was started, or `:undefined` when\n  the child was created by a [dynamic supervisor](`DynamicSupervisor`).\n  \"\"\"\n  @type child :: pid | :undefined\n\n  @typedoc \"The supervisor name.\"\n  @type name :: atom | {:global, term} | {:via, module, term}\n\n  @typedoc \"Option values used by the `start_link/2` and `start_link/3` functions.\"\n  @type option :: {:name, name}\n\n  @typedoc \"The supervisor flags returned on init.\"\n  @type sup_flags() :: %{\n          strategy: strategy(),\n          intensity: non_neg_integer(),\n          period: pos_integer(),\n          auto_shutdown: auto_shutdown()\n        }\n\n  @typedoc \"The supervisor reference.\"\n  @type supervisor :: pid | name | {atom, node}\n\n  @typedoc \"Options given to `start_link/2` and `init/2`.\"\n  @type init_option ::\n          {:strategy, strategy}\n          | {:max_restarts, non_neg_integer}\n          | {:max_seconds, pos_integer}\n          | {:auto_shutdown, auto_shutdown}\n\n  @typedoc \"Supported restart options.\"\n  @type restart :: :permanent | :transient | :temporary\n\n  @typedoc \"Supported shutdown options.\"\n  @type shutdown :: timeout() | :brutal_kill\n\n  @typedoc \"Supported strategies.\"\n  @type strategy :: :one_for_one | :one_for_all | :rest_for_one\n\n  @typedoc \"Supported automatic shutdown options.\"\n  @type auto_shutdown :: :never | :any_significant | :all_significant\n\n  @typedoc \"\"\"\n  Type of a supervised child.\n\n  Whether the supervised child is a worker or a supervisor.\n  \"\"\"\n  @type type :: :worker | :supervisor\n\n  # Note we have inlined all types for readability\n  @typedoc \"\"\"\n  The supervisor child specification.\n\n  It defines how the supervisor should start, stop and restart each of its children.\n  \"\"\"\n  @type child_spec :: %{\n          required(:id) => atom() | term(),\n          required(:start) => {module(), function_name :: atom(), args :: [term()]},\n          optional(:restart) => restart(),\n          optional(:shutdown) => shutdown(),\n          optional(:type) => type(),\n          optional(:modules) => [module()] | :dynamic,\n          optional(:significant) => boolean()\n        }\n\n  @typedoc \"\"\"\n  A module-based child spec.\n\n  This is a form of child spec that you can pass to functions such as `child_spec/2`,\n  `start_child/2`, and `start_link/2`, in addition to the normalized `t:child_spec/0`.\n\n  A module-based child spec can be:\n\n    * a **module** — the supervisor calls `module.child_spec([])` to retrieve the\n      child specification\n\n    * a **two-element tuple** in the shape of `{module, arg}` — the supervisor\n      calls `module.child_spec(arg)` to retrieve the child specification\n\n  \"\"\"\n  @typedoc since: \"1.16.0\"\n  @type module_spec :: {module(), args :: term()} | module()\n\n  @typedoc \"\"\"\n  Options for overriding child specification fields.\n  \"\"\"\n  @type child_spec_overrides :: [\n          id: atom() | term(),\n          start: {module(), atom(), [term()]},\n          restart: restart(),\n          shutdown: shutdown(),\n          type: type(),\n          modules: [module()] | :dynamic,\n          significant: boolean()\n        ]\n\n  @doc \"\"\"\n  Starts a supervisor with the given children.\n\n  `children` is a list of the following forms:\n\n    * a child specification (see `t:child_spec/0`)\n\n    * a module, where the supervisor calls `module.child_spec([])`\n      to retrieve the child specification (see `t:module_spec/0`)\n\n    * a `{module, arg}` tuple, where the supervisor calls `module.child_spec(arg)`\n      to retrieve the child specification (see `t:module_spec/0`)\n\n    * a (old) Erlang-style child specification (see\n      [`:supervisor.child_spec()`](`t::supervisor.child_spec/0`))\n\n  A strategy is required to be provided through the `:strategy` option. See\n  \"Supervisor strategies and options\" for examples and other options.\n\n  The options can also be used to register a supervisor name.\n  The supported values are described under the \"Name registration\"\n  section in the `GenServer` module docs.\n\n  If the supervisor and all child processes are successfully spawned\n  (if the start function of each child process returns `{:ok, child}`,\n  `{:ok, child, info}`, or `:ignore`), this function returns\n  `{:ok, pid}`, where `pid` is the PID of the supervisor. If the supervisor\n  is given a name and a process with the specified name already exists,\n  the function returns `{:error, {:already_started, pid}}`, where `pid`\n  is the PID of that process.\n\n  If the start function of any of the child processes fails or returns an error\n  tuple or an erroneous value, the supervisor first terminates with reason\n  `:shutdown` all the child processes that have already been started, and then\n  terminates itself and returns `{:error, {:shutdown, reason}}`.\n\n  Note that a supervisor started with this function is linked to the parent\n  process and exits not only on crashes but also if the parent process exits\n  with `:normal` reason.\n  \"\"\"\n  @spec start_link(\n          [child_spec | module_spec | (old_erlang_child_spec :: :supervisor.child_spec())],\n          [option | init_option]\n        ) ::\n          {:ok, pid} | {:error, {:already_started, pid} | {:shutdown, term} | term}\n  def start_link(children, options) when is_list(children) do\n    {sup_opts, start_opts} =\n      Keyword.split(options, [:strategy, :max_seconds, :max_restarts, :auto_shutdown])\n\n    start_link(Supervisor.Default, init(children, sup_opts), start_opts)\n  end\n\n  @doc \"\"\"\n  Receives a list of child specifications to initialize and a set of `options`.\n\n  This is typically invoked at the end of the `c:init/1` callback of\n  module-based supervisors. See the sections \"Supervisor strategies and options\" and\n  \"Module-based supervisors\" in the module documentation for more information.\n\n  This function returns a tuple containing the supervisor\n  flags and child specifications.\n\n  ## Examples\n\n      def init(_init_arg) do\n        children = [\n          {Counter, 0}\n        ]\n\n        Supervisor.init(children, strategy: :one_for_one)\n      end\n\n  ## Options\n\n    * `:strategy` - the supervision strategy option. It can be either\n      `:one_for_one`, `:rest_for_one`, or `:one_for_all`\n\n    * `:max_restarts` - the maximum number of restarts allowed in\n      a time frame. Defaults to `3`.\n\n    * `:max_seconds` - the time frame in seconds in which `:max_restarts`\n      applies. Defaults to `5`.\n\n    * `:auto_shutdown` - the automatic shutdown option. It can be either\n      `:never`, `:any_significant`, or `:all_significant`\n\n  The `:strategy` option is required and by default a maximum of 3 restarts\n  is allowed within 5 seconds. Check the `Supervisor` module for a detailed\n  description of the available strategies.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec init(\n          [child_spec | module_spec | (old_erlang_child_spec :: :supervisor.child_spec())],\n          [init_option]\n        ) ::\n          {:ok,\n           {sup_flags(), [child_spec() | (old_erlang_child_spec :: :supervisor.child_spec())]}}\n  def init(children, options) when is_list(children) and is_list(options) do\n    strategy =\n      case options[:strategy] do\n        nil ->\n          raise ArgumentError, \"expected :strategy option to be given\"\n\n        :simple_one_for_one ->\n          IO.warn(\n            \":simple_one_for_one strategy is deprecated, please use DynamicSupervisor instead\"\n          )\n\n          :simple_one_for_one\n\n        other ->\n          other\n      end\n\n    intensity = Keyword.get(options, :max_restarts, 3)\n    period = Keyword.get(options, :max_seconds, 5)\n    auto_shutdown = Keyword.get(options, :auto_shutdown, :never)\n\n    flags = %{\n      strategy: strategy,\n      intensity: intensity,\n      period: period,\n      auto_shutdown: auto_shutdown\n    }\n\n    {:ok, {flags, Enum.map(children, &init_child/1)}}\n  end\n\n  defp init_child(module) when is_atom(module) do\n    init_child({module, []})\n  end\n\n  defp init_child({module, arg}) when is_atom(module) do\n    try do\n      module.child_spec(arg)\n    rescue\n      e in UndefinedFunctionError ->\n        case __STACKTRACE__ do\n          [{^module, :child_spec, [^arg], _} | _] ->\n            raise ArgumentError, child_spec_error(module)\n\n          stack ->\n            reraise e, stack\n        end\n    end\n  end\n\n  defp init_child(map) when is_map(map) do\n    map\n  end\n\n  defp init_child({_, _, _, _, _, _} = tuple) do\n    tuple\n  end\n\n  defp init_child(other) do\n    raise ArgumentError, \"\"\"\n    supervisors expect each child to be one of the following:\n\n      * a module\n      * a {module, arg} tuple\n      * a child specification as a map with at least the :id and :start fields\n      * or a tuple with 6 elements generated by Supervisor.Spec (deprecated)\n\n    Got: #{inspect(other)}\n    \"\"\"\n  end\n\n  defp child_spec_error(module) do\n    if Code.ensure_loaded?(module) do\n      \"\"\"\n      The module #{inspect(module)} was given as a child to a supervisor\n      but it does not implement child_spec/1.\n\n      If you own the given module, please define a child_spec/1 function\n      that receives an argument and returns a child specification as a map.\n      For example:\n\n          def child_spec(opts) do\n            %{\n              id: __MODULE__,\n              start: {__MODULE__, :start_link, [opts]},\n              type: :worker,\n              restart: :permanent,\n              shutdown: 500\n            }\n          end\n\n      Note that \"use Agent\", \"use GenServer\" and so on automatically define\n      this function for you.\n\n      However, if you don't own the given module and it doesn't implement\n      child_spec/1, instead of passing the module name directly as a supervisor\n      child, you will have to pass a child specification as a map:\n\n          %{\n            id: #{inspect(module)},\n            start: {#{inspect(module)}, :start_link, [arg1, arg2]}\n          }\n\n      See the Supervisor documentation for more information\n      \"\"\"\n    else\n      \"The module #{inspect(module)} was given as a child to a supervisor but it does not exist\"\n    end\n  end\n\n  @doc \"\"\"\n  Builds and overrides a child specification.\n\n  Similar to `start_link/2` and `init/2`, it expects a module, `{module, arg}`,\n  or a [child specification](`t:child_spec/0`).\n\n  If a two-element tuple in the shape of `{module, arg}` is given,\n  the child specification is retrieved by calling `module.child_spec(arg)`.\n\n  If a module is given, the child specification is retrieved by calling\n  `module.child_spec([])`.\n\n  After the child specification is retrieved, the fields on `overrides`\n  are directly applied to the child spec. If `overrides` has keys that\n  do not map to any child specification field, an error is raised.\n\n  See the \"Child specification\" section in the module documentation\n  for all of the available keys for overriding.\n\n  ## Examples\n\n  This function is often used to set an `:id` option when\n  the same module needs to be started multiple times in the\n  supervision tree:\n\n      Supervisor.child_spec({Agent, fn -> :ok end}, id: {Agent, 1})\n      #=> %{id: {Agent, 1},\n      #=>   start: {Agent, :start_link, [fn -> :ok end]}}\n\n  \"\"\"\n  @spec child_spec(child_spec() | module_spec(), child_spec_overrides()) :: child_spec()\n  def child_spec(module_or_map, overrides)\n\n  def child_spec({_, _, _, _, _, _} = tuple, _overrides) do\n    raise ArgumentError,\n          \"old tuple-based child specification #{inspect(tuple)} \" <>\n            \"is not supported in Supervisor.child_spec/2\"\n  end\n\n  def child_spec(module_or_map, overrides) do\n    Enum.reduce(overrides, init_child(module_or_map), fn\n      {key, value}, acc\n      when key in [:id, :start, :restart, :shutdown, :type, :modules, :significant] ->\n        Map.put(acc, key, value)\n\n      {key, _value}, _acc ->\n        raise ArgumentError, \"unknown key #{inspect(key)} in child specification override\"\n    end)\n  end\n\n  @doc \"\"\"\n  Starts a module-based supervisor process with the given `module` and `init_arg`.\n\n  To start the supervisor, the `c:init/1` callback will be invoked in the given\n  `module`, with `init_arg` as its argument. The `c:init/1` callback must return a\n  supervisor specification which can be created with the help of the `init/2`\n  function.\n\n  If the `c:init/1` callback returns `:ignore`, this function returns\n  `:ignore` as well and the supervisor terminates with reason `:normal`.\n  If it fails or returns an incorrect value, this function returns\n  `{:error, term}` where `term` is a term with information about the\n  error, and the supervisor terminates with reason `term`.\n\n  The `:name` option can also be given in order to register a supervisor\n  name, the supported values are described in the \"Name registration\"\n  section in the `GenServer` module docs.\n  \"\"\"\n\n  # It is important to keep the two-arity spec because it is a catch-all\n  # to start_link(children, options).\n  @spec start_link(module, term) :: on_start\n  @spec start_link(module, term, [option]) :: on_start\n  def start_link(module, init_arg, options \\\\ []) when is_list(options) do\n    case Keyword.get(options, :name) do\n      nil ->\n        :supervisor.start_link(module, init_arg)\n\n      atom when is_atom(atom) ->\n        :supervisor.start_link({:local, atom}, module, init_arg)\n\n      {:global, _term} = tuple ->\n        :supervisor.start_link(tuple, module, init_arg)\n\n      {:via, via_module, _term} = tuple when is_atom(via_module) ->\n        :supervisor.start_link(tuple, module, init_arg)\n\n      other ->\n        raise ArgumentError, \"\"\"\n        expected :name option to be one of the following:\n\n          * nil\n          * atom\n          * {:global, term}\n          * {:via, module, term}\n\n        Got: #{inspect(other)}\n        \"\"\"\n    end\n  end\n\n  @doc \"\"\"\n  Adds a child specification to `supervisor` and starts that child.\n\n  `child_spec` should be a valid child specification. The child process will\n  be started as defined in the child specification.\n\n  If a child specification with the specified ID already exists, `child_spec` is\n  discarded and this function returns an error with `:already_started` or\n  `:already_present` if the corresponding child process is running or not,\n  respectively.\n\n  If the child process start function returns `{:ok, child}` or `{:ok, child,\n  info}`, then child specification and PID are added to the supervisor and\n  this function returns the same value.\n\n  If the child process start function returns `:ignore`, the child specification\n  is added to the supervisor, the PID is set to `:undefined` and this function\n  returns `{:ok, :undefined}`.\n\n  If the child process start function returns an error tuple or an erroneous\n  value, or if it fails, the child specification is discarded and this function\n  returns `{:error, error}` where `error` is a term containing information about\n  the error and child specification.\n\n  > #### Order Among Children {: .tip}\n  >\n  > The child specification is **appended** to the children of `supervisor`.\n  > This guarantees that semantics of things such as the `:rest_for_one` strategy\n  > are preserved correctly.\n  \"\"\"\n  @spec start_child(\n          supervisor,\n          child_spec | module_spec | (old_erlang_child_spec :: :supervisor.child_spec())\n        ) :: on_start_child\n  def start_child(supervisor, {_, _, _, _, _, _} = child_spec) do\n    call(supervisor, {:start_child, child_spec})\n  end\n\n  def start_child(supervisor, args) when is_list(args) do\n    IO.warn_once(\n      {__MODULE__, :start_child},\n      fn ->\n        \"Supervisor.start_child/2 with a list of args is deprecated, please use DynamicSupervisor instead\"\n      end,\n      _stacktrace_drop_levels = 2\n    )\n\n    call(supervisor, {:start_child, args})\n  end\n\n  def start_child(supervisor, child_spec) do\n    call(supervisor, {:start_child, Supervisor.child_spec(child_spec, [])})\n  end\n\n  @doc \"\"\"\n  Terminates the given child identified by `child_id`.\n\n  The process is terminated, if there's one. The child specification is\n  kept unless the child is temporary.\n\n  A non-temporary child process may later be restarted by the supervisor.\n  The child process can also be restarted explicitly by calling `restart_child/2`.\n  Use `delete_child/2` to remove the child specification.\n\n  If successful, this function returns `:ok`. If there is no child\n  specification for the given child ID, this function returns\n  `{:error, :not_found}`.\n  \"\"\"\n  @spec terminate_child(supervisor, term()) :: :ok | {:error, :not_found}\n  def terminate_child(supervisor, child_id)\n\n  def terminate_child(supervisor, pid) when is_pid(pid) do\n    IO.warn(\n      \"Supervisor.terminate_child/2 with a PID is deprecated, please use DynamicSupervisor instead\"\n    )\n\n    call(supervisor, {:terminate_child, pid})\n  end\n\n  def terminate_child(supervisor, child_id) do\n    call(supervisor, {:terminate_child, child_id})\n  end\n\n  @doc \"\"\"\n  Deletes the child specification identified by `child_id`.\n\n  The corresponding child process must not be running; use `terminate_child/2`\n  to terminate it if it's running.\n\n  If successful, this function returns `:ok`. This function may return an error\n  with an appropriate error tuple if the `child_id` is not found, or if the\n  current process is running or being restarted.\n  \"\"\"\n  @spec delete_child(supervisor, term()) :: :ok | {:error, error}\n        when error: :not_found | :running | :restarting\n  def delete_child(supervisor, child_id) do\n    call(supervisor, {:delete_child, child_id})\n  end\n\n  @doc \"\"\"\n  Restarts a child process identified by `child_id`.\n\n  The child specification must exist and the corresponding child process must not\n  be running.\n\n  Note that for temporary children, the child specification is automatically deleted\n  when the child terminates, and thus it is not possible to restart such children.\n\n  If the child process start function returns `{:ok, child}` or `{:ok, child, info}`,\n  the PID is added to the supervisor and this function returns the same value.\n\n  If the child process start function returns `:ignore`, the PID remains set to\n  `:undefined` and this function returns `{:ok, :undefined}`.\n\n  This function may return an error with an appropriate error tuple if the\n  `child_id` is not found, or if the current process is running or being\n  restarted.\n\n  If the child process start function returns an error tuple or an erroneous value,\n  or if it fails, this function returns `{:error, error}`.\n  \"\"\"\n  @spec restart_child(supervisor, term()) :: {:ok, child} | {:ok, child, term} | {:error, error}\n        when error: :not_found | :running | :restarting | term\n  def restart_child(supervisor, child_id) do\n    call(supervisor, {:restart_child, child_id})\n  end\n\n  @doc \"\"\"\n  Returns a list with information about all children of the given supervisor.\n\n  Note that calling this function when supervising a large number of children\n  under low memory conditions can bring the system down due to an out of memory\n  error.\n\n  This function returns a list of `{id, child, type, modules}` tuples, where:\n\n    * `id` - as defined in the child specification\n\n    * `child` - the PID of the corresponding child process, `:restarting` if the\n      process is about to be restarted, or `:undefined` if there is no such\n      process\n\n    * `type` - `:worker` or `:supervisor`, as specified by the child specification\n\n    * `modules` - as specified by the child specification\n\n  \"\"\"\n  @spec which_children(supervisor) :: [\n          # inlining module() | :dynamic here because :supervisor.modules() is not exported\n          {term() | :undefined, child | :restarting, :worker | :supervisor, [module()] | :dynamic}\n        ]\n  def which_children(supervisor) do\n    call(supervisor, :which_children)\n  end\n\n  @doc \"\"\"\n  Returns a map containing count values for the given supervisor.\n\n  The map contains the following keys:\n\n    * `:specs` - the total count of children, dead or alive\n\n    * `:active` - the count of all actively running child processes managed by\n      this supervisor\n\n    * `:supervisors` - the count of all supervisors whether or not these\n      child supervisors are still alive\n\n    * `:workers` - the count of all workers, whether or not these child workers\n      are still alive\n\n  \"\"\"\n  @spec count_children(supervisor) :: %{\n          specs: non_neg_integer,\n          active: non_neg_integer,\n          supervisors: non_neg_integer,\n          workers: non_neg_integer\n        }\n  def count_children(supervisor) do\n    call(supervisor, :count_children) |> :maps.from_list()\n  end\n\n  @doc \"\"\"\n  Synchronously stops the given supervisor with the given `reason`.\n\n  It returns `:ok` if the supervisor terminates with the given\n  reason. If it terminates with another reason, the call exits.\n\n  This function keeps OTP semantics regarding error reporting.\n  If the reason is any other than `:normal`, `:shutdown` or\n  `{:shutdown, _}`, an error report is logged.\n  \"\"\"\n  @spec stop(supervisor, reason :: term, timeout) :: :ok\n  def stop(supervisor, reason \\\\ :normal, timeout \\\\ :infinity) do\n    GenServer.stop(supervisor, reason, timeout)\n  end\n\n  @compile {:inline, call: 2}\n\n  defp call(supervisor, req) do\n    GenServer.call(supervisor, req, :infinity)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/system.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule System do\n  @moduledoc \"\"\"\n  The `System` module provides functions that interact directly\n  with the VM or the host system.\n\n  ## Time\n\n  The `System` module also provides functions that work with time,\n  returning different times kept by the system with support for\n  different time units.\n\n  One of the complexities in relying on system times is that they\n  may be adjusted. For example, when you enter and leave daylight\n  saving time, the system clock will be adjusted, often adding\n  or removing one hour. We call such changes \"time warps\". In\n  order to understand how such changes may be harmful, imagine\n  the following code:\n\n      ## DO NOT DO THIS\n      prev = System.os_time()\n      # ... execute some code ...\n      next = System.os_time()\n      diff = next - prev\n\n  If, while the code is executing, the system clock changes,\n  some code that executed in 1 second may be reported as taking\n  over 1 hour! To address such concerns, the VM provides a\n  monotonic time via `System.monotonic_time/0` which never\n  decreases and does not leap:\n\n      ## DO THIS\n      prev = System.monotonic_time()\n      # ... execute some code ...\n      next = System.monotonic_time()\n      diff = next - prev\n\n  Generally speaking, the VM provides three time measurements:\n\n    * `os_time/0` - the time reported by the operating system (OS). This time may be\n      adjusted forwards or backwards in time with no limitation;\n\n    * `system_time/0` - the VM view of the `os_time/0`. The system time and operating\n      system time may not match in case of time warps although the VM works towards\n      aligning them. This time is not monotonic (i.e., it may decrease)\n      as its behavior is configured [by the VM time warp\n      mode](https://www.erlang.org/doc/apps/erts/time_correction.html#Time_Warp_Modes);\n\n    * `monotonic_time/0` - a monotonically increasing time provided\n      by the Erlang VM. This is not strictly monotonically increasing. Multiple\n      sequential calls of the function may return the same value.\n\n  The time functions in this module work in the `:native` unit\n  (unless specified otherwise), which is operating system dependent. Most of\n  the time, all calculations are done in the `:native` unit, to\n  avoid loss of precision, with `convert_time_unit/3` being\n  invoked at the end to convert to a specific time unit like\n  `:millisecond` or `:microsecond`. See the `t:time_unit/0` type for\n  more information.\n\n  For a more complete rundown on the VM support for different\n  times, see the [chapter on time and time\n  correction](https://www.erlang.org/doc/apps/erts/time_correction.html)\n  in the Erlang docs.\n  \"\"\"\n\n  defmodule EnvError do\n    @moduledoc \"\"\"\n    An exception raised when a system environment variable is not set.\n\n    For example, see `System.fetch_env!/1`.\n    \"\"\"\n\n    defexception [:env]\n\n    @impl true\n    def message(%{env: env}) do\n      \"could not fetch environment variable #{inspect(env)} because it is not set\"\n    end\n  end\n\n  @typedoc \"\"\"\n  The time unit to be passed to functions like `monotonic_time/1` and others.\n\n  The `:second`, `:millisecond`, `:microsecond` and `:nanosecond` time\n  units controls the return value of the functions that accept a time unit.\n\n  A time unit can also be a strictly positive integer. In this case, it\n  represents the \"parts per second\": the time will be returned in `1 /\n  parts_per_second` seconds. For example, using the `:millisecond` time unit\n  is equivalent to using `1000` as the time unit (as the time will be returned\n  in 1/1000 seconds - milliseconds).\n  \"\"\"\n  @type time_unit ::\n          :second\n          | :millisecond\n          | :microsecond\n          | :nanosecond\n          | pos_integer\n\n  @type signal ::\n          :sigabrt\n          | :sigalrm\n          | :sigchld\n          | :sighup\n          | :sigquit\n          | :sigstop\n          | :sigterm\n          | :sigtstp\n          | :sigusr1\n          | :sigusr2\n\n  @type cmd_opts :: [\n          into: Collectable.t(),\n          lines: pos_integer(),\n          cd: Path.t(),\n          env: [{binary(), binary() | nil}],\n          arg0: binary(),\n          stderr_to_stdout: boolean(),\n          use_stdio: boolean(),\n          parallelism: boolean()\n        ]\n\n  @type shell_opts :: [\n          into: Collectable.t(),\n          lines: pos_integer(),\n          cd: Path.t(),\n          env: [{binary(), binary() | nil}],\n          stderr_to_stdout: boolean(),\n          use_stdio: boolean(),\n          parallelism: boolean(),\n          close_stdin: boolean()\n        ]\n\n  @vm_signals [:sigquit, :sigterm, :sigusr1]\n  @os_signals [:sighup, :sigabrt, :sigalrm, :sigusr2, :sigchld, :sigstop, :sigtstp]\n  @signals @vm_signals ++ @os_signals\n\n  @base_dir :filename.join(__DIR__, \"../../..\")\n  @version_file :filename.join(@base_dir, \"VERSION\")\n\n  defp strip(iodata) do\n    :re.replace(iodata, \"^[\\s\\r\\n\\t]+|[\\s\\r\\n\\t]+$\", \"\", [:global, return: :binary])\n  end\n\n  defp read_stripped(path) do\n    case :file.read_file(path) do\n      {:ok, binary} ->\n        strip(binary)\n\n      _ ->\n        \"\"\n    end\n  end\n\n  # Read and strip the version from the VERSION file.\n  defmacrop get_version do\n    case read_stripped(@version_file) do\n      \"\" -> raise \"could not read the version number from VERSION\"\n      data -> data\n    end\n  end\n\n  # Returns OTP version that Elixir was compiled with.\n  defmacrop get_otp_release do\n    :erlang.list_to_binary(:erlang.system_info(:otp_release))\n  end\n\n  # Tries to run \"git rev-parse --short=7 HEAD\". In the case of success returns\n  # the short revision hash. If that fails, returns an empty string.\n  defmacrop get_revision do\n    null =\n      case :os.type() do\n        {:win32, _} -> ~c\"NUL\"\n        _ -> ~c\"/dev/null\"\n      end\n\n    ~c\"git rev-parse --short=7 HEAD 2> \"\n    |> Kernel.++(null)\n    |> :os.cmd()\n    |> strip()\n  end\n\n  defp revision, do: get_revision()\n\n  # Get the date at compilation time.\n  # Follows https://reproducible-builds.org/specs/source-date-epoch/\n  defmacrop get_date do\n    unix_epoch =\n      if source_date_epoch = :os.getenv(~c\"SOURCE_DATE_EPOCH\") do\n        try do\n          List.to_integer(source_date_epoch)\n        rescue\n          _ -> nil\n        end\n      end\n\n    unix_epoch = unix_epoch || :os.system_time(:second)\n\n    {{year, month, day}, {hour, minute, second}} =\n      :calendar.gregorian_seconds_to_datetime(unix_epoch + 62_167_219_200)\n\n    \"~4..0b-~2..0b-~2..0bT~2..0b:~2..0b:~2..0bZ\"\n    |> :io_lib.format([year, month, day, hour, minute, second])\n    |> :erlang.iolist_to_binary()\n  end\n\n  @doc \"\"\"\n  Returns the endianness.\n  \"\"\"\n  @spec endianness() :: :little | :big\n  def endianness do\n    :erlang.system_info(:endian)\n  end\n\n  @doc \"\"\"\n  Returns the endianness the system was compiled with.\n  \"\"\"\n  @endianness :erlang.system_info(:endian)\n  @spec compiled_endianness() :: :little | :big\n  def compiled_endianness do\n    @endianness\n  end\n\n  @doc \"\"\"\n  Elixir version information.\n\n  Returns Elixir's version as binary.\n  \"\"\"\n  @spec version() :: String.t()\n  def version, do: get_version()\n\n  @doc \"\"\"\n  Elixir build information.\n\n  Returns a map with the Elixir version, the Erlang/OTP release it was compiled\n  with, a short Git revision hash and the date and time it was built.\n\n  Every value in the map is a string, and these are:\n\n    * `:build` - the Elixir version, short Git revision hash and\n      Erlang/OTP release it was compiled with\n    * `:date` - a string representation of the ISO8601 date and time it was built\n    * `:otp_release` - OTP release it was compiled with\n    * `:revision` - short Git revision hash. If Git was not available at building\n      time, it is set to `\"\"`\n    * `:version` - the Elixir version\n\n  One should not rely on the specific formats returned by each of those fields.\n  Instead one should use specialized functions, such as `version/0` to retrieve\n  the Elixir version and `otp_release/0` to retrieve the Erlang/OTP release.\n\n  ## Examples\n\n      iex> System.build_info()\n      %{\n        build: \"1.9.0-dev (772a00a0c) (compiled with Erlang/OTP 21)\",\n        date: \"2018-12-24T01:09:21Z\",\n        otp_release: \"21\",\n        revision: \"772a00a0c\",\n        version: \"1.9.0-dev\"\n      }\n\n  \"\"\"\n  @spec build_info() :: %{\n          build: String.t(),\n          date: String.t(),\n          revision: String.t(),\n          version: String.t(),\n          otp_release: String.t()\n        }\n  def build_info do\n    %{\n      build: build(),\n      date: get_date(),\n      revision: revision(),\n      version: version(),\n      otp_release: get_otp_release()\n    }\n  end\n\n  # Returns a string of the build info\n  defp build do\n    {:ok, v} = Version.parse(version())\n\n    revision_string = if v.pre != [] and revision() != \"\", do: \" (#{revision()})\", else: \"\"\n    otp_version_string = \" (compiled with Erlang/OTP #{get_otp_release()})\"\n\n    version() <> revision_string <> otp_version_string\n  end\n\n  @doc \"\"\"\n  Lists command line arguments.\n\n  Returns the list of command line arguments passed to the program.\n  \"\"\"\n  @spec argv() :: [String.t()]\n  def argv do\n    :elixir_config.get(:argv)\n  end\n\n  @doc \"\"\"\n  Modifies command line arguments.\n\n  Changes the list of command line arguments. Use it with caution,\n  as it destroys any previous argv information.\n  \"\"\"\n  @spec argv([String.t()]) :: :ok\n  def argv(args) do\n    :elixir_config.put(:argv, args)\n  end\n\n  @doc \"\"\"\n  Marks if the system should halt or not at the end of ARGV processing.\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec no_halt(boolean) :: :ok\n  def no_halt(boolean) when is_boolean(boolean) do\n    :elixir_config.put(:no_halt, boolean)\n  end\n\n  @doc \"\"\"\n  Checks if the system will halt or not at the end of ARGV processing.\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec no_halt() :: boolean\n  def no_halt() do\n    :elixir_config.get(:no_halt)\n  end\n\n  @doc \"\"\"\n  Current working directory.\n\n  Returns the current working directory or `nil` if one\n  is not available.\n  \"\"\"\n  @deprecated \"Use File.cwd/0 instead\"\n  @spec cwd() :: String.t() | nil\n  def cwd do\n    case File.cwd() do\n      {:ok, cwd} -> cwd\n      _ -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Current working directory, exception on error.\n\n  Returns the current working directory or raises `RuntimeError`.\n  \"\"\"\n  @deprecated \"Use File.cwd!/0 instead\"\n  @spec cwd!() :: String.t()\n  def cwd! do\n    case File.cwd() do\n      {:ok, cwd} ->\n        cwd\n\n      _ ->\n        raise \"could not get a current working directory, the current location is not accessible\"\n    end\n  end\n\n  @doc \"\"\"\n  User home directory.\n\n  Returns the user home directory (platform independent).\n  \"\"\"\n  @spec user_home() :: String.t() | nil\n  def user_home do\n    case :init.get_argument(:home) do\n      {:ok, [[home] | _]} ->\n        encoding = :file.native_name_encoding()\n        :unicode.characters_to_binary(home, encoding, encoding)\n\n      _ ->\n        nil\n    end\n  end\n\n  @doc \"\"\"\n  User home directory, exception on error.\n\n  Same as `user_home/0` but raises `RuntimeError`\n  instead of returning `nil` if no user home is set.\n  \"\"\"\n  @spec user_home!() :: String.t()\n  def user_home! do\n    user_home() || raise \"could not find the user home, please set the HOME environment variable\"\n  end\n\n  @doc ~S\"\"\"\n  Writable temporary directory.\n\n  Returns a writable temporary directory.\n  Searches for directories in the following order:\n\n    1. the directory named by the TMPDIR environment variable\n    2. the directory named by the TEMP environment variable\n    3. the directory named by the TMP environment variable\n    4. `C:\\TMP` on Windows or `/tmp` on Unix-like operating systems\n    5. as a last resort, the current working directory\n\n  Returns `nil` if none of the above are writable.\n  \"\"\"\n  @spec tmp_dir() :: String.t() | nil\n  def tmp_dir do\n    write_env_tmp_dir(~c\"TMPDIR\") || write_env_tmp_dir(~c\"TEMP\") || write_env_tmp_dir(~c\"TMP\") ||\n      write_tmp_dir(~c\"/tmp\") || write_cwd_tmp_dir()\n  end\n\n  defp write_cwd_tmp_dir do\n    case File.cwd() do\n      {:ok, cwd} -> write_tmp_dir(cwd)\n      _ -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Writable temporary directory, exception on error.\n\n  Same as `tmp_dir/0` but raises `RuntimeError`\n  instead of returning `nil` if no temp dir is set.\n  \"\"\"\n  @spec tmp_dir!() :: String.t()\n  def tmp_dir! do\n    tmp_dir() ||\n      raise \"could not get a writable temporary directory, please set the TMPDIR environment variable\"\n  end\n\n  defp write_env_tmp_dir(env) do\n    case :os.getenv(env) do\n      false -> nil\n      tmp -> write_tmp_dir(tmp)\n    end\n  end\n\n  defp write_tmp_dir(dir) do\n    case File.stat(dir) do\n      {:ok, stat} ->\n        case {stat.type, stat.access} do\n          {:directory, access} when access in [:read_write, :write] ->\n            IO.chardata_to_string(dir)\n\n          _ ->\n            nil\n        end\n\n      {:error, _} ->\n        nil\n    end\n  end\n\n  @doc \"\"\"\n  Registers a program exit handler function.\n\n  Registers a function that will be invoked at the end of an Elixir script.\n  A script is typically started via the command line via the `elixir` and\n  `mix` executables.\n\n  The handler always executes in a different process from the one it was\n  registered in. As a consequence, any resources managed by the calling process\n  (ETS tables, open files, and others) won't be available by the time the handler\n  function is invoked.\n\n  The function must receive the exit status code as an argument.\n\n  If the VM terminates programmatically, via `System.stop/1`, `System.halt/1`,\n  or exit signals, the `at_exit/1` callbacks are not guaranteed to be executed.\n  \"\"\"\n  @spec at_exit((non_neg_integer -> any)) :: :ok\n  def at_exit(fun) when is_function(fun, 1) do\n    :elixir_config.update(:at_exit, &[fun | &1])\n    :ok\n  end\n\n  defmodule SignalHandler do\n    @moduledoc false\n    @behaviour :gen_event\n\n    @impl true\n    def init({event, fun}) do\n      {:ok, {event, fun}}\n    end\n\n    @impl true\n    def handle_call(_message, state) do\n      {:ok, :ok, state}\n    end\n\n    @impl true\n    def handle_event(signal, {event, fun}) do\n      if signal == event, do: :ok = fun.()\n      {:ok, {event, fun}}\n    end\n\n    @impl true\n    def handle_info(_, {event, fun}) do\n      {:ok, {event, fun}}\n    end\n  end\n\n  @doc \"\"\"\n  Traps the given `signal` to execute the `fun`.\n\n  > #### Avoid setting traps in libraries {: .warning}\n  >\n  > Trapping signals may have strong implications\n  > on how a system shuts down and behaves in production and\n  > therefore it is extremely discouraged for libraries to\n  > set their own traps. Instead, they should redirect users\n  > to configure them themselves. The only cases where it is\n  > acceptable for libraries to set their own traps is when\n  > using Elixir in script mode, such as in `.exs` files and\n  > via Mix tasks.\n\n  An optional `id` that uniquely identifies the function\n  can be given, otherwise a unique one is automatically\n  generated. If a previously registered `id` is given,\n  this function returns an error tuple. The `id` can be\n  used to remove a registered signal by calling\n  `untrap_signal/2`.\n\n  The given `fun` receives no arguments and it must return\n  `:ok`.\n\n  It returns `{:ok, id}` in case of success,\n  `{:error, :already_registered}` in case the id has already\n  been registered for the given signal, or `{:error, :not_sup}`\n  in case trapping exists is not supported by the current OS.\n\n  The first time a signal is trapped, it will override the\n  default behavior from the operating system. If the same\n  signal is trapped multiple times, subsequent functions\n  given to `trap_signal` will execute *first*. In other\n  words, you can consider each function is prepended to\n  the signal handler.\n\n  By default, the Erlang VM register traps to the three\n  signals:\n\n    * `:sigstop` - gracefully shuts down the VM with `stop/0`\n    * `:sigquit` - halts the VM via `halt/0`\n    * `:sigusr1` - halts the VM via status code of 1\n\n  Therefore, if you add traps to the signals above, the\n  default behavior above will be executed after all user\n  signals.\n\n  ## Implementation notes\n\n  All signals run from a single process. Therefore, blocking the\n  `fun` will block subsequent traps. It is also not possible to add\n  or remove traps from within a trap itself.\n\n  Internally, this functionality is built on top of `:os.set_signal/2`.\n  When you register a trap, Elixir automatically sets it to `:handle`\n  and it reverts it back to `:default` once all traps are removed\n  (except for `:sigquit`, `:sigterm`, and `:sigusr1` which are always\n  handled). If you or a library call `:os.set_signal/2` directly,\n  it may disable Elixir traps (or Elixir may override your configuration).\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec trap_signal(signal, (-> :ok)) :: {:ok, reference()} | {:error, :not_sup}\n  @spec trap_signal(signal, id, (-> :ok)) ::\n          {:ok, id} | {:error, :already_registered} | {:error, :not_sup}\n        when id: term()\n  def trap_signal(signal, id \\\\ make_ref(), fun)\n      when signal in @signals and is_function(fun, 0) do\n    :elixir_config.serial(fn ->\n      gen_id = {signal, id}\n\n      if {SignalHandler, gen_id} in signal_handlers() do\n        {:error, :already_registered}\n      else\n        try do\n          :os.set_signal(signal, :handle)\n        rescue\n          _ -> {:error, :not_sup}\n        else\n          :ok ->\n            :ok =\n              :gen_event.add_handler(:erl_signal_server, {SignalHandler, gen_id}, {signal, fun})\n\n            {:ok, id}\n        end\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Removes a previously registered `signal` with `id`.\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec untrap_signal(signal, id) :: :ok | {:error, :not_found} when id: term\n  def untrap_signal(signal, id) when signal in @signals do\n    :elixir_config.serial(fn ->\n      gen_id = {signal, id}\n\n      case :gen_event.delete_handler(:erl_signal_server, {SignalHandler, gen_id}, :delete) do\n        :ok ->\n          if not trapping?(signal) do\n            :os.set_signal(signal, :default)\n          end\n\n          :ok\n\n        {:error, :module_not_found} ->\n          {:error, :not_found}\n      end\n    end)\n  end\n\n  defp trapping?(signal) do\n    signal in @vm_signals or\n      Enum.any?(signal_handlers(), &match?({_, {^signal, _}}, &1))\n  end\n\n  defp signal_handlers do\n    :gen_event.which_handlers(:erl_signal_server)\n  end\n\n  @doc \"\"\"\n  Locates an executable on the system.\n\n  This function looks up an executable program given\n  its name using the environment variable PATH on Windows and Unix-like\n  operating systems. It also considers the proper executable\n  extension for each operating system, so for Windows it will try to\n  lookup files with `.com`, `.cmd` or similar extensions.\n  \"\"\"\n  @spec find_executable(binary) :: binary | nil\n  def find_executable(program) when is_binary(program) do\n    assert_no_null_byte!(program, \"System.find_executable/1\")\n\n    case :os.find_executable(String.to_charlist(program)) do\n      false -> nil\n      other -> List.to_string(other)\n    end\n  end\n\n  @doc \"\"\"\n  Returns all system environment variables.\n\n  The returned value is a map containing name-value pairs.\n  Variable names and their values are strings.\n  \"\"\"\n  @spec get_env() :: %{optional(String.t()) => String.t()}\n  def get_env do\n    Map.new(:os.env(), fn {k, v} ->\n      {IO.chardata_to_string(k), IO.chardata_to_string(v)}\n    end)\n  end\n\n  @doc \"\"\"\n  Returns the value of the given environment variable.\n\n  The returned value of the environment variable\n  `varname` is a string. If the environment variable\n  is not set, returns the string specified in `default` or\n  `nil` if none is specified.\n\n  ## Examples\n\n      iex> System.get_env(\"PORT\")\n      \"4000\"\n\n      iex> System.get_env(\"NOT_SET\")\n      nil\n\n      iex> System.get_env(\"NOT_SET\", \"4001\")\n      \"4001\"\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec get_env(String.t(), String.t()) :: String.t()\n  @spec get_env(String.t(), nil) :: String.t() | nil\n  def get_env(varname, default \\\\ nil)\n      when is_binary(varname) and\n             (is_binary(default) or is_nil(default)) do\n    case :os.getenv(String.to_charlist(varname)) do\n      false -> default\n      other -> List.to_string(other)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the value of the given environment variable or `:error` if not found.\n\n  If the environment variable `varname` is set, then `{:ok, value}` is returned\n  where `value` is a string. If `varname` is not set, `:error` is returned.\n\n  ## Examples\n\n      iex> System.fetch_env(\"PORT\")\n      {:ok, \"4000\"}\n\n      iex> System.fetch_env(\"NOT_SET\")\n      :error\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec fetch_env(String.t()) :: {:ok, String.t()} | :error\n  def fetch_env(varname) when is_binary(varname) do\n    case :os.getenv(String.to_charlist(varname)) do\n      false -> :error\n      other -> {:ok, List.to_string(other)}\n    end\n  end\n\n  @doc \"\"\"\n  Returns the value of the given environment variable or raises if not found.\n\n  Same as `get_env/1` but raises instead of returning `nil` when the variable is\n  not set.\n\n  ## Examples\n\n      iex> System.fetch_env!(\"PORT\")\n      \"4000\"\n\n      iex> System.fetch_env!(\"NOT_SET\")\n      ** (System.EnvError) could not fetch environment variable \"NOT_SET\" because it is not set\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec fetch_env!(String.t()) :: String.t()\n  def fetch_env!(varname) when is_binary(varname) do\n    get_env(varname) || raise(EnvError, env: varname)\n  end\n\n  @doc \"\"\"\n  Erlang VM process identifier.\n\n  Returns the process identifier of the current Erlang emulator\n  in the format most commonly used by the operating system environment.\n\n  For more information, see `:os.getpid/0`.\n  \"\"\"\n  @deprecated \"Use System.pid/0 instead\"\n  @spec get_pid() :: binary\n  def get_pid, do: IO.iodata_to_binary(:os.getpid())\n\n  @doc \"\"\"\n  Sets an environment variable value.\n\n  Sets a new `value` for the environment variable `varname`.\n  \"\"\"\n  @spec put_env(binary, binary) :: :ok\n  def put_env(varname, value) when is_binary(varname) and is_binary(value) do\n    case :binary.match(varname, \"=\") do\n      {_, _} ->\n        raise ArgumentError,\n              \"cannot execute System.put_env/2 for key with \\\"=\\\", got: #{inspect(varname)}\"\n\n      :nomatch ->\n        :os.putenv(String.to_charlist(varname), String.to_charlist(value))\n        :ok\n    end\n  end\n\n  @doc \"\"\"\n  Sets multiple environment variables.\n\n  Sets a new value for each environment variable corresponding\n  to each `{key, value}` pair in `enum`. Keys and non-nil values\n  are automatically converted to charlists. `nil` values erase\n  the given keys.\n\n  Overall, this is a convenience wrapper around `put_env/2` and\n  `delete_env/2` with support for different key and value formats.\n  \"\"\"\n  @spec put_env(Enumerable.t()) :: :ok\n  def put_env(enum) do\n    Enum.each(enum, fn\n      {key, nil} ->\n        :os.unsetenv(to_charlist(key))\n\n      {key, val} ->\n        key = to_charlist(key)\n\n        case :string.find(key, \"=\") do\n          :nomatch ->\n            :os.putenv(key, to_charlist(val))\n\n          _ ->\n            raise ArgumentError,\n                  \"cannot execute System.put_env/1 for key with \\\"=\\\", got: #{inspect(key)}\"\n        end\n    end)\n  end\n\n  @doc \"\"\"\n  Deletes an environment variable.\n\n  Removes the variable `varname` from the environment.\n  \"\"\"\n  @spec delete_env(String.t()) :: :ok\n  def delete_env(varname) do\n    :os.unsetenv(String.to_charlist(varname))\n    :ok\n  end\n\n  @doc \"\"\"\n  Deprecated mechanism to retrieve the last exception stacktrace.\n\n  It always return an empty list.\n  \"\"\"\n  @deprecated \"Use __STACKTRACE__ instead\"\n  def stacktrace do\n    []\n  end\n\n  @doc \"\"\"\n  Immediately halts the Erlang runtime system.\n\n  Terminates the Erlang runtime system without properly shutting down\n  applications and ports. Please see `stop/1` for a careful shutdown of the\n  system.\n\n  `status` must be a non-negative integer, the atom `:abort` or a binary.\n\n    * If an integer, the runtime system exits with the integer value which\n      is returned to the operating system.\n\n    * If `:abort`, the runtime system aborts producing a core dump, if that is\n      enabled in the operating system.\n\n    * If a string, an Erlang crash dump is produced with status as slogan,\n      and then the runtime system exits with status code 1.\n\n  Note that on many platforms, only the status codes 0-255 are supported\n  by the operating system.\n\n  For more information, see `:erlang.halt/1`.\n\n  ## Examples\n\n      System.halt(0)\n      System.halt(1)\n      System.halt(:abort)\n\n  \"\"\"\n  @spec halt() :: no_return\n  @spec halt(non_neg_integer | binary | :abort) :: no_return\n  def halt(status \\\\ 0)\n\n  def halt(status) when is_integer(status) or status == :abort do\n    :erlang.halt(status)\n  end\n\n  def halt(status) when is_binary(status) do\n    :erlang.halt(String.to_charlist(status))\n  end\n\n  @doc \"\"\"\n  Returns the operating system PID for the current Erlang runtime system instance.\n\n  Returns a string containing the (usually) numerical identifier for a process.\n  On Unix-like operating systems, this is typically the return value of the `getpid()` system call.\n  On Windows, the process ID as returned by the `GetCurrentProcessId()` system\n  call is used.\n\n  ## Examples\n\n      System.pid()\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec pid :: String.t()\n  def pid do\n    List.to_string(:os.getpid())\n  end\n\n  @doc \"\"\"\n  Restarts all applications in the Erlang runtime system.\n\n  All applications are taken down smoothly, all code is unloaded, and all ports\n  are closed before the system starts all applications once again.\n\n  ## Examples\n\n      System.restart()\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec restart :: :ok\n  defdelegate restart(), to: :init\n\n  @doc \"\"\"\n  Asynchronously and carefully stops the Erlang runtime system.\n\n  All applications are taken down smoothly, all code is unloaded, and all ports\n  are closed before the system terminates by calling `halt/1`.\n\n  `status` must be a non-negative integer or a binary.\n\n    * If an integer, the runtime system exits with the integer value which is\n      returned to the operating system. On many platforms, only the status codes\n      0-255 are supported by the operating system.\n\n    * If a binary, an Erlang crash dump is produced with status as slogan, and\n      then the runtime system exits with status code 1.\n\n  Note this function is asynchronous and the current process will continue\n  executing after this function is invoked. In case you want to block the\n  current process until the system effectively shuts down, you can invoke\n  `Process.sleep(:infinity)`.\n\n  ## Examples\n\n      System.stop(0)\n      System.stop(1)\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec stop(non_neg_integer | binary) :: :ok\n  def stop(status \\\\ 0)\n\n  def stop(status) when is_integer(status) do\n    at_exit(fn _ -> Process.sleep(:infinity) end)\n    :init.stop(status)\n  end\n\n  def stop(status) when is_binary(status) do\n    at_exit(fn _ -> Process.sleep(:infinity) end)\n    :init.stop(String.to_charlist(status))\n  end\n\n  @doc ~S\"\"\"\n  Executes the given `command` in the OS shell.\n\n  It uses `sh` for Unix-like systems and `cmd` for Windows.\n\n  > #### Watch out {: .warning}\n  >\n  > Use this function with care. In particular, **never\n  > pass untrusted user input to this function**, as the user would be\n  > able to perform \"command injection attacks\" by executing any code\n  > directly on the machine. Generally speaking, prefer to use `cmd/3`\n  > over this function.\n\n  ## Examples\n\n      iex> System.shell(\"echo hello\")\n      {\"hello\\n\", 0}\n\n  If you want to stream the output to Standard IO as it arrives:\n\n      iex> System.shell(\"echo hello\", into: IO.stream())\n      hello\n      {%IO.Stream{}, 0}\n\n  ## Options\n\n  It accepts the same options as `cmd/3` (except for `arg0`).\n  It also accepts the following exclusive options:\n\n    * `:close_stdin` (since v1.14.1) - if the stdin should be closed\n      on Unix systems, forcing any command that waits on stdin to\n      immediately terminate. Defaults to `false`.\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec shell(binary, shell_opts) :: {Collectable.t(), exit_status :: non_neg_integer}\n  def shell(command, opts \\\\ []) when is_binary(command) do\n    command |> String.trim() |> do_shell(opts)\n  end\n\n  defp do_shell(\"\", _opts), do: {\"\", 0}\n\n  defp do_shell(command, opts) do\n    assert_no_null_byte!(command, \"System.shell/2\")\n    {close_stdin?, opts} = Keyword.pop(opts, :close_stdin, false)\n\n    # Finding shell command logic from :os.cmd in OTP\n    # https://github.com/erlang/otp/blob/8deb96fb1d017307e22d2ab88968b9ef9f1b71d0/lib/kernel/src/os.erl#L184\n    case :os.type() do\n      {:unix, _} ->\n        shell_path = :os.find_executable(~c\"sh\") || :erlang.error(:enoent, [command, opts])\n        close_stdin = if close_stdin?, do: \" </dev/null\", else: \"\"\n        command = IO.iodata_to_binary([\"(\", command, \"\\n)\", close_stdin])\n        do_cmd({:spawn_executable, shell_path}, [args: [\"-c\", command]], opts)\n\n      {:win32, osname} ->\n        command = String.to_charlist(command)\n\n        command =\n          case {System.get_env(\"COMSPEC\"), osname} do\n            {nil, :windows} -> ~c\"command.com /s /c \" ++ command\n            {nil, _} -> ~c\"cmd /s /c \" ++ command\n            {cmd, _} -> ~c\"#{cmd} /s /c \" ++ command\n          end\n\n        do_cmd({:spawn, command}, [], opts)\n    end\n  end\n\n  @doc ~S\"\"\"\n  Executes the given `command` with `args`.\n\n  `command` is expected to be an executable available in PATH\n  unless an absolute path is given.\n\n  `args` must be a list of binaries which the executable will receive\n  as its arguments as is. This means that:\n\n    * environment variables will not be interpolated\n    * wildcard expansion will not happen (unless `Path.wildcard/2` is used\n      explicitly)\n    * arguments do not need to be escaped or quoted for shell safety\n\n  This function returns a tuple containing the collected result\n  and the command exit status.\n\n  Internally, this function uses a `Port` for interacting with the\n  outside world. However, if you plan to run a long-running program,\n  ports guarantee stdin/stdout devices will be closed but it does not\n  automatically terminate the program. The documentation for the\n  `Port` module describes this problem and possible solutions under\n  the \"Orphan operating system processes\" section.\n\n  > #### Windows argument splitting and untrusted arguments {: .warning}\n  >\n  > On Unix systems, arguments are passed to a new operating system\n  > process as an array of strings but on Windows it is up to the child\n  > process to parse them and some Windows programs may apply their own\n  > rules, which are inconsistent with the standard C runtime `argv` parsing\n  >\n  > This is particularly troublesome when invoking `.bat` or `.com` files\n  > as these run implicitly through `cmd.exe`, whose argument parsing is\n  > vulnerable to malicious input and can be used to run arbitrary shell\n  > commands.\n  >\n  > Therefore, if you are running on Windows and you execute batch\n  > files or `.com` applications, you must not pass untrusted input as\n  > arguments to the program. You may avoid accidentally executing them\n  > by explicitly passing the extension of the program you want to run,\n  > such as `.exe`, and double check the program is indeed not a batch\n  > file or `.com` application.\n\n  ## Options\n\n    * `:into` - injects the result into the given collectable, defaults to `\"\"`\n\n    * `:lines` - (since v1.15.0) reads the output by lines instead of in bytes. It expects a\n      number of maximum bytes to buffer internally (1024 is a reasonable default).\n      The collectable will be called with each finished line (regardless of buffer\n      size) and without the EOL character\n\n    * `:cd` - the directory to run the command in\n\n    * `:env` - an enumerable of tuples containing environment key-value as\n      binary. The child process inherits all environment variables from its\n      parent process, the Elixir application, except those overwritten or\n      cleared using this option. Specify a value of `nil` to clear (unset) an\n      environment variable, which is useful for preventing credentials passed\n      to the application from leaking into child processes\n\n    * `:arg0` - sets the command arg0\n\n    * `:stderr_to_stdout` - redirects stderr to stdout when `true`, no effect\n      if `use_stdio` is `false`.\n\n    * `:use_stdio` - `true` by default, setting it to false allows direct\n      interaction with the terminal from the callee\n\n    * `:parallelism` - when `true`, the VM will schedule port tasks to improve\n      parallelism in the system. If set to `false`, the VM will try to perform\n      commands immediately, improving latency at the expense of parallelism.\n      The default is `false`, and can be set on system startup by passing the\n      [`+spp`](https://www.erlang.org/doc/man/erl.html#+spp) flag to `--erl`.\n      Use `:erlang.system_info(:port_parallelism)` to check if enabled.\n\n  ## Error reasons\n\n  If invalid arguments are given, `ArgumentError` is raised by\n  `System.cmd/3`. `System.cmd/3` also expects a strict set of\n  options and will raise if unknown or invalid options are given.\n\n  Furthermore, `System.cmd/3` may fail with one of the POSIX reasons\n  detailed below:\n\n    * `:system_limit` - all available ports in the Erlang emulator are in use\n\n    * `:enomem` - there was not enough memory to create the port\n\n    * `:eagain` - there are no more available operating system processes\n\n    * `:enametoolong` - the external command given was too long\n\n    * `:emfile` - there are no more available file descriptors\n      (for the operating system process that the Erlang emulator runs in)\n\n    * `:enfile` - the file table is full (for the entire operating system)\n\n    * `:eacces` - the command does not point to an executable file\n\n    * `:enoent` - the command does not point to an existing file\n\n  ## Shell commands\n\n  If you desire to execute a trusted command inside a shell, with pipes,\n  redirecting and so on, please check `shell/2`.\n\n  ## Examples\n\n      iex> System.cmd(\"echo\", [\"hello\"])\n      {\"hello\\n\", 0}\n\n      iex> System.cmd(\"echo\", [\"hello\"], env: [{\"MIX_ENV\", \"test\"}])\n      {\"hello\\n\", 0}\n\n  If you want to stream the output to Standard IO as it arrives:\n\n      iex> System.cmd(\"echo\", [\"hello\"], into: IO.stream())\n      hello\n      {%IO.Stream{}, 0}\n\n  If you want to read lines:\n\n      iex> System.cmd(\"echo\", [\"hello\\nworld\"], into: [], lines: 1024)\n      {[\"hello\", \"world\"], 0}\n\n  \"\"\"\n  @spec cmd(binary, [binary], cmd_opts) :: {Collectable.t(), exit_status :: non_neg_integer}\n  def cmd(command, args, opts \\\\ []) when is_binary(command) and is_list(args) do\n    assert_no_null_byte!(command, \"System.cmd/3\")\n\n    if not Enum.all?(args, &is_binary/1) do\n      raise ArgumentError, \"all arguments for System.cmd/3 must be binaries\"\n    end\n\n    cmd = String.to_charlist(command)\n\n    cmd =\n      if Path.type(cmd) == :absolute do\n        cmd\n      else\n        :os.find_executable(cmd) || :erlang.error(:enoent, [command, args, opts])\n      end\n\n    do_cmd({:spawn_executable, cmd}, [args: args], opts)\n  end\n\n  defp do_cmd(port_init, base_opts, opts) do\n    {use_stdio?, opts} = Keyword.pop(opts, :use_stdio, true)\n\n    {into, line, opts} =\n      cmd_opts(opts, [:exit_status, :binary, :hide] ++ base_opts, \"\", false, use_stdio?)\n\n    {initial, fun} = Collectable.into(into)\n\n    try do\n      case line do\n        true -> do_port_line(Port.open(port_init, opts), initial, fun, [])\n        false -> do_port_byte(Port.open(port_init, opts), initial, fun)\n      end\n    catch\n      kind, reason ->\n        fun.(initial, :halt)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {acc, status} -> {fun.(acc, :done), status}\n    end\n  end\n\n  defp do_port_byte(port, acc, fun) do\n    receive do\n      {^port, {:data, data}} ->\n        do_port_byte(port, fun.(acc, {:cont, data}), fun)\n\n      {^port, {:exit_status, status}} ->\n        {acc, status}\n    end\n  end\n\n  defp do_port_line(port, acc, fun, buffer) do\n    receive do\n      {^port, {:data, {:noeol, data}}} ->\n        do_port_line(port, acc, fun, [data | buffer])\n\n      {^port, {:data, {:eol, data}}} ->\n        data = [data | buffer] |> Enum.reverse() |> IO.iodata_to_binary()\n        do_port_line(port, fun.(acc, {:cont, data}), fun, [])\n\n      {^port, {:exit_status, status}} ->\n        # Data may arrive after exit status on line mode\n        receive do\n          {^port, {:data, {_, data}}} ->\n            data = [data | buffer] |> Enum.reverse() |> IO.iodata_to_binary()\n            {fun.(acc, {:cont, data}), status}\n        after\n          0 -> {acc, status}\n        end\n    end\n  end\n\n  defp cmd_opts([{:into, any} | t], opts, _into, line, stdio?),\n    do: cmd_opts(t, opts, any, line, stdio?)\n\n  defp cmd_opts([{:cd, bin} | t], opts, into, line, stdio?) when is_binary(bin),\n    do: cmd_opts(t, [{:cd, bin} | opts], into, line, stdio?)\n\n  defp cmd_opts([{:arg0, bin} | t], opts, into, line, stdio?) when is_binary(bin),\n    do: cmd_opts(t, [{:arg0, bin} | opts], into, line, stdio?)\n\n  defp cmd_opts([{:stderr_to_stdout, true} | t], opts, into, line, true),\n    do: cmd_opts(t, [:stderr_to_stdout | opts], into, line, true)\n\n  defp cmd_opts([{:stderr_to_stdout, true} | _], _opts, _into, _line, false),\n    do: raise(ArgumentError, \"cannot use \\\"stderr_to_stdout: true\\\" and \\\"use_stdio: false\\\"\")\n\n  defp cmd_opts([{:stderr_to_stdout, false} | t], opts, into, line, stdio?),\n    do: cmd_opts(t, opts, into, line, stdio?)\n\n  defp cmd_opts([{:parallelism, bool} | t], opts, into, line, stdio?) when is_boolean(bool),\n    do: cmd_opts(t, [{:parallelism, bool} | opts], into, line, stdio?)\n\n  defp cmd_opts([{:env, enum} | t], opts, into, line, stdio?),\n    do: cmd_opts(t, [{:env, validate_env(enum)} | opts], into, line, stdio?)\n\n  defp cmd_opts([{:lines, max_line_length} | t], opts, into, _line, stdio?)\n       when is_integer(max_line_length) and max_line_length > 0,\n       do: cmd_opts(t, [{:line, max_line_length} | opts], into, true, stdio?)\n\n  defp cmd_opts([{key, val} | _], _opts, _into, _line, _stdio?),\n    do: raise(ArgumentError, \"invalid option #{inspect(key)} with value #{inspect(val)}\")\n\n  defp cmd_opts([], opts, into, line, stdio?) do\n    opt = if stdio?, do: :use_stdio, else: :nouse_stdio\n    {into, line, [opt | opts]}\n  end\n\n  defp validate_env(enum) do\n    Enum.map(enum, fn\n      {k, nil} ->\n        {String.to_charlist(k), false}\n\n      {k, v} ->\n        {String.to_charlist(k), String.to_charlist(v)}\n\n      other ->\n        raise ArgumentError, \"invalid environment key-value #{inspect(other)}\"\n    end)\n  end\n\n  @doc \"\"\"\n  Returns the current monotonic time in the `:native` time unit.\n\n  This time is monotonically increasing and starts in an unspecified\n  point in time. This is not strictly monotonically increasing. Multiple\n  sequential calls of the function may return the same value.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec monotonic_time() :: integer\n  def monotonic_time do\n    :erlang.monotonic_time()\n  end\n\n  @doc \"\"\"\n  Returns the current monotonic time in the given time unit.\n\n  This time is monotonically increasing and starts in an unspecified\n  point in time.\n  \"\"\"\n  @spec monotonic_time(time_unit | :native) :: integer\n  def monotonic_time(unit) do\n    :erlang.monotonic_time(normalize_time_unit(unit))\n  end\n\n  @doc \"\"\"\n  Returns the current system time in the `:native` time unit.\n\n  It is the VM view of the `os_time/0`. They may not match in\n  case of time warps although the VM works towards aligning\n  them. This time is not monotonic.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec system_time() :: integer\n  def system_time do\n    :erlang.system_time()\n  end\n\n  @doc \"\"\"\n  Returns the current system time in the given time unit.\n\n  It is the VM view of the `os_time/0`. They may not match in\n  case of time warps although the VM works towards aligning\n  them. This time is not monotonic.\n  \"\"\"\n  @spec system_time(time_unit | :native) :: integer\n  def system_time(unit) do\n    :erlang.system_time(normalize_time_unit(unit))\n  end\n\n  @doc \"\"\"\n  Converts `time` from time unit `from_unit` to time unit `to_unit`.\n\n  The result is rounded via the floor function.\n\n  `convert_time_unit/3` accepts an additional time unit (other than the\n  ones in the `t:time_unit/0` type) called `:native`. `:native` is the time\n  unit used by the Erlang runtime system. It's determined when the runtime\n  starts and stays the same until the runtime is stopped, but could differ\n  the next time the runtime is started on the same machine. For this reason,\n  you should use this function to convert `:native` time units to a predictable\n  unit before you display them to humans.\n\n  To determine how many seconds the `:native` unit represents in your current\n  runtime, you can call this function to convert 1 second to the `:native`\n  time unit: `System.convert_time_unit(1, :second, :native)`.\n  \"\"\"\n  @spec convert_time_unit(integer, time_unit | :native, time_unit | :native) :: integer\n  def convert_time_unit(time, from_unit, to_unit) do\n    :erlang.convert_time_unit(time, normalize_time_unit(from_unit), normalize_time_unit(to_unit))\n  end\n\n  @doc \"\"\"\n  Returns the current time offset between the Erlang VM monotonic\n  time and the Erlang VM system time.\n\n  The result is returned in the `:native` time unit.\n\n  See `time_offset/1` for more information.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec time_offset() :: integer\n  def time_offset do\n    :erlang.time_offset()\n  end\n\n  @doc \"\"\"\n  Returns the current time offset between the Erlang VM monotonic\n  time and the Erlang VM system time.\n\n  The result is returned in the given time unit `unit`. The returned\n  offset, added to an Erlang monotonic time (for instance, one obtained with\n  `monotonic_time/1`), gives the Erlang system time that corresponds\n  to that monotonic time.\n  \"\"\"\n  @spec time_offset(time_unit | :native) :: integer\n  def time_offset(unit) do\n    :erlang.time_offset(normalize_time_unit(unit))\n  end\n\n  @doc \"\"\"\n  Returns the current operating system (OS) time.\n\n  The result is returned in the `:native` time unit.\n\n  This time may be adjusted forwards or backwards in time\n  with no limitation and is not monotonic.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec os_time() :: integer\n  @doc since: \"1.3.0\"\n  def os_time do\n    :os.system_time()\n  end\n\n  @doc \"\"\"\n  Returns the current operating system (OS) time in the given time `unit`.\n\n  This time may be adjusted forwards or backwards in time\n  with no limitation and is not monotonic.\n  \"\"\"\n  @spec os_time(time_unit | :native) :: integer\n  @doc since: \"1.3.0\"\n  def os_time(unit) do\n    :os.system_time(normalize_time_unit(unit))\n  end\n\n  @doc \"\"\"\n  Returns the Erlang/OTP release number.\n  \"\"\"\n  @spec otp_release :: String.t()\n  @doc since: \"1.3.0\"\n  def otp_release do\n    :erlang.list_to_binary(:erlang.system_info(:otp_release))\n  end\n\n  @doc \"\"\"\n  Returns the number of schedulers in the VM.\n  \"\"\"\n  @spec schedulers :: pos_integer\n  @doc since: \"1.3.0\"\n  def schedulers do\n    :erlang.system_info(:schedulers)\n  end\n\n  @doc \"\"\"\n  Returns the number of schedulers online in the VM.\n  \"\"\"\n  @spec schedulers_online :: pos_integer\n  @doc since: \"1.3.0\"\n  def schedulers_online do\n    :erlang.system_info(:schedulers_online)\n  end\n\n  @doc \"\"\"\n  Generates and returns an integer that is unique in the current runtime\n  instance.\n\n  \"Unique\" means that this function, called with the same list of `modifiers`,\n  will never return the same integer more than once on the current runtime\n  instance.\n\n  If `modifiers` is `[]`, then a unique integer (that can be positive or negative) is returned.\n  Other modifiers can be passed to change the properties of the returned integer:\n\n    * `:positive` - the returned integer is guaranteed to be positive.\n    * `:monotonic` - the returned integer is monotonically increasing. This\n      means that, on the same runtime instance (but even on different\n      processes), integers returned using the `:monotonic` modifier will always\n      be strictly less than integers returned by successive calls with the\n      `:monotonic` modifier.\n\n  All modifiers listed above can be combined; repeated modifiers in `modifiers`\n  will be ignored.\n\n  Inlined by the compiler.\n  \"\"\"\n  @spec unique_integer([:positive | :monotonic]) :: integer\n  def unique_integer(modifiers \\\\ []) do\n    :erlang.unique_integer(modifiers)\n  end\n\n  defp assert_no_null_byte!(binary, operation) do\n    case :binary.match(binary, \"\\0\") do\n      {_, _} ->\n        raise ArgumentError,\n              \"cannot execute #{operation} for program with null byte, got: #{inspect(binary)}\"\n\n      :nomatch ->\n        binary\n    end\n  end\n\n  defp normalize_time_unit(:native), do: :native\n\n  defp normalize_time_unit(:second), do: :second\n  defp normalize_time_unit(:millisecond), do: :millisecond\n  defp normalize_time_unit(:microsecond), do: :microsecond\n  defp normalize_time_unit(:nanosecond), do: :nanosecond\n\n  defp normalize_time_unit(:seconds), do: warn(:seconds, :second)\n  defp normalize_time_unit(:milliseconds), do: warn(:milliseconds, :millisecond)\n  defp normalize_time_unit(:microseconds), do: warn(:microseconds, :microsecond)\n  defp normalize_time_unit(:nanoseconds), do: warn(:nanoseconds, :nanosecond)\n\n  defp normalize_time_unit(:milli_seconds), do: warn(:milli_seconds, :millisecond)\n  defp normalize_time_unit(:micro_seconds), do: warn(:micro_seconds, :microsecond)\n  defp normalize_time_unit(:nano_seconds), do: warn(:nano_seconds, :nanosecond)\n\n  defp normalize_time_unit(unit) when is_integer(unit) and unit > 0, do: unit\n\n  defp normalize_time_unit(other) do\n    raise ArgumentError,\n          \"unsupported time unit. Expected :second, :millisecond, \" <>\n            \":microsecond, :nanosecond, or a positive integer, \" <> \"got #{inspect(other)}\"\n  end\n\n  defp warn(unit, replacement_unit) do\n    IO.warn_once(\n      {__MODULE__, unit},\n      fn ->\n        \"deprecated time unit: #{inspect(unit)}. A time unit should be \" <>\n          \":second, :millisecond, :microsecond, :nanosecond, or a positive integer\"\n      end,\n      _stacktrace_drop_levels = 4\n    )\n\n    replacement_unit\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/task/supervised.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Task.Supervised do\n  @moduledoc false\n  @ref_timeout 5000\n\n  def start(owner, callers, fun) do\n    {:ok, spawn(__MODULE__, :noreply, [owner, get_ancestors(), callers, fun])}\n  end\n\n  def start_link(owner, callers, fun) do\n    {:ok, spawn_link(__MODULE__, :noreply, [owner, get_ancestors(), callers, fun])}\n  end\n\n  def start_link(owner, monitor) do\n    {:ok, spawn_link(__MODULE__, :reply, [owner, get_ancestors(), monitor])}\n  end\n\n  def reply({_, _, owner_pid} = owner, ancestors, monitor) do\n    put_ancestors(ancestors)\n\n    case monitor do\n      :monitor ->\n        mref = Process.monitor(owner_pid)\n        reply(owner, owner_pid, mref, @ref_timeout)\n\n      :nomonitor ->\n        reply(owner, owner_pid, nil, :infinity)\n    end\n  end\n\n  defp reply(owner, owner_pid, mref, timeout) do\n    receive do\n      {^owner_pid, ref, reply_to, callers, mfa} ->\n        put_initial_call(mfa)\n        put_callers(callers)\n        _ = is_reference(mref) && Process.demonitor(mref, [:flush])\n        send(reply_to, {ref, invoke_mfa(owner, mfa)})\n\n      {:DOWN, ^mref, _, _, reason} ->\n        exit({:shutdown, reason})\n    after\n      # There is a race condition on this operation when working across\n      # node that manifests if a \"Task.Supervisor.async/2\" call is made\n      # while the supervisor is busy spawning previous tasks.\n      #\n      # Imagine the following workflow:\n      #\n      # 1. The nodes disconnect\n      # 2. The async call fails and is caught, the calling process does not exit\n      # 3. The task is spawned and links to the calling process, causing the nodes to reconnect\n      # 4. The calling process has not exited and so does not send its monitor reference\n      # 5. The spawned task waits forever for the monitor reference so it can begin\n      #\n      # We have solved this by specifying a timeout of 5000 milliseconds.\n      # Given no work is done in the client between the task start and\n      # sending the reference, 5000 should be enough to not raise false\n      # negatives unless the nodes are indeed not available.\n      #\n      # The same situation could occur with \"Task.Supervisor.async_nolink/2\",\n      # except a monitor is used instead of a link.\n      timeout ->\n        exit(:timeout)\n    end\n  end\n\n  def noreply(owner, ancestors, callers, mfa) do\n    put_initial_call(mfa)\n    put_ancestors(ancestors)\n    put_callers(callers)\n    invoke_mfa(owner, mfa)\n  end\n\n  defp get_ancestors() do\n    case :erlang.get(:\"$ancestors\") do\n      ancestors when is_list(ancestors) -> [self() | ancestors]\n      _ -> [self()]\n    end\n  end\n\n  defp put_ancestors(ancestors) do\n    Process.put(:\"$ancestors\", ancestors)\n  end\n\n  defp put_callers(callers) do\n    Process.put(:\"$callers\", callers)\n  end\n\n  defp put_initial_call(mfa) do\n    Process.put(:\"$initial_call\", get_initial_call(mfa))\n  end\n\n  defp get_initial_call({:erlang, :apply, [fun, []]}) when is_function(fun, 0) do\n    :erlang.fun_info_mfa(fun)\n  end\n\n  defp get_initial_call({mod, fun, args}) do\n    {mod, fun, length(args)}\n  end\n\n  defp invoke_mfa(owner, {module, fun, args} = mfa) do\n    try do\n      apply(module, fun, args)\n    catch\n      :exit, value\n      when value == :normal\n      when value == :shutdown\n      when tuple_size(value) == 2 and elem(value, 0) == :shutdown ->\n        :erlang.raise(:exit, value, __STACKTRACE__)\n\n      kind, value ->\n        {fun, args} = get_running(mfa)\n\n        :logger.error(\n          %{\n            label: {Task.Supervisor, :terminating},\n            report: %{\n              name: self(),\n              starter: get_from(owner),\n              function: fun,\n              args: args,\n              reason: {log_value(kind, value), __STACKTRACE__},\n              # using :proc_lib over Process because we want the :undefined default, not nil\n              process_label: :proc_lib.get_label(self())\n            }\n          },\n          %{\n            domain: [:otp, :elixir],\n            error_logger: %{tag: :error_msg},\n            report_cb: &__MODULE__.format_report/1,\n            callers: Process.get(:\"$callers\")\n          }\n        )\n\n        :erlang.raise(:exit, exit_reason(kind, value, __STACKTRACE__), __STACKTRACE__)\n    end\n  end\n\n  defp exit_reason(:error, reason, stacktrace), do: {reason, stacktrace}\n  defp exit_reason(:exit, reason, _stacktrace), do: reason\n  defp exit_reason(:throw, reason, stacktrace), do: {{:nocatch, reason}, stacktrace}\n\n  defp log_value(:throw, value), do: {:nocatch, value}\n  defp log_value(_, value), do: value\n\n  @doc false\n  def format_report(%{\n        label: {Task.Supervisor, :terminating},\n        report: %{\n          name: name,\n          starter: starter,\n          function: fun,\n          args: args,\n          reason: reason,\n          process_label: process_label\n        }\n      }) do\n    message =\n      ~c\"** Started from ~p~n\" ++\n        ~c\"** When function  == ~p~n\" ++\n        ~c\"**      arguments == ~p~n\" ++ ~c\"** Reason for termination == ~n\" ++ ~c\"** ~p~n\"\n\n    terms = [starter, fun, args, get_reason(reason)]\n\n    {message, terms} =\n      case process_label do\n        :undefined -> {message, terms}\n        _ -> {~c\"** Process Label == ~p~n\" ++ message, [process_label | terms]}\n      end\n\n    message =\n      ~c\"** Task ~p terminating~n\" ++ message\n\n    {message, [name | terms]}\n  end\n\n  defp get_from({node, pid_or_name, _pid}) when node == node(), do: pid_or_name\n  defp get_from({node, name, _pid}) when is_atom(name), do: {node, name}\n  defp get_from({_node, _name, pid}), do: pid\n\n  defp get_running({:erlang, :apply, [fun, []]}) when is_function(fun, 0), do: {fun, []}\n  defp get_running({mod, fun, args}), do: {Function.capture(mod, fun, length(args)), args}\n\n  defp get_reason({:undef, [{mod, fun, args, _info} | _] = stacktrace} = reason)\n       when is_atom(mod) and is_atom(fun) do\n    cond do\n      not Code.loaded?(mod) ->\n        {:\"module could not be loaded\", stacktrace}\n\n      is_list(args) and not function_exported?(mod, fun, length(args)) ->\n        {:\"function not exported\", stacktrace}\n\n      is_integer(args) and not function_exported?(mod, fun, args) ->\n        {:\"function not exported\", stacktrace}\n\n      true ->\n        reason\n    end\n  end\n\n  defp get_reason(reason) do\n    reason\n  end\n\n  ## Stream\n\n  def validate_stream_options(options) do\n    max_concurrency = Keyword.get_lazy(options, :max_concurrency, &System.schedulers_online/0)\n    on_timeout = Keyword.get(options, :on_timeout, :exit)\n    timeout = Keyword.get(options, :timeout, 5000)\n    ordered = Keyword.get(options, :ordered, true)\n    zip_input_on_exit = Keyword.get(options, :zip_input_on_exit, false)\n\n    if not (is_integer(max_concurrency) and max_concurrency > 0) do\n      raise ArgumentError, \":max_concurrency must be an integer greater than zero\"\n    end\n\n    if on_timeout not in [:exit, :kill_task] do\n      raise ArgumentError, \":on_timeout must be either :exit or :kill_task\"\n    end\n\n    if not ((is_integer(timeout) and timeout >= 0) or timeout == :infinity) do\n      raise ArgumentError, \":timeout must be either a positive integer or :infinity\"\n    end\n\n    %{\n      max_concurrency: max_concurrency,\n      on_timeout: on_timeout,\n      timeout: timeout,\n      ordered: ordered,\n      zip_input_on_exit: zip_input_on_exit\n    }\n  end\n\n  def stream(enumerable, acc, reducer, callers, mfa, options, spawn) when is_map(options) do\n    next = &Enumerable.reduce(enumerable, &1, fn x, acc -> {:suspend, [x | acc]} end)\n    parent = self()\n\n    {:trap_exit, trap_exit?} = Process.info(self(), :trap_exit)\n\n    # Start a process responsible for spawning processes and translating \"down\"\n    # messages. This process will trap exits if the current process is trapping\n    # exit, or it won't trap exits otherwise.\n    spawn_opts = [:link, :monitor]\n\n    {monitor_pid, monitor_ref} =\n      Process.spawn(\n        fn -> stream_monitor(parent, spawn, trap_exit?, options.timeout) end,\n        spawn_opts\n      )\n\n    # Now that we have the pid of the \"monitor\" process and the reference of the\n    # monitor we use to monitor such process, we can inform the monitor process\n    # about our reference to it.\n    send(monitor_pid, {parent, monitor_ref})\n\n    config =\n      Map.merge(\n        options,\n        %{\n          reducer: reducer,\n          monitor_pid: monitor_pid,\n          monitor_ref: monitor_ref,\n          callers: callers,\n          mfa: mfa\n        }\n      )\n\n    stream_reduce(\n      acc,\n      options.max_concurrency,\n      _spawned = 0,\n      _delivered = 0,\n      _waiting = %{},\n      next,\n      config\n    )\n  end\n\n  defp stream_reduce({:halt, acc}, _max, _spawned, _delivered, _waiting, next, config) do\n    stream_close(config)\n    is_function(next) && next.({:halt, []})\n    {:halted, acc}\n  end\n\n  defp stream_reduce({:suspend, acc}, max, spawned, delivered, waiting, next, config) do\n    continuation = &stream_reduce(&1, max, spawned, delivered, waiting, next, config)\n    {:suspended, acc, continuation}\n  end\n\n  # All spawned, all delivered, next is :done.\n  defp stream_reduce({:cont, acc}, _max, spawned, delivered, _waiting, next, config)\n       when spawned == delivered and next == :done do\n    stream_close(config)\n    {:done, acc}\n  end\n\n  # No more tasks to spawn because max == 0 or next is :done. We wait for task\n  # responses or tasks going down.\n  defp stream_reduce({:cont, acc}, max, spawned, delivered, waiting, next, config)\n       when max == 0\n       when next == :done do\n    %{\n      monitor_pid: monitor_pid,\n      monitor_ref: monitor_ref,\n      timeout: timeout,\n      on_timeout: on_timeout,\n      zip_input_on_exit: zip_input_on_exit?,\n      ordered: ordered?\n    } = config\n\n    receive do\n      # The task at position \"position\" replied with \"value\". We put the\n      # response in the \"waiting\" map and do nothing, since we'll only act on\n      # this response when the replying task dies (we'll see this in the :down\n      # message).\n      {{^monitor_ref, position}, reply} ->\n        %{^position => {pid, :running, _element}} = waiting\n        waiting = Map.put(waiting, position, {pid, {:ok, reply}})\n        stream_reduce({:cont, acc}, max, spawned, delivered, waiting, next, config)\n\n      # The task at position \"position\" died for some reason. We check if it\n      # replied already (then the death is peaceful) or if it's still running\n      # (then the reply from this task will be {:exit, reason}). This message is\n      # sent to us by the monitor process, not by the dying task directly.\n      {kind, {^monitor_ref, position}, reason}\n      when kind in [:down, :timed_out] ->\n        result =\n          case waiting do\n            # If the task replied, we don't care whether it went down for timeout\n            # or for normal reasons.\n            %{^position => {_, {:ok, _} = ok}} ->\n              ok\n\n            # If the task exited by itself before replying, we emit {:exit, reason}.\n            %{^position => {_, :running, element}}\n            when kind == :down ->\n              if zip_input_on_exit?, do: {:exit, {element, reason}}, else: {:exit, reason}\n\n            # If the task timed out before replying, we either exit (on_timeout: :exit)\n            # or emit {:exit, :timeout} (on_timeout: :kill_task) (note the task is already\n            # dead at this point).\n            %{^position => {_, :running, element}}\n            when kind == :timed_out ->\n              if on_timeout == :exit do\n                stream_cleanup_inbox(monitor_pid, monitor_ref)\n                exit({:timeout, {__MODULE__, :stream, [timeout]}})\n              else\n                if zip_input_on_exit?, do: {:exit, {element, :timeout}}, else: {:exit, :timeout}\n              end\n          end\n\n        if ordered? do\n          waiting = Map.put(waiting, position, {:done, result})\n          stream_deliver({:cont, acc}, max + 1, spawned, delivered, waiting, next, config)\n        else\n          pair = deliver_now(result, acc, next, config)\n          waiting = Map.delete(waiting, position)\n          stream_reduce(pair, max + 1, spawned, delivered + 1, waiting, next, config)\n        end\n\n      # The monitor process died. We just cleanup the messages from the monitor\n      # process and exit.\n      {:DOWN, ^monitor_ref, _, _, reason} ->\n        stream_cleanup_inbox(monitor_pid, monitor_ref)\n        exit({reason, {__MODULE__, :stream, [timeout]}})\n    end\n  end\n\n  defp stream_reduce({:cont, acc}, max, spawned, delivered, waiting, next, config) do\n    try do\n      next.({:cont, []})\n    catch\n      kind, reason ->\n        stream_close(config)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {:suspended, [value], next} ->\n        waiting = stream_spawn(value, spawned, waiting, config)\n        stream_reduce({:cont, acc}, max - 1, spawned + 1, delivered, waiting, next, config)\n\n      {_, [value]} ->\n        waiting = stream_spawn(value, spawned, waiting, config)\n        stream_reduce({:cont, acc}, max - 1, spawned + 1, delivered, waiting, :done, config)\n\n      {_, []} ->\n        stream_reduce({:cont, acc}, max, spawned, delivered, waiting, :done, config)\n    end\n  end\n\n  defp deliver_now(reply, acc, next, config) do\n    %{reducer: reducer} = config\n\n    try do\n      reducer.(reply, acc)\n    catch\n      kind, reason ->\n        is_function(next) && next.({:halt, []})\n        stream_close(config)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    end\n  end\n\n  defp stream_deliver({:suspend, acc}, max, spawned, delivered, waiting, next, config) do\n    continuation = &stream_deliver(&1, max, spawned, delivered, waiting, next, config)\n    {:suspended, acc, continuation}\n  end\n\n  defp stream_deliver({:halt, acc}, max, spawned, delivered, waiting, next, config) do\n    stream_reduce({:halt, acc}, max, spawned, delivered, waiting, next, config)\n  end\n\n  defp stream_deliver({:cont, acc}, max, spawned, delivered, waiting, next, config) do\n    %{reducer: reducer} = config\n\n    case waiting do\n      %{^delivered => {:done, reply}} ->\n        try do\n          reducer.(reply, acc)\n        catch\n          kind, reason ->\n            is_function(next) && next.({:halt, []})\n            stream_close(config)\n            :erlang.raise(kind, reason, __STACKTRACE__)\n        else\n          pair ->\n            waiting = Map.delete(waiting, delivered)\n            stream_deliver(pair, max, spawned, delivered + 1, waiting, next, config)\n        end\n\n      %{} ->\n        stream_reduce({:cont, acc}, max, spawned, delivered, waiting, next, config)\n    end\n  end\n\n  defp stream_close(%{monitor_pid: monitor_pid, monitor_ref: monitor_ref, timeout: timeout}) do\n    send(monitor_pid, {:stop, monitor_ref})\n\n    receive do\n      {:DOWN, ^monitor_ref, _, _, :normal} ->\n        stream_cleanup_inbox(monitor_pid, monitor_ref)\n        :ok\n\n      {:DOWN, ^monitor_ref, _, _, reason} ->\n        stream_cleanup_inbox(monitor_pid, monitor_ref)\n        exit({reason, {__MODULE__, :stream, [timeout]}})\n    end\n  end\n\n  defp stream_cleanup_inbox(monitor_pid, monitor_ref) do\n    receive do\n      {:EXIT, ^monitor_pid, _} -> stream_cleanup_inbox(monitor_ref)\n    after\n      0 -> stream_cleanup_inbox(monitor_ref)\n    end\n  end\n\n  defp stream_cleanup_inbox(monitor_ref) do\n    receive do\n      {{^monitor_ref, _}, _} ->\n        stream_cleanup_inbox(monitor_ref)\n\n      {kind, {^monitor_ref, _}, _} when kind in [:down, :timed_out] ->\n        stream_cleanup_inbox(monitor_ref)\n    after\n      0 ->\n        :ok\n    end\n  end\n\n  # This function spawns a task for the given \"value\", and puts the pid of this\n  # new task in the map of \"waiting\" tasks, which is returned.\n  defp stream_spawn(value, spawned, waiting, config) do\n    %{\n      monitor_pid: monitor_pid,\n      monitor_ref: monitor_ref,\n      timeout: timeout,\n      callers: callers,\n      mfa: mfa,\n      zip_input_on_exit: zip_input_on_exit?\n    } = config\n\n    send(monitor_pid, {:spawn, spawned})\n\n    receive do\n      {:spawned, {^monitor_ref, ^spawned}, pid} ->\n        mfa_with_value = normalize_mfa_with_arg(mfa, value)\n        send(pid, {self(), {monitor_ref, spawned}, self(), callers, mfa_with_value})\n        stored_value = if zip_input_on_exit?, do: value, else: nil\n        Map.put(waiting, spawned, {pid, :running, stored_value})\n\n      {:max_children, ^monitor_ref} ->\n        stream_close(config)\n\n        raise \"\"\"\n        reached the maximum number of tasks for this task supervisor. The maximum number \\\n        of tasks that are allowed to run at the same time under this supervisor can be \\\n        configured with the :max_children option passed to Task.Supervisor.start_link/1. When \\\n        using async_stream or async_stream_nolink, make sure to configure :max_concurrency to \\\n        be lower or equal to :max_children and pay attention to whether other tasks are also \\\n        spawned under the same task supervisor.\\\n        \"\"\"\n\n      {:DOWN, ^monitor_ref, _, ^monitor_pid, reason} ->\n        stream_cleanup_inbox(monitor_pid, monitor_ref)\n        exit({reason, {__MODULE__, :stream, [timeout]}})\n    end\n  end\n\n  defp stream_monitor(parent_pid, spawn, trap_exit?, timeout) do\n    Process.flag(:trap_exit, trap_exit?)\n    parent_ref = Process.monitor(parent_pid)\n\n    # Let's wait for the parent process to tell this process the monitor ref\n    # it's using to monitor this process. If the parent process dies while this\n    # process waits, this process dies with the same reason.\n    receive do\n      {^parent_pid, monitor_ref} ->\n        config = %{\n          parent_pid: parent_pid,\n          parent_ref: parent_ref,\n          spawn: spawn,\n          monitor_ref: monitor_ref,\n          timeout: timeout\n        }\n\n        stream_monitor_loop(_running_tasks = %{}, config)\n\n      {:DOWN, ^parent_ref, _, _, reason} ->\n        exit(reason)\n    end\n  end\n\n  defp stream_monitor_loop(running_tasks, config) do\n    %{\n      spawn: spawn,\n      parent_pid: parent_pid,\n      monitor_ref: monitor_ref,\n      timeout: timeout\n    } = config\n\n    receive do\n      # The parent process is telling us to spawn a new task to process\n      # \"value\". We spawn it and notify the parent about its pid.\n      {:spawn, position} ->\n        case spawn.() do\n          {:ok, type, pid} ->\n            ref = Process.monitor(pid)\n\n            # Schedule a timeout message to ourselves, unless the timeout was set to :infinity\n            timer_ref =\n              case timeout do\n                :infinity -> nil\n                timeout -> Process.send_after(self(), {:timeout, {monitor_ref, ref}}, timeout)\n              end\n\n            send(parent_pid, {:spawned, {monitor_ref, position}, pid})\n\n            running_tasks =\n              Map.put(running_tasks, ref, %{\n                position: position,\n                type: type,\n                pid: pid,\n                timer_ref: timer_ref,\n                timed_out?: false\n              })\n\n            stream_monitor_loop(running_tasks, config)\n\n          {:error, :max_children} ->\n            send(parent_pid, {:max_children, monitor_ref})\n            stream_waiting_for_stop_loop(running_tasks, config)\n        end\n\n      # One of the spawned processes went down. We inform the parent process of\n      # this and keep going.\n      {:DOWN, ref, _, _, reason} when is_map_key(running_tasks, ref) ->\n        {task, running_tasks} = Map.pop(running_tasks, ref)\n        %{position: position, timer_ref: timer_ref, timed_out?: timed_out?} = task\n\n        if timer_ref != nil do\n          :ok = Process.cancel_timer(timer_ref, async: true, info: false)\n        end\n\n        message_kind = if(timed_out?, do: :timed_out, else: :down)\n        send(parent_pid, {message_kind, {monitor_ref, position}, reason})\n        stream_monitor_loop(running_tasks, config)\n\n      # One of the spawned processes timed out. We kill that process here\n      # regardless of the value of :on_timeout. We then send a message to the\n      # parent process informing it that a task timed out, and the parent\n      # process decides what to do.\n      {:timeout, {^monitor_ref, ref}} ->\n        running_tasks =\n          case running_tasks do\n            %{^ref => %{pid: pid, timed_out?: false} = task_info} ->\n              unlink_and_kill(pid)\n              Map.put(running_tasks, ref, %{task_info | timed_out?: true})\n\n            _other ->\n              running_tasks\n          end\n\n        stream_monitor_loop(running_tasks, config)\n\n      {:EXIT, _, _} ->\n        stream_monitor_loop(running_tasks, config)\n\n      other ->\n        handle_stop_or_parent_down(other, running_tasks, config)\n        stream_monitor_loop(running_tasks, config)\n    end\n  end\n\n  defp stream_waiting_for_stop_loop(running_tasks, config) do\n    receive do\n      message ->\n        handle_stop_or_parent_down(message, running_tasks, config)\n        stream_waiting_for_stop_loop(running_tasks, config)\n    end\n  end\n\n  # The parent process is telling us to stop because the stream is being\n  # closed. In this case, we forcibly kill all spawned processes and then\n  # exit gracefully ourselves.\n  defp handle_stop_or_parent_down(\n         {:stop, monitor_ref},\n         running_tasks,\n         %{monitor_ref: monitor_ref}\n       ) do\n    Process.flag(:trap_exit, true)\n\n    for {_ref, %{pid: pid}} <- running_tasks, do: Process.exit(pid, :kill)\n\n    for {ref, _task} <- running_tasks do\n      receive do\n        {:DOWN, ^ref, _, _, _} -> :ok\n      end\n    end\n\n    exit(:normal)\n  end\n\n  # The parent process went down with a given reason. We kill all the\n  # spawned processes (that are also linked) with the same reason, and then\n  # exit ourselves with the same reason.\n  defp handle_stop_or_parent_down(\n         {:DOWN, parent_ref, _, _, reason},\n         running_tasks,\n         %{parent_ref: parent_ref}\n       ) do\n    for {_ref, %{type: :link, pid: pid}} <- running_tasks do\n      Process.exit(pid, reason)\n    end\n\n    exit(reason)\n  end\n\n  # We ignore all other messages.\n  defp handle_stop_or_parent_down(_other, _running_tasks, _config) do\n    :ok\n  end\n\n  defp unlink_and_kill(pid) do\n    caller = self()\n    ref = make_ref()\n\n    enforcer =\n      spawn(fn ->\n        mon = Process.monitor(caller)\n\n        receive do\n          {:done, ^ref} -> :ok\n          {:DOWN, ^mon, _, _, _} -> Process.exit(pid, :kill)\n        end\n      end)\n\n    Process.unlink(pid)\n    Process.exit(pid, :kill)\n    send(enforcer, {:done, ref})\n  end\n\n  defp normalize_mfa_with_arg({mod, fun, args}, arg), do: {mod, fun, [arg | args]}\n  defp normalize_mfa_with_arg(fun, arg), do: {:erlang, :apply, [fun, [arg]]}\nend\n"
  },
  {
    "path": "lib/elixir/lib/task/supervisor.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Task.Supervisor do\n  @moduledoc \"\"\"\n  A task supervisor.\n\n  This module defines a supervisor which can be used to dynamically\n  supervise tasks.\n\n  A task supervisor is started with no children, often under a\n  supervisor and a name:\n\n      children = [\n        {Task.Supervisor, name: MyApp.TaskSupervisor}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_one)\n\n  The options given in the child specification are documented in `start_link/1`.\n\n  Once started, you can start tasks directly under the supervisor, for example:\n\n      task = Task.Supervisor.async(MyApp.TaskSupervisor, fn ->\n        :do_some_work\n      end)\n\n  See the `Task` module for more examples.\n\n  ## Scalability and partitioning\n\n  The `Task.Supervisor` is a single process responsible for starting\n  other processes. In some applications, the `Task.Supervisor` may\n  become a bottleneck. To address this, you can start multiple instances\n  of the `Task.Supervisor` and then pick a random instance to start\n  the task on.\n\n  Instead of:\n\n      children = [\n        {Task.Supervisor, name: MyApp.TaskSupervisor}\n      ]\n\n  and:\n\n      Task.Supervisor.async(MyApp.TaskSupervisor, fn -> :do_some_work end)\n\n  You can do this:\n\n      children = [\n        {PartitionSupervisor,\n         child_spec: Task.Supervisor,\n         name: MyApp.TaskSupervisors}\n      ]\n\n  and then:\n\n      Task.Supervisor.async(\n        {:via, PartitionSupervisor, {MyApp.TaskSupervisors, self()}},\n        fn -> :do_some_work end\n      )\n\n  In the code above, we start a partition supervisor that will by default\n  start a dynamic supervisor for each core in your machine. Then, instead\n  of calling the `Task.Supervisor` by name, you call it through the\n  partition supervisor using the `{:via, PartitionSupervisor, {name, key}}`\n  format, where `name` is the name of the partition supervisor and `key`\n  is the routing key. We picked `self()` as the routing key, which means\n  each process will be assigned one of the existing task supervisors.\n  Read the `PartitionSupervisor` docs for more information.\n\n  ## Name registration\n\n  A `Task.Supervisor` is bound to the same name registration rules as a\n  `GenServer`. Read more about them in the `GenServer` docs.\n  \"\"\"\n\n  @typedoc \"Option values used by `start_link`\"\n  @type option ::\n          GenServer.option()\n          | DynamicSupervisor.init_option()\n\n  @typedoc \"\"\"\n  Options given to `async_stream` and `async_stream_nolink` functions.\n  \"\"\"\n  @typedoc since: \"1.17.0\"\n  @type async_stream_option :: Task.async_stream_option() | {:shutdown, Supervisor.shutdown()}\n\n  @typedoc \"\"\"\n  Options for `async/3`, `async/5`, `async_nolink/3`, and `async_nolink/5` functions.\n  \"\"\"\n  @type async_opts :: [\n          shutdown: :brutal_kill | timeout()\n        ]\n\n  @type start_child_opts :: [\n          restart: :temporary | :transient | :permanent,\n          shutdown: :brutal_kill | timeout()\n        ]\n\n  @doc false\n  def child_spec(opts) when is_list(opts) do\n    id =\n      case Keyword.get(opts, :name, Task.Supervisor) do\n        name when is_atom(name) -> name\n        {:global, name} -> name\n        {:via, _module, name} -> name\n      end\n\n    %{\n      id: id,\n      start: {Task.Supervisor, :start_link, [opts]},\n      type: :supervisor\n    }\n  end\n\n  @doc \"\"\"\n  Starts a new supervisor.\n\n  ## Examples\n\n  A task supervisor is typically started under a supervision tree using\n  the tuple format:\n\n      {Task.Supervisor, name: MyApp.TaskSupervisor}\n\n  You can also start it by calling `start_link/1` directly:\n\n      Task.Supervisor.start_link(name: MyApp.TaskSupervisor)\n\n  But this is recommended only for scripting and should be avoided in\n  production code. Generally speaking, processes should always be started\n  inside supervision trees.\n\n  ## Options\n\n    * `:name` - used to register a supervisor name, the supported values are\n      described under the `Name Registration` section in the `GenServer` module\n      docs;\n\n    * `:max_restarts`, `:max_seconds`, and `:max_children` - as specified in\n      `DynamicSupervisor`;\n\n  This function could also receive `:restart` and `:shutdown` as options\n  but those two options have been deprecated and it is now preferred to\n  give them directly to `start_child`.\n  \"\"\"\n  @spec start_link([option]) :: Supervisor.on_start()\n  def start_link(options \\\\ []) do\n    {restart, options} = Keyword.pop(options, :restart)\n    {shutdown, options} = Keyword.pop(options, :shutdown)\n\n    if restart || shutdown do\n      IO.warn(\n        \":restart and :shutdown options in Task.Supervisor.start_link/1 \" <>\n          \"are deprecated. Please pass those options on start_child/3 instead\"\n      )\n    end\n\n    keys = [:max_children, :max_seconds, :max_restarts]\n    {sup_opts, start_opts} = Keyword.split(options, keys)\n    restart_and_shutdown = {restart || :temporary, shutdown || 5000}\n    DynamicSupervisor.start_link(__MODULE__, {restart_and_shutdown, sup_opts}, start_opts)\n  end\n\n  @doc false\n  def init({{_restart, _shutdown} = arg, options}) do\n    Process.put(__MODULE__, arg)\n    DynamicSupervisor.init([strategy: :one_for_one] ++ options)\n  end\n\n  @doc \"\"\"\n  Starts a task that can be awaited on.\n\n  The `supervisor` must be a reference as defined in `Supervisor`.\n  The task will still be linked to the caller, see `Task.async/1` for\n  more information and `async_nolink/3` for a non-linked variant.\n\n  Raises an error if `supervisor` has reached the maximum number of\n  children.\n\n  ## Options\n\n    * `:shutdown` - `:brutal_kill` if the tasks must be killed directly on shutdown\n      or an integer indicating the timeout value, defaults to 5000 milliseconds.\n      The tasks must trap exits for the timeout to have an effect.\n\n  \"\"\"\n  @spec async(Supervisor.supervisor(), (-> any), async_opts) :: Task.t()\n  def async(supervisor, fun, options \\\\ []) do\n    async(supervisor, :erlang, :apply, [fun, []], options)\n  end\n\n  @doc \"\"\"\n  Starts a task that can be awaited on.\n\n  The `supervisor` must be a reference as defined in `Supervisor`.\n  The task will still be linked to the caller, see `Task.async/1` for\n  more information and `async_nolink/3` for a non-linked variant.\n\n  Raises an error if `supervisor` has reached the maximum number of\n  children.\n\n  ## Options\n\n    * `:shutdown` - `:brutal_kill` if the tasks must be killed directly on shutdown\n      or an integer indicating the timeout value, defaults to 5000 milliseconds.\n      The tasks must trap exits for the timeout to have an effect.\n\n  \"\"\"\n  @spec async(Supervisor.supervisor(), module, atom, [term], async_opts) :: Task.t()\n  def async(supervisor, module, fun, args, options \\\\ []) do\n    async(supervisor, :link, module, fun, args, options)\n  end\n\n  @doc \"\"\"\n  Starts a task that can be awaited on.\n\n  The `supervisor` must be a reference as defined in `Supervisor`.\n  The task won't be linked to the caller, see `Task.async/1` for\n  more information.\n\n  Raises an error if `supervisor` has reached the maximum number of\n  children.\n\n  Note this function requires the task supervisor to have `:temporary`\n  as the `:restart` option (the default), as `async_nolink/3` keeps a\n  direct reference to the task which is lost if the task is restarted.\n\n  ## Options\n\n    * `:shutdown` - `:brutal_kill` if the tasks must be killed directly on shutdown\n      or an integer indicating the timeout value, defaults to 5000 milliseconds.\n      The tasks must trap exits for the timeout to have an effect.\n\n  ## Compatibility with OTP behaviours\n\n  If you create a task using `async_nolink` inside an OTP behaviour\n  like `GenServer`, you should match on the message coming from the\n  task inside your `c:GenServer.handle_info/2` callback.\n\n  The reply sent by the task will be in the format `{ref, result}`,\n  where `ref` is the monitor reference held by the task struct\n  and `result` is the return value of the task function.\n\n  Keep in mind that, regardless of how the task created with `async_nolink`\n  terminates, the caller's process will always receive a `:DOWN` message\n  with the same `ref` value that is held by the task struct. If the task\n  terminates normally, the reason in the `:DOWN` message will be `:normal`.\n\n  ## Examples\n\n  Typically, you use `async_nolink/3` when there is a reasonable expectation that\n  the task may fail, and you don't want it to take down the caller. Let's see an\n  example where a `GenServer` is meant to run a single task and track its status:\n\n      defmodule MyApp.Server do\n        use GenServer\n\n        # ...\n\n        def start_task do\n          GenServer.call(__MODULE__, :start_task)\n        end\n\n        # In this case the task is already running, so we just return :ok.\n        def handle_call(:start_task, _from, %{ref: ref} = state) when is_reference(ref) do\n          {:reply, :ok, state}\n        end\n\n        # The task is not running yet, so let's start it.\n        def handle_call(:start_task, _from, %{ref: nil} = state) do\n          task =\n            Task.Supervisor.async_nolink(MyApp.TaskSupervisor, fn ->\n              ...\n            end)\n\n          # We return :ok and the server will continue running\n          {:reply, :ok, %{state | ref: task.ref}}\n        end\n\n        # The task completed successfully\n        def handle_info({ref, answer}, %{ref: ref} = state) do\n          # We don't care about the DOWN message now, so let's demonitor and flush it\n          Process.demonitor(ref, [:flush])\n          # Do something with the result and then return\n          {:noreply, %{state | ref: nil}}\n        end\n\n        # The task failed\n        def handle_info({:DOWN, ref, :process, _pid, _reason}, %{ref: ref} = state) do\n          # Log and possibly restart the task...\n          {:noreply, %{state | ref: nil}}\n        end\n      end\n\n  \"\"\"\n  @spec async_nolink(Supervisor.supervisor(), (-> any), async_opts) :: Task.t()\n  def async_nolink(supervisor, fun, options \\\\ []) do\n    async_nolink(supervisor, :erlang, :apply, [fun, []], options)\n  end\n\n  @doc \"\"\"\n  Starts a task that can be awaited on.\n\n  The `supervisor` must be a reference as defined in `Supervisor`.\n  The task won't be linked to the caller, see `Task.async/1` for\n  more information.\n\n  Raises an error if `supervisor` has reached the maximum number of\n  children.\n\n  Note this function requires the task supervisor to have `:temporary`\n  as the `:restart` option (the default), as `async_nolink/5` keeps a\n  direct reference to the task which is lost if the task is restarted.\n  \"\"\"\n  @spec async_nolink(Supervisor.supervisor(), module, atom, [term], async_opts) :: Task.t()\n  def async_nolink(supervisor, module, fun, args, options \\\\ []) do\n    async(supervisor, :nolink, module, fun, args, options)\n  end\n\n  @doc \"\"\"\n  Returns a stream where the given function (`module` and `function`)\n  is mapped concurrently on each element in `enumerable`.\n\n  Each element will be prepended to the given `args` and processed by its\n  own task. The tasks will be spawned under the given `supervisor` and\n  linked to the caller process, similarly to `async/5`.\n\n  When streamed, each task will emit `{:ok, value}` upon successful\n  completion or `{:exit, reason}` if the caller is trapping exits.\n  The order of results depends on the value of the `:ordered` option.\n\n  The level of concurrency and the time tasks are allowed to run can\n  be controlled via options (see the \"Options\" section below).\n\n  If you find yourself trapping exits to handle exits inside\n  the async stream, consider using `async_stream_nolink/6` to start tasks\n  that are not linked to the calling process.\n\n  ## Options\n\n    * `:max_concurrency` - sets the maximum number of tasks to run\n      at the same time. Defaults to `System.schedulers_online/0`.\n\n    * `:ordered` - whether the results should be returned in the same order\n      as the input stream. This option is useful when you have large\n      streams and don't want to buffer results before they are delivered.\n      This is also useful when you're using the tasks for side effects.\n      Defaults to `true`.\n\n    * `:timeout` - the maximum amount of time to wait (in milliseconds)\n      without receiving a task reply (across all running tasks).\n      Defaults to `5000`.\n\n    * `:on_timeout` - what do to when a task times out. The possible\n      values are:\n      * `:exit` (default) - the process that spawned the tasks exits.\n      * `:kill_task` - the task that timed out is killed. The value\n        emitted for that task is `{:exit, :timeout}`.\n\n    * `:zip_input_on_exit` - (since v1.14.0) adds the original\n      input to `:exit` tuples. The value emitted for that task is\n      `{:exit, {input, reason}}`, where `input` is the collection element\n      that caused an exited during processing. Defaults to `false`.\n\n    * `:shutdown` - `:brutal_kill` if the tasks must be killed directly on shutdown\n      or an integer indicating the timeout value. Defaults to `5000` milliseconds.\n      The tasks must trap exits for the timeout to have an effect.\n\n  ## Examples\n\n  Let's build a stream and then enumerate it:\n\n      stream = Task.Supervisor.async_stream(MySupervisor, collection, Mod, :expensive_fun, [])\n      Enum.to_list(stream)\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec async_stream(\n          Supervisor.supervisor(),\n          Enumerable.t(),\n          module,\n          atom,\n          [term],\n          [async_stream_option]\n        ) :: Enumerable.t()\n  def async_stream(supervisor, enumerable, module, function, args, options \\\\ [])\n      when is_atom(module) and is_atom(function) and is_list(args) do\n    build_stream(supervisor, :link, enumerable, {module, function, args}, options)\n  end\n\n  @doc \"\"\"\n  Returns a stream that runs the given function `fun` concurrently\n  on each element in `enumerable`.\n\n  Each element in `enumerable` is passed as argument to the given function `fun`\n  and processed by its own task. The tasks will be spawned under the given\n  `supervisor` and linked to the caller process, similarly to `async/3`.\n\n  See `async_stream/6` for discussion, options, and examples.\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec async_stream(\n          Supervisor.supervisor(),\n          Enumerable.t(),\n          (term -> term),\n          [async_stream_option]\n        ) :: Enumerable.t()\n  def async_stream(supervisor, enumerable, fun, options \\\\ []) when is_function(fun, 1) do\n    build_stream(supervisor, :link, enumerable, fun, options)\n  end\n\n  @doc \"\"\"\n  Returns a stream where the given function (`module` and `function`)\n  is mapped concurrently on each element in `enumerable`.\n\n  Each element in `enumerable` will be prepended to the given `args` and processed\n  by its own task. The tasks will be spawned under the given `supervisor` and\n  will not be linked to the caller process, similarly to `async_nolink/5`.\n\n  See `async_stream/6` for discussion, options, and examples.\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec async_stream_nolink(\n          Supervisor.supervisor(),\n          Enumerable.t(),\n          module,\n          atom,\n          [term],\n          [async_stream_option]\n        ) :: Enumerable.t()\n  def async_stream_nolink(supervisor, enumerable, module, function, args, options \\\\ [])\n      when is_atom(module) and is_atom(function) and is_list(args) do\n    build_stream(supervisor, :nolink, enumerable, {module, function, args}, options)\n  end\n\n  @doc ~S\"\"\"\n  Returns a stream that runs the given `function` concurrently on each\n  element in `enumerable`.\n\n  Each element in `enumerable` is passed as argument to the given function `fun`\n  and processed by its own task. The tasks will be spawned under the given\n  `supervisor` and will not be linked to the caller process, similarly\n  to `async_nolink/3`.\n\n  See `async_stream/6` for discussion and examples.\n\n  ## Error handling and cleanup\n\n  Even if tasks are not linked to the caller, there is no risk of leaving dangling tasks\n  running after the stream halts.\n\n  Consider the following example:\n\n      Task.Supervisor.async_stream_nolink(MySupervisor, collection, fun, on_timeout: :kill_task, ordered: false)\n      |> Enum.each(fn\n        {:ok, _} -> :ok\n        {:exit, reason} -> raise \"Task exited: #{Exception.format_exit(reason)}\"\n      end)\n\n  If one task raises or times out:\n\n    1. the second clause gets called\n    2. an exception is raised\n    3. the stream halts\n    4. all ongoing tasks will be shut down\n\n  Here is another example:\n\n      Task.Supervisor.async_stream_nolink(MySupervisor, collection, fun, on_timeout: :kill_task, ordered: false)\n      |> Stream.filter(&match?({:ok, _}, &1))\n      |> Enum.take(3)\n\n  This will return the three first tasks to succeed, ignoring timeouts and errors, and shut down\n  every ongoing task.\n\n  Just running the stream with `Stream.run/1` on the other hand would ignore errors and process the whole stream.\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec async_stream_nolink(\n          Supervisor.supervisor(),\n          Enumerable.t(),\n          (term -> term),\n          [async_stream_option]\n        ) :: Enumerable.t()\n  def async_stream_nolink(supervisor, enumerable, fun, options \\\\ []) when is_function(fun, 1) do\n    build_stream(supervisor, :nolink, enumerable, fun, options)\n  end\n\n  @doc \"\"\"\n  Terminates the child with the given `pid`.\n  \"\"\"\n  @spec terminate_child(Supervisor.supervisor(), pid) :: :ok | {:error, :not_found}\n  def terminate_child(supervisor, pid) when is_pid(pid) do\n    DynamicSupervisor.terminate_child(supervisor, pid)\n  end\n\n  @doc \"\"\"\n  Returns all children PIDs except those that are restarting.\n\n  Note that calling this function when supervising a large number\n  of children under low memory conditions can bring the system down due to an\n  out of memory error.\n  \"\"\"\n  @spec children(Supervisor.supervisor()) :: [pid]\n  def children(supervisor) do\n    for {_, pid, _, _} <- DynamicSupervisor.which_children(supervisor), is_pid(pid), do: pid\n  end\n\n  @doc \"\"\"\n  Starts a task as a child of the given `supervisor`.\n\n      Task.Supervisor.start_child(MyTaskSupervisor, fn ->\n        IO.puts(\"I am running in a task\")\n      end)\n\n  Note that the spawned process is not linked to the caller, but\n  only to the supervisor. This command is useful in case the\n  task needs to perform side-effects (like I/O) and you have no\n  interest in its results nor if it completes successfully.\n\n  ## Options\n\n    * `:restart` - the restart strategy, may be `:temporary` (the default),\n      `:transient` or `:permanent`. `:temporary` means the task is never\n      restarted, `:transient` means it is restarted if the exit is not\n      `:normal`, `:shutdown` or `{:shutdown, reason}`. A `:permanent` restart\n      strategy means it is always restarted.\n\n    * `:shutdown` - `:brutal_kill` if the task must be killed directly on shutdown\n      or an integer indicating the timeout value, defaults to 5000 milliseconds.\n      The task must trap exits for the timeout to have an effect.\n\n  \"\"\"\n  @spec start_child(Supervisor.supervisor(), (-> any), start_child_opts) ::\n          DynamicSupervisor.on_start_child()\n  def start_child(supervisor, fun, options \\\\ []) do\n    restart = options[:restart]\n    shutdown = options[:shutdown]\n    args = [get_owner(self()), get_callers(self()), {:erlang, :apply, [fun, []]}]\n    start_child_with_spec(supervisor, args, restart, shutdown)\n  end\n\n  @doc \"\"\"\n  Starts a task as a child of the given `supervisor`.\n\n  Similar to `start_child/3` except the task is specified\n  by the given `module`, `fun` and `args`.\n  \"\"\"\n  @spec start_child(Supervisor.supervisor(), module, atom, [term], start_child_opts) ::\n          DynamicSupervisor.on_start_child()\n  def start_child(supervisor, module, fun, args, options \\\\ [])\n      when is_atom(fun) and is_list(args) do\n    restart = options[:restart]\n    shutdown = options[:shutdown]\n    mfa = {module, fun, args}\n    owner = get_owner(self())\n    callers = get_callers(self())\n\n    if restart == :temporary or restart == nil do\n      start_child_maybe_temporary(supervisor, owner, callers, restart, shutdown, mfa)\n    else\n      start_child_with_spec(supervisor, [owner, callers, mfa], restart, shutdown)\n    end\n  end\n\n  defp start_child_maybe_temporary(supervisor, owner, callers, restart, shutdown, mfa) do\n    case start_child_with_spec(supervisor, [owner, :monitor], restart, shutdown) do\n      # TODO: This only exists because we need to support reading restart/shutdown\n      # from two different places. Remove this, the init function and the associated\n      # clause in DynamicSupervisor on Elixir v2.0\n      {:restart, restart} ->\n        start_child_with_spec(supervisor, [owner, callers, mfa], restart, shutdown)\n\n      {:ok, pid} ->\n        # We mimic async but there is nothing to reply to\n        alias = make_ref()\n        send(pid, {self(), alias, alias, callers, mfa})\n        {:ok, pid}\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  defp start_child_with_spec(supervisor, args, restart, shutdown) do\n    GenServer.call(supervisor, {:start_task, args, restart, shutdown}, :infinity)\n  end\n\n  defp get_owner(pid) do\n    self_or_name =\n      case Process.info(pid, :registered_name) do\n        {:registered_name, name} when is_atom(name) -> name\n        _ -> pid\n      end\n\n    {node(), self_or_name, pid}\n  end\n\n  defp get_callers(owner) do\n    case :erlang.get(:\"$callers\") do\n      [_ | _] = list -> [owner | list]\n      _ -> [owner]\n    end\n  end\n\n  defp async(supervisor, link_type, module, fun, args, options) do\n    owner = self()\n    shutdown = options[:shutdown]\n\n    case start_child_with_spec(supervisor, [get_owner(owner), :monitor], :temporary, shutdown) do\n      {:ok, pid} ->\n        if link_type == :link, do: Process.link(pid)\n        alias = Task.__alias__(pid)\n        send(pid, {owner, alias, alias, get_callers(owner), {module, fun, args}})\n        %Task{pid: pid, ref: alias, owner: owner, mfa: {module, fun, length(args)}}\n\n      {:error, :max_children} ->\n        raise \"\"\"\n        reached the maximum number of tasks for this task supervisor. The maximum number \\\n        of tasks that are allowed to run at the same time under this supervisor can be \\\n        configured with the :max_children option passed to Task.Supervisor.start_link/1\\\n        \"\"\"\n    end\n  end\n\n  defp build_stream(supervisor, link_type, enumerable, fun, options) do\n    shutdown = Keyword.get(options, :shutdown, 5000)\n\n    if not ((is_integer(shutdown) and shutdown >= 0) or shutdown == :brutal_kill) do\n      raise ArgumentError, \":shutdown must be either a positive integer or :brutal_kill\"\n    end\n\n    options = Task.Supervised.validate_stream_options(options)\n\n    fn acc, acc_fun ->\n      owner = get_owner(self())\n\n      Task.Supervised.stream(enumerable, acc, acc_fun, get_callers(self()), fun, options, fn ->\n        args = [owner, :monitor]\n\n        case start_child_with_spec(supervisor, args, :temporary, shutdown) do\n          {:ok, pid} ->\n            if link_type == :link, do: Process.link(pid)\n            {:ok, link_type, pid}\n\n          {:error, :max_children} ->\n            {:error, :max_children}\n        end\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/task.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Task do\n  @moduledoc \"\"\"\n  Conveniences for spawning and awaiting tasks.\n\n  Tasks are processes meant to execute one particular\n  action throughout their lifetime, often with little or no\n  communication with other processes. The most common use case\n  for tasks is to convert sequential code into concurrent code\n  by computing a value asynchronously:\n\n      task = Task.async(fn -> do_some_work() end)\n      res = do_some_other_work()\n      res + Task.await(task)\n\n  Tasks spawned with `async` can be awaited on by their caller\n  process (and only their caller) as shown in the example above.\n  They are implemented by spawning a process that sends a message\n  to the caller once the given computation is performed.\n\n  Compared to plain processes, started with `spawn/1`, tasks\n  include monitoring metadata and logging in case of errors.\n\n  Besides `async/1` and `await/2`, tasks can also be\n  started as part of a supervision tree and dynamically spawned\n  on remote nodes. We will explore these scenarios next.\n\n  ## async and await\n\n  One of the common uses of tasks is to convert sequential code\n  into concurrent code with `Task.async/1` while keeping its semantics.\n  When invoked, a new process will be created, linked and monitored\n  by the caller. Once the task action finishes, a message will be sent\n  to the caller with the result.\n\n  `Task.await/2` is used to read the message sent by the task.\n\n  There are two important things to consider when using `async`:\n\n    1. If you are using async tasks, you **must await** a reply\n       as they are *always* sent. If you are not expecting a reply,\n       consider using `Task.start_link/1` as detailed below.\n\n    2. Async tasks link the caller and the spawned process. This\n       means that, if the caller crashes, the task will crash\n       too and vice-versa. This is on purpose: if the process\n       meant to receive the result no longer exists, there is\n       no purpose in completing the computation. If this is not\n       desired, you will want to use supervised tasks, described\n       in a subsequent section.\n\n  ## Tasks are processes\n\n  Tasks are processes and so data will need to be completely copied\n  to them. Take the following code as an example:\n\n      large_data = fetch_large_data()\n      task = Task.async(fn -> do_some_work(large_data) end)\n      res = do_some_other_work()\n      res + Task.await(task)\n\n  The code above copies over all of `large_data`, which can be\n  resource intensive depending on the size of the data.\n  There are two ways to address this.\n\n  First, if you need to access only part of `large_data`,\n  consider extracting it before the task:\n\n      large_data = fetch_large_data()\n      subset_data = large_data.some_field\n      task = Task.async(fn -> do_some_work(subset_data) end)\n\n  Alternatively, if you can move the data loading altogether\n  to the task, it may be even better:\n\n      task = Task.async(fn ->\n        large_data = fetch_large_data()\n        do_some_work(large_data)\n      end)\n\n  ## Dynamically supervised tasks\n\n  The `Task.Supervisor` module allows developers to dynamically\n  create multiple supervised tasks.\n\n  A short example is:\n\n      {:ok, pid} = Task.Supervisor.start_link()\n\n      task =\n        Task.Supervisor.async(pid, fn ->\n          # Do something\n        end)\n\n      Task.await(task)\n\n  However, in the majority of cases, you want to add the task supervisor\n  to your supervision tree:\n\n      Supervisor.start_link([\n        {Task.Supervisor, name: MyApp.TaskSupervisor}\n      ], strategy: :one_for_one)\n\n  And now you can use async/await by passing the name of\n  the supervisor instead of the PID:\n\n      Task.Supervisor.async(MyApp.TaskSupervisor, fn ->\n        # Do something\n      end)\n      |> Task.await()\n\n  We encourage developers to rely on supervised tasks as much as possible.\n  Supervised tasks improve the visibility of how many tasks are running\n  at a given moment and enable a variety of patterns that give you\n  explicit control on how to handle the results, errors, and timeouts.\n  Here is a summary:\n\n    * Using `Task.Supervisor.start_child/2` allows you to start a fire-and-forget\n      task when you don't care about its results or if it completes successfully or not.\n\n    * Using `Task.Supervisor.async/2` + `Task.await/2` allows you to execute\n      tasks concurrently and retrieve its result. If the task fails,\n      the caller will also fail.\n\n    * Using `Task.Supervisor.async_nolink/2` + `Task.yield/2` + `Task.shutdown/2`\n      allows you to execute tasks concurrently and retrieve their results\n      or the reason they failed within a given time frame. If the task fails,\n      the caller won't fail. You will receive the error reason either on\n      `yield` or `shutdown`.\n\n  Furthermore, the supervisor guarantees all tasks terminate within a\n  configurable shutdown period when your application shuts down. See the\n  `Task.Supervisor` module for details on the supported operations.\n\n  ### Distributed tasks\n\n  With `Task.Supervisor`, it is easy to dynamically start tasks across nodes:\n\n      # First on the remote node named :remote@local\n      Task.Supervisor.start_link(name: MyApp.DistSupervisor)\n\n      # Then on the local client node\n      supervisor = {MyApp.DistSupervisor, :remote@local}\n      Task.Supervisor.async(supervisor, MyMod, :my_fun, [arg1, arg2, arg3])\n\n  Note that, as above, when working with distributed tasks, one should use the\n  `Task.Supervisor.async/5` function that expects explicit module, function,\n  and arguments, instead of `Task.Supervisor.async/3` that works with anonymous\n  functions. That's because anonymous functions expect the same module version\n  to exist on all involved nodes. Check the `Agent` module documentation for\n  more information on distributed processes as the limitations described there\n  apply to the whole ecosystem.\n\n  ## Statically supervised tasks\n\n  The `Task` module implements the `child_spec/1` function, which\n  allows it to be started directly under a regular `Supervisor` -\n  instead of a `Task.Supervisor` - by passing a tuple with a function\n  to run:\n\n      Supervisor.start_link([\n        {Task, fn -> :some_work end}\n      ], strategy: :one_for_one)\n\n  This is often useful when you need to execute code concurrently while\n  setting up your supervision tree. For example: to warm up caches,\n  log the initialization status, and such.\n\n  If you don't want to put the Task code directly under the `Supervisor`,\n  you can wrap the `Task` in its own module, similar to how you would\n  do with a `GenServer` or an `Agent`:\n\n      defmodule MyTask do\n        use Task\n\n        def start_link(arg) do\n          Task.start_link(__MODULE__, :run, [arg])\n        end\n\n        def run(arg) do\n          # ...\n        end\n      end\n\n  And then passing it to the supervisor:\n\n      Supervisor.start_link([\n        {MyTask, arg}\n      ], strategy: :one_for_one)\n\n  Since these tasks are supervised and not directly linked to the caller,\n  they cannot be awaited on. By default, the functions `Task.start/1`\n  and `Task.start_link/1` are for fire-and-forget tasks, where you don't\n  care about the results or if it completes successfully or not.\n\n  Keep in mind the Supervisor will not wait for the task to finish running\n  before starting the next child or returning. If you need synchronous\n  initialization, then either use an `Agent` or a `GenServer`.\n\n  > #### `use Task` {: .info}\n  >\n  > When you `use Task`, the `Task` module will define a\n  > `child_spec/1` function, so your module can be used\n  > as a child in a supervision tree.\n\n  The generated `child_spec/1` can be customized with the following options:\n\n    * `:id` - the child specification identifier, defaults to the current module\n    * `:restart` - when the child should be restarted, defaults to `:temporary`\n    * `:shutdown` - how to shut down the child, either immediately or by giving it time to shut down\n\n  Opposite to `GenServer`, `Agent` and `Supervisor`, a Task has\n  a default `:restart` of `:temporary`. This means the task will\n  not be restarted even if it crashes. If you desire the task to\n  be restarted for non-successful exits, do:\n\n      use Task, restart: :transient\n\n  If you want the task to always be restarted:\n\n      use Task, restart: :permanent\n\n  See the \"Child specification\" section in the `Supervisor` module\n  for more detailed information. The `@doc` annotation immediately\n  preceding `use Task` will be attached to the generated `child_spec/1`\n  function.\n\n  ## Ancestor and Caller Tracking\n\n  Whenever you start a new process, Elixir annotates the process with the parent\n  through the `$ancestors` key in the process dictionary. This is often used to\n  track the hierarchy inside a supervision tree.\n\n  For example, we recommend developers to always start tasks under a supervisor.\n  This provides more visibility and allows you to control how those tasks are\n  terminated when a node shuts down. That might look something like\n  `Task.Supervisor.start_child(MySupervisor, task_function)`. This means\n  that, although your code is the one invoking the task, the actual ancestor of\n  the task is the supervisor, as the supervisor is the one effectively starting it.\n\n  To track the relationship between your code and the task, we use the `$callers`\n  key in the process dictionary. Therefore, assuming the `Task.Supervisor` call\n  above, we have:\n\n      [your code] -- calls --> [supervisor] ---- spawns --> [task]\n\n  Which means we store the following relationships:\n\n      [your code]              [supervisor] <-- ancestor -- [task]\n          ^                                                  |\n          |--------------------- caller ---------------------|\n\n  The list of callers of the current process can be retrieved from the Process\n  dictionary with `Process.get(:\"$callers\")`. This will return either `nil` or\n  a list `[pid_n, ..., pid2, pid1]` with at least one entry where `pid_n` is\n  the PID that called the current process, `pid2` called `pid_n`, and `pid2` was\n  called by `pid1`.\n\n  If a task crashes, the callers field is included as part of the log message\n  metadata under the `:callers` key.\n  \"\"\"\n\n  @doc \"\"\"\n  The Task struct.\n\n  It contains these fields:\n\n    * `:mfa` - a three-element tuple containing the module, function name,\n      and arity invoked to start the task in `async/1` and `async/3`\n\n    * `:owner` - the PID of the process that started the task\n\n    * `:pid` - the PID of the task process; `nil` if there is no process\n      specifically assigned for the task\n\n    * `:ref` - an opaque term used as the task monitor reference\n\n  \"\"\"\n  @enforce_keys [:mfa, :owner, :pid, :ref]\n  defstruct @enforce_keys\n\n  @typedoc \"\"\"\n  The Task type.\n\n  See [`%Task{}`](`__struct__/0`) for information about each field of the structure.\n  \"\"\"\n  @type t :: %__MODULE__{\n          mfa: mfa(),\n          owner: pid(),\n          pid: pid() | nil,\n          ref: ref()\n        }\n\n  @typedoc \"\"\"\n  The task opaque reference.\n  \"\"\"\n  @opaque ref :: reference()\n\n  @typedoc \"\"\"\n  Options given to `async_stream` functions.\n  \"\"\"\n  @typedoc since: \"1.17.0\"\n  @type async_stream_option ::\n          {:max_concurrency, pos_integer()}\n          | {:ordered, boolean()}\n          | {:timeout, timeout()}\n          | {:on_timeout, :exit | :kill_task}\n          | {:zip_input_on_exit, boolean()}\n\n  defguardp is_timeout(timeout)\n            when timeout == :infinity or (is_integer(timeout) and timeout >= 0)\n\n  @doc \"\"\"\n  Returns a specification to start a task under a supervisor.\n\n  `arg` is passed as the argument to `Task.start_link/1` in the `:start` field\n  of the spec.\n\n  For more information, see the `Supervisor` module,\n  the `Supervisor.child_spec/2` function and the `t:Supervisor.child_spec/0` type.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec child_spec(term) :: Supervisor.child_spec()\n  def child_spec(arg) do\n    %{\n      id: Task,\n      start: {Task, :start_link, [arg]},\n      restart: :temporary\n    }\n  end\n\n  @doc false\n  defmacro __using__(opts) do\n    quote location: :keep, bind_quoted: [opts: opts] do\n      if not Module.has_attribute?(__MODULE__, :doc) do\n        @doc \"\"\"\n        Returns a specification to start this module under a supervisor.\n\n        `arg` is passed as the argument to `Task.start_link/1` in the `:start` field\n        of the spec.\n\n        For more information, see the `Supervisor` module,\n        the `Supervisor.child_spec/2` function and the `t:Supervisor.child_spec/0` type.\n        \"\"\"\n      end\n\n      def child_spec(arg) do\n        default = %{\n          id: __MODULE__,\n          start: {__MODULE__, :start_link, [arg]},\n          restart: :temporary\n        }\n\n        Supervisor.child_spec(default, unquote(Macro.escape(opts)))\n      end\n\n      defoverridable child_spec: 1\n    end\n  end\n\n  @doc \"\"\"\n  Starts a task as part of a supervision tree with the given `fun`.\n\n  `fun` must be a zero-arity anonymous function.\n\n  This is used to start a statically supervised task under a supervision tree.\n  \"\"\"\n  @spec start_link((-> any)) :: {:ok, pid}\n  def start_link(fun) when is_function(fun, 0) do\n    start_link(:erlang, :apply, [fun, []])\n  end\n\n  @doc \"\"\"\n  Starts a task as part of a supervision tree with the given\n  `module`, `function`, and `args`.\n\n  This is used to start a statically supervised task under a supervision tree.\n  \"\"\"\n  @spec start_link(module, atom, [term]) :: {:ok, pid}\n  def start_link(module, function, args)\n      when is_atom(module) and is_atom(function) and is_list(args) do\n    mfa = {module, function, args}\n    Task.Supervised.start_link(get_owner(self()), get_callers(self()), mfa)\n  end\n\n  @doc \"\"\"\n  Starts a task.\n\n  `fun` must be a zero-arity anonymous function.\n\n  This should only used when the task is used for side-effects\n  (like I/O) and you have no interest on its results nor if it\n  completes successfully.\n\n  If the current node is shutdown, the node will terminate even\n  if the task was not completed. For this reason, we recommend\n  to use `Task.Supervisor.start_child/2` instead, which allows\n  you to control the shutdown time via the `:shutdown` option.\n  \"\"\"\n  @spec start((-> any)) :: {:ok, pid}\n  def start(fun) when is_function(fun, 0) do\n    start(:erlang, :apply, [fun, []])\n  end\n\n  @doc \"\"\"\n  Starts a task.\n\n  This should only used when the task is used for side-effects\n  (like I/O) and you have no interest on its results nor if it\n  completes successfully.\n\n  If the current node is shutdown, the node will terminate even\n  if the task was not completed. For this reason, we recommend\n  to use `Task.Supervisor.start_child/2` instead, which allows\n  you to control the shutdown time via the `:shutdown` option.\n  \"\"\"\n  @spec start(module, atom, [term]) :: {:ok, pid}\n  def start(module, function_name, args)\n      when is_atom(module) and is_atom(function_name) and is_list(args) do\n    mfa = {module, function_name, args}\n    Task.Supervised.start(get_owner(self()), get_callers(self()), mfa)\n  end\n\n  @doc \"\"\"\n  Starts a task that must be awaited on.\n\n  `fun` must be a zero-arity anonymous function. This function\n  spawns a process that is linked to and monitored by the caller\n  process. A `Task` struct is returned containing the relevant\n  information.\n\n  If you start an `async`, you **must await**. This is either done\n  by calling `Task.await/2` or `Task.yield/2` followed by\n  `Task.shutdown/2` on the returned task. Alternatively, if you\n  spawn a task inside a `GenServer`, then the `GenServer` will\n  automatically await for you and call `c:GenServer.handle_info/2`\n  with the task response and associated `:DOWN` message.\n\n  Read the `Task` module documentation for more information about\n  the general usage of async tasks.\n\n  ## Linking\n\n  This function spawns a process that is linked to and monitored\n  by the caller process. The linking part is important because it\n  aborts the task if the parent process dies. It also guarantees\n  the code before async/await has the same properties after you\n  add the async call. For example, imagine you have this:\n\n      x = heavy_function()\n      y = some_function()\n      x + y\n\n  Now you want to make the `heavy_function()` async:\n\n      x = Task.async(&heavy_function/0)\n      y = some_function()\n      Task.await(x) + y\n\n  As before, if `heavy_function/0` fails, the whole computation will\n  fail, including the caller process. If you don't want the task\n  to fail then you must change the `heavy_fun/0` code in the\n  same way you would achieve it if you didn't have the async call.\n  For example, to either return `{:ok, val} | :error` results or,\n  in more extreme cases, by using `try/rescue`. In other words,\n  an asynchronous task should be thought of as an extension of the\n  caller process rather than a mechanism to isolate it from all errors.\n\n  If you don't want to link the caller to the task, then you\n  must use a supervised task with `Task.Supervisor` and call\n  `Task.Supervisor.async_nolink/2`.\n\n  In any case, avoid any of the following:\n\n    * Setting `:trap_exit` to `true` - trapping exits should be\n      used only in special circumstances as it would make your\n      process immune to not only exits from the task but from\n      any other processes.\n\n      Moreover, even when trapping exits, calling `await` will\n      still exit if the task has terminated without sending its\n      result back.\n\n    * Unlinking the task process started with `async`/`await`.\n      If you unlink the processes and the task does not belong\n      to any supervisor, you may leave dangling tasks in case\n      the caller process dies.\n\n  ## Metadata\n\n  The task created with this function stores `:erlang.apply/2` in\n  its `:mfa` metadata field, which is used internally to apply\n  the anonymous function. Use `async/3` if you want another function\n  to be used as metadata.\n  \"\"\"\n  @spec async((-> any)) :: t\n  def async(fun) when is_function(fun, 0) do\n    async(:erlang, :apply, [fun, []])\n  end\n\n  @doc \"\"\"\n  Starts a task that must be awaited on.\n\n  Similar to `async/1` except the function to be started is\n  specified by the given `module`, `function_name`, and `args`.\n  The `module`, `function_name`, and its arity are stored as\n  a tuple in the `:mfa` field for reflection purposes.\n  \"\"\"\n  @spec async(module, atom, [term]) :: t\n  def async(module, function_name, args)\n      when is_atom(module) and is_atom(function_name) and is_list(args) do\n    mfargs = {module, function_name, args}\n    owner = self()\n    # No need to monitor because the processes are linked\n    {:ok, pid} = Task.Supervised.start_link(get_owner(owner), :nomonitor)\n\n    alias = build_alias(pid)\n    send(pid, {owner, alias, alias, get_callers(owner), mfargs})\n    %Task{pid: pid, ref: alias, owner: owner, mfa: {module, function_name, length(args)}}\n  end\n\n  @doc \"\"\"\n  Starts a task that immediately completes with the given `result`.\n\n  Unlike `async/1`, this task does not spawn a linked process. It can\n  be awaited or yielded like any other task.\n\n  ## Usage\n\n  In some cases, it is useful to create a \"completed\" task that represents\n  a task that has already run and generated a result. For example, when\n  processing data you may be able to determine that certain inputs are\n  invalid before dispatching them for further processing:\n\n      def process(data) do\n        tasks =\n          for entry <- data do\n            if invalid_input?(entry) do\n              Task.completed({:error, :invalid_input})\n            else\n              Task.async(fn -> further_process(entry) end)\n            end\n          end\n\n        Task.await_many(tasks)\n      end\n\n  In many cases, `Task.completed/1` may be avoided in favor of returning the\n  result directly.  You should generally only require this variant when working\n  with mixed asynchrony, when a group of inputs will be handled partially\n  synchronously and partially asynchronously.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec completed(any) :: t\n  def completed(result) do\n    ref = make_ref()\n    owner = self()\n\n    # \"complete\" the task immediately\n    send(owner, {ref, result})\n\n    %Task{pid: nil, ref: ref, owner: owner, mfa: {Task, :completed, 1}}\n  end\n\n  @doc \"\"\"\n  Returns a stream where the given function (`module` and `function_name`)\n  is mapped concurrently on each element in `enumerable`.\n\n  Each element of `enumerable` will be prepended to the given `args` and\n  processed by its own task. Those tasks will be linked to an intermediate\n  process that is then linked to the caller process. This means a failure\n  in a task terminates the caller process and a failure in the caller\n  process terminates all tasks.\n\n  When streamed, each task will emit `{:ok, value}` upon successful\n  completion or `{:exit, reason}` if the caller is trapping exits.\n  It's possible to have `{:exit, {element, reason}}` for exits\n  using the `:zip_input_on_exit` option. The order of results depends\n  on the value of the `:ordered` option.\n\n  The level of concurrency and the time tasks are allowed to run can\n  be controlled via options (see the \"Options\" section below).\n\n  Consider using `Task.Supervisor.async_stream/6` to start tasks\n  under a supervisor. If you find yourself trapping exits to ensure\n  errors in the tasks do not terminate the caller process, consider\n  using `Task.Supervisor.async_stream_nolink/6` to start tasks that\n  are not linked to the caller process.\n\n  ## Options\n\n    * `:max_concurrency` - sets the maximum number of tasks to run\n      at the same time. Defaults to `System.schedulers_online/0`.\n\n    * `:ordered` - whether the results should be returned in the same order\n      as the input stream. When the output is ordered, Elixir may need to\n      buffer results to emit them in the original order. Setting this option\n      to false disables the need to buffer at the cost of removing ordering.\n      This is also useful when you're using the tasks only for the side effects.\n      Note that regardless of what `:ordered` is set to, the tasks will\n      process asynchronously. If you need to process elements in order,\n      consider using `Enum.map/2` or `Enum.each/2` instead. Defaults to `true`.\n\n    * `:timeout` - the maximum amount of time (in milliseconds or `:infinity`)\n      each task is allowed to execute for. Defaults to `5000`.\n\n    * `:on_timeout` - what to do when a task times out. The possible\n      values are:\n      * `:exit` (default) - the caller (the process that spawned the tasks) exits.\n      * `:kill_task` - the task that timed out is killed. The value\n        emitted for that task is `{:exit, :timeout}`.\n\n    * `:zip_input_on_exit` - (since v1.14.0) adds the original\n      input to `:exit` tuples. The value emitted for that task is\n      `{:exit, {input, reason}}`, where `input` is the collection element\n      that caused an exit during processing. Defaults to `false`.\n\n  ## Example\n\n  Let's build a stream and then enumerate it:\n\n      stream = Task.async_stream(collection, Mod, :expensive_fun, [])\n      Enum.to_list(stream)\n\n  The concurrency can be increased or decreased using the `:max_concurrency`\n  option. For example, if the tasks are IO heavy, the value can be increased:\n\n      max_concurrency = System.schedulers_online() * 2\n      stream = Task.async_stream(collection, Mod, :expensive_fun, [], max_concurrency: max_concurrency)\n      Enum.to_list(stream)\n\n  If you do not care about the results of the computation, you can run\n  the stream with `Stream.run/1`. Also set `ordered: false`, as you don't\n  care about the order of the results either:\n\n      stream = Task.async_stream(collection, Mod, :expensive_fun, [], ordered: false)\n      Stream.run(stream)\n\n  ## First async tasks to complete\n\n  You can also use `async_stream/3` to execute M tasks and find the N tasks\n  to complete. For example:\n\n      [\n        &heavy_call_1/0,\n        &heavy_call_2/0,\n        &heavy_call_3/0\n      ]\n      |> Task.async_stream(fn fun -> fun.() end, ordered: false, max_concurrency: 3)\n      |> Stream.filter(&match?({:ok, _}, &1))\n      |> Enum.take(2)\n\n  In the example above, we are executing three tasks and waiting for the\n  first 2 to complete. We use `Stream.filter/2` to restrict ourselves only\n  to successfully completed tasks, and then use `Enum.take/2` to retrieve\n  N items. Note it is important to set both `ordered: false` and\n  `max_concurrency: M`, where M is the number of tasks, to make sure all\n  calls execute concurrently.\n\n  ### Attention: unbound async + take\n\n  If you want to potentially process a high number of items and keep only\n  part of the results, you may end-up processing more items than desired.\n  Let's see an example:\n\n      1..100\n      |> Task.async_stream(fn i ->\n        Process.sleep(100)\n        IO.puts(to_string(i))\n      end)\n      |> Enum.take(10)\n\n  Running the example above in a machine with 8 cores will process 16 items,\n  even though you want only 10 elements, since `async_stream/3` process items\n  concurrently. That's because it will process 8 elements at once. Then all 8\n  elements complete at roughly the same time, causing 8 elements to be kicked\n  off for processing. Out of these extra 8, only 2 will be used, and the rest\n  will be terminated.\n\n  Depending on the problem, you can filter or limit the number of elements\n  upfront:\n\n      1..100\n      |> Stream.take(10)\n      |> Task.async_stream(fn i ->\n        Process.sleep(100)\n        IO.puts(to_string(i))\n      end)\n      |> Enum.to_list()\n\n  In other cases, you likely want to tweak `:max_concurrency` to limit how\n  many elements may be over processed at the cost of reducing concurrency.\n  You can also set the number of elements to take to be a multiple of\n  `:max_concurrency`. For instance, setting `max_concurrency: 5` in the\n  example above.\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec async_stream(Enumerable.t(), module, atom, [term], [async_stream_option]) ::\n          Enumerable.t()\n  def async_stream(enumerable, module, function_name, args, options \\\\ [])\n      when is_atom(module) and is_atom(function_name) and is_list(args) do\n    build_stream(enumerable, {module, function_name, args}, options)\n  end\n\n  @doc \"\"\"\n  Returns a stream that runs the given function `fun` concurrently\n  on each element in `enumerable`.\n\n  Works the same as `async_stream/5` but with an anonymous function instead of a\n  module-function-arguments tuple. `fun` must be a one-arity anonymous function.\n\n  Each `enumerable` element is passed as argument to the given function `fun` and\n  processed by its own task. The tasks will be linked to the caller process, similarly\n  to `async/1`.\n\n  ## Example\n\n  Count the code points in each string asynchronously, then add the counts together using reduce.\n\n      iex> strings = [\"long string\", \"longer string\", \"there are many of these\"]\n      iex> stream = Task.async_stream(strings, fn text -> text |> String.codepoints() |> Enum.count() end)\n      iex> Enum.sum_by(stream, fn {:ok, num} -> num end)\n      47\n\n  See `async_stream/5` for discussion, options, and more examples.\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec async_stream(Enumerable.t(), (term -> term), [async_stream_option]) :: Enumerable.t()\n  def async_stream(enumerable, fun, options \\\\ [])\n      when is_function(fun, 1) and is_list(options) do\n    build_stream(enumerable, fun, options)\n  end\n\n  defp build_stream(enumerable, fun, options) do\n    options = Task.Supervised.validate_stream_options(options)\n\n    fn acc, acc_fun ->\n      owner = get_owner(self())\n\n      Task.Supervised.stream(enumerable, acc, acc_fun, get_callers(self()), fun, options, fn ->\n        # No need to monitor because the processes are linked\n        {:ok, pid} = Task.Supervised.start_link(owner, :nomonitor)\n        {:ok, :link, pid}\n      end)\n    end\n  end\n\n  # Returns a tuple with the node where this is executed and either the\n  # registered name of the given PID or the PID of where this is executed. Used\n  # when exiting from tasks to print out from where the task was started.\n  defp get_owner(pid) do\n    self_or_name =\n      case Process.info(pid, :registered_name) do\n        {:registered_name, name} when is_atom(name) -> name\n        _ -> pid\n      end\n\n    {node(), self_or_name, pid}\n  end\n\n  defp get_callers(owner) do\n    case :erlang.get(:\"$callers\") do\n      [_ | _] = list -> [owner | list]\n      _ -> [owner]\n    end\n  end\n\n  @doc ~S\"\"\"\n  Awaits a task reply and returns it.\n\n  In case the task process dies, the caller process will exit with the same\n  reason as the task.\n\n  A timeout, in milliseconds or `:infinity`, can be given with a default value\n  of `5000`. If the timeout is exceeded, then the caller process will exit.\n  If the task process is linked to the caller process which is the case when\n  a task is started with `async`, then the task process will also exit. If the\n  task process is trapping exits or not linked to the caller process, then it\n  will continue to run.\n\n  This function assumes the task's monitor is still active or the monitor's\n  `:DOWN` message is in the message queue. If it has been demonitored, or the\n  message already received, this function will wait for the duration of the\n  timeout awaiting the message.\n\n  This function can only be called once for any given task. If you want\n  to be able to check multiple times if a long-running task has finished\n  its computation, use `yield/2` instead.\n\n  ## Examples\n\n      iex> task = Task.async(fn -> 1 + 1 end)\n      iex> Task.await(task)\n      2\n\n  ## Compatibility with OTP behaviours\n\n  It is not recommended to `await` a long-running task inside an OTP\n  behaviour such as `GenServer`. Instead, you should match on the message\n  coming from a task inside your `c:GenServer.handle_info/2` callback.\n\n  A GenServer will receive two messages on `handle_info/2`:\n\n    * `{ref, result}` - the reply message where `ref` is the monitor\n      reference returned by the `task.ref` and `result` is the task\n      result\n\n    * `{:DOWN, ref, :process, pid, reason}` - since all tasks are also\n      monitored, you will also receive the `:DOWN` message delivered by\n      `Process.monitor/1`. If you receive the `:DOWN` message without a\n      a reply, it means the task crashed\n\n  Another consideration to have in mind is that tasks started by `Task.async/1`\n  are always linked to their callers and you may not want the GenServer to\n  crash if the task crashes. Therefore, it is preferable to instead use\n  `Task.Supervisor.async_nolink/3` inside OTP behaviours. For completeness, here\n  is an example of a GenServer that start tasks and handles their results:\n\n      defmodule GenServerTaskExample do\n        use GenServer\n\n        def start_link(opts) do\n          GenServer.start_link(__MODULE__, :ok, opts)\n        end\n\n        def init(_opts) do\n          # We will keep all running tasks in a map\n          {:ok, %{tasks: %{}}}\n        end\n\n        # Imagine we invoke a task from the GenServer to access a URL...\n        def handle_call(:some_message, _from, state) do\n          url = ...\n          task = Task.Supervisor.async_nolink(MyApp.TaskSupervisor, fn -> fetch_url(url) end)\n\n          # After we start the task, we store its reference and the url it is fetching\n          state = put_in(state.tasks[task.ref], url)\n\n          {:reply, :ok, state}\n        end\n\n        # If the task succeeds...\n        def handle_info({ref, result}, state) do\n          # The task succeed so we can demonitor its reference\n          Process.demonitor(ref, [:flush])\n\n          {url, state} = pop_in(state.tasks[ref])\n          IO.puts(\"Got #{inspect(result)} for URL #{inspect url}\")\n          {:noreply, state}\n        end\n\n        # If the task fails...\n        def handle_info({:DOWN, ref, _, _, reason}, state) do\n          {url, state} = pop_in(state.tasks[ref])\n          IO.puts(\"URL #{inspect url} failed with reason #{inspect(reason)}\")\n          {:noreply, state}\n        end\n      end\n\n  With the server defined, you will want to start the task supervisor\n  above and the GenServer in your supervision tree:\n\n      children = [\n        {Task.Supervisor, name: MyApp.TaskSupervisor},\n        {GenServerTaskExample, name: MyApp.GenServerTaskExample}\n      ]\n\n      Supervisor.start_link(children, strategy: :one_for_one)\n\n  \"\"\"\n  @spec await(t, timeout) :: term\n  def await(%Task{ref: ref, owner: owner} = task, timeout \\\\ 5000) when is_timeout(timeout) do\n    if owner != self() do\n      raise ArgumentError, invalid_owner_error(task)\n    end\n\n    await_receive(ref, task, timeout)\n  end\n\n  defp await_receive(ref, task, timeout) do\n    receive do\n      {^ref, reply} ->\n        demonitor(ref)\n        reply\n\n      {:DOWN, ^ref, _, proc, reason} ->\n        exit({reason(reason, proc), {__MODULE__, :await, [task, timeout]}})\n    after\n      timeout ->\n        demonitor(ref)\n        exit({:timeout, {__MODULE__, :await, [task, timeout]}})\n    end\n  end\n\n  @doc \"\"\"\n  Ignores an existing task.\n\n  This means the task will continue running, but it will be unlinked\n  and you can no longer yield, await or shut it down.\n\n  Returns `{:ok, reply}` if the reply is received before ignoring the task,\n  `{:exit, reason}` if the task died before ignoring it, otherwise `nil`.\n\n  Important: avoid using [`Task.async/1,3`](`async/1`) and then immediately ignoring\n  the task. If you want to start tasks you don't care about their\n  results, use `Task.Supervisor.start_child/2` instead.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec ignore(t) :: {:ok, term} | {:exit, term} | nil\n  def ignore(%Task{ref: ref, pid: pid, owner: owner} = task) do\n    if owner != self() do\n      raise ArgumentError, invalid_owner_error(task)\n    end\n\n    ignore_receive(ref, pid, task)\n  end\n\n  defp ignore_receive(ref, pid, task) do\n    receive do\n      {^ref, reply} ->\n        pid && Process.unlink(pid)\n        demonitor(ref)\n        {:ok, reply}\n\n      {:DOWN, ^ref, _, proc, :noconnection} ->\n        exit({reason(:noconnection, proc), {__MODULE__, :ignore, [task]}})\n\n      {:DOWN, ^ref, _, _, reason} ->\n        {:exit, reason}\n    after\n      0 ->\n        pid && Process.unlink(pid)\n        demonitor(ref)\n        nil\n    end\n  end\n\n  @doc \"\"\"\n  Awaits replies from multiple tasks and returns them.\n\n  This function receives a list of tasks and waits for their replies in the\n  given time interval. It returns a list of the results, in the same order as\n  the tasks supplied in the `tasks` input argument.\n\n  If any of the task processes dies, the caller process will exit with the same\n  reason as that task.\n\n  A timeout, in milliseconds or `:infinity`, can be given with a default value\n  of `5000`. If the timeout is exceeded, then the caller process will exit.\n  Any task processes that are linked to the caller process (which is the case\n  when a task is started with `async`) will also exit. Any task processes that\n  are trapping exits or not linked to the caller process will continue to run.\n\n  This function assumes the tasks' monitors are still active or the monitor's\n  `:DOWN` message is in the message queue. If any tasks have been demonitored,\n  or the message already received, this function will wait for the duration of\n  the timeout.\n\n  This function can only be called once for any given task. If you want to be\n  able to check multiple times if a long-running task has finished its\n  computation, use `yield_many/2` instead.\n\n  ## Compatibility with OTP behaviours\n\n  It is not recommended to `await` long-running tasks inside an OTP behaviour\n  such as `GenServer`. See `await/2` for more information.\n\n  ## Examples\n\n      iex> tasks = [\n      ...>   Task.async(fn -> 1 + 1 end),\n      ...>   Task.async(fn -> 2 + 3 end)\n      ...> ]\n      iex> Task.await_many(tasks)\n      [2, 5]\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec await_many([t], timeout) :: [term]\n  def await_many(tasks, timeout \\\\ 5000) when is_timeout(timeout) do\n    awaiting =\n      Map.new(tasks, fn %Task{ref: ref, owner: owner} = task ->\n        if owner != self() do\n          raise ArgumentError, invalid_owner_error(task)\n        end\n\n        {ref, true}\n      end)\n\n    timeout_ref = make_ref()\n\n    timer_ref =\n      if timeout != :infinity do\n        Process.send_after(self(), timeout_ref, timeout)\n      end\n\n    try do\n      await_many(tasks, timeout, awaiting, %{}, timeout_ref)\n    after\n      timer_ref && Process.cancel_timer(timer_ref)\n      receive do: (^timeout_ref -> :ok), after: (0 -> :ok)\n    end\n  end\n\n  defp await_many(tasks, _timeout, awaiting, replies, _timeout_ref)\n       when map_size(awaiting) == 0 do\n    for %{ref: ref} <- tasks, do: Map.fetch!(replies, ref)\n  end\n\n  defp await_many(tasks, timeout, awaiting, replies, timeout_ref) do\n    receive do\n      ^timeout_ref ->\n        demonitor_pending_tasks(awaiting)\n        exit({:timeout, {__MODULE__, :await_many, [tasks, timeout]}})\n\n      {:DOWN, ref, _, proc, reason} when is_map_key(awaiting, ref) ->\n        demonitor_pending_tasks(awaiting)\n        exit({reason(reason, proc), {__MODULE__, :await_many, [tasks, timeout]}})\n\n      {ref, reply} when is_map_key(awaiting, ref) ->\n        demonitor(ref)\n\n        await_many(\n          tasks,\n          timeout,\n          Map.delete(awaiting, ref),\n          Map.put(replies, ref, reply),\n          timeout_ref\n        )\n    end\n  end\n\n  defp demonitor_pending_tasks(awaiting) do\n    Enum.each(awaiting, fn {ref, _} ->\n      demonitor(ref)\n    end)\n  end\n\n  @doc false\n  @deprecated \"Pattern match directly on the message instead\"\n  def find(tasks, {ref, reply}) when is_reference(ref) do\n    Enum.find_value(tasks, fn\n      %Task{ref: ^ref} = task ->\n        demonitor(ref)\n        {reply, task}\n\n      %Task{} ->\n        nil\n    end)\n  end\n\n  def find(tasks, {:DOWN, ref, _, proc, reason} = msg) when is_reference(ref) do\n    find = fn %Task{ref: task_ref} -> task_ref == ref end\n\n    if Enum.find(tasks, find) do\n      exit({reason(reason, proc), {__MODULE__, :find, [tasks, msg]}})\n    end\n  end\n\n  def find(_tasks, _msg) do\n    nil\n  end\n\n  @doc ~S\"\"\"\n  Temporarily blocks the caller process waiting for a task reply.\n\n  Returns `{:ok, reply}` if the reply is received, `nil` if\n  no reply has arrived, or `{:exit, reason}` if the task has already\n  exited. Keep in mind that normally a task failure also causes\n  the process owning the task to exit. Therefore this function can\n  return `{:exit, reason}` if at least one of the conditions below apply:\n\n    * the task process exited with the reason `:normal`\n    * the task isn't linked to the caller (the task was started\n      with `Task.Supervisor.async_nolink/2` or `Task.Supervisor.async_nolink/4`)\n    * the caller is trapping exits\n\n  A timeout, in milliseconds or `:infinity`, can be given with a default value\n  of `5000`. If the time runs out before a message from the task is received,\n  this function will return `nil` and the monitor will remain active. Therefore\n  `yield/2` can be called multiple times on the same task.\n\n  This function assumes the task's monitor is still active or the\n  monitor's `:DOWN` message is in the message queue. If it has been\n  demonitored or the message already received, this function will wait\n  for the duration of the timeout awaiting the message.\n\n  If you intend to shut the task down if it has not responded within `timeout`\n  milliseconds, you should chain this together with `shutdown/1`, like so:\n\n      case Task.yield(task, timeout) || Task.shutdown(task) do\n        {:ok, result} ->\n          result\n\n        nil ->\n          Logger.warning(\"Failed to get a result in #{timeout}ms\")\n          nil\n      end\n\n  If you intend to check on the task but leave it running after the timeout,\n  you can chain this together with `ignore/1`, like so:\n\n      case Task.yield(task, timeout) || Task.ignore(task) do\n        {:ok, result} ->\n          result\n\n        nil ->\n          Logger.warning(\"Failed to get a result in #{timeout}ms\")\n          nil\n      end\n\n  That ensures that if the task completes after the `timeout` but before `shutdown/1`\n  has been called, you will still get the result, since `shutdown/1` is designed to\n  handle this case and return the result.\n  \"\"\"\n  @spec yield(t, timeout) :: {:ok, term} | {:exit, term} | nil\n  def yield(%Task{ref: ref, owner: owner} = task, timeout \\\\ 5000) when is_timeout(timeout) do\n    if owner != self() do\n      raise ArgumentError, invalid_owner_error(task)\n    end\n\n    yield_receive(ref, task, timeout)\n  end\n\n  defp yield_receive(ref, task, timeout) do\n    receive do\n      {^ref, reply} ->\n        demonitor(ref)\n        {:ok, reply}\n\n      {:DOWN, ^ref, _, proc, :noconnection} ->\n        exit({reason(:noconnection, proc), {__MODULE__, :yield, [task, timeout]}})\n\n      {:DOWN, ^ref, _, _, reason} ->\n        {:exit, reason}\n    after\n      timeout ->\n        nil\n    end\n  end\n\n  @doc \"\"\"\n  Yields to multiple tasks in the given time interval.\n\n  This function receives a list of tasks and waits for their\n  replies in the given time interval. It returns a list\n  of two-element tuples, with the task as the first element\n  and the yielded result as the second. The tasks in the returned\n  list will be in the same order as the tasks supplied in the `tasks`\n  input argument.\n\n  Similarly to `yield/2`, each task's result will be\n\n    * `{:ok, term}` if the task has successfully reported its\n      result back in the given time interval\n    * `{:exit, reason}` if the task has died\n    * `nil` if the task keeps running, either because a limit\n      has been reached or past the timeout\n\n  Check `yield/2` for more information.\n\n  ## Example\n\n  `Task.yield_many/2` allows developers to spawn multiple tasks\n  and retrieve the results received in a given time frame.\n  If we combine it with `Task.shutdown/2` (or `Task.ignore/1`),\n  it allows us to gather those results and cancel (or ignore)\n  the tasks that have not replied in time.\n\n  Let's see an example.\n\n      tasks =\n        for i <- 1..10 do\n          Task.async(fn ->\n            Process.sleep(i * 1000)\n            i\n          end)\n        end\n\n      tasks_with_results = Task.yield_many(tasks, timeout: 5000)\n\n      results =\n        Enum.map(tasks_with_results, fn {task, res} ->\n          # Shut down the tasks that did not reply nor exit\n          res || Task.shutdown(task, :brutal_kill)\n        end)\n\n      # Here we are matching only on {:ok, value} and\n      # ignoring {:exit, _} (crashed tasks) and `nil` (no replies)\n      for {:ok, value} <- results do\n        IO.inspect(value)\n      end\n\n  In the example above, we create tasks that sleep from 1\n  up to 10 seconds and return the number of seconds they slept for.\n  If you execute the code all at once, you should see 1 up to 5\n  printed, as those were the tasks that have replied in the\n  given time. All other tasks will have been shut down using\n  the `Task.shutdown/2` call.\n\n  As a convenience, you can achieve a similar behavior to above\n  by specifying the `:on_timeout` option to be `:kill_task` (or\n  `:ignore`). See `Task.await_many/2` if you would rather exit\n  the caller process on timeout.\n\n  ## Options\n\n  The second argument is either a timeout or options, which defaults\n  to this:\n\n    * `:limit` - the maximum amount of tasks to wait for.\n      If the limit is reached before the timeout, this function\n      returns immediately without triggering the `:on_timeout` behaviour\n\n    * `:timeout` - the maximum amount of time (in milliseconds or `:infinity`)\n      each task is allowed to execute for. Defaults to `5000`.\n\n    * `:on_timeout` - what to do when a task times out. The possible\n      values are:\n      * `:nothing` - do nothing (default). The tasks can still be\n        awaited on, yielded on, ignored, or shut down later.\n      * `:ignore` - the results of the task will be ignored.\n      * `:kill_task` - the task that timed out is killed.\n  \"\"\"\n  @spec yield_many([t], timeout) :: [{t, {:ok, term} | {:exit, term} | nil}]\n  @spec yield_many([t],\n          limit: pos_integer(),\n          timeout: timeout,\n          on_timeout: :nothing | :ignore | :kill_task\n        ) ::\n          [{t, {:ok, term} | {:exit, term} | nil}]\n  def yield_many(tasks, opts \\\\ [])\n\n  def yield_many(tasks, timeout) when is_timeout(timeout) do\n    yield_many(tasks, timeout: timeout)\n  end\n\n  def yield_many(tasks, opts) when is_list(opts) do\n    refs =\n      Map.new(tasks, fn %Task{ref: ref, owner: owner} = task ->\n        if owner != self() do\n          raise ArgumentError, invalid_owner_error(task)\n        end\n\n        {ref, nil}\n      end)\n\n    on_timeout = Keyword.get(opts, :on_timeout, :nothing)\n    timeout = Keyword.get(opts, :timeout, 5_000)\n    limit = Keyword.get(opts, :limit, map_size(refs))\n    timeout_ref = make_ref()\n\n    timer_ref =\n      if timeout != :infinity do\n        Process.send_after(self(), timeout_ref, timeout)\n      end\n\n    try do\n      yield_many(limit, refs, timeout_ref, timer_ref)\n    catch\n      {:noconnection, reason} ->\n        exit({reason, {__MODULE__, :yield_many, [tasks, timeout]}})\n    else\n      {timed_out?, refs} ->\n        for task <- tasks do\n          value =\n            with nil <- Map.fetch!(refs, task.ref) do\n              case on_timeout do\n                _ when not timed_out? -> nil\n                :nothing -> nil\n                :kill_task -> shutdown(task, :brutal_kill)\n                :ignore -> ignore(task)\n              end\n            end\n\n          {task, value}\n        end\n    end\n  end\n\n  defp yield_many(0, refs, timeout_ref, timer_ref) do\n    timer_ref && Process.cancel_timer(timer_ref)\n    receive do: (^timeout_ref -> :ok), after: (0 -> :ok)\n    {false, refs}\n  end\n\n  defp yield_many(limit, refs, timeout_ref, timer_ref) do\n    receive do\n      {ref, reply} when is_map_key(refs, ref) ->\n        demonitor(ref)\n        yield_many(limit - 1, %{refs | ref => {:ok, reply}}, timeout_ref, timer_ref)\n\n      {:DOWN, ref, _, proc, reason} when is_map_key(refs, ref) ->\n        if reason == :noconnection do\n          throw({:noconnection, reason(:noconnection, proc)})\n        else\n          yield_many(limit - 1, %{refs | ref => {:exit, reason}}, timeout_ref, timer_ref)\n        end\n\n      ^timeout_ref ->\n        {true, refs}\n    end\n  end\n\n  @doc \"\"\"\n  Unlinks and shuts down the task, and then checks for a reply.\n\n  Returns `{:ok, reply}` if the reply is received while shutting down the task,\n  `{:exit, reason}` if the task died, otherwise `nil`. Once shut down,\n  you can no longer await or yield it.\n\n  The second argument is either a timeout or `:brutal_kill`. In case\n  of a timeout, a `:shutdown` exit signal is sent to the task process\n  and if it does not exit within the timeout, it is killed. With `:brutal_kill`\n  the task is killed straight away. In case the task terminates abnormally\n  (possibly killed by another process), this function will exit with the same reason.\n\n  It is not required to call this function when terminating the caller, unless\n  exiting with reason `:normal` or if the task is trapping exits. If the caller is\n  exiting with a reason other than `:normal` and the task is not trapping exits, the\n  caller's exit signal will stop the task. The caller can exit with reason\n  `:shutdown` to shut down all of its linked processes, including tasks, that\n  are not trapping exits without generating any log messages.\n\n  If there is no process linked to the task, such as tasks started by\n  `Task.completed/1`, we check for a response or error accordingly, but without\n  shutting a process down.\n\n  If a task's monitor has already been demonitored or received and there is not\n  a response waiting in the message queue this function will return\n  `{:exit, :noproc}` as the result or exit reason can not be determined.\n  \"\"\"\n  @spec shutdown(t, timeout | :brutal_kill) :: {:ok, term} | {:exit, term} | nil\n  def shutdown(task, shutdown \\\\ 5000)\n\n  def shutdown(%Task{pid: nil} = task, _) do\n    ignore(task)\n  end\n\n  def shutdown(%Task{owner: owner} = task, _) when owner != self() do\n    raise ArgumentError, invalid_owner_error(task)\n  end\n\n  def shutdown(%Task{pid: pid, ref: ref} = task, :brutal_kill) do\n    mon = build_monitor(pid)\n    shutdown_send(pid, :kill)\n\n    case shutdown_receive(ref, mon, task, :brutal_kill, :infinity) do\n      {:down, proc, :noconnection} ->\n        exit({reason(:noconnection, proc), {__MODULE__, :shutdown, [task, :brutal_kill]}})\n\n      {:down, _, reason} ->\n        {:exit, reason}\n\n      result ->\n        result\n    end\n  end\n\n  def shutdown(%Task{pid: pid, ref: ref} = task, timeout) when is_timeout(timeout) do\n    mon = build_monitor(pid)\n    shutdown_send(pid, :shutdown)\n\n    case shutdown_receive(ref, mon, task, :shutdown, timeout) do\n      {:down, proc, :noconnection} ->\n        exit({reason(:noconnection, proc), {__MODULE__, :shutdown, [task, timeout]}})\n\n      {:down, _, reason} ->\n        {:exit, reason}\n\n      result ->\n        result\n    end\n  end\n\n  # Spawn a process to ensure task gets exit signal\n  # if process dies from exit signal between unlink and exit.\n  defp shutdown_send(pid, reason) do\n    caller = self()\n    ref = make_ref()\n    enforcer = spawn(fn -> shutdown_send(pid, reason, caller, ref) end)\n    Process.unlink(pid)\n    Process.exit(pid, reason)\n    send(enforcer, {:done, ref})\n    :ok\n  end\n\n  defp shutdown_send(pid, reason, caller, ref) do\n    mon = Process.monitor(caller)\n\n    receive do\n      {:done, ^ref} -> :ok\n      {:DOWN, ^mon, _, _, _} -> Process.exit(pid, reason)\n    end\n  end\n\n  defp shutdown_receive(ref, mon, task, type, timeout) do\n    receive do\n      {:DOWN, ^mon, _, _, :shutdown} when type in [:shutdown, :timeout_kill] ->\n        demonitor(ref)\n        flush_reply(ref)\n\n      {:DOWN, ^mon, _, _, :killed} when type == :brutal_kill ->\n        demonitor(ref)\n        flush_reply(ref)\n\n      {:DOWN, ^mon, _, proc, :noproc} ->\n        reason = flush_noproc(ref, proc, type)\n        flush_reply(ref) || reason\n\n      {:DOWN, ^mon, _, proc, reason} ->\n        demonitor(ref)\n        flush_reply(ref) || {:down, proc, reason}\n    after\n      timeout ->\n        Process.exit(task.pid, :kill)\n        shutdown_receive(ref, mon, task, :timeout_kill, :infinity)\n    end\n  end\n\n  defp flush_reply(ref) do\n    receive do\n      {^ref, reply} -> {:ok, reply}\n    after\n      0 -> nil\n    end\n  end\n\n  defp flush_noproc(ref, proc, type) do\n    receive do\n      {:DOWN, ^ref, _, _, :shutdown} when type in [:shutdown, :timeout_kill] ->\n        nil\n\n      {:DOWN, ^ref, _, _, :killed} when type == :brutal_kill ->\n        nil\n\n      {:DOWN, ^ref, _, _, reason} ->\n        {:down, proc, reason}\n    after\n      0 ->\n        demonitor(ref)\n        {:down, proc, :noproc}\n    end\n  end\n\n  # exported only to avoid dialyzer opaqueness check in internal Task modules\n  @doc false\n  @spec __alias__(pid()) :: Task.ref()\n  def __alias__(pid) do\n    build_alias(pid)\n  end\n\n  ## Optimizations\n\n  defp build_monitor(pid) do\n    :erlang.monitor(:process, pid)\n  end\n\n  defp build_alias(pid) do\n    :erlang.monitor(:process, pid, alias: :demonitor)\n  end\n\n  @doc false\n  # This instructs the Erlang compiler to apply selective\n  # receive optimizations to several functions in this module.\n  # This function is never invoked directly, it is only here\n  # for compiler optimization purposes.\n  #\n  # To verify which functions have been optimized, run the\n  # following command after Elixir is compiled from the project\n  # root:\n  #\n  #     ERL_COMPILER_OPTIONS=recv_opt_info elixir lib/elixir/lib/task.ex\n  #\n  def __recv_opt_info__(pid, task) do\n    await_receive(build_alias(pid), task, :infinity)\n    shutdown_receive(build_alias(pid), build_monitor(pid), task, :shutdown, :infinity)\n    yield_receive(build_alias(pid), task, :infinity)\n    ignore_receive(build_alias(pid), pid, task)\n  end\n\n  ## Helpers\n\n  defp demonitor(ref) when is_reference(ref) do\n    Process.demonitor(ref, [:flush])\n    :ok\n  end\n\n  defp reason(:noconnection, proc), do: {:nodedown, monitor_node(proc)}\n  defp reason(reason, _), do: reason\n\n  defp monitor_node(pid) when is_pid(pid), do: node(pid)\n  defp monitor_node({_, node}), do: node\n\n  defp invalid_owner_error(task) do\n    \"task #{inspect(task)} must be queried from the owner but was queried from #{inspect(self())}\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/tuple.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Tuple do\n  @moduledoc \"\"\"\n  Functions for working with tuples.\n\n  Please note the following functions for tuples are found in `Kernel`:\n\n    * `elem/2` - accesses a tuple by index\n    * `put_elem/3` - inserts a value into a tuple by index\n    * `tuple_size/1` - gets the number of elements in a tuple\n\n  Tuples are intended as fixed-size containers for multiple elements.\n  To manipulate a collection of elements, use a list instead. `Enum`\n  functions do not work on tuples.\n\n  Tuples are denoted with curly braces:\n\n      iex> {}\n      {}\n      iex> {1, :two, \"three\"}\n      {1, :two, \"three\"}\n\n  A tuple may contain elements of different types, which are stored\n  contiguously in memory. Accessing any element takes constant time,\n  but modifying a tuple, which produces a shallow copy, takes linear time.\n  Tuples are good for reading data while lists are better for traversals.\n\n  Tuples are typically used either when a function has multiple return values\n  or for error handling. `File.read/1` returns `{:ok, contents}` if reading\n  the given file is successful, or else `{:error, reason}` such as when\n  the file does not exist.\n\n  The functions in this module that add and remove elements from tuples are\n  rarely used in practice, as they typically imply tuples are being used as\n  collections. To append to a tuple, it is preferable to extract the elements\n  from the old tuple with pattern matching, and then create a new tuple:\n\n      tuple = {:ok, :example}\n\n      # Avoid\n      result = Tuple.insert_at(tuple, 2, %{})\n\n      # Prefer\n      {:ok, atom} = tuple\n      result = {:ok, atom, %{}}\n\n  \"\"\"\n\n  @doc \"\"\"\n  Creates a new tuple.\n\n  Creates a tuple of `size` containing the\n  given `data` at every position.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> Tuple.duplicate(:hello, 3)\n      {:hello, :hello, :hello}\n\n  \"\"\"\n  @spec duplicate(term, non_neg_integer) :: tuple\n  def duplicate(data, size) when is_integer(size) and size >= 0 do\n    :erlang.make_tuple(size, data)\n  end\n\n  @doc \"\"\"\n  Inserts an element into a tuple.\n\n  Inserts `value` into `tuple` at the given `index`.\n  Raises an `ArgumentError` if `index` is negative or greater than the\n  length of `tuple`. Index is zero-based.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> tuple = {:bar, :baz}\n      iex> Tuple.insert_at(tuple, 0, :foo)\n      {:foo, :bar, :baz}\n      iex> Tuple.insert_at(tuple, 2, :bong)\n      {:bar, :baz, :bong}\n\n  \"\"\"\n  @spec insert_at(tuple, non_neg_integer, term) :: tuple\n  def insert_at(tuple, index, value) when is_integer(index) and index >= 0 do\n    :erlang.insert_element(index + 1, tuple, value)\n  end\n\n  @doc false\n  @deprecated \"Use insert_at instead\"\n  def append(tuple, value) do\n    :erlang.append_element(tuple, value)\n  end\n\n  @doc \"\"\"\n  Removes an element from a tuple.\n\n  Deletes the element at the given `index` from `tuple`.\n  Raises an `ArgumentError` if `index` is negative or greater than\n  or equal to the length of `tuple`. Index is zero-based.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> tuple = {:foo, :bar, :baz}\n      iex> Tuple.delete_at(tuple, 0)\n      {:bar, :baz}\n\n  \"\"\"\n  @spec delete_at(tuple, non_neg_integer) :: tuple\n  def delete_at(tuple, index) when is_integer(index) and index >= 0 do\n    :erlang.delete_element(index + 1, tuple)\n  end\n\n  @doc \"\"\"\n  Computes a sum of tuple elements.\n\n  ## Examples\n\n      iex> Tuple.sum({255, 255})\n      510\n      iex> Tuple.sum({255, 0.0})\n      255.0\n      iex> Tuple.sum({})\n      0\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec sum(tuple) :: number()\n  def sum(tuple), do: sum(tuple, tuple_size(tuple))\n\n  defp sum(_tuple, 0), do: 0\n  defp sum(tuple, index), do: :erlang.element(index, tuple) + sum(tuple, index - 1)\n\n  @doc \"\"\"\n  Computes a product of tuple elements.\n\n  ## Examples\n\n      iex> Tuple.product({255, 255})\n      65025\n      iex> Tuple.product({255, 1.0})\n      255.0\n      iex> Tuple.product({})\n      1\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec product(tuple) :: number()\n  def product(tuple), do: product(tuple, tuple_size(tuple))\n\n  defp product(_tuple, 0), do: 1\n  defp product(tuple, index), do: :erlang.element(index, tuple) * product(tuple, index - 1)\n\n  @doc \"\"\"\n  Converts a tuple to a list.\n\n  Returns a new list with all the tuple elements.\n\n  Inlined by the compiler.\n\n  ## Examples\n\n      iex> tuple = {:foo, :bar, :baz}\n      iex> Tuple.to_list(tuple)\n      [:foo, :bar, :baz]\n\n  \"\"\"\n  @spec to_list(tuple) :: list\n  def to_list(tuple) do\n    :erlang.tuple_to_list(tuple)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/uri.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule URI do\n  @moduledoc \"\"\"\n  Utilities for working with URIs.\n\n  This module provides functions for working with URIs (for example, parsing\n  URIs or encoding query strings). The functions in this module are implemented\n  according to [RFC 3986](https://tools.ietf.org/html/rfc3986) and it also\n  provides additional functionality for handling \"application/x-www-form-urlencoded\"\n  segments.\n\n  Additionally, the Erlang [`:uri_string` module](`:uri_string`) provides additional\n  functionality such as RFC 3986 compliant URI normalization.\n  \"\"\"\n\n  @doc \"\"\"\n  The URI struct.\n\n  The fields are defined to match the following URI representation\n  (with field names between brackets):\n\n      [scheme]://[userinfo]@[host]:[port][path]?[query]#[fragment]\n\n\n  Note the `authority` field is deprecated. `parse/1` will still\n  populate it for backwards compatibility but you should generally\n  avoid setting or getting it.\n  \"\"\"\n  @derive {Inspect, optional: [:authority]}\n  defstruct [:scheme, :authority, :userinfo, :host, :port, :path, :query, :fragment]\n\n  # We don't use opaque because URIs can be inlined,\n  # either via module attributes or by the compiler.\n  @typedoc deprecated: \"The authority field is deprecated\"\n  @type authority :: nil | binary\n\n  @type t :: %__MODULE__{\n          scheme: nil | binary,\n          authority: authority,\n          userinfo: nil | binary,\n          host: nil | binary,\n          port: nil | :inet.port_number(),\n          path: nil | binary,\n          query: nil | binary,\n          fragment: nil | binary\n        }\n\n  defmodule Error do\n    @moduledoc \"\"\"\n    An exception raised when an error occurs when a `URI` is invalid.\n\n    For example, see `URI.new!/1`.\n    \"\"\"\n\n    defexception [:action, :reason, :part]\n\n    @doc false\n    def message(%Error{action: action, reason: reason, part: part}) do\n      \"cannot #{action} due to reason #{reason}: #{inspect(part)}\"\n    end\n  end\n\n  import Bitwise\n\n  @reserved_characters ~c\":/?#[]@!$&'()*+,;=\"\n  @formatted_reserved_characters Enum.map_join(@reserved_characters, \", \", &<<?`, &1, ?`>>)\n\n  @doc \"\"\"\n  Returns the default port for a given `scheme`.\n\n  If the scheme is unknown to the `URI` module, this function returns\n  `nil`. The default port for any scheme can be configured globally\n  via `default_port/2`.\n\n  ## Examples\n\n      iex> URI.default_port(\"ftp\")\n      21\n\n      iex> URI.default_port(\"ponzi\")\n      nil\n\n  \"\"\"\n  @spec default_port(binary) :: nil | non_neg_integer\n  def default_port(scheme) when is_binary(scheme) do\n    :elixir_config.get({:uri, scheme}, nil)\n  end\n\n  @doc \"\"\"\n  Registers the default `port` for the given `scheme`.\n\n  After this function is called, `port` will be returned by\n  `default_port/1` for the given scheme `scheme`. Note that this function\n  changes the default port for the given `scheme` *globally*, meaning for\n  every application.\n\n  It is recommended for this function to be invoked in your\n  application's start callback in case you want to register\n  new URIs.\n  \"\"\"\n  @spec default_port(binary, non_neg_integer) :: :ok\n  def default_port(scheme, port) when is_binary(scheme) and is_integer(port) and port >= 0 do\n    :elixir_config.put({:uri, scheme}, port)\n  end\n\n  @doc \"\"\"\n  Encodes `enumerable` into a query string using `encoding`.\n\n  Takes an enumerable that enumerates as a list of two-element\n  tuples (for instance, a map or a keyword list) and returns a string\n  in the form of `key1=value1&key2=value2...`.\n\n  Keys and values can be any term that implements the `String.Chars`\n  protocol with the exception of lists, which are explicitly forbidden.\n\n  You can specify one of the following `encoding` strategies:\n\n    * `:www_form` - (default, since v1.12.0) keys and values are URL encoded as\n      per `encode_www_form/1`. This is the format typically used by browsers on\n      query strings and form data. It encodes \" \" as \"+\".\n\n    * `:rfc3986` - (since v1.12.0) the same as `:www_form` except it encodes\n      \" \" as \"%20\" according [RFC 3986](https://tools.ietf.org/html/rfc3986).\n      This is the best option if you are encoding in a non-browser situation,\n      since encoding spaces as \"+\" can be ambiguous to URI parsers. This can\n      inadvertently lead to spaces being interpreted as literal plus signs.\n\n  Encoding defaults to `:www_form` for backward compatibility.\n\n  ## Examples\n\n      iex> query = %{\"foo\" => 1, \"bar\" => 2}\n      iex> URI.encode_query(query)\n      \"bar=2&foo=1\"\n\n      iex> query = %{\"key\" => \"value with spaces\"}\n      iex> URI.encode_query(query)\n      \"key=value+with+spaces\"\n\n      iex> query = %{\"key\" => \"value with spaces\"}\n      iex> URI.encode_query(query, :rfc3986)\n      \"key=value%20with%20spaces\"\n\n      iex> URI.encode_query(%{key: [:a, :list]})\n      ** (ArgumentError) encode_query/2 values cannot be lists, got: [:a, :list]\n\n  \"\"\"\n  @spec encode_query(Enumerable.t(), :rfc3986 | :www_form) :: binary\n  def encode_query(enumerable, encoding \\\\ :www_form) do\n    Enum.map_join(enumerable, \"&\", &encode_kv_pair(&1, encoding))\n  end\n\n  defp encode_kv_pair({key, _}, _encoding) when is_list(key) do\n    raise ArgumentError, \"encode_query/2 keys cannot be lists, got: #{inspect(key)}\"\n  end\n\n  defp encode_kv_pair({_, value}, _encoding) when is_list(value) do\n    raise ArgumentError, \"encode_query/2 values cannot be lists, got: #{inspect(value)}\"\n  end\n\n  defp encode_kv_pair({key, value}, :rfc3986) do\n    encode(Kernel.to_string(key), &char_unreserved?/1) <>\n      \"=\" <> encode(Kernel.to_string(value), &char_unreserved?/1)\n  end\n\n  defp encode_kv_pair({key, value}, :www_form) do\n    encode_www_form(Kernel.to_string(key)) <> \"=\" <> encode_www_form(Kernel.to_string(value))\n  end\n\n  @doc \"\"\"\n  Decodes `query` into a map.\n\n  Given a query string in the form of `key1=value1&key2=value2...`, this\n  function inserts each key-value pair in the query string as one entry in the\n  given `map`. Keys and values in the resulting map will be binaries. Keys and\n  values will be percent-unescaped.\n\n  You can specify one of the following `encoding` options:\n\n    * `:www_form` - (default, since v1.12.0) keys and values are decoded as per\n      `decode_www_form/1`. This is the format typically used by browsers on\n      query strings and form data. It decodes \"+\" as \" \".\n\n    * `:rfc3986` - (since v1.12.0) keys and values are decoded as per\n      `decode/1`. The result is the same as `:www_form` except for leaving \"+\"\n      as is in line with [RFC 3986](https://tools.ietf.org/html/rfc3986).\n\n  Encoding defaults to `:www_form` for backward compatibility.\n\n  Use `query_decoder/1` if you want to iterate over each value manually.\n\n  ## Examples\n\n      iex> URI.decode_query(\"foo=1&bar=2\")\n      %{\"bar\" => \"2\", \"foo\" => \"1\"}\n\n      iex> URI.decode_query(\"percent=oh+yes%21\", %{\"starting\" => \"map\"})\n      %{\"percent\" => \"oh yes!\", \"starting\" => \"map\"}\n\n      iex> URI.decode_query(\"percent=oh+yes%21\", %{}, :rfc3986)\n      %{\"percent\" => \"oh+yes!\"}\n\n  \"\"\"\n  @spec decode_query(binary, %{optional(binary) => binary}, :rfc3986 | :www_form) :: %{\n          optional(binary) => binary\n        }\n  def decode_query(query, map \\\\ %{}, encoding \\\\ :www_form)\n\n  def decode_query(query, %_{} = dict, encoding) when is_binary(query) do\n    IO.warn(\n      \"URI.decode_query/3 expects the second argument to be a map, other usage is deprecated\"\n    )\n\n    decode_query_into_dict(query, dict, encoding)\n  end\n\n  def decode_query(query, map, encoding) when is_binary(query) and is_map(map) do\n    decode_query_into_map(query, map, encoding)\n  end\n\n  def decode_query(query, dict, encoding) when is_binary(query) do\n    IO.warn(\n      \"URI.decode_query/3 expects the second argument to be a map, other usage is deprecated\"\n    )\n\n    decode_query_into_dict(query, dict, encoding)\n  end\n\n  defp decode_query_into_map(query, map, encoding) do\n    case decode_next_query_pair(query, encoding) do\n      nil ->\n        map\n\n      {{key, value}, rest} ->\n        decode_query_into_map(rest, Map.put(map, key, value), encoding)\n    end\n  end\n\n  defp decode_query_into_dict(query, dict, encoding) do\n    case decode_next_query_pair(query, encoding) do\n      nil ->\n        dict\n\n      {{key, value}, rest} ->\n        # Avoid warnings about Dict being deprecated\n        dict_module = String.to_atom(\"Dict\")\n        decode_query_into_dict(rest, dict_module.put(dict, key, value), encoding)\n    end\n  end\n\n  @doc \"\"\"\n  Returns a stream of two-element tuples representing key-value pairs in the\n  given `query`.\n\n  Key and value in each tuple will be binaries and will be percent-unescaped.\n\n  You can specify one of the following `encoding` options:\n\n    * `:www_form` - (default, since v1.12.0) keys and values are decoded as per\n      `decode_www_form/1`. This is the format typically used by browsers on\n      query strings and form data. It decodes \"+\" as \" \".\n\n    * `:rfc3986` - (since v1.12.0) keys and values are decoded as per\n      `decode/1`. The result is the same as `:www_form` except for leaving \"+\"\n      as is in line with [RFC 3986](https://tools.ietf.org/html/rfc3986).\n\n  Encoding defaults to `:www_form` for backward compatibility.\n\n  ## Examples\n\n      iex> URI.query_decoder(\"foo=1&bar=2\") |> Enum.to_list()\n      [{\"foo\", \"1\"}, {\"bar\", \"2\"}]\n\n      iex> URI.query_decoder(\"food=bread%26butter&drinks=tap%20water+please\") |> Enum.to_list()\n      [{\"food\", \"bread&butter\"}, {\"drinks\", \"tap water please\"}]\n\n      iex> URI.query_decoder(\"food=bread%26butter&drinks=tap%20water+please\", :rfc3986) |> Enum.to_list()\n      [{\"food\", \"bread&butter\"}, {\"drinks\", \"tap water+please\"}]\n\n  \"\"\"\n  @spec query_decoder(binary, :rfc3986 | :www_form) :: Enumerable.t()\n  def query_decoder(query, encoding \\\\ :www_form) when is_binary(query) do\n    Stream.unfold(query, &decode_next_query_pair(&1, encoding))\n  end\n\n  defp decode_next_query_pair(\"\", _encoding) do\n    nil\n  end\n\n  defp decode_next_query_pair(query, encoding) do\n    {undecoded_next_pair, rest} =\n      case :binary.split(query, \"&\") do\n        [next_pair, rest] -> {next_pair, rest}\n        [next_pair] -> {next_pair, \"\"}\n      end\n\n    next_pair =\n      case :binary.split(undecoded_next_pair, \"=\") do\n        [key, value] ->\n          {decode_with_encoding(key, encoding), decode_with_encoding(value, encoding)}\n\n        [key] ->\n          {decode_with_encoding(key, encoding), \"\"}\n      end\n\n    {next_pair, rest}\n  end\n\n  defp decode_with_encoding(string, :www_form) do\n    decode_www_form(string)\n  end\n\n  defp decode_with_encoding(string, :rfc3986) do\n    decode(string)\n  end\n\n  @doc ~s\"\"\"\n  Checks if `character` is a reserved one in a URI.\n\n  As specified in [RFC 3986, section 2.2](https://tools.ietf.org/html/rfc3986#section-2.2),\n  the following characters are reserved: #{@formatted_reserved_characters}\n\n  ## Examples\n\n      iex> URI.char_reserved?(?+)\n      true\n\n  \"\"\"\n  @spec char_reserved?(byte) :: boolean\n  def char_reserved?(character) do\n    character in @reserved_characters\n  end\n\n  @doc \"\"\"\n  Checks if `character` is an unreserved one in a URI.\n\n  As specified in [RFC 3986, section 2.3](https://tools.ietf.org/html/rfc3986#section-2.3),\n  the following characters are unreserved:\n\n    * Alphanumeric characters: `A-Z`, `a-z`, `0-9`\n    * `~`, `_`, `-`, `.`\n\n  ## Examples\n\n      iex> URI.char_unreserved?(?_)\n      true\n\n  \"\"\"\n  @spec char_unreserved?(byte) :: boolean\n  def char_unreserved?(character) do\n    character in ?0..?9 or character in ?a..?z or character in ?A..?Z or character in ~c\"~_-.\"\n  end\n\n  @doc \"\"\"\n  Checks if `character` is allowed unescaped in a URI.\n\n  This is the default used by `URI.encode/2` where both\n  [reserved](`char_reserved?/1`) and [unreserved characters](`char_unreserved?/1`)\n  are kept unescaped.\n\n  ## Examples\n\n      iex> URI.char_unescaped?(?{)\n      false\n\n  \"\"\"\n  @spec char_unescaped?(byte) :: boolean\n  def char_unescaped?(character) do\n    char_reserved?(character) or char_unreserved?(character)\n  end\n\n  @doc \"\"\"\n  Percent-encodes all characters that require escaping in `string`.\n\n  The optional `predicate` argument specifies a function used to detect whether\n  a byte in the `string` should be escaped:\n\n    * if the function returns a truthy value, the byte should be kept as-is.\n    * if the function returns a falsy value, the byte should be escaped.\n\n  The `predicate` argument can use some built-in functions:\n\n    * `URI.char_unescaped?/1` (default) - reserved characters (such as `:`\n      and `/`) or unreserved (such as letters and numbers) are kept as-is.\n      It's typically used to encode the whole URI.\n    * `URI.char_unreserved?/1` - unreserved characters (such as letters and\n      numbers) are kept as-is. It's typically used to encode components in\n      a URI, such as query or fragment.\n    * `URI.char_reserved?/1` - Reserved characters (such as `:` and `/`) are\n      kept as-is.\n\n  And, you can also use custom functions.\n\n  See `encode_www_form/1` if you are interested in encoding `string` as\n  \"x-www-form-urlencoded\".\n\n  ## Examples\n\n      iex> URI.encode(\"ftp://s-ite.tld/?value=put it+й\")\n      \"ftp://s-ite.tld/?value=put%20it+%D0%B9\"\n\n      iex> URI.encode(\"a string\", &(&1 != ?i))\n      \"a str%69ng\"\n\n  \"\"\"\n  @spec encode(binary, (byte -> as_boolean(term))) :: binary\n  def encode(string, predicate \\\\ &char_unescaped?/1)\n      when is_binary(string) and is_function(predicate, 1) do\n    for <<byte <- string>>, into: \"\", do: percent(byte, predicate)\n  end\n\n  @doc \"\"\"\n  Encodes `string` as \"x-www-form-urlencoded\".\n\n  Note \"x-www-form-urlencoded\" is not specified as part of\n  RFC 3986. However, it is a commonly used format to encode\n  query strings and form data by browsers.\n\n  ## Example\n\n      iex> URI.encode_www_form(\"put: it+й\")\n      \"put%3A+it%2B%D0%B9\"\n\n  \"\"\"\n  @spec encode_www_form(binary) :: binary\n  def encode_www_form(string) when is_binary(string) do\n    for <<byte <- string>>, into: \"\" do\n      case percent(byte, &char_unreserved?/1) do\n        \"%20\" -> \"+\"\n        percent -> percent\n      end\n    end\n  end\n\n  defp percent(char, predicate) do\n    if predicate.(char) do\n      <<char>>\n    else\n      <<\"%\", hex(bsr(char, 4)), hex(band(char, 15))>>\n    end\n  end\n\n  defp hex(n) when n <= 9, do: n + ?0\n  defp hex(n), do: n + ?A - 10\n\n  @doc \"\"\"\n  Percent-unescapes a URI.\n\n  ## Examples\n\n      iex> URI.decode(\"https%3A%2F%2Felixir-lang.org\")\n      \"https://elixir-lang.org\"\n\n  \"\"\"\n  @spec decode(binary) :: binary\n  def decode(uri) do\n    unpercent(uri, \"\", false)\n  end\n\n  @doc \"\"\"\n  Decodes `string` as \"x-www-form-urlencoded\".\n\n  Note \"x-www-form-urlencoded\" is not specified as part of\n  RFC 3986. However, it is a commonly used format to encode\n  query strings and form data by browsers.\n\n  ## Examples\n\n      iex> URI.decode_www_form(\"%3Call+in%2F\")\n      \"<all in/\"\n\n  \"\"\"\n  @spec decode_www_form(binary) :: binary\n  def decode_www_form(string) when is_binary(string) do\n    unpercent(string, \"\", true)\n  end\n\n  defp unpercent(<<?+, tail::binary>>, acc, spaces = true) do\n    unpercent(tail, <<acc::binary, ?\\s>>, spaces)\n  end\n\n  defp unpercent(<<?%, tail::binary>>, acc, spaces) do\n    with <<hex1, hex2, tail::binary>> <- tail,\n         dec1 when is_integer(dec1) <- hex_to_dec(hex1),\n         dec2 when is_integer(dec2) <- hex_to_dec(hex2) do\n      unpercent(tail, <<acc::binary, bsl(dec1, 4) + dec2>>, spaces)\n    else\n      _ -> unpercent(tail, <<acc::binary, ?%>>, spaces)\n    end\n  end\n\n  defp unpercent(<<head, tail::binary>>, acc, spaces) do\n    unpercent(tail, <<acc::binary, head>>, spaces)\n  end\n\n  defp unpercent(<<>>, acc, _spaces), do: acc\n\n  @compile {:inline, hex_to_dec: 1}\n  defp hex_to_dec(n) when n in ?A..?F, do: n - ?A + 10\n  defp hex_to_dec(n) when n in ?a..?f, do: n - ?a + 10\n  defp hex_to_dec(n) when n in ?0..?9, do: n - ?0\n  defp hex_to_dec(_n), do: nil\n\n  @doc \"\"\"\n  Creates a new URI struct by parsing and validating a string or from an existing URI.\n\n  If a `%URI{}` struct is given, it returns `{:ok, uri}` as is. If a string is\n  given, it will parse and validate it. If the string is valid, it returns\n  `{:ok, uri}`, otherwise it returns `{:error, part}` with the invalid part\n  of the URI. For parsing URIs without further validation, see `parse/1`.\n\n  This function can parse both absolute and relative URLs. You can check\n  if a URI is absolute or relative by checking if the `scheme` field is\n  `nil` or not.\n\n  When a URI is given without a port, the value returned by `URI.default_port/1`\n  for the URI's scheme is used for the `:port` field. The scheme is also\n  normalized to lowercase.\n\n  > #### Browser compatibility {: .warning}\n  >\n  > This function does not follow the same parsing rules as browsers.\n  > Browsers adhere to the WHATWG URL standard, while this function\n  > implements RFC 3986. You should expect different behaviours between\n  > them and this function will often reject URLs that are accepted by\n  > browsers (as they tend to be permissive). Common examples include\n  > unencoded square brackets in query strings (such as `foo[bar]=baz`)\n  > and backslashes used as path separators.\n\n  ## Examples\n\n      iex> URI.new(\"https://elixir-lang.org/\")\n      {:ok, %URI{\n        fragment: nil,\n        host: \"elixir-lang.org\",\n        path: \"/\",\n        port: 443,\n        query: nil,\n        scheme: \"https\",\n        userinfo: nil\n      }}\n\n      iex> URI.new(\"//elixir-lang.org/\")\n      {:ok, %URI{\n        fragment: nil,\n        host: \"elixir-lang.org\",\n        path: \"/\",\n        port: nil,\n        query: nil,\n        scheme: nil,\n        userinfo: nil\n      }}\n\n      iex> URI.new(\"/foo/bar\")\n      {:ok, %URI{\n        fragment: nil,\n        host: nil,\n        path: \"/foo/bar\",\n        port: nil,\n        query: nil,\n        scheme: nil,\n        userinfo: nil\n      }}\n\n      iex> URI.new(\"foo/bar\")\n      {:ok, %URI{\n        fragment: nil,\n        host: nil,\n        path: \"foo/bar\",\n        port: nil,\n        query: nil,\n        scheme: nil,\n        userinfo: nil\n      }}\n\n      iex> URI.new(\"//[fe80::]/\")\n      {:ok, %URI{\n        fragment: nil,\n        host: \"fe80::\",\n        path: \"/\",\n        port: nil,\n        query: nil,\n        scheme: nil,\n        userinfo: nil\n      }}\n\n      iex> URI.new(\"https:?query\")\n      {:ok, %URI{\n        fragment: nil,\n        host: nil,\n        path: nil,\n        port: 443,\n        query: \"query\",\n        scheme: \"https\",\n        userinfo: nil\n      }}\n\n      iex> URI.new(\"/invalid_greater_than_in_path/>\")\n      {:error, \">\"}\n\n  Giving an existing URI simply returns it wrapped in a tuple:\n\n      iex> {:ok, uri} = URI.new(\"https://elixir-lang.org/\")\n      iex> URI.new(uri)\n      {:ok, %URI{\n        fragment: nil,\n        host: \"elixir-lang.org\",\n        path: \"/\",\n        port: 443,\n        query: nil,\n        scheme: \"https\",\n        userinfo: nil\n      }}\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec new(t() | String.t()) :: {:ok, t()} | {:error, String.t()}\n  def new(%URI{} = uri), do: {:ok, uri}\n\n  def new(binary) when is_binary(binary) do\n    case :uri_string.parse(binary) do\n      %{} = map -> {:ok, uri_from_map(map)}\n      {:error, :invalid_uri, term} -> {:error, Kernel.to_string(term)}\n    end\n  end\n\n  @doc \"\"\"\n  Similar to `new/1` but raises `URI.Error` if an invalid string is given.\n\n  ## Examples\n\n      iex> URI.new!(\"https://elixir-lang.org/\")\n      %URI{\n        fragment: nil,\n        host: \"elixir-lang.org\",\n        path: \"/\",\n        port: 443,\n        query: nil,\n        scheme: \"https\",\n        userinfo: nil\n      }\n\n      iex> URI.new!(\"/invalid_greater_than_in_path/>\")\n      ** (URI.Error) cannot parse due to reason invalid_uri: \">\"\n\n  Giving an existing URI simply returns it:\n\n      iex> uri = URI.new!(\"https://elixir-lang.org/\")\n      iex> URI.new!(uri)\n      %URI{\n        fragment: nil,\n        host: \"elixir-lang.org\",\n        path: \"/\",\n        port: 443,\n        query: nil,\n        scheme: \"https\",\n        userinfo: nil\n      }\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec new!(t() | String.t()) :: t()\n  def new!(%URI{} = uri), do: uri\n\n  def new!(binary) when is_binary(binary) do\n    case :uri_string.parse(binary) do\n      %{} = map ->\n        uri_from_map(map)\n\n      {:error, reason, part} ->\n        raise Error, action: :parse, reason: reason, part: Kernel.to_string(part)\n    end\n  end\n\n  defp uri_from_map(%{path: \"\"} = map), do: uri_from_map(%{map | path: nil})\n\n  defp uri_from_map(map) do\n    uri = Map.merge(%URI{}, map)\n\n    case map do\n      %{scheme: scheme} ->\n        scheme = String.downcase(scheme, :ascii)\n\n        case map do\n          %{port: port} when is_integer(port) ->\n            %{uri | scheme: scheme}\n\n          %{} ->\n            %{uri | scheme: scheme, port: default_port(scheme)}\n        end\n\n      %{port: :undefined} ->\n        %{uri | port: nil}\n\n      %{} ->\n        uri\n    end\n  end\n\n  @doc \"\"\"\n  Parses a URI into its components, without further validation.\n\n  This function can parse both absolute and relative URLs. You can check\n  if a URI is absolute or relative by checking if the `scheme` field is\n  nil or not.\n\n  This function expects both absolute and relative URIs to be well-formed\n  and does not perform any validation, it simply breaks the URL into parts.\n  Use `new/1` if you want to validate the URI fields after parsing.\n\n  When a URI is given without a port, the value returned by `URI.default_port/1`\n  for the URI's scheme is used for the `:port` field. The scheme is also\n  normalized to lowercase.\n\n  If a `URI` struct is given to this function, this function returns it\n  unmodified.\n\n  > #### Browser compatibility {: .warning}\n  >\n  > This function does not follow the same parsing rules as browsers.\n  > Browsers adhere to the WHATWG URL standard, while this function\n  > implements RFC 3986. You should expect different behaviours between\n  > them, especially around corner cases.\n\n  > #### `:authority` field {: .info}\n  >\n  > This function sets the deprecated field `:authority` for backwards-compatibility reasons.\n\n  ## Examples\n\n      iex> URI.parse(\"https://elixir-lang.org/\")\n      %URI{\n        authority: \"elixir-lang.org\",\n        fragment: nil,\n        host: \"elixir-lang.org\",\n        path: \"/\",\n        port: 443,\n        query: nil,\n        scheme: \"https\",\n        userinfo: nil\n      }\n\n      iex> URI.parse(\"//elixir-lang.org/\")\n      %URI{\n        authority: \"elixir-lang.org\",\n        fragment: nil,\n        host: \"elixir-lang.org\",\n        path: \"/\",\n        port: nil,\n        query: nil,\n        scheme: nil,\n        userinfo: nil\n      }\n\n      iex> URI.parse(\"/foo/bar\")\n      %URI{\n        fragment: nil,\n        host: nil,\n        path: \"/foo/bar\",\n        port: nil,\n        query: nil,\n        scheme: nil,\n        userinfo: nil\n      }\n\n      iex> URI.parse(\"foo/bar\")\n      %URI{\n        fragment: nil,\n        host: nil,\n        path: \"foo/bar\",\n        port: nil,\n        query: nil,\n        scheme: nil,\n        userinfo: nil\n      }\n\n  In contrast to `URI.new/1`, this function will accept poorly-formed\n  URIs and break them into components, as it does not perform validation.\n  For example:\n\n      iex> URI.parse(\"/invalid_greater_than_in_path/>\")\n      %URI{\n        fragment: nil,\n        host: nil,\n        path: \"/invalid_greater_than_in_path/>\",\n        port: nil,\n        query: nil,\n        scheme: nil,\n        userinfo: nil\n      }\n\n  Another example is a URI with brackets in query strings. It is accepted\n  by `parse/1` for the same reasons as above (no validation), but it will\n  be refused by `new/1`:\n\n      iex> URI.parse(\"/?foo[bar]=baz\")\n      %URI{\n        fragment: nil,\n        host: nil,\n        path: \"/\",\n        port: nil,\n        query: \"foo[bar]=baz\",\n        scheme: nil,\n        userinfo: nil\n      }\n\n  Generally speaking, square brackets are strictly invalid even in the WHATWG\n  URL standard used by browsers, but browsers tend to be permissive and often\n  allow invalid characters to pass through.\n  \"\"\"\n  @spec parse(t | binary) :: t\n  def parse(%URI{} = uri), do: uri\n\n  def parse(string) when is_binary(string) do\n    # From https://tools.ietf.org/html/rfc3986#appendix-B\n    # Parts:    12                        3  4          5       6  7        8 9\n    regex = ~r{^(([a-z][a-z0-9\\+\\-\\.]*):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?}i\n\n    parts = Regex.run(regex, string)\n\n    destructure [\n                  _full,\n                  # 1\n                  _scheme_with_colon,\n                  # 2\n                  scheme,\n                  # 3\n                  authority_with_slashes,\n                  # 4\n                  _authority,\n                  # 5\n                  path,\n                  # 6\n                  query_with_question_mark,\n                  # 7\n                  _query,\n                  # 8\n                  _fragment_with_hash,\n                  # 9\n                  fragment\n                ],\n                parts\n\n    path = nilify(path)\n    scheme = nilify(scheme)\n    query = nilify_query(query_with_question_mark)\n    {authority, userinfo, host, port} = split_authority(authority_with_slashes)\n\n    scheme = scheme && String.downcase(scheme)\n    port = port || (scheme && default_port(scheme))\n\n    %URI{\n      scheme: scheme,\n      path: path,\n      query: query,\n      fragment: fragment,\n      authority: authority,\n      userinfo: userinfo,\n      host: host,\n      port: port\n    }\n  end\n\n  defp nilify_query(\"?\" <> query), do: query\n  defp nilify_query(_other), do: nil\n\n  # Split an authority into its userinfo, host and port parts.\n  #\n  # Note that the host field is returned *without* [] even if, according to\n  # RFC3986 grammar, a native IPv6 address requires them.\n  defp split_authority(\"\") do\n    {nil, nil, nil, nil}\n  end\n\n  defp split_authority(\"//\") do\n    {\"\", nil, \"\", nil}\n  end\n\n  defp split_authority(\"//\" <> authority) do\n    regex = ~r/(^(.*)@)?(\\[[a-zA-Z0-9:.]*\\]|[^:]*)(:(\\d*))?/\n    components = Regex.run(regex, authority)\n\n    destructure [_, _, userinfo, host, _, port], components\n    userinfo = nilify(userinfo)\n    host = if nilify(host), do: host |> String.trim_leading(\"[\") |> String.trim_trailing(\"]\")\n    port = if nilify(port), do: String.to_integer(port)\n\n    {authority, userinfo, host, port}\n  end\n\n  # Regex.run returns empty strings sometimes. We want\n  # to replace those with nil for consistency.\n  defp nilify(\"\"), do: nil\n  defp nilify(other), do: other\n\n  @doc \"\"\"\n  Returns the string representation of the given [URI struct](`t:t/0`).\n\n  ## Examples\n\n      iex> uri = URI.parse(\"http://google.com\")\n      iex> URI.to_string(uri)\n      \"http://google.com\"\n\n      iex> uri = URI.parse(\"foo://bar.baz\")\n      iex> URI.to_string(uri)\n      \"foo://bar.baz\"\n\n  \"\"\"\n  @spec to_string(t) :: binary\n  defdelegate to_string(uri), to: String.Chars.URI\n\n  @doc ~S\"\"\"\n  Merges two URIs.\n\n  This function merges two URIs as per\n  [RFC 3986, section 5.2](https://tools.ietf.org/html/rfc3986#section-5.2).\n\n  ## Examples\n\n      iex> URI.merge(URI.parse(\"http://google.com\"), \"/query\") |> to_string()\n      \"http://google.com/query\"\n\n      iex> URI.merge(\"http://example.com\", \"http://google.com\") |> to_string()\n      \"http://google.com\"\n\n  \"\"\"\n  @spec merge(t | binary, t | binary) :: t\n  def merge(uri, rel)\n\n  def merge(%URI{scheme: nil}, _rel) do\n    raise ArgumentError, \"you must merge onto an absolute URI\"\n  end\n\n  def merge(_base, %URI{scheme: rel_scheme} = rel) when rel_scheme != nil do\n    %{rel | path: remove_dot_segments_from_path(rel.path)}\n  end\n\n  def merge(%URI{} = base, %URI{host: host} = rel) when host != nil do\n    %{rel | scheme: base.scheme, path: remove_dot_segments_from_path(rel.path)}\n  end\n\n  def merge(%URI{} = base, %URI{path: nil} = rel) do\n    %{base | query: rel.query || base.query, fragment: rel.fragment}\n  end\n\n  def merge(%URI{host: nil, path: nil} = base, %URI{} = rel) do\n    %{\n      base\n      | path: remove_dot_segments_from_path(rel.path),\n        query: rel.query,\n        fragment: rel.fragment\n    }\n  end\n\n  def merge(%URI{} = base, %URI{} = rel) do\n    new_path = merge_paths(base.path, rel.path)\n    %{base | path: new_path, query: rel.query, fragment: rel.fragment}\n  end\n\n  def merge(base, rel) do\n    merge(parse(base), parse(rel))\n  end\n\n  defp merge_paths(nil, rel_path), do: merge_paths(\"/\", rel_path)\n  defp merge_paths(\"\", rel_path), do: merge_paths(\"/\", rel_path)\n  defp merge_paths(_, \"/\" <> _ = rel_path), do: remove_dot_segments_from_path(rel_path)\n\n  defp merge_paths(base_path, rel_path) do\n    (path_to_segments(base_path) ++ [:+] ++ path_to_segments(rel_path))\n    |> remove_dot_segments([])\n    |> join_reversed_segments()\n  end\n\n  defp remove_dot_segments_from_path(nil), do: nil\n\n  defp remove_dot_segments_from_path(path) do\n    path_to_segments(path)\n    |> remove_dot_segments([])\n    |> join_reversed_segments()\n  end\n\n  defp path_to_segments(path) do\n    case String.split(path, \"/\") do\n      [\"\" | tail] -> [:/ | tail]\n      segments -> segments\n    end\n  end\n\n  defp remove_dot_segments([], acc), do: acc\n  defp remove_dot_segments([:/ | tail], acc), do: remove_dot_segments(tail, [:/ | acc])\n  defp remove_dot_segments([_, :+ | tail], acc), do: remove_dot_segments(tail, acc)\n  defp remove_dot_segments([\".\"], acc), do: remove_dot_segments([], [\"\" | acc])\n  defp remove_dot_segments([\".\" | tail], acc), do: remove_dot_segments(tail, acc)\n  defp remove_dot_segments([\"..\" | tail], [:/]), do: remove_dot_segments(tail, [:/])\n  defp remove_dot_segments([\"..\"], [_ | acc]), do: remove_dot_segments([], [\"\" | acc])\n  defp remove_dot_segments([\"..\" | tail], [_ | acc]), do: remove_dot_segments(tail, acc)\n  defp remove_dot_segments([head | tail], acc), do: remove_dot_segments(tail, [head | acc])\n\n  defp join_reversed_segments([:/]), do: \"/\"\n\n  defp join_reversed_segments(segments) do\n    case Enum.reverse(segments) do\n      [:/ | tail] -> [\"\" | tail]\n      list -> list\n    end\n    |> Enum.join(\"/\")\n  end\n\n  @doc \"\"\"\n  Appends `query` to the given `uri`.\n\n  The given `query` is not automatically encoded, use `encode/2` or `encode_www_form/1`.\n\n  ## Examples\n\n      iex> URI.append_query(URI.parse(\"http://example.com/\"), \"x=1\") |> URI.to_string()\n      \"http://example.com/?x=1\"\n\n      iex> URI.append_query(URI.parse(\"http://example.com/?x=1\"), \"y=2\") |> URI.to_string()\n      \"http://example.com/?x=1&y=2\"\n\n      iex> URI.append_query(URI.parse(\"http://example.com/?x=1\"), \"x=2\") |> URI.to_string()\n      \"http://example.com/?x=1&x=2\"\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec append_query(t(), binary()) :: t()\n  def append_query(%URI{} = uri, query) when is_binary(query) and uri.query in [nil, \"\"] do\n    %{uri | query: query}\n  end\n\n  def append_query(%URI{} = uri, query) when is_binary(query) do\n    if String.ends_with?(uri.query, \"&\") do\n      %{uri | query: uri.query <> query}\n    else\n      %{uri | query: uri.query <> \"&\" <> query}\n    end\n  end\n\n  @doc \"\"\"\n  Appends `path` to the given `uri`.\n\n  Path must start with `/` and cannot contain additional URL components like\n  fragments or query strings. This function further assumes the path is valid and\n  it does not contain a query string or fragment parts.\n\n  ## Examples\n\n      iex> URI.append_path(URI.parse(\"http://example.com/foo/?x=1\"), \"/my-path\") |> URI.to_string()\n      \"http://example.com/foo/my-path?x=1\"\n\n      iex> URI.append_path(URI.parse(\"http://example.com\"), \"my-path\")\n      ** (ArgumentError) path must start with \"/\", got: \"my-path\"\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec append_path(t(), String.t()) :: t()\n  def append_path(%URI{}, \"//\" <> _ = path) do\n    raise ArgumentError, ~s|path cannot start with \"//\", got: #{inspect(path)}|\n  end\n\n  def append_path(%URI{path: path} = uri, \"/\" <> rest = all) do\n    cond do\n      path == nil -> %{uri | path: all}\n      path != \"\" and :binary.last(path) == ?/ -> %{uri | path: path <> rest}\n      true -> %{uri | path: path <> all}\n    end\n  end\n\n  def append_path(%URI{}, path) when is_binary(path) do\n    raise ArgumentError, ~s|path must start with \"/\", got: #{inspect(path)}|\n  end\nend\n\ndefimpl String.Chars, for: URI do\n  def to_string(%{host: host, path: path} = uri)\n      when host != nil and is_binary(path) and\n             path != \"\" and binary_part(path, 0, 1) != \"/\" do\n    raise ArgumentError,\n          \":path in URI must be empty or an absolute path if URL has a :host, got: #{inspect(uri)}\"\n  end\n\n  def to_string(%{scheme: scheme, port: port, path: path, query: query, fragment: fragment} = uri) do\n    uri =\n      case scheme && URI.default_port(scheme) do\n        ^port -> %{uri | port: nil}\n        _ -> uri\n      end\n\n    # Based on https://tools.ietf.org/html/rfc3986#section-5.3\n    authority = extract_authority(uri)\n\n    IO.iodata_to_binary([\n      if(scheme, do: [scheme, ?:], else: []),\n      if(authority, do: [\"//\" | authority], else: []),\n      if(path, do: path, else: []),\n      if(query, do: [\"?\" | query], else: []),\n      if(fragment, do: [\"#\" | fragment], else: [])\n    ])\n  end\n\n  defp extract_authority(%{host: nil, authority: authority}) do\n    authority\n  end\n\n  defp extract_authority(%{host: host, userinfo: userinfo, port: port}) do\n    # According to the grammar at\n    # https://tools.ietf.org/html/rfc3986#appendix-A, a \"host\" can have a colon\n    # in it only if it's an IPv6 or \"IPvFuture\" address, so if there's a colon\n    # in the host we can safely surround it with [].\n    [\n      if(userinfo, do: [userinfo | \"@\"], else: []),\n      if(String.contains?(host, \":\"), do: [\"[\", host | \"]\"], else: host),\n      if(port, do: [\":\" | Integer.to_string(port)], else: [])\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/lib/version.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Version do\n  @moduledoc ~S\"\"\"\n  Functions for parsing and matching versions against requirements.\n\n  A version is a string in a specific format or a `Version`\n  generated after parsing via `Version.parse/1`.\n\n  Although Elixir projects are not required to follow SemVer,\n  they must follow the format outlined on [SemVer 2.0 schema](https://semver.org/).\n\n  ## Versions\n\n  In a nutshell, a version is represented by three numbers:\n\n      MAJOR.MINOR.PATCH\n\n  Pre-releases are supported by optionally appending a hyphen and a series of\n  period-separated identifiers immediately following the patch version.\n  Identifiers consist of only ASCII alphanumeric characters and hyphens (`[0-9A-Za-z-]`):\n\n      \"1.0.0-alpha.3\"\n\n  Build information can be added by appending a plus sign and a series of\n  dot-separated identifiers immediately following the patch or pre-release version.\n  Identifiers consist of only ASCII alphanumeric characters and hyphens (`[0-9A-Za-z-]`):\n\n      \"1.0.0-alpha.3+20130417140000.amd64\"\n\n  ## Requirements\n\n  Requirements allow you to specify which versions of a given\n  dependency you are willing to work against. Requirements support the common\n  comparison operators such as `>`, `>=`, `<`, `<=`, and `==` that work as one\n  would expect, and additionally the special operator `~>` described in detail\n  further below.\n\n      # Only version 2.0.0\n      \"== 2.0.0\"\n\n      # Anything later than 2.0.0\n      \"> 2.0.0\"\n\n  You can skip the operator, which is equivalent to `==`:\n\n      # Only version 2.0.0\n      \"2.0.0\"\n\n  Requirements also support `and` and `or` for complex conditions:\n\n      # 2.0.0 and later until 2.1.0\n      \">= 2.0.0 and < 2.1.0\"\n\n  Since the example above is such a common requirement, it can\n  be expressed as:\n\n      \"~> 2.0.0\"\n\n  `~>` will never include pre-release versions of its upper bound,\n  regardless of the usage of the `:allow_pre` option, or whether the operand\n  is a pre-release version. It can also be used to set an upper bound on only the major\n  version part. See the table below for `~>` requirements and\n  their corresponding translations.\n\n  `~>`           | Translation\n  :------------- | :---------------------\n  `~> 2.0.0`     | `>= 2.0.0 and < 2.1.0`\n  `~> 2.1.2`     | `>= 2.1.2 and < 2.2.0`\n  `~> 2.1.3-dev` | `>= 2.1.3-dev and < 2.2.0`\n  `~> 2.0`       | `>= 2.0.0 and < 3.0.0`\n  `~> 2.1`       | `>= 2.1.0 and < 3.0.0`\n\n  The requirement operand after the `~>` is allowed to omit the patch version,\n  allowing us to express `~> 2.1` or `~> 2.1-dev`, something that wouldn't be allowed\n  when using the common comparison operators.\n\n  When the `:allow_pre` option is set `false` in `Version.match?/3`, the requirement\n  will not match a pre-release version unless the operand is a pre-release version.\n  The default is to always allow pre-releases but note that in\n  Hex `:allow_pre` is set to `false`. See the table below for examples.\n\n  Requirement    | Version     | `:allow_pre`      | Matches\n  :------------- | :---------- | :---------------- | :------\n  `~> 2.0`       | `2.1.0`     | `true` or `false` | `true`\n  `~> 2.0`       | `3.0.0`     | `true` or `false` | `false`\n  `~> 2.0.0`     | `2.0.5`     | `true` or `false` | `true`\n  `~> 2.0.0`     | `2.1.0`     | `true` or `false` | `false`\n  `~> 2.1.2`     | `2.1.6-dev` | `true`            | `true`\n  `~> 2.1.2`     | `2.1.6-dev` | `false`           | `false`\n  `~> 2.1-dev`   | `2.2.0-dev` | `true` or `false` | `true`\n  `~> 2.1.2-dev` | `2.1.6-dev` | `true` or `false` | `true`\n  `>= 2.1.0`     | `2.2.0-dev` | `true`            | `true`\n  `>= 2.1.0`     | `2.2.0-dev` | `false`           | `false`\n  `>= 2.1.0-dev` | `2.2.6-dev` | `true` or `false` | `true`\n\n  \"\"\"\n\n  import Kernel, except: [match?: 2]\n\n  @doc \"\"\"\n  The Version struct.\n\n  It contains the fields `:major`, `:minor`, `:patch`, `:pre`, and\n  `:build` according to SemVer 2.0, where `:pre` is a list.\n\n  You can read those fields but you should not create a new `Version`\n  directly via the struct syntax. Instead use the functions in this\n  module.\n  \"\"\"\n  @enforce_keys [:major, :minor, :patch]\n  @derive {Inspect, optional: [:pre, :build]}\n  defstruct [:major, :minor, :patch, pre: [], build: nil]\n\n  @type version :: String.t() | t\n  @type requirement :: String.t() | Version.Requirement.t()\n  @type major :: non_neg_integer\n  @type minor :: non_neg_integer\n  @type patch :: non_neg_integer\n  @type pre :: [String.t() | non_neg_integer]\n  @type build :: String.t() | nil\n  @type t :: %__MODULE__{major: major, minor: minor, patch: patch, pre: pre, build: build}\n\n  @type match_opts :: [allow_pre: boolean()]\n\n  defmodule Requirement do\n    @moduledoc \"\"\"\n    A struct that holds version requirement information.\n\n    The struct fields are private and should not be accessed.\n\n    See the \"Requirements\" section in the `Version` module\n    for more information.\n    \"\"\"\n\n    defstruct [:source, :lexed]\n\n    @opaque t :: %__MODULE__{\n              source: String.t(),\n              lexed: [atom | matchable]\n            }\n\n    @typep matchable ::\n             {Version.major(), Version.minor(), Version.patch(), Version.pre(), Version.build()}\n\n    @compile inline: [compare: 2]\n\n    @doc false\n    @spec new(String.t(), [atom | matchable]) :: t\n    def new(source, lexed) do\n      %__MODULE__{source: source, lexed: lexed}\n    end\n\n    @doc false\n    @spec compile_requirement(t) :: t\n    def compile_requirement(%Requirement{} = requirement) do\n      requirement\n    end\n\n    @doc false\n    @spec match?(t, tuple) :: boolean\n    def match?(%__MODULE__{lexed: [operator, req | rest]}, version) do\n      match_lexed?(rest, version, match_op?(operator, req, version))\n    end\n\n    defp match_lexed?([:and, operator, req | rest], version, acc),\n      do: match_lexed?(rest, version, acc and match_op?(operator, req, version))\n\n    defp match_lexed?([:or, operator, req | rest], version, acc),\n      do: acc or match_lexed?(rest, version, match_op?(operator, req, version))\n\n    defp match_lexed?([], _version, acc),\n      do: acc\n\n    defp match_op?(:==, req, version) do\n      compare(version, req) == :eq\n    end\n\n    defp match_op?(:!=, req, version) do\n      compare(version, req) != :eq\n    end\n\n    defp match_op?(:~>, {major, minor, nil, req_pre, _}, {_, _, _, pre, allow_pre} = version) do\n      compare(version, {major, minor, 0, req_pre, nil}) in [:eq, :gt] and\n        compare(version, {major + 1, 0, 0, [0], nil}) == :lt and\n        (allow_pre or req_pre != [] or pre == [])\n    end\n\n    defp match_op?(:~>, {major, minor, _, req_pre, _} = req, {_, _, _, pre, allow_pre} = version) do\n      compare(version, req) in [:eq, :gt] and\n        compare(version, {major, minor + 1, 0, [0], nil}) == :lt and\n        (allow_pre or req_pre != [] or pre == [])\n    end\n\n    defp match_op?(:>, {_, _, _, req_pre, _} = req, {_, _, _, pre, allow_pre} = version) do\n      compare(version, req) == :gt and (allow_pre or req_pre != [] or pre == [])\n    end\n\n    defp match_op?(:>=, {_, _, _, req_pre, _} = req, {_, _, _, pre, allow_pre} = version) do\n      compare(version, req) in [:eq, :gt] and (allow_pre or req_pre != [] or pre == [])\n    end\n\n    defp match_op?(:<, req, version) do\n      compare(version, req) == :lt\n    end\n\n    defp match_op?(:<=, req, version) do\n      compare(version, req) in [:eq, :lt]\n    end\n\n    defp compare({major1, minor1, patch1, pre1, _}, {major2, minor2, patch2, pre2, _}) do\n      cond do\n        major1 > major2 -> :gt\n        major1 < major2 -> :lt\n        minor1 > minor2 -> :gt\n        minor1 < minor2 -> :lt\n        patch1 > patch2 -> :gt\n        patch1 < patch2 -> :lt\n        pre1 == [] and pre2 != [] -> :gt\n        pre1 != [] and pre2 == [] -> :lt\n        pre1 > pre2 -> :gt\n        pre1 < pre2 -> :lt\n        true -> :eq\n      end\n    end\n  end\n\n  defmodule InvalidRequirementError do\n    @moduledoc \"\"\"\n    An exception raised when a version requirement is invalid.\n\n    For example, see `Version.parse_requirement!/1`.\n    \"\"\"\n\n    defexception [:requirement]\n\n    @impl true\n    def exception(requirement) when is_binary(requirement) do\n      %__MODULE__{requirement: requirement}\n    end\n\n    @impl true\n    def message(%{requirement: requirement}) do\n      \"invalid requirement: #{inspect(requirement)}\"\n    end\n  end\n\n  defmodule InvalidVersionError do\n    @moduledoc \"\"\"\n    An exception raised when a version is invalid.\n\n    For example, see `Version.parse!/1`.\n    \"\"\"\n\n    defexception [:version]\n\n    @impl true\n    def exception(version) when is_binary(version) do\n      %__MODULE__{version: version}\n    end\n\n    @impl true\n    def message(%{version: version}) do\n      \"invalid version: #{inspect(version)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Checks if the given version matches the specification.\n\n  Returns `true` if `version` satisfies `requirement`, `false` otherwise.\n  Raises a `Version.InvalidRequirementError` exception if `requirement` is not\n  parsable, or a `Version.InvalidVersionError` exception if `version` is not parsable.\n  If given an already parsed version and requirement this function won't\n  raise.\n\n  ## Options\n\n    * `:allow_pre` (boolean) - when `false`, pre-release versions will not match\n      unless the operand is a pre-release version. Defaults to `true`.\n      For examples, please refer to the table above under the \"Requirements\" section.\n\n  ## Examples\n\n      iex> Version.match?(\"2.0.0\", \"> 1.0.0\")\n      true\n\n      iex> Version.match?(\"2.0.0\", \"== 1.0.0\")\n      false\n\n      iex> Version.match?(\"2.1.6-dev\", \"~> 2.1.2\")\n      true\n\n      iex> Version.match?(\"2.1.6-dev\", \"~> 2.1.2\", allow_pre: false)\n      false\n\n      iex> Version.match?(\"foo\", \"== 1.0.0\")\n      ** (Version.InvalidVersionError) invalid version: \"foo\"\n\n      iex> Version.match?(\"2.0.0\", \"== == 1.0.0\")\n      ** (Version.InvalidRequirementError) invalid requirement: \"== == 1.0.0\"\n\n  \"\"\"\n  @spec match?(version, requirement, match_opts) :: boolean\n  def match?(version, requirement, opts \\\\ [])\n\n  def match?(version, requirement, opts) when is_binary(requirement) do\n    match?(version, parse_requirement!(requirement), opts)\n  end\n\n  def match?(version, requirement, opts) do\n    allow_pre = Keyword.get(opts, :allow_pre, true)\n    matchable_pattern = to_matchable(version, allow_pre)\n\n    Requirement.match?(requirement, matchable_pattern)\n  end\n\n  @doc \"\"\"\n  Compares two versions.\n\n  Returns `:gt` if the first version is greater than the second one, and `:lt`\n  for vice versa. If the two versions are equal, `:eq` is returned.\n\n  Pre-releases are strictly less than their corresponding release versions.\n\n  Patch segments are compared lexicographically if they are alphanumeric, and\n  numerically otherwise.\n\n  Build segments are ignored: if two versions differ only in their build segment\n  they are considered to be equal.\n\n  Raises a `Version.InvalidVersionError` exception if any of the two given\n  versions are not parsable. If given an already parsed version this function\n  won't raise.\n\n  ## Examples\n\n      iex> Version.compare(\"2.0.1-alpha1\", \"2.0.0\")\n      :gt\n\n      iex> Version.compare(\"1.0.0-beta\", \"1.0.0-rc1\")\n      :lt\n\n      iex> Version.compare(\"1.0.0-10\", \"1.0.0-2\")\n      :gt\n\n      iex> Version.compare(\"2.0.1+build0\", \"2.0.1\")\n      :eq\n\n      iex> Version.compare(\"invalid\", \"2.0.1\")\n      ** (Version.InvalidVersionError) invalid version: \"invalid\"\n\n  \"\"\"\n  @spec compare(version, version) :: :gt | :eq | :lt\n  def compare(version1, version2) do\n    do_compare(to_matchable(version1, true), to_matchable(version2, true))\n  end\n\n  defp do_compare({major1, minor1, patch1, pre1, _}, {major2, minor2, patch2, pre2, _}) do\n    cond do\n      major1 > major2 -> :gt\n      major1 < major2 -> :lt\n      minor1 > minor2 -> :gt\n      minor1 < minor2 -> :lt\n      patch1 > patch2 -> :gt\n      patch1 < patch2 -> :lt\n      pre1 == [] and pre2 != [] -> :gt\n      pre1 != [] and pre2 == [] -> :lt\n      pre1 > pre2 -> :gt\n      pre1 < pre2 -> :lt\n      true -> :eq\n    end\n  end\n\n  @doc \"\"\"\n  Parses a version string into a `Version` struct.\n\n  ## Examples\n\n      iex> Version.parse(\"2.0.1-alpha1\")\n      {:ok, %Version{major: 2, minor: 0, patch: 1, pre: [\"alpha1\"]}}\n\n      iex> Version.parse(\"2.0-alpha1\")\n      :error\n\n  \"\"\"\n  @spec parse(String.t()) :: {:ok, t} | :error\n  def parse(string) when is_binary(string) do\n    case Version.Parser.parse_version(string) do\n      {:ok, {major, minor, patch, pre, build_parts}} ->\n        build = if build_parts == [], do: nil, else: Enum.join(build_parts, \".\")\n        version = %Version{major: major, minor: minor, patch: patch, pre: pre, build: build}\n        {:ok, version}\n\n      :error ->\n        :error\n    end\n  end\n\n  @doc \"\"\"\n  Parses a version string into a `Version`.\n\n  If `string` is an invalid version, a `Version.InvalidVersionError` is raised.\n\n  ## Examples\n\n      iex> Version.parse!(\"2.0.1-alpha1\")\n      %Version{major: 2, minor: 0, patch: 1, pre: [\"alpha1\"]}\n\n      iex> Version.parse!(\"2.0-alpha1\")\n      ** (Version.InvalidVersionError) invalid version: \"2.0-alpha1\"\n\n  \"\"\"\n  @spec parse!(String.t()) :: t\n  def parse!(string) when is_binary(string) do\n    case parse(string) do\n      {:ok, version} -> version\n      :error -> raise InvalidVersionError, string\n    end\n  end\n\n  @doc \"\"\"\n  Parses a version requirement string into a `Version.Requirement` struct.\n\n  ## Examples\n\n      iex> {:ok, requirement} = Version.parse_requirement(\"== 2.0.1\")\n      iex> requirement\n      Version.parse_requirement!(\"== 2.0.1\")\n\n      iex> Version.parse_requirement(\"== == 2.0.1\")\n      :error\n\n  \"\"\"\n  @spec parse_requirement(String.t()) :: {:ok, Requirement.t()} | :error\n  def parse_requirement(string) when is_binary(string) do\n    case Version.Parser.parse_requirement(string) do\n      {:ok, lexed} -> {:ok, Requirement.new(string, lexed)}\n      :error -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Parses a version requirement string into a `Version.Requirement` struct.\n\n  If `string` is an invalid requirement, a `Version.InvalidRequirementError` is raised.\n\n  ## Examples\n\n      iex> Version.parse_requirement!(\"== 2.0.1\")\n      Version.parse_requirement!(\"== 2.0.1\")\n\n      iex> Version.parse_requirement!(\"== == 2.0.1\")\n      ** (Version.InvalidRequirementError) invalid requirement: \"== == 2.0.1\"\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec parse_requirement!(String.t()) :: Requirement.t()\n  def parse_requirement!(string) when is_binary(string) do\n    case parse_requirement(string) do\n      {:ok, requirement} -> requirement\n      :error -> raise InvalidRequirementError, string\n    end\n  end\n\n  @doc \"\"\"\n  Compiles a requirement to an internal representation that may optimize matching.\n\n  The internal representation is opaque.\n  \"\"\"\n  @spec compile_requirement(Requirement.t()) :: Requirement.t()\n  defdelegate compile_requirement(requirement), to: Requirement\n\n  defp to_matchable(%Version{major: major, minor: minor, patch: patch, pre: pre}, allow_pre?) do\n    {major, minor, patch, pre, allow_pre?}\n  end\n\n  defp to_matchable(string, allow_pre?) do\n    case Version.Parser.parse_version(string) do\n      {:ok, {major, minor, patch, pre, _build_parts}} ->\n        {major, minor, patch, pre, allow_pre?}\n\n      :error ->\n        raise InvalidVersionError, string\n    end\n  end\n\n  @doc \"\"\"\n  Converts the given version to a string.\n\n  ## Examples\n\n      iex> Version.to_string(%Version{major: 1, minor: 2, patch: 3})\n      \"1.2.3\"\n      iex> Version.to_string(Version.parse!(\"1.14.0-rc.0+build0\"))\n      \"1.14.0-rc.0+build0\"\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec to_string(Version.t()) :: String.t()\n  def to_string(%Version{} = version) do\n    pre = pre_to_string(version.pre)\n    build = if build = version.build, do: \"+#{build}\"\n    \"#{version.major}.#{version.minor}.#{version.patch}#{pre}#{build}\"\n  end\n\n  defp pre_to_string([]) do\n    \"\"\n  end\n\n  defp pre_to_string(pre) do\n    \"-\" <>\n      Enum.map_join(pre, \".\", fn\n        int when is_integer(int) -> Integer.to_string(int)\n        string when is_binary(string) -> string\n      end)\n  end\n\n  defmodule Parser do\n    @moduledoc false\n\n    operators = [\n      {\">=\", :>=},\n      {\"<=\", :<=},\n      {\"~>\", :~>},\n      {\">\", :>},\n      {\"<\", :<},\n      {\"==\", :==},\n      {\" or \", :or},\n      {\" and \", :and}\n    ]\n\n    def lexer(string) do\n      lexer(string, \"\", [])\n    end\n\n    for {string_op, atom_op} <- operators do\n      defp lexer(unquote(string_op) <> rest, buffer, acc) do\n        lexer(rest, \"\", [unquote(atom_op) | maybe_prepend_buffer(buffer, acc)])\n      end\n    end\n\n    defp lexer(\"!=\" <> rest, buffer, acc) do\n      IO.warn(\"!= inside Version requirements is deprecated, use ~> or >= instead\")\n      lexer(rest, \"\", [:!= | maybe_prepend_buffer(buffer, acc)])\n    end\n\n    defp lexer(\"!\" <> rest, buffer, acc) do\n      IO.warn(\"! inside Version requirements is deprecated, use ~> or >= instead\")\n      lexer(rest, \"\", [:!= | maybe_prepend_buffer(buffer, acc)])\n    end\n\n    defp lexer(\" \" <> rest, buffer, acc) do\n      lexer(rest, \"\", maybe_prepend_buffer(buffer, acc))\n    end\n\n    defp lexer(<<char::utf8, rest::binary>>, buffer, acc) do\n      lexer(rest, <<buffer::binary, char::utf8>>, acc)\n    end\n\n    defp lexer(<<>>, buffer, acc) do\n      maybe_prepend_buffer(buffer, acc)\n    end\n\n    defp maybe_prepend_buffer(\"\", acc), do: acc\n\n    defp maybe_prepend_buffer(buffer, [head | _] = acc)\n         when is_atom(head) and head not in [:and, :or],\n         do: [buffer | acc]\n\n    defp maybe_prepend_buffer(buffer, acc),\n      do: [buffer, :== | acc]\n\n    defp revert_lexed([version, op, cond | rest], acc)\n         when is_binary(version) and is_atom(op) and cond in [:or, :and] do\n      with {:ok, version} <- validate_requirement(op, version) do\n        revert_lexed(rest, [cond, op, version | acc])\n      end\n    end\n\n    defp revert_lexed([version, op], acc) when is_binary(version) and is_atom(op) do\n      with {:ok, version} <- validate_requirement(op, version) do\n        {:ok, [op, version | acc]}\n      end\n    end\n\n    defp revert_lexed(_rest, _acc), do: :error\n\n    defp validate_requirement(op, version) do\n      case parse_version(version, true) do\n        {:ok, version} when op == :~> -> {:ok, version}\n        {:ok, {_, _, patch, _, _} = version} when is_integer(patch) -> {:ok, version}\n        _ -> :error\n      end\n    end\n\n    @spec parse_requirement(String.t()) :: {:ok, term} | :error\n    def parse_requirement(source) do\n      revert_lexed(lexer(source), [])\n    end\n\n    def parse_version(string, approximate? \\\\ false) when is_binary(string) do\n      destructure [version_with_pre, build], String.split(string, \"+\", parts: 2)\n      destructure [version, pre], String.split(version_with_pre, \"-\", parts: 2)\n      destructure [major, minor, patch, next], String.split(version, \".\")\n\n      with nil <- next,\n           {:ok, major} <- require_digits(major),\n           {:ok, minor} <- require_digits(minor),\n           {:ok, patch} <- maybe_patch(patch, approximate?),\n           {:ok, pre_parts} <- optional_dot_separated(pre),\n           {:ok, pre_parts} <- convert_parts_to_integer(pre_parts, []),\n           {:ok, build_parts} <- optional_dot_separated(build) do\n        {:ok, {major, minor, patch, pre_parts, build_parts}}\n      else\n        _other -> :error\n      end\n    end\n\n    defp require_digits(nil), do: :error\n\n    defp require_digits(string) do\n      if leading_zero?(string), do: :error, else: parse_digits(string, \"\")\n    end\n\n    defp leading_zero?(<<?0, _, _::binary>>), do: true\n    defp leading_zero?(_), do: false\n\n    defp parse_digits(<<char, rest::binary>>, acc) when char in ?0..?9,\n      do: parse_digits(rest, <<acc::binary, char>>)\n\n    defp parse_digits(<<>>, acc) when byte_size(acc) > 0, do: {:ok, String.to_integer(acc)}\n    defp parse_digits(_, _acc), do: :error\n\n    defp maybe_patch(patch, approximate?)\n    defp maybe_patch(nil, true), do: {:ok, nil}\n    defp maybe_patch(patch, _), do: require_digits(patch)\n\n    defp optional_dot_separated(nil), do: {:ok, []}\n\n    defp optional_dot_separated(string) do\n      parts = String.split(string, \".\")\n\n      if Enum.all?(parts, &(&1 != \"\" and valid_identifier?(&1))) do\n        {:ok, parts}\n      else\n        :error\n      end\n    end\n\n    defp convert_parts_to_integer([part | rest], acc) do\n      case parse_digits(part, \"\") do\n        {:ok, integer} ->\n          if leading_zero?(part) do\n            :error\n          else\n            convert_parts_to_integer(rest, [integer | acc])\n          end\n\n        :error ->\n          convert_parts_to_integer(rest, [part | acc])\n      end\n    end\n\n    defp convert_parts_to_integer([], acc) do\n      {:ok, Enum.reverse(acc)}\n    end\n\n    defp valid_identifier?(<<char, rest::binary>>)\n         when char in ?0..?9\n         when char in ?a..?z\n         when char in ?A..?Z\n         when char == ?- do\n      valid_identifier?(rest)\n    end\n\n    defp valid_identifier?(<<>>) do\n      true\n    end\n\n    defp valid_identifier?(_other) do\n      false\n    end\n  end\nend\n\ndefimpl String.Chars, for: Version do\n  defdelegate to_string(version), to: Version\nend\n\ndefimpl String.Chars, for: Version.Requirement do\n  def to_string(%Version.Requirement{source: source}) do\n    source\n  end\nend\n\ndefimpl Inspect, for: Version.Requirement do\n  def inspect(%Version.Requirement{source: source}, opts) do\n    colorized = Inspect.Algebra.color_doc(\"\\\"\" <> source <> \"\\\"\", :string, opts)\n\n    Inspect.Algebra.concat([\"Version.parse_requirement!(\", colorized, \")\"])\n  end\nend\n"
  },
  {
    "path": "lib/elixir/mix.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Elixir.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :elixir,\n      version: System.version(),\n      build_per_environment: false\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/pages/anti-patterns/code-anti-patterns.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Code-related anti-patterns\n\nThis document outlines potential anti-patterns related to your code and particular Elixir idioms and features.\n\n## Comments overuse\n\n#### Problem\n\nWhen you overuse comments or comment self-explanatory code, it can have the effect of making code *less readable*.\n\n#### Example\n\n```elixir\n# Returns the Unix timestamp of 5 minutes from the current time\ndefp unix_five_min_from_now do\n  # Get the current time\n  now = DateTime.utc_now()\n\n  # Convert it to a Unix timestamp\n  unix_now = DateTime.to_unix(now, :second)\n\n  # Add five minutes in seconds\n  unix_now + (60 * 5)\nend\n```\n\n#### Refactoring\n\nPrefer clear and self-explanatory function names, module names, and variable names when possible. In the example above, the function name explains well what the function does, so you likely won't need the comment before it. The code also explains the operations well through variable names and clear function calls.\n\nYou could refactor the code above like this:\n\n```elixir\n@five_min_in_seconds 60 * 5\n\ndefp unix_five_min_from_now do\n  now = DateTime.utc_now()\n  unix_now = DateTime.to_unix(now, :second)\n  unix_now + @five_min_in_seconds\nend\n```\n\nWe removed the unnecessary comments. We also added a `@five_min_in_seconds` module attribute, which serves the additional purpose of giving a name to the \"magic\" number `60 * 5`, making the code clearer and more expressive.\n\n#### Additional remarks\n\nElixir makes a clear distinction between **documentation** and code comments. The language has built-in first-class support for documentation through `@doc`, `@moduledoc`, and more. See the [\"Writing documentation\"](../getting-started/writing-documentation.md) guide for more information.\n\n## Complex `else` clauses in `with`\n\n#### Problem\n\nThis anti-pattern refers to `with` expressions that flatten all its error clauses into a single complex `else` block. This situation is harmful to the code readability and maintainability because it's difficult to know from which clause the error value came.\n\n#### Example\n\nAn example of this anti-pattern, as shown below, is a function `open_decoded_file/1` that reads a Base64-encoded string content from a file and returns a decoded binary string. This function uses a `with` expression that needs to handle two possible errors, all of which are concentrated in a single complex `else` block.\n\n```elixir\ndef open_decoded_file(path) do\n  with {:ok, encoded} <- File.read(path),\n       {:ok, decoded} <- Base.decode64(encoded) do\n    {:ok, String.trim(decoded)}\n  else\n    {:error, _} -> {:error, :badfile}\n    :error -> {:error, :badencoding}\n  end\nend\n```\n\nIn the code above, it is unclear how each pattern on the left side of `<-` relates to their error at the end. The more patterns in a `with`, the less clear the code gets, and the more likely it is that unrelated failures will overlap each other.\n\n#### Refactoring\n\nIn this situation, instead of concentrating all error handling within a single complex `else` block, it is better to normalize the return types in specific private functions. In this way, `with` can focus on the success case and the errors are normalized closer to where they happen, leading to better organized and maintainable code.\n\n```elixir\ndef open_decoded_file(path) do\n  with {:ok, encoded} <- file_read(path),\n       {:ok, decoded} <- base_decode64(encoded) do\n    {:ok, String.trim(decoded)}\n  end\nend\n\ndefp file_read(path) do\n  case File.read(path) do\n    {:ok, contents} -> {:ok, contents}\n    {:error, _} -> {:error, :badfile}\n  end\nend\n\ndefp base_decode64(contents) do\n  case Base.decode64(contents) do\n    {:ok, decoded} -> {:ok, decoded}\n    :error -> {:error, :badencoding}\n  end\nend\n```\n\n## Complex extractions in clauses\n\n#### Problem\n\nWhen we use multi-clause functions, it is possible to extract values in the clauses for further usage and for pattern matching/guard checking. This extraction itself does not represent an anti-pattern, but when you have *extractions made across several clauses and several arguments of the same function*, it becomes hard to know which extracted parts are used for pattern/guards and what is used only inside the function body. This anti-pattern is related to [Unrelated multi-clause function](design-anti-patterns.md#unrelated-multi-clause-function), but with implications of its own. It impairs the code readability in a different way.\n\n#### Example\n\nThe multi-clause function `drive/1` is extracting fields of an `%User{}` struct for usage in the clause expression (`age`) and for usage in the function body (`name`):\n\n```elixir\ndef drive(%User{name: name, age: age}) when age >= 18 do\n  \"#{name} can drive\"\nend\n\ndef drive(%User{name: name, age: age}) when age < 18 do\n  \"#{name} cannot drive\"\nend\n```\n\nWhile the example above is small and does not constitute an anti-pattern, it is an example of mixed extraction and pattern matching. A situation where `drive/1` was more complex, having many more clauses, arguments, and extractions, would make it hard to know at a glance which variables are used for pattern/guards and which ones are not.\n\n#### Refactoring\n\nAs shown below, a possible solution to this anti-pattern is to extract only pattern/guard related variables in the signature once you have many arguments or multiple clauses:\n\n```elixir\ndef drive(%User{age: age} = user) when age >= 18 do\n  %User{name: name} = user\n  \"#{name} can drive\"\nend\n\ndef drive(%User{age: age} = user) when age < 18 do\n  %User{name: name} = user\n  \"#{name} cannot drive\"\nend\n```\n\n## Dynamic atom creation\n\n#### Problem\n\nAn `Atom` is an Elixir basic type whose value is its own name. Atoms are often useful to identify resources or express the state, or result, of an operation. Creating atoms dynamically is not an anti-pattern by itself. However, atoms are not garbage collected by the Erlang Virtual Machine, so values of this type live in memory during a software's entire execution lifetime. The Erlang VM limits the number of atoms that can exist in an application by default to *1 048 576*, which is more than enough to cover all atoms defined in a program, but attempts to serve as an early limit for applications which are \"leaking atoms\" through dynamic creation.\n\nFor these reasons, creating atoms dynamically can be considered an anti-pattern when the developer has no control over how many atoms will be created during the software execution. This unpredictable scenario can expose the software to unexpected behavior caused by excessive memory usage, or even by reaching the maximum number of *atoms* possible.\n\n#### Example\n\nPicture yourself implementing code that converts string values into atoms. These strings could have been received from an external system, either as part of a request into our application, or as part of a response to your application. This dynamic and unpredictable scenario poses a security risk, as these uncontrolled conversions can potentially trigger out-of-memory errors.\n\n```elixir\ndefmodule MyRequestHandler do\n  def parse(%{\"status\" => status, \"message\" => message} = _payload) do\n    %{status: String.to_atom(status), message: message}\n  end\nend\n```\n\n```elixir\niex> MyRequestHandler.parse(%{\"status\" => \"ok\", \"message\" => \"all good\"})\n%{status: :ok, message: \"all good\"}\n```\n\nWhen we use the `String.to_atom/1` function to dynamically create an atom, it essentially gains potential access to create arbitrary atoms in our system, causing us to lose control over adhering to the limits established by the BEAM. This issue could be exploited by someone to create enough atoms to shut down a system.\n\n#### Refactoring\n\nTo eliminate this anti-pattern, developers must either perform explicit conversions by mapping strings to atoms or replace the use of `String.to_atom/1` with `String.to_existing_atom/1`. An explicit conversion could be done as follows:\n\n```elixir\ndefmodule MyRequestHandler do\n  def parse(%{\"status\" => status, \"message\" => message} = _payload) do\n    %{status: convert_status(status), message: message}\n  end\n\n  defp convert_status(\"ok\"), do: :ok\n  defp convert_status(\"error\"), do: :error\n  defp convert_status(\"redirect\"), do: :redirect\nend\n```\n\n```elixir\niex> MyRequestHandler.parse(%{\"status\" => \"status_not_seen_anywhere\", \"message\" => \"all good\"})\n** (FunctionClauseError) no function clause matching in MyRequestHandler.convert_status/1\n```\n\nBy explicitly listing all supported statuses, you guarantee only a limited number of conversions may happen. Passing an invalid status will lead to a function clause error.\n\nAn alternative is to use `String.to_existing_atom/1`, which will only convert a string to atom if the atom already exists in the system:\n\n```elixir\ndefmodule MyRequestHandler do\n  def parse(%{\"status\" => status, \"message\" => message} = _payload) do\n    %{status: String.to_existing_atom(status), message: message}\n  end\nend\n```\n\n```elixir\niex> MyRequestHandler.parse(%{\"status\" => \"status_not_seen_anywhere\", \"message\" => \"all good\"})\n** (ArgumentError) errors were found at the given arguments:\n\n  * 1st argument: not an already existing atom\n```\n\nIn such cases, passing an unknown status will raise as long as the status was not defined anywhere as an atom in the system. However, assuming `status` can be either `:ok`, `:error`, or `:redirect`, how can you guarantee those atoms exist? You must ensure those atoms exist somewhere **in the same module** where `String.to_existing_atom/1` is called. For example, if you had this code:\n\n```elixir\ndefmodule MyRequestHandler do\n  def parse(%{\"status\" => status, \"message\" => message} = _payload) do\n    %{status: String.to_existing_atom(status), message: message}\n  end\n\n  def handle(%{status: status}) do\n    case status do\n      :ok -> ...\n      :error -> ...\n      :redirect -> ...\n    end\n  end\nend\n```\n\nAll valid statuses are defined as atoms within the same module, and that's enough. If you want to be explicit, you could also have a function that lists them:\n\n```elixir\ndef valid_statuses do\n  [:ok, :error, :redirect]\nend\n```\n\nHowever, keep in mind using a module attribute or defining the atoms in the module body, outside of a function, are not sufficient, as the module body is only executed during compilation and it is not necessarily part of the compiled module loaded at runtime.\n\n## Long parameter list\n\n#### Problem\n\nIn a functional language like Elixir, functions tend to explicitly receive all inputs and return all relevant outputs, instead of relying on mutations or side-effects. As functions grow in complexity, the amount of arguments (parameters) they need to work with may grow, to a point where the function's interface becomes confusing and prone to errors during use.\n\n#### Example\n\nIn the following example, the `loan/6` functions takes too many arguments, causing its interface to be confusing and potentially leading developers to introduce errors during calls to this function.\n\n```elixir\ndefmodule Library do\n  # Too many parameters that can be grouped!\n  def loan(user_name, email, password, user_alias, book_title, book_ed) do\n    ...\n  end\nend\n```\n\n#### Refactoring\n\nTo address this anti-pattern, related arguments can be grouped using key-value data structures, such as maps, structs, or even keyword lists in the case of optional arguments. This effectively reduces the number of arguments and the key-value data structures adds clarity to the caller.\n\nFor this particular example, the arguments to `loan/6` can be grouped into two different maps, thereby reducing its arity to `loan/2`:\n\n```elixir\ndefmodule Library do\n  def loan(%{name: name, email: email, password: password, alias: alias} = user, %{title: title, ed: ed} = book) do\n    ...\n  end\nend\n```\n\nIn some cases, the function with too many arguments may be a private function, which gives us more flexibility over how to separate the function arguments. One possible suggestion for such scenarios is to split the arguments in two maps (or tuples): one map keeps the data that may change, and the other keeps the data that won't change (read-only). This gives us a mechanical option to refactor the code.\n\nOther times, a function may legitimately take half a dozen or more completely unrelated arguments. This may suggest the function is trying to do too much and would be better broken into multiple functions, each responsible for a smaller piece of the overall responsibility.\n\n## Namespace trespassing\n\n#### Problem\n\nThis anti-pattern manifests when a package author or a library defines modules outside of its \"namespace\". A library should use its name as a \"prefix\" for all of its modules. For example, a package named `:my_lib` should define all of its modules within the `MyLib` namespace, such as `MyLib.User`, `MyLib.SubModule`, `MyLib.Application`, and `MyLib` itself.\n\nThis is important because the Erlang VM can only load one instance of a module at a time. So if there are multiple libraries that define the same module, then they are incompatible with each other due to this limitation. By always using the library name as a prefix, it avoids module name clashes due to the unique prefix.\n\n#### Example\n\nThis problem commonly manifests when writing an extension of another library. For example, imagine you are writing a package that adds authentication to [Plug](https://github.com/elixir-plug/plug) called `:plug_auth`. You must avoid defining modules within the `Plug` namespace:\n\n```elixir\ndefmodule Plug.Auth do\n  # ...\nend\n```\n\nEven if `Plug` does not currently define a `Plug.Auth` module, it may add such a module in the future, which would ultimately conflict with `plug_auth`'s definition.\n\n#### Refactoring\n\nGiven the package is named `:plug_auth`, it must define modules inside the `PlugAuth` namespace:\n\n```elixir\ndefmodule PlugAuth do\n  # ...\nend\n```\n\n#### Additional remarks\n\nThere are few known exceptions to this anti-pattern:\n\n  * [Protocol implementations](`Kernel.defimpl/2`) are, by design, defined under the protocol namespace\n\n  * In some scenarios, the namespace owner may allow exceptions to this rule. For example, in Elixir itself, you defined [custom Mix tasks](`Mix.Task`) by placing them under the `Mix.Tasks` namespace, such as `Mix.Tasks.PlugAuth`\n\n  * If you are the maintainer for both `plug` and `plug_auth`, then you may allow `plug_auth` to define modules with the `Plug` namespace, such as `Plug.Auth`. However, you are responsible for avoiding or managing any conflicts that may arise in the future\n\n## Non-assertive map access\n\n#### Problem\n\nIn Elixir, it is possible to access values from `Map`s, which are key-value data structures, either statically or dynamically.\n\nWhen a key is expected to exist in a map, it must be accessed using the `map.key` notation, making it clear to developers (and the compiler) that the key must exist. If the key does not exist, an exception is raised (and in some cases also compiler warnings). This is also known as the static notation, as the key is known at the time of writing the code.\n\nWhen a key is optional, the `map[:key]` notation must be used instead. This way, if the informed key does not exist, `nil` is returned. This is the dynamic notation, as it also supports dynamic key access, such as `map[some_var]`.\n\nWhen you use `map[:key]` to access a key that always exists in the map, you are making the code less clear for developers and for the compiler, as they now need to work with the assumption the key may not be there. This mismatch may also make it harder to track certain bugs. If the key is unexpectedly missing, you will have a `nil` value propagate through the system, instead of raising on map access.\n\n##### Table: Comparison of map access notations\n\n| Access notation | Key exists | Key doesn't exist | Use case |\n| --------------- | ---------- | ----------------- | -------- |\n| `map.key` | Returns the value | Raises `KeyError` | Structs and maps with known atom keys |\n| `map[:key]` | Returns the value | Returns `nil` | Any `Access`-based data structure, optional keys |\n\n#### Example\n\nThe function `plot/1` tries to draw a graphic to represent the position of a point in a Cartesian plane. This function receives a parameter of `Map` type with the point attributes, which can be a point of a 2D or 3D Cartesian coordinate system. This function uses dynamic access to retrieve values for the map keys:\n\n```elixir\ndefmodule Graphics do\n  def plot(point) do\n    # Some other code...\n    {point[:x], point[:y], point[:z]}\n  end\nend\n```\n\n```elixir\niex> point_2d = %{x: 2, y: 3}\n%{x: 2, y: 3}\niex> point_3d = %{x: 5, y: 6, z: 7}\n%{x: 5, y: 6, z: 7}\niex> Graphics.plot(point_2d)\n{2, 3, nil}\niex> Graphics.plot(point_3d)\n{5, 6, 7}\n```\n\nGiven we want to plot both 2D and 3D points, the behavior above is expected. But what happens if we forget to pass a point with either `:x` or `:y`?\n\n```elixir\niex> bad_point = %{y: 3, z: 4}\n%{y: 3, z: 4}\niex> Graphics.plot(bad_point)\n{nil, 3, 4}\n```\n\nThe behavior above is unexpected because our function should not work with points without a `:x` key. This leads to subtle bugs, as we may now pass `nil` to another function, instead of raising early on, as shown next:\n\n```iex\niex> point_without_x = %{y: 10}\n%{y: 10}\niex> {x, y, _} = Graphics.plot(point_without_x)\n{nil, 10, nil}\niex> distance_from_origin = :math.sqrt(x * x + y * y)\n** (ArithmeticError) bad argument in arithmetic expression\n    :erlang.*(nil, nil)\n```\n\nThe error above occurs later in the code because `nil` (from missing `:x`) is invalid for arithmetic operations, making it harder to identify the original issue.\n\n#### Refactoring\n\nTo remove this anti-pattern, we must use the dynamic `map[:key]` syntax and the static `map.key` notation according to our requirements. We expect `:x` and `:y` to always exist, but not `:z`. The next code illustrates the refactoring of `plot/1`, removing this anti-pattern:\n\n```elixir\ndefmodule Graphics do\n  def plot(point) do\n    # Some other code...\n    {point.x, point.y, point[:z]}\n  end\nend\n```\n\n```elixir\niex> Graphics.plot(point_2d)\n{2, 3, nil}\niex> Graphics.plot(bad_point)\n** (KeyError) key :x not found in: %{y: 3, z: 4}\n  graphic.ex:4: Graphics.plot/1\n```\n\nThis is beneficial because:\n\n1. It makes your expectations clear to others reading the code\n2. It fails fast when required data is missing\n3. It allows the compiler to provide warnings when accessing non-existent fields, particularly in compile-time structures like structs\n\nOverall, the usage of `map.key` and `map[:key]` encode important information about your data structure, allowing developers to be clear about their intent. The `Access` module documentation also provides useful reference on this topic. You can also consider the `Map` module when working with maps of any keys, which contains functions for fetching keys (with or without default values), updating and removing keys, traversals, and more.\n\nAn alternative to refactor this anti-pattern is to use pattern matching, defining explicit clauses for 2D vs 3D points:\n\n```elixir\ndefmodule Graphics do\n  # 3d\n  def plot(%{x: x, y: y, z: z}) do\n    # Some other code...\n    {x, y, z}\n  end\n\n  # 2d\n  def plot(%{x: x, y: y}) do\n    # Some other code...\n    {x, y}\n  end\nend\n```\n\nPattern-matching is specially useful when matching over multiple keys as well as on the values themselves at once. In the example above, the code will not only extract the values but also verify that the required keys exist. If we try to call `plot/1` with a map that doesn't have the required keys, we'll get a `FunctionClauseError`:\n\n```elixir\niex> incomplete_point = %{x: 5}\n%{x: 5}\niex> Graphics.plot(incomplete_point)\n** (FunctionClauseError) no function clause matching in Graphics.plot/1\n\n    The following arguments were given to Graphics.plot/1:\n\n        # 1\n        %{x: 5}\n```\n\nAnother option is to use structs. By default, structs only support static access to its fields. In such scenarios, you may consider defining structs for both 2D and 3D points:\n\n```elixir\ndefmodule Point2D do\n  @enforce_keys [:x, :y]\n  defstruct [x: nil, y: nil]\nend\n```\n\nGenerally speaking, structs are useful when sharing data structures across modules, at the cost of adding a compile time dependency between these modules. If module `A` uses a struct defined in module `B`, `A` must be recompiled if the fields in the struct `B` change.\n\nIn summary, Elixir provides several ways to access map values, each with different behaviors:\n\n1. **Static access** (`map.key`): Fails fast when keys are missing, ideal for structs and maps with known atom keys\n2. **Dynamic access** (`map[:key]`): Works with any `Access` data structure, suitable for optional fields, returns nil for missing keys\n3. **Pattern matching**: Provides a powerful way to both extract values and ensure required map/struct keys exist in one operation\n\nChoosing the right approach depends if the keys are known upfront or not. Static access and pattern matching are mostly equivalent (although pattern matching allows you to match on multiple keys at once, including matching on the struct name).\n\n#### Additional remarks\n\nThis anti-pattern was formerly known as [Accessing non-existent map/struct fields](https://github.com/lucasvegi/Elixir-Code-Smells#accessing-non-existent-mapstruct-fields).\n\n## Non-assertive pattern matching\n\n#### Problem\n\nOverall, Elixir systems are composed of many supervised processes, so the effects of an error are localized to a single process, and don't propagate to the entire application. A supervisor detects the failing process, reports it, and possibly restarts it. This anti-pattern arises when developers write defensive or imprecise code, capable of returning incorrect values which were not planned for, instead of programming in an assertive style through pattern matching and guards.\n\n#### Example\n\nThe function `get_value/2` tries to extract a value from a specific key of a URL query string. As it is not implemented using pattern matching, `get_value/2` always returns a value, regardless of the format of the URL query string passed as a parameter in the call. Sometimes the returned value will be valid. However, if a URL query string with an unexpected format is used in the call, `get_value/2` will extract incorrect values from it:\n\n```elixir\ndefmodule Extract do\n  def get_value(string, desired_key) do\n    parts = String.split(string, \"&\")\n\n    Enum.find_value(parts, fn pair ->\n      key_value = String.split(pair, \"=\")\n      Enum.at(key_value, 0) == desired_key && Enum.at(key_value, 1)\n    end)\n  end\nend\n```\n\n```elixir\n# URL query string with the planned format - OK!\niex> Extract.get_value(\"name=Lucas&university=UFMG&lab=ASERG\", \"lab\")\n\"ASERG\"\niex> Extract.get_value(\"name=Lucas&university=UFMG&lab=ASERG\", \"university\")\n\"UFMG\"\n# Unplanned URL query string format - Unplanned value extraction!\niex> Extract.get_value(\"name=Lucas&university=institution=UFMG&lab=ASERG\", \"university\")\n\"institution\"   # <= why not \"institution=UFMG\"? or only \"UFMG\"?\n```\n\n#### Refactoring\n\nTo remove this anti-pattern, `get_value/2` can be refactored through the use of pattern matching. So, if an unexpected URL query string format is used, the function will crash instead of returning an invalid value. This behavior, shown below, allows clients to decide how to handle these errors and doesn't give a false impression that the code is working correctly when unexpected values are extracted:\n\n```elixir\ndefmodule Extract do\n  def get_value(string, desired_key) do\n    parts = String.split(string, \"&\")\n\n    Enum.find_value(parts, fn pair ->\n      [key, value] = String.split(pair, \"=\") # <= pattern matching\n      key == desired_key && value\n    end)\n  end\nend\n```\n\n```elixir\n# URL query string with the planned format - OK!\niex> Extract.get_value(\"name=Lucas&university=UFMG&lab=ASERG\", \"name\")\n\"Lucas\"\n# Unplanned URL query string format - Crash explaining the problem to the client!\niex> Extract.get_value(\"name=Lucas&university=institution=UFMG&lab=ASERG\", \"university\")\n** (MatchError) no match of right hand side value: [\"university\", \"institution\", \"UFMG\"]\n  extract.ex:7: anonymous fn/2 in Extract.get_value/2 # <= left hand: [key, value] pair\niex> Extract.get_value(\"name=Lucas&university&lab=ASERG\", \"university\")\n** (MatchError) no match of right hand side value: [\"university\"]\n  extract.ex:7: anonymous fn/2 in Extract.get_value/2 # <= left hand: [key, value] pair\n```\n\nElixir and pattern matching promote an assertive style of programming where you handle the known cases. Once an unexpected scenario arises, you can decide to address it accordingly based on practical examples, or conclude the scenario is indeed invalid and the exception is the desired choice.\n\n`case/2` is another important construct in Elixir that help us write assertive code, by matching on specific patterns. For example, if a function returns `{:ok, ...}` or `{:error, ...}`, prefer to explicitly match on both patterns:\n\n```elixir\ncase some_function(arg) do\n  {:ok, value} -> # ...\n  {:error, _} -> # ...\nend\n```\n\nIn particular, avoid matching solely on `_`, as shown below:\n\n```elixir\ncase some_function(arg) do\n  {:ok, value} -> # ...\n  _ -> # ...\nend\n```\n\n Matching on `_` is less clear in intent and it may hide bugs if `some_function/1` adds new return values in the future.\n\n#### Additional remarks\n\nThis anti-pattern was formerly known as [Speculative assumptions](https://github.com/lucasvegi/Elixir-Code-Smells#speculative-assumptions).\n\n## Non-assertive truthiness\n\n#### Problem\n\nElixir provides the concept of truthiness: `nil` and `false` are considered \"falsy\" and all other values are \"truthy\". Many constructs in the language, such as `&&/2`, `||/2`, and `!/1` handle truthy and falsy values. Using those operators is not an anti-pattern. However, using those operators when all operands are expected to be booleans, may be an anti-pattern.\n\n#### Example\n\nThe simplest scenario where this anti-pattern manifests is in conditionals, such as:\n\n```elixir\nif is_binary(name) && is_integer(age) do\n  # ...\nelse\n  # ...\nend\n```\n\nGiven both operands of `&&/2` are booleans, the code is more generic than necessary, and potentially unclear.\n\n#### Refactoring\n\nTo remove this anti-pattern, we can replace `&&/2`, `||/2`, and `!/1` by `and/2`, `or/2`, and `not/1` respectively. These operators assert at least their first argument is a boolean:\n\n```elixir\nif is_binary(name) and is_integer(age) do\n  # ...\nelse\n  # ...\nend\n```\n\nThis technique may be particularly important when working with Erlang code. Erlang does not have the concept of truthiness. It never returns `nil`, instead its functions may return `:error` or `:undefined` in places an Elixir developer would return `nil`. Therefore, to avoid accidentally interpreting `:undefined` or `:error` as a truthy value, you may prefer to use `and/2`, `or/2`, and `not/1` exclusively when interfacing with Erlang APIs.\n\n## Structs with 32 fields or more\n\n#### Problem\n\nStructs in Elixir are implemented as compile-time maps, which have a predefined amount of fields. When structs have 32 or more fields, their internal representation in the Erlang Virtual Machines changes, potentially leading to bloating and higher memory usage.\n\n#### Example\n\nAny struct with 32 or more fields will be problematic:\n\n```elixir\ndefmodule MyExample do\n  defstruct [\n    :field1,\n    :field2,\n    ...,\n    :field35\n  ]\nend\n```\n\nThe Erlang VM has two internal representations for maps: a flat map and a hash map. A flat map is represented internally as two tuples: one tuple containing the keys and another tuple holding the values. Whenever you update a flat map, the tuple keys are shared, reducing the amount of memory used by the update. A hash map has a more complex structure, which is efficient for a large amount of keys, but it does not share the key space.\n\nMaps of up to 32 keys are represented as flat maps. All others are hash map. Structs *are* maps (with a metadata field called `__struct__`) and so any struct with fewer than 32 fields is represented as a flat map. This allows us to optimize several struct operations, as we never add or remove fields to structs, we simply update them.\n\nFurthermore, structs of the same name \"instantiated\" in the same module will share the same \"tuple keys\" at compilation times, as long as they have fewer than 32 fields. For example, in the following code:\n\n```elixir\ndefmodule Example do\n  def users do\n    [%User{name: \"John\"}, %User{name: \"Meg\"}, ...]\n  end\nend\n```\n\nAll user structs will point to the same tuple keys at compile-time, also reducing the memory cost of instantiating structs with `%MyStruct{...}` notation. This optimization is also not available if the struct has 32 keys or more.\n\n#### Refactoring\n\nRemoving this anti-pattern, in a nutshell, requires ensuring your struct has fewer than 32 fields. There are a few techniques you could apply:\n\n  * If the struct has \"optional\" fields, for example, fields which are initialized with nil, you could nest all optional fields into other field, called `:metadata`, `:optionals`, or similar. This could lead to benefits such as being able to use pattern matching to check if a field exists or not, instead of relying on `nil` values\n\n  * You could nest structs, by storing structs within other fields. Fields that are rarely read or written to are good candidates to be moved to a nested struct\n\n  * You could nest fields as tuples. For example, if two fields are always read or updated together, they could be moved to a tuple (or another composite data structure)\n\nThe challenge is to balance the changes above with API ergonomics, in particular, when fields may be frequently read and written to.\n"
  },
  {
    "path": "lib/elixir/pages/anti-patterns/design-anti-patterns.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Design-related anti-patterns\n\nThis document outlines potential anti-patterns related to your modules, functions, and the role they play within a codebase.\n\n## Alternative return types\n\n#### Problem\n\nThis anti-pattern refers to functions that receive options (typically as a *keyword list* parameter) that drastically change their return type. Because options are optional and sometimes set dynamically, if they also change the return type, it may be hard to understand what the function actually returns.\n\n#### Example\n\nAn example of this anti-pattern, as shown below, is when a function has many alternative return types, depending on the options received as a parameter.\n\n```elixir\ndefmodule AlternativeInteger do\n  @spec parse(String.t(), keyword()) :: integer() | {integer(), String.t()} | :error\n  def parse(string, options \\\\ []) when is_list(options) do\n    if Keyword.get(options, :discard_rest, false) do\n      case Integer.parse(string) do\n        {int, _rest} -> int\n        :error -> :error\n      end\n    else\n      Integer.parse(string)\n    end\n  end\nend\n```\n\n```elixir\niex> AlternativeInteger.parse(\"13\")\n{13, \"\"}\niex> AlternativeInteger.parse(\"13\", discard_rest: false)\n{13, \"\"}\niex> AlternativeInteger.parse(\"13\", discard_rest: true)\n13\n```\n\n#### Refactoring\n\nTo refactor this anti-pattern, as shown next, add a specific function for each return type (for example, `parse_discard_rest/1`), no longer delegating this to options passed as arguments.\n\n```elixir\ndefmodule AlternativeInteger do\n  @spec parse(String.t()) :: {integer(), String.t()} | :error\n  def parse(string) do\n    Integer.parse(string)\n  end\n\n  @spec parse_discard_rest(String.t()) :: integer() | :error\n  def parse_discard_rest(string) do\n    case Integer.parse(string) do\n      {int, _rest} -> int\n      :error -> :error\n    end\n  end\nend\n```\n\n```elixir\niex> AlternativeInteger.parse(\"13\")\n{13, \"\"}\niex> AlternativeInteger.parse_discard_rest(\"13\")\n13\n```\n\n## Boolean obsession\n\n#### Problem\n\nThis anti-pattern happens when booleans are used instead of atoms to encode information. The usage of booleans themselves is not an anti-pattern, but whenever multiple booleans are used with overlapping states, replacing the booleans by atoms (or composite data types such as *tuples*) may lead to clearer code.\n\nThis is a special case of [*Primitive obsession*](#primitive-obsession), specific to boolean values.\n\n#### Example\n\nAn example of this anti-pattern is a function that receives two or more options, such as `editor: true` and `admin: true`, to configure its behavior in overlapping ways. In the code below, the `:editor` option has no effect if `:admin` is set, meaning that the `:admin` option has higher priority than `:editor`, and they are ultimately related.\n\n```elixir\ndefmodule MyApp do\n  def process(invoice, options \\\\ []) do\n    cond do\n      options[:admin] ->  # Is an admin\n      options[:editor] -> # Is an editor\n      true ->          # Is none\n    end\n  end\nend\n```\n\n#### Refactoring\n\nInstead of using multiple options, the code above could be refactored to receive a single option, called `:role`, that can be either `:admin`, `:editor`, or `:default`:\n\n```elixir\ndefmodule MyApp do\n  def process(invoice, options \\\\ []) do\n    case Keyword.get(options, :role, :default) do\n      :admin ->   # Is an admin\n      :editor ->  # Is an editor\n      :default -> # Is none\n    end\n  end\nend\n```\n\nThis anti-pattern may also happen in our own data structures. For example, we may define a `User` struct with two boolean fields, `:editor` and `:admin`, while a single field named `:role` may be preferred.\n\nFinally, it is worth noting that using atoms may be preferred even when we have a single boolean argument/option. For example, consider an invoice which may be set as approved/unapproved. One option is to provide a function that expects a boolean:\n\n```elixir\nMyApp.update(invoice, approved: true)\n```\n\nHowever, using atoms may read better and make it simpler to add further states (such as pending) in the future:\n\n```elixir\nMyApp.update(invoice, status: :approved)\n```\n\nRemember booleans are internally represented as atoms. Therefore there is no performance penalty in one approach over the other.\n\n## Exceptions for control-flow\n\n#### Problem\n\nThis anti-pattern refers to code that uses `Exception`s for control flow. Exception handling itself does not represent an anti-pattern, but developers must prefer to use `case` and pattern matching to change the flow of their code, instead of `try/rescue`. In turn, library authors should provide developers with APIs to handle errors without relying on exception handling. When developers have no freedom to decide if an error is exceptional or not, this is considered an anti-pattern.\n\n#### Example\n\nAn example of this anti-pattern, as shown below, is using `try/rescue` to deal with file operations:\n\n```elixir\ndefmodule MyModule do\n  def print_file(file) do\n    try do\n      IO.puts(File.read!(file))\n    rescue\n      e -> IO.puts(:stderr, Exception.message(e))\n    end\n  end\nend\n```\n\n```elixir\niex> MyModule.print_file(\"valid_file\")\nThis is a valid file!\n:ok\niex> MyModule.print_file(\"invalid_file\")\ncould not read file \"invalid_file\": no such file or directory\n:ok\n```\n\n#### Refactoring\n\nTo refactor this anti-pattern, as shown next, use `File.read/1`, which returns tuples instead of raising when a file cannot be read:\n\n```elixir\ndefmodule MyModule do\n  def print_file(file) do\n    case File.read(file) do\n      {:ok, binary} -> IO.puts(binary)\n      {:error, reason} -> IO.puts(:stderr, \"could not read file #{file}: #{reason}\")\n    end\n  end\nend\n```\n\nThis is only possible because the `File` module provides APIs for reading files with tuples as results (`File.read/1`), as well as a version that raises an exception (`File.read!/1`). The bang (exclamation point) is effectively part of [Elixir's naming conventions](naming-conventions.md#trailing-bang-foo).\n\nLibrary authors are encouraged to follow the same practices. In practice, the bang variant is implemented on top of the non-raising version of the code. For example, `File.read!/1` is implemented as:\n\n```elixir\ndef read!(path) do\n  case read(path) do\n    {:ok, binary} ->\n      binary\n\n    {:error, reason} ->\n      raise File.Error, reason: reason, action: \"read file\", path: IO.chardata_to_string(path)\n  end\nend\n```\n\nA common practice followed by the community is to make the non-raising version return `{:ok, result}` or `{:error, Exception.t}`. For example, an HTTP client may return `{:ok, %HTTP.Response{}}` on success cases and `{:error, %HTTP.Error{}}` for failures, where `HTTP.Error` is [implemented as an exception](`Kernel.defexception/1`). This makes it convenient for anyone to raise an exception by simply calling `Kernel.raise/1`.\n\n#### Additional remarks\n\nThis anti-pattern is of special importance to library authors and whenever writing functions that will be invoked by other developers and third-party code. Nevertheless, there are still scenarios where developers can afford to raise exceptions directly, for example:\n\n  * invalid arguments: it is expected that functions will raise for invalid arguments, as those are structural error and not semantic errors. For example, `File.read(123)` will always raise, because `123` is never a valid filename\n\n  * during tests, scripts, etc: those are common scenarios where you want your code to fail as soon as possible in case of errors. Using `!` functions, such as `File.read!/1`, allows you to do so quickly and with clear error messages\n\n  * some frameworks, such as [Phoenix](https://phoenixframework.org), allow developers to raise exceptions in their code and uses a protocol to convert these exceptions into semantic HTTP responses\n\nThis anti-pattern was formerly known as [Using exceptions for control-flow](https://github.com/lucasvegi/Elixir-Code-Smells#using-exceptions-for-control-flow).\n\n## Primitive obsession\n\n#### Problem\n\nThis anti-pattern happens when Elixir basic types (for example, *integer*, *float*, and *string*) are excessively used to carry structured information, rather than creating specific composite data types (for example, *tuples*, *maps*, and *structs*) that can better represent a domain.\n\n#### Example\n\nAn example of this anti-pattern is the use of a single *string* to represent an `Address`. An `Address` is a more complex structure than a simple basic (aka, primitive) value.\n\n```elixir\ndefmodule MyApp do\n  def extract_postal_code(address) when is_binary(address) do\n    # Extract postal code with address...\n  end\n\n  def fill_in_country(address) when is_binary(address) do\n    # Fill in missing country...\n  end\nend\n```\n\nWhile you may receive the `address` as a string from a database, web request, or a third-party, if you find yourself frequently manipulating or extracting information from the string, it is a good indicator you should convert the address into structured data:\n\nAnother example of this anti-pattern is using floating numbers to model money and currency, when [richer data structures should be preferred](https://hexdocs.pm/ex_money/).\n\n#### Refactoring\n\nPossible solutions to this anti-pattern is to use maps or structs to model our address. The example below creates an `Address` struct, better representing this domain through a composite type. Additionally, we introduce a `parse/1` function, that converts the string into an `Address`, which will simplify the logic of remaining functions. With this modification, we can extract each field of this composite type individually when needed.\n\n```elixir\ndefmodule Address do\n  defstruct [:street, :city, :state, :postal_code, :country]\nend\n```\n\n```elixir\ndefmodule MyApp do\n  def parse(address) when is_binary(address) do\n    # Returns %Address{}\n  end\n\n  def extract_postal_code(%Address{} = address) do\n    # Extract postal code with address...\n  end\n\n  def fill_in_country(%Address{} = address) do\n    # Fill in missing country...\n  end\nend\n```\n\n## Unrelated multi-clause function\n\n#### Problem\n\nUsing multi-clause functions is a powerful Elixir feature. However, some developers may abuse this feature to group *unrelated* functionality, which is an anti-pattern.\n\n#### Example\n\nA frequent example of this usage of multi-clause functions occurs when developers mix unrelated business logic into the same function definition, in a way that the behavior of each clause becomes completely distinct from the others. Such functions often have too broad specifications, making it difficult for other developers to understand and maintain them.\n\nSome developers may use documentation mechanisms such as `@doc` annotations to compensate for poor code readability, however the documentation itself may end-up full of conditionals to describe how the function behaves for each different argument combination. This is a good indicator that the clauses are ultimately unrelated.\n\n```elixir\n@doc \"\"\"\nUpdates a struct.\n\nIf given a product, it will...\n\nIf given an animal, it will...\n\"\"\"\ndef update(%Product{count: count, material: material})  do\n  # ...\nend\n\ndef update(%Animal{count: count, skin: skin})  do\n  # ...\nend\n```\n\nIf updating an animal is completely different from updating a product and requires a different set of rules, it may be worth splitting those over different functions or even different modules.\n\n#### Refactoring\n\nAs shown below, a possible solution to this anti-pattern is to break the business rules that are mixed up in a single unrelated multi-clause function in simple functions. Each function can have a specific name and `@doc`, describing its behavior and parameters received. While this refactoring sounds simple, it can impact the function's callers, so be careful!\n\n```elixir\n@doc \"\"\"\nUpdates a product.\n\nIt will...\n\"\"\"\ndef update_product(%Product{count: count, material: material}) do\n  # ...\nend\n\n@doc \"\"\"\nUpdates an animal.\n\nIt will...\n\"\"\"\ndef update_animal(%Animal{count: count, skin: skin}) do\n  # ...\nend\n```\n\nThese functions may still be implemented with multiple clauses, as long as the clauses group related functionality. For example, `update_product` could be in practice implemented as follows:\n\n```elixir\ndef update_product(%Product{count: 0}) do\n  # ...\nend\n\ndef update_product(%Product{material: material})\n    when material in [\"metal\", \"glass\"] do\n  # ...\nend\n\ndef update_product(%Product{material: material})\n    when material not in [\"metal\", \"glass\"] do\n  # ...\nend\n```\n\nYou can see this pattern in practice within Elixir itself. The `+/2` operator can add `Integer`s and `Float`s together, but not `String`s, which instead use the `<>/2` operator. In this sense, it is reasonable to handle integers and floats in the same operation, but strings are unrelated enough to deserve their own function.\n\nYou will also find examples in Elixir of functions that work with any struct, which would seemingly be an occurrence of this anti-pattern, such as `struct/2`:\n\n```elixir\niex> struct(URI.parse(\"/foo/bar\"), path: \"/bar/baz\")\n%URI{\n  scheme: nil,\n  userinfo: nil,\n  host: nil,\n  port: nil,\n  path: \"/bar/baz\",\n  query: nil,\n  fragment: nil\n}\n```\n\nThe difference here is that the `struct/2` function behaves precisely the same for any struct given, therefore there is no question of how the function handles different inputs. If the behavior is clear and consistent for all inputs, then the anti-pattern does not take place.\n\n## Using application configuration for libraries\n\n#### Problem\n\nThe [*application environment*](https://hexdocs.pm/elixir/Application.html#module-the-application-environment) can be used to parameterize global values that can be used in an Elixir system. This mechanism can be very useful and therefore is not considered an anti-pattern by itself. However, library authors should avoid using the application environment to configure their library. The reason is exactly that the application environment is a **global** state, so there can only be a single value for each key in the environment for an application. This makes it impossible for multiple applications depending on the same library to configure the same aspect of the library in different ways.\n\n#### Example\n\nThe `DashSplitter` module represents a library that configures the behavior of its functions through the global application environment. These configurations are concentrated in the *config/config.exs* file, shown below:\n\n```elixir\nimport Config\n\nconfig :app_config,\n  parts: 3\n\nimport_config \"#{config_env()}.exs\"\n```\n\nOne of the functions implemented by the `DashSplitter` library is `split/1`. This function aims to separate a string received via a parameter into a certain number of parts. The character used as a separator in `split/1` is always `\"-\"` and the number of parts the string is split into is defined globally by the application environment. This value is retrieved by the `split/1` function by calling `Application.fetch_env!/2`, as shown next:\n\n```elixir\ndefmodule DashSplitter do\n  def split(string) when is_binary(string) do\n    parts = Application.fetch_env!(:app_config, :parts) # <= retrieve parameterized value\n    String.split(string, \"-\", parts: parts)             # <= parts: 3\n  end\nend\n```\n\nDue to this parameterized value used by the `DashSplitter` library, all applications dependent on it can only use the `split/1` function with identical behavior about the number of parts generated by string separation. Currently, this value is equal to 3, as we can see in the use examples shown below:\n\n```elixir\niex> DashSplitter.split(\"Lucas-Francisco-Vegi\")\n[\"Lucas\", \"Francisco\", \"Vegi\"]\niex> DashSplitter.split(\"Lucas-Francisco-da-Matta-Vegi\")\n[\"Lucas\", \"Francisco\", \"da-Matta-Vegi\"]\n```\n\n#### Refactoring\n\nTo remove this anti-pattern, this type of configuration should be performed using a parameter passed to the function. The code shown below performs the refactoring of the `split/1` function by accepting [keyword lists](`Keyword`) as a new optional parameter. With this new parameter, it is possible to modify the default behavior of the function at the time of its call, allowing multiple different ways of using `split/2` within the same application:\n\n```elixir\ndefmodule DashSplitter do\n  def split(string, opts \\\\ []) when is_binary(string) and is_list(opts) do\n    parts = Keyword.get(opts, :parts, 2) # <= default config of parts == 2\n    String.split(string, \"-\", parts: parts)\n  end\nend\n```\n\n```elixir\niex> DashSplitter.split(\"Lucas-Francisco-da-Matta-Vegi\", [parts: 5])\n[\"Lucas\", \"Francisco\", \"da\", \"Matta\", \"Vegi\"]\niex> DashSplitter.split(\"Lucas-Francisco-da-Matta-Vegi\") #<= default config is used!\n[\"Lucas\", \"Francisco-da-Matta-Vegi\"]\n```\n\nOf course, not all uses of the application environment by libraries are incorrect. One example is using configuration to replace a component (or dependency) of a library by another that must behave the exact same. Consider a library that needs to parse CSV files. The library author may pick one package to use as default parser but allow its users to swap to different implementations via the application environment. At the end of the day, choosing a different CSV parser should not change the outcome, and library authors can even enforce this by [defining behaviours](../references/typespecs.md#behaviours) with the exact semantics they expect.\n\n#### Additional remarks: Supervision trees\n\nIn practice, libraries may require additional configuration beyond keyword lists. For example, if a library needs to start a supervision tree, how can the user of said library customize its supervision tree? Given the supervision tree itself is global (as it belongs to the library), library authors may be tempted to use the application configuration once more.\n\nOne solution is for the library to provide its own child specification, instead of starting the supervision tree itself. This allows the user to start all necessary processes under its own supervision tree, potentially passing custom configuration options during initialization.\n\nYou can see this pattern in practice in projects like [Nx](https://github.com/elixir-nx/nx) and [DNS Cluster](https://github.com/phoenixframework/dns_cluster). These libraries require that you list processes under your own supervision tree:\n\n```elixir\nchildren = [\n  {DNSCluster, query: \"my.subdomain\"}\n]\n```\n\nIn such cases, if the users of `DNSCluster` need to configure DNSCluster per environment, they can be the ones reading from the application environment, without the library forcing them to:\n\n```elixir\nchildren = [\n  {DNSCluster, query: Application.get_env(:my_app, :dns_cluster_query) || :ignore}\n]\n```\n\nSome libraries, such as [Ecto](https://github.com/elixir-ecto/ecto), allow you to pass your application name as an option (called `:otp_app` or similar) and then automatically read the environment from *your* application. While this addresses the issue with the application environment being global, as they read from each individual application, it comes at the cost of some indirection, compared to the example above where users explicitly read their application environment from their own code, whenever desired.\n\n#### Additional remarks: Compile-time configuration\n\nA similar discussion entails compile-time configuration. What if a library author requires some configuration to be provided at compilation time?\n\nOnce again, instead of forcing users of your library to provide compile-time configuration, you may want to allow users of your library to generate the code themselves. That's the approach taken by libraries such as [Ecto](https://github.com/elixir-ecto/ecto):\n\n```elixir\ndefmodule MyApp.Repo do\n  use Ecto.Repo, adapter: Ecto.Adapters.Postgres\nend\n```\n\nInstead of forcing developers to share a single repository, Ecto allows its users to define as many repositories as they want. Given the `:adapter` configuration is required at compile-time, it is a required value on `use Ecto.Repo`. If developers want to configure the adapter per environment, then it is their choice:\n\n```elixir\ndefmodule MyApp.Repo do\n  use Ecto.Repo, adapter: Application.compile_env(:my_app, :repo_adapter)\nend\n```\n\nOn the other hand, [code generation comes with its own anti-patterns](macro-anti-patterns.md), and must be considered carefully. That's to say: while using the application environment for libraries is discouraged, especially compile-time configuration, in some cases they may be the best option. For example, consider a library needs to parse CSV or JSON files to generate code based on data files. In such cases, it is best to provide reasonable defaults and make them customizable via the application environment, instead of asking each user of your library to generate the exact same code.\n\n#### Additional remarks: Mix tasks\n\nFor Mix tasks and related tools, it may be necessary to provide per-project configuration. For example, imagine you have a `:linter` project, which supports setting the output file and the verbosity level. You may choose to configure it through application environment:\n\n```elixir\nconfig :linter,\n  output_file: \"/path/to/output.json\",\n  verbosity: 3\n```\n\nHowever, `Mix` allows tasks to read per-project configuration via `Mix.Project.config/0`. In this case, you can configure the `:linter` directly in the `mix.exs` file:\n\n```elixir\ndef project do\n  [\n    app: :my_app,\n    version: \"1.0.0\",\n    linter: [\n      output_file: \"/path/to/output.json\",\n      verbosity: 3\n    ],\n    ...\n  ]\nend\n```\n\nAdditionally, if a Mix task is available, you can also accept these options as command line arguments (see `OptionParser`):\n\n```bash\nmix linter --output-file /path/to/output.json --verbosity 3\n```\n"
  },
  {
    "path": "lib/elixir/pages/anti-patterns/macro-anti-patterns.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Meta-programming anti-patterns\n\nThis document outlines potential anti-patterns related to meta-programming.\n\n## Compile-time dependencies\n\n#### Problem\n\nThis anti-pattern is related to dependencies between files in Elixir. Because macros are used at compile-time, the use of any macro in Elixir adds a compile-time dependency to the module that defines the macro.\n\nHowever, when macros are used in the body of a module, the arguments to the macro themselves may become compile-time dependencies. These dependencies may lead to dependency graphs where changing a single file causes several files to be recompiled.\n\n#### Example\n\nLet's take the [`Plug`](https://github.com/elixir-plug/plug) library as an example. The `Plug` project allows you to specify several modules, also known as plugs, which will be invoked whenever there is a request. As a user of `Plug`, you would use it as follows:\n\n```elixir\ndefmodule MyApp do\n  use Plug.Builder\n\n  plug MyApp.Authentication\nend\n```\n\nAnd imagine `Plug` has the following definitions of the macros above (simplified):\n\n```elixir\ndefmodule Plug.Builder do\n  defmacro __using__(_opts) do\n    quote do\n      Module.register_attribute(__MODULE__, :plugs, accumulate: true)\n      @before_compile Plug.Builder\n    end\n  end\n\n  defmacro plug(mod) do\n    quote do\n      @plugs unquote(mod)\n    end\n  end\n\n  ...\nend\n```\n\nThe implementation accumulates all modules inside the `@plugs` module attribute. Right before the module is compiled, `Plug.Builder` will reads all modules stored in `@plugs` and compile them into a function, like this:\n\n```elixir\ndef call(conn, _opts) do\n  MyApp.Authentication.call(conn)\nend\n```\n\nThe trouble with the code above is that, because the `plug MyApp.Authentication` was invoked at compile-time, the module `MyApp.Authentication` is now a compile-time dependency of `MyApp`, even though `MyApp.Authentication` is never used at compile-time. If `MyApp.Authentication` depends on other modules, even at runtime, this can now lead to a large recompilation graph in case of changes.\n\n#### Refactoring\n\nTo address this anti-pattern, a macro can expand literals within the context they are meant to be used, as follows:\n\n```elixir\n  defmacro plug(mod) do\n    mod = Macro.expand_literals(mod, %{__CALLER__ | function: {:call, 2}})\n\n    quote do\n      @plugs unquote(mod)\n    end\n  end\n```\n\nIn the example above, since `mod` is used only within the `call/2` function, we prematurely expand module reference as if it was inside the `call/2` function. Now `MyApp.Authentication` is only a runtime dependency of `MyApp`, no longer a compile-time one.\n\nNote, however, the above must only be done if your macros do not attempt to invoke any function, access any struct, or any other metadata of the module at compile-time. If you interact with the module given to a macro anywhere outside of definition of a function, then you effectively have a compile-time dependency. And, even though you generally want to avoid them, it is not always possible.\n\nIn actual projects, developers may use `mix xref trace path/to/file.ex` to execute a file and have it print information about which modules it depends on, and if those modules are compile-time, runtime, or export dependencies. See `mix xref` for more information.\n\n## Large code generation\n\n#### Problem\n\nThis anti-pattern is related to macros that generate too much code. When a macro generates a large amount of code, it impacts how the compiler and/or the runtime work. The reason for this is that Elixir may have to expand, compile, and execute the code multiple times, which will make compilation slower and the resulting compiled artifacts larger.\n\n#### Example\n\nImagine you are defining a router for a web application, where you could have macros like `get/2`. On every invocation of the macro (which could be hundreds), the code inside `get/2` will be expanded and compiled, which can generate a large volume of code overall.\n\n```elixir\ndefmodule Routes do\n  defmacro get(route, handler) do\n    quote do\n      route = unquote(route)\n      handler = unquote(handler)\n\n      if not is_binary(route) do\n        raise ArgumentError, \"route must be a binary\"\n      end\n\n      if not is_atom(handler) do\n        raise ArgumentError, \"handler must be a module\"\n      end\n\n      @store_route_for_compilation {route, handler}\n    end\n  end\nend\n```\n\n#### Refactoring\n\nTo remove this anti-pattern, the developer should simplify the macro, delegating part of its work to other functions. As shown below, by encapsulating the code inside `quote/1` inside the function `__define__/3` instead, we reduce the code that is expanded and compiled on every invocation of the macro, and instead we dispatch to a function to do the bulk of the work.\n\n```elixir\ndefmodule Routes do\n  defmacro get(route, handler) do\n    quote do\n      Routes.__define__(__MODULE__, unquote(route), unquote(handler))\n    end\n  end\n\n  def __define__(module, route, handler) do\n    if not is_binary(route) do\n      raise ArgumentError, \"route must be a binary\"\n    end\n\n    if not is_atom(handler) do\n      raise ArgumentError, \"handler must be a module\"\n    end\n\n    Module.put_attribute(module, :store_route_for_compilation, {route, handler})\n  end\nend\n```\n\n## Unnecessary macros\n\n#### Problem\n\n*Macros* are powerful meta-programming mechanisms that can be used in Elixir to extend the language. While using macros is not an anti-pattern in itself, this meta-programming mechanism should only be used when absolutely necessary. Whenever a macro is used, but it would have been possible to solve the same problem using functions or other existing Elixir structures, the code becomes unnecessarily more complex and less readable. Because macros are more difficult to implement and reason about, their indiscriminate use can compromise the evolution of a system, reducing its maintainability.\n\n#### Example\n\nThe `MyMath` module implements the `sum/2` macro to perform the sum of two numbers received as parameters. While this code has no syntax errors and can be executed correctly to get the desired result, it is unnecessarily more complex. By implementing this functionality as a macro rather than a conventional function, the code became less clear:\n\n```elixir\ndefmodule MyMath do\n  defmacro sum(v1, v2) do\n    quote do\n      unquote(v1) + unquote(v2)\n    end\n  end\nend\n```\n\n```elixir\niex> require MyMath\nMyMath\niex> MyMath.sum(3, 5)\n8\niex> MyMath.sum(3 + 1, 5 + 6)\n15\n```\n\n#### Refactoring\n\nTo remove this anti-pattern, the developer must replace the unnecessary macro with structures that are simpler to write and understand, such as named functions. The code shown below is the result of the refactoring of the previous example. Basically, the `sum/2` macro has been transformed into a conventional named function. Note that the `require/2` call is no longer needed:\n\n```elixir\ndefmodule MyMath do\n  def sum(v1, v2) do # <= The macro became a named function\n    v1 + v2\n  end\nend\n```\n\n```elixir\niex> MyMath.sum(3, 5)\n8\niex> MyMath.sum(3+1, 5+6)\n15\n```\n\n## `use` instead of `import`\n\n#### Problem\n\nElixir has mechanisms such as `import/1`, `alias/1`, and `use/1` to establish dependencies between modules. Code implemented with these mechanisms does not characterize a smell by itself. However, while the `import/1` and `alias/1` directives have lexical scope and only facilitate a module calling functions of another, the `use/1` directive has a *broader scope*, which can be problematic.\n\nThe `use/1` directive allows a module to inject any type of code into another, including propagating dependencies. In this way, using the `use/1` directive makes code harder to read, because to understand exactly what will happen when it references a module, it is necessary to have knowledge of the internal details of the referenced module.\n\n#### Example\n\nThe code shown below is an example of this anti-pattern. It defines three modules -- `ModuleA`, `Library`, and `ClientApp`. `ClientApp` is reusing code from the `Library` via the `use/1` directive, but is unaware of its internal details. This makes it harder for the author of `ClientApp` to visualize which modules and functionality are now available within its module. To make matters worse, `Library` also imports `ModuleA`, which defines a `foo/0` function that conflicts with a local function defined in `ClientApp`:\n\n```elixir\ndefmodule ModuleA do\n  def foo do\n    \"From Module A\"\n  end\nend\n```\n\n```elixir\ndefmodule Library do\n  defmacro __using__(_opts) do\n    quote do\n      import Library\n      import ModuleA  # <= propagating dependencies!\n    end\n  end\n\n  def from_lib do\n    \"From Library\"\n  end\nend\n```\n\n```elixir\ndefmodule ClientApp do\n  use Library\n\n  def foo do\n    \"Local function from client app\"\n  end\n\n  def from_client_app do\n    from_lib() <> \" - \" <> foo()\n  end\nend\n```\n\nWhen we try to compile `ClientApp`, Elixir detects the conflict and throws the following error:\n\n```text\nerror: imported ModuleA.foo/0 conflicts with local function\n  └ client_app.ex:4:\n```\n\n#### Refactoring\n\nTo remove this anti-pattern, we recommend library authors avoid providing `__using__/1` callbacks whenever it can be replaced by `alias/1` or `import/1` directives. In the following code, we assume `use Library` is no longer available and `ClientApp` was refactored in this way, and with that, the code is clearer and the conflict as previously shown no longer exists:\n\n```elixir\ndefmodule ClientApp do\n  import Library\n\n  def foo do\n    \"Local function from client app\"\n  end\n\n  def from_client_app do\n    from_lib() <> \" - \" <> foo()\n  end\nend\n```\n\n```elixir\niex> ClientApp.from_client_app()\n\"From Library - Local function from client app\"\n```\n\n#### Additional remarks\n\nIn situations where you need to do more than importing and aliasing modules, providing `use MyModule` may be necessary, as it provides a common extension point within the Elixir ecosystem.\n\nTherefore, to provide guidance and clarity, we recommend library authors to include an admonition block in their `@moduledoc` that explains how `use MyModule` impacts the developer's code. As an example, the `GenServer` documentation outlines:\n\n> #### `use GenServer` {: .info}\n>\n> When you `use GenServer`, the `GenServer` module will\n> set `@behaviour GenServer` and define a `child_spec/1`\n> function, so your module can be used as a child\n> in a supervision tree.\n\nThink of this summary as a [\"Nutrition facts label\"](https://en.wikipedia.org/wiki/Nutrition_facts_label) for code generation. Make sure to only list changes made to the public API of the module. For example, if `use Library` sets an internal attribute called `@_some_module_info` and this attribute is never meant to be public, avoid documenting it in the nutrition facts.\n\nFor convenience, the markup notation to generate the admonition block above is this:\n\n```markdown\n> #### `use GenServer` {: .info}\n>\n> When you `use GenServer`, the `GenServer` module will\n> set `@behaviour GenServer` and define a `child_spec/1`\n> function, so your module can be used as a child\n> in a supervision tree.\n```\n\n## Untracked compile-time dependencies\n\n#### Problem\n\nThis anti-pattern is the opposite of [\"Compile-time dependencies\"](#compile-time-dependencies) and it happens when a compile-time dependency is accidentally bypassed, making the Elixir compiler unable to track dependencies and recompile files correctly. This happens when building aliases (in other words, module names) dynamically, either within a module or within a macro.\n\n#### Example\n\nFor example, imagine you invoke a module at compile-time, you could write it as such:\n\n```elixir\ndefmodule MyModule do\n  SomeOtherModule.example()\nend\n```\n\nIn this case, Elixir knows `MyModule` is invoked `SomeOtherModule.example/0` outside of a function, and therefore at compile-time.\n\nElixir can also track module names even during dynamic calls:\n\n```elixir\ndefmodule MyModule do\n  mods = [OtherModule.Foo, OtherModule.Bar]\n\n  for mod <- mods do\n    mod.example()\n  end\nend\n```\n\nIn the previous example, even though Elixir does not know which modules the function `example/0` was invoked on, it knows the modules `OtherModule.Foo` and `OtherModule.Bar` are referred outside of a function and therefore they become compile-time dependencies. If any of them change, Elixir will recompile `MyModule` itself.\n\nHowever, you should not programmatically generate the module names themselves, as that would make it impossible for Elixir to track them. More precisely, do not do this:\n\n```elixir\ndefmodule MyModule do\n  parts = [:Foo, :Bar]\n\n  for part <- parts do\n    Module.concat(OtherModule, part).example()\n  end\nend\n```\n\nIn this case, because the whole module was generated, Elixir sees a dependency only to `OtherModule`, never to `OtherModule.Foo` and `OtherModule.Bar`, potentially leading to inconsistencies when recompiling projects.\n\nA similar bug can happen when abusing the property that aliases are simply atoms, defining the atoms directly. In the case below, Elixir never sees the aliases, leading to untracked compile-time dependencies:\n\n```elixir\ndefmodule MyModule do\n  mods = [:\"Elixir.OtherModule.Foo\", :\"Elixir.OtherModule.Bar\"]\n\n  for mod <- mods do\n    mod.example()\n  end\nend\n```\n\n#### Refactoring\n\nTo address this anti-pattern, you should avoid defining module names programmatically. For example, if you need to dispatch to multiple modules, do so by using full module names.\n\nInstead of:\n\n```elixir\ndefmodule MyModule do\n  parts = [:Foo, :Bar]\n\n  for part <- parts do\n    Module.concat(OtherModule, part).example()\n  end\nend\n```\n\nDo:\n\n```elixir\ndefmodule MyModule do\n  mods = [OtherModule.Foo, OtherModule.Bar]\n\n  for mod <- mods do\n    mod.example()\n  end\nend\n```\n\nIf you really need to define modules dynamically, you can do so via meta-programming, building the whole module name at compile-time:\n\n```elixir\ndefmodule MyMacro do\n  defmacro call_examples(parts) do\n    for part <- parts do\n      quote do\n        # This builds OtherModule.Foo at compile-time\n        OtherModule.unquote(part).example()\n      end\n    end\n  end\nend\n\ndefmodule MyModule do\n  import MyMacro\n  call_examples [:Foo, :Bar]\nend\n```\n\nIn actual projects, developers may use `mix xref trace path/to/file.ex` to execute a file and have it print information about which modules it depends on, and if those modules are compile-time, runtime, or export dependencies. This can help you debug if the dependencies are being properly tracked in relation to external modules. See `mix xref` for more information.\n"
  },
  {
    "path": "lib/elixir/pages/anti-patterns/process-anti-patterns.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Process-related anti-patterns\n\nThis document outlines potential anti-patterns related to processes and process-based abstractions.\n\n## Code organization by process\n\n#### Problem\n\nThis anti-pattern refers to code that is unnecessarily organized by processes. A process itself does not represent an anti-pattern, but it should only be used to model runtime properties (such as concurrency, access to shared resources, error isolation, etc). When you use a process for code organization, it can create bottlenecks in the system.\n\n#### Example\n\nAn example of this anti-pattern, as shown below, is a module that implements arithmetic operations (like `add` and `subtract`) by means of a `GenServer` process. If the number of calls to this single process grows, this code organization can compromise the system performance, therefore becoming a bottleneck.\n\n```elixir\ndefmodule Calculator do\n  @moduledoc \"\"\"\n  Calculator that performs basic arithmetic operations.\n\n  This code is unnecessarily organized in a GenServer process.\n  \"\"\"\n\n  use GenServer\n\n  def add(a, b, pid) do\n    GenServer.call(pid, {:add, a, b})\n  end\n\n  def subtract(a, b, pid) do\n    GenServer.call(pid, {:subtract, a, b})\n  end\n\n  @impl GenServer\n  def init(init_arg) do\n    {:ok, init_arg}\n  end\n\n  @impl GenServer\n  def handle_call({:add, a, b}, _from, state) do\n    {:reply, a + b, state}\n  end\n\n  def handle_call({:subtract, a, b}, _from, state) do\n    {:reply, a - b, state}\n  end\nend\n```\n\n```elixir\niex> {:ok, pid} = GenServer.start_link(Calculator, :init)\n{:ok, #PID<0.132.0>}\niex> Calculator.add(1, 5, pid)\n6\niex> Calculator.subtract(2, 3, pid)\n-1\n```\n\n#### Refactoring\n\nIn Elixir, as shown next, code organization must be done only through modules and functions. Whenever possible, a library should not impose specific behavior (such as parallelization) on its users. It is better to delegate this behavioral decision to the developers of clients, thus increasing the potential for code reuse of a library.\n\n```elixir\ndefmodule Calculator do\n  def add(a, b) do\n    a + b\n  end\n\n  def subtract(a, b) do\n    a - b\n  end\nend\n```\n\n```elixir\niex> Calculator.add(1, 5)\n6\niex> Calculator.subtract(2, 3)\n-1\n```\n\n## Scattered process interfaces\n\n#### Problem\n\nIn Elixir, the use of an `Agent`, a `GenServer`, or any other process abstraction is not an anti-pattern in itself. However, when the responsibility for direct interaction with a process is spread throughout the entire system, it can become problematic. This bad practice can increase the difficulty of code maintenance and make the code more prone to bugs.\n\n#### Example\n\nThe following code seeks to illustrate this anti-pattern. The responsibility for interacting directly with the `Agent` is spread across four different modules (`A`, `B`, `C`, and `D`).\n\n```elixir\ndefmodule A do\n  def update(process) do\n    # Some other code...\n    Agent.update(process, fn _list -> 123 end)\n  end\nend\n```\n\n```elixir\ndefmodule B do\n  def update(process) do\n    # Some other code...\n    Agent.update(process, fn content -> %{a: content} end)\n  end\nend\n```\n\n```elixir\ndefmodule C do\n  def update(process) do\n    # Some other code...\n    Agent.update(process, fn content -> [:atom_value | content] end)\n  end\nend\n```\n\n```elixir\ndefmodule D do\n  def get(process) do\n    # Some other code...\n    Agent.get(process, fn content -> content end)\n  end\nend\n```\n\nThis spreading of responsibility can generate duplicated code and make code maintenance more difficult. Also, due to the lack of control over the format of the shared data, complex composed data can be shared. This freedom to use any format of data is dangerous and can induce developers to introduce bugs.\n\n```elixir\n# start an agent with initial state of an empty list\niex> {:ok, agent} = Agent.start_link(fn -> [] end)\n{:ok, #PID<0.135.0>}\n\n# many data formats (for example, List, Map, Integer, Atom) are\n# combined through direct access spread across the entire system\niex> A.update(agent)\niex> B.update(agent)\niex> C.update(agent)\n\n# state of shared information\niex> D.get(agent)\n[:atom_value, %{a: 123}]\n```\n\nFor a `GenServer` and other behaviours, this anti-pattern will manifest when scattering calls to `GenServer.call/3` and `GenServer.cast/2` throughout multiple modules, instead of encapsulating all the interaction with the `GenServer` in a single place.\n\n#### Refactoring\n\nInstead of spreading direct access to a process abstraction, such as `Agent`, over many places in the code, it is better to refactor this code by centralizing the responsibility for interacting with a process in a single module. This refactoring improves maintainability by removing duplicated code; it also allows you to limit the accepted format for shared data, reducing bug-proneness. As shown below, the module `Foo.Bucket` is centralizing the responsibility for interacting with the `Agent`. Any other place in the code that needs to access shared data must now delegate this action to `Foo.Bucket`. Also, `Foo.Bucket` now only allows data to be shared in `Map` format.\n\n```elixir\ndefmodule Foo.Bucket do\n  use Agent\n\n  def start_link(_opts) do\n    Agent.start_link(fn -> %{} end)\n  end\n\n  def get(bucket, key) do\n    Agent.get(bucket, &Map.get(&1, key))\n  end\n\n  def put(bucket, key, value) do\n    Agent.update(bucket, &Map.put(&1, key, value))\n  end\nend\n```\n\nThe following are examples of how to delegate access to shared data (provided by an `Agent`) to `Foo.Bucket`.\n\n```elixir\n# start an agent through `Foo.Bucket`\niex> {:ok, bucket} = Foo.Bucket.start_link(%{})\n{:ok, #PID<0.114.0>}\n\n# add shared values to the keys `milk` and `beer`\niex> Foo.Bucket.put(bucket, \"milk\", 3)\niex> Foo.Bucket.put(bucket, \"beer\", 7)\n\n# access shared data of specific keys\niex> Foo.Bucket.get(bucket, \"beer\")\n7\niex> Foo.Bucket.get(bucket, \"milk\")\n3\n```\n\n#### Additional remarks\n\nThis anti-pattern was formerly known as [Agent obsession](https://github.com/lucasvegi/Elixir-Code-Smells/tree/main#agent-obsession).\n\n## Sending unnecessary data\n\n#### Problem\n\nSending a message to a process can be an expensive operation if the message is big enough. That's because that message will be fully copied to the receiving process, which may be CPU and memory intensive. This is due to Erlang's \"share nothing\" architecture, where each process has its own memory, which simplifies and speeds up garbage collection.\n\nThis is more obvious when using `send/2`, `GenServer.call/3`, or the initial data in `GenServer.start_link/3`. Notably this also happens when using `spawn/1`, `Task.async/1`, `Task.async_stream/3`, and so on. It is more subtle here as the anonymous function passed to these functions captures the variables it references, and all captured variables will be copied over. By doing this, you can accidentally send way more data to a process than you actually need.\n\n#### Example\n\nImagine you were to implement some simple reporting of IP addresses that made requests against your application. You want to do this asynchronously and not block processing, so you decide to use `spawn/1`. It may seem like a good idea to hand over the whole connection because we might need more data later. However passing the connection results in copying a lot of unnecessary data like the request body, params, etc.\n\n```elixir\n# log_request_ip send the ip to some external service\nspawn(fn -> log_request_ip(conn) end)\n```\n\nThis problem also occurs when accessing only the relevant parts:\n\n```elixir\nspawn(fn -> log_request_ip(conn.remote_ip) end)\n```\n\nThis will still copy over all of `conn`, because the `conn` variable is being captured inside the spawned function. The function then extracts the `remote_ip` field, but only after the whole `conn` has been copied over.\n\n`send/2` and the `GenServer` APIs also rely on message passing. In the example below, the `conn` is once again copied to the underlying `GenServer`:\n\n```elixir\nGenServer.cast(pid, {:report_ip_address, conn})\n```\n\n#### Refactoring\n\nThis anti-pattern has many potential remedies:\n\n  * Limit the data you send to the absolute necessary minimum instead of sending an entire struct. For example, don't send an entire `conn` struct if all you need is a couple of fields.\n\n  * If the only process that needs data is the one you are sending to, consider making the process fetch that data instead of passing it.\n\n  * Some abstractions, such as [`:persistent_term`](`:persistent_term`), allows you to share data between processes, as long as such data changes infrequently.\n\nIn our case, limiting the input data is a reasonable strategy. If all we need *right now* is the IP address, then let's only work with that and make sure we're only passing the IP address into the closure, like so:\n\n```elixir\nip_address = conn.remote_ip\nspawn(fn -> log_request_ip(ip_address) end)\n```\n\nOr in the `GenServer` case:\n\n```elixir\nGenServer.cast(pid, {:report_ip_address, conn.remote_ip})\n```\n\n## Unsupervised processes\n\n#### Problem\n\nIn Elixir, creating a process outside a supervision tree is not an anti-pattern in itself. However, when you spawn many long-running processes outside of supervision trees, this can make visibility and monitoring of these processes difficult, preventing developers from fully controlling their lifecycle.\n\n#### Example\n\nThe following code example seeks to illustrate a library responsible for maintaining a numerical `Counter` through a `Agent` process *outside a supervision tree*.\n\n```elixir\ndefmodule Counter do\n  @moduledoc \"\"\"\n  Global counter implemented as an Agent.\n  \"\"\"\n\n  use Agent\n\n  @doc \"Starts a counter process.\"\n  def start_link(opts \\\\ []) do\n    initial_state = Keyword.get(opts, :initial_value, 0)\n    name = Keyword.get(opts, :name, __MODULE__)\n    Agent.start_link(fn -> initial_state end, name: name)\n  end\n\n  @doc \"Gets the current value of the given counter.\"\n  def get(name \\\\ __MODULE__) do\n    Agent.get(name, fn state -> state end)\n  end\n\n  @doc \"Bumps the value of the given counter.\"\n  def bump(name \\\\ __MODULE__, value) do\n    Agent.get_and_update(fn state -> {state, value + state} end)\n  end\nend\n```\n\nWhile it is possible to start the process outside of a supervision tree:\n\n```elixir\niex> Counter.start_link()\n{:ok, #PID<0.115.0>}\niex> Counter.bump(13)\n0\niex> Counter.get()\n13\n```\n\nSuch processes are harder to observe and control their lifecycle. For example, if you have other processes that depend on the `Counter` above, you will need ad-hoc mechanisms to make sure they are initialized in order. Furthermore, when your application is shutting down, there is no guarantee when they are terminated.\n\n#### Refactoring\n\nTo ensure that clients of a library have full control over their systems, regardless of the number of processes used and the lifetime of each one, all processes must be started inside a supervision tree. As shown below, this code uses a `Supervisor` as a supervision tree.\n\n```elixir\ndefmodule SupervisedProcess.Application do\n  use Application\n\n  @impl true\n  def start(_type, _args) do\n    children = [\n      # With the default values for counter and name\n      Counter,\n      # With custom values for counter, name, and a custom ID\n      Supervisor.child_spec(\n        {Counter, name: :other_counter, initial_value: 15},\n        id: :other_counter\n      )\n    ]\n\n    Supervisor.start_link(children, strategy: :one_for_one, name: App.Supervisor)\n  end\nend\n```\n\nBesides having a deterministic order in which processes are started, supervision trees also guarantee they are terminated in reverse order, allowing you to perform any necessary clean up during shut down. Furthermore, supervision strategies allows us to configure exactly how process should act in case of unexpected failures.\n\nFinally, applications and supervision trees can be introspected through applications like the [Phoenix.LiveDashboard](https://github.com/phoenixframework/phoenix_live_dashboard) and [Erlang's built-in observer](https://www.erlang.org/doc/apps/observer/observer_ug):\n\n<img src=\"assets/kv-observer.png\" alt=\"Observer GUI screenshot\" />\n"
  },
  {
    "path": "lib/elixir/pages/anti-patterns/what-anti-patterns.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# What are anti-patterns?\n\nAnti-patterns describe common mistakes or indicators of problems in code.\nThey are also known as \"code smells\".\n\nThe goal of these guides is to document potential anti-patterns found in Elixir software\nand teach developers how to identify them and their pitfalls. If an existing piece\nof code matches an anti-pattern, it does not mean your code must be rewritten.\nSometimes, even if a snippet matches a potential anti-pattern and its limitations,\nit may be the best approach to the problem at hand. No codebase is free of anti-patterns\nand one should not aim to remove all of them.\n\nThe anti-patterns in these guides are broken into 4 main categories:\n\n  * **Code-related anti-patterns:** related to your code and particular\n    language idioms and features;\n\n  * **Design-related anti-patterns:** related to your modules, functions,\n    and the role they play within a codebase;\n\n  * **Process-related anti-patterns:** related to processes and process-based\n    abstractions;\n\n  * **Meta-programming anti-patterns:** related to meta-programming.\n\nEach anti-pattern is documented using the following structure:\n\n  * **Name:** Unique identifier of the anti-pattern. This name is important to facilitate\n    communication between developers;\n\n  * **Problem:** How the anti-pattern can harm code quality and what impacts this can have\n    for developers;\n\n  * **Example:** Code and textual descriptions to illustrate the occurrence of the anti-pattern;\n\n  * **Refactoring:** Ways to change your code to improve its qualities. Examples of refactored\n    code are presented to illustrate these changes.\n\nAn additional section with \"Additional Remarks\" may be provided. Those may include known scenarios where the anti-pattern does not apply.\n\nThe initial catalog of anti-patterns was proposed by Lucas Vegi and Marco Tulio Valente, from [ASERG/DCC/UFMG](http://aserg.labsoft.dcc.ufmg.br/). For more info, see [Understanding Code Smells in Elixir Functional Language](https://github.com/lucasvegi/Elixir-Code-Smells/blob/main/etc/2023-emse-code-smells-elixir.pdf) and [the associated code repository](https://github.com/lucasvegi/Elixir-Code-Smells).\n\nAdditionally, the Security Working Group of the [Erlang Ecosystem Foundation](https://security.erlef.org) publishes [documents with security resources and best-practices of both Erlang and Elixir, including detailed guides for web applications](https://security.erlef.org).\n"
  },
  {
    "path": "lib/elixir/pages/cheatsheets/enum-cheat.cheatmd",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Enum cheatsheet\n\nA quick reference into the `Enum` module, a module for working with collections (known as enumerables). Most of the examples below use the following data structure:\n\n```elixir\ncart = [\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\nSome examples use the [`string =~ part`](`=~/2`) operator, which checks the string on the left contains the part on the right.\n\n## Predicates\n{: .col-2}\n\n### [`any?(enum, fun)`](`Enum.any?/2`)\n\n```elixir\niex> Enum.any?(cart, & &1.fruit == \"orange\")\ntrue\niex> Enum.any?(cart, & &1.fruit == \"pear\")\nfalse\n```\n\n`any?` with an empty collection is always false:\n\n```elixir\niex> Enum.any?([], & &1.fruit == \"orange\")\nfalse\n```\n\n### [`all?(enum, fun)`](`Enum.all?/2`)\n\n```elixir\niex> Enum.all?(cart, & &1.count > 0)\ntrue\niex> Enum.all?(cart, & &1.count > 1)\nfalse\n```\n\n`all?` with an empty collection is always true:\n\n```elixir\niex> Enum.all?([], & &1.count > 0)\ntrue\n```\n\n### [`member?(enum, value)`](`Enum.member?/2`)\n\n```elixir\niex> Enum.member?(cart, %{fruit: \"apple\", count: 3})\ntrue\niex> Enum.member?(cart, :something_else)\nfalse\n```\n\n`item in enum` is equivalent to `Enum.member?(enum, item)`:\n\n```elixir\niex> %{fruit: \"apple\", count: 3} in cart\ntrue\niex> :something_else in cart\nfalse\n```\n\n### [`empty?(enum)`](`Enum.empty?/1`)\n\n```elixir\niex> Enum.empty?(cart)\nfalse\niex> Enum.empty?([])\ntrue\n```\n\n## Filtering\n{: .col-2}\n\n### [`filter(enum, fun)`](`Enum.filter/2`)\n\n```elixir\niex> Enum.filter(cart, &(&1.fruit =~ \"o\"))\n[%{fruit: \"orange\", count: 6}]\niex> Enum.filter(cart, &(&1.fruit =~ \"e\"))\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\n### [`reject(enum, fun)`](`Enum.reject/2`)\n\n```elixir\niex> Enum.reject(cart, &(&1.fruit =~ \"o\"))\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1}\n]\n```\n\n### [`flat_map(enum, fun)`](`Enum.flat_map/2`)\n\nThis function (also listed [below](#concatenating-flattening)) can\nbe used to transform and filter in one pass, returning empty lists\nto exclude results:\n\n```elixir\niex> Enum.flat_map(cart, fn item ->\n...>   if item.count > 1, do: [item.fruit], else: []\n...> end)\n[\"apple\", \"orange\"]\n```\n\n### [`Comprehension`](`for/1`)\n\nFiltering can also be done with comprehensions:\n\n```elixir\niex> for item <- cart, item.fruit =~ \"e\" do\n...>   item\n...> end\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\nPattern-matching in comprehensions acts as a filter as well:\n\n```elixir\niex> for %{count: 1, fruit: fruit} <- cart do\n...>   fruit\n...> end\n[\"banana\"]\n```\n\n## Mapping\n{: .col-2}\n\n### [`map(enum, fun)`](`Enum.map/2`)\n\n```elixir\niex> Enum.map(cart, & &1.fruit)\n[\"apple\", \"banana\", \"orange\"]\niex> Enum.map(cart, fn item ->\n...>   %{item | count: item.count + 10}\n...> end)\n[\n  %{fruit: \"apple\", count: 13},\n  %{fruit: \"banana\", count: 11},\n  %{fruit: \"orange\", count: 16}\n]\n```\n\n### [`map_every(enum, nth, fun)`](`Enum.map_every/3`)\n\n```elixir\niex> Enum.map_every(cart, 2, fn item ->\n...>   %{item | count: item.count + 10}\n...> end)\n[\n  %{fruit: \"apple\", count: 13},\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"orange\", count: 16}\n]\n```\n\n### [`Comprehension`](`for/1`)\n\nMapping can also be done with comprehensions:\n\n```elixir\niex> for item <- cart do\n...>   item.fruit\n...> end\n[\"apple\", \"banana\", \"orange\"]\n```\n\nYou can also filter and map at once:\n\n```elixir\niex> for item <- cart, item.fruit =~ \"e\" do\n...>   item.fruit\n...> end\n[\"apple\", \"orange\"]\n```\n\n## Side-effects\n{: .col-2}\n\n### [`each(enum, fun)`](`Enum.each/2`)\n\n```elixir\niex> Enum.each(cart, &IO.puts(&1.fruit))\napple\nbanana\norange\n:ok\n```\n\n`Enum.each/2` is used exclusively for side-effects.\n\n## Accumulating\n{: .col-2}\n\n### [`reduce(enum, acc, fun)`](`Enum.reduce/3`)\n\n```elixir\niex> Enum.reduce(cart, 0, fn item, acc ->\n...>   item.count + acc\n...> end)\n10\n```\n\n### [`map_reduce(enum, acc, fun)`](`Enum.map_reduce/3`)\n\n```elixir\niex> Enum.map_reduce(cart, 0, fn item, acc ->\n...>   {item.fruit, item.count + acc}\n...> end)\n{[\"apple\", \"banana\", \"orange\"], 10}\n```\n\n### [`scan(enum, acc, fun)`](`Enum.scan/3`)\n\n```elixir\niex> Enum.scan(cart, 0, fn item, acc ->\n...>   item.count + acc\n...> end)\n[3, 4, 10]\n```\n\n### [`reduce_while(enum, acc, fun)`](`Enum.reduce_while/3`)\n\n```elixir\niex> Enum.reduce_while(cart, 0, fn item, acc ->\n...>   if item.fruit == \"orange\" do\n...>     {:halt, acc}\n...>   else\n...>     {:cont, item.count + acc}\n...>   end\n...> end)\n4\n```\n\n### [`Comprehension`](`for/1`)\n\nReducing can also be done with comprehensions:\n\n```elixir\niex> for item <- cart, reduce: 0 do\n...>   acc -> item.count + acc\n...> end\n10\n```\n\nYou can also filter and reduce at once:\n\n```elixir\niex> for item <- cart, item.fruit =~ \"e\", reduce: 0 do\n...>   acc -> item.count + acc\n...> end\n9\n```\n\n## Aggregations\n{: .col-2}\n\n### [`count(enum)`](`Enum.count/1`)\n\n```elixir\niex> Enum.count(cart)\n3\n```\n\nSee `Enum.count_until/2` to count until a limit.\n\n### [`frequencies(enum)`](`Enum.frequencies/1`)\n\n```elixir\niex> Enum.frequencies([\"apple\", \"banana\", \"orange\", \"apple\"])\n%{\"apple\" => 2, \"banana\" => 1, \"orange\" => 1}\n```\n\n### [`frequencies_by(enum, key_fun)`](`Enum.frequencies_by/2`)\n\nFrequencies of the last letter of the fruit:\n\n```elixir\niex> Enum.frequencies_by(cart, &String.last(&1.fruit))\n%{\"a\" => 1, \"e\" => 2}\n```\n\n### [`count(enum, fun)`](`Enum.count/2`)\n\n```elixir\niex> Enum.count(cart, &(&1.fruit =~ \"e\"))\n2\niex> Enum.count(cart, &(&1.fruit =~ \"y\"))\n0\n```\n\nSee `Enum.count_until/3` to count until a limit with a function.\n\n### [`sum(enum)`](`Enum.sum/1`)\n\n```elixir\niex> cart |> Enum.map(& &1.count) |> Enum.sum()\n10\n```\n\nNote: this should typically be done in one pass using `Enum.sum_by/2`.\n\n### [`sum_by(enum, mapper)`](`Enum.sum_by/2`)\n\n```elixir\niex> Enum.sum_by(cart, & &1.count)\n10\n```\n\n### [`product(enum)`](`Enum.product/1`)\n\n```elixir\niex> cart |> Enum.map(& &1.count) |> Enum.product()\n18\n```\n\nNote: this should typically be done in one pass using `Enum.product_by/2`.\n\n### [`product_by(enum, mapper)`](`Enum.product_by/2`)\n\n```elixir\niex> Enum.product_by(cart, & &1.count)\n18\n```\n\n## Sorting\n{: .col-2}\n\n### [`sort(enum, sorter \\\\ :asc)`](`Enum.sort/2`)\n\n```elixir\niex> cart |> Enum.map(& &1.fruit) |> Enum.sort()\n[\"apple\", \"banana\", \"orange\"]\niex> cart |> Enum.map(& &1.fruit) |> Enum.sort(:desc)\n[\"orange\", \"banana\", \"apple\"]\n```\n\nWhen sorting structs, use `Enum.sort/2` with a module as sorter.\n\n### [`sort_by(enum, mapper, sorter \\\\ :asc)`](`Enum.sort_by/2`)\n\n```elixir\niex> Enum.sort_by(cart, & &1.count)\n[\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"orange\", count: 6}\n]\niex> Enum.sort_by(cart, & &1.count, :desc)\n[\n  %{fruit: \"orange\", count: 6},\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1}\n]\n```\n\nWhen the sorted by value is a struct, use `Enum.sort_by/3` with a module as sorter.\n\n### [`min(enum)`](`Enum.min/1`)\n\n```elixir\niex> cart |> Enum.map(& &1.count) |> Enum.min()\n1\n```\n\nWhen comparing structs, use `Enum.min/2` with a module as sorter.\n\n### [`min_by(enum, mapper)`](`Enum.min_by/2`)\n\n```elixir\niex> Enum.min_by(cart, & &1.count)\n%{fruit: \"banana\", count: 1}\n```\n\nWhen comparing structs, use `Enum.min_by/3` with a module as sorter.\n\n### [`max(enum)`](`Enum.max/1`)\n\n```elixir\niex> cart |> Enum.map(& &1.count) |> Enum.max()\n6\n```\n\nWhen comparing structs, use `Enum.max/2` with a module as sorter.\n\n### [`max_by(enum, mapper)`](`Enum.max_by/2`)\n\n```elixir\niex> Enum.max_by(cart, & &1.count)\n%{fruit: \"orange\", count: 6}\n```\n\nWhen comparing structs, use `Enum.max_by/3` with a module as sorter.\n\n## Concatenating & flattening\n{: .col-2}\n\n### [`concat(enums)`](`Enum.concat/1`)\n\n```elixir\niex> Enum.concat([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n[1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\n\n### [`concat(left, right)`](`Enum.concat/2`)\n\n```elixir\niex> Enum.concat([1, 2, 3], [4, 5, 6])\n[1, 2, 3, 4, 5, 6]\n```\n\n### [`flat_map(enum, fun)`](`Enum.flat_map/2`)\n\n```elixir\niex> Enum.flat_map(cart, fn item ->\n...>   List.duplicate(item.fruit, item.count)\n...> end)\n[\"apple\", \"apple\", \"apple\", \"banana\", \"orange\",\n \"orange\", \"orange\", \"orange\", \"orange\", \"orange\"]\n```\n\n### [`flat_map_reduce(enum, acc, fun)`](`Enum.flat_map_reduce/3`)\n\n```elixir\niex> Enum.flat_map_reduce(cart, 0, fn item, acc ->\n...>   list = List.duplicate(item.fruit, item.count)\n...>   acc = acc + item.count\n...>   {list, acc}\n...> end)\n{[\"apple\", \"apple\", \"apple\", \"banana\", \"orange\",\n  \"orange\", \"orange\", \"orange\", \"orange\", \"orange\"], 10}\n```\n\n### [`Comprehension`](`for/1`)\n\nFlattening can also be done with comprehensions:\n\n```elixir\niex> for item <- cart,\n...>     fruit <- List.duplicate(item.fruit, item.count) do\n...>   fruit\n...> end\n[\"apple\", \"apple\", \"apple\", \"banana\", \"orange\",\n \"orange\", \"orange\", \"orange\", \"orange\", \"orange\"]\n```\n\n## Conversion\n{: .col-2}\n\n### [`into(enum, collectable)`](`Enum.into/2`)\n\n```elixir\niex> pairs = [{\"apple\", 3}, {\"banana\", 1}, {\"orange\", 6}]\niex> Enum.into(pairs, %{})\n%{\"apple\" => 3, \"banana\" => 1, \"orange\" => 6}\n```\n\n### [`into(enum, collectable, transform)`](`Enum.into/3`)\n\n```elixir\niex> Enum.into(cart, %{}, fn item ->\n...>   {item.fruit, item.count}\n...> end)\n%{\"apple\" => 3, \"banana\" => 1, \"orange\" => 6}\n```\n\n### [`to_list(enum)`](`Enum.to_list/1`)\n\n```elixir\niex> Enum.to_list(1..5)\n[1, 2, 3, 4, 5]\n```\n\n### [`Comprehension`](`for/1`)\n\nConversion can also be done with comprehensions:\n\n```elixir\niex> for item <- cart, into: %{} do\n...>   {item.fruit, item.count}\n...> end\n%{\"apple\" => 3, \"banana\" => 1, \"orange\" => 6}\n```\n\n## Duplicates & uniques\n{: .col-2}\n\n### [`dedup(enum)`](`Enum.dedup/1`)\n\n`dedup` only removes contiguous duplicates:\n\n```elixir\niex> Enum.dedup([1, 2, 2, 3, 3, 3, 1, 2, 3])\n[1, 2, 3, 1, 2, 3]\n```\n\n### [`dedup_by(enum, fun)`](`Enum.dedup_by/2`)\n\nRemove contiguous entries given a property:\n\n```elixir\niex> Enum.dedup_by(cart, & &1.fruit =~ \"a\")\n[%{fruit: \"apple\", count: 3}]\niex> Enum.dedup_by(cart, & &1.count < 5)\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\n### [`uniq(enum)`](`Enum.uniq/1`)\n\n`uniq` applies to the whole collection:\n\n```elixir\niex> Enum.uniq([1, 2, 2, 3, 3, 3, 1, 2, 3])\n[1, 2, 3]\n```\n\nComprehensions also support the `uniq: true` option.\n\n### [`uniq_by(enum, fun)`](`Enum.uniq_by/2`)\n\nGet entries which are unique by the last letter of the fruit:\n\n```elixir\niex> Enum.uniq_by(cart, &String.last(&1.fruit))\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1}\n]\n```\n\n## Indexing\n{: .col-2}\n\n### [`at(enum, index, default \\\\ nil)`](`Enum.at/2`)\n\n```elixir\niex> Enum.at(cart, 0)\n%{fruit: \"apple\", count: 3}\niex> Enum.at(cart, 10)\nnil\niex> Enum.at(cart, 10, :none)\n:none\n```\n\nAccessing a list by index in a loop is discouraged.\n\n### [`fetch(enum, index)`](`Enum.fetch/2`)\n\n```elixir\niex> Enum.fetch(cart, 0)\n{:ok, %{fruit: \"apple\", count: 3}}\niex> Enum.fetch(cart, 10)\n:error\n```\n\n### [`fetch!(enum, index)`](`Enum.fetch!/2`)\n\n```elixir\niex> Enum.fetch!(cart, 0)\n%{fruit: \"apple\", count: 3}\niex> Enum.fetch!(cart, 10)\n** (Enum.OutOfBoundsError) out of bounds error\n```\n\n### [`with_index(enum)`](`Enum.with_index/1`)\n\n```elixir\niex> Enum.with_index(cart)\n[\n  {%{fruit: \"apple\", count: 3}, 0},\n  {%{fruit: \"banana\", count: 1}, 1},\n  {%{fruit: \"orange\", count: 6}, 2}\n]\n```\n\n### [`with_index(enum, fun)`](`Enum.with_index/2`)\n\n```elixir\niex> Enum.with_index(cart, fn item, index ->\n...>   {item.fruit, index}\n...> end)\n[\n  {\"apple\", 0},\n  {\"banana\", 1},\n  {\"orange\", 2}\n]\n```\n\n## Finding\n{: .col-2}\n\n### [`find(enum, default \\\\ nil, fun)`](`Enum.find/2`)\n\n```elixir\niex> Enum.find(cart, &(&1.fruit =~ \"o\"))\n%{fruit: \"orange\", count: 6}\niex> Enum.find(cart, &(&1.fruit =~ \"y\"))\nnil\niex> Enum.find(cart, :none, &(&1.fruit =~ \"y\"))\n:none\n```\n\n### [`find_index(enum, fun)`](`Enum.find_index/2`)\n\n```elixir\niex> Enum.find_index(cart, &(&1.fruit =~ \"o\"))\n2\niex> Enum.find_index(cart, &(&1.fruit =~ \"y\"))\nnil\n```\n\n### [`find_value(enum, default \\\\ nil, fun)`](`Enum.find_value/2`)\n\n```elixir\niex> Enum.find_value(cart, fn item ->\n...>   if item.count == 1, do: item.fruit, else: nil\n...> end)\n\"banana\"\niex> Enum.find_value(cart, :none, fn item ->\n...>   if item.count == 100, do: item.fruit, else: nil\n...> end)\n:none\n```\n\n## Grouping\n{: .col-2}\n\n### [`group_by(enum, key_fun)`](`Enum.group_by/2`)\n\nGroup by the last letter of the fruit:\n\n```elixir\niex> Enum.group_by(cart, &String.last(&1.fruit))\n%{\n  \"a\" => [%{fruit: \"banana\", count: 1}],\n  \"e\" => [\n    %{fruit: \"apple\", count: 3},\n    %{fruit: \"orange\", count: 6}\n  ]\n}\n```\n\n### [`group_by(enum, key_fun, value_fun)`](`Enum.group_by/3`)\n\nGroup by the last letter of the fruit with custom value:\n\n```elixir\niex> Enum.group_by(cart, &String.last(&1.fruit), & &1.fruit)\n%{\n  \"a\" => [\"banana\"],\n  \"e\" => [\"apple\", \"orange\"]\n}\n```\n\n## Joining & interspersing\n{: .col-2}\n\n### [`join(enum, joiner \\\\ \"\")`](`Enum.join/2`)\n\n```elixir\niex> Enum.join([\"apple\", \"banana\", \"orange\"], \", \")\n\"apple, banana, orange\"\n```\n\n### [`map_join(enum, joiner \\\\ \"\", mapper)`](`Enum.map_join/3`)\n\n```elixir\niex> Enum.map_join(cart, \", \", & &1.fruit)\n\"apple, banana, orange\"\n```\n\n### [`intersperse(enum, separator \\\\ \"\")`](`Enum.intersperse/2`)\n\n```elixir\niex> Enum.intersperse([\"apple\", \"banana\", \"orange\"], \", \")\n[\"apple\", \", \", \"banana\", \", \", \"orange\"]\n```\n\n### [`map_intersperse(enum, separator \\\\ \"\", mapper)`](`Enum.map_intersperse/3`)\n\n```elixir\niex> Enum.map_intersperse(cart, \", \", & &1.fruit)\n[\"apple\", \", \", \"banana\", \", \", \"orange\"]\n```\n\n## Slicing\n{: .col-2}\n\n### [`slice(enum, index_range)`](`Enum.slice/2`)\n\n```elixir\niex> Enum.slice(cart, 0..1)\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1}\n]\n```\n\nNegative ranges count from the back:\n\n```elixir\niex> Enum.slice(cart, -2..-1)\n[\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\n### [`slice(enum, start_index, amount)`](`Enum.slice/3`)\n\n```elixir\niex> Enum.slice(cart, 1, 2)\n[\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\n### [`slide(enum, range_or_single_index, insertion_index)`](`Enum.slide/3`)\n\n```elixir\nfruits = [\"apple\", \"banana\", \"grape\", \"orange\", \"pear\"]\niex> Enum.slide(fruits, 2, 0)\n[\"grape\", \"apple\", \"banana\", \"orange\", \"pear\"]\niex> Enum.slide(fruits, 2, 4)\n[\"apple\", \"banana\", \"orange\", \"pear\", \"grape\"]\niex> Enum.slide(fruits, 1..3, 0)\n[\"banana\", \"grape\", \"orange\", \"apple\", \"pear\"]\niex> Enum.slide(fruits, 1..3, 4)\n[\"apple\", \"pear\", \"banana\", \"grape\", \"orange\"]\n```\n\n## Reversing\n{: .col-2}\n\n### [`reverse(enum)`](`Enum.reverse/1`)\n\n```elixir\niex> Enum.reverse(cart)\n[\n  %{fruit: \"orange\", count: 6},\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"apple\", count: 3}\n]\n```\n\n### [`reverse(enum, tail)`](`Enum.reverse/2`)\n\n```elixir\niex> Enum.reverse(cart, [:this_will_be, :the_tail])\n[\n  %{fruit: \"orange\", count: 6},\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"apple\", count: 3},\n  :this_will_be,\n  :the_tail\n]\n```\n\n### [`reverse_slice(enum, start_index, count)`](`Enum.reverse_slice/3`)\n\n```elixir\niex> Enum.reverse_slice(cart, 1, 2)\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"orange\", count: 6},\n  %{fruit: \"banana\", count: 1}\n]\n```\n\n## Splitting\n{: .col-2}\n\n### [`split(enum, amount)`](`Enum.split/2`)\n\n```elixir\niex> Enum.split(cart, 1)\n{[%{fruit: \"apple\", count: 3}],\n [\n   %{fruit: \"banana\", count: 1},\n   %{fruit: \"orange\", count: 6}\n ]}\n```\n\nNegative indexes count from the back:\n\n```elixir\niex> Enum.split(cart, -1)\n{[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1}\n ],\n [%{fruit: \"orange\", count: 6}]}\n```\n\n### [`split_while(enum, fun)`](`Enum.split_while/2`)\n\nStops splitting as soon as it is false:\n\n```elixir\niex> Enum.split_while(cart, &(&1.fruit =~ \"e\"))\n{[%{fruit: \"apple\", count: 3}],\n [\n   %{fruit: \"banana\", count: 1},\n   %{fruit: \"orange\", count: 6}\n ]}\n```\n\n### [`split_with(enum, fun)`](`Enum.split_with/2`)\n\nSplits the whole collection:\n\n```elixir\niex> Enum.split_with(cart, &(&1.fruit =~ \"e\"))\n{[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"orange\", count: 6}\n ],\n [%{fruit: \"banana\", count: 1}]}\n```\n\n## Splitting (drop and take)\n{: .col-2}\n\n### [`drop(enum, amount)`](`Enum.drop/2`)\n\n```elixir\niex> Enum.drop(cart, 1)\n[\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\nNegative indexes count from the back:\n\n```elixir\niex> Enum.drop(cart, -1)\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1}\n]\n```\n\n### [`drop_every(enum, nth)`](`Enum.drop_every/2`)\n\n```elixir\niex> Enum.drop_every(cart, 2)\n[%{fruit: \"banana\", count: 1}]\n```\n\n### [`drop_while(enum, fun)`](`Enum.drop_while/2`)\n\n```elixir\niex> Enum.drop_while(cart, &(&1.fruit =~ \"e\"))\n[\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\n### [`take(enum, amount)`](`Enum.take/2`)\n\n```elixir\niex> Enum.take(cart, 1)\n[%{fruit: \"apple\", count: 3}]\n```\n\nNegative indexes count from the back:\n\n```elixir\niex> Enum.take(cart, -1)\n[%{fruit: \"orange\", count: 6}]\n```\n\n### [`take_every(enum, nth)`](`Enum.take_every/2`)\n\n```elixir\niex> Enum.take_every(cart, 2)\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\n### [`take_while(enum, fun)`](`Enum.take_while/2`)\n\n```elixir\niex> Enum.take_while(cart, &(&1.fruit =~ \"e\"))\n[%{fruit: \"apple\", count: 3}]\n```\n\n## Random\n{: .col-2}\n\n### [`random(enum)`](`Enum.random/1`)\n\nResults will vary on every call:\n\n```elixir\niex> Enum.random(cart)\n%{fruit: \"orange\", count: 6}\n```\n\n### [`take_random(enum, count)`](`Enum.take_random/2`)\n\nResults will vary on every call:\n\n```elixir\niex> Enum.take_random(cart, 2)\n[\n  %{fruit: \"orange\", count: 6},\n  %{fruit: \"apple\", count: 3}\n]\n```\n\n### [`shuffle(enum)`](`Enum.shuffle/1`)\n\nResults will vary on every call:\n\n```elixir\niex> Enum.shuffle(cart)\n[\n  %{fruit: \"orange\", count: 6},\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1}\n]\n```\n\n## Chunking\n{: .col-2}\n\n### [`chunk_by(enum, fun)`](`Enum.chunk_by/2`)\n\n```elixir\niex> Enum.chunk_by(cart, &String.length(&1.fruit))\n[\n  [%{fruit: \"apple\", count: 3}],\n  [\n    %{fruit: \"banana\", count: 1},\n    %{fruit: \"orange\", count: 6}\n  ]\n]\n```\n\n### [`chunk_every(enum, count)`](`Enum.chunk_every/2`)\n\n```elixir\niex> Enum.chunk_every(cart, 2)\n[\n  [\n    %{fruit: \"apple\", count: 3},\n    %{fruit: \"banana\", count: 1}\n  ],\n  [%{fruit: \"orange\", count: 6}]\n]\n```\n\n### [`chunk_every(enum, count, step, leftover \\\\ [])`](`Enum.chunk_every/2`)\n\n```elixir\niex> Enum.chunk_every(cart, 2, 2, [:elements, :to_complete])\n[\n  [\n    %{fruit: \"apple\", count: 3},\n    %{fruit: \"banana\", count: 1}\n  ],\n  [\n    %{fruit: \"orange\", count: 6},\n    :elements\n  ]\n]\niex> Enum.chunk_every(cart, 2, 1, :discard)\n[\n  [\n    %{fruit: \"apple\", count: 3},\n    %{fruit: \"banana\", count: 1}\n  ],\n  [\n    %{fruit: \"banana\", count: 1},\n    %{fruit: \"orange\", count: 6}\n  ]\n]\n```\n\nSee `Enum.chunk_while/4` for custom chunking.\n\n## Zipping\n{: .col-2}\n\n### [`zip(enum1, enum2)`](`Enum.zip/2`)\n\n```elixir\niex> fruits = [\"apple\", \"banana\", \"orange\"]\niex> counts = [3, 1, 6]\niex> Enum.zip(fruits, counts)\n[{\"apple\", 3}, {\"banana\", 1}, {\"orange\", 6}]\n```\n\nSee `Enum.zip/1` for zipping many collections at once.\n\n### [`zip_with(enum1, enum2, fun)`](`Enum.zip_with/2`)\n\n```elixir\niex> fruits = [\"apple\", \"banana\", \"orange\"]\niex> counts = [3, 1, 6]\niex> Enum.zip_with(fruits, counts, fn fruit, count ->\n...>   %{fruit: fruit, count: count}\n...> end)\n[\n  %{fruit: \"apple\", count: 3},\n  %{fruit: \"banana\", count: 1},\n  %{fruit: \"orange\", count: 6}\n]\n```\n\nSee `Enum.zip_with/2` for zipping many collections at once.\n\n### [`zip_reduce(left, right, acc, fun)`](`Enum.zip_reduce/4`)\n\n```elixir\niex> fruits = [\"apple\", \"banana\", \"orange\"]\niex> counts = [3, 1, 6]\niex> Enum.zip_reduce(fruits, counts, 0, fn fruit, count, acc ->\n...>   price = if fruit =~ \"e\", do: count * 2, else: count\n...>   acc + price\n...> end)\n19\n```\n\nSee `Enum.zip_reduce/3` for zipping many collections at once.\n\n### [`unzip(list)`](`Enum.unzip/1`)\n\n```elixir\niex> cart |> Enum.map(&{&1.fruit, &1.count}) |> Enum.unzip()\n{[\"apple\", \"banana\", \"orange\"], [3, 1, 6]}\n```\n"
  },
  {
    "path": "lib/elixir/pages/cheatsheets/types-cheat.cheatmd",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2025 The Elixir Team\n-->\n\n# Set-theoretic types cheatsheet\n\n## Set operators\n\n#### Union\n\n```elixir\ntype1 or type2\n```\n\n#### Intersection\n\n```elixir\ntype1 and type2\n```\n\n#### Difference\n\n```elixir\ntype1 and not type2\n```\n\n#### Negation\n\n```elixir\nnot type\n```\n\n## Data types\n\n### Broad types\n\n```elixir\nbitstring()\nbinary()\nempty_list()\ninteger()\nfloat()\npid()\nport()\nreference()\n```\n\n`binary()` is a subtype of `bitstring()`.\n\n### Atoms\n\n#### All atoms\n\n```elixir\natom()\n```\n\n#### Individual atoms\n\n```elixir\n:ok\n:error\nSomeModule\n```\n\n### Functions\n\n#### All functions\n\n```elixir\nfunction()\n```\n\n#### `n`-arity functions\n\n```elixir\n(-> :ok)\n(integer() -> boolean())\n(binary(), binary() -> binary())\n```\n\n#### Multiple clauses\n\n```elixir\n(integer() -> binary()) and (binary() -> atom())\n```\n\n### Maps\n\n#### All maps\n\n```elixir\nmap()\n```\n\n#### Empty map\n\n```elixir\nempty_map()\n```\n\n#### Maps with atom keys\n\n```elixir\n# Only has the keys name and age\n%{name: binary(), age: integer()}\n\n# Has the name key and age is optional\n%{name: binary(), age: if_set(integer())}\n\n# Has the keys name and age and may have other keys (open map)\n%{..., name: binary(), age: integer()}\n\n# Has the key name, may have other keys, but age is not set\n%{..., name: binary(), age: not_set()}\n```\n\n#### Maps with domain keys (domain keys are always treated as optional)\n\n```elixir\n# Has atom and binary keys\n%{atom() => binary(), binary() => binary()}\n\n# Has atom and binary keys and may have other keys (open map)\n%{..., atom() => binary(), binary() => binary()}\n```\n\n#### Maps with mixed keys\n\n```elixir\n# Has atom keys with binary values but a `:root` key of type integer\n%{atom() => binary(), root: integer()}\n\n# Has atom keys with binary values but a `:root` key of type integer, and may have other keys\n%{..., atom() => binary(), root: integer()}\n```\n\n#### Domain keys are `atom()`, `binary()`, `integer()`, `float()`, `fun()`, `list()`, `map()`, `pid()`, `port()`, `reference()`, `tuple()`\n\n### Non-empty lists\n\n#### Proper lists\n\n```elixir\nnon_empty_list(elem_type)\n```\n\n#### Improper lists (as long as `tail_type` does not include lists)\n\n```elixir\nnon_empty_list(elem_type, tail_type)\n```\n\n### Tuples\n\n#### All tuples\n\n```elixir\ntuple()\n```\n\n#### n-element tuples\n\n```elixir\n{:ok, binary()}\n{:error, binary(), term()}\n{pid(), reference()}\n```\n\n#### At least n-element tuples\n\n```elixir\n{binary(), binary(), ...}\n```\n\n## Additional types for convenience\n\n#### Common aliases\n\n```elixir\nboolean() = true or false\nnumber() = integer() or float()\n```\n\n#### List aliases\n\n```elixir\nlist() = empty_list() or non_empty_list(term())\nlist(a) = empty_list() or non_empty_list(a)\nlist(a, b) = empty_list() or non_empty_list(a, b)\n```"
  },
  {
    "path": "lib/elixir/pages/getting-started/alias-require-and-import.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# alias, require, import, and use\n\nIn order to facilitate software reuse, Elixir provides three directives (`alias`, `require`, and `import`) plus a macro called `use` summarized below:\n\n```elixir\n# Alias the module so it can be called as Bar instead of Foo.Bar\nalias Foo.Bar, as: Bar\n\n# Require the module in order to use its macros\nrequire Foo\n\n# Import functions from Foo so they can be called without the `Foo.` prefix\nimport Foo\n\n# Invokes the custom code defined in Foo as an extension point\nuse Foo\n```\n\nWe are going to explore them in detail now. Keep in mind the first three are called directives because they have *lexical scope*, while `use` is a common extension point that allows the used module to inject code.\n\n## alias\n\n`alias` allows you to set up aliases for any given module name.\n\nImagine a module uses a specialized list implemented in `Math.List`. The `alias` directive allows referring to `Math.List` just as `List` within the module definition:\n\n```elixir\ndefmodule Stats do\n  alias Math.List, as: List\n  # In the remaining module definition List expands to Math.List.\nend\n```\n\nThe original `List` can still be accessed within `Stats` by the fully-qualified name `Elixir.List`.\n\n> All modules defined in Elixir are defined inside the main `Elixir` namespace, such as `Elixir.String`. However, for convenience, you can omit \"Elixir.\" when referencing them.\n\nAliases are frequently used to define shortcuts. In fact, calling `alias` without an `:as` option sets the alias automatically to the last part of the module name, for example:\n\n```elixir\nalias Math.List\n```\n\nIs the same as:\n\n```elixir\nalias Math.List, as: List\n```\n\nNote that `alias` is *lexically scoped*, which allows you to set aliases inside specific functions:\n\n```elixir\ndefmodule Math do\n  def plus(a, b) do\n    alias Math.List\n    # ...\n  end\n\n  def minus(a, b) do\n    # ...\n  end\nend\n```\n\nIn the example above, since we are invoking `alias` inside the function `plus/2`, the alias will be valid only inside the function `plus/2`. `minus/2` won't be affected at all.\n\n## require\n\nElixir provides macros as a mechanism for meta-programming (writing code that generates code). Macros are expanded at compile time.\n\nPublic functions in modules are globally available, but in order to use macros, you need to opt-in by requiring the module they are defined in.\n\n```elixir\niex> Integer.is_odd(3)\n** (UndefinedFunctionError) function Integer.is_odd/1 is undefined or private. However, there is a macro with the same name and arity. Be sure to require Integer if you intend to invoke this macro\n    (elixir) Integer.is_odd(3)\niex> require Integer\nInteger\niex> Integer.is_odd(3)\ntrue\n```\n\nIn Elixir, `Integer.is_odd/1` is defined as a macro so that it can be used as a guard. This means that, in order to invoke `Integer.is_odd/1`, we need to first require the `Integer` module.\n\nNote that like the `alias` directive, `require` is also lexically scoped. We will talk more about macros in a later chapter.\n\n## import\n\nWe use `import` whenever we want to access functions or macros from other modules without using the fully-qualified name. Note we can only import public functions, as private functions are never accessible externally.\n\nFor example, if we want to use the `duplicate/2` function from the `List` module several times, we can import it:\n\n```elixir\niex> import List, only: [duplicate: 2]\nList\niex> duplicate(:ok, 3)\n[:ok, :ok, :ok]\n```\n\nWe imported only the function `duplicate` (with arity 2) from `List`. Although `:only` is optional, its usage is recommended in order to avoid importing all the functions of a given module inside the current scope. `:except` could also be given as an option in order to import everything in a module except a list of functions.\n\nNote that `import` is *lexically scoped* too. This means that we can import specific macros or functions inside function definitions:\n\n```elixir\ndefmodule Math do\n  def some_function do\n    import List, only: [duplicate: 2]\n    duplicate(:ok, 10)\n  end\nend\n```\n\nIn the example above, the imported `List.duplicate/2` is only visible within that specific function. `duplicate/2` won't be available in any other function in that module (or any other module for that matter).\n\nWhile `import`s can be useful for frameworks and libraries to build abstractions, developers should generally prefer `alias` to `import` on their own codebases, as aliases make the origin of the function being invoked clearer.\n\n## use\n\nThe `use` macro is frequently used as an extension point. This means that, when you `use` a module `FooBar`, you allow that module to inject *any* code in the current module, such as importing itself or other modules, defining new functions, setting a module state, etc.\n\nFor example, in order to write tests using the ExUnit framework, a developer should use the `ExUnit.Case` module:\n\n```elixir\ndefmodule AssertionTest do\n  use ExUnit.Case, async: true\n\n  test \"always pass\" do\n    assert true\n  end\nend\n```\n\nBehind the scenes, `use` requires the given module and then calls the `__using__/1` callback on it allowing the module to inject some code into the current context. Some modules (for example, the above `ExUnit.Case`, but also `Supervisor` and `GenServer`) use this mechanism to populate your module with some basic behaviour, which your module is intended to override or complete.\n\nGenerally speaking, the following module:\n\n```elixir\ndefmodule Example do\n  use Feature, option: :value\nend\n```\n\nis compiled into\n\n```elixir\ndefmodule Example do\n  require Feature\n  Feature.__using__(option: :value)\nend\n```\n\nSince `use` allows any code to run, we can't really know the side-effects of using a module without reading its documentation. Therefore use this function with care and only if strictly required. Don't use `use` where an `import` or `alias` would do.\n\n## Multi alias/import/require/use\n\nIt is possible to `alias`, `import`, `require`, or `use` multiple modules at once. This is particularly useful once we start nesting modules, which is very common when building Elixir applications. For example, imagine you have an application where all modules are nested under `MyApp`, you can alias the modules `MyApp.Foo`, `MyApp.Bar` and `MyApp.Baz` at once as follows:\n\n```elixir\nalias MyApp.{Foo, Bar, Baz}\n```\n\nWith this, we have finished our tour of Elixir modules.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/anonymous-functions.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Anonymous functions\n\nAnonymous functions allow us to store and pass executable code around as if it was an integer or a string. Let's learn more.\n\n## Identifying functions and documentation\n\nBefore we move on to discuss anonymous functions, let's talk about how Elixir identifies named functions – the functions defined in [modules](modules-and-functions.md).\n\nFunctions in Elixir are identified by both their name and their arity. The arity of a function describes the number of arguments that the function takes. From this point on we will use both the function name and its arity to describe functions throughout the documentation. `trunc/1` identifies the function which is named `trunc` and takes `1` argument, whereas `trunc/2` identifies a different (nonexistent) function with the same name but with an arity of `2`.\n\nWe can also use this syntax to access documentation. The Elixir shell defines the [`h`](`IEx.Helpers.h/1`) function, which you can use to access documentation for any function. For example, typing `h trunc/1` is going to print the documentation for the `trunc/1` function:\n\n```elixir\niex> h trunc/1\n                             def trunc(number)\n\nReturns the integer part of number.\n```\n\n`h trunc/1` works because it is defined in the `Kernel` module. All functions in the `Kernel` module are automatically imported into our namespace. Most often you will also include the module name when looking up the documentation for a given function:\n\n```elixir\niex> h Kernel.trunc/1\n                             def trunc(number)\n\nReturns the integer part of number.\n```\n\nYou can use the module+function identifiers to lookup documentation for anything, including operators (try `h Kernel.+/2`). Invoking [`h`](`IEx.Helpers.h/1`) without arguments displays the documentation for `IEx.Helpers`, which is where `h` and other functionalities are defined.\n\n## Defining anonymous functions\n\nAnonymous functions in Elixir are delimited by the keywords `fn` and `end`:\n\n```elixir\niex> add = fn a, b -> a + b end\n#Function<12.71889879/2 in :erl_eval.expr/5>\n```\n\nIn the example above, we defined an anonymous function that receives two arguments, `a` and `b`, and returns the result of `a + b`. The arguments are always on the left-hand side of `->` and the code to be executed on the right-hand side. The anonymous function is stored in the variable `add`. You can see it returns a value represented by `#Function<...>`. While its representation is opaque, the `:erl_eval.expr` bit tells us the function was defined in the shell (during evaluation).\n\nWe can invoke anonymous functions by passing arguments to it, using a dot (`.`) between the variable and the opening parenthesis:\n\n```elixir\niex> add.(1, 2)\n3\n```\n\nThe dot makes it clear when you are calling an anonymous function, stored in the variable `add`, opposed to a function named `add/2`. For example, if you have an anonymous function stored in the variable `is_atom`, there is no ambiguity between `is_atom.(:foo)` and `is_atom(:foo)`. If both used the same `is_atom(:foo)` syntax, the only way to know the actual behavior of `is_atom(:foo)` would be by scanning all code thus far for a possible definition of the `is_atom` variable. This scanning hurts maintainability as it requires developers to track additional context in their head when reading and writing code.\n\nAnonymous functions in Elixir are also identified by the number of arguments they receive. We can check if a value is a function using `is_function/1` and also check its arity by using `is_function/2`:\n\n```elixir\niex> is_function(add)\ntrue\n# check if add is a function that expects exactly 2 arguments\niex> is_function(add, 2)\ntrue\n# check if add is a function that expects exactly 1 argument\niex> is_function(add, 1)\nfalse\n```\n\n## Closures\n\nAnonymous functions can also access variables that are in scope when the function is defined. This is typically referred to as closures, as they close over their scope. Let's define a new anonymous function that uses the `add` anonymous function we have previously defined:\n\n```elixir\niex> double = fn a -> add.(a, a) end\n#Function<6.71889879/1 in :erl_eval.expr/5>\niex> double.(2)\n4\n```\n\nA variable assigned inside a function does not affect its surrounding environment:\n\n```elixir\niex> x = 42\n42\niex> (fn -> x = 0 end).()\n0\niex> x\n42\n```\n\n## Clauses and guards\n\nSimilar to `case/2`, we can pattern match on the arguments of anonymous functions as well as define multiple clauses and guards:\n\n```elixir\niex> f = fn\n...>   x, y when x > 0 -> x + y\n...>   x, y -> x * y\n...> end\n#Function<12.71889879/2 in :erl_eval.expr/5>\niex> f.(1, 3)\n4\niex> f.(-1, 3)\n-3\n```\n\nThe number of arguments in each anonymous function clause needs to be the same, otherwise an error is raised.\n\n```elixir\niex> f2 = fn\n...>   x, y when x > 0 -> x + y\n...>   x, y, z -> x * y + z\n...> end\n** (CompileError) iex:1: cannot mix clauses with different arities in anonymous functions\n```\n\n## The capture operator\n\nThroughout this guide, we have been using the notation `name/arity` to refer to functions. It happens that this notation can actually be used to capture an existing function into a data-type we can pass around, similar to how anonymous functions behave.\n\n```elixir\niex> fun = &is_atom/1\n&:erlang.is_atom/1\niex> is_function(fun)\ntrue\niex> fun.(:hello)\ntrue\niex> fun.(123)\nfalse\n```\n\nAs you can see, once a function is captured, we can pass it as argument or invoke it using the anonymous function notation. The returned value above also hints we can capture functions defined in modules:\n\n```elixir\niex> fun = &String.length/1\n&String.length/1\niex> fun.(\"hello\")\n5\n```\n\nSince operators are functions in Elixir, you can also capture operators:\n\n```elixir\niex> add = &+/2\n&:erlang.+/2\niex> add.(1, 2)\n3\n```\n\nThe capture syntax can also be used as a shortcut for creating functions that wrap existing functions. For example, imagine you want to create an anonymous function that checks if a given function has arity 2. You could write it as:\n\n```elixir\niex> is_arity_2 = fn fun -> is_function(fun, 2) end\n#Function<8.71889879/1 in :erl_eval.expr/5>\niex> is_arity_2.(add)\ntrue\n```\n\nBut using the capture syntax, you can write it as:\n\n```elixir\niex> is_arity_2 = &is_function(&1, 2)\n#Function<8.71889879/1 in :erl_eval.expr/5>\niex> is_arity_2.(add)\ntrue\n```\n\nThe `&1` represents the first argument passed into the function. Therefore both `is_arity_2` anonymous functions defined above are equivalent.\n\nOnce again, given operators are function calls, the capture syntax shorthand also works with operators, or even string interpolation:\n\n```elixir\niex> fun = &(&1 + 1)\n#Function<6.71889879/1 in :erl_eval.expr/5>\niex> fun.(1)\n2\n\niex> fun2 = &\"Good #{&1}\"\n#Function<6.127694169/1 in :erl_eval.expr/5>\niex> fun2.(\"morning\")\n\"Good morning\"\n```\n\n`&(&1 + 1)` above is exactly the same as `fn x -> x + 1 end`. You can read more about the capture operator `&` in [its documentation](`&/1`).\n\nNext let's revisit some of the data-types we learned in the past and dig deeper into how they work.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/basic-types.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Basic types\n\nIn this chapter we will learn more about Elixir basic types: integers, floats, booleans, atoms, and strings. Other data types, such as lists and tuples, will be explored in the next chapter.\n\n```elixir\niex> 1          # integer\niex> 0x1F       # integer\niex> 1.0        # float\niex> true       # boolean\niex> :atom      # atom / symbol\niex> \"elixir\"   # string\niex> [1, 2, 3]  # list\niex> {1, 2, 3}  # tuple\n```\n\n## Basic arithmetic\n\nOpen up `iex` and type the following expressions:\n\n```elixir\niex> 1 + 2\n3\niex> 5 * 5\n25\niex> 10 / 2\n5.0\n```\n\nNotice that `10 / 2` returned a float `5.0` instead of an integer `5`. This is expected. In Elixir, the operator [`/`](`//2`) always returns a float. If you want to do integer division or get the division remainder, you can invoke the [`div`](`div/2`) and [`rem`](`rem/2`) functions:\n\n```elixir\niex> div(10, 2)\n5\niex> div 10, 2\n5\niex> rem 10, 3\n1\n```\n\nNotice that Elixir allows you to drop the parentheses when invoking functions that expect one or more arguments. This feature gives a cleaner syntax when writing declarations and control-flow constructs. However, Elixir developers generally prefer to use parentheses.\n\nElixir also supports shortcut notations for entering binary, octal, and hexadecimal numbers:\n\n```elixir\niex> 0b1010\n10\niex> 0o777\n511\niex> 0x1F\n31\n```\n\nFloat numbers require a dot followed by at least one digit and also support `e` for scientific notation:\n\n```elixir\niex> 1.0\n1.0\niex> 1.0e-10\n1.0e-10\n```\n\nFloats in Elixir are 64-bit precision.\n\nYou can invoke the [`round`](`round/1`) function to get the closest integer to a given float, or the [`trunc`](`trunc/1`) function to get the integer part of a float.\n\n```elixir\niex> round(3.58)\n4\niex> trunc(3.58)\n3\n```\n\nFinally, we work with different data types, we will learn Elixir provides several predicate functions to check for the type of a value. For example, [`is_integer`](`is_integer/1`) can be used to check if a value is an integer or not:\n\n```elixir\niex> is_integer(1)\ntrue\niex> is_integer(2.0)\nfalse\n```\n\nYou can also use [`is_float`](`is_float/1`) or [`is_number`](`is_number/1`) to check, respectively, if an argument is a float, or either an integer or float.\n\n## Booleans and `nil`\n\nElixir supports `true` and `false` as booleans:\n\n```elixir\niex> true\ntrue\niex> true == false\nfalse\n```\n\nElixir also provides three boolean operators: [`or`](`or/2`), [`and`](`and/2`), and [`not`](`not/1`). These operators are strict in the sense that they expect something that evaluates to a boolean (`true` or `false`) as their first argument:\n\n```elixir\niex> true and true\ntrue\niex> false or is_boolean(true)\ntrue\n```\n\nProviding a non-boolean will raise an exception:\n\n```elixir\niex> 1 and true\n** (BadBooleanError) expected a boolean on left-side of \"and\", got: 1\n```\n\n`or` and `and` are short-circuit operators. They only execute the right side if the left side is not enough to determine the result:\n\n```elixir\niex> false and raise(\"This error will never be raised\")\nfalse\niex> true or raise(\"This error will never be raised\")\ntrue\n```\n\nElixir also provides the concept of `nil`, to indicate the absence of a value, and a set of logical operators that also manipulate `nil`: `||/2`, `&&/2`, and `!/1`. For these operators, `false` and `nil` are considered \"falsy\", all other values are considered \"truthy\":\n\n```elixir\n# or\niex> 1 || true\n1\niex> false || 11\n11\n\n# and\niex> nil && 13\nnil\niex> true && 17\n17\n\n# not\niex> !true\nfalse\niex> !1\nfalse\niex> !nil\ntrue\n```\n\nSimilarly, values like `0` and `\"\"`, which some other programming languages consider to be \"falsy\", are also \"truthy\" in Elixir.\n\nAs a rule of thumb, use `and`, `or` and `not` when you are expecting booleans. If any of the arguments are non-boolean, use `&&`, `||` and `!`.\n\n## Atoms\n\nAn atom is a constant whose value is its own name. Some other languages call these symbols. They are often useful to enumerate over distinct values, such as:\n\n```elixir\niex> :apple\n:apple\niex> :orange\n:orange\niex> :watermelon\n:watermelon\n```\n\nAtoms are equal if their names are equal.\n\n```elixir\niex> :apple == :apple\ntrue\niex> :apple == :orange\nfalse\n```\n\nOften they are used to express the state of an operation, by using values such as `:ok` and `:error`.\n\nThe booleans `true` and `false` are also atoms:\n\n```elixir\niex> true == :true\ntrue\niex> is_atom(false)\ntrue\niex> is_boolean(:false)\ntrue\n```\n\nElixir allows you to skip the leading `:` for the atoms `false`, `true` and `nil`.\n\n## Strings\n\nStrings in Elixir are delimited by double quotes, and they are encoded in UTF-8:\n\n```elixir\niex> \"hellö\"\n\"hellö\"\n```\n\n> Note: if you are running on Windows, there is a chance your terminal does not use UTF-8 by default. You can change the encoding of your current session by running `chcp 65001` before entering IEx.\n\nYou can concatenate two strings with the [`<>`](`<>/2`) operator:\n\n```elixir\niex> \"hello \" <> \"world!\"\n\"hello world!\"\n```\n\nElixir also supports string interpolation:\n\n```elixir\niex> string = \"world\"\niex> \"hello #{string}!\"\n\"hello world!\"\n```\n\nString concatenation requires both sides to be strings but interpolation supports any data type that may be converted to a string:\n\n```elixir\niex> number = 42\niex> \"i am #{number} years old!\"\n\"i am 42 years old!\"\n```\n\nStrings can have line breaks in them. You can introduce them using escape sequences:\n\n```elixir\niex> \"hello\n...> world\"\n\"hello\\nworld\"\niex> \"hello\\nworld\"\n\"hello\\nworld\"\n```\n\nYou can print a string using the [`IO.puts`](`IO.puts/1`) function from the `IO` module:\n\n```elixir\niex> IO.puts(\"hello\\nworld\")\nhello\nworld\n:ok\n```\n\nNotice that the [`IO.puts`](`IO.puts/1`) function returns the atom `:ok` after printing.\n\nStrings in Elixir are represented internally by contiguous sequences of bytes known as binaries:\n\n```elixir\niex> is_binary(\"hellö\")\ntrue\n```\n\nWe can also get the number of bytes in a string:\n\n```elixir\niex> byte_size(\"hellö\")\n6\n```\n\nNotice that the number of bytes in that string is 6, even though it has 5 graphemes. That's because the grapheme \"ö\" takes 2 bytes to be represented in UTF-8. We can get the actual length of the string, based on the number of graphemes, by using the [`String.length`](`String.length/1`) function:\n\n```elixir\niex> String.length(\"hellö\")\n5\n```\n\nThe `String` module contains a bunch of functions that operate on strings as defined in the Unicode standard:\n\n```elixir\niex> String.upcase(\"hellö\")\n\"HELLÖ\"\n```\n\n## Structural comparison\n\nElixir also provides [`==`](`==/2`), [`!=`](`!=/2`), [`<=`](`<=/2`), [`>=`](`>=/2`), [`<`](`</2`) and [`>`](`>/2`) as comparison operators. We can compare numbers:\n\n```elixir\niex> 1 == 1\ntrue\niex> 1 != 2\ntrue\niex> 1 < 2\ntrue\n```\n\nBut also atoms, strings, booleans, etc:\n\n```elixir\niex> \"foo\" == \"foo\"\ntrue\niex> \"foo\" == \"bar\"\nfalse\n```\n\nIntegers and floats compare the same if they have the same value:\n\n```elixir\niex> 1 == 1.0\ntrue\niex> 1 == 2.0\nfalse\n```\n\nHowever, you can use the strict comparison operator [`===`](`===/2`) and [`!==`](`!==/2`) if you want to distinguish between integers and floats:\n\n```elixir\niex> 1 === 1.0\nfalse\n```\n\nThe comparison operators in Elixir can compare across any data type. We say these operators perform _structural comparison_. For more information, you can read our documentation on [Structural vs Semantic comparisons](`Kernel#module-structural-comparison`).\n\nElixir also provides data-types for expressing collections, such as lists and tuples, which we learn next. When we talk about concurrency and fault-tolerance via processes, we will also discuss ports, pids, and references, but that will come on later chapters. Let's move forward.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/binaries-strings-and-charlists.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Binaries, strings, and charlists\n\nIn [\"Basic types\"](basic-types.md), we learned a bit about strings and we used the `is_binary/1` function for checks:\n\n```elixir\niex> string = \"hello\"\n\"hello\"\niex> is_binary(string)\ntrue\n```\n\nIn this chapter, we will gain clarity on what exactly binaries are and how they relate to strings. We will also learn about charlists, `~c\"like this\"`, which are often used for interoperability with Erlang.\n\nAlthough strings are one of the most common data types in computer languages, they are subtly complex and are often misunderstood. To understand strings in Elixir, let's first discuss [Unicode](https://en.wikipedia.org/wiki/Unicode) and character encodings, specifically the [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoding.\n\n## Unicode and Code Points\n\nIn order to facilitate meaningful communication between computers across multiple languages, a standard is required so that the ones and zeros on one machine mean the same thing when they are transmitted to another. The [Unicode Standard](https://unicode.org/standard/standard.html) acts as an official registry of virtually all the characters we know: this includes characters from classical and historical texts, emoji, and formatting and control characters as well.\n\nUnicode organizes all of the characters in its repertoire into code charts, and each character is given a unique numerical index. This numerical index is known as a [Code Point](https://en.wikipedia.org/wiki/Code_point).\n\nIn Elixir you can use a `?` in front of a character literal to reveal its code point:\n\n```elixir\niex> ?a\n97\niex> ?ł\n322\n```\n\nNote that most Unicode code charts will refer to a code point by its hexadecimal (hex) representation, e.g. `97` translates to `0061` in hex, and we can represent any Unicode character in an Elixir string by using the `\\uXXXX` notation and the hex representation of its code point number:\n\n```elixir\niex> \"\\u0061\" == \"a\"\ntrue\niex> 0x0061 = 97 = ?a\n97\n```\n\nThe hex representation will also help you look up information about a code point, e.g. [https://codepoints.net/U+0061](https://codepoints.net/U+0061) has a data sheet all about the lower case `a`, a.k.a. code point 97.\n\n## UTF-8 and Encodings\n\nNow that we understand what the Unicode standard is and what code points are, we can finally talk about encodings. Whereas the code point is **what** we store, an encoding deals with **how** we store it: encoding is an implementation. In other words, we need a mechanism to convert the code point numbers into bytes so they can be stored in memory, written to disk, etc.\n\nElixir uses UTF-8 to encode its strings, which means that code points are encoded as a series of 8-bit bytes. UTF-8 is a **variable width** character encoding that uses one to four bytes to store each code point. It is capable of encoding all valid Unicode code points. Let's see an example:\n\n```elixir\niex> string = \"héllo\"\n\"héllo\"\niex> String.length(string)\n5\niex> byte_size(string)\n6\n```\n\nAlthough the string above has 5 characters, it uses 6 bytes, as two bytes are used to represent the character `é`.\n\n> Note: if you are running on Windows, there is a chance your terminal does not use UTF-8 by default. You can change the encoding of your current session by running `chcp 65001` before entering `iex` (`iex.bat`).\n\nBesides defining characters, UTF-8 also provides a notion of graphemes. Graphemes may consist of multiple characters that are often perceived as one. For example, the [woman firefighter emoji](https://emojipedia.org/woman-firefighter/) is represented as the combination of three characters: the woman emoji (👩), a hidden zero-width joiner, and the fire engine emoji (🚒):\n\n```elixir\niex> String.codepoints(\"👩‍🚒\")\n[\"👩\", \"‍\", \"🚒\"]\niex> String.graphemes(\"👩‍🚒\")\n[\"👩‍🚒\"]\n```\n\nHowever, Elixir is smart enough to know they are seen as a single character, and therefore the length is still one:\n\n```elixir\niex> String.length(\"👩‍🚒\")\n1\n```\n\n> Note: if you can't see the emoji above in your terminal, you need to make sure your terminal supports emoji and that you are using a font that can render them.\n\nAlthough these rules may sound complicated, UTF-8 encoded documents are everywhere. This page itself is encoded in UTF-8. The encoding information is given to your browser which then knows how to render all of the bytes, characters, and graphemes accordingly.\n\nIf you want to see the exact bytes that a string would be stored in a file, a common trick is to concatenate the null byte `<<0>>` to it:\n\n```elixir\niex> \"hełło\" <> <<0>>\n<<104, 101, 197, 130, 197, 130, 111, 0>>\n```\n\nAlternatively, you can view a string's binary representation by using `IO.inspect/2`:\n\n```elixir\niex> IO.inspect(\"hełło\", binaries: :as_binaries)\n<<104, 101, 197, 130, 197, 130, 111>>\n```\n\nWe are getting a little bit ahead of ourselves. Let's talk about bitstrings to learn about what exactly the `<<>>` constructor means.\n\n## Bitstrings\n\nAlthough we have covered code points and UTF-8 encoding, we still need to go a bit deeper into how exactly we store the encoded bytes, and this is where we introduce the **bitstring**. A bitstring is a fundamental data type in Elixir, denoted with the [`<<>>`](`<<>>/1`) syntax. **A bitstring is a contiguous sequence of bits in memory.**\n\nBy default, 8 bits (i.e. 1 byte) is used to store each number in a bitstring, but you can manually specify the number of bits via a `::n` modifier to denote the size in `n` bits, or you can use the more verbose declaration `::size(n)`:\n\n```elixir\niex> <<42>> == <<42::8>>\ntrue\niex> <<3::4>>\n<<3::size(4)>>\n```\n\nFor example, the decimal number `3` when represented with 4 bits in base 2 would be `0011`, which is equivalent to the values `0`, `0`, `1`, `1`, each stored using 1 bit:\n\n```elixir\niex> <<0::1, 0::1, 1::1, 1::1>> == <<3::4>>\ntrue\n```\n\nAny value that exceeds what can be stored by the number of bits provisioned is truncated:\n\n```elixir\niex> <<1>> == <<257>>\ntrue\n```\n\nHere, 257 in base 2 would be represented as `100000001`, but since we have reserved only 8 bits for its representation (by default), the left-most bit is ignored and the value becomes truncated to `00000001`, or simply `1` in decimal.\n\nA complete reference for the bitstring constructor can be found in [`<<>>`](`<<>>/1`)'s documentation.\n\n## Binaries\n\n**A binary is a bitstring where the number of bits is divisible by 8.** That means that every binary is a bitstring, but not every bitstring is a binary. We can use the `is_bitstring/1` and `is_binary/1` functions to demonstrate this.\n\n```elixir\niex> is_bitstring(<<3::4>>)\ntrue\niex> is_binary(<<3::4>>)\nfalse\niex> is_bitstring(<<0, 255, 42>>)\ntrue\niex> is_binary(<<0, 255, 42>>)\ntrue\niex> is_binary(<<42::16>>)\ntrue\n```\n\nWe can pattern match on binaries / bitstrings:\n\n```elixir\niex> <<0, 1, x>> = <<0, 1, 2>>\n<<0, 1, 2>>\niex> x\n2\niex> <<0, 1, x>> = <<0, 1, 2, 3>>\n** (MatchError) no match of right hand side value: <<0, 1, 2, 3>>\n```\n\nNote that unless you explicitly use `::` modifiers, each entry in the binary pattern is expected to match a single byte (exactly 8 bits). If we want to match on a binary of unknown size, we can use the `binary` modifier at the end of the pattern:\n\n```elixir\niex> <<0, 1, x::binary>> = <<0, 1, 2, 3>>\n<<0, 1, 2, 3>>\niex> x\n<<2, 3>>\n```\n\nThere are a couple other modifiers that can be useful when doing pattern matches on binaries. The `binary-size(n)` modifier will match `n` bytes in a binary:\n\n```elixir\niex> <<head::binary-size(2), rest::binary>> = <<0, 1, 2, 3>>\n<<0, 1, 2, 3>>\niex> head\n<<0, 1>>\niex> rest\n<<2, 3>>\n```\n\n**A string is a UTF-8 encoded binary**, where the code point for each character is encoded using 1 to 4 bytes. Thus every string is a binary, but due to the UTF-8 standard encoding rules, not every binary is a valid string.\n\n```elixir\niex> is_binary(\"hello\")\ntrue\niex> is_binary(<<239, 191, 19>>)\ntrue\niex> String.valid?(<<239, 191, 19>>)\nfalse\n```\n\nThe string concatenation operator [`<>`](`<>/2`) is actually a binary concatenation operator:\n\n```elixir\niex> \"a\" <> \"ha\"\n\"aha\"\niex> <<0, 1>> <> <<2, 3>>\n<<0, 1, 2, 3>>\n```\n\nGiven that strings are binaries, we can also pattern match on strings:\n\n```elixir\niex> <<head, rest::binary>> = \"banana\"\n\"banana\"\niex> head == ?b\ntrue\niex> rest\n\"anana\"\n```\n\nHowever, remember that binary pattern matching works on *bytes*, so matching on the string like \"über\" with multibyte characters won't match on the *character*, it will match on the *first byte of that character*:\n\n```elixir\niex> \"ü\" <> <<0>>\n<<195, 188, 0>>\niex> <<x, rest::binary>> = \"über\"\n\"über\"\niex> x == ?ü\nfalse\niex> rest\n<<188, 98, 101, 114>>\n```\n\nAbove, `x` matched on only the first byte of the multibyte `ü` character.\n\nTherefore, when pattern matching on strings, it is important to use the `utf8` modifier:\n\n```elixir\niex> <<x::utf8, rest::binary>> = \"über\"\n\"über\"\niex> x == ?ü\ntrue\niex> rest\n\"ber\"\n```\n\n## Charlists\n\nOur tour of our bitstrings, binaries, and strings is nearly complete, but we have one more data type to explain: the charlist.\n\n**A charlist is a list of integers where all the integers are valid code points.** In practice, you will not come across them often, only in specific scenarios such as interfacing with older Erlang libraries that do not accept binaries as arguments.\n\n```elixir\niex> ~c\"hello\"\n~c\"hello\"\niex> [?h, ?e, ?l, ?l, ?o]\n~c\"hello\"\n```\n\nThe [`~c`](`Kernel.sigil_c/2`) sigil (we'll cover sigils later in the [\"Sigils\"](sigils.md) chapter) indicates the fact that we are dealing with a charlist and not a regular string.\n\nInstead of containing bytes, a charlist contains integer code points. However, the list is only printed as a sigil if all code points are within the ASCII range:\n\n```elixir\niex> ~c\"hełło\"\n[104, 101, 322, 322, 111]\niex> is_list(~c\"hełło\")\ntrue\n```\n\nThis is done to ease interoperability with Erlang, even though it may lead to some surprising behavior. For example, if you are storing a list of integers that happen to range between 0 and 127, by default IEx will interpret this as a charlist and it will display the corresponding ASCII characters.\n\n```elixir\niex> heartbeats_per_minute = [99, 97, 116]\n~c\"cat\"\n```\n\nYou can always force charlists to be printed in their list representation by calling the `inspect/2` function:\n\n```elixir\niex> inspect(heartbeats_per_minute, charlists: :as_list)\n\"[99, 97, 116]\"\n```\n\nFurthermore, you can convert a charlist to a string and back by using the `to_string/1` and `to_charlist/1`:\n\n```elixir\niex> to_charlist(\"hełło\")\n[104, 101, 322, 322, 111]\niex> to_string(~c\"hełło\")\n\"hełło\"\niex> to_string(:hello)\n\"hello\"\niex> to_string(1)\n\"1\"\n```\n\nThe functions above are polymorphic, in other words, they accept many shapes: not only do they convert charlists to strings (and vice-versa), they can also convert integers, atoms, and so on.\n\nString (binary) concatenation uses the [`<>`](`<>/2`) operator but charlists, being lists, use the list concatenation operator [`++`](`++/2`):\n\n```elixir\niex> ~c\"this \" <> ~c\"fails\"\n** (ArgumentError) expected binary argument in <> operator but got: ~c\"this \"\n    (elixir) lib/kernel.ex:1821: Kernel.wrap_concatenation/3\n    (elixir) lib/kernel.ex:1808: Kernel.extract_concatenations/2\n    (elixir) expanding macro: Kernel.<>/2\n    iex:1: (file)\niex> ~c\"this \" ++ ~c\"works\"\n~c\"this works\"\niex> \"he\" ++ \"llo\"\n** (ArgumentError) argument error\n    :erlang.++(\"he\", \"llo\")\niex> \"he\" <> \"llo\"\n\"hello\"\n```\n\nWith binaries, strings, and charlists out of the way, it is time to talk about key-value data structures.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/case-cond-and-if.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# case, cond, and if\n\nIn this chapter, we will learn about the [`case`](`case/2`), [`cond`](`cond/1`), and [`if`](`if/2`) control flow structures.\n\n## case\n\n[`case`](`case/2`) allows us to compare a value against many patterns until we find a matching one:\n\n```elixir\niex> case {1, 2, 3} do\n...>   {4, 5, 6} ->\n...>     \"This clause won't match\"\n...>   {1, x, 3} ->\n...>     \"This clause will match and bind x to 2 in this clause\"\n...>   _ ->\n...>     \"This clause would match any value\"\n...> end\n\"This clause will match and bind x to 2 in this clause\"\n```\n\nIf you want to pattern match against an existing variable, you need to use the [`^`](`^/1`) operator:\n\n```elixir\niex> x = 1\n1\niex> case 10 do\n...>   ^x -> \"Won't match\"\n...>   _ -> \"Will match\"\n...> end\n\"Will match\"\n```\n\nClauses also allow extra conditions to be specified via guards:\n\n```elixir\niex> case {1, 2, 3} do\n...>   {1, x, 3} when x > 0 ->\n...>     \"Will match\"\n...>   _ ->\n...>     \"Would match, if guard condition were not satisfied\"\n...> end\n\"Will match\"\n```\n\nThe first clause above will only match when `x` is positive.\n\nKeep in mind errors in guards do not leak but simply make the guard fail:\n\n```elixir\niex> hd(1)\n** (ArgumentError) argument error\niex> case 1 do\n...>   x when hd(x) -> \"Won't match\"\n...>   x -> \"Got #{x}\"\n...> end\n\"Got 1\"\n```\n\nIf none of the clauses match, an error is raised:\n\n```elixir\niex> case :ok do\n...>   :error -> \"Won't match\"\n...> end\n** (CaseClauseError) no case clause matching: :ok\n```\n\nThe documentation for the `Kernel` module lists all available guards in its sidebar. You can also consult the complete [Patterns and Guards](../references/patterns-and-guards.md#guards) reference for in-depth documentation.\n\n## if\n\n[`case`](`case/2`) builds on pattern matching and guards to destructure and match on certain conditions. However, patterns and guards are limited only to certain expressions which are optimized by the compiler. In many situations, you need to write conditions that go beyond what can be expressed with [`case`](`case/2`). For those, [`if`](`if/2`) is a useful alternative:\n\n```elixir\niex> if true do\n...>   \"This works!\"\n...> end\n\"This works!\"\niex> if false do\n...>   \"This will never be seen\"\n...> end\nnil\n```\n\nIf the condition given to [`if`](`if/2`) returns `false` or `nil`, the body given between `do`-`end` is not executed and instead it returns `nil`.\n\n[`if`](`if/2`) also supports `else` blocks:\n\n```elixir\niex> if nil do\n...>   \"This won't be seen\"\n...> else\n...>   \"This will\"\n...> end\n\"This will\"\n```\n\n### Expressions\n\nSome programming languages make a distinction about expressions (code that returns a value) and statements (code that returns no value). In Elixir, there are only expressions, no statements. Everything you write in Elixir language returns some value.\n\nThis property allows variables to be scoped to individual blocks of code such as [`if`](`if/2`), [`case`](`case/2`), where declarations or changes are only visible inside the block. A change can't leak to outer blocks, which makes code easier to follow and understand. For example:\n\n```elixir\niex> x = 1\n1\niex> if true do\n...>   x = x + 1\n...> end\n2\niex> x\n1\n```\n\nYou see the return value of the [`if`](`if/2`) expression as the resulting `2` here. To retain changes made within the [`if`](`if/2`) expression on the outer block you need to assign the returned value to a variable in the outer block.\n\n```elixir\niex> x = 1\n1\niex> x =\n...>   if true do\n...>     x + 1\n...>   else\n...>     x\n...>   end\n2\n```\n\nWith all expressions returning a value there's also no need for alternative constructs, such as ternary operators posing as an alternative to [`if`](`if/2`). Elixir does include an inline notation for [`if`](`if/2`) and, as we will [learn later](keywords-and-maps.md#do-blocks-and-keywords), it is a syntactic variation on `if`'s arguments.\n\n> #### `if` is a macro {: .info}\n>\n> An interesting note regarding [`if`](`if/2`) is that it is implemented as a macro in the language: it isn't a special language construct as it would be in many languages. You can check the documentation and its source for more information.\n\nIf you find yourself nesting several [`if`](`if/2`) blocks, you may want to consider using [`cond`](`cond/1`) instead. Let's check it out.\n\n## cond\n\nWe have used `case` to find a matching clause from many patterns. We have used `if` to check for a single condition. If you need to check across several conditions and find the first one that does not evaluate to `nil` or `false`, [`cond`](`cond/1`) is a useful construct:\n\n```elixir\niex> cond do\n...>   2 + 2 == 5 ->\n...>     \"This will not be true\"\n...>   2 * 2 == 3 ->\n...>     \"Nor this\"\n...>   1 + 1 == 2 ->\n...>     \"But this will\"\n...> end\n\"But this will\"\n```\n\nThis is equivalent to `else if` clauses in many imperative languages - although used less frequently in Elixir.\n\nIf all of the conditions return `nil` or `false`, an error (`CondClauseError`) is raised. For this reason, it may be necessary to add a final condition, equal to `true`, which will always match:\n\n```elixir\niex> cond do\n...>   2 + 2 == 5 ->\n...>     \"This is never true\"\n...>   2 * 2 == 3 ->\n...>     \"Nor this\"\n...>   true ->\n...>     \"This is always true (equivalent to else)\"\n...> end\n\"This is always true (equivalent to else)\"\n```\n\nSimilar to [`if`](`if/2`), [`cond`](`cond/1`) considers any value besides `nil` and `false` to be true:\n\n```elixir\niex> cond do\n...>   hd([1, 2, 3]) ->\n...>     \"1 is considered as true\"\n...> end\n\"1 is considered as true\"\n```\n\n## Summing up\n\nWe have concluded the introduction to the most fundamental control-flow constructs in Elixir. Generally speaking, Elixir developers prefer pattern matching and guards, using [`case`](`case/2`) and function definitions (which we will explore in future chapters), as they are succinct and precise. When your logic cannot be outlined within patterns and guards, you may consider [`if`](`if/2`), falling back to [`cond`](`cond/1`) when there are several conditions to check.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/comprehensions.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Comprehensions\n\nIn Elixir, it is common to loop over an `Enumerable`, often filtering out some results and mapping values into another list. Comprehensions are syntactic sugar for such constructs: they group those common tasks into the `for` special form.\n\nFor example, we can map a list of integers into their squared values:\n\n```elixir\niex> for n <- [1, 2, 3, 4], do: n * n\n[1, 4, 9, 16]\n```\n\nA comprehension is made of three parts: generators, filters, and collectables.\n\n## Generators and filters\n\nIn the expression above, `n <- [1, 2, 3, 4]` is the **generator**. It is literally generating values to be used in the comprehension. Any enumerable can be passed on the right-hand side of the generator expression:\n\n```elixir\niex> for n <- 1..4, do: n * n\n[1, 4, 9, 16]\n```\n\nGenerator expressions also support pattern matching on their left-hand side; all non-matching patterns are *ignored*. Imagine that, instead of a range, we have a keyword list where the key is the atom `:good` or `:bad` and we only want to compute the square of the `:good` values:\n\n```elixir\niex> values = [good: 1, good: 2, bad: 3, good: 4]\niex> for {:good, n} <- values, do: n * n\n[1, 4, 16]\n```\n\nAlternatively to pattern matching, filters can be used to select some particular elements. For example, we can select the multiples of 3 and discard all others:\n\n```elixir\niex> for n <- 0..5, rem(n, 3) == 0, do: n * n\n[0, 9]\n```\n\nComprehensions discard all elements for which the filter expression returns `false` or `nil`; all other values are selected.\n\nComprehensions generally provide a much more concise representation than using the equivalent functions from the `Enum` and `Stream` modules. Furthermore, comprehensions also allow multiple generators and filters to be given. Here is an example that receives a list of directories and gets the size of each file in those directories:\n\n```elixir\ndirs = [\"/home/mikey\", \"/home/james\"]\n\nfor dir <- dirs,\n    file <- File.ls!(dir),\n    path = Path.join(dir, file),\n    File.regular?(path) do\n  File.stat!(path).size\nend\n```\n\nMultiple generators can also be used to calculate the Cartesian product of two lists:\n\n```elixir\niex> for i <- [:a, :b, :c], j <- [1, 2], do:  {i, j}\n[a: 1, a: 2, b: 1, b: 2, c: 1, c: 2]\n```\n\nFinally, keep in mind that variable assignments inside the comprehension, be it in generators, filters or inside the block, are not reflected outside of the comprehension.\n\n## Bitstring generators\n\nBitstring generators are also supported and are very useful when you need to comprehend over bitstring streams. The example below receives a list of pixels from a binary with their respective red, green and blue values and converts them into tuples of three elements each:\n\n```elixir\niex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>\niex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}\n[{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]\n```\n\nA bitstring generator can be mixed with \"regular\" enumerable generators, and supports filters as well.\n\n## The `:into` option\n\nIn the examples above, all the comprehensions returned lists as their result. However, the result of a comprehension can be inserted into different data structures by passing the `:into` option to the comprehension.\n\nFor example, a bitstring generator can be used with the `:into` option in order to easily remove all spaces in a string:\n\n```elixir\niex> for <<c <- \" hello world \">>, c != ?\\s, into: \"\", do: <<c>>\n\"helloworld\"\n```\n\nSets, maps, and other dictionaries can also be given to the `:into` option. In general, `:into` accepts any structure that implements the `Collectable` protocol.\n\nA common use case of `:into` can be transforming values in a map:\n\n```elixir\niex> for {key, val} <- %{\"a\" => 1, \"b\" => 2}, into: %{}, do: {key, val * val}\n%{\"a\" => 1, \"b\" => 4}\n```\n\nLet's make another example using streams. Since the `IO` module provides streams (that are both `Enumerable`s and `Collectable`s), an echo terminal that echoes back the upcased version of whatever is typed can be implemented using comprehensions:\n\n```elixir\niex> stream = IO.stream(:stdio, :line)\niex> for line <- stream, into: stream do\n...>   String.upcase(line) <> \"\\n\"\n...> end\n```\n\nNow type any string into the terminal and you will see that the same value will be printed in upper-case. Unfortunately, this example also got your IEx shell stuck in the comprehension, so you will need to hit `Ctrl+C` twice to get out of it. :)\n\n## Other options\n\nComprehensions support other options, such as `:reduce` and `:uniq`. Here are additional resources to learn more about comprehensions:\n\n  * [`for` official reference in Elixir documentation](`for/1`)\n  * [Mitchell Hanberg's comprehensive guide to Elixir's comprehensions](https://www.mitchellhanberg.com/the-comprehensive-guide-to-elixirs-for-comprehension/)\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/debugging.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Debugging\n\nThere are a number of ways to debug code in Elixir. In this chapter we will cover some of the more common ways of doing so.\n\n## IO.inspect/2\n\nWhat makes `IO.inspect(item, opts \\\\ [])` really useful in debugging is that it returns the `item` argument passed to it without affecting the behavior of the original code. Let's see an example.\n\n```elixir\n(1..10)\n|> IO.inspect()\n|> Enum.map(fn x -> x * 2 end)\n|> IO.inspect()\n|> Enum.sum()\n|> IO.inspect()\n```\n\nPrints:\n\n```elixir\n1..10\n[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]\n110\n```\n\nAs you can see `IO.inspect/2` makes it possible to \"spy\" on values almost anywhere in your code without altering the result, making it very helpful inside of a pipeline like in the above case.\n\n`IO.inspect/2` also provides the ability to decorate the output with a `label` option. The label will be printed before the inspected `item`:\n\n```elixir\n[1, 2, 3]\n|> IO.inspect(label: \"before\")\n|> Enum.map(&(&1 * 2))\n|> IO.inspect(label: \"after\")\n|> Enum.sum\n```\n\nPrints:\n\n```elixir\nbefore: [1, 2, 3]\nafter: [2, 4, 6]\n```\n\nIt is also very common to use `IO.inspect/2` with `binding/0`, which returns all variable names and their values:\n\n```elixir\ndef some_function(a, b, c) do\n  IO.inspect(binding())\n  ...\nend\n```\n\nWhen `some_function/3` is invoked with `:foo`, `\"bar\"`, `:baz` it prints:\n\n```elixir\n[a: :foo, b: \"bar\", c: :baz]\n```\n\nSee `IO.inspect/2` and `Inspect.Opts` respectively to learn more about the function and read about all supported options.\n\n## dbg/2\n\nElixir v1.14 introduced `dbg/2`. `dbg` is similar to `IO.inspect/2` but specifically tailored for debugging. It prints the value passed to it and returns it (just like `IO.inspect/2`), but it also prints the code and location.\n\n```elixir\n# In my_file.exs\nfeature = %{name: :dbg, inspiration: \"Rust\"}\ndbg(feature)\ndbg(Map.put(feature, :in_version, \"1.14.0\"))\n```\n\nThe code above prints this:\n\n```text\n[my_file.exs:2: (file)]\nfeature #=> %{inspiration: \"Rust\", name: :dbg}\n[my_file.exs:3: (file)]\nMap.put(feature, :in_version, \"1.14.0\") #=> %{in_version: \"1.14.0\", inspiration: \"Rust\", name: :dbg}\n```\n\nWhen talking about `IO.inspect/2`, we mentioned its usefulness when placed between steps of `|>` pipelines. `dbg` does it better: it understands Elixir code, so it will print values at _every step of the pipeline_.\n\n```elixir\n# In dbg_pipes.exs\n__ENV__.file\n|> String.split(\"/\", trim: true)\n|> List.last()\n|> File.exists?()\n|> dbg()\n```\n\nThis code prints:\n\n```text\n[dbg_pipes.exs:5: (file)]\n__ENV__.file #=> \"/home/myuser/dbg_pipes.exs\"\n|> String.split(\"/\", trim: true) #=> [\"home\", \"myuser\", \"dbg_pipes.exs\"]\n|> List.last() #=> \"dbg_pipes.exs\"\n|> File.exists?() #=> true\n```\n\nWhile `dbg` provides conveniences around Elixir constructs, you will need `IEx` if you want to execute code and set breakpoints while debugging.\n\n## Pry\n\nWhen using `IEx`, you may pass `--dbg pry` as an option to \"stop\" the code execution where the `dbg` call is:\n\n```console\n$ iex --dbg pry\n```\n\nOr to debug inside of a project:\n\n```console\n$ iex --dbg pry -S mix\n```\n\nNow any call to `dbg` will ask if you want to pry the existing code. If you accept, you'll be able to access all variables, as well as imports and aliases from the code, directly from IEx. This is called \"prying\". While the pry session is running, the code execution stops, until `continue` (or `c`) or `next` (or `n`) are called. Remember you can always run `iex` in the context of a project with `iex -S mix TASK`.\n\n<script id=\"asciicast-509509\" src=\"https://asciinema.org/a/509509.js\" async></script><noscript><p><a href=\"https://asciinema.org/a/509509\">See the example in asciinema</a></p></noscript>\n\n## Breakpoints\n\n`dbg` calls require us to change the code we intend to debug and has limited stepping functionality. Luckily IEx also provides a `IEx.break!/2` function which allows you to set and manage breakpoints on any Elixir code without modifying its source:\n\n<script type=\"text/javascript\" src=\"https://asciinema.org/a/0h3po0AmTcBAorc5GBNU97nrs.js\" id=\"asciicast-0h3po0AmTcBAorc5GBNU97nrs\" async></script><noscript><p><a href=\"https://asciinema.org/a/0h3po0AmTcBAorc5GBNU97nrs\">See the example in asciinema</a></p></noscript>\n\nSimilar to `dbg`, once a breakpoint is reached, code execution stops until `continue` (or `c`) or `next` (or `n`) are invoked. Breakpoints can navigate line-by-line by default, however, they do not have access to aliases and imports when breakpoints are set on compiled modules.\n\nThe `mix test` task direct integration with breakpoints via the `-b`/`--breakpoints` flag. When the flag is used, a breakpoint is set at the beginning of every test that will run:\n\n<script async id=\"asciicast-XTZ15jFKFAlr8ZxIZMzaHgL5n\" src=\"https://asciinema.org/a/XTZ15jFKFAlr8ZxIZMzaHgL5n.js\"></script><noscript><p><a href=\"https://asciinema.org/a/XTZ15jFKFAlr8ZxIZMzaHgL5n\">See the example in asciinema</a></p></noscript>\n\nHere are some commands you can use in practice:\n\n```console\n# Debug all failed tests\n$ iex -S mix test --breakpoints --failed\n# Debug the test at the given file:line\n$ iex -S mix test -b path/to/file:line\n```\n\n## Observer\n\nFor debugging complex systems, jumping at the code is not enough. It is necessary to have an understanding of the whole virtual machine, processes, applications, as well as set up tracing mechanisms. Luckily this can be achieved in Erlang with `:observer`. In your application:\n\n```elixir\n$ iex\niex> :observer.start()\n```\n\n> #### Missing dependencies {: .warning}\n>\n> When running `iex` inside a project with `iex -S mix`, `observer` won't be available as a dependency. To do so, you will need to call the following functions before:\n>\n> ```elixir\n> iex> Mix.ensure_application!(:observer)\n> iex> :observer.start()\n> ```\n>\n> If any of the calls above fail, here is what may have happened: some package managers default to installing a minimized Erlang without WX bindings for GUI support. In some package managers, you may be able to replace the headless Erlang with a more complete package (look for packages named `erlang` vs `erlang-nox` on Debian/Ubuntu/Arch). In others managers, you may need to install a separate `erlang-wx` (or similarly named) package.\n\nThe above will open another Graphical User Interface that provides many panes to fully understand and navigate the runtime and your project.\n\nWe explore the Observer in the context of an actual project [in the Dynamic Supervisor chapter of the Mix & OTP guide](../mix-and-otp/dynamic-supervisor.md). This is one of the debugging techniques [the Phoenix framework used to achieve 2 million connections on a single machine](https://phoenixframework.org/blog/the-road-to-2-million-websocket-connections).\n\nIf you are using the Phoenix web framework, it ships with the [Phoenix LiveDashboard](https://github.com/phoenixframework/phoenix_live_dashboard), a web dashboard for production nodes which provides similar features to Observer.\n\nFinally, remember you can also get a mini-overview of the runtime info by calling `runtime_info/0` directly in IEx.\n\n## Other tools and community\n\nWe have just scratched the surface of what the Erlang VM has to offer, for example:\n\n  * Alongside the observer application, Erlang also includes a [`:crashdump_viewer`](`:crashdump_viewer`) to view crash dumps\n\n  * Integration with OS level tracers, such as [Linux Trace Toolkit](https://www.erlang.org/doc/apps/runtime_tools/lttng), [DTRACE](https://www.erlang.org/doc/apps/runtime_tools/dtrace), and [SystemTap](https://www.erlang.org/doc/apps/runtime_tools/systemtap)\n\n  * [Microstate accounting](`:msacc`) measures how much time the runtime spends in several low-level tasks in a short time interval\n\n  * Mix ships with many tasks under the `profile` namespace, such as `mix profile.cprof` and `mix profile.fprof`\n\n  * For more advanced use cases, we recommend the excellent [Erlang in Anger](https://www.erlang-in-anger.com/), which is available as a free ebook\n\nHappy debugging!\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/enumerable-and-streams.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Enumerables and Streams\n\nWhile Elixir allows us to write recursive code, most operations we perform on collections is done with the help of the `Enum` and `Stream` modules. Let's learn how.\n\n## Enumerables\n\nElixir provides the concept of enumerables and the `Enum` module to work with them. We have already learned two enumerables: lists and maps.\n\n```elixir\niex> Enum.map([1, 2, 3], fn x -> x * 2 end)\n[2, 4, 6]\niex> Enum.map(%{1 => 2, 3 => 4}, fn {k, v} -> k * v end)\n[2, 12]\n```\n\nThe `Enum` module provides a huge range of functions to transform, sort, group, filter and retrieve items from enumerables. It is one of the modules developers use frequently in their Elixir code. For a general overview of all functions in the `Enum` module, see [the `Enum` cheatsheet](enum-cheat.cheatmd).\n\nElixir also provides ranges (see `Range`), which are also enumerable:\n\n```elixir\niex> Enum.map(1..3, fn x -> x * 2 end)\n[2, 4, 6]\niex> Enum.reduce(1..3, 0, &+/2)\n6\n```\n\nThe functions in the `Enum` module are limited to, as the name says, enumerating values in data structures. For specific operations, like inserting and updating particular elements, you may need to reach for modules specific to the data type. For example, if you want to insert an element at a given position in a list, you should use the `List.insert_at/3` function, as it would make little sense to insert a value into, for example, a range.\n\nWe say the functions in the `Enum` module are polymorphic because they can work with diverse data types. In particular, the functions in the `Enum` module can work with any data type that implements the `Enumerable` protocol. We are going to discuss Protocols in a later chapter, for now we are going to move on to a specific kind of enumerable called a stream.\n\n## Eager vs Lazy\n\nAll the functions in the `Enum` module are eager. Many functions expect an enumerable and return a list back:\n\n```elixir\niex> odd? = fn x -> rem(x, 2) != 0 end\n#Function<6.80484245/1 in :erl_eval.expr/5>\niex> Enum.filter(1..3, odd?)\n[1, 3]\n```\n\nThis means that when performing multiple operations with `Enum`, each operation is going to generate an intermediate list until we reach the result:\n\n```elixir\niex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum()\n7500000000\n```\n\nThe example above has a pipeline of operations. We start with a range and then multiply each element in the range by 3. This first operation will now create and return a list with `100_000` items. Then we keep all odd elements from the list, generating a new list, now with `50_000` items, and then we sum all entries.\n\n## The pipe operator\n\nThe `|>` symbol used in the snippet above is the **pipe operator**: it takes the output from the expression on its left side and passes it as the first argument to the function call on its right side. Its purpose is to highlight the data being transformed by a series of functions. To see how it can make the code cleaner, have a look at the example above rewritten without using the `|>` operator:\n\n```elixir\niex> Enum.sum(Enum.filter(Enum.map(1..100_000, &(&1 * 3)), odd?))\n7500000000\n```\n\nFind more about the pipe operator [by reading its documentation](`|>/2`).\n\n## Streams\n\nAs an alternative to `Enum`, Elixir provides the `Stream` module which supports lazy operations:\n\n```elixir\niex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum()\n7500000000\n```\n\nStreams are lazy, composable enumerables.\n\nIn the example above, `1..100_000 |> Stream.map(&(&1 * 3))` returns a data type, an actual stream, that represents the `map` computation over the range `1..100_000`:\n\n```elixir\niex> 1..100_000 |> Stream.map(&(&1 * 3))\n#Stream<[enum: 1..100000, funs: [#Function<34.16982430/1 in Stream.map/2>]]>\n```\n\nFurthermore, they are composable because we can pipe many stream operations:\n\n```elixir\niex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)\n#Stream<[enum: 1..100000, funs: [...]]>\n```\n\nInstead of generating intermediate lists, streams build a series of computations that are invoked only when we pass the underlying stream to the `Enum` module. Streams are useful when working with large, *possibly infinite*, collections.\n\nMany functions in the `Stream` module accept any enumerable as an argument and return a stream as a result. It also provides functions for creating streams. For example, `Stream.cycle/1` can be used to create a stream that cycles a given enumerable infinitely. Be careful to not call a function like `Enum.map/2` on such streams, as they would cycle forever:\n\n```elixir\niex> stream = Stream.cycle([1, 2, 3])\n#Function<15.16982430/2 in Stream.unfold/2>\niex> Enum.take(stream, 10)\n[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]\n```\n\nAnother interesting function is `Stream.resource/3` which can be used to wrap around resources, guaranteeing they are opened right before enumeration and closed afterwards, even in the case of failures. For example, `File.stream!/1` builds on top of `Stream.resource/3` to stream files:\n\n```elixir\niex> \"path/to/file\" |> File.stream!() |> Enum.take(10)\n```\n\nThe example above will fetch the first 10 lines of the file you have selected. This means streams can be very useful for handling large files or even slow resources like network resources.\n\nThe `Enum` and `Stream` modules provide a wide range of functions, but you don't have to know all of them by heart. Familiarize yourself with `Enum.map/2`, `Enum.reduce/3` and other functions with either `map` or `reduce` in their names, and you will naturally build an intuition around the most important use cases. You may also focus on the `Enum` module first and only move to `Stream` for the particular scenarios where laziness is required, to either deal with slow resources or large, possibly infinite, collections.\n\nNext, we'll look at a feature central to Elixir, Processes, which allows us to write concurrent, parallel and distributed programs in an easy and understandable way.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/erlang-libraries.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Erlang libraries\n\nElixir provides excellent interoperability with Erlang libraries. In fact, Elixir discourages simply wrapping Erlang libraries in favor of directly interfacing with Erlang code. In this section, we will present some of the most common and useful Erlang functionality that is not found in Elixir.\n\nErlang modules have a different naming convention than in Elixir and start in lowercase. In both cases, module names are atoms and we invoke functions by dispatching to the module name:\n\n```elixir\niex> is_atom(String)\ntrue\niex> String.first(\"hello\")\n\"h\"\niex> is_atom(:binary)\ntrue\niex> :binary.first(\"hello\")\n104\n```\n\nAs you grow more proficient in Elixir, you may want to explore the Erlang [STDLIB Reference Manual](https://www.erlang.org/doc/apps/stdlib/index.html) in more detail.\n\n## The binary module\n\nThe built-in Elixir String module handles binaries that are UTF-8 encoded. [The `:binary` module](`:binary`) is useful when you are dealing with binary data that is not necessarily UTF-8 encoded.\n\n```elixir\niex> String.to_charlist(\"Ø\")\n[216]\niex> :binary.bin_to_list(\"Ø\")\n[195, 152]\n```\n\nThe above example shows the difference; the `String` module returns Unicode codepoints, while `:binary` deals with raw data bytes.\n\n## Formatted text output\n\nElixir does not contain a function similar to `printf` found in C and other languages. Luckily, the Erlang standard library functions `:io.format/2` and `:io_lib.format/2` may be used. The first formats to terminal output, while the second formats to an iolist. The format specifiers differ from `printf`, [refer to the Erlang documentation for details](`:io.format/2`).\n\n```elixir\niex> :io.format(\"Pi is approximately given by:~10.3f~n\", [:math.pi])\nPi is approximately given by:     3.142\n:ok\niex> to_string(:io_lib.format(\"Pi is approximately given by:~10.3f~n\", [:math.pi]))\n\"Pi is approximately given by:     3.142\\n\"\n```\n\n## The crypto module\n\n[The `:crypto` module](`:crypto`) contains hashing functions, digital signatures, encryption and more:\n\n```elixir\niex> Base.encode16(:crypto.hash(:sha256, \"Elixir\"))\n\"3315715A7A3AD57428298676C5AE465DADA38D951BDFAC9348A8A31E9C7401CB\"\n```\n\nThe `:crypto` module is part of the `:crypto` application that ships with Erlang. This means you must list the `:crypto` application as an additional application in your project configuration. To do this, edit your `mix.exs` file to include:\n\n```elixir\ndef application do\n  [extra_applications: [:crypto]]\nend\n```\n\nAny module that is not part of the `:kernel` or `:stdlib` Erlang applications must have their application explicitly listed in your `mix.exs`. You can find the application name of any Erlang module in the Erlang documentation, immediately below the Erlang logo in the sidebar.\n\n## The digraph module\n\nThe [`:digraph`](`:digraph`) and [`:digraph_utils`](`:digraph_utils`) modules contain functions for dealing with directed graphs built of vertices and edges. After constructing the graph, the algorithms in there will help find, for instance, the shortest path between two vertices, or loops in the graph.\n\nGiven three vertices, find the shortest path from the first to the last.\n\n```elixir\niex> digraph = :digraph.new()\niex> coords = [{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}]\niex> [v0, v1, v2] = (for c <- coords, do: :digraph.add_vertex(digraph, c))\niex> :digraph.add_edge(digraph, v0, v1)\niex> :digraph.add_edge(digraph, v1, v2)\niex> :digraph.get_short_path(digraph, v0, v2)\n[{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}]\n```\n\nNote that the functions in `:digraph` alter the graph structure in-place, this\nis possible because they are implemented as ETS tables, explained next.\n\n## Erlang Term Storage (ETS)\n\nThe modules [`:ets`](`:ets`) and [`:dets`](`:dets`) handle storage of large data structures in memory or on disk respectively.\n\nETS lets you create a table containing tuples. By default, ETS tables are protected, which means only the owner process may write to the table but any other process can read. ETS has some functionality to allow a table to be used as a simple database, a key-value store or as a cache mechanism.\n\nThe functions in the `ets` module will modify the state of the table as a side-effect.\n\n```elixir\niex> table = :ets.new(:ets_test, [])\n# Store as tuples with {name, population}\niex> :ets.insert(table, {\"China\", 1_374_000_000})\niex> :ets.insert(table, {\"India\", 1_284_000_000})\niex> :ets.insert(table, {\"USA\", 322_000_000})\niex> :ets.i(table)\n<1   > {<<\"India\">>,1284000000}\n<2   > {<<\"USA\">>,322000000}\n<3   > {<<\"China\">>,1374000000}\n```\n\n## The math module\n\nThe [`:math`](`:math`) module contains common mathematical operations covering trigonometry, exponential, and logarithmic functions.\n\n```elixir\niex> angle_45_deg = :math.pi() * 45.0 / 180.0\niex> :math.sin(angle_45_deg)\n0.7071067811865475\niex> :math.exp(55.0)\n7.694785265142018e23\niex> :math.log(7.694785265142018e23)\n55.0\n```\n\n## The queue module\n\nThe [`:queue`](`:queue`) module provides a data structure that implements (double-ended) FIFO (first-in first-out) queues efficiently:\n\n```elixir\niex> q = :queue.new\niex> q = :queue.in(\"A\", q)\niex> q = :queue.in(\"B\", q)\niex> {value, q} = :queue.out(q)\niex> value\n{:value, \"A\"}\niex> {value, q} = :queue.out(q)\niex> value\n{:value, \"B\"}\niex> {value, q} = :queue.out(q)\niex> value\n:empty\n```\n\n## The rand module\n\nThe [`:rand`](`:rand`) has functions for returning random values and setting the random seed.\n\n```elixir\niex> :rand.uniform()\n0.8175669086010815\niex> _ = :rand.seed(:exs1024, {123, 123_534, 345_345})\niex> :rand.uniform()\n0.5820506340260994\niex> :rand.uniform(6)\n6\n```\n\n## The zip and zlib modules\n\nThe [`:zip`](`:zip`) module lets you read and write ZIP files to and from disk or memory, as well as extracting file information.\n\nThis code counts the number of files in a ZIP file:\n\n```elixir\niex> :zip.foldl(fn _, _, _, acc -> acc + 1 end, 0, :binary.bin_to_list(\"file.zip\"))\n{:ok, 633}\n```\n\nThe [`:zlib`](`:zlib`) module deals with data compression in zlib format, as found in the `gzip` command line utility found in Unix systems.\n\n```elixir\niex> song = \"\n...> Mary had a little lamb,\n...> His fleece was white as snow,\n...> And everywhere that Mary went,\n...> The lamb was sure to go.\"\niex> compressed = :zlib.compress(song)\niex> byte_size(song)\n110\niex> byte_size(compressed)\n99\niex> :zlib.uncompress(compressed)\n\"\\nMary had a little lamb,\\nHis fleece was white as snow,\\nAnd everywhere that Mary went,\\nThe lamb was sure to go.\"\n```\n\n## Learning Erlang\n\nIf you want to get deeper into Erlang, here's a list of online resources that cover Erlang's fundamentals and its more advanced features:\n\n  * This [Erlang Syntax: A Crash Course](https://elixir-lang.org/crash-course.html) provides a concise intro to Erlang's syntax. Each code snippet is accompanied by equivalent code in Elixir. This is an opportunity for you to not only get some exposure to Erlang's syntax but also review what you learned about Elixir.\n\n  * Erlang's official website has a short [tutorial](https://www.erlang.org/course). There is a chapter with pictures briefly describing Erlang's primitives for [concurrent programming](https://www.erlang.org/course/concurrent_programming.html).\n\n  * [Learn You Some Erlang for Great Good!](https://learnyousomeerlang.com/) is an excellent introduction to Erlang, its design principles, standard library, best practices, and much more. Once you have read through the crash course mentioned above, you'll be able to safely skip the first couple of chapters in the book that mostly deal with the syntax. When you reach [The Hitchhiker's Guide to Concurrency](https://learnyousomeerlang.com/the-hitchhikers-guide-to-concurrency) chapter, that's where the real fun starts.\n\nOur last step is to take a look at existing Elixir (and Erlang) libraries you might use while debugging.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/introduction.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Introduction\n\nWelcome!\n\nThis guide will teach you about Elixir fundamentals - the language syntax, how to define modules, the common data structures in the language, and more. This chapter will focus on ensuring that Elixir is installed and that you can successfully run Elixir's Interactive Shell, called IEx.\n\nLet's get started.\n\n## Installation\n\nIf you haven't yet installed Elixir, visit our [installation page](https://elixir-lang.org/install.html). Once you are done, you can run `elixir --version` to get the current Elixir version. The requirements for this guide are:\n\n  * Elixir 1.18.0 onwards\n  * Erlang/OTP 27 onwards\n\nIf you are looking for other resources for learning Elixir, you can also consult the [learning page](https://elixir-lang.org/learning.html) of the official website.\n\n## Interactive mode\n\nWhen you install Elixir, you will have three new command line executables: `iex`, `elixir` and `elixirc`.\n\nFor now, let's start by running `iex` (or `iex.bat` if you are on Windows PowerShell, where `iex` is a PowerShell command) which stands for Interactive Elixir. In interactive mode, we can type any Elixir expression and get its result. Let's warm up with some basic expressions.\n\nOpen up `iex` and type the following expressions:\n\n```elixir\nErlang/OTP 26 [64-bit] [smp:2:2] [...]\n\nInteractive Elixir - press Ctrl+C to exit\niex(1)> 40 + 2\n42\niex(2)> \"hello\" <> \" world\"\n\"hello world\"\n```\n\nPlease note that some details like version numbers may differ a bit in your session, that's not important. By executing the code above, you should evaluate expressions and see their results. To exit `iex` press `Ctrl+C` twice.\n\nIt seems we are ready to go! We will use the interactive shell quite a lot in the next chapters to get a bit more familiar with the language constructs and basic types, starting in the next chapter.\n\n## Running scripts\n\nAfter getting familiar with the basics of the language you may want to try writing simple programs. This can be accomplished by putting the following Elixir code into a file:\n\n```elixir\nIO.puts(\"Hello world from Elixir\")\n```\n\nSave it as `simple.exs` and execute it with `elixir`:\n\n```console\n$ elixir simple.exs\nHello world from Elixir\n```\n\n`iex` and `elixir` are all we need to learn the main language concepts. There is a separate guide named [\"Mix and OTP guide\"](../mix-and-otp/introduction-to-mix.md) that explores how to actually create, manage, and test full-blown Elixir projects. For now, let's move on to learn the basic data types in the language.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/io-and-the-file-system.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# IO and the file system\n\nThis chapter introduces the input/output mechanisms, file-system-related tasks, and related modules such as `IO`, `File`, and `Path`. The IO system provides a great opportunity to shed some light on some philosophies and curiosities of Elixir and the Erlang VM.\n\n## The `IO` module\n\nThe `IO` module is the main mechanism in Elixir for reading and writing to standard input/output (`:stdio`), standard error (`:stderr`), files, and other IO devices. Usage of the module is pretty straightforward:\n\n```elixir\niex> IO.puts(\"hello world\")\nhello world\n:ok\niex> IO.gets(\"yes or no? \")\nyes or no? yes\n\"yes\\n\"\n```\n\nBy default, functions in the `IO` module read from the standard input and write to the standard output. We can change that by passing, for example, `:stderr` as an argument (in order to write to the standard error device):\n\n```elixir\niex> IO.puts(:stderr, \"hello world\")\nhello world\n:ok\n```\n\n## The `File` module\n\nThe `File` module contains functions that allow us to open files as IO devices. By default, files are opened in binary mode, which requires developers to use the specific `IO.binread/2` and `IO.binwrite/2` functions from the `IO` module:\n\n> #### Potential data loss warning {: .warning}\n>\n> The following code opens a file for writing. If an existing file is available at the given path, its contents will be deleted.\n\n```elixir\niex> {:ok, file} = File.open(\"path/to/file/hello\", [:write])\n{:ok, #PID<0.47.0>}\niex> IO.binwrite(file, \"world\")\n:ok\niex> File.close(file)\n:ok\niex> File.read(\"path/to/file/hello\")\n{:ok, \"world\"}\n```\n\nThe file could be opened with the `:append` option, instead of `:write`, to preserve its contents. You may also pass the `:utf8` option, which tells the `File` module to interpret the bytes read from the file as UTF-8-encoded bytes.\n\nBesides functions for opening, reading and writing files, the `File` module has many functions to work with the file system. Those functions are named after their UNIX equivalents. For example, `File.rm/1` can be used to remove files, `File.mkdir/1` to create directories, `File.mkdir_p/1` to create directories and all their parent chain. There are even `File.cp_r/2` and `File.rm_rf/1` to respectively copy and remove files and directories recursively (i.e., copying and removing the contents of the directories too).\n\nYou will also notice that functions in the `File` module have two variants: one \"regular\" variant and another variant with a trailing bang (`!`). For example, when we read the `\"hello\"` file in the example above, we use `File.read/1`. Alternatively, we can use `File.read!/1`:\n\n```elixir\niex> File.read(\"path/to/file/hello\")\n{:ok, \"world\"}\niex> File.read!(\"path/to/file/hello\")\n\"world\"\niex> File.read(\"path/to/file/unknown\")\n{:error, :enoent}\niex> File.read!(\"path/to/file/unknown\")\n** (File.Error) could not read file \"path/to/file/unknown\": no such file or directory\n```\n\nNotice that the version with `!` returns the contents of the file instead of a tuple, and if anything goes wrong the function raises an error.\n\nThe version without `!` is preferred when you want to handle different outcomes using pattern matching:\n\n```elixir\ncase File.read(\"path/to/file/hello\") do\n  {:ok, body} -> # do something with the `body`\n  {:error, reason} -> # handle the error caused by `reason`\nend\n```\n\nHowever, if you expect the file to be there, the bang variation is more useful as it raises a meaningful error message. Avoid writing:\n\n```elixir\n{:ok, body} = File.read(\"path/to/file/unknown\")\n```\n\nas, in case of an error, `File.read/1` will return `{:error, reason}` and the pattern matching will fail. You will still get the desired result (a raised error), but the message will be about the pattern which doesn't match (thus being cryptic in respect to what the error actually is about).\n\nTherefore, if you don't want to handle the error outcomes, prefer to use the functions ending with an exclamation mark, such as `File.read!/1`.\n\n## The `Path` module\n\nThe majority of the functions in the `File` module expect paths as arguments. Most commonly, those paths will be regular binaries. The `Path` module provides facilities for working with such paths:\n\n```elixir\niex> Path.join(\"foo\", \"bar\")\n\"foo/bar\"\niex> Path.expand(\"~/hello\")\n\"/Users/jose/hello\"\n```\n\nUsing functions from the `Path` module as opposed to directly manipulating strings is preferred since the `Path` module takes care of different operating systems transparently. Finally, keep in mind that Elixir will automatically convert slashes (`/`) into backslashes (`\\`) on Windows when performing file operations.\n\nWith this, we have covered the main modules that Elixir provides for dealing with IO and interacting with the file system. In the next section, we will peek a bit under the covers and learn how the IO system is implemented in the VM.\n\n## Processes\n\nYou may have noticed that `File.open/2` returns a tuple like `{:ok, pid}`:\n\n```elixir\niex> {:ok, file} = File.open(\"hello\")\n{:ok, #PID<0.47.0>}\n```\n\nThis happens because the `IO` module actually works with processes (see [the previous chapter](processes.md)). Given a file is a process, when you write to a file that has been closed, you are actually sending a message to a process which has been terminated:\n\n```elixir\niex> File.close(file)\n:ok\niex> IO.write(file, \"is anybody out there\")\n** (ErlangError) Erlang error: :terminated:\n\n  * 1st argument: the device has terminated\n\n    (stdlib 5.0) io.erl:94: :io.put_chars(#PID<0.114.0>, \"is anybody out there\")\n    iex:4: (file)\n```\n\nLet's see in more detail what happens when you request `IO.write(pid, binary)`. The `IO` module sends a message to the process identified by `pid` with the desired operation. A small ad-hoc process can help us see it:\n\n```elixir\niex> pid = spawn(fn ->\n...>   receive do\n...>     msg -> IO.inspect(msg)\n...>   end\n...> end)\n#PID<0.57.0>\niex> IO.write(pid, \"hello\")\n{:io_request, #PID<0.41.0>, #Reference<0.0.8.91>,\n {:put_chars, :unicode, \"hello\"}}\n** (ErlangError) erlang error: :terminated\n```\n\nAfter `IO.write/2`, we can see the request sent by the `IO` module printed out (a four-elements tuple). Soon after that, we see that it fails since the `IO` module expected some kind of result, which we did not supply.\n\nBy modeling IO devices with processes, the Erlang VM allows us to even read and write to files across nodes. Neat!\n\n## `iodata` and `chardata`\n\nIn all of the examples above, we used binaries when writing to files. However, most of the IO functions in Elixir also accept either \"iodata\" or \"chardata\".\n\nOne of the main reasons for using \"iodata\" and \"chardata\" is for performance. For example,\nimagine you need to greet someone in your application:\n\n```elixir\nname = \"Mary\"\nIO.puts(\"Hello \" <> name <> \"!\")\n```\n\nGiven strings in Elixir are immutable, as most data structures, the example above will copy the string \"Mary\" into the new \"Hello Mary!\" string. While this is unlikely to matter for the short string as above, copying can be quite expensive for large strings! For this reason, the IO functions in Elixir allow you to pass instead a list of strings:\n\n```elixir\nname = \"Mary\"\nIO.puts([\"Hello \", name, \"!\"])\n```\n\nIn the example above, there is no copying. Instead we create a list that contains the original name. We call such lists either \"iodata\" or \"chardata\" and we will learn the precise difference between them soon.\n\nThose lists are very useful because it can actually simplify the processing strings in several scenarios. For example, imagine you have a list of values, such as `[\"apple\", \"banana\", \"lemon\"]` that you want to write to disk separated by commas. How can you achieve this?\n\nOne option is to use `Enum.join/2` and convert the values to a string:\n\n```elixir\niex> Enum.join([\"apple\", \"banana\", \"lemon\"], \",\")\n\"apple,banana,lemon\"\n```\n\nThe above returns a new string by copying each value into the new string. However, with the knowledge in this section, we know that we can pass a list of strings to the IO/File functions. So instead we can do:\n\n```elixir\niex> Enum.intersperse([\"apple\", \"banana\", \"lemon\"], \",\")\n[\"apple\", \",\", \"banana\", \",\", \"lemon\"]\n```\n\n\"iodata\" and \"chardata\" do not only contain strings, but they may contain arbitrary nested lists of strings too:\n\n```elixir\niex> IO.puts([\"apple\", [\",\", \"banana\", [\",\", \"lemon\"]]])\n```\n\n\"iodata\" and \"chardata\" may also contain integers. For example, we could print our comma separated list of values by using `?,` as separator, which is the integer representing a comma (`44`):\n\n```elixir\niex> IO.puts([\"apple\", ?,, \"banana\", ?,, \"lemon\"])\n```\n\nThe difference between \"iodata\" and \"chardata\" is precisely what said integer represents. For iodata, the integers represent bytes. For chardata, the integers represent Unicode codepoints. For ASCII characters, the byte representation is the same as the codepoint representation, so it fits both classifications. However, the default IO device works with chardata, which means we can do:\n\n```elixir\niex> IO.puts([?O, ?l, ?á, ?\\s, \"Mary\", ?!])\n```\n\nCharlists, such as `~c\"hello world\"`, are lists of integers, and therefore are chardata.\n\nWe packed a lot into this small section, so let's break it down:\n\n  * iodata and chardata are lists of binaries and integers. Those binaries and integers can be arbitrarily nested inside lists. Their goal is to give flexibility and performance when working with IO devices and files;\n\n  * the choice between iodata and chardata depends on the encoding of the IO device. If the file is opened without encoding, the file expects iodata, and the functions in the `IO` module starting with `bin*` must be used. The default IO device (`:stdio`) and files opened with `:utf8` encoding expect chardata and work with the remaining functions in the `IO` module;\n\nThis finishes our tour of IO devices and IO related functionality. We have learned about three Elixir modules - `IO`, `File`, and `Path` - as well as how the VM uses processes for the underlying IO mechanisms and how to use `chardata` and `iodata` for IO operations.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/keywords-and-maps.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Keyword lists and maps\n\nNow let's talk about associative data structures. Associative data structures are able to associate a key to a certain value. Different languages call these different names like dictionaries, hashes, associative arrays, etc.\n\nIn Elixir, we have two main associative data structures: keyword lists and maps.\n\n## Keyword lists\n\nKeyword lists are a data-structure used to pass options to functions. Let's see a scenario where they may be useful.\n\nImagine you want to split a string of numbers. Initially, we can invoke `String.split/2` passing two strings as arguments:\n\n```elixir\niex> String.split(\"1 2 3 4\", \" \")\n[\"1\", \"2\", \"3\", \"4\"]\n```\n\nWhat if you only want to split at most 2 times? The `String.split/3` function allows the `parts` option to be set to the maximum number of entries in the result:\n\n```elixir\niex> String.split(\"1 2 3 4\", \" \", [parts: 3])\n[\"1\", \"2\", \"3 4\"]\n```\n\nAs you can see, we got 3 parts, the last one containing the remaining of the input without splitting it.\n\nNow imagine that some of the inputs you must split on contains additional spaces between the numbers:\n\n```elixir\niex> String.split(\"1  2  3  4\", \" \", [parts: 3])\n[\"1\", \"\", \"2  3  4\"]\n```\n\nAs you can see, the additional spaces lead to empty entries in the output. Luckily, we can also set the `trim` option to `true` to remove them:\n\n```elixir\niex> String.split(\"1  2  3  4\", \" \", [parts: 3, trim: true])\n[\"1\", \"2\", \" 3  4\"]\n```\n\nOnce again we got 3 parts, with the last one containing the leftovers.\n\n`[parts: 3]` and `[parts: 3, trim: true]` are keyword lists. When a keyword list is the last argument of a function, we can skip the brackets and write:\n\n```elixir\niex> String.split(\"1  2  3  4\", \" \", parts: 3, trim: true)\n[\"1\", \"2\", \" 3  4\"]\n```\n\nAs shown in the example above, keyword lists are mostly used as optional arguments to functions.\n\nAs the name implies, keyword lists are simply lists. In particular, they are lists consisting of 2-item tuples where the first element (the key) is an atom and the second element can be any value. Both representations are the same:\n\n```elixir\niex> [{:parts, 3}, {:trim, true}] == [parts: 3, trim: true]\ntrue\n```\n\nKeyword lists are important because they have three special characteristics:\n\n  * Keys must be atoms.\n  * Keys are ordered, as specified by the developer.\n  * Keys can be given more than once.\n\nFor example, we use the fact that keys can be repeated when [importing functions](../getting-started/alias-require-and-import.md) in Elixir:\n\n```elixir\niex> import String, only: [split: 1, split: 2]\nString\niex> split(\"hello world\")\n[\"hello\", \"world\"]\n```\n\nIn the example above, we imported both `split/1` and `split/2` from the `String` module, allowing us to invoke them without typing the module name. We used a keyword list to list the functions to import.\n\nSince keyword lists are lists, we can use all operations available to lists. For example, we can use `++` to add new values to a keyword list:\n\n```elixir\niex> list = [a: 1, b: 2]\n[a: 1, b: 2]\niex> list ++ [c: 3]\n[a: 1, b: 2, c: 3]\niex> [a: 0] ++ list\n[a: 0, a: 1, b: 2]\n```\n\nYou can read the value of a keyword list using the brackets syntax, which will return the value of the first matching key. This is also known as the access syntax, as it is defined by the `Access` module:\n\n```elixir\niex> list[:a]\n1\niex> list[:b]\n2\n```\n\nAlthough we can pattern match on keyword lists, it is not done in practice since pattern matching on lists requires the number of items and their order to match:\n\n```elixir\niex> [a: a] = [a: 1]\n[a: 1]\niex> a\n1\niex> [a: a] = [a: 1, b: 2]\n** (MatchError) no match of right hand side value: [a: 1, b: 2]\niex> [b: b, a: a] = [a: 1, b: 2]\n** (MatchError) no match of right hand side value: [a: 1, b: 2]\n```\n\nFurthermore, given keyword lists are often used as optional arguments, they are used in situations where not all keys may be present, which would make it impossible to match on them. In a nutshell, do not pattern match on keyword lists.\n\nIn order to manipulate keyword lists, Elixir provides the `Keyword` module. Remember, though, keyword lists are simply lists, and as such they provide the same linear performance characteristics: the longer the list, the longer it will take to find a key, to count the number of items, and so on. If you need to store a large amount of keys in a key-value data structure, Elixir offers maps, which we will soon learn.\n\n### `do`-blocks and keywords\n\nAs we have seen, keywords are mostly used in the language to pass optional values. In fact, we have used keywords in earlier chapters. Let's look at the `if/2` macro:\n\n```elixir\niex> if true do\n...>   \"This will be seen\"\n...> else\n...>   \"This won't\"\n...> end\n\"This will be seen\"\n```\n\nIn the example above, the `do` and `else` blocks make up a keyword list. They are nothing more than a syntax convenience on top of keyword lists. We can rewrite the above to:\n\n```elixir\niex> if(true, do: \"This will be seen\", else: \"This won't\")\n\"This will be seen\"\n```\n\nPay close attention to both syntaxes. The second example uses keyword lists, exactly as in the `String.split/3` example, so we separate each key-value pair with commas and each key is followed by `:`. In the `do`-blocks, we use bare words, such as `do`, `else`, and `end`, and separate them by a newline. They are useful precisely when writing blocks of code. Most of the time, you will use the block syntax, but it is good to know they are equivalent.\n\nThe fact the block syntax is equivalent to keywords means we only need few data structures to represent the language, keeping it simple overall. We will come back to this topic when discussing [optional syntax](optional-syntax.md) and [meta-programming](../meta-programming/quote-and-unquote.md).\n\nWith this out of the way, let's talk about maps.\n\n## Maps as key-value pairs\n\nWhenever you need to store key-value pairs, maps are the \"go to\" data structure in Elixir. A map is created using the `%{}` syntax:\n\n```elixir\niex> map = %{:a => 1, 2 => :b}\n%{2 => :b, :a => 1}\niex> map[:a]\n1\niex> map[2]\n:b\niex> map[:c]\nnil\n```\n\nCompared to keyword lists, we can already see two differences:\n\n  * Maps allow any value as a key.\n  * Maps have their own internal ordering, which is not guaranteed to be the same across different maps, even if they have the same keys\n\nIn contrast to keyword lists, maps are very useful with pattern matching. When a map is used in a pattern, it will always match on a subset of the given value:\n\n```elixir\niex> %{} = %{:a => 1, 2 => :b}\n%{2 => :b, :a => 1}\niex> %{:a => a} = %{:a => 1, 2 => :b}\n%{2 => :b, :a => 1}\niex> a\n1\niex> %{:c => c} = %{:a => 1, 2 => :b}\n** (MatchError) no match of right hand side value: %{2 => :b, :a => 1}\n```\n\nAs shown above, a map matches as long as the keys in the pattern exist in the given map. Therefore, an empty map matches all maps.\n\nThe `Map` module provides a very similar API to the `Keyword` module with convenience functions to add, remove, and update maps keys:\n\n```elixir\niex> Map.get(%{:a => 1, 2 => :b}, :a)\n1\niex> Map.put(%{:a => 1, 2 => :b}, :c, 3)\n%{2 => :b, :a => 1, :c => 3}\niex> Map.to_list(%{:a => 1, 2 => :b})\n[{2, :b}, {:a, 1}]\n```\n\n## Maps of predefined keys\n\nIn the previous section, we have used maps as a key-value data structure where keys can be added or removed at any time. However, it is also common to create maps with a predefined set of keys. Their values may be updated, but new keys are never added nor removed. This is useful when we know the shape of the data we are working with and, if we get a different key, it likely means a mistake was done elsewhere. In such cases, the keys are most often atoms:\n\n```elixir\niex> map = %{:name => \"John\", :age => 23}\n%{name: \"John\", age: 23}\n```\n\nAs you can see from the printed result above, Elixir also allows you to write maps of atom keys using the same `key: value` syntax as keyword lists:\n\n```elixir\niex> map = %{name: \"John\", age: 23}\n%{name: \"John\", age: 23}\n```\n\nWhen a key is an atom, we can also access them using the `map.key` syntax:\n\n```elixir\niex> map.name\n\"John\"\niex> map.agee\n** (KeyError) key :agee not found in: %{name: \"John\", age: 23}\n```\n\nThere is also syntax for updating keys, which also raises if the key has not yet been defined:\n\n```elixir\niex> %{map | name: \"Mary\"}\n%{name: \"Mary\", age: 23}\niex> %{map | agee: 27}\n** (KeyError) key :agee not found in: %{name: \"John\", age: 23}\n```\n\nThese operations have one large benefit in that they raise if the key does not exist in the map and the compiler may even detect and warn when possible. This makes them useful to get quick feedback and spot bugs and typos early on. This is also the syntax used to power another Elixir feature called \"Structs\", which we will learn later on.\n\nElixir developers typically prefer to use the `map.key` syntax and pattern matching instead of the functions in the `Map` module when working with maps because they lead to an assertive style of programming. [This blog post by José Valim](https://dashbit.co/blog/writing-assertive-code-with-elixir) provides insight and examples on how you get more concise and faster software by writing assertive code in Elixir.\n\nIn a further chapter you'll learn about [\"Structs\"](structs.md), which further enforce the idea of a map with predefined keys.\n\n## Nested data structures\n\nOften we will have maps inside maps, or even keywords lists inside maps, and so forth. Elixir provides conveniences for manipulating nested data structures via the `get_in/1`, `put_in/2`, `update_in/2`, and other macros giving the same conveniences you would find in imperative languages while keeping the immutable properties of the language.\n\nImagine you have the following structure:\n\n```elixir\niex> users = [\n  john: %{name: \"John\", age: 27, languages: [\"Erlang\", \"Ruby\", \"Elixir\"]},\n  mary: %{name: \"Mary\", age: 29, languages: [\"Elixir\", \"F#\", \"Clojure\"]}\n]\n[\n  john: %{age: 27, languages: [\"Erlang\", \"Ruby\", \"Elixir\"], name: \"John\"},\n  mary: %{age: 29, languages: [\"Elixir\", \"F#\", \"Clojure\"], name: \"Mary\"}\n]\n```\n\nWe have a keyword list of users where each value is a map containing the name, age and a list of programming languages each user likes. If we wanted to access the age for john, we could write:\n\n```elixir\niex> users[:john].age\n27\n```\n\nIt happens we can also use this same syntax for updating the value:\n\n```elixir\niex> users = put_in(users[:john].age, 31)\n[\n  john: %{age: 31, languages: [\"Erlang\", \"Ruby\", \"Elixir\"], name: \"John\"},\n  mary: %{age: 29, languages: [\"Elixir\", \"F#\", \"Clojure\"], name: \"Mary\"}\n]\n```\n\nThe `update_in/2` macro is similar but allows us to pass a function that controls how the value changes. For example, let's remove \"Clojure\" from Mary's list of languages:\n\n```elixir\niex> users = update_in(users[:mary].languages, fn languages -> List.delete(languages, \"Clojure\") end)\n[\n  john: %{age: 31, languages: [\"Erlang\", \"Ruby\", \"Elixir\"], name: \"John\"},\n  mary: %{age: 29, languages: [\"Elixir\", \"F#\"], name: \"Mary\"}\n]\n```\n\n## Summary\n\nThere are two different data structures for working with key-value stores in Elixir. Alongside the `Access` module and pattern matching, they provide a rich set of tools for manipulating complex, potentially nested, data structures.\n\nAs we conclude this chapter, remember that you should:\n\n  * Use keyword lists for passing optional values to functions\n\n  * Use maps for general key-value data structures\n\n  * Use maps when working with data that has a predefined set of keys\n\nNow let's talk about modules and functions.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/lists-and-tuples.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Lists and tuples\n\nIn this chapter we will learn two of the most used collection data-types in Elixir: lists and tuples.\n\n## (Linked) Lists\n\nElixir uses square brackets to specify a list of values. Values can be of any type:\n\n```elixir\niex> [1, 2, true, 3]\n[1, 2, true, 3]\niex> length([1, 2, 3])\n3\n```\n\nTwo lists can be concatenated or subtracted using the [`++`](`++/2`) and [`--`](`--/2`) operators respectively:\n\n```elixir\niex> [1, 2, 3] ++ [4, 5, 6]\n[1, 2, 3, 4, 5, 6]\niex> [1, true, 2, false, 3, true] -- [true, false]\n[1, 2, 3, true]\n```\n\nList operators never modify the existing list. Concatenating to or removing elements from a list returns a new list. We say that Elixir data structures are *immutable*. One advantage of immutability is that it leads to clearer code. You can freely pass the data around with the guarantee no one will mutate it in memory - only transform it.\n\nThroughout the tutorial, we will talk a lot about the head and tail of a list. The head is the first element of a list and the tail is the remainder of the list. They can be retrieved with the functions [`hd`](`hd/1`) and [`tl`](`tl/1`). Let's assign a list to a variable and retrieve its head and tail:\n\n```elixir\niex> list = [1, 2, 3]\niex> hd(list)\n1\niex> tl(list)\n[2, 3]\n```\n\nGetting the head or the tail of an empty list throws an error:\n\n```elixir\niex> hd([])\n** (ArgumentError) argument error\n```\n\nSometimes you will create a list and it will return a quoted value preceded by `~c`. For example:\n\n```elixir\niex> [11, 12, 13]\n~c\"\\v\\f\\r\"\niex> [104, 101, 108, 108, 111]\n~c\"hello\"\n```\n\nWhen Elixir sees a list of printable ASCII numbers, Elixir will print that as a charlist (literally a list of characters). Charlists are quite common when interfacing with existing Erlang code. Whenever you see a value in IEx and you are not quite sure what it is, you can use [`i`](`IEx.Helpers.i/1`) to retrieve information about it:\n\n```elixir\niex> i ~c\"hello\"\nTerm\n  i ~c\"hello\"\nData type\n  List\nDescription\n  ...\nRaw representation\n  [104, 101, 108, 108, 111]\nReference modules\n  List\nImplemented protocols\n  ...\n```\n\nWe will talk more about charlists in the [\"Binaries, strings, and charlists\"](binaries-strings-and-charlists.md) chapter.\n\n> #### Single-quoted strings {: .info}\n>\n> In Elixir, you can also use `'hello'` to build charlists, but this notation has been soft-deprecated in Elixir v1.15 and will emit warnings in future versions. Prefer to write `~c\"hello\"` instead.\n\n## Tuples\n\nElixir uses curly brackets to define tuples. Like lists, tuples can hold any value:\n\n```elixir\niex> {:ok, \"hello\"}\n{:ok, \"hello\"}\niex> tuple_size({:ok, \"hello\"})\n2\n```\n\nTuples store elements contiguously in memory. This means accessing a tuple element by index or getting the tuple size is a fast operation. Indexes start from zero:\n\n```elixir\niex> tuple = {:ok, \"hello\"}\n{:ok, \"hello\"}\niex> elem(tuple, 1)\n\"hello\"\niex> tuple_size(tuple)\n2\n```\n\nIt is also possible to put an element at a particular index in a tuple with [`put_elem`](`put_elem/3`):\n\n```elixir\niex> tuple = {:ok, \"hello\"}\n{:ok, \"hello\"}\niex> put_elem(tuple, 1, \"world\")\n{:ok, \"world\"}\niex> tuple\n{:ok, \"hello\"}\n```\n\nNotice that [`put_elem`](`put_elem/3`) returned a new tuple. The original tuple stored in the `tuple` variable was not modified. Like lists, tuples are also immutable. Every operation on a tuple returns a new tuple, it never changes the given one.\n\n## Lists or tuples?\n\nWhat is the difference between lists and tuples?\n\nLists are stored in memory as linked lists, meaning that each element in a list holds its value and points to the following element until the end of the list is reached. This means accessing the length of a list is a linear operation: we need to traverse the whole list in order to figure out its size.\n\nSimilarly, the performance of list concatenation depends on the length of the left-hand list:\n\n```elixir\niex> list = [1, 2, 3]\n[1, 2, 3]\n\n# This is fast as we only need to traverse `[0]` to prepend to `list`\niex> [0] ++ list\n[0, 1, 2, 3]\n\n# This is slow as we need to traverse `list` to append 4\niex> list ++ [4]\n[1, 2, 3, 4]\n```\n\nTuples, on the other hand, are stored contiguously in memory. This means getting the tuple size or accessing an element by index is fast. On the other hand, updating or adding elements to tuples is expensive because it requires creating a new tuple in memory:\n\n```elixir\niex> tuple = {:a, :b, :c, :d}\n{:a, :b, :c, :d}\niex> put_elem(tuple, 2, :e)\n{:a, :b, :e, :d}\n```\n\nNote, however, the elements themselves are not copied. When you update a tuple, all entries are shared between the old and the new tuple, except for the entry that has been replaced. This rule applies to most data structures in Elixir. This reduces the amount of memory allocation the language needs to perform and is only possible thanks to the immutable semantics of the language.\n\nThose performance characteristics dictate the usage of those data structures. In a nutshell, lists are used when the number of elements returned may vary. Tuples have a fixed size. Let's see two examples from the `String` module:\n\n```elixir\niex> String.split(\"hello world\")\n[\"hello\", \"world\"]\niex> String.split(\"hello beautiful world\")\n[\"hello\", \"beautiful\", \"world\"]\n```\n\nThe [`String.split`](`String.split/1`) function breaks a string into a list of strings on every whitespace character. Since the amount of elements returned depends on the input, we use a list.\n\nOn the other hand, [`String.split_at`](`String.split_at/2`) splits a string in two parts at a given position. Since it always returns two entries, regardless of the input size, it returns tuples:\n\n```elixir\niex> String.split_at(\"hello world\", 3)\n{\"hel\", \"lo world\"}\niex> String.split_at(\"hello world\", -4)\n{\"hello w\", \"orld\"}\n```\n\nIt is also very common to use tuples and atoms to create \"tagged tuples\", which is a handy return value when an operation may succeed or fail. For example, [`File.read`](`File.read/1`) reads the contents of a file at a given path, which may or may not exist. It returns tagged tuples:\n\n```elixir\niex> File.read(\"path/to/existing/file\")\n{:ok, \"... contents ...\"}\niex> File.read(\"path/to/unknown/file\")\n{:error, :enoent}\n```\n\nIf the path given to [`File.read`](`File.read/1`) exists, it returns a tuple with the atom `:ok` as the first element and the file contents as the second. Otherwise, it returns a tuple with `:error` and the error description. As we will soon learn, Elixir allows us to *pattern match* on tagged tuples and effortlessly handle both success and failure cases.\n\nGiven Elixir consistently follows those rules, the choice between lists and tuples get clearer as you learn and use the language. Elixir often guides you to do the right thing. For example, there is an [`elem`](`elem/2`) function to access a tuple item:\n\n```elixir\niex> tuple = {:ok, \"hello\"}\n{:ok, \"hello\"}\niex> elem(tuple, 1)\n\"hello\"\n```\n\nHowever, given you often don't know the number of elements in a list, there is no built-in equivalent for accessing arbitrary entries in a lists, apart from its head.\n\n## Size or length?\n\nWhen counting the elements in a data structure, Elixir also abides by a simple rule: the function is named `size` if the operation is in constant time (the value is pre-calculated) or `length` if the operation is linear (calculating the length gets slower as the input grows). As a mnemonic, both \"length\" and \"linear\" start with \"l\".\n\nFor example, we have used 4 counting functions so far: [`byte_size`](`byte_size/1`) (for the number of bytes in a string), [`tuple_size`](`tuple_size/1`) (for tuple size), [`length`](`length/1`) (for list length) and [`String.length`](`String.length/1`) (for the number of graphemes in a string). We use [`byte_size`](`byte_size/1`) to get the number of bytes in a string, which is a cheap operation. Retrieving the number of Unicode graphemes, on the other hand, uses [`String.length`](`String.length/1`), and may be expensive as it relies on a traversal of the entire string.\n\nNow that we are familiar with the basic data-types in the language, let's learn important constructs for writing code, before we discuss more complex data structures.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/module-attributes.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Module attributes\n\nModule attributes in Elixir serve three purposes:\n\n1. as module and function annotations\n2. as temporary module storage to be used during compilation\n3. as compile-time constants\n\nLet's check these examples.\n\n## As annotations\n\nElixir brings the concept of module attributes from Erlang. For example:\n\n```elixir\ndefmodule MyServer do\n  @moduledoc \"My server code.\"\nend\n```\n\nIn the example above, we are defining the module documentation by using the module attribute syntax. Elixir has a handful of reserved attributes. Here are a few of them, the most commonly used ones:\n\n  * `@moduledoc` — provides documentation for the current module.\n  * `@doc` — provides documentation for the function or macro that follows the attribute.\n  * `@spec` — provides a typespec for the function that follows the attribute.\n  * `@behaviour` — (notice the British spelling) used for specifying an OTP or user-defined behaviour.\n\n`@moduledoc` and `@doc` are by far the most used attributes, and we expect you to use them a lot. Elixir treats documentation as first-class and provides many functions to access documentation. We will cover them [in their own chapter](writing-documentation.md).\n\nDocumentation is only accessible from compiled modules. So in order to give it a try, let's once again define the `Math` module, but this time within a file named `math.ex`:\n\n```elixir\ndefmodule Math do\n  @moduledoc \"\"\"\n  Provides math-related functions.\n\n  ## Examples\n\n      iex> Math.sum(1, 2)\n      3\n\n  \"\"\"\n\n  @doc \"\"\"\n  Calculates the sum of two numbers.\n  \"\"\"\n  def sum(a, b), do: a + b\nend\n```\n\nElixir promotes the use of Markdown with heredocs to write readable documentation. Heredocs are multi-line strings, they start and end with triple double-quotes, keeping the formatting of the inner text.\n\nNow let's compile it. Start `iex` and then invoke [the `c/2` helper](`IEx.Helpers.c/2`):\n\n```elixir\niex> c(\"math.ex\", \".\")\n[Math]\n```\n\nAnd now we can access them:\n\n```elixir\niex> h Math # Docs for module Math\n...\niex> h Math.sum # Docs for the sum function\n...\n```\n\nWhen we compiled the module, you may have noticed Elixir created a `Elixir.Math.beam` file. That's the bytecode for the module and that's where the documentation is stored.\n\nIn our day to day, Elixir developers use the `Mix` build tool to compile code and projects like [ExDoc](https://github.com/elixir-lang/ex_doc) to generate HTML and EPUB pages from the documentation.\n\nTake a look at the docs for `Module` for a complete list of supported attributes.\n\n## As temporary storage\n\nSo far, we have seen how to define attributes, but how can we read them? Let's see an example:\n\n```elixir\ndefmodule MyServer do\n  @service URI.parse(\"https://example.com\")\n  IO.inspect(@service)\nend\n```\n\n> #### Newlines {: .warning}\n>\n> Do not add a newline between the attribute and its value, otherwise Elixir will assume you are reading the value, rather than setting it.\n\nTrying to access an attribute that was not defined will print a warning:\n\n```elixir\ndefmodule MyServer do\n  @unknown\nend\nwarning: undefined module attribute @unknown, please remove access to @unknown or explicitly set it before access\n```\n\nAttributes can also be read inside functions:\n\n```elixir\ndefmodule MyApp.Status do\n  @service URI.parse(\"https://example.com\")\n  def status(email) do\n    SomeHttpClient.get(@service)\n  end\nend\n```\n\nThe module attribute is defined at compilation time and its *return value*, not the function call itself, is what will be substituted in for the attribute. So the above will effectively compile to this:\n\n```elixir\ndefmodule MyApp.Status do\n  def status(email) do\n    SomeHttpClient.get(%URI{\n      authority: \"example.com\",\n      host: \"example.com\",\n      port: 443,\n      scheme: \"https\"\n    })\n  end\nend\n```\n\nThis can be useful for pre-computing values and then injecting its results into the module. This is what we mean by temporary storage: after the module is compiled, the module attribute is discarded, except for the functions that have read the attribute. Note you cannot invoke functions defined in the same module as part of the attribute itself, as those functions have not yet been defined.\n\nEvery time we read an attribute inside a function, Elixir takes a snapshot of its current value. Therefore if you read the same attribute multiple times inside multiple functions, you end-up increasing compilation times as Elixir now has to compile every snapshot. Generally speaking, you want to avoid reading the same attribute multiple times and instead move it to function. For example, instead of this:\n\n```elixir\ndef some_function, do: do_something_with(@example)\ndef another_function, do: do_something_else_with(@example)\n```\n\nPrefer this:\n\n```elixir\ndef some_function, do: do_something_with(example())\ndef another_function, do: do_something_else_with(example())\ndefp example, do: @example\n```\n\n## As compile-time constants\n\nModule attributes may also be useful as compile-time constants. Generally speaking, functions themselves are sufficient for the role of constants in a codebase. For example, instead of defining:\n\n```elixir\n@hours_in_a_day 24\n```\n\nYou should prefer:\n\n```elixir\ndefp hours_in_a_day(), do: 24\n```\n\nYou may even define a public function if it needs to be shared across modules. It is common in many projects to have a module called `MyApp.Constants` that defines all constants used throughout the codebase.\n\nYou can even have composite data structures as constants, as long as they are made exclusively of other data types (no function calls, no operators, and no other expressions). For example, you may specify a system configuration constant as follows:\n\n```elixir\ndefp system_config(), do: %{timezone: \"Etc/UTC\", locale: \"pt-BR\"}\n```\n\nGiven data structures in Elixir are immutable, only a single instance of the data structure above is allocated and shared across all functions calls, as long as it doesn't have any executable expression.\n\nThe use case for module attributes arise when you need to do some work at compile-time and then inject its results inside a function. A common scenario is module attributes inside patterns and guards (as an alternative to `defguard/1`), since they only support a limited set of expressions:\n\n```elixir\n# Inside pattern\n@default_timezone \"Etc/UTC\"\ndef shift(@default_timezone), do: ...\n\n# Inside guards\n@time_periods [:am, :pm]\ndef shift(time, period) when period in @time_periods, do: ...\n```\n\nModule attributes as constants and as temporary storage are most often used together: the module attribute is used to compute and store an expensive value, and then exposed as constant from that module.\n\n## Going further\n\nLibraries and frameworks can leverage module attributes to provide custom annotations. To see an example, look no further than Elixir's unit test framework called `ExUnit`. `ExUnit` uses module attributes for multiple different purposes:\n\n```elixir\ndefmodule MyTest do\n  use ExUnit.Case, async: true\n\n  @tag :external\n  @tag os: :unix\n  test \"contacts external service\" do\n    # ...\n  end\nend\n```\n\nIn the example above, `ExUnit` stores the value of `async: true` in a module attribute to change how the module is compiled. Tags also work as annotations and they can be supplied multiple times, thanks to Elixir's ability to [accumulate attributes](`Module.register_attribute/3`). Then you can use tags to setup and filter tests, such as avoiding executing Unix specific tests while running your test suite on Windows.\n\nTo fully understand how `ExUnit` works, we'd need macros, so we will revisit this pattern in the Meta-programming guide and learn how to use module attributes as storage for custom annotations.\n\nIn the next chapters, we'll explore structs and protocols before moving to exception handling and other constructs like sigils and comprehensions.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/modules-and-functions.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Modules and functions\n\nIn Elixir we group several functions into modules. We've already used many different modules in the previous chapters, such as the `String` module:\n\n```elixir\niex> String.length(\"hello\")\n5\n```\n\nIn order to create our own modules in Elixir, we use the [`defmodule`](`defmodule/2`) macro. The first letter of a module name (an alias, as described further down) must be in uppercase. We use the [`def`](`def/2`) macro to define functions in that module. The first letter of every function must be in lowercase (or underscore):\n\n```elixir\niex> defmodule Math do\n...>   def sum(a, b) do\n...>     a + b\n...>   end\n...> end\n\niex> Math.sum(1, 2)\n3\n```\n\nIn this chapter we will define our own modules, with different levels of complexity. As our examples get longer in size, it can be tricky to type them all in the shell, so we will resort more frequently to scripting.\n\n## Scripting\n\nElixir has two file extensions `.ex` (Elixir) and `.exs` (Elixir scripts). Elixir treats both files exactly the same way, the only difference is in intention. `.ex` files are meant to be compiled while `.exs` files are used for scripting.\n\nLet's create a file named `math.exs`:\n\n```elixir\ndefmodule Math do\n  def sum(a, b) do\n    a + b\n  end\nend\n\nIO.puts Math.sum(1, 2)\n```\n\nAnd execute it as:\n\n```console\n$ elixir math.exs\n```\n\nYou can also load the file within `iex` by running:\n\n```console\n$ iex math.exs\n```\n\nAnd then have direct access to the `Math` module.\n\n## Function definition\n\nInside a module, we can define functions with `def/2` and private functions with `defp/2`. A function defined with `def/2` can be invoked from other modules while a private function can only be invoked locally.\n\n```elixir\ndefmodule Math do\n  def sum(a, b) do\n    do_sum(a, b)\n  end\n\n  defp do_sum(a, b) do\n    a + b\n  end\nend\n\nIO.puts Math.sum(1, 2)    #=> 3\nIO.puts Math.do_sum(1, 2) #=> ** (UndefinedFunctionError)\n```\n\nFunction declarations also support guards and multiple clauses. If a function has several clauses, Elixir will try each clause until it finds one that matches. Here is an implementation of a function that checks if the given number is zero or not:\n\n```elixir\ndefmodule Math do\n  def zero?(0) do\n    true\n  end\n\n  def zero?(x) when is_integer(x) do\n    false\n  end\nend\n\nIO.puts Math.zero?(0)         #=> true\nIO.puts Math.zero?(1)         #=> false\nIO.puts Math.zero?([1, 2, 3]) #=> ** (FunctionClauseError)\nIO.puts Math.zero?(0.0)       #=> ** (FunctionClauseError)\n```\n\nThe trailing question mark in `zero?` means that this function returns a boolean. To learn more about the naming conventions for modules, function names, variables and more in Elixir, see [Naming Conventions](../references/naming-conventions.md).\n\nGiving an argument that does not match any of the clauses raises an error.\n\nSimilar to constructs like `if`, function definitions support both `do:` and `do`-block syntax, as [we learned in the previous chapter](keywords-and-maps.md#do-blocks-and-keywords). For example, we can edit `math.exs` to look like this:\n\n```elixir\ndefmodule Math do\n  def zero?(0), do: true\n  def zero?(x) when is_integer(x), do: false\nend\n```\n\nAnd it will provide the same behavior. You may use `do:` for one-liners but always use `do`-blocks for functions spanning multiple lines. If you prefer to be consistent, you can use `do`-blocks throughout your codebase.\n\n## Default arguments\n\nFunction definitions in Elixir also support default arguments:\n\n```elixir\ndefmodule Concat do\n  def join(a, b, sep \\\\ \" \") do\n    a <> sep <> b\n  end\nend\n\nIO.puts(Concat.join(\"Hello\", \"world\"))      #=> Hello world\nIO.puts(Concat.join(\"Hello\", \"world\", \"_\")) #=> Hello_world\n```\n\nAny expression is allowed to serve as a default value, but it won't be evaluated during the function definition. Every time the function is invoked and any of its default values have to be used, the expression for that default value will be evaluated:\n\n```elixir\ndefmodule DefaultTest do\n  def dowork(x \\\\ \"hello\") do\n    x\n  end\nend\n```\n\n```elixir\niex> DefaultTest.dowork()\n\"hello\"\niex> DefaultTest.dowork(123)\n123\niex> DefaultTest.dowork()\n\"hello\"\n```\n\nIf a function with default values has multiple clauses, it is required to create a function head (a function definition without a body) for declaring defaults:\n\n```elixir\ndefmodule Concat do\n  # A function head declaring defaults\n  def join(a, b, sep \\\\ \" \")\n\n  # The separator is unused in this case, so we prefix it with underscore\n  def join(a, b, _sep) when b == \"\" do\n    a\n  end\n\n  def join(a, b, sep) do\n    a <> sep <> b\n  end\nend\n\nIO.puts(Concat.join(\"Hello\", \"\"))           #=> Hello\nIO.puts(Concat.join(\"Hello\", \"world\"))      #=> Hello world\nIO.puts(Concat.join(\"Hello\", \"world\", \"_\")) #=> Hello_world\n```\n\nFunction heads cannot have patterns nor guards. They may only define the argument names and their default values.\n\n## Understanding Aliases\n\nAn alias in Elixir is a capitalized identifier (like `String`, `Keyword`, etc) which is converted to an atom during compilation. For instance, the `String` alias translates by default to the atom `:\"Elixir.String\"`:\n\n```elixir\niex> is_atom(String)\ntrue\niex> to_string(String)\n\"Elixir.String\"\niex> :\"Elixir.String\" == String\ntrue\n```\n\nBy using the `alias/2` directive, we are changing the atom the alias expands to.\n\nAliases expand to atoms because in the Erlang Virtual Machine (and consequently Elixir) modules are always represented by atoms. By namespacing those atoms, Elixir modules avoid conflicting with existing Erlang modules.\n\n```elixir\niex> List.flatten([1, [2], 3])\n[1, 2, 3]\niex> :\"Elixir.List\".flatten([1, [2], 3])\n[1, 2, 3]\n```\n\nThat's the mechanism we use to call Erlang modules:\n\n```elixir\niex> :lists.flatten([1, [2], 3])\n[1, 2, 3]\n```\n\n## Module nesting\n\nNow that we have talked about aliases, we can talk about nesting and how it works in Elixir. Consider the following example:\n\n```elixir\ndefmodule Foo do\n  defmodule Bar do\n  end\nend\n```\n\nThe example above will define two modules: `Foo` and `Foo.Bar`. The second can be accessed as `Bar` inside `Foo` as long as they are in the same lexical scope.\n\nIf, later, the `Bar` module is moved outside the `Foo` module definition, it must be referenced by its full name (`Foo.Bar`) or an alias must be set using the `alias` directive discussed above:\n\n```elixir\ndefmodule Foo.Bar do\nend\n\ndefmodule Foo do\n  alias Foo.Bar\n  # Can still access it as `Bar`\nend\n```\n\n> #### Module names are isolated {: .info}\n>\n> You don't have to define the `Foo` module before defining the `Foo.Bar` module, as they are effectively independent.\n\nAliasing a module only alias a single module, it doesn't alias any of its parents. Consider the following example:\n\n```elixir\ndefmodule Foo do\n  defmodule Bar do\n    defmodule Baz do\n    end\n  end\nend\n\nalias Foo.Bar.Baz\n# The module `Foo.Bar.Baz` is now available as `Baz`\n# However, the module `Foo.Bar` is *not* available as `Bar`\n```\n\nAs we will see in later chapters, aliases also work well with macros, to guarantee they are hygienic.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/optional-syntax.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Optional syntax sheet\n\nIn the previous chapters, we learned that the Elixir syntax allows developers to omit delimiters in a few occasions to make code more readable. For example, we learned that parentheses are optional:\n\n```elixir\niex> length([1, 2, 3]) == length [1, 2, 3]\ntrue\n```\n\nand that `do`-`end` blocks are equivalent to keyword lists:\n\n```elixir\n# do-end blocks\niex> if true do\n...>   :this\n...> else\n...>   :that\n...> end\n:this\n\n# keyword lists\niex> if true, do: :this, else: :that\n:this\n```\n\nKeyword lists use Elixir's regular notation for separating arguments, where we separate each key-value pair with commas, and each key is followed by `:`. In the `do`-blocks, we get rid of the colons, the commas, and separate each keyword by a newline. They are useful exactly because they remove the verbosity when writing blocks of code. Most of the time, we use the block syntax, but it is good to know they are equivalent.\n\nThose conveniences, which we call here \"optional syntax\", allow the language syntax core to be small, without sacrificing the readability and expressiveness of your code.  In this brief chapter, we will review the four rules provided by the language, using a short snippet as playground.\n\n## Walk-through\n\nTake the following code:\n\n```elixir\nif variable? do\n  Call.this()\nelse\n  Call.that()\nend\n```\n\nNow let's remove the conveniences one by one:\n\n1. `do`-`end` blocks are equivalent to keywords:\n\n   ```elixir\n   if variable?, do: Call.this(), else: Call.that()\n   ```\n\n2. Keyword lists as last argument do not require square brackets, but let's add them:\n\n   ```elixir\n   if variable?, [do: Call.this(), else: Call.that()]\n   ```\n\n3. Keyword lists are the same as lists of two-element tuples:\n\n   ```elixir\n   if variable?, [{:do, Call.this()}, {:else, Call.that()}]\n   ```\n\n4. Finally, parentheses are optional on function calls, but let's add them:\n\n   ```elixir\n   if(variable?, [{:do, Call.this()}, {:else, Call.that()}])\n   ```\n\nThat's it! Those four rules outline the optional syntax available in Elixir.\n\nTo understand why these rules matter, we can briefly compare Elixir with many other programming languages. Most programming languages have several keywords for defining methods, functions, conditionals, loops, and so forth. Each of those keywords have their own syntax rules attached to them.\n\nHowever, in Elixir, none of these language features require special \"keywords\", instead they all build from this small set of rules. The other benefit is that developers can also extend the language in a way that is consistent with the language itself, since the constructs for designing and extending the language are the same. We further explore this topic in [the \"Meta-programming\" guide](../meta-programming/quote-and-unquote.md).\n\nAt the end of the day, those rules are what enables us to write:\n\n```elixir\ndefmodule Math do\n  def add(a, b) do\n    a + b\n  end\nend\n```\n\ninstead of:\n\n```elixir\ndefmodule(Math, [\n  {:do, def(add(a, b), [{:do, a + b}])}\n])\n```\n\nWhenever you have any questions, this quick walk-through has you covered.\n\nFinally, if you are concerned about when to apply these rules, it's worth noting that the Elixir formatter handles those concerns for you. Most Elixir developers use the `mix format` task to format their codebases according to a well-defined set of rules defined by the Elixir team and the community. For instance, `mix format` will always add parentheses to function calls unless explicitly configured not to do so. This helps to maintain consistency across all codebases within organizations and the wider community.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/pattern-matching.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Pattern matching\n\nIn this chapter, we will learn why the [`=`](`=/2`) operator in Elixir is called the match operator and how to use it to pattern match inside data structures. We will learn about the pin operator [`^`](`^/1`) used to access previously bound values.\n\n## The match operator\n\nWe have used the [`=`](`=/2`) operator a couple times to assign variables in Elixir:\n\n```elixir\niex> x = 1\n1\niex> x\n1\n```\n\nIn Elixir, the [`=`](`=/2`) operator is actually called *the match operator*. Let's see why:\n\n```elixir\niex> x = 1\n1\niex> 1 = x\n1\niex> 2 = x\n** (MatchError) no match of right hand side value: 1\n```\n\nNotice that `1 = x` is a valid expression, and it matched because both the left and right side are equal to `1`. When the sides do not match, a `MatchError` is raised.\n\nA variable can only be assigned on the left side of [`=`](`=/2`):\n\n```elixir\niex> 1 = unknown\n** (CompileError) iex:1: undefined variable \"unknown\"\n```\n\n## Pattern matching\n\nThe match operator is not only used to match against simple values, but it is also useful for destructuring more complex data types. For example, we can pattern match on tuples:\n\n```elixir\niex> {a, b, c} = {:hello, \"world\", 42}\n{:hello, \"world\", 42}\niex> a\n:hello\niex> b\n\"world\"\n```\n\nA pattern match error will occur if the sides can't be matched, for example if the tuples have different sizes:\n\n```elixir\niex> {a, b, c} = {:hello, \"world\"}\n** (MatchError) no match of right hand side value: {:hello, \"world\"}\n```\n\nAnd also when comparing different types, for example if matching a tuple on the left side with a list on the right side:\n\n```elixir\niex> {a, b, c} = [:hello, \"world\", 42]\n** (MatchError) no match of right hand side value: [:hello, \"world\", 42]\n```\n\nMore interestingly, we can match on specific values. The example below asserts that the left side will only match the right side when the right side is a tuple that starts with the atom `:ok`:\n\n```elixir\niex> {:ok, result} = {:ok, 13}\n{:ok, 13}\niex> result\n13\n\niex> {:ok, result} = {:error, :oops}\n** (MatchError) no match of right hand side value: {:error, :oops}\n```\n\nWe can pattern match on lists:\n\n```elixir\niex> [a, b, c] = [1, 2, 3]\n[1, 2, 3]\niex> a\n1\n```\n\nA list also supports matching on its own head and tail:\n\n```elixir\niex> [head | tail] = [1, 2, 3]\n[1, 2, 3]\niex> head\n1\niex> tail\n[2, 3]\n```\n\nSimilar to the [`hd`](`hd/1`) and [`tl`](`tl/1`) functions, we can't match an empty list with a head and tail pattern:\n\n```elixir\niex> [head | tail] = []\n** (MatchError) no match of right hand side value: []\n```\n\nThe `[head | tail]` format is not only used on pattern matching but also for prepending items to a list:\n\n```elixir\niex> list = [1, 2, 3]\n[1, 2, 3]\niex> [0 | list]\n[0, 1, 2, 3]\n```\n\nIn some cases, you don't care about a particular value in a pattern. It is a common practice to bind those values to the underscore, `_`. For example, if only the head of the list matters to us, we can assign the tail to underscore:\n\n```elixir\niex> [head | _] = [1, 2, 3]\n[1, 2, 3]\niex> head\n1\n```\n\nThe variable `_` is special in that it can never be read from. Trying to read from it gives a compile error:\n\n```elixir\niex> _\n** (CompileError) iex:1: invalid use of _. \"_\" represents a value to be ignored in a pattern and cannot be used in expressions\n```\n\nIf a variable is mentioned more than once in a pattern, all references must bind to the same value:\n\n```elixir\niex> {x, x} = {1, 1}\n{1, 1}\niex> {x, x} = {1, 2}\n** (MatchError) no match of right hand side value: {1, 2}\n```\n\nAlthough pattern matching allows us to build powerful constructs, its usage is limited. For instance, you cannot make function calls on the left side of a match. The following example is invalid:\n\n```elixir\niex> length([1, [2], 3]) = 3\n** (CompileError) iex:1: cannot invoke remote function :erlang.length/1 inside match\n```\n\nPattern matching allows developers to easily destructure data types such as tuples and lists. As we will see in the following chapters, it is one of the foundations of recursion in Elixir and applies to other types as well, like maps and binaries.\n\n## The pin operator\n\nVariables in Elixir can be rebound:\n\n```elixir\niex> x = 1\n1\niex> x = 2\n2\n```\n\nHowever, there are times when we don't want variables to be rebound.\n\nUse the pin operator [`^`](`^/1`) when you want to pattern match against a variable's *existing value* rather than rebinding the variable.\n\n```elixir\niex> x = 1\n1\niex> ^x = 2\n** (MatchError) no match of right hand side value: 2\n```\n\nBecause we have pinned `x` when it was bound to the value of `1`, it is equivalent to the following:\n\n```elixir\niex> 1 = 2\n** (MatchError) no match of right hand side value: 2\n```\n\nNotice that we even see the exact same error message.\n\nWe can use the pin operator inside other pattern matches, such as tuples or lists:\n\n```elixir\niex> x = 1\n1\niex> [^x, 2, 3] = [1, 2, 3]\n[1, 2, 3]\niex> {y, ^x} = {2, 1}\n{2, 1}\niex> y\n2\niex> {y, ^x} = {2, 2}\n** (MatchError) no match of right hand side value: {2, 2}\n```\n\nBecause `x` was bound to the value of `1` when it was pinned, this last example could have been written as:\n\n```elixir\niex> {y, 1} = {2, 2}\n** (MatchError) no match of right hand side value: {2, 2}\n```\n\nThis finishes our introduction to pattern matching. As we will see in the next chapter, pattern matching is very common in many language constructs and they can be further augmented with guards.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/processes.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Processes\n\nIn Elixir, all code runs inside processes. Processes are isolated from each other, run concurrent to one another and communicate via message passing. Processes are not only the basis for concurrency in Elixir, but they also provide the means for building distributed and fault-tolerant programs.\n\nElixir's processes should not be confused with operating system processes. Processes in Elixir are extremely lightweight in terms of memory and CPU (even compared to threads as used in many other programming languages). Because of this, it is not uncommon to have tens or even hundreds of thousands of processes running simultaneously.\n\nIn this chapter, we will learn about the basic constructs for spawning new processes, as well as sending and receiving messages between processes.\n\n## Spawning processes\n\nThe basic mechanism for spawning new processes is the auto-imported `spawn/1` function:\n\n```elixir\niex> spawn(fn -> 1 + 2 end)\n#PID<0.43.0>\n```\n\n`spawn/1` takes a function which it will execute in another process.\n\nNotice `spawn/1` returns a PID (process identifier). At this point, the process you spawned is very likely dead. The spawned process will execute the given function and exit after the function is done:\n\n```elixir\niex> pid = spawn(fn -> 1 + 2 end)\n#PID<0.44.0>\niex> Process.alive?(pid)\nfalse\n```\n\n> Note: you will likely get different process identifiers than the ones we are showing in our snippets.\n\nWe can retrieve the PID of the current process by calling `self/0`:\n\n```elixir\niex> self()\n#PID<0.41.0>\niex> Process.alive?(self())\ntrue\n```\n\nProcesses get much more interesting when we are able to send and receive messages.\n\n## Sending and receiving messages\n\nWe can send messages to a process with `send/2` and receive them with `receive/1`:\n\n```elixir\niex> send(self(), {:hello, \"world\"})\n{:hello, \"world\"}\niex> receive do\n...>   {:hello, msg} -> msg\n...>   {:world, _msg} -> \"won't match\"\n...> end\n\"world\"\n```\n\nWhen a message is sent to a process, the message is stored in the process mailbox. The `receive/1` block goes through the current process mailbox searching for a message that matches any of the given patterns. `receive/1` supports guards and many clauses, exactly as `case/2`.\n\nThe process that sends the message does not block on `send/2`, it puts the message in the recipient's mailbox and continues. In particular, a process can send messages to itself.\n\nIf there is no message in the mailbox matching any of the patterns, the current process will wait until a matching message arrives. A timeout can also be specified:\n\n```elixir\niex> receive do\n...>   {:hello, msg}  -> msg\n...> after\n...>   1_000 -> \"nothing after 1s\"\n...> end\n\"nothing after 1s\"\n```\n\nA timeout of 0 can be given when you already expect the message to be in the mailbox.\n\nLet's put it all together and send messages between processes:\n\n```elixir\niex> parent = self()\n#PID<0.41.0>\niex> spawn(fn -> send(parent, {:hello, self()}) end)\n#PID<0.48.0>\niex> receive do\n...>   {:hello, pid} -> \"Got hello from #{inspect pid}\"\n...> end\n\"Got hello from #PID<0.48.0>\"\n```\n\nThe `inspect/1` function is used to convert a data structure's internal representation into a string, typically for printing. Notice that when the `receive` block gets executed the sender process we have spawned may already be dead, as its only instruction was to send a message.\n\nWhile in the shell, you may find the helper `flush/0` quite useful. It flushes and prints all the messages in the mailbox.\n\n```elixir\niex> send(self(), :hello)\n:hello\niex> flush()\n:hello\n:ok\n```\n\n## Links\n\nThe majority of times we spawn processes in Elixir, we spawn them as linked processes. Before we show an example with `spawn_link/1`, let's see what happens when a process started with `spawn/1` fails:\n\n```elixir\niex> spawn(fn -> raise \"oops\" end)\n#PID<0.58.0>\n\n[error] Process #PID<0.58.00> raised an exception\n** (RuntimeError) oops\n    (stdlib) erl_eval.erl:668: :erl_eval.do_apply/6\n```\n\nIt merely logged an error but the parent process is still running. That's because processes are isolated. If we want the failure in one process to propagate to another one, we should link them. This can be done with `spawn_link/1`:\n\n```elixir\niex> self()\n#PID<0.41.0>\niex> spawn_link(fn -> raise \"oops\" end)\n\n** (EXIT from #PID<0.41.0>) evaluator process exited with reason: an exception was raised:\n    ** (RuntimeError) oops\n        (stdlib) erl_eval.erl:668: :erl_eval.do_apply/6\n\n[error] Process #PID<0.289.0> raised an exception\n** (RuntimeError) oops\n    (stdlib) erl_eval.erl:668: :erl_eval.do_apply/6\n```\n\nBecause processes are linked, we now see a message saying the parent process, which is the shell process, has received an EXIT signal from another process causing the shell to terminate. IEx detects this situation and starts a new shell session.\n\nLinking can also be done manually by calling `Process.link/1`. We recommend that you take a look at the `Process` module for other functionality provided by processes.\n\nProcesses and links play an important role when building fault-tolerant systems. Elixir processes are isolated and don't share anything by default. Therefore, a failure in a process will never crash or corrupt the state of another process. Links, however, allow processes to establish a relationship in case of failure. We often link our processes to supervisors which will detect when a process dies and start a new process in its place.\n\nWhile other languages would require us to catch/handle exceptions, in Elixir we are actually fine with letting processes fail because we expect supervisors to properly restart our systems. \"Failing fast\" (sometimes referred as \"let it crash\") is a common philosophy when writing Elixir software!\n\n`spawn/1` and `spawn_link/1` are the basic primitives for creating processes in Elixir. Although we have used them exclusively so far, most of the time we are going to use abstractions that build on top of them. Let's see the most common one, called tasks.\n\n## Tasks\n\nTasks build on top of the spawn functions to provide better error reports and introspection:\n\n```elixir\niex> Task.start(fn -> raise \"oops\" end)\n{:ok, #PID<0.55.0>}\n\n15:22:33.046 [error] Task #PID<0.55.0> started from #PID<0.53.0> terminating\n** (RuntimeError) oops\n    (stdlib) erl_eval.erl:668: :erl_eval.do_apply/6\n    (elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2\n    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3\nFunction: #Function<20.99386804/0 in :erl_eval.expr/5>\n    Args: []\n```\n\nInstead of `spawn/1` and `spawn_link/1`, we use `Task.start/1` and `Task.start_link/1` which return `{:ok, pid}` rather than just the PID. This is what enables tasks to be used in supervision trees. Furthermore, `Task` provides convenience functions, like `Task.async/1` and `Task.await/1`, and functionality to ease distribution.\n\nWe will explore tasks and other abstractions around processes in the [\"Mix and OTP guide\"](../mix-and-otp/introduction-to-mix.md).\n\n## State\n\nWe haven't talked about state so far. If you are building an application that requires state, for example, to keep your application configuration, or you need to parse a file and keep it in memory, where would you store it?\n\nProcesses are the most common answer to this question. We can write processes that loop infinitely, maintain state, and send and receive messages. As an example, let's write a module that starts new processes that work as a key-value store in a file named `kv.exs`:\n\n```elixir\ndefmodule KV do\n  def start_link do\n    Task.start_link(fn -> loop(%{}) end)\n  end\n\n  defp loop(map) do\n    receive do\n      {:get, key, caller} ->\n        send(caller, Map.get(map, key))\n        loop(map)\n      {:put, key, value} ->\n        loop(Map.put(map, key, value))\n    end\n  end\nend\n```\n\nNote that the `start_link` function starts a new process that runs the `loop/1` function, starting with an empty map. The `loop/1` (private) function then waits for messages and performs the appropriate action for each message. We made `loop/1` private by using `defp` instead of `def`. In the case of a `:get` message, it sends a message back to the caller and calls `loop/1` again, to wait for a new message. While the `:put` message actually invokes `loop/1` with a new version of the map, with the given `key` and `value` stored.\n\nLet's give it a try by running `iex kv.exs`:\n\n```elixir\niex> {:ok, pid} = KV.start_link()\n{:ok, #PID<0.62.0>}\niex> send(pid, {:get, :hello, self()})\n{:get, :hello, #PID<0.41.0>}\niex> flush()\nnil\n:ok\n```\n\nAt first, the process map has no keys, so sending a `:get` message and then flushing the current process inbox returns `nil`. Let's send a `:put` message and try it again:\n\n```elixir\niex> send(pid, {:put, :hello, :world})\n{:put, :hello, :world}\niex> send(pid, {:get, :hello, self()})\n{:get, :hello, #PID<0.41.0>}\niex> flush()\n:world\n:ok\n```\n\nNotice how the process is keeping a state and we can get and update this state by sending the process messages. In fact, any process that knows the `pid` above will be able to send it messages and manipulate the state.\n\nIt is also possible to register the `pid`, giving it a name, and allowing everyone that knows the name to send it messages:\n\n```elixir\niex> Process.register(pid, :kv)\ntrue\niex> send(:kv, {:get, :hello, self()})\n{:get, :hello, #PID<0.41.0>}\niex> flush()\n:world\n:ok\n```\n\nUsing processes to maintain state and name registration are very common patterns in Elixir applications. However, most of the time, we won't implement those patterns manually as above, but by using one of the many abstractions that ship with Elixir. For example, Elixir provides `Agent`s, which are simple abstractions around state. Our code above could be directly written as:\n\n```elixir\niex> {:ok, pid} = Agent.start_link(fn -> %{} end)\n{:ok, #PID<0.72.0>}\niex> Agent.update(pid, fn map -> Map.put(map, :hello, :world) end)\n:ok\niex> Agent.get(pid, fn map -> Map.get(map, :hello) end)\n:world\n```\n\nA `:name` option could also be given to `Agent.start_link/2` and it would be automatically registered. Besides agents, Elixir provides an API for building generic servers (called `GenServer`), registries, and more, all powered by processes underneath. Those, along with supervision trees, will be explored with more detail in the [\"Mix and OTP guide\"](../mix-and-otp/introduction-to-mix.md), which will build a complete Elixir application from start to finish.\n\nFor now, let's move on and explore the world of I/O in Elixir.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/protocols.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Protocols\n\nProtocols are a mechanism to achieve polymorphism in Elixir where you want the behavior to vary depending on the data type. We are already familiar with one way of solving this type of problem: via pattern matching and guard clauses. Consider a simple utility module that would tell us the type of input variable:\n\n```elixir\ndefmodule Utility do\n  def type(value) when is_binary(value), do: \"string\"\n  def type(value) when is_integer(value), do: \"integer\"\n  # ... other implementations ...\nend\n```\n\nIf the use of this module were confined to your own project, you would be able to keep defining new `type/1` functions for each new data type. However, this code could be problematic if it was shared as a dependency by multiple apps because there would be no easy way to extend its functionality.\n\nThis is where protocols can help us: protocols allow us to extend the original behavior for as many data types as we need. That's because **dispatching on a protocol is available to any data type that has implemented the protocol** and a protocol can be implemented by anyone, at any time.\n\nHere's how we could write the same `Utility.type/1` functionality as a protocol:\n\n```elixir\ndefprotocol Utility do\n  @spec type(t) :: String.t()\n  def type(value)\nend\n\ndefimpl Utility, for: BitString do\n  def type(_value), do: \"string\"\nend\n\ndefimpl Utility, for: Integer do\n  def type(_value), do: \"integer\"\nend\n```\n\nWe define the protocol using `defprotocol/2` - its functions and specs may look similar to interfaces or abstract base classes in other languages. We can add as many implementations as we like using `defimpl/2`. The output is exactly the same as if we had a single module with multiple functions:\n\n```elixir\niex> Utility.type(\"foo\")\n\"string\"\niex> Utility.type(123)\n\"integer\"\n```\n\nWith protocols, however, we are no longer stuck having to continuously modify the same module to support more and more data types. For example, we could spread the `defimpl` calls above over multiple files and Elixir will dispatch the execution to the appropriate implementation based on the data type. Functions defined in a protocol may have more than one input, but the **dispatching will always be based on the data type of the first input**.\n\nOne of the most common protocols you may encounter is the `String.Chars` protocol: implementing its `to_string/1` function for your custom structs will tell the Elixir kernel how to represent them as strings. We will explore all the built-in protocols later. For now, let's implement our own.\n\n## Example\n\nNow that you have seen an example of the type of problem protocols help solve and how they solve them, let's look at a more in-depth example.\n\nIn Elixir, we have two idioms for checking how many items there are in a data structure: `length` and `size`. `length` means the information must be computed. For example, `length(list)` needs to traverse the whole list to calculate its length. On the other hand, `tuple_size(tuple)` and `byte_size(binary)` do not depend on the tuple and binary size as the size information is pre-computed in the data structure.\n\nEven if we have type-specific functions for getting the size built into Elixir (such as `tuple_size/1`), we could implement a generic `Size` protocol that all data structures for which size is pre-computed would implement.\n\nThe protocol definition would look like this:\n\n```elixir\ndefprotocol Size do\n  @doc \"Calculates the size (and not the length!) of a data structure\"\n  def size(data)\nend\n```\n\nThe `Size` protocol expects a function called `size` that receives one argument (the data structure we want to know the size of) to be implemented. We can now implement this protocol for the data structures that would have a compliant implementation:\n\n```elixir\ndefimpl Size, for: BitString do\n  def size(string), do: byte_size(string)\nend\n\ndefimpl Size, for: Map do\n  def size(map), do: map_size(map)\nend\n\ndefimpl Size, for: Tuple do\n  def size(tuple), do: tuple_size(tuple)\nend\n```\n\nWe didn't implement the `Size` protocol for lists as there is no \"size\" information pre-computed for lists, and the length of a list has to be computed (with `length/1`).\n\nNow with the protocol defined and implementations in hand, we can start using it:\n\n```elixir\niex> Size.size(\"foo\")\n3\niex> Size.size({:ok, \"hello\"})\n2\niex> Size.size(%{label: \"some label\"})\n1\n```\n\nPassing a data type that doesn't implement the protocol raises an error:\n\n```elixir\niex> Size.size([1, 2, 3])\n** (Protocol.UndefinedError) protocol Size not implemented for [1, 2, 3] of type List\n```\n\nIt's possible to implement protocols for all Elixir data types:\n\n  * `Atom`\n  * `BitString`\n  * `Float`\n  * `Function`\n  * `Integer`\n  * `List`\n  * `Map`\n  * `PID`\n  * `Port`\n  * `Reference`\n  * `Tuple`\n\n## Protocols and structs\n\nThe power of Elixir's extensibility comes when protocols and structs are used together.\n\nIn the [previous chapter](structs.md), we have learned that although structs are maps, they do not share protocol implementations with maps. For example, `MapSet`s (sets based on maps) are implemented as structs. Let's try to use the `Size` protocol with a `MapSet`:\n\n```elixir\niex> Size.size(%{})\n0\niex> set = %MapSet{} = MapSet.new\nMapSet.new([])\niex> Size.size(set)\n** (Protocol.UndefinedError) protocol Size not implemented for MapSet.new([]) of type MapSet (a struct)\n```\n\nInstead of sharing protocol implementation with maps, structs require their own protocol implementation. Since a `MapSet` has its size precomputed and accessible through `MapSet.size/1`, we can define a `Size` implementation for it:\n\n```elixir\ndefimpl Size, for: MapSet do\n  def size(set), do: MapSet.size(set)\nend\n```\n\nIf desired, you could come up with your own semantics for the size of your struct. Not only that, you could use structs to build more robust data types, like queues, and implement all relevant protocols, such as `Enumerable` and possibly `Size`, for this data type.\n\n```elixir\ndefmodule User do\n  defstruct [:name, :age]\nend\n\ndefimpl Size, for: User do\n  def size(_user), do: 2\nend\n```\n\n## Implementing `Any`\n\nManually implementing protocols for all types can quickly become repetitive and tedious. In such cases, Elixir provides two options: we can explicitly derive the protocol implementation for our types or automatically implement the protocol for all types. In both cases, we need to implement the protocol for `Any`.\n\n### Deriving\n\nElixir allows us to derive a protocol implementation based on the `Any` implementation. Let's first implement `Any` as follows:\n\n```elixir\ndefimpl Size, for: Any do\n  def size(_), do: 0\nend\n```\n\nThe implementation above is arguably not a reasonable one. For example, it makes no sense to say that the size of a `PID` or an `Integer` is `0`.\n\nHowever, should we be fine with the implementation for `Any`, in order to use such implementation we would need to tell our struct to explicitly derive the `Size` protocol:\n\n```elixir\ndefmodule OtherUser do\n  @derive [Size]\n  defstruct [:name, :age]\nend\n```\n\nWhen deriving, Elixir will implement the `Size` protocol for `OtherUser` based on the implementation provided for `Any`.\n\n### Fallback to `Any`\n\nAnother alternative to `@derive` is to explicitly tell the protocol to fallback to `Any` when an implementation cannot be found. This can be achieved by setting `@fallback_to_any` to `true` in the protocol definition:\n\n```elixir\ndefprotocol Size do\n  @fallback_to_any true\n  def size(data)\nend\n```\n\nAs we said in the previous section, the implementation of `Size` for `Any` is not one that can apply to any data type. That's one of the reasons why `@fallback_to_any` is an opt-in behavior. For the majority of protocols, raising an error when a protocol is not implemented is the proper behavior. That said, assuming we have implemented `Any` as in the previous section:\n\n```elixir\ndefimpl Size, for: Any do\n  def size(_), do: 0\nend\n```\n\nNow all data types (including structs) that have not implemented the `Size` protocol will be considered to have a size of `0`.\n\nWhich technique is best between deriving and falling back to `Any` depends on the use case but, given Elixir developers prefer explicit over implicit, you may see many libraries pushing towards the `@derive` approach.\n\n## Built-in protocols\n\nElixir ships with some built-in protocols. In previous chapters, we have discussed the `Enum` module which provides many functions that work with any data structure that implements the `Enumerable` protocol:\n\n```elixir\niex> Enum.map([1, 2, 3], fn x -> x * 2 end)\n[2, 4, 6]\niex> Enum.reduce(1..3, 0, fn x, acc -> x + acc end)\n6\n```\n\nAnother useful example is the `String.Chars` protocol, which specifies how to convert a data structure to its human representation as a string. It's exposed via the `to_string` function:\n\n```elixir\niex> to_string(:hello)\n\"hello\"\n```\n\nNotice that string interpolation in Elixir calls the `to_string` function:\n\n```elixir\niex> \"age: #{25}\"\n\"age: 25\"\n```\n\nThe snippet above only works because numbers implement the `String.Chars` protocol. Passing a tuple, for example, will lead to an error:\n\n```elixir\niex> tuple = {1, 2, 3}\n{1, 2, 3}\niex> \"tuple: #{tuple}\"\n** (Protocol.UndefinedError) protocol String.Chars not implemented for {1, 2, 3} of type Tuple\n```\n\nWhen there is a need to \"print\" a more complex data structure, one can use the `inspect` function, based on the `Inspect` protocol:\n\n```elixir\niex> \"tuple: #{inspect(tuple)}\"\n\"tuple: {1, 2, 3}\"\n```\n\nThe `Inspect` protocol is the protocol used to transform any data structure into a readable textual representation. This is what tools like IEx use to print results:\n\n```elixir\niex> {1, 2, 3}\n{1, 2, 3}\niex> %User{}\n%User{name: \"john\", age: 27}\n```\n\nKeep in mind that, by convention, whenever the inspected value starts with `#`, it is representing a data structure in non-valid Elixir syntax. This means the inspect protocol is not reversible as information may be lost along the way:\n\n```elixir\niex> inspect &(&1+2)\n\"#Function<6.71889879/1 in :erl_eval.expr/5>\"\n```\n\nThere are other protocols in Elixir, but this covers the most common ones. You can learn more about protocols and implementations in the `Protocol` module.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/recursion.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Recursion\n\nElixir does not provide loop constructs. Instead we leverage recursion and high-level functions for working with collections. This chapter will explore the former.\n\n## Loops through recursion\n\nDue to immutability, loops in Elixir (as in any functional programming language) are written differently from imperative languages. For example, in an imperative language like C, one would write:\n\n```c\nfor(i = 0; i < sizeof(array); i++) {\n  array[i] = array[i] * 2;\n}\n```\n\nIn the example above, we are mutating both the array and the variable `i`. However, data structures in Elixir are immutable. For this reason, functional languages rely on recursion: a function is called recursively until a condition is reached that stops the recursive action from continuing. No data is mutated in this process. Consider the example below that prints a string an arbitrary number of times:\n\n```elixir\ndefmodule Recursion do\n  def print_multiple_times(msg, n) when n > 0 do\n    IO.puts(msg)\n    print_multiple_times(msg, n - 1)\n  end\n\n  def print_multiple_times(_msg, 0) do\n    :ok\n  end\nend\n\nRecursion.print_multiple_times(\"Hello!\", 3)\n# Hello!\n# Hello!\n# Hello!\n:ok\n```\n\nSimilar to `case`, a function may have many clauses. A particular clause is executed when the arguments passed to the function match the clause's argument patterns and its guards evaluate to `true`.\n\nWhen `print_multiple_times/2` is initially called in the example above, the argument `n` is equal to `3`.\n\nThe first clause has a guard which says \"use this definition if and only if `n` is more than `0`\". Since this is the case, it prints the `msg` and then calls itself passing `n - 1` (`2`) as the second argument.\n\nNow we execute the same function again, starting from the first clause. Given the second argument, `n`, is still more than 0, we print the message and call ourselves once more, now with the second argument set to `1`. Then we print the message one last time and call `print_multiple_times(\"Hello!\", 0)`, starting from the top once again.\n\nWhen the second argument is zero, the guard `n > 0` evaluates to false, and the first function clause won't execute. Elixir then proceeds to try the next function clause, which explicitly matches on the case where `n` is `0`. This clause, also known as the termination clause, ignores the message argument by assigning it to the `_msg` variable and returns the atom `:ok`.\n\nFinally, if you pass an argument that does not match any clause, Elixir raises a `FunctionClauseError`:\n\n```elixir\niex> Recursion.print_multiple_times(\"Hello!\", -1)\n** (FunctionClauseError) no function clause matching in Recursion.print_multiple_times/2\n\n    The following arguments were given to Recursion.print_multiple_times/2:\n\n        # 1\n        \"Hello!\"\n\n        # 2\n        -1\n\n    iex:1: Recursion.print_multiple_times/2\n```\n\n## Reduce and map algorithms\n\nLet's now see how we can use the power of recursion to sum a list of numbers:\n\n```elixir\ndefmodule Math do\n  def sum_list([head | tail], accumulator) do\n    sum_list(tail, head + accumulator)\n  end\n\n  def sum_list([], accumulator) do\n    accumulator\n  end\nend\n\nIO.puts Math.sum_list([1, 2, 3], 0) #=> 6\n```\n\nWe invoke `sum_list` with the list `[1, 2, 3]` and the initial value `0` as arguments. We will try each clause until we find one that matches according to the pattern matching rules. In this case, the list `[1, 2, 3]` matches against `[head | tail]` which binds `head` to `1` and `tail` to `[2, 3]`; `accumulator` is set to `0`.\n\nThen, we add the head of the list to the accumulator `head + accumulator` and call `sum_list` again, recursively, passing the tail of the list as its first argument. The tail will once again match `[head | tail]` until the list is empty, as seen below:\n\n```elixir\nsum_list([1, 2, 3], 0)\nsum_list([2, 3], 1)\nsum_list([3], 3)\nsum_list([], 6)\n```\n\nWhen the list is empty, it will match the final clause which returns the final result of `6`.\n\nThe process of taking a list and _reducing_ it down to one value is known as a _reduce algorithm_ and is central to functional programming.\n\nWhat if we instead want to double all of the values in our list?\n\n```elixir\ndefmodule Math do\n  def double_each([head | tail]) do\n    [head * 2 | double_each(tail)]\n  end\n\n  def double_each([]) do\n    []\n  end\nend\n\nMath.double_each([1, 2, 3]) #=> [2, 4, 6]\n```\n\nHere we have used recursion to traverse a list, doubling each element and returning a new list. The process of taking a list and _mapping_ over it is known as a _map algorithm_.\n\nRecursion and [tail call](https://en.wikipedia.org/wiki/Tail_call) optimization are an important part of Elixir and are commonly used to create loops. However, when programming in Elixir you will rarely use recursion as above to manipulate lists.\n\nThe `Enum` module, which we're going to see in the next chapter already provides many conveniences for working with lists. For instance, the examples above could be written as:\n\n```elixir\niex> Enum.reduce([1, 2, 3], 0, fn x, acc -> x + acc end)\n6\niex> Enum.map([1, 2, 3], fn x -> x * 2 end)\n[2, 4, 6]\n```\n\nOr, using the [capture syntax](`Kernel.SpecialForms.&/1`):\n\n```elixir\niex> Enum.reduce([1, 2, 3], 0, &+/2)\n6\niex> Enum.map([1, 2, 3], &(&1 * 2))\n[2, 4, 6]\n```\n\nLet's take a deeper look at `Enumerable` and, while we're at it, its lazy counterpart, `Stream`.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/sigils.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Sigils\n\nElixir provides double-quoted strings as well as a concept called charlists, which are defined using the `~c\"hello world\"` sigil syntax. In this chapter, we will learn more about sigils and how to define our own.\n\nOne of Elixir's goals is extensibility: developers should be able to extend the language to fit any particular domain. Sigils provide the foundation for extending the language with custom textual representations. Sigils start with the tilde (`~`) character which is followed by either a single lower-case letter or one or more upper-case letters, and then a delimiter. Optional modifiers are added after the final delimiter.\n\n## Regular expressions\n\nThe most common sigil in Elixir is `~r`, which is used to create [regular expressions](https://en.wikipedia.org/wiki/Regular_Expressions):\n\n```elixir\n# A regular expression that matches strings which contain \"foo\" or \"bar\":\niex> regex = ~r/foo|bar/\n~r/foo|bar/\niex> \"foo\" =~ regex\ntrue\niex> \"bat\" =~ regex\nfalse\n```\n\nElixir provides Perl-compatible regular expressions (regexes), as implemented by the [PCRE](https://www.pcre.org/) library. Regexes also support modifiers. For example, the `i` modifier makes a regular expression case insensitive:\n\n```elixir\niex> \"HELLO\" =~ ~r/hello/\nfalse\niex> \"HELLO\" =~ ~r/hello/i\ntrue\n```\n\nCheck out the `Regex` module for more information on other modifiers and the supported operations with regular expressions.\n\nSo far, all examples have used `/` to delimit a regular expression. However, sigils support 8 different delimiters:\n\n```elixir\n~r/hello/\n~r|hello|\n~r\"hello\"\n~r'hello'\n~r(hello)\n~r[hello]\n~r{hello}\n~r<hello>\n```\n\nThe reason behind supporting different delimiters is to provide a way to write literals without escaped delimiters. For example, a regular expression with forward slashes like `~r(^https?://)` reads arguably better than `~r/^https?:\\/\\//`. Similarly, if the regular expression has forward slashes and capturing groups (that use `()`), you may then choose double quotes instead of parentheses.\n\n## Strings, charlists, and word lists sigils\n\nElixir ships with three sigils for building textual data structures. These allow you to choose an appropriate delimiter for your literal text such that you do not have to worry about escaping.\n\n### Strings\n\nThe `~s` sigil is used to generate strings, like double quotes are. The `~s` sigil is useful when a string contains double quotes:\n\n```elixir\niex> ~s(this is a string with \"double\" quotes, not 'single' ones)\n\"this is a string with \\\"double\\\" quotes, not 'single' ones\"\n```\n\n### Charlists\n\nThe `~c` sigil is the regular way to represent charlists.\n\n```elixir\niex> [?c, ?a, ?t]\n~c\"cat\"\niex> ~c(this is a char list containing \"double quotes\")\n~c\"this is a char list containing \\\"double quotes\\\"\"\n```\n\n### Word lists\n\nThe `~w` sigil is used to generate lists of words (*words* are just regular strings). Inside the `~w` sigil, words are separated by whitespace.\n\n```elixir\niex> ~w(foo bar bat)\n[\"foo\", \"bar\", \"bat\"]\n```\n\nThe `~w` sigil also accepts the `c`, `s` and `a` modifiers (for charlists, strings, and atoms, respectively), which specify the data type of the elements of the resulting list:\n\n```elixir\niex> ~w(foo bar bat)a\n[:foo, :bar, :bat]\n```\n\n## Interpolation and escaping in textual sigils\n\nSigils also help deal with escaping characters and interpolation. In particular, uppercase-letter textual sigils do not perform interpolation nor escaping, and most lowercase sigils have an uppercase variant. For example, although both `~s` and `~S` will return strings, the former allows escape codes and interpolation while the latter does not:\n\n```elixir\niex> ~s(String with escape codes \\x26 #{\"inter\" <> \"polation\"})\n\"String with escape codes & interpolation\"\niex> ~S(String without escape codes \\x26 without #{interpolation})\n\"String without escape codes \\\\x26 without \\#{interpolation}\"\n```\n\nThe following escape codes can be used in textual sigils:\n\n  * `\\\\` – single backslash\n  * `\\a` – bell/alert\n  * `\\b` – backspace\n  * `\\d` - delete\n  * `\\e` - escape\n  * `\\f` - form feed\n  * `\\n` – newline\n  * `\\r` – carriage return\n  * `\\s` – space\n  * `\\t` – tab\n  * `\\v` – vertical tab\n  * `\\0` - null byte\n  * `\\xDD` - represents a single byte in hexadecimal (such as `\\x13`)\n  * `\\uDDDD` and `\\u{D...}` - represents a Unicode codepoint in hexadecimal (such as `\\u{1F600}`)\n\nSigils also support heredocs, that is, three double-quotes or single-quotes as separators:\n\n```elixir\niex> ~s\"\"\"\n...> this is\n...> a heredoc string\n...> \"\"\"\n```\n\nThe most common use case for heredoc sigils is when writing documentation. For example, writing escape characters in the documentation would soon become error prone because of the need to double-escape some characters:\n\n```elixir\n@doc \"\"\"\nConverts double-quotes to single-quotes.\n\n## Examples\n\n    iex> convert(\"\\\\\\\"foo\\\\\\\"\")\n    \"'foo'\"\n\n\"\"\"\ndef convert(...)\n```\n\nBy using `~S`, this problem can be avoided altogether:\n\n```elixir\n@doc ~S\"\"\"\nConverts double-quotes to single-quotes.\n\n## Examples\n\n    iex> convert(\"\\\"foo\\\"\")\n    \"'foo'\"\n\n\"\"\"\ndef convert(...)\n```\n\n## Calendar sigils\n\nElixir offers sigils to deal with various flavors of times and dates.\n\n### Date\n\nA [%Date{}](`Date`) struct contains the fields `year`, `month`, `day`, and `calendar`. You can create one using the `~D` sigil:\n\n```elixir\niex> d = ~D[2019-10-31]\n~D[2019-10-31]\niex> d.day\n31\n```\n\n### Time\n\nThe [%Time{}](`Time`) struct contains the fields `hour`, `minute`, `second`, `microsecond`, and `calendar`. You can create one using the `~T` sigil:\n\n```elixir\niex> t = ~T[23:00:07.0]\n~T[23:00:07.0]\niex> t.second\n7\n```\n\n### NaiveDateTime\n\nThe [%NaiveDateTime{}](`NaiveDateTime`) struct contains fields from both `Date` and `Time`. You can create one using the `~N` sigil:\n\n```elixir\niex> ndt = ~N[2019-10-31 23:00:07]\n~N[2019-10-31 23:00:07]\n```\n\nWhy is it called naive? Because it does not contain timezone information. Therefore, the given datetime may not exist at all or it may exist twice in certain timezones - for example, when we move the clock back and forward for daylight saving time.\n\n### UTC DateTime\n\nA [%DateTime{}](`DateTime`) struct contains the same fields as a `NaiveDateTime` with the addition of fields to track timezones. The `~U` sigil allows developers to create a DateTime in the UTC timezone:\n\n```elixir\niex> dt = ~U[2019-10-31 19:59:03Z]\n~U[2019-10-31 19:59:03Z]\niex> %DateTime{minute: minute, time_zone: time_zone} = dt\n~U[2019-10-31 19:59:03Z]\niex> minute\n59\niex> time_zone\n\"Etc/UTC\"\n```\n\n## Custom sigils\n\nAs hinted at the beginning of this chapter, sigils in Elixir are extensible. In fact, using the sigil `~r/foo/i` is equivalent to calling `sigil_r` with a binary and a char list as the argument:\n\n```elixir\niex> sigil_r(<<\"foo\">>, [?i])\n~r\"foo\"i\n```\n\nWe can access the documentation for the `~r` sigil via `sigil_r`:\n\n```elixir\niex> h sigil_r\n...\n```\n\nWe can also provide our own sigils by implementing functions that follow the `sigil_{character}` pattern. For example, let's implement the `~i` sigil that returns an integer (with the optional `n` modifier to make it negative):\n\n```elixir\niex> defmodule MySigils do\n...>   def sigil_i(string, []), do: String.to_integer(string)\n...>   def sigil_i(string, [?n]), do: -String.to_integer(string)\n...> end\niex> import MySigils\niex> ~i(13)\n13\niex> ~i(42)n\n-42\n```\n\nCustom sigils may be either a single lowercase character, or an uppercase character followed by more uppercase characters and digits. In practice, they are often used to embed templating languages or even represent regular languages within Elixir itself. If you're interested in learning more, check out how sigils are implemented in the `Kernel` module (where the `sigil_*` functions/macros are defined) for a starting point.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/structs.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Structs\n\nWe learned about maps [in earlier chapters](keywords-and-maps.md):\n\n```elixir\niex> map = %{a: 1, b: 2}\n%{a: 1, b: 2}\niex> map[:a]\n1\niex> %{map | a: 3}\n%{a: 3, b: 2}\n```\n\nStructs are extensions built on top of maps that provide compile-time checks and default values.\n\n## Defining structs\n\nTo define a struct, the `defstruct/1` construct is used:\n\n```elixir\niex> defmodule User do\n...>   defstruct name: \"John\", age: 27\n...> end\n```\n\nThe keyword list used with `defstruct` defines what fields the struct will have along with their default values. Structs take the name of the module they're defined in. In the example above, we defined a struct named `User`.\n\nWe can now create `User` structs by using a syntax similar to the one used to create maps:\n\n```elixir\niex> %User{}\n%User{age: 27, name: \"John\"}\niex> %User{name: \"Jane\"}\n%User{age: 27, name: \"Jane\"}\n```\n\nStructs provide *compile-time* guarantees that only the fields defined through `defstruct` will be allowed to exist in a struct:\n\n```elixir\niex> %User{oops: :field}\n** (KeyError) key :oops not found expanding struct: User.__struct__/1\n```\n\n## Accessing and updating structs\n\nStructs share the same syntax for accessing and updating fields as maps of fixed keys:\n\n```elixir\niex> john = %User{}\n%User{age: 27, name: \"John\"}\niex> john.name\n\"John\"\niex> jane = %{john | name: \"Jane\"}\n%User{age: 27, name: \"Jane\"}\niex> %{jane | oops: :field}\n** (KeyError) key :oops not found in: %User{age: 27, name: \"Jane\"}\n```\n\nWhen using the update syntax (`|`), Elixir is aware that no new keys will be added to the struct, allowing the maps underneath to share their structure in memory. In the example above, both `john` and `jane` share the same key structure in memory.\n\nStructs can also be used in pattern matching, both for matching on the value of specific keys as well as for ensuring that the matching value is a struct of the same type as the matched value.\n\n```elixir\niex> %User{name: name} = john\n%User{age: 27, name: \"John\"}\niex> name\n\"John\"\niex> %User{} = %{}\n** (MatchError) no match of right hand side value: %{}\n```\n\nFor more details on creating, updating, and pattern matching structs, see the documentation for `%/2`.\n\n## Dynamic struct updates\n\nWhen you need to update structs with data from keyword lists or maps, use `Kernel.struct!/2`:\n\n```elixir\niex> john = %User{name: \"John\", age: 27}\n%User{age: 27, name: \"John\"}\niex> updates = [name: \"Jane\", age: 30]\n[name: \"Jane\", age: 30]\niex> struct!(john, updates)\n%User{age: 30, name: \"Jane\"}\n```\n\n`struct!/2` will raise an error if you try to set invalid fields:\n\n```elixir\niex> struct!(john, invalid: \"field\")\n** (KeyError) key :invalid not found in: %User{age: 27, name: \"John\"}\n```\n\nUse the map update syntax (`%{john | name: \"Jane\"}`) when you know the exact fields at compile time. Always use `struct!/2` instead of `Map` functions to preserve struct integrity.\n\n## Structs are bare maps underneath\n\nStructs are simply maps with a \"special\" field named `__struct__` that holds the name of the struct:\n\n```elixir\niex> is_map(john)\ntrue\niex> john.__struct__\nUser\n```\n\nHowever, structs do not inherit any of the protocols that maps do. For example, you can neither enumerate nor access a struct:\n\n```elixir\niex> john = %User{}\n%User{age: 27, name: \"John\"}\niex> john[:name]\n** (UndefinedFunctionError) function User.fetch/2 is undefined (User does not implement the Access behaviour)\n             User.fetch(%User{age: 27, name: \"John\"}, :name)\niex> Enum.each(john, fn {field, value} -> IO.puts(value) end)\n** (Protocol.UndefinedError) protocol Enumerable not implemented for %User{age: 27, name: \"John\"} of type User (a struct)\n```\n\nStructs alongside protocols provide one of the most important features for Elixir developers: data polymorphism. That's what we will explore in the next chapter.\n\n## Default values and required keys\n\nIf you don't specify a default key value when defining a struct, `nil` will be assumed:\n\n```elixir\niex> defmodule Product do\n...>   defstruct [:name]\n...> end\niex> %Product{}\n%Product{name: nil}\n```\n\nYou can define a structure combining both fields with explicit default values, and implicit `nil` values. In this case you must first specify the fields which implicitly default to `nil`:\n\n```elixir\niex> defmodule User do\n...>   defstruct [:email, name: \"John\", age: 27]\n...> end\niex> %User{}\n%User{age: 27, email: nil, name: \"John\"}\n```\n\nDoing it in reverse order will raise a syntax error:\n\n```elixir\niex> defmodule User do\n...>   defstruct [name: \"John\", age: 27, :email]\n...> end\n** (SyntaxError) iex:107: unexpected expression after keyword list. Keyword lists must always come last in lists and maps.\n```\n\nYou can also enforce that certain keys have to be specified when creating the struct via the `@enforce_keys` module attribute:\n\n```elixir\niex> defmodule Car do\n...>   @enforce_keys [:make]\n...>   defstruct [:model, :make]\n...> end\niex> %Car{}\n** (ArgumentError) the following keys must also be given when building struct Car: [:make]\n    expanding struct: Car.__struct__/1\n```\n\nEnforcing keys provides a simple compile-time guarantee to aid developers when building structs. It is not enforced on updates and it does not provide any sort of value-validation.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/try-catch-and-rescue.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# try, catch, and rescue\n\nElixir has three error mechanisms: errors, throws, and exits. In this chapter, we will explore each of them and include remarks about when each should be used.\n\n## Errors\n\nErrors (or *exceptions*) are used when exceptional things happen in the code. A sample error can be retrieved by trying to add a number to an atom:\n\n```elixir\niex> :foo + 1\n** (ArithmeticError) bad argument in arithmetic expression\n     :erlang.+(:foo, 1)\n```\n\nA runtime error can be raised any time by using `raise/1`:\n\n```elixir\niex> raise \"oops\"\n** (RuntimeError) oops\n```\n\nOther errors can be raised with `raise/2` passing the error name and a list of keyword arguments:\n\n```elixir\niex> raise ArgumentError, message: \"invalid argument foo\"\n** (ArgumentError) invalid argument foo\n```\n\nYou can also define your own errors by creating a module and using the `defexception/1` construct inside it. This way, you'll create an error with the same name as the module it's defined in. The most common case is to define a custom exception with a message field:\n\n```elixir\niex> defmodule MyError do\niex>   defexception message: \"default message\"\niex> end\niex> raise MyError\n** (MyError) default message\niex> raise MyError, message: \"custom message\"\n** (MyError) custom message\n```\n\nErrors can be **rescued** using the `try/rescue` construct:\n\n```elixir\niex> try do\n...>   raise \"oops\"\n...> rescue\n...>   e in RuntimeError -> e\n...> end\n%RuntimeError{message: \"oops\"}\n```\n\nThe example above rescues the runtime error and returns the exception itself, which is then printed in the `iex` session.\n\nIf you don't have any use for the exception, you don't have to pass a variable to `rescue`:\n\n```elixir\niex> try do\n...>   raise \"oops\"\n...> rescue\n...>   RuntimeError -> \"Error!\"\n...> end\n\"Error!\"\n```\n\nIn practice, Elixir developers rarely use the `try/rescue` construct. For example, many languages would force you to rescue an error when a file cannot be opened successfully. Elixir instead provides a `File.read/1` function which returns a tuple containing information about whether the file was opened successfully:\n\n```elixir\niex> File.read(\"hello\")\n{:error, :enoent}\niex> File.write(\"hello\", \"world\")\n:ok\niex> File.read(\"hello\")\n{:ok, \"world\"}\n```\n\nThere is no `try/rescue` here. In case you want to handle multiple outcomes of opening a file, you can use pattern matching using the `case` construct:\n\n```elixir\niex> case File.read(\"hello\") do\n...>   {:ok, body} -> IO.puts(\"Success: #{body}\")\n...>   {:error, reason} -> IO.puts(\"Error: #{reason}\")\n...> end\n```\n\nFor the cases where you do expect a file to exist (and the lack of that file is truly an *error*) you may use `File.read!/1`:\n\n```elixir\niex> File.read!(\"unknown\")\n** (File.Error) could not read file \"unknown\": no such file or directory\n    (elixir) lib/file.ex:272: File.read!/1\n```\n\nAt the end of the day, it's up to your application to decide if an error while opening a file is exceptional or not. That's why Elixir doesn't impose exceptions on `File.read/1` and many other functions. Instead, it leaves it up to the developer to choose the best way to proceed.\n\nMany functions in the standard library follow the pattern of having a counterpart that raises an exception instead of returning tuples to match against. The convention is to create a function (`foo`) which returns `{:ok, result}` or `{:error, reason}` tuples and another function (`foo!`, same name but with a trailing `!`) that takes the same arguments as `foo` but which raises an exception if there's an error. `foo!` should return the result (not wrapped in a tuple) if everything goes fine. The `File` module is a good example of this convention.\n\n### Fail fast / Let it crash\n\nOne saying that is common in the Erlang community, as well as Elixir's, is \"fail fast\" / \"let it crash\". The idea behind let it crash is that, in case something *unexpected* happens, it is best to let the exception happen, without rescuing it.\n\nIt is important to emphasize the word *unexpected*. For example, imagine you are building a script to process files. Your script receives filenames as inputs. It is expected that users may make mistakes and provide unknown filenames. In this scenario, while you could use `File.read!/1` to read files and let it crash in case of invalid filenames, it probably makes more sense to use `File.read/1` and provide users of your script with a clear and precise feedback of what went wrong.\n\nOther times, you may fully expect a certain file to exist, and in case it does not, it means something terribly wrong has happened elsewhere. In such cases, `File.read!/1` is all you need.\n\nThe second approach also works because, as discussed in the [Processes](processes.md) chapter, all Elixir code runs inside processes that are isolated and don't share anything by default. Therefore, an unhandled exception in a process will never crash or corrupt the state of another process. This allows us to define supervisor processes, which are meant to observe when a process terminates unexpectedly, and start a new one in its place.\n\nAt the end of the day, \"fail fast\" / \"let it crash\" is a way of saying that, when *something unexpected* happens, it is best to start from scratch within a new process, freshly started by a supervisor, rather than blindly trying to rescue all possible error cases without the full context of when and how they can happen.\n\n### Reraise\n\nWhile we generally avoid using `try/rescue` in Elixir, one situation where we may want to use such constructs is for observability/monitoring. Imagine you want to log that something went wrong, you could do:\n\n```elixir\ntry do\n  ... some code ...\nrescue\n  e ->\n    Logger.error(Exception.format(:error, e, __STACKTRACE__))\n    reraise e, __STACKTRACE__\nend\n```\n\nIn the example above, we rescued the exception, logged it, and then re-raised it. We use the `__STACKTRACE__` construct both when formatting the exception and when re-raising. This ensures we reraise the exception as is, without changing value or its origin.\n\nGenerally speaking, we take errors in Elixir literally: they are reserved for unexpected and/or exceptional situations, never for controlling the flow of our code. In case you actually need flow control constructs, *throws* should be used. That's what we are going to see next.\n\n## Throws\n\nIn Elixir, a value can be thrown and later be caught. `throw` and `catch` are reserved for situations where it is not possible to retrieve a value unless by using `throw` and `catch`.\n\nThose situations are quite uncommon in practice except when interfacing with libraries that do not provide a proper API. For example, let's imagine the `Enum` module did not provide any API for finding a value and that we needed to find the first multiple of 13 in a list of numbers:\n\n```elixir\niex> try do\n...>   Enum.each(-50..50, fn x ->\n...>     if rem(x, 13) == 0, do: throw(x)\n...>   end)\n...>   \"Got nothing\"\n...> catch\n...>   x -> \"Got #{x}\"\n...> end\n\"Got -39\"\n```\n\nSince `Enum` *does* provide a proper API, in practice `Enum.find/2` is the way to go:\n\n```elixir\niex> Enum.find(-50..50, &(rem(&1, 13) == 0))\n-39\n```\n\n## Exits\n\nAll Elixir code runs inside processes that communicate with each other. When a process dies of \"natural causes\" (e.g., unhandled exceptions), it sends an `exit` signal. A process can also die by explicitly sending an `exit` signal:\n\n```elixir\niex> spawn_link(fn -> exit(1) end)\n** (EXIT from #PID<0.56.0>) shell process exited with reason: 1\n```\n\nIn the example above, the linked process died by sending an `exit` signal with a value of 1. The Elixir shell automatically handles those messages and prints them to the terminal.\n\n`exit` can also be \"caught\" using `try/catch`:\n\n```elixir\niex> try do\n...>   exit(\"I am exiting\")\n...> catch\n...>   :exit, _ -> \"not really\"\n...> end\n\"not really\"\n```\n\n`catch` can also be used within a function body without a matching `try`.\n\n```elixir\ndefmodule Example do\n  def matched_catch do\n    exit(:timeout)\n  catch\n    :exit, :timeout ->\n      {:error, :timeout}\n  end\n\n  def mismatched_catch do\n    exit(:timeout)\n  catch\n    # Since no clause matches, this catch will have no effect\n    :exit, :explosion ->\n      {:error, :explosion}\n  end\nend\n```\n\nHowever, using `try/catch` is already uncommon and using it to catch exits is even rarer.\n\n`exit` signals are an important part of the fault tolerant system provided by the Erlang VM. Processes usually run under supervision trees which are themselves processes that listen to `exit` signals from the supervised processes. Once an `exit` signal is received, the supervision strategy kicks in and the supervised process is restarted.\n\nIt is exactly this supervision system that makes constructs like `try/catch` and `try/rescue` so uncommon in Elixir. Instead of rescuing an error, we'd rather \"fail fast\" since the supervision tree will guarantee our application will go back to a known initial state after the error.\n\n## After\n\nSometimes it's necessary to ensure that a resource is cleaned up after some action that could potentially raise an error. The `try/after` construct allows you to do that. For example, we can open a file and use an `after` clause to close it—even if something goes wrong:\n\n```elixir\niex> {:ok, file} = File.open(\"sample\", [:utf8, :write])\niex> try do\n...>   IO.write(file, \"olá\")\n...>   raise \"oops, something went wrong\"\n...> after\n...>   File.close(file)\n...> end\n** (RuntimeError) oops, something went wrong\n```\n\nThe `after` clause will be executed regardless of whether or not the tried block succeeds. Note, however, that if a linked process exits,\nthis process will exit and the `after` clause will not get run. Thus `after` provides only a soft guarantee. Luckily, files in Elixir are also linked to the current processes and therefore they will always get closed if the current process crashes, independent of the\n`after` clause. You will find the same to be true for other resources like ETS tables, sockets, ports and more.\n\nSometimes you may want to wrap the entire body of a function in a `try` construct, often to guarantee some code will be executed afterwards. In such cases, Elixir allows you to omit the `try` line:\n\n```elixir\niex> defmodule RunAfter do\n...>   def without_even_trying do\n...>     raise \"oops\"\n...>   after\n...>     IO.puts(\"cleaning up!\")\n...>   end\n...> end\niex> RunAfter.without_even_trying\ncleaning up!\n** (RuntimeError) oops\n```\n\nElixir will automatically wrap the function body in a `try` whenever one of `after`, `rescue` or `catch` is specified. The `after` block handles side effects and does not change the return value from the clauses above it.\n\n## Else\n\nIf an `else` block is present, it will match on the results of the `try` block whenever the `try` block finishes without a throw or an error.\n\n```elixir\niex> x = 2\n2\niex> try do\n...>   1 / x\n...> rescue\n...>   ArithmeticError ->\n...>     :infinity\n...> else\n...>   y when y < 1 and y > -1 ->\n...>     :small\n...>   _ ->\n...>     :large\n...> end\n:small\n```\n\nExceptions in the `else` block are not caught. If no pattern inside the `else` block matches, an exception will be raised; this exception is not caught by the current `try/catch/rescue/after` block.\n\n## Variables scope\n\nSimilar to `case`, `cond`, `if` and other constructs in Elixir, variables defined inside `try/catch/rescue/after` blocks do not leak to the outer context. In other words, this code is invalid:\n\n```elixir\niex> try do\n...>   raise \"fail\"\n...>   what_happened = :did_not_raise\n...> rescue\n...>   _ -> what_happened = :rescued\n...> end\niex> what_happened\n** (CompileError) undefined variable \"what_happened\"\n```\n\nInstead, you should return the value of the `try` expression:\n\n```elixir\niex> what_happened =\n...>   try do\n...>     raise \"fail\"\n...>     :did_not_raise\n...>   rescue\n...>     _ -> :rescued\n...>   end\niex> what_happened\n:rescued\n```\n\nFurthermore, variables defined in the do-block of `try` are not available inside `rescue/after/else` either. This is because the `try` block may fail at any moment and therefore the variables may have never been bound in the first place. So this also isn't valid:\n\n```elixir\niex> try do\n...>   raise \"fail\"\n...>   another_what_happened = :did_not_raise\n...> rescue\n...>   _ -> another_what_happened\n...> end\n** (CompileError) undefined variable \"another_what_happened\"\n```\n\nThis finishes our introduction on `try`, `catch`, and `rescue`. You will find they are used less frequently in Elixir than in other languages. Next we will talk about a very important subject to Elixir developers: writing documentation.\n"
  },
  {
    "path": "lib/elixir/pages/getting-started/writing-documentation.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Writing documentation\n\nElixir treats documentation as a first-class citizen. Documentation must be easy to write and easy to read. In this guide you will learn how to write documentation in Elixir, covering constructs like module attributes, style practices, and doctests.\n\n## Markdown\n\nElixir documentation is written using Markdown. There are plenty of guides on Markdown online, we recommend the one from GitHub as a getting started point:\n\n  * [Basic writing and formatting syntax](https://help.github.com/articles/basic-writing-and-formatting-syntax/)\n\n## Module Attributes\n\nDocumentation in Elixir is usually attached to module attributes. Let's see an example:\n\n```elixir\ndefmodule MyApp.Hello do\n  @moduledoc \"\"\"\n  This is the Hello module.\n  \"\"\"\n  @moduledoc since: \"1.0.0\"\n\n  @doc \"\"\"\n  Says hello to the given `name`.\n\n  Returns `:ok`.\n\n  ## Examples\n\n      iex> MyApp.Hello.world(:john)\n      :ok\n\n  \"\"\"\n  @doc since: \"1.3.0\"\n  def world(name) do\n    IO.puts(\"hello #{name}\")\n  end\nend\n```\n\nThe `@moduledoc` attribute is used to add documentation to the module. `@doc` is used before a function to provide documentation for it. Besides the attributes above, `@typedoc` can also be used to attach documentation to types defined as part of typespecs.\n\n## Function arguments\n\nWhen documenting a function, argument names are inferred by the compiler. For example:\n\n```elixir\ndef size(%{size: size}) do\n  size\nend\n```\n\nThe compiler will infer this argument as `map`. Sometimes the inference will be suboptimal, especially if the function contains multiple clauses with the argument matching on different values each time. You can specify the proper names for documentation by declaring only the function head at any moment before the implementation:\n\n```elixir\ndef size(map_with_size)\n\ndef size(%{size: size}) do\n  size\nend\n```\n\n## Documentation metadata\n\nElixir allows developers to attach arbitrary metadata to the documentation. This is done by passing a keyword list to the relevant attribute (such as `@moduledoc`, `@typedoc`, and `@doc`).\n\nMetadata can have any key. Documentation tools often use metadata to provide more data to readers and to enrich the user experience. The following keys already have a predefined meaning used by tooling:\n\n### `:deprecated`\n\nAnother common metadata is `:deprecated`, which emits a warning in the documentation, explaining that its usage is discouraged:\n\n```elixir\n@doc deprecated: \"Use Foo.bar/2 instead\"\n```\n\nNote that the `:deprecated` key does not warn when a developer invokes the functions. If you want the code to also emit a warning, you can use the `@deprecated` attribute:\n\n```elixir\n@deprecated \"Use Foo.bar/2 instead\"\n```\n\n### `:group`\n\nThe group a function, callback or type belongs to. This is used in `iex` for autocompleting and also to automatically by [ExDoc](https://github.com/elixir-lang/ex_doc/) to group items in the sidebar:\n\n```elixir\n@doc group: \"Query\"\ndef all(query)\n\n@doc group: \"Schema\"\ndef insert(schema)\n```\n\n### `:since`\n\nIt annotates in which version that particular module, function, type, or callback was added:\n\n```elixir\n@doc since: \"1.3.0\"\ndef world(name) do\n  IO.puts(\"hello #{name}\")\nend\n```\n\n## Recommendations\n\nWhen writing documentation:\n\n  * Keep the first paragraph of the documentation concise and simple, typically one-line. Tools like [ExDoc](https://github.com/elixir-lang/ex_doc/) use the first line to generate a summary.\n\n  * Reference modules by their full name. Markdown uses backticks (`` ` ``) to quote code. Elixir builds on top of that to automatically generate links when module or function names are referenced. For this reason, always use full module names. If you have a module called `MyApp.Hello`, always reference it as `` `MyApp.Hello` `` and never as `` `Hello` ``.\n\n  * Reference functions by name and arity if they are local, as in `` `world/1` ``, or by module, name and arity if pointing to an external module: `` `MyApp.Hello.world/1` ``.\n\n  * Reference a `@callback` by prepending `c:`, as in `` `c:world/1` ``.\n\n  * Reference a `@type` by prepending `t:`, as in `` `t:values/0` ``.\n\n  * Start new sections with second level Markdown headers `##`. First level headers are reserved for module and function names.\n\n  * Place documentation before the first clause of multi-clause functions. Documentation is always per function and arity and not per clause.\n\n  * Use the `:since` key in the documentation metadata to annotate whenever new functions or modules are added to your API.\n\n## Doctests\n\nWe advise developers to include examples in their documentation, often under their own `## Examples` heading. To ensure examples do not get out of date, Elixir's test framework (ExUnit) provides a feature called doctests that allows developers to test the examples in their documentation. Doctests work by parsing out code samples starting with `iex>` from the documentation. You can read more about them at `ExUnit.DocTest`.\n\n## Documentation != Code comments\n\nElixir treats documentation and code comments as different concepts. Documentation is an explicit contract between you and users of your Application Programming Interface (API), be they third-party developers, co-workers, or your future self. Modules and functions must always be documented if they are part of your API.\n\nCode comments are aimed at developers reading the code. They are useful for marking improvements, leaving notes (for example, why you had to resort to a workaround due to a bug in a library), and so forth. They are tied to the source code: you can completely rewrite a function and remove all existing code comments, and it will continue to behave the same, with no change to either its behavior or its documentation.\n\nBecause private functions cannot be accessed externally, Elixir will warn if a private function has a `@doc` attribute and will discard its content. However, you can add code comments to private functions, as with any other piece of code, and we recommend developers to do so whenever they believe it will add relevant information to the readers and maintainers of such code.\n\nIn summary, documentation is a contract with users of your API, who may not necessarily have access to the source code, whereas code comments are for those who interact directly with the source. You can learn and express different guarantees about your software by separating those two concepts.\n\n## Hiding internal modules and functions\n\nBesides the modules and functions libraries provide as part of their public interface, libraries may also implement important functionality that is not part of their API. While these modules and functions can be accessed, they are meant to be internal to the library and thus should not have documentation for end users.\n\nConveniently, Elixir allows developers to hide modules and functions from the documentation, by setting `@doc false` to hide a particular function, or `@moduledoc false` to hide the whole module. If a module is hidden, you may even document the functions in the module, but the module itself won't be listed in the documentation:\n\n```elixir\ndefmodule MyApp.Hidden do\n  @moduledoc false\n\n  @doc \"\"\"\n  This function won't be listed in docs.\n  \"\"\"\n  def function_that_wont_be_listed_in_docs do\n    # ...\n  end\nend\n```\n\nIn case you don't want to hide a whole module, you can hide functions individually:\n\n```elixir\ndefmodule MyApp.Sample do\n  @doc false\n  def add(a, b), do: a + b\nend\n```\n\nHowever, keep in mind `@moduledoc false` or `@doc false` do not make a function private. The function above can still be invoked as `MyApp.Sample.add(1, 2)`. Not only that, if `MyApp.Sample` is imported, the `add/2` function will also be imported into the caller. For those reasons, be cautious when adding `@doc false` to functions, instead use one of these two options:\n\n  * Move the undocumented function to a module with `@moduledoc false`, like `MyApp.Hidden`, ensuring the function won't be accidentally exposed or imported. Remember that you can use `@moduledoc false` to hide a whole module and still document each function with `@doc`. Tools will still ignore the module.\n\n  * Start the function name with one or two underscores, for example, `__add__/2`. Functions starting with underscore are automatically treated as hidden, although you can also be explicit and add `@doc false`. The compiler does not import functions with leading underscores and they hint to anyone reading the code of their intended private usage.\n\n## `Code.fetch_docs/1`\n\nElixir stores documentation inside pre-defined chunks in the bytecode. Documentation is not loaded into memory when modules are loaded, instead, it can be read from the bytecode in disk using the `Code.fetch_docs/1` function. The downside is that modules defined in-memory, like the ones defined in IEx, cannot have their documentation accessed as they do not write their bytecode to disk.\n"
  },
  {
    "path": "lib/elixir/pages/meta-programming/domain-specific-languages.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Domain-Specific Languages (DSLs)\n\n[Domain-specific Languages (DSLs)](https://en.wikipedia.org/wiki/Domain-specific_language) are languages tailored to a specific application domain. You don't need macros in order to have a DSL: every data structure and every function you define in your module is part of your domain-specific language.\n\nFor example, imagine we want to implement a `Validator` module which provides a data validation domain-specific language. We could implement it using data structures, functions, or macros. Let's see what those different DSLs would look like:\n\n```elixir\n# 1. Data structures\nimport Validator\nvalidate user, name: [length: 1..100], email: [matches: ~r/@/]\n\n# 2. Functions\nimport Validator\nuser\n|> validate_length(:name, 1..100)\n|> validate_matches(:email, ~r/@/)\n\n# 3. Macros + modules\ndefmodule MyValidator do\n  use Validator\n  validate_length :name, 1..100\n  validate_matches :email, ~r/@/\nend\n\nMyValidator.validate(user)\n```\n\nOf all the approaches above, the first is definitely the most flexible. If our domain rules can be encoded with data structures, they are by far the easiest to compose and implement, as Elixir's standard library is filled with functions for manipulating different data types.\n\nThe second approach uses function calls which better suits more complex APIs (for example, if you need to pass many options) and reads nicely in Elixir thanks to the pipe operator.\n\nThe third approach uses macros, and is by far the most complex. It will take more lines of code to implement, it is hard and expensive to test (compared to testing simple functions), and it limits how the user may use the library since all validations need to be defined inside a module.\n\nTo drive the point home, imagine you want to validate a certain attribute only if a given condition is met. We could easily achieve it with the first solution, by manipulating the data structure accordingly, or with the second solution by using conditionals (if/else) before invoking the function. However, it is impossible to do so with the macros approach unless its DSL is augmented.\n\nIn other words:\n\n```text\ndata > functions > macros\n```\n\nThat said, there are still cases where using macros and modules to build domain-specific languages is useful. Since we have explored data structures and function definitions in the Getting Started guide, this chapter will explore how to use macros and module attributes to tackle more complex DSLs.\n\n## Building our own test case\n\nThe goal in this chapter is to build a module named `TestCase` that allows us to write the following:\n\n```elixir\ndefmodule MyTest do\n  use TestCase\n\n  test \"arithmetic operations\" do\n    4 = 2 + 2\n  end\n\n  test \"list operations\" do\n    [1, 2, 3] = [1, 2] ++ [3]\n  end\nend\n\nMyTest.run()\n```\n\nIn the example above, by using `TestCase`, we can write tests using the `test` macro, which defines a function named `run` to automatically run all tests for us. Our prototype will rely on the match operator (`=`) as a mechanism to do assertions.\n\n## The `test` macro\n\nLet's start by creating a module that defines and imports the `test` macro when used:\n\n```elixir\ndefmodule TestCase do\n  # Callback invoked by `use`.\n  #\n  # For now it returns a quoted expression that\n  # imports the module itself into the user code.\n  @doc false\n  defmacro __using__(_opts) do\n    quote do\n      import TestCase\n    end\n  end\n\n  @doc \"\"\"\n  Defines a test case with the given description.\n\n  ## Examples\n\n      test \"arithmetic operations\" do\n        4 = 2 + 2\n      end\n\n  \"\"\"\n  defmacro test(description, do: block) do\n    function_name = String.to_atom(\"test \" <> description)\n    quote do\n      def unquote(function_name)(), do: unquote(block)\n    end\n  end\nend\n```\n\nAssuming we defined `TestCase` in a file named `tests.exs`, we can open it up by running `iex tests.exs` and define our first tests:\n\n```elixir\niex> defmodule MyTest do\n...>   use TestCase\n...>\n...>   test \"hello\" do\n...>     \"hello\" = \"world\"\n...>   end\n...> end\n```\n\nFor now, we don't have a mechanism to run tests, but we know that a function named `test hello` was defined behind the scenes. When we invoke it, it should fail:\n\n```elixir\niex> MyTest.\"test hello\"()\n** (MatchError) no match of right hand side value: \"world\"\n```\n\n## Storing information with attributes\n\nIn order to finish our `TestCase` implementation, we need to be able to access all defined test cases. One way of doing this is by retrieving the tests at runtime via `__MODULE__.__info__(:functions)`, which returns a list of all functions in a given module. However, considering that we may want to store more information about each test besides the test name, a more flexible approach is required.\n\nWhen discussing module attributes in earlier chapters, we mentioned how they can be used as temporary storage. That's exactly the property we will apply in this section.\n\nIn the `__using__/1` implementation, we will initialize a module attribute named `@tests` to an empty list, then store the name of each defined test in this attribute so the tests can be invoked from the `run` function.\n\nHere is the updated code for the `TestCase` module:\n\n```elixir\ndefmodule TestCase do\n  @doc false\n  defmacro __using__(_opts) do\n    quote do\n      import TestCase\n\n      # Initialize @tests to an empty list\n      @tests []\n\n      # Invoke TestCase.__before_compile__/1 before the module is compiled\n      @before_compile TestCase\n    end\n  end\n\n  @doc \"\"\"\n  Defines a test case with the given description.\n\n  ## Examples\n\n      test \"arithmetic operations\" do\n        4 = 2 + 2\n      end\n\n  \"\"\"\n  defmacro test(description, do: block) do\n    function_name = String.to_atom(\"test \" <> description)\n    quote do\n      # Prepend the newly defined test to the list of tests\n      @tests [unquote(function_name) | @tests]\n      def unquote(function_name)(), do: unquote(block)\n    end\n  end\n\n  # This will be invoked right before the target module is compiled\n  # giving us the perfect opportunity to inject the `run/0` function\n  @doc false\n  defmacro __before_compile__(_env) do\n    quote do\n      def run do\n        Enum.each(@tests, fn name ->\n          IO.puts(\"Running #{name}\")\n          apply(__MODULE__, name, [])\n        end)\n      end\n    end\n  end\nend\n```\n\nBy starting a new IEx session, we can now define our tests and run them:\n\n```elixir\niex> defmodule MyTest do\n...>   use TestCase\n...>\n...>   test \"hello\" do\n...>     \"hello\" = \"world\"\n...>   end\n...> end\niex> MyTest.run()\nRunning test hello\n** (MatchError) no match of right hand side value: \"world\"\n```\n\nAlthough we have overlooked some details, this is the main idea behind creating domain-specific languages in Elixir via modules and macros. Macros enable us to return quoted expressions that are executed in the caller, which we can then use to transform code and store relevant information in the target module via module attributes. Finally, callbacks such as `@before_compile` allow us to inject code into the module when its definition is complete.\n\nBesides `@before_compile`, there are other useful module attributes like `@on_definition` and `@after_compile`, which you can read more about in the docs for `Module`. You can also find useful information about macros and the compilation environment in the documentation for the `Macro` and `Macro.Env`.\n"
  },
  {
    "path": "lib/elixir/pages/meta-programming/macros.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Macros\n\nEven though Elixir attempts its best to provide a safe environment for macros, most of the responsibility of writing clean code with macros falls on developers. Macros are harder to write than ordinary Elixir functions, and it's considered to be bad style to use them when they're not necessary. Write macros responsibly.\n\nElixir already provides mechanisms to write your everyday code in a simple and readable fashion by using its data structures and functions. Macros should only be used as a last resort. Remember that **explicit is better than implicit**. **Clear code is better than concise code.**\n\n## Our first macro\n\nMacros in Elixir are defined via `defmacro/2`.\n\n> For this guide, we will be using files instead of running code samples in IEx. That's because the code samples will span multiple lines of code and typing them all in IEx can be counter-productive. You should be able to run the code samples by saving them into a `macros.exs` file and running it with `elixir macros.exs` or `iex macros.exs`.\n\nIn order to better understand how macros work, let's create a new module where we are going to implement `unless` (which does the opposite of `if/2`), as a macro and as a function:\n\n```elixir\ndefmodule Unless do\n  def fun_unless(clause, do: expression) do\n    if(!clause, do: expression)\n  end\n\n  defmacro macro_unless(clause, do: expression) do\n    quote do\n      if(!unquote(clause), do: unquote(expression))\n    end\n  end\nend\n```\n\nThe function receives the arguments and passes them to `if/2`. However, as we learned in the [previous guide](quote-and-unquote.md), the macro will receive quoted expressions, inject them into the quote, and finally return another quoted expression.\n\nLet's start `iex` with the module above:\n\n```console\n$ iex macros.exs\n```\n\nand play with those definitions:\n\n```elixir\niex> require Unless\niex> Unless.macro_unless(true, do: IO.puts(\"this should never be printed\"))\nnil\niex> Unless.fun_unless(true, do: IO.puts(\"this should never be printed\"))\n\"this should never be printed\"\nnil\n```\n\nIn our *macro* implementation, the sentence was not printed, although it was printed in our *function* implementation. That's because the arguments to a function call are evaluated before calling the function. However, macros do not evaluate their arguments. Instead, they receive the arguments as quoted expressions which are then transformed into other quoted expressions. In this case, we have rewritten our `unless` macro to become an `if/2` behind the scenes.\n\nIn other words, when invoked as:\n\n```elixir\nUnless.macro_unless(true, do: IO.puts(\"this should never be printed\"))\n```\n\nOur `macro_unless` macro received the following:\n\n```elixir\nmacro_unless(true, [do: {{:., [], [{:__aliases__, [], [:IO]}, :puts]}, [], [\"this should never be printed\"]}])\n```\n\nand it then returned a quoted expression as follows:\n\n```elixir\n{:if, [],\n [{:!, [], [true]},\n  [do: {{:., [],\n     [{:__aliases__,\n       [], [:IO]},\n      :puts]}, [], [\"this should never be printed\"]}]]}\n```\n\nWe can actually verify that this is the case by using `Macro.expand_once/2`:\n\n```elixir\niex> expr = quote do: Unless.macro_unless(true, do: IO.puts(\"this should never be printed\"))\niex> res  = Macro.expand_once(expr, __ENV__)\niex> IO.puts(Macro.to_string(res))\nif(!true) do\n  IO.puts(\"this should never be printed\")\nend\n:ok\n```\n\n`Macro.expand_once/2` receives a quoted expression and expands it according to the current environment. In this case, it expanded/invoked the `Unless.macro_unless/2` macro and returned its result. We then proceeded to convert the returned quoted expression to a string and print it (we will talk about `__ENV__` later in this chapter).\n\nThat's what macros are all about. They are about receiving quoted expressions and transforming them into something else.\nIn fact, `if/2` in Elixir is implemented as a macro:\n\n```elixir\ndefmacro if(clause, do: expression) do\n  quote do\n    case unquote(clause) do\n      x when x in [false, nil] -> nil\n      _ -> unquote(expression)\n  end\nend\n```\n\nConstructs such as `if/2`, `defmacro/2`, `def/2`, `defprotocol/2`, and many others used throughout the Elixir standard library are written in pure Elixir, often as a macro. This means that the constructs being used to build the language can be used by developers to extend the language to the domains they are working on.\n\nWe can define any function and macro we want, including ones that override the built-in definitions provided by Elixir. The only exceptions are Elixir special forms which are not implemented in Elixir and therefore cannot be overridden. The full list of special forms is available in `Kernel.SpecialForms`.\n\n## Macro hygiene\n\nElixir macros have \"late resolution\". This guarantees that a variable defined inside a quote won't conflict with a variable defined in the context where that macro is expanded. For example:\n\n```elixir\ndefmodule Hygiene do\n  defmacro no_interference do\n    quote do: a = 1\n  end\nend\n\ndefmodule HygieneTest do\n  def go do\n    require Hygiene\n    a = 13\n    Hygiene.no_interference()\n    a\n  end\nend\n\nHygieneTest.go()\n# => 13\n```\n\nIn the example above, even though the macro injects `a = 1`, it does not affect the variable `a` defined by the `go/0` function. If a macro wants to explicitly affect the context, it can use `var!/1`:\n\n```elixir\ndefmodule Hygiene do\n  defmacro interference do\n    quote do: var!(a) = 1\n  end\nend\n\ndefmodule HygieneTest do\n  def go do\n    require Hygiene\n    a = 13\n    Hygiene.interference()\n    a\n  end\nend\n\nHygieneTest.go()\n# => 1\n```\n\nThe code above will work but issue a warning: `variable \"a\" is unused`. The macro is overriding the original value and the original value is never used.\n\nVariable hygiene only works because Elixir annotates variables with their **context**. For example, a variable `x` defined on line 3 of a module would be represented as:\n\n```elixir\n{:x, [line: 3], nil}\n```\n\nHowever, a quoted variable would be represented as:\n\n```elixir\ndefmodule Sample do\n  def quoted do\n    quote do: x\n  end\nend\n\nSample.quoted() #=> {:x, [line: 3], Sample}\n```\n\nNotice that the *third element* in the quoted variable is the atom `Sample`, instead of `nil`, which marks the variable as coming from the `Sample` module. Therefore, Elixir considers these two variables as coming from different contexts and handles them accordingly.\n\nElixir provides similar mechanisms for imports and aliases too. This guarantees that a macro will behave as specified by its source module rather than conflicting with the target module where the macro is expanded. Hygiene can be bypassed under specific situations by using macros like `var!/2` and `alias!/1`, although one must be careful when using those as they directly change the user environment.\n\nSometimes variable names might be dynamically created. In such cases, `Macro.var/2` can be used to define new variables:\n\n```elixir\ndefmodule Sample do\n  defmacro initialize_to_char_count(variables) do\n    Enum.map(variables, fn name ->\n      var = Macro.var(name, nil)\n      length = name |> Atom.to_string() |> String.length()\n\n      quote do\n        unquote(var) = unquote(length)\n      end\n    end)\n  end\n\n  def run do\n    initialize_to_char_count([:red, :green, :yellow])\n    [red, green, yellow]\n  end\nend\n\n> Sample.run() #=> [3, 5, 6]\n```\n\nTake note of the second argument to `Macro.var/2`. This is the **context** being used and will determine hygiene as described in the next section. Check out also `Macro.unique_var/2`, for cases when you need to generate variables with unique names.\n\n## The environment\n\nWhen calling `Macro.expand_once/2` earlier in this chapter, we used the special form `__ENV__/0`.\n\n`__ENV__/0` returns a `Macro.Env` struct which contains useful information about the compilation environment, including the current module, file, and line, all variables defined in the current scope, as well as imports, requires, and more:\n\n```elixir\niex> __ENV__.module\nnil\niex> __ENV__.file\n\"iex\"\niex> __ENV__.requires\n[IEx.Helpers, Kernel, Kernel.Typespec]\niex> require Integer\nnil\niex> __ENV__.requires\n[IEx.Helpers, Integer, Kernel, Kernel.Typespec]\n```\n\nMany of the functions in the `Macro` module expect a `Macro.Env` environment. You can read more about these functions in `Macro` and learn more about the compilation environment in the `Macro.Env`.\n\n## Private macros\n\nElixir also supports **private macros** via `defmacrop`. Like private functions, these macros are only available inside the module that defines them, and only at compilation time.\n\nIt is important that a macro is defined before its usage. Failing to define a macro before its invocation will raise an error at runtime, since the macro won't be expanded and will be translated to a function call:\n\n```elixir\niex> defmodule Sample do\n...>  def four, do: two() + two()\n...>  defmacrop two, do: 2\n...> end\n** (CompileError) iex:2: function two/0 undefined\n```\n\n## Write macros responsibly\n\nMacros are a powerful construct and Elixir provides many mechanisms to ensure they are used responsibly.\n\n  * Macros are **hygienic**: by default, variables defined inside a macro are not going to affect the user code. Furthermore, function calls and aliases available in the macro context are not going to leak into the user context.\n\n  * Macros are **lexical**: it is impossible to inject code or macros globally. In order to use a macro, you need to explicitly `require` or `import` the module that defines the macro.\n\n  * Macros are **explicit**: it is impossible to run a macro without explicitly invoking it. For example, some languages allow developers to completely rewrite functions behind the scenes, often via parse transforms or via some reflection mechanisms. In Elixir, a macro must be explicitly invoked in the caller during compilation time.\n\n  * Macros' language is clear: many languages provide syntax shortcuts for `quote` and `unquote`. In Elixir, we preferred to have them explicitly spelled out, in order to clearly delimit the boundaries of a macro definition and its quoted expressions.\n\nEven with such guarantees, the developer plays a big role when writing macros responsibly. If you are confident you need to resort to macros, remember that macros are not your API. Keep your macro definitions short, including their quoted contents. For example, instead of writing a macro like this:\n\n```elixir\ndefmodule MyModule do\n  defmacro my_macro(a, b, c) do\n    quote do\n      do_this(unquote(a))\n      # ...\n      do_that(unquote(b))\n      # ...\n      and_that(unquote(c))\n    end\n  end\nend\n```\n\nwrite:\n\n```elixir\ndefmodule MyModule do\n  defmacro my_macro(a, b, c) do\n    quote do\n      # Keep what you need to do here to a minimum\n      # and move everything else to a function\n      MyModule.do_this_that_and_that(unquote(a), unquote(b), unquote(c))\n    end\n  end\n\n  def do_this_that_and_that(a, b, c) do\n    do_this(a)\n    ...\n    do_that(b)\n    ...\n    and_that(c)\n  end\nend\n```\n\nThis makes your code clearer and easier to test and maintain, as you can invoke and test `do_this_that_and_that/3` directly. It also helps you design an actual API for developers that do not want to rely on macros.\n\nWith this guide, we finish our introduction to macros. The next guide is a brief discussion on **DSLs** that shows how we can mix macros and module attributes to annotate and extend modules and functions.\n"
  },
  {
    "path": "lib/elixir/pages/meta-programming/quote-and-unquote.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Quote and unquote\n\nThis guide aims to introduce the meta-programming techniques available in Elixir. The ability to represent an Elixir program by its own data structures is at the heart of meta-programming. This chapter starts by exploring those structures and the associated `quote/2` and `unquote/1` constructs, so we can take a look at macros in the next guide, and finally build our own domain specific language.\n\n## Quoting\n\nThe building block of an Elixir program is a tuple with three elements. For example, the function call `sum(1, 2, 3)` is represented internally as:\n\n```elixir\n{:sum, [], [1, 2, 3]}\n```\n\nYou can get the representation of any expression by using the `quote/2` macro:\n\n```elixir\niex> quote do: sum(1, 2, 3)\n{:sum, [], [1, 2, 3]}\n```\n\nThe first element is the function name, the second is a keyword list containing metadata, and the third is the arguments list.\n\nOperators are also represented as such tuples:\n\n```elixir\niex> quote do: 1 + 2\n{:+, [context: Elixir, import: Kernel], [1, 2]}\n```\n\nEven a map is represented as a call to `%{}`:\n\n```elixir\niex> quote do: %{1 => 2}\n{:%{}, [], [{1, 2}]}\n```\n\nVariables are represented using such triplets, with the difference that the last element is an atom, instead of a list:\n\n```elixir\niex> quote do: x\n{:x, [], Elixir}\n```\n\nWhen quoting more complex expressions, we can see that the code is represented in such tuples, which are often nested inside each other in a structure resembling a tree. Many languages would call such representations an [*Abstract Syntax Tree*](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST). Elixir calls them *quoted expressions*:\n\n```elixir\niex> quote do: sum(1, 2 + 3, 4)\n{:sum, [], [1, {:+, [context: Elixir, import: Kernel], [2, 3]}, 4]}\n```\n\nSometimes, when working with quoted expressions, it may be useful to get the textual code representation back. This can be done with `Macro.to_string/1`:\n\n```elixir\niex> Macro.to_string(quote do: sum(1, 2 + 3, 4))\n\"sum(1, 2 + 3, 4)\"\n```\n\nIn general, the tuples above are structured according to the following format:\n\n```elixir\n{atom | tuple, list, list | atom}\n```\n\n  * The first element is an atom or another tuple in the same representation;\n  * The second element is a keyword list containing metadata, like numbers and contexts;\n  * The third element is either a list of arguments for the function call or an atom. When this element is an atom, it means the tuple represents a variable.\n\nBesides the tuple defined above, there are five Elixir literals that, when quoted, return themselves (and not a tuple). They are:\n\n```elixir\n:sum         #=> Atoms\n1.0          #=> Numbers\n[1, 2]       #=> Lists\n\"strings\"    #=> Strings\n{key, value} #=> Tuples with two elements\n```\n\nMost Elixir code has a straight-forward translation to its underlying quoted expression. We recommend you try out different code samples and see what the results are. For example, what does `String.upcase(\"foo\")` expand to? We have also learned that `if(true, do: :this, else: :that)` is the same as `if true do :this else :that end`. How does this affirmation hold with quoted expressions?\n\n## Unquoting\n\nQuoting is about retrieving the inner representation of some particular chunk of code. However, sometimes it may be necessary to inject some other particular chunk of code inside the representation we want to retrieve.\n\nFor example, imagine you have a variable called `number` which contains the number you want to inject inside a quoted expression.\n\n```elixir\niex> number = 13\niex> Macro.to_string(quote do: 11 + number)\n\"11 + number\"\n```\n\nThat's not what we wanted, since the value of the `number` variable has not been injected and `number` has been quoted in the expression. In order to inject the *value* of the `number` variable, `unquote/1` has to be used inside the quoted representation:\n\n```elixir\niex> number = 13\niex> Macro.to_string(quote do: 11 + unquote(number))\n\"11 + 13\"\n```\n\n`unquote/1` can even be used to inject function names:\n\n```elixir\niex> fun = :hello\niex> Macro.to_string(quote do: unquote(fun)(:world))\n\"hello(:world)\"\n```\n\nIn some cases, it may be necessary to inject many values inside a list. For example, imagine you have a list containing `[1, 2, 6]`, and we want to inject `[3, 4, 5]` into it. Using `unquote/1` won't yield the desired result:\n\n```elixir\niex> inner = [3, 4, 5]\niex> Macro.to_string(quote do: [1, 2, unquote(inner), 6])\n\"[1, 2, [3, 4, 5], 6]\"\n```\n\nThat's when `unquote_splicing/1` comes in handy:\n\n```elixir\niex> inner = [3, 4, 5]\niex> Macro.to_string(quote do: [1, 2, unquote_splicing(inner), 6])\n\"[1, 2, 3, 4, 5, 6]\"\n```\n\nUnquoting is very useful when working with macros. When writing macros, developers are able to receive code chunks and inject them inside other code chunks, which can be used to transform code or write code that generates code during compilation.\n\n## Escaping\n\nAs we saw at the beginning of this chapter, only some values are valid quoted expressions in Elixir. For example, a map is not a valid quoted expression. Neither is a tuple with four elements. However, such values *can* be expressed as a quoted expression:\n\n```elixir\niex> quote do: %{1 => 2}\n{:%{}, [], [{1, 2}]}\n```\n\nIn some cases, you may need to inject such *values* into *quoted expressions*. To do that, we need to first escape those values into quoted expressions with the help of `Macro.escape/1`:\n\n```elixir\niex> map = %{hello: :world}\niex> Macro.escape(map)\n{:%{}, [], [hello: :world]}\n```\n\nMacros receive quoted expressions and must return quoted expressions. However, sometimes during the execution of a macro, you may need to work with values and making a distinction between values and quoted expressions will be required.\n\nIn other words, it is important to make a distinction between a regular Elixir value (like a list, a map, a process, a reference, and so on) and a quoted expression. Some values, such as integers, atoms, and strings, have a quoted expression equal to the value itself. Other values, like maps, need to be explicitly converted. Finally, values like functions and references cannot be converted to a quoted expression at all.\n\nWhen working with macros and code that generates code, check out the documentation for the `Macro` module, which contains many functions to work with Elixir's AST.\n\nIn this introduction, we have laid the groundwork to finally write our first macro. You can check that out in the [next guide](macros.md).\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/agents.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Simple state with agents\n\nIn this chapter, we will learn how to keep and share state between multiple entities. If you have previous programming experience, you may think of globally shared variables, but the model we will learn here is quite different. The next chapters will generalize the concepts introduced here.\n\nIf you have skipped the *Getting Started* guide or read it long ago, be sure to re-read the [Processes](../getting-started/processes.md) chapter. We will use it as a starting point.\n\n## The trouble with (mutable) state\n\nElixir is an immutable language where nothing is shared by default. If we want to share information, this is typically done by sending messages between processes.\n\nWhen it comes to processes though, we rarely hand-roll our own, instead we use the abstractions available in Elixir and OTP:\n\n  * `Agent` — Simple wrappers around state.\n  * `GenServer` — \"Generic servers\" (processes) that encapsulate state, provide sync and async calls, support code reloading, and more.\n  * `Task` — Asynchronous units of computation that allow spawning a process and potentially retrieving its result at a later time.\n\nHere, we will use agents, and create a module named `KV.Bucket`, responsible for storing our key-value entries in a way that allows them to be read and modified by other processes.\n\n## Agents 101\n\n`Agent`s are simple wrappers around state. If all you want from a process is to keep state, agents are a great fit. Let's start a `iex` session inside the project with:\n\n```console\n$ iex -S mix\n```\n\nAnd play a bit with agents:\n\n```elixir\niex> {:ok, agent} = Agent.start_link(fn -> [] end)\n{:ok, #PID<0.57.0>}\niex> Agent.update(agent, fn list -> [\"eggs\" | list] end)\n:ok\niex> Agent.get(agent, fn list -> list end)\n[\"eggs\"]\niex> Agent.stop(agent)\n:ok\n```\n\nWe started an agent with an initial state of an empty list. The `start_link/1` function returned the `:ok` tuple with a process identifier (PID) of the agent. We will use this PID for all further interactions. We then updated the agent's state, adding our new item to the head of the list. The second argument of `Agent.update/3` is a function that takes the agent's current state as input and returns its desired new state. Finally, we retrieved the whole list. The second argument of `Agent.get/3` is a function that takes the state as input and returns the value that `Agent.get/3` itself will return. Once we are done with the agent, we can call `Agent.stop/3` to terminate the agent process.\n\nThe `Agent.update/3` function accepts as a second argument any function that receives one argument and returns a value:\n\n```elixir\niex> {:ok, agent} = Agent.start_link(fn -> [] end)\n{:ok, #PID<0.338.0>}\niex> Agent.update(agent, fn _list -> 123 end)\n:ok\niex> Agent.update(agent, fn content -> %{a: content} end)\n:ok\niex> Agent.update(agent, fn content -> [12 | [content]] end)\n:ok\niex> Agent.update(agent, fn list -> [:nop | list] end)\n:ok\niex> Agent.get(agent, fn content -> content end)\n[:nop, 12, %{a: 123}]\n```\n\nAs you can see, we can modify the agent state in any way we want. Therefore, we most likely don't want to access the Agent API throughout many different places in our code. Instead, we want to encapsulate all Agent-related functionality in a single module, which we will call `KV.Bucket`. Before we implement it, let's write some tests which will outline the API exposed by our module.\n\nCreate a file at `test/kv/bucket_test.exs` (remember the `.exs` extension) with the following:\n\n```elixir\ndefmodule KV.BucketTest do\n  use ExUnit.Case, async: true\n\n  test \"stores values by key\" do\n    {:ok, bucket} = KV.Bucket.start_link([])\n    assert KV.Bucket.get(bucket, \"milk\") == nil\n\n    KV.Bucket.put(bucket, \"milk\", 3)\n    assert KV.Bucket.get(bucket, \"milk\") == 3\n  end\nend\n```\n\n`use ExUnit.Case` is responsible for setting up our module for testing and imports many test-related functionality, such as the `test/2` macro.\n\nOur first test starts a new `KV.Bucket` by calling the `start_link/1` and passing an empty list of options. Then we perform some `get/2` and `put/3` operations on it, asserting the result.\n\nAlso note the `async: true` option passed to `ExUnit.Case`. This option makes the test case run in parallel with other `:async` test cases by using multiple cores in our machine. This is extremely useful to speed up our test suite. However, `:async` must *only* be set if the test case does not rely on or change any global values. For example, if the test requires writing to the file system or access a database, keep it synchronous (omit the `:async` option) to avoid race conditions between tests.\n\nAsync or not, our new test should obviously fail, as none of the functionality is implemented in the module being tested:\n\n```text\n1) test stores values by key (KV.BucketTest)\n   test/kv/bucket_test.exs:4\n   ** (UndefinedFunctionError) function KV.Bucket.start_link/1 is undefined (module KV.Bucket is not available)\n```\n\nIn order to fix the failing test, let's create a file at `lib/kv/bucket.ex` with the contents below. Feel free to give a try at implementing the `KV.Bucket` module yourself using agents before peeking at the implementation below.\n\n```elixir\ndefmodule KV.Bucket do\n  use Agent\n\n  @doc \"\"\"\n  Starts a new bucket.\n\n  All options are forwarded to `Agent.start_link/2`.\n  \"\"\"\n  def start_link(opts) do\n    Agent.start_link(fn -> %{} end, opts)\n  end\n\n  @doc \"\"\"\n  Gets a value from the `bucket` by `key`.\n  \"\"\"\n  def get(bucket, key) do\n    Agent.get(bucket, &Map.get(&1, key))\n  end\n\n  @doc \"\"\"\n  Puts the `value` for the given `key` in the `bucket`.\n  \"\"\"\n  def put(bucket, key, value) do\n    Agent.update(bucket, &Map.put(&1, key, value))\n  end\nend\n```\n\nThe first step in our implementation is to call `use Agent`. This is a pattern we will see throughout the guides and understand in depth in the next chapter.\n\nThen we define a `start_link/1` function, which will effectively start the agent. It is a convention to define a `start_link/1` function that always accepts a list of options. We then call `Agent.start_link/2` passing an anonymous function that returns the Agent's initial state and the same list of options we received.\n\nWe are keeping a map inside the agent to store our keys and values. Getting and putting values on the map is done with the Agent API and the capture operator `&`, introduced in [the Getting Started guide](../getting-started/anonymous-functions.md#the-capture-operator). The agent passes its state to the anonymous function via the `&1` argument when `Agent.get/2` and `Agent.update/2` are called.\n\nNow that the `KV.Bucket` module has been defined, our test should pass! You can try it yourself by running: `mix test`.\n\n## Naming processes\n\nWhen starting `KV.Bucket`, we pass a list of options which we forward to `Agent.start_link/2`. One of the options accepted by `Agent.start_link/2` is a name option which allows us to name a process, so we can interact with it using its name instead of its PID.\n\nLet's write a test as an example. Back on `KV.BucketTest`, add this:\n\n```elixir\n  test \"stores values by key on a named process\" do\n    {:ok, _} = KV.Bucket.start_link(name: :shopping_list)\n    assert KV.Bucket.get(:shopping_list, \"milk\") == nil\n\n    KV.Bucket.put(:shopping_list, \"milk\", 3)\n    assert KV.Bucket.get(:shopping_list, \"milk\") == 3\n  end\n```\n\nHowever, keep in mind that names are shared in the current node. If two tests attempt to create two processes named `:shopping_list` at the same time, one would succeed and the other would fail. For this reason, it is a common practice in Elixir to name processes started during tests after the test itself, like this:\n\n```elixir\n  test \"stores values by key on a named process\", config do\n    {:ok, _} = KV.Bucket.start_link(name: config.test)\n    assert KV.Bucket.get(config.test, \"milk\") == nil\n\n    KV.Bucket.put(config.test, \"milk\", 3)\n    assert KV.Bucket.get(config.test, \"milk\") == 3\n  end\n```\n\nThe `config` argument, passed after the test name, is the *test context* and it includes configuration and metadata about the current test, which is useful in scenarios like these.\n\n## Other agent actions\n\nBesides getting a value and updating the agent state, agents allow us to get a value and update the agent state in one function call via `Agent.get_and_update/2`. Let's implement a `KV.Bucket.delete/2` function that deletes a key from the bucket, returning its current value:\n\n```elixir\n@doc \"\"\"\nDeletes `key` from `bucket`.\n\nReturns the current value of `key`, if `key` exists.\n\"\"\"\ndef delete(bucket, key) do\n  Agent.get_and_update(bucket, &Map.pop(&1, key))\nend\n```\n\nNow it is your turn to write a test for the functionality above! Also, be sure to explore [the documentation for the `Agent` module](`Agent`) to learn more about them.\n\n## Client/server in agents\n\nBefore we move on to the next chapter, let's discuss the client/server dichotomy in agents. Let's expand the `delete/2` function we have just implemented:\n\n```elixir\ndef delete(bucket, key) do\n  Agent.get_and_update(bucket, fn map ->\n    Map.pop(map, key)\n  end)\nend\n```\n\nEverything that is inside the function we passed to the agent happens in the agent process. In this case, since the agent process is the one receiving and responding to our messages, we say the agent process is the server. Everything outside the function is happening in the client.\n\nThis distinction is important. If there are expensive actions to be done, you must consider if it will be better to perform these actions on the client or on the server. For example:\n\n```elixir\ndef delete(bucket, key) do\n  Process.sleep(1000) # puts client to sleep\n  Agent.get_and_update(bucket, fn map ->\n    Process.sleep(1000) # puts server to sleep\n    Map.pop(map, key)\n  end)\nend\n```\n\nWhen a long action is performed on the server, all other requests to that particular server will wait until the action is done, which may cause some clients to timeout.\n\nSome APIs, such as GenServers, make a clearer distinction between client and server, and we will explore them in future chapters. Next let's talk about naming things, applications, and supervisors.\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/config-and-distribution.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Configuration and distribution\n\nSo far we have hardcoded our applications to run a web server on port 4040. This has been somewhat problematic since we can't, for example, run our development server and tests at the same time. In this chapter, we will learn how to use the application environment for configuration, paving the way for us to enable distribution by running multiple development servers on the same machine (on different ports).\n\nIn this last guide, we will make the routing table for our distributed key-value store configurable, and then finally package the software for production.\n\nLet's do this.\n\n## Application environment\n\nIn the chapter [Registries, applications, and supervisors](supervisor-and-application.md), we have learned that our project is backed by an application, which bundles our modules and specifies how your supervision tree starts and shuts down. Each application can also have its own configuration, which in Erlang/OTP (and therefore Elixir) is called \"application environment\".\n\nWe can use the application environment to configure our own application, as well as others. Let's see the application environment in practice. Create a file `config/runtime.exs` with the following:\n\n```elixir\nimport Config\n\nport =\n  cond do\n    port_env = System.get_env(\"PORT\") ->\n      String.to_integer(port_env)\n\n    config_env() == :test ->\n      4040\n\n    true ->\n      4050\n  end\n\nconfig :kv, :port, port\n```\n\nThe above is attempting to read the \"PORT\" environment variable and use it as the port if defined. Otherwise, we default to port `4040` for tests and port `4050` for other environments, eliminating the conflict between environments we have seen in the past. Then we store its value under the `:port` key of our `:kv` application.\n\nNow we just need to read this configuration. Open up `lib/kv.ex` and the `start/2` function to the following:\n\n```elixir\n  def start(_type, _args) do\n    port = Application.fetch_env!(:kv, :port)\n\n    children = [\n      {Registry, name: KV, keys: :unique},\n      {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one},\n      {Task.Supervisor, name: KV.ServerSupervisor},\n      Supervisor.child_spec({Task, fn -> KV.Server.accept(port) end}, restart: :permanent)\n    ]\n\n    Supervisor.start_link(children, strategy: :one_for_one)\n  end\n```\n\nRun `iex -S mix` and you will see the following message printed:\n\n```text\n[info] Accepting connections on port 4050\n```\n\nRun tests, without killing the development server, and you will see it running on port 4040.\n\nOur change was straight-forward. We used `Application.fetch_env!/2` to read the entry for `port` in `:kv`'s environment. We explicitly used `fetch_env!/2` (instead of `get_env/2` or `fetch_env`) because it will raise if the port was not configured (preventing the app from booting).\n\n## Compile vs runtime configuration\n\nConfiguration files provide a mechanism for us to configure the environment of any application. Elixir provides two configuration entry points:\n\n  * `config/config.exs` — this file is read at build time, before we compile our application and before we even load our dependencies. This means we can't access the code in our application nor in our dependencies. However, it means we can control how they are compiled\n\n  * `config/runtime.exs` — this file is read after our application and dependencies are compiled and therefore it can configure how our application works at runtime. If you want to read system environment variables (via `System.get_env/1`) or access external configuration, this is the appropriate place to do so\n\nYou can learn more about configuration in the `Config` and `Config.Provider` modules.\n\nGenerally speaking, we use `Application.fetch_env!/2` (and friends) to read runtime configuration. `Application.compile_env/2` is available for reading compile-time configuration. This allows Elixir to track which modules to recompile when the compilation environment changes.\n\nNow that we can start multiple servers, let's explore distribution.\n\n## Our first distributed code\n\nElixir ships with facilities to connect nodes and exchange information between them. In fact, we use the same concepts of processes, message passing and receiving messages when working in a distributed environment because Elixir processes are *location transparent*. This means that when sending a message, it doesn't matter if the recipient process is on the same node or on another node, the VM will be able to deliver the message in both cases.\n\nIn order to run distributed code, we need to start the VM with a name. The name can be short (when in the same network) or long (requires the full computer address). Let's start a new IEx session:\n\n```console\n$ iex --sname foo\n```\n\nYou can see now the prompt is slightly different and shows the node name followed by the computer name:\n\n    Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)\n    iex(foo@jv)1>\n\nMy computer is named `jv`, so I see `foo@jv` in the example above, but you will get a different result. We will use `foo@computer-name` in the following examples and you should update them accordingly when trying out the code.\n\nLet's define a module named `Hello` in this shell:\n\n```elixir\niex> defmodule Hello do\n...>   def world, do: IO.puts(\"hello world\")\n...> end\n```\n\nIf you have another computer on the same network with both Erlang and Elixir installed, you can start another shell on it. If you don't, you can start another IEx session in another terminal. In either case, give it the short name of `bar`:\n\n```console\n$ iex --sname bar\n```\n\nNote that inside this new IEx session, we cannot access `Hello.world/0`:\n\n```elixir\niex> Hello.world\n** (UndefinedFunctionError) function Hello.world/0 is undefined (module Hello is not available)\n    Hello.world()\n```\n\nHowever, we can spawn a new process on `foo@computer-name` from `bar@computer-name`! Let's give it a try (where `@computer-name` is the one you see locally):\n\n```elixir\niex> Node.spawn_link(:\"foo@computer-name\", fn -> Hello.world() end)\n#PID<9014.59.0>\nhello world\n```\n\nElixir spawned a process on another node and returned its PID. You can see the PID number no longer starts with zero, showing it belongs to another node. The code then executed on the other node where the `Hello.world/0` function exists and invoked that function. Note that the result of \"hello world\" was printed on the current node `bar` and not on `foo`. In other words, the message to be printed was sent back from `foo` to `bar`. This happens because the process spawned on the other node (`foo`) knows all the output should be sent back to the original node!\n\nWe can send and receive messages from the PID returned by `Node.spawn_link/2` as usual. Let's try a quick ping-pong example:\n\n```elixir\niex> pid = Node.spawn_link(:\"foo@computer-name\", fn ->\n...>   receive do\n...>     {:ping, client} -> send(client, :pong)\n...>   end\n...> end)\n#PID<9014.59.0>\niex> send(pid, {:ping, self()})\n{:ping, #PID<0.73.0>}\niex> flush()\n:pong\n:ok\n```\n\nIn other words, we can spawn processes in other nodes, hold onto their PIDs, and then send messages to them as if they were running on the same machine. That's the *location transparency* principle. And because everything we have built so far was built on top of messaging passing, we should be able to adjust our key-value store to become a distributed one with little work.\n\n## Distributed naming registry with `:global`\n\nFirst, let's check that our code is not currently distributed. Start a new node like this:\n\n```console\n$ PORT=4100 iex --sname foo -S mix\n```\n\nAnd the other like this:\n\n```console\n$ PORT=4101 iex --sname bar -S mix\n```\n\nNow, within `foo@computer-name`, do this:\n\n```elixir\niex> :erpc.call(:\"bar@computer-name\", KV, :create_bucket, [\"shopping\"])\n{:ok, #PID<22121.164.0>}\n```\n\nInstead of using `Node.spawn_link/2`, we used [Erlang's builtin RPC module](`:erpc`) to call the function `create_bucket` in the `KV` module passing a one element list with the string \"shopping\" as the argument list. We could have used `Node.spawn_link/2`, but `:erpc.call/4` conveniently returns the result of the invocation.\n\nStill in `foo@computer-name`, let's try to access the bucket:\n\n```elixir\niex> KV.lookup_bucket(\"shopping\")\nnil\n```\n\nIt returns `nil`. However, if you run `KV.lookup_bucket(\"shopping\")` in `bar@computer-name`, it will return the proper bucket. In other words, the nodes can communicate with each other, but buckets spawned in one node are not visible to the other.\n\nThis is because we are using [Elixir's Registry](`Registry`) to name our buckets, which is a **local** process registry. In other words, it is designed for processes running on a single node and not for distribution.\n\nLuckily, Erlang ships with a distributed registry called [`:global`](`:global`), which is directly supported by the `:name` option by passing a `{:global, name}` tuple. All we need to do is update the `via/1` function in `lib/kv.ex` from this:\n\n```elixir\n  defp via(name), do: {:via, Registry, {KV, name}}\n```\n\nto this:\n\n```elixir\n  defp via(name), do: {:global, name}\n```\n\nDo the change above and restart both `foo@computer-name` and `bar@computer-name`. Now, back on `foo@computer-name`, let's give it another try:\n\n```elixir\niex> :erpc.call(:\"bar@computer-name\", KV, :create_bucket, [\"shopping\"])\n{:ok, #PID<21821.179.0>}\niex> KV.lookup_bucket(\"shopping\")\n#PID<21821.179.0>\n```\n\nAnd there you go! By simply changing which naming registry we used, we now have a distributed key value store. You can even try using `telnet` to connect to the servers on different ports and validate that changes in one session are visible in the other one. Exciting!\n\n## Node discovery and dependencies\n\nThere is one essential ingredient to wrap up our distributed key-value store. In order for the `:global` registry to work, we need to make sure the nodes are connected to each other. When we run `:erpc` call passing the node name:\n\n```elixir\n:erpc.call(:\"bar@computer-name\", KV, :create_bucket, [\"shopping\"])\n```\n\nElixir automatically connected the nodes together. This is easy to do in an IEx session when both instances are running on the same machine but it requires more work in a production environment, where instances are on different machines which may be started at any time and running on different IP addresses.\n\nLuckily for us, this is also a well-solved problem. For example, if you are using [the Phoenix web framework](https://phoenixframework.org) in production, it ships with [the `dns_cluster` package](https://github.com/phoenixframework/dns_cluster), which automatically runs DNS queries to find new nodes and connect them. If you are using Kubernetes or cloud providers, [packages like `libcluster`](https://github.com/bitwalker/libcluster) ship with different strategies to discover and connect nodes.\n\nInstalling dependencies in Elixir is simple. Most commonly, we use the [Hex Package Manager](https://hex.pm), by listing the dependency inside the deps function in our `mix.exs` file:\n\n```elixir\ndef deps do\n  [{:dns_cluster, \"~> 0.2\"}]\nend\n```\n\nThis dependency refers to the latest version of `dns_cluster` in the 0.x version series that has been pushed to Hex. This is indicated by the `~>` preceding the version number. For more information on specifying version requirements, see the documentation for the `Version` module.\n\nTypically, stable releases are pushed to Hex. If you want to depend on an external dependency still in development, Mix is able to manage Git dependencies too:\n\n```elixir\ndef deps do\n  [{:dns_cluster, git: \"https://github.com/phoenixframework/dns_cluster.git\"}]\nend\n```\n\nYou will notice that when you add a dependency to your project, Mix generates a `mix.lock` file that guarantees *repeatable builds*. The lock file must be checked in to your version control system, to guarantee that everyone who uses the project will use the same dependency versions as you.\n\nMix provides many tasks for working with dependencies, which can be seen in `mix help`:\n\n```console\n$ mix help\nmix deps              # Lists dependencies and their status\nmix deps.clean        # Deletes the given dependencies' files\nmix deps.compile      # Compiles dependencies\nmix deps.get          # Gets all out of date dependencies\nmix deps.tree         # Prints the dependency tree\nmix deps.unlock       # Unlocks the given dependencies\nmix deps.update       # Updates the given dependencies\n```\n\nThe most common tasks are `mix deps.get` and `mix deps.update`. Once fetched, dependencies are automatically compiled for you. You can read more about deps by running `mix help deps`.\n\nTo wrap up this chapter, we will build a very simple node discovery mechanism, where the name of the nodes we should connect to are given on boot, using the lessons we learned in this chapter.\n\n## `Node.connect/1`\n\nWe will change our application to support a \"NODES\" environment variable with the name of all nodes each instance should connect to.\n\nOpen up `config/runtime.exs` and add this to the bottom:\n\n```elixir\nnodes =\n  System.get_env(\"NODES\", \"\")\n  |> String.split(\",\", trim: true)\n  |> Enum.map(&String.to_atom/1)\n\nconfig :kv, :nodes, nodes\n```\n\nWe fetch the environment variable, split it on \",\" while discarding all empty strings, and then convert each entry to an atom, as node names are atoms.\n\nNow, in your `start/2` callback, we will add this to of the `start/2` function:\n\n```elixir\n  def start(_type, _args) do\n    for node <- Application.fetch_env!(:kv, :nodes) do\n      Node.connect(node)\n    end\n```\n\nNow we can start our nodes as:\n\n```console\n$ NODES=\"foo@computer-name,bar@computer-name\" PORT=4040 iex --sname foo -S mix\n$ NODES=\"foo@computer-name,bar@computer-name\" PORT=4041 iex --sname bar -S mix\n```\n\nAnd they should connect to each other. Give it a try!\n\nIn an actual production system, there is some additional care we must take. For example, we often use `--name` instead of `--sname` and give fully qualified node names.\n\nFurthermore, when connecting two instances, we must guarantee they have the same cookie, which is a secret Erlang uses to authorize the connection. When they run on the same machine, they share the same cookie by default, but it must be either explicitly set or shared in other ways when deploying in a cluster.\n\nWe will revisit these topics in the last chapter when we talk about releases.\n\n## Distributed system trade-offs\n\nIn this chapter, we made our key-value store distributed by using the `:global` naming registry. However, it is important to keep in mind that every distributed system, be it a library or a full-blown database, is designed with a series of trade-offs in mind.\n\nIn particular, `:global` requires consistency across all known nodes whenever a new bucket is created. For example, if your cluster has three nodes, creating a new bucket will require all three nodes to agree on its name. This means if one node is unresponsive, perhaps due to a [network partition](https://en.wikipedia.org/wiki/Network_partition), the node will have to either reconnect or be kicked out before registration succeeds. This also means that, as your cluster grows in size, registration becomes more expensive, although lookups are always cheap and immediate. Within the ecosystem, there are other named registries, which explore different trade-offs, such as [Syn](https://github.com/ostinelli/syn).\n\nFurther complications arise when we consider storage. Today, when our nodes terminate, we lose all data stored in the buckets. In our current design, since we allow each node to store their own buckets, it means we would need to backup each node. And, if we don't want data losses, we would also need to replicate the data.\n\nFor those reasons, it is still very common to use a database (or any storage system) when writing production applications in Elixir, and use Elixir to implement the realtime and collaborative aspects of your applications that extend beyond storage. For example, we can use Elixir to track which clients are connected to the cluster at any given moment or implement a feed where users are notified in realtime whenever items are added or removed from a bucket.\n\nIn fact, that's exactly what we will build in the next chapter. Allowing us to wrap up everything we have learned so far and also talk about one of the essential building blocks in Elixir software: GenServers.\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/docs-tests-and-with.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Doctests, patterns, and with\n\nIn this chapter, we will implement the code that parses the commands we described in the first chapter:\n\n```text\nCREATE shopping\nOK\n\nPUT shopping milk 1\nOK\n\nPUT shopping eggs 3\nOK\n\nGET shopping milk\n1\nOK\n\nDELETE shopping eggs\nOK\n```\n\nAfter the parsing is done, we will update our server to dispatch the parsed commands to the relevant buckets.\n\n## Doctests\n\nOn the language homepage, we mention that Elixir makes documentation a first-class citizen in the language. We have explored this concept many times throughout this guide, be it via `mix help` or by typing `h Enum` or another module in an IEx console.\n\nIn this section, we will implement the parsing functionality, document it and make sure our documentation is up to date with doctests. This helps us provide documentation with accurate code samples.\n\nLet's create our command parser at `lib/kv/command.ex` and start with the doctest:\n\n```elixir\ndefmodule KV.Command do\n  @doc ~S\"\"\"\n  Parses the given `line` into a command.\n\n  ## Examples\n\n      iex> KV.Command.parse(\"CREATE shopping\\r\\n\")\n      {:ok, {:create, \"shopping\"}}\n\n  \"\"\"\n  def parse(_line) do\n    :not_implemented\n  end\nend\n```\n\nDoctests are specified by an indentation of four spaces followed by the `iex>` prompt in a documentation string. If a command spans multiple lines, you can use `...>`, as in IEx. The expected result should start at the next line after `iex>` or `...>` line(s) and is terminated either by a newline or a new `iex>` prefix.\n\nAlso, note that we started the documentation string using `@doc ~S\"\"\"`. The `~S` prevents the `\\r\\n` characters from being converted to a carriage return and line feed until they are evaluated in the test.\n\nTo run our doctests, we'll create a file at `test/kv/command_test.exs` and call `doctest KV.Command` in the test case:\n\n```elixir\ndefmodule KV.CommandTest do\n  use ExUnit.Case, async: true\n  doctest KV.Command\nend\n```\n\nRun the test suite and the doctest should fail:\n\n```text\n  1) doctest KV.Command.parse/1 (1) (KV.CommandTest)\n     test/kv/command_test.exs:3\n     Doctest failed\n     doctest:\n       iex> KV.Command.parse(\"CREATE shopping\\r\\n\")\n       {:ok, {:create, \"shopping\"}}\n     code: KV.Command.parse \"CREATE shopping\\r\\n\" === {:ok, {:create, \"shopping\"}}\n     left:  :not_implemented\n     right: {:ok, {:create, \"shopping\"}}\n     stacktrace:\n       lib/kv/command.ex:7: KV.Command (module)\n```\n\nExcellent!\n\nNow let's make the doctest pass. Let's implement the `parse/1` function:\n\n```elixir\ndef parse(line) do\n  case String.split(line) do\n    [\"CREATE\", bucket] -> {:ok, {:create, bucket}}\n  end\nend\n```\n\nOur implementation splits the line on whitespace and then matches the command against a list. Using `String.split/1` means our commands will be whitespace-insensitive. Leading and trailing whitespace won't matter, nor will consecutive spaces between words. Let's add some new doctests to test this behavior along with the other commands:\n\n```elixir\n  @doc ~S\"\"\"\n  Parses the given `line` into a command.\n\n  ## Examples\n\n      iex> KV.Command.parse \"CREATE shopping\\r\\n\"\n      {:ok, {:create, \"shopping\"}}\n\n      iex> KV.Command.parse \"CREATE  shopping  \\r\\n\"\n      {:ok, {:create, \"shopping\"}}\n\n      iex> KV.Command.parse \"PUT shopping milk 1\\r\\n\"\n      {:ok, {:put, \"shopping\", \"milk\", \"1\"}}\n\n      iex> KV.Command.parse \"GET shopping milk\\r\\n\"\n      {:ok, {:get, \"shopping\", \"milk\"}}\n\n      iex> KV.Command.parse \"DELETE shopping eggs\\r\\n\"\n      {:ok, {:delete, \"shopping\", \"eggs\"}}\n\n  Unknown commands or commands with the wrong number of\n  arguments return an error:\n\n      iex> KV.Command.parse \"UNKNOWN shopping eggs\\r\\n\"\n      {:error, :unknown_command}\n\n      iex> KV.Command.parse \"GET shopping\\r\\n\"\n      {:error, :unknown_command}\n\n  \"\"\"\n```\n\nWith doctests at hand, it is your turn to make tests pass! Once you're ready, you can compare your work with our solution below:\n\n```elixir\n  def parse(line) do\n    case String.split(line) do\n      [\"CREATE\", bucket] -> {:ok, {:create, bucket}}\n      [\"GET\", bucket, key] -> {:ok, {:get, bucket, key}}\n      [\"PUT\", bucket, key, value] -> {:ok, {:put, bucket, key, value}}\n      [\"DELETE\", bucket, key] -> {:ok, {:delete, bucket, key}}\n      _ -> {:error, :unknown_command}\n    end\n  end\n```\n\nNotice how we were able to elegantly parse the commands without adding a bunch of `if/else` clauses that check the command name and number of arguments!\n\nFinally, you may have observed that each doctest corresponds to a different test in our suite, which now reports a total of 7 doctests. That is because ExUnit considers the following to define two different doctests:\n\n```elixir\niex> KV.Command.parse(\"UNKNOWN shopping eggs\\r\\n\")\n{:error, :unknown_command}\n\niex> KV.Command.parse(\"GET shopping\\r\\n\")\n{:error, :unknown_command}\n```\n\nWithout new lines, as seen below, ExUnit compiles it into a single doctest:\n\n```elixir\niex> KV.Command.parse(\"UNKNOWN shopping eggs\\r\\n\")\n{:error, :unknown_command}\niex> KV.Command.parse(\"GET shopping\\r\\n\")\n{:error, :unknown_command}\n```\n\nAs the name says, doctest is documentation first and a test later. Their goal is not to replace tests but to provide up-to-date documentation. You can read more about doctests in the `ExUnit.DocTest` documentation.\n\n## Using `with`\n\nAs we are now able to parse commands, we can finally start implementing the logic that runs the commands. Let's add a stub definition for this function for now:\n\n```elixir\ndefmodule KV.Command do\n  @doc \"\"\"\n  Runs the given command.\n  \"\"\"\n  def run(command, socket) do\n    :gen_tcp.send(socket, \"OK\\r\\n\")\n    :ok\n  end\nend\n```\n\nBefore we implement this function, let's change our server to start using our new `parse/1` and `run/1` functions. Remember, our `read_line/1` function was also crashing when the client closed the socket, so let's take the opportunity to fix it, too. Open up `lib/kv/server.ex` and replace the existing server definition:\n\n```elixir\n  defp serve(socket) do\n    socket\n    |> read_line()\n    |> write_line(socket)\n\n    serve(socket)\n  end\n\n  defp read_line(socket) do\n    {:ok, data} = :gen_tcp.recv(socket, 0)\n    data\n  end\n\n  defp write_line(line, socket) do\n    :gen_tcp.send(socket, line)\n  end\n```\n\nby the following:\n\n```elixir\n  defp serve(socket) do\n    msg =\n      case read_line(socket) do\n        {:ok, data} ->\n          case KV.Command.parse(data) do\n            {:ok, command} ->\n              KV.Command.run(command, socket)\n\n            {:error, _} = err ->\n              err\n          end\n\n        {:error, _} = err ->\n          err\n      end\n\n    write_line(socket, msg)\n    serve(socket)\n  end\n\n  defp read_line(socket) do\n    :gen_tcp.recv(socket, 0)\n  end\n\n  defp write_line(_socket, :ok) do\n    :ok\n  end\n\n  defp write_line(socket, {:error, :unknown_command}) do\n    # Known error; write to the client\n    :gen_tcp.send(socket, \"UNKNOWN COMMAND\\r\\n\")\n  end\n\n  defp write_line(_socket, {:error, :closed}) do\n    # The connection was closed, exit politely\n    exit(:shutdown)\n  end\n\n  defp write_line(socket, {:error, error}) do\n    # Unknown error; write to the client and exit\n    :gen_tcp.send(socket, \"ERROR\\r\\n\")\n    exit(error)\n  end\n```\n\nIf we start our server, we can now send commands to it. For now, we will get two different responses: \"OK\" when the command is known and \"UNKNOWN COMMAND\" otherwise:\n\n```console\n$ telnet 127.0.0.1 4040\nTrying 127.0.0.1...\nConnected to localhost.\nEscape character is '^]'.\nCREATE shopping\nOK\nHELLO\nUNKNOWN COMMAND\n```\n\nThis means our implementation is going in the correct direction, but it doesn't look very elegant, does it?\n\nThe previous implementation used pipelines which made the logic straightforward to follow. However, now that we need to handle different error codes along the way, our server logic is nested inside many `case` calls.\n\nThankfully, Elixir has the `with` construct, which allows you to simplify code like the above, replacing nested `case` calls with a chain of matching clauses. Let's rewrite the `serve/1` function to use `with`:\n\n```elixir\n  defp serve(socket) do\n    msg =\n      with {:ok, data} <- read_line(socket),\n          {:ok, command} <- KV.Command.parse(data),\n          do: KV.Command.run(command, socket)\n\n    write_line(socket, msg)\n    serve(socket)\n  end\n```\n\nMuch better! `with` will retrieve the value returned by the right-side of `<-` and match it against the pattern on the left side. If the value matches the pattern, `with` moves on to the next expression. In case there is no match, the non-matching value is returned.\n\nIn other words, we converted each expression given to `case/2` as a step in `with`. As soon as any of the steps return something that does not match `{:ok, x}`, `with` aborts, and returns the non-matching value.\n\nYou can read more about `with/1` in our documentation.\n\n## Running commands\n\nThe last step is to implement `KV.Command.run/1` to run the parsed commands on top of buckets. Its implementation is shown below:\n\n```elixir\n  @doc \"\"\"\n  Runs the given command.\n  \"\"\"\n  def run(command, socket)\n\n  def run({:create, bucket}, socket) do\n    KV.create_bucket(bucket)\n    :gen_tcp.send(socket, \"OK\\r\\n\")\n    :ok\n  end\n\n  def run({:get, bucket, key}, socket) do\n    lookup(bucket, fn pid ->\n      value = KV.Bucket.get(pid, key)\n      :gen_tcp.send(socket, \"#{value}\\r\\nOK\\r\\n\")\n      :ok\n    end)\n  end\n\n  def run({:put, bucket, key, value}, socket) do\n    lookup(bucket, fn pid ->\n      KV.Bucket.put(pid, key, value)\n      :gen_tcp.send(socket, \"OK\\r\\n\")\n      :ok\n    end)\n  end\n\n  def run({:delete, bucket, key}, socket) do\n    lookup(bucket, fn pid ->\n      KV.Bucket.delete(pid, key)\n      :gen_tcp.send(socket, \"OK\\r\\n\")\n      :ok\n    end)\n  end\n\n  defp lookup(bucket, callback) do\n    if bucket = KV.lookup_bucket(bucket) do\n      callback.(bucket)\n    else\n      {:error, :not_found}\n    end\n  end\n```\n\nEach function clause dispatches the appropriate command to the appropriate bucket.\n\nYou might have noticed we have a function head, `def run(command, socket)`, without a body. In the [Modules and Functions](../getting-started/modules-and-functions.md#default-arguments) chapter, we learned that a bodiless function can be used to declare default arguments for a multi-clause function. Here is another use case where we use a function without a body to document what the arguments are.\n\nWe have also defined a private function named `lookup/2` to help with the common functionality of looking up a bucket and returning its `pid` if it exists, `{:error, :not_found}` otherwise.\n\nBy the way, since we are now returning `{:error, :not_found}`, we should amend the `write_line/2` function in `KV.Server` to print such error as well:\n\n```elixir\ndefp write_line(socket, {:error, :not_found}) do\n  :gen_tcp.send(socket, \"NOT FOUND\\r\\n\")\nend\n```\n\nOur server functionality is almost complete. Only tests are missing.\n\n## Integration tests\n\n`KV.Command.run/1`'s implementation is sending commands directly to the `KV` module, which is using a local registry to name processes. This means if we have two tests sending messages to the same bucket, our tests will conflict with each other (and likely fail). One might think this would be a reason to use mocks and other strategies to keep our tests isolated, but such techniques often make our testing environment too distant from how our code actually runs in production, and you may end-up with bugs lurking.\n\nLuckily, there is a technique that we have been using throughout this guide that would be equally applicable here: it is ok to rely on the local registry as long as each test uses unique names. Using a combination of the test module and test name is more than enough to guarantee that.\n\nSo let's write integration tests that rely on unique names to exercise the whole stack from the TCP server to the bucket.\n\nCreate a new file at `test/kv/server_test.exs` as shown below:\n\n```elixir\ndefmodule KV.ServerTest do\n  use ExUnit.Case, async: true\n\n  @socket_options [:binary, packet: :line, active: false]\n\n  setup config do\n    {:ok, socket} = :gen_tcp.connect(~c\"localhost\", 4040, @socket_options)\n    test_name = config.test |> Atom.to_string() |> String.replace(\" \", \"-\")\n    %{socket: socket, name: \"#{config.module}-#{test_name}\"}\n  end\n\n  test \"server interaction\", %{socket: socket, name: name} do\n    # CREATE\n    assert send_and_recv(socket, \"CREATE #{name}\\r\\n\") == \"OK\\r\\n\"\n\n    # PUT\n    assert send_and_recv(socket, \"PUT #{name} eggs 3\\r\\n\") == \"OK\\r\\n\"\n\n    # GET\n    assert send_and_recv(socket, \"GET #{name} eggs\\r\\n\") == \"3\\r\\n\"\n    assert send_and_recv(socket, \"\") == \"OK\\r\\n\"\n\n    # DELETE\n    assert send_and_recv(socket, \"DELETE #{name} eggs\\r\\n\") == \"OK\\r\\n\"\n\n    # GET\n    assert send_and_recv(socket, \"GET #{name} eggs\\r\\n\") == \"\\r\\n\"\n    assert send_and_recv(socket, \"\") == \"OK\\r\\n\"\n  end\n\n  test \"unknown command\", %{socket: socket} do\n    assert send_and_recv(socket, \"WHATEVER\\r\\n\") ==\n             \"UNKNOWN COMMAND\\r\\n\"\n  end\n\n  test \"unknown bucket\", %{socket: socket} do\n    assert send_and_recv(socket, \"GET whatever eggs\\r\\n\") ==\n             \"NOT FOUND\\r\\n\"\n  end\n\n  defp send_and_recv(socket, command) do\n    :ok = :gen_tcp.send(socket, command)\n    {:ok, data} = :gen_tcp.recv(socket, 0, 1000)\n    data\n  end\nend\n```\n\nRun `mix test` and the tests should all pass. However, make sure to terminate any `iex -S mix` session you may have running, as currently tests and development environment are running on the same port (4040). We will address it in the next chapter.\n\nWe added three tests, the first one tests most bucket actions, while the other two deal with error cases. Given there is a lot of shared setup across these tests, we used the `setup/2` macro to deal with common boilerplate. The macro receives the same *test context* as tests and starts a client TCP connection per test. It also defines a unique bucket name using the module name and the test name, making sure any space in the test name is replaced by `-` as to not interfere with our command parsing logic.\n\nThen, in each test, we pattern matched on the *test context*, extracting the socket or name as necessary. This is similar to the code we wrote in `test/kv/bucket_test.exs`:\n\n```elixir\n  test \"stores values by key on a named process\", config do\n```\n\nExcept back then we matched on all config and, this time around, we matched only on the data we needed.\n\nLet's move to the next chapter. We will finally make our system distributed by adding a tiny bit of configuration and, *spoiler alert*, changing one line of code.\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/dynamic-supervisor.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Supervising dynamic children\n\nWe have successfully learned how our supervision tree is automatically started (and stopped) as part of our application's life cycle. We can also name our buckets via the `:name` option. We also learned that, in practice, we should always start new processes inside supervisors. Let's apply these insights by ensuring our buckets are named and supervised.\n\n## Child specs\n\nSupervisors know how to start processes because they are given \"child specifications\". In our `lib/kv.ex` file, we defined a list of children with a single child spec:\n\n```elixir\nchildren = [\n  {Registry, name: KV, keys: :unique}\n]\n```\n\nWhen the child specification is a tuple (as above) or module, then it is equivalent to calling the `child_spec/1` function on said module, which then returns the full specification. The pair above is equivalent to:\n\n```elixir\niex> Registry.child_spec(name: KV, keys: :unique)\n%{\n  id: KV,\n  start: {Registry, :start_link, [[name: KV, keys: :unique]]},\n  type: :supervisor\n}\n```\n\nThe underlying map returns the `:id` (required), the module-function-args triplet to invoke to start the process (required), the type of the process (optional), among other optional keys. In other words, the `child_spec/1` function allows us to compose and encapsulate specifications in modules.\n\nTherefore, if we want to supervise `KV.Bucket`, we only need to define a `child_spec/1` function. Luckily for us, whenever we invoke `use Agent` (or `use GenServer` or `use Supervisor` and so forth), an implementation with reasonable defaults is provided. So let's take it for a spin. Back on `iex -S mix`, try this:\n\n```elixir\niex> KV.Bucket.child_spec([])\n%{id: KV.Bucket, start: {KV.Bucket, :start_link, [[]]}}\niex> KV.Bucket.child_spec([name: :shopping])\n%{id: KV.Bucket, start: {KV.Bucket, :start_link, [[name: :shopping]]}}\n```\n\nLet's try to start it as part of a supervisor then, using the `{module, options}` format to pass the bucket name (let's also use an atom as the name for convenience):\n\n```elixir\niex> children = [{KV.Bucket, name: :shopping}]\niex> Supervisor.start_link(children, strategy: :one_for_one)\niex> KV.Bucket.put(:shopping, \"milk\", 1)\n:ok\niex> KV.Bucket.get(:shopping, \"milk\")\n1\n```\n\nWhat happens now if we explicitly kill the bucket process?\n\n```elixir\n# Find the pid for the given name\niex> pid = Process.whereis(:shopping)\n#PID<0.48.0>\n# Send it a kill exit signal\niex> Process.exit(pid, :kill)\ntrue\n# But a new process is alive in its place\niex> Process.whereis(:shopping)\n#PID<0.50.0>\n```\n\nGiven our buckets can already be supervised, it is time to hook them into our supervision tree.\n\n## Dynamic supervisors\n\nGiven our buckets can already be supervised, you may be thinking to start them as part of our application `start/2` callback, such as:\n\n```elixir\nchildren = [\n  {Registry, name: KV, keys: :unique}\n  {KV.Bucket, name: {:via, Registry, {KV, \"shopping\"}}}\n]\n```\n\nAnd while the above would definitely work, it comes with a huge caveat: it only starts a single bucket. In practice, we want the user to be able to create new buckets at any time. In other words, we need to start and supervise processes dynamically.\n\nWhile the `Supervisor` module has APIs for starting children after its initialization, it was not designed or optimized for the use case of having potentially millions of children. For this purpose, Elixir instead provides the `DynamicSupervisor` module. Using it is quite similar to `Supervisor` except that, instead of specifying the children during start, you do it afterwards. Let's take it for a spin:\n\n```elixir\niex> {:ok, sup_pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\niex> DynamicSupervisor.start_child(sup_pid, {KV.Bucket, name: :another_list})\niex> KV.Bucket.put(:another_list, \"milk\", 1)\n:ok\niex> KV.Bucket.get(:another_list, \"milk\")\n1\n```\n\nAnd it all works as expected. In fact, we can even give names to `DynamicSupervisor` themselves, instead of passing PIDs around and also use it to start buckets named using the registry:\n\n```elixir\niex> DynamicSupervisor.start_link(strategy: :one_for_one, name: :dyn_sup)\niex> name = {:via, Registry, {KV, \"yet_another_list\"}}\niex> DynamicSupervisor.start_child(:dyn_sup, {KV.Bucket, name: name})\niex> KV.Bucket.put(name, \"milk\", 1)\n:ok\niex> KV.Bucket.get(name, \"milk\")\n1\n```\n\nOverall, processes can be named and supervised, regardless if they are supervisors, agents, etc, since all of Elixir standard library was designed around those capabilities.\n\nWith all ingredients in place to supervise and name buckets, open up the `lib/kv.ex` module and let's add a new function called `KV.lookup_bucket/1`, which receives a name and either create or returns a bucket for the given name:\n\n```elixir\ndefmodule KV do\n  use Application\n\n  @impl true\n  def start(_type, _args) do\n    children = [\n      {Registry, name: KV, keys: :unique},\n      {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one}\n    ]\n\n    Supervisor.start_link(children, strategy: :one_for_one)\n  end\n\n  @doc \"\"\"\n  Creates a bucket with the given name.\n  \"\"\"\n  def create_bucket(name) do\n    DynamicSupervisor.start_child(KV.BucketSupervisor, {KV.Bucket, name: via(name)})\n  end\n\n  @doc \"\"\"\n  Looks up the given bucket.\n  \"\"\"\n  def lookup_bucket(name) do\n    GenServer.whereis(via(name))\n  end\n\n  defp via(name), do: {:via, Registry, {KV, name}}\nend\n```\n\nThe code is relatively simple. First we changed `start/2` to also start a dynamic supervisor named `KV.BucketSupervisor`. Then, when implemented `KV.create_bucket/1` which receives a bucket and starts with using our registry and dynamic supervisor. And we also added `KV.lookup_bucket/1` that receives the same name and attempts to find its PID.\n\nTo make sure it all works as expected, let's write a test. Open up `test/kv_test.exs` and add this:\n\n```elixir\ndefmodule KVTest do\n  use ExUnit.Case, async: true\n\n  test \"creates and looks up buckets by any name\" do\n    name = \"a unique name that won't be shared\"\n    assert is_nil(KV.lookup_bucket(name))\n\n    assert {:ok, bucket} = KV.create_bucket(name)\n    assert KV.lookup_bucket(name) == bucket\n\n    assert KV.create_bucket(name) == {:error, {:already_started, bucket}}\n  end\nend\n```\n\nThe test shows we are creating and locating buckets with any name, making sure we use a unique name to avoid conflicts between tests.\n\n## The `start_supervised` test helper\n\nBefore we move on, let's do some clean up.\n\nIn `test/kv/bucket_test.exs`, we explicitly invoked `KV.Bucket.start_link/1` to start our buckets. However, we now know that we should avoid calling `start_link/1` directly and instead start processes as part of supervision trees.\n\nIn order to aid testing, `ExUnit` already starts a supervision tree per test and provides the `start_supervised` function to start processes within test-specific supervision tree. One advantage of this approach is that `ExUnit` guarantees any started process is shut down at the end of the test too. Let's rewrite our tests to use it instead:\n\n```elixir\ndefmodule KV.BucketTest do\n  use ExUnit.Case, async: true\n\n  test \"stores values by key\" do\n    {:ok, bucket} = start_supervised(KV.Bucket)\n    assert KV.Bucket.get(bucket, \"milk\") == nil\n\n    KV.Bucket.put(bucket, \"milk\", 3)\n    assert KV.Bucket.get(bucket, \"milk\") == 3\n  end\n\n  test \"stores values by key on a named process\", config do\n    {:ok, _} = start_supervised({KV.Bucket, name: config.test})\n    assert KV.Bucket.get(config.test, \"milk\") == nil\n\n    KV.Bucket.put(config.test, \"milk\", 3)\n    assert KV.Bucket.get(config.test, \"milk\") == 3\n  end\nend\n```\n\nIt is a small change, but our tests are now using all of the relevant best practices. Excellent!\n\n## Observer\n\nNow that we have defined our supervision tree, it is a great opportunity to introduce the Observer tool that ships with Erlang. Start your application with `iex -S mix` and key this in:\n\n```elixir\niex> :observer.start()\n```\n\n> #### Missing dependencies {: .warning}\n>\n> When running `iex` inside a project with `iex -S mix`, `observer` won't be available as a dependency. To do so, you will need to call the following functions:\n>\n> ```elixir\n> iex> Mix.ensure_application!(:observer)\n> iex> :observer.start()\n> ```\n>\n> If the call above fails, here is what may have happened: some package managers default to installing a minimized Erlang without WX bindings for GUI support. In some package managers, you may be able to replace the headless Erlang with a more complete package (look for packages named `erlang` vs `erlang-nox` on Debian/Ubuntu/Arch). In others managers, you may need to install a separate `erlang-wx` (or similarly named) package.\n>\n> There are conversations to improve this experience in future releases.\n\nA GUI should pop up containing all sorts of information about our system, from general statistics to load charts as well as a list of all running processes and applications.\n\nIn the Applications tab, you will see all applications currently running in your system alongside their supervision tree. You can select the `kv` application to explore it further:\n\n<img src=\"assets/kv-observer.png\" alt=\"Observer GUI screenshot\" />\n\nNot only that, as you create new buckets on the terminal, you should see new processes spawned in the supervision tree shown in Observer:\n\n```elixir\niex> KV.create_bucket(\"shopping\")\n#PID<0.89.0>\n```\n\nWe will leave it up to you to further explore what Observer provides. Note you can double-click any process in the supervision tree to retrieve more information about it, as well as right-click a process to send \"a kill signal\", a perfect way to emulate failures and see if your supervisor reacts as expected.\n\nAt the end of the day, tools like Observer are one of the reasons you want to always start processes inside supervision trees, even if they are temporary, to ensure they are always reachable and introspectable.\n\nNow that our buckets are named and supervised, we are ready to start our server and start receiving requests.\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/genservers.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Client-server with GenServer\n\nTo wrap up our distributed key-value store, we will implement a feature where a client can subscribe to a bucket and receive realtime notifications of any modification happening in the bucket, regardless of where in the cluster the bucket is located.\n\nWe will do by adding a new command, called SUBSCRIBE, to be used like this:\n\n```text\nSUBSCRIBE shopping\nmilk SET TO 1\neggs SET TO 10\nmilk DELETED\n```\n\nTo make this work, we must change our `KV.Bucket` implementation to track subscriptions and emit broadcasts. However, as we will see, we cannot implement such on top of agents, and we will need to rewrite our bucket implementation to a `GenServer`.\n\n## Links and monitors\n\nProcesses in Elixir are isolated. When they need to communicate, they do so by sending messages. However, how do you know when a process terminates, either because it has completed or due to a crash?\n\nWe have two options: links and monitors.\n\nWe have used links extensively. Whenever we started a process, we typically did so by using `start_link` or similar. The idea behind links is that, if any of the processes crash, the other will crash due to the link. We talked about them in the [Process chapter of the Getting Started guide](../getting-started/processes.md). Here is a refresher:\n\n```elixir\niex> self()\n#PID<0.115.0>\niex> spawn_link(fn -> :nothing_bad_will_happen end)\n#PID<0.116.0>\niex> self()\n#PID<0.115.0>\n```\n\n```elixir\niex> spawn_link(fn -> raise \"oops\" end)\n#PID<0.117.0>\n\n12:37:33.229 [error] Process #PID<0.117.0> raised an exception\nInteractive Elixir (1.18.4) - press Ctrl+C to exit (type h() ENTER for help)\niex> self()\n#PID<0.118.0>\n```\n\nThe reason why we links are so pervasive is because when we start a process inside a supervisor, we want our process to crash if the supervisor terminates. On the other hand, we don't want the supervisor to crash when a child terminates, and therefore supervisors trap exits from links by calling `Process.flag(:trap_exit, true)`.\n\nIn other words, links create an intrinsic relationship between the processes. If we simply want to track when a process dies, without tying their exit signals to each other, a better solution is to use monitors. When a monitored process terminates, we receive a message in our inbox, regardless of the reason:\n\n```elixir\niex> pid = spawn(fn -> Process.sleep(5000) end)\n#PID<0.119.0>\niex> Process.monitor(pid)\n#Reference<0.1076459149.2159017989.118674>\niex> flush()\n:ok\n# Wait five seconds\niex> flush()\n{:DOWN, #Reference<0.1076459149.2159017989.118674>, :process, #PID<0.119.0>, :normal}\n:ok\n```\n\nOnce the process terminates, we receive a \"DOWN message\", represented in a five-element tuple. The last element is the reason why it crashed (`:normal` means it terminated successfully).\n\nMonitors will play a very important role in our subscribe feature. When a client subscribes to a bucket, the bucket will store the client PID and send messages to it on every change. However, if the client terminates (for example because it was disconnected), the bucket must remove the client from its list of subscribers (otherwise the list would keep on growing forever as clients connect and disconnect).\n\nWe chose the `Agent` module to implement our `KV.Bucket` and, unfortunately, agents cannot receive messages. So the first step is to rewrite our `KV.Bucket` to a `GenServer`. The `GenServer` module documentation has a good overview on what they are and how to implement them. Give it a read and then we are ready to proceed.\n\n## GenServer callbacks\n\nA GenServer is a process that invokes a limited set of functions under specific conditions. When we used an `Agent`, we would keep both the client code and the server code side by side, like this:\n\n```elixir\ndef put(bucket, key, value) do\n  Agent.update(bucket, &Map.put(&1, key, value))\nend\n```\n\nLet's break that code apart a bit:\n\n```elixir\ndef put(bucket, key, value) do\n  # Here is the client code\n  Agent.update(bucket, fn state ->\n    # Here is the server code\n    Map.put(state, key, value)\n  end)\n  # Back to the client code\nend\n```\n\nIn the code above, we have a process, which we call \"the client\" sending a request to an agent, \"the server\". The request contains an anonymous function, which must be executed by the server.\n\nIn a GenServer, the code above would be two separate functions, roughly like this:\n\n```elixir\ndef put(bucket, key, value) do\n  # Send the server a :put \"instruction\"\n  GenServer.call(bucket, {:put, key, value})\nend\n\n# Server callback\n\ndef handle_call({:put, key, value}, _from, state) do\n  {:reply, :ok, Map.put(state, key, value)}\nend\n```\n\nLet's go ahead and rewrite `KV.Bucket` at once. Open up `lib/kv/bucket.ex` and replace its contents with this new version:\n\n```elixir\ndefmodule KV.Bucket do\n  use GenServer\n\n  @doc \"\"\"\n  Starts a new bucket.\n  \"\"\"\n  def start_link(opts) do\n    GenServer.start_link(__MODULE__, %{}, opts)\n  end\n\n  @doc \"\"\"\n  Gets a value from the `bucket` by `key`.\n  \"\"\"\n  def get(bucket, key) do\n    GenServer.call(bucket, {:get, key})\n  end\n\n  @doc \"\"\"\n  Puts the `value` for the given `key` in the `bucket`.\n  \"\"\"\n  def put(bucket, key, value) do\n    GenServer.call(bucket, {:put, key, value})\n  end\n\n  @doc \"\"\"\n  Deletes `key` from `bucket`.\n\n  Returns the current value of `key`, if `key` exists.\n  \"\"\"\n  def delete(bucket, key) do\n    GenServer.call(bucket, {:delete, key})\n  end\n\n  ### Callbacks\n\n  @impl true\n  def init(bucket) do\n    state = %{\n      bucket: bucket\n    }\n\n    {:ok, state}\n  end\n\n  @impl true\n  def handle_call({:get, key}, _from, state) do\n    value = get_in(state.bucket[key])\n    {:reply, value, state}\n  end\n\n  def handle_call({:put, key, value}, _from, state) do\n    state = put_in(state.bucket[key], value)\n    {:reply, :ok, state}\n  end\n\n  def handle_call({:delete, key}, _from, state) do\n    {value, state} = pop_in(state.bucket[key])\n    {:reply, value, state}\n  end\nend\n```\n\nThe first function is `start_link/1`, which starts a new GenServer passing a list of options. `GenServer.start_link/3`, which takes three arguments:\n\n1. The module where the server callbacks are implemented, in this case `__MODULE__` (meaning the current module)\n\n2. The initialization arguments, in this case the empty bucket `%{}`\n\n3. A list of options which can be used to specify things like the name of the server. Once again, we forward the list of options that we receive on `start_link/1` to `GenServer.start_link/3`, as we did for agents\n\nOnce started, the GenServer will invoke the `init/1` callback, that receives the second argument given to `GenServer.start_link/3` and returns `{:ok, state}`, where state is a new map. We can already notice how the `GenServer` API makes the client/server segregation more apparent. `start_link/3` happens in the client, while `init/1` is the respective callback that runs on the server.\n\nThere are two types of requests you can send to a GenServer: calls and casts. Calls are synchronous and the server **must** send a response back to such requests. While the server computes the response, the client is **waiting**. Casts are asynchronous: the server won't send a response back and therefore the client won't wait for one. Both requests are messages sent to the server, and will be handled in sequence. So far we have only used `GenServer.call/2`, to keep the same semantics as the Agent, but we will give `cast` a try when implementing subscriptions. Given we kept the same behaviour, all tests will still pass.\n\nEach request must be implemented as a specific callback. For `call/2` requests, we implement a `handle_call/3` callback that receives the `request`, the process from which we received the request (`_from`), and the current server state (`state`). The `handle_call/3` callback returns a tuple in the format `{:reply, reply, updated_state}`. The first element of the tuple, `:reply`, indicates that the server should send a reply back to the client. The second element, `reply`, is what will be sent to the client while the third, `updated_state` is the new server state.\n\nAnother Elixir feature we used in the implementation above are the nested traversal functions: `get_in/1`, `put_in/2`, and `pop_in/1`. Instead of keeping the `bucket` as our GenServer state, we defined a state map with a `bucket` key inside. This will be important as we also need to track subscribers as part of the GenServer state. These new functions make it straight-forward to manipulate data structures nested in other data structures.\n\nWith our GenServer in place, let's work on subscription, starting with the tests.\n\n## Implementing subscriptions\n\nOur new test will subscribe to a bucket and then assert that, as operations are performed against the bucket, we receive messages of said events.\n\nOpen up `test/kv/bucket_test.exs` and key this in:\n\n```elixir\n  test \"subscribes to puts and deletes\" do\n    {:ok, bucket} = start_supervised(KV.Bucket)\n    KV.Bucket.subscribe(bucket)\n\n    KV.Bucket.put(bucket, \"milk\", 3)\n    assert_receive {:put, \"milk\", 3}\n\n    # Also check it works even from another process\n    spawn(fn -> KV.Bucket.delete(bucket, \"milk\") end)\n    assert_receive {:delete, \"milk\"}\n  end\n```\n\nIn order to make the test pass, we need to implement the `KV.Bucket.subscribe/1`. So let's add these three new functions to `KV.Bucket`:\n\n```elixir\n  @doc \"\"\"\n  Subscribes the current process to the bucket.\n  \"\"\"\n  def subscribe(bucket) do\n    GenServer.cast(bucket, {:subscribe, self()})\n  end\n\n  @impl true\n  def handle_cast({:subscribe, pid}, state) do\n    Process.monitor(pid)\n    state = update_in(state.subscribers, &MapSet.put(&1, pid))\n    {:noreply, state}\n  end\n\n  @impl true\n  def handle_info({:DOWN, _ref, _type, pid, _reason}, state) do\n    state = update_in(state.subscribers, &MapSet.delete(&1, pid))\n    {:noreply, state}\n  end\n```\n\nOn subscription, we send a `cast/2` request with the current process identifier and implement its `handle_cast/2` callback that receives the `request` and the current server state. We then proceed to monitor the given `pid` and add it to the list of subscribers, which we are implementing using `MapSet`. The `handle_cast/2` callback returns a tuple in the format `{:noreply, updated_state}`. Note that in a real application we would have probably implemented it with a synchronous call, as it provides back pressure, instead of an asynchronous cast. We are doing it this way to illustrate how to implement a cast callback.\n\nThen, because we have monitored a process, once that process terminates, we will receive a \"DOWN message\". GenServers handle regular messages using the `handle_info/2` callback, which also typically return `{:noreply, updated_state}`. In this callback, we remove the PID that terminated from our list of subscribers.\n\nWe are almost there. We can see both `handle_cast/2` and `handle_info/2` callbacks assume there is a subscribers key in our state with a `MapSet`. So let's add it by updating the existing `init/1` to the following:\n\n```elixir\n  @impl true\n  def init(bucket) do\n    state = %{\n      bucket: bucket,\n      subscribers: MapSet.new()\n    }\n\n    {:ok, state}\n  end\n```\n\nAnd finally let's update the callbacks for `put/3` and `delete/2` to broadcast messages whenever they are invoked, like this:\n\n```elixir\n  def handle_call({:put, key, value}, _from, state) do\n    state = put_in(state.bucket[key], value)\n    broadcast(state, {:put, key, value})\n    {:reply, :ok, state}\n  end\n\n  def handle_call({:delete, key}, _from, state) do\n    {value, state} = pop_in(state.bucket[key])\n    broadcast(state, {:delete, key})\n    {:reply, value, state}\n  end\n\n  defp broadcast(state, message) do\n    for pid <- state.subscribers do\n      send(pid, message)\n    end\n  end\n```\n\nThere is no need to modify the callback for `get/2`. And that's it, run the tests again, and our new test should pass!\n\n## Wiring it all up\n\nNow that our bucket deals with subscriptions, we need to expose this new functionality in our server. Let's once again start with the test.\n\nOpen up `test/kv/server_test.exs` and add this new test:\n\n```elixir\n  test \"subscribes to buckets\", %{socket: socket, name: name} do\n    assert send_and_recv(socket, \"CREATE #{name}\\r\\n\") == \"OK\\r\\n\"\n    :gen_tcp.send(socket, \"SUBSCRIBE #{name}\\r\\n\")\n\n    {:ok, other} = :gen_tcp.connect(~c\"localhost\", 4040, @socket_options)\n\n    assert send_and_recv(other, \"PUT #{name} milk 3\\r\\n\") == \"OK\\r\\n\"\n    assert :gen_tcp.recv(socket, 0, 1000) == {:ok, \"milk SET TO 3\\r\\n\"}\n\n    assert send_and_recv(other, \"DELETE #{name} milk\\r\\n\") == \"OK\\r\\n\"\n    assert :gen_tcp.recv(socket, 0, 1000) == {:ok, \"milk DELETED\\r\\n\"}\n  end\n```\n\nThe test creates a bucket and subscribes to it. Then it opens up another TCP connection to send commands. For each command sent, we expect the subscribed socket to receive a message.\n\nTo make the test pass, we need to change `KV.Command` to parse the new `SUBSCRIBE` command and then run it. Open up `lib/kv/commands.ex` and then first change the `parse/1` definition to the following:\n\n```elixir\n  def parse(line) do\n    case String.split(line) do\n      [\"SUBSCRIBE\", bucket] -> {:ok, {:subscribe, bucket}}\n      [\"CREATE\", bucket] -> {:ok, {:create, bucket}}\n      [\"GET\", bucket, key] -> {:ok, {:get, bucket, key}}\n      [\"PUT\", bucket, key, value] -> {:ok, {:put, bucket, key, value}}\n      [\"DELETE\", bucket, key] -> {:ok, {:delete, bucket, key}}\n      _ -> {:error, :unknown_command}\n    end\n  end\n```\n\nWe added a new clause that converts \"SUBSCRIBE\" into a tuple. Now we need to match on this tuple within `run/1`. We can do so by adding a new clause at the bottom of `run/1`, with the following code:\n\n```elixir\n  def run({:subscribe, bucket}, socket) do\n    lookup(bucket, fn pid ->\n      KV.Bucket.subscribe(pid)\n      :inet.setopts(socket, active: true)\n      receive_messages(socket)\n    end)\n  end\n\n  defp receive_messages(socket) do\n    receive do\n      {:put, key, value} ->\n        :gen_tcp.send(socket, \"#{key} SET TO #{value}\\r\\n\")\n        receive_messages(socket)\n\n      {:delete, key} ->\n        :gen_tcp.send(socket, \"#{key} DELETED\\r\\n\")\n        receive_messages(socket)\n\n      {:tcp_closed, ^socket} ->\n        {:error, :closed}\n\n      # If we receive any message, including socket writes, we discard them\n      _ ->\n        receive_messages(socket)\n    end\n  end\n```\n\nLet's go over it by parts. We use the existing `lookup/2` private function to lookup for a bucket. If one is found, we subscribe the current process to the bucket. Then we call `:inet.setopts(socket, active: true)` (which we will explain soon) and `receive_messages/1`.\n\n`receive_messages/1` awaits for messages from the bucket and then calls itself again, becoming a loop. We match on `{:put, key, value}` and `{:delete, key}` and write to those events to the socket. We also match on `{:tcp_closed, ^socket}`, which is a message that will be delivered if the TCP socket closes, and use it to abort the loop. We discard any other message.\n\nAt this point you may be wondering: where does `{:tcp_closed, ^socket}` come from?\n\nSo far, when receiving messages from the socket, we used `:gen_tcp.recv/3` to perform calls that will block the current process until content is available. This is known as \"passive mode\". However, we can also ask `:gen_tcp` to stream messages to the current process inbox as they arrive, which is known as \"active mode\", which is exactly what we configured when we called `:inet.setopts(socket, active: true)`. Those messages have the shape `{:tcp, socket, data}`. When the socket is in active mode and it is closed, it delivers a `{:tcp_closed, socket}` message. Once we receive this message, we exit the loop, which will exit the connection process. Since the bucket is monitoring the process, it will automatically remove the subscription too. You could verify this in practice by adding a `COUNT SUBSCRIPTIONS` command that returns the number of subscribers for a given bucket.\n\nIn practice, many systems would prefer to call `:inet.setopts(socket, active: :once)` to specify only a single TCP message should be delivered to avoid overflowing message queues. Once the message is received, they call `:inet.setopts/2` again. In our case, we are simply discarding anything that arrives over the socket, so setting `active: true` is equally fine. In all scenarios, the benefit of using active mode is that the process can receive TCP messages as well as messages from other processes at the same time, instead of blocking on `:gen_tcp.recv/3`.\n\nTo wrap it all up, you should give our new feature a try in a distributed setting too. Start two `NODES=... PORT=... iex --sname ... -S mix` instances. In one of them, create a bucket. In the other, subscribe to the same bucket. Once you go back to the first shell, you will see that, even as you send commands to the bucket in one machine, the messages will be streamed to the other one. In other words, our subscription system is also distributed, and all we had to do is to send messages!\n\n## `call`, `cast` or `info`?\n\nSo far we have used three callbacks: `handle_call/3`, `handle_cast/2` and `handle_info/2`. Here is what we should consider when deciding when to use each:\n\n1. `handle_call/3` must be used for synchronous requests. This should be the default choice as waiting for the server reply is a useful back-pressure mechanism.\n\n2. `handle_cast/2` must be used for asynchronous requests, when you don't care about a reply. A cast does not guarantee the server has received the message and, for this reason, should be used sparingly. For example, the `subscribe/1` function we have defined in this chapter should have used `call/2`. We have used `cast/2` for educational purposes.\n\n3. `handle_info/2` must be used for all other messages a server may receive that are not sent via `GenServer.call/2` or `GenServer.cast/2`, including regular messages sent with `send/2`. The monitoring `:DOWN` messages are an example of this.\n\nTo help developers remember the differences between call, cast and info, the supported return values and more, we have a tiny [GenServer cheat sheet](https://elixir-lang.org/downloads/cheatsheets/gen-server.pdf).\n\n## Agents or GenServers?\n\nBefore moving forward to the last chapter, you may be wondering: in the future, should you use an `Agent` or a `GenServer`?\n\nAs we saw throughout this guide, agents are straight-forward to get started but they are limited in what they can do. Agents are effectively a subset of GenServers. In fact, agents are implemented on top of GenServers. As well as supervisors, the `Registry` module, and many other features you will find in both Erlang and Elixir.\n\nIn other words, GenServers are the most essential component for building concurrent and fault-tolerant systems in Elixir. They provide a robust and flexible framework for managing state and coordinating interactions between processes.\n\nFor those reasons, many adopt a rule of thumb to never use Agents and jump straight into GenServers instead. On the other hand, others are more than fine with using agents to store a bit of state here and there. Either way, you will be fine!\n\nThis is the last feature we have implemented for our distributed key-value store. In the next chapter, we will learn how to package our application before shipping it to production.\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/introduction-to-mix.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Introduction to Mix\n\nIn this guide, we will build a complete Elixir application, with its own supervision tree, configuration, tests, and more.\n\nThe requirements for this guide are (see `elixir -v`):\n\n  * Elixir 1.18.0 onwards\n  * Erlang/OTP 27 onwards\n\nThe application works as a distributed key-value store. We are going to organize key-value pairs into buckets and distribute those buckets across multiple nodes. We will also build a simple client that allows us to connect to any of those nodes and send requests such as:\n\n```text\nCREATE shopping\nOK\n\nPUT shopping milk 1\nOK\n\nPUT shopping eggs 3\nOK\n\nGET shopping milk\n1\nOK\n\nDELETE shopping eggs\nOK\n```\n\nIn order to build our key-value application, we are going to use three main tools:\n\n  * ***OTP*** *(Open Telecom Platform)* is a set of libraries that ships with Erlang. Erlang developers use OTP to build robust, fault-tolerant applications. In this chapter we will explore how many aspects from OTP integrate with Elixir, including supervision trees, event managers and more;\n\n  * ***[Mix](`Mix`)*** is a build tool that ships with Elixir that provides tasks for creating, compiling, testing your application, managing its dependencies and much more;\n\n  * ***[ExUnit](`ExUnit`)*** is a unit-test based framework that ships with Elixir.\n\nIn this chapter, we will create our first project using Mix and explore different features in OTP, Mix, and ExUnit as we go.\n\n> #### Source code {: .info}\n>\n> The final code for the application built in this guide is in [this repository](https://github.com/josevalim/kv) and can be used as a reference.\n\n> #### Is this guide required reading? {: .info}\n>\n> This guide is not required reading in your Elixir journey. We'll explain.\n>\n> As an Elixir developer, you will most likely use one of the many existing frameworks when writing your Elixir code. [Phoenix](https://phoenixframework.org) covers web applications, [Ecto](https://github.com/elixir-ecto/ecto) communicates with databases, you can craft embedded software with [Nerves](https://nerves-project.org/), [Nx](https://github.com/elixir-nx) powers machine learning and AI projects, [Membrane](https://membrane.stream/) assembles audio/video processing pipelines, [Broadway](https://elixir-broadway.org/) handles data ingestion and processing, and many more. These frameworks handle the lower level details of concurrency, distribution, and fault-tolerance, so you, as a user, can focus on your own needs and demands.\n>\n> On the other hand, if you want to learn the foundations these frameworks are built upon, and the abstractions that power the Elixir ecosystem, this guide will give you a tour through several important concepts.\n\n## Our first project\n\nWhen you install Elixir, besides getting the `elixir`, `elixirc`, and `iex` executables, you also get an executable Elixir script named `mix`.\n\nLet's create our first project by invoking `mix new` from the command line. We'll pass the project path as the argument (`kv`, in this case). By default, the application name and module name will be retrieved from the path. So we tell Mix that our main module should be the all-uppercase `KV`, instead of the default, which would have been `Kv`:\n\n```console\n$ mix new kv --module KV\n```\n\nMix will create a directory named `kv` with a few files in it:\n\n```text\n* creating README.md\n* creating .formatter.exs\n* creating .gitignore\n* creating mix.exs\n* creating lib\n* creating lib/kv.ex\n* creating test\n* creating test/test_helper.exs\n* creating test/kv_test.exs\n```\n\nLet's take a brief look at those generated files.\n\n> #### Executables in the `PATH` {: .info}\n>\n> Mix is an Elixir executable. This means that in order to run `mix`, you need to have both `mix` and `elixir` executables in your [`PATH`](https://en.wikipedia.org/wiki/PATH_(variable)). That's what happens when you install Elixir.\n\n## Project compilation\n\nA file named `mix.exs` was generated inside our new project folder (`kv`) and its main responsibility is to configure our project. Let's take a look at it:\n\n```elixir\ndefmodule KV.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :kv,\n      version: \"0.1.0\",\n      elixir: \"~> 1.11\",\n      start_permanent: Mix.env() == :prod,\n      deps: deps()\n    ]\n  end\n\n  # Run \"mix help compile.app\" to learn about applications\n  def application do\n    [\n      extra_applications: [:logger]\n    ]\n  end\n\n  # Run \"mix help deps\" to learn about dependencies\n  defp deps do\n    [\n      # {:dep_from_hexpm, \"~> 0.3.0\"},\n      # {:dep_from_git, git: \"https://github.com/elixir-lang/my_dep.git\", tag: \"0.1.0\"},\n    ]\n  end\nend\n```\n\nOur `mix.exs` defines two public functions: `project`, which returns project configuration like the project name and version, and `application`, which is used to generate an application file.\n\nThere is also a private function named `deps`, which is invoked from the `project` function, that defines our project dependencies. Defining `deps` as a separate function is not required, but it helps keep the project configuration tidy.\n\nMix also generates a file at `lib/kv.ex` with a module containing exactly one function, called `hello`:\n\n```elixir\ndefmodule KV do\n  @moduledoc \"\"\"\n  Documentation for KV.\n  \"\"\"\n\n  @doc \"\"\"\n  Hello world.\n\n  ## Examples\n\n      iex> KV.hello()\n      :world\n\n  \"\"\"\n  def hello do\n    :world\n  end\nend\n\n```\n\nThis structure is enough to compile our project:\n\n```console\n$ cd kv\n$ mix compile\n```\n\nWill output:\n\n```text\nCompiling 1 file (.ex)\nGenerated kv app\n```\n\nThe `lib/kv.ex` file was compiled and an application manifest named `kv.app` was generated. All compilation artifacts are placed inside the `_build` directory using the options defined in the `mix.exs` file.\n\nOnce the project is compiled, you can start a `iex` session inside the project by running the command below. The `-S mix` is necessary to load the project in the interactive shell:\n\n```console\n$ iex -S mix\n```\n\nWe are going to work on this `kv` project, making modifications and trying out the latest changes from a `iex` session. While you may start a new session whenever there are changes to the project source code, you can also recompile the project from within `iex` with the `recompile` helper, like this:\n\n```elixir\niex> recompile()\nCompiling 1 file (.ex)\n:ok\niex> recompile()\n:noop\n```\n\nIf anything had to be compiled, you see some informative text, and get the `:ok` atom back, otherwise the function is silent, and returns `:noop`.\n\n## Running tests\n\nMix also generated the appropriate structure for running our project tests. Mix projects usually follow the convention of having a `<filename>_test.exs` file in the `test` directory for each file in the `lib` directory. For this reason, we can already find a `test/kv_test.exs` corresponding to our `lib/kv.ex` file. It doesn't do much at this point:\n\n```elixir\ndefmodule KVTest do\n  use ExUnit.Case\n  doctest KV\n\n  test \"greets the world\" do\n    assert KV.hello() == :world\n  end\nend\n```\n\nIt is important to note a couple of things:\n\n1. the test file is an Elixir script file (`.exs`). This is convenient because we don't need to compile test files before running them;\n\n2. we define a test module named `KVTest`, in which we [`use ExUnit.Case`](`ExUnit.Case`) to inject the testing API;\n\n3. we use one of the imported macros, `ExUnit.DocTest.doctest/1`, to indicate that the `KV` module contains doctests (we will discuss those in a later chapter);\n\n4. we use the `ExUnit.Case.test/2` macro to define a simple test;\n\nMix also generated a file named `test/test_helper.exs` which is responsible for setting up the test framework:\n\n```elixir\nExUnit.start()\n```\n\nThis file will be required by Mix every time before we run our tests. We can run tests with:\n\n```console\n$ mix test\nCompiled lib/kv.ex\nGenerated kv app\nRunning ExUnit with seed: 540224, max_cases: 16\n..\n\nFinished in 0.04 seconds\n1 doctest, 1 test, 0 failures\n```\n\nNotice that by running `mix test`, Mix has compiled the source files and generated the application manifest once again. This happens because Mix supports multiple environments, which we will discuss later in this chapter.\n\nFurthermore, you can see that ExUnit prints a dot for each successful test and automatically randomizes tests too. Let's make the test fail on purpose and see what happens.\n\nChange the assertion in `test/kv_test.exs` to the following:\n\n```elixir\nassert KV.hello() == :oops\n```\n\nNow run `mix test` again (notice this time there will be no compilation):\n\n```text\n  1) test greets the world (KVTest)\n     test/kv_test.exs:5\n     Assertion with == failed\n     code:  assert KV.hello() == :oops\n     left:  :world\n     right: :oops\n     stacktrace:\n       test/kv_test.exs:6: (test)\n\n.\n\nFinished in 0.05 seconds\n1 doctest, 1 test, 1 failure\n```\n\nFor each failure, ExUnit prints a detailed report, containing the test name with the test case, the code that failed and the values for the left side and right side (RHS) of the `==` operator.\n\nIn the second line of the failure, right below the test name, there is the location where the test was defined. If you copy the test location in full, including the file and line number, and append it to `mix test`, Mix will load and run just that particular test:\n\n```console\n$ mix test test/kv_test.exs:5\n```\n\nThis shortcut will be extremely useful as we build our project, allowing us to quickly iterate by running a single test.\n\nFinally, the stacktrace relates to the failure itself, giving information about the test and often the place the failure was generated from within the source files.\n\n## Automatic code formatting\n\nOne of the files generated by `mix new` is the `.formatter.exs`. Elixir ships with a code formatter that is capable of automatically formatting our codebase according to a consistent style. The formatter is triggered with the `mix format` task. The generated `.formatter.exs` file configures which files should be formatted when `mix format` runs.\n\nTo give the formatter a try, change a file in the `lib` or `test` directories to include extra spaces or extra newlines, such as `def  hello  do`, and then run `mix format`.\n\nMost editors provide built-in integration with the formatter, allowing a file to be formatted on save or via a chosen keybinding. If you are learning Elixir, editor integration gives you useful and quick feedback when learning the Elixir syntax.\n\nFor companies and teams, we recommend developers to run `mix format --check-formatted` on their continuous integration servers, ensuring all current and future code follows the standard.\n\nYou can learn more about the code formatter by checking [the format task documentation](`mix format`) or by reading [the release announcement for Elixir v1.6](https://elixir-lang.org/blog/2018/01/17/elixir-v1-6-0-released/), the first version to include the formatter.\n\n## Environments\n\nMix provides the concept of \"environments\". They allow a developer to customize compilation and other options for specific scenarios. By default, Mix understands three environments:\n\n  * `:dev` — the one in which Mix tasks (like `compile`) run by default\n  * `:test` — used by `mix test`\n  * `:prod` — the one you will use to run your project in production\n\nThe environment applies only to the current project. As we will see in future chapters, any dependency you add to your project will by default run in the `:prod` environment.\n\nCustomization per environment can be done by accessing the `Mix.env/0` in your `mix.exs` file, which returns the current environment as an atom. That's what we have used in the `:start_permanent` options:\n\n```elixir\ndef project do\n  [\n    ...,\n    start_permanent: Mix.env() == :prod,\n    ...\n  ]\nend\n```\n\nWhen true, the `:start_permanent` option starts your application in permanent mode, which means the Erlang VM will crash if your application's supervision tree shuts down. Notice we don't want this behavior in dev and test because it is useful to keep the VM instance running in those environments for troubleshooting purposes.\n\nMix will default to the `:dev` environment, except for the `test` task that will default to the `:test` environment. The environment can be changed via the `MIX_ENV` environment variable:\n\n```console\n$ MIX_ENV=prod mix compile\n```\n\nOr on Windows:\n\n```batch\n> set \"MIX_ENV=prod\" && mix compile\n```\n\n> #### Mix in production {: .warning}\n>\n> Mix is a **build tool** and, as such, it is not expected to be available in production. Therefore, it is recommended to access `Mix.env/0` only in configuration files and inside `mix.exs`, never in your application code (`lib`).\n\n## Exploring\n\nThere is much more to Mix, and we will continue to explore it as we build our project. A general overview is available on the [Mix documentation](`Mix`) and you can always invoke the help task to list all available tasks:\n\n```console\n$ mix help\n$ mix help compile\n```\n\nNow let's move forward and add the first modules and functions to our application.\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/releases.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Releases\n\nNow that our application is ready, you may be wondering how we can package our application to run in production. After all, all of our code so far depends on Erlang and Elixir versions that are installed in your current system. To achieve this goal, Elixir provides releases.\n\nA release is a self-contained directory that consists of your application code, all of its dependencies, plus the whole Erlang Virtual Machine (VM) and runtime. Once a release is assembled, it can be packaged and deployed to a target as long as the target runs on the same operating system (OS) distribution and version as the machine that assembled the release.\n\nTo get started, simply run `mix release` while setting `MIX_ENV=prod`:\n\n```console\n$ MIX_ENV=prod mix release\nCompiling 4 files (.ex)\nGenerated kv app\n* assembling kv-0.1.0 on MIX_ENV=prod\n* using config/runtime.exs to configure the release at runtime\n\nRelease created at _build/prod/rel/kv\n\n    # To start your system\n    _build/prod/rel/kv/bin/kv start\n\nOnce the release is running:\n\n    # To connect to it remotely\n    _build/prod/rel/kv/bin/kv remote\n\n    # To stop it gracefully (you may also send SIGINT/SIGTERM)\n    _build/prod/rel/kv/bin/kv stop\n\nTo list all commands:\n\n    _build/prod/rel/kv/bin/kv\n```\n\nExcellent! A release was assembled in `_build/prod/rel/kv`. Everything you need to run your application is inside that directory. In particular, there is a `bin/kv` file which is the entry point to your system. It supports multiple commands, such as:\n\n  * `bin/kv start`, `bin/kv start_iex`, `bin/kv restart`, and `bin/kv stop` — for general management of the release\n\n  * `bin/kv rpc COMMAND` and `bin/kv remote` — for running commands on the running system or to connect to the running system\n\n  * `bin/kv eval COMMAND` — to start a fresh system that runs a single command and then shuts down\n\n  * `bin/kv daemon` and `bin/kv daemon_iex` — to start the system as a daemon on Unix-like systems\n\n  * `bin/kv install` — to install the system as a service on Windows machines\n\nIf you run `bin/kv start_iex` inside the release directory, it will start the system using a short name (`--sname`) equal to the release name, which in this case is `kv`. The next step is to start two instances, on different ports and different names, as we did earlier on. But before we do this, let's talk a bit about the benefits of releases.\n\n## Why releases?\n\nReleases allow developers to precompile and package all of their code and the runtime into a single unit. The benefits of releases are:\n\n  * Code preloading. The VM has two mechanisms for loading code: interactive and embedded. By default, it runs in the interactive mode which dynamically loads modules when they are used for the first time. The first time your application calls `Enum.map/2`, the VM will find the `Enum` module and load it. There's a downside. When you start a new server in production, it may need to load many other modules, causing the first requests to have an unusual spike in response time. Releases run in embedded mode, which loads all available modules upfront, guaranteeing your system is ready to handle requests after booting.\n\n  * Configuration and customization. Releases give developers fine grained control over system configuration and the VM flags used to start the system.\n\n  * Self-contained. A release does not require the source code to be included in your production artifacts. All of the code is precompiled and packaged. Releases do not even require Erlang or Elixir on your servers, as they include the Erlang VM and its runtime by default. Furthermore, both Erlang and Elixir standard libraries are stripped to bring only the parts you are actually using.\n\n  * Multiple releases. You can assemble different releases with different configuration per application or even with different applications altogether.\n\nWe have written extensive documentation on releases, so [please check the official documentation for more information](`mix release`). For now, we will continue exploring some of the features outlined above.\n\n## Configuring releases\n\nReleases also provide built-in hooks for configuring almost every need of the production system:\n\n  * `config/config.exs` — provides build-time application configuration, which is executed before our application compiles. This file often imports configuration files based on the environment, such as `config/dev.exs` and `config/prod.exs`.\n\n  * `config/runtime.exs` — provides runtime application configuration. It is executed every time the release boots and is further extensible via config providers.\n\n  * `rel/env.sh.eex` and `rel/env.bat.eex` — template files that are copied into every release and executed on every command to set up environment variables, including ones specific to the VM, and the general environment.\n\n  * `rel/vm.args.eex` — a template file that is copied into every release and provides static configuration of the Erlang Virtual Machine and other runtime flags.\n\nIn this case, we already have specified a `config/runtime.exs` that deals with both `PORT` and `NODES` environment variables. Furthermore, while releases don't accept a `--sname` parameter, they do allow us to set the name via the `RELEASE_NODE` env var. Therefore, we can start two copies of the system by jumping into `_build/prod/rel/kv` and typing this (remember to adjust `@computer-name` to your actual computer name):\n\n```console\n$ NODES=\"foo@computer-name,bar@computer-name\" PORT=4040 RELEASE_NODE=\"foo\" bin/kv start_iex\n```\n\n```console\n$ NODES=\"foo@computer-name,bar@computer-name\" PORT=4041 RELEASE_NODE=\"bar\" bin/kv start_iex\n```\n\nTo verify it all worked out, you can type `Node.list` in the IEx section and see if it returns the other node. If it doesn't, you can start diagnosing, first by comparing the node names within each `iex>` prompt and calling `Node.connect/1` directly. With applications running, you can `telnet` into them as usual too.\n\nWhile the above is enough to get started, you may want to perform advanced configuration based on the environment you are replying to. Releases provide scripts for that, which are great to automate based on host, network, or cloud settings.\n\n## Operating System scripts\n\nEvery release contains an environment file, named `env.sh` on Unix-like systems and `env.bat` on Windows machines, that executes before the Elixir system starts. In this file, you can execute any OS-level code, such as invoke other applications, set environment variables and so on. Some of those environment variables can even configure how the release itself runs.\n\nFor instance, releases run using short-names (`--sname`). However, if you want to actually run a distributed key-value store in production, you will need multiple nodes and start the release with the `--name` option. We can achieve this by setting the `RELEASE_DISTRIBUTION` environment variable inside the `env.sh` and `env.bat` files. Mix already has a template for said files which we can customize, so let's ask Mix to copy them to our application:\n\n    $ mix release.init\n    * creating rel/vm.args.eex\n    * creating rel/remote.vm.args.eex\n    * creating rel/env.sh.eex\n    * creating rel/env.bat.eex\n\nIf you open up `rel/env.sh.eex`, you will see:\n\n```shell\n#!/bin/sh\n\n# # Sets and enables heart (recommended only in daemon mode)\n# case $RELEASE_COMMAND in\n#   daemon*)\n#     HEART_COMMAND=\"$RELEASE_ROOT/bin/$RELEASE_NAME $RELEASE_COMMAND\"\n#     export HEART_COMMAND\n#     export ELIXIR_ERL_OPTIONS=\"-heart\"\n#     ;;\n#   *)\n#     ;;\n# esac\n\n# # Set the release to load code on demand (interactive) instead of preloading (embedded).\n# export RELEASE_MODE=interactive\n\n# # Set the release to work across nodes.\n# # RELEASE_DISTRIBUTION must be \"sname\" (local), \"name\" (distributed) or \"none\".\n# export RELEASE_DISTRIBUTION=name\n# export RELEASE_NODE=<%= @release.name %>\n```\n\nThe steps necessary to work across nodes is already commented out as an example. You can enable full distribution by setting the `RELEASE_DISTRIBUTION` variable to `name`.\n\nIf you are on Windows, you will have to open up `rel/env.bat.eex`, where you will find this:\n\n```bat\n@echo off\nrem Set the release to load code on demand (interactive) instead of preloading (embedded).\nrem set RELEASE_MODE=interactive\n\nrem Set the release to work across nodes.\nrem RELEASE_DISTRIBUTION must be \"sname\" (local), \"name\" (distributed) or \"none\".\nrem set RELEASE_DISTRIBUTION=name\nrem set RELEASE_NODE=<%= @release.name %>\n```\n\nOnce again, set the `RELEASE_DISTRIBUTION` variable to `name` and you are good to go!\n\n## VM arguments\n\nThe `rel/vm.args.eex` allows you to specify low-level flags that control how the Erlang VM and its runtime operate. You specify entries as if you were specifying arguments in the command line with code comments also supported. Here is the default generated file:\n\n    ## Customize flags given to the VM: https://www.erlang.org/doc/man/erl.html\n    ## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here\n\n    ## Increase number of concurrent ports/sockets\n    ##+Q 65536\n\n    ## Tweak GC to run more often\n    ##-env ERL_FULLSWEEP_AFTER 10\n\nYou can see [a complete list of VM arguments and flags in the Erlang documentation](https://www.erlang.org/doc/man/erl.html).\n\n## Summing up\n\nThroughout the guide, we have built a very simple distributed key-value store as an opportunity to explore many constructs like generic servers, supervisors, tasks, agents, applications and more. Not only that, we have written tests for the whole application, got familiar with ExUnit, and learned how to use the Mix build tool to accomplish a wide range of tasks.\n\nIf you are looking for a distributed key-value store to use in production, you should definitely look into [Riak](https://riak.com/products/riak-kv/), which also runs in the Erlang VM. In Riak, the buckets are replicated and stored across several nodes to avoid data loss.\n\nOf course, Elixir can be used for much more than distributed key-value stores. Embedded systems, data-processing and data-ingestion, web applications, audio/video streaming systems, machine learning, and others are many of the different domains Elixir excels at. We hope this guide has prepared you to explore any of those domains or any future domain you may desire to bring Elixir into.\n\nHappy coding!\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/supervisor-and-application.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Registries and supervision trees\n\nIn the [previous chapter](agents.md), we used agents to represent our buckets. In the [introduction to mix](introduction-to-mix.md), we specified we would like to name each bucket so we can do the following:\n\n```text\nCREATE shopping\nOK\n\nPUT shopping milk 1\nOK\n\nGET shopping milk\n1\nOK\n```\n\nIn the example session above we interacted with the \"shopping\" bucket by referencing its name. Therefore, an important feature in our key-value store is to give names to processes.\n\nWe have also learned in the previous chapter we can already name our buckets. For example:\n\n```elixir\niex> KV.Bucket.start_link(name: :shopping)\n{:ok, #PID<0.43.0>}\niex> KV.Bucket.put(:shopping, \"milk\", 1)\n:ok\niex> KV.Bucket.get(:shopping, \"milk\")\n1\n```\n\nHowever, naming dynamic processes with atoms is a terrible idea! If we use atoms, we would need to convert the bucket name (often received from an external client) to atoms, and **we should never convert user input to atoms**. This is because atoms are not garbage collected. Once an atom is created, it is never reclaimed. Generating atoms from user input would mean the user can inject enough different names to exhaust our system memory!\n\nIn practice, it is more likely you will reach the Erlang VM limit for the maximum number of atoms before you run out of memory, which will bring your system down regardless.\n\nLuckily, Elixir (and Erlang) comes with built-in abstractions for naming processes, called name registries, each with different trade-offs which we will explore throughout these guides.\n\n## Local, decentralized, and scalable registry\n\nElixir ships with a single-node process registry module aptly called `Registry`. Its main feature is that you can use any Elixir value to name a process, not only atoms. Let's take it for a spin in `iex`:\n\n```elixir\niex> Registry.start_link(name: KV, keys: :unique)\niex> name = {:via, Registry, {KV, \"shopping\"}}\niex> KV.Bucket.start_link(name: name)\n{:ok, #PID<0.43.0>}\niex> KV.Bucket.put(name, \"milk\", 1)\n:ok\niex> KV.Bucket.get(name, \"milk\")\n1\n```\n\nAs you can see, instead of passing an atom to the `:name` option, we pass a tuple of shape `{:via, registry_module, {registry_name, process_name}}`, and everything just worked. You could have used anything as the `process_name`, even an integer or a map! That's because all of Elixir built-in behaviours, agents, supervisors, tasks, etc, are compatible with naming registries, as long as you pass them using the \"via\" tuple format.\n\nTherefore, all we need to do to name our buckets is to start a `Registry`, using `Registry.start_link/1`. But you may be wondering, where exactly should we place that?\n\n## Understanding applications\n\nEvery Elixir project is an application. Elixir itself is defined in an application named `:elixir`. The `ExUnit.Case` module is part of the `:ex_unit` application. And so forth.\n\nIn fact, we have been working inside an application this entire time. Every time we changed a file and ran `mix compile`, we could see a `Generated kv app` message in the compilation output.\n\nWe can find the generated `.app` file at `_build/dev/lib/kv/ebin/kv.app`. Let's have a look at its contents:\n\n```erlang\n{application,kv,\n             [{applications,[kernel,stdlib,elixir,logger]},\n              {description,\"kv\"},\n              {modules,['Elixir.KV','Elixir.KV.Bucket']},\n              {registered,[]},\n              {vsn,\"0.1.0\"}]}.\n```\n\nThis file contains Erlang terms (written using Erlang syntax). Even though we are not familiar with Erlang, it is easy to guess this file holds our application definition. It contains our application `version`, all the modules defined by it, as well as a list of applications we depend on, like Erlang's `kernel`, `elixir` itself, and `logger`.\n\n> The `logger` application ships as part of Elixir. We stated that our application needs it by specifying it in the `:extra_applications` list in `mix.exs`. See the [official documentation](`Logger`) for more information.\n\nIn a nutshell, an application consists of all the modules defined in the `.app` file, including the `.app` file itself. The application itself is located at the `_build/dev/lib/kv` folder and typically has only two directories: `ebin`, for Elixir artifacts, such as `.beam` and `.app` files, and `priv`, with any other artifact or asset you may need in your application.\n\nAlthough Mix generates and maintains the `.app` file for us, we can customize its contents by adding new entries to the `application/0` function inside the `mix.exs` project file. We are going to do our first customization soon.\n\n### Starting applications\n\nEach application in our system can be started and stopped. The rules for starting and stopping an application are also defined in the `.app` file. When we invoke `iex -S mix`, Mix compiles our application and then starts it.\n\nLet's see this in practice. Start a console with `iex -S mix` and try:\n\n```elixir\niex> Application.start(:kv)\n{:error, {:already_started, :kv}}\n```\n\nOops, it's already started. Mix starts the current application and all of its dependencies automatically. This is also true for `mix test` and many other Mix commands.\n\nWe can, however, stop our `:kv` application, as well as the `:logger` application:\n\n```elixir\niex> Application.stop(:kv)\n:ok\niex> Application.stop(:logger)\n:ok\n```\n\nAnd let's try to start our application again:\n\n```elixir\niex> Application.start(:kv)\n{:error, {:not_started, :logger}}\n```\n\nNow we get an error because an application that `:kv` depends on (`:logger` in this case) isn't started. We need to either start each application manually in the correct order or call `Application.ensure_all_started/1` as follows:\n\n```elixir\niex> Application.ensure_all_started(:kv)\n{:ok, [:logger, :kv]}\n```\n\nIn practice, our tools always start our applications for us, and you don't have to worry about the above, but it is good to know how it all works behind the scenes.\n\n### The application callback\n\nWhenever we invoke `iex -S mix`, Mix automatically starts our application by calling `Application.start(:kv)`. But can we customize what happens when our application starts? As a matter of fact, we can! To do so, we define an application callback.\n\nThe first step is to tell our application definition (for example, our `.app` file) which module is going to implement the application callback. Let's do so by opening `mix.exs` and changing `def application` to the following:\n\n```elixir\n  def application do\n    [\n      extra_applications: [:logger],\n      mod: {KV, []}\n    ]\n  end\n```\n\nThe `:mod` option specifies the \"application callback module\", followed by the arguments to be passed on application start. The application callback module can be any module that invokes `use Application`. Since we have specified `KV` as the module callback, let's change the `KV` module defined in `lib/kv.ex` to the following:\n\n```elixir\ndefmodule KV do\n  use Application\nend\n```\n\nNow run `mix test` and you will see a couple things happening. First of all, you will get a compilation warning:\n\n```text\nCompiling 1 file (.ex)\n    warning: function start/2 required by behaviour Application is not implemented (in module KV)\n    │\n  1 │ defmodule KV do\n    │ ~~~~~~~~~~~~~~~\n    │\n    └─ lib/kv.ex:1: KV (module)\n```\n\nThis warning is telling us that `use Application` actually defines a behaviour, which expects us to implement to a `start/2` function in our `KV` module.\n\nThen our application does not even boot because the `start/2` function is not actually implemented:\n\n```text\n18:29:39.109 [notice] Application kv exited: exited in: KV.start(:normal, [])\n    ** (EXIT) an exception was raised:\n        ** (UndefinedFunctionError) function KV.start/2 is undefined or private\n```\n\nImplementing the `start/2` callback is relatively straight-forward, all we need to do is to start a supervision tree, and return `{:ok, root_supervisor_pid}`. The `Supervisor.start_link/2` function does precisely that, it only expects a list of children and the supervision strategy. Let's just pass an empty list of children for now:\n\n```elixir\ndefmodule KV do\n  use Application\n\n  # The @impl true annotation says we are implementing a callback\n  @impl true\n  def start(_type, _args) do\n    Supervisor.start_link([], strategy: :one_for_one)\n  end\nend\n```\n\nNow run `mix test` again and our app should boot but we should see one failure. When we changed the `KV` module, we broke the boilerplate test case which tested the `KV.hello/0` function. You can simply remove that test case and we are back to a green suite.\n\nWe wrote very little code but we did something incredibly powerful. We now have a function, `KV.start/2` that is invoked whenever your application starts. This gives us the perfect place to start our key-value registry. The `Application` module also allows us to define a `stop/1` callback and other functionality. You can check the `Application` and `Supervisor` modules for extensive documentation on their uses.\n\nLet's finally start our registry.\n\n## Supervision trees\n\nNow that we have the `start/2` callback, we can finally go ahead and start our registry. You may be tempted to do it like this:\n\n```elixir\n  def start(_type, _args) do\n    Registry.start_link(name: KV, keys: :unique)\n    Supervisor.start_link([], strategy: :one_for_one)\n  end\n```\n\nHowever, this would not be a good idea. In Elixir, we typically start processes inside supervision trees. In fact, we rarely use the `start_link` functions to start processes (except at the root of the supervision tree itself). Instead, do this:\n\n```elixir\n  def start(_type, _args) do\n    children = [\n      {Registry, name: KV, keys: :unique}\n    ]\n\n    Supervisor.start_link(children, strategy: :one_for_one)\n  end\n```\n\nA supervisor receives one or more child specifications that tell it exactly how to start each child. A child specification is typically represented by a `{module, options}` pair, as shown above, and often as simply the module name. Sometimes, these children are supervisors themselves, giving us supervision trees.\n\nLet's take it for a spin and see if we can indeed name our buckets using our new registry. Let's make sure to start a new `iex -S mix` (`recompile()` is not enough, as it does not reload your supervision tree) and then:\n\n```iex\niex> name = {:via, Registry, {KV, \"shopping\"}}\niex> KV.Bucket.start_link(name: name)\n{:ok, #PID<0.43.0>}\niex> KV.Bucket.put(name, \"milk\", 1)\n:ok\niex> KV.Bucket.get(name, \"milk\")\n1\n```\n\nPerfect, this time we didn't need to start the registry inside `iex`, as it was started as part of the application itself.\n\nBy starting processes inside supervisors, we gain important properties such as:\n\n  * **Introspection**: for each application, you can fully introspect and visualize each process in its supervision tree, its memory usage, message queue, etc\n\n  * **Resilience**: when a process fails for an unexpected reason, its supervisor controls if and how those processes should be restarted, leading to self-healing systems\n\n  * **Graceful shutdown**: when your application is shutting down, the children of a supervision tree are terminated in the opposite order they were started, leading to graceful shutdowns\n\n## Projects or applications?\n\nMix makes a distinction between projects and applications. Based on the contents of our `mix.exs` file, we would say we have a Mix project that defines the `:kv` application.\n\nWhen we say \"project\" you should think about Mix. Mix is the tool that manages your project. It knows how to compile your project, test your project and more. It also knows how to compile and start the application relevant to your project.\n\nWhen we talk about applications, we talk about OTP. Applications are the entities that are started and stopped as a whole by the runtime. You can learn more about applications and how they relate to booting and shutting down of your system as a whole in the documentation for the `Application` module.\n\n## Summing up\n\nWe learned important concepts in this chapter:\n\n  * Naming registries allow us to find processes in a given machine (or, as we will see in the future, even in a cluster)\n\n  * Applications bundle our modules, its dependencies, and how code starts and stops\n\n  * Processes are started as part of supervisors for introspection and fault-tolerance\n\nIn the next chapter, we will tie it all up by making sure all our buckets are named and supervised. To do so, we will learn a new tool called dynamic supervisors.\n"
  },
  {
    "path": "lib/elixir/pages/mix-and-otp/task-and-gen-tcp.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Task and gen_tcp\n\nIn this chapter, we are going to learn how to use Erlang's [`:gen_tcp` module](`:gen_tcp`) to serve requests. This provides a great opportunity to explore Elixir's `Task` module. In future chapters, we will expand our server so that it can actually interact with buckets.\n\n## Echo server\n\nWe will start our TCP server by first implementing an echo server. It will send a response with the text it received in the request. We will slowly improve our server until it is supervised and ready to handle multiple connections.\n\nA TCP server, in broad strokes, performs the following steps:\n\n  1. Listens to a port until the port is available and it gets hold of the socket\n  2. Waits for a client connection on that port and accepts it\n  3. Reads the client request and writes a response back\n\nLet's implement those steps. Create a new `lib/kv/server.ex` and add the following functions:\n\n```elixir\ndefmodule KV.Server do\n  require Logger\n\n  def accept(port) do\n    # The options below mean:\n    #\n    # 1. `:binary` - receives data as binaries (instead of lists)\n    # 2. `packet: :line` - receives data line by line\n    # 3. `active: false` - blocks on `:gen_tcp.recv/2` until data is available\n    # 4. `reuseaddr: true` - allows us to reuse the address if the listener crashes\n    #\n    {:ok, socket} =\n      :gen_tcp.listen(port, [:binary, packet: :line, active: false, reuseaddr: true])\n    Logger.info(\"Accepting connections on port #{port}\")\n    loop_acceptor(socket)\n  end\n\n  defp loop_acceptor(socket) do\n    {:ok, client} = :gen_tcp.accept(socket)\n    serve(client)\n    loop_acceptor(socket)\n  end\n\n  defp serve(socket) do\n    socket\n    |> read_line()\n    |> write_line(socket)\n\n    serve(socket)\n  end\n\n  defp read_line(socket) do\n    {:ok, data} = :gen_tcp.recv(socket, 0)\n    data\n  end\n\n  defp write_line(line, socket) do\n    :gen_tcp.send(socket, line)\n  end\nend\n```\n\nWe are going to start our server by calling `KV.Server.accept(4040)`, where 4040 is the port. The first step in `accept/1` is to listen to the port until the socket becomes available and then call `loop_acceptor/1`. `loop_acceptor/1` is a loop accepting client connections. For each accepted connection, we call `serve/1`.\n\n`serve/1` is another loop that reads a line from the socket and writes those lines back to the socket. Note that the `serve/1` function uses the pipe operator `|>/2` to express this flow of operations. The pipe operator evaluates the left side and passes its result as the first argument to the function on the right side. The example above:\n\n```elixir\nsocket |> read_line() |> write_line(socket)\n```\n\nis equivalent to:\n\n```elixir\nwrite_line(read_line(socket), socket)\n```\n\nThe `read_line/1` implementation receives data from the socket using `:gen_tcp.recv/2` and `write_line/2` writes to the socket using `:gen_tcp.send/2`.\n\nNote that `serve/1` is an infinite loop called sequentially inside `loop_acceptor/1`, so the tail call to `loop_acceptor/1` is never reached and could be avoided. However, as we shall see, we will need to execute `serve/1` in a separate process, so we will need that tail call soon.\n\nThis is pretty much all we need to implement our echo server. Let's give it a try!\n\nStart an IEx session inside the `kv_server` application with `iex -S mix`. Inside IEx, run:\n\n```elixir\niex> KV.Server.accept(4040)\n```\n\nThe server is now running, and you will even notice the console is blocked. Let's use [a `telnet` client](https://en.wikipedia.org/wiki/Telnet) to access our server. There are clients available on most operating systems, and their command lines are generally similar:\n\n```console\n$ telnet 127.0.0.1 4040\nTrying 127.0.0.1...\nConnected to localhost.\nEscape character is '^]'.\nhello\nhello\nis it me\nis it me\nyou are looking for?\nyou are looking for?\n```\n\nType \"hello\", press enter, and you will get \"hello\" back. Excellent!\n\nMy particular telnet client can be exited by typing `ctrl + ]`, typing `quit`, and pressing `<Enter>`, but your client may require different steps.\n\nOnce you exit the telnet client, you will likely see an error in the IEx session:\n\n```text\n** (MatchError) no match of right hand side value: {:error, :closed}\n    (kv) lib/kv/server.ex:45: KV.Server.read_line/1\n    (kv) lib/kv/server.ex:37: KV.Server.serve/1\n    (kv) lib/kv/server.ex:30: KV.Server.loop_acceptor/1\n```\n\nThat's because we were expecting data from `:gen_tcp.recv/2` but the client closed the connection. We need to handle such cases better in future revisions of our server.\n\nFor now, there is a more important bug we need to fix: what happens if our TCP acceptor crashes? Since there is no supervision, the server dies and we won't be able to serve more requests, because it won't be restarted. That's why we must move our server to a supervision tree.\n\n## Tasks\n\nWhenever you have an existing function and you simply want to execute it when your application starts, the `Task` module is exactly what you need. For example, it has a `Task.start_link/1` function that receives an anonymous function and executes it inside a new process that will be part of a supervision tree.\n\nLet's give it a try. Open up `lib/kv.ex` and let's add a new child:\n\n```elixir\n  def start(_type, _args) do\n    children = [\n      {Registry, name: KV, keys: :unique},\n      {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one},\n      {Task, fn -> KV.Server.accept(4040) end}\n    ]\n\n    Supervisor.start_link(children, strategy: :one_for_one)\n  end\n```\n\nWith this change, we are saying that we want to run `KV.Server.accept(4040)` as a task. We are hardcoding the port for now but we will make this a configuration in later chapters. As usual, we've passed a two-element tuple as a child specification, which in turn will invoke `Task.start_link/1`.\n\nNow that the server is part of the supervision tree, it should start automatically when we run the application. Run `iex -S mix` to boot the app and use the `telnet` client to make sure that everything still works:\n\n```console\n$ telnet 127.0.0.1 4321\nTrying 127.0.0.1...\nConnected to localhost.\nEscape character is '^]'.\nsay you\nsay you\nsay me\nsay me\n```\n\nYes, it works! However, can it handle more than one client?\n\nTry to connect two telnet clients at the same time. When you do so, you will notice that the second client doesn't echo:\n\n```console\n$ telnet 127.0.0.1 4321\nTrying 127.0.0.1...\nConnected to localhost.\nEscape character is '^]'.\nhello\nhello?\nHELLOOOOOO?\n```\n\nIt doesn't seem to work at all. That's because we are serving requests in the same process that are accepting connections. When one client is connected, we can't accept another client.\n\n## Adding (flawed) concurrency\n\nIn order to make our server handle simultaneous connections, we need to have one process working as an acceptor that spawns other processes to serve requests. One solution would be to change:\n\n```elixir\ndefp loop_acceptor(socket) do\n  {:ok, client} = :gen_tcp.accept(socket)\n  serve(client)\n  loop_acceptor(socket)\nend\n```\n\nto also use `Task.start_link/1`:\n\n```elixir\ndefp loop_acceptor(socket) do\n  {:ok, client} = :gen_tcp.accept(socket)\n  {:ok, pid} = Task.start_link(fn -> serve(client) end)\n  :ok = :gen_tcp.controlling_process(client, pid)\n  loop_acceptor(socket)\nend\n```\n\nIn the new acceptor loop, we are starting a new task every time there is a new client. Now, if you attempt to connect two clients at the same time, it should work!\n\nOr does it? For example, what happens when you exit one telnet session? The other session should crash! The reason of this crash is two fold:\n\n1. We have a bug in our server where we don't expect `:gen_tcp.recv/2` to return an `{:error, :closed}` tuple\n\n2. Because each server task is linked to the acceptor process, if one task crashes, the acceptor process will also crash, taking down all other tasks and clients\n\nAn important rule of thumb throughout this guide is to always start processes as children of supervisors. The code above is an excellent example of what happens when we don't. If we don't isolate the different parts of our systems, failures can now cascade through our system, as it would happen in other languages.\n\nTo fix this, we could use a `DynamicSupervisor`, but tasks also provide a specialized `Task.Supervisor` which has better ergonomics and is optimized for supervising tasks themselves. Let's give it a try.\n\n## Adding a task supervisor\n\nLet's change `start/2` in `lib/kv.ex` once more, to add the task supervisor to our tree:\n\n```elixir\n  def start(_type, _args) do\n    children = [\n      {Registry, name: KV, keys: :unique},\n      {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one},\n      {Task.Supervisor, name: KV.ServerSupervisor},\n      {Task, fn -> KV.Server.accept(4040) end}\n    ]\n\n    Supervisor.start_link(children, strategy: :one_for_one)\n  end\n```\n\nWe'll now start a `Task.Supervisor` process with name `KV.TaskSupervisor`. Keep in mind that the order children are started matters. For example, the acceptor must come last because, if it comes first, it means our application can start accepting requests before the `Task.Supervisor` is running or before we can locate buckets. Shutting down an application will also stop the children in reverse order, guaranteeing a clean termination.\n\nNow we need to change `loop_acceptor/1` to use `Task.Supervisor` to serve each request:\n\n```elixir\ndefp loop_acceptor(socket) do\n  {:ok, client} = :gen_tcp.accept(socket)\n  {:ok, pid} = Task.Supervisor.start_child(KV.ServerSupervisor, fn -> serve(client) end)\n  :ok = :gen_tcp.controlling_process(client, pid)\n  loop_acceptor(socket)\nend\n```\n\nYou might notice that we added a line, `:ok = :gen_tcp.controlling_process(client, pid)`. This makes the child process the \"controlling process\" of the `client` socket. If we didn't do this, the acceptor would bring down all the clients if it crashed because sockets would be tied to the process that accepted them (which is the default behavior).\n\nNow start a new server with `iex -S mix` and try to open up many concurrent telnet clients. You will notice that quitting a client does not bring the acceptor down, even though we haven't fixed the bug in `:gen_tcp.recv/2` yet (which we will address in the next chapter). Excellent!\n\n## Restart strategies\n\nThere is one important topic we haven't explored yet with the necessary depth. What happens when a supervised process crashes?\n\nIn the previous chapter, when we started a bucket and killed it, the supervisor automatically started one in its place:\n\n```elixir\niex> children = [{KV.Bucket, name: :shopping}]\niex> Supervisor.start_link(children, strategy: :one_for_one)\niex> KV.Bucket.put(:shopping, \"milk\", 1)\niex> pid = Process.whereis(:shopping)\n#PID<0.48.0>\niex> Process.exit(pid, :kill)\ntrue\niex> Process.whereis(:shopping)\n#PID<0.50.0>\n```\n\nWhat exactly happens when a process terminates is part of its child specification. For `KV.Bucket`, we have this:\n\n```elixir\niex> KV.Bucket.child_spec([])\n%{id: KV.Bucket, start: {KV.Bucket, :start_link, [[]]}}\n```\n\nHowever, for tasks, we have this:\n\n```elixir\niex> Task.child_spec(fn -> :ok end)\n%{\n  id: Task,\n  restart: :temporary,\n  start: {Task, :start_link, [#Function<43.39164016/0 in :erl_eval.expr/6>]}\n}\n```\n\nNotice that a task says `:restart` is `:temporary`. `KV.Bucket` says nothing, which means it defaults to `:permanent`. `:temporary` means that a process is never restarted, regardless of why it crashed. `:permanent` means a process is always restarted, regardless of the exit reason. There is also `:transient`, which means it won't be restarted as long as it terminates successfully.\n\nNow we must ask ourselves, are those the correct settings?\n\nFor `KV.Bucket`, using `:permanent` seems logical, as we should not require the user to recreate a bucket they have previously created. Although currently we would lose the bucket data, in an actual system we would add mechanisms to recover it on initialization. However, for tasks, we have used them in two opposing ways in this chapter, which means at least one of them is wrong.\n\nWe use a task to start the acceptor. The acceptor is a critical component of our infrastructure. If it crashes, it means we won't accept further requests, and our server would then be useless as no one can connect to it. On the other hand, we also use `Task.Supervisor` to start tasks that deal with each connection. In this case, restarting may not be useful at all, given the reason we crashed could just as well be a connection issue, and attempting to restart over the same connection would lead to further failures.\n\nTherefore, we want the acceptor to actually run in `:permanent` mode, while we preserve the `Task.Supervisor` as `:temporary`. Luckily Elixir has an API that allows us to change an existing child specification, which we use below.\n\nLet's change `start/2` in `lib/kv.ex` once more to the following:\n\n```elixir\n  def start(_type, _args) do\n    children = [\n      {Registry, name: KV, keys: :unique},\n      {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one},\n      {Task.Supervisor, name: KV.ServerSupervisor},\n      Supervisor.child_spec({Task, fn -> KV.Server.accept(4040) end}, restart: :permanent)\n    ]\n\n    Supervisor.start_link(children, strategy: :one_for_one)\n  end\n```\n\nNow we have an always running acceptor that starts temporary task processes under an always running task supervisor.\n\n## Leveraging the ecosystem\n\nIn this chapter, we implemented a basic TCP acceptor while exploring concurrency and fault-tolerance. Our acceptor can manage concurrent connections, but it is still not ready for production. Production-ready TCP servers run a pool of acceptors, each with their own supervisor. Elixir's `PartitionSupervisor` might be used to partition and scale the acceptor, but it is out of scope for this guide. In practice, you will use existing packages tailored for this use-case, such as [Ranch](https://github.com/ninenines/ranch) (in Erlang) or [Thousand Island](https://github.com/mtrudel/thousand_island) (in Elixir).\n\nIn the next chapter, we will start parsing the client requests and sending responses, finishing our server.\n"
  },
  {
    "path": "lib/elixir/pages/references/compatibility-and-deprecations.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Compatibility and deprecations\n\nElixir is versioned according to a vMAJOR.MINOR.PATCH schema.\n\nElixir is currently at major version v1. A new backwards compatible minor release happens every 6 months. Patch releases are not scheduled and are made whenever there are bug fixes or security patches.\n\nElixir applies bug fixes only to the latest minor branch. Security patches are available for the last 5 minor branches:\n\nElixir version | Support\n:------------- | :-----------------------------\n1.20           | Development\n1.19           | Bug fixes and security patches\n1.18           | Security patches only\n1.17           | Security patches only\n1.16           | Security patches only\n1.15           | Security patches only\n\nNew releases are announced in the read-only [announcements mailing list](https://groups.google.com/group/elixir-lang-ann). All security releases [will be tagged with `[security]`](https://groups.google.com/forum/#!searchin/elixir-lang-ann/%5Bsecurity%5D%7Csort:date).\n\nThere are currently no plans for a major v2 release.\n\n## Between non-major Elixir versions\n\nElixir minor and patch releases are backwards compatible: well-defined behaviors and documented APIs in a given version will continue working on future versions.\n\nAlthough we expect the vast majority of programs to remain compatible over time, it is impossible to guarantee that no future change will break any program. Under some unlikely circumstances, we may introduce changes that break existing code:\n\n  * Security: a security issue in the implementation may arise whose resolution requires backwards incompatible changes. We reserve the right to address such security issues.\n\n  * Bugs: if an API has undesired behavior, a program that depends on the buggy behavior may break if the bug is fixed. We reserve the right to fix such bugs.\n\n  * Compiler front-end: improvements may be done to the compiler, introducing new warnings for ambiguous modes and providing more detailed error messages. Those can lead to compilation errors (when running with `--warnings-as-errors`) or tooling failures when asserting on specific error messages (although one should avoid such). We reserve the right to do such improvements.\n\n  * Imports: new functions may be added to the `Kernel` module, which is auto-imported. They may collide with local functions defined in your modules. Collisions can be resolved in a backwards compatible fashion using `import Kernel, except: [...]` with a list of all functions you don't want to be imported from `Kernel`. We reserve the right to do such additions.\n\nIn order to continue evolving the language without introducing breaking changes, Elixir will rely on deprecations to demote certain practices and promote new ones. Our deprecation policy is outlined in the [\"Deprecations\" section](#deprecations).\n\nThe only exception to the compatibility guarantees above are experimental features, which will be explicitly marked as such, and do not provide any compatibility guarantee until they are stabilized.\n\n## Between Elixir and Erlang/OTP\n\nErlang/OTP versioning is independent from the versioning of Elixir. Erlang releases a new major version yearly. Our goal is to support the last three Erlang major versions by the time Elixir is released. The compatibility table is shown below.\n\nElixir version | Supported Erlang/OTP versions\n:------------- | :-------------------------------\n1.20           | 27 - 29\n1.19           | 26 - 28\n1.18           | 25 - 27\n1.17           | 25 - 27\n1.16           | 24 - 26\n1.15           | 24 - 26\n1.14           | 23 - 25 (and Erlang/OTP 26 from v1.14.5)\n1.13           | 22 - 24 (and Erlang/OTP 25 from v1.13.4)\n1.12           | 22 - 24\n1.11           | 21 - 23 (and Erlang/OTP 24 from v1.11.4)\n1.10           | 21 - 22 (and Erlang/OTP 23 from v1.10.3)\n1.9            | 20 - 22\n1.8            | 20 - 22\n1.7            | 19 - 22\n1.6            | 19 - 20 (and Erlang/OTP 21 from v1.6.6)\n1.5            | 18 - 20\n1.4            | 18 - 19 (and Erlang/OTP 20 from v1.4.5)\n1.3            | 18 - 19\n1.2            | 18 - 18 (and Erlang/OTP 19 from v1.2.6)\n1.1            | 17 - 18\n1.0            | 17 - 17 (and Erlang/OTP 18 from v1.0.5)\n\nElixir may add compatibility to new Erlang/OTP versions on patch releases, such as support for Erlang/OTP 20 in v1.4.5. Those releases are made for convenience and typically contain the minimum changes for Elixir to run without errors, if any changes are necessary. Only the next minor release, in this case v1.5.0, effectively leverages the new features provided by the latest Erlang/OTP release.\n\n## Deprecations\n\n### Policy\n\nElixir deprecations happen in 3 steps:\n\n  1. The feature is soft-deprecated. It means both CHANGELOG and documentation must list the feature as deprecated but no warning is effectively emitted by running the code. There is no requirement to soft-deprecate a feature.\n\n  2. The feature is effectively deprecated by emitting warnings on usage. This is also known as hard-deprecation. In order to deprecate a feature, the proposed alternative MUST exist for AT LEAST THREE minor versions. For example, `Enum.uniq/2` was soft-deprecated in favor of `Enum.uniq_by/2` in Elixir v1.1. This means a deprecation warning may only be emitted by Elixir v1.4 or later.\n\n  3. The feature is removed. This can only happen on major releases. This means deprecated features in Elixir v1.x shall only be removed by Elixir v2.x.\n\n### Table of deprecations\n\nThe first column is the version the feature was hard deprecated. The second column shortly describes the deprecated feature and the third column explains the replacement and from which the version the replacement is available from.\n\nVersion | Deprecated feature                                  | Replaced by (available since)\n:-------| :-------------------------------------------------- | :---------------------------------------------------------------\n[v1.20] | `<<x::size(y)>>` in patterns without `^`            | `<<x::size(^y)>>` (v1.15)\n[v1.20] | `File.stream!(path, modes, lines_or_bytes)`         | `File.stream!(path, lines_or_bytes, modes)` (v1.16)\n[v1.20] | `Kernel.ParallelCompiler.async/1`                   | `Kernel.ParallelCompiler.pmap/2` (v1.16)\n[v1.20] | `Logger.*_backend` functions                        | The `LoggerBackends` module from [`:logger_backends`](https://hex.pm/packages/logger_backends) package\n[v1.20] | `Logger.enable/1` and `Logger.disable/1`            | `Logger.put_process_level/2` and `Logger.delete_process_level/1` respectively (v1.15)\n[v1.19] | CLI configuration in `def project` inside `mix.exs` | Moving it to `def cli` (v1.14)\n[v1.19] | Using `,` to separate tasks in `mix do`             | Using `+` (v1.14)\n[v1.19] | `Logger`'s `:backends` configuration                | `Logger`'s `:default_handler` configuration (v1.15)\n[v1.19] | Passing a callback to `File.cp/3`, `File.cp!/3`, `File.cp_r/3`, and `File.cp_r!/3` | The `:on_conflict` option (v1.14)\n[v1.18] | `<%#` in EEx                                        | `<%!--` (v1.14) or `<% #` (v1.0)\n[v1.18] | `EEx.Engine.handle_text/2` callback in EEx          | `c:EEx.Engine.handle_text/3` (v1.14)\n[v1.18] | Returning a 2-arity function from `Enumerable.slice/1` | Returning a 3-arity function (v1.14)\n[v1.18] | Ranges with negative steps in `Range.new/2`         | Explicit steps in ranges (v1.11)\n[v1.18] | `Tuple.append/2`                                    | `Tuple.insert_at/3` (v1.0)\n[v1.18] | `mix cmd --app APP`                                 | `mix do --app APP` (v1.14)\n[v1.18] | `List.zip/1`                                        | `Enum.zip/1` (v1.0)\n[v1.18] | `Module.eval_quoted/3`                              | `Code.eval_quoted/3` (v1.0)\n[v1.17] | Single-quoted charlists (`'foo'`)                   | `~c\"foo\"` (v1.0)\n[v1.17] | `left..right` in patterns and guards                | `left..right//step` (v1.11)\n[v1.17] | `ExUnit.Case.register_test/4`                       | `register_test/6` (v1.10)\n[v1.17] | `:all` in `IO.read/2` and `IO.binread/2`            | `:eof` (v1.13)\n[v1.16] | `~R/.../`                                           | `~r/.../` (v1.0)\n[v1.16] | Ranges with negative steps in `Enum.slice/2`        | Explicit steps in ranges (v1.11)\n[v1.16] | Ranges with negative steps in `String.slice/2`      | Explicit steps in ranges (v1.11)\n[v1.15] | `Calendar.ISO.day_of_week/3`                        | `Calendar.ISO.day_of_week/4` (v1.11)\n[v1.15] | `Exception.exception?/1`                            | `Kernel.is_exception/1` (v1.11)\n[v1.15] | `Regex.regex?/1`                                    | `Kernel.is_struct/2` (`Kernel.is_struct(term, Regex)`) (v1.11)\n[v1.15] | `Logger.warn/2`                                     | `Logger.warning/2` (v1.11)\n[v1.14] | `use Bitwise`                                       | `import Bitwise` (v1.0)\n[v1.14] | `~~~/1`                                             | `bnot/2` (v1.0)\n[v1.14] | `Application.get_env/3` and similar in module body  | `Application.compile_env/3` (v1.10)\n[v1.14] | Compiled patterns in `String.starts_with?/2`        | Pass a list of strings instead (v1.0)\n[v1.14] | `Mix.Tasks.Xref.calls/1`                            | Compilation tracers (outlined in `Code`) (v1.10)\n[v1.14] | `$levelpad` in Logger                               | *None*\n[v1.14] | `<\\|>` as a custom operator                         | Another custom operator (v1.0)\n[v1.13] | `!` and `!=` in Version requirements                | `~>` or `>=` (v1.0)\n[v1.13] | `Mix.Config`                                        | `Config` (v1.9)\n[v1.13] | `:strip_beam` config to `mix escript.build`         | `:strip_beams` (v1.9)\n[v1.13] | `Macro.to_string/2`                                 | `Macro.to_string/1` (v1.0)\n[v1.13] | `System.get_pid/0`                                  | `System.pid/0` (v1.9)\n[v1.12] | `^^^/2`                                             | `bxor/2` (v1.0)\n[v1.12] | `@foo()` to read module attributes                  | Remove the parenthesis (v1.0)\n[v1.12] | `use EEx.Engine`                                    | Explicitly delegate to EEx.Engine instead (v1.0)\n[v1.12] | `:xref` compiler in Mix                             | Nothing (it always runs as part of the compiler now)\n[v1.11] | `Mix.Project.compile/2`                             | `Mix.Task.run(\"compile\", args)` (v1.0)\n[v1.11] | `Supervisor.Spec.worker/3` and `Supervisor.Spec.supervisor/3` | The new child specs outlined in `Supervisor` (v1.5)\n[v1.11] | `Supervisor.start_child/2` and `Supervisor.terminate_child/2` | `DynamicSupervisor` (v1.6)\n[v1.11] | `System.stacktrace/1`                               | `__STACKTRACE__` in `try/catch/rescue` (v1.7)\n[v1.10] | `Code.ensure_compiled?/1`                           | `Code.ensure_compiled/1` (v1.0)\n[v1.10] | `Code.load_file/2`                                  | `Code.require_file/2` (v1.0) or `Code.compile_file/2` (v1.7)\n[v1.10] | `Code.loaded_files/0`                               | `Code.required_files/0` (v1.7)\n[v1.10] | `Code.unload_file/1`                                | `Code.unrequire_files/1` (v1.7)\n[v1.10] | Passing non-chardata to `Logger.log/2`              | Explicitly convert to string with `to_string/1` (v1.0)\n[v1.10] | `:compile_time_purge_level` in `Logger` app environment | `:compile_time_purge_matching` in `Logger` app environment (v1.7)\n[v1.10] | `Supervisor.Spec.supervise/2`                       | The new child specs outlined in `Supervisor` (v1.5)\n[v1.10] | `:simple_one_for_one` strategy in `Supervisor`      | `DynamicSupervisor` (v1.6)\n[v1.10] | `:restart` and `:shutdown` in `Task.Supervisor.start_link/1` | `:restart` and `:shutdown` in `Task.Supervisor.start_child/3` (v1.6)\n[v1.9]  | Enumerable keys in `Map.drop/2`, `Map.split/2`, and `Map.take/2` | Call `Enum.to_list/1` on the second argument before hand (v1.0)\n[v1.9]  | `Mix.Project.load_paths/1`                          | `Mix.Project.compile_path/1` (v1.0)\n[v1.9]  | Passing `:insert_replaced` to `String.replace/4`    | Use `:binary.replace/4` (v1.0)\n[v1.8]  | Passing a non-empty list to `Collectable.into/1`    | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `:into` in `for/1`      | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `Enum.into/2`           | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Time units in its plural form, such as: `:seconds`, `:milliseconds`, and the like | Use the singular form, such as: `:second`, `:millisecond`, and so on (v1.4)\n[v1.8]  | `Inspect.Algebra.surround/3`                        | `Inspect.Algebra.concat/2` and `Inspect.Algebra.nest/2` (v1.0)\n[v1.8]  | `Inspect.Algebra.surround_many/6`                   | `Inspect.Algebra.container_doc/6` (v1.6)\n[v1.9]  | `--detached` in `Kernel.CLI`                        | `--erl \"-detached\"` (v1.0)\n[v1.8]  | `Kernel.ParallelCompiler.files/2`                   | `Kernel.ParallelCompiler.compile/2` (v1.6)\n[v1.8]  | `Kernel.ParallelCompiler.files_to_path/2`           | `Kernel.ParallelCompiler.compile_to_path/2` (v1.6)\n[v1.8]  | `Kernel.ParallelRequire.files/2`                    | `Kernel.ParallelCompiler.require/2` (v1.6)\n[v1.8]  | Returning `{:ok, contents}` or `:error` from `Mix.Compilers.Erlang.compile/6`'s callback | Return `{:ok, contents, warnings}` or `{:error, errors, warnings}` (v1.6)\n[v1.8]  | `System.cwd/0` and `System.cwd!/0`                  | `File.cwd/0` and `File.cwd!/0` respectively (v1.0)\n[v1.7]  | `Code.get_docs/2`                                   | `Code.fetch_docs/1` (v1.7)\n[v1.7]  | `Enum.chunk/2,3,4`                                  | `Enum.chunk_every/2` and [`Enum.chunk_every/3,4`](`Enum.chunk_every/4`) (v1.5)\n[v1.7]  | Calling `super/1` in`GenServer` callbacks           | Implementing the behaviour explicitly without calling `super/1` (v1.0)\n[v1.7]  | [`not left in right`](`in/2`)                | [`left not in right`](`in/2`) (v1.5)\n[v1.7]  | `Registry.start_link/3`                             | `Registry.start_link/1` (v1.5)\n[v1.7]  | `Stream.chunk/2,3,4`                                | `Stream.chunk_every/2` and [`Stream.chunk_every/3,4`](`Stream.chunk_every/4`) (v1.5)\n[v1.6]  | `Enum.partition/2`                                  | `Enum.split_with/2` (v1.4)\n[v1.6]  | `Macro.unescape_tokens/1,2`                         | Use `Enum.map/2` to traverse over the arguments (v1.0)\n[v1.6]  | `Module.add_doc/6`                                  | [`@doc`](`Module`) module attribute (v1.0)\n[v1.6]  | `Range.range?/1`                                    | Pattern match on [`_.._`](`../2`) (v1.0)\n[v1.5]  | `()` to mean `nil`                                  | `nil` (v1.0)\n[v1.5]  | `char_list/0` type                                  | `t:charlist/0` type (v1.3)\n[v1.5]  | `Atom.to_char_list/1`                               | `Atom.to_charlist/1` (v1.3)\n[v1.5]  | `Enum.filter_map/3`                                 | `Enum.filter/2` + `Enum.map/2` or `for/1` comprehensions (v1.0)\n[v1.5]  | `Float.to_char_list/1`                              | `Float.to_charlist/1` (v1.3)\n[v1.5]  | `GenEvent` module                                   | `Supervisor` and `GenServer` (v1.0)\n[v1.5]  | `<%=` in middle and end expressions in `EEx`        | Use `<%` (`<%=` is allowed only in start expressions) (v1.0)\n[v1.5]  | `:as_char_lists` value in `t:Inspect.Opts.t/0` type | `:as_charlists` value (v1.3)\n[v1.5]  | `:char_lists` key in `t:Inspect.Opts.t/0` type      | `:charlists` key (v1.3)\n[v1.5]  | `Integer.to_char_list/1,2`                          | `Integer.to_charlist/1` and `Integer.to_charlist/2` (v1.3)\n[v1.5]  | `to_char_list/1`                                    | `to_charlist/1` (v1.3)\n[v1.5]  | `List.Chars.to_char_list/1`                         | `List.Chars.to_charlist/1` (v1.3)\n[v1.5]  | `@compile {:parse_transform, _}` in `Module`        | *None*\n[v1.5]  | `Stream.filter_map/3`                               | `Stream.filter/2` + `Stream.map/2` (v1.0)\n[v1.5]  | `String.ljust/3` and `String.rjust/3`               | Use `String.pad_leading/3` and `String.pad_trailing/3` with a binary padding (v1.3)\n[v1.5]  | `String.lstrip/1` and `String.rstrip/1`             | `String.trim_leading/1` and `String.trim_trailing/1` (v1.3)\n[v1.5]  | `String.lstrip/2` and `String.rstrip/2`             | Use `String.trim_leading/2` and `String.trim_trailing/2` with a binary as second argument (v1.3)\n[v1.5]  | `String.strip/1` and `String.strip/2`               | `String.trim/1` and `String.trim/2` (v1.3)\n[v1.5]  | `String.to_char_list/1`                             | `String.to_charlist/1` (v1.3)\n[v1.4]  | Anonymous functions with no expression after `->`   | Use an expression or explicitly return `nil` (v1.0)\n[v1.4]  | Support for making [private functions](`defp/2`) overridable | Use [public functions](`def/2`) (v1.0)\n[v1.4]  | Variable used as function call                      | Use parentheses (v1.0)\n[v1.4]  | `Access.key/1`                                      | `Access.key/2` (v1.3)\n[v1.4]  | `Behaviour` module                                  | `@callback` module attribute (v1.0)\n[v1.4]  | `Enum.uniq/2`                                       | `Enum.uniq_by/2` (v1.2)\n[v1.4]  | `Float.to_char_list/2`                              | `:erlang.float_to_list/2` (Erlang/OTP 17)\n[v1.4]  | `Float.to_string/2`                                 | `:erlang.float_to_binary/2` (Erlang/OTP 17)\n[v1.4]  | `HashDict` module                                   | `Map` (v1.2)\n[v1.4]  | `HashSet` module                                    | `MapSet` (v1.1)\n[v1.4]  | `IEx.Helpers.import_file/2`                         | `IEx.Helpers.import_file_if_available/1` (v1.3)\n[v1.4]  | `Mix.Utils.camelize/1`                              | `Macro.camelize/1` (v1.2)\n[v1.4]  | `Mix.Utils.underscore/1`                            | `Macro.underscore/1` (v1.2)\n[v1.4]  |  Multi-letter aliases in `OptionParser`             | Use single-letter aliases (v1.0)\n[v1.4]  | `Set` module                                        | `MapSet` (v1.1)\n[v1.4]  | `Stream.uniq/2`                                     | `Stream.uniq_by/2` (v1.2)\n[v1.3]  | `\\x{X*}` inside strings/sigils/charlists            | `\\uXXXX` or `\\u{X*}` (v1.1)\n[v1.3]  | `Dict` module                                       | `Keyword` (v1.0) or `Map` (v1.2)\n[v1.3]  | `:append_first` option in `defdelegate/2`           | Define the function explicitly (v1.0)\n[v1.3]  | Map/dictionary as 2nd argument in `Enum.group_by/3` | `Enum.reduce/3` (v1.0)\n[v1.3]  | `Keyword.size/1`                                    | `length/1` (v1.0)\n[v1.3]  | `Map.size/1`                                        | `map_size/1` (v1.0)\n[v1.3]  | `/r` option in `Regex`                              | `/U` (v1.1)\n[v1.3]  | `Set` behaviour                                     | `MapSet` data structure (v1.1)\n[v1.3]  | `String.valid_character?/1`                         | `String.valid?/1` (v1.0)\n[v1.3]  | `Task.find/2`                                       | Use direct message matching (v1.0)\n[v1.3]  | Non-map as 2nd argument in `URI.decode_query/2`     | Use a map (v1.0)\n[v1.2]  | `Dict` behaviour                                    | `Map` and `Keyword` (v1.0)\n[v1.1]  | `?\\xHEX`                                            | `0xHEX` (v1.0)\n[v1.1]  | `Access` protocol                                   | `Access` behaviour (v1.1)\n[v1.1]  | `as: true \\| false` in `alias/2` and `require/2`    | *None*\n\n[v1.1]: https://github.com/elixir-lang/elixir/blob/v1.1/CHANGELOG.md#4-deprecations\n[v1.2]: https://github.com/elixir-lang/elixir/blob/v1.2/CHANGELOG.md#changelog-for-elixir-v12\n[v1.3]: https://github.com/elixir-lang/elixir/blob/v1.3/CHANGELOG.md#4-deprecations\n[v1.4]: https://github.com/elixir-lang/elixir/blob/v1.4/CHANGELOG.md#4-deprecations\n[v1.5]: https://github.com/elixir-lang/elixir/blob/v1.5/CHANGELOG.md#4-deprecations\n[v1.6]: https://github.com/elixir-lang/elixir/blob/v1.6/CHANGELOG.md#4-deprecations\n[v1.7]: https://github.com/elixir-lang/elixir/blob/v1.7/CHANGELOG.md#4-hard-deprecations\n[v1.8]: https://github.com/elixir-lang/elixir/blob/v1.8/CHANGELOG.md#4-hard-deprecations\n[v1.9]: https://github.com/elixir-lang/elixir/blob/v1.9/CHANGELOG.md#4-hard-deprecations\n[v1.10]: https://github.com/elixir-lang/elixir/blob/v1.10/CHANGELOG.md#4-hard-deprecations\n[v1.11]: https://github.com/elixir-lang/elixir/blob/v1.11/CHANGELOG.md#4-hard-deprecations\n[v1.12]: https://github.com/elixir-lang/elixir/blob/v1.12/CHANGELOG.md#4-hard-deprecations\n[v1.13]: https://github.com/elixir-lang/elixir/blob/v1.13/CHANGELOG.md#4-hard-deprecations\n[v1.14]: https://github.com/elixir-lang/elixir/blob/v1.14/CHANGELOG.md#4-hard-deprecations\n[v1.15]: https://github.com/elixir-lang/elixir/blob/v1.15/CHANGELOG.md#4-hard-deprecations\n[v1.16]: https://github.com/elixir-lang/elixir/blob/v1.16/CHANGELOG.md#4-hard-deprecations\n[v1.17]: https://github.com/elixir-lang/elixir/blob/v1.17/CHANGELOG.md#4-hard-deprecations\n[v1.18]: https://github.com/elixir-lang/elixir/blob/v1.18/CHANGELOG.md#4-hard-deprecations\n[v1.19]: https://github.com/elixir-lang/elixir/blob/v1.19/CHANGELOG.md#4-hard-deprecations\n[v1.20]: https://github.com/elixir-lang/elixir/blob/main/CHANGELOG.md#4-hard-deprecations\n"
  },
  {
    "path": "lib/elixir/pages/references/gradual-set-theoretic-types.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Gradual set-theoretic types\n\nElixir is in the process of incorporating set-theoretic types into the compiler. This document outlines the current stage of our implementation for this Elixir version. Elixir's type system is:\n\n  * **sound** - the inferred and assigned by the type system align with the behaviour of the program\n\n  * **gradual** - Elixir's type system includes the `dynamic()` type, which can be used when the type of a variable or expression is checked at runtime. However, instead of simply discarding all typing information, Elixir's `dynamic()` type works as a range. For example, if you write `dynamic(integer() or binary())`, Elixir's type system will still emit violations if none of those types are accepted. Furthermore, in the absence of `dynamic()`, Elixir's type system behaves as a static one\n\n  * **developer friendly** - the types are described, implemented, and composed using basic set operations: unions, intersections, and negation (hence it is a set-theoretic type system)\n\nThe current milestone aims to infer types from existing programs and use them for type checking, enabling the Elixir compiler to find faults and bugs in codebases without requiring changes to existing software. User provided type signatures are planned for future releases. The underlying principles, theory, and roadmap of our work have been outlined in [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391).\n\n## A gentle introduction\n\nTypes in Elixir are written using the type named followed by parentheses, such as `integer()` or `list(integer())`.\n\nThe basic types are:\n\n```elixir\natom()\nbinary()\nbitstring()\nempty_list()\ninteger()\nfloat()\nfunction()\nmap()\nnon_empty_list(elem_type, tail_type)\npid()\nport()\nreference()\ntuple()\n```\n\nMany of the types above can also be written more precisely. We will discuss their syntax in the next sections, but here are two examples:\n\n  * While `atom()` represents all atoms, the atom `:ok` can also be represented in the type system as `:ok`\n\n  * While `tuple()` represents all tuples, you can specify the type of a two-element tuple where the first element is the atom `:ok` and the second is an integer as `{:ok, integer()}`\n\nThere are also three special types: `none()` (represents an empty set), `term()` (represents all types), `dynamic()` (represents a range of the given types).\n\nGiven the types are set-theoretic, we can compose them using unions (`or`), intersections (`and`), and negations (`not`). For example, to say a function returns either atoms or integers, one could write: `atom() or integer()`.\n\nIntersections will find the elements in common between the operands. For example, `atom() and integer()`, which in this case is the empty set `none()`. You can combine intersections and negations to perform difference, for example, to say that a function expects all atoms, except `nil` (which is an atom), you could write: `atom() and not nil`.\n\nYou can find a complete reference in the [set-theoretic types cheatsheet](../cheatsheets/types-cheat.cheatmd).\n\n## The syntax of data types\n\nIn this section we will cover the syntax of all data types. At the moment, developers will interact with those types mostly through compiler warnings and diagnostics.\n\n### Broad types\n\nThese types are broad in that they cannot represent individual elements, only the whole set. For example, the numbers `1` and `42` are both represented by the type `integer()`.\n\nThey are: `binary()`, `bitstring()`, `integer()`, `float()`, `pid()`, `port()`, `reference()`.\n\nThe `binary()` type is a subtype of the less frequently used `bitstring()` type, as binaries are bitstrings where the number of bits is divisible by 8.\n\n### Atoms\n\nYou can represent all atoms as `atom()`. You can also represent each individual atom using their literal syntax. For instance, the atom `:foo` and `:hello_world` are also valid (distinct) types.\n\n`nil`, `true`, and `false` are also atoms and can be written as is. `boolean()` is a convenience type alias that represents `true or false`.\n\n### Tuples\n\nYou can represent all tuples as `tuple()`. Tuples may also be written using the curly brackets syntax, such as `{:ok, binary()}`.\n\nYou may use `...` at the end of the tuple to imply the overall size of the tuple is unknown. For example, the following tuple has at least two elements: `{:ok, binary(), ...}`.\n\n### Lists\n\nYou can represent all _proper_ lists as `list()`, which also includes the empty list.\n\nYou can also specify the type of the list element as argument. For example, `list(integer())` represents the values `[]` and `[1, 2, 3]`, but not `[1, \"two\", 3]`.\n\nInternally, Elixir represents the type `list(a)` as the union two distinct types, `empty_list()` and `not_empty_list(a)`. In other words, `list(integer())` is equivalent to `empty_list() or non_empty_list(integer())`.\n\n#### Improper lists\n\nWhile most developers will simply use `list(a)`, the type system can express all different representations of lists in Elixirby passing a second argument to `non_empty_list`, which represents the type of the tail.\n\nA proper list is one where the tail is the empty list itself. The type `non_empty_list(integer())` is equivalent to `non_empty_list(integer(), empty_list())`.\n\nIf the `tail_type` is anything but a list, then we have an improper list. For example, the value `[1, 2 | 3]` would have the type `non_empty_list(integer(), integer())`.\n\nIf you pass a list type as the tail, then the list type is merged into the element type. For example, `non_empty_list(integer(), list(binary()))` is the same as `non_empty_list(integer() or binary(), empty_list())`.\n\n### Maps\n\nYou can represent all maps as `map()`.\n\nMaps may also be written using their literal syntax:\n\n```elixir\n%{name: binary(), age: integer()}\n```\n\nwhich outlines a map with exactly two keys, `:name` and `:age`, and values of type `binary()` and `integer()` respectively. We say the map above is \"closed\": it only supports the keys explicitly defined. We can also mark a map as \"open\", by including `...` as its first element:\n\n```elixir\n%{..., name: binary(), age: integer()}\n```\n\nThe type above says the keys `:name` and `:age` must exist, with their respective types, but other keys may be present. The `map()` type is the same as `%{...}`. For the empty map, you may write `%{}`, although we recommend using `empty_map()` for clarity.\n\n#### Optional keys\n\nA key may be marked as optional using the `if_set/1` operation on its value type:\n\n```elixir\n%{name: binary(), age: if_set(integer())}\n```\n\nis a map that certainly has the `:name` key but it may have the `:age` key (and if it has such key, its value type is `integer()`).\n\nYou can also use `not_set()` to denote a key cannot be present:\n\n```elixir\n%{..., age: not_set()}\n```\n\nThe type above says the map may have any key, except the `:age` one. This is, for instance, the type returned by `Map.delete(map, :age)`.\n\n#### Domain types\n\nIn the examples above, all map keys were atoms, but we can also use other types as map keys. For example:\n\n```elixir\n# Closed map\n%{binary() or atom() => integer()}\n\n# Open map\n%{..., binary() or atom() => integer()}\n```\n\nCurrently, the type system only tracks the top of each individual type as the domain keys. For example, if you say:\n\n```elixir\n%{list(integer()) => integer(), list(binary()) => binary()}\n```\n\nThat's the same as specifying all lists:\n\n```elixir\n%{list() => integer() or binary()}\n```\n\nThe supported domain keys are `atom()`, `bitstring()`, `binary()`, `integer()`, `float()`, `fun()`, `list()`, `map()`, `pid()`, `port()`, `reference()`, and `tuple()`. In the case of maps, the `bitstring()` domain stores exclusively keys which are not binary. The ones which are `binary()` are stored under the `binary()` domain.\n\nFurthermore, it is important to note that domain keys are, by definition, optional. Whenever you have a `%{integer() => integer()}`and you try to fetch a key, we must assume the key may not exist (after all, it is not possible to store all integers as map keys as they are infinite).\n\n#### Mixed keys\n\nIt is also possible to mix domain and atom keys. For example, the following map says that all atom keys are of type `binary()`, except the `:root` key, which has type `integer()`:\n\n```elixir\n# Closed map\n%{atom() => binary(), root: integer()}\n\n# Open map\n%{..., atom() => binary(), root: integer()}\n```\n\nThe order of the keys is of increasing precision. `:root` is more precise than `atom()`, therefore it comes later. This mirrors the runtime semantics of maps, where duplicate keys override the value of earlier ones.\n\n### Functions\n\nYou can represent all functions as `function()`.  However, in practice, most functions are represented as arrows. For example, a function that receives an integer and return boolean would be written as `(integer() -> boolean())`. A function that receives two integers and return a string (i.e. a binary) would be written as `(integer(), integer() -> binary())`.\n\nWhen representing functions with multiple clauses, which may take different input types, we use intersections. For example, imagine the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nIf you give it an integer, it negates it. If you give it a boolean, it negates it.\n\nWe can say this function has the type `(integer() -> integer())` because it is capable of receiving an integer and returning an integer. In this case, `(integer() -> integer())` is a set that represents all functions that can receive an integer and return an integer. Even though this function can receive other arguments and return other values, it is still part of the `(integer() -> integer())` set.\n\nThis function also has the type `(boolean() -> boolean())`, because it also receives booleans and returns booleans. If you pass the function above to another function that expects `(boolean() -> boolean())`, type checking will succeed. Therefore, we can say the overall type of the function is `(integer() -> integer()) and (boolean() -> boolean())`. The intersection means the function belongs to both sets.\n\nAt this point, you may ask, why not a union? As a real-world example, take a t-shirt with green and yellow stripes. We can say the t-shirt belongs to the set of \"t-shirts with green color\". We can also say the t-shirt belongs to the set of \"t-shirts with yellow color\". Let's see the difference between unions and intersections:\n\n  * `(t_shirts_with_green() or t_shirts_with_yellow())` - contains t-shirts with either green or yellow, such as green, green and red, green and yellow, but also only yellow, yellow and red, etc.\n\n  * `(t_shirts_with_green() and t_shirts_with_yellow())` - contains t-shirts with both green and yellow (and maybe other colors)\n\nSince the t-shirt has both colors, we could say it belongs to the union of green and yellow t-shirts, but doing so would not capture the fact it is both green and yellow. Therefore it is more precise to say it belongs to the intersection of both sets. The same way that a function that goes from `(integer() -> integer())` and `(boolean() -> boolean())` is also an intersection. In practice, it is not useful to define the union of two functions in Elixir, so the compiler will point you to the right direction if you specify the wrong one.\n\n## The `dynamic()` type\n\nExisting Elixir programs do not have type declarations, but we still want to be able to type check them. This is done with the introduction of the `dynamic()` type.\n\nWhen Elixir sees the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nElixir type checks it as if the function had the type `(dynamic() -> dynamic())`. Then, based on patterns and guards, we can refine the value of the variable `x` to be `dynamic() and integer()` and `dynamic() and boolean()` for each clause respectively. We say `dynamic()` is a gradual type, which leads us to _gradual set-theoretic types_.\n\nThe simplest way to reason about `dynamic()` in Elixir is that it is a range of types. If you have a type `atom() or integer()`, the underlying code needs to work with both `atom() or integer()`. For example, if you call `Integer.to_string(var)`, and `var` has type `atom() or integer()`, the type system will emit a warning, because `Integer.to_string/1` does not accept atoms.\n\nHowever, by intersecting a type with `dynamic()`, we make the type gradual and therefore only a subset of the type needs to be valid. For instance, if you call `Integer.to_string(var)`, and `var` has type `dynamic() and (atom() or integer())`, the type system will not emit a warning, because `Integer.to_string/1` works with at least one of the types. For convenience, most programs will write `dynamic(atom() or integer())` instead of the intersection. They are equivalent.\n\nCompared to other gradually typed languages, the `dynamic()` type in Elixir is quite powerful: it restricts our program to certain types, via intersections, while still emitting warnings once it is certain the code will fail. This makes `dynamic()` an excellent tool for typing existing Elixir code with meaningful warnings.\n\nIf the user provides their own types, and those types are not `dynamic()`, then Elixir's type system behaves as a statically typed one. This brings us to one last property of dynamic types in Elixir: dynamic types are always at the root. For example, when you write a tuple of type `{:ok, dynamic()}`, Elixir will rewrite it to `dynamic({:ok, term()})`. While this has the downside that you cannot make part of a tuple/map/list gradual, only the whole tuple/map/list, it comes with the upside that dynamic is always explicitly at the root, making it harder to accidentally sneak `dynamic()` in a statically typed program.\n\n## Type inference\n\nType inference (or reconstruction) is the ability of a type system to automatically deduce, either partially or fully, the type of an expression at compile time. Type inference may occur at different levels. For example, many programming languages can automatically infer the types of variables, also known \"local type inference\", but not all can infer type signatures of functions.\n\nInferring type signatures comes with a series of trade-offs:\n\n  * Speed - type inference algorithms are often more computationally intensive than type checking algorithms.\n\n  * Expressiveness - in any given type system, the constructs that support inference are always a subset of those that can be type-checked. Therefore, if a programming language is restricted to fully reconstructed types, it is less expressive than a solely type checked counterpart.\n\n  * Incremental compilation - type inference complicates incremental compilation. If module A depends on module B, which depends on module C, a change to C may require the type signature in B to be reconstructed, which may then require A to be recomputed (and so on). This dependency chain may require large projects to explicitly add type signatures for stability and compilation efficiency.\n\n  * Cascading errors - when a user accidentally makes type errors or the code has conflicting assumptions, type inference may lead to less clear error messages as the type system tries to reconcile diverging type assumptions across code paths.\n\nOn the other hand, type inference offers the benefit of enabling type checking for functions and codebases without requiring the user to add type annotations. To balance these trade-offs, Elixir aims to provide \"module type inference\": our goal is to infer the types of functions considering the current module, Elixir's standard library and your dependencies, while calls to modules within the same project are assumed to be `dynamic()`. Once types are inferred, then the whole project is type checked considering all modules and all types (inferred or otherwise).\n\nType inference in Elixir is best-effort: it doesn't guarantee it will find all possible type incompatibilities, only that it may find bugs where all combinations of a type _will_ fail, even in the absence of explicit type annotations. It is meant to be an efficient routine that brings developers some benefits of static typing without requiring any effort from them.\n\nIn the long term, Elixir developers who want typing guarantees must explicitly add type signatures to their functions (see \"Roadmap\"). Any function with an explicit type signature will be typed checked against the user-provided annotations, as in other statically typed languages, without performing type inference. In summary, type checking will rely on type signatures and only fallback to inferred types when no signature is available.\n\n## Roadmap\n\nThe current milestone is to implement type inference of existing codebases, as well as type checking of all language constructs, without changes to the Elixir language. At this stage, we want to collect feedback on the quality of error messages and performance, and therefore the type system has no user facing API. Full type inference of patterns was released in Elixir v1.18, and complete inference is expected as part of Elixir v1.20.\n\nIf the results are satisfactory, the next milestone will include a mechanism for defining typed structs. Elixir programs frequently pattern match on structs, which reveals information about the struct fields, but it knows nothing about their respective types. By propagating types from structs and their fields throughout the program, we will increase the type system’s ability to find errors while further straining our type system implementation. Proposals including the required changes to the language surface will be sent to the community once we reach this stage.\n\nThe third milestone is to introduce set-theoretic type signatures for functions. Unfortunately, the existing Erlang Typespecs are not precise enough for set-theoretic types and they will be phased out of the language and have their postprocessing moved into a separate library once this stage concludes.\n\n## Acknowledgements\n\nThe type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/), and [Tidewave](https://tidewave.ai/).\n"
  },
  {
    "path": "lib/elixir/pages/references/library-guidelines.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Library guidelines\n\nThis document outlines general guidelines for those writing and publishing\nElixir libraries meant to be consumed by other developers.\n\n## Getting started\n\nYou can create a new Elixir library by running the `mix new` command:\n\n    $ mix new my_library\n\nThe project name is given in the `snake_case` convention where all letters are lowercase and words are separate with underscores. This is the same convention used by variables, function names and atoms in Elixir. See the [Naming Conventions](naming-conventions.md) document for more information.\n\nEvery project has a `mix.exs` file, with instructions on how to build, compile, run tests, and so on. Libraries commonly have a `lib` directory, which includes Elixir source code, and a `test` directory. A `src` directory may also exist for Erlang sources.\n\nThe `mix new` command also allows the `--sup` option to scaffold a new project with a supervision tree out of the box. For more information on running your project, see the official [Mix & OTP guide](../mix-and-otp/introduction-to-mix.md) or [Mix documentation](`Mix`).\n\n## Publishing\n\nWriting code is only the first of many steps to publish a package. We strongly recommend developers to:\n\n  * Choose a versioning schema. Elixir requires versions to be in the format `MAJOR.MINOR.PATCH` but the meaning of those numbers is up to you. Most projects choose [Semantic Versioning](https://semver.org/).\n\n  * Choose a [license](https://choosealicense.com/). The most common licenses in the Elixir community are the [MIT License](https://choosealicense.com/licenses/mit/) and the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/). The latter is also the one used by Elixir itself.\n\n  * Run the [code formatter](`mix format`). The code formatter formats your code according to a consistent style shared by your library and the whole community, making it easier for other developers to understand your code and contribute.\n\n  * Write tests. Elixir ships with a test-framework named [ExUnit](`ExUnit`). The project generated by `mix new` includes sample tests and doctests.\n\n  * Write documentation. The Elixir community is proud of treating documentation as a first-class citizen and making documentation easily accessible. Libraries contribute to the status quo by providing complete API documentation with examples for their modules, types and functions. See the [Writing documentation](../getting-started/writing-documentation.md) chapter of the Getting Started guide for more information. Projects like [ExDoc](https://github.com/elixir-lang/ex_doc) can be used to generate HTML and EPUB documents from the documentation. ExDoc also supports \"extra pages\", like this one that you are reading. Such pages augment the documentation with tutorials, guides, references, and even cheat-sheets.\n\n  * Follow best practices. The Elixir project documents [a series of anti-patterns](../anti-patterns/what-anti-patterns.md) that you may want to avoid in your code. The [process-related anti-patterns](../anti-patterns/process-anti-patterns.md) and [meta-programming anti-patterns](../anti-patterns/macro-anti-patterns.md) are of special attention to library authors.\n\nProjects are often made available to other developers [by publishing a Hex package](https://hex.pm/docs/publish). Hex also [supports private packages for organizations](https://hex.pm/pricing). If ExDoc is configured for the Mix project, publishing a package on Hex will also automatically publish the generated documentation to [HexDocs](https://hexdocs.pm).\n\n## Dependency handling\n\nWhen your library is used as a dependency, it runs by default in the `:prod` environment. Therefore, if your library has dependencies that are only useful in development or testing, you want to specify those dependencies with the `:only` option. You can also specify `:optional` dependencies in your library, which are not enforced upon users of your library. In such cases, you should also consider compiling your projects with the `mix compile --no-optional-deps --warnings-as-errors` in your test environments, to ensure your library compiles without warnings even if optional dependencies are missing. See `mix deps` for all available options.\n\nKeep in mind your library's [lockfile](`Mix.Project#module-configuration`) (usually named `mix.lock`) is _ignored by the host project_. Running `mix deps.get` in the host project attempts to get the latest possible versions of your library’s dependencies, as specified by the requirements in the `deps` section of your `mix.exs`. These versions might be greater than those stored in your `mix.lock` (and hence used in your tests / CI).\n\nOn the other hand, contributors of your library, need a deterministic build, which implies the presence of `mix.lock` in your Version Control System (VCS), such as `git`.\n\nIf you want to validate both scenarios, you should check the `mix.lock` into version control and run two different Continuous Integration (CI) workflows: one that relies on the `mix.lock` for deterministic builds, and another one, that starts with `mix deps.unlock --all` and always compiles your library and runs tests against latest versions of dependencies. The latter one might be even run nightly or otherwise recurrently to stay notified about any possible issue in regard to dependencies updates.\n\n### Dependency Version Requirements\n\nWhen depending on other libraries, the dependency version requirements are ultimately up to you. However, you should consider the effects that an overly strict dependency requirement can have on users of your library. Most dependencies adopt [Semantic Versioning](https://semver.org/), and therefore provide reasonable guarantees about what each release contains. For instance, if you use `{:some_dep, “== 0.2.3”}`, this prevents users from using any other version but the one that you specified, which means that they cannot receive bug fix upgrades to that package. When in doubt, use a dependency in the format of `\"~> x.y\"`. This prevents the user from using a higher major version of the library, but allows them to upgrade to newer minor and patch versions, which should only include bug fixes and non-breaking improvements.\n\nThe exception to this is pre 1.0 libraries using [Semantic Versioning](https://semver.org/), which provide [no guarantees](https://semver.org/spec/v2.0.0.html#spec-item-4) about what might change from one version to the next. In this scenario, depending on the full patch version, i.e `\"~> 0.1.2\"` is a better default.\n\nA common mistake is to use a dependency in the format of `\"~> x.y.z\"` to express \"a version greater than `x.y.z`\". For example, if you are depending on `\"~> 1.2\"`, and the dependency publishes a fix in version `1.2.1` that you need for the next version of your library. If you use `\"~> 1.2.1\"` to express that dependency, you are preventing users from upgrading to `\"1.3.0\"` or higher! Instead of `\"~> 1.2.1\"`, you should use `\"~> 1.2 and >= 1.2.1\"` as the version requirement. This allows users to use any version less than `2.0`, and greater than `1.2.1`.\n"
  },
  {
    "path": "lib/elixir/pages/references/naming-conventions.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Naming conventions\n\nThis document is a reference of the naming conventions in Elixir, from casing to punctuation characters.\n\nThe naming convention is, by definition, a subset of the Elixir syntax. A convention aims to\nfollow and set best practices for language and the community. If instead you want a complete reference into the Elixir syntax, beyond its conventions, see [the Syntax reference](syntax-reference.md).\n\n## Casing\n\nElixir developers must use `snake_case` when defining variables, function names, module attributes, and the like:\n\n    some_map = %{this_is_a_key: \"and a value\"}\n    is_map(some_map)\n\nAliases, commonly used as module names, are an exception as they must be capitalized and written in `CamelCase`, like `OptionParser`. For aliases, capital letters are kept in acronyms, like `ExUnit.CaptureIO` or `Mix.SCM`.\n\nAtoms can be written either in `:snake_case` or `:CamelCase`, although the convention is to use the snake case version throughout Elixir.\n\nGenerally speaking, filenames follow the `snake_case` convention of the module they define. For example, `MyApp` should be defined inside the `my_app.ex` file. However, this is only a convention. At the end of the day any filename can be used as they do not affect the compiled code in any way.\n\n## Underscore (`_foo`)\n\nElixir relies on underscores in different situations.\n\nFor example, a value that is not meant to be used must be assigned to `_` or to a variable starting with underscore:\n\n    iex> {:ok, _contents} = File.read(\"README.md\")\n\nFunction names may also start with an underscore. Such functions are never imported by default:\n\n    iex> defmodule Example do\n    ...>   def _wont_be_imported do\n    ...>     :oops\n    ...>   end\n    ...> end\n\n    iex> import Example\n    iex> _wont_be_imported()\n    ** (CompileError) iex:1: undefined function _wont_be_imported/0\n\nDue to this property, Elixir relies on functions starting with underscore to attach compile-time metadata to modules. Such functions are most often in the `__foo__` format. For example, every module in Elixir has an [`__info__/1`](`c:Module.__info__/1`) function:\n\n    iex> String.__info__(:functions)\n    [at: 2, capitalize: 1, chunk: 2, ...]\n\nElixir also includes five special forms that follow the double underscore format: `__CALLER__/0`, `__DIR__/0`, `__ENV__/0`and `__MODULE__/0` retrieve compile-time information about the current environment, while `__STACKTRACE__/0` retrieves the stacktrace for the current exception.\n\n## Trailing bang (`foo!`)\n\nA trailing bang (exclamation mark) signifies a function or macro where failure cases raise an exception. They most often exist as a \"raising variant\" of a function that returns `:ok`/`:error` tuples (or `nil`).\n\nOne example is `File.read/1` and `File.read!/1`. `File.read/1` will return a success or failure tuple, whereas `File.read!/1` will return a plain value or else raise an exception:\n\n    iex> File.read(\"file.txt\")\n    {:ok, \"file contents\"}\n    iex> File.read(\"no_such_file.txt\")\n    {:error, :enoent}\n\n    iex> File.read!(\"file.txt\")\n    \"file contents\"\n    iex> File.read!(\"no_such_file.txt\")\n    ** (File.Error) could not read file no_such_file.txt: no such file or directory\n\nThe version without `!` is preferred when you want to handle different outcomes using pattern matching:\n\n    case File.read(file) do\n      {:ok, body} -> # do something with the `body`\n      {:error, reason} -> # handle the error caused by `reason`\n    end\n\nHowever, if you expect the outcome to always be successful (for instance, if you expect the file always to exist), the bang variation can be more convenient and will raise a more helpful error message (than a failed pattern match) on failure.\n\nWhen thinking about failure cases, we are often thinking about semantic errors related to the operation being performed, such as failing to open a file or trying to fetch key from a map. Errors that come from invalid argument types, or similar, must always raise regardless if the function has a bang or not. In such cases, the exception is often an `ArgumentError` or a detailed `FunctionClauseError`:\n\n    iex(1)> File.read(123)\n    ** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1\n\n        The following arguments were given to IO.chardata_to_string/1:\n\n            # 1\n            123\n\n        Attempted function clauses (showing 2 out of 2):\n\n            def chardata_to_string(string) when is_binary(string)\n            def chardata_to_string(list) when is_list(list)\n\nMore examples of paired functions: `Base.decode16/2` and `Base.decode16!/2`, `File.cwd/0` and `File.cwd!/0`. In some situations, you may have bang functions without a non-bang counterpart. They also imply the possibility of errors, such as: `Protocol.assert_protocol!/1` and `PartitionSupervisor.resize!/2`. This can be useful if you foresee the possibility of adding a non-raising variant in the future.\n\n## Trailing question mark (`foo?`)\n\nFunctions that return a boolean are named with a trailing question mark.\n\nExamples: `Keyword.keyword?/1`, `Mix.debug?/0`, `String.contains?/2`\n\nHowever, functions that return booleans and are valid in guards follow another convention, described next.\n\n## `is_` prefix (`is_foo`)\n\nType checks and other boolean checks that are allowed in guard clauses are named with an `is_` prefix.\n\nExamples: `Integer.is_even/1`, `is_list/1`\n\nThese functions and macros follow the Erlang convention of an `is_` prefix, instead of a trailing question mark, precisely to indicate that they are allowed in guard clauses. Type checks that are not valid in guard clauses do not follow this convention, such as `Keyword.keyword?/1`.\n\nA trailing question mark should not be used in combination with the `is_` prefix.\n\n## Special names\n\nSome names have specific meaning in Elixir. We detail those cases below.\n\n### length and size\n\nWhen you see `size` in a function name, it means the operation runs in constant time (also written as \"O(1) time\") because the size is stored alongside the data structure.\n\nExamples: `map_size/1`, `tuple_size/1`\n\nWhen you see `length`, the operation runs in linear time (\"O(n) time\") because the entire data structure has to be traversed.\n\nExamples: `length/1`, `String.length/1`\n\nIn other words, functions using the word \"size\" in its name will take the same amount of time whether the data structure is tiny or huge. Conversely, functions having \"length\" in its name will take more time as the data structure grows in size.\n\n### get, fetch, fetch!\n\nWhen you see the functions `get`, `fetch`, and `fetch!` for key-value data structures, you can expect the following behaviours:\n\n  * `get` returns a default value (which itself defaults to `nil`) if the key is not present, or returns the requested value.\n  * `fetch` returns `:error` if the key is not present, or returns `{:ok, value}` if it is.\n  * `fetch!` *raises* if the key is not present, or returns the requested value.\n\nExamples: `Map.get/2`, `Map.fetch/2`, `Map.fetch!/2`, `Keyword.get/2`, `Keyword.fetch/2`, `Keyword.fetch!/2`\n\n### compare\n\nThe function `compare/2` should return `:lt` if the first term is less than the second, `:eq` if the two\nterms compare as equivalent, or `:gt` if the first term is greater than the second.\n\nExamples: `DateTime.compare/2`\n\nNote that this specific convention is important due to the expectations of `Enum.sort/2`\n"
  },
  {
    "path": "lib/elixir/pages/references/operators.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Operators reference\n\nThis document is a complete reference of operators in Elixir, how they are parsed, how they can be defined, and how they can be overridden.\n\n## General operators\n\nElixir provides the following built-in operators:\n\n  * [`+`](`+/1`) and [`-`](`-/1`) - unary positive/negative\n  * [`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), and [`/`](`//2`) - basic arithmetic operations\n  * [`++`](`++/2`) and [`--`](`--/2`) - list concatenation and subtraction\n  * [`and`](`and/2`) and [`&&`](`&&/2`) - strict and relaxed boolean \"and\"\n  * [`or`](`or/2`) and [`||`](`||/2`) - strict and relaxed boolean \"or\"\n  * [`not`](`not/1`) and [`!`](`!/1`) - strict and relaxed boolean \"not\"\n  * [`in`](`in/2`) and [`not in`](`in/2`) - membership\n  * [`@`](`@/1`) - module attribute\n  * [`..`](`../0`), [`..`](`../2`), and [`..//`](`..///3`) - range creation\n  * [`<>`](`<>/2`) - binary concatenation\n  * [`|>`](`|>/2`) - pipeline\n  * [`=~`](`=~/2`) - text-based match\n\nMany of those can be used in guards. Consult the [list of allowed guard functions and operators](patterns-and-guards.md#list-of-allowed-functions-and-operators).\n\nAdditionally, there are a few other operators that Elixir parses but doesn't actually use.\nSee [Custom and overridden operators](#custom-and-overridden-operators) below for a list and for guidelines about their use.\n\nSome other operators are special forms and cannot be overridden:\n\n  * [`^`](`^/1`) - pin operator\n  * [`.`](`./2`) - dot operator\n  * [`=`](`=/2`) - match operator\n  * [`&`](`&/1`) - capture operator\n  * [`::`](`::/2`) - type operator\n\nFinally, these operators appear in the precedence table below but are only meaningful within certain constructs:\n\n  * `=>` - see [`%{}`](`%{}/1`)\n  * `when` - see [Guards](patterns-and-guards.md#guards)\n  * `<-` - see [`for`](`for/1`) and [`with`](`with/1`)\n  * `\\\\` - see [Default arguments](`Kernel#def/2-default-arguments`)\n\n## Comparison operators\n\nElixir provides the following built-in comparison operators (all of which can be used in guards):\n\n  * [`==`](`==/2`) - equal to\n  * [`===`](`===/2`) - strictly equal to\n  * [`!=`](`!=/2`) - not equal to\n  * [`!==`](`!==/2`) - strictly not equal to\n  * [`<`](`</2`) - less-than\n  * [`>`](`>/2`) - greater-than\n  * [`<=`](`<=/2`) - less-than or equal to\n  * [`>=`](`>=/2`) - greater-than or equal to\n\nThe only difference between [`==`](`==/2`) and [`===`](`===/2`) is that [`===`](`===/2`) is strict when it comes to comparing integers and floats:\n\n```elixir\niex> 1 == 1.0\ntrue\niex> 1 === 1.0\nfalse\n```\n\n[`!=`](`!=/2`) and [`!==`](`!==/2`) act as the negation of [`==`](`==/2`) and [`===`](`===/2`), respectively.\n\n## Operator precedence and associativity\n\nThe following is a list of all operators that Elixir is capable of parsing, ordered from higher to lower precedence, alongside their associativity:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`@`                                            | Unary\n`.`                                            | Left\n`+` `-` `!` `^` `not`                          | Unary\n`**`                                           | Left\n`*` `/`                                        | Left\n`+` `-`                                        | Left\n`++` `--` `+++` `---` `..` `<>`                | Right\n`//` (valid only inside `..//`)                | Right\n`in` `not in`                                  | Left\n`\\|>` `<<<` `>>>` `<<~` `~>>` `<~` `~>` `<~>`  | Left\n`<` `>` `<=` `>=`                              | Left\n`==` `!=` `=~` `===` `!==`                     | Left\n`&&` `&&&` `and`                               | Left\n`\\|\\|` `\\|\\|\\|` `or`                           | Left\n`=`                                            | Right\n`&`, `...`                                     | Unary\n`\\|`                                           | Right\n`::`                                           | Right\n`when`                                         | Right\n`<-` `\\\\`                                      | Left\n`=>` (valid only inside `%{}`)                 | None\n\nElixir also has two ternary operators:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`first..last//step`                            | Right\n`%{map \\| key => value, ...}`                  | None\n\n> #### Deprecated operator precedence {: .info}\n>\n> Elixir parses `not left in right` as `not(left in right)` and `!left in right` as `!(left in right)`, which mismatches the precedence table above, but such behaviour is deprecated and emits a warning. Both constructs must be written as `left not in right` instead. In future major versions, the parser will match the table above.\n\n## Custom and overridden operators\n\nElixir is capable of parsing a predefined set of operators. It's not possible to define new operators (as supported by some languages). However, not all operators that Elixir can parse are *used* by Elixir: for example, `+` and `||` are used by Elixir for addition and boolean *or*, but `<~>` is not used (but valid).\n\nTo define an operator, you can use the usual `def*` constructs (`def`, `defp`, `defmacro`, and so on) but with a syntax similar to how the operator is used:\n\n```elixir\ndefmodule MyOperators do\n  # We define ~> to return the maximum of the given two numbers,\n  # and <~ to return the minimum.\n\n  def a ~> b, do: max(a, b)\n  def a <~ b, do: min(a, b)\nend\n```\n\nTo use the newly defined operators, you **have to** import the module that defines them:\n\n```elixir\niex> import MyOperators\niex> 1 ~> 2\n2\niex> 1 <~ 2\n1\n```\n\nThe following is a table of all the operators that Elixir is capable of parsing, but that are not used by default:\n\n  * `|||`\n  * `&&&`\n  * `<<<`\n  * `>>>`\n  * `<<~`\n  * `~>>`\n  * `<~`\n  * `~>`\n  * `<~>`\n  * `+++`\n  * `---`\n  * `...`\n\nThe following operators are used by the `Bitwise` module when imported: [`&&&`](`Bitwise.&&&/2`), [`<<<`](`Bitwise.<<</2`), [`>>>`](`Bitwise.>>>/2`), and [`|||`](`Bitwise.|||/2`). See the `Bitwise` documentation for more information.\n\nNote that the Elixir community generally discourages custom operators. They can be hard to read and even more to understand, as they don't have a descriptive name like functions do. That said, some specific cases or custom domain specific languages (DSLs) may justify these practices.\n\nIt is also possible to replace predefined operators, such as `+`, but doing so is extremely discouraged.\n"
  },
  {
    "path": "lib/elixir/pages/references/patterns-and-guards.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Patterns and guards\n\nElixir provides pattern matching, which allows us to assert on the shape or extract values from data structures. Patterns are often augmented with guards, which give developers the ability to perform more complex checks, albeit limited.\n\nThis document provides a complete reference on patterns and guards, their semantics, where they are allowed, and how to extend them.\n\n## Patterns\n\nPatterns in Elixir are made of variables, literals, and data structure specific syntax. One of the most used constructs to perform pattern matching is the match operator ([`=`](`=/2`)):\n\n```iex\niex> x = 1\n1\niex> 1 = x\n1\n```\n\nIn the example above, `x` starts without a value and has `1` assigned to it. Then, we compare the value of `x` to the literal `1`, which succeeds as they are both `1`.\n\nMatching `x` against 2 would raise:\n\n```iex\niex> 2 = x\n** (MatchError) no match of right hand side value: 1\n```\n\nPatterns are not bidirectional. If you have a variable `y` that was never assigned to (often called an unbound variable) and you write `1 = y`, an error will be raised:\n\n```iex\niex> 1 = y\n** (CompileError) iex:2: undefined variable \"y\"\n```\n\nIn other words, patterns are allowed only on the left side of `=`. The right side of `=` follows the regular evaluation semantics of the language.\n\nNow let's cover the pattern matching rules for each construct and then for each relevant data types.\n\n### Variables\n\nVariables in patterns are always assigned to:\n\n```iex\niex> x = 1\n1\niex> x = 2\n2\niex> x\n2\n```\n\nIn other words, Elixir supports rebinding. In case you don't want the value of a variable to change, you can use the pin operator (`^`):\n\n```iex\niex> x = 1\n1\niex> ^x = 2\n** (MatchError) no match of right hand side value: 2\n```\n\nIf the same variable appears multiple times in the same pattern, then all of them must be bound to the same value:\n\n```iex\niex> {x, x} = {1, 1}\n{1, 1}\niex> {x, x} = {1, 2}\n** (MatchError) no match of right hand side value: {1, 2}\n```\n\nThe underscore variable (`_`) has a special meaning as it can never be bound to any value. It is especially useful when you don't care about certain value in a pattern:\n\n```iex\niex> {_, integer} = {:not_important, 1}\n{:not_important, 1}\niex> integer\n1\niex> _\n** (CompileError) iex:3: invalid use of _\n```\n\nA pinned value represents the value itself and not its – even if syntactically equal – pattern. The right hand side is compared to be equal to the pinned value:\n\n```iex\niex> x = %{}\n%{}\niex> {:ok, %{}} = {:ok, %{a: 13}}\n{:ok, %{a: 13}}\niex> {:ok, ^x} = {:ok, %{a: 13}}\n** (MatchError) no match of right hand side value: {:ok, %{a: 13}}\n    (stdlib 6.2) erl_eval.erl:667: :erl_eval.expr/6\n    iex:2: (file)\n```\n\n### Literals (numbers and atoms)\n\nAtoms and numbers (integers and floats) can appear in patterns and they are always represented as is. For example, an atom will only match an atom if they are the same atom:\n\n```iex\niex> :atom = :atom\n:atom\niex> :atom = :another_atom\n** (MatchError) no match of right hand side value: :another_atom\n```\n\nSimilar rule applies to numbers. Finally, note that numbers in patterns perform strict comparison. In other words, integers to do not match floats:\n\n```iex\niex> 1 = 1.0\n** (MatchError) no match of right hand side value: 1.0\n```\n\n### Tuples\n\nTuples may appear in patterns using the curly brackets syntax (`{}`). A tuple in a pattern will match only tuples of the same size, where each individual tuple element must also match:\n\n```iex\niex> {:ok, integer} = {:ok, 13}\n{:ok, 13}\n\n# won't match due to different size\niex> {:ok, integer} = {:ok, 11, 13}\n** (MatchError) no match of right hand side value: {:ok, 11, 13}\n\n# won't match due to mismatch on first element\niex> {:ok, binary} = {:error, :enoent}\n** (MatchError) no match of right hand side value: {:error, :enoent}\n```\n\n### Lists\n\nLists may appear in patterns using the square brackets syntax (`[]`). A list in a pattern will match only lists of the same size, where each individual list element must also match:\n\n```iex\niex> [:ok, integer] = [:ok, 13]\n[:ok, 13]\n\n# won't match due to different size\niex> [:ok, integer] = [:ok, 11, 13]\n** (MatchError) no match of right hand side value: [:ok, 11, 13]\n\n# won't match due to mismatch on first element\niex> [:ok, binary] = [:error, :enoent]\n** (MatchError) no match of right hand side value: [:error, :enoent]\n```\n\nOpposite to tuples, lists also allow matching on non-empty lists by using the `[head | tail]` notation, which matches on the `head` and `tail` of a list:\n\n```iex\niex> [head | tail] = [1, 2, 3]\n[1, 2, 3]\niex> head\n1\niex> tail\n[2, 3]\n```\n\nMultiple elements may prefix the `| tail` construct:\n\n```iex\niex> [first, second | tail] = [1, 2, 3]\n[1, 2, 3]\niex> tail\n[3]\n```\n\nNote `[head | tail]` does not match empty lists:\n\n```elixir\niex> [head | tail] = []\n** (MatchError) no match of right hand side value: []\n```\n\nGiven charlists are represented as a list of integers, one can also perform prefix matches on charlists using the list concatenation operator ([`++`](`++/2`)):\n\n```elixir\niex> ~c\"hello \" ++ world = ~c\"hello world\"\n~c\"hello world\"\niex> world\n~c\"world\"\n```\n\nWhich is equivalent to matching on `[?h, ?e, ?l, ?l, ?o, ?\\s | world]`. Suffix matches (`hello ++ ~c\" world\"`) are not valid patterns.\n\n### Maps\n\nMaps may appear in patterns using the percentage sign followed by the curly brackets syntax (`%{}`). Opposite to lists and tuples, maps perform a subset match. This means a map pattern will match any other map that has at least all of the keys in the pattern.\n\nHere is an example where all keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\"}\n%{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nHere is when a subset of the keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\", age: 23}\n%{age: 23, name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf a key in the pattern is not available in the map, then they won't match:\n\n```iex\niex> %{name: name, age: age} = %{name: \"meg\"}\n** (MatchError) no match of right hand side value: %{name: \"meg\"}\n```\n\nNote that the empty map will match all maps, which is a contrast to tuples and lists, where an empty tuple or an empty list will only match empty tuples and empty lists respectively:\n\n```iex\niex> %{} = %{name: \"meg\"}\n%{name: \"meg\"}\n```\n\nFinally, note map keys in patterns must always be literals or previously bound variables matched with the pin operator.\n\n### Structs\n\nStructs may appear in patterns using the percentage sign, the struct module name or a variable followed by the curly brackets syntax (`%{}`).\n\nGiven the following struct:\n\n```elixir\ndefmodule User do\n  defstruct [:name]\nend\n```\n\nHere is an example where all keys match:\n\n```iex\niex> %User{name: name} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf an unknown key is given, the compiler will raise an error:\n\n```iex\niex> %User{type: type} = %User{name: \"meg\"}\n** (CompileError) iex: unknown key :type for struct User\n```\n\nThe struct name can be extracted when putting a variable instead of a module name:\n\n```elixir\niex> %struct_name{} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> struct_name\nUser\n```\n\n### Binaries\n\nBinaries may appear in patterns using the double less-than/greater-than syntax ([`<<>>`](`<<>>/1`)). A binary in a pattern can match multiple segments at the same time, each with different type, size, and unit:\n\n```iex\niex> <<val::unit(8)-size(2)-integer>> = <<123, 56>>\n\"{8\"\niex> val\n31544\n```\n\nSee the documentation for [`<<>>`](`<<>>/1`) for a complete definition of pattern matching for binaries.\n\nFinally, remember that strings in Elixir are UTF-8 encoded binaries. This means that, similar to charlists, prefix matches on strings are also possible with the binary concatenation operator ([`<>`](`<>/2`)):\n\n```elixir\niex> \"hello \" <> world = \"hello world\"\n\"hello world\"\niex> world\n\"world\"\n```\n\nSuffix matches (`hello <> \" world\"`) are not valid patterns.\n\n## Guards\n\nGuards are a way to augment pattern matching with more complex checks. They are allowed in a predefined set of constructs where pattern matching is allowed, such as function definitions, case clauses, and others.\n\nNot all expressions are allowed in guard clauses, but only a handful of them. This is a deliberate choice. This way, Elixir (through Erlang) ensures that all guards are predictable (no mutations or other side-effects) and they can be optimized and performed efficiently.\n\n### List of allowed functions and operators\n\nYou can find the built-in list of guards [in the `Kernel` module](`Kernel#guards`). Here is an overview:\n\n  * comparison operators ([`==`](`==/2`), [`!=`](`!=/2`), [`===`](`===/2`), [`!==`](`!==/2`),\n    [`<`](`</2`), [`<=`](`<=/2`), [`>`](`>/2`), [`>=`](`>=/2`)), [`max`](`max/2`), [`min`](`min/2`)\n  * strictly boolean operators ([`and`](`and/2`), [`or`](`or/2`), [`not`](`not/1`)). Note [`&&`](`&&/2`), [`||`](`||/2`), and [`!`](`!/1`) sibling operators are **not allowed** as they're not *strictly* boolean - meaning they don't require arguments to be booleans\n  * arithmetic unary operators ([`+`](`+/1`), [`-`](`-/1`))\n  * arithmetic binary operators ([`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), [`/`](`//2`))\n  * [`in`](`in/2`) and [`not in`](`in/2`) operators (as long as the right-hand side is a list or a range)\n  * \"type-check\" functions (`is_list/1`, `is_number/1`, and the like)\n  * functions that work on built-in data types (`abs/1`, `hd/1`, `map_size/1`, and others)\n  * the `map.field` syntax\n\nThe module `Bitwise` also includes a handful of [Erlang bitwise operations as guards](Bitwise.html#guards).\n\nMacros constructed out of any combination of the above guards are also valid guards - for example, `Integer.is_even/1`. For more information, see the \"Custom patterns and guards expressions\" section shown below.\n\n### Why guards\n\nLet's see an example of a guard used in a function clause:\n\n```elixir\ndef empty_map?(map) when map_size(map) == 0, do: true\ndef empty_map?(map) when is_map(map), do: false\n```\n\nGuards start with the `when` operator, followed by a guard expression. The clause will be executed if and only if the guard expression returns `true`. Multiple boolean conditions can be combined with the [`and`](`and/2`) and [`or`](`or/2`) operators.\n\nWriting the `empty_map?/1` function by only using pattern matching would not be possible (as pattern matching on `%{}` would match *any* map, not only the empty ones).\n\n### Non-passing guards\n\nA function clause will be executed if and only if its guard expression evaluates to `true`. If any other value is returned, the function clause will be skipped. In particular, guards have no concept of \"truthy\" or \"falsy\".\n\nFor example, imagine a function that checks that the head of a list is not `nil`:\n\n```elixir\ndef not_nil_head?([head | _]) when head, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> false\n```\n\nEven though the head of the list is not `nil`, the first clause for `not_nil_head?/1` fails because the expression does not evaluate to `true`, but to `\"some_value\"`, therefore triggering the second clause which returns `false`. To make the guard behave correctly, you must ensure that the guard evaluates to `true`, like so:\n\n```elixir\ndef not_nil_head?([head | _]) when head != nil, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> true\n```\n\n### Errors in guards\n\nIn guards, when functions would normally raise exceptions, they cause the guard to fail instead.\n\nFor example, the `tuple_size/1` function only works with tuples. If we use it with anything else, an argument error is raised:\n\n```elixir\niex> tuple_size(\"hello\")\n** (ArgumentError) argument error\n```\n\nHowever, when used in guards, the corresponding clause will fail to match instead of raising an error:\n\n```elixir\niex> case \"hello\" do\n...>   something when tuple_size(something) == 2 ->\n...>     :worked\n...>   _anything_else ->\n...>     :failed\n...> end\n:failed\n```\n\nIn many cases, we can take advantage of this. In the code above, we used `tuple_size/1` to both check that the given value is a tuple *and* check its size (instead of using `is_tuple(something) and tuple_size(something) == 2`).\n\nHowever, if your guard has multiple conditions, such as checking for tuples or maps, it is best to call type-check functions like `is_tuple/1` before `tuple_size/1`, otherwise the whole guard will fail if a tuple is not given. Alternatively, your function clause can use multiple guards as shown in the following section.\n\n### Multiple guards in the same clause\n\nThere exists an additional way to simplify a chain of `or` expressions in guards: Elixir supports writing \"multiple guards\" in the same clause. The following code:\n\n```elixir\ndef categorize_number(term) when is_integer(term) or is_float(term) or is_nil(term),\n  do: :maybe_number\ndef categorize_number(_other),\n  do: :something_else\n```\n\ncan be alternatively written as:\n\n```elixir\ndef categorize_number(term)\n    when is_integer(term)\n    when is_float(term)\n    when is_nil(term) do\n  :maybe_number\nend\n\ndef categorize_number(_other) do\n  :something_else\nend\n```\n\nIf each guard expression always returns a boolean, the two forms are equivalent. However, recall that if any function call in a guard raises an exception, the entire guard fails. To illustrate this, the following function will not detect empty tuples:\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and tuple_size/1 will not be evaluated\n  def empty?(val) when map_size(val) == 0 or tuple_size(val) == 0, do: true\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> false # true was expected!\n```\n\nThis could be corrected by ensuring that no exception is raised, either via type checks like `is_map(val) and map_size(val) == 0`, or by using multiple guards, so that if an exception causes one guard to fail, the next one is evaluated.\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and the second guard will be evaluated\n  def empty?(val)\n      when map_size(val) == 0\n      when tuple_size(val) == 0,\n      do: true\n\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> true\n```\n\n## Where patterns and guards can be used\n\nIn the examples above, we have used the match operator ([`=`](`=/2`)) and function clauses to showcase patterns and guards respectively. Here is the list of the built-in constructs in Elixir that support patterns and guards.\n\n  * `match?/2`:\n\n    ```elixir\n    match?({:ok, value} when value > 0, {:ok, 13})\n    ```\n\n  * function clauses:\n\n    ```elixir\n    def type(term) when is_integer(term), do: :integer\n    def type(term) when is_float(term), do: :float\n    ```\n\n  * [`case`](`case/2`) expressions:\n\n    ```elixir\n    case x do\n      1 -> :one\n      2 -> :two\n      n when is_integer(n) and n > 2 -> :larger_than_two\n    end\n    ```\n\n  * anonymous functions (`fn/1`):\n\n    ```elixir\n    larger_than_two? = fn\n      n when is_integer(n) and n > 2 -> true\n      n when is_integer(n) -> false\n    end\n    ```\n\n  * [`for`](`for/1`) and [`with`](`with/1`) support patterns and guards on the left side of `<-`:\n\n    ```elixir\n    for x when x >= 0 <- [1, -2, 3, -4], do: x\n    ```\n\n    `with` also supports the `else` keyword, which supports patterns matching and guards.\n\n  * [`try`](`try/1`) supports patterns and guards on `catch` and `else`\n\n  * [`receive`](`receive/1`) supports patterns and guards to match on the received messages.\n\n  * custom guards can also be defined with `defguard/1` and `defguardp/1`. A custom guard can only be defined based on existing guards.\n\nNote that the match operator ([`=`](`=/2`)) does *not* support guards:\n\n```elixir\n{:ok, binary} = File.read(\"some/file\")\n```\n\n## Custom patterns and guards expressions\n\nOnly the constructs listed in this page are allowed in patterns and guards. However, we can take advantage of macros to write custom patterns guards that can simplify our programs or make them more domain-specific. At the end of the day, what matters is that the *output* of the macros boils down to a combination of the constructs above.\n\nFor example, the `Record` module in Elixir provides a series of macros to be used in patterns and guards that allows tuples to have named fields during compilation.\n\nFor defining your own guards, Elixir even provides conveniences in `defguard` and `defguardp`. Let's look at a quick case study: we want to check whether an argument is an even or an odd integer. With pattern matching this is impossible because there is an infinite number of integers, and therefore we can't pattern match on every single one of them. Therefore we must use guards. We will just focus on checking for even numbers since checking for the odd ones is almost identical.\n\nSuch a guard would look like this:\n\n```elixir\ndef my_function(number) when is_integer(number) and rem(number, 2) == 0 do\n  # do stuff\nend\n```\n\nIt would be repetitive to write every time we need this check. Instead, you can use `defguard/1` and `defguardp/1` to create guard macros. Here's an example how:\n\n```elixir\ndefmodule MyInteger do\n  defguard is_even(term) when is_integer(term) and rem(term, 2) == 0\nend\n```\n\nand then:\n\n```elixir\nimport MyInteger, only: [is_even: 1]\n\ndef my_function(number) when is_even(number) do\n  # do stuff\nend\n```\n\nWhile it's possible to create custom guards with macros, it's recommended to define them using `defguard/1` and `defguardp/1` which perform additional compile-time checks.\n"
  },
  {
    "path": "lib/elixir/pages/references/sbom.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Software Bill of Materials\n\nA Software Bill of Materials (SBoM) is a structured inventory of the components that make up a software system. This guide explains what SBoMs are, why they matter, and how to generate them for Elixir projects.\n\n## What is an SBoM?\n\nAn SBoM is a formal, machine-readable record of all components in a piece of software. Think of it as a detailed ingredient list for your application. A typical SBoM includes:\n\n  * **Dependencies**: all libraries and packages your project uses\n  * **Versions**: the exact version of each component\n  * **Source locations**: where each component was obtained (Hex, GitHub, etc.)\n  * **Checksums**: cryptographic hashes to verify integrity\n  * **Licensing information**: the license under which each component is distributed\n\nTwo widely adopted standards exist for SBoM formats:\n\n  * [CycloneDX](https://cyclonedx.org/): a lightweight standard designed for security contexts\n  * [SPDX](https://spdx.dev/): a more comprehensive standard originally focused on licensing\n\nBoth formats are machine-readable (JSON, XML) and designed to be consumed by automated tooling.\n\n> #### SBoM is an inventory, not a certification {: .info}\n>\n> An SBoM does not claim that software is secure, compliant, or free of vulnerabilities.\n> It simply provides a detailed inventory that enables further analysis. Security and\n> compliance assessments are performed by separate tools that consume the SBoM.\n\n## Why generate SBoMs?\n\nThere are three main reasons to generate SBoMs for your projects.\n\n### Vulnerability analysis\n\nWhen a security vulnerability (CVE) is discovered in a library, you need to quickly determine if your projects are affected. SBoMs make this possible by providing a complete inventory of your dependencies.\n\nTools like [OWASP Dependency-Track](https://dependencytrack.org/) continuously monitor your SBoMs against vulnerability databases. When a new CVE is published, you get notified if any of your projects use the affected component.\n\nWithout an SBoM, answering \"are we affected by CVE-2024-XXXXX?\" means manually checking each project, which is time-consuming and error-prone.\n\n### Regulatory requirements\n\nSBoMs are required by some regulations and procurement policies:\n\n  * **US Executive Order 14028** (2021) requires SBoMs for certain software supplied to the U.S. federal government, particularly for designated critical software\n  * **EU Cyber Resilience Act** introduces requirements for component inventories (commonly fulfilled using SBoMs) for products with digital elements placed on the EU market\n  * **Safety-critical industries** (medical devices, automotive, aerospace) often require detailed component inventories as part of certification\n\nCustomers and partners may also request SBoMs as part of their own compliance efforts.\n\n### License compliance\n\nEvery dependency in your project comes with a license. An SBoM provides a starting point for license review by listing the declared license for each package. This helps you:\n\n  * Get an overview of licenses in your dependency tree\n  * Flag packages that may need closer review\n  * Support due diligence for acquisitions, audits, or legal review\n\nNote that package-level license information (as provided by mix_sbom) reflects what the package declares, not necessarily all licenses present in its source files. For thorough license compliance, file-level scanning tools like ORT provide deeper analysis.\n\n## Generating SBoMs with mix_sbom\n\n[mix_sbom](https://github.com/erlef/mix_sbom) is an EEF project that generates CycloneDX SBoMs for Elixir projects.\n\n### Installation\n\nThere are several ways to install mix_sbom:\n\n  * **As a project dependency**: add `sbom` to your `mix.exs`\n  * **As a global escript**: run `mix escript.install hex sbom` (requires Elixir 1.19.4+)\n  * **As a standalone binary**: download from the [releases page](https://github.com/erlef/mix_sbom/releases)\n\nThe standalone binary is useful for CI environments or when you don't want to modify your project's dependencies. It requires no local Elixir or Erlang installation.\n\n### Basic usage\n\nTo generate an SBoM for your project using the standalone binary:\n\n```console\n$ mix_sbom cyclonedx /path/to/your/project\n```\n\nThis creates a `bom.cdx.json` file in CycloneDX format containing your project's complete dependency tree.\n\n### Common options\n\nThe most useful options are:\n\n  * `-o, --output PATH`: specify the output file (default: `bom.cdx.json`)\n  * `-t, --format FORMAT`: output format (`json`, `xml`, or `protobuf`)\n  * `-s, --schema VERSION`: CycloneDX schema version\n\nFor example, to generate an XML format SBoM:\n\n```console\n$ mix_sbom cyclonedx --format xml --output sbom.xml /path/to/project\n```\n\n## CI integration\n\nFor automated SBoM generation, mix_sbom provides a GitHub Action:\n\n```yaml\nname: Generate SBoM\non:\n  release:\n    types: [published]\n\njobs:\n  sbom:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: erlef/mix_sbom@v0\n        with:\n          path: \".\"\n          format: \"json\"\n      - uses: actions/upload-artifact@v4\n        with:\n          name: sbom\n          path: bom.cdx.json\n```\n\nThis workflow generates an SBoM whenever you publish a release and uploads it as a build artifact. See the [action's documentation](https://github.com/erlef/mix_sbom) for additional options.\n\n## Deeper analysis with ORT\n\nmix_sbom provides package-level license information based on what each dependency declares. However, some compliance workflows require file-level scanning. A package might declare an MIT license but contain individual files under different licenses, or include vendored code with its own licensing terms.\n\nThe [OSS Review Toolkit (ORT)](https://oss-review-toolkit.org/) addresses this by scanning actual source files for license headers and copyright notices. ORT supports Mix projects and provides:\n\n  * **File-level license detection**: scans source code for license texts and SPDX identifiers\n  * **Copyright holder identification**: extracts copyright notices from files\n  * **Policy enforcement**: define rules for allowed and denied licenses\n  * **Multi-ecosystem support**: analyze projects that span multiple package managers\n\nFor organizations with strict compliance requirements, ORT complements mix_sbom by providing the deeper analysis needed for thorough license audits.\n\nSee the [ORT Mix plugin documentation](https://oss-review-toolkit.org/ort/docs/plugins/package-managers/Mix) for details.\n\n## Next steps\n\n  * [CycloneDX Specification](https://cyclonedx.org/specification/overview/): learn more about the SBoM format\n  * [OWASP Dependency-Track](https://dependencytrack.org/): continuous SBoM analysis platform\n  * [mix_sbom documentation](https://hexdocs.pm/sbom): full documentation and advanced options\n"
  },
  {
    "path": "lib/elixir/pages/references/syntax-reference.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Syntax reference\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). This means the Elixir syntax is mostly uniform with a handful of \"syntax sugar\" constructs to reduce the noise in common Elixir idioms.\n\nThis document covers all of Elixir syntax constructs as a reference and then discuss their exact AST representation.\n\n## Reserved words\n\nThese are the reserved words in the Elixir language. They are detailed throughout this guide but summed up here for convenience:\n\n  * `true`, `false`, `nil` - used as atoms\n  * `when`, `and`, `or`, `not`, `in` - used as operators\n  * `fn` - used for anonymous function definitions\n  * `do`, `end`, `catch`, `rescue`, `after`, `else` - used in do-end blocks\n\n## Data types\n\n### Numbers\n\nIntegers (`1234`) and floats (`123.4`) in Elixir are represented as a sequence of digits that may be separated by underscore for readability purposes, such as `1_000_000`. Integers never contain a dot (`.`) in their representation. Floats contain a dot and at least one other digit after the dot. Floats also support the scientific notation, such as `123.4e10` or `123.4E10`.\n\n### Atoms\n\nUnquoted atoms start with a colon (`:`) which must be immediately followed by a Unicode letter or an underscore. The atom may continue using a sequence of Unicode letters, numbers, underscores, and `@`. Atoms may end in `!` or `?`. Valid unquoted atoms are: `:ok`, `:ISO8601`, and `:integer?`.\n\nIf the colon is immediately followed by a pair of double- or single-quotes surrounding the atom name, the atom is considered quoted. In contrast with an unquoted atom, this one can be made of any Unicode character (not only letters), such as `:'🌢 Elixir'`, `:\"++olá++\"`, and `:\"123\"`.\n\nQuoted and unquoted atoms with the same name are considered equivalent, so `:atom`, `:\"atom\"`, and `:'atom'` represent the same atom. The only catch is that the compiler will warn when quotes are used in atoms that do not need to be quoted.\n\nAll operators in Elixir are also valid atoms. Valid examples are `:foo`, `:FOO`, `:foo_42`, `:foo@bar`, and `:++`. Invalid examples are `:@foo` (`@` is not allowed at start), `:123` (numbers are not allowed at start), and `:(*)` (not a valid operator).\n\n`true`, `false`, and `nil` are reserved words that are represented by the atoms `:true`, `:false` and `:nil` respectively.\n\nTo learn more about all Unicode characters allowed in atom, see the [Unicode syntax](unicode-syntax.md) document.\n\n### Strings\n\nSingle-line strings in Elixir are written between double-quotes, such as `\"foo\"`. Any double-quote inside the string must be escaped with `\\ `. Strings support Unicode characters and are stored as UTF-8 encoded binaries.\n\nMulti-line strings in Elixir are called heredocs. They are written with three double-quotes, and can have unescaped quotes within them. The resulting string will end with a newline. The indentation of the last `\"\"\"` is used to strip indentation from the inner string. For example:\n\n```elixir\niex> test = \"\"\"\n...>     this\n...>     is\n...>     a\n...>     test\n...> \"\"\"\n\"    this\\n    is\\n    a\\n    test\\n\"\niex> test = \"\"\"\n...>     This\n...>     Is\n...>     A\n...>     Test\n...>     \"\"\"\n\"This\\nIs\\nA\\nTest\\n\"\n```\n\nStrings are always represented as themselves in the AST.\n\n### Charlists\n\nCharlists are lists of non-negative integers where each integer represents a Unicode code point.\n\n```elixir\niex(6)> 'abc' === [97, 98, 99]\ntrue\n```\n\nCharlists are written in single-quotes, such as `'foo'`. Any single-quote inside the string must be escaped with `\\ `.\nMulti-line charlists are written with three single-quotes (`'''`), the same way multi-line strings are.\nHowever, this syntax is deprecated in favor of the charlist sigil `~c`.\n\nCharlists are always represented as themselves in the AST.\n\nFor more in-depth information, please read the \"Charlists\" section in the `List` module.\n\n### Lists, tuples and binaries\n\nData structures such as lists, tuples, and binaries are marked respectively by the delimiters `[...]`, `{...}`, and `<<...>>`. Each element is separated by comma. A trailing comma is also allowed, such as in `[1, 2, 3,]`.\n\n### Maps and keyword lists\n\nMaps use the `%{...}` notation and each key-value is given by pairs marked with `=>`, such as `%{\"hello\" => 1, 2 => \"world\"}`.\n\nBoth keyword lists (list of two-element tuples where the first element is an atom) and maps with atom keys support a keyword notation where the colon character `:` is moved to the end of the atom. `%{hello: \"world\"}` is equivalent to `%{:hello => \"world\"}` and `[foo: :bar]` is equivalent to `[{:foo, :bar}]`. We discuss keywords in later sections.\n\n### Structs\n\nStructs built on the map syntax by passing the struct name between `%` and `{`. For example, `%User{...}`.\n\n## Expressions\n\n### Variables\n\nVariables in Elixir must start with an underscore or a Unicode letter that is not in uppercase or titlecase. The variable may continue using a sequence of Unicode letters, numbers, and underscores. Variables may end in `?` or `!`. To learn more about all Unicode characters allowed in variables, see the [Unicode syntax](unicode-syntax.md) document.\n\n[Elixir's naming conventions](naming-conventions.md) recommend variables to be in `snake_case` format.\n\n### Non-qualified calls (local calls)\n\nNon-qualified calls, such as `add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments.\n\nParentheses are required for zero-arity calls (i.e. calls without arguments), to avoid ambiguity with variables. If parentheses are used, they must immediately follow the function name *without spaces*. For example, `add (1, 2)` is a syntax error, since `(1, 2)` is treated as an invalid block which is attempted to be given as a single argument to `add`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Operators\n\nAs many programming languages, Elixir also support operators as non-qualified calls with their precedence and associativity rules. Constructs such as `=`, `when`, `&` and `@` are simply treated as operators. See [the Operators page](operators.md) for a full reference.\n\n### Qualified calls (remote calls)\n\nQualified calls, such as `Math.add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments. Qualified calls also support operators, such as `Kernel.+(1, 2)`. Elixir also allows the function name to be written between double- or single-quotes, allowing any character in between the quotes, such as `Math.\"++add++\"(1, 2)`.\n\nSimilar to non-qualified calls, parentheses have different meaning for zero-arity calls (i.e. calls without arguments). If parentheses are used, such as `mod.fun()`, it means a function call. If parenthesis are skipped, such as `map.field`, it means accessing a field of a map.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Aliases\n\nAliases are constructs that expand to atoms at compile-time. The alias `String` expands to the atom `:\"Elixir.String\"`. Aliases must start with an ASCII uppercase character which may be followed by any ASCII letter, number, or underscore. Non-ASCII characters are not supported in aliases.\n\nMultiple aliases can be joined with `.`, such as `MyApp.String`, and it expands to the atom `:\"Elixir.MyApp.String\"`. The dot is effectively part of the name but it can also be used for composition. If you define `alias MyApp.Example, as: Example` in your code, then `Example` will always expand to `:\"Elixir.MyApp.Example\"` and `Example.String` will expand to `:\"Elixir.MyApp.Example.String\"`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend aliases to be in `CamelCase` format.\n\n### Module attributes\n\nModule attributes are module-specific storage and are written as the composition of the unary operator `@` with variables and local calls. For example, to write to a module attribute named `foo`, use `@foo \"value\"`, and use `@foo` to read from it. Given module attributes are written using existing constructs, they follow the same rules above defined for operators, variables, and local calls.\n\n### Blocks\n\nBlocks are multiple Elixir expressions separated by newlines or semi-colons. A new block may be created at any moment by using parentheses.\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is used to establish a relationship between left and right, commonly referred as clauses. The left side may have zero, one, or more arguments; the right side is zero, one, or more expressions separated by new line. The `->` may appear one or more times between one of the following terminators: `do`-`end`, `fn`-`end` or `(`-`)`. When `->` is used, only other clauses are allowed between those terminators. Mixing clauses and regular expressions is invalid syntax.\n\nIt is seen on `case` and `cond` constructs between `do` and `end`:\n\n```elixir\ncase 1 do\n  2 -> 3\n  4 -> 5\nend\n\ncond do\n  true -> false\nend\n```\n\nSeen in typespecs between `(` and `)`:\n\n```elixir\n(integer(), boolean() -> integer())\n```\n\nIt is also used between `fn` and `end` for building anonymous functions:\n\n```elixir\nfn\n  x, y -> x + y\nend\n```\n\n### Sigils\n\nSigils start with `~` and are followed by one lowercase letter or by one or more uppercase letters, immediately followed by one of the following pairs:\n\n  * `(` and `)`\n  * `{` and `}`\n  * `[` and `]`\n  * `<` and `>`\n  * `\"` and `\"`\n  * `'` and `'`\n  * `|` and `|`\n  * `/` and `/`\n\nAfter closing the pair, zero or more ASCII letters and digits can be given as a modifier. Sigils are expressed as non-qualified calls prefixed with `sigil_` where the first argument is the sigil contents as a string and the second argument is a list of integers as modifiers:\n\nIf the sigil letter is in uppercase, no interpolation is allowed in the sigil, otherwise its contents may be dynamic. Compare the results of the sigils below for more information:\n\n```elixir\n~s/f#{\"o\"}o/\n~S/f#{\"o\"}o/\n```\n\nSigils are useful to encode text with their own escaping rules, such as regular expressions, datetimes, and others.\n\n## The Elixir AST\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). Elixir's AST is a regular Elixir data structure composed of the following elements:\n\n  * atoms - such as `:foo`\n  * integers - such as `42`\n  * floats - such as `13.1`\n  * strings - such as `\"hello\"`\n  * lists - such as `[1, 2, 3]`\n  * tuples with two elements - such as `{\"hello\", :world}`\n  * tuples with three elements, representing calls or variables, as explained next\n\nThe building block of Elixir's AST is a call, such as:\n\n```elixir\nsum(1, 2, 3)\n```\n\nwhich is represented as a tuple with three elements:\n\n```elixir\n{:sum, meta, [1, 2, 3]}\n```\n\nthe first element is an atom (or another tuple), the second element is a list of two-element tuples with metadata (such as line numbers) and the third is a list of arguments.\n\nWe can retrieve the AST for any Elixir expression by calling `quote`:\n\n```elixir\nquote do\n  sum()\nend\n#=> {:sum, [], []}\n```\n\nVariables are also represented using a tuple with three elements and a combination of lists and atoms, for example:\n\n```elixir\nquote do\n  sum\nend\n#=> {:sum, [], Elixir}\n```\n\nYou can see that variables are also represented with a tuple, except the third element is an atom expressing the variable context.\n\nOver the course of this section, we will explore many Elixir syntax constructs alongside their AST representations.\n\n### Operators\n\nOperators are treated as non-qualified calls:\n\n```elixir\nquote do\n  1 + 2\nend\n#=> {:+, [], [1, 2]}\n```\n\nNote that `.` is also an operator. Remote calls use the dot in the AST with two arguments, where the second argument is always an atom:\n\n```elixir\nquote do\n  foo.bar(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}, :bar]}, [], [1, 2, 3]}\n```\n\nCalling anonymous functions uses the dot in the AST with a single argument, mirroring the fact the function name is \"missing\" from right side of the dot:\n\n```elixir\nquote do\n  foo.(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}]}, [], [1, 2, 3]}\n```\n\n### Aliases\n\nAliases are represented by an `__aliases__` call with each segment separated by a dot as an argument:\n\n```elixir\nquote do\n  Foo.Bar.Baz\nend\n#=> {:__aliases__, [], [:Foo, :Bar, :Baz]}\n\nquote do\n  __MODULE__.Bar.Baz\nend\n#=> {:__aliases__, [], [{:__MODULE__, [], Elixir}, :Bar, :Baz]}\n```\n\nAll arguments, except the first, are guaranteed to be atoms.\n\n### Data structures\n\nRemember that lists are literals, so they are represented as themselves in the AST:\n\n```elixir\nquote do\n  [1, 2, 3]\nend\n#=> [1, 2, 3]\n```\n\nTuples have their own representation, except for two-element tuples, which are represented as themselves:\n\n```elixir\nquote do\n  {1, 2}\nend\n#=> {1, 2}\n\nquote do\n  {1, 2, 3}\nend\n#=> {:{}, [], [1, 2, 3]}\n```\n\nBinaries have a representation similar to tuples, except they are tagged with `:<<>>` instead of `:{}`:\n\n```elixir\nquote do\n  <<1, 2, 3>>\nend\n#=> {:<<>>, [], [1, 2, 3]}\n```\n\nThe same applies to maps, where pairs are treated as a list of tuples with two elements:\n\n```elixir\nquote do\n  %{1 => 2, 3 => 4}\nend\n#=> {:%{}, [], [{1, 2}, {3, 4}]}\n```\n\n### Blocks\n\nBlocks are represented as a `__block__` call with each line as a separate argument:\n\n```elixir\nquote do\n  1\n  2\n  3\nend\n#=> {:__block__, [], [1, 2, 3]}\n\nquote do 1; 2; 3; end\n#=> {:__block__, [], [1, 2, 3]}\n```\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is represented similar to operators except that they are always part of a list, its left side represents a list of arguments and the right side is an expression.\n\nFor example, in `case` and `cond`:\n\n```elixir\nquote do\n  case 1 do\n    2 -> 3\n    4 -> 5\n  end\nend\n#=> {:case, [], [1, [do: [{:->, [], [[2], 3]}, {:->, [], [[4], 5]}]]]}\n\nquote do\n  cond do\n    true -> false\n  end\nend\n#=> {:cond, [], [[do: [{:->, [], [[true], false]}]]]}\n```\n\nBetween `(` and `)`:\n\n```elixir\nquote do\n  (1, 2 -> 3\n   4, 5 -> 6)\nend\n#=> [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]\n```\n\nBetween `fn` and `end`:\n\n```elixir\nquote do\n  fn\n    1, 2 -> 3\n    4, 5 -> 6\n  end\nend\n#=> {:fn, [], [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]}\n```\n\n### Qualified tuples\n\nQualified tuples (`foo.{bar, baz}`) are represented by a `{:., [], [expr, :{}]}` call, where the `expr` represents the left hand side of the dot, and the arguments represent the elements inside the curly braces. This is used in Elixir to provide multi aliases:\n\n```elixir\nquote do\n  Foo.{Bar, Baz}\nend\n#=> {{:., [], [{:__aliases__, [], [:Foo]}, :{}]}, [], [{:__aliases__, [], [:Bar]}, {:__aliases__, [], [:Baz]}]}\n```\n\n### `do`-`end` blocks\n\nElixir's `do`-`end` blocks are equivalent to keywords as the last argument of a function call, where the block contents are wrapped in parentheses. For example:\n\n```elixir\nif true do\n  this\nelse\n  that\nend\n```\n\nis the same as:\n\n```elixir\nif(true, do: (this), else: (that))\n```\n\nWhile the construct above does not require custom nodes in Elixir's AST, they are restricted only to certain keywords, listed next:\n\n  * `after`\n  * `catch`\n  * `else`\n  * `rescue`\n\nYou will find them in constructs such as `receive`, `try`, and others. You can also find more examples in [the Optional Syntax chapter](../getting-started/optional-syntax.md).\n"
  },
  {
    "path": "lib/elixir/pages/references/typespecs.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Typespecs reference\n\n> #### Typespecs are not set-theoretic types {: .warning}\n>\n> Elixir is in the process of implementing its\n> [own type system](./gradual-set-theoretic-types.md) based on set-theoretic types.\n> Typespecs, which are described in the following document, are a distinct notation\n> for declaring types and specifications based on Erlang.\n> Typespecs may be phased out as the set-theoretic type effort moves forward.\n\nElixir is a dynamically typed language, and as such, type specifications are never used by the compiler to optimize or modify code. Still, using type specifications is useful because:\n\n  * they provide documentation (for example, tools such as [`ExDoc`](https://hexdocs.pm/ex_doc/) show type specifications in the documentation)\n  * they're used by tools such as [Dialyzer](`:dialyzer`), that can analyze code with typespecs to find type inconsistencies and possible bugs\n\nType specifications (most often referred to as *typespecs*) are defined in different contexts using the following attributes:\n\n  * `@type`\n  * `@opaque`\n  * `@typep`\n  * `@spec`\n  * `@callback`\n  * `@macrocallback`\n\nIn addition, you can use `@typedoc` to document a custom `@type` definition.\n\nSee the \"User-defined types\" and \"Defining a specification\" sub-sections below for more information on defining types and typespecs.\n\n## A simple example\n\n    defmodule StringHelpers do\n      @typedoc \"A word from the dictionary\"\n      @type word() :: String.t()\n\n      @spec long_word?(word()) :: boolean()\n      def long_word?(word) when is_binary(word) do\n        String.length(word) > 8\n      end\n    end\n\nIn the example above:\n\n  * We declare a new type (`word()`) that is equivalent to the string type (`String.t()`).\n\n  * We describe the type using a `@typedoc`, which will be included in the generated documentation.\n\n  * We specify that the `long_word?/1` function takes an argument of type `word()` and\n    returns a boolean (`boolean()`), that is, either `true` or `false`.\n\n## Types and their syntax\n\nThe syntax Elixir provides for type specifications is similar to [the one in Erlang](https://www.erlang.org/doc/reference_manual/typespec.html). Most of the built-in types provided in Erlang (for example, `pid()`) are expressed in the same way: `pid()` (or simply `pid`). Parameterized types (such as `list(integer)`) are supported as well and so are remote types (such as [`Enum.t()`](`t:Enum.t/0`)). Integers and atom literals are allowed as types (for example, `1`, `:atom`, or `false`). All other types are built out of unions of predefined types. Some types can also be declared using their syntactical notation, such as `[type]` for lists, `{type1, type2, ...}` for tuples and `<<_ * _>>` for binaries.\n\nThe notation to represent the union of types is the pipe `|`. For example, the typespec `type :: atom() | pid() | tuple()` creates a type `type` that can be either an `atom`, a `pid`, or a `tuple`. This is usually called a [sum type](https://en.wikipedia.org/wiki/Tagged_union) in other languages\n\n> #### Differences with set-theoretic types {: .warning}\n>\n> While they do share some similarities, the types below do not map one-to-one\n> to the new types from the set-theoretic type system.\n>\n> For example, there is no plan to support subsets of the `integer()` type such\n> as positive, ranges or literals.\n>\n> Furthermore, set-theoretic types support the full range of set operations,\n> including intersections and negations.\n\n### Basic types\n\n    type ::\n          any()                     # the top type, the set of all terms\n          | none()                  # the bottom type, contains no terms\n          | atom()\n          | map()                   # any map\n          | pid()                   # process identifier\n          | port()                  # port identifier\n          | reference()\n          | tuple()                 # tuple of any size\n\n                                    ## Numbers\n          | float()\n          | integer()\n          | neg_integer()           # ..., -3, -2, -1\n          | non_neg_integer()       # 0, 1, 2, 3, ...\n          | pos_integer()           # 1, 2, 3, ...\n\n                                                                          ## Lists\n          | list(type)                                                    # proper list ([]-terminated)\n          | nonempty_list(type)                                           # non-empty proper list\n          | maybe_improper_list(content_type, termination_type)           # proper or improper list\n          | nonempty_improper_list(content_type, termination_type)        # improper list\n          | nonempty_maybe_improper_list(content_type, termination_type)  # non-empty proper or improper list\n\n          | Literals                # Described in section \"Literals\"\n          | BuiltIn                 # Described in section \"Built-in types\"\n          | Remotes                 # Described in section \"Remote types\"\n          | UserDefined             # Described in section \"User-defined types\"\n\n### Literals\n\nThe following literals are also supported in typespecs:\n\n    type ::                               ## Atoms\n          :atom                           # atoms: :foo, :bar, ...\n          | true | false | nil            # special atom literals\n\n                                          ## Bitstrings\n          | <<>>                          # empty bitstring\n          | <<_::size>>                   # size is 0 or a positive integer\n          | <<_::_*unit>>                 # unit is an integer from 1 to 256\n          | <<_::size, _::_*unit>>\n\n                                          ## (Anonymous) Functions\n          | (-> type)                     # zero-arity, returns type\n          | (type1, type2 -> type)        # two-arity, returns type\n          | (... -> type)                 # any arity, returns type\n\n                                          ## Integers\n          | 1                             # integer\n          | 1..10                         # integer from 1 to 10\n\n                                          ## Lists\n          | [type]                        # list with any number of type elements\n          | []                            # empty list\n          | [...]                         # shorthand for nonempty_list(any())\n          | [type, ...]                   # shorthand for nonempty_list(type)\n          | [key: value_type]             # keyword list with optional key :key of value_type\n\n                                                  ## Maps\n          | %{}                                   # empty map\n          | %{key: value_type}                    # map with required key :key of value_type\n          | %{key_type => value_type}             # map with required pairs of key_type and value_type\n          | %{required(key_type) => value_type}   # map with required pairs of key_type and value_type\n          | %{optional(key_type) => value_type}   # map with optional pairs of key_type and value_type\n          | %SomeStruct{}                         # struct with all fields of any type\n          | %SomeStruct{key: value_type}          # struct with required key :key of value_type\n\n                                          ## Tuples\n          | {}                            # empty tuple\n          | {:ok, type}                   # two-element tuple with an atom and any type\n\n### Built-in types\n\nThe following types are also provided by Elixir as shortcuts on top of the basic and literal types described above.\n\nBuilt-in type           | Defined as\n:---------------------- | :---------\n`term()`                | `any()`\n`arity()`               | `0..255`\n`as_boolean(t)`         | `t`\n`binary()`              | `<<_::_*8>>`\n`nonempty_binary()`     | `<<_::8, _::_*8>>`\n`bitstring()`           | `<<_::_*1>>`\n`nonempty_bitstring()`  | `<<_::1, _::_*1>>`\n`boolean()`             | `true` \\| `false`\n`byte()`                | `0..255`\n`char()`                | `0..0x10FFFF`\n`charlist()`            | `[char()]`\n`nonempty_charlist()`   | `[char(), ...]`\n`fun()`                 | `(... -> any)`\n`function()`            | `fun()`\n`identifier()`          | `pid()` \\| `port()` \\| `reference()`\n`iodata()`              | `iolist()` \\| `binary()`\n`iolist()`              | `maybe_improper_list(byte() \\| binary() \\| iolist(), binary() \\| [])`\n`keyword()`             | `[{atom(), any()}]`\n`keyword(t)`            | `[{atom(), t}]`\n`list()`                | `[any()]`\n`nonempty_list()`       | `nonempty_list(any())`\n`maybe_improper_list()` | `maybe_improper_list(any(), any())`\n`nonempty_maybe_improper_list()` | `nonempty_maybe_improper_list(any(), any())`\n`mfa()`                 | `{module(), atom(), arity()}`\n`module()`              | `atom()`\n`no_return()`           | `none()`\n`node()`                | `atom()`\n`number()`              | `integer()` \\| `float()`\n`struct()`              | `%{:__struct__ => atom(), optional(atom()) => any()}`\n`timeout()`             | `:infinity` \\| `non_neg_integer()`\n\n`as_boolean(t)` exists to signal users that the given value will be treated as a boolean, where `nil` and `false` will be evaluated as `false` and everything else is `true`. For example, `Enum.filter/2` has the following specification: `filter(t, (element -> as_boolean(term))) :: list`.\n\n### Remote types\n\nAny module is also able to define its own types and the modules in Elixir are no exception. For example, the `Range` module defines a `t/0` type that represents a range: this type can be referred to as `t:Range.t/0`. In a similar fashion, a string is `t:String.t/0`, and so on.\n\n### Maps\n\nThe key types in maps are allowed to overlap, and if they do, the leftmost key takes precedence.\nA map value does not belong to this type if it contains a key that is not in the allowed map keys.\n\nIf you want to denote that keys that were not previously defined in the map are allowed,\nit is common to end a map type with `optional(any) => any`.\n\nNote that the syntactic representation of `map()` is `%{optional(any) => any}`, not `%{}`. The notation `%{}` specifies the singleton type for the empty map.\n\n### Keyword Lists\n\nBeyond `keyword()` and `keyword(t)`, it can be helpful to compose a spec for an expected keyword list.\nFor example:\n\n```elixir\n@type option :: {:name, String.t} | {:max, pos_integer} | {:min, pos_integer}\n@type options :: [option()]\n```\n\nThis makes it clear that only these options are allowed, none are required, and order does not matter.\n\nIt also allows composition with existing types.\nFor example:\n\n```elixir\n@type option :: {:my_option, String.t()} | GenServer.option()\n\n@spec start_link([option()]) :: GenServer.on_start()\ndef start_link(opts) do\n  {my_opts, gen_server_opts} = Keyword.split(opts, [:my_option])\n  GenServer.start_link(__MODULE__, my_opts, gen_server_opts)\nend\n```\n\nThe following spec syntaxes are equivalent:\n\n```elixir\n@type options [{:name, String.t} | {:max, pos_integer} | {:min, pos_integer}]\n\n@type options [name: String.t, max: pos_integer, min: pos_integer]\n```\n\n### User-defined types\n\nThe `@type`, `@typep`, and `@opaque` module attributes can be used to define new types:\n\n    @type type_name :: type\n    @typep type_name :: type\n    @opaque type_name :: type\n\nA type defined with `@typep` is private. An opaque type, defined with `@opaque` is a type where the internal structure of the type will not be visible, but the type is still public.\n\nTypes can be parameterized by defining variables as parameters; these variables can then be used to define the type.\n\n    @type dict(key, value) :: [{key, value}]\n\n## Defining a specification\n\nA specification for a function can be defined as follows:\n\n    @spec function_name(type1, type2) :: return_type\n\nGuards can be used to restrict type variables given as arguments to the function.\n\n    @spec function(arg) :: [arg] when arg: atom\n\nIf you want to specify more than one variable, you separate them by a comma.\n\n    @spec function(arg1, arg2) :: {arg1, arg2} when arg1: atom, arg2: integer\n\nType variables with no restriction can also be defined using `var`.\n\n    @spec function(arg) :: [arg] when arg: var\n\nThis guard notation only works with `@spec`, `@callback`, and `@macrocallback`.\n\nYou can also name your arguments in a typespec using `arg_name :: arg_type` syntax. This is particularly useful in documentation as a way to differentiate multiple arguments of the same type (or multiple elements of the same type in a type definition):\n\n    @spec days_since_epoch(year :: integer, month :: integer, day :: integer) :: integer\n    @type color :: {red :: integer, green :: integer, blue :: integer}\n\nSpecifications can be overloaded, just like ordinary functions.\n\n    @spec function(integer) :: atom\n    @spec function(atom) :: integer\n\n## Behaviours\n\nBehaviours in Elixir (and Erlang) are a way to separate and abstract the generic part of a component (which becomes the *behaviour module*) from the specific part (which becomes the *callback module*).\n\nA behaviour module defines a set of functions and macros (referred to as *callbacks*) that callback modules implementing that behaviour must export. This \"interface\" identifies the specific part of the component. For example, the `GenServer` behaviour and functions abstract away all the message-passing (sending and receiving) and error reporting that a \"server\" process will likely want to implement from the specific parts such as the actions that this server process has to perform.\n\nSay we want to implement a bunch of parsers, each parsing structured data: for example, a JSON parser and a MessagePack parser. Each of these two parsers will *behave* the same way: both will provide a `parse/1` function and an `extensions/0` function. The `parse/1` function will return an Elixir representation of the structured data, while the `extensions/0` function will return a list of file extensions that can be used for each type of data (e.g., `.json` for JSON files).\n\nWe can create a `Parser` behaviour:\n\n```elixir\ndefmodule Parser do\n  @doc \"\"\"\n  Parses a string.\n  \"\"\"\n  @callback parse(String.t) :: {:ok, term} | {:error, atom}\n\n  @doc \"\"\"\n  Lists all supported file extensions.\n  \"\"\"\n  @callback extensions() :: [String.t]\nend\n```\n\nAs seen in the example above, defining a callback is a matter of defining a specification for that callback, made of:\n\n  * the callback name (`parse` or `extensions` in the example)\n  * the arguments that the callback must accept (`String.t`)\n  * the *expected* type of the callback return value\n\nModules adopting the `Parser` behaviour will have to implement all the functions defined with the `@callback` attribute. As you can see, `@callback` expects a function name but also a function specification like the ones used with the `@spec` attribute we saw above.\n\n### Implementing behaviours\n\nImplementing a behaviour is straightforward:\n\n```elixir\ndefmodule JSONParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some json \" <> str} # ... parse JSON\n\n  @impl Parser\n  def extensions, do: [\".json\"]\nend\n```\n\n```elixir\ndefmodule CSVParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some csv \" <> str} # ... parse CSV\n\n  @impl Parser\n  def extensions, do: [\".csv\"]\nend\n```\n\nIf a module adopting a given behaviour doesn't implement one of the callbacks required by that behaviour, a compile-time warning will be generated.\n\nFurthermore, with `@impl` you can also make sure that you are implementing the **correct** callbacks from the given behaviour in an explicit manner. For example, the following parser implements both `parse` and `extensions`. However, thanks to a typo, `BADParser` is implementing `parse/0` instead of `parse/1`.\n\n```elixir\ndefmodule BADParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse, do: {:ok, \"something bad\"}\n\n  @impl Parser\n  def extensions, do: [\"bad\"]\nend\n```\n\nThis code generates a warning letting you know that you are mistakenly implementing `parse/0` instead of `parse/1`.\nYou can read more about `@impl` in the [module documentation](`Module#module-impl`).\n\n### Using behaviours\n\nBehaviours are useful because you can pass modules around as arguments and you can then *call back* to any of the functions specified in the behaviour. For example, we can have a function that receives a filename, several parsers, and parses the file based on its extension:\n\n```elixir\n@spec parse_path(Path.t(), [module()]) :: {:ok, term} | {:error, atom}\ndef parse_path(filename, parsers) do\n  with {:ok, ext} <- parse_extension(filename),\n       {:ok, parser} <- find_parser(ext, parsers),\n       {:ok, contents} <- File.read(filename) do\n    parser.parse(contents)\n  end\nend\n\ndefp parse_extension(filename) do\n  if ext = Path.extname(filename) do\n    {:ok, ext}\n  else\n    {:error, :no_extension}\n  end\nend\n\ndefp find_parser(ext, parsers) do\n  if parser = Enum.find(parsers, fn parser -> ext in parser.extensions() end) do\n    {:ok, parser}\n  else\n    {:error, :no_matching_parser}\n  end\nend\n```\n\nYou could also invoke any parser directly: `CSVParser.parse(...)`.\n\nNote you don't need to define a behaviour in order to dynamically dispatch on a module, but those features often go hand in hand.\n\n### Optional callbacks\n\nOptional callbacks are callbacks that callback modules may implement if they want to, but are not required to. Usually, behaviour modules know if they should call those callbacks based on configuration, or they check if the callbacks are defined with `function_exported?/3` or `macro_exported?/3`.\n\n> ### Unloaded modules {: .warning}\n>\n> `function_exported?/3` (and `macro_exported?/3`) do *not* load the module in case it is not loaded and Elixir lazily loads modules by default (except on releases). So in practice you will want to invoke `Code.ensure_loaded?/1` before checking if the function/macro is exported. See the documentation for `function_exported?/3` for examples.\n\nOptional callbacks can be defined through the `@optional_callbacks` module attribute, which has to be a keyword list with function or macro name as key and arity as value. For example:\n\n    defmodule MyBehaviour do\n      @callback vital_fun() :: any\n      @callback non_vital_fun() :: any\n      @macrocallback non_vital_macro(arg :: any) :: Macro.t\n      @optional_callbacks non_vital_fun: 0, non_vital_macro: 1\n    end\n\nOne example of optional callback in Elixir's standard library is `c:GenServer.format_status/1`.\n\n### Inspecting behaviours\n\nThe `@callback` and `@optional_callbacks` attributes are used to create a `behaviour_info/1` function available on the defining module. This function can be used to retrieve the callbacks and optional callbacks defined by that module.\n\nFor example, for the `MyBehaviour` module defined in \"Optional callbacks\" above:\n\n    MyBehaviour.behaviour_info(:callbacks)\n    #=> [vital_fun: 0, \"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n    MyBehaviour.behaviour_info(:optional_callbacks)\n    #=> [\"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n\nWhen using `iex`, the `IEx.Helpers.b/1` helper is also available.\n\n## Pitfalls\n\nThere are some known pitfalls when using typespecs, they are documented next.\n\n## The `string()` type\n\nElixir discourages the use of the `string()` type. The `string()` type refers to Erlang strings, which are known as \"charlists\" in Elixir. They do not refer to Elixir strings, which are UTF-8 encoded binaries. To avoid confusion, if you attempt to use the type `string()`, Elixir will emit a warning. You should use `charlist()`, `nonempty_charlist()`, `binary()` or `String.t()` accordingly, or any of the several literal representations for these types.\n\nNote that `String.t()` and `binary()` are equivalent to analysis tools. Although, for those reading the documentation, `String.t()` implies it is a UTF-8 encoded binary.\n\n## Functions which raise an error\n\nTypespecs do not need to indicate that a function can raise an error; any function can fail any time if given invalid input.\nIn the past, the Elixir standard library sometimes used `no_return()` to indicate this, but these usages have been removed.\n\nThe `no_return()` type also should not be used for functions which do return but whose purpose is a \"side effect\", such as `IO.puts/1`.\nIn these cases, the expected return type is `:ok`.\n\nInstead, `no_return()` should be used as the return type for functions which can never return a value.\nThis includes functions which loop forever calling `receive`, or which exist specifically to raise an error, or which shut down the VM.\n"
  },
  {
    "path": "lib/elixir/pages/references/unicode-syntax.md",
    "content": "<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Unicode syntax\n\nElixir supports Unicode throughout the language. This document is a complete reference of how\nElixir supports Unicode in its syntax.\n\nStrings (`\"olá\"`) and charlists (`'olá'`) support Unicode since Elixir v1.0. Strings are UTF-8 encoded. Charlists are lists of Unicode code points. In such cases, the contents are kept as written by developers, without any transformation.\n\nElixir also supports Unicode in variables, atoms, and calls since Elixir v1.5. The focus of this document is to provide a high-level introduction to how Elixir allows Unicode in its syntax. We also provide technical documentation describing how Elixir complies with the Unicode specification.\n\nTo check the Unicode version of your current Elixir installation, run `String.Unicode.version()`.\n\n## Introduction\n\nElixir allows Unicode characters in its variables, atoms, and calls. However, the Unicode characters must still obey the rules of the language syntax. In particular, variables and calls cannot start with an uppercase letter. From now on, we will refer to those terms as identifiers.\n\nThe characters allowed in identifiers are the ones specified by Unicode. Generally speaking, it is restricted to characters typically used by the writing system of human languages still in activity. In particular, it excludes symbols such as emojis, alternate numeric representations, musical notes, and the like.\n\nElixir imposes many restrictions on identifiers for security purposes. For example, the word \"josé\" can be written in two ways in Unicode: as the combination of the characters `j o s é` and as a combination of the characters `j o s e ́ `, where the accent is its own character. The former is called NFC form and the latter is the NFD form. Elixir normalizes all characters to be the in the NFC form.\n\nElixir also disallows mixed-scripts which are not explicitly separated by `_`. For example, it is not possible to name a variable `аdmin`, where `а` is in Cyrillic and the remaining characters are in Latin. Doing so will raise the following error:\n\n```text\n** (SyntaxError) invalid mixed-script identifier found: аdmin\n\nMixed-script identifiers are not supported for security reasons. 'аdmin' is made of the following scripts:\n\n  \\u0430 а {Cyrillic}\n  \\u0064 d {Latin}\n  \\u006D m {Latin}\n  \\u0069 i {Latin}\n  \\u006E n {Latin}\n\nMake sure all characters in the identifier resolve to a single script or a highly\nrestrictive script. See https://hexdocs.pm/elixir/unicode-syntax.html for more information.\n```\n\nFinally, Elixir will also warn of confusable identifiers in the same file. For example, Elixir will emit a warning if you use both variables `а` (Cyrillic) and `а` (Latin) in your code.\n\nThat's the overall introduction of how Unicode is used in Elixir identifiers. In a nutshell, its goal is to support different writing systems in use today while keeping the Elixir language itself clear and secure.\n\nFor the technical details, see the next sections that cover the technical Unicode requirements.\n\n## Unicode Standard Annex #31\n\nElixir conforms to the standards outlined in the [Unicode Standard Annex #31: Unicode Identifiers and Syntax](https://unicode.org/reports/tr31/), version 17.0.\n\n### R1. Default Identifiers\n\nThe general Elixir identifier rule is specified as:\n\n    <Identifier> := <Start> <Continue>* <Ending>?\n\nwhere `<Start>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> characters derived from the Unicode General Category of uppercase letters, lowercase letters, titlecase letters, modifier letters, other letters, letter numbers, plus `Other_ID_Start`, minus `Pattern_Syntax` and `Pattern_White_Space` code points\n>\n> In set notation: `[\\p{L}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\nand `<Continue>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> ID_Start characters, plus characters having the Unicode General Category of nonspacing marks, spacing combining marks, decimal number, connector punctuation, plus `Other_ID_Continue`, minus `Pattern_Syntax` and `Pattern_White_Space` code points.\n>\n> In set notation: `[\\p{ID_Start}\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}\\p{Other_ID_Continue}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n`<Ending>` is an addition specific to Elixir that includes only the code points `?` (003F) and `!` (0021).\n\nThe spec also provides a `<Medial>` set, but Elixir does not include any character on this set. Therefore, the identifier rule has been simplified to consider this.\n\nElixir does not allow the use of ZWJ or ZWNJ in identifiers and therefore does not implement R1a. Bidirectional control characters are also not supported. R1b is guaranteed for backwards compatibility purposes.\n\n#### Atoms\n\nUnicode atoms in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Continue>` additionally includes the code point `@` (0040)\n\nNote atoms can also be quoted, which allows any characters, such as `:\"hello elixir\"`. All Elixir operators are also valid atoms, such as `:+`, `:@`, `:|>`, and others. The full description of valid atoms is available in the [\"Atoms\" section in the syntax reference](syntax-reference.md#atoms).\n\n#### Variables, local calls, and remote calls\n\nVariables in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Start>` additionally excludes Lu (letter uppercase) and Lt (letter titlecase) characters\n\nIn set notation: `[\\u{005F}\\p{Ll}\\p{Lm}\\p{Lo}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n#### Aliases\n\nAliases in Elixir only allow ASCII characters, starting in uppercase, and no punctuation characters.\n\n### R3. Pattern_White_Space and Pattern_Syntax Characters\n\nElixir supports only code points `\\t` (0009), `\\n` (000A), `\\r` (000D) and `\\s` (0020) as whitespace and therefore does not follow requirement R3. R3 requires a wider variety of whitespace and syntax characters to be supported.\n\n### R4. Equivalent Normalized Identifiers\n\nIdentifiers in Elixir are case sensitive.\n\nElixir normalizes all atoms and variables to NFC form. Quoted-atoms and strings can, however, be in any form and are not verified by the parser.\n\nIn other words, the atom `:josé` can only be written with the code points `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301`, but Elixir will rewrite it to the former (from Elixir 1.14). On the other hand, `:\"josé\"` may be written as `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301` and its form will be retained, since it is written between quotes.\n\nChoosing requirement R4 automatically excludes requirements R5, R6, and R7.\n\n## Unicode Technical Standard #39\n\nElixir conforms to the clauses outlined in the [Unicode Technical Standard #39](https://unicode.org/reports/tr39/) on Security, version 17.0.\n\n### C1. General Security Profile for Identifiers\n\nElixir will not allow tokenization of identifiers with codepoints in `\\p{Identifier_Status=Restricted}`, except for the outlined 'Additional normalizations' section below.\n\n> An implementation following the General Security Profile does not permit any characters in \\p{Identifier_Status=Restricted}, ...\n\nFor instance, the 'HANGUL FILLER' (`ㅤ`) character, which is often invisible, is an uncommon codepoint and will trigger a warning.\n\n### C2. Confusable detection\n\nElixir will warn of identifiers that look the same, but aren't. Examples: in `а = a = 1`, the two 'a' characters are Cyrillic and Latin, and could be confused for each other; in `力 = カ = 1`, both are Japanese, but different codepoints, in different scripts of that writing system. Confusable identifiers can lead to hard-to-catch bugs (say, due to copy-pasted code) and can be unsafe, so we will warn of identifiers within a single file that could be confused with each other.\n\nWe use the means described in Section 4, 'Confusable Detection', with one noted modification:\n\n> Alternatively, it shall declare that it uses a modification, and provide a precise list of character mappings that are added to or removed from the provided ones.\n\nElixir will not warn about confusability for identifiers made up exclusively of characters in a-z, A-Z, 0-9, and _. This is because ASCII identifiers have existed for so long that the programming community has had their own means of dealing with confusability between identifiers like `l,1` or `O,0` (for instance, fonts designed for programming usually make it easy to differentiate between those characters).\n\n### C3. Mixed Script Detection\n\nElixir will not allow tokenization of mixed-script identifiers unless it is via chunks separated by an underscore, like `http_сервер`. We use the means described in Section 5.1, Mixed-Script Detection, to determine if script mixing is occurring, with the 'Additional Normalizations' documented in.\n\nExamples: Elixir allows an identifiers like `幻한`, even though it includes characters from multiple 'scripts', as Han characters may be mixed with Japanese and Korean, according to the rules from UTS 39 5.1. When mixing Latin and Japanese scripts, underscores are necessary, as in `:T_シャツ` (the Japanese word for 't-shirt' with an additional underscore separating the letter T).\n\nElixir does not allow code like `if аdmin, do: :ok, else: :err`, where the scriptset for the 'a' character is {Cyrillic} but all other characters have scriptsets of {Latin}. The scriptsets fail to resolve and a descriptive error is shown.\n\n### C4, C5 (inapplicable)\n\n'C4 - Restriction Level detection' conformance is not claimed and does not apply to identifiers in code; rather, it applies to classifying the level of safety of a given arbitrary string into one of 5 restriction levels.\n\n'C5 - Mixed number detection' conformance is inapplicable as Elixir does not support Unicode numbers.\n\n### Addition Normalizations\n\nAs of Elixir 1.14, some codepoints in `\\p{Identifier_Status=Restricted}` are *normalized* to other, unrestricted codepoints.\n\nThis is currently only applied to translate MICRO SIGN (`µ`) to Greek lowercase mu (`μ`).\n\nThe normalization avoids confusability and the mixed-script detection is modified to the extent that the normalized codepoint is given the union of scriptsets from both characters.\n\n  * For instance, in the example of MICRO => MU, MICRO was a 'Common'-script character - the same script given to the '_' underscore codepoint - and thus the normalized character's scriptset will be {Greek, Common}. 'Common' intersects with all non-empty scriptsets, and thus the normalized character can be used in tokens written in any script without causing script mixing.\n\n  * The code points normalized in this fashion are those that are in use in the community, and judged not likely to cause issues with unsafe script mixing. For instance, the MICRO or MU codepoint may be used in an atom or variable dealing with microseconds.\n"
  },
  {
    "path": "lib/elixir/scripts/cover.exs",
    "content": "#!bin/elixir\n\n# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"cover_record.exs\", __DIR__)\ncover_pid = CoverageRecorder.enable_coverage()\n\ncoverdata_inputs =\n  CoverageRecorder.cover_dir() |> Path.join(\"ex_unit_*.coverdata\") |> Path.wildcard()\n\ncoverdata_output = Path.join(CoverageRecorder.cover_dir(), \"combined.coverdata\")\n\nfor file <- coverdata_inputs do\n  :ok = :cover.import(String.to_charlist(file))\nend\n\n:ok = :cover.export(String.to_charlist(coverdata_output))\n\n{:ok, _} = Application.ensure_all_started(:mix)\n\n# Silence analyse import messages emitted by cover\n{:ok, string_io} = StringIO.open(\"\")\nProcess.group_leader(cover_pid, string_io)\n\n:ok =\n  Mix.Tasks.Test.Coverage.generate_cover_results(\n    output: CoverageRecorder.cover_dir(),\n    summary: [threshold: 0]\n  )\n"
  },
  {
    "path": "lib/elixir/scripts/cover_record.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule CoverageRecorder do\n  def maybe_record(suite_name) do\n    if enabled?() do\n      record(suite_name)\n\n      true\n    else\n      false\n    end\n  end\n\n  def enable_coverage do\n    _ = :cover.stop()\n    {:ok, pid} = :cover.start()\n\n    cover_compile_ebins()\n\n    pid\n  end\n\n  def cover_dir, do: Path.join(root_dir(), \"cover\")\n\n  defp enabled? do\n    case System.fetch_env(\"COVER\") do\n      {:ok, truthy} when truthy in ~w[1 true yes y] ->\n        true\n\n      _ ->\n        false\n    end\n  end\n\n  defp root_dir, do: Path.join(__DIR__, \"../../..\")\n  defp ebins, do: root_dir() |> Path.join(\"lib/*/ebin\") |> Path.wildcard()\n\n  defp record(suite_name) do\n    file = Path.join(cover_dir(), \"ex_unit_#{suite_name}.coverdata\")\n\n    enable_coverage()\n\n    System.at_exit(fn _status ->\n      File.mkdir_p!(cover_dir())\n\n      :ok = :cover.export(String.to_charlist(file))\n    end)\n  end\n\n  defp cover_compile_ebins do\n    relevant_beam_files()\n    |> Enum.map(&String.to_charlist/1)\n    |> :cover.compile_beam()\n    |> Enum.each(fn\n      {:ok, _module} ->\n        :ok\n\n      {:error, reason} ->\n        raise \"Failed to cover compile with reason: #{inspect(reason)}\"\n    end)\n  end\n\n  defp relevant_beam_files do\n    ebins()\n    |> Enum.flat_map(fn ebin ->\n      ebin |> Path.join(\"*.beam\") |> Path.wildcard()\n    end)\n    |> Enum.reject(&skip_from_coverage?/1)\n  end\n\n  @to_skip [\n    # Tested via the CLI only\n    :elixir_sup,\n    :iex,\n    Kernel.CLI,\n    Mix.CLI,\n    Mix.Compilers.Test,\n    Mix.Tasks.Test,\n    Mix.Tasks.Test.Coverage,\n\n    # Bootstrap\n    :elixir_bootstrap,\n    Kernel.SpecialForms\n  ]\n\n  defp skip_from_coverage?(file) do\n    mod = file |> Path.basename(\".beam\") |> String.to_atom()\n    mod in @to_skip or match?({:docs_v1, _, _, _, _, %{deprecated: _}, _}, Code.fetch_docs(mod))\n  end\nend\n"
  },
  {
    "path": "lib/elixir/scripts/diff.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Diff do\n  @moduledoc \"\"\"\n  Utilities for comparing build artifacts.\n  \"\"\"\n\n  @atom_chunks ~w(\n    atoms\n    attributes\n    compile_info\n    debug_info\n    exports\n    labeled_exports\n    imports\n    indexed_imports\n    locals\n    labeled_locals\n  )a\n\n  @term_chunks ~w(\n    ExCk\n    Docs\n  )c\n\n  @binary_chunks ~w(\n    Attr\n    AtU8\n    CInf\n    Dbgi\n    ExpT\n    ImpT\n    LocT\n  )c\n\n  @doc \"\"\"\n  Compares the build artifacts of two build directories.\n  \"\"\"\n  @spec compare_dirs(Path.t(), Path.t()) ::\n          {\n            only1_paths :: list(Path.t()),\n            only2_paths :: list(Path.t()),\n            diff :: list({Path.t(), diff :: String.t()})\n          }\n  def compare_dirs(dir1, dir2) do\n    dir1 = Path.expand(dir1)\n    dir2 = Path.expand(dir2)\n\n    assert_dir!(dir1)\n    assert_dir!(dir2)\n\n    dir1_paths = relative_paths(dir1)\n    dir2_paths = relative_paths(dir2)\n\n    only1_paths = dir1_paths -- dir2_paths\n    only2_paths = dir2_paths -- dir1_paths\n    common_paths = dir1_paths -- only1_paths\n    common_files = Enum.reject(common_paths, &File.dir?/1)\n\n    diff =\n      Enum.flat_map(common_files, fn path ->\n        file1 = Path.join(dir1, path)\n        file2 = Path.join(dir2, path)\n\n        case compare_files(file1, file2) do\n          :eq -> []\n          {:diff, diff} -> [{path, diff}]\n        end\n      end)\n\n    {only1_paths, only2_paths, diff}\n  end\n\n  @doc \"\"\"\n  Compares the contents of two files.\n\n  If the files are BEAM files, it performs a more human-friendly\n  \"BEAM-diff\".\n  \"\"\"\n  @spec compare_files(Path.t(), Path.t()) :: :eq | {:diff, diff :: String.t()}\n  def compare_files(file1, file2) do\n    content1 = File.read!(file1)\n    content2 = File.read!(file2)\n\n    if content1 == content2 do\n      :eq\n    else\n      diff =\n        if String.ends_with?(file1, \".beam\") do\n          beam_diff(file1, content1, file2, content2)\n        else\n          file_diff(file1, file2)\n        end\n\n      {:diff, diff}\n    end\n  end\n\n  defp inspect_all(data) do\n    inspect(data, pretty: true, limit: :infinity)\n  end\n\n  defp beam_diff(file1, content1, file2, content2) do\n    chunk_diff(content1, content2, @atom_chunks, &inspect_all(&1)) ||\n      chunk_diff(content1, content2, @term_chunks, &inspect_all(:erlang.binary_to_term(&1))) ||\n      chunk_diff(content1, content2, @binary_chunks, &(&1 |> write_tmp() |> xxd_dump())) ||\n      (\n        tmp_file1 =\n          file1\n          |> xxd_dump()\n          |> write_tmp()\n\n        tmp_file2 =\n          file2\n          |> xxd_dump()\n          |> write_tmp()\n\n        file_diff(tmp_file1, tmp_file2)\n      )\n  end\n\n  defp chunk_diff(content1, content2, names, formatter) do\n    with {:ok, {module, chunks1}} <- :beam_lib.chunks(content1, names),\n         {:ok, {^module, chunks2}} <- :beam_lib.chunks(content2, names),\n         true <- chunks1 != chunks2 do\n      if length(chunks1) != length(chunks2) do\n        \"\"\"\n        Different chunks:\n        * #{inspect(chunks1)}\n        * #{inspect(chunks2)}\n        \"\"\"\n      else\n        for {{name1, chunk1}, {name2, chunk2}} <- Enum.zip(chunks1, chunks2),\n            true = name1 == name2,\n            chunk1 != chunk2 do\n          tmp_file1 = chunk1 |> formatter.() |> write_tmp()\n          tmp_file2 = chunk2 |> formatter.() |> write_tmp()\n\n          message =\n            case file_diff(tmp_file1, tmp_file2) do\n              \"\" -> \"DIFF IS EMPTY: most likely non-deterministic term_to_binary/2\"\n              diff -> diff\n            end\n\n          [to_string(name1), ?\\n, message]\n        end\n      end\n    else\n      _ -> nil\n    end\n  end\n\n  defp xxd_dump(file) do\n    {dump, _} = System.cmd(\"xxd\", [file])\n    dump\n  end\n\n  defp file_diff(file1, file2) do\n    {diff, _} = System.cmd(\"diff\", [\"-U3\", file1, file2])\n    diff\n  end\n\n  defp relative_paths(dir) do\n    dir\n    |> Path.join(\"**\")\n    |> Path.wildcard()\n    |> Enum.map(&Path.relative_to(&1, dir))\n  end\n\n  defp assert_dir!(dir) do\n    if not File.dir?(dir) do\n      raise ArgumentError, \"#{inspect(dir)} is not a directory\"\n    end\n  end\n\n  defp write_tmp(content) do\n    filename = \"tmp-#{System.unique_integer([:positive])}\"\n    File.mkdir_p!(\"tmp\")\n    File.write!(Path.join(\"tmp\", filename), content)\n    Path.join(\"tmp\", filename)\n  end\nend\n\nif :deterministic not in :compile.env_compiler_options() do\n  IO.puts(\"Cannot validate if reproducible without setting ERL_COMPILER_OPTIONS=deterministic\")\n  System.halt(1)\nend\n\ncase System.argv() do\n  [dir1, dir2] ->\n    case Diff.compare_dirs(dir1, dir2) do\n      {[], [], []} ->\n        IO.puts(\"#{inspect(dir1)} and #{inspect(dir2)} are equal\")\n\n      {only1, only2, diff} ->\n        for path <- only1, do: IO.puts(\"Only in #{dir1}: #{path}\")\n        for path <- only2, do: IO.puts(\"Only in #{dir2}: #{path}\")\n        for {path, diff} <- diff, do: IO.puts(\"Diff #{path}:\\n#{diff}\")\n\n        System.halt(1)\n    end\n\n  _ ->\n    IO.puts(\"Please, provide two directories as arguments\")\n    System.halt(1)\nend\n"
  },
  {
    "path": "lib/elixir/scripts/docs_config.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\n# Generate docs_config.js for version chooser in ExDoc\n[app] = System.argv()\nskipped = Version.parse!(\"1.0.3\")\nroot_dir = Path.expand(\"../../../\", __DIR__)\n\ngit_repo? =\n  root_dir\n  |> Path.join(\".git\")\n  |> File.dir?()\n\nversions =\n  if git_repo? do\n    {text_tags, 0} = System.cmd(\"git\", [\"tag\"])\n\n    for(\n      \"v\" <> rest <- String.split(text_tags),\n      not String.ends_with?(rest, \"-latest\"),\n      version = Version.parse!(rest),\n      Version.compare(version, skipped) == :gt,\n      do: version\n    )\n    |> Enum.sort({:desc, Version})\n  else\n    IO.warn(\"skipping version dropdown\", [])\n\n    []\n  end\n\nlatest =\n  if git_repo? do\n    versions\n    |> Stream.filter(&(&1.pre == []))\n    |> Enum.fetch!(0)\n    |> Version.to_string()\n  else\n    System.version()\n  end\n\nversion_nodes =\n  for version <- versions do\n    version_string = Version.to_string(version)\n    map = %{version: \"v#{version_string}\", url: \"https://hexdocs.pm/#{app}/#{version_string}\"}\n\n    if version_string == latest do\n      Map.put(map, :latest, true)\n    else\n      map\n    end\n  end\n\nsearch_nodes =\n  for app <- ~w(eex elixir ex_unit iex logger mix)s do\n    %{name: app, version: latest}\n  end\n\nFile.mkdir_p!(\"doc/#{app}\")\n\nFile.write!(\"doc/#{app}/docs_config.js\", \"\"\"\nvar versionNodes = #{JSON.encode_to_iodata!(version_nodes)};\nvar searchNodes = #{JSON.encode_to_iodata!(search_nodes)};\n\"\"\")\n"
  },
  {
    "path": "lib/elixir/scripts/elixir_docs.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Returns config for Elixir docs (exclusively)\ncanonical = System.fetch_env!(\"CANONICAL\")\n\n[\n  search: [\n    %{\n      name: \"Elixir + libraries\",\n      help: \"Search Elixir, EEx, ExUnit, IEx, Logger, and Mix\",\n      packages:\n        Enum.map(\n          [:elixir, :eex, :ex_unit, :iex, :logger, :mix],\n          &{&1, String.trim(canonical, \"/\")}\n        )\n    },\n    %{\n      name: \"Current project\",\n      help: \"Search only this project\"\n    }\n  ],\n  assets: %{\"lib/elixir/pages/images\" => \"assets\"},\n  extras: [\n    \"lib/elixir/pages/getting-started/introduction.md\",\n    \"lib/elixir/pages/getting-started/basic-types.md\",\n    \"lib/elixir/pages/getting-started/lists-and-tuples.md\",\n    \"lib/elixir/pages/getting-started/pattern-matching.md\",\n    \"lib/elixir/pages/getting-started/case-cond-and-if.md\",\n    \"lib/elixir/pages/getting-started/anonymous-functions.md\",\n    \"lib/elixir/pages/getting-started/binaries-strings-and-charlists.md\",\n    \"lib/elixir/pages/getting-started/keywords-and-maps.md\",\n    \"lib/elixir/pages/getting-started/modules-and-functions.md\",\n    \"lib/elixir/pages/getting-started/alias-require-and-import.md\",\n    \"lib/elixir/pages/getting-started/module-attributes.md\",\n    \"lib/elixir/pages/getting-started/structs.md\",\n    \"lib/elixir/pages/getting-started/recursion.md\",\n    \"lib/elixir/pages/getting-started/enumerable-and-streams.md\",\n    \"lib/elixir/pages/getting-started/comprehensions.md\",\n    \"lib/elixir/pages/getting-started/protocols.md\",\n    \"lib/elixir/pages/getting-started/sigils.md\",\n    \"lib/elixir/pages/getting-started/try-catch-and-rescue.md\",\n    \"lib/elixir/pages/getting-started/processes.md\",\n    \"lib/elixir/pages/getting-started/io-and-the-file-system.md\",\n    \"lib/elixir/pages/getting-started/writing-documentation.md\",\n    \"lib/elixir/pages/getting-started/optional-syntax.md\",\n    \"lib/elixir/pages/getting-started/erlang-libraries.md\",\n    \"lib/elixir/pages/getting-started/debugging.md\",\n    \"lib/elixir/pages/cheatsheets/enum-cheat.cheatmd\",\n    \"lib/elixir/pages/cheatsheets/types-cheat.cheatmd\",\n    \"lib/elixir/pages/anti-patterns/what-anti-patterns.md\",\n    \"lib/elixir/pages/anti-patterns/code-anti-patterns.md\",\n    \"lib/elixir/pages/anti-patterns/design-anti-patterns.md\",\n    \"lib/elixir/pages/anti-patterns/process-anti-patterns.md\",\n    \"lib/elixir/pages/anti-patterns/macro-anti-patterns.md\",\n    \"lib/elixir/pages/references/compatibility-and-deprecations.md\",\n    \"lib/elixir/pages/references/gradual-set-theoretic-types.md\",\n    \"lib/elixir/pages/references/library-guidelines.md\",\n    \"lib/elixir/pages/references/naming-conventions.md\",\n    \"lib/elixir/pages/references/operators.md\",\n    \"lib/elixir/pages/references/patterns-and-guards.md\",\n    \"lib/elixir/pages/references/syntax-reference.md\",\n    \"lib/elixir/pages/references/sbom.md\",\n    \"lib/elixir/pages/references/typespecs.md\",\n    \"lib/elixir/pages/references/unicode-syntax.md\",\n    \"lib/elixir/pages/mix-and-otp/introduction-to-mix.md\",\n    \"lib/elixir/pages/mix-and-otp/agents.md\",\n    \"lib/elixir/pages/mix-and-otp/supervisor-and-application.md\",\n    \"lib/elixir/pages/mix-and-otp/dynamic-supervisor.md\",\n    \"lib/elixir/pages/mix-and-otp/task-and-gen-tcp.md\",\n    \"lib/elixir/pages/mix-and-otp/docs-tests-and-with.md\",\n    \"lib/elixir/pages/mix-and-otp/config-and-distribution.md\",\n    \"lib/elixir/pages/mix-and-otp/genservers.md\",\n    \"lib/elixir/pages/mix-and-otp/releases.md\",\n    \"lib/elixir/pages/meta-programming/quote-and-unquote.md\",\n    \"lib/elixir/pages/meta-programming/macros.md\",\n    \"lib/elixir/pages/meta-programming/domain-specific-languages.md\",\n    \"CHANGELOG.md\"\n  ],\n  deps: [\n    eex: \"https://hexdocs.pm/eex/#{canonical}\",\n    ex_unit: \"https://hexdocs.pm/ex_unit/#{canonical}\",\n    iex: \"https://hexdocs.pm/iex/#{canonical}\",\n    logger: \"https://hexdocs.pm/logger/#{canonical}\",\n    mix: \"https://hexdocs.pm/mix/#{canonical}\"\n  ],\n  groups_for_extras: [\n    \"Getting started\": ~r\"pages/getting-started/.*\\.md$\",\n    Cheatsheets: ~r\"pages/cheatsheets/.*\\.cheatmd$\",\n    \"Mix & OTP\": ~r\"pages/mix-and-otp/.*\\.md$\",\n    \"Anti-patterns\": ~r\"pages/anti-patterns/.*\\.md$\",\n    \"Meta-programming\": ~r\"pages/meta-programming/.*\\.md$\",\n    References: ~r\"pages/references/.*\\.md$\"\n  ],\n  groups_for_docs: [\n    Guards: &(&1[:guard] == true)\n  ],\n  skip_undefined_reference_warnings_on: [\n    \"lib/elixir/pages/references/compatibility-and-deprecations.md\"\n  ],\n  skip_code_autolink_to: [\n    \"Enumerable.List\",\n    \"Inspect.MapSet\"\n  ],\n  formatters: [\"html\", \"markdown\", \"epub\"],\n  groups_for_modules: [\n    # [Kernel, Kernel.SpecialForms],\n\n    \"Data Types\": [\n      Atom,\n      Base,\n      Bitwise,\n      Date,\n      DateTime,\n      Duration,\n      Exception,\n      Float,\n      Function,\n      Integer,\n      JSON,\n      Module,\n      NaiveDateTime,\n      Record,\n      Regex,\n      String,\n      Time,\n      Tuple,\n      URI,\n      Version,\n      Version.Requirement\n    ],\n    \"Collections & Enumerables\": [\n      Access,\n      Date.Range,\n      Enum,\n      Keyword,\n      List,\n      Map,\n      MapSet,\n      Range,\n      Stream\n    ],\n    \"IO & System\": [\n      File,\n      File.Stat,\n      File.Stream,\n      IO,\n      IO.ANSI,\n      IO.Stream,\n      OptionParser,\n      Path,\n      Port,\n      StringIO,\n      System\n    ],\n    Calendar: [\n      Calendar,\n      Calendar.ISO,\n      Calendar.TimeZoneDatabase,\n      Calendar.UTCOnlyTimeZoneDatabase\n    ],\n    \"Processes & Applications\": [\n      Agent,\n      Application,\n      Config,\n      Config.Provider,\n      Config.Reader,\n      DynamicSupervisor,\n      GenServer,\n      Node,\n      PartitionSupervisor,\n      Process,\n      Registry,\n      Supervisor,\n      Task,\n      Task.Supervisor\n    ],\n    Protocols: [\n      Collectable,\n      Enumerable,\n      JSON.Encoder,\n      Inspect,\n      Inspect.Algebra,\n      Inspect.Opts,\n      List.Chars,\n      Protocol,\n      String.Chars\n    ],\n    \"Code & Macros\": [\n      Code,\n      Code.Fragment,\n      Kernel.ParallelCompiler,\n      Macro,\n      Macro.Env\n    ]\n\n    ## Automatically detected groups\n\n    # Deprecated: [\n    #   Behaviour,\n    #   Dict,\n    #   GenEvent,\n    #   HashDict,\n    #   HashSet,\n    #   Set,\n    #   Supervisor.Spec\n    # ]\n  ],\n  before_closing_body_tag: fn\n    :html ->\n      \"\"\"\n      <script defer src=\"https://cdn.jsdelivr.net/npm/mermaid@11.6.0/dist/mermaid.min.js\"></script>\n      <script>\n        let initialized = false;\n\n        window.addEventListener(\"exdoc:loaded\", () => {\n          if (!initialized) {\n            mermaid.initialize({\n              startOnLoad: false,\n              theme: document.body.className.includes(\"dark\") ? \"dark\" : \"default\"\n            });\n            initialized = true;\n          }\n\n          let id = 0;\n          for (const codeEl of document.querySelectorAll(\"pre code.mermaid\")) {\n            const preEl = codeEl.parentElement;\n            const graphDefinition = codeEl.textContent;\n            const graphEl = document.createElement(\"div\");\n            const graphId = \"mermaid-graph-\" + id++;\n            mermaid.render(graphId, graphDefinition).then(({svg, bindFunctions}) => {\n              graphEl.innerHTML = svg;\n              bindFunctions?.(graphEl);\n              preEl.insertAdjacentElement(\"afterend\", graphEl);\n              preEl.remove();\n            });\n          }\n        });\n      </script>\n      \"\"\"\n\n    _ ->\n      \"\"\n  end\n]\n"
  },
  {
    "path": "lib/elixir/scripts/generate_app.escript",
    "content": "#!/usr/bin/env escript\n\n%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% -*- erlang -*-\n\nmain([Version]) ->\n  Source = \"lib/elixir/src/elixir.app.src\",\n  Target = \"lib/elixir/ebin/elixir.app\",\n  {ok, [{application, Name, Props0}]} = file:consult(Source),\n  Ebin = filename:dirname(Target),\n  Files = filelib:wildcard(filename:join(Ebin, \"*.beam\")),\n  Mods = [list_to_atom(filename:basename(F, \".beam\")) || F <- Files],\n  Props1 = lists:keyreplace(modules, 1, Props0, {modules, Mods}),\n  Props = lists:keyreplace(vsn, 1, Props1, {vsn, Version}),\n  AppDef = io_lib:format(\"~tp.~n\", [{application, Name, Props}]),\n  ok = file:write_file(Target, AppDef),\n  io:format(\"Generated ~ts app~n\", [Name]).\n"
  },
  {
    "path": "lib/elixir/scripts/infer.exs",
    "content": "# We disable type inference across modules by setting\n# infer_signatures to [] when compiling Elixir for\n# deterministic reasons. Now we do one additional pass\n# using the locally inferred types to infer all types\n# for stdlib itself.\nparent = self()\nebin = Path.expand(\"../ebin\", __DIR__)\n\n# Validate we are loading Elixir modules and that they are all in place\n[:elixir] = Code.get_compiler_option(:infer_signatures)\n\n[_ | _] =\n  modules =\n  for module <- Application.spec(:elixir, :modules),\n      match?(\"Elixir.\" <> _, Atom.to_string(module)) do\n    module\n  end\n\n# Do a quick sanity check that some modules are defined\ntrue = URI in modules and Version.Requirement in modules\n\n{time, modules_paths} =\n  :timer.tc(fn ->\n    {:ok, checker} = Module.ParallelChecker.start_link()\n\n    try do\n      modules\n      |> Task.async_stream(\n        fn module ->\n          path = Path.join(ebin, \"#{module}.beam\")\n          Module.ParallelChecker.put(parent, checker)\n          cache = Module.ParallelChecker.get()\n          binary = File.read!(path)\n\n          {:ok, {_, [{:debug_info, debug_info}, {_, checker_blob}]}} =\n            :beam_lib.chunks(binary, [:debug_info, ~c\"ExCk\"])\n\n          {:debug_info_v1, _backend, {:elixir_v1, module_map, _specs}} = debug_info\n\n          %{module: module, file: file, attributes: attributes, definitions: definitions} =\n            module_map\n\n          {_, checker} = :erlang.binary_to_term(checker_blob)\n          env = :elixir_env.new()\n\n          # We assume that all private functions have been invoked at this point\n          private =\n            for {fun_arity, kind, _, _} <- definitions, kind in [:defp, :defmacrop], do: fun_arity\n\n          {signatures, _} =\n            Module.Types.infer(module, file, attributes, definitions, private, env, cache)\n\n          checker =\n            update_in(checker.exports, fn exports ->\n              for {fun, info} <- exports do\n                {fun, %{info | sig: Map.get(signatures, fun, info.sig)}}\n              end\n            end)\n\n          [{\"ExCk\", checker_chunk}] = :elixir_erl.checker_chunk(checker, [:deterministic])\n          {:ok, ^module, chunks} = :beam_lib.all_chunks(binary)\n\n          {:ok, new_binary} =\n            chunks\n            |> List.keyreplace(~c\"ExCk\", 0, {~c\"ExCk\", checker_chunk})\n            |> :beam_lib.build_module()\n\n          {module, path, new_binary}\n        end,\n        timeout: :infinity\n      )\n      # Get all results first to avoid writing files\n      # while we are still doing inference\n      |> Enum.to_list()\n      |> Enum.map(fn {:ok, {module, path, new_binary}} ->\n        File.write!(path, new_binary)\n        {module, path}\n      end)\n    after\n      Module.ParallelChecker.stop(checker)\n    end\n  end)\n\nIO.puts(:stderr, [\"Type inferred stdlib in \", Integer.to_string(div(time, 1000)), \"ms\"])\n\n{time, _} =\n  :timer.tc(fn ->\n    # We start a new one so it uses the new cache\n    {:ok, checker} = Module.ParallelChecker.start_link()\n    Module.ParallelChecker.verify(checker, modules_paths)\n  end)\n\nIO.puts(:stderr, [\"Type checked stdlib in \", Integer.to_string(div(time, 1000)), \"ms\"])\n"
  },
  {
    "path": "lib/elixir/scripts/mix_docs.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\n# Returns config for other apps except Elixir\ncanonical = System.fetch_env!(\"CANONICAL\")\n\n[\n  search: [\n    %{\n      name: \"Elixir + libraries\",\n      help: \"Search Elixir, EEx, ExUnit, IEx, Logger, and Mix\",\n      packages:\n        Enum.map(\n          [:elixir, :eex, :ex_unit, :iex, :logger, :mix],\n          &{&1, String.trim(canonical, \"/\")}\n        )\n    },\n    %{\n      name: \"Current project\",\n      help: \"Search only this project\"\n    }\n  ],\n  deps: [\n    eex: \"https://hexdocs.pm/eex/#{canonical}\",\n    elixir: \"https://hexdocs.pm/elixir/#{canonical}\",\n    ex_unit: \"https://hexdocs.pm/ex_unit/#{canonical}\",\n    iex: \"https://hexdocs.pm/iex/#{canonical}\",\n    logger: \"https://hexdocs.pm/logger/#{canonical}\",\n    mix: \"https://hexdocs.pm/mix/#{canonical}\"\n  ],\n  formatters: [\"html\", \"markdown\", \"epub\"],\n  before_closing_body_tag: fn\n    :html ->\n      \"\"\"\n      <script defer src=\"https://cdn.jsdelivr.net/npm/mermaid@11.6.0/dist/mermaid.min.js\"></script>\n      <script>\n        let initialized = false;\n\n        window.addEventListener(\"exdoc:loaded\", () => {\n          if (!initialized) {\n            mermaid.initialize({\n              startOnLoad: false,\n              theme: document.body.className.includes(\"dark\") ? \"dark\" : \"default\"\n            });\n            initialized = true;\n          }\n\n          let id = 0;\n          for (const codeEl of document.querySelectorAll(\"pre code.mermaid\")) {\n            const preEl = codeEl.parentElement;\n            const graphDefinition = codeEl.textContent;\n            const graphEl = document.createElement(\"div\");\n            const graphId = \"mermaid-graph-\" + id++;\n            mermaid.render(graphId, graphDefinition).then(({svg, bindFunctions}) => {\n              graphEl.innerHTML = svg;\n              bindFunctions?.(graphEl);\n              preEl.insertAdjacentElement(\"afterend\", graphEl);\n              preEl.remove();\n            });\n          }\n        });\n      </script>\n      \"\"\"\n\n    _ ->\n      \"\"\n  end\n]\n"
  },
  {
    "path": "lib/elixir/scripts/windows_installer/.gitignore",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ntmp/\n"
  },
  {
    "path": "lib/elixir/scripts/windows_installer/build.sh",
    "content": "#!/bin/bash\n\n# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\n# Usage:\n#\n# With Elixir archive:\n#\n#     ELIXIR_ZIP=Precompiled.zip OTP_VERSION=25.3.2.2 ./build.sh\nset -euo pipefail\n\nmkdir -p tmp\nrm -rf tmp/elixir\nunzip -d \"tmp/elixir\" \"${ELIXIR_ZIP}\"\n\nelixir_version=`cat tmp/elixir/VERSION`\notp_release=`erl -noshell -eval 'io:put_chars(erlang:system_info(otp_release)), halt().'`\notp_version=`erl -noshell -eval '{ok, Vsn} = file:read_file(code:root_dir() ++ \"/releases/\" ++ erlang:system_info(otp_release) ++ \"/OTP_VERSION\"), io:put_chars(Vsn), halt().'`\nelixir_exe=elixir-otp-${otp_release}.exe\n\n# brew install makensis\n# apt install -y nsis\n# choco install -y nsis\nexport PATH=\"/c/Program Files (x86)/NSIS:${PATH}\"\nmakensis \\\n  -X\"OutFile tmp\\\\${elixir_exe}\" \\\n  -DOTP_RELEASE=\"${otp_release}\" \\\n  -DOTP_VERSION=${otp_version} \\\n  -DELIXIR_DIR=tmp\\\\elixir \\\n  -DELIXIR_VERSION=${elixir_version} \\\n  installer.nsi\n\necho \"Installer path: tmp/${elixir_exe}\"\n"
  },
  {
    "path": "lib/elixir/scripts/windows_installer/installer.nsi",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n!include \"MUI2.nsh\"\n!include \"StrFunc.nsh\"\n${Using:StrFunc} UnStrStr\n\nName \"Elixir\"\nManifestDPIAware true\nUnicode True\nInstallDir \"$PROGRAMFILES64\\Elixir\"\n!define MUI_ICON \"assets\\Elixir.ico\"\n!define MUI_UNICON \"assets\\Elixir.ico\"\n\n; Install Page: Install Erlang/OTP\n\nPage custom CheckOTPPageShow CheckOTPPageLeave\n\nvar InstalledOTPRelease\nvar OTPPath\n\nvar Dialog\nvar NoOTPLabel\nvar NoOTPLabelCreated\nvar OTPMismatchLabel\nvar OTPMismatchLabelCreated\nvar DownloadOTPLink\nvar DownloadOTPLinkCreated\nvar VerifyOTPButton\nvar VerifyOTPButtonCreated\nFunction CheckOTPPageShow\n  !insertmacro MUI_HEADER_TEXT \"Checking Erlang/OTP\" \"\"\n\n  nsDialogs::Create 1018\n  Pop $Dialog\n\n  ${If} $Dialog == error\n    Abort\n  ${EndIf}\n\n  Call VerifyOTP\n\n  nsDialogs::Show\nFunctionEnd\n\nFunction VerifyOTP\n  ${If} $NoOTPLabelCreated == \"true\"\n    ShowWindow $NoOTPLabel ${SW_HIDE}\n  ${EndIf}\n\n  ${If} $OTPMismatchLabelCreated == \"true\"\n    ShowWindow $OTPMismatchLabel ${SW_HIDE}\n  ${EndIf}\n\n  ${If} $DownloadOTPLinkCreated == \"true\"\n    ShowWindow $DownloadOTPLink ${SW_HIDE}\n  ${Else}\n    StrCpy $DownloadOTPLinkCreated \"true\"\n    ${NSD_CreateLink}  0 60u 100% 20u \"Download Erlang/OTP ${OTP_RELEASE}\"\n    Pop $DownloadOTPLink\n    ${NSD_OnClick} $DownloadOTPLink OpenOTPDownloads\n    ShowWindow $DownloadOTPLink ${SW_HIDE}\n  ${EndIf}\n\n  ${If} $VerifyOTPButtonCreated == \"true\"\n    ShowWindow $VerifyOTPButton ${SW_HIDE}\n  ${Else}\n    StrCpy $VerifyOTPButtonCreated \"true\"\n    ${NSD_CreateButton} 0 80u 25% 12u \"Verify Erlang/OTP\"\n    Pop $VerifyOTPButton\n    ${NSD_OnClick} $VerifyOTPButton VerifyOTP\n    ShowWindow $VerifyOTPButton ${SW_HIDE}\n  ${EndIf}\n\n  StrCpy $0 0\n  loop:\n    EnumRegKey $1 HKLM \"SOFTWARE\\WOW6432NODE\\Ericsson\\Erlang\" $0\n    StrCmp $1 \"\" done\n    ReadRegStr $1 HKLM \"SOFTWARE\\WOW6432NODE\\Ericsson\\Erlang\\$1\" \"\"\n    StrCpy $OTPPath $1\n    IntOp $0 $0 + 1\n    goto loop\n  done:\n\n  ${If} $OTPPath == \"\"\n    ${If} $NoOTPLabelCreated != \"true\"\n      StrCpy $NoOTPLabelCreated \"true\"\n      ${NSD_CreateLabel} 0 0   100% 20u \"Couldn't find existing Erlang/OTP installation. Click the link below to download and install it before proceeding.\"\n      Pop $NoOTPLabel\n    ${EndIf}\n\n    ShowWindow $NoOTPLabel ${SW_SHOW}\n    ShowWindow $DownloadOTPLink ${SW_SHOW}\n    ShowWindow $VerifyOTPButton ${SW_SHOW}\n\n  ${Else}\n    nsExec::ExecToStack `$OTPPath\\bin\\erl.exe -noinput -eval \"\\\n    io:put_chars(erlang:system_info(otp_release)),\\\n    halt().\"`\n    Pop $0\n    Pop $1\n\n    ${If} $0 == 0\n      StrCpy $InstalledOTPRelease $1\n      ${If} $InstalledOTPRelease == ${OTP_RELEASE}\n        ${NSD_CreateLabel} 0 0 100% 60u \"Found existing Erlang/OTP $InstalledOTPRelease installation at $OTPPath. Please proceed.\"\n\n      ${Else}\n        ${If} $OTPMismatchLabelCreated != \"true\"\n          StrCpy $OTPMismatchLabelCreated \"true\"\n          ${NSD_CreateLabel} 0 0 100% 60u \"Found existing Erlang/OTP $InstalledOTPRelease installation at $OTPPath but this Elixir installer was precompiled for Erlang/OTP ${OTP_RELEASE}. \\\n          $\\r$\\n$\\r$\\nYou can either search for another Elixir installer precompiled for Erlang/OTP $InstalledOTPRelease or download Erlang/OTP ${OTP_RELEASE} and install before proceeding.\"\n          Pop $OTPMismatchLabel\n        ${EndIf}\n\n        ShowWindow $OTPMismatchLabel ${SW_SHOW}\n        ShowWindow $DownloadOTPLink  ${SW_SHOW}\n        ShowWindow $VerifyOTPButton  ${SW_SHOW}\n      ${EndIf}\n    ${Else}\n      SetErrorlevel 5\n      MessageBox MB_ICONSTOP \"Found existing Erlang/OTP installation at $OTPPath but checking it exited with $0: $1\"\n    ${EndIf}\n  ${EndIf}\nFunctionEnd\n\nFunction OpenOTPDownloads\n  ExecShell \"open\" \"https://www.erlang.org/downloads/${OTP_RELEASE}\"\nFunctionEnd\n\nFunction CheckOTPPageLeave\nFunctionEnd\n\n; Install Page: Files\n\n!insertmacro MUI_PAGE_DIRECTORY\n!insertmacro MUI_PAGE_INSTFILES\n\n; Install Page: Finish\n\nPage custom FinishPageShow FinishPageLeave\n\nvar AddOTPToPathCheckbox\nvar AddElixirToPathCheckbox\nFunction FinishPageShow\n  !insertmacro MUI_HEADER_TEXT \"Finish Setup\" \"\"\n\n  nsDialogs::Create 1018\n  Pop $Dialog\n\n  ${If} $Dialog == error\n    Abort\n  ${EndIf}\n\n  ; we add to PATH using erlang, so there must be an OTP installed to do so.\n  ${If} \"$OTPPath\" != \"\"\n    ${NSD_CreateCheckbox} 0 0 195u 10u \"&Add $INSTDIR\\bin to %PATH%\"\n    Pop $AddElixirToPathCheckbox\n    SendMessage $AddElixirToPathCheckbox ${BM_SETCHECK} ${BST_CHECKED} 0\n\n    ${NSD_CreateCheckbox} 0 20u 195u 10u \"&Add $OTPPath\\bin to %PATH%\"\n    Pop $AddOTPToPathCheckbox\n    SendMessage $AddOTPToPathCheckbox ${BM_SETCHECK} ${BST_CHECKED} 0\n\n    ${NSD_CreateLabel} 0 40u 100% 20u \"Note: you need to restart your shell for the environment variable changes to take effect.\"\n  ${EndIf}\n\n  nsDialogs::Show\nFunctionEnd\n\nvar PathsToAdd\nFunction FinishPageLeave\n  ${NSD_GetState} $AddOTPToPathCheckbox $0\n  ${If} $0 <> ${BST_UNCHECKED}\n    StrCpy $PathsToAdd \";$OTPPath\\bin\"\n  ${EndIf}\n\n  ${NSD_GetState} $AddElixirToPathCheckbox $0\n  ${If} $0 <> ${BST_UNCHECKED}\n    StrCpy $PathsToAdd \"$PathsToAdd;$INSTDIR\\bin\"\n  ${EndIf}\n\n  ${If} \"$PathsToAdd\" != \"\"\n    nsExec::ExecToStack `\"$OTPPath\\bin\\escript.exe\" \"$INSTDIR\\update_system_path.erl\" add \"$PathsToAdd\"`\n    Pop $0\n    Pop $1\n    ${If} $0 != 0\n      SetErrorlevel 5\n      MessageBox MB_ICONSTOP \"adding paths failed with $0: $1\"\n      Quit\n    ${EndIf}\n  ${EndIf}\nFunctionEnd\n\nSection \"Install Elixir\" SectionElixir\n  SetOutPath \"$INSTDIR\"\n  File /r \"${ELIXIR_DIR}\\\"\n  File \"assets\\Elixir.ico\"\n  File \"update_system_path.erl\"\n  WriteRegStr   HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Elixir\" \"DisplayName\" \"Elixir\"\n  WriteRegStr   HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Elixir\" \"DisplayVersion\" \"${ELIXIR_VERSION}\"\n  WriteRegStr   HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Elixir\" \"DisplayIcon\" \"$INSTDIR\\Elixir.ico\"\n  WriteRegStr   HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Elixir\" \"Publisher\" \"The Elixir Team\"\n  WriteRegStr   HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Elixir\" \"UninstallString\" '\"$INSTDIR\\Uninstall.exe\"'\n  WriteRegDWORD HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Elixir\" \"NoModify\" 1\n  WriteRegDWORD HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Elixir\" \"NoRepair\" 1\n\n  WriteRegStr   HKLM \"Software\\Elixir\\Elixir\" \"InstallRoot\" \"$INSTDIR\"\n\n  WriteUninstaller \"Uninstall.exe\"\nSectionEnd\n\n; Uninstall Page: Remove from %PATH%\n\nvar RemoveOTPFromPathCheckbox\nvar RemoveElixirFromPathCheckbox\nFunction un.FinishPageShow\n  !insertmacro MUI_HEADER_TEXT \"Remove from %PATH%\" \"\"\n\n  StrCpy $0 0\n  loop:\n    EnumRegKey $1 HKLM \"SOFTWARE\\WOW6432NODE\\Ericsson\\Erlang\" $0\n    StrCmp $1 \"\" done\n    ReadRegStr $1 HKLM \"SOFTWARE\\WOW6432NODE\\Ericsson\\Erlang\\$1\" \"\"\n    StrCpy $OTPPath $1\n    IntOp $0 $0 + 1\n    goto loop\n  done:\n\n  nsDialogs::Create 1018\n  Pop $Dialog\n\n  ${If} $Dialog == error\n    Abort\n  ${EndIf}\n\n  ReadRegStr $0 HKCU \"Environment\" \"Path\"\n\n  ${UnStrStr} $1 \"$0\" \"$INSTDIR\\bin\"\n  ${If} $1 != \"\"\n    ${NSD_CreateCheckbox} 0 0 195u 10u \"&Remove $INSTDIR\\bin from %PATH%\"\n    Pop $RemoveElixirFromPathCheckbox\n    SendMessage $RemoveElixirFromPathCheckbox ${BM_SETCHECK} ${BST_CHECKED} 0\n  ${EndIf}\n\n  ${UnStrStr} $1 \"$0\" \"$OTPPath\\bin\"\n  ${If} $1 != \"\"\n    ${NSD_CreateCheckbox} 0 20u 195u 10u \"&Remove $OTPPath\\bin from %PATH%\"\n    Pop $RemoveOTPFromPathCheckbox\n    SendMessage $RemoveOTPFromPathCheckbox ${BM_SETCHECK} ${BST_CHECKED} 0\n  ${EndIf}\n\n  nsDialogs::Show\nFunctionEnd\n\nvar PathsToRemove\nFunction un.FinishPageLeave\n  ${NSD_GetState} $RemoveOTPFromPathCheckbox $1\n  ${If} $1 <> ${BST_UNCHECKED}\n    StrCpy $PathsToRemove \";$OTPPath\\bin\"\n  ${EndIf}\n\n  ${NSD_GetState} $RemoveElixirFromPathCheckbox $1\n  ${If} $1 <> ${BST_UNCHECKED}\n    StrCpy $PathsToRemove \"$PathsToRemove;$INSTDIR\\bin\"\n  ${EndIf}\n\n  ${If} \"$PathsToRemove\" != \"\"\n    nsExec::ExecToStack `\"$OTPPath\\bin\\escript.exe\" \"$INSTDIR\\update_system_path.erl\" remove \"$PathsToRemove\"`\n    Pop $0\n    Pop $1\n    ${If} $0 != 0\n      SetErrorlevel 5\n      MessageBox MB_ICONSTOP \"removing paths failed with $0: $1\"\n      Quit\n    ${EndIf}\n  ${EndIf}\nFunctionEnd\n\nUninstPage custom un.FinishPageShow un.FinishPageLeave\n\n!insertmacro MUI_UNPAGE_DIRECTORY\n!insertmacro MUI_UNPAGE_INSTFILES\n\nSection \"Uninstall\"\n  RMDir /r \"$INSTDIR\"\n  DeleteRegKey HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Elixir\"\n  DeleteRegKey HKLM \"Software\\Elixir\\Elixir\"\n  DeleteRegKey /ifempty HKLM \"Software\\Elixir\"\nSectionEnd\n\n!insertmacro MUI_LANGUAGE \"English\"\n"
  },
  {
    "path": "lib/elixir/scripts/windows_installer/update_system_path.erl",
    "content": "#!/usr/bin/env escript\n%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n\n%%! -noinput\n\n%% This file is used by the Elixir installer and uninstaller.\nmain([\"add\", \";\" ++ PathsToAdd]) ->\n  {ok, Reg} = win32reg:open([read, write]),\n  ok = win32reg:change_key(Reg, \"\\\\hkey_current_user\\\\environment\"),\n  {ok, SystemPath} = win32reg:value(Reg, \"path\"),\n\n  NewSystemPath =\n    lists:foldl(\n      fun(Elem, Acc) ->\n        Elem ++ \";\" ++\n          binary_to_list(\n            iolist_to_binary(\n              string:replace(Acc, Elem ++ \";\", \"\", all)))\n      end,\n      SystemPath,\n      string:split(PathsToAdd, \";\", all)\n    ),\n\n  ok = win32reg:set_value(Reg, \"Path\", NewSystemPath),\n  ok;\n\nmain([\"remove\", \";\" ++ PathsToRemove]) ->\n  {ok, Reg} = win32reg:open([read, write]),\n  ok = win32reg:change_key(Reg, \"\\\\hkey_current_user\\\\environment\"),\n  {ok, SystemPath} = win32reg:value(Reg, \"path\"),\n\n  NewSystemPath =\n    lists:foldl(\n      fun(Elem, Acc) ->\n        binary_to_list(\n          iolist_to_binary(\n            string:replace(Acc, Elem ++ \";\", \"\", all)))\n      end,\n      SystemPath,\n      string:split(PathsToRemove, \";\", all)\n    ),\n\n  ok = win32reg:set_value(Reg, \"Path\", NewSystemPath),\n  ok.\n"
  },
  {
    "path": "lib/elixir/src/elixir.app.src",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n{application, elixir,\n[{description, \"elixir\"},\n {vsn, '$will-be-replaced'},\n {modules, '$will-be-replaced'},\n {registered, [elixir_sup, elixir_config, elixir_code_server]},\n {applications, [kernel,stdlib,compiler]},\n {mod, {elixir,[]}},\n {env, [\n  {ansi_syntax_colors, [\n    {atom, cyan},\n    {binary, default_color},\n    {boolean, magenta},\n    {charlist, yellow},\n    {list, default_color},\n    {map, default_color},\n    {nil, magenta},\n    {number, yellow},\n    {string, green},\n    {tuple, default_color},\n    {variable, light_cyan},\n    {call, default_color},\n    {operator, default_color}\n  ]},\n  {check_endianness, true},\n  {dbg_callback, {'Elixir.Macro', dbg, []}},\n  {time_zone_database, 'Elixir.Calendar.UTCOnlyTimeZoneDatabase'}\n ]}\n]}.\n"
  },
  {
    "path": "lib/elixir/src/elixir.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Main entry point for Elixir functions. All of those functions are\n%% private to the Elixir compiler and reserved to be used by Elixir only.\n-module(elixir).\n-behaviour(application).\n-export([start_cli/0, start/0]).\n-export([start/2, stop/1, config_change/3]).\n-export([\n  string_to_tokens/5, tokens_to_quoted/3, string_to_quoted/5, 'string_to_quoted!'/5,\n  env_for_eval/1, quoted_to_erl/2, eval_forms/3, eval_forms/4, eval_quoted/3, eval_quoted/4,\n  erl_eval/3, eval_local_handler/2, eval_external_handler/3, emit_warnings/3\n]).\n-include(\"elixir.hrl\").\n-define(system, 'Elixir.System').\n-define(elixir_eval_env, {elixir, eval_env}).\n\n%% Top level types\n%% TODO: Remove char_list type on v2.0\n-export_type([charlist/0, char_list/0, nonempty_charlist/0, struct/0, as_boolean/1, keyword/0, keyword/1]).\n-type charlist() :: string().\n-type char_list() :: string().\n-type nonempty_charlist() :: nonempty_string().\n-type as_boolean(T) :: T.\n-type keyword() :: [{atom(), any()}].\n-type keyword(T) :: [{atom(), T}].\n-type struct() :: #{'__struct__' := atom(), atom() => any()}.\n\n%% OTP Application API\n\nstart(_Type, _Args) ->\n  _OTP = parse_otp_release(),\n  preload_common_modules(),\n  ok = io:setopts(standard_io, [binary]),\n  check_file_encoding(file:native_name_encoding()),\n\n  case init:get_argument(elixir_root) of\n    {ok, [[Root]]} ->\n      code:add_pathsa([\n        Root ++ \"/eex/ebin\",\n        Root ++ \"/ex_unit/ebin\",\n        Root ++ \"/iex/ebin\",\n        Root ++ \"/logger/ebin\",\n        Root ++ \"/mix/ebin\",\n        Root ++ \"/elixir/ebin\"\n      ], cache);\n    _ ->\n      ok\n  end,\n\n  case application:get_env(elixir, check_endianness, true) of\n    true  -> check_endianness();\n    false -> ok\n  end,\n\n  case application:get_env(elixir, ansi_enabled) of\n    {ok, _} ->\n      ok;\n\n    undefined ->\n      application:set_env(elixir, ansi_enabled, prim_tty:isatty(stdout) == true)\n  end,\n\n  Tokenizer = case code:ensure_loaded('Elixir.String.Tokenizer') of\n    {module, Mod} -> Mod;\n    _ -> elixir_tokenizer\n  end,\n\n  URIConfig = [\n    {{uri, <<\"ftp\">>}, 21},\n    {{uri, <<\"sftp\">>}, 22},\n    {{uri, <<\"tftp\">>}, 69},\n    {{uri, <<\"http\">>}, 80},\n    {{uri, <<\"https\">>}, 443},\n    {{uri, <<\"ldap\">>}, 389},\n    {{uri, <<\"ws\">>}, 80},\n    {{uri, <<\"wss\">>}, 443}\n  ],\n\n  Config = [\n    %% ARGV options\n    {at_exit, []},\n    {argv, []},\n    {no_halt, false},\n\n    %% Compiler options\n    {debug_info, true},\n    {docs, true},\n    {ignore_already_consolidated, false},\n    {ignore_module_conflict, false},\n    {infer_signatures, [elixir]},\n    {module_definition, compiled},\n    {no_warn_undefined, []},\n    {on_undefined_variable, raise},\n    {parser_options, [{columns, true}]},\n    {relative_paths, true},\n    {tracers, []}\n    | URIConfig\n  ],\n\n  elixir_config:static(#{bootstrap => false, identifier_tokenizer => Tokenizer}),\n  Tab = elixir_config:new(Config),\n\n  case elixir_sup:start_link() of\n    {ok, Sup} ->\n      {ok, Sup, Tab};\n    {error, _Reason} = Error ->\n      elixir_config:delete(Tab),\n      Error\n  end.\n\nstop(Tab) ->\n  elixir_config:delete(Tab).\n\nconfig_change(_Changed, _New, _Remove) ->\n  ok.\n\npreload_common_modules() ->\n  %% We attempt to load those modules here so throughout\n  %% the codebase we can avoid code:ensure_loaded/1 checks.\n  _ = code:ensure_loaded('Elixir.Kernel'),\n  _ = code:ensure_loaded('Elixir.Macro.Env'),\n  ok.\n\nparse_otp_release() ->\n  %% Whenever we change this check, we should also change Makefile.\n  case string:to_integer(erlang:system_info(otp_release)) of\n    {Num, _} when Num >= 27 ->\n      case Num == 28 andalso (code:ensure_loaded(re) == {module, re}) andalso not erlang:function_exported(re, import, 1) of\n        true ->\n          io:format(standard_error,\n            \"warning! Erlang/OTP 28.0 detected.~n\"\n            \"Regexes will be re-compiled from source at runtime, which will cause degraded performance.~n\"\n            \"This can be fixed by using Erlang OTP 28.1+ or 27.~n\"\n          , []);\n        false ->\n          ok\n      end,\n      Num;\n    _ ->\n      io:format(standard_error, \"ERROR! Unsupported Erlang/OTP version, expected Erlang/OTP 27+~n\", []),\n      erlang:halt(1)\n  end.\n\ncheck_endianness() ->\n  case code:ensure_loaded(?system) of\n    {module, ?system} ->\n      Endianness = ?system:endianness(),\n      case ?system:compiled_endianness() of\n        Endianness ->\n          ok;\n        _ ->\n          io:format(standard_error,\n            \"warning: Elixir is running in a system with a different endianness than the one its \"\n            \"source code was compiled in. Please make sure Elixir and all source files were compiled \"\n            \"in a machine with the same endianness as the current one: ~ts~n\", [Endianness])\n      end;\n    {error, _} ->\n      ok\n  end.\n\ncheck_file_encoding(Encoding) ->\n  case Encoding of\n    latin1 ->\n      io:format(standard_error,\n        \"warning: the VM is running with native name encoding of latin1 which may cause \"\n        \"Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 \"\n        \"(which can be verified by running \\\"locale\\\" in your shell) or set the \"\n        \"ELIXIR_ERL_OPTIONS=\\\"+fnu\\\" environment variable~n\", []);\n    _ ->\n      ok\n  end.\n\n%% Boot and process given options. Invoked by Elixir's script.\n\nstart() ->\n  user_drv:start(#{initial_shell => iex:shell()}).\n\nstart_cli() ->\n  {ok, _} = application:ensure_all_started(elixir),\n\n  %% We start the Logger so tools that depend on Elixir\n  %% always have the Logger directly accessible. However\n  %% Logger is not a dependency of the Elixir application,\n  %% which means releases that want to use Logger must\n  %% always list it as part of its applications.\n  _ = case code:ensure_loaded('Elixir.Logger') of\n    {module, _} -> application:start(logger);\n    {error, _}  -> ok\n  end,\n\n  'Elixir.Kernel.CLI':main(init:get_plain_arguments()).\n\n%% EVAL HOOKS\n\nenv_for_eval(#{'__struct__' := 'Elixir.Macro.Env', lexical_tracker := Pid} = Env) when map_size(Env) == 15 ->\n  NewEnv = Env#{\n    context := nil,\n    macro_aliases := [],\n    versioned_vars := #{}\n  },\n\n  case is_pid(Pid) of\n    true ->\n      case is_process_alive(Pid) of\n        true ->\n          NewEnv;\n        false ->\n          'Elixir.IO':warn(\n            <<\"an __ENV__ with outdated compilation information was given to eval, \"\n              \"call Macro.Env.prune_compile_info/1 to prune it\">>\n          ),\n          NewEnv#{lexical_tracker := nil, tracers := []}\n      end;\n    false ->\n      NewEnv#{tracers := []}\n  end;\nenv_for_eval(Opts) when is_list(Opts) ->\n  Env = elixir_env:new(),\n  Line = elixir_utils:get_line(Opts, Env),\n  File = elixir_utils:get_file(Opts, Env),\n\n  Module = case lists:keyfind(module, 1, Opts) of\n    {module, ModuleOpt} when is_atom(ModuleOpt) -> ModuleOpt;\n    false -> nil\n  end,\n\n  FA = case lists:keyfind(function, 1, Opts) of\n    {function, {Function, Arity}} when is_atom(Function), is_integer(Arity) -> {Function, Arity};\n    {function, nil} -> nil;\n    false -> nil\n  end,\n\n  TempTracers = case lists:keyfind(tracers, 1, Opts) of\n    {tracers, TracersOpt} when is_list(TracersOpt) -> TracersOpt;\n    false -> []\n  end,\n\n  %% TODO: Remove the following deprecations in future releases\n  Aliases = case lists:keyfind(aliases, 1, Opts) of\n    {aliases, AliasesOpt} when is_list(AliasesOpt) ->\n      'Elixir.IO':warn(<<\":aliases option in eval is deprecated\">>),\n      AliasesOpt;\n    false ->\n      ?key(Env, aliases)\n  end,\n\n  Requires = case lists:keyfind(requires, 1, Opts) of\n    {requires, RequiresOpt} when is_list(RequiresOpt) ->\n      'Elixir.IO':warn(<<\":requires option in eval is deprecated\">>),\n      ordsets:from_list(RequiresOpt);\n    false ->\n      ?key(Env, requires)\n  end,\n\n  Functions = case lists:keyfind(functions, 1, Opts) of\n    {functions, FunctionsOpt} when is_list(FunctionsOpt) ->\n      'Elixir.IO':warn(<<\":functions option in eval is deprecated\">>),\n      FunctionsOpt;\n    false ->\n      ?key(Env, functions)\n  end,\n\n  Macros = case lists:keyfind(macros, 1, Opts) of\n    {macros, MacrosOpt} when is_list(MacrosOpt) ->\n      'Elixir.IO':warn(<<\":macros option in eval is deprecated\">>),\n      MacrosOpt;\n    false ->\n      ?key(Env, macros)\n  end,\n\n  %% If there is a dead PID or lexical tracker is nil,\n  %% we assume the tracers also cannot be (re)used.\n  {LexicalTracker, Tracers} = case lists:keyfind(lexical_tracker, 1, Opts) of\n    {lexical_tracker, Pid} when is_pid(Pid) ->\n      'Elixir.IO':warn(<<\":lexical_tracker option in eval is deprecated\">>),\n      case is_process_alive(Pid) of\n        true -> {Pid, TempTracers};\n        false -> {nil, []}\n      end;\n    {lexical_tracker, nil} ->\n      'Elixir.IO':warn(<<\":lexical_tracker option in eval is deprecated\">>),\n      {nil, []};\n    false ->\n      {nil, TempTracers}\n  end,\n\n  Env#{\n    file := File, module := Module, function := FA, tracers := Tracers,\n    macros := Macros, functions := Functions, lexical_tracker := LexicalTracker,\n    requires := Requires, aliases := Aliases, line := Line\n  }.\n\n%% Quoted evaluation\n\neval_quoted(Tree, Binding, E) ->\n  eval_quoted(Tree, Binding, E, []).\neval_quoted(Tree, Binding, #{line := Line} = E, Opts) ->\n  eval_forms(elixir_quote:linify(Line, line, Tree), Binding, E, Opts).\n\neval_forms(Tree, Binding, OrigE) ->\n  eval_forms(Tree, Binding, OrigE, []).\neval_forms(Tree, Binding, OrigE, Opts) ->\n  Prune = proplists:get_value(prune_binding, Opts, false),\n  case proplists:get_value(dbg_callback, Opts) of\n    undefined -> ok;\n    DbgCallback -> erlang:put({elixir, dbg_callback}, DbgCallback)\n  end,\n  try\n    {ExVars, ErlVars, ErlBinding} = elixir_erl_var:load_binding(Binding, Prune),\n    E = elixir_env:with_vars(OrigE, ExVars),\n    ExS = elixir_env:env_to_ex(E),\n    ErlS = elixir_erl_var:from_env(E, ErlVars),\n    {Erl, NewErlS, NewExS, NewE} = quoted_to_erl(Tree, ErlS, ExS, E),\n\n    case Erl of\n      {Literal, _, Value} when Literal == atom; Literal == float; Literal == integer ->\n        if\n          Prune -> {Value, [], NewE#{versioned_vars := #{}}};\n          true -> {Value, Binding, NewE}\n        end;\n\n      _  ->\n        {value, Value, NewBinding} = erl_eval(Erl, ErlBinding, NewE),\n        PruneBefore = if Prune -> length(Binding); true -> -1 end,\n\n        {DumpedBinding, DumpedVars} =\n          elixir_erl_var:dump_binding(NewBinding, NewErlS, NewExS, PruneBefore),\n\n        {Value, DumpedBinding, NewE#{versioned_vars := DumpedVars}}\n    end\n  after\n    erlang:erase({elixir, dbg_callback})\n  end.\n\n%% Evaluate Erlang code with careful handling of local and external functions\nerl_eval(Expr, Binding, Env) ->\n  %% We use remote names so eval works across Elixir versions\n  LocalHandler = {value, fun ?MODULE:eval_local_handler/2},\n  ExternalHandler = {value, fun ?MODULE:eval_external_handler/3},\n\n  try\n    %% ?elixir_eval_env is used by the external handler.\n    %%\n    %% The reason why we use the process dictionary to pass the environment\n    %% is because we want to avoid passing closures to erl_eval, as that\n    %% would effectively tie the eval code to the Elixir version and it is\n    %% best if it depends solely on Erlang/OTP.\n    %%\n    %% The downside is that functions that escape the eval context will no\n    %% longer have the original environment they came from.\n    erlang:put(?elixir_eval_env, Env),\n    erl_eval:expr(Expr, Binding, LocalHandler, ExternalHandler)\n  after\n    erlang:erase(?elixir_eval_env)\n  end.\n\neval_local_handler(FunName, Args) ->\n  {current_stacktrace, Stack} = erlang:process_info(self(), current_stacktrace),\n  Opts = [{module, nil}, {function, FunName}, {arity, length(Args)}, {reason, 'undefined local'}],\n  Exception = 'Elixir.UndefinedFunctionError':exception(Opts),\n  erlang:raise(error, Exception, Stack).\n\neval_external_handler(Ann, FunOrModFun, Args) ->\n  try\n    case FunOrModFun of\n      {Mod, Fun} -> apply(Mod, Fun, Args);\n      Fun -> apply(Fun, Args)\n    end\n  catch\n    Kind:Reason:Stacktrace ->\n      %% Take everything up to the Elixir module\n      Pruned =\n        lists:takewhile(fun\n          ({elixir,_,_,_}) -> false;\n          (_) -> true\n        end, Stacktrace),\n\n      Caller =\n        lists:dropwhile(fun\n          ({elixir,_,_,_}) -> false;\n          (_) -> true\n        end, Stacktrace),\n\n      %% Now we prune any shared code path from erl_eval\n      {current_stacktrace, Current} =\n        erlang:process_info(self(), current_stacktrace),\n\n      %% We need to make sure that we don't generate more\n      %% frames than supported. So we do our best to drop\n      %% from the Caller, but if the caller has no frames,\n      %% we need to drop from Pruned.\n      {DroppedCaller, ToDrop} =\n        case Caller of\n          [] -> {[], true};\n          _ -> {lists:droplast(Caller), false}\n        end,\n\n      Reversed = drop_common(lists:reverse(Current), lists:reverse(Pruned), ToDrop),\n\n      %% Add file+line information at the bottom\n      Bottom =\n        case erlang:get(?elixir_eval_env) of\n          #{'__struct__' := 'Elixir.Macro.Env'} = E ->\n            'Elixir.Macro.Env':stacktrace(E#{line := erl_anno:line(Ann)});\n          _ ->\n            []\n        end,\n\n      Custom = lists:reverse(Bottom ++ Reversed, DroppedCaller),\n      erlang:raise(Kind, Reason, Custom)\n  end.\n\n%% We need to check if we have dropped any frames.\n%% If we have not dropped frames, then we need to drop one\n%% at the end so we can put the elixir_eval frame in. If\n%% we have more traces then depth, Erlang would discard\n%% the whole stacktrace.\ndrop_common([H | T1], [H | T2], _ToDrop) -> drop_common(T1, T2, false);\ndrop_common([_ | T1], T2, ToDrop) -> drop_common(T1, T2, ToDrop);\ndrop_common([], [{?MODULE, _, _, _} | T2], _ToDrop) -> T2;\ndrop_common([], [_ | T2], true) -> T2;\ndrop_common([], T2, _) -> T2.\n\n%% Converts a quoted expression to Erlang abstract format\n\nquoted_to_erl(Quoted, E) ->\n  {_, ErlS} = elixir_erl_var:from_env(E),\n  ExS = elixir_env:env_to_ex(E),\n  quoted_to_erl(Quoted, ErlS, ExS, E).\n\nquoted_to_erl(Quoted, ErlS, ExS, Env) ->\n  {Expanded, NewExS, NewEnv} =\n    elixir_expand:expand(Quoted, ExS, Env),\n  {Erl, NewErlS} = elixir_erl_pass:translate(Expanded, erl_anno:new(?key(Env, line)), ErlS),\n  {Erl, NewErlS, NewExS, NewEnv}.\n\n%% Converts a given string (charlist) into quote expression\n\nstring_to_tokens(String, StartLine, StartColumn, File, Opts) when is_integer(StartLine), is_binary(File) ->\n  case elixir_tokenizer:tokenize(String, StartLine, StartColumn, Opts) of\n    {ok, _Line, _Column, Warnings, Tokens, Terminators} ->\n      {ok, lists:reverse(Tokens, Terminators), Warnings};\n    {error, Info, _Rest, _Warnings, _SoFar} ->\n      {error, elixir_tokenizer:format_error(Info)}\n  end.\n\ntokens_to_quoted(Tokens, _WarningFile, Opts) ->\n  put_parsing_state(Opts),\n\n  try elixir_parser:parse(Tokens) of\n    {ok, Forms} ->\n      {ok, Forms, get(elixir_parser_warnings)};\n    {error, {Line, _, [{ErrorPrefix, ErrorSuffix}, Token]}} ->\n      {error, {parser_location(Line), {to_binary(ErrorPrefix), to_binary(ErrorSuffix)}, to_binary(Token)}};\n    {error, {Line, _, [Error, Token]}} ->\n      {error, {parser_location(Line), to_binary(Error), to_binary(Token)}}\n  after\n    erase(elixir_parser_warnings),\n    erase(elixir_parser_columns),\n    erase(elixir_token_metadata),\n    erase(elixir_literal_encoder)\n  end.\n\nemit_warnings(Warnings, File, Opts) ->\n  (Warnings /= []) andalso\n    (lists:keyfind(emit_warnings, 1, Opts) /= {emit_warnings, false}) andalso\n    [elixir_errors:erl_warn(L, File, M) || {L, M} <- lists:reverse(Warnings)].\n\nparser_location({Line, Column, _}) ->\n  [{line, Line}, {column, Column}];\nparser_location(Meta) ->\n  Line =\n    case lists:keyfind(line, 1, Meta) of\n      {line, L} -> L;\n      false -> 0\n    end,\n\n  case lists:keyfind(column, 1, Meta) of\n    {column, C} -> [{line, Line}, {column, C}];\n    false -> [{line, Line}]\n  end.\n\nstring_to_quoted(String, StartLine, StartColumn, File, Opts) ->\n  case string_to_tokens(String, StartLine, StartColumn, File, Opts) of\n    {ok, Tokens, Warnings1} ->\n      emit_warnings(Warnings1, File, Opts),\n\n      case tokens_to_quoted(Tokens, File, Opts) of\n        {ok, Forms, Warnings2} ->\n          emit_warnings(Warnings2, File, Opts),\n          {ok, Forms};\n\n        {error, Error} ->\n          {error, Error}\n      end;\n\n    {error, Error} ->\n      {error, Error}\n  end.\n\n'string_to_quoted!'(String, StartLine, StartColumn, File, Opts) ->\n  case string_to_quoted(String, StartLine, StartColumn, File, Opts) of\n    {ok, Forms} ->\n      Forms;\n    {error, {Meta, Error, Token}} ->\n      Indentation = proplists:get_value(indentation, Opts, 0),\n      Input = {String, StartLine, StartColumn, Indentation},\n      elixir_errors:parse_error(Meta, File, Error, Token, Input)\n  end.\n\nto_binary(List) when is_list(List) -> elixir_utils:characters_to_binary(List);\nto_binary(Atom) when is_atom(Atom) -> atom_to_binary(Atom).\n\nput_parsing_state(Opts) ->\n  LiteralEncoder =\n    case lists:keyfind(literal_encoder, 1, Opts) of\n      {literal_encoder, Fun} -> Fun;\n      false -> false\n    end,\n  TokenMetadata = lists:keyfind(token_metadata, 1, Opts) == {token_metadata, true},\n  Columns = lists:keyfind(columns, 1, Opts) == {columns, true},\n  put(elixir_parser_warnings, []),\n  put(elixir_parser_columns, Columns),\n  put(elixir_token_metadata, TokenMetadata),\n  put(elixir_literal_encoder, LiteralEncoder).\n"
  },
  {
    "path": "lib/elixir/src/elixir.hrl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-define(key(M, K), map_get(K, M)).\n-define(ann(Meta), elixir_erl:get_ann(Meta)).\n-define(line(Meta), elixir_utils:get_line(Meta)).\n-define(generated(Meta), elixir_utils:generated(Meta)).\n-define(var_context, ?MODULE).\n-define(remote(Ann, Module, Function, Args), {call, Ann, {remote, Ann, {atom, Ann, Module}, {atom, Ann, Function}}, Args}).\n-define(tracker, 'Elixir.Kernel.LexicalTracker').\n\n-record(elixir_ex, {\n  %% Stores that the function will fail, which can be used\n  %% to run more expensive checks upfront\n  tainted_function=false,\n  %% Stores if __CALLER__ is allowed\n  caller=false,\n  %% Stores the variables available before a match.\n  %% May be one of:\n  %%\n  %%   * {Read, Cycle :: #{}, Meta :: Counter | {bitsize, Original}}\n  %%   * pin\n  %%   * none.\n  %%\n  %% The cycle is used to detect cyclic dependencies between\n  %% variables in a match.\n  %%\n  %% The bitsize is used when dealing with bitstring modifiers,\n  %% as they allow guards but also support the pin operator.\n  prematch=none,\n  %% Stores if __STACKTRACE__ is allowed\n  stacktrace=false,\n  %% A map of unused vars and a version counter for vars\n  unused={#{}, 0},\n  %% A list of modules defined in functions (runtime)\n  runtime_modules=[],\n  %% A tuple with maps of read and optional write current vars.\n  %% Read variables is all defined variables. Write variables\n  %% stores the variables that have been made available (written\n  %% to) but cannot be currently read. This is used in two occasions:\n  %%\n  %%   * To store variables graphs inside = in patterns\n  %%\n  %%   * To store variables defined inside calls. For example,\n  %%     if you write foo(a = 123), the value of `a` cannot be\n  %%     read in the following argument, only after the call\n  %%\n  vars={#{}, false}\n}).\n\n-record(elixir_erl, {\n  %% Can be match, guards or nil\n  context=nil,\n  %% Extra information about the context, like pin_guard and map_key\n  extra=nil,\n  %% When true, it means caller was invoked\n  caller=false,\n  %% Maps of defined variables and their alias\n  var_names=#{},\n  %% Extra guards from args expansion\n  extra_guards=[],\n  %% A map counting the variables defined\n  counter=#{},\n  %% A boolean to control if captures should be expanded\n  expand_captures=false,\n  %% Holds information about the stacktrace variable\n  stacktrace=nil\n}).\n\n-record(elixir_tokenizer, {\n  terminators=[],\n  unescape=true,\n  cursor_completion=false,\n  existing_atoms_only=false,\n  static_atoms_encoder=nil,\n  preserve_comments=nil,\n  identifier_tokenizer=elixir_tokenizer,\n  ascii_identifiers_only=true,\n  indentation=0,\n  column=1,\n  mismatch_hints=[],\n  warnings=[]\n}).\n"
  },
  {
    "path": "lib/elixir/src/elixir_aliases.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_aliases).\n-export([inspect/1, concat/1, safe_concat/1, format_error/1,\n         ensure_loaded/3, expand/4, expand_or_concat/4, alias/6, require/5]).\n-include(\"elixir.hrl\").\n\ninspect(Atom) when is_atom(Atom) ->\n  case elixir_config:is_bootstrap() of\n    true  -> atom_to_binary(Atom);\n    false -> 'Elixir.Macro':inspect_atom(literal, Atom)\n  end.\n\nrequire(Meta, Ref, Opts, E, Trace) ->\n  Trace andalso elixir_env:trace({require, Meta, Ref, Opts}, E),\n  E#{requires := ordsets:add_element(Ref, ?key(E, requires))}.\n\nalias(Meta, Ref, IncludeByDefault, Opts, E, Trace) ->\n  #{aliases := Aliases, macro_aliases := MacroAliases} = E,\n\n  case expand_as(lists:keyfind(as, 1, Opts), IncludeByDefault, Ref) of\n    {ok, Ref} ->\n      {ok, false,\n       E#{aliases := remove_alias(Ref, Aliases),\n          macro_aliases := remove_macro_alias(Meta, Ref, MacroAliases)}};\n\n    {ok, New} ->\n      Trace andalso elixir_env:trace({alias, Meta, Ref, New, Opts}, E),\n      {ok, New,\n       E#{aliases := store_alias(New, Ref, Aliases),\n          macro_aliases := store_macro_alias(Meta, New, Ref, MacroAliases)}};\n\n    none ->\n      {ok, false, E};\n\n    {error, Reason} ->\n      {error, Reason}\n  end.\n\nexpand_as({as, Atom}, _IncludeByDefault, _Ref) when is_atom(Atom), not is_boolean(Atom) ->\n  case atom_to_list(Atom) of\n    \"Elixir.\" ++ ([FirstLetter | _] = Rest) when FirstLetter >= $A, FirstLetter =< $Z ->\n      case string:tokens(Rest, \".\") of\n        [_] ->\n          {ok, Atom};\n        _ ->\n          {error, {invalid_alias_for_as, nested_alias, Atom}}\n      end;\n    _ ->\n      {error, {invalid_alias_for_as, not_alias, Atom}}\n  end;\nexpand_as({as, Other}, _IncludeByDefault, _Ref) ->\n  {error, {invalid_alias_for_as, not_alias, Other}};\nexpand_as(false, true, Ref) ->\n  case atom_to_list(Ref) of\n    (\"Elixir.\" ++ [FirstLetter | _]) = List when FirstLetter >= $A, FirstLetter =< $Z ->\n      Last = last(lists:reverse(List), []),\n      {ok, list_to_atom(\"Elixir.\" ++ Last)};\n    _ ->\n      {error, {invalid_alias_module, Ref}}\n  end;\nexpand_as(false, false, _Ref) ->\n  none.\n\nlast([$. | _], Acc) -> Acc;\nlast([H | T], Acc)  -> last(T, [H | Acc]);\nlast([], Acc)       -> Acc.\n\nstore_alias(New, Old, Aliases) ->\n  lists:keystore(New, 1, Aliases, {New, Old}).\n\nstore_macro_alias(Meta, New, Old, Aliases) ->\n  case lists:keyfind(counter, 1, Meta) of\n    {counter, Counter} ->\n      lists:keystore(New, 1, Aliases, {New, {Counter, Old}});\n    false ->\n      Aliases\n  end.\n\nremove_alias(Atom, Aliases) ->\n  lists:keydelete(Atom, 1, Aliases).\n\nremove_macro_alias(Meta, Atom, Aliases) ->\n  case lists:keyfind(counter, 1, Meta) of\n    {counter, _Counter} ->\n      lists:keydelete(Atom, 1, Aliases);\n    false ->\n      Aliases\n  end.\n\n%% Expand an alias. It returns an atom (meaning that there\n%% was an expansion) or a list of atoms.\n\nexpand(_Meta, ['Elixir' | _] = List, _E, _Trace) ->\n  List;\n\nexpand(_Meta, [H | _] = List, _E, _Trace) when not is_atom(H) ->\n  List;\n\nexpand(Meta, List, #{aliases := Aliases, macro_aliases := MacroAliases} = E, Trace) ->\n  case lists:keyfind(alias, 1, Meta) of\n    {alias, false} ->\n      expand(Meta, List, MacroAliases, E, Trace);\n    {alias, Atom} when is_atom(Atom) ->\n      Atom;\n    false ->\n      expand(Meta, List, Aliases, E, Trace)\n  end.\n\nexpand(Meta, [H | T], Aliases, E, Trace) ->\n  Lookup  = list_to_atom(\"Elixir.\" ++ atom_to_list(H)),\n\n  Counter = case lists:keyfind(counter, 1, Meta) of\n    {counter, C} -> C;\n    _ -> nil\n  end,\n\n  case lookup(Lookup, Aliases, Counter) of\n    Lookup -> [H | T];\n    Atom ->\n      Trace andalso elixir_env:trace({alias_expansion, Meta, Lookup, Atom}, E),\n      case T of\n        [] -> Atom;\n        _  -> concat([Atom | T])\n      end\n  end.\n\n%% Expands or concat if possible.\n\nexpand_or_concat(Meta, List, E, Trace) ->\n  case expand(Meta, List, E, Trace) of\n    [H | T] when is_atom(H) -> concat([H | T]);\n    AtomOrList -> AtomOrList\n  end.\n\n%% Ensure a module is loaded before its usage.\n\n%% Skip Kernel verification for bootstrap purposes.\nensure_loaded(_Meta, 'Elixir.Kernel', _E) ->\n  ok;\nensure_loaded(Meta, Module, #{module := Module} = E) ->\n  elixir_errors:file_error(Meta, E, ?MODULE, {circular_module, Module});\nensure_loaded(Meta, Module, E) ->\n  case code:ensure_loaded(Module) of\n    {module, Module} ->\n      ok;\n\n    _ ->\n      case wait_for_module(Module, Meta, E) of\n        found ->\n          ok;\n\n        Wait ->\n          Kind = case lists:member(Module, ?key(E, context_modules)) of\n            true -> scheduled_module;\n            false when Wait == deadlock -> deadlock_module;\n            false -> unloaded_module\n          end,\n\n          elixir_errors:file_error(Meta, E, ?MODULE, {Kind, Module})\n      end\n  end.\n\nwait_for_module(Module, Meta, E) ->\n  case erlang:get(elixir_compiler_info) of\n    undefined -> not_found;\n    _ -> 'Elixir.Kernel.ErrorHandler':ensure_compiled(Module, module, hard, elixir_utils:get_line(Meta, E))\n  end.\n\n%% Receives a list of atoms, binaries or lists\n%% representing modules and concatenates them.\n\nconcat(Args)      -> binary_to_atom(do_concat(Args), utf8).\nsafe_concat(Args) -> binary_to_existing_atom(do_concat(Args), utf8).\n\ndo_concat([H | T]) when is_atom(H), H /= nil ->\n  do_concat([atom_to_binary(H) | T]);\ndo_concat([<<\"Elixir.\", _/binary>>=H | T]) ->\n  do_concat(T, H);\ndo_concat([<<\"Elixir\">>=H | T]) ->\n  do_concat(T, H);\ndo_concat(T) ->\n  do_concat(T, <<\"Elixir\">>).\n\ndo_concat([nil | T], Acc) ->\n  do_concat(T, Acc);\ndo_concat([H | T], Acc) when is_atom(H) ->\n  do_concat(T, <<Acc/binary, $., (to_partial(atom_to_binary(H)))/binary>>);\ndo_concat([H | T], Acc) when is_binary(H) ->\n  do_concat(T, <<Acc/binary, $., (to_partial(H))/binary>>);\ndo_concat([], Acc) ->\n  Acc.\n\nto_partial(<<\"Elixir.\", Arg/binary>>) -> Arg;\nto_partial(<<\".\", Arg/binary>>)       -> Arg;\nto_partial(Arg) when is_binary(Arg)   -> Arg.\n\n%% Lookup an alias in the current scope.\n\nlookup(Else, List, Counter) ->\n  case lists:keyfind(Else, 1, List) of\n    {Else, {Counter, Value}} -> Value;\n    {Else, Value} when is_atom(Value) -> Value;\n    _ -> Else\n  end.\n\n%% Errors\n\nformat_error({invalid_alias_module, Ref}) ->\n  io_lib:format(\"alias cannot be inferred automatically for module: ~ts, please use the :as option. Implicit aliasing is only supported with Elixir modules\",\n                ['Elixir.Macro':to_string(Ref)]);\n\nformat_error({invalid_alias_for_as, Reason, Value}) ->\n  ExpectedGot =\n    case Reason of\n      not_alias -> \"expected an alias, got\";\n      nested_alias -> \"expected a simple alias, got nested alias\"\n    end,\n  io_lib:format(\"invalid value for option :as, ~ts: ~ts\",\n                [ExpectedGot, 'Elixir.Macro':to_string(Value)]);\n\nformat_error({unloaded_module, Module}) ->\n  io_lib:format(\"module ~ts is not loaded and could not be found\", [inspect(Module)]);\n\nformat_error({deadlock_module, Module}) ->\n  io_lib:format(\"module ~ts is not loaded and could not be found. \"\n                \"This may be happening because the module you are trying to load \"\n                \"directly or indirectly depends on the current module\",\n                [inspect(Module)]);\n\nformat_error({scheduled_module, Module}) ->\n  io_lib:format(\n    \"module ~ts is not loaded but was defined. This happens when you depend on \"\n    \"a module in the same context in which it is defined. For example:\\n\"\n    \"\\n\"\n    \"    defmodule MyApp do\\n\"\n    \"      defmodule Mod do\\n\"\n    \"      end\\n\"\n    \"\\n\"\n    \"      use Mod\\n\"\n    \"    end\\n\"\n    \"\\n\"\n    \"Try defining the module outside the context that uses it:\\n\"\n    \"\\n\"\n    \"    defmodule MyApp.Mod do\\n\"\n    \"    end\\n\"\n    \"\\n\"\n    \"    defmodule MyApp do\\n\"\n    \"      use MyApp.Mod\\n\"\n    \"    end\\n\"\n    \"\\n\"\n    \"If the module is defined at the top-level and you are trying to \"\n    \"use it at the top-level, this is not supported by Elixir\",\n    [inspect(Module)]);\n\nformat_error({circular_module, Module}) ->\n  io_lib:format(\n    \"you are trying to use/import/require the module ~ts which is currently being defined.\\n\"\n    \"\\n\"\n    \"This may happen if you accidentally override the module you want to use. For example:\\n\"\n    \"\\n\"\n    \"    defmodule MyApp do\\n\"\n    \"      defmodule Supervisor do\\n\"\n    \"        use Supervisor\\n\"\n    \"      end\\n\"\n    \"    end\\n\"\n    \"\\n\"\n    \"In the example above, the new Supervisor conflicts with Elixir's Supervisor. \"\n    \"This may be fixed by using the fully qualified name in the definition:\\n\"\n    \"\\n\"\n    \"    defmodule MyApp.Supervisor do\\n\"\n    \"      use Supervisor\\n\"\n    \"    end\\n\",\n    [inspect(Module)]).\n"
  },
  {
    "path": "lib/elixir/src/elixir_bitstring.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_bitstring).\n-export([expand/5, format_error/1, validate_spec/2]).\n-import(elixir_errors, [function_error/4]).\n-include(\"elixir.hrl\").\n\nexpand_match(Expr, {S, OriginalS}, E) ->\n  {EExpr, SE, EE} = elixir_expand:expand(Expr, S, E),\n  {EExpr, {SE, OriginalS}, EE}.\n\nexpand(Meta, Args, S, E, RequireSize) ->\n  case ?key(E, context) of\n    match ->\n      {EArgs, Alignment, {SA, _}, EA} =\n        expand(Meta, fun expand_match/3, Args, [], {S, S}, E, 0, RequireSize),\n\n      {{'<<>>', [{alignment, Alignment} | Meta], EArgs}, SA, EA};\n    _ ->\n      PairS = {elixir_env:prepare_write(S), S},\n\n      {EArgs, Alignment, {SA, _}, EA} =\n        expand(Meta, fun elixir_expand:expand_arg/3, Args, [], PairS, E, 0, RequireSize),\n\n      {{'<<>>', [{alignment, Alignment} | Meta], EArgs}, elixir_env:close_write(SA, S), EA}\n  end.\n\nexpand(_BitstrMeta, _Fun, [], Acc, S, E, Alignment, _RequireSize) ->\n  {lists:reverse(Acc), Alignment, S, E};\nexpand(BitstrMeta, Fun, [{'::', Meta, [Left, Right]} | T], Acc, S, E, Alignment, RequireSize) ->\n  % We don't want to consider variables added in the Left pattern inside the Right specs\n  {#elixir_ex{vars=BeforeVars}, _} = S,\n\n  {ELeft, {#elixir_ex{vars=AfterVars} = SL, OriginalS}, EL} = expand_expr(Left, Fun, S, E),\n  validate_expr(ELeft, Meta, E),\n\n  MatchOrRequireSize = RequireSize or is_match_size(T, EL),\n  EType = expr_type(ELeft),\n  ExpectSize = case ELeft of\n    _ when not MatchOrRequireSize -> optional;\n    {'^', _, [{_, _, _}]} -> {infer, ELeft};\n    _ -> required\n  end,\n\n  {ERight, EAlignment, SS, ES} =\n    expand_specs(EType, Meta, Right, SL#elixir_ex{vars=BeforeVars}, OriginalS, EL, ExpectSize),\n\n  EAcc = concat_or_prepend_bitstring(Meta, ELeft, ERight, Acc, ES, MatchOrRequireSize),\n  PairS = {SS#elixir_ex{vars=AfterVars}, OriginalS},\n  expand(BitstrMeta, Fun, T, EAcc, PairS, ES, alignment(Alignment, EAlignment), RequireSize);\nexpand(BitstrMeta, Fun, [H | T], Acc, S, E, Alignment, RequireSize) ->\n  Meta = extract_meta(H, BitstrMeta),\n  {ELeft, {SS, OriginalS}, ES} = expand_expr(H, Fun, S, E),\n  validate_expr(ELeft, Meta, E),\n\n  MatchOrRequireSize = RequireSize or is_match_size(T, ES),\n  EType = expr_type(ELeft),\n  ERight = infer_spec(EType, Meta),\n\n  InferredMeta = [{inferred_bitstring_spec, true} | Meta],\n  EAcc = concat_or_prepend_bitstring(InferredMeta, ELeft, ERight, Acc, ES, MatchOrRequireSize),\n  expand(Meta, Fun, T, EAcc, {SS, OriginalS}, ES, Alignment, RequireSize).\n\nextract_meta({_, Meta, _}, _) -> Meta;\nextract_meta(_, Meta) -> Meta.\n\n%% Variables defined outside the binary can be accounted\n%% on subparts; however, we can't assign new variables.\nis_match_size([_ | _], #{context := match}) -> true;\nis_match_size(_, _) -> false.\n\nexpr_type(Integer) when is_integer(Integer) -> integer;\nexpr_type(Float) when is_float(Float) -> float;\nexpr_type(Binary) when is_binary(Binary) -> binary;\nexpr_type({'<<>>', _, _}) -> bitstring;\nexpr_type(_) -> default.\n\ninfer_spec(bitstring, Meta) -> {bitstring, Meta, nil};\ninfer_spec(binary, Meta) -> {binary, Meta, nil};\ninfer_spec(float, Meta) -> {float, Meta, nil};\ninfer_spec(integer, Meta) -> {integer, Meta, nil};\ninfer_spec(default, Meta) -> {integer, Meta, nil}.\n\nconcat_or_prepend_bitstring(_Meta, {'<<>>', _, []}, _ERight, Acc, _E, _RequireSize) ->\n  Acc;\nconcat_or_prepend_bitstring(Meta, {'<<>>', PartsMeta, Parts} = ELeft, ERight, Acc, E, RequireSize) ->\n  case E of\n    #{context := match} when RequireSize ->\n      case lists:last(Parts) of\n        {'::', SpecMeta, [Bin, {binary, _, nil}]} when not is_binary(Bin) ->\n          function_error(SpecMeta, E, ?MODULE, unsized_binary);\n\n        {'::', SpecMeta, [_, {bitstring, _, nil}]} ->\n          function_error(SpecMeta, E, ?MODULE, unsized_binary);\n\n        _ ->\n          ok\n      end;\n    _ ->\n      ok\n  end,\n\n  case ERight of\n    {binary, _, nil} ->\n      {alignment, Alignment} = lists:keyfind(alignment, 1, PartsMeta),\n\n      if\n        is_integer(Alignment) ->\n          (Alignment /= 0) andalso function_error(Meta, E, ?MODULE, {unaligned_binary, ELeft}),\n          lists:reverse(Parts, Acc);\n\n        true ->\n          [{'::', Meta, [ELeft, ERight]} | Acc]\n      end;\n    {bitstring, _, nil} ->\n      lists:reverse(Parts, Acc)\n  end;\nconcat_or_prepend_bitstring(Meta, ELeft, ERight, Acc, _E, _RequireSize) ->\n  [{'::', Meta, [ELeft, ERight]} | Acc].\n\n%% Handling of alignment\n\nalignment(Left, Right) when is_integer(Left), is_integer(Right) -> (Left + Right) rem 8;\nalignment(_, _) -> unknown.\n\ncompute_alignment(_, Size, Unit) when is_integer(Size), is_integer(Unit) -> (Size * Unit);\ncompute_alignment(default, Size, Unit) -> compute_alignment(integer, Size, Unit);\ncompute_alignment(integer, default, Unit) -> compute_alignment(integer, 8, Unit);\ncompute_alignment(integer, Size, default) -> compute_alignment(integer, Size, 1);\ncompute_alignment(bitstring, Size, default) -> compute_alignment(bitstring, Size, 1);\ncompute_alignment(binary, _, _) -> 0;\ncompute_alignment(float, _, _) -> 0;\ncompute_alignment(utf32, _, _) -> 0;\ncompute_alignment(utf16, _, _) -> 0;\ncompute_alignment(utf8, _, _) -> 0;\ncompute_alignment(_, _, _) -> unknown.\n\n%% Expands the expression of a bitstring, that is, the LHS of :: or\n%% an argument of the bitstring (such as \"foo\" in \"<<foo>>\").\n%% If we are inside a match/guard, we inline interpolations explicitly,\n%% otherwise they are inlined by elixir_rewrite.erl.\n\nexpand_expr({{'.', _, [Mod, to_string]}, _, [Arg]} = AST, Fun, S, #{context := Context} = E)\n    when Context /= nil, (Mod == 'Elixir.Kernel') orelse (Mod == 'Elixir.String.Chars') ->\n  case Fun(Arg, S, E) of\n    {EBin, SE, EE} when is_binary(EBin) -> {EBin, SE, EE};\n    _ -> Fun(AST, S, E) % Let it raise\n  end;\nexpand_expr(Component, Fun, S, E) ->\n  Fun(Component, S, E).\n\nvalidate_expr(Expr, Meta, #{context := match} = E) ->\n  case Expr of\n    {Var, _Meta, Ctx} when is_atom(Var), is_atom(Ctx) -> ok;\n    {'<<>>', _, _} -> ok;\n    {'^', _, _} -> ok;\n    _ when is_number(Expr); is_binary(Expr) -> ok;\n    _ -> function_error(extract_meta(Expr, Meta), E, ?MODULE, {unknown_match, Expr})\n  end;\nvalidate_expr(_Expr, _Meta, _E) ->\n  ok.\n\n%% Expands and normalizes types of a bitstring.\n\nexpand_specs(ExprType, Meta, Info, S, OriginalS, E, ExpectSize) ->\n  Default =\n    #{size => default,\n      unit => default,\n      sign => default,\n      type => default,\n      endianness => default},\n  {#{size := Size, unit := Unit, type := Type, endianness := Endianness, sign := Sign}, SS, ES} =\n    expand_each_spec(Meta, unpack_specs(Info, []), Default, S, OriginalS, E),\n\n  MergedType = type(Meta, ExprType, Type, E),\n  validate_size_required(Meta, ExpectSize, ExprType, MergedType, Size, ES),\n  SizeAndUnit = size_and_unit(Meta, ExprType, Size, Unit, ES),\n  Alignment = compute_alignment(MergedType, Size, Unit),\n\n  MaybeInferredSize = case {ExpectSize, MergedType, SizeAndUnit} of\n    {{infer, PinnedVar}, binary, []} -> [{size, Meta, [{{'.', Meta, [erlang, byte_size]}, Meta, [PinnedVar]}]}];\n    {{infer, PinnedVar}, bitstring, []} -> [{size, Meta, [{{'.', Meta, [erlang, bit_size]}, Meta, [PinnedVar]}]}];\n    _ -> SizeAndUnit\n  end,\n\n  [H | T] = build_spec(Meta, Size, Unit, MergedType, Endianness, Sign, MaybeInferredSize, ES),\n  {lists:foldl(fun(I, Acc) -> {'-', Meta, [Acc, I]} end, H, T), Alignment, SS, ES}.\n\ntype(_, default, default, _) ->\n  integer;\ntype(_, ExprType, default, _) ->\n  ExprType;\ntype(_, binary, Type, _) when Type == binary; Type == bitstring; Type == utf8; Type == utf16; Type == utf32 ->\n  Type;\ntype(_, bitstring, Type, _) when Type == binary; Type == bitstring ->\n  Type;\ntype(_, integer, Type, _) when Type == integer; Type == float; Type == utf8; Type == utf16; Type == utf32 ->\n  Type;\ntype(_, float, Type, _) when Type == float ->\n  Type;\ntype(_, default, Type, _) ->\n  Type;\ntype(Meta, Other, Type, E) ->\n  function_error(Meta, E, ?MODULE, {bittype_mismatch, Type, Other, type}),\n  Type.\n\nexpand_each_spec(Meta, [{Expr, MetaE, Args} = H | T], Map, S, OriginalS, E) when is_atom(Expr) ->\n  case validate_spec(Expr, Args) of\n    {Key, Arg} ->\n      case Args of\n        [] ->\n          elixir_errors:file_warn(Meta, E, ?MODULE, {parens_bittype, Expr});\n        _ -> ok\n      end,\n      {Value, SE, EE} = expand_spec_arg(Arg, S, OriginalS, E),\n      validate_spec_arg(Meta, Key, Value, SE, OriginalS, EE),\n\n      case maps:get(Key, Map) of\n        default -> ok;\n        Value -> ok;\n        Other -> function_error(Meta, E, ?MODULE, {bittype_mismatch, Value, Other, Key})\n      end,\n\n      expand_each_spec(Meta, T, maps:put(Key, Value, Map), SE, OriginalS, EE);\n\n    none ->\n      HA = case Args of\n        nil ->\n          elixir_errors:file_warn(Meta, E, ?MODULE, {unknown_bittype, Expr}),\n          {Expr, MetaE, []};\n        _ -> H\n      end,\n\n      case 'Elixir.Macro':expand(HA, E#{line := ?line(Meta)}) of\n        HA ->\n          function_error(Meta, E, ?MODULE, {undefined_bittype, H}),\n          expand_each_spec(Meta, T, Map, S, OriginalS, E);\n\n        NewTypes ->\n          expand_each_spec(Meta, unpack_specs(NewTypes, []) ++ T, Map, S, OriginalS, E)\n      end\n  end;\nexpand_each_spec(Meta, [Expr | Tail], Map, S, OriginalS, E) ->\n  function_error(Meta, E, ?MODULE, {undefined_bittype, Expr}),\n  expand_each_spec(Meta, Tail, Map, S, OriginalS, E);\nexpand_each_spec(_Meta, [], Map, S, _OriginalS, E) ->\n  {Map, S, E}.\n\nunpack_specs({'-', _, [H, T]}, Acc) ->\n  unpack_specs(H, unpack_specs(T, Acc));\nunpack_specs({'*', _, [{'_', _, Atom}, Unit]}, Acc) when is_atom(Atom) ->\n  [{unit, [], [Unit]} | Acc];\nunpack_specs({'*', _, [Size, Unit]}, Acc) ->\n  [{size, [], [Size]}, {unit, [], [Unit]} | Acc];\nunpack_specs(Size, Acc) when is_integer(Size) ->\n  [{size, [], [Size]} | Acc];\nunpack_specs({Expr, Meta, Args}, Acc) when is_atom(Expr) ->\n  ListArgs = if is_atom(Args) -> nil; is_list(Args) -> Args end,\n  [{Expr, Meta, ListArgs} | Acc];\nunpack_specs(Other, Acc) ->\n  [Other | Acc].\n\nvalidate_spec(Spec, [])       -> validate_spec(Spec, nil);\nvalidate_spec(big, nil)       -> {endianness, big};\nvalidate_spec(little, nil)    -> {endianness, little};\nvalidate_spec(native, nil)    -> {endianness, native};\nvalidate_spec(size, [Size])   -> {size, Size};\nvalidate_spec(unit, [Unit])   -> {unit, Unit};\nvalidate_spec(integer, nil)   -> {type, integer};\nvalidate_spec(float, nil)     -> {type, float};\nvalidate_spec(binary, nil)    -> {type, binary};\nvalidate_spec(bytes, nil)     -> {type, binary};\nvalidate_spec(bitstring, nil) -> {type, bitstring};\nvalidate_spec(bits, nil)      -> {type, bitstring};\nvalidate_spec(utf8, nil)      -> {type, utf8};\nvalidate_spec(utf16, nil)     -> {type, utf16};\nvalidate_spec(utf32, nil)     -> {type, utf32};\nvalidate_spec(signed, nil)    -> {sign, signed};\nvalidate_spec(unsigned, nil)  -> {sign, unsigned};\nvalidate_spec(_, _)           -> none.\n\nexpand_spec_arg(Expr, S, _OriginalS, E) when is_atom(Expr); is_integer(Expr) ->\n  {Expr, S, E};\nexpand_spec_arg(Expr, S, OriginalS, #{context := match} = E) ->\n  %% We can only access variables that are either on prematch or not in original\n  #elixir_ex{prematch={PreRead, PreCycle, _} = OldPre} = S,\n  #elixir_ex{vars={OriginalRead, _}} = OriginalS,\n  NewPre = {PreRead, PreCycle, {bitsize, OriginalRead}},\n  {EExpr, SE, EE} = elixir_expand:expand(Expr, S#elixir_ex{prematch=NewPre}, E#{context := guard}),\n  {EExpr, SE#elixir_ex{prematch=OldPre}, EE#{context := match}};\nexpand_spec_arg(Expr, S, OriginalS, E) ->\n  elixir_expand:expand(Expr, elixir_env:reset_read(S, OriginalS), E).\n\nvalidate_spec_arg(Meta, unit, Value, _S, _OriginalS, E) when not is_integer(Value) ->\n  function_error(Meta, E, ?MODULE, {bad_unit_argument, Value}),\n  ok;\nvalidate_spec_arg(_Meta, _Key, _Value, _S, _OriginalS, _E) ->\n  ok.\n\nvalidate_size_required(Meta, required, default, Type, default, E) when Type == binary; Type == bitstring ->\n  function_error(Meta, E, ?MODULE, unsized_binary),\n  ok;\nvalidate_size_required(_, _, _, _, _, _) ->\n  ok.\n\nsize_and_unit(Meta, bitstring, Size, Unit, E) when Size /= default; Unit /= default ->\n  function_error(Meta, E, ?MODULE, bittype_literal_bitstring),\n  [];\nsize_and_unit(Meta, binary, Size, Unit, E) when Size /= default; Unit /= default ->\n  function_error(Meta, E, ?MODULE, bittype_literal_string),\n  [];\nsize_and_unit(_Meta, _ExprType, Size, Unit, _E) ->\n  add_arg(unit, Unit, add_arg(size, Size, [])).\n\nadd_arg(_Key, default, Spec) -> Spec;\nadd_arg(Key, Arg, Spec) -> [{Key, [], [Arg]} | Spec].\n\nbuild_spec(Meta, Size, Unit, Type, Endianness, Sign, Spec, E) when Type == utf8; Type == utf16; Type == utf32 ->\n  if\n    Size /= default; Unit /= default ->\n      function_error(Meta, E, ?MODULE, bittype_utf);\n    Sign /= default ->\n      function_error(Meta, E, ?MODULE, bittype_signed);\n    true ->\n      ok\n  end,\n  add_spec(Type, add_spec(Endianness, Spec));\n\nbuild_spec(Meta, _Size, Unit, Type, _Endianness, Sign, Spec, E) when Type == binary; Type == bitstring ->\n  if\n    Type == bitstring, Unit /= default, Unit /= 1 ->\n      function_error(Meta, E, ?MODULE, {bittype_mismatch, Unit, 1, unit});\n    Sign /= default ->\n      function_error(Meta, E, ?MODULE, bittype_signed);\n    true ->\n      %% Endianness is supported but has no effect, so we just ignore it.\n      ok\n  end,\n  add_spec(Type, Spec);\n\nbuild_spec(Meta, Size, Unit, Type, Endianness, Sign, Spec, E) when Type == integer; Type == float ->\n  NumberSize = number_size(Size, Unit),\n  if\n    Type == float, is_integer(NumberSize) ->\n      case valid_float_size(NumberSize) of\n        true ->\n          add_spec(Type, add_spec(Endianness, add_spec(Sign, Spec)));\n        false ->\n          function_error(Meta, E, ?MODULE, {bittype_float_size, NumberSize}),\n          []\n      end;\n    Size == default, Unit /= default ->\n      function_error(Meta, E, ?MODULE, bittype_unit),\n      [];\n    true ->\n      add_spec(Type, add_spec(Endianness, add_spec(Sign, Spec)))\n  end.\n\nnumber_size(Size, default) when is_integer(Size) -> Size;\nnumber_size(Size, Unit) when is_integer(Size) -> Size * Unit;\nnumber_size(Size, _) -> Size.\n\nvalid_float_size(16) -> true;\nvalid_float_size(32) -> true;\nvalid_float_size(64) -> true;\nvalid_float_size(_) -> false.\n\nadd_spec(default, Spec) -> Spec;\nadd_spec(Key, Spec) -> [{Key, [], nil} | Spec].\n\nformat_error({unaligned_binary, Expr}) ->\n  Message = \"expected ~ts to be a binary but its number of bits is not divisible by 8\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Expr)]);\nformat_error(unsized_binary) ->\n  \"a binary field without size is only allowed at the end of a binary pattern, \"\n  \"at the right side of binary concatenation and never allowed in binary generators. \"\n  \"The following examples are invalid:\\n\\n\"\n  \"    rest <> \\\"foo\\\"\\n\"\n  \"    <<rest::binary, \\\"foo\\\">>\\n\\n\"\n  \"They are invalid because there is a bits/bitstring component not at the end. \"\n  \"However, the \\\"reverse\\\" would work:\\n\\n\"\n  \"    \\\"foo\\\" <> rest\\n\"\n  \"    <<\\\"foo\\\", rest::binary>>\\n\\n\";\nformat_error(bittype_literal_bitstring) ->\n  \"literal <<>> in bitstring supports only type specifiers, which must be one of: \"\n    \"binary or bitstring\";\nformat_error(bittype_literal_string) ->\n  \"literal string in bitstring supports only endianness and type specifiers, which must be one of: \"\n    \"little, big, native, utf8, utf16, utf32, bits, bytes, binary or bitstring\";\nformat_error(bittype_utf) ->\n  \"size and unit are not supported on utf types\";\nformat_error(bittype_signed) ->\n  \"signed and unsigned specifiers are supported only on integer and float types\";\nformat_error(bittype_unit) ->\n  \"integer and float types require a size specifier if the unit specifier is given\";\nformat_error({bittype_float_size, Other}) ->\n  io_lib:format(\"float requires size*unit to be 16, 32, or 64 (default), got: ~p\", [Other]);\nformat_error({undefined_bittype, Expr}) ->\n  io_lib:format(\"unknown bitstring specifier: ~ts\", ['Elixir.Macro':to_string(Expr)]);\nformat_error({unknown_bittype, Name}) ->\n  io_lib:format(\"bitstring specifier \\\"~ts\\\" does not exist and is being expanded to \\\"~ts()\\\",\"\n                \" please use parentheses to remove the ambiguity.\\n\"\n                \"You may run \\\"mix format --migrate\\\" to fix this warning automatically.\", [Name, Name]);\nformat_error({parens_bittype, Name}) ->\n    io_lib:format(\"extra parentheses on a bitstring specifier \\\"~ts()\\\" have been deprecated. \"\n    \"Please remove the parentheses: \\\"~ts\\\".\\n\"\n    \"You may run \\\"mix format --migrate\\\" to fix this warning automatically.\"\n    ,\n    [Name, Name]);\nformat_error({bittype_mismatch, Val1, Val2, Where}) ->\n  io_lib:format(\"conflicting ~ts specification for bit field: \\\"~p\\\" and \\\"~p\\\"\", [Where, Val1, Val2]);\nformat_error({bad_unit_argument, Unit}) ->\n  io_lib:format(\"unit in bitstring expects an integer as argument, got: ~ts\",\n                ['Elixir.Macro':to_string(Unit)]);\nformat_error({unknown_match, Expr}) ->\n  Message =\n    \"a bitstring only accepts binaries, numbers, and variables inside a match, got: ~ts\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Expr)]);\nformat_error({undefined_var_in_spec, Var}) ->\n  Message =\n    \"undefined variable \\\"~ts\\\" in bitstring segment. If the size of the binary is a \"\n      \"variable, the variable must be defined prior to its use in the binary/bitstring match \"\n      \"itself, or outside the pattern match\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Var)]).\n"
  },
  {
    "path": "lib/elixir/src/elixir_bootstrap.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% An Erlang module that behaves like an Elixir module\n%% used for bootstrapping.\n-module(elixir_bootstrap).\n-export(['MACRO-def'/2, 'MACRO-def'/3, 'MACRO-defp'/3, 'MACRO-defmodule'/3,\n         'MACRO-defmacro'/2, 'MACRO-defmacro'/3, 'MACRO-defmacrop'/3,\n         'MACRO-@'/2, '__info__'/1]).\n-define(kernel, 'Elixir.Kernel').\n\n%% Mock out @ to be a no-op unless Kernel is defined.\n'MACRO-@'(Caller, Tree) ->\n  unless_loaded('MACRO-@', [Caller, Tree], fun() -> nil end).\n\n'MACRO-def'(Caller, Call) -> 'MACRO-def'(Caller, Call, nil).\n'MACRO-def'(Caller, Call, Expr) -> define(Caller, def, Call, Expr).\n'MACRO-defp'(Caller, Call, Expr) -> define(Caller, defp, Call, Expr).\n\n'MACRO-defmacro'(Caller, Call) -> 'MACRO-defmacro'(Caller, Call, nil).\n'MACRO-defmacro'(Caller, Call, Expr) -> define(Caller, defmacro, Call, Expr).\n'MACRO-defmacrop'(Caller, Call, Expr) -> define(Caller, defmacrop, Call, Expr).\n\n'MACRO-defmodule'({Line, _S, _E} = _Caller, Alias, [{do, Block}]) ->\n  Escaped = elixir_quote:escape(Block, escape, false),\n  Args = [[{line, Line}], Alias, Escaped, [], false, env()],\n  {{'.', [], [elixir_module, compile]}, [], Args}.\n\n'__info__'(functions) ->\n  [];\n'__info__'(macros) ->\n  [{'@', 1},\n   {def, 1},\n   {def, 2},\n   {defmacro, 1},\n   {defmacro, 2},\n   {defmacrop, 2},\n   {defmodule, 2},\n   {defp, 2}].\n\ndefine({Line, _S, #{module := Module} = E}, Kind, Call, Expr) ->\n  UC = elixir_quote:has_unquotes(Call),\n  UE = elixir_quote:has_unquotes(Expr),\n\n  Store =\n    case UC or UE of\n      true ->\n        elixir_quote:escape({Call, Expr}, escape, true);\n\n      false ->\n        Key = erlang:unique_integer(),\n        elixir_module:write_cache(Module, Key, {Call, Expr}),\n        Key\n    end,\n\n  Args = [Kind, Store, elixir_module:cache_env(E#{line := Line})],\n  {{'.', [], [elixir_def, store_definition]}, [], Args}.\n\nunless_loaded(Fun, Args, Callback) ->\n  case erlang:module_loaded(?kernel) of\n    true -> apply(?kernel, Fun, Args);\n    false -> Callback()\n  end.\n\nenv() ->\n  {'__ENV__', [], nil}.\n"
  },
  {
    "path": "lib/elixir/src/elixir_clauses.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Handle code related to args, guard and -> matching for case,\n%% fn, receive and friends. try is handled in elixir_try.\n-module(elixir_clauses).\n-export([parallel_match/4, match/6, clause/6, def/3, head/4,\n         'case'/4, 'receive'/4, 'try'/4, 'cond'/4, with/4,\n         format_error/1]).\n-import(elixir_errors, [file_error/4, file_warn/4]).\n-include(\"elixir.hrl\").\n\n%% Deal with parallel matches and loops in variables\n\nparallel_match(Meta, Expr, S, #{context := match} = E) ->\n  #elixir_ex{vars={_Read, Write}} = S,\n  Matches = unpack_match(Expr, Meta, [], E),\n\n  {[{_, EHead} | ETail], EWrites, SM, EM} =\n    lists:foldl(fun({EMeta, Match}, {AccMatches, AccWrites, SI, EI}) ->\n      #elixir_ex{vars={Read, _Write}} = SI,\n      {EMatch, SM, EM} = elixir_expand:expand(Match, SI#elixir_ex{vars={Read, #{}}}, EI),\n      #elixir_ex{vars={_, EWrite}} = SM,\n      {[{EMeta, EMatch} | AccMatches], [EWrite | AccWrites], SM, EM}\n    end, {[], [], S, E}, Matches),\n\n  EMatch =\n    lists:foldl(fun({EMeta, EMatch}, Acc) ->\n      {'=', EMeta, [EMatch, Acc]}\n    end, EHead, ETail),\n\n  #elixir_ex{vars={VRead, _}, prematch={PRead, Cycles, PInfo}} = SM,\n  {PCycles, PWrites} = store_cycles(EWrites, Cycles, #{}),\n  VWrite = (Write /= false) andalso elixir_env:merge_vars(Write, PWrites),\n  {EMatch, SM#elixir_ex{vars={VRead, VWrite}, prematch={PRead, PCycles, PInfo}}, EM}.\n\nunpack_match({'=', Meta, [{_, VarMeta, _} = Node, Node]}, _Meta, Acc, E) ->\n  %% TODO: remove this clause on Elixir v1.23\n  file_warn(VarMeta, ?key(E, file), ?MODULE, {duplicate_match, Node}),\n  unpack_match(Node, Meta, Acc, E);\nunpack_match({'=', Meta, [Left, Right]}, _Meta, Acc, E) ->\n  unpack_match(Left, Meta, unpack_match(Right, Meta, Acc, E), E);\nunpack_match(Node, Meta, Acc, _E) ->\n  [{Meta, Node} | Acc].\n\nstore_cycles([Write | Writes], {Cycles, SkipList}, Acc) ->\n  %% Compute the variables this parallel pattern depends on\n  DependsOn = lists:foldl(fun maps:merge/2, Acc, Writes),\n\n  %% For each variable on a sibling, we store it inside the graph (Cycles).\n  %% The graph will by definition have at least one degree cycles. We need\n  %% to find variables which depend on each other more than once (tagged as\n  %% error below) and also all second-degree (or later) cycles. In other\n  %% words, take this code:\n  %%\n  %%     {x = y, x = {:ok, y}} = expr()\n  %%\n  %% The first parallel match will say we store the following cycle:\n  %%\n  %%     #{{x,nil} => #{{y,nil} => 1}, {y,nil} => #{{x,nil} => 0}}\n  %%\n  %% That's why one degree cycles are allowed. However, once we go\n  %% over the next parallel pattern, we will have:\n  %%\n  %%     #{{x,nil} => #{{y,nil} => error}, {y,nil} => #{{x,nil} => error}}\n  %%\n  AccCycles =\n    maps:fold(fun(Pair, _, AccCycles) ->\n      maps:update_with(Pair, fun(Current) ->\n        maps:merge_with(fun(_, _, _) -> error end, Current, DependsOn)\n      end, DependsOn, AccCycles)\n    end, Cycles, Write),\n\n  %% The SkipList keeps variables that are seen as defined together by other\n  %% nodes. Those must be skipped on the graph traversal, as they will always\n  %% contain cycles between them. For example:\n  %%\n  %%     {{a} = b} = c = expr()\n  %%\n  %% In the example above, c sees \"a\" and \"b\" as defined together and therefore\n  %% one should not point to the other when looking for cycles.\n  AccSkipList =\n    case map_size(DependsOn) > 1 of\n      true -> [DependsOn | SkipList];\n      false -> SkipList\n    end,\n\n  store_cycles(Writes, {AccCycles, AccSkipList}, maps:merge(Acc, Write));\nstore_cycles([], Cycles, Acc) ->\n  {Cycles, Acc}.\n\nvalidate_cycles({Cycles, SkipList}, Meta, Expr, E) ->\n  maps:fold(fun(Current, _DependsOn, Seen) ->\n    recur_cycles(Cycles, Current, root, Seen, SkipList, Meta, Expr, E)\n  end, #{}, Cycles).\n\nrecur_cycles(Cycles, Current, Source, Seen, SkipList, Meta, Expr, E) ->\n  case is_map_key(Current, Seen) of\n    true ->\n      Seen;\n\n    false ->\n      case maps:get(Current, Cycles) of\n        #{Current := _} ->\n          file_error(Meta, E, ?MODULE, {recursive, [Current], Expr});\n\n        DependsOn ->\n          %% We traverse over the skip list. For each entry that contains ourselves,\n          %% we will split the remaining variables in two groups: one which we have\n          %% direct dependencies and skip once and ones that we always skip.\n          %%\n          %% For example, take `foo = {bar = {baz, bat}}`. `baz` and `bat` never depend\n          %% on each other, so we always skip `baz` and `bat` whenever any of them are\n          %% seen. However, while `bar` is in the same group as `baz` and `bat` (from the\n          %% point of view of `foo`), it depends on them, so it only skips once.\n          {OnceKeys, AlwaysKeys} =\n            lists:foldl(fun\n              (#{Current := _} = Skip, Acc) ->\n                maps:fold(fun(K, _, {AccOnce, AccAlways}) ->\n                  case DependsOn of\n                    #{K := _} -> {[K | AccOnce], AccAlways};\n                    #{} -> {AccOnce, [K | AccAlways]}\n                  end\n                end, Acc, Skip);\n              (_Skip, Acc) ->\n                Acc\n            end, {[], []}, SkipList),\n\n          NewSeen = maps:merge(maps:from_keys(AlwaysKeys, false), maps:put(Current, true, Seen)),\n\n          maps:fold(fun\n            (Key, error, _See) ->\n              file_error(Meta, E, ?MODULE, {recursive, [Current, Key], Expr});\n\n            %% Never go back to the node that we came from (as we can always one hop).\n            (Key, _, AccSeen) when Key =:= Source ->\n              AccSeen;\n\n            (Key, _, AccSeen) ->\n              case lists:member(Key, OnceKeys) of\n                true ->\n                  AccSeen;\n\n                false when map_get(Key, Seen) ->\n                  file_error(Meta, E, ?MODULE, {recursive, [Current | maps:keys(Seen)], Expr});\n\n                false ->\n                  recur_cycles(Cycles, Key, Current, AccSeen, SkipList, Meta, Expr, E)\n              end\n          end, NewSeen, DependsOn)\n      end\n  end.\n\n%% Match\n\nmatch(Fun, Meta, Expr, AfterS, BeforeS, #{context := nil} = E) ->\n  #elixir_ex{vars=Current, unused={_, Counter} = Unused} = AfterS,\n  #elixir_ex{vars={Read, _}, prematch=Prematch} = BeforeS,\n\n  CallS = BeforeS#elixir_ex{\n    prematch={Read, {#{}, []}, Counter},\n    unused=Unused,\n    vars=Current\n  },\n\n  CallE = E#{context := match},\n  {EExpr, SE, EE} = Fun(Expr, CallS, CallE),\n\n  #elixir_ex{\n    vars=NewCurrent,\n    unused=NewUnused,\n    prematch={_, Cycles, _}\n  } = SE,\n\n  validate_cycles(Cycles, Meta, {match, Expr}, E),\n\n  EndS = AfterS#elixir_ex{\n    prematch=Prematch,\n    unused=NewUnused,\n    vars=NewCurrent\n  },\n\n  EndE = EE#{context := ?key(E, context)},\n  {EExpr, EndS, EndE}.\n\ndef({Meta, Args, Guards, Body}, S, E) ->\n  {EArgs, SA, EA} = elixir_expand:expand_args(Args, S#elixir_ex{prematch={#{}, {#{}, []}, 0}}, E#{context := match}),\n  #elixir_ex{prematch={_, Cycles, _}} = SA,\n  validate_cycles(Cycles, Meta, {?key(E, function), Args}, E),\n  {EGuards, SG, EG} = guard(Guards, SA#elixir_ex{prematch=none}, EA#{context := guard}),\n  {EBody, SB, EB} = elixir_expand:expand(Body, SG, EG#{context := nil}),\n  elixir_env:check_unused_vars(SB, EB),\n  {Meta, EArgs, EGuards, EBody}.\n\nclause(_Meta, _Kind, Fun, {'->', Meta, [Left, Right]}, S, E) ->\n  {ELeft, SL, EL}  = case is_function(Fun, 4) of\n    true -> Fun(Meta, Left, S, E);\n    false -> Fun(Left, S, E)\n  end,\n  {ERight, SR, ER} = elixir_expand:expand(Right, SL, EL),\n  {{'->', Meta, [ELeft, ERight]}, SR, ER};\nclause(Meta, Kind, _Fun, _, _, E) ->\n  file_error(Meta, E, ?MODULE, {bad_or_missing_clauses, Kind}).\n\nhead(Meta, [{'when', WhenMeta, [_ | _] = All}], S, E) ->\n  {Args, Guard} = elixir_utils:split_last(All),\n  guarded_head(Meta, WhenMeta, Args, Guard, S, E);\nhead(Meta, Args, S, E) ->\n  match(fun elixir_expand:expand_args/3, Meta, Args, S, S, E).\n\nguarded_head(Meta, WhenMeta, Args, Guard, S, E) ->\n  {EArgs, SA, EA} = match(fun elixir_expand:expand_args/3, Meta, Args, S, S, E),\n  {EGuard, SG, EG} = guard(Guard, SA, EA#{context := guard}),\n  {[{'when', WhenMeta, EArgs ++ [EGuard]}], SG, EG#{context := nil}}.\n\nguard({'when', Meta, [Left, Right]}, S, E) ->\n  {ELeft, SL, EL}  = guard(Left, S, E),\n  {ERight, SR, ER} = guard(Right, SL, EL),\n  {{'when', Meta, [ELeft, ERight]}, SR, ER};\nguard(Guard, S, E) ->\n  {EGuard, SG, EG} = elixir_expand:expand(Guard, S, E),\n  warn_zero_length_guard(EGuard, EG),\n  {EGuard, SG, EG}.\n\nwarn_zero_length_guard({{'.', _, [erlang, Op]}, Meta,\n                        [{{'.', _, [erlang, length]}, _, [Arg]}, 0]}, E) when Op == '=='; Op == '>' ->\n  Warn =\n    case Op of\n      '==' -> {zero_list_length_in_guard, Arg};\n      '>' -> {positive_list_length_in_guard, Arg}\n    end,\n  file_warn(Meta, ?key(E, file), ?MODULE, Warn);\nwarn_zero_length_guard({Op, _, [L, R]}, E) when Op == 'or'; Op == 'and' ->\n  warn_zero_length_guard(L, E),\n  warn_zero_length_guard(R, E);\nwarn_zero_length_guard(_, _) ->\n  ok.\n\n%% Case\n\n'case'(Meta, [], _S, E) ->\n  file_error(Meta, E, elixir_expand, {missing_option, 'case', [do]});\n'case'(Meta, Opts, _S, E) when not is_list(Opts) ->\n  file_error(Meta, E, elixir_expand, {invalid_args, 'case'});\n'case'(Meta, Opts, S, E) ->\n  ok = assert_at_most_once('do', Opts, 0, fun(Key) ->\n    file_error(Meta, E, ?MODULE, {duplicated_clauses, 'case', Key})\n  end),\n  {Case, SA} = lists:mapfoldl(fun(X, SA) -> expand_case(Meta, X, SA, E) end, S, Opts),\n  {Case, SA, E}.\n\nexpand_case(Meta, {'do', _} = Do, S, E) ->\n  Fun = expand_head('case', 'do'),\n  expand_clauses(Meta, 'case', Fun, Do, S, E);\nexpand_case(Meta, {Key, _}, _S, E) ->\n  file_error(Meta, E, ?MODULE, {unexpected_option, 'case', Key}).\n\n%% Cond\n\n'cond'(Meta, [], _S, E) ->\n  file_error(Meta, E, elixir_expand, {missing_option, 'cond', [do]});\n'cond'(Meta, Opts, _S, E) when not is_list(Opts) ->\n  file_error(Meta, E, elixir_expand, {invalid_args, 'cond'});\n'cond'(Meta, Opts, S, E) ->\n  ok = assert_at_most_once('do', Opts, 0, fun(Key) ->\n    file_error(Meta, E, ?MODULE, {duplicated_clauses, 'cond', Key})\n  end),\n  {Cond, SA} = lists:mapfoldl(fun(X, SA) -> expand_cond(Meta, X, SA, E) end, S, Opts),\n  {Cond, SA, E}.\n\nexpand_cond(Meta, {'do', _} = Do, S, E) ->\n  Fun = expand_one(Meta, 'cond', 'do', fun elixir_expand:expand_args/3),\n  expand_clauses(Meta, 'cond', Fun, Do, S, E);\nexpand_cond(Meta, {Key, _}, _S, E) ->\n  file_error(Meta, E, ?MODULE, {unexpected_option, 'cond', Key}).\n\n%% Receive\n\n'receive'(Meta, [], _S, E) ->\n  file_error(Meta, E, elixir_expand, {missing_option, 'receive', [do, 'after']});\n'receive'(Meta, Opts, _S, E) when not is_list(Opts) ->\n  file_error(Meta, E, elixir_expand, {invalid_args, 'receive'});\n'receive'(Meta, Opts, S, E) ->\n  RaiseError = fun(Key) ->\n    file_error(Meta, E, ?MODULE, {duplicated_clauses, 'receive', Key})\n  end,\n  ok = assert_at_most_once('do', Opts, 0, RaiseError),\n  ok = assert_at_most_once('after', Opts, 0, RaiseError),\n  {Receive, SA} = lists:mapfoldl(fun(X, SA) -> expand_receive(Meta, X, SA, E) end, S, Opts),\n  {Receive, SA, E}.\n\nexpand_receive(_Meta, {'do', {'__block__', _, []}} = Do, S, _E) ->\n  {Do, S};\nexpand_receive(Meta, {'do', _} = Do, S, E) ->\n  Fun = expand_head('receive', 'do'),\n  expand_clauses(Meta, 'receive', Fun, Do, S, E);\nexpand_receive(Meta, {'after', [_]} = After, S, E) ->\n  Fun = expand_one(Meta, 'receive', 'after', fun elixir_expand:expand_args/3),\n  expand_clauses(Meta, 'receive', Fun, After, S, E);\nexpand_receive(Meta, {'after', _}, _S, E) ->\n  file_error(Meta, E, ?MODULE, multiple_after_clauses_in_receive);\nexpand_receive(Meta, {Key, _}, _S, E) ->\n  file_error(Meta, E, ?MODULE, {unexpected_option, 'receive', Key}).\n\n%% With\n\nwith(Meta, Args, S, E) ->\n  {Exprs, Opts0} = elixir_utils:split_opts(Args),\n  S0 = elixir_env:reset_unused_vars(S),\n  {EExprs, {S1, E1, HasMatch}} = lists:mapfoldl(fun expand_with/2, {S0, E, false}, Exprs),\n  {EDo, Opts1, S2} = expand_with_do(Meta, Opts0, S, S1, E1),\n  {EOpts, Opts2, S3} = expand_with_else(Meta, Opts1, S2, E, HasMatch),\n\n  case Opts2 of\n    [{Key, _} | _] ->\n      file_error(Meta, E, elixir_clauses, {unexpected_option, with, Key});\n    [] ->\n      ok\n  end,\n\n  {{with, Meta, EExprs ++ [[{do, EDo} | EOpts]]}, S3, E}.\n\nexpand_with({'<-', Meta, [Left, Right]}, {S, E, HasMatch}) ->\n  {ERight, SR, ER} = elixir_expand:expand(Right, S, E),\n  SM = elixir_env:reset_read(SR, S),\n  {[ELeft], SL, EL} = head(Meta, [Left], SM, ER),\n  NewHasMatch =\n    case ELeft of\n      {Var, _, Ctx} when is_atom(Var), is_atom(Ctx) -> HasMatch;\n      _ -> true\n    end,\n  {{'<-', Meta, [ELeft, ERight]}, {SL, EL, NewHasMatch}};\nexpand_with(Expr, {S, E, HasMatch}) ->\n  {EExpr, SE, EE} = elixir_expand:expand(Expr, S, E),\n  {EExpr, {SE, EE, HasMatch}}.\n\nexpand_with_do(Meta, Opts, S, Acc, E) ->\n  case lists:keytake(do, 1, Opts) of\n    {value, {do, Expr}, RestOpts} ->\n      {EExpr, SAcc, EAcc} = elixir_expand:expand(Expr, Acc, E),\n      {EExpr, RestOpts, elixir_env:merge_and_check_unused_vars(SAcc, S, EAcc)};\n    false ->\n      file_error(Meta, E, elixir_expand, {missing_option, 'with', [do]})\n  end.\n\nexpand_with_else(Meta, Opts, S, E, HasMatch) ->\n  case lists:keytake('else', 1, Opts) of\n    {value, Pair, RestOpts} ->\n      if\n        HasMatch -> ok;\n        true -> file_warn(Meta, ?key(E, file), ?MODULE, unmatchable_else_in_with)\n      end,\n      Fun = expand_head('with', 'else'),\n      {EPair, SE} = expand_clauses(Meta, 'with', Fun, Pair, S, E),\n      {[EPair], RestOpts, SE};\n    false ->\n      {[], Opts, S}\n  end.\n\n%% Try\n\n'try'(Meta, [], _S, E) ->\n  file_error(Meta, E, elixir_expand, {missing_option, 'try', [do]});\n'try'(Meta, [{do, _}], _S, E) ->\n  file_error(Meta, E, elixir_expand, {missing_option, 'try', ['catch', 'rescue', 'after']});\n'try'(Meta, Opts, _S, E) when not is_list(Opts) ->\n  file_error(Meta, E, elixir_expand, {invalid_args, 'try'});\n'try'(Meta, Opts, S, E) ->\n  % TODO: Make this an error on v2.0\n  case Opts of\n    [{do, _}, {'else', _}] ->\n      file_warn(Meta, ?key(E, file), ?MODULE, {try_with_only_else_clause, origin(Meta, 'try')});\n    _ ->\n      ok\n  end,\n  RaiseError = fun(Key) ->\n    file_error(Meta, E, ?MODULE, {duplicated_clauses, 'try', Key})\n  end,\n  ok = assert_at_most_once('do', Opts, 0, RaiseError),\n  ok = assert_at_most_once('rescue', Opts, 0, RaiseError),\n  ok = assert_at_most_once('catch', Opts, 0, RaiseError),\n  ok = assert_at_most_once('else', Opts, 0, RaiseError),\n  ok = assert_at_most_once('after', Opts, 0, RaiseError),\n  ok = warn_catch_before_rescue(Opts, Meta, E, false),\n  {Try, SA} = lists:mapfoldl(fun(X, SA) -> expand_try(Meta, X, SA, E) end, S, Opts),\n  {Try, SA, E}.\n\nexpand_try(_Meta, {'do', Expr}, S, E) ->\n  {EExpr, SE, EE} = elixir_expand:expand(Expr, elixir_env:reset_unused_vars(S), E),\n  {{'do', EExpr}, elixir_env:merge_and_check_unused_vars(SE, S, EE)};\nexpand_try(_Meta, {'after', Expr}, S, E) ->\n  {EExpr, SE, EE} = elixir_expand:expand(Expr, elixir_env:reset_unused_vars(S), E),\n  {{'after', EExpr}, elixir_env:merge_and_check_unused_vars(SE, S, EE)};\nexpand_try(Meta, {'else', _} = Else, S, E) ->\n  Fun = expand_head('try', 'else'),\n  expand_clauses(Meta, 'try', Fun, Else, S, E);\nexpand_try(Meta, {'catch', _} = Catch, S, E) ->\n  expand_clauses_with_stacktrace(Meta, fun expand_catch/4, Catch, S, E);\nexpand_try(Meta, {'rescue', _} = Rescue, S, E) ->\n  expand_clauses_with_stacktrace(Meta, fun expand_rescue/4, Rescue, S, E);\nexpand_try(Meta, {Key, _}, _S, E) ->\n  file_error(Meta, E, ?MODULE, {unexpected_option, 'try', Key}).\n\nexpand_clauses_with_stacktrace(Meta, Fun, Clauses, S, E) ->\n  OldStacktrace = S#elixir_ex.stacktrace,\n  SS = S#elixir_ex{stacktrace=true},\n  {Ret, SE} = expand_clauses(Meta, 'try', Fun, Clauses, SS, E),\n  {Ret, SE#elixir_ex{stacktrace=OldStacktrace}}.\n\nexpand_catch(Meta, [{'when', _, [_, _, _, _ | _]}], _, E) ->\n  Error = {wrong_number_of_args_for_clause, \"one or two args\", origin(Meta, 'try'), 'catch'},\n  file_error(Meta, E, ?MODULE, Error);\nexpand_catch(Meta, [{'when', WhenMeta, [Arg1, Arg2, Guard]}], S, E) ->\n  guarded_head(Meta, WhenMeta, [Arg1, Arg2], Guard, S, E);\nexpand_catch(Meta, [{'when', WhenMeta, [Arg1, Guard]}], S, E) ->\n  guarded_head(Meta, WhenMeta, [throw, Arg1], Guard, S, E);\nexpand_catch(Meta, [Arg], S, E) ->\n  head(Meta, [throw, Arg], S, E);\nexpand_catch(Meta, [_, _] = Args, S, E) ->\n  head(Meta, Args, S, E);\nexpand_catch(Meta, _, _, E) ->\n  Error = {wrong_number_of_args_for_clause, \"one or two args\", origin(Meta, 'try'), 'catch'},\n  file_error(Meta, E, ?MODULE, Error).\n\nexpand_rescue(Meta, [Arg], S, E) ->\n  case expand_rescue(Arg, S, E) of\n    {EArg, SA, EA} ->\n      {[EArg], SA, EA};\n    false ->\n      file_error(Meta, E, ?MODULE, {invalid_rescue_clause, Arg})\n  end;\nexpand_rescue(Meta, _, _, E) ->\n  Error = {wrong_number_of_args_for_clause, \"one argument\", origin(Meta, 'try'), 'rescue'},\n  file_error(Meta, E, ?MODULE, Error).\n\n%% rescue var\nexpand_rescue({Name, Meta, Atom} = Var, S, E) when is_atom(Name), is_atom(Atom) ->\n  match(fun elixir_expand:expand/3, Meta, Var, S, S, E);\n\n%% rescue Alias => _ in [Alias]\nexpand_rescue({'__aliases__', _, [_ | _]} = Alias, S, E) ->\n  expand_rescue({in, [], [{'_', [], ?key(E, module)}, Alias]}, S, E);\n\n%% rescue var in _\nexpand_rescue({in, _, [{Name, Meta, VarContext} = Var, {'_', _, UnderscoreContext}]}, S, E)\n    when is_atom(Name), is_atom(VarContext), is_atom(UnderscoreContext) ->\n  match(fun elixir_expand:expand/3, Meta, Var, S, S, E);\n\n%% rescue var in (list() or atom())\nexpand_rescue({in, Meta, [Left, Right]}, S, E) ->\n  {ELeft, SL, EL}  = match(fun elixir_expand:expand/3, Meta, Left, S, S, E),\n  {ERight, SR, ER} = elixir_expand:expand(Right, SL, EL),\n\n  case ELeft of\n    {Name, _, Atom} when is_atom(Name), is_atom(Atom) ->\n      case normalize_rescue(ERight) of\n        false -> false;\n        Other -> {{in, Meta, [ELeft, Other]}, SR, ER}\n      end;\n    _ ->\n      false\n  end;\n\n%% rescue expr() => rescue expanded_expr()\nexpand_rescue({_, Meta, _} = Arg, S, E) ->\n  case 'Elixir.Macro':expand_once(Arg, E#{line := ?line(Meta)}) of\n    Arg -> false;\n    NewArg -> expand_rescue(NewArg, S, E)\n  end;\n\n%% rescue list() or atom() => _ in (list() or atom())\nexpand_rescue(Arg, S, E) ->\n  expand_rescue({in, [], [{'_', [], ?key(E, module)}, Arg]}, S, E).\n\nnormalize_rescue(Atom) when is_atom(Atom) ->\n  [Atom];\nnormalize_rescue(Other) ->\n  is_list(Other) andalso lists:all(fun is_atom/1, Other) andalso Other.\n\n%% Expansion helpers\n\nexpand_head(Kind, Key) ->\n  fun\n    (Meta, [{'when', _, [_, _, _ | _]}], _, E) ->\n      file_error(Meta, E, ?MODULE, {wrong_number_of_args_for_clause, \"one argument\", Kind, Key});\n    (Meta, [_] = Args, S, E) ->\n      head(Meta, Args, S, E);\n    (Meta, _, _, E) ->\n      file_error(Meta, E, ?MODULE, {wrong_number_of_args_for_clause, \"one argument\", Kind, Key})\n  end.\n\n%% Returns a function that expands arguments\n%% considering we have at maximum one entry.\nexpand_one(Meta, Kind, Key, Fun) ->\n  fun\n    ([_] = Args, S, E) ->\n      Fun(Args, S, E);\n    (_, _, E) ->\n      file_error(Meta, E, ?MODULE, {wrong_number_of_args_for_clause, \"one argument\", Kind, Key})\n  end.\n\n%% Expands all -> pairs in a given key but do not keep the overall vars.\nexpand_clauses(Meta, Kind, Fun, Clauses, S, E) ->\n  NewKind = origin(Meta, Kind),\n  expand_clauses_origin(Meta, NewKind, Fun, Clauses, S, E).\n\nexpand_clauses_origin(Meta, Kind, Fun, {Key, [_ | _] = Clauses}, S, E) ->\n  Transformer = fun(Clause, SA) ->\n    {EClause, SAcc, EAcc} =\n      clause(Meta, {Kind, Key}, Fun, Clause, elixir_env:reset_unused_vars(SA), E),\n\n    {EClause, elixir_env:merge_and_check_unused_vars(SAcc, SA, EAcc)}\n  end,\n  {Values, SE} = lists:mapfoldl(Transformer, S, Clauses),\n  {{Key, Values}, SE};\nexpand_clauses_origin(Meta, Kind, _Fun, {Key, _}, _, E) ->\n  file_error(Meta, E, ?MODULE, {bad_or_missing_clauses, {Kind, Key}}).\n\nassert_at_most_once(_Kind, [], _Count, _Fun) -> ok;\nassert_at_most_once(Kind, [{Kind, _} | _], 1, ErrorFun) ->\n  ErrorFun(Kind);\nassert_at_most_once(Kind, [{Kind, _} | Rest], Count, Fun) ->\n  assert_at_most_once(Kind, Rest, Count + 1, Fun);\nassert_at_most_once(Kind, [_ | Rest], Count, Fun) ->\n  assert_at_most_once(Kind, Rest, Count, Fun).\n\nwarn_catch_before_rescue([], _, _, _) ->\n  ok;\nwarn_catch_before_rescue([{'rescue', _} | _], Meta, E, true) ->\n  file_warn(Meta, ?key(E, file), ?MODULE, {catch_before_rescue, origin(Meta, 'try')});\nwarn_catch_before_rescue([{'catch', _} | Rest], Meta, E, _) ->\n  warn_catch_before_rescue(Rest, Meta, E, true);\nwarn_catch_before_rescue([_ | Rest], Meta, E, Found) ->\n  warn_catch_before_rescue(Rest, Meta, E, Found).\n\norigin(Meta, Default) ->\n  case lists:keyfind(origin, 1, Meta) of\n    {origin, Origin} -> Origin;\n    false -> Default\n  end.\n\nformat_error({duplicate_match, Expr}) ->\n  String = 'Elixir.Macro':to_string(Expr),\n  io_lib:format(\n    \"this pattern is matched against itself inside a match: ~ts = ~ts\",\n    [String, String]\n  );\n\nformat_error({recursive, Vars, TypeExpr}) ->\n  Code =\n    case TypeExpr of\n      {match, Expr} -> 'Elixir.Macro':to_string(Expr);\n      {{Name, _Arity}, Args} -> 'Elixir.Macro':to_string({Name, [], Args})\n    end,\n\n  Message =\n    case lists:map(fun({Name, Context}) -> elixir_utils:var_info(Name, Context) end, lists:sort(Vars)) of\n      [Var] ->\n        io_lib:format(\"the variable ~ts is defined in function of itself\", [Var]);\n      [Var1, Var2] ->\n        io_lib:format(\"the variable ~ts is defined recursively in function of ~ts\", [Var1, Var2]);\n      [Head | Tail] ->\n        List = lists:foldl(fun(X, Acc) -> [Acc, $,, $\\s, X] end, Head, Tail),\n        io_lib:format(\"the following variables form a cycle: ~ts\", [List])\n    end,\n\n  io_lib:format(\n    \"recursive variable definition in patterns:~n~n~ts~n~n~ts\",\n    [Code, Message]\n  );\n\nformat_error({bad_or_missing_clauses, {Kind, Key}}) ->\n  io_lib:format(\"invalid \\\"~ts\\\" block in \\\"~ts\\\", it expects \\\"pattern -> expr\\\" clauses\", [Key, Kind]);\n\nformat_error({duplicated_clauses, Kind, Key}) ->\n  io_lib:format(\"duplicate \\\"~ts\\\" clauses given for \\\"~ts\\\"\", [Key, Kind]);\n\nformat_error({unexpected_option, Kind, Option}) ->\n  io_lib:format(\"unexpected option ~ts in \\\"~ts\\\"\", ['Elixir.Macro':to_string(Option), Kind]);\n\nformat_error({wrong_number_of_args_for_clause, Expected, Kind, Key}) ->\n  io_lib:format(\"expected ~ts for \\\"~ts\\\" clauses (->) in \\\"~ts\\\"\", [Expected, Key, Kind]);\n\nformat_error(multiple_after_clauses_in_receive) ->\n  \"expected a single -> clause for :after in \\\"receive\\\"\";\n\nformat_error({invalid_rescue_clause, Arg}) ->\n  io_lib:format(\n    \"invalid \\\"rescue\\\" clause. The clause should match on an alias, a variable \"\n    \"or be in the \\\"var in [alias]\\\" format. Got: ~ts\",\n    ['Elixir.Macro':to_string(Arg)]\n  );\n\nformat_error({catch_before_rescue, Origin}) ->\n  io_lib:format(\"\\\"catch\\\" should always come after \\\"rescue\\\" in ~ts\", [Origin]);\n\nformat_error({try_with_only_else_clause, Origin}) ->\n  io_lib:format(\"\\\"else\\\" shouldn't be used as the only clause in \\\"~ts\\\", use \\\"case\\\" instead\",\n                [Origin]);\n\nformat_error(unmatchable_else_in_with) ->\n  \"\\\"else\\\" clauses will never match because all patterns in \\\"with\\\" will always match\";\n\nformat_error({zero_list_length_in_guard, ListArg}) ->\n  Arg = 'Elixir.Macro':to_string(ListArg),\n  io_lib:format(\"do not use \\\"length(~ts) == 0\\\" to check if a list is empty since length \"\n                \"always traverses the whole list. Prefer to pattern match on an empty list or \"\n                \"use \\\"~ts == []\\\" as a guard\", [Arg, Arg]);\n\nformat_error({positive_list_length_in_guard, ListArg}) ->\n  Arg = 'Elixir.Macro':to_string(ListArg),\n  io_lib:format(\"do not use \\\"length(~ts) > 0\\\" to check if a list is not empty since length \"\n                \"always traverses the whole list. Prefer to pattern match on a non-empty list, \"\n                \"such as [_ | _], or use \\\"~ts != []\\\" as a guard\", [Arg, Arg]).\n"
  },
  {
    "path": "lib/elixir/src/elixir_code_server.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_code_server).\n-export([call/1, cast/1]).\n-export([start_link/0, init/1, handle_call/3, handle_cast/2,\n  handle_info/2, terminate/2, code_change/3]).\n-behaviour(gen_server).\n\n-define(timeout, infinity).\n-record(elixir_code_server, {\n  required=#{},\n  mod_pool={[], [], 0},\n  mod_ets=#{}\n}).\n\ncall(Args) ->\n  gen_server:call(?MODULE, Args, ?timeout).\n\ncast(Args) ->\n  gen_server:cast(?MODULE, Args).\n\n%% Callbacks\n\nstart_link() ->\n  gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).\n\ninit(ok) ->\n  %% The table where we store module definitions\n  _ = ets:new(elixir_modules, [set, public, named_table, {read_concurrency, true}]),\n  {ok, #elixir_code_server{}}.\n\nhandle_call({defmodule, Module, Pid, Tuple}, _From, Config) ->\n  case ets:lookup(elixir_modules, Module) of\n    [] ->\n      {Ref, NewConfig} = defmodule(Pid, Tuple, Config),\n      {reply, {ok, Ref}, NewConfig};\n    [CurrentTuple] ->\n      {reply, {error, CurrentTuple}, Config}\n  end;\n\nhandle_call({undefmodule, Ref}, _From, Config) ->\n  {reply, ok, undefmodule(Ref, Config)};\n\nhandle_call({acquire, Path}, From, Config) ->\n  Current = Config#elixir_code_server.required,\n  case maps:find(Path, Current) of\n    {ok, true} ->\n      {reply, required, Config};\n    {ok, Queued} when is_list(Queued) ->\n      Required = maps:put(Path, [From | Queued], Current),\n      {noreply, Config#elixir_code_server{required=Required}};\n    error ->\n      Required = maps:put(Path, [], Current),\n      {reply, proceed, Config#elixir_code_server{required=Required}}\n  end;\n\nhandle_call(required, _From, Config) ->\n  {reply, [F || {F, true} <- maps:to_list(Config#elixir_code_server.required)], Config};\n\nhandle_call(retrieve_compiler_module, _From, Config) ->\n  case Config#elixir_code_server.mod_pool of\n    {Used, [Mod | Unused], Counter} ->\n      {reply, Mod, Config#elixir_code_server{mod_pool={Used, Unused, Counter}}};\n    {Used, [], Counter} ->\n      {reply, compiler_module(Counter), Config#elixir_code_server{mod_pool={Used, [], Counter+1}}}\n  end;\n\nhandle_call(purge_compiler_modules, _From, Config) ->\n  {Used, Unused, Counter} = Config#elixir_code_server.mod_pool,\n  purge_used(Used),\n  Mods = [Mod || {Mod, Purgeable} <- Used, Purgeable],\n  ModPool = {[], Mods ++ Unused, Counter},\n  {reply, {ok, length(Used)}, Config#elixir_code_server{mod_pool=ModPool}};\n\nhandle_call(Request, _From, Config) ->\n  {stop, {badcall, Request}, Config}.\n\nhandle_cast({required, Path}, Config) ->\n  Current = Config#elixir_code_server.required,\n  case maps:find(Path, Current) of\n    {ok, true} ->\n      {noreply, Config};\n    {ok, Queued} ->\n      _ = [gen_server:reply(From, required) || From <- lists:reverse(Queued)],\n      Done = maps:put(Path, true, Current),\n      {noreply, Config#elixir_code_server{required=Done}};\n    error ->\n      Done = maps:put(Path, true, Current),\n      {noreply, Config#elixir_code_server{required=Done}}\n  end;\n\nhandle_cast({unrequire_files, Files}, Config) ->\n  Current  = Config#elixir_code_server.required,\n  Unrequired = maps:without(Files, Current),\n  {noreply, Config#elixir_code_server{required=Unrequired}};\n\nhandle_cast({return_compiler_module, Module, Purgeable}, Config) ->\n  {Used, Unused, Counter} = Config#elixir_code_server.mod_pool,\n  ModPool = {[{Module, Purgeable} | Used], Unused, Counter},\n  {noreply, Config#elixir_code_server{mod_pool=ModPool}};\n\nhandle_cast(purge_compiler_modules, Config) ->\n  {Used, Unused, Counter} = Config#elixir_code_server.mod_pool,\n\n  case Used of\n    [] -> ok;\n    _ ->\n      %% Purging modules became more expensive in Erlang/OTP 27+,\n      %% so we accumulate them all during compilation and then\n      %% purge them asynchronously, especially because they can\n      %% block the code server. Ideally we would purge them in\n      %% batches, but that's not supported at the moment.\n      Mods = [Mod || {Mod, Purgeable} <- Used, Purgeable],\n      Opts = [{monitor, [{tag, {purged, Mods}}]}],\n      erlang:spawn_opt(fun() -> purge_used(Used) end, Opts)\n  end,\n\n  ModPool = {[], Unused, Counter},\n  {noreply, Config#elixir_code_server{mod_pool=ModPool}};\n\nhandle_cast(Request, Config) ->\n  {stop, {badcast, Request}, Config}.\n\nhandle_info({{purged, Purged}, _Ref, process, _Pid, _Reason}, Config) ->\n  {Used, Unused, Counter} = Config#elixir_code_server.mod_pool,\n  ModPool = {Used, Purged ++ Unused, Counter},\n  {noreply, Config#elixir_code_server{mod_pool=ModPool}};\n\nhandle_info({'DOWN', Ref, process, _Pid, _Reason}, Config) ->\n  {noreply, undefmodule(Ref, Config)};\n\nhandle_info(_Msg, Config) ->\n  {noreply, Config}.\n\nterminate(_Reason, _Config) ->\n  ok.\n\ncode_change(_Old, Config, _Extra) ->\n  {ok, Config}.\n\ncompiler_module(I) ->\n  list_to_atom(\"elixir_compiler_\" ++ integer_to_list(I)).\n\npurge_used(Used) ->\n  [begin\n    code:delete(Module),\n    Purgeable andalso code:purge(Module)\n  end || {Module, Purgeable} <- Used],\n  ok.\n\ndefmodule(Pid, Tuple, #elixir_code_server{mod_ets=ModEts} = Config) ->\n  ets:insert(elixir_modules, Tuple),\n  Ref = erlang:monitor(process, Pid),\n  Mod = erlang:element(1, Tuple),\n  {Ref, Config#elixir_code_server{mod_ets=maps:put(Ref, Mod, ModEts)}}.\n\nundefmodule(Ref, #elixir_code_server{mod_ets=ModEts} = Config) ->\n  case maps:find(Ref, ModEts) of\n    {ok, Mod} ->\n      ets:delete(elixir_modules, Mod),\n      Config#elixir_code_server{mod_ets=maps:remove(Ref, ModEts)};\n    error ->\n      Config\n  end.\n"
  },
  {
    "path": "lib/elixir/src/elixir_compiler.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Elixir compiler front-end to the Erlang backend.\n-module(elixir_compiler).\n-export([string/3, quoted/3, bootstrap/0, file/2, compile/4, interpret/3]).\n-include(\"elixir.hrl\").\n\nstring(Contents, File, Callback) ->\n  Forms = elixir:'string_to_quoted!'(Contents, 1, 1, File, elixir_config:get(parser_options)),\n  quoted(Forms, File, Callback).\n\nquoted(Forms, File, Callback) ->\n  Previous = get(elixir_module_binaries),\n\n  try\n    put(elixir_module_binaries, []),\n    Env = (elixir_env:new())#{line := 1, file := File, tracers := elixir_config:get(tracers)},\n\n    elixir_lexical:run(\n      Env,\n      fun (LexicalEnv) -> optimize_defmodule(Forms, LexicalEnv) end,\n      fun (#{lexical_tracker := Pid}) -> Callback(File, Pid) end\n    ),\n\n    lists:reverse(get(elixir_module_binaries))\n  after\n    put(elixir_module_binaries, Previous)\n  end.\n\nfile(File, Callback) ->\n  {ok, Bin} = file:read_file(File),\n  string(elixir_utils:characters_to_list(Bin), File, Callback).\n\n%% In case the forms only holds defmodules, we optimize\n%% it by expanding them directly.\noptimize_defmodule(Forms, E) ->\n  case (?key(E, module) == nil) andalso only_defmodule(Forms) andalso\n        (not elixir_config:is_bootstrap()) of\n    true  -> expand_defmodule(Forms, E);\n    false -> compile(Forms, [], [], E)\n  end,\n  ok.\n\n%% A version of compilation that uses eval (interpreted)\ninterpret(Quoted, ArgsList, #{line := Line} = E) ->\n  {Expanded, SE, EE} = elixir_expand:expand(Quoted, elixir_env:env_to_ex(E), E),\n  elixir_env:check_unused_vars(SE, EE),\n\n  {Vars, TS} = elixir_erl_var:from_env(E),\n  {ErlExprs, _} = elixir_erl_pass:translate(Expanded, erl_anno:new(Line), TS),\n\n  ListBinding = lists:zipwith(fun({_, Var}, Arg) -> {Var, Arg} end, Vars, ArgsList),\n  Binding = maps:from_list(ListBinding),\n\n  {value, Result, _} =\n    try\n      elixir:erl_eval(ErlExprs, Binding, E)\n    catch\n      Kind:Reason:Stacktrace ->\n        erlang:raise(Kind, Reason, Stacktrace ++ 'Elixir.Macro.Env':stacktrace(E))\n    end,\n\n  {Result, SE, EE}.\n\ncompile(Quoted, ArgsList, CompilerOpts, #{line := Line} = E) ->\n  Block = no_tail_optimize([{line, Line}], Quoted),\n  {Expanded, SE, EE} = elixir_expand:expand(Block, elixir_env:env_to_ex(E), E),\n  elixir_env:check_unused_vars(SE, EE),\n\n  {Module, Fun, LabelledLocals} =\n    elixir_erl_compiler:spawn(fun() -> spawned_compile(Expanded, CompilerOpts, E) end),\n\n  Args = list_to_tuple(ArgsList),\n  {dispatch(Module, Fun, Args, LabelledLocals), SE, EE}.\n\nspawned_compile(ExExprs, CompilerOpts, #{line := Line, file := File} = E) ->\n  {Vars, S} = elixir_erl_var:from_env(E),\n  {ErlExprs, _} = elixir_erl_pass:translate(ExExprs, erl_anno:new(Line), S),\n\n  Module = retrieve_compiler_module(),\n  Fun = code_fun(?key(E, module)),\n  Forms = code_mod(Fun, ErlExprs, Line, File, Module, Vars),\n\n  {Module, Binary} = elixir_erl_compiler:noenv_forms(Forms, File, [nowarn_nomatch | CompilerOpts]),\n  code:load_binary(Module, \"\", Binary),\n  {Module, Fun, is_purgeable(Binary)}.\n\nis_purgeable(<<\"FOR1\", _Size:32, \"BEAM\", Rest/binary>>) ->\n  do_is_purgeable(Rest).\n\ndo_is_purgeable(<<>>) -> true;\ndo_is_purgeable(<<\"LocT\", 4:32, 0:32, _/binary>>) -> true;\ndo_is_purgeable(<<\"LocT\", _:32, _/binary>>) -> false;\ndo_is_purgeable(<<_:4/binary, Size:32, Beam/binary>>) ->\n  <<_:(4 * trunc((Size+3) / 4))/binary, Rest/binary>> = Beam,\n  do_is_purgeable(Rest).\n\ndispatch(Module, Fun, Args, Purgeable) ->\n  Res = Module:Fun(Args),\n  return_compiler_module(Module, Purgeable),\n  Res.\n\ncode_fun(nil) -> '__FILE__';\ncode_fun(_)   -> '__MODULE__'.\n\ncode_mod(Fun, Expr, Line, File, Module, Vars) when is_binary(File), is_integer(Line) ->\n  Ann = erl_anno:new(Line),\n  Tuple = {tuple, Ann, [{var, Ann, Var} || {_, Var} <- Vars]},\n  Relative = elixir_utils:relative_to_cwd(File),\n\n  [{attribute, Ann, file, {elixir_utils:characters_to_list(Relative), 1}},\n   {attribute, Ann, module, Module},\n   {attribute, Ann, compile, no_auto_import},\n   {attribute, Ann, export, [{Fun, 1}, {'__RELATIVE__', 0}]},\n   {function, Ann, Fun, 1, [\n     {clause, Ann, [Tuple], [], [Expr]}\n   ]},\n   {function, Ann, '__RELATIVE__', 0, [\n     {clause, Ann, [], [], [elixir_erl:elixir_to_erl(Relative)]}\n   ]}].\n\nretrieve_compiler_module() ->\n  elixir_code_server:call(retrieve_compiler_module).\n\nreturn_compiler_module(Module, Purgeable) ->\n  elixir_code_server:cast({return_compiler_module, Module, Purgeable}).\n\nonly_defmodule({'__block__', _, Exprs}) ->\n  lists:all(fun only_defmodule/1, Exprs);\n  only_defmodule({defmodule, _, [_, [{do, _}]]}) ->\n  true;\nonly_defmodule(_) ->\n  false.\n\nexpand_defmodule({'__block__', _, Exprs}, E) ->\n  lists:foldl(fun(Expr, _) -> expand_defmodule(Expr, E) end, nil, Exprs);\nexpand_defmodule({defmodule, Meta, [Mod, [{do, Block}]]}, NoLineE) ->\n  E = NoLineE#{line := ?line(Meta)},\n\n  Expanded = case Mod of\n    {'__aliases__', AliasMeta, List} ->\n      case elixir_aliases:expand_or_concat(AliasMeta, List, E, true) of\n        Receiver when is_atom(Receiver) -> Receiver;\n        _ -> 'Elixir.Macro':expand(Mod, E)\n      end;\n\n    _ ->\n      'Elixir.Macro':expand(Mod, E)\n  end,\n\n  ContextModules = [Expanded | ?key(E, context_modules)],\n  elixir_module:compile(Meta, Expanded, Block, [], false, E#{context_modules := ContextModules}).\n\nno_tail_optimize(Meta, Block) ->\n  {'__block__', Meta, [\n    {'=', Meta, [{result, Meta, ?MODULE}, Block]},\n    {{'.', Meta, [elixir_utils, noop]}, Meta, []},\n    {result, Meta, ?MODULE}\n  ]}.\n\n%% Bootstrapper\n\nbootstrap() ->\n  {ok, _} = application:ensure_all_started(elixir),\n  elixir_config:static(#{bootstrap => true}),\n  elixir_config:put(docs, false),\n  elixir_config:put(ignore_module_conflict, true),\n  elixir_config:put(on_undefined_variable, raise),\n  elixir_config:put(parser_options, []),\n  elixir_config:put(relative_paths, false),\n  elixir_config:put(tracers, []),\n  elixir_config:put(infer_signatures, []),\n  {Init, Main} = bootstrap_files(),\n  {ok, Cwd} = file:get_cwd(),\n  Lib = filename:join(Cwd, \"lib/elixir/lib\"),\n  [bootstrap_file(Lib, File) || File <- [<<\"kernel.ex\">> | Init]],\n  [bootstrap_file(Lib, File) || File <- [<<\"kernel.ex\">> | Main]].\n\nbootstrap_file(Lib, Suffix) ->\n  try\n    File = filename:join(Lib, Suffix),\n    Mods = file(File, fun(_, _) -> ok end),\n    _ = [binary_to_path(X, \"lib/elixir/ebin\") || X <- Mods],\n    io:format(\"Compiled ~ts~n\", [Suffix])\n  catch\n    Kind:Reason:Stacktrace ->\n      io:format(\"~p: ~p~nstacktrace: ~p~n\", [Kind, Reason, Stacktrace]),\n      erlang:halt(1)\n  end.\n\nbootstrap_files() ->\n  {\n    [\n     <<\"kernel/utils.ex\">>,\n     <<\"macro/env.ex\">>,\n     <<\"range.ex\">>,\n     <<\"keyword.ex\">>,\n     <<\"module.ex\">>,\n     <<\"list.ex\">>,\n     <<\"macro.ex\">>,\n     <<\"kernel/typespec.ex\">>,\n     <<\"code.ex\">>,\n     <<\"code/identifier.ex\">>,\n     <<\"protocol.ex\">>,\n     <<\"stream/reducers.ex\">>,\n     <<\"enum.ex\">>,\n     <<\"regex.ex\">>,\n     <<\"inspect/algebra.ex\">>,\n     <<\"inspect.ex\">>,\n     <<\"string.ex\">>,\n     <<\"string/chars.ex\">>\n    ],\n    [\n     <<\"list/chars.ex\">>,\n     <<\"bitwise.ex\">>,\n     <<\"map.ex\">>,\n     <<\"module/parallel_checker.ex\">>,\n     <<\"module/behaviour.ex\">>,\n     <<\"module/types/helpers.ex\">>,\n     <<\"module/types/descr.ex\">>,\n     <<\"module/types/of.ex\">>,\n     <<\"module/types/pattern.ex\">>,\n     <<\"module/types/apply.ex\">>,\n     <<\"module/types/expr.ex\">>,\n     <<\"module/types/traverse.ex\">>,\n     <<\"module/types.ex\">>,\n     <<\"exception.ex\">>,\n     <<\"path.ex\">>,\n     <<\"file.ex\">>,\n     <<\"access.ex\">>,\n     <<\"io.ex\">>,\n     <<\"system.ex\">>,\n     <<\"code/formatter.ex\">>,\n     <<\"code/normalizer.ex\">>,\n     <<\"kernel/cli.ex\">>,\n     <<\"kernel/error_handler.ex\">>,\n     <<\"kernel/parallel_compiler.ex\">>,\n     <<\"kernel/lexical_tracker.ex\">>\n    ]\n  }.\n\nbinary_to_path({ModuleName, Binary}, CompilePath) ->\n  Path = filename:join(CompilePath, atom_to_list(ModuleName) ++ \".beam\"),\n  case file:write_file(Path, Binary) of\n    ok -> Path;\n    {error, Reason} -> error('Elixir.File.Error':exception([{action, \"write to\"}, {path, Path}, {reason, Reason}]))\n  end.\n"
  },
  {
    "path": "lib/elixir/src/elixir_config.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_config).\n-compile({no_auto_import, [get/1]}).\n-export([new/1, warn/2, serial/1]).\n-export([static/1, is_bootstrap/0, identifier_tokenizer/0]).\n-export([delete/1, put/2, get/1, get/2, update/2, get_and_put/2]).\n-export([start_link/0, init/1, handle_call/3, handle_cast/2]).\n-behaviour(gen_server).\n\n%% Persistent term\n\nstatic(Map) when is_map(Map) ->\n  persistent_term:put(?MODULE, maps:merge(persistent_term:get(?MODULE, #{}), Map)).\nis_bootstrap() ->\n  maps:get(bootstrap, persistent_term:get(?MODULE, #{}), false).\nidentifier_tokenizer() ->\n  maps:get(identifier_tokenizer, persistent_term:get(?MODULE, #{}), 'Elixir.String.Tokenizer').\n\n%% Key-value store (concurrent reads, serial writes)\n\nget(Key) ->\n  [{_, Value}] = ets:lookup(?MODULE, Key),\n  Value.\n\nget(Key, Default) ->\n  try ets:lookup(?MODULE, Key) of\n    [{_, Value}] -> Value;\n    [] -> Default\n  catch\n    _:_ -> Default\n  end.\n\nput(Key, Value) ->\n  gen_server:call(?MODULE, {put, Key, Value}, infinity).\n\nget_and_put(Key, Value) ->\n  gen_server:call(?MODULE, {get_and_put, Key, Value}, infinity).\n\nupdate(Key, Fun) ->\n  gen_server:call(?MODULE, {update, Key, Fun}, infinity).\n\nnew(Opts) ->\n  Tab = ets:new(?MODULE, [named_table, public, {read_concurrency, true}]),\n  true = ets:insert_new(?MODULE, Opts),\n  Tab.\n\ndelete(?MODULE) ->\n  ets:delete(?MODULE).\n\n%% MISC\n\nserial(Fun) ->\n  gen_server:call(?MODULE, {serial, Fun}, infinity).\n\n%% Used to guarantee warnings are emitted only once per caller.\nwarn(Key, [{Mod, Fun, ArgsOrArity, _} | _]) ->\n  EtsKey = {warn, Key, Mod, Fun, to_arity(ArgsOrArity)},\n  ets:update_counter(?MODULE, EtsKey, {2, 1, 1, 1}, {EtsKey, -1}) =:= 0;\n\nwarn(_, _) ->\n  true.\n\nto_arity(Args) when is_list(Args) -> length(Args);\nto_arity(Arity) -> Arity.\n\n%% gen_server api\n\nstart_link() ->\n  gen_server:start_link({local, ?MODULE}, ?MODULE, ?MODULE, []).\n\ninit(?MODULE) ->\n  {ok, []}.\n\nhandle_call({serial, Fun}, _From, State) ->\n  {reply, Fun(), State};\n  handle_call({put, Key, Value}, _From, State) ->\n  ets:insert(?MODULE, {Key, Value}),\n  {reply, ok, State};\nhandle_call({update, Key, Fun}, _From, State) ->\n  Value = Fun(get(Key)),\n  ets:insert(?MODULE, {Key, Value}),\n  {reply, Value, State};\nhandle_call({get_and_put, Key, Value}, _From, State) ->\n  OldValue = get(Key),\n  ets:insert(?MODULE, {Key, Value}),\n  {reply, OldValue, State}.\n\nhandle_cast(Cast, Tab) ->\n  {stop, {bad_cast, Cast}, Tab}.\n"
  },
  {
    "path": "lib/elixir/src/elixir_def.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n% Holds the logic responsible for function definitions (def(p) and defmacro(p)).\n-module(elixir_def).\n-export([setup/1, reset_last/1, local_for/5, external_for/5,\n  take_definition/2, store_definition/3, store_definition/9,\n  fetch_definitions/2, format_error/1]).\n-include(\"elixir.hrl\").\n-define(last_def, {elixir, last_def}).\n\nsetup(DataTables) ->\n  reset_last(DataTables),\n  ok.\n\nreset_last({DataSet, _DataBag}) ->\n  ets:insert(DataSet, {?last_def, none});\n\nreset_last(Module) when is_atom(Module) ->\n  reset_last(elixir_module:data_tables(Module)).\n\n%% Finds the local definition for the current module.\nlocal_for(Meta, Name, Arity, Kinds, E) ->\n  External = fun({Mod, Fun}, Args) ->\n    invoke_external([{from_macro, true} | Meta], Mod, Fun, Args, E)\n  end,\n  fun_for(Meta, ?key(E, module), Name, Arity, Kinds, {value, External}).\n\n%% Finds the local definition for an external module.\nexternal_for(Meta, Module, Name, Arity, Kinds) ->\n  fun_for(Meta, Module, Name, Arity, Kinds, none).\n\nfun_for(Meta, Module, Name, Arity, Kinds, External) ->\n  Tuple = {Name, Arity},\n\n  try\n    {Set, Bag} = elixir_module:data_tables(Module),\n    {ets:lookup(Set, {def, Tuple}), ets:lookup(Bag, {clauses, Tuple})}\n  of\n    {[{_, Kind, LocalMeta, _, _, _}], ClausesPairs} ->\n      case (Kinds == all) orelse (lists:member(Kind, Kinds)) of\n        true ->\n          (Kind == defmacrop) andalso track_defmacrop(Module, Tuple),\n          Local = {value, fun(Fun, Args) -> invoke_local(Meta, Module, Fun, Args, External) end},\n          Clauses = [Clause || {_, Clause} <- ClausesPairs],\n          elixir_erl:definition_to_anonymous(Kind, LocalMeta, Clauses, Local, External);\n        false ->\n          false\n      end;\n    {[], _} ->\n      false\n  catch\n    _:_ -> false\n  end.\n\ninvoke_local(Meta, Module, ErlName, Args, External) ->\n  {Name, Arity} = elixir_utils:erl_fa_to_elixir_fa(ErlName, length(Args)),\n\n  case fun_for(Meta, Module, Name, Arity, all, External) of\n    false ->\n      {current_stacktrace, [_ | T]} = erlang:process_info(self(), current_stacktrace),\n      erlang:raise(error, undef, [{Module, Name, Arity, []} | T]);\n    Fun ->\n      apply(Fun, Args)\n  end.\n\ntrack_defmacrop(Module, FunArity) ->\n  {_, Bag} = elixir_module:data_tables(Module),\n  ets:insert(Bag, {used_private, FunArity}).\n\ninvoke_external(Meta, Mod, Name, Args, E) ->\n  is_map(E) andalso elixir_env:trace({require, Meta, Mod, []}, E),\n  apply(Mod, Name, Args).\n\n%% Take a definition out of the table\n\ntake_definition(Module, {Name, Arity} = Tuple) ->\n  {Set, Bag} = elixir_module:data_tables(Module),\n  case ets:take(Set, {def, Tuple}) of\n    [{{def, Tuple}, _, _, _, _, {Defaults, _, _}} = Result] ->\n      ets:delete_object(Bag, {defs, Tuple}),\n      ets:delete_object(Bag, {{default, Name}, Arity, Defaults}),\n      {Result, [Clause || {_, Clause} <- ets:take(Bag, {clauses, Tuple})]};\n    [] ->\n      false\n  end.\n\n%% Fetch all available definitions\n\nfetch_definitions(Module, E) ->\n  {Set, Bag} = elixir_module:data_tables(Module),\n\n  Entries = try\n    lists:sort(ets:lookup_element(Bag, defs, 2))\n  catch\n    error:badarg -> []\n  end,\n\n  fetch_definition(Entries, E, Module, Set, Bag, []).\n\nfetch_definition([Tuple | T], E, Module, Set, Bag, All) ->\n  [{_, Kind, Meta, _, _, {MaxDefaults, _, _}}] = ets:lookup(Set, {def, Tuple}),\n\n  try ets:lookup_element(Bag, {clauses, Tuple}, 2) of\n    Clauses ->\n      NewAll = [{Tuple, Kind, add_defaults_to_meta(MaxDefaults, Meta), Clauses} | All],\n      fetch_definition(T, E, Module, Set, Bag, NewAll)\n  catch\n    error:badarg ->\n      elixir_errors:module_error(Meta, E, ?MODULE, {function_head, Kind, Tuple}),\n      fetch_definition(T, E, Module, Set, Bag, All)\n  end;\n\nfetch_definition([], _E, _Module, _Set, _Bag, All) ->\n  All.\n\nadd_defaults_to_meta(0, Meta) -> Meta;\nadd_defaults_to_meta(Defaults, Meta) -> [{defaults, Defaults} | Meta].\n\n%% Section for storing definitions\n\nstore_definition(Kind, {Call, Body}, Pos) ->\n  E = elixir_module:get_cached_env(Pos),\n  store_definition(Kind, false, Call, Body, E);\nstore_definition(Kind, Key, Pos) ->\n  #{module := Module} = E = elixir_module:get_cached_env(Pos),\n  {Call, Body} = elixir_module:read_cache(Module, Key),\n  store_definition(Kind, true, Call, Body, E).\n\nstore_definition(Kind, HasNoUnquote, Call, Body, #{line := Line} = E) ->\n  {NameAndArgs, Guards} = elixir_utils:extract_guards(Call),\n\n  {Name, Meta, Args} = case NameAndArgs of\n    {N, M, A} when is_atom(N), is_atom(A) -> {N, M, []};\n    {N, M, A} when is_atom(N), is_list(A) -> {N, M, A};\n    _ -> elixir_errors:file_error([{line, Line}], E, ?MODULE, {invalid_def, Kind, NameAndArgs})\n  end,\n\n  Context = case lists:keyfind(context, 1, Meta) of\n    {context, _} = ContextPair -> [ContextPair];\n    _ -> []\n  end,\n\n  Column = case lists:keyfind(column, 1, Meta) of\n    {column, _} = ColumnPair -> [ColumnPair | Context];\n    _ -> Context\n  end,\n\n  Generated = case lists:keyfind(generated, 1, Meta) of\n    {generated, true} = GeneratedPair -> [GeneratedPair | Column];\n    _ -> Column\n  end,\n\n  CheckClauses = (Context == []) andalso HasNoUnquote,\n\n  %% Check if there is a file information in the definition.\n  %% If so, we assume this come from another source and\n  %% we need to linify taking into account keep line numbers.\n  %%\n  %% Line and File will always point to the caller. __ENV__.line\n  %% will always point to the quoted one and __ENV__.file will\n  %% always point to the one at @file or the quoted one.\n  {Location, LinifyArgs, LinifyGuards, LinifyBody} =\n    case elixir_utils:meta_keep(Meta) of\n      {_, _} = MetaFile ->\n        {MetaFile,\n         elixir_quote:linify(Line, keep, Args),\n         elixir_quote:linify(Line, keep, Guards),\n         elixir_quote:linify(Line, keep, Body)};\n      nil ->\n        {nil, Args, Guards, Body}\n    end,\n\n  Arity = length(Args),\n\n  {File, DefMeta} =\n    case retrieve_location(Location, ?key(E, module)) of\n      {AF, RF, L} ->\n        {AF, [{line, Line}, {file, {RF, L}} | Generated]};\n      nil ->\n        {nil, [{line, Line} | Generated]}\n    end,\n\n  run_with_location_change(File, E, fun(EL) ->\n    assert_no_aliases_name(DefMeta, Name, Args, EL),\n    assert_valid_name(DefMeta, Kind, Name, Args, EL),\n    store_definition(DefMeta, Kind, CheckClauses, Name, Arity,\n                     LinifyArgs, LinifyGuards, LinifyBody, ?key(E, file), EL)\n  end).\n\nstore_definition(Meta, Kind, CheckClauses, Name, Arity, DefaultsArgs, Guards, Body, File, ER) ->\n  Module = ?key(ER, module),\n  Tuple = {Name, Arity},\n  {S, E} = env_for_expansion(Kind, Tuple, ER),\n\n  {Args, Defaults} = unpack_defaults(Kind, Meta, Name, DefaultsArgs, S, E),\n  Clauses = [elixir_clauses:def(Clause, S, E) ||\n             Clause <- def_to_clauses(Kind, Meta, Args, Guards, Body, E)],\n\n  DefaultsLength = length(Defaults),\n  check_previous_defaults(Meta, Module, Name, Arity, Kind, DefaultsLength, E),\n\n  store_definition(CheckClauses, Kind, Meta, Name, Arity, File,\n                   Module, DefaultsLength, Clauses),\n  [store_definition(false, Kind, [{context, ?MODULE} | Meta], Name, length(DefaultArgs), File,\n                    Module, 0, [Default]) || {_, DefaultArgs, _, _} = Default <- Defaults],\n\n  run_on_definition_callbacks(Meta, Kind, Module, Name, DefaultsArgs, Guards, Body, E),\n  Tuple.\n\nenv_for_expansion(Kind, Tuple, E) when Kind =:= defmacro; Kind =:= defmacrop ->\n  S = elixir_env:env_to_ex(E),\n  {S#elixir_ex{caller=true}, E#{function := Tuple}};\nenv_for_expansion(_Kind, Tuple, E) ->\n  {elixir_env:env_to_ex(E), E#{function := Tuple}}.\n\nretrieve_location(Location, Module) ->\n  {Set, _} = elixir_module:data_tables(Module),\n  case ets:take(Set, file) of\n    [] when is_tuple(Location) ->\n      {File, Line} = Location,\n      {filename:absname(File), elixir_utils:relative_to_cwd(File), Line};\n    [] ->\n      nil;\n    [{file, File, _, _}] when is_binary(File) ->\n      'Elixir.Module':delete_attribute(Module, file),\n      {filename:absname(File), elixir_utils:relative_to_cwd(File), 0};\n    [{file, {File, Line}, _, _}] when is_binary(File) andalso is_integer(Line) ->\n      'Elixir.Module':delete_attribute(Module, file),\n      {filename:absname(File), elixir_utils:relative_to_cwd(File), Line}\n  end.\n\nrun_with_location_change(nil, E, Callback) ->\n  Callback(E);\nrun_with_location_change(File, #{file := File} = E, Callback) ->\n  Callback(E);\nrun_with_location_change(File, E, Callback) ->\n  elixir_lexical:with_file(File, E, Callback).\n\ndef_to_clauses(_Kind, Meta, Args, Guards, nil, E) ->\n  check_args_for_function_head(Meta, Args, E),\n  (Guards /= []) andalso elixir_errors:module_error(Meta, E, ?MODULE, {invalid_function_head, guards}),\n  [];\ndef_to_clauses(_Kind, Meta, Args, Guards, [{do, Body}], _E) ->\n  [{Meta, Args, Guards, Body}];\ndef_to_clauses(Kind, Meta, Args, Guards, Body, E) ->\n  case is_list(Body) andalso lists:keyfind(do, 1, Body) of\n    {do, _} ->\n      [{Meta, Args, Guards, {'try', [{origin,  Kind} | Meta], [Body]}}];\n    false ->\n      elixir_errors:file_error(Meta, E, elixir_expand, {missing_option, Kind, [do]})\n  end.\n\nrun_on_definition_callbacks(Meta, Kind, Module, Name, Args, Guards, Body, E) ->\n  {_, Bag} = elixir_module:data_tables(Module),\n  Callbacks = ets:lookup_element(Bag, {accumulate, on_definition}, 2),\n  _ = [begin\n    elixir_env:trace({remote_function, Meta, Mod, Fun, 6}, E),\n    Mod:Fun(E, Kind, Name, Args, Guards, Body)\n  end || {Mod, Fun} <- lists:reverse(Callbacks)],\n  ok.\n\nstore_definition(CheckClauses, Kind, Meta, Name, Arity, File, Module, Defaults, Clauses)\n    when is_boolean(CheckClauses) ->\n  {Set, Bag} = elixir_module:data_tables(Module),\n  Tuple = {Name, Arity},\n  HasBody = Clauses =/= [],\n\n  if\n    Defaults > 0 ->\n      ets:insert(Bag, {{default, Name}, Arity, Defaults});\n    true ->\n      ok\n  end,\n\n  {MaxDefaults, FirstMeta} =\n    case ets:lookup(Set, {def, Tuple}) of\n      [{_, StoredKind, StoredMeta, StoredFile, StoredCheck, {StoredDefaults, LastHasBody, LastDefaults}}] ->\n        check_valid_kind(Meta, File, Name, Arity, Kind, StoredKind, StoredFile, StoredMeta),\n        check_valid_defaults(Meta, File, Name, Arity, Kind, Defaults, StoredMeta, StoredDefaults, LastDefaults, HasBody, LastHasBody),\n        (CheckClauses and StoredCheck) andalso\n          check_valid_clause(Meta, File, Name, Arity, Kind, Set, StoredMeta, StoredFile, Clauses),\n\n        {max(Defaults, StoredDefaults), StoredMeta};\n      [] ->\n        ets:insert(Bag, {defs, Tuple}),\n        {Defaults, Meta}\n    end,\n\n  CheckClauses andalso ets:insert(Set, {?last_def, Tuple}),\n  ets:insert(Bag, [{{clauses, Tuple}, Clause} || Clause <- Clauses]),\n  ets:insert(Set, {{def, Tuple}, Kind, FirstMeta, File, CheckClauses, {MaxDefaults, HasBody, Defaults}}).\n\n%% Handling of defaults\n\nunpack_defaults(Kind, Meta, Name, Args, S, E) ->\n  {Expanded, #elixir_ex{unused={_, VersionOffset}}} = expand_defaults(Args, S, E#{context := nil}, []),\n  unpack_expanded(Kind, Meta, Name, Expanded, VersionOffset, [], []).\n\nunpack_expanded(Kind, Meta, Name, [{'\\\\\\\\', DefaultMeta, [Expr, _]} | T] = List, VersionOffset, Acc, Clauses) ->\n  Base = match_defaults(Acc, length(Acc) + VersionOffset, []),\n  {Args, Invoke} = extract_defaults(List, length(Base) + VersionOffset, [], []),\n  Clause = {Meta, Base ++ Args, [], {super, [{super, {Kind, Name}}, {default, true} | DefaultMeta], Base ++ Invoke}},\n  unpack_expanded(Kind, Meta, Name, T, VersionOffset, [Expr | Acc], [Clause | Clauses]);\nunpack_expanded(Kind, Meta, Name, [H | T], VersionOffset, Acc, Clauses) ->\n  unpack_expanded(Kind, Meta, Name, T, VersionOffset, [H | Acc], Clauses);\nunpack_expanded(_Kind, _Meta, _Name, [], _VersionOffset, Acc, Clauses) ->\n  {lists:reverse(Acc), lists:reverse(Clauses)}.\n\nexpand_defaults([{'\\\\\\\\', Meta, [Expr, Default]} | Args], S, E, Acc) ->\n  {ExpandedDefault, SE, _} = elixir_expand:expand(Default, S, E),\n  expand_defaults(Args, SE, E, [{'\\\\\\\\', Meta, [Expr, ExpandedDefault]} | Acc]);\nexpand_defaults([Arg | Args], S, E, Acc) ->\n   expand_defaults(Args, S, E, [Arg | Acc]);\nexpand_defaults([], S, _E, Acc) ->\n  {lists:reverse(Acc), S}.\n\nextract_defaults([{'\\\\\\\\', _, [_Expr, Default]} | T], Counter, NewArgs, NewInvoke) ->\n  extract_defaults(T, Counter, NewArgs, [Default | NewInvoke]);\nextract_defaults([_ | T], Counter, NewArgs, NewInvoke) ->\n  H = default_var(Counter),\n  extract_defaults(T, Counter + 1, [H | NewArgs], [H | NewInvoke]);\nextract_defaults([], _Counter, NewArgs, NewInvoke) ->\n  {lists:reverse(NewArgs), lists:reverse(NewInvoke)}.\n\nmatch_defaults([], _Counter, Acc) ->\n  Acc;\nmatch_defaults([_ | T], Counter, Acc) ->\n  NewCounter = Counter - 1,\n  match_defaults(T, NewCounter, [default_var(NewCounter) | Acc]).\n\ndefault_var(Counter) ->\n  {list_to_atom([$x | integer_to_list(Counter)]), [{generated, true}, {version, Counter}], ?var_context}.\n\n%% Validations\n\ncheck_valid_kind(_Meta, _File, _Name, _Arity, Kind, Kind, _StoredFile, _StoredMeta) -> ok;\ncheck_valid_kind(Meta, File, Name, Arity, Kind, StoredKind, StoredFile, StoredMeta) ->\n  elixir_errors:file_error(Meta, File, ?MODULE,\n    {changed_kind, {Name, Arity, StoredKind, Kind, StoredFile, ?line(StoredMeta)}}).\n\ncheck_valid_clause(Meta, File, Name, Arity, Kind, Set, StoredMeta, StoredFile, Clauses) ->\n  case ets:lookup_element(Set, ?last_def, 2) of\n    none ->\n      ok;\n    {Name, Arity} when Clauses == [] ->\n      elixir_errors:file_warn(Meta, File, ?MODULE,\n        {late_function_head, {Kind, Name, Arity}});\n    {Name, Arity} ->\n      ok;\n    {Name, _} ->\n      Relative = elixir_utils:relative_to_cwd(StoredFile),\n      elixir_errors:file_warn(Meta, File, ?MODULE,\n        {ungrouped_name, {Kind, Name, Arity, ?line(StoredMeta), Relative}});\n    _ ->\n      Relative = elixir_utils:relative_to_cwd(StoredFile),\n      elixir_errors:file_warn(Meta, File, ?MODULE,\n        {ungrouped_arity, {Kind, Name, Arity, ?line(StoredMeta), Relative}})\n  end.\n\n% Clause with defaults after clause with defaults\ncheck_valid_defaults(Meta, File, Name, Arity, Kind, Defaults, StoredMeta, StoredDefaults, _, _, _)\n    when Defaults > 0, StoredDefaults > 0 ->\n  elixir_errors:file_error(Meta, File, ?MODULE, {duplicate_defaults, {Kind, Name, Arity, StoredMeta}});\n% Clause with defaults after clause without defaults\ncheck_valid_defaults(Meta, File, Name, Arity, Kind, Defaults, StoredMeta, 0, _, _, _) when Defaults > 0 ->\n  elixir_errors:file_warn(Meta, File, ?MODULE, {mixed_defaults, {Kind, Name, Arity, StoredMeta}});\n% Clause without defaults directly after clause with defaults (bodiless does not count)\ncheck_valid_defaults(Meta, File, Name, Arity, Kind, 0, StoredMeta, _, LastDefaults, true, true) when LastDefaults > 0 ->\n  elixir_errors:file_warn(Meta, File, ?MODULE, {mixed_defaults, {Kind, Name, Arity, StoredMeta}});\n% Clause without defaults\ncheck_valid_defaults(_Meta, _File, _Name, _Arity, _Kind, 0, _StoredMeta, _StoredDefaults, _LastDefaults, _HasBody, _LastHasBody) ->\n  ok.\n\ncheck_args_for_function_head(Meta, Args, E) ->\n  [begin\n     elixir_errors:module_error(Meta, E, ?MODULE, {invalid_function_head, patterns})\n   end || Arg <- Args, invalid_arg(Arg)].\n\ninvalid_arg({Name, _, Kind}) when is_atom(Name), is_atom(Kind) -> false;\ninvalid_arg(_) -> true.\n\ncheck_previous_defaults(Meta, Module, Name, Arity, Kind, Defaults, E) ->\n  {_Set, Bag} = elixir_module:data_tables(Module),\n  Matches = ets:lookup(Bag, {default, Name}),\n  [begin\n     elixir_errors:file_error(Meta, E, ?MODULE,\n       {defs_with_defaults, Kind, Name, Arity, A})\n   end || {_, A, D} <- Matches, A /= Arity, D /= 0, defaults_conflict(A, D, Arity, Defaults)].\n\ndefaults_conflict(A, D, Arity, Defaults) ->\n  ((Arity >= (A - D)) andalso (Arity < A)) orelse\n    ((A >= (Arity - Defaults)) andalso (A < Arity)).\n\nassert_no_aliases_name(Meta, '__aliases__', [Atom], #{file := File}) when is_atom(Atom) ->\n  elixir_errors:file_error(Meta, File, ?MODULE, {no_alias, Atom});\nassert_no_aliases_name(_Meta, _Aliases, _Args, _S) ->\n  ok.\n\nassert_valid_name(Meta, Kind, '__info__', [_], #{file := File}) ->\n  elixir_errors:file_error(Meta, File, ?MODULE, {'__info__', Kind});\nassert_valid_name(Meta, Kind, 'module_info', [], #{file := File}) ->\n  elixir_errors:file_error(Meta, File, ?MODULE, {module_info, Kind, 0});\nassert_valid_name(Meta, Kind, 'module_info', [_], #{file := File}) ->\n  elixir_errors:file_error(Meta, File, ?MODULE, {module_info, Kind, 1});\nassert_valid_name(Meta, Kind, is_record, [_, _], #{file := File}) when Kind == defp; Kind == def ->\n  elixir_errors:file_error(Meta, File, ?MODULE, {is_record, Kind});\nassert_valid_name(_Meta, _Kind, _Name, _Args, _S) ->\n  ok.\n\n%% Format errors\n\nformat_error({function_head, Kind, {Name, Arity}}) ->\n  io_lib:format(\"implementation not provided for predefined ~ts ~ts/~B\", [Kind, Name, Arity]);\n\nformat_error({no_module, {Kind, Name, Arity}}) ->\n  io_lib:format(\"cannot define function outside module, invalid scope for ~ts ~ts/~B\", [Kind, Name, Arity]);\n\nformat_error({defs_with_defaults, Kind, Name, Arity, A}) when Arity > A ->\n  io_lib:format(\"~ts ~ts/~B defaults conflicts with ~ts/~B\",\n    [Kind, Name, Arity, Name, A]);\n\nformat_error({defs_with_defaults, Kind, Name, Arity, A}) when Arity < A ->\n  io_lib:format(\"~ts ~ts/~B conflicts with defaults from ~ts/~B\",\n    [Kind, Name, Arity, Name, A]);\n\nformat_error({duplicate_defaults, {Kind, Name, Arity, StoredMeta}}) ->\n  io_lib:format(\n    \"~ts ~ts/~B defines defaults multiple times. \"\n    \"Elixir allows defaults to be declared once per definition. Instead of:\\n\"\n    \"\\n\"\n    \"    def foo(:first_clause, b \\\\\\\\ :default) do ... end\\n\"\n    \"    def foo(:second_clause, b \\\\\\\\ :default) do ... end\\n\"\n    \"\\n\"\n    \"one should write:\\n\"\n    \"\\n\"\n    \"    def foo(a, b \\\\\\\\ :default)\\n\"\n    \"    def foo(:first_clause, b) do ... end\\n\"\n    \"    def foo(:second_clause, b) do ... end\\n\"\n    \"~ts\",\n    [Kind, Name, Arity, maybe_stored_meta_line(StoredMeta)]);\n\nformat_error({mixed_defaults, {Kind, Name, Arity, StoredMeta}}) ->\n  io_lib:format(\n    \"~ts ~ts/~B has multiple clauses and also declares default values. \"\n    \"In such cases, the default values should be defined in a header. Instead of:\\n\"\n    \"\\n\"\n    \"    def foo(:first_clause, b \\\\\\\\ :default) do ... end\\n\"\n    \"    def foo(:second_clause, b) do ... end\\n\"\n    \"\\n\"\n    \"one should write:\\n\"\n    \"\\n\"\n    \"    def foo(a, b \\\\\\\\ :default)\\n\"\n    \"    def foo(:first_clause, b) do ... end\\n\"\n    \"    def foo(:second_clause, b) do ... end\\n\"\n    \"~ts\",\n    [Kind, Name, Arity, maybe_stored_meta_line(StoredMeta)]);\n\nformat_error({ungrouped_name, {Kind, Name, Arity, OrigLine, OrigFile}}) ->\n   io_lib:format(\"clauses with the same name should be grouped together, \\\"~ts ~ts/~B\\\" was previously defined (~ts:~B)\",\n     [Kind, Name, Arity, OrigFile, OrigLine]);\n\nformat_error({ungrouped_arity, {Kind, Name, Arity, OrigLine, OrigFile}}) ->\n  io_lib:format(\"clauses with the same name and arity (number of arguments) should be grouped together, \\\"~ts ~ts/~B\\\" was previously defined (~ts:~B)\",\n    [Kind, Name, Arity, OrigFile, OrigLine]);\n\nformat_error({late_function_head, {Kind, Name, Arity}}) ->\n  io_lib:format(\"function head for ~ts ~ts/~B must come at the top of its direct implementation. Instead of:\\n\"\n    \"\\n\"\n    \"    def add(a, b), do: a + b\\n\"\n    \"    def add(a, b)\\n\"\n    \"\\n\"\n    \"one should write:\\n\"\n    \"\\n\"\n    \"    def add(a, b)\\n\"\n    \"    def add(a, b), do: a + b\\n\",\n    [Kind, Name, Arity]);\n\nformat_error({changed_kind, {Name, Arity, Previous, Current, OrigFile, OrigLine}}) ->\n  OrigFileRelative = elixir_utils:relative_to_cwd(OrigFile),\n  io_lib:format(\"~ts ~ts/~B already defined as ~ts in ~ts:~B\", [Current, Name, Arity, Previous, OrigFileRelative, OrigLine]);\n\nformat_error({no_alias, Atom}) ->\n  io_lib:format(\"function names should start with lowercase characters or underscore, invalid name ~ts\", [Atom]);\n\nformat_error({invalid_def, Kind, NameAndArgs}) ->\n  io_lib:format(\"invalid syntax in ~ts ~ts\", [Kind, 'Elixir.Macro':to_string(NameAndArgs)]);\n\nformat_error({invalid_function_head, Prefix}) ->\n  atom_to_list(Prefix) ++ (\n  \" are not allowed in function head, only variables and default arguments (using \\\\\\\\)\\n\"\n  \"\\n\"\n  \"If you did not intend to define a function head, make sure your function \"\n  \"definition has the proper syntax by wrapping the arguments in parentheses \"\n  \"and using the do keyword accordingly:\\n\\n\"\n  \"    def add(a, b), do: a + b\\n\\n\"\n  \"    def add(a, b) do\\n\"\n  \"      a + b\\n\"\n  \"    end\\n\");\n\nformat_error({'__info__', Kind}) ->\n  io_lib:format(\"cannot define ~ts __info__/1 as it is automatically defined by Elixir\", [Kind]);\n\nformat_error({module_info, Kind, Arity}) ->\n  io_lib:format(\"cannot define ~ts module_info/~B as it is automatically defined by Erlang\", [Kind, Arity]);\n\nformat_error({is_record, Kind}) ->\n  io_lib:format(\"cannot define ~ts is_record/2 due to compatibility \"\n                \"with the Erlang compiler (it is a known limitation)\", [Kind]).\n\nmaybe_stored_meta_line(StoredMeta) ->\n  case lists:keyfind(line, 1, StoredMeta) of\n    {line, Line} when Line > 0 ->\n      \"\\nthe previous clause is defined on line \" ++ integer_to_list(Line) ++ \"\\n\";\n    _ -> \"\"\n  end.\n"
  },
  {
    "path": "lib/elixir/src/elixir_dispatch.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Helpers related to dispatching to imports and references.\n%% This module access the information stored on the scope\n%% by elixir_import and therefore assumes it is normalized (ordsets)\n-module(elixir_dispatch).\n-export([dispatch_import/6, dispatch_require/7,\n  require_function/5, import_function/4,\n  expand_import/7, expand_require/6, check_deprecated/6,\n  default_functions/0, default_macros/0, default_requires/0,\n  find_import/4, find_imports/3, format_error/1, stop_generated/1]).\n-include(\"elixir.hrl\").\n-import(ordsets, [is_element/2]).\n-define(kernel, 'Elixir.Kernel').\n-define(application, 'Elixir.Application').\n\ndefault_functions() ->\n  [{?kernel, elixir_imported_functions()}].\ndefault_macros() ->\n  [{?kernel, elixir_imported_macros()}].\ndefault_requires() ->\n  ['Elixir.Application', 'Elixir.Kernel'].\n\n%% This is used by elixir_quote. Note we don't record the\n%% import locally because at that point there is no\n%% ambiguity.\nfind_import(Meta, Name, Arity, E) ->\n  Tuple = {Name, Arity},\n\n  case find_import_by_name_arity(Meta, Tuple, [], E) of\n    {function, Receiver} ->\n      elixir_env:trace({imported_function, Meta, Receiver, Name, Arity}, E),\n      Receiver;\n    {macro, Receiver} ->\n      elixir_env:trace({imported_macro, Meta, Receiver, Name, Arity}, E),\n      Receiver;\n    {ambiguous, _} = Ambiguous ->\n      elixir_errors:file_error(Meta, E, ?MODULE, {import, Ambiguous, Name, Arity});\n    _ ->\n      false\n  end.\n\nfind_imports(Meta, Name, E) ->\n  Funs = ?key(E, functions),\n  Macs = ?key(E, macros),\n\n  Acc0 = #{},\n  Acc1 = find_imports_by_name(Funs, Acc0, Name, Meta, E),\n  Acc2 = find_imports_by_name(Macs, Acc1, Name, Meta, E),\n\n  lists:sort(maps:to_list(Acc2)).\n\n%% Function retrieval\n\nimport_function(Meta, Name, Arity, E) ->\n  Tuple = {Name, Arity},\n  case find_import_by_name_arity(Meta, Tuple, [], E) of\n    {function, Receiver} ->\n      elixir_env:trace({imported_function, Meta, Receiver, Name, Arity}, E),\n      elixir_import:record(Tuple, Receiver, ?key(E, module), ?key(E, function)),\n      remote_function(Meta, Receiver, Name, Arity, E);\n    {macro, _Receiver} ->\n      false;\n    {import, Receiver} ->\n      require_function(Meta, Receiver, Name, Arity, E);\n    {ambiguous, _} = Ambiguous ->\n      elixir_errors:file_error(Meta, E, ?MODULE, {import, Ambiguous, Name, Arity});\n    false ->\n      case elixir_import:special_form(Name, Arity) of\n        true ->\n          false;\n        false ->\n          Function = ?key(E, function),\n\n          case (Function /= nil) andalso (Function /= Tuple) andalso\n                elixir_def:local_for(Meta, Name, Arity, [defmacro, defmacrop], E) of\n            false ->\n              elixir_env:trace({local_function, Meta, Name, Arity}, E),\n              {local, Name, Arity};\n            _ ->\n              false\n          end\n      end\n  end.\n\nrequire_function(Meta, Receiver, Name, Arity, E) ->\n  Required = is_element(Receiver, ?key(E, requires)),\n\n  case is_macro(Name, Arity, Receiver, Required) of\n    true  -> false;\n    false ->\n      elixir_env:trace({remote_function, Meta, Receiver, Name, Arity}, E),\n      remote_function(Meta, Receiver, Name, Arity, E)\n  end.\n\nremote_function(Meta, Receiver, Name, Arity, E) ->\n  check_deprecated(function, Meta, Receiver, Name, Arity, E),\n\n  case elixir_rewrite:inline(Receiver, Name, Arity) of\n    {AR, AN} -> {remote, AR, AN, Arity};\n    false    -> {remote, Receiver, Name, Arity}\n  end.\n\n%% Dispatches\n\ndispatch_import(Meta, Name, Args, S, E, Callback) ->\n  Arity = length(Args),\n\n  AllowLocals =\n    %% If we are inside a function, we support reading from locals.\n    case E of\n      #{function := {N, A}} when Name =/= N; Arity =/= A -> true;\n      _ -> false\n    end,\n\n  case expand_import(Meta, Name, Arity, E, [], AllowLocals, true) of\n    {macro, Receiver, Expander} ->\n      check_deprecated(macro, Meta, Receiver, Name, Arity, E),\n      Caller = {?line(Meta), S, E},\n      expand_quoted(Meta, Receiver, Name, Arity, Expander(stop_generated(Args), Caller), S, E);\n    {function, Receiver, NewName} ->\n      case elixir_rewrite:inline(Receiver, NewName, Arity) of\n        {AR, AN} ->\n          Callback({AR, AN});\n        false ->\n          check_deprecated(function, Meta, Receiver, Name, Arity, E),\n          Callback({Receiver, NewName})\n      end;\n    not_found ->\n      Callback(local);\n    Error ->\n      elixir_errors:file_error(Meta, E, ?MODULE, {import, Error, Name, Arity})\n  end.\n\nstop_generated(Args) ->\n  lists:map(fun\n    ({Call, Meta, Ctx}) when is_list(Meta) -> {Call, [{stop_generated, true} | Meta], Ctx};\n    (Other) -> Other\n  end, Args).\n\ndispatch_require(Meta, Receiver, Name, Args, S, E, Callback) when is_atom(Receiver) ->\n  Arity = length(Args),\n\n  case elixir_rewrite:inline(Receiver, Name, Arity) of\n    {AR, AN} ->\n      elixir_env:trace({remote_function, Meta, Receiver, Name, Arity}, E),\n      Callback(AR, AN);\n    false ->\n      case expand_require(Meta, Receiver, Name, Arity, E, true) of\n        {macro, Receiver, Expander} ->\n          check_deprecated(macro, Meta, Receiver, Name, Arity, E),\n          Caller = {?line(Meta), S, E},\n          expand_quoted(Meta, Receiver, Name, Arity, Expander(Args, Caller), S, E);\n        error ->\n          check_deprecated(function, Meta, Receiver, Name, Arity, E),\n          elixir_env:trace({remote_function, Meta, Receiver, Name, Arity}, E),\n          Callback(Receiver, Name)\n      end\n  end;\n\ndispatch_require(_Meta, Receiver, Name, _Args, _S, _E, Callback) ->\n  Callback(Receiver, Name).\n\n%% Macros expansion\n\nexpand_import(Meta, Name, Arity, E, Extra, AllowLocals, Trace) ->\n  Tuple = {Name, Arity},\n  Module = ?key(E, module),\n  Dispatch = find_import_by_name_arity(Meta, Tuple, Extra, E),\n\n  case Dispatch of\n    {ambiguous, Ambiguous} ->\n      {ambiguous, Ambiguous};\n\n    {import, _} ->\n      do_expand_import(Dispatch, Meta, Name, Arity, Module, E, Trace);\n\n    _ ->\n      Local = case AllowLocals of\n        false -> false;\n        true  -> elixir_def:local_for(Meta, Name, Arity, [defmacro, defmacrop], E);\n        Fun when is_function(Fun, 0) -> Fun()\n      end,\n\n      case Dispatch of\n        %% There is a local and an import. This is a conflict unless\n        %% the receiver is the same as module (happens on bootstrap).\n        {_, Receiver} when Local /= false, Receiver /= Module ->\n          {conflict, Receiver};\n\n        %% There is no local. Dispatch the import.\n        _ when Local == false ->\n          do_expand_import(Dispatch, Meta, Name, Arity, Module, E, Trace);\n\n        %% Dispatch to the local.\n        _ ->\n          Trace andalso elixir_env:trace({local_macro, Meta, Name, Arity}, E),\n          {macro, Module, expander_macro_fun(Meta, Local, Module, Name, E)}\n      end\n  end.\n\ndo_expand_import(Result, Meta, Name, Arity, Module, E, Trace) ->\n  case Result of\n    {function, Receiver} ->\n      Trace andalso begin\n        elixir_env:trace({imported_function, Meta, Receiver, Name, Arity}, E),\n        elixir_import:record({Name, Arity}, Receiver, Module, ?key(E, function))\n      end,\n      {function, Receiver, Name};\n    {macro, Receiver} ->\n      Trace andalso begin\n        elixir_env:trace({imported_macro, Meta, Receiver, Name, Arity}, E),\n        elixir_import:record({Name, Arity}, Receiver, Module, ?key(E, function))\n      end,\n      {macro, Receiver, expander_macro_named(Meta, Receiver, Name, Arity, E)};\n    {import, Receiver} ->\n      case expand_require(true, Meta, Receiver, Name, Arity, E, Trace) of\n        {macro, _, _} = Response -> Response;\n        error ->\n          Trace andalso elixir_env:trace({remote_function, Meta, Receiver, Name, Arity}, E),\n          {function, Receiver, Name}\n      end;\n    false when Module == ?kernel ->\n      case elixir_rewrite:inline(Module, Name, Arity) of\n        {AR, AN} -> {function, AR, AN};\n        false -> not_found\n      end;\n    false ->\n      not_found\n  end.\n\nexpand_require(Meta, Receiver, Name, Arity, E, Trace) ->\n  Required = (Receiver == ?key(E, module))\n    orelse (lists:keyfind(required, 1, Meta) == {required, true})\n    orelse is_element(Receiver, ?key(E, requires)),\n\n  expand_require(Required, Meta, Receiver, Name, Arity, E, Trace).\n\nexpand_require(Required, Meta, Receiver, Name, Arity, E, Trace) ->\n  case is_macro(Name, Arity, Receiver, Required) of\n    true ->\n      Trace andalso elixir_env:trace({remote_macro, Meta, Receiver, Name, Arity}, E),\n      {macro, Receiver, expander_macro_named(Meta, Receiver, Name, Arity, E)};\n    false ->\n      error\n  end.\n\n%% Expansion helpers\n\nexpander_macro_fun(Meta, Fun, Receiver, Name, E) ->\n  fun(Args, Caller) -> expand_macro_fun(Meta, Fun, Receiver, Name, Args, Caller, E) end.\n\nexpander_macro_named(Meta, Receiver, Name, Arity, E) ->\n  ProperName  = elixir_utils:macro_name(Name),\n  ProperArity = Arity + 1,\n  Fun         = fun Receiver:ProperName/ProperArity,\n  fun(Args, Caller) -> expand_macro_fun(Meta, Fun, Receiver, Name, Args, Caller, E) end.\n\nexpand_macro_fun(Meta, Fun, Receiver, Name, Args, Caller, E) ->\n  try\n    apply(Fun, [Caller | Args])\n  catch\n    Kind:Reason:Stacktrace ->\n      Arity = length(Args),\n      MFA  = {Receiver, elixir_utils:macro_name(Name), Arity+1},\n      Info = [{Receiver, Name, Arity, [{file, \"expanding macro\"}]}, caller(?line(Meta), E)],\n      erlang:raise(Kind, Reason, prune_stacktrace(Stacktrace, MFA, Info, {ok, Caller}))\n  end.\n\nexpand_quoted(Meta, Receiver, Name, Arity, Quoted, S, E) ->\n  Next = elixir_module:next_counter(?key(E, module)),\n\n  try\n    ToExpand = elixir_quote:linify_with_context_counter(Meta, {Receiver, Next}, Quoted),\n    elixir_expand:expand(ToExpand, S, E)\n  catch\n    Kind:Reason:Stacktrace ->\n      MFA  = {Receiver, elixir_utils:macro_name(Name), Arity+1},\n      Info = [{Receiver, Name, Arity, [{file, \"expanding macro\"}]}, caller(?line(Meta), E)],\n      erlang:raise(Kind, Reason, prune_stacktrace(Stacktrace, MFA, Info, error))\n  end.\n\ncaller(Line, E) ->\n  elixir_utils:caller(Line, ?key(E, file), ?key(E, module), ?key(E, function)).\n\n%% Helpers\n\nfind_imports_by_name([{Mod, Imports} | ModImports], Acc, Name, Meta, E) ->\n  NewAcc = find_imports_by_name(Name, Imports, Acc, Mod, Meta, E),\n  find_imports_by_name(ModImports, NewAcc, Name, Meta, E);\nfind_imports_by_name([], Acc, _Name, _Meta, _E) ->\n  Acc.\n\nfind_imports_by_name(Name, [{Name, Arity} | Imports], Acc, Mod, Meta, E) ->\n  case Acc of\n    #{Arity := OtherMod} ->\n      Error = {import, {ambiguous, [Mod, OtherMod]}, Name, Arity},\n      elixir_errors:file_error(Meta, E, ?MODULE, Error);\n\n    #{} ->\n      find_imports_by_name(Name, Imports, Acc#{Arity => Mod}, Mod, Meta, E)\n  end;\nfind_imports_by_name(Name, [{ImportName, _} | Imports], Acc, Mod, Meta, E) when Name > ImportName ->\n  find_imports_by_name(Name, Imports, Acc, Mod, Meta, E);\nfind_imports_by_name(_Name, _Imports, Acc, _Mod, _Meta, _E) ->\n  Acc.\n\nfind_import_by_name_arity(Meta, {_Name, Arity} = Tuple, Extra, E) ->\n  case is_import(Meta, Arity) of\n    {import, _} = Import ->\n      Import;\n    false ->\n      Funs = ?key(E, functions),\n      Macs = Extra ++ ?key(E, macros),\n      FunMatch = find_import_by_name_arity(Tuple, Funs),\n      MacMatch = find_import_by_name_arity(Tuple, Macs),\n\n      case {FunMatch, MacMatch} of\n        {[], [Receiver]} -> {macro, Receiver};\n        {[Receiver], []} -> {function, Receiver};\n        {[], []} -> false;\n        _ -> {ambiguous, FunMatch ++ MacMatch}\n      end\n  end.\n\nfind_import_by_name_arity(Tuple, List) ->\n  [Receiver || {Receiver, Set} <- List, is_element(Tuple, Set)].\n\nis_import(Meta, Arity) ->\n  case lists:keyfind(imports, 1, Meta) of\n    {imports, [_ | _] = Imports} ->\n      case lists:keyfind(context, 1, Meta) of\n        {context, _} ->\n          case lists:keyfind(Arity, 1, Imports) of\n            {Arity, Receiver} -> {import, Receiver};\n            false -> false\n          end;\n        false -> false\n      end;\n    _ -> false\n  end.\n\n% %% We've reached the macro wrapper fun, skip it with the rest\nprune_stacktrace([{_, _, [Caller | _], _} | _], _MFA, Info, {ok, Caller}) ->\n  Info;\n%% We've reached the invoked macro, skip it\nprune_stacktrace([{M, F, A, _} | _], {M, F, A}, Info, _E) ->\n  Info;\n%% We've reached the elixir_dispatch internals, skip it with the rest\nprune_stacktrace([{Mod, _, _, _} | _], _MFA, Info, _E) when Mod == elixir_dispatch; Mod == elixir_exp ->\n  Info;\nprune_stacktrace([H | T], MFA, Info, E) ->\n  [H | prune_stacktrace(T, MFA, Info, E)];\nprune_stacktrace([], _MFA, Info, _E) ->\n  Info.\n\n%% ERROR HANDLING\n\nformat_error({import, {conflict, Receiver}, Name, Arity}) ->\n  io_lib:format(\"call to local macro ~ts/~B conflicts with imported ~ts.~ts/~B, \"\n    \"please rename the local macro or remove the conflicting import\",\n    [Name, Arity, elixir_aliases:inspect(Receiver), Name, Arity]);\nformat_error({import, {ambiguous, [Mod1, Mod2 | _]}, Name, Arity}) ->\n  io_lib:format(\"function ~ts/~B imported from both ~ts and ~ts, call is ambiguous\",\n    [Name, Arity, elixir_aliases:inspect(Mod1), elixir_aliases:inspect(Mod2)]);\nformat_error({compile_env, Name, Arity}) ->\n  io_lib:format(\"Application.~s/~B is discouraged in the module body, use Application.compile_env/3 instead\", [Name, Arity]);\nformat_error({deprecated, Mod, '__using__', 1, Message}) ->\n  io_lib:format(\"use ~s is deprecated. ~s\", [elixir_aliases:inspect(Mod), Message]);\nformat_error({deprecated, Mod, Fun, Arity, Message}) ->\n  io_lib:format(\"~s.~s/~B is deprecated. ~s\",[elixir_aliases:inspect(Mod), Fun, Arity, Message]).\n\n%% INTROSPECTION\n\nis_macro(_Name, _Arity, _Module, false) ->\n  false;\nis_macro(Name, Arity, Receiver, true) ->\n  try Receiver:'__info__'(macros) of\n    Macros -> is_element({Name, Arity}, Macros)\n  catch\n    error:_ -> false\n  end.\n\n%% Deprecations checks only happen at the module body,\n%% so in there we can try to at least load the module.\nget_deprecations(Receiver) ->\n  case code:ensure_loaded(Receiver) of\n    {module, Receiver} -> get_info(Receiver, deprecated);\n    _ -> []\n  end.\n\nget_info(Receiver, Key) ->\n  case erlang:function_exported(Receiver, '__info__', 1) of\n    true ->\n      try\n        Receiver:'__info__'(Key)\n      catch\n        error:_ -> []\n      end;\n    false ->\n      []\n  end.\n\nelixir_imported_functions() ->\n  try\n    ?kernel:'__info__'(functions)\n  catch\n    error:undef -> []\n  end.\n\nelixir_imported_macros() ->\n  try\n    ?kernel:'__info__'(macros)\n  catch\n    error:undef -> []\n  end.\n\ncheck_deprecated(_, _, erlang, _, _, _) -> ok;\ncheck_deprecated(_, _, elixir_def, _, _, _) -> ok;\ncheck_deprecated(_, _, elixir_module, _, _, _) -> ok;\ncheck_deprecated(_, _, ?kernel, _, _, _) -> ok;\ncheck_deprecated(Kind, Meta, ?application, Name, Arity, E) ->\n  case E of\n    #{module := Module, function := nil}\n    when (Module /= nil) or (Kind == macro), (Name == get_env) orelse (Name == fetch_env) orelse (Name == 'fetch_env!') ->\n      elixir_errors:file_warn(Meta, E, ?MODULE, {compile_env, Name, Arity});\n\n    _ ->\n      ok\n  end;\ncheck_deprecated(Kind, Meta, Receiver, Name, Arity, E) ->\n  %% Any compile time behavior cannot be verified by the runtime group pass.\n  case ((?key(E, function) == nil) or (Kind == macro)) andalso get_deprecations(Receiver) of\n    [_ | _] = Deprecations ->\n      case lists:keyfind({Name, Arity}, 1, Deprecations) of\n        {_, Message} ->\n          elixir_errors:file_warn(Meta, E, ?MODULE, {deprecated, Receiver, Name, Arity, Message});\n\n        false ->\n          false\n      end;\n\n    _ ->\n      ok\n  end.\n"
  },
  {
    "path": "lib/elixir/src/elixir_env.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_env).\n-include(\"elixir.hrl\").\n-export([\n  new/0, to_caller/1, merge_vars/2, with_vars/2, reset_vars/1, env_to_ex/1,\n  reset_unused_vars/1, check_unused_vars/2, merge_and_check_unused_vars/3, calculate_span/2,\n  trace/2, format_error/1,\n  reset_read/2, prepare_write/1, prepare_write/2, close_write/2\n]).\n\nnew() ->\n  #{\n    '__struct__' => 'Elixir.Macro.Env',\n    module => nil,                                    %% the current module\n    file => <<\"nofile\">>,                             %% the current filename\n    line => 1,                                        %% the current line\n    function => nil,                                  %% the current function\n    context => nil,                                   %% can be match, guard or nil\n    aliases => [],                                    %% a list of aliases by new -> old names\n    requires => elixir_dispatch:default_requires(),   %% a set with modules required\n    functions => elixir_dispatch:default_functions(), %% a list with functions imported from module\n    macros => elixir_dispatch:default_macros(),       %% a list with macros imported from module\n    macro_aliases => [],                              %% keep aliases defined inside a macro\n    context_modules => [],                            %% modules defined in the current context\n    versioned_vars => #{},                            %% a map of vars with their latest versions\n    lexical_tracker => nil,                           %% lexical tracker PID\n    tracers => []                                     %% available compilation tracers\n  }.\n\ntrace(Event, #{tracers := Tracers} = E) ->\n  [ok = Tracer:trace(Event, E) || Tracer <- Tracers],\n  ok.\n\nto_caller({Line, #elixir_ex{vars={Read, _}}, Env}) ->\n  Env#{line := Line, versioned_vars := Read};\nto_caller(#{'__struct__' := 'Elixir.Macro.Env'} = Env) ->\n  Env.\n\nwith_vars(Env, Vars) when is_list(Vars) ->\n  {ReversedVars, _} =\n    lists:foldl(fun(Var, {Acc, I}) -> {[{Var, I} | Acc], I + 1} end, {[], 0}, Vars),\n  Env#{versioned_vars := maps:from_list(ReversedVars)};\nwith_vars(Env, #{} = Vars) ->\n  Env#{versioned_vars := Vars}.\n\nreset_vars(Env) ->\n  Env#{versioned_vars := #{}}.\n\n%% CONVERSIONS\n\nenv_to_ex(#{context := match, versioned_vars := Vars}) ->\n  Counter = map_size(Vars),\n  #elixir_ex{\n    prematch={Vars, {#{}, []}, Counter},\n    vars={Vars, false},\n    unused={#{}, Counter}\n  };\nenv_to_ex(#{versioned_vars := Vars}) ->\n  #elixir_ex{\n    vars={Vars, false},\n    unused={#{}, map_size(Vars)}\n  }.\n\n%% VAR HANDLING\n\nreset_read(#elixir_ex{vars={_, Write}} = S, #elixir_ex{vars={Read, _}}) ->\n  S#elixir_ex{vars={Read, Write}}.\n\nprepare_write(S, #{context := nil}) ->\n  prepare_write(S);\nprepare_write(S, _) ->\n  S.\n\nprepare_write(#elixir_ex{vars={Read, _}} = S) ->\n  S#elixir_ex{vars={Read, Read}}.\n\nclose_write(#elixir_ex{vars={_Read, Write}} = S, #elixir_ex{vars={_, false}}) ->\n  S#elixir_ex{vars={Write, false}};\nclose_write(#elixir_ex{vars={_Read, Write}} = S, #elixir_ex{vars={_, UpperWrite}}) ->\n  S#elixir_ex{vars={Write, merge_vars(UpperWrite, Write)}}.\n\nmerge_vars(V, V) ->\n  V;\nmerge_vars(V1, V2) ->\n  maps:fold(fun(K, M2, Acc) ->\n    case Acc of\n      #{K := M1} when M1 >= M2 -> Acc;\n      _ -> Acc#{K => M2}\n    end\n  end, V1, V2).\n\n%% UNUSED VARS\n\nreset_unused_vars(#elixir_ex{unused={_Unused, Version}} = S) ->\n  S#elixir_ex{unused={#{}, Version}}.\n\ncheck_unused_vars(#elixir_ex{unused={Unused, _Version}}, E) ->\n  [elixir_errors:file_warn(calculate_span(Meta, Name), E, ?MODULE, {unused_var, Name, Overridden}) ||\n    {{{Name, _Kind}, _Count}, {Meta, Overridden}} <- maps:to_list(Unused), is_unused_var(Name)],\n  E.\n\ncalculate_span(Meta, Name) ->\n  case lists:keyfind(column, 1, Meta) of\n    {column, Column} ->\n      [{span, {?line(Meta), Column + string:length(atom_to_binary(Name))}} | Meta];\n\n    _ ->\n      Meta\n  end.\n\nmerge_and_check_unused_vars(S, #elixir_ex{vars={Read, Write}, unused={Unused, _Version}}, E) ->\n  #elixir_ex{unused={ClauseUnused, Version}} = S,\n  NewUnused = merge_and_check_unused_vars(Read, Unused, ClauseUnused, E),\n  S#elixir_ex{unused={NewUnused, Version}, vars={Read, Write}}.\n\nmerge_and_check_unused_vars(Current, Unused, ClauseUnused, E) ->\n  maps:fold(fun\n    ({Var, Count} = Key, false, Acc) ->\n      case Current of\n        #{Var := CurrentCount} when Count =< CurrentCount ->\n          %% The parent knows it, so we have to propagate it was used up.\n          Acc#{Key => false};\n\n        #{} ->\n          Acc\n      end;\n\n    ({{Name, _Kind}, _Count}, {Meta, Overridden}, Acc) ->\n      case is_unused_var(Name) of\n        true ->\n          Warn = {unused_var, Name, Overridden},\n          elixir_errors:file_warn(Meta, E, ?MODULE, Warn);\n\n        false ->\n          ok\n      end,\n\n      Acc\n  end, Unused, ClauseUnused).\n\nis_unused_var(Name) ->\n  case atom_to_list(Name) of\n    \"_\" ++ Rest -> is_compiler_var(Rest);\n    _ -> true\n  end.\n\nis_compiler_var([$_]) -> true;\nis_compiler_var([Var | Rest]) when Var =:= $_; Var >= $A, Var =< $Z -> is_compiler_var(Rest);\nis_compiler_var(_) -> false.\n\nformat_error({unused_var, Name, Overridden}) ->\n  case atom_to_list(Name) of\n    \"_\" ++ _ ->\n      io_lib:format(\"unknown compiler variable \\\"~ts\\\" (expected one of __MODULE__, __ENV__, __DIR__, __CALLER__, __STACKTRACE__)\", [Name]);\n    \"&\" ++ _ ->\n      io_lib:format(\"variable \\\"~ts\\\" is unused (this might happen when using a capture argument as a pattern)\", [Name]);\n    _ when Overridden ->\n      io_lib:format(\"variable \\\"~ts\\\" is unused (there is a variable with the same name in the context, use the pin operator (^) to match on it or prefix this variable with underscore if it is not meant to be used)\", [Name]);\n    _ ->\n      io_lib:format(\"variable \\\"~ts\\\" is unused (if the variable is not meant to be used, prefix it with an underscore)\", [Name])\n  end.\n"
  },
  {
    "path": "lib/elixir/src/elixir_erl.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Compiler backend to Erlang.\n\n-module(elixir_erl).\n-export([elixir_to_erl/1, elixir_to_erl/2, definition_to_anonymous/5, compile/2, consolidate/4,\n         get_ann/1, debug_info/4, scope/2, checker_chunk/2, checker_version/0, format_error/1]).\n-include(\"elixir.hrl\").\n-define(typespecs, 'Elixir.Kernel.Typespec').\n\nchecker_version() ->\n  elixir_checker_v7.\n\n%% debug_info callback\n\ndebug_info(elixir_v1, _Module, none, _Opts) ->\n  {error, missing};\ndebug_info(elixir_v1, _Module, {elixir_v1, Map, _Specs}, _Opts) ->\n  {ok, Map};\ndebug_info(erlang_v1, _Module, {elixir_v1, Map, Specs}, _Opts) ->\n  {Prefix, Forms, _, _, _} = dynamic_form(Map, nil),\n  {ok, Prefix ++ Specs ++ Forms};\ndebug_info(core_v1, _Module, {elixir_v1, Map, Specs}, Opts) ->\n  {Prefix, Forms, _, _, _} = dynamic_form(Map, nil),\n  #{compile_opts := CompileOpts} = Map,\n  AllOpts = CompileOpts ++ Opts,\n\n  %% Do not rely on elixir_erl_compiler because we don't warn\n  %% warnings nor the other functionality provided there.\n  case elixir_erl_compiler:erl_to_core(Prefix ++ Specs ++ Forms, AllOpts) of\n    {ok, CoreForms, _} ->\n      try compile:noenv_forms(CoreForms, [no_spawn_compiler_process, from_core, to_core, return | AllOpts]) of\n        {ok, _, Core, _} -> {ok, Core};\n        _What -> {error, failed_conversion}\n      catch\n        error:_ -> {error, failed_conversion}\n      end;\n    _ ->\n      {error, failed_conversion}\n  end;\ndebug_info(_, _, _, _) ->\n  {error, unknown_format}.\n\n%% Builds Erlang AST annotation.\n\nget_ann(Opts) when is_list(Opts) ->\n  get_ann(Opts, false, 0, undefined).\n\nget_ann([{generated, true} | T], _, Line, Column) -> get_ann(T, true, Line, Column);\nget_ann([{line, Line} | T], Gen, _, Column) when is_integer(Line) -> get_ann(T, Gen, Line, Column);\nget_ann([{column, Column} | T], Gen, Line, _) when is_integer(Column) -> get_ann(T, Gen, Line, Column);\nget_ann([_ | T], Gen, Line, Column) -> get_ann(T, Gen, Line, Column);\nget_ann([], Gen, Line, undefined) -> erl_anno:set_generated(Gen, erl_anno:new(Line));\nget_ann([], Gen, Line, Column) -> erl_anno:set_generated(Gen, erl_anno:new({Line, Column})).\n\n%% Converts an Elixir definition to an anonymous function.\n\ndefinition_to_anonymous(Kind, Meta, Clauses, LocalHandler, ExternalHandler) ->\n  ErlClauses = [translate_clause(Kind, 0, Clause, true) || Clause <- Clauses],\n  Fun = {'fun', ?ann(Meta), {clauses, ErlClauses}},\n  {value, Result, _Binding} = erl_eval:expr(Fun, [], LocalHandler, ExternalHandler),\n  Result.\n\n%% Converts Elixir quoted literals to Erlang AST.\nelixir_to_erl(Tree) ->\n  elixir_to_erl(Tree, erl_anno:new(0)).\n\nelixir_to_erl(Tree, Ann) when is_tuple(Tree) ->\n  {tuple, Ann, [elixir_to_erl(X, Ann) || X <- tuple_to_list(Tree)]};\nelixir_to_erl([], Ann) ->\n  {nil, Ann};\nelixir_to_erl(<<>>, Ann) ->\n  {bin, Ann, []};\nelixir_to_erl(#{} = Map, Ann) ->\n  Assocs = [{map_field_assoc, Ann, elixir_to_erl(K, Ann), elixir_to_erl(V, Ann)}\n            || {K, V} <- lists:sort(maps:to_list(Map))],\n  {map, Ann, Assocs};\nelixir_to_erl(Tree, Ann) when is_list(Tree) ->\n  elixir_to_erl_cons(Tree, Ann);\nelixir_to_erl(Tree, Ann) when is_atom(Tree) ->\n  {atom, Ann, Tree};\nelixir_to_erl(Tree, Ann) when is_integer(Tree) ->\n  {integer, Ann, Tree};\nelixir_to_erl(Tree, Ann) when is_float(Tree), Tree == 0.0 ->\n   % 0.0 needs to be rewritten as the AST for +0.0 in matches\n   Op =\n    case <<Tree/float>> of\n        <<1:1,_:63>> -> '-';\n        _ -> '+'\n    end,\n  {op, Ann, Op, {float, Ann, 0.0}};\nelixir_to_erl(Tree, Ann) when is_float(Tree) ->\n  {float, Ann, Tree};\nelixir_to_erl(Tree, Ann) when is_binary(Tree) ->\n  %% Note that our binaries are UTF-8 encoded and we are converting\n  %% to a list using binary_to_list. The reason for this is that Erlang\n  %% considers a string in a binary to be encoded in latin1, so the bytes\n  %% are not changed in any fashion.\n  {bin, Ann, [{bin_element, Ann, {string, Ann, binary_to_list(Tree)}, default, default}]};\nelixir_to_erl(Tree, Ann) when is_bitstring(Tree) ->\n  Segments = [elixir_to_erl_bitstring_segment(X, Ann) || X <- bitstring_to_list(Tree)],\n  {bin, Ann, Segments};\nelixir_to_erl(Tree, Ann) when is_function(Tree) ->\n  case (erlang:fun_info(Tree, type) == {type, external}) andalso\n       (erlang:fun_info(Tree, env) == {env, []}) of\n    true ->\n      {module, Module} = erlang:fun_info(Tree, module),\n      {name, Name} = erlang:fun_info(Tree, name),\n      {arity, Arity} = erlang:fun_info(Tree, arity),\n      {'fun', Ann, {function, {atom, Ann, Module}, {atom, Ann, Name}, {integer, Ann, Arity}}};\n    false ->\n      error(badarg, [Tree, Ann])\n  end;\nelixir_to_erl(Tree, Ann) when is_pid(Tree); is_port(Tree); is_reference(Tree) ->\n  ?remote(Ann, erlang, binary_to_term, [elixir_to_erl(term_to_binary(Tree), Ann)]);\nelixir_to_erl(Tree, Ann) ->\n  error(badarg, [Tree, Ann]).\n\nelixir_to_erl_cons([H | T], Ann) -> {cons, Ann, elixir_to_erl(H, Ann), elixir_to_erl_cons(T, Ann)};\nelixir_to_erl_cons(T, Ann) -> elixir_to_erl(T, Ann).\n\nelixir_to_erl_bitstring_segment(Int, Ann) when is_integer(Int) ->\n  {bin_element, Ann, {integer, Ann, Int}, default, [integer]};\nelixir_to_erl_bitstring_segment(Rest, Ann) when is_bitstring(Rest) ->\n  Size = bit_size(Rest),\n  <<Int:Size>> = Rest,\n  {bin_element, Ann, {integer, Ann, Int}, {integer, Ann, Size}, [integer]}.\n\n%% Returns a scope for translation.\n\nscope(_Meta, ExpandCaptures) ->\n  #elixir_erl{expand_captures=ExpandCaptures}.\n\n%% Static compilation hook, used in protocol consolidation\n\nconsolidate(Map, Checker, TypeSpecs, DocsChunk) ->\n  {Prefix, Forms, _Def, _Defmacro, _Macros} = dynamic_form(Map, nil),\n  CheckerChunk = checker_chunk(Checker, chunk_opts(Map)),\n  load_form(Map, Prefix, Forms, TypeSpecs, DocsChunk ++ CheckerChunk).\n\n%% Used for updating type checking chunks in Elixir\n\nchecker_chunk(nil, _ChunkOpts) ->\n  [];\nchecker_chunk(Contents, ChunkOpts) ->\n  [{<<\"ExCk\">>, term_to_binary({checker_version(), Contents}, ChunkOpts)}].\n\n%% Dynamic compilation hook, used in regular compiler\n\ncompile(#{module := Module, anno := Anno} = BaseMap, Signatures) ->\n  Map =\n    case elixir_erl_compiler:env_compiler_options() of\n      [] -> BaseMap;\n      EnvOptions -> BaseMap#{compile_opts := ?key(BaseMap, compile_opts) ++ EnvOptions}\n    end,\n\n  {Set, Bag} = elixir_module:data_tables(Module),\n\n  TranslatedTypespecs =\n    case elixir_config:is_bootstrap() andalso\n          (code:ensure_loaded(?typespecs) /= {module, ?typespecs}) of\n      true -> {[], [], [], [], []};\n      false -> ?typespecs:translate_typespecs_for_module(Set, Bag)\n    end,\n\n  MD5 = ets:lookup_element(Set, exports_md5, 2),\n  {Prefix, Forms, Def, Defmacro, Macros} = dynamic_form(Map, MD5),\n  {Types, Callbacks, TypeSpecs} = typespecs_form(Map, TranslatedTypespecs, Macros),\n\n  ChunkOpts = chunk_opts(Map),\n  DocsChunk = docs_chunk(Map, Set, Module, Anno, Def, Defmacro, Types, Callbacks, ChunkOpts),\n  CheckerChunk = checker_chunk(Map, Def, Signatures, ChunkOpts),\n  load_form(Map, Prefix, Forms, TypeSpecs, DocsChunk ++ CheckerChunk).\n\nchunk_opts(Map) ->\n  case lists:member(deterministic, ?key(Map, compile_opts)) of\n    true -> [deterministic];\n    false -> []\n  end.\n\ndynamic_form(#{module := Module, relative_file := RelativeFile,\n               attributes := Attributes, definitions := Definitions, unreachable := Unreachable,\n               deprecated := Deprecated, compile_opts := Opts} = Map, MD5) ->\n  %% TODO: Match on anno directly in Elixir v1.22+\n  Line = case Map of\n    #{anno := AnnoValue} -> erl_anno:line(AnnoValue);\n    #{line := LineValue} -> LineValue\n  end,\n\n  {Def, Defmacro, Macros, Exports, Functions} =\n    split_definition(Definitions, Unreachable, Line, [], [], [], [], {[], []}),\n\n  FilteredOpts = proplists:delete(debug_info, proplists:delete(no_warn_undefined, Opts)),\n  Location = {elixir_utils:characters_to_list(RelativeFile), Line},\n\n  Prefix = [{attribute, Line, file, Location},\n            {attribute, Line, module, Module},\n            {attribute, Line, compile, [no_auto_import | FilteredOpts]}],\n\n  Struct = maps:get(struct, Map, nil),\n  Forms0 = functions_form(Line, Module, Def, Defmacro, Exports, Functions, Deprecated, Struct, MD5),\n  Forms1 = attributes_form(Line, Attributes, Forms0),\n  {Prefix, Forms1, Def, Defmacro, Macros}.\n\n% Definitions\n\nsplit_definition([{Tuple, Kind, Meta, Clauses} | T], Unreachable, Line,\n                 Def, Defmacro, Macros, Exports, Functions) ->\n  case lists:member(Tuple, Unreachable) of\n    false ->\n      split_definition(Tuple, Kind, Meta, Clauses, T, Unreachable, Line,\n                       Def, Defmacro, Macros, Exports, Functions);\n    true ->\n      split_definition(T, Unreachable, Line, Def, Defmacro, Macros, Exports, Functions)\n  end;\n\nsplit_definition([], _Unreachable, _Line, Def, Defmacro, Macros, Exports, {Head, Tail}) ->\n  {lists:sort(Def), lists:sort(Defmacro), Macros, Exports, Head ++ Tail}.\n\nsplit_definition(Tuple, def, Meta, Clauses, T, Unreachable, Line,\n                 Def, Defmacro, Macros, Exports, Functions) ->\n  {_, _, N, A, _} = Entry = translate_definition(def, Line, Meta, Tuple, Clauses),\n  split_definition(T, Unreachable, Line, [{Tuple, Meta} | Def], Defmacro, Macros, [{N, A} | Exports],\n                   add_definition(Meta, Entry, Functions));\n\nsplit_definition(Tuple, defp, Meta, Clauses, T, Unreachable, Line,\n                 Def, Defmacro, Macros, Exports, Functions) ->\n  Entry = translate_definition(defp, Line, Meta, Tuple, Clauses),\n  split_definition(T, Unreachable, Line, Def, Defmacro, Macros, Exports,\n                   add_definition(Meta, Entry, Functions));\n\nsplit_definition(Tuple, defmacro, Meta, Clauses, T, Unreachable, Line,\n                 Def, Defmacro, Macros, Exports, Functions) ->\n  {_, _, N, A, _} = Entry = translate_definition(defmacro, Line, Meta, Tuple, Clauses),\n  split_definition(T, Unreachable, Line, Def, [{Tuple, Meta} | Defmacro], [Tuple | Macros], [{N, A} | Exports],\n                   add_definition(Meta, Entry, Functions));\n\nsplit_definition(Tuple, defmacrop, Meta, Clauses, T, Unreachable, Line,\n                 Def, Defmacro, Macros, Exports, Functions) ->\n  Entry = translate_definition(defmacro, Line, Meta, Tuple, Clauses),\n  split_definition(T, Unreachable, Line, Def, Defmacro, [Tuple | Macros], Exports,\n                   add_definition(Meta, Entry, Functions)).\n\nadd_definition(Meta, Body, {Head, Tail}) ->\n  case lists:keyfind(file, 1, Meta) of\n    {file, {F, L}} ->\n      %% Erlang's epp attempts to perform offsetting when generated is set to true\n      %% and that causes cover to fail when processing modules. Therefore we never\n      %% pass the generated annotation forward for file attributes. The function\n      %% will still be marked as generated though if that's the case.\n      FileMeta = erl_anno:set_generated(false, ?ann(Meta)),\n      Attr = {attribute, FileMeta, file, {elixir_utils:characters_to_list(F), L}},\n      {Head, [Attr, Body | Tail]};\n    false ->\n      {[Body | Head], Tail}\n  end.\n\ntranslate_definition(Kind, Line, Meta, {Name, Arity}, Clauses) ->\n  ErlClauses = [translate_clause(Kind, Line, Clause, false) || Clause <- Clauses],\n\n  case is_macro(Kind) of\n    true -> {function, ?ann(Meta), elixir_utils:macro_name(Name), Arity + 1, ErlClauses};\n    false -> {function, ?ann(Meta), Name, Arity, ErlClauses}\n  end.\n\ntranslate_clause(Kind, Line, {Meta, Args, Guards, Body}, ExpandCaptures) ->\n  S = scope(Meta, ExpandCaptures),\n\n  %% If the line matches the module line, then it is most likely an\n  %% auto-generated function and we don't want to track its contents.\n  Ann =\n    case ?line(Meta) of\n      Line -> erl_anno:set_generated(true, erl_anno:new(0));\n      _ -> ?ann(Meta)\n    end,\n\n  {TClause, TS} =\n    elixir_erl_clauses:clause(Ann, fun elixir_erl_pass:translate_args/3, Args, Body, Guards, S),\n\n  case is_macro(Kind) of\n    true ->\n      FArgs = {var, Ann, '_@CALLER'},\n      MClause = setelement(3, TClause, [FArgs | element(3, TClause)]),\n\n      case TS#elixir_erl.caller of\n        true  ->\n          FBody = {'match', Ann,\n            {'var', Ann, '__CALLER__'},\n            ?remote(Ann, elixir_env, to_caller, [{var, Ann, '_@CALLER'}])\n          },\n          setelement(5, MClause, [FBody | element(5, TClause)]);\n        false ->\n          MClause\n      end;\n    false ->\n      TClause\n  end.\n\nis_macro(defmacro)  -> true;\nis_macro(defmacrop) -> true;\nis_macro(_)         -> false.\n\n% Functions\n\nfunctions_form(Line, Module, Def, Defmacro, Exports, Body, Deprecated, Struct, MD5) ->\n  {Spec, Info} = add_info_function(Line, Module, Def, Defmacro, Deprecated, Struct, MD5),\n  [{attribute, Line, export, lists:usort([{'__info__', 1} | Exports])}, Spec, Info | Body].\n\nadd_info_function(Line, Module, Def, Defmacro, Deprecated, Struct, MD5) ->\n  DefNA = [NA || {NA, _Meta} <- Def],\n  DefmacroNA = [NA || {NA, _Meta} <- Defmacro],\n\n  AllowedAttrs = [attributes, compile, functions, macros, md5, exports_md5, module, deprecated, struct],\n  AllowedArgs = lists:map(fun(Atom) -> {atom, Line, Atom} end, AllowedAttrs),\n\n  Spec =\n    {attribute, Line, spec, {{'__info__', 1},\n      [{type, Line, 'fun', [\n        {type, Line, product, [\n          {type, Line, union, AllowedArgs}\n        ]},\n        {type, Line, any, []}\n      ]}]\n    }},\n\n  Info =\n    {function, 0, '__info__', 1, [\n      get_module_info(Module),\n      functions_info(DefNA),\n      macros_info(DefmacroNA),\n      struct_info(Struct),\n      exports_md5_info(MD5, DefNA, DefmacroNA, Struct),\n      get_module_info(Module, attributes),\n      get_module_info(Module, compile),\n      get_module_info(Module, md5),\n      deprecated_info(Deprecated)\n    ]},\n\n  {Spec, Info}.\n\nget_module_info(Module) ->\n  {clause, 0, [{atom, 0, module}], [], [{atom, 0, Module}]}.\n\nexports_md5_info(MD5Attr, Def, Defmacro, Struct) ->\n  MD5 = if\n    is_binary(MD5Attr) -> MD5Attr;\n    MD5Attr =:= nil -> elixir_module:exports_md5(Def, Defmacro, Struct)\n  end,\n  {clause, 0, [{atom, 0, exports_md5}], [], [elixir_to_erl(MD5)]}.\n\nfunctions_info(Def) ->\n  {clause, 0, [{atom, 0, functions}], [], [elixir_to_erl(Def)]}.\n\nmacros_info(Defmacro) ->\n  {clause, 0, [{atom, 0, macros}], [], [elixir_to_erl(Defmacro)]}.\n\nstruct_info(nil) ->\n  {clause, 0, [{atom, 0, struct}], [], [{atom, 0, nil}]};\nstruct_info(Fields) ->\n  {clause, 0, [{atom, 0, struct}], [], [elixir_to_erl(Fields)]}.\n\nget_module_info(Module, Key) ->\n  Call = ?remote(0, erlang, get_module_info, [{atom, 0, Module}, {var, 0, 'Key'}]),\n  {clause, 0, [{match, 0, {var, 0, 'Key'}, {atom, 0, Key}}], [], [Call]}.\n\ndeprecated_info(Deprecated) ->\n  {clause, 0, [{atom, 0, deprecated}], [], [elixir_to_erl(Deprecated)]}.\n\n% Typespecs\n\ntypespecs_form(Map, TranslatedTypespecs, MacroNames) ->\n  {Types, Specs, Callbacks, MacroCallbacks, OptionalCallbacks} = TranslatedTypespecs,\n\n  AllCallbacks = Callbacks ++ MacroCallbacks,\n  MacroCallbackNames = [NameArity || {_, NameArity, _, _} <- MacroCallbacks],\n  validate_behaviour_info_and_attributes(Map, AllCallbacks),\n  validate_optional_callbacks(Map, AllCallbacks, OptionalCallbacks),\n\n  Forms0 = [],\n  Forms1 = types_form(Types, Forms0),\n  Forms2 = callspecs_form(spec, Specs, [], MacroNames, Forms1, Map),\n  Forms3 = callspecs_form(callback, AllCallbacks, OptionalCallbacks, MacroCallbackNames, Forms2, Map),\n\n  AllCallbacksWithoutSpecs = usort_callbacks([\n    {{Kind, Name, Arity}, Meta} || {Kind, {Name, Arity}, Meta, _Spec} <- AllCallbacks\n  ]),\n\n  {Types, AllCallbacksWithoutSpecs, Forms3}.\n\nusort_callbacks(Callbacks) ->\n  % Sort and deduplicate callbacks. For duplicated callbacks we take\n  % the one with earliest line.\n\n  LineComparator = fun\n    ({Callback1, Meta1}, {Callback1, Meta2}) -> ?line(Meta1) =< ?line(Meta2);\n    ({Callback1, _Meta1}, {Callback2, _Meta2}) -> Callback1 =< Callback2\n  end,\n\n  UniqFun = fun({Callback, _Meta}) -> Callback end,\n\n  lists:uniq(UniqFun, lists:sort(LineComparator, Callbacks)).\n\n%% Types\n\ntypes_form(Types, Forms) ->\n  Fun = fun\n    ({Kind, NameArity, Meta, Expr, true}, Acc) ->\n      Line = ?line(Meta),\n      [{attribute, Line, export_type, [NameArity]}, {attribute, Line, Kind, Expr} | Acc];\n    ({Kind, _NameArity, Meta, Expr, false}, Acc) ->\n      Line = ?line(Meta),\n      [{attribute, Line, Kind, Expr} | Acc]\n  end,\n\n  lists:foldl(Fun, Forms, Types).\n\n%% Specs and callbacks\n\nvalidate_behaviour_info_and_attributes(#{definitions := Defs} = Map, AllCallbacks) ->\n  case {lists:keyfind({behaviour_info, 1}, 1, Defs), AllCallbacks} of\n    {false, _} ->\n      ok;\n    {_, [{Kind, {Name, Arity}, _, _} | _]} when Kind == callback; Kind == macrocallback ->\n      file_error(Map, {callbacks_but_also_behaviour_info, {Kind, Name, Arity}});\n    {_, _} ->\n      ok\n  end.\n\nvalidate_optional_callbacks(Map, AllCallbacks, Optional) ->\n  lists:foldl(fun(Callback, Acc) ->\n    case Callback of\n      {Name, Arity} when is_atom(Name) and is_integer(Arity) -> ok;\n      _ -> file_error(Map, {ill_defined_optional_callback, Callback})\n    end,\n\n    case lists:keyfind(Callback, 2, AllCallbacks) of\n      false -> file_error(Map, {unknown_callback, Callback});\n      _ -> ok\n    end,\n\n    case Acc of\n      #{Callback := _} -> file_error(Map, {duplicate_optional_callback, Callback});\n      _ -> ok\n    end,\n\n    maps:put(Callback, true, Acc)\n  end, #{}, Optional).\n\ncallspecs_form(_Kind, [], _Optional, _Macros, Forms, _ModuleMap) ->\n  Forms;\ncallspecs_form(Kind, Entries, Optional, Macros, Forms, ModuleMap) ->\n  #{unreachable := Unreachable} = ModuleMap,\n\n  {SpecsMap, Signatures} =\n    lists:foldl(fun({_, NameArity, Meta, Spec}, {Acc, NA}) ->\n      Line = ?line(Meta),\n\n      case Kind of\n        spec -> validate_spec_for_existing_function(ModuleMap, NameArity, Line);\n        _ -> ok\n      end,\n\n      case lists:member(NameArity, Unreachable) of\n        false ->\n          case Acc of\n            #{NameArity := List} -> {Acc#{NameArity := [{Spec, Line} | List]}, NA};\n            #{} -> {Acc#{NameArity => [{Spec, Line}]}, [NameArity | NA]}\n          end;\n        true ->\n          {Acc, NA}\n      end\n    end, {#{}, []}, Entries),\n\n  lists:foldl(fun(NameArity, Acc) ->\n    #{NameArity := ExprsLines} = SpecsMap,\n    {Exprs, Lines} = lists:unzip(ExprsLines),\n    Line = lists:min(Lines),\n\n    {Key, Value} =\n      case lists:member(NameArity, Macros) of\n        true ->\n          {Name, Arity} = NameArity,\n          {{elixir_utils:macro_name(Name), Arity + 1},\n           lists:map(fun spec_for_macro/1, Exprs)};\n        false ->\n          {NameArity, Exprs}\n      end,\n\n    case lists:member(NameArity, Optional) of\n      true ->\n        [{attribute, Line, Kind, {Key, lists:reverse(Value)}},\n         {attribute, Line, optional_callbacks, [Key]} | Acc];\n      false ->\n        [{attribute, Line, Kind, {Key, lists:reverse(Value)}} | Acc]\n    end\n  end, Forms, lists:usort(Signatures)).\n\nspec_for_macro({type, Line, 'bounded_fun', [H | T]}) ->\n  {type, Line, 'bounded_fun', [spec_for_macro(H) | T]};\nspec_for_macro({type, Line, 'fun', [{type, _, product, Args} | T]}) ->\n  {type, Line, 'fun', [{type, Line, product, [{type, Line, term, []} | Args]} | T]};\nspec_for_macro(Else) ->\n  Else.\n\nvalidate_spec_for_existing_function(ModuleMap, NameAndArity, Line) ->\n  #{definitions := Defs, file := File} = ModuleMap,\n\n  case lists:keymember(NameAndArity, 1, Defs) of\n    true -> ok;\n    false -> file_error(#{anno => erl_anno:new(Line), file => File}, {spec_for_undefined_function, NameAndArity})\n  end.\n\n% Attributes\n\nattributes_form(Line, Attributes, Forms) ->\n  Fun = fun({Key, Value}, Acc) -> [{attribute, Line, Key, Value} | Acc] end,\n  lists:foldr(Fun, Forms, Attributes).\n\n% Loading forms\n\nload_form(#{file := File, compile_opts := Opts} = Map, Prefix, Forms, Specs, Chunks) ->\n  CompileOpts = extra_chunks_opts(Chunks, debug_opts(Map, Specs, Opts)),\n  {_, Binary} = elixir_erl_compiler:noenv_forms(Prefix ++ Specs ++ Forms, File, CompileOpts),\n  Binary.\n\ndebug_opts(Map, Specs, Opts) ->\n  case take_debug_opts(Opts) of\n    {true, Rest} -> [{debug_info, {?MODULE, {elixir_v1, Map, Specs}}} | Rest];\n    {false, Rest} -> [{debug_info, {?MODULE, none}} | Rest]\n  end.\n\ntake_debug_opts(Opts) ->\n  case proplists:get_value(debug_info, Opts) of\n    true -> {true, proplists:delete(debug_info, Opts)};\n    false -> {false, proplists:delete(debug_info, Opts)};\n    undefined -> {elixir_config:get(debug_info), Opts}\n  end.\n\nextra_chunks_opts([], Opts) -> Opts;\nextra_chunks_opts(Chunks, Opts) -> [{extra_chunks, Chunks} | Opts].\n\ndocs_chunk(Map, Set, Module, Anno, Def, Defmacro, Types, Callbacks, ChunkOpts) ->\n  #{file := File, attributes := Attributes} = Map,\n\n  case elixir_config:get(docs) of\n    true ->\n      {ModuleDocLine, ModuleDoc} = get_moduledoc(erl_anno:line(Anno), Set),\n      ModuleDocMeta = get_moduledoc_meta(Set),\n      FunctionDocs = get_docs(Set, Module, Def, function),\n      MacroDocs = get_docs(Set, Module, Defmacro, macro),\n      CallbackDocs = get_callback_docs(Set, Callbacks),\n      TypeDocs = get_type_docs(Set, Types),\n\n      ModuleMeta = ModuleDocMeta#{\n        source_path => elixir_utils:characters_to_list(File),\n        source_annos => [Anno],\n        behaviours => [Mod || {behaviour, Mod} <- Attributes]\n      },\n\n      DocsChunkData = term_to_binary({docs_v1,\n        erl_anno:new(ModuleDocLine),\n        elixir,\n        <<\"text/markdown\">>,\n        ModuleDoc,\n        ModuleMeta,\n        FunctionDocs ++ MacroDocs ++ CallbackDocs ++ TypeDocs\n      }, [compressed | ChunkOpts]),\n\n      [{<<\"Docs\">>, DocsChunkData}];\n\n    false ->\n      []\n  end.\n\ndoc_value(Doc, Name) ->\n  case Doc of\n    false ->\n      hidden;\n    nil ->\n      case erlang:atom_to_list(Name) of\n        [$_ | _] -> hidden;\n        _ -> none\n      end;\n    Doc ->\n      #{<<\"en\">> => Doc}\n  end.\n\nget_moduledoc(Line, Set) ->\n  case ets:lookup_element(Set, moduledoc, 2) of\n    nil -> {Line, none};\n    {DocLine, false} -> {DocLine, hidden};\n    {DocLine, nil} -> {DocLine, none};\n    {DocLine, Doc} -> {DocLine, #{<<\"en\">> => Doc}}\n  end.\n\nget_moduledoc_meta(Set) ->\n  case ets:lookup(Set, {moduledoc, meta}) of\n    [] -> #{};\n    [{{moduledoc, meta}, Map}] when is_map(Map) -> Map\n  end.\n\nget_docs(Set, Module, Definitions, Kind) ->\n  [{Key,\n    erl_anno:new(Line),\n    [signature_to_binary(Module, Name, Signature)],\n    doc_value(Doc, Name),\n    Meta#{source_annos => [?ann(DefinitionMeta)]}\n   } || {{Name, Arity}, DefinitionMeta} <- Definitions,\n        {Key, _Ctx, Line, Signature, Doc, Meta} <- ets:lookup(Set, {Kind, Name, Arity})].\n\nget_callback_docs(Set, Callbacks) ->\n  [{Key,\n    erl_anno:new(Line),\n    [],\n    doc_value(Doc, Name),\n    Meta#{source_annos => [?ann(DefinitionMeta)]}\n   } || {{Kind, Name, Arity}, DefinitionMeta} <- Callbacks, {Key, Line, Doc, Meta} <- ets:lookup(Set, {Kind, Name, Arity})].\n\nget_type_docs(Set, Types) ->\n  [{Key,\n    erl_anno:new(Line),\n    [],\n    doc_value(Doc, Name),\n    Meta#{source_annos => [?ann(DefinitionMeta)]}\n   } || {_Kind, {Name, Arity}, DefinitionMeta, _, true} <- Types,\n        {Key, Line, Doc, Meta} <- ets:lookup(Set, {type, Name, Arity})].\n\nsignature_to_binary(_Module, Name, _Signature) when Name == '__aliases__'; Name == '__block__' ->\n  <<(atom_to_binary(Name))/binary, \"(args)\">>;\n\nsignature_to_binary(_Module, fn, _Signature) ->\n  <<\"fn(clauses)\">>;\n\nsignature_to_binary(_Module, Name, _Signature)\n    when Name == '__CALLER__'; Name == '__DIR__'; Name == '__ENV__';\n         Name == '__MODULE__'; Name == '__STACKTRACE__'; Name == '%{}' ->\n  atom_to_binary(Name);\n\nsignature_to_binary(_Module, '%', _) ->\n  <<\"%struct{}\">>;\n\nsignature_to_binary(Module, '__struct__', []) ->\n  <<\"%\", ('Elixir.Kernel':inspect(Module))/binary, \"{}\">>;\n\nsignature_to_binary(_, Name, Signature) ->\n  Quoted = {Name, [{closing, []}], Signature},\n  Doc = 'Elixir.Inspect.Algebra':format('Elixir.Code':quoted_to_algebra(Quoted), infinity),\n  'Elixir.IO':iodata_to_binary(Doc).\n\nchecker_chunk(Map, Def, Signatures, ChunkOpts) ->\n  #{deprecated := Deprecated, defines_behaviour := DefinesBehaviour, attributes := Attributes} = Map,\n  DeprecatedMap = maps:from_list(Deprecated),\n\n  Exports =\n    [begin\n      Signature = maps:get(FA, Signatures, none),\n      Info = case DeprecatedMap of\n        #{FA := Reason} -> #{deprecated => Reason, sig => Signature};\n        #{} -> #{sig => Signature}\n      end,\n      {FA, Info}\n    end || {FA, _Meta} <- prepend_behaviour_info(DefinesBehaviour, Def)],\n\n  Contents = #{\n    exports => Exports,\n    mode => case lists:keymember('__protocol__', 1, Attributes) of\n      true -> protocol;\n      false -> elixir\n    end\n  },\n\n  checker_chunk(Contents, ChunkOpts).\n\nprepend_behaviour_info(true, Def) -> [{{behaviour_info, 1}, []} | Def];\nprepend_behaviour_info(false, Def) -> Def.\n\n%% Errors\n\nfile_error(#{anno := Anno, file := File}, Error) ->\n  Line = erl_anno:line(Anno),\n  elixir_errors:file_error([{line, Line}], File, ?MODULE, Error).\n\nformat_error({ill_defined_optional_callback, Callback}) ->\n  io_lib:format(\"invalid optional callback ~ts. @optional_callbacks expects a \"\n                \"keyword list of callback names and arities\", ['Elixir.Kernel':inspect(Callback)]);\nformat_error({unknown_callback, {Name, Arity}}) ->\n  io_lib:format(\"unknown callback ~ts/~B given as optional callback\", [Name, Arity]);\nformat_error({duplicate_optional_callback, {Name, Arity}}) ->\n  io_lib:format(\"~ts/~B has been specified as optional callback more than once\", [Name, Arity]);\nformat_error({callbacks_but_also_behaviour_info, {Type, Fun, Arity}}) ->\n  io_lib:format(\"cannot define @~ts attribute for ~ts/~B when behaviour_info/1 is defined\",\n                [Type, Fun, Arity]);\nformat_error({spec_for_undefined_function, {Name, Arity}}) ->\n  io_lib:format(\"spec for undefined function ~ts/~B\", [Name, Arity]).\n"
  },
  {
    "path": "lib/elixir/src/elixir_erl_clauses.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Handle code related to args, guard and -> matching for case,\n%% fn, receive and friends. try is handled in elixir_erl_try.\n-module(elixir_erl_clauses).\n-export([match/4, clause/6, clauses/2, guards/4, get_clauses/3]).\n-include(\"elixir.hrl\").\n\n%% Get clauses under the given key.\n\nget_clauses(Key, Keyword, As) ->\n  case lists:keyfind(Key, 1, Keyword) of\n    {Key, Clauses} when is_list(Clauses) ->\n      [{As, Meta, Left, Right} || {'->', Meta, [Left, Right]} <- Clauses];\n    _ ->\n      []\n  end.\n\n%% Translate matches\n\nmatch(Ann, Fun, Match, #elixir_erl{context=Context} = S) when Context =/= match ->\n  {Result, NewS} = Fun(Match, Ann, S#elixir_erl{context=match}),\n  {Result, NewS#elixir_erl{context=Context}};\nmatch(Ann, Fun, Match, S) ->\n  Fun(Match, Ann, S).\n\n%% Translate clauses with args, guards and expressions\n\nclause(Ann, Fun, Match, Expr, Guards, S) ->\n  {TMatch, SA} = match(Ann, Fun, Match, S),\n  SG = SA#elixir_erl{extra_guards=[]},\n  TGuards = guards(Ann, Guards, SA#elixir_erl.extra_guards, SG),\n  {TExpr, SE} = elixir_erl_pass:translate(Expr, Ann, SG),\n  {{clause, Ann, TMatch, TGuards, unblock(TExpr)}, SE}.\n\n% Translate/Extract guards from the given expression.\n\nguards(Ann, Guards, Extra, S) ->\n  SG = S#elixir_erl{context=guard},\n  case Guards of\n    [] -> case Extra of [] -> []; _ -> [Extra] end;\n    _  -> [translate_guard(Guard, Ann, SG, Extra) || Guard <- Guards]\n  end.\n\ntranslate_guard(Guard, Ann, S, Extra) ->\n  [element(1, elixir_erl_pass:translate(Guard, Ann, S)) | Extra].\n\n% Function for translating macros with match style like case and receive.\n\nclauses([], S) ->\n  {[], S};\n\nclauses(Clauses, S) ->\n  lists:mapfoldl(fun each_clause/2, S, Clauses).\n\neach_clause({match, Meta, [Condition], Expr}, S) ->\n  {Arg, Guards} = elixir_utils:extract_guards(Condition),\n  clause(?ann(Meta), fun elixir_erl_pass:translate_args/3, [Arg], Expr, Guards, S);\n\neach_clause({expr, Meta, [Condition], Expr}, S) ->\n  Ann = ?ann(Meta),\n  {TCondition, SC} = elixir_erl_pass:translate(Condition, Ann, S),\n  {TExpr, SB} = elixir_erl_pass:translate(Expr, Ann, SC),\n  {{clause, Ann, [TCondition], [], unblock(TExpr)}, SB}.\n\nunblock({'block', _, Exprs}) -> Exprs;\nunblock(Exprs) -> [Exprs].\n"
  },
  {
    "path": "lib/elixir/src/elixir_erl_compiler.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_erl_compiler).\n-export([spawn/1, noenv_forms/3, erl_to_core/2, env_compiler_options/0]).\n-include(\"elixir.hrl\").\n\nspawn(Fun) ->\n  CompilerInfo = get(elixir_compiler_info),\n  {error_handler, ErrorHandler} = erlang:process_info(self(), error_handler),\n\n  CodeDiagnostics =\n    case get(elixir_code_diagnostics) of\n      undefined -> undefined;\n      {_Tail, Log} -> {[], Log}\n    end,\n\n  {_, Ref} =\n    spawn_monitor(fun() ->\n      erlang:process_flag(error_handler, ErrorHandler),\n      put(elixir_compiler_info, CompilerInfo),\n      put(elixir_code_diagnostics, CodeDiagnostics),\n\n      try Fun() of\n        Result -> exit({ok, Result, get(elixir_code_diagnostics)})\n      catch\n        Kind:Reason:Stack ->\n          exit({Kind, Reason, Stack, get(elixir_code_diagnostics)})\n      end\n    end),\n\n  receive\n    {'DOWN', Ref, process, _, {ok, Result, Diagnostics}} ->\n      copy_diagnostics(Diagnostics),\n      Result;\n    {'DOWN', Ref, process, _, {Kind, Reason, Stack, Diagnostics}} ->\n      copy_diagnostics(Diagnostics),\n      erlang:raise(Kind, Reason, Stack)\n  end.\n\ncopy_diagnostics(undefined) ->\n  ok;\ncopy_diagnostics({Head, _}) ->\n  case get(elixir_code_diagnostics) of\n    undefined -> ok;\n    {Tail, Log} -> put(elixir_code_diagnostics, {Head ++ Tail, Log})\n  end.\n\nenv_compiler_options() ->\n  case persistent_term:get(?MODULE, undefined) of\n    undefined ->\n      Options = compile:env_compiler_options() -- [warnings_as_errors],\n      persistent_term:put(?MODULE, Options),\n      Options;\n\n    Options ->\n      Options\n  end.\n\nerl_to_core(Forms, Opts) ->\n  %% TODO: Remove parse transform handling on Elixir v2.0\n  case [M || {parse_transform, M} <- Opts] of\n    [] ->\n      v3_core:module(Forms, Opts);\n    _ ->\n      case compile:noenv_forms(Forms, [no_spawn_compiler_process, to_core0, return, no_auto_import | Opts]) of\n        {ok, _Module, Core, Warnings} -> {ok, Core, Warnings};\n        {error, Errors, Warnings} -> {error, Errors, Warnings}\n      end\n  end.\n\nnoenv_forms(Forms, File, Opts) when is_list(Forms), is_list(Opts), is_binary(File) ->\n  Source = elixir_utils:characters_to_list(File),\n\n  case erl_to_core(Forms, Opts) of\n    {ok, CoreForms, CoreWarnings} ->\n      format_warnings(Opts, CoreWarnings),\n      CompileOpts = [no_spawn_compiler_process, from_core, no_core_prepare,\n                     no_auto_import, return, {source, Source} | Opts],\n\n      case compile:noenv_forms(CoreForms, CompileOpts) of\n        {ok, Module, Binary, Warnings} when is_binary(Binary) ->\n          format_warnings(Opts, Warnings),\n          {Module, Binary};\n\n        {ok, Module, _, _} ->\n          incompatible_options(\"could not compile module ~ts\", [elixir_aliases:inspect(Module)], File);\n\n        {ok, Module, _} ->\n          incompatible_options(\"could not compile module ~ts\", [elixir_aliases:inspect(Module)], File);\n\n        {error, Errors, Warnings} ->\n          format_warnings(Opts, Warnings),\n          format_errors(Errors);\n\n        _ ->\n          incompatible_options(\"could not compile module\", [], File)\n      end;\n\n    {error, CoreErrors, CoreWarnings} ->\n      format_warnings(Opts, CoreWarnings),\n      format_errors(CoreErrors)\n  end.\n\nincompatible_options(Prefix, Args, File) ->\n  Message = io_lib:format(\n    Prefix ++ \". We expected the compiler to return a .beam binary but \"\n    \"got something else. This usually happens because ERL_COMPILER_OPTIONS or @compile \"\n    \"was set to change the compilation outcome in a way that is incompatible with Elixir\",\n    Args\n  ),\n\n  elixir_errors:compile_error([], File, Message).\n\nformat_errors([]) ->\n  exit({nocompile, \"compilation failed but no error was raised\"});\nformat_errors(Errors) ->\n  lists:foreach(fun\n    ({File, Each}) when is_list(File) ->\n      BinFile = elixir_utils:characters_to_binary(File),\n      lists:foreach(fun(Error) -> handle_file_error(BinFile, Error) end, Each);\n    ({Mod, Each}) when is_atom(Mod) ->\n      lists:foreach(fun(Error) -> handle_file_error(elixir_aliases:inspect(Mod), Error) end, Each)\n  end, Errors).\n\nformat_warnings(Opts, Warnings) ->\n  NoWarnNoMatch = proplists:get_value(nowarn_nomatch, Opts, false),\n  lists:foreach(fun ({File, Each}) ->\n    BinFile = elixir_utils:characters_to_binary(File),\n    lists:foreach(fun(Warning) ->\n      handle_file_warning(NoWarnNoMatch, BinFile, Warning)\n    end, Each)\n  end, Warnings).\n\n%% Handle warnings from Erlang land\n\n%% Those we implement ourselves\nhandle_file_warning(_, _File, {_Line, v3_core, {map_key_repeated, _}}) -> ok;\nhandle_file_warning(_, _File, {_Line, sys_core_fold, {ignored, useless_building}}) -> ok;\n\n%% We skip all of no_match related to no_clause, clause_type, guard, shadow.\n%% Those have too little information and they overlap with the type system.\n%% We keep the remaining ones because the Erlang compiler performs analyses\n%% on literals (including numbers), which the type system does not do.\nhandle_file_warning(_, _File, {_Line, sys_core_fold, {nomatch, Reason}}) when is_atom(Reason) -> ok;\n\n%% Ignore all linting errors (only come up on parse transforms)\nhandle_file_warning(_, _File, {_Line, erl_lint, _}) -> ok;\n\nhandle_file_warning(_, File, {Line, Module, Desc}) ->\n  Message = custom_format(Module, Desc),\n  elixir_errors:erl_warn(Line, File, Message).\n\n%% Handle warnings\n\nhandle_file_error(File, {beam_validator, Desc}) ->\n  elixir_errors:compile_error([{line, 0}], File, beam_validator:format_error(Desc));\nhandle_file_error(File, {Line, Module, Desc}) ->\n  Message = custom_format(Module, Desc),\n  elixir_errors:compile_error([{line, Line}], File, Message).\n\n%% Mention the capture operator in make_fun\ncustom_format(sys_core_fold, {ignored, {no_effect, {erlang, make_fun, 3}}}) ->\n  \"the result of the capture operator & (Function.capture/3) is never used\";\n\n%% Make no_effect clauses pretty\ncustom_format(sys_core_fold, {ignored, {no_effect, {erlang, F, A}}}) ->\n  {Fmt, Args} = case erl_internal:comp_op(F, A) of\n    true -> {\"use of operator ~ts has no effect\", [elixir_utils:erlang_comparison_op_to_elixir(F)]};\n    false ->\n      case erl_internal:bif(F, A) of\n        false -> {\"the call to :erlang.~ts/~B has no effect\", [F, A]};\n        true ->  {\"the call to ~ts/~B has no effect\", [F, A]}\n      end\n  end,\n  io_lib:format(Fmt, Args);\n\ncustom_format(sys_core_fold, {nomatch, {shadow, Line, {ErlName, ErlArity}}}) ->\n  {Name, Arity} = elixir_utils:erl_fa_to_elixir_fa(ErlName, ErlArity),\n\n  io_lib:format(\n    \"this clause for ~ts/~B cannot match because a previous clause at line ~B always matches\",\n    [Name, Arity, Line]\n  );\n\ncustom_format([], Desc) ->\n  io_lib:format(\"~p\", [Desc]);\n\ncustom_format(Module, Desc) ->\n  Module:format_error(Desc).\n"
  },
  {
    "path": "lib/elixir/src/elixir_erl_for.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_erl_for).\n-export([translate/3]).\n-include(\"elixir.hrl\").\n\n-define(empty_map_set_pattern, {map, _, [\n    {map_field_assoc, _, {atom, _, '__struct__'}, {atom, _, 'Elixir.MapSet'}},\n    {map_field_assoc, _, {atom, _, map}, {map, _, []}}\n  ]}).\n\ntranslate(Meta, Args, S) ->\n  {Cases, [{do, Expr} | Opts]} = elixir_utils:split_last(Args),\n\n  case lists:keyfind(reduce, 1, Opts) of\n    {reduce, Reduce} -> translate_reduce(Meta, Cases, Expr, Reduce, S);\n    false -> translate_into(Meta, Cases, Expr, Opts, S)\n  end.\n\ntranslate_reduce(Meta, Cases, Expr, Reduce, S) ->\n  Ann = ?ann(Meta),\n  {TReduce, SR} = elixir_erl_pass:translate(Reduce, Ann, S),\n  {TCases, SC} = translate_gen(Meta, Cases, [], SR),\n  CaseExpr = {'case', Meta, [ok, [{do, Expr}]]},\n  {TExpr, SE} = elixir_erl_pass:translate(CaseExpr, Ann, SC),\n\n  InnerFun = fun\n    ({'case', CaseAnn, _, CaseBlock}, InnerAcc) -> {'case', CaseAnn, InnerAcc, CaseBlock}\n  end,\n\n  build_reduce(Ann, TCases, InnerFun, TExpr, TReduce, false, SE).\n\ntranslate_into(Meta, Cases, Expr, Opts, S) ->\n  Ann = ?ann(Meta),\n\n  {TInto, SI} =\n    case lists:keyfind(into, 1, Opts) of\n      {into, Into} -> elixir_erl_pass:translate(Into, Ann, S);\n      false -> {false, S}\n    end,\n\n  TUniq = lists:keyfind(uniq, 1, Opts) == {uniq, true},\n\n  {TCases, SC} = translate_gen(Meta, Cases, [], SI),\n  {TExpr, SE}  = elixir_erl_pass:translate(wrap_expr_if_unused(Expr, TInto), Ann, SC),\n\n  case inline_or_into(TInto) of\n    inline -> build_inline(Ann, TCases, TExpr, TInto, TUniq, SE);\n    into -> build_into(Ann, TCases, TExpr, TInto, TUniq, SE)\n  end.\n\n%% In case we have no return, we wrap the expression\n%% in a block that returns nil.\nwrap_expr_if_unused(Expr, false) -> {'__block__', [], [Expr, nil]};\nwrap_expr_if_unused(Expr, _)  -> Expr.\n\ntranslate_gen(ForMeta, [{'<-', Meta, [Left, Right]} | T], Acc, S) ->\n  {TLeft, TRight, TFilters, TT, TS} = translate_gen(Meta, Left, Right, T, S),\n  TAcc = [{enum, Meta, TLeft, TRight, TFilters} | Acc],\n  translate_gen(ForMeta, TT, TAcc, TS);\ntranslate_gen(ForMeta, [{'<<>>', _, [{'<-', Meta, [Left, Right]}]} | T], Acc, S) ->\n  {TLeft, TRight, TFilters, TT, TS} = translate_gen(Meta, Left, Right, T, S),\n  TAcc = [{bin, Meta, TLeft, TRight, TFilters} | Acc],\n  translate_gen(ForMeta, TT, TAcc, TS);\ntranslate_gen(_ForMeta, [], Acc, S) ->\n  {lists:reverse(Acc), S}.\n\ntranslate_gen(Meta, Left, Right, T, S) ->\n  Ann = ?ann(Meta),\n  {TRight, SR} = elixir_erl_pass:translate(Right, Ann, S),\n  {LeftArgs, LeftGuards} = elixir_utils:extract_guards(Left),\n  {TLeft, SL} = elixir_erl_clauses:match(Ann, fun elixir_erl_pass:translate/3, LeftArgs,\n                                         SR#elixir_erl{extra=pin_guard}),\n\n  TLeftGuards = elixir_erl_clauses:guards(Ann, LeftGuards, [], SL),\n  ExtraGuards = [{nil, X} || X <- SL#elixir_erl.extra_guards],\n  {Filters, TT} = collect_filters(T, []),\n\n  {TFilters, TS} =\n    lists:mapfoldr(\n      fun(F, SF) -> translate_filter(F, Ann, SF) end,\n      SL#elixir_erl{extra=S#elixir_erl.extra, extra_guards=[]},\n      Filters\n    ),\n\n  %% The list of guards is kept in reverse order\n  Guards = TFilters ++ translate_guards(TLeftGuards) ++ ExtraGuards,\n  {TLeft, TRight, Guards, TT, TS}.\n\ntranslate_guards([]) ->\n  [];\ntranslate_guards([[Guards]]) ->\n  [{nil, Guards}];\ntranslate_guards([[Left], [Right] | Rest]) ->\n  translate_guards([[{op, element(2, Left), 'orelse', Left, Right}] | Rest]).\n\ntranslate_filter(Filter, Ann, S) ->\n  {TFilter, TS} = elixir_erl_pass:translate(Filter, Ann, S),\n  case elixir_utils:returns_boolean(Filter) of\n    true ->\n      {{nil, TFilter}, TS};\n    false ->\n      {Name, VS} = elixir_erl_var:build('_', TS),\n      {{{var, 0, Name}, TFilter}, VS}\n  end.\n\ncollect_filters([{'<-', _, [_, _]} | _] = T, Acc) ->\n  {Acc, T};\ncollect_filters([{'<<>>', _, [{'<-', _, [_, _]}]} | _] = T, Acc) ->\n  {Acc, T};\ncollect_filters([H | T], Acc) ->\n  collect_filters(T, [H | Acc]);\ncollect_filters([], Acc) ->\n  {Acc, []}.\n\nbuild_inline(Ann, Clauses, Expr, Into, Uniq, S) ->\n  case not Uniq and lists:all(fun(Clause) -> element(1, Clause) == bin end, Clauses) of\n    true  -> {build_comprehension(Ann, Clauses, Expr, Into), S};\n    false -> build_inline_each(Ann, Clauses, Expr, Into, Uniq, S)\n  end.\n\nbuild_inline_each(Ann, Clauses, Expr, false, Uniq, S) ->\n  InnerFun = fun(InnerExpr, _InnerAcc) -> InnerExpr end,\n  build_reduce(Ann, Clauses, InnerFun, Expr, {nil, Ann}, Uniq, S);\nbuild_inline_each(Ann, [{enum, _, Left = {var, _, _}, Right, [] = _Filters}], Expr, {nil, _} = _Into, false, S) ->\n  Clauses = [{clause, Ann, [Left], [], [Expr]}],\n  Args = [Right, {'fun', Ann, {clauses, Clauses}}],\n  {?remote(Ann, 'Elixir.Enum', map, Args), S};\nbuild_inline_each(Ann, [{enum, _, Left = {var, _, _}, Right, [] = _Filters}], Expr, {map, _, []} = _Into, false, S) ->\n  Clauses = [{clause, Ann, [Left], [], [Expr]}],\n  Args = [Right, {'fun', Ann, {clauses, Clauses}}],\n  List = ?remote(Ann, 'Elixir.Enum', map, Args),\n  {?remote(Ann, maps, from_list, [List]), S};\nbuild_inline_each(Ann, Clauses, Expr, {nil, _} = Into, Uniq, S) ->\n  InnerFun = fun(InnerExpr, InnerAcc) -> {cons, Ann, InnerExpr, InnerAcc} end,\n  {ReduceExpr, SR} = build_reduce(Ann, Clauses, InnerFun, Expr, Into, Uniq, S),\n  {?remote(Ann, lists, reverse, [ReduceExpr]), SR};\nbuild_inline_each(Ann, Clauses, Expr, {bin, _, []}, Uniq, S) ->\n  {InnerValue, SV} = build_var(Ann, S),\n  Generated = erl_anno:set_generated(true, Ann),\n\n  InnerFun = fun(InnerExpr, InnerAcc) ->\n    {'case', Ann, InnerExpr, [\n      {clause, Generated,\n       [InnerValue],\n       [[?remote(Ann, erlang, is_bitstring, [InnerValue]),\n         ?remote(Ann, erlang, is_list, [InnerAcc])]],\n       [{cons, Generated, InnerAcc, InnerValue}]},\n      {clause, Generated,\n       [InnerValue],\n       [],\n       [?remote(Ann, erlang, error, [{tuple, Ann, [{atom, Ann, badarg}, InnerValue]}])]}\n    ]}\n  end,\n\n  {ReduceExpr, SR} = build_reduce(Ann, Clauses, InnerFun, Expr, {nil, Ann}, Uniq, SV),\n  {?remote(Ann, erlang, list_to_bitstring, [ReduceExpr]), SR}.\n\nbuild_into(Ann, Clauses, Expr, {map, _, []}, Uniq, S) ->\n  {ReduceExpr, SR} = build_inline_each(Ann, Clauses, Expr, {nil, Ann}, Uniq, S),\n  {?remote(Ann, maps, from_list, [ReduceExpr]), SR};\nbuild_into(Ann, Clauses, Expr, ?empty_map_set_pattern = _Into, Uniq, S) ->\n  InnerFun = fun(InnerExpr, InnerAcc) -> {cons, Ann, InnerExpr, InnerAcc} end,\n  {ReduceExpr, SR} = build_reduce(Ann, Clauses, InnerFun, Expr, {nil, Ann}, Uniq, S),\n  {?remote(Ann, 'Elixir.MapSet', new, [ReduceExpr]), SR};\nbuild_into(Ann, Clauses, Expr, Into, Uniq, S) ->\n  {Fun, SF}    = build_var(Ann, S),\n  {Acc, SA}    = build_var(Ann, SF),\n  {Kind, SK}   = build_var(Ann, SA),\n  {Reason, SR} = build_var(Ann, SK),\n  {Stack, ST}  = build_var(Ann, SR),\n  {Done, SD}   = build_var(Ann, ST),\n\n  InnerFun = fun(InnerExpr, InnerAcc) ->\n    {call, Ann, Fun, [InnerAcc, pair(Ann, cont, InnerExpr)]}\n  end,\n\n  MatchExpr = {match, Ann,\n    {tuple, Ann, [Acc, Fun]},\n    ?remote(Ann, 'Elixir.Collectable', into, [Into])\n  },\n\n  {IntoReduceExpr, SN} = build_reduce(Ann, Clauses, InnerFun, Expr, Acc, Uniq, SD),\n\n  TryExpr =\n    {'try', Ann,\n      [IntoReduceExpr],\n      [{clause, Ann,\n        [Done],\n        [],\n        [{call, Ann, Fun, [Done, {atom, Ann, done}]}]}],\n      [stacktrace_clause(Ann, Fun, Acc, Kind, Reason, Stack)],\n      []},\n\n  {{block, Ann, [MatchExpr, TryExpr]}, SN}.\n\nstacktrace_clause(Ann, Fun, Acc, Kind, Reason, Stack) ->\n  {clause, Ann,\n    [{tuple, Ann, [Kind, Reason, Stack]}],\n    [],\n    [{call, Ann, Fun, [Acc, {atom, Ann, halt}]},\n     ?remote(Ann, erlang, raise, [Kind, Reason, Stack])]}.\n\n%% Helpers\n\nbuild_reduce(Ann, Clauses, InnerFun, Expr, Into, false, S) ->\n  {Acc, SA} = build_var(Ann, S),\n  {build_reduce_each(Clauses, InnerFun(Expr, Acc), Into, Acc, SA), SA};\nbuild_reduce(Ann, Clauses, InnerFun, Expr, Into, true, S) ->\n  %% Those variables are used only inside the anonymous function\n  %% so we don't need to worry about returning the scope.\n  {Acc, SA} = build_var(Ann, S),\n  {Value, SV} = build_var(Ann, SA),\n  {IntoAcc, SI} = build_var(Ann, SV),\n  {UniqAcc, SU} = build_var(Ann, SI),\n\n  NewInto = {tuple, Ann, [Into, {map, Ann, []}]},\n  AccTuple = {tuple, Ann, [IntoAcc, UniqAcc]},\n  PutUniqExpr = {map, Ann, UniqAcc, [{map_field_assoc, Ann, Value, {atom, Ann, true}}]},\n\n  InnerExpr = {block, Ann, [\n    {match, Ann, AccTuple, Acc},\n    {match, Ann, Value, Expr},\n    {'case', Ann, UniqAcc, [\n      {clause, Ann, [{map, Ann, [{map_field_exact, Ann, Value, {atom, Ann, true}}]}], [], [AccTuple]},\n      {clause, Ann, [{map, Ann, []}], [], [{tuple, Ann, [InnerFun(Value, IntoAcc), PutUniqExpr]}]}\n    ]}\n  ]},\n\n  EnumReduceCall = build_reduce_each(Clauses, InnerExpr, NewInto, Acc, SU),\n  {?remote(Ann, erlang, element, [{integer, Ann, 1}, EnumReduceCall]), SU}.\n\nbuild_reduce_each([{enum, Meta, Left, Right, Filters} | T], Expr, Arg, Acc, S) ->\n  Ann = ?ann(Meta),\n  True = build_reduce_each(T, Expr, Acc, Acc, S),\n  False = Acc,\n  Generated = erl_anno:set_generated(true, Ann),\n\n  Clauses0 =\n    case is_var(Left) of\n      true  -> [];\n      false ->\n        [{clause, Generated,\n          [{var, Ann, '_'}, Acc], [],\n          [False]}]\n    end,\n\n  Clauses1 =\n    [{clause, Ann,\n      [Left, Acc], [],\n      [join_filters(Generated, Filters, True, False)]} | Clauses0],\n\n  Args  = [Right, Arg, {'fun', Ann, {clauses, Clauses1}}],\n  ?remote(Ann, 'Elixir.Enum', reduce, Args);\n\nbuild_reduce_each([{bin, Meta, Left, Right, Filters} | T], Expr, Arg, Acc, S) ->\n  Ann = ?ann(Meta),\n  Generated  = erl_anno:set_generated(true, Ann),\n  {Tail, ST} = build_var(Ann, S),\n  {Fun, SF}  = build_var(Ann, ST),\n\n  True = build_reduce_each(T, Expr, Acc, Acc, SF),\n  False = Acc,\n  {bin, _, Elements} = Left,\n  TailElement = {bin_element, Ann, Tail, default, [bitstring]},\n\n  Clauses =\n    [{clause, Generated,\n      [{bin, Ann, [TailElement]}, Acc], [],\n      [Acc]},\n     {clause, Generated,\n      [Tail, {var, Ann, '_'}], [],\n      [?remote(Ann, erlang, error, [pair(Ann, badarg, Tail)])]}],\n\n  NoVarClauses =\n    case no_var(Generated, Elements) of\n      error ->\n        Clauses;\n\n      NoVarElements ->\n        NoVarMatch = {bin, Ann, NoVarElements ++ [TailElement]},\n        [{clause, Generated, [NoVarMatch, Acc], [], [{call, Ann, Fun, [Tail, False]}]} | Clauses]\n    end,\n\n  BinMatch = {bin, Ann, Elements ++ [TailElement]},\n  VarClauses =\n    [{clause, Ann,\n     [BinMatch, Acc], [],\n     [{call, Ann, Fun, [Tail, join_filters(Generated, Filters, True, False)]}]} | NoVarClauses],\n\n  {call, Ann,\n    {named_fun, Ann, element(3, Fun), VarClauses},\n    [Right, Arg]};\n\nbuild_reduce_each([], Expr, _Arg, _Acc, _S) ->\n  Expr.\n\nis_var({var, _, _}) -> true;\nis_var(_) -> false.\n\npair(Ann, Atom, Arg) ->\n  {tuple, Ann, [{atom, Ann, Atom}, Arg]}.\n\nbuild_var(Ann, S) ->\n  {Name, ST} = elixir_erl_var:build('_', S),\n  {{var, Ann, Name}, ST}.\n\nno_var(ParentAnn, Elements) ->\n  try\n    [{bin_element, Ann, NoVarExpr, no_var_size(Size), Types} ||\n     {bin_element, Ann, Expr, Size, Types} <- Elements,\n     NoVarExpr <- no_var_expr(ParentAnn, Expr)]\n  catch\n    unbound_size -> error\n  end.\n\nno_var_expr(Ann, {string, _, String}) -> [{var, Ann, '_'} || _ <- String];\nno_var_expr(Ann, _) -> [{var, Ann, '_'}].\nno_var_size({var, _, _}) -> throw(unbound_size);\nno_var_size(Size) -> Size.\n\nbuild_comprehension(Ann, Clauses, Expr, Into) ->\n  {comprehension_kind(Into), Ann, Expr, comprehension_clause(Clauses)}.\n\ncomprehension_clause([{bin, Meta, Left, Right, Filters} | T]) ->\n  Ann = ?ann(Meta),\n  [{b_generate, Ann, Left, Right}] ++\n    comprehension_filter(Ann, Filters) ++\n    comprehension_clause(T);\ncomprehension_clause([]) ->\n  [].\n\ncomprehension_kind(false) -> lc;\ncomprehension_kind({nil, _}) -> lc;\ncomprehension_kind({bin, _, []}) -> bc.\n\ninline_or_into({bin, _, []}) -> inline;\ninline_or_into({nil, _}) -> inline;\ninline_or_into(false) -> inline;\ninline_or_into(_) -> into.\n\ncomprehension_filter(Ann, Filters) ->\n  [join_filter(Ann, Filter, {atom, Ann, true}, {atom, Ann, false}) ||\n   Filter <- lists:reverse(Filters)].\n\njoin_filters(_Ann, [], True, _False) ->\n  True;\njoin_filters(Ann, [H | T], True, False) ->\n  lists:foldl(fun(Filter, Acc) ->\n    join_filter(Ann, Filter, Acc, False)\n  end, join_filter(Ann, H, True, False), T).\n\njoin_filter(Ann, {nil, Filter}, True, False) ->\n  {'case', Ann, Filter, [\n    {clause, Ann, [{atom, Ann, true}], [], [True]},\n    {clause, Ann, [{atom, Ann, false}], [], [False]}\n  ]};\njoin_filter(Ann, {Var, Filter}, True, False) ->\n  Guards = [[{op, Ann, 'orelse',\n    {op, Ann, '==', Var, {atom, Ann, false}},\n    {op, Ann, '==', Var, {atom, Ann, nil}}\n  }]],\n\n  {'case', Ann, Filter, [\n    {clause, Ann, [Var], Guards, [False]},\n    {clause, Ann, [{var, Ann, '_'}], [], [True]}\n  ]}.\n"
  },
  {
    "path": "lib/elixir/src/elixir_erl_pass.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Translate Elixir quoted expressions to Erlang Abstract Format.\n-module(elixir_erl_pass).\n-export([translate/3, translate_args/3, no_parens_error/2]).\n%% TODO: Remove me on Elixir v2.0.\n-export([parens_map_field/2, no_parens_remote/2]).\n-include(\"elixir.hrl\").\n\n%% =\n\ntranslate({'=', Meta, [{'_', _, Atom}, Right]}, _Ann, S) when is_atom(Atom) ->\n  Ann = ?ann(Meta),\n  {TRight, SR} = translate(Right, Ann, S),\n  {{match, Ann, {var, Ann, '_'}, TRight}, SR};\n\ntranslate({'=', Meta, [Left, Right]}, _Ann, S) ->\n  Ann = ?ann(Meta),\n  {TRight, SR} = translate(Right, Ann, S),\n  case elixir_erl_clauses:match(Ann, fun translate/3, Left, SR) of\n    {TLeft, #elixir_erl{extra_guards=ExtraGuards, context=Context} = SL0}\n        when ExtraGuards =/= [], Context =/= match ->\n      SL1 = SL0#elixir_erl{extra_guards=[]},\n      {ResultVarName, SL2} = elixir_erl_var:build('_', SL1),\n      Match = {match, Ann, TLeft, TRight},\n      Generated = erl_anno:set_generated(true, Ann),\n      ResultVar = {var, Generated, ResultVarName},\n      ResultMatch = {match, Generated, ResultVar, Match},\n      True = {atom, Generated, true},\n      Reason = {tuple, Generated, [{atom, Generated, badmatch}, ResultVar]},\n      RaiseExpr = ?remote(Generated, erlang, error, [Reason]),\n      GuardsExp = {'if', Generated, [\n        {clause, Generated, [], [ExtraGuards], [ResultVar]},\n        {clause, Generated, [], [[True]], [RaiseExpr]}\n      ]},\n      {{block, Generated, [ResultMatch, GuardsExp]}, SL2};\n\n    {TLeft, SL} ->\n      {{match, Ann, TLeft, TRight}, SL}\n  end;\n\n%% Containers\n\ntranslate({'{}', Meta, Args}, _Ann, S) when is_list(Args) ->\n  Ann = ?ann(Meta),\n  {TArgs, SE} = translate_args(Args, Ann, S),\n  {{tuple, Ann, TArgs}, SE};\n\ntranslate({'%{}', Meta, Args}, _Ann, S) when is_list(Args) ->\n  translate_map(?ann(Meta), Args, S);\n\ntranslate({'%', Meta, [{'^', _, [{Name, _, Context}]} = Left, Right]}, _Ann, S) when is_atom(Name), is_atom(Context) ->\n  translate_struct_var_name(?ann(Meta), Left, Right, S);\n\ntranslate({'%', Meta, [{Name, _, Context} = Left, Right]}, _Ann, S) when is_atom(Name), is_atom(Context) ->\n  translate_struct_var_name(?ann(Meta), Left, Right, S);\n\ntranslate({'%', Meta, [Left, Right]}, _Ann, S) ->\n  translate_struct(?ann(Meta), Left, Right, S);\n\ntranslate({'<<>>', Meta, Args}, _Ann, S) when is_list(Args) ->\n  translate_bitstring(Meta, Args, S);\n\n%% Blocks\n\ntranslate({'__block__', Meta, Args}, _Ann, S) when is_list(Args) ->\n  Ann = ?ann(Meta),\n  {TArgs, SA} = translate_block(Args, Ann, [], S),\n  {{block, Ann, lists:reverse(TArgs)}, SA};\n\n%% Compilation environment macros\n\ntranslate({'__CALLER__', Meta, Atom}, _Ann, S) when is_atom(Atom) ->\n  {{var, ?ann(Meta), '__CALLER__'}, S#elixir_erl{caller=true}};\n\ntranslate({'__STACKTRACE__', Meta, Atom}, _Ann, S = #elixir_erl{stacktrace=Var}) when is_atom(Atom) ->\n  {{var, ?ann(Meta), Var}, S};\n\ntranslate({'super', Meta, Args}, _Ann, S) when is_list(Args) ->\n  Ann = ?ann(Meta),\n\n  %% In the expanded AST, super is used to invoke a function\n  %% in the current module originated from a default clause\n  %% or a super call.\n  {TArgs, SA} = translate_args(Args, Ann, S),\n  {super, {Kind, Name}} = lists:keyfind(super, 1, Meta),\n\n  if\n    Kind == defmacro; Kind == defmacrop ->\n      MacroName = elixir_utils:macro_name(Name),\n      {{call, Ann, {atom, Ann, MacroName}, [{var, Ann, '__CALLER__'} | TArgs]}, SA#elixir_erl{caller=true}};\n    Kind == def; Kind == defp ->\n      {{call, Ann, {atom, Ann, Name}, TArgs}, SA}\n  end;\n\n%% Functions\n\ntranslate({'&', Meta, [{'/', _, [{{'.', _, [Remote, Fun]}, _, []}, Arity]}]}, _Ann, S)\n    when is_atom(Fun), is_integer(Arity) ->\n  Ann = ?ann(Meta),\n  {TRemote, SR} = translate(Remote, Ann, S),\n  TFun = {atom, Ann, Fun},\n  TArity = {integer, Ann, Arity},\n  {{'fun', Ann, {function, TRemote, TFun, TArity}}, SR};\ntranslate({'&', Meta, [{'/', _, [{Fun, _, Atom}, Arity]}]}, Ann, S)\n    when is_atom(Fun), is_atom(Atom), is_integer(Arity) ->\n  case S of\n    #elixir_erl{expand_captures=true} ->\n      {Vars, SV} = lists:mapfoldl(fun(_, Acc) ->\n        {Var, _, AccS} = elixir_erl_var:assign(Meta, Acc),\n        {Var, AccS}\n      end, S, tl(lists:seq(0, Arity))),\n      translate({'fn', Meta, [{'->', Meta, [Vars, {Fun, Meta, Vars}]}]}, Ann, SV);\n\n    #elixir_erl{expand_captures=false} ->\n      {{'fun', ?ann(Meta), {function, Fun, Arity}}, S}\n  end;\n\ntranslate({fn, Meta, Clauses}, _Ann, S) ->\n  Transformer = fun({'->', CMeta, [ArgsWithGuards, Expr]}, Acc) ->\n    {Args, Guards} = elixir_utils:extract_splat_guards(ArgsWithGuards),\n    elixir_erl_clauses:clause(?ann(CMeta), fun translate_fn_match/3, Args, Expr, Guards, Acc)\n  end,\n  {TClauses, NS} = lists:mapfoldl(Transformer, S, Clauses),\n  {{'fun', ?ann(Meta), {clauses, TClauses}}, NS};\n\n%% Cond\n\ntranslate({'cond', CondMeta, [[{do, Clauses}]]}, Ann, S) ->\n  [{'->', Meta, [[Condition], _]} = H | T] = lists:reverse(Clauses),\n\n  FirstMeta =\n    if\n      is_atom(Condition), Condition /= false, Condition /= nil -> ?generated(Meta);\n      true -> Meta\n    end,\n\n  Error = {{'.', Meta, [erlang, error]}, Meta, [cond_clause]},\n  {Case, SC} = build_cond_clauses([H | T], Error, FirstMeta, S),\n  translate(replace_case_meta(CondMeta, Case), Ann, SC);\n\n%% Case\n\ntranslate({'case', Meta, [Expr, Opts]}, _Ann, S) ->\n  translate_case(Meta, Expr, Opts, S);\n\n%% Try\n\ntranslate({'try', Meta, [Opts]}, _Ann, S) ->\n  Ann = ?ann(Meta),\n  Do = proplists:get_value('do', Opts, nil),\n  {TDo, SB} = translate(Do, Ann, S),\n\n  Catch = [Tuple || {X, _} = Tuple <- Opts, X == 'rescue' orelse X == 'catch'],\n  {TCatch, SC} = elixir_erl_try:clauses(Ann, Catch, SB),\n\n  {TAfter, SA} = case lists:keyfind('after', 1, Opts) of\n    {'after', After} ->\n      {TBlock, SAExtracted} = translate(After, Ann, SC),\n      {unblock(TBlock), SAExtracted};\n    false ->\n      {[], SC}\n  end,\n\n  Else = elixir_erl_clauses:get_clauses('else', Opts, match),\n  {TElse, SE} = elixir_erl_clauses:clauses(Else, SA),\n  {{'try', ?ann(Meta), unblock(TDo), TElse, TCatch, TAfter}, SE};\n\n%% Receive\n\ntranslate({'receive', Meta, [Opts]}, _Ann, S) ->\n  Do = elixir_erl_clauses:get_clauses(do, Opts, match),\n\n  case lists:keyfind('after', 1, Opts) of\n    false ->\n      {TClauses, SC} = elixir_erl_clauses:clauses(Do, S),\n      {{'receive', ?ann(Meta), TClauses}, SC};\n    _ ->\n      After = elixir_erl_clauses:get_clauses('after', Opts, expr),\n      {TClauses, SC} = elixir_erl_clauses:clauses(Do ++ After, S),\n      {FClauses, TAfter} = elixir_utils:split_last(TClauses),\n      {_, _, [FExpr], _, FAfter} = TAfter,\n      {{'receive', ?ann(Meta), FClauses, FExpr, FAfter}, SC}\n  end;\n\n%% Comprehensions and with\n\ntranslate({for, Meta, [_ | _] = Args}, _Ann, S) ->\n  elixir_erl_for:translate(Meta, Args, S);\n\ntranslate({with, Meta, [_ | _] = Args}, _Ann, S) ->\n  Ann = ?ann(Meta),\n  {Exprs, [{do, Do} | Opts]} = elixir_utils:split_last(Args),\n  {ElseClause, MaybeFun, SE} = translate_with_else(Meta, Opts, S),\n  {Case, SD} = translate_with_do(Exprs, Ann, Do, ElseClause, SE),\n\n  case MaybeFun of\n    nil -> {Case, SD};\n    FunAssign -> {{block, Ann, [FunAssign, Case]}, SD}\n  end;\n\n%% Variables\n\ntranslate({'^', _, [{Name, VarMeta, Kind}]}, _Ann, S) when is_atom(Name), is_atom(Kind) ->\n  {Var, VS} = elixir_erl_var:translate(VarMeta, Name, Kind, S),\n\n  case S#elixir_erl.extra of\n    pin_guard ->\n      {PinVarName, PS} = elixir_erl_var:build('_', VS),\n      Ann = ?ann(?generated(VarMeta)),\n      PinVar = {var, Ann, PinVarName},\n      Guard = {op, Ann, '=:=', Var, PinVar},\n      {PinVar, PS#elixir_erl{extra_guards=[Guard | PS#elixir_erl.extra_guards]}};\n    _ ->\n      {Var, VS}\n  end;\n\ntranslate({Name, Meta, Kind}, _Ann, S) when is_atom(Name), is_atom(Kind) ->\n  elixir_erl_var:translate(Meta, Name, Kind, S);\n\n%% Local calls\n\ntranslate({Name, Meta, Args}, _Ann, S) when is_atom(Name), is_list(Meta), is_list(Args) ->\n  Ann = ?ann(Meta),\n  {TArgs, NS} = translate_args(Args, Ann, S),\n  {{call, Ann, {atom, Ann, Name}, TArgs}, NS};\n\n%% Remote calls\n\ntranslate({{'.', _, [Left, Right]}, Meta, []}, _Ann, #elixir_erl{context=guard} = S)\n    when is_tuple(Left), is_atom(Right), is_list(Meta) ->\n  Ann = ?ann(Meta),\n  {TLeft, SL}  = translate(Left, Ann, S),\n  TRight = {atom, Ann, Right},\n  {?remote(Ann, erlang, map_get, [TRight, TLeft]), SL};\n\ntranslate({{'.', _, [Left, Right]}, Meta, []}, _Ann, S)\n  when is_tuple(Left) orelse Left =:= nil orelse is_boolean(Left), is_atom(Right), is_list(Meta) ->\n  Ann = ?ann(Meta),\n  {TLeft, SL} = translate(Left, Ann, S),\n  TRight = {atom, Ann, Right},\n  Generated = erl_anno:set_generated(true, Ann),\n\n  case proplists:get_value(no_parens, Meta, false) of\n    true ->\n      {Var, SV} = elixir_erl_var:build('_', SL),\n      TVar = {var, Generated, Var},\n\n      {{'case', Generated, TLeft, [\n        {clause, Generated,\n          [{map, Ann, [{map_field_exact, Ann, TRight, TVar}]}],\n          [],\n          [TVar]},\n        {clause, Generated,\n          [TVar],\n          [],\n          [?remote(Ann, erlang, error, [\n            ?remote(Generated, elixir_erl_pass, no_parens_error, [TVar, TRight])\n           ])]}\n      ]}, SV};\n\n    false ->\n      {{call, Generated, {remote, Generated, TLeft, TRight}, []}, SL}\n    end;\n\ntranslate({{'.', _, [Left, Right]}, Meta, Args}, _Ann, S)\n    when (is_tuple(Left) orelse is_atom(Left)), is_atom(Right), is_list(Meta), is_list(Args) ->\n  translate_remote(Left, Right, Meta, Args, S);\n\n%% Anonymous function calls\n\ntranslate({{'.', _, [Expr]}, Meta, Args}, _Ann, S) when is_list(Args) ->\n  Ann = ?ann(Meta),\n  {TExpr, SE} = translate(Expr, Ann, S),\n  {TArgs, SA} = translate_args(Args, Ann, SE),\n  {{call, Ann, TExpr, TArgs}, SA};\n\n%% Literals\n\ntranslate({Left, Right}, Ann, S) ->\n  {TLeft, SL} = translate(Left, Ann, S),\n  {TRight, SR} = translate(Right, Ann, SL),\n  {{tuple, Ann, [TLeft, TRight]}, SR};\n\ntranslate(List, Ann, S) when is_list(List) ->\n  translate_list(List, Ann, [], S);\n\ntranslate(Other, Ann, S) ->\n  {elixir_erl:elixir_to_erl(Other, Ann), S}.\n\n%% Helpers\n\ntranslate_case(Meta, Expr, Opts, S) ->\n  Ann = ?ann(Meta),\n  {TExpr, SE} = translate(Expr, Ann, S),\n  Clauses = elixir_erl_clauses:get_clauses(do, Opts, match),\n  RClauses =\n    %% For constructs that optimize booleans, we mark them as generated\n    %% to avoid reports from the Erlang compiler but specially Dialyzer.\n    case lists:member({optimize_boolean, true}, Meta) of\n      true -> [{N, ?generated(M), H, B} || {N, M, H, B} <- Clauses];\n      false -> Clauses\n    end,\n  {TClauses, SC} = elixir_erl_clauses:clauses(RClauses, SE),\n  {{'case', Ann, TExpr, TClauses}, SC}.\n\ntranslate_list([{'|', _, [Left, Right]}], Ann, List, Acc) ->\n  {TLeft, LAcc} = translate(Left, Ann, Acc),\n  {TRight, TAcc} = translate(Right, Ann, LAcc),\n  {build_list([TLeft | List], TRight, Ann), TAcc};\ntranslate_list([H | T], Ann, List, Acc) ->\n  {TH, TAcc} = translate(H, Ann, Acc),\n  translate_list(T, Ann, [TH | List], TAcc);\ntranslate_list([], Ann, List, Acc) ->\n  {build_list(List, {nil, Ann}, Ann), Acc}.\n\nbuild_list([H | T], Acc, Ann) ->\n  build_list(T, {cons, Ann, H, Acc}, Ann);\nbuild_list([], Acc, _Ann) ->\n  Acc.\n\n%% Pack a list of expressions from a block.\nunblock({'block', _, Exprs}) -> Exprs;\nunblock(Expr)                -> [Expr].\n\ntranslate_fn_match(Arg, Ann, S) ->\n  {TArg, TS} = translate_args(Arg, Ann, S#elixir_erl{extra=pin_guard}),\n  {TArg, TS#elixir_erl{extra=S#elixir_erl.extra}}.\n\n%% Translate args\n\ntranslate_args(Args, Ann, S) ->\n  lists:mapfoldl(fun\n    (Arg, SA) when is_list(Arg) ->\n      translate_list(Arg, Ann, [], SA);\n    (Arg, SA) when is_tuple(Arg) ->\n      translate(Arg, Ann, SA);\n    (Arg, SA) ->\n      {elixir_erl:elixir_to_erl(Arg, Ann), SA}\n  end, S, Args).\n\n%% Translate blocks\n\ntranslate_block([], _Ann, Acc, S) ->\n  {Acc, S};\ntranslate_block([H], Ann, Acc, S) ->\n  {TH, TS} = translate(H, Ann, S),\n  translate_block([], Ann, [TH | Acc], TS);\ntranslate_block([{'__block__', Meta, Args} | T], Ann, Acc, S) when is_list(Args) ->\n  {TAcc, SA} = translate_block(Args, ?ann(Meta), Acc, S),\n  translate_block(T, Ann, TAcc, SA);\ntranslate_block([H | T], Ann, Acc, S) ->\n  {TH, TS} = translate(H, Ann, S),\n  translate_block(T, Ann, [TH | Acc], TS).\n\n%% Cond\n\nbuild_cond_clauses([{'->', NewMeta, [[Condition], Body]} | T], Acc, OldMeta, S) ->\n  {NewCondition, Truthy, Other, ST} = build_truthy_clause(NewMeta, Condition, Body, S),\n  Falsy = {'->', OldMeta, [[Other], Acc]},\n  Case = {'case', NewMeta, [NewCondition, [{do, [Truthy, Falsy]}]]},\n  build_cond_clauses(T, Case, NewMeta, ST);\nbuild_cond_clauses([], Acc, _, S) ->\n  {Acc, S}.\n\nreplace_case_meta(Meta, {'case', _, Args}) ->\n  {'case', Meta, Args};\nreplace_case_meta(_Meta, Other) ->\n  Other.\n\nbuild_truthy_clause(Meta, Condition, Body, S) ->\n  case returns_boolean(Condition, Body) of\n    {NewCondition, NewBody} ->\n      {NewCondition, {'->', Meta, [[true], NewBody]}, false, S};\n    false ->\n      {Var, _, SV} = elixir_erl_var:assign(Meta, S),\n      Head = {'when', [], [Var,\n        {{'.', [], [erlang, 'andalso']}, [], [\n          {{'.', [], [erlang, '/=']}, [], [Var, nil]},\n          {{'.', [], [erlang, '/=']}, [], [Var, false]}\n        ]}\n      ]},\n      {Condition, {'->', Meta, [[Head], Body]}, {'_', [], nil}, SV}\n  end.\n\n%% In case a variable is defined to match in a condition\n%% but a condition returns boolean, we can replace the\n%% variable directly by the boolean result.\nreturns_boolean({'=', _, [{Var, _, Ctx}, Condition]}, {Var, _, Ctx}) when is_atom(Var), is_atom(Ctx) ->\n  case elixir_utils:returns_boolean(Condition) of\n    true  -> {Condition, true};\n    false -> false\n  end;\n\n%% For all other cases, we check the condition but\n%% return both condition and body untouched.\nreturns_boolean(Condition, Body) ->\n  case elixir_utils:returns_boolean(Condition) of\n    true  -> {Condition, Body};\n    false -> false\n  end.\n\n%% with\n\ntranslate_with_else(Meta, [], S) ->\n  Ann = ?ann(Meta),\n  {VarName, SC} = elixir_erl_var:build('_', S),\n  Var = {var, Ann, VarName},\n  Generated = erl_anno:set_generated(true, Ann),\n  {{clause, Generated, [Var], [], [Var]}, nil, SC};\ntranslate_with_else(Meta, [{'else', [{'->', _, [[{Var, VarMeta, Kind}], Clause]}]}], S) when is_atom(Var), is_atom(Kind) ->\n  Ann = ?ann(Meta),\n  {ElseVarErl, SV} = elixir_erl_var:translate(VarMeta, Var, Kind, S#elixir_erl{context=match}),\n  {TranslatedClause, SC} = translate(Clause, Ann, SV#elixir_erl{context=nil}),\n  Clauses = [{clause, Ann, [ElseVarErl], [], [TranslatedClause]}],\n  with_else_closure(Meta, Clauses, SC);\ntranslate_with_else(Meta, [{'else', Else}], S) ->\n  Generated = ?generated(Meta),\n  {RaiseVar, _, SV} = elixir_erl_var:assign(Generated, S),\n\n  RaiseExpr = {{'.', Generated, [erlang, error]}, Generated, [{else_clause, RaiseVar}]},\n  RaiseClause = {'->', Generated, [[RaiseVar], RaiseExpr]},\n\n  Clauses = elixir_erl_clauses:get_clauses('else', [{'else', Else ++ [RaiseClause]}], match),\n  {TranslatedClauses, SC} = elixir_erl_clauses:clauses(Clauses, SV#elixir_erl{extra=pin_guard}),\n  with_else_closure(Generated, TranslatedClauses, SC#elixir_erl{extra=SV#elixir_erl.extra}).\n\nwith_else_closure(Meta, TranslatedClauses, S) ->\n  Ann = ?ann(Meta),\n  {_, FunErlVar, SC} = elixir_erl_var:assign(Meta, S),\n  {_, ArgErlVar, SA} = elixir_erl_var:assign(Meta, SC),\n  Generated = erl_anno:set_generated(true, Ann),\n  FunAssign = {match, Ann, FunErlVar, {'fun', Generated, {clauses, TranslatedClauses}}},\n  FunCall = {call, Ann, FunErlVar, [ArgErlVar]},\n  {{clause, Generated, [ArgErlVar], [], [FunCall]}, FunAssign, SA}.\n\ntranslate_with_do([{'<-', Meta, [{Var, _, Ctx} = Left, Expr]} | Rest], Ann, Do, Else, S) when is_atom(Var), is_atom(Ctx) ->\n  translate_with_do([{'=', Meta, [Left, Expr]} | Rest], Ann, Do, Else, S);\ntranslate_with_do([{'<-', Meta, [Left, Expr]} | Rest], _Ann, Do, Else, S) ->\n  Ann = ?ann(Meta),\n  {Args, Guards} = elixir_utils:extract_guards(Left),\n  {TExpr, SR} = translate(Expr, Ann, S),\n  {TArgs, SA} = elixir_erl_clauses:match(Ann, fun translate/3, Args, SR),\n  TGuards = elixir_erl_clauses:guards(Ann, Guards, SA#elixir_erl.extra_guards, SA),\n  {TBody, SB} = translate_with_do(Rest, Ann, Do, Else, SA#elixir_erl{extra_guards=[]}),\n  Clause = {clause, Ann, [TArgs], TGuards, unblock(TBody)},\n  {{'case', Ann, TExpr, [Clause, Else]}, SB};\ntranslate_with_do([Expr | Rest], Ann, Do, Else, S) ->\n  {TExpr, TS} = translate(Expr, Ann, S),\n  {TRest, RS} = translate_with_do(Rest, Ann, Do, Else, TS),\n  {{block, Ann, [TExpr | unblock(TRest)]}, RS};\ntranslate_with_do([], Ann, Do, _Else, S) ->\n  translate(Do, Ann, S).\n\n%% Maps and structs\n\ntranslate_struct_var_name(Ann, Name, Args, S0) ->\n  {{map, MapAnn, TArgs0}, S1} = translate_struct(Ann, Name, Args, S0),\n  {TArgs1, S2} = generate_struct_name_guard(TArgs0, [], S1),\n  {{map, MapAnn, TArgs1}, S2}.\n\ntranslate_struct(Ann, _Name, {'%{}', _, [{'|', Meta, [Update, Assocs]}]}, S) ->\n  {TUpdate, SU} = translate(Update, Ann, S),\n  translate_map(?ann(Meta), Assocs, {ok, TUpdate}, SU);\ntranslate_struct(Ann, Name, {'%{}', _, Assocs}, S) ->\n  translate_map(Ann, [{'__struct__', Name}] ++ Assocs, none, S).\n\ntranslate_map(Ann, [{'|', Meta, [Update, Assocs]}], S) ->\n  {TUpdate, SU} = translate(Update, Ann, S),\n  translate_map(?ann(Meta), Assocs, {ok, TUpdate}, SU);\ntranslate_map(Ann, Assocs, S) ->\n  translate_map(Ann, Assocs, none, S).\n\ntranslate_map(Ann, Assocs, TUpdate, #elixir_erl{extra=Extra} = S) ->\n  Op = translate_key_val_op(TUpdate, S),\n\n  {TArgs, SA} = lists:mapfoldl(fun({Key, Value}, Acc0) ->\n    {TKey, Acc1} = translate(Key, Ann, Acc0#elixir_erl{extra=map_key}),\n    {TValue, Acc2} = translate(Value, Ann, Acc1#elixir_erl{extra=Extra}),\n    {{Op, Ann, TKey, TValue}, Acc2}\n  end, S, Assocs),\n\n  build_map(Ann, TUpdate, TArgs, SA).\n\ntranslate_key_val_op(_TUpdate, #elixir_erl{extra=map_key}) -> map_field_assoc;\ntranslate_key_val_op(_TUpdate, #elixir_erl{context=match}) -> map_field_exact;\ntranslate_key_val_op(none, _) -> map_field_assoc;\ntranslate_key_val_op(_, _) -> map_field_exact.\n\nbuild_map(Ann, {ok, TUpdate}, TArgs, SA) -> {{map, Ann, TUpdate, TArgs}, SA};\nbuild_map(Ann, none, TArgs, SA) -> {{map, Ann, TArgs}, SA}.\n\n%% Translate bitstrings\n\ntranslate_bitstring(Meta, Args, S) ->\n  build_bitstr(Args, ?ann(Meta), S, []).\n\nbuild_bitstr([{'::', Meta, [H, V]} | T], Ann, S, Acc) ->\n  {Size, Types} = extract_bit_info(V, Meta, S#elixir_erl{context=nil, extra=nil}),\n  build_bitstr(T, Ann, S, Acc, H, Size, Types);\nbuild_bitstr([], Ann, S, Acc) ->\n  {{bin, Ann, lists:reverse(Acc)}, S}.\n\nbuild_bitstr(T, Ann, S, Acc, H, default, Types) when is_binary(H) ->\n  Element =\n    case requires_utf_conversion(Types) of\n      false ->\n        %% See explanation in elixir_erl:elixir_to_erl/1 to\n        %% know why we can simply convert the binary to a list.\n        {bin_element, Ann, {string, 0, binary_to_list(H)}, default, default};\n      true ->\n        %% UTF types require conversion.\n        {bin_element, Ann, {string, 0, elixir_utils:characters_to_list(H)}, default, Types}\n    end,\n  build_bitstr(T, Ann, S, [Element | Acc]);\n\nbuild_bitstr(T, Ann, S, Acc, H, Size, Types) ->\n  {Expr, NS} = translate(H, Ann, S),\n  build_bitstr(T, Ann, NS, [{bin_element, Ann, Expr, Size, Types} | Acc]).\n\nrequires_utf_conversion([bitstring | _]) -> false;\nrequires_utf_conversion([binary | _]) -> false;\nrequires_utf_conversion(_) -> true.\n\nextract_bit_info({'-', _, [L, {size, _, [Size]}]}, Meta, S) ->\n  {extract_bit_size(Size, Meta, S), extract_bit_type(L, [])};\nextract_bit_info({size, _, [Size]}, Meta, S) ->\n  {extract_bit_size(Size, Meta, S), []};\nextract_bit_info(L, _Meta, _S) ->\n  {default, extract_bit_type(L, [])}.\n\nextract_bit_size(Size, Meta, S) ->\n  {TSize, _} = translate(Size, ?ann(Meta), S#elixir_erl{context=guard}),\n  TSize.\n\nextract_bit_type({'-', _, [L, R]}, Acc) ->\n  extract_bit_type(L, extract_bit_type(R, Acc));\nextract_bit_type({unit, _, [Arg]}, Acc) ->\n  [{unit, Arg} | Acc];\nextract_bit_type({Other, _, nil}, Acc) ->\n  [Other | Acc];\n%% TODO: Remove me on Elixir v2.0.\n%% Elixir v1.14 and earlier emitted an empty list\n%% and may still be processed via debug_info.\nextract_bit_type({Other, _, []}, Acc) ->\n  [Other | Acc].\n\n%% Optimizations that are specific to Erlang and change\n%% the format of the AST.\n\ntranslate_remote('Elixir.String.Chars', to_string, Meta, [Arg], S) ->\n  Ann = ?ann(Meta),\n  {TArg, TS} = translate(Arg, Ann, S),\n  {VarName, VS} = elixir_erl_var:build('_', TS),\n\n  Generated = erl_anno:set_generated(true, Ann),\n  Var = {var, Generated, VarName},\n  Guard = ?remote(Generated, erlang, is_binary, [Var]),\n  Slow = ?remote(Generated, 'Elixir.String.Chars', to_string, [Var]),\n  Fast = Var,\n\n  {{'case', Generated, TArg, [\n    {clause, Generated, [Var], [[Guard]], [Fast]},\n    {clause, Generated, [Var], [], [Slow]}\n  ]}, VS};\ntranslate_remote(maps, put, Meta, [Key, Value, Map], S) ->\n  Ann = ?ann(Meta),\n\n  case translate_args([Key, Value, Map], Ann, S) of\n    {[TKey, TValue, {map, _, InnerMap, Pairs}], TS} ->\n      {{map, Ann, InnerMap, Pairs ++ [{map_field_assoc, Ann, TKey, TValue}]}, TS};\n\n    {[TKey, TValue, {map, _, Pairs}], TS} ->\n      {{map, Ann, Pairs ++ [{map_field_assoc, Ann, TKey, TValue}]}, TS};\n\n    {[TKey, TValue, TMap], TS} ->\n      {{map, Ann, TMap, [{map_field_assoc, Ann, TKey, TValue}]}, TS}\n  end;\ntranslate_remote(lists, member, Meta, [Expr, [Head | Tail] = List], S) ->\n  Ann = ?ann(Meta),\n\n  case optimize_list_membership(List, 0) of\n    true ->\n      {TExpr, S1} = translate(Expr, Ann, S),\n\n      {TVar, TFun, S3} =\n        case TExpr of\n          {var, _, _} ->\n            {TExpr, fun(Orelse) -> Orelse end, S1};\n\n          _ ->\n            {VarName, S2} = elixir_erl_var:build('_', S1),\n            Generated = erl_anno:set_generated(true, Ann),\n            Var = {var, Generated, VarName},\n            Fun = fun(Orelse) -> {block, Generated, [{match, Generated, Var, TExpr}, Orelse]} end,\n            {Var, Fun, S2}\n        end,\n\n      {THead, _} = translate(Head, Ann, S),\n\n      TOrelse =\n        lists:foldl(\n          fun(X, Acc) ->\n            {TX, _} = translate(X, Ann, S),\n            {op, Ann, 'orelse', Acc, {op, Ann, '=:=', TVar, TX}}\n          end,\n          {op, Ann, '=:=', TVar, THead},\n          Tail\n        ),\n\n      {TFun(TOrelse), S3};\n\n    false ->\n      {TArgs, SA} = translate_args([Expr, List], Ann, S),\n      {{call, Ann, {remote, Ann, {atom, Ann, lists}, {atom, Ann, member}}, TArgs}, SA}\n  end;\ntranslate_remote(maps, merge, Meta, [Map1, Map2], S) ->\n  Ann = ?ann(Meta),\n\n  case translate_args([Map1, Map2], Ann, S) of\n    {[{map, _, Pairs1}, {map, _, Pairs2}], TS} ->\n      {{map, Ann, Pairs1 ++ Pairs2}, TS};\n\n    {[{map, _, InnerMap1, Pairs1}, {map, _, Pairs2}], TS} ->\n      {{map, Ann, InnerMap1, Pairs1 ++ Pairs2}, TS};\n\n    {[TMap1, {map, _, Pairs2}], TS} ->\n      {{map, Ann, TMap1, Pairs2}, TS};\n\n    {[TMap1, TMap2], TS} ->\n      {{call, Ann, {remote, Ann, {atom, Ann, maps}, {atom, Ann, merge}}, [TMap1, TMap2]}, TS}\n  end;\ntranslate_remote(Left, Right, Meta, Args, S) ->\n  Ann = ?ann(Meta),\n\n  case rewrite_strategy(Left, Right, Args) of\n    guard_op ->\n      {TArgs, SA} = translate_args(Args, Ann, S),\n      %% Rewrite Erlang function calls as operators so they\n      %% work in guards, matches and so on.\n      case TArgs of\n        [TOne]       -> {{op, Ann, Right, TOne}, SA};\n        [TOne, TTwo] -> {{op, Ann, Right, TOne, TTwo}, SA}\n      end;\n    {inline_pure, Result} ->\n      Generated = erl_anno:set_generated(true, Ann),\n      translate(Result, Generated, S);\n    {inline_args, NewArgs} ->\n      {TLeft, SL} = translate(Left, Ann, S),\n      {TArgs, SA} = translate_args(NewArgs, Ann, SL),\n      TRight = {atom, Ann, Right},\n      {{call, Ann, {remote, Ann, TLeft, TRight}, TArgs}, SA};\n    none ->\n      {TLeft, SL} = translate(Left, Ann, S),\n      {TArgs, SA} = translate_args(Args, Ann, SL),\n      TRight = {atom, Ann, Right},\n      {{call, Ann, {remote, Ann, TLeft, TRight}, TArgs}, SA}\n  end.\n\noptimize_list_membership([Head | Tail], Count)\n    when Count =< 32, is_number(Head) orelse is_atom(Head) orelse is_binary(Head) ->\n  optimize_list_membership(Tail, Count + 1);\noptimize_list_membership([], _Count) ->\n  true;\noptimize_list_membership(_, _Count) ->\n  false.\n\nrewrite_strategy(erlang, Right, Args) ->\n  Arity  = length(Args),\n  case elixir_utils:guard_op(Right, Arity) of\n    true -> guard_op;\n    false -> none\n  end;\nrewrite_strategy(Left, shift, [Struct, Opts | RestArgs]) when\n  Left == 'Elixir.Date';\n  Left == 'Elixir.DateTime';\n  Left == 'Elixir.NaiveDateTime';\n  Left == 'Elixir.Time'\n->\n  case basic_type_arg(Opts) of\n    true ->\n      try\n        {inline_args, [Struct, Left:'__duration__!'(Opts) | RestArgs]}\n      catch _:_ ->\n        % fail silently, will fail at runtime\n        none\n      end;\n    false ->\n      none\n  end;\nrewrite_strategy(Left, Right, Args) ->\n  case inline_pure_function(Left, Right) andalso basic_type_arg(Args) of\n    true ->\n      try\n        {inline_pure, apply(Left, Right, Args)}\n      catch _:_ ->\n        % fail silently, will fail at runtime\n        none\n      end;\n    false ->\n      none\n  end.\n\ninline_pure_function('Elixir.Duration', 'new!') -> true;\ninline_pure_function('Elixir.MapSet', new) -> true;\ninline_pure_function('Elixir.String', length) -> true;\ninline_pure_function('Elixir.String', graphemes) -> true;\ninline_pure_function('Elixir.String', codepoints) -> true;\ninline_pure_function('Elixir.String', split) -> true;\ninline_pure_function('Elixir.Kernel', to_timeout) -> true;\ninline_pure_function('Elixir.URI', new) -> true;\ninline_pure_function('Elixir.URI', 'new!') -> true;\ninline_pure_function('Elixir.URI', parse) -> true;\ninline_pure_function('Elixir.URI', encode_query) -> true;\ninline_pure_function('Elixir.URI', encode_www_form) -> true;\ninline_pure_function('Elixir.URI', decode) -> true;\ninline_pure_function('Elixir.URI', decode_www_form) -> true;\ninline_pure_function('Elixir.Version', parse) -> true;\ninline_pure_function('Elixir.Version', 'parse!') -> true;\ninline_pure_function('Elixir.Version', parse_requirement) -> true;\ninline_pure_function('Elixir.Version', 'parse_requirement!') -> true;\ninline_pure_function(_Left, _Right) -> false.\n\n% we do not want to try and inline calls which might depend on protocols that might be overridden later\nbasic_type_arg(Term) when is_number(Term); is_atom(Term); is_binary(Term) -> true;\nbasic_type_arg(List) when is_list(List) -> lists:all(fun basic_type_arg/1, List);\nbasic_type_arg({Left, Right}) -> basic_type_arg(Left) and basic_type_arg(Right);\nbasic_type_arg(_) -> false.\n\ngenerate_struct_name_guard([{map_field_exact, Ann, {atom, _, '__struct__'} = Key, Var} | Rest], Acc, S0) ->\n  {ModuleVarName, S1} = elixir_erl_var:build('_', S0),\n  Generated = erl_anno:set_generated(true, Ann),\n  ModuleVar = {var, Generated, ModuleVarName},\n  Match = {match, Generated, ModuleVar, Var},\n  Guard = ?remote(Generated, erlang, is_atom, [ModuleVar]),\n  S2 = S1#elixir_erl{extra_guards=[Guard | S1#elixir_erl.extra_guards]},\n  {lists:reverse(Acc, [{map_field_exact, Ann, Key, Match} | Rest]), S2};\ngenerate_struct_name_guard([Field | Rest], Acc, S) ->\n  generate_struct_name_guard(Rest, [Field | Acc], S).\n\nno_parens_error(#{} = Map, Key) ->\n  {badkey, Key, Map};\nno_parens_error(Other, _Key) ->\n  {badmap, Other}.\n\n%% TODO: Previous Elixir code was compiled with these functions,\n%% so we have to keep them.\nno_parens_remote(nil, _Key) -> {error, {badmap, nil}};\nno_parens_remote(false, _Key) -> {error, {badmap, false}};\nno_parens_remote(true, _Key) -> {error, {badmap, true}};\nno_parens_remote(Atom, Fun) when is_atom(Atom) ->\n  Message = fun() ->\n    io_lib:format(\n      \"using map.field notation (without parentheses) to invoke function ~ts.~ts() is deprecated, \"\n      \"you must add parentheses instead: remote.function()\",\n      [elixir_aliases:inspect(Atom), Fun]\n    )\n  end,\n  'Elixir.IO':warn_once(?MODULE, Message, 3),\n  {ok, apply(Atom, Fun, [])};\nno_parens_remote(#{} = Map, Key) ->\n  {error, {badkey, Key, Map}};\nno_parens_remote(Other, _Key) ->\n  {error, {badmap, Other}}.\n\nparens_map_field(Key, Value) ->\n  Message = fun() ->\n    io_lib:format(\n      \"using module.function() notation (with parentheses) to fetch map field ~ts is deprecated, \"\n      \"you must remove the parentheses: map.field\",\n      [elixir_aliases:inspect(Key)]\n    )\n  end,\n  'Elixir.IO':warn_once(?MODULE, Message, 3),\n  Value.\n"
  },
  {
    "path": "lib/elixir/src/elixir_erl_try.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_erl_try).\n-export([clauses/3]).\n-include(\"elixir.hrl\").\n-define(REQUIRES_STACKTRACE,\n        ['Elixir.FunctionClauseError', 'Elixir.UndefinedFunctionError',\n         'Elixir.KeyError', 'Elixir.ArgumentError', 'Elixir.SystemLimitError']).\n\nclauses(_Ann, Args, S) ->\n  Catch = elixir_erl_clauses:get_clauses('catch', Args, 'catch'),\n  Rescue = elixir_erl_clauses:get_clauses(rescue, Args, rescue),\n  {StackName, SV} = elixir_erl_var:build('__STACKTRACE__', S),\n  OldStack = SV#elixir_erl.stacktrace,\n  SS = SV#elixir_erl{stacktrace=StackName},\n  reduce_clauses(Rescue ++ Catch, [], OldStack, SS, SS).\n\nreduce_clauses([H | T], Acc, OldStack, SAcc, S) ->\n  {TH, TS} = each_clause(H, SAcc),\n  reduce_clauses(T, [TH | Acc], OldStack, TS, S);\nreduce_clauses([], Acc, OldStack, SAcc, _S) ->\n  {lists:reverse(Acc), SAcc#elixir_erl{stacktrace=OldStack}}.\n\neach_clause({'catch', Meta, Raw, Expr}, S) ->\n  {Args, Guards} = elixir_utils:extract_splat_guards(Raw),\n\n  Match =\n    %% TODO: Remove me on Elixir v2.0.\n    %% Elixir v1.17 and earlier emitted single argument\n    %% and may still be processed via debug_info.\n    case Args of\n      [X] -> [throw, X];\n      [X, Y] -> [X, Y]\n    end,\n\n  {{clause, Line, [TKind, TMatches], TGuards, TBody}, TS} =\n    elixir_erl_clauses:clause(?ann(Meta), fun elixir_erl_pass:translate_args/3, Match, Expr, Guards, S),\n\n  build_clause(Line, TKind, TMatches, TGuards, TBody, TS);\n\neach_clause({rescue, Meta, [{in, _, [Left, Right]}], Expr}, S) ->\n  {TempVar, _, CS} = elixir_erl_var:assign(Meta, S),\n  {Guards, ErlangAliases} = rescue_guards(Meta, TempVar, Right),\n  Body = normalize_rescue(Meta, TempVar, Left, Expr, ErlangAliases),\n  build_rescue(Meta, TempVar, Guards, Body, CS);\n\neach_clause({rescue, Meta, [{VarName, _, Context} = Left], Expr}, S) when is_atom(VarName), is_atom(Context) ->\n  {TempVar, _, CS} = elixir_erl_var:assign(Meta, S),\n  Body = normalize_rescue(Meta, TempVar, Left, Expr, ['Elixir.ErlangError']),\n  build_rescue(Meta, TempVar, [], Body, CS).\n\nnormalize_rescue(_Meta, _Var, {'_', _, Atom}, Expr, _) when is_atom(Atom) ->\n  Expr;\nnormalize_rescue(Meta, Var, Pattern, Expr, []) ->\n  prepend_to_block(Meta, {'=', Meta, [Pattern, Var]}, Expr);\nnormalize_rescue(Meta, Var, Pattern, Expr, ErlangAliases) ->\n  Stacktrace =\n    case lists:member('Elixir.ErlangError', ErlangAliases) of\n      true ->\n        dynamic_normalize(Meta, Var, ?REQUIRES_STACKTRACE);\n\n      false ->\n        case lists:partition(fun is_normalized_with_stacktrace/1, ErlangAliases) of\n          {[], _} -> [];\n          {_, []} -> {'__STACKTRACE__', Meta, nil};\n          {Some, _} -> dynamic_normalize(Meta, Var, Some)\n        end\n    end,\n\n  Normalized = {{'.', Meta, ['Elixir.Exception', normalize]}, Meta, [error, Var, Stacktrace]},\n  prepend_to_block(Meta, {'=', Meta, [Pattern, Normalized]}, Expr).\n\ndynamic_normalize(Meta, Var, [H | T]) ->\n  Generated = ?generated(Meta),\n\n  Guards =\n    lists:foldl(fun(Alias, Acc) ->\n      {'when', Generated, [erl_rescue_stacktrace_for(Generated, Var, Alias), Acc]}\n    end, erl_rescue_stacktrace_for(Generated, Var, H), T),\n\n  {'case', Generated, [\n    Var,\n    [{do, [\n      {'->', Generated, [[{'when', Generated, [{'_', Generated, nil}, Guards]}], {'__STACKTRACE__', Generated, nil}]},\n      {'->', Generated, [[{'_', Generated, nil}], []]}\n    ]}]\n  ]}.\n\nerl_rescue_stacktrace_for(_Meta, _Var, 'Elixir.ErlangError') ->\n  %% ErlangError is a \"meta\" exception, we should never expand it here.\n  error(badarg);\nerl_rescue_stacktrace_for(Meta, Var, 'Elixir.KeyError') ->\n  %% Only the two-element tuple requires stacktrace.\n  erl_and(Meta, erl_tuple_size(Meta, Var, 2), erl_record_compare(Meta, Var, badkey));\nerl_rescue_stacktrace_for(Meta, Var, Module) ->\n  erl_rescue_guard_for(Meta, Var, Module).\n\nis_normalized_with_stacktrace(Module) ->\n  lists:member(Module, ?REQUIRES_STACKTRACE).\n\n%% Helpers\n\nbuild_rescue(Meta, Var, Guards, Body, S) ->\n  {{clause, Line, [TMatch], TGuards, TBody}, TS} =\n    elixir_erl_clauses:clause(?ann(Meta), fun elixir_erl_pass:translate_args/3, [Var], Body, Guards, S),\n\n  build_clause(Line, {atom, Line, error}, TMatch, TGuards, TBody, TS).\n\n%% Convert rescue clauses (\"var in [alias1, alias2]\") into guards.\nrescue_guards(_Meta, _Var, []) ->\n  {[], []};\nrescue_guards(Meta, Var, Aliases) ->\n  {ErlangGuards, ErlangAliases} = erl_rescue(Meta, Var, Aliases, [], []),\n\n  ElixirGuards =\n    [erl_and(Meta,\n       {erl(Meta, '=='), Meta, [{erl(Meta, map_get), Meta, ['__struct__', Var]}, Alias]},\n       {erl(Meta, map_get), Meta, ['__exception__', Var]}\n     ) || Alias <- Aliases],\n\n  {ElixirGuards ++ ErlangGuards, ErlangAliases}.\n\nbuild_clause(Line, Kind, Expr, Guards, Body, #elixir_erl{stacktrace=Var} = TS) ->\n  Match = {tuple, Line, [Kind, Expr, {var, Line, Var}]},\n  {{clause, Line, [Match], Guards, Body}, TS}.\n\n%% Rescue each atom name considering their Erlang or Elixir matches.\n%% Matching of variables is done with Erlang exceptions is done in\n%% function for optimization.\n\nerl_rescue(Meta, Var, [H | T], Guards, Aliases) when is_atom(H) ->\n  case erl_rescue_guard_for(Meta, Var, H) of\n    false -> erl_rescue(Meta, Var, T, Guards, Aliases);\n    Expr  -> erl_rescue(Meta, Var, T, [Expr | Guards], [H | Aliases])\n  end;\nerl_rescue(_, _, [], Guards, Aliases) ->\n  {Guards, Aliases}.\n\n%% Handle Erlang rescue matches.\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.UndefinedFunctionError') ->\n  {erl(Meta, '=='), Meta, [Var, undef]};\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.FunctionClauseError') ->\n  {erl(Meta, '=='), Meta, [Var, function_clause]};\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.SystemLimitError') ->\n  {erl(Meta, '=='), Meta, [Var, system_limit]};\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.ArithmeticError') ->\n  {erl(Meta, '=='), Meta, [Var, badarith]};\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.CondClauseError') ->\n  {erl(Meta, '=='), Meta, [Var, cond_clause]};\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.BadArityError') ->\n  erl_and(Meta,\n          erl_tuple_size(Meta, Var, 2),\n          erl_record_compare(Meta, Var, badarity));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.BadFunctionError') ->\n  erl_and(Meta,\n          erl_tuple_size(Meta, Var, 2),\n          erl_record_compare(Meta, Var, badfun));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.MatchError') ->\n  erl_and(Meta,\n          erl_tuple_size(Meta, Var, 2),\n          erl_record_compare(Meta, Var, badmatch));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.CaseClauseError') ->\n  erl_and(Meta,\n          erl_tuple_size(Meta, Var, 2),\n          erl_record_compare(Meta, Var, case_clause));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.WithClauseError') ->\n  erl_and(Meta,\n          erl_tuple_size(Meta, Var, 2),\n          erl_record_compare(Meta, Var, else_clause));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.TryClauseError') ->\n  erl_and(Meta,\n          erl_tuple_size(Meta, Var, 2),\n          erl_record_compare(Meta, Var, try_clause));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.BadMapError') ->\n  erl_and(Meta,\n          erl_tuple_size(Meta, Var, 2),\n          erl_record_compare(Meta, Var, badmap));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.BadBooleanError') ->\n  erl_and(Meta,\n          erl_tuple_size(Meta, Var, 3),\n          erl_record_compare(Meta, Var, badbool));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.KeyError') ->\n  erl_and(Meta,\n          erl_or(Meta,\n            erl_tuple_size(Meta, Var, 2),\n            erl_tuple_size(Meta, Var, 3)),\n          erl_record_compare(Meta, Var, badkey));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.ArgumentError') ->\n  erl_or(Meta,\n         {erl(Meta, '=='), Meta, [Var, badarg]},\n         erl_and(Meta,\n                 erl_tuple_size(Meta, Var, 2),\n                 erl_record_compare(Meta, Var, badarg)));\n\nerl_rescue_guard_for(Meta, Var, 'Elixir.ErlangError') ->\n  Condition =\n    erl_and(\n      Meta,\n      {erl(Meta, is_map), Meta, [Var]},\n      {erl(Meta, is_map_key), Meta, ['__exception__', Var]}\n    ),\n  {erl(Meta, 'not'), Meta, [Condition]};\n\nerl_rescue_guard_for(_, _, _) ->\n  false.\n\n%% Helpers\n\nerl_tuple_size(Meta, Var, Size) ->\n  {erl(Meta, '=='), Meta, [{erl(Meta, tuple_size), Meta, [Var]}, Size]}.\n\nerl_record_compare(Meta, Var, Expr) ->\n  {erl(Meta, '=='), Meta, [\n    {erl(Meta, element), Meta, [1, Var]},\n    Expr\n  ]}.\n\nprepend_to_block(_Meta, Expr, {'__block__', Meta, Args}) ->\n  {'__block__', Meta, [Expr | Args]};\n\nprepend_to_block(Meta, Expr, Args) ->\n  {'__block__', Meta, [Expr, Args]}.\n\nerl(Meta, Op) -> {'.', Meta, [erlang, Op]}.\nerl_or(Meta, Left, Right) -> {erl(Meta, 'orelse'), Meta, [Left, Right]}.\nerl_and(Meta, Left, Right) -> {erl(Meta, 'andalso'), Meta, [Left, Right]}.\n"
  },
  {
    "path": "lib/elixir/src/elixir_erl_var.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Convenience functions used to manipulate scope and its variables.\n-module(elixir_erl_var).\n-export([\n  translate/4, assign/2, build/2,\n  load_binding/2, dump_binding/4,\n  from_env/1, from_env/2\n]).\n-include(\"elixir.hrl\").\n\n%% VAR HANDLING\n\ntranslate(Meta, '_', _Kind, S) ->\n  {{var, ?ann(Meta), '_'}, S};\n\ntranslate(Meta, Name, Kind, #elixir_erl{var_names=VarNames} = S) ->\n  {version, Version} = lists:keyfind(version, 1, Meta),\n\n  case VarNames of\n    #{Version :=  ErlName} -> {{var, ?ann(Meta), ErlName}, S};\n    #{} when Kind /= nil -> assign(Meta, '_', Version, S);\n    #{} -> assign(Meta, Name, Version, S)\n  end.\n\nassign(Meta, #elixir_erl{var_names=VarNames} = S) ->\n  Version = -(map_size(VarNames)+1),\n  ExVar = {var, [{version, Version} | Meta], ?var_context},\n  {ErlVar, SV} = assign(Meta, '_', Version, S),\n  {ExVar, ErlVar, SV}.\n\nassign(Meta, Name, Version, #elixir_erl{var_names=VarNames} = S) ->\n  {NewVar, NS} = build(Name, S),\n  NewVarNames = VarNames#{Version => NewVar},\n  {{var, ?ann(Meta), NewVar}, NS#elixir_erl{var_names=NewVarNames}}.\n\nbuild(Key, #elixir_erl{counter=Counter} = S) ->\n  Count =\n    case Counter of\n      #{Key := Val} -> Val + 1;\n      _ -> 1\n    end,\n  {build_name(Key, Count),\n   S#elixir_erl{counter=Counter#{Key => Count}}}.\n\nbuild_name('_', Count) -> list_to_atom(\"_@\" ++ integer_to_list(Count));\nbuild_name(Name, Count) -> list_to_atom(\"_\" ++ atom_to_list(Name) ++ \"@\" ++ integer_to_list(Count)).\n\n%% BINDINGS\n\nfrom_env(#{versioned_vars := Read} = Env) ->\n  VarsList = to_erl_vars(maps:values(Read), 0),\n  {VarsList, from_env(Env, maps:from_list(VarsList))}.\n\nfrom_env(#{context := Context}, VarsMap) ->\n  #elixir_erl{\n    context=Context,\n    var_names=VarsMap,\n    counter=#{'_' => map_size(VarsMap)}\n  }.\n\nto_erl_vars([Version | Versions], Counter) ->\n  [{Version, to_erl_var(Counter)} | to_erl_vars(Versions, Counter + 1)];\nto_erl_vars([], _Counter) ->\n  [].\n\nto_erl_var(Counter) ->\n  list_to_atom(\"_@\" ++ integer_to_list(Counter)).\n\nload_binding(Binding, Prune) ->\n  load_binding(Binding, #{}, [], [], 0, Prune).\n\nload_binding([Binding | NextBindings], ExVars, ErlVars, Normalized, Counter, Prune) ->\n  {Pair, Value} = load_pair(Binding),\n\n  case ExVars of\n    #{Pair := VarCounter} ->\n      ErlVar = to_erl_var(VarCounter),\n      load_binding(NextBindings, ExVars, ErlVars, [{ErlVar, Value} | Normalized], Counter, Prune);\n\n    #{} ->\n      ErlVar = to_erl_var(Counter),\n\n      load_binding(\n        NextBindings,\n        ExVars#{Pair => Counter},\n        [{Counter, ErlVar} | ErlVars],\n        [{ErlVar, Value} | Normalized],\n        Counter + 1,\n        Prune\n      )\n  end;\nload_binding([], ExVars, ErlVars, Normalized, Counter, true) ->\n  load_binding([{{elixir, prune_binding}, true}], ExVars, ErlVars, Normalized, Counter, false);\nload_binding([], ExVars, ErlVars, Normalized, _Counter, false) ->\n  {ExVars, maps:from_list(ErlVars), maps:from_list(lists:reverse(Normalized))}.\n\nload_pair({Key, Value}) when is_atom(Key) -> {{Key, nil}, Value};\nload_pair({Pair, Value}) -> {Pair, Value}.\n\ndump_binding(Binding, ErlS, ExS, PruneBefore) ->\n  #elixir_erl{var_names=ErlVars} = ErlS,\n  #elixir_ex{vars={ExVars, _}, unused={Unused, _}} = ExS,\n\n  maps:fold(fun\n    ({Var, Kind} = Pair, Version, {B, V})\n    when is_atom(Kind),\n         %% If the variable is part of the pruning (usually the input binding)\n         %% and is unused, we removed it from vars.\n         Version > PruneBefore orelse is_map_key({Pair, Version}, Unused) ->\n      Key = case Kind of\n        nil -> Var;\n        _ -> Pair\n      end,\n\n      ErlName = maps:get(Version, ErlVars),\n      Value = maps:get(ErlName, Binding, nil),\n      {[{Key, Value} | B], V};\n\n    (Pair, _, {B, V}) when PruneBefore >= 0 ->\n      {B, maps:remove(Pair, V)};\n\n    (_, _, Acc) ->\n      Acc\n  end, {[], ExVars}, ExVars).\n"
  },
  {
    "path": "lib/elixir/src/elixir_errors.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% A bunch of helpers to help to deal with errors in Elixir source code.\n%% This is not exposed in the Elixir language.\n%%\n%% Note that this is also called by the Erlang backend, so we also support\n%% the line number to be none (as it may happen in some erlang errors).\n-module(elixir_errors).\n-export([compile_error/1, compile_error/3, parse_error/5]).\n-export([function_error/4, module_error/4, file_error/4]).\n-export([format_snippet/6]).\n-export([erl_warn/3, file_warn/4]).\n-export([prefix/1]).\n-export([print_diagnostics/1, print_diagnostic/2, emit_diagnostic/6]).\n-export([print_warning/3]).\n-include(\"elixir.hrl\").\n-type location() :: non_neg_integer() | {non_neg_integer(), non_neg_integer()}.\n\n%% Diagnostic API\n\n%% TODO: Remove me on Elixir v2.0.\n%% Called by deprecated Kernel.ParallelCompiler.print_warning.\nprint_warning(Position, File, Message) ->\n  Output = format_snippet(warning, Position, File, Message, nil, #{}),\n  io:put_chars(standard_error, [Output, $\\n, $\\n]).\n\n%% Used by Module.ParallelChecker.\nprint_diagnostics([Diagnostic | Others]) ->\n  #{file := File, position := Position, message := Message} = Diagnostic,\n  Snippet = read_snippet(File, Position),\n  Formatted = format_snippet(warning, Position, File, Message, Snippet, Diagnostic),\n  LineNumber = extract_line(Position),\n  LineDigits = get_line_number_digits(LineNumber, 1),\n  Padding = case Snippet of\n    nil -> 0;\n    _ -> max(4, LineDigits + 2)\n  end,\n  Locations = [[\"\\n\", n_spaces(Padding), \"└─ \", 'Elixir.Exception':format_stacktrace_entry(ES)] || #{stacktrace := [ES]} <- Others],\n  io:put_chars(standard_error, [Formatted, Locations, $\\n, $\\n]).\n\nprint_diagnostic(#{severity := S, message := M, position := P, file := F} = Diagnostic, ReadSnippet) ->\n  Snippet =\n    case ReadSnippet of\n      true -> read_snippet(F, P);\n      false -> nil\n    end,\n\n  Output = format_snippet(S, P, F, M, Snippet, Diagnostic),\n\n  MaybeStack =\n    case (F /= nil) orelse elixir_config:is_bootstrap() of\n      true -> [];\n      false -> [[\"\\n  \", 'Elixir.Exception':format_stacktrace_entry(E)] || E <- ?key(Diagnostic, stacktrace)]\n    end,\n\n  io:put_chars(standard_error, [Output, MaybeStack, $\\n, $\\n]),\n  Diagnostic.\n\nemit_diagnostic(Severity, Position, File, Message, Stacktrace, Options) ->\n  ReadSnippet = proplists:get_value(read_snippet, Options, false),\n\n  Span = case lists:keyfind(span, 1, Options) of\n    {span, {EndLine, EndCol}} -> {EndLine, EndCol};\n    _ -> nil\n  end,\n\n  Diagnostic = #{\n    severity => Severity,\n    source => case get(elixir_compiler_file) of\n      undefined -> File;\n      CompilerFile -> CompilerFile\n    end,\n    file => File,\n    position => Position,\n    message => unicode:characters_to_binary(Message),\n    stacktrace => Stacktrace,\n    span => Span\n  },\n\n  case get(elixir_code_diagnostics) of\n    undefined ->\n      case get(elixir_compiler_info) of\n        undefined -> print_diagnostic(Diagnostic, ReadSnippet);\n        {CompilerPid, _} -> CompilerPid ! {diagnostic, Diagnostic, ReadSnippet}\n      end;\n\n    {Tail, true} ->\n      put(elixir_code_diagnostics, {[print_diagnostic(Diagnostic, ReadSnippet) | Tail], true});\n\n    {Tail, false} ->\n      put(elixir_code_diagnostics, {[Diagnostic | Tail], false})\n  end,\n\n  ok.\n\nextract_line({L, _}) -> L;\nextract_line(L) -> L.\n\nextract_column({_, C}) -> C;\nextract_column(_) -> nil.\n\n%% Format snippets\n%% \"Snippet\" here refers to the source code line where the diagnostic/error occurred\n\nformat_snippet(Severity, _Position, nil, Message, nil, _Diagnostic) ->\n  Formatted = [prefix(Severity), \" \", Message],\n  unicode:characters_to_binary(Formatted);\n\nformat_snippet(Severity, Position, File, Message, nil, Diagnostic) ->\n  Location = location_format(Position, File, maps:get(stacktrace, Diagnostic, [])),\n\n  Formatted = io_lib:format(\n    \"~ts ~ts\\n\"\n    \"└─ ~ts\",\n    [prefix(Severity), Message, Location]\n   ),\n\n  unicode:characters_to_binary(Formatted);\n\nformat_snippet(Severity, Position, File, Message, Snippet, Diagnostic) ->\n  Column = extract_column(Position),\n  LineNumber = extract_line(Position),\n  LineDigits = get_line_number_digits(LineNumber, 1),\n  Spacing = n_spaces(max(2, LineDigits) + 1),\n  LineNumberSpacing = if LineDigits =:= 1 -> 1; true -> 0 end,\n  {FormattedLine, ColumnsTrimmed} = format_line(Snippet),\n  Location = location_format(Position, File, maps:get(stacktrace, Diagnostic, [])),\n  MessageDetail = format_detail(Diagnostic, Message),\n\n  Highlight =\n    case Column of\n      nil ->\n        highlight_below_line(FormattedLine, Severity);\n      _ ->\n        Length = calculate_span_length({LineNumber, Column}, Diagnostic),\n        highlight_at_position(Column - ColumnsTrimmed, Severity, Length)\n    end,\n\n  Formatted = io_lib:format(\n    \" ~ts~ts ~ts\\n\"\n    \" ~ts│\\n\"\n    \" ~ts~p │ ~ts\\n\"\n    \" ~ts│ ~ts\\n\"\n    \" ~ts│\\n\"\n    \" ~ts└─ ~ts\",\n    [\n     Spacing, prefix(Severity), format_message(MessageDetail, LineDigits, 2 + LineNumberSpacing),\n     Spacing,\n     n_spaces(LineNumberSpacing), LineNumber, FormattedLine,\n     Spacing, Highlight,\n     Spacing,\n     Spacing, Location\n    ]),\n\n  unicode:characters_to_binary(Formatted).\n\nformat_detail(#{details := #{typing_traces := _}}, Message) -> [Message | \"\\ntype warning found at:\"];\nformat_detail(_, Message) -> Message.\n\ncalculate_span_length({StartLine, StartCol}, #{span := {StartLine, EndCol}}) -> EndCol - StartCol;\ncalculate_span_length({StartLine, _}, #{span := {EndLine, _}}) when EndLine > StartLine -> 1;\ncalculate_span_length({_, _}, #{}) -> 1.\n\nformat_line(Line) ->\n  case trim_line(Line, 0) of\n    {Trimmed, SpacesMatched} when SpacesMatched >= 27 ->\n      ColumnsTrimmed = SpacesMatched - 22,\n      {[\"...\", n_spaces(19), Trimmed], ColumnsTrimmed};\n\n    {_, _} ->\n      {Line, 0}\n  end.\n\ntrim_line(<<$\\s, Rest/binary>>, Count) -> trim_line(Rest, Count + 1);\ntrim_line(<<$\\t, Rest/binary>>, Count) -> trim_line(Rest, Count + 8);\ntrim_line(Rest, Count) -> {Rest, Count}.\n\nformat_message(Message, NDigits, PaddingSize) ->\n  Padding = list_to_binary([$\\n, n_spaces(NDigits + PaddingSize)]),\n  Bin = unicode:characters_to_binary(Message),\n  pad_line(binary:split(Bin, <<\"\\n\">>, [global]), Padding).\n\npad_line([Last], _Padding) -> [Last];\npad_line([First, <<\"\">> | Rest], Padding) -> [First, \"\\n\" | pad_line([<<\"\">> | Rest], Padding)];\npad_line([First | Rest], Padding) -> [First, Padding | pad_line(Rest, Padding)].\n\nhighlight_at_position(Column, Severity, Length) ->\n  Spacing = n_spaces(max(Column - 1, 0)),\n  case Severity of\n    warning ->  highlight([Spacing, lists:duplicate(Length, $~)], warning);\n    error -> highlight([Spacing, lists:duplicate(Length, $^)], error)\n  end.\n\nhighlight_below_line(Line, Severity) ->\n  % Don't highlight leading whitespaces in line\n  {Rest, SpacesMatched} = trim_line(Line, 0),\n\n  Length = string:length(Rest),\n  Highlight = case Severity of\n    warning -> highlight(lists:duplicate(Length, $~), warning);\n    error -> highlight(lists:duplicate(Length, $^), error)\n  end,\n\n  [n_spaces(SpacesMatched), Highlight].\n\nget_line_number_digits(Number, Acc) when Number < 10 -> Acc;\nget_line_number_digits(Number, Acc) ->\n  get_line_number_digits(Number div 10, Acc + 1).\n\nn_spaces(N) -> lists:duplicate(N, \" \").\n\nread_snippet(nil, _Position) ->\n  nil;\nread_snippet(<<\"nofile\">>, _Position) ->\n  nil;\nread_snippet(File, Position) ->\n  LineNumber = extract_line(Position),\n  get_file_line(File, LineNumber).\n\nget_file_line(File, LineNumber) when is_integer(LineNumber), LineNumber > 0 ->\n  case file:open(File, [read, binary]) of\n    {ok, IoDevice} ->\n      Line = traverse_file_line(IoDevice, LineNumber),\n      ok = file:close(IoDevice),\n      Line;\n    {error, _} ->\n      nil\n  end;\nget_file_line(_, _) -> nil.\n\ntraverse_file_line(IoDevice, 1) ->\n  case file:read_line(IoDevice) of\n    {ok, Line} -> binary:replace(Line, <<\"\\n\">>, <<>>);\n    _ -> nil\n  end;\ntraverse_file_line(IoDevice, N) ->\n  file:read_line(IoDevice),\n  traverse_file_line(IoDevice, N - 1).\n\n%% Compilation error/warn handling.\n\n%% Low-level warning, should be used only from Erlang passes.\n-spec erl_warn(location() | none, unicode:chardata(), unicode:chardata()) -> ok.\nerl_warn(none, File, Warning) ->\n  erl_warn(0, File, Warning);\nerl_warn(Location, File, Warning) when is_binary(File) ->\n  emit_diagnostic(warning, Location, File, Warning, [], [{read_snippet, true}]).\n\n-spec file_warn(list(), binary() | #{file := binary(), _ => _}, module(), any()) -> ok.\nfile_warn(Meta, File, Module, Desc) when is_list(Meta), is_binary(File) ->\n  file_warn(Meta, #{file => File}, Module, Desc);\nfile_warn(Meta, E, Module, Desc) when is_list(Meta) ->\n  % Skip warnings during bootstrap, they will be reported during recompilation\n  case elixir_config:is_bootstrap() of\n    true -> ok;\n    false ->\n      {EnvPosition, EnvFile, EnvStacktrace} = env_format(Meta, E),\n      Message = Module:format_error(Desc),\n      emit_diagnostic(warning, EnvPosition, EnvFile, Message, EnvStacktrace, [{read_snippet, true} | Meta])\n  end.\n\n-spec file_error(list(), binary() | #{file := binary(), _ => _}, module(), any()) -> no_return().\nfile_error(Meta, File, Module, Desc) when is_list(Meta), is_binary(File) ->\n  file_error(Meta, #{file => File}, Module, Desc);\nfile_error(Meta, Env, Module, Desc) when is_list(Meta) ->\n  print_error(Meta, Env, Module, Desc),\n  compile_error(Env).\n\n%% A module error is one where it can continue if there is a module\n%% being compiled. If there is no module, it is a regular file_error.\n-spec module_error(list(), #{file := binary(), module => module() | nil, _ => _}, module(), any()) -> ok.\nmodule_error(Meta, #{module := EnvModule} = Env, Module, Desc) when EnvModule /= nil ->\n  print_error(Meta, Env, Module, Desc),\n  case elixir_module:taint(EnvModule) of\n    true -> ok;\n    false -> compile_error(Env)\n  end;\nmodule_error(Meta, Env, Module, Desc) ->\n  file_error(Meta, Env, Module, Desc).\n\n%% A function error is one where it can continue if there is a function\n%% being compiled. If there is no function, it is falls back to file_error.\n-spec function_error(list(), #{file := binary(), function => {term(), term()} | nil, _ => _}, module(), any()) -> ok.\nfunction_error(Meta, #{function := {_, _}} = Env, Module, Desc) ->\n  module_error(Meta, Env, Module, Desc);\nfunction_error(Meta, Env, Module, Desc) ->\n  file_error(Meta, Env, Module, Desc).\n\nprint_error(Meta, Env, Module, Desc) ->\n  {EnvPosition, EnvFile, EnvStacktrace} = env_format(Meta, Env),\n  Message = Module:format_error(Desc),\n  emit_diagnostic(error, EnvPosition, EnvFile, Message, EnvStacktrace, [{read_snippet, true} | Meta]),\n  ok.\n\n%% Compilation error.\n\n-spec compile_error(#{file := binary(), _ => _}) -> no_return().\n%% We check for the lexical tracker because pry() inside a module\n%% will have the environment but not a tracker.\ncompile_error(#{module := Module, file := File, lexical_tracker := LT}) when Module /= nil, LT /= nil ->\n  Inspected = elixir_aliases:inspect(Module),\n  Message = io_lib:format(\"cannot compile module ~ts (errors have been logged)\", [Inspected]),\n  compile_error([], File, Message);\ncompile_error(#{file := File}) ->\n  compile_error([], File, \"cannot compile file (errors have been logged)\").\n\n-spec compile_error(list(), binary(), binary() | unicode:charlist()) -> no_return().\ncompile_error(Meta, File, Message) when is_binary(Message) ->\n  {File, Position} = meta_location(Meta, File),\n  raise('Elixir.CompileError', Message, [{file, File} | Position]);\ncompile_error(Meta, File, Message) when is_list(Message) ->\n  {File, Position} = meta_location(Meta, File),\n  raise('Elixir.CompileError', elixir_utils:characters_to_binary(Message), [{file, File} | Position]).\n\n%% Tokenization parsing/errors.\n\n-spec parse_error(elixir:keyword(), binary() | {binary(), binary()},\n                  binary(), binary(), {unicode:charlist(), integer(), integer()}) -> no_return().\nparse_error(Location, File, Error, <<>>, Input) ->\n  Message = case Error of\n    <<\"syntax error before: \">> -> <<\"syntax error: expression is incomplete\">>;\n    _ -> <<Error/binary>>\n  end,\n\n  raise_snippet(Location, File, Input, 'Elixir.TokenMissingError', Message);\n\n%% Show a nicer message for end of line\nparse_error(Location, File, <<\"syntax error before: \">>, <<\"eol\">>, Input) ->\n  raise_snippet(Location, File, Input, 'Elixir.SyntaxError',\n        <<\"unexpectedly reached end of line. The current expression is invalid or incomplete\">>);\n\n%% Show a nicer message for keywords pt1 (Erlang keywords show up wrapped in single quotes)\nparse_error(Location, File, <<\"syntax error before: \">>, Keyword, Input)\n    when Keyword == <<\"'not'\">>;\n         Keyword == <<\"'and'\">>;\n         Keyword == <<\"'or'\">>;\n         Keyword == <<\"'when'\">>;\n         Keyword == <<\"'after'\">>;\n         Keyword == <<\"'catch'\">>;\n         Keyword == <<\"'end'\">> ->\n  raise_reserved(Location, File, Input, binary_part(Keyword, 1, byte_size(Keyword) - 2));\n\n%% Show a nicer message for keywords pt2 (Elixir keywords show up as is)\nparse_error(Location, File, <<\"syntax error before: \">>, Keyword, Input)\n    when Keyword == <<\"fn\">>;\n         Keyword == <<\"else\">>;\n         Keyword == <<\"rescue\">>;\n         Keyword == <<\"true\">>;\n         Keyword == <<\"false\">>;\n         Keyword == <<\"nil\">>;\n         Keyword == <<\"in\">> ->\n  raise_reserved(Location, File, Input, Keyword);\n\n%% Produce a human-readable message for errors before a sigil\nparse_error(Location, File, <<\"syntax error before: \">>, <<\"{sigil,\", _Rest/binary>> = Full, Input) ->\n  {ok, {sigil, _, Atom, [Content | _], _, _, _}} = parse_erl_term(Full),\n  Content2 = case is_binary(Content) of\n    true -> Content;\n    false -> <<>>\n  end,\n\n  % :static_atoms_encoder might encode :sigil_ atoms as arbitrary terms\n  MaybeSigil = case is_atom(Atom) of\n    true -> case atom_to_binary(Atom) of\n      <<\"sigil_\", Chars/binary>> -> <<\"\\~\", Chars/binary, \" \">>;\n      _ -> <<>>\n    end;\n    false -> <<>>\n  end,\n\n  Message = <<\"syntax error before: sigil \", MaybeSigil/binary, \"starting with content '\", Content2/binary, \"'\">>,\n  raise_snippet(Location, File, Input, 'Elixir.SyntaxError', Message);\n\n%% Binaries (and interpolation) are wrapped in [<<...>>]\nparse_error(Location, File, Error, <<\"[\", _/binary>> = Full, Input) when is_binary(Error) ->\n  Term = case parse_erl_term(Full) of\n    {ok, [H | _]} when is_binary(H) -> <<$\", H/binary, $\">>;\n    _ -> <<$\">>\n  end,\n  raise_snippet(Location, File, Input, 'Elixir.SyntaxError', <<Error/binary, Term/binary>>);\n\n%% Given a string prefix and suffix to insert the token inside the error message rather than append it\nparse_error(Location, File, {ErrorPrefix, ErrorSuffix}, Token, Input) when is_binary(ErrorPrefix), is_binary(ErrorSuffix), is_binary(Token) ->\n  Message = <<ErrorPrefix/binary, Token/binary, ErrorSuffix/binary>>,\n  raise_snippet(Location, File, Input, 'Elixir.SyntaxError', Message);\n\n%% Misplaced char tokens (for example, {char, _, 97}) are translated by Erlang into\n%% the char literal (i.e., the token in the previous example becomes $a),\n%% because {char, _, _} is a valid Erlang token for an Erlang char literal. We\n%% want to represent that token as ?a in the error, according to the Elixir\n%% syntax.\nparse_error(Location, File, <<\"syntax error before: \">>, <<$$, Char/binary>>, Input) ->\n  Message = <<\"syntax error before: ?\", Char/binary>>,\n  raise_snippet(Location, File, Input, 'Elixir.SyntaxError', Message);\n\n%% Everything else is fine as is\nparse_error(Location, File, Error, Token, Input) when is_binary(Error), is_binary(Token) ->\n  Message = <<Error/binary, Token/binary>>,\n  case lists:keytake(error_type, 1, Location) of\n    {value, {error_type, mismatched_delimiter}, Loc} ->\n      raise_snippet(Loc, File, Input, 'Elixir.MismatchedDelimiterError', Message);\n    _ ->\n      raise_snippet(Location, File, Input, 'Elixir.SyntaxError', Message)\n  end.\n\nparse_erl_term(Term) ->\n  case erl_scan:string(binary_to_list(Term)) of\n    {ok, Tokens, _} ->\n      case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of\n        {ok, Parsed} -> {ok, Parsed};\n        _ -> error\n      end;\n    _ -> error\n  end.\n\nraise_reserved(Location, File, Input, Keyword) ->\n  raise_snippet(Location, File, Input, 'Elixir.SyntaxError',\n        <<\"syntax error before: \", Keyword/binary, \". \\\"\", Keyword/binary, \"\\\" is a \"\n          \"reserved word in Elixir and therefore its usage is limited. For instance, \"\n          \"it can't be used as a variable or be defined nor invoked as a regular function\">>).\n\nraise_snippet(Location, File, Input, Kind, Message) when is_binary(File) ->\n  Snippet = cut_snippet(Location, Input),\n  raise(Kind, Message, [{file, File}, {snippet, Snippet} | Location]).\n\ncut_snippet(Location, Input) ->\n  case lists:keyfind(column, 1, Location) of\n    {column, _} ->\n      {line, Line} = lists:keyfind(line, 1, Location),\n\n      case lists:keyfind(end_line, 1, Location) of\n        {end_line, EndLine} ->\n          cut_snippet(Input, Line, EndLine - Line + 1);\n\n        false ->\n          Snippet = cut_snippet(Input, Line, 1),\n          case string:trim(Snippet, leading) of\n            <<>> -> nil;\n            _ -> Snippet\n          end\n      end;\n\n    false ->\n      nil\n  end.\n\ncut_snippet({InputString, StartLine, StartColumn, Indentation}, Line, Span) ->\n  %% In case the code is indented, we need to add the indentation back\n  %% for the snippets to match the reported columns.\n  Prelude = lists:duplicate(max(StartColumn - Indentation - 1, 0), \" \"),\n  Lines = string:split(Prelude ++ InputString, \"\\n\", all),\n  Indent = binary:copy(<<\" \">>, Indentation),\n  [Head | Tail] = lists:nthtail(Line - StartLine, Lines),\n  IndentedTail = indent_n(Tail, Span - 1, <<\"\\n\", Indent/binary>>),\n  elixir_utils:characters_to_binary([Indent, Head, IndentedTail]).\n\nindent_n([], _Count, _Indent) -> [];\nindent_n(_Lines, 0, _Indent) -> [];\nindent_n([H | T], Count, Indent) -> [Indent, H | indent_n(T, Count - 1, Indent)].\n\n%% Helpers\n\nprefix(warning) -> highlight(<<\"warning:\">>, warning);\nprefix(error) -> highlight(<<\"error:\">>, error);\nprefix(hint) -> <<\"hint:\">>.\n\nhighlight(Message, Severity) ->\n  case {Severity, application:get_env(elixir, ansi_enabled, false)} of\n    {warning, true} -> yellow(Message);\n    {error, true} -> red(Message);\n    _ -> Message\n  end.\n\nyellow(Msg) -> [\"\\e[33m\", Msg, \"\\e[0m\"].\nred(Msg) -> [\"\\e[31m\", Msg, \"\\e[0m\"].\n\nenv_format(Meta, #{file := EnvFile} = E) ->\n  {File, Position} = meta_location(Meta, EnvFile),\n  Line = ?line(Position),\n\n  Stacktrace =\n    case E of\n      #{function := {Name, Arity}, module := Module} ->\n        [{Module, Name, Arity, [{file, elixir_utils:relative_to_cwd(File)} | Position ]}];\n      #{module := Module} when Module /= nil ->\n        [{Module, '__MODULE__', 0, [{file, elixir_utils:relative_to_cwd(File)} | Position]}];\n      #{} ->\n        []\n    end,\n\n  case lists:keyfind(column, 1, Position) of\n    {column, Column} -> {{Line, Column}, File, Stacktrace};\n    _ -> {Line, File, Stacktrace}\n  end.\n\n%% We prefer the stacktrace, if available, as it also contains module/function.\nlocation_format(_Position, _File, [E | _]) ->\n  'Elixir.Exception':format_stacktrace_entry(E);\nlocation_format(Position, File, []) ->\n  file_format(Position, File).\n\nfile_format({0, _Column}, File) ->\n  elixir_utils:relative_to_cwd(File);\nfile_format({Line, nil}, File) ->\n  file_format(Line, File);\nfile_format({Line, Column}, File) ->\n  io_lib:format(\"~ts:~w:~w\", [elixir_utils:relative_to_cwd(File), Line, Column]);\nfile_format(0, File) ->\n  elixir_utils:relative_to_cwd(File);\nfile_format(Line, File) ->\n  io_lib:format(\"~ts:~w\", [elixir_utils:relative_to_cwd(File), Line]).\n\nmeta_location(Meta, File) ->\n  case elixir_utils:meta_keep(Meta) of\n    {F, L} -> {F, [{line, L}]};\n    nil    -> {File, maybe_add_col([{line, ?line(Meta)}], Meta)}\n  end.\n\nmaybe_add_col(Position, Meta) ->\n  case lists:keyfind(column, 1, Meta) of\n    {column, Col} when is_integer(Col) -> [{column, Col} | Position];\n    false -> Position\n  end.\n\nraise(Kind, Message, Opts) when is_binary(Message) ->\n  Stacktrace = try throw(ok) catch _:_:Stack -> Stack end,\n  Exception = Kind:exception([{description, Message} | Opts]),\n  erlang:raise(error, Exception, tl(Stacktrace)).\n"
  },
  {
    "path": "lib/elixir/src/elixir_expand.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_expand).\n-export([expand/3, expand_args/3, expand_arg/3, format_error/1]).\n-import(elixir_errors, [file_error/4, module_error/4, function_error/4]).\n-include(\"elixir.hrl\").\n-define(kernel, 'Elixir.Kernel').\n\n%% =\n\nexpand({'=', Meta, [_, _]} = Expr, S, #{context := match} = E) ->\n  elixir_clauses:parallel_match(Meta, Expr, S, E);\n\nexpand({'=', Meta, [Left, Right]}, S, E) ->\n  assert_no_guard_scope(Meta, \"=\", S, E),\n  {ERight, SR, ER} = expand(Right, S, E),\n  {ELeft, SL, EL} = elixir_clauses:match(fun expand/3, Meta, Left, SR, S, ER),\n  {{'=', Meta, [ELeft, ERight]}, SL, EL};\n\n%% Literal operators\n\nexpand({'{}', Meta, Args}, S, E) ->\n  {EArgs, SA, EA} = expand_args(Args, S, E),\n  {{'{}', Meta, EArgs}, SA, EA};\n\nexpand({'%{}', Meta, Args}, S, E) ->\n  elixir_map:expand_map(Meta, Args, S, E);\n\nexpand({'%', Meta, [Left, Right]}, S, E) ->\n  elixir_map:expand_struct(Meta, Left, Right, S, E);\n\nexpand({'<<>>', Meta, Args}, S, E) ->\n  elixir_bitstring:expand(Meta, Args, S, E, false);\n\nexpand({'->', Meta, [_, _]}, _S, E) ->\n  file_error(Meta, E, ?MODULE, unhandled_arrow_op);\n\nexpand({'::', Meta, [_, _]}, _S, E) ->\n  file_error(Meta, E, ?MODULE, unhandled_type_op);\n\nexpand({'|', Meta, [_, _]}, _S, E) ->\n  file_error(Meta, E, ?MODULE, unhandled_cons_op);\n\n%% __block__\n\nexpand({'__block__', _Meta, []}, S, E) ->\n  {nil, S, E};\nexpand({'__block__', _Meta, [Arg]}, S, E) ->\n  expand(Arg, S, E);\nexpand({'__block__', Meta, Args}, S, E) when is_list(Args) ->\n  {EArgs, SA, EA} = expand_block(Args, [], Meta, S, E),\n  {{'__block__', Meta, EArgs}, SA, EA};\n\n%% __aliases__\n\nexpand({'__aliases__', _, _} = Alias, S, E) ->\n  expand_aliases(Alias, S, E, true);\n\n%% alias\n\nexpand({Kind, Meta, [{{'.', _, [Base, '{}']}, _, Refs} | Rest]}, S, E)\n    when Kind == alias; Kind == require; Kind == import ->\n  case Rest of\n    [] ->\n      expand_multi_alias_call(Kind, Meta, Base, Refs, [], S, E);\n    [Opts] ->\n      lists:keymember(as, 1, Opts) andalso file_error(Meta, E, ?MODULE, as_in_multi_alias_call),\n      expand_multi_alias_call(Kind, Meta, Base, Refs, Opts, S, E)\n  end;\nexpand({alias, Meta, [Ref]}, S, E) ->\n  expand({alias, Meta, [Ref, []]}, S, E);\nexpand({alias, Meta, [Ref, Opts]}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"alias\", S, E),\n  {ERef, SR, ER} = expand_without_aliases_report(Ref, S, E),\n  {EOpts, ST, ET} = expand_opts(Meta, alias, [as, warn], no_alias_opts(Opts), SR, ER),\n\n  is_atom(ERef) orelse\n    file_error(Meta, E, ?MODULE, {expected_compile_time_module, alias, Ref}),\n\n  {ok, New, EQ} = alias(Meta, ERef, true, EOpts, ET),\n\n  Quoted =\n    case (New /= false) andalso should_warn(Meta, EOpts, EQ) of\n      false ->\n        ERef;\n\n      Pid when ?key(EQ, function) /= nil ->\n        ?tracker:warn_alias(Pid, Meta, New, ERef);\n\n      Pid ->\n        {{'.', Meta, [?tracker, warn_alias]}, Meta, [Pid, Meta, New, ERef]}\n    end,\n\n  {Quoted, ST, EQ};\n\nexpand({require, Meta, [Ref]}, S, E) ->\n  expand({require, Meta, [Ref, []]}, S, E);\nexpand({require, Meta, [Ref, Opts]}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"require\", S, E),\n\n  {ERef, SR, ER} = expand_without_aliases_report(Ref, S, E),\n  {EOpts, ST, ET}  = expand_opts(Meta, require, [as, warn], no_alias_opts(Opts), SR, ER),\n\n  %% Add the alias to context_modules if defined is set.\n  %% This is used by defmodule in order to store the defined\n  %% module in context modules.\n  case lists:keyfind(defined, 1, Meta) of\n    {defined, Mod} when is_atom(Mod) ->\n      Mods = [Mod | ?key(ET, context_modules)],\n      {ok, _, EU} = alias(Meta, ERef, false, EOpts, ET#{context_modules := Mods}),\n\n      SU = case E of\n        #{function := nil} -> ST;\n        _ -> ST#elixir_ex{runtime_modules=[Mod | ST#elixir_ex.runtime_modules]}\n      end,\n\n      {ERef, SU, EU};\n\n    false when is_atom(ERef) ->\n      elixir_aliases:ensure_loaded(Meta, ERef, ET),\n      RE = elixir_aliases:require(Meta, ERef, EOpts, ET, true),\n      {ok, Alias, EU} = alias(Meta, ERef, false, EOpts, RE),\n\n      Quoted =\n        case should_warn(Meta, EOpts, EU) of\n          false ->\n            ERef;\n\n          Pid when ?key(EU, function) /= nil ->\n            ?tracker:warn_require(Pid, Meta, ERef, Alias);\n\n          Pid ->\n            {{'.', Meta, [?tracker, warn_require]}, Meta, [Pid, Meta, ERef, Alias]}\n        end,\n\n      {Quoted, ST, EU};\n\n    false ->\n      file_error(Meta, E, ?MODULE, {expected_compile_time_module, require, Ref})\n  end;\n\nexpand({import, Meta, [Left]}, S, E) ->\n  expand({import, Meta, [Left, []]}, S, E);\n\nexpand({import, Meta, [Ref, Opts]}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"import\", S, E),\n  {ERef, SR, ER} = expand_without_aliases_report(Ref, S, E),\n  {EOpts, ST, ET} = expand_opts(Meta, import, [only, except, warn], Opts, SR, ER),\n\n  is_atom(ERef) orelse\n    file_error(Meta, E, ?MODULE, {expected_compile_time_module, import, Ref}),\n\n  elixir_aliases:ensure_loaded(Meta, ERef, ET),\n\n  case elixir_import:import(Meta, ERef, EOpts, ET, true, true) of\n    {ok, Imported, EI} ->\n      Quoted =\n        case Imported andalso should_warn(Meta, EOpts, ET) of\n          false ->\n            ERef;\n\n          Pid ->\n            Only =\n              case lists:keyfind(only, 1, EOpts) of\n                {only, List} when is_list(List) -> List;\n                _ -> []\n              end,\n\n            %% If we are outside a function, we turn on the warnings at execution time.\n            case ET of\n              #{function := nil} ->\n                ?tracker:add_import(Pid, ERef, Only, Meta, false),\n                {{'.', Meta, [?tracker, warn_import]}, Meta, [Pid, ERef]};\n\n              #{} ->\n                ?tracker:add_import(Pid, ERef, Only, Meta, true),\n                ERef\n            end\n        end,\n\n        {Quoted, ST, EI};\n\n    {error, Reason} ->\n      elixir_errors:file_error(Meta, E, elixir_import, Reason)\n  end;\n\n%% Compilation environment macros\n\nexpand({'__MODULE__', _, Atom}, S, E) when is_atom(Atom) ->\n  {?key(E, module), S, E};\nexpand({'__DIR__', _, Atom}, S, E) when is_atom(Atom) ->\n  {filename:dirname(?key(E, file)), S, E};\nexpand({'__CALLER__', Meta, Atom} = Caller, S, E) when is_atom(Atom) ->\n  assert_no_match_scope(Meta, \"__CALLER__\", E),\n  (not S#elixir_ex.caller) andalso function_error(Meta, E, ?MODULE, caller_not_allowed),\n  {Caller, S, E};\nexpand({'__STACKTRACE__', Meta, Atom} = Stacktrace, S, E) when is_atom(Atom) ->\n  assert_no_match_scope(Meta, \"__STACKTRACE__\", E),\n  (not S#elixir_ex.stacktrace) andalso function_error(Meta, E, ?MODULE, stacktrace_not_allowed),\n  {Stacktrace, S, E};\nexpand({'__ENV__', Meta, Atom}, S, E) when is_atom(Atom) ->\n  assert_no_match_scope(Meta, \"__ENV__\", E),\n  {escape_map(escape_env_entries(Meta, S, E)), S, E};\nexpand({{'.', DotMeta, [{'__ENV__', Meta, Atom}, Field]}, CallMeta, []}, S, E)\n    when is_atom(Atom), is_atom(Field) ->\n  assert_no_match_scope(Meta, \"__ENV__\", E),\n  Env = escape_env_entries(Meta, S, E),\n  case maps:is_key(Field, Env) of\n    true  -> {maps:get(Field, Env), S, E};\n    false -> {{{'.', DotMeta, [escape_map(Env), Field]}, CallMeta, []}, S, E}\n  end;\nexpand({'__cursor__', Meta, Args}, _S, E) when is_list(Args) ->\n  file_error(Meta, E, ?MODULE, '__cursor__');\n\n%% Quote\n\nexpand({Unquote, Meta, [_]}, _S, E) when Unquote == unquote; Unquote == unquote_splicing ->\n  file_error(Meta, E, ?MODULE, {unquote_outside_quote, Unquote});\n\nexpand({quote, Meta, [Opts]}, S, E) when is_list(Opts) ->\n  case lists:keytake(do, 1, Opts) of\n    {value, {do, Do}, DoOpts} ->\n      expand({quote, Meta, [DoOpts, [{do, Do}]]}, S, E);\n    false ->\n      file_error(Meta, E, ?MODULE, {missing_option, 'quote', [do]})\n  end;\n\nexpand({quote, Meta, [_]}, _S, E) ->\n  file_error(Meta, E, ?MODULE, {invalid_args, 'quote'});\n\nexpand({quote, Meta, [Opts, Do]}, S, E) when is_list(Do) ->\n  Exprs =\n    case lists:keyfind(do, 1, Do) of\n      {do, Expr} -> Expr;\n      false -> file_error(Meta, E, ?MODULE, {missing_option, 'quote', [do]})\n    end,\n\n  ValidOpts = [context, location, line, file, unquote, bind_quoted, generated],\n  {EOpts, ST, ET} = expand_opts(Meta, quote, ValidOpts, Opts, S, E),\n\n  Context = proplists:get_value(context, EOpts, case ?key(E, module) of\n    nil -> 'Elixir';\n    Mod -> Mod\n  end),\n\n  {File, Line} = case lists:keyfind(location, 1, EOpts) of\n    {location, keep} ->\n      {?key(E, file), true};\n    false ->\n      {proplists:get_value(file, EOpts, nil), proplists:get_value(line, EOpts, false)}\n  end,\n\n  {Binding, DefaultUnquote} = case lists:keyfind(bind_quoted, 1, EOpts) of\n    {bind_quoted, BQ} ->\n      case is_list(BQ) andalso\n            lists:all(fun({Key, _}) when is_atom(Key) -> true; (_) -> false end, BQ) of\n        true -> {BQ, false};\n        false -> file_error(Meta, E, ?MODULE, {invalid_bind_quoted_for_quote, BQ})\n      end;\n    false ->\n      {[], true}\n  end,\n\n  Unquote = proplists:get_value(unquote, EOpts, DefaultUnquote),\n  Generated = proplists:get_value(generated, EOpts, false),\n\n  {Q, QContext, QPrelude} = elixir_quote:build(Meta, Line, File, Context, Unquote, Generated, ET),\n  {EPrelude, SP, EP} = expand(QPrelude, ST, ET),\n  {EContext, SC, EC} = expand(QContext, SP, EP),\n  Quoted = elixir_quote:quote(Exprs, Q),\n  {EQuoted, ES, EQ} = expand(Quoted, SC, EC),\n  BindingMeta = lists:keydelete(column, 1, Meta),\n\n  EBinding =\n      [{'{}', [],\n        ['=', [], [\n          {'{}', [], [K, BindingMeta, EContext]},\n          V\n        ]\n       ]} || {K, V} <- Binding],\n\n  EBindingQuoted =\n    case EBinding of\n      [] -> EQuoted;\n      _ -> {'{}', [], ['__block__', [], EBinding ++ [EQuoted]]}\n    end,\n\n  case EPrelude of\n    [] -> {EBindingQuoted, ES, EQ};\n    _ -> {{'__block__', [], EPrelude ++ [EBindingQuoted]}, ES, EQ}\n  end;\n\nexpand({quote, Meta, [_, _]}, _S, E) ->\n  file_error(Meta, E, ?MODULE, {invalid_args, 'quote'});\n\n%% Functions\n\nexpand({'&', Meta, [{super, SuperMeta, Args} = Expr]}, S, E) when is_list(Args) ->\n  assert_no_match_or_guard_scope(Meta, \"&\", S, E),\n\n  case resolve_super(Meta, length(Args), E) of\n    {Kind, Name, _} when Kind == def; Kind == defp ->\n      expand_fn_capture(Meta, {Name, SuperMeta, Args}, S, E);\n    _ ->\n      expand_fn_capture(Meta, Expr, S, E)\n  end;\n\nexpand({'&', Meta, [{'/', ArityMeta, [{super, SuperMeta, Context}, Arity]} = Expr]}, S, E) when is_atom(Context), is_integer(Arity) ->\n  assert_no_match_or_guard_scope(Meta, \"&\", S, E),\n\n  case resolve_super(Meta, Arity, E) of\n    {Kind, Name, _} when Kind == def; Kind == defp ->\n      expand({'&', Meta, [{'/', ArityMeta, [{Name, SuperMeta, Context}, Arity]}]}, S, E);\n    _ ->\n      expand_fn_capture(Meta, Expr, S, E)\n  end;\n\nexpand({'&', Meta, [Arg]}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"&\", S, E),\n  expand_fn_capture(Meta, Arg, S, E);\n\nexpand({fn, Meta, Pairs}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"fn\", S, E),\n  elixir_fn:expand(Meta, Pairs, S, E);\n\n%% Case/Receive/Try\n\nexpand({'cond', Meta, [Opts]}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"cond\", S, E),\n  assert_no_underscore_clause_in_cond(Opts, E),\n  {EClauses, SC, EC} = elixir_clauses:'cond'(Meta, Opts, S, E),\n  {{'cond', Meta, [EClauses]}, SC, EC};\n\nexpand({'case', Meta, [Expr, Options]}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"case\", S, E),\n  expand_case(Meta, Expr, Options, S, E);\n\nexpand({'receive', Meta, [Opts]}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"receive\", S, E),\n  {EClauses, SC, EC} = elixir_clauses:'receive'(Meta, Opts, S, E),\n  {{'receive', Meta, [EClauses]}, SC, EC};\n\nexpand({'try', Meta, [Opts]}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"try\", S, E),\n  {EClauses, SC, EC} = elixir_clauses:'try'(Meta, Opts, S, E),\n  {{'try', Meta, [EClauses]}, SC, EC};\n\n%% Comprehensions\n\nexpand({for, _, [_ | _] } = Expr, S, E) ->\n  expand_for(Expr, S, E, true);\n\n%% With\n\nexpand({with, Meta, [_ | _] = Args}, S, E) ->\n  assert_no_match_or_guard_scope(Meta, \"with\", S, E),\n  elixir_clauses:with(Meta, Args, S, E);\n\n%% Super\n\nexpand({super, Meta, Args}, S, E) when is_list(Args) ->\n  assert_no_match_or_guard_scope(Meta, \"super\", S, E),\n  Arity = length(Args),\n  {Kind, Name, _} = resolve_super(Meta, Arity, E),\n  elixir_env:trace({local_function, Meta, Name, Arity}, E),\n  {EArgs, SA, EA} = expand_args(Args, S, E),\n  {{super, [{super, {Kind, Name}} | Meta], EArgs}, SA, EA};\n\n%% Vars\n\nexpand({'^', Meta, [Arg]}, #elixir_ex{prematch={Prematch, _, _}, vars={_, Write}} = S, E) ->\n  NoMatchS = S#elixir_ex{prematch=pin, vars={Prematch, Write}},\n\n  case expand(Arg, NoMatchS, E#{context := nil}) of\n    {{Name, _, Kind} = Var, #elixir_ex{unused=Unused}, _} when is_atom(Name), is_atom(Kind) ->\n      {{'^', Meta, [Var]}, S#elixir_ex{unused=Unused}, E};\n\n    _ ->\n      function_error(Meta, E, ?MODULE, {invalid_arg_for_pin, Arg}),\n      {{'^', Meta, [Arg]}, S#elixir_ex{tainted_function=true}, E}\n  end;\nexpand({'^', Meta, [Arg]}, S, E) ->\n  function_error(Meta, E, ?MODULE, {pin_outside_of_match, Arg}),\n  {{'^', Meta, [Arg]}, S#elixir_ex{tainted_function=true}, E};\n\nexpand({'_', Meta, Kind} = Var, S, #{context := Context} = E) when is_atom(Kind) ->\n  case Context of\n    match ->\n      {Var, S, E};\n    _ ->\n      function_error(Meta, E, ?MODULE, unbound_underscore),\n      {Var, S#elixir_ex{tainted_function=true}, E}\n  end;\n\nexpand({Name, Meta, Kind}, S, #{context := match} = E) when is_atom(Name), is_atom(Kind) ->\n  #elixir_ex{\n    prematch={_, _, PrematchVersion},\n    unused={Unused, Version},\n    vars={Read, Write}\n  } = S,\n\n  Pair = {Name, elixir_utils:var_context(Meta, Kind)},\n\n  case Read of\n    %% Variable was already overridden\n    #{Pair := VarVersion} when VarVersion >= PrematchVersion ->\n      maybe_warn_underscored_var_repeat(Meta, Name, Kind, E),\n      NewUnused = var_used(Pair, Meta, VarVersion, Unused),\n      NewWrite = (Write /= false) andalso Write#{Pair => Version},\n      Var = {Name, [{version, VarVersion} | Meta], Kind},\n      {Var, S#elixir_ex{vars={Read, NewWrite}, unused={NewUnused, Version}}, E};\n\n    %% Variable is being overridden now\n    #{Pair := _} ->\n      NewUnused = var_unused(Pair, Meta, Version, Unused, true),\n      NewRead = Read#{Pair => Version},\n      NewWrite = (Write /= false) andalso Write#{Pair => Version},\n      Var = {Name, [{version, Version} | Meta], Kind},\n      {Var, S#elixir_ex{vars={NewRead, NewWrite}, unused={NewUnused, Version + 1}}, E};\n\n    %% Variable defined for the first time\n    _ ->\n      NewUnused = var_unused(Pair, Meta, Version, Unused, false),\n      NewRead = Read#{Pair => Version},\n      NewWrite = (Write /= false) andalso Write#{Pair => Version},\n      Var = {Name, [{version, Version} | Meta], Kind},\n      {Var, S#elixir_ex{vars={NewRead, NewWrite}, unused={NewUnused, Version + 1}}, E}\n  end;\n\nexpand({Name, Meta, Kind}, S, E) when is_atom(Name), is_atom(Kind) ->\n  #elixir_ex{vars={Read, _Write}, unused={Unused, Version}, prematch=Prematch} = S,\n  Pair = {Name, elixir_utils:var_context(Meta, Kind)},\n\n  Result =\n    case Read of\n      #{Pair := CurrentVersion} ->\n        case Prematch of\n          {Pre, _Cycle, {bitsize, Original}} ->\n            if\n              map_get(Pair, Pre) /= CurrentVersion ->\n                {ok, CurrentVersion};\n\n              is_map_key(Pair, Pre) ->\n                %% TODO: Remove me on Elixir 2.0\n                elixir_errors:file_warn(Meta, E, ?MODULE, {unpinned_bitsize_var, Name, Kind}),\n                {ok, CurrentVersion};\n\n              not is_map_key(Pair, Original) ->\n                {ok, CurrentVersion};\n\n              true ->\n                raise\n            end;\n\n          _ ->\n            {ok, CurrentVersion}\n        end;\n\n      _ ->\n        case E of\n          #{context := guard} -> raise;\n          #{} when S#elixir_ex.prematch =:= pin -> pin;\n          %% TODO: Remove fallback on on_undefined_variable\n          _ -> elixir_config:get(on_undefined_variable)\n        end\n    end,\n\n  case Result of\n    {ok, PairVersion} ->\n      maybe_warn_underscored_var_access(Meta, Name, Kind, E),\n      Var = {Name, [{version, PairVersion} | Meta], Kind},\n      {Var, S#elixir_ex{unused={var_used(Pair, Meta, PairVersion, Unused), Version}}, E};\n\n    Error ->\n      case lists:keyfind(if_undefined, 1, Meta) of\n        {if_undefined, apply} ->\n          expand({Name, Meta, []}, S, E);\n\n        %% TODO: Remove this clause on v2.0 as we will raise by default\n        {if_undefined, raise} ->\n          function_error(Meta, E, ?MODULE, {undefined_var, Name, Kind}),\n          {{Name, Meta, Kind}, S#elixir_ex{tainted_function=true}, E};\n\n        %% TODO: Remove this clause on v2.0 as we will no longer support warn\n        _ when Error == warn ->\n          elixir_errors:file_warn(Meta, E, ?MODULE, {undefined_var_to_call, Name}),\n          expand({Name, [{if_undefined, warn} | Meta], []}, S, E);\n\n        _ when Error == pin ->\n          function_error(Meta, E, ?MODULE, {undefined_var_pin, Name, Kind}),\n          {{Name, Meta, Kind}, S#elixir_ex{tainted_function=true}, E};\n\n        _ when Error == raise ->\n          SpanMeta =  elixir_env:calculate_span(Meta, Name),\n          function_error(SpanMeta, E, ?MODULE, {undefined_var, Name, Kind}),\n          {{Name, SpanMeta, Kind}, S#elixir_ex{tainted_function=true}, E}\n      end\n  end;\n\n%% Local calls\n\nexpand({Atom, Meta, Args}, S, E) when is_atom(Atom), is_list(Meta), is_list(Args) ->\n  assert_no_ambiguous_op(Atom, Meta, Args, S, E),\n\n  elixir_dispatch:dispatch_import(Meta, Atom, Args, S, E, fun\n    ({AR, AF}) ->\n      expand_remote(AR, Meta, AF, Meta, Args, S, elixir_env:prepare_write(S, E), E);\n\n    (local) ->\n      expand_local(Meta, Atom, Args, S, E)\n  end);\n\n%% Remote calls\n\nexpand({{'.', DotMeta, [Left, Right]}, Meta, Args}, S, E)\n    when (is_tuple(Left) orelse is_atom(Left)), is_atom(Right), is_list(Meta), is_list(Args) ->\n  {ELeft, SL, EL} = expand(Left, elixir_env:prepare_write(S, E), E),\n\n  elixir_dispatch:dispatch_require(Meta, ELeft, Right, Args, S, EL, fun(AR, AF) ->\n    expand_remote(AR, DotMeta, AF, Meta, Args, S, SL, EL)\n  end);\n\n%% Anonymous calls\n\nexpand({{'.', DotMeta, [Expr]}, Meta, Args}, S, E) when is_list(Args) ->\n  assert_no_match_or_guard_scope(Meta, \"anonymous call\", S, E),\n  {[EExpr | EArgs], SA, EA} = expand_args([Expr | Args], S, E),\n  {{{'.', DotMeta, [EExpr]}, Meta, EArgs}, SA, EA};\n\n%% Invalid calls\n\nexpand({_, Meta, Args} = Invalid, _S, E) when is_list(Meta) and is_list(Args) ->\n  file_error(Meta, E, ?MODULE, {invalid_call, Invalid});\n\n%% Literals\n\nexpand({Left, Right}, S, E) ->\n  {[ELeft, ERight], SE, EE} = expand_args([Left, Right], S, E),\n  {{ELeft, ERight}, SE, EE};\n\nexpand(List, S, #{context := match} = E) when is_list(List) ->\n  expand_list(List, fun expand/3, S, E, []);\n\nexpand(List, S, E) when is_list(List) ->\n  {EArgs, {SE, _}, EE} =\n    expand_list(List, fun expand_arg/3, {elixir_env:prepare_write(S), S}, E, []),\n\n  {EArgs, elixir_env:close_write(SE, S), EE};\n\nexpand(Zero, S, #{context := match} = E) when is_float(Zero), Zero == 0.0 ->\n  elixir_errors:file_warn([], E, ?MODULE, invalid_match_on_zero_float),\n  {Zero, S, E};\n\nexpand(Other, S, E) when is_number(Other); is_atom(Other); is_binary(Other) ->\n  {Other, S, E};\n\nexpand(Function, S, E) when is_function(Function) ->\n  case (erlang:fun_info(Function, type) == {type, external}) andalso\n        (erlang:fun_info(Function, env) == {env, []}) of\n    true ->\n      {elixir_quote:fun_to_quoted(Function), S, E};\n    false ->\n      file_error([{line, 0}], ?key(E, file), ?MODULE, {invalid_quoted_expr, Function})\n  end;\n\nexpand(Pid, S, E) when is_pid(Pid) ->\n  case ?key(E, function) of\n    nil ->\n      {Pid, S, E};\n    Function ->\n      %% TODO: Make me an error on v2.0\n      elixir_errors:file_warn([], E, ?MODULE, {invalid_pid_in_function, Pid, Function}),\n      {Pid, S, E}\n  end;\n\nexpand(Other, _S, E) ->\n  file_error([{line, 0}], ?key(E, file), ?MODULE, {invalid_quoted_expr, Other}).\n\n%% Helpers\n\nescape_env_entries(Meta, #elixir_ex{vars={Read, _}}, Env0) ->\n  Env1 = case Env0 of\n    #{function := nil} -> Env0;\n    _ -> Env0#{lexical_tracker := nil, tracers := []}\n  end,\n\n  Env1#{versioned_vars := escape_map(Read), line := ?line(Meta)}.\n\nescape_map(Map) -> {'%{}', [], lists:sort(maps:to_list(Map))}.\n\nexpand_multi_alias_call(Kind, Meta, Base, Refs, Opts, S, E) ->\n  {BaseRef, SB, EB} = expand_without_aliases_report(Base, S, E),\n\n  case is_atom(BaseRef) of\n    true ->\n      Fun = fun\n        ({'__aliases__', _, Ref}, SR, ER) ->\n          expand({Kind, Meta, [elixir_aliases:concat([BaseRef | Ref]), Opts]}, SR, ER);\n\n        (Ref, SR, ER) when is_atom(Ref) ->\n          expand({Kind, Meta, [elixir_aliases:concat([BaseRef, Ref]), Opts]}, SR, ER);\n\n        (Other, _SR, _ER) ->\n          file_error(Meta, E, ?MODULE, {expected_compile_time_module, Kind, Other})\n      end,\n\n      mapfold(Fun, SB, EB, Refs);\n\n    false ->\n      file_error(Meta, E, ?MODULE, {invalid_alias, Base})\n  end.\n\nresolve_super(Meta, Arity, E) ->\n  Module = assert_module_scope(Meta, super, E),\n  Function = assert_function_scope(Meta, super, E),\n\n  case Function of\n    {_, Arity} ->\n      {Kind, Name, SuperMeta} = elixir_overridable:super(Meta, Module, Function, E),\n      maybe_warn_deprecated_super_in_gen_server_callback(Meta, Function, SuperMeta, E),\n      {Kind, Name, SuperMeta};\n\n    _ ->\n      file_error(Meta, E, ?MODULE, wrong_number_of_args_for_super)\n  end.\n\nexpand_fn_capture(Meta, Arg, S, E) ->\n  case elixir_fn:capture(Meta, Arg, S, E) of\n    {{remote, Remote, Fun, Arity}, RequireMeta, DotMeta, SE, EE} ->\n      AttachedMeta = attach_runtime_module(Remote, RequireMeta, S, E),\n      {{'&', Meta, [{'/', [], [{{'.', DotMeta, [Remote, Fun]}, AttachedMeta, []}, Arity]}]}, SE, EE};\n    {{local, Fun, Arity}, _, _, _SE, #{function := nil}} ->\n      file_error(Meta, E, ?MODULE, {undefined_local_capture, Fun, Arity});\n    {{local, Fun, Arity}, LocalMeta, _, SE, EE} ->\n      {{'&', Meta, [{'/', [], [{Fun, LocalMeta, nil}, Arity]}]}, SE, EE};\n    {expand, Expr, SE, EE} ->\n      expand(Expr, SE, EE)\n  end.\n\nexpand_list([{'|', Meta, [_, _] = Args}], Fun, S, E, List) ->\n  {EArgs, SAcc, EAcc} = mapfold(Fun, S, E, Args),\n  expand_list([], Fun, SAcc, EAcc, [{'|', Meta, EArgs} | List]);\nexpand_list([H | T], Fun, S, E, List) ->\n  {EArg, SAcc, EAcc} = Fun(H, S, E),\n  expand_list(T, Fun, SAcc, EAcc, [EArg | List]);\nexpand_list([], _Fun, S, E, List) ->\n  {lists:reverse(List), S, E}.\n\nexpand_block([], Acc, _Meta, S, E) ->\n  {lists:reverse(Acc), S, E};\nexpand_block([H], Acc, Meta, S, E) ->\n  {EH, SE, EE} = expand(H, S, E),\n  expand_block([], [EH | Acc], Meta, SE, EE);\nexpand_block([{for, _, [_ | _]} = H | T], Acc, Meta, S, E) ->\n  {EH, SE, EE} = expand_for(H, S, E, false),\n  expand_block(T, [EH | Acc], Meta, SE, EE);\nexpand_block([{'=', _, [{'_', _, Ctx}, {for, _, [_ | _]} = H]}  | T], Acc, Meta, S, E) when is_atom(Ctx) ->\n  {EH, SE, EE} = expand_for(H, S, E, false),\n  expand_block(T, [EH | Acc], Meta, SE, EE);\nexpand_block([H | T], Acc, Meta, S, E) ->\n  {EH, SE, EE} = expand(H, S, E),\n\n  %% Note that checks rely on the code BEFORE expansion\n  %% instead of relying on Erlang checks.\n  %%\n  %% That's because expansion may generate useless\n  %% terms on their own (think compile time removed\n  %% logger calls) and we don't want to catch those.\n  %%\n  %% Or, similarly, the work is all in the expansion\n  %% (for example, to register something) and it is\n  %% simply returning something as replacement.\n  case is_useless_building(H, EH, Meta) of\n    {UselessMeta, UselessTerm} ->\n      elixir_errors:file_warn(UselessMeta, E, ?MODULE, UselessTerm);\n\n    false ->\n      ok\n  end,\n\n  expand_block(T, [EH | Acc], Meta, SE, EE).\n\n%% Note that we don't handle atoms on purpose. They are common\n%% when unquoting AST and it is unlikely that we would catch\n%% bugs as we don't do binary operations on them like in\n%% strings or numbers.\nis_useless_building(H, _, Meta) when is_binary(H); is_number(H) ->\n  {Meta, {useless_literal, H}};\nis_useless_building({'@', Meta, [{Var, _, Ctx}]}, _, _) when is_atom(Ctx); Ctx == [] ->\n  {Meta, {useless_attr, Var}};\nis_useless_building({Var, Meta, Ctx}, {Var, _, Ctx}, _) when is_atom(Ctx) ->\n  {Meta, {useless_var, Var}};\nis_useless_building(_, _, _) ->\n  false.\n\n%% Variables in arguments are not propagated from one\n%% argument to the other. For instance:\n%%\n%%   x = 1\n%%   foo(x = x + 2, x)\n%%   x\n%%\n%% Should be the same as:\n%%\n%%   foo(3, 1)\n%%   3\n%%\n%% However, lexical information is.\nexpand_arg(Arg, Acc, E) when is_number(Arg); is_atom(Arg); is_binary(Arg); is_pid(Arg) ->\n  {Arg, Acc, E};\nexpand_arg(Arg, {Acc, S}, E) ->\n  {EArg, SAcc, EAcc} = expand(Arg, elixir_env:reset_read(Acc, S), E),\n  {EArg, {SAcc, S}, EAcc}.\n\nexpand_args([Arg], S, E) ->\n  {EArg, SE, EE} = expand(Arg, S, E),\n  {[EArg], SE, EE};\nexpand_args(Args, S, #{context := match} = E) ->\n  mapfold(fun expand/3, S, E, Args);\nexpand_args(Args, S, E) ->\n  {EArgs, {SA, _}, EA} = mapfold(fun expand_arg/3, {elixir_env:prepare_write(S), S}, E, Args),\n  {EArgs, elixir_env:close_write(SA, S), EA}.\n\nmapfold(Fun, S, E, List) ->\n  mapfold(Fun, S, E, List, []).\n\nmapfold(Fun, S, E, [H | T], Acc) ->\n  {RH, RS, RE} = Fun(H, S, E),\n  mapfold(Fun, RS, RE, T, [RH | Acc]);\nmapfold(_Fun, S, E, [], Acc) ->\n  {lists:reverse(Acc), S, E}.\n\n%% Match/var helpers\n\nvar_unused({_, Kind} = Pair, Meta, Version, Unused, Override) ->\n  case (Kind == nil) andalso should_warn(Meta) of\n    true -> Unused#{{Pair, Version} => {Meta, Override}};\n    false -> Unused\n  end.\n\nvar_used({_, Kind} = Pair, Meta, Version, Unused) ->\n  KeepUnused = lists:keymember(keep_unused, 1, Meta),\n\n  if\n    KeepUnused -> Unused;\n    is_atom(Kind) -> Unused#{{Pair, Version} => false};\n    true -> Unused\n  end.\n\nmaybe_warn_underscored_var_repeat(Meta, Name, Kind, E) ->\n  case should_warn(Meta) andalso atom_to_list(Name) of\n    \"_\" ++ _ ->\n      elixir_errors:file_warn(Meta, E, ?MODULE, {underscored_var_repeat, Name, Kind});\n    _ ->\n      ok\n  end.\n\nmaybe_warn_underscored_var_access(Meta, Name, Kind, E) ->\n  case (Kind == nil) andalso should_warn(Meta) andalso atom_to_list(Name) of\n    \"_\" ++ _ ->\n      elixir_errors:file_warn(Meta, E, ?MODULE, {underscored_var_access, Name});\n    _ ->\n      ok\n  end.\n\n%% TODO: Remove this on Elixir v2.0 and make all GenServer callbacks optional\nmaybe_warn_deprecated_super_in_gen_server_callback(Meta, Function, SuperMeta, E) ->\n  case lists:keyfind(context, 1, SuperMeta) of\n    {context, 'Elixir.GenServer'} ->\n      case Function of\n        {child_spec, 1} ->\n          ok;\n\n        _ ->\n          elixir_errors:file_warn(Meta, E, ?MODULE, {super_in_genserver, Function})\n      end;\n\n    _ ->\n      ok\n  end.\n\nshould_warn(Meta) ->\n  lists:keyfind(generated, 1, Meta) /= {generated, true}.\n\n%% Case\n\nexpand_case(Meta, Expr, Opts, S, E) ->\n  {EExpr, SE, EE} = expand(Expr, S, E),\n\n  ROpts =\n    case lists:member({optimize_boolean, true}, Meta) andalso elixir_utils:returns_boolean(EExpr) of\n      true -> rewrite_case_clauses(Opts);\n      false -> Opts\n    end,\n\n  {EOpts, SO, EO} = elixir_clauses:'case'(Meta, ROpts, SE, EE),\n  {{'case', Meta, [EExpr, EOpts]}, SO, EO}.\n\nrewrite_case_clauses([{do, [\n  {'->', FalseMeta, [\n    [{'when', _, [{Var, _, ?kernel}, {{'.', _, ['erlang', 'orelse']}, _, [\n      {{'.', _, ['erlang', '=:=']}, _, [{Var, _, ?kernel}, false]},\n      {{'.', _, ['erlang', '=:=']}, _, [{Var, _, ?kernel}, nil]}\n    ]}]}],\n    FalseExpr\n  ]},\n  {'->', TrueMeta, [\n    [{'_', _, _}],\n    TrueExpr\n  ]}\n]}]) ->\n  rewrite_case_clauses(FalseMeta, FalseExpr, TrueMeta, TrueExpr);\n\nrewrite_case_clauses([{do, [\n  {'->', FalseMeta, [[false], FalseExpr]},\n  {'->', TrueMeta, [[true], TrueExpr]} | _\n]}]) ->\n  rewrite_case_clauses(FalseMeta, FalseExpr, TrueMeta, TrueExpr);\n\nrewrite_case_clauses(Opts) ->\n  Opts.\n\nrewrite_case_clauses(FalseMeta, FalseExpr, TrueMeta, TrueExpr) ->\n  [{do, [\n    {'->', FalseMeta, [[false], FalseExpr]},\n    {'->', TrueMeta, [[true], TrueExpr]}\n  ]}].\n\n%% Comprehensions\n\nexpand_for({for, Meta, [_ | _] = Args}, S, E, Return) ->\n  assert_no_match_or_guard_scope(Meta, \"for\", S, E),\n  {Cases, Block} = elixir_utils:split_opts(Args),\n  validate_opts(Meta, for, [do, into, uniq, reduce], Block, E),\n\n  {Expr, Opts} =\n    case lists:keytake(do, 1, Block) of\n      {value, {do, Do}, DoOpts} ->\n        {Do, DoOpts};\n      false ->\n        file_error(Meta, E, ?MODULE, {missing_option, for, [do]})\n    end,\n\n  {EOpts, SO, EO} = expand(Opts, elixir_env:reset_unused_vars(S), E),\n  {ECases, SC, EC} = mapfold(fun expand_for_generator/3, SO, EO, Cases),\n  assert_generator_start(Meta, ECases, E),\n\n  {{EExpr, SE, EE}, NormalizedOpts} =\n    case validate_for_options(EOpts, false, false, false, Return, Meta, E, []) of\n      {ok, MaybeReduce, NOpts} -> {expand_for_do_block(Meta, Expr, SC, EC, MaybeReduce), NOpts};\n      {error, Error} -> {file_error(Meta, E, ?MODULE, Error), EOpts}\n    end,\n\n  {{for, Meta, ECases ++ [[{do, EExpr} | NormalizedOpts]]},\n   elixir_env:merge_and_check_unused_vars(SE, S, EE),\n   E}.\n\nvalidate_for_options([{into, _} = Pair | Opts], _Into, Uniq, Reduce, Return, Meta, E, Acc) ->\n  validate_for_options(Opts, Pair, Uniq, Reduce, Return, Meta, E, [Pair | Acc]);\nvalidate_for_options([{uniq, Boolean} = Pair | Opts], Into, _Uniq, Reduce, Return, Meta, E, Acc) when is_boolean(Boolean) ->\n  validate_for_options(Opts, Into, Pair, Reduce, Return, Meta, E, [Pair | Acc]);\nvalidate_for_options([{uniq, Value} | _], _, _, _, _, _, _, _) ->\n  {error, {for_invalid_uniq, Value}};\nvalidate_for_options([{reduce, _} = Pair | Opts], Into, Uniq, _Reduce, Return, Meta, E, Acc) ->\n  validate_for_options(Opts, Into, Uniq, Pair, Return, Meta, E, [Pair | Acc]);\nvalidate_for_options([], Into, Uniq, {reduce, _}, _Return, _Meta, _E, _Acc) when Into /= false; Uniq /= false ->\n  {error, for_conflicting_reduce_into_uniq};\nvalidate_for_options([], _Into = false, Uniq, Reduce = false, Return = true, Meta, E, Acc) ->\n  Pair = {into, []},\n  validate_for_options([Pair], Pair, Uniq, Reduce, Return, Meta, E, Acc);\nvalidate_for_options([], Into = false, {uniq, true}, Reduce = false, Return = false, Meta, E, Acc) ->\n  elixir_errors:file_warn(Meta, E, ?MODULE, for_with_unused_uniq),\n  AccWithoutUniq = lists:keydelete(uniq, 1, Acc),\n  validate_for_options([], Into, false, Reduce, Return, Meta, E, AccWithoutUniq);\nvalidate_for_options([], _Into, _Uniq, Reduce, _Return, _Meta, _E, Acc) ->\n  {ok, Reduce, lists:reverse(Acc)}.\n\nexpand_for_do_block(Meta, [{'->', _, _} | _], _S, E, false) ->\n  file_error(Meta, E, ?MODULE, for_without_reduce_bad_block);\nexpand_for_do_block(_Meta, Expr, S, E, false) ->\n  expand(Expr, S, E);\nexpand_for_do_block(Meta, [{'->', _, _} | _] = Clauses, S, E, {reduce, _}) ->\n  Transformer = fun\n    ({_, _, [[{'when', _, [_, _, _ | _]}], _]}, _) ->\n      file_error(Meta, E, ?MODULE, for_with_reduce_bad_block);\n\n    ({_, _, [[_], _]} = Clause, SA) ->\n      SReset = elixir_env:reset_unused_vars(SA),\n\n      {EClause, SAcc, EAcc} =\n        elixir_clauses:clause(Meta, fn, fun elixir_clauses:head/4, Clause, SReset, E),\n\n      {EClause, elixir_env:merge_and_check_unused_vars(SAcc, SA, EAcc)};\n\n    (_, _) ->\n      file_error(Meta, E, ?MODULE, for_with_reduce_bad_block)\n  end,\n\n  {Do, SA} = lists:mapfoldl(Transformer, S, Clauses),\n  {Do, SA, E};\nexpand_for_do_block(Meta, _Expr, _S, E, {reduce, _}) ->\n  file_error(Meta, E, ?MODULE, for_with_reduce_bad_block).\n\n%% Locals\n\nassert_no_ambiguous_op(Name, Meta, [Arg], S, E) ->\n  case lists:keyfind(ambiguous_op, 1, Meta) of\n    {ambiguous_op, Kind} ->\n      Pair = {Name, Kind},\n      case S#elixir_ex.vars of\n        {#{Pair := _}, _} ->\n          file_error(Meta, E, ?MODULE, {op_ambiguity, Name, Arg});\n        _ ->\n          ok\n      end;\n    _ ->\n      ok\n  end;\nassert_no_ambiguous_op(_Atom, _Meta, _Args, _S, _E) ->\n  ok.\n\nexpand_local(Meta, Name, Args, S, #{function := Function, context := Context} = E)\n    when Function /= nil ->\n  %% In case we have the wrong context, we log a module error\n  %% so we can print multiple entries at the same time.\n  case Context of\n    match ->\n      module_error(Meta, E, ?MODULE, {invalid_local_invocation, \"match\", {Name, Meta, Args}});\n\n    guard ->\n      module_error(Meta, E, ?MODULE, {invalid_local_invocation, elixir_utils:guard_info(S), {Name, Meta, Args}});\n\n    nil ->\n      elixir_env:trace({local_function, Meta, Name, length(Args)}, E)\n  end,\n\n  {EArgs, SA, EA} = expand_args(Args, S, E),\n  {{Name, Meta, EArgs}, SA, EA};\nexpand_local(Meta, Name, Args, _S, #{function := nil} = E) ->\n  file_error(Meta, E, ?MODULE, {undefined_function, Name, Args}).\n\n%% Remote\n\nexpand_remote(Receiver, DotMeta, Right, Meta, Args, S, SL, #{context := Context} = E)\n    when is_atom(Receiver) or is_tuple(Receiver) ->\n  if\n    Context =:= guard, is_tuple(Receiver) ->\n      (lists:keyfind(no_parens, 1, Meta) /= {no_parens, true}) andalso\n        function_error(Meta, E, ?MODULE, {parens_map_lookup, Receiver, Right, elixir_utils:guard_info(S)}),\n\n      {{{'.', DotMeta, [Receiver, Right]}, Meta, []}, SL, E};\n\n    Context =:= nil ->\n      AttachedMeta = attach_runtime_module(Receiver, Meta, S, E),\n      {EArgs, {SA, _}, EA} = mapfold(fun expand_arg/3, {SL, S}, E, Args),\n\n      SA#elixir_ex.tainted_function andalso is_atom(Receiver) andalso\n        (not is_loaded_and_exported(Receiver, Right, Args)) andalso\n        elixir_errors:file_warn(Meta, E, ?MODULE, {undefined_function, Receiver, Right, length(Args)}),\n\n      Rewritten = elixir_rewrite:rewrite(Receiver, DotMeta, Right, AttachedMeta, EArgs),\n      {Rewritten, elixir_env:close_write(SA, S), EA};\n\n    true ->\n      case {Receiver, Right, Args} of\n        {erlang, '+', [Arg]} when is_number(Arg) -> {+Arg, SL, E};\n        {erlang, '-', [Arg]} when is_number(Arg) -> {-Arg, SL, E};\n        _ ->\n          {EArgs, SA, EA} = mapfold(fun expand/3, SL, E, Args),\n\n          case elixir_rewrite:Context(Receiver, DotMeta, Right, Meta, EArgs, S) of\n            {ok, Rewritten} -> {Rewritten, SA, EA};\n            {error, Error} -> file_error(Meta, E, elixir_rewrite, Error)\n          end\n      end\n  end;\nexpand_remote(Receiver, DotMeta, Right, Meta, Args, _, _, E) ->\n  Call = {{'.', DotMeta, [Receiver, Right]}, Meta, Args},\n  file_error(Meta, E, ?MODULE, {invalid_call, Call}).\n\nis_loaded_and_exported(Receiver, Fun, Args) ->\n  (code:ensure_loaded(Receiver) =:= {module, Receiver}) andalso\n    erlang:function_exported(Receiver, Fun, length(Args)).\n\nattach_runtime_module(Receiver, Meta, S, _E) ->\n  case lists:member(Receiver, S#elixir_ex.runtime_modules) of\n    true -> [{runtime_module, true} | Meta];\n    false -> Meta\n  end.\n\n%% Lexical helpers\n\nexpand_opts(Meta, Kind, Allowed, Opts, S, E) ->\n  {EOpts, SE, EE} = expand(Opts, S, E),\n  validate_opts(Meta, Kind, Allowed, EOpts, EE),\n  {EOpts, SE, EE}.\n\nvalidate_opts(Meta, Kind, Allowed, Opts, E) when is_list(Opts) ->\n  [begin\n    file_error(Meta, E, ?MODULE, {unsupported_option, Kind, Key})\n  end || {Key, _} <- Opts, not lists:member(Key, Allowed)];\n\nvalidate_opts(Meta, Kind, _Allowed, Opts, E) ->\n  file_error(Meta, E, ?MODULE, {options_are_not_keyword, Kind, Opts}).\n\nno_alias_opts(Opts) when is_list(Opts) ->\n  case lists:keyfind(as, 1, Opts) of\n    {as, As} -> lists:keystore(as, 1, Opts, {as, no_alias_expansion(As)});\n    false -> Opts\n  end;\nno_alias_opts(Opts) -> Opts.\n\nno_alias_expansion({'__aliases__', _, [H | T]}) when is_atom(H) ->\n  elixir_aliases:concat([H | T]);\nno_alias_expansion(Other) ->\n  Other.\n\nshould_warn(_Meta, _Opts, #{lexical_tracker := nil}) ->\n  false;\nshould_warn(Meta, Opts, #{lexical_tracker := Pid}) ->\n  case lists:keyfind(warn, 1, Opts) of\n    {warn, false} -> false;\n    {warn, true} -> Pid;\n    false ->\n      case lists:keymember(context, 1, Meta) of\n        true -> false;\n        false -> Pid\n      end\n  end.\n\n%% Aliases\n\nalias(Meta, Ref, IncludeByDefault, Opts, E) ->\n  case elixir_aliases:alias(Meta, Ref, IncludeByDefault, Opts, E, true) of\n    {ok, New, EA} -> {ok, New, EA};\n    {error, Reason} -> elixir_errors:file_error(Meta, E, elixir_aliases, Reason)\n  end.\n\nexpand_without_aliases_report({'__aliases__', _, _} = Alias, S, E) ->\n  expand_aliases(Alias, S, E, false);\nexpand_without_aliases_report(Other, S, E) ->\n  expand(Other, S, E).\n\nexpand_aliases({'__aliases__', Meta, List} = Alias, S, E, Report) ->\n  case elixir_aliases:expand_or_concat(Meta, List, E, true) of\n    Receiver when is_atom(Receiver) ->\n      if\n        Receiver =:= 'Elixir.True'; Receiver =:= 'Elixir.False'; Receiver =:= 'Elixir.Nil' ->\n          elixir_errors:file_warn(Meta, E, ?MODULE, {commonly_mistaken_alias, Receiver});\n        true ->\n          ok\n      end,\n      Report andalso elixir_env:trace({alias_reference, Meta, Receiver}, E),\n      {Receiver, S, E};\n\n    [Head | Tail] ->\n      {EHead, SA, EA} = expand(Head, S, E),\n\n      case is_atom(EHead) of\n        true ->\n          Receiver = elixir_aliases:concat([EHead | Tail]),\n          Report andalso elixir_env:trace({alias_reference, Meta, Receiver}, E),\n          {Receiver, SA, EA};\n\n        false ->\n          file_error(Meta, E, ?MODULE, {invalid_alias, Alias})\n      end\n  end.\n\n%% Comprehensions\n\nexpand_for_generator({'<-', Meta, [Left, Right]}, S, E) ->\n  {ERight, SR, ER} = expand(Right, S, E),\n  SM = elixir_env:reset_read(SR, S),\n  {[ELeft], SL, EL} = elixir_clauses:head(Meta, [Left], SM, ER),\n  {{'<-', Meta, [ELeft, ERight]}, SL, EL};\nexpand_for_generator({'<<>>', Meta, Args} = X, S, E) when is_list(Args) ->\n  case elixir_utils:split_last(Args) of\n    {LeftStart, {'<-', OpMeta, [LeftEnd, Right]}} ->\n      {ERight, SR, ER} = expand(Right, S, E),\n      SM = elixir_env:reset_read(SR, S),\n      {ELeft, SL, EL} = elixir_clauses:match(fun(BArg, BS, BE) ->\n        elixir_bitstring:expand(Meta, BArg, BS, BE, true)\n      end, Meta, LeftStart ++ [LeftEnd], SM, SM, ER),\n      {{'<<>>', Meta, [{'<-', OpMeta, [ELeft, ERight]}]}, SL, EL};\n    _ ->\n      expand(X, S, E)\n  end;\nexpand_for_generator(X, S, E) ->\n  expand(X, S, E).\n\nassert_generator_start(_, [{'<-', _, [_, _]} | _], _) ->\n  ok;\nassert_generator_start(_, [{'<<>>', _, [{'<-', _, [_, _]}]} | _], _) ->\n  ok;\nassert_generator_start(Meta, _, E) ->\n  elixir_errors:file_error(Meta, E, ?MODULE, for_generator_start).\n\n%% Assertions\n\nassert_module_scope(Meta, Kind, #{module := nil, file := File}) ->\n  file_error(Meta, File, ?MODULE, {invalid_expr_in_scope, \"module\", Kind});\nassert_module_scope(_Meta, _Kind, #{module:=Module}) -> Module.\n\nassert_function_scope(Meta, Kind, #{function := nil, file := File}) ->\n  file_error(Meta, File, ?MODULE, {invalid_expr_in_scope, \"function\", Kind});\nassert_function_scope(_Meta, _Kind, #{function := Function}) -> Function.\n\nassert_no_match_or_guard_scope(Meta, Kind, S, E) ->\n  assert_no_match_scope(Meta, Kind, E),\n  assert_no_guard_scope(Meta, Kind, S, E).\nassert_no_match_scope(Meta, Kind, #{context := match, file := File}) ->\n  file_error(Meta, File, ?MODULE, {invalid_pattern_in_match, Kind});\nassert_no_match_scope(_Meta, _Kind, _E) -> ok.\nassert_no_guard_scope(Meta, Kind, S, #{context := guard, file := File}) ->\n  Key =\n    case S of\n      #elixir_ex{prematch={_, _, {bitsize, _}}}  -> invalid_expr_in_bitsize;\n      _ -> invalid_expr_in_guard\n    end,\n  file_error(Meta, File, ?MODULE, {Key, Kind});\nassert_no_guard_scope(_Meta, _Kind, _S, _E) -> ok.\n\n%% Here we look into the Clauses \"optimistically\", that is, we don't check for\n%% multiple \"do\"s and similar stuff. After all, the error we're gonna give here\n%% is just a friendlier version of the \"undefined variable _\" error that we\n%% would raise if we found a \"_ -> ...\" clause in a \"cond\". For this reason, if\n%% Clauses has a bad shape, we just do nothing and let future functions catch\n%% this.\nassert_no_underscore_clause_in_cond([{do, Clauses}], E) when is_list(Clauses) ->\n  case lists:last(Clauses) of\n    {'->', Meta, [[{'_', _, Atom}], _]} when is_atom(Atom) ->\n      file_error(Meta, E, ?MODULE, underscore_in_cond);\n    _Other ->\n      ok\n  end;\nassert_no_underscore_clause_in_cond(_Other, _E) ->\n  ok.\n\n%% Errors\n\nformat_error({undefined_function, Module, Fun, Arity}) ->\n  Opts = [{module, Module}, {function, Fun}, {arity, Arity}],\n  Exception = 'Elixir.UndefinedFunctionError':exception(Opts),\n  {BlamedException, _} = 'Elixir.UndefinedFunctionError':blame(Exception, []),\n  'Elixir.UndefinedFunctionError':message(BlamedException);\nformat_error(invalid_match_on_zero_float) ->\n  \"pattern matching on 0.0 is equivalent to matching only on +0.0. Instead you must match on +0.0 or -0.0\";\nformat_error({useless_literal, Term}) ->\n  io_lib:format(\"code block contains unused literal ~ts \"\n                \"(remove the literal or assign it to _ to avoid warnings)\",\n                ['Elixir.Macro':to_string(Term)]);\nformat_error({useless_var, Var}) ->\n  io_lib:format(\"variable ~ts in code block has no effect as it is never returned \"\n                \"(remove the variable or assign it to _ to avoid warnings)\",\n                [Var]);\nformat_error({useless_attr, Attr}) ->\n  io_lib:format(\"module attribute @~ts in code block has no effect as it is never returned \"\n                \"(remove the attribute or assign it to _ to avoid warnings)\",\n                [Attr]);\nformat_error({missing_option, Construct, Opts}) when is_list(Opts) ->\n  StringOpts = lists:map(fun(Opt) -> [$: | atom_to_list(Opt)] end, Opts),\n  io_lib:format(\"missing ~ts option in \\\"~ts\\\"\", [string:join(StringOpts, \"/\"), Construct]);\nformat_error({invalid_args, Construct}) ->\n  io_lib:format(\"invalid arguments for \\\"~ts\\\"\", [Construct]);\nformat_error({for_invalid_uniq, Value}) ->\n  io_lib:format(\":uniq option for comprehensions only accepts a boolean, got: ~ts\", ['Elixir.Macro':to_string(Value)]);\nformat_error(for_conflicting_reduce_into_uniq) ->\n  \"cannot use :reduce alongside :into/:uniq in comprehension\";\nformat_error(for_with_reduce_bad_block) ->\n  \"when using :reduce with comprehensions, the do block must be written using acc -> expr clauses, where each clause expects the accumulator as a single argument\";\nformat_error(for_without_reduce_bad_block) ->\n  \"the do block was written using acc -> expr clauses but the :reduce option was not given\";\nformat_error(for_generator_start) ->\n  \"for comprehensions must start with a generator\";\nformat_error(for_with_unused_uniq) ->\n  \"the :uniq option has no effect since the result of the for comprehension is not used\";\nformat_error(unhandled_arrow_op) ->\n  \"misplaced operator ->\\n\\n\"\n  \"This typically means invalid syntax or a macro is not available in scope\";\nformat_error(unhandled_cons_op) ->\n  \"misplaced operator |/2\\n\\n\"\n  \"The | operator is typically used between brackets to mark the tail of a list:\\n\\n\"\n  \"    [head | tail]\\n\"\n  \"    [head, middle, ... | tail]\\n\\n\"\n  \"It is also used to update maps and structs, via the %{map | key: value} notation, \"\n  \"and in typespecs, such as @type and @spec, to express the union of two types\";\nformat_error(unhandled_type_op) ->\n  \"misplaced operator ::/2\\n\\n\"\n  \"The :: operator is typically used in bitstrings to specify types and sizes of segments:\\n\\n\"\n  \"    <<size::32-integer, letter::utf8, rest::binary>>\\n\\n\"\n  \"It is also used in typespecs, such as @type and @spec, to describe inputs and outputs\";\nformat_error(as_in_multi_alias_call) ->\n  \":as option is not supported by multi-alias call\";\nformat_error({commonly_mistaken_alias, Ref}) ->\n  Module = 'Elixir.Macro':to_string(Ref),\n  io_lib:format(\"reserved alias \\\"~ts\\\" expands to the atom :\\\"Elixir.~ts\\\". Perhaps you meant to write \\\"~ts\\\" instead?\", [Module, Module, string:casefold(Module)]);\nformat_error({expected_compile_time_module, Kind, GivenTerm}) ->\n  io_lib:format(\"invalid argument for ~ts, expected a compile time atom or alias, got: ~ts\",\n                [Kind, 'Elixir.Macro':to_string(GivenTerm)]);\nformat_error({unquote_outside_quote, Unquote}) ->\n  %% Unquote can be \"unquote\" or \"unquote_splicing\".\n  io_lib:format(\"~p called outside quote\", [Unquote]);\nformat_error({invalid_bind_quoted_for_quote, BQ}) ->\n  io_lib:format(\"invalid :bind_quoted for quote, expected a keyword list of variable names, got: ~ts\",\n                ['Elixir.Macro':to_string(BQ)]);\nformat_error(wrong_number_of_args_for_super) ->\n  \"super must be called with the same number of arguments as the current definition\";\nformat_error({invalid_arg_for_pin, Arg}) ->\n  io_lib:format(\"invalid argument for unary operator ^, expected an existing variable, got: ^~ts\",\n                ['Elixir.Macro':to_string(Arg)]);\nformat_error({pin_outside_of_match, Arg}) ->\n  io_lib:format(\n    \"misplaced operator ^~ts\\n\\n\"\n    \"The pin operator ^ is supported only inside matches or inside custom macros. \"\n    \"Make sure you are inside a match or all necessary macros have been required\",\n    ['Elixir.Macro':to_string(Arg)]\n  );\nformat_error(unbound_underscore) ->\n  \"invalid use of _. _ can only be used inside patterns to ignore values and cannot be used in expressions. Make sure you are inside a pattern or change it accordingly\";\nformat_error({undefined_var, Name, Kind}) ->\n  io_lib:format(\"undefined variable ~ts\", [elixir_utils:var_info(Name, Kind)]);\nformat_error({undefined_var_pin, Name, Kind}) ->\n  Message = \"undefined variable ^~ts. No variable ~ts has been defined before the current pattern\",\n  io_lib:format(Message, [Name, elixir_utils:var_info(Name, Kind)]);\nformat_error(underscore_in_cond) ->\n  \"invalid use of _ inside \\\"cond\\\". If you want the last clause to always match, \"\n    \"you probably meant to use: true ->\";\nformat_error({invalid_pattern_in_match, Kind}) ->\n  io_lib:format(\"invalid pattern in match, ~ts is not allowed in matches\", [Kind]);\nformat_error({invalid_expr_in_scope, Scope, Kind}) ->\n  io_lib:format(\"cannot invoke ~ts outside ~ts\", [Kind, Scope]);\nformat_error({invalid_expr_in_guard, Kind}) ->\n  Message =\n    \"invalid expression in guards, ~ts is not allowed in guards. To learn more about \"\n    \"guards, visit: https://hexdocs.pm/elixir/patterns-and-guards.html#guards\",\n  io_lib:format(Message, [Kind]);\nformat_error({invalid_expr_in_bitsize, Kind}) ->\n  Message =\n    \"~ts is not allowed inside a bitstring size specifier. The size specifier in matches works like guards. \"\n    \"To learn more about guards, visit: https://hexdocs.pm/elixir/patterns-and-guards.html#guards\",\n  io_lib:format(Message, [Kind]);\nformat_error({invalid_alias, Expr}) ->\n  Message =\n    \"invalid alias: \\\"~ts\\\". If you wanted to define an alias, an alias must expand \"\n    \"to an atom at compile time but it did not, you may use Module.concat/2 to build \"\n    \"it at runtime. If instead you wanted to invoke a function or access a field, \"\n    \"wrap the function or field name in double quotes\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Expr)]);\nformat_error({op_ambiguity, Name, Arg}) ->\n  NameString = atom_to_binary(Name),\n  ArgString = 'Elixir.Macro':to_string(Arg),\n\n  Message =\n    \"\\\"~ts ~ts\\\" looks like a function call but there is a variable named \\\"~ts\\\". \"\n    \"If you want to perform a function call, use parentheses:\\n\"\n    \"\\n\"\n    \"    ~ts(~ts)\\n\"\n    \"\\n\"\n    \"If you want to perform an operation on the variable ~ts, use spaces \"\n    \"around the unary operator\",\n  io_lib:format(Message, [NameString, ArgString, NameString, NameString, ArgString, NameString]);\nformat_error({invalid_clauses, Name}) ->\n  Message =\n    \"the function \\\"~ts\\\" cannot handle clauses with the -> operator because it is not a macro. \"\n    \"Please make sure you are invoking the proper name and that it is a macro\",\n  io_lib:format(Message, [Name]);\nformat_error({invalid_call, Call}) ->\n  io_lib:format(\"invalid call ~ts\", ['Elixir.Macro':to_string(Call)]);\nformat_error({invalid_quoted_expr, Expr}) ->\n  Message =\n    \"invalid quoted expression: ~ts\\n\\n\"\n    \"Please make sure your quoted expressions are made of valid AST nodes. \"\n    \"If you would like to introduce a value into the AST, such as a four-element \"\n    \"tuple or a map, make sure to call Macro.escape/1 before\",\n  io_lib:format(Message, ['Elixir.Kernel':inspect(Expr, [])]);\nformat_error({invalid_local_invocation, Context, {Name, _, Args} = Call}) ->\n  Message =\n    \"cannot find or invoke local ~ts/~B inside a ~ts. \"\n    \"Only macros can be invoked inside a ~ts and they must be defined before their invocation. Called as: ~ts\",\n  io_lib:format(Message, [Name, length(Args), Context, Context, 'Elixir.Macro':to_string(Call)]);\nformat_error({invalid_pid_in_function, Pid, {Name, Arity}}) ->\n  io_lib:format(\"cannot compile PID ~ts inside quoted expression for function ~ts/~B\",\n                ['Elixir.Kernel':inspect(Pid, []), Name, Arity]);\nformat_error({unsupported_option, Kind, Key}) ->\n  io_lib:format(\"unsupported option ~ts given to ~s\",\n                ['Elixir.Macro':to_string(Key), Kind]);\nformat_error({options_are_not_keyword, Kind, Opts}) ->\n  io_lib:format(\"invalid options for ~s, expected a keyword list, got: ~ts\",\n                [Kind, 'Elixir.Macro':to_string(Opts)]);\nformat_error({undefined_function, Name, Args}) ->\n  io_lib:format(\"undefined function ~ts/~B (there is no such import)\", [Name, length(Args)]);\nformat_error({unpinned_bitsize_var, Name, Kind}) ->\n  io_lib:format(\"the variable ~ts is accessed inside size(...) of a bitstring \"\n                \"but it was defined outside of the match. You must precede it with the \"\n                \"pin operator\", [elixir_utils:var_info(Name, Kind)]);\nformat_error({underscored_var_repeat, Name, Kind}) ->\n  io_lib:format(\"the underscored variable ~ts appears more than once in a \"\n                \"match. This means the pattern will only match if all \\\"~ts\\\" bind \"\n                \"to the same value. If this is the intended behaviour, please \"\n                \"remove the leading underscore from the variable name, otherwise \"\n                \"give the variables different names\", [elixir_utils:var_info(Name, Kind), Name]);\nformat_error({underscored_var_access, Name}) ->\n  io_lib:format(\"the underscored variable \\\"~ts\\\" is used after being set. \"\n                \"A leading underscore indicates that the value of the variable \"\n                \"should be ignored. If this is intended please rename the \"\n                \"variable to remove the underscore\", [Name]);\nformat_error({nested_comparison, CompExpr}) ->\n  String = 'Elixir.Macro':to_string(CompExpr),\n  io_lib:format(\"Elixir does not support nested comparisons. Something like\\n\\n\"\n                \"     x < y < z\\n\\n\"\n                \"is equivalent to\\n\\n\"\n                \"     (x < y) < z\\n\\n\"\n                \"which ultimately compares z with the boolean result of (x < y). \"\n                \"Instead, consider joining together each comparison segment with an \\\"and\\\", for example,\\n\\n\"\n                \"     x < y and y < z\\n\\n\"\n                \"You wrote: ~ts\", [String]);\nformat_error({undefined_local_capture, Fun, Arity}) ->\n  io_lib:format(\"undefined function ~ts/~B (there is no such import)\", [Fun, Arity]);\nformat_error(caller_not_allowed) ->\n  \"__CALLER__ is available only inside defmacro and defmacrop\";\nformat_error(stacktrace_not_allowed) ->\n  \"__STACKTRACE__ is available only inside catch and rescue clauses of try expressions\";\nformat_error({undefined_var_to_call, Name}) ->\n  io_lib:format(\"variable \\\"~ts\\\" does not exist and is being expanded to \\\"~ts()\\\",\"\n                \" please use parentheses to remove the ambiguity or change the variable name\", [Name, Name]);\nformat_error({parens_map_lookup, Map, Field, Context}) ->\n  io_lib:format(\"cannot invoke remote function inside a ~ts. \"\n                \"If you want to do a map lookup instead, please remove parens from ~ts.~ts()\",\n                [Context, 'Elixir.Macro':to_string(Map), Field]);\nformat_error({super_in_genserver, {Name, Arity}}) ->\n  io_lib:format(\"calling super for GenServer callback ~ts/~B is deprecated\", [Name, Arity]);\nformat_error('__cursor__') ->\n  \"reserved special form __cursor__ cannot be expanded, it is used exclusively to annotate ASTs\"."
  },
  {
    "path": "lib/elixir/src/elixir_fn.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_fn).\n-export([capture/4, expand/4, format_error/1]).\n-import(elixir_errors, [file_error/4]).\n-include(\"elixir.hrl\").\n\n%% Anonymous functions\n\nexpand(Meta, Clauses, S, E) when is_list(Clauses) ->\n  Transformer = fun({_, _, [Left, _Right]} = Clause, SA) ->\n    case lists:any(fun is_invalid_arg/1, Left) of\n      true ->\n        file_error(Meta, E, ?MODULE, defaults_in_args);\n      false ->\n        SReset = elixir_env:reset_unused_vars(SA),\n\n        {EClause, SAcc, EAcc} =\n          elixir_clauses:clause(Meta, fn, fun elixir_clauses:head/4, Clause, SReset, E),\n\n        {EClause, elixir_env:merge_and_check_unused_vars(SAcc, SA, EAcc)}\n    end\n  end,\n\n  {EClauses, SE} = lists:mapfoldl(Transformer, S, Clauses),\n  EArities = [fn_arity(Args) || {'->', _, [Args, _]} <- EClauses],\n\n  case lists:usort(EArities) of\n    [_] ->\n      {{fn, Meta, EClauses}, SE, E};\n    _ ->\n      file_error(Meta, E, ?MODULE, clauses_with_different_arities)\n  end.\n\nis_invalid_arg({'\\\\\\\\', _, _}) -> true;\nis_invalid_arg(_) -> false.\n\nfn_arity([{'when', _, Args}]) -> length(Args) - 1;\nfn_arity(Args) -> length(Args).\n\n%% Capture\n\ncapture(Meta, {'/', _, [{{'.', _, [M, F]} = Dot, RequireMeta, []}, A]}, S, E) when is_atom(F), is_integer(A) ->\n  Args = args_from_arity(Meta, A, E),\n  handle_capture_possible_warning(Meta, RequireMeta, M, F, A, E),\n  capture_require({Dot, RequireMeta, Args}, S, E, arity);\n\ncapture(Meta, {'/', _, [{F, ImportMeta, C}, A]}, S, E) when is_atom(F), is_integer(A), is_atom(C) ->\n  Args = args_from_arity(Meta, A, E),\n  capture_import({F, ImportMeta, Args}, S, E, arity);\n\ncapture(_Meta, {{'.', _, [_, Fun]}, _, Args} = Expr, S, E) when is_atom(Fun), is_list(Args) ->\n  capture_require(Expr, S, E, check_sequential_and_not_empty(Args));\n\ncapture(Meta, {{'.', _, [_]}, _, Args} = Expr, S, E) when is_list(Args) ->\n  capture_expr(Meta, Expr, S, E, non_sequential);\n\ncapture(Meta, {'__block__', _, [Expr]}, S, E) ->\n  capture(Meta, Expr, S, E);\n\ncapture(Meta, {'__block__', _, _} = Expr, _S, E) ->\n  file_error(Meta, E, ?MODULE, {block_expr_in_capture, Expr});\n\ncapture(_Meta, {Atom, _, Args} = Expr, S, E) when is_atom(Atom), is_list(Args) ->\n  capture_import(Expr, S, E, check_sequential_and_not_empty(Args));\n\ncapture(Meta, {Left, Right}, S, E) ->\n  capture(Meta, {'{}', Meta, [Left, Right]}, S, E);\n\ncapture(Meta, List, S, E) when is_list(List) ->\n  capture_expr(Meta, List, S, E, check_sequential_and_not_empty(List));\n\ncapture(Meta, Integer, _S, E) when is_integer(Integer) ->\n  file_error(Meta, E, ?MODULE, {capture_arg_outside_of_capture, Integer});\n\ncapture(Meta, Arg, _S, E) ->\n  invalid_capture(Meta, Arg, E).\n\ncapture_import({Atom, ImportMeta, Args} = Expr, S, E, ArgsType) ->\n  Res = ArgsType /= non_sequential andalso\n        elixir_dispatch:import_function(ImportMeta, Atom, length(Args), E),\n  handle_capture(Res, ImportMeta, ImportMeta, Expr, S, E, ArgsType).\n\ncapture_require({{'.', DotMeta, [Left, Right]}, RequireMeta, Args}, S, E, ArgsType) ->\n  case escape(Left, E, []) of\n    {EscLeft, []} ->\n      {ELeft, SE, EE} = elixir_expand:expand(EscLeft, S, E),\n\n      case ELeft of\n        _ when ArgsType /= arity -> ok;\n        Atom when is_atom(Atom) -> ok;\n        {Var, _, Ctx} when is_atom(Var), is_atom(Ctx) -> ok;\n        %% TODO: Raise on Elixir v2.0\n        _ -> elixir_errors:file_warn(RequireMeta, E, ?MODULE, {complex_module_capture, Left})\n      end,\n\n      Res = ArgsType /= non_sequential andalso case ELeft of\n        {Name, _, Context} when is_atom(Name), is_atom(Context) ->\n          {remote, ELeft, Right, length(Args)};\n        _ when is_atom(ELeft) ->\n          elixir_dispatch:require_function(RequireMeta, ELeft, Right, length(Args), EE);\n        _ ->\n          false\n      end,\n\n      Dot = {{'.', DotMeta, [ELeft, Right]}, RequireMeta, Args},\n      handle_capture(Res, RequireMeta, DotMeta, Dot, SE, EE, ArgsType);\n\n    {EscLeft, Escaped} ->\n      Dot = {{'.', DotMeta, [EscLeft, Right]}, RequireMeta, Args},\n      capture_expr(RequireMeta, Dot, S, E, Escaped, ArgsType)\n  end.\n\nhandle_capture(false, Meta, _DotMeta, Expr, S, E, ArgsType) ->\n  capture_expr(Meta, Expr, S, E, ArgsType);\nhandle_capture(LocalOrRemote, Meta, DotMeta, _Expr, S, E, _ArgsType) ->\n  {LocalOrRemote, Meta, DotMeta, S, E}.\n\ncapture_expr(Meta, Expr, S, E, ArgsType) ->\n  capture_expr(Meta, Expr, S, E, [], ArgsType).\ncapture_expr(Meta, Expr, S, E, Escaped, ArgsType) ->\n  case escape(Expr, E, Escaped) of\n    {_, []} when ArgsType == non_sequential ->\n      invalid_capture(Meta, Expr, E);\n    %% TODO: Remove this clause once we raise on complex module captures like &get_mod().fun/0\n    {{{'.', _, [_, _]} = Dot, _, Args}, []} ->\n      Meta2 = lists:keydelete(no_parens, 1, Meta),\n      Fn = {fn, Meta2, [{'->', Meta2, [[], {Dot, Meta2, Args}]}]},\n      {expand, Fn, S, E};\n    {EExpr, EDict} ->\n      EVars = validate(Meta, EDict, 1, E),\n      Fn = {fn, [{capture, true} | Meta], [{'->', Meta, [EVars, EExpr]}]},\n      {expand, Fn, S, E}\n  end.\n\ninvalid_capture(Meta, Arg, E) ->\n  file_error(Meta, E, ?MODULE, {invalid_args_for_capture, Arg}).\n\nvalidate(Meta, [{Pos, Var} | T], Pos, E) ->\n  [Var | validate(Meta, T, Pos + 1, E)];\nvalidate(Meta, [{Pos, _} | _], Expected, E) ->\n  file_error(Meta, E, ?MODULE, {capture_arg_without_predecessor, Pos, Expected});\nvalidate(_Meta, [], _Pos, _E) ->\n  [].\n\nescape({'&', Meta, [Pos]}, E, Dict) when is_integer(Pos), Pos > 0 ->\n  % Using a nil context here to emit warnings when variable is unused.\n  % This might pollute user space but is unlikely because variables\n  % named :\"&1\" are not valid syntax.\n  case orddict:find(Pos, Dict) of\n    {ok, Var} ->\n      {Var, Dict};\n    error ->\n      Next = elixir_module:next_counter(?key(E, module)),\n      Var = {capture, [{counter, Next}, {capture, Pos} | Meta], nil},\n      {Var, orddict:store(Pos, Var, Dict)}\n  end;\nescape({'&', Meta, [Pos]}, E, _Dict) when is_integer(Pos) ->\n  file_error(Meta, E, ?MODULE, {invalid_arity_for_capture, Pos});\nescape({'&', Meta, _} = Arg, E, _Dict) ->\n  file_error(Meta, E, ?MODULE, {nested_capture, Arg});\nescape({Left, Meta, Right}, E, Dict0) ->\n  {TLeft, Dict1}  = escape(Left, E, Dict0),\n  {TRight, Dict2} = escape(Right, E, Dict1),\n  {{TLeft, Meta, TRight}, Dict2};\nescape({Left, Right}, E, Dict0) ->\n  {TLeft, Dict1}  = escape(Left, E, Dict0),\n  {TRight, Dict2} = escape(Right, E, Dict1),\n  {{TLeft, TRight}, Dict2};\nescape(List, E, Dict) when is_list(List) ->\n  lists:mapfoldl(fun(X, Acc) -> escape(X, E, Acc) end, Dict, List);\nescape(Other, _E, Dict) ->\n  {Other, Dict}.\n\nargs_from_arity(_Meta, A, _E) when is_integer(A), A >= 0, A =< 255 ->\n  [{'&', [], [X]} || X <- lists:seq(1, A)];\nargs_from_arity(Meta, A, E) ->\n  file_error(Meta, E, ?MODULE, {invalid_arity_for_capture, A}).\n\ncheck_sequential_and_not_empty([])   -> non_sequential;\ncheck_sequential_and_not_empty(List) -> check_sequential(List, 1).\n\ncheck_sequential([{'&', _, [Int]} | T], Int) -> check_sequential(T, Int + 1);\ncheck_sequential([], _Int) -> sequential;\ncheck_sequential(_, _Int) -> non_sequential.\n\nhandle_capture_possible_warning(Meta, DotMeta, Mod, Fun, Arity, E) ->\n  case (Arity =:= 0) andalso (lists:keyfind(no_parens, 1, DotMeta) /= {no_parens, true}) of\n    true ->\n      elixir_errors:file_warn(Meta, E, ?MODULE, {parens_remote_capture, Mod, Fun});\n\n    false -> ok\n  end.\n\n%% TODO: Raise on Elixir v2.0\nformat_error({parens_remote_capture, Mod, Fun}) ->\n  io_lib:format(\"extra parentheses on a remote function capture &~ts.~ts()/0 have been \"\n                 \"deprecated. Please remove the parentheses: &~ts.~ts/0\",\n                 ['Elixir.Macro':to_string(Mod), Fun, 'Elixir.Macro':to_string(Mod), Fun]);\nformat_error({complex_module_capture, Mod}) ->\n  io_lib:format(\"expected the module in &module.fun/arity to expand to a variable or an atom, got: ~ts\\n\"\n                \"You can either compute the module name outside of & or convert it to a regular anonymous function.\",\n                 ['Elixir.Macro':to_string(Mod)]);\nformat_error(clauses_with_different_arities) ->\n  \"cannot mix clauses with different arities in anonymous functions\";\nformat_error(defaults_in_args) ->\n  \"anonymous functions cannot have optional arguments\";\nformat_error({block_expr_in_capture, Expr}) ->\n  io_lib:format(\"block expressions are not allowed inside the capture operator &, got: ~ts\",\n                ['Elixir.Macro':to_string(Expr)]);\nformat_error({nested_capture, Arg}) ->\n  io_lib:format(\"nested captures are not allowed. You cannot define a function using \"\n    \"the capture operator & inside another function defined via &. Got invalid nested \"\n    \"capture: ~ts\", ['Elixir.Macro':to_string(Arg)]);\nformat_error({invalid_arity_for_capture, Arity}) ->\n  io_lib:format(\"capture argument &~B must be numbered between 1 and 255\", [Arity]);\nformat_error({capture_arg_outside_of_capture, Integer}) ->\n  io_lib:format(\"capture argument &~B must be used within the capture operator &\", [Integer]);\nformat_error({capture_arg_without_predecessor, Pos, Expected}) ->\n  io_lib:format(\"capture argument &~B cannot be defined without &~B \"\n    \"(you cannot skip arguments, all arguments must be numbered)\", [Pos, Expected]);\nformat_error({invalid_args_for_capture, Arg}) ->\n  Message =\n    \"invalid args for &, expected one of:\\n\\n\"\n    \"  * &Mod.fun/arity to capture a remote function, such as &Enum.map/2\\n\"\n    \"  * &fun/arity to capture a local or imported function, such as &is_atom/1\\n\"\n    \"  * &some_code(&1, ...) containing at least one argument as &1, such as &List.flatten(&1)\\n\\n\"\n    \"Got: ~ts\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Arg)]).\n"
  },
  {
    "path": "lib/elixir/src/elixir_import.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Module responsible for handling imports and conflicts\n%% between local functions and imports.\n%% For imports dispatch, please check elixir_dispatch.\n-module(elixir_import).\n-export([import/6, import/7, special_form/2,\n         record/4, ensure_no_local_conflict/3,\n         format_error/1]).\n-compile(inline_list_funcs).\n-include(\"elixir.hrl\").\n\nimport(Meta, Ref, Opts, E, Warn, Trace) ->\n  import(Meta, Ref, Opts, E, Warn, Trace, fun Ref:'__info__'/1).\n\nimport(Meta, Ref, Opts, E, Warn, Trace, InfoCallback) ->\n  case import_only_except(Meta, Ref, Opts, E, Warn, InfoCallback) of\n    {Functions, Macros, Added} ->\n      Trace andalso elixir_env:trace({import, Meta, Ref, Opts}, E),\n      EI = E#{functions := Functions, macros := Macros},\n      {ok, Added, elixir_aliases:require(Meta, Ref, [{warn, false} | Opts], EI, Trace)};\n\n    {error, Reason} ->\n      {error, Reason}\n  end.\n\nimport_only_except(Meta, Ref, Opts, E, Warn, InfoCallback) ->\n  MaybeOnly = lists:keyfind(only, 1, Opts),\n\n  case lists:keyfind(except, 1, Opts) of\n    false ->\n      import_only_except(Meta, Ref, MaybeOnly, false, E, Warn, InfoCallback);\n\n    {except, DupExcept} when is_list(DupExcept) ->\n      case ensure_keyword_list(DupExcept) of\n        ok ->\n          Except = ensure_no_duplicates(DupExcept, except, Meta, E, Warn),\n          import_only_except(Meta, Ref, MaybeOnly, Except, E, Warn, InfoCallback);\n\n        error ->\n          {error, {invalid_option, except, DupExcept}}\n      end;\n\n    {except, Other} ->\n      {error, {invalid_option, except, Other}}\n  end.\n\nimport_only_except(Meta, Ref, MaybeOnly, Except, E, Warn, InfoCallback) ->\n  case MaybeOnly of\n    {only, functions} ->\n      {Added1, _Used1, Funs} = import_functions(Meta, Ref, Except, E, Warn, InfoCallback),\n      {Funs, keydelete(Ref, ?key(E, macros)), Added1};\n\n    {only, macros} ->\n      {Added2, _Used2, Macs} = import_macros(Meta, Ref, Except, E, Warn, InfoCallback),\n      {keydelete(Ref, ?key(E, functions)), Macs, Added2};\n\n    {only, sigils} ->\n      {Added1, _Used1, Funs} = import_sigil_functions(Meta, Ref, Except, E, Warn, InfoCallback),\n      {Added2, _Used2, Macs} = import_sigil_macros(Meta, Ref, Except, E, Warn, InfoCallback),\n      {Funs, Macs, Added1 or Added2};\n\n    {only, DupOnly} when is_list(DupOnly) ->\n      case ensure_keyword_list(DupOnly) of\n        ok when Except =:= false ->\n          Only = ensure_no_duplicates(DupOnly, only, Meta, E, Warn),\n          {Added1, Used1, Funs} = import_listed_functions(Meta, Ref, Only, E, Warn, InfoCallback),\n          {Added2, Used2, Macs} = import_listed_macros(Meta, Ref, Only, E, Warn, InfoCallback),\n          [Warn andalso elixir_errors:file_warn(Meta, E, ?MODULE, {invalid_import, {Ref, Name, Arity}}) ||\n            {Name, Arity} <- (Only -- Used1) -- Used2],\n          {Funs, Macs, Added1 or Added2};\n\n        ok ->\n          {error, only_and_except_given};\n\n        error ->\n          {error, {invalid_option, only, DupOnly}}\n      end;\n\n    {only, Other} ->\n      {error, {invalid_option, only, Other}};\n\n    false ->\n      {Added1, _Used1, Funs} = import_functions(Meta, Ref, Except, E, Warn, InfoCallback),\n      {Added2, _Used2, Macs} = import_macros(Meta, Ref, Except, E, Warn, InfoCallback),\n      {Funs, Macs, Added1 or Added2}\n  end.\n\nimport_listed_functions(Meta, Ref, Only, E, Warn, InfoCallback) ->\n  New = intersection(Only, get_functions(Ref, InfoCallback)),\n  calculate_key(Meta, Ref, ?key(E, functions), New, E, Warn).\n\nimport_listed_macros(Meta, Ref, Only, E, Warn, InfoCallback) ->\n  New = intersection(Only, get_macros(InfoCallback)),\n  calculate_key(Meta, Ref, ?key(E, macros), New, E, Warn).\n\nimport_functions(Meta, Ref, Except, E, Warn, InfoCallback) ->\n  calculate_except(Meta, Ref, Except, ?key(E, functions), E, Warn, fun() ->\n    get_functions(Ref, InfoCallback)\n  end).\n\nimport_macros(Meta, Ref, Except, E, Warn, InfoCallback) ->\n  calculate_except(Meta, Ref, Except, ?key(E, macros), E, Warn, fun() ->\n    get_macros(InfoCallback)\n  end).\n\nimport_sigil_functions(Meta, Ref, Except, E, Warn, InfoCallback) ->\n  calculate_except(Meta, Ref, Except, ?key(E, functions), E, Warn, fun() ->\n    filter_sigils(InfoCallback(functions))\n  end).\n\nimport_sigil_macros(Meta, Ref, Except, E, Warn, InfoCallback) ->\n  calculate_except(Meta, Ref, Except, ?key(E, macros), E, Warn, fun() ->\n    filter_sigils(InfoCallback(macros))\n  end).\n\ncalculate_except(Meta, Key, false, Old, E, Warn, Existing) ->\n  New = remove_underscored(Existing()),\n  calculate_key(Meta, Key, Old, New, E, Warn);\n\ncalculate_except(Meta, Key, Except, Old, E, Warn, Existing) ->\n  %% We are not checking existence of exports listed in :except\n  %% option on purpose: to support backwards compatible code.\n  %% For example, \"import String, except: [trim: 1]\"\n  %% should work across all Elixir versions.\n  New =\n    case lists:keyfind(Key, 1, Old) of\n      false -> remove_underscored(Existing()) -- Except;\n      {Key, OldImports} -> OldImports -- Except\n    end,\n  calculate_key(Meta, Key, Old, New, E, Warn).\n\ncalculate_key(Meta, Key, Old, New, E, Warn) ->\n  case ordsets:from_list(New) of\n    [] ->\n      {false, [], keydelete(Key, Old)};\n    Set  ->\n      FinalSet = ensure_no_special_form_conflict(Set, Key, Meta, E, Warn),\n      {true, FinalSet, [{Key, FinalSet} | keydelete(Key, Old)]}\n  end.\n\n%% Record function calls for local conflicts\n\nrecord(_Tuple, Receiver, Module, Function)\n  when Function == nil; Module == Receiver -> false;\nrecord(Tuple, Receiver, Module, _Function) ->\n  try\n    {Set, _Bag} = elixir_module:data_tables(Module),\n    ets:insert(Set, {{import, Tuple}, Receiver}),\n    true\n  catch\n    error:badarg -> false\n  end.\n\nensure_no_local_conflict('Elixir.Kernel', _All, _E) ->\n  ok;\nensure_no_local_conflict(Module, AllDefinitions, E) ->\n  {Set, _} = elixir_module:data_tables(Module),\n\n  [try\n     Receiver = ets:lookup_element(Set, {import, Pair}, 2),\n     elixir_errors:module_error(Meta, E, ?MODULE, {import_conflict, Receiver, Pair})\n   catch\n    error:badarg -> false\n   end || {Pair, _, Meta, _} <- AllDefinitions].\n\n%% Retrieve functions and macros from modules\n\nget_functions(Module, InfoCallback) ->\n  try\n    InfoCallback(functions)\n  catch\n    error:undef -> remove_internals(Module:module_info(exports))\n  end.\n\nget_macros(InfoCallback) ->\n  try\n    InfoCallback(macros)\n  catch\n    error:undef -> []\n  end.\n\nfilter_sigils(Funs) ->\n  lists:filter(fun is_sigil/1, Funs).\n\nis_sigil({Name, 2}) ->\n  case atom_to_list(Name) of\n    \"sigil_\" ++ Letters ->\n      case Letters of\n        [L] when L >= $a, L =< $z -> true;\n        [] -> false;\n        [H|T] when H >= $A, H =< $Z ->\n              lists:all(fun(L) -> (L >= $0 andalso L =< $9)\n                                  orelse (L>= $A andalso L =< $Z)\n                        end, T)\n      end;\n    _ ->\n      false\n  end;\nis_sigil(_) ->\n  false.\n\n%% VALIDATION HELPERS\\\n\nensure_keyword_list([]) ->\n  ok;\nensure_keyword_list([{Key, Value} | Rest]) when is_atom(Key), is_integer(Value) ->\n  ensure_keyword_list(Rest);\nensure_keyword_list(_Other) ->\n  error.\n\nensure_no_special_form_conflict(Set, Key, Meta, E, Warn) ->\n  lists:filter(fun({Name, Arity}) ->\n    case special_form(Name, Arity) of\n      true  ->\n        Warn andalso elixir_errors:file_warn(Meta, E, ?MODULE, {special_form_conflict, {Key, Name, Arity}}),\n        false;\n      false ->\n        true\n    end\n  end, Set).\n\nensure_no_duplicates(Option, Kind, Meta, E, Warn) ->\n  lists:foldl(fun({Name, Arity}, Acc) ->\n    case lists:member({Name, Arity}, Acc) of\n      true ->\n        Warn andalso elixir_errors:file_warn(Meta, E, ?MODULE, {duplicated_import, {Kind, Name, Arity}}),\n        Acc;\n      false ->\n        [{Name, Arity} | Acc]\n    end\n  end, [], Option).\n\n%% ERROR HANDLING\n\nformat_error(only_and_except_given) ->\n  \":only and :except can only be given together to import \"\n  \"when :only is :functions, :macros, or :sigils\";\n\nformat_error({duplicated_import, {Option, Name, Arity}}) ->\n  io_lib:format(\"invalid :~s option for import, ~ts/~B is duplicated\", [Option, Name, Arity]);\n\nformat_error({invalid_import, {Receiver, Name, Arity}}) ->\n  io_lib:format(\"cannot import ~ts.~ts/~B because it is undefined or private\",\n    [elixir_aliases:inspect(Receiver), Name, Arity]);\n\nformat_error({invalid_option, only, Value}) ->\n  Message = \"invalid :only option for import, expected value to be an atom :functions, :macros\"\n  \", or a literal keyword list of function names with arity as values, got: ~s\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Value)]);\n\nformat_error({invalid_option, except, Value}) ->\n  Message = \"invalid :except option for import, expected value to be a literal keyword list of function names with arity as values, got: ~s\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Value)]);\n\nformat_error({special_form_conflict, {Receiver, Name, Arity}}) ->\n  io_lib:format(\"cannot import ~ts.~ts/~B because it conflicts with Elixir special forms, the import has been discarded\",\n    [elixir_aliases:inspect(Receiver), Name, Arity]);\n\nformat_error({no_macros, Module}) ->\n  io_lib:format(\"could not load macros from module ~ts\", [elixir_aliases:inspect(Module)]);\n\nformat_error({import_conflict, Receiver, {Name, Arity}}) ->\n  io_lib:format(\"imported ~ts.~ts/~B conflicts with local function\",\n    [elixir_aliases:inspect(Receiver), Name, Arity]).\n\n%% LIST HELPERS\n\nkeydelete(Key, List) ->\n  lists:keydelete(Key, 1, List).\n\nintersection([H | T], All) ->\n  case lists:member(H, All) of\n    true  -> [H | intersection(T, All)];\n    false -> intersection(T, All)\n  end;\n\nintersection([], _All) -> [].\n\n%% Internal funs that are never imported, and the like\n\nremove_underscored(List) ->\n  lists:filter(fun({Name, _}) ->\n    case atom_to_list(Name) of\n      \"_\" ++ _ -> false;\n      _ -> true\n    end\n  end, List).\n\nremove_internals(Set) ->\n  Set -- [{behaviour_info, 1}, {module_info, 1}, {module_info, 0}].\n\n%% Special forms\n\nspecial_form('&', 1) -> true;\nspecial_form('^', 1) -> true;\nspecial_form('=', 2) -> true;\nspecial_form('%', 2) -> true;\nspecial_form('|', 2) -> true;\nspecial_form('.', 2) -> true;\nspecial_form('::', 2) -> true;\nspecial_form('__aliases__', _) -> true;\nspecial_form('__block__', _) -> true;\nspecial_form('__cursor__', _) -> true;\nspecial_form('->', _) -> true;\nspecial_form('<<>>', _) -> true;\nspecial_form('{}', _) -> true;\nspecial_form('%{}', _) -> true;\nspecial_form('alias', 1) -> true;\nspecial_form('alias', 2) -> true;\nspecial_form('require', 1) -> true;\nspecial_form('require', 2) -> true;\nspecial_form('import', 1) -> true;\nspecial_form('import', 2) -> true;\nspecial_form('__ENV__', 0) -> true;\nspecial_form('__CALLER__', 0) -> true;\nspecial_form('__STACKTRACE__', 0) -> true;\nspecial_form('__MODULE__', 0) -> true;\nspecial_form('__DIR__', 0) -> true;\nspecial_form('quote', 1) -> true;\nspecial_form('quote', 2) -> true;\nspecial_form('unquote', 1) -> true;\nspecial_form('unquote_splicing', 1) -> true;\nspecial_form('fn', _) -> true;\nspecial_form('super', _) -> true;\nspecial_form('for', _) -> true;\nspecial_form('with', _) -> true;\nspecial_form('cond', 1) -> true;\nspecial_form('case', 2) -> true;\nspecial_form('try', 1) -> true;\nspecial_form('receive', 1) -> true;\nspecial_form(_, _) -> false.\n"
  },
  {
    "path": "lib/elixir/src/elixir_interpolation.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n% Handle string and string-like interpolations.\n-module(elixir_interpolation).\n-export([extract/6, unescape_string/1, unescape_string/2,\nunescape_tokens/1, unescape_map/1]).\n-include(\"elixir.hrl\").\n-include(\"elixir_tokenizer.hrl\").\n\n%% Extract string interpolations\n\nextract(Line, Column, Scope, Interpol, String, Last) ->\n  extract(String, [], [], Line, Column, Scope, Interpol, Last).\n\n%% Terminators\n\nextract([], _Buffer, _Output, Line, Column, #elixir_tokenizer{cursor_completion=false}, _Interpol, Last) ->\n  {error, {string, Line, Column, io_lib:format(\"missing terminator: ~ts\", [[Last]]), []}};\n\nextract([], Buffer, Output, Line, Column, Scope, _Interpol, _Last) ->\n  finish_extraction([], false, Buffer, Output, Line, Column, Scope);\n\nextract([Last | Rest], Buffer, Output, Line, Column, Scope, _Interpol, Last) ->\n  finish_extraction(Rest, true, Buffer, Output, Line, Column + 1, Scope);\n\n%% Going through the string\n\nextract([$\\\\, $\\r, $\\n | Rest], Buffer, Output, Line, _Column, Scope, Interpol, Last) ->\n  extract_nl(Rest, [$\\n, $\\r, $\\\\ | Buffer], Output, Line, Scope, Interpol, Last);\n\nextract([$\\\\, $\\n | Rest], Buffer, Output, Line, _Column, Scope, Interpol, Last) ->\n  extract_nl(Rest, [$\\n, $\\\\ | Buffer], Output, Line, Scope, Interpol, Last);\n\nextract([$\\n | Rest], Buffer, Output, Line, _Column, Scope, Interpol, Last) ->\n  extract_nl(Rest, [$\\n | Buffer], Output, Line, Scope, Interpol, Last);\n\nextract([$\\\\, Last | Rest], Buffer, Output, Line, Column, Scope, Interpol, Last) ->\n  NewScope =\n    %% TODO: Remove this on Elixir v2.0\n    case Interpol of\n      true ->\n        Scope;\n      false ->\n        Msg = \"using \\\\~ts to escape the closing of an uppercase sigil is deprecated, please use another delimiter or a lowercase sigil instead\",\n        prepend_warning(Line, Column, io_lib:format(Msg, [[Last]]), Scope)\n    end,\n\n  extract(Rest, [Last | Buffer], Output, Line, Column+2, NewScope, Interpol, Last);\n\nextract([$\\\\, Last, Last, Last | Rest], Buffer, Output, Line, Column, Scope, Interpol, [Last, Last, Last] = All) ->\n  extract(Rest, [Last, Last, Last | Buffer], Output, Line, Column+4, Scope, Interpol, All);\n\nextract([$\\\\, $#, ${ | Rest], Buffer, Output, Line, Column, Scope, true, Last) ->\n  extract(Rest, [${, $#, $\\\\ | Buffer], Output, Line, Column+3, Scope, true, Last);\n\nextract([$#, ${ | Rest], Buffer, Output, Line, Column, Scope, true, Last) ->\n  Output1 = build_string(Buffer, Output),\n  case elixir_tokenizer:tokenize(Rest, Line, Column + 2, Scope#elixir_tokenizer{terminators=[]}) of\n    {error, {Location, _, \"}\"}, [$} | NewRest], Warnings, Tokens} ->\n      NewScope = Scope#elixir_tokenizer{warnings=Warnings},\n      {line, EndLine} = lists:keyfind(line, 1, Location),\n      {column, EndColumn} = lists:keyfind(column, 1, Location),\n      Output2 = build_interpol(Line, Column, EndLine, EndColumn, lists:reverse(Tokens), Output1),\n      extract(NewRest, [], Output2, EndLine, EndColumn + 1, NewScope, true, Last);\n    {error, Reason, _, _, _} ->\n      {error, Reason};\n    {ok, EndLine, EndColumn, Warnings, Tokens, Terminators} when Scope#elixir_tokenizer.cursor_completion /= false ->\n      NewScope = Scope#elixir_tokenizer{warnings=Warnings, cursor_completion=noprune},\n      {CursorTerminators, _} = cursor_complete(EndLine, EndColumn, Terminators),\n      Output2 = build_interpol(Line, Column, EndLine, EndColumn, lists:reverse(Tokens, CursorTerminators), Output1),\n      extract([], [], Output2, EndLine, EndColumn, NewScope, true, Last);\n    {ok, _, _, _, _, _} ->\n      {error, {string, Line, Column, \"missing interpolation terminator: \\\"}\\\"\", []}}\n  end;\n\nextract([$\\\\ | Rest], Buffer, Output, Line, Column, Scope, Interpol, Last) ->\n  extract_char(Rest, [$\\\\ | Buffer], Output, Line, Column + 1, Scope, Interpol, Last);\n\n%% Catch all clause\n\nextract([Char1, Char2 | Rest], Buffer, Output, Line, Column, Scope, Interpol, Last)\n    when Char1 =< 255, Char2 =< 255 ->\n  extract([Char2 | Rest], [Char1 | Buffer], Output, Line, Column + 1, Scope, Interpol, Last);\n\nextract(Rest, Buffer, Output, Line, Column, Scope, Interpol, Last) ->\n  extract_char(Rest, Buffer, Output, Line, Column, Scope, Interpol, Last).\n\nextract_char(Rest, Buffer, Output, Line, Column, Scope, Interpol, Last) ->\n  case unicode_util:gc(Rest) of\n    [Char | _] when ?bidi(Char); ?break(Char) ->\n      Token = io_lib:format(\"\\\\u~4.16.0B\", [Char]),\n      Pre = if\n        ?bidi(Char) -> \"invalid bidirectional formatting character in string: \";\n        true -> \"invalid line break character in string: \"\n      end,\n      Pos = io_lib:format(\". If you want to use such character, use it in its escaped ~ts form instead\", [Token]),\n      {error, {?LOC(Line, Column), {Pre, Pos}, Token}};\n\n    [Char | NewRest] when is_list(Char) ->\n      extract(NewRest, lists:reverse(Char, Buffer), Output, Line, Column + 1, Scope, Interpol, Last);\n\n    [Char | NewRest] when is_integer(Char) ->\n      extract(NewRest, [Char | Buffer], Output, Line, Column + 1, Scope, Interpol, Last);\n\n    [] ->\n      extract([], Buffer, Output, Line, Column, Scope, Interpol, Last)\n  end.\n\n%% Handle newlines. Heredocs require special attention\n\nextract_nl(Rest, Buffer, Output, Line, Scope, Interpol, [H,H,H] = Last) ->\n  case strip_horizontal_space(Rest, Buffer, 1) of\n    {[H,H,H|NewRest], _NewBuffer, Column} ->\n      finish_extraction(NewRest, true, Buffer, Output, Line + 1, Column + 3, Scope);\n    {NewRest, NewBuffer, Column} ->\n      extract(NewRest, NewBuffer, Output, Line + 1, Column, Scope, Interpol, Last)\n  end;\nextract_nl(Rest, Buffer, Output, Line, Scope, Interpol, Last) ->\n  extract(Rest, Buffer, Output, Line + 1, Scope#elixir_tokenizer.column, Scope, Interpol, Last).\n\nstrip_horizontal_space([H | T], Buffer, Counter) when H =:= $\\s; H =:= $\\t ->\n  strip_horizontal_space(T, [H | Buffer], Counter + 1);\nstrip_horizontal_space(T, Buffer, Counter) ->\n  {T, Buffer, Counter}.\n\ncursor_complete(Line, Column, Terminators) ->\n  lists:mapfoldl(\n    fun({Start, _, _}, AccColumn) ->\n      End = elixir_tokenizer:terminator(Start),\n      {{End, {Line, AccColumn, nil}}, AccColumn + length(erlang:atom_to_list(End))}\n    end,\n    Column,\n    Terminators\n  ).\n\n%% Unescape a series of tokens as returned by extract.\n\nunescape_tokens(Tokens) ->\n  try [unescape_token(Token, fun unescape_map/1) || Token <- Tokens] of\n    Unescaped -> {ok, Unescaped}\n  catch\n    {error, _Reason, _Token} = Error -> Error\n  end.\n\nunescape_token(Token, Map) when is_list(Token) ->\n  unescape_chars(elixir_utils:characters_to_binary(Token), Map);\nunescape_token(Token, Map) when is_binary(Token) ->\n  unescape_chars(Token, Map);\nunescape_token(Other, _Map) ->\n  Other.\n\n% Unescape string. This is called by Elixir. Wrapped by convenience.\n\nunescape_string(String) ->\n  unescape_string(String, fun unescape_map/1).\n\nunescape_string(String, Map) ->\n  try\n    unescape_chars(String, Map)\n  catch\n    {error, Reason, _} ->\n      Message = elixir_utils:characters_to_binary(Reason),\n      error('Elixir.ArgumentError':exception([{message, Message}]))\n  end.\n\n% Unescape chars. For instance, \"\\\" \"n\" (two chars) needs to be converted to \"\\n\" (one char).\n\nunescape_chars(String, Map) ->\n  unescape_chars(String, Map, <<>>).\n\nunescape_chars(<<$\\\\, $x, Rest/binary>>, Map, Acc) ->\n  case Map(hex) of\n    true  -> unescape_hex(Rest, Map, Acc);\n    false -> unescape_chars(Rest, Map, <<Acc/binary, $\\\\, $x>>)\n  end;\n\nunescape_chars(<<$\\\\, $u, Rest/binary>>, Map, Acc) ->\n  case Map(unicode) of\n    true  -> unescape_unicode(Rest, Map, Acc);\n    false -> unescape_chars(Rest, Map, <<Acc/binary, $\\\\, $u>>)\n  end;\n\nunescape_chars(<<$\\\\, $\\n, Rest/binary>>, Map, Acc) ->\n  case Map(newline) of\n    true  -> unescape_chars(Rest, Map, Acc);\n    false -> unescape_chars(Rest, Map, <<Acc/binary, $\\\\, $\\n>>)\n  end;\n\nunescape_chars(<<$\\\\, $\\r, $\\n, Rest/binary>>, Map, Acc) ->\n  case Map(newline) of\n    true  -> unescape_chars(Rest, Map, Acc);\n    false -> unescape_chars(Rest, Map, <<Acc/binary, $\\\\, $\\r, $\\n>>)\n  end;\n\nunescape_chars(<<$\\\\, Escaped, Rest/binary>>, Map, Acc) ->\n  case Map(Escaped) of\n    false -> unescape_chars(Rest, Map, <<Acc/binary, $\\\\, Escaped>>);\n    Other -> unescape_chars(Rest, Map, <<Acc/binary, Other>>)\n  end;\n\nunescape_chars(<<Char, Rest/binary>>, Map, Acc) ->\n  unescape_chars(Rest, Map, <<Acc/binary, Char>>);\n\nunescape_chars(<<>>, _Map, Acc) -> Acc.\n\n% Unescape Helpers\n\nunescape_hex(<<A, B, Rest/binary>>, Map, Acc) when ?is_hex(A), ?is_hex(B) ->\n  Bytes = list_to_integer([A, B], 16),\n  unescape_chars(Rest, Map, <<Acc/binary, Bytes>>);\n\nunescape_hex(<<_/binary>>, _Map, _Acc) ->\n  throw({error, \"invalid hex escape character, expected \\\\xHH where H is a hexadecimal digit\", \"\\\\x\"}).\n\n%% Finish deprecated sequences\n\nunescape_unicode(<<A, B, C, D, Rest/binary>>, Map, Acc) when ?is_hex(A), ?is_hex(B), ?is_hex(C), ?is_hex(D) ->\n  append_codepoint(Rest, Map, [A, B, C, D], Acc, 16);\n\nunescape_unicode(<<${, A, $}, Rest/binary>>, Map, Acc) when ?is_hex(A) ->\n  append_codepoint(Rest, Map, [A], Acc, 16);\n\nunescape_unicode(<<${, A, B, $}, Rest/binary>>, Map, Acc) when ?is_hex(A), ?is_hex(B) ->\n  append_codepoint(Rest, Map, [A, B], Acc, 16);\n\nunescape_unicode(<<${, A, B, C, $}, Rest/binary>>, Map, Acc) when ?is_hex(A), ?is_hex(B), ?is_hex(C) ->\n  append_codepoint(Rest, Map, [A, B, C], Acc, 16);\n\nunescape_unicode(<<${, A, B, C, D, $}, Rest/binary>>, Map, Acc) when ?is_hex(A), ?is_hex(B), ?is_hex(C), ?is_hex(D) ->\n  append_codepoint(Rest, Map, [A, B, C, D], Acc, 16);\n\nunescape_unicode(<<${, A, B, C, D, E, $}, Rest/binary>>, Map, Acc) when ?is_hex(A), ?is_hex(B), ?is_hex(C), ?is_hex(D), ?is_hex(E) ->\n  append_codepoint(Rest, Map, [A, B, C, D, E], Acc, 16);\n\nunescape_unicode(<<${, A, B, C, D, E, F, $}, Rest/binary>>, Map, Acc) when ?is_hex(A), ?is_hex(B), ?is_hex(C), ?is_hex(D), ?is_hex(E), ?is_hex(F) ->\n  append_codepoint(Rest, Map, [A, B, C, D, E, F], Acc, 16);\n\nunescape_unicode(<<_/binary>>, _Map, _Acc) ->\n  throw({error, \"invalid Unicode escape character, expected \\\\uHHHH or \\\\u{H*} where H is a hexadecimal digit\", \"\\\\u\"}).\n\nappend_codepoint(Rest, Map, List, Acc, Base) ->\n  Codepoint = list_to_integer(List, Base),\n  try <<Acc/binary, Codepoint/utf8>> of\n    Binary -> unescape_chars(Rest, Map, Binary)\n  catch\n    error:badarg ->\n      throw({error, \"invalid or reserved Unicode code point \\\\u{\" ++ List ++ \"}\", \"\\\\u\"})\n  end.\n\nunescape_map(newline) -> true;\nunescape_map(unicode) -> true;\nunescape_map(hex) -> true;\nunescape_map($0) -> 0;\nunescape_map($a) -> 7;\nunescape_map($b) -> $\\b;\nunescape_map($d) -> $\\d;\nunescape_map($e) -> $\\e;\nunescape_map($f) -> $\\f;\nunescape_map($n) -> $\\n;\nunescape_map($r) -> $\\r;\nunescape_map($s) -> $\\s;\nunescape_map($t) -> $\\t;\nunescape_map($v) -> $\\v;\nunescape_map(E)  -> E.\n\n% Extract Helpers\n\nfinish_extraction(Remaining, Done, Buffer, Output, Line, Column, Scope) ->\n  Final = case build_string(Buffer, Output) of\n    [] -> [[]];\n    F  -> F\n  end,\n\n  {Line, Column, lists:reverse(Final), Remaining, Done, Scope}.\n\nbuild_string([], Output) -> Output;\nbuild_string(Buffer, Output) -> [lists:reverse(Buffer) | Output].\n\nbuild_interpol(Line, Column, EndLine, EndColumn, Buffer, Output) ->\n  [{{Line, Column, nil}, {EndLine, EndColumn, nil}, Buffer} | Output].\n\nprepend_warning(Line, Column, Msg, #elixir_tokenizer{warnings=Warnings} = Scope) ->\n  Scope#elixir_tokenizer{warnings = [{{Line, Column}, Msg} | Warnings]}.\n"
  },
  {
    "path": "lib/elixir/src/elixir_lexical.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Module responsible for tracking lexical information.\n-module(elixir_lexical).\n-feature(maybe_expr, enable).\n-export([run/3, with_file/3, trace/2, format_error/1]).\n-include(\"elixir.hrl\").\n\nrun(#{tracers := Tracers} = E, ExecutionCallback, AfterExecutionCallback) ->\n  case elixir_config:is_bootstrap() of\n    false ->\n      {ok, Pid} = ?tracker:start_link(),\n      LexEnv = E#{lexical_tracker := Pid, tracers := [?MODULE | Tracers]},\n      elixir_env:trace(start, LexEnv),\n\n      try ExecutionCallback(LexEnv) of\n        Res ->\n          warn_unused_aliases(Pid, LexEnv),\n          warn_unused_imports(Pid, LexEnv),\n          warn_unused_requires(Pid, LexEnv),\n          AfterExecutionCallback(LexEnv),\n          Res\n      after\n        elixir_env:trace(stop, LexEnv),\n        unlink(Pid),\n        ?tracker:stop(Pid)\n      end;\n\n    true ->\n      ExecutionCallback(E),\n      AfterExecutionCallback(E)\n  end.\ntrace({alias_expansion, _Meta, Lookup, _Result}, #{lexical_tracker := Pid}) ->\n  ?tracker:alias_dispatch(Pid, Lookup),\n  ok;\ntrace({require, Meta, Module, _Opts}, #{lexical_tracker := Pid}) ->\n  case lists:keyfind(from_macro, 1, Meta) of\n    {from_macro, true} -> ?tracker:remote_dispatch(Pid, Module, compile);\n    _ -> ?tracker:add_export(Pid, Module)\n  end,\n  ok;\ntrace({struct_expansion, Meta, Module, _Keys}, #{lexical_tracker := Pid} = E) ->\n  maybe\n    #{function := {_, _}} ?= E,\n    Operation = proplists:get_value(operation, Meta, unknown),\n    true ?= (Operation =:= match) orelse (Operation =:= update),\n    ?tracker:remote_dispatch(Pid, Module, runtime)\n  else\n    _ -> ?tracker:add_export(Pid, Module)\n  end,\n  ok;\ntrace({alias_reference, _Meta, Module}, #{lexical_tracker := Pid} = E) ->\n  case E of\n    %% Alias references inside patterns and guards in functions are not\n    %% compile time dependencies.\n    #{function := nil} -> ?tracker:remote_dispatch(Pid, Module, compile);\n    #{context := nil} -> ?tracker:remote_dispatch(Pid, Module, runtime);\n    #{} -> ok\n  end,\n  ok;\ntrace({remote_function, _Meta, Module, _Function, _Arity}, #{lexical_tracker := Pid} = E) ->\n  ?tracker:remote_dispatch(Pid, Module, mode(E)),\n  ok;\ntrace({remote_macro, _Meta, Module, _Function, _Arity}, #{lexical_tracker := Pid}) ->\n  ?tracker:remote_dispatch(Pid, Module, compile),\n  ok;\ntrace({imported_function, _Meta, Module, Function, Arity}, #{lexical_tracker := Pid} = E) ->\n  ?tracker:import_dispatch(Pid, Module, {Function, Arity}, mode(E)),\n  ok;\ntrace({imported_macro, _Meta, Module, Function, Arity}, #{lexical_tracker := Pid}) ->\n  ?tracker:import_dispatch(Pid, Module, {Function, Arity}, compile),\n  ok;\ntrace({imported_quoted, _Meta, Module, Function, Arities}, #{lexical_tracker := Pid}) ->\n  ?tracker:import_quoted(Pid, Module, Function, Arities),\n  ok;\ntrace({compile_env, App, Path, Return}, #{lexical_tracker := Pid}) ->\n  ?tracker:add_compile_env(Pid, App, Path, Return),\n  ok;\ntrace(_, _) ->\n  ok.\n\nmode(#{function := nil}) -> compile;\nmode(#{}) -> runtime.\n\n%% EXTERNAL SOURCES\n\nwith_file(File, #{lexical_tracker := nil} = E, Callback) ->\n  Callback(E#{file := File});\nwith_file(File, #{lexical_tracker := Pid} = E, Callback) ->\n  try\n    ?tracker:set_file(Pid, File),\n    Callback(E#{file := File})\n  after\n    ?tracker:reset_file(Pid)\n  end.\n\n%% ERROR HANDLING\n\nwarn_unused_imports(Pid, E) ->\n  [elixir_errors:file_warn(Meta, ?key(E, file), ?MODULE, {unused_import, ModOrMFA})\n   || {Module, Imports} <- ?tracker:collect_unused_imports(Pid),\n      {ModOrMFA, Meta} <- unused_imports_for_module(Module, Imports)],\n  ok.\n\nwarn_unused_requires(Pid, E) ->\n  [elixir_errors:file_warn(Meta, ?key(E, file), ?MODULE, {unused_require, Module, Alias, AliasUsed})\n   || {Module, Meta, Alias, AliasUsed} <- ?tracker:collect_unused_requires(Pid)],\n  ok.\n\nunused_imports_for_module(Module, Imports) ->\n  case Imports of\n    #{Module := Meta} -> [{Module, Meta}];\n    #{} -> [{{Module, Fun, Arity}, Meta} || {{Fun, Arity}, Meta} <- maps:to_list(Imports)]\n  end.\n\nwarn_unused_aliases(Pid, E) ->\n  [elixir_errors:file_warn(Meta, ?key(E, file), ?MODULE, {unused_alias, Module})\n   || {Module, Meta} <- ?tracker:collect_unused_aliases(Pid)],\n  ok.\n\nformat_error({unused_alias, Module}) ->\n  io_lib:format(\"unused alias ~ts\", [elixir_aliases:inspect(Module)]);\nformat_error({unused_import, {Module, Function, Arity}}) ->\n  io_lib:format(\"unused import ~ts.~ts/~w\", [elixir_aliases:inspect(Module), Function, Arity]);\nformat_error({unused_import, Module}) ->\n  io_lib:format(\"unused import ~ts\", [elixir_aliases:inspect(Module)]);\nformat_error({unused_require, Module, Alias, AliasUsed}) ->\n  Message = if\n    Alias == false -> \"unused require ~ts\";\n    AliasUsed -> \"unused require ~ts (convert it to an alias instead)\";\n    true -> \"unused require ~ts (the alias is also unused)\"\n  end,\n  io_lib:format(Message, [elixir_aliases:inspect(Module)]).\n"
  },
  {
    "path": "lib/elixir/src/elixir_map.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_map).\n-export([expand_map/4, expand_struct/5, format_error/1, maybe_load_struct_info/3]).\n-import(elixir_errors, [function_error/4, file_error/4, file_warn/4]).\n-include(\"elixir.hrl\").\n\nexpand_map(Meta, [{'|', UpdateMeta, [Left, Right]}], S, #{context := nil} = E) ->\n  {[ELeft | ERight], SE, EE} = elixir_expand:expand_args([Left | Right], S, E),\n  validate_kv(Meta, ERight, Right, E),\n  {{'%{}', Meta, [{'|', UpdateMeta, [ELeft, ERight]}]}, SE, EE};\nexpand_map(Meta, [{'|', _, [_, _]}] = Args, _S, #{context := Context, file := File}) ->\n  file_error(Meta, File, ?MODULE, {update_syntax_in_wrong_context, Context, {'%{}', Meta, Args}});\nexpand_map(Meta, Args, S, E) ->\n  {EArgs, SE, EE} = elixir_expand:expand_args(Args, S, E),\n  validate_kv(Meta, EArgs, Args, E),\n  {{'%{}', Meta, EArgs}, SE, EE}.\n\nexpand_struct(Meta, Left, {'%{}', MapMeta, MapArgs}, S, #{context := Context} = E) ->\n  CleanMapArgs = delete_struct_key(Meta, MapArgs, E),\n  {[ELeft, ERight], SE, EE} = elixir_expand:expand_args([Left, {'%{}', MapMeta, CleanMapArgs}], S, E),\n\n  case validate_struct(ELeft, Context) of\n    true when is_atom(ELeft) ->\n      case ERight of\n        {'%{}', MapMeta, [{'|', _, [_, Assocs]}]} ->\n          assert_and_trace_struct_assocs([{operation, update} | Meta], ELeft, Assocs, E),\n          assert_struct_info_if_not_function(Meta, ELeft, Assocs, EE),\n          {{'%', Meta, [ELeft, ERight]}, SE, EE};\n\n        {'%{}', MapMeta, Assocs} when Context /= match ->\n          AssocKeys = assert_and_trace_struct_assocs(Meta, ELeft, Assocs, EE),\n          Struct = load_struct(Meta, ELeft, Assocs, EE),\n          Keys = ['__struct__'] ++ AssocKeys,\n          WithoutKeys = lists:sort(maps:to_list(maps:without(Keys, Struct))),\n          StructAssocs = elixir_quote:escape(WithoutKeys, escape, false),\n          {{'%', Meta, [ELeft, {'%{}', MapMeta, StructAssocs ++ Assocs}]}, SE, EE};\n\n        {'%{}', MapMeta, Assocs} ->\n          assert_and_trace_struct_assocs([{operation, match} | Meta], ELeft, Assocs, E),\n          assert_struct_info_if_not_function(Meta, ELeft, Assocs, EE),\n          {{'%', Meta, [ELeft, ERight]}, SE, EE}\n      end;\n\n    true ->\n      {{'%', Meta, [ELeft, ERight]}, SE, EE};\n\n    false when Context == match ->\n      file_error(Meta, E, ?MODULE, {invalid_struct_name_in_match, ELeft});\n\n    false ->\n      file_error(Meta, E, ?MODULE, {invalid_struct_name, ELeft})\n  end;\nexpand_struct(Meta, _Left, Right, _S, E) ->\n  file_error(Meta, E, ?MODULE, {non_map_after_struct, Right}).\n\ndelete_struct_key(Meta, [{'|', PipeMeta, [Left, MapAssocs]}], E) ->\n  [{'|', PipeMeta, [Left, delete_struct_key_assoc(Meta, MapAssocs, E)]}];\ndelete_struct_key(Meta, MapAssocs, E) ->\n  delete_struct_key_assoc(Meta, MapAssocs, E).\n\ndelete_struct_key_assoc(Meta, Assocs, E) ->\n  case lists:keytake('__struct__', 1, Assocs) of\n    {value, _, CleanAssocs} ->\n      file_warn(Meta, ?key(E, file), ?MODULE, ignored_struct_key_in_struct),\n      CleanAssocs;\n    false ->\n      Assocs\n  end.\n\nvalidate_match_key(Meta, {Name, _, Context}, E) when is_atom(Name), is_atom(Context) ->\n  file_error(Meta, E, ?MODULE, {invalid_variable_in_map_key_match, Name});\nvalidate_match_key(Meta, {'::', _, [Left, _]}, E) ->\n  validate_match_key(Meta, Left, E);\nvalidate_match_key(_, {'^', _, [{Name, _, Context}]}, _) when is_atom(Name), is_atom(Context) ->\n  ok;\nvalidate_match_key(_, {'%{}', _, [_ | _]}, _) ->\n  ok;\nvalidate_match_key(Meta, {Left, _, Right}, E) ->\n  validate_match_key(Meta, Left, E),\n  validate_match_key(Meta, Right, E);\nvalidate_match_key(Meta, {Left, Right}, E) ->\n  validate_match_key(Meta, Left, E),\n  validate_match_key(Meta, Right, E);\nvalidate_match_key(Meta, List, E) when is_list(List) ->\n  [validate_match_key(Meta, Each, E) || Each <- List];\nvalidate_match_key(_, _, _) ->\n  ok.\n\nvalidate_not_repeated(Meta, Key, Used, E) ->\n  case is_literal(Key) andalso Used of\n    #{Key := true} ->\n      case E of\n        #{context := match} -> function_error(Meta, ?key(E, file), ?MODULE, {repeated_key, Key});\n        _ -> file_warn(Meta, ?key(E, file), ?MODULE, {repeated_key, Key})\n      end,\n      Used;\n\n    #{} ->\n      Used#{Key => true};\n\n    false ->\n      Used\n  end.\n\nis_literal({_, _, _}) -> false;\nis_literal({Left, Right}) -> is_literal(Left) andalso is_literal(Right);\nis_literal([_ | _] = List) -> lists:all(fun is_literal/1, List);\nis_literal(_) -> true.\n\nvalidate_kv(Meta, KV, Original, #{context := Context} = E) ->\n  lists:foldl(fun\n    ({K, _V}, {Index, Used}) ->\n      (Context == match) andalso validate_match_key(Meta, K, E),\n      NewUsed = validate_not_repeated(Meta, K, Used, E),\n      {Index + 1, NewUsed};\n    (_, {Index, _Used}) ->\n      file_error(Meta, E, ?MODULE, {not_kv_pair, lists:nth(Index, Original)})\n  end, {1, #{}}, KV).\n\nvalidate_struct({'^', _, [{Var, _, Ctx}]}, match) when is_atom(Var), is_atom(Ctx) -> true;\nvalidate_struct({Var, _Meta, Ctx}, match) when is_atom(Var), is_atom(Ctx) -> true;\nvalidate_struct(Atom, _) when is_atom(Atom) -> true;\nvalidate_struct(_, _) -> false.\n\nassert_struct_info_if_not_function(Meta, Name, Assocs, #{function := nil} = E) ->\n  case maybe_load_struct_info(Meta, Name, E) of\n    {ok, Info} ->\n      [lists:any(fun(Field) -> ?key(Field, field) =:= Key end, Info) orelse\n         function_error(Meta, E, ?MODULE, {unknown_key_for_struct, Name, Key})\n       || {Key, _} <- Assocs],\n      ok;\n\n    {error, Desc} ->\n      file_error(Meta, E, ?MODULE, Desc)\n  end;\nassert_struct_info_if_not_function(_Meta, _Name, _Assocs, _E) ->\n  ok.\n\nmaybe_load_struct_info(Meta, Name, E) ->\n  try\n    case is_open(Name, Meta, E) andalso lookup_struct_info_from_data_tables(Name) of\n      %% If I am accessing myself and there is no attribute,\n      %% don't invoke the fallback to avoid calling loaded code.\n      false when ?key(E, module) =:= Name -> nil;\n      false -> Name:'__info__'(struct);\n      InfoList -> InfoList\n    end\n  of\n    nil -> {error, struct_undef(Name, E)};\n    Info -> {ok, Info}\n  catch\n    error:undef -> {error, struct_undef(Name, E)}\n  end.\n\nlookup_struct_info_from_data_tables(Module) ->\n  try\n    {Set, _} = elixir_module:data_tables(Module),\n    ets:lookup_element(Set, {elixir, struct}, 2)\n  catch\n    _:_ -> false\n  end.\n\nload_struct(Meta, Name, Assocs, E) ->\n  try\n    maybe_load_struct(Meta, Name, Assocs, E)\n  of\n    {ok, Struct} -> Struct;\n    {error, Desc} -> file_error(Meta, E, ?MODULE, Desc)\n  catch\n    Kind:Reason ->\n      Info = [{Name, '__struct__', 1, [{file, \"expanding struct\"}]},\n              elixir_utils:caller(?line(Meta), ?key(E, file), ?key(E, module), ?key(E, function))],\n      erlang:raise(Kind, Reason, Info)\n  end.\n\nmaybe_load_struct(Meta, Name, Assocs, E) ->\n  try\n    case is_open(Name, Meta, E) andalso elixir_def:external_for(Meta, Name, '__struct__', 1, [def]) of\n      %% If I am accessing myself and there is no __struct__ function,\n      %% don't invoke the fallback to avoid calling loaded code.\n      false when ?key(E, module) =:= Name ->\n        error(undef);\n\n      false ->\n        Name:'__struct__'(Assocs);\n\n      ExternalFun ->\n        %% There is an inherent race condition when using external_for.\n        %% By the time we got to execute the function, the ETS table\n        %% with temporary definitions for the given module may no longer\n        %% be available, so any function invocation happening inside the\n        %% local function will fail. In this case, we need to fall back to\n        %% the regular dispatching since the module will be available if\n        %% the table has not been deleted (unless compilation of that\n        %% module failed which should then cause this call to fail too).\n        try\n          ExternalFun(Assocs)\n        catch\n          error:undef -> Name:'__struct__'(Assocs)\n        end\n    end\n  of\n    #{'__struct__' := Name} = Struct ->\n      [maps:is_key(Key, Struct) orelse\n          function_error(Meta, E, ?MODULE, {unknown_key_for_struct, Name, Key})\n       || {Key, _} <- Assocs],\n      {ok, Struct};\n\n    #{'__struct__' := StructName} when is_atom(StructName) ->\n      {error, {struct_name_mismatch, Name, StructName}};\n\n    Other ->\n      {error, {invalid_struct_return_value, Name, Other}}\n  catch\n    error:undef -> {error, struct_undef(Name, E)}\n  end.\n\nassert_and_trace_struct_assocs(Meta, Name, Assocs, E) ->\n  Keys = [begin\n    is_atom(K) orelse function_error(Meta, E, ?MODULE, {invalid_key_for_struct, K}),\n    K\n  end || {K, _} <- Assocs],\n  elixir_env:trace({struct_expansion, Meta, Name, Keys}, E),\n  Keys.\n\nis_open(Name, Meta, E) ->\n  in_context(Name, E) orelse ((code:ensure_loaded(Name) /= {module, Name}) andalso wait_for_struct(Name, Meta, E)).\n\nin_context(Name, E) ->\n  %% We also include the current module because it won't be present\n  %% in context module in case the module name is defined dynamically.\n  lists:member(Name, [?key(E, module) | ?key(E, context_modules)]).\n\nwait_for_struct(Module, Meta, E) ->\n  (erlang:get(elixir_compiler_info) /= undefined) andalso\n    ('Elixir.Kernel.ErrorHandler':ensure_compiled(Module, struct, hard, elixir_utils:get_line(Meta, E)) =:= found).\n\nstruct_undef(Name, E) ->\n  case in_context(Name, E) andalso (?key(E, function) == nil) of\n    true -> {inaccessible_struct, Name};\n    false -> {undefined_struct, Name}\n  end.\n\nformat_error({update_syntax_in_wrong_context, Context, Expr}) ->\n  io_lib:format(\"cannot use map/struct update syntax in ~ts, got: ~ts\",\n                [Context, 'Elixir.Macro':to_string(Expr)]);\nformat_error({invalid_struct_name_in_match, Expr}) ->\n  Message =\n    \"expected struct name in a match to be a compile time atom, alias or a \"\n    \"variable, got: ~ts\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Expr)]);\nformat_error({invalid_struct_name, Expr}) ->\n  Message = \"expected struct name to be a compile time atom or alias, got: ~ts\",\n  io_lib:format(Message, ['Elixir.Macro':to_string(Expr)]);\nformat_error({invalid_variable_in_map_key_match, Name}) ->\n  Message =\n    \"cannot use variable ~ts as map key inside a pattern. Map keys in patterns can only be literals \"\n    \"(such as atoms, strings, tuples, and the like) or an existing variable matched with the pin operator \"\n    \"(such as ^some_var)\",\n  io_lib:format(Message, [Name]);\nformat_error({repeated_key, Key}) ->\n    io_lib:format(\"key ~ts will be overridden in map\", ['Elixir.Macro':to_string(Key)]);\nformat_error({not_kv_pair, Expr}) ->\n  io_lib:format(\"expected key-value pairs in a map, got: ~ts\",\n                ['Elixir.Macro':to_string(Expr)]);\nformat_error({non_map_after_struct, Expr}) ->\n  io_lib:format(\"expected struct to be followed by a map, got: ~ts\",\n                ['Elixir.Macro':to_string(Expr)]);\nformat_error({struct_name_mismatch, Module, StructName}) ->\n  Name = elixir_aliases:inspect(Module),\n  Message = \"expected struct name returned by ~ts.__struct__/1 to be ~ts, got: ~ts\",\n  io_lib:format(Message, [Name, Name, elixir_aliases:inspect(StructName)]);\nformat_error({invalid_struct_return_value, Module, Value}) ->\n  Message =\n    \"expected ~ts.__struct__/1 to return a map with a :__struct__ key that holds the \"\n    \"name of the struct (atom), got: ~ts\",\n  io_lib:format(Message, [elixir_aliases:inspect(Module), 'Elixir.Kernel':inspect(Value)]);\nformat_error({inaccessible_struct, Module}) ->\n  Message =\n    \"cannot access struct ~ts, the struct was not yet defined or the struct is \"\n    \"being accessed in the same context that defines it\",\n  io_lib:format(Message, [elixir_aliases:inspect(Module)]);\nformat_error({undefined_struct, Module}) ->\n  Name = elixir_aliases:inspect(Module),\n  io_lib:format(\n    \"~ts.__struct__/1 is undefined, cannot expand struct ~ts. \"\n    \"Make sure the struct name is correct. If the struct name exists and is correct \"\n    \"but it still cannot be found, you likely have cyclic module usage in your code\",\n    [Name, Name]);\nformat_error({unknown_key_for_struct, Module, Key}) ->\n  io_lib:format(\"unknown key ~ts for struct ~ts\",\n                ['Elixir.Macro':to_string(Key), elixir_aliases:inspect(Module)]);\nformat_error({invalid_key_for_struct, Key}) ->\n  io_lib:format(\"invalid key ~ts for struct, struct keys must be atoms, got: \",\n                ['Elixir.Macro':to_string(Key)]);\nformat_error(ignored_struct_key_in_struct) ->\n  \"key :__struct__ is ignored when using structs\"."
  },
  {
    "path": "lib/elixir/src/elixir_module.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_module).\n-export([file/1, data_tables/1, is_open/1, mode/1, delete_definition_attributes/6,\n         compile/6, expand_callback/6, format_error/1, compiler_modules/0, exports_md5/3,\n         write_cache/3, read_cache/2, next_counter/1, taint/1, cache_env/1, get_cached_env/1]).\n-include(\"elixir.hrl\").\n-define(counter_attr, {elixir, counter}).\n-define(cache_key, {elixir, cache_env}).\n\n%% Stores modules currently being defined by the compiler\n\ncompiler_modules() ->\n  case erlang:get(elixir_compiler_modules) of\n    undefined -> [];\n    M when is_list(M) -> M\n  end.\n\nput_compiler_modules([]) ->\n  erlang:erase(elixir_compiler_modules);\nput_compiler_modules(M) when is_list(M) ->\n  erlang:put(elixir_compiler_modules, M).\n\nexports_md5(Def, Defmacro, Struct) ->\n  erlang:md5(term_to_binary({lists:sort(Def), lists:sort(Defmacro), Struct}, [deterministic])).\n\n%% Table functions\n\nfile(Module) ->\n  ets:lookup_element(elixir_modules, Module, 4).\n\ndata_tables(Module) ->\n  ets:lookup_element(elixir_modules, Module, 2).\n\nis_open(Module) ->\n  ets:member(elixir_modules, Module).\n\nmode(Module) ->\n  try ets:lookup_element(elixir_modules, Module, 5) of\n    Mode -> Mode\n  catch\n    _:badarg -> closed\n  end.\n\nmake_readonly(Module) ->\n  ets:update_element(elixir_modules, Module, {5, readonly}).\n\ndelete_definition_attributes(#{module := Module}, _, _, _, _, _) ->\n  {DataSet, _} = data_tables(Module),\n  ets:delete(DataSet, doc),\n  ets:delete(DataSet, deprecated),\n  ets:delete(DataSet, impl).\n\nwrite_cache(Module, Key, Value) ->\n  {DataSet, _} = data_tables(Module),\n  ets:insert(DataSet, {{cache, Key}, Value}).\n\nread_cache(Module, Key) ->\n  {DataSet, _} = data_tables(Module),\n  ets:lookup_element(DataSet, {cache, Key}, 2).\n\nnext_counter(nil) -> erlang:unique_integer();\nnext_counter(Module) ->\n  try\n    {DataSet, _} = data_tables(Module),\n    {Module, ets:update_counter(DataSet, ?counter_attr, 1)}\n  catch\n    _:_ -> erlang:unique_integer()\n  end.\n\ntaint(Module) ->\n  try\n    {DataSet, _} = data_tables(Module),\n    ets:insert(DataSet, [{{elixir, taint}}]),\n    true\n  catch\n    _:_ -> false\n  end.\n\ncache_env(#{line := Line, module := Module} = E) ->\n  {Set, _} = data_tables(Module),\n  Cache = elixir_env:reset_vars(E#{line := nil}),\n  PrevKey = ets:lookup_element(Set, ?cache_key, 2),\n\n  Pos =\n    case ets:lookup(Set, {cache_env, PrevKey}) of\n      [{_, Cache}] ->\n        PrevKey;\n      _ ->\n        NewKey = PrevKey + 1,\n        ets:insert(Set, [{{cache_env, NewKey}, Cache}, {?cache_key, NewKey}]),\n        NewKey\n    end,\n\n  {Module, {Line, Pos}}.\n\nget_cached_env({Module, {Line, Pos}}) ->\n  {Set, _} = data_tables(Module),\n  (ets:lookup_element(Set, {cache_env, Pos}, 2))#{line := Line};\nget_cached_env(Env) ->\n  Env.\n\n%% Compilation hook\n\ncompile(Meta, Module, Block, Vars, Prune, Env) ->\n  ModuleAsCharlist = validate_module_name(Module),\n  #{function := Function, versioned_vars := OldVerVars} = Env,\n\n  {VerVars, _} =\n    lists:mapfoldl(fun({Var, _}, I) -> {{Var, I}, I + 1} end, 0, maps:to_list(OldVerVars)),\n\n  BaseEnv = Env#{module := Module, versioned_vars := maps:from_list(VerVars)},\n\n  MaybeLexEnv =\n    case Function of\n      nil -> BaseEnv;\n      _   -> BaseEnv#{lexical_tracker := nil, tracers := [], function := nil}\n    end,\n\n  case MaybeLexEnv of\n    #{lexical_tracker := nil} ->\n      elixir_lexical:run(\n        MaybeLexEnv,\n        fun(LexEnv) -> compile(Meta, Module, ModuleAsCharlist, Block, Vars, Prune, LexEnv) end,\n        fun(_LexEnv) -> ok end\n      );\n    _ ->\n      compile(Meta, Module, ModuleAsCharlist, Block, Vars, Prune, MaybeLexEnv)\n  end.\n\nvalidate_module_name(Module) when Module == nil; is_boolean(Module); not is_atom(Module) ->\n  invalid_module_name(Module);\nvalidate_module_name(Module) ->\n  Charlist = atom_to_list(Module),\n  case lists:any(fun(Char) -> (Char =:= $/) or (Char =:= $\\\\) end, Charlist) of\n    true -> invalid_module_name(Module);\n    false -> Charlist\n  end.\n\ninvalid_module_name(Module) ->\n  %% We raise an argument error to keep it close to Elixir errors before it starts.\n  erlang:error('Elixir.ArgumentError':exception(\n    <<\"invalid module name: \",\n      ('Elixir.Kernel':inspect(Module))/binary>>\n  )).\n\ncompile(Meta, Module, ModuleAsCharlist, Block, Vars, Prune, E) ->\n  Anno = ?ann(Meta),\n  Line = erl_anno:line(Anno),\n\n  File = ?key(E, file),\n  check_module_availability(Module, Line, E),\n  elixir_env:trace(defmodule, E),\n\n  CompilerModules = compiler_modules(),\n  {Tables, Ref} = build(Module, Line, File, E),\n  {DataSet, DataBag} = Tables,\n\n  try\n    put_compiler_modules([Module | CompilerModules]),\n    {Result, ModuleE, CallbackE} = eval_form(Line, Module, DataBag, Block, Vars, Prune, E),\n    CheckerInfo = checker_info(),\n    {BeamLocation, Forceload} = beam_location(ModuleAsCharlist),\n\n    {Binary, PersistedAttributes, Autoload} =\n      elixir_erl_compiler:spawn(fun() ->\n        PersistedAttributes = ets:lookup_element(DataBag, persisted_attributes, 2),\n        Attributes = attributes(DataSet, DataBag, PersistedAttributes),\n        AllDefinitions = elixir_def:fetch_definitions(Module, E),\n\n        OnLoadAttribute = lists:keyfind(on_load, 1, Attributes),\n        validate_on_load_attribute(OnLoadAttribute, AllDefinitions, DataBag, Line, E),\n\n        DialyzerAttribute = lists:keyfind(dialyzer, 1, Attributes),\n        validate_dialyzer_attribute(DialyzerAttribute, AllDefinitions, Line, E),\n\n        NifsAttribute = lists:keyfind(nifs, 1, Attributes),\n        validate_nifs_attribute(NifsAttribute, AllDefinitions, Line, E),\n        elixir_import:ensure_no_local_conflict(Module, AllDefinitions, E),\n        make_readonly(Module),\n\n        (not elixir_config:is_bootstrap()) andalso\n         'Elixir.Module':'__check_attributes__'(E, DataSet, DataBag),\n\n        AfterVerify = bag_lookup_element(DataBag, {accumulate, after_verify}, 2),\n        [elixir_env:trace({remote_function, [{line, Line}], VerifyMod, VerifyFun, 1}, CallbackE) ||\n         {VerifyMod, VerifyFun} <- AfterVerify],\n\n        %% Ensure there are no errors before we infer types\n        compile_error_if_tainted(DataSet, E),\n\n        {Signatures, Unreachable} =\n          case elixir_config:is_bootstrap() of\n            true -> {#{}, []};\n            false ->\n              UsedPrivate = bag_lookup_element(DataBag, used_private, 2),\n              'Elixir.Module.Types':infer(Module, File, Attributes, AllDefinitions, UsedPrivate, E, CheckerInfo)\n          end,\n\n        RawCompileOpts = bag_lookup_element(DataBag, {accumulate, compile}, 2),\n        CompileOpts = validate_compile_opts(RawCompileOpts, AllDefinitions, Unreachable, Line, E),\n        Impls = bag_lookup_element(DataBag, impls, 2),\n\n        Struct = get_struct(DataSet),\n        set_exports_md5(DataSet, AllDefinitions, Struct),\n\n        ModuleMap = #{\n          struct => Struct,\n          module => Module,\n          anno => Anno,\n          file => File,\n          relative_file => elixir_utils:relative_to_cwd(File),\n          attributes => Attributes,\n          definitions => AllDefinitions,\n          after_verify => AfterVerify,\n          compile_opts => CompileOpts,\n          deprecated => get_deprecated(DataBag),\n          defines_behaviour => defines_behaviour(DataBag),\n          impls => Impls,\n          unreachable => Unreachable\n        },\n\n        compile_error_if_tainted(DataSet, E),\n        Binary = elixir_erl:compile(ModuleMap, Signatures),\n        Autoload = Forceload or proplists:get_value(autoload, CompileOpts, false),\n        spawn_parallel_checker(CheckerInfo, Module, ModuleMap, Signatures, BeamLocation),\n        {Binary, PersistedAttributes, Autoload}\n      end),\n\n    Autoload andalso code:load_binary(Module, BeamLocation, Binary),\n    make_module_available(Module, Binary, Autoload),\n    put_compiler_modules(CompilerModules),\n    eval_callbacks(Line, DataBag, after_compile, [CallbackE, Binary], CallbackE),\n    elixir_env:trace({on_module, Binary, none}, ModuleE),\n    warn_unused_attributes(DataSet, DataBag, PersistedAttributes, E),\n    (element(2, CheckerInfo) == nil) andalso\n      [VerifyMod:VerifyFun(Module) ||\n       {VerifyMod, VerifyFun} <- bag_lookup_element(DataBag, {accumulate, after_verify}, 2)],\n    {module, Module, Binary, Result}\n  catch\n    error:undef:Stacktrace ->\n      case Stacktrace of\n        [{Module, Fun, Args, _Info} | _] = Stack when is_list(Args) ->\n          compile_undef(Module, Fun, length(Args), Stack);\n        [{Module, Fun, Arity, _Info} | _] = Stack ->\n          compile_undef(Module, Fun, Arity, Stack);\n        Stack ->\n          erlang:raise(error, undef, Stack)\n      end\n  after\n    put_compiler_modules(CompilerModules),\n    ets:delete(DataSet),\n    ets:delete(DataBag),\n    elixir_code_server:call({undefmodule, Ref})\n  end.\n\ncompile_error_if_tainted(DataSet, E) ->\n  case ets:member(DataSet, {elixir, taint}) of\n    true -> elixir_errors:compile_error(E);\n    false -> ok\n  end.\n\nset_exports_md5(DataSet, AllDefinitions, Struct) ->\n  {Funs, Macros} =\n    lists:foldl(fun\n      ({Tuple, def, _Meta, _Clauses}, {Funs, Macros}) -> {[Tuple | Funs], Macros};\n      ({Tuple, defmacro, _Meta, _Clauses}, {Funs, Macros}) -> {Funs, [Tuple | Macros]};\n      ({_Tuple, _Kind, _Meta, _Clauses}, {Funs, Macros}) -> {Funs, Macros}\n    end, {[], []}, AllDefinitions),\n  MD5 = exports_md5(Funs, Macros, Struct),\n  ets:insert(DataSet, {exports_md5, MD5, nil, []}).\n\nvalidate_compile_opts(Opts, Defs, Unreachable, Line, E) ->\n  lists:flatmap(fun (Opt) -> validate_compile_opt(Opt, Defs, Unreachable, Line, E) end, Opts).\n\n%% TODO: Make this an error on v2.0\nvalidate_compile_opt({parse_transform, Module} = Opt, _Defs, _Unreachable, Line, E) ->\n  elixir_errors:file_warn([{line, Line}], E, ?MODULE, {parse_transform, Module}),\n  [Opt];\nvalidate_compile_opt({inline, Inlines}, Defs, Unreachable, Line, E) ->\n  case validate_inlines(Inlines, Defs, Unreachable, []) of\n    {ok, []} ->\n      [];\n    {ok, FilteredInlines} ->\n      [{inline, FilteredInlines}];\n    {error, Reason} ->\n      elixir_errors:module_error([{line, Line}], E, ?MODULE, Reason),\n      []\n  end;\nvalidate_compile_opt(Opt, Defs, Unreachable, Line, E) when is_list(Opt) ->\n  validate_compile_opts(Opt, Defs, Unreachable, Line, E);\nvalidate_compile_opt(Opt, _Defs, _Unreachable, _Line, _E) ->\n  [Opt].\n\nvalidate_inlines([Inline | Inlines], Defs, Unreachable, Acc) ->\n  case lists:keyfind(Inline, 1, Defs) of\n    false ->\n      {error, {undefined_function, {compile, inline}, Inline}};\n    {_Def, Kind, _Meta, _Clauses} when Kind == defmacro; Kind == defmacrop ->\n      {error, {bad_macro, {compile, inline}, Inline}};\n    _ ->\n      case lists:member(Inline, Unreachable) of\n        true -> validate_inlines(Inlines, Defs, Unreachable, Acc);\n        false -> validate_inlines(Inlines, Defs, Unreachable, [Inline | Acc])\n      end\n  end;\nvalidate_inlines([], _Defs, _Unreachable, Acc) -> {ok, Acc}.\n\nvalidate_on_load_attribute({on_load, Def}, Defs, Bag, Line, E) ->\n  case lists:keyfind(Def, 1, Defs) of\n    false ->\n      elixir_errors:module_error([{line, Line}], E, ?MODULE, {undefined_function, on_load, Def});\n    {_Def, Kind, _Meta, _Clauses} when Kind == defmacro; Kind == defmacrop ->\n      elixir_errors:module_error([{line, Line}], E, ?MODULE, {bad_macro, on_load, Def});\n    {{Name, Arity}, Kind, _Meta, _Clauses} ->\n      elixir_env:trace({local_function, [{line, Line}], Name, Arity}, E),\n      (Kind == defp) andalso ets:insert(Bag, {used_private, Def})\n  end;\nvalidate_on_load_attribute(false, _Defs, _Bag, _Line, _E) -> ok.\n\nvalidate_dialyzer_attribute({dialyzer, Dialyzer}, Defs, Line, E) ->\n  [validate_definition({dialyzer, Key}, Fun, Defs, Line, E)\n   || {Key, Funs} <- lists:flatten([Dialyzer]), Fun <- lists:flatten([Funs])];\nvalidate_dialyzer_attribute(false, _Defs, _Line, _E) ->\n  ok.\n\nvalidate_nifs_attribute({nifs, Funs}, Defs, Line, E) ->\n  [validate_definition(nifs, Fun, Defs, Line, E) || Fun <- lists:flatten([Funs])];\nvalidate_nifs_attribute(false, _Defs, _Line, _E) ->\n  ok.\n\nvalidate_definition(Key, Fun, Defs, Line, E) ->\n  case lists:keyfind(Fun, 1, Defs) of\n    false ->\n      elixir_errors:module_error([{line, Line}], E, ?MODULE, {undefined_function, Key, Fun});\n    {Fun, Type, _Meta, _Clauses} when Type == defmacro; Type == defmacrop ->\n      elixir_errors:module_error([{line, Line}], E, ?MODULE, {bad_macro, Key, Fun});\n    _ ->\n      ok\n   end.\n\ndefines_behaviour(DataBag) ->\n  ets:member(DataBag, {accumulate, callback}) orelse ets:member(DataBag, {accumulate, macrocallback}).\n\n%% An undef error for a function in the module being compiled might result in an\n%% exception message suggesting the current module is not loaded. This is\n%% misleading so use a custom reason.\ncompile_undef(Module, Fun, Arity, Stack) ->\n  case elixir_config:is_bootstrap() of\n    false ->\n      Opts = [{module, Module}, {function, Fun}, {arity, Arity},\n              {reason, 'function not available'}],\n      Exception = 'Elixir.UndefinedFunctionError':exception(Opts),\n      erlang:raise(error, Exception, Stack);\n    true ->\n      erlang:raise(error, undef, Stack)\n  end.\n\n%% Handle reserved modules and duplicates.\n\ncheck_module_availability(Module, Line, E) ->\n  Reserved = ['Elixir.True', 'Elixir.False', 'Elixir.Nil',\n              'Elixir.Any', 'Elixir.BitString', 'Elixir.PID',\n              'Elixir.Reference', 'Elixir.Elixir', 'Elixir'],\n\n  case lists:member(Module, Reserved) of\n    true  -> elixir_errors:file_error([{line, Line}], E, ?MODULE, {module_reserved, Module});\n    false -> ok\n  end,\n\n  case elixir_config:get(ignore_module_conflict) of\n    false ->\n      case code:ensure_loaded(Module) of\n        {module, _} ->\n          elixir_errors:file_warn([{line, Line}], E, ?MODULE, {module_defined, Module});\n        {error, _}  ->\n          ok\n      end;\n    true ->\n      ok\n  end.\n\n%% Hook that builds both attribute and functions and set up common hooks.\n\nbuild(Module, Line, File, E) ->\n  %% In the set table we store:\n  %%\n  %% * {Attribute, Value, AccumulateOrUnsetOrReadOrUnreadline, TraceLineOrNil}\n  %% * {{elixir, ...}, ...}\n  %% * {{cache, ...}, ...}\n  %% * {{function, Tuple}, ...}, {{macro, Tuple}, ...}\n  %% * {{type, Tuple}, ...}, {{opaque, Tuple}, ...}\n  %% * {{callback, Tuple}, ...}, {{macrocallback, Tuple}, ...}\n  %% * {{def, Tuple}, ...} (from elixir_def)\n  %% * {{overridable, Tuple}, ...} (from elixir_overridable)\n  %%\n  DataSet = ets:new(Module, [set, public]),\n\n  %% In the bag table we store:\n  %%\n  %% * {{accumulate, Attribute}, ...} (includes typespecs)\n  %% * {warn_attributes, ...}\n  %% * {impls, ...}\n  %% * {deprecated, ...}\n  %% * {persisted_attributes, ...}\n  %% * {defs, ...} (from elixir_def)\n  %% * {overridables, ...} (from elixir_overridable)\n  %% * {{default, Name}, ...} (from elixir_def)\n  %% * {{clauses, Tuple}, ...} (from elixir_def)\n  %%\n  DataBag = ets:new(Module, [duplicate_bag, public]),\n\n  ets:insert(DataSet, [\n    % {Key, Value, ReadOrUnreadLine, TraceLine}\n    {moduledoc, nil, nil, []},\n\n    % {Key, Value, accumulate, TraceLine}\n    {after_compile, [], accumulate, []},\n    {after_verify, [], accumulate, []},\n    {before_compile, [], accumulate, []},\n    {behaviour, [], accumulate, []},\n    {compile, [], accumulate, []},\n    {derive, [], accumulate, []},\n    {dialyzer, [], accumulate, []},\n    {external_resource, [], accumulate, []},\n    {nifs, [], accumulate, []},\n    {on_definition, [], accumulate, []},\n    {opaque, [], accumulate, []},\n    {type, [], accumulate, []},\n    {typep, [], accumulate, []},\n    {spec, [], accumulate, []},\n    {callback, [], accumulate, []},\n    {macrocallback, [], accumulate, []},\n    {optional_callbacks, [], accumulate, []},\n\n    % Others\n    {?cache_key, 0},\n    {?counter_attr, 0}\n  ]),\n\n  Persisted = [behaviour, dialyzer, external_resource, nifs, on_load, vsn],\n  ets:insert(DataBag, [{persisted_attributes, Attr} || Attr <- Persisted]),\n\n  OnDefinition =\n    case elixir_config:is_bootstrap() of\n      false -> {'Elixir.Module', compile_definition_attributes};\n      _ -> {elixir_module, delete_definition_attributes}\n    end,\n  ets:insert(DataBag, {{accumulate, on_definition}, OnDefinition}),\n\n  %% Setup definition related modules\n  Tables = {DataSet, DataBag},\n  elixir_def:setup(Tables),\n  Tuple = {Module, Tables, Line, File, all},\n\n  Ref =\n    case elixir_code_server:call({defmodule, Module, self(), Tuple}) of\n      {ok, ModuleRef} ->\n        ModuleRef;\n      {error, {Module, _, OldLine, OldFile, _}} ->\n        ets:delete(DataSet),\n        ets:delete(DataBag),\n        Error = {module_in_definition, Module, OldFile, OldLine},\n        elixir_errors:file_error([{line, Line}], E, ?MODULE, Error)\n    end,\n\n  {Tables, Ref}.\n\n%% Handles module and callback evaluations.\n\neval_form(Line, Module, DataBag, Block, Vars, Prune, E) ->\n  %% Given Elixir modules can get very long to compile due to metaprogramming,\n  %% we disable expansions that have linear time to code size.\n  {Value, ExS, EE} =\n    case elixir_config:get(module_definition) of\n      interpreted -> elixir_compiler:interpret(Block, Vars, E);\n      compiled -> elixir_compiler:compile(Block, Vars, [no_bool_opt, no_ssa_opt], E)\n    end,\n  elixir_overridable:store_not_overridden(Module),\n  EV = (elixir_env:reset_vars(EE))#{line := Line},\n  EC = eval_callbacks(Line, DataBag, before_compile, [EV], EV),\n  elixir_overridable:store_not_overridden(Module),\n  {Value, maybe_prune_versioned_vars(Prune, Vars, ExS, E), EC}.\n\nmaybe_prune_versioned_vars(false, _Vars, _Exs, E) ->\n  E;\nmaybe_prune_versioned_vars(true, Vars, ExS, E) ->\n  PruneBefore = length(Vars),\n  #elixir_ex{vars={ExVars, _}, unused={Unused, _}} = ExS,\n\n  VersionedVars =\n    maps:filter(fun\n      (Pair, Version) when Version < PruneBefore, not is_map_key({Pair, Version}, Unused) -> false;\n      (_, _) -> true\n    end, ExVars),\n\n  E#{versioned_vars := VersionedVars}.\n\neval_callbacks(Line, DataBag, Name, Args, E) ->\n  Callbacks = bag_lookup_element(DataBag, {accumulate, Name}, 2),\n  lists:foldl(fun({M, F}, Acc) ->\n    expand_callback(Line, M, F, Args, Acc, fun(AM, AF, AA) -> apply(AM, AF, AA) end)\n  end, E, Callbacks).\n\nexpand_callback(Line, M, F, Args, Acc, Fun) ->\n  E = elixir_env:reset_vars(Acc),\n  S = elixir_env:env_to_ex(E),\n  Meta = [{line, Line}, {required, true}],\n\n  {EE, _S, ET} =\n    elixir_dispatch:dispatch_require(Meta, M, F, Args, S, E, fun(AM, AF) ->\n      Fun(AM, AF, Args),\n      {ok, S, E}\n    end),\n\n  if\n    is_atom(EE) ->\n      ET;\n    true ->\n      try\n        {_Value, _Binding, EF} = elixir:eval_forms(EE, [], ET),\n        EF\n      catch\n        Kind:Reason:Stacktrace ->\n          Info = {M, F, length(Args), location(Line, E)},\n          erlang:raise(Kind, Reason, prune_stacktrace(Info, Stacktrace))\n      end\n  end.\n\n%% Add attributes handling to the form\n\nattributes(DataSet, DataBag, PersistedAttributes) ->\n  [{Key, Value} || Key <- PersistedAttributes, Value <- lookup_attribute(DataSet, DataBag, Key)].\n\nlookup_attribute(DataSet, DataBag, Key) when is_atom(Key) ->\n  case ets:lookup(DataSet, Key) of\n    [{_, _, accumulate, _}] -> bag_lookup_element(DataBag, {accumulate, Key}, 2);\n    [{_, _, unset, _}] -> [];\n    [{_, Value, _, _}] -> [Value];\n    [] -> []\n  end.\n\nwarn_unused_attributes(DataSet, DataBag, PersistedAttrs, E) ->\n  StoredAttrs = bag_lookup_element(DataBag, warn_attributes, 2),\n  %% This is the same list as in Module.put_attribute\n  %% without moduledoc which are never warned on.\n  Attrs = [doc, typedoc, impl, deprecated | StoredAttrs -- PersistedAttrs],\n  Query = [{{Attr, '_', '$1', '_'}, [{is_integer, '$1'}], [[Attr, '$1']]} || Attr <- Attrs],\n  [elixir_errors:file_warn([{line, Line}], E, ?MODULE, {unused_attribute, Key})\n   || [Key, Line] <- ets:select(DataSet, Query)].\n\nget_struct(Set) ->\n  case ets:lookup(Set, {elixir, struct}) of\n    [] -> nil;\n    [{_, Fields}] -> Fields\n  end.\n\nget_deprecated(Bag) ->\n  lists:usort(bag_lookup_element(Bag, deprecated, 2)).\n\nbag_lookup_element(Table, Name, Pos) ->\n  try\n    ets:lookup_element(Table, Name, Pos)\n  catch\n    error:badarg -> []\n  end.\n\nbeam_location(ModuleAsCharlist) ->\n  case get(elixir_compiler_dest) of\n    {Dest, Forceload} when is_binary(Dest) ->\n      {filename:join(elixir_utils:characters_to_list(Dest), ModuleAsCharlist ++ \".beam\"),\n       Forceload};\n    _ ->\n      {\"\", true}\n  end.\n\n%% Integration with elixir_compiler that makes the module available\n\nchecker_info() ->\n  case get(elixir_checker_info) of\n    undefined -> {self(), nil};\n    _ -> 'Elixir.Module.ParallelChecker':get()\n  end.\n\nspawn_parallel_checker({_, nil}, _Module, _ModuleMap, _Signatures, _BeamLocation) ->\n  ok;\nspawn_parallel_checker(CheckerInfo, Module, ModuleMap, Signatures, BeamLocation) ->\n  Log =\n    case erlang:get(elixir_code_diagnostics) of\n      {_, false} -> false;\n      _ -> true\n    end,\n  'Elixir.Module.ParallelChecker':spawn(CheckerInfo, Module, ModuleMap, Signatures, BeamLocation, Log).\n\nmake_module_available(Module, Binary, Loaded) ->\n  case get(elixir_module_binaries) of\n    Current when is_list(Current) ->\n      put(elixir_module_binaries, [{Module, Binary} | Current]);\n    _ ->\n      ok\n  end,\n\n  case get(elixir_compiler_info) of\n    undefined ->\n      ok;\n    {PID, _} ->\n      Ref = make_ref(),\n      PID ! {module_available, self(), Ref, get(elixir_compiler_file), Module, Binary, Loaded},\n      receive {Ref, ack} -> ok end\n  end.\n\n%% Error handling and helpers.\n\n%% We've reached the elixir_module or eval internals, skip it with the rest\nprune_stacktrace(Info, [{elixir, eval_forms, _, _} | _]) ->\n  [Info];\nprune_stacktrace(Info, [{elixir_module, _, _, _} | _]) ->\n  [Info];\nprune_stacktrace(Info, [H | T]) ->\n  [H | prune_stacktrace(Info, T)];\nprune_stacktrace(Info, []) ->\n  [Info].\n\nlocation(Line, E) ->\n  [{file, elixir_utils:characters_to_list(?key(E, file))}, {line, Line}].\n\nformat_error({unused_attribute, typedoc}) ->\n  \"module attribute @typedoc was set but no type follows it\";\nformat_error({unused_attribute, doc}) ->\n  \"module attribute @doc was set but no definition follows it\";\nformat_error({unused_attribute, impl}) ->\n  \"module attribute @impl was set but no definition follows it\";\nformat_error({unused_attribute, deprecated}) ->\n  \"module attribute @deprecated was set but no definition follows it\";\nformat_error({unused_attribute, Attr}) ->\n  io_lib:format(\"module attribute @~ts was set but never used\", [Attr]);\nformat_error({module_defined, Module}) ->\n  Extra =\n    case code:which(Module) of\n      \"\" ->\n        \" (current version defined in memory)\";\n      Path when is_list(Path) ->\n        io_lib:format(\" (current version loaded from ~ts)\", [elixir_utils:relative_to_cwd(Path)]);\n      _ ->\n        \"\"\n    end,\n  io_lib:format(\"redefining module ~ts~ts\", [elixir_aliases:inspect(Module), Extra]);\nformat_error({module_reserved, Module}) ->\n  io_lib:format(\"module ~ts is reserved and cannot be defined\", [elixir_aliases:inspect(Module)]);\nformat_error({module_in_definition, Module, File, Line}) ->\n  io_lib:format(\"cannot define module ~ts because it is currently being defined in ~ts:~B\",\n    [elixir_aliases:inspect(Module), elixir_utils:relative_to_cwd(File), Line]);\nformat_error({undefined_function, {Attr, Key}, {Name, Arity}}) ->\n  io_lib:format(\"undefined function ~ts/~B given to @~ts :~ts\", [Name, Arity, Attr, Key]);\nformat_error({undefined_function, Attr, {Name, Arity}}) ->\n  io_lib:format(\"undefined function ~ts/~B given to @~ts\", [Name, Arity, Attr]);\nformat_error({bad_macro, {Attr, Key}, {Name, Arity}}) ->\n  io_lib:format(\"macro ~ts/~B given to @~ts :~ts (only functions are supported)\", [Name, Arity, Attr, Key]);\nformat_error({bad_macro, Attr, {Name, Arity}}) ->\n  io_lib:format(\"macro ~ts/~B given to @~ts (only functions are supported)\", [Name, Arity, Attr]);\nformat_error({parse_transform, Module}) ->\n  io_lib:format(\"@compile {:parse_transform, ~ts} is deprecated. Elixir will no longer support \"\n                \"Erlang-based transforms in future versions\", [elixir_aliases:inspect(Module)]).\n"
  },
  {
    "path": "lib/elixir/src/elixir_overridable.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n% Holds the logic responsible for defining overridable functions and handling super.\n-module(elixir_overridable).\n-export([overridables_for/1, overridable_for/2,\n         record_overridable/3, super/4,\n         store_not_overridden/1, format_error/1]).\n-include(\"elixir.hrl\").\n-define(overridden_pos, 4).\n\noverridables_for(Module) ->\n  {_, Bag} = elixir_module:data_tables(Module),\n  try\n    ets:lookup_element(Bag, overridables, 2)\n  catch\n    _:_ -> []\n  end.\n\noverridable_for(Module, Tuple) ->\n  {Set, _} = elixir_module:data_tables(Module),\n\n  case ets:lookup(Set, {overridable, Tuple}) of\n    [Overridable] -> Overridable;\n    [] -> not_overridable\n  end.\n\nrecord_overridable(Module, Tuple, Def) ->\n  {Set, Bag} = elixir_module:data_tables(Module),\n\n  case ets:insert_new(Set, {{overridable, Tuple}, 1, Def, false}) of\n    true ->\n      ets:insert(Bag, {overridables, Tuple});\n    false ->\n      [{_, Count, PreviousDef, _}] = ets:lookup(Set, {overridable, Tuple}),\n      {{_, Kind, Meta, File, _, _}, _} = Def,\n      {{_, PreviousKind, _, _, _, _}, _} = PreviousDef,\n\n      case is_valid_kind(Kind, PreviousKind) of\n        true ->\n          ets:insert(Set, {{overridable, Tuple}, Count + 1, Def, false});\n        false ->\n          elixir_errors:file_error(Meta, File, ?MODULE, {bad_kind, Module, Tuple, Kind})\n      end\n  end,\n\n  ok.\n\nsuper(Meta, Module, Tuple, E) ->\n  {Set, _} = elixir_module:data_tables(Module),\n\n  case ets:lookup(Set, {overridable, Tuple}) of\n    [Overridable] ->\n      store(Set, Module, Tuple, Overridable, true);\n    [] ->\n      elixir_errors:file_error(Meta, E, ?MODULE, {no_super, Module, Tuple})\n  end.\n\nstore_not_overridden(Module) ->\n  {Set, Bag} = elixir_module:data_tables(Module),\n\n  lists:foreach(fun({_, Tuple}) ->\n    [Overridable] = ets:lookup(Set, {overridable, Tuple}),\n\n    case ets:lookup(Set, {def, Tuple}) of\n      [] ->\n        store(Set, Module, Tuple, Overridable, false);\n      [{_, Kind, Meta, File, _, _}] ->\n        {{_, OverridableKind, _, _, _, _}, _} = element(3, Overridable),\n\n        case is_valid_kind(Kind, OverridableKind) of\n          true -> ok;\n          false -> elixir_errors:file_error(Meta, File, ?MODULE, {bad_kind, Module, Tuple, Kind})\n        end\n    end\n  end, ets:lookup(Bag, overridables)).\n\n%% Private\n\nstore(Set, Module, Tuple, {_, Count, Def, Overridden}, Hidden) ->\n  {{{def, {Name, Arity}}, Kind, BaseMeta, File, _Check,\n   {Defaults, _HasBody, _LastDefaults}}, Clauses} = Def,\n  Meta = [{from_super, Hidden} | BaseMeta],\n\n  {FinalKind, FinalName, FinalArity, FinalClauses} =\n    case Hidden of\n      false ->\n        {Kind, Name, Arity, Clauses};\n      true when Kind == defmacro; Kind == defmacrop ->\n        {defmacrop, name(Name, Count), Arity, Clauses};\n      true ->\n        {defp, name(Name, Count), Arity, Clauses}\n    end,\n\n  case Overridden of\n    false ->\n      ets:update_element(Set, {overridable, Tuple}, {?overridden_pos, true}),\n      elixir_def:store_definition(false, FinalKind, Meta, FinalName, FinalArity,\n                                  File, Module, Defaults, FinalClauses);\n    true ->\n      ok\n  end,\n\n  {FinalKind, FinalName, Meta}.\n\nname(Name, Count) when is_integer(Count) ->\n  list_to_atom(atom_to_list(Name) ++ \" (overridable \" ++ integer_to_list(Count) ++ \")\").\n\nis_valid_kind(NewKind, PreviousKind) ->\n  is_macro(NewKind) =:= is_macro(PreviousKind).\n\nis_macro(defmacro) -> true;\nis_macro(defmacrop) -> true;\nis_macro(_) -> false.\n\n%% Error handling\nformat_error({bad_kind, Module, {Name, Arity}, Kind}) ->\n  case is_macro(Kind) of\n    true ->\n      io_lib:format(\"cannot override function (def, defp) ~ts/~B in module ~ts as a macro (defmacro, defmacrop)\",\n        [Name, Arity, elixir_aliases:inspect(Module)]);\n    false ->\n      io_lib:format(\"cannot override macro (defmacro, defmacrop) ~ts/~B in module ~ts as a function (def, defp)\",\n        [Name, Arity, elixir_aliases:inspect(Module)])\n  end;\n\nformat_error({no_super, Module, {Name, Arity}}) ->\n  Bins   = [format_fa(Tuple) || Tuple <- overridables_for(Module)],\n  Joined = 'Elixir.Enum':join(Bins, <<\", \">>),\n  io_lib:format(\"no super defined for ~ts/~B in module ~ts. Overridable functions available are: ~ts\",\n    [Name, Arity, elixir_aliases:inspect(Module), Joined]).\n\nformat_fa({Name, Arity}) ->\n  A = 'Elixir.Macro':inspect_atom(remote_call, Name),\n  B = integer_to_binary(Arity),\n  <<A/binary, $/, B/binary>>.\n"
  },
  {
    "path": "lib/elixir/src/elixir_parser.yrl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% REUSE-IgnoreStart\nHeader \"%% SPDX-License-Identifier: Apache-2.0\"\n\"%% SPDX-FileCopyrightText: 2021 The Elixir Team\"\n\"%% SPDX-FileCopyrightText: 2012 Plataformatec\".\n%% REUSE-IgnoreEnd\n\nNonterminals\n  grammar expr_list\n  expr container_expr block_expr access_expr\n  no_parens_expr no_parens_zero_expr no_parens_one_expr no_parens_one_ambig_expr\n  bracket_expr bracket_at_expr bracket_arg matched_expr unmatched_expr sub_matched_expr\n  unmatched_op_expr matched_op_expr no_parens_op_expr no_parens_many_expr\n  comp_op_eol at_op_eol unary_op_eol and_op_eol or_op_eol capture_op_eol\n  dual_op_eol mult_op_eol power_op_eol concat_op_eol xor_op_eol pipe_op_eol\n  stab_op_eol arrow_op_eol match_op_eol when_op_eol in_op_eol in_match_op_eol\n  type_op_eol rel_op_eol range_op_eol ternary_op_eol\n  open_paren close_paren empty_paren eoe\n  list list_args open_bracket close_bracket\n  tuple open_curly close_curly\n  bitstring open_bit close_bit\n  map map_op map_base_expr map_close map_args\n  assoc_op_eol assoc_expr assoc_base assoc assoc_update assoc_update_kw\n  container_args_base container_args\n  call_args_parens_expr call_args_parens_base call_args_parens parens_call\n  call_args_no_parens_one call_args_no_parens_ambig call_args_no_parens_expr\n  call_args_no_parens_comma_expr call_args_no_parens_all call_args_no_parens_many\n  call_args_no_parens_many_strict\n  stab stab_eoe stab_expr stab_op_eol_and_expr stab_parens_many\n  kw_eol kw_base kw_data kw_call call_args_no_parens_kw_expr call_args_no_parens_kw\n  dot_op dot_alias dot_bracket_identifier dot_call_identifier\n  dot_identifier dot_op_identifier dot_do_identifier dot_paren_identifier\n  do_block fn_eoe do_eoe block_eoe block_item block_list\n  .\n\nTerminals\n  identifier kw_identifier kw_identifier_safe kw_identifier_unsafe bracket_identifier\n  paren_identifier do_identifier block_identifier op_identifier\n  fn 'end' alias\n  atom atom_quoted atom_safe atom_unsafe bin_string list_string sigil\n  bin_heredoc list_heredoc\n  comp_op at_op unary_op and_op or_op arrow_op match_op in_op in_match_op ellipsis_op\n  type_op dual_op mult_op power_op concat_op range_op xor_op pipe_op stab_op when_op\n  capture_int capture_op assoc_op rel_op ternary_op dot_call_op\n  'true' 'false' 'nil' 'do' eol ';' ',' '.'\n  '(' ')' '[' ']' '{' '}' '<<' '>>' '%{}' '%'\n  int flt char\n  .\n\nRootsymbol grammar.\n\n%% Two shift/reduce conflicts coming from call_args_parens and\n%% one coming from empty_paren on stab.\nExpect 3.\n\n%% Changes in ops and precedence should be reflected on:\n%%\n%%   1. lib/elixir/lib/code/identifier.ex\n%%   2. lib/elixir/pages/operators.md\n%%   3. lib/iex/lib/iex/evaluator.ex\n%%\n%% Note though the operator => in practice has lower precedence\n%% than all others, its entry in the table is only to support the\n%% %{user | foo => bar} syntax.\n\nLeft       5 do.\nRight     10 stab_op_eol.     %% ->\nLeft      20 ','.\nLeft      40 in_match_op_eol. %% <-, \\\\ (allowed in matches along =)\nRight     50 when_op_eol.     %% when\nRight     60 type_op_eol.     %% ::\nRight     70 pipe_op_eol.     %% |\nRight     80 assoc_op_eol.    %% =>\nNonassoc  90 capture_op_eol.  %% &\nNonassoc  90 ellipsis_op.     %% ...\nRight    100 match_op_eol.    %% =\nLeft     120 or_op_eol.       %% ||, |||, or\nLeft     130 and_op_eol.      %% &&, &&&, and\nLeft     140 comp_op_eol.     %% ==, !=, =~, ===, !==\nLeft     150 rel_op_eol.      %% <, >, <=, >=\nLeft     160 arrow_op_eol.    %% <<<, >>>, |>, <<~, ~>>, <~, ~>, <~>, <|>\nLeft     170 in_op_eol.       %% in, not in\nLeft     180 xor_op_eol.      %% ^^^\nRight    190 ternary_op_eol.  %% //\nRight    200 concat_op_eol.   %% ++, --, +++, ---, <>\nRight    200 range_op_eol.    %% ..\nLeft     210 dual_op_eol.     %% +, -\nLeft     220 mult_op_eol.     %% *, /\nLeft     230 power_op_eol.    %% **\nNonassoc 300 unary_op_eol.    %% +, -, !, ^, not, ~~~\nLeft     310 dot_call_op.\nLeft     310 dot_op.          %% .\nNonassoc 320 at_op_eol.       %% @\nNonassoc 330 dot_identifier.\n\n%%% MAIN FLOW OF EXPRESSIONS\n\ngrammar -> eoe : {'__block__', meta_from_location({1, 1, nil}), []}.\ngrammar -> expr_list : build_block(reverse('$1')).\ngrammar -> eoe expr_list : build_block(reverse('$2')).\ngrammar -> expr_list eoe : build_block(reverse(annotate_eoe('$2', '$1'))).\ngrammar -> eoe expr_list eoe : build_block(reverse(annotate_eoe('$3', '$2'))).\ngrammar -> '$empty' : {'__block__', meta_from_location({1, 1, nil}), []}.\n\n% Note expressions are on reverse order\nexpr_list -> expr : ['$1'].\nexpr_list -> expr_list eoe expr : ['$3' | annotate_eoe('$2', '$1')].\n\nexpr -> matched_expr : '$1'.\nexpr -> no_parens_expr : '$1'.\nexpr -> unmatched_expr : '$1'.\n\n%% In Elixir we have three main call syntaxes: with parentheses,\n%% without parentheses and with do blocks. They are represented\n%% in the AST as matched, no_parens and unmatched.\n%%\n%% Calls without parentheses are further divided according to how\n%% problematic they are:\n%%\n%% (a) no_parens_one: a call with one unproblematic argument\n%% (for example, `f a` or `f g a` and similar) (includes unary operators)\n%%\n%% (b) no_parens_many: a call with several arguments (for example, `f a, b`)\n%%\n%% (c) no_parens_one_ambig: a call with one argument which is\n%% itself a no_parens_many or no_parens_one_ambig (for example, `f g a, b`,\n%% `f g h a, b` and similar)\n%%\n%% Note, in particular, that no_parens_one_ambig expressions are\n%% ambiguous and are interpreted such that the outer function has\n%% arity 1. For instance, `f g a, b` is interpreted as `f(g(a, b))` rather\n%% than `f(g(a), b)`. Hence the name, no_parens_one_ambig.\n%%\n%% The distinction is required because we can't, for example, have\n%% a function call with a do block as argument inside another do\n%% block call, unless there are parentheses:\n%%\n%%   if if true do true else false end do  #=> invalid\n%%   if(if true do true else false end) do #=> valid\n%%\n%% Similarly, it is not possible to nest calls without parentheses\n%% if their arity is more than 1:\n%%\n%%   foo a, bar b, c  #=> invalid\n%%   foo(a, bar b, c) #=> invalid\n%%   foo bar a, b     #=> valid\n%%   foo a, bar(b, c) #=> valid\n%%\n%% So the different grammar rules need to take into account\n%% if calls without parentheses are do blocks in particular\n%% segments and act accordingly.\nmatched_expr -> matched_expr matched_op_expr : build_op('$1', '$2').\nmatched_expr -> unary_op_eol matched_expr : build_unary_op('$1', '$2').\nmatched_expr -> at_op_eol matched_expr : build_unary_op('$1', '$2').\nmatched_expr -> capture_op_eol matched_expr : build_unary_op('$1', '$2').\nmatched_expr -> ellipsis_op matched_expr : build_unary_op('$1', '$2').\nmatched_expr -> no_parens_one_expr : '$1'.\nmatched_expr -> sub_matched_expr : '$1'.\n\nunmatched_expr -> matched_expr unmatched_op_expr : build_op('$1', '$2').\nunmatched_expr -> unmatched_expr matched_op_expr : build_op('$1', '$2').\nunmatched_expr -> unmatched_expr unmatched_op_expr : build_op('$1', '$2').\nunmatched_expr -> unmatched_expr no_parens_op_expr : warn_no_parens_after_do_op('$2'), build_op('$1', '$2').\nunmatched_expr -> unary_op_eol expr : build_unary_op('$1', '$2').\nunmatched_expr -> at_op_eol expr : build_unary_op('$1', '$2').\nunmatched_expr -> capture_op_eol expr : build_unary_op('$1', '$2').\nunmatched_expr -> ellipsis_op expr : build_unary_op('$1', '$2').\nunmatched_expr -> block_expr : '$1'.\n\nno_parens_expr -> matched_expr no_parens_op_expr : build_op('$1', '$2').\nno_parens_expr -> unary_op_eol no_parens_expr : build_unary_op('$1', '$2').\nno_parens_expr -> at_op_eol no_parens_expr : build_unary_op('$1', '$2').\nno_parens_expr -> capture_op_eol no_parens_expr : build_unary_op('$1', '$2').\nno_parens_expr -> ellipsis_op no_parens_expr : build_unary_op('$1', '$2').\nno_parens_expr -> no_parens_one_ambig_expr : '$1'.\nno_parens_expr -> no_parens_many_expr : '$1'.\n\nblock_expr -> dot_call_identifier call_args_parens do_block : build_parens('$1', '$2', '$3').\nblock_expr -> dot_call_identifier call_args_parens call_args_parens do_block : build_nested_parens('$1', '$2', '$3', '$4').\nblock_expr -> dot_do_identifier do_block : build_no_parens_do_block('$1', [], '$2').\nblock_expr -> dot_op_identifier call_args_no_parens_all do_block : build_no_parens_do_block('$1', '$2', '$3').\nblock_expr -> dot_identifier call_args_no_parens_all do_block : build_no_parens_do_block('$1', '$2', '$3').\n\nmatched_op_expr -> match_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> dual_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> mult_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> power_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> concat_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> range_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> ternary_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> xor_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> and_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> or_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> in_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> in_match_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> type_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> when_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> pipe_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> comp_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> rel_op_eol matched_expr : {'$1', '$2'}.\nmatched_op_expr -> arrow_op_eol matched_expr : {'$1', '$2'}.\n\n%% We warn exclusively of |> and friends because they are used\n%% in other languages with lower precedence than function application,\n%% which can be the source of confusion.\nmatched_op_expr -> arrow_op_eol no_parens_one_expr : warn_pipe('$1', '$2'), {'$1', '$2'}.\n\nunmatched_op_expr -> match_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> dual_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> mult_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> power_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> concat_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> range_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> ternary_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> xor_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> and_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> or_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> in_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> in_match_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> type_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> when_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> pipe_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> comp_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> rel_op_eol unmatched_expr : {'$1', '$2'}.\nunmatched_op_expr -> arrow_op_eol unmatched_expr : {'$1', '$2'}.\n\nno_parens_op_expr -> match_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> dual_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> mult_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> power_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> concat_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> range_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> ternary_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> xor_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> and_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> or_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> in_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> in_match_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> type_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> when_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> pipe_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> comp_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> rel_op_eol no_parens_expr : {'$1', '$2'}.\nno_parens_op_expr -> arrow_op_eol no_parens_expr : warn_pipe('$1', '$2'), {'$1', '$2'}.\n\n%% Allow when (and only when) with keywords\nno_parens_op_expr -> when_op_eol call_args_no_parens_kw : {'$1', '$2'}.\n\nno_parens_one_ambig_expr -> dot_op_identifier call_args_no_parens_ambig : build_no_parens('$1', '$2').\nno_parens_one_ambig_expr -> dot_identifier call_args_no_parens_ambig : build_no_parens('$1', '$2').\n\nno_parens_many_expr -> dot_op_identifier call_args_no_parens_many_strict : build_no_parens('$1', '$2').\nno_parens_many_expr -> dot_identifier call_args_no_parens_many_strict : build_no_parens('$1', '$2').\n\nno_parens_one_expr -> dot_op_identifier call_args_no_parens_one : build_no_parens('$1', '$2').\nno_parens_one_expr -> dot_identifier call_args_no_parens_one : build_no_parens('$1', '$2').\nno_parens_zero_expr -> dot_do_identifier : build_identifier('$1').\nno_parens_zero_expr -> dot_identifier : build_identifier('$1').\n\nsub_matched_expr -> no_parens_zero_expr : '$1'.\nsub_matched_expr -> range_op : build_nullary_op('$1').\nsub_matched_expr -> ellipsis_op : build_nullary_op('$1').\nsub_matched_expr -> access_expr : '$1'.\nsub_matched_expr -> access_expr kw_identifier : error_invalid_kw_identifier('$2').\n\n%% From this point on, we just have constructs that can be\n%% used with the access syntax. Note that (dot_)identifier\n%% is not included in this list simply because the tokenizer\n%% marks identifiers followed by brackets as bracket_identifier.\naccess_expr -> bracket_at_expr : '$1'.\naccess_expr -> bracket_expr : '$1'.\naccess_expr -> capture_int int : build_unary_op('$1', number_value('$2')).\naccess_expr -> fn_eoe stab_eoe 'end' : build_fn('$1', '$2', '$3').\naccess_expr -> open_paren stab_eoe ')' : build_paren_stab('$1', '$2', '$3').\naccess_expr -> open_paren ';' stab_eoe ')' : build_paren_stab('$1', '$3', '$4').\naccess_expr -> open_paren ';' close_paren : build_paren_stab('$1', [], '$3').\naccess_expr -> empty_paren : warn_empty_paren('$1'), {'__block__', parens_meta('$1'), []}.\naccess_expr -> int : handle_number(number_value('$1'), '$1', ?exprs('$1')).\naccess_expr -> flt : handle_number(number_value('$1'), '$1', ?exprs('$1')).\naccess_expr -> char : handle_number(?exprs('$1'), '$1', number_value('$1')).\naccess_expr -> list : element(1, '$1').\naccess_expr -> map : '$1'.\naccess_expr -> tuple : '$1'.\naccess_expr -> 'true' : handle_literal(?id('$1'), '$1').\naccess_expr -> 'false' : handle_literal(?id('$1'), '$1').\naccess_expr -> 'nil' : handle_literal(?id('$1'), '$1').\naccess_expr -> bin_string : build_bin_string('$1', delimiter(<<$\">>)).\naccess_expr -> list_string : build_list_string('$1', delimiter(<<$'>>)).\naccess_expr -> bin_heredoc : build_bin_heredoc('$1').\naccess_expr -> list_heredoc : build_list_heredoc('$1').\naccess_expr -> bitstring : '$1'.\naccess_expr -> sigil : build_sigil('$1').\naccess_expr -> atom : handle_literal(?exprs('$1'), '$1', atom_colon_meta('$1')).\naccess_expr -> atom_quoted : handle_literal(?exprs('$1'), '$1', atom_delimiter_meta('$1')).\naccess_expr -> atom_safe : build_quoted_atom('$1', true, atom_delimiter_meta('$1')).\naccess_expr -> atom_unsafe : build_quoted_atom('$1', false, atom_delimiter_meta('$1')).\naccess_expr -> dot_alias : '$1'.\naccess_expr -> parens_call : '$1'.\n\n%% Also used by maps and structs\nparens_call -> dot_call_identifier call_args_parens : build_parens('$1', '$2', {[], []}).\nparens_call -> dot_call_identifier call_args_parens call_args_parens : build_nested_parens('$1', '$2', '$3', {[], []}).\n\nbracket_arg -> open_bracket kw_data close_bracket : build_access_arg('$1', '$2', '$3').\nbracket_arg -> open_bracket container_expr close_bracket : build_access_arg('$1', '$2', '$3').\nbracket_arg -> open_bracket container_expr ',' close_bracket : build_access_arg('$1', '$2', '$4').\nbracket_arg -> open_bracket container_expr ',' container_args close_bracket : error_too_many_access_syntax('$3').\n\nbracket_expr -> dot_bracket_identifier bracket_arg : build_access(build_identifier('$1'), meta_with_from_brackets('$2')).\nbracket_expr -> access_expr bracket_arg : build_access('$1', meta_with_from_brackets('$2')).\n\nbracket_at_expr -> at_op_eol dot_bracket_identifier bracket_arg :\n                     build_access(build_unary_op('$1', build_identifier('$2')), meta_with_from_brackets('$3')).\nbracket_at_expr -> at_op_eol access_expr bracket_arg :\n                     build_access(build_unary_op('$1', '$2'), meta_with_from_brackets('$3')).\n\n%% Blocks\n\ndo_block -> do_eoe 'end' :\n              {do_end_meta('$1', '$2'), [[{handle_literal(do, '$1'), {'__block__', meta_from_token('$1'), []}}]]}.\ndo_block -> do_eoe stab_eoe 'end' :\n              {do_end_meta('$1', '$3'), [[{handle_literal(do, '$1'), build_stab('$2', meta_from_token('$1'))}]]}.\ndo_block -> do_eoe block_list 'end' :\n              {do_end_meta('$1', '$3'), [[{handle_literal(do, '$1'), {'__block__', meta_from_token('$1'), []}} | '$2']]}.\ndo_block -> do_eoe stab_eoe block_list 'end' :\n              {do_end_meta('$1', '$4'), [[{handle_literal(do, '$1'), build_stab('$2', meta_from_token('$1'))} | '$3']]}.\n\neoe -> eol : '$1'.\neoe -> ';' : '$1'.\neoe -> eol ';' : '$1'.\n\nfn_eoe -> 'fn' : '$1'.\nfn_eoe -> 'fn' eoe : next_is_eol('$1', '$2').\n\ndo_eoe -> 'do' : '$1'.\ndo_eoe -> 'do' eoe : '$1'.\n\nblock_eoe -> block_identifier : '$1'.\nblock_eoe -> block_identifier eoe : '$1'.\n\nstab -> stab_expr : ['$1'].\nstab -> stab eoe stab_expr : ['$3' | annotate_eoe('$2', '$1')].\n\nstab_eoe -> stab : '$1'.\nstab_eoe -> stab eoe : annotate_eoe('$2', '$1').\n\nstab_expr -> expr :\n               '$1'.\nstab_expr -> stab_op_eol_and_expr :\n               build_op([], '$1').\nstab_expr -> empty_paren stab_op_eol_and_expr :\n               build_op_with_meta([], '$2', parens_meta('$1')).\nstab_expr -> empty_paren when_op expr stab_op_eol_and_expr :\n               build_op_with_meta([{'when', meta_from_token('$2'), ['$3']}], '$4', parens_meta('$1')).\nstab_expr -> call_args_no_parens_all stab_op_eol_and_expr :\n               build_op(unwrap_when(unwrap_splice('$1')), '$2').\nstab_expr -> stab_parens_many stab_op_eol_and_expr :\n               build_op_with_meta(unwrap_splice(element(2, '$1')), '$2', parens_meta('$1')).\nstab_expr -> stab_parens_many when_op expr stab_op_eol_and_expr :\n               build_op_with_meta([{'when', meta_from_token('$2'), unwrap_splice(element(2, '$1')) ++ ['$3']}], '$4', parens_meta('$1')).\n\nstab_op_eol_and_expr -> stab_op_eol expr : {'$1', '$2'}.\nstab_op_eol_and_expr -> stab_op_eol : warn_empty_stab_clause('$1'), {'$1', handle_literal(nil, '$1')}.\n\nblock_item -> block_eoe stab_eoe :\n                {handle_literal(?exprs('$1'), '$1'), build_stab('$2', [])}.\nblock_item -> block_eoe :\n                {handle_literal(?exprs('$1'), '$1'), {'__block__', [], []}}.\n\nblock_list -> block_item : ['$1'].\nblock_list -> block_item block_list : ['$1' | '$2'].\n\n%% Helpers\n\nopen_paren -> '('      : '$1'.\nopen_paren -> '(' eol  : next_is_eol('$1', '$2').\nclose_paren -> ')'     : '$1'.\nclose_paren -> eol ')' : '$2'.\n\nempty_paren -> open_paren ')' : {'$1', '$2'}.\n\nopen_bracket  -> '['     : '$1'.\nopen_bracket  -> '[' eol : next_is_eol('$1', '$2').\nclose_bracket -> ']'     : '$1'.\nclose_bracket -> eol ']' : '$2'.\n\nopen_bit  -> '<<'     : '$1'.\nopen_bit  -> '<<' eol : next_is_eol('$1', '$2').\nclose_bit -> '>>'     : '$1'.\nclose_bit -> eol '>>' : '$2'.\n\nopen_curly  -> '{'     : '$1'.\nopen_curly  -> '{' eol : next_is_eol('$1', '$2').\nclose_curly -> '}'     : '$1'.\nclose_curly -> eol '}' : '$2'.\n\n% Operators\n\nunary_op_eol -> unary_op : '$1'.\nunary_op_eol -> unary_op eol : '$1'.\nunary_op_eol -> dual_op : '$1'.\nunary_op_eol -> dual_op eol : '$1'.\nunary_op_eol -> ternary_op : '$1'.\nunary_op_eol -> ternary_op eol : '$1'.\n\ncapture_op_eol -> capture_op : '$1'.\ncapture_op_eol -> capture_op eol : '$1'.\n\nat_op_eol -> at_op : '$1'.\nat_op_eol -> at_op eol : '$1'.\n\nmatch_op_eol -> match_op : '$1'.\nmatch_op_eol -> match_op eol : next_is_eol('$1', '$2').\n\ndual_op_eol -> dual_op : '$1'.\ndual_op_eol -> dual_op eol : next_is_eol('$1', '$2').\n\nmult_op_eol -> mult_op : '$1'.\nmult_op_eol -> mult_op eol : next_is_eol('$1', '$2').\n\npower_op_eol -> power_op : '$1'.\npower_op_eol -> power_op eol : next_is_eol('$1', '$2').\n\nconcat_op_eol -> concat_op : '$1'.\nconcat_op_eol -> concat_op eol : next_is_eol('$1', '$2').\n\nrange_op_eol -> range_op : '$1'.\nrange_op_eol -> range_op eol : next_is_eol('$1', '$2').\n\nternary_op_eol -> ternary_op : '$1'.\nternary_op_eol -> ternary_op eol : next_is_eol('$1', '$2').\n\nxor_op_eol -> xor_op : '$1'.\nxor_op_eol -> xor_op eol : next_is_eol('$1', '$2').\n\npipe_op_eol -> pipe_op : '$1'.\npipe_op_eol -> pipe_op eol : next_is_eol('$1', '$2').\n\nand_op_eol -> and_op : '$1'.\nand_op_eol -> and_op eol : next_is_eol('$1', '$2').\n\nor_op_eol -> or_op : '$1'.\nor_op_eol -> or_op eol : next_is_eol('$1', '$2').\n\nin_op_eol -> in_op : '$1'.\nin_op_eol -> in_op eol : next_is_eol('$1', '$2').\n\nin_match_op_eol -> in_match_op : '$1'.\nin_match_op_eol -> in_match_op eol : next_is_eol('$1', '$2').\n\ntype_op_eol -> type_op : '$1'.\ntype_op_eol -> type_op eol : next_is_eol('$1', '$2').\n\nwhen_op_eol -> when_op : '$1'.\nwhen_op_eol -> when_op eol : next_is_eol('$1', '$2').\n\nstab_op_eol -> stab_op : '$1'.\nstab_op_eol -> stab_op eol : next_is_eol('$1', '$2').\n\ncomp_op_eol -> comp_op : '$1'.\ncomp_op_eol -> comp_op eol : next_is_eol('$1', '$2').\n\nrel_op_eol -> rel_op : '$1'.\nrel_op_eol -> rel_op eol : next_is_eol('$1', '$2').\n\narrow_op_eol -> arrow_op : '$1'.\narrow_op_eol -> arrow_op eol : next_is_eol('$1', '$2').\n\n% Dot operator\n\ndot_op -> '.' : '$1'.\ndot_op -> '.' eol : '$1'.\n\ndot_identifier -> identifier : '$1'.\ndot_identifier -> matched_expr dot_op identifier : build_dot('$2', '$1', '$3').\n\ndot_alias -> alias : build_alias('$1').\ndot_alias -> matched_expr dot_op alias : build_dot_alias('$2', '$1', '$3').\ndot_alias -> matched_expr dot_op open_curly '}' : build_dot_container('$2', '$1', [], newlines_pair('$3', '$4')).\ndot_alias -> matched_expr dot_op open_curly container_args close_curly : build_dot_container('$2', '$1', '$4', newlines_pair('$3', '$5')).\n\ndot_op_identifier -> op_identifier : '$1'.\ndot_op_identifier -> matched_expr dot_op op_identifier : build_dot('$2', '$1', '$3').\n\ndot_do_identifier -> do_identifier : '$1'.\ndot_do_identifier -> matched_expr dot_op do_identifier : build_dot('$2', '$1', '$3').\n\ndot_bracket_identifier -> bracket_identifier : '$1'.\ndot_bracket_identifier -> matched_expr dot_op bracket_identifier : build_dot('$2', '$1', '$3').\n\ndot_paren_identifier -> paren_identifier : '$1'.\ndot_paren_identifier -> matched_expr dot_op paren_identifier : build_dot('$2', '$1', '$3').\n\ndot_call_identifier -> dot_paren_identifier : '$1'.\ndot_call_identifier -> matched_expr dot_call_op : {'.', meta_from_token('$2'), ['$1']}. % Fun/local calls\n\n% Function calls with no parentheses\n\ncall_args_no_parens_expr -> matched_expr : '$1'.\ncall_args_no_parens_expr -> no_parens_expr : error_no_parens_many_strict('$1').\n\ncall_args_no_parens_comma_expr -> matched_expr ',' call_args_no_parens_expr : ['$3', '$1'].\ncall_args_no_parens_comma_expr -> call_args_no_parens_comma_expr ',' call_args_no_parens_expr : ['$3' | '$1'].\n\ncall_args_no_parens_all -> call_args_no_parens_one : '$1'.\ncall_args_no_parens_all -> call_args_no_parens_ambig : '$1'.\ncall_args_no_parens_all -> call_args_no_parens_many : '$1'.\n\ncall_args_no_parens_one -> call_args_no_parens_kw : ['$1'].\ncall_args_no_parens_one -> matched_expr : ['$1'].\n\n%% This is the only no parens ambiguity where we don't\n%% raise nor warn: \"parent_call nested_call 1, 2, 3\"\n%% always assumes that all arguments are nested.\ncall_args_no_parens_ambig -> no_parens_expr : ['$1'].\n\ncall_args_no_parens_many -> matched_expr ',' call_args_no_parens_kw : ['$1', '$3'].\ncall_args_no_parens_many -> call_args_no_parens_comma_expr : reverse('$1').\ncall_args_no_parens_many -> call_args_no_parens_comma_expr ',' call_args_no_parens_kw : reverse(['$3' | '$1']).\n\ncall_args_no_parens_many_strict -> call_args_no_parens_many : '$1'.\ncall_args_no_parens_many_strict -> open_paren call_args_no_parens_kw close_paren : error_no_parens_strict('$1').\ncall_args_no_parens_many_strict -> open_paren call_args_no_parens_many close_paren : error_no_parens_strict('$1').\n\nstab_parens_many -> open_paren call_args_no_parens_kw close_paren : {'$1', ['$2'], '$3'}.\nstab_parens_many -> open_paren call_args_no_parens_many close_paren : {'$1', '$2', '$3'}.\n\n% Containers\n\ncontainer_expr -> matched_expr : '$1'.\ncontainer_expr -> unmatched_expr : '$1'.\ncontainer_expr -> no_parens_expr : error_no_parens_container_strict('$1').\n\ncontainer_args_base -> container_expr : ['$1'].\ncontainer_args_base -> container_args_base ',' container_expr : ['$3' | '$1'].\n\ncontainer_args -> container_args_base : reverse('$1').\ncontainer_args -> container_args_base ',' : reverse('$1').\ncontainer_args -> container_args_base ',' kw_data : reverse(['$3' | '$1']).\n\n% Function calls with parentheses\n\ncall_args_parens_expr -> matched_expr : '$1'.\ncall_args_parens_expr -> unmatched_expr : '$1'.\ncall_args_parens_expr -> no_parens_expr : error_no_parens_many_strict('$1').\n\ncall_args_parens_base -> call_args_parens_expr : ['$1'].\ncall_args_parens_base -> call_args_parens_base ',' call_args_parens_expr : ['$3' | '$1'].\n\ncall_args_parens -> open_paren ')' :\n                      {newlines_pair('$1', '$2'), []}.\ncall_args_parens -> open_paren no_parens_expr close_paren :\n                      {newlines_pair('$1', '$3'), ['$2']}.\ncall_args_parens -> open_paren kw_call close_paren :\n                      {newlines_pair('$1', '$3'), ['$2']}.\ncall_args_parens -> open_paren call_args_parens_base close_paren :\n                      {newlines_pair('$1', '$3'), reverse('$2')}.\ncall_args_parens -> open_paren call_args_parens_base ',' kw_call close_paren :\n                      {newlines_pair('$1', '$5'), reverse(['$4' | '$2'])}.\n\n% KV\n\nkw_eol -> kw_identifier : handle_literal(?exprs('$1'), '$1', kw_identifier_meta('$1')).\nkw_eol -> kw_identifier eol : handle_literal(?exprs('$1'), '$1', kw_identifier_meta('$1')).\nkw_eol -> kw_identifier_safe : build_quoted_atom('$1', true, kw_identifier_meta('$1')).\nkw_eol -> kw_identifier_safe eol : build_quoted_atom('$1', true, kw_identifier_meta('$1')).\nkw_eol -> kw_identifier_unsafe : build_quoted_atom('$1', false, kw_identifier_meta('$1')).\nkw_eol -> kw_identifier_unsafe eol : build_quoted_atom('$1', false, kw_identifier_meta('$1')).\n\nkw_base -> kw_eol container_expr : [{'$1', '$2'}].\nkw_base -> kw_base ',' kw_eol container_expr : [{'$3', '$4'} | '$1'].\n\nkw_call -> kw_base : reverse('$1').\nkw_call -> kw_base ',' : warn_trailing_comma('$2'), reverse('$1').\nkw_call -> kw_base ',' matched_expr : maybe_bad_keyword_call_follow_up('$2', '$1', '$3').\n\nkw_data -> kw_base : reverse('$1').\nkw_data -> kw_base ',' : reverse('$1').\nkw_data -> kw_base ',' matched_expr : maybe_bad_keyword_data_follow_up('$2', '$1', '$3').\n\ncall_args_no_parens_kw_expr -> kw_eol matched_expr : {'$1', '$2'}.\ncall_args_no_parens_kw_expr -> kw_eol no_parens_expr : warn_nested_no_parens_keyword('$1', '$2'), {'$1', '$2'}.\n\ncall_args_no_parens_kw -> call_args_no_parens_kw_expr : ['$1'].\ncall_args_no_parens_kw -> call_args_no_parens_kw_expr ',' call_args_no_parens_kw : ['$1' | '$3'].\ncall_args_no_parens_kw -> call_args_no_parens_kw_expr ',' matched_expr : maybe_bad_keyword_call_follow_up('$2', ['$1'], '$3').\n\n% Lists\n\nlist_args -> kw_data : '$1'.\nlist_args -> container_args_base : reverse('$1').\nlist_args -> container_args_base ',' : reverse('$1').\nlist_args -> container_args_base ',' kw_data : reverse('$1', '$3').\n\nlist -> open_bracket ']' : build_list('$1', [], '$2').\nlist -> open_bracket list_args close_bracket : build_list('$1', '$2', '$3').\n\n% Tuple\n\ntuple -> open_curly '}' : build_tuple('$1', [], '$2').\ntuple -> open_curly kw_data '}' : bad_keyword('$1', tuple, \"'{'\").\ntuple -> open_curly container_args close_curly :  build_tuple('$1', '$2', '$3').\n\n% Bitstrings\n\nbitstring -> open_bit '>>' : build_bit('$1', [], '$2').\nbitstring -> open_bit kw_data '>>' : bad_keyword('$1', bitstring, \"'<<'\").\nbitstring -> open_bit container_args close_bit : build_bit('$1', '$2', '$3').\n\n% Map and structs\n\nmap_base_expr -> sub_matched_expr : '$1'.\nmap_base_expr -> at_op_eol map_base_expr : build_unary_op('$1', '$2').\nmap_base_expr -> unary_op_eol map_base_expr : build_unary_op('$1', '$2').\nmap_base_expr -> ellipsis_op map_base_expr : build_unary_op('$1', '$2').\n\nassoc_op_eol -> assoc_op : '$1'.\nassoc_op_eol -> assoc_op eol : '$1'.\n\nassoc_expr -> matched_expr assoc_op_eol matched_expr : {with_assoc_meta('$1', '$2'), '$3'}.\nassoc_expr -> unmatched_expr assoc_op_eol unmatched_expr : {with_assoc_meta('$1', '$2'), '$3'}.\nassoc_expr -> matched_expr assoc_op_eol unmatched_expr : {with_assoc_meta('$1', '$2'), '$3'}.\nassoc_expr -> unmatched_expr assoc_op_eol matched_expr : {with_assoc_meta('$1', '$2'), '$3'}.\nassoc_expr -> map_base_expr : '$1'.\n\nassoc_update -> matched_expr pipe_op_eol assoc_expr : {'$2', '$1', ['$3']}.\nassoc_update -> unmatched_expr pipe_op_eol assoc_expr : {'$2', '$1', ['$3']}.\n\nassoc_update_kw -> matched_expr pipe_op_eol kw_data : {'$2', '$1', '$3'}.\nassoc_update_kw -> unmatched_expr pipe_op_eol kw_data : {'$2', '$1', '$3'}.\n\nassoc_base -> assoc_expr : ['$1'].\nassoc_base -> assoc_base ',' assoc_expr : ['$3' | '$1'].\n\nassoc -> assoc_base : reverse('$1').\nassoc -> assoc_base ',' : reverse('$1').\n\nmap_op -> '%{}' : '$1'.\nmap_op -> '%{}' eol : '$1'.\n\nmap_close -> kw_data close_curly : {'$1', '$2'}.\nmap_close -> assoc close_curly : {'$1', '$2'}.\nmap_close -> assoc_base ',' kw_data close_curly : {reverse('$1', '$3'), '$4'}.\n\nmap_args -> open_curly '}' : build_map('$1', [], '$2').\nmap_args -> open_curly map_close : build_map('$1', element(1, '$2'), element(2, '$2')).\nmap_args -> open_curly assoc_update close_curly : build_map_update('$1', '$2', '$3', []).\nmap_args -> open_curly assoc_update ',' close_curly : build_map_update('$1', '$2', '$4', []).\nmap_args -> open_curly assoc_update ',' map_close : build_map_update('$1', '$2', element(2, '$4'), element(1, '$4')).\nmap_args -> open_curly assoc_update_kw close_curly : build_map_update('$1', '$2', '$3', []).\n\nmap -> map_op map_args : '$2'.\nmap -> '%' map_base_expr map_args : {'%', meta_from_token('$1'), ['$2', '$3']}.\nmap -> '%' map_base_expr eol map_args : {'%', meta_from_token('$1'), ['$2', '$4']}.\n\nErlang code.\n\n-define(columns(), get(elixir_parser_columns)).\n-define(token_metadata(), get(elixir_token_metadata)).\n\n-define(id(Token), element(1, Token)).\n-define(location(Token), element(2, Token)).\n-define(op(Token), element(3, Token)).\n-define(meta(Node), element(2, Node)).\n-define(exprs(Node), element(3, Node)).\n-define(rearrange_uop(Op), (Op == 'not' orelse Op == '!')).\n\n-compile({inline, meta_from_token/1, meta_from_location/1, is_eol/1}).\n-import(lists, [reverse/1, reverse/2]).\n\nmeta_from_token(Token) ->\n  meta_from_location(?location(Token)).\n\nmeta_from_location({Line, Column, _}) ->\n  case ?columns() of\n    true -> [{line, Line}, {column, Column}];\n    false -> [{line, Line}]\n  end.\n\ndo_end_meta(Do, End) ->\n  case ?token_metadata() of\n    true ->\n      [{do, meta_from_token(Do)}, {'end', meta_from_token(End)}];\n    false ->\n      []\n  end.\n\nmeta_from_token_with_closing(Begin, End) ->\n  case ?token_metadata() of\n    true ->\n      [{closing, meta_from_token(End)} | meta_from_token(Begin)];\n    false ->\n      meta_from_token(Begin)\n  end.\n\nappend_non_empty(Left, []) -> Left;\nappend_non_empty(Left, Right) -> Left ++ Right.\n\n%% Handle metadata in literals\n\nhandle_literal(Literal, Token) ->\n  handle_literal(Literal, Token, []).\n\nhandle_literal(Literal, Token, ExtraMeta) ->\n  case get(elixir_literal_encoder) of\n    false ->\n      Literal;\n\n    Fun ->\n      Meta = ExtraMeta ++ meta_from_token(Token),\n      case Fun(Literal, Meta) of\n        {ok, EncodedLiteral} ->\n          EncodedLiteral;\n        {error, Reason} ->\n          return_error(?location(Token), elixir_utils:characters_to_list(Reason) ++ [\": \"], \"literal\")\n      end\n  end.\n\nhandle_number(Number, Token, Original) ->\n  case ?token_metadata() of\n    true -> handle_literal(Number, Token, [{token, elixir_utils:characters_to_binary(Original)}]);\n    false -> handle_literal(Number, Token, [])\n  end.\n\nnumber_value({_, {_, _, Value}, _}) ->\n  Value.\n\n%% Operators\n\nbuild_op_with_meta(Left, {Op, Right}, Meta) ->\n  {Op1, OpMeta, Args} = build_op(Left, Op, Right),\n  {Op1, Meta ++ OpMeta, Args}.\n\nbuild_op(Left, {Op, Right}) ->\n  build_op(Left, Op, Right).\n\nbuild_op(AST, {_Kind, Location, '//'}, Right) ->\n  case AST of\n    {'..', Meta, [Left, Middle]} ->\n      {'..//', Meta, [Left, Middle, Right]};\n\n    _ ->\n      return_error(Location, \"the range step operator (//) must immediately follow the range definition operator (..), for example: 1..9//2. If you wanted to define a default argument, use (\\\\\\\\) instead. Syntax error before: \", \"'//'\")\n  end;\n\nbuild_op({UOp, UMeta, [Left]}, {_Kind, {Line, Column, _} = Location, 'in'}, Right) when ?rearrange_uop(UOp) ->\n  %% TODO: Remove \"not left in right\" rearrangement on v2.0\n  warn({Line, Column}, case UOp of\n    '!' -> \"\\\"!expr1 in expr2\\\" is deprecated, use \\\"expr1 not in expr2\\\" instead\";\n    'not' -> \"\\\"not expr1 in expr2\\\" is deprecated, use \\\"expr1 not in expr2\\\" instead\"\n  end),\n  Meta = meta_from_location(Location),\n  {UOp, UMeta, [{'in', Meta, [Left, Right]}]};\n\nbuild_op(Left, {in_op, NotLocation, 'not in', InLocation}, Right) ->\n  NotMeta = newlines_op(NotLocation) ++ meta_from_location(NotLocation),\n  InMeta = meta_from_location(InLocation),\n  {'not', NotMeta, [{'in', InMeta, [Left, Right]}]};\n\nbuild_op(Left, {_Kind, Location, Op}, Right) ->\n  {Op, newlines_op(Location) ++ meta_from_location(Location), [Left, Right]}.\n\nbuild_unary_op({_Kind, {Line, Column, _}, '//'}, Expr) ->\n  {Outer, Inner} =\n    case ?columns() of\n      true -> {[{column, Column+1}], [{column, Column}]};\n      false -> {[], []}\n    end,\n  {'/', [{line, Line} | Outer], [{'/', [{line, Line} | Inner], nil}, Expr]};\n\nbuild_unary_op({_Kind, Location, Op}, Expr) ->\n  {Op, meta_from_location(Location), [Expr]}.\n\nbuild_nullary_op({_Kind, Location, Op}) ->\n  {Op, meta_from_location(Location), []}.\n\nbuild_list(Left, Args, Right) ->\n  {handle_literal(Args, Left, newlines_pair(Left, Right)), ?location(Left)}.\n\nbuild_tuple(Left, [Arg1, Arg2], Right) ->\n  handle_literal({Arg1, Arg2}, Left, newlines_pair(Left, Right));\nbuild_tuple(Left, Args, Right) ->\n  {'{}', newlines_pair(Left, Right) ++ meta_from_token(Left), Args}.\n\nbuild_bit(Left, Args, Right) ->\n  {'<<>>', newlines_pair(Left, Right) ++ meta_from_token(Left), Args}.\n\nbuild_map(Left, Args, Right) ->\n  {'%{}', newlines_pair(Left, Right) ++ meta_from_token(Left), Args}.\n\nbuild_map_update(Left, {Pipe, Struct, Map}, Right, Extra) ->\n  Op = build_op(Struct, Pipe, append_non_empty(Map, Extra)),\n  {'%{}', newlines_pair(Left, Right) ++ meta_from_token(Left), [Op]}.\n\n%% Blocks\n\nbuild_block(Exprs) -> build_block(Exprs, []).\n\nbuild_block([{unquote_splicing, _, [_]}]=Exprs, Meta) ->\n  {'__block__', Meta, Exprs};\nbuild_block([{Op, ExprMeta, Args}], Meta) ->\n  ExprMetaWithExtra =\n    case ?token_metadata() of\n      true when Meta /= [] -> [{parens, Meta} | ExprMeta];\n      _ -> ExprMeta\n    end,\n  {Op, ExprMetaWithExtra, Args};\nbuild_block([Expr], _Meta) ->\n  Expr;\nbuild_block(Exprs, Meta) ->\n  {'__block__', Meta, Exprs}.\n\n%% Newlines\n\nnewlines_pair(Left, Right) ->\n  case ?token_metadata() of\n    true ->\n      newlines(?location(Left), [{closing, meta_from_token(Right)}]);\n    false ->\n      []\n  end.\n\nnewlines_op(Location) ->\n  case ?token_metadata() of\n    true -> newlines(Location, []);\n    false -> []\n  end.\n\nnext_is_eol(Token, {_, {_, _, Count}}) ->\n  {Line, Column, _} = ?location(Token),\n  setelement(2, Token, {Line, Column, Count}).\n\nnewlines({_, _, Count}, Meta) when is_integer(Count) and (Count > 0) ->\n  [{newlines, Count} | Meta];\nnewlines(_, Meta) ->\n  Meta.\n\nannotate_eoe(Token, Stack) ->\n  case ?token_metadata() of\n    true ->\n      case {Token, Stack} of\n        {{_, Location}, [{'->', StabMeta, [StabArgs, {Left, Meta, Right}]} | Rest]} when is_list(Meta) ->\n          [{'->', StabMeta, [StabArgs, {Left, [{end_of_expression, end_of_expression(Location)} | Meta], Right}]} | Rest];\n\n        {{_, Location}, [{Left, Meta, Right} | Rest]} when is_list(Meta), Left =/= '->' ->\n          [{Left, [{end_of_expression, end_of_expression(Location)} | Meta], Right} | Rest];\n\n        _ ->\n          Stack\n      end;\n    false ->\n      Stack\n  end.\n\nend_of_expression({_, _, Count} = Location) when is_integer(Count) ->\n  [{newlines, Count} | meta_from_location(Location)];\nend_of_expression(Location) ->\n  meta_from_location(Location).\n\n%% Dots\n\nbuild_alias({'alias', Location, Alias}) ->\n  Meta = meta_from_location(Location),\n  MetaWithExtra =\n    case ?token_metadata() of\n      true -> [{last, meta_from_location(Location)} | Meta];\n      false -> Meta\n    end,\n  {'__aliases__', MetaWithExtra, [Alias]}.\n\nbuild_dot_alias(_Dot, {'__aliases__', Meta, Left}, {'alias', SegmentLocation, Right}) ->\n  MetaWithExtra =\n    case ?token_metadata() of\n      true -> lists:keystore(last, 1, Meta, {last, meta_from_location(SegmentLocation)});\n      false -> Meta\n    end,\n  {'__aliases__', MetaWithExtra, Left ++ [Right]};\nbuild_dot_alias(_Dot, Atom, Right) when is_atom(Atom) ->\n  error_bad_atom(Right);\nbuild_dot_alias(Dot, Expr, {'alias', SegmentLocation, Right}) ->\n  Meta = meta_from_token(Dot),\n  MetaWithExtra =\n    case ?token_metadata() of\n      true -> [{last, meta_from_location(SegmentLocation)} | Meta];\n      false -> Meta\n    end,\n  {'__aliases__', MetaWithExtra, [Expr, Right]}.\n\nbuild_dot_container(Dot, Left, Right, Extra) ->\n  Meta = meta_from_token(Dot),\n  {{'.', Meta, [Left, '{}']}, Extra ++ Meta, Right}.\n\nbuild_dot(Dot, Left, {_, Location, _} = Right) ->\n  Meta = meta_from_token(Dot),\n  IdentifierMeta0 = meta_from_location(Location),\n  IdentifierMeta1 =\n    case Location of\n      {_Line, _Column, Delimiter} when is_integer(Delimiter) ->\n        delimiter(<<Delimiter>>) ++ IdentifierMeta0;\n      _ ->\n        IdentifierMeta0\n    end,\n  {'.', Meta, IdentifierMeta1, [Left, extract_identifier(Right)]}.\n\nextract_identifier({Kind, _, Identifier}) when\n    Kind == identifier; Kind == bracket_identifier; Kind == paren_identifier;\n    Kind == do_identifier; Kind == op_identifier ->\n  Identifier.\n\n%% Identifiers\n\nbuild_nested_parens(Dot, Args1, {Args2Meta, Args2}, {BlockMeta, Block}) ->\n  Identifier = build_parens(Dot, Args1, {[], []}),\n  %% Take line and column meta from the call target node\n  LocationMeta = lists:filter(fun({Key, _}) -> Key == line orelse Key == column end, ?meta(Identifier)),\n  Meta = BlockMeta ++ Args2Meta ++ LocationMeta,\n  {Identifier, Meta, append_non_empty(Args2, Block)}.\n\nbuild_parens(Expr, {ArgsMeta, Args}, {BlockMeta, Block}) ->\n  {BuiltExpr, BuiltMeta, BuiltArgs} = build_call(Expr, append_non_empty(Args, Block)),\n  {BuiltExpr, BlockMeta ++ ArgsMeta ++ BuiltMeta, BuiltArgs}.\n\nbuild_no_parens_do_block(Expr, Args, {BlockMeta, Block}) ->\n  {BuiltExpr, BuiltMeta, BuiltArgs} = build_call(Expr, Args ++ Block),\n  {BuiltExpr, BlockMeta ++ BuiltMeta, BuiltArgs}.\n\nbuild_no_parens(Expr, Args) ->\n  build_call(Expr, Args).\n\nbuild_identifier({'.', Meta, IdentifierMeta, DotArgs}) ->\n  {{'.', Meta, DotArgs}, [{no_parens, true} | IdentifierMeta], []};\n\nbuild_identifier({'.', Meta, _} = Dot) ->\n  {Dot, [{no_parens, true} | Meta], []};\n\nbuild_identifier({_, Location, Identifier}) ->\n  {Identifier, meta_from_location(Location), nil}.\n\nbuild_call({'.', Meta, IdentifierMeta, DotArgs}, Args) ->\n  {{'.', Meta, DotArgs}, IdentifierMeta, Args};\n\nbuild_call({'.', Meta, _} = Dot, Args) ->\n  {Dot, Meta, Args};\n\nbuild_call({op_identifier, Location, Identifier}, [Arg]) ->\n  {Identifier, [{ambiguous_op, nil} | meta_from_location(Location)], [Arg]};\n\nbuild_call({_, Location, Identifier}, Args) ->\n  {Identifier, meta_from_location(Location), Args}.\n\n%% Fn\n\nbuild_fn(Fn, Stab, End) ->\n  case check_stab(Stab, none) of\n    stab ->\n      Meta = newlines_op(?location(Fn)) ++ meta_from_token_with_closing(Fn, End),\n      {fn, Meta, collect_stab(Stab, [], [])};\n    block ->\n      return_error(?location(Fn), \"expected anonymous functions to be defined with -> inside: \", \"'fn'\")\n  end.\n\n%% Access\n\nbuild_access_arg(Left, Args, Right) ->\n  {Args, newlines_pair(Left, Right) ++ meta_from_token(Left)}.\n\nbuild_access(Expr, {List, Meta}) ->\n  {{'.', Meta, ['Elixir.Access', get]}, Meta, [Expr, List]}.\n\n%% Interpolation aware\n\nbuild_sigil({sigil, Location, Atom, Parts, Modifiers, Indentation, Delimiter}) ->\n  Meta = meta_from_location(Location),\n  MetaWithDelimiter = [{delimiter, Delimiter} | Meta],\n  MetaWithIndentation = meta_with_indentation(Meta, Indentation),\n  {Atom,\n   MetaWithDelimiter,\n   [{'<<>>', MetaWithIndentation, string_parts(Parts)}, Modifiers]}.\n\nmeta_with_indentation(Meta, nil) ->\n  Meta;\nmeta_with_indentation(Meta, Indentation) ->\n  [{indentation, Indentation} | Meta].\n\nmeta_with_from_brackets({List, Meta}) ->\n  {List, [{from_brackets, true} | Meta]}.\n\nbuild_bin_heredoc({bin_heredoc, Location, Indentation, Args}) ->\n  ExtraMeta =\n    case ?token_metadata() of\n      true -> [{delimiter, <<$\", $\", $\">>}, {indentation, Indentation}];\n      false -> []\n    end,\n  build_bin_string({bin_string, Location, Args}, ExtraMeta).\n\nbuild_list_heredoc({list_heredoc, Location, Indentation, Args}) ->\n  ExtraMeta =\n    case ?token_metadata() of\n      true -> [{delimiter, <<$', $', $'>>}, {indentation, Indentation}];\n      false -> []\n    end,\n  build_list_string({list_string, Location, Args}, ExtraMeta).\n\nbuild_bin_string({bin_string, _Location, [H]} = Token, ExtraMeta) when is_binary(H) ->\n  handle_literal(H, Token, ExtraMeta);\nbuild_bin_string({bin_string, Location, Args}, ExtraMeta) ->\n  Meta =\n    case ?token_metadata() of\n      true -> ExtraMeta ++ meta_from_location(Location);\n      false -> meta_from_location(Location)\n    end,\n  {'<<>>', Meta, string_parts(Args)}.\n\nbuild_list_string({list_string, _Location, [H]} = Token, ExtraMeta) when is_binary(H) ->\n  try\n    List = elixir_utils:characters_to_list(H),\n    handle_literal(List, Token, ExtraMeta)\n  catch\n    error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n      return_error(?location(Token), elixir_utils:characters_to_list(Message), \"'\")\n  end;\nbuild_list_string({list_string, Location, Args}, ExtraMeta) ->\n  Meta = meta_from_location(Location),\n  MetaWithExtra =\n    case ?token_metadata() of\n      true -> ExtraMeta ++ Meta;\n      false -> Meta\n    end,\n  {{'.', Meta, ['Elixir.List', to_charlist]}, MetaWithExtra, [charlist_parts(Args)]}.\n\nbuild_quoted_atom({_, _Location, [H]} = Token, Safe, ExtraMeta) when is_binary(H) ->\n  Op = binary_to_atom_op(Safe),\n  handle_literal(erlang:Op(H, utf8), Token, ExtraMeta);\nbuild_quoted_atom({_, Location, Args}, Safe, ExtraMeta) ->\n  Meta = meta_from_location(Location),\n  MetaWithExtra =\n    case ?token_metadata() of\n      true -> ExtraMeta ++ Meta;\n      false -> Meta\n    end,\n  {{'.', Meta, [erlang, binary_to_atom_op(Safe)]}, MetaWithExtra, [{'<<>>', Meta, string_parts(Args)}, utf8]}.\n\nbinary_to_atom_op(true)  -> binary_to_existing_atom;\nbinary_to_atom_op(false) -> binary_to_atom.\n\natom_colon_meta({atom, _Location, Atom}) when Atom =:= true orelse Atom =:= false orelse Atom =:= nil ->\n  [{format, atom}];\natom_colon_meta(_) ->\n  [].\n\natom_delimiter_meta({_Kind, {_Line, _Column, Delimiter}, _Args}) ->\n  case ?token_metadata() of\n    true -> [{delimiter, <<Delimiter>>}];\n    false -> []\n  end.\n\nkw_identifier_meta({_Kind, {_Line, _Column, Delimiter}, _Args}) ->\n  Meta = [{format, keyword}],\n  case ?token_metadata() of\n    true when is_integer(Delimiter) -> [{delimiter, <<Delimiter>>} | Meta];\n    _ -> Meta\n  end.\n\ncharlist_parts(Parts) ->\n  [charlist_part(Part) || Part <- Parts].\ncharlist_part(Binary) when is_binary(Binary) ->\n  Binary;\ncharlist_part({Begin, End, Tokens}) ->\n  Form = string_tokens_parse(Tokens),\n  Meta = meta_from_location(Begin),\n  MetaWithExtra =\n    case ?token_metadata() of\n      true -> [{closing, meta_from_location(End)} | Meta];\n      false -> Meta\n    end,\n  {{'.', Meta, ['Elixir.Kernel', to_string]}, [{from_interpolation, true} | MetaWithExtra], [Form]}.\n\nstring_parts(Parts) ->\n  [string_part(Part) || Part <- Parts].\nstring_part(Binary) when is_binary(Binary) ->\n  Binary;\nstring_part({Begin, End, Tokens}) ->\n  Form = string_tokens_parse(Tokens),\n  Meta = meta_from_location(Begin),\n  MetaWithExtra =\n    case ?token_metadata() of\n      true -> [{closing, meta_from_location(End)} | Meta];\n      false -> Meta\n    end,\n  {'::', Meta, [{{'.', Meta, ['Elixir.Kernel', to_string]}, [{from_interpolation, true} | MetaWithExtra], [Form]}, {binary, Meta, nil}]}.\n\nstring_tokens_parse(Tokens) ->\n  case parse(Tokens) of\n    {ok, Forms} -> Forms;\n    {error, _} = Error -> throw(Error)\n  end.\n\ndelimiter(Delimiter) ->\n  case ?token_metadata() of\n    true -> [{delimiter, Delimiter}];\n    false -> []\n  end.\n\n%% Keywords\n\ncheck_stab([{'->', _, [_, _]}], _) -> stab;\ncheck_stab([], none) -> block;\ncheck_stab([_], none) -> block;\ncheck_stab([_], Meta) -> error_invalid_stab(Meta);\ncheck_stab([{'->', Meta, [_, _]} | T], _) -> check_stab(T, Meta);\ncheck_stab([_ | T], MaybeMeta) -> check_stab(T, MaybeMeta).\n\nbuild_stab(Stab, BlockMeta) ->\n  case check_stab(Stab, none) of\n    block -> build_block(reverse(Stab), BlockMeta);\n    stab -> collect_stab(Stab, [], [])\n  end.\n\nbuild_paren_stab(_Before, [{Op, _, [_]}]=Exprs, _After) when ?rearrange_uop(Op) ->\n  {'__block__', [], Exprs};\nbuild_paren_stab(Before, Stab, After) ->\n  case check_stab(Stab, none) of\n    block -> build_block(reverse(Stab), meta_from_token_with_closing(Before, After));\n    stab -> handle_literal(collect_stab(Stab, [], []), Before, newlines_pair(Before, After))\n  end.\n\ncollect_stab([{'->', Meta, [Left, Right]} | T], Exprs, Stabs) ->\n  Stab = {'->', Meta, [Left, build_block([Right | Exprs])]},\n  collect_stab(T, [], [Stab | Stabs]);\n\ncollect_stab([H | T], Exprs, Stabs) ->\n  collect_stab(T, [H | Exprs], Stabs);\n\ncollect_stab([], [], Stabs) ->\n  Stabs.\n\n%% Every time the parser sees a (unquote_splicing())\n%% it assumes that a block is being spliced, wrapping\n%% the splicing in a __block__. But in the stab clause,\n%% we can have (unquote_splicing(1, 2, 3)) -> :ok, in such\n%% case, we don't actually want the block, since it is\n%% an arg style call. unwrap_splice unwraps the splice\n%% from such blocks.\nunwrap_splice([{'__block__', _, [{unquote_splicing, _, _}] = Splice}]) ->\n  Splice;\nunwrap_splice(Other) ->\n  Other.\n\nunwrap_when(Args) ->\n  case elixir_utils:split_last(Args) of\n    {Start, {'when', Meta, [_, _] = End}} ->\n      [{'when', Meta, Start ++ End}];\n    {_, _} ->\n      Args\n  end.\n\nparens_meta({Open, Close}) ->\n  case ?token_metadata() of\n    true ->\n      ParensEntry = [{closing, meta_from_token(Close)} | meta_from_token(Open)],\n      [{parens, ParensEntry}];\n    false ->\n      []\n  end;\nparens_meta({Open, _Args, Close}) ->\n  parens_meta({Open, Close}).\n\nwith_assoc_meta({Target, Meta, Args}, AssocToken) ->\n  case ?token_metadata() of\n    true ->\n      {Target, [{assoc, meta_from_token(AssocToken)} | Meta], Args};\n    false ->\n      {Target, Meta, Args}\n  end;\n\nwith_assoc_meta(Left, _AssocToken) -> Left.\n\n%% Warnings and errors\n\nreturn_error({Line, Column, _}, ErrorMessage, ErrorToken) ->\n  return_error([{line, Line}, {column, Column}], [ErrorMessage, ErrorToken]).\n\n%% We should prefer to use return_error as it includes\n%% Line and Column but that's not always possible.\nreturn_error_with_meta(Meta, ErrorMessage, ErrorToken) ->\n  return_error(Meta, [ErrorMessage, ErrorToken]).\n\nerror_invalid_stab(MetaStab) ->\n  return_error_with_meta(MetaStab,\n    \"unexpected operator ->. If you want to define multiple clauses, the first expression must use ->. \"\n    \"Syntax error before: \", \"'->'\").\n\nerror_bad_atom(Token) ->\n  return_error(?location(Token), \"atom cannot be followed by an alias. \"\n    \"If the '.' was meant to be part of the atom's name, \"\n    \"the atom name must be quoted. Syntax error before: \", \"'.'\").\n\nbad_keyword(Token, Context, StartString) ->\n  return_error(?location(Token),\n    \"unexpected keyword list inside \" ++ atom_to_list(Context) ++ \". \"\n    \"Did you mean to write a map (using %{...}) or a list (using [...]) instead? \"\n    \"Syntax error after: \", StartString).\n\nmaybe_bad_keyword_call_follow_up(_Token, KW, {'__cursor__', _, []} = Expr) ->\n  reverse([Expr | KW]);\nmaybe_bad_keyword_call_follow_up(Token, _KW, _Expr) ->\n  return_error(?location(Token),\n    \"unexpected expression after keyword list. Keyword lists must always come as the last argument. Therefore, this is not allowed:\\n\\n\"\n    \"    function_call(1, some: :option, 2)\\n\\n\"\n    \"Instead, wrap the keyword in brackets:\\n\\n\"\n    \"    function_call(1, [some: :option], 2)\\n\\n\"\n    \"Syntax error after: \", \"','\").\n\nmaybe_bad_keyword_data_follow_up(_Token, KW, {'__cursor__', _, []} = Expr) ->\n  reverse([Expr | KW]);\nmaybe_bad_keyword_data_follow_up(Token, _KW, _Expr) ->\n  return_error(?location(Token),\n    \"unexpected expression after keyword list. Keyword lists must always come last in lists and maps. Therefore, this is not allowed:\\n\\n\"\n    \"    [some: :value, :another]\\n\"\n    \"    %{some: :value, another => value}\\n\\n\"\n    \"Instead, reorder it to be the last entry:\\n\\n\"\n    \"    [:another, some: :value]\\n\"\n    \"    %{another => value, some: :value}\\n\\n\"\n    \"Syntax error after: \", \"','\").\n\nerror_no_parens_strict(Token) ->\n  return_error(?location(Token), \"unexpected parentheses. If you are making a \"\n    \"function call, do not insert spaces between the function name and the \"\n    \"opening parentheses. Syntax error before: \", \"'('\").\n\nerror_no_parens_many_strict(Node) ->\n  return_error_with_meta(?meta(Node),\n    \"unexpected comma. Parentheses are required to solve ambiguity in nested calls.\\n\\n\"\n    \"This error happens when you have nested function calls without parentheses. \"\n    \"For example:\\n\\n\"\n    \"    parent_call a, nested_call b, c, d\\n\\n\"\n    \"In the example above, we don't know if the parameters \\\"c\\\" and \\\"d\\\" apply \"\n    \"to the function \\\"parent_call\\\" or \\\"nested_call\\\". You can solve this by \"\n    \"explicitly adding parentheses:\\n\\n\"\n    \"    parent_call a, nested_call(b, c, d)\\n\\n\"\n    \"Or by adding commas (in case a nested call is not intended):\\n\\n\"\n    \"    parent_call a, nested_call, b, c, d\\n\\n\"\n    \"Elixir cannot compile otherwise. Syntax error before: \", \"','\").\n\nerror_no_parens_container_strict(Node) ->\n  return_error_with_meta(?meta(Node),\n    \"unexpected comma. Parentheses are required to solve ambiguity inside containers.\\n\\n\"\n    \"This error may happen when you forget a comma in a list or other container:\\n\\n\"\n    \"    [a, b c, d]\\n\\n\"\n    \"Or when you have ambiguous calls:\\n\\n\"\n    \"    [function a, b, c]\\n\\n\"\n    \"In the example above, we don't know if the values \\\"b\\\" and \\\"c\\\" \"\n    \"belongs to the list or the function \\\"function\\\". You can solve this by explicitly \"\n    \"adding parentheses:\\n\\n\"\n    \"    [one, function(a, b, c)]\\n\\n\"\n    \"Elixir cannot compile otherwise. Syntax error before: \", \"','\").\n\nerror_too_many_access_syntax(Comma) ->\n  return_error(?location(Comma), \"too many arguments when accessing a value. \"\n    \"The value[key] notation in Elixir expects either a single argument or a keyword list. \"\n    \"The following examples are allowed:\\n\\n\"\n    \"    value[one]\\n\"\n    \"    value[one: 1, two: 2]\\n\"\n    \"    value[[one, two, three]]\\n\\n\"\n    \"These are invalid:\\n\\n\"\n    \"    value[1, 2, 3]\\n\"\n    \"    value[one, two, three]\\n\\n\"\n    \"Syntax error after: \", \"','\").\n\nerror_invalid_kw_identifier({_, Location, do}) ->\n  return_error(Location, elixir_tokenizer:invalid_do_error(\"unexpected keyword: \"), \"do:\");\nerror_invalid_kw_identifier({_, Location, KW}) ->\n  return_error(Location, \"syntax error before: \", \"'\" ++ atom_to_list(KW) ++ \":'\").\n\n%% TODO: Make this an error on v2.0\nwarn_trailing_comma({',', {Line, Column, _}}) ->\n  warn({Line, Column}, \"trailing commas are not allowed inside function/macro call arguments\").\n\n%% TODO: Make this an error on v2.0\nwarn_pipe({arrow_op, {Line, Column, _}, Op}, {_, [_ | _], [_ | _]}) ->\n  warn(\n    {Line, Column},\n    io_lib:format(\n      \"parentheses are required when piping into a function call. For example:\\n\\n\"\n      \"    foo 1 ~ts bar 2 ~ts baz 3\\n\\n\"\n      \"is ambiguous and should be written as\\n\\n\"\n      \"    foo(1) ~ts bar(2) ~ts baz(3)\\n\\n\"\n      \"Ambiguous pipe found at:\",\n      [Op, Op, Op, Op]\n    )\n  );\nwarn_pipe(_Token, _) ->\n  ok.\n\n%% TODO: Make this an error on v2.0\nwarn_no_parens_after_do_op({Token, _}) ->\n  {Line, _, _} = ?location(Token),\n\n  warn(\n    Line,\n    \"missing parentheses on expression following operator \\\"\" ++ atom_to_list(?op(Token)) ++ \"\\\", \"\n    \"you must add parentheses to avoid ambiguities\"\n  ).\n\n%% TODO: Make this an error on v2.0\nwarn_nested_no_parens_keyword(Key, Value) when is_atom(Key) ->\n  {line, Line} = lists:keyfind(line, 1, ?meta(Value)),\n  warn(\n    Line,\n    \"missing parentheses for expression following \\\"\" ++ atom_to_list(Key) ++ \":\\\" keyword. \"\n    \"Parentheses are required to solve ambiguity inside keywords.\\n\\n\"\n    \"This error happens when you have function calls without parentheses inside keywords. \"\n    \"For example:\\n\\n\"\n    \"    function(arg, one: nested_call a, b, c)\\n\"\n    \"    function(arg, one: if expr, do: :this, else: :that)\\n\\n\"\n    \"In the examples above, we don't know if the arguments \\\"b\\\" and \\\"c\\\" apply \"\n    \"to the function \\\"function\\\" or \\\"nested_call\\\". Or if the keywords \\\"do\\\" and \"\n    \"\\\"else\\\" apply to the function \\\"function\\\" or \\\"if\\\". You can solve this by \"\n    \"explicitly adding parentheses:\\n\\n\"\n    \"    function(arg, one: if(expr, do: :this, else: :that))\\n\"\n    \"    function(arg, one: nested_call(a, b, c))\\n\\n\"\n    \"Ambiguity found at:\"\n  );\n\n% Key might not be an atom when using literal_encoder, we just skip the warning\nwarn_nested_no_parens_keyword(_Key, _Value) ->\n  ok.\n\nwarn_empty_paren({{_, {Line, Column, _}}, _}) ->\n  warn(\n    {Line, Column},\n    \"invalid expression (). \"\n    \"If you want to invoke or define a function, make sure there are \"\n    \"no spaces between the function name and its arguments. If you wanted \"\n    \"to pass an empty block or code, pass a value instead, such as a nil or an atom\"\n  ).\n\nwarn_empty_stab_clause({stab_op, {Line, Column, _}, '->'}) ->\n  warn(\n    {Line, Column},\n    \"an expression is always required on the right side of ->. \"\n    \"Please provide a value after ->\"\n  ).\n\nwarn(LineColumn, Message) ->\n  put(elixir_parser_warnings, [{LineColumn, Message} | get(elixir_parser_warnings)]).\n"
  },
  {
    "path": "lib/elixir/src/elixir_quote.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_quote).\n\n-feature(maybe_expr, enable).\n\n-export([escape/3, linify/3, linify_with_context_counter/3, build/7, quote/2, has_unquotes/1, fun_to_quoted/1]).\n-export([dot/5, tail_list/3, list/2, validate_runtime/2, shallow_validate_ast/1]). %% Quote callbacks\n\n-include(\"elixir.hrl\").\n-define(defs(Kind), Kind == def; Kind == defp; Kind == defmacro; Kind == defmacrop; Kind == '@').\n-define(lexical(Kind), Kind == import; Kind == alias; Kind == require).\n-compile({inline, [keyfind/2, keystore/3, keydelete/2, keynew/3, do_tuple_linify/6]}).\n\n-record(elixir_quote, {\n  line=false,\n  file=nil,\n  context=nil,\n  op=escape, % escape | escape_and_prune | {struct, Module} | quote\n  aliases_hygiene=nil,\n  imports_hygiene=nil,\n  unquote=true,\n  generated=false,\n  shallow_validate=false\n}).\n\n%% fun_to_quoted\n\nfun_to_quoted(Function) ->\n  Meta = [],\n  {module, Module} = erlang:fun_info(Function, module),\n  {name, Name}     = erlang:fun_info(Function, name),\n  {arity, Arity}   = erlang:fun_info(Function, arity),\n  {'&', Meta, [{'/', Meta, [{{'.', Meta, [Module, Name]}, [{no_parens, true} | Meta], []}, Arity]}]}.\n\n%% has_unquotes\n\nhas_unquotes(Ast) -> has_unquotes(Ast, 0).\n\nhas_unquotes({quote, _, [Child]}, QuoteLevel) ->\n  has_unquotes(Child, QuoteLevel + 1);\nhas_unquotes({quote, _, [QuoteOpts, Child]}, QuoteLevel) ->\n  case disables_unquote(QuoteOpts) of\n    true -> false;\n    _ -> has_unquotes(Child, QuoteLevel + 1)\n  end;\nhas_unquotes({Unquote, _, [Child]}, QuoteLevel)\n  when Unquote == unquote; Unquote == unquote_splicing ->\n  case QuoteLevel of\n    0 -> true;\n    _ ->  has_unquotes(Child, QuoteLevel - 1)\nend;\nhas_unquotes({{'.', _, [_, unquote]}, _, [_]}, _) -> true;\nhas_unquotes({Var, _, Ctx}, _) when is_atom(Var), is_atom(Ctx) -> false;\nhas_unquotes({Name, _, Args}, QuoteLevel) when is_list(Args) ->\n  has_unquotes(Name) orelse lists:any(fun(Child) -> has_unquotes(Child, QuoteLevel) end, Args);\nhas_unquotes({Left, Right}, QuoteLevel) ->\n  has_unquotes(Left, QuoteLevel) orelse has_unquotes(Right, QuoteLevel);\nhas_unquotes(List, QuoteLevel) when is_list(List) ->\n  lists:any(fun(Child) -> has_unquotes(Child, QuoteLevel) end, List);\nhas_unquotes(_Other, _) -> false.\n\ndisables_unquote([{unquote, false} | _]) -> true;\ndisables_unquote([{bind_quoted, _} | _]) -> true;\ndisables_unquote([_H | T]) -> disables_unquote(T);\ndisables_unquote(_) -> false.\n\n%% Apply the line from site call on quoted contents.\n%% Receives a Key to look for the default line as argument.\nlinify(0, _Key, Exprs) ->\n  Exprs;\nlinify(Line, Key, Exprs) when is_integer(Line) ->\n  Fun =\n    case Key of\n      line ->\n        fun(Meta) -> keynew(line, Meta, Line) end;\n      keep ->\n        fun(Meta) ->\n          case lists:keytake(keep, 1, Meta) of\n            {value, {keep, {_, Int}}, MetaNoFile} ->\n              [{line, Int} | keydelete(line, MetaNoFile)];\n            _ ->\n              keynew(line, Meta, Line)\n          end\n        end\n    end,\n\n  do_linify(Fun, Exprs, nil, false).\n\n%% Same as linify but also considers the context counter and generated.\nlinify_with_context_counter(ContextMeta, Var, Exprs) when is_list(ContextMeta) ->\n  Line = ?line(ContextMeta),\n\n  Generated = keyfind(generated, ContextMeta) == {generated, true},\n\n  Fun = if\n    Line =:= 0 -> fun(Meta) -> Meta end;\n    true -> fun(Meta) -> keynew(line, Meta, Line) end\n  end,\n\n  do_linify(Fun, Exprs, Var, Generated).\n\ndo_linify(Fun, {quote, Meta, [_ | _] = Args}, {Receiver, Counter} = Var, Gen)\n    when is_list(Meta) ->\n  NewMeta =\n    case keyfind(context, Meta) == {context, Receiver} of\n      true -> keynew(counter, Meta, Counter);\n      false -> Meta\n    end,\n  do_tuple_linify(Fun, NewMeta, quote, Args, Var, Gen);\n\ndo_linify(Fun, {Left, Meta, Receiver}, {Receiver, Counter} = Var, Gen)\n    when is_atom(Left), is_list(Meta), Left /= '_' ->\n  do_tuple_linify(Fun, keynew(counter, Meta, Counter), Left, Receiver, Var, Gen);\n\ndo_linify(Fun, {Lexical, Meta, [_ | _] = Args}, {_, Counter} = Var, Gen)\n    when ?lexical(Lexical); Lexical == '__aliases__' ->\n  do_tuple_linify(Fun, keynew(counter, Meta, Counter), Lexical, Args, Var, Gen);\n\ndo_linify(Fun, {Left, Meta, Right}, Var, Gen) when is_list(Meta) ->\n  do_tuple_linify(Fun, Meta, Left, Right, Var, Gen);\n\ndo_linify(Fun, {Left, Right}, Var, Gen) ->\n  {do_linify(Fun, Left, Var, Gen), do_linify(Fun, Right, Var, Gen)};\n\ndo_linify(Fun, List, Var, Gen) when is_list(List) ->\n  [do_linify(Fun, X, Var, Gen) || X <- List];\n\ndo_linify(_, Else, _, _Gen) -> Else.\n\ndo_tuple_linify(Fun, Meta, Left, Right, Var, Gen) ->\n  {NewMeta, NewGen} =\n    case keyfind(stop_generated, Meta) of\n      {stop_generated, true} -> {keydelete(stop_generated, Meta), false};\n      _ when Gen -> {elixir_utils:generated(Meta), Gen};\n      _ -> {Meta, Gen}\n    end,\n\n  {do_linify(Fun, Left, Var, NewGen), Fun(NewMeta), do_linify(Fun, Right, Var, NewGen)}.\n\n%% Escaping\n\n%% Escapes the given expression. It is similar to quote, but\n%% lines are kept and hygiene mechanisms are disabled.\nescape(Expr, Op, Unquote) ->\n  try\n    do_quote(Expr, #elixir_quote{\n      line=true,\n      file=nil,\n      op=Op,\n      unquote=Unquote\n    })\n  catch\n    Kind:Reason:Stacktrace ->\n      Pruned = lists:dropwhile(fun\n        ({?MODULE, _, _, _}) -> true;\n        (_) -> false\n      end, Stacktrace),\n      erlang:raise(Kind, Reason, Pruned)\n  end.\n\ndo_escape({Left, Meta, Right}, #elixir_quote{op=escape_and_prune} = Q) when is_list(Meta) ->\n  TM = [{K, V} || {K, V} <- Meta, (K == no_parens) orelse (K == line) orelse (K == delimiter)],\n  TL = do_quote(Left, Q),\n  TR = do_quote(Right, Q),\n  {'{}', [], [TL, TM, TR]};\n\ndo_escape({Left, Right}, Q) ->\n  {do_quote(Left, Q), do_quote(Right, Q)};\n\ndo_escape(Tuple, Q) when is_tuple(Tuple) ->\n  TT = do_quote(tuple_to_list(Tuple), Q),\n  {'{}', [], TT};\n\ndo_escape(BitString, _) when is_bitstring(BitString) ->\n  case bit_size(BitString) rem 8 of\n    0 ->\n      BitString;\n    Size ->\n      <<Bits:Size, Bytes/binary>> = BitString,\n      {'<<>>', [], [{'::', [], [Bits, {size, [], [Size]}]}, {'::', [], [Bytes, {binary, [], nil}]}]}\n  end;\n\ndo_escape(Map, Q) when is_map(Map) ->\n  maybe\n    #{'__struct__' := Module} ?= Map,\n    true ?= is_atom(Module),\n    % We never escape ourselves (it can only happen during Elixir bootstrapping)\n    true ?= (Q#elixir_quote.op /= {struct, Module}),\n    {module, Module} ?= code:ensure_loaded(Module),\n    true ?= erlang:function_exported(Module, '__escape__', 1),\n    case Q#elixir_quote.op of\n      {struct, _Module} ->\n        argument_error(<<('Elixir.Kernel':inspect(Module))/binary,\n          \" defines custom escaping rules which are not supported in struct defaults\",\n          (bad_escape_hint())/binary>>);\n\n      _ ->\n        Expr = Module:'__escape__'(Map),\n        case shallow_valid_ast(Expr) of\n          true -> Expr;\n          false -> argument_error(\n            <<('Elixir.Kernel':inspect(Module))/binary, \".__escape__/1 returned invalid AST: \", ('Elixir.Kernel':inspect(Expr))/binary>>\n          )\n        end\n    end\n  else\n    _ ->\n      TT = [\n        {do_quote(K, Q), do_quote(V, Q)}\n        || {K, V} <- lists:sort(maps:to_list(Map))\n      ],\n      {'%{}', [], TT}\n  end;\n\ndo_escape([], _) ->\n  [];\n\ndo_escape([H | T], #elixir_quote{unquote=false} = Q) ->\n  do_quote_simple_list(T, do_escape(H, Q), Q);\n\ndo_escape([H | T], Q) ->\n  %% The improper case is inefficient, but improper lists are rare.\n  try lists:reverse(T, [H]) of\n    L -> do_quote_tail(L, Q)\n  catch\n    _:_ ->\n      {L, R} = reverse_improper(T, [H]),\n      TL = do_quote_splice(L, Q, [], []),\n      TR = do_quote(R, Q),\n      update_last(TL, fun(X) -> {'|', [], [X, TR]} end)\n  end;\n\ndo_escape(Other, _) when is_number(Other); is_atom(Other); is_pid(Other) ->\n  Other;\n\ndo_escape(Fun, _) when is_function(Fun) ->\n  case (erlang:fun_info(Fun, env) == {env, []}) andalso\n       (erlang:fun_info(Fun, type) == {type, external}) of\n    true  -> fun_to_quoted(Fun);\n    false -> bad_escape(Fun)\n  end;\n\ndo_escape(Other, _) ->\n  bad_escape(Other).\n\nbad_escape(Arg) ->\n  argument_error(<<\"cannot escape \", ('Elixir.Kernel':inspect(Arg, []))/binary,\n                   (bad_escape_hint())/binary>>).\n\nbad_escape_hint() ->\n  <<\". The supported values are: lists, tuples, maps, atoms, numbers, bitstrings, \",\n    \"PIDs and remote functions in the format &Mod.fun/arity\">>.\n\n%% Quote entry points\n\nbuild(Meta, Line, File, Context, Unquote, Generated, E) ->\n  Acc0 = [],\n  {VLine, Acc1} = validate_compile(Meta, line, Line, Acc0),\n  {VFile, Acc2} = validate_compile(Meta, file, File, Acc1),\n  {VContext, Acc3} = validate_compile(Meta, context, Context, Acc2),\n  validate_runtime(unquote, Unquote),\n  validate_runtime(generated, Generated),\n\n  Q = #elixir_quote{\n    op=quote,\n    aliases_hygiene=E,\n    imports_hygiene=E,\n    line=VLine,\n    file=VFile,\n    unquote=Unquote,\n    context=VContext,\n    generated=Generated,\n    shallow_validate=true\n  },\n\n  {Q, VContext, Acc3}.\n\nvalidate_compile(_Meta, line, Value, Acc) when is_boolean(Value) ->\n  {Value, Acc};\nvalidate_compile(_Meta, file, nil, Acc) ->\n  {nil, Acc};\nvalidate_compile(Meta, Key, Value, Acc) ->\n  case is_valid(Key, Value) of\n    true ->\n      {Value, Acc};\n    false ->\n      Var = {Key, Meta, ?MODULE},\n      Call = {{'.', Meta, [?MODULE, validate_runtime]}, Meta, [Key, Value]},\n      {Var, [{'=', Meta, [Var, Call]} | Acc]}\n  end.\n\nvalidate_runtime(Key, Value) ->\n  case is_valid(Key, Value) of\n    true ->\n      Value;\n\n    false ->\n      erlang:error(\n        'Elixir.ArgumentError':exception(\n          <<\"invalid runtime value for option :\", (erlang:atom_to_binary(Key))/binary,\n            \" in quote, got: \", ('Elixir.Kernel':inspect(Value))/binary>>\n        )\n      )\n  end.\n\nis_valid(line, Line) -> is_integer(Line);\nis_valid(file, File) -> is_binary(File);\nis_valid(context, Context) -> is_atom(Context) andalso (Context /= nil);\nis_valid(generated, Generated) -> is_boolean(Generated);\nis_valid(unquote, Unquote) -> is_boolean(Unquote).\n\nshallow_validate_ast(Expr) ->\n  case shallow_valid_ast(Expr) of\n    true -> Expr;\n    false -> argument_error(\n      <<\"tried to unquote invalid AST: \", ('Elixir.Kernel':inspect(Expr))/binary,\n        \"\\nDid you forget to escape term using Macro.escape/1?\">>)\n  end.\n\nshallow_valid_ast(Expr) when is_list(Expr) -> valid_ast_list(Expr);\nshallow_valid_ast(Expr) -> valid_ast_elem(Expr).\n\nvalid_ast_list([]) -> true;\nvalid_ast_list([Head | Tail]) -> valid_ast_elem(Head) andalso valid_ast_list(Tail);\nvalid_ast_list(_Improper) -> false.\n\nvalid_ast_elem(Expr) when is_list(Expr); is_atom(Expr); is_binary(Expr); is_number(Expr); is_pid(Expr); is_function(Expr) -> true;\nvalid_ast_elem({Left, Right}) -> valid_ast_elem(Left) andalso valid_ast_elem(Right);\nvalid_ast_elem({Atom, Meta, Args}) when is_atom(Atom), is_list(Meta), is_atom(Args) orelse is_list(Args) -> true;\nvalid_ast_elem({Call, Meta, Args}) when is_list(Meta), is_list(Args) -> shallow_valid_ast(Call);\nvalid_ast_elem(_Term) -> false.\n\nquote({unquote_splicing, _, [_]}, #elixir_quote{unquote=true}) ->\n  argument_error(<<\"unquote_splicing only works inside arguments and block contexts, \"\n    \"wrap it in parens if you want it to work with one-liners\">>);\nquote(Expr, Q) ->\n  do_quote(Expr, Q).\n\n%% quote/unquote\n\ndo_quote({quote, Meta, [Arg]}, Q) when is_list(Meta) ->\n  TArg = do_quote(Arg, Q#elixir_quote{unquote=false}),\n\n  NewMeta = case Q of\n    #elixir_quote{op=quote, context=Context} -> keystore(context, Meta, Context);\n    _ -> Meta\n  end,\n\n  {'{}', [], [quote, meta(NewMeta, Q), [TArg]]};\n\ndo_quote({quote, Meta, [Opts, Arg]}, Q) when is_list(Meta) ->\n  TOpts = do_quote(Opts, Q),\n  TArg = do_quote(Arg, Q#elixir_quote{unquote=false}),\n\n  NewMeta = case Q of\n    #elixir_quote{op=quote, context=Context} -> keystore(context, Meta, Context);\n    _ -> Meta\n  end,\n\n  {'{}', [], [quote, meta(NewMeta, Q), [TOpts, TArg]]};\n\ndo_quote({unquote, Meta, [Expr]}, #elixir_quote{unquote=true, shallow_validate=Validate}) when is_list(Meta) ->\n  case Validate of\n    true -> {{'.', Meta, [?MODULE, shallow_validate_ast]}, Meta, [Expr]};\n    false -> Expr\n  end;\n\n%% Aliases\n\ndo_quote({'__aliases__', Meta, [H | T]}, #elixir_quote{aliases_hygiene=(#{}=E)} = Q)\n     when is_list(Meta), is_atom(H), H /= 'Elixir' ->\n  Annotation =\n    case elixir_aliases:expand(Meta, [H | T], E, true) of\n      Atom when is_atom(Atom) -> Atom;\n      Aliases when is_list(Aliases) -> false\n    end,\n  AliasMeta = keystore(alias, keydelete(counter, Meta), Annotation),\n  do_quote_tuple('__aliases__', AliasMeta, [H | T], Q);\n\n%% Vars\n\ndo_quote({Name, Meta, nil}, #elixir_quote{op=quote} = Q)\n    when is_atom(Name), is_list(Meta) ->\n  ImportMeta = case Q#elixir_quote.imports_hygiene of\n    nil -> Meta;\n    E -> import_meta(Meta, Name, 0, Q, E)\n  end,\n\n  {'{}', [], [Name, meta(ImportMeta, Q), Q#elixir_quote.context]};\n\n%% Unquote\n\ndo_quote({{{'.', Meta, [Left, unquote]}, _, [Expr]}, _, Args}, #elixir_quote{unquote=true} = Q) when is_list(Meta) ->\n  do_quote_call(Left, Meta, Expr, Args, Q);\n\ndo_quote({{'.', Meta, [Left, unquote]}, _, [Expr]}, #elixir_quote{unquote=true} = Q) when is_list(Meta) ->\n  do_quote_call(Left, Meta, Expr, nil, Q);\n\n%% Imports\n\ndo_quote({'&', Meta, [{'/', _, [{F, _, C}, A]}] = Args},\n  #elixir_quote{imports_hygiene=(#{}=E)} = Q) when is_atom(F), is_integer(A), is_atom(C), is_list(Meta) ->\n  NewMeta =\n    case elixir_dispatch:find_import(Meta, F, A, E) of\n      false ->\n        Meta;\n\n      Receiver ->\n        keystore(context, keystore(imports, Meta, [{A, Receiver}]), Q#elixir_quote.context)\n    end,\n  do_quote_tuple('&', NewMeta, Args, Q);\n\ndo_quote({Name, Meta, ArgsOrContext}, #elixir_quote{imports_hygiene=(#{}=E)} = Q)\n    when is_atom(Name), is_list(Meta), is_list(ArgsOrContext) or is_atom(ArgsOrContext) ->\n  Arity = if\n    is_atom(ArgsOrContext) -> 0;\n    true -> length(ArgsOrContext)\n  end,\n\n  ImportMeta = import_meta(Meta, Name, Arity, Q, E),\n  Annotated = annotate({Name, ImportMeta, ArgsOrContext}, Q#elixir_quote.context),\n  do_quote_tuple(Annotated, Q);\n\n%% Two-element tuples\n\ndo_quote({Left, Right}, #elixir_quote{unquote=true} = Q) when\n    is_tuple(Left)  andalso (element(1, Left) == unquote_splicing);\n    is_tuple(Right) andalso (element(1, Right) == unquote_splicing) ->\n  do_quote({'{}', [], [Left, Right]}, Q);\n\ndo_quote({Left, Right}, Q) ->\n  TLeft  = do_quote(Left, Q),\n  TRight = do_quote(Right, Q),\n  {TLeft, TRight};\n\n%% Everything else\n\ndo_quote(Other, #elixir_quote{op=Op} = Q) when Op =/= quote ->\n  do_escape(Other, Q);\n\ndo_quote({_, _, _} = Tuple, Q) ->\n  Annotated = annotate(Tuple, Q#elixir_quote.context),\n  do_quote_tuple(Annotated, Q);\n\ndo_quote([], _) ->\n  [];\n\ndo_quote([H | T], #elixir_quote{unquote=false} = Q) ->\n  do_quote_simple_list(T, do_quote(H, Q), Q);\n\ndo_quote([H | T], Q) ->\n  do_quote_tail(lists:reverse(T, [H]), Q);\n\ndo_quote(Other, _) ->\n  Other.\n\nimport_meta(Meta, Name, Arity, Q, E) ->\n  case (keyfind(imports, Meta) == false) andalso\n      elixir_dispatch:find_imports(Meta, Name, E) of\n    [_ | _] = Imports ->\n      trace_import_quoted(Imports, Meta, Name, E),\n      keystore(imports, keystore(context, Meta, Q#elixir_quote.context), Imports);\n\n    _ ->\n      case (Arity == 1) andalso keyfind(ambiguous_op, Meta) of\n        {ambiguous_op, nil} -> keystore(ambiguous_op, Meta, Q#elixir_quote.context);\n        _ -> Meta\n      end\n  end.\n\ntrace_import_quoted([{Arity, Mod} | Imports], Meta, Name, E) ->\n  {Rest, Arities} = collect_trace_import_quoted(Imports, Mod, [], [Arity]),\n  elixir_env:trace({imported_quoted, Meta, Mod, Name, Arities}, E),\n  trace_import_quoted(Rest, Meta, Name, E);\ntrace_import_quoted([], _Meta, _Name, _E) ->\n  ok.\n\ncollect_trace_import_quoted([{Arity, Mod} | Imports], Mod, Acc, Arities) ->\n  collect_trace_import_quoted(Imports, Mod, Acc, [Arity | Arities]);\ncollect_trace_import_quoted([Import | Imports], Mod, Acc, Arities) ->\n  collect_trace_import_quoted(Imports, Mod, [Import | Acc], Arities);\ncollect_trace_import_quoted([], _Mod, Acc, Arities) ->\n  {lists:reverse(Acc), lists:reverse(Arities)}.\n\n%% do_quote_*\n\ndo_quote_call(Left, Meta, Expr, Args, Q) ->\n  All  = [Left, {unquote, Meta, [Expr]}, Args, Q#elixir_quote.context],\n  TAll = [do_quote(X, Q) || X <- All],\n  {{'.', Meta, [elixir_quote, dot]}, Meta, [meta(Meta, Q) | TAll]}.\n\ndo_quote_tuple({Left, Meta, Right}, Q) ->\n  do_quote_tuple(Left, Meta, Right, Q).\n\ndo_quote_tuple(Left, Meta, Right, Q) ->\n  TLeft = do_quote(Left, Q),\n  TRight = do_quote(Right, Q),\n  {'{}', [], [TLeft, meta(Meta, Q), TRight]}.\n\ndo_quote_simple_list([], Prev, _) -> [Prev];\ndo_quote_simple_list([H | T], Prev, Q) ->\n  [Prev | do_quote_simple_list(T, do_quote(H, Q), Q)];\ndo_quote_simple_list(Other, Prev, Q) ->\n  [{'|', [], [Prev, do_quote(Other, Q)]}].\n\ndo_quote_tail([{'|', Meta, [{unquote_splicing, _, [Left]}, Right]} | T], #elixir_quote{unquote=true} = Q) ->\n  %% Process the remaining entries on the list.\n  %% For [1, 2, 3, unquote_splicing(arg) | tail], this will quote\n  %% 1, 2 and 3, which could even be unquotes.\n  TT = do_quote_splice(T, Q, [], []),\n  TR = do_quote(Right, Q),\n  do_runtime_list(Meta, tail_list, [Left, TR, TT]);\n\ndo_quote_tail(List, Q) ->\n  do_quote_splice(List, Q, [], []).\n\ndo_quote_splice([{unquote_splicing, Meta, [Expr]} | T], #elixir_quote{unquote=true} = Q, Buffer, Acc) ->\n  Runtime = do_runtime_list(Meta, list, [Expr, do_list_concat(Buffer, Acc)]),\n  do_quote_splice(T, Q, [], Runtime);\n\ndo_quote_splice([H | T], Q, Buffer, Acc) ->\n  TH = do_quote(H, Q),\n  do_quote_splice(T, Q, [TH | Buffer], Acc);\n\ndo_quote_splice([], _Q, Buffer, Acc) ->\n  do_list_concat(Buffer, Acc).\n\ndo_list_concat(Left, []) -> Left;\ndo_list_concat([], Right) -> Right;\ndo_list_concat(Left, Right) -> {{'.', [], [erlang, '++']}, [], [Left, Right]}.\n\ndo_runtime_list(Meta, Fun, Args) ->\n  {{'.', Meta, [elixir_quote, Fun]}, Meta, Args}.\n\n%% Callbacks\n\n%% Some expressions cannot be unquoted at compilation time.\n%% This function is responsible for doing runtime unquoting.\ndot(Meta, Left, Right, Args, Context) ->\n  annotate(dot(Meta, Left, Right, Args), Context).\n\ndot(Meta, Left, {'__aliases__', _, Args}, nil) ->\n  {'__aliases__', Meta, [Left | Args]};\n\ndot(Meta, Left, Right, nil) when is_atom(Right) ->\n  case atom_to_list(Right) of\n    \"Elixir.\" ++ _ ->\n      {'__aliases__', Meta, [Left, Right]};\n    _ ->\n      {{'.', Meta, [Left, Right]}, [{no_parens, true} | Meta], []}\n  end;\n\ndot(Meta, Left, {Right, _, Context}, nil) when is_atom(Right), is_atom(Context) ->\n  {{'.', Meta, [Left, Right]}, [{no_parens, true} | Meta], []};\n\ndot(Meta, Left, {Right, _, Args}, nil) when is_atom(Right) ->\n  {{'.', Meta, [Left, Right]}, Meta, Args};\n\ndot(_Meta, _Left, Right, nil) ->\n  argument_error(<<\"expected unquote after dot to return an atom, an alias or a quoted call, got: \",\n                   ('Elixir.Macro':to_string(Right))/binary>>);\n\ndot(Meta, Left, Right, Args) when is_atom(Right) ->\n  {{'.', Meta, [Left, Right]}, Meta, Args};\n\ndot(Meta, Left, {Right, _, Context}, Args) when is_atom(Right), is_atom(Context) ->\n  {{'.', Meta, [Left, Right]}, Meta, Args};\n\ndot(_Meta, _Left, Right, _Args) ->\n  argument_error(<<\"expected unquote after dot with args to return an atom or a quoted call, got: \",\n                   ('Elixir.Macro':to_string(Right))/binary>>).\n\nlist(Left, Right) when is_list(Right) ->\n  validate_list(Left),\n  Left ++ Right.\n\ntail_list(Left, Right, Tail) when is_list(Right), is_list(Tail) ->\n  validate_list(Left),\n  Tail ++ Left ++ Right;\n\ntail_list(Left, Right, Tail) when is_list(Left) ->\n  validate_list(Left),\n  [H | T] = lists:reverse(Tail ++ Left),\n  lists:reverse([{'|', [], [H, Right]} | T]).\n\nvalidate_list(List) ->\n  case valid_ast_list(List) of\n    true -> ok;\n    false -> argument_error(<<\"expected a list with quoted expressions in unquote_splicing/1, got: \",\n                   ('Elixir.Kernel':inspect(List))/binary>>)\n  end.\n\nargument_error(Message) ->\n  error('Elixir.ArgumentError':exception([{message, Message}])).\n\n%% Helpers\n\nmeta(Meta, #elixir_quote{op=quote} = Q) ->\n  generated(keep(keydelete(column, Meta), Q), Q);\nmeta(Meta, Q) ->\n  do_quote(Meta, Q).\n\ngenerated(Meta, #elixir_quote{generated=true}) -> [{generated, true} | Meta];\ngenerated(Meta, #elixir_quote{generated=false}) -> Meta.\n\nkeep(Meta, #elixir_quote{file=nil, line=Line}) ->\n  line(Meta, Line);\nkeep(Meta, #elixir_quote{file=File, line=true}) ->\n  case lists:keytake(line, 1, Meta) of\n    {value, {line, Line}, MetaNoLine} ->\n      [{keep, {File, Line}} | MetaNoLine];\n    false ->\n      [{keep, {File, 0}} | Meta]\n  end;\nkeep(Meta, #elixir_quote{file=File, line=false}) ->\n  [{keep, {File, 0}} | keydelete(line, Meta)];\nkeep(Meta, #elixir_quote{file=File, line=Line}) ->\n  [{keep, {File, Line}} | keydelete(line, Meta)].\n\nline(Meta, true) ->\n  Meta;\nline(Meta, false) ->\n  keydelete(line, Meta);\nline(Meta, Line) ->\n  keystore(line, Meta, Line).\n\nreverse_improper([H | T], Acc) -> reverse_improper(T, [H | Acc]);\nreverse_improper([], Acc) -> Acc;\nreverse_improper(T, Acc) -> {Acc, T}.\n\nupdate_last([], _) -> [];\nupdate_last([H], F) -> [F(H)];\nupdate_last([H | T], F) -> [H | update_last(T, F)].\n\nkeyfind(Key, Meta) ->\n  lists:keyfind(Key, 1, Meta).\nkeydelete(Key, Meta) ->\n  lists:keydelete(Key, 1, Meta).\nkeystore(_Key, Meta, nil) ->\n  Meta;\nkeystore(Key, Meta, Value) ->\n  lists:keystore(Key, 1, Meta, {Key, Value}).\nkeynew(Key, Meta, Value) ->\n  case lists:keymember(Key, 1, Meta) of\n    true -> Meta;\n    false -> [{Key, Value} | Meta]\n  end.\n\n%% Annotates the AST with context and other info.\n%%\n%% Note we need to delete the counter because linify\n%% adds the counter recursively, even inside quoted\n%% expressions, so we need to clean up the forms to\n%% allow them to get a new counter on the next expansion.\n\nannotate({Def, Meta, [H | T]}, Context) when ?defs(Def) ->\n  {Def, Meta, [annotate_def(H, Context) | T]};\nannotate({{'.', _, [_, Def]} = Target, Meta, [H | T]}, Context) when ?defs(Def) ->\n  {Target, Meta, [annotate_def(H, Context) | T]};\nannotate({Lexical, Meta, [_ | _] = Args}, Context) when ?lexical(Lexical) ->\n  NewMeta = keystore(context, keydelete(counter, Meta), Context),\n  {Lexical, NewMeta, Args};\nannotate(Tree, _Context) -> Tree.\n\nannotate_def({'when', Meta, [Left, Right]}, Context) ->\n  {'when', Meta, [annotate_def(Left, Context), Right]};\nannotate_def({Fun, Meta, Args}, Context) ->\n  {Fun, keystore(context, Meta, Context), Args};\nannotate_def(Other, _Context) ->\n  Other.\n"
  },
  {
    "path": "lib/elixir/src/elixir_rewrite.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_rewrite).\n-compile({inline, [inner_inline/4, inner_rewrite/5]}).\n-compile(nowarn_shadow_vars).\n-export([erl_to_ex/3, inline/3, rewrite/5, match/6, guard/6, format_error/1]).\n-include(\"elixir.hrl\").\n\n%% Convenience variables\n\n-define(atom, 'Elixir.Atom').\n-define(bitwise, 'Elixir.Bitwise').\n-define(enum, 'Elixir.Enum').\n-define(float, 'Elixir.Float').\n-define(function, 'Elixir.Function').\n-define(integer, 'Elixir.Integer').\n-define(io, 'Elixir.IO').\n-define(kernel, 'Elixir.Kernel').\n-define(list, 'Elixir.List').\n-define(map, 'Elixir.Map').\n-define(node, 'Elixir.Node').\n-define(port, 'Elixir.Port').\n-define(process, 'Elixir.Process').\n-define(string, 'Elixir.String').\n-define(string_chars, 'Elixir.String.Chars').\n-define(system, 'Elixir.System').\n-define(tuple, 'Elixir.Tuple').\n\n% Macros used to define inline and rewrite rules.\n% Defines the rules from Elixir function to Erlang function\n% and the reverse, rewrites that are not reversible or have\n% complex rules are defined without the macros.\n-define(\n  inline(ExMod, ExFun, Arity, ErlMod, ErlFun),\n  inner_inline(ex_to_erl, ExMod, ExFun, Arity) -> {ErlMod, ErlFun};\n  inner_inline(erl_to_ex, ErlMod, ErlFun, Arity) -> {ExMod, ExFun}\n).\n\n-define(\n  rewrite(ExMod, ExFun, ExArgs, ErlMod, ErlFun, ErlArgs),\n  inner_rewrite(ex_to_erl, _Meta, ExMod, ExFun, ExArgs) -> {ErlMod, ErlFun, ErlArgs};\n  inner_rewrite(erl_to_ex, _Meta, ErlMod, ErlFun, ErlArgs) -> {ExMod, ExFun, ExArgs, fun(ErlArgs) -> ExArgs end}\n).\n\nerl_to_ex(Mod, Fun, Args) when is_list(Args) ->\n  case inner_inline(erl_to_ex, Mod, Fun, length(Args)) of\n    false -> inner_rewrite(erl_to_ex, [], Mod, Fun, Args);\n    {ExMod, ExFun} -> {ExMod, ExFun, Args, fun identity/1}\n  end;\n\nerl_to_ex(Mod, Fun, Arity) when is_integer(Arity) ->\n  inner_inline(erl_to_ex, Mod, Fun, Arity).\n\n%% Inline rules\n%%\n%% Inline rules are straightforward, they keep the same\n%% number and order of arguments and show up on captures.\ninline(Mod, Fun, Arity) -> inner_inline(ex_to_erl, Mod, Fun, Arity).\n\n?inline(?atom, to_charlist, 1, erlang, atom_to_list);\n?inline(?atom, to_string, 1, erlang, atom_to_binary);\n\n?inline(?bitwise, 'bnot', 1, erlang, 'bnot');\n?inline(?bitwise, 'band', 2, erlang, 'band');\n?inline(?bitwise, 'bor', 2, erlang, 'bor');\n?inline(?bitwise, 'bxor', 2, erlang, 'bxor');\n?inline(?bitwise, 'bsl', 2, erlang, 'bsl');\n?inline(?bitwise, 'bsr', 2, erlang, 'bsr');\n\n?inline(?function, capture, 3, erlang, make_fun);\n?inline(?function, info, 1, erlang, fun_info);\n?inline(?function, info, 2, erlang, fun_info);\n\n?inline(?integer, to_charlist, 1, erlang, integer_to_list);\n?inline(?integer, to_charlist, 2, erlang, integer_to_list);\n?inline(?integer, to_string, 1, erlang, integer_to_binary);\n?inline(?integer, to_string, 2, erlang, integer_to_binary);\n\n?inline(?io, iodata_length, 1, erlang, iolist_size);\n?inline(?io, iodata_to_binary, 1, erlang, iolist_to_binary);\n\n?inline(?kernel, '!=', 2, erlang, '/=');\n?inline(?kernel, '!==', 2, erlang, '=/=');\n?inline(?kernel, '*', 2, erlang, '*');\n?inline(?kernel, '+', 1, erlang, '+');\n?inline(?kernel, '+', 2, erlang, '+');\n?inline(?kernel, '++', 2, erlang, '++');\n?inline(?kernel, '-', 1, erlang, '-');\n?inline(?kernel, '-', 2, erlang, '-');\n?inline(?kernel, '--', 2, erlang, '--');\n?inline(?kernel, '/', 2, erlang, '/');\n?inline(?kernel, '<', 2, erlang, '<');\n?inline(?kernel, '<=', 2, erlang, '=<');\n?inline(?kernel, '==', 2, erlang, '==');\n?inline(?kernel, '===', 2, erlang, '=:=');\n?inline(?kernel, '>', 2, erlang, '>');\n?inline(?kernel, '>=', 2, erlang, '>=');\n?inline(?kernel, abs, 1, erlang, abs);\n?inline(?kernel, apply, 2, erlang, apply);\n?inline(?kernel, apply, 3, erlang, apply);\n?inline(?kernel, binary_part, 3, erlang, binary_part);\n?inline(?kernel, bit_size, 1, erlang, bit_size);\n?inline(?kernel, byte_size, 1, erlang, byte_size);\n?inline(?kernel, ceil, 1, erlang, ceil);\n?inline(?kernel, 'div', 2, erlang, 'div');\n?inline(?kernel, exit, 1, erlang, exit);\n?inline(?kernel, floor, 1, erlang, floor);\n?inline(?kernel, 'function_exported?', 3, erlang, function_exported);\n?inline(?kernel, hd, 1, erlang, hd);\n?inline(?kernel, is_atom, 1, erlang, is_atom);\n?inline(?kernel, is_binary, 1, erlang, is_binary);\n?inline(?kernel, is_bitstring, 1, erlang, is_bitstring);\n?inline(?kernel, is_boolean, 1, erlang, is_boolean);\n?inline(?kernel, is_float, 1, erlang, is_float);\n?inline(?kernel, is_function, 1, erlang, is_function);\n?inline(?kernel, is_function, 2, erlang, is_function);\n?inline(?kernel, is_integer, 1, erlang, is_integer);\n?inline(?kernel, is_list, 1, erlang, is_list);\n?inline(?kernel, is_map, 1, erlang, is_map);\n?inline(?kernel, is_number, 1, erlang, is_number);\n?inline(?kernel, is_pid, 1, erlang, is_pid);\n?inline(?kernel, is_port, 1, erlang, is_port);\n?inline(?kernel, is_reference, 1, erlang, is_reference);\n?inline(?kernel, is_tuple, 1, erlang, is_tuple);\n?inline(?kernel, length, 1, erlang, length);\n?inline(?kernel, make_ref, 0, erlang, make_ref);\n?inline(?kernel, map_size, 1, erlang, map_size);\n?inline(?kernel, max, 2, erlang, max);\n?inline(?kernel, min, 2, erlang, min);\n?inline(?kernel, node, 0, erlang, node);\n?inline(?kernel, node, 1, erlang, node);\n?inline(?kernel, 'not', 1, erlang, 'not');\n?inline(?kernel, 'rem', 2, erlang, 'rem');\n?inline(?kernel, round, 1, erlang, round);\n?inline(?kernel, self, 0, erlang, self);\n?inline(?kernel, send, 2, erlang, send);\n?inline(?kernel, spawn, 1, erlang, spawn);\n?inline(?kernel, spawn, 3, erlang, spawn);\n?inline(?kernel, spawn_link, 1, erlang, spawn_link);\n?inline(?kernel, spawn_link, 3, erlang, spawn_link);\n?inline(?kernel, spawn_monitor, 1, erlang, spawn_monitor);\n?inline(?kernel, spawn_monitor, 3, erlang, spawn_monitor);\n?inline(?kernel, throw, 1, erlang, throw);\n?inline(?kernel, tl, 1, erlang, tl);\n?inline(?kernel, trunc, 1, erlang, trunc);\n?inline(?kernel, tuple_size, 1, erlang, tuple_size);\n\n?inline(?list, to_atom, 1, erlang, list_to_atom);\n?inline(?list, to_existing_atom, 1, erlang, list_to_existing_atom);\n?inline(?list, to_float, 1, erlang, list_to_float);\n?inline(?list, to_integer, 1, erlang, list_to_integer);\n?inline(?list, to_integer, 2, erlang, list_to_integer);\n?inline(?list, to_tuple, 1, erlang, list_to_tuple);\n\n?inline(?map, from_keys, 2, maps, from_keys);\n?inline(?map, intersect, 2, maps, intersect);\n?inline(?map, keys, 1, maps, keys);\n?inline(?map, merge, 2, maps, merge);\n?inline(?map, to_list, 1, maps, to_list);\n?inline(?map, values, 1, maps, values);\n\n?inline(?node, list, 0, erlang, nodes);\n?inline(?node, list, 1, erlang, nodes);\n?inline(?node, spawn, 2, erlang, spawn);\n?inline(?node, spawn, 3, erlang, spawn_opt);\n?inline(?node, spawn, 4, erlang, spawn);\n?inline(?node, spawn, 5, erlang, spawn_opt);\n?inline(?node, spawn_link, 2, erlang, spawn_link);\n?inline(?node, spawn_link, 4, erlang, spawn_link);\n?inline(?node, spawn_monitor, 2, erlang, spawn_monitor);\n?inline(?node, spawn_monitor, 4, erlang, spawn_monitor);\n\n?inline(?port, close, 1, erlang, port_close);\n?inline(?port, command, 2, erlang, port_command);\n?inline(?port, command, 3, erlang, port_command);\n?inline(?port, connect, 2, erlang, port_connect);\n?inline(?port, list, 0, erlang, ports);\n?inline(?port, open, 2, erlang, open_port);\n\n?inline(?process, alias, 0, erlang, alias);\n?inline(?process, alias, 1, erlang, alias);\n?inline(?process, 'alive?', 1, erlang, is_process_alive);\n?inline(?process, cancel_timer, 1, erlang, cancel_timer);\n?inline(?process, cancel_timer, 2, erlang, cancel_timer);\n?inline(?process, demonitor, 1, erlang, demonitor);\n?inline(?process, demonitor, 2, erlang, demonitor);\n?inline(?process, exit, 2, erlang, exit);\n?inline(?process, flag, 2, erlang, process_flag);\n?inline(?process, flag, 3, erlang, process_flag);\n?inline(?process, get, 0, erlang, get);\n?inline(?process, get_keys, 0, erlang, get_keys);\n?inline(?process, get_keys, 1, erlang, get_keys);\n?inline(?process, group_leader, 0, erlang, group_leader);\n?inline(?process, hibernate, 3, erlang, hibernate);\n?inline(?process, link, 1, erlang, link);\n?inline(?process, list, 0, erlang, processes);\n?inline(?process, read_timer, 1, erlang, read_timer);\n?inline(?process, registered, 0, erlang, registered);\n?inline(?process, send, 3, erlang, send);\n?inline(?process, spawn, 2, erlang, spawn_opt);\n?inline(?process, spawn, 4, erlang, spawn_opt);\n?inline(?process, unalias, 1, erlang, unalias);\n?inline(?process, unlink, 1, erlang, unlink);\n?inline(?process, unregister, 1, erlang, unregister);\n\n?inline(?string, duplicate, 2, binary, copy);\n?inline(?string, to_atom, 1, erlang, binary_to_atom);\n?inline(?string, to_existing_atom, 1, erlang, binary_to_existing_atom);\n?inline(?string, to_float, 1, erlang, binary_to_float);\n?inline(?string, to_integer, 1, erlang, binary_to_integer);\n?inline(?string, to_integer, 2, erlang, binary_to_integer);\n\n?inline(?system, monotonic_time, 0, erlang, monotonic_time);\n?inline(?system, os_time, 0, os, system_time);\n?inline(?system, system_time, 0, erlang, system_time);\n?inline(?system, time_offset, 0, erlang, time_offset);\n?inline(?system, unique_integer, 0, erlang, unique_integer);\n?inline(?system, unique_integer, 1, erlang, unique_integer);\n?inline(?tuple, to_list, 1, erlang, tuple_to_list);\n\n% Defined without macro to avoid conflict with Bitwise named operators\ninner_inline(ex_to_erl, ?bitwise, '~~~', 1) -> {erlang, 'bnot'};\ninner_inline(ex_to_erl, ?bitwise, '&&&', 2) -> {erlang, 'band'};\ninner_inline(ex_to_erl, ?bitwise, '|||', 2) -> {erlang, 'bor'};\ninner_inline(ex_to_erl, ?bitwise, '^^^', 2) -> {erlang, 'bxor'};\ninner_inline(ex_to_erl, ?bitwise, '<<<', 2) -> {erlang, 'bsl'};\ninner_inline(ex_to_erl, ?bitwise, '>>>', 2) -> {erlang, 'bsr'};\n\n% Defined without macro to avoid conflict with Process.demonitor\ninner_inline(ex_to_erl, ?port, demonitor, 1) -> {erlang, demonitor};\ninner_inline(ex_to_erl, ?port, demonitor, 2) -> {erlang, demonitor};\n\ninner_inline(_, _, _, _) -> false.\n\n%% Rewrite rules\n%%\n%% Rewrite rules are more complex than regular inlining code\n%% as they may change the number of arguments. However, they\n%% don't add new code (such as case expressions), at best they\n%% perform dead code removal.\nrewrite(?string_chars, DotMeta, to_string, Meta, [Arg]) ->\n  case is_always_string(Arg) of\n    true -> Arg;\n    false -> {{'.', DotMeta, [?string_chars, to_string]}, Meta, [Arg]}\n  end;\nrewrite(erlang, _, '+', _, [Arg]) when is_number(Arg) -> +Arg;\nrewrite(erlang, _, '-', _, [Arg]) when is_number(Arg) -> -Arg;\nrewrite(Receiver, DotMeta, Right, Meta, Args) ->\n  {EReceiver, ERight, EArgs} = inner_rewrite(ex_to_erl, DotMeta, Receiver, Right, Args),\n  {{'.', DotMeta, [EReceiver, ERight]}, Meta, EArgs}.\n\n?rewrite(?float, to_charlist, [Arg], erlang, float_to_list, [Arg, [short]]);\n?rewrite(?float, to_string, [Arg], erlang, float_to_binary, [Arg, [short]]);\n?rewrite(?kernel, is_map_key, [Map, Key], erlang, is_map_key, [Key, Map]);\n?rewrite(?map, delete, [Map, Key], maps, remove, [Key, Map]);\n?rewrite(?map, fetch, [Map, Key], maps, find, [Key, Map]);\n?rewrite(?map, 'fetch!', [Map, Key], maps, get, [Key, Map]);\n?rewrite(?map, 'has_key?', [Map, Key], maps, is_key, [Key, Map]);\n?rewrite(?map, put, [Map, Key, Value], maps, put, [Key, Value, Map]);\n?rewrite(?map, 'replace!', [Map, Key, Value], maps, update, [Key, Value, Map]);\n?rewrite(?port, monitor, [Arg], erlang, monitor, [port, Arg]);\n?rewrite(?process, group_leader, [Pid, Leader], erlang, group_leader, [Leader, Pid]);\n?rewrite(?process, monitor, [Arg], erlang, monitor, [process, Arg]);\n?rewrite(?process, monitor, [Arg, Opts], erlang, monitor, [process, Arg, Opts]);\n?rewrite(?process, send_after, [Dest, Msg, Time], erlang, send_after, [Time, Dest, Msg]);\n?rewrite(?process, send_after, [Dest, Msg, Time, Opts], erlang, send_after, [Time, Dest, Msg, Opts]);\n?rewrite(?tuple, duplicate, [Data, Size], erlang, make_tuple, [Size, Data]);\n\ninner_rewrite(ex_to_erl, Meta, ?tuple, delete_at, [Tuple, Index]) ->\n  {erlang, delete_element, [increment(Meta, Index), Tuple]};\ninner_rewrite(ex_to_erl, Meta, ?tuple, insert_at, [Tuple, Index, Term]) ->\n  {erlang, insert_element, [increment(Meta, Index), Tuple, Term]};\ninner_rewrite(ex_to_erl, Meta, ?kernel, elem, [Tuple, Index]) ->\n  {erlang, element, [increment(Meta, Index), Tuple]};\ninner_rewrite(ex_to_erl, Meta, ?kernel, put_elem, [Tuple, Index, Value]) ->\n  {erlang, setelement, [increment(Meta, Index), Tuple, Value]};\n\ninner_rewrite(erl_to_ex, _Meta, erlang, delete_element, [Index, Tuple]) when is_number(Index) ->\n  {?tuple, delete_at, [Tuple, Index - 1], fun([Index, Tuple]) -> [Tuple, Index] end};\ninner_rewrite(erl_to_ex, _Meta, erlang, insert_element, [Index, Tuple, Term]) when is_number(Index) ->\n  {?tuple, insert_at, [Tuple, Index - 1, Term], fun([Index, Tuple, Term]) -> [Tuple, Index, Term] end};\ninner_rewrite(erl_to_ex, _Meta, erlang, element, [Index, Tuple]) when is_number(Index) ->\n  {?kernel, elem, [Tuple, Index - 1], fun([Index, Tuple]) -> [Tuple, Index] end};\ninner_rewrite(erl_to_ex, _Meta, erlang, setelement, [Index, Tuple, Term]) when is_number(Index) ->\n  {?kernel, put_elem, [Tuple, Index - 1, Term], fun([Index, Tuple, Term]) -> [Tuple, Index, Term] end};\n\ninner_rewrite(erl_to_ex, _Meta, erlang, delete_element, [{{'.', _, [erlang, '+']}, _, [Index, 1]}, Tuple]) ->\n  {?tuple, delete_at, [Tuple, Index], fun([Index, Tuple]) -> [Tuple, Index] end};\ninner_rewrite(erl_to_ex, _Meta, erlang, insert_element, [{{'.', _, [erlang, '+']}, _, [Index, 1]}, Tuple, Term]) ->\n  {?tuple, insert_at, [Tuple, Index, Term], fun([Index, Tuple, Term]) -> [Tuple, Index, Term] end};\ninner_rewrite(erl_to_ex, _Meta, erlang, element, [{{'.', _, [erlang, '+']}, _, [Index, 1]}, Tuple]) ->\n  {?kernel, elem, [Tuple, Index], fun([Index, Tuple]) -> [Tuple, Index] end};\ninner_rewrite(erl_to_ex, _Meta, erlang, setelement, [{{'.', _, [erlang, '+']}, _, [Index, 1]}, Tuple, Term]) ->\n  {?kernel, put_elem, [Tuple, Index, Term], fun([Index, Tuple, Term]) -> [Tuple, Index, Term] end};\n\ninner_rewrite(erl_to_ex, _Meta, erlang, 'orelse', [_, _] = Args) ->\n  {?kernel, 'or', Args, fun identity/1};\ninner_rewrite(erl_to_ex, _Meta, erlang, 'andalso', [_, _] = Args) ->\n  {?kernel, 'and', Args, fun identity/1};\n\ninner_rewrite(ex_to_erl, _Meta, Mod, Fun, Args) -> {Mod, Fun, Args};\ninner_rewrite(erl_to_ex, _Meta, Mod, Fun, Args) -> {Mod, Fun, Args, fun identity/1}.\n\nidentity(Arg) -> Arg.\n\nincrement(_Meta, Number) when is_number(Number) ->\n  Number + 1;\nincrement(Meta, Other) ->\n  {{'.', Meta, [erlang, '+']}, Meta, [Other, 1]}.\n\n%% Match rewrite\n%%\n%% Match rewrite is similar to regular rewrite, except\n%% it also verifies the rewrite rule applies in a match context.\n%% The allowed operations are very limited.\n%% The Kernel operators are already inlined by now, we only need to\n%% care about Erlang ones.\nmatch(erlang, _, '++', Meta, [Left, Right], _S) ->\n  try {ok, static_append(Left, Right, Meta)}\n  catch impossible -> {error, {invalid_match_append, Left}}\n  end;\nmatch(Receiver, _, Right, _, Args, _S) ->\n  {error, {invalid_match, Receiver, Right, length(Args)}}.\n\nstatic_append([], Right, _Meta) -> Right;\nstatic_append([{'|', InnerMeta, [Head, Tail]}], Right, Meta) when is_list(Tail) ->\n  [{'|', InnerMeta, [Head, static_append(Tail, Right, Meta)]}];\nstatic_append([{'|', _, [_, _]}], _, _) -> throw(impossible);\nstatic_append([Last], Right, Meta) -> [{'|', Meta, [Last, Right]}];\nstatic_append([Head | Tail], Right, Meta) -> [Head | static_append(Tail, Right, Meta)];\nstatic_append(_, _, _) -> throw(impossible).\n\n%% Guard rewrite\n%%\n%% Guard rewrite is similar to regular rewrite, except\n%% it also verifies the resulting function is supported in\n%% guard context - only certain BIFs and operators are.\nguard(Receiver, DotMeta, Right, Meta, Args, S) ->\n  case inner_rewrite(ex_to_erl, DotMeta, Receiver, Right, Args) of\n    {erlang, RRight, RArgs} ->\n      case allowed_guard(RRight, length(RArgs)) of\n        true -> {ok, {{'.', DotMeta, [erlang, RRight]}, Meta, RArgs}};\n        false -> {error, {invalid_guard, Receiver, Right, length(Args), elixir_utils:guard_info(S)}}\n      end;\n    _ -> {error, {invalid_guard, Receiver, Right, length(Args), elixir_utils:guard_info(S)}}\n  end.\n\n%% erlang:is_record/2-3 are compiler guards in Erlang which we\n%% need to explicitly forbid as they are allowed in erl_internal.\nallowed_guard(is_record, 2) -> false;\nallowed_guard(is_record, 3) -> false;\nallowed_guard(Right, Arity) ->\n  erl_internal:guard_bif(Right, Arity) orelse elixir_utils:guard_op(Right, Arity).\n\nformat_error({invalid_guard, Receiver, Right, Arity, Context}) ->\n  io_lib:format(cannot_invoke_or_maybe_require(Receiver, Right, Arity) ++ \" ~ts.~ts/~B inside a ~ts\",\n                ['Elixir.Macro':to_string(Receiver), Right, Arity, Context]);\nformat_error({invalid_match, Receiver, Right, Arity}) ->\n  io_lib:format(cannot_invoke_or_maybe_require(Receiver, Right, Arity) ++ \" ~ts.~ts/~B inside a match\",\n                ['Elixir.Macro':to_string(Receiver), Right, Arity]);\nformat_error({invalid_match_append, Arg}) ->\n  io_lib:format(\"invalid argument for ++ operator inside a match, expected a literal proper list, got: ~ts\",\n                ['Elixir.Macro':to_string(Arg)]).\n\ncannot_invoke_or_maybe_require(Receiver, Fun, Arity) ->\n  try\n    true = lists:member({Fun, Arity}, Receiver:'__info__'(macros)),\n    [\"you must require the module \", 'Elixir.Macro':to_string(Receiver), \" before invoking macro\"]\n  catch\n    _:_ -> \"cannot invoke remote function\"\n  end.\n\nis_always_string({{'.', _, [Module, Function]}, _, Args}) ->\n  is_always_string(Module, Function, length(Args));\nis_always_string(Ast) ->\n  is_binary(Ast).\n\nis_always_string('Elixir.Enum', join, _) -> true;\nis_always_string('Elixir.Enum', map_join, _) -> true;\nis_always_string('Elixir.Kernel', inspect, _) -> true;\nis_always_string('Elixir.Macro', to_string, _) -> true;\nis_always_string('Elixir.String.Chars', to_string, _) -> true;\nis_always_string('Elixir.Path', join, _) -> true;\nis_always_string(_Module, _Function, _Args) -> false.\n"
  },
  {
    "path": "lib/elixir/src/elixir_sup.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_sup).\n-behaviour(supervisor).\n-export([init/1, start_link/0]).\n\nstart_link() ->\n  supervisor:start_link({local, ?MODULE}, ?MODULE, ok).\n\ninit(ok) ->\n  Workers = [\n    {\n      elixir_config,\n      {elixir_config, start_link, []},\n\n      permanent,                    % Restart  = permanent | transient | temporary\n      2000,                         % Shutdown = brutal_kill | int() >= 0 | infinity\n      worker,                       % Type     = worker | supervisor\n      [elixir_config]               % Modules  = [Module] | dynamic\n    },\n\n    {\n      elixir_code_server,\n      {elixir_code_server, start_link, []},\n\n      permanent,                    % Restart  = permanent | transient | temporary\n      2000,                         % Shutdown = brutal_kill | int() >= 0 | infinity\n      worker,                       % Type     = worker | supervisor\n      [elixir_code_server]          % Modules  = [Module] | dynamic\n    }\n  ],\n\n  {ok, {{one_for_one, 3, 10}, Workers}}.\n"
  },
  {
    "path": "lib/elixir/src/elixir_tokenizer.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(elixir_tokenizer).\n-include(\"elixir.hrl\").\n-include(\"elixir_tokenizer.hrl\").\n-export([tokenize/1, tokenize/3, tokenize/4, invalid_do_error/1,\n         format_error/1, terminator/1]).\n\n-define(at_op(T),\n  T =:= $@).\n\n-define(capture_op(T),\n  T =:= $&).\n\n-define(unary_op(T),\n  T =:= $!;\n  T =:= $^).\n\n-define(range_op(T1, T2),\n  T1 =:= $., T2 =:= $.).\n\n-define(concat_op(T1, T2),\n  T1 =:= $+, T2 =:= $+;\n  T1 =:= $-, T2 =:= $-;\n  T1 =:= $<, T2 =:= $>).\n\n-define(concat_op3(T1, T2, T3),\n  T1 =:= $+, T2 =:= $+, T3 =:= $+;\n  T1 =:= $-, T2 =:= $-, T3 =:= $-).\n\n-define(power_op(T1, T2),\n  T1 =:= $*, T2 =:= $*).\n\n-define(mult_op(T),\n  T =:= $* orelse T =:= $/).\n\n-define(dual_op(T),\n  T =:= $+ orelse T =:= $-).\n\n-define(arrow_op3(T1, T2, T3),\n  T1 =:= $<, T2 =:= $<, T3 =:= $<;\n  T1 =:= $>, T2 =:= $>, T3 =:= $>;\n  T1 =:= $~, T2 =:= $>, T3 =:= $>;\n  T1 =:= $<, T2 =:= $<, T3 =:= $~;\n  T1 =:= $<, T2 =:= $~, T3 =:= $>;\n  T1 =:= $<, T2 =:= $|, T3 =:= $>).\n\n-define(arrow_op(T1, T2),\n  T1 =:= $|, T2 =:= $>;\n  T1 =:= $~, T2 =:= $>;\n  T1 =:= $<, T2 =:= $~).\n\n-define(rel_op(T),\n  T =:= $<;\n  T =:= $>).\n\n-define(rel_op2(T1, T2),\n  T1 =:= $<, T2 =:= $=;\n  T1 =:= $>, T2 =:= $=).\n\n-define(comp_op2(T1, T2),\n  T1 =:= $=, T2 =:= $=;\n  T1 =:= $=, T2 =:= $~;\n  T1 =:= $!, T2 =:= $=).\n\n-define(comp_op3(T1, T2, T3),\n  T1 =:= $=, T2 =:= $=, T3 =:= $=;\n  T1 =:= $!, T2 =:= $=, T3 =:= $=).\n\n-define(ternary_op(T1, T2),\n  T1 =:= $/, T2 =:= $/).\n\n-define(and_op(T1, T2),\n  T1 =:= $&, T2 =:= $&).\n\n-define(or_op(T1, T2),\n  T1 =:= $|, T2 =:= $|).\n\n-define(and_op3(T1, T2, T3),\n  T1 =:= $&, T2 =:= $&, T3 =:= $&).\n\n-define(or_op3(T1, T2, T3),\n  T1 =:= $|, T2 =:= $|, T3 =:= $|).\n\n-define(match_op(T),\n  T =:= $=).\n\n-define(in_match_op(T1, T2),\n  T1 =:= $<, T2 =:= $-;\n  T1 =:= $\\\\, T2 =:= $\\\\).\n\n-define(stab_op(T1, T2),\n  T1 =:= $-, T2 =:= $>).\n\n-define(type_op(T1, T2),\n  T1 =:= $:, T2 =:= $:).\n\n-define(pipe_op(T),\n  T =:= $|).\n\n-define(ellipsis_op3(T1, T2, T3),\n  T1 =:= $., T2 =:= $., T3 =:= $.).\n\n%% Deprecated operators\n\n-define(unary_op3(T1, T2, T3),\n  T1 =:= $~, T2 =:= $~, T3 =:= $~).\n\n-define(xor_op3(T1, T2, T3),\n  T1 =:= $^, T2 =:= $^, T3 =:= $^).\n\ntokenize(String, Line, Column, #elixir_tokenizer{} = Scope) ->\n  tokenize(String, Line, Column, Scope, []);\n\ntokenize(String, Line, Column, Opts) ->\n  IdentifierTokenizer = elixir_config:identifier_tokenizer(),\n\n  Scope =\n    lists:foldl(fun\n      ({check_terminators, false}, Acc) ->\n        Acc#elixir_tokenizer{cursor_completion=false, terminators=none};\n      ({check_terminators, {cursor, Sigils, Terminators}}, Acc) ->\n        Acc#elixir_tokenizer{cursor_completion={prune_and_cursor, Sigils}, terminators=Terminators};\n      ({existing_atoms_only, ExistingAtomsOnly}, Acc) when is_boolean(ExistingAtomsOnly) ->\n        Acc#elixir_tokenizer{existing_atoms_only=ExistingAtomsOnly};\n      ({static_atoms_encoder, StaticAtomsEncoder}, Acc) when is_function(StaticAtomsEncoder) ->\n        Acc#elixir_tokenizer{static_atoms_encoder=StaticAtomsEncoder};\n      ({preserve_comments, PreserveComments}, Acc) when is_function(PreserveComments) ->\n        Acc#elixir_tokenizer{preserve_comments=PreserveComments};\n      ({unescape, Unescape}, Acc) when is_boolean(Unescape) ->\n        Acc#elixir_tokenizer{unescape=Unescape};\n      ({indentation, Indentation}, Acc) when Indentation >= 0 ->\n        Acc#elixir_tokenizer{column=Indentation+1};\n      (_, Acc) ->\n        Acc\n    end, #elixir_tokenizer{identifier_tokenizer=IdentifierTokenizer}, Opts),\n\n  tokenize(String, Line, Column, Scope, []).\n\ntokenize(String, Line, Opts) ->\n  tokenize(String, Line, 1, Opts).\n\ntokenize([], Line, Column, #elixir_tokenizer{cursor_completion=Cursor} = Scope, Tokens) when Cursor /= false ->\n  #elixir_tokenizer{ascii_identifiers_only=Ascii, terminators=Terminators, warnings=Warnings} = Scope,\n  {CursorColumn, AccTokens} = add_cursor(Line, Column, Cursor, Tokens),\n  AllWarnings = maybe_unicode_lint_warnings(Ascii, Tokens, Warnings),\n  {ok, Line, CursorColumn, AllWarnings, AccTokens, Terminators};\n\ntokenize([], EndLine, EndColumn, #elixir_tokenizer{terminators=[{Start, {StartLine, StartColumn, _}, _} | _]} = Scope, Tokens) ->\n  End = terminator(Start),\n  Hint = missing_terminator_hint(Start, End, Scope),\n  Message = \"missing terminator: ~ts\",\n  Formatted = io_lib:format(Message, [End]),\n  Meta = [\n    {opening_delimiter, Start},\n    {expected_delimiter, End},\n    {line, StartLine},\n    {column, StartColumn},\n    {end_line, EndLine},\n    {end_column, EndColumn}\n  ],\n  error({Meta, [Formatted, Hint], []}, [], Scope, Tokens);\n\ntokenize([], Line, Column, #elixir_tokenizer{} = Scope, Tokens) ->\n  #elixir_tokenizer{ascii_identifiers_only=Ascii, warnings=Warnings} = Scope,\n  AllWarnings = maybe_unicode_lint_warnings(Ascii, Tokens, Warnings),\n  {ok, Line, Column, AllWarnings, Tokens, []};\n\n% VC merge conflict\n\ntokenize((\"<<<<<<<\" ++ _) = Original, Line, 1, Scope, Tokens) ->\n  FirstLine = lists:takewhile(fun(C) -> C =/= $\\n andalso C =/= $\\r end, Original),\n  Reason = {?LOC(Line, 1), \"found an unexpected version control marker, please resolve the conflicts: \", FirstLine},\n  error(Reason, Original, Scope, Tokens);\n\n% Base integers\n\ntokenize([$0, $x, H | T], Line, Column, Scope, Tokens) when ?is_hex(H) ->\n  {Rest, Number, OriginalRepresentation, Length} = tokenize_hex(T, [H], 1),\n  Token = {int, {Line, Column, Number}, OriginalRepresentation},\n  tokenize(Rest, Line, Column + 2 + Length, Scope, [Token | Tokens]);\n\ntokenize([$0, $b, H | T], Line, Column, Scope, Tokens) when ?is_bin(H) ->\n  {Rest, Number, OriginalRepresentation, Length} = tokenize_bin(T, [H], 1),\n  Token = {int, {Line, Column, Number}, OriginalRepresentation},\n  tokenize(Rest, Line, Column + 2 + Length, Scope, [Token | Tokens]);\n\ntokenize([$0, $o, H | T], Line, Column, Scope, Tokens) when ?is_octal(H) ->\n  {Rest, Number, OriginalRepresentation, Length} = tokenize_octal(T, [H], 1),\n  Token = {int, {Line, Column, Number}, OriginalRepresentation},\n  tokenize(Rest, Line, Column + 2 + Length, Scope, [Token | Tokens]);\n\n% Comments\n\ntokenize([$# | String], Line, Column, Scope, Tokens) ->\n  case tokenize_comment(String, [$#]) of\n    {error, Char, Reason} ->\n      error_comment(Char, Reason, [$# | String], Line, Column, Scope, Tokens);\n    {Rest, Comment} ->\n      preserve_comments(Line, Column, Tokens, Comment, Rest, Scope),\n      tokenize(Rest, Line, Column, Scope, reset_eol(Tokens))\n  end;\n\n% Sigils\n\ntokenize([$~, H | _T] = Original, Line, Column, Scope, Tokens) when ?is_upcase(H) orelse ?is_downcase(H) ->\n  tokenize_sigil(Original, Line, Column, Scope, Tokens);\n\n% Char tokens\n\n% We tokenize char literals (?a) as {char, _, CharInt} instead of {number, _,\n% CharInt}. This is exactly what Erlang does with Erlang char literals\n% ($a). This means we'll have to adjust the error message for char literals in\n% elixir_errors.erl as by default {char, _, _} tokens are \"hijacked\" by Erlang\n% and printed with Erlang syntax ($a) in the parser's error messages.\n\ntokenize([$?, $\\\\, H | T], Line, Column, Scope, Tokens) ->\n  Char = elixir_interpolation:unescape_map(H),\n\n  NewScope = if\n    H =:= Char, H =/= $\\\\ ->\n      case handle_char(Char) of\n        {Escape, Name} ->\n          Msg = io_lib:format(\"found ?\\\\ followed by code point 0x~.16B (~ts), please use ?~ts instead\",\n                              [Char, Name, Escape]),\n          prepend_warning(Line, Column, Msg, Scope);\n\n        false when ?is_downcase(H); ?is_upcase(H) ->\n          Msg = io_lib:format(\"unknown escape sequence ?\\\\~tc, use ?~tc instead\", [H, H]),\n          prepend_warning(Line, Column, Msg, Scope);\n\n        false ->\n          Scope\n      end;\n    true ->\n      Scope\n  end,\n\n  Token = {char, {Line, Column, [$?, $\\\\, H]}, Char},\n  case H of\n    $\\n ->\n      %% If original char is a literal line feed, we already emit a warning,\n      %% but we need to bump the line without emitting an EOL token.\n      tokenize_eol(T, Line, NewScope, [Token | Tokens]);\n    _ ->\n      tokenize(T, Line, Column + 3, NewScope, [Token | Tokens])\n  end;\n\ntokenize([$?, Char | T], Line, Column, Scope, Tokens) ->\n  NewScope = case handle_char(Char) of\n    {Escape, Name} ->\n      Msg = io_lib:format(\"found ? followed by code point 0x~.16B (~ts), please use ?~ts instead\",\n                          [Char, Name, Escape]),\n      prepend_warning(Line, Column, Msg, Scope);\n    false ->\n      Scope\n  end,\n  Token = {char, {Line, Column, [$?, Char]}, Char},\n  case Char of\n    $\\n ->\n      %% If original char is a literal line feed, we already emit a warning,\n      %% but we need to bump the line without emitting an EOL token.\n      tokenize_eol(T, Line, NewScope, [Token | Tokens]);\n    _ ->\n      tokenize(T, Line, Column + 2, NewScope, [Token | Tokens])\n  end;\n\n% Heredocs\n\ntokenize(\"\\\"\\\"\\\"\" ++ T, Line, Column, Scope, Tokens) ->\n  handle_heredocs(T, Line, Column, $\", Scope, Tokens);\n\n%% TODO: Remove me in Elixir v2.0\ntokenize(\"'''\" ++ T, Line, Column, Scope, Tokens) ->\n  NewScope = prepend_warning(Line, Column, \"single-quoted string represent charlists. Use ~c''' if you indeed want a charlist or use \\\"\\\"\\\" instead\", Scope),\n  handle_heredocs(T, Line, Column, $', NewScope, Tokens);\n\n% Strings\n\ntokenize([$\" | T], Line, Column, Scope, Tokens) ->\n  handle_strings(T, Line, Column + 1, $\", Scope, Tokens);\n\n%% TODO: Remove me in Elixir v2.0\ntokenize([$' | T], Line, Column, Scope, Tokens) ->\n  handle_strings(T, Line, Column + 1, $', Scope, Tokens);\n\n% Operator atoms\n\ntokenize(\".:\" ++ Rest, Line, Column, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  tokenize(Rest, Line, Column + 2, Scope, [{kw_identifier, {Line, Column, nil}, '.'} | Tokens]);\n\ntokenize(\"<<>>:\" ++ Rest, Line, Column, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  tokenize(Rest, Line, Column + 5, Scope, [{kw_identifier, {Line, Column, nil}, '<<>>'} | Tokens]);\ntokenize(\"%{}:\" ++ Rest, Line, Column, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  tokenize(Rest, Line, Column + 4, Scope, [{kw_identifier, {Line, Column, nil}, '%{}'} | Tokens]);\ntokenize(\"%:\" ++ Rest, Line, Column, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  tokenize(Rest, Line, Column + 2, Scope, [{kw_identifier, {Line, Column, nil}, '%'} | Tokens]);\ntokenize(\"&:\" ++ Rest, Line, Column, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  tokenize(Rest, Line, Column + 2, Scope, [{kw_identifier, {Line, Column, nil}, '&'} | Tokens]);\ntokenize(\"{}:\" ++ Rest, Line, Column, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  tokenize(Rest, Line, Column + 3, Scope, [{kw_identifier, {Line, Column, nil}, '{}'} | Tokens]);\ntokenize(\"..//:\" ++ Rest, Line, Column, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  tokenize(Rest, Line, Column + 5, Scope, [{kw_identifier, {Line, Column, nil}, '..//'} | Tokens]);\n\ntokenize(\":<<>>\" ++ Rest, Line, Column, Scope, Tokens) ->\n  tokenize(Rest, Line, Column + 5, Scope, [{atom, {Line, Column, nil}, '<<>>'} | Tokens]);\ntokenize(\":%{}\" ++ Rest, Line, Column, Scope, Tokens) ->\n  tokenize(Rest, Line, Column + 4, Scope, [{atom, {Line, Column, nil}, '%{}'} | Tokens]);\ntokenize(\":%\" ++ Rest, Line, Column, Scope, Tokens) ->\n  tokenize(Rest, Line, Column + 2, Scope, [{atom, {Line, Column, nil}, '%'} | Tokens]);\ntokenize(\":{}\" ++ Rest, Line, Column, Scope, Tokens) ->\n  tokenize(Rest, Line, Column + 3, Scope, [{atom, {Line, Column, nil}, '{}'} | Tokens]);\ntokenize(\":..//\" ++ Rest, Line, Column, Scope, Tokens) ->\n  tokenize(Rest, Line, Column + 5, Scope, [{atom, {Line, Column, nil}, '..//'} | Tokens]);\n\n% ## Three Token Operators\ntokenize([$:, T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when\n    ?unary_op3(T1, T2, T3); ?comp_op3(T1, T2, T3); ?and_op3(T1, T2, T3); ?or_op3(T1, T2, T3);\n    ?arrow_op3(T1, T2, T3); ?xor_op3(T1, T2, T3); ?concat_op3(T1, T2, T3); ?ellipsis_op3(T1, T2, T3) ->\n  Token = {atom, {Line, Column, nil}, list_to_atom([T1, T2, T3])},\n  tokenize(Rest, Line, Column + 4, Scope, [Token | Tokens]);\n\n% ## Two Token Operators\n\ntokenize([$:, $:, $: | Rest], Line, Column, Scope, Tokens) ->\n  Message = \"atom ::: must be written between quotes, as in :\\\"::\\\", to avoid ambiguity\",\n  NewScope = prepend_warning(Line, Column, Message, Scope),\n  Token = {atom, {Line, Column, nil}, '::'},\n  tokenize(Rest, Line, Column + 3, NewScope, [Token | Tokens]);\n\ntokenize([$:, T1, T2 | Rest], Line, Column, Scope, Tokens) when\n    ?comp_op2(T1, T2); ?rel_op2(T1, T2); ?and_op(T1, T2); ?or_op(T1, T2);\n    ?arrow_op(T1, T2); ?in_match_op(T1, T2); ?concat_op(T1, T2); ?power_op(T1, T2);\n    ?stab_op(T1, T2); ?range_op(T1, T2) ->\n  Token = {atom, {Line, Column, nil}, list_to_atom([T1, T2])},\n  tokenize(Rest, Line, Column + 3, Scope, [Token | Tokens]);\n\n% ## Single Token Operators\ntokenize([$:, T | Rest], Line, Column, Scope, Tokens) when\n    ?at_op(T); ?unary_op(T); ?capture_op(T); ?dual_op(T); ?mult_op(T);\n    ?rel_op(T); ?match_op(T); ?pipe_op(T); T =:= $. ->\n  Token = {atom, {Line, Column, nil}, list_to_atom([T])},\n  tokenize(Rest, Line, Column + 2, Scope, [Token | Tokens]);\n\n% ## Stand-alone tokens\n\ntokenize(\"=>\" ++ Rest, Line, Column, Scope, Tokens) ->\n  Token = {assoc_op, {Line, Column, previous_was_eol(Tokens)}, '=>'},\n  tokenize(Rest, Line, Column + 2, Scope, add_token_with_eol(Token, Tokens));\n\ntokenize(\"..//\" ++ Rest = String, Line, Column, Scope, Tokens) ->\n  case strip_horizontal_space(Rest, Line, Column + 4, Scope) of\n    {[$/ | _] = Remaining, NewLine, NewColumn} ->\n      Token = {identifier, {Line, Column, nil}, '..//'},\n      tokenize(Remaining, NewLine, NewColumn, Scope, [Token | Tokens]);\n    {_, _, _} ->\n      unexpected_token(String, Line, Column, Scope, Tokens)\n  end;\n\n% ## Ternary operator\n\n% ## Three token operators\ntokenize([T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when ?unary_op3(T1, T2, T3) ->\n  handle_unary_op(Rest, Line, Column, unary_op, 3, list_to_atom([T1, T2, T3]), Scope, Tokens);\n\ntokenize([T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when ?ellipsis_op3(T1, T2, T3) ->\n  handle_unary_op(Rest, Line, Column, ellipsis_op, 3, list_to_atom([T1, T2, T3]), Scope, Tokens);\n\ntokenize([T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when ?comp_op3(T1, T2, T3) ->\n  handle_op(Rest, Line, Column, comp_op, 3, list_to_atom([T1, T2, T3]), Scope, Tokens);\n\ntokenize([T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when ?and_op3(T1, T2, T3) ->\n  NewScope = maybe_warn_too_many_of_same_char([T1, T2, T3], Rest, Line, Column, Scope),\n  handle_op(Rest, Line, Column, and_op, 3, list_to_atom([T1, T2, T3]), NewScope, Tokens);\n\ntokenize([T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when ?or_op3(T1, T2, T3) ->\n  NewScope = maybe_warn_too_many_of_same_char([T1, T2, T3], Rest, Line, Column, Scope),\n  handle_op(Rest, Line, Column, or_op, 3, list_to_atom([T1, T2, T3]), NewScope, Tokens);\n\ntokenize([T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when ?xor_op3(T1, T2, T3) ->\n  NewScope = maybe_warn_too_many_of_same_char([T1, T2, T3], Rest, Line, Column, Scope),\n  handle_op(Rest, Line, Column, xor_op, 3, list_to_atom([T1, T2, T3]), NewScope, Tokens);\n\ntokenize([T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when ?concat_op3(T1, T2, T3) ->\n  NewScope = maybe_warn_too_many_of_same_char([T1, T2, T3], Rest, Line, Column, Scope),\n  handle_op(Rest, Line, Column, concat_op, 3, list_to_atom([T1, T2, T3]), NewScope, Tokens);\n\ntokenize([T1, T2, T3 | Rest], Line, Column, Scope, Tokens) when ?arrow_op3(T1, T2, T3) ->\n  handle_op(Rest, Line, Column, arrow_op, 3, list_to_atom([T1, T2, T3]), Scope, Tokens);\n\n% ## Containers + punctuation tokens\ntokenize([$, | Rest], Line, Column, Scope, Tokens) ->\n  Token = {',', {Line, Column, 0}},\n  tokenize(Rest, Line, Column + 1, Scope, [Token | Tokens]);\n\ntokenize([$<, $< | Rest], Line, Column, Scope, Tokens) ->\n  Token = {'<<', {Line, Column, nil}},\n  handle_terminator(Rest, Line, Column + 2, Scope, Token, Tokens);\n\ntokenize([$>, $> | Rest], Line, Column, Scope, Tokens) ->\n  Token = {'>>', {Line, Column, previous_was_eol(Tokens)}},\n  handle_terminator(Rest, Line, Column + 2, Scope, Token, Tokens);\n\ntokenize([${ | Rest], Line, Column, Scope, [{'%', _} | _] = Tokens) ->\n  Message =\n    \"unexpected space between % and {\\n\\n\"\n    \"If you want to define a map, write %{...}, with no spaces.\\n\"\n    \"If you want to define a struct, write %StructName{...}.\\n\\n\"\n    \"Syntax error before: \",\n  error({?LOC(Line, Column), Message, [${]}, Rest, Scope, Tokens);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when T =:= $(; T =:= ${; T =:= $[ ->\n  Token = {list_to_atom([T]), {Line, Column, nil}},\n  handle_terminator(Rest, Line, Column + 1, Scope, Token, Tokens);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when T =:= $); T =:= $}; T =:= $] ->\n  Token = {list_to_atom([T]), {Line, Column, previous_was_eol(Tokens)}},\n  handle_terminator(Rest, Line, Column + 1, Scope, Token, Tokens);\n\n% ## Two Token Operators\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?ternary_op(T1, T2) ->\n  Op = list_to_atom([T1, T2]),\n  Token = {ternary_op, {Line, Column, previous_was_eol(Tokens)}, Op},\n  tokenize(Rest, Line, Column + 2, Scope, add_token_with_eol(Token, Tokens));\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?power_op(T1, T2) ->\n  handle_op(Rest, Line, Column, power_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?range_op(T1, T2) ->\n  handle_op(Rest, Line, Column, range_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?concat_op(T1, T2) ->\n  handle_op(Rest, Line, Column, concat_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?arrow_op(T1, T2) ->\n  handle_op(Rest, Line, Column, arrow_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?comp_op2(T1, T2) ->\n  handle_op(Rest, Line, Column, comp_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?rel_op2(T1, T2) ->\n  handle_op(Rest, Line, Column, rel_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?and_op(T1, T2) ->\n  handle_op(Rest, Line, Column, and_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?or_op(T1, T2) ->\n  handle_op(Rest, Line, Column, or_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?in_match_op(T1, T2) ->\n  handle_op(Rest, Line, Column, in_match_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?type_op(T1, T2) ->\n  handle_op(Rest, Line, Column, type_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\ntokenize([T1, T2 | Rest], Line, Column, Scope, Tokens) when ?stab_op(T1, T2) ->\n  handle_op(Rest, Line, Column, stab_op, 2, list_to_atom([T1, T2]), Scope, Tokens);\n\n% ## Single Token Operators\n\ntokenize([$& | Rest], Line, Column, Scope, Tokens) ->\n  Kind =\n    case strip_horizontal_space(Rest, Line, 0, Scope) of\n      {[Int | _], Line, 0} when ?is_digit(Int) ->\n        capture_int;\n\n      {[$/ | NewRest], _, _} ->\n        case strip_horizontal_space(NewRest, Line, 0, Scope) of\n          {[$/ | _], _, _} -> capture_op;\n          {_, _, _} -> identifier\n        end;\n\n      {_, _, _} ->\n        capture_op\n    end,\n\n  Token = {Kind, {Line, Column, nil}, '&'},\n  tokenize(Rest, Line, Column + 1, Scope, [Token | Tokens]);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when ?at_op(T) ->\n  handle_unary_op(Rest, Line, Column, at_op, 1, list_to_atom([T]), Scope, Tokens);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when ?unary_op(T) ->\n  handle_unary_op(Rest, Line, Column, unary_op, 1, list_to_atom([T]), Scope, Tokens);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when ?rel_op(T) ->\n  handle_op(Rest, Line, Column, rel_op, 1, list_to_atom([T]), Scope, Tokens);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when ?dual_op(T) ->\n  handle_unary_op(Rest, Line, Column, dual_op, 1, list_to_atom([T]), Scope, Tokens);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when ?mult_op(T) ->\n  handle_op(Rest, Line, Column, mult_op, 1, list_to_atom([T]), Scope, Tokens);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when ?match_op(T) ->\n  handle_op(Rest, Line, Column, match_op, 1, list_to_atom([T]), Scope, Tokens);\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when ?pipe_op(T) ->\n  handle_op(Rest, Line, Column, pipe_op, 1, list_to_atom([T]), Scope, Tokens);\n\n% Non-operator Atoms\n\ntokenize([$:, H | T] = Original, Line, Column, BaseScope, Tokens) when ?is_quote(H) ->\n  Scope = case H == $' of\n    true ->\n      prepend_warning(Line, Column, \"single quotes around atoms are deprecated. Use double quotes instead\", BaseScope);\n\n    false ->\n      BaseScope\n  end,\n\n  case elixir_interpolation:extract(Line, Column + 2, Scope, true, T, H) of\n    {NewLine, NewColumn, Parts, Rest, _Done, InterScope} ->\n      NewScope = case is_unnecessary_quote(Parts, InterScope) of\n        true ->\n          WarnMsg = io_lib:format(\n            \"found quoted atom \\\"~ts\\\" but the quotes are not required. \"\n            \"Atoms made exclusively of ASCII letters, numbers, underscores, \"\n            \"beginning with a letter or underscore, and optionally ending with ! or ? \"\n            \"do not require quotes\",\n            [hd(Parts)]\n          ),\n          prepend_warning(Line, Column, WarnMsg, InterScope);\n\n        false ->\n          InterScope\n      end,\n\n      case unescape_tokens(Parts, Line, Column, NewScope) of\n        {ok, [Part]} when is_binary(Part) ->\n          case unsafe_to_atom(Part, Line, Column, Scope) of\n            {ok, Atom} ->\n              Token = {atom_quoted, {Line, Column, H}, Atom},\n              tokenize(Rest, NewLine, NewColumn, NewScope, [Token | Tokens]);\n\n            {error, Reason} ->\n              error(Reason, Rest, NewScope, Tokens)\n          end;\n\n        {ok, Unescaped} ->\n          Key = case Scope#elixir_tokenizer.existing_atoms_only of\n            true  -> atom_safe;\n            false -> atom_unsafe\n          end,\n          Token = {Key, {Line, Column, H}, Unescaped},\n          tokenize(Rest, NewLine, NewColumn, NewScope, [Token | Tokens]);\n\n        {error, Reason} ->\n          error(Reason, Rest, NewScope, Tokens)\n      end;\n\n    {error, Reason} ->\n      Message = \" (for atom starting at line ~B)\",\n      interpolation_error(Reason, Original, Scope, Tokens, Message, [Line], Line, Column + 1, [H], [H])\n  end;\n\ntokenize([$: | String] = Original, Line, Column, Scope, Tokens) ->\n  case tokenize_identifier(String, Line, Column, Scope, false) of\n    {_Kind, Unencoded, Atom, Rest, Length, Ascii, _Special} ->\n      NewScope = maybe_warn_for_ambiguous_bang_before_equals(atom, Unencoded, Rest, Line, Column, Scope),\n      TrackedScope = track_ascii(Ascii, NewScope),\n      Token = {atom, {Line, Column, Unencoded}, Atom},\n      tokenize(Rest, Line, Column + 1 + Length, TrackedScope, [Token | Tokens]);\n    empty when Scope#elixir_tokenizer.cursor_completion == false ->\n      unexpected_token(Original, Line, Column, Scope, Tokens);\n    empty ->\n      tokenize([], Line, Column, Scope, Tokens);\n    {unexpected_token, Length} ->\n      unexpected_token(lists:nthtail(Length - 1, String), Line, Column + Length - 1, Scope, Tokens);\n    {error, Reason} ->\n      error(Reason, Original, Scope, Tokens)\n  end;\n\n% Integers and floats\n% We use int and flt otherwise elixir_parser won't format them\n% properly in case of errors.\n\ntokenize([H | T], Line, Column, Scope, Tokens) when ?is_digit(H) ->\n  case tokenize_number(T, [H], 1, false) of\n    {error, Reason, Original} ->\n      error({?LOC(Line, Column), Reason, Original}, T, Scope, Tokens);\n    {[I | Rest], Number, Original, _Length} when ?is_upcase(I); ?is_downcase(I); I == $_ ->\n      if\n        Number == 0, (I =:= $x) orelse (I =:= $o) orelse (I =:= $b), Rest == [],\n        Scope#elixir_tokenizer.cursor_completion /= false ->\n          tokenize([], Line, Column, Scope, Tokens);\n\n        true ->\n          Msg =\n            io_lib:format(\n              \"invalid character \\\"~ts\\\" after number ~ts. If you intended to write a number, \"\n              \"make sure to separate the number from the character (using comma, space, etc). \"\n              \"If you meant to write a function name or a variable, note that identifiers in \"\n              \"Elixir cannot start with numbers. Unexpected token: \",\n              [[I], Original]\n            ),\n\n          error({?LOC(Line, Column), Msg, [I]}, T, Scope, Tokens)\n      end;\n    {Rest, Number, Original, Length} when is_integer(Number) ->\n      Token = {int, {Line, Column, Number}, Original},\n      tokenize(Rest, Line, Column + Length, Scope, [Token | Tokens]);\n    {Rest, Number, Original, Length} ->\n      Token = {flt, {Line, Column, Number}, Original},\n      tokenize(Rest, Line, Column + Length, Scope, [Token | Tokens])\n  end;\n\n% Spaces\n\ntokenize([T | Rest], Line, Column, Scope, Tokens) when ?is_horizontal_space(T) ->\n  {Remaining, NewLine, NewColumn} = strip_horizontal_space(Rest, Line, Column + 1, Scope),\n  handle_space_sensitive_tokens(Remaining, NewLine, NewColumn, Scope, Tokens);\n\n% End of line\n\ntokenize(\";\" ++ Rest, Line, Column, Scope, []) ->\n  tokenize(Rest, Line, Column + 1, Scope, [{';', {Line, Column, 0}}]);\n\ntokenize(\";\" ++ Rest, Line, Column, Scope, [Top | _] = Tokens) when element(1, Top) /= ';' ->\n  tokenize(Rest, Line, Column + 1, Scope, [{';', {Line, Column, 0}} | Tokens]);\n\ntokenize(\"\\\\\" = Original, Line, Column, Scope, Tokens) ->\n  error({?LOC(Line, Column), \"invalid escape \\\\ at end of file\", []}, Original, Scope, Tokens);\n\ntokenize(\"\\\\\\n\" = Original, Line, Column, Scope, Tokens) ->\n  error({?LOC(Line, Column), \"invalid escape \\\\ at end of file\", []}, Original, Scope, Tokens);\n\ntokenize(\"\\\\\\r\\n\" = Original, Line, Column, Scope, Tokens) ->\n  error({?LOC(Line, Column), \"invalid escape \\\\ at end of file\", []}, Original, Scope, Tokens);\n\ntokenize(\"\\\\\\n\" ++ Rest, Line, _Column, Scope, Tokens) ->\n  tokenize_eol(Rest, Line, Scope, Tokens);\n\ntokenize(\"\\\\\\r\\n\" ++ Rest, Line, _Column, Scope, Tokens) ->\n  tokenize_eol(Rest, Line, Scope, Tokens);\n\ntokenize(\"\\n\" ++ Rest, Line, Column, Scope, Tokens) ->\n  tokenize_eol(Rest, Line, Scope, eol(Line, Column, Tokens));\n\ntokenize(\"\\r\\n\" ++ Rest, Line, Column, Scope, Tokens) ->\n  tokenize_eol(Rest, Line, Scope, eol(Line, Column, Tokens));\n\n% Others\n\ntokenize([$%, $( | Rest], Line, Column, Scope, Tokens) ->\n  Reason = {?LOC(Line, Column), \"expected %{ to define a map, got: \", [$%, $(]},\n  error(Reason, Rest, Scope, Tokens);\n\ntokenize([$%, $[ | Rest], Line, Column, Scope, Tokens) ->\n  Reason = {?LOC(Line, Column), \"expected %{ to define a map, got: \", [$%, $[]},\n  error(Reason, Rest, Scope, Tokens);\n\ntokenize([$%, ${ | T], Line, Column, Scope, Tokens) ->\n  Token = {'{', {Line, Column, nil}},\n  handle_terminator(T, Line, Column + 2, Scope, Token, [{'%{}', {Line, Column, nil}} | Tokens]);\n\ntokenize([$% | T], Line, Column, Scope, Tokens) ->\n  tokenize(T, Line, Column + 1, Scope, [{'%', {Line, Column, nil}} | Tokens]);\n\ntokenize([$. | T], Line, Column, Scope, Tokens) ->\n  tokenize_dot(T, Line, Column + 1, {Line, Column, nil}, Scope, Tokens);\n\n% Identifiers\n\ntokenize(String, Line, Column, OriginalScope, Tokens) ->\n  case tokenize_identifier(String, Line, Column, OriginalScope, not previous_was_dot(Tokens)) of\n    {Kind, Unencoded, Atom, Rest, Length, Ascii, Special} ->\n      HasAt = lists:member(at, Special),\n      Scope = track_ascii(Ascii, OriginalScope),\n\n      case Rest of\n        [$: | T] when ?is_space(hd(T)) ->\n          Token = {kw_identifier, {Line, Column, Unencoded}, Atom},\n          tokenize(T, Line, Column + Length + 1, Scope, [Token | Tokens]);\n\n        [$: | T] when hd(T) =/= $: ->\n          AtomName = atom_to_list(Atom) ++ [$:],\n          Reason = {?LOC(Line, Column), \"keyword argument must be followed by space after: \", AtomName},\n          error(Reason, String, Scope, Tokens);\n\n        _ when HasAt ->\n          Reason = {?LOC(Line, Column), invalid_character_error(Kind, $@), atom_to_list(Atom)},\n          error(Reason, String, Scope, Tokens);\n\n        _ when Atom == '__aliases__'; Atom == '__block__' ->\n          error({?LOC(Line, Column), \"reserved token: \", atom_to_list(Atom)}, Rest, Scope, Tokens);\n\n        _ when Kind == alias ->\n          tokenize_alias(Rest, Line, Column, Unencoded, Atom, Length, Ascii, Special, Scope, Tokens);\n\n        _ when Kind == identifier ->\n          NewScope = maybe_warn_for_ambiguous_bang_before_equals(identifier, Unencoded, Rest, Line, Column, Scope),\n          Token = check_call_identifier(Line, Column, Unencoded, Atom, Rest),\n          tokenize(Rest, Line, Column + Length, NewScope, [Token | Tokens]);\n\n        _ ->\n          unexpected_token(String, Line, Column, Scope, Tokens)\n      end;\n\n    {keyword, Atom, Type, Rest, Length} ->\n      tokenize_keyword(Type, Rest, Line, Column, Atom, Length, OriginalScope, Tokens);\n\n    empty when OriginalScope#elixir_tokenizer.cursor_completion == false ->\n      unexpected_token(String, Line, Column, OriginalScope, Tokens);\n\n    empty  ->\n      case String of\n        [$~, L] when ?is_upcase(L); ?is_downcase(L) -> tokenize([], Line, Column, OriginalScope, Tokens);\n        [$~] -> tokenize([], Line, Column, OriginalScope, Tokens);\n        _ -> unexpected_token(String, Line, Column, OriginalScope, Tokens)\n      end;\n\n    {unexpected_token, Length} ->\n      unexpected_token(lists:nthtail(Length - 1, String), Line, Column + Length - 1, OriginalScope, Tokens);\n\n    {error, Reason} ->\n      error(Reason, String, OriginalScope, Tokens)\n  end.\n\nprevious_was_dot([{'.', _} | _]) -> true;\nprevious_was_dot(_) -> false.\n\nunexpected_token([T | Rest], Line, Column, Scope, Tokens) ->\n  Message =\n    case handle_char(T) of\n      {_Escaped, Explanation} ->\n        io_lib:format(\"~ts (column ~p, code point U+~4.16.0B)\", [Explanation, Column, T]);\n      false ->\n        io_lib:format(\"\\\"~ts\\\" (column ~p, code point U+~4.16.0B)\", [[T], Column, T])\n    end,\n  error({?LOC(Line, Column), \"unexpected token: \", Message}, Rest, Scope, Tokens).\n\ntokenize_eol(Rest, Line, Scope, Tokens) ->\n  {StrippedRest, NewLine, NewColumn} =\n    strip_horizontal_space(Rest, Line + 1, Scope#elixir_tokenizer.column, Scope),\n  IndentedScope = Scope#elixir_tokenizer{indentation=NewColumn-1},\n  tokenize(StrippedRest, NewLine, NewColumn, IndentedScope, Tokens).\n\nstrip_horizontal_space([H | T], Line, Counter, Scope) when ?is_horizontal_space(H) ->\n  strip_horizontal_space(T, Line, Counter + 1, Scope);\n%% \\\\ at the end of lines is treated as horizontal whitespace\n%% except at the very end of the buffer, which we treat as incomplete\nstrip_horizontal_space(\"\\\\\\n\" ++ T, Line, _Counter, Scope) when T /= [] ->\n  strip_horizontal_space(T, Line+1, Scope#elixir_tokenizer.column, Scope);\nstrip_horizontal_space(\"\\\\\\r\\n\" ++ T, Line, _Counter, Scope) when T /= [] ->\n  strip_horizontal_space(T, Line+1, Scope#elixir_tokenizer.column, Scope);\nstrip_horizontal_space(T, Line, Counter, _Scope) ->\n  {T, Line, Counter}.\n\ntokenize_dot(T, Line, Column, DotInfo, Scope, Tokens) ->\n  case strip_horizontal_space(T, Line, Column, Scope) of\n    {[$# | R], NewLine, NewColumn} ->\n      case tokenize_comment(R, [$#]) of\n        {error, Char, Reason} ->\n          error_comment(Char, Reason, [$# | R], NewLine, NewColumn, Scope, Tokens);\n\n        {Rest, Comment} ->\n          preserve_comments(NewLine, NewColumn, Tokens, Comment, Rest, Scope),\n          tokenize_dot(Rest, NewLine, Scope#elixir_tokenizer.column, DotInfo, Scope, Tokens)\n      end;\n    {\"\\r\\n\" ++ Rest, NewLine, _NewColumn} ->\n      tokenize_dot(Rest, NewLine + 1, Scope#elixir_tokenizer.column, DotInfo, Scope, Tokens);\n    {\"\\n\" ++ Rest, NewLine, _NewColumn} ->\n      tokenize_dot(Rest, NewLine + 1, Scope#elixir_tokenizer.column, DotInfo, Scope, Tokens);\n    {Rest, NewLine, NewColumn} ->\n      handle_dot([$. | Rest], NewLine, NewColumn, DotInfo, Scope, Tokens)\n  end.\n\nhandle_char(0)   -> {\"\\\\0\", \"null byte\"};\nhandle_char(7)   -> {\"\\\\a\", \"alert\"};\nhandle_char($\\b) -> {\"\\\\b\", \"backspace\"};\nhandle_char($\\d) -> {\"\\\\d\", \"delete\"};\nhandle_char($\\e) -> {\"\\\\e\", \"escape\"};\nhandle_char($\\f) -> {\"\\\\f\", \"form feed\"};\nhandle_char($\\n) -> {\"\\\\n\", \"newline\"};\nhandle_char($\\r) -> {\"\\\\r\", \"carriage return\"};\nhandle_char($\\s) -> {\"\\\\s\", \"space\"};\nhandle_char($\\t) -> {\"\\\\t\", \"tab\"};\nhandle_char($\\v) -> {\"\\\\v\", \"vertical tab\"};\nhandle_char(_)  -> false.\n\n%% Handlers\n\nhandle_heredocs(T, Line, Column, H, Scope, Tokens) ->\n  case extract_heredoc_with_interpolation(Line, Column, Scope, true, T, H) of\n    {ok, NewLine, NewColumn, Parts, Rest, _Done, NewScope} ->\n      case unescape_tokens(Parts, Line, Column, NewScope) of\n        {ok, Unescaped} ->\n          Token = {heredoc_type(H), {Line, Column, nil}, NewColumn - 4, Unescaped},\n          tokenize(Rest, NewLine, NewColumn, NewScope, [Token | Tokens]);\n\n        {error, Reason} ->\n          error(Reason, Rest, Scope, Tokens)\n      end;\n\n    {error, Reason} ->\n      error(Reason, [H, H, H] ++ T, Scope, Tokens)\n  end.\n\nhandle_strings(T, Line, Column, H, Scope, Tokens) ->\n  case elixir_interpolation:extract(Line, Column, Scope, true, T, H) of\n    {error, Reason} ->\n      interpolation_error(Reason, [H | T], Scope, Tokens, \" (for string starting at line ~B)\", [Line], Line, Column-1, [H], [H]);\n\n    {NewLine, NewColumn, Parts, [$: | Rest], _Done, InterScope} when ?is_space(hd(Rest)) ->\n      NewScope = case is_unnecessary_quote(Parts, InterScope) of\n        true ->\n          WarnMsg = io_lib:format(\n            \"found quoted keyword \\\"~ts\\\" but the quotes are not required. \"\n            \"Note that keywords are always atoms, even when quoted. \"\n            \"Similar to atoms, keywords made exclusively of ASCII \"\n            \"letters, numbers, and underscores and not beginning with a \"\n            \"number do not require quotes\",\n            [hd(Parts)]\n          ),\n          prepend_warning(Line, Column-1, WarnMsg, InterScope);\n\n        false when H =:= $' ->\n          WarnMsg = \"single quotes around keywords are deprecated. Use double quotes instead\",\n          prepend_warning(Line, Column-1, WarnMsg, InterScope);\n\n        false ->\n          InterScope\n      end,\n\n      case unescape_tokens(Parts, Line, Column, NewScope) of\n        {ok, [Part]} when is_binary(Part) ->\n          case unsafe_to_atom(Part, Line, Column - 1, Scope) of\n            {ok, Atom} ->\n              Token = {kw_identifier, {Line, Column - 1, H}, Atom},\n              tokenize(Rest, NewLine, NewColumn + 1, NewScope, [Token | Tokens]);\n            {error, Reason} ->\n              error(Reason, Rest, NewScope, Tokens)\n          end;\n\n        {ok, Unescaped} ->\n          Key = case Scope#elixir_tokenizer.existing_atoms_only of\n            true  -> kw_identifier_safe;\n            false -> kw_identifier_unsafe\n          end,\n          Token = {Key, {Line, Column - 1, H}, Unescaped},\n          tokenize(Rest, NewLine, NewColumn + 1, NewScope, [Token | Tokens]);\n\n        {error, Reason} ->\n          error(Reason, Rest, NewScope, Tokens)\n      end;\n\n    {NewLine, NewColumn, Parts, Rest, _Done, InterScope} ->\n      NewScope =\n        case H of\n          $' ->\n            Message = \"using single-quoted strings to represent charlists is deprecated.\\n\"\n              \"Use ~c\\\"\\\" if you indeed want a charlist or use \\\"\\\" instead.\\n\"\n              \"You may run \\\"mix format --migrate\\\" to change all single-quoted\\n\"\n              \"strings to use the ~c sigil and fix this warning.\",\n            prepend_warning(Line, Column-1, Message, InterScope);\n\n          _ ->\n            InterScope\n        end,\n\n      case unescape_tokens(Parts, Line, Column, NewScope) of\n        {ok, Unescaped} ->\n          Token = {string_type(H), {Line, Column - 1, nil}, Unescaped},\n          tokenize(Rest, NewLine, NewColumn, NewScope, [Token | Tokens]);\n\n        {error, Reason} ->\n          error(Reason, Rest, NewScope, Tokens)\n      end\n  end.\n\nhandle_unary_op([$: | Rest], Line, Column, _Kind, Length, Op, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  Token = {kw_identifier, {Line, Column, nil}, Op},\n  tokenize(Rest, Line, Column + Length + 1, Scope, [Token | Tokens]);\n\nhandle_unary_op(Rest, Line, Column, Kind, Length, Op, Scope, Tokens) ->\n  case strip_horizontal_space(Rest, Line, Column + Length, Scope) of\n    {[$/ | _] = Remaining, NewLine, NewColumn} ->\n      Token = {identifier, {Line, Column, nil}, Op},\n      tokenize(Remaining, NewLine, NewColumn, Scope, [Token | Tokens]);\n    {Remaining, NewLine, NewColumn} ->\n      NewScope =\n        %% TODO: Remove these deprecations on Elixir v2.0\n        case Op of\n          '~~~' ->\n            Msg = \"~~~ is deprecated. Use Bitwise.bnot/1 instead for clarity\",\n            prepend_warning(Line, Column, Msg, Scope);\n          _ ->\n            Scope\n        end,\n\n      Token = {Kind, {Line, Column, nil}, Op},\n      tokenize(Remaining, NewLine, NewColumn, NewScope, [Token | Tokens])\n  end.\n\nhandle_op([$: | Rest], Line, Column, _Kind, Length, Op, Scope, Tokens) when ?is_space(hd(Rest)) ->\n  Token = {kw_identifier, {Line, Column, nil}, Op},\n  tokenize(Rest, Line, Column + Length + 1, Scope, [Token | Tokens]);\n\nhandle_op(Rest, Line, Column, Kind, Length, Op, Scope, Tokens) ->\n  case strip_horizontal_space(Rest, Line, Column + Length, Scope) of\n    {[$/ | _] = Remaining, NewLine, NewColumn} ->\n      Token = {identifier, {Line, Column, nil}, Op},\n      tokenize(Remaining, NewLine, NewColumn, Scope, [Token | Tokens]);\n    {Remaining, NewLine, NewColumn} ->\n      NewScope =\n        %% TODO: Remove these deprecations on Elixir v2.0\n        case Op of\n          '^^^' ->\n            Msg = \"^^^ is deprecated. It is typically used as xor but it has the wrong precedence, use Bitwise.bxor/2 instead\",\n            prepend_warning(Line, Column, Msg, Scope);\n\n          '<|>' ->\n            Msg = \"<|> is deprecated. Use another pipe-like operator\",\n            prepend_warning(Line, Column, Msg, Scope);\n\n          _ ->\n            Scope\n        end,\n\n      Token = {Kind, {Line, Column, previous_was_eol(Tokens)}, Op},\n      tokenize(Remaining, NewLine, NewColumn, NewScope, add_token_with_eol(Token, Tokens))\n  end.\n\n% ## Three Token Operators\nhandle_dot([$., T1, T2, T3 | Rest], Line, Column, DotInfo, Scope, Tokens) when\n    ?unary_op3(T1, T2, T3); ?comp_op3(T1, T2, T3); ?and_op3(T1, T2, T3); ?or_op3(T1, T2, T3);\n    ?arrow_op3(T1, T2, T3); ?xor_op3(T1, T2, T3); ?concat_op3(T1, T2, T3) ->\n  handle_call_identifier(Rest, Line, Column, DotInfo, 3, [T1, T2, T3], Scope, Tokens);\n\n% ## Two Token Operators\nhandle_dot([$., T1, T2 | Rest], Line, Column, DotInfo, Scope, Tokens) when\n    ?comp_op2(T1, T2); ?rel_op2(T1, T2); ?and_op(T1, T2); ?or_op(T1, T2);\n    ?arrow_op(T1, T2); ?in_match_op(T1, T2); ?concat_op(T1, T2); ?power_op(T1, T2);\n    ?type_op(T1, T2) ->\n  handle_call_identifier(Rest, Line, Column, DotInfo, 2, [T1, T2], Scope, Tokens);\n\n% ## Single Token Operators\nhandle_dot([$., T | Rest], Line, Column, DotInfo, Scope, Tokens) when\n    ?at_op(T); ?unary_op(T); ?capture_op(T); ?dual_op(T); ?mult_op(T);\n    ?rel_op(T); ?match_op(T); ?pipe_op(T) ->\n  handle_call_identifier(Rest, Line, Column, DotInfo, 1, [T], Scope, Tokens);\n\n% ## Exception for .( as it needs to be treated specially in the parser\nhandle_dot([$., $( | Rest], Line, Column, DotInfo, Scope, Tokens) ->\n  TokensSoFar = add_token_with_eol({dot_call_op, DotInfo, '.'}, Tokens),\n  tokenize([$( | Rest], Line, Column, Scope, TokensSoFar);\n\nhandle_dot([$., H | T] = Original, Line, Column, DotInfo, BaseScope, Tokens) when ?is_quote(H) ->\n  Scope = case H == $' of\n    true ->\n      prepend_warning(Line, Column, \"single quotes around calls are deprecated. Use double quotes instead\", BaseScope);\n\n    false ->\n      BaseScope\n  end,\n\n  case elixir_interpolation:extract(Line, Column + 1, Scope, true, T, H) of\n    {NewLine, NewColumn, [Part], Rest, _Done, InterScope} when is_list(Part) ->\n      NewScope = case is_unnecessary_quote([Part], InterScope) of\n        true ->\n          WarnMsg = io_lib:format(\n            \"found quoted call \\\"~ts\\\" but the quotes are not required. \"\n            \"Calls made exclusively of Unicode letters, numbers, and underscores \"\n            \"and not beginning with a number do not require quotes\",\n            [Part]\n          ),\n          prepend_warning(Line, Column, WarnMsg, InterScope);\n\n        false ->\n          InterScope\n      end,\n\n      case unescape_tokens([Part], Line, Column, NewScope) of\n        {ok, [UnescapedPart]} ->\n          case unsafe_to_atom(UnescapedPart, Line, Column, NewScope) of\n            {ok, Atom} ->\n              Token = check_call_identifier(Line, Column, H, Atom, Rest),\n              TokensSoFar = add_token_with_eol({'.', DotInfo}, Tokens),\n              tokenize(Rest, NewLine, NewColumn, NewScope, [Token | TokensSoFar]);\n\n            {error, Reason} ->\n              error(Reason, Original, NewScope, Tokens)\n          end;\n\n        {error, Reason} ->\n          error(Reason, Original, NewScope, Tokens)\n      end;\n\n    {_NewLine, _NewColumn, _Parts, Rest, _Done, NewScope} ->\n      Message = \"interpolation is not allowed when calling function/macro. Found interpolation in a call starting with: \",\n      error({?LOC(Line, Column), Message, [H]}, Rest, NewScope, Tokens);\n    {error, Reason} ->\n      interpolation_error(Reason, Original, Scope, Tokens, \" (for function name starting at line ~B)\", [Line], Line, Column, [H], [H])\n  end;\n\nhandle_dot([$. | Rest], Line, Column, DotInfo, Scope, Tokens) ->\n  TokensSoFar = add_token_with_eol({'.', DotInfo}, Tokens),\n  tokenize(Rest, Line, Column, Scope, TokensSoFar).\n\nhandle_call_identifier(Rest, Line, Column, DotInfo, Length, UnencodedOp, Scope, Tokens) ->\n  Token = check_call_identifier(Line, Column, UnencodedOp, list_to_atom(UnencodedOp), Rest),\n  TokensSoFar = add_token_with_eol({'.', DotInfo}, Tokens),\n  tokenize(Rest, Line, Column + Length, Scope, [Token | TokensSoFar]).\n\n% ## Ambiguous unary/binary operators tokens\n% Keywords are not ambiguous operators\nhandle_space_sensitive_tokens([Sign, $:, Space | _] = String, Line, Column, Scope, Tokens) when\n    ?dual_op(Sign), ?is_space(Space) ->\n  tokenize(String, Line, Column, Scope, Tokens);\n\n% But everything else, except other operators, are\nhandle_space_sensitive_tokens([Sign, NotMarker | T], Line, Column, Scope, [{identifier, _, _} = H | Tokens]) when\n    ?dual_op(Sign), not(?is_space(NotMarker)),\n    %% Do not match ++ or --\n    NotMarker =/= Sign,\n    %% Do not match +/2 or -/2\n    NotMarker =/= $/,\n    %% Do not match ->\n    NotMarker =/= $>,\n    %% Do not match +\\\\n or -\\\\n (it should be treated as if a space is there)\n    NotMarker =/= $\\\\ ->\n  Rest = [NotMarker | T],\n  DualOpToken = {dual_op, {Line, Column, nil}, list_to_atom([Sign])},\n  tokenize(Rest, Line, Column + 1, Scope, [DualOpToken, setelement(1, H, op_identifier) | Tokens]);\n\n% Handle cursor completion\nhandle_space_sensitive_tokens([], Line, Column,\n                              #elixir_tokenizer{cursor_completion=Cursor} = Scope,\n                              [{identifier, Info, Identifier} | Tokens]) when Cursor /= false ->\n  tokenize([$(], Line, Column+1, Scope, [{paren_identifier, Info, Identifier} | Tokens]);\n\nhandle_space_sensitive_tokens(String, Line, Column, Scope, Tokens) ->\n  tokenize(String, Line, Column, Scope, Tokens).\n\n%% Helpers\n\neol(_Line, _Column, [{',', {Line, Column, Count}} | Tokens]) ->\n  [{',', {Line, Column, Count + 1}} | Tokens];\neol(_Line, _Column, [{';', {Line, Column, Count}} | Tokens]) ->\n  [{';', {Line, Column, Count + 1}} | Tokens];\neol(_Line, _Column, [{eol, {Line, Column, Count}} | Tokens]) ->\n  [{eol, {Line, Column, Count + 1}} | Tokens];\neol(Line, Column, Tokens) ->\n  [{eol, {Line, Column, 1}} | Tokens].\n\nis_unnecessary_quote([Part], Scope) when is_list(Part) ->\n  case (Scope#elixir_tokenizer.identifier_tokenizer):tokenize(Part) of\n    {identifier, _, [], _, true, Special} -> not lists:member(at, Special);\n    _ -> false\n  end;\nis_unnecessary_quote(_Parts, _Scope) ->\n  false.\n\nunsafe_to_atom(Part, Line, Column, #elixir_tokenizer{}) when\n    is_binary(Part) andalso byte_size(Part) > 255;\n    is_list(Part) andalso length(Part) > 255 ->\n  try\n    PartList = elixir_utils:characters_to_list(Part),\n    {error, {?LOC(Line, Column), \"atom length must be less than system limit: \", PartList}}\n  catch\n    error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n      {error, {?LOC(Line, Column), \"invalid encoding in atom: \", elixir_utils:characters_to_list(Message)}}\n  end;\nunsafe_to_atom(Part, Line, Column, #elixir_tokenizer{static_atoms_encoder=StaticAtomsEncoder}) when\n    is_function(StaticAtomsEncoder) ->\n  EncodeResult = try\n    ValueEncBin = elixir_utils:characters_to_binary(Part),\n    ValueEncList = elixir_utils:characters_to_list(Part),\n    {ok, ValueEncBin, ValueEncList}\n  catch\n    error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n      {error, {?LOC(Line, Column), \"invalid encoding in atom: \", elixir_utils:characters_to_list(Message)}}\n  end,\n\n  case EncodeResult of\n    {ok, Value, ValueList} ->\n      case StaticAtomsEncoder(Value, [{line, Line}, {column, Column}]) of\n        {ok, Term} ->\n          {ok, Term};\n        {error, Reason} when is_binary(Reason) ->\n          {error, {?LOC(Line, Column), elixir_utils:characters_to_list(Reason) ++ \": \", ValueList}}\n      end;\n    EncError -> EncError\n  end;\nunsafe_to_atom(Binary, Line, Column, #elixir_tokenizer{existing_atoms_only=true}) when is_binary(Binary) ->\n  try\n    {ok, binary_to_existing_atom(Binary, utf8)}\n  catch\n    error:badarg ->\n      % Check if it's a UTF-8 issue by trying to convert to list\n      try\n        List = elixir_utils:characters_to_list(Binary),\n        % If we get here, it's not a UTF-8 issue\n        {error, {?LOC(Line, Column), \"unsafe atom does not exist: \", List}}\n      catch\n        error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n          {error, {?LOC(Line, Column), \"invalid encoding in atom: \", elixir_utils:characters_to_list(Message)}}\n      end\n  end;\nunsafe_to_atom(Binary, Line, Column, #elixir_tokenizer{}) when is_binary(Binary) ->\n  try\n    {ok, binary_to_atom(Binary, utf8)}\n  catch\n    error:badarg ->\n      % Try to convert using elixir_utils to get proper UnicodeConversionError\n      try\n        List = elixir_utils:characters_to_list(Binary),\n        % If we get here, it's not a UTF-8 issue, so it's some other badarg\n        {error, {?LOC(Line, Column), \"invalid atom: \", List}}\n      catch\n        error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n          {error, {?LOC(Line, Column), \"invalid encoding in atom: \", elixir_utils:characters_to_list(Message)}}\n      end\n  end;\nunsafe_to_atom(List, Line, Column, #elixir_tokenizer{existing_atoms_only=true}) when is_list(List) ->\n  try\n    {ok, list_to_existing_atom(List)}\n  catch\n    error:badarg ->\n      % Try to convert using elixir_utils to get proper UnicodeConversionError\n      try\n        elixir_utils:characters_to_binary(List),\n        % If we get here, it's not a UTF-8 issue\n        {error, {?LOC(Line, Column), \"unsafe atom does not exist: \", List}}\n      catch\n        error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n          {error, {?LOC(Line, Column), \"invalid encoding in atom: \", elixir_utils:characters_to_list(Message)}}\n      end\n  end;\nunsafe_to_atom(List, Line, Column, #elixir_tokenizer{}) when is_list(List) ->\n  try\n    {ok, list_to_atom(List)}\n  catch\n    error:badarg ->\n      % Try to convert using elixir_utils to get proper UnicodeConversionError\n      try\n        elixir_utils:characters_to_binary(List),\n        % If we get here, it's not a UTF-8 issue, so it's some other badarg\n        {error, {?LOC(Line, Column), \"invalid atom: \", List}}\n      catch\n        error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n          {error, {?LOC(Line, Column), \"invalid encoding in atom: \", elixir_utils:characters_to_list(Message)}}\n      end\n  end.\n\ncollect_modifiers([H | T], Column, Buffer) when ?is_downcase(H) or ?is_upcase(H) or ?is_digit(H) ->\n  collect_modifiers(T, Column + 1, [H | Buffer]);\n\ncollect_modifiers(Rest, Column, Buffer) ->\n  {Rest, Column, lists:reverse(Buffer)}.\n\n%% Heredocs\n\nextract_heredoc_with_interpolation(Line, Column, Scope, Interpol, T, H) ->\n  case extract_heredoc_header(T) of\n    {ok, Headerless} ->\n      %% We prepend a new line so we can transparently remove\n      %% spaces later. This new line is removed by calling \"tl\"\n      %% in the final heredoc body three lines below.\n      case elixir_interpolation:extract(Line, Column, Scope, Interpol, [$\\n|Headerless], [H,H,H]) of\n        {NewLine, NewColumn, Parts0, Rest, Done, InterScope} ->\n          Indent = NewColumn - 4,\n          Fun = fun(Part, Acc) -> extract_heredoc_indent(Part, Acc, Indent) end,\n          {Parts1, {ShouldWarn, _}} = lists:mapfoldl(Fun, {false, Line}, Parts0),\n          Parts2 = extract_heredoc_head(Parts1),\n          NewScope = maybe_heredoc_warn(ShouldWarn, Column, InterScope, H),\n          try\n            {ok, NewLine, NewColumn, tokens_to_binary(Parts2), Rest, Done, NewScope}\n          catch\n            error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n              {error, interpolation_format(Message, \" (for heredoc starting at line ~B)\", [Line], Line, Column, [H, H, H], [H, H, H])}\n          end;\n\n        {error, Reason} ->\n          {error, interpolation_format(Reason, \" (for heredoc starting at line ~B)\", [Line], Line, Column, [H, H, H], [H, H, H])}\n      end;\n\n    error ->\n      Message = \"heredoc allows only whitespace characters followed by a new line after opening \",\n      {error, {?LOC(Line, Column + 3), io_lib:format(Message, []), [H, H, H]}}\n  end.\n\nextract_heredoc_header(\"\\r\\n\" ++ Rest) ->\n  {ok, Rest};\nextract_heredoc_header(\"\\n\" ++ Rest) ->\n  {ok, Rest};\nextract_heredoc_header([H | T]) when ?is_horizontal_space(H) ->\n  extract_heredoc_header(T);\nextract_heredoc_header(_) ->\n  error.\n\nextract_heredoc_indent(Part, {Warned, Line}, Indent) when is_list(Part) ->\n  extract_heredoc_indent(Part, [], Warned, Line, Indent);\nextract_heredoc_indent({_, {EndLine, _, _}, _} = Part, {Warned, _Line}, _Indent) ->\n  {Part, {Warned, EndLine}}.\n\nextract_heredoc_indent([$\\n | Rest], Acc, Warned, Line, Indent) ->\n  {Trimmed, ShouldWarn} = trim_space(Rest, Indent),\n  Warn = if ShouldWarn, not Warned -> Line + 1; true -> Warned end,\n  extract_heredoc_indent(Trimmed, [$\\n | Acc], Warn, Line + 1, Indent);\nextract_heredoc_indent([Head | Rest], Acc, Warned, Line, Indent) ->\n  extract_heredoc_indent(Rest, [Head | Acc], Warned, Line, Indent);\nextract_heredoc_indent([], Acc, Warned, Line, _Indent) ->\n  {lists:reverse(Acc), {Warned, Line}}.\n\ntrim_space(Rest, 0) -> {Rest, false};\ntrim_space([$\\r, $\\n | _] = Rest, _) -> {Rest, false};\ntrim_space([$\\n | _] = Rest, _) -> {Rest, false};\ntrim_space([H | T], Spaces) when ?is_horizontal_space(H) -> trim_space(T, Spaces - 1);\ntrim_space([], _Spaces) -> {[], false};\ntrim_space(Rest, _Spaces) -> {Rest, true}.\n\nmaybe_heredoc_warn(false, _Column, Scope, _Marker) ->\n  Scope;\nmaybe_heredoc_warn(Line, Column, Scope, Marker) ->\n  Msg = io_lib:format(\"outdented heredoc line. The contents inside the heredoc should be indented \"\n                      \"at the same level as the closing ~ts. The following is forbidden:~n~n\"\n                      \"    def text do~n\"\n                      \"      \\\"\\\"\\\"~n\"\n                      \"    contents~n\"\n                      \"      \\\"\\\"\\\"~n\"\n                      \"    end~n~n\"\n                      \"Instead make sure the contents are indented as much as the heredoc closing:~n~n\"\n                      \"    def text do~n\"\n                      \"      \\\"\\\"\\\"~n\"\n                      \"      contents~n\"\n                      \"      \\\"\\\"\\\"~n\"\n                      \"    end~n~n\"\n                      \"The current heredoc line is indented too little\", [[Marker, Marker, Marker]]),\n\n  prepend_warning(Line, Column, Msg, Scope).\n\nextract_heredoc_head([[$\\n|H]|T]) -> [H|T].\n\nunescape_tokens(Tokens, Line, Column, #elixir_tokenizer{unescape=true}) ->\n  case elixir_interpolation:unescape_tokens(Tokens) of\n    {ok, Result} ->\n      {ok, Result};\n\n    {error, Message, Token} ->\n      {error, {?LOC(Line, Column), Message ++ \". Syntax error after: \", Token}}\n  end;\nunescape_tokens(Tokens, Line, Column, #elixir_tokenizer{unescape=false}) ->\n  try\n    {ok, tokens_to_binary(Tokens)}\n  catch\n    error:#{'__struct__' := 'Elixir.UnicodeConversionError', message := Message} ->\n      {error, {?LOC(Line, Column), \"invalid encoding in tokens: \", elixir_utils:characters_to_list(Message)}}\n  end.\n\ntokens_to_binary(Tokens) ->\n  [if is_list(Token) -> elixir_utils:characters_to_binary(Token); true -> Token end\n   || Token <- Tokens].\n\n%% Integers and floats\n%% At this point, we are at least sure the first digit is a number.\n\n%% Check if we have a point followed by a number;\ntokenize_number([$., H | T], Acc, Length, false) when ?is_digit(H) ->\n  tokenize_number(T, [H, $. | Acc], Length + 2, true);\n\n%% Check if we have an underscore followed by a number;\ntokenize_number([$_, H | T], Acc, Length, Bool) when ?is_digit(H) ->\n  tokenize_number(T, [H, $_ | Acc], Length + 2, Bool);\n\n%% Check if we have e- followed by numbers (valid only for floats);\ntokenize_number([E, S, H | T], Acc, Length, true)\n    when (E =:= $E) or (E =:= $e), ?is_digit(H), S =:= $+ orelse S =:= $- ->\n  tokenize_number(T, [H, S, E | Acc], Length + 3, true);\n\n%% Check if we have e followed by numbers (valid only for floats);\ntokenize_number([E, H | T], Acc, Length, true)\n    when (E =:= $E) or (E =:= $e), ?is_digit(H) ->\n  tokenize_number(T, [H, E | Acc], Length + 2, true);\n\n%% Finally just numbers.\ntokenize_number([H | T], Acc, Length, Bool) when ?is_digit(H) ->\n  tokenize_number(T, [H | Acc], Length + 1, Bool);\n\n%% Cast to float...\ntokenize_number(Rest, Acc, Length, true) ->\n  try\n    {Number, Original} = reverse_number(Acc, [], []),\n    {Rest, list_to_float(Number), Original, Length}\n  catch\n    error:badarg -> {error, \"invalid float number \", lists:reverse(Acc)}\n  end;\n\n%% Or integer.\ntokenize_number(Rest, Acc, Length, false) ->\n  {Number, Original} = reverse_number(Acc, [], []),\n  {Rest, list_to_integer(Number), Original, Length}.\n\ntokenize_hex([H | T], Acc, Length) when ?is_hex(H) ->\n  tokenize_hex(T, [H | Acc], Length + 1);\ntokenize_hex([$_, H | T], Acc, Length) when ?is_hex(H) ->\n  tokenize_hex(T, [H, $_ | Acc], Length + 2);\ntokenize_hex(Rest, Acc, Length) ->\n  {Number, Original} = reverse_number(Acc, [], []),\n  {Rest, list_to_integer(Number, 16), [$0, $x | Original], Length}.\n\ntokenize_octal([H | T], Acc, Length) when ?is_octal(H) ->\n  tokenize_octal(T, [H | Acc], Length + 1);\ntokenize_octal([$_, H | T], Acc, Length) when ?is_octal(H) ->\n  tokenize_octal(T, [H, $_ | Acc], Length + 2);\ntokenize_octal(Rest, Acc, Length) ->\n  {Number, Original} = reverse_number(Acc, [], []),\n  {Rest, list_to_integer(Number, 8), [$0, $o | Original], Length}.\n\ntokenize_bin([H | T], Acc, Length) when ?is_bin(H) ->\n  tokenize_bin(T, [H | Acc], Length + 1);\ntokenize_bin([$_, H | T], Acc, Length) when ?is_bin(H) ->\n  tokenize_bin(T, [H, $_ | Acc], Length + 2);\ntokenize_bin(Rest, Acc, Length) ->\n  {Number, Original} = reverse_number(Acc, [], []),\n  {Rest, list_to_integer(Number, 2), [$0, $b | Original], Length}.\n\nreverse_number([$_ | T], Number, Original) ->\n  reverse_number(T, Number, [$_ | Original]);\nreverse_number([H | T], Number, Original) ->\n  reverse_number(T, [H | Number], [H | Original]);\nreverse_number([], Number, Original) ->\n  {Number, Original}.\n\n%% Comments\n\nreset_eol([{eol, {Line, Column, _}} | Rest]) -> [{eol, {Line, Column, 0}} | Rest];\nreset_eol(Rest) -> Rest.\n\ntokenize_comment(\"\\r\\n\" ++ _ = Rest, Acc) ->\n  {Rest, lists:reverse(Acc)};\ntokenize_comment(\"\\n\" ++ _ = Rest, Acc) ->\n  {Rest, lists:reverse(Acc)};\ntokenize_comment([H | _Rest], _) when ?bidi(H) ->\n  {error, H, \"invalid bidirectional formatting character in comment: \"};\ntokenize_comment([H | _Rest], _) when ?break(H) ->\n  {error, H, \"invalid line break character in comment: \"};\ntokenize_comment([H | Rest], Acc) ->\n  tokenize_comment(Rest, [H | Acc]);\ntokenize_comment([], Acc) ->\n  {[], lists:reverse(Acc)}.\n\nerror_comment(Char, Reason, Comment, Line, Column, Scope, Tokens) ->\n  Token = io_lib:format(\"\\\\u~4.16.0B\", [Char]),\n  error({?LOC(Line, Column), Reason, Token}, Comment, Scope, Tokens).\n\npreserve_comments(Line, Column, Tokens, Comment, Rest, Scope) ->\n  case Scope#elixir_tokenizer.preserve_comments of\n    Fun when is_function(Fun) ->\n      Fun(Line, Column, Tokens, Comment, Rest);\n    nil ->\n      ok\n  end.\n\n%% Identifiers\n\ntokenize([H | T]) when ?is_upcase(H) ->\n  {Acc, Rest, Length, Special} = tokenize_continue(T, [H], 1, []),\n  {alias, lists:reverse(Acc), Rest, Length, true, Special};\ntokenize([H | T]) when ?is_downcase(H); H =:= $_ ->\n  {Acc, Rest, Length, Special} = tokenize_continue(T, [H], 1, []),\n  {identifier, lists:reverse(Acc), Rest, Length, true, Special};\ntokenize(_List) ->\n  {error, empty}.\n\ntokenize_continue([$@ | T], Acc, Length, Special) ->\n  tokenize_continue(T, [$@ | Acc], Length + 1, [at | lists:delete(at, Special)]);\ntokenize_continue([$! | T], Acc, Length, Special) ->\n  {[$! | Acc], T, Length + 1, [punctuation | Special]};\ntokenize_continue([$? | T], Acc, Length, Special) ->\n  {[$? | Acc], T, Length + 1, [punctuation | Special]};\ntokenize_continue([H | T], Acc, Length, Special) when ?is_upcase(H); ?is_downcase(H); ?is_digit(H); H =:= $_ ->\n  tokenize_continue(T, [H | Acc], Length + 1, Special);\ntokenize_continue(Rest, Acc, Length, Special) ->\n  {Acc, Rest, Length, Special}.\n\ntokenize_identifier(String, Line, Column, Scope, MaybeKeyword) ->\n  case (Scope#elixir_tokenizer.identifier_tokenizer):tokenize(String) of\n    {Kind, Acc, Rest, Length, Ascii, Special} ->\n      Keyword = MaybeKeyword andalso maybe_keyword(Rest),\n\n      case keyword_or_unsafe_to_atom(Keyword, Acc, Line, Column, Scope) of\n        {keyword, Atom, Type} ->\n          {keyword, Atom, Type, Rest, Length};\n        {ok, Atom} ->\n          {Kind, Acc, Atom, Rest, Length, Ascii, Special};\n        {error, _Reason} = Error ->\n          Error\n      end;\n\n    {error, {mixed_script, Wrong, {Prefix, Suffix}}} ->\n      WrongColumn = Column + length(Wrong) - 1,\n      case suggest_simpler_unexpected_token_in_error(Wrong, Line, WrongColumn, Scope) of\n        no_suggestion ->\n          %% we append a pointer to more info if we aren't appending a suggestion\n          MoreInfo = \"\\nSee https://hexdocs.pm/elixir/unicode-syntax.html for more information.\",\n          {error, {?LOC(Line, Column), {Prefix, Suffix ++ MoreInfo}, Wrong}};\n\n        {_, {Location, _, SuggestionMessage}} = _SuggestionError ->\n          {error, {Location, {Prefix, Suffix ++ SuggestionMessage}, Wrong}}\n      end;\n\n    {error, {unexpected_token, Wrong}} ->\n      WrongColumn = Column + length(Wrong) - 1,\n      case suggest_simpler_unexpected_token_in_error(Wrong, Line, WrongColumn, Scope) of\n        no_suggestion ->\n          [T | _] = lists:reverse(Wrong),\n          case suggest_simpler_unexpected_token_in_error([T], Line, WrongColumn, Scope) of\n            no_suggestion -> {unexpected_token, length(Wrong)};\n            SuggestionError -> SuggestionError\n          end;\n\n        SuggestionError ->\n          SuggestionError\n      end;\n\n    {error, empty} ->\n      empty\n  end.\n\n%% heuristic: try nfkc; try confusability skeleton; try calling this again w/just failed codepoint\nsuggest_simpler_unexpected_token_in_error(Wrong, Line, WrongColumn, Scope) ->\n  NFKC = unicode:characters_to_nfkc_list(Wrong),\n  case (Scope#elixir_tokenizer.identifier_tokenizer):tokenize(NFKC) of\n    {error, _Reason} ->\n       ConfusableSkeleton = 'Elixir.String.Tokenizer.Security':confusable_skeleton(Wrong),\n       case (Scope#elixir_tokenizer.identifier_tokenizer):tokenize(ConfusableSkeleton) of\n         {_, Simpler, _, _, _, _} ->\n           Message = suggest_change(\"Codepoint failed identifier tokenization, but a simpler form was found.\",\n                                    Wrong,\n                                    \"You could write the above in a similar way that is accepted by Elixir:\",\n                                    Simpler,\n                                    \"See https://hexdocs.pm/elixir/unicode-syntax.html for more information.\"),\n           {error, {?LOC(Line, WrongColumn), \"unexpected token: \", Message}};\n         _other ->\n           no_suggestion\n       end;\n    {_, _NFKC, _, _, _, _} ->\n      Message = suggest_change(\"Elixir expects unquoted Unicode atoms, variables, and calls to use allowed codepoints and to be in NFC form.\",\n                               Wrong,\n                               \"You could write the above in a compatible format that is accepted by Elixir:\",\n                               NFKC,\n                               \"See https://hexdocs.pm/elixir/unicode-syntax.html for more information.\"),\n          {error, {?LOC(Line, WrongColumn), \"unexpected token: \", Message}}\n    end.\n\nsuggest_change(Intro, WrongForm, Hint, HintedForm, Ending) ->\n  WrongCodepoints = list_to_codepoint_hex(WrongForm),\n  HintedCodepoints = list_to_codepoint_hex(HintedForm),\n  io_lib:format(\"~ts\\n\\nGot:\\n\\n    \\\"~ts\\\" (code points~ts)\\n\\n\"\n                \"Hint: ~ts\\n\\n    \\\"~ts\\\" (code points~ts)\\n\\n~ts\",\n                [Intro, WrongForm, WrongCodepoints, Hint, HintedForm, HintedCodepoints, Ending]).\n\nmaybe_keyword([]) -> true;\nmaybe_keyword([$:, $: | _]) -> true;\nmaybe_keyword([$: | _]) -> false;\nmaybe_keyword(_) -> true.\n\nlist_to_codepoint_hex(List) ->\n  [io_lib:format(\" 0x~5.16.0B\", [Codepoint]) || Codepoint <- List].\n\ntokenize_alias(Rest, Line, Column, Unencoded, Atom, Length, Ascii, Special, Scope, Tokens) ->\n  if\n    not Ascii or (Special /= []) ->\n      Invalid = hd([C || C <- Unencoded, (C < $A) or (C > 127)]),\n      Reason = {?LOC(Line, Column), invalid_character_error(\"alias (only ASCII characters, without punctuation, are allowed)\", Invalid), Unencoded},\n      error(Reason, Unencoded ++ Rest, Scope, Tokens);\n\n    true ->\n      AliasesToken = {alias, {Line, Column, Unencoded}, Atom},\n      tokenize(Rest, Line, Column + Length, Scope, [AliasesToken | Tokens])\n  end.\n\n%% Check if it is a call identifier (paren | bracket | do)\n\ncheck_call_identifier(Line, Column, Info, Atom, [$( | _]) ->\n  {paren_identifier, {Line, Column, Info}, Atom};\ncheck_call_identifier(Line, Column, Info, Atom, [$[ | _]) ->\n  {bracket_identifier, {Line, Column, Info}, Atom};\ncheck_call_identifier(Line, Column, Info, Atom, _Rest) ->\n  {identifier, {Line, Column, Info}, Atom}.\n\nadd_token_with_eol({unary_op, _, _} = Left, T) -> [Left | T];\nadd_token_with_eol(Left, [{eol, _} | T]) -> [Left | T];\nadd_token_with_eol(Left, T) -> [Left | T].\n\nprevious_was_eol([{',', {_, _, Count}} | _]) when Count > 0 -> Count;\nprevious_was_eol([{';', {_, _, Count}} | _]) when Count > 0 -> Count;\nprevious_was_eol([{eol, {_, _, Count}} | _]) when Count > 0 -> Count;\nprevious_was_eol(_) -> nil.\n\n%% Error handling\n\ninterpolation_error(Reason, Rest, Scope, Tokens, Extension, Args, Line, Column, Opening, Closing) ->\n  error(interpolation_format(Reason, Extension, Args, Line, Column, Opening, Closing), Rest, Scope, Tokens).\n\ninterpolation_format({string, EndLine, EndColumn, Message, Token}, Extension, Args, Line, Column, Opening, Closing) ->\n  Meta = [\n    {opening_delimiter, list_to_atom(Opening)},\n    {expected_delimiter, list_to_atom(Closing)},\n    {line, Line},\n    {column, Column},\n    {end_line, EndLine},\n    {end_column, EndColumn}\n  ],\n  {Meta, [Message, io_lib:format(Extension, Args)], Token};\ninterpolation_format({_, _, _} = Reason, _Extension, _Args, _Line, _Column, _Opening, _Closing) ->\n  Reason.\n\n%% Terminators\n\nhandle_terminator(Rest, _, _, Scope, {'(', {Line, Column, _}}, [{alias, _, Alias} | Tokens]) when is_atom(Alias) ->\n  Reason =\n    io_lib:format(\n      \"unexpected ( after alias ~ts. Function names and identifiers in Elixir \"\n      \"start with lowercase characters or underscore. For example:\\n\\n\"\n      \"    hello_world()\\n\"\n      \"    _starting_with_underscore()\\n\"\n      \"    numb3rs_are_allowed()\\n\"\n      \"    may_finish_with_question_mark?()\\n\"\n      \"    may_finish_with_exclamation_mark!()\\n\\n\"\n      \"Unexpected token: \",\n      [Alias]\n    ),\n\n  error({?LOC(Line, Column), Reason, [\"(\"]}, atom_to_list(Alias) ++ [$( | Rest], Scope, Tokens);\nhandle_terminator(Rest, Line, Column, #elixir_tokenizer{terminators=none} = Scope, Token, Tokens) ->\n  tokenize(Rest, Line, Column, Scope, [Token | Tokens]);\nhandle_terminator(Rest, Line, Column, Scope, Token, Tokens) ->\n  #elixir_tokenizer{terminators=Terminators} = Scope,\n\n  case check_terminator(Token, Terminators, Scope) of\n    {error, Reason} ->\n      error(Reason, atom_to_list(element(1, Token)) ++ Rest, Scope, Tokens);\n    {ok, New} ->\n      tokenize(Rest, Line, Column, New, [Token | Tokens])\n  end.\n\ncheck_terminator({Start, Meta}, Terminators, Scope)\n    when Start == '('; Start == '['; Start == '{'; Start == '<<' ->\n  Indentation = Scope#elixir_tokenizer.indentation,\n  {ok, Scope#elixir_tokenizer{terminators=[{Start, Meta, Indentation} | Terminators]}};\n\ncheck_terminator({Start, Meta}, Terminators, Scope) when Start == 'fn'; Start == 'do' ->\n  Indentation = Scope#elixir_tokenizer.indentation,\n\n  NewScope =\n    case Terminators of\n      %% If the do is indented equally or less than the previous do, it may be a missing end error!\n      [{Start, _, PreviousIndentation} = Previous | _] when Indentation =< PreviousIndentation ->\n        Scope#elixir_tokenizer{mismatch_hints=[Previous | Scope#elixir_tokenizer.mismatch_hints]};\n\n      _ ->\n        Scope\n    end,\n\n  {ok, NewScope#elixir_tokenizer{terminators=[{Start, Meta, Indentation} | Terminators]}};\n\ncheck_terminator({'end', {EndLine, _, _}}, [{'do', _, Indentation} | Terminators], Scope) ->\n  NewScope =\n    %% If the end is more indented than the do, it may be a missing do error!\n    case Scope#elixir_tokenizer.indentation > Indentation of\n      true ->\n        Hint = {'end', EndLine, Scope#elixir_tokenizer.indentation},\n        Scope#elixir_tokenizer{mismatch_hints=[Hint | Scope#elixir_tokenizer.mismatch_hints]};\n\n      false ->\n        Scope\n    end,\n\n  {ok, NewScope#elixir_tokenizer{terminators=Terminators}};\n\ncheck_terminator({End, {EndLine, EndColumn, _}}, [{Start, {StartLine, StartColumn, _}, _} | Terminators], Scope)\n    when End == 'end'; End == ')'; End == ']'; End == '}'; End == '>>' ->\n  case terminator(Start) of\n    End ->\n      {ok, Scope#elixir_tokenizer{terminators=Terminators}};\n\n    ExpectedEnd ->\n      Meta = [\n        {line, StartLine},\n        {column, StartColumn},\n        {end_line, EndLine},\n        {end_column, EndColumn},\n        {error_type, mismatched_delimiter},\n        {opening_delimiter, Start},\n        {closing_delimiter, End},\n        {expected_delimiter, ExpectedEnd}\n     ],\n     {error, {Meta, unexpected_token_or_reserved(End), [atom_to_list(End)]}}\n  end;\n\ncheck_terminator({'end', {Line, Column, _}}, [], #elixir_tokenizer{mismatch_hints=Hints}) ->\n  Suffix =\n    case lists:keyfind('end', 1, Hints) of\n      {'end', HintLine, _Indentation} ->\n        io_lib:format(\"\\n~ts the \\\"end\\\" on line ~B may not have a matching \\\"do\\\" \"\n                      \"defined before it (based on indentation)\", [elixir_errors:prefix(hint), HintLine]);\n      false ->\n        \"\"\n    end,\n\n  {error, {?LOC(Line, Column), {\"unexpected reserved word: \", Suffix}, \"end\"}};\n\ncheck_terminator({End, {Line, Column, _}}, [], _Scope)\n    when End == ')'; End == ']'; End == '}'; End == '>>' ->\n  {error, {?LOC(Line, Column), \"unexpected token: \", atom_to_list(End)}};\n\ncheck_terminator(_, _, Scope) ->\n  {ok, Scope}.\n\nunexpected_token_or_reserved('end') -> \"unexpected reserved word: \";\nunexpected_token_or_reserved(_) -> \"unexpected token: \".\n\nmissing_terminator_hint(Start, End, #elixir_tokenizer{mismatch_hints=Hints}) ->\n  case lists:keyfind(Start, 1, Hints) of\n    {Start, {HintLine, _, _}, _} ->\n      io_lib:format(\"\\n~ts it looks like the \\\"~ts\\\" on line ~B does not have a matching \\\"~ts\\\"\",\n                    [elixir_errors:prefix(hint), Start, HintLine, End]);\n    false ->\n      \"\"\n  end.\n\nstring_type($\") -> bin_string;\nstring_type($') -> list_string.\n\nheredoc_type($\") -> bin_heredoc;\nheredoc_type($') -> list_heredoc.\n\nsigil_terminator($() -> $);\nsigil_terminator($[) -> $];\nsigil_terminator(${) -> $};\nsigil_terminator($<) -> $>;\nsigil_terminator(O) -> O.\n\nterminator('fn') -> 'end';\nterminator('do') -> 'end';\nterminator('(')  -> ')';\nterminator('[')  -> ']';\nterminator('{')  -> '}';\nterminator('<<') -> '>>'.\n\n%% Keywords checking\n\nkeyword_or_unsafe_to_atom(true, \"fn\", _Line, _Column, _Scope) -> {keyword, 'fn', terminator};\nkeyword_or_unsafe_to_atom(true, \"do\", _Line, _Column, _Scope) -> {keyword, 'do', terminator};\nkeyword_or_unsafe_to_atom(true, \"end\", _Line, _Column, _Scope) -> {keyword, 'end', terminator};\nkeyword_or_unsafe_to_atom(true, \"true\", _Line, _Column, _Scope) -> {keyword, 'true', token};\nkeyword_or_unsafe_to_atom(true, \"false\", _Line, _Column, _Scope) -> {keyword, 'false', token};\nkeyword_or_unsafe_to_atom(true, \"nil\", _Line, _Column, _Scope) -> {keyword, 'nil', token};\n\nkeyword_or_unsafe_to_atom(true, \"not\", _Line, _Column, _Scope) -> {keyword, 'not', unary_op};\nkeyword_or_unsafe_to_atom(true, \"and\", _Line, _Column, _Scope) -> {keyword, 'and', and_op};\nkeyword_or_unsafe_to_atom(true, \"or\", _Line, _Column, _Scope) -> {keyword, 'or', or_op};\nkeyword_or_unsafe_to_atom(true, \"when\", _Line, _Column, _Scope) -> {keyword, 'when', when_op};\nkeyword_or_unsafe_to_atom(true, \"in\", _Line, _Column, _Scope) -> {keyword, 'in', in_op};\n\nkeyword_or_unsafe_to_atom(true, \"after\", _Line, _Column, _Scope) -> {keyword, 'after', block};\nkeyword_or_unsafe_to_atom(true, \"else\", _Line, _Column, _Scope) -> {keyword, 'else', block};\nkeyword_or_unsafe_to_atom(true, \"catch\", _Line, _Column, _Scope) -> {keyword, 'catch', block};\nkeyword_or_unsafe_to_atom(true, \"rescue\", _Line, _Column, _Scope) -> {keyword, 'rescue', block};\n\nkeyword_or_unsafe_to_atom(_, Part, Line, Column, Scope) ->\n  unsafe_to_atom(Part, Line, Column, Scope).\n\ntokenize_keyword(terminator, Rest, Line, Column, Atom, Length, Scope, Tokens) ->\n  case tokenize_keyword_terminator(Line, Column, Atom, Tokens) of\n    {ok, [Check | T]} ->\n      handle_terminator(Rest, Line, Column + Length, Scope, Check, T);\n    {error, Message, Token} ->\n      error({?LOC(Line, Column), Message, Token}, Token ++ Rest, Scope, Tokens)\n  end;\n\ntokenize_keyword(token, Rest, Line, Column, Atom, Length, Scope, Tokens) ->\n  Token = {Atom, {Line, Column, nil}},\n  tokenize(Rest, Line, Column + Length, Scope, [Token | Tokens]);\n\ntokenize_keyword(block, Rest, Line, Column, Atom, Length, Scope, Tokens) ->\n  Token = {block_identifier, {Line, Column, nil}, Atom},\n  tokenize(Rest, Line, Column + Length, Scope, [Token | Tokens]);\n\ntokenize_keyword(Kind, Rest, Line, Column, Atom, Length, Scope, Tokens) ->\n  NewTokens =\n    case strip_horizontal_space(Rest, Line, Column, Scope) of\n      {[$/ | _], _, _} ->\n        [{identifier, {Line, Column, nil}, Atom} | Tokens];\n\n      _ ->\n        Info = {Line, Column, previous_was_eol(Tokens)},\n\n        case {Kind, Tokens} of\n          {in_op, [{unary_op, NotInfo, 'not'} | T]} ->\n            add_token_with_eol({in_op, NotInfo, 'not in', Info}, T);\n\n          {_, _} ->\n            add_token_with_eol({Kind, Info, Atom}, Tokens)\n        end\n    end,\n\n  tokenize(Rest, Line, Column + Length, Scope, NewTokens).\n\ntokenize_sigil([$~ | T], Line, Column, Scope, Tokens) ->\n  case tokenize_sigil_name(T, [], Line, Column + 1, Scope, Tokens) of\n    {ok, Name, Rest, NewLine, NewColumn, NewScope, NewTokens} ->\n      tokenize_sigil_contents(Rest, Name, NewLine, NewColumn, NewScope, NewTokens);\n\n    {error, Message, Token} ->\n      Reason = {?LOC(Line, Column), Message, Token},\n      error(Reason, T, Scope, Tokens)\n  end.\n\n% A one-letter sigil is ok both as upcase as well as downcase.\ntokenize_sigil_name([S | T], [], Line, Column, Scope, Tokens) when ?is_downcase(S) ->\n  tokenize_lower_sigil_name(T, [S], Line, Column + 1, Scope, Tokens);\ntokenize_sigil_name([S | T], [], Line, Column, Scope, Tokens) when ?is_upcase(S) ->\n    tokenize_upper_sigil_name(T, [S], Line, Column + 1, Scope, Tokens).\n\ntokenize_lower_sigil_name([S | _T] = Original, [_ | _] = NameAcc, _Line, _Column, _Scope, _Tokens) when ?is_downcase(S) ->\n  SigilName = lists:reverse(NameAcc) ++ Original,\n  {error, sigil_name_error(), [$~] ++ SigilName};\ntokenize_lower_sigil_name(T, NameAcc, Line, Column, Scope, Tokens) ->\n  {ok, lists:reverse(NameAcc), T, Line, Column, Scope, Tokens}.\n\n% If we have an uppercase letter, we keep tokenizing the name.\n% A digit is allowed but an uppercase letter or digit must proceed it.\ntokenize_upper_sigil_name([S | T], NameAcc, Line, Column, Scope, Tokens) when ?is_upcase(S); ?is_digit(S) ->\n  tokenize_upper_sigil_name(T, [S | NameAcc], Line, Column + 1, Scope, Tokens);\n% With a lowercase letter and a non-empty NameAcc we return an error.\ntokenize_upper_sigil_name([S | _T] = Original, [_ | _] = NameAcc, _Line, _Column, _Scope, _Tokens) when ?is_downcase(S) ->\n  SigilName = lists:reverse(NameAcc) ++ Original,\n  {error,  sigil_name_error(), [$~] ++ SigilName};\n% We finished the letters, so the name is over.\ntokenize_upper_sigil_name(T, NameAcc, Line, Column, Scope, Tokens) ->\n  {ok, lists:reverse(NameAcc), T, Line, Column, Scope, Tokens}.\n\nsigil_name_error() ->\n  \"invalid sigil name, it should be either a one-letter lowercase letter or an \" ++\n  \"uppercase letter optionally followed by uppercase letters and digits, got: \".\n\ntokenize_sigil_contents([H, H, H | T] = Original, [S | _] = SigilName, Line, Column, Scope, Tokens)\n    when ?is_quote(H) ->\n  case extract_heredoc_with_interpolation(Line, Column, Scope, ?is_downcase(S), T, H) of\n    {ok, NewLine, NewColumn, Parts, Rest, Done, NewScope} ->\n      Indentation = NewColumn - 4,\n      add_sigil_token(SigilName, Line, Column, NewLine, NewColumn, Parts, Rest, Done, NewScope, Tokens, Indentation, <<H, H, H>>);\n\n    {error, Reason} ->\n      error(Reason, [$~] ++ SigilName ++ Original, Scope, Tokens)\n  end;\n\ntokenize_sigil_contents([H | T] = Original, [S | _] = SigilName, Line, Column, Scope, Tokens)\n    when ?is_sigil(H) ->\n  case elixir_interpolation:extract(Line, Column + 1, Scope, ?is_downcase(S), T, sigil_terminator(H)) of\n    {NewLine, NewColumn, Parts, Rest, Done, NewScope} ->\n      Indentation = nil,\n      add_sigil_token(SigilName, Line, Column, NewLine, NewColumn,\n                      tokens_to_binary(Parts), Rest, Done, NewScope, Tokens, Indentation, <<H>>);\n\n    {error, Reason} ->\n      Sigil = [$~, S, H],\n      Message = \" (for sigil ~ts starting at line ~B)\",\n      interpolation_error(Reason, [$~] ++ SigilName ++ Original, Scope, Tokens, Message, [Sigil, Line], Line, Column, [H], [sigil_terminator(H)])\n  end;\n\ntokenize_sigil_contents([H | _] = Original, SigilName, Line, Column, Scope, Tokens) ->\n  MessageString =\n    \"\\\"~ts\\\" (column ~p, code point U+~4.16.0B). The available delimiters are: \"\n    \"//, ||, \\\"\\\", '', (), [], {}, <>\",\n  Message = io_lib:format(MessageString, [[H], Column, H]),\n  ErrorColumn = Column - 1 - length(SigilName),\n  error({?LOC(Line, ErrorColumn), \"invalid sigil delimiter: \", Message}, [$~] ++ SigilName ++ Original, Scope, Tokens);\n\n% Incomplete sigil.\ntokenize_sigil_contents([], _SigilName, Line, Column, Scope, Tokens) ->\n  tokenize([], Line, Column, Scope, Tokens).\n\nadd_sigil_token(SigilName, Line, Column, NewLine, NewColumn, Parts, Rest, Done, Scope, Tokens, Indentation, Delimiter) ->\n  TokenColumn = Column - 1 - length(SigilName),\n  MaybeEncoded = case SigilName of\n    % Single-letter sigils present no risk of atom exhaustion (limited possibilities)\n    [_Char] -> {ok, list_to_atom(\"sigil_\" ++ SigilName)};\n    _ -> unsafe_to_atom(\"sigil_\" ++ SigilName, Line, TokenColumn, Scope)\n  end,\n  case MaybeEncoded of\n    {ok, Atom} ->\n      {Final, NewColumnWithModifiers, Modifiers} = case Done of\n        true -> collect_modifiers(Rest, NewColumn, []);\n        false -> {Rest, NewColumn, false}\n      end,\n      Token = {sigil, {Line, TokenColumn, {NewLine, NewColumnWithModifiers}},\n               Atom, Parts, Modifiers, Indentation, Delimiter},\n      tokenize(Final, NewLine, NewColumnWithModifiers, Scope, [Token | Tokens]);\n\n    {error, Reason} ->\n      error(Reason, Rest, Scope, Tokens)\n  end.\n\n%% Fail early on invalid do syntax. For example, after\n%% most keywords, after comma and so on.\ntokenize_keyword_terminator(DoLine, DoColumn, do, [{identifier, {Line, Column, Meta}, Atom} | T]) ->\n  {ok, add_token_with_eol({do, {DoLine, DoColumn, nil}},\n                          [{do_identifier, {Line, Column, Meta}, Atom} | T])};\ntokenize_keyword_terminator(_Line, _Column, do, [{'fn', _} | _]) ->\n  {error, invalid_do_with_fn_error(\"unexpected reserved word: \"), \"do\"};\ntokenize_keyword_terminator(Line, Column, do, Tokens) ->\n  case is_valid_do(Tokens) of\n    true  -> {ok, add_token_with_eol({do, {Line, Column, nil}}, Tokens)};\n    false -> {error, invalid_do_error(\"unexpected reserved word: \"), \"do\"}\n  end;\ntokenize_keyword_terminator(Line, Column, Atom, Tokens) ->\n  {ok, [{Atom, {Line, Column, nil}} | Tokens]}.\n\nis_valid_do([{Atom, _} | _]) ->\n  case Atom of\n    ','      -> false;\n    ';'      -> false;\n    'not'    -> false;\n    'and'    -> false;\n    'or'     -> false;\n    'when'   -> false;\n    'in'     -> false;\n    'after'  -> false;\n    'else'   -> false;\n    'catch'  -> false;\n    'rescue' -> false;\n    _        -> true\n  end;\nis_valid_do(_) ->\n  true.\n\ninvalid_character_error(What, Char) ->\n  io_lib:format(\"invalid character \\\"~ts\\\" (code point U+~4.16.0B) in ~ts: \", [[Char], Char, What]).\n\ninvalid_do_error(Prefix) ->\n  {Prefix, \". In case you wanted to write a \\\"do\\\" expression, \"\n  \"you must either use do-blocks or separate the keyword argument with comma. \"\n  \"For example, you should either write:\\n\\n\"\n  \"    if some_condition? do\\n\"\n  \"      :this\\n\"\n  \"    else\\n\"\n  \"      :that\\n\"\n  \"    end\\n\\n\"\n  \"or the equivalent construct:\\n\\n\"\n  \"    if(some_condition?, do: :this, else: :that)\\n\\n\"\n  \"where \\\"some_condition?\\\" is the first argument and the second argument is a keyword list.\\n\\n\"\n  \"You may see this error if you forget a trailing comma before the \\\"do\\\" in a \\\"do\\\" block\"}.\n\ninvalid_do_with_fn_error(Prefix) ->\n  {Prefix, \". Anonymous functions are written as:\\n\\n\"\n  \"    fn pattern -> expression end\\n\\nPlease remove the \\\"do\\\" keyword\"}.\n\n% TODO: Turn into an error on v2.0\nmaybe_warn_too_many_of_same_char([T | _] = Token, [T | _] = _Rest, Line, Column, Scope) ->\n  Message = io_lib:format(\n    \"found \\\"~ts\\\" followed by \\\"~ts\\\", please use a space between \\\"~ts\\\" and the next \\\"~ts\\\"\",\n    [Token, [T], Token, [T]]\n  ),\n  prepend_warning(Line, Column, Message, Scope);\nmaybe_warn_too_many_of_same_char(_Token, _Rest, _Line, _Column, Scope) ->\n  Scope.\n\n%% TODO: Turn into an error on v2.0\nmaybe_warn_for_ambiguous_bang_before_equals(Kind, Unencoded, [$= | _], Line, Column, Scope) ->\n  {What, Identifier} =\n    case Kind of\n      atom -> {\"atom\", [$: | Unencoded]};\n      identifier -> {\"identifier\", Unencoded}\n    end,\n\n  case lists:last(Identifier) of\n    Last when Last =:= $!; Last =:= $? ->\n      Msg = io_lib:format(\"found ~ts \\\"~ts\\\", ending with \\\"~ts\\\", followed by =. \"\n                          \"It is unclear if you mean \\\"~ts ~ts=\\\" or \\\"~ts =\\\". Please add \"\n                          \"a space before or after ~ts to remove the ambiguity\",\n                          [What, Identifier, [Last], lists:droplast(Identifier), [Last], Identifier, [Last]]),\n      prepend_warning(Line, Column, Msg, Scope);\n    _ ->\n      Scope\n  end;\nmaybe_warn_for_ambiguous_bang_before_equals(_Kind, _Atom, _Rest, _Line, _Column, Scope) ->\n  Scope.\n\nprepend_warning(Line, Column, Msg, #elixir_tokenizer{warnings=Warnings} = Scope) ->\n  Scope#elixir_tokenizer{warnings = [{{Line, Column}, Msg} | Warnings]}.\n\ntrack_ascii(true, Scope) -> Scope;\ntrack_ascii(false, Scope) -> Scope#elixir_tokenizer{ascii_identifiers_only=false}.\n\nmaybe_unicode_lint_warnings(_Ascii=false, Tokens, Warnings) ->\n  'Elixir.String.Tokenizer.Security':unicode_lint_warnings(lists:reverse(Tokens)) ++ Warnings;\nmaybe_unicode_lint_warnings(_Ascii=true, _Tokens, Warnings) ->\n  Warnings.\n\nerror(Reason, Rest, #elixir_tokenizer{warnings=Warnings}, Tokens) ->\n  {error, Reason, Rest, Warnings, Tokens}.\n\nformat_error({Location, {ErrorPrefix, ErrorSuffix}, Token}) ->\n  {Location, {elixir_utils:characters_to_binary(ErrorPrefix), elixir_utils:characters_to_binary(ErrorSuffix)}, elixir_utils:characters_to_binary(Token)};\nformat_error({Location, Error, Token}) ->\n  {Location, elixir_utils:characters_to_binary(Error), elixir_utils:characters_to_binary(Token)}.\n\n%% Cursor handling\n\nadd_cursor(_Line, Column, noprune, Tokens) ->\n  {Column, Tokens};\n\nadd_cursor(Line, Column, {prune_and_cursor, true},\n           [{sigil, {_, _, {Line, Column}} = Location, Name, Parts, Modifier, Identation, Delimiter} | Rest]) ->\n  Cursor = {'__cursor__', [{line, Line}, {column, Column}], []},\n  CursorModifier = case Modifier of\n    false -> Cursor;\n    List -> List ++ [Cursor]\n  end,\n  {Column + 12, [{sigil, Location, Name, Parts, CursorModifier, Identation, Delimiter} | Rest]};\n\nadd_cursor(Line, Column, {prune_and_cursor, _}, Tokens) ->\n  PrePrunedTokens = prune_identifier(Tokens),\n  PrunedTokens = prune_tokens(PrePrunedTokens, []),\n  CursorTokens = [\n    {')', {Line, Column + 11, nil}},\n    {'(', {Line, Column + 10, nil}},\n    {paren_identifier, {Line, Column, nil}, '__cursor__'}\n    | PrunedTokens\n  ],\n  {Column + 12, CursorTokens}.\n\nprune_identifier([{identifier, _, _} | Tokens]) -> Tokens;\nprune_identifier(Tokens) -> Tokens.\n\n%%% Any terminator needs to be closed\nprune_tokens([{'end', _} | Tokens], Opener) ->\n  prune_tokens(Tokens, ['end' | Opener]);\nprune_tokens([{')', _} | Tokens], Opener) ->\n  prune_tokens(Tokens, [')' | Opener]);\nprune_tokens([{']', _} | Tokens], Opener) ->\n  prune_tokens(Tokens, [']' | Opener]);\nprune_tokens([{'}', _} | Tokens], Opener) ->\n  prune_tokens(Tokens, ['}' | Opener]);\nprune_tokens([{'>>', _} | Tokens], Opener) ->\n  prune_tokens(Tokens, ['>>' | Opener]);\n%%% Close opened terminators\nprune_tokens([{'fn', _} | Tokens], ['end' | Opener]) ->\n  prune_tokens(Tokens, Opener);\nprune_tokens([{'do', _} | Tokens], ['end' | Opener]) ->\n  prune_tokens(Tokens, Opener);\nprune_tokens([{'(', _} | Tokens], [')' | Opener]) ->\n  prune_tokens(Tokens, Opener);\nprune_tokens([{'[', _} | Tokens], [']' | Opener]) ->\n  prune_tokens(Tokens, Opener);\nprune_tokens([{'{', _} | Tokens], ['}' | Opener]) ->\n  prune_tokens(Tokens, Opener);\nprune_tokens([{'<<', _} | Tokens], ['>>' | Opener]) ->\n  prune_tokens(Tokens, Opener);\n%%% or it is time to stop...\nprune_tokens([{';', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{'eol', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{',', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{'fn', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{'do', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{'(', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{'[', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{'{', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{'<<', _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{identifier, _, _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{block_identifier, _, _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{kw_identifier, _, _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{kw_identifier_safe, _, _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{kw_identifier_unsafe, _, _} | _] = Tokens, []) ->\n  Tokens;\nprune_tokens([{OpType, _, _} | _] = Tokens, [])\n  when OpType =:= comp_op; OpType =:= at_op; OpType =:= unary_op; OpType =:= and_op;\n       OpType =:= or_op; OpType =:= arrow_op; OpType =:= match_op; OpType =:= in_op;\n       OpType =:= in_match_op; OpType =:= type_op; OpType =:= dual_op; OpType =:= mult_op;\n       OpType =:= power_op; OpType =:= concat_op; OpType =:= range_op; OpType =:= xor_op;\n       OpType =:= pipe_op; OpType =:= stab_op; OpType =:= when_op; OpType =:= assoc_op;\n       OpType =:= rel_op; OpType =:= ternary_op; OpType =:= capture_op; OpType =:= ellipsis_op ->\n  Tokens;\n%%% or we traverse until the end.\nprune_tokens([_ | Tokens], Opener) ->\n  prune_tokens(Tokens, Opener);\nprune_tokens([], _Opener) ->\n  [].\n"
  },
  {
    "path": "lib/elixir/src/elixir_tokenizer.hrl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n\n%% Numbers\n-define(is_hex(S), (?is_digit(S) orelse (S >= $A andalso S =< $F) orelse (S >= $a andalso S =< $f))).\n-define(is_bin(S), (S >= $0 andalso S =< $1)).\n-define(is_octal(S), (S >= $0 andalso S =< $7)).\n\n%% Digits and letters\n-define(is_digit(S), (S >= $0 andalso S =< $9)).\n-define(is_upcase(S), (S >= $A andalso S =< $Z)).\n-define(is_downcase(S), (S >= $a andalso S =< $z)).\n\n%% Others\n-define(is_quote(S), (S =:= $\" orelse S =:= $')).\n-define(is_sigil(S), (S =:= $/ orelse S =:= $< orelse S =:= $\" orelse S =:= $' orelse\n                      S =:= $[ orelse S =:= $( orelse S =:= ${ orelse S =:= $|)).\n-define(LOC(Line, Column), [{line, Line}, {column, Column}]).\n\n%% Spaces\n-define(is_horizontal_space(S), (S =:= $\\s orelse S =:= $\\t)).\n-define(is_vertical_space(S), (S =:= $\\r orelse S =:= $\\n)).\n-define(is_space(S), (?is_horizontal_space(S) orelse ?is_vertical_space(S))).\n\n%% Bidirectional control\n%% Retrieved from https://trojansource.codes/trojan-source.pdf\n-define(bidi(C), C =:= 16#202A;\n                 C =:= 16#202B;\n                 C =:= 16#202D;\n                 C =:= 16#202E;\n                 C =:= 16#2066;\n                 C =:= 16#2067;\n                 C =:= 16#2068;\n                 C =:= 16#202C;\n                 C =:= 16#2069).\n\n%% Unsupported newlines\n%% https://www.unicode.org/reports/tr55/\n-define(break(C), C =:= 16#000B;\n                  C =:= 16#000C;\n                  C =:= 16#0085;\n                  C =:= 16#2028;\n                  C =:= 16#2029)."
  },
  {
    "path": "lib/elixir/src/elixir_utils.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n%% Convenience functions used throughout elixir source code\n%% for ast manipulation and querying.\n-module(elixir_utils).\n-export([get_line/1, get_line/2, get_file/2, generated/1,\n  split_last/1, split_opts/1, noop/0, var_context/2,\n  characters_to_list/1, characters_to_binary/1, relative_to_cwd/1,\n  macro_name/1, returns_boolean/1, caller/4, meta_keep/1,\n  read_file_type/1, read_file_type/2, read_link_type/1, read_posix_mtime_and_size/1,\n  change_posix_time/2, change_universal_time/2, var_info/2,\n  guard_op/2, guard_info/1, extract_splat_guards/1, extract_guards/1,\n  erlang_comparison_op_to_elixir/1, erl_fa_to_elixir_fa/2]).\n-include(\"elixir.hrl\").\n-include_lib(\"kernel/include/file.hrl\").\n\nvar_info(Name, Kind) when Kind == nil; is_integer(Kind) ->\n  io_lib:format(\"\\\"~ts\\\"\", [Name]);\nvar_info(Name, Kind) ->\n  io_lib:format(\"\\\"~ts\\\" (context ~ts)\", [Name, elixir_aliases:inspect(Kind)]).\n\nguard_info(#elixir_ex{prematch={_, _, {bitsize, _}}}) -> \"bitstring size specifier\";\nguard_info(_) -> \"guard\".\n\nmacro_name(Macro) ->\n  list_to_atom(\"MACRO-\" ++ atom_to_list(Macro)).\n\nerl_fa_to_elixir_fa(Name, Arity) ->\n  case atom_to_list(Name) of\n    \"MACRO-\" ++ Rest -> {list_to_atom(Rest), Arity - 1};\n    _ -> {Name, Arity}\n  end.\n\nguard_op('andalso', 2) ->\n  true;\nguard_op('orelse', 2) ->\n  true;\nguard_op(Op, Arity) ->\n  try erl_internal:op_type(Op, Arity) of\n    arith -> true;\n    comp  -> true;\n    bool  -> true;\n    list  -> false;\n    send  -> false\n  catch\n    _:_ -> false\n  end.\n\nerlang_comparison_op_to_elixir('/=') -> '!=';\nerlang_comparison_op_to_elixir('=<') -> '<=';\nerlang_comparison_op_to_elixir('=:=') -> '===';\nerlang_comparison_op_to_elixir('=/=') -> '!==';\nerlang_comparison_op_to_elixir(Other) -> Other.\n\nvar_context(Meta, Kind) ->\n  case lists:keyfind(counter, 1, Meta) of\n    {counter, Counter} -> Counter;\n    false -> Kind\n  end.\n\n% Extract guards\n\nextract_guards({'when', _, [Left, Right]}) -> {Left, extract_or_guards(Right)};\nextract_guards(Else) -> {Else, []}.\n\nextract_or_guards({'when', _, [Left, Right]}) -> [Left | extract_or_guards(Right)];\nextract_or_guards(Term) -> [Term].\n\n% Extract guards when multiple left side args are allowed.\n\nextract_splat_guards([{'when', _, [_ | _] = Args}]) ->\n  {Left, Right} = split_last(Args),\n  {Left, extract_or_guards(Right)};\nextract_splat_guards(Else) ->\n  {Else, []}.\n\n%% No-op function that can be used for stuff like preventing tail-call\n%% optimization to kick in.\nnoop() ->\n  ok.\n\nsplit_last([])           -> {[], []};\nsplit_last(List)         -> split_last(List, []).\nsplit_last([H], Acc)     -> {lists:reverse(Acc), H};\nsplit_last([H | T], Acc) -> split_last(T, [H | Acc]).\n\n%% Useful to handle options similarly in `opts, do ... end` and `opts, do: ...`.\nsplit_opts(Args) ->\n  case elixir_utils:split_last(Args) of\n    {OuterCases, OuterOpts} when is_list(OuterOpts) ->\n      case elixir_utils:split_last(OuterCases) of\n        {InnerCases, InnerOpts} when is_list(InnerOpts) ->\n          {InnerCases, InnerOpts ++ OuterOpts};\n        _ ->\n          {OuterCases, OuterOpts}\n      end;\n    _ ->\n      {Args, []}\n  end.\n\nread_file_type(File) ->\n  read_file_type(File, []).\n\nread_file_type(File, Opts) ->\n  case file:read_file_info(File, [{time, posix} | Opts]) of\n    {ok, #file_info{type=Type}} -> {ok, Type};\n    {error, _} = Error -> Error\n  end.\n\nread_link_type(File) ->\n  case file:read_link_info(File) of\n    {ok, #file_info{type=Type}} -> {ok, Type};\n    {error, _} = Error -> Error\n  end.\n\nread_posix_mtime_and_size(File) ->\n  case file:read_file_info(File, [raw, {time, posix}]) of\n    {ok, #file_info{mtime=Mtime, size=Size}} -> {ok, Mtime, Size};\n    {error, _} = Error -> Error\n  end.\n\nchange_posix_time(Name, Time) when is_integer(Time) ->\n  file:write_file_info(Name, #file_info{mtime=Time}, [raw, {time, posix}]).\n\nchange_universal_time(Name, {{Y, M, D}, {H, Min, Sec}}=Time)\n    when is_integer(Y), is_integer(M), is_integer(D),\n         is_integer(H), is_integer(Min), is_integer(Sec) ->\n  file:write_file_info(Name, #file_info{mtime=Time}, [raw, {time, universal}]).\n\nrelative_to_cwd(Path) ->\n  try elixir_config:get(relative_paths) of\n    true  -> 'Elixir.Path':relative_to_cwd(Path);\n    false -> Path\n  catch\n    _:_ -> Path\n  end.\n\ncharacters_to_list(Data) when is_list(Data) ->\n  Data;\ncharacters_to_list(Data) ->\n  case unicode:characters_to_list(Data) of\n    Result when is_list(Result) -> Result;\n    {error, Encoded, Rest} -> conversion_error(invalid, Encoded, Rest);\n    {incomplete, Encoded, Rest} -> conversion_error(incomplete, Encoded, Rest)\n  end.\n\ncharacters_to_binary(Data) when is_binary(Data) ->\n  Data;\ncharacters_to_binary(Data) ->\n  case unicode:characters_to_binary(Data) of\n    Result when is_binary(Result) -> Result;\n    {error, Encoded, Rest} -> conversion_error(invalid, Encoded, Rest);\n    {incomplete, Encoded, Rest} -> conversion_error(incomplete, Encoded, Rest)\n  end.\n\nconversion_error(Kind, Encoded, Rest) ->\n  error('Elixir.UnicodeConversionError':exception([{encoded, Encoded}, {rest, Rest}, {kind, Kind}])).\n\n%% Returns the caller as a stacktrace entry.\ncaller(Line, File, nil, _) ->\n  {elixir_compiler_0, '__FILE__', 1, stack_location(Line, File)};\ncaller(Line, File, Module, nil) ->\n  {Module, '__MODULE__', 0, stack_location(Line, File)};\ncaller(Line, File, Module, {Name, Arity}) ->\n  {Module, Name, Arity, stack_location(Line, File)}.\n\nstack_location(Line, File) ->\n  [{file, elixir_utils:characters_to_list(elixir_utils:relative_to_cwd(File))},\n   {line, Line}].\n\nget_line(Opts) when is_list(Opts) ->\n  case lists:keyfind(line, 1, Opts) of\n    {line, Line} when is_integer(Line) -> Line;\n    _ -> 0\n  end.\n\nget_line(Meta, Env) when is_list(Meta) ->\n  case lists:keyfind(line, 1, Meta) of\n    {line, LineOpt} when is_integer(LineOpt) -> LineOpt;\n    false -> ?key(Env, line)\n  end.\n\nget_file(Meta, Env) when is_list(Meta) ->\n  case lists:keyfind(file, 1, Meta) of\n    {file, FileOpt} when is_binary(FileOpt) -> FileOpt;\n    false -> ?key(Env, file)\n  end.\n\ngenerated([{generated, true} | _] = Meta) -> Meta;\ngenerated(Meta) -> [{generated, true} | Meta].\n\n%% Meta location.\n%%\n%% Macros add a file pair on location keep which we\n%% should take into account for error reporting.\n%%\n%% Returns {binary, integer} on location keep or nil.\n\nmeta_keep(Meta) ->\n  case lists:keyfind(keep, 1, Meta) of\n    {keep, {File, Line} = Pair} when is_binary(File), is_integer(Line) ->\n      Pair;\n    _ ->\n      nil\n  end.\n\n%% Boolean checks\n\nreturns_boolean(Bool) when is_boolean(Bool) -> true;\n\nreturns_boolean({{'.', _, [erlang, Op]}, _, [_]}) when Op == 'not' -> true;\n\nreturns_boolean({{'.', _, [erlang, Op]}, _, [_, _]}) when\n  Op == 'and'; Op == 'or'; Op == 'xor';\n  Op == '==';  Op == '/='; Op == '=<';  Op == '>=';\n  Op == '<';   Op == '>';  Op == '=:='; Op == '=/=' -> true;\n\nreturns_boolean({{'.', _, [erlang, Op]}, _, [_, Right]}) when\n  Op == 'andalso'; Op == 'orelse' ->\n  returns_boolean(Right);\n\nreturns_boolean({{'.', _, [erlang, Fun]}, _, [_]}) when\n  Fun == is_atom;   Fun == is_binary;   Fun == is_bitstring; Fun == is_boolean;\n  Fun == is_float;  Fun == is_function; Fun == is_integer;   Fun == is_list;\n  Fun == is_number; Fun == is_pid;      Fun == is_port;      Fun == is_reference;\n  Fun == is_tuple;  Fun == is_map;      Fun == is_process_alive -> true;\n\nreturns_boolean({{'.', _, [erlang, Fun]}, _, [_, _]}) when\n  Fun == is_map_key; Fun == is_function; Fun == is_record -> true;\n\nreturns_boolean({{'.', _, [erlang, Fun]}, _, [_, _, _]}) when\n  Fun == function_exported; Fun == is_record -> true;\n\nreturns_boolean({'case', _, [_, [{do, Clauses}]]}) ->\n  lists:all(fun\n    ({'->', _, [_, Expr]}) -> returns_boolean(Expr)\n  end, Clauses);\n\nreturns_boolean({'cond', _, [[{do, Clauses}]]}) ->\n  lists:all(fun\n    ({'->', _, [_, Expr]}) -> returns_boolean(Expr)\n  end, Clauses);\n\nreturns_boolean({'__block__', _, Exprs}) ->\n  returns_boolean(lists:last(Exprs));\n\nreturns_boolean(_) -> false.\n"
  },
  {
    "path": "lib/elixir/src/iex.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n\n-module(iex).\n-export([start/0, start/2, shell/0, sync_remote/2]).\n\n%% Manual tests for changing the CLI boot.\n%%\n%% 1. In some situations, we cannot read inputs as IEx boots:\n%%\n%%      $ iex -e \":io.get_line(:foo)\"\n%%\n%% 2. In some situations, connecting to a remote node via --remsh\n%%    is not possible. This can be tested by starting two IEx nodes:\n%%\n%%      $ iex --sname foo\n%%      $ iex --sname bar --remsh foo\n%%\n%% 3. When still using --remsh, we need to guarantee the arguments\n%%    are processed on the local node and not the remote one. For such,\n%%    one can replace the last line above by:\n%%\n%%      $ iex --sname bar --remsh foo -e 'IO.inspect node()'\n%%\n%%    And verify that the local node name is printed.\n%%\n%% 4. Finally, in some other circumstances, printing messages may become\n%%    borked. This can be verified with:\n%%\n%%      $ iex -e \":logger.info(~c'foo~nbar', [])\"\n%%\n%% By the time those instructions have been written, all tests above pass.\n\nstart() ->\n  start([], {elixir_utils, noop, []}).\n\nstart(Opts, MFA) ->\n  {ok, _} = application:ensure_all_started(elixir),\n  {ok, _} = application:ensure_all_started(iex),\n\n  spawn(fun() ->\n    case init:notify_when_started(self()) of\n      started -> ok;\n      _ -> init:wait_until_started()\n    end,\n\n    ok = io:setopts([{binary, true}, {encoding, unicode}]),\n    'Elixir.IEx.Server':run_from_shell(Opts, MFA)\n  end).\n\nshell() ->\n  Args = init:get_plain_arguments(),\n\n  case get_remsh(Args) of\n    nil ->\n      start_mfa(Args, {elixir, start_cli, []});\n\n    Remote ->\n      Ref = make_ref(),\n\n      Parent =\n        spawn_link(fun() ->\n          receive\n            {'begin', Ref, Other} ->\n              elixir:start_cli(),\n              Other ! {done, Ref}\n          end\n        end),\n\n      {remote, Remote, start_mfa(Args, {?MODULE, sync_remote, [Parent, Ref]})}\n  end.\n\nsync_remote(Parent, Ref) ->\n  Parent ! {'begin', Ref, self()},\n  receive {done, Ref} -> ok end.\n\nstart_mfa(Args, MFA) ->\n  Opts = [{dot_iex, get_dot_iex(Args)}, {on_eof, halt}],\n  {?MODULE, start, [Opts, MFA]}.\n\nget_dot_iex([\"--dot-iex\", H | _]) -> elixir_utils:characters_to_binary(H);\nget_dot_iex([_ | T]) -> get_dot_iex(T);\nget_dot_iex([]) -> nil.\n\nget_remsh([\"--remsh\", H | _]) -> H;\nget_remsh([_ | T]) -> get_remsh(T);\nget_remsh([]) -> nil.\n"
  },
  {
    "path": "lib/elixir/test/elixir/access_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule AccessTest do\n  use ExUnit.Case, async: true\n\n  doctest Access\n\n  # Test nil at compilation time does not fail\n  # and that @config[:foo] has proper precedence.\n  @config nil\n  nil = @config[:foo]\n\n  @config [foo: :bar]\n  :bar = @config[:foo]\n\n  @mod :lists\n  [1, 2, 3] = @mod.flatten([1, [2], 3])\n\n  @mod -13\n  -13 = @mod\n\n  test \"for nil\" do\n    assert nil[:foo] == nil\n    assert Access.fetch(nil, :foo) == :error\n    assert Access.get(nil, :foo) == nil\n\n    assert_raise ArgumentError, \"could not put/update key :foo on a nil value\", fn ->\n      Access.get_and_update(nil, :foo, fn nil -> {:ok, :bar} end)\n    end\n  end\n\n  test \"for keywords\" do\n    assert [foo: :bar][:foo] == :bar\n    assert [foo: [bar: :baz]][:foo][:bar] == :baz\n    assert [foo: [bar: :baz]][:fuu][:bar] == nil\n\n    assert Access.fetch([foo: :bar], :foo) == {:ok, :bar}\n    assert Access.fetch([foo: :bar], :bar) == :error\n\n    msg = ~r/the Access calls for keywords expect the key to be an atom/\n\n    assert_raise ArgumentError, msg, fn ->\n      Access.fetch([], \"foo\")\n    end\n\n    assert Access.get([foo: :bar], :foo) == :bar\n    assert Access.get_and_update([], :foo, fn nil -> {:ok, :baz} end) == {:ok, [foo: :baz]}\n\n    assert Access.get_and_update([foo: :bar], :foo, fn :bar -> {:ok, :baz} end) ==\n             {:ok, [foo: :baz]}\n\n    assert Access.pop([foo: :bar], :foo) == {:bar, []}\n    assert Access.pop([], :foo) == {nil, []}\n  end\n\n  test \"for maps\" do\n    assert %{foo: :bar}[:foo] == :bar\n    assert %{1 => 1}[1] == 1\n    assert %{1.0 => 1.0}[1.0] == 1.0\n    assert %{1 => 1}[1.0] == nil\n\n    assert Access.fetch(%{foo: :bar}, :foo) == {:ok, :bar}\n    assert Access.fetch(%{foo: :bar}, :bar) == :error\n\n    assert Access.get(%{foo: :bar}, :foo) == :bar\n    assert Access.get_and_update(%{}, :foo, fn nil -> {:ok, :baz} end) == {:ok, %{foo: :baz}}\n\n    assert Access.get_and_update(%{foo: :bar}, :foo, fn :bar -> {:ok, :baz} end) ==\n             {:ok, %{foo: :baz}}\n\n    assert Access.pop(%{foo: :bar}, :foo) == {:bar, %{}}\n    assert Access.pop(%{}, :foo) == {nil, %{}}\n  end\n\n  test \"for struct\" do\n    defmodule Sample do\n      defstruct [:name]\n    end\n\n    message =\n      ~r\"function AccessTest.Sample.fetch/2 is undefined \\(AccessTest.Sample does not implement the Access behaviour\"\n\n    assert_raise UndefinedFunctionError, message, fn ->\n      Access.fetch(struct(Sample, []), :name)\n    end\n\n    message =\n      ~r\"function AccessTest.Sample.get_and_update/3 is undefined \\(AccessTest.Sample does not implement the Access behaviour\"\n\n    assert_raise UndefinedFunctionError, message, fn ->\n      Access.get_and_update(struct(Sample, []), :name, fn nil -> {:ok, :baz} end)\n    end\n\n    message =\n      ~r\"function AccessTest.Sample.pop/2 is undefined \\(AccessTest.Sample does not implement the Access behaviour\"\n\n    assert_raise UndefinedFunctionError, message, fn ->\n      Access.pop(struct(Sample, []), :name)\n    end\n  end\n\n  describe \"fetch!/2\" do\n    assert Access.fetch!(%{foo: :bar}, :foo) == :bar\n\n    assert_raise ArgumentError,\n                 ~r/the Access calls for keywords expect the key to be an atom/,\n                 fn -> Access.fetch!([], \"foo\") end\n\n    assert_raise KeyError,\n                 ~r/key \\\"foo\\\" not found/,\n                 fn -> Access.fetch!(nil, \"foo\") end\n  end\n\n  describe \"filter/1\" do\n    @test_list [1, 2, 3, 4, 5, 6]\n\n    test \"filters in get_in\" do\n      assert get_in(@test_list, [Access.filter(&(&1 > 3))]) == [4, 5, 6]\n    end\n\n    test \"retains order in get_and_update_in\" do\n      assert get_and_update_in(@test_list, [Access.filter(&(&1 == 3 || &1 == 2))], &{&1 * 2, &1}) ==\n               {[4, 6], [1, 2, 3, 4, 5, 6]}\n    end\n\n    test \"retains order in pop_in\" do\n      assert pop_in(@test_list, [Access.filter(&(&1 == 3 || &1 == 2))]) == {[2, 3], [1, 4, 5, 6]}\n    end\n\n    test \"chains with other access functions\" do\n      mixed_map_and_list = %{foo: Enum.map(@test_list, &%{value: &1})}\n\n      assert get_in(mixed_map_and_list, [:foo, Access.filter(&(&1.value <= 3)), :value]) ==\n               [1, 2, 3]\n    end\n  end\n\n  describe \"slice/1\" do\n    @test_list [1, 2, 3, 4, 5, 6, 7]\n\n    test \"retrieves a range from the start of the list\" do\n      assert [2, 3] == get_in(@test_list, [Access.slice(1..2)])\n    end\n\n    test \"retrieves a range from the end of the list\" do\n      assert [6, 7] == get_in(@test_list, [Access.slice(-2..-1)])\n    end\n\n    test \"retrieves a range from positive first and negative last\" do\n      assert [2, 3, 4, 5, 6] == get_in(@test_list, [Access.slice(1..-2//1)])\n    end\n\n    test \"retrieves a range from negative first and positive last\" do\n      assert [6, 7] == get_in(@test_list, [Access.slice(-2..7//1)])\n    end\n\n    test \"retrieves a range with steps\" do\n      assert [1, 3] == get_in(@test_list, [Access.slice(0..2//2)])\n      assert [2, 5] == get_in(@test_list, [Access.slice(1..4//3)])\n      assert [2] == get_in(@test_list, [Access.slice(1..2//3)])\n      assert [1, 3, 5, 7] == get_in(@test_list, [Access.slice(0..6//2)])\n    end\n\n    test \"pops a range from the start of the list\" do\n      assert {[2, 3], [1, 4, 5, 6, 7]} == pop_in(@test_list, [Access.slice(1..2)])\n    end\n\n    test \"pops a range from the end of the list\" do\n      assert {[6, 7], [1, 2, 3, 4, 5]} == pop_in(@test_list, [Access.slice(-2..-1)])\n    end\n\n    test \"pops a range from positive first and negative last\" do\n      assert {[2, 3, 4, 5, 6], [1, 7]} == pop_in(@test_list, [Access.slice(1..-2//1)])\n    end\n\n    test \"pops a range from negative first and positive last\" do\n      assert {[6, 7], [1, 2, 3, 4, 5]} == pop_in(@test_list, [Access.slice(-2..7//1)])\n    end\n\n    test \"pops a range with steps\" do\n      assert {[1, 3, 5], [2, 4, 6, 7]} == pop_in(@test_list, [Access.slice(0..4//2)])\n      assert {[2], [1, 3, 4, 5, 6, 7]} == pop_in(@test_list, [Access.slice(1..2//2)])\n      assert {[1, 4], [1, 2, 5, 6, 7]} == pop_in([1, 2, 1, 4, 5, 6, 7], [Access.slice(2..3)])\n    end\n\n    test \"updates range from the start of the list\" do\n      assert [-1, 2, 3, 4, 5, 6, 7] == update_in(@test_list, [Access.slice(0..0)], &(&1 * -1))\n\n      assert [1, -2, -3, 4, 5, 6, 7] == update_in(@test_list, [Access.slice(1..2)], &(&1 * -1))\n    end\n\n    test \"updates range from the end of the list\" do\n      assert [1, 2, 3, 4, 5, -6, -7] == update_in(@test_list, [Access.slice(-2..-1)], &(&1 * -1))\n\n      assert [-1, -2, 3, 4, 5, 6, 7] == update_in(@test_list, [Access.slice(-7..-6)], &(&1 * -1))\n    end\n\n    test \"updates a range from positive first and negative last\" do\n      assert [1, -2, -3, -4, -5, -6, 7] ==\n               update_in(@test_list, [Access.slice(1..-2//1)], &(&1 * -1))\n    end\n\n    test \"updates a range from negative first and positive last\" do\n      assert [1, 2, 3, 4, 5, -6, -7] ==\n               update_in(@test_list, [Access.slice(-2..7//1)], &(&1 * -1))\n    end\n\n    test \"updates a range with steps\" do\n      assert [-1, 2, -3, 4, -5, 6, 7] ==\n               update_in(@test_list, [Access.slice(0..4//2)], &(&1 * -1))\n    end\n\n    test \"returns empty when the start of the range is greater than the end\" do\n      assert [] == get_in(@test_list, [Access.slice(2..1//1)])\n    end\n  end\n\n  describe \"at/1\" do\n    @test_list [1, 2, 3, 4, 5, 6]\n\n    test \"returns element from the end if index is negative\" do\n      assert get_in(@test_list, [Access.at(-2)]) == 5\n    end\n\n    test \"returns nil if index is out of bounds counting from the end\" do\n      assert get_in(@test_list, [Access.at(-10)]) == nil\n    end\n\n    test \"updates the element counting from the end if index is negative\" do\n      assert get_and_update_in(@test_list, [Access.at(-2)], fn prev ->\n               {prev, :foo}\n             end) == {5, [1, 2, 3, 4, :foo, 6]}\n    end\n\n    test \"returns nil and does not update if index is out of bounds\" do\n      assert get_and_update_in(@test_list, [Access.at(-10)], fn prev ->\n               {prev, :foo}\n             end) == {nil, [1, 2, 3, 4, 5, 6]}\n    end\n  end\n\n  describe \"at!/1\" do\n    @test_list [1, 2, 3, 4, 5, 6]\n\n    test \"returns a list element when the index is within bounds, with get_in\" do\n      assert get_in(@test_list, [Access.at!(5)]) == 6\n      assert get_in(@test_list, [Access.at!(-6)]) == 1\n    end\n\n    test \"updates a list element when the index is within bounds, with get_and_update_in\" do\n      assert get_and_update_in(@test_list, [Access.at!(5)], fn prev ->\n               {prev, :foo}\n             end) == {6, [1, 2, 3, 4, 5, :foo]}\n\n      assert get_and_update_in(@test_list, [Access.at!(-6)], fn prev ->\n               {prev, :foo}\n             end) == {1, [:foo, 2, 3, 4, 5, 6]}\n    end\n\n    test \"raises OutOfBoundsError when out of bounds, with get_in\" do\n      assert_raise Enum.OutOfBoundsError, fn ->\n        get_in(@test_list, [Access.at!(6)])\n      end\n\n      assert_raise Enum.OutOfBoundsError, fn ->\n        get_in(@test_list, [Access.at!(-7)])\n      end\n    end\n\n    test \"raises OutOfBoundsError when out of bounds, with get_and_update_in\" do\n      assert_raise Enum.OutOfBoundsError, fn ->\n        get_and_update_in(@test_list, [Access.at!(6)], fn prev -> {prev, :foo} end)\n      end\n\n      assert_raise Enum.OutOfBoundsError, fn ->\n        get_and_update_in(@test_list, [Access.at!(-7)], fn prev -> {prev, :foo} end)\n      end\n    end\n\n    test \"raises when not given a list\" do\n      assert_raise RuntimeError, \"Access.at!/1 expected a list, got: %{}\", fn ->\n        get_in(%{}, [Access.at!(0)])\n      end\n    end\n\n    test \"chains\" do\n      input = %{list: [%{greeting: \"hi\"}]}\n      assert get_in(input, [:list, Access.at!(0), :greeting]) == \"hi\"\n    end\n  end\n\n  describe \"values/0\" do\n    @test_map %{a: 1, b: 2, c: 3, d: 4}\n    @test_list [a: 1, b: 2, c: 3, d: 4]\n\n    test \"retrieves values in a map\" do\n      assert [1, 2, 3, 4] = get_in(@test_map, [Access.values()]) |> Enum.sort()\n    end\n\n    test \"retrieves values in a keyword list\" do\n      assert [1, 2, 3, 4] = get_in(@test_list, [Access.values()])\n    end\n\n    test \"gets and updates values in a map\" do\n      assert {gets, %{a: 3, b: 4, c: 5, d: 6}} =\n               get_and_update_in(@test_map, [Access.values()], fn n -> {n + 1, n + 2} end)\n\n      assert [2, 3, 4, 5] = Enum.sort(gets)\n    end\n\n    test \"gets and updates values in a keyword list\" do\n      assert {[2, 3, 4, 5], [a: 3, b: 4, c: 5, d: 6]} =\n               get_and_update_in(@test_list, [Access.values()], fn n -> {n + 1, n + 2} end)\n    end\n\n    test \"pops values from a map\" do\n      assert {gets, %{c: 4, d: 5}} =\n               get_and_update_in(@test_map, [Access.values()], fn n ->\n                 if(n > 2, do: {-n, n + 1}, else: :pop)\n               end)\n\n      assert [-4, -3, 1, 2] = Enum.sort(gets)\n    end\n\n    test \"pops values from a keyword list\" do\n      assert {[1, 2, -3, -4], [c: 4, d: 5]} =\n               get_and_update_in(@test_list, [Access.values()], fn n ->\n                 if(n > 2, do: {-n, n + 1}, else: :pop)\n               end)\n    end\n\n    test \"raises when not given a map or a keyword list\" do\n      message = ~r[^Access.values/0 expected a map or a keyword list, got: .*]\n\n      assert_raise RuntimeError, message, fn ->\n        get_in(123, [Access.values()])\n      end\n\n      assert_raise RuntimeError, message, fn ->\n        get_and_update_in(:some_atom, [Access.values()], fn x -> {x, x} end)\n      end\n\n      assert_raise RuntimeError, message, fn ->\n        get_in([:a, :b, :c], [Access.values()])\n      end\n\n      assert_raise RuntimeError, message, fn ->\n        get_in([{:a, :b, :c}, {:d, :e, :f}], [Access.values()])\n      end\n\n      assert_raise RuntimeError, message, fn ->\n        get_in([{1, 2}, {3, 4}], [Access.values()])\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/agent_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule AgentTest do\n  use ExUnit.Case, async: true\n\n  doctest Agent\n\n  def identity(state) do\n    state\n  end\n\n  test \"can be supervised directly\" do\n    assert {:ok, _} = Supervisor.start_link([{Agent, fn -> :ok end}], strategy: :one_for_one)\n  end\n\n  test \"generates child_spec/1\" do\n    defmodule MyAgent do\n      use Agent\n    end\n\n    assert MyAgent.child_spec([:hello]) == %{\n             id: MyAgent,\n             start: {MyAgent, :start_link, [[:hello]]}\n           }\n\n    defmodule CustomAgent do\n      use Agent, id: :id, restart: :temporary, shutdown: :infinity, start: {:foo, :bar, []}\n    end\n\n    assert CustomAgent.child_spec([:hello]) == %{\n             id: :id,\n             restart: :temporary,\n             shutdown: :infinity,\n             start: {:foo, :bar, []}\n           }\n  end\n\n  test \"start_link/2 workflow with unregistered name and anonymous functions\" do\n    {:ok, pid} = Agent.start_link(&Map.new/0)\n\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    assert :proc_lib.translate_initial_call(pid) == {Map, :new, 0}\n\n    assert Agent.update(pid, &Map.put(&1, :hello, :world)) == :ok\n    assert Agent.get(pid, &Map.get(&1, :hello), 3000) == :world\n    assert Agent.get_and_update(pid, &Map.pop(&1, :hello), 3000) == :world\n    assert Agent.get(pid, & &1) == %{}\n    assert Agent.stop(pid) == :ok\n    wait_until_dead(pid)\n  end\n\n  test \"start_link/2 with spawn_opt\" do\n    {:ok, pid} = Agent.start_link(fn -> 0 end, spawn_opt: [priority: :high])\n    assert Process.info(pid, :priority) == {:priority, :high}\n  end\n\n  test \"start/2 workflow with registered name and module functions\" do\n    {:ok, pid} = Agent.start(Map, :new, [], name: :agent)\n    assert Process.info(pid, :registered_name) == {:registered_name, :agent}\n    assert :proc_lib.translate_initial_call(pid) == {Map, :new, 0}\n    assert Agent.cast(:agent, Map, :put, [:hello, :world]) == :ok\n    assert Agent.get(:agent, Map, :get, [:hello]) == :world\n    assert Agent.get_and_update(:agent, Map, :pop, [:hello]) == :world\n    assert Agent.get(:agent, AgentTest, :identity, []) == %{}\n    assert Agent.stop(:agent) == :ok\n    assert Process.info(pid, :registered_name) == nil\n  end\n\n  test \":sys.change_code/4 with mfa\" do\n    {:ok, pid} = Agent.start_link(fn -> %{} end)\n    :ok = :sys.suspend(pid)\n    mfa = {Map, :put, [:hello, :world]}\n    assert :sys.change_code(pid, __MODULE__, \"vsn\", mfa) == :ok\n    :ok = :sys.resume(pid)\n    assert Agent.get(pid, &Map.get(&1, :hello)) == :world\n    assert Agent.stop(pid) == :ok\n  end\n\n  test \":sys.change_code/4 with raising mfa\" do\n    {:ok, pid} = Agent.start_link(fn -> %{} end)\n    :ok = :sys.suspend(pid)\n    mfa = {:erlang, :error, []}\n    assert match?({:error, _}, :sys.change_code(pid, __MODULE__, \"vsn\", mfa))\n    :ok = :sys.resume(pid)\n    assert Agent.get(pid, & &1) == %{}\n    assert Agent.stop(pid) == :ok\n  end\n\n  defp wait_until_dead(pid) do\n    if Process.alive?(pid) do\n      wait_until_dead(pid)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/application_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule ApplicationTest do\n  use ExUnit.Case, async: true\n\n  import PathHelpers\n  import ExUnit.CaptureIO\n\n  @app :elixir\n\n  test \"application environment\" do\n    assert_raise ArgumentError, ~r/because the application was not loaded nor configured/, fn ->\n      Application.fetch_env!(:unknown, :unknown)\n    end\n\n    assert_raise ArgumentError, ~r/because configuration at :unknown was not set/, fn ->\n      Application.fetch_env!(:elixir, :unknown)\n    end\n\n    assert Application.get_env(:elixir, :unknown) == nil\n    assert Application.get_env(:elixir, :unknown, :default) == :default\n    assert Application.fetch_env(:elixir, :unknown) == :error\n\n    assert Application.put_env(:elixir, :unknown, :known) == :ok\n    assert Application.fetch_env(:elixir, :unknown) == {:ok, :known}\n    assert Application.fetch_env!(:elixir, :unknown) == :known\n    assert Application.get_env(:elixir, :unknown, :default) == :known\n    assert {:unknown, :known} in Application.get_all_env(:elixir)\n\n    assert Application.delete_env(:elixir, :unknown) == :ok\n    assert Application.get_env(:elixir, :unknown, :default) == :default\n  after\n    Application.delete_env(:elixir, :unknown)\n  end\n\n  test \"deprecated non-atom keys\" do\n    assert_deprecated(fn ->\n      Application.put_env(:elixir, [:a, :b], :c)\n    end)\n\n    assert_deprecated(fn ->\n      assert Application.get_env(:elixir, [:a, :b]) == :c\n    end)\n\n    assert_deprecated(fn ->\n      assert Application.fetch_env!(:elixir, [:a, :b]) == :c\n    end)\n  after\n    assert_deprecated(fn ->\n      Application.delete_env(:elixir, [:a, :b])\n    end)\n  end\n\n  defp assert_deprecated(fun) do\n    assert capture_io(:stderr, fun) =~ ~r/passing non-atom as application env key is deprecated/\n  end\n\n  describe \"compile environment\" do\n    test \"invoked at compile time\" do\n      assert_raise ArgumentError, ~r/because the application was not loaded nor configured/, fn ->\n        compile_env!(:unknown, :unknown)\n      end\n\n      assert_received {:compile_env, :unknown, [:unknown], :error}\n\n      assert_raise ArgumentError, ~r/because configuration at :unknown was not set/, fn ->\n        compile_env!(:elixir, :unknown)\n      end\n\n      assert_received {:compile_env, :elixir, [:unknown], :error}\n\n      assert compile_env(:elixir, :unknown) == nil\n      assert_received {:compile_env, :elixir, [:unknown], :error}\n\n      assert compile_env(:elixir, :unknown, :default) == :default\n      assert_received {:compile_env, :elixir, [:unknown], :error}\n\n      assert Application.put_env(:elixir, :unknown, nested: [key: :value]) == :ok\n\n      assert compile_env(@app, :unknown, :default) == [nested: [key: :value]]\n      assert_received {:compile_env, :elixir, [:unknown], {:ok, [nested: [key: :value]]}}\n      assert compile_env(:elixir, :unknown, :default) == [nested: [key: :value]]\n      assert_received {:compile_env, :elixir, [:unknown], {:ok, [nested: [key: :value]]}}\n\n      assert compile_env(:elixir, :unknown) == [nested: [key: :value]]\n      assert_received {:compile_env, :elixir, [:unknown], {:ok, [nested: [key: :value]]}}\n\n      assert compile_env!(@app, :unknown) == [nested: [key: :value]]\n      assert_received {:compile_env, :elixir, [:unknown], {:ok, [nested: [key: :value]]}}\n      assert compile_env!(:elixir, :unknown) == [nested: [key: :value]]\n      assert_received {:compile_env, :elixir, [:unknown], {:ok, [nested: [key: :value]]}}\n\n      assert compile_env(:elixir, [:unknown, :nested]) == [key: :value]\n      assert_received {:compile_env, :elixir, [:unknown, :nested], {:ok, [key: :value]}}\n\n      assert compile_env!(:elixir, [:unknown, :nested]) == [key: :value]\n      assert_received {:compile_env, :elixir, [:unknown, :nested], {:ok, [key: :value]}}\n\n      assert compile_env(:elixir, [:unknown, :nested, :key]) == :value\n      assert_received {:compile_env, :elixir, [:unknown, :nested, :key], {:ok, :value}}\n\n      assert compile_env!(:elixir, [:unknown, :nested, :key]) == :value\n      assert_received {:compile_env, :elixir, [:unknown, :nested, :key], {:ok, :value}}\n\n      assert compile_env(:elixir, [:unknown, :unknown, :key], :default) == :default\n      assert_received {:compile_env, :elixir, [:unknown, :unknown, :key], :error}\n\n      assert compile_env(:elixir, [:unknown, :nested, :unknown], :default) == :default\n      assert_received {:compile_env, :elixir, [:unknown, :nested, :unknown], :error}\n    after\n      Application.delete_env(:elixir, :unknown)\n    end\n\n    def trace({:compile_env, _, _, _} = msg, %Macro.Env{}) do\n      send(self(), msg)\n      :ok\n    end\n\n    def trace(_, _), do: :ok\n\n    defp compile_env(app, key, default \\\\ nil) do\n      code =\n        quote do\n          require Application\n          Application.compile_env(unquote(app), unquote(key), unquote(default))\n        end\n\n      {result, _binding} = Code.eval_quoted(code, [], tracers: [__MODULE__])\n      result\n    end\n\n    defp compile_env!(app, key) do\n      code =\n        quote do\n          require Application\n          Application.compile_env!(unquote(app), unquote(key))\n        end\n\n      {result, _binding} = Code.eval_quoted(code, [], tracers: [__MODULE__])\n      result\n    end\n  end\n\n  test \"loaded and started applications\" do\n    started = Application.started_applications()\n    assert is_list(started)\n    assert {:elixir, ~c\"elixir\", _} = List.keyfind(started, :elixir, 0)\n\n    started_timeout = Application.started_applications(7000)\n    assert is_list(started_timeout)\n    assert {:elixir, ~c\"elixir\", _} = List.keyfind(started_timeout, :elixir, 0)\n\n    loaded = Application.loaded_applications()\n    assert is_list(loaded)\n    assert {:elixir, ~c\"elixir\", _} = List.keyfind(loaded, :elixir, 0)\n  end\n\n  test \"application specification\" do\n    assert is_list(Application.spec(:elixir))\n    assert Application.spec(:unknown) == nil\n    assert Application.spec(:unknown, :description) == nil\n    assert Application.spec(:elixir, :description) == ~c\"elixir\"\n\n    assert_raise FunctionClauseError, fn ->\n      Application.spec(:elixir, Process.get(:unknown, :unknown))\n    end\n  end\n\n  test \"application module\" do\n    assert Application.get_application(String) == :elixir\n    assert Application.get_application(__MODULE__) == nil\n    assert Application.get_application(__MODULE__.Unknown) == nil\n  end\n\n  test \"application directory\" do\n    root = Path.expand(\"../../../..\", __DIR__)\n\n    assert normalize_app_dir(Application.app_dir(:elixir)) ==\n             normalize_app_dir(Path.join(root, \"bin/../lib/elixir\"))\n\n    assert normalize_app_dir(Application.app_dir(:elixir, \"priv\")) ==\n             normalize_app_dir(Path.join(root, \"bin/../lib/elixir/priv\"))\n\n    assert normalize_app_dir(Application.app_dir(:elixir, [\"priv\", \"foo\"])) ==\n             normalize_app_dir(Path.join(root, \"bin/../lib/elixir/priv/foo\"))\n\n    assert_raise ArgumentError, fn ->\n      Application.app_dir(:unknown)\n    end\n  end\n\n  if windows?() do\n    defp normalize_app_dir(path) do\n      path |> String.downcase() |> Path.expand()\n    end\n  else\n    defp normalize_app_dir(path) do\n      path |> String.downcase()\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/atom_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule AtomTest do\n  use ExUnit.Case, async: true\n\n  doctest Atom, except: [:moduledoc]\n\n  test \"to_string/1\" do\n    assert \"héllo\" |> String.to_atom() |> Atom.to_string() == \"héllo\"\n  end\n\n  test \"to_charlist/1\" do\n    assert \"héllo\" |> String.to_atom() |> Atom.to_charlist() == ~c\"héllo\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/base_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule BaseTest do\n  use ExUnit.Case, async: true\n\n  doctest Base\n  import Base\n\n  test \"encode16/1\" do\n    assert \"\" == encode16(\"\")\n    assert \"66\" == encode16(\"f\")\n    assert \"666F\" == encode16(\"fo\")\n    assert \"666F6F\" == encode16(\"foo\")\n    assert \"666F6F62\" == encode16(\"foob\")\n    assert \"666F6F6261\" == encode16(\"fooba\")\n    assert \"666F6F626172\" == encode16(\"foobar\")\n    assert \"A1B2C3D4E5F67891\" == encode16(<<161, 178, 195, 212, 229, 246, 120, 145>>)\n\n    assert \"a1b2c3d4e5f67891\" ==\n             encode16(<<161, 178, 195, 212, 229, 246, 120, 145>>, case: :lower)\n  end\n\n  test \"decode16/1\" do\n    assert {:ok, \"\"} == decode16(\"\")\n    assert {:ok, \"f\"} == decode16(\"66\")\n    assert {:ok, \"fo\"} == decode16(\"666F\")\n    assert {:ok, \"foo\"} == decode16(\"666F6F\")\n    assert {:ok, \"foob\"} == decode16(\"666F6F62\")\n    assert {:ok, \"fooba\"} == decode16(\"666F6F6261\")\n    assert {:ok, \"foobar\"} == decode16(\"666F6F626172\")\n    assert {:ok, <<161, 178, 195, 212, 229, 246, 120, 145>>} == decode16(\"A1B2C3D4E5F67891\")\n\n    assert {:ok, <<161, 178, 195, 212, 229, 246, 120, 145>>} ==\n             decode16(\"a1b2c3d4e5f67891\", case: :lower)\n\n    assert {:ok, <<161, 178, 195, 212, 229, 246, 120, 145>>} ==\n             decode16(\"a1B2c3D4e5F67891\", case: :mixed)\n  end\n\n  test \"decode16!/1\" do\n    assert \"\" == decode16!(\"\")\n    assert \"f\" == decode16!(\"66\")\n    assert \"fo\" == decode16!(\"666F\")\n    assert \"foo\" == decode16!(\"666F6F\")\n    assert \"foob\" == decode16!(\"666F6F62\")\n    assert \"fooba\" == decode16!(\"666F6F6261\")\n    assert \"foobar\" == decode16!(\"666F6F626172\")\n    assert <<161, 178, 195, 212, 229, 246, 120, 145>> == decode16!(\"A1B2C3D4E5F67891\")\n\n    assert <<161, 178, 195, 212, 229, 246, 120, 145>> ==\n             decode16!(\"a1b2c3d4e5f67891\", case: :lower)\n\n    assert <<161, 178, 195, 212, 229, 246, 120, 145>> ==\n             decode16!(\"a1B2c3D4e5F67891\", case: :mixed)\n  end\n\n  test \"decode16/1 errors on non-alphabet character\" do\n    assert :error == decode16(\"66KF\")\n    assert :error == decode16(\"66ff\")\n    assert :error == decode16(\"66FF\", case: :lower)\n  end\n\n  test \"decode16!/1 errors on non-alphabet character\" do\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"K\\\" (byte 75)\", fn ->\n      decode16!(\"66KF\")\n    end\n\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"f\\\" (byte 102)\", fn ->\n      decode16!(\"66ff\")\n    end\n\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"F\\\" (byte 70)\", fn ->\n      decode16!(\"66FF\", case: :lower)\n    end\n  end\n\n  test \"decode16/1 errors on odd-length string\" do\n    assert :error == decode16(\"666\")\n  end\n\n  test \"decode16!/1 errors odd-length string\" do\n    assert_raise ArgumentError, ~r/string given to decode has wrong length/, fn ->\n      decode16!(\"666\")\n    end\n  end\n\n  test \"valid16?/1\" do\n    assert valid16?(\"\")\n    assert valid16?(\"66\")\n    assert valid16?(\"666F\")\n    assert valid16?(\"666F6F\")\n    assert valid16?(\"666F6F62\")\n    assert valid16?(\"666F6F6261\")\n    assert valid16?(\"666F6F626172\")\n    assert valid16?(\"A1B2C3D4E5F67891\")\n    assert valid16?(\"a1b2c3d4e5f67891\", case: :lower)\n    assert valid16?(\"a1B2c3D4e5F67891\", case: :mixed)\n  end\n\n  test \"valid16?/1 returns false on non-alphabet character\" do\n    refute valid16?(\"66KF\")\n    refute valid16?(\"66ff\")\n    refute valid16?(\"66FF\", case: :lower)\n    refute valid16?(\"66fg\", case: :mixed)\n  end\n\n  test \"valid16?/1 errors on odd-length string\" do\n    refute valid16?(\"666\")\n  end\n\n  test \"encode64/1 can deal with empty strings\" do\n    assert \"\" == encode64(\"\")\n  end\n\n  test \"encode64/1 with two pads\" do\n    assert \"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\" == encode64(\"Aladdin:open sesame\")\n  end\n\n  test \"encode64/1 with one pad\" do\n    assert \"SGVsbG8gV29ybGQ=\" == encode64(\"Hello World\")\n  end\n\n  test \"encode64/1 with no pad\" do\n    assert \"QWxhZGRpbjpvcGVuIHNlc2Ft\" == encode64(\"Aladdin:open sesam\")\n\n    assert \"MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9\" ==\n             encode64(<<\"0123456789!@#0^&*();:<>,. []{}\">>)\n  end\n\n  test \"encode64/1 with one pad and ignoring padding\" do\n    assert \"SGVsbG8gV29ybGQ\" == encode64(\"Hello World\", padding: false)\n  end\n\n  test \"encode64/1 with two pads and ignoring padding\" do\n    assert \"QWxhZGRpbjpvcGVuIHNlc2FtZQ\" == encode64(\"Aladdin:open sesame\", padding: false)\n  end\n\n  test \"encode64/1 with no pads and ignoring padding\" do\n    assert \"QWxhZGRpbjpvcGVuIHNlc2Ft\" == encode64(\"Aladdin:open sesam\", padding: false)\n  end\n\n  test \"decode64/1 can deal with empty strings\" do\n    assert {:ok, \"\"} == decode64(\"\")\n  end\n\n  test \"decode64!/1 can deal with empty strings\" do\n    assert \"\" == decode64!(\"\")\n  end\n\n  test \"decode64/1 with two pads\" do\n    assert {:ok, \"Aladdin:open sesame\"} == decode64(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\")\n  end\n\n  test \"decode64!/1 with two pads\" do\n    assert \"Aladdin:open sesame\" == decode64!(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\")\n  end\n\n  test \"decode64/1 with one pad\" do\n    assert {:ok, \"Hello World\"} == decode64(\"SGVsbG8gV29ybGQ=\")\n  end\n\n  test \"decode64!/1 with one pad\" do\n    assert \"Hello World\" == decode64!(\"SGVsbG8gV29ybGQ=\")\n  end\n\n  test \"decode64/1 with no pad\" do\n    assert {:ok, \"Aladdin:open sesam\"} == decode64(\"QWxhZGRpbjpvcGVuIHNlc2Ft\")\n  end\n\n  test \"decode64!/1 with no pad\" do\n    assert \"Aladdin:open sesam\" == decode64!(\"QWxhZGRpbjpvcGVuIHNlc2Ft\")\n  end\n\n  test \"decode64/1 errors on non-alphabet character\" do\n    assert :error == decode64(\"Zm9)\")\n  end\n\n  test \"decode64!/1 errors on non-alphabet character\" do\n    assert_raise ArgumentError, \"non-alphabet character found: \\\")\\\" (byte 41)\", fn ->\n      decode64!(\"Zm9)\")\n    end\n  end\n\n  test \"decode64/1 errors on whitespace unless there's ignore: :whitespace\" do\n    assert :error == decode64(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\")\n\n    assert {:ok, \"Aladdin:open sesam\"} ==\n             decode64(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\", ignore: :whitespace)\n  end\n\n  test \"decode64!/1 errors on whitespace unless there's ignore: :whitespace\" do\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"\\\\n\\\" (byte 10)\", fn ->\n      decode64!(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\")\n    end\n\n    assert \"Aladdin:open sesam\" ==\n             decode64!(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\", ignore: :whitespace)\n  end\n\n  test \"decode64/1 errors on incorrect padding\" do\n    assert :error == decode64(\"SGVsbG8gV29ybGQ\")\n  end\n\n  test \"decode64!/1 errors on incorrect padding\" do\n    assert_raise ArgumentError, \"incorrect padding\", fn ->\n      decode64!(\"SGVsbG8gV29ybGQ\")\n    end\n  end\n\n  test \"decode64/2 with two pads and ignoring padding\" do\n    assert {:ok, \"Aladdin:open sesame\"} == decode64(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ\", padding: false)\n  end\n\n  test \"decode64!/2 with two pads and ignoring padding\" do\n    assert \"Aladdin:open sesame\" == decode64!(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ\", padding: false)\n  end\n\n  test \"decode64/2 with one pad and ignoring padding\" do\n    assert {:ok, \"Hello World\"} == decode64(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"decode64!/2 with one pad and ignoring padding\" do\n    assert \"Hello World\" == decode64!(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"decode64/2 with no pad and ignoring padding\" do\n    assert {:ok, \"Aladdin:open sesam\"} == decode64(\"QWxhZGRpbjpvcGVuIHNlc2Ft\", padding: false)\n  end\n\n  test \"decode64!/2 with no pad and ignoring padding\" do\n    assert \"Aladdin:open sesam\" == decode64!(\"QWxhZGRpbjpvcGVuIHNlc2Ft\", padding: false)\n  end\n\n  test \"decode64/2 with incorrect padding and ignoring padding\" do\n    assert {:ok, \"Hello World\"} == decode64(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"decode64!/2 with incorrect padding and ignoring padding\" do\n    assert \"Hello World\" == decode64!(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"valid64?/1 can deal with empty strings\" do\n    assert valid64?(\"\")\n  end\n\n  test \"valid64?/1 with two pads\" do\n    assert valid64?(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\")\n  end\n\n  test \"valid64?/1 with one pad\" do\n    assert valid64?(\"SGVsbG8gV29ybGQ=\")\n  end\n\n  test \"valid64?/1 with no pad\" do\n    assert valid64?(\"QWxhZGRpbjpvcGVuIHNlc2Ft\")\n  end\n\n  test \"valid64?/1 returns false on non-alphabet character\" do\n    refute valid64?(\"Zm9)\")\n  end\n\n  test \"valid64?/1 returns false on whitespace unless there's ignore: :whitespace\" do\n    refute valid64?(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\")\n\n    assert valid64?(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\", ignore: :whitespace)\n  end\n\n  test \"valid64?/1 returns false on incorrect padding\" do\n    refute valid64?(\"SGVsbG8gV29ybGQ\")\n  end\n\n  test \"valid64?/2 with two pads and ignoring padding\" do\n    assert valid64?(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ\", padding: false)\n  end\n\n  test \"valid64?/2 with one pad and ignoring padding\" do\n    assert valid64?(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"valid64?/2 with no pad and ignoring padding\" do\n    assert valid64?(\"QWxhZGRpbjpvcGVuIHNlc2Ft\", padding: false)\n  end\n\n  test \"valid64?/2 with incorrect padding and ignoring padding\" do\n    assert valid64?(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"url_encode64/1 can deal with empty strings\" do\n    assert \"\" == url_encode64(\"\")\n  end\n\n  test \"url_encode64/1 with two pads\" do\n    assert \"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\" == url_encode64(\"Aladdin:open sesame\")\n  end\n\n  test \"url_encode64/1 with one pad\" do\n    assert \"SGVsbG8gV29ybGQ=\" == url_encode64(\"Hello World\")\n  end\n\n  test \"url_encode64/1 with no pad\" do\n    assert \"QWxhZGRpbjpvcGVuIHNlc2Ft\" == url_encode64(\"Aladdin:open sesam\")\n\n    assert \"MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9\" ==\n             url_encode64(<<\"0123456789!@#0^&*();:<>,. []{}\">>)\n  end\n\n  test \"url_encode64/2 with two pads and ignoring padding\" do\n    assert \"QWxhZGRpbjpvcGVuIHNlc2FtZQ\" == url_encode64(\"Aladdin:open sesame\", padding: false)\n  end\n\n  test \"url_encode64/2 with one pad and ignoring padding\" do\n    assert \"SGVsbG8gV29ybGQ\" == url_encode64(\"Hello World\", padding: false)\n  end\n\n  test \"url_encode64/2 with no pad and ignoring padding\" do\n    assert \"QWxhZGRpbjpvcGVuIHNlc2Ft\" == url_encode64(\"Aladdin:open sesam\", padding: false)\n  end\n\n  test \"url_encode64/1 doesn't produce URL-unsafe characters\" do\n    refute \"/3/+/A==\" == url_encode64(<<255, 127, 254, 252>>)\n    assert \"_3_-_A==\" == url_encode64(<<255, 127, 254, 252>>)\n  end\n\n  test \"url_decode64/1 can deal with empty strings\" do\n    assert {:ok, \"\"} == url_decode64(\"\")\n  end\n\n  test \"url_decode64!/1 can deal with empty strings\" do\n    assert \"\" == url_decode64!(\"\")\n  end\n\n  test \"url_decode64/1 with two pads\" do\n    assert {:ok, \"Aladdin:open sesame\"} == url_decode64(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\")\n  end\n\n  test \"url_decode64!/1 with two pads\" do\n    assert \"Aladdin:open sesame\" == url_decode64!(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\")\n  end\n\n  test \"url_decode64/1 with one pad\" do\n    assert {:ok, \"Hello World\"} == url_decode64(\"SGVsbG8gV29ybGQ=\")\n  end\n\n  test \"url_decode64!/1 with one pad\" do\n    assert \"Hello World\" == url_decode64!(\"SGVsbG8gV29ybGQ=\")\n  end\n\n  test \"url_decode64/1 with no pad\" do\n    assert {:ok, \"Aladdin:open sesam\"} == url_decode64(\"QWxhZGRpbjpvcGVuIHNlc2Ft\")\n  end\n\n  test \"url_decode64!/1 with no pad\" do\n    assert \"Aladdin:open sesam\" == url_decode64!(\"QWxhZGRpbjpvcGVuIHNlc2Ft\")\n  end\n\n  test \"url_decode64/1,2 error on whitespace unless there's ignore: :whitespace\" do\n    assert :error == url_decode64(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\")\n\n    assert {:ok, \"Aladdin:open sesam\"} ==\n             url_decode64(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\", ignore: :whitespace)\n  end\n\n  test \"url_decode64!/1,2 error on whitespace unless there's ignore: :whitespace\" do\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"\\\\n\\\" (byte 10)\", fn ->\n      url_decode64!(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\")\n    end\n\n    assert \"Aladdin:open sesam\" ==\n             url_decode64!(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\", ignore: :whitespace)\n  end\n\n  test \"url_decode64/1 errors on non-alphabet character\" do\n    assert :error == url_decode64(\"Zm9)\")\n  end\n\n  test \"url_decode64!/1 errors on non-alphabet character\" do\n    assert_raise ArgumentError, \"non-alphabet character found: \\\")\\\" (byte 41)\", fn ->\n      url_decode64!(\"Zm9)\")\n    end\n  end\n\n  test \"url_decode64/1 errors on incorrect padding\" do\n    assert :error == url_decode64(\"SGVsbG8gV29ybGQ\")\n  end\n\n  test \"url_decode64!/1 errors on incorrect padding\" do\n    assert_raise ArgumentError, \"incorrect padding\", fn ->\n      url_decode64!(\"SGVsbG8gV29ybGQ\")\n    end\n  end\n\n  test \"url_decode64/2 with two pads and ignoring padding\" do\n    assert {:ok, \"Aladdin:open sesame\"} ==\n             url_decode64(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ\", padding: false)\n  end\n\n  test \"url_decode64!/2 with two pads and ignoring padding\" do\n    assert \"Aladdin:open sesame\" == url_decode64!(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ\", padding: false)\n  end\n\n  test \"url_decode64/2 with one pad and ignoring padding\" do\n    assert {:ok, \"Hello World\"} == url_decode64(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"url_decode64!/2 with one pad and ignoring padding\" do\n    assert \"Hello World\" == url_decode64!(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"url_decode64/2 with no pad and ignoring padding\" do\n    assert {:ok, \"Aladdin:open sesam\"} == url_decode64(\"QWxhZGRpbjpvcGVuIHNlc2Ft\", padding: false)\n  end\n\n  test \"url_decode64!/2 with no pad and ignoring padding\" do\n    assert \"Aladdin:open sesam\" == url_decode64!(\"QWxhZGRpbjpvcGVuIHNlc2Ft\", padding: false)\n  end\n\n  test \"url_decode64/2 ignores incorrect padding when :padding is false\" do\n    assert {:ok, \"Hello World\"} == url_decode64(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"url_decode64!/2 ignores incorrect padding when :padding is false\" do\n    assert \"Hello World\" == url_decode64!(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"url_valid64?/1 can deal with empty strings\" do\n    assert url_valid64?(\"\")\n  end\n\n  test \"url_valid64?/1 with two pads\" do\n    assert url_valid64?(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\")\n  end\n\n  test \"url_valid64?/1 with one pad\" do\n    assert url_valid64?(\"SGVsbG8gV29ybGQ=\")\n  end\n\n  test \"url_valid64?/1 with no pad\" do\n    assert url_valid64?(\"QWxhZGRpbjpvcGVuIHNlc2Ft\")\n  end\n\n  test \"url_valid64?/1 returns false on non-alphabet character\" do\n    refute url_valid64?(\"Zm9)\")\n  end\n\n  test \"url_valid64?/1 returns false on whitespace unless there's ignore: :whitespace\" do\n    refute url_valid64?(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\")\n\n    assert url_valid64?(\"\\nQWxhZGRp bjpvcGVu\\sIHNlc2Ft\\t\", ignore: :whitespace)\n  end\n\n  test \"url_valid64?/1 returns false on incorrect padding\" do\n    refute url_valid64?(\"SGVsbG8gV29ybGQ\")\n  end\n\n  test \"url_valid64?/2 with two pads and ignoring padding\" do\n    assert url_valid64?(\"QWxhZGRpbjpvcGVuIHNlc2FtZQ\", padding: false)\n  end\n\n  test \"url_valid64?/2 with one pad and ignoring padding\" do\n    assert url_valid64?(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"url_valid64?/2 with no pad and ignoring padding\" do\n    assert url_valid64?(\"QWxhZGRpbjpvcGVuIHNlc2Ft\", padding: false)\n  end\n\n  test \"url_valid64?/2 errors on incorrect padding\" do\n    refute url_valid64?(\"SGVsbG8gV29ybGQ\")\n  end\n\n  test \"url_valid64?/2 ignores incorrect padding when :padding is false\" do\n    assert url_valid64?(\"SGVsbG8gV29ybGQ\", padding: false)\n  end\n\n  test \"encode32/1 can deal with empty strings\" do\n    assert \"\" == encode32(\"\")\n  end\n\n  test \"encode32/1 with one pad\" do\n    assert \"MZXW6YQ=\" == encode32(\"foob\")\n  end\n\n  test \"encode32/1 with three pads\" do\n    assert \"MZXW6===\" == encode32(\"foo\")\n  end\n\n  test \"encode32/1 with four pads\" do\n    assert \"MZXQ====\" == encode32(\"fo\")\n  end\n\n  test \"encode32/1 with six pads\" do\n    assert \"MZXW6YTBOI======\" == encode32(\"foobar\")\n    assert \"MY======\" == encode32(\"f\")\n  end\n\n  test \"encode32/1 with no pads\" do\n    assert \"MZXW6YTB\" == encode32(\"fooba\")\n  end\n\n  test \"encode32/2 with one pad and ignoring padding\" do\n    assert \"MZXW6YQ\" == encode32(\"foob\", padding: false)\n  end\n\n  test \"encode32/2 with three pads and ignoring padding\" do\n    assert \"MZXW6\" == encode32(\"foo\", padding: false)\n  end\n\n  test \"encode32/2 with four pads and ignoring padding\" do\n    assert \"MZXQ\" == encode32(\"fo\", padding: false)\n  end\n\n  test \"encode32/2 with six pads and ignoring padding\" do\n    assert \"MZXW6YTBOI\" == encode32(\"foobar\", padding: false)\n  end\n\n  test \"encode32/2 with no pads and ignoring padding\" do\n    assert \"MZXW6YTB\" == encode32(\"fooba\", padding: false)\n  end\n\n  test \"encode32/2 with lowercase\" do\n    assert \"mzxw6ytb\" == encode32(\"fooba\", case: :lower)\n  end\n\n  test \"decode32/1 can deal with empty strings\" do\n    assert {:ok, \"\"} == decode32(\"\")\n  end\n\n  test \"decode32!/2 can deal with empty strings\" do\n    assert \"\" == decode32!(\"\")\n  end\n\n  test \"decode32/1 with one pad\" do\n    assert {:ok, \"foob\"} == decode32(\"MZXW6YQ=\")\n  end\n\n  test \"decode32!/1 with one pad\" do\n    assert \"foob\" == decode32!(\"MZXW6YQ=\")\n  end\n\n  test \"decode32/1 with three pads\" do\n    assert {:ok, \"foo\"} == decode32(\"MZXW6===\")\n  end\n\n  test \"decode32!/1 with three pads\" do\n    assert \"foo\" == decode32!(\"MZXW6===\")\n  end\n\n  test \"decode32/1 with four pads\" do\n    assert {:ok, \"fo\"} == decode32(\"MZXQ====\")\n  end\n\n  test \"decode32!/1 with four pads\" do\n    assert \"fo\" == decode32!(\"MZXQ====\")\n  end\n\n  test \"decode32/2 with lowercase\" do\n    assert {:ok, \"fo\"} == decode32(\"mzxq====\", case: :lower)\n  end\n\n  test \"decode32!/2 with lowercase\" do\n    assert \"fo\" == decode32!(\"mzxq====\", case: :lower)\n  end\n\n  test \"decode32/2 with mixed case\" do\n    assert {:ok, \"fo\"} == decode32(\"mZXq====\", case: :mixed)\n  end\n\n  test \"decode32!/2 with mixed case\" do\n    assert \"fo\" == decode32!(\"mZXq====\", case: :mixed)\n  end\n\n  test \"decode32/1 with six pads\" do\n    assert {:ok, \"foobar\"} == decode32(\"MZXW6YTBOI======\")\n    assert {:ok, \"f\"} == decode32(\"MY======\")\n  end\n\n  test \"decode32!/1 with six pads\" do\n    assert \"foobar\" == decode32!(\"MZXW6YTBOI======\")\n    assert \"f\" == decode32!(\"MY======\")\n  end\n\n  test \"decode32/1 with no pads\" do\n    assert {:ok, \"fooba\"} == decode32(\"MZXW6YTB\")\n  end\n\n  test \"decode32!/1 with no pads\" do\n    assert \"fooba\" == decode32!(\"MZXW6YTB\")\n  end\n\n  test \"decode32/1,2 error on non-alphabet character\" do\n    assert :error == decode32(\"MZX)6YTB\")\n    assert :error == decode32(\"66ff\")\n    assert :error == decode32(\"66FF\", case: :lower)\n  end\n\n  test \"decode32!/1,2 argument error on non-alphabet character\" do\n    assert_raise ArgumentError, \"non-alphabet character found: \\\")\\\" (byte 41)\", fn ->\n      decode32!(\"MZX)6YTB\")\n    end\n\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"m\\\" (byte 109)\", fn ->\n      decode32!(\"mzxw6ytboi======\")\n    end\n\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"M\\\" (byte 77)\", fn ->\n      decode32!(\"MZXW6YTBOI======\", case: :lower)\n    end\n\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"0\\\" (byte 48)\", fn ->\n      decode32!(\"0ZXW6YTB0I======\", case: :mixed)\n    end\n  end\n\n  test \"decode32/1 errors on incorrect padding\" do\n    assert :error == decode32(\"MZXW6YQ\")\n  end\n\n  test \"decode32!/1 errors on incorrect padding\" do\n    assert_raise ArgumentError, \"incorrect padding\", fn ->\n      decode32!(\"MZXW6YQ\")\n    end\n  end\n\n  test \"decode32/2 with one pad and :padding to false\" do\n    assert {:ok, \"foob\"} == decode32(\"MZXW6YQ\", padding: false)\n  end\n\n  test \"decode32!/2 with one pad and :padding to false\" do\n    assert \"foob\" == decode32!(\"MZXW6YQ\", padding: false)\n  end\n\n  test \"decode32/2 with three pads and ignoring padding\" do\n    assert {:ok, \"foo\"} == decode32(\"MZXW6\", padding: false)\n  end\n\n  test \"decode32!/2 with three pads and ignoring padding\" do\n    assert \"foo\" == decode32!(\"MZXW6\", padding: false)\n  end\n\n  test \"decode32/2 with four pads and ignoring padding\" do\n    assert {:ok, \"fo\"} == decode32(\"MZXQ\", padding: false)\n  end\n\n  test \"decode32!/2 with four pads and ignoring padding\" do\n    assert \"fo\" == decode32!(\"MZXQ\", padding: false)\n  end\n\n  test \"decode32/2 with :lower case and ignoring padding\" do\n    assert {:ok, \"fo\"} == decode32(\"mzxq\", case: :lower, padding: false)\n  end\n\n  test \"decode32!/2 with :lower case and ignoring padding\" do\n    assert \"fo\" == decode32!(\"mzxq\", case: :lower, padding: false)\n  end\n\n  test \"decode32/2 with :mixed case and ignoring padding\" do\n    assert {:ok, \"fo\"} == decode32(\"mZXq\", case: :mixed, padding: false)\n  end\n\n  test \"decode32!/2 with :mixed case and ignoring padding\" do\n    assert \"fo\" == decode32!(\"mZXq\", case: :mixed, padding: false)\n  end\n\n  test \"decode32/2 with six pads and ignoring padding\" do\n    assert {:ok, \"foobar\"} == decode32(\"MZXW6YTBOI\", padding: false)\n  end\n\n  test \"decode32!/2 with six pads and ignoring padding\" do\n    assert \"foobar\" == decode32!(\"MZXW6YTBOI\", padding: false)\n  end\n\n  test \"decode32/2 with no pads and ignoring padding\" do\n    assert {:ok, \"fooba\"} == decode32(\"MZXW6YTB\", padding: false)\n  end\n\n  test \"decode32!/2 with no pads and ignoring padding\" do\n    assert \"fooba\" == decode32!(\"MZXW6YTB\", padding: false)\n  end\n\n  test \"decode32/2 ignores incorrect padding when :padding is false\" do\n    assert {:ok, \"foob\"} == decode32(\"MZXW6YQ\", padding: false)\n  end\n\n  test \"decode32!/2 ignores incorrect padding when :padding is false\" do\n    \"foob\" = decode32!(\"MZXW6YQ\", padding: false)\n  end\n\n  test \"valid32?/1 can deal with empty strings\" do\n    assert valid32?(\"\")\n  end\n\n  test \"valid32?/1 with one pad\" do\n    assert valid32?(\"MZXW6YQ=\")\n  end\n\n  test \"valid32?/1 with three pads\" do\n    assert valid32?(\"MZXW6===\")\n  end\n\n  test \"valid32?/1 with four pads\" do\n    assert valid32?(\"MZXQ====\")\n  end\n\n  test \"valid32?/1 with lowercase\" do\n    assert valid32?(\"mzxq====\", case: :lower)\n  end\n\n  test \"valid32?/1 with mixed case\" do\n    assert valid32?(\"mZXq====\", case: :mixed)\n  end\n\n  test \"valid32?/1 with six pads\" do\n    assert valid32?(\"MZXW6YTBOI======\")\n  end\n\n  test \"valid32?/1 with no pads\" do\n    assert valid32?(\"MZXW6YTB\")\n  end\n\n  test \"valid32?/1,2 returns false on non-alphabet character\" do\n    refute valid32?(\"MZX)6YTB\")\n    refute valid32?(\"66ff\")\n    refute valid32?(\"66FF\", case: :lower)\n    refute valid32?(\"0ZXW6YTB0I======\", case: :mixed)\n  end\n\n  test \"valid32?/1 returns false on incorrect padding\" do\n    refute valid32?(\"MZXW6YQ\")\n  end\n\n  test \"valid32?/2 with one pad and :padding to false\" do\n    assert valid32?(\"MZXW6YQ\", padding: false)\n  end\n\n  test \"valid32?/2 with three pads and ignoring padding\" do\n    assert valid32?(\"MZXW6\", padding: false)\n  end\n\n  test \"valid32?/2 with four pads and ignoring padding\" do\n    assert valid32?(\"MZXQ\", padding: false)\n  end\n\n  test \"valid32?/2 with :lower case and ignoring padding\" do\n    assert valid32?(\"mzxq\", case: :lower, padding: false)\n  end\n\n  test \"valid32?/2 with :mixed case and ignoring padding\" do\n    assert valid32?(\"mZXq\", case: :mixed, padding: false)\n  end\n\n  test \"valid32?/2 with six pads and ignoring padding\" do\n    assert valid32?(\"MZXW6YTBOI\", padding: false)\n  end\n\n  test \"valid32?/2 with no pads and ignoring padding\" do\n    assert valid32?(\"MZXW6YTB\", padding: false)\n  end\n\n  test \"valid32?/2 ignores incorrect padding when :padding is false\" do\n    assert valid32?(\"MZXW6YQ\", padding: false)\n  end\n\n  test \"hex_encode32/1 can deal with empty strings\" do\n    assert \"\" == hex_encode32(\"\")\n  end\n\n  test \"hex_encode32/1 with one pad\" do\n    assert \"CPNMUOG=\" == hex_encode32(\"foob\")\n  end\n\n  test \"hex_encode32/1 with three pads\" do\n    assert \"CPNMU===\" == hex_encode32(\"foo\")\n  end\n\n  test \"hex_encode32/1 with four pads\" do\n    assert \"CPNG====\" == hex_encode32(\"fo\")\n  end\n\n  test \"hex_encode32/1 with six pads\" do\n    assert \"CPNMUOJ1E8======\" == hex_encode32(\"foobar\")\n    assert \"CO======\" == hex_encode32(\"f\")\n  end\n\n  test \"hex_encode32/1 with no pads\" do\n    assert \"CPNMUOJ1\" == hex_encode32(\"fooba\")\n  end\n\n  test \"hex_encode32/2 with one pad and ignoring padding\" do\n    assert \"CPNMUOG\" == hex_encode32(\"foob\", padding: false)\n  end\n\n  test \"hex_encode32/2 with three pads and ignoring padding\" do\n    assert \"CPNMU\" == hex_encode32(\"foo\", padding: false)\n  end\n\n  test \"hex_encode32/2 with four pads and ignoring padding\" do\n    assert \"CPNG\" == hex_encode32(\"fo\", padding: false)\n  end\n\n  test \"hex_encode32/2 with six pads and ignoring padding\" do\n    assert \"CPNMUOJ1E8\" == hex_encode32(\"foobar\", padding: false)\n  end\n\n  test \"hex_encode32/2 with no pads and ignoring padding\" do\n    assert \"CPNMUOJ1\" == hex_encode32(\"fooba\", padding: false)\n  end\n\n  test \"hex_encode32/2 with lowercase\" do\n    assert \"cpnmuoj1\" == hex_encode32(\"fooba\", case: :lower)\n  end\n\n  test \"hex_decode32/1 can deal with empty strings\" do\n    assert {:ok, \"\"} == hex_decode32(\"\")\n  end\n\n  test \"hex_decode32!/1 can deal with empty strings\" do\n    assert \"\" == hex_decode32!(\"\")\n  end\n\n  test \"hex_decode32/1 with one pad\" do\n    assert {:ok, \"foob\"} == hex_decode32(\"CPNMUOG=\")\n  end\n\n  test \"hex_decode32!/1 with one pad\" do\n    assert \"foob\" == hex_decode32!(\"CPNMUOG=\")\n  end\n\n  test \"hex_decode32/1 with three pads\" do\n    assert {:ok, \"foo\"} == hex_decode32(\"CPNMU===\")\n  end\n\n  test \"hex_decode32!/1 with three pads\" do\n    assert \"foo\" == hex_decode32!(\"CPNMU===\")\n  end\n\n  test \"hex_decode32/1 with four pads\" do\n    assert {:ok, \"fo\"} == hex_decode32(\"CPNG====\")\n  end\n\n  test \"hex_decode32!/1 with four pads\" do\n    assert \"fo\" == hex_decode32!(\"CPNG====\")\n  end\n\n  test \"hex_decode32/1 with six pads\" do\n    assert {:ok, \"foobar\"} == hex_decode32(\"CPNMUOJ1E8======\")\n    assert {:ok, \"f\"} == hex_decode32(\"CO======\")\n  end\n\n  test \"hex_decode32!/1 with six pads\" do\n    assert \"foobar\" == hex_decode32!(\"CPNMUOJ1E8======\")\n    assert \"f\" == hex_decode32!(\"CO======\")\n  end\n\n  test \"hex_decode32/1 with no pads\" do\n    assert {:ok, \"fooba\"} == hex_decode32(\"CPNMUOJ1\")\n  end\n\n  test \"hex_decode32!/1 with no pads\" do\n    assert \"fooba\" == hex_decode32!(\"CPNMUOJ1\")\n  end\n\n  test \"hex_decode32/1,2 error on non-alphabet character\" do\n    assert :error == hex_decode32(\"CPN)UOJ1\")\n    assert :error == hex_decode32(\"66f\")\n    assert :error == hex_decode32(\"66F\", case: :lower)\n  end\n\n  test \"hex_decode32!/1,2 error non-alphabet character\" do\n    assert_raise ArgumentError, \"non-alphabet character found: \\\")\\\" (byte 41)\", fn ->\n      hex_decode32!(\"CPN)UOJ1\")\n    end\n\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"c\\\" (byte 99)\", fn ->\n      hex_decode32!(\"cpnmuoj1e8======\")\n    end\n\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"C\\\" (byte 67)\", fn ->\n      hex_decode32!(\"CPNMUOJ1E8======\", case: :lower)\n    end\n  end\n\n  test \"hex_decode32/1 errors on incorrect padding\" do\n    assert :error == hex_decode32(\"CPNMUOG\")\n  end\n\n  test \"hex_decode32!/1 errors on incorrect padding\" do\n    assert_raise ArgumentError, \"incorrect padding\", fn ->\n      hex_decode32!(\"CPNMUOG\")\n    end\n  end\n\n  test \"hex_decode32/2 with lowercase\" do\n    assert {:ok, \"fo\"} == hex_decode32(\"cpng====\", case: :lower)\n  end\n\n  test \"hex_decode32!/2 with lowercase\" do\n    assert \"fo\" == hex_decode32!(\"cpng====\", case: :lower)\n  end\n\n  test \"hex_decode32/2 with mixed case\" do\n    assert {:ok, \"fo\"} == hex_decode32(\"cPNg====\", case: :mixed)\n  end\n\n  test \"hex_decode32!/2 with mixed case\" do\n    assert \"fo\" == hex_decode32!(\"cPNg====\", case: :mixed)\n  end\n\n  test \"decode16!/1 errors on non-UTF-8 char\" do\n    assert_raise ArgumentError, \"non-alphabet character found: \\\"\\\\0\\\" (byte 0)\", fn ->\n      decode16!(\"012\" <> <<0>>)\n    end\n  end\n\n  test \"hex_decode32/2 with one pad and ignoring padding\" do\n    assert {:ok, \"foob\"} == hex_decode32(\"CPNMUOG\", padding: false)\n  end\n\n  test \"hex_decode32!/2 with one pad and ignoring padding\" do\n    assert \"foob\" == hex_decode32!(\"CPNMUOG\", padding: false)\n  end\n\n  test \"hex_decode32/2 with three pads and ignoring padding\" do\n    assert {:ok, \"foo\"} == hex_decode32(\"CPNMU\", padding: false)\n  end\n\n  test \"hex_decode32!/2 with three pads and ignoring padding\" do\n    assert \"foo\" == hex_decode32!(\"CPNMU\", padding: false)\n  end\n\n  test \"hex_decode32/2 with four pads and ignoring padding\" do\n    assert {:ok, \"fo\"} == hex_decode32(\"CPNG\", padding: false)\n  end\n\n  test \"hex_decode32!/2 with four pads and ignoring padding\" do\n    assert \"fo\" == hex_decode32!(\"CPNG\", padding: false)\n  end\n\n  test \"hex_decode32/2 with six pads and ignoring padding\" do\n    assert {:ok, \"foobar\"} == hex_decode32(\"CPNMUOJ1E8\", padding: false)\n  end\n\n  test \"hex_decode32!/2 with six pads and ignoring padding\" do\n    assert \"foobar\" == hex_decode32!(\"CPNMUOJ1E8\", padding: false)\n  end\n\n  test \"hex_decode32/2 with no pads and ignoring padding\" do\n    assert {:ok, \"fooba\"} == hex_decode32(\"CPNMUOJ1\", padding: false)\n  end\n\n  test \"hex_decode32!/2 with no pads and ignoring padding\" do\n    assert \"fooba\" == hex_decode32!(\"CPNMUOJ1\", padding: false)\n  end\n\n  test \"hex_decode32/2 ignores incorrect padding when :padding is false\" do\n    assert {:ok, \"foob\"} == hex_decode32(\"CPNMUOG\", padding: false)\n  end\n\n  test \"hex_decode32!/2 ignores incorrect padding when :padding is false\" do\n    \"foob\" = hex_decode32!(\"CPNMUOG\", padding: false)\n  end\n\n  test \"hex_decode32/2 with :lower case and ignoring padding\" do\n    assert {:ok, \"fo\"} == hex_decode32(\"cpng\", case: :lower, padding: false)\n  end\n\n  test \"hex_decode32!/2 with :lower case and ignoring padding\" do\n    assert \"fo\" == hex_decode32!(\"cpng\", case: :lower, padding: false)\n  end\n\n  test \"hex_decode32/2 with :mixed case and ignoring padding\" do\n    assert {:ok, \"fo\"} == hex_decode32(\"cPNg====\", case: :mixed, padding: false)\n  end\n\n  test \"hex_decode32!/2 with :mixed case and ignoring padding\" do\n    assert \"fo\" == hex_decode32!(\"cPNg\", case: :mixed, padding: false)\n  end\n\n  test \"hex_valid32?/1 can deal with empty strings\" do\n    assert hex_valid32?(\"\")\n  end\n\n  test \"hex_valid32?/1 with one pad\" do\n    assert hex_valid32?(\"CPNMUOG=\")\n  end\n\n  test \"hex_valid32?/1 with three pads\" do\n    assert hex_valid32?(\"CPNMU===\")\n  end\n\n  test \"hex_valid32?/1 with four pads\" do\n    assert hex_valid32?(\"CPNG====\")\n  end\n\n  test \"hex_valid32?/1 with six pads\" do\n    assert hex_valid32?(\"CPNMUOJ1E8======\")\n    assert hex_valid32?(\"CO======\")\n  end\n\n  test \"hex_valid32?/1 with no pads\" do\n    assert hex_valid32?(\"CPNMUOJ1\")\n  end\n\n  test \"hex_valid32?/1,2 returns false on non-alphabet character\" do\n    refute hex_valid32?(\"CPN)UOJ1\")\n    refute hex_valid32?(\"66f\")\n    refute hex_valid32?(\"66F\", case: :lower)\n  end\n\n  test \"hex_valid32?/1 returns false on incorrect padding\" do\n    refute hex_valid32?(\"CPNMUOG\")\n  end\n\n  test \"hex_valid32?/2 with lowercase\" do\n    assert hex_valid32?(\"cpng====\", case: :lower)\n  end\n\n  test \"hex_valid32?/2 with mixed case\" do\n    assert hex_valid32?(\"cPNg====\", case: :mixed)\n  end\n\n  test \"hex_valid32?/2 with one pad and ignoring padding\" do\n    assert hex_valid32?(\"CPNMUOG\", padding: false)\n  end\n\n  test \"hex_valid32?/2 with three pads and ignoring padding\" do\n    assert hex_valid32?(\"CPNMU\", padding: false)\n  end\n\n  test \"hex_valid32?/2 with four pads and ignoring padding\" do\n    assert hex_valid32?(\"CPNG\", padding: false)\n  end\n\n  test \"hex_valid32?/2 with six pads and ignoring padding\" do\n    assert hex_valid32?(\"CPNMUOJ1E8\", padding: false)\n  end\n\n  test \"hex_valid32?/2 with no pads and ignoring padding\" do\n    assert hex_valid32?(\"CPNMUOJ1\", padding: false)\n  end\n\n  test \"hex_valid32?/2 ignores incorrect padding when :padding is false\" do\n    assert hex_valid32?(\"CPNMUOG\", padding: false)\n  end\n\n  test \"hex_valid32?/2 with :lower case and ignoring padding\" do\n    assert hex_valid32?(\"cpng\", case: :lower, padding: false)\n  end\n\n  test \"hex_valid32?/2 with :mixed case and ignoring padding\" do\n    assert hex_valid32?(\"cPNg====\", case: :mixed, padding: false)\n  end\n\n  # TODO: add valid? tests\n  test \"encode then decode is identity\" do\n    for {encode, decode, valid?} <- [\n          {&encode16/2, &decode16!/2, &valid16?/2},\n          {&encode32/2, &decode32!/2, &valid32?/2},\n          {&hex_encode32/2, &hex_decode32!/2, &hex_valid32?/2},\n          {&encode64/2, &decode64!/2, &valid64?/2},\n          {&url_encode64/2, &url_decode64!/2, &url_valid64?/2}\n        ],\n        encode_case <- [:upper, :lower],\n        decode_case <- [:upper, :lower, :mixed],\n        encode_case == decode_case or decode_case == :mixed,\n        pad? <- [true, false],\n        len <- 0..256 do\n      data =\n        0\n        |> :lists.seq(len - 1)\n        |> Enum.shuffle()\n        |> IO.iodata_to_binary()\n\n      allowed_opts =\n        encode\n        |> Function.info()\n        |> Keyword.fetch!(:name)\n        |> case do\n          :encode16 -> [:case]\n          :encode64 -> [:padding]\n          :url_encode64 -> [:padding]\n          _ -> [:case, :padding]\n        end\n\n      encoded = encode.(data, Keyword.take([case: encode_case, padding: pad?], allowed_opts))\n\n      decode_opts = Keyword.take([case: decode_case, padding: pad?], allowed_opts)\n      assert valid?.(encoded, decode_opts)\n      expected = decode.(encoded, decode_opts)\n\n      assert data == expected,\n             \"identity did not match for #{inspect(data)} when #{inspect(encode)} (#{encode_case})\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/bitwise_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule BitwiseTest do\n  use ExUnit.Case, async: true\n\n  import Bitwise\n  doctest Bitwise\n\n  test \"bnot/1\" do\n    assert bnot(1) == -2\n  end\n\n  test \"band/2\" do\n    assert band(1, 1) == 1\n  end\n\n  test \"bor/2\" do\n    assert bor(0, 1) == 1\n  end\n\n  test \"bxor/2\" do\n    assert bxor(1, 1) == 0\n  end\n\n  test \"bsl/2\" do\n    assert bsl(1, 1) == 2\n  end\n\n  test \"bsr/2\" do\n    assert bsr(1, 1) == 0\n  end\n\n  test \"band (&&&)\" do\n    assert (1 &&& 1) == 1\n  end\n\n  test \"bor (|||)\" do\n    assert (0 ||| 1) == 1\n  end\n\n  test \"bsl (<<<)\" do\n    assert 1 <<< 1 == 2\n  end\n\n  test \"bsr (>>>)\" do\n    assert 1 >>> 1 == 0\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/date_range_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\nCode.require_file(\"holocene.exs\", __DIR__)\n\ndefmodule Date.RangeTest do\n  use ExUnit.Case, async: true\n\n  @asc_range Date.range(~D[2000-01-01], ~D[2001-01-01])\n  @asc_range_2 Date.range(~D[2000-01-01], ~D[2001-01-01], 2)\n  @desc_range Date.range(~D[2001-01-01], ~D[2000-01-01], -1)\n  @desc_range_2 Date.range(~D[2001-01-01], ~D[2000-01-01], -2)\n  @empty_range Date.range(~D[2001-01-01], ~D[2000-01-01], 1)\n\n  describe \"Enum.member?/2\" do\n    test \"for ascending range\" do\n      assert Enum.member?(@asc_range, ~D[2000-02-22])\n      assert Enum.member?(@asc_range, ~D[2000-01-01])\n      assert Enum.member?(@asc_range, ~D[2001-01-01])\n      refute Enum.member?(@asc_range, ~D[2002-01-01])\n      refute Enum.member?(@asc_range, Calendar.Holocene.date(12000, 1, 1))\n\n      assert Enum.member?(@asc_range_2, ~D[2000-01-03])\n      refute Enum.member?(@asc_range_2, ~D[2000-01-02])\n    end\n\n    test \"for descending range\" do\n      assert Enum.member?(@desc_range, ~D[2000-02-22])\n      assert Enum.member?(@desc_range, ~D[2000-01-01])\n      assert Enum.member?(@desc_range, ~D[2001-01-01])\n      refute Enum.member?(@desc_range, ~D[1999-01-01])\n      refute Enum.member?(@desc_range, Calendar.Holocene.date(12000, 1, 1))\n\n      assert Enum.member?(@desc_range_2, ~D[2000-12-30])\n      refute Enum.member?(@desc_range_2, ~D[2000-12-29])\n    end\n\n    test \"empty range\" do\n      refute Enum.member?(@empty_range, @empty_range.first)\n    end\n  end\n\n  describe \"Enum.count/1\" do\n    test \"for ascending range\" do\n      assert Enum.count(@asc_range) == 367\n      assert Enum.count(@asc_range_2) == 184\n    end\n\n    test \"for descending range\" do\n      assert Enum.count(@desc_range) == 367\n      assert Enum.count(@desc_range_2) == 184\n    end\n\n    test \"for empty range\" do\n      assert Enum.count(@empty_range) == 0\n    end\n  end\n\n  describe \"Enum.slice/3\" do\n    test \"for ascending range\" do\n      assert Enum.slice(@asc_range, 3, 3) == [~D[2000-01-04], ~D[2000-01-05], ~D[2000-01-06]]\n      assert Enum.slice(@asc_range, -3, 3) == [~D[2000-12-30], ~D[2000-12-31], ~D[2001-01-01]]\n\n      assert Enum.slice(@asc_range_2, 3, 3) == [~D[2000-01-07], ~D[2000-01-09], ~D[2000-01-11]]\n      assert Enum.slice(@asc_range_2, -3, 3) == [~D[2000-12-28], ~D[2000-12-30], ~D[2001-01-01]]\n    end\n\n    test \"for descending range\" do\n      assert Enum.slice(@desc_range, 3, 3) == [~D[2000-12-29], ~D[2000-12-28], ~D[2000-12-27]]\n      assert Enum.slice(@desc_range, -3, 3) == [~D[2000-01-03], ~D[2000-01-02], ~D[2000-01-01]]\n\n      assert Enum.slice(@desc_range_2, 3, 3) == [~D[2000-12-26], ~D[2000-12-24], ~D[2000-12-22]]\n      assert Enum.slice(@desc_range_2, -3, 3) == [~D[2000-01-05], ~D[2000-01-03], ~D[2000-01-01]]\n    end\n\n    test \"for empty range\" do\n      assert Enum.slice(@empty_range, 1, 3) == []\n      assert Enum.slice(@empty_range, 3, 3) == []\n      assert Enum.slice(@empty_range, -1, 3) == []\n      assert Enum.slice(@empty_range, -3, 3) == []\n    end\n  end\n\n  describe \"Enum.reduce/3\" do\n    test \"for ascending range\" do\n      assert Enum.take(@asc_range, 3) == [~D[2000-01-01], ~D[2000-01-02], ~D[2000-01-03]]\n\n      assert Enum.take(@asc_range_2, 3) == [~D[2000-01-01], ~D[2000-01-03], ~D[2000-01-05]]\n    end\n\n    test \"for descending range\" do\n      assert Enum.take(@desc_range, 3) == [~D[2001-01-01], ~D[2000-12-31], ~D[2000-12-30]]\n\n      assert Enum.take(@desc_range_2, 3) == [~D[2001-01-01], ~D[2000-12-30], ~D[2000-12-28]]\n    end\n\n    test \"for empty range\" do\n      assert Enum.take(@empty_range, 3) == []\n    end\n  end\n\n  test \"Enum.take/1 for empty range with negative step\" do\n    assert Enum.take(@empty_range, -1) == []\n  end\n\n  test \"works with date-like structs\" do\n    range = Date.range(~N[2000-01-01 09:00:00], ~U[2000-01-02 09:00:00Z])\n    assert range.first == ~D[2000-01-01]\n    assert range.last == ~D[2000-01-02]\n    assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-02]]\n\n    range = Date.range(~N[2000-01-01 09:00:00], ~U[2000-01-03 09:00:00Z], 2)\n    assert range.first == ~D[2000-01-01]\n    assert range.last == ~D[2000-01-03]\n    assert Enum.to_list(range) == [~D[2000-01-01], ~D[2000-01-03]]\n  end\n\n  test \"both dates must have matching calendars\" do\n    first = ~D[2000-01-01]\n    last = Calendar.Holocene.date(12001, 1, 1)\n\n    assert_raise ArgumentError, \"both dates must have matching calendars\", fn ->\n      Date.range(first, last)\n    end\n  end\n\n  test \"accepts equal but non Calendar.ISO calendars\" do\n    first = Calendar.Holocene.date(12000, 1, 1)\n    last = Calendar.Holocene.date(12001, 1, 1)\n    range = Date.range(first, last)\n    assert range\n    assert first in range\n    assert last in range\n    assert Enum.count(range) == 367\n  end\n\n  test \"step is a non-zero integer\" do\n    step = 1.0\n    message = ~r\"the step must be a non-zero integer\"\n\n    assert_raise ArgumentError, message, fn ->\n      Date.range(~D[2000-01-01], ~D[2000-01-31], step)\n    end\n\n    step = 0\n    message = ~r\"the step must be a non-zero integer\"\n\n    assert_raise ArgumentError, message, fn ->\n      Date.range(~D[2000-01-01], ~D[2000-01-31], step)\n    end\n  end\n\n  describe \"old date ranges\" do\n    test \"enumerable\" do\n      asc = %{\n        __struct__: Date.Range,\n        first: ~D[2021-07-14],\n        first_in_iso_days: 738_350,\n        last: ~D[2021-07-17],\n        last_in_iso_days: 738_353\n      }\n\n      desc = %{\n        __struct__: Date.Range,\n        first: ~D[2021-07-17],\n        first_in_iso_days: 738_353,\n        last: ~D[2021-07-14],\n        last_in_iso_days: 738_350\n      }\n\n      # member? implementations tests also empty?\n      assert Enumerable.member?(asc, ~D[2021-07-15])\n      assert {:ok, 4, _} = Enumerable.slice(asc)\n\n      assert Enum.reduce(asc, [], fn x, acc -> [x | acc] end) == [\n               ~D[2021-07-17],\n               ~D[2021-07-16],\n               ~D[2021-07-15],\n               ~D[2021-07-14]\n             ]\n\n      assert Enum.count(asc) == 4\n\n      # member? implementations tests also empty?\n      assert Enumerable.member?(desc, ~D[2021-07-15])\n      assert {:ok, 4, _} = Enumerable.slice(desc)\n\n      assert Enum.reduce(desc, [], fn x, acc -> [x | acc] end) == [\n               ~D[2021-07-14],\n               ~D[2021-07-15],\n               ~D[2021-07-16],\n               ~D[2021-07-17]\n             ]\n\n      assert Enum.count(desc) == 4\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/date_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\nCode.require_file(\"holocene.exs\", __DIR__)\nCode.require_file(\"fakes.exs\", __DIR__)\n\ndefmodule DateTest do\n  use ExUnit.Case, async: true\n  doctest Date\n\n  test \"sigil_D\" do\n    assert ~D[2000-01-01] ==\n             %Date{calendar: Calendar.ISO, year: 2000, month: 1, day: 1}\n\n    assert ~D[20001-01-01 Calendar.Holocene] ==\n             %Date{calendar: Calendar.Holocene, year: 20001, month: 1, day: 1}\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2000-50-50\" as Date for Calendar.ISO, reason: :invalid_date/,\n                 fn -> Code.eval_string(\"~D[2000-50-50]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2000-04-15 notalias\" as Date for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(\"~D[2000-04-15 notalias]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"20010415\" as Date for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(~s{~D[20010415]}) end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"20001-50-50\" as Date for Calendar.Holocene, reason: :invalid_date/,\n                 fn -> Code.eval_string(\"~D[20001-50-50 Calendar.Holocene]\") end\n\n    assert_raise UndefinedFunctionError, fn ->\n      Code.eval_string(\"~D[2000-01-01 UnknownCalendar]\")\n    end\n  end\n\n  test \"to_string/1\" do\n    date = ~D[2000-01-01]\n    assert to_string(date) == \"2000-01-01\"\n    assert Date.to_string(date) == \"2000-01-01\"\n    assert Date.to_string(Map.from_struct(date)) == \"2000-01-01\"\n\n    assert to_string(%{date | calendar: FakeCalendar}) == \"1/1/2000\"\n    assert Date.to_string(%{date | calendar: FakeCalendar}) == \"1/1/2000\"\n\n    date2 = Date.new!(5_874_897, 12, 31)\n    assert to_string(date2) == \"5874897-12-31\"\n    assert Date.to_string(date2) == \"5874897-12-31\"\n    assert Date.to_string(Map.from_struct(date2)) == \"5874897-12-31\"\n\n    assert to_string(%{date2 | calendar: FakeCalendar}) == \"31/12/5874897\"\n    assert Date.to_string(%{date2 | calendar: FakeCalendar}) == \"31/12/5874897\"\n  end\n\n  test \"inspect/1\" do\n    assert inspect(~D[2000-01-01]) == \"~D[2000-01-01]\"\n    assert inspect(~D[-0100-12-31]) == \"~D[-0100-12-31]\"\n\n    date = %{~D[2000-01-01] | calendar: FakeCalendar}\n    assert inspect(date) == \"~D[1/1/2000 FakeCalendar]\"\n\n    assert inspect(Date.new!(99999, 12, 31)) == \"Date.new!(99999, 12, 31)\"\n    assert inspect(Date.new!(-99999, 1, 1)) == \"Date.new!(-99999, 1, 1)\"\n\n    date2 = %{Date.new!(99999, 12, 31) | calendar: FakeCalendar}\n\n    assert inspect(%{date2 | calendar: FakeCalendar}) ==\n             \"~D[31/12/99999 FakeCalendar]\"\n  end\n\n  test \"compare/2\" do\n    date1 = ~D[-0001-12-30]\n    date2 = ~D[-0001-12-31]\n    date3 = ~D[0001-01-01]\n    date4 = Date.new!(5_874_897, 12, 31)\n    date5 = Date.new!(-4713, 1, 1)\n\n    assert Date.compare(date1, date1) == :eq\n    assert Date.compare(date1, date2) == :lt\n    assert Date.compare(date2, date1) == :gt\n    assert Date.compare(date3, date3) == :eq\n    assert Date.compare(date2, date3) == :lt\n    assert Date.compare(date3, date2) == :gt\n    assert Date.compare(date4, date1) == :gt\n    assert Date.compare(date1, date4) == :lt\n    assert Date.compare(date4, date4) == :eq\n    assert Date.compare(date4, date5) == :gt\n    assert Date.compare(date5, date4) == :lt\n    assert Date.compare(date5, date5) == :eq\n\n    assert_raise ArgumentError,\n                 ~r/cannot compare .*\\n\\n.* their calendars have incompatible day rollover moments/,\n                 fn -> Date.compare(date1, %{date2 | calendar: FakeCalendar}) end\n  end\n\n  test \"before?/2 and after?/2\" do\n    date1 = ~D[2022-11-01]\n    date2 = ~D[2022-11-02]\n    date3 = Date.new!(5_874_897, 12, 31)\n    date4 = Date.new!(-4713, 1, 1)\n\n    assert Date.before?(date1, date2)\n    assert Date.before?(date1, date3)\n    assert Date.before?(date4, date1)\n    assert not Date.before?(date2, date1)\n    assert not Date.before?(date3, date1)\n    assert not Date.before?(date1, date4)\n\n    assert Date.after?(date2, date1)\n    assert Date.after?(date3, date2)\n    assert Date.after?(date2, date4)\n    assert not Date.after?(date1, date2)\n    assert not Date.after?(date2, date3)\n    assert not Date.after?(date4, date2)\n  end\n\n  test \"compare/2 across calendars\" do\n    date1 = ~D[2000-01-01]\n    date2 = Calendar.Holocene.date(12000, 01, 01)\n    assert Date.compare(date1, date2) == :eq\n\n    date2 = Calendar.Holocene.date(12001, 01, 01)\n    assert Date.compare(date1, date2) == :lt\n    assert Date.compare(date2, date1) == :gt\n  end\n\n  test \"day_of_week/1\" do\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 10, 31)) == 1\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 01)) == 2\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 02)) == 3\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 03)) == 4\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 04)) == 5\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 05)) == 6\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 06)) == 7\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 07)) == 1\n\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 10, 30), :sunday) == 1\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 10, 31), :sunday) == 2\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 01), :sunday) == 3\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 02), :sunday) == 4\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 03), :sunday) == 5\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 04), :sunday) == 6\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 05), :sunday) == 7\n    assert Date.day_of_week(Calendar.Holocene.date(2016, 11, 06), :sunday) == 1\n  end\n\n  test \"beginning_of_week\" do\n    assert Date.beginning_of_week(Calendar.Holocene.date(2020, 07, 11)) ==\n             Calendar.Holocene.date(2020, 07, 06)\n\n    assert Date.beginning_of_week(Calendar.Holocene.date(2020, 07, 06)) ==\n             Calendar.Holocene.date(2020, 07, 06)\n\n    assert Date.beginning_of_week(Calendar.Holocene.date(2020, 07, 11), :sunday) ==\n             Calendar.Holocene.date(2020, 07, 05)\n\n    assert Date.beginning_of_week(Calendar.Holocene.date(2020, 07, 11), :saturday) ==\n             Calendar.Holocene.date(2020, 07, 11)\n  end\n\n  test \"end_of_week\" do\n    assert Date.end_of_week(Calendar.Holocene.date(2020, 07, 11)) ==\n             Calendar.Holocene.date(2020, 07, 12)\n\n    assert Date.end_of_week(Calendar.Holocene.date(2020, 07, 05)) ==\n             Calendar.Holocene.date(2020, 07, 05)\n\n    assert Date.end_of_week(Calendar.Holocene.date(2020, 07, 05), :sunday) ==\n             Calendar.Holocene.date(2020, 07, 11)\n\n    assert Date.end_of_week(Calendar.Holocene.date(2020, 07, 05), :saturday) ==\n             Calendar.Holocene.date(2020, 07, 10)\n  end\n\n  test \"convert/2\" do\n    assert Date.convert(~D[2000-01-01], Calendar.Holocene) ==\n             {:ok, Calendar.Holocene.date(12000, 01, 01)}\n\n    assert ~D[2000-01-01]\n           |> Date.convert!(Calendar.Holocene)\n           |> Date.convert!(Calendar.ISO) == ~D[2000-01-01]\n\n    assert Date.convert(~N[2000-01-01 00:00:00], Calendar.Holocene) ==\n             {:ok, Calendar.Holocene.date(12000, 01, 01)}\n\n    assert Date.convert(~D[2016-02-03], FakeCalendar) == {:error, :incompatible_calendars}\n\n    assert_raise ArgumentError,\n                 \"cannot convert ~D[2016-02-03] to target calendar FakeCalendar, reason: :incompatible_calendars\",\n                 fn -> Date.convert!(~D[2016-02-03], FakeCalendar) end\n  end\n\n  test \"add/2\" do\n    assert Date.add(~D[0000-01-01], 3_652_424) == ~D[9999-12-31]\n    assert Date.add(~D[0000-01-01], 3_652_425) == Date.new!(10000, 1, 1)\n    assert Date.add(~D[0000-01-01], -1) == ~D[-0001-12-31]\n    assert Date.add(~D[0000-01-01], -365) == ~D[-0001-01-01]\n    assert Date.add(~D[0000-01-01], -366) == ~D[-0002-12-31]\n    assert Date.add(~D[0000-01-01], -(365 * 4)) == ~D[-0004-01-02]\n    assert Date.add(~D[0000-01-01], -(365 * 5)) == ~D[-0005-01-02]\n    assert Date.add(~D[0000-01-01], -(365 * 100)) == ~D[-0100-01-25]\n    assert Date.add(~D[0000-01-01], -3_652_059) == ~D[-9999-01-01]\n    assert Date.add(~D[0000-01-01], -3_652_060) == Date.new!(-10000, 12, 31)\n    assert Date.add(Date.new!(5_874_897, 12, 31), 1) == Date.new!(5_874_898, 1, 1)\n  end\n\n  test \"diff/2\" do\n    assert Date.diff(~D[2000-01-31], ~D[2000-01-01]) == 30\n    assert Date.diff(~D[2000-01-01], ~D[2000-01-31]) == -30\n\n    assert Date.diff(~D[0000-01-01], ~D[-0001-01-01]) == 365\n    assert Date.diff(~D[-0003-01-01], ~D[-0004-01-01]) == 366\n\n    assert Date.diff(Date.new!(5_874_898, 1, 1), Date.new!(5_874_897, 1, 1)) == 365\n    assert Date.diff(Date.new!(5_874_905, 1, 1), Date.new!(5_874_904, 1, 1)) == 366\n\n    date1 = ~D[2000-01-01]\n    date2 = Calendar.Holocene.date(12000, 01, 14)\n    assert Date.diff(date1, date2) == -13\n    assert Date.diff(date2, date1) == 13\n\n    assert_raise ArgumentError,\n                 ~r/cannot calculate the difference between .* because their calendars are not compatible/,\n                 fn -> Date.diff(date1, %{date2 | calendar: FakeCalendar}) end\n  end\n\n  test \"shift/2\" do\n    assert Date.shift(~D[2012-02-29], day: -1) == ~D[2012-02-28]\n    assert Date.shift(~D[2012-02-29], month: -1) == ~D[2012-01-29]\n    assert Date.shift(~D[2012-02-29], week: -9) == ~D[2011-12-28]\n    assert Date.shift(~D[2012-02-29], month: 1) == ~D[2012-03-29]\n    assert Date.shift(~D[2012-02-29], year: -1) == ~D[2011-02-28]\n    assert Date.shift(~D[2012-02-29], year: 4) == ~D[2016-02-29]\n    assert Date.shift(~D[0000-01-01], day: -1) == ~D[-0001-12-31]\n    assert Date.shift(~D[0000-01-01], month: -1) == ~D[-0001-12-01]\n    assert Date.shift(~D[0000-01-01], year: -1) == ~D[-0001-01-01]\n    assert Date.shift(~D[0000-01-01], year: -1) == ~D[-0001-01-01]\n    assert Date.shift(~D[2000-01-01], month: 12) == ~D[2001-01-01]\n    assert Date.shift(~D[0000-01-01], day: 2, year: 1, month: 37) == ~D[0004-02-03]\n\n    assert Date.shift(Date.new!(5_874_904, 2, 29), day: -1) == Date.new!(5_874_904, 2, 28)\n    assert Date.shift(Date.new!(5_874_904, 2, 29), month: -2) == Date.new!(5_874_903, 12, 29)\n    assert Date.shift(Date.new!(5_874_904, 2, 29), week: -9) == Date.new!(5_874_903, 12, 28)\n    assert Date.shift(Date.new!(5_874_904, 2, 29), month: 1) == Date.new!(5_874_904, 3, 29)\n    assert Date.shift(Date.new!(5_874_904, 2, 29), year: -1) == Date.new!(5_874_903, 2, 28)\n    assert Date.shift(Date.new!(5_874_904, 2, 29), year: -4) == Date.new!(5_874_900, 2, 28)\n    assert Date.shift(Date.new!(5_874_904, 2, 29), year: 4) == Date.new!(5_874_908, 2, 29)\n\n    assert Date.shift(Date.new!(5_874_904, 2, 29), day: 1, year: 4, month: 2) ==\n             Date.new!(5_874_908, 4, 30)\n\n    assert_raise ArgumentError,\n                 \"unsupported unit :second. Expected :year, :month, :week, :day\",\n                 fn -> Date.shift(~D[2012-02-29], second: 86400) end\n\n    assert_raise ArgumentError,\n                 \"unknown unit :months. Expected :year, :month, :week, :day\",\n                 fn -> Date.shift(~D[2012-01-01], months: 12) end\n\n    assert_raise ArgumentError,\n                 \"unsupported value nil for :day. Expected an integer\",\n                 fn -> Date.shift(~D[2012-02-29], year: 1, day: nil) end\n\n    assert_raise ArgumentError,\n                 \"cannot shift date by time scale unit. Expected :year, :month, :week, :day\",\n                 fn -> Date.shift(~D[2012-02-29], %Duration{second: 86400}) end\n\n    # Microsecond precision is ignored\n    assert Date.shift(~D[2012-02-29], Duration.new!(microsecond: {0, 6})) == ~D[2012-02-29]\n\n    assert_raise ArgumentError,\n                 \"cannot shift date by time scale unit. Expected :year, :month, :week, :day\",\n                 fn -> Date.shift(~D[2012-02-29], %Duration{microsecond: {100, 6}}) end\n\n    # Implements calendar callback\n    assert_raise RuntimeError, \"shift_date/4 not implemented\", fn ->\n      date = Calendar.Holocene.date(10000, 01, 01)\n      Date.shift(date, month: 1)\n    end\n  end\n\n  test \"utc_today/1\" do\n    date = Date.utc_today()\n    assert date.year > 2020\n    assert date.calendar == Calendar.ISO\n\n    date = Date.utc_today(Calendar.ISO)\n    assert date.year > 2020\n    assert date.calendar == Calendar.ISO\n\n    date = Date.utc_today(Calendar.Holocene)\n    assert date.year > 12020\n    assert date.calendar == Calendar.Holocene\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/datetime_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\nCode.require_file(\"holocene.exs\", __DIR__)\nCode.require_file(\"fakes.exs\", __DIR__)\n\ndefmodule DateTimeTest do\n  use ExUnit.Case\n  doctest DateTime\n\n  test \"sigil_U\" do\n    assert ~U[2000-01-01T12:34:56Z] ==\n             %DateTime{\n               calendar: Calendar.ISO,\n               year: 2000,\n               month: 1,\n               day: 1,\n               hour: 12,\n               minute: 34,\n               second: 56,\n               std_offset: 0,\n               utc_offset: 0,\n               time_zone: \"Etc/UTC\",\n               zone_abbr: \"UTC\"\n             }\n\n    assert ~U[2000-01-01T12:34:56+00:00 Calendar.Holocene] ==\n             %DateTime{\n               calendar: Calendar.Holocene,\n               year: 2000,\n               month: 1,\n               day: 1,\n               hour: 12,\n               minute: 34,\n               second: 56,\n               std_offset: 0,\n               utc_offset: 0,\n               time_zone: \"Etc/UTC\",\n               zone_abbr: \"UTC\"\n             }\n\n    assert ~U[2000-01-01 12:34:56+00:00] ==\n             %DateTime{\n               calendar: Calendar.ISO,\n               year: 2000,\n               month: 1,\n               day: 1,\n               hour: 12,\n               minute: 34,\n               second: 56,\n               std_offset: 0,\n               utc_offset: 0,\n               time_zone: \"Etc/UTC\",\n               zone_abbr: \"UTC\"\n             }\n\n    assert ~U[2000-01-01 12:34:56Z Calendar.Holocene] ==\n             %DateTime{\n               calendar: Calendar.Holocene,\n               year: 2000,\n               month: 1,\n               day: 1,\n               hour: 12,\n               minute: 34,\n               second: 56,\n               std_offset: 0,\n               utc_offset: 0,\n               time_zone: \"Etc/UTC\",\n               zone_abbr: \"UTC\"\n             }\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-50-50T12:34:56Z\" as UTC DateTime for Calendar.ISO, reason: :invalid_date/,\n                 fn -> Code.eval_string(\"~U[2001-50-50T12:34:56Z]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01T12:34:65Z\" as UTC DateTime for Calendar.ISO, reason: :invalid_time/,\n                 fn -> Code.eval_string(\"~U[2001-01-01T12:34:65Z]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01T12:34:56\\+01:00\" as UTC DateTime for Calendar.ISO, reason: :non_utc_offset/,\n                 fn -> Code.eval_string(\"~U[2001-01-01T12:34:56+01:00]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01 12:34:56Z notalias\" as UTC DateTime for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(\"~U[2001-01-01 12:34:56Z notalias]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01T12:34:56Z notalias\" as UTC DateTime for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(\"~U[2001-01-01T12:34:56Z notalias]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-50-50T12:34:56Z\" as UTC DateTime for Calendar.Holocene, reason: :invalid_date/,\n                 fn -> Code.eval_string(\"~U[2001-50-50T12:34:56Z Calendar.Holocene]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01T12:34:65Z\" as UTC DateTime for Calendar.Holocene, reason: :invalid_time/,\n                 fn -> Code.eval_string(\"~U[2001-01-01T12:34:65Z Calendar.Holocene]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01T12:34:56+01:00 Calendar.Holocene\" as UTC DateTime for Calendar.Holocene, reason: :non_utc_offset/,\n                 fn -> Code.eval_string(\"~U[2001-01-01T12:34:56+01:00 Calendar.Holocene]\") end\n\n    assert_raise UndefinedFunctionError, fn ->\n      Code.eval_string(\"~U[2001-01-01 12:34:56 UnknownCalendar]\")\n    end\n\n    assert_raise UndefinedFunctionError, fn ->\n      Code.eval_string(\"~U[2001-01-01T12:34:56 UnknownCalendar]\")\n    end\n  end\n\n  test \"to_string/1\" do\n    datetime = %DateTime{\n      year: 2000,\n      month: 2,\n      day: 29,\n      zone_abbr: \"BRM\",\n      hour: 23,\n      minute: 0,\n      second: 7,\n      microsecond: {0, 0},\n      utc_offset: -12600,\n      std_offset: 3600,\n      time_zone: \"Brazil/Manaus\"\n    }\n\n    assert to_string(datetime) == \"2000-02-29 23:00:07-02:30 BRM Brazil/Manaus\"\n    assert DateTime.to_string(datetime) == \"2000-02-29 23:00:07-02:30 BRM Brazil/Manaus\"\n\n    assert DateTime.to_string(Map.from_struct(datetime)) ==\n             \"2000-02-29 23:00:07-02:30 BRM Brazil/Manaus\"\n\n    assert to_string(%{datetime | calendar: FakeCalendar}) ==\n             \"29/2/2000F23::0::7 Brazil/Manaus BRM -12600 3600\"\n\n    assert DateTime.to_string(%{datetime | calendar: FakeCalendar}) ==\n             \"29/2/2000F23::0::7 Brazil/Manaus BRM -12600 3600\"\n  end\n\n  test \"inspect/1\" do\n    utc_datetime = ~U[2000-01-01 23:00:07.005Z]\n    assert inspect(utc_datetime) == \"~U[2000-01-01 23:00:07.005Z]\"\n\n    assert inspect(%{utc_datetime | year: 99999}) == \"#DateTime<99999-01-01 23:00:07.005Z>\"\n\n    assert inspect(%{utc_datetime | calendar: FakeCalendar}) ==\n             \"~U[1/1/2000F23::0::7 Etc/UTC UTC 0 0 FakeCalendar]\"\n\n    datetime = %DateTime{\n      year: 2000,\n      month: 2,\n      day: 29,\n      zone_abbr: \"BRM\",\n      hour: 23,\n      minute: 0,\n      second: 7,\n      microsecond: {0, 0},\n      utc_offset: -12600,\n      std_offset: 3600,\n      time_zone: \"Brazil/Manaus\"\n    }\n\n    assert inspect(datetime) == \"#DateTime<2000-02-29 23:00:07-02:30 BRM Brazil/Manaus>\"\n\n    assert inspect(%{datetime | calendar: FakeCalendar}) ==\n             \"#DateTime<29/2/2000F23::0::7 Brazil/Manaus BRM -12600 3600 FakeCalendar>\"\n  end\n\n  test \"from_iso8601/1 handles positive and negative offsets\" do\n    assert DateTime.from_iso8601(\"2015-01-24T09:50:07-10:00\") |> elem(1) ==\n             %DateTime{\n               microsecond: {0, 0},\n               month: 1,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               utc_offset: 0,\n               year: 2015,\n               zone_abbr: \"UTC\",\n               day: 24,\n               hour: 19,\n               minute: 50,\n               second: 7\n             }\n\n    assert DateTime.from_iso8601(\"2015-01-24T09:50:07+10:00\") |> elem(1) ==\n             %DateTime{\n               microsecond: {0, 0},\n               month: 1,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               utc_offset: 0,\n               year: 2015,\n               zone_abbr: \"UTC\",\n               day: 23,\n               hour: 23,\n               minute: 50,\n               second: 7\n             }\n\n    assert DateTime.from_iso8601(\"0000-01-01T01:22:07+10:30\") |> elem(1) ==\n             %DateTime{\n               microsecond: {0, 0},\n               month: 12,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               utc_offset: 0,\n               year: -1,\n               zone_abbr: \"UTC\",\n               day: 31,\n               hour: 14,\n               minute: 52,\n               second: 7\n             }\n  end\n\n  test \"from_iso8601/1 handles negative dates\" do\n    assert DateTime.from_iso8601(\"-2015-01-24T09:50:07-10:00\") |> elem(1) ==\n             %DateTime{\n               microsecond: {0, 0},\n               month: 1,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               utc_offset: 0,\n               year: -2015,\n               zone_abbr: \"UTC\",\n               day: 24,\n               hour: 19,\n               minute: 50,\n               second: 7\n             }\n\n    assert DateTime.from_iso8601(\"-2015-01-24T09:50:07+10:00\") |> elem(1) ==\n             %DateTime{\n               microsecond: {0, 0},\n               month: 1,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               utc_offset: 0,\n               year: -2015,\n               zone_abbr: \"UTC\",\n               day: 23,\n               hour: 23,\n               minute: 50,\n               second: 7\n             }\n\n    assert DateTime.from_iso8601(\"-0001-01-01T01:22:07+10:30\") |> elem(1) ==\n             %DateTime{\n               microsecond: {0, 0},\n               month: 12,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               utc_offset: 0,\n               year: -2,\n               zone_abbr: \"UTC\",\n               day: 31,\n               hour: 14,\n               minute: 52,\n               second: 7\n             }\n\n    assert DateTime.from_iso8601(\"-0001-01-01T01:22:07-10:30\") |> elem(1) ==\n             %DateTime{\n               microsecond: {0, 0},\n               month: 1,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               utc_offset: 0,\n               year: -1,\n               zone_abbr: \"UTC\",\n               day: 1,\n               hour: 11,\n               minute: 52,\n               second: 7\n             }\n\n    assert DateTime.from_iso8601(\"-0001-12-31T23:22:07-10:30\") |> elem(1) ==\n             %DateTime{\n               microsecond: {0, 0},\n               month: 1,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               utc_offset: 0,\n               year: 0,\n               zone_abbr: \"UTC\",\n               day: 1,\n               hour: 9,\n               minute: 52,\n               second: 7\n             }\n  end\n\n  test \"from_iso8601/3 with basic format handles positive and negative offsets\" do\n    assert DateTime.from_iso8601(\"20150124T095007-1000\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"2015-01-24T09:50:07-10:00\", Calendar.ISO)\n\n    assert DateTime.from_iso8601(\"20150124T095007+1000\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"2015-01-24T09:50:07+10:00\", Calendar.ISO)\n\n    assert DateTime.from_iso8601(\"00000101T012207+1030\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"0000-01-01T01:22:07+10:30\", Calendar.ISO)\n  end\n\n  test \"from_iso8601/3 with basic format handles negative dates\" do\n    assert DateTime.from_iso8601(\"-20150124T095007-1000\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"-2015-01-24T09:50:07-10:00\", Calendar.ISO)\n\n    assert DateTime.from_iso8601(\"-20150124T095007+1000\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"-2015-01-24T09:50:07+10:00\", Calendar.ISO)\n\n    assert DateTime.from_iso8601(\"-00010101T012207+1030\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"-0001-01-01T01:22:07+10:30\", Calendar.ISO)\n\n    assert DateTime.from_iso8601(\"-00010101T012207-1030\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"-0001-01-01T01:22:07-10:30\", Calendar.ISO)\n\n    assert DateTime.from_iso8601(\"-00011231T232207-1030\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"-0001-12-31T23:22:07-10:30\", Calendar.ISO)\n  end\n\n  test \"from_iso8601/2 handles either a calendar or a format as the second parameter\" do\n    assert DateTime.from_iso8601(\"20150124T095007-1000\", :basic) ==\n             DateTime.from_iso8601(\"2015-01-24T09:50:07-10:00\", Calendar.ISO)\n  end\n\n  test \"from_iso8601 handles invalid date, time, formats correctly\" do\n    assert DateTime.from_iso8601(\"2015-01-23T23:50:07\") == {:error, :missing_offset}\n    assert DateTime.from_iso8601(\"2015-01-23 23:50:61\") == {:error, :invalid_time}\n    assert DateTime.from_iso8601(\"2015-01-32 23:50:07\") == {:error, :invalid_date}\n    assert DateTime.from_iso8601(\"2015-01-23 23:50:07A\") == {:error, :invalid_format}\n    assert DateTime.from_iso8601(\"2015-01-23T23:50:07.123-00:60\") == {:error, :invalid_format}\n\n    assert DateTime.from_iso8601(\"20150123T235007\", Calendar.ISO, :basic) ==\n             {:error, :missing_offset}\n\n    assert DateTime.from_iso8601(\"20150123 235061\", Calendar.ISO, :basic) ==\n             {:error, :invalid_time}\n\n    assert DateTime.from_iso8601(\"20150132 235007\", Calendar.ISO, :basic) ==\n             {:error, :invalid_date}\n\n    assert DateTime.from_iso8601(\"20150123 235007A\", Calendar.ISO, :basic) ==\n             {:error, :invalid_format}\n\n    assert DateTime.from_iso8601(\"2015-01-24T09:50:07-10:00\", Calendar.ISO, :basic) ==\n             {:error, :invalid_format}\n\n    assert DateTime.from_iso8601(\"20150123T235007.123-0060\", Calendar.ISO, :basic) ==\n             {:error, :invalid_format}\n  end\n\n  test \"from_unix/2\" do\n    min_datetime = %DateTime{\n      calendar: Calendar.ISO,\n      day: 1,\n      hour: 0,\n      microsecond: {0, 0},\n      minute: 0,\n      month: 1,\n      second: 0,\n      std_offset: 0,\n      time_zone: \"Etc/UTC\",\n      utc_offset: 0,\n      year: -9999,\n      zone_abbr: \"UTC\"\n    }\n\n    assert DateTime.from_unix(-377_705_116_800) == {:ok, min_datetime}\n\n    assert DateTime.from_unix(-377_705_116_800_000_001, :microsecond) ==\n             {:error, :invalid_unix_time}\n\n    assert DateTime.from_unix(143_256_036_886_856, 1024) ==\n             {:ok,\n              %DateTime{\n                calendar: Calendar.ISO,\n                day: 17,\n                hour: 7,\n                microsecond: {320_312, 6},\n                minute: 5,\n                month: 3,\n                second: 22,\n                std_offset: 0,\n                time_zone: \"Etc/UTC\",\n                utc_offset: 0,\n                year: 6403,\n                zone_abbr: \"UTC\"\n              }}\n\n    max_datetime = %DateTime{\n      calendar: Calendar.ISO,\n      day: 31,\n      hour: 23,\n      microsecond: {999_999, 6},\n      minute: 59,\n      month: 12,\n      second: 59,\n      std_offset: 0,\n      time_zone: \"Etc/UTC\",\n      utc_offset: 0,\n      year: 9999,\n      zone_abbr: \"UTC\"\n    }\n\n    assert DateTime.from_unix(253_402_300_799_999_999, :microsecond) == {:ok, max_datetime}\n\n    assert DateTime.from_unix(253_402_300_800) == {:error, :invalid_unix_time}\n\n    minus_datetime = %DateTime{\n      calendar: Calendar.ISO,\n      day: 31,\n      hour: 23,\n      microsecond: {999_999, 6},\n      minute: 59,\n      month: 12,\n      second: 59,\n      std_offset: 0,\n      time_zone: \"Etc/UTC\",\n      utc_offset: 0,\n      year: 1969,\n      zone_abbr: \"UTC\"\n    }\n\n    assert DateTime.from_unix(-1, :microsecond) == {:ok, minus_datetime}\n\n    assert_raise ArgumentError, fn ->\n      DateTime.from_unix(0, :unknown_atom)\n    end\n\n    assert_raise ArgumentError, fn ->\n      DateTime.from_unix(0, \"invalid type\")\n    end\n  end\n\n  test \"from_unix!/2\" do\n    # with Unix times back to 0 Gregorian seconds\n    datetime = %DateTime{\n      calendar: Calendar.ISO,\n      day: 1,\n      hour: 0,\n      microsecond: {0, 0},\n      minute: 0,\n      month: 1,\n      second: 0,\n      std_offset: 0,\n      time_zone: \"Etc/UTC\",\n      utc_offset: 0,\n      year: 0,\n      zone_abbr: \"UTC\"\n    }\n\n    assert DateTime.from_unix!(-62_167_219_200) == datetime\n\n    assert_raise ArgumentError, fn ->\n      DateTime.from_unix!(-377_705_116_801)\n    end\n\n    assert_raise ArgumentError, fn ->\n      DateTime.from_unix!(0, :unknown_atom)\n    end\n\n    assert_raise ArgumentError, fn ->\n      DateTime.from_unix!(0, \"invalid type\")\n    end\n  end\n\n  test \"to_unix/2 works with Unix times back to 0 Gregorian seconds\" do\n    # with Unix times back to 0 Gregorian seconds\n    gregorian_0 = %DateTime{\n      calendar: Calendar.ISO,\n      day: 1,\n      hour: 0,\n      microsecond: {0, 0},\n      minute: 0,\n      month: 1,\n      second: 0,\n      std_offset: 0,\n      time_zone: \"Etc/UTC\",\n      utc_offset: 0,\n      year: 0,\n      zone_abbr: \"UTC\"\n    }\n\n    assert DateTime.to_unix(gregorian_0) == -62_167_219_200\n    assert DateTime.to_unix(Map.from_struct(gregorian_0)) == -62_167_219_200\n\n    min_datetime = %{gregorian_0 | year: -9999}\n    assert DateTime.to_unix(min_datetime) == -377_705_116_800\n  end\n\n  test \"compare/2\" do\n    datetime1 = %DateTime{\n      year: 2000,\n      month: 2,\n      day: 29,\n      zone_abbr: \"CET\",\n      hour: 23,\n      minute: 0,\n      second: 7,\n      microsecond: {0, 0},\n      utc_offset: 3600,\n      std_offset: 0,\n      time_zone: \"Europe/Warsaw\"\n    }\n\n    datetime2 = %DateTime{\n      year: 2000,\n      month: 2,\n      day: 29,\n      zone_abbr: \"AMT\",\n      hour: 23,\n      minute: 0,\n      second: 7,\n      microsecond: {0, 0},\n      utc_offset: -14400,\n      std_offset: 0,\n      time_zone: \"America/Manaus\"\n    }\n\n    datetime3 = %DateTime{\n      year: -99,\n      month: 2,\n      day: 28,\n      zone_abbr: \"AMT\",\n      hour: 23,\n      minute: 0,\n      second: 7,\n      microsecond: {0, 0},\n      utc_offset: -14400,\n      std_offset: 0,\n      time_zone: \"America/Manaus\"\n    }\n\n    assert DateTime.compare(datetime1, datetime1) == :eq\n    assert DateTime.compare(datetime1, datetime2) == :lt\n    assert DateTime.compare(datetime2, datetime1) == :gt\n    assert DateTime.compare(datetime3, datetime3) == :eq\n    assert DateTime.compare(datetime2, datetime3) == :gt\n    assert DateTime.compare(datetime3, datetime1) == :lt\n    assert DateTime.compare(Map.from_struct(datetime3), Map.from_struct(datetime1)) == :lt\n  end\n\n  test \"before?/2 and after?/2\" do\n    datetime1 = ~U[2015-01-02T12:34:56Z]\n    datetime2 = ~U[2015-01-02T12:55:55Z]\n\n    assert DateTime.before?(datetime1, datetime2)\n    assert not DateTime.before?(datetime2, datetime1)\n\n    assert DateTime.after?(datetime2, datetime1)\n    assert not DateTime.after?(datetime1, datetime2)\n  end\n\n  test \"convert/2\" do\n    datetime_iso = %DateTime{\n      year: 2000,\n      month: 2,\n      day: 29,\n      zone_abbr: \"CET\",\n      hour: 23,\n      minute: 0,\n      second: 7,\n      microsecond: {0, 0},\n      utc_offset: 3600,\n      std_offset: 0,\n      time_zone: \"Europe/Warsaw\"\n    }\n\n    datetime_hol = %DateTime{\n      year: 12000,\n      month: 2,\n      day: 29,\n      zone_abbr: \"CET\",\n      hour: 23,\n      minute: 0,\n      second: 7,\n      microsecond: {0, 0},\n      utc_offset: 3600,\n      std_offset: 0,\n      time_zone: \"Europe/Warsaw\",\n      calendar: Calendar.Holocene\n    }\n\n    assert DateTime.convert(datetime_iso, Calendar.Holocene) == {:ok, datetime_hol}\n\n    assert datetime_iso\n           |> DateTime.convert!(Calendar.Holocene)\n           |> DateTime.convert!(Calendar.ISO) == datetime_iso\n\n    assert %{datetime_iso | microsecond: {123, 6}}\n           |> DateTime.convert!(Calendar.Holocene)\n           |> DateTime.convert!(Calendar.ISO) == %{datetime_iso | microsecond: {123, 6}}\n\n    assert DateTime.convert(datetime_iso, FakeCalendar) == {:error, :incompatible_calendars}\n\n    # Test passing non-struct map when converting to different calendar returns DateTime struct\n    assert DateTime.convert(Map.from_struct(datetime_iso), Calendar.Holocene) ==\n             {:ok, datetime_hol}\n\n    # Test passing non-struct map when converting to same calendar returns DateTime struct\n    assert DateTime.convert(Map.from_struct(datetime_iso), Calendar.ISO) ==\n             {:ok, datetime_iso}\n  end\n\n  test \"from_iso8601/1 with tz offsets\" do\n    assert DateTime.from_iso8601(\"2017-06-02T14:00:00+01:00\")\n           |> elem(1) ==\n             %DateTime{\n               year: 2017,\n               month: 6,\n               day: 2,\n               zone_abbr: \"UTC\",\n               hour: 13,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               utc_offset: 0,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\"\n             }\n\n    assert DateTime.from_iso8601(\"2017-06-02T14:00:00-04:00\")\n           |> elem(1) ==\n             %DateTime{\n               year: 2017,\n               month: 6,\n               day: 2,\n               zone_abbr: \"UTC\",\n               hour: 18,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               utc_offset: 0,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\"\n             }\n\n    assert DateTime.from_iso8601(\"2017-06-02T14:00:00+0100\")\n           |> elem(1) ==\n             %DateTime{\n               year: 2017,\n               month: 6,\n               day: 2,\n               zone_abbr: \"UTC\",\n               hour: 13,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               utc_offset: 0,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\"\n             }\n\n    assert DateTime.from_iso8601(\"2017-06-02T14:00:00-0400\")\n           |> elem(1) ==\n             %DateTime{\n               year: 2017,\n               month: 6,\n               day: 2,\n               zone_abbr: \"UTC\",\n               hour: 18,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               utc_offset: 0,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\"\n             }\n\n    assert DateTime.from_iso8601(\"2017-06-02T14:00:00+01\")\n           |> elem(1) ==\n             %DateTime{\n               year: 2017,\n               month: 6,\n               day: 2,\n               zone_abbr: \"UTC\",\n               hour: 13,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               utc_offset: 0,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\"\n             }\n\n    assert DateTime.from_iso8601(\"2017-06-02T14:00:00-04\")\n           |> elem(1) ==\n             %DateTime{\n               year: 2017,\n               month: 6,\n               day: 2,\n               zone_abbr: \"UTC\",\n               hour: 18,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               utc_offset: 0,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\"\n             }\n  end\n\n  test \"from_iso8601/3 with basic format with tz offsets\" do\n    assert DateTime.from_iso8601(\"20170602T140000+0100\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"2017-06-02T14:00:00+01:00\", Calendar.ISO)\n\n    assert DateTime.from_iso8601(\"20170602T140000-0400\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"2017-06-02T14:00:00-04:00\")\n\n    assert DateTime.from_iso8601(\"20170602T140000+01\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"2017-06-02T14:00:00+01\")\n\n    assert DateTime.from_iso8601(\"20170602T140000-04\", Calendar.ISO, :basic) ==\n             DateTime.from_iso8601(\"2017-06-02T14:00:00-04\")\n  end\n\n  test \"truncate/2\" do\n    datetime = %DateTime{\n      year: 2017,\n      month: 11,\n      day: 6,\n      zone_abbr: \"CET\",\n      hour: 0,\n      minute: 6,\n      second: 23,\n      microsecond: {0, 0},\n      utc_offset: 3600,\n      std_offset: 0,\n      time_zone: \"Europe/Paris\"\n    }\n\n    datetime_map = Map.from_struct(datetime)\n\n    assert DateTime.truncate(%{datetime | microsecond: {123_456, 6}}, :microsecond) ==\n             %{datetime | microsecond: {123_456, 6}}\n\n    # A struct should be returned when passing a map.\n    assert DateTime.truncate(%{datetime_map | microsecond: {123_456, 6}}, :microsecond) ==\n             %{datetime | microsecond: {123_456, 6}}\n\n    assert DateTime.truncate(%{datetime | microsecond: {0, 0}}, :millisecond) ==\n             %{datetime | microsecond: {0, 0}}\n\n    assert DateTime.truncate(%{datetime | microsecond: {000_100, 6}}, :millisecond) ==\n             %{datetime | microsecond: {0, 3}}\n\n    assert DateTime.truncate(%{datetime | microsecond: {000_999, 6}}, :millisecond) ==\n             %{datetime | microsecond: {0, 3}}\n\n    assert DateTime.truncate(%{datetime | microsecond: {001_000, 6}}, :millisecond) ==\n             %{datetime | microsecond: {1000, 3}}\n\n    assert DateTime.truncate(%{datetime | microsecond: {001_200, 6}}, :millisecond) ==\n             %{datetime | microsecond: {1000, 3}}\n\n    assert DateTime.truncate(%{datetime | microsecond: {123_456, 6}}, :millisecond) ==\n             %{datetime | microsecond: {123_000, 3}}\n\n    assert DateTime.truncate(%{datetime | microsecond: {123_456, 6}}, :second) ==\n             %{datetime | microsecond: {0, 0}}\n  end\n\n  describe \"diff\" do\n    test \"with invalid time unit\" do\n      dt = DateTime.utc_now()\n\n      message =\n        ~r/unsupported time unit\\. Expected :day, :hour, :minute, :second, :millisecond, :microsecond, :nanosecond, or a positive integer, got \"day\"/\n\n      assert_raise ArgumentError, message, fn -> DateTime.diff(dt, dt, \"day\") end\n    end\n\n    test \"with valid time unit\" do\n      dt1 = %DateTime{\n        year: 100,\n        month: 2,\n        day: 28,\n        zone_abbr: \"CET\",\n        hour: 23,\n        minute: 0,\n        second: 7,\n        microsecond: {0, 0},\n        utc_offset: 3600,\n        std_offset: 0,\n        time_zone: \"Europe/Warsaw\"\n      }\n\n      dt2 = %DateTime{\n        year: -0004,\n        month: 2,\n        day: 29,\n        zone_abbr: \"CET\",\n        hour: 23,\n        minute: 0,\n        second: 7,\n        microsecond: {0, 0},\n        utc_offset: 3600,\n        std_offset: 0,\n        time_zone: \"Europe/Warsaw\"\n      }\n\n      assert DateTime.diff(dt1, dt2) == 3_281_904_000\n\n      # Test with a non-struct map conforming to Calendar.datetime\n      assert DateTime.diff(Map.from_struct(dt1), Map.from_struct(dt2)) == 3_281_904_000\n    end\n\n    test \"with microseconds\" do\n      datetime = ~U[2023-02-01 10:30:10.123456Z]\n\n      in_almost_7_days =\n        datetime\n        |> DateTime.add(7, :day)\n        |> DateTime.add(-1, :microsecond)\n\n      assert DateTime.diff(in_almost_7_days, datetime, :day) == 6\n    end\n\n    test \"in microseconds\" do\n      datetime1 = ~U[2023-02-01 10:30:10.000000Z]\n      datetime2 = DateTime.add(datetime1, 1234, :microsecond)\n\n      assert DateTime.diff(datetime1, datetime2, :microsecond) == -1234\n    end\n  end\n\n  describe \"from_naive\" do\n    test \"uses default time zone database from config\" do\n      Calendar.put_time_zone_database(FakeTimeZoneDatabase)\n\n      assert DateTime.from_naive(\n               ~N[2018-07-01 12:34:25.123456],\n               \"Europe/Copenhagen\",\n               FakeTimeZoneDatabase\n             ) ==\n               {:ok,\n                %DateTime{\n                  day: 1,\n                  hour: 12,\n                  microsecond: {123_456, 6},\n                  minute: 34,\n                  month: 7,\n                  second: 25,\n                  std_offset: 3600,\n                  time_zone: \"Europe/Copenhagen\",\n                  utc_offset: 3600,\n                  year: 2018,\n                  zone_abbr: \"CEST\"\n                }}\n    after\n      Calendar.put_time_zone_database(Calendar.UTCOnlyTimeZoneDatabase)\n    end\n\n    test \"with compatible calendar on unambiguous wall clock\" do\n      holocene_ndt = %NaiveDateTime{\n        calendar: Calendar.Holocene,\n        year: 12018,\n        month: 7,\n        day: 1,\n        hour: 12,\n        minute: 34,\n        second: 25,\n        microsecond: {123_456, 6}\n      }\n\n      assert DateTime.from_naive(holocene_ndt, \"Europe/Copenhagen\", FakeTimeZoneDatabase) ==\n               {:ok,\n                %DateTime{\n                  calendar: Calendar.Holocene,\n                  day: 1,\n                  hour: 12,\n                  microsecond: {123_456, 6},\n                  minute: 34,\n                  month: 7,\n                  second: 25,\n                  std_offset: 3600,\n                  time_zone: \"Europe/Copenhagen\",\n                  utc_offset: 3600,\n                  year: 12018,\n                  zone_abbr: \"CEST\"\n                }}\n    end\n\n    test \"with compatible calendar on ambiguous wall clock\" do\n      holocene_ndt = %NaiveDateTime{\n        calendar: Calendar.Holocene,\n        year: 12018,\n        month: 10,\n        day: 28,\n        hour: 02,\n        minute: 30,\n        second: 00,\n        microsecond: {123_456, 6}\n      }\n\n      assert {:ambiguous, first_dt, second_dt} =\n               DateTime.from_naive(holocene_ndt, \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n\n      assert %DateTime{calendar: Calendar.Holocene, zone_abbr: \"CEST\"} = first_dt\n      assert %DateTime{calendar: Calendar.Holocene, zone_abbr: \"CET\"} = second_dt\n    end\n\n    test \"with compatible calendar on gap\" do\n      holocene_ndt = %NaiveDateTime{\n        calendar: Calendar.Holocene,\n        year: 12019,\n        month: 03,\n        day: 31,\n        hour: 02,\n        minute: 30,\n        second: 00,\n        microsecond: {123_456, 6}\n      }\n\n      assert {:gap, first_dt, second_dt} =\n               DateTime.from_naive(holocene_ndt, \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n\n      assert %DateTime{calendar: Calendar.Holocene, zone_abbr: \"CET\"} = first_dt\n      assert %DateTime{calendar: Calendar.Holocene, zone_abbr: \"CEST\"} = second_dt\n    end\n\n    test \"with incompatible calendar\" do\n      ndt = %{~N[2018-07-20 00:00:00] | calendar: FakeCalendar}\n\n      assert DateTime.from_naive(ndt, \"Europe/Copenhagen\", FakeTimeZoneDatabase) ==\n               {:error, :incompatible_calendars}\n    end\n  end\n\n  describe \"from_naive!\" do\n    test \"raises on ambiguous wall clock\" do\n      assert_raise ArgumentError, ~r\"ambiguous\", fn ->\n        DateTime.from_naive!(~N[2018-10-28 02:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      end\n    end\n\n    test \"raises on gap\" do\n      assert_raise ArgumentError, ~r\"gap\", fn ->\n        DateTime.from_naive!(~N[2019-03-31 02:30:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n      end\n    end\n  end\n\n  describe \"shift_zone\" do\n    test \"with compatible calendar\" do\n      holocene_ndt = %NaiveDateTime{\n        calendar: Calendar.Holocene,\n        year: 12018,\n        month: 7,\n        day: 1,\n        hour: 12,\n        minute: 34,\n        second: 25,\n        microsecond: {123_456, 6}\n      }\n\n      {:ok, holocene_dt} =\n        DateTime.from_naive(holocene_ndt, \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n\n      {:ok, dt} = DateTime.shift_zone(holocene_dt, \"America/Los_Angeles\", FakeTimeZoneDatabase)\n\n      assert dt == %DateTime{\n               calendar: Calendar.Holocene,\n               day: 1,\n               hour: 3,\n               microsecond: {123_456, 6},\n               minute: 34,\n               month: 7,\n               second: 25,\n               std_offset: 3600,\n               time_zone: \"America/Los_Angeles\",\n               utc_offset: -28800,\n               year: 12018,\n               zone_abbr: \"PDT\"\n             }\n    end\n\n    test \"uses default time zone database from config\" do\n      Calendar.put_time_zone_database(FakeTimeZoneDatabase)\n\n      {:ok, dt} = DateTime.from_naive(~N[2018-07-01 12:34:25.123456], \"Europe/Copenhagen\")\n      {:ok, dt} = DateTime.shift_zone(dt, \"America/Los_Angeles\")\n\n      assert dt == %DateTime{\n               day: 1,\n               hour: 3,\n               microsecond: {123_456, 6},\n               minute: 34,\n               month: 7,\n               second: 25,\n               std_offset: 3600,\n               time_zone: \"America/Los_Angeles\",\n               utc_offset: -28800,\n               year: 2018,\n               zone_abbr: \"PDT\"\n             }\n    after\n      Calendar.put_time_zone_database(Calendar.UTCOnlyTimeZoneDatabase)\n    end\n  end\n\n  describe \"add\" do\n    test \"with non-struct map that conforms to Calendar.datetime\" do\n      dt_map = DateTime.from_naive!(~N[2018-08-28 00:00:00], \"Etc/UTC\") |> Map.from_struct()\n\n      assert DateTime.add(dt_map, 1, :second) == %DateTime{\n               calendar: Calendar.ISO,\n               year: 2018,\n               month: 8,\n               day: 28,\n               hour: 0,\n               minute: 0,\n               second: 1,\n               std_offset: 0,\n               time_zone: \"Etc/UTC\",\n               zone_abbr: \"UTC\",\n               utc_offset: 0,\n               microsecond: {0, 0}\n             }\n    end\n\n    test \"with UTC only database and non UTC datetime emits error\" do\n      dt =\n        DateTime.from_naive!(~N[2018-08-28 00:00:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n\n      assert_raise ArgumentError, fn ->\n        DateTime.add(dt, 1, :second)\n      end\n    end\n\n    test \"with other calendars\" do\n      assert ~N[2000-01-01 12:34:15.123456]\n             |> NaiveDateTime.convert!(Calendar.Holocene)\n             |> DateTime.from_naive!(\"Etc/UTC\")\n             |> DateTime.add(10, :second) ==\n               %DateTime{\n                 calendar: Calendar.Holocene,\n                 year: 12000,\n                 month: 1,\n                 day: 1,\n                 hour: 12,\n                 minute: 34,\n                 second: 25,\n                 std_offset: 0,\n                 time_zone: \"Etc/UTC\",\n                 zone_abbr: \"UTC\",\n                 utc_offset: 0,\n                 microsecond: {123_456, 6}\n               }\n    end\n  end\n\n  describe \"to_iso8601\" do\n    test \"to_iso8601/2 with a normal DateTime struct\" do\n      datetime = DateTime.from_naive!(~N[2018-07-01 12:34:25.123456], \"Etc/UTC\")\n\n      assert DateTime.to_iso8601(datetime) == \"2018-07-01T12:34:25.123456Z\"\n    end\n\n    test \"to_iso8601/2 with a non-struct map conforming to the Calendar.datetime type\" do\n      datetime_map =\n        DateTime.from_naive!(~N[2018-07-01 12:34:25.123456], \"Etc/UTC\") |> Map.from_struct()\n\n      assert DateTime.to_iso8601(datetime_map) == \"2018-07-01T12:34:25.123456Z\"\n    end\n  end\n\n  describe \"to_date/1\" do\n    test \"upcasting\" do\n      assert catch_error(DateTime.to_date(~N[2000-02-29 12:23:34]))\n    end\n  end\n\n  describe \"to_time/1\" do\n    test \"upcasting\" do\n      assert catch_error(DateTime.to_time(~N[2000-02-29 12:23:34]))\n    end\n  end\n\n  describe \"to_naive/1\" do\n    test \"upcasting\" do\n      assert catch_error(DateTime.to_naive(~N[2000-02-29 12:23:34]))\n    end\n  end\n\n  test \"shift/2\" do\n    assert DateTime.shift(~U[2000-01-01 00:00:00Z], year: 1) == ~U[2001-01-01 00:00:00Z]\n    assert DateTime.shift(~U[2000-01-01 00:00:00Z], month: 1) == ~U[2000-02-01 00:00:00Z]\n    assert DateTime.shift(~U[2000-01-01 00:00:00Z], month: 1, day: 28) == ~U[2000-02-29 00:00:00Z]\n    assert DateTime.shift(~U[2000-01-01 00:00:00Z], month: 1, day: 30) == ~U[2000-03-02 00:00:00Z]\n    assert DateTime.shift(~U[2000-01-01 00:00:00Z], month: 2, day: 29) == ~U[2000-03-30 00:00:00Z]\n\n    assert DateTime.shift(~U[2000-01-01 00:00:00Z], microsecond: {4000, 4}) ==\n             ~U[2000-01-01 00:00:00.0040Z]\n\n    assert DateTime.shift(~U[2000-02-29 00:00:00Z], year: -1) == ~U[1999-02-28 00:00:00Z]\n    assert DateTime.shift(~U[2000-02-29 00:00:00Z], month: -1) == ~U[2000-01-29 00:00:00Z]\n\n    assert DateTime.shift(~U[2000-02-29 00:00:00Z], month: -1, day: -28) ==\n             ~U[2000-01-01 00:00:00Z]\n\n    assert DateTime.shift(~U[2000-02-29 00:00:00Z], month: -1, day: -30) ==\n             ~U[1999-12-30 00:00:00Z]\n\n    assert DateTime.shift(~U[2000-02-29 00:00:00Z], month: -1, day: -29) ==\n             ~U[1999-12-31 00:00:00Z]\n\n    datetime =\n      DateTime.new!(~D[2018-11-04], ~T[03:00:00], \"America/Los_Angeles\", FakeTimeZoneDatabase)\n\n    assert DateTime.shift(datetime, [month: -1], FakeTimeZoneDatabase) ==\n             %DateTime{\n               calendar: Calendar.ISO,\n               year: 2018,\n               month: 10,\n               day: 4,\n               hour: 4,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               time_zone: \"America/Los_Angeles\",\n               std_offset: 3600,\n               utc_offset: -28800,\n               zone_abbr: \"PDT\"\n             }\n\n    datetime =\n      DateTime.new!(~D[2018-11-04], ~T[00:00:00], \"America/Los_Angeles\", FakeTimeZoneDatabase)\n\n    assert DateTime.shift(datetime, [hour: 2], FakeTimeZoneDatabase) ==\n             %DateTime{\n               calendar: Calendar.ISO,\n               year: 2018,\n               month: 11,\n               day: 4,\n               hour: 1,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               time_zone: \"America/Los_Angeles\",\n               std_offset: 0,\n               utc_offset: -28800,\n               zone_abbr: \"PST\"\n             }\n\n    datetime =\n      DateTime.new!(~D[2019-03-31], ~T[01:00:00], \"Europe/Copenhagen\", FakeTimeZoneDatabase)\n\n    assert DateTime.shift(datetime, [hour: 1], FakeTimeZoneDatabase) ==\n             %DateTime{\n               calendar: Calendar.ISO,\n               year: 2019,\n               month: 03,\n               day: 31,\n               hour: 3,\n               minute: 0,\n               second: 0,\n               microsecond: {0, 0},\n               time_zone: \"Europe/Copenhagen\",\n               std_offset: 3600,\n               utc_offset: 3600,\n               zone_abbr: \"CEST\"\n             }\n\n    assert_raise ArgumentError,\n                 \"unknown unit :months. Expected :year, :month, :week, :day, :hour, :minute, :second, :microsecond\",\n                 fn -> DateTime.shift(~U[2012-01-01 00:00:00Z], months: 12) end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/duration_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule DurationTest do\n  use ExUnit.Case, async: true\n  doctest Duration\n\n  test \"new!/1\" do\n    assert Duration.new!(year: 2, month: 1, week: 3) == %Duration{year: 2, month: 1, week: 3}\n    assert Duration.new!(microsecond: {20000, 2}) == %Duration{microsecond: {20000, 2}}\n\n    duration = %Duration{year: 1}\n    assert ^duration = Duration.new!(duration)\n\n    assert_raise ArgumentError,\n                 \"unsupported value nil for :month. Expected an integer\",\n                 fn -> Duration.new!(month: nil) end\n\n    assert_raise ArgumentError,\n                 \"unknown unit :years. Expected :year, :month, :week, :day, :hour, :minute, :second, :microsecond\",\n                 fn -> Duration.new!(years: 1) end\n\n    assert_raise ArgumentError,\n                 \"unsupported value {1, 2, 3} for :microsecond. Expected a tuple {ms, precision} where precision is an integer from 0 to 6\",\n                 fn -> Duration.new!(microsecond: {1, 2, 3}) end\n\n    assert_raise ArgumentError,\n                 \"unsupported value {100, 7} for :microsecond. Expected a tuple {ms, precision} where precision is an integer from 0 to 6\",\n                 fn -> Duration.new!(microsecond: {100, 7}) end\n  end\n\n  test \"add/2\" do\n    d1 = %Duration{\n      year: 1,\n      month: 2,\n      week: 3,\n      day: 4,\n      hour: 5,\n      minute: 6,\n      second: 7,\n      microsecond: {8, 6}\n    }\n\n    d2 = %Duration{\n      year: 8,\n      month: 7,\n      week: 6,\n      day: 5,\n      hour: 4,\n      minute: 3,\n      second: 2,\n      microsecond: {1, 6}\n    }\n\n    assert Duration.add(d1, d2) == %Duration{\n             year: 9,\n             month: 9,\n             week: 9,\n             day: 9,\n             hour: 9,\n             minute: 9,\n             second: 9,\n             microsecond: {9, 6}\n           }\n\n    assert Duration.add(d1, d2) == Duration.add(d2, d1)\n\n    d1 = %Duration{month: 2, week: 3, day: 4}\n    d2 = %Duration{year: 8, day: 2, second: 2}\n\n    assert Duration.add(d1, d2) == %Duration{\n             year: 8,\n             month: 2,\n             week: 3,\n             day: 6,\n             hour: 0,\n             minute: 0,\n             second: 2,\n             microsecond: {0, 0}\n           }\n\n    d1 = %Duration{microsecond: {1000, 4}}\n    d2 = %Duration{microsecond: {5, 6}}\n    assert Duration.add(d1, d2) == %Duration{microsecond: {1005, 6}}\n  end\n\n  test \"subtract/2\" do\n    d1 = %Duration{\n      year: 1,\n      month: 2,\n      week: 3,\n      day: 4,\n      hour: 5,\n      minute: 6,\n      second: 7,\n      microsecond: {8, 6}\n    }\n\n    d2 = %Duration{\n      year: 8,\n      month: 7,\n      week: 6,\n      day: 5,\n      hour: 4,\n      minute: 3,\n      second: 2,\n      microsecond: {1, 6}\n    }\n\n    assert Duration.subtract(d1, d2) == %Duration{\n             year: -7,\n             month: -5,\n             week: -3,\n             day: -1,\n             hour: 1,\n             minute: 3,\n             second: 5,\n             microsecond: {7, 6}\n           }\n\n    assert Duration.subtract(d2, d1) == %Duration{\n             year: 7,\n             month: 5,\n             week: 3,\n             day: 1,\n             hour: -1,\n             minute: -3,\n             second: -5,\n             microsecond: {-7, 6}\n           }\n\n    assert Duration.subtract(d1, d2) != Duration.subtract(d2, d1)\n\n    d1 = %Duration{year: 10, month: 2, week: 3, day: 4}\n    d2 = %Duration{year: 8, day: 2, second: 2}\n\n    assert Duration.subtract(d1, d2) == %Duration{\n             year: 2,\n             month: 2,\n             week: 3,\n             day: 2,\n             hour: 0,\n             minute: 0,\n             second: -2,\n             microsecond: {0, 0}\n           }\n\n    d1 = %Duration{microsecond: {1000, 4}}\n    d2 = %Duration{microsecond: {5, 6}}\n    assert Duration.subtract(d1, d2) == %Duration{microsecond: {995, 6}}\n  end\n\n  test \"multiply/2\" do\n    duration = %Duration{\n      year: 1,\n      month: 2,\n      week: 3,\n      day: 4,\n      hour: 5,\n      minute: 6,\n      second: 7,\n      microsecond: {8, 6}\n    }\n\n    assert Duration.multiply(duration, 3) == %Duration{\n             year: 3,\n             month: 6,\n             week: 9,\n             day: 12,\n             hour: 15,\n             minute: 18,\n             second: 21,\n             microsecond: {24, 6}\n           }\n\n    assert Duration.multiply(%Duration{year: 2, day: 4, minute: 5}, 4) ==\n             %Duration{\n               year: 8,\n               month: 0,\n               week: 0,\n               day: 16,\n               hour: 0,\n               minute: 20,\n               second: 0,\n               microsecond: {0, 0}\n             }\n  end\n\n  test \"negate/1\" do\n    duration = %Duration{\n      year: 1,\n      month: 2,\n      week: 3,\n      day: 4,\n      hour: 5,\n      minute: 6,\n      second: 7,\n      microsecond: {8, 6}\n    }\n\n    assert Duration.negate(duration) == %Duration{\n             year: -1,\n             month: -2,\n             week: -3,\n             day: -4,\n             hour: -5,\n             minute: -6,\n             second: -7,\n             microsecond: {-8, 6}\n           }\n\n    assert Duration.negate(%Duration{year: 2, day: 4, minute: 5}) ==\n             %Duration{\n               year: -2,\n               month: 0,\n               week: 0,\n               day: -4,\n               hour: 0,\n               minute: -5,\n               second: 0,\n               microsecond: {0, 0}\n             }\n  end\n\n  test \"from_iso8601/1\" do\n    assert Duration.from_iso8601(\"P1Y2M3DT4H5M6S\") ==\n             {:ok, %Duration{year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6}}\n\n    assert Duration.from_iso8601(\"P3WT5H3M\") == {:ok, %Duration{week: 3, hour: 5, minute: 3}}\n    assert Duration.from_iso8601(\"PT5H3M\") == {:ok, %Duration{hour: 5, minute: 3}}\n    assert Duration.from_iso8601(\"P1Y2M3D\") == {:ok, %Duration{year: 1, month: 2, day: 3}}\n    assert Duration.from_iso8601(\"PT4H5M6S\") == {:ok, %Duration{hour: 4, minute: 5, second: 6}}\n    assert Duration.from_iso8601(\"P1Y2M\") == {:ok, %Duration{year: 1, month: 2}}\n    assert Duration.from_iso8601(\"P3D\") == {:ok, %Duration{day: 3}}\n    assert Duration.from_iso8601(\"PT4H5M\") == {:ok, %Duration{hour: 4, minute: 5}}\n    assert Duration.from_iso8601(\"PT6S\") == {:ok, %Duration{second: 6}}\n    assert Duration.from_iso8601(\"P2M4Y\") == {:error, :invalid_date_component}\n    assert Duration.from_iso8601(\"P4Y2W3Y\") == {:error, :invalid_date_component}\n    assert Duration.from_iso8601(\"P5HT4MT3S\") == {:error, :invalid_date_component}\n    assert Duration.from_iso8601(\"P5H3HT4M\") == {:error, :invalid_date_component}\n    assert Duration.from_iso8601(\"P0.5Y\") == {:error, :invalid_date_component}\n    assert Duration.from_iso8601(\"PT1D\") == {:error, :invalid_time_component}\n    assert Duration.from_iso8601(\"PT.6S\") == {:error, :invalid_time_component}\n    assert Duration.from_iso8601(\"PT0.5H\") == {:error, :invalid_time_component}\n    assert Duration.from_iso8601(\"invalid\") == {:error, :invalid_duration}\n  end\n\n  test \"from_iso8601!/1\" do\n    assert Duration.from_iso8601!(\"P1Y2M3DT4H5M6S\") == %Duration{\n             year: 1,\n             month: 2,\n             day: 3,\n             hour: 4,\n             minute: 5,\n             second: 6\n           }\n\n    assert Duration.from_iso8601!(\"P3WT5H3M\") == %Duration{week: 3, hour: 5, minute: 3}\n    assert Duration.from_iso8601!(\"PT5H3M\") == %Duration{hour: 5, minute: 3}\n    assert Duration.from_iso8601!(\"P1Y2M3D\") == %Duration{year: 1, month: 2, day: 3}\n    assert Duration.from_iso8601!(\"PT4H5M6S\") == %Duration{hour: 4, minute: 5, second: 6}\n    assert Duration.from_iso8601!(\"P1Y2M\") == %Duration{year: 1, month: 2}\n    assert Duration.from_iso8601!(\"P3D\") == %Duration{day: 3}\n    assert Duration.from_iso8601!(\"PT4H5M\") == %Duration{hour: 4, minute: 5}\n    assert Duration.from_iso8601!(\"PT6S\") == %Duration{second: 6}\n    assert Duration.from_iso8601!(\"PT1,6S\") == %Duration{second: 1, microsecond: {600_000, 1}}\n    assert Duration.from_iso8601!(\"PT-1.6S\") == %Duration{second: -1, microsecond: {-600_000, 1}}\n    assert Duration.from_iso8601!(\"PT0,6S\") == %Duration{second: 0, microsecond: {600_000, 1}}\n    assert Duration.from_iso8601!(\"PT-0,6S\") == %Duration{second: 0, microsecond: {-600_000, 1}}\n    assert Duration.from_iso8601!(\"-PT-0,6S\") == %Duration{second: 0, microsecond: {600_000, 1}}\n    assert Duration.from_iso8601!(\"-P10DT4H\") == %Duration{day: -10, hour: -4}\n    assert Duration.from_iso8601!(\"-P10DT-4H\") == %Duration{day: -10, hour: 4}\n    assert Duration.from_iso8601!(\"P-10D\") == %Duration{day: -10}\n    assert Duration.from_iso8601!(\"+P10DT-4H\") == %Duration{day: 10, hour: -4}\n    assert Duration.from_iso8601!(\"P+10D\") == %Duration{day: 10}\n    assert Duration.from_iso8601!(\"-P+10D\") == %Duration{day: -10}\n\n    assert Duration.from_iso8601!(\"PT-1.234567S\") == %Duration{\n             second: -1,\n             microsecond: {-234_567, 6}\n           }\n\n    assert Duration.from_iso8601!(\"PT1.12345678S\") == %Duration{\n             second: 1,\n             microsecond: {123_456, 6}\n           }\n\n    assert Duration.from_iso8601!(\"P3Y4W-3DT-6S\") == %Duration{\n             year: 3,\n             week: 4,\n             day: -3,\n             second: -6\n           }\n\n    assert Duration.from_iso8601!(\"PT-4.23S\") == %Duration{second: -4, microsecond: {-230_000, 2}}\n\n    assert_raise ArgumentError,\n                 ~s/failed to parse duration \"P5H3HT4M\". reason: :invalid_date_component/,\n                 fn ->\n                   Duration.from_iso8601!(\"P5H3HT4M\")\n                 end\n\n    assert_raise ArgumentError,\n                 ~s/failed to parse duration \"P4Y2W3Y\". reason: :invalid_date_component/,\n                 fn ->\n                   Duration.from_iso8601!(\"P4Y2W3Y\")\n                 end\n\n    assert_raise ArgumentError,\n                 ~s/failed to parse duration \"invalid\". reason: :invalid_duration/,\n                 fn ->\n                   Duration.from_iso8601!(\"invalid\")\n                 end\n\n    assert_raise ArgumentError,\n                 ~s/failed to parse duration \"P4.5YT6S\". reason: :invalid_date_component/,\n                 fn ->\n                   Duration.from_iso8601!(\"P4.5YT6S\")\n                 end\n  end\n\n  test \"to_iso8601/1\" do\n    assert %Duration{year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6}\n           |> Duration.to_iso8601() == \"P1Y2M3DT4H5M6S\"\n\n    assert %Duration{week: 3, hour: 5, minute: 3} |> Duration.to_iso8601() == \"P3WT5H3M\"\n    assert %Duration{hour: 5, minute: 3} |> Duration.to_iso8601() == \"PT5H3M\"\n    assert %Duration{year: 1, month: 2, day: 3} |> Duration.to_iso8601() == \"P1Y2M3D\"\n    assert %Duration{hour: 4, minute: 5, second: 6} |> Duration.to_iso8601() == \"PT4H5M6S\"\n    assert %Duration{year: 1, month: 2} |> Duration.to_iso8601() == \"P1Y2M\"\n    assert %Duration{day: 3} |> Duration.to_iso8601() == \"P3D\"\n    assert %Duration{hour: 4, minute: 5} |> Duration.to_iso8601() == \"PT4H5M\"\n    assert %Duration{second: 6} |> Duration.to_iso8601() == \"PT6S\"\n    assert %Duration{second: 1, microsecond: {600_000, 1}} |> Duration.to_iso8601() == \"PT1.6S\"\n    assert %Duration{second: -1, microsecond: {-600_000, 1}} |> Duration.to_iso8601() == \"PT-1.6S\"\n\n    assert %Duration{second: -1, microsecond: {-234_567, 6}} |> Duration.to_iso8601() ==\n             \"PT-1.234567S\"\n\n    assert %Duration{second: 1, microsecond: {123_456, 6}} |> Duration.to_iso8601() ==\n             \"PT1.123456S\"\n\n    assert %Duration{year: 3, week: 4, day: -3, second: -6} |> Duration.to_iso8601() ==\n             \"P3Y4W-3DT-6S\"\n\n    assert %Duration{second: -4, microsecond: {-230_000, 2}} |> Duration.to_iso8601() ==\n             \"PT-4.23S\"\n\n    assert %Duration{second: -4, microsecond: {230_000, 2}} |> Duration.to_iso8601() ==\n             \"PT-3.77S\"\n\n    assert %Duration{second: 2, microsecond: {-1_200_000, 4}} |> Duration.to_iso8601() ==\n             \"PT0.8000S\"\n\n    assert %Duration{second: 1, microsecond: {-1_200_000, 3}} |> Duration.to_iso8601() ==\n             \"PT-0.200S\"\n\n    assert %Duration{microsecond: {-800_000, 2}} |> Duration.to_iso8601() == \"PT-0.80S\"\n    assert %Duration{microsecond: {-800_000, 0}} |> Duration.to_iso8601() == \"PT0S\"\n    assert %Duration{microsecond: {-1_200_000, 2}} |> Duration.to_iso8601() == \"PT-1.20S\"\n  end\n\n  test \"to_string/1\" do\n    assert Duration.to_string(%Duration{year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6}) ==\n             \"1a 2mo 3d 4h 5min 6s\"\n\n    assert Duration.to_string(%Duration{week: 3, hour: 5, minute: 3}) ==\n             \"3wk 5h 3min\"\n\n    assert Duration.to_string(%Duration{hour: 5, minute: 3}) ==\n             \"5h 3min\"\n\n    assert Duration.to_string(%Duration{year: 1, month: 2, day: 3}) ==\n             \"1a 2mo 3d\"\n\n    assert Duration.to_string(%Duration{hour: 4, minute: 5, second: 6}) ==\n             \"4h 5min 6s\"\n\n    assert Duration.to_string(%Duration{year: 1, month: 2}) ==\n             \"1a 2mo\"\n\n    assert Duration.to_string(%Duration{day: 3}) ==\n             \"3d\"\n\n    assert Duration.to_string(%Duration{hour: 4, minute: 5}) ==\n             \"4h 5min\"\n\n    assert Duration.to_string(%Duration{second: 6}) ==\n             \"6s\"\n\n    assert Duration.to_string(%Duration{second: 1, microsecond: {600_000, 1}}) ==\n             \"1.6s\"\n\n    assert Duration.to_string(%Duration{second: -1, microsecond: {-600_000, 1}}) ==\n             \"-1.6s\"\n\n    assert Duration.to_string(%Duration{second: -1, microsecond: {-234_567, 6}}) ==\n             \"-1.234567s\"\n\n    assert Duration.to_string(%Duration{second: 1, microsecond: {123_456, 6}}) ==\n             \"1.123456s\"\n\n    assert Duration.to_string(%Duration{year: 3, week: 4, day: -3, second: -6}) ==\n             \"3a 4wk -3d -6s\"\n\n    assert Duration.to_string(%Duration{second: -4, microsecond: {-230_000, 2}}) ==\n             \"-4.23s\"\n\n    assert Duration.to_string(%Duration{second: -4, microsecond: {230_000, 2}}) ==\n             \"-3.77s\"\n\n    assert Duration.to_string(%Duration{second: 2, microsecond: {-1_200_000, 4}}) ==\n             \"0.8000s\"\n\n    assert Duration.to_string(%Duration{second: 1, microsecond: {-1_200_000, 3}}) ==\n             \"-0.200s\"\n\n    assert Duration.to_string(%Duration{microsecond: {-800_000, 2}}) ==\n             \"-0.80s\"\n\n    assert Duration.to_string(%Duration{microsecond: {-800_000, 0}}) ==\n             \"0s\"\n\n    assert Duration.to_string(%Duration{microsecond: {-1_200_000, 2}}) ==\n             \"-1.20s\"\n\n    assert Duration.to_string(%Duration{year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6},\n             units: [year: \"year\", month: \"month\", day: \"day\"],\n             separator: \"-\"\n           ) ==\n             \"1year-2month-3day-4h-5min-6s\"\n  end\n\n  test \"inspect/1\" do\n    assert inspect(%Duration{hour: 5, minute: 3}) == \"%Duration{hour: 5, minute: 3}\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/fakes.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule FakeCalendar do\n  def time_to_string(hour, minute, second, _), do: \"#{hour}::#{minute}::#{second}\"\n  def date_to_string(year, month, day), do: \"#{day}/#{month}/#{year}\"\n\n  def naive_datetime_to_string(year, month, day, hour, minute, second, microsecond) do\n    date_to_string(year, month, day) <> \"F\" <> time_to_string(hour, minute, second, microsecond)\n  end\n\n  def datetime_to_string(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        time_zone,\n        abbr,\n        utc_offset,\n        std_offset\n      ) do\n    naive_datetime_to_string(year, month, day, hour, minute, second, microsecond) <>\n      \" #{time_zone} #{abbr} #{utc_offset} #{std_offset}\"\n  end\n\n  def day_rollover_relative_to_midnight_utc, do: {123_456, 123_457}\nend\n\ndefmodule FakeTimeZoneDatabase do\n  @behaviour Calendar.TimeZoneDatabase\n\n  @time_zone_period_cph_summer_2018 %{\n    std_offset: 3600,\n    utc_offset: 3600,\n    zone_abbr: \"CEST\",\n    from_wall: ~N[2018-03-25 03:00:00],\n    until_wall: ~N[2018-10-28 03:00:00]\n  }\n\n  @time_zone_period_cph_winter_2018_2019 %{\n    std_offset: 0,\n    utc_offset: 3600,\n    zone_abbr: \"CET\",\n    from_wall: ~N[2018-10-28 02:00:00],\n    until_wall: ~N[2019-03-31 02:00:00]\n  }\n\n  @time_zone_period_cph_summer_2019 %{\n    std_offset: 3600,\n    utc_offset: 3600,\n    zone_abbr: \"CEST\",\n    from_wall: ~N[2019-03-31 03:00:00],\n    until_wall: ~N[2019-10-27 03:00:00]\n  }\n\n  @time_zone_period_usla_summer_2018 %{\n    std_offset: 3600,\n    utc_offset: -28800,\n    zone_abbr: \"PDT\",\n    from_wall: ~N[2018-03-11 02:00:00],\n    until_wall: ~N[2018-11-04 02:00:00]\n  }\n\n  @time_zone_period_usla_winter_2018_2019 %{\n    std_offset: 0,\n    utc_offset: -28800,\n    zone_abbr: \"PST\",\n    from_wall: ~N[2018-11-04 02:00:00],\n    until_wall: ~N[2019-03-10 03:00:00]\n  }\n\n  @spec time_zone_period_from_utc_iso_days(Calendar.iso_days(), Calendar.time_zone()) ::\n          {:ok, TimeZoneDatabase.time_zone_period()} | {:error, :time_zone_not_found}\n  @impl true\n  def time_zone_period_from_utc_iso_days(iso_days, time_zone) do\n    {:ok, ndt} = naive_datetime_from_iso_days(iso_days)\n    time_zone_periods_from_utc(time_zone, NaiveDateTime.to_erl(ndt))\n  end\n\n  @spec time_zone_periods_from_wall_datetime(Calendar.naive_datetime(), Calendar.time_zone()) ::\n          {:ok, TimeZoneDatabase.time_zone_period()}\n          | {:ambiguous, TimeZoneDatabase.time_zone_period(), TimeZoneDatabase.time_zone_period()}\n          | {:gap,\n             {TimeZoneDatabase.time_zone_period(), TimeZoneDatabase.time_zone_period_limit()},\n             {TimeZoneDatabase.time_zone_period(), TimeZoneDatabase.time_zone_period_limit()}}\n          | {:error, :time_zone_not_found}\n  @impl true\n  def time_zone_periods_from_wall_datetime(naive_datetime, time_zone) do\n    time_zone_periods_from_wall(time_zone, NaiveDateTime.to_erl(naive_datetime))\n  end\n\n  defp time_zone_periods_from_utc(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2018, 3, 25}, {1, 0, 0}} and\n              erl_datetime < {{2018, 10, 28}, {3, 0, 0}} do\n    {:ok, @time_zone_period_cph_summer_2018}\n  end\n\n  defp time_zone_periods_from_utc(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2018, 10, 28}, {2, 0, 0}} and\n              erl_datetime < {{2019, 3, 31}, {1, 0, 0}} do\n    {:ok, @time_zone_period_cph_winter_2018_2019}\n  end\n\n  defp time_zone_periods_from_utc(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2019, 3, 31}, {1, 0, 0}} and\n              erl_datetime < {{2019, 10, 28}, {3, 0, 0}} do\n    {:ok, @time_zone_period_cph_summer_2019}\n  end\n\n  defp time_zone_periods_from_utc(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2015, 3, 29}, {1, 0, 0}} and\n              erl_datetime < {{2015, 10, 25}, {1, 0, 0}} do\n    {:ok,\n     %{\n       std_offset: 3600,\n       utc_offset: 3600,\n       zone_abbr: \"CEST\"\n     }}\n  end\n\n  defp time_zone_periods_from_utc(\"America/Los_Angeles\", erl_datetime)\n       when erl_datetime >= {{2018, 3, 11}, {2, 0, 0}} and\n              erl_datetime < {{2018, 11, 4}, {2, 0, 0}} do\n    {:ok, @time_zone_period_usla_summer_2018}\n  end\n\n  defp time_zone_periods_from_utc(\"America/Los_Angeles\", erl_datetime)\n       when erl_datetime >= {{2018, 11, 4}, {2, 0, 0}} and\n              erl_datetime < {{2019, 3, 10}, {3, 0, 0}} do\n    {:ok, @time_zone_period_usla_winter_2018_2019}\n  end\n\n  defp time_zone_periods_from_utc(\"Etc/UTC\", _erl_datetime) do\n    {:ok,\n     %{\n       std_offset: 0,\n       utc_offset: 0,\n       zone_abbr: \"UTC\"\n     }}\n  end\n\n  defp time_zone_periods_from_utc(time_zone, _) when time_zone != \"Europe/Copenhagen\" do\n    {:error, :time_zone_not_found}\n  end\n\n  defp time_zone_periods_from_wall(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2019, 3, 31}, {2, 0, 0}} and\n              erl_datetime < {{2019, 3, 31}, {3, 0, 0}} do\n    {:gap,\n     {@time_zone_period_cph_winter_2018_2019, @time_zone_period_cph_winter_2018_2019.until_wall},\n     {@time_zone_period_cph_summer_2019, @time_zone_period_cph_summer_2019.from_wall}}\n  end\n\n  defp time_zone_periods_from_wall(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime < {{2018, 10, 28}, {3, 0, 0}} and\n              erl_datetime >= {{2018, 10, 28}, {2, 0, 0}} do\n    {:ambiguous, @time_zone_period_cph_summer_2018, @time_zone_period_cph_winter_2018_2019}\n  end\n\n  defp time_zone_periods_from_wall(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2018, 3, 25}, {3, 0, 0}} and\n              erl_datetime < {{2018, 10, 28}, {3, 0, 0}} do\n    {:ok, @time_zone_period_cph_summer_2018}\n  end\n\n  defp time_zone_periods_from_wall(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2018, 10, 28}, {2, 0, 0}} and\n              erl_datetime < {{2019, 3, 31}, {2, 0, 0}} do\n    {:ok, @time_zone_period_cph_winter_2018_2019}\n  end\n\n  defp time_zone_periods_from_wall(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2019, 3, 31}, {3, 0, 0}} and\n              erl_datetime < {{2019, 10, 27}, {3, 0, 0}} do\n    {:ok, @time_zone_period_cph_summer_2019}\n  end\n\n  defp time_zone_periods_from_wall(\"America/Los_Angeles\", erl_datetime)\n       when erl_datetime >= {{2018, 3, 11}, {2, 0, 0}} and\n              erl_datetime < {{2018, 11, 4}, {2, 0, 0}} do\n    {:ok, @time_zone_period_usla_summer_2018}\n  end\n\n  defp time_zone_periods_from_wall(\"America/Los_Angeles\", erl_datetime)\n       when erl_datetime >= {{2018, 11, 4}, {3, 0, 0}} and\n              erl_datetime < {{2019, 3, 10}, {3, 0, 0}} do\n    {:ok, @time_zone_period_usla_winter_2018_2019}\n  end\n\n  defp time_zone_periods_from_wall(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2015, 3, 29}, {3, 0, 0}} and\n              erl_datetime < {{2015, 10, 25}, {3, 0, 0}} do\n    {:ok,\n     %{\n       std_offset: 3600,\n       utc_offset: 3600,\n       zone_abbr: \"CEST\"\n     }}\n  end\n\n  defp time_zone_periods_from_wall(\"Europe/Copenhagen\", erl_datetime)\n       when erl_datetime >= {{2090, 3, 26}, {3, 0, 0}} and\n              erl_datetime < {{2090, 10, 29}, {3, 0, 0}} do\n    {:ok,\n     %{\n       std_offset: 3600,\n       utc_offset: 3600,\n       zone_abbr: \"CEST\"\n     }}\n  end\n\n  defp time_zone_periods_from_wall(\"Etc/UTC\", _erl_datetime) do\n    {:ok,\n     %{\n       std_offset: 0,\n       utc_offset: 0,\n       zone_abbr: \"UTC\"\n     }}\n  end\n\n  defp time_zone_periods_from_wall(time_zone, _) when time_zone != \"Europe/Copenhagen\" do\n    {:error, :time_zone_not_found}\n  end\n\n  defp naive_datetime_from_iso_days(iso_days) do\n    {year, month, day, hour, minute, second, microsecond} =\n      Calendar.ISO.naive_datetime_from_iso_days(iso_days)\n\n    NaiveDateTime.new(year, month, day, hour, minute, second, microsecond)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/holocene.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Calendar.Holocene do\n  # This calendar is used to test conversions between calendars.\n  # It implements the Holocene calendar, which is based on the\n  # Proleptic Gregorian calendar with every year + 10000.\n\n  @behaviour Calendar\n\n  def date(year, month, day) do\n    %Date{year: year, month: month, day: day, calendar: __MODULE__}\n  end\n\n  def naive_datetime(year, month, day, hour, minute, second, microsecond \\\\ {0, 0}) do\n    %NaiveDateTime{\n      year: year,\n      month: month,\n      day: day,\n      hour: hour,\n      minute: minute,\n      second: second,\n      microsecond: microsecond,\n      calendar: __MODULE__\n    }\n  end\n\n  @impl true\n  def date_to_string(year, month, day) do\n    \"#{year}-#{zero_pad(month, 2)}-#{zero_pad(day, 2)}\"\n  end\n\n  @impl true\n  def naive_datetime_to_string(year, month, day, hour, minute, second, microsecond) do\n    \"#{year}-#{zero_pad(month, 2)}-#{zero_pad(day, 2)}\" <>\n      Calendar.ISO.time_to_string(hour, minute, second, microsecond)\n  end\n\n  @impl true\n  def datetime_to_string(\n        year,\n        month,\n        day,\n        hour,\n        minute,\n        second,\n        microsecond,\n        _time_zone,\n        zone_abbr,\n        _utc_offset,\n        _std_offset\n      ) do\n    \"#{year}-#{zero_pad(month, 2)}-#{zero_pad(day, 2)}\" <>\n      Calendar.ISO.time_to_string(hour, minute, second, microsecond) <>\n      \" #{zone_abbr}\"\n  end\n\n  @impl true\n  defdelegate time_to_string(hour, minute, second, microsecond), to: Calendar.ISO\n\n  @impl true\n  def day_rollover_relative_to_midnight_utc(), do: {0, 1}\n\n  @impl true\n  def naive_datetime_from_iso_days(entry) do\n    {year, month, day, hour, minute, second, microsecond} =\n      Calendar.ISO.naive_datetime_from_iso_days(entry)\n\n    {year + 10000, month, day, hour, minute, second, microsecond}\n  end\n\n  @impl true\n  def naive_datetime_to_iso_days(year, month, day, hour, minute, second, microsecond) do\n    Calendar.ISO.naive_datetime_to_iso_days(\n      year - 10000,\n      month,\n      day,\n      hour,\n      minute,\n      second,\n      microsecond\n    )\n  end\n\n  defp zero_pad(val, count) when val >= 0 do\n    String.pad_leading(\"#{val}\", count, [\"0\"])\n  end\n\n  defp zero_pad(val, count) do\n    \"-\" <> zero_pad(-val, count)\n  end\n\n  @impl true\n  def parse_date(string) do\n    {year, month, day} =\n      string\n      |> String.split(\"-\")\n      |> Enum.map(&String.to_integer/1)\n      |> List.to_tuple()\n\n    if valid_date?(year, month, day) do\n      {:ok, {year, month, day}}\n    else\n      {:error, :invalid_date}\n    end\n  end\n\n  @impl true\n  def valid_date?(year, month, day) do\n    :calendar.valid_date(year, month, day)\n  end\n\n  @impl true\n  defdelegate parse_time(string), to: Calendar.ISO\n\n  @impl true\n  defdelegate parse_naive_datetime(string), to: Calendar.ISO\n\n  @impl true\n  defdelegate parse_utc_datetime(string), to: Calendar.ISO\n\n  @impl true\n  defdelegate time_from_day_fraction(day_fraction), to: Calendar.ISO\n\n  @impl true\n  defdelegate time_to_day_fraction(hour, minute, second, microsecond), to: Calendar.ISO\n\n  @impl true\n  defdelegate leap_year?(year), to: Calendar.ISO\n\n  @impl true\n  defdelegate days_in_month(year, month), to: Calendar.ISO\n\n  @impl true\n  defdelegate months_in_year(year), to: Calendar.ISO\n\n  @impl true\n  defdelegate day_of_week(year, month, day, starting_on), to: Calendar.ISO\n\n  @impl true\n  defdelegate day_of_year(year, month, day), to: Calendar.ISO\n\n  @impl true\n  defdelegate quarter_of_year(year, month, day), to: Calendar.ISO\n\n  @impl true\n  defdelegate year_of_era(year, month, day), to: Calendar.ISO\n\n  @impl true\n  defdelegate day_of_era(year, month, day), to: Calendar.ISO\n\n  @impl true\n  defdelegate valid_time?(hour, minute, second, microsecond), to: Calendar.ISO\n\n  @impl true\n  defdelegate iso_days_to_beginning_of_day(iso_days), to: Calendar.ISO\n\n  @impl true\n  defdelegate iso_days_to_end_of_day(iso_days), to: Calendar.ISO\n\n  # The Holocene calendar extends most year and day count guards implemented in the ISO calendars.\n  @impl true\n  def shift_date(_year, _month, _day, _duration) do\n    raise \"shift_date/4 not implemented\"\n  end\n\n  @impl true\n  def shift_naive_datetime(_year, _month, _day, _hour, _minute, _second, _microsecond, _duration) do\n    raise \"shift_naive_datetime/8 not implemented\"\n  end\n\n  @impl true\n  def shift_time(_hour, _minute, _second, _microsecond, _duration) do\n    raise \"shift_time/5 not implemented\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/iso_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Calendar.ISOTest do\n  use ExUnit.Case, async: true\n  doctest Calendar.ISO\n\n  describe \"date_from_iso_days\" do\n    test \"with positive dates\" do\n      assert {0, 1, 1} == iso_day_roundtrip(0, 1, 1)\n      assert {0, 12, 31} == iso_day_roundtrip(0, 12, 31)\n      assert {1, 12, 31} == iso_day_roundtrip(1, 12, 31)\n      assert {4, 1, 1} == iso_day_roundtrip(4, 1, 1)\n      assert {4, 12, 31} == iso_day_roundtrip(4, 12, 31)\n      assert {9999, 12, 31} == iso_day_roundtrip(9999, 12, 31)\n      assert {9999, 1, 1} == iso_day_roundtrip(9999, 1, 1)\n      assert {9996, 12, 31} == iso_day_roundtrip(9996, 12, 31)\n      assert {9996, 1, 1} == iso_day_roundtrip(9996, 1, 1)\n    end\n\n    test \"with negative dates\" do\n      assert {-1, 1, 1} == iso_day_roundtrip(-1, 1, 1)\n      assert {-1, 12, 31} == iso_day_roundtrip(-1, 12, 31)\n      assert {-1, 12, 31} == iso_day_roundtrip(-1, 12, 31)\n      assert {-2, 1, 1} == iso_day_roundtrip(-2, 1, 1)\n      assert {-5, 12, 31} == iso_day_roundtrip(-5, 12, 31)\n\n      assert {-4, 1, 1} == iso_day_roundtrip(-4, 1, 1)\n      assert {-4, 12, 31} == iso_day_roundtrip(-4, 12, 31)\n\n      assert {-9999, 12, 31} == iso_day_roundtrip(-9999, 12, 31)\n      assert {-9996, 12, 31} == iso_day_roundtrip(-9996, 12, 31)\n\n      assert {-9996, 12, 31} == iso_day_roundtrip(-9996, 12, 31)\n      assert {-9996, 1, 1} == iso_day_roundtrip(-9996, 1, 1)\n    end\n  end\n\n  describe \"date_to_string/4\" do\n    test \"regular use\" do\n      assert Calendar.ISO.date_to_string(1000, 1, 1, :basic) == \"10000101\"\n      assert Calendar.ISO.date_to_string(1000, 1, 1, :extended) == \"1000-01-01\"\n\n      assert Calendar.ISO.date_to_string(-123, 1, 1, :basic) == \"-01230101\"\n      assert Calendar.ISO.date_to_string(-123, 1, 1, :extended) == \"-0123-01-01\"\n    end\n\n    test \"handles years > 9999\" do\n      assert Calendar.ISO.date_to_string(10000, 1, 1, :basic) == \"100000101\"\n      assert Calendar.ISO.date_to_string(10000, 1, 1, :extended) == \"10000-01-01\"\n    end\n  end\n\n  describe \"naive_datetime_to_iso_days/7\" do\n    test \"raises with invalid dates\" do\n      assert_raise ArgumentError, \"invalid date: 2018-02-30\", fn ->\n        Calendar.ISO.naive_datetime_to_iso_days(2018, 2, 30, 0, 0, 0, {0, 0})\n      end\n\n      assert_raise ArgumentError, \"invalid date: 2017-11--03\", fn ->\n        Calendar.ISO.naive_datetime_to_iso_days(2017, 11, -3, 0, 0, 0, {0, 0})\n      end\n    end\n  end\n\n  describe \"day_of_week/4\" do\n    test \"raises with invalid dates\" do\n      assert_raise ArgumentError, \"invalid date: 2018-02-30\", fn ->\n        Calendar.ISO.day_of_week(2018, 2, 30, :default)\n      end\n\n      assert_raise ArgumentError, \"invalid date: 2017-11-00\", fn ->\n        Calendar.ISO.day_of_week(2017, 11, 0, :default)\n      end\n    end\n  end\n\n  describe \"day_of_era/3\" do\n    test \"raises with invalid dates\" do\n      assert_raise ArgumentError, \"invalid date: 2018-02-30\", fn ->\n        Calendar.ISO.day_of_era(2018, 2, 30)\n      end\n\n      assert_raise ArgumentError, \"invalid date: 2017-11-00\", fn ->\n        Calendar.ISO.day_of_era(2017, 11, 0)\n      end\n    end\n  end\n\n  describe \"day_of_year/3\" do\n    test \"raises with invalid dates\" do\n      assert_raise ArgumentError, \"invalid date: 2018-02-30\", fn ->\n        Calendar.ISO.day_of_year(2018, 2, 30)\n      end\n\n      assert_raise ArgumentError, \"invalid date: 2017-11-00\", fn ->\n        Calendar.ISO.day_of_year(2017, 11, 0)\n      end\n    end\n  end\n\n  test \"year_of_era/3\" do\n    # Compatibility tests for year_of_era/1\n    assert Calendar.ISO.year_of_era(-9999) == {10000, 0}\n    assert Calendar.ISO.year_of_era(-1) == {2, 0}\n    assert Calendar.ISO.year_of_era(0) == {1, 0}\n    assert Calendar.ISO.year_of_era(1) == {1, 1}\n    assert Calendar.ISO.year_of_era(1984) == {1984, 1}\n\n    assert Calendar.ISO.year_of_era(-9999, 1, 1) == {10000, 0}\n    assert Calendar.ISO.year_of_era(-1, 1, 1) == {2, 0}\n    assert Calendar.ISO.year_of_era(0, 12, 1) == {1, 0}\n    assert Calendar.ISO.year_of_era(1, 12, 1) == {1, 1}\n    assert Calendar.ISO.year_of_era(1984, 12, 1) == {1984, 1}\n\n    random_positive_year = Enum.random(1..9999)\n    assert Calendar.ISO.year_of_era(random_positive_year, 1, 1) == {random_positive_year, 1}\n  end\n\n  defp iso_day_roundtrip(year, month, day) do\n    iso_days = Calendar.ISO.date_to_iso_days(year, month, day)\n    Calendar.ISO.date_from_iso_days(iso_days)\n  end\n\n  describe \"parse_date/1\" do\n    test \"supports both only extended format by default\" do\n      assert Calendar.ISO.parse_date(\"20150123\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_date(\"2015-01-23\") == {:ok, {2015, 1, 23}}\n    end\n  end\n\n  describe \"parse_date/2\" do\n    test \"allows enforcing basic formats\" do\n      assert Calendar.ISO.parse_date(\"20150123\", :basic) == {:ok, {2015, 1, 23}}\n      assert Calendar.ISO.parse_date(\"2015-01-23\", :basic) == {:error, :invalid_format}\n    end\n\n    test \"allows enforcing extended formats\" do\n      assert Calendar.ISO.parse_date(\"20150123\", :extended) == {:error, :invalid_format}\n      assert Calendar.ISO.parse_date(\"2015-01-23\", :extended) == {:ok, {2015, 1, 23}}\n    end\n  end\n\n  describe \"parse_time/1\" do\n    test \"supports only extended format by default\" do\n      assert Calendar.ISO.parse_time(\"235007\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"23:50:07\") == {:ok, {23, 50, 7, {0, 0}}}\n    end\n\n    test \"ignores offset data but requires valid ones\" do\n      assert Calendar.ISO.parse_time(\"23:50:07Z\") == {:ok, {23, 50, 7, {0, 0}}}\n      assert Calendar.ISO.parse_time(\"23:50:07+01:00\") == {:ok, {23, 50, 7, {0, 0}}}\n\n      assert Calendar.ISO.parse_time(\"2015-01-23 23:50-00:00\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"2015-01-23 23:50-00:60\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"2015-01-23 23:50-24:00\") == {:error, :invalid_format}\n    end\n\n    test \"supports either comma or period millisecond delimiters\" do\n      assert Calendar.ISO.parse_time(\"23:50:07,012345\") == {:ok, {23, 50, 7, {12345, 6}}}\n      assert Calendar.ISO.parse_time(\"23:50:07.012345\") == {:ok, {23, 50, 7, {12345, 6}}}\n    end\n\n    test \"only supports reduced precision for milliseconds\" do\n      assert Calendar.ISO.parse_time(\"23:50:07.012345\") == {:ok, {23, 50, 7, {12345, 6}}}\n      assert Calendar.ISO.parse_time(\"23:50:07\") == {:ok, {23, 50, 7, {0, 0}}}\n      assert Calendar.ISO.parse_time(\"23:50\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"23\") == {:error, :invalid_format}\n    end\n\n    test \"supports various millisecond precisions\" do\n      assert Calendar.ISO.parse_time(\"23:50:07.012345\") == {:ok, {23, 50, 7, {12345, 6}}}\n      assert Calendar.ISO.parse_time(\"23:50:07.0123\") == {:ok, {23, 50, 7, {12300, 4}}}\n      assert Calendar.ISO.parse_time(\"23:50:07.01\") == {:ok, {23, 50, 7, {10000, 2}}}\n      assert Calendar.ISO.parse_time(\"23:50:07.0\") == {:ok, {23, 50, 7, {0, 1}}}\n      assert Calendar.ISO.parse_time(\"23:50:07\") == {:ok, {23, 50, 7, {0, 0}}}\n    end\n\n    test \"truncates extra millisecond precision\" do\n      assert Calendar.ISO.parse_time(\"23:50:07.012345\") == {:ok, {23, 50, 7, {12345, 6}}}\n      assert Calendar.ISO.parse_time(\"23:50:07.0123456\") == {:ok, {23, 50, 7, {12345, 6}}}\n    end\n\n    test \"rejects strings with formatting errors\" do\n      assert Calendar.ISO.parse_time(\"23:50:07A\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"23:50:07.\") == {:error, :invalid_format}\n    end\n\n    test \"refuses to parse the wrong thing\" do\n      assert Calendar.ISO.parse_time(\"2015:01:23 23-50-07\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"2015-01-23 23:50:07\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"2015:01:23T23-50-07\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"2015-01-23T23:50:07\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"2015:01:23\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"2015-01-23\") == {:error, :invalid_format}\n    end\n\n    test \"recognizes invalid times\" do\n      assert Calendar.ISO.parse_time(\"23:59:61\") == {:error, :invalid_time}\n      assert Calendar.ISO.parse_time(\"23:61:59\") == {:error, :invalid_time}\n      assert Calendar.ISO.parse_time(\"25:59:59\") == {:error, :invalid_time}\n    end\n  end\n\n  describe \"parse_time/2\" do\n    test \"allows enforcing basic formats\" do\n      assert Calendar.ISO.parse_time(\"235007\", :basic) == {:ok, {23, 50, 7, {0, 0}}}\n      assert Calendar.ISO.parse_time(\"23:50:07\", :basic) == {:error, :invalid_format}\n    end\n\n    test \"allows enforcing extended formats\" do\n      assert Calendar.ISO.parse_time(\"235007\", :extended) == {:error, :invalid_format}\n      assert Calendar.ISO.parse_time(\"23:50:07\", :extended) == {:ok, {23, 50, 7, {0, 0}}}\n    end\n  end\n\n  describe \"parse_naive_datetime/1\" do\n    test \"rejects strings with formatting errors\" do\n      assert Calendar.ISO.parse_naive_datetime(\"2015:01:23 23-50-07\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23P23:50:07\") == {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07A\") ==\n               {:error, :invalid_format}\n    end\n\n    test \"recognizes invalid dates and times\" do\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:61\") == {:error, :invalid_time}\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-32 23:50:07\") == {:error, :invalid_date}\n    end\n\n    test \"ignores offset data but requires valid ones\" do\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07.123+02:30\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07.123+00:00\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07.123-02:30\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07.123-00:00\") ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07.123-00:60\") ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07.123-24:00\") ==\n               {:error, :invalid_format}\n    end\n\n    test \"supports both spaces and 'T' as datetime separators\" do\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23T23:50:07\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}}\n    end\n\n    test \"supports only extended format by default\" do\n      assert Calendar.ISO.parse_naive_datetime(\"20150123 235007.123\") ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07.123\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}}\n    end\n\n    test \"errors on mixed basic and extended formats\" do\n      assert Calendar.ISO.parse_naive_datetime(\"20150123 23:50:07.123\") ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23 235007.123\") ==\n               {:error, :invalid_format}\n    end\n  end\n\n  describe \"parse_naive_datetime/2\" do\n    test \"allows enforcing basic formats\" do\n      assert Calendar.ISO.parse_naive_datetime(\"20150123 235007.123\", :basic) ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07.123\", :basic) ==\n               {:error, :invalid_format}\n    end\n\n    test \"allows enforcing extended formats\" do\n      assert Calendar.ISO.parse_naive_datetime(\"20150123 235007.123\", :extended) ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_naive_datetime(\"2015-01-23 23:50:07.123\", :extended) ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}}\n    end\n  end\n\n  describe \"parse_utc_datetime/1\" do\n    test \"rejects strings with formatting errors\" do\n      assert Calendar.ISO.parse_utc_datetime(\"2015:01:23 23-50-07Z\") == {:error, :invalid_format}\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23P23:50:07Z\") == {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07A\") == {:error, :invalid_format}\n    end\n\n    test \"recognizes invalid dates, times, and offsets\" do\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07\") == {:error, :missing_offset}\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:61Z\") == {:error, :invalid_time}\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-32 23:50:07Z\") == {:error, :invalid_date}\n    end\n\n    test \"interprets offset data\" do\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23T23:50:07.123+02:30\") ==\n               {:ok, {2015, 1, 23, 21, 20, 7, {123_000, 3}}, 9000}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23T23:50:07.123+00:00\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}, 0}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23T23:50:07.123-02:30\") ==\n               {:ok, {2015, 1, 24, 2, 20, 7, {123_000, 3}}, -9000}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23T23:50:07.123-00:00\") ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23T23:50:07.123-00:60\") ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23T23:50:07.123-24:00\") ==\n               {:error, :invalid_format}\n    end\n\n    test \"supports both spaces and 'T' as datetime separators\" do\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07Z\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}, 0}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23T23:50:07Z\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {0, 0}}, 0}\n    end\n\n    test \"supports only extended format by default\" do\n      assert Calendar.ISO.parse_utc_datetime(\"20150123 235007.123Z\") ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07.123Z\") ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}, 0}\n    end\n\n    test \"errors on mixed basic and extended formats\" do\n      assert Calendar.ISO.parse_utc_datetime(\"20150123 23:50:07.123Z\") ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 235007.123Z\") ==\n               {:error, :invalid_format}\n    end\n  end\n\n  describe \"parse_utc_datetime/2\" do\n    test \"allows enforcing basic formats\" do\n      assert Calendar.ISO.parse_utc_datetime(\"20150123 235007.123Z\", :basic) ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}, 0}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07.123Z\", :basic) ==\n               {:error, :invalid_format}\n    end\n\n    test \"allows enforcing extended formats\" do\n      assert Calendar.ISO.parse_utc_datetime(\"20150123 235007.123Z\", :extended) ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 23:50:07.123Z\", :extended) ==\n               {:ok, {2015, 1, 23, 23, 50, 7, {123_000, 3}}, 0}\n    end\n\n    test \"errors on mixed basic and extended formats\" do\n      assert Calendar.ISO.parse_utc_datetime(\"20150123 23:50:07.123Z\", :basic) ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"20150123 23:50:07.123Z\", :extended) ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 235007.123Z\", :basic) ==\n               {:error, :invalid_format}\n\n      assert Calendar.ISO.parse_utc_datetime(\"2015-01-23 235007.123Z\", :extended) ==\n               {:error, :invalid_format}\n    end\n  end\n\n  test \"shift_date/2\" do\n    assert Calendar.ISO.shift_date(2024, 3, 2, Duration.new!([])) == {2024, 3, 2}\n    assert Calendar.ISO.shift_date(2024, 3, 2, Duration.new!(year: 1)) == {2025, 3, 2}\n    assert Calendar.ISO.shift_date(2024, 3, 2, Duration.new!(month: 2)) == {2024, 5, 2}\n    assert Calendar.ISO.shift_date(2024, 3, 2, Duration.new!(week: 3)) == {2024, 3, 23}\n    assert Calendar.ISO.shift_date(2024, 3, 2, Duration.new!(day: 5)) == {2024, 3, 7}\n\n    assert Calendar.ISO.shift_date(0, 1, 1, Duration.new!(month: 1)) == {0, 2, 1}\n    assert Calendar.ISO.shift_date(0, 1, 1, Duration.new!(year: 1)) == {1, 1, 1}\n    assert Calendar.ISO.shift_date(0, 1, 1, Duration.new!(year: -2, month: 2)) == {-2, 3, 1}\n    assert Calendar.ISO.shift_date(-4, 1, 1, Duration.new!(year: -1)) == {-5, 1, 1}\n\n    assert Calendar.ISO.shift_date(2024, 3, 2, Duration.new!(year: 1, month: 2, week: 3, day: 5)) ==\n             {2025, 5, 28}\n\n    assert Calendar.ISO.shift_date(2024, 3, 2, Duration.new!(year: -1, month: -2, week: -3)) ==\n             {2022, 12, 12}\n\n    assert Calendar.ISO.shift_date(2020, 2, 28, Duration.new!(day: 1)) == {2020, 2, 29}\n    assert Calendar.ISO.shift_date(2020, 2, 29, Duration.new!(year: 1)) == {2021, 2, 28}\n    assert Calendar.ISO.shift_date(2024, 3, 31, Duration.new!(month: -1)) == {2024, 2, 29}\n    assert Calendar.ISO.shift_date(2024, 3, 31, Duration.new!(month: -2)) == {2024, 1, 31}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 1)) == {2024, 2, 29}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 2)) == {2024, 3, 31}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 3)) == {2024, 4, 30}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 4)) == {2024, 5, 31}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 5)) == {2024, 6, 30}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 6)) == {2024, 7, 31}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 7)) == {2024, 8, 31}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 8)) == {2024, 9, 30}\n    assert Calendar.ISO.shift_date(2024, 1, 31, Duration.new!(month: 9)) == {2024, 10, 31}\n  end\n\n  test \"shift_naive_datetime/2\" do\n    assert Calendar.ISO.shift_naive_datetime(\n             2024,\n             3,\n             2,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!([])\n           ) == {2024, 3, 2, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             1,\n             1,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(year: 1)\n           ) == {2001, 1, 1, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             1,\n             1,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(month: 1)\n           ) == {2000, 2, 1, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             1,\n             1,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(month: 1, day: 28)\n           ) == {2000, 2, 29, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             1,\n             1,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(month: 1, day: 30)\n           ) == {2000, 3, 2, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             1,\n             1,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(month: 2, day: 29)\n           ) == {2000, 3, 30, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             2,\n             29,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(year: -1)\n           ) == {1999, 2, 28, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             2,\n             29,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(month: -1)\n           ) == {2000, 1, 29, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             2,\n             29,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(month: -1, day: -28)\n           ) == {2000, 1, 1, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             2,\n             29,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(month: -1, day: -30)\n           ) == {1999, 12, 30, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             2,\n             29,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(month: -1, day: -29)\n           ) == {1999, 12, 31, 0, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             1,\n             1,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(hour: 12)\n           ) == {2000, 1, 1, 12, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_naive_datetime(\n             2000,\n             1,\n             1,\n             0,\n             0,\n             0,\n             {0, 0},\n             Duration.new!(minute: -65)\n           ) == {1999, 12, 31, 22, 55, 0, {0, 0}}\n  end\n\n  test \"shift_time/2\" do\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(hour: 1)) == {1, 0, 0, {0, 0}}\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(hour: -1)) == {23, 0, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(minute: 30)) ==\n             {0, 30, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(minute: -30)) ==\n             {23, 30, 0, {0, 0}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(second: 30)) ==\n             {0, 0, 30, {0, 0}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(second: -30)) ==\n             {23, 59, 30, {0, 0}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(microsecond: {100, 6})) ==\n             {0, 0, 0, {100, 6}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(microsecond: {-100, 6})) ==\n             {23, 59, 59, {999_900, 6}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(microsecond: {2000, 4})) ==\n             {0, 0, 0, {2000, 4}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {0, 0}, Duration.new!(microsecond: {-2000, 4})) ==\n             {23, 59, 59, {998_000, 4}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {3500, 6}, Duration.new!(microsecond: {-2000, 4})) ==\n             {0, 0, 0, {1500, 4}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {3500, 4}, Duration.new!(minute: 5)) ==\n             {0, 5, 0, {3500, 4}}\n\n    assert Calendar.ISO.shift_time(0, 0, 0, {3500, 6}, Duration.new!(hour: 4)) ==\n             {4, 0, 0, {3500, 6}}\n\n    assert Calendar.ISO.shift_time(\n             23,\n             59,\n             59,\n             {999_900, 6},\n             Duration.new!(hour: 4, microsecond: {100, 6})\n           ) == {4, 0, 0, {0, 6}}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/naive_datetime_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\nCode.require_file(\"holocene.exs\", __DIR__)\nCode.require_file(\"fakes.exs\", __DIR__)\n\ndefmodule NaiveDateTimeTest do\n  use ExUnit.Case, async: true\n  doctest NaiveDateTime\n\n  test \"sigil_N\" do\n    assert ~N[2000-01-01T12:34:56] ==\n             %NaiveDateTime{\n               calendar: Calendar.ISO,\n               year: 2000,\n               month: 1,\n               day: 1,\n               hour: 12,\n               minute: 34,\n               second: 56\n             }\n\n    assert ~N[2000-01-01T12:34:56 Calendar.Holocene] ==\n             %NaiveDateTime{\n               calendar: Calendar.Holocene,\n               year: 2000,\n               month: 1,\n               day: 1,\n               hour: 12,\n               minute: 34,\n               second: 56\n             }\n\n    assert ~N[2000-01-01 12:34:56] ==\n             %NaiveDateTime{\n               calendar: Calendar.ISO,\n               year: 2000,\n               month: 1,\n               day: 1,\n               hour: 12,\n               minute: 34,\n               second: 56\n             }\n\n    assert ~N[2000-01-01 12:34:56 Calendar.Holocene] ==\n             %NaiveDateTime{\n               calendar: Calendar.Holocene,\n               year: 2000,\n               month: 1,\n               day: 1,\n               hour: 12,\n               minute: 34,\n               second: 56\n             }\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-50-50T12:34:56\" as NaiveDateTime for Calendar.ISO, reason: :invalid_date/,\n                 fn -> Code.eval_string(\"~N[2001-50-50T12:34:56]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01T12:34:65\" as NaiveDateTime for Calendar.ISO, reason: :invalid_time/,\n                 fn -> Code.eval_string(\"~N[2001-01-01T12:34:65]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"20010101 123456\" as NaiveDateTime for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(~s{~N[20010101 123456]}) end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01 12:34:56 notalias\" as NaiveDateTime for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(\"~N[2001-01-01 12:34:56 notalias]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01T12:34:56 notalias\" as NaiveDateTime for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(\"~N[2001-01-01T12:34:56 notalias]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-50-50T12:34:56\" as NaiveDateTime for Calendar.Holocene, reason: :invalid_date/,\n                 fn -> Code.eval_string(\"~N[2001-50-50T12:34:56 Calendar.Holocene]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"2001-01-01T12:34:65\" as NaiveDateTime for Calendar.Holocene, reason: :invalid_time/,\n                 fn -> Code.eval_string(\"~N[2001-01-01T12:34:65 Calendar.Holocene]\") end\n\n    assert_raise UndefinedFunctionError, fn ->\n      Code.eval_string(\"~N[2001-01-01 12:34:56 UnknownCalendar]\")\n    end\n\n    assert_raise UndefinedFunctionError, fn ->\n      Code.eval_string(\"~N[2001-01-01T12:34:56 UnknownCalendar]\")\n    end\n  end\n\n  test \"to_string/1\" do\n    assert to_string(~N[2000-01-01 23:00:07.005]) == \"2000-01-01 23:00:07.005\"\n    assert NaiveDateTime.to_string(~N[2000-01-01 23:00:07.005]) == \"2000-01-01 23:00:07.005\"\n\n    ndt = %{~N[2000-01-01 23:00:07.005] | calendar: FakeCalendar}\n    assert to_string(ndt) == \"1/1/2000F23::0::7\"\n  end\n\n  test \"inspect/1\" do\n    assert inspect(~N[2000-01-01 23:00:07.005]) == \"~N[2000-01-01 23:00:07.005]\"\n    assert inspect(~N[-0100-12-31 23:00:07.005]) == \"~N[-0100-12-31 23:00:07.005]\"\n\n    assert inspect(%{~N[2000-01-01 23:00:07.005] | year: 99999}) ==\n             \"NaiveDateTime.new!(99999, 1, 1, 23, 0, 7, {5000, 3})\"\n\n    ndt = %{~N[2000-01-01 23:00:07.005] | calendar: FakeCalendar}\n    assert inspect(ndt) == \"~N[1/1/2000F23::0::7 FakeCalendar]\"\n  end\n\n  test \"compare/2\" do\n    ndt1 = ~N[2000-04-16 13:30:15.0049]\n    ndt2 = ~N[2000-04-16 13:30:15.0050]\n    ndt3 = ~N[2001-04-16 13:30:15.0050]\n    ndt4 = ~N[-0001-04-16 13:30:15.004]\n    assert NaiveDateTime.compare(ndt1, ndt1) == :eq\n    assert NaiveDateTime.compare(ndt1, ndt2) == :lt\n    assert NaiveDateTime.compare(ndt2, ndt1) == :gt\n    assert NaiveDateTime.compare(ndt3, ndt1) == :gt\n    assert NaiveDateTime.compare(ndt3, ndt2) == :gt\n    assert NaiveDateTime.compare(ndt4, ndt4) == :eq\n    assert NaiveDateTime.compare(ndt1, ndt4) == :gt\n    assert NaiveDateTime.compare(ndt4, ndt3) == :lt\n  end\n\n  test \"before?/2 and after?/2\" do\n    ndt1 = ~N[2022-01-12 10:10:11.0019]\n    ndt2 = ~N[2022-02-16 13:20:15.0019]\n\n    assert NaiveDateTime.before?(ndt1, ndt2)\n    assert not NaiveDateTime.before?(ndt2, ndt1)\n\n    assert NaiveDateTime.after?(ndt2, ndt1)\n    assert not NaiveDateTime.after?(ndt1, ndt2)\n  end\n\n  test \"to_iso8601/1\" do\n    ndt = ~N[2000-04-16 12:34:15.1234]\n    ndt = put_in(ndt.calendar, FakeCalendar)\n\n    message =\n      \"cannot convert #{inspect(ndt)} to target calendar Calendar.ISO, \" <>\n        \"reason: #{inspect(ndt.calendar)} and Calendar.ISO have different day rollover moments, \" <>\n        \"making this conversion ambiguous\"\n\n    assert_raise ArgumentError, message, fn ->\n      NaiveDateTime.to_iso8601(ndt)\n    end\n  end\n\n  describe \"add\" do\n    test \"with other calendars\" do\n      assert ~N[2000-01-01 12:34:15.123456]\n             |> NaiveDateTime.convert!(Calendar.Holocene)\n             |> NaiveDateTime.add(10, :second) ==\n               %NaiveDateTime{\n                 calendar: Calendar.Holocene,\n                 year: 12000,\n                 month: 1,\n                 day: 1,\n                 hour: 12,\n                 minute: 34,\n                 second: 25,\n                 microsecond: {123_456, 6}\n               }\n    end\n\n    test \"with datetime\" do\n      dt = %DateTime{\n        year: 2000,\n        month: 2,\n        day: 29,\n        zone_abbr: \"CET\",\n        hour: 23,\n        minute: 0,\n        second: 7,\n        microsecond: {0, 0},\n        utc_offset: 3600,\n        std_offset: 0,\n        time_zone: \"Europe/Warsaw\"\n      }\n\n      assert NaiveDateTime.add(dt, 21, :second) == ~N[2000-02-29 23:00:28]\n    end\n  end\n\n  describe \"diff\" do\n    test \"with invalid time unit\" do\n      dt = NaiveDateTime.utc_now()\n\n      message =\n        ~r/unsupported time unit\\. Expected :day, :hour, :minute, :second, :millisecond, :microsecond, :nanosecond, or a positive integer, got \"day\"/\n\n      assert_raise ArgumentError, message, fn -> NaiveDateTime.diff(dt, dt, \"day\") end\n    end\n\n    test \"with other calendars\" do\n      assert ~N[2000-01-01 12:34:15.123456]\n             |> NaiveDateTime.convert!(Calendar.Holocene)\n             |> NaiveDateTime.add(10, :second)\n             |> NaiveDateTime.diff(~N[2000-01-01 12:34:15.123456]) == 10\n    end\n\n    test \"with datetime\" do\n      dt = %DateTime{\n        year: 2000,\n        month: 2,\n        day: 29,\n        zone_abbr: \"CET\",\n        hour: 23,\n        minute: 0,\n        second: 7,\n        microsecond: {0, 0},\n        utc_offset: 3600,\n        std_offset: 0,\n        time_zone: \"Europe/Warsaw\"\n      }\n\n      assert NaiveDateTime.diff(%{dt | second: 57}, dt, :second) == 50\n    end\n  end\n\n  test \"convert/2\" do\n    assert NaiveDateTime.convert(~N[2000-01-01 12:34:15.123400], Calendar.Holocene) ==\n             {:ok, Calendar.Holocene.naive_datetime(12000, 1, 1, 12, 34, 15, {123_400, 6})}\n\n    assert ~N[2000-01-01 12:34:15]\n           |> NaiveDateTime.convert!(Calendar.Holocene)\n           |> NaiveDateTime.convert!(Calendar.ISO) == ~N[2000-01-01 12:34:15]\n\n    assert ~N[2000-01-01 12:34:15.123456]\n           |> NaiveDateTime.convert!(Calendar.Holocene)\n           |> NaiveDateTime.convert!(Calendar.ISO) == ~N[2000-01-01 12:34:15.123456]\n\n    assert NaiveDateTime.convert(~N[2016-02-03 00:00:01], FakeCalendar) ==\n             {:error, :incompatible_calendars}\n\n    assert NaiveDateTime.convert(~N[1970-01-01 00:00:00], Calendar.Holocene) ==\n             {:ok, Calendar.Holocene.naive_datetime(11970, 1, 1, 0, 0, 0, {0, 0})}\n\n    assert NaiveDateTime.convert(DateTime.from_unix!(0, :second), Calendar.Holocene) ==\n             {:ok, Calendar.Holocene.naive_datetime(11970, 1, 1, 0, 0, 0, {0, 0})}\n  end\n\n  test \"truncate/2\" do\n    assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :microsecond) ==\n             ~N[2017-11-06 00:23:51.123456]\n\n    assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.0], :millisecond) ==\n             ~N[2017-11-06 00:23:51.0]\n\n    assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.999], :millisecond) ==\n             ~N[2017-11-06 00:23:51.999]\n\n    assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.1009], :millisecond) ==\n             ~N[2017-11-06 00:23:51.100]\n\n    assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :millisecond) ==\n             ~N[2017-11-06 00:23:51.123]\n\n    assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.000456], :millisecond) ==\n             ~N[2017-11-06 00:23:51.000]\n\n    assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :second) ==\n             ~N[2017-11-06 00:23:51]\n  end\n\n  test \"truncate/2 with datetime\" do\n    dt = %DateTime{\n      year: 2000,\n      month: 2,\n      day: 29,\n      zone_abbr: \"CET\",\n      hour: 23,\n      minute: 0,\n      second: 7,\n      microsecond: {3000, 6},\n      utc_offset: 3600,\n      std_offset: 0,\n      time_zone: \"Europe/Warsaw\"\n    }\n\n    assert NaiveDateTime.truncate(dt, :millisecond) == ~N[2000-02-29 23:00:07.003]\n    assert catch_error(NaiveDateTime.truncate(~T[00:00:00.000000], :millisecond))\n  end\n\n  describe \"utc_now/1\" do\n    test \"utc_now/1 with default calendar (ISO)\" do\n      naive_datetime = NaiveDateTime.utc_now()\n      assert naive_datetime.year >= 2019\n    end\n\n    test \"utc_now/1 with alternative calendar\" do\n      naive_datetime = NaiveDateTime.utc_now(Calendar.Holocene)\n      assert naive_datetime.calendar == Calendar.Holocene\n      assert naive_datetime.year >= 12019\n    end\n  end\n\n  describe \"local_now/1\" do\n    test \"local_now/1 with default calendar (ISO)\" do\n      naive_datetime = NaiveDateTime.local_now()\n      assert naive_datetime.year >= 2018\n    end\n\n    test \"local_now/1 alternative calendar\" do\n      naive_datetime = NaiveDateTime.local_now(Calendar.Holocene)\n      assert naive_datetime.calendar == Calendar.Holocene\n      assert naive_datetime.year >= 12018\n    end\n\n    test \"local_now/1 incompatible calendar\" do\n      assert_raise ArgumentError,\n                   ~s(cannot get \"local now\" in target calendar FakeCalendar, reason: cannot convert from Calendar.ISO to FakeCalendar.),\n                   fn ->\n                     NaiveDateTime.local_now(FakeCalendar)\n                   end\n    end\n  end\n\n  describe \"to_date/2\" do\n    test \"downcasting\" do\n      dt = %DateTime{\n        year: 2000,\n        month: 2,\n        day: 29,\n        zone_abbr: \"CET\",\n        hour: 23,\n        minute: 0,\n        second: 7,\n        microsecond: {3000, 6},\n        utc_offset: 3600,\n        std_offset: 0,\n        time_zone: \"Europe/Warsaw\"\n      }\n\n      assert NaiveDateTime.to_date(dt) == ~D[2000-02-29]\n    end\n\n    test \"upcasting\" do\n      assert catch_error(NaiveDateTime.to_date(~D[2000-02-29]))\n    end\n  end\n\n  describe \"to_time/2\" do\n    test \"downcasting\" do\n      dt = %DateTime{\n        year: 2000,\n        month: 2,\n        day: 29,\n        zone_abbr: \"CET\",\n        hour: 23,\n        minute: 0,\n        second: 7,\n        microsecond: {3000, 6},\n        utc_offset: 3600,\n        std_offset: 0,\n        time_zone: \"Europe/Warsaw\"\n      }\n\n      assert NaiveDateTime.to_time(dt) == ~T[23:00:07.003000]\n    end\n\n    test \"upcasting\" do\n      assert catch_error(NaiveDateTime.to_time(~T[00:00:00.000000]))\n    end\n  end\n\n  describe \"beginning_of_day/1\" do\n    test \"precision\" do\n      assert NaiveDateTime.beginning_of_day(~N[2000-01-01 23:00:07.123]) ==\n               ~N[2000-01-01 00:00:00.000]\n\n      assert NaiveDateTime.beginning_of_day(~N[2000-01-01 23:00:07]) == ~N[2000-01-01 00:00:00]\n    end\n  end\n\n  describe \"end_of_day/1\" do\n    test \"precision\" do\n      assert NaiveDateTime.end_of_day(~N[2000-01-01 23:00:07.1]) == ~N[2000-01-01 23:59:59.9]\n      assert NaiveDateTime.end_of_day(~N[2000-01-01 23:00:07.123]) == ~N[2000-01-01 23:59:59.999]\n\n      assert NaiveDateTime.end_of_day(~N[2000-01-01 23:00:07.12345]) ==\n               ~N[2000-01-01 23:59:59.99999]\n\n      assert NaiveDateTime.end_of_day(~N[2000-01-01 23:00:07]) == ~N[2000-01-01 23:59:59]\n    end\n  end\n\n  test \"shift/2\" do\n    naive_datetime = ~N[2000-01-01 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, year: 1) == ~N[2001-01-01 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, month: 1) == ~N[2000-02-01 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, week: 3) == ~N[2000-01-22 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, day: 2) == ~N[2000-01-03 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, hour: 6) == ~N[2000-01-01 06:00:00]\n    assert NaiveDateTime.shift(naive_datetime, minute: 30) == ~N[2000-01-01 00:30:00]\n    assert NaiveDateTime.shift(naive_datetime, second: 45) == ~N[2000-01-01 00:00:45]\n    assert NaiveDateTime.shift(naive_datetime, year: -1) == ~N[1999-01-01 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, month: -1) == ~N[1999-12-01 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, week: -1) == ~N[1999-12-25 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, day: -1) == ~N[1999-12-31 00:00:00]\n    assert NaiveDateTime.shift(naive_datetime, hour: -12) == ~N[1999-12-31 12:00:00]\n    assert NaiveDateTime.shift(naive_datetime, minute: -45) == ~N[1999-12-31 23:15:00]\n    assert NaiveDateTime.shift(naive_datetime, second: -30) == ~N[1999-12-31 23:59:30]\n    assert NaiveDateTime.shift(naive_datetime, year: 1, month: 2) == ~N[2001-03-01 00:00:00]\n\n    assert NaiveDateTime.shift(naive_datetime, microsecond: {-500, 6}) ==\n             ~N[1999-12-31 23:59:59.999500]\n\n    assert NaiveDateTime.shift(naive_datetime, microsecond: {500, 6}) ==\n             ~N[2000-01-01 00:00:00.000500]\n\n    assert NaiveDateTime.shift(naive_datetime, microsecond: {100, 6}) ==\n             ~N[2000-01-01 00:00:00.000100]\n\n    assert NaiveDateTime.shift(naive_datetime, microsecond: {100, 4}) ==\n             ~N[2000-01-01 00:00:00.0001]\n\n    assert NaiveDateTime.shift(naive_datetime, month: 2, day: 3, hour: 6, minute: 15) ==\n             ~N[2000-03-04 06:15:00]\n\n    assert NaiveDateTime.shift(naive_datetime,\n             year: 1,\n             month: 2,\n             week: 3,\n             day: 4,\n             hour: 5,\n             minute: 6,\n             second: 7,\n             microsecond: {8, 6}\n           ) == ~N[2001-03-26 05:06:07.000008]\n\n    assert NaiveDateTime.shift(naive_datetime,\n             year: -1,\n             month: -2,\n             week: -3,\n             day: -4,\n             hour: -5,\n             minute: -6,\n             second: -7,\n             microsecond: {-8, 6}\n           ) == ~N[1998-10-06 18:53:52.999992]\n\n    assert_raise ArgumentError,\n                 \"unknown unit :months. Expected :year, :month, :week, :day, :hour, :minute, :second, :microsecond\",\n                 fn -> NaiveDateTime.shift(~N[2000-01-01 00:00:00], months: 12) end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar/time_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\nCode.require_file(\"holocene.exs\", __DIR__)\nCode.require_file(\"fakes.exs\", __DIR__)\n\ndefmodule TimeTest do\n  use ExUnit.Case, async: true\n  doctest Time\n\n  test \"sigil_T\" do\n    assert ~T[12:34:56] ==\n             %Time{calendar: Calendar.ISO, hour: 12, minute: 34, second: 56}\n\n    assert ~T[12:34:56 Calendar.Holocene] ==\n             %Time{calendar: Calendar.Holocene, hour: 12, minute: 34, second: 56}\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"12:34:65\" as Time for Calendar.ISO, reason: :invalid_time/,\n                 fn -> Code.eval_string(\"~T[12:34:65]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"123456\" as Time for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(\"~T[123456]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"12:34:56 notalias\" as Time for Calendar.ISO, reason: :invalid_format/,\n                 fn -> Code.eval_string(\"~T[12:34:56 notalias]\") end\n\n    assert_raise ArgumentError,\n                 ~s/cannot parse \"12:34:65\" as Time for Calendar.Holocene, reason: :invalid_time/,\n                 fn -> Code.eval_string(\"~T[12:34:65 Calendar.Holocene]\") end\n\n    assert_raise UndefinedFunctionError, fn ->\n      Code.eval_string(\"~T[12:34:56 UnknownCalendar]\")\n    end\n  end\n\n  test \"to_iso8601/2\" do\n    time1 = ~T[23:00:07.005]\n    assert Time.to_iso8601(time1) == \"23:00:07.005\"\n    assert Time.to_iso8601(Map.from_struct(time1)) == \"23:00:07.005\"\n    assert Time.to_iso8601(time1, :basic) == \"230007.005\"\n\n    time2 = ~T[23:00:07.005 Calendar.Holocene]\n    assert Time.to_iso8601(time2) == \"23:00:07.005\"\n    assert Time.to_iso8601(Map.from_struct(time2)) == \"23:00:07.005\"\n    assert Time.to_iso8601(time2, :basic) == \"230007.005\"\n  end\n\n  test \"to_string/1\" do\n    time = ~T[23:00:07.005]\n    assert to_string(time) == \"23:00:07.005\"\n    assert Time.to_string(time) == \"23:00:07.005\"\n    assert Time.to_string(Map.from_struct(time)) == \"23:00:07.005\"\n\n    assert to_string(%{time | calendar: FakeCalendar}) == \"23::0::7\"\n    assert Time.to_string(%{time | calendar: FakeCalendar}) == \"23::0::7\"\n  end\n\n  test \"inspect/1\" do\n    assert inspect(~T[23:00:07.005]) == \"~T[23:00:07.005]\"\n\n    time = %{~T[23:00:07.005] | calendar: FakeCalendar}\n    assert inspect(time) == \"~T[23::0::7 FakeCalendar]\"\n  end\n\n  test \"compare/2\" do\n    time0 = ~T[01:01:01.0]\n    time1 = ~T[01:01:01.005]\n    time2 = ~T[01:01:01.0050]\n    time3 = ~T[23:01:01.0050]\n    assert Time.compare(time0, time1) == :lt\n    assert Time.compare(time1, time1) == :eq\n    assert Time.compare(time1, time2) == :eq\n    assert Time.compare(time1, time3) == :lt\n    assert Time.compare(time3, time2) == :gt\n\n    time1_holocene = ~T[01:01:01.005 Calendar.Holocene]\n    assert Time.compare(time1_holocene, time1) == :eq\n    assert Time.compare(time1_holocene, time2) == :eq\n    assert Time.compare(time1_holocene, time3) == :lt\n  end\n\n  test \"before?/2 and after?/2\" do\n    time1 = ~T[05:02:01.234]\n    time2 = ~T[10:00:04.123]\n\n    assert Time.before?(time1, time2)\n    assert not Time.before?(time2, time1)\n\n    assert Time.after?(time2, time1)\n    assert not Time.after?(time1, time2)\n  end\n\n  test \"diff/3\" do\n    time1 = ~T[05:02:01.234]\n    time2 = ~T[10:00:04.123]\n    time1_holocene = ~T[05:02:01.234 Calendar.Holocene]\n\n    assert Time.diff(time1, time2) == -17883\n    assert Time.diff(time1, time2, :hour) == -4\n    assert Time.diff(time1, time2, :minute) == -298\n    assert Time.diff(time1, time2, :second) == -17883\n    assert Time.diff(time1, time2, :millisecond) == -17_882_889\n    assert Time.diff(time1, time2, :microsecond) == -17_882_889_000\n\n    assert Time.diff(time1_holocene, time2) == -17883\n    assert Time.diff(time1_holocene, time2, :hour) == -4\n    assert Time.diff(time1_holocene, time2, :minute) == -298\n    assert Time.diff(time1_holocene, time2, :second) == -17883\n    assert Time.diff(time1_holocene, time2, :millisecond) == -17_882_889\n    assert Time.diff(time1_holocene, time2, :microsecond) == -17_882_889_000\n  end\n\n  test \"truncate/2\" do\n    assert Time.truncate(~T[01:01:01.123456], :microsecond) == ~T[01:01:01.123456]\n\n    assert Time.truncate(~T[01:01:01.0], :millisecond) == ~T[01:01:01.0]\n    assert Time.truncate(~T[01:01:01.00], :millisecond) == ~T[01:01:01.00]\n    assert Time.truncate(~T[01:01:01.1], :millisecond) == ~T[01:01:01.1]\n    assert Time.truncate(~T[01:01:01.100], :millisecond) == ~T[01:01:01.100]\n    assert Time.truncate(~T[01:01:01.999], :millisecond) == ~T[01:01:01.999]\n    assert Time.truncate(~T[01:01:01.1000], :millisecond) == ~T[01:01:01.100]\n    assert Time.truncate(~T[01:01:01.1001], :millisecond) == ~T[01:01:01.100]\n    assert Time.truncate(~T[01:01:01.123456], :millisecond) == ~T[01:01:01.123]\n    assert Time.truncate(~T[01:01:01.000123], :millisecond) == ~T[01:01:01.000]\n    assert Time.truncate(~T[01:01:01.00012], :millisecond) == ~T[01:01:01.000]\n\n    assert Time.truncate(~T[01:01:01.123456], :second) == ~T[01:01:01]\n  end\n\n  test \"add/3\" do\n    time = ~T[00:00:00.0]\n\n    assert Time.add(time, 1, :hour) == ~T[01:00:00.0]\n\n    assert Time.add(time, 1, 10) == ~T[00:00:00.100000]\n\n    assert_raise ArgumentError, ~r/Expected :hour, :minute, :second/, fn ->\n      Time.add(time, 1, 0)\n    end\n  end\n\n  test \"shift/2\" do\n    time = ~T[00:00:00.0]\n    assert Time.shift(time, hour: 1) == ~T[01:00:00.0]\n    assert Time.shift(time, hour: 25) == ~T[01:00:00.0]\n    assert Time.shift(time, minute: 25) == ~T[00:25:00.0]\n    assert Time.shift(time, second: 50) == ~T[00:00:50.0]\n    assert Time.shift(time, microsecond: {150, 6}) == ~T[00:00:00.000150]\n    assert Time.shift(time, microsecond: {1000, 4}) == ~T[00:00:00.0010]\n    assert Time.shift(time, hour: 2, minute: 65, second: 5) == ~T[03:05:05.0]\n\n    assert_raise ArgumentError,\n                 \"unsupported unit :day. Expected :hour, :minute, :second, :microsecond\",\n                 fn -> Time.shift(time, day: 1) end\n\n    assert_raise ArgumentError,\n                 \"unknown unit :hours. Expected :hour, :minute, :second, :microsecond\",\n                 fn -> Time.shift(time, hours: 12) end\n\n    assert_raise ArgumentError,\n                 \"cannot shift time by date scale unit. Expected :hour, :minute, :second, :microsecond\",\n                 fn -> Time.shift(time, %Duration{day: 1}) end\n\n    assert_raise ArgumentError,\n                 \"unsupported value nil for :minute. Expected an integer\",\n                 fn -> Time.shift(time, minute: nil) end\n\n    assert_raise ArgumentError,\n                 ~r/unsupported value 1 for :microsecond. Expected a tuple \\{ms, precision\\}/,\n                 fn -> Time.shift(time, microsecond: 1) end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/calendar_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule CalendarTest do\n  use ExUnit.Case, async: true\n  doctest Calendar\n\n  describe \"strftime/3\" do\n    test \"returns received string if there is no datetime formatting to be found in it\" do\n      assert Calendar.strftime(~N[2019-08-20 15:47:34.001], \"same string\") == \"same string\"\n    end\n\n    test \"formats all time zones blank when receiving a NaiveDateTime\" do\n      assert Calendar.strftime(~N[2019-08-15 17:07:57.001], \"%z%Z\") == \"\"\n    end\n\n    test \"raises error when trying to format a date with a map that has no date fields\" do\n      time_without_date = %{hour: 15, minute: 47, second: 34, microsecond: {0, 0}}\n\n      assert_raise KeyError, fn -> Calendar.strftime(time_without_date, \"%x\") end\n    end\n\n    test \"raises error when trying to format a time with a map that has no time fields\" do\n      date_without_time = %{year: 2019, month: 8, day: 20}\n\n      assert_raise KeyError, fn -> Calendar.strftime(date_without_time, \"%X\") end\n    end\n\n    test \"raises error when the format is invalid\" do\n      assert_raise ArgumentError, \"invalid strftime format: %-\", fn ->\n        Calendar.strftime(~N[2019-08-20 15:47:34.001], \"%-2-ç\")\n      end\n\n      assert_raise ArgumentError, \"invalid strftime format: %\", fn ->\n        Calendar.strftime(~N[2019-08-20 15:47:34.001], \"%\")\n      end\n    end\n\n    test \"raises error when the preferred_datetime calls itself\" do\n      assert_raise ArgumentError, fn ->\n        Calendar.strftime(~N[2019-08-20 15:47:34.001], \"%c\", preferred_datetime: \"%c\")\n      end\n    end\n\n    test \"raises error when the preferred_date calls itself\" do\n      assert_raise ArgumentError, fn ->\n        Calendar.strftime(~N[2019-08-20 15:47:34.001], \"%x\", preferred_date: \"%x\")\n      end\n    end\n\n    test \"raises error when the preferred_time calls itself\" do\n      assert_raise ArgumentError, fn ->\n        Calendar.strftime(~N[2019-08-20 15:47:34.001], \"%X\", preferred_time: \"%X\")\n      end\n    end\n\n    test \"raises error when the preferred formats creates a circular chain\" do\n      assert_raise ArgumentError, fn ->\n        Calendar.strftime(~N[2019-08-20 15:47:34.001], \"%c\",\n          preferred_datetime: \"%x\",\n          preferred_date: \"%X\",\n          preferred_time: \"%c\"\n        )\n      end\n    end\n\n    test \"with preferred formats are included multiple times on the same string\" do\n      assert Calendar.strftime(~N[2019-08-15 17:07:57.001], \"%c %c %x %x %X %X\") ==\n               \"2019-08-15 17:07:57 2019-08-15 17:07:57 2019-08-15 2019-08-15 17:07:57 17:07:57\"\n    end\n\n    test \"`-` removes padding\" do\n      assert Calendar.strftime(~D[2019-01-01], \"%-j\") == \"1\"\n      assert Calendar.strftime(~T[17:07:57.001], \"%-999M\") == \"7\"\n    end\n\n    test \"formats time zones correctly when receiving a DateTime\" do\n      datetime_with_zone = %DateTime{\n        year: 2019,\n        month: 8,\n        day: 15,\n        zone_abbr: \"EEST\",\n        hour: 17,\n        minute: 7,\n        second: 57,\n        microsecond: {0, 0},\n        utc_offset: 7200,\n        std_offset: 3600,\n        time_zone: \"UK\"\n      }\n\n      assert Calendar.strftime(datetime_with_zone, \"%z %Z\") == \"+0300 EEST\"\n    end\n\n    test \"formats AM and PM correctly on the %P and %p options\" do\n      am_time_almost_pm = ~U[2019-08-26 11:59:59.001Z]\n      pm_time = ~U[2019-08-26 12:00:57.001Z]\n      pm_time_almost_am = ~U[2019-08-26 23:59:57.001Z]\n      am_time = ~U[2019-08-26 00:00:01.001Z]\n\n      assert Calendar.strftime(am_time_almost_pm, \"%P %p\") == \"am AM\"\n      assert Calendar.strftime(pm_time, \"%P %p\") == \"pm PM\"\n      assert Calendar.strftime(pm_time_almost_am, \"%P %p\") == \"pm PM\"\n      assert Calendar.strftime(am_time, \"%P %p\") == \"am AM\"\n    end\n\n    test \"formats all weekdays correctly with %A and %a formats\" do\n      sunday = ~U[2019-08-25 11:59:59.001Z]\n      monday = ~U[2019-08-26 11:59:59.001Z]\n      tuesday = ~U[2019-08-27 11:59:59.001Z]\n      wednesday = ~U[2019-08-28 11:59:59.001Z]\n      thursday = ~U[2019-08-29 11:59:59.001Z]\n      friday = ~U[2019-08-30 11:59:59.001Z]\n      saturday = ~U[2019-08-31 11:59:59.001Z]\n\n      assert Calendar.strftime(sunday, \"%A %a\") == \"Sunday Sun\"\n      assert Calendar.strftime(monday, \"%A %a\") == \"Monday Mon\"\n      assert Calendar.strftime(tuesday, \"%A %a\") == \"Tuesday Tue\"\n      assert Calendar.strftime(wednesday, \"%A %a\") == \"Wednesday Wed\"\n      assert Calendar.strftime(thursday, \"%A %a\") == \"Thursday Thu\"\n      assert Calendar.strftime(friday, \"%A %a\") == \"Friday Fri\"\n      assert Calendar.strftime(saturday, \"%A %a\") == \"Saturday Sat\"\n    end\n\n    test \"formats all months correctly with the %B and %b formats\" do\n      assert Calendar.strftime(%{month: 1}, \"%B %b\") == \"January Jan\"\n      assert Calendar.strftime(%{month: 2}, \"%B %b\") == \"February Feb\"\n      assert Calendar.strftime(%{month: 3}, \"%B %b\") == \"March Mar\"\n      assert Calendar.strftime(%{month: 4}, \"%B %b\") == \"April Apr\"\n      assert Calendar.strftime(%{month: 5}, \"%B %b\") == \"May May\"\n      assert Calendar.strftime(%{month: 6}, \"%B %b\") == \"June Jun\"\n      assert Calendar.strftime(%{month: 7}, \"%B %b\") == \"July Jul\"\n      assert Calendar.strftime(%{month: 8}, \"%B %b\") == \"August Aug\"\n      assert Calendar.strftime(%{month: 9}, \"%B %b\") == \"September Sep\"\n      assert Calendar.strftime(%{month: 10}, \"%B %b\") == \"October Oct\"\n      assert Calendar.strftime(%{month: 11}, \"%B %b\") == \"November Nov\"\n      assert Calendar.strftime(%{month: 12}, \"%B %b\") == \"December Dec\"\n    end\n\n    test \"formats all weekdays correctly on %A with day_of_week_names option\" do\n      sunday = ~U[2019-08-25 11:59:59.001Z]\n      monday = ~U[2019-08-26 11:59:59.001Z]\n      tuesday = ~U[2019-08-27 11:59:59.001Z]\n      wednesday = ~U[2019-08-28 11:59:59.001Z]\n      thursday = ~U[2019-08-29 11:59:59.001Z]\n      friday = ~U[2019-08-30 11:59:59.001Z]\n      saturday = ~U[2019-08-31 11:59:59.001Z]\n\n      day_of_week_names = fn day_of_week ->\n        {\"segunda-feira\", \"terça-feira\", \"quarta-feira\", \"quinta-feira\", \"sexta-feira\", \"sábado\",\n         \"domingo\"}\n        |> elem(day_of_week - 1)\n      end\n\n      assert Calendar.strftime(sunday, \"%A\", day_of_week_names: day_of_week_names) ==\n               \"domingo\"\n\n      assert Calendar.strftime(monday, \"%A\", day_of_week_names: day_of_week_names) ==\n               \"segunda-feira\"\n\n      assert Calendar.strftime(tuesday, \"%A\", day_of_week_names: day_of_week_names) ==\n               \"terça-feira\"\n\n      assert Calendar.strftime(wednesday, \"%A\", day_of_week_names: day_of_week_names) ==\n               \"quarta-feira\"\n\n      assert Calendar.strftime(thursday, \"%A\", day_of_week_names: day_of_week_names) ==\n               \"quinta-feira\"\n\n      assert Calendar.strftime(friday, \"%A\", day_of_week_names: day_of_week_names) ==\n               \"sexta-feira\"\n\n      assert Calendar.strftime(saturday, \"%A\", day_of_week_names: day_of_week_names) ==\n               \"sábado\"\n    end\n\n    test \"formats all months correctly on the %B with month_names option\" do\n      month_names = fn month ->\n        {\"январь\", \"февраль\", \"март\", \"апрель\", \"май\", \"июнь\", \"июль\", \"август\", \"сентябрь\",\n         \"октябрь\", \"ноябрь\", \"декабрь\"}\n        |> elem(month - 1)\n      end\n\n      assert Calendar.strftime(%{month: 1}, \"%B\", month_names: month_names) == \"январь\"\n      assert Calendar.strftime(%{month: 2}, \"%B\", month_names: month_names) == \"февраль\"\n      assert Calendar.strftime(%{month: 3}, \"%B\", month_names: month_names) == \"март\"\n      assert Calendar.strftime(%{month: 4}, \"%B\", month_names: month_names) == \"апрель\"\n      assert Calendar.strftime(%{month: 5}, \"%B\", month_names: month_names) == \"май\"\n      assert Calendar.strftime(%{month: 6}, \"%B\", month_names: month_names) == \"июнь\"\n      assert Calendar.strftime(%{month: 7}, \"%B\", month_names: month_names) == \"июль\"\n      assert Calendar.strftime(%{month: 8}, \"%B\", month_names: month_names) == \"август\"\n      assert Calendar.strftime(%{month: 9}, \"%B\", month_names: month_names) == \"сентябрь\"\n      assert Calendar.strftime(%{month: 10}, \"%B\", month_names: month_names) == \"октябрь\"\n      assert Calendar.strftime(%{month: 11}, \"%B\", month_names: month_names) == \"ноябрь\"\n      assert Calendar.strftime(%{month: 12}, \"%B\", month_names: month_names) == \"декабрь\"\n    end\n\n    test \"formats all weekdays correctly on the %a format with abbreviated_day_of_week_names option\" do\n      sunday = ~U[2019-08-25 11:59:59.001Z]\n      monday = ~U[2019-08-26 11:59:59.001Z]\n      tuesday = ~U[2019-08-27 11:59:59.001Z]\n      wednesday = ~U[2019-08-28 11:59:59.001Z]\n      thursday = ~U[2019-08-29 11:59:59.001Z]\n      friday = ~U[2019-08-30 11:59:59.001Z]\n      saturday = ~U[2019-08-31 11:59:59.001Z]\n\n      abbreviated_day_of_week_names = fn day_of_week ->\n        {\"seg\", \"ter\", \"qua\", \"qui\", \"sex\", \"sáb\", \"dom\"}\n        |> elem(day_of_week - 1)\n      end\n\n      assert Calendar.strftime(sunday, \"%a\",\n               abbreviated_day_of_week_names: abbreviated_day_of_week_names\n             ) == \"dom\"\n\n      assert Calendar.strftime(monday, \"%a\",\n               abbreviated_day_of_week_names: abbreviated_day_of_week_names\n             ) == \"seg\"\n\n      assert Calendar.strftime(tuesday, \"%a\",\n               abbreviated_day_of_week_names: abbreviated_day_of_week_names\n             ) == \"ter\"\n\n      assert Calendar.strftime(wednesday, \"%a\",\n               abbreviated_day_of_week_names: abbreviated_day_of_week_names\n             ) == \"qua\"\n\n      assert Calendar.strftime(thursday, \"%a\",\n               abbreviated_day_of_week_names: abbreviated_day_of_week_names\n             ) == \"qui\"\n\n      assert Calendar.strftime(friday, \"%a\",\n               abbreviated_day_of_week_names: abbreviated_day_of_week_names\n             ) == \"sex\"\n\n      assert Calendar.strftime(saturday, \"%a\",\n               abbreviated_day_of_week_names: abbreviated_day_of_week_names\n             ) == \"sáb\"\n    end\n\n    test \"formats all months correctly on the %b format with abbreviated_month_names option\" do\n      abbreviated_month_names = fn month ->\n        {\"янв\", \"февр\", \"март\", \"апр\", \"май\", \"июнь\", \"июль\", \"авг\", \"сент\", \"окт\", \"нояб\", \"дек\"}\n        |> elem(month - 1)\n      end\n\n      assert Calendar.strftime(%{month: 1}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"янв\"\n\n      assert Calendar.strftime(%{month: 2}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"февр\"\n\n      assert Calendar.strftime(%{month: 3}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"март\"\n\n      assert Calendar.strftime(%{month: 4}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"апр\"\n\n      assert Calendar.strftime(%{month: 5}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"май\"\n\n      assert Calendar.strftime(%{month: 6}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"июнь\"\n\n      assert Calendar.strftime(%{month: 7}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"июль\"\n\n      assert Calendar.strftime(%{month: 8}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"авг\"\n\n      assert Calendar.strftime(%{month: 9}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) ==\n               \"сент\"\n\n      assert Calendar.strftime(%{month: 10}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) == \"окт\"\n\n      assert Calendar.strftime(%{month: 11}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) == \"нояб\"\n\n      assert Calendar.strftime(%{month: 12}, \"%b\",\n               abbreviated_month_names: abbreviated_month_names\n             ) == \"дек\"\n    end\n\n    test \"formats ignores padding and width options on microseconds\" do\n      datetime = ~U[2019-08-15 17:07:57.001234Z]\n      assert Calendar.strftime(datetime, \"%f\") == \"001234\"\n      assert Calendar.strftime(datetime, \"%f\") == Calendar.strftime(datetime, \"%_20f\")\n      assert Calendar.strftime(datetime, \"%f\") == Calendar.strftime(datetime, \"%020f\")\n      assert Calendar.strftime(datetime, \"%f\") == Calendar.strftime(datetime, \"%-f\")\n    end\n\n    test \"formats properly dates with different microsecond precisions\" do\n      assert Calendar.strftime(~U[2019-08-15 17:07:57.5Z], \"%f\") == \"5\"\n      assert Calendar.strftime(~U[2019-08-15 17:07:57.45Z], \"%f\") == \"45\"\n      assert Calendar.strftime(~U[2019-08-15 17:07:57.345Z], \"%f\") == \"345\"\n      assert Calendar.strftime(~U[2019-08-15 17:07:57.2345Z], \"%f\") == \"2345\"\n      assert Calendar.strftime(~U[2019-08-15 17:07:57.12345Z], \"%f\") == \"12345\"\n      assert Calendar.strftime(~U[2019-08-15 17:07:57.012345Z], \"%f\") == \"012345\"\n    end\n\n    test \"formats properly different microsecond precisions of zero\" do\n      assert Calendar.strftime(~N[2019-08-15 17:07:57.0], \"%f\") == \"0\"\n      assert Calendar.strftime(~N[2019-08-15 17:07:57.00], \"%f\") == \"00\"\n      assert Calendar.strftime(~N[2019-08-15 17:07:57.000], \"%f\") == \"000\"\n      assert Calendar.strftime(~N[2019-08-15 17:07:57.0000], \"%f\") == \"0000\"\n      assert Calendar.strftime(~N[2019-08-15 17:07:57.00000], \"%f\") == \"00000\"\n      assert Calendar.strftime(~N[2019-08-15 17:07:57.000000], \"%f\") == \"000000\"\n    end\n\n    test \"returns a single zero if there's no microseconds precision\" do\n      assert Calendar.strftime(~N[2019-08-15 17:07:57], \"%f\") == \"0\"\n    end\n\n    test \"handles `0` both as padding and as part of a width\" do\n      assert Calendar.strftime(~N[2019-08-15 17:07:57], \"%10A\") == \"  Thursday\"\n      assert Calendar.strftime(~N[2019-08-15 17:07:57], \"%010A\") == \"00Thursday\"\n    end\n\n    test \"formats Epoch time with %s\" do\n      assert Calendar.strftime(~N[2019-08-15 17:07:57], \"%s\") == \"1565888877\"\n\n      datetime = %DateTime{\n        year: 2019,\n        month: 8,\n        day: 15,\n        hour: 17,\n        minute: 7,\n        second: 57,\n        microsecond: {0, 0},\n        time_zone: \"Europe/Berlin\",\n        zone_abbr: \"CET\",\n        utc_offset: 3600,\n        std_offset: 0\n      }\n\n      assert Calendar.strftime(datetime, \"%s\") == \"1565885277\"\n    end\n\n    test \"formats datetime with all options and modifiers\" do\n      assert Calendar.strftime(\n               ~U[2019-08-15 17:07:57.001Z],\n               \"%04% %a %A %b %B %-3c %d %f %H %I %j %m %_5M %p %P %q %S %u %x %X %y %Y %z %Z\"\n             ) ==\n               \"000% Thu Thursday Aug August 2019-08-15 17:07:57 15 001 17 05 227 08     7 PM pm 3 57 4 2019-08-15 17:07:57 19 2019 +0000 UTC\"\n    end\n\n    test \"formats according to custom configs\" do\n      assert Calendar.strftime(\n               ~U[2019-08-15 17:07:57.001Z],\n               \"%A %a %p %B %b %c %x %X\",\n               am_pm_names: fn\n                 :am -> \"a\"\n                 :pm -> \"p\"\n               end,\n               month_names: fn month ->\n                 {\"Janeiro\", \"Fevereiro\", \"Março\", \"Abril\", \"Maio\", \"Junho\", \"Julho\", \"Agosto\",\n                  \"Setembro\", \"Outubro\", \"Novembro\", \"Dezembro\"}\n                 |> elem(month - 1)\n               end,\n               day_of_week_names: fn day_of_week ->\n                 {\"понедельник\", \"вторник\", \"среда\", \"четверг\", \"пятница\", \"суббота\",\n                  \"воскресенье\"}\n                 |> elem(day_of_week - 1)\n               end,\n               abbreviated_month_names: fn month ->\n                 {\"Jan\", \"Fev\", \"Mar\", \"Abr\", \"Mai\", \"Jun\", \"Jul\", \"Ago\", \"Set\", \"Out\", \"Nov\",\n                  \"Dez\"}\n                 |> elem(month - 1)\n               end,\n               abbreviated_day_of_week_names: fn day_of_week ->\n                 {\"ПНД\", \"ВТР\", \"СРД\", \"ЧТВ\", \"ПТН\", \"СБТ\", \"ВСК\"}\n                 |> elem(day_of_week - 1)\n               end,\n               preferred_date: \"%05Y-%m-%d\",\n               preferred_time: \"%M:%_3H%S\",\n               preferred_datetime: \"%%\"\n             ) == \"четверг ЧТВ P Agosto Ago % 02019-08-15 07: 1757\"\n    end\n\n    test \"formats according to custom configs with 2-arity functions\" do\n      assert Calendar.strftime(\n               ~U[2019-08-15 17:07:57.001Z],\n               \"%A %a %p %B %b %c %x %X\",\n               am_pm_names: fn\n                 :am, ~U[2019-08-15 17:07:57.001Z] -> \"a\"\n                 :pm, ~U[2019-08-15 17:07:57.001Z] -> \"p\"\n               end,\n               month_names: fn month, ~U[2019-08-15 17:07:57.001Z] ->\n                 {\"Janeiro\", \"Fevereiro\", \"Março\", \"Abril\", \"Maio\", \"Junho\", \"Julho\", \"Agosto\",\n                  \"Setembro\", \"Outubro\", \"Novembro\", \"Dezembro\"}\n                 |> elem(month - 1)\n               end,\n               day_of_week_names: fn day_of_week, ~U[2019-08-15 17:07:57.001Z] ->\n                 {\"понедельник\", \"вторник\", \"среда\", \"четверг\", \"пятница\", \"суббота\",\n                  \"воскресенье\"}\n                 |> elem(day_of_week - 1)\n               end,\n               abbreviated_month_names: fn month, ~U[2019-08-15 17:07:57.001Z] ->\n                 {\"Jan\", \"Fev\", \"Mar\", \"Abr\", \"Mai\", \"Jun\", \"Jul\", \"Ago\", \"Set\", \"Out\", \"Nov\",\n                  \"Dez\"}\n                 |> elem(month - 1)\n               end,\n               abbreviated_day_of_week_names: fn day_of_week, ~U[2019-08-15 17:07:57.001Z] ->\n                 {\"ПНД\", \"ВТР\", \"СРД\", \"ЧТВ\", \"ПТН\", \"СБТ\", \"ВСК\"}\n                 |> elem(day_of_week - 1)\n               end,\n               preferred_date: \"%05Y-%m-%d\",\n               preferred_time: \"%M:%_3H%S\",\n               preferred_datetime: \"%%\"\n             ) == \"четверг ЧТВ P Agosto Ago % 02019-08-15 07: 1757\"\n    end\n\n    test \"raises on unknown option according to custom configs\" do\n      assert_raise ArgumentError, \"unknown option :unknown given to Calendar.strftime/3\", fn ->\n        Calendar.strftime(~D[2019-08-15], \"%D\", unknown: \"option\")\n      end\n    end\n\n    test \"zero padding for negative year\" do\n      assert Calendar.strftime(Date.new!(-1, 1, 1), \"%Y\") == \"-0001\"\n      assert Calendar.strftime(Date.new!(-11, 1, 1), \"%Y\") == \"-0011\"\n      assert Calendar.strftime(Date.new!(-111, 1, 1), \"%Y\") == \"-0111\"\n      assert Calendar.strftime(Date.new!(-1111, 1, 1), \"%Y\") == \"-1111\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/changelog_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nExUnit.start()\n\ndefmodule ChangelogTest do\n  use ExUnit.Case, async: true\n  doctest_file(Path.expand(\"../../../../CHANGELOG.md\", __DIR__))\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_formatter/calls_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Formatter.CallsTest do\n  use ExUnit.Case, async: true\n\n  import CodeFormatterHelpers\n\n  @short_length [line_length: 10]\n  @medium_length [line_length: 20]\n\n  describe \"next break fits\" do\n    test \"does not apply to function calls\" do\n      bad = \"foo(very_long_call(bar))\"\n\n      good = \"\"\"\n      foo(\n        very_long_call(\n          bar\n        )\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"does not apply to strings\" do\n      bad = \"foo(\\\"very long string\\\")\"\n\n      good = \"\"\"\n      foo(\n        \"very long string\"\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"for functions\" do\n      assert_same \"\"\"\n      foo(fn x -> y end)\n      \"\"\"\n\n      assert_same \"\"\"\n      foo(fn\n        a1 -> :ok\n        b2 -> :error\n      end)\n      \"\"\"\n\n      assert_same \"\"\"\n      foo(bar, fn\n        a1 -> :ok\n        b2 -> :error\n      end)\n      \"\"\"\n\n      assert_same \"\"\"\n                  foo(fn x ->\n                    :really_long_atom\n                  end)\n                  \"\"\",\n                  @medium_length\n\n      assert_same \"\"\"\n                  foo(bar, fn\n                    a1 ->\n                      :ok\n\n                    b2 ->\n                      :really_long_error\n                  end)\n                  \"\"\",\n                  @medium_length\n    end\n\n    test \"for heredocs\" do\n      assert_same \"\"\"\n      foo(~c'''\n      bar\n      ''')\n      \"\"\"\n\n      assert_same ~S'''\n      foo(\"\"\"\n      bar\n      \"\"\")\n      '''\n\n      assert_same \"\"\"\n      foo(~S'''\n      bar\n      ''')\n      \"\"\"\n\n      assert_same \"\"\"\n                  foo(~S'''\n                  very long line does trigger another break\n                  ''')\n                  \"\"\",\n                  @short_length\n    end\n\n    test \"for lists\" do\n      bad = \"foo([1, 2, 3, 4])\"\n\n      good = \"\"\"\n      foo([\n        1,\n        2,\n        3,\n        4\n      ])\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"for {} calls\" do\n      bad = \"\"\"\n      alias Foo.{\n              Bar, Baz\n            }\n      \"\"\"\n\n      good = \"\"\"\n      alias Foo.{\n        Bar,\n        Baz\n      }\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"for binaries only on eol\" do\n      bad = \"foo(<<1, 2, 3, 4>>)\"\n\n      good = \"\"\"\n      foo(\n        <<1, 2,\n          3, 4>>\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"\"\"\n      foo(<<\n        # foo\n        1,\n        2,\n        3,\n        4>>)\n      \"\"\"\n\n      good = \"\"\"\n      foo(<<\n        # foo\n        1,\n        2,\n        3,\n        4\n      >>)\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"for maps\" do\n      assert_same \"a(%{x: 1})\", @short_length\n      assert_format \"ab(%{x: 1})\", \"ab(%{\\n  x: 1\\n})\", @short_length\n    end\n  end\n\n  describe \"local calls\" do\n    test \"without arguments\" do\n      assert_format \"foo( )\", \"foo()\"\n    end\n\n    test \"without arguments doesn't split on line limit\" do\n      assert_same \"very_long_function_name()\", @short_length\n    end\n\n    test \"removes outer parens except for unquote_splicing/1\" do\n      assert_format \"(foo())\", \"foo()\"\n      assert_same \"(unquote_splicing(123))\"\n    end\n\n    test \"with arguments\" do\n      assert_format \"foo( :one ,:two,\\n   :three)\", \"foo(:one, :two, :three)\"\n    end\n\n    test \"with arguments splits on line limit\" do\n      bad = \"\"\"\n      fun(x, y, z)\n      \"\"\"\n\n      good = \"\"\"\n      fun(\n        x,\n        y,\n        z\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with arguments on comma limit\" do\n      bad = \"\"\"\n      import(foo(abc, cde), :next)\n      \"\"\"\n\n      good = \"\"\"\n      import(\n        foo(abc, cde),\n        :next\n      )\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"with keyword lists\" do\n      assert_same \"foo(foo: 1, bar: 2)\"\n      assert_same \"foo(:hello, foo: 1, bar: 2)\"\n\n      bad = \"\"\"\n      foo(:hello, foo: 1, bar: 2)\n      \"\"\"\n\n      good = \"\"\"\n      foo(\n        :hello,\n        foo: 1,\n        bar: 2\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"\"\"\n      foo(:hello, foo: 1,\n        bar: 2, baz: 3)\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      foo(:hello, foo: 1, bar: 2, baz: 3)\n      \"\"\"\n    end\n\n    test \"with lists maybe rewritten as keyword lists\" do\n      assert_format \"foo([foo: 1, bar: 2])\", \"foo(foo: 1, bar: 2)\"\n      assert_format \"foo(:arg, [foo: 1, bar: 2])\", \"foo(:arg, foo: 1, bar: 2)\"\n      assert_same \"foo(:arg, [:elem, foo: 1, bar: 2])\"\n    end\n\n    test \"without parens\" do\n      assert_same \"import :foo, :bar\"\n      assert_same \"bar = if foo, do: bar, else: baz\"\n\n      assert_same \"\"\"\n      for :one,\n          :two,\n          :three,\n          fn ->\n            :ok\n          end\n      \"\"\"\n\n      assert_same \"\"\"\n      for :one, fn ->\n        :ok\n      end\n      \"\"\"\n    end\n\n    test \"without parens on line limit\" do\n      bad = \"import :long_atom, :other_arg\"\n\n      good = \"\"\"\n      import :long_atom,\n             :other_arg\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"without parens on comma limit\" do\n      bad = \"\"\"\n      import foo(abc, cde), :next\n      \"\"\"\n\n      good = \"\"\"\n      import foo(\n               abc,\n               cde\n             ),\n             :next\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"without parens and with keyword lists preserves multiline\" do\n      assert_same \"\"\"\n      defstruct foo: 1,\n                bar: 2\n      \"\"\"\n\n      assert_same \"\"\"\n      config :app,\n        foo: 1\n      \"\"\"\n\n      assert_same \"\"\"\n      config :app,\n        foo: 1,\n        bar: 2\n      \"\"\"\n\n      assert_same \"\"\"\n      config :app, :key,\n        foo: 1,\n        bar: 2\n      \"\"\"\n\n      assert_same \"\"\"\n      config :app,\n             :key,\n             foo: 1,\n             bar: 2\n      \"\"\"\n\n      bad = \"\"\"\n      config :app, foo: 1,\n        bar: 2\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      config :app,\n        foo: 1,\n        bar: 2\n      \"\"\"\n    end\n\n    test \"without parens and with keyword lists on comma limit\" do\n      bad = \"\"\"\n      import foo(abc, cde), opts: :next\n      \"\"\"\n\n      good = \"\"\"\n      import foo(\n               abc,\n               cde\n             ),\n             opts: :next\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"without parens and with keyword lists on line limit\" do\n      assert_same \"import :atom, opts: [foo: :bar]\"\n\n      bad = \"import :atom, opts: [foo: :bar]\"\n\n      good = \"\"\"\n      import :atom,\n        opts: [foo: :bar]\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n\n      bad = \"import :atom, really_long_key: [foo: :bar]\"\n\n      good = \"\"\"\n      import :atom,\n        really_long_key: [\n          foo: :bar\n        ]\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n\n      assert_same \"\"\"\n                  import :foo,\n                    one: two,\n                    three: four,\n                    five: [6, 7, 8, 9]\n                  \"\"\",\n                  @medium_length\n\n      assert_same \"\"\"\n                  import :really_long_atom_but_no_breaks,\n                    one: two,\n                    three: four\n                  \"\"\",\n                  @medium_length\n\n      bad = \"with :really_long_atom1, :really_long_atom2, opts: [foo: :bar]\"\n\n      good = \"\"\"\n      with :really_long_atom1,\n           :really_long_atom2,\n           opts: [\n             foo: :bar\n           ]\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"without parens from option\" do\n      assert_format \"foo bar\", \"foo(bar)\"\n      assert_same \"foo bar\", locals_without_parens: [foo: 1]\n      assert_same \"foo(bar)\", locals_without_parens: [foo: 1]\n      assert_same \"foo bar\", locals_without_parens: [foo: :*]\n      assert_same \"foo(bar)\", locals_without_parens: [foo: :*]\n    end\n\n    test \"without parens on unique argument\" do\n      assert_same \"foo(for 1, 2, 3)\"\n      assert_same \"foo(bar, for(1, 2, 3))\"\n      assert_same \"assert for 1, 2, 3\"\n      assert_same \"assert foo, for(1, 2, 3)\"\n\n      assert_same \"\"\"\n      assert for 1, 2, 3 do\n        :ok\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      assert foo, for(1, 2, 3) do\n        :ok\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      assert for(1, 2, 3) do\n        :ok\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      assert (for 1, 2, 3 do\n                :ok\n              end)\n      \"\"\"\n    end\n\n    test \"call on call\" do\n      assert_same \"unquote(call)()\"\n      assert_same \"unquote(call)(one, two)\"\n\n      assert_same \"\"\"\n      unquote(call)() do\n        :ok\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      unquote(call)(one, two) do\n        :ok\n      end\n      \"\"\"\n    end\n\n    test \"call on call on line limit\" do\n      bad = \"foo(bar)(one, two, three)\"\n\n      good = \"\"\"\n      foo(bar)(\n        one,\n        two,\n        three\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with generators\" do\n      assert_same \"foo(bar <- baz, is_bat(bar))\"\n      assert_same \"for bar <- baz, is_bat(bar)\"\n\n      assert_same \"\"\"\n      foo(\n        bar <- baz,\n        is_bat(bar),\n        bat <- bar\n      )\n      \"\"\"\n\n      assert_same \"\"\"\n      for bar <- baz,\n          is_bat(bar),\n          bat <- bar\n      \"\"\"\n\n      assert_same \"\"\"\n      for bar <- baz,\n          is_bat(bar),\n          bat <- bar do\n        :ok\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      for bar <- baz,\n          is_bat(bar),\n          bat <- bar,\n          into: %{}\n      \"\"\"\n    end\n\n    test \"preserves user choice on parens even when it fits\" do\n      assert_same \"\"\"\n      call(\n        :hello,\n        :foo,\n        :bar\n      )\n      \"\"\"\n\n      assert_same \"\"\"\n      call(\n        :hello,\n        :foo,\n        :bar\n      ) do\n        1 + 2\n      end\n      \"\"\"\n\n      # Doesn't preserve this because only the ending has a newline\n      assert_format \"call(foo, bar, baz\\n)\", \"call(foo, bar, baz)\"\n\n      # Doesn't preserve because there are no args\n      bad = \"\"\"\n      call() do\n        1 + 2\n      end\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      call do\n        1 + 2\n      end\n      \"\"\"\n\n      # Doesn't preserve because we have a single argument with next break fits\n      bad = \"\"\"\n      call(\n        %{\n          key: :value\n        }\n      )\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      call(%{\n        key: :value\n      })\n      \"\"\"\n    end\n  end\n\n  describe \"remote calls\" do\n    test \"with no arguments\" do\n      assert_format \"Foo . Bar . baz\", \"Foo.Bar.baz()\"\n      assert_format \":erlang.\\nget_stacktrace\", \":erlang.get_stacktrace()\"\n      assert_format \"@foo.bar\", \"@foo.bar\"\n      assert_format \"@foo.bar()\", \"@foo.bar()\"\n      assert_format \"(@foo).bar()\", \"@foo.bar()\"\n      assert_format \"__MODULE__.start_link\", \"__MODULE__.start_link()\"\n      assert_format \"Foo.bar.baz.bong\", \"Foo.bar().baz.bong\"\n      assert_format \"(1 + 2).foo\", \"(1 + 2).foo\"\n      assert_format \"(1 + 2).foo()\", \"(1 + 2).foo()\"\n    end\n\n    test \"with arguments\" do\n      assert_format \"Foo . Bar. baz(1, 2, 3)\", \"Foo.Bar.baz(1, 2, 3)\"\n      assert_format \":erlang.\\nget(\\n:some_key)\", \":erlang.get(:some_key)\"\n      assert_format \":erlang.\\nget(:some_key\\n)\", \":erlang.get(:some_key)\"\n      assert_same \"@foo.bar(1, 2, 3)\"\n      assert_same \"__MODULE__.start_link(1, 2, 3)\"\n      assert_same \"foo.bar(1).baz(2, 3)\"\n    end\n\n    test \"inspects function names correctly\" do\n      assert_same ~S[MyModule.\"my function\"(1, 2)]\n      assert_same ~S[MyModule.\"Foo.Bar\"(1, 2)]\n      assert_same ~S[Kernel.+(1, 2)]\n      assert_same ~S[:erlang.+(1, 2)]\n      assert_same ~S[foo.\"bar baz\"(1, 2)]\n      assert_same ~S[foo.\"bar\\nbaz\"(1, 2)]\n    end\n\n    test \"splits on arguments and dot on line limit\" do\n      bad = \"\"\"\n      MyModule.Foo.bar(:one, :two, :three)\n      \"\"\"\n\n      good = \"\"\"\n      MyModule.Foo.bar(\n        :one,\n        :two,\n        :three\n      )\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n\n      bad = \"\"\"\n      My_function.foo().bar(2, 3).baz(4, 5)\n      \"\"\"\n\n      good = \"\"\"\n      My_function.foo().bar(\n        2,\n        3\n      ).baz(4, 5)\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"doesn't split on parens on empty arguments\" do\n      assert_same \"Mod.func()\", @short_length\n    end\n\n    test \"with keyword lists\" do\n      assert_same \"mod.foo(foo: 1, bar: 2)\"\n\n      assert_same \"mod.foo(:hello, foo: 1, bar: 2)\"\n\n      assert_same \"\"\"\n                  mod.really_long_function_name(\n                    :hello,\n                    foo: 1,\n                    bar: 2\n                  )\n                  \"\"\",\n                  @short_length\n\n      assert_same \"\"\"\n                  really_long_module_name.foo(\n                    :hello,\n                    foo: 1,\n                    bar: 2\n                  )\n                  \"\"\",\n                  @short_length\n    end\n\n    test \"wraps left side in parens if it is an anonymous function\" do\n      assert_same \"(fn -> :ok end).foo\"\n    end\n\n    test \"wraps left side in parens if it is a do-end block\" do\n      assert_same \"\"\"\n      (if true do\n         :ok\n       end).foo\n      \"\"\"\n    end\n\n    test \"wraps left side in parens if it is a do-end block as an argument\" do\n      assert_same \"\"\"\n      import (if true do\n                :ok\n              end).foo\n      \"\"\"\n    end\n\n    test \"call on call\" do\n      assert_same \"foo.bar(call)()\"\n      assert_same \"foo.bar(call)(one, two)\"\n\n      assert_same \"\"\"\n      foo.bar(call)() do\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      foo.bar(call)(one, two) do\n        :ok\n      end\n      \"\"\"\n    end\n\n    test \"call on call on line limit\" do\n      bad = \"a.b(foo)(one, two, three)\"\n\n      good = \"\"\"\n      a.b(foo)(\n        one,\n        two,\n        three\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"on vars\" do\n      assert_same \"foo.bar\"\n      assert_same \"foo.bar()\"\n    end\n\n    test \"on vars before blocks\" do\n      assert_same \"\"\"\n      if var.field do\n        raise \"oops\"\n      end\n      \"\"\"\n    end\n\n    test \"on vars before brackets\" do\n      assert_same \"\"\"\n      exception.opts[:foo]\n      \"\"\"\n    end\n\n    test \"preserves user choice on parens even when it fits\" do\n      assert_same \"\"\"\n      Remote.call(\n        :hello,\n        :foo,\n        :bar\n      )\n      \"\"\"\n\n      # Doesn't preserve this because only the ending has a newline\n      assert_format \"Remote.call(foo, bar, baz\\n)\", \"Remote.call(foo, bar, baz)\"\n\n      assert_same \"\"\"\n      Remote.call(\n        :hello,\n        :foo,\n        fn -> :bar end\n      )\n      \"\"\"\n    end\n  end\n\n  describe \"anonymous function calls\" do\n    test \"without arguments\" do\n      assert_format \"foo . ()\", \"foo.()\"\n      assert_format \"(foo.()).().()\", \"foo.().().()\"\n      assert_same \"@foo.()\"\n      assert_same \"(1 + 1).()\"\n      assert_same \":foo.()\"\n    end\n\n    test \"with arguments\" do\n      assert_format \"foo . (1, 2  ,  3 )\", \"foo.(1, 2, 3)\"\n      assert_format \"foo . (1, 2 ).(3,4)\", \"foo.(1, 2).(3, 4)\"\n      assert_same \"@foo.(:one, :two)\"\n      assert_same \"foo.(1 + 1).(hello)\"\n    end\n\n    test \"does not split on dot on line limit\" do\n      assert_same \"my_function.()\", @short_length\n    end\n\n    test \"splits on arguments on line limit\" do\n      bad = \"\"\"\n      my_function.(1, 2, 3)\n      \"\"\"\n\n      good = \"\"\"\n      my_function.(\n        1,\n        2,\n        3\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"\"\"\n      my_function.(1, 2).f(3, 4).(5, 6)\n      \"\"\"\n\n      good = \"\"\"\n      my_function.(\n        1,\n        2\n      ).f(3, 4).(\n        5,\n        6\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with keyword lists\" do\n      assert_same \"foo.(foo: 1, bar: 2)\"\n\n      assert_same \"foo.(:hello, foo: 1, bar: 2)\"\n\n      assert_same \"\"\"\n                  foo.(\n                    :hello,\n                    foo: 1,\n                    bar: 2\n                  )\n                  \"\"\",\n                  @short_length\n    end\n\n    test \"wraps left side in parens if it is an anonymous function\" do\n      assert_same \"(fn -> :ok end).()\"\n    end\n\n    test \"wraps left side in parens if it is a do-end block\" do\n      assert_same \"\"\"\n      (if true do\n         :ok\n       end).()\n      \"\"\"\n    end\n\n    test \"wraps left side in parens if it is a do-end block as an argument\" do\n      assert_same \"\"\"\n      import (if true do\n                :ok\n              end).()\n      \"\"\"\n    end\n\n    test \"preserves user choice on parens even when it fits\" do\n      assert_same \"\"\"\n      call.(\n        :hello,\n        :foo,\n        :bar\n      )\n      \"\"\"\n\n      # Doesn't preserve this because only the ending has a newline\n      assert_format \"call.(foo, bar, baz\\n)\", \"call.(foo, bar, baz)\"\n    end\n  end\n\n  describe \"do-end blocks\" do\n    test \"with non-block keywords\" do\n      assert_same \"foo(do: nil)\"\n    end\n\n    test \"with forced block keywords\" do\n      good = \"\"\"\n      foo do\n        nil\n      end\n      \"\"\"\n\n      assert_format \"foo(do: nil)\", good, force_do_end_blocks: true\n\n      # Avoid false positives\n      assert_same \"foo(do: 1, do: 2)\", force_do_end_blocks: true\n      assert_same \"foo(do: 1, another: 2)\", force_do_end_blocks: true\n    end\n\n    test \"with multiple keywords\" do\n      assert_same \"\"\"\n      foo do\n        :do\n      rescue\n        :rescue\n      catch\n        :catch\n      else\n        :else\n      after\n        :after\n      end\n      \"\"\"\n    end\n\n    test \"with multiple keywords and arrows\" do\n      assert_same \"\"\"\n      foo do\n        a1 -> a2\n        b1 -> b2\n      rescue\n        a1 -> a2\n        b1 -> b2\n      catch\n        a1 -> a2\n        b1 -> b2\n      else\n        a1 -> a2\n        b1 -> b2\n      after\n        a1 -> a2\n        b1 -> b2\n      end\n      \"\"\"\n    end\n\n    test \"with no extra arguments\" do\n      assert_same \"\"\"\n      foo do\n        :ok\n      end\n      \"\"\"\n    end\n\n    test \"with no extra arguments and line breaks\" do\n      assert_same \"\"\"\n                  foo do\n                    a1 ->\n                      really_long_line\n\n                    b1 ->\n                      b2\n                  rescue\n                    c1\n                  catch\n                    d1 -> d1\n                    e1 -> e1\n                  else\n                    f2\n                  after\n                    g1 ->\n                      really_long_line\n\n                    h1 ->\n                      h2\n                  end\n                  \"\"\",\n                  @medium_length\n    end\n\n    test \"with extra arguments\" do\n      assert_same \"\"\"\n      foo bar, baz do\n        :ok\n      end\n      \"\"\"\n    end\n\n    test \"with extra arguments and line breaks\" do\n      assert_same \"\"\"\n                  foo bar do\n                    a1 ->\n                      really_long_line\n\n                    b1 ->\n                      b2\n                  rescue\n                    c1\n                  catch\n                    d1 -> d1\n                    e1 -> e1\n                  else\n                    f2\n                  after\n                    g1 ->\n                      really_long_line\n\n                    h1 ->\n                      h2\n                  end\n                  \"\"\",\n                  @medium_length\n\n      assert_same \"\"\"\n                  foo really,\n                      long,\n                      list,\n                      of,\n                      arguments do\n                    a1 ->\n                      really_long_line\n\n                    b1 ->\n                      b2\n                  rescue\n                    c1\n                  catch\n                    d1 -> d1\n                    e1 -> e1\n                  else\n                    f2\n                  after\n                    g1 ->\n                      really_long_line\n\n                    h1 ->\n                      h2\n                  end\n                  \"\"\",\n                  @medium_length\n    end\n\n    test \"when empty\" do\n      assert_same \"\"\"\n      foo do\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      foo do\n      rescue\n      catch\n      else\n      after\n      end\n      \"\"\"\n    end\n\n    test \"inside call\" do\n      bad = \"foo (bar do :ok end)\"\n\n      good = \"\"\"\n      foo(\n        bar do\n          :ok\n        end\n      )\n      \"\"\"\n\n      assert_format bad, good\n\n      bad = \"import (bar do :ok end)\"\n\n      good = \"\"\"\n      import (bar do\n                :ok\n              end)\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"inside operator\" do\n      bad = \"foo + bar do :ok end\"\n\n      good = \"\"\"\n      foo +\n        bar do\n          :ok\n        end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"inside operator inside argument\" do\n      bad = \"fun foo + (bar do :ok end)\"\n\n      good = \"\"\"\n      fun(\n        foo +\n          bar do\n            :ok\n          end\n      )\n      \"\"\"\n\n      assert_format bad, good\n\n      bad = \"if foo + (bar do :ok end) do :ok end\"\n\n      good = \"\"\"\n      if foo +\n           (bar do\n              :ok\n            end) do\n        :ok\n      end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"inside operator inside argument with remote call\" do\n      bad = \"if foo + (Bar.baz do :ok end) do :ok end\"\n\n      good = \"\"\"\n      if foo +\n           (Bar.baz do\n              :ok\n            end) do\n        :ok\n      end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"keeps repeated keys\" do\n      assert_same \"\"\"\n      receive do\n        :ok\n      after\n        0 -> 1\n      after\n        2 -> 3\n      end\n      \"\"\"\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      case do\n        1 ->\n          :ok\n\n        2 ->\n          :ok\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      case do\n        1 ->\n          :ok\n\n        2 ->\n          :ok\n\n        3 ->\n          :ok\n      end\n      \"\"\"\n    end\n  end\n\n  describe \"tuple calls\" do\n    test \"without arguments\" do\n      assert_format \"foo . {}\", \"foo.{}\"\n    end\n\n    test \"with arguments\" do\n      assert_format \"foo.{bar,baz,bat,}\", \"foo.{bar, baz, bat}\"\n    end\n\n    test \"with arguments on line limit\" do\n      bad = \"foo.{bar,baz,bat,}\"\n\n      good = \"\"\"\n      foo.{\n        bar,\n        baz,\n        bat\n      }\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"really_long_expression.{bar,baz,bat,}\"\n\n      good = \"\"\"\n      really_long_expression.{\n        bar,\n        baz,\n        bat\n      }\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with keywords\" do\n      assert_same \"expr.{:hello, foo: bar, baz: bat}\"\n    end\n\n    test \"preserves user choice on parens even when it fits\" do\n      assert_same \"\"\"\n      call.{\n        :hello,\n        :foo,\n        :bar\n      }\n      \"\"\"\n\n      assert_format \"call.{foo, bar, baz\\n}\", \"call.{foo, bar, baz}\"\n    end\n  end\n\n  describe \"access\" do\n    test \"with one argument\" do\n      assert_format \"foo[ bar ]\", \"foo[bar]\"\n    end\n\n    test \"with arguments on line limit\" do\n      bad = \"foo[really_long_argument()]\"\n\n      good = \"\"\"\n      foo[\n        really_long_argument()\n      ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"really_long_expression[really_long_argument()]\"\n\n      good = \"\"\"\n      really_long_expression[\n        really_long_argument()\n      ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with do-end blocks\" do\n      assert_same \"\"\"\n      (if true do\n         false\n       end)[key]\n      \"\"\"\n    end\n\n    test \"with keywords\" do\n      assert_format \"expr[[]]\", \"expr[[]]\"\n      assert_format \"expr[foo: bar, baz: bat]\", \"expr[foo: bar, baz: bat]\"\n      assert_format \"expr[[foo: bar, baz: bat]]\", \"expr[[foo: bar, baz: bat]]\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_formatter/comments_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Formatter.CommentsTest do\n  use ExUnit.Case, async: true\n\n  import CodeFormatterHelpers\n\n  @short_length [line_length: 10]\n\n  describe \"at the root\" do\n    test \"for empty documents\" do\n      assert_same \"# hello world\"\n    end\n\n    test \"are reformatted\" do\n      assert_format \"#oops\", \"# oops\"\n      assert_format \"##oops\", \"## oops\"\n      assert_same \"# ## oops\"\n    end\n\n    test \"recognizes hashbangs\" do\n      assert_format \"#! /usr/bin/env elixir\", \"#! /usr/bin/env elixir\"\n      assert_format \"#!/usr/bin/env elixir\", \"#!/usr/bin/env elixir\"\n      assert_same \"#!\"\n    end\n\n    test \"before and after expressions\" do\n      assert_same \"\"\"\n      # before comment\n      :hello\n      \"\"\"\n\n      assert_same \"\"\"\n      :hello\n      # after comment\n      \"\"\"\n\n      assert_same \"\"\"\n      # before comment\n      :hello\n      # after comment\n      \"\"\"\n    end\n\n    test \"on expressions\" do\n      bad = \"\"\"\n      :hello # this is hello\n      :world # this is world\n      \"\"\"\n\n      good = \"\"\"\n      # this is hello\n      :hello\n      # this is world\n      :world\n      \"\"\"\n\n      assert_format bad, good\n\n      bad = \"\"\"\n      foo   # this is foo\n      ++ bar # this is bar\n      ++ baz # this is baz\n      \"\"\"\n\n      good = \"\"\"\n      # this is foo\n      # this is bar\n      # this is baz\n      foo ++\n        bar ++\n        baz\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"empty comment\" do\n      assert_same \"\"\"\n      #\n      :foo\n      \"\"\"\n    end\n\n    test \"before and after expressions with newlines\" do\n      assert_same \"\"\"\n      # before comment\n      # second line\n\n      :hello\n\n      # middle comment 1\n\n      #\n\n      # middle comment 2\n\n      :world\n\n      # after comment\n      # second line\n      \"\"\"\n    end\n  end\n\n  describe \"modules attributes\" do\n    test \"with comments around\" do\n      assert_same \"\"\"\n      defmodule Sample do\n        # Comment 0\n        @moduledoc false\n        # Comment 1\n\n        # Comment 2\n        @attr1 1\n        # Comment 3\n\n        # Comment 4\n        @doc \"Doc\"\n        # Comment 5\n        @attr2 2\n        # Comment 6\n        def sample, do: :sample\n      end\n      \"\"\"\n    end\n\n    test \"with comments only after\" do\n      assert_same \"\"\"\n      @moduledoc false\n      # Comment 1\n\n      @attr 1\n      \"\"\"\n    end\n\n    test \"with too many new lines\" do\n      bad = \"\"\"\n      defmodule Sample do\n\n        # Comment 0\n\n\n        @moduledoc false\n\n\n        # Comment 1\n\n\n        # Comment 2\n\n\n        @attr1 1\n\n\n        # Comment 3\n\n\n        # Comment 4\n\n\n        @doc \"Doc\"\n\n\n        # Comment 5\n\n\n        @attr2 2\n\n\n        # Comment 6\n\n\n        def sample, do: :sample\n      end\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      defmodule Sample do\n        # Comment 0\n\n        @moduledoc false\n\n        # Comment 1\n\n        # Comment 2\n\n        @attr1 1\n\n        # Comment 3\n\n        # Comment 4\n\n        @doc \"Doc\"\n\n        # Comment 5\n\n        @attr2 2\n\n        # Comment 6\n\n        def sample, do: :sample\n      end\n      \"\"\"\n    end\n  end\n\n  describe \"interpolation\" do\n    test \"with comment outside before, during and after\" do\n      assert_same ~S\"\"\"\n      # comment\n      IO.puts(\"Hello #{world}\")\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      IO.puts(\"Hello #{world}\")\n      # comment\n      \"\"\"\n    end\n\n    test \"with trailing comments\" do\n      # This is trailing so we move the comment out\n      trailing = ~S\"\"\"\n      IO.puts(\"Hello #{world}\") # comment\n      \"\"\"\n\n      assert_format trailing, ~S\"\"\"\n      # comment\n      IO.puts(\"Hello #{world}\")\n      \"\"\"\n\n      # This is ambiguous so we move the comment out\n      ambiguous = ~S\"\"\"\n      IO.puts(\"Hello #{world # comment\n      }\")\n      \"\"\"\n\n      assert_format ambiguous, ~S\"\"\"\n      # comment\n      IO.puts(\"Hello #{world}\")\n      \"\"\"\n    end\n\n    test \"with comment inside before and after\" do\n      bad = ~S\"\"\"\n      IO.puts(\n        \"Hello #{\n          # comment\n          world\n        }\"\n      )\n      \"\"\"\n\n      good = ~S\"\"\"\n      IO.puts(\n        # comment\n        \"Hello #{world}\"\n      )\n      \"\"\"\n\n      assert_format bad, good\n\n      bad = ~S\"\"\"\n      IO.puts(\n        \"Hello #{\n          world\n          # comment\n        }\"\n      )\n      \"\"\"\n\n      good = ~S\"\"\"\n      IO.puts(\n        \"Hello #{world}\"\n        # comment\n      )\n      \"\"\"\n\n      assert_format bad, good\n\n      bad = ~S\"\"\"\n      IO.puts(\"Hello #{hello\n      world}\")\n      \"\"\"\n\n      good = ~S\"\"\"\n      IO.puts(\n        \"Hello #{hello\n        world}\"\n      )\n      \"\"\"\n\n      assert_format bad, good\n    end\n  end\n\n  describe \"parens blocks\" do\n    test \"with comment outside before and after\" do\n      assert_same ~S\"\"\"\n      # comment\n      assert (\n               hello\n               world\n             )\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      assert (\n               hello\n               world\n             )\n\n      # comment\n      \"\"\"\n    end\n\n    test \"with trailing comments\" do\n      # This is ambiguous so we move the comment out\n      ambiguous = ~S\"\"\"\n      assert ( # comment\n               hello\n               world\n             )\n      \"\"\"\n\n      assert_format ambiguous, ~S\"\"\"\n      # comment\n      assert (\n               hello\n               world\n             )\n      \"\"\"\n\n      # This is ambiguous so we move the comment out\n      ambiguous = ~S\"\"\"\n      assert (\n               hello\n               world\n             ) # comment\n      \"\"\"\n\n      assert_format ambiguous, ~S\"\"\"\n      assert (\n               hello\n               world\n             )\n\n      # comment\n      \"\"\"\n    end\n\n    test \"with comment inside before and after\" do\n      assert_same ~S\"\"\"\n      assert (\n               # comment\n               hello\n               world\n             )\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      assert (\n               hello\n               world\n               # comment\n             )\n      \"\"\"\n    end\n  end\n\n  describe \"access\" do\n    test \"before and after single arg\" do\n      assert_same ~S\"\"\"\n      foo[\n        # bar\n        baz\n        # bat\n      ]\n      \"\"\"\n    end\n\n    test \"before and after keywords\" do\n      assert_same ~S\"\"\"\n      foo[\n        # bar\n        one: :two,\n        # baz\n        three: :four\n        # bat\n      ]\n      \"\"\"\n    end\n  end\n\n  describe \"calls\" do\n    test \"local with parens inside before and after\" do\n      assert_same ~S\"\"\"\n      call(\n        # before\n        hello,\n        # middle\n        world\n        # after\n      )\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      call(\n        # command\n      )\n      \"\"\"\n    end\n\n    test \"remote with parens inside before and after\" do\n      assert_same ~S\"\"\"\n      Remote.call(\n        # before\n        hello,\n        # middle\n        world\n        # after\n      )\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      Remote.call(\n        # command\n      )\n      \"\"\"\n    end\n\n    test \"local with parens and keywords inside before and after\" do\n      assert_same ~S\"\"\"\n      call(\n        # before\n        hello,\n        # middle\n        world,\n        # key before\n        key: hello,\n        # key middle\n        key: world\n        # key after\n      )\n      \"\"\"\n    end\n\n    test \"remote with parens and keywords inside before and after\" do\n      assert_same ~S\"\"\"\n      call(\n        # before\n        hello,\n        # middle\n        world,\n        # key before\n        key: hello,\n        # key middle\n        key: world\n        # key after\n      )\n      \"\"\"\n    end\n\n    test \"local with no parens inside before and after\" do\n      bad = ~S\"\"\"\n             # before\n      assert hello,\n             # middle\n             world\n             # after\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # before\n      assert hello,\n             # middle\n             world\n\n      # after\n      \"\"\"\n    end\n\n    test \"local with no parens and keywords inside before and after\" do\n      bad = ~S\"\"\"\n      config hello, world,\n        # key before\n        key: hello,\n        # key middle\n        key: world\n        # key after\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      config hello, world,\n        # key before\n        key: hello,\n        # key middle\n        key: world\n\n      # key after\n      \"\"\"\n\n      bad = ~S\"\"\"\n             # before\n      config hello,\n             # middle\n             world,\n             # key before\n             key: hello,\n             # key middle\n             key: world\n             # key after\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # before\n      config hello,\n             # middle\n             world,\n             # key before\n             key: hello,\n             # key middle\n             key: world\n\n      # key after\n      \"\"\"\n    end\n  end\n\n  describe \"anonymous functions\" do\n    test \"with one clause and no args\" do\n      assert_same ~S\"\"\"\n      fn ->\n        # comment\n        hello\n        world\n      end\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      fn ->\n        hello\n        world\n        # comment\n      end\n      \"\"\"\n    end\n\n    test \"with one clause and no args and trailing comments\" do\n      bad = ~S\"\"\"\n      fn # comment\n        ->\n        hello\n        world\n      end\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # comment\n      fn ->\n        hello\n        world\n      end\n      \"\"\"\n\n      bad = ~S\"\"\"\n      fn\n        # comment\n        ->\n        hello\n        world\n      end\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # comment\n      fn ->\n        hello\n        world\n      end\n      \"\"\"\n    end\n\n    test \"with one clause and args\" do\n      assert_same ~S\"\"\"\n      fn hello ->\n        # before\n        hello\n        # middle\n        world\n        # after\n      end\n      \"\"\"\n    end\n\n    test \"with one clause and args and trailing comments\" do\n      bad = ~S\"\"\"\n      fn # fn\n        # before head\n        hello # middle head\n        # after head\n        ->\n          # before body\n          world # middle body\n          # after body\n      end\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # fn\n      fn\n        # before head\n        # middle head\n        hello ->\n          # after head\n          # before body\n          # middle body\n          world\n          # after body\n      end\n      \"\"\"\n    end\n\n    test \"with multiple clauses and args\" do\n      bad = ~S\"\"\"\n      fn # fn\n        # before one\n        one, # middle one\n        # after one / before two\n        two # middle two\n        # after two\n        ->\n          # before hello\n          hello # middle hello\n          # after hello\n\n        # before three\n        three # middle three\n        # after three\n        ->\n          # before world\n          world # middle world\n          # after world\n      end\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # fn\n      fn\n        # before one\n        # middle one\n        # after one / before two\n        # middle two\n        one, two ->\n          # after two\n          # before hello\n          # middle hello\n          hello\n\n        # after hello\n\n        # before three\n        # middle three\n        three ->\n          # after three\n          # before world\n          # middle world\n          world\n          # after world\n      end\n      \"\"\"\n    end\n\n    test \"with commented out clause\" do\n      assert_same \"\"\"\n      fn\n        arg1 ->\n          body1\n\n        # arg2 ->\n        #   body 2\n\n        arg3 ->\n          body3\n      end\n      \"\"\"\n    end\n  end\n\n  describe \"do-end blocks\" do\n    test \"with comment outside before and after\" do\n      assert_same ~S\"\"\"\n      # comment\n      assert do\n        hello\n        world\n      end\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      assert do\n        hello\n        world\n      end\n\n      # comment\n      \"\"\"\n    end\n\n    test \"with trailing comments\" do\n      # This is ambiguous so we move the comment out\n      ambiguous = ~S\"\"\"\n      assert do # comment\n        hello\n        world\n      end\n      \"\"\"\n\n      assert_format ambiguous, ~S\"\"\"\n      # comment\n      assert do\n        hello\n        world\n      end\n      \"\"\"\n\n      # This is ambiguous so we move the comment out\n      ambiguous = ~S\"\"\"\n      assert do\n        hello\n        world\n      end # comment\n      \"\"\"\n\n      assert_format ambiguous, ~S\"\"\"\n      assert do\n        hello\n        world\n      end\n\n      # comment\n      \"\"\"\n    end\n\n    test \"with comment inside before and after\" do\n      assert_same ~S\"\"\"\n      assert do\n        # comment\n        hello\n        world\n      end\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      assert do\n        hello\n        world\n        # comment\n      end\n      \"\"\"\n    end\n\n    test \"with comment inside before and after and multiple keywords\" do\n      assert_same ~S\"\"\"\n      assert do\n        # before\n        hello\n        world\n        # after\n      rescue\n        # before\n        hello\n        world\n        # after\n      after\n        # before\n        hello\n        world\n        # after\n      catch\n        # before\n        hello\n        world\n        # after\n      else\n        # before\n        hello\n        world\n        # after\n      end\n      \"\"\"\n    end\n\n    test \"when empty\" do\n      assert_same ~S\"\"\"\n      assert do\n        # comment\n      end\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      assert do\n        # comment\n      rescue\n        # comment\n      after\n        # comment\n      catch\n        # comment\n      else\n        # comment\n      end\n      \"\"\"\n    end\n\n    test \"with one-line clauses\" do\n      bad = ~S\"\"\"\n      assert do # do\n        # before\n        one -> two\n      end\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # do\n      assert do\n        # before\n        one -> two\n      end\n      \"\"\"\n\n      bad = ~S\"\"\"\n      assert do # do\n        # before\n        one -> two\n        # after\n        three -> four\n      end\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # do\n      assert do\n        # before\n        one -> two\n        # after\n        three -> four\n      end\n      \"\"\"\n    end\n\n    test \"with multiple clauses and args\" do\n      bad = ~S\"\"\"\n      assert do # do\n        # before one\n        one, # middle one\n        # after one / before two\n        two # middle two\n        # after two\n        ->\n          # before hello\n          hello # middle hello\n          # after hello\n\n        # before three\n        three # middle three\n        # after three\n        ->\n          # before world\n          world # middle world\n          # after world\n      end\n      \"\"\"\n\n      assert_format bad, ~S\"\"\"\n      # do\n      assert do\n        # before one\n        # middle one\n        # after one / before two\n        # middle two\n        one, two ->\n          # after two\n          # before hello\n          # middle hello\n          hello\n\n        # after hello\n\n        # before three\n        # middle three\n        three ->\n          # after three\n          # before world\n          # middle world\n          world\n          # after world\n      end\n      \"\"\"\n    end\n  end\n\n  describe \"operators\" do\n    test \"with comment before, during and after uniform pipelines\" do\n      assert_same \"\"\"\n      foo\n      # |> bar\n      # |> baz\n      |> bat\n      \"\"\"\n\n      bad = \"\"\"\n      # before\n      foo    # this is foo\n      |> bar # this is bar\n      |> baz # this is baz\n      # after\n      \"\"\"\n\n      good = \"\"\"\n      # before\n      # this is foo\n      foo\n      # this is bar\n      |> bar\n      # this is baz\n      |> baz\n\n      # after\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with comment before, during and after mixed pipelines\" do\n      assert_same \"\"\"\n      foo\n      # |> bar\n      # |> baz\n      ~> bat\n      \"\"\"\n\n      bad = \"\"\"\n      # before\n      foo    # this is foo\n      ~> bar # this is bar\n      <~> baz # this is baz\n      # after\n      \"\"\"\n\n      good = \"\"\"\n      # before\n      # this is foo\n      foo\n      # this is bar\n      ~> bar\n      # this is baz\n      <~> baz\n\n      # after\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with comment before, during and after uniform right\" do\n      assert_same \"\"\"\n      foo\n      # | bar\n      # | baz\n      | bat\n      \"\"\"\n\n      bad = \"\"\"\n      # before\n      foo    # this is foo\n      | bar # this is bar\n      | baz # this is baz\n      # after\n      \"\"\"\n\n      good = \"\"\"\n      # before\n      # this is foo\n      foo\n      # this is bar\n      | bar\n      # this is baz\n      | baz\n\n      # after\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with comment before, during and after mixed right\" do\n      assert_same \"\"\"\n      one\n      # when two\n      # when three\n      when four\n           # | five\n           | six\n      \"\"\"\n    end\n\n    test \"handles nodes without meta info\" do\n      assert_same \"(a -> b) |> (c -> d)\"\n      assert_same \"(a -> b) when c: d\"\n      assert_same \"(a -> b) when (c -> d)\"\n    end\n  end\n\n  describe \"containers\" do\n    test \"with comment outside before, during and after\" do\n      assert_same ~S\"\"\"\n      # comment\n      [one, two, three]\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      [one, two, three]\n      # comment\n      \"\"\"\n    end\n\n    test \"with trailing comments\" do\n      # This is trailing so we move the comment out\n      trailing = ~S\"\"\"\n      [one, two, three] # comment\n      \"\"\"\n\n      assert_format trailing, ~S\"\"\"\n      # comment\n      [one, two, three]\n      \"\"\"\n\n      # This is ambiguous so we move the comment out\n      ambiguous = ~S\"\"\"\n      [# comment\n       one, two, three]\n      \"\"\"\n\n      assert_format ambiguous, ~S\"\"\"\n      # comment\n      [\n        one,\n        two,\n        three\n      ]\n      \"\"\"\n    end\n\n    test \"when empty\" do\n      assert_same ~S\"\"\"\n      [\n        # comment\n      ]\n      \"\"\"\n    end\n\n    test \"with block\" do\n      assert_same ~S\"\"\"\n      [\n        (\n          # before\n          multi\n          line\n          # after\n        )\n      ]\n      \"\"\"\n    end\n\n    test \"with comments inside lists before and after\" do\n      bad = ~S\"\"\"\n      [\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one,\n        after_one,\n        after_one do\n          :ok\n        end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        three # final\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      ]\n      \"\"\"\n\n      good = ~S\"\"\"\n      [\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one,\n        after_one,\n        after_one do\n          :ok\n        end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        # final\n        three\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      ]\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"with comments inside tuples before and after\" do\n      bad = ~S\"\"\"\n      {\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one,\n        after_one,\n        after_one do\n          :ok\n        end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        three # final\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      }\n      \"\"\"\n\n      good = ~S\"\"\"\n      {\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one,\n        after_one,\n        after_one do\n          :ok\n        end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        # final\n        three\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      }\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"with comments inside bitstrings before and after\" do\n      bad = ~S\"\"\"\n      <<\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one,\n        after_one,\n        after_one do\n          :ok\n        end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        three # final\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      >>\n      \"\"\"\n\n      good = ~S\"\"\"\n      <<\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one,\n        after_one,\n        after_one do\n          :ok\n        end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        # final\n        three\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      >>\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"with comments inside maps before and after\" do\n      bad = ~S\"\"\"\n      %{\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one: one,\n        one: after_one,\n        one: after_one do\n          :ok\n        end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        three: three # final\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      }\n      \"\"\"\n\n      good = ~S\"\"\"\n      %{\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one: one,\n        one: after_one,\n        one:\n          after_one do\n            :ok\n          end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        # final\n        three: three\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      }\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"with comments inside structs before and after\" do\n      bad = ~S\"\"\"\n      %Foo{bar |\n        # 1. one\n\n        # 1. two\n        # 1. three\n        one: one,\n        one: after_one,\n        one: after_one do\n          :ok\n        end,\n\n        # 2. one\n\n        # 2. two\n        # 2. three\n        # two,\n\n        # 3. one\n\n        # 3. two\n        # 3. three\n        three: three # final\n\n        # 4. one\n\n        # 4. two\n        # 4. three\n        # four\n      }\n      \"\"\"\n\n      good = ~S\"\"\"\n      %Foo{\n        bar\n        | # 1. one\n\n          # 1. two\n          # 1. three\n          one: one,\n          one: after_one,\n          one:\n            after_one do\n              :ok\n            end,\n\n          # 2. one\n\n          # 2. two\n          # 2. three\n          # two,\n\n          # 3. one\n\n          # 3. two\n          # 3. three\n          # final\n          three: three\n\n          # 4. one\n\n          # 4. two\n          # 4. three\n          # four\n      }\n      \"\"\"\n\n      assert_format bad, good\n    end\n  end\n\n  describe \"defstruct\" do\n    test \"with first field comments\" do\n      bad = ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        defstruct [ # foo\n          # 1. one\n          one: 1, # 2. one\n          # 1. two\n          # 2. two\n          two: 2\n        ]\n      end\n      \"\"\"\n\n      good = ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        # foo\n        defstruct [\n          # 1. one\n          # 2. one\n          one: 1,\n          # 1. two\n          # 2. two\n          two: 2\n        ]\n      end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"with first field comments and defstruct has the parens\" do\n      bad = ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        defstruct([ # foo\n          # 1. one\n          one: 1, # 2. one\n          # 1. two\n          # 2. two\n          two: 2\n        ])\n      end\n      \"\"\"\n\n      good = ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        # foo\n        defstruct(\n          # 1. one\n          # 2. one\n          one: 1,\n          # 1. two\n          # 2. two\n          two: 2\n        )\n      end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"without first field comments\" do\n      bad = ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        defstruct [\n          one: 1,\n          # 1. two\n          two: 2 # 2. two\n        ]\n      end\n      \"\"\"\n\n      good = ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        defstruct one: 1,\n                  # 1. two\n                  # 2. two\n                  two: 2\n      end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"without field comments\" do\n      bad = ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        defstruct [\n          one: 1,\n          two: 2\n        ]\n      end\n      \"\"\"\n\n      good = ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        defstruct one: 1,\n                  two: 2\n      end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"without square brackets\" do\n      assert_same ~S\"\"\"\n      defmodule Foo do\n        # defstruct\n        defstruct one: 1,\n                  # 1. two\n                  # 2. two\n                  two: 2\n      end\n      \"\"\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_formatter/containers_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Formatter.ContainersTest do\n  use ExUnit.Case, async: true\n\n  import CodeFormatterHelpers\n\n  @short_length [line_length: 10]\n  @medium_length [line_length: 20]\n\n  describe \"tuples\" do\n    test \"without arguments\" do\n      assert_format \"{ }\", \"{}\"\n    end\n\n    test \"with arguments\" do\n      assert_format \"{1,2}\", \"{1, 2}\"\n      assert_format \"{1,2,3}\", \"{1, 2, 3}\"\n    end\n\n    test \"is flex on line limits\" do\n      bad = \"{1, 2, 3, 4}\"\n\n      good = \"\"\"\n      {1, 2, 3,\n       4}\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"removes trailing comma\" do\n      assert_format \"{1,}\", \"{1}\"\n      assert_format \"{1, 2, 3,}\", \"{1, 2, 3}\"\n    end\n\n    test \"with keyword lists\" do\n      # The one below is not valid syntax\n      # assert_same \"{foo: 1, bar: 2}\"\n      assert_same \"{:hello, foo: 1, bar: 2}\"\n\n      tuple = \"\"\"\n      {\n        :hello,\n        foo: 1,\n        bar: 2\n      }\n      \"\"\"\n\n      assert_same tuple, @short_length\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      {\n        :hello,\n        :foo,\n        :bar\n      }\n      \"\"\"\n\n      # Doesn't preserve this because only the ending has a newline\n      assert_format \"{foo, bar, baz\\n}\", \"{foo, bar, baz}\"\n    end\n\n    test \"preserves user choice even when it fits with trailing comma\" do\n      bad = \"\"\"\n      {\n        :hello,\n        :foo,\n        :bar,\n      }\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      {\n        :hello,\n        :foo,\n        :bar\n      }\n      \"\"\"\n    end\n  end\n\n  describe \"lists\" do\n    test \"empty\" do\n      assert_format \"[ ]\", \"[]\"\n      assert_format \"[\\n]\", \"[]\"\n    end\n\n    test \"with elements\" do\n      assert_format \"[ 1 , 2,3, 4 ]\", \"[1, 2, 3, 4]\"\n    end\n\n    test \"with tail\" do\n      assert_format \"[1,2,3|4]\", \"[1, 2, 3 | 4]\"\n    end\n\n    test \"are strict on line limit\" do\n      bad = \"\"\"\n      [11, 22, 33, 44]\n      \"\"\"\n\n      good = \"\"\"\n      [\n        11,\n        22,\n        33,\n        44\n      ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"\"\"\n      [11, 22, 33 | 44]\n      \"\"\"\n\n      good = \"\"\"\n      [\n        11,\n        22,\n        33 | 44\n      ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"\"\"\n      [1, 2, 3 | 4]\n      \"\"\"\n\n      good = \"\"\"\n      [\n        1,\n        2,\n        3 | 4\n      ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"\"\"\n      [1, 2, 3 | really_long_expression()]\n      \"\"\"\n\n      good = \"\"\"\n      [\n        1,\n        2,\n        3\n        | really_long_expression()\n      ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"removes trailing comma\" do\n      assert_format \"[1,]\", \"[1]\"\n      assert_format \"[1, 2, 3,]\", \"[1, 2, 3]\"\n    end\n\n    test \"with keyword lists\" do\n      assert_same \"[foo: 1, bar: 2]\"\n      assert_same \"[:hello, foo: 1, bar: 2]\"\n\n      # Pseudo keyword lists are kept as is\n      assert_same \"[{:foo, 1}, {:bar, 2}]\"\n\n      keyword = \"\"\"\n      [\n        foo: 1,\n        bar: 2\n      ]\n      \"\"\"\n\n      assert_same keyword, @short_length\n    end\n\n    test \"with keyword lists on comma line limit\" do\n      bad = \"\"\"\n      [\n        foooo: 1,\n        barrr: 2\n      ]\n      \"\"\"\n\n      good = \"\"\"\n      [\n        foooo:\n          1,\n        barrr: 2\n      ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with quoted keyword lists\" do\n      assert_same ~S([\"with spaces\": 1])\n      assert_same ~S([\"one #{two} three\": 1])\n      assert_same ~S([\"\\w\": 1, \"\\\\w\": 2])\n      assert_same ~S([\"Elixir.Foo\": 1, \"Elixir.Bar\": 2])\n      assert_format ~S([\"Foo\": 1, \"Bar\": 2]), ~S([Foo: 1, Bar: 2])\n      assert_same ~S([\"with \\\"scare quotes\\\"\": 1])\n    end\n\n    test \"with operators keyword lists\" do\n      assert_same ~S([.: :.])\n      assert_same ~S([..: :..])\n      assert_same ~S([...: :...])\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      [\n        :hello,\n        :foo,\n        :bar\n      ]\n      \"\"\"\n\n      # Doesn't preserve this because only the ending has a newline\n      assert_format \"[foo, bar, baz\\n]\", \"[foo, bar, baz]\"\n    end\n\n    test \"preserves user choice even when it fits with trailing comma\" do\n      bad = \"\"\"\n      [\n        :hello,\n        :foo,\n        :bar,\n      ]\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      [\n        :hello,\n        :foo,\n        :bar\n      ]\n      \"\"\"\n    end\n  end\n\n  describe \"bitstrings\" do\n    test \"without arguments\" do\n      assert_format \"<< >>\", \"<<>>\"\n      assert_format \"<<\\n>>\", \"<<>>\"\n    end\n\n    test \"with arguments\" do\n      assert_format \"<<1,2,3>>\", \"<<1, 2, 3>>\"\n    end\n\n    test \"add parens on first and last in case of binary ambiguity\" do\n      assert_format \"<< <<>> >>\", \"<<(<<>>)>>\"\n      assert_format \"<< <<>> + <<>> >>\", \"<<(<<>> + <<>>)>>\"\n      assert_format \"<< 1 + <<>> >>\", \"<<(1 + <<>>)>>\"\n      assert_format \"<< <<>> + 1 >>\", \"<<(<<>> + 1)>>\"\n      assert_format \"<< <<>>, <<>>, <<>> >>\", \"<<(<<>>), <<>>, (<<>>)>>\"\n      assert_format \"<< <<>>::1, <<>>::2, <<>>::3 >>\", \"<<(<<>>)::1, <<>>::2, <<>>::3>>\"\n      assert_format \"<< <<>>::<<>> >>\", \"<<(<<>>)::(<<>>)>>\"\n    end\n\n    test \"add parens on first in case of operator ambiguity\" do\n      assert_format \"<< ~~~1::8 >>\", \"<<(~~~1)::8>>\"\n      assert_format \"<< ~s[foo]::binary >>\", \"<<(~s[foo])::binary>>\"\n    end\n\n    test \"with modifiers\" do\n      assert_format \"<< 1 :: 1 >>\", \"<<1::1>>\"\n      assert_format \"<< 1 :: 2 + 3 >>\", \"<<1::(2 + 3)>>\"\n      assert_format \"<< 1 :: 2 - integer >>\", \"<<1::2-integer>>\"\n      assert_format \"<< 1 :: 2 - unit(3) >>\", \"<<1::2-unit(3)>>\"\n      assert_format \"<< 1 :: 2 * 3 - unit(4) >>\", \"<<1::2*3-unit(4)>>\"\n      assert_format \"<< 1 :: 2 - unit(3) - 4 / 5 >>\", \"<<1::2-unit(3)-(4 / 5)>>\"\n      assert_format \"<<0 :: ( x - 1 ) * 5>>\", \"<<0::(x-1)*5>>\"\n      assert_format \"<<0 :: 2 * 3 * 4>>\", \"<<0::(2*3)*4>>\"\n    end\n\n    test \"in comprehensions\" do\n      assert_format \"<< 0, 1 :: 1 <- x >>\", \"<<0, 1::1 <- x>>\"\n      assert_format \"<< 0, 1 :: 2 + 3 <- x >>\", \"<<0, 1::(2 + 3) <- x>>\"\n      assert_format \"<< 0, 1 :: 2 - integer <- x >>\", \"<<0, 1::2-integer <- x>>\"\n      assert_format \"<< 0, 1 :: 2 - unit(3) <- x >>\", \"<<0, 1::2-unit(3) <- x>>\"\n      assert_format \"<< 0, 1 :: 2 * 3 - unit(4) <- x >>\", \"<<0, 1::2*3-unit(4) <- x>>\"\n      assert_format \"<< 0, 1 :: 2 - unit(3) - 4 / 5 <- x >>\", \"<<0, 1::2-unit(3)-(4 / 5) <- x>>\"\n\n      assert_same \"<<(<<y>> <- <<x>>)>>\"\n      assert_same \"<<(y <- <<x>>)>>\"\n      assert_same \"<<(<<y>> <- x)>>\"\n    end\n\n    test \"keeps parentheses by default\" do\n      assert_same \"<<foo::binary()>>\"\n      assert_same \"<<foo::binary>>\"\n\n      assert_same \"<<foo::custom_type>>\"\n      assert_same \"<<foo::custom_type()>>\"\n\n      assert_same \"<<x::binary()-(13 * 6)-custom>>\"\n      assert_same \"<<0, 1::2-integer() <- x>>\"\n    end\n\n    test \"is flex on line limits\" do\n      bad = \"<<1, 2, 3, 4>>\"\n\n      good = \"\"\"\n      <<1, 2, 3,\n        4>>\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      <<\n        :hello,\n        :foo,\n        :bar\n      >>\n      \"\"\"\n\n      # Doesn't preserve this because only the ending has a newline\n      assert_format \"<<foo, bar, baz\\n>>\", \"<<foo, bar, baz>>\"\n    end\n\n    test \"preserves user choice even when it fits with trailing comma\" do\n      bad = \"\"\"\n      <<\n        :hello,\n        :foo,\n        :bar,\n      >>\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      <<\n        :hello,\n        :foo,\n        :bar\n      >>\n      \"\"\"\n    end\n  end\n\n  describe \"maps\" do\n    test \"without arguments\" do\n      assert_format \"%{ }\", \"%{}\"\n    end\n\n    test \"with arguments\" do\n      assert_format \"%{1 => 2,3 => 4}\", \"%{1 => 2, 3 => 4}\"\n    end\n\n    test \"is strict on line limits\" do\n      bad = \"%{1 => 2, 3 => 4}\"\n\n      good = \"\"\"\n      %{\n        1 => 2,\n        3 => 4\n      }\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      map = \"\"\"\n      %{\n        a(1, 2) => b,\n        c(3, 4) => d\n      }\n      \"\"\"\n\n      assert_same map, @medium_length\n\n      map = \"\"\"\n      %{\n        a => fn x ->\n          y\n        end,\n        b => fn y ->\n          z\n        end\n      }\n      \"\"\"\n\n      assert_same map, @medium_length\n\n      map = \"\"\"\n      %{\n        a =>\n          for(\n            y <- x,\n            z <- y,\n            do: 123\n          )\n      }\n      \"\"\"\n\n      assert_same map, @medium_length\n\n      map = \"\"\"\n      %{\n        a =>\n          for do\n            :ok\n          end\n      }\n      \"\"\"\n\n      assert_same map, @short_length\n    end\n\n    test \"removes trailing comma\" do\n      assert_format \"%{1 => 2,}\", \"%{1 => 2}\"\n    end\n\n    test \"with keyword lists\" do\n      assert_same \"%{:foo => :bar, baz: :bat}\"\n\n      map = \"\"\"\n      %{\n        :foo => :bar,\n        baz: :bat\n      }\n      \"\"\"\n\n      assert_same map, @medium_length\n    end\n\n    test \"preserves user choice in regards to =>\" do\n      assert_same \"%{:hello => 1, :world => 2}\"\n      assert_format \"%{:true => 1, :false => 2}\", \"%{true => 1, false => 2}\"\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      %{\n        :hello => 1,\n        :foo => 2,\n        :bar => 3\n      }\n      \"\"\"\n\n      # Doesn't preserve this because only the ending has a newline\n      assert_format \"%{foo: 1, bar: 2\\n}\", \"%{foo: 1, bar: 2}\"\n    end\n\n    test \"preserves user choice even when it fits with trailing comma\" do\n      bad = \"\"\"\n      %{\n        hello,\n        foo,\n        bar,\n      }\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      %{\n        hello,\n        foo,\n        bar\n      }\n      \"\"\"\n    end\n\n    test \"preserves user choice when a newline is used after keyword\" do\n      good = \"\"\"\n      %{\n        hello:\n          {:ok, :world}\n      }\n      \"\"\"\n\n      assert_same good, @medium_length\n    end\n\n    test \"preserves user choice when a newline is used after assoc\" do\n      good = \"\"\"\n      %{\n        hello =>\n          {:ok, :world}\n      }\n      \"\"\"\n\n      assert_same good, @medium_length\n    end\n  end\n\n  describe \"maps with update\" do\n    test \"with arguments\" do\n      assert_format \"%{foo | 1 => 2,3 => 4}\", \"%{foo | 1 => 2, 3 => 4}\"\n    end\n\n    test \"is strict on line limits\" do\n      bad = \"%{foo | 1 => 2, 3 => 4}\"\n\n      good = \"\"\"\n      %{\n        foo\n        | 1 => 2,\n          3 => 4\n      }\n      \"\"\"\n\n      assert_format bad, good, line_length: 11\n    end\n\n    test \"removes trailing comma\" do\n      assert_format \"%{foo | 1 => 2,}\", \"%{foo | 1 => 2}\"\n    end\n\n    test \"with keyword lists\" do\n      assert_same \"%{foo | :foo => :bar, baz: :bat}\"\n\n      map = \"\"\"\n      %{\n        foo\n        | :foo => :bar,\n          baz: :bat\n      }\n      \"\"\"\n\n      assert_same map, @medium_length\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      %{\n        foo\n        | :hello => 1,\n          :foo => 2,\n          :bar => 3\n      }\n      \"\"\"\n    end\n\n    test \"wraps operators in parens\" do\n      assert_format \"%{foo && bar | baz: :bat}\", \"%{(foo && bar) | baz: :bat}\"\n      assert_same \"%{@foo | baz: :bat}\"\n    end\n  end\n\n  describe \"structs\" do\n    test \"without arguments\" do\n      assert_format \"%struct{ }\", \"%struct{}\"\n    end\n\n    test \"with arguments\" do\n      assert_format \"%struct{1 => 2,3 => 4}\", \"%struct{1 => 2, 3 => 4}\"\n    end\n\n    test \"is strict on line limits\" do\n      bad = \"%struct{1 => 2, 3 => 4}\"\n\n      good = \"\"\"\n      %struct{\n        1 => 2,\n        3 => 4\n      }\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"removes trailing comma\" do\n      assert_format \"%struct{1 => 2,}\", \"%struct{1 => 2}\"\n    end\n\n    test \"with keyword lists\" do\n      assert_same \"%struct{:foo => :bar, baz: :bat}\"\n\n      struct = \"\"\"\n      %struct{\n        :foo => :bar,\n        baz: :bat\n      }\n      \"\"\"\n\n      assert_same struct, @medium_length\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      %Foo{\n        :hello => 1,\n        :foo => 2,\n        :bar => 3\n      }\n      \"\"\"\n    end\n  end\n\n  describe \"struct with update\" do\n    test \"with arguments\" do\n      assert_format \"%struct{foo | 1 => 2,3 => 4}\", \"%struct{foo | 1 => 2, 3 => 4}\"\n    end\n\n    test \"is strict on line limits\" do\n      bad = \"%struct{foo | 1 => 2, 3 => 4}\"\n\n      good = \"\"\"\n      %struct{\n        foo\n        | 1 => 2,\n          3 => 4\n      }\n      \"\"\"\n\n      assert_format bad, good, line_length: 11\n    end\n\n    test \"removes trailing comma\" do\n      assert_format \"%struct{foo | 1 => 2,}\", \"%struct{foo | 1 => 2}\"\n    end\n\n    test \"with keyword lists\" do\n      assert_same \"%struct{foo | :foo => :bar, baz: :bat}\"\n\n      struct = \"\"\"\n      %struct{\n        foo\n        | :foo => :bar,\n          baz: :bat\n      }\n      \"\"\"\n\n      assert_same struct, @medium_length\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      %Foo{\n        foo\n        | :hello => 1,\n          :foo => 2,\n          :bar => 3\n      }\n      \"\"\"\n    end\n\n    test \"converges\" do\n      bad = \"hello_world(%struct{foo | 1 => 2, 3 => 4})\"\n\n      good = \"\"\"\n      hello_world(%struct{\n        foo\n        | 1 => 2,\n          3 => 4\n      })\n      \"\"\"\n\n      assert_format bad, good, line_length: 30\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_formatter/general_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Formatter.GeneralTest do\n  use ExUnit.Case, async: true\n\n  import CodeFormatterHelpers\n\n  @short_length [line_length: 10]\n\n  test \"does not emit warnings\" do\n    assert_format \"fn -> end\", \"fn -> nil end\"\n  end\n\n  describe \"unicode normalization\" do\n    test \"with nfc normalizations\" do\n      assert_format \"ç\", \"ç\"\n    end\n\n    test \"with custom normalizations\" do\n      assert_format \"µs\", \"μs\"\n    end\n  end\n\n  describe \"aliases\" do\n    test \"with atom-only parts\" do\n      assert_same \"Elixir\"\n      assert_same \"Elixir.Foo\"\n      assert_same \"Foo.Bar.Baz\"\n    end\n\n    test \"removes spaces between aliases\" do\n      assert_format \"Foo . Bar . Baz\", \"Foo.Bar.Baz\"\n    end\n\n    test \"starting with expression\" do\n      assert_same \"__MODULE__.Foo.Bar\"\n      # Syntactically valid, semantically invalid\n      assert_same ~S[~c\"Foo\".Bar.Baz]\n    end\n\n    test \"wraps the head in parens if it has an operator\" do\n      assert_format \"+(Foo . Bar . Baz)\", \"+Foo.Bar.Baz\"\n      assert_format \"(+Foo) . Bar . Baz\", \"(+Foo).Bar.Baz\"\n    end\n  end\n\n  describe \"sigils\" do\n    test \"without interpolation\" do\n      assert_same ~S[~s(foo)]\n      assert_same ~S[~s{foo bar}]\n      assert_same ~S[~r/Bar Baz/]\n      assert_same ~S[~w<>]\n      assert_same ~S[~W()]\n      assert_same ~S[~MAT()]\n      assert_same ~S[~MAT{1,2,3}]\n    end\n\n    test \"with escapes\" do\n      assert_same ~S[~s(foo \\) bar)]\n      assert_same ~S[~s(f\\a\\b\\ro)]\n\n      assert_same ~S\"\"\"\n      ~S(foo\\\n      bar)\n      \"\"\"\n    end\n\n    test \"with nested new lines\" do\n      assert_same ~S\"\"\"\n      foo do\n        ~S(foo\\\n      bar)\n      end\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      foo do\n        ~s(#{bar}\n      )\n      end\n      \"\"\"\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S[~s(one #{2} three)]\n    end\n\n    test \"with modifiers\" do\n      assert_same ~S[~w(one two three)a]\n      assert_same ~S[~z(one two three)foo]\n    end\n\n    test \"with interpolation on line limit\" do\n      assert_same ~S\"\"\"\n                  ~s(one #{\"two\"} three)\n                  \"\"\",\n                  @short_length\n    end\n\n    test \"with heredoc syntax\" do\n      assert_same ~S\"\"\"\n      ~s'''\n      one\\a\n      #{:two}\\r\n      three\\0\n      '''\n      \"\"\"\n\n      assert_same ~S'''\n      ~s\"\"\"\n      one\\a\n      #{:two}\\r\n      three\\0\n      \"\"\"\n      '''\n    end\n\n    test \"with heredoc syntax and modifier\" do\n      assert_same ~S\"\"\"\n      ~s'''\n      foo\n      '''rsa\n      \"\"\"\n    end\n\n    test \"with heredoc syntax and interpolation on line limit\" do\n      assert_same ~S\"\"\"\n                  ~s'''\n                  one #{\"two two\"} three\n                  '''\n                  \"\"\",\n                  @short_length\n    end\n\n    test \"with custom formatting\" do\n      bad = \"\"\"\n      ~W/foo  bar  baz/\n      \"\"\"\n\n      good = \"\"\"\n      ~W/foo bar baz/\n      \"\"\"\n\n      formatter = fn content, opts ->\n        assert opts == [file: nil, line: 1, sigil: :W, modifiers: [], opening_delimiter: \"/\"]\n        content |> String.split(~r/ +/) |> Enum.join(\" \")\n      end\n\n      assert_format bad, good, sigils: [W: formatter]\n\n      bad = \"\"\"\n      var = ~W<foo  bar  baz>abc\n      \"\"\"\n\n      good = \"\"\"\n      var = ~W<foo bar baz>abc\n      \"\"\"\n\n      formatter = fn content, opts ->\n        assert opts == [file: nil, line: 1, sigil: :W, modifiers: ~c\"abc\", opening_delimiter: \"<\"]\n        content |> String.split(~r/ +/) |> Enum.intersperse(\" \")\n      end\n\n      assert_format bad, good, sigils: [W: formatter]\n\n      bad = \"\"\"\n      var = ~MAT{foo  bar  baz}abc\n      \"\"\"\n\n      good = \"\"\"\n      var = ~MAT{foo bar baz}abc\n      \"\"\"\n\n      formatter = fn content, opts ->\n        assert opts == [\n                 file: nil,\n                 line: 1,\n                 sigil: :MAT,\n                 modifiers: ~c\"abc\",\n                 opening_delimiter: \"{\"\n               ]\n\n        content |> String.split(~r/ +/) |> Enum.intersperse(\" \")\n      end\n\n      assert_format bad, good, sigils: [MAT: formatter]\n    end\n\n    test \"with custom formatting on heredocs\" do\n      bad = \"\"\"\n      ~W'''\n      foo  bar  baz\n      '''\n      \"\"\"\n\n      good = \"\"\"\n      ~W'''\n      foo bar baz\n      '''\n      \"\"\"\n\n      formatter = fn content, opts ->\n        assert opts == [file: nil, line: 1, sigil: :W, modifiers: [], opening_delimiter: \"'''\"]\n        content |> String.split(~r/ +/) |> Enum.join(\" \")\n      end\n\n      assert_format bad, good, sigils: [W: formatter]\n\n      bad = ~S'''\n      if true do\n        ~W\"\"\"\n        foo\n        bar\n        baz\n        \"\"\"abc\n      end\n      '''\n\n      good = ~S'''\n      if true do\n        ~W\"\"\"\n        foo\n        bar\n        baz\n        \"\"\"abc\n      end\n      '''\n\n      formatter = fn content, opts ->\n        assert opts == [\n                 file: nil,\n                 line: 2,\n                 sigil: :W,\n                 modifiers: ~c\"abc\",\n                 opening_delimiter: ~S/\"\"\"/\n               ]\n\n        content |> String.split(~r/ +/) |> Enum.join(\"\\n\")\n      end\n\n      assert_format bad, good, sigils: [W: formatter]\n    end\n  end\n\n  describe \"anonymous functions\" do\n    test \"with a single clause and no arguments\" do\n      assert_format \"fn  ->:ok  end\", \"fn -> :ok end\"\n\n      bad = \"fn -> :foo end\"\n\n      good = \"\"\"\n      fn ->\n        :foo\n      end\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      assert_same \"fn () when node() == :nonode@nohost -> true end\"\n    end\n\n    test \"with a single clause and arguments\" do\n      assert_format \"fn  x ,y-> x + y  end\", \"fn x, y -> x + y end\"\n\n      bad = \"fn x -> foo(x) end\"\n\n      good = \"\"\"\n      fn x ->\n        foo(x)\n      end\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"fn one, two, three -> foo(x) end\"\n\n      good = \"\"\"\n      fn one,\n         two,\n         three ->\n        foo(x)\n      end\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with a single clause and when\" do\n      code = \"\"\"\n      fn arg\n         when guard ->\n        :ok\n      end\n      \"\"\"\n\n      assert_same code, @short_length\n    end\n\n    test \"keeps parens if argument includes keyword list\" do\n      assert_same \"\"\"\n      fn [] when is_integer(x) ->\n        x + 42\n      end\n      \"\"\"\n\n      bad = \"\"\"\n      fn (input: x) when is_integer(x) ->\n        x + 42\n      end\n      \"\"\"\n\n      good = \"\"\"\n      fn [input: x] when is_integer(x) ->\n        x + 42\n      end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"with a single clause, followed by a newline, and can fit in one line\" do\n      assert_same \"\"\"\n      fn\n        hello -> world\n      end\n      \"\"\"\n    end\n\n    test \"with a single clause, followed by a newline, and can not fit in one line\" do\n      assert_same \"\"\"\n      SomeModule.long_function_name_that_approaches_max_columns(argument, acc, fn\n        %SomeStruct{key: key}, acc -> more_code(key, acc)\n      end)\n      \"\"\"\n    end\n\n    test \"with multiple clauses\" do\n      code = \"\"\"\n      fn\n        1 -> :ok\n        2 -> :ok\n      end\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      fn\n        1 ->\n          :ok\n\n        2 ->\n          :error\n      end\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      fn\n        arg11,\n        arg12 ->\n          body1\n\n        arg21,\n        arg22 ->\n          body2\n      end\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      fn\n        arg11,\n        arg12 ->\n          body1\n\n        arg21,\n        arg22 ->\n          body2\n\n        arg31,\n        arg32 ->\n          body3\n      end\n      \"\"\"\n\n      assert_same code, @short_length\n    end\n\n    test \"with heredocs\" do\n      assert_same ~S'''\n      fn\n        arg1 ->\n          \"\"\"\n          foo\n          \"\"\"\n\n        arg2 ->\n          \"\"\"\n          bar\n          \"\"\"\n      end\n      '''\n    end\n\n    test \"with multiple empty clauses\" do\n      assert_same \"\"\"\n      fn\n        () -> :ok1\n        () -> :ok2\n      end\n      \"\"\"\n    end\n\n    test \"with when in clauses\" do\n      assert_same \"\"\"\n      fn\n        a1 when a + b -> :ok\n        b1 when c + d -> :ok\n      end\n      \"\"\"\n\n      long = \"\"\"\n      fn\n        a1, a2 when a + b -> :ok\n        b1, b2 when c + d -> :ok\n      end\n      \"\"\"\n\n      assert_same long\n\n      good = \"\"\"\n      fn\n        a1, a2\n        when a +\n               b ->\n          :ok\n\n        b1, b2\n        when c +\n               d ->\n          :ok\n      end\n      \"\"\"\n\n      assert_format long, good, @short_length\n    end\n\n    test \"uses block context for the body of each clause\" do\n      assert_same \"fn -> @foo bar end\"\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      fn\n        1 ->\n          :ok\n\n        2 ->\n          :ok\n      end\n      \"\"\"\n\n      assert_same \"\"\"\n      fn\n        1 ->\n          :ok\n\n        2 ->\n          :ok\n\n        3 ->\n          :ok\n      end\n      \"\"\"\n    end\n\n    test \"with -> on line limit\" do\n      bad = \"\"\"\n      fn ab, cd ->\n        ab + cd\n      end\n      \"\"\"\n\n      good = \"\"\"\n      fn ab,\n         cd ->\n        ab + cd\n      end\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"\"\"\n      fn\n        ab, cd ->\n          1\n        xy, zw ->\n          2\n      end\n      \"\"\"\n\n      good = \"\"\"\n      fn\n        ab,\n        cd ->\n          1\n\n        xy,\n        zw ->\n          2\n      end\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n  end\n\n  describe \"anonymous functions types\" do\n    test \"with a single clause and no arguments\" do\n      assert_same \"(-> :ok)\"\n      assert_format \"(->:ok)\", \"(-> :ok)\"\n      assert_format \"( -> :ok)\", \"(-> :ok)\"\n      assert_format \"(() -> :really_long_atom)\", \"(-> :really_long_atom)\", @short_length\n      assert_same \"(() when node() == :nonode@nohost -> true)\"\n    end\n\n    test \"with a single clause and arguments\" do\n      assert_format \"( x ,y-> x + y  )\", \"(x, y -> x + y)\"\n\n      bad = \"(x -> :really_long_atom)\"\n\n      good = \"\"\"\n      (x ->\n         :really_long_atom)\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"(one, two, three -> foo(x))\"\n\n      good = \"\"\"\n      (one,\n       two,\n       three ->\n         foo(x))\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with multiple clauses\" do\n      code = \"\"\"\n      (\n        1 -> :ok\n        2 -> :ok\n      )\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      (\n        1 ->\n          :ok\n\n        2 ->\n          :error\n      )\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      (\n        arg11,\n        arg12 ->\n          body1\n\n        arg21,\n        arg22 ->\n          body2\n      )\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      (\n        arg11,\n        arg12 ->\n          body1\n\n        arg21,\n        arg22 ->\n          body2\n\n        arg31,\n        arg32 ->\n          body2\n      )\n      \"\"\"\n\n      assert_same code, @short_length\n    end\n\n    test \"with heredocs\" do\n      assert_same ~S'''\n      (\n        arg1 ->\n          \"\"\"\n          foo\n          \"\"\"\n\n        arg2 ->\n          \"\"\"\n          bar\n          \"\"\"\n      )\n      '''\n    end\n\n    test \"with multiple empty clauses\" do\n      assert_same \"\"\"\n      (\n        () -> :ok1\n        () -> :ok2\n      )\n      \"\"\"\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      (\n        1 ->\n          :ok\n\n        2 ->\n          :ok\n      )\n      \"\"\"\n\n      assert_same \"\"\"\n      (\n        1 ->\n          :ok\n\n        2 ->\n          :ok\n\n        3 ->\n          :ok\n      )\n      \"\"\"\n    end\n  end\n\n  describe \"blocks\" do\n    test \"empty\" do\n      assert_format \"(;)\", \"\"\n      assert_format \"quote do: (;)\", \"quote do: nil\"\n      assert_format \"quote do end\", \"quote do\\nend\"\n      assert_format \"quote do ; end\", \"quote do\\nend\"\n    end\n\n    test \"with multiple lines\" do\n      assert_same \"\"\"\n      foo = bar\n      baz = bat\n      \"\"\"\n    end\n\n    test \"with multiple lines with line limit\" do\n      code = \"\"\"\n      foo =\n        bar(one)\n\n      baz =\n        bat(two)\n\n      a(b)\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      foo =\n        bar(one)\n\n      a(b)\n\n      baz =\n        bat(two)\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      a(b)\n\n      foo =\n        bar(one)\n\n      baz =\n        bat(two)\n      \"\"\"\n\n      assert_same code, @short_length\n\n      code = \"\"\"\n      foo =\n        bar(one)\n\n      one =\n        two(ghi)\n\n      baz =\n        bat(two)\n      \"\"\"\n\n      assert_same code, @short_length\n    end\n\n    test \"with multiple lines with line limit inside block\" do\n      code = \"\"\"\n      block do\n        a =\n          b(foo)\n\n        c =\n          d(bar)\n\n        e =\n          f(baz)\n      end\n      \"\"\"\n\n      assert_same code, @short_length\n    end\n\n    test \"with multiple lines with cancel expressions\" do\n      code = \"\"\"\n      foo(%{\n        key: 1\n      })\n\n      bar(%{\n        key: 1\n      })\n\n      baz(%{\n        key: 1\n      })\n      \"\"\"\n\n      assert_same code, @short_length\n    end\n\n    test \"with heredoc\" do\n      assert_same ~S'''\n      block do\n        \"\"\"\n        a\n\n        b\n\n        c\n        \"\"\"\n      end\n      '''\n    end\n\n    test \"keeps user newlines\" do\n      assert_same \"\"\"\n      defmodule Mod do\n        field(:foo)\n        field(:bar)\n        field(:baz)\n        belongs_to(:one)\n        belongs_to(:two)\n        timestamp()\n        lock()\n        has_many(:three)\n        has_many(:four)\n        :ok\n        has_one(:five)\n        has_one(:six)\n        foo = 1\n        bar = 2\n        :before\n        baz = 3\n        :after\n      end\n      \"\"\"\n\n      bad = \"\"\"\n      defmodule Mod do\n        field(:foo)\n\n        field(:bar)\n\n        field(:baz)\n\n\n        belongs_to(:one)\n        belongs_to(:two)\n\n\n        timestamp()\n\n        lock()\n\n\n        has_many(:three)\n        has_many(:four)\n\n\n        :ok\n\n\n        has_one(:five)\n        has_one(:six)\n\n\n        foo = 1\n        bar = 2\n\n\n        :before\n        baz = 3\n        :after\n      end\n      \"\"\"\n\n      good = \"\"\"\n      defmodule Mod do\n        field(:foo)\n\n        field(:bar)\n\n        field(:baz)\n\n        belongs_to(:one)\n        belongs_to(:two)\n\n        timestamp()\n\n        lock()\n\n        has_many(:three)\n        has_many(:four)\n\n        :ok\n\n        has_one(:five)\n        has_one(:six)\n\n        foo = 1\n        bar = 2\n\n        :before\n        baz = 3\n        :after\n      end\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"with multiple defs\" do\n      assert_same \"\"\"\n      def foo(:one), do: 1\n      def foo(:two), do: 2\n      def foo(:three), do: 3\n      \"\"\"\n    end\n\n    test \"with module attributes\" do\n      assert_same ~S'''\n      defmodule Foo do\n        @constant 1\n        @constant 2\n\n        @doc \"\"\"\n        foo\n        \"\"\"\n        def foo do\n          :ok\n        end\n\n        @spec bar :: 1\n        @spec bar :: 2\n        def bar do\n          :ok\n        end\n\n        @other_constant 3\n\n        @spec baz :: 4\n        @doc \"\"\"\n        baz\n        \"\"\"\n        def baz do\n          :ok\n        end\n\n        @another_constant 5\n        @another_constant 5\n\n        @doc \"\"\"\n        baz\n        \"\"\"\n        @spec baz :: 6\n        def baz do\n          :ok\n        end\n      end\n      '''\n    end\n\n    test \"as function arguments\" do\n      assert_same \"\"\"\n      fun(\n        (\n          foo\n          bar\n        )\n      )\n      \"\"\"\n\n      assert_same \"\"\"\n      assert true,\n        do:\n          (\n            foo\n            bar\n          )\n      \"\"\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_formatter/integration_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Formatter.IntegrationTest do\n  use ExUnit.Case, async: true\n\n  import CodeFormatterHelpers\n\n  test \"empty documents\" do\n    assert_format \"   \", \"\"\n    assert_format \"\\n\", \"\"\n    assert_format \";\", \"\"\n  end\n\n  test \"function with multiple calls and case\" do\n    assert_same \"\"\"\n    def equivalent(string1, string2) when is_binary(string1) and is_binary(string2) do\n      quoted1 = Code.string_to_quoted!(string1)\n      quoted2 = Code.string_to_quoted!(string2)\n\n      case not_equivalent(quoted1, quoted2) do\n        {left, right} -> {:error, left, right}\n        nil -> :ok\n      end\n    end\n    \"\"\"\n  end\n\n  test \"function with long pipeline\" do\n    assert_same ~S\"\"\"\n    def to_algebra!(string, opts \\\\ []) when is_binary(string) and is_list(opts) do\n      string\n      |> Code.string_to_quoted!(wrap_literals_in_blocks: true, unescape: false)\n      |> block_to_algebra(state(opts))\n      |> elem(0)\n    end\n    \"\"\"\n  end\n\n  test \"case with multiple multi-line arrows\" do\n    assert_same ~S\"\"\"\n    case meta[:format] do\n      :list_heredoc ->\n        string = list |> List.to_string() |> escape_string(:heredoc)\n        {@single_heredoc |> line(string) |> concat(@single_heredoc) |> force_unfit(), state}\n\n      :charlist ->\n        string = list |> List.to_string() |> escape_string(@single_quote)\n        {@single_quote |> concat(string) |> concat(@single_quote), state}\n\n      _other ->\n        list_to_algebra(list, state)\n    end\n    \"\"\"\n  end\n\n  test \"function with long guards\" do\n    assert_same \"\"\"\n    defp module_attribute_read?({:@, _, [{var, _, var_context}]})\n         when is_atom(var) and is_atom(var_context) do\n      Macro.classify_atom(var) == :identifier\n    end\n    \"\"\"\n  end\n\n  test \"anonymous function with single clause and blocks\" do\n    assert_same \"\"\"\n    {args_doc, state} =\n      Enum.reduce(args, {[], state}, fn quoted, {acc, state} ->\n        {doc, state} = quoted_to_algebra(quoted, :block, state)\n        doc = doc |> concat(nest(break(\"\"), :reset)) |> group()\n        {[doc | acc], state}\n      end)\n    \"\"\"\n  end\n\n  test \"anonymous function with long single clause and blocks\" do\n    assert_same \"\"\"\n    {function_count, call_count, total_time} =\n      Enum.reduce(call_results, {0, 0, 0}, fn {_, {count, time}},\n                                              {function_count, call_count, total_time} ->\n        {function_count + 1, call_count + count, total_time + time}\n      end)\n    \"\"\"\n  end\n\n  test \"cond with long clause args\" do\n    assert_same \"\"\"\n    cond do\n      parent_prec == prec and parent_assoc == side ->\n        binary_op_to_algebra(op, op_string, left, right, context, state, op_info, nesting)\n\n      parent_op in @required_parens_on_binary_operands or parent_prec > prec or\n          (parent_prec == prec and parent_assoc != side) ->\n        {operand, state} =\n          binary_op_to_algebra(op, op_string, left, right, context, state, op_info, 2)\n\n        {concat(concat(\"(\", nest(operand, 1)), \")\"), state}\n\n      true ->\n        binary_op_to_algebra(op, op_string, left, right, context, state, op_info, 2)\n    end\n    \"\"\"\n  end\n\n  test \"type with multiple |\" do\n    assert_same \"\"\"\n    @type t ::\n            binary\n            | :doc_nil\n            | :doc_line\n            | doc_string\n            | doc_cons\n            | doc_nest\n            | doc_break\n            | doc_group\n            | doc_color\n            | doc_force\n            | doc_cancel\n    \"\"\"\n  end\n\n  test \"spec with when keywords and |\" do\n    assert_same \"\"\"\n    @spec send(dest, msg, [option]) :: :ok | :noconnect | :nosuspend\n          when dest: pid | port | atom | {atom, node},\n               msg: any,\n               option: :noconnect | :nosuspend\n    \"\"\"\n\n    assert_same \"\"\"\n    @spec send(dest, msg, [option]) :: :ok | :noconnect | :nosuspend\n          when dest:\n                 pid\n                 | port\n                 | atom\n                 | {atom, node}\n                 | and_a_really_long_type_to_force_a_line_break\n                 | followed_by_another_really_long_type\n    \"\"\"\n\n    assert_same \"\"\"\n    @callback get_and_update(data, key, (value -> {get_value, value} | :pop)) :: {get_value, data}\n              when get_value: var, data: container\n    \"\"\"\n  end\n\n  test \"spec with multiple keys on type\" do\n    assert_same \"\"\"\n    @spec foo(%{(String.t() | atom) => any}) :: any\n    \"\"\"\n  end\n\n  test \"multiple whens with new lines\" do\n    assert_same \"\"\"\n    def sleep(timeout)\n        when is_integer(timeout) and timeout >= 0\n        when timeout == :infinity do\n      receive after: (timeout -> :ok)\n    end\n    \"\"\"\n  end\n\n  test \"function with operator and pipeline\" do\n    assert_same \"\"\"\n    defp apply_next_break_fits?({fun, meta, args}) when is_atom(fun) and is_list(args) do\n      meta[:terminator] in [@double_heredoc, @single_heredoc] and\n        fun |> Atom.to_string() |> String.starts_with?(\"sigil_\")\n    end\n    \"\"\"\n  end\n\n  test \"mixed parens and no parens calls with anonymous function\" do\n    assert_same ~S\"\"\"\n    node interface do\n      resolve_type(fn\n        %{__struct__: str}, _ ->\n          str |> Model.Node.model_to_node_type()\n\n        value, _ ->\n          Logger.warning(\"Could not extract node type from value: #{inspect(value)}\")\n          nil\n      end)\n    end\n    \"\"\"\n  end\n\n  test \"long defstruct definition\" do\n    assert_same \"\"\"\n    defstruct name: nil,\n              module: nil,\n              schema: nil,\n              alias: nil,\n              base_module: nil,\n              web_module: nil,\n              basename: nil,\n              file: nil,\n              test_file: nil\n    \"\"\"\n  end\n\n  test \"mix of operators and arguments\" do\n    assert_same \"\"\"\n    def count(%{path: path, line_or_bytes: bytes}) do\n      case File.stat(path) do\n        {:ok, %{size: 0}} -> {:error, __MODULE__}\n        {:ok, %{size: size}} -> {:ok, div(size, bytes) + if(rem(size, bytes) == 0, do: 0, else: 1)}\n        {:error, reason} -> raise File.Error, reason: reason, action: \"stream\", path: path\n      end\n    end\n    \"\"\"\n  end\n\n  test \"mix of left and right operands\" do\n    assert_same \"\"\"\n    defp server_get_modules(handlers) do\n      for(handler(module: module) <- handlers, do: module)\n      |> :ordsets.from_list()\n      |> :ordsets.to_list()\n    end\n    \"\"\"\n\n    assert_same \"\"\"\n    neighbours = for({_, _} = t <- neighbours, do: t) |> :sets.from_list()\n    \"\"\"\n  end\n\n  test \"long expression with single line anonymous function\" do\n    assert_same \"\"\"\n    for_many(uniq_list_of(integer(1..10000)), fn list ->\n      assert Enum.uniq(list) == list\n    end)\n    \"\"\"\n  end\n\n  test \"long comprehension\" do\n    assert_same \"\"\"\n    for %{app: app, opts: opts, top_level: true} <- Mix.Dep.cached(),\n        Keyword.get(opts, :app, true),\n        Keyword.get(opts, :runtime, true),\n        not Keyword.get(opts, :optional, false),\n        app not in included_applications,\n        app not in included_applications,\n        do: app\n    \"\"\"\n  end\n\n  test \"short comprehensions\" do\n    assert_same \"\"\"\n    for {protocol, :protocol, _beam} <- removed_metadata,\n        remove_consolidated(protocol, output),\n        do: {protocol, true},\n        into: %{}\n    \"\"\"\n  end\n\n  test \"comprehensions with when\" do\n    assert_same \"\"\"\n    for {key, value} when is_atom(key) <- Map.to_list(map),\n        key = Atom.to_string(key),\n        String.starts_with?(key, hint) do\n      %{kind: :map_key, name: key, value_is_map: is_map(value)}\n    end\n    \"\"\"\n\n    assert_same \"\"\"\n    with {_, doc} when unquote(doc_attr?) <-\n           Module.get_attribute(__MODULE__, unquote(name), unquote(escaped)),\n         do: doc\n    \"\"\"\n  end\n\n  test \"next break fits followed by inline tuple\" do\n    assert_same \"\"\"\n    assert ExUnit.Filters.eval([line: \"1\"], [:line], %{line: 3, describe_line: 2}, tests) ==\n             {:error, \"due to line filter\"}\n    \"\"\"\n  end\n\n  test \"try/catch with clause comment\" do\n    assert_same \"\"\"\n    def format_error(reason) do\n      try do\n        do_format_error(reason)\n      catch\n        # A user could create an error that looks like a built-in one\n        # causing an error.\n        :error, _ ->\n          inspect(reason)\n      end\n    end\n    \"\"\"\n  end\n\n  test \"case with when and clause comment\" do\n    assert_same \"\"\"\n    case decomposition do\n      # Decomposition\n      <<h, _::binary>> when h != ?< ->\n        decomposition =\n          decomposition\n          |> :binary.split(\" \", [:global])\n          |> Enum.map(&String.to_integer(&1, 16))\n\n        Map.put(dacc, String.to_integer(codepoint, 16), decomposition)\n\n      _ ->\n        dacc\n    end\n    \"\"\"\n  end\n\n  test \"do-end inside binary\" do\n    assert_same \"\"\"\n    <<if true do\n        \"hello\"\n      end::binary>>\n    \"\"\"\n  end\n\n  test \"anonymous function with parens around integer argument\" do\n    bad = \"\"\"\n    fn (1) -> \"hello\" end\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    fn 1 -> \"hello\" end\n    \"\"\"\n  end\n\n  test \"no parens keywords at the end of the line\" do\n    bad = \"\"\"\n    defmodule Mod do\n      def token_list_downcase(<<char, rest::binary>>, acc) when is_whitespace(char) or is_comma(char), do: token_list_downcase(rest, acc)\n      def token_list_downcase(some_really_long_arg11, some_really_long_arg22, some_really_long_arg33), do: token_list_downcase(rest, acc)\n    end\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    defmodule Mod do\n      def token_list_downcase(<<char, rest::binary>>, acc) when is_whitespace(char) or is_comma(char),\n        do: token_list_downcase(rest, acc)\n\n      def token_list_downcase(some_really_long_arg11, some_really_long_arg22, some_really_long_arg33),\n        do: token_list_downcase(rest, acc)\n    end\n    \"\"\"\n  end\n\n  test \"do at the end of the line\" do\n    bad = \"\"\"\n    foo bar, baz, quux do\n      :ok\n    end\n    \"\"\"\n\n    good = \"\"\"\n    foo bar,\n        baz,\n        quux do\n      :ok\n    end\n    \"\"\"\n\n    assert_format bad, good, line_length: 18\n  end\n\n  test \"keyword lists in last line\" do\n    assert_same \"\"\"\n    content =\n      config(VeryLongModuleNameThatWillCauseBreak, \"new.html\",\n        conn: conn,\n        changeset: changeset,\n        categories: categories\n      )\n    \"\"\"\n\n    assert_same \"\"\"\n    content =\n      config VeryLongModuleNameThatWillCauseBreak, \"new.html\",\n        conn: conn,\n        changeset: changeset,\n        categories: categories\n    \"\"\"\n  end\n\n  test \"keyword list at line limit\" do\n    bad = \"\"\"\n    pre()\n    config(arg, foo: bar)\n    post()\n    \"\"\"\n\n    good = \"\"\"\n    pre()\n\n    config(arg,\n      foo: bar\n    )\n\n    post()\n    \"\"\"\n\n    assert_format bad, good, line_length: 20\n  end\n\n  test \"do at the end of the line with single argument\" do\n    bad = \"\"\"\n    defmodule Location do\n      def new(line, column) when is_integer(line) and line >= 0 and is_integer(column) and column >= 0 do\n        %{column: column, line: line}\n      end\n    end\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    defmodule Location do\n      def new(line, column)\n          when is_integer(line) and line >= 0 and is_integer(column) and column >= 0 do\n        %{column: column, line: line}\n      end\n    end\n    \"\"\"\n  end\n\n  test \"tuples as trees\" do\n    bad = \"\"\"\n    @document Parser.parse(\n      {\"html\", [], [\n         {\"head\", [], []},\n         {\"body\", [], [\n              {\"div\", [], [\n                  {\"p\", [], [\"1\"]},\n                  {\"p\", [], [\"2\"]},\n                  {\"div\", [], [\n                      {\"p\", [], [\"3\"]},\n                      {\"p\", [], [\"4\"]}]},\n                  {\"p\", [], [\"5\"]}]}]}]})\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    @document Parser.parse(\n                {\"html\", [],\n                 [\n                   {\"head\", [], []},\n                   {\"body\", [],\n                    [\n                      {\"div\", [],\n                       [\n                         {\"p\", [], [\"1\"]},\n                         {\"p\", [], [\"2\"]},\n                         {\"div\", [],\n                          [\n                            {\"p\", [], [\"3\"]},\n                            {\"p\", [], [\"4\"]}\n                          ]},\n                         {\"p\", [], [\"5\"]}\n                       ]}\n                    ]}\n                 ]}\n              )\n    \"\"\"\n  end\n\n  test \"nested tuples as lines\" do\n    assert_same \"\"\"\n                {:ok,\n                 {1, 2, 3,\n                  4, 5}} =\n                  call()\n                \"\"\",\n                line_length: 10\n  end\n\n  test \"first argument in a call without parens with comments\" do\n    assert_same \"\"\"\n    with bar ::\n           :ok\n           | :invalid\n           # | :unknown\n           | :other\n    \"\"\"\n\n    assert_same \"\"\"\n    @spec bar ::\n            :ok\n            | :invalid\n            # | :unknown\n            | :other\n    \"\"\"\n  end\n\n  test \"when with keywords inside call\" do\n    assert_same \"\"\"\n    quote((bar(foo(1)) when bat: foo(1)), [])\n    \"\"\"\n\n    assert_same \"\"\"\n    quote(do: (bar(foo(1)) when bat: foo(1)), line: 1)\n    \"\"\"\n\n    assert_same \"\"\"\n    typespec(quote(do: (bar(foo(1)) when bat: foo(1))), [foo: 1], [])\n    \"\"\"\n  end\n\n  test \"false positive sigil\" do\n    assert_same \"\"\"\n    def sigil_d(<<year::2-bytes, \"-\", month::2-bytes, \"-\", day::2-bytes>>, calendar) do\n      ymd(year, month, day, calendar)\n    end\n    \"\"\"\n  end\n\n  test \"newline after stab\" do\n    assert_same \"\"\"\n    capture_io(\":erl. mof*,,l\", fn ->\n      assert :io.scan_erl_form(~c\">\") == {:ok, [{:\":\", 1}, {:atom, 1, :erl}, {:dot, 1}], 1}\n\n      expected_tokens = [{:atom, 1, :mof}, {:*, 1}, {:\",\", 1}, {:\",\", 1}, {:atom, 1, :l}]\n      assert :io.scan_erl_form(~c\">\") == {:ok, expected_tokens, 1}\n\n      assert :io.scan_erl_form(~c\">\") == {:eof, 1}\n    end)\n    \"\"\"\n  end\n\n  test \"capture with operators\" do\n    assert_same \"\"\"\n    \"this works\" |> (&String.upcase/1) |> (&String.downcase/1)\n    \"\"\"\n\n    assert_same \"\"\"\n    \"this works\" || (&String.upcase/1) || (&String.downcase/1)\n    \"\"\"\n\n    assert_same \"\"\"\n    \"this works\" == (&String.upcase/1) == (&String.downcase/1)\n    \"\"\"\n\n    bad = \"\"\"\n    \"this works\" = (&String.upcase/1) = (&String.downcase/1)\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    \"this works\" = (&String.upcase/1) = &String.downcase/1\n    \"\"\"\n\n    bad = \"\"\"\n    \"this works\" ++ (&String.upcase/1) ++ (&String.downcase/1)\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    \"this works\" ++ (&String.upcase/1) ++ &String.downcase/1\n    \"\"\"\n\n    bad = \"\"\"\n    \"this works\" +++ (&String.upcase/1) +++ (&String.downcase/1)\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    \"this works\" +++ (&String.upcase/1) +++ &String.downcase/1\n    \"\"\"\n\n    bad = \"\"\"\n    \"this works\" | (&String.upcase/1) | (&String.downcase/1)\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    \"this works\" | (&String.upcase/1) | &String.downcase/1\n    \"\"\"\n\n    bad = ~S\"\"\"\n    \"this works\" \\\\ (&String.upcase/1) \\\\ (&String.downcase/1)\n    \"\"\"\n\n    assert_format bad, ~S\"\"\"\n    \"this works\" \\\\ &String.upcase/1 \\\\ &String.downcase/1\n    \"\"\"\n  end\n\n  test \"multiline expression inside interpolation\" do\n    bad = ~S\"\"\"\n    Logger.info(\"Example: #{\n      inspect(%{\n        a: 1,\n        b: 2\n      })\n    }\")\n    \"\"\"\n\n    assert_format bad, ~S\"\"\"\n    Logger.info(\"Example: #{inspect(%{a: 1, b: 2})}\")\n    \"\"\"\n  end\n\n  test \"comment inside operator with when\" do\n    bad = \"\"\"\n    raise function(x) ::\n            # Comment\n            any\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    # Comment\n    raise function(x) ::\n            any\n    \"\"\"\n\n    bad = \"\"\"\n    raise function(x) ::\n            # Comment\n            any\n          when x: any\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    raise function(x) ::\n            any\n          # Comment\n          when x: any\n    \"\"\"\n\n    bad = \"\"\"\n    @spec function(x) ::\n            # Comment\n            any\n          when x: any\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    @spec function(x) ::\n            any\n          # Comment\n          when x: any\n    \"\"\"\n\n    bad = \"\"\"\n    @spec function(x) ::\n            # Comment\n            any\n          when x\n          when y\n    \"\"\"\n\n    assert_format bad, \"\"\"\n    @spec function(x) ::\n            any\n          # Comment\n          when x\n          when y\n    \"\"\"\n  end\n\n  test \"nested heredocs with multi-line string in interpolation\" do\n    bad = ~S'''\n    def foo do\n      \"\"\"\n      #{(feature_flag(:feature_x) && \"\n      new_field\n      \" || \"\")}\n      \"\"\"\n    end\n    '''\n\n    good = ~S'''\n    def foo do\n      \"\"\"\n      #{(feature_flag(:feature_x) && \"\n      new_field\n      \") || \"\"}\n      \"\"\"\n    end\n    '''\n\n    assert_format bad, good\n  end\n\n  test \"functions with infinity line length\" do\n    assert_same ~S\"\"\"\n                x = fn ->\n                  {:ok, pid} = Repl.start_link({self(), opts})\n                  assert Exception.message(error) =~ msg\n                end\n                \"\"\",\n                line_length: :infinity\n\n    assert_same ~S\"\"\"\n                capture_log(fn x ->\n                  {:ok, pid} = Repl.start_link({self(), opts})\n                  assert Exception.message(error) =~ msg\n                end) =~ msg\n                \"\"\",\n                line_length: :infinity\n\n    assert_same ~S\"\"\"\n                capture_log(fn ->\n                  {:ok, pid} = Repl.start_link({self(), opts})\n                  assert Exception.message(error) =~ msg\n                end) =~ msg\n                \"\"\",\n                line_length: :infinity\n\n    assert_same ~S\"\"\"\n                capture_log(fn x ->\n                  {:ok, pid} = Repl.start_link({self(), opts})\n                  assert Exception.message(error) =~ msg\n                end) =~ msg\n                \"\"\",\n                line_length: :infinity\n  end\n\n  test \"functions without parentheses within do: keyword\" do\n    assert_format ~S\"defmodule Foo, do: foo bar, baz\",\n                  ~S\"defmodule Foo, do: foo(bar, baz)\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_formatter/literals_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Formatter.LiteralsTest do\n  use ExUnit.Case, async: true\n\n  import CodeFormatterHelpers\n\n  @short_length [line_length: 10]\n\n  describe \"integers\" do\n    test \"in decimal base\" do\n      assert_same \"0\"\n      assert_same \"100\"\n      assert_same \"007\"\n      assert_same \"10000\"\n      assert_same \"100_00\"\n      assert_format \"100000\", \"100_000\"\n      assert_format \"1000000\", \"1_000_000\"\n    end\n\n    test \"in binary base\" do\n      assert_same \"0b0\"\n      assert_same \"0b1\"\n      assert_same \"0b101\"\n      assert_same \"0b01\"\n      assert_same \"0b111_111\"\n    end\n\n    test \"in octal base\" do\n      assert_same \"0o77\"\n      assert_same \"0o0\"\n      assert_same \"0o01\"\n      assert_same \"0o777_777\"\n    end\n\n    test \"in hex base\" do\n      assert_same \"0x1\"\n      assert_format \"0xabcdef\", \"0xABCDEF\"\n      assert_same \"0x01\"\n      assert_format \"0xfff_fff\", \"0xFFF_FFF\"\n    end\n\n    test \"as chars\" do\n      assert_same \"?a\"\n      assert_same \"?1\"\n      assert_same \"?è\"\n      assert_same \"??\"\n      assert_same \"?\\\\\\\\\"\n      assert_same \"?\\\\s\"\n      assert_same \"?🎾\"\n    end\n  end\n\n  describe \"floats\" do\n    test \"with normal notation\" do\n      assert_same \"0.0\"\n      assert_same \"1.0\"\n      assert_same \"123.456\"\n      assert_same \"0.0000001\"\n      assert_same \"001.100\"\n      assert_same \"0_10000_0.000_000\"\n      assert_format \"0100000.000000\", \"0_100_000.000000\"\n    end\n\n    test \"with scientific notation\" do\n      assert_same \"1.0e1\"\n      assert_same \"1.0e-1\"\n      assert_same \"1.0e01\"\n      assert_same \"1.0e-01\"\n      assert_same \"001.100e-010\"\n      assert_same \"0_100_0000.100e-010\"\n      assert_format \"0100000.0e-5\", \"0_100_000.0e-5\"\n\n      assert_format \"1.0E01\", \"1.0e01\"\n      assert_format \"1.0E-01\", \"1.0e-01\"\n    end\n  end\n\n  describe \"atoms\" do\n    test \"true, false, nil\" do\n      assert_same \"nil\"\n      assert_same \"true\"\n      assert_same \"false\"\n    end\n\n    test \"without escapes\" do\n      assert_same ~S[:foo]\n      assert_same ~S[:\\\\]\n    end\n\n    test \"with escapes\" do\n      assert_same ~S[:\"f\\a\\b\\ro\"]\n      assert_format ~S[:'f\\a\\b\\ro'], ~S[:\"f\\a\\b\\ro\"]\n      assert_format ~S[:'single \\' quote'], ~S[:\"single ' quote\"]\n      assert_format ~S[:\"double \\\" quote\"], ~S[:\"double \\\" quote\"]\n      assert_same ~S[:\"\\\\\"]\n    end\n\n    test \"with unicode\" do\n      assert_same ~S[:ólá]\n    end\n\n    test \"does not reformat aliases\" do\n      assert_same ~S[:\"Elixir.String\"]\n    end\n\n    test \"removes quotes when they are not necessary\" do\n      assert_format ~S[:\"foo\"], ~S[:foo]\n      assert_format ~S[:\"++\"], ~S[:++]\n    end\n\n    test \"quoted operators\" do\n      assert_same ~S[:\"::\"]\n    end\n\n    test \"uses double quotes even when single quotes are used\" do\n      assert_format ~S[:'foo bar'], ~S[:\"foo bar\"]\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S[:\"one #{2} three\"]\n    end\n\n    test \"with escapes and interpolation\" do\n      assert_same ~S[:\"one\\n\\\"#{2}\\\"\\nthree\"]\n    end\n\n    test \"with interpolation on line limit\" do\n      assert_same ~S\"\"\"\n                  :\"one #{\"two\"} three\"\n                  \"\"\",\n                  @short_length\n    end\n  end\n\n  describe \"strings\" do\n    test \"without escapes\" do\n      assert_same ~S[\"foo\"]\n    end\n\n    test \"with escapes\" do\n      assert_same ~S[\"f\\a\\b\\ro\"]\n      assert_same ~S[\"double \\\" quote\"]\n    end\n\n    test \"keeps literal new lines\" do\n      assert_same \"\"\"\n      \"fo\n      o\"\n      \"\"\"\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S[\"one #{} three\"]\n      assert_same ~S[\"one #{2} three\"]\n    end\n\n    test \"with interpolation uses block content\" do\n      assert_format ~S[\"one #{@two(three)}\"], ~S[\"one #{@two three}\"]\n    end\n\n    test \"with interpolation on line limit\" do\n      assert_same ~S\"\"\"\n                  \"one #{\"two\"} three\"\n                  \"\"\",\n                  @short_length\n    end\n\n    test \"with escaped interpolation\" do\n      assert_same ~S[\"one\\#{two}three\"]\n    end\n\n    test \"with escapes and interpolation\" do\n      assert_same ~S[\"one\\n\\\"#{2}\\\"\\nthree\"]\n    end\n\n    test \"is measured in graphemes\" do\n      assert_same ~S\"\"\"\n                  \"áá#{0}áá\"\n                  \"\"\",\n                  @short_length\n    end\n\n    test \"literal new lines don't count towards line limit\" do\n      assert_same ~S\"\"\"\n                  \"one\n                  #{\"two\"}\n                  three\"\n                  \"\"\",\n                  @short_length\n    end\n  end\n\n  describe \"charlists\" do\n    test \"without escapes\" do\n      assert_same ~S['']\n      assert_same ~S[' ']\n      assert_same ~S['foo']\n    end\n\n    test \"with escapes\" do\n      assert_same ~S['f\\a\\b\\ro']\n      assert_same ~S['single \\' quote']\n      assert_same ~S['double \" quote']\n      assert_same ~S['escaped \\\" quote']\n      assert_same ~S['\\\\\"']\n    end\n\n    test \"keeps literal new lines\" do\n      assert_same \"\"\"\n      'fo\n      o'\n      \"\"\"\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S['one #{2} three']\n      assert_same ~S['#{1}\\n \\\\ \" \\\"']\n    end\n\n    test \"with escape and interpolation\" do\n      assert_same ~S['one\\n\\'#{2}\\'\\nthree']\n    end\n\n    test \"with interpolation on line limit\" do\n      assert_same ~S\"\"\"\n                  'one #{\"two\"} three'\n                  \"\"\",\n                  @short_length\n    end\n\n    test \"literal new lines don't count towards line limit\" do\n      assert_same ~S\"\"\"\n                  'one\n                  #{\"two\"}\n                  three'\n                  \"\"\",\n                  @short_length\n    end\n  end\n\n  describe \"string heredocs\" do\n    test \"without escapes\" do\n      assert_same ~S'''\n      \"\"\"\n      hello\n      \"\"\"\n      '''\n    end\n\n    test \"with escapes\" do\n      assert_same ~S'''\n      \"\"\"\n      f\\a\\b\\ro\n      \"\"\"\n      '''\n\n      assert_same ~S'''\n      \"\"\"\n      multiple \"\\\"\" quotes\n      \"\"\"\n      '''\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S'''\n      \"\"\"\n      one\n      #{2}\n      three\n      \"\"\"\n      '''\n\n      assert_same ~S'''\n      \"\"\"\n      one\n      \"\n      #{2}\n      \"\n      three\n      \"\"\"\n      '''\n    end\n\n    test \"with interpolation on line limit\" do\n      assert_same ~S'''\n                  \"\"\"\n                  one #{\"two two\"} three\n                  \"\"\"\n                  ''',\n                  @short_length\n    end\n\n    test \"nested with empty lines\" do\n      assert_same ~S'''\n      nested do\n        \"\"\"\n\n        foo\n\n\n        bar\n\n        \"\"\"\n      end\n      '''\n    end\n\n    test \"nested with empty lines and interpolation\" do\n      assert_same ~S'''\n      nested do\n        \"\"\"\n\n        #{foo}\n\n\n        #{bar}\n\n        \"\"\"\n      end\n      '''\n\n      assert_same ~S'''\n      nested do\n        \"\"\"\n        #{foo}\n\n\n        #{bar}\n        \"\"\"\n      end\n      '''\n    end\n\n    test \"literal new lines don't count towards line limit\" do\n      assert_same ~S'''\n                  \"\"\"\n                  one\n                  #{\"two\"}\n                  three\n                  \"\"\"\n                  ''',\n                  @short_length\n    end\n\n    test \"with escaped new lines\" do\n      assert_same ~S'''\n      \"\"\"\n      one\\\n      #{\"two\"}\\\n      three\\\n      \"\"\"\n      '''\n    end\n\n    test \"with new lines\" do\n      assert_format ~s|foo do\\n  \"\"\"\\n  foo\\n  \\n  bar\\n  \"\"\"\\nend|,\n                    ~s|foo do\\n  \"\"\"\\n  foo\\n\\n  bar\\n  \"\"\"\\nend|\n\n      assert_format ~s|foo do\\r\\n  \"\"\"\\r\\n  foo\\r\\n  \\r\\n  bar\\r\\n  \"\"\"\\r\\nend|,\n                    ~s|foo do\\n  \"\"\"\\n  foo\\r\\n\\r\\n  bar\\r\\n  \"\"\"\\nend|\n    end\n  end\n\n  describe \"charlist heredocs\" do\n    test \"without escapes\" do\n      assert_same ~S\"\"\"\n      '''\n      hello\n      '''\n      \"\"\"\n    end\n\n    test \"with escapes\" do\n      assert_same ~S\"\"\"\n      '''\n      f\\a\\b\\ro\n      '''\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      '''\n      multiple \"\\\"\" quotes\n      '''\n      \"\"\"\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S\"\"\"\n      '''\n      one\n      #{2}\n      three\n      '''\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      '''\n      one\n      \"\n      #{2}\n      \"\n      three\n      '''\n      \"\"\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_formatter/migration_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Formatter.MigrationTest do\n  use ExUnit.Case, async: true\n\n  import CodeFormatterHelpers\n\n  @short_length [line_length: 10]\n\n  describe \"migrate_bitstring_modifiers: true\" do\n    @opts [migrate_bitstring_modifiers: true]\n\n    test \"normalizes bitstring modifiers\" do\n      assert_format \"<<foo::binary()>>\", \"<<foo::binary>>\", @opts\n      assert_same \"<<foo::binary>>\", @opts\n\n      assert_format \"<<foo::custom_type>>\", \"<<foo::custom_type()>>\", @opts\n      assert_same \"<<foo::custom_type()>>\", @opts\n\n      assert_format \"<<x::binary()-(13 * 6)-custom>>\", \"<<x::binary-(13 * 6)-custom()>>\", @opts\n      assert_same \"<<x::binary-(13 * 6)-custom()>>\", @opts\n      assert_same \"<<0::size*unit, bytes::binary>>\", @opts\n      assert_format \"<<0::size*unit, bytes::custom>>\", \"<<0::size*unit, bytes::custom()>>\", @opts\n\n      assert_format \"<<0, 1::2-integer() <- x>>\", \"<<0, 1::2-integer <- x>>\", @opts\n      assert_same \"<<0, 1::2-integer <- x>>\", @opts\n    end\n  end\n\n  describe \"migrate_call_parens_on_pipe: true\" do\n    @opts [migrate_call_parens_on_pipe: true]\n\n    test \"adds parentheses on the right operand\" do\n      assert_format \"x |> y\", \"x |> y()\", @opts\n      assert_format \"x |> y |> z\", \"x |> y() |> z()\", @opts\n      assert_format \"x |> y.z\", \"x |> y.z()\", @opts\n      assert_format \"x |> y.z.t\", \"x |> y.z.t()\", @opts\n    end\n\n    test \"does nothing within defmacro\" do\n      assert_same \"defmacro left |> right, do: ...\", @opts\n    end\n\n    test \"does nothing without the migrate_unless option\" do\n      assert_same \"x |> y\"\n      assert_same \"x |> y |> z\"\n      assert_same \"x |> y.z\"\n    end\n  end\n\n  describe \"migrate_charlists_as_sigils: true\" do\n    @opts [migrate_charlists_as_sigils: true]\n\n    test \"without escapes\" do\n      assert_format ~S[''], ~S[~c\"\"], @opts\n      assert_format ~S[' '], ~S[~c\" \"], @opts\n      assert_format ~S['foo'], ~S[~c\"foo\"], @opts\n    end\n\n    test \"with escapes\" do\n      assert_format ~S['f\\a\\b\\ro'], ~S[~c\"f\\a\\b\\ro\"], @opts\n      assert_format ~S['single \\' quote'], ~S[~c\"single ' quote\"], @opts\n      assert_format ~S['double \" quote'], ~S[~c'double \" quote'], @opts\n      assert_format ~S['escaped \\\" quote'], ~S[~c'escaped \\\" quote'], @opts\n      assert_format ~S['\\\\\"'], ~S[~c'\\\\\"'], @opts\n    end\n\n    test \"keeps literal new lines\" do\n      assert_format \"\"\"\n                    'fo\n                    o'\n                    \"\"\",\n                    \"\"\"\n                    ~c\"fo\n                    o\"\n                    \"\"\",\n                    @opts\n    end\n\n    test \"with interpolation\" do\n      assert_format ~S['one #{2} three'], ~S[~c\"one #{2} three\"], @opts\n      assert_format ~S['#{1}\\n \\\\ \" \\\"'], ~S[~c'#{1}\\n \\\\ \" \\\"'], @opts\n    end\n\n    test \"with escape and interpolation\" do\n      assert_format ~S['one\\n\\'#{2}\\'\\nthree'], ~S[~c\"one\\n'#{2}'\\nthree\"], @opts\n      assert_format ~S['one\\n\"#{2}\"\\nthree'], ~S[~c'one\\n\"#{2}\"\\nthree'], @opts\n    end\n\n    test \"with interpolation on line limit\" do\n      assert_format ~S\"\"\"\n                    'one #{\"two\"} three'\n                    \"\"\",\n                    ~S\"\"\"\n                    ~c\"one #{\"two\"} three\"\n                    \"\"\",\n                    @short_length ++ @opts\n    end\n\n    test \"literal new lines don't count towards line limit\" do\n      assert_format ~S\"\"\"\n                    'one\n                    #{\"two\"}\n                    three'\n                    \"\"\",\n                    ~S\"\"\"\n                    ~c\"one\n                    #{\"two\"}\n                    three\"\n                    \"\"\",\n                    @short_length ++ @opts\n    end\n\n    test \"heredocs without escapes\" do\n      assert_format ~S\"\"\"\n                    '''\n                    hello\n                    '''\n                    \"\"\",\n                    ~S'''\n                    ~c\"\"\"\n                    hello\n                    \"\"\"\n                    ''',\n                    @opts\n    end\n\n    test \"heredocs with escapes\" do\n      assert_format ~S\"\"\"\n                    '''\n                    f\\a\\b\\ro\n                    '''\n                    \"\"\",\n                    ~S'''\n                    ~c\"\"\"\n                    f\\a\\b\\ro\n                    \"\"\"\n                    ''',\n                    @opts\n\n      assert_format ~S\"\"\"\n                    '''\n                    multiple \"\\\"\" quotes\n                    '''\n                    \"\"\",\n                    ~S'''\n                    ~c\"\"\"\n                    multiple \"\\\"\" quotes\n                    \"\"\"\n                    ''',\n                    @opts\n    end\n\n    test \"heredocs with interpolation\" do\n      assert_format ~S\"\"\"\n                    '''\n                    one\n                    #{2}\n                    three\n                    '''\n                    \"\"\",\n                    ~S'''\n                    ~c\"\"\"\n                    one\n                    #{2}\n                    three\n                    \"\"\"\n                    ''',\n                    @opts\n\n      assert_format ~S\"\"\"\n                    '''\n                    one\n                    \"\n                    #{2}\n                    \"\n                    three\n                    '''\n                    \"\"\",\n                    ~S'''\n                    ~c\"\"\"\n                    one\n                    \"\n                    #{2}\n                    \"\n                    three\n                    \"\"\"\n                    ''',\n                    @opts\n    end\n\n    test \"heredocs with interpolation on line limit\" do\n      assert_format ~S\"\"\"\n                    '''\n                    one #{\"two two\"} three\n                    '''\n                    \"\"\",\n                    ~S'''\n                    ~c\"\"\"\n                    one #{\"two two\"} three\n                    \"\"\"\n                    ''',\n                    @short_length ++ @opts\n    end\n\n    test \"heredocs literal new lines don't count towards line limit\" do\n      assert_format ~S\"\"\"\n                    '''\n                    one\n                    #{\"two\"}\n                    three\n                    '''\n                    \"\"\",\n                    ~S'''\n                    ~c\"\"\"\n                    one\n                    #{\"two\"}\n                    three\n                    \"\"\"\n                    ''',\n                    @short_length ++ @opts\n    end\n  end\n\n  describe \"migrate_unless: true\" do\n    @opts [migrate_unless: true]\n\n    test \"rewrites unless as an if with negated condition\" do\n      bad = \"unless x, do: y\"\n\n      good = \"if !x, do: y\"\n\n      assert_format bad, good, @opts\n\n      bad = \"\"\"\n      unless x do\n        y\n      else\n        z\n      end\n      \"\"\"\n\n      good = \"\"\"\n      if !x do\n        y\n      else\n        z\n      end\n      \"\"\"\n\n      assert_format bad, good, @opts\n    end\n\n    test \"rewrites pipelines with negated condition\" do\n      bad = \"x |> unless(do: y)\"\n\n      good = \"!x |> if(do: y)\"\n\n      assert_format bad, good, @opts\n\n      bad = \"x |> foo() |> unless(do: y)\"\n\n      good = \"x |> foo() |> Kernel.!() |> if(do: y)\"\n\n      assert_format bad, good, @opts\n\n      bad = \"unless x |> foo(), do: y\"\n      good = \"if !(x |> foo()), do: y\"\n\n      assert_format bad, good, @opts\n    end\n\n    test \"rewrites in as not in\" do\n      assert_format \"unless x in y, do: 1\", \"if x not in y, do: 1\", @opts\n    end\n\n    test \"rewrites equality operators\" do\n      assert_format \"unless x == y, do: 1\", \"if x != y, do: 1\", @opts\n      assert_format \"unless x === y, do: 1\", \"if x !== y, do: 1\", @opts\n      assert_format \"unless x != y, do: 1\", \"if x == y, do: 1\", @opts\n      assert_format \"unless x !== y, do: 1\", \"if x === y, do: 1\", @opts\n    end\n\n    test \"rewrites boolean or is_* conditions with not\" do\n      assert_format \"unless x > 0, do: 1\", \"if not (x > 0), do: 1\", @opts\n      assert_format \"unless is_atom(x), do: 1\", \"if not is_atom(x), do: 1\", @opts\n    end\n\n    test \"removes ! or not in condition\" do\n      assert_format \"unless not x, do: 1\", \"if x, do: 1\", @opts\n      assert_format \"unless !x, do: 1\", \"if x, do: 1\", @opts\n    end\n\n    test \"does nothing without the migrate_unless option\" do\n      assert_same \"unless x, do: y\"\n      assert_same \"unless x, do: y, else: z\"\n    end\n  end\n\n  describe \"migrate: true\" do\n    test \"enables :migrate_bitstring_modifiers\" do\n      assert_format \"<<foo::binary()>>\", \"<<foo::binary>>\", migrate: true\n    end\n\n    test \"enables :migrate_call_parens_on_pipe\" do\n      bad = \"x |> y\"\n\n      good = \"x |> y()\"\n\n      assert_format bad, good, migrate: true\n    end\n\n    test \"enables :migrate_charlists_as_sigils\" do\n      assert_format ~S['abc'], ~S[~c\"abc\"], migrate: true\n    end\n\n    test \"enables :migrate_unless\" do\n      bad = \"unless x, do: y\"\n\n      good = \"if !x, do: y\"\n\n      assert_format bad, good, migrate: true\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_formatter/operators_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Formatter.OperatorsTest do\n  use ExUnit.Case, async: true\n\n  import CodeFormatterHelpers\n\n  @short_length [line_length: 10]\n  @medium_length [line_length: 20]\n\n  describe \"nullary\" do\n    test \"formats symbol operators\" do\n      assert_same \"..\"\n    end\n\n    test \"combines with unary and binary operators\" do\n      assert_same \"not ..\"\n      assert_same \"left = ..\"\n      assert_same \".. = right\"\n    end\n\n    test \"is wrapped in parentheses on ambiguous calls\" do\n      assert_same \"require (..)\"\n      assert_same \"require foo, (..)\"\n      assert_same \"require (..), bar\"\n      assert_same \"require(..)\"\n      assert_same \"require(foo, ..)\"\n      assert_same \"require(.., bar)\"\n\n      assert_same \"assert [.., :ok]\"\n      assert_same \"assert {.., :ok}\"\n      assert_same \"assert (..) == 0..-1//1\"\n      assert_same \"assert 0..-1//1 == (..)\"\n\n      assert_same \"\"\"\n      defmacro (..) do\n        :ok\n      end\\\n      \"\"\"\n\n      assert_format \"Range.range? (..)\", \"Range.range?(..)\"\n    end\n  end\n\n  describe \"unary\" do\n    test \"formats symbol operators without spaces\" do\n      assert_format \"+ 1\", \"+1\"\n      assert_format \"- 1\", \"-1\"\n      assert_format \"! 1\", \"!1\"\n      assert_format \"^ 1\", \"^1\"\n    end\n\n    test \"formats word operators with spaces\" do\n      assert_same \"not 1\"\n      assert_same \"not true\"\n    end\n\n    test \"wraps operand if it is a unary or binary operator\" do\n      assert_format \"!+1\", \"!(+1)\"\n      assert_format \"+ +1\", \"+(+1)\"\n      assert_format \"not +1\", \"not (+1)\"\n      assert_format \"!not 1\", \"!(not 1)\"\n      assert_format \"not !1\", \"not (!1)\"\n      assert_format \"not(!1)\", \"not (!1)\"\n      assert_format \"not(1 + 1)\", \"not (1 + 1)\"\n      assert_format \"-(2**2)\", \"-(2 ** 2)\"\n    end\n\n    test \"wraps operand in ambiguous calls\" do\n      assert_same \"def -(2 ** 2)\"\n      assert_same \"def -var\"\n      assert_format \"def (-(2 ** 2))\", \"def -(2 ** 2)\"\n      assert_format \"def --var\", \"def -- var\"\n      assert_format \"def -+var\", \"def -(+var)\"\n    end\n\n    test \"does not wrap operand if it is a nestable operator\" do\n      assert_format \"! ! var\", \"!!var\"\n      assert_same \"not not var\"\n    end\n\n    test \"nests operand\" do\n      bad = \"+foo(bar, baz, bat)\"\n\n      good = \"\"\"\n      +foo(\n        bar,\n        baz,\n        bat\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      operator = \"\"\"\n      +assert foo,\n              bar\n      \"\"\"\n\n      assert_same operator, @short_length\n    end\n\n    test \"does not nest operand\" do\n      bad = \"not foo(bar, baz, bat)\"\n\n      good = \"\"\"\n      not foo(\n        bar,\n        baz,\n        bat\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      operator = \"\"\"\n      not assert foo,\n                 bar\n      \"\"\"\n\n      assert_same operator, @short_length\n    end\n\n    test \"inside do-end block\" do\n      assert_same \"\"\"\n      if +value do\n        true\n      end\n      \"\"\"\n    end\n  end\n\n  describe \"binary without space\" do\n    test \"formats without spaces\" do\n      assert_format \"1 .. 2\", \"1..2\"\n    end\n\n    test \"never breaks\" do\n      assert_same \"123_456_789..987_654_321\", @short_length\n    end\n  end\n\n  describe \"ternary without space\" do\n    test \"formats without spaces\" do\n      assert_format \"1 .. 2 // 3\", \"1..2//3\"\n      assert_same \"(1..2//3).step\"\n    end\n\n    test \"never breaks\" do\n      assert_same \"123_456_789..987_654_321//147_268_369\", @short_length\n    end\n  end\n\n  describe \"binary without newline\" do\n    test \"formats without spaces\" do\n      assert_same \"1 in 2\"\n      assert_format \"1\\\\\\\\2\", \"1 \\\\\\\\ 2\"\n    end\n\n    test \"never breaks\" do\n      assert_same \"123_456_789 in 987_654_321\", @short_length\n    end\n\n    test \"not in\" do\n      assert_format \"not(foo in bar)\", \"foo not in bar\"\n\n      assert_same \"foo not in bar\"\n      assert_same \"(not foo) in bar\"\n      assert_same \"(!foo) in bar\"\n    end\n\n    test \"bitwise precedence\" do\n      assert_format \"(crc >>> 8) ||| byte\", \"crc >>> 8 ||| byte\"\n      assert_same \"crc >>> (8 ||| byte)\"\n    end\n  end\n\n  describe \"binary operators with preceding new line\" do\n    test \"formats with spaces\" do\n      assert_format \"1|>2\", \"1 |> 2\"\n    end\n\n    test \"breaks into new line\" do\n      bad = \"123_456_789 |> 987_654_321\"\n\n      good = \"\"\"\n      123_456_789\n      |> 987_654_321\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"123 |> foo(bar, baz)\"\n\n      good = \"\"\"\n      123\n      |> foo(\n        bar,\n        baz\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"123 |> foo(bar) |> bar(bat)\"\n\n      good = \"\"\"\n      123\n      |> foo(\n        bar\n      )\n      |> bar(\n        bat\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"foo(bar, 123 |> bar(baz))\"\n\n      good = \"\"\"\n      foo(\n        bar,\n        123\n        |> bar(\n          baz\n        )\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"foo(bar, baz) |> 123\"\n\n      good = \"\"\"\n      foo(\n        bar,\n        baz\n      )\n      |> 123\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"foo(bar, baz) |> 123 |> 456\"\n\n      good = \"\"\"\n      foo(\n        bar,\n        baz\n      )\n      |> 123\n      |> 456\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"123 |> foo(bar, baz) |> 456\"\n\n      good = \"\"\"\n      123\n      |> foo(\n        bar,\n        baz\n      )\n      |> 456\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with multiple of the different entry and same precedence\" do\n      assert_same \"foo <~> bar ~> baz\"\n\n      bad = \"foo <~> bar ~> baz\"\n\n      good = \"\"\"\n      foo\n      <~> bar\n      ~> baz\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with multiple of the different entry, same precedence and right associative\" do\n      assert_format \"foo ++ bar ++ baz -- bat\", \"foo ++ bar ++ (baz -- bat)\"\n\n      assert_format \"foo +++ bar +++ baz --- bat\", \"foo +++ bar +++ (baz --- bat)\"\n    end\n\n    test \"preserves user choice even when it fits\" do\n      assert_same \"\"\"\n      foo\n      |> bar\n      \"\"\"\n\n      assert_same \"\"\"\n      foo =\n        one\n        |> two()\n        |> three()\n      \"\"\"\n\n      bad = \"\"\"\n      foo |>\n        bar\n      \"\"\"\n\n      good = \"\"\"\n      foo\n      |> bar\n      \"\"\"\n\n      assert_format bad, good\n    end\n  end\n\n  describe \"binary with following new line\" do\n    test \"formats with spaces\" do\n      assert_format \"1++2\", \"1 ++ 2\"\n\n      assert_format \"1+++2\", \"1 +++ 2\"\n    end\n\n    test \"breaks into new line\" do\n      bad = \"123_456_789 ++ 987_654_321\"\n\n      good = \"\"\"\n      123_456_789 ++\n        987_654_321\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"123 ++ foo(bar)\"\n\n      good = \"\"\"\n      123 ++\n        foo(bar)\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"123 ++ foo(bar, baz)\"\n\n      good = \"\"\"\n      123 ++\n        foo(\n          bar,\n          baz\n        )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"foo(bar, 123 ++ bar(baz))\"\n\n      good = \"\"\"\n      foo(\n        bar,\n        123 ++\n          bar(\n            baz\n          )\n      )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"foo(bar, baz) ++ 123\"\n\n      good = \"\"\"\n      foo(\n        bar,\n        baz\n      ) ++ 123\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with multiple of the same entry and left associative\" do\n      assert_same \"foo == bar == baz\"\n\n      bad = \"a == b == c\"\n\n      good = \"\"\"\n      a == b ==\n        c\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"(a == (b == c))\"\n\n      good = \"\"\"\n      a ==\n        (b == c)\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"foo == bar == baz\"\n\n      good = \"\"\"\n      foo == bar ==\n        baz\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"(foo == (bar == baz))\"\n\n      good = \"\"\"\n      foo ==\n        (bar ==\n           baz)\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with multiple of the same entry and right associative\" do\n      assert_same \"foo ++ bar ++ baz\"\n      assert_format \"foo -- bar -- baz\", \"foo -- (bar -- baz)\"\n      assert_same \"foo +++ bar +++ baz\"\n      assert_format \"foo --- bar --- baz\", \"foo --- (bar --- baz)\"\n\n      bad = \"a ++ b ++ c\"\n\n      good = \"\"\"\n      a ++\n        b ++ c\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"((a ++ b) ++ c)\"\n\n      good = \"\"\"\n      (a ++ b) ++\n        c\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"foo ++ bar ++ baz\"\n\n      good = \"\"\"\n      foo ++\n        bar ++\n        baz\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"((foo ++ bar) ++ baz)\"\n\n      good = \"\"\"\n      (foo ++\n         bar) ++\n        baz\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with precedence\" do\n      assert_format \"(a + b) == (c + d)\", \"a + b == c + d\"\n      assert_format \"a + (b == c) + d\", \"a + (b == c) + d\"\n\n      bad = \"(a + b) == (c + d)\"\n\n      good = \"\"\"\n      a + b ==\n        c + d\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"a * (b + c) * d\"\n\n      good = \"\"\"\n      a *\n        (b + c) *\n        d\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"(one + two) == (three + four)\"\n\n      good = \"\"\"\n      one + two ==\n        three + four\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n\n      bad = \"one * (two + three) * four\"\n\n      good = \"\"\"\n      one * (two + three) *\n        four\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n\n      bad = \"one * (two + three + four) * five\"\n\n      good = \"\"\"\n      one *\n        (two + three +\n           four) * five\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n\n      bad = \"var = one * (two + three + four) * five\"\n\n      good = \"\"\"\n      var =\n        one *\n          (two + three +\n             four) * five\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"with required parens\" do\n      assert_same \"(a |> b) ++ (c |> d)\"\n      assert_format \"a + b |> c + d\", \"(a + b) |> (c + d)\"\n      assert_format \"a ++ b |> c ++ d\", \"(a ++ b) |> (c ++ d)\"\n      assert_format \"a |> b ++ c |> d\", \"a |> (b ++ c) |> d\"\n    end\n\n    test \"with required parens skips on no parens\" do\n      assert_same \"1..2 |> 3..4\"\n    end\n\n    test \"with logical operators\" do\n      assert_same \"a or b or c\"\n      assert_format \"a or b and c\", \"a or (b and c)\"\n      assert_format \"a and b or c\", \"(a and b) or c\"\n    end\n\n    test \"mixed before and after lines\" do\n      bad = \"var :: a | b and c | d\"\n\n      good = \"\"\"\n      var ::\n        a\n        | b and\n            c\n        | d\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"var :: a | b and c + d + e + f | g\"\n\n      good = \"\"\"\n      var ::\n        a\n        | b and\n            c + d + e + f\n        | g\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n\n      assert_same \"\"\"\n      var ::\n        {\n          :one,\n          :two\n        }\n        | :three\n      \"\"\"\n    end\n\n    test \"preserves user choice even when it fits and left associative\" do\n      assert_same \"\"\"\n      foo + bar +\n        baz + bat\n      \"\"\"\n\n      assert_same \"\"\"\n      foo +\n        bar +\n        baz +\n        bat\n      \"\"\"\n    end\n\n    test \"preserves user choice even when it fits and right associative\" do\n      bad = \"\"\"\n      foo ++ bar ++\n        baz ++ bat\n      \"\"\"\n\n      assert_format bad, \"\"\"\n      foo ++\n        bar ++\n        baz ++ bat\n      \"\"\"\n\n      assert_same \"\"\"\n      foo ++\n        bar ++\n        baz ++\n        bat\n      \"\"\"\n    end\n  end\n\n  # Theoretically it fits under binary operators\n  # but the goal of this section is to test common idioms.\n  describe \"match\" do\n    test \"with calls\" do\n      bad = \"var = fun(one, two, three)\"\n\n      good = \"\"\"\n      var =\n        fun(\n          one,\n          two,\n          three\n        )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"fun(one, two, three) = var\"\n\n      good = \"\"\"\n      fun(\n        one,\n        two,\n        three\n      ) = var\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"fun(foo, bar) = fun(baz, bat)\"\n\n      good = \"\"\"\n      fun(\n        foo,\n        bar\n      ) =\n        fun(\n          baz,\n          bat\n        )\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"fun(foo, bar) = fun(baz, bat)\"\n\n      good = \"\"\"\n      fun(foo, bar) =\n        fun(baz, bat)\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"with containers\" do\n      bad = \"var = [one, two, three]\"\n\n      good = \"\"\"\n      var = [\n        one,\n        two,\n        three\n      ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"\"\"\n      var =\n        [one, two, three]\n      \"\"\"\n\n      good = \"\"\"\n      var =\n        [\n          one,\n          two,\n          three\n        ]\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"[one, two, three] = var\"\n\n      good = \"\"\"\n      [\n        one,\n        two,\n        three\n      ] = var\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      bad = \"[one, two, three] = foo(bar, baz)\"\n\n      good = \"\"\"\n      [one, two, three] =\n        foo(bar, baz)\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"with heredoc\" do\n      heredoc = ~S'''\n      var = \"\"\"\n      one\n      \"\"\"\n      '''\n\n      assert_same heredoc, @short_length\n\n      heredoc = ~S'''\n      var = \"\"\"\n      #{one}\n      \"\"\"\n      '''\n\n      assert_same heredoc, @short_length\n    end\n\n    test \"with anonymous functions\" do\n      bad = \"var = fn arg1 -> body1; arg2 -> body2 end\"\n\n      good = \"\"\"\n      var = fn\n        arg1 ->\n          body1\n\n        arg2 ->\n          body2\n      end\n      \"\"\"\n\n      assert_format bad, good, @short_length\n\n      good = \"\"\"\n      var = fn\n        arg1 -> body1\n        arg2 -> body2\n      end\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n\n    test \"with do-end blocks\" do\n      assert_same \"\"\"\n      var =\n        case true do\n          foo -> bar\n          baz -> bat\n        end\n      \"\"\"\n    end\n  end\n\n  describe \"module attributes\" do\n    test \"when reading\" do\n      assert_format \"@ my_attribute\", \"@my_attribute\"\n    end\n\n    test \"when setting\" do\n      assert_format \"@ my_attribute(:some_value)\", \"@my_attribute :some_value\"\n    end\n\n    test \"doesn't split when reading on line limit\" do\n      assert_same \"@my_long_attribute\", @short_length\n    end\n\n    test \"doesn't split when setting on line limit\" do\n      assert_same \"@my_long_attribute :some_value\", @short_length\n    end\n\n    test \"with do-end block\" do\n      assert_same \"\"\"\n      @attr (for x <- y do\n               z\n             end)\n      \"\"\"\n    end\n\n    test \"is parenthesized when setting inside a call\" do\n      assert_same \"my_fun(@foo(bar), baz)\"\n    end\n\n    test \"fall back to @ as an operator when needed\" do\n      assert_same \"@(1 + 1)\"\n      assert_same \"@:foo\"\n      assert_same \"+@foo\"\n      assert_same \"@@foo\"\n      assert_same \"@(+foo)\"\n      assert_same \"!(@(1 + 1))\"\n      assert_same \"(@Foo).Baz\"\n      assert_same \"@bar(1, 2)\"\n\n      assert_format \"@+1\", \"@(+1)\"\n      assert_format \"@Foo.Baz\", \"(@Foo).Baz\"\n      assert_format \"@(Foo.Bar).Baz\", \"(@(Foo.Bar)).Baz\"\n    end\n\n    test \"with next break fits\" do\n      attribute = ~S'''\n      @doc \"\"\"\n      foo\n      \"\"\"\n      '''\n\n      assert_same attribute\n\n      attribute = ~S'''\n      @doc foo: \"\"\"\n           bar\n           \"\"\"\n      '''\n\n      assert_same attribute\n    end\n\n    test \"without next break fits\" do\n      bad = \"@really_long_expr foo + bar\"\n\n      good = \"\"\"\n      @really_long_expr foo +\n                          bar\n      \"\"\"\n\n      assert_format bad, good, @short_length\n    end\n\n    test \"with do-end blocks\" do\n      attribute = \"\"\"\n      @doc do\n        :ok\n      end\n      \"\"\"\n\n      assert_same attribute, @short_length\n\n      attribute = \"\"\"\n      use (@doc do\n             :end\n           end)\n      \"\"\"\n\n      assert_same attribute, @short_length\n    end\n\n    test \"do not rewrite lists to keyword lists\" do\n      assert_same \"\"\"\n      @foo [\n        bar: baz\n      ]\n      \"\"\"\n    end\n  end\n\n  describe \"capture\" do\n    test \"with integers\" do\n      assert_same \"&1\"\n      assert_format \"&(&1)\", \"& &1\"\n      assert_format \"&(&1.foo)\", \"& &1.foo\"\n    end\n\n    test \"with operators inside\" do\n      assert_format \"& +1\", \"&(+1)\"\n      assert_format \"& 1[:foo]\", \"& 1[:foo]\"\n      assert_format \"& not &1\", \"&(not &1)\"\n      assert_format \"& a ++ b\", \"&(a ++ b)\"\n      assert_format \"& &1 && &2\", \"&(&1 && &2)\"\n      assert_same \"&(&1 | &2)\"\n    end\n\n    test \"with operators outside\" do\n      assert_same \"(& &1) == (& &2)\"\n      assert_same \"(& &1) and (& &2)\"\n      assert_same \"(&foo/1) and (&bar/1)\"\n      assert_same \"[(&IO.puts/1) | &IO.puts/2]\"\n    end\n\n    test \"with call expressions\" do\n      assert_format \"& local(&1, &2)\", \"&local(&1, &2)\"\n      assert_format \"&-local(&1, &2)\", \"&(-local(&1, &2))\"\n    end\n\n    test \"with blocks\" do\n      bad = \"&(1; 2)\"\n\n      good = \"\"\"\n      &(\n        1\n        2\n      )\n      \"\"\"\n\n      assert_format bad, good\n    end\n\n    test \"with no parens\" do\n      capture = \"\"\"\n      &assert foo,\n              bar\n      \"\"\"\n\n      assert_same capture, @short_length\n    end\n\n    test \"precedence when combined with calls\" do\n      assert_same \"(&Foo).Bar\"\n      assert_format \"&(Foo).Bar\", \"&Foo.Bar\"\n      assert_format \"&(Foo.Bar).Baz\", \"&Foo.Bar.Baz\"\n    end\n\n    test \"local/arity\" do\n      assert_format \"&(foo/1)\", \"&foo/1\"\n      assert_format \"&(foo/bar)\", \"&(foo / bar)\"\n    end\n\n    test \"operator/arity\" do\n      assert_same \"&+/2\"\n      assert_same \"&and/2\"\n      assert_same \"& &&/2\"\n      assert_same \"& &/1\"\n      assert_same \"&//2\"\n    end\n\n    test \"Module.remote/arity\" do\n      assert_format \"&(Mod.foo/1)\", \"&Mod.foo/1\"\n      assert_format \"&(Mod.++/1)\", \"&Mod.++/1\"\n      assert_format ~s[&(Mod.\"foo bar\"/1)], ~s[&Mod.\"foo bar\"/1]\n      assert_format ~S[&(Mod.\"foo\\nbar\"/1)], ~S[&Mod.\"foo\\nbar\"/1]\n\n      # Invalid\n      assert_format \"& Mod.foo/bar\", \"&(Mod.foo() / bar)\"\n\n      # This is \"invalid\" as a special form but we don't\n      # have enough knowledge to know that, so let's just\n      # make sure we format it properly with proper wrapping.\n      assert_same \"&(1 + 2).foo/1\"\n\n      assert_same \"&my_function.foo.bar/3\", @short_length\n    end\n  end\n\n  describe \"when\" do\n    test \"with keywords\" do\n      assert_same \"foo when bar: :baz\"\n    end\n\n    test \"with keywords on line breaks\" do\n      bad = \"foo when one: :two, three: :four\"\n\n      good = \"\"\"\n      foo\n      when one: :two,\n           three: :four\n      \"\"\"\n\n      assert_format bad, good, @medium_length\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_fragment_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule CodeFragmentTest do\n  use ExUnit.Case, async: true\n\n  doctest Code.Fragment\n  alias Code.Fragment, as: CF\n\n  describe \"cursor_context/2\" do\n    test \"expressions\" do\n      assert CF.cursor_context([]) == :expr\n      assert CF.cursor_context(\",\") == :expr\n      assert CF.cursor_context(\"[\") == :expr\n      assert CF.cursor_context(\"<<\") == :expr\n      assert CF.cursor_context(\"=>\") == :expr\n      assert CF.cursor_context(\"->\") == :expr\n      assert CF.cursor_context(\"foo(<<\") == :expr\n      assert CF.cursor_context(\"hello: \") == :expr\n      assert CF.cursor_context(\"\\n\") == :expr\n      assert CF.cursor_context(~c\"\\n\") == :expr\n      assert CF.cursor_context(\"\\n\\n\") == :expr\n      assert CF.cursor_context(~c\"\\n\\n\") == :expr\n      assert CF.cursor_context(\"\\r\\n\") == :expr\n      assert CF.cursor_context(~c\"\\r\\n\") == :expr\n      assert CF.cursor_context(\"\\r\\n\\r\\n\") == :expr\n      assert CF.cursor_context(~c\"\\r\\n\\r\\n\") == :expr\n    end\n\n    test \"local_or_var\" do\n      assert CF.cursor_context(\"hello_wo\") == {:local_or_var, ~c\"hello_wo\"}\n      assert CF.cursor_context(\"hello_world?\") == {:local_or_var, ~c\"hello_world?\"}\n      assert CF.cursor_context(\"hello_world!\") == {:local_or_var, ~c\"hello_world!\"}\n      assert CF.cursor_context(\"hello/wor\") == {:local_or_var, ~c\"wor\"}\n      assert CF.cursor_context(\"hello..wor\") == {:local_or_var, ~c\"wor\"}\n      assert CF.cursor_context(\"hello::wor\") == {:local_or_var, ~c\"wor\"}\n      assert CF.cursor_context(\"[hello_wo\") == {:local_or_var, ~c\"hello_wo\"}\n      assert CF.cursor_context(\"'hello_wo\") == {:local_or_var, ~c\"hello_wo\"}\n      assert CF.cursor_context(\"hellò_wó\") == {:local_or_var, ~c\"hellò_wó\"}\n      assert CF.cursor_context(\"hello? world\") == {:local_or_var, ~c\"world\"}\n      assert CF.cursor_context(\"hello! world\") == {:local_or_var, ~c\"world\"}\n      assert CF.cursor_context(\"hello: world\") == {:local_or_var, ~c\"world\"}\n      assert CF.cursor_context(\"__MODULE__\") == {:local_or_var, ~c\"__MODULE__\"}\n    end\n\n    test \"dot\" do\n      assert CF.cursor_context(\"hello.\") == {:dot, {:var, ~c\"hello\"}, ~c\"\"}\n      assert CF.cursor_context(\":hello.\") == {:dot, {:unquoted_atom, ~c\"hello\"}, ~c\"\"}\n      assert CF.cursor_context(\"nested.map.\") == {:dot, {:dot, {:var, ~c\"nested\"}, ~c\"map\"}, ~c\"\"}\n\n      assert CF.cursor_context(\"Hello.\") == {:dot, {:alias, ~c\"Hello\"}, ~c\"\"}\n      assert CF.cursor_context(\"Hello.World.\") == {:dot, {:alias, ~c\"Hello.World\"}, ~c\"\"}\n      assert CF.cursor_context(\"Hello.wor\") == {:dot, {:alias, ~c\"Hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"hello.wor\") == {:dot, {:var, ~c\"hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"Hello.++\") == {:dot, {:alias, ~c\"Hello\"}, ~c\"++\"}\n      assert CF.cursor_context(\":hello.wor\") == {:dot, {:unquoted_atom, ~c\"hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\":hell@o.wor\") == {:dot, {:unquoted_atom, ~c\"hell@o\"}, ~c\"wor\"}\n      assert CF.cursor_context(\":he@ll@o.wor\") == {:dot, {:unquoted_atom, ~c\"he@ll@o\"}, ~c\"wor\"}\n      assert CF.cursor_context(\":hell@@o.wor\") == {:dot, {:unquoted_atom, ~c\"hell@@o\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"@hello.wor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"@hello. wor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"@hello .wor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"@hello . wor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"@hello.\\nwor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"@hello. \\nwor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"@hello.\\n wor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"@hello.\\r\\nwor\") ==\n               {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"@hello\\n.wor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"@hello \\n.wor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n      assert CF.cursor_context(\"@hello\\n .wor\") == {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"@hello. # some comment\\nwor\") ==\n               {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"@hello. # some comment\\n\\nwor\") ==\n               {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"@hello. # some comment\\nsub\\n.wor\") ==\n               {:dot, {:dot, {:module_attribute, ~c\"hello\"}, ~c\"sub\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(~c\"@hello.\\nwor\") ==\n               {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(~c\"@hello.\\r\\nwor\") ==\n               {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(~c\"@hello\\n.wor\") ==\n               {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(~c\"@hello. # some comment\\nwor\") ==\n               {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(~c\"@hello. # some comment\\n\\nwor\") ==\n               {:dot, {:module_attribute, ~c\"hello\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(~c\"@hello. # some comment\\nsub\\n.wor\") ==\n               {:dot, {:dot, {:module_attribute, ~c\"hello\"}, ~c\"sub\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"nested.map.wor\") ==\n               {:dot, {:dot, {:var, ~c\"nested\"}, ~c\"map\"}, ~c\"wor\"}\n\n      assert CF.cursor_context(\"__MODULE__.\") == {:dot, {:var, ~c\"__MODULE__\"}, ~c\"\"}\n\n      assert CF.cursor_context(\"__MODULE__.Sub.\") ==\n               {:dot, {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Sub\"}, ~c\"\"}\n\n      assert CF.cursor_context(\"@hello.Sub.wor\") ==\n               {:dot, {:alias, {:module_attribute, ~c\"hello\"}, ~c\"Sub\"}, ~c\"wor\"}\n    end\n\n    test \"local_arity\" do\n      assert CF.cursor_context(\"hello/\") == {:local_arity, ~c\"hello\"}\n    end\n\n    test \"local_call\" do\n      assert CF.cursor_context(\"hello\\s\") == {:local_call, ~c\"hello\"}\n      assert CF.cursor_context(\"hello\\t\") == {:local_call, ~c\"hello\"}\n      assert CF.cursor_context(\"hello(\") == {:local_call, ~c\"hello\"}\n      assert CF.cursor_context(\"hello(\\s\") == {:local_call, ~c\"hello\"}\n      assert CF.cursor_context(\"hello(\\t\") == {:local_call, ~c\"hello\"}\n      assert CF.cursor_context(\"hello(\\n\") == {:local_call, ~c\"hello\"}\n      assert CF.cursor_context(\"hello(\\r\\n\") == {:local_call, ~c\"hello\"}\n    end\n\n    test \"dot_arity\" do\n      assert CF.cursor_context(\"Foo.hello/\") == {:dot_arity, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo.+/\") == {:dot_arity, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"Foo . hello /\") == {:dot_arity, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo . + /\") == {:dot_arity, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"foo.hello/\") == {:dot_arity, {:var, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\":foo.hello/\") ==\n               {:dot_arity, {:unquoted_atom, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\"@f.hello/\") == {:dot_arity, {:module_attribute, ~c\"f\"}, ~c\"hello\"}\n    end\n\n    test \"dot_call\" do\n      assert CF.cursor_context(\"Foo.hello\\s\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo.hello\\t\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo.hello(\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo.hello(\\s\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo.hello(\\t\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo . hello (\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo . hello (\\s\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"Foo . hello (\\t\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\":foo.hello\\s\") ==\n               {:dot_call, {:unquoted_atom, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\":foo.hello\\t\") ==\n               {:dot_call, {:unquoted_atom, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\":foo.hello(\") == {:dot_call, {:unquoted_atom, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\":foo.hello(\\s\") ==\n               {:dot_call, {:unquoted_atom, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\":foo.hello(\\t\") ==\n               {:dot_call, {:unquoted_atom, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\":foo.hello\\s\") ==\n               {:dot_call, {:unquoted_atom, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\"foo.hello\\s\") == {:dot_call, {:var, ~c\"foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"foo.hello\\t\") == {:dot_call, {:var, ~c\"foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"foo.hello(\") == {:dot_call, {:var, ~c\"foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"foo.hello(\\s\") == {:dot_call, {:var, ~c\"foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"foo.hello(\\t\") == {:dot_call, {:var, ~c\"foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"foo.hello(\\n\") == {:dot_call, {:var, ~c\"foo\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"foo.hello(\\r\\n\") == {:dot_call, {:var, ~c\"foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\"@f.hello\\s\") == {:dot_call, {:module_attribute, ~c\"f\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"@f.hello\\t\") == {:dot_call, {:module_attribute, ~c\"f\"}, ~c\"hello\"}\n      assert CF.cursor_context(\"@f.hello(\") == {:dot_call, {:module_attribute, ~c\"f\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\"@f.hello(\\s\") ==\n               {:dot_call, {:module_attribute, ~c\"f\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\"@f.hello(\\t\") ==\n               {:dot_call, {:module_attribute, ~c\"f\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\"Foo.+\\s\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"Foo.+\\t\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"Foo.+(\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"Foo.+(\\s\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"Foo.+(\\t\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"Foo . + (\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"Foo . + (\\s\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"+\"}\n      assert CF.cursor_context(\"Foo . + (\\t\") == {:dot_call, {:alias, ~c\"Foo\"}, ~c\"+\"}\n\n      assert CF.cursor_context(\"__MODULE__.Foo.hello(\") ==\n               {:dot_call, {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Foo\"}, ~c\"hello\"}\n\n      assert CF.cursor_context(\"@foo.Foo.hello(\") ==\n               {:dot_call, {:alias, {:module_attribute, ~c\"foo\"}, ~c\"Foo\"}, ~c\"hello\"}\n    end\n\n    test \"anonymous_call\" do\n      assert CF.cursor_context(\"hello.(\") == {:anonymous_call, {:var, ~c\"hello\"}}\n      assert CF.cursor_context(\"hello.(\\s\") == {:anonymous_call, {:var, ~c\"hello\"}}\n      assert CF.cursor_context(\"hello.(\\t\") == {:anonymous_call, {:var, ~c\"hello\"}}\n      assert CF.cursor_context(\"hello.(\\n\") == {:anonymous_call, {:var, ~c\"hello\"}}\n      assert CF.cursor_context(\"hello.(\\r\\n\") == {:anonymous_call, {:var, ~c\"hello\"}}\n\n      assert CF.cursor_context(\"hello . (\") == {:anonymous_call, {:var, ~c\"hello\"}}\n\n      assert CF.cursor_context(\"@hello.(\") == {:anonymous_call, {:module_attribute, ~c\"hello\"}}\n      assert CF.cursor_context(\"@hello . (\") == {:anonymous_call, {:module_attribute, ~c\"hello\"}}\n    end\n\n    test \"nested expressions\" do\n      assert CF.cursor_context(\"Hello.world()\") == :none\n      assert CF.cursor_context(\"hello().\") == {:dot, :expr, ~c\"\"}\n      assert CF.cursor_context(\"Foo.hello ('(').\") == {:dot, :expr, ~c\"\"}\n      assert CF.cursor_context(\"Foo.hello('(', ?), ?().bar\") == {:dot, :expr, ~c\"bar\"}\n      assert CF.cursor_context(\"Hello.bar(World.call(42), ?), ?().foo\") == {:dot, :expr, ~c\"foo\"}\n      assert CF.cursor_context(\"Foo.hello( ).world\") == {:dot, :expr, ~c\"world\"}\n      assert CF.cursor_context(\"hello.dyn_impl().call(42).bar\") == {:dot, :expr, ~c\"bar\"}\n\n      assert CF.cursor_context(\"Foo.dyn_impl().call(\") == {:dot_call, :expr, ~c\"call\"}\n      assert CF.cursor_context(\"hello().call(\") == {:dot_call, :expr, ~c\"call\"}\n    end\n\n    test \"alias\" do\n      assert CF.cursor_context(\"HelloWor\") == {:alias, ~c\"HelloWor\"}\n      assert CF.cursor_context(\"Hello.Wor\") == {:alias, ~c\"Hello.Wor\"}\n      assert CF.cursor_context(\"Hello.\\nWor\") == {:alias, ~c\"Hello.Wor\"}\n      assert CF.cursor_context(\"Hello.\\r\\nWor\") == {:alias, ~c\"Hello.Wor\"}\n      assert CF.cursor_context(\"Hello . Wor\") == {:alias, ~c\"Hello.Wor\"}\n      assert CF.cursor_context(\"Hello::Wor\") == {:alias, ~c\"Wor\"}\n      assert CF.cursor_context(\"Hello..Wor\") == {:alias, ~c\"Wor\"}\n\n      assert CF.cursor_context(\"hello.World\") ==\n               {:alias, {:local_or_var, ~c\"hello\"}, ~c\"World\"}\n\n      assert CF.cursor_context(\"__MODULE__.Wor\") ==\n               {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Wor\"}\n\n      assert CF.cursor_context(\"@foo.Wor\") == {:alias, {:module_attribute, ~c\"foo\"}, ~c\"Wor\"}\n    end\n\n    test \"structs\" do\n      assert CF.cursor_context(\"%\") == {:struct, ~c\"\"}\n      assert CF.cursor_context(\":%\") == {:unquoted_atom, ~c\"%\"}\n      assert CF.cursor_context(\"::%\") == {:struct, ~c\"\"}\n\n      assert CF.cursor_context(\"%HelloWor\") == {:struct, ~c\"HelloWor\"}\n\n      assert CF.cursor_context(\"%Hello.\") == {:struct, {:dot, {:alias, ~c\"Hello\"}, ~c\"\"}}\n      assert CF.cursor_context(\"%Hello.nam\") == {:struct, {:dot, {:alias, ~c\"Hello\"}, ~c\"nam\"}}\n      assert CF.cursor_context(\"%Hello.Wor\") == {:struct, ~c\"Hello.Wor\"}\n      assert CF.cursor_context(\"% Hello . Wor\") == {:struct, ~c\"Hello.Wor\"}\n\n      assert CF.cursor_context(\"%__MODULE_\") == {:struct, {:local_or_var, ~c\"__MODULE_\"}}\n      assert CF.cursor_context(\"%__MODULE__\") == {:struct, {:local_or_var, ~c\"__MODULE__\"}}\n\n      assert CF.cursor_context(\"%__MODULE__.\") ==\n               {:struct, {:dot, {:local_or_var, ~c\"__MODULE__\"}, ~c\"\"}}\n\n      assert CF.cursor_context(\"%__MODULE__.Sub.\") ==\n               {:struct, {:dot, {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Sub\"}, ~c\"\"}}\n\n      assert CF.cursor_context(\"%__MODULE__.Wor\") ==\n               {:struct, {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Wor\"}}\n\n      assert CF.cursor_context(\"%@foo\") ==\n               {:struct, {:module_attribute, ~c\"foo\"}}\n\n      assert CF.cursor_context(\"%@foo.\") ==\n               {:struct, {:dot, {:module_attribute, ~c\"foo\"}, ~c\"\"}}\n\n      assert CF.cursor_context(\"%@foo.Wor\") ==\n               {:struct, {:alias, {:module_attribute, ~c\"foo\"}, ~c\"Wor\"}}\n    end\n\n    test \"unquoted atom\" do\n      assert CF.cursor_context(\":\") == {:unquoted_atom, ~c\"\"}\n      assert CF.cursor_context(\":HelloWor\") == {:unquoted_atom, ~c\"HelloWor\"}\n      assert CF.cursor_context(\":HelloWór\") == {:unquoted_atom, ~c\"HelloWór\"}\n      assert CF.cursor_context(\":hello_wor\") == {:unquoted_atom, ~c\"hello_wor\"}\n      assert CF.cursor_context(\":Óla_mundo\") == {:unquoted_atom, ~c\"Óla_mundo\"}\n      assert CF.cursor_context(\":Ol@_mundo\") == {:unquoted_atom, ~c\"Ol@_mundo\"}\n      assert CF.cursor_context(\":Ol@\") == {:unquoted_atom, ~c\"Ol@\"}\n      assert CF.cursor_context(\"foo:hello_wor\") == {:unquoted_atom, ~c\"hello_wor\"}\n\n      # Operators from atoms\n      assert CF.cursor_context(\":+\") == {:unquoted_atom, ~c\"+\"}\n      assert CF.cursor_context(\":or\") == {:unquoted_atom, ~c\"or\"}\n      assert CF.cursor_context(\":<\") == {:unquoted_atom, ~c\"<\"}\n      assert CF.cursor_context(\":.\") == {:unquoted_atom, ~c\".\"}\n      assert CF.cursor_context(\":..\") == {:unquoted_atom, ~c\"..\"}\n      assert CF.cursor_context(\":->\") == {:unquoted_atom, ~c\"->\"}\n      assert CF.cursor_context(\":%\") == {:unquoted_atom, ~c\"%\"}\n    end\n\n    test \"operators\" do\n      assert CF.cursor_context(\"/\") == {:operator, ~c\"/\"}\n      assert CF.cursor_context(\"+\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"++\") == {:operator, ~c\"++\"}\n      assert CF.cursor_context(\"!\") == {:operator, ~c\"!\"}\n      assert CF.cursor_context(\"<\") == {:operator, ~c\"<\"}\n      assert CF.cursor_context(\"<<<\") == {:operator, ~c\"<<<\"}\n      assert CF.cursor_context(\"..\") == {:operator, ~c\"..\"}\n      assert CF.cursor_context(\"<~\") == {:operator, ~c\"<~\"}\n      assert CF.cursor_context(\"=~\") == {:operator, ~c\"=~\"}\n      assert CF.cursor_context(\"<~>\") == {:operator, ~c\"<~>\"}\n      assert CF.cursor_context(\"::\") == {:operator, ~c\"::\"}\n\n      assert CF.cursor_context(\"+ \") == {:operator_call, ~c\"+\"}\n      assert CF.cursor_context(\"++ \") == {:operator_call, ~c\"++\"}\n      assert CF.cursor_context(\"! \") == {:operator_call, ~c\"!\"}\n      assert CF.cursor_context(\"< \") == {:operator_call, ~c\"<\"}\n      assert CF.cursor_context(\"<<< \") == {:operator_call, ~c\"<<<\"}\n      assert CF.cursor_context(\".. \") == {:operator_call, ~c\"..\"}\n      assert CF.cursor_context(\"<~ \") == {:operator_call, ~c\"<~\"}\n      assert CF.cursor_context(\"=~ \") == {:operator_call, ~c\"=~\"}\n      assert CF.cursor_context(\"<~> \") == {:operator_call, ~c\"<~>\"}\n      assert CF.cursor_context(\":: \") == {:operator_call, ~c\"::\"}\n\n      assert CF.cursor_context(\"...(\") == {:operator_call, ~c\"...\"}\n      assert CF.cursor_context(\"...(\\s\") == {:operator_call, ~c\"...\"}\n      assert CF.cursor_context(\"+(\") == {:operator_call, ~c\"+\"}\n      assert CF.cursor_context(\"++(\\s\") == {:operator_call, ~c\"++\"}\n\n      assert CF.cursor_context(\"+/\") == {:operator_arity, ~c\"+\"}\n      assert CF.cursor_context(\"++/\") == {:operator_arity, ~c\"++\"}\n      assert CF.cursor_context(\"!/\") == {:operator_arity, ~c\"!\"}\n      assert CF.cursor_context(\"</\") == {:operator_arity, ~c\"<\"}\n      assert CF.cursor_context(\"<<</\") == {:operator_arity, ~c\"<<<\"}\n      assert CF.cursor_context(\"../\") == {:operator_arity, ~c\"..\"}\n      assert CF.cursor_context(\"<~/\") == {:operator_arity, ~c\"<~\"}\n      assert CF.cursor_context(\"=~/\") == {:operator_arity, ~c\"=~\"}\n      assert CF.cursor_context(\"<~>/\") == {:operator_arity, ~c\"<~>\"}\n      assert CF.cursor_context(\"::/\") == {:operator_arity, ~c\"::\"}\n\n      # Unknown operators altogether\n      assert CF.cursor_context(\"***\") == :none\n\n      # Textual operators are shown as local_or_var UNLESS there is space\n      assert CF.cursor_context(\"when\") == {:local_or_var, ~c\"when\"}\n      assert CF.cursor_context(\"when \") == {:operator_call, ~c\"when\"}\n      assert CF.cursor_context(\"when.\") == :none\n\n      assert CF.cursor_context(\"not\") == {:local_or_var, ~c\"not\"}\n      assert CF.cursor_context(\"not \") == {:operator_call, ~c\"not\"}\n      assert CF.cursor_context(\"not.\") == :none\n    end\n\n    test \"sigil\" do\n      assert CF.cursor_context(\"~\") == {:sigil, ~c\"\"}\n      assert CF.cursor_context(\"~ \") == :none\n\n      assert CF.cursor_context(\"~r\") == {:sigil, ~c\"r\"}\n      assert CF.cursor_context(\"~r/\") == :none\n      assert CF.cursor_context(\"~r<\") == :none\n\n      assert CF.cursor_context(\"~r''\") == :none\n      assert CF.cursor_context(\"~r' '\") == :none\n      assert CF.cursor_context(\"~r'foo'\") == :none\n\n      # The slash is used in sigils, arities, and operators, so there is ambiguity\n      assert CF.cursor_context(\"~r//\") == {:operator, ~c\"/\"}\n      assert CF.cursor_context(\"~r/ /\") == {:operator, ~c\"/\"}\n      assert CF.cursor_context(\"~r/foo/\") == {:local_arity, ~c\"foo\"}\n\n      assert CF.cursor_context(\"~R\") == {:sigil, ~c\"R\"}\n      assert CF.cursor_context(\"~R/\") == :none\n      assert CF.cursor_context(\"~R<\") == :none\n\n      assert CF.cursor_context(\"Foo.~\") == :none\n      assert CF.cursor_context(\"Foo.~ \") == :none\n    end\n\n    test \"module attribute\" do\n      assert CF.cursor_context(\"@\") == {:module_attribute, ~c\"\"}\n      assert CF.cursor_context(\"@hello_wo\") == {:module_attribute, ~c\"hello_wo\"}\n    end\n\n    test \"keyword or binary operator\" do\n      # Literals\n      assert CF.cursor_context(\"Foo.Bar \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"Foo \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\":foo \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"123 \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"nil \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"true \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"false \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"\\\"foo\\\" \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"'foo' \") == {:block_keyword_or_binary_operator, ~c\"\"}\n\n      # Containers\n      assert CF.cursor_context(\"(foo) \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"[foo] \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"{foo} \") == {:block_keyword_or_binary_operator, ~c\"\"}\n      assert CF.cursor_context(\"<<foo>> \") == {:block_keyword_or_binary_operator, ~c\"\"}\n\n      # False positives\n      assert CF.cursor_context(\"foo ~>> \") == {:operator_call, ~c\"~>>\"}\n      assert CF.cursor_context(\"foo >>> \") == {:operator_call, ~c\">>>\"}\n    end\n\n    test \"keyword from keyword or binary operator\" do\n      # Literals\n      assert CF.cursor_context(\"Foo.Bar do\") == {:block_keyword_or_binary_operator, ~c\"do\"}\n      assert CF.cursor_context(\"Foo.Bar d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"Foo d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\":foo d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"123 d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"nil d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"true d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"false d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"\\\"foo\\\" d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"'foo' d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n\n      # Containers\n      assert CF.cursor_context(\"(foo) d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"[foo] d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"{foo} d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n      assert CF.cursor_context(\"<<foo>> d\") == {:block_keyword_or_binary_operator, ~c\"d\"}\n\n      # False positives\n      assert CF.cursor_context(\"foo ~>> d\") == {:local_or_var, ~c\"d\"}\n      assert CF.cursor_context(\"foo >>> d\") == {:local_or_var, ~c\"d\"}\n    end\n\n    test \"operator from keyword or binary operator\" do\n      # Literals\n      assert CF.cursor_context(\"Foo.Bar +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"Foo +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\":foo +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"123 +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"nil +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"true +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"false +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"\\\"foo\\\" +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"'foo' +\") == {:operator, ~c\"+\"}\n\n      # Containers\n      assert CF.cursor_context(\"(foo) +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"[foo] +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"{foo} +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"<<foo>> +\") == {:operator, ~c\"+\"}\n\n      # False positives\n      assert CF.cursor_context(\"foo ~>> +\") == {:operator, ~c\"+\"}\n      assert CF.cursor_context(\"foo >>> +\") == {:operator, ~c\"+\"}\n    end\n\n    test \"none\" do\n      # Punctuation\n      assert CF.cursor_context(\")\") == :none\n      assert CF.cursor_context(\"}\") == :none\n      assert CF.cursor_context(\">>\") == :none\n      assert CF.cursor_context(\"'\") == :none\n      assert CF.cursor_context(\"\\\"\") == :none\n\n      # Numbers\n      assert CF.cursor_context(\"123\") == :none\n      assert CF.cursor_context(\"123?\") == :none\n      assert CF.cursor_context(\"123!\") == :none\n      assert CF.cursor_context(\"123var?\") == :none\n      assert CF.cursor_context(\"0x\") == :none\n\n      # Codepoints\n      assert CF.cursor_context(\"?\") == :none\n      assert CF.cursor_context(\"?a\") == :none\n      assert CF.cursor_context(\"?foo\") == :none\n\n      # Dots\n      assert CF.cursor_context(\".\") == :none\n      assert CF.cursor_context(\"Mundo.Óla\") == :none\n      assert CF.cursor_context(\":hello.World\") == :none\n\n      # Aliases\n      assert CF.cursor_context(\"Hello::Wór\") == :none\n      assert CF.cursor_context(\"ÓlaMundo\") == :none\n      assert CF.cursor_context(\"HelloWór\") == :none\n      assert CF.cursor_context(\"@Hello\") == :none\n      assert CF.cursor_context(\"Hello(\") == :none\n\n      # Identifier\n      assert CF.cursor_context(\"foo@bar\") == :none\n      assert CF.cursor_context(\"@foo@bar\") == :none\n    end\n\n    test \"newlines\" do\n      assert CF.cursor_context(\"this+does-not*matter\\nHello.\") ==\n               {:dot, {:alias, ~c\"Hello\"}, ~c\"\"}\n\n      assert CF.cursor_context(~c\"this+does-not*matter\\nHello.\") ==\n               {:dot, {:alias, ~c\"Hello\"}, ~c\"\"}\n\n      assert CF.cursor_context(\"this+does-not*matter\\r\\nHello.\") ==\n               {:dot, {:alias, ~c\"Hello\"}, ~c\"\"}\n\n      assert CF.cursor_context(~c\"this+does-not*matter\\r\\nHello.\") ==\n               {:dot, {:alias, ~c\"Hello\"}, ~c\"\"}\n    end\n  end\n\n  describe \"surround_context/2\" do\n    test \"newlines\" do\n      for i <- 1..8 do\n        assert CF.surround_context(\"\\n\\nhello_wo\\n\", {3, i}) == %{\n                 context: {:local_or_var, ~c\"hello_wo\"},\n                 begin: {3, 1},\n                 end: {3, 9}\n               }\n\n        assert CF.surround_context(\"\\r\\n\\r\\nhello_wo\\r\\n\", {3, i}) == %{\n                 context: {:local_or_var, ~c\"hello_wo\"},\n                 begin: {3, 1},\n                 end: {3, 9}\n               }\n\n        assert CF.surround_context(~c\"\\r\\n\\r\\nhello_wo\\r\\n\", {3, i}) == %{\n                 context: {:local_or_var, ~c\"hello_wo\"},\n                 begin: {3, 1},\n                 end: {3, 9}\n               }\n      end\n    end\n\n    test \"column out of range\" do\n      assert CF.surround_context(\"hello\", {1, 20}) == :none\n    end\n\n    test \"local_or_var\" do\n      for i <- 1..8 do\n        assert CF.surround_context(\"hello_wo\", {1, i}) == %{\n                 context: {:local_or_var, ~c\"hello_wo\"},\n                 begin: {1, 1},\n                 end: {1, 9}\n               }\n      end\n\n      assert CF.surround_context(\"hello_wo\", {1, 9}) == :none\n\n      for i <- 2..9 do\n        assert CF.surround_context(\" hello_wo\", {1, i}) == %{\n                 context: {:local_or_var, ~c\"hello_wo\"},\n                 begin: {1, 2},\n                 end: {1, 10}\n               }\n      end\n\n      assert CF.surround_context(\" hello_wo\", {1, 10}) == :none\n\n      for i <- 1..6 do\n        assert CF.surround_context(\"hello!\", {1, i}) == %{\n                 context: {:local_or_var, ~c\"hello!\"},\n                 begin: {1, 1},\n                 end: {1, 7}\n               }\n      end\n\n      assert CF.surround_context(\"hello!\", {1, 7}) == :none\n\n      for i <- 1..5 do\n        assert CF.surround_context(\"안녕_세상\", {1, i}) == %{\n                 context: {:local_or_var, ~c\"안녕_세상\"},\n                 begin: {1, 1},\n                 end: {1, 6}\n               }\n      end\n\n      assert CF.surround_context(\"안녕_세상\", {1, 6}) == :none\n\n      # Keywords are not local or var\n      for keyword <- ~w(do end after catch else rescue fn true false nil)c,\n          length = length(keyword),\n          i <- 1..length do\n        assert CF.surround_context(keyword, {1, i}) == %{\n                 context: {:keyword, keyword},\n                 begin: {1, 1},\n                 end: {1, length + 1}\n               }\n\n        assert CF.surround_context(~c\"Foo \" ++ keyword, {1, 4 + i}) == %{\n                 context: {:keyword, keyword},\n                 begin: {1, 5},\n                 end: {1, length + 5}\n               }\n      end\n    end\n\n    test \"local call\" do\n      for i <- 1..8 do\n        assert CF.surround_context(\"hello_wo(\", {1, i}) == %{\n                 context: {:local_call, ~c\"hello_wo\"},\n                 begin: {1, 1},\n                 end: {1, 9}\n               }\n      end\n\n      assert CF.surround_context(\"hello_wo(\", {1, 9}) == :none\n\n      for i <- 1..8 do\n        assert CF.surround_context(\"hello_wo (\", {1, i}) == %{\n                 context: {:local_call, ~c\"hello_wo\"},\n                 begin: {1, 1},\n                 end: {1, 9}\n               }\n      end\n\n      assert CF.surround_context(\"hello_wo (\", {1, 9}) == :none\n\n      for i <- 1..6 do\n        assert CF.surround_context(\"hello!(\", {1, i}) == %{\n                 context: {:local_call, ~c\"hello!\"},\n                 begin: {1, 1},\n                 end: {1, 7}\n               }\n      end\n\n      assert CF.surround_context(\"hello!(\", {1, 7}) == :none\n\n      for i <- 1..5 do\n        assert CF.surround_context(\"안녕_세상(\", {1, i}) == %{\n                 context: {:local_call, ~c\"안녕_세상\"},\n                 begin: {1, 1},\n                 end: {1, 6}\n               }\n      end\n\n      assert CF.surround_context(\"안녕_세상(\", {1, 6}) == :none\n    end\n\n    test \"local arity\" do\n      for i <- 1..8 do\n        assert CF.surround_context(\"hello_wo/\", {1, i}) == %{\n                 context: {:local_arity, ~c\"hello_wo\"},\n                 begin: {1, 1},\n                 end: {1, 9}\n               }\n      end\n\n      assert CF.surround_context(\"hello_wo/\", {1, 9}) == :none\n\n      for i <- 1..8 do\n        assert CF.surround_context(\"hello_wo /\", {1, i}) == %{\n                 context: {:local_arity, ~c\"hello_wo\"},\n                 begin: {1, 1},\n                 end: {1, 9}\n               }\n      end\n\n      assert CF.surround_context(\"hello_wo /\", {1, 9}) == :none\n\n      for i <- 1..6 do\n        assert CF.surround_context(\"hello!/\", {1, i}) == %{\n                 context: {:local_arity, ~c\"hello!\"},\n                 begin: {1, 1},\n                 end: {1, 7}\n               }\n      end\n\n      assert CF.surround_context(\"hello!/\", {1, 7}) == :none\n\n      for i <- 1..5 do\n        assert CF.surround_context(\"안녕_세상/\", {1, i}) == %{\n                 context: {:local_arity, ~c\"안녕_세상\"},\n                 begin: {1, 1},\n                 end: {1, 6}\n               }\n      end\n\n      assert CF.surround_context(\"안녕_세상/\", {1, 6}) == :none\n    end\n\n    test \"textual operators\" do\n      for op <- ~w(when not or and in), i <- 1..byte_size(op) do\n        assert CF.surround_context(\"#{op}\", {1, i}) == %{\n                 context: {:operator, String.to_charlist(op)},\n                 begin: {1, 1},\n                 end: {1, byte_size(op) + 1}\n               }\n\n        assert CF.surround_context(\"Foo #{op}\", {1, 4 + i}) == %{\n                 context: {:operator, String.to_charlist(op)},\n                 begin: {1, 5},\n                 end: {1, byte_size(op) + 5}\n               }\n      end\n    end\n\n    test \"dot\" do\n      for i <- 1..5 do\n        assert CF.surround_context(\"Hello.wor\", {1, i}) == %{\n                 context: {:alias, ~c\"Hello\"},\n                 begin: {1, 1},\n                 end: {1, 6}\n               }\n      end\n\n      for i <- 6..9 do\n        assert CF.surround_context(\"Hello.wor\", {1, i}) == %{\n                 context: {:dot, {:alias, ~c\"Hello\"}, ~c\"wor\"},\n                 begin: {1, 1},\n                 end: {1, 10}\n               }\n      end\n\n      assert CF.surround_context(\"Hello.\", {1, 6}) == :none\n\n      for i <- 1..5 do\n        assert CF.surround_context(\"Hello . wor\", {1, i}) == %{\n                 context: {:alias, ~c\"Hello\"},\n                 begin: {1, 1},\n                 end: {1, 6}\n               }\n      end\n\n      for i <- 6..11 do\n        assert CF.surround_context(\"Hello . wor\", {1, i}) == %{\n                 context: {:dot, {:alias, ~c\"Hello\"}, ~c\"wor\"},\n                 begin: {1, 1},\n                 end: {1, 12}\n               }\n      end\n\n      assert CF.surround_context(\"Hello .\", {1, 6}) == :none\n\n      for i <- 1..5 do\n        assert CF.surround_context(\"hello.wor\", {1, i}) == %{\n                 context: {:local_or_var, ~c\"hello\"},\n                 begin: {1, 1},\n                 end: {1, 6}\n               }\n      end\n\n      for i <- 6..9 do\n        assert CF.surround_context(\"hello.wor\", {1, i}) == %{\n                 context: {:dot, {:var, ~c\"hello\"}, ~c\"wor\"},\n                 begin: {1, 1},\n                 end: {1, 10}\n               }\n      end\n\n      assert CF.surround_context(\"hello # comment\\n  .wor\", {2, 4}) == %{\n               context: {:dot, {:var, ~c\"hello\"}, ~c\"wor\"},\n               begin: {1, 1},\n               end: {2, 7}\n             }\n\n      assert CF.surround_context(\"123 + hello. # comment\\n\\n  wor\", {3, 4}) == %{\n               context: {:dot, {:var, ~c\"hello\"}, ~c\"wor\"},\n               begin: {1, 7},\n               end: {3, 6}\n             }\n\n      assert CF.surround_context(\"hello. # comment\\n\\n # wor\", {3, 5}) == %{\n               context: {:local_or_var, ~c\"wor\"},\n               begin: {3, 4},\n               end: {3, 7}\n             }\n    end\n\n    test \"alias\" do\n      for i <- 1..8 do\n        assert CF.surround_context(\"HelloWor\", {1, i}) == %{\n                 context: {:alias, ~c\"HelloWor\"},\n                 begin: {1, 1},\n                 end: {1, 9}\n               }\n      end\n\n      assert CF.surround_context(\"HelloWor\", {1, 9}) == :none\n\n      for i <- 2..9 do\n        assert CF.surround_context(\" HelloWor\", {1, i}) == %{\n                 context: {:alias, ~c\"HelloWor\"},\n                 begin: {1, 2},\n                 end: {1, 10}\n               }\n      end\n\n      assert CF.surround_context(\" HelloWor\", {1, 10}) == :none\n\n      for i <- 1..9 do\n        assert CF.surround_context(\"Hello.Wor\", {1, i}) == %{\n                 context: {:alias, ~c\"Hello.Wor\"},\n                 begin: {1, 1},\n                 end: {1, 10}\n               }\n      end\n\n      assert CF.surround_context(\"Hello.Wor\", {1, 10}) == :none\n\n      for i <- 1..11 do\n        assert CF.surround_context(\"Hello . Wor\", {1, i}) == %{\n                 context: {:alias, ~c\"Hello.Wor\"},\n                 begin: {1, 1},\n                 end: {1, 12}\n               }\n      end\n\n      assert CF.surround_context(\"Hello . Wor\", {1, 12}) == :none\n\n      for i <- 1..15 do\n        assert CF.surround_context(\"Foo . Bar . Baz\", {1, i}) == %{\n                 context: {:alias, ~c\"Foo.Bar.Baz\"},\n                 begin: {1, 1},\n                 end: {1, 16}\n               }\n      end\n\n      for i <- 1..3 do\n        assert CF.surround_context(\"Foo # dc\\n. Bar .\\n Baz\", {i, 1}) == %{\n                 context: {:alias, ~c\"Foo.Bar.Baz\"},\n                 begin: {1, 1},\n                 end: {3, 5}\n               }\n      end\n\n      for i <- 1..11 do\n        assert CF.surround_context(\"Foo.Bar.Baz.foo(bar)\", {1, i}) == %{\n                 context: {:alias, ~c\"Foo.Bar.Baz\"},\n                 begin: {1, 1},\n                 end: {1, 12}\n               }\n      end\n    end\n\n    test \"underscored special forms\" do\n      assert CF.surround_context(\"__MODULE__\", {1, 1}) == %{\n               context: {:local_or_var, ~c\"__MODULE__\"},\n               begin: {1, 1},\n               end: {1, 11}\n             }\n\n      for i <- 1..14 do\n        assert CF.surround_context(\"__MODULE__.Foo\", {1, i}) == %{\n                 context: {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Foo\"},\n                 begin: {1, 1},\n                 end: {1, 15}\n               }\n      end\n\n      for i <- 1..18 do\n        assert CF.surround_context(\"__MODULE__.Foo.Sub\", {1, i}) == %{\n                 context: {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Foo.Sub\"},\n                 begin: {1, 1},\n                 end: {1, 19}\n               }\n      end\n\n      assert CF.surround_context(\"%__MODULE__{}\", {1, 5}) == %{\n               context: {:struct, {:local_or_var, ~c\"__MODULE__\"}},\n               begin: {1, 1},\n               end: {1, 12}\n             }\n\n      assert CF.surround_context(\"%__MODULE__.Foo{}\", {1, 13}) == %{\n               context: {:struct, {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Foo\"}},\n               begin: {1, 1},\n               end: {1, 16}\n             }\n\n      assert CF.surround_context(\"%__MODULE__.Foo.Sub{}\", {1, 17}) == %{\n               context: {:struct, {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Foo.Sub\"}},\n               begin: {1, 1},\n               end: {1, 20}\n             }\n\n      assert CF.surround_context(\"__MODULE__.call()\", {1, 13}) == %{\n               context: {:dot, {:var, ~c\"__MODULE__\"}, ~c\"call\"},\n               begin: {1, 1},\n               end: {1, 16}\n             }\n\n      assert CF.surround_context(\"__MODULE__.Foo.call()\", {1, 17}) == %{\n               context: {:dot, {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Foo\"}, ~c\"call\"},\n               begin: {1, 1},\n               end: {1, 20}\n             }\n\n      assert CF.surround_context(\"__MODULE__.Foo.Sub.call()\", {1, 21}) == %{\n               context: {:dot, {:alias, {:local_or_var, ~c\"__MODULE__\"}, ~c\"Foo.Sub\"}, ~c\"call\"},\n               begin: {1, 1},\n               end: {1, 24}\n             }\n\n      assert CF.surround_context(\"__ENV__.module.call()\", {1, 17}) == %{\n               context: {:dot, {:dot, {:var, ~c\"__ENV__\"}, ~c\"module\"}, ~c\"call\"},\n               begin: {1, 1},\n               end: {1, 20}\n             }\n    end\n\n    test \"attribute submodules\" do\n      for i <- 1..9 do\n        assert CF.surround_context(\"@some.Foo\", {1, i}) == %{\n                 context: {:alias, {:module_attribute, ~c\"some\"}, ~c\"Foo\"},\n                 begin: {1, 1},\n                 end: {1, 10}\n               }\n      end\n\n      for i <- 1..13 do\n        assert CF.surround_context(\"@some.Foo.Sub\", {1, i}) == %{\n                 context: {:alias, {:module_attribute, ~c\"some\"}, ~c\"Foo.Sub\"},\n                 begin: {1, 1},\n                 end: {1, 14}\n               }\n      end\n\n      assert CF.surround_context(\"%@some{}\", {1, 5}) == %{\n               context: {:struct, {:module_attribute, ~c\"some\"}},\n               begin: {1, 1},\n               end: {1, 7}\n             }\n\n      assert CF.surround_context(\"%@some.Foo{}\", {1, 10}) == %{\n               context: {:struct, {:alias, {:module_attribute, ~c\"some\"}, ~c\"Foo\"}},\n               begin: {1, 1},\n               end: {1, 11}\n             }\n\n      assert CF.surround_context(\"%@some.Foo.Sub{}\", {1, 14}) == %{\n               context: {:struct, {:alias, {:module_attribute, ~c\"some\"}, ~c\"Foo.Sub\"}},\n               begin: {1, 1},\n               end: {1, 15}\n             }\n\n      assert CF.surround_context(\"@some.call()\", {1, 8}) == %{\n               context: {:dot, {:module_attribute, ~c\"some\"}, ~c\"call\"},\n               begin: {1, 1},\n               end: {1, 11}\n             }\n\n      assert CF.surround_context(\"@some.Foo.call()\", {1, 12}) == %{\n               context: {:dot, {:alias, {:module_attribute, ~c\"some\"}, ~c\"Foo\"}, ~c\"call\"},\n               begin: {1, 1},\n               end: {1, 15}\n             }\n\n      assert CF.surround_context(\"@some.Foo.Sub.call()\", {1, 16}) == %{\n               context: {:dot, {:alias, {:module_attribute, ~c\"some\"}, ~c\"Foo.Sub\"}, ~c\"call\"},\n               begin: {1, 1},\n               end: {1, 19}\n             }\n    end\n\n    test \"struct\" do\n      assert CF.surround_context(\"%\", {1, 1}) == :none\n      assert CF.surround_context(\"::%\", {1, 1}) == :none\n      assert CF.surround_context(\"::%\", {1, 2}) == :none\n      assert CF.surround_context(\"::%Hello\", {1, 1}) == :none\n      assert CF.surround_context(\"::%Hello\", {1, 2}) == :none\n\n      assert CF.surround_context(\"::%Hello\", {1, 3}) == %{\n               context: {:struct, ~c\"Hello\"},\n               begin: {1, 3},\n               end: {1, 9}\n             }\n\n      assert CF.surround_context(\"::% Hello\", {1, 3}) == %{\n               context: {:struct, ~c\"Hello\"},\n               begin: {1, 3},\n               end: {1, 10}\n             }\n\n      assert CF.surround_context(\"::% Hello\", {1, 4}) == %{\n               context: {:struct, ~c\"Hello\"},\n               begin: {1, 3},\n               end: {1, 10}\n             }\n\n      # Alias\n      assert CF.surround_context(\"%HelloWor\", {1, 1}) == %{\n               context: {:struct, ~c\"HelloWor\"},\n               begin: {1, 1},\n               end: {1, 10}\n             }\n\n      assert CF.surround_context(\"%HelloWor.some\", {1, 12}) == %{\n               context: {:struct, {:dot, {:alias, ~c\"HelloWor\"}, ~c\"some\"}},\n               begin: {1, 1},\n               end: {1, 15}\n             }\n\n      for i <- 2..9 do\n        assert CF.surround_context(\"%HelloWor\", {1, i}) == %{\n                 context: {:struct, ~c\"HelloWor\"},\n                 begin: {1, 1},\n                 end: {1, 10}\n               }\n      end\n\n      assert CF.surround_context(\"%HelloWor\", {1, 10}) == :none\n\n      # With dot\n      assert CF.surround_context(\"%Hello.Wor\", {1, 1}) == %{\n               context: {:struct, ~c\"Hello.Wor\"},\n               begin: {1, 1},\n               end: {1, 11}\n             }\n\n      for i <- 2..10 do\n        assert CF.surround_context(\"%Hello.Wor\", {1, i}) == %{\n                 context: {:struct, ~c\"Hello.Wor\"},\n                 begin: {1, 1},\n                 end: {1, 11}\n               }\n      end\n\n      assert CF.surround_context(\"%Hello.Wor\", {1, 11}) == :none\n\n      # With spaces\n      assert CF.surround_context(\"% Hello . Wor\", {1, 1}) == %{\n               context: {:struct, ~c\"Hello.Wor\"},\n               begin: {1, 1},\n               end: {1, 14}\n             }\n\n      for i <- 2..13 do\n        assert CF.surround_context(\"% Hello . Wor\", {1, i}) == %{\n                 context: {:struct, ~c\"Hello.Wor\"},\n                 begin: {1, 1},\n                 end: {1, 14}\n               }\n      end\n\n      assert CF.surround_context(\"% Hello . Wor\", {1, 14}) == :none\n    end\n\n    test \"module attributes\" do\n      for i <- 1..10 do\n        assert CF.surround_context(\"@hello_wor\", {1, i}) == %{\n                 context: {:module_attribute, ~c\"hello_wor\"},\n                 begin: {1, 1},\n                 end: {1, 11}\n               }\n      end\n\n      assert CF.surround_context(\"@Hello\", {1, 1}) == :none\n    end\n\n    test \"operators\" do\n      for i <- 2..4 do\n        assert CF.surround_context(\"1<<<3\", {1, i}) == %{\n                 context: {:operator, ~c\"<<<\"},\n                 begin: {1, 2},\n                 end: {1, 5}\n               }\n      end\n\n      for i <- 3..5 do\n        assert CF.surround_context(\"1 <<< 3\", {1, i}) == %{\n                 context: {:operator, ~c\"<<<\"},\n                 begin: {1, 3},\n                 end: {1, 6}\n               }\n      end\n\n      for i <- 2..3 do\n        assert CF.surround_context(\"1::3\", {1, i}) == %{\n                 context: {:operator, ~c\"::\"},\n                 begin: {1, 2},\n                 end: {1, 4}\n               }\n      end\n\n      for i <- 3..4 do\n        assert CF.surround_context(\"1 :: 3\", {1, i}) == %{\n                 context: {:operator, ~c\"::\"},\n                 begin: {1, 3},\n                 end: {1, 5}\n               }\n      end\n\n      for i <- 2..3 do\n        assert CF.surround_context(\"x..y\", {1, i}) == %{\n                 context: {:operator, ~c\"..\"},\n                 begin: {1, 2},\n                 end: {1, 4}\n               }\n      end\n\n      for i <- 3..4 do\n        assert CF.surround_context(\"x .. y\", {1, i}) == %{\n                 context: {:operator, ~c\"..\"},\n                 begin: {1, 3},\n                 end: {1, 5}\n               }\n      end\n\n      assert CF.surround_context(\"@\", {1, 1}) == %{\n               context: {:operator, ~c\"@\"},\n               begin: {1, 1},\n               end: {1, 2}\n             }\n\n      assert CF.surround_context(\"!\", {1, 1}) == %{\n               context: {:operator, ~c\"!\"},\n               begin: {1, 1},\n               end: {1, 2}\n             }\n\n      assert CF.surround_context(\"!foo\", {1, 1}) == %{\n               context: {:operator, ~c\"!\"},\n               begin: {1, 1},\n               end: {1, 2}\n             }\n\n      assert CF.surround_context(\"foo !bar\", {1, 5}) == %{\n               context: {:operator, ~c\"!\"},\n               begin: {1, 5},\n               end: {1, 6}\n             }\n\n      # invalid\n      assert CF.surround_context(\"->\", {1, 2}) == :none\n    end\n\n    test \"sigil\" do\n      assert CF.surround_context(\"~\", {1, 1}) == :none\n      assert CF.surround_context(\"~~r\", {1, 1}) == :none\n      assert CF.surround_context(\"~~r\", {1, 2}) == :none\n\n      assert CF.surround_context(\"~r/foo/\", {1, 1}) == %{\n               begin: {1, 1},\n               context: {:sigil, ~c\"r\"},\n               end: {1, 3}\n             }\n\n      assert CF.surround_context(\"~r/foo/\", {1, 2}) == %{\n               begin: {1, 1},\n               context: {:sigil, ~c\"r\"},\n               end: {1, 3}\n             }\n\n      assert CF.surround_context(\"~r/foo/\", {1, 3}) == :none\n\n      assert CF.surround_context(\"~R<foo>\", {1, 1}) == %{\n               begin: {1, 1},\n               context: {:sigil, ~c\"R\"},\n               end: {1, 3}\n             }\n\n      assert CF.surround_context(\"~R<foo>\", {1, 2}) == %{\n               begin: {1, 1},\n               context: {:sigil, ~c\"R\"},\n               end: {1, 3}\n             }\n\n      assert CF.surround_context(\"~R<foo>\", {1, 3}) == :none\n    end\n\n    test \"dot operator\" do\n      for i <- 4..7 do\n        assert CF.surround_context(\"Foo.<<<\", {1, i}) == %{\n                 context: {:dot, {:alias, ~c\"Foo\"}, ~c\"<<<\"},\n                 begin: {1, 1},\n                 end: {1, 8}\n               }\n      end\n\n      for i <- 4..9 do\n        assert CF.surround_context(\"Foo . <<<\", {1, i}) == %{\n                 context: {:dot, {:alias, ~c\"Foo\"}, ~c\"<<<\"},\n                 begin: {1, 1},\n                 end: {1, 10}\n               }\n      end\n\n      for i <- 4..6 do\n        assert CF.surround_context(\"Foo.::\", {1, i}) == %{\n                 context: {:dot, {:alias, ~c\"Foo\"}, ~c\"::\"},\n                 begin: {1, 1},\n                 end: {1, 7}\n               }\n      end\n\n      for i <- 4..8 do\n        assert CF.surround_context(\"Foo . ::\", {1, i}) == %{\n                 context: {:dot, {:alias, ~c\"Foo\"}, ~c\"::\"},\n                 begin: {1, 1},\n                 end: {1, 9}\n               }\n      end\n    end\n\n    test \"capture operator\" do\n      assert CF.surround_context(\"& &123 + 1\", {1, 1}) == %{\n               context: {:operator, ~c\"&\"},\n               begin: {1, 1},\n               end: {1, 2}\n             }\n\n      for i <- 3..6 do\n        assert CF.surround_context(\"& &123 + 1\", {1, i}) == %{\n                 context: {:capture_arg, ~c\"&123\"},\n                 begin: {1, 3},\n                 end: {1, 7}\n               }\n      end\n    end\n\n    test \"capture operator false positive\" do\n      assert CF.surround_context(\"1&&2\", {1, 3}) == %{\n               context: {:operator, ~c\"&&\"},\n               begin: {1, 2},\n               end: {1, 4}\n             }\n\n      assert CF.surround_context(\"1&&2\", {1, 4}) == :none\n\n      assert CF.surround_context(\"&a\", {1, 2}) == %{\n               context: {:local_or_var, ~c\"a\"},\n               begin: {1, 2},\n               end: {1, 3}\n             }\n    end\n\n    test \"unquoted atom\" do\n      for i <- 1..10 do\n        assert CF.surround_context(\":hello_wor\", {1, i}) == %{\n                 context: {:unquoted_atom, ~c\"hello_wor\"},\n                 begin: {1, 1},\n                 end: {1, 11}\n               }\n      end\n\n      for i <- 1..10 do\n        assert CF.surround_context(\":Hello@Wor\", {1, i}) == %{\n                 context: {:unquoted_atom, ~c\"Hello@Wor\"},\n                 begin: {1, 1},\n                 end: {1, 11}\n               }\n      end\n\n      assert CF.surround_context(\":\", {1, 1}) == :none\n    end\n\n    test \"keyword keys\" do\n      for i <- 2..4 do\n        assert CF.surround_context(\"[foo:\", {1, i}) == %{\n                 context: {:key, ~c\"foo\"},\n                 begin: {1, 2},\n                 end: {1, 5}\n               }\n      end\n\n      for i <- 10..12 do\n        assert CF.surround_context(\"[foo: 1, bar: 2]\", {1, i}) == %{\n                 context: {:key, ~c\"bar\"},\n                 begin: {1, 10},\n                 end: {1, 13}\n               }\n      end\n\n      assert CF.surround_context(\"if foo?, do: bar()\", {1, 10}) == %{\n               context: {:key, ~c\"do\"},\n               begin: {1, 10},\n               end: {1, 12}\n             }\n    end\n\n    test \"keyword false positives\" do\n      assert CF.surround_context(\"<<foo::\", {1, 3}) == %{\n               context: {:local_or_var, ~c\"foo\"},\n               begin: {1, 3},\n               end: {1, 6}\n             }\n\n      assert CF.surround_context(\"[foo  :atom\", {1, 2}) == %{\n               context: {:local_or_var, ~c\"foo\"},\n               begin: {1, 2},\n               end: {1, 5}\n             }\n    end\n  end\n\n  describe \"container_cursor_to_quoted/2\" do\n    def s2q!(arg, opts \\\\ []), do: Code.string_to_quoted!(arg, opts)\n\n    def cc2q!(arg, opts \\\\ []) do\n      {:ok, res} = CF.container_cursor_to_quoted(arg, opts)\n      res\n    end\n\n    test \"completes terminators\" do\n      assert cc2q!(\"(\") == s2q!(\"(__cursor__())\")\n      assert cc2q!(\"[\") == s2q!(\"[__cursor__()]\")\n      assert cc2q!(\"{\") == s2q!(\"{__cursor__()}\")\n      assert cc2q!(\"<<\") == s2q!(\"<<__cursor__()>>\")\n      assert cc2q!(\"foo do\") == s2q!(\"foo do __cursor__() end\")\n      assert cc2q!(\"foo do true else\") == s2q!(\"foo do true else __cursor__() end\")\n    end\n\n    test \"inside interpolation\" do\n      assert cc2q!(~S|\"foo #{(|) == s2q!(~S|\"foo #{(__cursor__())}\"|)\n      assert cc2q!(~S|\"foo #{\"bar #{{|) == s2q!(~S|\"foo #{\"bar #{{__cursor__()}}\"}\"|)\n    end\n\n    test \"keeps operators\" do\n      assert cc2q!(\"1 + 2\") == s2q!(\"1 + __cursor__()\")\n      assert cc2q!(\"&foo\") == s2q!(\"&__cursor__()\")\n      assert cc2q!(\"&foo/\") == s2q!(\"&foo/__cursor__()\")\n    end\n\n    test \"keeps function calls without parens\" do\n      assert cc2q!(\"alias\") == s2q!(\"__cursor__()\")\n      assert cc2q!(\"alias \") == s2q!(\"alias __cursor__()\")\n      assert cc2q!(\"alias foo\") == s2q!(\"alias __cursor__()\")\n      assert cc2q!(\"alias Foo.Bar\") == s2q!(\"alias __cursor__()\")\n      assert cc2q!(\"alias Foo.Bar,\") == s2q!(\"alias Foo.Bar, __cursor__()\")\n      assert cc2q!(\"alias Foo.Bar, as: \") == s2q!(\"alias Foo.Bar, as: __cursor__()\")\n    end\n\n    test \"do-end blocks\" do\n      assert cc2q!(\"foo do baz\") == s2q!(\"foo do __cursor__() end\")\n      assert cc2q!(\"foo do bar; baz\") == s2q!(\"foo do bar; __cursor__() end\")\n      assert cc2q!(\"foo do bar\\nbaz\") == s2q!(\"foo do bar\\n__cursor__() end\")\n\n      assert cc2q!(\"foo(bar do baz\") == s2q!(\"foo(bar do __cursor__() end)\")\n      assert cc2q!(\"foo(bar do baz \") == s2q!(\"foo(bar do baz(__cursor__()) end)\")\n      assert cc2q!(\"foo(bar do baz(\") == s2q!(\"foo(bar do baz(__cursor__()) end)\")\n      assert cc2q!(\"foo(bar do baz bat,\") == s2q!(\"foo(bar do baz(bat, __cursor__()) end)\")\n\n      assert cc2q!(\"foo(bar do baz, bat\", trailing_fragment: \" -> :ok end\") ==\n               s2q!(\"foo(bar do baz, __cursor__() -> :ok end)\")\n    end\n\n    test \"keyword lists\" do\n      assert cc2q!(\"[bar: \") == s2q!(\"[bar: __cursor__()]\")\n      assert cc2q!(\"[bar: baz,\") == s2q!(\"[bar: baz, __cursor__()]\")\n      assert cc2q!(\"[arg, bar: baz,\") == s2q!(\"[arg, bar: baz, __cursor__()]\")\n      assert cc2q!(\"[arg: val, bar: baz,\") == s2q!(\"[arg: val, bar: baz, __cursor__()]\")\n\n      assert cc2q!(\"{arg, bar: \") == s2q!(\"{arg, bar: __cursor__()}\")\n      assert cc2q!(\"{arg, bar: baz,\") == s2q!(\"{arg, bar: baz, __cursor__()}\")\n\n      assert cc2q!(\"foo(bar: \") == s2q!(\"foo(bar: __cursor__())\")\n      assert cc2q!(\"foo(bar: baz,\") == s2q!(\"foo([bar: baz, __cursor__()])\")\n      assert cc2q!(\"foo(arg, bar: \") == s2q!(\"foo(arg, bar: __cursor__())\")\n      assert cc2q!(\"foo(arg, bar: baz,\") == s2q!(\"foo(arg, [bar: baz, __cursor__()])\")\n      assert cc2q!(\"foo(arg: val, bar: \") == s2q!(\"foo(arg: val, bar: __cursor__())\")\n      assert cc2q!(\"foo(arg: val, bar: baz,\") == s2q!(\"foo([arg: val, bar: baz, __cursor__()])\")\n\n      assert cc2q!(\"foo bar: \") == s2q!(\"foo(bar: __cursor__())\")\n      assert cc2q!(\"foo bar: baz,\") == s2q!(\"foo([bar: baz, __cursor__()])\")\n      assert cc2q!(\"foo arg, bar: \") == s2q!(\"foo(arg, bar: __cursor__())\")\n      assert cc2q!(\"foo arg, bar: baz,\") == s2q!(\"foo(arg, [bar: baz, __cursor__()])\")\n      assert cc2q!(\"foo arg: val, bar: \") == s2q!(\"foo(arg: val, bar: __cursor__())\")\n      assert cc2q!(\"foo arg: val, bar: baz,\") == s2q!(\"foo([arg: val, bar: baz, __cursor__()])\")\n    end\n\n    test \"maps and structs\" do\n      assert cc2q!(\"%\") == s2q!(\"__cursor__()\")\n      assert cc2q!(\"%{\") == s2q!(\"%{__cursor__()}\")\n      assert cc2q!(\"%{bar:\") == s2q!(\"%{__cursor__()}\")\n      assert cc2q!(\"%{bar: \") == s2q!(\"%{bar: __cursor__()}\")\n      assert cc2q!(\"%{bar: baz,\") == s2q!(\"%{bar: baz, __cursor__()}\")\n      assert cc2q!(\"%{foo | \") == s2q!(\"%{foo | __cursor__()}\")\n      assert cc2q!(\"%{foo | bar:\") == s2q!(\"%{foo | __cursor__()}\")\n      assert cc2q!(\"%{foo | bar: \") == s2q!(\"%{foo | bar: __cursor__()}\")\n      assert cc2q!(\"%{foo | bar: baz,\") == s2q!(\"%{foo | bar: baz, __cursor__()}\")\n\n      assert cc2q!(\"%Foo\") == s2q!(\"__cursor__()\")\n      assert cc2q!(\"%Foo{\") == s2q!(\"%Foo{__cursor__()}\")\n      assert cc2q!(\"%Foo{bar: \") == s2q!(\"%Foo{bar: __cursor__()}\")\n      assert cc2q!(\"%Foo{bar: baz,\") == s2q!(\"%Foo{bar: baz, __cursor__()}\")\n      assert cc2q!(\"%Foo{foo | \") == s2q!(\"%Foo{foo | __cursor__()}\")\n      assert cc2q!(\"%Foo{foo | bar:\") == s2q!(\"%Foo{foo | __cursor__()}\")\n      assert cc2q!(\"%Foo{foo | bar: \") == s2q!(\"%Foo{foo | bar: __cursor__()}\")\n      assert cc2q!(\"%Foo{foo | bar: baz,\") == s2q!(\"%Foo{foo | bar: baz, __cursor__()}\")\n    end\n\n    test \"binaries\" do\n      assert cc2q!(\"<<\") == s2q!(\"<<__cursor__()>>\")\n      assert cc2q!(\"<<foo\") == s2q!(\"<<__cursor__()>>\")\n      assert cc2q!(\"<<foo, bar\") == s2q!(\"<<foo, __cursor__()>>\")\n      assert cc2q!(\"<<foo, bar::baz\") == s2q!(\"<<foo, bar::__cursor__()>>\")\n    end\n\n    test \"anonymous functions\" do\n      assert cc2q!(\"(fn\", trailing_fragment: \"-> end)\") == s2q!(\"(fn __cursor__() -> nil end)\")\n\n      assert cc2q!(\"(fn\", trailing_fragment: \"-> 1 + 2 end)\") ==\n               s2q!(\"(fn __cursor__() -> 1 + 2 end)\")\n\n      assert cc2q!(\"(fn x\", trailing_fragment: \"-> :ok end)\") ==\n               s2q!(\"(fn __cursor__() -> :ok end)\")\n\n      assert cc2q!(\"(fn x\", trailing_fragment: \", y -> :ok end)\") ==\n               s2q!(\"(fn __cursor__(), y -> :ok end)\")\n\n      assert cc2q!(\"(fn x,\", trailing_fragment: \"y -> :ok end)\") ==\n               s2q!(\"(fn x, __cursor__() -> :ok end)\")\n\n      assert cc2q!(\"(fn x,\", trailing_fragment: \"\\ny -> :ok end)\") ==\n               s2q!(\"(fn x, __cursor__()\\n -> :ok end)\")\n\n      assert cc2q!(\"(fn x, {\", trailing_fragment: \"y, z} -> :ok end)\") ==\n               s2q!(\"(fn x, {__cursor__(), z} -> :ok end)\")\n\n      assert cc2q!(\"(fn x, {y\", trailing_fragment: \", z} -> :ok end)\") ==\n               s2q!(\"(fn x, {__cursor__(), z} -> :ok end)\")\n\n      assert cc2q!(\"(fn x, {y, \", trailing_fragment: \"z} -> :ok end)\") ==\n               s2q!(\"(fn x, {y, __cursor__()} -> :ok end)\")\n\n      assert cc2q!(\"(fn x ->\", trailing_fragment: \":ok end)\") ==\n               s2q!(\"(fn x -> __cursor__() end)\")\n\n      assert cc2q!(\"(fn x ->\", trailing_fragment: \"\\n:ok end)\") ==\n               s2q!(\"(fn x -> __cursor__() end)\")\n\n      assert cc2q!(\"(fn x when \", trailing_fragment: \"-> :ok end)\") ==\n               s2q!(\"(fn x when __cursor__() -> :ok end)\")\n\n      assert cc2q!(\"(fn x when \", trailing_fragment: \"->\\n:ok end)\") ==\n               s2q!(\"(fn x when __cursor__() -> :ok end)\")\n\n      assert cc2q!(\"(fn\") == s2q!(\"(__cursor__())\")\n      assert cc2q!(\"(fn x\") == s2q!(\"(__cursor__())\")\n      assert cc2q!(\"(fn x,\") == s2q!(\"(__cursor__())\")\n      assert cc2q!(\"(fn x ->\") == s2q!(\"(fn x -> __cursor__() end)\")\n      assert cc2q!(\"(fn x -> x\") == s2q!(\"(fn x -> __cursor__() end)\")\n      assert cc2q!(\"(fn x, y -> x + y\") == s2q!(\"(fn x, y -> x + __cursor__() end)\")\n      assert cc2q!(\"(fn x, y -> x + y end\") == s2q!(\"(__cursor__())\")\n    end\n\n    test \"do -> end\" do\n      assert cc2q!(\"if do\\nx ->\\n\", trailing_fragment: \"y\\nz ->\\nw\\nend\") ==\n               s2q!(\"if do\\nx ->\\n__cursor__()\\nz -> \\nw\\nend\")\n\n      assert cc2q!(\"if do\\nx ->\\ny\", trailing_fragment: \"\\nz ->\\nw\\nend\") ==\n               s2q!(\"if do\\nx ->\\n__cursor__()\\nz -> \\nw\\nend\")\n\n      assert cc2q!(\"if do\\nx ->\\ny\\n\", trailing_fragment: \"\\nz ->\\nw\\nend\") ==\n               s2q!(\"if do\\nx ->\\ny\\n__cursor__()\\nz -> \\nw\\nend\")\n\n      assert cc2q!(\"for x <- [], reduce: %{} do\\ny, \", trailing_fragment: \"-> :ok\\nend\") ==\n               s2q!(\"for x <- [], reduce: %{} do\\ny, __cursor__() -> :ok\\nend\")\n\n      assert cc2q!(\"for x <- [], reduce: %{} do\\ny, z when \", trailing_fragment: \"-> :ok\\nend\") ==\n               s2q!(\"for x <- [], reduce: %{} do\\ny, z when __cursor__() -> :ok\\nend\")\n\n      assert cc2q!(\"case do\\na -> a\\nb = \", trailing_fragment: \"c -> c\\nend\") ==\n               s2q!(\"case do\\na -> a\\nb = __cursor__() -> c\\nend\")\n    end\n\n    test \"removes tokens until opening\" do\n      assert cc2q!(\"(123\") == s2q!(\"(__cursor__())\")\n      assert cc2q!(\"[foo\") == s2q!(\"[__cursor__()]\")\n      assert cc2q!(\"{'foo'\") == s2q!(\"{__cursor__()}\")\n      assert cc2q!(\"foo do :atom\") == s2q!(\"foo do __cursor__() end\")\n      assert cc2q!(\"foo(:atom\") == s2q!(\"foo(__cursor__())\")\n    end\n\n    test \"removes tokens until comma\" do\n      assert cc2q!(\"[bar, 123\") == s2q!(\"[bar, __cursor__()]\")\n      assert cc2q!(\"{bar, 'foo'\") == s2q!(\"{bar, __cursor__()}\")\n      assert cc2q!(\"<<bar, \\\"sample\\\"\") == s2q!(\"<<bar, __cursor__()>>\")\n      assert cc2q!(\"foo(bar, :atom\") == s2q!(\"foo(bar, __cursor__())\")\n      assert cc2q!(\"foo bar, :atom\") == s2q!(\"foo(bar, __cursor__())\")\n    end\n\n    test \"removes closed terminators\" do\n      assert cc2q!(\"foo([1, 2, 3]\") == s2q!(\"foo(__cursor__())\")\n      assert cc2q!(\"foo({1, 2, 3}\") == s2q!(\"foo(__cursor__())\")\n      assert cc2q!(\"foo((1, 2, 3)\") == s2q!(\"foo(__cursor__())\")\n      assert cc2q!(\"foo(<<1, 2, 3>>\") == s2q!(\"foo(__cursor__())\")\n      assert cc2q!(\"foo(bar do :done end\") == s2q!(\"foo(__cursor__())\")\n    end\n\n    test \"incomplete expressions\" do\n      assert cc2q!(\"foo(123, :\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, %\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, 0x\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r/\") == s2q!(\"foo(123, __cursor__())\")\n    end\n\n    test \"sigils\" do\n      assert cc2q!(\"foo(123, ~\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r/\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r/foo\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r//\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r//i\") == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r//i \") == s2q!(\"foo(123, __cursor__())\")\n\n      drop_metadata = fn ast ->\n        Macro.prewalk(ast, fn node ->\n          Macro.update_meta(node, &Keyword.drop(&1, [:delimiter, :column]))\n        end)\n      end\n\n      assert cc2q!(\"foo(123, ~\", preserve_sigils: true) == s2q!(\"foo(123, __cursor__())\")\n      assert cc2q!(\"foo(123, ~r\", preserve_sigils: true) == s2q!(\"foo(123, __cursor__())\")\n\n      assert cc2q!(\"foo(123, ~r/\", preserve_sigils: true) |> drop_metadata.() ==\n               s2q!(\"foo(123, sigil_r(<<\\\"\\\">>, __cursor__()))\")\n\n      assert cc2q!(\"foo(123, ~r/foo\", preserve_sigils: true) |> drop_metadata.() ==\n               s2q!(\"foo(123, sigil_r(<<\\\"foo\\\">>, __cursor__()))\")\n\n      assert cc2q!(\"foo(123, ~r//\", preserve_sigils: true) |> drop_metadata.() ==\n               s2q!(\"foo(123, sigil_r(<<\\\"\\\">>, [__cursor__()]))\")\n\n      assert cc2q!(\"foo(123, ~r//i\", preserve_sigils: true) |> drop_metadata.() ==\n               s2q!(\"foo(123, sigil_r(<<\\\"\\\">>, [?i, __cursor__()]))\")\n\n      assert cc2q!(\"foo(123, ~r//i \", preserve_sigils: true) |> drop_metadata.() ==\n               s2q!(\"foo(123, __cursor__())\")\n    end\n\n    test \"no warnings\" do\n      assert cc2q!(~s\"?\\\\ \") == s2q!(\"__cursor__()\")\n      assert cc2q!(~s\"{fn -> end, \") == s2q!(\"{fn -> nil end, __cursor__()}\")\n    end\n\n    test \"options\" do\n      opts = [columns: true]\n      assert cc2q!(\"foo(\", opts) == s2q!(\"foo(__cursor__())\", opts)\n      assert cc2q!(\"foo(123,\", opts) == s2q!(\"foo(123,__cursor__())\", opts)\n\n      opts = [token_metadata: true]\n      assert cc2q!(\"foo(\", opts) == s2q!(\"foo(__cursor__())\", opts)\n      assert cc2q!(\"foo(123,\", opts) == s2q!(\"foo(123,__cursor__())\", opts)\n\n      opts = [literal_encoder: fn ast, _ -> {:ok, {:literal, ast}} end]\n      assert cc2q!(\"foo(\", opts) == s2q!(\"foo(__cursor__())\", opts)\n      assert cc2q!(\"foo(123,\", opts) == s2q!(\"foo({:literal, 123},__cursor__())\", [])\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_identifier_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule Code.IdentifierTest do\n  use ExUnit.Case, async: true\n  doctest Code.Identifier\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_normalizer/formatted_ast_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Normalizer.FormatterASTTest do\n  use ExUnit.Case, async: true\n\n  defmacro assert_same(good, opts \\\\ []) do\n    quote bind_quoted: [good: good, opts: opts], location: :keep do\n      assert IO.iodata_to_binary(Code.format_string!(good, opts)) ==\n               string_to_string(good, opts)\n    end\n  end\n\n  def string_to_string(good, opts) do\n    line_length = Keyword.get(opts, :line_length, 98)\n    good = String.trim(good)\n\n    to_quoted_opts =\n      Keyword.merge(\n        [\n          literal_encoder: &{:ok, {:__block__, &2, [&1]}},\n          token_metadata: true,\n          unescape: false\n        ],\n        opts\n      )\n\n    {quoted, comments} = Code.string_to_quoted_with_comments!(good, to_quoted_opts)\n\n    to_algebra_opts = [comments: comments, escape: false] ++ opts\n\n    quoted\n    |> Code.quoted_to_algebra(to_algebra_opts)\n    |> Inspect.Algebra.format(line_length)\n    |> IO.iodata_to_binary()\n  end\n\n  describe \"integers\" do\n    test \"in decimal base\" do\n      assert_same \"0\"\n      assert_same \"100\"\n      assert_same \"007\"\n      assert_same \"10000\"\n      assert_same \"100_00\"\n    end\n\n    test \"in binary base\" do\n      assert_same \"0b0\"\n      assert_same \"0b1\"\n      assert_same \"0b101\"\n      assert_same \"0b01\"\n      assert_same \"0b111_111\"\n    end\n\n    test \"in octal base\" do\n      assert_same \"0o77\"\n      assert_same \"0o0\"\n      assert_same \"0o01\"\n      assert_same \"0o777_777\"\n    end\n\n    test \"in hex base\" do\n      assert_same \"0x1\"\n      assert_same \"0x01\"\n    end\n\n    test \"as chars\" do\n      assert_same \"?a\"\n      assert_same \"?1\"\n      assert_same \"?è\"\n      assert_same \"??\"\n      assert_same \"?\\\\\\\\\"\n      assert_same \"?\\\\s\"\n      assert_same \"?🎾\"\n    end\n  end\n\n  describe \"floats\" do\n    test \"with normal notation\" do\n      assert_same \"0.0\"\n      assert_same \"1.0\"\n      assert_same \"123.456\"\n      assert_same \"0.0000001\"\n      assert_same \"001.100\"\n      assert_same \"0_10000_0.000_000\"\n    end\n\n    test \"with scientific notation\" do\n      assert_same \"1.0e1\"\n      assert_same \"1.0e-1\"\n      assert_same \"1.0e01\"\n      assert_same \"1.0e-01\"\n      assert_same \"001.100e-010\"\n      assert_same \"0_100_0000.100e-010\"\n    end\n  end\n\n  describe \"atoms\" do\n    test \"true, false, nil\" do\n      assert_same \"nil\"\n      assert_same \"true\"\n      assert_same \"false\"\n    end\n\n    test \"without escapes\" do\n      assert_same ~S[:foo]\n    end\n\n    test \"with escapes\" do\n      assert_same ~S[:\"f\\a\\b\\ro\"]\n    end\n\n    test \"with unicode\" do\n      assert_same ~S[:ólá]\n    end\n\n    test \"does not reformat aliases\" do\n      assert_same ~S[:\"Elixir.String\"]\n      assert_same ~S[:\"Elixir\"]\n    end\n\n    test \"quoted operators\" do\n      assert_same ~S[:\"::\"]\n      assert_same ~S[:\"..//\"]\n      assert_same ~S{[\"..//\": 1]}\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S[:\"one #{2} three\"]\n    end\n\n    test \"with escapes and interpolation\" do\n      assert_same ~S[:\"one\\n\\\"#{2}\\\"\\nthree\"]\n    end\n  end\n\n  describe \"strings\" do\n    test \"without escapes\" do\n      assert_same ~S[\"foo\"]\n    end\n\n    test \"with escapes\" do\n      assert_same ~S[\"\\x0A\"]\n      assert_same ~S[\"f\\a\\b\\ro\"]\n      assert_same ~S[\"double \\\" quote\"]\n    end\n\n    test \"keeps literal new lines\" do\n      assert_same \"\"\"\n      \"fo\n      o\"\n      \"\"\"\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S[\"one #{} three\"]\n      assert_same ~S[\"one #{2} three\"]\n    end\n\n    test \"with escaped interpolation\" do\n      assert_same ~S[\"one\\#{two}three\"]\n    end\n\n    test \"with escapes and interpolation\" do\n      assert_same ~S[\"one\\n\\\"#{2}\\\"\\nthree\"]\n    end\n  end\n\n  describe \"lists\" do\n    test \"on module attribute\" do\n      assert_same ~S\"@foo [1]\"\n    end\n  end\n\n  describe \"charlists\" do\n    test \"without escapes\" do\n      assert_same ~S[~c\"\"]\n      assert_same ~S[~c\" \"]\n      assert_same ~S[~c\"foo\"]\n    end\n\n    test \"with escapes\" do\n      assert_same ~S[~c\"f\\a\\b\\ro\"]\n      assert_same ~S[~c'single \\' quote']\n      assert_same ~S[~c\"double \\\" quote\"]\n    end\n\n    test \"keeps literal new lines\" do\n      assert_same \"\"\"\n      ~c\"fo\n      o\"\n      \"\"\"\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S[~c\"one #{2} three\"]\n    end\n\n    test \"with escape and interpolation\" do\n      assert_same ~S[~c'one\\n\\'#{2}\\'\\nthree']\n    end\n  end\n\n  describe \"string heredocs\" do\n    test \"without escapes\" do\n      assert_same ~S'''\n      \"\"\"\n      hello\n      \"\"\"\n      '''\n    end\n\n    test \"with escapes\" do\n      assert_same ~S'''\n      \"\"\"\n      f\\a\\b\\ro\n      \"\"\"\n      '''\n\n      assert_same ~S'''\n      \"\"\"\n      multiple \"\\\"\" quotes\n      \"\"\"\n      '''\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S'''\n      \"\"\"\n      one\n      #{2}\n      three\n      \"\"\"\n      '''\n\n      assert_same ~S'''\n      \"\"\"\n      one\n      \"\n      #{2}\n      \"\n      three\n      \"\"\"\n      '''\n    end\n\n    test \"nested with empty lines\" do\n      assert_same ~S'''\n      nested do\n        \"\"\"\n\n        foo\n\n\n        bar\n\n        \"\"\"\n      end\n      '''\n    end\n\n    test \"nested with empty lines and interpolation\" do\n      assert_same ~S'''\n      nested do\n        \"\"\"\n\n        #{foo}\n\n\n        #{bar}\n\n        \"\"\"\n      end\n      '''\n\n      assert_same ~S'''\n      nested do\n        \"\"\"\n        #{foo}\n\n\n        #{bar}\n        \"\"\"\n      end\n      '''\n    end\n\n    test \"with escaped new lines\" do\n      assert_same ~S'''\n      \"\"\"\n      one\\\n      #{\"two\"}\\\n      three\\\n      \"\"\"\n      '''\n    end\n  end\n\n  describe \"charlist heredocs\" do\n    test \"without escapes\" do\n      assert_same ~S\"\"\"\n      ~c'''\n      hello\n      '''\n      \"\"\"\n    end\n\n    test \"with escapes\" do\n      assert_same ~S\"\"\"\n      ~c'''\n      f\\a\\b\\ro\n      '''\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      ~c'''\n      multiple \"\\\"\" quotes\n      '''\n      \"\"\"\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S\"\"\"\n      ~c'''\n      one\n      #{2}\n      three\n      '''\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      ~c'''\n      one\n      \"\n      #{2}\n      \"\n      three\n      '''\n      \"\"\"\n    end\n  end\n\n  describe \"keyword list\" do\n    test \"blocks\" do\n      assert_same ~S\"\"\"\n      defmodule Example do\n        def sample, do: :ok\n      end\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      with true, do: :ok, else: (_ -> :ok)\n      \"\"\"\n    end\n\n    test \"omitting brackets\" do\n      assert_same ~S\"\"\"\n      @type foo :: a when b: :c\n      \"\"\"\n    end\n\n    test \"last tuple element as keyword list keeps its format\" do\n      assert_same ~S\"{:wrapped, [opt1: true, opt2: false]}\"\n      assert_same ~S\"{:unwrapped, opt1: true, opt2: false}\"\n      assert_same ~S\"{:wrapped, 1, [opt1: true, opt2: false]}\"\n      assert_same ~S\"{:unwrapped, 1, opt1: true, opt2: false}\"\n    end\n\n    test \"on module attribute\" do\n      assert_same ~S\"\"\"\n      @foo a: b,\n           c: d\n      \"\"\"\n\n      assert_same ~S\"@foo [\n        a: b,\n        c: d\n      ]\"\n    end\n  end\n\n  describe \"preserves user choice on parenthesis\" do\n    test \"in functions with do blocks\" do\n      assert_same(~S\"\"\"\n      foo Bar do\n        :ok\n      end\n      \"\"\")\n\n      assert_same(~S\"\"\"\n      foo(Bar) do\n        :ok\n      end\n      \"\"\")\n    end\n  end\n\n  describe \"preserves formatting for sigils\" do\n    test \"without interpolation\" do\n      assert_same ~S[~s(foo)]\n      assert_same ~S[~s{foo bar}]\n      assert_same ~S[~r/Bar Baz/]\n      assert_same ~S[~w<>]\n      assert_same ~S[~W()]\n    end\n\n    test \"with escapes\" do\n      assert_same ~S[~s(foo \\) bar)]\n      assert_same ~S[~s(f\\a\\b\\ro)]\n\n      assert_same ~S\"\"\"\n      ~S(foo\\\n      bar)\n      \"\"\"\n    end\n\n    test \"with nested new lines\" do\n      assert_same ~S\"\"\"\n      foo do\n        ~S(foo\\\n      bar)\n      end\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      foo do\n        ~s(#{bar}\n      )\n      end\n      \"\"\"\n    end\n\n    test \"with interpolation\" do\n      assert_same ~S[~s(one #{2} three)]\n    end\n\n    test \"with modifiers\" do\n      assert_same ~S[~w(one two three)a]\n      assert_same ~S[~z(one two three)foo]\n    end\n\n    test \"with heredoc syntax\" do\n      assert_same ~S\"\"\"\n      ~s'''\n      one\\a\n      #{:two}\\r\n      three\\0\n      '''\n      \"\"\"\n\n      assert_same ~S'''\n      ~s\"\"\"\n      one\\a\n      #{:two}\\r\n      three\\0\n      \"\"\"\n      '''\n    end\n\n    test \"with heredoc syntax and modifier\" do\n      assert_same ~S\"\"\"\n      ~s'''\n      foo\n      '''rsa\n      \"\"\"\n    end\n  end\n\n  describe \"preserves comments formatting\" do\n    test \"before and after expressions\" do\n      assert_same \"\"\"\n      # before comment\n      :hello\n      \"\"\"\n\n      assert_same \"\"\"\n      :hello\n      # after comment\n      \"\"\"\n\n      assert_same \"\"\"\n      # before comment\n      :hello\n      # after comment\n      \"\"\"\n    end\n\n    test \"empty comment\" do\n      assert_same \"\"\"\n      #\n      :foo\n      \"\"\"\n    end\n\n    test \"handles comments with unescaped literal\" do\n      assert_same \"\"\"\n                  # before\n                  Mix.install([:foo])\n                  # after\n                  \"\"\",\n                  literal_encoder: fn literal, _ -> {:ok, literal} end\n\n      assert_same \"\"\"\n                  # before\n                  Mix.install([1 + 2, :foo])\n                  # after\n                  \"\"\",\n                  literal_encoder: fn literal, _ -> {:ok, literal} end\n\n      assert_same \"\"\"\n                  # before\n                  Mix.install([:foo, 1 + 2])\n                  # after\n                  \"\"\",\n                  literal_encoder: fn literal, _ -> {:ok, literal} end\n\n      assert_same \"\"\"\n                  block do\n                    # before 1\n                    1 + 1\n\n                    # before 2\n                    2 + 2\n                  end\n                  \"\"\",\n                  literal_encoder: fn literal, _ -> {:ok, literal} end\n\n      assert_same \"\"\"\n                  block do\n                    # before 1\n                    Mix.install([1 + 1])\n\n                    # before 2\n                    Mix.install([2 + 2])\n                  end\n                  \"\"\",\n                  literal_encoder: fn literal, _ -> {:ok, literal} end\n    end\n\n    test \"before and after expressions with newlines\" do\n      assert_same \"\"\"\n      # before comment\n      # second line\n\n      :hello\n\n      # middle comment 1\n\n      #\n\n      # middle comment 2\n\n      :world\n\n      # after comment\n      # second line\n      \"\"\"\n    end\n\n    test \"interpolation with comment outside before and after\" do\n      assert_same ~S\"\"\"\n      # comment\n      IO.puts(\"Hello #{world}\")\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      IO.puts(\"Hello #{world}\")\n      # comment\n      \"\"\"\n    end\n\n    test \"blocks with keyword list\" do\n      assert_same ~S\"\"\"\n      defp sample do\n        [\n          # comment\n          {:a, \"~> 1.2\"}\n        ]\n      end\n      \"\"\"\n\n      assert_same ~S\"\"\"\n      defp sample do\n        [\n          # comment\n          {:a, \"~> 1.2\"},\n          {:b, \"~> 1.2\"}\n        ]\n      end\n      \"\"\"\n    end\n\n    test \"keyword literals with variable values\" do\n      assert_same(~S\"\"\"\n      foo = foo()\n      [foo: foo]\n      \"\"\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Code.Normalizer.QuotedASTTest do\n  use ExUnit.Case, async: true\n\n  describe \"quoted_to_algebra/2\" do\n    test \"variable\" do\n      assert quoted_to_string(quote(do: foo)) == \"foo\"\n      assert quoted_to_string({:{}, [], nil}) == \"{}\"\n    end\n\n    test \"variable with colors\" do\n      opts = [syntax_colors: [variable: :blue]]\n      assert quoted_to_string(quote(do: foo), opts) == \"\\e[34mfoo\\e[0m\"\n    end\n\n    test \"local call\" do\n      assert quoted_to_string(quote(do: foo(1, 2, 3))) == \"foo(1, 2, 3)\"\n      assert quoted_to_string(quote(do: foo([1, 2, 3]))) == \"foo([1, 2, 3])\"\n\n      assert quoted_to_string(quote(do: foo(1, 2, 3)), locals_without_parens: [foo: 3]) ==\n               \"foo 1, 2, 3\"\n\n      # Mixing literals and non-literals\n      assert quoted_to_string(quote(do: foo(a, 2))) == \"foo(a, 2)\"\n      assert quoted_to_string(quote(do: foo(1, b))) == \"foo(1, b)\"\n\n      # Mixing literals and non-literals with line\n      assert quoted_to_string(quote(line: __ENV__.line, do: foo(a, 2))) == \"foo(a, 2)\"\n      assert quoted_to_string(quote(line: __ENV__.line, do: foo(1, b))) == \"foo(1, b)\"\n    end\n\n    test \"local call with colors\" do\n      opts = [syntax_colors: [call: :blue, number: :yellow, variable: :red]]\n\n      assert quoted_to_string(quote(do: foo(1, a)), opts) ==\n               \"\\e[34mfoo\\e[0m(\\e[33m1\\e[0m, \\e[31ma\\e[0m)\"\n    end\n\n    test \"local call no parens\" do\n      assert quoted_to_string({:def, [], [1, 2]}) == \"def 1, 2\"\n      assert quoted_to_string({:def, [closing: []], [1, 2]}) == \"def(1, 2)\"\n    end\n\n    test \"remote call\" do\n      assert quoted_to_string(quote(do: foo.bar(1, 2, 3))) == \"foo.bar(1, 2, 3)\"\n      assert quoted_to_string(quote(do: foo.bar([1, 2, 3]))) == \"foo.bar([1, 2, 3])\"\n\n      quoted =\n        quote do\n          (foo do\n             :ok\n           end).bar([1, 2, 3])\n        end\n\n      assert quoted_to_string(quoted) == \"(foo do\\n   :ok\\n end).bar([1, 2, 3])\"\n    end\n\n    test \"nullary remote call\" do\n      assert quoted_to_string(quote do: foo.bar) == \"foo.bar\"\n      assert quoted_to_string(quote do: foo.bar()) == \"foo.bar()\"\n    end\n\n    test \"atom remote call\" do\n      assert quoted_to_string(quote(do: :foo.bar(1, 2, 3))) == \":foo.bar(1, 2, 3)\"\n    end\n\n    test \"remote and fun call\" do\n      assert quoted_to_string(quote(do: foo.bar().(1, 2, 3))) == \"foo.bar().(1, 2, 3)\"\n      assert quoted_to_string(quote(do: foo.bar().([1, 2, 3]))) == \"foo.bar().([1, 2, 3])\"\n    end\n\n    test \"unusual remote atom fun call\" do\n      assert quoted_to_string(quote(do: Foo.\"42\"())) == ~s/Foo.\"42\"()/\n      assert quoted_to_string(quote(do: Foo.\"Bar\"())) == ~s/Foo.\"Bar\"()/\n      assert quoted_to_string(quote(do: Foo.\"bar baz\"().\"\"())) == ~s/Foo.\"bar baz\"().\"\"()/\n      assert quoted_to_string(quote(do: Foo.\"%{}\"())) == ~s/Foo.\"%{}\"()/\n      assert quoted_to_string(quote(do: Foo.\"...\"())) == ~s/Foo.\"...\"()/\n    end\n\n    test \"atom fun call\" do\n      assert quoted_to_string(quote(do: :foo.(1, 2, 3))) == \":foo.(1, 2, 3)\"\n    end\n\n    test \"aliases call\" do\n      assert quoted_to_string(quote(do: Foo.Bar.baz(1, 2, 3))) == \"Foo.Bar.baz(1, 2, 3)\"\n      assert quoted_to_string(quote(do: Foo.Bar.baz([1, 2, 3]))) == \"Foo.Bar.baz([1, 2, 3])\"\n      assert quoted_to_string(quote(do: ?0.Bar.baz([1, 2, 3]))) == \"48.Bar.baz([1, 2, 3])\"\n      assert quoted_to_string(quote(do: Foo.bar(<<>>, []))) == \"Foo.bar(<<>>, [])\"\n    end\n\n    test \"remote call with colors\" do\n      opts = [syntax_colors: [call: :blue, number: :yellow, variable: :red, atom: :green]]\n\n      assert quoted_to_string(quote(do: foo.bar(1, 2)), opts) ==\n               \"\\e[31mfoo\\e[0m.\\e[34mbar\\e[0m(\\e[33m1\\e[0m, \\e[33m2\\e[0m)\"\n\n      assert quoted_to_string(quote(do: :foo.bar(1, 2)), opts) ==\n               \"\\e[32m:foo\\e[0m.\\e[34mbar\\e[0m(\\e[33m1\\e[0m, \\e[33m2\\e[0m)\"\n\n      assert quoted_to_string(quote(do: Foo.Bar.bar(1, 2)), opts) ==\n               \"\\e[32mFoo.Bar\\e[0m.\\e[34mbar\\e[0m(\\e[33m1\\e[0m, \\e[33m2\\e[0m)\"\n    end\n\n    test \"keyword call\" do\n      assert quoted_to_string(quote(do: Foo.bar(foo: :bar))) == \"Foo.bar(foo: :bar)\"\n      assert quoted_to_string(quote(do: Foo.bar(\"Elixir.Foo\": :bar))) == \"Foo.bar([{Foo, :bar}])\"\n    end\n\n    test \"sigil call\" do\n      assert quoted_to_string(quote(do: ~r\"123\")) == ~S/~r\"123\"/\n      assert quoted_to_string(quote(do: ~r\"\\n123\")) == ~S/~r\"\\n123\"/\n      assert quoted_to_string(quote(do: ~r\"12\\\"3\")) == ~S/~r\"12\\\"3\"/\n      assert quoted_to_string(quote(do: ~r/12\\/3/u)) == ~S\"~r/12\\/3/u\"\n      assert quoted_to_string(quote(do: ~r{\\n123})) == ~S/~r{\\n123}/\n      assert quoted_to_string(quote(do: ~r((1\\)(2\\)3))) == ~S/~r((1\\)(2\\)3)/\n      assert quoted_to_string(quote(do: ~r{\\n1{1\\}23})) == ~S/~r{\\n1{1\\}23}/\n      assert quoted_to_string(quote(do: ~r|12\\|3|)) == ~S\"~r|12\\|3|\"\n\n      assert quoted_to_string(quote(do: ~r[1#{two}3])) == ~S/~r[1#{two}3]/\n      assert quoted_to_string(quote(do: ~r|1[#{two}]3|)) == ~S/~r|1[#{two}]3|/\n      assert quoted_to_string(quote(do: ~r'1#{two}3'u)) == ~S/~r'1#{two}3'u/\n\n      assert quoted_to_string(quote(do: ~R\"123\")) == ~S/~R\"123\"/\n      assert quoted_to_string(quote(do: ~R\"123\"u)) == ~S/~R\"123\"u/\n      assert quoted_to_string(quote(do: ~R\"\\n123\")) == ~S/~R\"\\n123\"/\n\n      assert quoted_to_string(quote(do: ~S[\"'(123)'\"])) == ~S/~S[\"'(123)'\"]/\n      assert quoted_to_string(quote(do: ~s\"#{\"foo\"}\")) == ~S/~s\"#{\"foo\"}\"/\n\n      assert quoted_to_string(quote(do: ~S[\"'(123)'\"]) |> strip_metadata()) == ~S/~S\"\\\"'(123)'\\\"\"/\n      assert quoted_to_string(quote(do: ~s\"#{\"foo\"}\") |> strip_metadata()) == ~S/~s\"#{\"foo\"}\"/\n\n      assert quoted_to_string(\n               quote do\n                 ~s\"\"\"\n                 \"\\\"\"foo\"\\\"\"\n                 \"\"\"\n               end\n             ) == ~s[~s\"\"\"\\n\"\\\\\"\"foo\"\\\\\"\"\\n\"\"\"]\n\n      assert quoted_to_string(\n               quote do\n                 ~s'''\n                 '\\''foo'\\''\n                 '''\n               end\n             ) == ~s[~s'''\\n'\\\\''foo'\\\\''\\n''']\n\n      assert quoted_to_string(\n               quote do\n                 ~s\"\"\"\n                 \"\\\"foo\\\"\"\n                 \"\"\"\n               end\n             ) == ~s[~s\"\"\"\\n\"\\\\\"foo\\\\\"\"\\n\"\"\"]\n\n      assert quoted_to_string(\n               quote do\n                 ~s'''\n                 '\\\"foo\\\"'\n                 '''\n               end\n             ) == ~s[~s'''\\n'\\\\\"foo\\\\\"'\\n''']\n\n      assert quoted_to_string(\n               quote do\n                 ~S\"\"\"\n                 \"123\"\n                 \"\"\"\n               end\n             ) == ~s[~S\"\"\"\\n\"123\"\\n\"\"\"]\n    end\n\n    test \"regression: invalid sigil calls\" do\n      assert quoted_to_string(quote do: sigil_r(<<\"foo\", 123>>, [])) ==\n               \"sigil_r(<<\\\"foo\\\", 123>>, [])\"\n\n      assert quoted_to_string(quote do: sigil_r(<<\"foo\">>, :invalid_modifiers)) ==\n               \"sigil_r(\\\"foo\\\", :invalid_modifiers)\"\n\n      assert quoted_to_string(quote do: sigil_r(<<\"foo\">>, [:invalid_modifier])) ==\n               \"sigil_r(\\\"foo\\\", [:invalid_modifier])\"\n\n      assert quoted_to_string(quote do: sigil_r(<<\"foo\">>, [])) == \"~r\\\"foo\\\"\"\n      assert quoted_to_string(quote do: sigil_r(<<\"foo\">>, [?a, ?b, ?c])) == \"~r\\\"foo\\\"abc\"\n    end\n\n    test \"tuple\" do\n      assert quoted_to_string(quote do: {1, 2}) == \"{1, 2}\"\n      assert quoted_to_string(quote do: {1}) == \"{1}\"\n      assert quoted_to_string(quote do: {1, 2, 3}) == \"{1, 2, 3}\"\n      assert quoted_to_string(quote do: {1, 2, 3, foo: :bar}) == \"{1, 2, 3, foo: :bar}\"\n    end\n\n    test \"tuple with colors\" do\n      opts = [syntax_colors: [tuple: :blue, number: :yellow]]\n\n      assert quoted_to_string(quote(do: {1, 2, 3}), opts) ==\n               \"\\e[34m{\\e[0m\\e[33m1\\e[0m, \\e[33m2\\e[0m, \\e[33m3\\e[0m\\e[34m}\\e[0m\"\n    end\n\n    test \"tuple call\" do\n      assert quoted_to_string(quote(do: alias(Foo.{Bar, Baz, Bong}))) ==\n               \"alias Foo.{Bar, Baz, Bong}\"\n\n      assert quoted_to_string(quote(do: foo(Foo.{}))) == \"foo(Foo.{})\"\n    end\n\n    test \"arrow\" do\n      assert quoted_to_string(quote(do: foo(1, (2 -> 3)))) == \"foo(1, (2 -> 3))\"\n    end\n\n    test \"block\" do\n      quoted =\n        quote do\n          1\n          2\n\n          (\n            :foo\n            :bar\n          )\n\n          3\n        end\n\n      expected = \"\"\"\n      1\n      2\n\n      (\n        :foo\n        :bar\n      )\n\n      3\n      \"\"\"\n\n      assert quoted_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"not in\" do\n      assert quoted_to_string(quote(do: false not in [])) == \"false not in []\"\n    end\n\n    test \"if else\" do\n      expected = \"\"\"\n      if foo do\n        bar\n      else\n        baz\n      end\n      \"\"\"\n\n      assert quoted_to_string(quote(do: if(foo, do: bar, else: baz))) <> \"\\n\" == expected\n    end\n\n    test \"case\" do\n      quoted =\n        quote do\n          case foo do\n            true ->\n              0\n\n            false ->\n              1\n              2\n          end\n        end\n\n      expected = \"\"\"\n      case foo do\n        true ->\n          0\n\n        false ->\n          1\n          2\n      end\n      \"\"\"\n\n      assert quoted_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"case if else\" do\n      expected = \"\"\"\n      case (if foo do\n              bar\n            else\n              baz\n            end) do\n      end\n      \"\"\"\n\n      assert quoted_to_string(\n               quote(\n                 do:\n                   case if(foo, do: bar, else: baz) do\n                   end\n               )\n             ) <> \"\\n\" == expected\n    end\n\n    test \"try\" do\n      quoted =\n        quote do\n          try do\n            foo\n          catch\n            _, _ ->\n              2\n          rescue\n            ArgumentError ->\n              1\n          after\n            4\n          else\n            _ ->\n              3\n          end\n        end\n\n      expected = \"\"\"\n      try do\n        foo\n      catch\n        _, _ -> 2\n      rescue\n        ArgumentError -> 1\n      after\n        4\n      else\n        _ -> 3\n      end\n      \"\"\"\n\n      assert quoted_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"fn\" do\n      assert quoted_to_string(quote(do: fn -> 1 + 2 end)) == \"fn -> 1 + 2 end\"\n      assert quoted_to_string(quote(do: fn x -> x + 1 end)) == \"fn x -> x + 1 end\"\n\n      quoted =\n        quote do\n          fn x ->\n            y = x + 1\n            y\n          end\n        end\n\n      expected = \"\"\"\n      fn x ->\n        y = x + 1\n        y\n      end\n      \"\"\"\n\n      assert quoted_to_string(quoted) <> \"\\n\" == expected\n\n      quoted =\n        quote do\n          fn\n            x ->\n              y = x + 1\n              y\n\n            z ->\n              z\n          end\n        end\n\n      expected = \"\"\"\n      fn\n        x ->\n          y = x + 1\n          y\n\n        z ->\n          z\n      end\n      \"\"\"\n\n      assert quoted_to_string(quoted) <> \"\\n\" == expected\n\n      assert quoted_to_string(quote(do: (fn x -> x end).(1))) == \"(fn x -> x end).(1)\"\n\n      quoted =\n        quote do\n          (fn\n             %{} -> :map\n             _ -> :other\n           end).(1)\n        end\n\n      expected = \"\"\"\n      (fn\n         %{} -> :map\n         _ -> :other\n       end).(1)\n      \"\"\"\n\n      assert quoted_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"range\" do\n      assert quoted_to_string(quote(do: -1..+2)) == \"-1..+2\"\n      assert quoted_to_string(quote(do: Foo.integer()..3)) == \"Foo.integer()..3\"\n      assert quoted_to_string(quote(do: -1..+2//-3)) == \"-1..+2//-3\"\n\n      assert quoted_to_string(quote(do: Foo.integer()..3//Bar.bat())) ==\n               \"Foo.integer()..3//Bar.bat()\"\n\n      # invalid AST\n      assert quoted_to_string(-1..+2) == \"-1..2\"\n      assert quoted_to_string(-1..+2//-3) == \"-1..2//-3\"\n    end\n\n    test \"when\" do\n      assert quoted_to_string(quote(do: (-> x))) == \"(-> x)\"\n      assert quoted_to_string(quote(do: (x when y -> z))) == \"(x when y -> z)\"\n      assert quoted_to_string(quote(do: (x, y when z -> w))) == \"(x, y when z -> w)\"\n      assert quoted_to_string(quote(do: (x, y when z -> w))) == \"(x, y when z -> w)\"\n      assert quoted_to_string(quote(do: (x, y when z -> w))) == \"(x, y when z -> w)\"\n      assert quoted_to_string(quote(do: (x when y: z))) == \"x when y: z\"\n      assert quoted_to_string(quote(do: (x when y: z, z: w))) == \"x when y: z, z: w\"\n    end\n\n    test \"nested\" do\n      quoted =\n        quote do\n          defmodule Foo do\n            def foo do\n              1 + 1\n            end\n          end\n        end\n\n      expected = \"\"\"\n      defmodule Foo do\n        def foo do\n          1 + 1\n        end\n      end\n      \"\"\"\n\n      assert quoted_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"operator precedence\" do\n      assert quoted_to_string(quote(do: (1 + 2) * (3 - 4))) == \"(1 + 2) * (3 - 4)\"\n      assert quoted_to_string(quote(do: (1 + 2) * 3 - 4)) == \"(1 + 2) * 3 - 4\"\n      assert quoted_to_string(quote(do: 1 + 2 + 3)) == \"1 + 2 + 3\"\n      assert quoted_to_string(quote(do: 1 + 2 - 3)) == \"1 + 2 - 3\"\n    end\n\n    test \"capture operator\" do\n      assert quoted_to_string(quote(do: &foo/0)) == \"&foo/0\"\n      assert quoted_to_string(quote(do: &Foo.foo/0)) == \"&Foo.foo/0\"\n      assert quoted_to_string(quote(do: &(&1 + &2))) == \"&(&1 + &2)\"\n      assert quoted_to_string(quote(do: & &1)) == \"& &1\"\n      assert quoted_to_string(quote(do: & &1.(:x))) == \"& &1.(:x)\"\n      assert quoted_to_string(quote(do: (& &1).(:x))) == \"(& &1).(:x)\"\n    end\n\n    test \"operators\" do\n      assert quoted_to_string(quote(do: foo |> {1, 2})) == \"foo |> {1, 2}\"\n      assert quoted_to_string(quote(do: foo |> {:map, arg})) == \"foo |> {:map, arg}\"\n    end\n\n    test \"containers\" do\n      assert quoted_to_string(quote(do: {})) == \"{}\"\n      assert quoted_to_string(quote(do: [])) == \"[]\"\n      assert quoted_to_string(quote(do: {1, 2, 3})) == \"{1, 2, 3}\"\n      assert quoted_to_string(quote(do: [1, 2, 3])) == \"[1, 2, 3]\"\n      assert quoted_to_string(quote(do: [\"Elixir.Foo\": :bar])) == \"[{Foo, :bar}]\"\n      assert quoted_to_string(quote(do: %{})) == \"%{}\"\n      assert quoted_to_string(quote(do: %{:foo => :bar})) == \"%{foo: :bar}\"\n      assert quoted_to_string(quote(do: %{:\"Elixir.Foo\" => :bar})) == \"%{Foo => :bar}\"\n      assert quoted_to_string(quote(do: %{{1, 2} => [1, 2, 3]})) == \"%{{1, 2} => [1, 2, 3]}\"\n      assert quoted_to_string(quote(do: %{map | \"a\" => \"b\"})) == \"%{map | \\\"a\\\" => \\\"b\\\"}\"\n      assert quoted_to_string(quote(do: [1, 2, 3])) == \"[1, 2, 3]\"\n    end\n\n    test \"false positive containers\" do\n      assert quoted_to_string({:%{}, [], nil}) == \"%{}\"\n    end\n\n    test \"struct\" do\n      assert quoted_to_string(quote(do: %Test{})) == \"%Test{}\"\n      assert quoted_to_string(quote(do: %Test{foo: 1, bar: 1})) == \"%Test{foo: 1, bar: 1}\"\n      assert quoted_to_string(quote(do: %Test{struct | foo: 2})) == \"%Test{struct | foo: 2}\"\n      assert quoted_to_string(quote(do: %Test{} + 1)) == \"%Test{} + 1\"\n      assert quoted_to_string(quote(do: %Test{foo(1)} + 2)) == \"%Test{foo(1)} + 2\"\n    end\n\n    test \"binary operators\" do\n      assert quoted_to_string(quote(do: 1 + 2)) == \"1 + 2\"\n      assert quoted_to_string(quote(do: [1, 2 | 3])) == \"[1, 2 | 3]\"\n      assert quoted_to_string(quote(do: [h | t] = [1, 2, 3])) == \"[h | t] = [1, 2, 3]\"\n      assert quoted_to_string(quote(do: (x ++ y) ++ z)) == \"(x ++ y) ++ z\"\n      assert quoted_to_string(quote(do: (x +++ y) +++ z)) == \"(x +++ y) +++ z\"\n    end\n\n    test \"unary operators\" do\n      assert quoted_to_string(quote(do: not 1)) == \"not 1\"\n      assert quoted_to_string(quote(do: not foo)) == \"not foo\"\n      assert quoted_to_string(quote(do: -1)) == \"-1\"\n      assert quoted_to_string(quote(do: +(+1))) == \"+(+1)\"\n      assert quoted_to_string(quote(do: !(foo > bar))) == \"!(foo > bar)\"\n      assert quoted_to_string(quote(do: @foo(bar))) == \"@foo bar\"\n      assert quoted_to_string(quote(do: identity(&1))) == \"identity(&1)\"\n    end\n\n    test \"operators with colors\" do\n      opts = [syntax_colors: [operator: :blue, number: :yellow]]\n      assert quoted_to_string(quote(do: !!1), opts) == \"\\e[34m!\\e[0m\\e[34m!\\e[0m\\e[33m1\\e[0m\"\n      assert quoted_to_string(quote(do: 1 + 2), opts) == \"\\e[33m1\\e[0m\\e[34m +\\e[0m \\e[33m2\\e[0m\"\n    end\n\n    test \"access\" do\n      assert quoted_to_string(quote(do: a[b])) == \"a[b]\"\n      assert quoted_to_string(quote(do: a[1 + 2])) == \"a[1 + 2]\"\n      assert quoted_to_string(quote(do: (a || [a: 1])[:a])) == \"(a || [a: 1])[:a]\"\n      assert quoted_to_string(quote(do: Map.put(%{}, :a, 1)[:a])) == \"Map.put(%{}, :a, 1)[:a]\"\n    end\n\n    test \"keyword list\" do\n      assert quoted_to_string(quote(do: [a: a, b: b])) == \"[a: a, b: b]\"\n      assert quoted_to_string(quote(do: [a: 1, b: 1 + 2])) == \"[a: 1, b: 1 + 2]\"\n      assert quoted_to_string(quote(do: [\"a.b\": 1, c: 1 + 2])) == \"[\\\"a.b\\\": 1, c: 1 + 2]\"\n\n      tuple = {{:__block__, [format: :keyword], [:a]}, {:b, [], nil}}\n      assert quoted_to_string([tuple, :foo, tuple]) == \"[{:a, b}, :foo, a: b]\"\n      assert quoted_to_string([tuple, :foo, {:c, :d}, tuple]) == \"[{:a, b}, :foo, c: :d, a: b]\"\n\n      # Not keyword lists\n      assert quoted_to_string(quote(do: [{binary(), integer()}])) == \"[{binary(), integer()}]\"\n    end\n\n    test \"keyword list with colors\" do\n      opts = [syntax_colors: [list: :blue, atom: :green, number: :yellow]]\n\n      assert quoted_to_string(quote(do: [a: 1, b: 2]), opts) ==\n               \"\\e[34m[\\e[0m\\e[32ma:\\e[0m \\e[33m1\\e[0m, \\e[32mb:\\e[0m \\e[33m2\\e[0m\\e[34m]\\e[0m\"\n    end\n\n    test \"keyword list with :do as operand\" do\n      assert quoted_to_string(quote(do: a = [do: 1])) == \"a = [do: 1]\"\n    end\n\n    test \"interpolation\" do\n      assert quoted_to_string(quote(do: \"foo#{bar}baz\")) == ~S[\"foo#{bar}baz\"]\n    end\n\n    test \"bit syntax\" do\n      ast = quote(do: <<1::8*4>>)\n      assert quoted_to_string(ast) == \"<<1::8*4>>\"\n\n      ast = quote(do: @type(foo :: <<_::8, _::_*4>>))\n      assert quoted_to_string(ast) == \"@type foo :: <<_::8, _::_*4>>\"\n\n      ast = quote(do: <<69 - 4::bits-size(8 - 4)-unit(1), 65>>)\n      assert quoted_to_string(ast) == \"<<69 - 4::bits-size(8 - 4)-unit(1), 65>>\"\n\n      ast = quote(do: <<(<<65>>), 65>>)\n      assert quoted_to_string(ast) == \"<<(<<65>>), 65>>\"\n\n      ast = quote(do: <<65, (<<65>>)>>)\n      assert quoted_to_string(ast) == \"<<65, (<<65>>)>>\"\n\n      ast = quote(do: for(<<(a::4 <- <<1, 2>>)>>, do: a))\n      assert quoted_to_string(ast) == \"for <<(a::4 <- <<1, 2>>)>> do\\n  a\\nend\"\n    end\n\n    test \"integer/float\" do\n      assert quoted_to_string(1) == \"1\"\n      assert quoted_to_string({:__block__, [], [1]}) == \"1\"\n      assert quoted_to_string(1.23) == \"1.23\"\n    end\n\n    test \"integer/float with colors\" do\n      opts = [syntax_colors: [number: :yellow]]\n      assert quoted_to_string(1, opts) == \"\\e[33m1\\e[0m\"\n      assert quoted_to_string(1.23, opts) == \"\\e[33m1.23\\e[0m\"\n    end\n\n    test \"charlist\" do\n      assert quoted_to_string(quote(do: [])) == \"[]\"\n      assert quoted_to_string(quote(do: ~c\"abc\")) == ~S/~c\"abc\"/\n\n      # False positive\n      assert quoted_to_string(\n               quote do\n                 :\"Elixir.List\".to_charlist([\n                   case var do\n                     var -> var\n                   end\n                 ])\n               end\n             ) =~ \"List.to_charlist([\\n  case var do\\n    var -> var\\n  end\\n])\"\n    end\n\n    test \"string\" do\n      assert quoted_to_string(quote(do: \"\")) == ~S/\"\"/\n      assert quoted_to_string(quote(do: \"abc\")) == ~S/\"abc\"/\n      assert quoted_to_string(quote(do: \"#{\"abc\"}\")) == ~S/\"#{\"abc\"}\"/\n    end\n\n    test \"string with colors\" do\n      opts = [syntax_colors: [string: :green]]\n      assert quoted_to_string(quote(do: \"abc\"), opts) == \"\\e[32m\\\"abc\\\"\\e[0m\"\n    end\n\n    test \"catch-all\" do\n      assert quoted_to_string(quote do: {unquote(self())}) == \"{#{inspect(self())}}\"\n      assert quoted_to_string(quote do: foo(unquote(self()))) == \"foo(#{inspect(self())})\"\n    end\n\n    test \"last arg keyword list\" do\n      assert quoted_to_string(quote(do: foo([]))) == \"foo([])\"\n      assert quoted_to_string(quote(do: foo(x: y))) == \"foo(x: y)\"\n      assert quoted_to_string(quote(do: foo(x: 1 + 2))) == \"foo(x: 1 + 2)\"\n      assert quoted_to_string(quote(do: foo(x: y, p: q))) == \"foo(x: y, p: q)\"\n      assert quoted_to_string(quote(do: foo(a, x: y, p: q))) == \"foo(a, x: y, p: q)\"\n\n      assert quoted_to_string(quote(do: {[]})) == \"{[]}\"\n      assert quoted_to_string(quote(do: {[a: b]})) == \"{[a: b]}\"\n      assert quoted_to_string(quote(do: {x, a: b})) == \"{x, a: b}\"\n      assert quoted_to_string(quote(do: foo(else: a))) == \"foo(else: a)\"\n      assert quoted_to_string(quote(do: foo(catch: a))) == \"foo(catch: a)\"\n      assert quoted_to_string(quote(do: foo |> [bar: :baz])) == \"foo |> [bar: :baz]\"\n    end\n\n    test \"keyword arg with cursor\" do\n      input = \"def foo, do: :bar, __cursor__()\"\n      expected = \"def foo, [{:do, :bar}, __cursor__()]\"\n\n      ast = Code.string_to_quoted!(input)\n      assert quoted_to_string(ast) == expected\n\n      encoder = &{:ok, {:__block__, &2, [&1]}}\n      ast = Code.string_to_quoted!(input, literal_encoder: encoder)\n      assert quoted_to_string(ast) == expected\n\n      ast = Code.string_to_quoted!(input, token_metadata: true)\n      assert quoted_to_string(ast) == expected\n\n      ast = Code.string_to_quoted!(input, literal_encoder: encoder, token_metadata: true)\n      assert quoted_to_string(ast) == expected\n    end\n\n    test \"keyword arg with literal encoder and no metadata\" do\n      input = \"\"\"\n      foo(Bar) do\n        :ok\n      end\n      \"\"\"\n\n      encoder = &{:ok, {:__block__, &2, [&1]}}\n      ast = Code.string_to_quoted!(input, literal_encoder: encoder)\n      assert quoted_to_string(ast) == \"foo(Bar, do: :ok)\"\n    end\n\n    test \"list in module attribute\" do\n      assert quoted_to_string(\n               quote do\n                 @foo []\n               end\n             ) == \"@foo []\"\n\n      assert quoted_to_string(\n               quote do\n                 @foo [1]\n               end\n             ) == \"@foo [1]\"\n\n      assert quoted_to_string(\n               quote do\n                 @foo [foo: :bar]\n               end\n             ) == \"@foo foo: :bar\"\n\n      assert quoted_to_string(\n               quote do\n                 @foo [1, foo: :bar]\n               end\n             ) == \"@foo [1, foo: :bar]\"\n    end\n  end\n\n  describe \"quoted_to_algebra/2 escapes\" do\n    test \"strings with slash escapes\" do\n      assert quoted_to_string(quote(do: \"\\a\\b\\d\\e\\f\\n\\r\\t\\v\"), escape: false) ==\n               ~s/\"\\a\\b\\d\\e\\f\\n\\r\\t\\v\"/\n\n      assert quoted_to_string(quote(do: \"\\a\\b\\d\\e\\f\\n\\r\\t\\v\")) ==\n               ~s/\"\\\\a\\\\b\\\\d\\\\e\\\\f\\\\n\\\\r\\\\t\\\\v\"/\n\n      assert quoted_to_string({:__block__, [], [\"\\a\\b\\d\\e\\f\\n\\r\\t\\v\"]}, escape: false) ==\n               ~s/\"\\a\\b\\d\\e\\f\\n\\r\\t\\v\"/\n\n      assert quoted_to_string({:__block__, [], [\"\\a\\b\\d\\e\\f\\n\\r\\t\\v\"]}) ==\n               ~s/\"\\\\a\\\\b\\\\d\\\\e\\\\f\\\\n\\\\r\\\\t\\\\v\"/\n    end\n\n    test \"strings with non printable characters\" do\n      assert quoted_to_string(quote(do: \"\\x00\\x01\\x10\"), escape: false) == ~s/\"\\x00\\x01\\x10\"/\n      assert quoted_to_string(quote(do: \"\\x00\\x01\\x10\")) == ~S/\"\\0\\x01\\x10\"/\n    end\n\n    test \"charlists with slash escapes\" do\n      assert quoted_to_string(~c\"\\a\\b\\e\\n\\r\\t\\v\", escape: false) ==\n               ~s/~c\"\\a\\b\\e\\n\\r\\t\\v\"/\n\n      assert quoted_to_string(~c\"\\a\\b\\e\\n\\r\\t\\v\") ==\n               ~s/~c\"\\\\a\\\\b\\\\e\\\\n\\\\r\\\\t\\\\v\"/\n\n      assert quoted_to_string({:__block__, [], [~c\"\\a\\b\\e\\n\\r\\t\\v\"]}, escape: false) ==\n               ~s/~c\"\\a\\b\\e\\n\\r\\t\\v\"/\n\n      assert quoted_to_string({:__block__, [], [~c\"\\a\\b\\e\\n\\r\\t\\v\"]}) ==\n               ~s/~c\"\\\\a\\\\b\\\\e\\\\n\\\\r\\\\t\\\\v\"/\n    end\n\n    test \"charlists with non printable characters\" do\n      assert quoted_to_string(~c\"\\x00\\x01\\x10\", escape: false) == ~S/[0, 1, 16]/\n      assert quoted_to_string(~c\"\\x00\\x01\\x10\") == ~S/[0, 1, 16]/\n    end\n\n    test \"atoms\" do\n      assert quoted_to_string(quote(do: :\"a\\nb\\tc\"), escape: false) == ~s/:\"a\\nb\\tc\"/\n      assert quoted_to_string(quote(do: :\"a\\nb\\tc\")) == ~S/:\"a\\nb\\tc\"/\n\n      assert quoted_to_string({:__block__, [], [:\"a\\nb\\tc\"]}, escape: false) == ~s/:\"a\\nb\\tc\"/\n      assert quoted_to_string({:__block__, [], [:\"a\\nb\\tc\"]}) == ~S/:\"a\\nb\\tc\"/\n\n      assert quoted_to_string(quote(do: :\"Elixir\")) == \"Elixir\"\n      assert quoted_to_string(quote(do: :\"Elixir.Foo\")) == \"Foo\"\n      assert quoted_to_string(quote(do: :\"Elixir.Foo.Bar\")) == \"Foo.Bar\"\n      assert quoted_to_string(quote(do: :\"Elixir.foobar\")) == ~S/:\"Elixir.foobar\"/\n    end\n\n    test \"atoms with non printable characters\" do\n      assert quoted_to_string(quote(do: :\"\\x00\\x01\\x10\"), escape: false) == ~s/:\"\\0\\x01\\x10\"/\n      assert quoted_to_string(quote(do: :\"\\x00\\x01\\x10\")) == ~S/:\"\\0\\x01\\x10\"/\n    end\n\n    test \"atoms with interpolations\" do\n      assert quoted_to_string(quote(do: :\"foo\\n#{bar}\\tbaz\"), escape: false) ==\n               ~s[:\"foo\\n\\#{bar}\\tbaz\"]\n\n      assert quoted_to_string(quote(do: :\"foo\\n#{bar}\\tbaz\")) == ~S[:\"foo\\n#{bar}\\tbaz\"]\n\n      assert quoted_to_string(quote(do: :\"foo\\\"bar\"), escape: false) == ~S[:\"foo\\\"bar\"]\n      assert quoted_to_string(quote(do: :\"foo\\\"bar\")) == ~S[:\"foo\\\"bar\"]\n\n      assert quoted_to_string(quote(do: :\"foo#{~s/\\n/}bar\"), escape: false) ==\n               ~S[:\"foo#{~s/\\n/}bar\"]\n\n      assert quoted_to_string(quote(do: :\"foo#{~s/\\n/}bar\")) == ~S[:\"foo#{~s/\\n/}bar\"]\n\n      assert quoted_to_string(quote(do: :\"one\\n\\\"#{2}\\\"\\nthree\"), escape: false) ==\n               ~s[:\"one\\n\\\\\"\\#{2}\\\\\"\\nthree\"]\n\n      assert quoted_to_string(quote(do: :\"one\\n\\\"#{2}\\\"\\nthree\")) == ~S[:\"one\\n\\\"#{2}\\\"\\nthree\"]\n    end\n\n    test \":erlang.binary_to_atom/2 edge cases\" do\n      assert quoted_to_string(quote(do: :erlang.binary_to_atom(<<>>, :utf8))) == ~S[:\"\"]\n\n      assert quoted_to_string(quote(do: :erlang.binary_to_atom(<<1>>, :utf8))) ==\n               ~S\":erlang.binary_to_atom(<<1>>, :utf8)\"\n    end\n  end\n\n  describe \"quoted_to_algebra/2 with invalid\" do\n    test \"block\" do\n      assert quoted_to_string({:__block__, [], {:bar, [], []}}) ==\n               \"{:__block__, [], {:bar, [], []}}\"\n\n      assert quoted_to_string({:foo, [], [{:do, :ok}, :not_keyword]}) ==\n               \"foo({:do, :ok}, :not_keyword)\"\n\n      assert quoted_to_string({:foo, [], [[{:do, :ok}, :not_keyword]]}) ==\n               \"foo([{:do, :ok}, :not_keyword])\"\n    end\n\n    test \"ode\" do\n      assert quoted_to_string(1..3) == \"1..3\"\n    end\n  end\n\n  describe \"quoted_to_algebra/2 does not escape\" do\n    test \"sigils\" do\n      assert quoted_to_string(quote(do: ~s/a\\nb\\tc/), escape: false) == ~S\"~s/a\\nb\\tc/\"\n      assert quoted_to_string(quote(do: ~s/a\\nb\\tc/)) == ~S\"~s/a\\nb\\tc/\"\n\n      assert quoted_to_string(quote(do: ~s/\\a\\b\\d\\e\\f\\n\\r\\t\\v/), escape: false) ==\n               ~S\"~s/\\a\\b\\d\\e\\f\\n\\r\\t\\v/\"\n\n      assert quoted_to_string(quote(do: ~s/\\a\\b\\d\\e\\f\\n\\r\\t\\v/)) == ~S\"~s/\\a\\b\\d\\e\\f\\n\\r\\t\\v/\"\n\n      assert quoted_to_string(quote(do: ~s/\\x00\\x01\\x10/), escape: false) == ~S\"~s/\\x00\\x01\\x10/\"\n      assert quoted_to_string(quote(do: ~s/\\x00\\x01\\x10/)) == ~S\"~s/\\x00\\x01\\x10/\"\n    end\n  end\n\n  defp strip_metadata(ast) do\n    Macro.prewalk(ast, &Macro.update_meta(&1, fn _ -> [] end))\n  end\n\n  defp quoted_to_string(quoted, opts \\\\ []) do\n    doc = Code.quoted_to_algebra(quoted, opts)\n\n    Inspect.Algebra.format(doc, 98)\n    |> IO.iodata_to_binary()\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/code_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule CodeTest do\n  use ExUnit.Case, async: true\n\n  doctest Code\n  import PathHelpers\n\n  def genmodule(name) do\n    defmodule name do\n      Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n    end\n  end\n\n  contents =\n    quote do\n      defmodule CodeTest.Sample do\n        def eval_quoted_info, do: {__MODULE__, __ENV__.file, __ENV__.line}\n      end\n    end\n\n  Code.eval_quoted(contents, [], file: \"sample.ex\", line: 13)\n\n  describe \"with_diagnostics/2\" do\n    test \"captures warnings\" do\n      assert {:warn, [%{message: \"hello\"}]} =\n               Code.with_diagnostics(fn ->\n                 IO.warn(\"hello\")\n                 :warn\n               end)\n    end\n\n    test \"captures and logs warnings\" do\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               assert {:warn, [%{message: \"hello\"}]} =\n                        Code.with_diagnostics([log: true], fn ->\n                          IO.warn(\"hello\")\n                          :warn\n                        end)\n             end) =~ \"hello\"\n    end\n\n    test \"can be nested\" do\n      assert {:warn, [%{message: \"hello\"}]} =\n               Code.with_diagnostics(fn ->\n                 IO.warn(\"hello\")\n\n                 assert {:nested, [%{message: \"world\"}]} =\n                          Code.with_diagnostics(fn ->\n                            IO.warn(\"world\")\n                            :nested\n                          end)\n\n                 :warn\n               end)\n    end\n\n    test \"includes column information on unused variables\" do\n      assert {_, [%{position: {1, 12}}]} =\n               Code.with_diagnostics(fn ->\n                 quoted = Code.string_to_quoted!(\"if true do var = :foo end\", columns: true)\n                 Code.eval_quoted(quoted, [])\n               end)\n    end\n\n    test \"includes column information on unused aliases\" do\n      sample = \"\"\"\n      defmodule CodeTest.UnusedAlias do\n        alias String.Chars\n      end\n      \"\"\"\n\n      assert {_, [%{position: {2, 3}}]} =\n               Code.with_diagnostics(fn ->\n                 quoted = Code.string_to_quoted!(sample, columns: true)\n                 Code.eval_quoted(quoted, [])\n               end)\n    end\n\n    test \"includes column information on unused imports\" do\n      sample = \"\"\"\n      defmodule CodeTest.UnusedImport do\n        import URI\n      end\n      \"\"\"\n\n      assert {_, [%{position: {2, 3}}]} =\n               Code.with_diagnostics(fn ->\n                 quoted = Code.string_to_quoted!(sample, columns: true)\n                 Code.eval_quoted(quoted, [])\n               end)\n    end\n\n    test \"includes column information on unknown remote function calls\" do\n      sample = \"\"\"\n      defmodule CodeTest.UnknownRemoteCall do\n        def perform do\n          UnknownModule.foo()\n        end\n      end\n      \"\"\"\n\n      assert {_, [%{position: {3, 19}}]} =\n               Code.with_diagnostics(fn ->\n                 quoted = Code.string_to_quoted!(sample, columns: true)\n                 Code.eval_quoted(quoted, [])\n               end)\n    end\n\n    test \"captures unknown local calls\" do\n      sample = \"\"\"\n      defmodule CodeTest.UnknownLocalCall do\n        def perform do\n          foo()\n        end\n      end\n      \"\"\"\n\n      assert {:rescued, [%{message: message}]} =\n               Code.with_diagnostics(fn ->\n                 try do\n                   quoted = Code.string_to_quoted!(sample, columns: true)\n                   Code.eval_quoted(quoted, [])\n                 rescue\n                   _ -> :rescued\n                 end\n               end)\n\n      assert message =~ \"undefined function foo/0\"\n    end\n  end\n\n  describe \"eval_string/1,2,3\" do\n    test \"correctly evaluates a string of code\" do\n      assert Code.eval_string(\"1 + 2\") == {3, []}\n      assert Code.eval_string(\"two = 1 + 1\") == {2, [two: 2]}\n    end\n\n    test \"keeps bindings on optimized evals\" do\n      assert Code.eval_string(\"import Enum\", x: 1) == {Enum, [x: 1]}\n    end\n\n    test \"supports a %Macro.Env{} struct as the third argument\" do\n      assert {3, _} = Code.eval_string(\"a + b\", [a: 1, b: 2], __ENV__)\n    end\n\n    test \"supports unnamed scopes\" do\n      assert {%RuntimeError{}, [a: %RuntimeError{}]} =\n               Code.eval_string(\"a = (try do (raise \\\"hello\\\") rescue e -> e end)\")\n    end\n\n    test \"returns bindings from a different context\" do\n      assert Code.eval_string(\"var!(a, Sample) = 1\") == {1, [{{:a, Sample}, 1}]}\n    end\n\n    defmacro hygiene_var do\n      quote do\n        a = 1\n      end\n    end\n\n    test \"does not return bindings from macro hygiene\" do\n      assert Code.eval_string(\"require CodeTest; CodeTest.hygiene_var()\") == {1, []}\n    end\n\n    test \"does not raise on duplicate bindings\" do\n      # The order of which values win is not guaranteed, but it should evaluate successfully.\n      assert Code.eval_string(\"b = String.Chars.to_string(a)\", a: 0, a: 1) ==\n               {\"1\", [{:b, \"1\"}, {:a, 1}]}\n\n      assert Code.eval_string(\"b = String.Chars.to_string(a)\", a: 0, a: 1, c: 2) ==\n               {\"1\", [{:c, 2}, {:b, \"1\"}, {:a, 1}]}\n    end\n\n    test \"raises on invalid binding type\" do\n      assert_raise ArgumentError, \"binding must be a list, got: :not_a_list\", fn ->\n        Code.eval_string(\"1 + 1\", :not_a_list)\n      end\n\n      assert_raise ArgumentError, \"binding must be a list, got: %{}\", fn ->\n        Code.eval_string(\"1 + 1\", %{}, __ENV__)\n      end\n    end\n\n    test \"keeps caller in stacktrace\" do\n      try do\n        Code.eval_string(\"<<a::size(b)>>\", [a: :a, b: :b], file: \"myfile\")\n      rescue\n        _ ->\n          assert Enum.any?(__STACKTRACE__, &(elem(&1, 0) == __MODULE__))\n      end\n    end\n\n    test \"includes eval file in stacktrace\" do\n      try do\n        Code.eval_string(\"<<a::size(b)>>\", [a: :a, b: :b], file: \"myfile\")\n      rescue\n        _ ->\n          assert Exception.format_stacktrace(__STACKTRACE__) =~ \"myfile:1\"\n      end\n\n      try do\n        Code.eval_string(\n          \"Enum.map([a: :a, b: :b], fn {a, b} -> <<a::size(b)>> end)\",\n          [],\n          file: \"myfile\"\n        )\n      rescue\n        _ ->\n          assert Exception.format_stacktrace(__STACKTRACE__) =~ \"myfile:1\"\n      end\n    end\n\n    test \"warns when lexical tracker process is dead\" do\n      {pid, ref} = spawn_monitor(fn -> :ok end)\n      assert_receive {:DOWN, ^ref, _, _, _}\n      env = %{__ENV__ | lexical_tracker: pid}\n\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               assert Code.eval_string(\"1 + 2\", [], env) == {3, []}\n             end) =~ \"an __ENV__ with outdated compilation information was given to eval\"\n    end\n\n    test \"formats diagnostic file paths as relatives\" do\n      {_, diagnostics} =\n        Code.with_diagnostics(fn ->\n          try do\n            Code.eval_string(\"x\", [])\n          rescue\n            e -> e\n          end\n        end)\n\n      assert [\n               %{\n                 message: \"undefined variable \\\"x\\\"\",\n                 position: 1,\n                 file: \"nofile\",\n                 source: \"nofile\",\n                 stacktrace: [],\n                 severity: :error\n               }\n             ] = diagnostics\n    end\n\n    test \"with :prune_binding\" do\n      opts = [prune_binding: true]\n      assert {2, [x: 1]} = Code.eval_string(\"x + 1\", [x: 1, y: 2], opts)\n    end\n\n    test \"with :debug_callback\" do\n      opts = [dbg_callback: {__MODULE__, :dbg_callback_add_one, []}]\n      assert {2, _binding} = Code.eval_string(\"dbg(1)\", [], opts)\n\n      # Maintains the default behaviour when called again without the option.\n      ExUnit.CaptureIO.capture_io(fn ->\n        assert {1, _binding} = Code.eval_string(\"dbg(1)\", [])\n      end)\n    end\n  end\n\n  describe \"eval_quoted/1\" do\n    test \"evaluates expression\" do\n      assert Code.eval_quoted(quote(do: 1 + 2)) == {3, []}\n      assert CodeTest.Sample.eval_quoted_info() == {CodeTest.Sample, \"sample.ex\", 13}\n    end\n\n    test \"with %Macro.Env{} at runtime\" do\n      alias :lists, as: MyList\n      quoted = quote(do: MyList.flatten([[1, 2, 3]]))\n\n      assert Code.eval_quoted(quoted, [], __ENV__) == {[1, 2, 3], []}\n\n      # Let's check it discards tracers since the lexical tracker is explicitly nil\n      assert Code.eval_quoted(quoted, [], %{__ENV__ | tracers: [:bad]}) == {[1, 2, 3], []}\n    end\n\n    test \"with %Macro.Env{} at compile time\" do\n      defmodule CompileTimeEnv do\n        alias String.Chars\n        {\"foo\", []} = Code.eval_string(\"Chars.to_string(:foo)\", [], __ENV__)\n      end\n    end\n\n    test \"with :prune_binding\" do\n      quoted = quote(do: var!(x) + 1)\n      opts = [prune_binding: true]\n      assert {2, [x: 1]} = Code.eval_quoted(quoted, [x: 1, y: 2], opts)\n    end\n\n    test \"with :dbg_callback\" do\n      quoted = quote(do: dbg(1))\n      opts = [dbg_callback: {__MODULE__, :dbg_callback_add_one, []}]\n      assert {2, _binding} = Code.eval_quoted(quoted, [], opts)\n\n      # Maintains the default behaviour when called again without the option.\n      ExUnit.CaptureIO.capture_io(fn ->\n        assert {1, _binding} = Code.eval_quoted(quoted, [])\n      end)\n    end\n  end\n\n  test \"eval_file/1\" do\n    assert Code.eval_file(fixture_path(\"code_sample.exs\")) == {3, [var: 3]}\n\n    assert_raise Code.LoadError, fn ->\n      Code.eval_file(\"non_existent.exs\")\n    end\n  end\n\n  describe \"eval_quoted_with_env/3\" do\n    test \"returns results, bindings, and env\" do\n      alias :lists, as: MyList\n      quoted = quote(do: MyList.flatten([[1, 2, 3]]))\n      env = Code.env_for_eval(__ENV__)\n      assert Code.eval_quoted_with_env(quoted, [], env) == {[1, 2, 3], [], env}\n\n      quoted = quote(do: alias(:dict, as: MyDict))\n      {:dict, [], env} = Code.eval_quoted_with_env(quoted, [], env)\n      assert Keyword.fetch(env.aliases, Elixir.MyDict) == {:ok, :dict}\n    end\n\n    test \"manages env vars\" do\n      env = Code.env_for_eval(__ENV__)\n      {1, [x: 1], env} = Code.eval_quoted_with_env(quote(do: var!(x) = 1), [], env)\n      assert Macro.Env.vars(env) == [{:x, nil}]\n    end\n\n    test \"prunes vars\" do\n      env = Code.env_for_eval(__ENV__)\n\n      fun = fn quoted, binding ->\n        {_, binding, env} = Code.eval_quoted_with_env(quoted, binding, env, prune_binding: true)\n        {binding, Macro.Env.vars(env)}\n      end\n\n      assert fun.(quote(do: 123), []) == {[], []}\n      assert fun.(quote(do: 123), x: 2, y: 3) == {[], []}\n\n      assert fun.(quote(do: var!(x) = 1), []) == {[x: 1], [x: nil]}\n      assert fun.(quote(do: var!(x) = 1), x: 2, y: 3) == {[x: 1], [x: nil]}\n\n      assert fun.(quote(do: var!(x, :foo) = 1), []) == {[{{:x, :foo}, 1}], [x: :foo]}\n      assert fun.(quote(do: var!(x, :foo) = 1), x: 2, y: 3) == {[{{:x, :foo}, 1}], [x: :foo]}\n\n      assert fun.(quote(do: var!(x, :foo) = 1), [{{:x, :foo}, 2}, {{:y, :foo}, 3}]) ==\n               {[{{:x, :foo}, 1}], [x: :foo]}\n\n      assert fun.(quote(do: fn -> var!(x, :foo) = 1 end), []) == {[], []}\n      assert fun.(quote(do: fn -> var!(x, :foo) = 1 end), x: 1, y: 2) == {[], []}\n\n      assert fun.(quote(do: fn -> var!(x) end), x: 2, y: 3) == {[x: 2], [x: nil]}\n\n      assert fun.(quote(do: fn -> var!(x, :foo) end), [{{:x, :foo}, 2}, {{:y, :foo}, 3}]) ==\n               {[{{:x, :foo}, 2}], [x: :foo]}\n    end\n\n    test \"undefined function\" do\n      env = Code.env_for_eval(__ENV__)\n      quoted = quote do: foo()\n\n      assert_exception(\n        UndefinedFunctionError,\n        [\"** (UndefinedFunctionError) function foo/0 is undefined (there is no such import)\"],\n        fn ->\n          Code.eval_quoted_with_env(quoted, [], env)\n        end\n      )\n    end\n\n    defmodule Tracer do\n      def trace(event, env) do\n        send(self(), {:trace, event, env})\n        :ok\n      end\n    end\n\n    test \"with tracing and pruning\" do\n      env = %{Code.env_for_eval(__ENV__) | tracers: [Tracer], function: nil}\n      binding = [x: 1, y: 2, z: 3]\n\n      quoted =\n        quote do\n          defmodule Elixir.CodeTest.TracingPruning do\n            var!(y) = :updated\n            var!(y)\n            var!(x)\n          end\n        end\n\n      {_, binding, env} = Code.eval_quoted_with_env(quoted, binding, env, prune_binding: true)\n      assert Enum.sort(binding) == []\n      assert env.versioned_vars == %{}\n\n      assert_receive {:trace, {:on_module, _, _}, %{module: CodeTest.TracingPruning} = trace_env}\n\n      assert trace_env.versioned_vars == %{\n               {:result, :elixir_compiler} => 5,\n               {:x, nil} => 1,\n               {:y, nil} => 4\n             }\n    end\n\n    test \"with defguard\" do\n      require Integer, warn: false\n      env = Code.env_for_eval(__ENV__)\n      quoted = quote do: Integer.is_even(1)\n      {false, binding, env} = Code.eval_quoted_with_env(quoted, [], env, prune_binding: true)\n      assert binding == []\n      assert Macro.Env.vars(env) == []\n    end\n\n    test \"with :dbg_callback\" do\n      quoted = quote(do: dbg(1))\n      env = Code.env_for_eval(__ENV__)\n      opts = [dbg_callback: {__MODULE__, :dbg_callback_add_one, []}]\n      assert {2, _binding, _env} = Code.eval_quoted_with_env(quoted, [], env, opts)\n\n      # Maintains the default behaviour when called again without the option.\n      ExUnit.CaptureIO.capture_io(fn ->\n        assert {1, _binding, _env} = Code.eval_quoted_with_env(quoted, [], env, [])\n      end)\n    end\n  end\n\n  def dbg_callback_add_one(code, _options, _caller) do\n    quote do\n      unquote(code) + 1\n    end\n  end\n\n  describe \"compile_file/1\" do\n    test \"compiles the given path\" do\n      assert Code.compile_file(fixture_path(\"code_sample.exs\")) == []\n      refute fixture_path(\"code_sample.exs\") in Code.required_files()\n    end\n  end\n\n  test \"require_file/1\" do\n    assert Code.require_file(fixture_path(\"code_sample.exs\")) == []\n    assert fixture_path(\"code_sample.exs\") in Code.required_files()\n    assert Code.require_file(fixture_path(\"code_sample.exs\")) == nil\n\n    Code.unrequire_files([fixture_path(\"code_sample.exs\")])\n    refute fixture_path(\"code_sample.exs\") in Code.required_files()\n    assert Code.require_file(fixture_path(\"code_sample.exs\")) != nil\n  after\n    Code.unrequire_files([fixture_path(\"code_sample.exs\")])\n  end\n\n  test \"string_to_quoted!/2 errors take lines/columns/indentation into account\" do\n    assert_exception(\n      SyntaxError,\n      [\"nofile:1:5:\", \"syntax error before:\", \"1 + * 3\", \"^\"],\n      fn ->\n        Code.string_to_quoted!(\"1 + * 3\")\n      end\n    )\n\n    assert_exception(\n      SyntaxError,\n      [\"nofile:10:5:\", \"syntax error before:\", \"1 + * 3\", \"^\"],\n      fn ->\n        Code.string_to_quoted!(\"1 + * 3\", line: 10)\n      end\n    )\n\n    assert_exception(\n      SyntaxError,\n      [\"nofile:10:7:\", \"syntax error before:\", \"1 + * 3\", \"^\"],\n      fn ->\n        Code.string_to_quoted!(\"1 + * 3\", line: 10, column: 3)\n      end\n    )\n\n    assert_exception(\n      SyntaxError,\n      [\"nofile:11:15:\", \"syntax error before:\", \"1 + * 3\", \"^\"],\n      fn ->\n        Code.string_to_quoted!(\":ok\\n1 + * 3\", line: 10, column: 3, indentation: 10)\n      end\n    )\n  end\n\n  test \"string_to_quoted only requires the List.Chars protocol implementation to work\" do\n    assert {:ok, 1.23} = Code.string_to_quoted(1.23)\n    assert 1.23 = Code.string_to_quoted!(1.23)\n    assert {:ok, 1.23, []} = Code.string_to_quoted_with_comments(1.23)\n    assert {1.23, []} = Code.string_to_quoted_with_comments!(1.23)\n  end\n\n  test \"string_to_quoted returns error on incomplete escaped string\" do\n    assert {:error, {meta, \"missing terminator: \\\" (for string starting at line 1)\", \"\"}} =\n             Code.string_to_quoted(\"\\\"\\\\\")\n\n    assert meta[:line] == 1\n    assert meta[:column] == 1\n    assert meta[:end_line] == 1\n    assert meta[:end_column] == 3\n  end\n\n  test \"string_to_quoted with comments\" do\n    assert Code.string_to_quoted_with_comments(\"\"\"\n           # top\n           [\n             # before\n\n             # right-before\n             expr, # middle\n             # right-after\n\n             # after\n           ]\n           # bottom\n           \"\"\") ==\n             {\n               :ok,\n               [{:expr, [line: 6], nil}],\n               [\n                 %{\n                   column: 1,\n                   line: 1,\n                   next_eol_count: 1,\n                   previous_eol_count: 1,\n                   text: \"# top\"\n                 },\n                 %{\n                   column: 3,\n                   line: 3,\n                   next_eol_count: 2,\n                   previous_eol_count: 1,\n                   text: \"# before\"\n                 },\n                 %{\n                   column: 3,\n                   line: 5,\n                   next_eol_count: 1,\n                   previous_eol_count: 2,\n                   text: \"# right-before\"\n                 },\n                 %{\n                   column: 9,\n                   line: 6,\n                   next_eol_count: 1,\n                   previous_eol_count: 0,\n                   text: \"# middle\"\n                 },\n                 %{\n                   column: 3,\n                   line: 7,\n                   next_eol_count: 2,\n                   previous_eol_count: 1,\n                   text: \"# right-after\"\n                 },\n                 %{\n                   column: 3,\n                   line: 9,\n                   next_eol_count: 1,\n                   previous_eol_count: 2,\n                   text: \"# after\"\n                 },\n                 %{\n                   column: 1,\n                   line: 11,\n                   next_eol_count: 1,\n                   previous_eol_count: 1,\n                   text: \"# bottom\"\n                 }\n               ]\n             }\n  end\n\n  test \"string_to_quoted handles unescape errors properly\" do\n    # Test invalid hex escape character\n    assert {:error, {meta, message, token}} = Code.string_to_quoted(\"a.'\\\\xg'\")\n\n    assert meta[:line] == 1\n    assert meta[:column] == 3\n\n    assert message ==\n             \"invalid hex escape character, expected \\\\xHH where H is a hexadecimal digit. Syntax error after: \"\n\n    assert token == \"\\\\x\"\n\n    # Test invalid Unicode escape character\n    assert {:error, {meta2, message2, token2}} = Code.string_to_quoted(\"a.'\\\\ug'\")\n\n    assert meta2[:line] == 1\n    assert meta2[:column] == 3\n\n    assert message2 ==\n             \"invalid Unicode escape character, expected \\\\uHHHH or \\\\u{H*} where H is a hexadecimal digit. Syntax error after: \"\n\n    assert token2 == \"\\\\u\"\n\n    # Test invalid Unicode code point (surrogate pair)\n    assert {:error, {meta3, message3, token3}} = Code.string_to_quoted(\"a.'\\\\u{D800}'\")\n\n    assert meta3[:line] == 1\n    assert meta3[:column] == 3\n\n    assert message3 == \"invalid or reserved Unicode code point \\\\u{D800}. Syntax error after: \"\n    assert token3 == \"\\\\u\"\n\n    # Test Unicode code point beyond valid range\n    assert {:error, {meta4, message4, token4}} = Code.string_to_quoted(\"a.'\\\\u{110000}'\")\n\n    assert meta4[:line] == 1\n    assert meta4[:column] == 3\n\n    assert message4 == \"invalid or reserved Unicode code point \\\\u{110000}. Syntax error after: \"\n    assert token4 == \"\\\\u\"\n  end\n\n  test \"string_to_quoted returns error for invalid UTF-8 in strings\" do\n    invalid_utf8_cases = [\n      # charlist\n      \"'\\\\xFF'\",\n      # charlist heredoc\n      \"'''\\n\\\\xFF\\\\\\n'''\"\n    ]\n\n    for code <- invalid_utf8_cases do\n      assert {:error, {_, message, _}} = Code.string_to_quoted(code)\n      assert message =~ \"invalid encoding starting at <<255>>\"\n    end\n  end\n\n  test \"string_to_quoted returns error for invalid UTF-8 in quoted atoms and function calls\" do\n    invalid_utf8_cases = [\n      # charlist\n      # ~S{'\\xFF'},\n      # charlist heredoc\n      # ~s{'''\\n\\xFF\\n'''},\n      # Quoted atom\n      ~S{:\"\\xFF\"},\n      ~S{:'\\xFF'},\n      # Quoted keyword identifier\n      ~S{[\"\\xFF\": 1]},\n      ~S{['\\xFF': 1]},\n      # Quoted function call\n      ~S{foo.\"\\xFF\"()},\n      ~S{foo.'\\xFF'()}\n    ]\n\n    for code <- invalid_utf8_cases do\n      assert {:error, {_, message, detail}} = Code.string_to_quoted(code)\n      assert message =~ \"invalid encoding in atom: \"\n      assert detail =~ \"invalid encoding starting at <<255>>\"\n\n      assert {:error, {_, message, detail}} =\n               Code.string_to_quoted(code, existing_atoms_only: true)\n\n      assert message =~ \"invalid encoding in atom: \"\n      assert detail =~ \"invalid encoding starting at <<255>>\"\n    end\n  end\n\n  @tag :requires_source\n  test \"compile source\" do\n    assert __MODULE__.__info__(:compile)[:source] == String.to_charlist(__ENV__.file)\n  end\n\n  describe \"compile_string/1\" do\n    test \"compiles the given string\" do\n      assert [{CompileStringSample, _}] =\n               Code.compile_string(\"defmodule CompileStringSample, do: :ok\")\n    after\n      :code.purge(CompileSimpleSample)\n      :code.delete(CompileSimpleSample)\n    end\n\n    test \"works across lexical scopes\" do\n      assert [{CompileCrossSample, _}] =\n               Code.compile_string(\"CodeTest.genmodule CompileCrossSample\")\n    after\n      :code.purge(CompileCrossSample)\n      :code.delete(CompileCrossSample)\n    end\n\n    test \"disables tail call optimization at the root\" do\n      try do\n        Code.compile_string(\"List.flatten(123)\")\n      rescue\n        _ -> assert Enum.any?(__STACKTRACE__, &match?({_, :__FILE__, 1, _}, &1))\n      end\n    end\n  end\n\n  test \"format_string/2 returns empty iodata for empty string\" do\n    assert Code.format_string!(\"\") == \"\"\n  end\n\n  test \"ensure_loaded?/1\" do\n    assert Code.ensure_loaded?(__MODULE__)\n    refute Code.ensure_loaded?(Code.NoFile)\n  end\n\n  test \"ensure_loaded!/1\" do\n    assert Code.ensure_loaded!(__MODULE__) == __MODULE__\n\n    assert_raise ArgumentError, \"could not load module Code.NoFile due to reason :nofile\", fn ->\n      Code.ensure_loaded!(Code.NoFile)\n    end\n  end\n\n  test \"ensure_all_loaded/1\" do\n    assert Code.ensure_all_loaded([__MODULE__]) == :ok\n    assert Code.ensure_all_loaded([__MODULE__, Kernel]) == :ok\n\n    assert {:error, [error]} = Code.ensure_all_loaded([__MODULE__, Code.NoFile, __MODULE__])\n    assert error == {Code.NoFile, :nofile}\n  end\n\n  test \"ensure_all_loaded!/1\" do\n    assert Code.ensure_all_loaded!([__MODULE__]) == :ok\n    assert Code.ensure_all_loaded!([__MODULE__, Kernel]) == :ok\n\n    message = \"\"\"\n    could not load the following modules:\n\n      * Code.NoFile due to reason :nofile\n      * Code.OtherNoFile due to reason :nofile\\\n    \"\"\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.ensure_all_loaded!([__MODULE__, Code.NoFile, Code.OtherNoFile])\n    end\n  end\n\n  test \"ensure_compiled/1\" do\n    assert Code.ensure_compiled(__MODULE__) == {:module, __MODULE__}\n    assert Code.ensure_compiled(Code.NoFile) == {:error, :nofile}\n  end\n\n  test \"ensure_compiled!/1\" do\n    assert Code.ensure_compiled!(__MODULE__) == __MODULE__\n\n    assert_raise ArgumentError, \"could not load module Code.NoFile due to reason :nofile\", fn ->\n      Code.ensure_compiled!(Code.NoFile)\n    end\n  end\n\n  test \"put_compiler_option/2 validates options\" do\n    message = \"unknown compiler option: :not_a_valid_option\"\n\n    assert_raise RuntimeError, message, fn ->\n      Code.put_compiler_option(:not_a_valid_option, :foo)\n    end\n\n    message = \"compiler option :debug_info should be a boolean, got: :not_a_boolean\"\n\n    assert_raise RuntimeError, message, fn ->\n      Code.put_compiler_option(:debug_info, :not_a_boolean)\n    end\n  end\n\n  describe \"fetch_docs/1\" do\n    test \"is case sensitive\" do\n      assert {:docs_v1, _, :elixir, _, %{\"en\" => module_doc}, _, _} = Code.fetch_docs(IO)\n\n      assert \"Functions handling input/output (IO).\" =\n               module_doc |> String.split(\"\\n\") |> Enum.at(0)\n\n      assert Code.fetch_docs(Io) == {:error, :module_not_found}\n    end\n  end\n\n  defp assert_exception(ex, messages, callback) do\n    e =\n      assert_raise ex, fn ->\n        callback.()\n      end\n\n    error_msg = Exception.format(:error, e, [])\n\n    for msg <- messages do\n      assert error_msg =~ msg\n    end\n  end\nend\n\ndefmodule Code.SyncTest do\n  use ExUnit.Case\n\n  import PathHelpers\n\n  defp assert_cached(path) do\n    assert find_path(path) != :nocache\n  end\n\n  defp refute_cached(path) do\n    assert find_path(path) == :nocache\n  end\n\n  defp find_path(path) do\n    {:status, _, {:module, :code_server}, [_, :running, _, _, state]} =\n      :sys.get_status(:code_server)\n\n    [:state, _, _otp_root, paths | _] = Tuple.to_list(state)\n    {_, value} = List.keyfind(paths, to_charlist(path), 0)\n    value\n  end\n\n  test \"evaluates module definitions\" do\n    Code.put_compiler_option(:module_definition, :interpreted)\n\n    defmodule CodeTest.EvalModule do\n      {:current_stacktrace, stacktrace} = Process.info(self(), :current_stacktrace)\n      assert Enum.find(stacktrace, &(elem(&1, 0) == :erl_eval))\n    end\n  after\n    Code.put_compiler_option(:module_definition, :compiled)\n  end\n\n  test \"evaluates module definitions with stacktraces\" do\n    Code.put_compiler_option(:module_definition, :interpreted)\n\n    try do\n      defmodule CodeTest.EvalModuleRaise do\n        Enum.map(1..10, fn x -> x <> \"example\" end)\n      end\n    rescue\n      e ->\n        assert e.__struct__ == ArgumentError\n        assert Enum.find(__STACKTRACE__, &(elem(&1, 0) == Code.SyncTest.CodeTest.EvalModuleRaise))\n        assert Enum.find(__STACKTRACE__, &(elem(&1, 0) == :erl_eval))\n    else\n      _ -> flunk(\"defmodule should have failed\")\n    end\n  after\n    Code.put_compiler_option(:module_definition, :compiled)\n  end\n\n  test \"prepend_path\" do\n    path = Path.join(__DIR__, \"fixtures\")\n    true = Code.prepend_path(path)\n    assert to_charlist(path) in :code.get_path()\n    refute_cached(path)\n\n    true = Code.prepend_path(path, cache: true)\n    assert_cached(path)\n\n    Code.delete_path(path)\n    refute to_charlist(path) in :code.get_path()\n  end\n\n  test \"append_path\" do\n    path = Path.join(__DIR__, \"fixtures\")\n    true = Code.append_path(path)\n    assert to_charlist(path) in :code.get_path()\n    refute_cached(path)\n\n    true = Code.append_path(path, cache: true)\n    assert_cached(path)\n\n    Code.delete_path(path)\n    refute to_charlist(path) in :code.get_path()\n  end\n\n  test \"prepend_paths\" do\n    path = Path.join(__DIR__, \"fixtures\")\n    :ok = Code.prepend_paths([path])\n    assert to_charlist(path) in :code.get_path()\n    refute_cached(path)\n\n    :ok = Code.prepend_paths([path], cache: true)\n    assert_cached(path)\n\n    Code.delete_paths([path])\n    refute to_charlist(path) in :code.get_path()\n  end\n\n  test \"append_paths\" do\n    path = Path.join(__DIR__, \"fixtures\")\n    :ok = Code.append_paths([path])\n    assert to_charlist(path) in :code.get_path()\n    refute_cached(path)\n\n    :ok = Code.append_paths([path], cache: true)\n    assert_cached(path)\n\n    Code.delete_paths([path])\n    refute to_charlist(path) in :code.get_path()\n  end\n\n  test \"returns previous options when setting compiler options\" do\n    Code.compiler_options(debug_info: false)\n    assert Code.compiler_options(debug_info: true) == %{debug_info: false}\n  after\n    Code.compiler_options(debug_info: true)\n  end\n\n  test \"compile_file/1 return value\" do\n    assert [{CompileSample, binary}] = Code.compile_file(fixture_path(\"compile_sample.ex\"))\n    assert is_binary(binary)\n  after\n    :code.purge(CompileSample)\n    :code.delete(CompileSample)\n  end\n\n  test \"require_file/1 return value\" do\n    assert [{CompileSample, binary}] = Code.require_file(fixture_path(\"compile_sample.ex\"))\n    assert is_binary(binary)\n  after\n    Code.unrequire_files([fixture_path(\"compile_sample.ex\")])\n    :code.purge(CompileSample)\n    :code.delete(CompileSample)\n  end\n\n  test \"purges compiler modules\" do\n    quoted = quote(do: :ok)\n    Code.compile_quoted(quoted)\n\n    {:ok, claimed} = Code.purge_compiler_modules()\n    assert claimed > 0\n\n    {:ok, claimed} = Code.purge_compiler_modules()\n    assert claimed == 0\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/collectable_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule CollectableTest do\n  use ExUnit.Case, async: true\n\n  doctest Collectable\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/config/provider_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Config.ProviderTest do\n  use ExUnit.Case\n\n  doctest Config.Provider\n  alias Config.Provider\n  import PathHelpers\n  import ExUnit.CaptureIO\n\n  @tmp_path tmp_path(\"config_provider\")\n  @env_var \"ELIXIR_CONFIG_PROVIDER_BOOTED\"\n  @sys_config Path.join(@tmp_path, \"sys.config\")\n\n  setup context do\n    File.rm_rf(@tmp_path)\n    File.mkdir_p!(@tmp_path)\n    write_sys_config!(context[:sys_config] || [])\n\n    on_exit(fn ->\n      Application.delete_env(:elixir, :config_provider_init)\n      Application.delete_env(:elixir, :config_provider_booted)\n      System.delete_env(@env_var)\n    end)\n  end\n\n  test \"validate_compile_env\" do\n    assert Config.Provider.validate_compile_env([{:elixir, [:unknown], :error}]) == :ok\n\n    Application.put_env(:elixir, :unknown, nested: [key: :value])\n\n    assert Config.Provider.validate_compile_env([\n             {:elixir, [:unknown], {:ok, [nested: [key: :value]]}}\n           ]) == :ok\n\n    assert Config.Provider.validate_compile_env([\n             {:elixir, [:unknown, :nested], {:ok, [key: :value]}}\n           ]) == :ok\n\n    assert Config.Provider.validate_compile_env([\n             {:elixir, [:unknown, :nested, :key], {:ok, :value}}\n           ]) == :ok\n\n    assert Config.Provider.validate_compile_env([\n             {:elixir, [:unknown, :nested, :unknown], :error}\n           ]) == :ok\n\n    assert {:error, msg} =\n             Config.Provider.validate_compile_env([{:elixir, [:unknown, :nested], :error}])\n\n    assert msg =~ \"Compile time value was not set\"\n\n    assert {:error, msg} =\n             Config.Provider.validate_compile_env([\n               {:elixir, [:unknown, :nested], {:ok, :another}}\n             ])\n\n    assert msg =~ \"Compile time value was set to: :another\"\n\n    keys = [:unknown, :nested, :key, :too_deep]\n\n    assert {:error, msg} =\n             Config.Provider.validate_compile_env([{:elixir, keys, :error}])\n\n    assert msg =~\n             \"application :elixir failed reading its compile environment for path [:nested, :key, :too_deep] inside key :unknown\"\n  after\n    Application.delete_env(:elixir, :unknown)\n  end\n\n  describe \"config_path\" do\n    test \"validate!\" do\n      assert Provider.validate_config_path!(\"/foo\") == :ok\n      assert Provider.validate_config_path!({:system, \"foo\", \"bar\"}) == :ok\n\n      assert_raise ArgumentError, fn -> Provider.validate_config_path!({:system, 1, 2}) end\n      assert_raise ArgumentError, fn -> Provider.validate_config_path!(~c\"baz\") end\n    end\n\n    test \"resolve!\" do\n      env_var = \"ELIXIR_CONFIG_PROVIDER_PATH\"\n\n      try do\n        System.put_env(env_var, @tmp_path)\n        assert Provider.resolve_config_path!(\"/foo\") == \"/foo\"\n        assert Provider.resolve_config_path!({:system, env_var, \"/bar\"}) == @tmp_path <> \"/bar\"\n      after\n        System.delete_env(env_var)\n      end\n    end\n  end\n\n  describe \"boot\" do\n    test \"runs providers\" do\n      init_and_assert_boot()\n      config = consult(@sys_config)\n      assert config[:my_app] == [key: :value]\n      assert config[:elixir] == [config_provider_booted: {:booted, nil}]\n    end\n\n    @tag sys_config: [my_app: [encoding: {:_μ, :\"£\", \"£\", ~c\"£\"}]]\n    test \"writes sys_config with encoding\" do\n      init_and_assert_boot()\n      config = consult(@sys_config)\n      assert config[:my_app][:encoding] == {:_μ, :\"£\", \"£\", ~c\"£\"}\n    end\n\n    @tag sys_config: [my_app: [key: :old_value, sys_key: :sys_value, extra_config: :old_value]]\n    test \"writes extra config with overrides\" do\n      init_and_assert_boot(extra_config: [my_app: [key: :old_extra_value, extra_config: :value]])\n\n      assert consult(@sys_config)[:my_app] ==\n               [sys_key: :sys_value, extra_config: :value, key: :value]\n    end\n\n    test \"returns :booted if already booted and keeps config file\" do\n      init_and_assert_boot()\n      Application.put_all_env(Keyword.take(consult(@sys_config), [:elixir]))\n      assert boot() == :booted\n      refute_received :restart\n      assert File.exists?(@sys_config)\n    end\n\n    test \"returns :booted if already booted and prunes config file\" do\n      init_and_assert_boot(prune_runtime_sys_config_after_boot: true)\n      Application.put_all_env(Keyword.take(consult(@sys_config), [:elixir]))\n      assert boot() == :booted\n      refute_received :restart\n      refute File.exists?(@sys_config)\n    end\n\n    test \"returns :booted if already booted and runs validate_compile_env\" do\n      init_and_assert_boot(\n        prune_runtime_sys_config_after_boot: true,\n        validate_compile_env: [{:elixir, [:unknown], {:ok, :value}}]\n      )\n\n      Application.put_all_env(Keyword.take(consult(@sys_config), [:elixir]))\n\n      assert capture_abort(fn -> boot() end) =~\n               \"the application :elixir has a different value set for key :unknown\"\n    end\n\n    test \"returns without rebooting\" do\n      reader = {Config.Reader, fixture_path(\"configs/kernel.exs\")}\n      init = Config.Provider.init([reader], @sys_config, reboot_system_after_config: false)\n      Application.put_all_env(init)\n\n      assert capture_abort(fn ->\n               Provider.boot(fn ->\n                 raise \"should not be called\"\n               end)\n             end) =~\n               \"Cannot configure :kernel because :reboot_system_after_config has been set to false\"\n\n      # Make sure values before and after match\n      write_sys_config!(kernel: [elixir_reboot: true])\n      Application.put_all_env(init)\n      System.delete_env(@env_var)\n\n      Provider.boot(fn -> raise \"should not be called\" end)\n      assert Application.get_env(:kernel, :elixir_reboot) == true\n      assert Application.get_env(:elixir_reboot, :key) == :value\n    end\n  end\n\n  defp init(opts) do\n    reader = {Config.Reader, fixture_path(\"configs/good_config.exs\")}\n    init = Config.Provider.init([reader], Keyword.get(opts, :path, @sys_config), opts)\n    Application.put_all_env(init)\n    init\n  end\n\n  defp boot do\n    Provider.boot(fn -> send(self(), :restart) end)\n  end\n\n  defp init_and_assert_boot(opts \\\\ []) do\n    init(opts ++ [reboot_system_after_config: true])\n    boot()\n    assert_received :restart\n  end\n\n  defp consult(file) do\n    {:ok, [config]} = :file.consult(file)\n    config\n  end\n\n  defp capture_abort(fun) do\n    capture_io(fn ->\n      assert_raise ErlangError, fun\n    end)\n  end\n\n  defp write_sys_config!(data) do\n    File.write!(@sys_config, IO.chardata_to_string(:io_lib.format(\"~tw.~n\", [data])))\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/config/reader_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Config.ReaderTest do\n  use ExUnit.Case, async: true\n\n  doctest Config.Reader\n  import PathHelpers\n\n  test \"read_imports!/2\" do\n    assert Config.Reader.read_imports!(fixture_path(\"configs/good_kw.exs\")) ==\n             {[my_app: [key: :value]], [fixture_path(\"configs/good_kw.exs\")]}\n\n    assert Config.Reader.read_imports!(fixture_path(\"configs/good_config.exs\")) ==\n             {[my_app: [key: :value]], [fixture_path(\"configs/good_config.exs\")]}\n\n    assert Config.Reader.read_imports!(fixture_path(\"configs/good_import.exs\")) ==\n             {[my_app: [key: :value]],\n              [fixture_path(\"configs/good_config.exs\"), fixture_path(\"configs/good_import.exs\")]}\n\n    assert_raise ArgumentError,\n                 \":imports must be a list of paths\",\n                 fn -> Config.Reader.read_imports!(\"config\", imports: :disabled) end\n\n    assert_raise File.Error,\n                 fn -> Config.Reader.read_imports!(fixture_path(\"configs/bad_root.exs\")) end\n\n    assert_raise File.Error,\n                 fn -> Config.Reader.read_imports!(fixture_path(\"configs/bad_import.exs\")) end\n  end\n\n  test \"read!/2\" do\n    assert Config.Reader.read!(fixture_path(\"configs/good_kw.exs\")) ==\n             [my_app: [key: :value]]\n\n    assert Config.Reader.read!(fixture_path(\"configs/good_config.exs\")) ==\n             [my_app: [key: :value]]\n\n    assert Config.Reader.read!(fixture_path(\"configs/good_import.exs\")) ==\n             [my_app: [key: :value]]\n\n    assert Config.Reader.read!(fixture_path(\"configs/env.exs\"), env: :dev, target: :host) ==\n             [my_app: [env: :dev, target: :host]]\n\n    assert Config.Reader.read!(fixture_path(\"configs/env.exs\"), env: :prod, target: :embedded) ==\n             [my_app: [env: :prod, target: :embedded]]\n\n    assert_raise ArgumentError,\n                 ~r\"expected config for app :sample in .*/bad_app.exs to return keyword list\",\n                 fn -> Config.Reader.read!(fixture_path(\"configs/bad_app.exs\")) end\n\n    assert_raise RuntimeError, \"no :env key was given to this configuration file\", fn ->\n      Config.Reader.read!(fixture_path(\"configs/env.exs\"))\n    end\n\n    assert_raise RuntimeError, \"no :target key was given to this configuration file\", fn ->\n      Config.Reader.read!(fixture_path(\"configs/env.exs\"), env: :prod)\n    end\n\n    assert_raise RuntimeError,\n                 ~r\"import_config/1 is not enabled for this configuration file\",\n                 fn ->\n                   Config.Reader.read!(fixture_path(\"configs/good_import.exs\"),\n                     imports: :disabled\n                   )\n                 end\n  end\n\n  test \"eval!/3\" do\n    files = [\"configs/good_kw.exs\", \"configs/good_config.exs\", \"configs/good_import.exs\"]\n\n    for file <- files do\n      file = fixture_path(file)\n      assert Config.Reader.read!(file) == Config.Reader.eval!(file, File.read!(file))\n    end\n\n    file = fixture_path(\"configs/env.exs\")\n\n    assert Config.Reader.read!(file, env: :dev, target: :host) ==\n             Config.Reader.eval!(file, File.read!(file), env: :dev, target: :host)\n  end\n\n  test \"as a provider\" do\n    state = Config.Reader.init(fixture_path(\"configs/good_config.exs\"))\n    assert Config.Reader.load([my_app: [key: :old_value]], state) == [my_app: [key: :value]]\n\n    state = Config.Reader.init(path: fixture_path(\"configs/env.exs\"), env: :prod, target: :host)\n\n    assert Config.Reader.load([my_app: [env: :dev]], state) ==\n             [my_app: [env: :prod, target: :host]]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/config_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule ConfigTest do\n  use ExUnit.Case, async: true\n\n  doctest Config\n  import Config\n  import PathHelpers\n\n  setup config do\n    Process.put({Config, :opts}, {config[:env], config[:target]})\n    Process.put({Config, :config}, [])\n    Process.put({Config, :imports}, config[:imports] || [])\n    :ok\n  end\n\n  defp config do\n    Process.get({Config, :config})\n  end\n\n  defp files do\n    Process.get({Config, :imports})\n  end\n\n  test \"config/2\" do\n    assert config() == []\n\n    config :lager, key: :value\n    assert config() == [lager: [key: :value]]\n\n    config :lager, other: :value\n    assert config() == [lager: [key: :value, other: :value]]\n\n    config :lager, key: :other\n    assert config() == [lager: [other: :value, key: :other]]\n\n    # Works inside functions too...\n    f = fn -> config(:lager, key: :fn) end\n    f.()\n    assert config() == [lager: [other: :value, key: :fn]]\n\n    # ...and in for comprehensions.\n    for _ <- 0..0, do: config(:lager, key: :for)\n    assert config() == [lager: [other: :value, key: :for]]\n  end\n\n  test \"config/3\" do\n    config :app, Repo, key: :value\n    assert config() == [app: [{Repo, key: :value}]]\n\n    config :app, Repo, other: :value\n    assert config() == [app: [{Repo, key: :value, other: :value}]]\n\n    config :app, Repo, key: :other\n    assert config() == [app: [{Repo, other: :value, key: :other}]]\n\n    config :app, Repo, key: [nested: false]\n    assert config() == [app: [{Repo, other: :value, key: [nested: false]}]]\n\n    config :app, Repo, key: [nested: true]\n    assert config() == [app: [{Repo, other: :value, key: [nested: true]}]]\n\n    config :app, Repo, key: :other\n    assert config() == [app: [{Repo, other: :value, key: :other}]]\n  end\n\n  test \"read_config/1\" do\n    assert read_config(:lager) == nil\n\n    config :lager, key: :value\n    assert read_config(:lager) == [key: :value]\n\n    config :lager, other: :value\n    assert read_config(:lager) == [key: :value, other: :value]\n  end\n\n  @tag env: :dev\n  test \"config_env/0\" do\n    assert config_env() == :dev\n  end\n\n  test \"config_env/0 raises if no env is set\" do\n    assert_raise RuntimeError, \"no :env key was given to this configuration file\", fn ->\n      config_env()\n    end\n  end\n\n  @tag target: :host\n  test \"config_target/0\" do\n    assert config_target() == :host\n  end\n\n  test \"config_target/0 raises if no env is set\" do\n    assert_raise RuntimeError, \"no :target key was given to this configuration file\", fn ->\n      config_target()\n    end\n  end\n\n  test \"import_config/1\" do\n    import_config fixture_path(\"configs/good_config.exs\")\n    assert config() == [my_app: [key: :value]]\n    assert files() == [fixture_path(\"configs/good_config.exs\")]\n  end\n\n  @tag imports: :disabled\n  test \"import_config/1 raises when disabled\" do\n    assert_raise RuntimeError,\n                 ~r\"import_config/1 is not enabled for this configuration file\",\n                 fn -> import_config fixture_path(\"configs/good_config.exs\") end\n  end\n\n  test \"import_config/1 raises for recursive import\" do\n    assert_raise ArgumentError,\n                 ~r\"attempting to load configuration .*/imports_recursive.exs recursively\",\n                 fn -> import_config fixture_path(\"configs/imports_recursive.exs\") end\n  end\n\n  test \"import_config/1 with nested\" do\n    config :app, Repo, key: [nested: false, other: true]\n    import_config fixture_path(\"configs/nested.exs\")\n    assert config() == [app: [{Repo, key: [other: true, nested: true]}]]\n  end\n\n  test \"import_config/1 with bad path\" do\n    assert_raise File.Error, ~r\"could not read file .*/configs/unknown.exs\", fn ->\n      import_config fixture_path(\"configs/unknown.exs\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/dynamic_supervisor_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule DynamicSupervisorTest do\n  use ExUnit.Case, async: true\n\n  defmodule Simple do\n    use DynamicSupervisor\n\n    def init(args), do: args\n  end\n\n  test \"can be supervised directly\" do\n    children = [{DynamicSupervisor, name: :dyn_sup_spec_test}]\n    assert {:ok, _} = Supervisor.start_link(children, strategy: :one_for_one)\n    assert DynamicSupervisor.which_children(:dyn_sup_spec_test) == []\n  end\n\n  test \"multiple supervisors can be supervised and identified with simple child spec\" do\n    {:ok, _} = Registry.start_link(keys: :unique, name: DynSup.Registry)\n\n    children = [\n      {DynamicSupervisor, name: :simple_name},\n      {DynamicSupervisor, name: {:global, :global_name}},\n      {DynamicSupervisor, name: {:via, Registry, {DynSup.Registry, \"via_name\"}}}\n    ]\n\n    assert {:ok, supsup} = Supervisor.start_link(children, strategy: :one_for_one)\n\n    assert {:ok, no_name_dynsup} =\n             Supervisor.start_child(supsup, {DynamicSupervisor, strategy: :one_for_one})\n\n    assert DynamicSupervisor.which_children(:simple_name) == []\n    assert DynamicSupervisor.which_children({:global, :global_name}) == []\n    assert DynamicSupervisor.which_children({:via, Registry, {DynSup.Registry, \"via_name\"}}) == []\n    assert DynamicSupervisor.which_children(no_name_dynsup) == []\n\n    assert Supervisor.start_child(supsup, {DynamicSupervisor, strategy: :one_for_one}) ==\n             {:error, {:already_started, no_name_dynsup}}\n  end\n\n  describe \"use/2\" do\n    test \"generates child_spec/1\" do\n      assert Simple.child_spec([:hello]) == %{\n               id: Simple,\n               start: {Simple, :start_link, [[:hello]]},\n               type: :supervisor\n             }\n\n      defmodule Custom do\n        use DynamicSupervisor,\n          id: :id,\n          restart: :temporary,\n          shutdown: :infinity,\n          start: {:foo, :bar, []}\n\n        def init(arg), do: {:producer, arg}\n      end\n\n      assert Custom.child_spec([:hello]) == %{\n               id: :id,\n               restart: :temporary,\n               shutdown: :infinity,\n               start: {:foo, :bar, []},\n               type: :supervisor\n             }\n    end\n  end\n\n  describe \"init/1\" do\n    test \"set default options\" do\n      assert DynamicSupervisor.init([]) ==\n               {:ok,\n                %{\n                  strategy: :one_for_one,\n                  intensity: 3,\n                  period: 5,\n                  max_children: :infinity,\n                  extra_arguments: []\n                }}\n    end\n  end\n\n  describe \"start_link/3\" do\n    test \"with non-ok init\" do\n      Process.flag(:trap_exit, true)\n\n      assert DynamicSupervisor.start_link(Simple, {:ok, %{strategy: :unknown}}) ==\n               {:error, {:supervisor_data, {:invalid_strategy, :unknown}}}\n\n      assert DynamicSupervisor.start_link(Simple, {:ok, %{intensity: -1}}) ==\n               {:error, {:supervisor_data, {:invalid_intensity, -1}}}\n\n      assert DynamicSupervisor.start_link(Simple, {:ok, %{period: 0}}) ==\n               {:error, {:supervisor_data, {:invalid_period, 0}}}\n\n      assert DynamicSupervisor.start_link(Simple, {:ok, %{max_children: -1}}) ==\n               {:error, {:supervisor_data, {:invalid_max_children, -1}}}\n\n      assert DynamicSupervisor.start_link(Simple, {:ok, %{extra_arguments: -1}}) ==\n               {:error, {:supervisor_data, {:invalid_extra_arguments, -1}}}\n\n      assert DynamicSupervisor.start_link(Simple, {:ok, %{auto_shutdown: :any_significant}}) ==\n               {:error, {:supervisor_data, {:invalid_auto_shutdown, :any_significant}}}\n\n      assert DynamicSupervisor.start_link(Simple, :unknown) ==\n               {:error, {:bad_return, {Simple, :init, :unknown}}}\n\n      assert DynamicSupervisor.start_link(Simple, :ignore) == :ignore\n    end\n\n    test \"with registered process\" do\n      {:ok, pid} = DynamicSupervisor.start_link(Simple, {:ok, %{}}, name: __MODULE__)\n\n      # Sets up a link\n      {:links, links} = Process.info(self(), :links)\n      assert pid in links\n\n      # A name\n      assert Process.whereis(__MODULE__) == pid\n\n      # And the initial call\n      assert {:supervisor, DynamicSupervisorTest.Simple, 1} =\n               :proc_lib.translate_initial_call(pid)\n\n      # And shuts down\n      assert DynamicSupervisor.stop(__MODULE__) == :ok\n    end\n\n    test \"with spawn_opt\" do\n      {:ok, pid} =\n        DynamicSupervisor.start_link(strategy: :one_for_one, spawn_opt: [priority: :high])\n\n      assert Process.info(pid, :priority) == {:priority, :high}\n    end\n\n    test \"sets initial call to the same as a regular supervisor\" do\n      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n      assert :proc_lib.initial_call(pid) == {:supervisor, Supervisor.Default, [:Argument__1]}\n\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n      assert :proc_lib.initial_call(pid) == {:supervisor, Supervisor.Default, [:Argument__1]}\n    end\n  end\n\n  ## Code change\n\n  describe \"code_change/3\" do\n    test \"with non-ok init\" do\n      {:ok, pid} = DynamicSupervisor.start_link(Simple, {:ok, %{}})\n\n      assert fake_upgrade(pid, {:ok, %{strategy: :unknown}}) ==\n               {:error, {:error, {:supervisor_data, {:invalid_strategy, :unknown}}}}\n\n      assert fake_upgrade(pid, {:ok, %{intensity: -1}}) ==\n               {:error, {:error, {:supervisor_data, {:invalid_intensity, -1}}}}\n\n      assert fake_upgrade(pid, {:ok, %{period: 0}}) ==\n               {:error, {:error, {:supervisor_data, {:invalid_period, 0}}}}\n\n      assert fake_upgrade(pid, {:ok, %{max_children: -1}}) ==\n               {:error, {:error, {:supervisor_data, {:invalid_max_children, -1}}}}\n\n      assert fake_upgrade(pid, :unknown) == {:error, :unknown}\n      assert fake_upgrade(pid, :ignore) == :ok\n    end\n\n    test \"with ok init\" do\n      {:ok, pid} = DynamicSupervisor.start_link(Simple, {:ok, %{}})\n      {:ok, _} = DynamicSupervisor.start_child(pid, sleepy_worker())\n      assert %{active: 1} = DynamicSupervisor.count_children(pid)\n\n      assert fake_upgrade(pid, {:ok, %{max_children: 1}}) == :ok\n      assert %{active: 1} = DynamicSupervisor.count_children(pid)\n      assert DynamicSupervisor.start_child(pid, {Task, fn -> :ok end}) == {:error, :max_children}\n    end\n\n    defp fake_upgrade(pid, init_arg) do\n      :ok = :sys.suspend(pid)\n      :sys.replace_state(pid, fn state -> %{state | args: init_arg} end)\n      res = :sys.change_code(pid, :gen_server, 123, :extra)\n      :ok = :sys.resume(pid)\n      res\n    end\n  end\n\n  describe \"start_child/2\" do\n    test \"supports old child spec\" do\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n      child = {Task, {Task, :start_link, [fn -> :ok end]}, :temporary, 5000, :worker, [Task]}\n      assert {:ok, pid} = DynamicSupervisor.start_child(pid, child)\n      assert is_pid(pid)\n    end\n\n    test \"supports new child spec as tuple\" do\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n      child = %{id: Task, restart: :temporary, start: {Task, :start_link, [fn -> :ok end]}}\n      assert {:ok, pid} = DynamicSupervisor.start_child(pid, child)\n      assert is_pid(pid)\n    end\n\n    test \"supports new child spec\" do\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n      child = {Task, fn -> Process.sleep(:infinity) end}\n      assert {:ok, pid} = DynamicSupervisor.start_child(pid, child)\n      assert is_pid(pid)\n    end\n\n    test \"supports extra arguments\" do\n      parent = self()\n      fun = fn -> send(parent, :from_child) end\n\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, extra_arguments: [fun])\n      child = %{id: Task, restart: :temporary, start: {Task, :start_link, []}}\n      assert {:ok, pid} = DynamicSupervisor.start_child(pid, child)\n      assert is_pid(pid)\n      assert_receive :from_child\n    end\n\n    test \"with invalid child spec\" do\n      assert DynamicSupervisor.start_child(:not_used, %{}) == {:error, {:invalid_child_spec, %{}}}\n\n      assert DynamicSupervisor.start_child(:not_used, {1, 2, 3, 4, 5, 6}) ==\n               {:error, {:invalid_mfa, 2}}\n\n      assert DynamicSupervisor.start_child(:not_used, %{id: 1, start: {Task, :foo, :bar}}) ==\n               {:error, {:invalid_mfa, {Task, :foo, :bar}}}\n\n      assert DynamicSupervisor.start_child(:not_used, %{\n               id: 1,\n               start: {Task, :foo, [:bar]},\n               shutdown: -1\n             }) ==\n               {:error, {:invalid_shutdown, -1}}\n\n      assert DynamicSupervisor.start_child(:not_used, %{\n               id: 1,\n               start: {Task, :foo, [:bar]},\n               significant: true\n             }) ==\n               {:error, {:invalid_significant, true}}\n    end\n\n    test \"with different returns\" do\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      assert {:ok, _, :extra} = DynamicSupervisor.start_child(pid, current_module_worker([:ok3]))\n      assert {:ok, _} = DynamicSupervisor.start_child(pid, current_module_worker([:ok2]))\n      assert :ignore = DynamicSupervisor.start_child(pid, current_module_worker([:ignore]))\n\n      assert {:error, :found} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:error]))\n\n      assert {:error, :unknown} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:unknown]))\n    end\n\n    test \"with throw/error/exit\" do\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      assert {:error, {{:nocatch, :oops}, [_ | _]}} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:non_local, :throw]))\n\n      assert {:error, {%RuntimeError{}, [_ | _]}} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:non_local, :error]))\n\n      assert {:error, :oops} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:non_local, :exit]))\n    end\n\n    test \"with max_children\" do\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, max_children: 0)\n\n      assert {:error, :max_children} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:ok2]))\n    end\n\n    test \"temporary child is not restarted regardless of reason\" do\n      child = current_module_worker([:ok2], restart: :temporary)\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :shutdown)\n      assert %{workers: 0, active: 0} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :whatever)\n      assert %{workers: 0, active: 0} = DynamicSupervisor.count_children(pid)\n    end\n\n    test \"transient child is restarted unless normal/shutdown/{shutdown, _}\" do\n      child = current_module_worker([:ok2], restart: :transient)\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :shutdown)\n      assert %{workers: 0, active: 0} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, {:shutdown, :signal})\n      assert %{workers: 0, active: 0} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :whatever)\n      assert %{workers: 1, active: 1} = DynamicSupervisor.count_children(pid)\n    end\n\n    test \"permanent child is restarted regardless of reason\" do\n      child = current_module_worker([:ok2], restart: :permanent)\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, max_restarts: 100_000)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :shutdown)\n      assert %{workers: 1, active: 1} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, {:shutdown, :signal})\n      assert %{workers: 2, active: 2} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :whatever)\n      assert %{workers: 3, active: 3} = DynamicSupervisor.count_children(pid)\n    end\n\n    test \"child is restarted with different values\" do\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, max_restarts: 100_000)\n\n      assert {:ok, child1} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:restart, :ok2]))\n\n      assert [{:undefined, ^child1, :worker, [DynamicSupervisorTest]}] =\n               DynamicSupervisor.which_children(pid)\n\n      assert_kill(child1, :shutdown)\n      assert %{workers: 1, active: 1} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child2} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:restart, :ok3]))\n\n      assert [\n               {:undefined, _, :worker, [DynamicSupervisorTest]},\n               {:undefined, ^child2, :worker, [DynamicSupervisorTest]}\n             ] = DynamicSupervisor.which_children(pid)\n\n      assert_kill(child2, :shutdown)\n      assert %{workers: 2, active: 2} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child3} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:restart, :ignore]))\n\n      assert [\n               {:undefined, _, :worker, [DynamicSupervisorTest]},\n               {:undefined, _, :worker, [DynamicSupervisorTest]},\n               {:undefined, _, :worker, [DynamicSupervisorTest]}\n             ] = DynamicSupervisor.which_children(pid)\n\n      assert_kill(child3, :shutdown)\n      assert %{workers: 2, active: 2} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child4} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:restart, :error]))\n\n      assert [\n               {:undefined, _, :worker, [DynamicSupervisorTest]},\n               {:undefined, _, :worker, [DynamicSupervisorTest]},\n               {:undefined, _, :worker, [DynamicSupervisorTest]}\n             ] = DynamicSupervisor.which_children(pid)\n\n      assert_kill(child4, :shutdown)\n      assert %{workers: 3, active: 2} = DynamicSupervisor.count_children(pid)\n\n      assert {:ok, child5} =\n               DynamicSupervisor.start_child(pid, current_module_worker([:restart, :unknown]))\n\n      assert [\n               {:undefined, _, :worker, [DynamicSupervisorTest]},\n               {:undefined, _, :worker, [DynamicSupervisorTest]},\n               {:undefined, :restarting, :worker, [DynamicSupervisorTest]},\n               {:undefined, _, :worker, [DynamicSupervisorTest]}\n             ] = DynamicSupervisor.which_children(pid)\n\n      assert_kill(child5, :shutdown)\n      assert %{workers: 4, active: 2} = DynamicSupervisor.count_children(pid)\n    end\n\n    test \"restarting on init children counted in max_children\" do\n      child = current_module_worker([:restart, :error], restart: :permanent)\n      opts = [strategy: :one_for_one, max_children: 1, max_restarts: 100_000]\n      {:ok, pid} = DynamicSupervisor.start_link(opts)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :shutdown)\n      assert %{workers: 1, active: 0} = DynamicSupervisor.count_children(pid)\n\n      child = current_module_worker([:restart, :ok2], restart: :permanent)\n      assert {:error, :max_children} = DynamicSupervisor.start_child(pid, child)\n    end\n\n    test \"restarting on exit children counted in max_children\" do\n      child = current_module_worker([:ok2], restart: :permanent)\n      opts = [strategy: :one_for_one, max_children: 1, max_restarts: 100_000]\n      {:ok, pid} = DynamicSupervisor.start_link(opts)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :shutdown)\n      assert %{workers: 1, active: 1} = DynamicSupervisor.count_children(pid)\n\n      child = current_module_worker([:ok2], restart: :permanent)\n      assert {:error, :max_children} = DynamicSupervisor.start_child(pid, child)\n    end\n\n    test \"restarting a child with extra_arguments successfully restarts child\" do\n      parent = self()\n\n      fun = fn ->\n        send(parent, :from_child)\n        Process.sleep(:infinity)\n      end\n\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one, extra_arguments: [fun])\n      child = %{id: Task, restart: :transient, start: {Task, :start_link, []}}\n\n      assert {:ok, child} = DynamicSupervisor.start_child(sup, child)\n      assert is_pid(child)\n      assert_receive :from_child\n      assert %{active: 1, workers: 1} = DynamicSupervisor.count_children(sup)\n      assert_kill(child, :oops)\n      assert_receive :from_child\n      assert %{workers: 1, active: 1} = DynamicSupervisor.count_children(sup)\n    end\n\n    test \"child is restarted when trying again\" do\n      child = current_module_worker([:try_again, self()], restart: :permanent)\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, max_restarts: 2)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_received {:try_again, true}\n      assert_kill(child_pid, :shutdown)\n      assert_receive {:try_again, false}\n      assert_receive {:try_again, true}\n      assert %{workers: 1, active: 1} = DynamicSupervisor.count_children(pid)\n    end\n\n    test \"child triggers maximum restarts\" do\n      Process.flag(:trap_exit, true)\n      child = current_module_worker([:restart, :error], restart: :permanent)\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, max_restarts: 1)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :shutdown)\n      assert_receive {:EXIT, ^pid, :shutdown}\n    end\n\n    test \"child triggers maximum intensity when trying again\" do\n      Process.flag(:trap_exit, true)\n      child = current_module_worker([:restart, :error], restart: :permanent)\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, max_restarts: 10)\n\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(pid, child)\n      assert_kill(child_pid, :shutdown)\n      assert_receive {:EXIT, ^pid, :shutdown}\n    end\n\n    test \"with valid shutdown\" do\n      Process.flag(:trap_exit, true)\n\n      {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      for n <- 0..1 do\n        assert {:ok, child_pid} =\n                 DynamicSupervisor.start_child(pid, %{\n                   id: n,\n                   start: {Task, :start_link, [fn -> Process.sleep(:infinity) end]},\n                   shutdown: n\n                 })\n\n        assert_kill(child_pid, :shutdown)\n      end\n    end\n\n    test \"with invalid valid shutdown\" do\n      assert DynamicSupervisor.start_child(:not_used, %{\n               id: 1,\n               start: {Task, :start_link, [fn -> :ok end]},\n               shutdown: -1\n             }) == {:error, {:invalid_shutdown, -1}}\n    end\n\n    def start_link(:ok3), do: {:ok, spawn_link(fn -> Process.sleep(:infinity) end), :extra}\n    def start_link(:ok2), do: {:ok, spawn_link(fn -> Process.sleep(:infinity) end)}\n    def start_link(:error), do: {:error, :found}\n    def start_link(:ignore), do: :ignore\n    def start_link(:unknown), do: :unknown\n\n    def start_link(:non_local, :throw), do: throw(:oops)\n    def start_link(:non_local, :error), do: raise(\"oops\")\n    def start_link(:non_local, :exit), do: exit(:oops)\n\n    def start_link(:try_again, notify) do\n      if Process.get(:try_again) do\n        Process.put(:try_again, false)\n        send(notify, {:try_again, false})\n        {:error, :try_again}\n      else\n        Process.put(:try_again, true)\n        send(notify, {:try_again, true})\n        start_link(:ok2)\n      end\n    end\n\n    def start_link(:restart, value) do\n      if Process.get({:restart, value}) do\n        start_link(value)\n      else\n        Process.put({:restart, value}, true)\n        start_link(:ok2)\n      end\n    end\n  end\n\n  describe \"terminate/2\" do\n    test \"terminates children with brutal kill\" do\n      Process.flag(:trap_exit, true)\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      child = sleepy_worker(shutdown: :brutal_kill)\n      assert {:ok, child1} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child2} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child3} = DynamicSupervisor.start_child(sup, child)\n\n      Process.monitor(child1)\n      Process.monitor(child2)\n      Process.monitor(child3)\n      assert_kill(sup, :shutdown)\n      assert_receive {:DOWN, _, :process, ^child1, :killed}\n      assert_receive {:DOWN, _, :process, ^child2, :killed}\n      assert_receive {:DOWN, _, :process, ^child3, :killed}\n    end\n\n    test \"terminates children with infinity shutdown\" do\n      Process.flag(:trap_exit, true)\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      child = sleepy_worker(shutdown: :infinity)\n      assert {:ok, child1} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child2} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child3} = DynamicSupervisor.start_child(sup, child)\n\n      Process.monitor(child1)\n      Process.monitor(child2)\n      Process.monitor(child3)\n      assert_kill(sup, :shutdown)\n      assert_receive {:DOWN, _, :process, ^child1, :shutdown}\n      assert_receive {:DOWN, _, :process, ^child2, :shutdown}\n      assert_receive {:DOWN, _, :process, ^child3, :shutdown}\n    end\n\n    test \"terminates children with infinity shutdown and abnormal reason\" do\n      Process.flag(:trap_exit, true)\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n      parent = self()\n\n      fun = fn ->\n        Process.flag(:trap_exit, true)\n        send(parent, :ready)\n        receive(do: (_ -> exit({:shutdown, :oops})))\n      end\n\n      child = Supervisor.child_spec({Task, fun}, shutdown: :infinity)\n      assert {:ok, child1} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child2} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child3} = DynamicSupervisor.start_child(sup, child)\n\n      assert_receive :ready\n      assert_receive :ready\n      assert_receive :ready\n\n      Process.monitor(child1)\n      Process.monitor(child2)\n      Process.monitor(child3)\n      assert_kill(sup, :shutdown)\n\n      assert_receive {:DOWN, _, :process, ^child1, {:shutdown, :oops}}\n      assert_receive {:DOWN, _, :process, ^child2, {:shutdown, :oops}}\n      assert_receive {:DOWN, _, :process, ^child3, {:shutdown, :oops}}\n    end\n\n    test \"terminates children with integer shutdown\" do\n      Process.flag(:trap_exit, true)\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      child = sleepy_worker(shutdown: 1000)\n      assert {:ok, child1} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child2} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child3} = DynamicSupervisor.start_child(sup, child)\n\n      Process.monitor(child1)\n      Process.monitor(child2)\n      Process.monitor(child3)\n      assert_kill(sup, :shutdown)\n      assert_receive {:DOWN, _, :process, ^child1, :shutdown}\n      assert_receive {:DOWN, _, :process, ^child2, :shutdown}\n      assert_receive {:DOWN, _, :process, ^child3, :shutdown}\n    end\n\n    test \"terminates children with integer shutdown and abnormal reason\" do\n      Process.flag(:trap_exit, true)\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n      parent = self()\n\n      fun = fn ->\n        Process.flag(:trap_exit, true)\n        send(parent, :ready)\n        receive(do: (_ -> exit({:shutdown, :oops})))\n      end\n\n      child = Supervisor.child_spec({Task, fun}, shutdown: 1000)\n      assert {:ok, child1} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child2} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child3} = DynamicSupervisor.start_child(sup, child)\n\n      assert_receive :ready\n      assert_receive :ready\n      assert_receive :ready\n\n      Process.monitor(child1)\n      Process.monitor(child2)\n      Process.monitor(child3)\n      assert_kill(sup, :shutdown)\n\n      assert_receive {:DOWN, _, :process, ^child1, {:shutdown, :oops}}\n      assert_receive {:DOWN, _, :process, ^child2, {:shutdown, :oops}}\n      assert_receive {:DOWN, _, :process, ^child3, {:shutdown, :oops}}\n    end\n\n    test \"terminates children with expired integer shutdown\" do\n      Process.flag(:trap_exit, true)\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n      parent = self()\n\n      fun = fn ->\n        Process.sleep(:infinity)\n      end\n\n      tmt = fn ->\n        Process.flag(:trap_exit, true)\n        send(parent, :ready)\n        Process.sleep(:infinity)\n      end\n\n      child_fun = Supervisor.child_spec({Task, fun}, shutdown: 1)\n      child_tmt = Supervisor.child_spec({Task, tmt}, shutdown: 1)\n      assert {:ok, child1} = DynamicSupervisor.start_child(sup, child_fun)\n      assert {:ok, child2} = DynamicSupervisor.start_child(sup, child_tmt)\n      assert {:ok, child3} = DynamicSupervisor.start_child(sup, child_fun)\n\n      assert_receive :ready\n      Process.monitor(child1)\n      Process.monitor(child2)\n      Process.monitor(child3)\n      assert_kill(sup, :shutdown)\n\n      assert_receive {:DOWN, _, :process, ^child1, :shutdown}\n      assert_receive {:DOWN, _, :process, ^child2, :killed}\n      assert_receive {:DOWN, _, :process, ^child3, :shutdown}\n    end\n\n    test \"terminates children with permanent restart and normal reason\" do\n      Process.flag(:trap_exit, true)\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n      parent = self()\n\n      fun = fn ->\n        Process.flag(:trap_exit, true)\n        send(parent, :ready)\n        receive(do: (_ -> exit(:normal)))\n      end\n\n      child = Supervisor.child_spec({Task, fun}, shutdown: :infinity, restart: :permanent)\n      assert {:ok, child1} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child2} = DynamicSupervisor.start_child(sup, child)\n      assert {:ok, child3} = DynamicSupervisor.start_child(sup, child)\n\n      assert_receive :ready\n      assert_receive :ready\n      assert_receive :ready\n\n      Process.monitor(child1)\n      Process.monitor(child2)\n      Process.monitor(child3)\n      assert_kill(sup, :shutdown)\n      assert_receive {:DOWN, _, :process, ^child1, :normal}\n      assert_receive {:DOWN, _, :process, ^child2, :normal}\n      assert_receive {:DOWN, _, :process, ^child3, :normal}\n    end\n\n    test \"terminates with mixed children\" do\n      Process.flag(:trap_exit, true)\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      assert {:ok, child1} =\n               DynamicSupervisor.start_child(sup, sleepy_worker(shutdown: :infinity))\n\n      assert {:ok, child2} =\n               DynamicSupervisor.start_child(sup, sleepy_worker(shutdown: :brutal_kill))\n\n      Process.monitor(child1)\n      Process.monitor(child2)\n      assert_kill(sup, :shutdown)\n      assert_receive {:DOWN, _, :process, ^child1, :shutdown}\n      assert_receive {:DOWN, _, :process, ^child2, :killed}\n    end\n  end\n\n  describe \"terminate_child/2\" do\n    test \"terminates child with brutal kill\" do\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      child = sleepy_worker(shutdown: :brutal_kill)\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(sup, child)\n\n      Process.monitor(child_pid)\n      assert :ok = DynamicSupervisor.terminate_child(sup, child_pid)\n      assert_receive {:DOWN, _, :process, ^child_pid, :killed}\n\n      assert {:error, :not_found} = DynamicSupervisor.terminate_child(sup, child_pid)\n      assert %{workers: 0, active: 0} = DynamicSupervisor.count_children(sup)\n    end\n\n    test \"terminates child with integer shutdown\" do\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n      child = sleepy_worker(shutdown: 1000)\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(sup, child)\n\n      Process.monitor(child_pid)\n      assert :ok = DynamicSupervisor.terminate_child(sup, child_pid)\n      assert_receive {:DOWN, _, :process, ^child_pid, :shutdown}\n\n      assert {:error, :not_found} = DynamicSupervisor.terminate_child(sup, child_pid)\n      assert %{workers: 0, active: 0} = DynamicSupervisor.count_children(sup)\n    end\n\n    test \"terminates restarting child\" do\n      {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one, max_restarts: 100_000)\n\n      child = current_module_worker([:restart, :error], restart: :permanent)\n      assert {:ok, child_pid} = DynamicSupervisor.start_child(sup, child)\n      assert_kill(child_pid, :shutdown)\n      assert :ok = DynamicSupervisor.terminate_child(sup, child_pid)\n\n      assert {:error, :not_found} = DynamicSupervisor.terminate_child(sup, child_pid)\n      assert %{workers: 0, active: 0} = DynamicSupervisor.count_children(sup)\n    end\n  end\n\n  defp sleepy_worker(opts \\\\ []) do\n    mfa = {Task, :start_link, [Process, :sleep, [:infinity]]}\n    Supervisor.child_spec(%{id: Task, start: mfa}, opts)\n  end\n\n  defp current_module_worker(args, opts \\\\ []) do\n    Supervisor.child_spec(%{id: __MODULE__, start: {__MODULE__, :start_link, args}}, opts)\n  end\n\n  defp assert_kill(pid, reason) do\n    ref = Process.monitor(pid)\n    Process.exit(pid, reason)\n    assert_receive {:DOWN, ^ref, _, _, _}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/enum_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule EnumTest do\n  use ExUnit.Case, async: true\n  doctest Enum\n\n  defp assert_runs_enumeration_only_once(enum_fun) do\n    enumerator =\n      Stream.map([:element], fn element ->\n        send(self(), element)\n        element\n      end)\n\n    enum_fun.(enumerator)\n    assert_received :element\n    refute_received :element\n  end\n\n  describe \"zip_reduce/4\" do\n    test \"two non lists\" do\n      left = %{a: 1}\n      right = %{b: 2}\n      reducer = fn {_, x}, {_, y}, acc -> [x + y | acc] end\n      assert Enum.zip_reduce(left, right, [], reducer) == [3]\n\n      # Empty Left\n      assert Enum.zip_reduce(%{}, right, [], reducer) == []\n\n      # Empty Right\n      assert Enum.zip_reduce(left, %{}, [], reducer) == []\n    end\n\n    test \"lists\" do\n      assert Enum.zip_reduce([1, 2], [3, 4], 0, fn x, y, acc -> x + y + acc end) == 10\n      assert Enum.zip_reduce([1, 2], [3, 4], [], fn x, y, acc -> [x + y | acc] end) == [6, 4]\n    end\n\n    test \"when left empty\" do\n      assert Enum.zip_reduce([], [1, 2], 0, fn x, y, acc -> x + y + acc end) == 0\n    end\n\n    test \"when right empty\" do\n      assert Enum.zip_reduce([1, 2], [], 0, fn x, y, acc -> x + y + acc end) == 0\n    end\n  end\n\n  describe \"zip_reduce/3\" do\n    test \"when enums empty\" do\n      assert Enum.zip_reduce([], 0, fn _, acc -> acc end) == 0\n    end\n\n    test \"lists work\" do\n      enums = [[1, 1], [2, 2], [3, 3]]\n      result = Enum.zip_reduce(enums, [], fn elements, acc -> [List.to_tuple(elements) | acc] end)\n      assert result == [{1, 2, 3}, {1, 2, 3}]\n    end\n\n    test \"mix and match\" do\n      enums = [[1, 2], 3..4, [5, 6]]\n      result = Enum.zip_reduce(enums, [], fn elements, acc -> [List.to_tuple(elements) | acc] end)\n      assert result == [{2, 4, 6}, {1, 3, 5}]\n    end\n  end\n\n  test \"all?/2\" do\n    assert Enum.all?([2, 4, 6])\n    refute Enum.all?([2, nil, 4])\n    assert Enum.all?([])\n\n    assert Enum.all?([2, 4, 6], fn x -> rem(x, 2) == 0 end)\n    refute Enum.all?([2, 3, 4], fn x -> rem(x, 2) == 0 end)\n  end\n\n  test \"any?/2\" do\n    refute Enum.any?([2, 4, 6], fn x -> rem(x, 2) == 1 end)\n    assert Enum.any?([2, 3, 4], fn x -> rem(x, 2) == 1 end)\n\n    refute Enum.any?([false, false, false])\n    assert Enum.any?([false, true, false])\n\n    assert Enum.any?([:foo, false, false])\n    refute Enum.any?([false, nil, false])\n\n    refute Enum.any?([])\n  end\n\n  test \"at/3\" do\n    assert Enum.at([2, 4, 6], 0) == 2\n    assert Enum.at([2, 4, 6], 2) == 6\n    assert Enum.at([2, 4, 6], 4) == nil\n    assert Enum.at([2, 4, 6], 4, :none) == :none\n    assert Enum.at([2, 4, 6], -2) == 4\n    assert Enum.at([2, 4, 6], -4) == nil\n  end\n\n  test \"chunk/3\" do\n    enum = String.to_atom(\"Elixir.Enum\")\n    assert enum.chunk(1..5, 2, 1) == Enum.chunk_every(1..5, 2, 1, :discard)\n  end\n\n  test \"chunk/4\" do\n    enum = String.to_atom(\"Elixir.Enum\")\n    assert enum.chunk(1..5, 2, 1, nil) == Enum.chunk_every(1..5, 2, 1, :discard)\n  end\n\n  test \"chunk_every/2\" do\n    assert Enum.chunk_every([1, 2, 3, 4, 5], 2) == [[1, 2], [3, 4], [5]]\n  end\n\n  test \"chunk_every/4\" do\n    assert Enum.chunk_every([1, 2, 3, 4, 5], 2, 2, [6]) == [[1, 2], [3, 4], [5, 6]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, :discard) == [[1, 2, 3], [3, 4, 5]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5, 6], 2, 3, :discard) == [[1, 2], [4, 5]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, []) == [[1, 2, 3], [3, 4, 5], [5, 6]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 3, []) == [[1, 2, 3], [4, 5, 6]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5], 4, 4, 6..10) == [[1, 2, 3, 4], [5, 6, 7, 8]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5], 2, 3, []) == [[1, 2], [4, 5]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5, 6], 2, 3, []) == [[1, 2], [4, 5]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5, 6, 7], 2, 3, []) == [[1, 2], [4, 5], [7]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5, 6, 7], 2, 3, [8]) == [[1, 2], [4, 5], [7, 8]]\n    assert Enum.chunk_every([1, 2, 3, 4, 5, 6, 7], 2, 4, []) == [[1, 2], [5, 6]]\n  end\n\n  test \"chunk_by/2\" do\n    assert Enum.chunk_by([1, 2, 2, 3, 4, 4, 6, 7, 7], &(rem(&1, 2) == 1)) ==\n             [[1], [2, 2], [3], [4, 4, 6], [7, 7]]\n\n    assert Enum.chunk_by([1, 2, 3, 4], fn _ -> true end) == [[1, 2, 3, 4]]\n    assert Enum.chunk_by([], fn _ -> true end) == []\n    assert Enum.chunk_by([1], fn _ -> true end) == [[1]]\n  end\n\n  test \"chunk_while/4\" do\n    chunk_fun = fn i, acc ->\n      cond do\n        i > 10 ->\n          {:halt, acc}\n\n        rem(i, 2) == 0 ->\n          {:cont, Enum.reverse([i | acc]), []}\n\n        true ->\n          {:cont, [i | acc]}\n      end\n    end\n\n    after_fun = fn\n      [] -> {:cont, []}\n      acc -> {:cont, Enum.reverse(acc), []}\n    end\n\n    assert Enum.chunk_while([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [], chunk_fun, after_fun) ==\n             [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]\n\n    assert Enum.chunk_while(0..9, [], chunk_fun, after_fun) ==\n             [[0], [1, 2], [3, 4], [5, 6], [7, 8], [9]]\n\n    assert Enum.chunk_while(0..10, [], chunk_fun, after_fun) ==\n             [[0], [1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]\n\n    assert Enum.chunk_while(0..11, [], chunk_fun, after_fun) ==\n             [[0], [1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]\n\n    assert Enum.chunk_while([5, 7, 9, 11], [], chunk_fun, after_fun) == [[5, 7, 9]]\n\n    assert Enum.chunk_while([1, 2, 3, 5, 7], [], chunk_fun, after_fun) == [[1, 2], [3, 5, 7]]\n\n    chunk_fn2 = fn\n      -1, acc -> {:cont, acc, 0}\n      i, acc -> {:cont, acc + i}\n    end\n\n    after_fn2 = fn acc -> {:cont, acc, 0} end\n\n    assert Enum.chunk_while([1, -1, 2, 3, -1, 4, 5, 6], 0, chunk_fn2, after_fn2) == [1, 5, 15]\n  end\n\n  test \"concat/1\" do\n    assert Enum.concat([[1, [2], 3], [4], [5, 6]]) == [1, [2], 3, 4, 5, 6]\n\n    assert Enum.concat([[], []]) == []\n    assert Enum.concat([[]]) == []\n    assert Enum.concat([]) == []\n  end\n\n  test \"concat/2\" do\n    assert Enum.concat([], [1]) == [1]\n    assert Enum.concat([1, [2], 3], [4, 5]) == [1, [2], 3, 4, 5]\n\n    assert Enum.concat([1, 2], 3..5) == [1, 2, 3, 4, 5]\n\n    assert Enum.concat([], []) == []\n    assert Enum.concat([], 1..3) == [1, 2, 3]\n\n    assert Enum.concat(fn acc, _ -> acc end, [1]) == [1]\n  end\n\n  test \"count/1\" do\n    assert Enum.count([1, 2, 3]) == 3\n    assert Enum.count([]) == 0\n    assert Enum.count([1, true, false, nil]) == 4\n  end\n\n  test \"count/2\" do\n    assert Enum.count([1, 2, 3], fn x -> rem(x, 2) == 0 end) == 1\n    assert Enum.count([], fn x -> rem(x, 2) == 0 end) == 0\n    assert Enum.count([1, true, false, nil], & &1) == 2\n  end\n\n  test \"count_until/2\" do\n    assert Enum.count_until([1, 2, 3], 2) == 2\n    assert Enum.count_until([], 2) == 0\n    assert Enum.count_until([1, 2], 2) == 2\n  end\n\n  test \"count_until/2 with streams\" do\n    count_until_stream = fn list, limit -> list |> Stream.map(& &1) |> Enum.count_until(limit) end\n\n    assert count_until_stream.([1, 2, 3], 2) == 2\n    assert count_until_stream.([], 2) == 0\n    assert count_until_stream.([1, 2], 2) == 2\n  end\n\n  test \"count_until/2 with invalid limit\" do\n    assert_raise ArgumentError, \"expected limit to be greater than 0, got: 0\", fn ->\n      Enum.count_until([1, 2, 3], 0)\n    end\n\n    assert_raise ArgumentError, \"expected limit to be greater than 0, got: -22\", fn ->\n      Enum.count_until([1, 2, 3], -22)\n    end\n  end\n\n  test \"count_until/3\" do\n    assert Enum.count_until([1, 2, 3, 4, 5, 6], fn x -> rem(x, 2) == 0 end, 2) == 2\n    assert Enum.count_until([1, 2], fn x -> rem(x, 2) == 0 end, 2) == 1\n    assert Enum.count_until([1, 2, 3, 4], fn x -> rem(x, 2) == 0 end, 2) == 2\n    assert Enum.count_until([], fn x -> rem(x, 2) == 0 end, 2) == 0\n  end\n\n  test \"count_until/3 with streams\" do\n    count_until_stream = fn list, fun, limit ->\n      list |> Stream.map(& &1) |> Enum.count_until(fun, limit)\n    end\n\n    assert count_until_stream.([1, 2, 3, 4, 5, 6], fn x -> rem(x, 2) == 0 end, 2) == 2\n    assert count_until_stream.([1, 2], fn x -> rem(x, 2) == 0 end, 2) == 1\n    assert count_until_stream.([1, 2, 3, 4], fn x -> rem(x, 2) == 0 end, 2) == 2\n    assert count_until_stream.([], fn x -> rem(x, 2) == 0 end, 2) == 0\n  end\n\n  test \"count_until/3 with invalid limit\" do\n    assert_raise ArgumentError, \"expected limit to be greater than 0, got: 0\", fn ->\n      Enum.count_until([1, 2, 3], fn x -> rem(x, 2) == 0 end, 0)\n    end\n\n    assert_raise ArgumentError, \"expected limit to be greater than 0, got: -22\", fn ->\n      Enum.count_until([1, 2, 3], fn x -> rem(x, 2) == 0 end, -22)\n    end\n  end\n\n  test \"dedup/1\" do\n    assert Enum.dedup([1, 1, 2, 1, 1, 2, 1]) == [1, 2, 1, 2, 1]\n    assert Enum.dedup([2, 1, 1, 2, 1]) == [2, 1, 2, 1]\n    assert Enum.dedup([1, 2, 3, 4]) == [1, 2, 3, 4]\n    assert Enum.dedup([1, 1.0, 2.0, 2]) == [1, 1.0, 2.0, 2]\n    assert Enum.dedup([]) == []\n    assert Enum.dedup([nil, nil, true, {:value, true}]) == [nil, true, {:value, true}]\n    assert Enum.dedup([nil]) == [nil]\n  end\n\n  test \"dedup/1 with streams\" do\n    dedup_stream = fn list -> list |> Stream.map(& &1) |> Enum.dedup() end\n\n    assert dedup_stream.([1, 1, 2, 1, 1, 2, 1]) == [1, 2, 1, 2, 1]\n    assert dedup_stream.([2, 1, 1, 2, 1]) == [2, 1, 2, 1]\n    assert dedup_stream.([1, 2, 3, 4]) == [1, 2, 3, 4]\n    assert dedup_stream.([1, 1.0, 2.0, 2]) == [1, 1.0, 2.0, 2]\n    assert dedup_stream.([]) == []\n    assert dedup_stream.([nil, nil, true, {:value, true}]) == [nil, true, {:value, true}]\n    assert dedup_stream.([nil]) == [nil]\n  end\n\n  test \"dedup_by/2\" do\n    assert Enum.dedup_by([{1, :x}, {2, :y}, {2, :z}, {1, :x}], fn {x, _} -> x end) ==\n             [{1, :x}, {2, :y}, {1, :x}]\n\n    assert Enum.dedup_by([5, 1, 2, 3, 2, 1], fn x -> x > 2 end) == [5, 1, 3, 2]\n  end\n\n  test \"drop/2\" do\n    assert Enum.drop([1, 2, 3], 0) == [1, 2, 3]\n    assert Enum.drop([1, 2, 3], 1) == [2, 3]\n    assert Enum.drop([1, 2, 3], 2) == [3]\n    assert Enum.drop([1, 2, 3], 3) == []\n    assert Enum.drop([1, 2, 3], 4) == []\n    assert Enum.drop([1, 2, 3], -1) == [1, 2]\n    assert Enum.drop([1, 2, 3], -2) == [1]\n    assert Enum.drop([1, 2, 3], -4) == []\n    assert Enum.drop([], 3) == []\n  end\n\n  test \"drop/2 with streams\" do\n    drop_stream = fn list, count -> list |> Stream.map(& &1) |> Enum.drop(count) end\n\n    assert drop_stream.([1, 2, 3], 0) == [1, 2, 3]\n    assert drop_stream.([1, 2, 3], 1) == [2, 3]\n    assert drop_stream.([1, 2, 3], 2) == [3]\n    assert drop_stream.([1, 2, 3], 3) == []\n    assert drop_stream.([1, 2, 3], 4) == []\n    assert drop_stream.([1, 2, 3], -1) == [1, 2]\n    assert drop_stream.([1, 2, 3], -2) == [1]\n    assert drop_stream.([1, 2, 3], -4) == []\n    assert drop_stream.([], 3) == []\n  end\n\n  test \"drop_every/2\" do\n    assert Enum.drop_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2) == [2, 4, 6, 8, 10]\n    assert Enum.drop_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3) == [2, 3, 5, 6, 8, 9]\n    assert Enum.drop_every([], 2) == []\n    assert Enum.drop_every([1, 2], 2) == [2]\n    assert Enum.drop_every([1, 2, 3], 0) == [1, 2, 3]\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.drop_every([1, 2, 3], -1)\n    end\n  end\n\n  test \"drop_while/2\" do\n    assert Enum.drop_while([1, 2, 3, 4, 3, 2, 1], fn x -> x <= 3 end) == [4, 3, 2, 1]\n    assert Enum.drop_while([1, 2, 3], fn _ -> false end) == [1, 2, 3]\n    assert Enum.drop_while([1, 2, 3], fn x -> x <= 3 end) == []\n    assert Enum.drop_while([], fn _ -> false end) == []\n  end\n\n  test \"each/2\" do\n    try do\n      assert Enum.each([], fn x -> x end) == :ok\n      assert Enum.each([1, 2, 3], fn x -> Process.put(:enum_test_each, x * 2) end) == :ok\n      assert Process.get(:enum_test_each) == 6\n    after\n      Process.delete(:enum_test_each)\n    end\n  end\n\n  test \"empty?/1\" do\n    assert Enum.empty?([])\n    assert Enum.empty?(%{})\n    refute Enum.empty?([1, 2, 3])\n    refute Enum.empty?(%{one: 1})\n    refute Enum.empty?(1..3)\n\n    assert Stream.take([1], 0) |> Enum.empty?()\n    refute Stream.take([1], 1) |> Enum.empty?()\n  end\n\n  test \"fetch/2\" do\n    assert Enum.fetch([66], 0) == {:ok, 66}\n    assert Enum.fetch([66], -1) == {:ok, 66}\n    assert Enum.fetch([66], 1) == :error\n    assert Enum.fetch([66], -2) == :error\n\n    assert Enum.fetch([2, 4, 6], 0) == {:ok, 2}\n    assert Enum.fetch([2, 4, 6], -1) == {:ok, 6}\n    assert Enum.fetch([2, 4, 6], 2) == {:ok, 6}\n    assert Enum.fetch([2, 4, 6], 4) == :error\n    assert Enum.fetch([2, 4, 6], -2) == {:ok, 4}\n    assert Enum.fetch([2, 4, 6], -4) == :error\n\n    assert Enum.fetch([], 0) == :error\n    assert Enum.fetch([], 1) == :error\n  end\n\n  test \"fetch!/2\" do\n    assert Enum.fetch!([2, 4, 6], 0) == 2\n    assert Enum.fetch!([2, 4, 6], 2) == 6\n    assert Enum.fetch!([2, 4, 6], -2) == 4\n\n    assert_raise Enum.OutOfBoundsError, fn ->\n      Enum.fetch!([2, 4, 6], 4)\n    end\n\n    assert_raise Enum.OutOfBoundsError, fn ->\n      Enum.fetch!([2, 4, 6], -4)\n    end\n  end\n\n  test \"filter/2\" do\n    assert Enum.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end) == [2]\n    assert Enum.filter([2, 4, 6], fn x -> rem(x, 2) == 0 end) == [2, 4, 6]\n\n    assert Enum.filter([1, 2, false, 3, nil], & &1) == [1, 2, 3]\n    assert Enum.filter([1, 2, 3], &match?(1, &1)) == [1]\n    assert Enum.filter([1, 2, 3], &match?(x when x < 3, &1)) == [1, 2]\n    assert Enum.filter([1, 2, 3], fn _ -> true end) == [1, 2, 3]\n  end\n\n  test \"find/3\" do\n    assert Enum.find([2, 4, 6], fn x -> rem(x, 2) == 1 end) == nil\n    assert Enum.find([2, 4, 6], 0, fn x -> rem(x, 2) == 1 end) == 0\n    assert Enum.find([2, 3, 4], fn x -> rem(x, 2) == 1 end) == 3\n  end\n\n  test \"find_index/2\" do\n    assert Enum.find_index([2, 4, 6], fn x -> rem(x, 2) == 1 end) == nil\n    assert Enum.find_index([2, 3, 4], fn x -> rem(x, 2) == 1 end) == 1\n    assert Stream.take(1..3, 3) |> Enum.find_index(fn _ -> false end) == nil\n    assert Stream.take(1..6, 6) |> Enum.find_index(fn x -> x == 5 end) == 4\n  end\n\n  test \"find_value/2\" do\n    assert Enum.find_value([2, 4, 6], fn x -> rem(x, 2) == 1 end) == nil\n    assert Enum.find_value([2, 4, 6], 0, fn x -> rem(x, 2) == 1 end) == 0\n    assert Enum.find_value([2, 3, 4], fn x -> rem(x, 2) == 1 end)\n  end\n\n  test \"flat_map/2\" do\n    assert Enum.flat_map([], fn x -> [x, x] end) == []\n    assert Enum.flat_map([1, 2, 3], fn x -> [x, x] end) == [1, 1, 2, 2, 3, 3]\n    assert Enum.flat_map([1, 2, 3], fn x -> x..(x + 1) end) == [1, 2, 2, 3, 3, 4]\n    assert Enum.flat_map([1, 2, 3], fn x -> Stream.duplicate(x, 2) end) == [1, 1, 2, 2, 3, 3]\n  end\n\n  test \"flat_map/2 with streams\" do\n    flat_map_stream = fn list, fun -> list |> Stream.map(& &1) |> Enum.flat_map(fun) end\n\n    assert flat_map_stream.([], fn x -> [x, x] end) == []\n    assert flat_map_stream.([1, 2, 3], fn x -> [x, x] end) == [1, 1, 2, 2, 3, 3]\n    assert flat_map_stream.([1, 2, 3], fn x -> x..(x + 1) end) == [1, 2, 2, 3, 3, 4]\n    assert flat_map_stream.([1, 2, 3], fn x -> Stream.duplicate(x, 2) end) == [1, 1, 2, 2, 3, 3]\n  end\n\n  test \"flat_map_reduce/3\" do\n    assert Enum.flat_map_reduce([1, 2, 3], 0, &{[&1, &2], &1 + &2}) == {[1, 0, 2, 1, 3, 3], 6}\n  end\n\n  test \"frequencies/1\" do\n    assert Enum.frequencies([]) == %{}\n    assert Enum.frequencies(~w{a c a a c b}) == %{\"a\" => 3, \"b\" => 1, \"c\" => 2}\n  end\n\n  test \"frequencies_by/2\" do\n    assert Enum.frequencies_by([], fn _ -> raise \"oops\" end) == %{}\n    assert Enum.frequencies_by([12, 7, 6, 5, 1], &Integer.mod(&1, 2)) == %{0 => 2, 1 => 3}\n  end\n\n  test \"group_by/3\" do\n    assert Enum.group_by([], fn _ -> raise \"oops\" end) == %{}\n    assert Enum.group_by([1, 2, 3], &rem(&1, 2)) == %{0 => [2], 1 => [1, 3]}\n  end\n\n  test \"intersperse/2\" do\n    assert Enum.intersperse([], true) == []\n    assert Enum.intersperse([1], true) == [1]\n    assert Enum.intersperse([1, 2, 3], true) == [1, true, 2, true, 3]\n\n    assert Enum.intersperse(.., true) == []\n    assert Enum.intersperse(1..1, true) == [1]\n    assert Enum.intersperse(1..3, true) == [1, true, 2, true, 3]\n  end\n\n  test \"into/2\" do\n    assert Enum.into([a: 1, b: 2], %{}) == %{a: 1, b: 2}\n    assert Enum.into([a: 1, b: 2], %{c: 3}) == %{a: 1, b: 2, c: 3}\n    assert Enum.into(MapSet.new(a: 1, b: 2), %{}) == %{a: 1, b: 2}\n    assert Enum.into(MapSet.new(a: 1, b: 2), %{c: 3}) == %{a: 1, b: 2, c: 3}\n    assert Enum.into(%{a: 1, b: 2}, []) |> Enum.sort() == [a: 1, b: 2]\n    assert Enum.into(1..3, []) == [1, 2, 3]\n    assert Enum.into([\"H\", \"i\"], \"\") == \"Hi\"\n\n    assert Enum.into([a: 1, b: 2], MapSet.new()) == MapSet.new(a: 1, b: 2)\n    assert Enum.into(%{a: 1, b: 2}, MapSet.new()) == MapSet.new(a: 1, b: 2)\n    assert Enum.into([a: 1, b: 2], MapSet.new(a: 1, c: 3)) == MapSet.new(a: 1, b: 2, c: 3)\n  end\n\n  test \"into/2 exceptions\" do\n    assert_raise ArgumentError,\n                 \"collecting into a map requires {key, value} tuples, got: 1\",\n                 fn -> Enum.into(1..10, %{}) end\n\n    assert_raise ArgumentError, \"collecting into a binary requires a bitstring, got: 1\", fn ->\n      Enum.into(1..10, <<>>)\n    end\n\n    assert_raise ArgumentError, \"collecting into a bitstring requires a bitstring, got: 1\", fn ->\n      Enum.into(1..10, <<1::1>>)\n    end\n  end\n\n  test \"into/3\" do\n    assert Enum.into([1, 2, 3], [], fn x -> x * 2 end) == [2, 4, 6]\n    assert Enum.into([1, 2, 3], \"numbers: \", &to_string/1) == \"numbers: 123\"\n\n    assert Enum.into([1, 2, 3], MapSet.new(), &(&1 * 2)) == MapSet.new([2, 4, 6])\n    assert Enum.into([1, 2, 3], MapSet.new([0, 2]), &(&1 * 2)) == MapSet.new([0, 2, 4, 6])\n\n    assert_raise MatchError, fn ->\n      Enum.into([2, 3], %{a: 1}, & &1)\n    end\n  end\n\n  test \"join/2\" do\n    assert Enum.join([], \" = \") == \"\"\n    assert Enum.join([1, 2, 3], \" = \") == \"1 = 2 = 3\"\n    assert Enum.join([1, \"2\", 3], \" = \") == \"1 = 2 = 3\"\n    assert Enum.join([1, 2, 3]) == \"123\"\n    assert Enum.join([\"\", \"\", 1, 2, \"\", 3, \"\", \"\\n\"], \";\") == \";;1;2;;3;;\\n\"\n    assert Enum.join([\"\"]) == \"\"\n\n    assert Enum.join(fn acc, _ -> acc end, \".\") == \"\"\n  end\n\n  test \"map/2\" do\n    assert Enum.map([], fn x -> x * 2 end) == []\n    assert Enum.map([1, 2, 3], fn x -> x * 2 end) == [2, 4, 6]\n  end\n\n  test \"map_every/3\" do\n    assert Enum.map_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2, fn x -> x * 2 end) ==\n             [2, 2, 6, 4, 10, 6, 14, 8, 18, 10]\n\n    assert Enum.map_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3, fn x -> x * 2 end) ==\n             [2, 2, 3, 8, 5, 6, 14, 8, 9, 20]\n\n    assert Enum.map_every([], 2, fn x -> x * 2 end) == []\n    assert Enum.map_every([1, 2], 2, fn x -> x * 2 end) == [2, 2]\n\n    assert Enum.map_every([1, 2, 3], 0, fn _x -> raise \"should not be invoked\" end) ==\n             [1, 2, 3]\n\n    assert Enum.map_every(1..3, 1, fn x -> x * 2 end) == [2, 4, 6]\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.map_every([1, 2, 3], -1, fn x -> x * 2 end)\n    end\n\n    assert Enum.map_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 9, fn x -> x + 1000 end) ==\n             [1001, 2, 3, 4, 5, 6, 7, 8, 9, 1010]\n\n    assert Enum.map_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10, fn x -> x + 1000 end) ==\n             [1001, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n    assert Enum.map_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 100, fn x -> x + 1000 end) ==\n             [1001, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n  end\n\n  test \"map_intersperse/3\" do\n    assert Enum.map_intersperse([], :a, &(&1 * 2)) == []\n    assert Enum.map_intersperse([1], :a, &(&1 * 2)) == [2]\n    assert Enum.map_intersperse([1, 2, 3], :a, &(&1 * 2)) == [2, :a, 4, :a, 6]\n  end\n\n  test \"map_join/3\" do\n    assert Enum.map_join([], \" = \", &(&1 * 2)) == \"\"\n    assert Enum.map_join([1, 2, 3], \" = \", &(&1 * 2)) == \"2 = 4 = 6\"\n    assert Enum.map_join([1, 2, 3], &(&1 * 2)) == \"246\"\n    assert Enum.map_join([\"\", \"\", 1, 2, \"\", 3, \"\", \"\\n\"], \";\", & &1) == \";;1;2;;3;;\\n\"\n    assert Enum.map_join([\"\"], \"\", & &1) == \"\"\n    assert Enum.map_join(fn acc, _ -> acc end, \".\", &(&1 + 0)) == \"\"\n  end\n\n  test \"map_reduce/3\" do\n    assert Enum.map_reduce([], 1, fn x, acc -> {x * 2, x + acc} end) == {[], 1}\n    assert Enum.map_reduce([1, 2, 3], 1, fn x, acc -> {x * 2, x + acc} end) == {[2, 4, 6], 7}\n  end\n\n  test \"max/1\" do\n    assert Enum.max([1]) == 1\n    assert Enum.max([1, 2, 3]) == 3\n    assert Enum.max([1, [], :a, {}]) == []\n\n    assert Enum.max([1, 1.0]) === 1\n    assert Enum.max([1.0, 1]) === 1.0\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.max([])\n    end\n  end\n\n  test \"max/2 with empty fallback\" do\n    assert Enum.max([], fn -> 0 end) === 0\n    assert Enum.max([1, 2], fn -> 0 end) === 2\n  end\n\n  test \"max/2 with stable sorting\" do\n    assert Enum.max([1, 1.0], &>=/2) === 1\n    assert Enum.max([1.0, 1], &>=/2) === 1.0\n    assert Enum.max([1, 1.0], &>/2) === 1.0\n    assert Enum.max([1.0, 1], &>/2) === 1\n  end\n\n  test \"max/2 with module\" do\n    assert Enum.max([~D[2019-01-01], ~D[2020-01-01]], Date) === ~D[2020-01-01]\n  end\n\n  test \"max/3\" do\n    assert Enum.max([1], &>=/2, fn -> nil end) == 1\n    assert Enum.max([1, 2, 3], &>=/2, fn -> nil end) == 3\n    assert Enum.max([1, [], :a, {}], &>=/2, fn -> nil end) == []\n    assert Enum.max([], &>=/2, fn -> :empty_value end) == :empty_value\n    assert Enum.max(%{}, &>=/2, fn -> :empty_value end) == :empty_value\n    assert_runs_enumeration_only_once(&Enum.max(&1, fn a, b -> a >= b end, fn -> nil end))\n  end\n\n  test \"max_by/2\" do\n    assert Enum.max_by([\"a\", \"aa\", \"aaa\"], fn x -> String.length(x) end) == \"aaa\"\n\n    assert Enum.max_by([1, 1.0], & &1) === 1\n    assert Enum.max_by([1.0, 1], & &1) === 1.0\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.max_by([], fn x -> String.length(x) end)\n    end\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.max_by(%{}, & &1)\n    end\n  end\n\n  test \"max_by/3 with stable sorting\" do\n    assert Enum.max_by([1, 1.0], & &1, &>=/2) === 1\n    assert Enum.max_by([1.0, 1], & &1, &>=/2) === 1.0\n    assert Enum.max_by([1, 1.0], & &1, &>/2) === 1.0\n    assert Enum.max_by([1.0, 1], & &1, &>/2) === 1\n  end\n\n  test \"max_by/3 with module\" do\n    users = [%{id: 1, date: ~D[2019-01-01]}, %{id: 2, date: ~D[2020-01-01]}]\n    assert Enum.max_by(users, & &1.date, Date).id == 2\n\n    users = [%{id: 1, date: ~D[2020-01-01]}, %{id: 2, date: ~D[2020-01-01]}]\n    assert Enum.max_by(users, & &1.date, Date).id == 1\n  end\n\n  test \"max_by/4\" do\n    assert Enum.max_by([\"a\", \"aa\", \"aaa\"], fn x -> String.length(x) end, &>=/2, fn -> nil end) ==\n             \"aaa\"\n\n    assert Enum.max_by([], fn x -> String.length(x) end, &>=/2, fn -> :empty_value end) ==\n             :empty_value\n\n    assert Enum.max_by(%{}, & &1, &>=/2, fn -> :empty_value end) == :empty_value\n    assert Enum.max_by(%{}, & &1, &>=/2, fn -> {:a, :tuple} end) == {:a, :tuple}\n\n    assert_runs_enumeration_only_once(\n      &Enum.max_by(&1, fn e -> e end, fn a, b -> a >= b end, fn -> nil end)\n    )\n  end\n\n  test \"member?/2\" do\n    assert Enum.member?([1, 2, 3], 2)\n    refute Enum.member?([], 0)\n    refute Enum.member?([1, 2, 3], 0)\n  end\n\n  test \"min/1\" do\n    assert Enum.min([1]) == 1\n    assert Enum.min([1, 2, 3]) == 1\n    assert Enum.min([[], :a, {}]) == :a\n\n    assert Enum.min([1, 1.0]) === 1\n    assert Enum.min([1.0, 1]) === 1.0\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.min([])\n    end\n  end\n\n  test \"min/2 with empty fallback\" do\n    assert Enum.min([], fn -> 0 end) === 0\n    assert Enum.min([1, 2], fn -> 0 end) === 1\n  end\n\n  test \"min/2 with stable sorting\" do\n    assert Enum.min([1, 1.0], &<=/2) === 1\n    assert Enum.min([1.0, 1], &<=/2) === 1.0\n    assert Enum.min([1, 1.0], &</2) === 1.0\n    assert Enum.min([1.0, 1], &</2) === 1\n  end\n\n  test \"min/2 with module\" do\n    assert Enum.min([~D[2019-01-01], ~D[2020-01-01]], Date) === ~D[2019-01-01]\n  end\n\n  test \"min/3\" do\n    assert Enum.min([1], &<=/2, fn -> nil end) == 1\n    assert Enum.min([1, 2, 3], &<=/2, fn -> nil end) == 1\n    assert Enum.min([[], :a, {}], &<=/2, fn -> nil end) == :a\n    assert Enum.min([], &<=/2, fn -> :empty_value end) == :empty_value\n    assert Enum.min(%{}, &<=/2, fn -> :empty_value end) == :empty_value\n    assert_runs_enumeration_only_once(&Enum.min(&1, fn a, b -> a <= b end, fn -> nil end))\n  end\n\n  test \"min_by/2\" do\n    assert Enum.min_by([\"a\", \"aa\", \"aaa\"], fn x -> String.length(x) end) == \"a\"\n\n    assert Enum.min_by([1, 1.0], & &1) === 1\n    assert Enum.min_by([1.0, 1], & &1) === 1.0\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.min_by([], fn x -> String.length(x) end)\n    end\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.min_by(%{}, & &1)\n    end\n  end\n\n  test \"min_by/3 with stable sorting\" do\n    assert Enum.min_by([1, 1.0], & &1, &<=/2) === 1\n    assert Enum.min_by([1.0, 1], & &1, &<=/2) === 1.0\n    assert Enum.min_by([1, 1.0], & &1, &</2) === 1.0\n    assert Enum.min_by([1.0, 1], & &1, &</2) === 1\n  end\n\n  test \"min_by/3 with module\" do\n    users = [%{id: 1, date: ~D[2019-01-01]}, %{id: 2, date: ~D[2020-01-01]}]\n    assert Enum.min_by(users, & &1.date, Date).id == 1\n\n    users = [%{id: 1, date: ~D[2020-01-01]}, %{id: 2, date: ~D[2020-01-01]}]\n    assert Enum.min_by(users, & &1.date, Date).id == 1\n  end\n\n  test \"min_by/4\" do\n    assert Enum.min_by([\"a\", \"aa\", \"aaa\"], fn x -> String.length(x) end, &<=/2, fn -> nil end) ==\n             \"a\"\n\n    assert Enum.min_by([], fn x -> String.length(x) end, &<=/2, fn -> :empty_value end) ==\n             :empty_value\n\n    assert Enum.min_by(%{}, & &1, &<=/2, fn -> :empty_value end) == :empty_value\n    assert Enum.min_by(%{}, & &1, &<=/2, fn -> {:a, :tuple} end) == {:a, :tuple}\n\n    assert_runs_enumeration_only_once(\n      &Enum.min_by(&1, fn e -> e end, fn a, b -> a <= b end, fn -> nil end)\n    )\n  end\n\n  test \"min_max/1\" do\n    assert Enum.min_max([1]) == {1, 1}\n    assert Enum.min_max([2, 3, 1]) == {1, 3}\n    assert Enum.min_max([[], :a, {}]) == {:a, []}\n\n    assert Enum.min_max([1, 1.0]) === {1, 1}\n    assert Enum.min_max([1.0, 1]) === {1.0, 1.0}\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.min_max([])\n    end\n  end\n\n  test \"min_max/2\" do\n    assert Enum.min_max([1], fn -> nil end) == {1, 1}\n    assert Enum.min_max([2, 3, 1], fn -> nil end) == {1, 3}\n    assert Enum.min_max([[], :a, {}], fn -> nil end) == {:a, []}\n    assert Enum.min_max([], fn -> {:empty_min, :empty_max} end) == {:empty_min, :empty_max}\n    assert Enum.min_max(%{}, fn -> {:empty_min, :empty_max} end) == {:empty_min, :empty_max}\n    assert_runs_enumeration_only_once(&Enum.min_max(&1, fn -> nil end))\n  end\n\n  test \"min_max/3\" do\n    dates = [~D[2020-01-01], ~D[2019-01-01]]\n\n    assert Enum.min_max(dates, Date) ==\n             {~D[2019-01-01], ~D[2020-01-01]}\n\n    assert Enum.min_max([~D[2000-01-01]], Date) ==\n             {~D[2000-01-01], ~D[2000-01-01]}\n\n    assert Enum.min_max([3, 1, 2], &>/2, fn -> nil end) ==\n             {3, 1}\n\n    assert Enum.min_max([], &>/2, fn -> {:no_min, :no_max} end) ==\n             {:no_min, :no_max}\n\n    assert Enum.min_max(%{}, &>/2, fn -> {:no_min, :no_max} end) ==\n             {:no_min, :no_max}\n\n    assert Enum.min_max(1..5, &>/2, fn -> {:no_min, :no_max} end) ==\n             {5, 1}\n\n    assert_runs_enumeration_only_once(&Enum.min_max(&1, fn a, b -> a > b end, fn -> nil end))\n  end\n\n  test \"min_max_by/2\" do\n    assert Enum.min_max_by([\"aaa\", \"a\", \"aa\"], fn x -> String.length(x) end) == {\"a\", \"aaa\"}\n\n    assert Enum.min_max_by([1, 1.0], & &1) === {1, 1}\n    assert Enum.min_max_by([1.0, 1], & &1) === {1.0, 1.0}\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.min_max_by([], fn x -> String.length(x) end)\n    end\n  end\n\n  test \"min_max_by/3\" do\n    assert Enum.min_max_by([\"aaa\", \"a\", \"aa\"], fn x -> String.length(x) end, fn -> nil end) ==\n             {\"a\", \"aaa\"}\n\n    assert Enum.min_max_by([], fn x -> String.length(x) end, fn -> {:no_min, :no_max} end) ==\n             {:no_min, :no_max}\n\n    assert Enum.min_max_by(%{}, fn x -> String.length(x) end, fn -> {:no_min, :no_max} end) ==\n             {:no_min, :no_max}\n\n    assert Enum.min_max_by([\"aaa\", \"a\", \"aa\"], fn x -> String.length(x) end, &>/2) == {\"aaa\", \"a\"}\n\n    assert_runs_enumeration_only_once(&Enum.min_max_by(&1, fn x -> x end, fn -> nil end))\n  end\n\n  test \"min_max_by/4\" do\n    users = [%{id: 1, date: ~D[2019-01-01]}, %{id: 2, date: ~D[2020-01-01]}]\n\n    assert Enum.min_max_by(users, & &1.date, Date) ==\n             {%{id: 1, date: ~D[2019-01-01]}, %{id: 2, date: ~D[2020-01-01]}}\n\n    assert Enum.min_max_by([\"aaa\", \"a\", \"aa\"], fn x -> String.length(x) end, &>/2, fn -> nil end) ==\n             {\"aaa\", \"a\"}\n\n    assert Enum.min_max_by([], fn x -> String.length(x) end, &>/2, fn -> {:no_min, :no_max} end) ==\n             {:no_min, :no_max}\n\n    assert Enum.min_max_by(%{}, fn x -> String.length(x) end, &>/2, fn -> {:no_min, :no_max} end) ==\n             {:no_min, :no_max}\n\n    assert_runs_enumeration_only_once(\n      &Enum.min_max_by(&1, fn x -> x end, fn a, b -> a > b end, fn -> nil end)\n    )\n  end\n\n  test \"split_with/2\" do\n    assert Enum.split_with([], fn x -> rem(x, 2) == 0 end) == {[], []}\n    assert Enum.split_with([1, 2, 3], fn x -> rem(x, 2) == 0 end) == {[2], [1, 3]}\n    assert Enum.split_with([2, 4, 6], fn x -> rem(x, 2) == 0 end) == {[2, 4, 6], []}\n\n    assert Enum.split_with(1..5, fn x -> rem(x, 2) == 0 end) == {[2, 4], [1, 3, 5]}\n    assert Enum.split_with(-3..0, fn x -> x > 0 end) == {[], [-3, -2, -1, 0]}\n\n    assert Enum.split_with(%{}, fn x -> rem(x, 2) == 0 end) == {[], []}\n\n    assert Enum.split_with(%{a: 1, b: 2}, fn {_k, v} -> rem(v, 2) == 0 end) ==\n             {[b: 2], [a: 1]}\n\n    assert Enum.split_with(%{b: 2, d: 4, f: 6}, fn {_k, v} -> rem(v, 2) == 0 end) ==\n             {Map.to_list(%{b: 2, d: 4, f: 6}), []}\n  end\n\n  test \"random/1\" do\n    # corner cases, independent of the seed\n    assert_raise Enum.EmptyError, fn -> Enum.random([]) end\n    assert Enum.random([1]) == 1\n\n    # set a fixed seed so the test can be deterministic\n    # please note the order of following assertions is important\n    seed1 = {1406, 407_414, 139_258}\n    seed2 = {1306, 421_106, 567_597}\n    :rand.seed(:exsss, seed1)\n    assert Enum.random([1, 2]) == 1\n    assert Enum.random([1, 2]) == 2\n    :rand.seed(:exsss, seed1)\n    assert Enum.random([1, 2]) == 1\n    assert Enum.random([1, 2, 3]) == 1\n    assert Enum.random([1, 2, 3, 4]) == 2\n    assert Enum.random([1, 2, 3, 4, 5]) == 3\n    :rand.seed(:exsss, seed2)\n    assert Enum.random([1, 2]) == 1\n    assert Enum.random([1, 2, 3]) == 2\n    assert Enum.random([1, 2, 3, 4]) == 4\n    assert Enum.random([1, 2, 3, 4, 5]) == 3\n  end\n\n  test \"random/1 with streams\" do\n    random_stream = fn list -> list |> Stream.map(& &1) |> Enum.random() end\n\n    assert_raise Enum.EmptyError, fn -> random_stream.([]) end\n    assert random_stream.([1]) == 1\n\n    seed = {1406, 407_414, 139_258}\n    :rand.seed(:exsss, seed)\n\n    assert random_stream.([1, 2]) == 2\n    assert random_stream.([1, 2, 3]) == 3\n    assert random_stream.([1, 2, 3, 4]) == 1\n    assert random_stream.([1, 2, 3, 4, 5]) == 3\n  end\n\n  test \"reduce/2\" do\n    assert Enum.reduce([1, 2, 3], fn x, acc -> x + acc end) == 6\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.reduce([], fn x, acc -> x + acc end)\n    end\n\n    assert_raise Enum.EmptyError, fn ->\n      Enum.reduce(%{}, fn _, acc -> acc end)\n    end\n  end\n\n  test \"reduce/3\" do\n    assert Enum.reduce([], 1, fn x, acc -> x + acc end) == 1\n    assert Enum.reduce([1, 2, 3], 1, fn x, acc -> x + acc end) == 7\n  end\n\n  test \"reduce/3 with streams\" do\n    reduce_stream = fn list, acc, fun -> list |> Stream.map(& &1) |> Enum.reduce(acc, fun) end\n\n    assert reduce_stream.([], 1, fn x, acc -> x + acc end) == 1\n    assert reduce_stream.([1, 2, 3], 1, fn x, acc -> x + acc end) == 7\n  end\n\n  test \"reduce_while/3\" do\n    assert Enum.reduce_while([1, 2, 3], 1, fn i, acc -> {:cont, acc + i} end) == 7\n    assert Enum.reduce_while([1, 2, 3], 1, fn _i, acc -> {:halt, acc} end) == 1\n    assert Enum.reduce_while([], 0, fn _i, acc -> {:cont, acc} end) == 0\n  end\n\n  test \"reject/2\" do\n    assert Enum.reject([1, 2, 3], fn x -> rem(x, 2) == 0 end) == [1, 3]\n    assert Enum.reject([2, 4, 6], fn x -> rem(x, 2) == 0 end) == []\n    assert Enum.reject([1, true, nil, false, 2], & &1) == [nil, false]\n  end\n\n  test \"reverse/1\" do\n    assert Enum.reverse([]) == []\n    assert Enum.reverse([1, 2, 3]) == [3, 2, 1]\n    assert Enum.reverse([5..5]) == [5..5]\n  end\n\n  test \"reverse/2\" do\n    assert Enum.reverse([1, 2, 3], [4, 5, 6]) == [3, 2, 1, 4, 5, 6]\n    assert Enum.reverse([1, 2, 3], []) == [3, 2, 1]\n    assert Enum.reverse([5..5], [5]) == [5..5, 5]\n  end\n\n  test \"reverse_slice/3\" do\n    assert Enum.reverse_slice([], 1, 2) == []\n    assert Enum.reverse_slice([1, 2, 3], 0, 0) == [1, 2, 3]\n    assert Enum.reverse_slice([1, 2, 3], 0, 1) == [1, 2, 3]\n    assert Enum.reverse_slice([1, 2, 3], 0, 2) == [2, 1, 3]\n    assert Enum.reverse_slice([1, 2, 3], 0, 20_000_000) == [3, 2, 1]\n    assert Enum.reverse_slice([1, 2, 3], 100, 2) == [1, 2, 3]\n    assert Enum.reverse_slice([1, 2, 3], 10, 10) == [1, 2, 3]\n  end\n\n  describe \"slide/3\" do\n    test \"on an empty enum produces an empty list\" do\n      for enum <- [[], %{}, 0..-1//1, MapSet.new()] do\n        assert Enum.slide(enum, 0..0, 0) == []\n        assert Enum.slide(enum, 1..1, 2) == []\n      end\n    end\n\n    test \"on a single-element enumerable is the same as transforming to list\" do\n      for enum <- [[\"foo\"], [1], [%{foo: \"bar\"}], %{foo: :bar}, MapSet.new([\"foo\"]), 1..1] do\n        assert Enum.slide(enum, 0..0, 0) == Enum.to_list(enum)\n      end\n    end\n\n    test \"moves a single element\" do\n      for zero_to_20 <- [0..20, Enum.to_list(0..20)] do\n        expected_numbers = Enum.flat_map([0..7, [14], 8..13, 15..20], &Enum.to_list/1)\n        assert Enum.slide(zero_to_20, 14..14, 8) == expected_numbers\n      end\n\n      assert Enum.slide([:a, :b, :c, :d, :e, :f], 3..3, 2) == [:a, :b, :d, :c, :e, :f]\n      assert Enum.slide([:a, :b, :c, :d, :e, :f], 3, 3) == [:a, :b, :c, :d, :e, :f]\n    end\n\n    test \"on a subsection of a list reorders the range correctly\" do\n      for zero_to_20 <- [0..20, Enum.to_list(0..20)] do\n        expected_numbers = Enum.flat_map([0..7, 14..18, 8..13, 19..20], &Enum.to_list/1)\n        assert Enum.slide(zero_to_20, 14..18, 8) == expected_numbers\n      end\n\n      assert Enum.slide([:a, :b, :c, :d, :e, :f], 3..4, 2) == [:a, :b, :d, :e, :c, :f]\n    end\n\n    test \"handles negative indices\" do\n      make_negative_range = fn first..last//1, length ->\n        (first - length)..(last - length)//1\n      end\n\n      test_specs = [\n        {[], 0..0, 0},\n        {[1], 0..0, 0},\n        {[-2, 1], 1..1, 1},\n        {[4, -3, 2, -1], 3..3, 2},\n        {[-5, -3, 4, 4, 5], 0..2, 3},\n        {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4..7, 9},\n        {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4..7, 0}\n      ]\n\n      for {list, range, insertion_point} <- test_specs do\n        negative_range = make_negative_range.(range, length(list))\n\n        assert Enum.slide(list, negative_range, insertion_point) ==\n                 Enum.slide(list, range, insertion_point)\n      end\n    end\n\n    test \"handles mixed positive and negative indices\" do\n      for zero_to_20 <- [0..20, Enum.to_list(0..20)] do\n        assert Enum.slide(zero_to_20, -6..-1, 8) ==\n                 Enum.slide(zero_to_20, 15..20, 8)\n\n        assert Enum.slide(zero_to_20, 15..-1//1, 8) ==\n                 Enum.slide(zero_to_20, 15..20, 8)\n\n        assert Enum.slide(zero_to_20, -6..20, 8) ==\n                 Enum.slide(zero_to_20, 15..20, 8)\n\n        assert Enum.slide(zero_to_20, -100..5, 8) ==\n                 Enum.slide(zero_to_20, 0..5, 8)\n      end\n    end\n\n    test \"raises an error when the step is not exactly 1\" do\n      slide_ranges_that_should_fail = [2..10//2, 8..-1//-1, 10..2//-1, 10..4//-2, -1..-8//-1]\n\n      for zero_to_20 <- [0..20, Enum.to_list(0..20)],\n          range_that_should_fail <- slide_ranges_that_should_fail do\n        assert_raise(ArgumentError, fn ->\n          Enum.slide(zero_to_20, range_that_should_fail, 1)\n        end)\n      end\n    end\n\n    test \"doesn't change the order when the first and middle indices match\" do\n      for zero_to_20 <- [0..20, Enum.to_list(0..20)] do\n        assert Enum.slide(zero_to_20, 8..18, 8) == Enum.to_list(0..20)\n      end\n\n      assert Enum.slide([:a, :b, :c, :d, :e, :f], 1..3, 1) == [:a, :b, :c, :d, :e, :f]\n    end\n\n    test \"on the whole of an enumerable reorders it correctly\" do\n      for zero_to_20 <- [0..20, Enum.to_list(0..20)] do\n        expected_numbers = Enum.flat_map([10..20, 0..9], &Enum.to_list/1)\n        assert Enum.slide(zero_to_20, 10..20, 0) == expected_numbers\n      end\n\n      assert Enum.slide([:a, :b, :c, :d, :e, :f], 4..5, 0) == [:e, :f, :a, :b, :c, :d]\n    end\n\n    test \"raises when the insertion point is inside the range\" do\n      for zero_to_20 <- [0..20, Enum.to_list(0..20)] do\n        assert_raise ArgumentError, fn ->\n          Enum.slide(zero_to_20, 10..18, 14)\n        end\n      end\n    end\n\n    test \"accepts range starts that are off the end of the enum, returning the input list\" do\n      assert Enum.slide([], 1..5, 0) == []\n\n      for zero_to_20 <- [0..20, Enum.to_list(0..20)] do\n        assert Enum.slide(zero_to_20, 21..25, 3) == Enum.to_list(0..20)\n      end\n    end\n\n    test \"accepts range ends that are off the end of the enum, truncating the moved range\" do\n      for zero_to_10 <- [0..10, Enum.to_list(0..10)] do\n        assert Enum.slide(zero_to_10, 8..15, 4) == Enum.slide(zero_to_10, 8..10, 4)\n      end\n    end\n\n    test \"matches behavior for lists vs. ranges\" do\n      range = 0..20\n      list = Enum.to_list(range)\n      # Below 32 elements, the map implementation currently sticks values in order.\n      # If ever the MapSet implementation changes, this will fail (not affecting the correctness\n      # of slide). I figured it'd be worth testing this for the time being just to have\n      # another enumerable (aside from range) testing the generic implementation.\n      set = MapSet.new(list)\n\n      test_specs = [\n        {0..0, 0},\n        {0..0, 20},\n        {11..11, 14},\n        {11..11, 3},\n        {4..8, 19},\n        {4..8, 0},\n        {4..8, 2},\n        {10..20, 0},\n        {2..1//1, -20}\n      ]\n\n      for {slide_range, insertion_point} <- test_specs do\n        slide = &Enum.slide(&1, slide_range, insertion_point)\n        assert slide.(list) == slide.(set)\n        assert slide.(list) == slide.(range)\n      end\n    end\n\n    test \"inserts at negative indices\" do\n      for zero_to_5 <- [0..5, Enum.to_list(0..5)] do\n        assert Enum.slide(zero_to_5, 0, -1) == [1, 2, 3, 4, 5, 0]\n        assert Enum.slide(zero_to_5, 1, -1) == [0, 2, 3, 4, 5, 1]\n        assert Enum.slide(zero_to_5, 1..2, -2) == [0, 3, 4, 1, 2, 5]\n        assert Enum.slide(zero_to_5, -5..-4//1, -2) == [0, 3, 4, 1, 2, 5]\n      end\n\n      assert Enum.slide([:a, :b, :c, :d, :e, :f], -5..-3//1, -2) ==\n               Enum.slide([:a, :b, :c, :d, :e, :f], 1..3, 4)\n    end\n\n    test \"raises when insertion index would fall inside the range\" do\n      for zero_to_5 <- [0..5, Enum.to_list(0..5)] do\n        assert_raise ArgumentError, fn ->\n          Enum.slide(zero_to_5, 2..3, -3)\n        end\n      end\n\n      for zero_to_10 <- [0..10, Enum.to_list(0..10)],\n          insertion_idx <- 3..5 do\n        assert_raise ArgumentError, fn ->\n          assert Enum.slide(zero_to_10, 2..5, insertion_idx)\n        end\n      end\n    end\n  end\n\n  test \"scan/2\" do\n    assert Enum.scan([1, 2, 3, 4, 5], &(&1 + &2)) == [1, 3, 6, 10, 15]\n    assert Enum.scan([], &(&1 + &2)) == []\n  end\n\n  test \"scan/3\" do\n    assert Enum.scan([1, 2, 3, 4, 5], 0, &(&1 + &2)) == [1, 3, 6, 10, 15]\n    assert Enum.scan([], 0, &(&1 + &2)) == []\n  end\n\n  test \"shuffle/1\" do\n    # set a fixed seed so the test can be deterministic\n    :rand.seed(:exsss, {1374, 347_975, 449_264})\n    assert Enum.shuffle([1, 2, 3, 4, 5]) == [2, 5, 4, 3, 1]\n  end\n\n  test \"slice/2\" do\n    list = [1, 2, 3, 4, 5]\n    assert Enum.slice(list, 0..0) == [1]\n    assert Enum.slice(list, 0..1) == [1, 2]\n    assert Enum.slice(list, 0..2) == [1, 2, 3]\n\n    assert Enum.slice(list, 0..10//2) == [1, 3, 5]\n    assert Enum.slice(list, 0..10//3) == [1, 4]\n    assert Enum.slice(list, 0..10//4) == [1, 5]\n    assert Enum.slice(list, 0..10//5) == [1]\n    assert Enum.slice(list, 0..10//6) == [1]\n\n    assert Enum.slice(list, 0..2//2) == [1, 3]\n    assert Enum.slice(list, 0..2//3) == [1]\n\n    assert Enum.slice(list, 0..-1//2) == [1, 3, 5]\n    assert Enum.slice(list, 0..-1//3) == [1, 4]\n    assert Enum.slice(list, 0..-1//4) == [1, 5]\n    assert Enum.slice(list, 0..-1//5) == [1]\n    assert Enum.slice(list, 0..-1//6) == [1]\n\n    assert Enum.slice(list, 1..-1//2) == [2, 4]\n    assert Enum.slice(list, 1..-1//3) == [2, 5]\n    assert Enum.slice(list, 1..-1//4) == [2]\n    assert Enum.slice(list, 1..-1//5) == [2]\n\n    assert Enum.slice(list, -4..-1//2) == [2, 4]\n    assert Enum.slice(list, -4..-1//3) == [2, 5]\n    assert Enum.slice(list, -4..-1//4) == [2]\n    assert Enum.slice(list, -4..-1//5) == [2]\n  end\n\n  test \"slice/3\" do\n    list = [1, 2, 3, 4, 5]\n    assert Enum.slice(list, 0, 0) == []\n    assert Enum.slice(list, 0, 1) == [1]\n    assert Enum.slice(list, 0, 2) == [1, 2]\n    assert Enum.slice(list, 1, 2) == [2, 3]\n    assert Enum.slice(list, 1, 0) == []\n    assert Enum.slice(list, 2, 5) == [3, 4, 5]\n    assert Enum.slice(list, 2, 6) == [3, 4, 5]\n    assert Enum.slice(list, 5, 5) == []\n    assert Enum.slice(list, 6, 5) == []\n    assert Enum.slice(list, 6, 0) == []\n    assert Enum.slice(list, -6, 0) == []\n    assert Enum.slice(list, -6, 5) == [1, 2, 3, 4, 5]\n    assert Enum.slice(list, -2, 5) == [4, 5]\n    assert Enum.slice(list, -3, 1) == [3]\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.slice(list, 0, -1)\n    end\n  end\n\n  test \"slice on infinite streams\" do\n    assert [1, 2, 3] |> Stream.cycle() |> Enum.slice(0, 2) == [1, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Enum.slice(0, 5) == [1, 2, 3, 1, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Enum.slice(0..1) == [1, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Enum.slice(0..4) == [1, 2, 3, 1, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Enum.slice(0..4//2) == [1, 3, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Enum.slice(0..5//2) == [1, 3, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Enum.slice(1..6//2) == [2, 1, 3]\n  end\n\n  test \"slice on pruned infinite streams\" do\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(0, 2) == [1, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(0, 5) == [1, 2, 3, 1, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(0..1) == [1, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(0..4) == [1, 2, 3, 1, 2]\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(0..4//2) == [1, 3, 2]\n\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(-10..-9//1) ==\n             [1, 2]\n\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(-10..-6//1) ==\n             [1, 2, 3, 1, 2]\n\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(-10..-6//2) ==\n             [1, 3, 2]\n\n    assert [1, 2, 3] |> Stream.cycle() |> Stream.take(10) |> Enum.slice(-9..-5//2) ==\n             [2, 1, 3]\n  end\n\n  test \"slice on MapSets\" do\n    assert MapSet.new(1..10) |> Enum.slice(0, 2) |> Enum.count() == 2\n    assert MapSet.new(1..3) |> Enum.slice(0, 10) |> Enum.count() == 3\n    assert MapSet.new(1..10) |> Enum.slice(0..1) |> Enum.count() == 2\n    assert MapSet.new(1..3) |> Enum.slice(0..10) |> Enum.count() == 3\n\n    assert MapSet.new(1..10) |> Enum.slice(0..4//2) |> Enum.count() == 3\n    assert MapSet.new(1..10) |> Enum.slice(0..5//2) |> Enum.count() == 3\n  end\n\n  test \"sort/1\" do\n    assert Enum.sort([5, 3, 2, 4, 1]) == [1, 2, 3, 4, 5]\n  end\n\n  test \"sort/2\" do\n    assert Enum.sort([5, 3, 2, 4, 1], &(&1 >= &2)) == [5, 4, 3, 2, 1]\n    assert Enum.sort([5, 3, 2, 4, 1], :asc) == [1, 2, 3, 4, 5]\n    assert Enum.sort([5, 3, 2, 4, 1], :desc) == [5, 4, 3, 2, 1]\n\n    assert Enum.sort([3, 2, 1, 3, 2, 3], :asc) == [1, 2, 2, 3, 3, 3]\n    assert Enum.sort([3, 2, 1, 3, 2, 3], :desc) == [3, 3, 3, 2, 2, 1]\n\n    shuffled = Enum.shuffle(1..100)\n    assert Enum.sort(shuffled, :asc) == Enum.to_list(1..100)\n    assert Enum.sort(shuffled, :desc) == Enum.reverse(1..100)\n  end\n\n  test \"sort/2 with module\" do\n    assert Enum.sort([~D[2020-01-01], ~D[2018-01-01], ~D[2019-01-01]], Date) ==\n             [~D[2018-01-01], ~D[2019-01-01], ~D[2020-01-01]]\n\n    assert Enum.sort([~D[2020-01-01], ~D[2018-01-01], ~D[2019-01-01]], {:asc, Date}) ==\n             [~D[2018-01-01], ~D[2019-01-01], ~D[2020-01-01]]\n\n    assert Enum.sort([~D[2020-01-01], ~D[2018-01-01], ~D[2019-01-01]], {:desc, Date}) ==\n             [~D[2020-01-01], ~D[2019-01-01], ~D[2018-01-01]]\n  end\n\n  test \"sort/2 with streams\" do\n    sort_stream = fn list, sorter -> list |> Stream.map(& &1) |> Enum.sort(sorter) end\n\n    assert sort_stream.([5, 3, 2, 4, 1], &(&1 >= &2)) == [5, 4, 3, 2, 1]\n    assert sort_stream.([5, 3, 2, 4, 1], :asc) == [1, 2, 3, 4, 5]\n    assert sort_stream.([5, 3, 2, 4, 1], :desc) == [5, 4, 3, 2, 1]\n\n    assert sort_stream.([3, 2, 1, 3, 2, 3], :asc) == [1, 2, 2, 3, 3, 3]\n    assert sort_stream.([3, 2, 1, 3, 2, 3], :desc) == [3, 3, 3, 2, 2, 1]\n\n    shuffled = Enum.shuffle(1..100)\n    assert sort_stream.(shuffled, :asc) == Enum.to_list(1..100)\n    assert sort_stream.(shuffled, :desc) == Enum.reverse(1..100)\n  end\n\n  test \"sort_by/3\" do\n    collection = [\n      [sorted_data: 4],\n      [sorted_data: 5],\n      [sorted_data: 2],\n      [sorted_data: 1],\n      [sorted_data: 3]\n    ]\n\n    asc = [\n      [sorted_data: 1],\n      [sorted_data: 2],\n      [sorted_data: 3],\n      [sorted_data: 4],\n      [sorted_data: 5]\n    ]\n\n    desc = [\n      [sorted_data: 5],\n      [sorted_data: 4],\n      [sorted_data: 3],\n      [sorted_data: 2],\n      [sorted_data: 1]\n    ]\n\n    assert Enum.sort_by(collection, & &1[:sorted_data]) == asc\n    assert Enum.sort_by(collection, & &1[:sorted_data], :asc) == asc\n    assert Enum.sort_by(collection, & &1[:sorted_data], &>=/2) == desc\n    assert Enum.sort_by(collection, & &1[:sorted_data], :desc) == desc\n  end\n\n  test \"sort_by/3 with stable sorting\" do\n    collection = [\n      [other_data: 2, sorted_data: 4],\n      [other_data: 1, sorted_data: 5],\n      [other_data: 2, sorted_data: 2],\n      [other_data: 3, sorted_data: 1],\n      [other_data: 4, sorted_data: 3]\n    ]\n\n    # Stable sorting\n    assert Enum.sort_by(collection, & &1[:other_data]) == [\n             [other_data: 1, sorted_data: 5],\n             [other_data: 2, sorted_data: 4],\n             [other_data: 2, sorted_data: 2],\n             [other_data: 3, sorted_data: 1],\n             [other_data: 4, sorted_data: 3]\n           ]\n\n    assert Enum.sort_by(collection, & &1[:other_data]) ==\n             Enum.sort_by(collection, & &1[:other_data], :asc)\n\n    assert Enum.sort_by(collection, & &1[:other_data], &</2) == [\n             [other_data: 1, sorted_data: 5],\n             [other_data: 2, sorted_data: 2],\n             [other_data: 2, sorted_data: 4],\n             [other_data: 3, sorted_data: 1],\n             [other_data: 4, sorted_data: 3]\n           ]\n\n    assert Enum.sort_by(collection, & &1[:other_data], :desc) == [\n             [other_data: 4, sorted_data: 3],\n             [other_data: 3, sorted_data: 1],\n             [other_data: 2, sorted_data: 4],\n             [other_data: 2, sorted_data: 2],\n             [other_data: 1, sorted_data: 5]\n           ]\n  end\n\n  test \"sort_by/3 with module\" do\n    collection = [\n      [sorted_data: ~D[2010-01-05]],\n      [sorted_data: ~D[2010-01-04]],\n      [sorted_data: ~D[2010-01-03]],\n      [sorted_data: ~D[2010-01-02]],\n      [sorted_data: ~D[2010-01-01]]\n    ]\n\n    assert Enum.sort_by(collection, & &1[:sorted_data], Date) == [\n             [sorted_data: ~D[2010-01-01]],\n             [sorted_data: ~D[2010-01-02]],\n             [sorted_data: ~D[2010-01-03]],\n             [sorted_data: ~D[2010-01-04]],\n             [sorted_data: ~D[2010-01-05]]\n           ]\n\n    assert Enum.sort_by(collection, & &1[:sorted_data], Date) ==\n             assert(Enum.sort_by(collection, & &1[:sorted_data], {:asc, Date}))\n\n    assert Enum.sort_by(collection, & &1[:sorted_data], {:desc, Date}) == [\n             [sorted_data: ~D[2010-01-05]],\n             [sorted_data: ~D[2010-01-04]],\n             [sorted_data: ~D[2010-01-03]],\n             [sorted_data: ~D[2010-01-02]],\n             [sorted_data: ~D[2010-01-01]]\n           ]\n  end\n\n  test \"sort_by/3 with module and stable sorting\" do\n    collection = [\n      [other_data: ~D[2010-01-02], sorted_data: 4],\n      [other_data: ~D[2010-01-01], sorted_data: 5],\n      [other_data: ~D[2010-01-02], sorted_data: 2],\n      [other_data: ~D[2010-01-03], sorted_data: 1],\n      [other_data: ~D[2010-01-04], sorted_data: 3]\n    ]\n\n    # Stable sorting\n    assert Enum.sort_by(collection, & &1[:other_data], Date) == [\n             [other_data: ~D[2010-01-01], sorted_data: 5],\n             [other_data: ~D[2010-01-02], sorted_data: 4],\n             [other_data: ~D[2010-01-02], sorted_data: 2],\n             [other_data: ~D[2010-01-03], sorted_data: 1],\n             [other_data: ~D[2010-01-04], sorted_data: 3]\n           ]\n\n    assert Enum.sort_by(collection, & &1[:other_data], Date) ==\n             Enum.sort_by(collection, & &1[:other_data], {:asc, Date})\n\n    assert Enum.sort_by(collection, & &1[:other_data], {:desc, Date}) == [\n             [other_data: ~D[2010-01-04], sorted_data: 3],\n             [other_data: ~D[2010-01-03], sorted_data: 1],\n             [other_data: ~D[2010-01-02], sorted_data: 4],\n             [other_data: ~D[2010-01-02], sorted_data: 2],\n             [other_data: ~D[2010-01-01], sorted_data: 5]\n           ]\n  end\n\n  test \"split/2\" do\n    assert Enum.split([1, 2, 3], 0) == {[], [1, 2, 3]}\n    assert Enum.split([1, 2, 3], 1) == {[1], [2, 3]}\n    assert Enum.split([1, 2, 3], 2) == {[1, 2], [3]}\n    assert Enum.split([1, 2, 3], 3) == {[1, 2, 3], []}\n    assert Enum.split([1, 2, 3], 4) == {[1, 2, 3], []}\n    assert Enum.split([], 3) == {[], []}\n    assert Enum.split([1, 2, 3], -1) == {[1, 2], [3]}\n    assert Enum.split([1, 2, 3], -2) == {[1], [2, 3]}\n    assert Enum.split([1, 2, 3], -3) == {[], [1, 2, 3]}\n    assert Enum.split([1, 2, 3], -10) == {[], [1, 2, 3]}\n  end\n\n  test \"split_while/2\" do\n    assert Enum.split_while([1, 2, 3], fn _ -> false end) == {[], [1, 2, 3]}\n    assert Enum.split_while([1, 2, 3], fn _ -> true end) == {[1, 2, 3], []}\n    assert Enum.split_while([1, 2, 3], fn x -> x > 2 end) == {[], [1, 2, 3]}\n    assert Enum.split_while([1, 2, 3], fn x -> x > 3 end) == {[], [1, 2, 3]}\n    assert Enum.split_while([1, 2, 3], fn x -> x < 3 end) == {[1, 2], [3]}\n    assert Enum.split_while([], fn _ -> true end) == {[], []}\n  end\n\n  test \"sum/1\" do\n    assert Enum.sum([]) == 0\n    assert Enum.sum([1]) == 1\n    assert Enum.sum([1, 2, 3]) == 6\n    assert Enum.sum([1.1, 2.2, 3.3]) == 6.6\n    assert Enum.sum([-3, -2, -1, 0, 1, 2, 3]) == 0\n    assert Enum.sum(42..42) == 42\n    assert Enum.sum(11..17) == 98\n    assert Enum.sum(17..11//-1) == 98\n    assert Enum.sum(11..-17//-1) == Enum.sum(-17..11)\n\n    assert_raise ArithmeticError, fn ->\n      Enum.sum([{}])\n    end\n\n    assert_raise ArithmeticError, fn ->\n      Enum.sum([1, {}])\n    end\n  end\n\n  test \"sum_by/2\" do\n    assert Enum.sum_by([], &hd/1) == 0\n    assert Enum.sum_by([[1]], &hd/1) == 1\n    assert Enum.sum_by([[1], [2], [3]], &hd/1) == 6\n    assert Enum.sum_by([[1.1], [2.2], [3.3]], &hd/1) == 6.6\n    assert Enum.sum_by([[-3], [-2], [-1], [0], [1], [2], [3]], &hd/1) == 0\n\n    assert Enum.sum_by(1..3, &(&1 ** 2)) == 14\n\n    assert_raise ArithmeticError, fn ->\n      Enum.sum_by([[{}]], &hd/1)\n    end\n\n    assert_raise ArithmeticError, fn ->\n      Enum.sum_by([[1], [{}]], &hd/1)\n    end\n  end\n\n  test \"product/1\" do\n    assert Enum.product([]) == 1\n    assert Enum.product([1]) == 1\n    assert Enum.product([1, 2, 3, 4, 5]) == 120\n    assert Enum.product([1, -2, 3, 4, 5]) == -120\n    assert Enum.product(1..5) == 120\n    assert Enum.product(11..-17//-1) == Enum.product(-17..11)\n\n    assert_raise ArithmeticError, fn ->\n      Enum.product([{}])\n    end\n\n    assert_raise ArithmeticError, fn ->\n      Enum.product([1, {}])\n    end\n\n    assert_raise ArithmeticError, fn ->\n      Enum.product(%{a: 1, b: 2})\n    end\n  end\n\n  test \"product_by/2\" do\n    assert Enum.product_by([], &hd/1) == 1\n    assert Enum.product_by([[1]], &hd/1) == 1\n    assert Enum.product_by([[1], [2], [3], [4], [5]], &hd/1) == 120\n    assert Enum.product_by([[1], [-2], [3], [4], [5]], &hd/1) == -120\n    assert Enum.product_by(1..5, & &1) == 120\n    assert Enum.product_by(11..-17//-1, & &1) == 0\n\n    assert_raise ArithmeticError, fn ->\n      Enum.product_by([[{}]], &hd/1)\n    end\n\n    assert_raise ArithmeticError, fn ->\n      Enum.product_by([[1], [{}]], &hd/1)\n    end\n\n    assert_raise ArithmeticError, fn ->\n      Enum.product_by(%{a: 1, b: 2}, & &1)\n    end\n  end\n\n  test \"take/2\" do\n    assert Enum.take([1, 2, 3], 0) == []\n    assert Enum.take([1, 2, 3], 1) == [1]\n    assert Enum.take([1, 2, 3], 2) == [1, 2]\n    assert Enum.take([1, 2, 3], 3) == [1, 2, 3]\n    assert Enum.take([1, 2, 3], 4) == [1, 2, 3]\n    assert Enum.take([1, 2, 3], -1) == [3]\n    assert Enum.take([1, 2, 3], -2) == [2, 3]\n    assert Enum.take([1, 2, 3], -4) == [1, 2, 3]\n    assert Enum.take([], 3) == []\n  end\n\n  test \"take_every/2\" do\n    assert Enum.take_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2) == [1, 3, 5, 7, 9]\n    assert Enum.take_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3) == [1, 4, 7, 10]\n    assert Enum.take_every([], 2) == []\n    assert Enum.take_every([1, 2], 2) == [1]\n    assert Enum.take_every([1, 2, 3], 0) == []\n    assert Enum.take_every(1..3, 1) == [1, 2, 3]\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.take_every([1, 2, 3], -1)\n    end\n  end\n\n  test \"take_random/2\" do\n    assert Enum.take_random(-42..-42, 1) == [-42]\n\n    # corner cases, independent of the seed\n    assert_raise FunctionClauseError, fn -> Enum.take_random([1, 2], -1) end\n    assert Enum.take_random([], 0) == []\n    assert Enum.take_random([], 3) == []\n    assert Enum.take_random([1], 0) == []\n    assert Enum.take_random([1], 2) == [1]\n    assert Enum.take_random([1, 2], 0) == []\n\n    # set a fixed seed so the test can be deterministic\n    # please note the order of following assertions is important\n    seed1 = {1406, 407_414, 139_258}\n    seed2 = {1406, 421_106, 567_597}\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random([1, 2, 3], 1) == [2]\n    assert Enum.take_random([1, 2, 3], 2) == [2, 3]\n    assert Enum.take_random([1, 2, 3], 3) == [3, 1, 2]\n    assert Enum.take_random([1, 2, 3], 4) == [2, 3, 1]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random([1, 2, 3], 1) == [1]\n    assert Enum.take_random([1, 2, 3], 2) == [3, 1]\n    assert Enum.take_random([1, 2, 3], 3) == [2, 3, 1]\n    assert Enum.take_random([1, 2, 3], 4) == [3, 2, 1]\n    assert Enum.take_random([1, 2, 3], 129) == [2, 1, 3]\n\n    # assert that every item in the sample comes from the input list\n    list = for _ <- 1..100, do: make_ref()\n\n    for x <- Enum.take_random(list, 50) do\n      assert x in list\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.take_random(1..10, -1)\n    end\n  end\n\n  test \"take_while/2\" do\n    assert Enum.take_while([1, 2, 3], fn x -> x > 3 end) == []\n    assert Enum.take_while([1, 2, 3], fn x -> x <= 1 end) == [1]\n    assert Enum.take_while([1, 2, 3], fn x -> x <= 3 end) == [1, 2, 3]\n    assert Enum.take_while([], fn _ -> true end) == []\n  end\n\n  test \"to_list/1\" do\n    assert Enum.to_list([]) == []\n  end\n\n  test \"uniq/1\" do\n    assert Enum.uniq([5, 1, 2, 3, 2, 1]) == [5, 1, 2, 3]\n  end\n\n  test \"uniq_by/2\" do\n    assert Enum.uniq_by([1, 2, 3, 2, 1], fn x -> x end) == [1, 2, 3]\n  end\n\n  test \"unzip/1\" do\n    assert Enum.unzip([{:a, 1}, {:b, 2}, {:c, 3}]) == {[:a, :b, :c], [1, 2, 3]}\n    assert Enum.unzip([]) == {[], []}\n    assert Enum.unzip(%{a: 1}) == {[:a], [1]}\n    assert Enum.unzip(foo: \"a\", bar: \"b\") == {[:foo, :bar], [\"a\", \"b\"]}\n\n    assert_raise FunctionClauseError, fn -> Enum.unzip([{:a, 1}, {:b, 2, \"foo\"}]) end\n    assert_raise FunctionClauseError, fn -> Enum.unzip([{1, 2, {3, {4, 5}}}]) end\n    assert_raise FunctionClauseError, fn -> Enum.unzip([1, 2, 3]) end\n  end\n\n  test \"with_index/2\" do\n    assert Enum.with_index([]) == []\n    assert Enum.with_index([1, 2, 3]) == [{1, 0}, {2, 1}, {3, 2}]\n    assert Enum.with_index([1, 2, 3], 10) == [{1, 10}, {2, 11}, {3, 12}]\n\n    assert Enum.with_index([1, 2, 3], fn element, index -> {index, element} end) ==\n             [{0, 1}, {1, 2}, {2, 3}]\n\n    assert Enum.with_index(1..0//1) == []\n    assert Enum.with_index(1..3) == [{1, 0}, {2, 1}, {3, 2}]\n    assert Enum.with_index(1..3, 10) == [{1, 10}, {2, 11}, {3, 12}]\n\n    assert Enum.with_index(1..3, fn element, index -> {index, element} end) ==\n             [{0, 1}, {1, 2}, {2, 3}]\n  end\n\n  test \"zip/2\" do\n    assert Enum.zip([:a, :b], [1, 2]) == [{:a, 1}, {:b, 2}]\n    assert Enum.zip([:a, :b], [1, 2, 3, 4]) == [{:a, 1}, {:b, 2}]\n    assert Enum.zip([:a, :b, :c, :d], [1, 2]) == [{:a, 1}, {:b, 2}]\n\n    assert Enum.zip([], [1]) == []\n    assert Enum.zip([1], []) == []\n    assert Enum.zip([], []) == []\n  end\n\n  test \"zip/2 with infinite streams\" do\n    assert Enum.zip([], Stream.cycle([1, 2])) == []\n    assert Enum.zip([], Stream.cycle(1..2)) == []\n    assert Enum.zip(.., Stream.cycle([1, 2])) == []\n    assert Enum.zip(.., Stream.cycle(1..2)) == []\n\n    assert Enum.zip(Stream.cycle([1, 2]), ..) == []\n    assert Enum.zip(Stream.cycle(1..2), ..) == []\n    assert Enum.zip(Stream.cycle([1, 2]), ..) == []\n    assert Enum.zip(Stream.cycle(1..2), ..) == []\n  end\n\n  test \"zip/1\" do\n    assert Enum.zip([[:a, :b], [1, 2], [\"foo\", \"bar\"]]) == [{:a, 1, \"foo\"}, {:b, 2, \"bar\"}]\n\n    assert Enum.zip([[:a, :b], [1, 2, 3, 4], [\"foo\", \"bar\", \"baz\", \"qux\"]]) ==\n             [{:a, 1, \"foo\"}, {:b, 2, \"bar\"}]\n\n    assert Enum.zip([[:a, :b, :c, :d], [1, 2], [\"foo\", \"bar\", \"baz\", \"qux\"]]) ==\n             [{:a, 1, \"foo\"}, {:b, 2, \"bar\"}]\n\n    assert Enum.zip([[:a, :b, :c, :d], [1, 2, 3, 4], [\"foo\", \"bar\"]]) ==\n             [{:a, 1, \"foo\"}, {:b, 2, \"bar\"}]\n\n    assert Enum.zip([1..10, [\"foo\", \"bar\"]]) == [{1, \"foo\"}, {2, \"bar\"}]\n\n    assert Enum.zip([]) == []\n    assert Enum.zip([[]]) == []\n    assert Enum.zip([[1]]) == [{1}]\n\n    assert Enum.zip([[], [], [], []]) == []\n    assert Enum.zip(%{}) == []\n  end\n\n  test \"zip_with/3\" do\n    assert Enum.zip_with([1, 2], [3, 4], fn a, b -> a * b end) == [3, 8]\n    assert Enum.zip_with([:a, :b], [1, 2], &{&1, &2}) == [{:a, 1}, {:b, 2}]\n    assert Enum.zip_with([:a, :b], [1, 2, 3, 4], &{&1, &2}) == [{:a, 1}, {:b, 2}]\n    assert Enum.zip_with([:a, :b, :c, :d], [1, 2], &{&1, &2}) == [{:a, 1}, {:b, 2}]\n    assert Enum.zip_with([], [1], &{&1, &2}) == []\n    assert Enum.zip_with([1], [], &{&1, &2}) == []\n    assert Enum.zip_with([], [], &{&1, &2}) == []\n\n    # Ranges\n    assert Enum.zip_with(1..6, 3..4, fn a, b -> a + b end) == [4, 6]\n    assert Enum.zip_with([1, 2, 5, 6], 3..4, fn a, b -> a + b end) == [4, 6]\n    assert Enum.zip_with(fn _, _ -> {:cont, [1, 2]} end, 3..4, fn a, b -> a + b end) == [4, 6]\n    assert Enum.zip_with(1..1, 0..0, fn a, b -> a + b end) == [1]\n\n    # Date.range\n    week_1 = Date.range(~D[2020-10-12], ~D[2020-10-16])\n    week_2 = Date.range(~D[2020-10-19], ~D[2020-10-23])\n\n    result =\n      Enum.zip_with(week_1, week_2, fn a, b ->\n        Date.day_of_week(a) + Date.day_of_week(b)\n      end)\n\n    assert result == [2, 4, 6, 8, 10]\n\n    # Maps\n    result = Enum.zip_with(%{a: 7}, 3..4, fn {key, value}, b -> {key, value + b} end)\n    assert result == [a: 10]\n\n    result = Enum.zip_with(3..4, %{a: 7}, fn a, {key, value} -> {key, value + a} end)\n    assert result == [a: 10]\n  end\n\n  test \"zip_with/2\" do\n    zip_fun = fn items -> List.to_tuple(items) end\n    result = Enum.zip_with([[:a, :b], [1, 2], [\"foo\", \"bar\"]], zip_fun)\n    assert result == [{:a, 1, \"foo\"}, {:b, 2, \"bar\"}]\n\n    map = %{a: :b, c: :d}\n    [x1, x2] = Map.to_list(map)\n    lots = Enum.zip_with([[:a, :b], [1, 2], [\"foo\", \"bar\"], map], zip_fun)\n    assert lots == [{:a, 1, \"foo\", x1}, {:b, 2, \"bar\", x2}]\n\n    assert Enum.zip_with([[:a, :b], [1, 2, 3, 4], [\"foo\", \"bar\", \"baz\", \"qux\"]], zip_fun) ==\n             [{:a, 1, \"foo\"}, {:b, 2, \"bar\"}]\n\n    assert Enum.zip_with([[:a, :b, :c, :d], [1, 2], [\"foo\", \"bar\", \"baz\", \"qux\"]], zip_fun) ==\n             [{:a, 1, \"foo\"}, {:b, 2, \"bar\"}]\n\n    assert Enum.zip_with([[:a, :b, :c, :d], [1, 2, 3, 4], [\"foo\", \"bar\"]], zip_fun) ==\n             [{:a, 1, \"foo\"}, {:b, 2, \"bar\"}]\n\n    assert Enum.zip_with([1..10, [\"foo\", \"bar\"]], zip_fun) == [{1, \"foo\"}, {2, \"bar\"}]\n    assert Enum.zip_with([], zip_fun) == []\n    assert Enum.zip_with([[]], zip_fun) == []\n    assert Enum.zip_with([[1]], zip_fun) == [{1}]\n    assert Enum.zip_with([[], [], [], []], zip_fun) == []\n    assert Enum.zip_with(%{}, zip_fun) == []\n    assert Enum.zip_with([[1, 2, 5, 6], 3..4], fn [x, y] -> x + y end) == [4, 6]\n\n    # Ranges\n    assert Enum.zip_with([1..6, 3..4], fn [a, b] -> a + b end) == [4, 6]\n    assert Enum.zip_with([[1, 2, 5, 6], 3..4], fn [a, b] -> a + b end) == [4, 6]\n    assert Enum.zip_with([fn _, _ -> {:cont, [1, 2]} end, 3..4], fn [a, b] -> a + b end) == [4, 6]\n    assert Enum.zip_with([1..1, 0..0], fn [a, b] -> a + b end) == [1]\n\n    # Date.range\n    week_1 = Date.range(~D[2020-10-12], ~D[2020-10-16])\n    week_2 = Date.range(~D[2020-10-19], ~D[2020-10-23])\n\n    result =\n      Enum.zip_with([week_1, week_2], fn [a, b] ->\n        Date.day_of_week(a) + Date.day_of_week(b)\n      end)\n\n    assert result == [2, 4, 6, 8, 10]\n\n    # Maps\n    result = Enum.zip_with([%{a: 7}, 3..4], fn [{key, value}, b] -> {key, value + b} end)\n    assert result == [a: 10]\n\n    result = Enum.zip_with([%{a: 7}, 3..4], fn [{key, value}, b] -> {key, value + b} end)\n    assert result == [a: 10]\n  end\nend\n\ndefmodule EnumTest.Range do\n  # Ranges use custom callbacks for protocols in many operations.\n  use ExUnit.Case, async: true\n\n  test \"all?/2\" do\n    assert Enum.all?(0..1)\n    assert Enum.all?(1..0//-1)\n    refute Enum.all?(0..5, fn x -> rem(x, 2) == 0 end)\n    assert Enum.all?(0..1, fn x -> x < 2 end)\n\n    assert Enum.all?(0..1//-1)\n    assert Enum.all?(0..5//2, fn x -> rem(x, 2) == 0 end)\n    refute Enum.all?(1..5//2, fn x -> rem(x, 2) == 0 end)\n  end\n\n  test \"any?/2\" do\n    assert Enum.any?(1..0//-1)\n    refute Enum.any?(0..5, &(&1 > 10))\n    assert Enum.any?(0..5, &(&1 > 3))\n\n    refute Enum.any?(0..1//-1)\n    assert Enum.any?(0..5//2, fn x -> rem(x, 2) == 0 end)\n    refute Enum.any?(1..5//2, fn x -> rem(x, 2) == 0 end)\n  end\n\n  test \"at/3\" do\n    assert Enum.at(2..6, 0) == 2\n    assert Enum.at(2..6, 4) == 6\n    assert Enum.at(2..6, 6) == nil\n    assert Enum.at(2..6, 6, :none) == :none\n    assert Enum.at(2..6, -2) == 5\n    assert Enum.at(2..6, -8) == nil\n\n    assert Enum.at(0..1//-1, 0) == nil\n    assert Enum.at(1..1//5, 0) == 1\n    assert Enum.at(1..3//2, 0) == 1\n    assert Enum.at(1..3//2, 1) == 3\n    assert Enum.at(1..3//2, 2) == nil\n    assert Enum.at(1..3//2, -1) == 3\n    assert Enum.at(1..3//2, -2) == 1\n    assert Enum.at(1..3//2, -3) == nil\n  end\n\n  test \"chunk_every/2\" do\n    assert Enum.chunk_every(1..5, 2) == [[1, 2], [3, 4], [5]]\n    assert Enum.chunk_every(1..10//2, 2) == [[1, 3], [5, 7], [9]]\n  end\n\n  test \"chunk_every/4\" do\n    assert Enum.chunk_every(1..5, 2, 2) == [[1, 2], [3, 4], [5]]\n    assert Enum.chunk_every(1..6, 3, 2, :discard) == [[1, 2, 3], [3, 4, 5]]\n    assert Enum.chunk_every(1..6, 2, 3, :discard) == [[1, 2], [4, 5]]\n    assert Enum.chunk_every(1..6, 3, 2, []) == [[1, 2, 3], [3, 4, 5], [5, 6]]\n    assert Enum.chunk_every(1..5, 4, 4, 6..10) == [[1, 2, 3, 4], [5, 6, 7, 8]]\n    assert Enum.chunk_every(1..10//2, 4, 4, 11..20) == [[1, 3, 5, 7], [9, 11, 12, 13]]\n  end\n\n  test \"chunk_by/2\" do\n    assert Enum.chunk_by(1..4, fn _ -> true end) == [[1, 2, 3, 4]]\n    assert Enum.chunk_by(1..4, &(rem(&1, 2) == 1)) == [[1], [2], [3], [4]]\n    assert Enum.chunk_by(1..20//3, &(rem(&1, 2) == 1)) == [[1], [4], [7], [10], [13], [16], [19]]\n  end\n\n  test \"concat/1\" do\n    assert Enum.concat([1..2, 4..6]) == [1, 2, 4, 5, 6]\n    assert Enum.concat([1..5, fn acc, _ -> acc end, [1]]) == [1, 2, 3, 4, 5, 1]\n    assert Enum.concat([1..5, 6..10//2]) == [1, 2, 3, 4, 5, 6, 8, 10]\n  end\n\n  test \"concat/2\" do\n    assert Enum.concat(1..3, 4..5) == [1, 2, 3, 4, 5]\n    assert Enum.concat(1..3, [4, 5]) == [1, 2, 3, 4, 5]\n    assert Enum.concat(1..3, []) == [1, 2, 3]\n    assert Enum.concat(1..3, 0..0) == [1, 2, 3, 0]\n    assert Enum.concat(1..5, 6..10//2) == [1, 2, 3, 4, 5, 6, 8, 10]\n    assert Enum.concat(1..5, 0..1//-1) == [1, 2, 3, 4, 5]\n    assert Enum.concat(1..5, 1..0//1) == [1, 2, 3, 4, 5]\n  end\n\n  test \"count/1\" do\n    assert Enum.count(1..5) == 5\n    assert Enum.count(1..1) == 1\n    assert Enum.count(1..9//2) == 5\n    assert Enum.count(1..10//2) == 5\n    assert Enum.count(1..11//2) == 6\n    assert Enum.count(1..11//-2) == 0\n    assert Enum.count(11..1//-2) == 6\n    assert Enum.count(10..1//-2) == 5\n    assert Enum.count(9..1//-2) == 5\n    assert Enum.count(9..1//2) == 0\n  end\n\n  test \"count/2\" do\n    assert Enum.count(1..5, fn x -> rem(x, 2) == 0 end) == 2\n    assert Enum.count(1..1, fn x -> rem(x, 2) == 0 end) == 0\n    assert Enum.count(0..5//2, fn x -> rem(x, 2) == 0 end) == 3\n    assert Enum.count(1..5//2, fn x -> rem(x, 2) == 0 end) == 0\n  end\n\n  test \"dedup/1\" do\n    assert Enum.dedup(1..3) == [1, 2, 3]\n    assert Enum.dedup(1..3//2) == [1, 3]\n  end\n\n  test \"dedup_by/2\" do\n    assert Enum.dedup_by(1..3, fn _ -> 1 end) == [1]\n    assert Enum.dedup_by(1..3//2, fn _ -> 1 end) == [1]\n  end\n\n  test \"drop/2\" do\n    assert Enum.drop(1..3, 0) == [1, 2, 3]\n    assert Enum.drop(1..3, 1) == [2, 3]\n    assert Enum.drop(1..3, 2) == [3]\n    assert Enum.drop(1..3, 3) == []\n    assert Enum.drop(1..3, 4) == []\n    assert Enum.drop(1..3, -1) == [1, 2]\n    assert Enum.drop(1..3, -2) == [1]\n    assert Enum.drop(1..3, -4) == []\n    assert Enum.drop(1..0//-1, 3) == []\n\n    assert Enum.drop(1..9//2, 2) == [5, 7, 9]\n    assert Enum.drop(1..9//2, -2) == [1, 3, 5]\n    assert Enum.drop(9..1//-2, 2) == [5, 3, 1]\n    assert Enum.drop(9..1//-2, -2) == [9, 7, 5]\n  end\n\n  test \"drop_every/2\" do\n    assert Enum.drop_every(1..10, 2) == [2, 4, 6, 8, 10]\n    assert Enum.drop_every(1..10, 3) == [2, 3, 5, 6, 8, 9]\n    assert Enum.drop_every(0..0, 2) == []\n    assert Enum.drop_every(1..2, 2) == [2]\n    assert Enum.drop_every(1..3, 0) == [1, 2, 3]\n    assert Enum.drop_every(1..3, 1) == []\n\n    assert Enum.drop_every(1..5//2, 0) == [1, 3, 5]\n    assert Enum.drop_every(1..5//2, 1) == []\n    assert Enum.drop_every(1..5//2, 2) == [3]\n  end\n\n  test \"drop_while/2\" do\n    assert Enum.drop_while(0..6, fn x -> x <= 3 end) == [4, 5, 6]\n    assert Enum.drop_while(0..6, fn _ -> false end) == [0, 1, 2, 3, 4, 5, 6]\n    assert Enum.drop_while(0..3, fn x -> x <= 3 end) == []\n    assert Enum.drop_while(1..0//-1, fn _ -> nil end) == [1, 0]\n  end\n\n  test \"each/2\" do\n    try do\n      assert Enum.each(1..0//-1, fn x -> x end) == :ok\n      assert Enum.each(1..3, fn x -> Process.put(:enum_test_each, x * 2) end) == :ok\n      assert Process.get(:enum_test_each) == 6\n    after\n      Process.delete(:enum_test_each)\n    end\n\n    try do\n      assert Enum.each(-1..-3//-1, fn x -> Process.put(:enum_test_each, x * 2) end) == :ok\n      assert Process.get(:enum_test_each) == -6\n    after\n      Process.delete(:enum_test_each)\n    end\n  end\n\n  test \"empty?/1\" do\n    refute Enum.empty?(1..0//-1)\n    refute Enum.empty?(1..2)\n    refute Enum.empty?(1..2//2)\n    assert Enum.empty?(1..2//-2)\n  end\n\n  test \"fetch/2\" do\n    # ascending order\n    assert Enum.fetch(-10..20, 4) == {:ok, -6}\n    assert Enum.fetch(-10..20, -4) == {:ok, 17}\n    # ascending order, first\n    assert Enum.fetch(-10..20, 0) == {:ok, -10}\n    assert Enum.fetch(-10..20, -31) == {:ok, -10}\n    # ascending order, last\n    assert Enum.fetch(-10..20, -1) == {:ok, 20}\n    assert Enum.fetch(-10..20, 30) == {:ok, 20}\n    # ascending order, out of bound\n    assert Enum.fetch(-10..20, 31) == :error\n    assert Enum.fetch(-10..20, -32) == :error\n\n    # descending order\n    assert Enum.fetch(20..-10//-1, 4) == {:ok, 16}\n    assert Enum.fetch(20..-10//-1, -4) == {:ok, -7}\n    # descending order, first\n    assert Enum.fetch(20..-10//-1, 0) == {:ok, 20}\n    assert Enum.fetch(20..-10//-1, -31) == {:ok, 20}\n    # descending order, last\n    assert Enum.fetch(20..-10//-1, -1) == {:ok, -10}\n    assert Enum.fetch(20..-10//-1, 30) == {:ok, -10}\n    # descending order, out of bound\n    assert Enum.fetch(20..-10//-1, 31) == :error\n    assert Enum.fetch(20..-10//-1, -32) == :error\n\n    # edge cases\n    assert Enum.fetch(42..42, 0) == {:ok, 42}\n    assert Enum.fetch(42..42, -1) == {:ok, 42}\n    assert Enum.fetch(42..42, 2) == :error\n    assert Enum.fetch(42..42, -2) == :error\n\n    assert Enum.fetch(42..42//2, 0) == {:ok, 42}\n    assert Enum.fetch(42..42//2, -1) == {:ok, 42}\n    assert Enum.fetch(42..42//2, 2) == :error\n    assert Enum.fetch(42..42//2, -2) == :error\n  end\n\n  test \"fetch!/2\" do\n    assert Enum.fetch!(2..6, 0) == 2\n    assert Enum.fetch!(2..6, 4) == 6\n    assert Enum.fetch!(2..6, -1) == 6\n    assert Enum.fetch!(2..6, -2) == 5\n    assert Enum.fetch!(-2..-6//-1, 0) == -2\n    assert Enum.fetch!(-2..-6//-1, 4) == -6\n\n    assert_raise Enum.OutOfBoundsError, fn ->\n      Enum.fetch!(2..6, 8)\n    end\n\n    assert_raise Enum.OutOfBoundsError, fn ->\n      Enum.fetch!(-2..-6//-1, 8)\n    end\n\n    assert_raise Enum.OutOfBoundsError, fn ->\n      Enum.fetch!(2..6, -8)\n    end\n  end\n\n  test \"filter/2\" do\n    assert Enum.filter(1..3, fn x -> rem(x, 2) == 0 end) == [2]\n    assert Enum.filter(1..6, fn x -> rem(x, 2) == 0 end) == [2, 4, 6]\n\n    assert Enum.filter(1..3, &match?(1, &1)) == [1]\n    assert Enum.filter(1..3, &match?(x when x < 3, &1)) == [1, 2]\n    assert Enum.filter(1..3, fn _ -> true end) == [1, 2, 3]\n  end\n\n  test \"find/3\" do\n    assert Enum.find(2..6, fn x -> rem(x, 2) == 0 end) == 2\n    assert Enum.find(2..6, fn x -> rem(x, 2) == 1 end) == 3\n    assert Enum.find(2..6, fn _ -> false end) == nil\n    assert Enum.find(2..6, 0, fn _ -> false end) == 0\n  end\n\n  test \"find_index/2\" do\n    assert Enum.find_index(2..6, fn x -> rem(x, 2) == 1 end) == 1\n  end\n\n  test \"find_value/3\" do\n    assert Enum.find_value(2..6, fn x -> rem(x, 2) == 1 end)\n  end\n\n  test \"flat_map/2\" do\n    assert Enum.flat_map(1..3, fn x -> [x, x] end) == [1, 1, 2, 2, 3, 3]\n  end\n\n  test \"flat_map_reduce/3\" do\n    assert Enum.flat_map_reduce(1..100, 0, fn i, acc ->\n             if acc < 3, do: {[i], acc + 1}, else: {:halt, acc}\n           end) == {[1, 2, 3], 3}\n  end\n\n  test \"group_by/3\" do\n    assert Enum.group_by(1..6, &rem(&1, 3)) == %{0 => [3, 6], 1 => [1, 4], 2 => [2, 5]}\n\n    assert Enum.group_by(1..6, &rem(&1, 3), &(&1 * 2)) ==\n             %{0 => [6, 12], 1 => [2, 8], 2 => [4, 10]}\n  end\n\n  test \"intersperse/2\" do\n    assert Enum.intersperse(1..0//-1, true) == [1, true, 0]\n    assert Enum.intersperse(1..3, false) == [1, false, 2, false, 3]\n  end\n\n  test \"into/2\" do\n    assert Enum.into(1..5, []) == [1, 2, 3, 4, 5]\n    assert Enum.into(1..5, MapSet.new()) == MapSet.new([1, 2, 3, 4, 5])\n  end\n\n  test \"into/3\" do\n    assert Enum.into(1..5, [], fn x -> x * 2 end) == [2, 4, 6, 8, 10]\n    assert Enum.into(1..3, \"numbers: \", &to_string/1) == \"numbers: 123\"\n    assert Enum.into(1..3, MapSet.new(), &(&1 * 2)) == MapSet.new([2, 4, 6])\n  end\n\n  test \"join/2\" do\n    assert Enum.join(1..0//-1, \" = \") == \"1 = 0\"\n    assert Enum.join(1..3, \" = \") == \"1 = 2 = 3\"\n    assert Enum.join(1..3) == \"123\"\n  end\n\n  test \"map/2\" do\n    assert Enum.map(1..3, fn x -> x * 2 end) == [2, 4, 6]\n    assert Enum.map(-1..-3//-1, fn x -> x * 2 end) == [-2, -4, -6]\n    assert Enum.map(1..10//2, fn x -> x * 2 end) == [2, 6, 10, 14, 18]\n    assert Enum.map(3..1//-2, fn x -> x * 2 end) == [6, 2]\n    assert Enum.map(0..1//-1, fn x -> x * 2 end) == []\n  end\n\n  test \"map_every/3\" do\n    assert Enum.map_every(1..10, 2, fn x -> x * 2 end) == [2, 2, 6, 4, 10, 6, 14, 8, 18, 10]\n\n    assert Enum.map_every(-1..-10//-1, 2, fn x -> x * 2 end) ==\n             [-2, -2, -6, -4, -10, -6, -14, -8, -18, -10]\n\n    assert Enum.map_every(1..2, 2, fn x -> x * 2 end) == [2, 2]\n    assert Enum.map_every(1..3, 0, fn x -> x * 2 end) == [1, 2, 3]\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.map_every(1..3, -1, fn x -> x * 2 end)\n    end\n  end\n\n  test \"map_intersperse/3\" do\n    assert Enum.map_intersperse(1..1, :a, &(&1 * 2)) == [2]\n    assert Enum.map_intersperse(1..3, :a, &(&1 * 2)) == [2, :a, 4, :a, 6]\n  end\n\n  test \"map_join/3\" do\n    assert Enum.map_join(1..0//-1, \" = \", &(&1 * 2)) == \"2 = 0\"\n    assert Enum.map_join(1..3, \" = \", &(&1 * 2)) == \"2 = 4 = 6\"\n    assert Enum.map_join(1..3, &(&1 * 2)) == \"246\"\n  end\n\n  test \"map_reduce/3\" do\n    assert Enum.map_reduce(1..0//-1, 1, fn x, acc -> {x * 2, x + acc} end) == {[2, 0], 2}\n    assert Enum.map_reduce(1..3, 1, fn x, acc -> {x * 2, x + acc} end) == {[2, 4, 6], 7}\n  end\n\n  test \"max/1\" do\n    assert Enum.max(1..1) == 1\n    assert Enum.max(1..3) == 3\n    assert Enum.max(3..1//-1) == 3\n\n    assert Enum.max(1..9//2) == 9\n    assert Enum.max(1..10//2) == 9\n    assert Enum.max(-1..-9//-2) == -1\n\n    assert_raise Enum.EmptyError, fn -> Enum.max(1..0//1) end\n  end\n\n  test \"max/2 with empty fallback\" do\n    assert Enum.max(.., fn -> 0 end) === 0\n    assert Enum.max(1..2, fn -> 0 end) === 2\n  end\n\n  test \"max_by/2\" do\n    assert Enum.max_by(1..1, fn x -> :math.pow(-2, x) end) == 1\n    assert Enum.max_by(1..3, fn x -> :math.pow(-2, x) end) == 2\n\n    assert Enum.max_by(1..8//3, fn x -> :math.pow(-2, x) end) == 4\n    assert_raise Enum.EmptyError, fn -> Enum.max_by(1..0//1, & &1) end\n  end\n\n  test \"member?/2\" do\n    assert Enum.member?(1..3, 2)\n    refute Enum.member?(1..3, 0)\n\n    assert Enum.member?(1..9//2, 1)\n    assert Enum.member?(1..9//2, 9)\n    refute Enum.member?(1..9//2, 10)\n    refute Enum.member?(1..10//2, 10)\n    assert Enum.member?(1..2//2, 1)\n    refute Enum.member?(1..2//2, 2)\n\n    assert Enum.member?(-1..-9//-2, -1)\n    assert Enum.member?(-1..-9//-2, -9)\n    refute Enum.member?(-1..-9//-2, -8)\n\n    refute Enum.member?(1..0//1, 1)\n    refute Enum.member?(0..1//-1, 1)\n  end\n\n  test \"min/1\" do\n    assert Enum.min(1..1) == 1\n    assert Enum.min(1..3) == 1\n\n    assert Enum.min(1..9//2) == 1\n    assert Enum.min(1..10//2) == 1\n    assert Enum.min(-1..-9//-2) == -9\n\n    assert_raise Enum.EmptyError, fn -> Enum.min(1..0//1) end\n  end\n\n  test \"min/2 with empty fallback\" do\n    assert Enum.min(.., fn -> 0 end) === 0\n    assert Enum.min(1..2, fn -> 0 end) === 1\n  end\n\n  test \"min_by/2\" do\n    assert Enum.min_by(1..1, fn x -> :math.pow(-2, x) end) == 1\n    assert Enum.min_by(1..3, fn x -> :math.pow(-2, x) end) == 3\n\n    assert Enum.min_by(1..8//3, fn x -> :math.pow(-2, x) end) == 7\n    assert_raise Enum.EmptyError, fn -> Enum.min_by(1..0//1, & &1) end\n  end\n\n  test \"min_max/1\" do\n    assert Enum.min_max(1..1) == {1, 1}\n    assert Enum.min_max(1..3) == {1, 3}\n    assert Enum.min_max(3..1//-1) == {1, 3}\n\n    assert Enum.min_max(1..9//2) == {1, 9}\n    assert Enum.min_max(1..10//2) == {1, 9}\n    assert Enum.min_max(-1..-9//-2) == {-9, -1}\n\n    assert_raise Enum.EmptyError, fn -> Enum.min_max(1..0//1) end\n  end\n\n  test \"min_max_by/2\" do\n    assert Enum.min_max_by(1..1, fn x -> x end) == {1, 1}\n    assert Enum.min_max_by(1..3, fn x -> x end) == {1, 3}\n\n    assert Enum.min_max_by(1..8//3, fn x -> :math.pow(-2, x) end) == {7, 4}\n    assert_raise Enum.EmptyError, fn -> Enum.min_max_by(1..0//1, & &1) end\n  end\n\n  test \"split_with/2\" do\n    assert Enum.split_with(1..3, fn x -> rem(x, 2) == 0 end) == {[2], [1, 3]}\n  end\n\n  test \"random/1\" do\n    # corner cases, independent of the seed\n    assert Enum.random(1..1) == 1\n\n    # set a fixed seed so the test can be deterministic\n    # please note the order of following assertions is important\n    seed1 = {1406, 407_414, 139_258}\n    seed2 = {1306, 421_106, 567_597}\n    :rand.seed(:exsss, seed1)\n    assert Enum.random(1..2) == 1\n    assert Enum.random(1..3) == 1\n    assert Enum.random(3..1//-1) == 2\n\n    :rand.seed(:exsss, seed2)\n    assert Enum.random(1..2) == 1\n    assert Enum.random(1..3) == 2\n\n    assert Enum.random(1..10//2) == 7\n    assert Enum.random(1..10//2) == 5\n\n    assert_raise Enum.EmptyError, fn -> Enum.random(..) end\n  end\n\n  test \"reduce/2\" do\n    assert Enum.reduce(1..3, fn x, acc -> x + acc end) == 6\n    assert Enum.reduce(1..10//2, fn x, acc -> x + acc end) == 25\n    assert_raise Enum.EmptyError, fn -> Enum.reduce(0..1//-1, &+/2) end\n  end\n\n  test \"reduce/3\" do\n    assert Enum.reduce(1..0//-1, 1, fn x, acc -> x + acc end) == 2\n    assert Enum.reduce(1..3, 1, fn x, acc -> x + acc end) == 7\n    assert Enum.reduce(1..10//2, 1, fn x, acc -> x + acc end) == 26\n    assert Enum.reduce(0..1//-1, 1, fn x, acc -> x + acc end) == 1\n  end\n\n  test \"reduce_while/3\" do\n    assert Enum.reduce_while(1..100, 0, fn i, acc ->\n             if i <= 3, do: {:cont, acc + i}, else: {:halt, acc}\n           end) == 6\n  end\n\n  test \"reject/2\" do\n    assert Enum.reject(1..3, fn x -> rem(x, 2) == 0 end) == [1, 3]\n    assert Enum.reject(1..6, fn x -> rem(x, 2) == 0 end) == [1, 3, 5]\n  end\n\n  test \"reverse/1\" do\n    assert Enum.reverse(0..0) == [0]\n    assert Enum.reverse(1..3) == [3, 2, 1]\n    assert Enum.reverse(-3..5) == [5, 4, 3, 2, 1, 0, -1, -2, -3]\n    assert Enum.reverse(5..5) == [5]\n\n    assert Enum.reverse(0..1//-1) == []\n    assert Enum.reverse(1..10//2) == [9, 7, 5, 3, 1]\n  end\n\n  test \"reverse/2\" do\n    assert Enum.reverse(1..3, 4..6) == [3, 2, 1, 4, 5, 6]\n    assert Enum.reverse([1, 2, 3], 4..6) == [3, 2, 1, 4, 5, 6]\n    assert Enum.reverse(1..3, [4, 5, 6]) == [3, 2, 1, 4, 5, 6]\n    assert Enum.reverse(-3..5, MapSet.new([-3, -2])) == [5, 4, 3, 2, 1, 0, -1, -2, -3, -3, -2]\n    assert Enum.reverse(5..5, [5]) == [5, 5]\n  end\n\n  test \"reverse_slice/3\" do\n    assert Enum.reverse_slice(1..6, 2, 0) == [1, 2, 3, 4, 5, 6]\n    assert Enum.reverse_slice(1..6, 2, 2) == [1, 2, 4, 3, 5, 6]\n    assert Enum.reverse_slice(1..6, 2, 4) == [1, 2, 6, 5, 4, 3]\n    assert Enum.reverse_slice(1..6, 2, 10_000_000) == [1, 2, 6, 5, 4, 3]\n    assert Enum.reverse_slice(1..6, 10_000_000, 4) == [1, 2, 3, 4, 5, 6]\n    assert Enum.reverse_slice(1..6, 50, 50) == [1, 2, 3, 4, 5, 6]\n  end\n\n  test \"scan/2\" do\n    assert Enum.scan(1..5, &(&1 + &2)) == [1, 3, 6, 10, 15]\n  end\n\n  test \"scan/3\" do\n    assert Enum.scan(1..5, 0, &(&1 + &2)) == [1, 3, 6, 10, 15]\n  end\n\n  test \"shuffle/1\" do\n    # set a fixed seed so the test can be deterministic\n    :rand.seed(:exsss, {1374, 347_975, 449_264})\n    assert Enum.shuffle(1..5) == [2, 5, 4, 3, 1]\n    assert Enum.shuffle(1..10//2) == [5, 1, 7, 9, 3]\n  end\n\n  test \"slice/2\" do\n    assert Enum.slice(1..5, 0..0) == [1]\n    assert Enum.slice(1..5, 0..1) == [1, 2]\n    assert Enum.slice(1..5, 0..2) == [1, 2, 3]\n    assert Enum.slice(1..5, 1..2) == [2, 3]\n    assert Enum.slice(1..5, 1..0//1) == []\n    assert Enum.slice(1..5, 2..5) == [3, 4, 5]\n    assert Enum.slice(1..5, 2..6) == [3, 4, 5]\n    assert Enum.slice(1..5, 4..4) == [5]\n    assert Enum.slice(1..5, 5..5) == []\n    assert Enum.slice(1..5, 6..5//1) == []\n    assert Enum.slice(1..5, 6..0//1) == []\n    assert Enum.slice(1..5, -3..0) == []\n    assert Enum.slice(1..5, -3..1) == []\n    assert Enum.slice(1..5, -6..0) == [1]\n    assert Enum.slice(1..5, -6..5) == [1, 2, 3, 4, 5]\n    assert Enum.slice(1..5, -6..-1) == [1, 2, 3, 4, 5]\n    assert Enum.slice(1..5, -5..-1) == [1, 2, 3, 4, 5]\n    assert Enum.slice(1..5, -5..-3) == [1, 2, 3]\n\n    assert Enum.slice(1..5, 0..10//2) == [1, 3, 5]\n    assert Enum.slice(1..5, 0..10//3) == [1, 4]\n    assert Enum.slice(1..5, 0..10//4) == [1, 5]\n    assert Enum.slice(1..5, 0..10//5) == [1]\n    assert Enum.slice(1..5, 0..10//6) == [1]\n\n    assert Enum.slice(1..5, 0..2//2) == [1, 3]\n    assert Enum.slice(1..5, 0..2//3) == [1]\n\n    assert Enum.slice(1..5, 0..-1//2) == [1, 3, 5]\n    assert Enum.slice(1..5, 0..-1//3) == [1, 4]\n    assert Enum.slice(1..5, 0..-1//4) == [1, 5]\n    assert Enum.slice(1..5, 0..-1//5) == [1]\n    assert Enum.slice(1..5, 0..-1//6) == [1]\n\n    assert Enum.slice(1..5, 1..-1//2) == [2, 4]\n    assert Enum.slice(1..5, 1..-1//3) == [2, 5]\n    assert Enum.slice(1..5, 1..-1//4) == [2]\n    assert Enum.slice(1..5, 1..-1//5) == [2]\n\n    assert Enum.slice(1..5, -4..-1//2) == [2, 4]\n    assert Enum.slice(1..5, -4..-1//3) == [2, 5]\n    assert Enum.slice(1..5, -4..-1//4) == [2]\n    assert Enum.slice(1..5, -4..-1//5) == [2]\n\n    assert Enum.slice(5..1//-1, 0..0) == [5]\n    assert Enum.slice(5..1//-1, 0..1) == [5, 4]\n    assert Enum.slice(5..1//-1, 0..2) == [5, 4, 3]\n    assert Enum.slice(5..1//-1, 1..2) == [4, 3]\n    assert Enum.slice(5..1//-1, 1..0//1) == []\n    assert Enum.slice(5..1//-1, 2..5) == [3, 2, 1]\n    assert Enum.slice(5..1//-1, 2..6) == [3, 2, 1]\n    assert Enum.slice(5..1//-1, 4..4) == [1]\n    assert Enum.slice(5..1//-1, 5..5) == []\n    assert Enum.slice(5..1//-1, 6..5//1) == []\n    assert Enum.slice(5..1//-1, 6..0//1) == []\n    assert Enum.slice(5..1//-1, -6..0) == [5]\n    assert Enum.slice(5..1//-1, -6..5) == [5, 4, 3, 2, 1]\n    assert Enum.slice(5..1//-1, -6..-1) == [5, 4, 3, 2, 1]\n    assert Enum.slice(5..1//-1, -5..-1) == [5, 4, 3, 2, 1]\n    assert Enum.slice(5..1//-1, -5..-3) == [5, 4, 3]\n\n    assert Enum.slice(1..10//2, 0..0) == [1]\n    assert Enum.slice(1..10//2, 0..1) == [1, 3]\n    assert Enum.slice(1..10//2, 0..2) == [1, 3, 5]\n    assert Enum.slice(1..10//2, 1..2) == [3, 5]\n    assert Enum.slice(1..10//2, 1..0//1) == []\n    assert Enum.slice(1..10//2, 2..5) == [5, 7, 9]\n    assert Enum.slice(1..10//2, 2..6) == [5, 7, 9]\n    assert Enum.slice(1..10//2, 4..4) == [9]\n    assert Enum.slice(1..10//2, 5..5) == []\n    assert Enum.slice(1..10//2, 6..5//1) == []\n    assert Enum.slice(1..10//2, 6..0//1) == []\n    assert Enum.slice(1..10//2, -3..0) == []\n    assert Enum.slice(1..10//2, -3..1) == []\n    assert Enum.slice(1..10//2, -6..0) == [1]\n    assert Enum.slice(1..10//2, -6..5) == [1, 3, 5, 7, 9]\n    assert Enum.slice(1..10//2, -6..-1) == [1, 3, 5, 7, 9]\n    assert Enum.slice(1..10//2, -5..-1) == [1, 3, 5, 7, 9]\n    assert Enum.slice(1..10//2, -5..-3) == [1, 3, 5]\n\n    # Range with step > 1 sliced by a range with step > 1\n    assert Enum.slice(1..10//2, 0..4//2) == [1, 5, 9]\n    assert Enum.slice(1..10//2, 0..4//3) == [1, 7]\n    assert Enum.slice(1..10//2, 1..4//2) == [3, 7]\n    assert Enum.slice(0..20//3, 0..6//2) == [0, 6, 12, 18]\n\n    # Range with negative step sliced by a range with step > 1\n    assert Enum.slice(10..1//-2, 0..4//2) == [10, 6, 2]\n    assert Enum.slice(20..0//-3, 0..6//2) == [20, 14, 8, 2]\n\n    assert_raise ArgumentError,\n                 \"Enum.slice/2 does not accept ranges with negative steps, got: 1..3//-2\",\n                 fn -> Enum.slice(1..5, 1..3//-2) end\n  end\n\n  test \"slice/3\" do\n    assert Enum.slice(1..5, 0, 0) == []\n    assert Enum.slice(1..5, 0, 1) == [1]\n    assert Enum.slice(1..5, 0, 2) == [1, 2]\n    assert Enum.slice(1..5, 1, 2) == [2, 3]\n    assert Enum.slice(1..5, 1, 0) == []\n    assert Enum.slice(1..5, 2, 3) == [3, 4, 5]\n    assert Enum.slice(1..5, 2, 6) == [3, 4, 5]\n    assert Enum.slice(1..5, 5, 5) == []\n    assert Enum.slice(1..5, 6, 5) == []\n    assert Enum.slice(1..5, 6, 0) == []\n    assert Enum.slice(1..5, -6, 0) == []\n    assert Enum.slice(1..5, -6, 5) == [1, 2, 3, 4, 5]\n    assert Enum.slice(1..5, -2, 5) == [4, 5]\n    assert Enum.slice(1..5, -3, 1) == [3]\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.slice(1..5, 0, -1)\n    end\n\n    assert Enum.slice(5..1//-1, 0, 0) == []\n    assert Enum.slice(5..1//-1, 0, 1) == [5]\n    assert Enum.slice(5..1//-1, 0, 2) == [5, 4]\n    assert Enum.slice(5..1//-1, 1, 2) == [4, 3]\n    assert Enum.slice(5..1//-1, 1, 0) == []\n    assert Enum.slice(5..1//-1, 2, 3) == [3, 2, 1]\n    assert Enum.slice(5..1//-1, 2, 6) == [3, 2, 1]\n    assert Enum.slice(5..1//-1, 4, 4) == [1]\n    assert Enum.slice(5..1//-1, 5, 5) == []\n    assert Enum.slice(5..1//-1, 6, 5) == []\n    assert Enum.slice(5..1//-1, 6, 0) == []\n    assert Enum.slice(5..1//-1, -6, 0) == []\n    assert Enum.slice(5..1//-1, -6, 5) == [5, 4, 3, 2, 1]\n\n    assert Enum.slice(1..10//2, 0, 0) == []\n    assert Enum.slice(1..10//2, 0, 1) == [1]\n    assert Enum.slice(1..10//2, 0, 2) == [1, 3]\n    assert Enum.slice(1..10//2, 1, 2) == [3, 5]\n    assert Enum.slice(1..10//2, 1, 0) == []\n    assert Enum.slice(1..10//2, 2, 3) == [5, 7, 9]\n    assert Enum.slice(1..10//2, 2, 6) == [5, 7, 9]\n    assert Enum.slice(1..10//2, 5, 5) == []\n    assert Enum.slice(1..10//2, 6, 5) == []\n    assert Enum.slice(1..10//2, 6, 0) == []\n    assert Enum.slice(1..10//2, -6, 0) == []\n    assert Enum.slice(1..10//2, -6, 5) == [1, 3, 5, 7, 9]\n    assert Enum.slice(1..10//2, -2, 5) == [7, 9]\n    assert Enum.slice(1..10//2, -3, 1) == [5]\n  end\n\n  test \"sort/1\" do\n    assert Enum.sort(3..1//-1) == [1, 2, 3]\n    assert Enum.sort(2..1//-1) == [1, 2]\n    assert Enum.sort(1..1) == [1]\n  end\n\n  test \"sort/2\" do\n    assert Enum.sort(3..1//-1, &(&1 > &2)) == [3, 2, 1]\n    assert Enum.sort(2..1//-1, &(&1 > &2)) == [2, 1]\n    assert Enum.sort(1..1, &(&1 > &2)) == [1]\n\n    assert Enum.sort(3..1//-1, :asc) == [1, 2, 3]\n    assert Enum.sort(3..1//-1, :desc) == [3, 2, 1]\n  end\n\n  test \"sort_by/2\" do\n    assert Enum.sort_by(3..1//-1, & &1) == [1, 2, 3]\n    assert Enum.sort_by(3..1//-1, & &1, :asc) == [1, 2, 3]\n    assert Enum.sort_by(3..1//-1, & &1, :desc) == [3, 2, 1]\n  end\n\n  test \"split/2\" do\n    assert Enum.split(1..3, 0) == {[], [1, 2, 3]}\n    assert Enum.split(1..3, 1) == {[1], [2, 3]}\n    assert Enum.split(1..3, 2) == {[1, 2], [3]}\n    assert Enum.split(1..3, 3) == {[1, 2, 3], []}\n    assert Enum.split(1..3, 4) == {[1, 2, 3], []}\n    assert Enum.split(1..3, -1) == {[1, 2], [3]}\n    assert Enum.split(1..3, -2) == {[1], [2, 3]}\n    assert Enum.split(1..3, -3) == {[], [1, 2, 3]}\n    assert Enum.split(1..3, -10) == {[], [1, 2, 3]}\n    assert Enum.split(1..0//-1, 3) == {[1, 0], []}\n  end\n\n  test \"split_while/2\" do\n    assert Enum.split_while(1..3, fn _ -> false end) == {[], [1, 2, 3]}\n    assert Enum.split_while(1..3, fn _ -> nil end) == {[], [1, 2, 3]}\n    assert Enum.split_while(1..3, fn _ -> true end) == {[1, 2, 3], []}\n    assert Enum.split_while(1..3, fn x -> x > 2 end) == {[], [1, 2, 3]}\n    assert Enum.split_while(1..3, fn x -> x > 3 end) == {[], [1, 2, 3]}\n    assert Enum.split_while(1..3, fn x -> x < 3 end) == {[1, 2], [3]}\n    assert Enum.split_while(1..3, fn x -> x end) == {[1, 2, 3], []}\n    assert Enum.split_while(1..0//-1, fn _ -> true end) == {[1, 0], []}\n  end\n\n  test \"sum/1\" do\n    assert Enum.sum(0..0) == 0\n    assert Enum.sum(1..1) == 1\n    assert Enum.sum(1..3) == 6\n    assert Enum.sum(0..100) == 5050\n    assert Enum.sum(10..100) == 5005\n    assert Enum.sum(100..10//-1) == 5005\n    assert Enum.sum(-10..-20//-1) == -165\n    assert Enum.sum(-10..2) == -52\n\n    assert Enum.sum(0..1//-1) == 0\n    assert Enum.sum(1..9//2) == 25\n    assert Enum.sum(1..10//2) == 25\n    assert Enum.sum(9..1//-2) == 25\n  end\n\n  test \"take/2\" do\n    assert Enum.take(1..3, 0) == []\n    assert Enum.take(1..3, 1) == [1]\n    assert Enum.take(1..3, 2) == [1, 2]\n    assert Enum.take(1..3, 3) == [1, 2, 3]\n    assert Enum.take(1..3, 4) == [1, 2, 3]\n    assert Enum.take(1..3, -1) == [3]\n    assert Enum.take(1..3, -2) == [2, 3]\n    assert Enum.take(1..3, -4) == [1, 2, 3]\n    assert Enum.take(1..0//-1, 3) == [1, 0]\n    assert Enum.take(1..0//1, -3) == []\n  end\n\n  test \"take_every/2\" do\n    assert Enum.take_every(1..10, 2) == [1, 3, 5, 7, 9]\n    assert Enum.take_every(1..2, 2) == [1]\n    assert Enum.take_every(1..3, 0) == []\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.take_every(1..3, -1)\n    end\n  end\n\n  test \"take_random/2\" do\n    # corner cases, independent of the seed\n    assert_raise FunctionClauseError, fn -> Enum.take_random(1..2, -1) end\n    assert Enum.take_random(1..1, 0) == []\n    assert Enum.take_random(1..1, 1) == [1]\n    assert Enum.take_random(1..1, 2) == [1]\n    assert Enum.take_random(1..2, 0) == []\n\n    # set a fixed seed so the test can be deterministic\n    # please note the order of following assertions is important\n    seed1 = {1406, 407_414, 139_258}\n    seed2 = {1406, 421_106, 567_597}\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(1..3, 1) == [2]\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(1..3, 2) == [3, 1]\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(1..3, 3) == [3, 1, 2]\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(1..3, 4) == [3, 1, 2]\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(1..3, 5) == [3, 1, 2]\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(3..1//-1, 1) == [2]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(1..3, 1) == [1]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(1..3, 2) == [3, 2]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(1..3, 3) == [1, 3, 2]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(1..3, 4) == [1, 3, 2]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(1..3, 5) == [1, 3, 2]\n  end\n\n  test \"take_while/2\" do\n    assert Enum.take_while(1..3, fn x -> x > 3 end) == []\n    assert Enum.take_while(1..3, fn x -> x <= 1 end) == [1]\n    assert Enum.take_while(1..3, fn x -> x <= 3 end) == [1, 2, 3]\n    assert Enum.take_while(1..3, fn x -> x end) == [1, 2, 3]\n    assert Enum.take_while(1..3, fn _ -> nil end) == []\n  end\n\n  test \"to_list/1\" do\n    assert Enum.to_list(1..3) == [1, 2, 3]\n    assert Enum.to_list(1..3//2) == [1, 3]\n    assert Enum.to_list(3..1//-2) == [3, 1]\n    assert Enum.to_list(0..1//-1) == []\n  end\n\n  test \"uniq/1\" do\n    assert Enum.uniq(1..3) == [1, 2, 3]\n  end\n\n  test \"uniq_by/2\" do\n    assert Enum.uniq_by(1..3, fn x -> x end) == [1, 2, 3]\n  end\n\n  test \"unzip/1\" do\n    assert_raise FunctionClauseError, fn -> Enum.unzip(1..3) end\n  end\n\n  test \"with_index/2\" do\n    assert Enum.with_index(1..3) == [{1, 0}, {2, 1}, {3, 2}]\n    assert Enum.with_index(1..3, 3) == [{1, 3}, {2, 4}, {3, 5}]\n  end\n\n  test \"zip/2\" do\n    assert Enum.zip([:a, :b], 1..2) == [{:a, 1}, {:b, 2}]\n    assert Enum.zip([:a, :b], 1..4) == [{:a, 1}, {:b, 2}]\n    assert Enum.zip([:a, :b, :c, :d], 1..2) == [{:a, 1}, {:b, 2}]\n\n    assert Enum.zip(1..2, [:a, :b]) == [{1, :a}, {2, :b}]\n    assert Enum.zip(1..4, [:a, :b]) == [{1, :a}, {2, :b}]\n    assert Enum.zip(1..2, [:a, :b, :c, :d]) == [{1, :a}, {2, :b}]\n\n    assert Enum.zip(1..2, 1..2) == [{1, 1}, {2, 2}]\n    assert Enum.zip(1..4, 1..2) == [{1, 1}, {2, 2}]\n    assert Enum.zip(1..2, 1..4) == [{1, 1}, {2, 2}]\n\n    assert Enum.zip(1..10//2, 1..10//3) == [{1, 1}, {3, 4}, {5, 7}, {7, 10}]\n    assert Enum.zip(0..1//-1, 1..10//3) == []\n  end\nend\n\ndefmodule EnumTest.Map do\n  # Maps use different protocols path than lists and ranges in the cases below.\n  use ExUnit.Case, async: true\n\n  test \"random/1\" do\n    map = %{a: 1, b: 2, c: 3}\n    [x1, x2, x3] = Map.to_list(map)\n    seed1 = {1406, 407_414, 139_258}\n    seed2 = {1406, 421_106, 567_597}\n    :rand.seed(:exsss, seed1)\n    assert Enum.random(map) == x3\n    assert Enum.random(map) == x1\n    assert Enum.random(map) == x2\n\n    :rand.seed(:exsss, seed2)\n    assert Enum.random(map) == x3\n    assert Enum.random(map) == x2\n  end\n\n  test \"take_random/2\" do\n    # corner cases, independent of the seed\n    assert_raise FunctionClauseError, fn -> Enum.take_random(1..2, -1) end\n    assert Enum.take_random(%{a: 1}, 0) == []\n    assert Enum.take_random(%{a: 1}, 2) == [a: 1]\n    assert Enum.take_random(%{a: 1, b: 2}, 0) == []\n\n    # set a fixed seed so the test can be deterministic\n    # please note the order of following assertions is important\n    map = %{a: 1, b: 2, c: 3}\n    [x1, x2, x3] = Map.to_list(map)\n    seed1 = {1406, 407_414, 139_258}\n    seed2 = {1406, 421_106, 567_597}\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(map, 1) == [x2]\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(map, 2) == [x3, x1]\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(map, 3) == [x3, x1, x2]\n    :rand.seed(:exsss, seed1)\n    assert Enum.take_random(map, 4) == [x3, x1, x2]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(map, 1) == [x1]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(map, 2) == [x3, x2]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(map, 3) == [x1, x3, x2]\n    :rand.seed(:exsss, seed2)\n    assert Enum.take_random(map, 4) == [x1, x3, x2]\n  end\n\n  test \"reverse/1\" do\n    assert Enum.reverse(%{}) == []\n    assert Enum.reverse(MapSet.new()) == []\n\n    map = %{a: 1, b: 2, c: 3}\n    assert Enum.reverse(map) == Map.to_list(map) |> Enum.reverse()\n  end\n\n  test \"reverse/2\" do\n    assert Enum.reverse([a: 1, b: 2, c: 3, a: 1], %{x: 1}) == [a: 1, c: 3, b: 2, a: 1, x: 1]\n\n    assert Enum.reverse([], %{a: 1}) == [a: 1]\n    assert Enum.reverse([], %{}) == []\n    assert Enum.reverse(%{a: 1}, []) == [a: 1]\n    assert Enum.reverse(MapSet.new(), %{}) == []\n  end\n\n  test \"fetch/2\" do\n    map = %{a: 1, b: 2, c: 3, d: 4, e: 5}\n    [x1, _x2, _x3, x4, x5] = Map.to_list(map)\n    assert Enum.fetch(map, 0) == {:ok, x1}\n    assert Enum.fetch(map, -2) == {:ok, x4}\n    assert Enum.fetch(map, -6) == :error\n    assert Enum.fetch(map, 5) == :error\n    assert Enum.fetch(%{}, 0) == :error\n\n    assert Stream.take(map, 3) |> Enum.fetch(3) == :error\n    assert Stream.take(map, 5) |> Enum.fetch(4) == {:ok, x5}\n  end\n\n  test \"map_intersperse/3\" do\n    assert Enum.map_intersperse(%{}, :a, & &1) == []\n    assert Enum.map_intersperse(%{foo: :bar}, :a, & &1) == [{:foo, :bar}]\n\n    map = %{foo: :bar, baz: :bat}\n    [x1, x2] = Map.to_list(map)\n\n    assert Enum.map_intersperse(map, :a, & &1) == [x1, :a, x2]\n  end\n\n  test \"slice/2\" do\n    map = %{a: 1, b: 2, c: 3, d: 4, e: 5}\n    [x1, x2, x3 | _] = Map.to_list(map)\n    assert Enum.slice(map, 0..0) == [x1]\n    assert Enum.slice(map, 0..1) == [x1, x2]\n    assert Enum.slice(map, 0..2) == [x1, x2, x3]\n  end\n\n  test \"slice/3\" do\n    map = %{a: 1, b: 2, c: 3, d: 4, e: 5}\n    [x1, x2, x3, x4, x5] = Map.to_list(map)\n    assert Enum.slice(map, 1, 2) == [x2, x3]\n    assert Enum.slice(map, 1, 0) == []\n    assert Enum.slice(map, 2, 5) == [x3, x4, x5]\n    assert Enum.slice(map, 2, 6) == [x3, x4, x5]\n    assert Enum.slice(map, 5, 5) == []\n    assert Enum.slice(map, 6, 5) == []\n    assert Enum.slice(map, 6, 0) == []\n    assert Enum.slice(map, -6, 0) == []\n    assert Enum.slice(map, -6, 5) == [x1, x2, x3, x4, x5]\n    assert Enum.slice(map, -2, 5) == [x4, x5]\n    assert Enum.slice(map, -3, 1) == [x3]\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.slice(map, 0, -1)\n    end\n\n    assert Enum.slice(map, 0, 0) == []\n    assert Enum.slice(map, 0, 1) == [x1]\n    assert Enum.slice(map, 0, 2) == [x1, x2]\n    assert Enum.slice(map, 1, 2) == [x2, x3]\n    assert Enum.slice(map, 1, 0) == []\n    assert Enum.slice(map, 2, 5) == [x3, x4, x5]\n    assert Enum.slice(map, 2, 6) == [x3, x4, x5]\n    assert Enum.slice(map, 5, 5) == []\n    assert Enum.slice(map, 6, 5) == []\n    assert Enum.slice(map, 6, 0) == []\n    assert Enum.slice(map, -6, 0) == []\n    assert Enum.slice(map, -6, 5) == [x1, x2, x3, x4, x5]\n    assert Enum.slice(map, -2, 5) == [x4, x5]\n    assert Enum.slice(map, -3, 1) == [x3]\n\n    assert_raise FunctionClauseError, fn ->\n      Enum.slice(map, 0, -1)\n    end\n  end\n\n  test \"reduce/3\" do\n    assert Enum.reduce(%{}, 1, fn x, acc -> x + acc end) == 1\n    assert Enum.reduce(%{a: 1, b: 2}, 1, fn {_, x}, acc -> x + acc end) == 4\n  end\nend\n\ndefmodule EnumTest.SideEffects do\n  use ExUnit.Case, async: true\n\n  import ExUnit.CaptureIO\n\n  test \"take/2 with side effects\" do\n    stream =\n      Stream.unfold(1, fn x ->\n        IO.puts(x)\n        {x, x + 1}\n      end)\n\n    assert capture_io(fn ->\n             Enum.take(stream, 1)\n           end) == \"1\\n\"\n  end\n\n  @tag :tmp_dir\n  test \"take/2 does not consume next without a need\", config do\n    path = Path.join(config.tmp_dir, \"oneliner.txt\")\n    File.mkdir(Path.dirname(path))\n\n    try do\n      File.write!(path, \"ONE\")\n\n      File.open!(path, [], fn file ->\n        iterator = IO.stream(file, :line)\n        assert Enum.take(iterator, 1) == [\"ONE\"]\n        assert Enum.take(iterator, 5) == []\n      end)\n    after\n      File.rm(path)\n    end\n  end\n\n  test \"take/2 with no elements works as no-op\" do\n    iterator = File.stream!(PathHelpers.fixture_path(\"unknown.txt\"))\n\n    assert Enum.take(iterator, 0) == []\n    assert Enum.take(iterator, 0) == []\n    assert Enum.take(iterator, 0) == []\n    assert Enum.take(iterator, 0) == []\n  end\nend\n\ndefmodule EnumTest.Function do\n  use ExUnit.Case, async: true\n\n  test \"raises Protocol.UndefinedError for funs of wrong arity\" do\n    assert_raise Protocol.UndefinedError, fn ->\n      Enum.to_list(fn -> nil end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/exception_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule ExceptionTest do\n  use ExUnit.Case, async: true\n\n  defp capture_err(fun) do\n    ExUnit.CaptureIO.capture_io(:stderr, fun)\n  end\n\n  doctest Exception\n\n  doctest RuntimeError\n  doctest SystemLimitError\n  doctest MismatchedDelimiterError\n  doctest SyntaxError\n  doctest TokenMissingError\n  doctest BadBooleanError\n  doctest UndefinedFunctionError\n  doctest FunctionClauseError\n  doctest Protocol.UndefinedError\n  doctest UnicodeConversionError\n  doctest Enum.OutOfBoundsError\n  doctest Enum.EmptyError\n  doctest File.Error\n  doctest File.CopyError\n  doctest File.RenameError\n  doctest File.LinkError\n  doctest ErlangError\n\n  test \"message/1\" do\n    defmodule BadException do\n      def message(exception) do\n        if exception.raise do\n          raise \"oops\"\n        end\n      end\n    end\n\n    assert \"got RuntimeError with message \\\"oops\\\" while retrieving Exception.message/1 for %{\" <>\n             inspected =\n             Exception.message(%{__struct__: BadException, __exception__: true, raise: true})\n\n    assert inspected =~ \"raise: true\"\n    assert inspected =~ \"__exception__: true\"\n    assert inspected =~ \"__struct__: ExceptionTest.BadException\"\n\n    assert \"got nil while retrieving Exception.message/1 for %{\" <> inspected =\n             Exception.message(%{__struct__: BadException, __exception__: true, raise: false})\n\n    assert inspected =~ \"raise: false\"\n    assert inspected =~ \"__exception__: true\"\n    assert inspected =~ \"__struct__: ExceptionTest.BadException\"\n  end\n\n  test \"normalize/2\" do\n    assert Exception.normalize(:throw, :badarg, []) == :badarg\n    assert Exception.normalize(:exit, :badarg, []) == :badarg\n    assert Exception.normalize({:EXIT, self()}, :badarg, []) == :badarg\n    assert Exception.normalize(:error, :badarg, []).__struct__ == ArgumentError\n    assert Exception.normalize(:error, %ArgumentError{}, []).__struct__ == ArgumentError\n\n    assert %ErlangError{original: :no_translation, reason: \": foo\"} =\n             Exception.normalize(:error, :no_translation, [\n               {:io, :put_chars, [self(), <<222>>],\n                [error_info: %{module: __MODULE__, function: :dummy_error_extras}]}\n             ])\n\n    assert %ErlangError{original: {:failed_load_cacerts, :enoent}, reason: \": this is chardata\"} =\n             Exception.normalize(:error, {:failed_load_cacerts, :enoent}, [\n               {:pubkey_os_cacerts, :get, 0,\n                [error_info: %{module: __MODULE__, function: :dummy_error_chardata}]}\n             ])\n  end\n\n  test \"format/2 without stacktrace\" do\n    stacktrace =\n      try do\n        throw(:stack)\n      catch\n        :stack -> __STACKTRACE__\n      end\n\n    assert Exception.format(:error, :badarg, stacktrace) ==\n             \"** (ArgumentError) argument error\\n\" <> Exception.format_stacktrace(stacktrace)\n  end\n\n  test \"format/2 with empty stacktrace\" do\n    assert Exception.format(:error, :badarg, []) == \"** (ArgumentError) argument error\"\n  end\n\n  test \"format/2 with EXIT (has no stacktrace)\" do\n    assert Exception.format({:EXIT, self()}, :badarg, []) ==\n             \"** (EXIT from #{inspect(self())}) :badarg\"\n  end\n\n  test \"format_banner/2\" do\n    assert Exception.format_banner(:error, :badarg) == \"** (ArgumentError) argument error\"\n    assert Exception.format_banner(:throw, :badarg) == \"** (throw) :badarg\"\n    assert Exception.format_banner(:exit, :badarg) == \"** (exit) :badarg\"\n\n    assert Exception.format_banner({:EXIT, self()}, :badarg) ==\n             \"** (EXIT from #{inspect(self())}) :badarg\"\n  end\n\n  test \"format_stacktrace/1 from file\" do\n    try do\n      Code.eval_string(\"def foo do end\", [], file: \"my_file\")\n    rescue\n      ArgumentError ->\n        assert Exception.format_stacktrace(__STACKTRACE__) =~ \"my_file:1: (file)\"\n    else\n      _ -> flunk(\"expected failure\")\n    end\n  end\n\n  test \"format_stacktrace/1 from module\" do\n    try do\n      Code.eval_string(\n        \"defmodule FmtStack do raise ArgumentError, ~s(oops) end\",\n        [],\n        file: \"my_file\"\n      )\n    rescue\n      ArgumentError ->\n        assert Exception.format_stacktrace(__STACKTRACE__) =~ \"my_file:1: (module)\"\n    else\n      _ -> flunk(\"expected failure\")\n    end\n  end\n\n  test \"format_stacktrace_entry/1 with no file or line\" do\n    assert Exception.format_stacktrace_entry({Foo, :bar, [1, 2, 3], []}) == \"Foo.bar(1, 2, 3)\"\n    assert Exception.format_stacktrace_entry({Foo, :bar, [], []}) == \"Foo.bar()\"\n    assert Exception.format_stacktrace_entry({Foo, :bar, 1, []}) == \"Foo.bar/1\"\n  end\n\n  test \"format_stacktrace_entry/1 with file and line\" do\n    assert Exception.format_stacktrace_entry({Foo, :bar, [], [file: ~c\"file.ex\", line: 10]}) ==\n             \"file.ex:10: Foo.bar()\"\n\n    assert Exception.format_stacktrace_entry(\n             {Foo, :bar, [1, 2, 3], [file: ~c\"file.ex\", line: 10]}\n           ) ==\n             \"file.ex:10: Foo.bar(1, 2, 3)\"\n\n    assert Exception.format_stacktrace_entry({Foo, :bar, 1, [file: ~c\"file.ex\", line: 10]}) ==\n             \"file.ex:10: Foo.bar/1\"\n  end\n\n  test \"format_stacktrace_entry/1 with file no line\" do\n    assert Exception.format_stacktrace_entry({Foo, :bar, [], [file: ~c\"file.ex\"]}) ==\n             \"file.ex: Foo.bar()\"\n\n    assert Exception.format_stacktrace_entry({Foo, :bar, [], [file: ~c\"file.ex\", line: 0]}) ==\n             \"file.ex: Foo.bar()\"\n\n    assert Exception.format_stacktrace_entry({Foo, :bar, [1, 2, 3], [file: ~c\"file.ex\"]}) ==\n             \"file.ex: Foo.bar(1, 2, 3)\"\n\n    assert Exception.format_stacktrace_entry({Foo, :bar, 1, [file: ~c\"file.ex\"]}) ==\n             \"file.ex: Foo.bar/1\"\n  end\n\n  test \"format_stacktrace_entry/1 with application\" do\n    assert Exception.format_stacktrace_entry({Exception, :bar, [], [file: ~c\"file.ex\"]}) ==\n             \"(elixir #{System.version()}) file.ex: Exception.bar()\"\n\n    assert Exception.format_stacktrace_entry({Exception, :bar, [], [file: ~c\"file.ex\", line: 10]}) ==\n             \"(elixir #{System.version()}) file.ex:10: Exception.bar()\"\n  end\n\n  test \"format_stacktrace_entry/1 with fun\" do\n    assert Exception.format_stacktrace_entry({fn x -> x end, [1], []}) =~ ~r/#Function<.+>\\(1\\)/\n\n    assert Exception.format_stacktrace_entry({fn x, y -> {x, y} end, 2, []}) =~\n             ~r\"#Function<.+>/2\"\n  end\n\n  test \"format_mfa/3\" do\n    # Let's create this atom so that String.to_existing_atom/1 inside\n    # format_mfa/3 doesn't raise.\n    _ = :\"some function\"\n\n    assert Exception.format_mfa(Foo, nil, 1) == \"Foo.nil/1\"\n    assert Exception.format_mfa(Foo, :bar, 1) == \"Foo.bar/1\"\n    assert Exception.format_mfa(Foo, :bar, []) == \"Foo.bar()\"\n    assert Exception.format_mfa(nil, :bar, []) == \"nil.bar()\"\n    assert Exception.format_mfa(:foo, :bar, [1, 2]) == \":foo.bar(1, 2)\"\n    assert Exception.format_mfa(Foo, :b@r, 1) == \"Foo.\\\"b@r\\\"/1\"\n    assert Exception.format_mfa(Foo, :\"bar baz\", 1) == \"Foo.\\\"bar baz\\\"/1\"\n    assert Exception.format_mfa(Foo, :\"-func/2-fun-0-\", 4) == \"anonymous fn/4 in Foo.func/2\"\n\n    assert Exception.format_mfa(Foo, :\"-some function/2-fun-0-\", 4) ==\n             \"anonymous fn/4 in Foo.\\\"some function\\\"/2\"\n\n    assert Exception.format_mfa(Foo, :\"42\", 1) == \"Foo.\\\"42\\\"/1\"\n    assert Exception.format_mfa(Foo, :Bar, [1, 2]) == \"Foo.\\\"Bar\\\"(1, 2)\"\n    assert Exception.format_mfa(Foo, :%{}, [1, 2]) == \"Foo.\\\"%{}\\\"(1, 2)\"\n    assert Exception.format_mfa(Foo, :..., 1) == \"Foo.\\\"...\\\"/1\"\n  end\n\n  test \"format_mfa/3 with Unicode\" do\n    assert Exception.format_mfa(Foo, :olá, [1, 2]) == \"Foo.olá(1, 2)\"\n    assert Exception.format_mfa(Foo, :Olá, [1, 2]) == \"Foo.\\\"Olá\\\"(1, 2)\"\n    assert Exception.format_mfa(Foo, :Ólá, [1, 2]) == \"Foo.\\\"Ólá\\\"(1, 2)\"\n    assert Exception.format_mfa(Foo, :こんにちは世界, [1, 2]) == \"Foo.こんにちは世界(1, 2)\"\n\n    nfd = :unicode.characters_to_nfd_binary(\"olá\")\n    assert Exception.format_mfa(Foo, String.to_atom(nfd), [1, 2]) == \"Foo.\\\"#{nfd}\\\"(1, 2)\"\n  end\n\n  test \"format_fa/2\" do\n    assert Exception.format_fa(fn -> nil end, 1) =~\n             ~r\"#Function<\\d+\\.\\d+/0 in ExceptionTest\\.\\\"test format_fa/2\\\"/1>/1\"\n  end\n\n  describe \"format_exit/1\" do\n    test \"with atom/tuples\" do\n      assert Exception.format_exit(:bye) == \":bye\"\n      assert Exception.format_exit(:noconnection) == \"no connection\"\n      assert Exception.format_exit({:nodedown, :node@host}) == \"no connection to node@host\"\n      assert Exception.format_exit(:timeout) == \"time out\"\n      assert Exception.format_exit(:noproc) |> String.starts_with?(\"no process:\")\n      assert Exception.format_exit(:killed) == \"killed\"\n      assert Exception.format_exit(:normal) == \"normal\"\n      assert Exception.format_exit(:shutdown) == \"shutdown\"\n      assert Exception.format_exit(:calling_self) == \"process attempted to call itself\"\n      assert Exception.format_exit({:shutdown, :bye}) == \"shutdown: :bye\"\n\n      assert Exception.format_exit({:badarg, [{:not_a_real_module, :function, 0, []}]}) ==\n               \"an exception was raised:\\n    ** (ArgumentError) argument error\\n        :not_a_real_module.function/0\"\n\n      assert Exception.format_exit({:bad_call, :request}) == \"bad call: :request\"\n      assert Exception.format_exit({:bad_cast, :request}) == \"bad cast: :request\"\n\n      assert Exception.format_exit({:start_spec, :unexpected}) ==\n               \"bad child specification, got: :unexpected\"\n\n      assert Exception.format_exit({:supervisor_data, :unexpected}) ==\n               \"bad supervisor configuration, got: :unexpected\"\n    end\n\n    defmodule Sup do\n      def start_link(fun), do: :supervisor.start_link(__MODULE__, fun)\n\n      def init(fun), do: fun.()\n    end\n\n    test \"with supervisor errors\" do\n      Process.flag(:trap_exit, true)\n\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> :foo end)\n\n      assert Exception.format_exit(reason) ==\n               \"#{inspect(__MODULE__.Sup)}.init/1 returned a bad value: :foo\"\n\n      return = {:ok, {:foo, []}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n      assert Exception.format_exit(reason) == \"bad supervisor configuration, invalid type: :foo\"\n\n      return = {:ok, {{:foo, 1, 1}, []}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n\n      assert Exception.format_exit(reason) ==\n               \"bad supervisor configuration, invalid strategy: :foo\"\n\n      return = {:ok, {{:one_for_one, :foo, 1}, []}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n\n      assert Exception.format_exit(reason) ==\n               \"bad supervisor configuration, invalid max_restarts (intensity): :foo\"\n\n      return = {:ok, {{:one_for_one, 1, :foo}, []}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n\n      assert Exception.format_exit(reason) ==\n               \"bad supervisor configuration, invalid max_seconds (period): :foo\"\n\n      return = {:ok, {{:simple_one_for_one, 1, 1}, :foo}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n      assert Exception.format_exit(reason) == \"bad child specification, invalid children: :foo\"\n\n      return = {:ok, {{:one_for_one, 1, 1}, [:foo]}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n\n      assert Exception.format_exit(reason) ==\n               \"bad child specification, invalid child specification: :foo\"\n\n      return = {:ok, {{:one_for_one, 1, 1}, [{:child, :foo, :temporary, 1, :worker, []}]}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n      assert Exception.format_exit(reason) == \"bad child specification, invalid mfa: :foo\"\n\n      return = {:ok, {{:one_for_one, 1, 1}, [{:child, {:m, :f, []}, :foo, 1, :worker, []}]}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n\n      assert Exception.format_exit(reason) =~\n               \"bad child specification, invalid restart type: :foo\"\n\n      return = {\n        :ok,\n        {{:one_for_one, 1, 1}, [{:child, {:m, :f, []}, :temporary, :foo, :worker, []}]}\n      }\n\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n      assert Exception.format_exit(reason) =~ \"bad child specification, invalid shutdown: :foo\"\n\n      return = {:ok, {{:one_for_one, 1, 1}, [{:child, {:m, :f, []}, :temporary, 1, :foo, []}]}}\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n      assert Exception.format_exit(reason) =~ \"bad child specification, invalid child type: :foo\"\n\n      return =\n        {:ok, {{:one_for_one, 1, 1}, [{:child, {:m, :f, []}, :temporary, 1, :worker, :foo}]}}\n\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n      assert Exception.format_exit(reason) =~ \"bad child specification, invalid modules: :foo\"\n\n      return = {\n        :ok,\n        {{:one_for_one, 1, 1}, [{:child, {:m, :f, []}, :temporary, 1, :worker, [{:foo}]}]}\n      }\n\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n      assert Exception.format_exit(reason) =~ \"bad child specification, invalid module: {:foo}\"\n\n      return = {\n        :ok,\n        {\n          {:one_for_one, 1, 1},\n          [\n            {:child, {:m, :f, []}, :permanent, 1, :worker, []},\n            {:child, {:m, :f, []}, :permanent, 1, :worker, []}\n          ]\n        }\n      }\n\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n\n      assert Exception.format_exit(reason) =~\n               \"bad child specification, more than one child specification has the id: :child\"\n\n      return = {\n        :ok,\n        {{:one_for_one, 1, 1}, [{:child, {Kernel, :exit, [:foo]}, :temporary, 1, :worker, []}]}\n      }\n\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n\n      assert Exception.format_exit(reason) ==\n               \"shutdown: failed to start child: :child\\n    ** (EXIT) :foo\"\n\n      return = {\n        :ok,\n        {\n          {:one_for_one, 1, 1},\n          [{:child, {Kernel, :apply, [fn -> {:error, :foo} end, []]}, :temporary, 1, :worker, []}]\n        }\n      }\n\n      {:error, reason} = __MODULE__.Sup.start_link(fn -> return end)\n\n      assert Exception.format_exit(reason) ==\n               \"shutdown: failed to start child: :child\\n    ** (EXIT) :foo\"\n    end\n\n    test \"with call\" do\n      reason =\n        try do\n          :gen_server.call(:does_not_exist, :hello)\n        catch\n          :exit, reason -> reason\n        end\n\n      expected_to_start_with =\n        \"exited in: :gen_server.call(:does_not_exist, :hello)\\n    ** (EXIT) no process:\"\n\n      assert Exception.format_exit(reason) |> String.starts_with?(expected_to_start_with)\n    end\n\n    test \"with nested calls\" do\n      Process.flag(:trap_exit, true)\n      # Fake reason to prevent error_logger printing to stdout\n      exit_fun = fn -> receive do: (_ -> exit(:normal)) end\n\n      outer_pid =\n        spawn_link(fn ->\n          Process.flag(:trap_exit, true)\n\n          receive do\n            _ ->\n              :gen_event.call(spawn_link(exit_fun), :handler, :hello)\n          end\n        end)\n\n      reason =\n        try do\n          :gen_server.call(outer_pid, :hi)\n        catch\n          :exit, reason -> reason\n        end\n\n      formatted = Exception.format_exit(reason)\n      assert formatted =~ ~r\"exited in: :gen_server\\.call\\(#PID<\\d+\\.\\d+\\.\\d+>, :hi\\)\\n\"\n\n      assert formatted =~\n               ~r\"\\s{4}\\*\\* \\(EXIT\\) exited in: :gen_event\\.call\\(#PID<\\d+\\.\\d+\\.\\d+>, :handler, :hello\\)\\n\"\n\n      assert formatted =~ ~r\"\\s{8}\\*\\* \\(EXIT\\) normal\"\n    end\n\n    test \"format_exit/1 with nested calls and exception\" do\n      Process.flag(:trap_exit, true)\n      # Fake reason to prevent error_logger printing to stdout\n      exit_reason = {%ArgumentError{}, [{:not_a_real_module, :function, 0, []}]}\n      exit_fun = fn -> receive do: (_ -> exit(exit_reason)) end\n\n      outer_pid =\n        spawn_link(fn ->\n          Process.flag(:trap_exit, true)\n          :gen_event.call(spawn_link(exit_fun), :handler, :hello)\n        end)\n\n      reason =\n        try do\n          :gen_server.call(outer_pid, :hi)\n        catch\n          :exit, reason -> reason\n        end\n\n      formatted = Exception.format_exit(reason)\n      assert formatted =~ ~r\"exited in: :gen_server\\.call\\(#PID<\\d+\\.\\d+\\.\\d+>, :hi\\)\\n\"\n\n      assert formatted =~\n               ~r\"\\s{4}\\*\\* \\(EXIT\\) exited in: :gen_event\\.call\\(#PID<\\d+\\.\\d+\\.\\d+>, :handler, :hello\\)\\n\"\n\n      assert formatted =~ ~r\"\\s{8}\\*\\* \\(EXIT\\) an exception was raised:\\n\"\n      assert formatted =~ ~r\"\\s{12}\\*\\* \\(ArgumentError\\) argument error\\n\"\n      assert formatted =~ ~r\"\\s{16}:not_a_real_module\\.function/0\"\n    end\n  end\n\n  describe \"blaming\" do\n    test \"does not annotate throws/exits\" do\n      stack = [{Keyword, :pop, [%{}, :key, nil], [line: 13]}]\n      assert Exception.blame(:throw, :function_clause, stack) == {:function_clause, stack}\n      assert Exception.blame(:exit, :function_clause, stack) == {:function_clause, stack}\n    end\n\n    test \"handles operators precedence\" do\n      import PathHelpers\n\n      write_beam(\n        defmodule OperatorPrecedence do\n          def test!(x, y) when x in [1, 2, 3] and y >= 4, do: :ok\n        end\n      )\n\n      :code.purge(OperatorPrecedence)\n      :code.delete(OperatorPrecedence)\n\n      assert blame_message(OperatorPrecedence, & &1.test!(1, 2)) =~ \"\"\"\n             no function clause matching in ExceptionTest.OperatorPrecedence.test!/2\n\n             The following arguments were given to ExceptionTest.OperatorPrecedence.test!/2:\n\n                 # 1\n                 1\n\n                 # 2\n                 2\n\n             Attempted function clauses (showing 1 out of 1):\n\n                 def test!(x, y) when (x === 1 or -x === 2- or -x === 3-) and -y >= 4-\n             \"\"\"\n    end\n\n    test \"reverts is_struct macro on guards for blaming\" do\n      import PathHelpers\n\n      write_beam(\n        defmodule Req do\n          def get!(url)\n              when is_binary(url) or (is_struct(url) and is_struct(url, URI) and false) do\n            url\n          end\n\n          def get!(url, url_module)\n              when is_binary(url) or (is_struct(url) and is_struct(url, url_module) and false) do\n            url\n          end\n\n          def sub_get!(url) when is_struct(url.sub, URI), do: url.sub\n        end\n      )\n\n      :code.purge(Req)\n      :code.delete(Req)\n\n      assert blame_message(Req, & &1.get!(url: \"https://elixir-lang.org\")) =~ \"\"\"\n             no function clause matching in ExceptionTest.Req.get!/1\n\n             The following arguments were given to ExceptionTest.Req.get!/1:\n\n                 # 1\n                 [url: \"https://elixir-lang.org\"]\n\n             Attempted function clauses (showing 1 out of 1):\n\n                 def get!(url) when -is_binary(url)- or -is_struct(url)- and -is_struct(url, URI)- and -false-\n             \"\"\"\n\n      elixir_uri = %URI{} = URI.parse(\"https://elixir-lang.org\")\n\n      assert blame_message(Req, & &1.get!(elixir_uri, URI)) =~ \"\"\"\n             no function clause matching in ExceptionTest.Req.get!/2\n\n             The following arguments were given to ExceptionTest.Req.get!/2:\n\n                 # 1\n                 %URI{scheme: \\\"https\\\", authority: \\\"elixir-lang.org\\\", userinfo: nil, host: \\\"elixir-lang.org\\\", port: 443, path: nil, query: nil, fragment: nil}\n\n                 # 2\n                 URI\n\n             Attempted function clauses (showing 1 out of 1):\n\n                 def get!(url, url_module) when -is_binary(url)- or is_struct(url) and is_struct(url, url_module) and -false-\n             \"\"\"\n\n      assert blame_message(Req, & &1.get!(elixir_uri)) =~ \"\"\"\n             no function clause matching in ExceptionTest.Req.get!/1\n\n             The following arguments were given to ExceptionTest.Req.get!/1:\n\n                 # 1\n                 %URI{scheme: \\\"https\\\", authority: \\\"elixir-lang.org\\\", userinfo: nil, host: \\\"elixir-lang.org\\\", port: 443, path: nil, query: nil, fragment: nil}\n\n             Attempted function clauses (showing 1 out of 1):\n\n                 def get!(url) when -is_binary(url)- or is_struct(url) and is_struct(url, URI) and -false-\n             \"\"\"\n\n      assert blame_message(Req, & &1.sub_get!(%{})) =~ \"\"\"\n             no function clause matching in ExceptionTest.Req.sub_get!/1\n\n             The following arguments were given to ExceptionTest.Req.sub_get!/1:\n\n                 # 1\n                 %{}\n\n             Attempted function clauses (showing 1 out of 1):\n\n                 def sub_get!(url) when -is_struct(url.sub, URI)-\n             \"\"\"\n    end\n\n    test \"annotates badarg on apply\" do\n      assert blame_message([], & &1.foo()) ==\n               \"you attempted to apply a function named :foo on []. If you are using Kernel.apply/3, make sure \" <>\n                 \"the module is an atom. If you are using the dot syntax, such as \" <>\n                 \"module.function(), make sure the left-hand side of the dot is an atom representing a module\"\n\n      assert blame_message([], &apply(&1, :foo, [])) ==\n               \"you attempted to apply a function named :foo on []. If you are using Kernel.apply/3, make sure \" <>\n                 \"the module is an atom. If you are using the dot syntax, such as \" <>\n                 \"module.function(), make sure the left-hand side of the dot is an atom representing a module\"\n\n      assert blame_message([], &apply(&1, :foo, [1, 2])) ==\n               \"you attempted to apply a function on []. Modules (the first argument of apply) must always be an atom\"\n    end\n\n    test \"annotates function clause errors\" do\n      import PathHelpers\n\n      write_beam(\n        defmodule ExampleModule do\n          def fun(arg1, arg2)\n          def fun(:one, :one), do: :ok\n          def fun(:two, :two), do: :ok\n        end\n      )\n\n      message = blame_message(ExceptionTest.ExampleModule, & &1.fun(:three, :four))\n\n      assert message =~ \"\"\"\n             no function clause matching in ExceptionTest.ExampleModule.fun/2\n\n             The following arguments were given to ExceptionTest.ExampleModule.fun/2:\n\n                 # 1\n                 :three\n\n                 # 2\n                 :four\n\n             Attempted function clauses (showing 2 out of 2):\n\n                 def fun(-:one-, -:one-)\n                 def fun(-:two-, -:two-)\n             \"\"\"\n    end\n\n    test \"annotates undefined function error with suggestions\" do\n      assert blame_message(Enum, & &1.map(:ok)) == \"\"\"\n             function Enum.map/1 is undefined or private. Did you mean:\n\n                 * map/2\n             \"\"\"\n\n      assert blame_message(Enum, & &1.man(:ok)) == \"\"\"\n             function Enum.man/1 is undefined or private. Did you mean:\n\n                 * map/2\n                 * max/1\n                 * max/2\n                 * max/3\n                 * min/1\n             \"\"\"\n\n      message = blame_message(:erlang, & &1.gt_cookie())\n      assert message =~ \"function :erlang.gt_cookie/0 is undefined or private. Did you mean:\"\n      assert message =~ \"* get_cookie/0\"\n      assert message =~ \"* set_cookie/2\"\n    end\n\n    test \"annotates undefined function error with module suggestions\" do\n      import PathHelpers\n\n      modules = [\n        Namespace.A.One,\n        Namespace.A.Two,\n        Namespace.A.Three,\n        Namespace.B.One,\n        Namespace.B.Two,\n        Namespace.B.Three\n      ]\n\n      for module <- modules do\n        write_beam(\n          defmodule module do\n            def foo, do: :bar\n          end\n        )\n      end\n\n      assert blame_message(ENUM, & &1.map(&1, 1)) == \"\"\"\n             function ENUM.map/2 is undefined (module ENUM is not available). Did you mean:\n\n                   * Enum.map/2\n             \"\"\"\n\n      assert blame_message(ENUM, & &1.not_a_function(&1, 1)) ==\n               \"function ENUM.not_a_function/2 is undefined (module ENUM is not available). \" <>\n                 \"Make sure the module name is correct and has been specified in full (or that an alias has been defined)\"\n\n      assert blame_message(One, & &1.foo()) == \"\"\"\n             function One.foo/0 is undefined (module One is not available). Did you mean:\n\n                   * Namespace.A.One.foo/0\n                   * Namespace.B.One.foo/0\n             \"\"\"\n\n      for module <- modules do\n        :code.purge(module)\n        :code.delete(module)\n      end\n    end\n\n    test \"annotates undefined function clause error with macro hints\" do\n      assert blame_message(Integer, & &1.is_odd(1)) ==\n               \"function Integer.is_odd/1 is undefined or private. However, there is \" <>\n                 \"a macro with the same name and arity. Be sure to require Integer if \" <>\n                 \"you intend to invoke this macro\"\n    end\n\n    test \"annotates undefined function clause error with callback hints\" do\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n          defmodule Behaviour do\n            @callback callback() :: :ok\n          end\n\n          defmodule Implementation do\n            @behaviour Behaviour\n          end\n        \"\"\")\n      end)\n\n      assert blame_message(Implementation, & &1.callback()) ==\n               \"function Implementation.callback/0 is undefined or private\" <>\n                 \", but the behaviour Behaviour expects it to be present\"\n    end\n\n    test \"does not annotate undefined function clause error with callback hints when callback is optional\" do\n      defmodule BehaviourWithOptional do\n        @callback callback() :: :ok\n        @callback optional() :: :ok\n        @optional_callbacks callback: 0, optional: 0\n      end\n\n      defmodule ImplementationWithOptional do\n        @behaviour BehaviourWithOptional\n        def callback(), do: :ok\n      end\n\n      assert blame_message(ImplementationWithOptional, & &1.optional()) ==\n               \"function ExceptionTest.ImplementationWithOptional.optional/0 is undefined or private\"\n    end\n\n    test \"annotates undefined function clause error with otp obsolete hints\" do\n      assert blame_message(:erlang, & &1.hash(1, 2)) ==\n               \"function :erlang.hash/2 is undefined or private, use erlang:phash2/2 instead\"\n    end\n\n    test \"annotates undefined function clause error with nil hints\" do\n      assert blame_message(nil, & &1.foo()) ==\n               \"function nil.foo/0 is undefined. If you are using the dot syntax, \" <>\n                 \"such as module.function(), make sure the left-hand side of \" <>\n                 \"the dot is a module atom\"\n\n      assert blame_message(\"nil.foo()\", &Code.eval_string/1) ==\n               \"function nil.foo/0 is undefined. If you are using the dot syntax, \" <>\n                 \"such as module.function(), make sure the left-hand side of \" <>\n                 \"the dot is a module atom\"\n    end\n\n    test \"annotates key error with suggestions if keys are atoms\" do\n      message = blame_message(%{first: nil, second: nil}, fn map -> map.firts end)\n\n      assert message ==\n               \"\"\"\n               key :firts not found in:\n\n                   %{first: nil, second: nil}\n\n               Did you mean:\n\n                   * :first\n               \"\"\"\n\n      message = blame_message(%{\"first\" => nil, \"second\" => nil}, fn map -> map.firts end)\n\n      assert message == \"\"\"\n             key :firts not found in:\n\n                 %{\"first\" => nil, \"second\" => nil}\n             \"\"\"\n\n      message =\n        blame_message(%{\"first\" => nil, \"second\" => nil}, fn map -> Map.fetch!(map, \"firts\") end)\n\n      assert message ==\n               \"\"\"\n               key \"firts\" not found in:\n\n                   %{\"first\" => nil, \"second\" => nil}\n               \"\"\"\n\n      message =\n        blame_message(\n          [\n            created_at: nil,\n            updated_at: nil,\n            deleted_at: nil,\n            started_at: nil,\n            finished_at: nil\n          ],\n          fn kwlist ->\n            Keyword.fetch!(kwlist, :inserted_at)\n          end\n        )\n\n      assert message == \"\"\"\n             key :inserted_at not found in:\n\n                 [\n                   created_at: nil,\n                   updated_at: nil,\n                   deleted_at: nil,\n                   started_at: nil,\n                   finished_at: nil\n                 ]\n\n             Did you mean:\n\n                 * :created_at\n                 * :finished_at\n                 * :started_at\n             \"\"\"\n    end\n\n    test \"annotates key error with suggestions for structs\" do\n      message = blame_message(%URI{}, fn map -> map.schema end)\n      assert message =~ \"key :schema not found in:\\n\\n    %URI{\"\n      assert message =~ \"Did you mean:\"\n      assert message =~ \"* :scheme\"\n    end\n\n    test \"annotates +/1 arithmetic errors\" do\n      assert blame_message(:foo, &(+&1)) == \"bad argument in arithmetic expression: +(:foo)\"\n    end\n\n    test \"annotates -/1 arithmetic errors\" do\n      assert blame_message(:foo, &(-&1)) == \"bad argument in arithmetic expression: -(:foo)\"\n    end\n\n    test \"annotates div arithmetic errors\" do\n      assert blame_message(0, &div(10, &1)) ==\n               \"bad argument in arithmetic expression: div(10, 0)\"\n    end\n\n    test \"annotates rem arithmetic errors\" do\n      assert blame_message(0, &rem(10, &1)) ==\n               \"bad argument in arithmetic expression: rem(10, 0)\"\n    end\n\n    test \"annotates band arithmetic errors\" do\n      import Bitwise\n\n      assert blame_message(:foo, &band(&1, 10)) ==\n               \"bad argument in arithmetic expression: Bitwise.band(:foo, 10)\"\n\n      assert blame_message(:foo, &(&1 &&& 10)) ==\n               \"bad argument in arithmetic expression: Bitwise.band(:foo, 10)\"\n    end\n\n    test \"annotates bor arithmetic errors\" do\n      import Bitwise\n\n      assert blame_message(:foo, &bor(&1, 10)) ==\n               \"bad argument in arithmetic expression: Bitwise.bor(:foo, 10)\"\n\n      assert blame_message(:foo, &(&1 ||| 10)) ==\n               \"bad argument in arithmetic expression: Bitwise.bor(:foo, 10)\"\n    end\n\n    test \"annotates bxor arithmetic errors\" do\n      import Bitwise\n\n      assert blame_message(:foo, &bxor(&1, 10)) ==\n               \"bad argument in arithmetic expression: Bitwise.bxor(:foo, 10)\"\n    end\n\n    test \"annotates bsl arithmetic errors\" do\n      import Bitwise\n\n      assert blame_message(:foo, &bsl(10, &1)) ==\n               \"bad argument in arithmetic expression: Bitwise.bsl(10, :foo)\"\n\n      assert blame_message(:foo, &(10 <<< &1)) ==\n               \"bad argument in arithmetic expression: Bitwise.bsl(10, :foo)\"\n    end\n\n    test \"annotates bsr arithmetic errors\" do\n      import Bitwise\n\n      assert blame_message(:foo, &bsr(10, &1)) ==\n               \"bad argument in arithmetic expression: Bitwise.bsr(10, :foo)\"\n\n      assert blame_message(:foo, &(10 >>> &1)) ==\n               \"bad argument in arithmetic expression: Bitwise.bsr(10, :foo)\"\n    end\n\n    test \"annotates bnot arithmetic errors\" do\n      import Bitwise\n\n      assert blame_message(:foo, &bnot(&1)) ==\n               \"bad argument in arithmetic expression: Bitwise.bnot(:foo)\"\n    end\n\n    defp blame_message(arg, fun) do\n      try do\n        fun.(arg)\n      rescue\n        e ->\n          Exception.blame(:error, e, __STACKTRACE__) |> elem(0) |> Exception.message()\n      end\n    end\n  end\n\n  describe \"blaming unit tests\" do\n    test \"annotates clauses errors\" do\n      import PathHelpers\n\n      write_beam(\n        defmodule BlameModule do\n          def fun(arg), do: arg\n        end\n      )\n\n      args = [nil]\n\n      {exception, stack} =\n        Exception.blame(:error, :function_clause, [{BlameModule, :fun, args, [line: 13]}])\n\n      assert %FunctionClauseError{kind: :def, args: ^args, clauses: [_]} = exception\n      assert stack == [{BlameModule, :fun, 1, [line: 13]}]\n    end\n\n    @tag :require_ast\n    test \"annotates args and clauses from mfa\" do\n      import PathHelpers\n\n      write_beam(\n        defmodule Blaming do\n          def with_elem(x, y) when elem(x, 1) == 0 and elem(x, y) == 1 do\n            {x, y}\n          end\n\n          def fetch(%module{} = container, key), do: {module, container, key}\n          def fetch(map, key) when is_map(map), do: {map, key}\n          def fetch(list, key) when is_list(list) and is_atom(key), do: {list, key}\n          def fetch(nil, _key), do: nil\n\n          require Integer\n          def even_and_odd(foo, bar) when Integer.is_even(foo) and Integer.is_odd(bar), do: :ok\n        end\n      )\n\n      :code.purge(Blaming)\n      :code.delete(Blaming)\n\n      {:ok, :def, clauses} = Exception.blame_mfa(Blaming, :with_elem, [1, 2])\n\n      assert annotated_clauses_to_string(clauses) == [\n               \"{[+x+, +y+], [-elem(x, 1) == 0- and -elem(x, y) == 1-]}\"\n             ]\n\n      {:ok, :def, clauses} = Exception.blame_mfa(Blaming, :fetch, [self(), \"oops\"])\n\n      assert annotated_clauses_to_string(clauses) == [\n               \"{[-%module{} = container-, +key+], []}\",\n               \"{[+map+, +key+], [-is_map(map)-]}\",\n               \"{[+list+, +key+], [-is_list(list)- and -is_atom(key)-]}\",\n               \"{[-nil-, +_key+], []}\"\n             ]\n\n      {:ok, :def, clauses} = Exception.blame_mfa(Blaming, :even_and_odd, [1, 1])\n\n      assert annotated_clauses_to_string(clauses) == [\n               \"{[+foo+, +bar+], [+is_integer(foo)+ and -Bitwise.band(foo, 1) == 0- and +is_integer(bar)+ and +Bitwise.band(bar, 1) == 1+]}\"\n             ]\n\n      {:ok, :defmacro, clauses} = Exception.blame_mfa(Kernel, :!, [true])\n\n      assert annotated_clauses_to_string(clauses) == [\n               \"{[-{:!, _, [value]}-], []}\",\n               \"{[+value+], []}\"\n             ]\n    end\n\n    defp annotated_clauses_to_string(clauses) do\n      Enum.map(clauses, fn {args, clauses} ->\n        args = Enum.map_join(args, \", \", &arg_to_string/1)\n        clauses = Enum.map_join(clauses, \", \", &clause_to_string/1)\n        \"{[#{args}], [#{clauses}]}\"\n      end)\n    end\n\n    defp arg_to_string(%{match?: true, node: node}), do: \"+\" <> Macro.to_string(node) <> \"+\"\n    defp arg_to_string(%{match?: false, node: node}), do: \"-\" <> Macro.to_string(node) <> \"-\"\n\n    defp clause_to_string({op, _, [left, right]}),\n      do: clause_to_string(left) <> \" #{op} \" <> clause_to_string(right)\n\n    defp clause_to_string(other),\n      do: arg_to_string(other)\n  end\n\n  describe \"exception messages\" do\n    import Exception, only: [message: 1]\n\n    test \"RuntimeError\" do\n      assert %RuntimeError{} |> message() == \"runtime error\"\n      assert %RuntimeError{message: \"unexpected roquefort\"} |> message() == \"unexpected roquefort\"\n    end\n\n    test \"ArithmeticError\" do\n      assert %ArithmeticError{} |> message() == \"bad argument in arithmetic expression\"\n\n      assert %ArithmeticError{message: \"unexpected camembert\"}\n             |> message() == \"unexpected camembert\"\n    end\n\n    test \"ArgumentError\" do\n      assert %ArgumentError{} |> message() == \"argument error\"\n      assert %ArgumentError{message: \"unexpected comté\"} |> message() == \"unexpected comté\"\n    end\n\n    test \"KeyError\" do\n      assert %KeyError{} |> message() == \"key nil not found\"\n      assert %KeyError{message: \"key missed\"} |> message() == \"key missed\"\n    end\n\n    test \"Enum.OutOfBoundsError\" do\n      assert %Enum.OutOfBoundsError{} |> message() == \"out of bounds error\"\n\n      assert %Enum.OutOfBoundsError{message: \"the brie is not on the table\"}\n             |> message() == \"the brie is not on the table\"\n    end\n\n    test \"Enum.EmptyError\" do\n      assert %Enum.EmptyError{} |> message() == \"empty error\"\n\n      assert %Enum.EmptyError{message: \"there is no saint-nectaire left!\"}\n             |> message() == \"there is no saint-nectaire left!\"\n    end\n\n    test \"UndefinedFunctionError\" do\n      assert %UndefinedFunctionError{} |> message() == \"undefined function\"\n\n      assert %UndefinedFunctionError{module: Kernel, function: :bar, arity: 1}\n             |> message() == \"function Kernel.bar/1 is undefined or private\"\n\n      assert %UndefinedFunctionError{module: Foo, function: :bar, arity: 1}\n             |> message() ==\n               \"function Foo.bar/1 is undefined (module Foo is not available). \" <>\n                 \"Make sure the module name is correct and has been specified in full (or that an alias has been defined)\"\n\n      assert %UndefinedFunctionError{module: nil, function: :bar, arity: 3}\n             |> message() == \"function nil.bar/3 is undefined\"\n\n      assert %UndefinedFunctionError{module: nil, function: :bar, arity: 0}\n             |> message() == \"function nil.bar/0 is undefined\"\n    end\n\n    test \"FunctionClauseError\" do\n      assert %FunctionClauseError{} |> message() == \"no function clause matches\"\n\n      assert %FunctionClauseError{module: Foo, function: :bar, arity: 1}\n             |> message() == \"no function clause matching in Foo.bar/1\"\n    end\n\n    test \"ErlangError\" do\n      assert %ErlangError{original: :sample} |> message() == \"Erlang error: :sample\"\n    end\n\n    test \"MissingApplicationsError\" do\n      assert %MissingApplicationsError{\n               apps: [{:logger, \"~> 1.18\"}, {:ex_unit, Version.parse_requirement!(\">= 0.0.0\")}],\n               description: \"applications are required\"\n             }\n             |> message() == \"\"\"\n             applications are required\n\n             To address this, include these applications as your dependencies:\n\n               {:logger, \"~> 1.18\"}\n               {:ex_unit, \">= 0.0.0\"}\\\n             \"\"\"\n    end\n  end\n\n  describe \"error_info\" do\n    test \"badarg on erlang\" do\n      assert message(:erlang, & &1.element(\"foo\", \"bar\")) == \"\"\"\n             errors were found at the given arguments:\n\n               * 1st argument: not an integer\n               * 2nd argument: not a tuple\n             \"\"\"\n    end\n\n    test \"badarg on ets\" do\n      ets = :ets.new(:foo, [])\n      :ets.delete(ets)\n\n      assert message(:ets, & &1.insert(ets, 1)) == \"\"\"\n             errors were found at the given arguments:\n\n               * 1st argument: the table identifier does not refer to an existing ETS table\n               * 2nd argument: not a tuple\n             \"\"\"\n    end\n\n    test \"system_limit on counters\" do\n      assert message(:counters, & &1.new(123_456_789_123_456_789_123_456_789, [])) == \"\"\"\n             a system limit has been reached due to errors at the given arguments:\n\n               * 1st argument: counters array size reached a system limit\n             \"\"\"\n    end\n  end\n\n  describe \"binary constructor error info\" do\n    defp concat(a, b), do: a <> b\n\n    test \"on binary concatenation\" do\n      assert message(123, &concat(&1, \"bar\")) ==\n               \"construction of binary failed: segment 1 of type 'binary': expected a binary but got: 123\"\n\n      assert message(~D[0001-02-03], &concat(&1, \"bar\")) ==\n               \"construction of binary failed: segment 1 of type 'binary': expected a binary but got: ~D[0001-02-03]\"\n    end\n  end\n\n  defp message(arg, fun) do\n    try do\n      fun.(arg)\n    rescue\n      e -> Exception.message(e)\n    end\n  end\n\n  def dummy_error_extras(_exception, _stacktrace), do: %{general: \"foo\"}\n\n  def dummy_error_chardata(_exception, _stacktrace) do\n    %{general: ~c\"this is \" ++ [~c\"chardata\"], reason: ~c\"this \" ++ [~c\"too\"]}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/file/stream_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule File.StreamTest do\n  use ExUnit.Case\n  import PathHelpers\n\n  setup do\n    File.mkdir_p!(tmp_path())\n    on_exit(fn -> File.rm_rf(tmp_path()) end)\n    :ok\n  end\n\n  defp stream!(node, src, lines_or_bytes_or_modes \\\\ []) do\n    :erpc.call(node, File, :stream!, [src, lines_or_bytes_or_modes])\n  end\n\n  defp stream!(node, src, modes, lines_or_bytes) do\n    :erpc.call(node, File, :stream!, [src, modes, lines_or_bytes])\n  end\n\n  distributed_node = :\"secondary@#{node() |> Atom.to_string() |> :binary.split(\"@\") |> tl()}\"\n\n  for {type, node} <- [local: node(), distributed: distributed_node] do\n    describe \"#{type} node\" do\n      @describetag type\n      @node node\n\n      test \"returns a struct\" do\n        src = fixture_path(\"file.txt\")\n        stream = stream!(@node, src)\n        assert %File.Stream{} = stream\n        assert stream.modes == [:raw, :read_ahead, :binary]\n        assert stream.raw\n        assert stream.line_or_bytes == :line\n\n        stream = stream!(@node, src, read_ahead: false)\n        assert %File.Stream{} = stream\n        assert stream.modes == [:raw, :binary]\n        assert stream.raw\n\n        stream = stream!(@node, src, read_ahead: 5000)\n        assert %File.Stream{} = stream\n        assert stream.modes == [:raw, {:read_ahead, 5000}, :binary]\n        assert stream.raw\n\n        stream = stream!(@node, src, 10, [:utf8])\n        assert %File.Stream{} = stream\n        assert stream.modes == [{:encoding, :utf8}, :binary]\n        refute stream.raw\n        assert stream.line_or_bytes == 10\n      end\n\n      test \"counts bytes/characters\" do\n        src = fixture_path(\"file.txt\")\n        stream = stream!(@node, src)\n        assert Enum.count(stream) == 1\n\n        stream = stream!(@node, src, [:utf8])\n        assert Enum.count(stream) == 1\n\n        stream = stream!(@node, src, 2)\n        assert Enum.count(stream) == 2\n      end\n\n      test \"counts lines without trailing newline\" do\n        no_trailing = tmp_path(\"no_trailing.txt\")\n        single_line = tmp_path(\"single_line.txt\")\n        empty_file = tmp_path(\"empty.txt\")\n\n        try do\n          File.write!(no_trailing, \"line1\\nline2\\nline3\")\n          File.write!(single_line, \"hello\")\n          File.write!(empty_file, \"\")\n\n          # 3 lines, no trailing newline\n          stream = stream!(@node, no_trailing)\n          assert Enum.count(stream) == 3\n\n          # 1 line, no newline at all\n          stream = stream!(@node, single_line)\n          assert Enum.count(stream) == 1\n\n          # empty file\n          stream = stream!(@node, empty_file)\n          assert Enum.count(stream) == 0\n        after\n          File.rm(no_trailing)\n          File.rm(single_line)\n          File.rm(empty_file)\n        end\n      end\n\n      test \"reads and writes lines\" do\n        src = fixture_path(\"file.txt\")\n        dest = tmp_path(\"tmp_test.txt\")\n\n        try do\n          stream = stream!(@node, src)\n\n          File.open(dest, [:write], fn target ->\n            Enum.each(stream, fn line ->\n              IO.write(target, String.replace(line, \"O\", \"A\"))\n            end)\n          end)\n\n          assert File.read(dest) == {:ok, \"FAA\\n\"}\n        after\n          File.rm(dest)\n        end\n      end\n\n      test \"reads and writes bytes\" do\n        src = fixture_path(\"file.txt\")\n        dest = tmp_path(\"tmp_test.txt\")\n\n        try do\n          stream = stream!(@node, src, 1)\n\n          File.open(dest, [:write], fn target ->\n            Enum.each(stream, fn <<char>> ->\n              IO.write(target, <<char + 1>>)\n            end)\n          end)\n\n          assert File.read(dest) == {:ok, \"GPP\\v\"}\n        after\n          File.rm(dest)\n        end\n      end\n\n      test \"is collectable\" do\n        src = fixture_path(\"file.txt\")\n        dest = tmp_path(\"tmp_test.txt\")\n\n        try do\n          refute File.exists?(dest)\n          original = stream!(@node, dest)\n\n          stream =\n            stream!(@node, src)\n            |> Stream.map(&String.replace(&1, \"O\", \"A\"))\n            |> Enum.into(original)\n\n          assert stream == original\n          assert File.read(dest) == {:ok, \"FAA\\n\"}\n        after\n          File.rm(dest)\n        end\n      end\n\n      test \"is collectable with append\" do\n        src = fixture_path(\"file.txt\")\n        dest = tmp_path(\"tmp_test.txt\")\n\n        try do\n          refute File.exists?(dest)\n          original = stream!(@node, dest, [:append])\n\n          stream!(@node, src, [:append])\n          |> Stream.map(&String.replace(&1, \"O\", \"A\"))\n          |> Enum.into(original)\n\n          stream!(@node, src, [:append])\n          |> Enum.into(original)\n\n          assert File.read(dest) == {:ok, \"FAA\\nFOO\\n\"}\n        after\n          File.rm(dest)\n        end\n      end\n\n      test \"supports byte offset\" do\n        src = fixture_path(\"file.txt\")\n\n        assert @node\n               |> stream!(src, read_offset: 0)\n               |> Enum.take(1) == [\"FOO\\n\"]\n\n        assert @node\n               |> stream!(src, read_offset: 1)\n               |> Enum.take(1) == [\"OO\\n\"]\n\n        assert @node\n               |> stream!(src, read_offset: 4)\n               |> Enum.take(1) == []\n\n        assert @node |> stream!(src, 1, read_offset: 1) |> Enum.count() == 3\n        assert @node |> stream!(src, 1, read_offset: 4) |> Enum.count() == 0\n      end\n\n      test \"applies offset after trimming BOM\" do\n        src = fixture_path(\"utf8_bom.txt\")\n\n        assert @node\n               |> stream!(src, [:trim_bom, read_offset: 4])\n               |> Enum.take(1) == [\"сский\\n\"]\n\n        assert @node |> stream!(src, 1, [:trim_bom, read_offset: 4]) |> Enum.count() == 15\n      end\n\n      test \"keeps BOM when raw\" do\n        src = fixture_path(\"utf8_bom.txt\")\n\n        assert @node\n               |> stream!(src, [])\n               |> Enum.take(1) == [<<239, 187, 191>> <> \"Русский\\n\"]\n\n        assert @node\n               |> stream!(src, 1)\n               |> Enum.take(5) == [<<239>>, <<187>>, <<191>>, <<208>>, <<160>>]\n\n        assert @node |> stream!(src, []) |> Enum.count() == 2\n        assert @node |> stream!(src, 1) |> Enum.count() == 22\n      end\n\n      test \"trims BOM via option when raw\" do\n        src = fixture_path(\"utf8_bom.txt\")\n\n        assert @node\n               |> stream!(src, [:trim_bom])\n               |> Enum.take(1) == [\"Русский\\n\"]\n\n        assert @node\n               |> stream!(src, 1, [:trim_bom])\n               |> Enum.take(5) == [<<208>>, <<160>>, <<209>>, <<131>>, <<209>>]\n\n        assert @node |> stream!(src, [:trim_bom]) |> Enum.count() == 2\n        assert @node |> stream!(src, 1, [:trim_bom]) |> Enum.count() == 19\n        assert @node |> stream!(src, 2, [:trim_bom]) |> Enum.count() == 10\n      end\n\n      test \"keeps BOM with utf8 encoding\" do\n        src = fixture_path(\"utf8_bom.txt\")\n\n        assert @node\n               |> stream!(src, encoding: :utf8)\n               |> Enum.take(1) == [<<239, 187, 191>> <> \"Русский\\n\"]\n\n        assert @node\n               |> stream!(src, 1, encoding: :utf8)\n               |> Enum.take(9) == [\"\\uFEFF\", \"Р\", \"у\", \"с\", \"с\", \"к\", \"и\", \"й\", \"\\n\"]\n      end\n\n      test \"trims BOM via option with utf8 encoding\" do\n        src = fixture_path(\"utf8_bom.txt\")\n\n        assert @node\n               |> stream!(src, [{:encoding, :utf8}, :trim_bom])\n               |> Enum.take(1) == [\"Русский\\n\"]\n\n        assert @node\n               |> stream!(src, 1, [{:encoding, :utf8}, :trim_bom])\n               |> Enum.take(8) == [\"Р\", \"у\", \"с\", \"с\", \"к\", \"и\", \"й\", \"\\n\"]\n      end\n\n      test \"keeps BOM with UTF16 BE\" do\n        src = fixture_path(\"utf16_be_bom.txt\")\n\n        assert @node\n               |> stream!(src, [{:encoding, {:utf16, :big}}])\n               |> Enum.take(1) == [\"\\uFEFFРусский\\n\"]\n      end\n\n      test \"keeps BOM with UTF16 LE\" do\n        src = fixture_path(\"utf16_le_bom.txt\")\n\n        assert @node\n               |> stream!(src, [{:encoding, {:utf16, :little}}])\n               |> Enum.take(1) == [\"\\uFEFFРусский\\n\"]\n      end\n\n      test \"trims BOM via option with utf16 BE encoding\" do\n        src = fixture_path(\"utf16_be_bom.txt\")\n\n        assert @node\n               |> stream!(src, [{:encoding, {:utf16, :big}}, :trim_bom])\n               |> Enum.take(1) == [\"Русский\\n\"]\n\n        assert @node\n               |> stream!(src, 1, [{:encoding, {:utf16, :big}}, :trim_bom])\n               |> Enum.take(8) == [\"Р\", \"у\", \"с\", \"с\", \"к\", \"и\", \"й\", \"\\n\"]\n      end\n\n      test \"trims BOM via option with utf16 LE encoding\" do\n        src = fixture_path(\"utf16_le_bom.txt\")\n\n        assert @node\n               |> stream!(src, [{:encoding, {:utf16, :little}}, :trim_bom])\n               |> Enum.take(1) == [\"Русский\\n\"]\n\n        assert @node\n               |> stream!(src, 1, [{:encoding, {:utf16, :little}}, :trim_bom])\n               |> Enum.take(8) == [\"Р\", \"у\", \"с\", \"с\", \"к\", \"и\", \"й\", \"\\n\"]\n      end\n\n      test \"reads and writes line by line in UTF-8\" do\n        src = fixture_path(\"file.txt\")\n        dest = tmp_path(\"tmp_test.txt\")\n\n        try do\n          stream = stream!(@node, src)\n\n          File.open(dest, [:write, :utf8], fn target ->\n            Enum.each(stream, fn line ->\n              IO.write(target, String.replace(line, \"O\", \"A\"))\n            end)\n          end)\n\n          assert File.read(dest) == {:ok, \"FAA\\n\"}\n        after\n          File.rm(dest)\n        end\n      end\n\n      test \"reads and writes character in UTF-8\" do\n        src = fixture_path(\"file.txt\")\n        dest = tmp_path(\"tmp_test.txt\")\n\n        try do\n          stream = stream!(@node, src, 1, [:utf8])\n\n          File.open(dest, [:write], fn target ->\n            Enum.each(stream, fn <<char::utf8>> ->\n              IO.write(target, <<char + 1::utf8>>)\n            end)\n          end)\n\n          assert File.read(dest) == {:ok, \"GPP\\v\"}\n        after\n          File.rm(dest)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/file_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule FileTest do\n  use ExUnit.Case\n  import PathHelpers\n\n  setup do\n    File.mkdir_p!(tmp_path())\n    on_exit(fn -> File.rm_rf(tmp_path()) end)\n    :ok\n  end\n\n  describe \"rename\" do\n    # Following Erlang's underlying implementation\n    #\n    # Renaming files\n    # :ok               -> rename file to existing file default behavior\n    # {:error, :eisdir} -> rename file to existing empty dir\n    # {:error, :eisdir} -> rename file to existing non-empty dir\n    # :ok               -> rename file to non-existing location\n    # {:error, :eexist} -> rename file to existing file\n    # :ok               -> rename file to itself\n\n    # Renaming dirs\n    # {:error, :enotdir} -> rename dir to existing file\n    # :ok                -> rename dir to non-existing leaf location\n    # {:error, ??}       -> rename dir to non-existing parent location\n    # :ok                -> rename dir to itself\n    # :ok                -> rename dir to existing empty dir default behavior\n    # {:error, :eexist}  -> rename dir to existing empty dir\n    # {:error, :einval}  -> rename parent dir to existing sub dir\n    # {:error, :einval}  -> rename parent dir to non-existing sub dir\n    # {:error, :eexist}  -> rename dir to existing non-empty dir\n\n    # other tests\n    # {:error, :enoent} -> rename unknown source\n    # :ok               -> rename preserves mode\n    test \"rename file to existing file default behavior\" do\n      src = tmp_fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      File.write!(dest, \"hello\")\n\n      try do\n        assert File.exists?(dest)\n        assert File.rename(src, dest) == :ok\n        refute File.exists?(src)\n        assert File.read!(dest) == \"FOO\\n\"\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename file to existing empty dir\" do\n      src = tmp_fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp\")\n\n      try do\n        File.mkdir(dest)\n        assert File.rename(src, dest) == {:error, :eisdir}\n        assert File.exists?(src)\n        refute File.exists?(tmp_path(\"tmp/file.txt\"))\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename file to existing non-empty dir\" do\n      src = tmp_fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp\")\n\n      try do\n        File.mkdir_p(Path.join(dest, \"a\"))\n        assert File.rename(src, dest) in [{:error, :eisdir}, {:error, :eexist}]\n        assert File.exists?(src)\n        refute File.exists?(Path.join(dest, \"file.txt\"))\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename file to non-existing location\" do\n      src = tmp_fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.rename(src, dest) == :ok\n        assert File.exists?(dest)\n        refute File.exists?(src)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename file to existing file\" do\n      src = tmp_fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      File.write!(dest, \"hello\")\n\n      try do\n        assert File.exists?(dest)\n        assert File.rename(src, dest) == :ok\n        refute File.exists?(src)\n        assert File.read!(dest) == \"FOO\\n\"\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename file to itself\" do\n      src = tmp_fixture_path(\"file.txt\")\n      dest = src\n\n      try do\n        assert File.exists?(src)\n        assert File.rename(src, dest) == :ok\n        assert File.exists?(src)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename! file to existing file default behavior\" do\n      src = tmp_fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      File.write!(dest, \"hello\")\n\n      try do\n        assert File.exists?(dest)\n        assert File.rename!(src, dest) == :ok\n        refute File.exists?(src)\n        assert File.read!(dest) == \"FOO\\n\"\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename! with invalid file\" do\n      src = tmp_fixture_path(\"invalid.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      message =\n        \"could not rename from #{inspect(src)} to #{inspect(dest)}: no such file or directory\"\n\n      assert_raise File.RenameError, message, fn ->\n        File.rename!(src, dest)\n      end\n    end\n\n    test \"rename dir to existing file\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp.file\")\n\n      try do\n        File.touch(dest)\n        assert File.rename(src, dest) == {:error, :enotdir}\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename dir to non-existing leaf location\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      try do\n        refute File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        refute File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        refute File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n        assert File.rename(src, dest) == :ok\n        {:ok, files} = File.ls(dest)\n        assert length(files) == 2\n        assert \"a\" in files\n\n        {:ok, files} = File.ls(tmp_path(\"tmp/a\"))\n        assert length(files) == 2\n        assert \"1.txt\" in files\n\n        assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n        refute File.exists?(src)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename dir to non-existing parent location\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp/a/b\")\n\n      try do\n        assert File.rename(src, dest) == {:error, :enoent}\n        assert File.exists?(src)\n        refute File.exists?(dest)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename dir to itself\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = src\n\n      try do\n        assert File.exists?(src)\n        assert File.rename(src, dest) == :ok\n        assert File.exists?(src)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename parent dir to existing sub dir\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = tmp_path(\"cp_r/a\")\n\n      try do\n        assert File.exists?(src)\n        assert File.rename(src, dest) in [{:error, :einval}, {:error, :eexist}]\n        assert File.exists?(src)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename parent dir to non-existing sub dir\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = tmp_path(\"cp_r/x\")\n\n      try do\n        assert File.exists?(src)\n        assert File.rename(src, dest) == {:error, :einval}\n        assert File.exists?(src)\n        refute File.exists?(dest)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename dir to existing empty dir default behavior\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir(dest)\n\n      try do\n        refute File.exists?(tmp_path(\"tmp/a\"))\n\n        assert File.rename(src, dest) == :ok\n        {:ok, files} = File.ls(dest)\n        assert length(files) == 2\n        assert \"a\" in files\n\n        {:ok, files} = File.ls(tmp_path(\"tmp/a\"))\n        assert length(files) == 2\n        assert \"1.txt\" in files\n\n        assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n        refute File.exists?(src)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename dir to existing empty dir\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir(dest)\n\n      try do\n        assert File.exists?(dest)\n        assert File.rename(src, dest) == :ok\n        refute File.exists?(src)\n        assert File.exists?(tmp_path(\"tmp/a\"))\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename dir to existing non-empty dir\" do\n      src = tmp_fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir_p(tmp_path(\"tmp/x\"))\n\n      try do\n        assert File.exists?(tmp_path(\"tmp/x\"))\n        assert File.exists?(src)\n        refute File.exists?(tmp_path(\"tmp/a\"))\n\n        assert File.rename(src, dest) == {:error, :eexist}\n\n        assert File.exists?(tmp_path(\"tmp/x\"))\n        assert File.exists?(src)\n        refute File.exists?(tmp_path(\"tmp/a\"))\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename unknown source\" do\n      src = fixture_path(\"unknown\")\n      dest = tmp_path(\"tmp\")\n\n      try do\n        assert File.rename(src, dest) == {:error, :enoent}\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"rename preserves mode\" do\n      File.mkdir_p!(tmp_path(\"tmp\"))\n      src = tmp_fixture_path(\"cp_mode\")\n      dest = tmp_path(\"tmp/cp_mode\")\n\n      try do\n        %File.Stat{mode: src_mode} = File.stat!(src)\n        File.rename(src, dest)\n        %File.Stat{mode: dest_mode} = File.stat!(dest)\n        assert src_mode == dest_mode\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    def tmp_fixture_path(extra) do\n      src = fixture_path(extra)\n      dest = tmp_path(extra)\n      File.cp_r(src, dest)\n      dest\n    end\n  end\n\n  describe \"cp\" do\n    test \"cp with src file and dest file\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"sample.txt\")\n\n      File.touch(dest)\n\n      try do\n        assert File.exists?(dest)\n        assert File.cp(src, dest) == :ok\n        assert File.exists?(dest)\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"cp with src file and dest dir\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir(dest)\n\n      try do\n        assert File.cp(src, dest) == {:error, :eisdir}\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp with src file and dest unknown\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.cp(src, dest) == :ok\n        assert File.exists?(dest)\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp with src dir\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp.file\")\n      assert File.cp(src, dest) == {:error, :eisdir}\n    end\n\n    test \"cp with conflict\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      File.write!(dest, \"hello\")\n\n      try do\n        assert File.exists?(dest)\n        assert File.cp(src, dest) == :ok\n        assert File.read!(dest) == \"FOO\\n\"\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp with conflict with function\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      File.write!(dest, \"hello\")\n\n      try do\n        assert File.exists?(dest)\n\n        assert File.cp(src, dest,\n                 on_conflict: fn src_file, dest_file ->\n                   assert src_file == src\n                   assert dest_file == dest\n                   false\n                 end\n               ) == :ok\n\n        assert File.read!(dest) == \"hello\"\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp! with src file and dest file\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"sample.txt\")\n\n      File.touch(dest)\n\n      try do\n        assert File.exists?(dest)\n        assert File.cp!(src, dest) == :ok\n        assert File.exists?(dest)\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"cp! with src dir\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp.file\")\n\n      message =\n        \"could not copy from #{inspect(src)} to #{inspect(dest)}: illegal operation on a directory\"\n\n      assert_raise File.CopyError, message, fn ->\n        File.cp!(src, dest)\n      end\n    end\n\n    test \"cp itself\" do\n      src = dest = tmp_path(\"tmp.file\")\n\n      File.write!(src, \"here\")\n\n      try do\n        assert File.cp(src, dest) == :ok\n        assert File.read!(dest) == \"here\"\n        assert File.cp_r(src, dest) == {:ok, []}\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"cp_r raises on path with null byte\" do\n      assert_raise ArgumentError, ~r/null byte/, fn -> File.cp_r(\"source\", \"foo\\0bar\") end\n      assert_raise ArgumentError, ~r/null byte/, fn -> File.cp_r(\"foo\\0bar\", \"dest\") end\n    end\n\n    test \"cp_r with src file and dest file\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"sample.txt\")\n\n      File.touch(dest)\n\n      try do\n        assert File.exists?(dest)\n        assert File.cp_r(src, dest) == {:ok, [dest]}\n        assert File.exists?(dest)\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"cp_r with src file and dest dir\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir(dest)\n\n      try do\n        assert io_error?(File.cp_r(src, dest))\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with src file and dest unknown\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp.file\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.cp_r(src, dest) == {:ok, [dest]}\n        assert File.exists?(dest)\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with src dir and dest dir\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir(dest)\n\n      try do\n        refute File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        refute File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        refute File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n        {:ok, files} = File.cp_r(src, dest)\n        assert length(files) == 7\n        assert tmp_path(\"tmp/a\") in files\n        assert tmp_path(\"tmp/a/1.txt\") in files\n\n        assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with src dir and dest file\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp.file\")\n\n      try do\n        File.touch!(dest)\n        assert File.cp_r(src, dest) |> io_error?()\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with src dir and dest unknown\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      try do\n        refute File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        refute File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        refute File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n        {:ok, files} = File.cp_r(src, dest)\n        assert length(files) == 7\n\n        assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with src unknown\" do\n      src = fixture_path(\"unknown\")\n      dest = tmp_path(\"tmp\")\n      assert File.cp_r(src, dest) == {:error, :enoent, src}\n    end\n\n    test \"cp_r with absolute symlink\" do\n      linked_src = fixture_path(\"cp_r\")\n      src = tmp_path(\"tmp/src\")\n      dest = tmp_path(\"tmp/dest\")\n\n      File.mkdir_p!(src)\n      :ok = :file.make_symlink(Path.join(linked_src, \"a\"), Path.join(src, \"sym\"))\n\n      try do\n        {:ok, files} = File.cp_r(src, dest)\n        assert length(files) == 2\n\n        assert File.exists?(tmp_path(\"tmp/dest/sym/1.txt\"))\n        assert File.exists?(tmp_path(\"tmp/dest/sym/a/2.txt\"))\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with dereference absolute symlink\" do\n      linked_src = fixture_path(\"cp_r\")\n      src = tmp_path(\"tmp/src\")\n      dest = tmp_path(\"tmp/dest\")\n\n      File.mkdir_p!(src)\n      :ok = :file.make_symlink(Path.join(linked_src, \"a\"), Path.join(src, \"sym\"))\n\n      try do\n        {:ok, files} = File.cp_r(src, dest, dereference_symlinks: true)\n        assert length(files) == 5\n\n        assert File.exists?(tmp_path(\"tmp/dest/sym/1.txt\"))\n        assert File.exists?(tmp_path(\"tmp/dest/sym/a/2.txt\"))\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    @tag :unix\n    test \"cp_r with relative symlink\" do\n      doc = tmp_path(\"tmp/doc\")\n      src = tmp_path(\"tmp/src\")\n      dest = tmp_path(\"tmp/dest\")\n\n      File.mkdir_p!(src)\n      File.write!(doc, \"hello\")\n      :ok = :file.make_symlink(\"../doc\", Path.join(src, \"sym\"))\n\n      try do\n        {:ok, files} = File.cp_r(src, dest)\n        assert length(files) == 2\n        assert File.lstat!(tmp_path(\"tmp/dest/sym\")).type == :symlink\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    @tag :unix\n    test \"cp_r with dereference relative symlink\" do\n      doc = tmp_path(\"tmp/doc\")\n      src = tmp_path(\"tmp/src\")\n      dest = tmp_path(\"tmp/dest\")\n\n      File.mkdir_p!(src)\n      File.write!(doc, \"hello\")\n      :ok = :file.make_symlink(\"../doc\", Path.join(src, \"sym\"))\n\n      try do\n        {:ok, files} = File.cp_r(src, dest, dereference_symlinks: true)\n        assert length(files) == 2\n        assert File.lstat!(tmp_path(\"tmp/dest/sym\")).type == :regular\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    @tag :unix\n    test \"cp_r with dereference symlink cycle returns eloop error\" do\n      src = tmp_path(\"tmp/src\")\n      dest = tmp_path(\"tmp/dest\")\n\n      File.mkdir_p!(src)\n      :ok = :file.make_symlink(Path.join(src, \"b\"), Path.join(src, \"a\"))\n      :ok = :file.make_symlink(Path.join(src, \"a\"), Path.join(src, \"b\"))\n\n      try do\n        assert {:error, :eloop, _} = File.cp_r(src, dest, dereference_symlinks: true)\n      after\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with dir and file conflict\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      try do\n        File.mkdir(dest)\n        File.write!(Path.join(dest, \"a\"), \"hello\")\n        assert io_error?(File.cp_r(src, dest))\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with src dir and dest dir using lists\" do\n      src = fixture_path(\"cp_r\") |> to_charlist()\n      dest = tmp_path(\"tmp\") |> to_charlist()\n\n      File.mkdir(dest)\n\n      try do\n        refute File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        refute File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        refute File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n        {:ok, files} = File.cp_r(src, dest)\n        assert length(files) == 7\n        assert Enum.all?(files, &is_binary/1)\n\n        assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with src with file conflict\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir_p(tmp_path(\"tmp/a\"))\n      File.write!(tmp_path(\"tmp/a/1.txt\"), \"hello\")\n\n      try do\n        assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        File.cp_r(src, dest)\n        assert File.read!(tmp_path(\"tmp/a/1.txt\")) == \"\"\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r with src with file conflict callback\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir_p(tmp_path(\"tmp/a\"))\n      File.write!(tmp_path(\"tmp/a/1.txt\"), \"hello\")\n\n      try do\n        assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n\n        File.cp_r(src, dest,\n          on_conflict: fn src_file, dest_file ->\n            assert src_file == fixture_path(\"cp_r/a/1.txt\")\n            assert dest_file == tmp_path(\"tmp/a/1.txt\")\n            false\n          end\n        )\n\n        assert File.read!(tmp_path(\"tmp/a/1.txt\")) == \"hello\"\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r!\" do\n      src = fixture_path(\"cp_r\")\n      dest = tmp_path(\"tmp\")\n\n      File.mkdir(dest)\n\n      try do\n        refute File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        refute File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        refute File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n        assert length(File.cp_r!(src, dest)) == 7\n\n        assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n        assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n        assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n      after\n        File.rm_rf(dest)\n      end\n    end\n\n    test \"cp_r! with src unknown\" do\n      src = fixture_path(\"unknown\")\n      dest = tmp_path(\"tmp\")\n\n      message =\n        \"could not copy recursively from #{inspect(src)} to #{inspect(dest)}. #{src}: no such file or directory\"\n\n      assert_raise File.CopyError, message, fn ->\n        File.cp_r!(src, dest)\n      end\n    end\n\n    test \"cp_r! with file src and dest unknown\" do\n      src = fixture_path(\"cp_r/a/1.txt\")\n      dest = tmp_path(\"tmp/unknown/\")\n\n      message =\n        \"could not copy recursively from #{inspect(src)} to #{inspect(dest)}. #{dest}: no such file or directory\"\n\n      assert_raise File.CopyError, message, fn ->\n        File.cp_r!(src, dest)\n      end\n    end\n\n    test \"cp_r with destination inside source returns error\" do\n      src = tmp_path(\"tmp/src\")\n      dest = tmp_path(\"tmp/src/subdir/dest\")\n\n      File.mkdir_p!(src)\n      File.write!(Path.join(src, \"file.txt\"), \"hello\")\n\n      try do\n        assert File.cp_r(src, dest) == {:error, :einval, dest}\n        refute File.exists?(dest)\n      after\n        File.rm_rf(src)\n      end\n    end\n\n    test \"cp_r! with destination inside source raises\" do\n      src = tmp_path(\"tmp/src\")\n      dest = tmp_path(\"tmp/src/subdir/dest\")\n\n      File.mkdir_p!(src)\n      File.write!(Path.join(src, \"file.txt\"), \"hello\")\n\n      try do\n        message =\n          \"could not copy recursively from #{inspect(src)} to #{inspect(dest)}. #{dest}: invalid argument\"\n\n        assert_raise File.CopyError, message, fn ->\n          File.cp_r!(src, dest)\n        end\n\n        refute File.exists?(dest)\n      after\n        File.rm_rf(src)\n      end\n    end\n\n    test \"cp preserves mode\" do\n      File.mkdir_p!(tmp_path(\"tmp\"))\n      src = fixture_path(\"cp_mode\")\n      dest = tmp_path(\"tmp/cp_mode\")\n\n      File.cp!(src, dest)\n      %File.Stat{mode: src_mode} = File.stat!(src)\n      %File.Stat{mode: dest_mode} = File.stat!(dest)\n      assert src_mode == dest_mode\n\n      # On overwrite\n      File.cp!(src, dest, on_conflict: fn _, _ -> true end)\n      %File.Stat{mode: src_mode} = File.stat!(src)\n      %File.Stat{mode: dest_mode} = File.stat!(dest)\n      assert src_mode == dest_mode\n    end\n\n    test \"cp_r preserves directory mode\" do\n      src = tmp_path(\"tmp/src_dir\")\n      dest = tmp_path(\"tmp/dest_dir\")\n      inner = Path.join(src, \"inner\")\n\n      File.mkdir_p!(inner)\n      File.chmod!(inner, 0o700)\n\n      try do\n        File.cp_r!(src, dest)\n\n        %File.Stat{mode: src_mode} = File.stat!(inner)\n        %File.Stat{mode: dest_mode} = File.stat!(Path.join(dest, \"inner\"))\n        assert src_mode == dest_mode\n      after\n        File.rm_rf!(src)\n        File.rm_rf!(dest)\n      end\n    end\n\n    @tag :unix\n    test \"cp_r skips sockets and other special files\" do\n      # We use tmpdir because macOS has a limit on socket paths\n      src = Path.join(System.tmp_dir(), \"src_with_socket\")\n      dest = tmp_path(\"dest_with_socket\")\n      socket_path = Path.join(src, \"test.sock\")\n      regular_path = Path.join(src, \"regular.txt\")\n\n      File.mkdir_p!(src)\n      File.write!(regular_path, \"content\")\n\n      {:ok, socket} = :gen_tcp.listen(0, [:local, {:ifaddr, {:local, socket_path}}])\n\n      try do\n        assert File.exists?(socket_path)\n        assert :elixir_utils.read_link_type(socket_path) == {:ok, :other}\n\n        {:ok, copied_files} = File.cp_r(src, dest)\n        assert Path.join(dest, \"regular.txt\") in copied_files\n\n        refute File.exists?(Path.join(dest, \"test.sock\"))\n        refute Path.join(dest, \"test.sock\") in copied_files\n      after\n        :gen_tcp.close(socket)\n        File.rm_rf(src)\n        File.rm_rf(dest)\n      end\n    end\n  end\n\n  defmodule Queries do\n    use ExUnit.Case\n\n    test \"regular\" do\n      assert File.regular?(__ENV__.file)\n      assert File.regular?(String.to_charlist(__ENV__.file))\n      refute File.regular?(\"#{__ENV__.file}.unknown\")\n    end\n\n    test \"exists\" do\n      assert File.exists?(__ENV__.file)\n      assert File.exists?(fixture_path())\n      assert File.exists?(fixture_path(\"file.txt\"))\n\n      refute File.exists?(fixture_path(\"missing.txt\"))\n      refute File.exists?(\"_missing.txt\")\n    end\n\n    test \"exists with dangling symlink\" do\n      invalid_file = tmp_path(\"invalid_file\")\n      dest = tmp_path(\"dangling_symlink\")\n      File.ln_s(invalid_file, dest)\n\n      try do\n        refute File.exists?(dest)\n      after\n        File.rm(dest)\n      end\n    end\n  end\n\n  test \"ls\" do\n    {:ok, value} = File.ls(fixture_path())\n    assert \"code_sample.exs\" in value\n    assert \"file.txt\" in value\n\n    {:error, :enoent} = File.ls(fixture_path(\"non-existent-subdirectory\"))\n  end\n\n  test \"ls!\" do\n    value = File.ls!(fixture_path())\n    assert \"code_sample.exs\" in value\n    assert \"file.txt\" in value\n\n    assert_raise File.Error, fn ->\n      File.ls!(fixture_path(\"non-existent-subdirectory\"))\n    end\n  end\n\n  describe \"open-read-write\" do\n    test \"read with binary\" do\n      assert {:ok, \"FOO\\n\"} = File.read(fixture_path(\"file.txt\"))\n      assert {:error, :enoent} = File.read(fixture_path(\"missing.txt\"))\n    end\n\n    test \"read with list\" do\n      assert {:ok, \"FOO\\n\"} = File.read(Path.expand(~c\"fixtures/file.txt\", __DIR__))\n      assert {:error, :enoent} = File.read(Path.expand(~c\"fixtures/missing.txt\", __DIR__))\n    end\n\n    test \"read with UTF-8\" do\n      assert {:ok, \"Русский\\n日\\n\"} = File.read(Path.expand(~c\"fixtures/utf8.txt\", __DIR__))\n    end\n\n    test \"read with :raw options\" do\n      assert {:ok, \"FOO\\n\"} = File.read(fixture_path(\"file.txt\"), [:raw])\n    end\n\n    test \"read!\" do\n      assert File.read!(fixture_path(\"file.txt\")) == \"FOO\\n\"\n      expected_message = \"could not read file \\\"fixtures/missing.txt\\\": no such file or directory\"\n\n      assert_raise File.Error, expected_message, fn ->\n        File.read!(\"fixtures/missing.txt\")\n      end\n    end\n\n    test \"write ASCII content\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(fixture)\n        assert File.write(fixture, ~c\"test text\") == :ok\n        assert File.read(fixture) == {:ok, \"test text\"}\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"write UTF-8\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(fixture)\n        assert File.write(fixture, \"Русский\\n日\\n\") == :ok\n        assert {:ok, \"Русский\\n日\\n\"} == File.read(fixture)\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"write with options\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(fixture)\n        assert File.write(fixture, \"Русский\\n日\\n\") == :ok\n        assert File.write(fixture, \"test text\", [:append]) == :ok\n        assert {:ok, \"Русский\\n日\\ntest text\"} == File.read(fixture)\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"open file without modes\" do\n      {:ok, file} = File.open(fixture_path(\"file.txt\"))\n      assert IO.gets(file, \"\") == \"FOO\\n\"\n      assert File.close(file) == :ok\n    end\n\n    test \"open file with charlist\" do\n      {:ok, file} = File.open(fixture_path(\"file.txt\"), [:charlist])\n      assert IO.gets(file, \"\") == ~c\"FOO\\n\"\n      assert File.close(file) == :ok\n    end\n\n    test \"open UTF-8 by default\" do\n      {:ok, file} = File.open(fixture_path(\"utf8.txt\"), [:utf8])\n      assert IO.gets(file, \"\") == \"Русский\\n\"\n      assert File.close(file) == :ok\n    end\n\n    test \"open readonly by default\" do\n      {:ok, file} = File.open(fixture_path(\"file.txt\"))\n      assert_raise ArgumentError, fn -> IO.write(file, \"foo\") end\n      assert File.close(file) == :ok\n    end\n\n    test \"open with write permission\" do\n      fixture = tmp_path(\"tmp_text.txt\")\n\n      try do\n        {:ok, file} = File.open(fixture, [:write])\n        assert IO.write(file, \"foo\") == :ok\n        assert File.close(file) == :ok\n        assert File.read(fixture) == {:ok, \"foo\"}\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"open with binwrite permission\" do\n      fixture = tmp_path(\"tmp_text.txt\")\n\n      try do\n        {:ok, file} = File.open(fixture, [:write])\n        assert IO.binwrite(file, \"Русский\") == :ok\n        assert File.close(file) == :ok\n        assert_raise ErlangError, fn -> IO.binwrite(file, \"Русский\") end\n        assert File.read(fixture) == {:ok, \"Русский\"}\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"open UTF-8 and charlist\" do\n      {:ok, file} = File.open(fixture_path(\"utf8.txt\"), [:charlist, :utf8])\n      assert IO.gets(file, \"\") == [1056, 1091, 1089, 1089, 1082, 1080, 1081, 10]\n      assert File.close(file) == :ok\n    end\n\n    test \"open respects encoding\" do\n      {:ok, file} = File.open(fixture_path(\"utf8.txt\"), [{:encoding, :latin1}])\n\n      data =\n        <<195, 144, 194, 160, 195, 145, 194, 131, 195, 145, 194, 129, 195, 145>> <>\n          <<194, 129, 195, 144, 194, 186, 195, 144, 194, 184, 195, 144, 194, 185, 10>>\n\n      assert IO.gets(file, \"\") == data\n      assert File.close(file) == :ok\n    end\n\n    test \"open a missing file\" do\n      assert File.open(~c\"missing.txt\") == {:error, :enoent}\n    end\n\n    test \"open a file with function\" do\n      file = fixture_path(\"file.txt\")\n      assert File.open(file, &IO.read(&1, :line)) == {:ok, \"FOO\\n\"}\n    end\n\n    test \"open! a missing file\" do\n      message = \"could not open \\\"missing.txt\\\": no such file or directory\"\n\n      assert_raise File.Error, message, fn ->\n        File.open!(~c\"missing.txt\")\n      end\n    end\n\n    test \"open! a file with function\" do\n      file = fixture_path(\"file.txt\")\n      assert File.open!(file, &IO.read(&1, :line)) == \"FOO\\n\"\n    end\n  end\n\n  describe \"mkdir\" do\n    test \"mkdir with binary\" do\n      fixture = tmp_path(\"tmp_test\")\n\n      try do\n        refute File.exists?(fixture)\n        assert File.mkdir(fixture) == :ok\n        assert File.exists?(fixture)\n      after\n        File.rmdir(fixture)\n      end\n    end\n\n    test \"mkdir with list\" do\n      fixture = tmp_path(\"tmp_test\") |> to_charlist()\n\n      try do\n        refute File.exists?(fixture)\n        assert File.mkdir(fixture) == :ok\n        assert File.exists?(fixture)\n      after\n        File.rmdir(fixture)\n      end\n    end\n\n    test \"mkdir with invalid path\" do\n      fixture = fixture_path(\"file.txt\")\n      invalid = Path.join(fixture, \"test\")\n      assert File.exists?(fixture)\n      assert io_error?(File.mkdir(invalid))\n      refute File.exists?(invalid)\n    end\n\n    test \"mkdir!\" do\n      fixture = tmp_path(\"tmp_test\")\n\n      try do\n        refute File.exists?(fixture)\n        assert File.mkdir!(fixture) == :ok\n        assert File.exists?(fixture)\n      after\n        File.rmdir(fixture)\n      end\n    end\n\n    test \"mkdir! with invalid path\" do\n      fixture = fixture_path(\"file.txt\")\n      invalid = Path.join(fixture, \"test\")\n      assert File.exists?(fixture)\n\n      message =\n        ~r\"\\Acould not make directory #{inspect(invalid)}: (not a directory|no such file or directory)\"\n\n      assert_raise File.Error, message, fn ->\n        File.mkdir!(invalid)\n      end\n    end\n\n    test \"mkdir_p with one directory\" do\n      fixture = tmp_path(\"tmp_test\")\n\n      try do\n        refute File.exists?(fixture)\n        assert File.mkdir_p(fixture) == :ok\n        assert File.exists?(fixture)\n      after\n        File.rm_rf(fixture)\n      end\n    end\n\n    test \"mkdir_p with nested directory and binary\" do\n      base = tmp_path(\"tmp_test\")\n      fixture = Path.join(base, \"test\")\n      refute File.exists?(base)\n\n      try do\n        assert File.mkdir_p(fixture) == :ok\n        assert File.exists?(base)\n        assert File.exists?(fixture)\n      after\n        File.rm_rf(base)\n      end\n    end\n\n    test \"mkdir_p with nested directory and list\" do\n      base = tmp_path(\"tmp_test\") |> to_charlist()\n      fixture = Path.join(base, \"test\")\n      refute File.exists?(base)\n\n      try do\n        assert File.mkdir_p(fixture) == :ok\n        assert File.exists?(base)\n        assert File.exists?(fixture)\n      after\n        File.rm_rf(base)\n      end\n    end\n\n    test \"mkdir_p with nested directory and existing parent\" do\n      base = tmp_path(\"tmp_test\")\n      fixture = Path.join(base, \"test\")\n\n      File.mkdir(base)\n\n      try do\n        assert File.mkdir_p(fixture) == :ok\n        assert File.exists?(base)\n        assert File.exists?(fixture)\n      after\n        File.rm_rf(base)\n      end\n    end\n\n    test \"mkdir_p with invalid path\" do\n      assert File.exists?(fixture_path(\"file.txt\"))\n      invalid = Path.join(fixture_path(\"file.txt\"), \"test/foo\")\n      assert io_error?(File.mkdir(invalid))\n      refute File.exists?(invalid)\n    end\n\n    test \"mkdir_p!\" do\n      fixture = tmp_path(\"tmp_test\")\n\n      try do\n        refute File.exists?(fixture)\n        assert File.mkdir_p!(fixture) == :ok\n        assert File.exists?(fixture)\n      after\n        File.rm_rf(fixture)\n      end\n    end\n\n    test \"mkdir_p! with invalid path\" do\n      fixture = fixture_path(\"file.txt\")\n      invalid = Path.join(fixture, \"test\")\n      assert File.exists?(fixture)\n\n      message =\n        ~r\"\\Acould not make directory \\(with -p\\) #{inspect(invalid)}: (not a directory|no such file or directory)\"\n\n      assert_raise File.Error, message, fn ->\n        File.mkdir_p!(invalid)\n      end\n    end\n\n    @tag :unix\n    test \"mkdir_p with non-accessible parent directory\" do\n      fixture = tmp_path(\"tmp_test_parent\")\n\n      try do\n        refute File.exists?(fixture)\n        assert File.mkdir_p!(fixture) == :ok\n        %File.Stat{mode: orig_mode} = File.stat!(fixture)\n        assert File.chmod!(fixture, 0o000) == :ok\n\n        child = Path.join(fixture, \"child\")\n        refute File.exists?(child)\n\n        assert File.mkdir_p(child) == {:error, :eacces}\n        refute File.exists?(child)\n\n        assert File.chmod!(fixture, orig_mode) == :ok\n      after\n        File.rm_rf(fixture)\n      end\n    end\n  end\n\n  describe \"rm\" do\n    test \"rm file\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.write(fixture, \"test\")\n      assert File.exists?(fixture)\n      assert File.rm(fixture) == :ok\n      refute File.exists?(fixture)\n    end\n\n    test \"rm read only file\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.write(fixture, \"test\")\n      assert File.exists?(fixture)\n      File.chmod(fixture, 0o100444)\n      assert File.rm(fixture) == :ok\n      refute File.exists?(fixture)\n    end\n\n    test \"rm file with dir\" do\n      assert File.rm(fixture_path()) == {:error, :eperm}\n    end\n\n    test \"rm nonexistent file\" do\n      assert File.rm(~c\"missing.txt\") == {:error, :enoent}\n    end\n\n    test \"rm!\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.write(fixture, \"test\")\n      assert File.exists?(fixture)\n      assert File.rm!(fixture) == :ok\n      refute File.exists?(fixture)\n    end\n\n    test \"rm! with invalid file\" do\n      message = \"could not remove file \\\"missing.file\\\": no such file or directory\"\n\n      assert_raise File.Error, message, fn ->\n        File.rm!(\"missing.file\")\n      end\n    end\n\n    test \"rmdir\" do\n      fixture = tmp_path(\"tmp_test\")\n      File.mkdir_p(fixture)\n      assert File.dir?(fixture)\n      assert File.rmdir(fixture) == :ok\n      refute File.exists?(fixture)\n    end\n\n    test \"rmdir with file\" do\n      assert io_error?(File.rmdir(fixture_path(\"file.txt\")))\n    end\n\n    test \"rmdir!\" do\n      fixture = tmp_path(\"tmp_test\")\n      File.mkdir_p(fixture)\n      assert File.dir?(fixture)\n      assert File.rmdir!(fixture) == :ok\n      refute File.exists?(fixture)\n    end\n\n    test \"rmdir! with file\" do\n      fixture = fixture_path(\"file.txt\")\n      message = ~r\"\\Acould not remove directory #{inspect(fixture)}: (not a directory|I/O error)\"\n\n      assert_raise File.Error, message, fn ->\n        File.rmdir!(fixture)\n      end\n    end\n\n    test \"rmdir! error messages\" do\n      fixture = tmp_path(\"tmp_test\")\n      File.mkdir_p(fixture)\n      File.touch(fixture <> \"/file\")\n\n      # directory is not empty\n      dir_not_empty_message =\n        \"could not remove directory #{inspect(fixture)}: directory is not empty\"\n\n      assert_raise File.Error, dir_not_empty_message, fn ->\n        File.rmdir!(fixture)\n      end\n\n      # directory does not exist\n      non_existent_dir = fixture <> \"/non_existent_dir\"\n\n      non_existent_dir_message =\n        ~r\"\\Acould not remove directory #{inspect(non_existent_dir)}: (not a directory|no such file or directory)\"\n\n      assert_raise File.Error, non_existent_dir_message, fn ->\n        File.rmdir!(non_existent_dir)\n      end\n\n      File.rm_rf(fixture)\n    end\n\n    test \"rm_rf\" do\n      fixture = tmp_path(\"tmp\")\n      File.mkdir(fixture)\n      File.cp_r!(fixture_path(\"cp_r\"), fixture)\n\n      assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n      assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n      assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n      {:ok, files} = File.rm_rf(fixture)\n      assert length(files) == 7\n      assert fixture in files\n      assert tmp_path(\"tmp/a/1.txt\") in files\n\n      refute File.exists?(tmp_path(\"tmp/a/1.txt\"))\n      refute File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n      refute File.exists?(tmp_path(\"tmp/b/3.txt\"))\n      refute File.exists?(fixture)\n    end\n\n    test \"rm_rf raises on path with null byte\" do\n      assert_raise ArgumentError, ~r/null byte/, fn -> File.rm_rf(\"foo\\0bar\") end\n    end\n\n    test \"rm_rf with symlink\" do\n      from = tmp_path(\"tmp/from\")\n      to = tmp_path(\"tmp/to\")\n\n      File.mkdir_p!(to)\n      File.write!(Path.join(to, \"hello\"), \"world\")\n      :file.make_symlink(to, from)\n\n      if File.exists?(from) or not windows?() do\n        assert File.exists?(from)\n\n        {:ok, files} = File.rm_rf(from)\n        assert length(files) == 1\n\n        assert File.exists?(Path.join(to, \"hello\"))\n        refute File.exists?(from)\n      end\n    after\n      File.rm(tmp_path(\"tmp/from\"))\n    end\n\n    test \"rm_rf with charlist\" do\n      fixture = tmp_path(\"tmp\") |> to_charlist()\n      File.mkdir(fixture)\n      File.cp_r!(fixture_path(\"cp_r\"), fixture)\n\n      assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n      assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n      assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n      {:ok, files} = File.rm_rf(fixture)\n      assert length(files) == 7\n      assert tmp_path(\"tmp\") in files\n      assert Enum.all?(files, &is_binary/1)\n\n      refute File.exists?(tmp_path(\"tmp/a/1.txt\"))\n      refute File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n      refute File.exists?(tmp_path(\"tmp/b/3.txt\"))\n      refute File.exists?(fixture)\n    end\n\n    test \"rm_rf with file\" do\n      fixture = tmp_path(\"tmp\")\n      File.write(fixture, \"hello\")\n      assert File.rm_rf(fixture) == {:ok, [fixture]}\n    end\n\n    test \"rm_rf with write-only subdir\" do\n      dir = tmp_path(\"tmp\")\n      subdir = Path.join(dir, \"write-only\")\n      File.mkdir_p!(subdir)\n      File.chmod!(subdir, 0o222)\n      assert File.rm_rf(dir) == {:ok, [dir, subdir]}\n    end\n\n    test \"rm_rf with unknown\" do\n      fixture = tmp_path(\"tmp.unknown\")\n      assert File.rm_rf(fixture) == {:ok, []}\n    end\n\n    test \"rm_rf with invalid\" do\n      fixture = fixture_path(\"file.txt/path\")\n      assert File.rm_rf(fixture) == {:ok, []}\n    end\n\n    test \"rm_rf!\" do\n      fixture = tmp_path(\"tmp\")\n      File.mkdir(fixture)\n      File.cp_r!(fixture_path(\"cp_r\"), fixture)\n\n      assert File.exists?(tmp_path(\"tmp/a/1.txt\"))\n      assert File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n      assert File.exists?(tmp_path(\"tmp/b/3.txt\"))\n\n      files = File.rm_rf!(fixture)\n      assert length(files) == 7\n      assert fixture in files\n      assert tmp_path(\"tmp/a/1.txt\") in files\n\n      refute File.exists?(tmp_path(\"tmp/a/1.txt\"))\n      refute File.exists?(tmp_path(\"tmp/a/a/2.txt\"))\n      refute File.exists?(tmp_path(\"tmp/b/3.txt\"))\n      refute File.exists?(fixture)\n    end\n\n    test \"rm_rf! with invalid path\" do\n      fixture = fixture_path(\"file.txt/path\")\n      assert File.rm_rf!(fixture) == []\n    end\n  end\n\n  describe \"stat\" do\n    test \"stat\" do\n      {:ok, info} = File.stat(__ENV__.file)\n      assert info.mtime\n    end\n\n    test \"stat!\" do\n      assert File.stat!(__ENV__.file).mtime\n    end\n\n    test \"stat with invalid file\" do\n      assert {:error, _} = File.stat(\"./invalid_file\")\n    end\n\n    test \"stat! with invalid_file\" do\n      assert_raise File.Error, fn ->\n        File.stat!(\"./invalid_file\")\n      end\n    end\n\n    test \"lstat\" do\n      {:ok, info} = File.lstat(__ENV__.file)\n      assert info.mtime\n    end\n\n    test \"lstat!\" do\n      assert File.lstat!(__ENV__.file).mtime\n    end\n\n    test \"lstat with invalid file\" do\n      invalid_file = tmp_path(\"invalid_file\")\n      assert {:error, _} = File.lstat(invalid_file)\n    end\n\n    test \"lstat! with invalid file\" do\n      invalid_file = tmp_path(\"invalid_file\")\n\n      assert_raise File.Error, fn ->\n        File.lstat!(invalid_file)\n      end\n    end\n\n    test \"lstat with dangling symlink\" do\n      invalid_file = tmp_path(\"invalid_file\")\n      dest = tmp_path(\"dangling_symlink\")\n      File.ln_s(invalid_file, dest)\n\n      try do\n        assert {:ok, info} = File.lstat(dest)\n        assert info.type == :symlink\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"lstat! with dangling symlink\" do\n      invalid_file = tmp_path(\"invalid_file\")\n      dest = tmp_path(\"dangling_symlink\")\n      File.ln_s(invalid_file, dest)\n\n      try do\n        assert File.lstat!(dest).type == :symlink\n      after\n        File.rm(dest)\n      end\n    end\n  end\n\n  describe \"IO stream\" do\n    test \"IO stream UTF-8\" do\n      src = File.open!(fixture_path(\"file.txt\"), [:utf8])\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        stream = IO.stream(src, :line)\n\n        File.open(dest, [:write], fn target ->\n          Enum.into(stream, IO.stream(target, :line), &String.replace(&1, \"O\", \"A\"))\n        end)\n\n        assert File.read(dest) == {:ok, \"FAA\\n\"}\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"IO stream\" do\n      src = File.open!(fixture_path(\"file.txt\"))\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        stream = IO.binstream(src, :line)\n\n        File.open(dest, [:write], fn target ->\n          Enum.into(stream, IO.binstream(target, :line), &String.replace(&1, \"O\", \"A\"))\n        end)\n\n        assert File.read(dest) == {:ok, \"FAA\\n\"}\n      after\n        File.rm(dest)\n      end\n    end\n  end\n\n  describe \"links\" do\n    test \"read_link with regular file\" do\n      dest = tmp_path(\"symlink\")\n      File.touch(dest)\n\n      try do\n        assert File.read_link(dest) == {:error, :einval}\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"read_link with nonexistent file\" do\n      dest = tmp_path(\"does_not_exist\")\n      assert File.read_link(dest) == {:error, :enoent}\n    end\n\n    test \"read_link! with nonexistent file\" do\n      dest = tmp_path(\"does_not_exist\")\n      assert_raise File.Error, fn -> File.read_link!(dest) end\n    end\n\n    @tag :unix\n    test \"read_link with symlink\" do\n      target = tmp_path(\"does_not_need_to_exist\")\n      dest = tmp_path(\"symlink\")\n      File.ln_s(target, dest)\n\n      try do\n        assert File.read_link(dest) == {:ok, target}\n      after\n        File.rm(dest)\n      end\n    end\n\n    @tag :unix\n    test \"read_link! with symlink\" do\n      target = tmp_path(\"does_not_need_to_exist\")\n      dest = tmp_path(\"symlink\")\n      File.ln_s(target, dest)\n\n      try do\n        assert File.read_link!(dest) == target\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"ln\" do\n      existing = fixture_path(\"file.txt\")\n      new = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(new)\n        assert File.ln(existing, new) == :ok\n        assert File.read(new) == {:ok, \"FOO\\n\"}\n      after\n        File.rm(new)\n      end\n    end\n\n    test \"ln with existing destination\" do\n      existing = fixture_path(\"file.txt\")\n      assert File.ln(existing, existing) == {:error, :eexist}\n    end\n\n    test \"ln! with existing destination\" do\n      assert_raise File.LinkError, fn ->\n        existing = fixture_path(\"file.txt\")\n        File.ln!(existing, existing)\n      end\n    end\n\n    test \"ln_s\" do\n      existing = fixture_path(\"file.txt\")\n      new = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(new)\n        assert File.ln_s(existing, new) == :ok\n        assert File.read(new) == {:ok, \"FOO\\n\"}\n      after\n        File.rm(new)\n      end\n    end\n\n    test \"ln_s with existing destination\" do\n      existing = fixture_path(\"file.txt\")\n      assert File.ln_s(existing, existing) == {:error, :eexist}\n    end\n\n    test \"ln_s! with existing destination\" do\n      existing = fixture_path(\"file.txt\")\n\n      assert_raise File.LinkError, fn ->\n        File.ln_s!(existing, existing)\n      end\n    end\n  end\n\n  describe \"copy\" do\n    test \"copy\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.copy(src, dest) == {:ok, 4}\n        assert File.read(dest) == {:ok, \"FOO\\n\"}\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"copy with an io_device\" do\n      {:ok, src} = File.open(fixture_path(\"file.txt\"))\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.copy(src, dest) == {:ok, 4}\n        assert File.read(dest) == {:ok, \"FOO\\n\"}\n      after\n        File.close(src)\n        File.rm(dest)\n      end\n    end\n\n    test \"copy with raw io_device\" do\n      {:ok, src} = File.open(fixture_path(\"file.txt\"), [:raw])\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.copy(src, dest) == {:ok, 4}\n        assert File.read(dest) == {:ok, \"FOO\\n\"}\n      after\n        File.close(src)\n        File.rm(dest)\n      end\n    end\n\n    test \"copy with ram io_device\" do\n      {:ok, src} = File.open(\"FOO\\n\", [:ram])\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.copy(src, dest) == {:ok, 4}\n        assert File.read(dest) == {:ok, \"FOO\\n\"}\n      after\n        File.close(src)\n        File.rm(dest)\n      end\n    end\n\n    test \"copy with bytes count\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.copy(src, dest, 2) == {:ok, 2}\n        assert {:ok, \"FO\"} == File.read(dest)\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"copy with invalid file\" do\n      src = fixture_path(\"invalid.txt\")\n      dest = tmp_path(\"tmp_test.txt\")\n      assert File.copy(src, dest, 2) == {:error, :enoent}\n    end\n\n    test \"copy!\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.copy!(src, dest) == 4\n        assert {:ok, \"FOO\\n\"} == File.read(dest)\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"copy! with bytes count\" do\n      src = fixture_path(\"file.txt\")\n      dest = tmp_path(\"tmp_test.txt\")\n\n      try do\n        refute File.exists?(dest)\n        assert File.copy!(src, dest, 2) == 2\n        assert {:ok, \"FO\"} == File.read(dest)\n      after\n        File.rm(dest)\n      end\n    end\n\n    test \"copy! with invalid file\" do\n      src = fixture_path(\"invalid.txt\")\n      dest = tmp_path(\"tmp_test.txt\")\n\n      message =\n        \"could not copy from #{inspect(src)} to #{inspect(dest)}: no such file or directory\"\n\n      assert_raise File.CopyError, message, fn ->\n        File.copy!(src, dest, 2)\n      end\n    end\n  end\n\n  describe \"cwd and cd\" do\n    test \"cwd and cd\" do\n      {:ok, current} = File.cwd()\n\n      try do\n        assert File.cd(fixture_path()) == :ok\n        assert File.exists?(\"file.txt\")\n      after\n        File.cd!(current)\n      end\n    end\n\n    if :file.native_name_encoding() == :utf8 do\n      test \"cwd and cd with UTF-8\" do\n        File.mkdir_p(tmp_path(\"héllò\"))\n\n        File.cd!(tmp_path(\"héllò\"), fn ->\n          assert Path.basename(File.cwd!()) == \"héllò\"\n        end)\n      after\n        File.rm_rf(tmp_path(\"héllò\"))\n      end\n    end\n\n    test \"invalid cd\" do\n      assert io_error?(File.cd(fixture_path(\"file.txt\")))\n    end\n\n    test \"invalid_cd!\" do\n      message =\n        ~r\"\\Acould not set current working directory to #{inspect(fixture_path(\"file.txt\"))}: (not a directory|no such file or directory|I/O error)\"\n\n      assert_raise File.Error, message, fn ->\n        File.cd!(fixture_path(\"file.txt\"))\n      end\n    end\n\n    test \"cd with function\" do\n      assert File.cd!(fixture_path(), fn ->\n               assert File.exists?(\"file.txt\")\n               :cd_result\n             end) == :cd_result\n    end\n  end\n\n  describe \"touch\" do\n    test \"touch with no file\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      time = {{2010, 4, 17}, {14, 0, 0}}\n\n      try do\n        refute File.exists?(fixture)\n        assert File.touch(fixture, time) == :ok\n        assert {:ok, \"\"} == File.read(fixture)\n        assert File.stat!(fixture).mtime == time\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"touch with Erlang timestamp\" do\n      fixture = tmp_path(\"tmp_erlang_touch.txt\")\n\n      try do\n        assert File.touch!(fixture, :erlang.universaltime()) == :ok\n        stat = File.stat!(fixture)\n\n        assert File.touch!(fixture, last_year()) == :ok\n        assert stat.mtime > File.stat!(fixture).mtime\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"touch with posix timestamp\" do\n      fixture = tmp_path(\"tmp_posix_touch.txt\")\n\n      try do\n        assert File.touch!(fixture, System.os_time(:second)) == :ok\n        stat = File.stat!(fixture)\n\n        assert File.touch!(fixture, last_year()) == :ok\n        assert stat.mtime > File.stat!(fixture).mtime\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"touch with dir\" do\n      assert File.touch(fixture_path()) == :ok\n    end\n\n    test \"touch with failure\" do\n      fixture = fixture_path(\"file.txt/bar\")\n      assert io_error?(File.touch(fixture))\n    end\n\n    test \"touch! raises\" do\n      fixture = fixture_path(\"file.txt/bar\")\n\n      message =\n        ~r\"\\Acould not touch #{inspect(fixture)}: (not a directory|no such file or directory)\"\n\n      assert_raise File.Error, message, fn ->\n        File.touch!(fixture)\n      end\n    end\n  end\n\n  describe \"ch*\" do\n    test \"chmod with success\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n\n      File.touch(fixture)\n\n      try do\n        assert File.chmod(fixture, 0o100666) == :ok\n        stat = File.stat!(fixture)\n        assert stat.mode == 0o100666\n\n        if not windows?() do\n          assert File.chmod(fixture, 0o100777) == :ok\n          stat = File.stat!(fixture)\n          assert stat.mode == 0o100777\n        end\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"chmod! with success\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n\n      File.touch(fixture)\n\n      try do\n        assert File.chmod!(fixture, 0o100666) == :ok\n        stat = File.stat!(fixture)\n        assert stat.mode == 0o100666\n\n        if not windows?() do\n          assert File.chmod!(fixture, 0o100777) == :ok\n          stat = File.stat!(fixture)\n          assert stat.mode == 0o100777\n        end\n      after\n        File.rm(fixture)\n      end\n    end\n\n    test \"chmod with failure\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.rm(fixture)\n\n      assert File.chmod(fixture, 0o100777) == {:error, :enoent}\n    end\n\n    test \"chmod! with failure\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.rm(fixture)\n\n      message = ~r\"could not change mode for #{inspect(fixture)}: no such file or directory\"\n\n      assert_raise File.Error, message, fn ->\n        File.chmod!(fixture, 0o100777)\n      end\n    end\n\n    test \"chgrp with failure\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.rm(fixture)\n\n      assert File.chgrp(fixture, 1) == {:error, :enoent}\n    end\n\n    test \"chgrp! with failure\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.rm(fixture)\n\n      message = ~r\"could not change group for #{inspect(fixture)}: no such file or directory\"\n\n      assert_raise File.Error, message, fn ->\n        File.chgrp!(fixture, 1)\n      end\n    end\n\n    test \"chown with failure\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.rm(fixture)\n\n      assert File.chown(fixture, 1) == {:error, :enoent}\n    end\n\n    test \"chown! with failure\" do\n      fixture = tmp_path(\"tmp_test.txt\")\n      File.rm(fixture)\n\n      message = ~r\"could not change owner for #{inspect(fixture)}: no such file or directory\"\n\n      assert_raise File.Error, message, fn ->\n        File.chown!(fixture, 1)\n      end\n    end\n  end\n\n  defp last_year do\n    System.os_time(:second) - 365 * 24 * 60 * 60\n  end\n\n  defp io_error?(result) do\n    elem(result, 1) in [:enotdir, :eio, :enoent, :eisdir]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/at_exit.exs",
    "content": "defmodule AtExit do\n  def at_exit(str) do\n    System.at_exit(fn _ -> IO.write(str) end)\n  end\nend\n\nSystem.at_exit(fn status -> IO.puts(\"cruel world with status #{status}\") end)\nAtExit.at_exit(\"goodbye \")\nexit({:shutdown, 1})\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/code_sample.exs",
    "content": "# Some Comments\nvar = 1 + 2\nvar\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/compile_sample.ex",
    "content": "defmodule(CompileSample, do: nil)\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/bad_app.exs",
    "content": "[sample: :oops]\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/bad_import.exs",
    "content": "import Config\nimport_config \"bad_root.exs\"\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/env.exs",
    "content": "import Config\nconfig :my_app, env: config_env(), target: config_target()\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/good_config.exs",
    "content": "import Config\nconfig :my_app, :key, :value\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/good_import.exs",
    "content": "import Config\nimport_config \"good_config.exs\"\n:done\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/good_kw.exs",
    "content": "[my_app: [key: :value]]\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/imports_recursive.exs",
    "content": "import Config\nimport_config \"recursive.exs\"\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/kernel.exs",
    "content": "import Config\nconfig :kernel, :elixir_reboot, true\nconfig :elixir_reboot, :key, :value\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/nested.exs",
    "content": "import Config\nconfig :app, Repo, key: [nested: true]\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/configs/recursive.exs",
    "content": "import Config\nimport_config \"imports_recursive.exs\"\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/consolidation/no_impl.ex",
    "content": "defprotocol Protocol.ConsolidationTest.NoImpl do\n  def ok(term)\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/consolidation/sample.ex",
    "content": "defprotocol Protocol.ConsolidationTest.Sample do\n  @type t :: any\n  @doc \"Ok\"\n  @deprecated \"Reason\"\n  @spec ok(t) :: boolean\n  def ok(term)\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/consolidation/with_any.ex",
    "content": "defprotocol Protocol.ConsolidationTest.WithAny do\n  @fallback_to_any true\n  @doc \"Ok\"\n  def ok(term, opts)\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/cp_mode",
    "content": ""
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/cp_r/a/1.txt",
    "content": ""
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/cp_r/a/a/2.txt",
    "content": ""
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/cp_r/b/3.txt",
    "content": ""
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/assertions.ex",
    "content": "defmodule Dialyzer.Assertions do\n  import ExUnit.Assertions\n\n  def assert_with_truthy_match do\n    assert :ok = known_type_truthy()\n  end\n\n  def assert_with_truthy_value do\n    assert known_type_truthy()\n  end\n\n  def assert_with_unknown_type do\n    assert unknown_type_truthy()\n  end\n\n  def refute_with_falsy_value do\n    refute known_type_falsy()\n  end\n\n  def refute_with_unknown_type do\n    refute unknown_type_falsy()\n  end\n\n  def refute_with_operator(log) do\n    refute log == \"failure\"\n  end\n\n  defp known_type_truthy, do: :ok\n  defp known_type_falsy, do: nil\n\n  @spec unknown_type_truthy :: any\n  defp unknown_type_truthy, do: Enum.random([1, true, :ok])\n  @spec unknown_type_falsy :: any\n  defp unknown_type_falsy, do: Enum.random([false, nil])\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/boolean_check.ex",
    "content": "defmodule Dialyzer.BooleanCheck do\n  def and_check(arg) when is_boolean(arg) do\n    arg and arg\n  end\n\n  def or_check(arg) when is_boolean(arg) do\n    arg or arg\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/callback.ex",
    "content": "defmodule Dialyzer.Callback do\n  @callback required(atom) :: atom\n  @callback required(list) :: list\nend\n\ndefmodule Dialyzer.Callback.ImplAtom do\n  @behaviour Dialyzer.Callback\n  def required(:ok), do: :ok\nend\n\ndefmodule Dialyzer.Callback.ImplList do\n  @behaviour Dialyzer.Callback\n  def required([a, b]), do: [b, a]\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/cond.ex",
    "content": "defmodule Dialyzer.Cond do\n  def one_boolean do\n    cond do\n      true -> :ok\n    end\n  end\n\n  def two_boolean do\n    cond do\n      List.flatten([]) == [] -> :ok\n      true -> :ok\n    end\n  end\n\n  def one_otherwise do\n    cond do\n      :otherwise -> :ok\n    end\n  end\n\n  def two_otherwise do\n    cond do\n      List.flatten([]) == [] -> :ok\n      :otherwise -> :ok\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/defmacrop.ex",
    "content": "defmodule Dialyzer.Defmacrop do\n  defmacrop good_macro(id) do\n    quote do\n      {:good, {:good_macro, unquote(id)}}\n    end\n  end\n\n  def run() do\n    good_macro(\"Not So Bad\")\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/for_bitstring.ex",
    "content": "defmodule Dialyzer.ForBitstring do\n  def foo() do\n    for a <- 1..3, into: \"\", do: <<a>>\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/for_boolean_check.ex",
    "content": "defmodule Dialyzer.ForBooleanCheck do\n  def foo(enum, potential) when is_binary(potential) do\n    for element <- enum, string = Atom.to_string(element), string == potential do\n      element\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/in_range.ex",
    "content": "defmodule Dialyzer.InRange do\n  def string_to_number_in_range(x) do\n    String.to_integer(x) in 1..10\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/is_struct.ex",
    "content": "defmodule Dialyzer.IsStruct do\n  def map_literal_atom_literal() do\n    is_struct(%Macro.Env{}, Macro.Env)\n  end\n\n  def arg_atom_literal(arg) do\n    is_struct(arg, Macro.Env)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/macrocallback.ex",
    "content": "defmodule Dialyzer.Macrocallback do\n  @macrocallback required(atom) :: Macro.t()\n  @macrocallback optional(atom) :: Macro.t()\n  @optional_callbacks [optional: 1]\nend\n\ndefmodule Dialyzer.Macrocallback.Impl do\n  @behaviour Dialyzer.Macrocallback\n  defmacro required(var), do: Macro.expand(var, __CALLER__)\n  defmacro optional(var), do: Macro.expand(var, __CALLER__)\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/opaqueness.ex",
    "content": "defmodule Dialyzer.Opaqueness do\n  @spec bar(MapSet.t()) :: term()\n  def bar(set) do\n    set\n  end\n\n  def inlined do\n    # inlining of literals should not violate opaqueness check\n    bar(MapSet.new([1, 2, 3]))\n  end\n\n  @my_set MapSet.new([1, 2, 3])\n  def module_attr do\n    bar(@my_set)\n  end\n\n  # Task.Supervisor returns a Task.t() containing an opaque Task.ref()\n  @spec run_task() :: Task.t()\n  def run_task do\n    Task.Supervisor.async(SupervisorName, fn -> :ok end)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/raise.ex",
    "content": "defmodule Dialyzer.Raise do\n  defexception [:message]\n\n  def exception_var() do\n    ex = %Dialyzer.Raise{}\n    raise ex\n  end\n\n  def exception_var(ex = %Dialyzer.Raise{}) do\n    raise ex\n  end\n\n  def string_var() do\n    string = \"hello\"\n    raise string\n  end\n\n  def string_var(string) when is_binary(string) do\n    raise string\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/regressions.ex",
    "content": "defmodule Dialyzer.Regressions do\n  def io_inspect_opts do\n    IO.inspect(123, label: \"foo\", limit: :infinity)\n  end\n\n  def format_opts do\n    Code.format_string!(\"\",\n      line_length: 120,\n      force_do_end_blocks: true,\n      locals_without_parens: true,\n      migrate: true\n    )\n  end\n\n  def eex_eval_opts do\n    EEx.eval_string(\"foo <%= bar %>\", [bar: \"baz\"], trim: true)\n  end\n\n  @spec inlined_map_set :: MapSet.t(integer())\n  def inlined_map_set, do: MapSet.new([1, 2])\n\n  @spec inlined_uri :: URI.t()\n  def inlined_uri, do: URI.new!(\"example.com\")\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/remote_call.ex",
    "content": "defmodule Dialyzer.RemoteCall do\n  _ = Application.load(:dialyzer)\n\n  case Application.spec(:dialyzer, :vsn) do\n    ~c(2.) ++ _ ->\n      @dialyzer {:no_fail_call, [map_var: 0]}\n\n    three when three < ~c(3.0.2) ->\n      # regression introduced in 3.0 for map warnings fixed in 3.0.2\n      @dialyzer {:no_match, [map_var: 0, mod_var: 0]}\n\n    _ ->\n      :ok\n  end\n\n  def map_var() do\n    map = %{key: 1}\n    map.key\n  end\n\n  def map_var(map) when is_map(map) do\n    map.key\n  end\n\n  def mod_var() do\n    module = String.to_atom(\"Elixir.Hello\")\n    module.fun()\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/rewrite.ex",
    "content": "defmodule Dialyzer.Rewrite do\n  def interpolation do\n    \"foo #{:a}\"\n  end\n\n  def reverse do\n    Enum.reverse(1..3)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/try.ex",
    "content": "defmodule Dialyzer.Try do\n  def rescue_error do\n    try do\n      :erlang.error(:badarg)\n    rescue\n      e in ErlangError -> {:ok, e}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/with.ex",
    "content": "defmodule Dialyzer.With do\n  def with_else do\n    with :ok <- ok_or_error(),\n         :ok <- ok_or_other_error(),\n         :ok <- ok_or_tuple_error(),\n         :ok <- ok_or_tuple_list_error() do\n      :ok\n    else\n      :error ->\n        :error\n\n      :other_error ->\n        :other_error\n\n      {:error, msg} when is_list(msg) when is_tuple(msg) ->\n        :error\n\n      {:error, _msg} ->\n        :error\n    end\n  end\n\n  @spec ok_or_error() :: :ok | :error\n  defp ok_or_error do\n    Enum.random([:ok, :error])\n  end\n\n  @spec ok_or_other_error() :: :ok | :other_error\n  defp ok_or_other_error do\n    Enum.random([:ok, :other_error])\n  end\n\n  @spec ok_or_tuple_error() :: :ok | {:error, :err}\n  defp ok_or_tuple_error do\n    Enum.random([:ok, {:error, :err}])\n  end\n\n  @spec ok_or_tuple_list_error() :: :ok | {:error, [:err]}\n  defp ok_or_tuple_list_error do\n    Enum.random([:ok, {:error, [:err]}])\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/with_no_return.ex",
    "content": "defmodule Dialyzer.WithNoReturn do\n  def with_no_return(list) do\n    no_return = fn -> throw(:no_return) end\n\n    with [] <- list do\n      :ok\n    else\n      # note: throwing here directly wouldn't be caught in the first place,\n      # calling a no_return function is what could cause an issue.\n      _ -> no_return.()\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/dialyzer/with_throwing_else.ex",
    "content": "defmodule Dialyzer.WithThrowingElse do\n  def with_throwing_else(map) do\n    with {:ok, foo} <- Map.fetch(map, :foo),\n         false <- Enum.empty?(foo) do\n      foo\n    else\n      # several clauses but one is a no_return\n      :error -> throw(:empty_map)\n      true -> nil\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/file.txt",
    "content": "FOO\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/multiline_file.txt",
    "content": "this is the first line\nthis is the second line\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/utf8.txt",
    "content": "Русский\n日\n"
  },
  {
    "path": "lib/elixir/test/elixir/fixtures/utf8_bom.txt",
    "content": "﻿Русский\n日\n"
  },
  {
    "path": "lib/elixir/test/elixir/float_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule FloatTest do\n  use ExUnit.Case, async: true\n\n  doctest Float\n\n  test \"parse/1\" do\n    assert Float.parse(\"12\") === {12.0, \"\"}\n    assert Float.parse(\"-12\") === {-12.0, \"\"}\n    assert Float.parse(\"-0.1\") === {-0.1, \"\"}\n    assert Float.parse(\"123456789\") === {123_456_789.0, \"\"}\n    assert Float.parse(\"12.5\") === {12.5, \"\"}\n    assert Float.parse(\"12.524235\") === {12.524235, \"\"}\n    assert Float.parse(\"-12.5\") === {-12.5, \"\"}\n    assert Float.parse(\"-12.524235\") === {-12.524235, \"\"}\n    assert Float.parse(\"0.3534091\") === {0.3534091, \"\"}\n    assert Float.parse(\"0.3534091elixir\") === {0.3534091, \"elixir\"}\n    assert Float.parse(\"7.5e3\") === {7.5e3, \"\"}\n    assert Float.parse(\"7.5e-3\") === {7.5e-3, \"\"}\n    assert Float.parse(\"12x\") === {12.0, \"x\"}\n    assert Float.parse(\"12.5x\") === {12.5, \"x\"}\n    assert Float.parse(\"-12.32453e10\") === {-1.232453e11, \"\"}\n    assert Float.parse(\"-12.32453e-10\") === {-1.232453e-9, \"\"}\n    assert Float.parse(\"0.32453e-10\") === {3.2453e-11, \"\"}\n    assert Float.parse(\"1.32453e-10\") === {1.32453e-10, \"\"}\n    assert Float.parse(\"1.7976931348623159e-99999foo\") === {0.0, \"foo\"}\n    assert Float.parse(\"1.32.45\") === {1.32, \".45\"}\n    assert Float.parse(\"1.o\") === {1.0, \".o\"}\n    assert Float.parse(\"+12.3E+4\") === {1.23e5, \"\"}\n    assert Float.parse(\"+12.3E-4x\") === {0.00123, \"x\"}\n    assert Float.parse(\"-1.23e-0xFF\") === {-1.23, \"xFF\"}\n    assert Float.parse(\"-1.e2\") === {-1.0, \".e2\"}\n    assert Float.parse(\".12\") === :error\n    assert Float.parse(\"--1.2\") === :error\n    assert Float.parse(\"++1.2\") === :error\n    assert Float.parse(\"pi\") === :error\n    assert Float.parse(\"1.7976931348623157e308\") === {1.7976931348623157e308, \"\"}\n    assert Float.parse(\"1.7976931348623157e308foo\") === {1.7976931348623157e308, \"foo\"}\n    assert Float.parse(\"1.7976931348623157e+308foo\") === {1.7976931348623157e308, \"foo\"}\n    assert Float.parse(\"1.7976931348623157e-308foo\") === {1.7976931348623155e-308, \"foo\"}\n    assert Float.parse(\"1.7976931348623159e308\") === :error\n    assert Float.parse(\"1.7976931348623159e+308\") === :error\n    assert Float.parse(\"9e8363\") === :error\n\n    # Non-scientific notation overflow\n    assert Float.parse(String.duplicate(\"9\", 310) <> \".0\") === :error\n    assert Float.parse(\"-\" <> String.duplicate(\"9\", 310) <> \".0\") === :error\n    assert Float.parse(String.duplicate(\"9\", 310) <> \".0foo\") === :error\n  end\n\n  test \"floor/1\" do\n    assert Float.floor(12.524235) === 12.0\n    assert Float.floor(-12.5) === -13.0\n    assert Float.floor(-12.524235) === -13.0\n    assert Float.floor(7.5e3) === 7500.0\n    assert Float.floor(7.5432e3) === 7543.0\n    assert Float.floor(7.5e-3) === 0.0\n    assert Float.floor(-12.32453e4) === -123_246.0\n    assert Float.floor(-12.32453e-10) === -1.0\n    assert Float.floor(0.32453e-10) === 0.0\n    assert Float.floor(-0.32453e-10) === -1.0\n    assert Float.floor(1.32453e-10) === 0.0\n  end\n\n  describe \"floor/2\" do\n    test \"with 0.0\" do\n      for precision <- 0..15 do\n        assert Float.floor(0.0, precision) === 0.0\n        assert Float.floor(-0.0, precision) === -0.0\n      end\n    end\n\n    test \"floor/2 with precision\" do\n      assert Float.floor(12.524235, 0) === 12.0\n      assert Float.floor(-12.524235, 0) === -13.0\n\n      assert Float.floor(12.52, 2) === 12.51\n      assert Float.floor(-12.52, 2) === -12.52\n\n      assert Float.floor(12.524235, 2) === 12.52\n      assert Float.floor(-12.524235, 3) === -12.525\n\n      assert Float.floor(12.32453e-20, 2) === 0.0\n      assert Float.floor(-12.32453e-20, 2) === -0.01\n\n      assert_raise ArgumentError, \"precision 16 is out of valid range of 0..15\", fn ->\n        Float.floor(1.1, 16)\n      end\n    end\n\n    test \"with subnormal floats\" do\n      assert Float.floor(-5.0e-324, 0) === -1.0\n      assert Float.floor(-5.0e-324, 1) === -0.1\n      assert Float.floor(-5.0e-324, 2) === -0.01\n      assert Float.floor(-5.0e-324, 15) === -0.000000000000001\n\n      for precision <- 0..15 do\n        assert Float.floor(5.0e-324, precision) === 0.0\n      end\n    end\n  end\n\n  test \"ceil/1\" do\n    assert Float.ceil(12.524235) === 13.0\n    assert Float.ceil(-12.5) === -12.0\n    assert Float.ceil(-12.524235) === -12.0\n    assert Float.ceil(7.5e3) === 7500.0\n    assert Float.ceil(7.5432e3) === 7544.0\n    assert Float.ceil(7.5e-3) === 1.0\n    assert Float.ceil(-12.32453e4) === -123_245.0\n    assert Float.ceil(-12.32453e-10) === -0.0\n    assert Float.ceil(0.32453e-10) === 1.0\n    assert Float.ceil(-0.32453e-10) === -0.0\n    assert Float.ceil(1.32453e-10) === 1.0\n    assert Float.ceil(0.0) === 0.0\n  end\n\n  describe \"ceil/2\" do\n    test \"with 0.0\" do\n      for precision <- 0..15 do\n        assert Float.ceil(0.0, precision) === 0.0\n        assert Float.ceil(-0.0, precision) === -0.0\n      end\n    end\n\n    test \"with regular floats\" do\n      assert Float.ceil(12.524235, 0) === 13.0\n      assert Float.ceil(-12.524235, 0) === -12.0\n\n      assert Float.ceil(12.52, 2) === 12.52\n      assert Float.ceil(-12.52, 2) === -12.51\n\n      assert Float.ceil(12.524235, 2) === 12.53\n      assert Float.ceil(-12.524235, 3) === -12.524\n\n      assert Float.ceil(12.32453e-20, 2) === 0.01\n      assert Float.ceil(-12.32453e-20, 2) === -0.0\n\n      assert Float.ceil(0.0, 2) === 0.0\n\n      assert_raise ArgumentError, \"precision 16 is out of valid range of 0..15\", fn ->\n        Float.ceil(1.1, 16)\n      end\n    end\n\n    test \"with small floats rounded up to -0.0\" do\n      assert Float.ceil(-0.1, 0) === -0.0\n      assert Float.ceil(-0.01, 1) === -0.0\n    end\n\n    test \"with subnormal floats\" do\n      assert Float.ceil(5.0e-324, 0) === 1.0\n      assert Float.ceil(5.0e-324, 1) === 0.1\n      assert Float.ceil(5.0e-324, 2) === 0.01\n      assert Float.ceil(5.0e-324, 15) === 0.000000000000001\n\n      for precision <- 0..15 do\n        assert Float.ceil(-5.0e-324, precision) === -0.0\n      end\n    end\n  end\n\n  describe \"round/2\" do\n    test \"with 0.0\" do\n      for precision <- 0..15 do\n        assert Float.round(0.0, precision) === 0.0\n        assert Float.round(-0.0, precision) === -0.0\n      end\n    end\n\n    test \"with regular floats\" do\n      assert Float.round(5.5675, 3) === 5.567\n      assert Float.round(-5.5674, 3) === -5.567\n      assert Float.round(5.5, 3) === 5.5\n      assert Float.round(5.5e-10, 10) === 5.0e-10\n      assert Float.round(5.5e-10, 8) === 0.0\n      assert Float.round(5.0, 0) === 5.0\n\n      assert_raise ArgumentError, \"precision 16 is out of valid range of 0..15\", fn ->\n        Float.round(1.1, 16)\n      end\n    end\n\n    test \"with small floats rounded to +0.0 / -0.0\" do\n      assert Float.round(0.01, 0) === 0.0\n      assert Float.round(0.01, 1) === 0.0\n\n      assert Float.round(-0.01, 0) === -0.0\n      assert Float.round(-0.01, 1) === -0.0\n\n      assert Float.round(-0.49999, 0) === -0.0\n      assert Float.round(-0.049999, 1) === -0.0\n    end\n\n    test \"with subnormal floats\" do\n      for precision <- 0..15 do\n        assert Float.round(5.0e-324, precision) === 0.0\n        assert Float.round(-5.0e-324, precision) === -0.0\n      end\n    end\n  end\n\n  describe \"ratio/1\" do\n    test \"with 0.0\" do\n      assert Float.ratio(0.0) == {0, 1}\n    end\n\n    test \"with regular floats\" do\n      assert Float.ratio(3.14) == {7_070_651_414_971_679, 2_251_799_813_685_248}\n      assert Float.ratio(-3.14) == {-7_070_651_414_971_679, 2_251_799_813_685_248}\n      assert Float.ratio(1.5) == {3, 2}\n    end\n\n    test \"with subnormal floats\" do\n      assert Float.ratio(5.0e-324) ==\n               {1,\n                202_402_253_307_310_618_352_495_346_718_917_307_049_556_649_764_142_118_356_901_358_027_430_339_567_995_346_891_960_383_701_437_124_495_187_077_864_316_811_911_389_808_737_385_793_476_867_013_399_940_738_509_921_517_424_276_566_361_364_466_907_742_093_216_341_239_767_678_472_745_068_562_007_483_424_692_698_618_103_355_649_159_556_340_810_056_512_358_769_552_333_414_615_230_502_532_186_327_508_646_006_263_307_707_741_093_494_784}\n\n      assert Float.ratio(1.0e-323) ==\n               {1,\n                101_201_126_653_655_309_176_247_673_359_458_653_524_778_324_882_071_059_178_450_679_013_715_169_783_997_673_445_980_191_850_718_562_247_593_538_932_158_405_955_694_904_368_692_896_738_433_506_699_970_369_254_960_758_712_138_283_180_682_233_453_871_046_608_170_619_883_839_236_372_534_281_003_741_712_346_349_309_051_677_824_579_778_170_405_028_256_179_384_776_166_707_307_615_251_266_093_163_754_323_003_131_653_853_870_546_747_392}\n\n      assert Float.ratio(2.225073858507201e-308) ==\n               {4_503_599_627_370_495,\n                202_402_253_307_310_618_352_495_346_718_917_307_049_556_649_764_142_118_356_901_358_027_430_339_567_995_346_891_960_383_701_437_124_495_187_077_864_316_811_911_389_808_737_385_793_476_867_013_399_940_738_509_921_517_424_276_566_361_364_466_907_742_093_216_341_239_767_678_472_745_068_562_007_483_424_692_698_618_103_355_649_159_556_340_810_056_512_358_769_552_333_414_615_230_502_532_186_327_508_646_006_263_307_707_741_093_494_784}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/function_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule DummyFunction do\n  def function_with_arity_0 do\n    true\n  end\n\n  def zero?(0), do: true\n  def zero?(_), do: false\nend\n\ndefmodule FunctionTest do\n  use ExUnit.Case, async: true\n\n  doctest Function\n  import Function\n\n  @information_keys_for_named [:type, :module, :arity, :name, :env]\n  @information_keys_for_anonymous @information_keys_for_named ++\n                                    [:pid, :index, :new_index, :new_uniq, :uniq]\n\n  describe \"capture/3\" do\n    test \"captures module functions with arity 0\" do\n      f = capture(DummyFunction, :function_with_arity_0, 0)\n\n      assert is_function(f)\n    end\n\n    test \"captures module functions with any arity\" do\n      f = capture(DummyFunction, :zero?, 1)\n\n      assert is_function(f)\n      assert f.(0)\n    end\n  end\n\n  describe \"info/1\" do\n    test \"returns info for named captured functions\" do\n      f = &DummyFunction.zero?/1\n      expected = [module: DummyFunction, name: :zero?, arity: 1, env: [], type: :external]\n\n      result = info(f)\n\n      assert expected == result\n    end\n\n    test \"returns info for anonymous functions\" do\n      f = fn x -> x end\n\n      result = info(f)\n\n      for {key, _value} <- result do\n        assert key in @information_keys_for_anonymous\n      end\n    end\n  end\n\n  describe \"info/2\" do\n    test \"returns info for every possible information key for named functions\" do\n      f = &DummyFunction.zero?/1\n\n      for x <- @information_keys_for_named do\n        assert {^x, _} = info(f, x)\n      end\n    end\n\n    test \"returns info for every possible information key for anonymous functions\" do\n      f = &DummyFunction.zero?/1\n\n      for x <- @information_keys_for_anonymous do\n        assert {^x, _} = info(f, x)\n      end\n\n      assert {:arity, 1} = info(f, :arity)\n    end\n  end\n\n  describe \"identity/1\" do\n    test \"returns whatever it gets passed\" do\n      assert :hello = Function.identity(:hello)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/gen_server_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule GenServerTest do\n  use ExUnit.Case, async: true\n\n  defmodule Stack do\n    use GenServer\n\n    def init(args) do\n      {:ok, args}\n    end\n\n    def handle_call(:pop, _from, [h | t]) do\n      {:reply, h, t}\n    end\n\n    def handle_call(:noreply, _from, h) do\n      {:noreply, h}\n    end\n\n    def handle_call(:stop_self, _from, state) do\n      reason = catch_exit(GenServer.stop(self()))\n      {:reply, reason, state}\n    end\n\n    def handle_cast({:push, element}, state) do\n      {:noreply, [element | state]}\n    end\n\n    def terminate(_reason, _state) do\n      # There is a race condition if the agent is\n      # restarted too fast and it is registered.\n      try do\n        self() |> Process.info(:registered_name) |> elem(1) |> Process.unregister()\n      rescue\n        _ -> :ok\n      end\n\n      :ok\n    end\n  end\n\n  test \"generates child_spec/1\" do\n    assert Stack.child_spec([:hello]) == %{\n             id: Stack,\n             start: {Stack, :start_link, [[:hello]]}\n           }\n\n    defmodule CustomStack do\n      use GenServer, id: :id, restart: :temporary, shutdown: :infinity, start: {:foo, :bar, []}\n\n      def init(args) do\n        {:ok, args}\n      end\n    end\n\n    assert CustomStack.child_spec([:hello]) == %{\n             id: :id,\n             restart: :temporary,\n             shutdown: :infinity,\n             start: {:foo, :bar, []}\n           }\n  end\n\n  test \"start_link/3\" do\n    assert_raise ArgumentError, ~r\"expected :name option to be one of the following:\", fn ->\n      GenServer.start_link(Stack, [:hello], name: \"my_gen_server_name\")\n    end\n\n    assert_raise ArgumentError, ~r\"expected :name option to be one of the following:\", fn ->\n      GenServer.start_link(Stack, [:hello], name: {:invalid_tuple, \"my_gen_server_name\"})\n    end\n\n    assert_raise ArgumentError, ~r\"expected :name option to be one of the following:\", fn ->\n      GenServer.start_link(Stack, [:hello], name: {:via, \"Via\", \"my_gen_server_name\"})\n    end\n\n    assert_raise ArgumentError, ~r/Got: \"my_gen_server_name\"/, fn ->\n      GenServer.start_link(Stack, [:hello], name: \"my_gen_server_name\")\n    end\n  end\n\n  test \"start_link/3 with via\" do\n    GenServer.start_link(Stack, [:hello], name: {:via, :global, :via_stack})\n    assert GenServer.call({:via, :global, :via_stack}, :pop) == :hello\n  end\n\n  test \"start_link/3 with global\" do\n    GenServer.start_link(Stack, [:hello], name: {:global, :global_stack})\n    assert GenServer.call({:global, :global_stack}, :pop) == :hello\n  end\n\n  test \"start_link/3 with local\" do\n    GenServer.start_link(Stack, [:hello], name: :stack)\n    assert GenServer.call(:stack, :pop) == :hello\n  end\n\n  test \"start_link/2, call/2 and cast/2\" do\n    {:ok, pid} = GenServer.start_link(Stack, [:hello])\n\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    assert GenServer.call(pid, :pop) == :hello\n    assert GenServer.cast(pid, {:push, :world}) == :ok\n    assert GenServer.call(pid, :pop) == :world\n    assert GenServer.stop(pid) == :ok\n\n    assert GenServer.cast({:global, :foo}, {:push, :world}) == :ok\n    assert GenServer.cast({:via, :foo, :bar}, {:push, :world}) == :ok\n    assert GenServer.cast(:foo, {:push, :world}) == :ok\n  end\n\n  @tag capture_log: true\n  test \"call/3 exit messages\" do\n    name = :self\n    Process.register(self(), name)\n    :global.register_name(name, self())\n    {:ok, pid} = GenServer.start_link(Stack, [:hello])\n    {:ok, stopped_pid} = GenServer.start(Stack, [:hello])\n    GenServer.stop(stopped_pid)\n\n    assert catch_exit(GenServer.call(name, :pop, 5000)) ==\n             {:calling_self, {GenServer, :call, [name, :pop, 5000]}}\n\n    assert catch_exit(GenServer.call({:global, name}, :pop, 5000)) ==\n             {:calling_self, {GenServer, :call, [{:global, name}, :pop, 5000]}}\n\n    assert catch_exit(GenServer.call({:via, :global, name}, :pop, 5000)) ==\n             {:calling_self, {GenServer, :call, [{:via, :global, name}, :pop, 5000]}}\n\n    assert catch_exit(GenServer.call(self(), :pop, 5000)) ==\n             {:calling_self, {GenServer, :call, [self(), :pop, 5000]}}\n\n    assert catch_exit(GenServer.call(pid, :noreply, 1)) ==\n             {:timeout, {GenServer, :call, [pid, :noreply, 1]}}\n\n    assert catch_exit(GenServer.call(nil, :pop, 5000)) ==\n             {:noproc, {GenServer, :call, [nil, :pop, 5000]}}\n\n    assert catch_exit(GenServer.call(stopped_pid, :pop, 5000)) ==\n             {:noproc, {GenServer, :call, [stopped_pid, :pop, 5000]}}\n\n    assert catch_exit(GenServer.call({:stack, :bogus_node}, :pop, 5000)) ==\n             {{:nodedown, :bogus_node}, {GenServer, :call, [{:stack, :bogus_node}, :pop, 5000]}}\n  end\n\n  test \"nil name\" do\n    {:ok, pid} = GenServer.start_link(Stack, [:hello], name: nil)\n    assert Process.info(pid, :registered_name) == {:registered_name, []}\n  end\n\n  test \"start/2\" do\n    {:ok, pid} = GenServer.start(Stack, [:hello])\n    {:links, links} = Process.info(self(), :links)\n    refute pid in links\n    GenServer.stop(pid)\n  end\n\n  test \"abcast/3\", %{test: name} do\n    {:ok, _} = GenServer.start_link(Stack, [], name: name)\n\n    assert GenServer.abcast(name, {:push, :hello}) == :abcast\n    assert GenServer.call({name, node()}, :pop) == :hello\n\n    assert GenServer.abcast([node(), :foo@bar], name, {:push, :world}) == :abcast\n    assert GenServer.call(name, :pop) == :world\n  end\n\n  test \"multi_call/4\", %{test: name} do\n    {:ok, _} = GenServer.start_link(Stack, [:hello, :world], name: name)\n    node = node()\n\n    assert {[{^node, :hello}], _} = GenServer.multi_call(name, :pop)\n    assert {[{^node, :world}], [:foo@bar]} = GenServer.multi_call([node(), :foo@bar], name, :pop)\n  end\n\n  test \"whereis/1\" do\n    name = :whereis_server\n\n    {:ok, pid} = GenServer.start_link(Stack, [], name: name)\n    assert GenServer.whereis(name) == pid\n    assert GenServer.whereis({name, node()}) == pid\n    assert GenServer.whereis({name, :another_node}) == {name, :another_node}\n    assert GenServer.whereis(pid) == pid\n    assert GenServer.whereis(:whereis_bad_server) == nil\n\n    {:ok, pid} = GenServer.start_link(Stack, [], name: {:global, name})\n    assert GenServer.whereis({:global, name}) == pid\n    assert GenServer.whereis({:global, :whereis_bad_server}) == nil\n    assert GenServer.whereis({:via, :global, name}) == pid\n    assert GenServer.whereis({:via, :global, :whereis_bad_server}) == nil\n  end\n\n  test \"stop/3\", %{test: name} do\n    {:ok, pid} = GenServer.start(Stack, [])\n    assert GenServer.stop(pid, :normal) == :ok\n\n    stopped_pid = pid\n\n    assert catch_exit(GenServer.stop(stopped_pid)) ==\n             {:noproc, {GenServer, :stop, [stopped_pid, :normal, :infinity]}}\n\n    assert catch_exit(GenServer.stop(nil)) ==\n             {:noproc, {GenServer, :stop, [nil, :normal, :infinity]}}\n\n    {:ok, pid} = GenServer.start(Stack, [])\n\n    assert GenServer.call(pid, :stop_self) ==\n             {:calling_self, {GenServer, :stop, [pid, :normal, :infinity]}}\n\n    {:ok, _} = GenServer.start(Stack, [], name: name)\n    assert GenServer.stop(name, :normal) == :ok\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/inspect/algebra_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Inspect.OptsTest do\n  use ExUnit.Case\n\n  test \"new\" do\n    opts = Inspect.Opts.new(limit: 13, pretty: true)\n    assert opts.limit == 13\n    assert opts.pretty\n  end\n\n  test \"default_inspect_fun\" do\n    assert Inspect.Opts.default_inspect_fun() == (&Inspect.inspect/2)\n\n    assert Inspect.Opts.default_inspect_fun(fn\n             :rewrite_atom, _ -> \"rewritten_atom\"\n             value, opts -> Inspect.inspect(value, opts)\n           end) == :ok\n\n    assert inspect(:rewrite_atom) == \"rewritten_atom\"\n  after\n    Inspect.Opts.default_inspect_fun(&Inspect.inspect/2)\n  end\nend\n\ndefmodule Inspect.AlgebraTest do\n  use ExUnit.Case, async: true\n\n  doctest Inspect.Algebra\n\n  import Inspect.Algebra\n\n  defp render(doc, limit) do\n    doc |> group() |> format(limit) |> IO.iodata_to_binary()\n  end\n\n  test \"empty doc\" do\n    # Consistent with definitions\n    assert empty() == []\n\n    # Consistent formatting\n    assert render(empty(), 80) == \"\"\n  end\n\n  test \"strict break doc\" do\n    # Consistent with definitions\n    assert break(\"break\") == {:doc_break, \"break\", :strict}\n    assert break(\"\") == {:doc_break, \"\", :strict}\n\n    # Consistent formatting\n    assert render(break(\"_\"), 80) == \"_\"\n    assert render(glue(\"foo\", \" \", glue(\"bar\", \" \", \"baz\")), 10) == \"foo\\nbar\\nbaz\"\n  end\n\n  test \"flex break doc\" do\n    # Consistent with definitions\n    assert flex_break(\"break\") == {:doc_break, \"break\", :flex}\n    assert flex_break(\"\") == {:doc_break, \"\", :flex}\n\n    # Consistent formatting\n    assert render(flex_break(\"_\"), 80) == \"_\"\n    assert render(flex_glue(\"foo\", \" \", flex_glue(\"bar\", \" \", \"baz\")), 10) == \"foo bar\\nbaz\"\n  end\n\n  test \"glue doc\" do\n    # Consistent with definitions\n    assert glue(\"a\", \"->\", \"b\") == [\"a\", {:doc_break, \"->\", :strict} | \"b\"]\n    assert glue(\"a\", \"b\") == glue(\"a\", \" \", \"b\")\n  end\n\n  test \"flex glue doc\" do\n    # Consistent with definitions\n    assert flex_glue(\"a\", \"->\", \"b\") ==\n             [\"a\", {:doc_break, \"->\", :flex} | \"b\"]\n\n    assert flex_glue(\"a\", \"b\") == flex_glue(\"a\", \" \", \"b\")\n  end\n\n  test \"binary doc\" do\n    assert render(\"_\", 80) == \"_\"\n  end\n\n  test \"string doc\" do\n    # Consistent with definitions\n    assert string(\"ólá\") == {:doc_string, \"ólá\", 3}\n\n    # Counts graphemes\n    doc = glue(string(\"olá\"), \" \", string(\"mundo\"))\n    assert render(doc, 9) == \"olá mundo\"\n  end\n\n  test \"space doc\" do\n    # Consistent with definitions\n    assert space(\"a\", \"b\") == [\"a\", \" \" | \"b\"]\n  end\n\n  test \"always nest doc\" do\n    # Consistent with definitions\n    assert nest(empty(), 1) == {:doc_nest, empty(), 1, :always}\n    assert nest(empty(), 0) == []\n\n    # Consistent formatting\n    assert render(nest(\"a\", 1), 80) == \"a\"\n    assert render(nest(glue(\"a\", \"b\"), 1), 2) == \"a\\n b\"\n    assert render(nest(line(\"a\", \"b\"), 1), 20) == \"a\\n b\"\n  end\n\n  test \"break nest doc\" do\n    # Consistent with definitions\n    assert nest(empty(), 1, :break) == {:doc_nest, empty(), 1, :break}\n    assert nest(empty(), 0, :break) == []\n\n    # Consistent formatting\n    assert render(nest(\"a\", 1, :break), 80) == \"a\"\n    assert render(nest(glue(\"a\", \"b\"), 1, :break), 2) == \"a\\n b\"\n    assert render(nest(line(\"a\", \"b\"), 1, :break), 20) == \"a\\nb\"\n  end\n\n  test \"cursor nest doc\" do\n    # Consistent with definitions\n    assert nest(empty(), :cursor) == {:doc_nest, empty(), :cursor, :always}\n\n    # Consistent formatting\n    assert render(nest(\"a\", :cursor), 80) == \"a\"\n    assert render(concat(\"prefix \", nest(glue(\"a\", \"b\"), :cursor)), 2) == \"prefix a\\n       b\"\n    assert render(concat(\"prefix \", nest(line(\"a\", \"b\"), :cursor)), 2) == \"prefix a\\n       b\"\n  end\n\n  test \"reset nest doc\" do\n    # Consistent with definitions\n    assert nest(empty(), :reset) == {:doc_nest, empty(), :reset, :always}\n\n    # Consistent formatting\n    assert render(nest(\"a\", :reset), 80) == \"a\"\n    assert render(nest(nest(glue(\"a\", \"b\"), :reset), 10), 2) == \"a\\nb\"\n    assert render(nest(nest(line(\"a\", \"b\"), :reset), 10), 2) == \"a\\nb\"\n  end\n\n  test \"color doc\" do\n    # Consistent with definitions\n    opts = %Inspect.Opts{}\n    assert color_doc(empty(), :atom, opts) == empty()\n\n    opts = %Inspect.Opts{syntax_colors: [regex: :red]}\n    assert color_doc(empty(), :atom, opts) == empty()\n\n    opts = %Inspect.Opts{syntax_colors: [atom: :red]}\n    doc1 = {:doc_color, \"Hi\", IO.ANSI.red()}\n    doc2 = {:doc_color, empty(), IO.ANSI.reset()}\n    assert color_doc(\"Hi\", :atom, opts) == concat(doc1, doc2)\n\n    opts = %Inspect.Opts{syntax_colors: [reset: :red]}\n    assert color_doc(empty(), :atom, opts) == empty()\n\n    opts = %Inspect.Opts{syntax_colors: [number: :cyan, reset: :red]}\n    doc1 = {:doc_color, \"123\", IO.ANSI.cyan()}\n    doc2 = {:doc_color, empty(), IO.ANSI.red()}\n    assert color_doc(\"123\", :number, opts) == concat(doc1, doc2)\n\n    # Consistent formatting\n    opts = %Inspect.Opts{syntax_colors: [atom: :cyan]}\n    assert render(glue(color_doc(\"AA\", :atom, opts), \"BB\"), 5) == \"\\e[36mAA\\e[0m BB\"\n    assert render(glue(color_doc(\"AA\", :atom, opts), \"BB\"), 3) == \"\\e[36mAA\\e[0m\\nBB\"\n    assert render(glue(\"AA\", color_doc(\"BB\", :atom, opts)), 6) == \"AA \\e[36mBB\\e[0m\"\n  end\n\n  test \"line doc\" do\n    # Consistent with definitions\n    assert line(\"a\", \"b\") == [\"a\", :doc_line | \"b\"]\n\n    # Consistent formatting\n    assert render(line(glue(\"aaa\", \"bbb\"), glue(\"ccc\", \"ddd\")), 10) == \"aaa bbb\\nccc ddd\"\n  end\n\n  test \"group doc\" do\n    # Consistent with definitions\n    assert group(\"ab\") == {:doc_group, \"ab\", :normal}\n    assert group(empty()) == {:doc_group, empty(), :normal}\n\n    # Consistent formatting\n    doc = concat(glue(glue(glue(\"hello\", \"a\"), \"b\"), \"c\"), \"d\")\n    assert render(group(doc), 5) == \"hello\\na\\nb\\ncd\"\n  end\n\n  test \"group modes doc\" do\n    doc = glue(glue(\"hello\", \"a\"), \"b\")\n    assert render(doc, 10) == \"hello a b\"\n\n    assert render(doc |> glue(\"c\") |> group(), 10) ==\n             \"hello\\na\\nb\\nc\"\n\n    assert render(doc |> group() |> glue(\"c\") |> group() |> glue(\"d\"), 10) ==\n             \"hello a b\\nc\\nd\"\n\n    assert render(doc |> group(:optimistic) |> glue(\"c\") |> group() |> glue(\"d\"), 10) ==\n             \"hello\\na\\nb c d\"\n\n    assert render(doc |> group(:optimistic) |> glue(\"c\") |> group(:pessimistic) |> glue(\"d\"), 10) ==\n             \"hello\\na\\nb c\\nd\"\n  end\n\n  test \"no limit doc\" do\n    doc = no_limit(group(glue(glue(\"hello\", \"a\"), \"b\")))\n    assert render(doc, 5) == \"hello a b\"\n    assert render(doc, :infinity) == \"hello a b\"\n  end\n\n  test \"collapse lines\" do\n    # Consistent with definitions\n    assert collapse_lines(3) == {:doc_collapse, 3}\n\n    # Consistent formatting\n    doc = concat([collapse_lines(2), line(), line(), line()])\n    assert render(doc, 10) == \"\\n\\n\"\n    assert render(nest(doc, 2), 10) == \"\\n\\n  \"\n\n    doc = concat([collapse_lines(2), line(), line()])\n    assert render(doc, 10) == \"\\n\\n\"\n    assert render(nest(doc, 2), 10) == \"\\n\\n  \"\n\n    doc = concat([collapse_lines(2), line()])\n    assert render(doc, 10) == \"\\n\"\n    assert render(nest(doc, 2), 10) == \"\\n  \"\n\n    doc = concat([collapse_lines(2), line(), \"\", line(), \"\", line()])\n    assert render(doc, 10) == \"\\n\\n\"\n    assert render(nest(doc, 2), 10) == \"\\n\\n  \"\n\n    doc = concat([collapse_lines(2), line(), \"foo\", line(), \"bar\", line()])\n    assert render(doc, 10) == \"\\nfoo\\nbar\\n\"\n    assert render(nest(doc, 2), 10) == \"\\n  foo\\n  bar\\n  \"\n  end\n\n  test \"force doc and cancel doc\" do\n    # Consistent with definitions\n    assert force_unfit(\"ab\") == {:doc_force, \"ab\"}\n    assert force_unfit(empty()) == {:doc_force, empty()}\n\n    # Consistent formatting\n    doc = force_unfit(glue(glue(\"hello\", \"a\"), \"b\"))\n    assert render(doc, 20) == \"hello\\na\\nb\"\n\n    assert render(doc |> glue(\"c\") |> group(), 20) ==\n             \"hello\\na\\nb\\nc\"\n\n    assert render(doc |> group(:optimistic) |> glue(\"c\") |> group() |> glue(\"d\"), 20) ==\n             \"hello\\na\\nb c d\"\n\n    assert render(doc |> group(:optimistic) |> glue(\"c\") |> group(:pessimistic) |> glue(\"d\"), 20) ==\n             \"hello\\na\\nb c\\nd\"\n  end\n\n  test \"formatting groups with lines\" do\n    doc = line(glue(\"a\", \"b\"), glue(\"hello\", \"world\"))\n    assert render(group(doc), 5) == \"a\\nb\\nhello\\nworld\"\n    assert render(group(doc), 100) == \"a b\\nhello world\"\n  end\n\n  test \"formatting with infinity\" do\n    str = String.duplicate(\"x\", 50)\n    colon = \";\"\n\n    doc =\n      str\n      |> glue(colon, str)\n      |> glue(colon, str)\n      |> glue(colon, str)\n      |> glue(colon, str)\n      |> group()\n\n    assert render(doc, :infinity) ==\n             str <> colon <> str <> colon <> str <> colon <> str <> colon <> str\n  end\n\n  test \"formatting container_doc with empty\" do\n    sm = &container_doc(\"[\", &1, \"]\", %Inspect.Opts{}, fn d, _ -> d end, separator: \",\")\n\n    assert sm.([]) |> render(80) == \"[]\"\n    assert sm.([empty()]) |> render(80) == \"[]\"\n    assert sm.([empty(), empty()]) |> render(80) == \"[]\"\n    assert sm.([\"a\"]) |> render(80) == \"[a]\"\n    assert sm.([\"a\", empty()]) |> render(80) == \"[a]\"\n    assert sm.([empty(), \"a\"]) |> render(80) == \"[a]\"\n    assert sm.([\"a\", empty(), \"b\"]) |> render(80) == \"[a, b]\"\n    assert sm.([empty(), \"a\", \"b\"]) |> render(80) == \"[a, b]\"\n    assert sm.([\"a\", \"b\", empty()]) |> render(80) == \"[a, b]\"\n    assert sm.([\"a\", \"b\" | \"c\"]) |> render(80) == \"[a, b | c]\"\n    assert sm.([\"a\" | \"b\"]) |> render(80) == \"[a | b]\"\n    assert sm.([\"a\" | empty()]) |> render(80) == \"[a]\"\n    assert sm.([empty() | \"b\"]) |> render(80) == \"[b]\"\n  end\n\n  test \"formatting container_doc with empty and limit\" do\n    opts = %Inspect.Opts{limit: 2}\n    value = [\"a\", empty(), \"b\"]\n\n    assert container_doc(\"[\", value, \"]\", opts, fn d, _ -> d end, separator: \",\") |> render(80) ==\n             \"[a, b]\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/inspect_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule Inspect.AtomTest do\n  use ExUnit.Case, async: true\n\n  doctest Inspect\n\n  test \"basic\" do\n    assert inspect(:foo) == \":foo\"\n  end\n\n  test \"empty\" do\n    assert inspect(:\"\") == \":\\\"\\\"\"\n  end\n\n  test \"true, false, nil\" do\n    assert inspect(false) == \"false\"\n    assert inspect(true) == \"true\"\n    assert inspect(nil) == \"nil\"\n  end\n\n  test \"with uppercase letters\" do\n    assert inspect(:fOO) == \":fOO\"\n    assert inspect(:FOO) == \":FOO\"\n  end\n\n  test \"aliases\" do\n    assert inspect(Foo) == \"Foo\"\n    assert inspect(Foo.Bar) == \"Foo.Bar\"\n    assert inspect(Elixir) == \"Elixir\"\n    assert inspect(Elixir.Foo) == \"Foo\"\n    assert inspect(Elixir.Elixir) == \"Elixir.Elixir\"\n    assert inspect(Elixir.Elixir.Foo) == \"Elixir.Elixir.Foo\"\n  end\n\n  test \"with integers\" do\n    assert inspect(User1) == \"User1\"\n    assert inspect(:user1) == \":user1\"\n  end\n\n  test \"with trailing ? or !\" do\n    assert inspect(:foo?) == \":foo?\"\n    assert inspect(:bar!) == \":bar!\"\n    assert inspect(:Foo?) == \":Foo?\"\n  end\n\n  test \"operators\" do\n    assert inspect(:+) == \":+\"\n    assert inspect(:<~) == \":<~\"\n    assert inspect(:~>) == \":~>\"\n    assert inspect(:&&&) == \":&&&\"\n    assert inspect(:\"~~~\") == \":\\\"~~~\\\"\"\n    assert inspect(:<<~) == \":<<~\"\n    assert inspect(:~>>) == \":~>>\"\n    assert inspect(:<~>) == \":<~>\"\n    assert inspect(:+++) == \":+++\"\n    assert inspect(:---) == \":---\"\n  end\n\n  test \"::\" do\n    assert inspect(:\"::\") == ~s[:\"::\"]\n  end\n\n  test \"with @\" do\n    assert inspect(:@) == \":@\"\n    assert inspect(:foo@bar) == \":foo@bar\"\n    assert inspect(:foo@bar@) == \":foo@bar@\"\n    assert inspect(:foo@bar@baz) == \":foo@bar@baz\"\n  end\n\n  test \"others\" do\n    assert inspect(:...) == \":...\"\n    assert inspect(:<<>>) == \":<<>>\"\n    assert inspect(:{}) == \":{}\"\n    assert inspect(:%{}) == \":%{}\"\n    assert inspect(:%) == \":%\"\n    assert inspect(:->) == \":->\"\n  end\n\n  test \"escaping\" do\n    assert inspect(:\"hy-phen\") == ~s(:\"hy-phen\")\n    assert inspect(:\"@hello\") == ~s(:\"@hello\")\n    assert inspect(:\"Wat!?\") == ~s(:\"Wat!?\")\n    assert inspect(:\"'quotes' and \\\"double quotes\\\"\") == ~S(:\"'quotes' and \\\"double quotes\\\"\")\n  end\n\n  test \"colors\" do\n    opts = [syntax_colors: [atom: :red]]\n    assert inspect(:hello, opts) == \"\\e[31m:hello\\e[0m\"\n    opts = [syntax_colors: [reset: :cyan]]\n    assert inspect(:hello, opts) == \":hello\"\n  end\n\n  test \"Unicode\" do\n    assert inspect(:olá) == \":olá\"\n    assert inspect(:Olá) == \":Olá\"\n    assert inspect(:Ólá) == \":Ólá\"\n    assert inspect(:こんにちは世界) == \":こんにちは世界\"\n\n    nfd = :unicode.characters_to_nfd_binary(\"olá\")\n    assert inspect(String.to_atom(nfd)) == \":\\\"#{nfd}\\\"\"\n  end\nend\n\ndefmodule Inspect.BitStringTest do\n  use ExUnit.Case, async: true\n\n  test \"bitstring\" do\n    assert inspect(<<1::12-integer-signed>>) == \"<<0, 1::size(4)>>\"\n\n    assert inspect(<<1::12-integer-signed>>, syntax_colors: [number: :blue]) ==\n             \"<<\\e[34m0\\e[0m, \\e[34m1\\e[0m::size(4)>>\"\n\n    assert inspect(<<1, 2, 3, 4, 5>>, pretty: true, width: 10) == \"<<1, 2, 3,\\n  4, 5>>\"\n  end\n\n  test \"binary\" do\n    assert inspect(\"foo\") == \"\\\"foo\\\"\"\n    assert inspect(<<?a, ?b, ?c>>) == \"\\\"abc\\\"\"\n  end\n\n  test \"escaping\" do\n    assert inspect(\"f\\no\") == \"\\\"f\\\\no\\\"\"\n    assert inspect(\"f\\\\o\") == \"\\\"f\\\\\\\\o\\\"\"\n    assert inspect(\"f\\ao\") == \"\\\"f\\\\ao\\\"\"\n\n    assert inspect(\"\\a\\b\\d\\e\\f\\n\\r\\s\\t\\v\") == \"\\\"\\\\a\\\\b\\\\d\\\\e\\\\f\\\\n\\\\r \\\\t\\\\v\\\"\"\n  end\n\n  test \"UTF-8\" do\n    assert inspect(\" ゆんゆん\") == \"\\\" ゆんゆん\\\"\"\n    # BOM\n    assert inspect(\"\\uFEFFhello world\") == \"\\\"\\\\uFEFFhello world\\\"\"\n    # Invisible characters\n    assert inspect(\"\\u2063\") == \"\\\"\\\\u2063\\\"\"\n  end\n\n  test \"infer\" do\n    assert inspect(<<\"john\", 193, \"doe\">>, binaries: :infer) ==\n             ~s(<<106, 111, 104, 110, 193, 100, 111, 101>>)\n\n    assert inspect(<<\"john\">>, binaries: :infer) == ~s(\"john\")\n    assert inspect(<<193>>, binaries: :infer) == ~s(<<193>>)\n  end\n\n  test \"as strings\" do\n    assert inspect(<<\"john\", 193, \"doe\">>, binaries: :as_strings) == ~s(\"john\\\\xC1doe\")\n    assert inspect(<<\"john\">>, binaries: :as_strings) == ~s(\"john\")\n    assert inspect(<<193>>, binaries: :as_strings) == ~s(\"\\\\xC1\")\n    assert inspect(<<193>>, base: :hex, binaries: :as_strings) == ~s(\"\\\\xC1\")\n  end\n\n  test \"as binaries\" do\n    assert inspect(<<\"john\", 193, \"doe\">>, binaries: :as_binaries) ==\n             \"<<106, 111, 104, 110, 193, 100, 111, 101>>\"\n\n    assert inspect(<<\"john\">>, binaries: :as_binaries) == \"<<106, 111, 104, 110>>\"\n    assert inspect(<<193>>, binaries: :as_binaries) == \"<<193>>\"\n\n    # Any base other than :decimal implies \"binaries: :as_binaries\"\n    assert inspect(\"abc\", base: :hex) == \"<<0x61, 0x62, 0x63>>\"\n    assert inspect(\"abc\", base: :octal) == \"<<0o141, 0o142, 0o143>>\"\n\n    # Size is still represented as decimal\n    assert inspect(<<10, 11, 12::4>>, base: :hex) == \"<<0xA, 0xB, 0xC::size(4)>>\"\n  end\n\n  test \"unprintable with limit\" do\n    assert inspect(<<193, 193, 193, 193>>, limit: 3) == \"<<193, 193, 193, ...>>\"\n  end\n\n  test \"printable limit\" do\n    assert inspect(\"hello world\", printable_limit: 4) == ~s(\"hell\" <> ...)\n\n    # Non-printable characters after the limit don't matter\n    assert inspect(\"hello world\" <> <<0>>, printable_limit: 4) == ~s(\"hell\" <> ...)\n\n    # Non printable strings aren't affected by printable limit\n    assert inspect(<<0, 1, 2, 3, 4>>, printable_limit: 3) == ~s(<<0, 1, 2, 3, 4>>)\n  end\nend\n\ndefmodule Inspect.NumberTest do\n  use ExUnit.Case, async: true\n\n  test \"integer\" do\n    assert inspect(100) == \"100\"\n  end\n\n  test \"decimal\" do\n    assert inspect(100, base: :decimal) == \"100\"\n  end\n\n  test \"hex\" do\n    assert inspect(100, base: :hex) == \"0x64\"\n    assert inspect(-100, base: :hex) == \"-0x64\"\n  end\n\n  test \"octal\" do\n    assert inspect(100, base: :octal) == \"0o144\"\n    assert inspect(-100, base: :octal) == \"-0o144\"\n  end\n\n  test \"binary\" do\n    assert inspect(86, base: :binary) == \"0b1010110\"\n    assert inspect(-86, base: :binary) == \"-0b1010110\"\n  end\n\n  test \"float\" do\n    assert inspect(1.0) == \"1.0\"\n    assert inspect(1.0e10) == \"10000000000.0\"\n    assert inspect(1.0e-10) == \"1.0e-10\"\n  end\n\n  test \"integer colors\" do\n    opts = [syntax_colors: [number: :red]]\n    assert inspect(123, opts) == \"\\e[31m123\\e[0m\"\n    opts = [syntax_colors: [reset: :cyan]]\n    assert inspect(123, opts) == \"123\"\n  end\n\n  test \"float colors\" do\n    opts = [syntax_colors: [number: :red]]\n    assert inspect(1.3, opts) == \"\\e[31m1.3\\e[0m\"\n    opts = [syntax_colors: [reset: :cyan]]\n    assert inspect(1.3, opts) == \"1.3\"\n  end\nend\n\ndefmodule Inspect.TupleTest do\n  use ExUnit.Case, async: true\n\n  test \"basic\" do\n    assert inspect({1, \"b\", 3}) == \"{1, \\\"b\\\", 3}\"\n    assert inspect({1, \"b\", 3}, pretty: true, width: 1) == \"{1,\\n \\\"b\\\",\\n 3}\"\n    assert inspect({1, \"b\", 3}, pretty: true, width: 10) == \"{1, \\\"b\\\",\\n 3}\"\n  end\n\n  test \"empty\" do\n    assert inspect({}) == \"{}\"\n  end\n\n  test \"with limit\" do\n    assert inspect({1, 2, 3, 4}, limit: 3) == \"{1, 2, 3, ...}\"\n  end\n\n  test \"colors\" do\n    opts = [syntax_colors: []]\n    assert inspect({}, opts) == \"{}\"\n\n    opts = [syntax_colors: [reset: :cyan]]\n    assert inspect({}, opts) == \"{}\"\n    assert inspect({:x, :y}, opts) == \"{:x, :y}\"\n\n    opts = [syntax_colors: [reset: :cyan, atom: :red]]\n    assert inspect({}, opts) == \"{}\"\n    assert inspect({:x, :y}, opts) == \"{\\e[31m:x\\e[36m, \\e[31m:y\\e[36m}\"\n\n    opts = [syntax_colors: [tuple: :green, reset: :cyan, atom: :red]]\n    assert inspect({}, opts) == \"\\e[32m{\\e[36m\\e[32m}\\e[36m\"\n\n    assert inspect({:x, :y}, opts) ==\n             \"\\e[32m{\\e[36m\\e[31m:x\\e[36m\\e[32m,\\e[36m \\e[31m:y\\e[36m\\e[32m}\\e[36m\"\n  end\nend\n\ndefmodule Inspect.ListTest do\n  use ExUnit.Case, async: true\n\n  test \"basic\" do\n    assert inspect([1, \"b\", 3]) == \"[1, \\\"b\\\", 3]\"\n    assert inspect([1, \"b\", 3], pretty: true, width: 1) == \"[1,\\n \\\"b\\\",\\n 3]\"\n  end\n\n  test \"printable\" do\n    assert inspect(~c\"abc\") == ~s(~c\"abc\")\n  end\n\n  test \"printable limit\" do\n    assert inspect(~c\"hello world\", printable_limit: 4) == ~s(~c\"hell\" ++ ...)\n    # Non printable characters after the limit don't matter\n    assert inspect(~c\"hello world\" ++ [0], printable_limit: 4) == ~s(~c\"hell\" ++ ...)\n    # Non printable strings aren't affected by printable limit\n    assert inspect([0, 1, 2, 3, 4], printable_limit: 3) == ~s([0, 1, 2, 3, 4])\n  end\n\n  test \"keyword\" do\n    assert inspect(a: 1) == \"[a: 1]\"\n    assert inspect(a: 1, b: 2) == \"[a: 1, b: 2]\"\n    assert inspect(a: 1, a: 2, b: 2) == \"[a: 1, a: 2, b: 2]\"\n    assert inspect(\"123\": 1) == ~s([\"123\": 1])\n\n    assert inspect([foo: [1, 2, 3], baz: [4, 5, 6]], pretty: true, width: 20) ==\n             \"[\\n  foo: [1, 2, 3],\\n  baz: [4, 5, 6]\\n]\"\n  end\n\n  test \"keyword operators\" do\n    assert inspect(\"::\": 1, +: 2) == ~s([\"::\": 1, +: 2])\n  end\n\n  test \"opt infer\" do\n    assert inspect(~c\"john\" ++ [0] ++ ~c\"doe\", charlists: :infer) ==\n             \"[106, 111, 104, 110, 0, 100, 111, 101]\"\n\n    assert inspect(~c\"john\", charlists: :infer) == ~s(~c\"john\")\n    assert inspect([0], charlists: :infer) == \"[0]\"\n  end\n\n  test \"opt as strings\" do\n    assert inspect(~c\"john\" ++ [0] ++ ~c\"doe\", charlists: :as_charlists) == ~s(~c\"john\\\\0doe\")\n    assert inspect(~c\"john\", charlists: :as_charlists) == ~s(~c\"john\")\n    assert inspect([0], charlists: :as_charlists) == ~s(~c\"\\\\0\")\n  end\n\n  test \"opt as lists\" do\n    assert inspect(~c\"john\" ++ [0] ++ ~c\"doe\", charlists: :as_lists) ==\n             \"[106, 111, 104, 110, 0, 100, 111, 101]\"\n\n    assert inspect(~c\"john\", charlists: :as_lists) == \"[106, 111, 104, 110]\"\n    assert inspect([0], charlists: :as_lists) == \"[0]\"\n  end\n\n  test \"non printable\" do\n    assert inspect([{:b, 1}, {:a, 1}]) == \"[b: 1, a: 1]\"\n  end\n\n  test \"improper\" do\n    assert inspect([:foo | :bar]) == \"[:foo | :bar]\"\n\n    assert inspect([1, 2, 3, 4, 5 | 42], pretty: true, width: 1) ==\n             \"[1,\\n 2,\\n 3,\\n 4,\\n 5 |\\n 42]\"\n  end\n\n  test \"nested\" do\n    assert inspect(Enum.reduce(1..5, [0], &[&2, &1]), limit: 5) ==\n             \"[[[[[[...], ...], ...], ...], ...], ...]\"\n\n    assert inspect(Enum.reduce(1..5, [0], &[&2, &1]), limit: 10) ==\n             \"[[[[[[0], 1], 2], 3], 4], ...]\"\n\n    assert inspect(Enum.reduce(1..6, [0], &[&2, &1]), limit: 10) ==\n             \"[[[[[[[0], 1], 2], 3], ...], ...], ...]\"\n\n    assert inspect(Enum.reduce(1..100, [0], &[&2 | &1]), limit: 5) ==\n             \"[[[[[[...] | 96] | 97] | 98] | 99] | 100]\"\n  end\n\n  test \"codepoints\" do\n    assert inspect(~c\"é\") == \"[233]\"\n  end\n\n  test \"empty\" do\n    assert inspect([]) == \"[]\"\n  end\n\n  test \"with limit\" do\n    assert inspect([1, 2, 3, 4], limit: 3) == \"[1, 2, 3, ...]\"\n  end\n\n  test \"colors\" do\n    opts = [syntax_colors: []]\n    assert inspect([], opts) == \"[]\"\n\n    opts = [syntax_colors: [reset: :cyan]]\n    assert inspect([], opts) == \"[]\"\n    assert inspect([:x, :y], opts) == \"[:x, :y]\"\n\n    opts = [syntax_colors: [reset: :cyan, atom: :red]]\n    assert inspect([], opts) == \"[]\"\n    assert inspect([:x, :y], opts) == \"[\\e[31m:x\\e[36m, \\e[31m:y\\e[36m]\"\n\n    opts = [syntax_colors: [reset: :cyan, atom: :red, list: :green]]\n    assert inspect([], opts) == \"\\e[32m[]\\e[36m\"\n\n    assert inspect([:x, :y], opts) ==\n             \"\\e[32m[\\e[36m\\e[31m:x\\e[36m\\e[32m,\\e[36m \\e[31m:y\\e[36m\\e[32m]\\e[36m\"\n  end\n\n  test \"keyword with colors\" do\n    opts = [syntax_colors: [reset: :cyan, list: :green, number: :blue]]\n    assert inspect([], opts) == \"\\e[32m[]\\e[36m\"\n\n    assert inspect([a: 9999], opts) == \"\\e[32m[\\e[36ma: \\e[34m9999\\e[36m\\e[32m]\\e[36m\"\n\n    opts = [syntax_colors: [reset: :cyan, atom: :red, list: :green, number: :blue]]\n    assert inspect([], opts) == \"\\e[32m[]\\e[36m\"\n\n    assert inspect([a: 9999], opts) == \"\\e[32m[\\e[36m\\e[31ma:\\e[36m \\e[34m9999\\e[36m\\e[32m]\\e[36m\"\n  end\n\n  test \"limit with colors\" do\n    opts = [limit: 1, syntax_colors: [reset: :cyan, list: :green, atom: :red]]\n    assert inspect([], opts) == \"\\e[32m[]\\e[36m\"\n\n    assert inspect([:x, :y], opts) == \"\\e[32m[\\e[36m\\e[31m:x\\e[36m\\e[32m,\\e[36m ...\\e[32m]\\e[36m\"\n  end\nend\n\ndefmodule Inspect.MapTest do\n  use ExUnit.Case, async: true\n\n  test \"basic\" do\n    assert inspect(%{1 => \"b\"}) == \"%{1 => \\\"b\\\"}\"\n\n    assert inspect(%{1 => \"b\", 2 => \"c\"},\n             pretty: true,\n             width: 1,\n             custom_options: [sort_maps: true]\n           ) ==\n             \"%{\\n  1 => \\\"b\\\",\\n  2 => \\\"c\\\"\\n}\"\n  end\n\n  test \"keyword\" do\n    assert inspect(%{a: 1}) == \"%{a: 1}\"\n    assert inspect(%{a: 1, b: 2}, custom_options: [sort_maps: true]) == \"%{a: 1, b: 2}\"\n\n    assert inspect(%{a: 1, b: 2, c: 3}, custom_options: [sort_maps: true]) ==\n             \"%{a: 1, b: 2, c: 3}\"\n  end\n\n  test \"with limit\" do\n    assert inspect(%{1 => 1, 2 => 2, 3 => 3, 4 => 4}, limit: 3) ==\n             \"%{1 => 1, 2 => 2, 3 => 3, ...}\"\n  end\n\n  defmodule Public do\n    defstruct key: 0\n  end\n\n  defmodule Private do\n  end\n\n  test \"public struct\" do\n    assert inspect(%Public{key: 1}) == \"%Inspect.MapTest.Public{key: 1}\"\n  end\n\n  test \"public modified struct\" do\n    public = %Public{key: 1}\n\n    assert inspect(Map.put(public, :foo, :bar), custom_options: [sort_maps: true]) ==\n             \"%{__struct__: Inspect.MapTest.Public, foo: :bar, key: 1}\"\n  end\n\n  test \"public modified struct with defimpl\" do\n    map_set = MapSet.new([1, 2])\n\n    assert inspect(Map.put(map_set, :foo, :bar), custom_options: [sort_maps: true]) ==\n             \"%{__struct__: MapSet, foo: :bar, map: %{1 => [], 2 => []}}\"\n  end\n\n  test \"private struct\" do\n    assert inspect(%{__struct__: Private, key: 1}, custom_options: [sort_maps: true]) ==\n             \"%{__struct__: Inspect.MapTest.Private, key: 1}\"\n  end\n\n  defmodule Failing do\n    @enforce_keys [:name]\n    defstruct @enforce_keys\n\n    defimpl Inspect do\n      def inspect(%Failing{name: name}, _) do\n        Atom.to_string(name)\n      end\n    end\n  end\n\n  test \"safely inspect bad implementation\" do\n    assert_raise ArgumentError, ~r/argument error/, fn ->\n      raise(ArgumentError)\n    end\n\n    message = ~s'''\n    #Inspect.Error<\n      got ArgumentError with message:\n\n          \"\"\"\n          errors were found at the given arguments:\n\n            * 1st argument: not an atom\n          \"\"\"\n\n      while inspecting:\n\n          %{__struct__: Inspect.MapTest.Failing, name: \"Foo\"}\n    '''\n\n    assert inspect(%Failing{name: \"Foo\"}, custom_options: [sort_maps: true]) =~ message\n  end\n\n  test \"safely inspect bad implementation disables colors\" do\n    message = ~s'''\n    #Inspect.Error<\n      got ArgumentError with message:\n\n          \"\"\"\n          errors were found at the given arguments:\n\n            * 1st argument: not an atom\n          \"\"\"\n\n      while inspecting:\n\n          %{__struct__: Inspect.MapTest.Failing, name: \"Foo\"}\n    '''\n\n    assert inspect(%Failing{name: \"Foo\"},\n             syntax_colors: [atom: [:green]],\n             custom_options: [sort_maps: true]\n           ) =~ message\n  end\n\n  test \"unsafely inspect bad implementation\" do\n    exception_message = ~s'''\n    got ArgumentError with message:\n\n        \"\"\"\n        errors were found at the given arguments:\n\n          * 1st argument: not an atom\n        \"\"\"\n\n    while inspecting:\n\n        %{__struct__: Inspect.MapTest.Failing, name: \"Foo\"}\n    '''\n\n    try do\n      inspect(%Failing{name: \"Foo\"}, safe: false, custom_options: [sort_maps: true])\n    rescue\n      exception in Inspect.Error ->\n        assert Exception.message(exception) =~ exception_message\n        assert [{:erlang, :atom_to_binary, [_], [_ | _]} | _] = __STACKTRACE__\n    else\n      _ -> flunk(\"expected failure\")\n    end\n  end\n\n  test \"raise when trying to inspect with a bad implementation from inside another exception that is being raised\" do\n    # Inspect.Error is raised here when we tried to print the error message\n    # called by another exception (Protocol.UndefinedError in this case)\n    exception_message = ~s'''\n    protocol Enumerable not implemented for Inspect.MapTest.Failing (a struct)\n\n    Got value:\n\n        #Inspect.Error<\n          got ArgumentError with message:\n\n              \"\"\"\n              errors were found at the given arguments:\n\n                * 1st argument: not an atom\n              \"\"\"\n\n          while inspecting:\n\n    '''\n\n    try do\n      Enum.to_list(%Failing{name: \"Foo\"})\n    rescue\n      exception in Protocol.UndefinedError ->\n        message = Exception.message(exception)\n        assert message =~ exception_message\n        assert message =~ \"__struct__: Inspect.MapTest.Failing\"\n        assert message =~ \"name: \\\"Foo\\\"\"\n\n        assert [\n                 {Enumerable, :impl_for!, 1, _} | _\n               ] = __STACKTRACE__\n\n        # The culprit\n        assert Enum.any?(__STACKTRACE__, fn\n                 {Enum, :to_list, 1, _} -> true\n                 _ -> false\n               end)\n\n        # The line calling the culprit\n        assert Enum.any?(__STACKTRACE__, fn\n                 {Inspect.MapTest, _test_name, 1, file: file, line: _line_number} ->\n                   String.ends_with?(List.to_string(file), \"test/elixir/inspect_test.exs\")\n\n                 _ ->\n                   false\n               end)\n    else\n      _ -> flunk(\"expected failure\")\n    end\n  end\n\n  test \"Exception.message/1 with bad implementation\" do\n    failing = %Failing{name: \"Foo\"}\n\n    message = ~s'''\n    #Inspect.Error<\n      got ArgumentError with message:\n\n          \"\"\"\n          errors were found at the given arguments:\n\n            * 1st argument: not an atom\n          \"\"\"\n\n      while inspecting:\n\n          %{__struct__: Inspect.MapTest.Failing, name: \"Foo\"}\n    '''\n\n    {my_argument_error, stacktrace} =\n      try do\n        atom_to_string(Process.get(:unused, failing.name))\n      rescue\n        e -> {e, __STACKTRACE__}\n      end\n\n    inspected =\n      inspect(\n        Inspect.Error.exception(\n          exception: my_argument_error,\n          stacktrace: stacktrace,\n          inspected_struct: \"%{__struct__: Inspect.MapTest.Failing, name: \\\"Foo\\\"}\"\n        )\n      )\n\n    assert inspect(failing, custom_options: [sort_maps: true]) =~ message\n    assert inspected =~ message\n  end\n\n  defp atom_to_string(atom) do\n    Atom.to_string(atom)\n  end\n\n  test \"exception\" do\n    assert inspect(%RuntimeError{message: \"runtime error\"}) ==\n             \"%RuntimeError{message: \\\"runtime error\\\"}\"\n  end\n\n  test \"colors\" do\n    opts = [syntax_colors: [reset: :cyan, atom: :red, number: :magenta]]\n    assert inspect(%{1 => 2}, opts) == \"%{\\e[35m1\\e[36m => \\e[35m2\\e[36m}\"\n\n    assert inspect(%{a: 1}, opts) == \"%{\\e[31ma:\\e[36m \\e[35m1\\e[36m}\"\n\n    assert inspect(%Public{key: 1}, opts) ==\n             \"%Inspect.MapTest.Public{\\e[31mkey:\\e[36m \\e[35m1\\e[36m}\"\n\n    opts = [syntax_colors: [reset: :cyan, atom: :red, map: :green, number: :blue]]\n\n    assert inspect(%{a: 9999}, opts) ==\n             \"\\e[32m%{\\e[36m\" <> \"\\e[31ma:\\e[36m \" <> \"\\e[34m9999\\e[36m\" <> \"\\e[32m}\\e[36m\"\n  end\n\n  defmodule StructWithoutOptions do\n    @derive Inspect\n    defstruct [:a, :b, :c, :d]\n  end\n\n  test \"struct without options\" do\n    struct = %StructWithoutOptions{a: 1, b: 2, c: 3, d: 4}\n    assert inspect(struct) == \"%Inspect.MapTest.StructWithoutOptions{a: 1, b: 2, c: 3, d: 4}\"\n\n    assert inspect(struct, pretty: true, width: 1) ==\n             \"%Inspect.MapTest.StructWithoutOptions{\\n  a: 1,\\n  b: 2,\\n  c: 3,\\n  d: 4\\n}\"\n  end\n\n  defmodule StructWithOnlyOption do\n    @derive {Inspect, only: [:b, :c]}\n    defstruct [:a, :b, :c, :d]\n  end\n\n  test \"struct with :only option\" do\n    struct = %StructWithOnlyOption{a: 1, b: 2, c: 3, d: 4}\n    assert inspect(struct) == \"#Inspect.MapTest.StructWithOnlyOption<b: 2, c: 3, ...>\"\n\n    assert inspect(struct, pretty: true, width: 1) ==\n             \"#Inspect.MapTest.StructWithOnlyOption<\\n  b: 2,\\n  c: 3,\\n  ...\\n>\"\n\n    struct = %{struct | c: [1, 2, 3, 4]}\n    assert inspect(struct) == \"#Inspect.MapTest.StructWithOnlyOption<b: 2, c: [1, 2, 3, 4], ...>\"\n  end\n\n  defmodule StructWithEmptyOnlyOption do\n    @derive {Inspect, only: []}\n    defstruct [:a, :b, :c, :d]\n  end\n\n  test \"struct with empty :only option\" do\n    struct = %StructWithEmptyOnlyOption{a: 1, b: 2, c: 3, d: 4}\n    assert inspect(struct) == \"#Inspect.MapTest.StructWithEmptyOnlyOption<...>\"\n  end\n\n  defmodule StructWithAllFieldsInOnlyOption do\n    @derive {Inspect, only: [:a, :b]}\n    defstruct [:a, :b]\n  end\n\n  test \"struct with all fields in the :only option\" do\n    struct = %StructWithAllFieldsInOnlyOption{a: 1, b: 2}\n    assert inspect(struct) == \"%Inspect.MapTest.StructWithAllFieldsInOnlyOption{a: 1, b: 2}\"\n\n    assert inspect(struct, pretty: true, width: 1) ==\n             \"%Inspect.MapTest.StructWithAllFieldsInOnlyOption{\\n  a: 1,\\n  b: 2\\n}\"\n  end\n\n  test \"struct missing fields in the :only option\" do\n    assert_raise ArgumentError,\n                 \"unknown fields [:c] in :only when deriving the Inspect protocol for Inspect.MapTest.StructMissingFieldsInOnlyOption\",\n                 fn ->\n                   defmodule StructMissingFieldsInOnlyOption do\n                     @derive {Inspect, only: [:c]}\n                     defstruct [:a, :b]\n                   end\n                 end\n  end\n\n  test \"struct missing fields in the :except option\" do\n    assert_raise ArgumentError,\n                 \"unknown fields [:c, :d] in :except when deriving the Inspect protocol for Inspect.MapTest.StructMissingFieldsInExceptOption\",\n                 fn ->\n                   defmodule StructMissingFieldsInExceptOption do\n                     @derive {Inspect, except: [:c, :d]}\n                     defstruct [:a, :b]\n                   end\n                 end\n  end\n\n  test \"passing a non-list to the :only option\" do\n    assert_raise ArgumentError,\n                 \"invalid value :not_a_list in :only when deriving the Inspect protocol for Inspect.MapTest.StructInvalidListInOnlyOption (expected a list)\",\n                 fn ->\n                   defmodule StructInvalidListInOnlyOption do\n                     @derive {Inspect, only: :not_a_list}\n                     defstruct [:a, :b]\n                   end\n                 end\n  end\n\n  defmodule StructWithExceptOption do\n    @derive {Inspect, except: [:b, :c]}\n    defstruct [:a, :b, :c, :d]\n  end\n\n  test \"struct with :except option\" do\n    struct = %StructWithExceptOption{a: 1, b: 2, c: 3, d: 4}\n    assert inspect(struct) == \"#Inspect.MapTest.StructWithExceptOption<a: 1, d: 4, ...>\"\n\n    assert inspect(struct, pretty: true, width: 1) ==\n             \"#Inspect.MapTest.StructWithExceptOption<\\n  a: 1,\\n  d: 4,\\n  ...\\n>\"\n  end\n\n  defmodule StructWithBothOnlyAndExceptOptions do\n    @derive {Inspect, only: [:a, :b], except: [:b, :c]}\n    defstruct [:a, :b, :c, :d]\n  end\n\n  test \"struct with both :only and :except options\" do\n    struct = %StructWithBothOnlyAndExceptOptions{a: 1, b: 2, c: 3, d: 4}\n    assert inspect(struct) == \"#Inspect.MapTest.StructWithBothOnlyAndExceptOptions<a: 1, ...>\"\n\n    assert inspect(struct, pretty: true, width: 1) ==\n             \"#Inspect.MapTest.StructWithBothOnlyAndExceptOptions<\\n  a: 1,\\n  ...\\n>\"\n  end\n\n  defmodule StructWithOptionalAndOrder do\n    @derive {Inspect, optional: [:b, :c]}\n    defstruct [:c, :d, :a, :b]\n  end\n\n  test \"struct with both :order and :optional options\" do\n    struct = %StructWithOptionalAndOrder{a: 1, b: 2, c: 3, d: 4}\n\n    assert inspect(struct) ==\n             \"%Inspect.MapTest.StructWithOptionalAndOrder{c: 3, d: 4, a: 1, b: 2}\"\n\n    struct = %StructWithOptionalAndOrder{}\n    assert inspect(struct) == \"%Inspect.MapTest.StructWithOptionalAndOrder{d: nil, a: nil}\"\n  end\n\n  defmodule StructWithExceptOptionalAndOrder do\n    @derive {Inspect, optional: [:b, :c], except: [:e]}\n    defstruct [:c, :d, :e, :a, :b]\n  end\n\n  test \"struct with :except, :order, and :optional options\" do\n    struct = %StructWithExceptOptionalAndOrder{a: 1, b: 2, c: 3, d: 4}\n\n    assert inspect(struct) ==\n             \"#Inspect.MapTest.StructWithExceptOptionalAndOrder<c: 3, d: 4, a: 1, b: 2, ...>\"\n\n    struct = %StructWithExceptOptionalAndOrder{}\n\n    assert inspect(struct) ==\n             \"#Inspect.MapTest.StructWithExceptOptionalAndOrder<d: nil, a: nil, ...>\"\n  end\n\n  defmodule StructWithOptionalAll do\n    @derive {Inspect, optional: :all}\n    defstruct [:a, :b, :c, :d]\n  end\n\n  test \"struct with :optional set to :all\" do\n    struct = %StructWithOptionalAll{a: 1, b: 2}\n\n    assert inspect(struct) == \"%Inspect.MapTest.StructWithOptionalAll{a: 1, b: 2}\"\n\n    struct = %StructWithOptionalAll{}\n    assert inspect(struct) == \"%Inspect.MapTest.StructWithOptionalAll{}\"\n  end\nend\n\ndefmodule Inspect.OthersTest do\n  use ExUnit.Case, async: true\n\n  def fun() do\n    fn -> :ok end\n  end\n\n  def unquote(:\"weirdly named/fun-\")() do\n    fn -> :ok end\n  end\n\n  test \"external Elixir funs\" do\n    bin = inspect(&Enum.map/2)\n    assert bin == \"&Enum.map/2\"\n\n    assert inspect(&__MODULE__.\"weirdly named/fun-\"/0) ==\n             ~s(&Inspect.OthersTest.\"weirdly named/fun-\"/0)\n  end\n\n  test \"external Erlang funs\" do\n    bin = inspect(&:lists.map/2)\n    assert bin == \"&:lists.map/2\"\n  end\n\n  test \"outdated functions\" do\n    defmodule V do\n      def fun do\n        fn -> 1 end\n      end\n    end\n\n    Application.put_env(:elixir, :anony, V.fun())\n    Application.put_env(:elixir, :named, &V.fun/0)\n\n    :code.purge(V)\n    :code.delete(V)\n\n    anony = Application.get_env(:elixir, :anony)\n    named = Application.get_env(:elixir, :named)\n\n    assert inspect(anony) =~ ~r\"#Function<0.\\d+/0\"\n    assert inspect(named) =~ ~r\"&Inspect.OthersTest.V.fun/0\"\n  after\n    Application.delete_env(:elixir, :anony)\n    Application.delete_env(:elixir, :named)\n  end\n\n  test \"other funs\" do\n    assert \"#Function<\" <> _ = inspect(fn x -> x + 1 end)\n    assert \"#Function<\" <> _ = inspect(fun())\n    opts = [syntax_colors: []]\n    assert \"#Function<\" <> _ = inspect(fun(), opts)\n    opts = [syntax_colors: [reset: :red]]\n    assert \"#Function<\" <> rest = inspect(fun(), opts)\n    assert String.ends_with?(rest, \">\")\n\n    inspected = inspect(__MODULE__.\"weirdly named/fun-\"())\n    assert inspected =~ ~r(#Function<\\d+\\.\\d+/0 in Inspect\\.OthersTest\\.\"weirdly named/fun-\"/0>)\n  end\n\n  test \"map set\" do\n    assert \"MapSet.new(\" <> _ = inspect(MapSet.new())\n  end\n\n  test \"PIDs\" do\n    assert \"#PID<\" <> _ = inspect(self())\n    opts = [syntax_colors: []]\n    assert \"#PID<\" <> _ = inspect(self(), opts)\n    opts = [syntax_colors: [reset: :cyan]]\n    assert \"#PID<\" <> rest = inspect(self(), opts)\n    assert String.ends_with?(rest, \">\")\n  end\n\n  test \"references\" do\n    assert \"#Reference<\" <> _ = inspect(make_ref())\n  end\n\n  test \"regex\" do\n    assert inspect(~r(foo)m) == \"~r/foo/m\"\n    assert inspect(~r[\\\\\\#{2,}]iu) == ~S\"~r/\\\\\\#{2,}/iu\"\n\n    assert inspect(Regex.compile!(\"a\\\\/b\")) == \"~r/a\\\\/b/\"\n\n    assert inspect(Regex.compile!(\"\\a\\b\\d\\e\\f\\n\\r\\s\\t\\v/\")) ==\n             \"~r/\\\\a\\\\x08\\\\x7F\\\\x1B\\\\f\\\\n\\\\r \\\\t\\\\v\\\\//\"\n\n    assert inspect(~r<\\a\\b\\d\\e\\f\\n\\r\\s\\t\\v/>) == \"~r/\\\\a\\\\b\\\\d\\\\e\\\\f\\\\n\\\\r\\\\s\\\\t\\\\v\\\\//\"\n    assert inspect(~r\" \\\\/ \") == \"~r/ \\\\\\\\\\\\/ /\"\n    assert inspect(~r/hi/, syntax_colors: [regex: :red]) == \"\\e[31m~r/hi/\\e[0m\"\n\n    assert inspect(Regex.compile!(\"foo\", \"i\")) == \"~r/foo/i\"\n    assert inspect(Regex.compile!(\"foo\", [:ucp])) == ~S'Regex.compile!(\"foo\", [:ucp])'\n  end\n\n  @tag :re_import\n  test \"exported regex\" do\n    assert inspect(~r/foo/E) == \"~r/foo/E\"\n  end\n\n  test \"inspect_fun\" do\n    fun = fn\n      integer, _opts when is_integer(integer) ->\n        \"<#{integer}>\"\n\n      %URI{} = uri, _opts ->\n        \"#URI<#{uri}>\"\n\n      term, opts ->\n        Inspect.inspect(term, opts)\n    end\n\n    opts = [inspect_fun: fun]\n\n    assert inspect(1000, opts) == \"<1000>\"\n    assert inspect([1000], opts) == \"[<1000>]\"\n\n    uri = URI.parse(\"https://elixir-lang.org\")\n    assert inspect(uri, opts) == \"#URI<https://elixir-lang.org>\"\n    assert inspect([uri], opts) == \"[#URI<https://elixir-lang.org>]\"\n  end\n\n  defmodule Nested do\n    defstruct nested: nil\n\n    defimpl Inspect do\n      import Inspect.Algebra\n\n      def inspect(%Nested{nested: nested}, opts) do\n        indent = Keyword.get(opts.custom_options, :indent, 2)\n        level = Keyword.get(opts.custom_options, :level, 1)\n\n        nested_str =\n          Kernel.inspect(nested, custom_options: [level: level + 1, indent: indent + 2])\n\n        concat(\n          nest(line(\"#Nested[##{level}/#{indent}]<\", nested_str), indent),\n          nest(line(\"\", \">\"), indent - 2)\n        )\n      end\n    end\n  end\n\n  test \"custom_options\" do\n    assert inspect(%Nested{nested: %Nested{nested: 42}}) ==\n             \"#Nested[#1/2]<\\n  #Nested[#2/4]<\\n    42\\n  >\\n>\"\n  end\nend\n\ndefmodule Inspect.CustomProtocolTest do\n  use ExUnit.Case, async: true\n\n  defprotocol CustomInspect do\n    def inspect(term, opts)\n  end\n\n  defmodule MissingImplementation do\n    defstruct []\n  end\n\n  test \"unsafely inspect missing implementation\" do\n    msg = ~S'''\n    got Protocol.UndefinedError with message:\n\n        \"\"\"\n        protocol Inspect.CustomProtocolTest.CustomInspect not implemented for Inspect.CustomProtocolTest.MissingImplementation (a struct)\n\n        Got value:\n\n            %Inspect.CustomProtocolTest.MissingImplementation{}\n        \"\"\"\n\n    while inspecting:\n\n        %{__struct__: Inspect.CustomProtocolTest.MissingImplementation}\n    '''\n\n    opts = [safe: false, inspect_fun: &CustomInspect.inspect/2]\n\n    try do\n      inspect(%MissingImplementation{}, opts)\n    rescue\n      e in Inspect.Error ->\n        assert Exception.message(e) =~ msg\n        assert [{Inspect.CustomProtocolTest.CustomInspect, :impl_for!, 1, _} | _] = __STACKTRACE__\n    else\n      _ -> flunk(\"expected failure\")\n    end\n  end\n\n  test \"safely inspect missing implementation\" do\n    msg = ~S'''\n    #Inspect.Error<\n      got Protocol.UndefinedError with message:\n\n          \"\"\"\n          protocol Inspect.CustomProtocolTest.CustomInspect not implemented for Inspect.CustomProtocolTest.MissingImplementation (a struct)\n\n          Got value:\n\n              %Inspect.CustomProtocolTest.MissingImplementation{}\n          \"\"\"\n\n      while inspecting:\n\n          %{__struct__: Inspect.CustomProtocolTest.MissingImplementation}\n    '''\n\n    opts = [inspect_fun: &CustomInspect.inspect/2]\n    assert inspect(%MissingImplementation{}, opts) =~ msg\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/integer_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule IntegerTest do\n  use ExUnit.Case, async: true\n\n  doctest Integer\n\n  require Integer\n\n  def test_is_odd_in_guards(number) when Integer.is_odd(number), do: number\n  def test_is_odd_in_guards(_number), do: false\n\n  def test_is_even_in_guards(number) when Integer.is_even(number), do: number\n  def test_is_even_in_guards(_number), do: false\n\n  test \"is_odd/1\" do\n    assert Integer.is_odd(0) == false\n    assert Integer.is_odd(1) == true\n    assert Integer.is_odd(2) == false\n    assert Integer.is_odd(3) == true\n    assert Integer.is_odd(-1) == true\n    assert Integer.is_odd(-2) == false\n    assert Integer.is_odd(-3) == true\n    assert test_is_odd_in_guards(10) == false\n    assert test_is_odd_in_guards(11) == 11\n    assert test_is_odd_in_guards(:not_integer) == false\n  end\n\n  test \"is_even/1\" do\n    assert Integer.is_even(0) == true\n    assert Integer.is_even(1) == false\n    assert Integer.is_even(2) == true\n    assert Integer.is_even(3) == false\n    assert Integer.is_even(-1) == false\n    assert Integer.is_even(-2) == true\n    assert Integer.is_even(-3) == false\n    assert test_is_even_in_guards(10) == 10\n    assert test_is_even_in_guards(11) == false\n    assert test_is_even_in_guards(:not_integer) == false\n  end\n\n  test \"mod/2\" do\n    assert Integer.mod(10, -5) == 0\n    assert Integer.mod(3, 2) == 1\n    assert Integer.mod(0, 10) == 0\n    assert Integer.mod(0, -5) == 0\n    assert Integer.mod(30000, 2001) == 1986\n    assert Integer.mod(30000, -2001) == -15\n    assert Integer.mod(-20, 11) == 2\n    assert Integer.mod(-55, -22) == -11\n  end\n\n  test \"mod/2 raises ArithmeticError when divisor is 0\" do\n    assert_raise ArithmeticError, fn -> Integer.mod(3, 0) end\n    assert_raise ArithmeticError, fn -> Integer.mod(-50, 0) end\n  end\n\n  test \"floor_div/2\" do\n    assert Integer.floor_div(10, -5) == -2\n    assert Integer.floor_div(3, 2) == 1\n    assert Integer.floor_div(0, 10) == 0\n    assert Integer.floor_div(0, -5) == 0\n    assert Integer.floor_div(30000, 2001) == 14\n    assert Integer.floor_div(30000, -2001) == -15\n    assert Integer.floor_div(-20, 11) == -2\n    assert Integer.floor_div(-55, -22) == 2\n  end\n\n  test \"floor_div/2 raises ArithmeticError when divisor is 0\" do\n    assert_raise ArithmeticError, fn -> Integer.floor_div(3, 0) end\n    assert_raise ArithmeticError, fn -> Integer.floor_div(-50, 0) end\n  end\n\n  test \"floor_div/2 raises ArithmeticError when non-integers used as arguments\" do\n    assert_raise ArithmeticError, fn -> Integer.floor_div(3.0, 2) end\n    assert_raise ArithmeticError, fn -> Integer.floor_div(20, 1.2) end\n  end\n\n  test \"ceil_div/2\" do\n    assert Integer.ceil_div(10, -5) == -2\n    assert Integer.ceil_div(3, 2) == 2\n    assert Integer.ceil_div(0, 10) == 0\n    assert Integer.ceil_div(0, -10) == 0\n    assert Integer.ceil_div(30000, -2001) == -14\n    assert Integer.ceil_div(-20, 11) == -1\n    assert Integer.ceil_div(-55, -22) == 3\n  end\n\n  test \"ceil_div/2 raises ArithmeticError when divisor is 0\" do\n    assert_raise ArithmeticError, fn -> Integer.ceil_div(3, 0) end\n    assert_raise ArithmeticError, fn -> Integer.ceil_div(-50, 0) end\n  end\n\n  test \"ceil_div/2 raises ArithmeticError when non-integers used as arguments\" do\n    assert_raise ArithmeticError, fn -> Integer.ceil_div(3.0, 2) end\n    assert_raise ArithmeticError, fn -> Integer.ceil_div(20, 1.2) end\n  end\n\n  test \"digits/2\" do\n    assert Integer.digits(0) == [0]\n    assert Integer.digits(0, 2) == [0]\n    assert Integer.digits(1) == [1]\n    assert Integer.digits(-1) == [-1]\n    assert Integer.digits(123, 123) == [1, 0]\n    assert Integer.digits(-123, 123) == [-1, 0]\n    assert Integer.digits(456, 1000) == [456]\n    assert Integer.digits(-456, 1000) == [-456]\n    assert Integer.digits(123) == [1, 2, 3]\n    assert Integer.digits(-123) == [-1, -2, -3]\n    assert Integer.digits(58127, 2) == [1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]\n    assert Integer.digits(-58127, 2) == [-1, -1, -1, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1]\n\n    for n <- Enum.to_list(-1..1) do\n      assert_raise FunctionClauseError, fn ->\n        Integer.digits(10, n)\n        Integer.digits(-10, n)\n      end\n    end\n  end\n\n  test \"undigits/2\" do\n    assert Integer.undigits([]) == 0\n    assert Integer.undigits([0]) == 0\n    assert Integer.undigits([1]) == 1\n    assert Integer.undigits([1, 0, 1]) == 101\n    assert Integer.undigits([1, 4], 16) == 0x14\n    assert Integer.undigits([1, 4], 8) == 0o14\n    assert Integer.undigits([1, 1], 2) == 0b11\n    assert Integer.undigits([1, 2, 3, 4, 5]) == 12345\n    assert Integer.undigits([1, 0, -5]) == 95\n    assert Integer.undigits([-1, -1, -5]) == -115\n    assert Integer.undigits([0, 0, 0, -1, -1, -5]) == -115\n\n    for n <- Enum.to_list(-1..1) do\n      assert_raise FunctionClauseError, fn ->\n        Integer.undigits([1, 0, 1], n)\n      end\n    end\n\n    assert_raise ArgumentError, \"invalid digit 17 in base 16\", fn ->\n      Integer.undigits([1, 2, 17], 16)\n    end\n\n    assert_raise ArgumentError, \"invalid digit -10 in base 10\", fn ->\n      Integer.undigits([-10], 10)\n    end\n\n    assert_raise ArgumentError, \"invalid digit -17 in base 16\", fn ->\n      Integer.undigits([1, 2, -17], 16)\n    end\n  end\n\n  test \"parse/2\" do\n    assert Integer.parse(\"12\") === {12, \"\"}\n    assert Integer.parse(\"012\") === {12, \"\"}\n    assert Integer.parse(\"+12\") === {12, \"\"}\n    assert Integer.parse(\"-12\") === {-12, \"\"}\n    assert Integer.parse(\"123456789\") === {123_456_789, \"\"}\n    assert Integer.parse(\"12.5\") === {12, \".5\"}\n    assert Integer.parse(\"7.5e-3\") === {7, \".5e-3\"}\n    assert Integer.parse(\"12x\") === {12, \"x\"}\n    assert Integer.parse(\"++1\") === :error\n    assert Integer.parse(\"--1\") === :error\n    assert Integer.parse(\"+-1\") === :error\n    assert Integer.parse(\"three\") === :error\n\n    assert Integer.parse(\"12\", 10) === {12, \"\"}\n    assert Integer.parse(\"-12\", 12) === {-14, \"\"}\n    assert Integer.parse(\"12345678\", 9) === {6_053_444, \"\"}\n    assert Integer.parse(\"3.14\", 4) === {3, \".14\"}\n    assert Integer.parse(\"64eb\", 16) === {25835, \"\"}\n    assert Integer.parse(\"64eb\", 10) === {64, \"eb\"}\n    assert Integer.parse(\"10\", 2) === {2, \"\"}\n    assert Integer.parse(\"++4\", 10) === :error\n\n    # Base should be in range 2..36\n    assert_raise ArgumentError, \"invalid base 1\", fn -> Integer.parse(\"2\", 1) end\n    assert_raise ArgumentError, \"invalid base 37\", fn -> Integer.parse(\"2\", 37) end\n\n    # Base should be an integer\n    assert_raise ArgumentError, \"invalid base 10.2\", fn -> Integer.parse(\"2\", 10.2) end\n\n    assert_raise ArgumentError, \"invalid base nil\", fn -> Integer.parse(\"2\", nil) end\n  end\n\n  test \"to_string/2\" do\n    assert Integer.to_string(42) == \"42\"\n    assert Integer.to_string(+42) == \"42\"\n    assert Integer.to_string(-42) == \"-42\"\n    assert Integer.to_string(-0001) == \"-1\"\n\n    for n <- [42.0, :forty_two, ~c\"42\", \"42\"] do\n      assert_raise ArgumentError, fn ->\n        Integer.to_string(n)\n      end\n    end\n\n    assert Integer.to_string(42, 2) == \"101010\"\n    assert Integer.to_string(42, 10) == \"42\"\n    assert Integer.to_string(42, 16) == \"2A\"\n    assert Integer.to_string(+42, 16) == \"2A\"\n    assert Integer.to_string(-42, 16) == \"-2A\"\n    assert Integer.to_string(-042, 16) == \"-2A\"\n\n    for n <- [42.0, :forty_two, ~c\"42\", \"42\"] do\n      assert_raise ArgumentError, fn ->\n        Integer.to_string(n, 42)\n      end\n    end\n\n    for n <- [-1, 0, 1, 37] do\n      assert_raise ArgumentError, fn ->\n        Integer.to_string(42, n)\n      end\n\n      assert_raise ArgumentError, fn ->\n        Integer.to_string(n, n)\n      end\n    end\n  end\n\n  test \"to_charlist/2\" do\n    module = String.to_atom(\"Elixir.Integer\")\n\n    assert Integer.to_charlist(42) == ~c\"42\"\n    assert Integer.to_charlist(+42) == ~c\"42\"\n    assert Integer.to_charlist(-42) == ~c\"-42\"\n    assert Integer.to_charlist(-0001) == ~c\"-1\"\n\n    for n <- [42.0, :forty_two, ~c\"42\", \"42\"] do\n      assert_raise ArgumentError, fn ->\n        Integer.to_charlist(n)\n      end\n    end\n\n    assert module.to_char_list(42) == ~c\"42\"\n    assert module.to_char_list(42, 2) == ~c\"101010\"\n\n    assert Integer.to_charlist(42, 2) == ~c\"101010\"\n    assert Integer.to_charlist(42, 10) == ~c\"42\"\n    assert Integer.to_charlist(42, 16) == ~c\"2A\"\n    assert Integer.to_charlist(+42, 16) == ~c\"2A\"\n    assert Integer.to_charlist(-42, 16) == ~c\"-2A\"\n    assert Integer.to_charlist(-042, 16) == ~c\"-2A\"\n\n    for n <- [42.0, :forty_two, ~c\"42\", \"42\"] do\n      assert_raise ArgumentError, fn ->\n        Integer.to_charlist(n, 42)\n      end\n    end\n\n    for n <- [-1, 0, 1, 37] do\n      assert_raise ArgumentError, fn ->\n        Integer.to_charlist(42, n)\n      end\n\n      assert_raise ArgumentError, fn ->\n        Integer.to_charlist(n, n)\n      end\n    end\n  end\n\n  test \"gcd/2\" do\n    assert Integer.gcd(1, 5) == 1\n    assert Integer.gcd(2, 3) == 1\n    assert Integer.gcd(8, 12) == 4\n    assert Integer.gcd(-8, 12) == 4\n    assert Integer.gcd(8, -12) == 4\n    assert Integer.gcd(-8, -12) == 4\n    assert Integer.gcd(27, 27) == 27\n    assert Integer.gcd(-27, -27) == 27\n    assert Integer.gcd(-27, 27) == 27\n    assert Integer.gcd(0, 3) == 3\n    assert Integer.gcd(0, -3) == 3\n    assert Integer.gcd(3, 0) == 3\n    assert Integer.gcd(-3, 0) == 3\n    assert Integer.gcd(0, 0) == 0\n  end\n\n  test \"extended_gcd\" do\n    # Poor's man property based testing\n    for _ <- 1..100 do\n      left = :rand.uniform(1000)\n      right = :rand.uniform(1000)\n      {gcd, m, n} = Integer.extended_gcd(left, right)\n      assert Integer.gcd(left, right) == gcd\n      assert m * left + n * right == gcd\n    end\n\n    # zero cases\n    for {left, right} <- [{10, 0}, {0, 10}, {0, -10}, {-10, 0}] do\n      {gcd, m, n} = Integer.extended_gcd(left, right)\n      assert Integer.gcd(left, right) == gcd\n      assert m * left + n * right == gcd\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/io/ansi/docs_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule IO.ANSI.DocsTest do\n  use ExUnit.Case, async: true\n  import ExUnit.CaptureIO\n\n  def format_headings(list) do\n    capture_io(fn -> IO.ANSI.Docs.print_headings(list, []) end) |> String.trim_trailing()\n  end\n\n  def format_metadata(map) do\n    capture_io(fn -> IO.ANSI.Docs.print_metadata(map, []) end)\n  end\n\n  def format_markdown(str, opts \\\\ []) do\n    capture_io(fn -> IO.ANSI.Docs.print(str, \"text/markdown\", opts) end)\n    |> String.trim_trailing()\n  end\n\n  describe \"heading\" do\n    test \"is formatted\" do\n      result = format_headings([\"foo\"])\n      assert String.starts_with?(result, \"\\e[0m\\n\\e[7m\\e[33m\")\n      assert String.ends_with?(result, \"\\e[0m\\n\\e[0m\")\n      assert String.contains?(result, \" foo \")\n    end\n\n    test \"multiple entries formatted\" do\n      result = format_headings([\"foo\", \"bar\"])\n      assert :binary.matches(result, \"\\e[0m\\n\\e[7m\\e[33m\") |> length() == 2\n      assert String.starts_with?(result, \"\\e[0m\\n\\e[7m\\e[33m\")\n      assert String.ends_with?(result, \"\\e[0m\\n\\e[0m\")\n      assert String.contains?(result, \" foo \")\n      assert String.contains?(result, \" bar \")\n    end\n\n    test \"is correctly formatted when newline character is present\" do\n      result = format_headings([\"foo\\nbar\"])\n      assert :binary.matches(result, \"\\e[0m\\n\\e[7m\\e[33m\") |> length() == 2\n      assert [\"\\e[0m\", foo_line, bar_line, \"\\e[0m\"] = String.split(result, \"\\n\")\n      assert Regex.match?(~r/\\e\\[7m\\e\\[33m +foo +\\e\\[0m/, foo_line)\n      assert Regex.match?(~r/\\e\\[7m\\e\\[33m +bar +\\e\\[0m/, bar_line)\n    end\n  end\n\n  describe \"metadata\" do\n    test \"is formatted\" do\n      result =\n        format_metadata(%{\n          since: \"1.2.3\",\n          deprecated: \"Use that other one\",\n          author: \"Alice\",\n          delegate_to: {Foo, :bar, 3}\n        })\n\n      assert result == \"\"\"\n             \\e[33mdelegate_to:\\e[0m Foo.bar/3\n             \\e[33mdeprecated:\\e[0m Use that other one\n             \\e[33msince:\\e[0m 1.2.3\n\n             \"\"\"\n\n      assert format_metadata(%{author: \"Alice\"}) == \"\"\n    end\n  end\n\n  describe \"markdown\" do\n    test \"first level heading is converted\" do\n      result = format_markdown(\"# wibble\\n\\ntext\\n\")\n      assert result == \"\\e[33m# wibble\\e[0m\\n\\e[0m\\ntext\\n\\e[0m\"\n    end\n\n    test \"second level heading is converted\" do\n      result = format_markdown(\"## wibble\\n\\ntext\\n\")\n      assert result == \"\\e[33m## wibble\\e[0m\\n\\e[0m\\ntext\\n\\e[0m\"\n    end\n\n    test \"third level heading is converted\" do\n      result = format_markdown(\"### wibble\\n\\ntext\\n\")\n      assert result == \"\\e[33m### wibble\\e[0m\\n\\e[0m\\ntext\\n\\e[0m\"\n    end\n\n    test \"short single-line quote block is converted into single-line quote\" do\n      result =\n        format_markdown(\"\"\"\n        line\n\n        > normal *italics* `code`\n\n        line2\n        \"\"\")\n\n      assert result ==\n               \"\"\"\n               line\n               \\e[0m\n               \\e[90m> \\e[0mnormal \\e[4mitalics\\e[0m \\e[36mcode\\e[0m\n               \\e[0m\n               line2\n               \\e[0m\\\n               \"\"\"\n    end\n\n    test \"short multi-line quote block is converted into single-line quote\" do\n      result =\n        format_markdown(\"\"\"\n        line\n\n        > normal\n        > *italics*\n        > `code`\n\n        line2\n        \"\"\")\n\n      assert result ==\n               \"\"\"\n               line\n               \\e[0m\n               \\e[90m> \\e[0mnormal \\e[4mitalics\\e[0m \\e[36mcode\\e[0m\n               \\e[0m\n               line2\n               \\e[0m\\\n               \"\"\"\n    end\n\n    test \"long multi-line quote block is converted into wrapped multi-line quote\" do\n      result =\n        format_markdown(\"\"\"\n        line\n\n        > normal\n        > *italics*\n        > `code`\n        > some-extremely-long-word-which-can-not-possibly-fit-into-the-previous-line\n\n        line2\n        \"\"\")\n\n      assert result ==\n               \"\"\"\n               line\n               \\e[0m\n               \\e[90m> \\e[0mnormal \\e[4mitalics\\e[0m \\e[36mcode\\e[0m\n               \\e[90m> \\e[0msome-extremely-long-word-which-can-not-possibly-fit-into-the-previous-line\n               \\e[0m\n               line2\n               \\e[0m\\\n               \"\"\"\n    end\n\n    test \"multi-line quote block containing empty lines is converted into wrapped multi-line quote\" do\n      result =\n        format_markdown(\"\"\"\n        line\n\n        > normal\n        > *italics*\n        >\n        > `code`\n        > some-extremely-long-word-which-can-not-possibly-fit-into-the-previous-line\n\n        line2\n        \"\"\")\n\n      assert result ==\n               \"\"\"\n               line\n               \\e[0m\n               \\e[90m> \\e[0mnormal \\e[4mitalics\\e[0m\n               \\e[90m> \\e[0m\n               \\e[90m> \\e[0m\\e[36mcode\\e[0m\n               \\e[90m> \\e[0msome-extremely-long-word-which-can-not-possibly-fit-into-the-previous-line\n               \\e[0m\n               line2\n               \\e[0m\\\n               \"\"\"\n    end\n\n    test \"code block is converted\" do\n      result = format_markdown(\"line\\n\\n    code\\n    code2\\n\\nline2\\n\")\n      assert result == \"line\\n\\e[0m\\n\\e[36m    code\\n    code2\\e[0m\\n\\e[0m\\nline2\\n\\e[0m\"\n    end\n\n    test \"fenced code block is converted\" do\n      result = format_markdown(\"line\\n```\\ncode\\ncode2\\n```\\nline2\\n\")\n      assert result == \"line\\n\\e[0m\\n\\e[36m    code\\n    code2\\e[0m\\n\\e[0m\\nline2\\n\\e[0m\"\n      result = format_markdown(\"line\\n```elixir\\ncode\\ncode2\\n```\\nline2\\n\")\n      assert result == \"line\\n\\e[0m\\n\\e[36m    code\\n    code2\\e[0m\\n\\e[0m\\nline2\\n\\e[0m\"\n    end\n\n    test \"mermaid fenced code block is discarded\" do\n      result = format_markdown(\"line\\n```mermaid\\ncode\\ncode2\\n```\\nline2\\n\")\n      assert result == \"line\\n\\e[0m\\nline2\\n\\e[0m\"\n    end\n\n    test \"* list is converted\" do\n      result = format_markdown(\"* one\\n* two\\n* three\\n\")\n      assert result == \"  • one\\n  • two\\n  • three\\n\\e[0m\"\n    end\n\n    test \"* list is converted without ansi\" do\n      result = format_markdown(\"* one\\n* two\\n* three\\n\", enabled: false)\n      assert result == \"  * one\\n  * two\\n  * three\"\n    end\n\n    test \"* list surrounded by text is converted\" do\n      result = format_markdown(\"Count:\\n\\n* one\\n* two\\n* three\\n\\nDone\")\n      assert result == \"Count:\\n\\e[0m\\n  • one\\n  • two\\n  • three\\n\\e[0m\\nDone\\n\\e[0m\"\n    end\n\n    test \"* list with continuation is converted\" do\n      result = format_markdown(\"* one\\ntwo\\n\\n    three\\nfour\\n* five\")\n      assert result == \"  • one two\\n    three four\\n\\e[0m\\n  • five\\n\\e[0m\"\n    end\n\n    test \"* nested lists are converted\" do\n      result = format_markdown(\"* one\\n  * one.one\\n  * one.two\\n* two\")\n      assert result == \"  • one\\n    • one.one\\n    • one.two\\n\\e[0m\\n  • two\\n\\e[0m\"\n    end\n\n    test \"* deep nested lists are converted\" do\n      result =\n        format_markdown(\"\"\"\n          * level 1\n            * level 2a\n            * level 2b\n              * level 3\n                * level 4a\n                * level 4b\n                  * level 5\n                    * level 6\n        \"\"\")\n\n      assert result ==\n               \"  • level 1\\n    • level 2a\\n    • level 2b\\n      • level 3\\n        • level 4a\\n        • level 4b\\n          • level 5\\n            • level 6\\n\\e[0m\\n\\e[0m\\n\\e[0m\\n\\e[0m\\n\\e[0m\\n\\e[0m\"\n    end\n\n    test \"* lists with spaces are converted\" do\n      result = format_markdown(\"  * one\\n  * two\\n  * three\")\n      assert result == \"  • one\\n  • two\\n  • three\\n\\e[0m\"\n    end\n\n    test \"* lists with code\" do\n      result = format_markdown(\"  * one\\n        two three\")\n      assert result == \"  • one\\n\\e[36m        two three\\e[0m\\n\\e[0m\\n\\e[0m\"\n    end\n\n    test \"- list is converted\" do\n      result = format_markdown(\"- one\\n- two\\n- three\\n\")\n      assert result == \"  • one\\n  • two\\n  • three\\n\\e[0m\"\n    end\n\n    test \"+ list is converted\" do\n      result = format_markdown(\"+ one\\n+ two\\n+ three\\n\")\n      assert result == \"  • one\\n  • two\\n  • three\\n\\e[0m\"\n    end\n\n    test \"+ and - nested lists are converted\" do\n      result = format_markdown(\"- one\\n  + one.one\\n  + one.two\\n- two\")\n      assert result == \"  • one\\n    • one.one\\n    • one.two\\n\\e[0m\\n  • two\\n\\e[0m\"\n    end\n\n    test \"paragraphs are split\" do\n      result = format_markdown(\"para1\\n\\npara2\")\n      assert result == \"para1\\n\\e[0m\\npara2\\n\\e[0m\"\n    end\n\n    test \"extra whitespace is ignored between paras\" do\n      result = format_markdown(\"para1\\n   \\npara2\")\n      assert result == \"para1\\n\\e[0m\\npara2\\n\\e[0m\"\n    end\n\n    test \"extra whitespace doesn't mess up a following list\" do\n      result = format_markdown(\"para1\\n   \\n* one\\n* two\")\n      assert result == \"para1\\n\\e[0m\\n  • one\\n  • two\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick works\" do\n      result = format_markdown(\"*world*\")\n      assert result == \"\\e[4mworld\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"*world*.\")\n      assert result == \"\\e[4mworld\\e[0m.\\n\\e[0m\"\n\n      result = format_markdown(\"**world**\")\n      assert result == \"\\e[1mworld\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"_world_\")\n      assert result == \"\\e[4mworld\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"__world__\")\n      assert result == \"\\e[1mworld\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"`world`\")\n      assert result == \"\\e[36mworld\\e[0m\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick works across words\" do\n      result = format_markdown(\"*hello world*\")\n      assert result == \"\\e[4mhello world\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"**hello world**\")\n      assert result == \"\\e[1mhello world\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"_hello world_\")\n      assert result == \"\\e[4mhello world\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"__hello world__\")\n      assert result == \"\\e[1mhello world\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"`hello world`\")\n      assert result == \"\\e[36mhello world\\e[0m\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick works across words with ansi disabled\" do\n      result = format_markdown(\"*hello world*\", enabled: false)\n      assert result == \"*hello world*\"\n\n      result = format_markdown(\"**hello world**\", enabled: false)\n      assert result == \"**hello world**\"\n\n      result = format_markdown(\"_hello world_\", enabled: false)\n      assert result == \"_hello world_\"\n\n      result = format_markdown(\"__hello world__\", enabled: false)\n      assert result == \"__hello world__\"\n\n      result = format_markdown(\"`hello world`\", enabled: false)\n      assert result == \"`hello world`\"\n    end\n\n    test \"multiple stars/underscores/backticks work\" do\n      result = format_markdown(\"*hello world* *hello world*\")\n      assert result == \"\\e[4mhello world\\e[0m \\e[4mhello world\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"_hello world_ _hello world_\")\n      assert result == \"\\e[4mhello world\\e[0m \\e[4mhello world\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"`hello world` `hello world`\")\n      assert result == \"\\e[36mhello world\\e[0m \\e[36mhello world\\e[0m\\n\\e[0m\"\n    end\n\n    test \"multiple stars/underscores/backticks work when separated by other words\" do\n      result = format_markdown(\"*hello world* unit test *hello world*\")\n      assert result == \"\\e[4mhello world\\e[0m unit test \\e[4mhello world\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"_hello world_ unit test _hello world_\")\n      assert result == \"\\e[4mhello world\\e[0m unit test \\e[4mhello world\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"`hello world` unit test `hello world`\")\n      assert result == \"\\e[36mhello world\\e[0m unit test \\e[36mhello world\\e[0m\\n\\e[0m\"\n    end\n\n    test \"star/underscore preceded by space doesn't get interpreted\" do\n      result = format_markdown(\"_unit _size\")\n      assert result == \"_unit _size\\n\\e[0m\"\n\n      result = format_markdown(\"**unit **size\")\n      assert result == \"**unit **size\\n\\e[0m\"\n\n      result = format_markdown(\"*unit *size\")\n      assert result == \"*unit *size\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick preceded by non-space delimiters gets interpreted\" do\n      result = format_markdown(\"(`hello world`)\")\n      assert result == \"(\\e[36mhello world\\e[0m)\\n\\e[0m\"\n      result = format_markdown(\"<`hello world`>\")\n      assert result == \"<\\e[36mhello world\\e[0m>\\n\\e[0m\"\n\n      result = format_markdown(\"(*hello world*)\")\n      assert result == \"(\\e[4mhello world\\e[0m)\\n\\e[0m\"\n      result = format_markdown(\"@*hello world*@\")\n      assert result == \"@\\e[4mhello world\\e[0m@\\n\\e[0m\"\n\n      result = format_markdown(\"(_hello world_)\")\n      assert result == \"(\\e[4mhello world\\e[0m)\\n\\e[0m\"\n      result = format_markdown(\"'_hello world_'\")\n      assert result == \"'\\e[4mhello world\\e[0m'\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick starts/ends within a word doesn't get interpreted\" do\n      result = format_markdown(\"foo_bar, foo_bar_baz!\")\n      assert result == \"foo_bar, foo_bar_baz!\\n\\e[0m\"\n\n      result = format_markdown(\"_foo_bar\")\n      assert result == \"_foo_bar\\n\\e[0m\"\n\n      result = format_markdown(\"foo_bar_\")\n      assert result == \"foo_bar_\\n\\e[0m\"\n\n      result = format_markdown(\"foo*bar, foo*bar*baz!\")\n      assert result == \"foo*bar, foo*bar*baz!\\n\\e[0m\"\n\n      result = format_markdown(\"*foo*bar\")\n      assert result == \"*foo*bar\\n\\e[0m\"\n\n      result = format_markdown(\"foo*bar*\")\n      assert result == \"foo*bar*\\n\\e[0m\"\n    end\n\n    test \"backtick preceded by space gets interpreted\" do\n      result = format_markdown(\"`unit `size\")\n      assert result == \"\\e[36munit \\e[0msize\\n\\e[0m\"\n    end\n\n    test \"backtick does not escape characters\" do\n      result = format_markdown(\"`Ctrl+\\\\ `\")\n      assert result == \"\\e[36mCtrl+\\\\ \\e[0m\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick with leading escape\" do\n      result = format_markdown(\"\\\\_unit_\")\n      assert result == \"_unit_\\n\\e[0m\"\n\n      result = format_markdown(\"\\\\*unit*\")\n      assert result == \"*unit*\\n\\e[0m\"\n\n      result = format_markdown(\"\\\\`unit`\")\n      assert result == \"`unit`\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick with closing escape\" do\n      result = format_markdown(\"_unit\\\\_\")\n      assert result == \"_unit_\\n\\e[0m\"\n\n      result = format_markdown(\"*unit\\\\*\")\n      assert result == \"*unit*\\n\\e[0m\"\n\n      result = format_markdown(\"`unit\\\\`\")\n      assert result == \"\\e[36munit\\\\\\e[0m\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick with double escape\" do\n      result = format_markdown(\"\\\\\\\\*world*\")\n      assert result == \"\\\\\\e[4mworld\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"\\\\\\\\_world_\")\n      assert result == \"\\\\\\e[4mworld\\e[0m\\n\\e[0m\"\n\n      result = format_markdown(\"\\\\\\\\`world`\")\n      assert result == \"\\\\\\e[36mworld\\e[0m\\n\\e[0m\"\n    end\n\n    test \"star/underscore/backtick when incomplete\" do\n      result = format_markdown(\"unit_size\")\n      assert result == \"unit_size\\n\\e[0m\"\n\n      result = format_markdown(\"unit`size\")\n      assert result == \"unit`size\\n\\e[0m\"\n\n      result = format_markdown(\"unit*size\")\n      assert result == \"unit*size\\n\\e[0m\"\n\n      result = format_markdown(\"unit**size\")\n      assert result == \"unit**size\\n\\e[0m\"\n    end\n\n    test \"backtick with escape\" do\n      result = format_markdown(\"`\\\\`\")\n      assert result == \"\\e[36m\\\\\\e[0m\\n\\e[0m\"\n    end\n\n    test \"backtick close to underscores gets interpreted as code\" do\n      result = format_markdown(\"`__world__`\")\n      assert result == \"\\e[36m__world__\\e[0m\\n\\e[0m\"\n    end\n\n    test \"escaping of underlines within links\" do\n      result = format_markdown(\"(https://en.wikipedia.org/wiki/ANSI_escape_code)\")\n      assert result == \"(https://en.wikipedia.org/wiki/ANSI_escape_code)\\n\\e[0m\"\n\n      result =\n        format_markdown(\"[ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code)\")\n\n      assert result == \"ANSI escape code (https://en.wikipedia.org/wiki/ANSI_escape_code)\\n\\e[0m\"\n\n      result = format_markdown(\"(ftp://example.com/ANSI_escape_code.zip)\")\n      assert result == \"(ftp://example.com/ANSI_escape_code.zip)\\n\\e[0m\"\n    end\n\n    test \"escaping of underlines within links does not escape surrounding text\" do\n      result =\n        format_markdown(\n          \"_emphasis_ (https://en.wikipedia.org/wiki/ANSI_escape_code) more _emphasis_\"\n        )\n\n      assert result ==\n               \"\\e[4memphasis\\e[0m (https://en.wikipedia.org/wiki/ANSI_escape_code) more \\e[4memphasis\\e[0m\\n\\e[0m\"\n    end\n\n    test \"escaping of underlines within links avoids false positives\" do\n      assert format_markdown(\"`https_proxy`\") == \"\\e[36mhttps_proxy\\e[0m\\n\\e[0m\"\n    end\n\n    test \"escaping of several Markdown links in one line\" do\n      assert format_markdown(\"[List](`List`) (`[1, 2, 3]`), [Map](`Map`)\") ==\n               \"List (\\e[36mList\\e[0m) (\\e[36m[1, 2, 3]\\e[0m), Map (\\e[36mMap\\e[0m)\\n\\e[0m\"\n    end\n\n    test \"one reference link label per line\" do\n      assert format_markdown(\"  [id]: //example.com\\n  [Elixir]:  https://elixir-lang.org\") ==\n               \"  [id]: //example.com\\n  [Elixir]:  https://elixir-lang.org\"\n    end\n  end\n\n  describe \"markdown tables\" do\n    test \"lone thing that looks like a table line isn't\" do\n      assert format_markdown(\"one\\n2 | 3\\ntwo\\n\") == \"one 2 | 3 two\\n\\e[0m\"\n    end\n\n    test \"lone table line at end of input isn't\" do\n      assert format_markdown(\"one\\n2 | 3\") == \"one 2 | 3\\n\\e[0m\"\n    end\n\n    test \"two successive table lines are a table\" do\n      # note spacing\n      assert format_markdown(\"a | b\\none | two\\n\") == \"a   | b  \\none | two\\n\\e[0m\"\n    end\n\n    test \"table with heading\" do\n      assert format_markdown(\"column 1 | and 2\\n-- | --\\na | b\\none | two\\n\") ==\n               \"\\e[7mcolumn 1 | and 2\\e[0m\\na        | b    \\none      | two  \\n\\e[0m\"\n    end\n\n    test \"table with heading alignment\" do\n      table = \"\"\"\n      column 1 | 2        | and three\n      -------: | :------: | :-----\n          a    |  even    | c\\none | odd | three\n      \"\"\"\n\n      expected =\n        \"\"\"\n        \\e[7mcolumn 1 |   2   | and three\\e[0m\n               a | even  | c\\s\\s\\s\\s\\s\\s\\s\\s\n             one |  odd  | three\\s\\s\\s\\s\n        \\e[0m\n        \"\"\"\n        |> String.trim_trailing()\n\n      assert format_markdown(table) == expected\n    end\n\n    test \"table with heading alignment and no space around \\\"|\\\"\" do\n      table = \"\"\"\n      | Value | Encoding | Value | Encoding |\n      |------:|:---------|------:|:---------|\n      |     0 | A        |    17 | R        |\n      |     1 | B        |    18 | S        |\n      \"\"\"\n\n      expected =\n        \"\\e[7m\" <>\n          \"Value | Encoding | Value | Encoding\\e[0m\\n\" <>\n          \"    0 | A        |    17 | R       \\n\" <>\n          \"    1 | B        |    18 | S       \\n\\e[0m\"\n\n      assert format_markdown(table) == expected\n    end\n\n    test \"table with formatting in cells\" do\n      assert format_markdown(\"`a` | _b_\\nc | d\") == \"\\e[36ma\\e[0m | \\e[4mb\\e[0m\\nc | d\\n\\e[0m\"\n\n      assert format_markdown(\"`abc` | d \\n`e` | f\") ==\n               \"\\e[36mabc\\e[0m | d\\n\\e[36me\\e[0m   | f\\n\\e[0m\"\n    end\n\n    test \"table with variable number of columns\" do\n      assert format_markdown(\"a | b | c\\nd | e\") == \"a | b | c\\nd | e |  \\n\\e[0m\"\n    end\n\n    test \"table with escaped \\\"|\\\" inside cell\" do\n      table = \"a | smth\\\\|smth_else | c\\nd | e | f\"\n\n      expected =\n        \"\"\"\n        a | smth|smth_else | c\n        d | e              | f\n        \\e[0m\n        \"\"\"\n        |> String.trim_trailing()\n\n      assert format_markdown(table) == expected\n    end\n\n    test \"table with last two columns empty\" do\n      table = \"\"\"\n      AAA |     |     |\n      BBB | CCC |     |\n      GGG | HHH | III |\n      JJJ | KKK | LLL | MMM\n      \"\"\"\n\n      expected =\n        \"\"\"\n        AAA |     |     |\\s\\s\\s\\s\n        BBB | CCC |     |\\s\\s\\s\\s\n        GGG | HHH | III |\\s\\s\\s\\s\n        JJJ | KKK | LLL | MMM\n        \\e[0m\n        \"\"\"\n        |> String.trim_trailing()\n\n      assert format_markdown(table) == expected\n    end\n\n    test \"HTML comments are ignored\" do\n      markdown = \"\"\"\n      <!-- comment -->\n      hello\n      \"\"\"\n\n      assert format_markdown(markdown) == \"hello\\n\\e[0m\"\n\n      markdown = \"\"\"\n      <!-- comment -->\n\n      hello\n      \"\"\"\n\n      assert format_markdown(markdown) == \"hello\\n\\e[0m\"\n\n      markdown = \"\"\"\n      hello\n      <!-- comment -->\n      world\n      \"\"\"\n\n      assert format_markdown(markdown) == \"hello\\n\\e[0m\\nworld\\n\\e[0m\"\n\n      markdown = \"\"\"\n      hello\n\n      <!-- comment -->\n\n      world\n      \"\"\"\n\n      assert format_markdown(markdown) == \"hello\\n\\e[0m\\nworld\\n\\e[0m\"\n\n      markdown = \"\"\"\n      hello\n      <!-- comment --> world\n      \"\"\"\n\n      assert format_markdown(markdown) == \"hello world\\n\\e[0m\"\n\n      markdown = \"\"\"\n      hello <!-- comment --> world\n      \"\"\"\n\n      assert format_markdown(markdown) == \"hello  world\\n\\e[0m\"\n    end\n  end\n\n  describe \"invalid format\" do\n    test \"prints message\" do\n      assert capture_io(fn -> IO.ANSI.Docs.print(\"hello\", \"text/unknown\", []) end) ==\n               \"\\nUnknown documentation format \\\"text/unknown\\\"\\n\\n\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/io/ansi_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule IO.ANSITest do\n  use ExUnit.Case, async: true\n\n  doctest IO.ANSI\n\n  test \"format ansicode\" do\n    assert IO.chardata_to_string(IO.ANSI.format(:green, true)) ==\n             \"#{IO.ANSI.green()}#{IO.ANSI.reset()}\"\n\n    assert IO.chardata_to_string(IO.ANSI.format(:green, false)) == \"\"\n  end\n\n  test \"format binary\" do\n    assert IO.chardata_to_string(IO.ANSI.format(\"Hello, world!\", true)) == \"Hello, world!\"\n\n    assert IO.chardata_to_string(IO.ANSI.format(\"A map: %{foo: :bar}\", false)) ==\n             \"A map: %{foo: :bar}\"\n  end\n\n  test \"format empty list\" do\n    assert IO.chardata_to_string(IO.ANSI.format([], true)) == \"\"\n    assert IO.chardata_to_string(IO.ANSI.format([], false)) == \"\"\n  end\n\n  test \"format ansicode list\" do\n    assert IO.chardata_to_string(IO.ANSI.format([:red, :bright], true)) ==\n             \"#{IO.ANSI.red()}#{IO.ANSI.bright()}#{IO.ANSI.reset()}\"\n\n    assert IO.chardata_to_string(IO.ANSI.format([:red, :bright], false)) == \"\"\n  end\n\n  test \"format binary list\" do\n    assert IO.chardata_to_string(IO.ANSI.format([\"Hello, \", \"world!\"], true)) == \"Hello, world!\"\n    assert IO.chardata_to_string(IO.ANSI.format([\"Hello, \", \"world!\"], false)) == \"Hello, world!\"\n  end\n\n  test \"format charlist\" do\n    assert IO.chardata_to_string(IO.ANSI.format(~c\"Hello, world!\", true)) == \"Hello, world!\"\n    assert IO.chardata_to_string(IO.ANSI.format(~c\"Hello, world!\", false)) == \"Hello, world!\"\n  end\n\n  test \"format mixed list\" do\n    data = [\"Hello\", ?,, 32, :red, \"world!\"]\n\n    assert IO.chardata_to_string(IO.ANSI.format(data, true)) ==\n             \"Hello, #{IO.ANSI.red()}world!#{IO.ANSI.reset()}\"\n\n    assert IO.chardata_to_string(IO.ANSI.format(data, false)) == \"Hello, world!\"\n  end\n\n  test \"format nested list\" do\n    data = [\"Hello, \", [\"nested\", 32, :red, \"world!\"]]\n\n    assert IO.chardata_to_string(IO.ANSI.format(data, true)) ==\n             \"Hello, nested #{IO.ANSI.red()}world!#{IO.ANSI.reset()}\"\n\n    assert IO.chardata_to_string(IO.ANSI.format(data, false)) == \"Hello, nested world!\"\n  end\n\n  test \"format improper list\" do\n    data = [\"Hello, \", :red, \"world\" | \"!\"]\n\n    assert IO.chardata_to_string(IO.ANSI.format(data, true)) ==\n             \"Hello, #{IO.ANSI.red()}world!#{IO.ANSI.reset()}\"\n\n    assert IO.chardata_to_string(IO.ANSI.format(data, false)) == \"Hello, world!\"\n  end\n\n  test \"format nested improper list\" do\n    data = [[\"Hello, \" | :red], \"world!\" | :green]\n\n    assert IO.chardata_to_string(IO.ANSI.format(data, true)) ==\n             \"Hello, #{IO.ANSI.red()}world!#{IO.ANSI.green()}#{IO.ANSI.reset()}\"\n\n    assert IO.chardata_to_string(IO.ANSI.format(data, false)) == \"Hello, world!\"\n  end\n\n  test \"format fragment\" do\n    assert IO.chardata_to_string(IO.ANSI.format_fragment([:red, \"Hello!\"], true)) ==\n             \"#{IO.ANSI.red()}Hello!\"\n  end\n\n  test \"format invalid sequence\" do\n    assert_raise ArgumentError, \"invalid ANSI sequence specification: :brigh\", fn ->\n      IO.ANSI.format([:brigh, \"Hello!\"], true)\n    end\n\n    assert_raise ArgumentError, \"invalid ANSI sequence specification: nil\", fn ->\n      IO.ANSI.format([\"Hello!\", nil], true)\n    end\n\n    assert_raise ArgumentError, \"invalid ANSI sequence specification: :brigh\", fn ->\n      IO.ANSI.format([:brigh, \"Hello!\"], false)\n    end\n\n    assert_raise ArgumentError, \"invalid ANSI sequence specification: nil\", fn ->\n      IO.ANSI.format([\"Hello!\", nil], false)\n    end\n\n    assert_raise ArgumentError, \"invalid ANSI sequence specification: :invalid\", fn ->\n      IO.ANSI.format(:invalid, false)\n    end\n  end\n\n  test \"colors\" do\n    assert IO.ANSI.red() == \"\\e[31m\"\n    assert IO.ANSI.light_red() == \"\\e[91m\"\n\n    assert IO.ANSI.red_background() == \"\\e[41m\"\n    assert IO.ANSI.light_red_background() == \"\\e[101m\"\n  end\n\n  test \"color/1\" do\n    assert IO.ANSI.color(0) == \"\\e[38;5;0m\"\n    assert IO.ANSI.color(42) == \"\\e[38;5;42m\"\n    assert IO.ANSI.color(255) == \"\\e[38;5;255m\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.color(-1)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.color(256)\n    end\n  end\n\n  test \"color/3\" do\n    assert IO.ANSI.color(0, 4, 2) == \"\\e[38;5;42m\"\n    assert IO.ANSI.color(1, 1, 1) == \"\\e[38;5;59m\"\n    assert IO.ANSI.color(5, 5, 5) == \"\\e[38;5;231m\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.color(0, 6, 1)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.color(5, -1, 1)\n    end\n  end\n\n  test \"color_background/1\" do\n    assert IO.ANSI.color_background(0) == \"\\e[48;5;0m\"\n    assert IO.ANSI.color_background(42) == \"\\e[48;5;42m\"\n    assert IO.ANSI.color_background(255) == \"\\e[48;5;255m\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.color_background(-1)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.color_background(256)\n    end\n  end\n\n  test \"color_background/3\" do\n    assert IO.ANSI.color_background(0, 4, 2) == \"\\e[48;5;42m\"\n    assert IO.ANSI.color_background(1, 1, 1) == \"\\e[48;5;59m\"\n    assert IO.ANSI.color_background(5, 5, 5) == \"\\e[48;5;231m\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.color_background(0, 6, 1)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.color_background(5, -1, 1)\n    end\n  end\n\n  test \"cursor/2\" do\n    assert IO.ANSI.cursor(0, 0) == \"\\e[0;0H\"\n    assert IO.ANSI.cursor(11, 12) == \"\\e[11;12H\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor(-1, 5)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor(5, -1)\n    end\n  end\n\n  test \"cursor_up/1\" do\n    assert IO.ANSI.cursor_up() == \"\\e[1A\"\n    assert IO.ANSI.cursor_up(12) == \"\\e[12A\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor_up(0)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor_up(-1)\n    end\n  end\n\n  test \"cursor_down/1\" do\n    assert IO.ANSI.cursor_down() == \"\\e[1B\"\n    assert IO.ANSI.cursor_down(2) == \"\\e[2B\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor_right(0)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor_down(-1)\n    end\n  end\n\n  test \"cursor_left/1\" do\n    assert IO.ANSI.cursor_left() == \"\\e[1D\"\n    assert IO.ANSI.cursor_left(3) == \"\\e[3D\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor_left(0)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor_left(-1)\n    end\n  end\n\n  test \"cursor_right/1\" do\n    assert IO.ANSI.cursor_right() == \"\\e[1C\"\n    assert IO.ANSI.cursor_right(4) == \"\\e[4C\"\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor_right(0)\n    end\n\n    assert_raise FunctionClauseError, fn ->\n      IO.ANSI.cursor_right(-1)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/io_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule IOTest do\n  use ExUnit.Case, async: true\n\n  doctest IO\n\n  import ExUnit.CaptureIO\n\n  test \"read with count\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/file.txt\", __DIR__), [:charlist])\n    assert ~c\"FOO\" == IO.read(file, 3)\n    assert File.close(file) == :ok\n  end\n\n  test \"read with UTF-8 and binary\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/utf8.txt\", __DIR__), [:utf8])\n    assert \"Русский\" == IO.read(file, 7)\n    assert File.close(file) == :ok\n  end\n\n  test \"read all charlist\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/multiline_file.txt\", __DIR__), [:charlist])\n    assert ~c\"this is the first line\\nthis is the second line\\n\" == IO.read(file, :eof)\n    assert File.close(file) == :ok\n  end\n\n  test \"read empty file\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/cp_mode\", __DIR__), [])\n    assert IO.read(file, :eof) == :eof\n    assert File.close(file) == :ok\n\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/cp_mode\", __DIR__), [:charlist])\n    assert IO.read(file, :eof) == :eof\n    assert File.close(file) == :ok\n  end\n\n  test \"binread\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/utf8.txt\", __DIR__))\n    assert \"Русский\" == IO.binread(file, 14)\n    assert File.close(file) == :ok\n  end\n\n  test \"binread eof\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/file.bin\", __DIR__))\n    assert \"LF\\nCR\\rCRLF\\r\\nLFCR\\n\\r\" == IO.binread(file, :eof)\n    assert File.close(file) == :ok\n  end\n\n  test \"getn\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/file.txt\", __DIR__))\n    assert \"F\" == IO.getn(file, \"\")\n    assert \"O\" == IO.getn(file, \"\")\n    assert \"O\" == IO.getn(file, \"\")\n    assert \"\\n\" == IO.getn(file, \"\")\n    assert :eof == IO.getn(file, \"\")\n    assert File.close(file) == :ok\n  end\n\n  test \"getn with count\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/file.txt\", __DIR__), [:charlist])\n    assert ~c\"F\" == IO.getn(file, \"λ\")\n    assert ~c\"OO\" == IO.getn(file, \"\", 2)\n    assert ~c\"\\n\" == IO.getn(file, \"λ\", 99)\n    assert :eof == IO.getn(file, \"λ\", 1)\n    assert File.close(file) == :ok\n  end\n\n  test \"getn with eof\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/file.txt\", __DIR__), [:charlist])\n    assert ~c\"F\" == IO.getn(file, \"λ\")\n    assert ~c\"OO\\n\" == IO.getn(file, \"\", :eof)\n    assert :eof == IO.getn(file, \"\", :eof)\n    assert File.close(file) == :ok\n  end\n\n  test \"getn with UTF-8 and binary\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/utf8.txt\", __DIR__), [:utf8])\n    assert \"Русский\" == IO.getn(file, \"\", 7)\n    assert \"\\n日\\n\" == IO.getn(file, \"\", :eof)\n    assert :eof == IO.getn(file, \"\", :eof)\n    assert File.close(file) == :ok\n  end\n\n  test \"gets\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/file.txt\", __DIR__), [:charlist])\n    assert ~c\"FOO\\n\" == IO.gets(file, \"\")\n    assert :eof == IO.gets(file, \"\")\n    assert File.close(file) == :ok\n  end\n\n  test \"gets with UTF-8 and binary\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/utf8.txt\", __DIR__), [:utf8])\n    assert \"Русский\\n\" == IO.gets(file, \"\")\n    assert \"日\\n\" == IO.gets(file, \"\")\n    assert File.close(file) == :ok\n  end\n\n  test \"read with eof\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/file.txt\", __DIR__))\n    assert \"FOO\\n\" == IO.read(file, :eof)\n    assert :eof == IO.read(file, :eof)\n    assert File.close(file) == :ok\n  end\n\n  test \"read with eof and UTF-8 and binary\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/utf8.txt\", __DIR__), [:utf8])\n    assert \"Русский\\n日\\n\" == IO.read(file, :eof)\n    assert :eof == IO.read(file, :eof)\n    assert File.close(file) == :ok\n  end\n\n  test \"readline\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/file.txt\", __DIR__))\n    assert \"FOO\\n\" == IO.read(file, :line)\n    assert :eof == IO.read(file, :line)\n    assert File.close(file) == :ok\n  end\n\n  test \"readline with UTF-8 and binary\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/utf8.txt\", __DIR__), [:utf8])\n    assert \"Русский\\n\" == IO.read(file, :line)\n    assert \"日\\n\" == IO.read(file, :line)\n    assert File.close(file) == :ok\n  end\n\n  test \"binread with eof\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/utf8.txt\", __DIR__))\n    assert \"Русский\\n日\\n\" == IO.binread(file, :eof)\n    assert :eof == IO.binread(file, :eof)\n    assert File.close(file) == :ok\n  end\n\n  test \"binread with line\" do\n    {:ok, file} = File.open(Path.expand(~c\"fixtures/utf8.txt\", __DIR__))\n    assert \"Русский\\n\" == IO.binread(file, :line)\n    assert \"日\\n\" == IO.binread(file, :line)\n    assert File.close(file) == :ok\n  end\n\n  test \"puts with chardata\" do\n    assert capture_io(fn -> IO.puts(\"hello\") end) == \"hello\\n\"\n    assert capture_io(fn -> IO.puts(~c\"hello\") end) == \"hello\\n\"\n    assert capture_io(fn -> IO.puts(:hello) end) == \"hello\\n\"\n    assert capture_io(fn -> IO.puts(13) end) == \"13\\n\"\n  end\n\n  describe \"warn\" do\n    test \"with chardata\" do\n      capture_io(:stderr, fn -> IO.warn(\"hello\") end)\n      |> assert_emits([\"hello\", \"(ex_unit #{System.version()}) lib/ex_unit\"])\n\n      capture_io(:stderr, fn -> IO.warn(~c\"hello\") end)\n      |> assert_emits([\"hello\", \"(ex_unit #{System.version()}) lib/ex_unit\"])\n\n      capture_io(:stderr, fn -> IO.warn(:hello) end)\n      |> assert_emits([\"hello\", \"(ex_unit #{System.version()}) lib/ex_unit\"])\n\n      capture_io(:stderr, fn -> IO.warn(13) end)\n      |> assert_emits([\"13\", \"(ex_unit #{System.version()}) lib/ex_unit\"])\n    end\n\n    test \"no stacktrace\" do\n      assert capture_io(:stderr, fn -> IO.warn(\"hello\", []) end) =~ \"hello\\n\"\n    end\n\n    test \"with stacktrace\" do\n      stacktrace = [{IEx.Evaluator, :eval, 4, [file: ~c\"lib/iex/evaluator.ex\", line: 108]}]\n\n      output = capture_io(:stderr, fn -> IO.warn(\"hello\", stacktrace) end)\n\n      assert output =~ \"hello\"\n      assert output =~ \"lib/iex/evaluator.ex:108: IEx.Evaluator.eval/4\"\n    end\n\n    test \"with env\" do\n      output = capture_io(:stderr, fn -> IO.warn(\"hello\", __ENV__) end)\n\n      assert output =~ \"hello\"\n\n      assert output =~\n               ~r\"(lib/elixir/)?test/elixir/io_test.exs:#{__ENV__.line - 5}: IOTest.\\\"test warn with env\\\"/1\"\n    end\n\n    test \"with options\" do\n      capture_io(:stderr, fn ->\n        IO.warn(\"hello\", line: 13, file: \"lib/foo.ex\", module: Foo, function: {:bar, 1})\n      end)\n      |> assert_emits([\"hello\", \"lib/foo.ex:13: Foo.bar/1\"])\n\n      capture_io(:stderr, fn ->\n        IO.warn(\"hello\", file: \"lib/foo.ex\", module: Foo, function: {:bar, 1})\n      end)\n      |> assert_emits([\"hello\", \"lib/foo.ex: Foo.bar/1\"])\n\n      capture_io(:stderr, fn -> IO.warn(\"hello\", file: \"lib/foo.ex\", module: Foo) end)\n      |> assert_emits([\"hello\", \"lib/foo.ex: Foo (module)\"])\n\n      capture_io(:stderr, fn -> IO.warn(\"hello\", file: \"lib/foo.ex\") end)\n      |> assert_emits([\"hello\", \"lib/foo.ex: (file)\"])\n\n      capture_io(:stderr, fn ->\n        IO.warn(\"hello\", file: \"lib/foo.ex\", function: {:bar, 1})\n      end)\n      |> assert_emits([\"hello\", \"lib/foo.ex: (file)\"])\n\n      assert capture_io(:stderr, fn ->\n               IO.warn(\"hello\", line: 13, module: Foo, function: {:bar, 1})\n             end) =~ \"hello\"\n    end\n  end\n\n  test \"write with chardata\" do\n    assert capture_io(fn -> IO.write(\"hello\") end) == \"hello\"\n    assert capture_io(fn -> IO.write(~c\"hello\") end) == \"hello\"\n    assert capture_io(fn -> IO.write(:hello) end) == \"hello\"\n    assert capture_io(fn -> IO.write(13) end) == \"13\"\n  end\n\n  test \"gets with chardata\" do\n    assert capture_io(\"foo\\n\", fn -> IO.gets(\"hello\") end) == \"hello\"\n    assert capture_io(\"foo\\n\", fn -> IO.gets(~c\"hello\") end) == \"hello\"\n    assert capture_io(\"foo\\n\", fn -> IO.gets(:hello) end) == \"hello\"\n    assert capture_io(\"foo\\n\", fn -> IO.gets(13) end) == \"13\"\n  end\n\n  test \"getn with chardata\" do\n    assert capture_io(\"foo\\n\", fn -> IO.getn(\"hello\", 3) end) == \"hello\"\n    assert capture_io(\"foo\\n\", fn -> IO.getn(~c\"hello\", 3) end) == \"hello\"\n    assert capture_io(\"foo\\n\", fn -> IO.getn(:hello, 3) end) == \"hello\"\n    assert capture_io(\"foo\\n\", fn -> IO.getn(13, 3) end) == \"13\"\n  end\n\n  test \"getn with different arities\" do\n    assert capture_io(\"hello\", fn ->\n             input = IO.getn(\">\")\n             IO.write(input)\n           end) == \">h\"\n\n    assert capture_io(\"hello\", fn ->\n             input = IO.getn(\">\", 3)\n             IO.write(input)\n           end) == \">hel\"\n\n    assert capture_io(\"hello\", fn ->\n             input = IO.getn(Process.group_leader(), \">\")\n             IO.write(input)\n           end) == \">h\"\n\n    assert capture_io(\"hello\", fn ->\n             input = IO.getn(Process.group_leader(), \">\")\n             IO.write(input)\n           end) == \">h\"\n\n    assert capture_io(\"hello\", fn ->\n             input = IO.getn(Process.group_leader(), \">\", 99)\n             IO.write(input)\n           end) == \">hello\"\n  end\n\n  test \"inspect\" do\n    assert capture_io(fn -> IO.inspect(1) end) == \"1\\n\"\n    assert capture_io(fn -> IO.inspect(1, label: \"foo\") end) == \"foo: 1\\n\"\n    assert capture_io(fn -> IO.inspect(1, label: :foo) end) == \"foo: 1\\n\"\n  end\n\n  test \"stream\" do\n    assert IO.stream() == IO.stream(:stdio, :line)\n    assert IO.binstream() == IO.binstream(:stdio, :line)\n  end\n\n  test \"iodata_empty?\" do\n    assert IO.iodata_empty?([])\n    assert IO.iodata_empty?(\"\")\n    assert IO.iodata_empty?([[\"\", []] | \"\"])\n\n    refute IO.iodata_empty?([1])\n    refute IO.iodata_empty?(\"1\")\n    refute IO.iodata_empty?([[\"\", []] | \"ok\"])\n  end\n\n  defp assert_emits(output, messages) do\n    for m <- messages do\n      assert output =~ m\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/json_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule JSONTest do\n  use ExUnit.Case, async: true\n\n  defmodule Token do\n    defstruct [:value]\n\n    defimpl JSON.Encoder do\n      def encode(token, encoder) do\n        [?[, encoder.(token.value, encoder), ?]]\n      end\n    end\n  end\n\n  doctest JSON\n\n  describe \"encode\" do\n    test \"atoms\" do\n      assert JSON.encode!([nil, false, true, :another]) == \"[null,false,true,\\\"another\\\"]\"\n    end\n\n    test \"binaries\" do\n      assert JSON.encode!(\"hello\\0world\\t✂️\") == \"\\\"hello\\\\u0000world\\\\t✂️\\\"\"\n    end\n\n    test \"integers\" do\n      assert JSON.encode!(123_456) == \"123456\"\n    end\n\n    test \"floats\" do\n      assert JSON.encode!(123.456) == \"123.456\"\n    end\n\n    test \"maps\" do\n      assert JSON.encode!(%{1 => 2, 3.0 => 4.0, ~c\"list\" => ~c\"list\", key: :bar}) ==\n               \"{\\\"1\\\":2,\\\"3.0\\\":4.0,\\\"key\\\":\\\"bar\\\",\\\"list\\\":[108,105,115,116]}\"\n    end\n\n    test \"lists\" do\n      assert JSON.encode!([1, 1.0, \"one\", %{1 => 2, 3.0 => 4.0, key: :bar}]) ==\n               \"[1,1.0,\\\"one\\\",{\\\"1\\\":2,\\\"3.0\\\":4.0,\\\"key\\\":\\\"bar\\\"}]\"\n    end\n\n    test \"structs\" do\n      assert JSON.encode!(%Token{value: :example}) == \"[\\\"example\\\"]\"\n      assert JSON.encode!(%Token{value: \"hello\\0world\"}) == \"[\\\"hello\\\\u0000world\\\"]\"\n    end\n\n    test \"calendar\" do\n      assert JSON.encode!(~D[2010-04-17]) == \"\\\"2010-04-17\\\"\"\n      assert JSON.encode!(~T[14:00:00.123]) == \"\\\"14:00:00.123\\\"\"\n      assert JSON.encode!(~N[2010-04-17 14:00:00.123]) == \"\\\"2010-04-17T14:00:00.123\\\"\"\n      assert JSON.encode!(~U[2010-04-17 14:00:00.123Z]) == \"\\\"2010-04-17T14:00:00.123Z\\\"\"\n      assert JSON.encode!(Duration.new!(month: 2, hour: 3)) == \"\\\"P2MT3H\\\"\"\n    end\n  end\n\n  describe \"JSON.Encoder\" do\n    defp protocol_encode(term) do\n      term\n      |> JSON.Encoder.encode(&JSON.protocol_encode/2)\n      |> IO.iodata_to_binary()\n    end\n\n    test \"atoms\" do\n      assert protocol_encode(:another) == \"\\\"another\\\"\"\n      assert protocol_encode([nil, false, true, :another]) == \"[null,false,true,\\\"another\\\"]\"\n    end\n\n    test \"binaries\" do\n      assert protocol_encode(\"hello\\0world\\t✂️\") == \"\\\"hello\\\\u0000world\\\\t✂️\\\"\"\n    end\n\n    test \"integers\" do\n      assert protocol_encode(123_456) == \"123456\"\n    end\n\n    test \"floats\" do\n      assert protocol_encode(123.456) == \"123.456\"\n    end\n\n    test \"maps\" do\n      assert protocol_encode(%{1 => 2, 3.0 => 4.0, ~c\"list\" => ~c\"list\", key: :bar}) ==\n               \"{\\\"1\\\":2,\\\"3.0\\\":4.0,\\\"key\\\":\\\"bar\\\",\\\"list\\\":[108,105,115,116]}\"\n    end\n\n    test \"lists\" do\n      assert protocol_encode([1, 1.0, \"one\", %{1 => 2, 3.0 => 4.0, key: :bar}]) ==\n               \"[1,1.0,\\\"one\\\",{\\\"1\\\":2,\\\"3.0\\\":4.0,\\\"key\\\":\\\"bar\\\"}]\"\n    end\n\n    test \"structs\" do\n      assert protocol_encode(%Token{value: :example}) == \"[\\\"example\\\"]\"\n      assert protocol_encode(%Token{value: \"hello\\0world\"}) == \"[\\\"hello\\\\u0000world\\\"]\"\n    end\n  end\n\n  test \"encode_to_iodata\" do\n    list = JSON.encode_to_iodata!([1, 1.0, \"one\", %{1 => 2, 3.0 => 4.0, key: :bar}])\n    assert is_list(list)\n    assert IO.iodata_to_binary(list) == \"[1,1.0,\\\"one\\\",{\\\"1\\\":2,\\\"3.0\\\":4.0,\\\"key\\\":\\\"bar\\\"}]\"\n\n    list =\n      JSON.encode_to_iodata!([\n        ~T[12:34:56.78],\n        ~D[2024-12-31],\n        ~N[2010-04-17 14:00:00.123],\n        ~U[2010-04-17 14:00:00.123Z],\n        Duration.new!(month: 2, hour: 3)\n      ])\n\n    assert IO.iodata_to_binary(list) ==\n             ~s'[\"12:34:56.78\",\"2024-12-31\",\"2010-04-17T14:00:00.123\",\"2010-04-17T14:00:00.123Z\",\"P2MT3H\"]'\n  end\n\n  test \"deprecated\" do\n    assert JSON.encode!([:hello, \"world\"]) == \"[\\\"hello\\\",\\\"world\\\"]\"\n\n    list = JSON.encode_to_iodata!([:hello, \"world\"])\n    assert is_list(list)\n    assert IO.iodata_to_binary(list) == \"[\\\"hello\\\",\\\"world\\\"]\"\n  end\n\n  describe \"deriving\" do\n    defmodule WithOnly do\n      @derive {JSON.Encoder, only: [:a, :b, :d]}\n      # The encoded order depends on only\n      defstruct Enum.shuffle([:a, :b, :c, :d])\n    end\n\n    test \"with only\" do\n      assert [\"{\\\"a\\\":\", _, \",\\\"b\\\":\", _, \",\\\"d\\\":\", _, 125] =\n               json = JSON.encode_to_iodata!(%WithOnly{a: :a, b: \"b\", c: make_ref(), d: [?d]})\n\n      assert IO.iodata_to_binary(json) == \"{\\\"a\\\":\\\"a\\\",\\\"b\\\":\\\"b\\\",\\\"d\\\":[100]}\"\n    end\n\n    defmodule WithExcept do\n      @derive {JSON.Encoder, except: [:c]}\n      defstruct [:a, :b, :c, :d]\n    end\n\n    test \"with except\" do\n      assert [\"{\\\"a\\\":\", _, \",\\\"b\\\":\", _, \",\\\"d\\\":\", _, 125] =\n               json = JSON.encode_to_iodata!(%WithExcept{a: :a, b: \"b\", c: make_ref(), d: [?d]})\n\n      assert IO.iodata_to_binary(json) == \"{\\\"a\\\":\\\"a\\\",\\\"b\\\":\\\"b\\\",\\\"d\\\":[100]}\"\n    end\n\n    defmodule WithEmpty do\n      @derive {JSON.Encoder, only: []}\n      defstruct [:a, :b]\n    end\n\n    test \"with empty\" do\n      assert JSON.encode_to_iodata!(%WithEmpty{}) == \"{}\"\n    end\n  end\n\n  describe \"decode\" do\n    test \"succeeds\" do\n      assert JSON.decode(\"[null,123,456.7,\\\"string\\\",{\\\"key\\\":\\\"value\\\"}]\") ==\n               {:ok, [nil, 123, 456.7, \"string\", %{\"key\" => \"value\"}]}\n\n      assert JSON.decode!(\"[null,123,456.7,\\\"string\\\",{\\\"key\\\":\\\"value\\\"}]\") ==\n               [nil, 123, 456.7, \"string\", %{\"key\" => \"value\"}]\n    end\n\n    test \"unexpected end\" do\n      assert JSON.decode(\"{\") == {:error, {:unexpected_end, 1}}\n\n      assert_raise JSON.DecodeError,\n                   \"unexpected end of JSON binary at position (byte offset) 1\",\n                   fn -> JSON.decode!(\"{\") end\n    end\n\n    test \"invalid byte\" do\n      assert JSON.decode(\",\") == {:error, {:invalid_byte, 0, ?,}}\n      assert JSON.decode(\"123o\") == {:error, {:invalid_byte, 3, ?o}}\n\n      assert_raise JSON.DecodeError,\n                   \"invalid byte 111 at position (byte offset) 3\",\n                   fn -> JSON.decode!(\"123o\") end\n    end\n\n    test \"unexpected sequence\" do\n      assert JSON.decode(\"\\\"\\\\ud8aa\\\\udcxx\\\"\") ==\n               {:error, {:unexpected_sequence, 1, \"\\\\ud8aa\\\\udcxx\"}}\n\n      assert_raise JSON.DecodeError,\n                   \"unexpected sequence \\\"\\\\\\\\ud8aa\\\\\\\\udcxx\\\" at position (byte offset) 1\",\n                   fn -> JSON.decode!(\"\\\"\\\\ud8aa\\\\udcxx\\\"\") end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/alias_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\nalias Kernel.AliasTest.Nested, as: Nested\n\ndefmodule Nested do\n  def value, do: 1\nend\n\ndefmodule Kernel.AliasTest do\n  use ExUnit.Case, async: true\n\n  test \"alias Erlang\" do\n    alias :lists, as: MyList\n    assert MyList.flatten([1, [2], 3]) == [1, 2, 3]\n    assert Elixir.MyList.Bar == :\"Elixir.MyList.Bar\"\n    assert MyList.Bar == :\"Elixir.lists.Bar\"\n  end\n\n  test \"double alias\" do\n    alias Kernel.AliasTest.Nested, as: Nested2\n    assert Nested.value() == 1\n    assert Nested2.value() == 1\n  end\n\n  test \"overwritten alias\" do\n    assert alias(List, as: Nested) == List\n    assert Nested.flatten([[13]]) == [13]\n  end\n\n  test \"non-recursive alias\" do\n    alias Billing, as: BillingLib\n    alias MyApp.Billing\n    assert BillingLib == :\"Elixir.Billing\"\n    assert Billing == :\"Elixir.MyApp.Billing\"\n  end\n\n  test \"lexical\" do\n    if Process.get(:unused, true) do\n      alias OMG, as: List, warn: false\n    else\n      alias ABC, as: List, warn: false\n    end\n\n    assert List.flatten([1, [2], 3]) == [1, 2, 3]\n  end\n\n  defmodule Elixir do\n    def sample, do: 1\n  end\n\n  test \"nested Elixir alias\" do\n    assert Kernel.AliasTest.Elixir.sample() == 1\n  end\n\n  test \"multi-call\" do\n    result = alias unquote(Inspect).{Opts, Algebra}\n    assert result == [Inspect.Opts, Inspect.Algebra]\n    assert %Opts{} == %Inspect.Opts{}\n    assert Algebra.empty() == []\n  end\n\n  test \"alias removal\" do\n    alias __MODULE__.Foo\n    assert Foo == __MODULE__.Foo\n    alias Elixir.Foo\n    assert Foo == Elixir.Foo\n    alias Elixir.Bar\n  end\nend\n\ndefmodule Kernel.AliasNestingGenerator do\n  defmacro create do\n    quote do\n      defmodule Parent do\n        def a, do: :a\n      end\n\n      defmodule Parent.Child do\n        def b, do: Parent.a()\n      end\n    end\n  end\nend\n\ndefmodule Kernel.AliasNestingTest do\n  use ExUnit.Case, async: true\n\n  test \"aliases nesting\" do\n    require Kernel.AliasNestingGenerator\n    Kernel.AliasNestingGenerator.create()\n\n    assert Parent.a() == :a\n    assert Parent.Child.b() == :a\n  end\n\n  defmodule Nested do\n    def value, do: 2\n  end\n\n  test \"aliases nesting with previous alias\" do\n    assert Nested.value() == 2\n  end\n\n  alias Another.AliasEnv, warn: false\n  def aliases_before, do: __ENV__.aliases\n\n  defmodule Elixir.AliasEnv do\n    def aliases_nested, do: __ENV__.aliases\n  end\n\n  def aliases_after, do: __ENV__.aliases\n\n  test \"keeps env after overriding nested Elixir module of the same name\" do\n    assert aliases_before() == [\n             {Elixir.Nested, Kernel.AliasNestingTest.Nested},\n             {Elixir.AliasEnv, Another.AliasEnv}\n           ]\n\n    assert Elixir.AliasEnv.aliases_nested() == [\n             {Elixir.Nested, Kernel.AliasNestingTest.Nested},\n             {Elixir.AliasEnv, Another.AliasEnv}\n           ]\n\n    assert aliases_after() == [\n             {Elixir.Nested, Kernel.AliasNestingTest.Nested},\n             {Elixir.AliasEnv, Another.AliasEnv}\n           ]\n  end\nend\n\n# Test case extracted from using records with aliases\n# and @before_compile. We are basically testing that\n# macro aliases are not leaking from the macro.\n\ndefmodule Macro.AliasTest.Definer do\n  defmacro __using__(_options) do\n    quote do\n      @before_compile unquote(__MODULE__)\n    end\n  end\n\n  defmacro __before_compile__(_env) do\n    quote do\n      defmodule First do\n        defstruct foo: :bar\n      end\n\n      defmodule Second do\n        defstruct baz: %First{}\n      end\n    end\n  end\nend\n\ndefmodule Macro.AliasTest.Aliaser do\n  defmacro __using__(_options) do\n    quote do\n      alias Some.First\n    end\n  end\nend\n\ndefmodule Macro.AliasTest.User do\n  use ExUnit.Case, async: true\n\n  use Macro.AliasTest.Definer\n  use Macro.AliasTest.Aliaser\n\n  test \"has a struct defined from after compile\" do\n    assert is_map(struct(Macro.AliasTest.User.First, []))\n    assert is_map(struct(Macro.AliasTest.User.Second, []).baz)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/binary_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.BinaryTest do\n  use ExUnit.Case, async: true\n\n  test \"heredoc\" do\n    assert 11 == __ENV__.line\n\n    assert \"foo\\nbar\\n\" == \"\"\"\n           foo\n           bar\n           \"\"\"\n\n    assert 18 == __ENV__.line\n\n    assert \"foo\\nbar \\\"\\\"\\\"\\n\" == \"\"\"\n           foo\n           bar \\\"\"\"\n           \"\"\"\n  end\n\n  test \"aligned heredoc\" do\n    assert \"foo\\nbar\\n\" == \"\"\"\n           foo\n           bar\n           \"\"\"\n  end\n\n  test \"heredoc with interpolation\" do\n    assert \"35\\n\" == \"\"\"\n           #{__ENV__.line}\n           \"\"\"\n\n    assert \"\\n40\\n\" == \"\"\"\n\n           #{__ENV__.line}\n           \"\"\"\n  end\n\n  test \"heredoc in call\" do\n    assert \"foo\\nbar\" ==\n             Kernel.<>(\n               \"\"\"\n               foo\n               \"\"\",\n               \"bar\"\n             )\n  end\n\n  test \"heredoc with heredoc inside interpolation\" do\n    assert \"\"\"\n           1\n           #{\"\"\"\n           2\n           \"\"\"}\n           \"\"\" == \"1\\n2\\n\\n\"\n  end\n\n  test \"UTF-8\" do\n    assert byte_size(\" ゆんゆん\") == 13\n  end\n\n  test \"UTF-8 char\" do\n    assert ?ゆ == 12422\n  end\n\n  test \"size outside match\" do\n    x = 16\n    assert <<0::size(x)>> == <<0, 0>>\n  end\n\n  test \"string concatenation as match\" do\n    \"foo\" <> x = \"foobar\"\n    assert x == \"bar\"\n\n    <<\"foo\">> <> x = \"foobar\"\n    assert x == \"bar\"\n\n    <<\"f\", \"oo\">> <> x = \"foobar\"\n    assert x == \"bar\"\n\n    <<x::binary-size(3)>> <> _ = \"foobar\"\n    assert x == \"foo\"\n\n    size = 3\n    <<x::binary-size(^size)>> <> _ = \"foobar\"\n    assert x == \"foo\"\n\n    size = 3\n    <<size, x::binary-size(^size)>> <> _ = <<10, \"foobar\">>\n    assert x == \"foo\"\n    assert size == 10\n\n    <<x::6*4-binary>> <> _ = \"foobar\"\n    assert x == \"foo\"\n\n    <<x::3-bytes>> <> _ = \"foobar\"\n    assert x == \"foo\"\n\n    <<x::24-bits>> <> _ = \"foobar\"\n    assert x == \"foo\"\n\n    <<x::utf8>> <> _ = \"foobar\"\n    assert x == ?f\n  end\n\n  test \"string concatenation outside match\" do\n    x = \"bar\"\n    assert \"foobar\" = \"foo\" <> x\n    assert \"barfoo\" = x <> \"foo\"\n  end\n\n  test \"invalid string concatenation arguments\" do\n    assert_raise ArgumentError, ~r\"expected binary argument in <> operator but got: :bar\", fn ->\n      Code.eval_string(~s[\"foo\" <> :bar])\n    end\n\n    assert_raise ArgumentError, ~r\"expected binary argument in <> operator but got: 1\", fn ->\n      Code.eval_string(~s[\"foo\" <> 1])\n    end\n\n    message = ~r\"cannot perform prefix match because the left operand of <> has unknown size.\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(~s[a <> \"b\" = \"ab\"])\n    end\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(~s[\"a\" <> b <> \"c\" = \"abc\"])\n    end\n  end\n\n  test \"hex\" do\n    assert \"\\x76\" == \"v\"\n    assert \"\\u00FF\" == \"ÿ\"\n    assert \"\\u{A}\" == \"\\n\"\n    assert \"\\u{E9}\" == \"é\"\n    assert \"\\u{10F}\" == <<196, 143>>\n    assert \"\\u{10FF}\" == <<225, 131, 191>>\n    assert \"\\u{10FFF}\" == <<240, 144, 191, 191>>\n    assert \"\\u{10FFFF}\" == <<244, 143, 191, 191>>\n  end\n\n  test \"match\" do\n    assert match?(<<?a, _::binary>>, \"ab\")\n    refute match?(<<?a, _::binary>>, \"cd\")\n    assert match?(<<_::utf8>> <> _, \"éf\")\n  end\n\n  test \"interpolation\" do\n    res = \"hello \\\\abc\"\n    assert \"hello #{\"\\\\abc\"}\" == res\n    assert \"hello #{\"\\\\abc\" <> \"\"}\" == res\n  end\n\n  test \"pattern match\" do\n    s = 16\n    assert <<_a, _b::size(^s)>> = \"foo\"\n  end\n\n  test \"pattern match with splice\" do\n    assert <<1, <<2, 3, 4>>, 5>> = <<1, 2, 3, 4, 5>>\n  end\n\n  test \"partial application\" do\n    assert (&<<&1, 2>>).(1) == <<1, 2>>\n    assert (&<<&1, &2>>).(1, 2) == <<1, 2>>\n    assert (&<<&2, &1>>).(2, 1) == <<1, 2>>\n  end\n\n  test \"literal\" do\n    assert <<106, 111, 115, 195, 169>> == <<\"josé\">>\n    assert <<106, 111, 115, 195, 169>> == <<\"#{:josé}\">>\n    assert <<106, 111, 115, 195, 169>> == <<\"josé\"::binary>>\n    assert <<106, 111, 115, 195, 169>> == <<\"josé\"::bits>>\n    assert <<106, 111, 115, 195, 169>> == <<\"josé\"::bitstring>>\n    assert <<106, 111, 115, 195, 169>> == <<\"josé\"::bytes>>\n\n    assert <<106, 111, 115, 195, 169>> == <<\"josé\"::utf8>>\n    assert <<0, 106, 0, 111, 0, 115, 0, 233>> == <<\"josé\"::utf16>>\n    assert <<106, 0, 111, 0, 115, 0, 233, 0>> == <<\"josé\"::little-utf16>>\n    assert <<0, 0, 0, 106, 0, 0, 0, 111, 0, 0, 0, 115, 0, 0, 0, 233>> == <<\"josé\"::utf32>>\n  end\n\n  test \"literal errors\" do\n    message = \"conflicting type specification for bit field\"\n\n    assert_compile_error(message, fn ->\n      Code.eval_string(~s[<<\"foo\"::integer>>])\n    end)\n\n    assert_compile_error(message, fn ->\n      Code.eval_string(~s[<<\"foo\"::float>>])\n    end)\n  end\n\n  @bitstring <<\"foo\", 16::4>>\n\n  test \"bitstring attribute\" do\n    assert @bitstring == <<\"foo\", 16::4>>\n  end\n\n  @binary \"new \"\n\n  test \"bitsyntax expansion\" do\n    assert <<@binary, \"world\">> == \"new world\"\n  end\n\n  test \"bitsyntax translation\" do\n    refb = \"sample\"\n    sec_data = \"another\"\n\n    <<\n      byte_size(refb)::size(1)-big-signed-integer-unit(8),\n      refb::binary,\n      byte_size(sec_data)::1*16-big-signed-integer,\n      sec_data::binary\n    >>\n  end\n\n  test \"bitsyntax size shortcut\" do\n    assert <<1::3>> == <<1::size(3)>>\n    assert <<1::3*8>> == <<1::size(3)-unit(8)>>\n  end\n\n  test \"bitsyntax variable size\" do\n    x = 8\n    assert <<_, _::size(^x)>> = <<?a, ?b>>\n    assert (fn <<_, _::size(^x)>> -> true end).(<<?a, ?b>>)\n  end\n\n  test \"bitsyntax size using expressions\" do\n    x = 8\n    assert <<1::size(x - 5)>>\n\n    foo = %{bar: 5}\n    assert <<1::size(foo.bar)>>\n    assert <<1::size(length(~c\"abcd\"))>>\n    assert <<255::size(hd(List.flatten([3])))>>\n  end\n\n  test \"bitsyntax size using guard expressions in match context\" do\n    x = 8\n    assert <<1::size(^x - 5)>> = <<1::3>>\n    assert <<1::size(^x - 5)-unit(8)>> = <<1::3*8>>\n    assert <<1::size(length(~c\"abcd\"))>> = <<1::4>>\n\n    foo = %{bar: 5}\n    assert <<1::size((^foo).bar)>> = <<1::5>>\n  end\n\n  test \"bitsyntax size with pinned integer\" do\n    a = 1\n    b = <<2, 3>>\n    assert <<^a, ^b::binary>> = <<1, 2, 3>>\n  end\n\n  test \"automatic size computation of matched bitsyntax variable\" do\n    var = \"foo\"\n    <<^var::binary, rest::binary>> = \"foobar\"\n    assert rest == \"bar\"\n\n    <<^var::bytes, rest::bytes>> = \"foobar\"\n    assert rest == \"bar\"\n\n    ^var <> rest = \"foobar\"\n    assert rest == \"bar\"\n\n    var = <<0, 1>>\n    <<^var::bitstring, rest::bitstring>> = <<0, 1, 2, 3>>\n    assert rest == <<2, 3>>\n\n    <<^var::bits, rest::bits>> = <<0, 1, 2, 3>>\n    assert rest == <<2, 3>>\n\n    ^var <> rest = <<0, 1, 2, 3>>\n    assert rest == <<2, 3>>\n  end\n\n  defmacro signed_16 do\n    quote do\n      big - signed - integer - unit(16)\n    end\n  end\n\n  defmacro refb_spec do\n    quote do\n      1 * 8 - big - signed - integer\n    end\n  end\n\n  test \"bitsyntax macro\" do\n    refb = \"sample\"\n    sec_data = \"another\"\n\n    <<\n      byte_size(refb)::refb_spec(),\n      refb::binary,\n      byte_size(sec_data)::size(1)-signed_16(),\n      sec_data::binary\n    >>\n  end\n\n  test \"bitsyntax macro is expanded with a warning\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"<<1::refb_spec>>\", [], __ENV__)\n           end) =~\n             \"bitstring specifier \\\"refb_spec\\\" does not exist and is being expanded to \\\"refb_spec()\\\"\"\n\n    assert capture_err(fn ->\n             Code.eval_string(\"<<1::size(1)-signed_16>>\", [], __ENV__)\n           end) =~\n             \"bitstring specifier \\\"signed_16\\\" does not exist and is being expanded to \\\"signed_16()\\\"\"\n  end\n\n  test \"bitsyntax with extra parentheses warns\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"<<1::big()>>\")\n           end) =~ \"extra parentheses on a bitstring specifier \\\"big()\\\" have been deprecated\"\n\n    assert capture_err(fn ->\n             Code.eval_string(\"<<1::size(8)-integer()>>\")\n           end) =~ \"extra parentheses on a bitstring specifier \\\"integer()\\\" have been deprecated\"\n  end\n\n  defp capture_err(fun) do\n    ExUnit.CaptureIO.capture_io(:stderr, fun)\n  end\n\n  defp assert_compile_error(message, fun) do\n    assert capture_err(fn -> assert_raise CompileError, fun end) =~ message\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/charlist_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule CharlistTest do\n  use ExUnit.Case, async: true\n\n  test \"heredoc\" do\n    assert __ENV__.line == 11\n\n    assert ~c\"foo\\nbar\\n\" == ~c\"\"\"\n           foo\n           bar\n           \"\"\"\n\n    assert __ENV__.line == 18\n\n    assert ~c\"foo\\nbar '''\\n\" == ~c\"\"\"\n           foo\n           bar \\'\\'\\'\n           \"\"\"\n  end\n\n  test \"UTF-8\" do\n    assert length(~c\" ゆんゆん\") == 5\n  end\n\n  test \"hex\" do\n    assert ~c\"\\x76\" == ~c\"v\"\n    assert ~c\"\\u00fF\" == ~c\"ÿ\"\n    assert ~c\"\\u{A}\" == ~c\"\\n\"\n    assert ~c\"\\u{e9}\" == ~c\"é\"\n    assert ~c\"\\u{10F}\" == [271]\n    assert ~c\"\\u{10FF}\" == [4351]\n    assert ~c\"\\u{10FFF}\" == [69631]\n    assert ~c\"\\u{10FFFF}\" == [1_114_111]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/cli_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\nimport PathHelpers\n\ndefmodule Retry do\n  # Tests that write to stderr fail on Windows due to late writes,\n  # so we do a simple retry already them.\n  defmacro stderr_test(msg, context \\\\ quote(do: _), do: block) do\n    if windows?() do\n      quote do\n        test unquote(msg), unquote(context) do\n          unquote(__MODULE__).retry(fn -> unquote(block) end, 3)\n        end\n      end\n    else\n      quote do\n        test(unquote(msg), unquote(context), do: unquote(block))\n      end\n    end\n  end\n\n  def retry(fun, 1) do\n    fun.()\n  end\n\n  def retry(fun, n) do\n    try do\n      fun.()\n    rescue\n      _ -> retry(fun, n - 1)\n    end\n  end\nend\n\ndefmodule Kernel.CLITest do\n  use ExUnit.Case, async: true\n\n  import ExUnit.CaptureIO\n\n  defp run(argv) do\n    {config, argv} = Kernel.CLI.parse_argv(Enum.map(argv, &String.to_charlist/1))\n    assert Kernel.CLI.process_commands(config) == []\n    Enum.map(argv, &IO.chardata_to_string/1)\n  end\n\n  test \"argv handling\" do\n    assert capture_io(fn ->\n             assert run([\"-e\", \"IO.puts :ok\", \"sample.exs\", \"-o\", \"1\", \"2\"]) ==\n                      [\"sample.exs\", \"-o\", \"1\", \"2\"]\n           end) == \"ok\\n\"\n\n    assert capture_io(fn ->\n             assert run([\"-e\", \"IO.puts :ok\", \"--\", \"sample.exs\", \"-o\", \"1\", \"2\"]) ==\n                      [\"sample.exs\", \"-o\", \"1\", \"2\"]\n           end) == \"ok\\n\"\n\n    assert capture_io(fn ->\n             assert run([\"-e\", \"\", \"--\", \"sample.exs\", \"-o\", \"1\", \"2\"]) ==\n                      [\"sample.exs\", \"-o\", \"1\", \"2\"]\n           end)\n  end\nend\n\ntest_parameters =\n  if(PathHelpers.windows?(),\n    do: [%{cli_extension: \".bat\"}],\n    else: [%{cli_extension: \"\"}]\n  )\n\ndefmodule Kernel.CLI.ExecutableTest do\n  use ExUnit.Case,\n    async: true,\n    parameterize: test_parameters\n\n  import Retry\n\n  @tag :tmp_dir\n  test \"file smoke test\", context do\n    file = Path.join(context.tmp_dir, \"hello_world!.exs\")\n    File.write!(file, \"IO.puts :hello_world123\")\n    {output, 0} = System.cmd(elixir_executable(context.cli_extension), [file])\n    assert output =~ \"hello_world123\"\n  end\n\n  test \"--eval smoke test\", context do\n    {output, 0} =\n      System.cmd(elixir_executable(context.cli_extension), [\"--eval\", \"IO.puts :hello_world123\"])\n\n    assert output =~ \"hello_world123\"\n\n    # Check for -e and exclamation mark handling on Windows\n    assert {_output, 0} =\n             System.cmd(elixir_executable(context.cli_extension), [\"-e\", \"Time.new!(0, 0, 0)\"])\n  end\n\n  @tag :unix\n  # This test hangs on Windows but \"iex --version\" works on the command line\n  test \"iex smoke test\", %{cli_extension: cli_extension} do\n    output = iex(~c\"--version\", cli_extension)\n    assert output =~ \"Erlang/OTP #{System.otp_release()}\"\n    assert output =~ \"IEx #{System.version()}\"\n  end\n\n  test \"--version smoke test\", %{cli_extension: cli_extension} do\n    output = elixir(~c\"--version\", cli_extension)\n    assert output =~ \"Erlang/OTP #{System.otp_release()}\"\n    assert output =~ \"Elixir #{System.version()}\"\n\n    output = elixir(~c\"--version -e \\\"IO.puts(:test_output)\\\"\", cli_extension)\n    assert output =~ \"Erlang/OTP #{System.otp_release()}\"\n    assert output =~ \"Elixir #{System.version()}\"\n    assert output =~ \"Standalone options can't be combined with other options\"\n  end\n\n  test \"--short-version smoke test\", %{cli_extension: cli_extension} do\n    output = elixir(~c\"--short-version\", cli_extension)\n    assert output =~ System.version()\n    refute output =~ \"Erlang\"\n  end\n\n  stderr_test \"--help smoke test\", %{cli_extension: cli_extension} do\n    output = elixir(~c\"--help\", cli_extension)\n    assert output =~ \"Usage: elixir\"\n  end\n\n  stderr_test \"combining --help results in error\", %{cli_extension: cli_extension} do\n    output = elixir(~c\"-e 1 --help\", cli_extension)\n    assert output =~ \"--help : Standalone options can't be combined with other options\"\n\n    output = elixir(~c\"--help -e 1\", cli_extension)\n    assert output =~ \"--help : Standalone options can't be combined with other options\"\n  end\n\n  stderr_test \"combining --short-version results in error\", %{cli_extension: cli_extension} do\n    output = elixir(~c\"--short-version -e 1\", cli_extension)\n    assert output =~ \"--short-version : Standalone options can't be combined with other options\"\n\n    output = elixir(~c\"-e 1 --short-version\", cli_extension)\n    assert output =~ \"--short-version : Standalone options can't be combined with other options\"\n  end\n\n  test \"parses paths\", %{cli_extension: cli_extension} do\n    root = fixture_path(\"../../..\") |> to_charlist()\n\n    args =\n      ~c\"-pa \\\"#{root}/*\\\" -pz \\\"#{root}/lib/*\\\" -e \\\"IO.inspect(:code.get_path(), limit: :infinity)\\\"\"\n\n    list = elixir(args, cli_extension)\n    {path, _} = Code.eval_string(list, [])\n\n    # pa\n    assert to_charlist(Path.expand(~c\"ebin\", root)) in path\n    assert to_charlist(Path.expand(~c\"lib\", root)) in path\n    assert to_charlist(Path.expand(~c\"src\", root)) in path\n\n    # pz\n    assert to_charlist(Path.expand(~c\"lib/list\", root)) in path\n  end\n\n  stderr_test \"formats errors\", %{cli_extension: cli_extension} do\n    assert String.starts_with?(elixir(~c\"-e \\\":erlang.throw 1\\\"\", cli_extension), \"** (throw) 1\")\n\n    assert String.starts_with?(\n             elixir(~c\"-e \\\":erlang.error 1\\\"\", cli_extension),\n             \"** (ErlangError) Erlang error: 1\"\n           )\n\n    assert String.starts_with?(elixir(~c\"-e \\\"1 +\\\"\", cli_extension), \"** (TokenMissingError)\")\n\n    assert elixir(\n             ~c\"-e \\\"Task.async(fn -> raise ArgumentError end) |> Task.await\\\"\",\n             cli_extension\n           ) =~\n             \"an exception was raised:\\n    ** (ArgumentError) argument error\"\n\n    assert elixir(\n             ~c\"-e \\\"IO.puts(Process.flag(:trap_exit, false)); exit({:shutdown, 1})\\\"\",\n             cli_extension\n           ) ==\n             \"false\\n\"\n  end\n\n  stderr_test \"blames exceptions\", %{cli_extension: cli_extension} do\n    error = elixir(~c\"-e \\\"Access.fetch :foo, :bar\\\"\", cli_extension)\n    assert error =~ \"** (FunctionClauseError) no function clause matching in Access.fetch/2\"\n    assert error =~ \"The following arguments were given to Access.fetch/2\"\n    assert error =~ \":foo\"\n    assert error =~ \"def fetch(-%module{} = container-, +key+)\"\n    assert error =~ ~r\"\\(elixir #{System.version()}\\) lib/access\\.ex:\\d+: Access\\.fetch/2\"\n  end\n\n  test \"invokes at_exit callbacks\" do\n    assert elixir(fixture_path(\"at_exit.exs\") |> to_charlist()) ==\n             \"goodbye cruel world with status 1\\n\"\n  end\nend\n\ndefmodule Kernel.CLI.RPCTest do\n  use ExUnit.Case, async: true\n\n  import Retry\n\n  defp rpc_eval(command) do\n    node = \"cli-rpc#{System.unique_integer()}@127.0.0.1\"\n    elixir(~c\"--name #{node} --rpc-eval #{node} \\\"#{command}\\\"\")\n  end\n\n  test \"invokes command on remote node\" do\n    assert rpc_eval(\"IO.puts :ok\") == \"ok\\n\"\n  end\n\n  test \"invokes command on remote node without host and --name after --rpc-eval\" do\n    node = \"cli-rpc#{System.unique_integer()}\"\n    assert elixir(~c\"--rpc-eval #{node} \\\"IO.puts :ok\\\" --name #{node}@127.0.0.1 \") == \"ok\\n\"\n  end\n\n  test \"can be invoked multiple times\" do\n    node = \"cli-rpc#{System.unique_integer()}\"\n\n    assert elixir(\n             ~c\"--name #{node}@127.0.0.1 --rpc-eval #{node} \\\"IO.puts :foo\\\" --rpc-eval #{node} \\\"IO.puts :bar\\\"\"\n           ) == \"foo\\nbar\\n\"\n  end\n\n  # Windows does not provide an easy to check for missing args\n  @tag :unix\n  test \"fails on wrong arguments\" do\n    node = \"cli-rpc#{System.unique_integer()}\"\n\n    assert elixir(~c\"--name #{node}@127.0.0.1 --rpc-eval\") ==\n             \"--rpc-eval : wrong number of arguments\\n\"\n\n    assert elixir(~c\"--name #{node}@127.0.0.1 --rpc-eval #{node}\") ==\n             \"--rpc-eval : wrong number of arguments\\n\"\n  end\n\n  stderr_test \"properly formats errors\" do\n    assert String.starts_with?(rpc_eval(\":erlang.throw 1\"), \"** (throw) 1\")\n    assert String.starts_with?(rpc_eval(\":erlang.error 1\"), \"** (ErlangError) Erlang error: 1\")\n    assert String.starts_with?(rpc_eval(\"1 +\"), \"** (TokenMissingError)\")\n\n    assert rpc_eval(\"Task.async(fn -> raise ArgumentError end) |> Task.await\") =~\n             \"an exception was raised:\\n    ** (ArgumentError) argument error\"\n\n    assert rpc_eval(\"IO.puts(Process.flag(:trap_exit, false)); exit({:shutdown, 1})\") ==\n             \"false\\n\"\n  end\nend\n\ndefmodule Kernel.CLI.CompileTest do\n  use ExUnit.Case,\n    async: true,\n    parameterize: test_parameters\n\n  import Retry\n  @moduletag :tmp_dir\n\n  setup context do\n    beam_file_path = Path.join([context.tmp_dir, \"Elixir.CompileSample.beam\"])\n    fixture = fixture_path(\"compile_sample.ex\")\n    {:ok, [beam_file_path: beam_file_path, fixture: fixture]}\n  end\n\n  test \"compiles code\", context do\n    assert elixirc(~c\"#{context.fixture} -o #{context.tmp_dir}\", context.cli_extension) == \"\"\n    assert File.regular?(context.beam_file_path)\n\n    # Assert that the module is loaded into memory with the proper destination for the BEAM file.\n    Code.append_path(context.tmp_dir)\n    assert :code.which(CompileSample) |> List.to_string() == Path.expand(context.beam_file_path)\n  after\n    :code.purge(CompileSample)\n    :code.delete(CompileSample)\n    Code.delete_path(context.tmp_dir)\n  end\n\n  @tag :windows\n  stderr_test \"compiles code with Windows paths\", context do\n    try do\n      fixture = String.replace(context.fixture, \"/\", \"\\\\\")\n      tmp_dir_path = String.replace(context.tmp_dir, \"/\", \"\\\\\")\n      assert elixirc(~c\"#{fixture} -o #{tmp_dir_path}\", context.cli_extension) == \"\"\n      assert File.regular?(context[:beam_file_path])\n\n      # Assert that the module is loaded into memory with the proper destination for the BEAM file.\n      Code.append_path(context.tmp_dir)\n\n      assert :code.which(CompileSample) |> List.to_string() ==\n               Path.expand(context[:beam_file_path])\n    after\n      :code.purge(CompileSample)\n      :code.delete(CompileSample)\n      Code.delete_path(context.tmp_dir)\n    end\n  end\n\n  stderr_test \"fails on missing patterns\", context do\n    output =\n      elixirc(~c\"#{context.fixture} non_existing.ex -o #{context.tmp_dir}\", context.cli_extension)\n\n    assert output =~ \"non_existing.ex\"\n    refute output =~ \"compile_sample.ex\"\n    refute File.exists?(context.beam_file_path)\n  end\n\n  stderr_test \"fails on missing write access to .beam file\", context do\n    compilation_args = ~c\"#{context.fixture} -o #{context.tmp_dir}\"\n\n    assert elixirc(compilation_args, context.cli_extension) == \"\"\n    assert File.regular?(context.beam_file_path)\n\n    # Set the .beam file to read-only\n    File.chmod!(context.beam_file_path, 4)\n    {:ok, %{access: access}} = File.stat(context.beam_file_path)\n\n    # Can only assert when read-only applies to the user\n    if access != :read_write do\n      output = elixirc(compilation_args, context.cli_extension)\n\n      expected =\n        \"(File.Error) could not write to file #{inspect(context.beam_file_path)}: permission denied\"\n\n      assert output =~ expected\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/comprehension_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.ComprehensionTest do\n  use ExUnit.Case, async: true\n\n  import ExUnit.CaptureIO\n  require Integer\n\n  defmodule Pdict do\n    defstruct []\n\n    defimpl Collectable do\n      def into(struct) do\n        fun = fn\n          _, {:cont, x} -> Process.put(:into_cont, [x | Process.get(:into_cont)])\n          _, :done -> Process.put(:into_done, true)\n          _, :halt -> Process.put(:into_halt, true)\n        end\n\n        {struct, fun}\n      end\n    end\n  end\n\n  defp to_bin(x) do\n    <<x>>\n  end\n\n  defp nilly, do: nil\n\n  ## Enum comprehensions (the common case)\n\n  test \"for comprehensions\" do\n    enum = 1..3\n    assert for(x <- enum, do: x * 2) == [2, 4, 6]\n  end\n\n  test \"for comprehensions with matching\" do\n    assert for({_, x} <- 1..3, do: x * 2) == []\n  end\n\n  test \"for comprehensions with pin matching\" do\n    maps = [x: 1, y: 2, x: 3]\n    assert for({:x, v} <- maps, do: v * 2) == [2, 6]\n    x = :x\n    assert for({^x, v} <- maps, do: v * 2) == [2, 6]\n  end\n\n  test \"for comprehensions with guards\" do\n    assert for(x when x < 4 <- 1..10, do: x) == [1, 2, 3]\n    assert for(x when x == 3 when x == 7 <- 1..10, do: x) == [3, 7]\n  end\n\n  test \"for comprehensions with guards and filters\" do\n    assert for(\n             {var, _}\n             when is_atom(var) <- [{:foo, 1}, {2, :bar}],\n             var = Atom.to_string(var),\n             do: var\n           ) == [\"foo\"]\n  end\n\n  test \"for comprehensions with map key matching\" do\n    maps = [%{x: 1}, %{y: 2}, %{x: 3}]\n    assert for(%{x: v} <- maps, do: v * 2) == [2, 6]\n    x = :x\n    assert for(%{^x => v} <- maps, do: v * 2) == [2, 6]\n  end\n\n  test \"for comprehensions with filters\" do\n    assert for(x <- 1..3, x > 1, x < 3, do: x * 2) == [4]\n  end\n\n  test \"for comprehensions with unique values\" do\n    list = [1, 1, 2, 3]\n    assert for(x <- list, uniq: true, do: x * 2) == [2, 4, 6]\n    assert for(x <- list, uniq: true, into: [], do: x * 2) == [2, 4, 6]\n    assert for(x <- list, uniq: true, into: %{}, do: {x, 1}) == %{1 => 1, 2 => 1, 3 => 1}\n    assert for(x <- list, uniq: true, into: \"\", do: to_bin(x * 2)) == <<2, 4, 6>>\n    assert for(<<x <- \"abcabc\">>, uniq: true, into: \"\", do: to_bin(x)) == \"abc\"\n\n    Process.put(:into_cont, [])\n    Process.put(:into_done, false)\n    Process.put(:into_halt, false)\n\n    for x <- list, uniq: true, into: %Pdict{} do\n      x * 2\n    end\n\n    assert Process.get(:into_cont) == [6, 4, 2]\n    assert Process.get(:into_done)\n    refute Process.get(:into_halt)\n\n    assert_raise RuntimeError, \"oops\", fn ->\n      for _ <- [1, 2, 3], uniq: true, into: %Pdict{}, do: raise(\"oops\")\n    end\n\n    assert Process.get(:into_halt)\n  end\n\n  test \"nested for comprehensions with unique values\" do\n    assert for(x <- [1, 1, 2], uniq: true, do: for(y <- [3, 3], uniq: true, do: x * y)) == [\n             [3],\n             [6]\n           ]\n\n    assert for(<<x <- \"abcabc\">>,\n             uniq: true,\n             into: \"\",\n             do: for(<<y <- \"zz\">>, uniq: true, into: \"\", do: to_bin(x) <> to_bin(y))\n           ) == \"azbzcz\"\n  end\n\n  test \"for comprehensions with nilly filters\" do\n    assert for(x <- 1..3, nilly(), do: x * 2) == []\n  end\n\n  test \"for comprehensions with unique option where value is not used\" do\n    assert capture_io(:stderr, fn ->\n             assert capture_io(fn ->\n                      Code.eval_quoted(\n                        quote do\n                          for x <- [1, 2, 1, 2], uniq: true, do: IO.puts(x)\n                          nil\n                        end\n                      )\n                    end) ==\n                      \"1\\n2\\n1\\n2\\n\"\n           end) =~\n             \"the :uniq option has no effect since the result of the for comprehension is not used\"\n  end\n\n  test \"for comprehensions with unique option where value is assigned to _\" do\n    assert capture_io(:stderr, fn ->\n             assert capture_io(fn ->\n                      Code.eval_quoted(\n                        quote do\n                          _ = for x <- [1, 2, 1, 2], uniq: true, do: IO.puts(x)\n                          nil\n                        end\n                      )\n                    end) ==\n                      \"1\\n2\\n1\\n2\\n\"\n           end) =~\n             \"the :uniq option has no effect since the result of the for comprehension is not used\"\n  end\n\n  test \"for comprehensions with errors on filters\" do\n    assert_raise ArgumentError, fn ->\n      for x <- 1..3, hd(x), do: :ok\n    end\n  end\n\n  test \"for comprehensions with variables in filters\" do\n    assert for(x <- 1..3, y = x + 1, y > 2, z = y, do: x * z) == [6, 12]\n  end\n\n  test \"for comprehensions with two enum generators\" do\n    assert for(\n             x <- [1, 2, 3],\n             y <- [4, 5, 6],\n             do: x * y\n           ) == [4, 5, 6, 8, 10, 12, 12, 15, 18]\n  end\n\n  test \"for comprehensions with two enum generators and filters\" do\n    assert for(\n             x <- [1, 2, 3],\n             y <- [4, 5, 6],\n             y / 2 == x,\n             do: x * y\n           ) == [8, 18]\n  end\n\n  test \"for comprehensions generators precedence\" do\n    assert for({_, _} = x <- [foo: :bar], do: x) == [foo: :bar]\n  end\n\n  test \"for comprehensions with shadowing\" do\n    assert for(\n             a <-\n               (\n                 b = 1\n                 _ = b\n                 [1]\n               ),\n             b <- [2],\n             do: a + b\n           ) == [3]\n  end\n\n  test \"for comprehensions with binary, enum generators and filters\" do\n    assert for(x <- [1, 2, 3], <<(y <- <<4, 5, 6>>)>>, y / 2 == x, do: x * y) == [8, 18]\n  end\n\n  test \"for comprehensions into list\" do\n    enum = 1..3\n    assert for(x <- enum, into: [], do: x * 2) == [2, 4, 6]\n  end\n\n  test \"for comprehensions into binary\" do\n    enum = 0..3\n\n    assert (for x <- enum, into: \"\" do\n              to_bin(x * 2)\n            end) == <<0, 2, 4, 6>>\n\n    assert (for x <- enum, into: \"\" do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n  end\n\n  test \"for comprehensions into dynamic binary\" do\n    enum = 0..3\n    into = \"\"\n\n    assert (for x <- enum, into: into do\n              to_bin(x * 2)\n            end) == <<0, 2, 4, 6>>\n\n    assert (for x <- enum, into: into do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n\n    into = <<7::size(1)>>\n\n    assert (for x <- enum, into: into do\n              to_bin(x * 2)\n            end) == <<7::size(1), 0, 2, 4, 6>>\n\n    assert (for x <- enum, into: into do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<7::size(1), 0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n  end\n\n  test \"for comprehensions where value is not used\" do\n    enum = 1..3\n\n    assert capture_io(fn ->\n             for x <- enum, do: IO.puts(x)\n             nil\n           end) == \"1\\n2\\n3\\n\"\n  end\n\n  test \"for comprehensions with into\" do\n    Process.put(:into_cont, [])\n    Process.put(:into_done, false)\n    Process.put(:into_halt, false)\n\n    for x <- 1..3, into: %Pdict{} do\n      x * 2\n    end\n\n    assert Process.get(:into_cont) == [6, 4, 2]\n    assert Process.get(:into_done)\n    refute Process.get(:into_halt)\n  end\n\n  test \"for comprehension with into leading to errors\" do\n    Process.put(:into_cont, [])\n    Process.put(:into_done, false)\n    Process.put(:into_halt, false)\n\n    catch_error(\n      for x <- 1..3, into: %Pdict{} do\n        if x > 2, do: raise(\"oops\"), else: x\n      end\n    )\n\n    assert Process.get(:into_cont) == [2, 1]\n    refute Process.get(:into_done)\n    assert Process.get(:into_halt)\n  end\n\n  test \"for comprehension with into, generators and filters\" do\n    Process.put(:into_cont, [])\n\n    for x <- 1..3, Integer.is_odd(x), <<y <- \"hello\">>, into: %Pdict{} do\n      x + y\n    end\n\n    assert IO.iodata_to_binary(Process.get(:into_cont)) == \"roohkpmmfi\"\n  end\n\n  test \"for comprehensions of map into map\" do\n    enum = %{a: 2, b: 3}\n    assert for({k, v} <- enum, into: %{}, do: {k, v * v}) == %{a: 4, b: 9}\n  end\n\n  test \"for comprehensions with reduce, generators and filters\" do\n    acc =\n      for x <- 1..3, Integer.is_odd(x), <<y <- \"hello\">>, reduce: %{} do\n        acc -> Map.update(acc, x, [y], &[y | &1])\n      end\n\n    assert acc == %{1 => ~c\"olleh\", 3 => ~c\"olleh\"}\n  end\n\n  test \"for comprehensions with matched reduce\" do\n    acc =\n      for entry <- [1, 2, 3], reduce: {:ok, nil} do\n        {:ok, _} ->\n          {:ok, entry}\n\n        {:error, _} = error ->\n          error\n      end\n\n    assert acc == {:ok, 3}\n  end\n\n  ## List generators (inlined by the compiler)\n\n  test \"list for comprehensions\" do\n    list = [1, 2, 3]\n    assert for(x <- list, do: x * 2) == [2, 4, 6]\n  end\n\n  test \"list for comprehensions with matching\" do\n    assert for({_, x} <- [1, 2, a: 3, b: 4, c: 5], do: x * 2) == [6, 8, 10]\n  end\n\n  test \"list for comprehension matched to '_' on last line of block\" do\n    assert (if Process.get(:unused, true) do\n              _ = for x <- [1, 2, 3], do: x * 2\n            end) == [2, 4, 6]\n  end\n\n  test \"list for comprehensions with filters\" do\n    assert for(x <- [1, 2, 3], x > 1, x < 3, do: x * 2) == [4]\n  end\n\n  test \"list for comprehensions with nilly filters\" do\n    assert for(x <- [1, 2, 3], nilly(), do: x * 2) == []\n  end\n\n  test \"list for comprehensions with errors on filters\" do\n    assert_raise ArgumentError, fn ->\n      for x <- [1, 2, 3], hd(Process.get(:unused, x)), do: x * 2\n    end\n  end\n\n  test \"list for comprehensions with variables in filters\" do\n    assert for(x <- [1, 2, 3], y = x + 1, y > 2, z = y, do: x * z) == [6, 12]\n  end\n\n  test \"list for comprehensions into list\" do\n    enum = [1, 2, 3]\n    assert for(x <- enum, into: [], do: x * 2) == [2, 4, 6]\n  end\n\n  test \"list for comprehensions into binary\" do\n    enum = [0, 1, 2, 3]\n\n    assert (for x <- enum, into: \"\" do\n              to_bin(x * 2)\n            end) == <<0, 2, 4, 6>>\n\n    assert (for x <- enum, into: \"\" do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n  end\n\n  test \"list for comprehensions into dynamic binary\" do\n    enum = [0, 1, 2, 3]\n    into = \"\"\n\n    assert (for x <- enum, into: into do\n              to_bin(x * 2)\n            end) == <<0, 2, 4, 6>>\n\n    assert (for x <- enum, into: into do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n\n    into = <<7::size(1)>>\n\n    assert (for x <- enum, into: into do\n              to_bin(x * 2)\n            end) == <<7::size(1), 0, 2, 4, 6>>\n\n    assert (for x <- enum, into: into do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<7::size(1), 0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n  end\n\n  test \"list for comprehensions where value is not used\" do\n    enum = [1, 2, 3]\n\n    assert capture_io(fn ->\n             for x <- enum, do: IO.puts(x)\n             nil\n           end) == \"1\\n2\\n3\\n\"\n  end\n\n  test \"list for comprehensions with reduce, generators and filters\" do\n    acc =\n      for x <- [1, 2, 3], Integer.is_odd(x), <<y <- \"hello\">>, reduce: %{} do\n        acc -> Map.update(acc, x, [y], &[y | &1])\n      end\n\n    assert acc == %{1 => ~c\"olleh\", 3 => ~c\"olleh\"}\n  end\n\n  ## Binary generators (inlined by the compiler)\n\n  test \"binary for comprehensions\" do\n    bin = <<1, 2, 3>>\n    assert for(<<x <- bin>>, do: x * 2) == [2, 4, 6]\n  end\n\n  test \"binary for comprehensions with inner binary\" do\n    bin = <<1, 2, 3>>\n    assert for(<<(<<x>> <- bin)>>, do: x * 2) == [2, 4, 6]\n  end\n\n  test \"binary for comprehensions with two generators\" do\n    assert for(<<(x <- <<1, 2, 3>>)>>, <<(y <- <<4, 5, 6>>)>>, y / 2 == x, do: x * y) == [8, 18]\n  end\n\n  test \"binary for comprehensions into list\" do\n    bin = <<1, 2, 3>>\n    assert for(<<x <- bin>>, into: [], do: x * 2) == [2, 4, 6]\n  end\n\n  test \"binary for comprehensions into binary\" do\n    bin = <<0, 1, 2, 3>>\n\n    assert (for <<x <- bin>>, into: \"\" do\n              to_bin(x * 2)\n            end) == <<0, 2, 4, 6>>\n\n    assert (for <<x <- bin>>, into: \"\" do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n  end\n\n  test \"binary for comprehensions into dynamic binary\" do\n    bin = <<0, 1, 2, 3>>\n    into = \"\"\n\n    assert (for <<x <- bin>>, into: into do\n              to_bin(x * 2)\n            end) == <<0, 2, 4, 6>>\n\n    assert (for <<x <- bin>>, into: into do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n\n    into = <<7::size(1)>>\n\n    assert (for <<x <- bin>>, into: into do\n              to_bin(x * 2)\n            end) == <<7::size(1), 0, 2, 4, 6>>\n\n    assert (for <<x <- bin>>, into: into do\n              if Integer.is_even(x), do: <<x::size(2)>>, else: <<x::size(1)>>\n            end) == <<7::size(1), 0::size(2), 1::size(1), 2::size(2), 3::size(1)>>\n  end\n\n  test \"binary for comprehensions with literal matches\" do\n    # Integers\n    bin = <<1, 2, 1, 3, 1, 4>>\n    assert for(<<1, x <- bin>>, into: \"\", do: to_bin(x)) == <<2, 3, 4>>\n    assert for(<<1, x <- bin>>, into: %{}, do: {x, x}) == %{2 => 2, 3 => 3, 4 => 4}\n\n    bin = <<1, 2, 3, 1, 4>>\n    assert for(<<1, x <- bin>>, into: \"\", do: to_bin(x)) == <<2>>\n    assert for(<<1, x <- bin>>, into: %{}, do: {x, x}) == %{2 => 2}\n\n    # Floats\n    bin = <<1.0, 2, 1.0, 3, 1.0, 4>>\n    assert for(<<1.0, x <- bin>>, into: \"\", do: to_bin(x)) == <<2, 3, 4>>\n    assert for(<<1.0, x <- bin>>, into: %{}, do: {x, x}) == %{2 => 2, 3 => 3, 4 => 4}\n\n    bin = <<1.0, 2, 3, 1.0, 4>>\n    assert for(<<1.0, x <- bin>>, into: \"\", do: to_bin(x)) == <<2>>\n    assert for(<<1.0, x <- bin>>, into: %{}, do: {x, x}) == %{2 => 2}\n\n    # Binaries\n    bin = <<\"foo\", 2, \"foo\", 3, \"foo\", 4>>\n    assert for(<<\"foo\", x <- bin>>, into: \"\", do: to_bin(x)) == <<2, 3, 4>>\n    assert for(<<\"foo\", x <- bin>>, into: %{}, do: {x, x}) == %{2 => 2, 3 => 3, 4 => 4}\n\n    bin = <<\"foo\", 2, 3, \"foo\", 4>>\n    assert for(<<\"foo\", x <- bin>>, into: \"\", do: to_bin(x)) == <<2>>\n    assert for(<<\"foo\", x <- bin>>, into: %{}, do: {x, x}) == %{2 => 2}\n\n    bin = <<\"foo\", 2, 3, 4, \"foo\", 5>>\n    assert for(<<\"foo\", x <- bin>>, into: \"\", do: to_bin(x)) == <<2>>\n    assert for(<<\"foo\", x <- bin>>, into: %{}, do: {x, x}) == %{2 => 2}\n  end\n\n  test \"binary for comprehensions with variable size\" do\n    s = 16\n    bin = <<1, 2, 3, 4, 5, 6>>\n    assert for(<<x::size(^s) <- bin>>, into: \"\", do: to_bin(div(x, 2))) == <<129, 130, 131>>\n\n    s = 8\n    bin = <<1, 2, 3, 4, 5, 6>>\n    assert for(<<s, x::size(^s) <- bin>>, into: \"\", do: <<x * s>>) == <<2, 12, 30>>\n\n    # Aligned\n    bin = <<8, 1, 16, 2, 3>>\n    assert for(<<s, x::size(s) <- bin>>, into: \"\", do: <<x::size(s)>>) == <<1, 2, 3>>\n    assert for(<<s, x::size(s) <- bin>>, into: %{}, do: {s, x}) == %{8 => 1, 16 => 515}\n\n    # Unaligned\n    bin = <<8, 1, 32, 2, 3>>\n    assert for(<<s, x::size(s) <- bin>>, into: \"\", do: <<x::size(s)>>) == <<1>>\n    assert for(<<s, x::size(s) <- bin>>, into: %{}, do: {s, x}) == %{8 => 1}\n  end\n\n  test \"binary for comprehensions where value is not used\" do\n    bin = <<1, 2, 3>>\n\n    assert capture_io(fn ->\n             for <<x <- bin>>, do: IO.puts(x)\n             nil\n           end) == \"1\\n2\\n3\\n\"\n  end\n\n  test \"binary for comprehensions with reduce, generators and filters\" do\n    bin = <<1, 2, 3>>\n\n    acc =\n      for <<x <- bin>>, Integer.is_odd(x), <<y <- \"hello\">>, reduce: %{} do\n        acc -> Map.update(acc, x, [y], &[y | &1])\n      end\n\n    assert acc == %{1 => ~c\"olleh\", 3 => ~c\"olleh\"}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/defaults_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.DefaultsTest do\n  use ExUnit.Case, async: true\n\n  import ExUnit.CaptureIO\n\n  def fun_with_fn_defaults(\n        x,\n        fun1 \\\\ & &1,\n        fun2 \\\\ & &1,\n        y\n      ) do\n    {fun1.(x), fun2.(y)}\n  end\n\n  def fun_with_block_defaults(\n        x,\n        y \\\\ (\n          default = \"y\"\n          default\n        ),\n        z \\\\ (\n          default = \"z\"\n          default\n        )\n      ) do\n    {x, y, z}\n  end\n\n  test \"with anonymous function defaults\" do\n    assert {1, 2} = fun_with_fn_defaults(1, 2)\n    assert {100, 2} = fun_with_fn_defaults(1, &(&1 * 100), 2)\n    assert {100, 12} = fun_with_fn_defaults(1, &(&1 * 100), &(&1 + 10), 2)\n  end\n\n  test \"with block defaults\" do\n    assert {1, \"y\", \"z\"} = fun_with_block_defaults(1)\n    assert {1, 2, \"z\"} = fun_with_block_defaults(1, 2)\n    assert {1, 2, 3} = fun_with_block_defaults(1, 2, 3)\n  end\n\n  test \"errors on accessing variable from default block\" do\n    assert_compile_error(~r/undefined variable \\\"default\\\"/, fn ->\n      defmodule VarDefaultScope do\n        def test(_ \\\\ default = 1),\n          do: default\n      end\n    end)\n  end\n\n  test \"errors on multiple defaults\" do\n    message = ~r\"def hello/1 defines defaults multiple times\"\n\n    assert_compile_error(message, fn ->\n      defmodule Kernel.ErrorsTest.ClauseWithDefaults do\n        def hello(_arg \\\\ 0)\n        def hello(_arg \\\\ 1)\n      end\n    end)\n\n    assert_compile_error(message, fn ->\n      defmodule Kernel.ErrorsTest.ClauseWithDefaults do\n        def hello(_arg \\\\ 0), do: nil\n        def hello(_arg \\\\ 1), do: nil\n      end\n    end)\n\n    assert_compile_error(message, fn ->\n      defmodule Kernel.ErrorsTest.ClauseWithDefaults do\n        def hello(_arg \\\\ 0)\n        def hello(_arg \\\\ 1), do: nil\n      end\n    end)\n\n    assert_compile_error(message, fn ->\n      defmodule Kernel.ErrorsTest.ClauseWithDefaults do\n        def hello(_arg \\\\ 0), do: nil\n        def hello(_arg \\\\ 1)\n      end\n    end)\n\n    assert_compile_error(\"undefined variable \\\"foo\\\"\", fn ->\n      defmodule Kernel.ErrorsTest.ClauseWithDefaults5 do\n        def hello(foo, bar \\\\ foo)\n        def hello(foo, bar), do: foo + bar\n      end\n    end)\n  end\n\n  test \"errors on conflicting defaults\" do\n    assert_compile_error(~r\"def hello/3 defaults conflicts with hello/2\", fn ->\n      defmodule Kernel.ErrorsTest.DifferentDefsWithDefaults1 do\n        def hello(a, b \\\\ nil), do: a + b\n        def hello(a, b \\\\ nil, c \\\\ nil), do: a + b + c\n      end\n    end)\n\n    assert_compile_error(~r\"def hello/2 conflicts with defaults from hello/3\", fn ->\n      defmodule Kernel.ErrorsTest.DifferentDefsWithDefaults2 do\n        def hello(a, b \\\\ nil, c \\\\ nil), do: a + b + c\n        def hello(a, b \\\\ nil), do: a + b\n      end\n    end)\n  end\n\n  defp assert_compile_error(message, fun) do\n    assert capture_io(:stderr, fn ->\n             assert_raise CompileError, fun\n           end) =~ message\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/deprecated_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.DeprecatedTest do\n  use ExUnit.Case\n\n  import PathHelpers\n\n  test \"raises on invalid @deprecated\" do\n    assert_raise ArgumentError, ~r\"should be a string with the reason\", fn ->\n      defmodule InvalidDeprecated do\n        @deprecated 1.2\n        def foo, do: :bar\n      end\n    end\n  end\n\n  test \"takes into account deprecated from defaults\" do\n    defmodule DefaultDeprecated do\n      @deprecated \"reason\"\n      def foo(x \\\\ true), do: x\n    end\n\n    assert DefaultDeprecated.__info__(:deprecated) == [\n             {{:foo, 0}, \"reason\"},\n             {{:foo, 1}, \"reason\"}\n           ]\n  end\n\n  test \"add deprecated to __info__\" do\n    write_beam(\n      defmodule SampleDeprecated do\n        @deprecated \"Use SampleDeprecated.bar/0 instead\"\n        def foo, do: true\n\n        def bar, do: false\n      end\n    )\n\n    deprecated = [\n      {{:foo, 0}, \"Use SampleDeprecated.bar/0 instead\"}\n    ]\n\n    assert SampleDeprecated.__info__(:deprecated) == deprecated\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/diagnostics_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.DiagnosticsTest do\n  use ExUnit.Case, async: false\n\n  import ExUnit.CaptureIO\n\n  setup_all do\n    previous = Application.get_env(:elixir, :ansi_enabled, false)\n    Application.put_env(:elixir, :ansi_enabled, false)\n    on_exit(fn -> Application.put_env(:elixir, :ansi_enabled, previous) end)\n  end\n\n  describe \"mismatched delimiter\" do\n    test \"same line - handles unicode input\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [1, 2, 3, 4, 5, 6) <- 😎\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:1:18:\n                 error: unexpected token: )\n                 │\n               1 │ [1, 2, 3, 4, 5, 6) <- 😎\n                 │ │                └ mismatched closing delimiter (expected \"]\")\n                 │ └ unclosed delimiter\n                 │\n                 └─ nofile:1:18\\\n             \"\"\"\n    end\n\n    test \"same line\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [1, 2, 3, 4, 5, 6)\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:1:18:\n                 error: unexpected token: )\n                 │\n               1 │ [1, 2, 3, 4, 5, 6)\n                 │ │                └ mismatched closing delimiter (expected \"]\")\n                 │ └ unclosed delimiter\n                 │\n                 └─ nofile:1:18\\\n             \"\"\"\n    end\n\n    test \"same line with offset\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [1, 2, 3, 4, 5, 6)\n          \"\"\",\n          MismatchedDelimiterError,\n          line: 3\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:3:18:\n                 error: unexpected token: )\n                 │\n               3 │ [1, 2, 3, 4, 5, 6)\n                 │ │                └ mismatched closing delimiter (expected \"]\")\n                 │ └ unclosed delimiter\n                 │\n                 └─ nofile:3:18\\\n             \"\"\"\n    end\n\n    test \"two-line span\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [a, b, c\n           d, f, g}\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:2:9:\n                 error: unexpected token: }\n                 │\n               1 │ [a, b, c\n                 │ └ unclosed delimiter\n               2 │  d, f, g}\n                 │         └ mismatched closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:2:9\\\n             \"\"\"\n    end\n\n    test \"two-line span with offset\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [a, b, c\n           d, f, g}\n          \"\"\",\n          MismatchedDelimiterError,\n          line: 3\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:4:9:\n                 error: unexpected token: }\n                 │\n               3 │ [a, b, c\n                 │ └ unclosed delimiter\n               4 │  d, f, g}\n                 │         └ mismatched closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:4:9\\\n             \"\"\"\n    end\n\n    test \"many-line span\" do\n      output =\n        capture_raise(\n          \"\"\"\n              [ a,\n            b,\n            c,\n            d\n            e )\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:5:5:\n                 error: unexpected token: )\n                 │\n               1 │     [ a,\n                 │     └ unclosed delimiter\n               2 │   b,\n               3 │   c,\n               4 │   d\n               5 │   e )\n                 │     └ mismatched closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:5:5\\\n             \"\"\"\n    end\n\n    test \"many-line span with offset\" do\n      output =\n        capture_raise(\n          \"\"\"\n          fn always_forget_end ->\n            IO.inspect(2 + 2) + 2\n          )\n          \"\"\",\n          MismatchedDelimiterError,\n          line: 3\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:5:1:\n                 error: unexpected token: )\n                 │\n               3 │ fn always_forget_end ->\n                 │ └ unclosed delimiter\n               4 │   IO.inspect(2 + 2) + 2\n               5 │ )\n                 │ └ mismatched closing delimiter (expected \"end\")\n                 │\n                 └─ nofile:5:1\\\n             \"\"\"\n    end\n\n    test \"line range - handles unicode input\" do\n      output =\n        capture_raise(\n          \"\"\"\n          defmodule A do\n            IO.inspect(2 + 2)\n          ) <- 😎\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:3:1:\n                 error: unexpected token: )\n                 │\n               1 │ defmodule A do\n                 │             └ unclosed delimiter\n               2 │   IO.inspect(2 + 2)\n               3 │ ) <- 😎\n                 │ └ mismatched closing delimiter (expected \"end\")\n                 │\n                 └─ nofile:3:1\\\n             \"\"\"\n    end\n\n    test \"trim in between lines if too many\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [ :a,\n            :b,\n            :c,\n            :d,\n            :e,\n            :f,\n            :g,\n            :h\n          )\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:9:1:\n                 error: unexpected token: )\n                 │\n               1 │ [ :a,\n                 │ └ unclosed delimiter\n              ...\n               9 │ )\n                 │ └ mismatched closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:9:1\\\n             \"\"\"\n    end\n\n    test \"trimmed line range - handles unicode input\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [ :a,\n            :b,\n            :c,\n            :d,\n            :e,\n            :f,\n            :g,\n            :h\n          ) <- 😎\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:9:1:\n                 error: unexpected token: )\n                 │\n               1 │ [ :a,\n                 │ └ unclosed delimiter\n              ...\n               9 │ ) <- 😎\n                 │ └ mismatched closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:9:1\\\n             \"\"\"\n    end\n\n    test \"pads according to line number digits\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [ a,\n          #{String.duplicate(\"\\n\", 10)}\n            b )\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:13:5:\n                 error: unexpected token: )\n                 │\n               1 │ [ a,\n                 │ └ unclosed delimiter\n              ...\n              13 │   b )\n                 │     └ mismatched closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:13:5\\\n             \"\"\"\n\n      output =\n        capture_raise(\n          \"\"\"\n          [ a,\n          #{String.duplicate(\"\\n\", 400)}\n            b )\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:403:5:\n                  error: unexpected token: )\n                  │\n                1 │ [ a,\n                  │ └ unclosed delimiter\n              ...\n              403 │   b )\n                  │     └ mismatched closing delimiter (expected \"]\")\n                  │\n                  └─ nofile:403:5\\\n             \"\"\"\n\n      output =\n        capture_raise(\n          \"\"\"\n          #{String.duplicate(\"\\n\", 97)}\n          [ a,\n          #{String.duplicate(\"\\n\", 6)}\n            b )\n          \"\"\",\n          MismatchedDelimiterError\n        )\n\n      assert output == \"\"\"\n             ** (MismatchedDelimiterError) mismatched delimiter found on nofile:107:5:\n                  error: unexpected token: )\n                  │\n               99 │ [ a,\n                  │ └ unclosed delimiter\n              ...\n              107 │   b )\n                  │     └ mismatched closing delimiter (expected \"]\")\n                  │\n                  └─ nofile:107:5\\\n             \"\"\"\n    end\n  end\n\n  describe \"token missing error\" do\n    test \"missing parens terminator\" do\n      output =\n        capture_raise(\n          \"\"\"\n          my_numbers = [1, 2, 3, 4, 5, 6\n          IO.inspect(my_numbers)\n          \"\"\",\n          TokenMissingError\n        )\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:2:23:\n                 error: missing terminator: ]\n                 │\n               1 │ my_numbers = [1, 2, 3, 4, 5, 6\n                 │              └ unclosed delimiter\n               2 │ IO.inspect(my_numbers)\n                 │                       └ missing closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:2:23\\\n             \"\"\"\n    end\n\n    test \"missing heredoc terminator\" do\n      output =\n        capture_raise(\n          \"\"\"\n          a = \\\"\"\"\n          test string\n\n          IO.inspect(10 + 20)\n          \"\"\",\n          TokenMissingError\n        )\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:4:20:\n                 error: missing terminator: \\\"\"\" (for heredoc starting at line 1)\n                 │\n               1 │ a = \\\"\"\"\n                 │     └ unclosed delimiter\n               2 │ test string\n               3 │\\s\n               4 │ IO.inspect(10 + 20)\n                 │                    └ missing closing delimiter (expected \\\"\"\")\n                 │\n                 └─ nofile:4:20\\\n             \"\"\"\n    end\n\n    test \"missing sigil terminator\" do\n      output =\n        capture_raise(\"~s<foobar\", TokenMissingError)\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:1:10:\n                 error: missing terminator: > (for sigil ~s< starting at line 1)\n                 │\n               1 │ ~s<foobar\n                 │   │      └ missing closing delimiter (expected \">\")\n                 │   └ unclosed delimiter\n                 │\n                 └─ nofile:1:10\\\n             \"\"\"\n\n      output =\n        capture_raise(\"~s|foobar\", TokenMissingError)\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:1:10:\n                 error: missing terminator: | (for sigil ~s| starting at line 1)\n                 │\n               1 │ ~s|foobar\n                 │   │      └ missing closing delimiter (expected \"|\")\n                 │   └ unclosed delimiter\n                 │\n                 └─ nofile:1:10\\\n             \"\"\"\n    end\n\n    test \"missing string terminator\" do\n      output =\n        capture_raise(\"\\\"foobar\", TokenMissingError)\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:1:8:\n                 error: missing terminator: \" (for string starting at line 1)\n                 │\n               1 │ \"foobar\n                 │ │      └ missing closing delimiter (expected \")\n                 │ └ unclosed delimiter\n                 │\n                 └─ nofile:1:8\\\n             \"\"\"\n    end\n\n    test \"missing atom terminator\" do\n      output =\n        capture_raise(\":\\\"foobar\", TokenMissingError)\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:1:9:\n                 error: missing terminator: \" (for atom starting at line 1)\n                 │\n               1 │ :\"foobar\n                 │  │      └ missing closing delimiter (expected \")\n                 │  └ unclosed delimiter\n                 │\n                 └─ nofile:1:9\\\n             \"\"\"\n    end\n\n    test \"missing function terminator\" do\n      output =\n        capture_raise(\"K.\\\"foobar\", TokenMissingError)\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:1:10:\n                 error: missing terminator: \" (for function name starting at line 1)\n                 │\n               1 │ K.\"foobar\n                 │   │      └ missing closing delimiter (expected \")\n                 │   └ unclosed delimiter\n                 │\n                 └─ nofile:1:10\\\n             \"\"\"\n    end\n\n    test \"shows in between lines if EOL is not far below\" do\n      output =\n        capture_raise(\n          \"\"\"\n          my_numbers = [1, 2, 3, 4, 5, 6\n          my_numbers\n          |> Enum.map(&(&1 + 1))\n          |> Enum.map(&(&1 * &1))\n          |> IO.inspect()\n          \"\"\",\n          TokenMissingError\n        )\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:5:16:\n                 error: missing terminator: ]\n                 │\n               1 │ my_numbers = [1, 2, 3, 4, 5, 6\n                 │              └ unclosed delimiter\n               2 │ my_numbers\n               3 │ |> Enum.map(&(&1 + 1))\n               4 │ |> Enum.map(&(&1 * &1))\n               5 │ |> IO.inspect()\n                 │                └ missing closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:5:16\\\n             \"\"\"\n    end\n\n    test \"trims lines\" do\n      output =\n        capture_raise(\n          \"\"\"\n          my_numbers = (1, 2, 3, 4, 5, 6\n\n\n\n\n\n\n          IO.inspect(my_numbers)\n          \"\"\",\n          TokenMissingError\n        )\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:8:23:\n                 error: missing terminator: )\n                 │\n               1 │ my_numbers = (1, 2, 3, 4, 5, 6\n                 │              └ unclosed delimiter\n              ...\n               8 │ IO.inspect(my_numbers)\n                 │                       └ missing closing delimiter (expected \")\")\n                 │\n                 └─ nofile:8:23\\\n             \"\"\"\n    end\n\n    test \"shows the last non-empty line of a file\" do\n      output =\n        capture_raise(\n          \"\"\"\n          my_numbers = {1, 2, 3, 4, 5, 6\n          IO.inspect(my_numbers)\n\n\n\n\n          \"\"\",\n          TokenMissingError\n        )\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:2:23:\n                 error: missing terminator: }\n                 │\n               1 │ my_numbers = {1, 2, 3, 4, 5, 6\n                 │              └ unclosed delimiter\n               2 │ IO.inspect(my_numbers)\n                 │                       └ missing closing delimiter (expected \"}\")\n                 │\n                 └─ nofile:2:23\\\n             \"\"\"\n    end\n\n    test \"supports unicode\" do\n      output =\n        capture_raise(\n          \"\"\"\n          my_emojis = [1, 2, 3, 4 # ⚗️\n          IO.inspect(my_numbers)\n          \"\"\",\n          TokenMissingError\n        )\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:2:23:\n                 error: missing terminator: ]\n                 │\n               1 │ my_emojis = [1, 2, 3, 4 # ⚗️\n                 │             └ unclosed delimiter\n               2 │ IO.inspect(my_numbers)\n                 │                       └ missing closing delimiter (expected \"]\")\n                 │\n                 └─ nofile:2:23\\\n             \"\"\"\n    end\n  end\n\n  describe \"compile-time exceptions\" do\n    test \"SyntaxError (snippet)\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [1, 2, 3, 4, 5, *]\n          \"\"\",\n          SyntaxError\n        )\n\n      assert output == \"\"\"\n             ** (SyntaxError) invalid syntax found on nofile:1:17:\n                 error: syntax error before: '*'\n                 │\n               1 │ [1, 2, 3, 4, 5, *]\n                 │                 ^\n                 │\n                 └─ nofile:1:17\\\n             \"\"\"\n    end\n\n    test \"SyntaxError (snippet) with offset\" do\n      output =\n        capture_raise(\n          \"\"\"\n          [1, 2, 3, 4, 5, *]\n          \"\"\",\n          SyntaxError,\n          line: 3\n        )\n\n      assert output == \"\"\"\n             ** (SyntaxError) invalid syntax found on nofile:3:17:\n                 error: syntax error before: '*'\n                 │\n               3 │ [1, 2, 3, 4, 5, *]\n                 │                 ^\n                 │\n                 └─ nofile:3:17\\\n             \"\"\"\n    end\n\n    test \"TokenMissingError (snippet)\" do\n      output =\n        capture_raise(\n          \"\"\"\n          1 +\n          \"\"\",\n          TokenMissingError\n        )\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:1:4:\n                 error: syntax error: expression is incomplete\n                 │\n               1 │ 1 +\n                 │    ^\n                 │\n                 └─ nofile:1:4\\\n             \"\"\"\n    end\n\n    test \"TokenMissingError (snippet) with offset and column\" do\n      output =\n        capture_raise(\n          \"\"\"\n          1 +\n          \"\"\",\n          TokenMissingError,\n          line: 3,\n          column: 3\n        )\n\n      assert output == \"\"\"\n             ** (TokenMissingError) token missing on nofile:3:6:\n                 error: syntax error: expression is incomplete\n                 │\n               3 │   1 +\n                 │      ^\n                 │\n                 └─ nofile:3:6\\\n             \"\"\"\n    end\n\n    test \"TokenMissingError (unclosed delimiter)\" do\n      expected = \"\"\"\n      ** (TokenMissingError) token missing on nofile:1:5:\n          error: missing terminator: end\n          │\n        1 │ fn a\n          │ │   └ missing closing delimiter (expected \"end\")\n          │ └ unclosed delimiter\n          │\n          └─ nofile:1:5\\\n      \"\"\"\n\n      output =\n        capture_raise(\n          \"\"\"\n          fn a\n          \"\"\",\n          TokenMissingError\n        )\n\n      assert output == expected\n    end\n\n    test \"keeps trailing whitespace if under threshold\" do\n      expected = \"\"\"\n      ** (SyntaxError) invalid syntax found on nofile:1:23:\n          error: unexpected token: \"😎\" (column 23, code point U+****)\n          │\n        1 │                   a + 😎\n          │                       ^\n          │\n          └─ nofile:1:23\\\n      \"\"\"\n\n      output =\n        capture_raise(\n          \"\"\"\n                            a + 😎\n          \"\"\",\n          SyntaxError\n        )\n\n      assert output == expected\n    end\n\n    test \"limits trailing whitespace if too many\" do\n      expected = \"\"\"\n      ** (SyntaxError) invalid syntax found on nofile:1:43:\n          error: unexpected token: \"😎\" (column 43, code point U+****)\n          │\n        1 │ ...                   a + 😎\n          │                           ^\n          │\n          └─ nofile:1:43\\\n      \"\"\"\n\n      output =\n        capture_raise(\n          \"\"\"\n                                                a + 😎\n          \"\"\",\n          SyntaxError\n        )\n\n      assert output == expected\n    end\n\n    test \"shows stacktrace if present\" do\n      fake_stacktrace = [\n        {:fake, :fun, 3, [file: \"nofile\", line: 10]},\n        {:real, :fun, 2, [file: \"nofile\", line: 10]}\n      ]\n\n      expected = \"\"\"\n      ** (TokenMissingError) token missing on nofile:1:4:\n          error: syntax error: expression is incomplete\n          │\n        1 │ 1 -\n          │    ^\n          │\n          └─ nofile:1:4\n          nofile:10: :fake.fun/3\n          nofile:10: :real.fun/2\n      \"\"\"\n\n      output =\n        capture_raise(\n          \"\"\"\n          1 -\n          \"\"\",\n          TokenMissingError,\n          stacktrace: fake_stacktrace\n        )\n\n      assert output == expected\n    end\n\n    test \"2-digit line errors stay aligned 1-digit line errors\" do\n      fake_stacktrace = [\n        {:fake, :fun, 3, [file: \"nofile\", line: 10]}\n      ]\n\n      expected = \"\"\"\n      ** (TokenMissingError) token missing on nofile:12:4:\n          error: syntax error: expression is incomplete\n          │\n       12 │ 1 -\n          │    ^\n          │\n          └─ nofile:12:4\n          nofile:10: :fake.fun/3\n      \"\"\"\n\n      output =\n        capture_raise(\n          \"\"\"\n          #{String.duplicate(\"\\n\", 10)}\n          1 -\n          \"\"\",\n          TokenMissingError,\n          stacktrace: fake_stacktrace\n        )\n\n      assert output == expected\n    end\n\n    test \"handles unicode\" do\n      source = \"\"\"\n      defmodule Sample do\n        def a do\n          10 + 😎\n        end\n      end\n      \"\"\"\n\n      output = capture_raise(source, SyntaxError)\n\n      assert output =~ \"😎\"\n    after\n      purge(Sample)\n    end\n  end\n\n  describe \"compiler warnings\" do\n    @tag :tmp_dir\n    test \"simple warning (line + column + file)\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"long-warning.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n        defp a, do: Unknown.b()\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: Unknown.b/0 is undefined (module Unknown is not available or is yet to be defined). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n          │\n        3 │   defp a, do: Unknown.b()\n          │                       ~\n          │\n          └─ #{path}:3:23: Sample.a/0\n      \"\"\"\n\n      assert capture_eval(source) =~ expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"simple warning (line + file)\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"long-warning.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n        defp a, do: Unknown.b()\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: Unknown.b/0 is undefined (module Unknown is not available or is yet to be defined). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n          │\n        3 │   defp a, do: Unknown.b()\n          │   ~~~~~~~~~~~~~~~~~~~~~~~\n          │\n          └─ #{path}:3: Sample.a/0\n      \"\"\"\n\n      assert capture_eval(source, columns: false) =~ expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"simple warning with tabs (line + file)\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"long-warning.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n      \\t@file \"#{path}\"\n      \\tdefp a do\n      \\t\\tUnknown.b()\n      \\tend\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: Unknown.b/0 is undefined (module Unknown is not available or is yet to be defined). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n          │\n        4 │ \\t\\tUnknown.b()\n          │                 ~~~~~~~~~~~\n          │\n          └─ #{path}:4: Sample.a/0\n      \"\"\"\n\n      assert capture_eval(source, columns: false) =~ expected\n    after\n      purge(Sample)\n    end\n\n    test \"simple warning (no file)\" do\n      source = \"\"\"\n      defmodule Sample do\n        defp a, do: Unknown.b()\n      end\n      \"\"\"\n\n      expected = \"\"\"\n      warning: Unknown.b/0 is undefined (module Unknown is not available or is yet to be defined). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n      └─ nofile:2:23: Sample.a/0\n      \"\"\"\n\n      assert capture_eval(source) =~ expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"IO.warn file+line\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"io-warn-file-line.ex\")\n\n      source = \"\"\"\n      IO.warn(\"oops\\\\nmulti\\\\nline\", file: __ENV__.file, line: __ENV__.line)\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: oops\n          multi\n          line\n          │\n        1 │ IO.warn(\"oops\\\\nmulti\\\\nline\", file: __ENV__.file, line: __ENV__.line)\n          │ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n          │\n          └─ tmp\\\n      \"\"\"\n\n      assert capture_io(:stderr, fn -> Code.eval_file(path) end) =~ expected\n    end\n\n    @tag :tmp_dir\n    test \"IO.warn file+line+column\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"io-warn-file-line-column.ex\")\n\n      source = \"\"\"\n      IO.warn(\"oops\\\\nmulti\\\\nline\", file: __ENV__.file, line: __ENV__.line, column: 4)\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: oops\n          multi\n          line\n          │\n        1 │ IO.warn(\"oops\\\\nmulti\\\\nline\", file: __ENV__.file, line: __ENV__.line, column: 4)\n          │    ~\n          │\n          └─ tmp\\\n      \"\"\"\n\n      assert capture_io(:stderr, fn -> Code.eval_file(path) end) =~ expected\n    end\n\n    test \"IO.warn with missing data\" do\n      assert capture_eval(\"\"\"\n             IO.warn(\"oops-bad\", file: #{inspect(__ENV__.file)}, line: 3, column: nil)\n             \"\"\") =~ \"warning: oops-bad\"\n\n      assert capture_eval(\"\"\"\n             IO.warn(\"oops-bad\", file: #{inspect(__ENV__.file)}, line: nil)\n             \"\"\") =~ \"oops-bad\"\n\n      assert capture_eval(\"\"\"\n             IO.warn(\"oops-bad\", file: nil)\n             \"\"\") =~ \"oops-bad\"\n    end\n\n    @tag :tmp_dir\n    test \"trims lines if too many whitespaces\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"trim_warning_line.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def a do\n                                                  Unknown.bar(:test)\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: Unknown.bar/1 is undefined (module Unknown is not available or is yet to be defined). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n          │\n        5 │ ...                   Unknown.bar(:test)\n          │                               ~\n          │\n          └─ #{path}:5:53: Sample.a/0\n\n      \"\"\"\n\n      assert capture_eval(source) == expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"handles unicode\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"warning_group_unicode.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def a do\n          Unknown.bar(\"😎\")\n          Unknown.bar(\"😎\")\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      assert capture_eval(source) =~ \"😎\"\n    after\n      purge(Sample)\n    end\n  end\n\n  describe \"warning groups\" do\n    test \"no file\" do\n      source = \"\"\"\n      defmodule Sample do\n        def a do\n          Unknown.bar()\n          Unknown.bar()\n          Unknown.bar()\n          Unknown.bar()\n        end\n      end\n      \"\"\"\n\n      expected = \"\"\"\n      warning: Unknown.bar/0 is undefined (module Unknown is not available or is yet to be defined). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n      └─ nofile:3:13: Sample.a/0\n      └─ nofile:4:13: Sample.a/0\n      └─ nofile:5:13: Sample.a/0\n      └─ nofile:6:13: Sample.a/0\n\n      \"\"\"\n\n      assert capture_eval(source) =~ expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"file + line + column\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"warning_group_nofile.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def a do\n          Unknown.bar()\n          Unknown.bar()\n          Unknown.bar()\n          Unknown.bar()\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: Unknown.bar/0 is undefined (module Unknown is not available or is yet to be defined). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n          │\n        5 │     Unknown.bar()\n          │             ~\n          │\n          └─ #{path}:5:13: Sample.a/0\n          └─ #{path}:6:13: Sample.a/0\n          └─ #{path}:7:13: Sample.a/0\n          └─ #{path}:8:13: Sample.a/0\n\n      \"\"\"\n\n      assert capture_eval(source) == expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"file + line\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"warning_group_nofile.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def a do\n          Unknown.bar()\n          Unknown.bar()\n          Unknown.bar()\n          Unknown.bar()\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: Unknown.bar/0 is undefined (module Unknown is not available or is yet to be defined). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n          │\n        5 │     Unknown.bar()\n          │     ~~~~~~~~~~~~~\n          │\n          └─ #{path}:5: Sample.a/0\n          └─ #{path}:6: Sample.a/0\n          └─ #{path}:7: Sample.a/0\n          └─ #{path}:8: Sample.a/0\n\n      \"\"\"\n\n      assert capture_eval(source, columns: false) == expected\n    after\n      purge(Sample)\n    end\n  end\n\n  describe \"error diagnostics\" do\n    @tag :tmp_dir\n    test \"line only\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"error_line_only.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n        def CamelCase do\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          error: function names should start with lowercase characters or underscore, invalid name CamelCase\n          │\n        3 │   def CamelCase do\n          │   ^^^^^^^^^^^^^^^^\n          │\n          └─ #{path}:3\n\n      \"\"\"\n\n      assert capture_compile(source, columns: false) == expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"shows span for unused variables\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"error_line_column.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def foo(unused_param) do\n          :constant\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: variable \"unused_param\" is unused (if the variable is not meant to be used, prefix it with an underscore)\n          │\n        4 │   def foo(unused_param) do\n          │           ~~~~~~~~~~~~\n          │\n          └─ #{path}:4:11: Sample.foo/1\n\n      \"\"\"\n\n      assert capture_eval(source) == expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"shows span for undefined variables\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"undefined_variable_span.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def foo(a) do\n          a - unknown_var\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          error: undefined variable \"unknown_var\"\n          │\n        5 │     a - unknown_var\n          │         ^^^^^^^^^^^\n          │\n          └─ #{path}:5:9: Sample.foo/1\n\n      \"\"\"\n\n      assert capture_compile(source) == expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"shows span for unknown local function calls\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"unknown_local_function_call.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def foo do\n          _result = unknown_func_call!(:hello!)\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          error: undefined function unknown_func_call!/1 (expected Sample to define such a function or for it to be imported, but none are available)\n          │\n        5 │     _result = unknown_func_call!(:hello!)\n          │               ^^^^^^^^^^^^^^^^^^\n          │\n          └─ #{path}:5:15: Sample.foo/0\n\n      \"\"\"\n\n      assert capture_compile(source) == expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"line + column\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"error_line_column.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def foo do\n          IO.puts(bar)\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          error: undefined variable \"bar\"\n          │\n        5 │     IO.puts(bar)\n          │             ^^^\n          │\n          └─ #{path}:5:13: Sample.foo/0\n\n      \"\"\"\n\n      assert capture_compile(source) == expected\n    after\n      purge(Sample)\n    end\n\n    test \"no file\" do\n      expected = \"\"\"\n      error: undefined function module_info/0 (this function is auto-generated by the compiler and must always be called as a remote, as in __MODULE__.module_info/0)\n      └─ nofile:2:16: Sample.foo/0\n\n      \"\"\"\n\n      output =\n        capture_compile(\"\"\"\n        defmodule Sample do\n          def foo, do: module_info()\n        end\n        \"\"\")\n\n      assert expected == output\n    after\n      purge(Sample)\n    end\n  end\n\n  describe \"warning diagnostics\" do\n    @tag :tmp_dir\n    test \"line only\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"warn_line.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n        def a(unused), do: 1\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: variable \"unused\" is unused (if the variable is not meant to be used, prefix it with an underscore)\n          │\n        3 │   def a(unused), do: 1\n          │   ~~~~~~~~~~~~~~~~~~~~\n          │\n          └─ #{path}:3: Sample.a/1\n\n      \"\"\"\n\n      assert capture_eval(source, columns: false) == expected\n    after\n      purge(Sample)\n    end\n\n    @tag :tmp_dir\n    test \"line + column\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"warn_line_column.ex\")\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n        @foo 1\n\n        def bar do\n          @foo\n          :ok\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      expected = \"\"\"\n          warning: module attribute @foo in code block has no effect as it is never returned (remove the attribute or assign it to _ to avoid warnings)\n          │\n        6 │     @foo\n          │     ~\n          │\n          └─ #{path}:6:5: Sample.bar/0\n\n      \"\"\"\n\n      assert capture_eval(source) == expected\n    after\n      purge(Sample)\n    end\n\n    test \"no file\" do\n      expected = \"\"\"\n      warning: unused alias List\n      └─ nofile:2:3\n\n      \"\"\"\n\n      output =\n        capture_eval(\"\"\"\n        defmodule Sample do\n          alias :lists, as: List\n          import MapSet\n          new()\n        end\n        \"\"\")\n\n      assert output == expected\n    after\n      purge(Sample)\n    end\n  end\n\n  describe \"Code.print_diagnostic\" do\n    @tag :tmp_dir\n    test \"handles diagnostic with span\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"diagnostic_length.ex\")\n\n      diagnostic = %{\n        file: path,\n        severity: :error,\n        message: \"Diagnostic span test\",\n        stacktrace: [],\n        position: {4, 7},\n        span: {4, 10},\n        compiler_name: \"Elixir\"\n      }\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def bar do\n          nil\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      result =\n        ExUnit.CaptureIO.capture_io(:stderr, fn ->\n          Code.print_diagnostic(diagnostic)\n        end)\n\n      assert result == \"\"\"\n                 error: Diagnostic span test\n                 │\n               4 │   def bar do\n                 │       ^^^\n                 │\n                 └─ #{path}:4:7\n\n             \"\"\"\n    end\n\n    @tag :tmp_dir\n    test \"prints single marker for multiline diagnostic\", %{tmp_dir: tmp_dir} do\n      path = make_relative_tmp(tmp_dir, \"diagnostic_length.ex\")\n\n      diagnostic = %{\n        file: path,\n        severity: :error,\n        message: \"Diagnostic span test\",\n        stacktrace: [],\n        position: {4, 7},\n        span: {5, 2},\n        compiler_name: \"Elixir\"\n      }\n\n      source = \"\"\"\n      defmodule Sample do\n        @file \"#{path}\"\n\n        def bar do\n          nil\n        end\n      end\n      \"\"\"\n\n      File.write!(path, source)\n\n      result =\n        ExUnit.CaptureIO.capture_io(:stderr, fn ->\n          Code.print_diagnostic(diagnostic)\n        end)\n\n      assert result == \"\"\"\n                 error: Diagnostic span test\n                 │\n               4 │   def bar do\n                 │       ^\n                 │\n                 └─ #{path}:4:7\n\n             \"\"\"\n    end\n  end\n\n  defp make_relative_tmp(tmp_dir, filename) do\n    # Compiler outputs relative, so we just grab the tmp dir\n    tmp_dir\n    |> Path.join(filename)\n    |> Path.relative_to_cwd()\n  end\n\n  defp capture_eval(source, opts \\\\ [columns: true]) do\n    capture_io(:stderr, fn ->\n      quoted = Code.string_to_quoted!(source, opts)\n      Code.eval_quoted(quoted)\n    end)\n  end\n\n  defp capture_compile(source, opts \\\\ [columns: true]) do\n    capture_io(:stderr, fn ->\n      assert_raise CompileError, fn ->\n        ast = Code.string_to_quoted!(source, opts)\n        Code.eval_quoted(ast)\n      end\n    end)\n  end\n\n  defp capture_raise(source, exception, opts \\\\ []) do\n    {stacktrace, opts} = Keyword.pop(opts, :stacktrace, [])\n\n    e =\n      assert_raise exception, fn ->\n        ast = Code.string_to_quoted!(source, [columns: true] ++ opts)\n        Code.eval_quoted(ast)\n      end\n\n    Exception.format(:error, e, stacktrace)\n  end\n\n  defp purge(module) when is_atom(module) do\n    :code.purge(module)\n    :code.delete(module)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/dialyzer_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.DialyzerTest do\n  use ExUnit.Case, async: true\n\n  @moduletag :dialyzer\n  @moduletag :require_ast\n  import PathHelpers\n\n  setup_all do\n    dir = tmp_path(\"dialyzer\")\n    File.rm_rf!(dir)\n    File.mkdir_p!(dir)\n\n    plt =\n      dir\n      |> Path.join(\"base_plt\")\n      |> String.to_charlist()\n\n    # Some OSs (like Windows) do not provide the HOME environment variable.\n    if !System.get_env(\"HOME\") do\n      System.put_env(\"HOME\", System.user_home())\n    end\n\n    # Add a few key Elixir modules for types and macro functions\n    mods = [\n      :elixir,\n      :elixir_env,\n      :elixir_erl_pass,\n      :inet,\n      :maps,\n      :sets,\n      ArgumentError,\n      Atom,\n      Code,\n      EEx,\n      Enum,\n      Exception,\n      ExUnit.AssertionError,\n      ExUnit.Assertions,\n      IO,\n      Kernel,\n      Kernel.Utils,\n      List,\n      Macro,\n      Macro.Env,\n      MapSet,\n      Module,\n      Protocol,\n      String,\n      String.Chars,\n      Task,\n      Task.Supervisor,\n      URI\n    ]\n\n    files = Enum.map(mods, &:code.which/1)\n    dialyzer_run(analysis_type: :plt_build, output_plt: plt, apps: [:erts], files: files)\n\n    # Compile Dialyzer fixtures\n    source_files = Path.wildcard(Path.join(fixture_path(\"dialyzer\"), \"*\"))\n\n    {:ok, _, _} =\n      Kernel.ParallelCompiler.compile_to_path(source_files, dir, return_diagnostics: true)\n\n    {:ok, [base_dir: dir, base_plt: plt]}\n  end\n\n  setup context do\n    dir = String.to_charlist(context.tmp_dir)\n\n    plt =\n      dir\n      |> Path.join(\"plt\")\n      |> String.to_charlist()\n\n    File.cp!(context.base_plt, plt)\n    warnings = Map.get(context, :warnings, [])\n\n    dialyzer = [\n      analysis_type: :succ_typings,\n      check_plt: false,\n      files_rec: [dir],\n      plts: [plt],\n      warnings: warnings\n    ]\n\n    {:ok, [outdir: dir, dialyzer: dialyzer]}\n  end\n\n  @moduletag :tmp_dir\n\n  @tag warnings: [:specdiffs]\n  test \"no warnings on specdiffs\", context do\n    copy_beam!(context, Dialyzer.RemoteCall)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on valid remote calls\", context do\n    copy_beam!(context, Dialyzer.RemoteCall)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on rewrites\", context do\n    copy_beam!(context, Dialyzer.Rewrite)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on raise\", context do\n    copy_beam!(context, Dialyzer.Raise)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on in range\", context do\n    copy_beam!(context, Dialyzer.InRange)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on macrocallback\", context do\n    copy_beam!(context, Dialyzer.Macrocallback)\n    copy_beam!(context, Dialyzer.Macrocallback.Impl)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on callback\", context do\n    copy_beam!(context, Dialyzer.Callback)\n    copy_beam!(context, Dialyzer.Callback.ImplAtom)\n    copy_beam!(context, Dialyzer.Callback.ImplList)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on and/2 and or/2\", context do\n    copy_beam!(context, Dialyzer.BooleanCheck)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on cond\", context do\n    copy_beam!(context, Dialyzer.Cond)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on for comprehensions with bitstrings\", context do\n    copy_beam!(context, Dialyzer.ForBitstring)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on for falsy check that always boolean\", context do\n    copy_beam!(context, Dialyzer.ForBooleanCheck)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on with/else\", context do\n    copy_beam!(context, Dialyzer.With)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on with when else has a no_return type\", context do\n    copy_beam!(context, Dialyzer.WithNoReturn)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on with when multiple else clauses and one is a no_return\", context do\n    copy_beam!(context, Dialyzer.WithThrowingElse)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on defmacrop\", context do\n    copy_beam!(context, Dialyzer.Defmacrop)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warnings on try\", context do\n    copy_beam!(context, Dialyzer.Try)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warning on is_struct/2\", context do\n    copy_beam!(context, Dialyzer.IsStruct)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warning on ExUnit assertions\", context do\n    copy_beam!(context, Dialyzer.Assertions)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warning due to opaqueness edge cases\", context do\n    copy_beam!(context, Dialyzer.Opaqueness)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  test \"no warning in various non-regression cases\", context do\n    copy_beam!(context, Dialyzer.Regressions)\n    assert_dialyze_no_warnings!(context)\n  end\n\n  defp copy_beam!(context, module) do\n    name = \"#{module}.beam\"\n    File.cp!(Path.join(context.base_dir, name), Path.join(context.outdir, name))\n  end\n\n  defp assert_dialyze_no_warnings!(context) do\n    case dialyzer_run(context.dialyzer) do\n      [] ->\n        :ok\n\n      warnings ->\n        formatted = for warn <- warnings, do: [:dialyzer.format_warning(warn), ?\\n]\n        formatted |> IO.chardata_to_string() |> flunk()\n    end\n  end\n\n  defp dialyzer_run(opts) do\n    try do\n      :dialyzer.run(opts)\n    catch\n      :throw, {:dialyzer_error, chardata} ->\n        raise \"dialyzer error: \" <> IO.chardata_to_string(chardata)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/docs_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.DocsTest do\n  use ExUnit.Case\n\n  import PathHelpers\n\n  defmacro wrong_doc_baz do\n    quote do\n      @doc \"Wrong doc\"\n      @doc since: \"1.2\"\n      def baz(_arg)\n      def baz(arg), do: arg + 1\n    end\n  end\n\n  test \"attributes format\" do\n    defmodule DocAttributes do\n      @moduledoc \"Module doc\"\n      assert @moduledoc == \"Module doc\"\n      assert Module.get_attribute(__MODULE__, :moduledoc) == {__ENV__.line - 2, \"Module doc\"}\n\n      @typedoc \"Type doc\"\n      assert @typedoc == \"Type doc\"\n      assert Module.get_attribute(__MODULE__, :typedoc) == {__ENV__.line - 2, \"Type doc\"}\n      @type foobar :: any\n\n      @doc \"Function doc\"\n      assert @doc == \"Function doc\"\n      assert Module.get_attribute(__MODULE__, :doc) == {__ENV__.line - 2, \"Function doc\"}\n\n      def foobar() do\n        :ok\n      end\n    end\n  end\n\n  test \"compiled without docs\" do\n    Code.compiler_options(docs: false)\n\n    write_beam(\n      defmodule WithoutDocs do\n        @moduledoc \"Module doc\"\n\n        @doc \"Some doc\"\n        def foobar(arg), do: arg\n      end\n    )\n\n    assert Code.fetch_docs(WithoutDocs) == {:error, :chunk_not_found}\n  after\n    Code.compiler_options(docs: true)\n  end\n\n  test \"compiled in memory does not have accessible docs\" do\n    defmodule InMemoryDocs do\n      @moduledoc \"Module doc\"\n\n      @doc \"Some doc\"\n      def foobar(arg), do: arg\n    end\n\n    assert Code.fetch_docs(InMemoryDocs) == {:error, :module_not_found}\n  end\n\n  test \"non-existent beam file\" do\n    assert {:error, :module_not_found} = Code.fetch_docs(\"bad.beam\")\n  end\n\n  test \"raises on invalid @doc since: ...\" do\n    assert_raise ArgumentError, ~r\"should be a string representing the version\", fn ->\n      defmodule InvalidSince do\n        @doc since: 1.2\n        def foo, do: :bar\n      end\n    end\n  end\n\n  test \"raises on invalid @doc\" do\n    assert_raise ArgumentError, ~r/When set dynamically, it should be {line, doc}/, fn ->\n      defmodule DocAttributesFormat do\n        Module.put_attribute(__MODULE__, :moduledoc, \"Other\")\n      end\n    end\n\n    message = ~r/should be either false, nil, a string, or a keyword list/\n\n    assert_raise ArgumentError, message, fn ->\n      defmodule AtSyntaxDocAttributesFormat do\n        @moduledoc :not_a_binary\n      end\n    end\n\n    assert_raise ArgumentError, message, fn ->\n      defmodule AtSyntaxDocAttributesFormat do\n        @moduledoc true\n      end\n    end\n  end\n\n  describe \"compiled with docs\" do\n    test \"infers signatures\" do\n      write_beam(\n        defmodule SignatureDocs do\n          def arg_names([], [], %{}, [], %{}), do: false\n\n          @year 2015\n          def with_defaults(@year, arg \\\\ 0, year \\\\ @year, fun \\\\ &>=/2) do\n            {fun, arg + year}\n          end\n\n          def with_map_and_default(%{key: value} \\\\ %{key: :default}), do: value\n          def with_struct(%URI{}), do: :ok\n\n          def with_underscore({_, _} = _two_tuple), do: :ok\n          def with_underscore(_), do: :error\n\n          def only_underscore(_), do: :ok\n\n          def two_good_names(first, :ok), do: first\n          def two_good_names(second, :error), do: second\n\n          def really_long_signature(\n                really_long_var_named_one,\n                really_long_var_named_two,\n                really_long_var_named_three\n              ) do\n            {really_long_var_named_one, really_long_var_named_two, really_long_var_named_three}\n          end\n        end\n      )\n\n      assert {:docs_v1, _, :elixir, _, _, _, docs} = Code.fetch_docs(SignatureDocs)\n      signatures = for {{:function, n, a}, _, signature, _, %{}} <- docs, do: {{n, a}, signature}\n\n      assert [\n               arg_names,\n               only_underscore,\n               really_long_signature,\n               two_good_names,\n               with_defaults,\n               with_map_and_default,\n               with_struct,\n               with_underscore\n             ] = Enum.sort(signatures)\n\n      # arg_names/5\n      assert {{:arg_names, 5}, [\"arg_names(list1, list2, map1, list3, map2)\"]} = arg_names\n\n      # only_underscore/1\n      assert {{:only_underscore, 1}, [\"only_underscore(_)\"]} = only_underscore\n\n      # really_long_signature/3\n      assert {{:really_long_signature, 3},\n              [\n                \"really_long_signature(really_long_var_named_one, really_long_var_named_two, really_long_var_named_three)\"\n              ]} = really_long_signature\n\n      # two_good_names/2\n      assert {{:two_good_names, 2}, [\"two_good_names(first, atom)\"]} = two_good_names\n\n      # with_defaults/4\n      assert {{:with_defaults, 4},\n              [\"with_defaults(int, arg \\\\\\\\ 0, year \\\\\\\\ 2015, fun \\\\\\\\ &>=/2)\"]} = with_defaults\n\n      # with_map_and_default/1\n      assert {{:with_map_and_default, 1}, [\"with_map_and_default(map \\\\\\\\ %{key: :default})\"]} =\n               with_map_and_default\n\n      # with_struct/1\n      assert {{:with_struct, 1}, [\"with_struct(uri)\"]} = with_struct\n\n      # with_underscore/1\n      assert {{:with_underscore, 1}, [\"with_underscore(two_tuple)\"]} = with_underscore\n    end\n\n    test \"includes docs for functions, modules, types and callbacks\" do\n      line = __ENV__.line\n\n      write_beam(\n        defmodule SampleDocs do\n          @moduledoc \"Module doc\"\n          @moduledoc authors: \"Elixir Contributors\", purpose: :test\n\n          @doc \"My struct\"\n          defstruct [:sample]\n\n          @typedoc \"Type doc\"\n          @typedoc since: \"1.2.3\", color: :red\n          @type foo(any) :: any\n\n          @typedoc \"Opaque type doc\"\n          @opaque bar(any) :: any\n\n          @doc \"Callback doc\"\n          @doc since: \"1.2.3\", color: :red, deprecated: \"use baz/2 instead\"\n          @doc color: :blue, stable: true\n          @callback foo(any) :: any\n\n          @doc false\n          @doc since: \"1.2.3\"\n          @callback bar() :: term\n          @callback baz(any, term) :: any\n\n          @doc \"Callback with multiple clauses\"\n          @callback callback_multi(integer) :: integer\n          @callback callback_multi(atom) :: atom\n\n          @doc \"Macrocallback doc\"\n          @macrocallback qux(any) :: any\n\n          @doc \"Macrocallback with multiple clauses\"\n          @macrocallback macrocallback_multi(integer) :: integer\n          @macrocallback macrocallback_multi(atom) :: atom\n\n          @doc \"Function doc\"\n          @doc since: \"1.2.3\", color: :red\n          @doc color: :blue, stable: true\n          @deprecated \"use baz/2 instead\"\n          def foo(arg \\\\ 0), do: arg + 1\n\n          @doc \"Multiple function head doc\"\n          @deprecated \"something else\"\n          def bar(_arg)\n          def bar(arg), do: arg + 1\n\n          require Kernel.DocsTest\n          Kernel.DocsTest.wrong_doc_baz()\n\n          @doc \"Multiple function head and docs\"\n          @doc since: \"1.2.3\"\n          def baz(_arg)\n\n          @doc false\n          def qux(true), do: false\n\n          @doc \"A guard\"\n          defguard is_zero(v) when v == 0\n\n          # We do this to avoid the deprecation warning.\n          module = Module\n          module.add_doc(__MODULE__, __ENV__.line, :def, {:nullary, 0}, [], \"add_doc\")\n          def nullary, do: 0\n\n          defmodule SampleBehaviour do\n            @callback foo(any()) :: any()\n          end\n\n          @behaviour SampleBehaviour\n        end\n      )\n\n      assert {:docs_v1, _, :elixir, \"text/markdown\", %{\"en\" => module_doc}, module_doc_meta, docs} =\n               Code.fetch_docs(SampleDocs)\n\n      assert module_doc == \"Module doc\"\n\n      file = String.to_charlist(__ENV__.file)\n\n      source_annos = [:erl_anno.new({line + 3, 19})]\n\n      assert %{\n               # Generated meta\n               source_path: ^file,\n               source_annos: ^source_annos,\n               behaviours: [SampleDocs.SampleBehaviour],\n               # User meta\n               authors: \"Elixir Contributors\",\n               purpose: :test\n             } = module_doc_meta\n\n      [\n        callback_bar,\n        callback_baz,\n        callback_multi,\n        callback_foo,\n        function_struct_0,\n        function_struct_1,\n        function_bar,\n        function_baz,\n        function_foo,\n        function_nullary,\n        function_qux,\n        guard_is_zero,\n        macrocallback_multi,\n        macrocallback_qux,\n        type_bar,\n        type_foo\n      ] = Enum.sort(docs)\n\n      assert {{:callback, :bar, 0}, _, [], :hidden, %{}} = callback_bar\n      assert {{:callback, :baz, 2}, _, [], :none, %{}} = callback_baz\n\n      source_annos = [:erl_anno.new({line + 20, 21})]\n\n      assert {{:callback, :foo, 1}, _, [], %{\"en\" => \"Callback doc\"},\n              %{\n                source_annos: ^source_annos,\n                since: \"1.2.3\",\n                deprecated: \"use baz/2 instead\",\n                color: :blue,\n                stable: true\n              }} = callback_foo\n\n      assert {{:callback, :callback_multi, 1}, _, [], %{\"en\" => \"Callback with multiple clauses\"},\n              %{}} = callback_multi\n\n      assert {{:function, :__struct__, 0}, _, [\"%Kernel.DocsTest.SampleDocs{}\"],\n              %{\"en\" => \"My struct\"}, %{}} = function_struct_0\n\n      assert {{:function, :__struct__, 1}, _, [\"__struct__(kv)\"], :hidden, %{}} =\n               function_struct_1\n\n      assert {{:function, :bar, 1}, _, [\"bar(arg)\"], %{\"en\" => \"Multiple function head doc\"},\n              %{deprecated: \"something else\"}} = function_bar\n\n      assert {{:function, :baz, 1}, _, [\"baz(arg)\"], %{\"en\" => \"Multiple function head and docs\"},\n              %{since: \"1.2.3\"}} = function_baz\n\n      source_annos = [:erl_anno.new({line + 42, 15})]\n\n      assert {{:function, :foo, 1}, _, [\"foo(arg \\\\\\\\ 0)\"], %{\"en\" => \"Function doc\"},\n              %{\n                source_annos: ^source_annos,\n                since: \"1.2.3\",\n                deprecated: \"use baz/2 instead\",\n                color: :blue,\n                stable: true,\n                defaults: 1\n              }} = function_foo\n\n      assert {{:function, :nullary, 0}, _, [\"nullary()\"], %{\"en\" => \"add_doc\"}, %{}} =\n               function_nullary\n\n      assert {{:function, :qux, 1}, _, [\"qux(bool)\"], :hidden, %{}} = function_qux\n\n      source_annos = [:erl_anno.new({line + 60, 20})]\n\n      assert {{:macro, :is_zero, 1}, _, [\"is_zero(v)\"], %{\"en\" => \"A guard\"},\n              %{source_annos: ^source_annos, guard: true}} = guard_is_zero\n\n      assert {{:macrocallback, :macrocallback_multi, 1}, _, [],\n              %{\"en\" => \"Macrocallback with multiple clauses\"}, %{}} = macrocallback_multi\n\n      assert {{:macrocallback, :qux, 1}, _, [], %{\"en\" => \"Macrocallback doc\"}, %{}} =\n               macrocallback_qux\n\n      assert {{:type, :bar, 1}, _, [], %{\"en\" => \"Opaque type doc\"}, %{opaque: true}} = type_bar\n\n      source_annos = [:erl_anno.new({line + 12, 17})]\n\n      assert {{:type, :foo, 1}, _, [], %{\"en\" => \"Type doc\"},\n              %{\n                source_annos: ^source_annos,\n                since: \"1.2.3\",\n                color: :red\n              }} = type_foo\n    end\n  end\n\n  test \"fetch docs chunk from doc/chunks\" do\n    Code.compiler_options(docs: false)\n\n    doc_chunks_path = Path.join([tmp_path(), \"doc\", \"chunks\"])\n    File.rm_rf!(doc_chunks_path)\n    File.mkdir_p!(doc_chunks_path)\n\n    write_beam(\n      defmodule ExternalDocs do\n      end\n    )\n\n    assert Code.fetch_docs(ExternalDocs) == {:error, :chunk_not_found}\n\n    path = Path.join([doc_chunks_path, \"#{ExternalDocs}.chunk\"])\n    chunk = {:docs_v1, 1, :elixir, \"text/markdown\", %{\"en\" => \"Some docs\"}, %{}}\n    File.write!(path, :erlang.term_to_binary(chunk))\n\n    assert Code.fetch_docs(ExternalDocs) == chunk\n  after\n    Code.compiler_options(docs: true)\n  end\n\n  test \"@impl true doesn't set @doc false if previous implementation has docs\" do\n    write_beam(\n      defmodule Docs do\n        defmodule SampleBehaviour do\n          @callback foo(any()) :: any()\n          @callback bar() :: any()\n          @callback baz() :: any()\n        end\n\n        @behaviour SampleBehaviour\n\n        @doc \"Foo docs\"\n        def foo(nil), do: nil\n\n        @impl true\n        def foo(_), do: false\n\n        @impl true\n        def bar(), do: true\n\n        @doc \"Baz docs\"\n        @impl true\n        def baz(), do: true\n\n        def fuz(), do: true\n      end\n    )\n\n    {:docs_v1, _, _, _, _, _, docs} = Code.fetch_docs(Docs)\n    function_docs = for {{:function, name, arity}, _, _, doc, _} <- docs, do: {{name, arity}, doc}\n\n    assert [\n             {{:bar, 0}, :hidden},\n             {{:baz, 0}, %{\"en\" => \"Baz docs\"}},\n             {{:foo, 1}, %{\"en\" => \"Foo docs\"}},\n             {{:fuz, 0}, :none}\n           ] = Enum.sort(function_docs)\n  end\n\n  test \"generated functions are annotated as such\" do\n    line = __ENV__.line\n\n    write_beam(\n      defmodule ToBeUsed do\n        defmacro __using__(_) do\n          quote generated: true do\n            @doc \"Hello\"\n            def foo, do: :bar\n          end\n        end\n      end\n    )\n\n    write_beam(\n      defmodule WillBeUsing do\n        use ToBeUsed\n      end\n    )\n\n    {:docs_v1, _, _, _, _, _, docs} = Code.fetch_docs(WillBeUsing)\n\n    doc_anno = :erl_anno.new(line + 15)\n    source_anno = :erl_anno.set_generated(true, :erl_anno.new(line + 15))\n\n    assert [\n             {{:function, :foo, 0}, ^doc_anno, [\"foo()\"], %{\"en\" => \"Hello\"},\n              %{source_annos: [^source_anno]}}\n           ] = docs\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/errors_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.ErrorsTest do\n  use ExUnit.Case, async: true\n\n  defmacro hello(_) do\n    quote location: :keep do\n      def hello, do: :world\n    end\n  end\n\n  test \"no default arguments in fn\" do\n    assert_compile_error(\n      [\"nofile:1:1\", \"anonymous functions cannot have optional arguments\"],\n      ~c\"fn x \\\\\\\\ 1 -> x end\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1:1\", \"anonymous functions cannot have optional arguments\"],\n      ~c\"fn x, y \\\\\\\\ 1 -> x + y end\"\n    )\n  end\n\n  test \"invalid __CALLER__\" do\n    assert_compile_error(\n      [\"nofile:1:34\", \"__CALLER__ is available only inside defmacro and defmacrop\"],\n      ~c\"defmodule Sample do def hello do __CALLER__ end end\"\n    )\n  end\n\n  test \"invalid __STACKTRACE__\" do\n    assert_compile_error(\n      [\n        \"nofile:1:34\",\n        \"__STACKTRACE__ is available only inside catch and rescue clauses of try expressions\"\n      ],\n      ~c\"defmodule Sample do def hello do __STACKTRACE__ end end\"\n    )\n\n    assert_compile_error(\n      [\n        \"nofile:1:66\",\n        \"__STACKTRACE__ is available only inside catch and rescue clauses of try expressions\"\n      ],\n      ~c\"defmodule Sample do try do raise \\\"oops\\\" rescue _ -> def hello do __STACKTRACE__ end end end\"\n    )\n  end\n\n  test \"undefined function\" do\n    assert_compile_error(\n      [\n        \"hello.ex:4:5: \",\n        \"undefined function bar/0 (expected Kernel.ErrorsTest.BadForm to define such a function or for it to be imported, but none are available)\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.BadForm do\n        @file \"hello.ex\"\n        def foo do\n          bar()\n        end\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\n        \"nofile:2:16\",\n        \"undefined function module_info/0 (this function is auto-generated by the compiler and must always be called as a remote, as in __MODULE__.module_info/0)\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.Info do\n        def foo, do: module_info()\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\n        \"nofile:3:16\",\n        \"undefined function behaviour_info/1 (this function is auto-generated by the compiler and must always be called as a remote, as in __MODULE__.behaviour_info/1)\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.BehaviourInfo do\n        @callback dummy() :: :ok\n        def foo, do: behaviour_info(:callbacks)\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\n        \"nofile:3:5\",\n        \"undefined function bar/1 (expected Kernel.ErrorsTest.BadForm to define such a function or for it to be imported, but none are available)\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.BadForm do\n        def foo do\n          bar(\n            baz(1, 2)\n          )\n        end\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\n        \"nofile:8:5\",\n        \"undefined function baz/0 (expected Sample to define such a function or for it to be imported, but none are available)\"\n      ],\n      ~c\"\"\"\n      defmodule Sample do\n        def foo do\n          bar()\n        end\n\n        defoverridable [foo: 0]\n        def foo do\n          baz()\n        end\n      end\n      \"\"\"\n    )\n  end\n\n  test \"undefined function within unused function\" do\n    assert_compile_error(\n      [\"nofile:2:8\", \"undefined function bar/0\"],\n      ~c\"\"\"\n      defmodule Sample do\n        defp foo, do: bar()\n      end\n      \"\"\"\n    )\n  end\n\n  test \"undefined non-local function\" do\n    assert_compile_error(\n      [\"nofile:1:1\", \"undefined function call/2 (there is no such import)\"],\n      ~c\"call foo, do: :foo\"\n    )\n  end\n\n  test \"undefined variables\" do\n    assert_compile_error(\n      [\"nofile:3:13\", \"undefined variable \\\"bar\\\"\", \"nofile:4:13\", \"undefined variable \\\"baz\\\"\"],\n      ~c\"\"\"\n      defmodule Sample do\n        def foo do\n          IO.puts bar\n          IO.puts baz\n        end\n      end\n      \"\"\"\n    )\n  end\n\n  test \"cascading from undefined variables\" do\n    # Test that we show undefined modules/functions/macros on variable failure,\n    # as sometimes the variable failure come from a missing module or require\n    assert_compile_error(\n      [\n        \"nofile:3:23\",\n        \"undefined variable \\\"bar\\\"\",\n        \"nofile:3:19\",\n        \"function UnknownModule.foo/1 is undefined (module UnknownModule is not available)\"\n      ],\n      ~c\"\"\"\n      defmodule Sample do\n        def foo do\n          UnknownModule.foo(bar)\n        end\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\n        \"nofile:3:20\",\n        \"undefined variable \\\"bar\\\"\",\n        \"nofile:3:16\",\n        \"function Enumerable.foo/1 is undefined or private\"\n      ],\n      ~c\"\"\"\n      defmodule Sample do\n        def foo do\n          Enumerable.foo(bar)\n        end\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\n        \"nofile:3:29\",\n        \"undefined variable \\\"bar\\\"\",\n        \"nofile:3:23\",\n        \"function Kernel.ErrorsTest.hello/1 is undefined or private\",\n        \"there is a macro with the same name and arity\"\n      ],\n      ~c\"\"\"\n      defmodule Sample do\n        def foo do\n          Kernel.ErrorsTest.hello(bar)\n        end\n      end\n      \"\"\"\n    )\n  end\n\n  test \"recursive variables on definition\" do\n    assert_compile_error(\n      [\n        \"nofile:2:7: \",\n        \"recursive variable definition in patterns:\",\n        \"foo(x = y, y = z, z = x)\",\n        \"the following variables form a cycle: \\\"x\\\", \\\"y\\\", \\\"z\\\"\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.RecursiveVars do\n        def foo(x = y, y = z, z = x), do: {x, y, z}\n      end\n      \"\"\"\n    )\n  end\n\n  test \"function without definition\" do\n    assert_compile_error(\n      [\"nofile:2:7: \", \"implementation not provided for predefined def foo/0\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.FunctionWithoutDefinition do\n        def foo\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:10: \", \"implementation not provided for predefined def example/2\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.FunctionTemplate do\n        defmacro __using__(_) do\n          quote do\n            def example(foo, bar \\\\\\\\ [])\n          end\n        end\n      end\n\n      defmodule Kernel.ErrorsTest.UseFunctionTemplate do\n        use Kernel.ErrorsTest.FunctionTemplate\n      end\n      \"\"\"\n    )\n  end\n\n  test \"guard without definition\" do\n    assert_compile_error(\n      [\"nofile:2:12: \", \"implementation not provided for predefined defmacro foo/1\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.GuardWithoutDefinition do\n        defguard foo(bar)\n      end\n      \"\"\"\n    )\n  end\n\n  test \"literal on map and struct\" do\n    assert_compile_error(\n      [\"nofile:1:10\", \"expected key-value pairs in a map, got: put_in(foo.bar.baz, nil)\"],\n      ~c\"foo = 1; %{put_in(foo.bar.baz, nil), foo}\"\n    )\n  end\n\n  test \"struct fields on defstruct\" do\n    assert_eval_raise ArgumentError, [\"struct field names must be atoms, got: 1\"], ~c\"\"\"\n    defmodule Kernel.ErrorsTest.StructFieldsOnDefstruct do\n      defstruct [1, 2, 3]\n    end\n    \"\"\"\n  end\n\n  test \"struct access on body\" do\n    assert_compile_error(\n      [\n        \"nofile:3:3\",\n        \"cannot access struct Kernel.ErrorsTest.StructAccessOnBody, \" <>\n          \"the struct was not yet defined or the struct \" <>\n          \"is being accessed in the same context that defines it\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.StructAccessOnBody do\n        defstruct %{name: \"Brasilia\"}\n        %Kernel.ErrorsTest.StructAccessOnBody{}\n      end\n      \"\"\"\n    )\n  end\n\n  describe \"struct errors\" do\n    test \"bad errors\" do\n      assert_compile_error(\n        [\"nofile:1:1\", \"BadStruct.__struct__/1 is undefined, cannot expand struct BadStruct\"],\n        ~c\"%BadStruct{}\"\n      )\n\n      assert_compile_error(\n        [\"nofile:1:1\", \"BadStruct.__struct__/1 is undefined, cannot expand struct BadStruct\"],\n        ~c\"%BadStruct{} = %{}\"\n      )\n\n      bad_struct_type_error =\n        ~r\"expected Kernel.ErrorsTest.BadStructType.__struct__/(0|1) to return a map.*, got: :invalid\"\n\n      defmodule BadStructType do\n        def __struct__, do: :invalid\n        def __struct__(_), do: :invalid\n      end\n\n      assert_compile_error(bad_struct_type_error, ~c\"%#{BadStructType}{}\")\n\n      assert_raise ArgumentError, bad_struct_type_error, fn ->\n        struct(BadStructType)\n      end\n\n      assert_raise ArgumentError, bad_struct_type_error, fn ->\n        struct(BadStructType, foo: 1)\n      end\n    end\n\n    test \"bad struct on module conflict\" do\n      Code.put_compiler_option(:ignore_module_conflict, true)\n\n      assert_compile_error(~r'MissingStructOnReload\\.__struct__/1 is undefined', ~c'''\n      defmodule MissingStructOnReload do\n        defstruct [:title]\n        def d(), do: %MissingStructOnReload{}\n      end\n\n      defmodule MissingStructOnReload do\n        def d(), do: %MissingStructOnReload{}\n      end\n      ''')\n    after\n      Code.put_compiler_option(:ignore_module_conflict, false)\n    end\n\n    test \"missing struct key\" do\n      missing_struct_key_error =\n        ~r\"expected Kernel.ErrorsTest.MissingStructKey.__struct__/(0|1) to return a map.*, got: %\\{\\}\"\n\n      defmodule MissingStructKey do\n        def __struct__, do: %{}\n        def __struct__(_), do: %{}\n      end\n\n      assert_compile_error(missing_struct_key_error, ~c\"%#{MissingStructKey}{}\")\n\n      assert_raise ArgumentError, missing_struct_key_error, fn ->\n        struct(MissingStructKey)\n      end\n\n      assert_raise ArgumentError, missing_struct_key_error, fn ->\n        struct(MissingStructKey, foo: 1)\n      end\n\n      invalid_struct_key_error =\n        ~r\"expected Kernel.ErrorsTest.InvalidStructKey.__struct__/(0|1) to return a map.*, got: %\\{__struct__: 1\\}\"\n\n      defmodule InvalidStructKey do\n        def __struct__, do: %{__struct__: 1}\n        def __struct__(_), do: %{__struct__: 1}\n      end\n\n      assert_compile_error(invalid_struct_key_error, ~c\"%#{InvalidStructKey}{}\")\n\n      assert_raise ArgumentError, invalid_struct_key_error, fn ->\n        struct(InvalidStructKey)\n      end\n\n      assert_raise ArgumentError, invalid_struct_key_error, fn ->\n        struct(InvalidStructKey, foo: 1)\n      end\n    end\n\n    test \"invalid struct\" do\n      invalid_struct_name_error =\n        ~r\"expected struct name returned by Kernel.ErrorsTest.InvalidStructName.__struct__/(0|1) to be Kernel.ErrorsTest.InvalidStructName, got: InvalidName\"\n\n      defmodule InvalidStructName do\n        def __struct__, do: %{__struct__: InvalidName}\n        def __struct__(_), do: %{__struct__: InvalidName}\n      end\n\n      assert_compile_error(invalid_struct_name_error, ~c\"%#{InvalidStructName}{}\")\n\n      assert_raise ArgumentError, invalid_struct_name_error, fn ->\n        struct(InvalidStructName)\n      end\n\n      assert_raise ArgumentError, invalid_struct_name_error, fn ->\n        struct(InvalidStructName, foo: 1)\n      end\n    end\n\n    test \"good struct\" do\n      defmodule GoodStruct do\n        defstruct name: \"john\"\n      end\n\n      assert_eval_raise KeyError,\n                        [\"key :age not found\"],\n                        ~c\"%#{GoodStruct}{age: 27}\"\n\n      assert_compile_error(\n        [\"nofile:1:1\", \"unknown key :age for struct Kernel.ErrorsTest.GoodStruct\"],\n        ~c\"%#{GoodStruct}{age: 27} = %{}\"\n      )\n    end\n\n    test \"enforce @enforce_keys\" do\n      defmodule EnforceKeys do\n        @enforce_keys [:foo]\n        defstruct(foo: nil)\n      end\n\n      assert_raise ArgumentError,\n                   \"@enforce_keys required keys ([:fo, :bar]) that are not defined in defstruct: [foo: nil]\",\n                   fn ->\n                     defmodule EnforceKeysError do\n                       @enforce_keys [:foo, :fo, :bar]\n                       defstruct(foo: nil)\n                     end\n                   end\n    end\n  end\n\n  test \"invalid unquote\" do\n    assert_compile_error([\"nofile:1:1\", \"unquote called outside quote\"], ~c\"unquote 1\")\n  end\n\n  test \"invalid unquote splicing in one-liners\" do\n    assert_eval_raise ArgumentError,\n                      [\n                        \"unquote_splicing only works inside arguments and block contexts, \" <>\n                          \"wrap it in parens if you want it to work with one-liners\"\n                      ],\n                      ~c\"\"\"\n                      defmodule Kernel.ErrorsTest.InvalidUnquoteSplicingInOneliners do\n                        defmacro oneliner2 do\n                          quote do: unquote_splicing 1\n                        end\n\n                        def callme do\n                          oneliner2\n                        end\n                      end\n                      \"\"\"\n  end\n\n  test \"invalid attribute\" do\n    msg = ~r\"cannot inject attribute @foo into function/macro because cannot escape \"\n\n    assert_raise ArgumentError, msg, fn ->\n      defmodule InvalidAttribute do\n        @foo fn -> nil end\n        def bar, do: @foo\n      end\n    end\n  end\n\n  test \"typespec attributes set via Module.put_attribute/4\" do\n    message =\n      \"attributes type, typep, opaque, spec, callback, and macrocallback \" <>\n        \"must be set directly via the @ notation\"\n\n    for kind <- [:type, :typep, :opaque, :spec, :callback, :macrocallback] do\n      assert_eval_raise ArgumentError,\n                        [message],\n                        \"\"\"\n                        defmodule PutTypespecAttribute do\n                          Module.put_attribute(__MODULE__, #{inspect(kind)}, {})\n                        end\n                        \"\"\"\n    end\n  end\n\n  test \"invalid struct field value\" do\n    msg = ~r\"invalid default value for struct field baz, cannot escape \"\n\n    assert_raise ArgumentError, msg, fn ->\n      defmodule InvalidStructFieldValue do\n        defstruct baz: fn -> nil end\n      end\n    end\n  end\n\n  test \"invalid case clauses\" do\n    assert_compile_error(\n      [\"nofile:1:37\", \"expected one argument for \\\"do\\\" clauses (->) in \\\"case\\\"\"],\n      ~c\"case nil do 0, z when not is_nil(z) -> z end\"\n    )\n  end\n\n  test \"invalid fn args\" do\n    exception =\n      assert_eval_raise TokenMissingError,\n                        [\n                          \"nofile:1:5:\",\n                          ~r/missing terminator: end/\n                        ],\n                        ~c\"fn 1\"\n\n    assert exception.opening_delimiter == :fn\n  end\n\n  test \"invalid escape\" do\n    assert_eval_raise TokenMissingError,\n                      [\"nofile:1:3:\", \"invalid escape \\\\ at end of file\"],\n                      ~c\"1 \\\\\"\n  end\n\n  test \"show snippet on missing tokens\" do\n    assert_eval_raise TokenMissingError,\n                      [\n                        \"nofile:1:25:\",\n                        \"missing terminator: end\",\n                        \"defmodule ShowSnippet do\\n\",\n                        \"└ unclosed delimiter\"\n                      ],\n                      ~c\"defmodule ShowSnippet do\"\n  end\n\n  test \"don't show snippet when error line is empty\" do\n    assert_eval_raise TokenMissingError,\n                      [\"nofile:1:25:\", \"missing terminator: end\"],\n                      ~c\"defmodule ShowSnippet do\\n\\n\"\n  end\n\n  test \"function local conflict\" do\n    assert_compile_error(\n      [\"nofile:3:9: \", \"imported Kernel.&&/2 conflicts with local function\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.FunctionLocalConflict do\n        def other, do: 1 && 2\n        def _ && _, do: :error\n      end\n      \"\"\"\n    )\n  end\n\n  test \"macro local conflict\" do\n    assert_compile_error(\n      [\n        \"nofile:6:20\",\n        \"call to local macro &&/2 conflicts with imported Kernel.&&/2, \" <>\n          \"please rename the local macro or remove the conflicting import\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.MacroLocalConflict do\n        def hello, do: 1 || 2\n        defmacro _ || _, do: :ok\n\n        defmacro _ && _, do: :error\n        def world, do: 1 && 2\n      end\n      \"\"\"\n    )\n  end\n\n  test \"macro with undefined local\" do\n    assert_eval_raise UndefinedFunctionError,\n                      [\n                        \"function Kernel.ErrorsTest.MacroWithUndefinedLocal.unknown/1 is undefined (function not available)\"\n                      ],\n                      ~c\"\"\"\n                      defmodule Kernel.ErrorsTest.MacroWithUndefinedLocal do\n                        defmacrop bar, do: unknown(1)\n                        def baz, do: bar()\n                      end\n                      \"\"\"\n  end\n\n  test \"private macro\" do\n    assert_eval_raise UndefinedFunctionError,\n                      [\n                        \"function Kernel.ErrorsTest.PrivateMacro.foo/0 is undefined (function not available)\"\n                      ],\n                      ~c\"\"\"\n                      defmodule Kernel.ErrorsTest.PrivateMacro do\n                        defmacrop foo, do: 1\n                        defmacro bar, do: __MODULE__.foo()\n                        defmacro baz, do: bar()\n                      end\n                      \"\"\"\n  end\n\n  test \"macro invoked before its definition\" do\n    assert_compile_error(\n      [\"nofile:2:16\", \"cannot invoke macro bar/0 before its definition\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.IncorrectMacroDispatch do\n        def foo, do: bar()\n        defmacro bar, do: :bar\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:2:16\", \"cannot invoke macro bar/0 before its definition\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.IncorrectMacropDispatch do\n        def foo, do: bar()\n        defmacrop bar, do: :ok\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:2:40\", \"cannot invoke macro bar/1 before its definition\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.IncorrectMacroDispatch do\n        defmacro bar(a) when is_atom(a), do: bar([a])\n      end\n      \"\"\"\n    )\n  end\n\n  test \"macro captured before its definition\" do\n    assert_compile_error(\n      [\"nofile:3:18\", \"cannot invoke macro is_ok/1 before its definition\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.IncorrectMacroDispatch.Capture do\n        def foo do\n          predicate = &is_ok/1\n          Enum.any?([:ok, :error, :foo], predicate)\n        end\n\n        defmacro is_ok(atom), do: atom == :ok\n      end\n      \"\"\"\n    )\n  end\n\n  test \"function definition with alias\" do\n    assert_compile_error(\n      [\n        \"nofile:2:7\\n\",\n        \"function names should start with lowercase characters or underscore, invalid name Bar\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.FunctionDefinitionWithAlias do\n        def Bar do\n          :baz\n        end\n      end\n      \"\"\"\n    )\n  end\n\n  test \"function import conflict\" do\n    assert_compile_error(\n      [\"nofile:3:16\", \"function exit/1 imported from both :erlang and Kernel, call is ambiguous\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.FunctionImportConflict do\n        import :erlang, only: [exit: 1], warn: false\n        def foo, do: exit(:test)\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:3:17\", \"function exit/1 imported from both :erlang and Kernel, call is ambiguous\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.FunctionImportConflict do\n        import :erlang, only: [exit: 1], warn: false\n        def foo, do: &exit/1\n      end\n      \"\"\"\n    )\n  end\n\n  test \"ensure valid import :only option\" do\n    assert_compile_error(\n      [\n        \"nofile:3:3\",\n        \"invalid :only option for import, expected value to be an atom :functions, :macros, or a literal keyword list of function names with arity as values, got: x\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.Only do\n        x = [flatten: 1]\n        import List, only: x\n      end\n      \"\"\"\n    )\n  end\n\n  test \"ensure valid import :except option\" do\n    assert_compile_error(\n      [\n        \"nofile:3:3\",\n        \"invalid :except option for import, expected value to be a literal keyword list of function names \" <>\n          \"with arity as values, got: Module.__get_attribute__(Kernel.ErrorsTest.Only, :x, 3, true)\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.Only do\n        @x [flatten: 1]\n        import List, except: @x\n      end\n      \"\"\"\n    )\n  end\n\n  test \"def defmacro clause change\" do\n    assert_compile_error(\n      [\"nofile:3:12\\n\", \"defmacro foo/1 already defined as def in nofile:2\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.DefDefmacroClauseChange do\n        def foo(1), do: 1\n        defmacro foo(x), do: x\n      end\n      \"\"\"\n    )\n  end\n\n  test \"def defp clause change from another file\" do\n    assert_compile_error([\"nofile:4\\n\", \"def hello/0 already defined as defp\"], ~c\"\"\"\n    defmodule Kernel.ErrorsTest.DefDefmacroClauseChange do\n      require Kernel.ErrorsTest\n      defp hello, do: :world\n      Kernel.ErrorsTest.hello(:ok)\n    end\n    \"\"\")\n  end\n\n  test \"internal function overridden\" do\n    assert_compile_error(\n      [\"nofile:2:7\\n\", \"cannot define def __info__/1 as it is automatically defined by Elixir\"],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.InternalFunctionOverridden do\n        def __info__(_), do: []\n      end\n      \"\"\"\n    )\n  end\n\n  test \"invalid macro\" do\n    assert_compile_error(\n      \"invalid quoted expression: {:foo, :bar, :baz, :bat}\",\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.InvalidMacro do\n        defmacrop oops do\n          {:foo, :bar, :baz, :bat}\n        end\n\n        def test, do: oops()\n      end\n      \"\"\"\n    )\n  end\n\n  test \"unloaded module\" do\n    assert_compile_error(\n      [\"nofile:1:1\", \"module Certainly.Doesnt.Exist is not loaded and could not be found\"],\n      ~c\"import Certainly.Doesnt.Exist\"\n    )\n  end\n\n  test \"module imported from the context it was defined in\" do\n    assert_compile_error(\n      [\n        \"nofile:4:3\",\n        \"module Kernel.ErrorsTest.ScheduledModule.Hygiene is not loaded but was defined.\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.ScheduledModule do\n        defmodule Hygiene do\n        end\n        import Kernel.ErrorsTest.ScheduledModule.Hygiene\n      end\n      \"\"\"\n    )\n  end\n\n  test \"module imported from the same module\" do\n    assert_compile_error(\n      [\n        \"nofile:3:5\",\n        \"you are trying to use/import/require the module Kernel.ErrorsTest.ScheduledModule.Hygiene which is currently being defined\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.ScheduledModule do\n        defmodule Hygiene do\n          import Kernel.ErrorsTest.ScheduledModule.Hygiene\n        end\n      end\n      \"\"\"\n    )\n  end\n\n  test \"invalid @compile inline\" do\n    assert_compile_error(\n      [\"nofile:1: \", \"undefined function foo/1 given to @compile :inline\"],\n      ~c\"defmodule Test do @compile {:inline, foo: 1} end\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1: \", \"macro foo/1 given to @compile :inline\"],\n      ~c\"defmodule Test do @compile {:inline, foo: 1}; defmacro foo(_), do: :ok end\"\n    )\n  end\n\n  test \"invalid @nifs attribute\" do\n    assert_compile_error(\n      [\"nofile:1: \", \"undefined function foo/1 given to @nifs\"],\n      ~c\"defmodule Test do @nifs [foo: 1] end\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1: \", \"undefined function foo/1 given to @nifs\"],\n      ~c\"defmodule Test do @nifs [foo: 1]; defmacro foo(_) end\"\n    )\n\n    assert_eval_raise ArgumentError,\n                      [\"@nifs is a built-in module attribute\"],\n                      ~c\"defmodule Test do @nifs :not_an_option end\"\n  end\n\n  test \"invalid @dialyzer options\" do\n    assert_compile_error(\n      [\"nofile:1: \", \"undefined function foo/1 given to @dialyzer :nowarn_function\"],\n      ~c\"defmodule Test do @dialyzer {:nowarn_function, {:foo, 1}} end\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1: \", \"macro foo/1 given to @dialyzer :nowarn_function\"],\n      ~c\"defmodule Test do @dialyzer {:nowarn_function, {:foo, 1}}; defmacro foo(_), do: :ok end\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1: \", \"undefined function foo/1 given to @dialyzer :no_opaque\"],\n      ~c\"defmodule Test do @dialyzer {:no_opaque, {:foo, 1}} end\"\n    )\n\n    assert_eval_raise ArgumentError,\n                      [\"invalid value for @dialyzer attribute: :not_an_option\"],\n                      ~c\"defmodule Test do @dialyzer :not_an_option end\"\n  end\n\n  test \"@on_load attribute format\" do\n    assert_raise ArgumentError, ~r/should be an atom or an {atom, 0} tuple/, fn ->\n      defmodule BadOnLoadAttribute do\n        Module.put_attribute(__MODULE__, :on_load, \"not an atom\")\n      end\n    end\n  end\n\n  test \"duplicated @on_load attribute\" do\n    assert_raise ArgumentError, \"the @on_load attribute can only be set once per module\", fn ->\n      defmodule DuplicatedOnLoadAttribute do\n        @on_load :foo\n        @on_load :bar\n      end\n    end\n  end\n\n  test \"@on_load attribute with undefined function\" do\n    assert_compile_error(\n      [\"nofile:1: \", \"undefined function foo/0 given to @on_load\"],\n      ~c\"defmodule UndefinedOnLoadFunction do @on_load :foo end\"\n    )\n  end\n\n  test \"wrong kind for @on_load attribute\" do\n    assert_compile_error(\n      [\"nofile:1: \", \"macro foo/0 given to @on_load\"],\n      ~c\"\"\"\n      defmodule PrivateOnLoadFunction do\n        @on_load :foo\n        defmacro foo, do: :ok\n      end\n      \"\"\"\n    )\n  end\n\n  test \"in definition module\" do\n    assert_compile_error(\n      [\n        \"nofile:2: \",\n        \"cannot define module Kernel.ErrorsTest.InDefinitionModule \" <>\n          \"because it is currently being defined in nofile:1\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.InDefinitionModule do\n        defmodule Elixir.Kernel.ErrorsTest.InDefinitionModule, do: true\n      end\n      \"\"\"\n    )\n  end\n\n  test \"invalid definition\" do\n    assert_compile_error(\n      [\"nofile:1: \", \"invalid syntax in def 1.(hello)\"],\n      ~c\"defmodule Kernel.ErrorsTest.InvalidDefinition, do: (def 1.(hello), do: true)\"\n    )\n  end\n\n  test \"invalid function head\" do\n    assert_compile_error(\n      [\n        \"nofile:2:7: \",\n        \"patterns are not allowed in function head, only variables and default arguments (using \\\\\\\\)\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.InvalidPatternsInFunctionHead do\n        def foo(nil)\n        def foo(_), do: :ok\n      end\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\n        \"nofile:2:7: \",\n        \"guards are not allowed in function head, only variables and default arguments (using \\\\\\\\)\"\n      ],\n      ~c\"\"\"\n      defmodule Kernel.ErrorsTest.InvalidGuardsInFunctionHead do\n        def foo(x) when x == nil\n        def foo(_), do: :ok\n      end\n      \"\"\"\n    )\n\n    assert_compile_error([\"nofile:2:7: \", \"missing :do option in \\\"def\\\"\"], ~c\"\"\"\n    defmodule Kernel.ErrorsTest.BodyessFunctionWithGuard do\n      def foo(n), true\n    end\n    \"\"\")\n\n    assert_compile_error([\"nofile:2:7: \", \"missing :do option in \\\"def\\\"\"], ~c\"\"\"\n    defmodule Kernel.ErrorsTest.BodyessFunctionWithGuard do\n      def foo(n) when is_number(n), true\n    end\n    \"\"\")\n  end\n\n  test \"bad multi-call\" do\n    assert_compile_error(\n      [\n        \"nofile:1:1\",\n        \"invalid argument for alias, expected a compile time atom or alias, got: 42\"\n      ],\n      ~c\"alias IO.{ANSI, 42}\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1:1\", \":as option is not supported by multi-alias call\"],\n      ~c\"alias Elixir.{Map}, as: Dict\"\n    )\n\n    assert_eval_raise UndefinedFunctionError,\n                      [\"function List.\\\"{}\\\"/1 is undefined or private\"],\n                      ~c\"[List.{Chars}, \\\"one\\\"]\"\n  end\n\n  test \"macros error stacktrace\" do\n    assert [\n             {:erlang, :+, [1, :foo], _},\n             {Kernel.ErrorsTest.MacrosErrorStacktrace, :sample, 1, _} | _\n           ] =\n             rescue_stacktrace(\"\"\"\n             defmodule Kernel.ErrorsTest.MacrosErrorStacktrace do\n               defmacro sample(num), do: num + :foo\n               def other, do: sample(1)\n             end\n             \"\"\")\n  end\n\n  test \"macros function clause stacktrace\" do\n    assert [{__MODULE__, :sample, 1, _} | _] =\n             rescue_stacktrace(\"\"\"\n             defmodule Kernel.ErrorsTest.MacrosFunctionClauseStacktrace do\n               import Kernel.ErrorsTest\n               sample(1)\n             end\n             \"\"\")\n  end\n\n  test \"macros interpreted function clause stacktrace\" do\n    assert [{Kernel.ErrorsTest.MacrosInterpretedFunctionClauseStacktrace, :sample, 1, _} | _] =\n             rescue_stacktrace(\"\"\"\n             defmodule Kernel.ErrorsTest.MacrosInterpretedFunctionClauseStacktrace do\n               defmacro sample(0), do: 0\n               def other, do: sample(1)\n             end\n             \"\"\")\n  end\n\n  test \"macros compiled callback\" do\n    assert [{Kernel.ErrorsTest, :__before_compile__, [env], _} | _] =\n             rescue_stacktrace(\"\"\"\n             defmodule Kernel.ErrorsTest.MacrosCompiledCallback do\n               Module.put_attribute(__MODULE__, :before_compile, Kernel.ErrorsTest)\n             end\n             \"\"\")\n\n    assert %Macro.Env{module: Kernel.ErrorsTest.MacrosCompiledCallback} = env\n  end\n\n  test \"failed remote call stacktrace includes file/line info\" do\n    try do\n      bad_remote_call(Process.get(:unused, 1))\n    rescue\n      ArgumentError ->\n        assert [\n                 {:erlang, :apply, [1, :foo, []], _},\n                 {__MODULE__, :bad_remote_call, 1, [file: _, line: _]} | _\n               ] = __STACKTRACE__\n    end\n  end\n\n  test \"def fails when rescue, else or catch don't have clauses\" do\n    assert_compile_error(\n      ~r\"invalid \\\"rescue\\\" block in \\\"def\\\", it expects \\\"pattern -> expr\\\" clauses\",\n      \"\"\"\n      defmodule Example do\n        def foo do\n          bar()\n        rescue\n          baz()\n        end\n      end\n      \"\"\"\n    )\n  end\n\n  test \"duplicate map keys\" do\n    assert_compile_error([\"nofile:1:3\", \"key :a will be overridden in map\"], \"\"\"\n      %{a: :b, a: :c} = %{a: :c}\n    \"\"\")\n\n    assert_compile_error([\"nofile:1:3\", \"key :a will be overridden in map\"], \"\"\"\n      %{a: :b, a: :c, a: :d} = %{a: :c}\n    \"\"\")\n  end\n\n  test \"| outside of cons\" do\n    assert_compile_error([\"nofile:1:3\", \"misplaced operator |/2\"], \"1 | 2\")\n\n    assert_compile_error(\n      [\"nofile:1:45\", \"misplaced operator |/2\"],\n      \"defmodule MisplacedOperator, do: (def bar(1 | 2), do: :ok)\"\n    )\n  end\n\n  test \"reserved word used at module top-level\" do\n    assert_eval_raise(\n      ArgumentError,\n      [\"unexpected reserved word at the top-level of the \\\"defmodule Foo\\\" do-block: catch\"],\n      \"\"\"\n      defmodule Foo do\n        def foo, do: :foo catch :bar\n      end\n      \"\"\"\n    )\n  end\n\n  defp bad_remote_call(x), do: x.foo()\n\n  defmacro sample(0), do: 0\n\n  defmacro before_compile(_) do\n    quote(do: _)\n  end\n\n  ## Helpers\n\n  defp assert_eval_raise(given_exception, messages, source) do\n    exception =\n      assert_raise given_exception, fn ->\n        Code.eval_string(source)\n      end\n\n    error_msg = Exception.format(:error, exception, [])\n\n    for msg <- messages do\n      assert error_msg =~ msg\n    end\n\n    exception\n  end\n\n  defp assert_compile_error(messages, string) do\n    captured =\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        ast = Code.string_to_quoted!(string, columns: true)\n        assert_raise CompileError, fn -> Code.eval_quoted(ast) end\n      end)\n\n    for message <- List.wrap(messages) do\n      assert captured =~ message\n    end\n  end\n\n  defp rescue_stacktrace(string) do\n    try do\n      Code.eval_string(string)\n      nil\n    rescue\n      _ -> __STACKTRACE__\n    else\n      _ -> flunk(\"Expected expression to fail\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/expansion_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.ExpansionTarget do\n  defmacro seventeen, do: 17\n  defmacro bar, do: \"bar\"\n\n  defmacro message_hello(arg) do\n    send(self(), :hello)\n    arg\n  end\nend\n\ndefmodule Kernel.ExpansionTest do\n  use ExUnit.Case, async: true\n\n  import ExUnit.CaptureIO\n\n  describe \"__block__\" do\n    test \"expands to nil when empty\" do\n      assert expand(quote(do: unquote(:__block__)())) == nil\n    end\n\n    test \"expands to argument when arity is 1\" do\n      assert expand(quote(do: unquote(:__block__)(1))) == 1\n    end\n\n    test \"is recursive to argument when arity is 1\" do\n      expanded =\n        quote do\n          _ = 1\n          2\n        end\n\n      assert expand(quote(do: unquote(:__block__)(_ = 1, unquote(:__block__)(2)))) == expanded\n    end\n\n    test \"accumulates vars\" do\n      before_expansion =\n        quote do\n          a = 1\n          a\n        end\n\n      after_expansion =\n        quote do\n          a = 1\n          a\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n  end\n\n  describe \"alias\" do\n    test \"expand args, defines alias and returns itself\" do\n      alias true, as: True\n\n      input = quote(do: alias(:hello, as: World, warn: True))\n      {output, env} = expand_env(input, __ENV__)\n\n      assert output == :hello\n      assert env.aliases == [{:\"Elixir.True\", true}, {:\"Elixir.World\", :hello}]\n    end\n\n    test \"invalid alias\" do\n      message =\n        ~r\"invalid value for option :as, expected a simple alias, got nested alias: Sample.Lists\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: alias(:lists, as: Sample.Lists)))\n      end)\n\n      message = ~r\"invalid argument for alias, expected a compile time atom or alias, got: 1 \\+ 2\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: alias(1 + 2)))\n      end)\n\n      message = ~r\"invalid value for option :as, expected an alias, got: :foobar\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: alias(:lists, as: :foobar)))\n      end)\n\n      message = ~r\"invalid value for option :as, expected an alias, got: :\\\"Elixir.foobar\\\"\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: alias(:lists, as: :\"Elixir.foobar\")))\n      end)\n\n      message =\n        ~r\"alias cannot be inferred automatically for module: :lists, please use the :as option\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: alias(:lists)))\n      end)\n    end\n\n    test \"invalid expansion\" do\n      assert_compile_error(~r\"invalid alias: \\\"foo\\.Foo\\\"\", fn ->\n        code =\n          quote do\n            foo = :foo\n            foo.Foo\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"raises if :as is passed to multi-alias aliases\" do\n      assert_compile_error(~r\":as option is not supported by multi-alias call\", fn ->\n        expand(quote(do: alias(Foo.{Bar, Baz}, as: BarBaz)))\n      end)\n    end\n\n    test \"raises on multi-alias with non-atom base\" do\n      assert_compile_error(~r\"invalid alias: \\\"foo\\\"\", fn ->\n        expand(quote(do: alias(foo.{Bar, Baz})))\n      end)\n    end\n\n    test \"invalid options\" do\n      assert_compile_error(~r\"unsupported option :ops given to alias\", fn ->\n        expand(quote(do: alias(Foo, ops: 1)))\n      end)\n    end\n  end\n\n  describe \"__aliases__\" do\n    test \"expands even if no alias\" do\n      assert expand(quote(do: World)) == :\"Elixir.World\"\n      assert expand(quote(do: Elixir.World)) == :\"Elixir.World\"\n    end\n\n    test \"expands with alias\" do\n      alias Hello, as: World\n      assert expand_env(quote(do: World), __ENV__) |> elem(0) == :\"Elixir.Hello\"\n    end\n\n    test \"expands with alias is recursive\" do\n      alias Source, as: Hello\n      alias Hello, as: World\n      assert expand_env(quote(do: World), __ENV__) |> elem(0) == :\"Elixir.Source\"\n    end\n  end\n\n  describe \"import\" do\n    test \"raises on conflicting options\" do\n      message =\n        ~r\":only and :except can only be given together to import when :only is :functions, :macros, or :sigils\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: import(Kernel, only: [], except: [])))\n      end)\n    end\n\n    test \"invalid import option\" do\n      assert_compile_error(~r\"unsupported option :ops given to import\", fn ->\n        expand(quote(do: import(:lists, ops: 1)))\n      end)\n    end\n\n    test \"raises for non-compile-time module\" do\n      assert_compile_error(~r\"invalid argument for import, .*, got: {:a, :tuple}\", fn ->\n        expand(quote(do: import({:a, :tuple})))\n      end)\n    end\n  end\n\n  describe \"require\" do\n    test \"raises for non-compile-time module\" do\n      assert_compile_error(~r\"invalid argument for require, .*, got: {:a, :tuple}\", fn ->\n        expand(quote(do: require({:a, :tuple})))\n      end)\n    end\n\n    test \"invalid options\" do\n      assert_compile_error(~r\"unsupported option :ops given to require\", fn ->\n        expand(quote(do: require(Foo, ops: 1)))\n      end)\n    end\n  end\n\n  describe \"=\" do\n    test \"defines vars\" do\n      {output, env} = expand_env(quote(do: a = 1), __ENV__)\n      assert output == quote(do: a = 1)\n      assert Macro.Env.has_var?(env, {:a, __MODULE__})\n    end\n\n    test \"does not define _\" do\n      {output, env} = expand_env(quote(do: _ = 1), __ENV__)\n      assert output == quote(do: _ = 1)\n      assert Macro.Env.vars(env) == []\n    end\n\n    test \"errors on directly recursive definitions\" do\n      assert_compile_error(\n        ~r\"\"\"\n        recursive variable definition in patterns:\n\n        \\{x = \\{:ok, x\\}\\}\n\n        the variable \"x\" \\(context Kernel.ExpansionTest\\) is defined in function of itself\n        \"\"\",\n        fn -> expand(quote(do: {x = {:ok, x}} = :ok)) end\n      )\n\n      assert_compile_error(\n        ~r\"\"\"\n        recursive variable definition in patterns:\n\n        \\{\\{x, y\\} = \\{y, x\\}\\}\n\n        the variable \"x\" \\(context Kernel.ExpansionTest\\) is defined in function of itself\n        \"\"\",\n        fn -> expand(quote(do: {{x, y} = {y, x}} = :ok)) end\n      )\n\n      assert_compile_error(\n        ~r\"\"\"\n        recursive variable definition in patterns:\n\n        \\{\\{:x, y\\} = \\{x, :y\\}, x = y\\}\n\n        the variable \"x\" \\(context Kernel.ExpansionTest\\) is defined recursively in function of \"y\" \\(context Kernel.ExpansionTest\\)\n        \"\"\",\n        fn -> expand(quote(do: {{:x, y} = {x, :y}, x = y} = :ok)) end\n      )\n\n      assert_compile_error(\n        ~r\"\"\"\n        recursive variable definition in patterns:\n\n        \\{x = y, y = z, z = x\\}\n\n        the following variables form a cycle: \"x\" \\(context Kernel.ExpansionTest\\), \"y\" \\(context Kernel.ExpansionTest\\), \"z\" \\(context Kernel.ExpansionTest\\)\n        \"\"\",\n        fn -> expand(quote(do: {x = y, y = z, z = x} = :ok)) end\n      )\n    end\n\n    test \"complex recursive variable definitions\" do\n      assert expand(\n               quote do:\n                       {%{type: type, client_id: client_id} = message,\n                        %{type: type, client_id: client_id} = state} = :ok\n             )\n\n      assert_compile_error(\n        ~r\"recursive variable definition in patterns\",\n        fn ->\n          expand(\n            quote do:\n                    {%{type: type, client_id: client_id} = message,\n                     %{type: type, client_id: client_id} = state, client_id = type} = :ok\n          )\n        end\n      )\n    end\n  end\n\n  describe \"environment macros\" do\n    test \"__MODULE__\" do\n      assert expand(quote(do: __MODULE__)) == __MODULE__\n    end\n\n    test \"__DIR__\" do\n      assert expand(quote(do: __DIR__)) == __DIR__\n    end\n\n    test \"__ENV__\" do\n      env = %{__ENV__ | line: 0}\n      assert expand_env(quote(do: __ENV__), env) == {Macro.escape(env), env}\n      assert %{lexical_tracker: nil, tracers: []} = __ENV__\n    end\n\n    test \"__ENV__.accessor\" do\n      env = %{__ENV__ | line: 0}\n      assert expand_env(quote(do: __ENV__.file), env) == {__ENV__.file, env}\n\n      assert expand_env(quote(do: __ENV__.unknown), env) ==\n               {quote(do: unquote(Macro.escape(env)).unknown), env}\n\n      assert __ENV__.lexical_tracker == nil\n      assert __ENV__.tracers == []\n    end\n\n    test \"on match\" do\n      assert_compile_error(\n        ~r\"invalid pattern in match, __ENV__ is not allowed in matches\",\n        fn -> expand(quote(do: __ENV__ = :ok)) end\n      )\n\n      assert_compile_error(\n        ~r\"invalid pattern in match, __CALLER__ is not allowed in matches\",\n        fn -> expand(quote(do: __CALLER__ = :ok)) end\n      )\n\n      assert_compile_error(\n        ~r\"invalid pattern in match, __STACKTRACE__ is not allowed in matches\",\n        fn -> expand(quote(do: __STACKTRACE__ = :ok)) end\n      )\n    end\n  end\n\n  describe \"vars\" do\n    test \"raises on undefined var by default\" do\n      assert_compile_error(~r\"undefined variable \\\"a\\\"\", fn ->\n        expand_env({:a, [], nil}, __ENV__, [])\n      end)\n    end\n\n    test \"expands vars to local call when :on_undefined_variable is :warn\" do\n      Code.put_compiler_option(:on_undefined_variable, :warn)\n\n      {output, env} = expand_env({:a, [], nil}, __ENV__, [])\n      assert output == {:a, [if_undefined: :warn], []}\n      assert Macro.Env.vars(env) == []\n    after\n      Code.put_compiler_option(:on_undefined_variable, :raise)\n    end\n\n    test \"expands vars to local call without warning\" do\n      env = __ENV__\n\n      {output, _, env} =\n        :elixir_expand.expand({:a, [if_undefined: :apply], nil}, :elixir_env.env_to_ex(env), env)\n\n      assert output == {:a, [if_undefined: :apply], []}\n      assert Macro.Env.vars(env) == []\n    end\n\n    test \"raises when expanding var to local call\" do\n      env = __ENV__\n\n      assert_compile_error(~r\"undefined variable \\\"a\\\"\", fn ->\n        :elixir_expand.expand({:a, [if_undefined: :raise], nil}, :elixir_env.env_to_ex(env), env)\n      end)\n    end\n\n    test \"forces variable to exist\" do\n      code =\n        quote do\n          var!(a) = 1\n          var!(a)\n        end\n\n      assert expand(code)\n\n      message = ~r\"undefined variable \\\"a\\\"\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: var!(a)))\n      end)\n\n      message = ~r\"undefined variable \\\"a\\\" \\(context Unknown\\)\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: var!(a, Unknown)))\n      end)\n    end\n\n    test \"raises for _ used outside of a match\" do\n      assert_compile_error(~r\"invalid use of _\", fn ->\n        expand(quote(do: {1, 2, _}))\n      end)\n    end\n\n    defmacrop var_ver(var, version) do\n      quote do\n        {unquote(var), [version: unquote(version)], __MODULE__}\n      end\n    end\n\n    defp expand_with_version(expr) do\n      env = :elixir_env.reset_vars(__ENV__)\n      {expr, _, _} = :elixir_expand.expand(expr, :elixir_env.env_to_ex(env), env)\n      expr\n    end\n\n    test \"tracks variable version\" do\n      assert {:__block__, _, [{:=, _, [var_ver(:x, 0), 0]}, {:=, _, [_, var_ver(:x, 0)]}]} =\n               expand_with_version(\n                 quote do\n                   x = 0\n                   _ = x\n                 end\n               )\n\n      assert {:__block__, _,\n              [\n                {:=, _, [var_ver(:x, 0), 0]},\n                {:=, _, [_, var_ver(:x, 0)]},\n                {:=, _, [var_ver(:x, 1), 1]},\n                {:=, _, [_, var_ver(:x, 1)]}\n              ]} =\n               expand_with_version(\n                 quote do\n                   x = 0\n                   _ = x\n                   x = 1\n                   _ = x\n                 end\n               )\n\n      assert {:__block__, _,\n              [\n                {:=, _, [var_ver(:x, 0), 0]},\n                {:fn, _, [{:->, _, [[var_ver(:x, 1)], {:=, _, [var_ver(:x, 2), 2]}]}]},\n                {:=, _, [_, var_ver(:x, 0)]},\n                {:=, _, [var_ver(:x, 3), 3]}\n              ]} =\n               expand_with_version(\n                 quote do\n                   x = 0\n                   fn x -> x = 2 end\n                   _ = x\n                   x = 3\n                 end\n               )\n\n      assert {:__block__, _,\n              [\n                {:=, _, [var_ver(:x, 0), 0]},\n                {:case, _, [:foo, [do: [{:->, _, [[var_ver(:x, 1)], var_ver(:x, 1)]}]]]},\n                {:=, _, [_, var_ver(:x, 0)]},\n                {:=, _, [var_ver(:x, 2), 2]}\n              ]} =\n               expand_with_version(\n                 quote do\n                   x = 0\n                   case(:foo, do: (x -> x))\n                   _ = x\n                   x = 2\n                 end\n               )\n    end\n  end\n\n  describe \"^\" do\n    test \"expands args\" do\n      before_expansion =\n        quote do\n          after_expansion = 1\n          ^after_expansion = 1\n        end\n\n      after_expansion =\n        quote do\n          after_expansion = 1\n          ^after_expansion = 1\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"raises outside match\" do\n      assert_compile_error(~r\"misplaced operator \\^a\", fn ->\n        expand(quote(do: ^a))\n      end)\n    end\n\n    test \"raises without var\" do\n      message =\n        ~r\"invalid argument for unary operator \\^, expected an existing variable, got: \\^1\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: ^1 = 1))\n      end)\n    end\n\n    test \"raises when the var is undefined\" do\n      assert_compile_error(~r\"undefined variable \\^foo\", fn ->\n        expand(quote(do: ^foo = :foo), [])\n      end)\n    end\n  end\n\n  describe \"locals\" do\n    test \"expands to remote calls\" do\n      assert {{:., _, [Kernel, :=~]}, _, [{:a, _, []}, {:b, _, []}]} = expand(quote(do: a =~ b))\n    end\n\n    test \"in matches\" do\n      assert_compile_error(\n        ~r\"cannot find or invoke local foo/1 inside a match. .+ Called as: foo\\(:bar\\)\",\n        fn ->\n          expand(quote(do: foo(:bar) = :bar))\n        end\n      )\n    end\n\n    test \"in guards\" do\n      code = quote(do: fn pid when :erlang.==(pid, self) -> pid end)\n      expanded_code = quote(do: fn pid when :erlang.==(pid, :erlang.self()) -> pid end)\n      assert clean_meta(expand(code), [:imports, :context]) == expanded_code\n\n      assert_compile_error(~r\"cannot find or invoke local foo/1\", fn ->\n        expand(quote(do: fn arg when foo(arg) -> arg end))\n      end)\n    end\n\n    test \"custom imports\" do\n      before_expansion =\n        quote do\n          import Kernel.ExpansionTarget\n          seventeen()\n        end\n\n      after_expansion =\n        quote do\n          :\"Elixir.Kernel.ExpansionTarget\"\n          17\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"invalid metadata\" do\n      assert expand({:foo, [imports: 2, context: :unknown], [1, 2]}) ==\n               {:foo, [imports: 2, context: :unknown], [1, 2]}\n    end\n  end\n\n  describe \"floats\" do\n    test \"cannot be 0.0 inside match\" do\n      assert capture_io(:stderr, fn -> expand(quote(do: 0.0 = 0.0)) end) =~\n               \"pattern matching on 0.0 is equivalent to matching only on +0.0\"\n\n      assert {:=, [], [+0.0, +0.0]} = expand(quote(do: +0.0 = 0.0))\n      assert {:=, [], [-0.0, +0.0]} = expand(quote(do: -0.0 = 0.0))\n    end\n  end\n\n  describe \"tuples\" do\n    test \"expanded as arguments\" do\n      assert expand(quote(do: {after_expansion = 1, a})) == quote(do: {after_expansion = 1, a()})\n\n      assert expand(quote(do: {b, after_expansion = 1, a})) ==\n               quote(do: {b(), after_expansion = 1, a()})\n    end\n  end\n\n  describe \"maps\" do\n    test \"expanded as arguments\" do\n      assert expand(quote(do: %{a: after_expansion = 1, b: a})) ==\n               quote(do: %{a: after_expansion = 1, b: a()})\n    end\n\n    test \"with variables on keys inside patterns\" do\n      ast =\n        quote do\n          %{(x = 1) => 1}\n        end\n\n      assert expand(ast) == ast\n\n      ast =\n        quote do\n          x = 1\n          %{%{^x => 1} => 2} = y()\n        end\n\n      assert expand(ast) == ast\n\n      ast =\n        quote do\n          x = 1\n          %{{^x} => 1} = %{{1} => 1}\n        end\n\n      assert expand(ast) == ast\n\n      assert_compile_error(~r\"cannot use variable x as map key inside a pattern\", fn ->\n        expand(quote(do: %{x => 1} = %{}))\n      end)\n\n      assert_compile_error(~r\"undefined variable \\^x\", fn ->\n        expand(quote(do: {x, %{^x => 1}} = %{}), [])\n      end)\n    end\n\n    test \"with binaries in keys inside patterns\" do\n      before_ast =\n        quote do\n          %{<<0>> => nil} = %{<<0>> => nil}\n        end\n\n      after_ast =\n        quote do\n          %{<<0::integer>> => nil} = %{<<0::integer>> => nil}\n        end\n\n      assert expand(before_ast) |> clean_meta([:alignment]) == clean_bit_modifiers(after_ast)\n      assert expand(after_ast) |> clean_meta([:alignment]) == clean_bit_modifiers(after_ast)\n\n      ast =\n        quote do\n          x = 8\n          %{<<0::integer-size(x)>> => nil} = %{<<0::integer>> => nil}\n        end\n\n      assert expand(ast) |> clean_meta([:alignment]) ==\n               clean_bit_modifiers(ast) |> clean_meta([:context, :imports])\n\n      assert_compile_error(~r\"cannot use variable x as map key inside a pattern\", fn ->\n        expand(quote(do: %{<<x::integer>> => 1} = %{}), [])\n      end)\n    end\n\n    test \"expects key-value pairs\" do\n      assert_compile_error(~r\"expected key-value pairs in a map, got: :foo\", fn ->\n        expand(quote(do: unquote({:%{}, [], [:foo]})))\n      end)\n    end\n  end\n\n  defmodule User do\n    defstruct name: \"\", age: 0\n  end\n\n  describe \"structs\" do\n    test \"expanded as arguments\" do\n      assert expand(quote(do: %User{})) ==\n               quote(do: %:\"Elixir.Kernel.ExpansionTest.User\"{age: 0, name: \"\"})\n\n      assert expand(quote(do: %User{name: \"john doe\"})) ==\n               quote(do: %:\"Elixir.Kernel.ExpansionTest.User\"{age: 0, name: \"john doe\"})\n    end\n\n    test \"expects atoms\" do\n      expand(quote(do: %unknown{a: 1} = x))\n\n      message = ~r\"expected struct name to be a compile time atom or alias\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: %unknown{a: 1}))\n      end)\n\n      message = ~r\"expected struct name to be a compile time atom or alias\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: %unquote(1){a: 1}))\n      end)\n\n      message = ~r\"expected struct name in a match to be a compile time atom, alias or a variable\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: %unquote(1){a: 1} = x))\n      end)\n    end\n\n    test \"update syntax\" do\n      expand(quote(do: %{%{a: 0} | a: 1}))\n\n      assert_compile_error(~r\"cannot use map/struct update syntax in match\", fn ->\n        expand(quote(do: %{%{a: 0} | a: 1} = %{}))\n      end)\n    end\n\n    test \"dynamic syntax expands to itself\" do\n      assert expand(quote(do: %x{} = 1)) == quote(do: %x{} = 1)\n    end\n\n    test \"invalid keys in structs\" do\n      assert_compile_error(~r\"invalid key :erlang\\.\\+\\(1, 2\\) for struct\", fn ->\n        expand(\n          quote do\n            %User{(1 + 2) => :my_value}\n          end\n        )\n      end)\n    end\n\n    test \"unknown key in structs\" do\n      message = ~r\"unknown key :foo for struct Kernel\\.ExpansionTest\\.User\"\n\n      assert_compile_error(message, fn ->\n        expand_env(quote(do: %User{foo: :my_value} = %{}), %{__ENV__ | function: nil})\n      end)\n    end\n  end\n\n  describe \"quote\" do\n    test \"expanded to raw forms\" do\n      assert expand(quote(do: quote(do: hello)), []) == {:{}, [], [:hello, [], __MODULE__]}\n    end\n\n    test \"raises if the :bind_quoted option is invalid\" do\n      assert_compile_error(~r\"invalid :bind_quoted for quote\", fn ->\n        expand(quote(do: quote(bind_quoted: self(), do: :ok)))\n      end)\n\n      assert_compile_error(~r\"invalid :bind_quoted for quote\", fn ->\n        expand(quote(do: quote(bind_quoted: [{1, 2}], do: :ok)))\n      end)\n    end\n\n    test \"raises for missing do\" do\n      assert_compile_error(~r\"missing :do option in \\\"quote\\\"\", fn ->\n        expand(quote(do: quote(context: Foo)))\n      end)\n    end\n\n    test \"raises for invalid arguments\" do\n      assert_compile_error(~r\"invalid arguments for \\\"quote\\\"\", fn ->\n        expand(quote(do: quote(1 + 1)))\n      end)\n    end\n\n    test \"raises unless its options are a keyword list\" do\n      assert_compile_error(~r\"invalid options for quote, expected a keyword list\", fn ->\n        expand(quote(do: quote(:foo, do: :foo)))\n      end)\n    end\n  end\n\n  describe \"anonymous calls\" do\n    test \"expands base and args\" do\n      assert expand(quote(do: a.(b))) == quote(do: a().(b()))\n    end\n  end\n\n  describe \"remotes\" do\n    test \"expands to Erlang\" do\n      assert expand(quote(do: Kernel.is_atom(a))) == quote(do: :erlang.is_atom(a()))\n    end\n\n    test \"expands macros\" do\n      assert expand(quote(do: Kernel.ExpansionTest.thirteen())) == 13\n    end\n\n    test \"expands receiver and args\" do\n      assert expand(quote(do: a.is_atom(b))) == quote(do: a().is_atom(b()))\n\n      assert expand(quote(do: (after_expansion = :foo).is_atom(a))) ==\n               quote(do: (after_expansion = :foo).is_atom(a()))\n    end\n\n    test \"modules must be required for macros\" do\n      before_expansion =\n        quote do\n          require Kernel.ExpansionTarget\n          Kernel.ExpansionTarget.seventeen()\n        end\n\n      after_expansion =\n        quote do\n          :\"Elixir.Kernel.ExpansionTarget\"\n          17\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"in matches\" do\n      message = ~r\"cannot invoke remote function Hello.fun_that_does_not_exist/0 inside a match\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: Hello.fun_that_does_not_exist() = :foo))\n      end)\n\n      message = ~r\"cannot invoke remote function :erlang.make_ref/0 inside a match\"\n      assert_compile_error(message, fn -> expand(quote(do: make_ref() = :foo)) end)\n\n      message = ~r\"invalid argument for \\+\\+ operator inside a match\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: \"a\" ++ \"b\" = \"ab\"))\n      end)\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: [1 | 2] ++ [3] = [1, 2, 3]))\n      end)\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: [1] ++ 2 ++ [3] = [1, 2, 3]))\n      end)\n\n      assert {:=, _, [-1, -1]} =\n               expand(quote(do: -1 = -1))\n\n      assert {:=, _, [1, 1]} =\n               expand(quote(do: +1 = +1))\n\n      assert {:=, _, [[{:|, _, [1, [{:|, _, [2, 3]}]]}], [1, 2, 3]]} =\n               expand(quote(do: [1] ++ [2] ++ 3 = [1, 2, 3]))\n    end\n\n    test \"in guards\" do\n      message =\n        ~r\"cannot invoke remote function Hello.something_that_does_not_exist/1 inside a guard\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: fn arg when Hello.something_that_does_not_exist(arg) -> arg end))\n      end)\n\n      message = ~r\"cannot invoke remote function :erlang.make_ref/0 inside a guard\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: fn arg when make_ref() -> arg end))\n      end)\n    end\n\n    test \"in guards with macros\" do\n      message =\n        ~r\"you must require the module Integer before invoking macro Integer.is_even/1 inside a guard\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: fn arg when Integer.is_even(arg) -> arg end))\n      end)\n    end\n\n    test \"in guards with bitstrings\" do\n      message = ~r\"cannot invoke remote function String.Chars.to_string/1 inside a guard\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: fn arg when \"#{arg}foo\" == \"argfoo\" -> arg end))\n      end)\n\n      assert_compile_error(message, fn ->\n        expand(\n          quote do\n            fn arg when <<:\"Elixir.Kernel\".to_string(arg)::binary, \"foo\">> == \"argfoo\" ->\n              arg\n            end\n          end\n        )\n      end)\n    end\n  end\n\n  describe \"comprehensions\" do\n    test \"variables do not leak with enums\" do\n      before_expansion =\n        quote do\n          for(a <- b, do: c = 1)\n          c\n        end\n\n      after_expansion =\n        quote do\n          for(a <- b(), do: c = 1)\n          c()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"variables do not leak with binaries\" do\n      before_expansion =\n        quote do\n          for(<<a <- b>>, do: c = 1)\n          c\n        end\n\n      after_expansion =\n        quote do\n          for(<<(<<a::integer>> <- b())>>, do: c = 1)\n          c()\n        end\n\n      assert expand(before_expansion) |> clean_meta([:alignment]) ==\n               clean_bit_modifiers(after_expansion)\n    end\n\n    test \"variables inside generator args do not leak\" do\n      before_expansion =\n        quote do\n          for(\n            b <-\n              (\n                a = 1\n                [2]\n              ),\n            do: {a, b}\n          )\n\n          a\n        end\n\n      after_expansion =\n        quote do\n          for(\n            b <-\n              (\n                a = 1\n                [2]\n              ),\n            do: {a(), b}\n          )\n\n          a()\n        end\n\n      assert expand(before_expansion) == after_expansion\n\n      before_expansion =\n        quote do\n          for(\n            b <-\n              (\n                a = 1\n                [2]\n              ),\n            d <-\n              (\n                c = 3\n                [4]\n              ),\n            do: {a, b, c, d}\n          )\n        end\n\n      after_expansion =\n        quote do\n          for(\n            b <-\n              (\n                a = 1\n                [2]\n              ),\n            d <-\n              (\n                c = 3\n                [4]\n              ),\n            do: {a(), b, c(), d},\n            into: []\n          )\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"variables inside filters are available in blocks\" do\n      assert expand(quote(do: for(a <- b, c = a, do: c))) ==\n               quote(do: for(a <- b(), c = a, do: c, into: []))\n    end\n\n    test \"variables inside options do not leak\" do\n      before_expansion =\n        quote do\n          for(a <- c = b, into: [], do: 1)\n          c\n        end\n\n      after_expansion =\n        quote do\n          for(a <- c = b(), do: 1, into: [])\n          c()\n        end\n\n      assert expand(before_expansion) == after_expansion\n\n      before_expansion =\n        quote do\n          for(a <- b, into: c = [], do: 1)\n          c\n        end\n\n      after_expansion =\n        quote do\n          for(a <- b(), do: 1, into: c = [])\n          c()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"must start with generators\" do\n      assert_compile_error(~r\"for comprehensions must start with a generator\", fn ->\n        expand(quote(do: for(is_atom(:foo), do: :foo)))\n      end)\n\n      assert_compile_error(~r\"for comprehensions must start with a generator\", fn ->\n        expand(quote(do: for(do: :foo)))\n      end)\n    end\n\n    test \"requires size on binary generators\" do\n      message = ~r\"a binary field without size is only allowed at the end of a binary pattern\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: for(<<x::binary <- \"123\">>, do: x)))\n      end)\n    end\n\n    test \"require do option\" do\n      assert_compile_error(~r\"missing :do option in \\\"for\\\"\", fn ->\n        expand(quote(do: for(_ <- 1..2)))\n      end)\n    end\n\n    test \"uniq option is boolean\" do\n      message = ~r\":uniq option for comprehensions only accepts a boolean, got: x\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: for(x <- 1..2, uniq: x, do: x)))\n      end)\n    end\n\n    test \"raise error on invalid reduce\" do\n      assert_compile_error(\n        ~r\"cannot use :reduce alongside :into/:uniq in comprehension\",\n        fn ->\n          expand(quote(do: for(x <- 1..3, reduce: %{}, into: %{}, do: (acc -> acc))))\n        end\n      )\n\n      assert_compile_error(\n        ~r\"the do block was written using acc -> expr clauses but the :reduce option was not given\",\n        fn -> expand(quote(do: for(x <- 1..3, do: (acc -> acc)))) end\n      )\n\n      assert_compile_error(\n        ~r\"when using :reduce with comprehensions, the do block must be written using acc -> expr clauses\",\n        fn -> expand(quote(do: for(x <- 1..3, reduce: %{}, do: x))) end\n      )\n\n      assert_compile_error(\n        ~r\"when using :reduce with comprehensions, the do block must be written using acc -> expr clauses\",\n        fn -> expand(quote(do: for(x <- 1..3, reduce: %{}, do: (acc, x -> x)))) end\n      )\n\n      assert_compile_error(\n        ~r\"when using :reduce with comprehensions, the do block must be written using acc -> expr clauses\",\n        fn -> expand(quote(do: for(x <- 1..3, reduce: %{}, do: (acc, x when 1 == 1 -> x)))) end\n      )\n    end\n\n    test \"raise error for unknown options\" do\n      assert_compile_error(~r\"unsupported option :else given to for\", fn ->\n        expand(quote(do: for(_ <- 1..2, do: 1, else: 1)))\n      end)\n\n      assert_compile_error(~r\"unsupported option :other given to for\", fn ->\n        expand(quote(do: for(_ <- 1..2, do: 1, other: 1)))\n      end)\n    end\n  end\n\n  describe \"with\" do\n    test \"variables do not leak\" do\n      before_expansion =\n        quote do\n          with({foo} <- {bar}, do: baz = :ok)\n          baz\n        end\n\n      after_expansion =\n        quote do\n          with({foo} <- {bar()}, do: baz = :ok)\n          baz()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"variables inside args expression do not leak\" do\n      before_expansion =\n        quote do\n          with(\n            b <-\n              (\n                a = 1\n                2\n              ),\n            do: {a, b}\n          )\n\n          a\n        end\n\n      after_expansion =\n        quote do\n          with(\n            b <-\n              (\n                a = 1\n                2\n              ),\n            do: {a(), b}\n          )\n\n          a()\n        end\n\n      assert expand(before_expansion) == after_expansion\n\n      before_expansion =\n        quote do\n          with(\n            b <-\n              (\n                a = 1\n                2\n              ),\n            d <-\n              (\n                c = 3\n                4\n              ),\n            do: {a, b, c, d}\n          )\n        end\n\n      after_expansion =\n        quote do\n          with(\n            b <-\n              (\n                a = 1\n                2\n              ),\n            d <-\n              (\n                c = 3\n                4\n              ),\n            do: {a(), b, c(), d}\n          )\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"variables are available in do option\" do\n      before_expansion =\n        quote do\n          with({foo} <- {bar}, do: baz = foo)\n          baz\n        end\n\n      after_expansion =\n        quote do\n          with({foo} <- {bar()}, do: baz = foo)\n          baz()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"variables inside else do not leak\" do\n      before_expansion =\n        quote do\n          with({foo} <- {bar}, do: :ok, else: (baz -> baz))\n          baz\n        end\n\n      after_expansion =\n        quote do\n          with({foo} <- {bar()}, do: :ok, else: (baz -> baz))\n          baz()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"fails if \\\"do\\\" is missing\" do\n      assert_compile_error(~r\"missing :do option in \\\"with\\\"\", fn ->\n        expand(quote(do: with(_ <- true, [])))\n      end)\n    end\n\n    test \"fails on invalid else option\" do\n      assert_compile_error(\n        ~r\"invalid \\\"else\\\" block in \\\"with\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          expand(quote(do: with(_ <- true, do: :ok, else: [:error])))\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"else\\\" block in \\\"with\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          expand(quote(do: with(_ <- true, do: :ok, else: :error)))\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"else\\\" block in \\\"with\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          expand(quote(do: with(_ <- true, do: :ok, else: [])))\n        end\n      )\n    end\n\n    test \"fails for invalid options\" do\n      # Only the required \"do\" is present alongside the unexpected option.\n      assert_compile_error(~r\"unexpected option :foo in \\\"with\\\"\", fn ->\n        expand(quote(do: with(_ <- true, foo: :bar, do: :ok)))\n      end)\n\n      # More options are present alongside the unexpected option.\n      assert_compile_error(~r\"unexpected option :foo in \\\"with\\\"\", fn ->\n        expand(quote(do: with(_ <- true, do: :ok, else: (_ -> :ok), foo: :bar)))\n      end)\n\n      assert_compile_error(~r\"unexpected option :foo in \\\"with\\\"\", fn ->\n        expand(\n          quote do\n            with _ <- true, foo: :bar do\n              :ok\n            end\n          end\n        )\n      end)\n    end\n  end\n\n  describe \"&\" do\n    test \"keeps locals\" do\n      assert expand(quote(do: &unknown/2)) == {:&, [], [{:/, [], [{:unknown, [], nil}, 2]}]}\n      assert expand(quote(do: &unknown(&1, &2))) == {:&, [], [{:/, [], [{:unknown, [], nil}, 2]}]}\n    end\n\n    test \"keeps position meta on & variables\" do\n      assert expand(Code.string_to_quoted!(\"& &1\")) |> clean_meta([:counter]) ==\n               {:fn, [capture: true, line: 1],\n                [\n                  {:->, [line: 1],\n                   [\n                     [{:capture, [capture: 1, line: 1], nil}],\n                     {:capture, [capture: 1, line: 1], nil}\n                   ]}\n                ]}\n    end\n\n    test \"removes no_parens when expanding 0-arity capture to fn\" do\n      assert expand(quote(do: &foo().bar/0)) ==\n               quote(do: fn -> foo().bar() end)\n    end\n\n    test \"expands remotes\" do\n      assert expand(quote(do: &List.flatten/2)) ==\n               quote(do: &:\"Elixir.List\".flatten/2)\n               |> clean_meta([:imports, :context])\n\n      assert expand(quote(do: &Kernel.is_atom/1)) ==\n               quote(do: &:erlang.is_atom/1) |> clean_meta([:imports, :context])\n    end\n\n    test \"expands macros\" do\n      before_expansion =\n        quote do\n          require Kernel.ExpansionTarget\n          &Kernel.ExpansionTarget.seventeen/0\n        end\n\n      after_expansion =\n        quote do\n          :\"Elixir.Kernel.ExpansionTarget\"\n          fn -> 17 end\n        end\n\n      assert clean_meta(expand(before_expansion), [:imports, :context, :no_parens]) ==\n               after_expansion\n    end\n\n    test \"fails on non-continuous\" do\n      assert_compile_error(~r\"capture argument &0 must be numbered between 1 and 255\", fn ->\n        expand(quote(do: &foo(&0)))\n      end)\n\n      assert_compile_error(~r\"capture argument &2 cannot be defined without &1\", fn ->\n        expand(quote(do: & &2))\n      end)\n\n      assert_compile_error(~r\"capture argument &255 cannot be defined without &1\", fn ->\n        expand(quote(do: & &255))\n      end)\n    end\n\n    test \"fails on block\" do\n      message = ~r\"block expressions are not allowed inside the capture operator &, got: 1\\n2\"\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            &(\n              1\n              2\n            )\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"fails on other types\" do\n      assert_compile_error(~r\"invalid args for &, expected one of:\", fn ->\n        expand(quote(do: &:foo))\n      end)\n    end\n\n    test \"fails on invalid arity\" do\n      message = ~r\"capture argument &256 must be numbered between 1 and 255\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: &Mod.fun/256))\n      end)\n    end\n\n    test \"fails when no captures\" do\n      assert_compile_error(~r\"invalid args for &, expected one of:\", fn ->\n        expand(quote(do: &foo()))\n      end)\n    end\n\n    test \"fails on nested capture\" do\n      assert_compile_error(~r\"nested captures are not allowed\", fn ->\n        expand(quote(do: &(& &1)))\n      end)\n    end\n\n    test \"fails on integers\" do\n      assert_compile_error(\n        ~r\"capture argument &1 must be used within the capture operator &\",\n        fn -> expand(quote(do: &1)) end\n      )\n    end\n  end\n\n  describe \"fn\" do\n    test \"expands each clause\" do\n      before_expansion =\n        quote do\n          fn\n            x -> x\n            _ -> x\n          end\n        end\n\n      after_expansion =\n        quote do\n          fn\n            x -> x\n            _ -> x()\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not share lexical scope between clauses\" do\n      before_expansion =\n        quote do\n          fn\n            1 -> import List\n            2 -> flatten([1, 2, 3])\n          end\n        end\n\n      after_expansion =\n        quote do\n          fn\n            1 -> :\"Elixir.List\"\n            2 -> flatten([1, 2, 3])\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expands guards\" do\n      assert expand(quote(do: fn x when x when __ENV__.context -> true end)) ==\n               quote(do: fn x when x when :guard -> true end)\n    end\n\n    test \"does not leak vars\" do\n      before_expansion =\n        quote do\n          fn x -> x end\n          x\n        end\n\n      after_expansion =\n        quote do\n          fn x -> x end\n          x()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"raises on mixed arities\" do\n      message = ~r\"cannot mix clauses with different arities in anonymous functions\"\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            fn\n              x -> x\n              x, y -> x + y\n            end\n          end\n\n        expand(code)\n      end)\n    end\n  end\n\n  describe \"cond\" do\n    test \"expands each clause\" do\n      before_expansion =\n        quote do\n          cond do\n            x = 1 -> x\n            true -> x\n          end\n        end\n\n      after_expansion =\n        quote do\n          cond do\n            x = 1 -> x\n            true -> x()\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not share lexical scope between clauses\" do\n      before_expansion =\n        quote do\n          cond do\n            1 -> import List\n            2 -> flatten([1, 2, 3])\n          end\n        end\n\n      after_expansion =\n        quote do\n          cond do\n            1 -> :\"Elixir.List\"\n            2 -> flatten([1, 2, 3])\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not leaks vars on head\" do\n      before_expansion =\n        quote do\n          cond do\n            x = 1 -> x\n            y = 2 -> y\n          end\n\n          :erlang.+(x, y)\n        end\n\n      after_expansion =\n        quote do\n          cond do\n            x = 1 -> x\n            y = 2 -> y\n          end\n\n          :erlang.+(x(), y())\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not leak vars\" do\n      before_expansion =\n        quote do\n          cond do\n            1 -> x = 1\n            2 -> y = 2\n          end\n\n          :erlang.+(x, y)\n        end\n\n      after_expansion =\n        quote do\n          cond do\n            1 -> x = 1\n            2 -> y = 2\n          end\n\n          :erlang.+(x(), y())\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expects exactly one do\" do\n      assert_compile_error(~r\"missing :do option in \\\"cond\\\"\", fn ->\n        expand(quote(do: cond([])))\n      end)\n\n      assert_compile_error(~r\"duplicate \\\"do\\\" clauses given for \\\"cond\\\"\", fn ->\n        expand(quote(do: cond(do: (x -> x), do: (y -> y))))\n      end)\n    end\n\n    test \"expects clauses\" do\n      assert_compile_error(\n        ~r\"invalid \\\"do\\\" block in \\\"cond\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          expand(quote(do: cond(do: :ok)))\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"do\\\" block in \\\"cond\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          expand(quote(do: cond(do: [:not, :clauses])))\n        end\n      )\n    end\n\n    test \"expects one argument in clauses\" do\n      assert_compile_error(\n        ~r\"expected one argument for \\\"do\\\" clauses \\(->\\) in \\\"cond\\\"\",\n        fn ->\n          code =\n            quote do\n              cond do\n                _, _ -> :ok\n              end\n            end\n\n          expand(code)\n        end\n      )\n    end\n\n    test \"raises for invalid arguments\" do\n      assert_compile_error(~r\"invalid arguments for \\\"cond\\\"\", fn ->\n        expand(quote(do: cond(:foo)))\n      end)\n    end\n\n    test \"raises with invalid options\" do\n      assert_compile_error(~r\"unexpected option :foo in \\\"cond\\\"\", fn ->\n        expand(quote(do: cond(do: (1 -> 1), foo: :bar)))\n      end)\n    end\n\n    test \"raises for _ in clauses\" do\n      message = ~r\"invalid use of _ inside \\\"cond\\\"\\. If you want the last clause\"\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            cond do\n              x -> x\n              _ -> :raise\n            end\n          end\n\n        expand(code)\n      end)\n    end\n  end\n\n  describe \"case\" do\n    test \"expands each clause\" do\n      before_expansion =\n        quote do\n          case w do\n            x -> x\n            _ -> x\n          end\n        end\n\n      after_expansion =\n        quote do\n          case w() do\n            x -> x\n            _ -> x()\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not share lexical scope between clauses\" do\n      before_expansion =\n        quote do\n          case w do\n            1 -> import List\n            2 -> flatten([1, 2, 3])\n          end\n        end\n\n      after_expansion =\n        quote do\n          case w() do\n            1 -> :\"Elixir.List\"\n            2 -> flatten([1, 2, 3])\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expands guards\" do\n      before_expansion =\n        quote do\n          case w do\n            x when x when __ENV__.context -> true\n          end\n        end\n\n      after_expansion =\n        quote do\n          case w() do\n            x when x when :guard -> true\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not leaks vars on head\" do\n      before_expansion =\n        quote do\n          case w do\n            x -> x\n            y -> y\n          end\n\n          :erlang.+(x, y)\n        end\n\n      after_expansion =\n        quote do\n          case w() do\n            x -> x\n            y -> y\n          end\n\n          :erlang.+(x(), y())\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not leak vars\" do\n      before_expansion =\n        quote do\n          case w do\n            x -> x = x\n            y -> y = y\n          end\n\n          :erlang.+(x, y)\n        end\n\n      after_expansion =\n        quote do\n          case w() do\n            x -> x = x\n            y -> y = y\n          end\n\n          :erlang.+(x(), y())\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expects exactly one do\" do\n      assert_compile_error(~r\"missing :do option in \\\"case\\\"\", fn ->\n        expand(quote(do: case(e, [])))\n      end)\n\n      assert_compile_error(~r\"duplicate \\\"do\\\" clauses given for \\\"case\\\"\", fn ->\n        expand(quote(do: case(e, do: (x -> x), do: (y -> y))))\n      end)\n    end\n\n    test \"expects clauses\" do\n      assert_compile_error(\n        ~r\"invalid \\\"do\\\" block in \\\"case\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              case e do\n                x\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"do\\\" block in \\\"case\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              case e do\n                [:not, :clauses]\n              end\n            end\n\n          expand(code)\n        end\n      )\n    end\n\n    test \"expects exactly one argument in clauses\" do\n      assert_compile_error(\n        ~r\"expected one argument for \\\"do\\\" clauses \\(->\\) in \\\"case\\\"\",\n        fn ->\n          code =\n            quote do\n              case e do\n                _, _ -> :ok\n              end\n            end\n\n          expand(code)\n        end\n      )\n    end\n\n    test \"fails with invalid arguments\" do\n      assert_compile_error(~r\"invalid arguments for \\\"case\\\"\", fn ->\n        expand(quote(do: case(:foo, :bar)))\n      end)\n    end\n\n    test \"fails for invalid options\" do\n      assert_compile_error(~r\"unexpected option :foo in \\\"case\\\"\", fn ->\n        expand(quote(do: case(e, do: (x -> x), foo: :bar)))\n      end)\n    end\n  end\n\n  describe \"receive\" do\n    test \"expands each clause\" do\n      before_expansion =\n        quote do\n          receive do\n            x -> x\n            _ -> x\n          end\n        end\n\n      after_expansion =\n        quote do\n          receive do\n            x -> x\n            _ -> x()\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not share lexical scope between clauses\" do\n      before_expansion =\n        quote do\n          receive do\n            1 -> import List\n            2 -> flatten([1, 2, 3])\n          end\n        end\n\n      after_expansion =\n        quote do\n          receive do\n            1 -> :\"Elixir.List\"\n            2 -> flatten([1, 2, 3])\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expands guards\" do\n      before_expansion =\n        quote do\n          receive do\n            x when x when __ENV__.context -> true\n          end\n        end\n\n      after_expansion =\n        quote do\n          receive do\n            x when x when :guard -> true\n          end\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not leaks clause vars\" do\n      before_expansion =\n        quote do\n          receive do\n            x -> x\n            y -> y\n          end\n\n          :erlang.+(x, y)\n        end\n\n      after_expansion =\n        quote do\n          receive do\n            x -> x\n            y -> y\n          end\n\n          :erlang.+(x(), y())\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not leak vars\" do\n      before_expansion =\n        quote do\n          receive do\n            x -> x = x\n            y -> y = y\n          end\n\n          :erlang.+(x, y)\n        end\n\n      after_expansion =\n        quote do\n          receive do\n            x -> x = x\n            y -> y = y\n          end\n\n          :erlang.+(x(), y())\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"does not leak vars on after\" do\n      before_expansion =\n        quote do\n          receive do\n            x -> x = x\n          after\n            y ->\n              y\n              w = y\n          end\n\n          :erlang.+(x, w)\n        end\n\n      after_expansion =\n        quote do\n          receive do\n            x -> x = x\n          after\n            y() ->\n              y()\n              w = y()\n          end\n\n          :erlang.+(x(), w())\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expects exactly one do or after\" do\n      assert_compile_error(~r\"missing :do/:after option in \\\"receive\\\"\", fn ->\n        expand(quote(do: receive([])))\n      end)\n\n      assert_compile_error(~r\"duplicate \\\"do\\\" clauses given for \\\"receive\\\"\", fn ->\n        expand(quote(do: receive(do: (x -> x), do: (y -> y))))\n      end)\n\n      assert_compile_error(~r\"duplicate \\\"after\\\" clauses given for \\\"receive\\\"\", fn ->\n        code =\n          quote do\n            receive do\n              x -> x\n            after\n              y -> y\n            after\n              z -> z\n            end\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"expects clauses\" do\n      assert_compile_error(\n        ~r\"invalid \\\"do\\\" block in \\\"receive\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              receive do\n                x\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"do\\\" block in \\\"receive\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              receive do\n                [:not, :clauses]\n              end\n            end\n\n          expand(code)\n        end\n      )\n    end\n\n    test \"expects on argument for do/after clauses\" do\n      assert_compile_error(\n        ~r\"expected one argument for \\\"do\\\" clauses \\(->\\) in \\\"receive\\\"\",\n        fn ->\n          code =\n            quote do\n              receive do\n                _, _ -> :ok\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      message = ~r\"expected one argument for \\\"after\\\" clauses \\(->\\) in \\\"receive\\\"\"\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            receive do\n              x -> x\n            after\n              _, _ -> :ok\n            end\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"expects a single clause for \\\"after\\\"\" do\n      assert_compile_error(~r\"expected a single -> clause for :after in \\\"receive\\\"\", fn ->\n        code =\n          quote do\n            receive do\n              x -> x\n            after\n              1 -> y\n              2 -> z\n            end\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"raises for invalid arguments\" do\n      assert_compile_error(~r\"invalid arguments for \\\"receive\\\"\", fn ->\n        expand(quote(do: receive(:foo)))\n      end)\n    end\n\n    test \"raises with invalid options\" do\n      assert_compile_error(~r\"unexpected option :foo in \\\"receive\\\"\", fn ->\n        expand(quote(do: receive(do: (x -> x), foo: :bar)))\n      end)\n    end\n  end\n\n  describe \"try\" do\n    test \"expands catch\" do\n      before_expansion =\n        quote do\n          try do\n            x\n          catch\n            x, y -> z = :erlang.+(x, y)\n          end\n\n          z\n        end\n\n      after_expansion =\n        quote do\n          try do\n            x()\n          catch\n            x, y -> z = :erlang.+(x, y)\n          end\n\n          z()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expands catch with when\" do\n      before_expansion =\n        quote do\n          try do\n            x\n          catch\n            x when x -> z = :erlang.-(x)\n          end\n\n          z\n        end\n\n      after_expansion =\n        quote do\n          try do\n            x()\n          catch\n            :throw, x when x -> z = :erlang.-(x)\n          end\n\n          z()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expands after\" do\n      before_expansion =\n        quote do\n          try do\n            x\n          after\n            z = y\n          end\n\n          z\n        end\n\n      after_expansion =\n        quote do\n          try do\n            x()\n          after\n            z = y()\n          end\n\n          z()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expands else\" do\n      before_expansion =\n        quote do\n          try do\n            x\n          catch\n            _, _ -> :ok\n          else\n            z -> z\n          end\n\n          z\n        end\n\n      after_expansion =\n        quote do\n          try do\n            x()\n          catch\n            _, _ -> :ok\n          else\n            z -> z\n          end\n\n          z()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expands rescue\" do\n      before_expansion =\n        quote do\n          try do\n            x\n          rescue\n            x -> x\n            Error -> x\n          end\n\n          x\n        end\n\n      after_expansion =\n        quote do\n          try do\n            x()\n          rescue\n            x -> x\n            unquote(:in)(_, [:\"Elixir.Error\"]) -> x()\n          end\n\n          x()\n        end\n\n      assert expand(before_expansion) == after_expansion\n    end\n\n    test \"expects more than do\" do\n      assert_compile_error(~r\"missing :catch/:rescue/:after option in \\\"try\\\"\", fn ->\n        code =\n          quote do\n            try do\n              x = y\n            end\n\n            x\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"raises if do is missing\" do\n      assert_compile_error(~r\"missing :do option in \\\"try\\\"\", fn ->\n        expand(quote(do: try([])))\n      end)\n    end\n\n    test \"expects at most one clause\" do\n      assert_compile_error(~r\"duplicate \\\"do\\\" clauses given for \\\"try\\\"\", fn ->\n        expand(quote(do: try(do: e, do: f)))\n      end)\n\n      assert_compile_error(~r\"duplicate \\\"rescue\\\" clauses given for \\\"try\\\"\", fn ->\n        code =\n          quote do\n            try do\n              e\n            rescue\n              x -> x\n            rescue\n              y -> y\n            end\n          end\n\n        expand(code)\n      end)\n\n      assert_compile_error(~r\"duplicate \\\"after\\\" clauses given for \\\"try\\\"\", fn ->\n        code =\n          quote do\n            try do\n              e\n            after\n              x = y\n            after\n              x = y\n            end\n          end\n\n        expand(code)\n      end)\n\n      assert_compile_error(~r\"duplicate \\\"else\\\" clauses given for \\\"try\\\"\", fn ->\n        code =\n          quote do\n            try do\n              e\n            else\n              x -> x\n            else\n              y -> y\n            end\n          end\n\n        expand(code)\n      end)\n\n      assert_compile_error(~r\"duplicate \\\"catch\\\" clauses given for \\\"try\\\"\", fn ->\n        code =\n          quote do\n            try do\n              e\n            catch\n              x -> x\n            catch\n              y -> y\n            end\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"raises with invalid arguments\" do\n      assert_compile_error(~r\"invalid arguments for \\\"try\\\"\", fn ->\n        expand(quote(do: try(:foo)))\n      end)\n    end\n\n    test \"raises with invalid options\" do\n      assert_compile_error(~r\"unexpected option :foo in \\\"try\\\"\", fn ->\n        expand(quote(do: try(do: x, foo: :bar)))\n      end)\n    end\n\n    test \"expects exactly one argument in rescue clauses\" do\n      assert_compile_error(\n        ~r\"expected one argument for \\\"rescue\\\" clauses \\(->\\) in \\\"try\\\"\",\n        fn ->\n          code =\n            quote do\n              try do\n                x\n              rescue\n                _, _ -> :ok\n              end\n            end\n\n          expand(code)\n        end\n      )\n    end\n\n    test \"expects an alias, a variable, or \\\"var in [alias]\\\" as the argument of rescue clauses\" do\n      assert_compile_error(~r\"invalid \\\"rescue\\\" clause\\. The clause should match\", fn ->\n        code =\n          quote do\n            try do\n              x\n            rescue\n              function(:call) -> :ok\n            end\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"expects one or two args for catch clauses\" do\n      message = ~r\"expected one or two args for \\\"catch\\\" clauses \\(->\\) in \\\"try\\\"\"\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            try do\n              x\n            catch\n              _, _, _ -> :ok\n            end\n          end\n\n        expand(code)\n      end)\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            try do\n              x\n            catch\n              _, _, _ when 1 == 1 -> :ok\n            end\n          end\n\n        expand(code)\n      end)\n    end\n\n    test \"expects clauses for rescue, else, catch\" do\n      assert_compile_error(\n        ~r\"invalid \\\"rescue\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              rescue\n                x\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"rescue\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              rescue\n                [:not, :clauses]\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"rescue\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              rescue\n                []\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"catch\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              catch\n                x\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"catch\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              catch\n                [:not, :clauses]\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"catch\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              catch\n                []\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"else\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              catch\n                _ -> :ok\n              else\n                x\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"else\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              catch\n                _ -> :ok\n              else\n                [:not, :clauses]\n              end\n            end\n\n          expand(code)\n        end\n      )\n\n      assert_compile_error(\n        ~r\"invalid \\\"else\\\" block in \\\"try\\\", it expects \\\"pattern -> expr\\\" clauses\",\n        fn ->\n          code =\n            quote do\n              try do\n                e\n              catch\n                _ -> :ok\n              else\n                []\n              end\n            end\n\n          expand(code)\n        end\n      )\n    end\n  end\n\n  describe \"bitstrings\" do\n    test \"parallel match\" do\n      assert expand(quote(do: <<foo>> = <<bar>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<foo::integer>> = <<bar()::integer>>)\n               |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<foo>> = baz = <<bar>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<foo::integer>> = baz = <<bar()::integer>>)\n               |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<foo>> = <<bar>> = baz)) |> clean_meta([:alignment]) ==\n               quote(do: <<foo::integer>> = <<bar::integer>> = baz())\n               |> clean_bit_modifiers()\n    end\n\n    test \"invalid match\" do\n      assert_compile_error(\n        \"a bitstring only accepts binaries, numbers, and variables inside a match\",\n        fn ->\n          expand(quote(do: <<%{}>> = foo()))\n        end\n      )\n    end\n\n    test \"nested match\" do\n      assert expand(quote(do: <<foo = bar>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<foo = bar()::integer>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<?-, <<_, _::binary>> = rest()::binary>>))\n             |> clean_meta([:alignment]) ==\n               quote(do: <<45::integer, <<_::integer, _::binary>> = rest()::binary>>)\n               |> clean_bit_modifiers()\n    end\n\n    test \"inlines binaries inside interpolation\" do\n      import Kernel.ExpansionTarget\n\n      # Check expansion happens only once\n      assert expand(quote(do: \"foo#{message_hello(\"bar\")}\")) |> clean_meta([:alignment]) ==\n               quote(do: <<\"foo\"::binary, \"bar\"::binary>>) |> clean_bit_modifiers()\n\n      assert_received :hello\n      refute_received :hello\n\n      # And it also works in match\n      assert expand(quote(do: \"foo#{bar()}\" = \"foobar\")) |> clean_meta([:alignment]) ==\n               quote(do: <<\"foo\"::binary, \"bar\"::binary>> = \"foobar\")\n               |> clean_bit_modifiers()\n    end\n\n    test \"inlines binaries inside interpolation is isomorphic after manual expansion\" do\n      import Kernel.ExpansionTarget\n\n      quoted = Macro.prewalk(quote(do: \"foo#{bar()}\" = \"foobar\"), &Macro.expand(&1, __ENV__))\n\n      assert expand(quoted) |> clean_meta([:alignment]) ==\n               quote(do: <<\"foo\"::binary, \"bar\"::binary>> = \"foobar\")\n               |> clean_bit_modifiers()\n    end\n\n    test \"expands size * unit\" do\n      import Kernel, except: [-: 1, -: 2]\n      import Kernel.ExpansionTarget\n\n      assert expand(quote(do: <<x::13>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-size(13)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::13*6>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-unit(6)-size(13)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::_*6-binary>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::binary-unit(6)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::13*6-binary>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::binary-unit(6)-size(13)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::binary-(13 * 6)-binary>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::binary-unit(6)-size(13)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::seventeen()>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-size(17)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::seventeen()*2>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-unit(2)-size(17)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::seventeen()*seventeen()>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-unit(17)-size(17)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::_*seventeen()-binary>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::binary-unit(17)>>) |> clean_bit_modifiers()\n    end\n\n    test \"expands binary/bitstring specifiers\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      assert expand(quote(do: <<x::binary>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::binary>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::bytes>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::binary>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::bitstring>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::bitstring>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::bits>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::bitstring>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::binary-little>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::binary>>) |> clean_bit_modifiers()\n\n      message = ~r\"signed and unsigned specifiers are supported only on integer and float type\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<x()::binary-signed>>))\n      end)\n    end\n\n    test \"expands utf* specifiers\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      assert expand(quote(do: <<x::utf8>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::utf8>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::utf16>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::utf16>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::utf32-little>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::utf32-little>>) |> clean_bit_modifiers()\n\n      message = ~r\"signed and unsigned specifiers are supported only on integer and float type\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<x()::utf8-signed>>))\n      end)\n\n      assert_compile_error(~r\"size and unit are not supported on utf types\", fn ->\n        expand(quote(do: <<x()::utf8-size(32)>>))\n      end)\n    end\n\n    test \"expands numbers specifiers\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      assert expand(quote(do: <<x::integer>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::little>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-little>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::signed>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-signed>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::signed-native>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-native-signed>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x::float-signed-native>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::float-native-signed>>) |> clean_bit_modifiers()\n\n      message =\n        ~r\"integer and float types require a size specifier if the unit specifier is given\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<x::unit(8)>>))\n      end)\n    end\n\n    test \"expands macro specifiers\" do\n      import Kernel, except: [-: 1, -: 2]\n      import Kernel.ExpansionTarget\n\n      assert expand(quote(do: <<x::seventeen()>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer-size(17)>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<seventeen::seventeen(), x::size(seventeen)>> = 1))\n             |> clean_meta([:alignment]) ==\n               quote(do: <<seventeen::integer-size(17), x::integer-size(seventeen)>> = 1)\n               |> clean_bit_modifiers()\n    end\n\n    test \"expands macro in args\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      before_expansion =\n        quote do\n          require Kernel.ExpansionTarget\n          <<x::size(Kernel.ExpansionTarget.seventeen())>>\n        end\n\n      after_expansion =\n        quote do\n          :\"Elixir.Kernel.ExpansionTarget\"\n          <<x()::integer-size(17)>>\n        end\n\n      assert expand(before_expansion) |> clean_meta([:alignment]) ==\n               clean_bit_modifiers(after_expansion)\n    end\n\n    test \"supports dynamic size\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      before_expansion =\n        quote do\n          var = 1\n          <<x::size(var)-unit(8)>>\n        end\n\n      after_expansion =\n        quote do\n          var = 1\n          <<x()::integer-unit(8)-size(var)>>\n        end\n\n      assert expand(before_expansion) |> clean_meta([:alignment]) ==\n               clean_bit_modifiers(after_expansion)\n    end\n\n    defmacro offset(size, binary) do\n      quote do\n        offset = unquote(size)\n        <<_::size(^offset)>> = unquote(binary)\n      end\n    end\n\n    test \"supports size from counters\" do\n      assert offset(8, <<0>>)\n    end\n\n    test \"merges bitstrings\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      assert expand(quote(do: <<x, <<y::signed-native>>, z>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer, y()::integer-native-signed, z()::integer>>)\n               |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<x, <<y::signed-native>>::bitstring, z>>))\n             |> clean_meta([:alignment]) ==\n               quote(do: <<x()::integer, y()::integer-native-signed, z()::integer>>)\n               |> clean_bit_modifiers()\n    end\n\n    test \"merges binaries\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      assert expand(quote(do: \"foo\" <> x)) |> clean_meta([:alignment]) ==\n               quote(do: <<\"foo\"::binary, x()::binary>>) |> clean_bit_modifiers()\n\n      assert expand(quote(do: \"foo\" <> <<x::size(4), y::size(4)>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<\"foo\"::binary, x()::integer-size(4), y()::integer-size(4)>>)\n               |> clean_bit_modifiers()\n\n      assert expand(quote(do: <<\"foo\", <<x::size(4), y::size(4)>>::binary>>))\n             |> clean_meta([:alignment]) ==\n               quote(do: <<\"foo\"::binary, x()::integer-size(4), y()::integer-size(4)>>)\n               |> clean_bit_modifiers()\n    end\n\n    test \"guard expressions on size\" do\n      import Kernel, except: [-: 1, -: 2, +: 1, +: 2, length: 1]\n\n      # Arithmetic operations with literals and variables are valid expressions\n      # for bitstring size in OTP 23+\n\n      before_expansion =\n        quote do\n          var = 1\n          <<x::size(var + 3)>>\n        end\n\n      after_expansion =\n        quote do\n          var = 1\n          <<x()::integer-size(:erlang.+(var, 3))>>\n        end\n\n      assert expand(before_expansion) |> clean_meta([:alignment]) ==\n               clean_bit_modifiers(after_expansion)\n\n      # Other valid guard expressions are also legal for bitstring size in OTP 23+\n\n      before_expansion = quote(do: <<x::size(length(~c\"test\"))>>)\n      after_expansion = quote(do: <<x()::integer-size(:erlang.length([?t, ?e, ?s, ?t]))>>)\n\n      assert expand(before_expansion) |> clean_meta([:alignment]) ==\n               clean_bit_modifiers(after_expansion)\n    end\n\n    test \"map lookup on size\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      before_expansion =\n        quote do\n          var = %{foo: 3}\n          <<x::size(var.foo)>>\n        end\n\n      after_expansion =\n        quote do\n          var = %{foo: 3}\n          <<x()::integer-size(var.foo)>>\n        end\n\n      assert expand(before_expansion) |> clean_meta([:alignment]) ==\n               clean_bit_modifiers(after_expansion)\n    end\n\n    test \"raises on unaligned binaries in match\" do\n      message = ~r\"its number of bits is not divisible by 8\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<rest::size(3)>> <> _ = \"foo\"))\n      end)\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<1::4>> <> \"foo\"))\n      end)\n    end\n\n    test \"raises on size or unit for literal bitstrings\" do\n      message = ~r\"literal <<>> in bitstring supports only type specifiers\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<(<<\"foo\">>)::32>>))\n      end)\n    end\n\n    test \"raises on size or unit for literal strings\" do\n      message = ~r\"literal string in bitstring supports only endianness and type specifiers\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<\"foo\"::32>>))\n      end)\n    end\n\n    test \"16-bit floats\" do\n      import Kernel, except: [-: 1, -: 2]\n\n      assert expand(quote(do: <<12.3::float-16>>)) |> clean_meta([:alignment]) ==\n               quote(do: <<12.3::float-size(16)>>) |> clean_bit_modifiers()\n    end\n\n    test \"raises for invalid size * unit for floats\" do\n      message = ~r\"float requires size\\*unit to be 16, 32, or 64 \\(default\\), got: 128\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<12.3::32*4>>))\n      end)\n\n      message = ~r\"float requires size\\*unit to be 16, 32, or 64 \\(default\\), got: 256\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<12.3::256>>))\n      end)\n    end\n\n    test \"raises for invalid size\" do\n      assert_compile_error(~r/undefined variable \"foo\"/, fn ->\n        code =\n          quote do\n            fn <<_::size(foo)>> -> :ok end\n          end\n\n        expand(code, [])\n      end)\n\n      assert_compile_error(~r/undefined variable \"foo\"/, fn ->\n        code =\n          quote do\n            fn <<_::size(foo), foo::size(8)>> -> :ok end\n          end\n\n        expand(code, [])\n      end)\n\n      assert_compile_error(~r/undefined variable \"foo\"/, fn ->\n        code =\n          quote do\n            fn foo, <<_::size(foo)>> -> :ok end\n          end\n\n        expand(code, [])\n      end)\n\n      assert_compile_error(~r/undefined variable \"foo\"/, fn ->\n        code =\n          quote do\n            fn foo, <<_::size(foo + 1)>> -> :ok end\n          end\n\n        expand(code, [])\n      end)\n\n      assert_compile_error(\n        ~r\"cannot find or invoke local foo/0 inside a bitstring size specifier\",\n        fn ->\n          code =\n            quote do\n              fn <<_::size(foo())>> -> :ok end\n            end\n\n          expand(code, [])\n        end\n      )\n\n      message = ~r\"anonymous call is not allowed inside a bitstring size specifier\"\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            fn <<_::size(foo.())>> -> :ok end\n          end\n\n        expand(code, [])\n      end)\n\n      message = ~r\"cannot invoke remote function inside a bitstring size specifier\"\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            foo = %{bar: true}\n            fn <<_::size(foo.bar())>> -> :ok end\n          end\n\n        expand(code, [])\n      end)\n\n      message = ~r\"cannot invoke remote function Foo.bar/0 inside a bitstring size specifier\"\n\n      assert_compile_error(message, fn ->\n        code =\n          quote do\n            fn <<_::size(Foo.bar())>> -> :ok end\n          end\n\n        expand(code, [])\n      end)\n    end\n\n    test \"raises for variable used both in pattern and size\" do\n      assert_compile_error(~r/undefined variable \"foo\"/, fn ->\n        code =\n          quote do\n            fn <<foo::size(foo)>> -> :ok end\n          end\n\n        expand(code, [])\n      end)\n    end\n\n    test \"raises for invalid unit\" do\n      message = ~r\"unit in bitstring expects an integer as argument, got: :oops\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<\"foo\"::size(8)-unit(:oops)>>))\n      end)\n    end\n\n    test \"raises for unknown specifier\" do\n      assert_compile_error(~r\"unknown bitstring specifier: unknown()\", fn ->\n        expand(quote(do: <<1::unknown()>>))\n      end)\n    end\n\n    test \"raises for conflicting specifiers\" do\n      assert_compile_error(~r\"conflicting endianness specification for bit field\", fn ->\n        expand(quote(do: <<1::little-big>>))\n      end)\n\n      assert_compile_error(~r\"conflicting unit specification for bit field\", fn ->\n        expand(quote(do: <<x::bitstring-unit(2)>>))\n      end)\n    end\n\n    test \"raises on binary fields with size in matches\" do\n      assert expand(quote(do: <<x::binary-size(3), y::binary>> = \"foobar\"))\n\n      message = ~r\"a binary field without size is only allowed at the end of a binary pattern\"\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<x::binary, y::binary>> = \"foobar\"))\n      end)\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<(<<x::binary>>), y::binary>> = \"foobar\"))\n      end)\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<(<<x::bitstring>>), y::bitstring>> = \"foobar\"))\n      end)\n\n      assert_compile_error(message, fn ->\n        expand(quote(do: <<(<<x::bitstring>>)::bitstring, y::bitstring>> = \"foobar\"))\n      end)\n    end\n  end\n\n  describe \"op ambiguity\" do\n    test \"raises when a call is ambiguous\" do\n      # We use string_to_quoted! here to avoid the formatter adding parentheses\n      message = ~r[\"a -1\" looks like a function call but there is a variable named \"a\"]\n\n      assert_compile_error(message, fn ->\n        code =\n          Code.string_to_quoted!(\"\"\"\n          a = 1\n          a -1\n          \"\"\")\n\n        expand(code)\n      end)\n\n      message =\n        ~r[\"a -1\\.\\.\\(a \\+ 1\\)\" looks like a function call but there is a variable named \"a\"]\n\n      assert_compile_error(message, fn ->\n        code =\n          Code.string_to_quoted!(\"\"\"\n          a = 1\n          a -1 .. a + 1\n          \"\"\")\n\n        expand(code)\n      end)\n    end\n  end\n\n  test \"handles invalid expressions\" do\n    assert_compile_error(~r\"invalid quoted expression: {1, 2, 3}\", fn ->\n      expand_env({1, 2, 3}, __ENV__)\n    end)\n\n    assert_compile_error(~r\"invalid quoted expression: #Function\\<\", fn ->\n      expand({:sample, fn -> nil end})\n    end)\n\n    assert_compile_error(~r\"invalid pattern in match\", fn ->\n      code =\n        quote do\n          x = & &1\n\n          case true do\n            x.(false) -> true\n          end\n        end\n\n      expand(code)\n    end)\n\n    assert_compile_error(~r\"anonymous call is not allowed in guards\", fn ->\n      code =\n        quote do\n          x = & &1\n\n          case true do\n            true when x.(true) -> true\n          end\n        end\n\n      expand(code)\n    end)\n\n    assert_compile_error(~r\"invalid call foo\\(1\\)\\(2\\)\", fn ->\n      expand(quote(do: foo(1)(2)))\n    end)\n\n    assert_compile_error(~r\"invalid call 1\\.foo\", fn ->\n      expand(quote(do: 1.foo))\n    end)\n\n    assert_compile_error(~r\"invalid call 0\\.foo\", fn ->\n      expand(quote(do: __ENV__.line.foo))\n    end)\n\n    assert_compile_error(~r\"misplaced operator ->\", fn ->\n      expand(quote(do: (foo -> bar)))\n    end)\n  end\n\n  ## Helpers\n\n  defmacro thirteen do\n    13\n  end\n\n  defp assert_compile_error(message, fun) do\n    assert capture_io(:stderr, fn ->\n             assert_raise CompileError, fun\n           end) =~ message\n  end\n\n  defp clean_meta(expr, vars) do\n    cleaner = &Keyword.drop(&1, vars)\n    Macro.prewalk(expr, &Macro.update_meta(&1, cleaner))\n  end\n\n  @bitstring_modifiers [\n    :integer,\n    :float,\n    :binary,\n    :utf8,\n    :utf16,\n    :utf32,\n    :native,\n    :signed,\n    :bitstring,\n    :little\n  ]\n\n  defp clean_bit_modifiers(expr) do\n    Macro.prewalk(expr, fn\n      {expr, meta, atom} when expr in @bitstring_modifiers and is_atom(atom) ->\n        {expr, meta, nil}\n\n      other ->\n        other\n    end)\n  end\n\n  defp expand(expr, extra_meta \\\\ [if_undefined: :apply]) do\n    add_meta = &Keyword.merge(&1, extra_meta)\n\n    expr\n    |> Macro.postwalk(&Macro.update_meta(&1, add_meta))\n    |> expand_env(__ENV__)\n    |> elem(0)\n  end\n\n  defp expand_env(expr, env, to_clean \\\\ [:version, :inferred_bitstring_spec, :if_undefined]) do\n    {{expr, scope, env}, _capture} =\n      with_io(:stderr, fn ->\n        :elixir_expand.expand(expr, :elixir_env.env_to_ex(env), env)\n      end)\n\n    env = :elixir_env.to_caller({env.line, scope, env})\n    {clean_meta(expr, to_clean), env}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/fn_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.FnTest do\n  use ExUnit.Case, async: true\n\n  test \"arithmetic constants on match\" do\n    assert (fn -1 -> true end).(-1)\n    assert (fn +1 -> true end).(1)\n  end\n\n  defp fun_match(x) do\n    fn\n      ^x -> true\n      _ -> false\n    end\n  end\n\n  test \"pin operator on match\" do\n    refute fun_match(1).(0)\n    assert fun_match(1).(1)\n    refute fun_match(1).(1.0)\n  end\n\n  test \"guards with no args\" do\n    fun = fn () when node() == :nonode@nohost -> true end\n    assert is_function(fun, 0)\n  end\n\n  test \"case function hoisting does not affect anonymous fns\" do\n    result =\n      if Process.get(:unused, false) do\n        user = :defined\n        user\n      else\n        (fn ->\n           user = :undefined\n           user\n         end).()\n      end\n\n    assert result == :undefined\n  end\n\n  test \"capture with access\" do\n    assert (& &1[:hello]).(hello: :world) == :world\n  end\n\n  test \"capture remote\" do\n    assert (&:erlang.atom_to_list/1).(:a) == ~c\"a\"\n    assert (&Atom.to_charlist/1).(:a) == ~c\"a\"\n\n    assert (&List.flatten/1).([[0]]) == [0]\n    assert (&List.flatten/1).([[0]]) == [0]\n    assert (&List.flatten(&1)).([[0]]) == [0]\n    assert (&List.flatten(&1)) == (&List.flatten/1)\n  end\n\n  test \"capture local\" do\n    assert (&atl/1).(:a) == ~c\"a\"\n    assert (&atl/1).(:a) == ~c\"a\"\n    assert (&atl(&1)).(:a) == ~c\"a\"\n  end\n\n  test \"capture local with question mark\" do\n    assert (&atom?/1).(:a)\n    assert (&atom?/1).(:a)\n    assert (&atom?(&1)).(:a)\n  end\n\n  test \"capture imported\" do\n    assert (&is_atom/1).(:a)\n    assert (&is_atom/1).(:a)\n    assert (&is_atom(&1)).(:a)\n    assert (&is_atom(&1)) == (&is_atom/1)\n  end\n\n  test \"capture macro\" do\n    assert (&to_string/1).(:a) == \"a\"\n    assert (&to_string(&1)).(:a) == \"a\"\n    assert (&Kernel.to_string/1).(:a) == \"a\"\n    assert (&Kernel.to_string(&1)).(:a) == \"a\"\n  end\n\n  test \"capture operator\" do\n    assert is_function(&+/2)\n    assert is_function(& &&/2)\n    assert is_function(&(&1 + &2), 2)\n    assert is_function(&and/2)\n  end\n\n  test \"capture with variable module\" do\n    mod = List\n    assert (&mod.flatten(&1)).([1, [2], 3]) == [1, 2, 3]\n    assert (&mod.flatten/1).([1, [2], 3]) == [1, 2, 3]\n    assert (&mod.flatten/1) == (&List.flatten/1)\n  end\n\n  test \"local partial application\" do\n    assert (&atb(&1, :utf8)).(:a) == \"a\"\n    assert (&atb(List.to_atom(&1), :utf8)).(~c\"a\") == \"a\"\n  end\n\n  test \"imported partial application\" do\n    import Record\n    assert (&is_record(&1, :sample)).({:sample, 1})\n  end\n\n  test \"remote partial application\" do\n    assert (&:erlang.binary_part(&1, 1, 2)).(\"foo\") == \"oo\"\n    assert (&:erlang.binary_part(Atom.to_string(&1), 1, 2)).(:foo) == \"oo\"\n  end\n\n  test \"capture and partially apply tuples\" do\n    assert (&{&1, &2}).(1, 2) == {1, 2}\n    assert (&{&1, &2, &3}).(1, 2, 3) == {1, 2, 3}\n\n    assert (&{1, &1}).(2) == {1, 2}\n    assert (&{1, &1, &2}).(2, 3) == {1, 2, 3}\n  end\n\n  test \"capture and partially apply lists\" do\n    assert (&[&1, &2]).(1, 2) == [1, 2]\n    assert (&[&1, &2, &3]).(1, 2, 3) == [1, 2, 3]\n\n    assert (&[1, &1]).(2) == [1, 2]\n    assert (&[1, &1, &2]).(2, 3) == [1, 2, 3]\n\n    assert (&[&1 | &2]).(1, 2) == [1 | 2]\n  end\n\n  test \"capture and partially apply on call\" do\n    assert (& &1.module).(__ENV__) == __MODULE__\n  end\n\n  test \"capture block like\" do\n    assert (&(!is_atom(&1))).(:foo) == false\n  end\n\n  test \"capture with function call\" do\n    assert (& &1).(:ok) == :ok\n\n    fun = fn a, b -> a + b end\n    assert (&fun.(&1, 2)).(1) == 3\n  end\n\n  defmacro c(x) do\n    quote do\n      &(unquote(x) <> &1)\n    end\n  end\n\n  test \"capture within capture through macro\" do\n    assert (&c(&1).(\"b\")).(\"a\") == \"ab\"\n  end\n\n  defp atom?(atom) when is_atom(atom), do: true\n  defp atom?(_), do: false\n\n  defp atl(arg) do\n    :erlang.atom_to_list(arg)\n  end\n\n  defp atb(arg, encoding) do\n    :erlang.atom_to_binary(arg, encoding)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/guard_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.GuardTest do\n  use ExUnit.Case, async: true\n\n  import ExUnit.CaptureIO\n\n  describe \"defguard(p) usage\" do\n    defmodule GuardsInMacros do\n      defguard is_foo(atom) when atom == :foo\n\n      defmacro is_compile_time_foo(atom) when is_foo(atom) do\n        quote do: unquote(__MODULE__).is_foo(unquote(atom))\n      end\n    end\n\n    test \"guards can be used in other macros in the same module\" do\n      require GuardsInMacros\n      assert GuardsInMacros.is_foo(:foo)\n      refute GuardsInMacros.is_foo(:baz)\n      assert GuardsInMacros.is_compile_time_foo(:foo)\n    end\n\n    defmodule GuardsInFuns do\n      defguard is_foo(atom) when atom == :foo\n      defguard is_equal(foo, bar) when foo == bar\n\n      def foo?(atom) when is_foo(atom) do\n        is_foo(atom)\n      end\n    end\n\n    test \"guards can be used in other funs in the same module\" do\n      require GuardsInFuns\n      assert GuardsInFuns.is_foo(:foo)\n      refute GuardsInFuns.is_foo(:bar)\n    end\n\n    test \"guards do not change code evaluation semantics\" do\n      require GuardsInFuns\n      x = 1\n      assert GuardsInFuns.is_equal(x = 2, x) == false\n      assert x == 2\n    end\n\n    defmodule MacrosInGuards do\n      defmacro is_foo(atom) do\n        quote do\n          unquote(atom) == :foo\n        end\n      end\n\n      defguard is_foobar(atom) when is_foo(atom) or atom == :bar\n    end\n\n    test \"macros can be used in other guards in the same module\" do\n      require MacrosInGuards\n      assert MacrosInGuards.is_foobar(:foo)\n      assert MacrosInGuards.is_foobar(:bar)\n      refute MacrosInGuards.is_foobar(:baz)\n    end\n\n    defmodule UnquotedInGuardCall do\n      @value :foo\n\n      defguard unquote(String.to_atom(\"is_#{@value}\"))(x) when x == unquote(@value)\n    end\n\n    test \"guards names can be defined dynamically using unquote\" do\n      require UnquotedInGuardCall\n      assert UnquotedInGuardCall.is_foo(:foo)\n      refute UnquotedInGuardCall.is_foo(:bar)\n    end\n\n    defmodule GuardsInGuards do\n      defguard is_foo(atom) when atom == :foo\n      defguard is_foobar(atom) when is_foo(atom) or atom == :bar\n    end\n\n    test \"guards can be used in other guards in the same module\" do\n      require GuardsInGuards\n      assert GuardsInGuards.is_foobar(:foo)\n      assert GuardsInGuards.is_foobar(:bar)\n      refute GuardsInGuards.is_foobar(:baz)\n    end\n\n    defmodule DefaultArgs do\n      defguard is_divisible(value, remainder \\\\ 2)\n               when is_integer(value) and rem(value, remainder) == 0\n    end\n\n    test \"permits default values in args\" do\n      require DefaultArgs\n      assert DefaultArgs.is_divisible(2)\n      refute DefaultArgs.is_divisible(1)\n      assert DefaultArgs.is_divisible(3, 3)\n      refute DefaultArgs.is_divisible(3, 4)\n    end\n\n    test \"doesn't allow matching in args\" do\n      assert_raise ArgumentError, ~r\"invalid syntax in defguard\", fn ->\n        defmodule Integer.Args do\n          defguard foo(value, 1) when is_integer(value)\n        end\n      end\n\n      assert_raise ArgumentError, ~r\"invalid syntax in defguard\", fn ->\n        defmodule String.Args do\n          defguard foo(value, \"string\") when is_integer(value)\n        end\n      end\n\n      assert_raise ArgumentError, ~r\"invalid syntax in defguard\", fn ->\n        defmodule Atom.Args do\n          defguard foo(value, :atom) when is_integer(value)\n        end\n      end\n\n      assert_raise ArgumentError, ~r\"invalid syntax in defguard\", fn ->\n        defmodule Tuple.Args do\n          defguard foo(value, {foo, bar}) when is_integer(value)\n        end\n      end\n    end\n\n    defmodule GuardFromMacro do\n      defmacro __using__(_) do\n        quote do\n          defguard is_even(value) when is_integer(value) and rem(value, 2) == 0\n        end\n      end\n    end\n\n    test \"defguard defines a guard from inside another macro\" do\n      defmodule UseGuardFromMacro do\n        use GuardFromMacro\n\n        def assert! do\n          assert is_even(0)\n          refute is_even(1)\n        end\n      end\n\n      UseGuardFromMacro.assert!()\n    end\n\n    defmodule IntegerPrivateGuards do\n      defguardp is_even(value) when is_integer(value) and rem(value, 2) == 0\n\n      def even_and_large?(value) when is_even(value) and value > 100, do: true\n      def even_and_large?(_), do: false\n\n      def even_and_small?(value) do\n        if is_even(value) and value <= 100, do: true, else: false\n      end\n    end\n\n    test \"defguardp defines private guards that work inside and outside guard clauses\" do\n      assert IntegerPrivateGuards.even_and_large?(102)\n      refute IntegerPrivateGuards.even_and_large?(98)\n      refute IntegerPrivateGuards.even_and_large?(99)\n      refute IntegerPrivateGuards.even_and_large?(103)\n\n      assert IntegerPrivateGuards.even_and_small?(98)\n      refute IntegerPrivateGuards.even_and_small?(99)\n      refute IntegerPrivateGuards.even_and_small?(102)\n      refute IntegerPrivateGuards.even_and_small?(103)\n\n      assert_compile_error(~r\"cannot find or invoke local is_even/1\", fn ->\n        defmodule IntegerPrivateGuardUtils do\n          import IntegerPrivateGuards\n\n          def even_and_large?(value) when is_even(value) and value > 100, do: true\n          def even_and_large?(_), do: false\n        end\n      end)\n\n      assert_compile_error(~r\"undefined function is_even/1\", fn ->\n        defmodule IntegerPrivateFunctionUtils do\n          import IntegerPrivateGuards\n\n          def even_and_small?(value) do\n            if is_even(value) and value <= 100, do: true, else: false\n          end\n        end\n      end)\n    end\n\n    test \"requires a proper macro name\" do\n      assert_raise ArgumentError, ~r\"invalid syntax in defguard\", fn ->\n        defmodule(LiteralUsage, do: defguard(\"literal is bad\"))\n      end\n\n      assert_raise ArgumentError, ~r\"invalid syntax in defguard\", fn ->\n        defmodule(RemoteUsage, do: defguard(Remote.call(is_bad)))\n      end\n    end\n\n    test \"handles overriding appropriately\" do\n      assert_compile_error(~r\"defmacro (.*?) already defined as def\", fn ->\n        defmodule OverriddenFunUsage do\n          def foo(bar), do: bar\n          defguard foo(bar) when bar\n        end\n      end)\n\n      assert_compile_error(~r\"defmacro (.*?) already defined as defp\", fn ->\n        defmodule OverriddenPrivateFunUsage do\n          defp foo(bar), do: bar\n          defguard foo(bar) when bar\n        end\n      end)\n\n      assert_compile_error(~r\"defmacro (.*?) already defined as defmacrop\", fn ->\n        defmodule OverriddenPrivateFunUsage do\n          defmacrop foo(bar), do: bar\n          defguard foo(bar) when bar\n        end\n      end)\n\n      assert_compile_error(~r\"defmacrop (.*?) already defined as def\", fn ->\n        defmodule OverriddenFunUsage do\n          def foo(bar), do: bar\n          defguardp foo(bar) when bar\n        end\n      end)\n\n      assert_compile_error(~r\"defmacrop (.*?) already defined as defp\", fn ->\n        defmodule OverriddenPrivateFunUsage do\n          defp foo(bar), do: bar\n          defguardp foo(bar) when bar\n        end\n      end)\n\n      assert_compile_error(~r\"defmacrop (.*?) already defined as defmacro\", fn ->\n        defmodule OverriddenPrivateFunUsage do\n          defmacro foo(bar), do: bar\n          defguardp foo(bar) when bar\n        end\n      end)\n    end\n\n    test \"does not allow multiple guard clauses\" do\n      assert_raise ArgumentError, ~r\"invalid syntax in defguard\", fn ->\n        defmodule MultiGuardUsage do\n          defguardp foo(bar, baz) when bar == 1 when baz == 2\n        end\n      end\n    end\n\n    test \"does not accept a block\" do\n      assert_compile_error(~r\"undefined function defguard/2\", fn ->\n        defmodule OnelinerBlockUsage do\n          defguard(foo(bar), do: one_liner)\n        end\n      end)\n\n      assert_compile_error(~r\"undefined function defguard/2\", fn ->\n        defmodule MultilineBlockUsage do\n          defguard foo(bar) do\n            multi\n            liner\n          end\n        end\n      end)\n\n      assert_compile_error(~r\"undefined function defguard/2\", fn ->\n        defmodule ImplAndBlockUsage do\n          defguard(foo(bar) when both_given, do: error)\n        end\n      end)\n    end\n  end\n\n  describe \"defguard(p) compilation\" do\n    test \"refuses to compile nonsensical code\" do\n      assert_compile_error(\"cannot find or invoke local undefined/1\", fn ->\n        defmodule UndefinedUsage do\n          defguard foo(function) when undefined(function)\n        end\n      end)\n    end\n\n    test \"fails on expressions not allowed in guards\" do\n      # Slightly unique errors\n\n      assert_raise ArgumentError, ~r{invalid right argument for operator \"in\"}, fn ->\n        defmodule RuntimeListUsage do\n          defguard foo(bar, baz) when bar in baz\n        end\n      end\n\n      assert_compile_error(\"cannot invoke remote function\", fn ->\n        defmodule BadErlangFunctionUsage do\n          defguard foo(bar) when :erlang.binary_to_atom(\"foo\")\n        end\n      end)\n\n      assert_compile_error(\"cannot invoke remote function\", fn ->\n        defmodule SendUsage do\n          defguard foo(bar) when send(self(), :baz)\n        end\n      end)\n\n      # Consistent errors\n\n      assert_raise ArgumentError, ~r\"invalid expression in guard, ! is not allowed\", fn ->\n        defmodule SoftNegationLogicUsage do\n          defguard foo(logic) when !logic\n        end\n      end\n\n      assert_raise ArgumentError, ~r\"invalid expression in guard, && is not allowed\", fn ->\n        defmodule SoftAndLogicUsage do\n          defguard foo(soft, logic) when soft && logic\n        end\n      end\n\n      assert_raise ArgumentError, ~r\"invalid expression in guard, || is not allowed\", fn ->\n        defmodule SoftOrLogicUsage do\n          defguard foo(soft, logic) when soft || logic\n        end\n      end\n\n      assert_compile_error(\n        \"cannot invoke remote function :erlang\\.is_record/2 inside a guard\",\n        fn ->\n          defmodule IsRecord2Usage do\n            defguard foo(rec) when :erlang.is_record(rec, :tag)\n          end\n        end\n      )\n\n      assert_compile_error(\n        \"cannot invoke remote function :erlang\\.is_record/3 inside a guard\",\n        fn ->\n          defmodule IsRecord3Usage do\n            defguard foo(rec) when :erlang.is_record(rec, :tag, 7)\n          end\n        end\n      )\n\n      assert_compile_error(\n        ~r\"cannot invoke remote function :erlang\\.\\+\\+/2 inside a guard\",\n        fn ->\n          defmodule ListSubtractionUsage do\n            defguard foo(list) when list ++ []\n          end\n        end\n      )\n\n      assert_compile_error(\n        \"cannot invoke remote function :erlang\\.\\-\\-/2 inside a guard\",\n        fn ->\n          defmodule ListSubtractionUsage do\n            defguard foo(list) when list -- []\n          end\n        end\n      )\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule LocalCallUsage do\n          defguard foo(local, call) when local.(call)\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule ComprehensionUsage do\n          defguard foo(bar) when for(x <- [1, 2, 3], do: x * bar)\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule AliasUsage do\n          defguard foo(bar) when alias(bar)\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule ImportUsage do\n          defguard foo(bar) when import(bar)\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule RequireUsage do\n          defguard foo(bar) when require(bar)\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule SuperUsage do\n          defguard foo(bar) when super(bar)\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule SpawnUsage do\n          defguard foo(bar) when spawn(& &1)\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule ReceiveUsage do\n          defguard foo(bar) when receive(do: (baz -> baz))\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule CaseUsage do\n          defguard foo(bar) when case(bar, do: (baz -> :baz))\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule CondUsage do\n          defguard foo(bar) when cond(do: (bar -> :baz))\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule TryUsage do\n          defguard foo(bar) when try(do: (baz -> baz))\n        end\n      end)\n\n      assert_compile_error(\"invalid expression in guard\", fn ->\n        defmodule WithUsage do\n          defguard foo(bar) when with(do: (baz -> baz))\n        end\n      end)\n\n      assert_compile_error(\n        \"cannot invoke remote function inside a guard. \" <>\n          \"If you want to do a map lookup instead, please remove parens from map.field()\",\n        fn ->\n          defmodule MapDot do\n            def map_dot(map) when map.field(), do: true\n          end\n        end\n      )\n\n      assert_compile_error(\"cannot invoke remote function Module.fun/0 inside a guard\", fn ->\n        defmodule MapDot do\n          def map_dot(map) when Module.fun(), do: true\n        end\n      end)\n    end\n  end\n\n  describe \"defguard(p) expansion\" do\n    defguard with_unused_vars(foo, bar, _baz) when foo + bar\n\n    test \"doesn't obscure unused variables\" do\n      args = quote(do: [1 + 1, 2 + 2, 3 + 3])\n\n      assert expand_defguard_to_string(:with_unused_vars, args, :guard) == \"\"\"\n             :erlang.+(1 + 1, 2 + 2)\n             \"\"\"\n\n      assert expand_defguard_to_string(:with_unused_vars, args, nil) == \"\"\"\n             {arg1, arg2} = {1 + 1, 2 + 2}\n             :erlang.+(arg1, arg2)\n             \"\"\"\n    end\n\n    defguard with_reused_vars(foo, bar, baz) when foo + foo + bar + baz\n\n    test \"handles re-used variables\" do\n      args = quote(do: [1 + 1, 2 + 2, 3 + 3])\n\n      assert expand_defguard_to_string(:with_reused_vars, args, :guard) == \"\"\"\n             :erlang.+(:erlang.+(:erlang.+(1 + 1, 1 + 1), 2 + 2), 3 + 3)\n             \"\"\"\n\n      assert expand_defguard_to_string(:with_reused_vars, args, nil) == \"\"\"\n             {arg1, arg2, arg3} = {1 + 1, 2 + 2, 3 + 3}\n             :erlang.+(:erlang.+(:erlang.+(arg1, arg1), arg2), arg3)\n             \"\"\"\n    end\n\n    defguard in_list(a) when Kernel.in(a, [:test])\n\n    test \"expands remote functions\" do\n      assert expand_defguard_to_string(:in_list, [:not_test], :guard) == \"\"\"\n             :erlang.\\\"=:=\\\"(:not_test, :test)\n             \"\"\"\n    end\n\n    defp expand_defguard_to_string(fun, args, context) do\n      {{:., [], [__MODULE__, fun]}, [], args}\n      |> Macro.expand(%{__ENV__ | context: context})\n      |> Macro.to_string()\n      |> Kernel.<>(\"\\n\")\n    end\n  end\n\n  defp assert_compile_error(message, fun) do\n    assert capture_io(:stderr, fn ->\n             assert_raise CompileError, fun\n           end) =~ message\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/impl_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.ImplTest do\n  use ExUnit.Case, async: true\n\n  defp capture_err(fun) do\n    ExUnit.CaptureIO.capture_io(:stderr, fun)\n  end\n\n  defp purge(module) do\n    :code.purge(module)\n    :code.delete(module)\n  end\n\n  setup do\n    on_exit(fn -> purge(Kernel.ImplTest.ImplAttributes) end)\n  end\n\n  defprotocol AProtocol do\n    def foo(term)\n    def bar(term)\n  end\n\n  defmodule Behaviour do\n    @callback foo() :: any\n  end\n\n  defmodule BehaviourWithArgument do\n    @callback foo(any) :: any\n  end\n\n  defmodule BehaviourWithThreeArguments do\n    @callback foo(any, any, any) :: any\n  end\n\n  defmodule UseBehaviourWithoutImpl do\n    @callback foo_without_impl() :: any\n    @callback bar_without_impl() :: any\n    @callback baz_without_impl() :: any\n\n    defmacro __using__(_opts) do\n      quote do\n        @behaviour Kernel.ImplTest.UseBehaviourWithoutImpl\n        def foo_without_impl(), do: :auto_generated\n      end\n    end\n  end\n\n  defmodule UseBehaviourWithImpl do\n    @callback foo_with_impl() :: any\n    @callback bar_with_impl() :: any\n    @callback baz_with_impl() :: any\n\n    defmacro __using__(_opts) do\n      quote do\n        @behaviour Kernel.ImplTest.UseBehaviourWithImpl\n        @impl true\n        def foo_with_impl(), do: :auto_generated\n        def bar_with_impl(), do: :auto_generated\n      end\n    end\n  end\n\n  defmodule MacroBehaviour do\n    @macrocallback bar :: any\n  end\n\n  defmodule ManualBehaviour do\n    def behaviour_info(:callbacks), do: [foo: 0]\n    def behaviour_info(:optional_callbacks), do: :undefined\n  end\n\n  test \"sets @impl to boolean\" do\n    defmodule ImplAttributes do\n      @behaviour Behaviour\n\n      @impl true\n      def foo(), do: :ok\n\n      @impl false\n      def foo(term) do\n        term\n      end\n    end\n  end\n\n  test \"sets @impl to nil\" do\n    assert_raise ArgumentError, ~r/should be a module or a boolean/, fn ->\n      defmodule ImplAttributes do\n        @behaviour Behaviour\n        @impl nil\n        def foo(), do: :ok\n      end\n    end\n  end\n\n  test \"sets @impl to behaviour\" do\n    defmodule ImplAttributes do\n      @behaviour Behaviour\n      @impl Behaviour\n      def foo(), do: :ok\n    end\n  end\n\n  test \"does not set @impl\" do\n    defmodule ImplAttributes do\n      @behaviour Behaviour\n      def foo(), do: :ok\n    end\n  end\n\n  test \"sets @impl to boolean on manual behaviour\" do\n    defmodule ImplAttributes do\n      @behaviour ManualBehaviour\n\n      @impl true\n      def foo(), do: :ok\n    end\n  end\n\n  test \"warns of undefined module, but does not warn at @impl line\" do\n    capture_err =\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n        defmodule Kernel.ImplTest.ImplAttributes do\n          @behaviour Abc\n\n          @impl Abc\n          def foo(), do: :ok\n        end\n        \"\"\")\n      end)\n\n    assert capture_err =~\n             \"@behaviour Abc does not exist (in module Kernel.ImplTest.ImplAttributes)\"\n\n    refute capture_err =~\n             \"got \\\"@impl Abc\\\"\"\n  end\n\n  test \"warns of undefined behaviour, but does not warn at @impl line\" do\n    capture_err =\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n        defmodule Kernel.ImplTest.ImplAttributes do\n          @behaviour Enum\n\n          @impl Enum\n          def foo(), do: :ok\n        end\n        \"\"\")\n      end)\n\n    assert capture_err =~\n             \"module Enum is not a behaviour (in module Kernel.ImplTest.ImplAttributes)\"\n\n    refute capture_err =~\n             \"got \\\"@impl Abc\\\"\"\n  end\n\n  test \"warns of callbacks without impl and @impl has been set before\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @behaviour Kernel.ImplTest.MacroBehaviour\n\n               @impl true\n               def foo(), do: :ok\n\n               defmacro bar(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"module attribute @impl was not set for macro bar/0 callback (specified in Kernel.ImplTest.MacroBehaviour)\"\n  end\n\n  test \"warns of callbacks without impl and @impl has been set after\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @behaviour Kernel.ImplTest.MacroBehaviour\n\n               defmacro bar(), do: :ok\n\n               @impl true\n               def foo(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"module attribute @impl was not set for macro bar/0 callback (specified in Kernel.ImplTest.MacroBehaviour)\"\n  end\n\n  test \"warns when @impl is set on private function\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @impl true\n               defp foo(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"function foo/0 is private, @impl attribute is always discarded for private functions/macros\"\n  end\n\n  test \"warns when @impl is set and no function\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @impl true\n             end\n             \"\"\")\n           end) =~ \"module attribute @impl was set but no definition follows it\"\n  end\n\n  test \"warns of @impl true and no behaviour\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @impl true\n               def foo(), do: :ok\n             end\n             \"\"\")\n           end) =~ \"got \\\"@impl true\\\" for function foo/0 but no behaviour was declared\"\n  end\n\n  test \"warns of @impl true with callback name not in behaviour\" do\n    message =\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n        defmodule Kernel.ImplTest.ImplAttributes do\n          @behaviour Kernel.ImplTest.Behaviour\n          @impl true\n          def bar(), do: :ok\n        end\n        \"\"\")\n      end)\n\n    assert message =~\n             \"got \\\"@impl true\\\" for function bar/0 but no behaviour specifies such callback\"\n\n    assert message =~ \"The known callbacks are\"\n    assert message =~ \"* Kernel.ImplTest.Behaviour.foo/0 (function)\"\n  end\n\n  test \"warns of @impl true with macro callback name not in behaviour\" do\n    message =\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n        defmodule Kernel.ImplTest.ImplAttributes do\n          @behaviour Kernel.ImplTest.MacroBehaviour\n          @impl true\n          defmacro foo(), do: :ok\n        end\n        \"\"\")\n      end)\n\n    assert message =~\n             \"got \\\"@impl true\\\" for macro foo/0 but no behaviour specifies such callback\"\n\n    assert message =~ \"The known callbacks are\"\n    assert message =~ \"* Kernel.ImplTest.MacroBehaviour.bar/0 (macro)\"\n  end\n\n  test \"warns of @impl true with callback kind not in behaviour\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.MacroBehaviour\n               @impl true\n               def foo(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl true\\\" for function foo/0 but no behaviour specifies such callback\"\n  end\n\n  test \"warns of @impl true with wrong arity\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @impl true\n               def foo(arg), do: arg\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl true\\\" for function foo/1 but no behaviour specifies such callback\"\n  end\n\n  test \"warns of @impl false and there are no callbacks\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @impl false\n               def baz(term), do: term\n             end\n             \"\"\")\n           end) =~ \"got \\\"@impl false\\\" for function baz/1 but no behaviour was declared\"\n  end\n\n  test \"warns of @impl false and it is a callback\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @impl false\n               def foo(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl false\\\" for function foo/0 but it is a callback specified in Kernel.ImplTest.Behaviour\"\n  end\n\n  test \"warns of @impl module and no behaviour\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @impl Kernel.ImplTest.Behaviour\n               def foo(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl Kernel.ImplTest.Behaviour\\\" for function foo/0 but no behaviour was declared\"\n  end\n\n  test \"warns of @impl module with callback name not in behaviour\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @impl Kernel.ImplTest.Behaviour\n               def bar(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl Kernel.ImplTest.Behaviour\\\" for function bar/0 but Kernel.ImplTest.Behaviour does not specify such callback\"\n  end\n\n  test \"warns of @impl module with macro callback name not in behaviour\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.MacroBehaviour\n               @impl Kernel.ImplTest.MacroBehaviour\n               defmacro foo(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl Kernel.ImplTest.MacroBehaviour\\\" for macro foo/0 but Kernel.ImplTest.MacroBehaviour does not specify such callback\"\n  end\n\n  test \"warns of @impl module with macro callback kind not in behaviour\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.MacroBehaviour\n               @impl Kernel.ImplTest.MacroBehaviour\n               def foo(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl Kernel.ImplTest.MacroBehaviour\\\" for function foo/0 but Kernel.ImplTest.MacroBehaviour does not specify such callback\"\n  end\n\n  test \"warns of @impl module and callback belongs to another known module\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @behaviour Kernel.ImplTest.MacroBehaviour\n               @impl Kernel.ImplTest.Behaviour\n               def bar(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl Kernel.ImplTest.Behaviour\\\" for function bar/0 but Kernel.ImplTest.Behaviour does not specify such callback\"\n  end\n\n  test \"warns of @impl module and callback belongs to another unknown module\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @impl Kernel.ImplTest.MacroBehaviour\n               def bar(), do: :ok\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl Kernel.ImplTest.MacroBehaviour\\\" for function bar/0 but this behaviour was not declared with @behaviour\"\n  end\n\n  test \"does not warn of @impl when the function with default conforms with several typespecs\" do\n    Code.eval_string(~S\"\"\"\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @behaviour Kernel.ImplTest.Behaviour\n      @behaviour Kernel.ImplTest.BehaviourWithArgument\n\n      @impl true\n      def foo(args \\\\ []), do: args\n    end\n    \"\"\")\n  end\n\n  test \"does not warn of @impl when the function conforms to behaviour but has default value for arg\" do\n    Code.eval_string(~S\"\"\"\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @behaviour Kernel.ImplTest.BehaviourWithArgument\n\n      @impl true\n      def foo(args \\\\ []), do: args\n    end\n    \"\"\")\n  end\n\n  test \"does not warn of @impl when the function conforms to behaviour but has additional trailing default args\" do\n    Code.eval_string(~S\"\"\"\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @behaviour Kernel.ImplTest.BehaviourWithArgument\n\n      @impl true\n      def foo(arg_1, _args \\\\ []), do: arg_1\n    end\n    \"\"\")\n  end\n\n  test \"does not warn of @impl when the function conforms to behaviour but has additional leading default args\" do\n    Code.eval_string(~S\"\"\"\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @behaviour Kernel.ImplTest.BehaviourWithArgument\n\n      @impl true\n      def foo(_defaulted_arg \\\\ [], args), do: args\n    end\n    \"\"\")\n  end\n\n  test \"does not warn of @impl when the function has more args than callback, but they're all defaulted\" do\n    Code.eval_string(~S\"\"\"\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @behaviour Kernel.ImplTest.BehaviourWithArgument\n\n      @impl true\n      def foo(args \\\\ [], _bar \\\\ []), do: args\n    end\n    \"\"\")\n  end\n\n  test \"does not warn of @impl with defaults when the same function is defined multiple times\" do\n    Code.eval_string(~S\"\"\"\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @behaviour Kernel.ImplTest.BehaviourWithArgument\n      @behaviour Kernel.ImplTest.BehaviourWithThreeArguments\n\n      @impl Kernel.ImplTest.BehaviourWithArgument\n      def foo(_foo \\\\ [], _bar \\\\ []), do: :ok\n\n      @impl Kernel.ImplTest.BehaviourWithThreeArguments\n      def foo(_foo, _bar, _baz, _qux \\\\ []), do: :ok\n    end\n    \"\"\")\n  end\n\n  test \"does not warn of no @impl when overriding callback\" do\n    Code.eval_string(~S\"\"\"\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @behaviour Kernel.ImplTest.Behaviour\n\n      def foo(), do: :overridable\n\n      defoverridable Kernel.ImplTest.Behaviour\n\n      def foo(), do: :overridden\n    end\n    \"\"\")\n  end\n\n  test \"does not warn of overridable function missing @impl\" do\n    Code.eval_string(~S\"\"\"\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @behaviour Kernel.ImplTest.Behaviour\n\n      def foo(), do: :overridable\n\n      defoverridable Kernel.ImplTest.Behaviour\n\n      @impl Kernel.ImplTest.Behaviour\n      def foo(), do: :overridden\n    end\n    \"\"\")\n  end\n\n  test \"warns correctly of missing @impl only for end-user implemented function\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @behaviour Kernel.ImplTest.MacroBehaviour\n\n               def foo(), do: :overridable\n\n               defoverridable Kernel.ImplTest.Behaviour\n\n               def foo(), do: :overridden\n\n               @impl true\n               defmacro bar(), do: :overridden\n             end\n             \"\"\")\n           end) =~\n             \"module attribute @impl was not set for function foo/0 callback (specified in Kernel.ImplTest.Behaviour)\"\n  end\n\n  test \"warns correctly of incorrect @impl in overridable callback\" do\n    assert capture_err(fn ->\n             Code.eval_string(\"\"\"\n             defmodule Kernel.ImplTest.ImplAttributes do\n               @behaviour Kernel.ImplTest.Behaviour\n               @behaviour Kernel.ImplTest.MacroBehaviour\n\n               @impl Kernel.ImplTest.MacroBehaviour\n               def foo(), do: :overridable\n\n               defoverridable Kernel.ImplTest.Behaviour\n\n               @impl Kernel.ImplTest.Behaviour\n               def foo(), do: :overridden\n             end\n             \"\"\")\n           end) =~\n             \"got \\\"@impl Kernel.ImplTest.MacroBehaviour\\\" for function foo/0 but Kernel.ImplTest.MacroBehaviour does not specify such callback\"\n  end\n\n  test \"warns only of non-generated functions in non-generated @impl\" do\n    message =\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n        defmodule Kernel.ImplTest.ImplAttributes do\n          @behaviour Kernel.ImplTest.Behaviour\n          use Kernel.ImplTest.UseBehaviourWithoutImpl\n\n          @impl true\n          def bar_without_impl(), do: :overridden\n          def baz_without_impl(), do: :overridden\n\n          defdelegate foo(), to: __MODULE__, as: :baz\n          def baz(), do: :ok\n        end\n        \"\"\")\n      end)\n\n    assert message =~\n             \"module attribute @impl was not set for function baz_without_impl/0 callback\"\n\n    assert message =~\n             \"module attribute @impl was not set for function foo/0 callback\"\n\n    refute message =~ \"foo_without_impl/0\"\n  end\n\n  test \"warns only of non-generated functions in non-generated @impl in protocols\" do\n    message =\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n        defimpl  Kernel.ImplTest.AProtocol, for: List do\n          @impl true\n          def foo(_list), do: :ok\n\n          defdelegate bar(list), to: __MODULE__, as: :baz\n          def baz(_list), do: :ok\n        end\n        \"\"\")\n      end)\n\n    assert message =~\n             \"module attribute @impl was not set for function bar/1 callback\"\n  end\n\n  test \"warns only of generated functions in generated @impl\" do\n    message =\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n        defmodule Kernel.ImplTest.ImplAttributes do\n          use Kernel.ImplTest.UseBehaviourWithImpl\n          def baz_with_impl(), do: :overridden\n        end\n        \"\"\")\n      end)\n\n    assert message =~ \"module attribute @impl was not set for function bar_with_impl/0 callback\"\n    refute message =~ \"foo_with_impl/0\"\n  end\n\n  test \"does not warn of overridable callback when using __before_compile__/1 hook\" do\n    Code.eval_string(~S\"\"\"\n    defmodule BeforeCompile do\n      defmacro __before_compile__(_) do\n        quote do\n          @behaviour Kernel.ImplTest.Behaviour\n\n          def foo(), do: :overridable\n\n          defoverridable Kernel.ImplTest.Behaviour\n        end\n      end\n    end\n\n    defmodule Kernel.ImplTest.ImplAttributes do\n      @before_compile BeforeCompile\n      @behaviour Kernel.ImplTest.MacroBehaviour\n\n      defmacro bar(), do: :overridable\n\n      defoverridable Kernel.ImplTest.MacroBehaviour\n\n      @impl Kernel.ImplTest.MacroBehaviour\n      defmacro bar(), do: :overridden\n    end\n    \"\"\")\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/import_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.ImportTest do\n  use ExUnit.Case, async: true\n\n  # This should not warn due to the empty only\n  import URI, only: []\n\n  defmodule ImportAvailable do\n    defmacro flatten do\n      [flatten: 1]\n    end\n  end\n\n  test \"multi-call\" do\n    assert [List, String] = import(Elixir.{List, unquote(:String)})\n    assert keymember?([a: 1], :a, 0)\n    assert valid?(\"ø\")\n  end\n\n  test \"blank multi-call\" do\n    assert [] = import(List.{})\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  test \"multi-call with options\" do\n    assert [List] = import(Elixir.{List}, only: [])\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  test \"import all\" do\n    assert :lists = import(:lists)\n    assert flatten([1, [2], 3]) == [1, 2, 3]\n  end\n\n  test \"import except none\" do\n    import :lists, except: []\n    assert flatten([1, [2], 3]) == [1, 2, 3]\n  end\n\n  test \"import except one\" do\n    import :lists, except: [duplicate: 2]\n    assert flatten([1, [2], 3]) == [1, 2, 3]\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  test \"import only via macro\" do\n    require ImportAvailable\n    import :lists, only: ImportAvailable.flatten()\n    assert flatten([1, [2], 3]) == [1, 2, 3]\n  end\n\n  defmacrop dynamic_opts do\n    [only: [flatten: 1]]\n  end\n\n  test \"import with options via macro\" do\n    import :lists, dynamic_opts()\n    assert flatten([1, [2], 3]) == [1, 2, 3]\n  end\n\n  test \"import with double except\" do\n    import :lists, except: [duplicate: 2]\n    import :lists, except: [each: 2]\n    assert append([1], [2, 3]) == [1, 2, 3]\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  test \"import except none respects previous import with except\" do\n    import :lists, except: [duplicate: 2]\n    import :lists, except: []\n    assert append([1], [2, 3]) == [1, 2, 3]\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  test \"import except none respects previous import with only\" do\n    import :lists, only: [append: 2]\n    import :lists, except: []\n    assert append([1], [2, 3]) == [1, 2, 3]\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  defmodule Underscored do\n    def hello(x), do: x\n    def __underscore__(x), do: x\n  end\n\n  defmodule ExplicitUnderscored do\n    def __underscore__(x), do: x * 2\n  end\n\n  test \"import only with underscore\" do\n    import Underscored, only: [__underscore__: 1]\n    assert __underscore__(3) == 3\n  end\n\n  test \"import non-underscored\" do\n    import ExplicitUnderscored, only: [__underscore__: 1]\n    import Underscored\n    assert hello(2) == 2\n    assert __underscore__(3) == 6\n  end\n\n  defmodule MessedBitwise do\n    defmacro bnot(x), do: x\n    defmacro bor(x, _), do: x\n  end\n\n  import Bitwise, only: :functions\n\n  test \"conflicting imports with only and except\" do\n    import Bitwise, only: :functions, except: [bnot: 1]\n    import MessedBitwise, only: [bnot: 1]\n    assert bnot(0) == 0\n    assert bor(0, 1) == 1\n  end\n\n  # This test is asserting that the imports in the\n  # test above do not affect this test.\n  test \"imports from other functions do not leak\" do\n    assert band(1, 1) == 1\n    assert bor(0, 1) == 1\n    assert bnot(0) == -1\n  end\n\n  test \"import ambiguous\" do\n    # Simply make sure that we can indeed import functions with\n    # the same name and arity from different modules without the\n    # import itself causing any errors.\n    import List\n    import String\n  end\n\n  test \"import many\" do\n    [import(List), import(String)]\n    assert capitalize(\"foo\") == \"Foo\"\n    assert flatten([1, [2], 3]) == [1, 2, 3]\n  end\n\n  test \"does not import *_info in Erlang\" do\n    import :gen_server, warn: false\n    assert Macro.Env.lookup_import(__ENV__, {:module_info, 1}) == []\n    assert Macro.Env.lookup_import(__ENV__, {:behaviour_info, 1}) == []\n  end\n\n  test \"does not import *_info in Elixir\" do\n    import GenServer, warn: false\n    assert Macro.Env.lookup_import(__ENV__, {:module_info, 1}) == []\n    assert Macro.Env.lookup_import(__ENV__, {:behaviour_info, 1}) == []\n  end\n\n  defmodule ModuleWithSigils do\n    def sigil_i(string, []), do: String.to_integer(string)\n\n    defmacro sigil_I(string, []) do\n      quote do\n        String.to_integer(unquote(string))\n      end\n    end\n\n    defmacro sigil_III(string, []) do\n      quote do\n        3 * String.to_integer(unquote(string))\n      end\n    end\n\n    def sigil_w(_string, []), do: []\n\n    def bnot(x), do: x\n    defmacro bor(x, _), do: x\n  end\n\n  test \"import only sigils\" do\n    import Kernel, except: [sigil_w: 2]\n    import ModuleWithSigils, only: :sigils\n\n    # Ensure that both function and macro sigils are imported\n    assert ~i'10' == 10\n    assert ~I'10' == 10\n    assert ~III'10' == 30\n    assert ~w(abc def) == []\n\n    # Ensure that non-sigil functions and macros from ModuleWithSigils were not loaded\n    assert bnot(0) == -1\n    assert bor(0, 1) == 1\n  end\n\n  test \"import only sigils with except\" do\n    import ModuleWithSigils, only: :sigils, except: [sigil_w: 2]\n\n    assert ~i'10' == 10\n    assert ~I'10' == 10\n    assert ~III'10' == 30\n    assert ~w(abc def) == [\"abc\", \"def\"]\n  end\n\n  test \"import only removes the non-import part\" do\n    import List\n    import List, only: :macros\n    # Buggy local duplicate is used because we asked only for macros\n    assert duplicate([1], 2) == [1]\n  end\n\n  test \"import lexical on if\" do\n    if false do\n      import List\n      flatten([1, [2], 3])\n      flunk()\n    else\n      # Buggy local duplicate is untouched\n      assert duplicate([1], 2) == [1]\n    end\n  end\n\n  test \"import lexical on case\" do\n    case Process.get(:unused, true) do\n      false ->\n        import List\n        flatten([1, [2], 3])\n        flunk()\n\n      true ->\n        # Buggy local duplicate is untouched\n        assert duplicate([1], 2) == [1]\n    end\n  end\n\n  test \"import lexical on for\" do\n    for x <- [1, 2, 3], x > 10 do\n      import List\n      flatten([1, [2], 3])\n      flunk()\n    end\n\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  test \"import lexical on with\" do\n    with [_ | _] <- List.flatten([]) do\n      import List\n      flatten([1, [2], 3])\n      flunk()\n    end\n\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  test \"import lexical on try\" do\n    try do\n      import List\n      flatten([1, [2], 3])\n      flunk()\n    catch\n      _, _ ->\n        # Buggy local duplicate is untouched\n        assert duplicate([1], 2) == [1]\n    end\n\n    # Buggy local duplicate is untouched\n    assert duplicate([1], 2) == [1]\n  end\n\n  defp duplicate(list, _), do: list\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/lexical_tracker_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.LexicalTrackerTest do\n  use ExUnit.Case, async: true\n\n  alias Kernel.LexicalTracker, as: D\n  defstruct used_by_tests: :ok\n\n  setup do\n    {:ok, pid} = D.start_link()\n    {:ok, [pid: pid]}\n  end\n\n  test \"can add remote dispatch\", config do\n    D.remote_dispatch(config[:pid], String, :runtime)\n    assert D.references(config[:pid]) == {[], [], [String], []}\n\n    D.remote_dispatch(config[:pid], String, :compile)\n    assert D.references(config[:pid]) == {[String], [], [], []}\n\n    D.remote_dispatch(config[:pid], String, :runtime)\n    assert D.references(config[:pid]) == {[String], [], [], []}\n  end\n\n  test \"can add requires\", config do\n    D.add_export(config[:pid], URI)\n    assert D.references(config[:pid]) == {[], [URI], [], []}\n\n    D.remote_dispatch(config[:pid], URI, :runtime)\n    assert D.references(config[:pid]) == {[], [URI], [URI], []}\n\n    D.remote_dispatch(config[:pid], URI, :compile)\n    assert D.references(config[:pid]) == {[URI], [URI], [], []}\n  end\n\n  test \"can add module imports\", config do\n    D.add_export(config[:pid], String)\n    D.add_import(config[:pid], String, [], 1, true)\n\n    D.import_dispatch(config[:pid], String, {:upcase, 1}, :runtime)\n    assert D.references(config[:pid]) == {[], [String], [String], []}\n\n    D.import_dispatch(config[:pid], String, {:upcase, 1}, :compile)\n    assert D.references(config[:pid]) == {[String], [String], [], []}\n  end\n\n  test \"can add module with {function, arity} imports\", config do\n    D.add_export(config[:pid], String)\n    D.add_import(config[:pid], String, [upcase: 1], 1, true)\n\n    D.import_dispatch(config[:pid], String, {:upcase, 1}, :compile)\n    assert D.references(config[:pid]) == {[String], [String], [], []}\n  end\n\n  test \"can add aliases\", config do\n    D.alias_dispatch(config[:pid], String)\n    assert D.references(config[:pid]) == {[], [], [], []}\n  end\n\n  test \"unused module imports\", config do\n    D.add_import(config[:pid], String, [], 1, true)\n    assert D.collect_unused_imports(config[:pid]) == [{String, %{String => 1}}]\n  end\n\n  test \"used module imports are not unused\", config do\n    D.add_import(config[:pid], String, [], 1, true)\n    D.import_dispatch(config[:pid], String, {:upcase, 1}, :compile)\n    assert D.collect_unused_imports(config[:pid]) == [{String, %{}}]\n  end\n\n  test \"unused {module, function, arity} imports\", config do\n    D.add_import(config[:pid], String, [upcase: 1], 1, true)\n    assert D.collect_unused_imports(config[:pid]) == [{String, %{String => 1, {:upcase, 1} => 1}}]\n  end\n\n  test \"used {module, function, arity} imports are not unused\", config do\n    D.add_import(config[:pid], String, [upcase: 1], 1, true)\n    D.add_import(config[:pid], String, [downcase: 1], 1, true)\n    D.import_dispatch(config[:pid], String, {:upcase, 1}, :compile)\n    assert D.collect_unused_imports(config[:pid]) == [{String, %{{:downcase, 1} => 1}}]\n  end\n\n  test \"overwriting {module, function, arity} import with module import\", config do\n    D.add_import(config[:pid], String, [upcase: 1], 1, true)\n    D.add_import(config[:pid], String, [], 1, true)\n    D.import_dispatch(config[:pid], String, {:downcase, 1}, :compile)\n    assert D.collect_unused_imports(config[:pid]) == [{String, %{}}]\n  end\n\n  test \"imports with no warn are not unused\", config do\n    D.add_import(config[:pid], String, [], 1, false)\n    assert D.collect_unused_imports(config[:pid]) == []\n  end\n\n  test \"unused requires\", config do\n    D.warn_require(config[:pid], [], String, false)\n    D.warn_require(config[:pid], [], List, false)\n    D.remote_dispatch(config[:pid], String, :compile)\n    assert D.collect_unused_requires(config[:pid]) == [{List, [], false, false}]\n  end\n\n  test \"function calls do not count as macro usage\", config do\n    D.warn_require(config[:pid], [], String, false)\n    D.remote_dispatch(config[:pid], String, :runtime)\n    assert D.collect_unused_requires(config[:pid]) == [{String, [], false, false}]\n  end\n\n  test \"track alias usage through require\", config do\n    D.warn_require(config[:pid], [], String, S)\n    D.remote_dispatch(config[:pid], String, :runtime)\n    assert D.collect_unused_requires(config[:pid]) == [{String, [], S, false}]\n    D.alias_dispatch(config[:pid], S)\n    assert D.collect_unused_requires(config[:pid]) == [{String, [], S, true}]\n  end\n\n  test \"unused aliases\", config do\n    D.warn_alias(config[:pid], [], String, String)\n    assert D.collect_unused_aliases(config[:pid]) == [{String, []}]\n  end\n\n  test \"used aliases are not unused\", config do\n    D.warn_alias(config[:pid], [], String, String)\n    D.alias_dispatch(config[:pid], String)\n    assert D.collect_unused_aliases(config[:pid]) == []\n  end\n\n  test \"used aliases are not unused in reverse order\", config do\n    D.alias_dispatch(config[:pid], String)\n    D.warn_alias(config[:pid], [], String, String)\n    assert D.collect_unused_aliases(config[:pid]) == []\n  end\n\n  describe \"references\" do\n    test \"typespecs do not tag aliases nor types\" do\n      Code.eval_string(\"\"\"\n      defmodule Kernel.LexicalTrackerTest.AliasTypespecs do\n        alias Foo.Bar, as: Bar, warn: false\n        @type bar :: Foo.Bar | Foo.Bar.t\n        @opaque bar2 :: Foo.Bar.t\n        @typep bar3 :: Foo.Bar.t\n        @callback foo :: Foo.Bar.t\n        @macrocallback foo2(Foo.Bar.t) :: Foo.Bar.t\n        @spec foo(bar3) :: Foo.Bar.t\n        def foo(_), do: :ok\n\n        # References from specs are processed only late\n        @after_compile __MODULE__\n        def __after_compile__(env, _) do\n          send(self(), {:references, Kernel.LexicalTracker.references(env.lexical_tracker)})\n        end\n      end\n      \"\"\")\n\n      assert_received {:references, {compile, _exports, runtime, _}}\n\n      refute Elixir.Bar in runtime\n      refute Elixir.Bar in compile\n\n      refute Foo.Bar in runtime\n      refute Foo.Bar in compile\n    end\n\n    test \"typespecs track structs as exports\" do\n      Code.eval_string(\"\"\"\n      defmodule Kernel.LexicalTrackerTest.StructTypespecs do\n        @type uri :: %URI{}\n\n        # References from specs are processed only late\n        @after_compile __MODULE__\n        def __after_compile__(env, _) do\n          send(self(), {:references, Kernel.LexicalTracker.references(env.lexical_tracker)})\n        end\n      end\n      \"\"\")\n\n      assert_received {:references, {compile, exports, runtime, _}}\n\n      assert URI in runtime\n      assert URI in exports\n      refute URI in compile\n    end\n\n    test \"attributes adds dependency based on expansion\" do\n      {{compile, _, _, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Attribute1 do\n          @example [String, Enum, 3 + 10]\n          def foo(atom) when atom in @example, do: atom\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute String in compile\n      refute Enum in compile\n\n      {{compile, _, _, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Attribute2 do\n          @example [String, Enum]\n          def foo(atom) when atom in @example, do: atom\n          _ = @example\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert String in compile\n      assert Enum in compile\n\n      {{compile, _, _, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Attribute3 do\n          @example [String, Enum]\n          _ = Module.get_attribute(__MODULE__, :example)\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert String in compile\n      assert Enum in compile\n\n      {{compile, _, _, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Attribute4 do\n          Module.register_attribute(__MODULE__, :example, accumulate: true)\n          @example String\n          def foo(atom) when atom in @example, do: atom\n          @example Enum\n          def bar(atom) when atom in @example, do: atom\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute String in compile\n      refute Enum in compile\n\n      {{compile, _, _, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Attribute5 do\n          Module.register_attribute(__MODULE__, :example, accumulate: true)\n          @example String\n          def foo(atom) when atom in @example, do: atom\n          @example Enum\n          def bar(atom) when atom in @example, do: atom\n          _ = Module.get_attribute(__MODULE__, :example)\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert String in compile\n      assert Enum in compile\n\n      {{compile, _, _, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Attribute6 do\n          @example %{foo: Application.compile_env(:elixir, Enum, String)}\n          def foo(atom) when atom == @example.foo, do: atom\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute String in compile\n      refute Enum in compile\n\n      {{compile, _, _, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Attribute7 do\n          Module.register_attribute(__MODULE__, :example, accumulate: true)\n          @example String\n          @example Enum\n          _ = Module.get_last_attribute(__MODULE__, :example)\n\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert String in compile\n      assert Enum in compile\n    end\n\n    test \"@compile adds a runtime dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Compile do\n          @compile {:no_warn_undefined, String}\n          @compile {:no_warn_undefined, {Enum, :concat, 1}}\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute String in compile\n      refute String in exports\n      assert String in runtime\n\n      refute Enum in compile\n      refute Enum in exports\n      assert Enum in runtime\n    end\n\n    def __before_compile__(_), do: :ok\n    def __after_compile__(_, _), do: :ok\n    def __on_definition__(_, _, _, _, _, _), do: :ok\n\n    test \"module callbacks add a compile dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.BeforeCompile do\n          @before_compile Kernel.LexicalTrackerTest\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert Kernel.LexicalTrackerTest in compile\n      refute Kernel.LexicalTrackerTest in exports\n      refute Kernel.LexicalTrackerTest in runtime\n\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.AfterCompile do\n          @after_compile Kernel.LexicalTrackerTest\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert Kernel.LexicalTrackerTest in compile\n      refute Kernel.LexicalTrackerTest in exports\n      refute Kernel.LexicalTrackerTest in runtime\n\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.OnDefinition do\n          @on_definition Kernel.LexicalTrackerTest\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert Kernel.LexicalTrackerTest in compile\n      refute Kernel.LexicalTrackerTest in exports\n      refute Kernel.LexicalTrackerTest in runtime\n    end\n\n    test \"defdelegate with literal adds runtime dependency\" do\n      {{compile, _exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Defdelegate do\n          defdelegate decode_query(query), to: URI\n\n          opts = [to: Enum]\n          defdelegate concat(enum), opts\n\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute URI in compile\n      assert Enum in compile\n      assert URI in runtime\n    end\n\n    test \"dbg adds a compile dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Dbg do\n          def foo, do: dbg(:ok)\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert Macro in compile\n      refute Macro in exports\n      refute Macro in runtime\n\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.NoDbg do\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute Macro in compile\n      refute Macro in exports\n      refute Macro in runtime\n    end\n\n    test \"imports adds an export dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Imports do\n          import String, warn: false\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute String in compile\n      assert String in exports\n      refute String in runtime\n    end\n\n    test \"structs are runtime/exports/compile time\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.StructRuntime do\n          def expand, do: %URI{}\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute URI in compile\n      assert URI in exports\n      assert URI in runtime\n\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.StructCompile do\n          _ = %URI{}\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert URI in compile\n      assert URI in exports\n      refute URI in runtime\n\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.StructPattern do\n          def uri?(%URI{}), do: true\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute URI in compile\n      refute URI in exports\n      assert URI in runtime\n    end\n\n    test \"Macro.struct_info! adds an export dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.MacroStruct do\n          # We do not use the alias because it would be a compile time\n          # dependency. The alias may happen in practice, which is the\n          # mechanism to make this expansion become a compile-time one.\n          # However, in some cases, such as typespecs, we don't necessarily\n          # want the compile-time dependency to happen.\n          Macro.struct_info!(:\"Elixir.URI\", __ENV__)\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute URI in compile\n      assert URI in exports\n      refute URI in runtime\n    end\n\n    test \"aliases in patterns and guards inside functions do not add runtime dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.PatternGuardsRuntime do\n          def uri_atom?(URI), do: true\n          def range_struct?(range) when is_struct(range, Range), do: true\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute URI in compile\n      refute URI in exports\n      refute URI in runtime\n      refute Range in compile\n      refute Range in exports\n      refute Range in runtime\n    end\n\n    test \"aliases in patterns and guards outside functions do add compile dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.PatternGuardsCompile do\n          %URI{} = URI.parse(\"/\")\n          case Range.new(1, 3) do\n            range when is_struct(range, Range) -> :ok\n          end\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert URI in compile\n      assert URI in exports\n      refute URI in runtime\n      assert Range in compile\n      refute Range in exports\n      refute Range in runtime\n    end\n\n    test \"compile_env! does not add a compile dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.CompileEnvStruct do\n          require Application\n          Application.compile_env(:elixir, URI)\n          Application.compile_env(:elixir, [:foo, URI, :bar])\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute URI in compile\n      refute URI in exports\n      assert URI in runtime\n    end\n\n    test \"defmodule does not add a compile dependency\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Defmodule do\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute Kernel.LexicalTrackerTest.Defmodule in compile\n      refute Kernel.LexicalTrackerTest.Defmodule in exports\n      refute Kernel.LexicalTrackerTest.Defmodule in runtime\n    end\n\n    test \"defmacro adds a compile-time dependency for local calls\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.Defmacro do\n          defmacro uri(path) do\n            Macro.escape(URI.parse(path))\n          end\n\n          def fun() do\n            uri(\"/hello\")\n          end\n\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert URI in compile\n      refute URI in exports\n      refute URI in runtime\n    end\n\n    test \"imported functions from quote adds dependencies\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.QuotedFun do\n          import URI\n\n          defmacro parse_root() do\n            quote do\n              parse(\"/\")\n            end\n          end\n        end\n\n        defmodule Kernel.LexicalTrackerTest.UsingQuotedFun do\n          require Kernel.LexicalTrackerTest.QuotedFun, as: QF\n          QF.parse_root()\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert URI in compile\n      refute URI in exports\n      refute URI in runtime\n    end\n\n    test \"imported macro from quote adds dependencies\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defmodule Kernel.LexicalTrackerTest.QuotedMacro do\n          import Config\n\n          defmacro config_env() do\n            quote do\n              config_env()\n            end\n          end\n        end\n\n        defmodule Kernel.LexicalTrackerTest.UsingQuotedMacro do\n          require Kernel.LexicalTrackerTest.QuotedMacro, as: QM\n          def fun(), do: QM.config_env()\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      assert Config in compile\n      refute Config in exports\n      refute Config in runtime\n    end\n\n    test \"defimpl does not add dependencies on for, only on impl\" do\n      {{compile, exports, runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defimpl String.Chars, for: Kernel.LexicalTrackerTest do\n          def to_string(val), do: val.used_by_tests\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute String.Chars in compile\n      assert String.Chars in exports\n\n      refute Kernel.LexicalTrackerTest in compile\n      refute Kernel.LexicalTrackerTest in exports\n      refute Kernel.LexicalTrackerTest in runtime\n    end\n\n    test \"defprotocol does not add dependencies on implementations\" do\n      {{compile, _exports, _runtime, _}, _binding} =\n        Code.eval_string(\"\"\"\n        defprotocol Kernel.LexicalTracker.ProtocolTest do\n          @fallback_to_any true\n          def example(val)\n          Kernel.LexicalTracker.references(__ENV__.lexical_tracker)\n        end |> elem(3)\n        \"\"\")\n\n      refute Kernel.LexicalTracker.ProtocolTest.Any in compile\n      refute Kernel.LexicalTracker.ProtocolTest.Tuple in compile\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/macros_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.MacrosTest.Nested do\n  defmacro value, do: 1\n\n  defmacro do_identity!(do: x) do\n    x\n  end\n\n  defmacro unused_require do\n    quote do\n      require Integer\n    end\n  end\nend\n\ndefmodule Kernel.MacrosTest do\n  use ExUnit.Case, async: true\n\n  Kernel.MacrosTest.Nested = require Kernel.MacrosTest.Nested, as: Nested\n\n  # Unused require from macro should not warn\n  Kernel.MacrosTest.Nested.unused_require()\n\n  @spec my_macro :: Macro.t()\n  defmacro my_macro do\n    quote(do: 1 + 1)\n  end\n\n  @spec my_private_macro :: Macro.t()\n  defmacrop my_private_macro do\n    quote(do: 1 + 3)\n  end\n\n  defmacro my_macro_with_default(value \\\\ 5) do\n    quote(do: 1 + unquote(value))\n  end\n\n  defp by_two(x), do: x * 2\n\n  defmacro my_macro_with_local(value) do\n    value = by_two(by_two(value))\n    quote(do: 1 + unquote(value))\n  end\n\n  defmacro my_macro_with_capture(value) do\n    Enum.map(value, &by_two/1)\n  end\n\n  test \"require\" do\n    assert Kernel.MacrosTest.Nested.value() == 1\n  end\n\n  test \"require with alias\" do\n    assert Nested.value() == 1\n  end\n\n  test \"local with private macro\" do\n    assert my_private_macro() == 4\n  end\n\n  test \"local with defaults macro\" do\n    assert my_macro_with_default() == 6\n  end\n\n  test \"local with local call\" do\n    assert my_macro_with_local(4) == 17\n  end\n\n  test \"local with capture\" do\n    assert my_macro_with_capture([1, 2, 3]) == [2, 4, 6]\n  end\n\n  test \"macros cannot be called dynamically\" do\n    x = String.to_atom(\"Elixir.Nested\")\n    assert_raise UndefinedFunctionError, fn -> x.func() end\n  end\n\n  test \"macros with bang and do block have proper precedence\" do\n    import Kernel.MacrosTest.Nested\n\n    assert (do_identity! do\n              1\n            end) == 1\n\n    assert (Kernel.MacrosTest.Nested.do_identity! do\n              1\n            end) == 1\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/overridable_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.Overridable do\n  def sample do\n    1\n  end\n\n  def with_super do\n    1\n  end\n\n  def without_super do\n    1\n  end\n\n  def super_with_multiple_args(x, y) do\n    x + y\n  end\n\n  def capture_super(x) do\n    x\n  end\n\n  defmacro capture_super_macro(x) do\n    x\n  end\n\n  def many_clauses(0) do\n    11\n  end\n\n  def many_clauses(1) do\n    13\n  end\n\n  def locals do\n    undefined_function()\n  end\n\n  def multiple_overrides do\n    [1]\n  end\n\n  def public_to_private do\n    :public\n  end\n\n  defoverridable sample: 0,\n                 with_super: 0,\n                 without_super: 0,\n                 super_with_multiple_args: 2,\n                 capture_super: 1,\n                 capture_super_macro: 1,\n                 many_clauses: 1,\n                 locals: 0,\n                 multiple_overrides: 0,\n                 public_to_private: 0\n\n  true = Module.overridable?(__MODULE__, {:without_super, 0})\n  true = Module.overridable?(__MODULE__, {:with_super, 0})\n\n  true = {:with_super, 0} in Module.overridables_in(__MODULE__)\n  true = {:without_super, 0} in Module.overridables_in(__MODULE__)\n\n  def without_super do\n    :without_super\n  end\n\n  def with_super do\n    super() + 2\n  end\n\n  true = Module.overridable?(__MODULE__, {:without_super, 0})\n  true = Module.overridable?(__MODULE__, {:with_super, 0})\n\n  true = {:with_super, 0} in Module.overridables_in(__MODULE__)\n  true = {:without_super, 0} in Module.overridables_in(__MODULE__)\n\n  def super_with_multiple_args(x, y) do\n    super(x, y * 2)\n  end\n\n  def capture_super(x) do\n    Enum.map(1..x, &super(&1)) ++ Enum.map(1..x, &super/1)\n  end\n\n  defmacro capture_super_macro(x) do\n    Enum.map(1..x, &super(&1)) ++ Enum.map(1..x, &super/1)\n  end\n\n  def many_clauses(2) do\n    17\n  end\n\n  def many_clauses(3) do\n    super(0) + super(1)\n  end\n\n  def many_clauses(x) do\n    super(x)\n  end\n\n  def locals do\n    :ok\n  end\n\n  def multiple_overrides do\n    [2 | super()]\n  end\n\n  defp public_to_private do\n    :private\n  end\n\n  def test_public_to_private do\n    public_to_private()\n  end\n\n  defoverridable multiple_overrides: 0\n\n  def multiple_overrides do\n    [3 | super()]\n  end\n\n  ## Macros\n\n  defmacro overridable_macro(x) do\n    quote do\n      unquote(x) + 100\n    end\n  end\n\n  defoverridable overridable_macro: 1\n\n  defmacro overridable_macro(x) do\n    quote do\n      unquote(super(x)) + 1000\n    end\n  end\n\n  defmacrop private_macro(x) do\n    quote do\n      unquote(x) + 100\n    end\n  end\n\n  defoverridable private_macro: 1\n\n  defmacrop private_macro(x) do\n    quote do\n      unquote(super(x)) + 1000\n    end\n  end\n\n  def private_macro_call(val \\\\ 11) do\n    private_macro(val)\n  end\n\n  ## Defaults\n\n  def with_default(a, b \\\\ 1) do\n    a + b\n  end\n\n  defoverridable with_default: 2\n\n  def with_default(a, b) do\n    super(a + b, a + b)\n  end\nend\n\ndefmodule Kernel.OverridableExampleBehaviour do\n  @callback required_callback :: any\n  @callback optional_callback :: any\n  @macrocallback required_macro_callback(arg :: any) :: Macro.t()\n  @macrocallback optional_macro_callback(arg :: any, arg2 :: any) :: Macro.t()\n  @optional_callbacks optional_callback: 0, optional_macro_callback: 2\nend\n\ndefmodule Kernel.OverridableTest do\n  require Kernel.Overridable, as: Overridable\n  use ExUnit.Case, async: true\n\n  defp purge(module) do\n    :code.purge(module)\n    :code.delete(module)\n  end\n\n  test \"overridable keeps function ordering\" do\n    defmodule OverridableOrder do\n      def not_private(str) do\n        process_url(str)\n      end\n\n      def process_url(_str) do\n        :first\n      end\n\n      # There was a bug where the order in which we removed\n      # overridable expressions lead to errors. This module\n      # aims to guarantee removing process_url/1 before we\n      # remove the function that depends on it does not cause\n      # errors. If it compiles, it works!\n      defoverridable process_url: 1, not_private: 1\n\n      def process_url(_str) do\n        :second\n      end\n    end\n  end\n\n  test \"overridable works with defaults\" do\n    defmodule OverridableDefault do\n      def fun(value, opt \\\\ :from_parent) do\n        {value, opt}\n      end\n\n      defmacro macro(value, opt \\\\ :from_parent) do\n        {{value, opt}, Macro.escape(__CALLER__)}\n      end\n\n      # There was a bug where the default function would\n      # attempt to call its overridable name instead of\n      # func/1. If it compiles, it works!\n      defoverridable fun: 1, fun: 2, macro: 1, macro: 2\n\n      def fun(value) do\n        {value, super(value)}\n      end\n\n      defmacro macro(value) do\n        {{value, super(value)}, Macro.escape(__CALLER__)}\n      end\n    end\n\n    defmodule OverridableCall do\n      require OverridableDefault\n      OverridableDefault.fun(:foo)\n      OverridableDefault.macro(:bar)\n    end\n  end\n\n  test \"overridable is made concrete if no other is defined\" do\n    assert Overridable.sample() == 1\n  end\n\n  test \"overridable overridden with super\" do\n    assert Overridable.with_super() == 3\n  end\n\n  test \"overridable overridden without super\" do\n    assert Overridable.without_super() == :without_super\n  end\n\n  test \"public overridable overridden as private function\" do\n    assert Overridable.test_public_to_private() == :private\n    refute {:public_to_private, 0} in Overridable.module_info(:exports)\n  end\n\n  test \"overridable locals are ignored without super\" do\n    assert Overridable.locals() == :ok\n  end\n\n  test \"calling super with multiple args\" do\n    assert Overridable.super_with_multiple_args(1, 2) == 5\n  end\n\n  test \"calling super using function captures\" do\n    assert Overridable.capture_super(5) == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n  end\n\n  test \"calling super of an overridable macro using function captures\" do\n    assert Overridable.capture_super_macro(5) == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n  end\n\n  test \"super as a variable\" do\n    super = :ok\n    assert super == :ok\n  end\n\n  test \"overridable with many clauses\" do\n    assert Overridable.many_clauses(0) == 11\n    assert Overridable.many_clauses(1) == 13\n    assert Overridable.many_clauses(2) == 17\n    assert Overridable.many_clauses(3) == 24\n  end\n\n  test \"overridable definitions are private\" do\n    refute {:\"with_super (overridable 0)\", 0} in Overridable.module_info(:exports)\n    refute {:\"with_super (overridable 1)\", 0} in Overridable.module_info(:exports)\n  end\n\n  test \"multiple overrides\" do\n    assert Overridable.multiple_overrides() == [3, 2, 1]\n  end\n\n  test \"with defaults\" do\n    assert Overridable.with_default(5) == 12\n    assert Overridable.with_default(5, 2) == 14\n  end\n\n  test \"overridable macros\" do\n    a = 11\n    assert Overridable.overridable_macro(a) == 1111\n    assert Overridable.private_macro_call() == 1111\n  end\n\n  test \"invalid super call\" do\n    messages = [\n      \"nofile:4\",\n      \"no super defined for foo/0 in module Kernel.OverridableOrder.Forwarding. \" <>\n        \"Overridable functions available are: bar/0\"\n    ]\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableOrder.Forwarding do\n        def bar(), do: 1\n        defoverridable bar: 0\n        def foo(), do: super()\n      end\n      \"\"\")\n    end)\n\n    purge(Kernel.OverridableOrder.Forwarding)\n  end\n\n  test \"invalid super call with different arity\" do\n    messages = [\n      \"nofile:4\",\n      \"super must be called with the same number of arguments as the current definition\"\n    ]\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableSuper.DifferentArities do\n        def bar(a), do: a\n        defoverridable bar: 1\n        def bar(_), do: super()\n      end\n      \"\"\")\n    end)\n  end\n\n  test \"invalid super capture with different arity\" do\n    messages = [\n      \"nofile:4\",\n      \"super must be called with the same number of arguments as the current definition\"\n    ]\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableSuperCapture.DifferentArities do\n        def bar(a), do: a\n        defoverridable bar: 1\n        def bar(_), do: (&super/0).()\n      end\n      \"\"\")\n    end)\n  end\n\n  test \"does not allow to override a macro as a function\" do\n    messages = [\n      \"nofile:4\",\n      \"cannot override macro (defmacro, defmacrop) foo/0 in module \" <>\n        \"Kernel.OverridableMacro.FunctionOverride as a function (def, defp)\"\n    ]\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableMacro.FunctionOverride do\n        defmacro foo(), do: :ok\n        defoverridable foo: 0\n        def foo(), do: :invalid\n      end\n      \"\"\")\n    end)\n\n    purge(Kernel.OverridableMacro.FunctionOverride)\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableMacro.FunctionOverride do\n        defmacro foo(), do: :ok\n        defoverridable foo: 0\n        def foo(), do: :invalid\n        defoverridable foo: 0\n        def foo(), do: :invalid\n      end\n      \"\"\")\n    end)\n\n    purge(Kernel.OverridableMacro.FunctionOverride)\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableMacro.FunctionOverride do\n        defmacro foo(), do: :ok\n        defoverridable foo: 0\n        def foo(), do: super()\n      end\n      \"\"\")\n    end)\n\n    purge(Kernel.OverridableMacro.FunctionOverride)\n  end\n\n  test \"does not allow to override a function as a macro\" do\n    messages = [\n      \"nofile:4\",\n      \"cannot override function (def, defp) foo/0 in module \" <>\n        \"Kernel.OverridableFunction.MacroOverride as a macro (defmacro, defmacrop)\"\n    ]\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableFunction.MacroOverride do\n        def foo(), do: :ok\n        defoverridable foo: 0\n        defmacro foo(), do: :invalid\n      end\n      \"\"\")\n    end)\n\n    purge(Kernel.OverridableFunction.MacroOverride)\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableFunction.MacroOverride do\n        def foo(), do: :ok\n        defoverridable foo: 0\n        defmacro foo(), do: :invalid\n        defoverridable foo: 0\n        defmacro foo(), do: :invalid\n      end\n      \"\"\")\n    end)\n\n    purge(Kernel.OverridableFunction.MacroOverride)\n\n    assert_compile_error(messages, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableFunction.MacroOverride do\n        def foo(), do: :ok\n        defoverridable foo: 0\n        defmacro foo(), do: super()\n      end\n      \"\"\")\n    end)\n\n    purge(Kernel.OverridableFunction.MacroOverride)\n  end\n\n  test \"undefined functions can't be marked as overridable\" do\n    message = \"cannot make function foo/2 overridable because it was not defined\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableOrder.Foo do\n        defoverridable foo: 2\n      end\n      \"\"\")\n    end\n\n    purge(Kernel.OverridableOrder.Foo)\n  end\n\n  test \"overrides with behaviour\" do\n    defmodule OverridableWithBehaviour do\n      @behaviour Elixir.Kernel.OverridableExampleBehaviour\n\n      def required_callback(), do: \"original\"\n\n      def optional_callback(), do: \"original\"\n\n      def not_a_behaviour_callback(), do: \"original\"\n\n      defmacro required_macro_callback(boolean) do\n        quote do\n          if unquote(boolean) do\n            \"original\"\n          end\n        end\n      end\n\n      defoverridable Elixir.Kernel.OverridableExampleBehaviour\n\n      defmacro optional_macro_callback(arg1, arg2), do: {arg1, arg2}\n\n      assert Module.overridable?(__MODULE__, {:required_callback, 0})\n      assert Module.overridable?(__MODULE__, {:optional_callback, 0})\n      assert Module.overridable?(__MODULE__, {:required_macro_callback, 1})\n      refute Module.overridable?(__MODULE__, {:optional_macro_callback, 1})\n      refute Module.overridable?(__MODULE__, {:not_a_behaviour_callback, 1})\n    end\n  end\n\n  test \"undefined module can't be passed as argument to defoverridable\" do\n    message =\n      \"cannot pass module Kernel.OverridableTest.Bar as argument to defoverridable/1 because it was not defined\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableTest.Foo do\n        defoverridable Kernel.OverridableTest.Bar\n      end\n      \"\"\")\n    end\n\n    purge(Kernel.OverridableTest.Foo)\n  end\n\n  test \"module without @behaviour can't be passed as argument to defoverridable\" do\n    message =\n      \"cannot pass module Kernel.OverridableExampleBehaviour as argument to defoverridable/1\" <>\n        \" because its corresponding behaviour is missing. Did you forget to add \" <>\n        \"@behaviour Kernel.OverridableExampleBehaviour?\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableTest.Foo do\n        defoverridable Kernel.OverridableExampleBehaviour\n      end\n      \"\"\")\n    end\n\n    purge(Kernel.OverridableTest.Foo)\n  end\n\n  test \"module with no callbacks can't be passed as argument to defoverridable\" do\n    message =\n      \"cannot pass module Kernel.OverridableTest.Bar as argument to defoverridable/1 because it does not define any callbacks\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableTest.Bar do\n      end\n      defmodule Kernel.OverridableTest.Foo do\n        @behaviour Kernel.OverridableTest.Bar\n        defoverridable Kernel.OverridableTest.Bar\n      end\n      \"\"\")\n    end\n\n    purge(Kernel.OverridableTest.Bar)\n    purge(Kernel.OverridableTest.Foo)\n  end\n\n  test \"atom which is not a module can't be passed as argument to defoverridable\" do\n    message = \"cannot pass module :abc as argument to defoverridable/1 because it was not defined\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule Kernel.OverridableTest.Foo do\n        defoverridable :abc\n      end\n      \"\"\")\n    end\n\n    purge(Kernel.OverridableTest.Foo)\n  end\n\n  defp assert_compile_error(messages, fun) do\n    captured =\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        assert_raise CompileError, fun\n      end)\n\n    for message <- List.wrap(messages) do\n      assert captured =~ message\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/parallel_compiler_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\nimport PathHelpers\n\ndefmodule Kernel.ParallelCompilerTest do\n  use ExUnit.Case\n  import ExUnit.CaptureIO\n\n  @no_warnings %{compile_warnings: [], runtime_warnings: []}\n\n  defp compile(files, opts \\\\ []) do\n    Kernel.ParallelCompiler.compile(files, [return_diagnostics: true] ++ opts)\n  end\n\n  defp purge(modules) do\n    Enum.map(modules, fn mod ->\n      :code.purge(mod)\n      :code.delete(mod)\n    end)\n  end\n\n  defp write_tmp(context, kv) do\n    dir = tmp_path(context)\n    File.rm_rf!(dir)\n    File.mkdir_p!(dir)\n\n    for {key, contents} <- kv do\n      path = Path.join(dir, \"#{key}.ex\")\n      File.write!(path, contents)\n      path\n    end\n  end\n\n  describe \"compile\" do\n    test \"with profiling\" do\n      fixtures =\n        write_tmp(\n          \"profile_time\",\n          bar: \"\"\"\n          defmodule HelloWorld do\n          end\n          \"\"\"\n        )\n\n      profile =\n        capture_io(:stderr, fn ->\n          assert {:ok, modules, @no_warnings} = compile(fixtures, profile: :time)\n\n          assert HelloWorld in modules\n        end)\n\n      assert profile =~\n               ~r\"\\[profile\\] [\\s\\d]{6}ms compiling \\+      0ms waiting while compiling .*tmp/profile_time/bar.ex\"\n\n      assert profile =~ ~r\"\\[profile\\] Finished compilation cycle of 1 modules in \\d+ms\"\n      assert profile =~ ~r\"\\[profile\\] Finished group pass check of 1 modules in \\d+ms\"\n    after\n      purge([HelloWorld])\n    end\n\n    test \"immediately loads modules when not writing them to disk\" do\n      fixtures =\n        write_tmp(\n          \"compile_loads\",\n          will_be_loaded: \"\"\"\n          defmodule WillBeLoaded do\n          end\n          true = Code.loaded?(WillBeLoaded)\n          \"\"\"\n        )\n\n      assert {:ok, _modules, @no_warnings} = compile(fixtures)\n    end\n\n    test \"lazily loads modules when writing them to disk\" do\n      fixtures =\n        write_tmp(\n          \"compile_lazy_loads\",\n          will_be_lazy_loaded: \"\"\"\n          defmodule WillBeLazyLoaded do\n          end\n          false = Code.loaded?(WillBeLazyLoaded)\n          {:error, _} = Code.ensure_loaded(WillBeLazyLoaded)\n          {:module, _} = Code.ensure_compiled(WillBeLazyLoaded)\n          \"\"\",\n          is_autoloaded: \"\"\"\n          defmodule WillBeAutoLoaded do\n            @compile {:autoload, true}\n          end\n          true = Code.loaded?(WillBeAutoLoaded)\n          \"\"\"\n        )\n\n      assert {:ok, _modules, @no_warnings} =\n               Kernel.ParallelCompiler.compile_to_path(fixtures, tmp_path(\"pcload\"),\n                 return_diagnostics: true\n               )\n    end\n\n    test \"solves dependencies between modules\" do\n      fixtures =\n        write_tmp(\n          \"parallel_compiler\",\n          bar: \"\"\"\n          defmodule BarParallel do\n          end\n\n          require FooParallel\n          IO.puts(FooParallel.message())\n          \"\"\",\n          foo: \"\"\"\n          defmodule FooParallel do\n            # We use this ensure_compiled clause so both Foo and\n            # Bar block. Foo depends on Unknown and Bar depends on\n            # Foo. The compiler will see this dependency and first\n            # release Foo and then Bar, compiling with success.\n            {:error, _} = Code.ensure_compiled(Unknown)\n            def message, do: \"message_from_foo\"\n          end\n          \"\"\"\n        )\n\n      assert capture_io(fn ->\n               assert {:ok, modules, @no_warnings} = compile(fixtures)\n               assert BarParallel in modules\n               assert FooParallel in modules\n             end) =~ \"message_from_foo\"\n    after\n      purge([FooParallel, BarParallel])\n    end\n\n    test \"solves dependencies between structs\" do\n      fixtures =\n        write_tmp(\n          \"parallel_struct\",\n          bar: \"\"\"\n          defmodule BarStruct do\n            defstruct name: \"\", foo: %FooStruct{}\n          end\n          \"\"\",\n          foo: \"\"\"\n          defmodule FooStruct do\n            defstruct name: \"\"\n            def bar?(%BarStruct{}), do: true\n          end\n          \"\"\"\n        )\n\n      assert {:ok, modules, @no_warnings} = compile(fixtures)\n      assert [BarStruct, FooStruct] = Enum.sort(modules)\n    after\n      purge([FooStruct, BarStruct])\n    end\n\n    test \"solves dependencies between structs in typespecs\" do\n      fixtures =\n        write_tmp(\n          \"parallel_typespec_struct\",\n          bar: \"\"\"\n          defmodule BarStruct do\n            defstruct name: \"\"\n            @type t :: %FooStruct{}\n          end\n          \"\"\",\n          foo: \"\"\"\n          defmodule FooStruct do\n            defstruct name: \"\"\n            @type t :: %BarStruct{}\n          end\n          \"\"\"\n        )\n\n      assert {:ok, modules, @no_warnings} = compile(fixtures)\n      assert [BarStruct, FooStruct] = Enum.sort(modules)\n    after\n      purge([FooStruct, BarStruct])\n    end\n\n    test \"returns struct undefined error when local struct is undefined\" do\n      [fixture] =\n        write_tmp(\n          \"compile_struct\",\n          undef: \"\"\"\n          defmodule Undef do\n            def undef() do\n              %__MODULE__{}\n            end\n          end\n          \"\"\"\n        )\n\n      expected_msg = \"Undef.__struct__/1 is undefined, cannot expand struct Undef\"\n\n      assert capture_io(:stderr, fn ->\n               assert {:error,\n                       [\n                         %{file: ^fixture, position: {3, 5}, message: msg},\n                         %{file: ^fixture, position: 0, message: compile_msg}\n                       ], @no_warnings} =\n                        compile([fixture])\n\n               assert msg =~ expected_msg\n               assert compile_msg =~ \"cannot compile module Undef (errors have been logged)\"\n             end) =~ expected_msg\n    end\n\n    test \"returns error when fails to expand struct\" do\n      [fixture] =\n        write_tmp(\n          \"compile_struct_invalid_key\",\n          undef: \"\"\"\n          defmodule InvalidStructKey do\n            def invalid_struct_key() do\n              %Date{invalid_key: 2020}\n            end\n          end\n          \"\"\"\n        )\n\n      expected_msg = \"** (KeyError) key :invalid_key not found\"\n\n      assert capture_io(:stderr, fn ->\n               assert {:error, [%{file: ^fixture, position: 3, message: msg}], @no_warnings} =\n                        compile([fixture])\n\n               assert msg =~ expected_msg\n             end) =~ expected_msg\n    end\n\n    test \"does not crash with pending monitor message\" do\n      {pid, ref} = spawn_monitor(fn -> :ok end)\n\n      [fixture] =\n        write_tmp(\n          \"quick_example\",\n          quick_example: \"\"\"\n          defmodule QuickExample do\n          end\n          \"\"\"\n        )\n\n      assert {:ok, [QuickExample], @no_warnings} = compile([fixture])\n      assert_received {:DOWN, ^ref, _, ^pid, :normal}\n    after\n      purge([QuickExample])\n    end\n\n    test \"does not crash on external reports\" do\n      [fixture] =\n        write_tmp(\n          \"compile_quoted\",\n          quick_example: \"\"\"\n          defmodule CompileQuoted do\n            try do\n              Code.compile_quoted({:fn, [], [{:->, [], [[], quote(do: unknown_var)]}]})\n            rescue\n              _ -> :ok\n            end\n          end\n          \"\"\"\n        )\n\n      assert capture_io(:stderr, fn ->\n               assert {:ok, [CompileQuoted], @no_warnings} = compile([fixture])\n             end) =~ \"undefined variable \\\"unknown_var\\\"\"\n    after\n      purge([CompileQuoted])\n    end\n\n    test \"does not hang on missing dependencies\" do\n      [fixture] =\n        write_tmp(\n          \"compile_does_not_hang\",\n          with_behaviour_and_struct: \"\"\"\n          # We need to ensure it won't block even after multiple calls.\n          # So we use both behaviour and struct expansion below.\n          defmodule WithBehaviourAndStruct do\n            # @behaviour will call ensure_compiled().\n            @behaviour :unknown\n            # Struct expansion calls it as well.\n            %ThisModuleWillNeverBeAvailable{}\n          end\n          \"\"\"\n        )\n\n      expected_msg =\n        \"ThisModuleWillNeverBeAvailable.__struct__/1 is undefined, cannot expand struct ThisModuleWillNeverBeAvailable\"\n\n      assert capture_io(:stderr, fn ->\n               assert {:error,\n                       [\n                         %{file: ^fixture, position: {7, 3}, message: msg},\n                         %{file: ^fixture, position: 0, message: compile_msg}\n                       ], @no_warnings} =\n                        compile([fixture])\n\n               assert msg =~ expected_msg\n\n               assert compile_msg =~\n                        \"cannot compile module WithBehaviourAndStruct (errors have been logged)\"\n             end) =~ expected_msg\n    end\n\n    test \"does not deadlock on missing dependencies\" do\n      [missing_struct, depends_on] =\n        write_tmp(\n          \"does_not_deadlock\",\n          missing_struct: \"\"\"\n          defmodule MissingStruct do\n            %ThisModuleWillNeverBeAvailable{}\n            def hello, do: :ok\n          end\n          \"\"\",\n          depends_on_missing_struct: \"\"\"\n          MissingStruct.hello()\n          \"\"\"\n        )\n\n      expected_msg =\n        \"ThisModuleWillNeverBeAvailable.__struct__/1 is undefined, cannot expand struct ThisModuleWillNeverBeAvailable\"\n\n      assert capture_io(:stderr, fn ->\n               assert {:error,\n                       [\n                         %{file: ^missing_struct, position: {2, 3}, message: msg},\n                         %{file: ^missing_struct, position: 0, message: compile_msg}\n                       ], @no_warnings} =\n                        compile([missing_struct, depends_on])\n\n               assert msg =~ expected_msg\n\n               assert compile_msg =~\n                        \"cannot compile module MissingStruct (errors have been logged)\"\n             end) =~ expected_msg\n    end\n\n    test \"does not deadlock on missing import/struct dependencies\" do\n      [missing_import, depends_on] =\n        write_tmp(\n          \"import_and_structs\",\n          missing_import: \"\"\"\n          defmodule MissingStruct do\n            import Unknown.Module\n          end\n          \"\"\",\n          depends_on_missing_struct: \"\"\"\n          %MissingStruct{}\n          \"\"\"\n        )\n\n      expected_msg = \"module Unknown.Module is not loaded and could not be found\"\n\n      assert capture_io(:stderr, fn ->\n               assert {:error,\n                       [\n                         %{file: ^missing_import, position: {2, 3}, message: msg},\n                         %{file: ^missing_import, position: 0, message: compile_msg}\n                       ], @no_warnings} =\n                        compile([missing_import, depends_on])\n\n               assert msg =~ expected_msg\n\n               assert compile_msg =~\n                        \"cannot compile module MissingStruct (errors have been logged)\"\n             end) =~ expected_msg\n    end\n\n    test \"handles deadlocks\" do\n      [foo, bar] =\n        write_tmp(\n          \"parallel_deadlock\",\n          foo: \"\"\"\n          defmodule FooDeadlock do\n            BarDeadlock.__info__(:module)\n          end\n          \"\"\",\n          bar: \"\"\"\n          defmodule BarDeadlock do\n            %FooDeadlock{}\n          end\n          \"\"\"\n        )\n\n      msg =\n        capture_io(:stderr, fn ->\n          fixtures = [foo, bar]\n          assert {:error, [bar_error, foo_error], @no_warnings} = compile(fixtures)\n\n          assert %{file: ^bar, position: 2, message: \"deadlocked waiting on struct FooDeadlock\"} =\n                   bar_error\n\n          assert %{file: ^foo, position: nil, message: \"deadlocked waiting on module BarDeadlock\"} =\n                   foo_error\n        end)\n\n      assert msg =~ \"Compilation failed because of a deadlock between files.\"\n      assert msg =~ \"parallel_deadlock/foo.ex => BarDeadlock\"\n      assert msg =~ \"parallel_deadlock/bar.ex => FooDeadlock\"\n      assert msg =~ ~r\"== Compilation error in file .+parallel_deadlock/foo\\.ex ==\"\n      assert msg =~ \"** (CompileError) deadlocked waiting on module BarDeadlock\"\n      assert msg =~ ~r\"== Compilation error in file .+parallel_deadlock/bar\\.ex:2 ==\"\n      assert msg =~ \"** (CompileError) deadlocked waiting on struct FooDeadlock\"\n    end\n\n    test \"does not deadlock from Code.ensure_compiled\" do\n      [foo, bar] =\n        write_tmp(\n          \"parallel_ensure_nodeadlock\",\n          foo: \"\"\"\n          defmodule FooCircular do\n            {:error, :unavailable} = Code.ensure_compiled(BarCircular)\n          end\n          \"\"\",\n          bar: \"\"\"\n          defmodule BarCircular do\n            {:error, :unavailable} = Code.ensure_compiled(FooCircular)\n          end\n          \"\"\"\n        )\n\n      assert {:ok, _modules, @no_warnings} = compile([foo, bar])\n      assert Enum.sort([FooCircular, BarCircular]) == [BarCircular, FooCircular]\n    after\n      purge([FooCircular, BarCircular])\n    end\n\n    test \"handles pmap compilation\" do\n      [foo, bar] =\n        write_tmp(\n          \"async_compile\",\n          foo: \"\"\"\n          defmodule FooAsync do\n            true = Code.can_await_module_compilation?()\n\n            [BarAsync] =\n              Kernel.ParallelCompiler.pmap([:ok], fn :ok ->\n                true = Code.can_await_module_compilation?()\n                BarAsync.__info__(:module)\n              end)\n          end\n          \"\"\",\n          bar: \"\"\"\n          defmodule BarAsync do\n            true = Code.can_await_module_compilation?()\n          end\n          \"\"\"\n        )\n\n      capture_io(:stderr, fn ->\n        fixtures = [foo, bar]\n        assert {:ok, modules, @no_warnings} = compile(fixtures)\n        assert FooAsync in modules\n        assert BarAsync in modules\n      end)\n    after\n      purge([FooAsync, BarAsync])\n    end\n\n    test \"handles pmap deadlocks\" do\n      [foo, bar] =\n        write_tmp(\n          \"async_deadlock\",\n          foo: \"\"\"\n          defmodule FooAsyncDeadlock do\n            Kernel.ParallelCompiler.pmap([:ok], fn :ok ->\n              BarAsyncDeadlock.__info__(:module)\n            end)\n          end\n          \"\"\",\n          bar: \"\"\"\n          defmodule BarAsyncDeadlock do\n            FooAsyncDeadlock.__info__(:module)\n          end\n          \"\"\"\n        )\n\n      capture_io(:stderr, fn ->\n        fixtures = [foo, bar]\n        assert {:error, [bar_error, foo_error], @no_warnings} = compile(fixtures)\n\n        assert %{\n                 file: ^bar,\n                 position: nil,\n                 message: \"deadlocked waiting on module FooAsyncDeadlock\"\n               } = bar_error\n\n        assert %{file: ^foo, position: nil, message: \"deadlocked waiting on pmap [#PID<\" <> _} =\n                 foo_error\n      end)\n    end\n\n    test \"does not use incorrect line number when error originates in another file\" do\n      File.mkdir_p!(tmp_path())\n\n      [a, b] =\n        write_tmp(\n          \"error_line\",\n          a: \"\"\"\n          defmodule PCA do\n            def fun(arg), do: arg / 2\n          end\n          \"\"\",\n          b: \"\"\"\n          defmodule PCB do\n            def fun(arg) do\n              PCA.fun(arg)\n              :ok\n            end\n          end\n          PCB.fun(:not_a_number)\n          \"\"\"\n        )\n\n      capture_io(:stderr, fn ->\n        assert {:error, [%{file: ^b, position: 0, message: _}], _} = compile([a, b])\n      end)\n    end\n\n    test \"gets both source and file on @file annotations\" do\n      File.mkdir_p!(tmp_path())\n\n      [a] =\n        write_tmp(\n          \"file_source\",\n          a: \"\"\"\n          defmodule FileAttr do\n            @file \"unknown.foo.bar\"\n            def fun, do: (unused = :ok)\n          end\n          \"\"\"\n        )\n\n      capture_io(:stderr, fn ->\n        assert {:ok, [FileAttr], %{compile_warnings: [%{source: ^a, file: file, message: _}]}} =\n                 compile([a])\n\n        assert String.ends_with?(file, \"unknown.foo.bar\")\n        assert Path.type(file) == :absolute\n      end)\n    after\n      purge([FileAttr])\n    end\n\n    test \"gets correct line number for UndefinedFunctionError\" do\n      File.mkdir_p!(tmp_path())\n\n      [fixture] =\n        write_tmp(\"undef\",\n          undef: \"\"\"\n          defmodule UndefErrorLine do\n            Bogus.fun()\n          end\n          \"\"\"\n        )\n\n      capture_io(:stderr, fn ->\n        assert {:error, [%{file: ^fixture, position: 2, message: _}], _} = compile([fixture])\n      end)\n    end\n\n    test \"gets correct file+line+column number for SyntaxError\" do\n      File.mkdir_p!(tmp_path())\n\n      [fixture] =\n        write_tmp(\"error\",\n          error: \"\"\"\n          raise SyntaxError, file: \"foo/bar.ex\", line: 3, column: 10\n          \"\"\"\n        )\n\n      file = Path.absname(\"foo/bar.ex\")\n\n      capture_io(:stderr, fn ->\n        assert {:error, [%{file: ^file, source: ^fixture, position: {3, 10}}], _} =\n                 compile([fixture])\n      end)\n    end\n\n    test \"gets proper beam destinations from dynamic modules\" do\n      fixtures =\n        write_tmp(\n          \"dynamic\",\n          dynamic: \"\"\"\n          Module.create(Dynamic, quote(do: :ok), file: \"dynamic.ex\")\n          [_ | _] = :code.which(Dynamic)\n          \"\"\"\n        )\n\n      assert {:ok, [Dynamic], @no_warnings} = compile(fixtures, dest: \"sample\")\n    after\n      purge([Dynamic])\n    end\n  end\n\n  describe \"require\" do\n    test \"returns struct undefined error when local struct is undefined\" do\n      [fixture] =\n        write_tmp(\n          \"require_struct\",\n          undef: \"\"\"\n          defmodule Undef do\n            def undef() do\n              %__MODULE__{}\n            end\n          end\n          \"\"\"\n        )\n\n      expected_msg = \"Undef.__struct__/1 is undefined, cannot expand struct Undef\"\n\n      assert capture_io(:stderr, fn ->\n               assert {:error,\n                       [\n                         %{file: ^fixture, position: {3, 5}, message: msg},\n                         %{file: ^fixture, position: 0, message: compile_msg}\n                       ], @no_warnings} =\n                        Kernel.ParallelCompiler.require([fixture], return_diagnostics: true)\n\n               assert msg =~ expected_msg\n               assert compile_msg =~ \"cannot compile module Undef (errors have been logged)\"\n             end) =~ expected_msg\n    end\n\n    test \"does not hang on missing dependencies\" do\n      [fixture] =\n        write_tmp(\n          \"require_does_not_hang\",\n          with_behaviour_and_struct: \"\"\"\n          # We need to ensure it won't block even after multiple calls.\n          # So we use both behaviour and struct expansion below.\n          defmodule WithBehaviourAndStruct do\n            # @behaviour will call ensure_compiled().\n            @behaviour :unknown\n            # Struct expansion calls it as well.\n            %ThisModuleWillNeverBeAvailable{}\n          end\n          \"\"\"\n        )\n\n      expected_msg =\n        \"ThisModuleWillNeverBeAvailable.__struct__/1 is undefined, cannot expand struct ThisModuleWillNeverBeAvailable\"\n\n      assert capture_io(:stderr, fn ->\n               assert {:error,\n                       [\n                         %{file: ^fixture, position: {7, 3}, message: msg},\n                         %{file: ^fixture, position: 0, message: compile_msg}\n                       ], @no_warnings} =\n                        Kernel.ParallelCompiler.require([fixture], return_diagnostics: true)\n\n               assert msg =~ expected_msg\n\n               assert compile_msg =~\n                        \"cannot compile module WithBehaviourAndStruct (errors have been logged)\"\n             end) =~ expected_msg\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/parser_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.ParserTest do\n  use ExUnit.Case, async: true\n\n  test \"empty\" do\n    assert Code.string_to_quoted!(\"\") == {:__block__, [line: 1], []}\n    assert Code.string_to_quoted!(\"\", columns: true) == {:__block__, [line: 1, column: 1], []}\n\n    assert Code.string_to_quoted!(\"  \\n\") == {:__block__, [line: 1], []}\n    assert Code.string_to_quoted!(\"  \\n\", columns: true) == {:__block__, [line: 1, column: 1], []}\n  end\n\n  describe \"nullary ops\" do\n    test \"in expressions\" do\n      assert parse!(\"..\") == {:.., [line: 1], []}\n      assert parse!(\"...\") == {:..., [line: 1], []}\n    end\n\n    test \"in capture\" do\n      assert parse!(\"&../0\") == {:&, [line: 1], [{:/, [line: 1], [{:.., [line: 1], nil}, 0]}]}\n      assert parse!(\"&.../0\") == {:&, [line: 1], [{:/, [line: 1], [{:..., [line: 1], nil}, 0]}]}\n    end\n\n    test \"raises on ambiguous uses when also binary\" do\n      assert_raise SyntaxError, ~r/syntax error before: do/, fn ->\n        parse!(\"if .. do end\")\n      end\n    end\n  end\n\n  describe \"unary ops\" do\n    test \"in keywords\" do\n      assert parse!(\"f(!: :ok)\") == {:f, [line: 1], [[!: :ok]]}\n      assert parse!(\"f @: :ok\") == {:f, [line: 1], [[@: :ok]]}\n    end\n\n    test \"in maps\" do\n      assert parse!(\"%{+foo, bar => bat, ...baz}\") ==\n               {:%{}, [line: 1],\n                [\n                  {:+, [line: 1], [{:foo, [line: 1], nil}]},\n                  {{:bar, [line: 1], nil}, {:bat, [line: 1], nil}},\n                  {:..., [line: 1], [{:baz, [line: 1], nil}]}\n                ]}\n    end\n\n    test \"ambiguous ops\" do\n      assert parse!(\"f -var\") ==\n               {:f, [ambiguous_op: nil, line: 1], [{:-, [line: 1], [{:var, [line: 1], nil}]}]}\n\n      assert parse!(\"f -(var)\") ==\n               {:f, [ambiguous_op: nil, line: 1], [{:-, [line: 1], [{:var, [line: 1], nil}]}]}\n\n      assert parse!(\"f +-var\") ==\n               {:f, [{:ambiguous_op, nil}, {:line, 1}],\n                [{:+, [line: 1], [{:-, [line: 1], [{:var, [line: 1], nil}]}]}]}\n\n      assert parse!(\"f - var\") ==\n               {:-, [line: 1], [{:f, [line: 1], nil}, {:var, [line: 1], nil}]}\n\n      assert parse!(\"f --var\") ==\n               {:--, [line: 1], [{:f, [line: 1], nil}, {:var, [line: 1], nil}]}\n\n      assert parse!(\"(f ->var)\") ==\n               [{:->, [line: 1], [[{:f, [line: 1], nil}], {:var, [line: 1], nil}]}]\n    end\n\n    test \"ambiguous ops in keywords\" do\n      assert parse!(\"f(+: :ok)\") == {:f, [line: 1], [[+: :ok]]}\n      assert parse!(\"f +: :ok\") == {:f, [line: 1], [[+: :ok]]}\n      assert parse!(\"f +:\\n:ok\") == {:f, [line: 1], [[+: :ok]]}\n    end\n  end\n\n  describe \"ternary ops\" do\n    test \"root\" do\n      assert parse!(\"1..2//3\") == {:..//, [line: 1], [1, 2, 3]}\n      assert parse!(\"(1..2)//3\") == {:..//, [line: 1], [1, 2, 3]}\n    end\n\n    test \"with do-blocks\" do\n      assert parse!(\"foo do end..bar do end//baz do end\") == {\n               :..//,\n               [line: 1],\n               [\n                 {:foo, [line: 1], [[do: {:__block__, [line: 1], []}]]},\n                 {:bar, [line: 1], [[do: {:__block__, [line: 1], []}]]},\n                 {:baz, [line: 1], [[do: {:__block__, [line: 1], []}]]}\n               ]\n             }\n    end\n\n    test \"with no parens\" do\n      assert parse!(\"1..foo do end//bar bat\") == {\n               :..//,\n               [line: 1],\n               [\n                 1,\n                 {:foo, [line: 1], [[do: {:__block__, [line: 1], []}]]},\n                 {:bar, [line: 1], [{:bat, [line: 1], nil}]}\n               ]\n             }\n    end\n\n    test \"errors\" do\n      msg =\n        \"the range step operator (//) must immediately follow the range definition operator (..)\"\n\n      assert_syntax_error([msg], \"foo..bar baz//bat\")\n      assert_syntax_error([msg], \"foo++bar//bat\")\n      assert_syntax_error([msg], \"foo..(bar//bat)\")\n    end\n  end\n\n  describe \"\\\\\\\\ + newline\" do\n    test \"with ambiguous ops\" do\n      assert parse!(\"f \\\\\\n-var\") ==\n               {:f, [ambiguous_op: nil, line: 1], [{:-, [line: 2], [{:var, [line: 2], nil}]}]}\n\n      assert parse!(\"f \\\\\\n- var\") ==\n               {:-, [line: 2], [{:f, [line: 1], nil}, {:var, [line: 2], nil}]}\n\n      assert parse!(\"f -\\\\\\nvar\") ==\n               {:-, [line: 1], [{:f, [line: 1], nil}, {:var, [line: 2], nil}]}\n\n      assert parse!(\"f -\\\\\\n var\") ==\n               {:-, [line: 1], [{:f, [line: 1], nil}, {:var, [line: 2], nil}]}\n    end\n\n    test \"with capture\" do\n      assert parse!(\"&..//\\\\\\n/3\") ==\n               {:&, [line: 1], [{:/, [line: 2], [{:..//, [line: 1], nil}, 3]}]}\n\n      assert parse!(\"&\\\\\\n+/2\") == {:&, [line: 1], [{:/, [line: 2], [{:+, [line: 2], nil}, 2]}]}\n      assert parse!(\"&\\\\\\n//2\") == {:&, [line: 1], [{:/, [line: 2], [{:/, [line: 2], nil}, 2]}]}\n      assert parse!(\"&\\\\\\nor/2\") == {:&, [line: 1], [{:/, [line: 2], [{:or, [line: 2], nil}, 2]}]}\n\n      assert parse!(\"&+\\\\\\n/2\") == {:&, [line: 1], [{:/, [line: 2], [{:+, [line: 1], nil}, 2]}]}\n      assert parse!(\"&/\\\\\\n/2\") == {:&, [line: 1], [{:/, [line: 2], [{:/, [line: 1], nil}, 2]}]}\n      assert parse!(\"&or\\\\\\n/2\") == {:&, [line: 1], [{:/, [line: 2], [{:or, [line: 1], nil}, 2]}]}\n\n      assert parse!(\"&+/\\\\\\n2\") == {:&, [line: 1], [{:/, [line: 1], [{:+, [line: 1], nil}, 2]}]}\n      assert parse!(\"&//\\\\\\n2\") == {:&, [line: 1], [{:/, [line: 1], [{:/, [line: 1], nil}, 2]}]}\n      assert parse!(\"&or/\\\\\\n2\") == {:&, [line: 1], [{:/, [line: 1], [{:or, [line: 1], nil}, 2]}]}\n    end\n  end\n\n  describe \"identifier unicode normalization\" do\n    test \"stops at ascii codepoints\" do\n      assert {:ok, {:ç, _, nil}} = Code.string_to_quoted(\"ç\\n\")\n      assert {:ok, {:\\\\, _, [{:ç, _, nil}, 1]}} = Code.string_to_quoted(~S\"ç\\\\1\")\n    end\n\n    test \"nfc normalization is performed\" do\n      # before elixir 1.14, non-nfc would error\n      #  non-nfc:        \"ç\" (code points 0x0063 0x0327)\n      #  nfc-normalized: \"ç\" (code points 0x00E7)\n      assert Code.eval_string(\"ç = 1; ç\") == {1, [ç: 1]}\n    end\n\n    test \"elixir's additional normalization is performed\" do\n      # Common micro => Greek mu. See code formatter test too.\n      assert Code.eval_string(\"µs = 1; μs\") == {1, [{:μs, 1}]}\n\n      # commented out: math symbols capability in elixir\n      # normalizations, to ensure that we *can* handle codepoints\n      # that are Common-script and non-ASCII\n      # assert Code.eval_string(\"_ℕ𝕩 = 1\") == {1, [{:\"_ℕ𝕩\", 1}]}\n    end\n\n    test \"handles graphemes inside quoted identifiers\" do\n      string_to_quoted =\n        fn code ->\n          Code.string_to_quoted!(code,\n            token_metadata: true,\n            literal_encoder: &{:ok, {:__block__, &2, [&1]}},\n            emit_warnings: false\n          )\n        end\n\n      assert {\n               {:., _, [{:foo, _, nil}, :\"➡️\"]},\n               [no_parens: true, delimiter: ~S[\"], line: 1],\n               []\n             } = string_to_quoted.(~S|foo.\"➡️\"|)\n\n      assert {\n               {:., _, [{:foo, _, nil}, :\"➡️\"]},\n               [no_parens: true, delimiter: ~S['], line: 1],\n               []\n             } = string_to_quoted.(~S|foo.'➡️'|)\n\n      assert {:__block__, [delimiter: ~S[\"], line: 1], [:\"➡️\"]} = string_to_quoted.(~S|:\"➡️\"|)\n\n      assert {:__block__, [delimiter: ~S['], line: 1], [:\"➡️\"]} = string_to_quoted.(~S|:'➡️'|)\n\n      assert {:__block__, [closing: [line: 1], line: 1],\n              [\n                [\n                  {{:__block__, [delimiter: ~S[\"], format: :keyword, line: 1], [:\"➡️\"]},\n                   {:x, [line: 1], nil}}\n                ]\n              ]} = string_to_quoted.(~S|[\"➡️\": x]|)\n\n      assert {:__block__, [closing: [line: 1], line: 1],\n              [\n                [\n                  {{:__block__, [delimiter: ~S['], format: :keyword, line: 1], [:\"➡️\"]},\n                   {:x, [line: 1], nil}}\n                ]\n              ]} = string_to_quoted.(~S|['➡️': x]|)\n    end\n  end\n\n  describe \"strings/sigils\" do\n    test \"delimiter information for sigils is included\" do\n      string_to_quoted = &Code.string_to_quoted!(&1, token_metadata: false)\n\n      assert parse!(\"~r/foo/\") ==\n               {:sigil_r, [delimiter: \"/\", line: 1], [{:<<>>, [line: 1], [\"foo\"]}, []]}\n\n      assert string_to_quoted.(\"~r[foo]\") ==\n               {:sigil_r, [delimiter: \"[\", line: 1], [{:<<>>, [line: 1], [\"foo\"]}, []]}\n\n      assert string_to_quoted.(\"~r\\\"foo\\\"\") ==\n               {:sigil_r, [delimiter: \"\\\"\", line: 1], [{:<<>>, [line: 1], [\"foo\"]}, []]}\n\n      meta = [delimiter: \"\\\"\\\"\\\"\", line: 1]\n      args = {:sigil_S, meta, [{:<<>>, [indentation: 0, line: 1], [\"sigil heredoc\\n\"]}, []]}\n      assert string_to_quoted.(\"~S\\\"\\\"\\\"\\nsigil heredoc\\n\\\"\\\"\\\"\") == args\n\n      meta = [delimiter: \"'''\", line: 1]\n      args = {:sigil_S, meta, [{:<<>>, [indentation: 0, line: 1], [\"sigil heredoc\\n\"]}, []]}\n      assert string_to_quoted.(\"~S'''\\nsigil heredoc\\n'''\") == args\n    end\n\n    test \"valid multi-letter sigils\" do\n      string_to_quoted = &Code.string_to_quoted!(&1, token_metadata: false)\n\n      assert string_to_quoted.(\"~REGEX/foo/\") ==\n               {:sigil_REGEX, [delimiter: \"/\", line: 1], [{:<<>>, [line: 1], [\"foo\"]}, []]}\n\n      assert string_to_quoted.(\"~REGEX/foo/mods\") ==\n               {:sigil_REGEX, [delimiter: \"/\", line: 1], [{:<<>>, [line: 1], [\"foo\"]}, ~c\"mods\"]}\n\n      assert string_to_quoted.(\"~REGEX[foo]\") ==\n               {:sigil_REGEX, [delimiter: \"[\", line: 1], [{:<<>>, [line: 1], [\"foo\"]}, []]}\n\n      meta = [delimiter: \"\\\"\\\"\\\"\", line: 1]\n      args = {:sigil_MAT, meta, [{:<<>>, [indentation: 0, line: 1], [\"1,2,3\\n\"]}, []]}\n      assert string_to_quoted.(\"~MAT\\\"\\\"\\\"\\n1,2,3\\n\\\"\\\"\\\"\") == args\n\n      args = {:sigil_FOO1, meta, [{:<<>>, [indentation: 0, line: 1], [\"1,2,3\\n\"]}, []]}\n      assert string_to_quoted.(\"~FOO1\\\"\\\"\\\"\\n1,2,3\\n\\\"\\\"\\\"\") == args\n\n      args = {:sigil_BAR321, meta, [{:<<>>, [indentation: 0, line: 1], [\"1,2,3\\n\"]}, []]}\n      assert string_to_quoted.(\"~BAR321\\\"\\\"\\\"\\n1,2,3\\n\\\"\\\"\\\"\") == args\n\n      args = {:sigil_I18N, meta, [{:<<>>, [indentation: 0, line: 1], [\"1,2,3\\n\"]}, []]}\n      assert string_to_quoted.(\"~I18N\\\"\\\"\\\"\\n1,2,3\\n\\\"\\\"\\\"\") == args\n    end\n\n    test \"invalid multi-letter sigils\" do\n      msg =\n        ~r/invalid sigil name, it should be either a one-letter lowercase letter or an uppercase letter optionally followed by uppercase letters and digits/\n\n      assert_syntax_error([\"nofile:1:1:\", msg], \"~Regex/foo/\")\n\n      assert_syntax_error([\"nofile:1:1:\", msg], \"~FOo1{bar]\")\n\n      assert_syntax_error([\"nofile:1:1:\", msg], \"~foo1{bar]\")\n    end\n\n    test \"sigil newlines\" do\n      assert {:sigil_s, _, [{:<<>>, _, [\"here\\ndoc\"]}, []]} =\n               Code.string_to_quoted!(~s|~s\"here\\ndoc\"|)\n\n      assert {:sigil_s, _, [{:<<>>, _, [\"here\\r\\ndoc\"]}, []]} =\n               Code.string_to_quoted!(~s|~s\"here\\r\\ndoc\"|)\n    end\n\n    test \"string newlines\" do\n      assert Code.string_to_quoted!(~s|\"here\\ndoc\"|) == \"here\\ndoc\"\n      assert Code.string_to_quoted!(~s|\"here\\r\\ndoc\"|) == \"here\\r\\ndoc\"\n      assert Code.string_to_quoted!(~s|\"here\\\\\\ndoc\"|) == \"heredoc\"\n      assert Code.string_to_quoted!(~s|\"here\\\\\\r\\ndoc\"|) == \"heredoc\"\n    end\n\n    test \"heredoc newlines\" do\n      assert Code.string_to_quoted!(~s|\"\"\"\\nhere\\ndoc\\n\"\"\"|) == \"here\\ndoc\\n\"\n      assert Code.string_to_quoted!(~s|\"\"\"\\r\\nhere\\r\\ndoc\\r\\n\"\"\"|) == \"here\\r\\ndoc\\r\\n\"\n      assert Code.string_to_quoted!(~s|  \"\"\"\\n  here\\n  doc\\n  \"\"\"|) == \"here\\ndoc\\n\"\n      assert Code.string_to_quoted!(~s|  \"\"\"\\r\\n  here\\r\\n  doc\\r\\n  \"\"\"|) == \"here\\r\\ndoc\\r\\n\"\n      assert Code.string_to_quoted!(~s|\"\"\"\\nhere\\\\\\ndoc\\\\\\n\"\"\"|) == \"heredoc\"\n      assert Code.string_to_quoted!(~s|\"\"\"\\r\\nhere\\\\\\r\\ndoc\\\\\\r\\n\"\"\"|) == \"heredoc\"\n    end\n\n    test \"heredoc indentation\" do\n      meta = [delimiter: \"'''\", line: 1]\n      args = {:sigil_S, meta, [{:<<>>, [indentation: 2, line: 1], [\"  sigil heredoc\\n\"]}, []]}\n      assert Code.string_to_quoted!(\"~S'''\\n    sigil heredoc\\n  '''\") == args\n    end\n  end\n\n  describe \"string_to_quoted/2\" do\n    test \"converts strings to quoted expressions\" do\n      assert Code.string_to_quoted(\"1 + 2\") == {:ok, {:+, [line: 1], [1, 2]}}\n\n      assert Code.string_to_quoted(\"a.1\") ==\n               {:error, {[line: 1, column: 3], \"syntax error before: \", \"\\\"1\\\"\"}}\n    end\n  end\n\n  describe \"string_to_quoted/2 and atom handling\" do\n    test \"ensures :existing_atoms_only\" do\n      assert Code.string_to_quoted(\":there_is_no_such_atom\", existing_atoms_only: true) ==\n               {:error,\n                {[line: 1, column: 1], \"unsafe atom does not exist: \", \"there_is_no_such_atom\"}}\n\n      assert Code.string_to_quoted(\"~UNKNOWN'foo bar'\", existing_atoms_only: true) ==\n               {:error, {[line: 1, column: 1], \"unsafe atom does not exist: \", \"sigil_UNKNOWN\"}}\n    end\n\n    test \"encodes atoms\" do\n      ref = make_ref()\n\n      encoder = fn atom, meta ->\n        assert atom == \"there_is_no_such_atom\"\n        assert meta[:line] == 1\n        assert meta[:column] == 1\n        {:ok, {:my, \"atom\", ref}}\n      end\n\n      assert {:ok, {:my, \"atom\", ^ref}} =\n               Code.string_to_quoted(\":there_is_no_such_atom\", static_atoms_encoder: encoder)\n    end\n\n    test \"encodes vars\" do\n      ref = make_ref()\n\n      encoder = fn atom, meta ->\n        assert atom == \"there_is_no_such_var\"\n        assert meta[:line] == 1\n        assert meta[:column] == 1\n        {:ok, {:my, \"atom\", ref}}\n      end\n\n      assert {:ok, {{:my, \"atom\", ^ref}, [line: 1], nil}} =\n               Code.string_to_quoted(\"there_is_no_such_var\", static_atoms_encoder: encoder)\n    end\n\n    test \"encodes quoted keyword keys\" do\n      ref = make_ref()\n\n      encoder = fn atom, meta ->\n        assert atom == \"there is no such key\"\n        assert meta[:line] == 1\n        assert meta[:column] == 2\n        {:ok, {:my, \"atom\", ref}}\n      end\n\n      assert {:ok, [{{:my, \"atom\", ^ref}, true}]} =\n               Code.string_to_quoted(~S([\"there is no such key\": true]),\n                 static_atoms_encoder: encoder\n               )\n    end\n\n    test \"encodes multi-letter sigils\" do\n      ref = make_ref()\n\n      encoder = fn atom, meta ->\n        assert atom == \"sigil_UNKNOWN\"\n        assert meta[:line] == 1\n        assert meta[:column] == 1\n        {:ok, ref}\n      end\n\n      assert {:ok, {^ref, [delimiter: \"'\", line: 1], [{:<<>>, [line: 1], [\"abc\"]}, []]}} =\n               Code.string_to_quoted(\"~UNKNOWN'abc'\", static_atoms_encoder: encoder)\n    end\n\n    test \"addresses ambiguities\" do\n      encoder = fn string, _meta -> {:ok, {:atom, string}} end\n\n      # We check a=1 for precedence issues with a!=1, make sure it works\n      assert Code.string_to_quoted!(\"a = 1\", static_atoms_encoder: encoder)\n      assert Code.string_to_quoted!(\"a=1\", static_atoms_encoder: encoder)\n    end\n\n    test \"does not encode keywords\" do\n      encoder = fn atom, _meta -> raise \"shouldn't be invoked for #{atom}\" end\n\n      assert {:ok, {:fn, [line: 1], [{:->, [line: 1], [[1], 2]}]}} =\n               Code.string_to_quoted(\"fn 1 -> 2 end\", static_atoms_encoder: encoder)\n\n      assert {:ok, {:or, [line: 1], [true, false]}} =\n               Code.string_to_quoted(\"true or false\", static_atoms_encoder: encoder)\n\n      encoder = fn atom, _meta -> {:ok, {:encoded, atom}} end\n\n      assert {:ok, [encoded: \"true\", encoded: \"do\", encoded: \"and\"]} =\n               Code.string_to_quoted(\"[:true, :do, :and]\", static_atoms_encoder: encoder)\n\n      assert {:ok, [{{:encoded, \"do\"}, 1}, {{:encoded, \"true\"}, 2}, {{:encoded, \"end\"}, 3}]} =\n               Code.string_to_quoted(\"[do: 1, true: 2, end: 3]\", static_atoms_encoder: encoder)\n    end\n\n    test \"does not encode one-letter sigils\" do\n      encoder = fn atom, _meta -> raise \"shouldn't be invoked for #{atom}\" end\n\n      assert {:ok, {:sigil_z, [{:delimiter, \"'\"}, {:line, 1}], [{:<<>>, [line: 1], [\"foo\"]}, []]}} =\n               Code.string_to_quoted(\"~z'foo'\", static_atoms_encoder: encoder)\n\n      assert {:ok, {:sigil_Z, [{:delimiter, \"'\"}, {:line, 1}], [{:<<>>, [line: 1], [\"foo\"]}, []]}} =\n               Code.string_to_quoted(\"~Z'foo'\", static_atoms_encoder: encoder)\n    end\n\n    test \"returns errors on long atoms even when using static_atoms_encoder\" do\n      atom = String.duplicate(\"a\", 256)\n\n      encoder = fn atom, _meta -> {:ok, atom} end\n\n      assert Code.string_to_quoted(atom, static_atoms_encoder: encoder) ==\n               {:error,\n                {[line: 1, column: 1], \"atom length must be less than system limit: \", atom}}\n    end\n\n    test \"avoids crashes on invalid AST\" do\n      encoder = fn atom, _meta -> {:ok, {:atom, [], [atom]}} end\n\n      assert {:error, {_, \"missing terminator: )\", \"\"}} =\n               Code.string_to_quoted(\"Module(\", static_atoms_encoder: encoder)\n\n      assert {:error, {_, \"syntax error before: \", \"'('\"}} =\n               Code.string_to_quoted(\"Module()\", static_atoms_encoder: encoder)\n    end\n\n    test \"may return errors\" do\n      encoder = fn _atom, _meta ->\n        {:error, \"Invalid atom name\"}\n      end\n\n      assert {:error, {[line: 1, column: 1], \"Invalid atom name: \", \"there_is_no_such_atom\"}} =\n               Code.string_to_quoted(\":there_is_no_such_atom\", static_atoms_encoder: encoder)\n\n      assert {:error, {[line: 1, column: 1], \"Invalid atom name: \", \"sigil_UNKNOWN\"}} =\n               Code.string_to_quoted(\"~UNKNOWN'foo bar'\", static_atoms_encoder: encoder)\n    end\n\n    test \"may return tuples\" do\n      encoder = fn string, _metadata ->\n        try do\n          {:ok, String.to_existing_atom(string)}\n        rescue\n          ArgumentError ->\n            {:ok, {:user_atom, string}}\n        end\n      end\n\n      assert {:ok, {:try, _, [[do: {:test, _, [{{:user_atom, \"atom_does_not_exist\"}, _, []}]}]]}} =\n               Code.string_to_quoted(\"try do: test(atom_does_not_exist())\",\n                 static_atoms_encoder: encoder\n               )\n    end\n  end\n\n  describe \"string_to_quoted/2 with :columns\" do\n    test \"includes column information\" do\n      string_to_quoted = &Code.string_to_quoted(&1, columns: true)\n      assert string_to_quoted.(\"1 + 2\") == {:ok, {:+, [line: 1, column: 3], [1, 2]}}\n\n      foo = {:foo, [line: 1, column: 1], nil}\n      bar = {:bar, [line: 1, column: 7], nil}\n      assert string_to_quoted.(\"foo + bar\") == {:ok, {:+, [line: 1, column: 5], [foo, bar]}}\n\n      nfc_abba = [225, 98, 98, 224]\n      nfd_abba = [97, 769, 98, 98, 97, 768]\n      context = [line: 1, column: 8]\n      expr = \"\\\"ábbà\\\" = 1\"\n\n      assert string_to_quoted.(String.normalize(expr, :nfc)) ==\n               {:ok, {:=, context, [List.to_string(nfc_abba), 1]}}\n\n      assert string_to_quoted.(String.normalize(expr, :nfd)) ==\n               {:ok, {:=, context, [List.to_string(nfd_abba), 1]}}\n    end\n\n    test \"not in\" do\n      assert Code.string_to_quoted!(\"a not in b\", columns: true) ==\n               {:not, [line: 1, column: 3],\n                [\n                  {:in, [line: 1, column: 7],\n                   [{:a, [line: 1, column: 1], nil}, {:b, [line: 1, column: 10], nil}]}\n                ]}\n\n      assert Code.string_to_quoted!(\"a not  in b\", columns: true, token_metadata: true) ==\n               {:not, [line: 1, column: 3],\n                [\n                  {:in, [line: 1, column: 8],\n                   [{:a, [line: 1, column: 1], nil}, {:b, [line: 1, column: 11], nil}]}\n                ]}\n\n      assert Code.string_to_quoted!(\"a\\nnot in b\", columns: true, token_metadata: true) ==\n               {:not, [newlines: 1, line: 2, column: 1],\n                [\n                  {:in, [line: 2, column: 5],\n                   [{:a, [line: 1, column: 1], nil}, {:b, [line: 2, column: 8], nil}]}\n                ]}\n\n      assert Code.string_to_quoted!(\"a not in\\nb\", columns: true, token_metadata: true) ==\n               {:not, [newlines: 1, line: 1, column: 3],\n                [\n                  {:in, [line: 1, column: 7],\n                   [{:a, [line: 1, column: 1], nil}, {:b, [line: 2, column: 1], nil}]}\n                ]}\n\n      assert Code.string_to_quoted!(\"a\\nnot in\\nb\", columns: true, token_metadata: true) ==\n               {:not, [newlines: 1, line: 2, column: 1],\n                [\n                  {:in, [line: 2, column: 5],\n                   [{:a, [line: 1, column: 1], nil}, {:b, [line: 3, column: 1], nil}]}\n                ]}\n    end\n\n    test \"deprecated not/in\" do\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               assert Code.string_to_quoted!(\"not a in b\", columns: true) ==\n                        {:not, [line: 1, column: 1],\n                         [\n                           {:in, [line: 1, column: 7],\n                            [\n                              {:a, [line: 1, column: 5], nil},\n                              {:b, [line: 1, column: 10], nil}\n                            ]}\n                         ]}\n             end) =~ \"not expr1 in expr2\"\n\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               assert Code.string_to_quoted!(\"!a in b\", columns: true) ==\n                        {:!, [line: 1, column: 1],\n                         [\n                           {:in, [line: 1, column: 4],\n                            [\n                              {:a, [line: 1, column: 2], nil},\n                              {:b, [line: 1, column: 7], nil}\n                            ]}\n                         ]}\n             end) =~ \"!expr1 in expr2\"\n    end\n\n    test \"handles maps and structs\" do\n      assert Code.string_to_quoted(\"%{}\", columns: true) ==\n               {:ok, {:%{}, [line: 1, column: 1], []}}\n\n      assert Code.string_to_quoted(\"%:atom{}\", columns: true) ==\n               {:ok, {:%, [line: 1, column: 1], [:atom, {:%{}, [line: 1, column: 7], []}]}}\n    end\n  end\n\n  describe \"string_to_quoted/2 with :token_metadata\" do\n    test \"adds end_of_expression information to blocks\" do\n      file = \"\"\"\n      one();two()\n      three()\n\n      four()\n\n\n      five()\n      \"\"\"\n\n      args = [\n        {:one,\n         [\n           end_of_expression: [newlines: 0, line: 1, column: 6],\n           closing: [line: 1, column: 5],\n           line: 1,\n           column: 1\n         ], []},\n        {:two,\n         [\n           end_of_expression: [newlines: 1, line: 1, column: 12],\n           closing: [line: 1, column: 11],\n           line: 1,\n           column: 7\n         ], []},\n        {:three,\n         [\n           end_of_expression: [newlines: 2, line: 2, column: 8],\n           closing: [line: 2, column: 7],\n           line: 2,\n           column: 1\n         ], []},\n        {:four,\n         [\n           end_of_expression: [newlines: 3, line: 4, column: 7],\n           closing: [line: 4, column: 6],\n           line: 4,\n           column: 1\n         ], []},\n        {:five,\n         [\n           end_of_expression: [newlines: 1, line: 7, column: 7],\n           closing: [line: 7, column: 6],\n           line: 7,\n           column: 1\n         ], []}\n      ]\n\n      assert Code.string_to_quoted!(file, token_metadata: true, columns: true) ==\n               {:__block__, [], args}\n    end\n\n    test \"adds end_of_expression to the right hand side of ->\" do\n      file = \"\"\"\n      case true do\n        :foo -> bar(); two()\n        :baz -> bat()\n      end\n      \"\"\"\n\n      assert Code.string_to_quoted!(file, token_metadata: true) ==\n               {:case,\n                [\n                  end_of_expression: [newlines: 1, line: 4],\n                  do: [line: 1],\n                  end: [line: 4],\n                  line: 1\n                ],\n                [\n                  true,\n                  [\n                    do: [\n                      {:->, [line: 2],\n                       [\n                         [:foo],\n                         {:__block__, [],\n                          [\n                            {:bar,\n                             [\n                               end_of_expression: [newlines: 0, line: 2],\n                               closing: [line: 2],\n                               line: 2\n                             ], []},\n                            {:two,\n                             [\n                               end_of_expression: [newlines: 1, line: 2],\n                               closing: [line: 2],\n                               line: 2\n                             ], []}\n                          ]}\n                       ]},\n                      {:->, [line: 3],\n                       [\n                         [:baz],\n                         {:bat,\n                          [\n                            end_of_expression: [newlines: 1, line: 3],\n                            closing: [line: 3],\n                            line: 3\n                          ], []}\n                       ]}\n                    ]\n                  ]\n                ]}\n    end\n\n    test \"end of expression with literal\" do\n      file = \"\"\"\n      a do\n        d ->\n          (\n            b -> c\n          )\n      end\n      \"\"\"\n\n      assert Code.string_to_quoted!(file,\n               token_metadata: true,\n               literal_encoder: &{:ok, {:__block__, &2, [&1]}}\n             ) ==\n               {:a,\n                [\n                  end_of_expression: [newlines: 1, line: 6],\n                  do: [line: 1],\n                  end: [line: 6],\n                  line: 1\n                ],\n                [\n                  [\n                    {{:__block__, [line: 1], [:do]},\n                     [\n                       {:->, [newlines: 1, line: 2],\n                        [\n                          [{:d, [line: 2], nil}],\n                          {:__block__,\n                           [\n                             end_of_expression: [newlines: 1, line: 5],\n                             newlines: 1,\n                             closing: [line: 5],\n                             line: 3\n                           ],\n                           [\n                             [\n                               {:->, [line: 4],\n                                [\n                                  [{:b, [line: 4], nil}],\n                                  {:c, [end_of_expression: [newlines: 1, line: 4], line: 4], nil}\n                                ]}\n                             ]\n                           ]}\n                        ]}\n                     ]}\n                  ]\n                ]}\n    end\n\n    test \"does not add end of expression to ->\" do\n      file = \"\"\"\n      case true do\n        :foo -> :bar\n        :baz -> :bat\n      end\\\n      \"\"\"\n\n      assert Code.string_to_quoted!(file, token_metadata: true) ==\n               {:case, [do: [line: 1], end: [line: 4], line: 1],\n                [\n                  true,\n                  [\n                    do: [\n                      {:->, [line: 2], [[:foo], :bar]},\n                      {:->, [line: 3], [[:baz], :bat]}\n                    ]\n                  ]\n                ]}\n    end\n\n    test \"adds pairing information\" do\n      string_to_quoted = &Code.string_to_quoted!(&1, token_metadata: true)\n\n      assert string_to_quoted.(\"foo\") == {:foo, [line: 1], nil}\n      assert string_to_quoted.(\"foo()\") == {:foo, [closing: [line: 1], line: 1], []}\n\n      assert string_to_quoted.(\"foo(\\n)\") ==\n               {:foo, [newlines: 1, closing: [line: 2], line: 1], []}\n\n      assert string_to_quoted.(\"%{\\n}\") == {:%{}, [newlines: 1, closing: [line: 2], line: 1], []}\n\n      assert string_to_quoted.(\"foo(\\n) do\\nend\") ==\n               {:foo, [do: [line: 2], end: [line: 3], newlines: 1, closing: [line: 2], line: 1],\n                [[do: {:__block__, [line: 2], []}]]}\n\n      assert string_to_quoted.(\"foo(\\n)(\\n)\") ==\n               {{:foo, [newlines: 1, closing: [line: 2], line: 1], []},\n                [newlines: 1, closing: [line: 3], line: 1], []}\n    end\n\n    test \"adds opening and closing information for single-expression block\" do\n      file = \"1 + (2 + 3)\"\n\n      assert Code.string_to_quoted!(file, token_metadata: true, columns: true) ==\n               {:+, [line: 1, column: 3],\n                [\n                  1,\n                  {:+,\n                   [\n                     parens: [closing: [line: 1, column: 11], line: 1, column: 5],\n                     line: 1,\n                     column: 8\n                   ], [2, 3]}\n                ]}\n\n      file = \"1 + ((2 + 3))\"\n\n      assert Code.string_to_quoted!(file, token_metadata: true, columns: true) ==\n               {:+, [line: 1, column: 3],\n                [\n                  1,\n                  {:+,\n                   [\n                     parens: [closing: [line: 1, column: 13], line: 1, column: 5],\n                     parens: [closing: [line: 1, column: 12], line: 1, column: 6],\n                     line: 1,\n                     column: 9\n                   ], [2, 3]}\n                ]}\n    end\n\n    test \"adds opening and closing information for tuples\" do\n      string_to_quoted = &Code.string_to_quoted!(&1, token_metadata: true, columns: true)\n\n      assert string_to_quoted.(\"{}\") ==\n               {:{}, [closing: [line: 1, column: 2], line: 1, column: 1], []}\n\n      assert string_to_quoted.(\"{123}\") ==\n               {:{}, [closing: [line: 1, column: 5], line: 1, column: 1], [123]}\n\n      assert string_to_quoted.(\"x.{}\") ==\n               {{:., [line: 1, column: 2], [{:x, [line: 1, column: 1], nil}, :{}]},\n                [closing: [line: 1, column: 4], line: 1, column: 2], []}\n\n      assert string_to_quoted.(\"x.{123}\") ==\n               {{:., [line: 1, column: 2], [{:x, [line: 1, column: 1], nil}, :{}]},\n                [closing: [line: 1, column: 7], line: 1, column: 2], [123]}\n    end\n\n    test \"adds opening and closing information for empty block\" do\n      string_to_quoted =\n        &Code.string_to_quoted!(&1, token_metadata: true, columns: true, emit_warnings: false)\n\n      file = \"()\"\n\n      assert string_to_quoted.(file) ==\n               {:__block__, [parens: [closing: [line: 1, column: 2], line: 1, column: 1]], []}\n\n      file = \"(())\"\n\n      assert string_to_quoted.(file) ==\n               {:__block__,\n                [\n                  parens: [closing: [line: 1, column: 4], line: 1, column: 1],\n                  parens: [closing: [line: 1, column: 3], line: 1, column: 2]\n                ], []}\n\n      file = \"\"\"\n      (\n        # Foo\n        (\n          # Bar\n        )\n      )\n      \"\"\"\n\n      assert string_to_quoted.(file) ==\n               {:__block__,\n                [\n                  end_of_expression: [newlines: 1, line: 6, column: 2],\n                  parens: [closing: [line: 6, column: 1], line: 1, column: 1],\n                  end_of_expression: [newlines: 1, line: 5, column: 4],\n                  parens: [closing: [line: 5, column: 3], line: 3, column: 3]\n                ], []}\n    end\n\n    test \"adds opening and closing information for stab arguments\" do\n      file = \"fn () -> x end \"\n\n      assert Code.string_to_quoted!(file, token_metadata: true, columns: true) ==\n               {:fn, [closing: [line: 1, column: 12], line: 1, column: 1],\n                [\n                  {:->,\n                   [\n                     parens: [closing: [line: 1, column: 5], line: 1, column: 4],\n                     line: 1,\n                     column: 7\n                   ], [[], {:x, [line: 1, column: 10], nil}]}\n                ]}\n\n      file = \"fn (x, y) -> x end \"\n\n      assert Code.string_to_quoted!(file, token_metadata: true, columns: true) ==\n               {\n                 :fn,\n                 [{:closing, [line: 1, column: 16]}, {:line, 1}, {:column, 1}],\n                 [\n                   {:->,\n                    [\n                      parens: [closing: [line: 1, column: 9], line: 1, column: 4],\n                      line: 1,\n                      column: 11\n                    ],\n                    [\n                      [{:x, [line: 1, column: 5], nil}, {:y, [line: 1, column: 8], nil}],\n                      {:x, [line: 1, column: 14], nil}\n                    ]}\n                 ]\n               }\n\n      file = \"if true do (x, y) -> x end\"\n\n      assert Code.string_to_quoted!(file, token_metadata: true, columns: true) ==\n               {\n                 :if,\n                 [\n                   {:do, [line: 1, column: 9]},\n                   {:end, [line: 1, column: 24]},\n                   {:line, 1},\n                   {:column, 1}\n                 ],\n                 [\n                   true,\n                   [\n                     do: [\n                       {:->,\n                        [\n                          parens: [closing: [line: 1, column: 17], line: 1, column: 12],\n                          line: 1,\n                          column: 19\n                        ],\n                        [\n                          [{:x, [line: 1, column: 13], nil}, {:y, [line: 1, column: 16], nil}],\n                          {:x, [line: 1, column: 22], nil}\n                        ]}\n                     ]\n                   ]\n                 ]\n               }\n    end\n\n    test \"with :literal_encoder\" do\n      opts = [literal_encoder: &{:ok, {:__block__, &2, [&1]}}, token_metadata: true]\n      string_to_quoted = &Code.string_to_quoted!(&1, opts)\n\n      assert string_to_quoted.(~s(\"one\")) == {:__block__, [delimiter: \"\\\"\", line: 1], [\"one\"]}\n      assert string_to_quoted.(\"?é\") == {:__block__, [token: \"?é\", line: 1], [233]}\n      assert string_to_quoted.(\"0b10\") == {:__block__, [token: \"0b10\", line: 1], [2]}\n      assert string_to_quoted.(\"12\") == {:__block__, [token: \"12\", line: 1], [12]}\n      assert string_to_quoted.(\"0o123\") == {:__block__, [token: \"0o123\", line: 1], [83]}\n      assert string_to_quoted.(\"0xEF\") == {:__block__, [token: \"0xEF\", line: 1], [239]}\n      assert string_to_quoted.(\"12.3\") == {:__block__, [token: \"12.3\", line: 1], [12.3]}\n      assert string_to_quoted.(\"nil\") == {:__block__, [line: 1], [nil]}\n      assert string_to_quoted.(\":one\") == {:__block__, [line: 1], [:one]}\n\n      assert string_to_quoted.(\"true\") == {:__block__, [line: 1], [true]}\n      assert string_to_quoted.(\":true\") == {:__block__, [format: :atom, line: 1], [true]}\n\n      assert string_to_quoted.(\"[one: :two]\") == {\n               :__block__,\n               [{:closing, [line: 1]}, {:line, 1}],\n               [\n                 [\n                   {{:__block__, [format: :keyword, line: 1], [:one]},\n                    {:__block__, [line: 1], [:two]}}\n                 ]\n               ]\n             }\n\n      assert string_to_quoted.(\"[1]\") ==\n               {:__block__, [closing: [line: 1], line: 1],\n                [[{:__block__, [token: \"1\", line: 1], [1]}]]}\n\n      assert string_to_quoted.(~s(\"\"\"\\nhello\\n\"\"\")) ==\n               {:__block__, [delimiter: ~s[\"\"\"], indentation: 0, line: 1], [\"hello\\n\"]}\n\n      assert string_to_quoted.(~s[fn (1) -> \"hello\" end]) ==\n               {:fn, [closing: [line: 1], line: 1],\n                [\n                  {:->, [line: 1],\n                   [\n                     [\n                       {:__block__,\n                        [\n                          parens: [closing: [line: 1], line: 1],\n                          token: \"1\",\n                          line: 1\n                        ], [1]}\n                     ],\n                     {:__block__, [delimiter: \"\\\"\", line: 1], [\"hello\"]}\n                   ]}\n                ]}\n\n      assert string_to_quoted.(\"(1)\") ==\n               {:__block__, [parens: [closing: [line: 1], line: 1], token: \"1\", line: 1], [1]}\n    end\n\n    test \"adds identifier_location for qualified identifiers\" do\n      string_to_quoted = &Code.string_to_quoted!(&1, token_metadata: true, columns: true)\n\n      assert string_to_quoted.(\"foo.\\nbar\") ==\n               {{:., [line: 1, column: 4],\n                 [\n                   {:foo, [line: 1, column: 1], nil},\n                   :bar\n                 ]}, [no_parens: true, line: 2, column: 1], []}\n\n      assert string_to_quoted.(\"foo\\n.\\nbar\") ==\n               {{:., [line: 2, column: 1],\n                 [\n                   {:foo, [line: 1, column: 1], nil},\n                   :bar\n                 ]}, [no_parens: true, line: 3, column: 1], []}\n\n      assert string_to_quoted.(~s[Foo.\\nbar(1)]) ==\n               {{:., [line: 1, column: 4],\n                 [\n                   {:__aliases__, [last: [line: 1, column: 1], line: 1, column: 1], [:Foo]},\n                   :bar\n                 ]}, [closing: [line: 2, column: 6], line: 2, column: 1], [1]}\n    end\n\n    test \"adds metadata for the last alias segment\" do\n      string_to_quoted = &Code.string_to_quoted!(&1, token_metadata: true)\n\n      assert string_to_quoted.(\"Foo\") == {:__aliases__, [last: [line: 1], line: 1], [:Foo]}\n\n      assert string_to_quoted.(\"Foo.\\nBar\\n.\\nBaz\") ==\n               {:__aliases__, [last: [line: 4], line: 1], [:Foo, :Bar, :Baz]}\n\n      assert string_to_quoted.(\"foo.\\nBar\\n.\\nBaz\") ==\n               {:__aliases__, [last: [line: 4], line: 1], [{:foo, [line: 1], nil}, :Bar, :Baz]}\n    end\n\n    test \"adds metadata about assoc operator position in maps\" do\n      opts = [\n        literal_encoder: &{:ok, {:__block__, &2, [&1]}},\n        token_metadata: true,\n        columns: true\n      ]\n\n      string_to_quoted = &Code.string_to_quoted!(&1, opts)\n\n      file = \"%{:key => 1, {} => {}}\"\n\n      assert string_to_quoted.(file) ==\n               {\n                 :%{},\n                 [closing: [line: 1, column: 22], line: 1, column: 1],\n                 [\n                   {{:__block__, [assoc: [line: 1, column: 8], line: 1, column: 3], [:key]},\n                    {:__block__, [token: \"1\", line: 1, column: 11], [1]}},\n                   {\n                     {:{},\n                      [\n                        assoc: [line: 1, column: 17],\n                        closing: [line: 1, column: 15],\n                        line: 1,\n                        column: 14\n                      ], []},\n                     {:{}, [closing: [line: 1, column: 21], line: 1, column: 20], []}\n                   }\n                 ]\n               }\n    end\n  end\n\n  describe \"syntax errors\" do\n    test \"invalid heredoc start\" do\n      assert_syntax_error(\n        [\n          \"nofile:1:4:\",\n          ~r/heredoc allows only whitespace characters followed by a new line after opening \\\"\\\"\\\"/\n        ],\n        ~c\"\\\"\\\"\\\"bar\\n\\\"\\\"\\\"\"\n      )\n    end\n\n    test \"invalid fn\" do\n      assert_syntax_error(\n        [\"nofile:1:1:\", \"expected anonymous functions to be defined with -> inside: 'fn'\"],\n        ~c\"fn 1 end\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:2:\", \"unexpected operator ->. If you want to define multiple clauses,\"],\n        ~c\"fn 1\\n2 -> 3 end\"\n      )\n    end\n\n    test \"invalid token\" do\n      assert_syntax_error(\n        [\"nofile:1:1:\", ~s/unexpected token: \"#{\"\\u3164\"}\" (column 1, code point U+3164)/],\n        ~c\"ㅤ = 1\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:7:\", ~s/unexpected token: \"#{\"\\u200B\"}\" (column 7, code point U+200B)/],\n        ~c\"[foo: \\u200B]\\noops\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:1:\", ~s/unexpected token: carriage return (column 1, code point U+000D)/],\n        ~c\"\\r\"\n      )\n    end\n\n    test \"invalid bidi in source\" do\n      assert_syntax_error(\n        [\"nofile:1:1:\", ~s/invalid bidirectional formatting character in comment: \\\\u202A/],\n        ~c\"# This is a \\u202A\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:6:\", \"invalid bidirectional formatting character in comment: \\\\u202A\"],\n        ~c\"foo. # This is a \\u202A\"\n      )\n\n      assert_syntax_error(\n        [\n          \"nofile:1:12:\",\n          \"invalid bidirectional formatting character in string: \\\\u202A. If you want to use such character, use it in its escaped \\\\u202A form instead\"\n        ],\n        ~c\"\\\"this is a \\u202A\\\"\"\n      )\n\n      assert_syntax_error(\n        [\n          \"nofile:1:13:\",\n          \"invalid bidirectional formatting character in string: \\\\u202A. If you want to use such character, use it in its escaped \\\\u202A form instead\"\n        ],\n        ~c\"\\\"this is a \\\\\\u202A\\\"\"\n      )\n    end\n\n    test \"invalid newline in source\" do\n      assert_syntax_error(\n        [\"nofile:1:1:\", ~s/invalid line break character in comment: \\\\u2028/],\n        ~c\"# This is a \\u2028\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:6:\", \"invalid line break character in comment: \\\\u2028\"],\n        ~c\"foo. # This is a \\u2028\"\n      )\n\n      assert_syntax_error(\n        [\n          \"nofile:1:12:\",\n          \"invalid line break character in string: \\\\u2028. If you want to use such character, use it in its escaped \\\\u2028 form instead\"\n        ],\n        ~c\"\\\"this is a \\u2028\\\"\"\n      )\n\n      assert_syntax_error(\n        [\n          \"nofile:1:13:\",\n          \"invalid line break character in string: \\\\u2028. If you want to use such character, use it in its escaped \\\\u2028 form instead\"\n        ],\n        ~c\"\\\"this is a \\\\\\u2028\\\"\"\n      )\n    end\n\n    test \"reserved tokens\" do\n      assert_syntax_error([\"nofile:1:1:\", \"reserved token: __aliases__\"], ~c\"__aliases__\")\n      assert_syntax_error([\"nofile:1:1:\", \"reserved token: __block__\"], ~c\"__block__\")\n    end\n\n    test \"invalid alias terminator\" do\n      assert_syntax_error([\"nofile:1:4:\", \"unexpected ( after alias Foo\"], ~c\"Foo()\")\n    end\n\n    test \"invalid quoted token\" do\n      assert_syntax_error(\n        [\"nofile:1:9:\", \"syntax error before: \\\"world\\\"\"],\n        ~c\"\\\"hello\\\" \\\"world\\\"\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:3:\", \"syntax error before: 'Foobar'\"],\n        ~c\"1 Foobar\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:5:\", \"syntax error before: foo\"],\n        ~c\"Foo.:foo\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:5:\", \"syntax error before: \\\"foo\\\"\"],\n        ~c\"Foo.:\\\"foo\\#{:bar}\\\"\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:5:\", \"syntax error before: \\\"\"],\n        ~c\"Foo.:\\\"\\#{:bar}\\\"\"\n      )\n    end\n\n    test \"invalid identifier\" do\n      message =\n        &[\"nofile:1:1:\", ~s/invalid character \"@\" (code point U+0040) in identifier: #{&1}/]\n\n      assert_syntax_error(message.(\"foo@\"), ~c\"foo@\")\n      assert_syntax_error(message.(\"foo@\"), ~c\"foo@ \")\n      assert_syntax_error(message.(\"foo@bar\"), ~c\"foo@bar\")\n\n      message =\n        &[\"nofile:1:1:\", \"invalid character \\\"@\\\" (code point U+0040) in alias: #{&1}\"]\n\n      assert_syntax_error(message.(\"Foo@\"), ~c\"Foo@\")\n      assert_syntax_error(message.(\"Foo@bar\"), ~c\"Foo@bar\")\n\n      message =\n        [\n          \"nofile:1:1:\",\n          ~s/invalid character \"!\" (code point U+0021) in alias (only ASCII characters, without punctuation, are allowed): Foo!/\n        ]\n\n      assert_syntax_error(message, ~c\"Foo!\")\n\n      message =\n        [\n          \"nofile:1:1:\",\n          ~s/invalid character \"?\" (code point U+003F) in alias (only ASCII characters, without punctuation, are allowed): Foo?/\n        ]\n\n      assert_syntax_error(message, ~c\"Foo?\")\n\n      message =\n        [\n          \"nofile:1:1:\",\n          ~s/invalid character \"ó\" (code point U+00F3) in alias (only ASCII characters, without punctuation, are allowed): Foó/\n        ]\n\n      assert_syntax_error(message, ~c\"Foó\")\n\n      # token suggestion heuristic:\n      #  \"for foO𝚳, NFKC isn't enough because 𝚳 nfkc's to Greek Μ, would be mixed script.\n      #   however the 'confusability skeleton' for that token produces an all-Latin foOM\n      #   and would tokenize -- so suggest that, in case that's what they want\"\n      message = [\n        \"Codepoint failed identifier tokenization, but a simpler form was found.\",\n        \"Got:\",\n        ~s/\"foO𝚳\" (code points 0x00066 0x0006F 0x0004F 0x1D6B3)/,\n        \"Hint: You could write the above in a similar way that is accepted by Elixir:\",\n        ~s/\"foOM\" (code points 0x00066 0x0006F 0x0004F 0x0004D)/,\n        \"See https://hexdocs.pm/elixir/unicode-syntax.html for more information.\"\n      ]\n\n      assert_syntax_error(message, ~c\"foO𝚳\")\n\n      # token suggestion heuristic:\n      #  \"for fooی𝚳, both NKFC and confusability would result in mixed scripts,\n      #   because the Farsi letter is confusable with a different Arabic letter.\n      #   Well, can't fix it all at once -- let's check for a suggestion just on\n      #   the one codepoint that triggered this, the 𝚳 -- that would at least\n      #   nudge them forwards.\"\n      message = [\n        \"Elixir expects unquoted Unicode atoms, variables, and calls to use allowed codepoints and to be in NFC form.\",\n        \"Got:\",\n        ~s/\"𝚳\" (code points 0x1D6B3)/,\n        \"Hint: You could write the above in a compatible format that is accepted by Elixir:\",\n        ~s/\"Μ\" (code points 0x0039C)/,\n        \"See https://hexdocs.pm/elixir/unicode-syntax.html for more information.\"\n      ]\n\n      assert_syntax_error(message, ~c\"fooی𝚳\")\n    end\n\n    test \"keyword missing space\" do\n      msg = [\"nofile:1:1:\", \"keyword argument must be followed by space after: foo:\"]\n\n      assert_syntax_error(msg, \"foo:bar\")\n      assert_syntax_error(msg, \"foo:+\")\n      assert_syntax_error(msg, \"foo:+1\")\n    end\n\n    test \"invalid keyword list in tuple/binary\" do\n      assert_syntax_error(\n        [\"unexpected keyword list inside tuple\"],\n        ~c\"{foo: :bar}\"\n      )\n\n      assert_syntax_error(\n        [\"unexpected keyword list inside tuple\"],\n        ~c\"{foo: :bar, baz: :bar}\"\n      )\n\n      assert_syntax_error(\n        [\"unexpected keyword list inside bitstring\"],\n        ~c\"<<foo: :bar, baz: :bar>>\"\n      )\n    end\n\n    test \"expression after keyword lists\" do\n      assert_syntax_error(\n        [\"unexpected expression after keyword list\"],\n        ~c\"call foo: 1, :bar\"\n      )\n\n      assert_syntax_error(\n        [\"unexpected expression after keyword list\"],\n        ~c\"call(foo: 1, :bar)\"\n      )\n\n      assert_syntax_error(\n        [\"unexpected expression after keyword list\"],\n        ~c\"[foo: 1, :bar]\"\n      )\n\n      assert_syntax_error(\n        [\"unexpected expression after keyword list\"],\n        ~c\"%{foo: 1, :bar => :bar}\"\n      )\n    end\n\n    test \"syntax errors include formatted snippet\" do\n      message = [\"nofile:1:5:\", \"syntax error before:\", \"1 + * 3\", \"^\"]\n      assert_syntax_error(message, \"1 + * 3\")\n    end\n\n    test \"invalid map start\" do\n      assert_syntax_error(\n        [\"nofile:1:7:\", \"expected %{ to define a map, got: %[\"],\n        \"{:ok, %[], %{}}\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:3:\", \"unexpected space between % and {\"],\n        \"% {1, 2, 3}\"\n      )\n    end\n\n    test \"invalid access\" do\n      msg = [\"nofile:1:6:\", \"too many arguments when accessing a value\"]\n      assert_syntax_error(msg, \"foo[1, 2]\")\n      assert_syntax_error(msg, \"foo[1, 2, 3]\")\n      assert_syntax_error(msg, \"foo[1, 2, 3,]\")\n    end\n\n    test \"unexpected end\" do\n      assert_syntax_error([\"nofile:1:3:\", \"unexpected reserved word: end\"], ~c\"1 end\")\n\n      assert_syntax_error(\n        [\n          \"hint:\",\n          \"the \\\"end\\\" on line 2 may not have a matching \\\"do\\\" defined before it (based on indentation)\"\n        ],\n        ~c\"\"\"\n        defmodule MyApp do\n          def one end\n          def two do end\n        end\n        \"\"\"\n      )\n\n      assert_syntax_error(\n        [\n          \"hint:\",\n          \"the \\\"end\\\" on line 3 may not have a matching \\\"do\\\" defined before it (based on indentation)\"\n        ],\n        ~c\"\"\"\n        defmodule MyApp do\n          def one\n          end\n\n          def two do\n          end\n        end\n        \"\"\"\n      )\n\n      assert_syntax_error(\n        [\n          \"hint:\",\n          \"the \\\"end\\\" on line 6 may not have a matching \\\"do\\\" defined before it (based on indentation)\"\n        ],\n        ~c\"\"\"\n        defmodule MyApp do\n          def one do\n          end\n\n          def two\n          end\n        end\n        \"\"\"\n      )\n    end\n\n    test \"invalid keywords\" do\n      assert_syntax_error(\n        [\"nofile:1:2:\", \"syntax error before: '.'\"],\n        ~c\"+.foo\"\n      )\n\n      assert_syntax_error(\n        [\"nofile:1:1:\", \"syntax error before: after. \\\"after\\\" is a reserved word\"],\n        ~c\"after = 1\"\n      )\n    end\n\n    test \"before sigil\" do\n      msg = &[\"nofile:1:9:\", \"syntax error before: sigil ~s starting with content '#{&1}'\"]\n\n      assert_syntax_error(msg.(\"bar baz\"), ~c\"~s(foo) ~s(bar baz)\")\n      assert_syntax_error(msg.(\"\"), ~c\"~s(foo) ~s()\")\n      assert_syntax_error(msg.(\"bar \"), ~c\"~s(foo) ~s(bar \\#{:baz})\")\n      assert_syntax_error(msg.(\"\"), ~c\"~s(foo) ~s(\\#{:bar} baz)\")\n    end\n\n    test \"invalid do\" do\n      assert_syntax_error(\n        [\"nofile:1:10:\", \"unexpected reserved word: do.\"],\n        ~c\"if true, do\\n\"\n      )\n\n      assert_syntax_error([\"nofile:1:9:\", \"unexpected keyword: do:.\"], ~c\"if true do:\\n\")\n    end\n\n    test \"invalid parens call\" do\n      msg =\n        [\n          \"nofile:1:5:\",\n          \"unexpected parentheses\",\n          \"If you are making a function call, do not insert spaces between the function name and the opening parentheses.\",\n          \"Syntax error before: '\\('\"\n        ]\n\n      assert_syntax_error(msg, ~c\"foo (hello, world)\")\n    end\n\n    test \"invalid nested no parens call\" do\n      msg = [\"nofile:1:\", \"unexpected comma. Parentheses are required to solve ambiguity\"]\n\n      assert_syntax_error(msg, ~c\"[foo 1, 2]\")\n      assert_syntax_error(msg, ~c\"[foo bar 1, 2]\")\n      assert_syntax_error(msg, ~c\"[do: foo 1, 2]\")\n      assert_syntax_error(msg, ~c\"foo(do: bar 1, 2)\")\n      assert_syntax_error(msg, ~c\"{foo 1, 2}\")\n      assert_syntax_error(msg, ~c\"{foo bar 1, 2}\")\n      assert_syntax_error(msg, ~c\"foo 1, foo 2, 3\")\n      assert_syntax_error(msg, ~c\"foo 1, @bar 3, 4\")\n      assert_syntax_error(msg, ~c\"foo 1, 2 + bar 3, 4\")\n      assert_syntax_error(msg, ~c\"foo(1, foo 2, 3)\")\n\n      interpret = fn x -> Macro.to_string(Code.string_to_quoted!(x)) end\n      assert interpret.(\"f 1 + g h 2, 3\") == \"f(1 + g(h(2, 3)))\"\n\n      assert interpret.(\"assert [] = TestRepo.all from p in Post, where: p.title in ^[]\") ==\n               \"assert [] = TestRepo.all(from(p in Post, where: p.title in ^[]))\"\n    end\n\n    test \"invalid atom dot alias\" do\n      msg =\n        [\n          \"nofile:1:6:\",\n          \"atom cannot be followed by an alias. If the '.' was meant to be \" <>\n            \"part of the atom's name, the atom name must be quoted. Syntax error before: '.'\"\n        ]\n\n      assert_syntax_error(msg, ~c\":foo.Bar\")\n      assert_syntax_error(msg, ~c\":\\\"+\\\".Bar\")\n    end\n\n    test \"invalid map/struct\" do\n      assert_syntax_error([\"nofile:1:15:\", \"syntax error before: '}'\"], ~c\"%{foo bar, baz}\")\n      assert_syntax_error([\"nofile:1:8:\", \"syntax error before: '{'\"], ~c\"%{a, b}{a: :b}\")\n    end\n\n    test \"mismatching delimiters\" do\n      assert_mismatched_delimiter_error(\n        [\n          \"nofile:1:9:\",\n          \"unexpected token:\",\n          \"└ unclosed delimiter\",\n          \"└ mismatched closing delimiter\"\n        ],\n        ~c\"fn a -> )\"\n      )\n\n      assert_mismatched_delimiter_error(\n        [\n          \"nofile:1:16:\",\n          \"unexpected token:\",\n          \"└ unclosed delimiter\",\n          \"└ mismatched closing delimiter\"\n        ],\n        ~c\"defmodule A do ]\"\n      )\n\n      assert_mismatched_delimiter_error(\n        [\n          \"nofile:1:9:\",\n          \"unexpected token:\",\n          \"└ unclosed delimiter\",\n          \"└ mismatched closing delimiter\"\n        ],\n        ~c\"(1, 2, 3}\"\n      )\n\n      assert_mismatched_delimiter_error(\n        [\n          \"nofile:1:14:\",\n          \"unexpected reserved word:\",\n          \"└ unclosed delimiter\",\n          \"└ mismatched closing delimiter\"\n        ],\n        ~c\"<<1, 2, 3, 4 end\"\n      )\n    end\n\n    test \"invalid interpolation\" do\n      assert_mismatched_delimiter_error(\n        [\n          \"nofile:1:17:\",\n          \"unexpected token:\",\n          \"└ unclosed delimiter\",\n          \"└ mismatched closing delimiter\"\n        ],\n        ~c\"\\\"foo\\#{case 1 do )}bar\\\"\"\n      )\n\n      assert_mismatched_delimiter_error(\n        [\n          \"nofile:8:3:\",\n          \"unexpected token: )\",\n          \"└ unclosed delimiter\",\n          \"└ mismatched closing delimiter\"\n        ],\n        ~c\"\"\"\n        defmodule MyApp do\n          (\n            def one do\n            # end\n\n            def two do\n            end\n          )\n        end\n        \"\"\"\n      )\n    end\n\n    test \"invalid end of expression\" do\n      # All valid examples\n      Code.eval_quoted(~c\"\"\"\n      1;\n      2;\n      3\n\n      (;)\n      (;1)\n      (1;)\n      (1; 2)\n\n      fn -> 1; 2 end\n      fn -> ; end\n\n      if true do\n        ;\n      end\n\n      try do\n        ;\n      catch\n        _, _ -> ;\n      after\n        ;\n      end\n      \"\"\")\n\n      # All invalid examples\n      assert_syntax_error([\"nofile:1:3:\", \"syntax error before: ';'\"], ~c\"1+;\\n2\")\n\n      assert_syntax_error([\"nofile:1:8:\", \"syntax error before: ';'\"], ~c\"max(1, ;2)\")\n    end\n\n    test \"invalid new line\" do\n      assert_syntax_error(\n        [\n          \"nofile:3:6:\",\n          \"unexpectedly reached end of line. The current expression is invalid or incomplete\",\n          \"baz\",\n          \"^\"\n        ],\n        ~c\"if true do\\n  foo = [],\\n  baz\\nend\"\n      )\n    end\n\n    test \"invalid \\\"fn do expr end\\\"\" do\n      assert_syntax_error(\n        [\n          \"nofile:1:4:\",\n          \"unexpected reserved word: do. Anonymous functions are written as:\",\n          \"fn pattern -> expression end\",\n          \"Please remove the \\\"do\\\" keyword\",\n          \"fn do :ok end\",\n          \"^\"\n        ],\n        ~c\"fn do :ok end\"\n      )\n    end\n\n    test \"characters literal are printed correctly in syntax errors\" do\n      assert_syntax_error([\"nofile:1:5:\", \"syntax error before: ?a\"], ~c\":ok ?a\")\n      assert_syntax_error([\"nofile:1:5:\", \"syntax error before: ?\\\\s\"], ~c\":ok ?\\\\s\")\n      assert_syntax_error([\"nofile:1:5:\", \"syntax error before: ?す\"], ~c\":ok ?す\")\n    end\n\n    test \"character literals take newlines into account\" do\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        assert parse!(\"{?\\n}\\n{123}\") ==\n                 {:__block__, [], [{:{}, [line: 1], ~c\"\\n\"}, {:{}, [line: 3], ~c\"{\"}]}\n\n        assert parse!(\"{?\\\\n}\\n{123}\") ==\n                 {:__block__, [], [{:{}, [line: 1], ~c\"\\n\"}, {:{}, [line: 2], ~c\"{\"}]}\n\n        assert parse!(\"{?\\\\\\n}\\n{123}\") ==\n                 {:__block__, [], [{:{}, [line: 1], ~c\"\\n\"}, {:{}, [line: 3], ~c\"{\"}]}\n      end)\n    end\n\n    test \"numbers are printed correctly in syntax errors\" do\n      assert_syntax_error([\"nofile:1:5:\", ~s/syntax error before: \"12\"/], ~c\":ok 12\")\n      assert_syntax_error([\"nofile:1:5:\", ~s/syntax error before: \"0b1\"/], ~c\":ok 0b1\")\n      assert_syntax_error([\"nofile:1:5:\", ~s/syntax error before: \"12.3\"/], ~c\":ok 12.3\")\n\n      assert_syntax_error(\n        [\"nofile:1:1:\", ~s/invalid character \"_\" after number 123_456/],\n        ~c\"123_456_foo\"\n      )\n    end\n\n    test \"on hex errors\" do\n      msg =\n        \"invalid hex escape character, expected \\\\xHH where H is a hexadecimal digit. Syntax error after: \\\\x\"\n\n      assert_syntax_error([\"nofile:1:2:\", msg], ~S[\"\\x\"])\n      assert_syntax_error([\"nofile:1:1:\", msg], ~S[:\"\\x\"])\n      assert_syntax_error([\"nofile:1:2:\", msg], ~S[\"\\x\": 123])\n      assert_syntax_error([\"nofile:1:1:\", msg], ~s[\"\"\"\\n\\\\x\\n\"\"\"])\n    end\n\n    test \"on unicode errors\" do\n      msg = \"invalid Unicode escape character\"\n\n      assert_syntax_error([\"nofile:1:2:\", msg], ~S[\"\\u\"])\n      assert_syntax_error([\"nofile:1:1:\", msg], ~S[:\"\\u\"])\n      assert_syntax_error([\"nofile:1:2:\", msg], ~S[\"\\u\": 123])\n      assert_syntax_error([\"nofile:1:1:\", msg], ~s[\"\"\"\\n\\\\u\\n\"\"\"])\n\n      assert_syntax_error(\n        [\n          \"nofile:1:2:\",\n          \"invalid or reserved Unicode code point \\\\u{FFFFFF}. Syntax error after: \\\\u\"\n        ],\n        ~S[\"\\u{FFFFFF}\"]\n      )\n    end\n\n    test \"on interpolation in calls\" do\n      msg =\n        \"interpolation is not allowed when calling function/macro. Found interpolation in a call starting with: \\\"\"\n\n      assert_syntax_error([msg], \".\\\"\\#{}\\\"\")\n      assert_syntax_error([msg], \".\\\"a\\#{:b}\\\"c\")\n    end\n\n    test \"on long atoms\" do\n      atom =\n        \"@GR{+z]`_XrNla!d<GTZ]iw[s'l2N<5hGD0(.xh&}>0ptDp(amr.oS&<q(FA)5T3=},^{=JnwIOE*DPOslKV KF-kb7NF&Y#Lp3D7l/!s],^hnz1iB |E8~Y'-Rp&*E(O}|zoB#xsE.S/~~'=%H'2HOZu0PCfz6j=eHq5:yk{7&|}zeRONM+KWBCAUKWFw(tv9vkHTu#Ek$&]Q:~>,UbT}v$L|rHHXGV{;W!>avHbD[T-G5xrzR6m?rQPot-37B@\"\n\n      assert_syntax_error(\n        [\"atom length must be less than system limit: \"],\n        ~s{:\"#{atom}\"}\n      )\n\n      assert_syntax_error(\n        [\"atom length must be less than system limit: \"],\n        ~s{[\"#{atom}\": 123]}\n      )\n    end\n  end\n\n  defp parse!(string), do: Code.string_to_quoted!(string)\n\n  defp assert_syntax_error(given_messages, source) do\n    e = assert_raise SyntaxError, fn -> parse!(source) end\n    assert_exception_msg(e, given_messages)\n  end\n\n  defp assert_mismatched_delimiter_error(given_messages, source) do\n    e = assert_raise MismatchedDelimiterError, fn -> parse!(source) end\n    assert_exception_msg(e, given_messages)\n  end\n\n  defp assert_exception_msg(exception, messages) do\n    error_msg = Exception.format(:error, exception, [])\n\n    for msg <- messages do\n      assert error_msg =~ msg\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/quote_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.QuoteTest do\n  use ExUnit.Case, async: true\n\n  @some_fun &List.flatten/1\n\n  test \"fun\" do\n    assert is_function(@some_fun)\n  end\n\n  test \"list\" do\n    assert quote(do: [1, 2, 3]) == [1, 2, 3]\n  end\n\n  test \"tuple\" do\n    assert quote(do: {:a, 1}) == {:a, 1}\n  end\n\n  test \"keep line\" do\n    line = __ENV__.line + 2\n\n    assert quote(location: :keep, do: bar(1, 2, 3)) ==\n             {:bar, [keep: {__ENV__.file, line}], [1, 2, 3]}\n  end\n\n  test \"fixed line\" do\n    assert quote(line: 3, do: bar(1, 2, 3)) == {:bar, [line: 3], [1, 2, 3]}\n    assert quote(line: false, do: bar(1, 2, 3)) == {:bar, [], [1, 2, 3]}\n    assert quote(line: true, do: bar(1, 2, 3)) == {:bar, [line: __ENV__.line], [1, 2, 3]}\n  end\n\n  test \"file line\" do\n    assert quote(file: \"foo\", line: 3, do: bar(1, 2, 3)) ==\n             {:bar, [keep: {\"foo\", 3}], [1, 2, 3]}\n\n    assert quote(file: \"foo\", line: false, do: bar(1, 2, 3)) ==\n             {:bar, [keep: {\"foo\", 0}], [1, 2, 3]}\n\n    assert quote(file: \"foo\", line: true, do: bar(1, 2, 3)) ==\n             {:bar, [keep: {\"foo\", __ENV__.line - 1}], [1, 2, 3]}\n  end\n\n  test \"quote line var\" do\n    line = __ENV__.line\n    assert quote(line: line, do: bar(1, 2, 3)) == {:bar, [line: line], [1, 2, 3]}\n\n    assert_raise ArgumentError, fn ->\n      line = \"oops\"\n      quote(line: line, do: bar(1, 2, 3))\n    end\n\n    assert_raise ArgumentError, fn ->\n      line = true\n      quote(line: line, do: bar(1, 2, 3))\n    end\n  end\n\n  test \"quote context var\" do\n    context = :dynamic\n    assert quote(context: context, do: bar) == {:bar, [], :dynamic}\n\n    assert_raise ArgumentError, fn ->\n      context = \"oops\"\n      quote(context: context, do: bar)\n    end\n\n    assert_raise ArgumentError, fn ->\n      context = nil\n      quote(context: context, do: bar)\n    end\n  end\n\n  test \"quote context bind_quoted\" do\n    assert {:__block__, _,\n            [{:=, [], [{:some_var, _, :fallback}, 321]}, {:some_var, _, :fallback}]} =\n             (quote bind_quoted: [some_var: 321], context: __ENV__.context || :fallback do\n                some_var\n              end)\n  end\n\n  test \"operator precedence\" do\n    assert {:+, _, [{:+, _, [1, _]}, 1]} = quote(do: 1 + Foo.l() + 1)\n    assert {:+, _, [1, {_, _, [{:+, _, [1]}]}]} = quote(do: 1 + Foo.l(+1))\n  end\n\n  test \"generated\" do\n    assert quote(generated: true, do: bar(1)) == {:bar, [generated: true], [1]}\n  end\n\n  test \"unquote call\" do\n    assert quote(do: foo(bar)[unquote(:baz)]) == quote(do: foo(bar)[:baz])\n    assert quote(do: unquote(:bar)()) == quote(do: bar())\n\n    assert (quote do\n              unquote(:bar)(1) do\n                2 + 3\n              end\n            end) ==\n             (quote do\n                bar 1 do\n                  2 + 3\n                end\n              end)\n\n    assert quote(do: foo.unquote(:bar)) == quote(do: foo.bar)\n    assert quote(do: foo.unquote(:bar)()) == quote(do: foo.bar())\n    assert quote(do: foo.unquote(:bar)(1)) == quote(do: foo.bar(1))\n\n    assert (quote do\n              foo.unquote(:bar)(1) do\n                2 + 3\n              end\n            end) ==\n             (quote do\n                foo.bar 1 do\n                  2 + 3\n                end\n              end)\n\n    assert quote(do: foo.unquote({:bar, [], nil})) == quote(do: foo.bar)\n    assert quote(do: foo.unquote({:bar, [], nil})()) == quote(do: foo.bar())\n    assert quote(do: foo.unquote({:bar, [], [1, 2]})) == quote(do: foo.bar(1, 2))\n\n    assert Code.eval_quoted(quote(do: Foo.unquote(Bar))) == {Elixir.Foo.Bar, []}\n    assert Code.eval_quoted(quote(do: Foo.unquote(quote(do: Bar)))) == {Elixir.Foo.Bar, []}\n\n    assert_raise ArgumentError, fn ->\n      quote(do: foo.unquote(1))\n    end\n  end\n\n  test \"unquote call with dynamic line\" do\n    assert quote(line: String.to_integer(\"123\"), do: Foo.unquote(:bar)()) ==\n             quote(line: 123, do: Foo.bar())\n  end\n\n  test \"nested quote\" do\n    assert {:quote, _, [[do: {:unquote, _, _}]]} = quote(do: quote(do: unquote(x)))\n  end\n\n  test \"import inside nested quote\" do\n    # Check that we can evaluate imports from quote inside quote\n    assert {{:to_string, meta, [123]}, _} = Code.eval_quoted(quote(do: quote(do: to_string(123))))\n    assert meta[:imports] == [{1, Kernel}]\n  end\n\n  defmacrop nested_quote_in_macro do\n    x = 1\n\n    quote do\n      x = unquote(x)\n\n      quote do\n        unquote(x)\n      end\n    end\n  end\n\n  test \"nested quote in macro\" do\n    assert nested_quote_in_macro() == 1\n  end\n\n  defmodule Dyn do\n    for {k, v} <- [foo: 1, bar: 2, baz: 3] do\n      # Local call unquote\n      def unquote(k)(), do: unquote(v)\n\n      # Remote call unquote\n      def unquote(k)(arg), do: __MODULE__.unquote(k)() + arg\n    end\n  end\n\n  test \"dynamic definition with unquote\" do\n    assert Dyn.foo() == 1\n    assert Dyn.bar() == 2\n    assert Dyn.baz() == 3\n\n    assert Dyn.foo(1) == 2\n    assert Dyn.bar(2) == 4\n    assert Dyn.baz(3) == 6\n  end\n\n  test \"splice on root\" do\n    contents = [1, 2, 3]\n\n    assert quote(do: (unquote_splicing(contents))) ==\n             (quote do\n                1\n                2\n                3\n              end)\n  end\n\n  test \"splice with tail\" do\n    contents = [1, 2, 3]\n\n    assert quote(do: [unquote_splicing(contents) | [1, 2, 3]]) == [1, 2, 3, 1, 2, 3]\n\n    assert quote(do: [unquote_splicing(contents) | val]) == quote(do: [1, 2, 3 | val])\n\n    assert quote(do: [unquote_splicing(contents) | unquote([4])]) == quote(do: [1, 2, 3, 4])\n  end\n\n  test \"splice on stab\" do\n    {fun, []} = Code.eval_quoted(quote(do: fn unquote_splicing([1, 2, 3]) -> :ok end), [])\n    assert fun.(1, 2, 3) == :ok\n\n    {fun, []} = Code.eval_quoted(quote(do: fn 1, unquote_splicing([2, 3]) -> :ok end), [])\n    assert fun.(1, 2, 3) == :ok\n  end\n\n  test \"splice on definition\" do\n    defmodule Hello do\n      def world([unquote_splicing([\"foo\", \"bar\"]) | rest]) do\n        rest\n      end\n    end\n\n    assert Hello.world([\"foo\", \"bar\", \"baz\"]) == [\"baz\"]\n  end\n\n  test \"splice on map\" do\n    assert %{unquote_splicing(foo: :bar)} == %{foo: :bar}\n    assert %{unquote_splicing(foo: :bar), baz: :bat} == %{foo: :bar, baz: :bat}\n    assert %{unquote_splicing(foo: :bar), :baz => :bat} == %{foo: :bar, baz: :bat}\n    assert %{:baz => :bat, unquote_splicing(foo: :bar)} == %{foo: :bar, baz: :bat}\n\n    map = %{foo: :default}\n    assert %{map | unquote_splicing(foo: :bar)} == %{foo: :bar}\n  end\n\n  test \"when\" do\n    assert [{:->, _, [[{:when, _, [1, 2, 3, 4]}], 5]}] = quote(do: (1, 2, 3 when 4 -> 5))\n\n    assert [{:->, _, [[{:when, _, [1, 2, 3, {:when, _, [4, 5]}]}], 6]}] =\n             quote(do: (1, 2, 3 when 4 when 5 -> 6))\n  end\n\n  test \"stab\" do\n    assert [{:->, _, [[], 1]}] =\n             (quote do\n                () -> 1\n              end)\n\n    assert [{:->, _, [[], 1]}] = quote(do: (-> 1))\n  end\n\n  test \"empty block\" do\n    # Since ; is allowed by itself, it must also be allowed inside ()\n    # The exception to this rule is an empty (). While empty expressions\n    # are allowed, an empty () is ambiguous. We also can't use quote here,\n    # since the formatter will rewrite (;) to something else.\n    assert {:ok, {:__block__, [line: 1], []}} = Code.string_to_quoted(\"(;)\")\n  end\n\n  test \"bind quoted\" do\n    args = [\n      {:=, [], [{:foo, [line: __ENV__.line + 4], Kernel.QuoteTest}, 3]},\n      {:foo, [], Kernel.QuoteTest}\n    ]\n\n    quoted = quote(bind_quoted: [foo: 1 + 2], do: foo)\n    assert quoted == {:__block__, [], args}\n  end\n\n  test \"literals\" do\n    assert quote(do: []) == []\n    assert quote(do: nil) == nil\n\n    assert (quote do\n              []\n            end) == []\n\n    assert (quote do\n              nil\n            end) == nil\n  end\n\n  defmacrop dynamic_opts do\n    [line: 3]\n  end\n\n  test \"with dynamic opts\" do\n    assert quote(dynamic_opts(), do: bar(1, 2, 3)) == {:bar, [line: 3], [1, 2, 3]}\n  end\n\n  test \"unary with integer precedence\" do\n    assert quote(do: +1.foo) == quote(do: +1.foo)\n    assert quote(do: (@1).foo) == quote(do: (@1).foo)\n    assert quote(do: &1.foo) == quote(do: &1.foo)\n  end\n\n  test \"pipe precedence\" do\n    assert {:|>, _, [{:|>, _, [{:foo, _, _}, {:bar, _, _}]}, {:baz, _, _}]} =\n             quote(do: foo |> bar |> baz)\n\n    assert {:|>, _, [{:|>, _, [{:foo, _, _}, {:bar, _, _}]}, {:baz, _, _}]} =\n             (quote do\n                foo do\n                end\n                |> bar\n                |> baz\n              end)\n\n    assert {:|>, _, [{:|>, _, [{:foo, _, _}, {:bar, _, _}]}, {:baz, _, _}]} =\n             (quote do\n                foo\n                |> bar do\n                end\n                |> baz\n              end)\n\n    assert {:|>, _, [{:|>, _, [{:foo, _, _}, {:bar, _, _}]}, {:baz, _, _}]} =\n             (quote do\n                foo\n                |> bar\n                |> baz do\n                end\n              end)\n\n    assert {:|>, _, [{:|>, _, [{:foo, _, _}, {:bar, _, _}]}, {:baz, _, _}]} =\n             (quote do\n                foo do\n                end\n                |> bar\n                |> baz do\n                end\n              end)\n\n    assert {:|>, _, [{:|>, _, [{:foo, _, _}, {:bar, _, _}]}, {:baz, _, _}]} =\n             (quote do\n                foo do\n                end\n                |> bar do\n                end\n                |> baz do\n                end\n              end)\n  end\n\n  test \"capture\" do\n    assert Code.string_to_quoted!(\"&1[:foo]\") == Code.string_to_quoted!(\"(&1)[:foo]\")\n    assert Code.string_to_quoted!(\"&1 [:foo]\") == Code.string_to_quoted!(\"(&1)[:foo]\")\n    assert Code.string_to_quoted!(\"& 1[:foo]\") == Code.string_to_quoted!(\"&(1[:foo])\")\n  end\n\n  test \"not and ! as rearrange ops\" do\n    assert {:__block__, _, [{:not, [line: 1], [true]}]} = Code.string_to_quoted!(\"(not true)\")\n\n    assert {:fn, _, [{:->, _, [[], {:not, _, [true]}]}]} =\n             Code.string_to_quoted!(\"fn -> not true end\")\n  end\nend\n\ndefmodule Kernel.QuoteTest.Errors do\n  def line, do: __ENV__.line + 4\n\n  defmacro defraise do\n    quote location: :keep do\n      def will_raise(_a, _b), do: raise(\"oops\")\n    end\n  end\n\n  defmacro will_raise do\n    quote(location: :keep, do: raise(\"oops\"))\n  end\nend\n\ndefmodule Kernel.QuoteTest.ErrorsTest do\n  use ExUnit.Case, async: true\n  import Kernel.QuoteTest.Errors\n\n  # Defines the add function\n  defraise()\n\n  @line line()\n  test \"inside function error\" do\n    try do\n      will_raise(:a, :b)\n    rescue\n      RuntimeError ->\n        mod = Kernel.QuoteTest.ErrorsTest\n        file = __ENV__.file |> Path.relative_to_cwd() |> String.to_charlist()\n        assert [{^mod, :will_raise, 2, [file: ^file, line: @line] ++ _} | _] = __STACKTRACE__\n    end\n  end\n\n  @line __ENV__.line + 3\n  test \"outside function error\" do\n    try do\n      will_raise()\n      flunk(\"expected failure\")\n    rescue\n      RuntimeError ->\n        mod = Kernel.QuoteTest.ErrorsTest\n        file = __ENV__.file |> Path.relative_to_cwd() |> String.to_charlist()\n        assert [{^mod, _, _, [file: ^file, line: @line] ++ _} | _] = __STACKTRACE__\n    end\n  end\nend\n\ndefmodule Kernel.QuoteTest.VarHygiene do\n  defmacro no_interference do\n    quote(do: a = 1)\n  end\n\n  defmacro write_interference do\n    quote(do: var!(a) = 1)\n  end\n\n  defmacro read_interference do\n    quote(do: 10 = var!(a))\n  end\n\n  defmacro cross_module_interference do\n    quote(do: var!(a, Kernel.QuoteTest.VarHygieneTest) = 1)\n  end\nend\n\ndefmodule Kernel.QuoteTest.VarHygieneTest do\n  use ExUnit.Case, async: true\n  import Kernel.QuoteTest.VarHygiene\n\n  defmacrop cross_module_no_interference do\n    quote(do: a = 10)\n  end\n\n  defmacrop read_cross_module do\n    quote(do: var!(a, __MODULE__))\n  end\n\n  defmacrop nested(var, do: block) do\n    quote do\n      var = unquote(var)\n      unquote(block)\n      var\n    end\n  end\n\n  defmacrop hat do\n    quote do\n      var = 1\n      ^var = 1\n      var\n    end\n  end\n\n  test \"no interference\" do\n    a = 10\n    no_interference()\n    assert a == 10\n  end\n\n  test \"cross module interference\" do\n    cross_module_no_interference()\n    cross_module_interference()\n    assert read_cross_module() == 1\n  end\n\n  test \"write interference\" do\n    write_interference()\n    assert a == 1\n  end\n\n  test \"read interference\" do\n    a = 10\n    read_interference()\n  end\n\n  test \"hat\" do\n    assert hat() == 1\n  end\n\n  test \"nested macro\" do\n    assert (nested 1 do\n              nested 2 do\n                _ = :ok\n              end\n            end) == 1\n  end\n\n  test \"nested quoted\" do\n    defmodule NestedQuote do\n      defmacro __using__(_) do\n        quote unquote: false do\n          arg = quote(do: arg)\n\n          def test(arg) do\n            unquote(arg)\n          end\n        end\n      end\n    end\n\n    defmodule UseNestedQuote do\n      use NestedQuote\n    end\n\n    assert UseNestedQuote.test(\"foo\") == \"foo\"\n  end\n\n  test \"nested bind quoted\" do\n    defmodule NestedBindQuoted do\n      defmacrop macro(arg) do\n        quote bind_quoted: [arg: arg] do\n          quote bind_quoted: [arg: arg], do: String.duplicate(arg, 2)\n        end\n      end\n\n      defmacro __using__(_) do\n        quote do\n          def test do\n            unquote(macro(\"foo\"))\n          end\n        end\n      end\n    end\n\n    defmodule UseNestedBindQuoted do\n      use NestedBindQuoted\n    end\n\n    assert UseNestedBindQuoted.test() == \"foofoo\"\n  end\nend\n\ndefmodule Kernel.QuoteTest.AliasHygiene do\n  alias Dict, as: SuperDict\n\n  defmacro dict do\n    quote(do: Dict.Bar)\n  end\n\n  defmacro super_dict do\n    quote(do: SuperDict.Bar)\n  end\nend\n\ndefmodule Kernel.QuoteTest.AliasHygieneTest do\n  use ExUnit.Case, async: true\n\n  alias Dict, as: SuperDict\n\n  test \"annotate aliases\" do\n    assert {:__aliases__, [alias: false], [:Foo, :Bar]} = quote(do: Foo.Bar)\n    assert {:__aliases__, [alias: false], [:Dict, :Bar]} = quote(do: Dict.Bar)\n    assert {:__aliases__, [alias: Dict.Bar], [:SuperDict, :Bar]} = quote(do: SuperDict.Bar)\n\n    # Edge-case\n    assert {:__aliases__, _, [Elixir]} = quote(do: Elixir)\n  end\n\n  test \"expand aliases\" do\n    assert Code.eval_quoted(quote(do: SuperDict.Bar)) == {Elixir.Dict.Bar, []}\n    assert Code.eval_quoted(quote(do: alias!(SuperDict.Bar))) == {Elixir.SuperDict.Bar, []}\n  end\n\n  test \"expand aliases without macro\" do\n    alias HashDict, as: SuperDict\n    assert SuperDict.Bar == Elixir.HashDict.Bar\n  end\n\n  test \"expand aliases with macro does not expand source alias\" do\n    alias HashDict, as: Dict, warn: false\n    require Kernel.QuoteTest.AliasHygiene\n    assert Kernel.QuoteTest.AliasHygiene.dict() == Elixir.Dict.Bar\n  end\n\n  test \"expand aliases with macro has higher preference\" do\n    alias HashDict, as: SuperDict, warn: false\n    require Kernel.QuoteTest.AliasHygiene\n    assert Kernel.QuoteTest.AliasHygiene.super_dict() == Elixir.Dict.Bar\n  end\nend\n\ndefmodule Kernel.QuoteTest.ImportsHygieneTest do\n  use ExUnit.Case, async: true\n\n  # We are redefining |> and using it inside the quote\n  # and only inside the quote. This code should still compile.\n  defmacro x |> f do\n    quote do\n      unquote(x) |> unquote(f)\n    end\n  end\n\n  defmacrop get_list_length do\n    quote do\n      length(~c\"hello\")\n    end\n  end\n\n  defmacrop get_list_length_with_pipe do\n    quote do\n      ~c\"hello\" |> length()\n    end\n  end\n\n  defmacrop get_list_length_with_partial do\n    quote do\n      (&length(&1)).(~c\"hello\")\n    end\n  end\n\n  defmacrop get_list_length_with_function do\n    quote do\n      (&length/1).(~c\"hello\")\n    end\n  end\n\n  test \"expand imports\" do\n    import Kernel, except: [length: 1]\n    assert get_list_length() == 5\n    assert get_list_length_with_pipe() == 5\n    assert get_list_length_with_partial() == 5\n    assert get_list_length_with_function() == 5\n  end\n\n  defmacrop get_string_length do\n    import Kernel, except: [length: 1]\n\n    quote do\n      length(\"hello\")\n    end\n  end\n\n  test \"lazy expand imports\" do\n    import Kernel, except: [length: 1]\n    import String, only: [length: 1]\n    assert get_string_length() == 5\n  end\n\n  test \"lazy expand imports no conflicts\" do\n    import Kernel, except: [length: 1]\n    import String, only: [length: 1], warn: false\n\n    assert get_list_length() == 5\n    assert get_list_length_with_partial() == 5\n    assert get_list_length_with_function() == 5\n  end\n\n  defmacrop with_length do\n    quote do\n      import Kernel, except: [length: 1]\n      import String, only: [length: 1]\n      length(~c\"hello\")\n    end\n  end\n\n  test \"explicitly overridden imports\" do\n    assert with_length() == 5\n  end\n\n  defmodule BinaryUtils do\n    defmacro int32 do\n      quote do\n        integer - size(32)\n      end\n    end\n  end\n\n  test \"checks the context also for variables to zero-arity functions\" do\n    import BinaryUtils\n    {:int32, meta, __MODULE__} = quote(do: int32)\n    assert meta[:imports] == [{0, BinaryUtils}]\n  end\nend\n\ndefmodule Kernel.QuoteTest.HasUnquoteTest do\n  use ExUnit.Case, async: true\n\n  test \"expression without unquote returns false\" do\n    ast =\n      quote unquote: false do\n        opts = [x: 5]\n        x = Keyword.fetch!(opts, :x)\n        x + 1\n      end\n\n    refute :elixir_quote.has_unquotes(ast)\n  end\n\n  test \"expression with unquote returns true\" do\n    ast =\n      quote unquote: false do\n        [x: unquote(x)]\n      end\n\n    assert :elixir_quote.has_unquotes(ast)\n\n    ast =\n      quote unquote: false do\n        unquote(module).fun(x)\n      end\n\n    assert :elixir_quote.has_unquotes(ast)\n\n    ast =\n      quote unquote: false do\n        module.unquote(fun)(x)\n      end\n\n    assert :elixir_quote.has_unquotes(ast)\n\n    ast =\n      quote unquote: false do\n        module.fun(unquote(x))\n      end\n\n    assert :elixir_quote.has_unquotes(ast)\n\n    ast =\n      quote unquote: false do\n        module.fun(unquote_splicing(args))\n      end\n\n    assert :elixir_quote.has_unquotes(ast)\n  end\n\n  test \"expression with unquote within quote returns false\" do\n    ast =\n      quote unquote: false do\n        quote do\n          x + unquote(y)\n        end\n      end\n\n    refute :elixir_quote.has_unquotes(ast)\n\n    ast =\n      quote unquote: false do\n        quote do\n          foo = bar(unquote_splicing(args))\n        end\n      end\n\n    refute :elixir_quote.has_unquotes(ast)\n  end\n\n  test \"expression with unquote within unquote within quote returns true\" do\n    ast =\n      quote unquote: false do\n        quote do\n          x + unquote(unquote(y))\n        end\n      end\n\n    assert :elixir_quote.has_unquotes(ast)\n\n    ast =\n      quote unquote: false do\n        quote do\n          foo = bar(unquote_splicing(unquote(args)))\n        end\n      end\n\n    assert :elixir_quote.has_unquotes(ast)\n\n    ast =\n      quote unquote: false do\n        quote do\n          foo = bar(unquote(unquote_splicing(args)))\n        end\n      end\n\n    assert :elixir_quote.has_unquotes(ast)\n  end\n\n  test \"expression within quote disabling unquotes always returns false\" do\n    ast =\n      quote unquote: false do\n        quote unquote: false do\n          x + unquote(unquote(y))\n        end\n      end\n\n    refute :elixir_quote.has_unquotes(ast)\n\n    ast =\n      quote unquote: false do\n        quote bind_quoted: [x: x] do\n          x + unquote(unquote(y))\n        end\n      end\n\n    refute :elixir_quote.has_unquotes(ast)\n  end\n\n  test \"unquote with invalid AST (shallow check)\" do\n    for term <- [\n          %{unescaped: :map},\n          1..10,\n          {:bad_meta, nil, []},\n          {:bad_arg, nil, 1},\n          {:bad_tuple},\n          make_ref(),\n          [:improper | :list],\n          [nested: {}]\n        ] do\n      message = \"\"\"\n      tried to unquote invalid AST: #{inspect(term)}\n      Did you forget to escape term using Macro.escape/1?\\\n      \"\"\"\n\n      assert_raise ArgumentError, message, fn -> quote do: unquote(term) end\n    end\n  end\n\n  test \"unquote with invalid AST is not checked deeply\" do\n    assert quote do: unquote(foo: [1 | 2]) == [foo: [1 | 2]]\n    assert quote do: unquote(foo: [bar: %{}]) == [foo: [bar: %{}]]\n  end\n\n  test \"unquote_splicing with invalid AST\" do\n    for args <- [\n          \"not_a_list\",\n          [:improper | :list],\n          [%{unescaped: :map}],\n          [1..10],\n          [{:bad_meta, nil, []}],\n          [{:bad_arg, nil, 1}],\n          [{:bad_tuple}],\n          [make_ref()],\n          [nested: {}]\n        ] do\n      message =\n        \"expected a list with quoted expressions in unquote_splicing/1, got: #{inspect(args)}\"\n\n      assert_raise ArgumentError, message, fn -> quote do: [unquote_splicing(args)] end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/raise_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.RaiseTest do\n  use ExUnit.Case, async: true\n\n  # Silence warnings\n  defp atom, do: RuntimeError\n  defp binary, do: \"message\"\n  defp opts, do: [message: \"message\"]\n  defp struct, do: %RuntimeError{message: \"message\"}\n\n  @compile {:no_warn_undefined, DoNotExist}\n  @trace [{:foo, :bar, 0, []}]\n\n  test \"raise preserves the stacktrace\" do\n    stacktrace =\n      try do\n        raise \"a\"\n      rescue\n        _ -> Enum.fetch!(__STACKTRACE__, 0)\n      end\n\n    file = __ENV__.file |> Path.relative_to_cwd() |> String.to_charlist()\n\n    assert {__MODULE__, :\"test raise preserves the stacktrace\", _, [file: ^file, line: 22] ++ _} =\n             stacktrace\n  end\n\n  test \"raise message\" do\n    assert_raise RuntimeError, \"message\", fn ->\n      raise \"message\"\n    end\n\n    assert_raise RuntimeError, \"message\", fn ->\n      var = binary()\n      raise var\n    end\n  end\n\n  test \"raise with no arguments\" do\n    assert_raise RuntimeError, fn ->\n      raise RuntimeError\n    end\n\n    assert_raise RuntimeError, fn ->\n      var = atom()\n      raise var\n    end\n  end\n\n  test \"raise with arguments\" do\n    assert_raise RuntimeError, \"message\", fn ->\n      raise RuntimeError, message: \"message\"\n    end\n\n    assert_raise RuntimeError, \"message\", fn ->\n      atom = atom()\n      opts = opts()\n      raise atom, opts\n    end\n  end\n\n  test \"raise existing exception\" do\n    assert_raise RuntimeError, \"message\", fn ->\n      raise %RuntimeError{message: \"message\"}\n    end\n\n    assert_raise RuntimeError, \"message\", fn ->\n      var = struct()\n      raise var\n    end\n  end\n\n  test \"raise with error_info\" do\n    {exception, stacktrace} =\n      try do\n        raise \"a\"\n      rescue\n        e -> {e, __STACKTRACE__}\n      end\n\n    assert [{__MODULE__, _, _, meta} | _] = stacktrace\n    assert meta[:error_info] == %{module: Exception}\n\n    assert Exception.format_error(exception, stacktrace) ==\n             %{general: \"a\", reason: \"#Elixir.RuntimeError\"}\n  end\n\n  test \"reraise message\" do\n    try do\n      reraise \"message\", @trace\n      flunk(\"should not reach\")\n    rescue\n      RuntimeError ->\n        assert @trace == __STACKTRACE__\n    end\n\n    try do\n      var = binary()\n      reraise var, @trace\n      flunk(\"should not reach\")\n    rescue\n      RuntimeError ->\n        assert @trace == __STACKTRACE__\n    end\n  end\n\n  test \"reraise with no arguments\" do\n    try do\n      reraise RuntimeError, @trace\n      flunk(\"should not reach\")\n    rescue\n      RuntimeError ->\n        assert @trace == __STACKTRACE__\n    end\n\n    try do\n      var = atom()\n      reraise var, @trace\n      flunk(\"should not reach\")\n    rescue\n      RuntimeError ->\n        assert @trace == __STACKTRACE__\n    end\n  end\n\n  test \"reraise with arguments\" do\n    try do\n      reraise RuntimeError, [message: \"message\"], @trace\n      flunk(\"should not reach\")\n    rescue\n      RuntimeError ->\n        assert @trace == __STACKTRACE__\n    end\n\n    try do\n      atom = atom()\n      opts = opts()\n      reraise atom, opts, @trace\n      flunk(\"should not reach\")\n    rescue\n      RuntimeError ->\n        assert @trace == __STACKTRACE__\n    end\n  end\n\n  test \"reraise existing exception\" do\n    try do\n      reraise %RuntimeError{message: \"message\"}, @trace\n      flunk(\"should not reach\")\n    rescue\n      RuntimeError ->\n        assert @trace == __STACKTRACE__\n    end\n\n    try do\n      var = struct()\n      reraise var, @trace\n      flunk(\"should not reach\")\n    rescue\n      RuntimeError ->\n        assert @trace == __STACKTRACE__\n    end\n  end\n\n  describe \"rescue\" do\n    test \"runtime error\" do\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          RuntimeError -> true\n        catch\n          :error, _ -> false\n        end\n\n      assert result\n\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          ArgumentError -> true\n        catch\n          :error, _ -> false\n        end\n\n      refute result\n    end\n\n    test \"named runtime error\" do\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          x in [RuntimeError] -> Exception.message(x)\n        catch\n          :error, _ -> false\n        end\n\n      assert result == \"an exception\"\n    end\n\n    test \"named runtime or argument error\" do\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          x in [ArgumentError, RuntimeError] -> Exception.message(x)\n        catch\n          :error, _ -> false\n        end\n\n      assert result == \"an exception\"\n    end\n\n    test \"named function clause (stacktrace) or runtime (no stacktrace) error\" do\n      result =\n        try do\n          Access.get(Process.get(:unused, \"foo\"), 0)\n        rescue\n          x in [FunctionClauseError, CaseClauseError] -> Exception.message(x)\n        end\n\n      assert result == \"no function clause matching in Access.get/3\"\n    end\n\n    test \"with higher precedence than catch\" do\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          _ -> true\n        catch\n          _, _ -> false\n        end\n\n      assert result\n    end\n\n    test \"argument error from Erlang\" do\n      result =\n        try do\n          :erlang.error(:badarg)\n        rescue\n          ArgumentError -> true\n        end\n\n      assert result\n    end\n\n    test \"argument error from Elixir\" do\n      result =\n        try do\n          raise ArgumentError, \"\"\n        rescue\n          ArgumentError -> true\n        end\n\n      assert result\n    end\n\n    test \"catch-all variable\" do\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          x -> Exception.message(x)\n        end\n\n      assert result == \"an exception\"\n    end\n\n    test \"catch-all underscore\" do\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          _ -> true\n        end\n\n      assert result\n    end\n\n    test \"catch-all unused variable\" do\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          _any -> true\n        end\n\n      assert result\n    end\n\n    test \"catch-all with \\\"x in _\\\" syntax\" do\n      result =\n        try do\n          raise \"an exception\"\n        rescue\n          exception in _ ->\n            Exception.message(exception)\n        end\n\n      assert result == \"an exception\"\n    end\n\n    defmacrop argerr(e) do\n      quote(do: unquote(e) in ArgumentError)\n    end\n\n    test \"with rescue macro\" do\n      result =\n        try do\n          raise ArgumentError, \"oops, badarg\"\n        rescue\n          argerr(e) -> Exception.message(e)\n        end\n\n      assert result == \"oops, badarg\"\n    end\n  end\n\n  describe \"normalize\" do\n    test \"wrap custom Erlang error\" do\n      result =\n        try do\n          :erlang.error(:sample)\n        rescue\n          x in [ErlangError] -> Exception.message(x)\n        end\n\n      assert result == \"Erlang error: :sample\"\n    end\n\n    test \"undefined function error\" do\n      result =\n        try do\n          DoNotExist.for_sure()\n        rescue\n          x in [UndefinedFunctionError] -> Exception.message(x)\n        end\n\n      assert result ==\n               \"function DoNotExist.for_sure/0 is undefined (module DoNotExist is not available). \" <>\n                 \"Make sure the module name is correct and has been specified in full (or that an alias has been defined)\"\n    end\n\n    test \"function clause error\" do\n      result =\n        try do\n          Access.get(Process.get(:unused, :ok), :error)\n        rescue\n          x in [FunctionClauseError] -> Exception.message(x)\n        end\n\n      assert result == \"no function clause matching in Access.get/3\"\n    end\n\n    test \"badarg error\" do\n      result =\n        try do\n          :erlang.error(:badarg)\n        rescue\n          x in [ArgumentError] -> Exception.message(x)\n        end\n\n      assert result == \"argument error\"\n    end\n\n    test \"tuple badarg error\" do\n      result =\n        try do\n          :erlang.error({:badarg, [1, 2, 3]})\n        rescue\n          x in [ArgumentError] -> Exception.message(x)\n        end\n\n      assert result == \"argument error: [1, 2, 3]\"\n    end\n\n    test \"badarith error\" do\n      result =\n        try do\n          :erlang.error(:badarith)\n        rescue\n          x in [ArithmeticError] -> Exception.message(x)\n        end\n\n      assert result == \"bad argument in arithmetic expression\"\n    end\n\n    test \"badarity error\" do\n      fun = fn x -> x end\n      string = \"#{inspect(fun)} with arity 1 called with 2 arguments (1, 2)\"\n\n      result =\n        try do\n          Process.get(:unused, fun).(1, 2)\n        rescue\n          x in [BadArityError] -> Exception.message(x)\n        end\n\n      assert result == string\n    end\n\n    test \"badfun error\" do\n      result =\n        try do\n          Process.get(:unused, :example).(2)\n        rescue\n          x in [BadFunctionError] -> Exception.message(x)\n        end\n\n      assert result == \"expected a function, got: :example\"\n    end\n\n    test \"badfun error when the function is gone\" do\n      defmodule BadFunction.Missing do\n        def fun, do: fn -> :ok end\n      end\n\n      fun = BadFunction.Missing.fun()\n\n      :code.purge(BadFunction.Missing)\n      :code.delete(BadFunction.Missing)\n\n      defmodule BadFunction.Missing do\n        def fun, do: fn -> :another end\n      end\n\n      :code.purge(BadFunction.Missing)\n\n      try do\n        fun.()\n      rescue\n        x in [BadFunctionError] ->\n          assert Exception.message(x) =~\n                   ~r/function #Function<[0-9]\\.[0-9]*\\/0[^>]*> is invalid, likely because it points to an old version of the code/\n      else\n        _ -> flunk(\"this should not be invoked\")\n      end\n    end\n\n    test \"badmatch error\" do\n      result =\n        try do\n          [] = Range.to_list(1000_000..1_000_009)\n        rescue\n          x in [MatchError] -> Exception.message(x)\n        end\n\n      assert result ==\n               \"\"\"\n               no match of right hand side value:\n\n                   [1000000, 1000001, 1000002, 1000003, 1000004, 1000005, 1000006, 1000007,\n                    1000008, 1000009]\n               \"\"\"\n    end\n\n    test \"bad key error\" do\n      result =\n        try do\n          %{Process.get(:unused, %{}) | foo: :bar}\n        rescue\n          x in [KeyError] -> Exception.message(x)\n        end\n\n      assert result == \"key :foo not found\"\n\n      result =\n        try do\n          Process.get(:unused, %{}).foo\n        rescue\n          x in [KeyError] -> Exception.message(x)\n        end\n\n      assert result == \"key :foo not found in:\\n\\n    %{}\\n\"\n    end\n\n    test \"bad map error\" do\n      result =\n        try do\n          %{Process.get(:unused, 0) | foo: :bar}\n        rescue\n          x in [BadMapError] -> Exception.message(x)\n        end\n\n      assert result == \"expected a map, got:\\n\\n    0\\n\"\n    end\n\n    test \"bad boolean error\" do\n      result =\n        try do\n          Process.get(:unused, 1) and true\n        rescue\n          x in [BadBooleanError] -> Exception.message(x)\n        end\n\n      assert result == \"expected a boolean on left-side of \\\"and\\\", got:\\n\\n    1\\n\"\n    end\n\n    test \"case clause error\" do\n      x = :example\n\n      result =\n        try do\n          case Process.get(:unused, 0) do\n            ^x -> nil\n          end\n        rescue\n          x in [CaseClauseError] -> Exception.message(x)\n        end\n\n      assert result == \"no case clause matching:\\n\\n    0\\n\"\n    end\n\n    test \"cond clause error\" do\n      result =\n        try do\n          cond do\n            !Process.get(:unused, 0) -> :ok\n          end\n        rescue\n          x in [CondClauseError] -> Exception.message(x)\n        end\n\n      assert result == \"no cond clause evaluated to a truthy value\"\n    end\n\n    test \"try clause error\" do\n      result =\n        try do\n          try do\n            Process.get(:unused, :example)\n          rescue\n            _exception ->\n              :ok\n          else\n            :other ->\n              :ok\n          end\n        rescue\n          x in [TryClauseError] -> Exception.message(x)\n        end\n\n      assert result == \"no try clause matching:\\n\\n    :example\\n\"\n    end\n\n    test \"undefined function error as Erlang error\" do\n      result =\n        try do\n          DoNotExist.for_sure()\n        rescue\n          x in [ErlangError] -> Exception.message(x)\n        end\n\n      assert result ==\n               \"function DoNotExist.for_sure/0 is undefined (module DoNotExist is not available). \" <>\n                 \"Make sure the module name is correct and has been specified in full (or that an alias has been defined)\"\n    end\n  end\n\n  defmacrop exceptions do\n    [ErlangError]\n  end\n\n  test \"with macros\" do\n    result =\n      try do\n        DoNotExist.for_sure()\n      rescue\n        x in exceptions() -> Exception.message(x)\n      end\n\n    assert result ==\n             \"function DoNotExist.for_sure/0 is undefined (module DoNotExist is not available). \" <>\n               \"Make sure the module name is correct and has been specified in full (or that an alias has been defined)\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/sigils_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.SigilsTest do\n  use ExUnit.Case, async: true\n\n  test \"sigil s\" do\n    assert ~s(foo) == \"foo\"\n    assert ~s(f#{:o}o) == \"foo\"\n    assert ~s(f\\no) == \"f\\no\"\n  end\n\n  test \"sigil s with heredoc\" do\n    assert \"  foo\\n\\n\" == ~s\"\"\"\n             f#{:o}o\\n\n           \"\"\"\n  end\n\n  test \"sigil S\" do\n    assert ~S(foo) == \"foo\"\n    assert ~S[foo] == \"foo\"\n    assert ~S{foo} == \"foo\"\n    assert ~S'foo' == \"foo\"\n    assert ~S\"foo\" == \"foo\"\n    assert ~S<foo> == \"foo\"\n    assert ~S/foo/ == \"foo\"\n    assert ~S|foo| == \"foo\"\n    assert ~S(f#{o}o) == \"f\\#{o}o\"\n    assert ~S(f\\#{o}o) == \"f\\\\\\#{o}o\"\n    assert ~S(f\\no) == \"f\\\\no\"\n  end\n\n  test \"sigil S newline\" do\n    assert ~S(foo\\\nbar) in [\"foo\\\\\\nbar\", \"foo\\\\\\r\\nbar\"]\n  end\n\n  test \"sigil S with heredoc\" do\n    assert \"  f\\#{o}o\\\\n\\n\" == ~S\"\"\"\n             f#{o}o\\n\n           \"\"\"\n  end\n\n  test \"sigil s/S expand to binary when possible\" do\n    assert Macro.expand(quote(do: ~s(foo)), __ENV__) == \"foo\"\n    assert Macro.expand(quote(do: ~S(foo)), __ENV__) == \"foo\"\n  end\n\n  test \"sigil c\" do\n    assert ~c(foo) == ~c\"foo\"\n    assert ~c(f#{:o}o) == ~c\"foo\"\n    assert ~c(f\\no) == ~c\"f\\no\"\n  end\n\n  test \"sigil C\" do\n    assert ~C(foo) == ~c\"foo\"\n    assert ~C[foo] == ~c\"foo\"\n    assert ~C{foo} == ~c\"foo\"\n    assert ~C'foo' == ~c\"foo\"\n    assert ~C\"foo\" == ~c\"foo\"\n    assert ~C|foo| == ~c\"foo\"\n    assert ~C(f#{o}o) == ~c\"f\\#{o}o\"\n    assert ~C(f\\no) == ~c\"f\\\\no\"\n  end\n\n  test \"sigil w\" do\n    assert ~w() == []\n    assert ~w([ , ]) == [\"[\", \",\", \"]\"]\n    assert ~w(foo bar baz) == [\"foo\", \"bar\", \"baz\"]\n    assert ~w(foo #{:bar} baz) == [\"foo\", \"bar\", \"baz\"]\n\n    assert ~w(#{\"\"}) == []\n    assert ~w(foo #{\"\"}) == [\"foo\"]\n    assert ~w(#{\" foo bar \"}) == [\"foo\", \"bar\"]\n\n    assert ~w(foo\\ #{:bar}) == [\"foo\", \"bar\"]\n    assert ~w(foo\\ bar) == [\"foo\", \"bar\"]\n\n    assert ~w(\n      foo\n      bar\n      baz\n    ) == [\"foo\", \"bar\", \"baz\"]\n\n    assert ~w(foo bar baz)s == [\"foo\", \"bar\", \"baz\"]\n    assert ~w(foo bar baz)a == [:foo, :bar, :baz]\n    assert ~w(foo bar baz)c == [~c\"foo\", ~c\"bar\", ~c\"baz\"]\n\n    bad_modifier = quote(do: ~w(foo bar baz)x)\n    assert %ArgumentError{} = catch_error(Code.eval_quoted(bad_modifier))\n\n    assert ~w(Foo Bar)a == [:Foo, :Bar]\n    assert ~w(Foo.#{Bar}.Baz)a == [:\"Foo.Elixir.Bar.Baz\"]\n    assert ~w(Foo.Bar)s == [\"Foo.Bar\"]\n    assert ~w(Foo.#{Bar})c == [~c\"Foo.Elixir.Bar\"]\n\n    # Ensure it is fully expanded at compile time\n    assert Macro.expand(quote(do: ~w(a b c)a), __ENV__) == [:a, :b, :c]\n  end\n\n  test \"sigil W\" do\n    assert ~W() == []\n    assert ~W([ , ]) == [\"[\", \",\", \"]\"]\n    assert ~W(foo #{bar} baz) == [\"foo\", \"\\#{bar}\", \"baz\"]\n\n    assert ~W(foo\\ bar) == [\"foo\\\\\", \"bar\"]\n\n    assert ~W(\n      foo\n      bar\n      baz\n    ) == [\"foo\", \"bar\", \"baz\"]\n\n    assert ~W(foo bar baz)s == [\"foo\", \"bar\", \"baz\"]\n    assert ~W(foo bar baz)a == [:foo, :bar, :baz]\n    assert ~W(foo bar baz)c == [~c\"foo\", ~c\"bar\", ~c\"baz\"]\n\n    bad_modifier = quote(do: ~W(foo bar baz)x)\n    assert %ArgumentError{} = catch_error(Code.eval_quoted(bad_modifier))\n\n    assert ~W(Foo #{Bar})a == [:Foo, :\"\\#{Bar}\"]\n    assert ~W(Foo.Bar.Baz)a == [:\"Foo.Bar.Baz\"]\n  end\n\n  test \"sigils matching\" do\n    assert ~s(f\\(oo) == \"f(oo\"\n    assert ~s(fo\\)o) == \"fo)o\"\n    assert ~s(f\\(o\\)o) == \"f(o)o\"\n    assert ~s(f[oo) == \"f[oo\"\n    assert ~s(fo]o) == \"fo]o\"\n  end\n\n  describe \"multi-letter sigils\" do\n    def sigil_MAT(string, modifiers) do\n      %{matrix: string, modifiers: modifiers}\n    end\n\n    test \"sigil MAT\" do\n      assert ~MAT\"foo\" == %{matrix: \"foo\", modifiers: []}\n      assert ~MAT[foo]i == %{matrix: \"foo\", modifiers: ~c\"i\"}\n      assert ~MAT(\"1\")mod == %{matrix: \"\\\"1\\\"\", modifiers: ~c\"mod\"}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/special_forms_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.SpecialFormsTest do\n  use ExUnit.Case, async: true\n\n  doctest Kernel.SpecialForms\n\n  describe \"cond\" do\n    test \"does not leak variables for one clause\" do\n      x = 0\n\n      cond do\n        true ->\n          x = 1\n          x\n      end\n\n      assert x == 0\n    end\n\n    test \"does not leak variables for one clause with non-boolean as catch-all\" do\n      x = 0\n\n      cond do\n        :otherwise ->\n          x = 1\n          x\n      end\n\n      assert x == 0\n    end\n\n    test \"does not leak variables for multiple clauses\" do\n      x = 0\n\n      cond do\n        List.flatten([]) == [] ->\n          x = 1\n          x\n\n        true ->\n          x = 1\n          x\n      end\n\n      assert x == 0\n    end\n\n    test \"does not leak variables from conditions\" do\n      x = :not_nil\n\n      result =\n        cond do\n          x = List.first([]) ->\n            x\n\n          true ->\n            x\n        end\n\n      assert result == :not_nil\n    end\n\n    test \"does not warn on non-boolean as catch-all\" do\n      cond do\n        List.flatten([]) == [] -> :good\n        :otherwise -> :also_good\n      end\n    end\n\n    test \"cond_clause error keeps line number in stacktrace\" do\n      try do\n        cond do\n          Process.get(:unused, false) -> :ok\n        end\n      rescue\n        _ ->\n          assert [{Kernel.SpecialFormsTest, _, _, meta} | _] = __STACKTRACE__\n          assert meta[:file]\n          assert meta[:line]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/string_tokenizer_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.StringTokenizerTest do\n  use ExUnit.Case, async: true\n\n  defp var({var, _, nil}), do: var\n  defp aliases({:__aliases__, _, [alias]}), do: alias\n\n  test \"tokenizes vars\" do\n    assert Code.string_to_quoted!(\"_12\") |> var() == :_12\n    assert Code.string_to_quoted!(\"ola\") |> var() == :ola\n    assert Code.string_to_quoted!(\"ólá\") |> var() == :ólá\n    assert Code.string_to_quoted!(\"óLÁ\") |> var() == :óLÁ\n    assert Code.string_to_quoted!(\"ólá?\") |> var() == :ólá?\n    assert Code.string_to_quoted!(\"ólá!\") |> var() == :ólá!\n    assert Code.string_to_quoted!(\"こんにちは世界\") |> var() == :こんにちは世界\n    assert {:error, _} = Code.string_to_quoted(\"v@r\")\n    assert {:error, _} = Code.string_to_quoted(\"1var\")\n  end\n\n  test \"tokenizes atoms\" do\n    assert Code.string_to_quoted!(\":_12\") == :_12\n    assert Code.string_to_quoted!(\":ola\") == :ola\n    assert Code.string_to_quoted!(\":ólá\") == :ólá\n    assert Code.string_to_quoted!(\":ólá?\") == :ólá?\n    assert Code.string_to_quoted!(\":ólá!\") == :ólá!\n    assert Code.string_to_quoted!(\":ól@\") == :ól@\n    assert Code.string_to_quoted!(\":ól@!\") == :ól@!\n    assert Code.string_to_quoted!(\":ó@@!\") == :ó@@!\n    assert Code.string_to_quoted!(\":Ola\") == :Ola\n    assert Code.string_to_quoted!(\":Ólá\") == :Ólá\n    assert Code.string_to_quoted!(\":ÓLÁ\") == :ÓLÁ\n    assert Code.string_to_quoted!(\":ÓLÁ?\") == :ÓLÁ?\n    assert Code.string_to_quoted!(\":ÓLÁ!\") == :ÓLÁ!\n    assert Code.string_to_quoted!(\":ÓL@!\") == :ÓL@!\n    assert Code.string_to_quoted!(\":Ó@@!\") == :Ó@@!\n    assert Code.string_to_quoted!(\":こんにちは世界\") == :こんにちは世界\n    assert {:error, _} = Code.string_to_quoted(\":123\")\n    assert {:error, _} = Code.string_to_quoted(\":@123\")\n  end\n\n  test \"tokenizes keywords\" do\n    assert Code.string_to_quoted!(\"[_12: 0]\") == [_12: 0]\n    assert Code.string_to_quoted!(\"[ola: 0]\") == [ola: 0]\n    assert Code.string_to_quoted!(\"[ólá: 0]\") == [ólá: 0]\n    assert Code.string_to_quoted!(\"[ólá?: 0]\") == [ólá?: 0]\n    assert Code.string_to_quoted!(\"[ólá!: 0]\") == [ólá!: 0]\n    assert Code.string_to_quoted!(\"[ól@: 0]\") == [ól@: 0]\n    assert Code.string_to_quoted!(\"[ól@!: 0]\") == [ól@!: 0]\n    assert Code.string_to_quoted!(\"[ó@@!: 0]\") == [ó@@!: 0]\n    assert Code.string_to_quoted!(\"[Ola: 0]\") == [Ola: 0]\n    assert Code.string_to_quoted!(\"[Ólá: 0]\") == [Ólá: 0]\n    assert Code.string_to_quoted!(\"[ÓLÁ: 0]\") == [ÓLÁ: 0]\n    assert Code.string_to_quoted!(\"[ÓLÁ?: 0]\") == [ÓLÁ?: 0]\n    assert Code.string_to_quoted!(\"[ÓLÁ!: 0]\") == [ÓLÁ!: 0]\n    assert Code.string_to_quoted!(\"[ÓL@!: 0]\") == [ÓL@!: 0]\n    assert Code.string_to_quoted!(\"[Ó@@!: 0]\") == [Ó@@!: 0]\n    assert Code.string_to_quoted!(\"[こんにちは世界: 0]\") == [こんにちは世界: 0]\n    assert {:error, _} = Code.string_to_quoted(\"[123: 0]\")\n    assert {:error, _} = Code.string_to_quoted(\"[@123: 0]\")\n  end\n\n  test \"tokenizes aliases\" do\n    assert Code.string_to_quoted!(\"Ola\") |> aliases() == String.to_atom(\"Ola\")\n    assert Code.string_to_quoted!(\"M_123\") |> aliases() == String.to_atom(\"M_123\")\n    assert {:error, _} = Code.string_to_quoted(\"Óla\")\n    assert {:error, _} = Code.string_to_quoted(\"Olá\")\n    assert {:error, _} = Code.string_to_quoted(\"Ol@\")\n    assert {:error, _} = Code.string_to_quoted(\"Ola?\")\n    assert {:error, _} = Code.string_to_quoted(\"Ola!\")\n  end\n\n  test \"tokenizes remote calls\" do\n    # We chose the atom below because Erlang represents it using nested lists\n    assert {{:., _, [:foo, :บูมเมอแรง]}, _, []} =\n             Code.string_to_quoted!(\":foo.บูมเมอแรง()\")\n\n    assert {{:., _, [:foo, :บูมเมอแรง]}, _, []} =\n             Code.string_to_quoted!(\":foo.\\\"บูมเมอแรง\\\"()\")\n  end\n\n  describe \"script mixing\" do\n    test \"prevents Restricted codepoints in identifiers\" do\n      exception = assert_raise SyntaxError, fn -> Code.string_to_quoted!(\"_shibㅤ = 1\") end\n\n      assert Exception.message(exception) =~\n               \"unexpected token: \\\"ㅤ\\\" (column 6, code point U+3164)\"\n    end\n\n    test \"prevents unsafe mixing in identifiers\" do\n      exception =\n        assert_raise SyntaxError, fn ->\n          Code.string_to_quoted!(\"if аdmin_, do: :ok, else: :err\")\n        end\n\n      assert Exception.message(exception) =~ \"nofile:1:9:\"\n      assert Exception.message(exception) =~ \"invalid mixed-script identifier found: аdmin\"\n\n      for s <- [\n            \"\\\\u0430 а {Cyrillic}\",\n            \"\\\\u0064 d {Latin}\",\n            \"\\\\u006D m {Latin}\",\n            \"\\\\u0069 i {Latin}\",\n            \"\\\\u006E n {Latin}\",\n            \"\\\\u005F _\"\n          ] do\n        assert Exception.message(exception) =~ s\n      end\n\n      # includes suggestion about what to change\n      assert Exception.message(exception) =~ \"\"\"\n             Hint: You could write the above in a similar way that is accepted by Elixir:\n             \"\"\"\n\n      assert Exception.message(exception) =~ \"\"\"\n             \"admin_\" (code points 0x00061 0x00064 0x0006D 0x00069 0x0006E 0x0005F)\n             \"\"\"\n\n      # a is in cyrillic\n      assert_raise SyntaxError, ~r/mixed/, fn -> Code.string_to_quoted!(\"[аdmin: 1]\") end\n      assert_raise SyntaxError, ~r/mixed/, fn -> Code.string_to_quoted!(\"[{:аdmin, 1}]\") end\n      assert_raise SyntaxError, ~r/mixed/, fn -> Code.string_to_quoted!(\"quote do: аdmin(1)\") end\n\n      # c is Latin\n      assert_raise SyntaxError, ~r/mixed/, fn -> Code.string_to_quoted!(\"http_cервер = 1\") end\n\n      # T is in cyrillic\n      assert_raise SyntaxError, ~r/mixed/, fn -> Code.string_to_quoted!(\"[Тシャツ: 1]\") end\n    end\n\n    test \"allows legitimate script mixing\" do\n      # Mixed script with supersets, numbers, and underscores\n      assert Code.eval_string(\"幻한 = 1\") == {1, [幻한: 1]}\n      assert Code.eval_string(\"幻한1 = 1\") == {1, [幻한1: 1]}\n      assert Code.eval_string(\"__सवव_1? = 1\") == {1, [__सवव_1?: 1]}\n\n      # Elixir's normalizations combine scriptsets of the 'from' and 'to' characters,\n      # ex: {Common} MICRO => {Greek} MU == {Common, Greek}; Common intersects w/all\n      assert Code.eval_string(\"μs = 1\") == {1, [μs: 1]}\n\n      # Mixed scripts in variables\n      assert Code.eval_string(\"http_сервер = 1\") == {1, [http_сервер: 1]}\n      assert Code.eval_string(\"сервер_http = 1\") == {1, [сервер_http: 1]}\n\n      # Mixed scripts in atoms\n      assert Code.eval_string(\":T_シャツ\") == {:T_シャツ, []}\n    end\n\n    test \"bidi\" do\n      # test that the implementation of String.Tokenizer.Security.unbidify/1 agrees\n      # w/Unicode Bidi Algo (UAX9) for these (identifier-specific, no-bracket) examples\n      #\n      # you can create new examples with: https://util.unicode.org/UnicodeJsps/bidic.jsp?s=foo_%D9%84%D8%A7%D9%85%D8%AF%D8%A7_baz&b=0&u=140&d=2\n      # inspired by (none of these are directly usable for our idents): https://www.unicode.org/Public/UCD/latest/ucd/BidiCharacterTest.txt\n      #\n      # there's a spurious ;A; after the identifier, because the semicolon is dir-neutral, and\n      # deleting it makes these examples hard to read in many/most editors!\n      \"\"\"\n      foo;A;0066 006F 006F;0 1 2\n      _foo_ ;A;005F 0066 006F 006F 005F;0 1 2 3 4\n      __foo__ ;A;005F 005F 0066 006F 006F 005F 005F;0 1 2 3 4 5 6\n      لامدا_foo ;A;0644 0627 0645 062F 0627 005F 0066 006F 006F;4 3 2 1 0 5 6 7 8\n      foo_لامدا_baz ;A;0066 006F 006F 005F 0644 0627 0645 062F 0627 005F 0062 0061 007A;0 1 2 3 8 7 6 5 4 9 10 11 12\n      foo_لامدا ;A;0066 006F 006F 005F 0644 0627 0645 062F 0627;0 1 2 3 8 7 6 5 4\n      foo_لامدا1 ;A;0066 006F 006F 005F 0644 0627 0645 062F 0627 0031;0 1 2 3 9 8 7 6 5 4\n      foo_لامدا_حدد ;A;0066 006F 006F 005F 0644 0627 0645 062F 0627 005F 062D 062F 062F;0 1 2 3 12 11 10 9 8 7 6 5 4\n      foo_لامدا_حدد1 ;A;0066 006F 006F 005F 0644 0627 0645 062F 0627 005F 062D 062F 062F 0031;0 1 2 3 13 12 11 10 9 8 7 6 5 4\n      foo_لامدا_حدد1_bar ;A; 0066 006F 006F 005F 0644 0627 0645 062F 0627 005F 062D 062F 062F 0031 005F 0062 0061 0072;0 1 2 3 13 12 11 10 9 8 7 6 5 4 14 15 16 17\n      foo_لامدا_حدد1_bar1 ;A;0066 006F 006F 005F 0644 0627 0645 062F 0627 005F 062D 062F 062F 0031 005F 0062 0061 0072 0031;0 1 2 3 13 12 11 10 9 8 7 6 5 4 14 15 16 17 18\n      \"\"\"\n      |> String.split(\"\\n\", trim: true)\n      |> Enum.map(&String.split(&1, \";\", trim: true))\n      |> Enum.each(fn\n        [ident, _, bytes, indices | _rest] ->\n          bytes = String.split(bytes, \" \", trim: true) |> Enum.map(&String.to_integer(&1, 16))\n          indices = String.split(indices, \" \", trim: true) |> Enum.map(&String.to_integer/1)\n          display_ordered = for i <- indices, do: Enum.at(bytes, i)\n          unbidified = String.Tokenizer.Security.unbidify(bytes)\n\n          if display_ordered != unbidified do\n            raise \"\"\"\n            Failing String.Tokenizer.Security.unbidify/1 case for: '#{ident}'\n              bytes        : #{bytes |> Enum.map(&Integer.to_string(&1, 16)) |> Enum.join(\" \")}\n              byte order   : #{bytes |> Enum.intersperse(32)}\n              uax9 order   : #{display_ordered |> Enum.intersperse(32)}\n              uax9 indices : #{indices |> Enum.join(\" \")}\n              unbidify/1   : #{unbidified |> Enum.intersperse(32)}\n            \"\"\"\n          end\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/tracers_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.TracersTest do\n  use ExUnit.Case\n\n  defp compile_string(string) do\n    string\n    |> Code.string_to_quoted!(columns: true)\n    |> Code.compile_quoted()\n  end\n\n  def trace(event, %Macro.Env{} = env) do\n    for {pid, _} <- Registry.lookup(__MODULE__, :tracers) do\n      send(pid, {event, env})\n    end\n\n    :ok\n  end\n\n  setup_all do\n    start_supervised!({Registry, keys: :duplicate, name: __MODULE__})\n    Code.put_compiler_option(:tracers, [__MODULE__])\n\n    on_exit(fn ->\n      Code.put_compiler_option(:tracers, [])\n    end)\n  end\n\n  setup do\n    Registry.register(__MODULE__, :tracers, :unused)\n    :ok\n  end\n\n  test \"traces start and stop\" do\n    compile_string(\"\"\"\n    Foo\n    \"\"\")\n\n    assert_received {:start, %{lexical_tracker: pid}} when is_pid(pid)\n    assert_received {:stop, %{lexical_tracker: pid}} when is_pid(pid)\n  end\n\n  test \"traces alias references\" do\n    compile_string(\"\"\"\n    Foo\n    \"\"\")\n\n    assert_received {{:alias_reference, meta, Foo}, _}\n    assert meta[:line] == 1\n    assert meta[:column] == 1\n  end\n\n  test \"traces aliases\" do\n    compile_string(\"\"\"\n    alias Hello.World\n    World\n\n    alias Foo, as: Bar, warn: true\n    Bar\n    \"\"\")\n\n    assert_received {{:alias, meta, Hello.World, World, []}, _}\n    assert meta[:line] == 1\n    assert meta[:column] == 1\n    assert_received {{:alias_expansion, meta, World, Hello.World}, _}\n    assert meta[:line] == 2\n    assert meta[:column] == 1\n\n    assert_received {{:alias, meta, Foo, Bar, [as: Bar, warn: true]}, _}\n    assert meta[:line] == 4\n    assert meta[:column] == 1\n    assert_received {{:alias_expansion, meta, Bar, Foo}, _}\n    assert meta[:line] == 5\n    assert meta[:column] == 1\n  end\n\n  test \"traces imports\" do\n    compile_string(\"\"\"\n    import Integer, only: [is_odd: 1, parse: 1]\n    true = is_odd(1)\n    {1, \"\"} = parse(\"1\")\n    \"\"\")\n\n    assert_received {{:import, meta, Integer, only: [is_odd: 1, parse: 1]}, _}\n    assert meta[:line] == 1\n    assert meta[:column] == 1\n\n    assert_received {{:imported_macro, meta, Integer, :is_odd, 1}, _}\n    assert meta[:line] == 2\n    assert meta[:column] == 8\n\n    assert_received {{:imported_function, meta, Integer, :parse, 1}, _}\n    assert meta[:line] == 3\n    assert meta[:column] == 11\n\n    refute_received {{:remote_function, _, Integer, :parse, 1}, _}\n  end\n\n  test \"traces imports via capture\" do\n    compile_string(\"\"\"\n    import Integer, only: [is_odd: 1, parse: 1]\n    &is_odd/1\n    &parse/1\n    \"\"\")\n\n    assert_received {{:import, meta, Integer, only: [is_odd: 1, parse: 1]}, _}\n    assert meta[:line] == 1\n    assert meta[:column] == 1\n\n    assert_received {{:imported_macro, meta, Integer, :is_odd, 1}, _}\n    assert meta[:line] == 2\n    assert meta[:column] == 2\n\n    assert_received {{:imported_function, meta, Integer, :parse, 1}, _}\n    assert meta[:line] == 3\n    assert meta[:column] == 2\n\n    refute_received {{:remote_function, _meta, Integer, :parse, 1}, _}\n  end\n\n  test \"traces structs\" do\n    compile_string(\"\"\"\n    %URI{path: \"/\"}\n    \"\"\")\n\n    assert_received {{:struct_expansion, meta, URI, [:path]}, _}\n    assert meta[:line] == 1\n    assert meta[:column] == 1\n  end\n\n  test \"traces remote\" do\n    compile_string(\"\"\"\n    require Integer\n    true = Integer.is_odd(1)\n    {1, \"\"} = Integer.parse(\"1\")\n    \"foo\" = Atom.to_string(:foo)\n    \"\"\")\n\n    assert_received {{:remote_macro, meta, Integer, :is_odd, 1}, _}\n    assert meta[:line] == 2\n    assert meta[:column] == 16\n\n    assert_received {{:remote_function, meta, Integer, :parse, 1}, _}\n    assert meta[:line] == 3\n    assert meta[:column] == 19\n\n    assert_received {{:remote_function, meta, Atom, :to_string, 1}, _}\n    assert meta[:line] == 4\n    assert meta[:column] == 14\n  end\n\n  test \"traces remote via captures\" do\n    compile_string(\"\"\"\n    require Integer\n    &Integer.is_odd/1\n    &Integer.parse/1\n    \"\"\")\n\n    assert_received {{:remote_macro, meta, Integer, :is_odd, 1}, _}\n    assert meta[:line] == 2\n    assert meta[:column] == 10\n\n    assert_received {{:remote_function, meta, Integer, :parse, 1}, _}\n    assert meta[:line] == 3\n    assert meta[:column] == 10\n  end\n\n  test \"traces locals\" do\n    compile_string(\"\"\"\n    defmodule Sample do\n      defmacro foo(arg), do: arg\n      def bar(arg), do: arg\n      def baz(arg), do: foo(arg) + bar(arg)\n    end\n    \"\"\")\n\n    assert_received {{:local_macro, meta, :foo, 1}, _}\n    assert meta[:line] == 4\n    assert meta[:column] == 21\n\n    assert_received {{:local_function, meta, :bar, 1}, _}\n    assert meta[:line] == 4\n    assert meta[:column] == 32\n  after\n    :code.purge(Sample)\n    :code.delete(Sample)\n  end\n\n  test \"traces locals with capture\" do\n    compile_string(\"\"\"\n    defmodule Sample do\n      defmacro foo(arg), do: arg\n      def bar(arg), do: arg\n      def baz(_), do: {&foo/1, &bar/1}\n    end\n    \"\"\")\n\n    assert_received {{:local_macro, meta, :foo, 1}, _}\n    assert meta[:line] == 4\n    assert meta[:column] == 21\n\n    assert_received {{:local_function, meta, :bar, 1}, _}\n    assert meta[:line] == 4\n    assert meta[:column] == 29\n  after\n    :code.purge(Sample)\n    :code.delete(Sample)\n  end\n\n  test \"traces modules\" do\n    compile_string(\"\"\"\n    defmodule Sample do\n      :ok\n    end\n    \"\"\")\n\n    assert_received {:defmodule, %{module: Sample, function: nil}}\n    assert_received {{:on_module, <<_::binary>>, :none}, %{module: Sample, function: nil}}\n  after\n    :code.purge(Sample)\n    :code.delete(Sample)\n  end\n\n  test \"traces dynamic modules\" do\n    compile_string(\"\"\"\n    Module.create(Sample, :ok, __ENV__)\n    \"\"\")\n\n    assert_received {:defmodule, %{module: Sample, function: nil}}\n    assert_received {{:on_module, <<_::binary>>, :none}, %{module: Sample, function: nil}}\n  after\n    :code.purge(Sample)\n    :code.delete(Sample)\n  end\n\n  test \"traces module attribute expansion\" do\n    compile_string(\"\"\"\n    defmodule TracersModuleAttribute do\n      @module URI\n      @module\n    end\n    \"\"\")\n\n    assert_received {{:alias_reference, [line: 3], URI}, %{file: \"@module\"}}\n  end\n\n  test \"traces string interpolation\" do\n    compile_string(\"\"\"\n    arg = 1 + 2\n    \"foo\\#{arg}\"\n    \"\"\")\n\n    assert_received {{:remote_macro, meta, Kernel, :to_string, 1}, _env}\n    assert meta[:from_interpolation]\n  end\n\n  test \"traces bracket access\" do\n    compile_string(\"\"\"\n    foo = %{bar: 3}\n    foo[:bar]\n    \"\"\")\n\n    assert_received {{:remote_function, meta, Access, :get, 2}, _env}\n    assert meta[:from_brackets]\n\n    compile_string(\"\"\"\n    defmodule TracerBracketAccess do\n      @foo %{bar: 3}\n      def a() do\n        @foo[:bar]\n      end\n    end\n    \"\"\")\n\n    assert_received {{:remote_function, meta, Access, :get, 2}, _env}\n    assert meta[:from_brackets]\n\n    compile_string(\"\"\"\n    %{bar: 3}[:bar]\n    \"\"\")\n\n    assert_received {{:remote_function, meta, Access, :get, 2}, _env}\n    assert meta[:from_brackets]\n  end\n\n  test \"traces on_load\" do\n    compile_string(\"\"\"\n    defmodule TracerOnLoad do\n      @on_load :init\n      def init, do: :ok\n    end\n    \"\"\")\n\n    assert_received {{:local_function, meta, :init, 0}, _}\n    assert meta[:line] == 1\n  end\n\n  def __before_compile__(_), do: :ok\n  def __after_compile__(_, _), do: :ok\n  def __after_verify__(_), do: :ok\n  def __on_definition__(_, _, _, _, _, _), do: :ok\n\n  test \"traces compile time attributes\" do\n    compile_string(\"\"\"\n    defmodule TracerCompileAttributes do\n      @before_compile Kernel.TracersTest\n      @after_compile Kernel.TracersTest\n      @on_definition Kernel.TracersTest\n      @after_verify Kernel.TracersTest\n      def hello, do: :world\n    end\n    \"\"\")\n\n    assert_received {{:remote_function, meta, __MODULE__, :__before_compile__, 1}, _}\n    assert meta[:line] == 1\n\n    assert_received {{:remote_function, meta, __MODULE__, :__after_compile__, 2}, _}\n    assert meta[:line] == 1\n\n    assert_received {{:remote_function, meta, __MODULE__, :__after_verify__, 1}, _}\n    assert meta[:line] == 1\n\n    assert_received {{:remote_function, meta, __MODULE__, :__on_definition__, 6}, _}\n    assert meta[:line] == 6\n  end\n\n  test \"traces super\" do\n    compile_string(\"\"\"\n    defmodule TracerOverridable do\n      def local(x), do: x\n      defoverridable [local: 1]\n      def local(x), do: super(x)\n\n      defmacro macro(x), do: x\n      defoverridable [macro: 1]\n      defmacro macro(x), do: super(x)\n\n      def capture(x), do: x\n      defoverridable [capture: 1]\n      def capture(x), do: tap(x, &super/1)\n\n      def capture_arg(x), do: x\n      defoverridable [capture_arg: 1]\n      def capture_arg(x), do: tap(x, &super(&1))\n    end\n    \"\"\")\n\n    assert_received {{:local_function, _, :\"local (overridable 1)\", 1}, _}\n    assert_received {{:local_function, _, :\"macro (overridable 1)\", 1}, _}\n    assert_received {{:local_function, _, :\"capture (overridable 1)\", 1}, _}\n    assert_received {{:local_function, _, :\"capture_arg (overridable 1)\", 1}, _}\n    refute_received {{:local_function, _, _, _}, _}\n  end\n\n  test \"does not trace bind quoted twice\" do\n    compile_string(\"\"\"\n    quote bind_quoted: [foo: List.flatten([])] do\n      foo\n    end\n    \"\"\")\n\n    assert_received {{:remote_function, _, List, :flatten, 1}, _}\n    refute_received {{:remote_function, _, List, :flatten, 1}, _}\n  end\n\n  test \"does not trace captures twice\" do\n    compile_string(\"\"\"\n    &List.flatten/1\n    \"\"\")\n\n    assert_received {{:remote_function, _, List, :flatten, 1}, _}\n    refute_received {{:remote_function, _, List, :flatten, 1}, _}\n  end\n\n  \"\"\"\n  # Make sure this module is compiled with column information\n  defmodule MacroWithColumn do\n    defmacro some_macro(list) do\n      quote do\n        Enum.map(unquote(list), fn str -> String.upcase(str) end)\n      end\n    end\n  end\n  \"\"\"\n  |> Code.string_to_quoted!(columns: true)\n  |> Code.compile_quoted()\n\n  test \"traces quoted from macro expansion without column information\" do\n    compile_string(\"\"\"\n    require MacroWithColumn\n    MacroWithColumn.some_macro([\"hello\", \"world\", \"!\"])\n    \"\"\")\n\n    assert_received {{:alias_reference, meta, Enum}, _env}\n    refute meta[:column]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/warning_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.WarningTest do\n  use ExUnit.Case\n  import ExUnit.CaptureIO\n\n  defp capture_err(fun) when is_function(fun), do: capture_io(:stderr, fun)\n\n  defp assert_messages_match(messages, output) when is_list(messages) do\n    for message <- messages do\n      assert output =~ message\n    end\n  end\n\n  defp assert_warn_eval(messages, source) do\n    captured =\n      capture_err(fn ->\n        quoted = Code.string_to_quoted!(source, columns: true)\n        Code.eval_quoted(quoted)\n      end)\n\n    assert_messages_match(messages, captured)\n  end\n\n  defp assert_warn_quoted(messages, source) do\n    captured =\n      capture_err(fn ->\n        Code.string_to_quoted!(source, columns: true)\n      end)\n\n    assert_messages_match(messages, captured)\n  end\n\n  defp assert_warn_compile(messages, source) do\n    captured =\n      capture_err(fn ->\n        quoted = Code.string_to_quoted!(source, columns: true)\n        Code.compile_quoted(quoted)\n      end)\n\n    assert_messages_match(messages, captured)\n  end\n\n  defp capture_eval(source) do\n    capture_err(fn ->\n      quoted = Code.string_to_quoted!(source, columns: true)\n      Code.eval_quoted(quoted)\n    end)\n  end\n\n  defp capture_compile(source) do\n    capture_err(fn ->\n      quoted = Code.string_to_quoted!(source, columns: true)\n      Code.compile_quoted(quoted)\n    end)\n  end\n\n  defmacro will_warn do\n    quote file: \"demo\", line: true do\n      %{dup: 1, dup: 2}\n    end\n  end\n\n  test \"warnings from macro\" do\n    assert_warn_eval(\n      [\"demo:64\\n\", \"key :dup will be overridden in map\\n\"],\n      \"\"\"\n      import Kernel.WarningTest\n      will_warn()\n      \"\"\"\n    )\n  end\n\n  test \"outdented heredoc\" do\n    assert_warn_eval(\n      [\"nofile:2:3\", \"outdented heredoc line\"],\n      \"\"\"\n        '''\n      outdented\n        '''\n      \"\"\"\n    )\n  end\n\n  test \"does not warn on incomplete tokenization\" do\n    assert {:error, _} = Code.string_to_quoted(~s[:\"foobar\" do])\n  end\n\n  describe \"unicode identifier security\" do\n    test \"warns on confusables\" do\n      assert_warn_quoted(\n        [\"nofile:1:6\", \"confusable identifier: 'a' looks like 'а' on line 1\"],\n        \"а=1; a=1\"\n      )\n\n      assert_warn_quoted(\n        [\"nofile:1:12\", \"confusable identifier: 'a' looks like 'а' on line 1\"],\n        \"[{:а, 1}, {:a, 1}]\"\n      )\n\n      assert_warn_quoted(\n        [\"nofile:1:8\", \"confusable identifier: 'a' looks like 'а' on line 1\"],\n        \"[а: 1, a: 1]\"\n      )\n\n      assert_warn_quoted(\n        [\"nofile:1:18\", \"confusable identifier: 'a' looks like 'а' on line 1\"],\n        \"quote do: [а(1), a(1)]\"\n      )\n\n      assert_warn_quoted(\n        [\"nofile:1:6\", \"confusable identifier: 'カ' looks like '力' on line 1\"],\n        \"力=1; カ=1\"\n      )\n\n      # by convention, doesn't warn on ascii-only confusables\n      assert capture_eval(\"x0 = xO = 1\") == \"\"\n      assert capture_eval(\"l1 = ll = 1\") == \"\"\n\n      # works with a custom atom encoder\n      assert capture_err(fn ->\n               Code.string_to_quoted(\"[{:а, 1}, {:a, 1}]\",\n                 static_atoms_encoder: fn token, _ -> {:ok, {:wrapped, token}} end\n               )\n             end) =~\n               \"confusable identifier: 'a' looks like 'а' on line 1\"\n    end\n\n    test \"warns on LTR-confusables\" do\n      # warning outputs in byte order (vs bidi algo display order, uax9), mentions presence of rtl\n      assert_warn_quoted(\n        [\"nofile:1:9\", \"'_1א' looks like '_א1'\", \"right-to-left characters\"],\n        \"_א1 and _1א\"\n      )\n\n      assert_warn_quoted(\n        [\n          \"'a_1א' includes right-to-left characters\",\n          \"\\\\u0061 a ltr\",\n          \"\\\\u005F _ neutral\",\n          \"\\\\u0031 1 weak_number\",\n          \"\\\\u05D0 א rtl\",\n          \"'a_א1' includes right-to-left characters:\",\n          \"\\\\u0061 a ltr\",\n          \"\\\\u005F _ neutral\",\n          \"\\\\u05D0 א rtl\",\n          \"\\\\u0031 1 weak_number\"\n        ],\n        \"a_א1 or a_1א\"\n      )\n    end\n  end\n\n  test \"operators formed by many of the same character followed by that character\" do\n    assert_warn_eval(\n      [\n        \"nofile:1:12\",\n        \"found \\\"+++\\\" followed by \\\"+\\\", please use a space between \\\"+++\\\" and the next \\\"+\\\"\"\n      ],\n      \"quote do: 1++++1\"\n    )\n  end\n\n  test \"identifier that ends in ! followed by the = operator without a space in between\" do\n    assert_warn_eval(\n      [\"nofile:1:1\", \"found identifier \\\"foo!\\\", ending with \\\"!\\\"\"],\n      \"foo!= 1\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:1:1\", \"found atom \\\":foo!\\\", ending with \\\"!\\\"\"],\n      \":foo!= :foo!\"\n    )\n  end\n\n  describe \"unnecessary quotes\" do\n    test \"does not warn of unnecessary quotes in uppercase atoms/keywords\" do\n      assert capture_eval(~s/:\"Foo\"/) == \"\"\n      assert capture_eval(~s/[\"Foo\": :bar]/) == \"\"\n      assert capture_eval(~s/:\"Foo\"/) == \"\"\n      assert capture_eval(~s/:\"foo@bar\"/) == \"\"\n      assert capture_eval(~s/:\"héllò\"/) == \"\"\n      assert capture_eval(~s/:\"3L1X1R\"/) == \"\"\n    end\n\n    test \"warns of unnecessary quotes\" do\n      assert_warn_eval(\n        [\"nofile:1:1\", \"found quoted atom \\\"foo\\\" but the quotes are not required\"],\n        ~s/:\"foo\"/\n      )\n\n      assert_warn_eval(\n        [\"nofile:1:2\", \"found quoted keyword \\\"foo\\\" but the quotes are not required\"],\n        ~s/[\"foo\": :bar]/\n      )\n\n      assert_warn_eval(\n        [\"nofile:1:9\", \"found quoted call \\\"length\\\" but the quotes are not required\"],\n        ~s/[Kernel.\"length\"([])]/\n      )\n    end\n  end\n\n  describe \"deprecated single quotes in atoms\" do\n    test \"warns of single quotes in atoms\" do\n      assert_warn_eval(\n        [\n          \"nofile:1:1\",\n          \"single quotes around atoms are deprecated. Use double quotes instead\"\n        ],\n        ~s/:'a+b'/\n      )\n    end\n\n    test \"warns twice of single and unnecessary atom quotes\" do\n      assert_warn_eval(\n        [\n          \"nofile:1:1\",\n          \"single quotes around atoms are deprecated. Use double quotes instead\",\n          \"nofile:1:1\",\n          \"found quoted atom \\\"ab\\\" but the quotes are not required\"\n        ],\n        ~s/:'ab'/\n      )\n    end\n\n    test \"warns twice of single and unnecessary call quotes\" do\n      assert_warn_eval(\n        [\n          \"nofile:1:9\",\n          \"single quotes around calls are deprecated. Use double quotes instead\",\n          \"nofile:1:9\",\n          \"found quoted call \\\"length\\\" but the quotes are not required\"\n        ],\n        ~s/[Kernel.'length'([])]/\n      )\n    end\n  end\n\n  test \"warns on :: as atom\" do\n    assert_warn_eval(\n      [\n        \"nofile:1:1\",\n        \"atom ::: must be written between quotes, as in :\\\"::\\\", to avoid ambiguity\"\n      ],\n      ~s/:::/\n    )\n  end\n\n  test \"unused variable\" do\n    # Note we use compile_string because eval_string does not emit unused vars warning\n    assert_warn_compile(\n      [\n        \"nofile:2:3\",\n        \"variable \\\"module\\\" is unused\",\n        \"nofile:3:13\",\n        \"variable \\\"arg\\\" is unused\",\n        \"nofile:5:1\",\n        \"variable \\\"file\\\" is unused\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        module = 1\n        def hello(arg), do: nil\n      end\n      file = 2\n      file = 3\n      file\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unused variable that could be pinned\" do\n    # Note we use compile_string because eval_string does not emit unused vars warning\n    assert_warn_compile(\n      [\n        \"nofile:4:12\",\n        \"variable \\\"compare_local\\\" is unused (there is a variable with the same name in the context, use the pin operator (^) to match on it or prefix this variable with underscore if it is not meant to be used)\",\n        \"nofile:8:7\",\n        \"variable \\\"compare_nested\\\" is unused (there is a variable with the same name in the context, use the pin operator (^) to match on it or prefix this variable with underscore if it is not meant to be used)\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def test do\n          compare_local = \"hello\"\n          match?(compare_local, \"hello\")\n\n          compare_nested = \"hello\"\n          case \"hello\" do\n            compare_nested -> true\n            _other -> false\n          end\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"duplicate pattern\" do\n    output =\n      capture_eval(\"\"\"\n      defmodule Sample do\n        var = quote(do: x)\n        def hello(unquote(var) = unquote(var)), do: unquote(var)\n      end\n      \"\"\")\n\n    assert output =~ \"this pattern is matched against itself inside a match: x = x\"\n  after\n    purge(Sample)\n  end\n\n  test \"unused compiler variable\" do\n    output =\n      capture_eval(\"\"\"\n      defmodule Sample do\n        def hello(__MODULE___), do: :ok\n        def world(_R), do: :ok\n      end\n      \"\"\")\n\n    assert output =~ \"unknown compiler variable \\\"__MODULE___\\\"\"\n    assert output =~ \"nofile:2:13\"\n    refute output =~ \"unknown compiler variable \\\"_R\\\"\"\n  after\n    purge(Sample)\n  end\n\n  test \"nested unused variable\" do\n    messages = [\"undefined variable \\\"x\\\"\", \"variable \\\"x\\\" is unused\"]\n\n    assert_compile_error(\n      [\"nofile:5:1\", \"nofile:2:11\" | messages],\n      \"\"\"\n      case false do\n        true -> x = 1\n        _ -> 1\n      end\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1:12\", \"nofile:2:1\" | messages],\n      \"\"\"\n      false and (x = 1)\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1:10\", \"nofile:2:1\" | messages],\n      \"\"\"\n      true or (x = 1)\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:2:3\", \"nofile:4:1\" | messages],\n      \"\"\"\n      if false do\n        x = 1\n      end\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:2:12\", \"nofile:5:1\" | messages],\n      \"\"\"\n      cond do\n        false -> x = 1\n        true -> 1\n      end\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:2:11\", \"nofile:6:1\" | messages],\n      \"\"\"\n      receive do\n        :foo -> x = 1\n      after\n        0 -> 1\n      end\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1:11\", \"nofile:2:1\" | messages],\n      \"\"\"\n      false && (x = 1)\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:1:10\", \"nofile:2:1\" | messages],\n      \"\"\"\n      true || (x = 1)\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:2:3\", \"nofile:4:1\" | messages],\n      \"\"\"\n      with true <- true do\n        x = false\n      end\n      x\n      \"\"\"\n    )\n\n    assert_compile_error(\n      [\"nofile:2:3\", \"nofile:4:1\" | messages],\n      \"\"\"\n      fn ->\n        x = true\n      end\n      x\n      \"\"\"\n    )\n  end\n\n  test \"unused variable in redefined function in different file\" do\n    output =\n      capture_err(fn ->\n        Code.eval_string(\"\"\"\n        defmodule Sample do\n          defmacro __using__(_) do\n            quote location: :keep do\n              def function(arg)\n            end\n          end\n        end\n        \"\"\")\n\n        code = \"\"\"\n          defmodule RedefineSample do\n            use Sample\n            def function(var123), do: nil\n          end\n        \"\"\"\n\n        Code.eval_string(code, [], file: \"redefine_sample.ex\")\n      end)\n\n    assert output =~ \"redefine_sample.ex:3: \"\n    assert output =~ \"variable \\\"var123\\\" is unused\"\n  after\n    purge(Sample)\n    purge(RedefineSample)\n  end\n\n  test \"unused variable because re-declared in a match? pattern\" do\n    assert_warn_eval(\n      [\n        \"nofile:1:16\",\n        \"variable \\\"x\\\" is unused (there is a variable with the same name in the context,\",\n        \"variable \\\"x\\\" is unused (if the variable is not meant to be used,\"\n      ],\n      \"\"\"\n      fn x -> match?(x, :value) end\n      \"\"\"\n    )\n  end\n\n  test \"useless literal\" do\n    message = \"code block contains unused literal \\\"oops\\\"\"\n\n    assert_warn_eval(\n      [\"nofile:1\\n\", message],\n      \"\"\"\n      \"oops\"\n      :ok\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:1\\n\", message],\n      \"\"\"\n      fn ->\n        \"oops\"\n        :ok\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:1:5\\n\", message],\n      \"\"\"\n      try do\n        \"oops\"\n        :ok\n      after\n        :ok\n      end\n      \"\"\"\n    )\n  end\n\n  test \"useless attr\" do\n    assert_warn_eval(\n      [\n        \"nofile:4:3\",\n        \"module attribute @foo in code block has no effect as it is never returned \",\n        \"nofile:7:5\",\n        \"module attribute @bar in code block has no effect as it is never returned \"\n      ],\n      \"\"\"\n      defmodule Sample do\n        @foo 1\n        @bar 1\n        @foo\n\n        def bar do\n          @bar\n          :ok\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"useless var\" do\n    message = \"variable foo in code block has no effect as it is never returned \"\n\n    assert_warn_eval(\n      [\"nofile:2:1\", message],\n      \"\"\"\n      foo = 1\n      foo\n      :ok\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:3:3\", message],\n      \"\"\"\n      fn ->\n        foo = 1\n        foo\n        :ok\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:3:3\", message],\n      \"\"\"\n      try do\n        foo = 1\n        foo\n        :ok\n      after\n        :ok\n      end\n      \"\"\"\n    )\n\n    assert capture_eval(\"\"\"\n           node()\n           :ok\n           \"\"\") == \"\"\n  end\n\n  test \"underscored variable on match\" do\n    assert_warn_eval(\n      [\"nofile:1:8\", \"the underscored variable \\\"_arg\\\" appears more than once in a match\"],\n      \"\"\"\n      {_arg, _arg} = {1, 1}\n      \"\"\"\n    )\n  end\n\n  test \"underscored variable on use\" do\n    assert_warn_eval(\n      [\"nofile:1:12\", \"the underscored variable \\\"_var\\\" is used after being set\"],\n      \"\"\"\n      fn _var -> _var + 1 end\n      \"\"\"\n    )\n\n    assert capture_eval(\"\"\"\n           fn var!(_var, Foo) -> var!(_var, Foo) + 1 end\n           \"\"\") == \"\"\n  end\n\n  test \"unused function\" do\n    assert_warn_eval(\n      [\"nofile:2:8: \", \"function hello/0 is unused\\n\"],\n      \"\"\"\n      defmodule Sample1 do\n        defp hello, do: nil\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:2:8: \", \"function hello/1 is unused\\n\"],\n      \"\"\"\n      defmodule Sample2 do\n        defp hello(0), do: hello(1)\n        defp hello(1), do: :ok\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:4:8: \", \"function c/2 is unused\\n\"],\n      ~S\"\"\"\n      defmodule Sample3 do\n        def a, do: nil\n        def b, do: d(10)\n        defp c(x, y \\\\ 1), do: [x, y]\n        defp d(x), do: x\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:3:8: \", \"function b/2 is unused\\n\"],\n      ~S\"\"\"\n      defmodule Sample4 do\n        def a, do: nil\n        defp b(x \\\\ 1, y \\\\ 1)\n        defp b(x, y), do: [x, y]\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:3:8: \", \"function b/0 is unused\\n\"],\n      ~S\"\"\"\n      defmodule Sample5 do\n        def a, do: nil\n        defp b(), do: unquote(1)\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2, Sample3, Sample4, Sample5])\n  end\n\n  test \"unused cyclic functions\" do\n    assert_warn_eval(\n      [\n        \"nofile:2:8: \",\n        \"function a/0 is unused\\n\",\n        \"nofile:3:8: \",\n        \"function b/0 is unused\\n\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        defp a, do: b()\n        defp b, do: a()\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unused macro\" do\n    assert_warn_eval(\n      [\"nofile:2:13: \", \"macro hello/0 is unused\"],\n      \"\"\"\n      defmodule Sample do\n        defmacrop hello, do: nil\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:2:13: \", \"macro hello/0 is unused\\n\"],\n      ~S\"\"\"\n      defmodule Sample2 do\n        defmacrop hello do\n          quote do: unquote(1)\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample, Sample2])\n  end\n\n  test \"shadowing\" do\n    assert capture_eval(\"\"\"\n           defmodule Sample do\n             def test(x) do\n               case x do\n                 {:file, fid} -> fid\n                 {:path, _}   -> fn(fid) -> fid end\n               end\n             end\n           end\n           \"\"\") == \"\"\n  after\n    purge(Sample)\n  end\n\n  test \"unused default args\" do\n    assert_warn_eval(\n      [\n        \"nofile:3:8: \",\n        \"default values for the optional arguments in the private function b/3 are never used\"\n      ],\n      ~S\"\"\"\n      defmodule Sample1 do\n        def a, do: b(1, 2, 3)\n        defp b(arg1 \\\\ 1, arg2 \\\\ 2, arg3 \\\\ 3), do: [arg1, arg2, arg3]\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\n        \"nofile:3:8: \",\n        \"the default value for the last optional argument in the private function b/3 is never used\"\n      ],\n      ~S\"\"\"\n      defmodule Sample2 do\n        def a, do: b(1, 2)\n        defp b(arg1 \\\\ 1, arg2 \\\\ 2, arg3 \\\\ 3), do: [arg1, arg2, arg3]\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\n        \"nofile:3:8: \",\n        \"the default values for the last 2 optional arguments in the private function b/4 are never used\"\n      ],\n      ~S\"\"\"\n      defmodule Sample3 do\n        def a, do: b(1, 2)\n        defp b(arg1, arg2 \\\\ 2, arg3 \\\\ 3, arg4 \\\\ 4), do: [arg1, arg2, arg3, arg4]\n      end\n      \"\"\"\n    )\n\n    assert capture_eval(~S\"\"\"\n           defmodule Sample4 do\n             def a, do: b(1)\n             defp b(arg1 \\\\ 1, arg2, arg3 \\\\ 3), do: [arg1, arg2, arg3]\n           end\n           \"\"\") == \"\"\n\n    assert_warn_eval(\n      [\n        \"nofile:3:8: \",\n        \"the default value for the last optional argument in the private function b/3 is never used\"\n      ],\n      ~S\"\"\"\n      defmodule Sample5 do\n        def a, do: b(1, 2)\n        defp b(arg1 \\\\ 1, arg2 \\\\ 2, arg3 \\\\ 3)\n\n        defp b(arg1, arg2, arg3), do: [arg1, arg2, arg3]\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2, Sample3, Sample4, Sample5])\n  end\n\n  test \"unused import\" do\n    assert_warn_compile(\n      [\"nofile:2:3\", \"unused import :lists\"],\n      \"\"\"\n      defmodule Sample do\n        import :lists\n        def a, do: nil\n      end\n      \"\"\"\n    )\n\n    assert_warn_compile(\n      [\"nofile:1:1\", \"unused import :lists\"],\n      \"\"\"\n      import :lists\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unknown import\" do\n    assert_warn_compile(\n      [\"nofile:1:1\", \"cannot import Kernel.invalid/1 because it is undefined or private\"],\n      \"\"\"\n      import(Kernel, only: [invalid: 1])\n      \"\"\"\n    )\n  end\n\n  test \"conditional import\" do\n    assert capture_err(fn ->\n             defmodule KernelTest.ConditionalImport do\n               if false do\n                 import Map, only: [new: 0]\n                 def fun, do: new()\n               end\n             end\n           end) == \"\"\n  after\n    purge(Sample)\n  end\n\n  test \"unused import of one of the functions in :only\" do\n    assert_warn_compile(\n      [\n        \"nofile:2:3\",\n        \"unused import String.downcase/1\",\n        \"nofile:2:3\",\n        \"unused import String.trim/1\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        import String, only: [upcase: 1, downcase: 1, trim: 1]\n        def a, do: upcase(\"hello\")\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unused import of any of the functions in :only\" do\n    assert_warn_compile(\n      [\"nofile:1:1\", \"unused import String\"],\n      \"\"\"\n      import String, only: [upcase: 1, downcase: 1]\n      \"\"\"\n    )\n  end\n\n  test \"unused import inside dynamic module\" do\n    import List, only: [flatten: 1], warn: false\n\n    assert capture_err(fn ->\n             defmodule Sample do\n               import String, only: [downcase: 1]\n\n               def world do\n                 flatten([1, 2, 3])\n               end\n             end\n           end) =~ \"unused import String\"\n  after\n    purge(Sample)\n  end\n\n  def with(a, b, c), do: [a, b, c]\n\n  test \"import matches special form\" do\n    assert_warn_compile(\n      [\n        \"nofile:1:1\",\n        \"cannot import Kernel.WarningTest.with/3 because it conflicts with Elixir special forms\"\n      ],\n      \"\"\"\n      import Kernel.WarningTest, only: [with: 3]\n      :ok = with true <- true, true <- true, do: :ok\n      \"\"\"\n    )\n  end\n\n  test \"duplicated function on import options\" do\n    assert_warn_compile(\n      [\"nofile:2:3\", \"invalid :only option for import, wrap/1 is duplicated\"],\n      \"\"\"\n      defmodule Kernel.WarningsTest.DuplicatedFunctionOnImportOnly do\n        import List, only: [wrap: 1, keyfind: 3, wrap: 1]\n      end\n      \"\"\"\n    )\n\n    assert_warn_compile(\n      [\"nofile:2:3\", \"invalid :except option for import, wrap/1 is duplicated\"],\n      \"\"\"\n      defmodule Kernel.WarningsTest.DuplicatedFunctionOnImportExcept do\n        import List, except: [wrap: 1, keyfind: 3, wrap: 1]\n      end\n      \"\"\"\n    )\n  end\n\n  test \"conditional alias\" do\n    assert capture_err(fn ->\n             defmodule KernelTest.ConditionaAlias do\n               if false do\n                 alias Map, as: M\n                 def fun, do: M.new()\n               end\n             end\n           end) == \"\"\n  end\n\n  test \"unused alias\" do\n    assert_warn_compile(\n      [\"nofile:2:3\", \"unused alias List\"],\n      \"\"\"\n      defmodule Sample do\n        alias :lists, as: List\n        def a, do: nil\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unused alias when also import\" do\n    assert_warn_compile(\n      [\"nofile:2:3\", \"unused alias List\"],\n      \"\"\"\n      defmodule Sample do\n        alias :lists, as: List\n        import MapSet\n        new()\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"duplicate map keys\" do\n    assert_warn_eval(\n      [\n        \"key :a will be overridden in map\",\n        \"nofile:4:10\\n\",\n        \"key :m will be overridden in map\",\n        \"nofile:5:10\\n\",\n        \"key 1 will be overridden in map\",\n        \"nofile:6:10\\n\"\n      ],\n      \"\"\"\n      defmodule DuplicateMapKeys do\n        import ExUnit.Assertions\n\n        assert %{a: :b, a: :c} == %{a: :c}\n        assert %{m: :n, m: :o, m: :p} == %{m: :p}\n        assert %{1 => 2, 1 => 3} == %{1 => 3}\n      end\n      \"\"\"\n    )\n\n    assert map_size(%{System.unique_integer() => 1, System.unique_integer() => 2}) == 2\n  end\n\n  test \"length(list) == 0 in guard\" do\n    assert_warn_eval(\n      [\n        \"nofile:5:24\",\n        \"do not use \\\"length(v) == 0\\\" to check if a list is empty\",\n        \"Prefer to pattern match on an empty list or use \\\"v == []\\\" as a guard\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def list_case do\n          v = []\n          case v do\n            _ when length(v) == 0 -> :ok\n            _ -> :fail\n          end\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"length(list) > 0 in guard\" do\n    assert_warn_eval(\n      [\n        \"nofile:5:24\",\n        \"do not use \\\"length(v) > 0\\\" to check if a list is not empty\",\n        \"Prefer to pattern match on a non-empty list, such as [_ | _], or use \\\"v != []\\\" as a guard\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def list_case do\n          v = []\n          case v do\n            _ when length(v) > 0 -> :ok\n            _ -> :fail\n          end\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"late function heads\" do\n    assert_warn_eval(\n      [\n        \"nofile:4:7\\n\",\n        \"function head for def add/2 must come at the top of its direct implementation\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def add(a, b), do: a + b\n        @doc \"hello\"\n        def add(a, b)\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"late function heads do not warn of meta programming\" do\n    assert capture_eval(\"\"\"\n           defmodule Sample1 do\n             defmacro __using__(_) do\n               quote do\n                 def add(a, b), do: a + b\n               end\n             end\n           end\n\n           defmodule Sample2 do\n             use Sample1\n             @doc \"hello\"\n             def add(a, b)\n           end\n           \"\"\") == \"\"\n\n    assert capture_eval(\"\"\"\n           defmodule Sample3 do\n            for fun <- [:foo, :bar] do\n              def unquote(fun)(), do: unquote(fun)\n            end\n\n             def foo()\n             def bar()\n           end\n           \"\"\") == \"\"\n  after\n    purge([Sample1, Sample2, Sample3])\n  end\n\n  test \"used import via alias\" do\n    assert capture_eval(\"\"\"\n           defmodule Sample1 do\n             import List, only: [flatten: 1]\n\n             defmacro generate do\n               List.duplicate(quote(do: flatten([1, 2, 3])), 100)\n             end\n           end\n\n           defmodule Sample2 do\n             import Sample1\n             generate()\n           end\n           \"\"\") == \"\"\n  after\n    purge([Sample1, Sample2])\n  end\n\n  test \"clause not match\" do\n    assert_warn_eval(\n      [\n        \"nofile:3:7\\n\",\n        ~r\"this clause( for hello/0)? cannot match because a previous clause at line 2 always matches\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def hello, do: nil\n        def hello, do: nil\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"generated clause not match\" do\n    assert_warn_eval(\n      [\n        \"nofile:10\\n\",\n        ~r\"this clause( for hello/0)? cannot match because a previous clause at line 10 always matches\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        defmacro __using__(_) do\n          quote do\n            def hello, do: nil\n            def hello, do: nil\n          end\n        end\n      end\n      defmodule UseSample do\n        use Sample\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n    purge(UseSample)\n  end\n\n  test \"deprecated closing sigil delimiter\" do\n    assert_warn_eval([\"nofile:1:7\", \"deprecated\"], \"~S(foo\\\\))\")\n  end\n\n  test \"deprecated not left in right\" do\n    assert_warn_eval([\"nofile:1:7\", \"deprecated\"], \"not 1 in [1, 2, 3]\")\n  end\n\n  test \"clause with defaults should be first\" do\n    message = \"def hello/1 has multiple clauses and also declares default values\"\n\n    assert_warn_eval(\n      [\"nofile:3:7\\n\", message, \"the previous clause is defined on line 2\"],\n      ~S\"\"\"\n      defmodule Sample1 do\n        def hello(arg), do: arg\n        def hello(arg \\\\ 0), do: arg\n      end\n      \"\"\"\n    )\n\n    assert_warn_eval(\n      [\"nofile:3:7\\n\", message, \"the previous clause is defined on line 2\"],\n      ~S\"\"\"\n      defmodule Sample2 do\n        def hello(_arg)\n        def hello(arg \\\\ 0), do: arg\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2])\n  end\n\n  test \"clauses with default should use header\" do\n    assert_warn_eval(\n      [\n        \"nofile:3:7\\n\",\n        \"def hello/1 has multiple clauses and also declares default values\",\n        \"the previous clause is defined on line 2\"\n      ],\n      ~S\"\"\"\n      defmodule Sample do\n        def hello(arg \\\\ 0), do: arg\n        def hello(arg), do: arg\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unused with local with overridable\" do\n    assert_warn_eval(\n      [\"nofile:3:8: \", \"function world/0 is unused\"],\n      \"\"\"\n      defmodule Sample do\n        def hello, do: world()\n        defp world, do: :ok\n        defoverridable [hello: 0]\n        def hello, do: :ok\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"undefined module attribute\" do\n    assert_warn_eval(\n      [\n        \"nofile:2: \",\n        \"undefined module attribute @foo, please remove access to @foo or explicitly set it before access\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        @foo\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"parens with module attribute\" do\n    assert_warn_eval(\n      [\n        \"nofile:3: \",\n        \"the @foo() notation (with parentheses) is deprecated, please use @foo (without parentheses) instead\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        @foo 13\n        @foo()\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"undefined module attribute in function\" do\n    assert_warn_eval(\n      [\n        \"nofile:3: \",\n        \"undefined module attribute @foo, please remove access to @foo or explicitly set it before access\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def hello do\n          @foo\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"undefined module attribute with file\" do\n    assert_warn_eval(\n      [\n        \"nofile:2: \",\n        \"undefined module attribute @foo, please remove access to @foo or explicitly set it before access\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        @foo\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"parse transform\" do\n    assert_warn_eval(\n      [\"nofile:1: \", \"@compile {:parse_transform, :ms_transform} is deprecated\"],\n      \"\"\"\n      defmodule Sample do\n        @compile {:parse_transform, :ms_transform}\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"@compile inline no warning for unreachable function\" do\n    refute capture_eval(\"\"\"\n           defmodule Sample do\n             @compile {:inline, foo: 1}\n\n             defp foo(_), do: :ok\n           end\n           \"\"\") =~ \"inlined function foo/1 undefined\"\n  after\n    purge(Sample)\n  end\n\n  test \"no effect operator\" do\n    assert_warn_eval(\n      [\"nofile:3:7\\n\", \"use of operator != has no effect\"],\n      \"\"\"\n      defmodule Sample do\n        def a(x) do\n          x != :foo\n          :ok\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"undefined function for behaviour\" do\n    assert_warn_eval(\n      [\n        \"nofile:5: \",\n        \"function foo/0 required by behaviour Sample1 is not implemented (in module Sample2)\"\n      ],\n      \"\"\"\n      defmodule Sample1 do\n        @callback foo :: term\n      end\n\n      defmodule Sample2 do\n        @behaviour Sample1\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2])\n  end\n\n  test \"undefined macro for behaviour\" do\n    assert_warn_eval(\n      [\n        \"nofile:5: \",\n        \"macro foo/0 required by behaviour Sample1 is not implemented (in module Sample2)\"\n      ],\n      \"\"\"\n      defmodule Sample1 do\n        @macrocallback foo :: Macro.t\n      end\n\n      defmodule Sample2 do\n        @behaviour Sample1\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2])\n  end\n\n  test \"wrong kind for behaviour\" do\n    assert_warn_eval(\n      [\n        \"nofile:5: \",\n        \"function foo/0 required by behaviour Sample1 was implemented as \\\"defmacro\\\" but should have been \\\"def\\\"\"\n      ],\n      \"\"\"\n      defmodule Sample1 do\n        @callback foo :: term\n      end\n\n      defmodule Sample2 do\n        @behaviour Sample1\n        defmacro foo, do: :ok\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2])\n  end\n\n  test \"conflicting behaviour\" do\n    assert_warn_eval(\n      [\n        \"nofile:9: \",\n        \"conflicting behaviours found. Callback function foo/0 is defined by both Sample1 and Sample2 (in module Sample3)\"\n      ],\n      \"\"\"\n      defmodule Sample1 do\n        @callback foo :: term\n      end\n\n      defmodule Sample2 do\n        @callback foo :: term\n      end\n\n      defmodule Sample3 do\n        @behaviour Sample1\n        @behaviour Sample2\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2, Sample3])\n  end\n\n  test \"conflicting behaviour (but one optional callback)\" do\n    message =\n      capture_compile(\"\"\"\n      defmodule Sample1 do\n        @callback foo :: term\n      end\n\n      defmodule Sample2 do\n        @callback foo :: term\n        @callback bar :: term\n        @optional_callbacks foo: 0\n      end\n\n      defmodule Sample3 do\n        @behaviour Sample1\n        @behaviour Sample2\n\n        @impl Sample1\n        def foo, do: 1\n        @impl Sample2\n        def bar, do: 2\n      end\n      \"\"\")\n\n    assert message =~\n             \"conflicting behaviours found. Callback function foo/0 is defined by both Sample1 and Sample2 (in module Sample3)\"\n\n    refute message =~ \"module attribute @impl was not set\"\n    refute message =~ \"this behaviour does not specify such callback\"\n  after\n    purge([Sample1, Sample2, Sample3])\n  end\n\n  test \"duplicate behaviour\" do\n    assert_warn_eval(\n      [\n        \"nofile:5: \",\n        \"the behaviour Sample1 has been declared twice (conflict in function foo/0 in module Sample2)\"\n      ],\n      \"\"\"\n      defmodule Sample1 do\n        @callback foo :: term\n      end\n\n      defmodule Sample2 do\n        @behaviour Sample1\n        @behaviour Sample1\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2])\n  end\n\n  test \"unknown remote call\" do\n    assert capture_compile(\"\"\"\n           defmodule Sample do\n             def perform(), do: Unknown.call()\n           end\n           \"\"\") =~\n             \"Unknown.call/0 is undefined (module Unknown is not available or is yet to be defined)\"\n  after\n    purge(Sample)\n  end\n\n  test \"undefined behaviour\" do\n    assert_warn_eval(\n      [\"nofile:1: \", \"@behaviour UndefinedBehaviour does not exist (in module Sample)\"],\n      \"\"\"\n      defmodule Sample do\n        @behaviour UndefinedBehaviour\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"empty behaviours\" do\n    assert_warn_eval(\n      [\"nofile:3: \", \"module EmptyBehaviour is not a behaviour (in module Sample)\"],\n      \"\"\"\n      defmodule EmptyBehaviour do\n      end\n      defmodule Sample do\n        @behaviour EmptyBehaviour\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n    purge(EmptyBehaviour)\n  end\n\n  test \"undefined function for protocol\" do\n    assert_warn_eval(\n      [\n        \"nofile:5: \",\n        \"function foo/1 required by protocol Sample1 is not implemented (in module Sample1.Atom)\"\n      ],\n      \"\"\"\n      defprotocol Sample1 do\n        def foo(subject)\n      end\n\n      defimpl Sample1, for: Atom do\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample1.Atom])\n  end\n\n  test \"ungrouped def name\" do\n    assert_warn_eval(\n      [\n        \"nofile:4:7\\n\",\n        \"clauses with the same name should be grouped together, \\\"def foo/2\\\" was previously defined (nofile:2)\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def foo(x, 1), do: x + 1\n        def foo(), do: nil\n        def foo(x, 2), do: x * 2\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"ungrouped def name and arity\" do\n    assert_warn_eval(\n      [\n        \"nofile:4:7\\n\",\n        \"clauses with the same name and arity (number of arguments) should be grouped together, \\\"def foo/2\\\" was previously defined (nofile:2)\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def foo(x, 1), do: x + 1\n        def bar(), do: nil\n        def foo(x, 2), do: x * 2\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"ungrouped defs do not warn of meta programming\" do\n    assert capture_eval(\"\"\"\n           defmodule Sample do\n             for atom <- [:foo, :bar] do\n               def from_string(unquote(to_string(atom))), do: unquote(atom)\n               def to_string(unquote(atom)), do: unquote(to_string(atom))\n             end\n           end\n           \"\"\") == \"\"\n  after\n    purge(Sample)\n  end\n\n  test \"warning with overridden file\" do\n    assert_warn_eval(\n      [\"sample:3:11:\", \"variable \\\"x\\\" is unused\"],\n      \"\"\"\n      defmodule Sample do\n        @file \"sample\"\n        def foo(x), do: :ok\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"warning on unnecessary code point escape\" do\n    assert capture_eval(\"?\\\\n + ?\\\\\\\\\") == \"\"\n\n    assert_warn_eval(\n      [\"nofile:1:1\", \"unknown escape sequence ?\\\\w, use ?w instead\"],\n      \"?\\\\w\"\n    )\n  end\n\n  test \"warning on code point escape\" do\n    assert_warn_eval(\n      [\"nofile:1:1\", \"found ? followed by code point 0x20 (space), please use ?\\\\s instead\"],\n      \"? \"\n    )\n\n    assert_warn_eval(\n      [\"nofile:1:1\", \"found ?\\\\ followed by code point 0x20 (space), please use ?\\\\s instead\"],\n      \"?\\\\ \"\n    )\n  end\n\n  test \"duplicated docs in the same clause\" do\n    output =\n      capture_eval(\"\"\"\n      defmodule Sample do\n        @doc \"Something\"\n        @doc \"Another\"\n        def foo, do: :ok\n      end\n      \"\"\")\n\n    assert output =~ \"redefining @doc attribute previously set at line 2\"\n    assert output =~ \"nofile:3: Sample (module)\"\n  after\n    purge(Sample)\n  end\n\n  test \"duplicate docs across clauses\" do\n    assert capture_eval(\"\"\"\n           defmodule Sample1 do\n             defmacro __using__(_) do\n               quote do\n                 @doc \"hello\"\n                 def add(a, 1), do: a + 1\n               end\n             end\n           end\n\n           defmodule Sample2 do\n             use Sample1\n             @doc \"world\"\n             def add(a, 2), do: a + 2\n           end\n           \"\"\") == \"\"\n\n    assert_warn_eval(\n      [\"nofile:4: \", \"redefining @doc attribute previously set at line\"],\n      \"\"\"\n      defmodule Sample3 do\n        @doc \"hello\"\n        def add(a, 1), do: a + 1\n        @doc \"world\"\n        def add(a, 2), do: a + 2\n      end\n      \"\"\"\n    )\n  after\n    purge([Sample1, Sample2, Sample3])\n  end\n\n  test \"reserved doc metadata keys\" do\n    {output, diagnostics} =\n      Code.with_diagnostics([log: true], fn ->\n        capture_eval(\"\"\"\n        defmodule Sample do\n          @typedoc opaque: false\n          @type t :: binary\n\n          @doc defaults: 3, since: \"1.2.3\"\n          def foo(a), do: a\n        end\n        \"\"\")\n      end)\n\n    assert output =~ \"ignoring reserved documentation metadata key: :opaque\"\n    assert output =~ \"nofile:2: \"\n    assert output =~ \"ignoring reserved documentation metadata key: :defaults\"\n    assert output =~ \"nofile:5: \"\n    refute output =~ \":since\"\n\n    assert [\n             %{\n               message: \"ignoring reserved documentation metadata key: :opaque\",\n               position: 2,\n               file: \"nofile\",\n               severity: :warning\n             },\n             %{\n               message: \"ignoring reserved documentation metadata key: :defaults\",\n               position: 5,\n               file: \"nofile\",\n               severity: :warning\n             }\n           ] = diagnostics\n  after\n    purge(Sample)\n  end\n\n  describe \"typespecs\" do\n    test \"unused types\" do\n      output =\n        capture_eval(\"\"\"\n        defmodule Sample do\n          @type pub :: any\n          @opaque op :: any\n          @typep priv :: any\n          @typep priv_args(var1, var2) :: {var1, var2}\n          @typep priv2 :: any\n          @typep priv3 :: priv2 | atom\n\n          @spec my_fun(priv3) :: pub\n          def my_fun(var), do: var\n        end\n        \"\"\")\n\n      assert output =~ \"nofile:4: \"\n      assert output =~ \"type priv/0 is unused\"\n      assert output =~ \"nofile:5: \"\n      assert output =~ \"type priv_args/2 is unused\"\n      refute output =~ \"type pub/0 is unused\"\n      refute output =~ \"type op/0 is unused\"\n      refute output =~ \"type priv2/0 is unused\"\n      refute output =~ \"type priv3/0 is unused\"\n    after\n      purge(Sample)\n    end\n\n    test \"underspecified opaque types\" do\n      output =\n        capture_eval(\"\"\"\n        defmodule Sample do\n          @opaque op1 :: term\n          @opaque op2 :: any\n          @opaque op3 :: atom\n        end\n        \"\"\")\n\n      assert output =~ \"nofile:2: \"\n      assert output =~ \"@opaque type op1/0 is underspecified and therefore meaningless\"\n      assert output =~ \"nofile:3: \"\n      assert output =~ \"@opaque type op2/0 is underspecified and therefore meaningless\"\n      refute output =~ \"nofile:4: \"\n      refute output =~ \"op3\"\n    after\n      purge(Sample)\n    end\n\n    test \"underscored types variables\" do\n      output =\n        capture_eval(\"\"\"\n        defmodule Sample do\n          @type in_typespec_vars(_var1, _var1) :: atom\n          @type in_typespec(_var2) :: {atom, _var2}\n\n          @spec in_spec(_var3) :: {atom, _var3} when _var3: var\n          def in_spec(a), do: {:ok, a}\n        end\n        \"\"\")\n\n      assert output =~ \"nofile:2: \"\n      assert output =~ ~r/the underscored type variable \"_var1\" is used more than once/\n      assert output =~ \"nofile:3: \"\n      assert output =~ ~r/the underscored type variable \"_var2\" is used more than once/\n      assert output =~ \"nofile:5: \"\n      assert output =~ ~r/the underscored type variable \"_var3\" is used more than once/\n    after\n      purge(Sample)\n    end\n\n    test \"typedoc on typep\" do\n      assert_warn_eval(\n        [\n          \"nofile:2: \",\n          \"type priv/0 is private, @typedoc's are always discarded for private types\"\n        ],\n        \"\"\"\n        defmodule Sample do\n          @typedoc \"Something\"\n          @typep priv :: any\n          @spec foo() :: priv\n          def foo(), do: nil\n        end\n        \"\"\"\n      )\n    after\n      purge(Sample)\n    end\n\n    test \"discouraged types\" do\n      string_discouraged =\n        \"string() type use is discouraged. \" <>\n          \"For character lists, use charlist() type, for strings, String.t()\\n\"\n\n      nonempty_string_discouraged =\n        \"nonempty_string() type use is discouraged. \" <>\n          \"For non-empty character lists, use nonempty_charlist() type, for strings, String.t()\\n\"\n\n      assert_warn_eval(\n        [\n          \"nofile:2: \",\n          string_discouraged,\n          \"nofile:3: \",\n          nonempty_string_discouraged\n        ],\n        \"\"\"\n        defmodule Sample do\n          @type foo :: string()\n          @type bar :: nonempty_string()\n        end\n        \"\"\"\n      )\n    after\n      purge(Sample)\n    end\n\n    test \"nested type annotations\" do\n      message = \"invalid type annotation. Type annotations cannot be nested\"\n\n      assert_warn_eval(\n        [\"nofile:2: \", message],\n        \"\"\"\n        defmodule Sample1 do\n          @type my_type :: ann_type :: nested_ann_type :: atom\n        end\n        \"\"\"\n      )\n\n      purge(Sample1)\n\n      assert_warn_eval(\n        [\"nofile:2: \", message],\n        \"\"\"\n        defmodule Sample2 do\n          @type my_type :: ann_type :: nested_ann_type :: atom | port\n        end\n        \"\"\"\n      )\n\n      purge(Sample2)\n\n      assert_warn_eval(\n        [\"nofile:2: \", message],\n        \"\"\"\n        defmodule Sample3 do\n          @spec foo :: {pid, ann_type :: nested_ann_type :: atom}\n          def foo, do: nil\n        end\n        \"\"\"\n      )\n    after\n      purge([Sample1, Sample2, Sample3])\n    end\n\n    test \"invalid fun\" do\n      assert_warn_eval(\n        [\n          \"nofile:2: \",\n          \"fun/1 is not valid in typespecs. Either specify fun() or use (... -> return) instead\"\n        ],\n        \"\"\"\n        defmodule InvalidFunType do\n          @type my_type :: fun(integer())\n        end\n        \"\"\"\n      )\n    end\n\n    test \"invalid type annotations\" do\n      assert_warn_eval(\n        [\n          \"nofile:2: \",\n          \"invalid type annotation. The left side of :: must be a variable, got: pid()\"\n        ],\n        \"\"\"\n        defmodule Sample1 do\n          @type my_type :: (pid() :: atom)\n        end\n        \"\"\"\n      )\n\n      message =\n        \"invalid type annotation. The left side of :: must be a variable, got: pid | ann_type. \" <>\n          \"Note \\\"left | right :: ann\\\" is the same as \\\"(left | right) :: ann\\\"\"\n\n      assert_warn_eval(\n        [\"nofile:2: \", message],\n        \"\"\"\n        defmodule Sample2 do\n          @type my_type :: pid | ann_type :: atom\n        end\n        \"\"\"\n      )\n    after\n      purge([Sample1, Sample2])\n    end\n  end\n\n  test \"attribute with no use\" do\n    assert_warn_eval(\n      [\"nofile:2: \", \"module attribute @at was set but never used\"],\n      \"\"\"\n      defmodule Sample do\n        @at \"Something\"\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"registered attribute with no use\" do\n    assert_warn_eval(\n      [\"nofile:3: \", \"module attribute @at was set but never used\"],\n      \"\"\"\n      defmodule Sample do\n        Module.register_attribute(__MODULE__, :at, [])\n        @at \"Something\"\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"typedoc with no type\" do\n    assert_warn_eval(\n      [\"nofile:2: \", \"module attribute @typedoc was set but no type follows it\"],\n      \"\"\"\n      defmodule Sample do\n        @typedoc \"Something\"\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"doc with no function\" do\n    assert_warn_eval(\n      [\"nofile:2: \", \"module attribute @doc was set but no definition follows it\"],\n      \"\"\"\n      defmodule Sample do\n        @doc \"Something\"\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"pipe without explicit parentheses\" do\n    assert_warn_eval(\n      [\"nofile:2:1\", \"parentheses are required when piping into a function call\"],\n      \"\"\"\n      [5, 6, 7, 3]\n      |> Enum.map_join \"\", &(Integer.to_string(&1))\n      |> String.to_integer\n      \"\"\"\n    )\n  end\n\n  test \"keywords without explicit parentheses\" do\n    assert_warn_eval(\n      [\"nofile:2\\n\", \"missing parentheses for expression following \\\"label:\\\" keyword. \"],\n      \"\"\"\n      quote do\n        IO.inspect arg, label: if true, do: \"foo\", else: \"baz\"\n      end\n      \"\"\"\n    )\n  end\n\n  test \"do+end with operator without explicit parentheses\" do\n    assert_warn_eval(\n      [\"nofile:3\\n\", \"missing parentheses on expression following operator \\\"||\\\"\"],\n      \"\"\"\n      quote do\n        case do\n        end || raise 1, 2\n      end\n      \"\"\"\n    )\n  end\n\n  test \"do+end with not in operator without explicit parentheses\" do\n    assert_warn_eval(\n      [\"nofile:3\\n\", \"missing parentheses on expression following operator \\\"not in\\\"\"],\n      \"\"\"\n      quote do\n        case do\n        end not in no_parens 1, 2\n      end\n      \"\"\"\n    )\n  end\n\n  test \"variable is being expanded to function call (on_undefined_variable: warn)\" do\n    capture_io(:stderr, fn ->\n      Code.put_compiler_option(:on_undefined_variable, :warn)\n    end)\n\n    output =\n      capture_eval(\"\"\"\n      self\n      defmodule Sample do\n        def my_node(), do: node\n      end\n      \"\"\")\n\n    assert output =~ \"variable \\\"self\\\" does not exist and is being expanded to \\\"self()\\\"\"\n    assert output =~ \"nofile:1:1\"\n    assert output =~ \"variable \\\"node\\\" does not exist and is being expanded to \\\"node()\\\"\"\n    assert output =~ \"nofile:3:22\"\n  after\n    Code.put_compiler_option(:on_undefined_variable, :raise)\n    purge(Sample)\n  end\n\n  defmodule User do\n    defstruct [:name]\n  end\n\n  test \":__struct__ is ignored when using structs\" do\n    assert capture_err(fn ->\n             code = \"\"\"\n             assert %Kernel.WarningTest.User{__struct__: Ignored, name: \"joe\"} ==\n                    %Kernel.WarningTest.User{name: \"joe\"}\n             \"\"\"\n\n             Code.eval_string(code, [], __ENV__)\n           end) =~ \"key :__struct__ is ignored when using structs\"\n\n    assert capture_err(fn ->\n             code = \"\"\"\n             user = %Kernel.WarningTest.User{name: \"meg\"}\n             assert %Kernel.WarningTest.User{user | __struct__: Ignored, name: \"joe\"} ==\n                    %Kernel.WarningTest.User{__struct__: Kernel.WarningTest.User, name: \"joe\"}\n             \"\"\"\n\n             Code.eval_string(code, [], __ENV__)\n           end) =~ \"key :__struct__ is ignored when using structs\"\n  end\n\n  test \"catch comes before rescue in try block\" do\n    assert_warn_eval(\n      [\"nofile:1:1\\n\", ~s(\"catch\" should always come after \"rescue\" in try)],\n      \"\"\"\n      try do\n        :trying\n      catch\n        _ -> :caught\n      rescue\n        _ -> :error\n      end\n      \"\"\"\n    )\n  end\n\n  test \"catch comes before rescue in def\" do\n    assert_warn_eval(\n      [\"nofile:2:7\\n\", ~s(\"catch\" should always come after \"rescue\" in def)],\n      \"\"\"\n      defmodule Sample do\n        def foo do\n          :trying\n        catch\n          _, _ -> :caught\n        rescue\n          _ -> :error\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unused variable in defguard\" do\n    assert_warn_eval(\n      [\"nofile:2:21\", \"variable \\\"baz\\\" is unused\"],\n      \"\"\"\n      defmodule Sample do\n        defguard foo(bar, baz) when bar\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unused import in defguard\" do\n    assert_warn_eval(\n      [\"nofile:2:3\", \"unused import Record\\n\"],\n      \"\"\"\n      defmodule Sample do\n        import Record\n        defguard is_record(baz) when baz\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"unused private guard\" do\n    assert_warn_eval(\n      [\"nofile:2:13: \", \"macro foo/2 is unused\\n\"],\n      \"\"\"\n      defmodule Sample do\n        defguardp foo(bar, baz) when bar + baz\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"defguard overriding defmacro\" do\n    assert_warn_eval(\n      [\n        \"nofile:3:12\\n\",\n        ~r\"this clause( for foo/1)? cannot match because a previous clause at line 2 always matches\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        defmacro foo(bar), do: bar == :bar\n        defguard foo(baz) when baz == :baz\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"defmacro overriding defguard\" do\n    assert_warn_eval(\n      [\n        \"nofile:3:12\\n\",\n        ~r\"this clause( for foo/1)? cannot match because a previous clause at line 2 always matches\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        defguard foo(baz) when baz == :baz\n        defmacro foo(bar), do: bar == :bar\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"deprecated GenServer super on callbacks\" do\n    assert_warn_eval(\n      [\"nofile:1: \", \"calling super for GenServer callback handle_call/3 is deprecated\"],\n      \"\"\"\n      defmodule Sample do\n        use GenServer\n\n        def handle_call(a, b, c) do\n          super(a, b, c)\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"super is allowed on GenServer.child_spec/1\" do\n    refute capture_eval(\"\"\"\n           defmodule Sample do\n             use GenServer\n\n             def child_spec(opts) do\n               super(opts)\n             end\n           end\n           \"\"\") =~ \"calling super for GenServer callback child_spec/1 is deprecated\"\n  after\n    purge(Sample)\n  end\n\n  test \"def warns if only clause is else\" do\n    assert_warn_compile(\n      [\"nofile:2:7\\n\", \"\\\"else\\\" shouldn't be used as the only clause in \\\"def\\\"\"],\n      \"\"\"\n      defmodule Sample do\n        def foo do\n          :bar\n        else\n          _other -> :ok\n        end\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"try warns if only clause is else\" do\n    assert_warn_compile(\n      [\"nofile:1:1\\n\", \"\\\"else\\\" shouldn't be used as the only clause in \\\"try\\\"\"],\n      \"\"\"\n      try do\n        :ok\n      else\n        other -> other\n      end\n      \"\"\"\n    )\n  end\n\n  test \"sigil w/W warns on trailing comma at macro expansion time\" do\n    for sigil <- ~w(w W),\n        modifier <- ~w(a s c) do\n      output =\n        capture_err(fn ->\n          {:ok, ast} =\n            \"~#{sigil}(foo, bar baz)#{modifier}\"\n            |> Code.string_to_quoted()\n\n          Macro.expand(ast, __ENV__)\n        end)\n\n      assert output =~ \"the sigils ~w/~W do not allow trailing commas\"\n    end\n  end\n\n  test \"warnings on trailing comma on call\" do\n    assert_warn_eval(\n      [\"nofile:1:25\\n\", \"trailing commas are not allowed inside function/macro call arguments\"],\n      \"Keyword.merge([], foo: 1,)\"\n    )\n  end\n\n  test \"defstruct warns with duplicate keys\" do\n    assert_warn_eval(\n      [\"nofile:2: Sample\", \"duplicate key :foo found in struct\"],\n      \"\"\"\n      defmodule Sample do\n        defstruct [:foo, :bar, foo: 1]\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"deprecate nullary remote zero-arity capture with parens\" do\n    assert capture_eval(\"\"\"\n           import System, only: [pid: 0]\n           &pid/0\n           \"\"\") == \"\"\n\n    assert_warn_eval(\n      [\n        \"nofile:1:1\\n\",\n        \"extra parentheses on a remote function capture &System.pid()/0 have been deprecated. Please remove the parentheses: &System.pid/0\"\n      ],\n      \"\"\"\n      &System.pid()/0\n      \"\"\"\n    )\n  end\n\n  test \"deprecate &module.fun/arity captures with complex expressions as modules\" do\n    assert_warn_eval(\n      [\n        \"nofile:2:\",\n        \"\"\"\n        expected the module in &module.fun/arity to expand to a variable or an atom, got: hd(modules)\n        You can either compute the module name outside of & or convert it to a regular anonymous function.\n        \"\"\"\n      ],\n      \"\"\"\n      defmodule Sample do\n        def foo(modules), do: &hd(modules).module_info/0\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"deprecate non-quoted variables in bitstring size modifiers\" do\n    assert_warn_eval(\n      [\n        \"the variable \\\"a\\\" is accessed inside size(...) of a bitstring but it was defined outside of the match\",\n        \"You must precede it with the pin operator\"\n      ],\n      \"\"\"\n      a = \"foo\"\n      <<a::binary-size(byte_size(a) - 1)>> <> _ = a\n      \"fo\" = a\n      \"\"\"\n    )\n  end\n\n  defp assert_compile_error(messages, string) do\n    captured =\n      capture_err(fn ->\n        assert_raise CompileError, fn ->\n          ast = Code.string_to_quoted!(string, columns: true)\n          Code.eval_quoted(ast)\n        end\n      end)\n\n    for message <- List.wrap(messages) do\n      assert captured =~ message\n    end\n  end\n\n  defp purge(list) when is_list(list) do\n    Enum.each(list, &purge/1)\n  end\n\n  test \"unused require\" do\n    assert_warn_compile(\n      [\"nofile:1:1\", \"unused require Logger\"],\n      \"\"\"\n      require Logger\n      \"\"\"\n    )\n\n    # Within a module\n    assert_warn_compile(\n      [\"nofile:2:3\", \"unused require Application\"],\n      \"\"\"\n      defmodule Sample do\n        require Application\n        def a, do: nil\n      end\n      \"\"\"\n    )\n\n    # Unused require and alias\n    assert_warn_compile(\n      [\"nofile:2:3\", \"unused require Application (the alias is also unused)\"],\n      \"\"\"\n      defmodule Sample do\n        require Application, as: A\n        def a, do: nil\n      end\n      \"\"\"\n    )\n\n    # Unused require but used alias\n    assert_warn_compile(\n      [\"nofile:2:3\", \"unused require Application (convert it to an alias instead)\"],\n      \"\"\"\n      defmodule Sample do\n        require Application, as: A\n        def a, do: A.started_applications()\n      end\n      \"\"\"\n    )\n  after\n    purge(Sample)\n  end\n\n  test \"conditional require\" do\n    assert capture_err(fn ->\n             defmodule KernelTest.ConditionalRequire do\n               if false do\n                 require Integer\n                 def fun(x), do: Integer.is_odd(x)\n               end\n             end\n           end) == \"\"\n  after\n    purge(Sample)\n  end\n\n  defp purge(module) when is_atom(module) do\n    :code.purge(module)\n    :code.delete(module)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel/with_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Kernel.WithTest do\n  use ExUnit.Case, async: true\n\n  test \"basic with\" do\n    assert with({:ok, res} <- ok(41), do: res) == 41\n    assert with(res <- four(), do: res + 10) == 14\n  end\n\n  test \"matching with\" do\n    assert with(_..42//_ <- 1..42, do: :ok) == :ok\n    assert with({:ok, res} <- error(), do: res) == :error\n    assert with({:ok, _} = res <- ok(42), do: elem(res, 1)) == 42\n  end\n\n  test \"with guards\" do\n    assert with(x when x < 2 <- four(), do: :ok) == 4\n    assert with(x when x > 2 <- four(), do: :ok) == :ok\n    assert with(x when x < 2 when x == 4 <- four(), do: :ok) == :ok\n  end\n\n  test \"pin matching with\" do\n    key = :ok\n    assert with({^key, res} <- ok(42), do: res) == 42\n  end\n\n  test \"pin matching with multiple else\" do\n    key = :error\n\n    first_else =\n      with nil <- error() do\n        :ok\n      else\n        ^key -> :pinned\n        _other -> :other\n      end\n\n    assert first_else == :pinned\n\n    second_else =\n      with nil <- ok(42) do\n        :ok\n      else\n        ^key -> :pinned\n        _other -> :other\n      end\n\n    assert second_else == :other\n  end\n\n  test \"two levels with\" do\n    result =\n      with {:ok, n1} <- ok(11),\n           n2 <- 22,\n           do: n1 + n2\n\n    assert result == 33\n\n    result =\n      with n1 <- 11,\n           {:ok, n2} <- error(),\n           do: n1 + n2\n\n    assert result == :error\n  end\n\n  test \"binding inside with\" do\n    result =\n      with {:ok, n1} <- ok(11),\n           n2 = n1 + 10,\n           {:ok, n3} <- ok(22),\n           do: n2 + n3\n\n    assert result == 43\n\n    result =\n      with {:ok, n1} <- ok(11),\n           n2 = n1 + 10,\n           {:ok, n3} <- error(),\n           do: n2 + n3\n\n    assert result == :error\n  end\n\n  test \"does not leak variables to else\" do\n    state = 1\n\n    result =\n      with 1 <- state,\n           state = 2,\n           :ok <- error(),\n           do: state,\n           else: (_ -> state)\n\n    assert result == 1\n    assert state == 1\n  end\n\n  test \"with shadowing\" do\n    assert with(\n             a <-\n               (\n                 b = 1\n                 _ = b\n                 1\n               ),\n             b <- 2,\n             do: a + b\n           ) == 3\n  end\n\n  test \"with extra guards\" do\n    var =\n      with %_{} = a <- struct(URI),\n           %_{} <- a do\n        :ok\n      end\n\n    assert var == :ok\n  end\n\n  test \"errors in with\" do\n    assert_raise RuntimeError, fn ->\n      with({:ok, res} <- oops(), do: res)\n    end\n\n    assert_raise RuntimeError, fn ->\n      with({:ok, res} <- ok(42), oops(), do: res)\n    end\n  end\n\n  test \"else conditions\" do\n    assert (with {:ok, res} <- four() do\n              res\n            else\n              {:error, error} -> error\n              res -> res + 1\n            end) == 5\n\n    assert (with {:ok, res} <- four() do\n              res\n            else\n              res when res == 4 -> res + 1\n              res -> res\n            end) == 5\n\n    assert with({:ok, res} <- four(), do: res, else: (_ -> :error)) == :error\n  end\n\n  test \"else conditions with match error\" do\n    assert_raise WithClauseError, \"no with clause matching:\\n\\n    :error\\n\", fn ->\n      with({:ok, res} <- error(), do: res, else: ({:error, error} -> error))\n    end\n  end\n\n  defp four() do\n    4\n  end\n\n  defp error() do\n    :error\n  end\n\n  defp ok(num) do\n    {:ok, num}\n  end\n\n  defp oops() do\n    raise(\"oops\")\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/kernel_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule KernelTest do\n  use ExUnit.Case, async: true\n\n  # Skip these doctests are they emit warnings\n  doctest Kernel,\n    except:\n      [===: 2, !==: 2, and: 2, or: 2] ++\n        [is_exception: 1, is_exception: 2, is_nil: 1, is_struct: 1, is_non_struct_map: 1]\n\n  def id(arg), do: arg\n  def id(arg1, arg2), do: {arg1, arg2}\n  def empty_map, do: %{}\n\n  defp purge(module) do\n    :code.purge(module)\n    :code.delete(module)\n  end\n\n  defp assert_eval_raise(error, msg, string) do\n    assert_raise error, msg, fn ->\n      Code.eval_string(string)\n    end\n  end\n\n  test \"op ambiguity\" do\n    max = 1\n    assert max == 1\n    assert max(1, 2) == 2\n  end\n\n  describe \"=/2\" do\n    test \"can be reassigned\" do\n      var = 1\n      id(var)\n      var = 2\n      assert var == 2\n    end\n\n    test \"can be reassigned inside a list\" do\n      _ = [var = 1, 2, 3]\n      id(var)\n      _ = [var = 2, 3, 4]\n      assert var == 2\n    end\n\n    test \"can be reassigned inside a keyword list\" do\n      _ = [a: var = 1, b: 2]\n      id(var)\n      _ = [b: var = 2, c: 3]\n      assert var == 2\n    end\n\n    test \"can be reassigned inside a call\" do\n      id(var = 1)\n      id(var)\n      id(var = 2)\n      assert var == 2\n    end\n\n    test \"can be reassigned inside a multi-argument call\" do\n      id(:arg, var = 1)\n      id(:arg, var)\n      id(:arg, var = 2)\n      assert var == 2\n\n      id(:arg, a: 1, b: var = 2)\n      id(:arg, var)\n      id(:arg, b: 2, c: var = 3)\n      assert var == 3\n    end\n\n    test \"++/2 works in matches\" do\n      [1, 2] ++ var = [1, 2]\n      assert var == []\n\n      [1, 2] ++ var = [1, 2, 3]\n      assert var == [3]\n\n      ~c\"ab\" ++ var = ~c\"abc\"\n      assert var == ~c\"c\"\n\n      [:a, :b] ++ var = [:a, :b, :c]\n      assert var == [:c]\n    end\n  end\n\n  test \"=~/2\" do\n    assert \"abcd\" =~ ~r/c(d)/ == true\n    assert \"abcd\" =~ ~r/e/ == false\n\n    string = \"^ab+cd*$\"\n    assert string =~ \"ab+\" == true\n    assert string =~ \"bb\" == false\n\n    assert \"abcd\" =~ ~r// == true\n    assert \"abcd\" =~ \"\" == true\n\n    assert \"\" =~ ~r// == true\n    assert \"\" =~ \"\" == true\n\n    assert \"\" =~ \"abcd\" == false\n    assert \"\" =~ ~r/abcd/ == false\n  end\n\n  test \"^\" do\n    x = List.first([1])\n\n    assert_raise MatchError, fn ->\n      {x, ^x} = {2, 2}\n      x\n    end\n  end\n\n  # Note we use `==` in assertions so `assert` does not rewrite `match?/2`.\n  test \"match?/2\" do\n    a = List.first([0])\n    assert match?(b when b > a, 1) == true\n    assert binding() == [a: 0]\n\n    assert match?(b when b > a, -1) == false\n    assert binding() == [a: 0]\n\n    # Does not warn on underscored variables\n    assert match?(_unused, a) == true\n  end\n\n  def exported?, do: not_exported?()\n  defp not_exported?, do: true\n\n  test \"function_exported?/3\" do\n    assert function_exported?(__MODULE__, :exported?, 0)\n    refute function_exported?(__MODULE__, :not_exported?, 0)\n  end\n\n  test \"macro_exported?/3\" do\n    assert macro_exported?(Kernel, :in, 2) == true\n    assert macro_exported?(Kernel, :def, 1) == true\n    assert macro_exported?(Kernel, :def, 2) == true\n    assert macro_exported?(Kernel, :def, 3) == false\n    assert macro_exported?(Kernel, :no_such_macro, 2) == false\n    assert macro_exported?(:erlang, :abs, 1) == false\n  end\n\n  test \"apply/3 and apply/2\" do\n    assert apply(Enum, :reverse, [[1 | [2, 3]]]) == [3, 2, 1]\n    assert apply(fn x -> x * 2 end, [2]) == 4\n  end\n\n  test \"binding/0 and binding/1\" do\n    x = 1\n    assert binding() == [x: 1]\n\n    x = 2\n    assert binding() == [x: 2]\n\n    y = 3\n    assert binding() == [x: 2, y: 3]\n\n    var!(x, :foo) = 4\n    assert binding() == [x: 2, y: 3]\n    assert binding(:foo) == [x: 4]\n\n    # No warnings\n    _x = 1\n    assert binding() == [_x: 1, x: 2, y: 3]\n  end\n\n  defmodule User do\n    assert is_map(defstruct name: \"john\")\n    # Ensure we keep the line information around.\n    # It is important for debugging tools, ExDoc, etc.\n    {:v1, :def, anno, _clauses} = Module.get_definition(__MODULE__, {:__struct__, 1})\n    anno[:line] == __ENV__.line - 4\n  end\n\n  test \"struct/1 and struct/2\" do\n    assert struct(User) == %User{name: \"john\"}\n\n    user = struct(User, name: \"meg\")\n    assert user == %User{name: \"meg\"}\n    assert struct(user, %{name: \"meg\"}) == user\n\n    assert struct(user, unknown: \"key\") == user\n    assert struct(user, %{name: \"john\"}) == %User{name: \"john\"}\n    assert struct(user, name: \"other\", __struct__: Post) == %User{name: \"other\"}\n  end\n\n  test \"struct!/1 and struct!/2\" do\n    assert struct!(User) == %User{name: \"john\"}\n\n    user = struct!(User, name: \"meg\")\n    assert user == %User{name: \"meg\"}\n\n    assert_raise KeyError, fn ->\n      struct!(user, unknown: \"key\")\n    end\n\n    assert struct!(user, %{name: \"john\"}) == %User{name: \"john\"}\n    assert struct!(user, name: \"other\", __struct__: Post) == %User{name: \"other\"}\n  end\n\n  test \"if/2 with invalid keys\" do\n    error_message =\n      \"invalid or duplicate keys for if, only \\\"do\\\" and an optional \\\"else\\\" are permitted\"\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"if true, foo: 7\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"if true, do: 6, boo: 7\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"if true, do: 7, do: 6\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"if true, do: 8, else: 7, else: 6\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"if true, else: 6\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"if true, []\")\n    end\n  end\n\n  test \"unless/2 with invalid keys\" do\n    error_message =\n      \"invalid or duplicate keys for unless, only \\\"do\\\" \" <>\n        \"and an optional \\\"else\\\" are permitted\"\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"unless true, foo: 7\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"unless true, do: 6, boo: 7\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"unless true, do: 7, do: 6\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"unless true, do: 8, else: 7, else: 6\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"unless true, else: 6\")\n    end\n\n    assert_raise ArgumentError, error_message, fn ->\n      Code.eval_string(\"unless true, []\")\n    end\n  end\n\n  test \"and/2\" do\n    assert (true and false) == false\n    assert (true and true) == true\n    assert (true and 0) == 0\n    assert (false and false) == false\n    assert (false and true) == false\n    assert (false and 0) == false\n    assert (false and raise(\"oops\")) == false\n    assert ((x = Process.get(:unused, true)) and not x) == false\n    assert_raise BadBooleanError, fn -> Process.get(:unused, 0) and 1 end\n  end\n\n  test \"or/2\" do\n    assert (true or false) == true\n    assert (true or true) == true\n    assert (true or 0) == true\n    assert (true or raise(\"foo\")) == true\n    assert (false or false) == false\n    assert (false or true) == true\n    assert (false or 0) == 0\n    assert ((x = Process.get(:unused, false)) or not x) == true\n    assert_raise BadBooleanError, fn -> Process.get(:unused, 0) or 1 end\n  end\n\n  defp delegate_is_struct(arg), do: is_struct(arg)\n\n  defp guarded_is_struct(arg) when is_struct(arg), do: true\n  defp guarded_is_struct(_arg), do: false\n\n  defp struct_or_map?(arg) when is_struct(arg) or is_map(arg), do: true\n  defp struct_or_map?(_arg), do: false\n\n  test \"is_struct/1\" do\n    assert delegate_is_struct(%{}) == false\n    assert delegate_is_struct([]) == false\n    assert delegate_is_struct(%Macro.Env{}) == true\n    assert delegate_is_struct(%{__struct__: \"foo\"}) == false\n    assert guarded_is_struct(%Macro.Env{}) == true\n    assert guarded_is_struct(%{__struct__: \"foo\"}) == false\n    assert guarded_is_struct([]) == false\n    assert guarded_is_struct(%{}) == false\n  end\n\n  test \"is_struct/1 and other match works\" do\n    assert struct_or_map?(%Macro.Env{}) == true\n    assert struct_or_map?(%{}) == true\n    assert struct_or_map?(10) == false\n  end\n\n  defp delegate_is_struct(arg, name), do: is_struct(arg, name)\n\n  defp guarded_is_struct(arg, name) when is_struct(arg, name), do: true\n  defp guarded_is_struct(_arg, _name), do: false\n\n  defp struct_or_map?(arg, name) when is_struct(arg, name) or is_map(arg), do: true\n  defp struct_or_map?(_arg, _name), do: false\n\n  defp not_atom(), do: \"not atom\"\n\n  test \"is_struct/2\" do\n    assert delegate_is_struct(%{}, Macro.Env) == false\n    assert delegate_is_struct([], Macro.Env) == false\n    assert delegate_is_struct(%Macro.Env{}, Macro.Env) == true\n    assert delegate_is_struct(%Macro.Env{}, URI) == false\n    assert guarded_is_struct(%Macro.Env{}, Macro.Env) == true\n    assert guarded_is_struct(%Macro.Env{}, URI) == false\n    assert guarded_is_struct(%{__struct__: \"foo\"}, \"foo\") == false\n    assert guarded_is_struct(%{__struct__: \"foo\"}, Macro.Env) == false\n    assert guarded_is_struct([], Macro.Env) == false\n    assert guarded_is_struct(%{}, Macro.Env) == false\n\n    assert_raise ArgumentError, \"argument error\", fn ->\n      is_struct(%{}, not_atom())\n    end\n  end\n\n  test \"is_struct/2 and other match works\" do\n    assert struct_or_map?(%{}, \"foo\") == false\n    assert struct_or_map?(%{}, Macro.Env) == true\n    assert struct_or_map?(%Macro.Env{}, Macro.Env) == true\n  end\n\n  defp delegate_is_non_struct_map(arg), do: is_non_struct_map(arg)\n\n  defp guarded_is_non_struct_map(arg) when is_non_struct_map(arg), do: true\n  defp guarded_is_non_struct_map(_arg), do: false\n\n  defp non_struct_map_or_struct?(arg) when is_non_struct_map(arg) or is_struct(arg), do: true\n  defp non_struct_map_or_struct?(_arg), do: false\n\n  test \"is_non_struct_map/1\" do\n    assert delegate_is_non_struct_map(%{}) == true\n    assert delegate_is_non_struct_map([]) == false\n    assert delegate_is_non_struct_map(%Macro.Env{}) == false\n    assert delegate_is_non_struct_map(%{__struct__: \"foo\"}) == true\n    assert guarded_is_non_struct_map(%Macro.Env{}) == false\n    assert guarded_is_non_struct_map(%{__struct__: \"foo\"}) == true\n    assert guarded_is_non_struct_map([]) == false\n    assert guarded_is_non_struct_map(%{}) == true\n  end\n\n  test \"is_non_struct_map/1 and other match works\" do\n    assert non_struct_map_or_struct?(%Macro.Env{}) == true\n    assert non_struct_map_or_struct?(%{}) == true\n    assert non_struct_map_or_struct?(10) == false\n  end\n\n  defp delegate_is_exception(arg), do: is_exception(arg)\n\n  defp guarded_is_exception(arg) when is_exception(arg), do: true\n  defp guarded_is_exception(_arg), do: false\n\n  defp exception_or_map?(arg) when is_exception(arg) or is_map(arg), do: true\n  defp exception_or_map?(_arg), do: false\n\n  test \"is_exception/1\" do\n    assert delegate_is_exception(%{}) == false\n    assert delegate_is_exception([]) == false\n    assert delegate_is_exception(%RuntimeError{}) == true\n    assert delegate_is_exception(%{__exception__: \"foo\"}) == false\n    assert guarded_is_exception(%RuntimeError{}) == true\n    assert guarded_is_exception(%{__exception__: \"foo\"}) == false\n    assert guarded_is_exception([]) == false\n    assert guarded_is_exception(%{}) == false\n  end\n\n  test \"is_exception/1 and other match works\" do\n    assert exception_or_map?(%RuntimeError{}) == true\n    assert exception_or_map?(%{}) == true\n    assert exception_or_map?(10) == false\n  end\n\n  defp delegate_is_exception(arg, name), do: is_exception(arg, name)\n\n  defp guarded_is_exception(arg, name) when is_exception(arg, name), do: true\n  defp guarded_is_exception(_arg, _name), do: false\n\n  defp exception_or_map?(arg, name) when is_exception(arg, name) or is_map(arg), do: true\n  defp exception_or_map?(_arg, _name), do: false\n\n  test \"is_exception/2\" do\n    assert delegate_is_exception(%{}, RuntimeError) == false\n    assert delegate_is_exception([], RuntimeError) == false\n    assert delegate_is_exception(%RuntimeError{}, RuntimeError) == true\n    assert delegate_is_exception(%RuntimeError{}, Macro.Env) == false\n    assert guarded_is_exception(%RuntimeError{}, RuntimeError) == true\n    assert guarded_is_exception(%RuntimeError{}, Macro.Env) == false\n    assert guarded_is_exception(%{__exception__: \"foo\"}, \"foo\") == false\n    assert guarded_is_exception(%{__exception__: \"foo\"}, RuntimeError) == false\n    assert guarded_is_exception([], RuntimeError) == false\n    assert guarded_is_exception(%{}, RuntimeError) == false\n\n    assert_raise ArgumentError, \"argument error\", fn ->\n      delegate_is_exception(%{}, not_atom())\n    end\n  end\n\n  test \"is_exception/2 and other match works\" do\n    assert exception_or_map?(%{}, \"foo\") == false\n    assert exception_or_map?(%{}, RuntimeError) == true\n    assert exception_or_map?(%RuntimeError{}, RuntimeError) == true\n  end\n\n  test \"then/2\" do\n    assert 1 |> then(fn x -> x * 2 end) == 2\n  end\n\n  test \"if/2 boolean optimization does not leak variables during expansion\" do\n    if false do\n      :ok\n    else\n      assert Macro.Env.vars(__ENV__) == []\n    end\n  end\n\n  describe \"..\" do\n    test \"returns 0..-1//1\" do\n      assert (..) == 0..-1//1\n    end\n  end\n\n  describe \"in/2\" do\n    # This test may take a long time on machine with low resources\n    @tag timeout: 120_000\n    test \"too large list in guards\" do\n      defmodule TooLargeList do\n        @list Enum.map(1..1024, & &1)\n        defguard is_value(value) when value in @list\n      end\n    end\n\n    test \"with literals on right side\" do\n      assert 2 in [1, 2, 3]\n      assert 2 in 1..3\n      refute 4 in [1, 2, 3]\n      refute 4 in 1..3\n      refute 2 in []\n      refute false in []\n      refute true in []\n    end\n\n    test \"with expressions on right side\" do\n      list = [1, 2, 3]\n      empty_list = []\n      assert 2 in list\n      refute 4 in list\n\n      refute 4 in empty_list\n      refute false in empty_list\n      refute true in empty_list\n\n      assert 2 in [1 | [2, 3]]\n      assert 3 in [1 | list]\n\n      some_call = & &1\n      refute :x in [1, 2 | some_call.([3, 4])]\n      assert :x in [1, 2 | some_call.([3, :x])]\n\n      assert_raise ArgumentError, fn ->\n        :x in [1, 2 | some_call.({3, 4})]\n      end\n    end\n\n    @at_list1 [4, 5]\n    @at_range 6..8\n    @at_list2 [13, 14]\n    def fun_in(x) when x in [0], do: :list\n    def fun_in(x) when x in 1..3, do: :range\n    def fun_in(x) when x in @at_list1, do: :at_list\n    def fun_in(x) when x in @at_range, do: :at_range\n    def fun_in(x) when x in [9 | [10, 11]], do: :list_cons\n    def fun_in(x) when x in [12 | @at_list2], do: :list_cons_at\n    def fun_in(x) when x in 21..15//1, do: raise(\"oops positive\")\n    def fun_in(x) when x in 15..21//-1, do: raise(\"oops negative\")\n    def fun_in(x) when x in 15..21//2, do: :range_step_2\n    def fun_in(x) when x in 15..21//1, do: :range_step_1\n    def fun_in(_), do: :none\n\n    test \"in function guard\" do\n      assert fun_in(0) == :list\n      assert fun_in(1) == :range\n      assert fun_in(2) == :range\n      assert fun_in(3) == :range\n      assert fun_in(5) == :at_list\n      assert fun_in(6) == :at_range\n      assert fun_in(7) == :at_range\n      assert fun_in(8) == :at_range\n      assert fun_in(9) == :list_cons\n      assert fun_in(10) == :list_cons\n      assert fun_in(11) == :list_cons\n      assert fun_in(12) == :list_cons_at\n      assert fun_in(13) == :list_cons_at\n      assert fun_in(14) == :list_cons_at\n      assert fun_in(15) == :range_step_2\n      assert fun_in(16) == :range_step_1\n      assert fun_in(17) == :range_step_2\n      assert fun_in(22) == :none\n\n      assert fun_in(0.0) == :none\n      assert fun_in(1.0) == :none\n      assert fun_in(2.0) == :none\n      assert fun_in(3.0) == :none\n      assert fun_in(6.0) == :none\n      assert fun_in(7.0) == :none\n      assert fun_in(8.0) == :none\n      assert fun_in(9.0) == :none\n      assert fun_in(10.0) == :none\n      assert fun_in(11.0) == :none\n      assert fun_in(12.0) == :none\n      assert fun_in(13.0) == :none\n      assert fun_in(14.0) == :none\n      assert fun_in(15.0) == :none\n      assert fun_in(16.0) == :none\n      assert fun_in(17.0) == :none\n    end\n\n    def dynamic_step_in(x, y, z, w) when x in y..z//w, do: true\n    def dynamic_step_in(_x, _y, _z, _w), do: false\n\n    test \"in dynamic range with step function guard\" do\n      assert dynamic_step_in(1, 1, 3, 1)\n      assert dynamic_step_in(2, 1, 3, 1)\n      assert dynamic_step_in(3, 1, 3, 1)\n\n      refute dynamic_step_in(1, 1, 3, -1)\n      refute dynamic_step_in(2, 1, 3, -1)\n      refute dynamic_step_in(3, 1, 3, -1)\n\n      assert dynamic_step_in(1, 3, 1, -1)\n      assert dynamic_step_in(2, 3, 1, -1)\n      assert dynamic_step_in(3, 3, 1, -1)\n\n      refute dynamic_step_in(1, 3, 1, 1)\n      refute dynamic_step_in(2, 3, 1, 1)\n      refute dynamic_step_in(3, 3, 1, 1)\n\n      assert dynamic_step_in(1, 1, 3, 2)\n      refute dynamic_step_in(2, 1, 3, 2)\n      assert dynamic_step_in(3, 1, 3, 2)\n      assert dynamic_step_in(3, 1, 4, 2)\n      refute dynamic_step_in(4, 1, 4, 2)\n    end\n\n    defmacrop case_in(x, y) do\n      quote do\n        case 0 do\n          _ when unquote(x) in unquote(y) -> true\n          _ -> false\n        end\n      end\n    end\n\n    test \"in case guard\" do\n      assert case_in(1, [1, 2, 3]) == true\n      assert case_in(1, 1..3) == true\n      assert case_in(2, 1..3) == true\n      assert case_in(3, 1..3) == true\n      assert case_in(-3, -1..-3//-1) == true\n    end\n\n    def map_dot(map) when map.field, do: true\n    def map_dot(_other), do: false\n\n    test \"map dot guard\" do\n      refute map_dot(:foo)\n      refute map_dot(%{})\n      refute map_dot(%{field: false})\n      assert map_dot(%{field: true})\n    end\n\n    test \"performs all side-effects\" do\n      assert 1 in [1, send(self(), 2)]\n      assert_received 2\n\n      assert 1 in [1 | send(self(), [2])]\n      assert_received [2]\n\n      assert 2 in [1 | send(self(), [2])]\n      assert_received [2]\n    end\n\n    test \"has proper evaluation order\" do\n      a = 1\n      assert 1 in [a = 2, a]\n      # silence unused var warning\n      _ = a\n    end\n\n    test \"in module body\" do\n      defmodule InSample do\n        @foo [:a, :b]\n        true = :a in @foo\n      end\n    after\n      purge(InSample)\n    end\n\n    test \"inside and/2\" do\n      response = Process.get(:unused, %{code: 200})\n\n      if is_map(response) and response.code in 200..299 do\n        :pass\n      end\n\n      # This module definition copies internal variable\n      # defined during in/2 expansion.\n      Module.create(InVarCopy, nil, __ENV__)\n      purge(InVarCopy)\n    end\n\n    test \"with a non-literal non-escaped compile-time range in guards\" do\n      message = ~r\"found unescaped value on the right side of in/2: 1..3\"\n\n      assert_eval_raise(ArgumentError, message, \"\"\"\n      defmodule InErrors do\n        range = 1..3\n        def foo(x) when x in unquote(range), do: :ok\n      end\n      \"\"\")\n    end\n\n    test \"with a non-compile-time range in guards\" do\n      message = ~r/invalid right argument for operator \"in\", .* got: :hello/\n\n      assert_eval_raise(ArgumentError, message, \"\"\"\n      defmodule InErrors do\n        def foo(x) when x in :hello, do: :ok\n      end\n      \"\"\")\n    end\n\n    test \"with a non-compile-time list cons in guards\" do\n      message = ~r/invalid right argument for operator \"in\", .* got: \\[1 | list\\(\\)\\]/\n\n      assert_eval_raise(ArgumentError, message, \"\"\"\n      defmodule InErrors do\n        def list, do: [1]\n        def foo(x) when x in [1 | list()], do: :ok\n      end\n      \"\"\")\n    end\n\n    test \"with a compile-time non-list in tail in guards\" do\n      message = ~r/invalid right argument for operator \"in\", .* got: \\[1 | 1..3\\]/\n\n      assert_eval_raise(ArgumentError, message, \"\"\"\n      defmodule InErrors do\n        def foo(x) when x in [1 | 1..3], do: :ok\n      end\n      \"\"\")\n    end\n\n    test \"hoists variables and keeps order\" do\n      # Ranges\n      result = expand_to_string(quote(do: rand() in 1..2))\n      assert result =~ \"var = rand()\"\n\n      result = expand_to_string(quote(do: var in 1..2), :guard)\n\n      assert result =~ \"\"\"\n             :erlang.andalso(\n               :erlang.is_integer(var),\n               :erlang.andalso(:erlang.>=(var, 1), :erlang.\\\"=<\\\"(var, 2))\n             )\\\n             \"\"\"\n\n      # Empty list\n      assert expand_to_string(quote(do: :x in [])) =~ \"_ = :x\\nfalse\"\n      assert expand_to_string(quote(do: :x in []), :guard) == \"false\"\n\n      # Lists\n      result = expand_to_string(quote(do: rand() in [1, 2]))\n      assert result =~ \":lists.member(rand(), [1, 2]\"\n    end\n\n    test \"is optimized\" do\n      assert expand_to_string(quote(do: foo in []), :guard) ==\n               \"false\"\n\n      assert expand_to_string(quote(do: foo in [1, 2, 3]), :guard) == \"\"\"\n             :erlang.orelse(\n               :erlang.orelse(:erlang.\\\"=:=\\\"(foo, 1), :erlang.\\\"=:=\\\"(foo, 2)),\n               :erlang.\\\"=:=\\\"(foo, 3)\n             )\\\n             \"\"\"\n\n      assert expand_to_string(quote(do: foo in 0..1), :guard) == \"\"\"\n             :erlang.andalso(\n               :erlang.is_integer(foo),\n               :erlang.andalso(:erlang.>=(foo, 0), :erlang.\\\"=<\\\"(foo, 1))\n             )\\\n             \"\"\"\n\n      assert expand_to_string(quote(do: foo in -1..0), :guard) == \"\"\"\n             :erlang.andalso(\n               :erlang.is_integer(foo),\n               :erlang.andalso(:erlang.>=(foo, -1), :erlang.\\\"=<\\\"(foo, 0))\n             )\\\n             \"\"\"\n\n      assert expand_to_string(quote(do: foo in 1..1), :guard) ==\n               \":erlang.\\\"=:=\\\"(foo, 1)\"\n\n      assert expand_to_string(quote(do: 2 in 1..3), :guard) ==\n               \":erlang.andalso(:erlang.is_integer(2), :erlang.andalso(:erlang.>=(2, 1), :erlang.\\\"=<\\\"(2, 3)))\"\n    end\n\n    defp expand_to_string(ast, environment_or_context \\\\ __ENV__)\n\n    defp expand_to_string(ast, context) when is_atom(context) do\n      expand_to_string(ast, %{__ENV__ | context: context})\n    end\n\n    defp expand_to_string(ast, environment) do\n      ast\n      |> Macro.prewalk(&Macro.expand(&1, environment))\n      |> Macro.to_string()\n    end\n  end\n\n  describe \"__info__\" do\n    test \":macros\" do\n      assert {:in, 2} in Kernel.__info__(:macros)\n    end\n\n    test \":functions\" do\n      refute {:__info__, 1} in Kernel.__info__(:functions)\n    end\n\n    test \":struct\" do\n      assert Kernel.__info__(:struct) == nil\n      assert [%{field: :scheme, default: nil} | _] = URI.__info__(:struct)\n    end\n\n    test \"others\" do\n      assert Kernel.__info__(:module) == Kernel\n      assert is_list(Kernel.__info__(:compile))\n      assert is_list(Kernel.__info__(:attributes))\n    end\n  end\n\n  describe \"@\" do\n    test \"setting attribute with do-block\" do\n      exception =\n        catch_error(\n          defmodule UpcaseAttrSample do\n            @foo quote do\n              :ok\n            end\n          end\n        )\n\n      assert exception.message =~ \"expected 0 or 1 argument for @foo, got 2\"\n      assert exception.message =~ \"You probably want to wrap the argument value in parentheses\"\n    end\n\n    test \"setting attribute with uppercase\" do\n      message = \"module attributes set via @ cannot start with an uppercase letter\"\n\n      assert_raise ArgumentError, message, fn ->\n        defmodule UpcaseAttrSample do\n          @Upper\n        end\n      end\n    end\n\n    test \"matching attribute\" do\n      assert_raise ArgumentError, ~r\"invalid usage of module attributes\", fn ->\n        defmodule MatchAttributeInModule do\n          @foo = 42\n        end\n      end\n\n      assert_raise ArgumentError, ~r\"invalid usage of module attributes\", fn ->\n        defmodule MatchAttributeInModule do\n          @foo 16\n          <<_::@foo>> = \"ab\"\n        end\n      end\n\n      assert_raise ArgumentError, ~r\"invalid usage of module attributes\", fn ->\n        defmodule MatchAttributeInModule do\n          @foo 16\n          <<_::size(@foo)>> = \"ab\"\n        end\n      end\n    end\n  end\n\n  describe \"defdelegate\" do\n    defdelegate my_flatten(list), to: List, as: :flatten\n\n    dynamic = :dynamic_flatten\n    defdelegate unquote(dynamic)(list), to: List, as: :flatten\n\n    test \"dispatches to delegated functions\" do\n      assert my_flatten([[1]]) == [1]\n    end\n\n    test \"with unquote\" do\n      assert dynamic_flatten([[1]]) == [1]\n    end\n\n    test \"raises with non-variable arguments\" do\n      assert_raise ArgumentError,\n                   \"guards are not allowed in defdelegate/2, got: when is_list(term) or is_binary(term)\",\n                   fn ->\n                     string = \"\"\"\n                     defmodule IntDelegateWithGuards do\n                       defdelegate foo(term) when is_list(term) or is_binary(term), to: List\n                     end\n                     \"\"\"\n\n                     Code.eval_string(string, [], __ENV__)\n                   end\n\n      msg = \"defdelegate/2 only accepts function parameters, got: 1\"\n\n      assert_raise ArgumentError, msg, fn ->\n        string = \"\"\"\n        defmodule IntDelegate do\n          defdelegate foo(1), to: List\n        end\n        \"\"\"\n\n        Code.eval_string(string, [], __ENV__)\n      end\n\n      assert_raise ArgumentError, msg, fn ->\n        string = \"\"\"\n        defmodule IntOptionDelegate do\n          defdelegate foo(1 \\\\\\\\ 1), to: List\n        end\n        \"\"\"\n\n        Code.eval_string(string, [], __ENV__)\n      end\n    end\n\n    test \"raises when :to targeting the delegating module is given without the :as option\" do\n      assert_raise ArgumentError,\n                   ~r/defdelegate function is calling itself, which will lead to an infinite loop. You should either change the value of the :to option or specify the :as option/,\n                   fn ->\n                     defmodule ImplAttributes do\n                       defdelegate foo(), to: __MODULE__\n                     end\n                   end\n    end\n\n    defdelegate my_reverse(list \\\\ []), to: :lists, as: :reverse\n    defdelegate my_get(map \\\\ %{}, key, default \\\\ \"\"), to: Map, as: :get\n\n    test \"accepts variable with optional arguments\" do\n      assert my_reverse() == []\n      assert my_reverse([1, 2, 3]) == [3, 2, 1]\n\n      assert my_get(\"foo\") == \"\"\n      assert my_get(%{}, \"foo\") == \"\"\n      assert my_get(%{\"foo\" => \"bar\"}, \"foo\") == \"bar\"\n      assert my_get(%{}, \"foo\", \"not_found\") == \"not_found\"\n    end\n  end\n\n  describe \"defmodule\" do\n    test \"expects atoms as module names\" do\n      msg = ~r\"invalid module name: 3\"\n\n      assert_raise ArgumentError, msg, fn ->\n        defmodule 1 + 2, do: :ok\n      end\n    end\n\n    test \"does not accept special atoms as module names\" do\n      special_atoms = [nil, true, false]\n\n      Enum.each(special_atoms, fn special_atom ->\n        msg = ~r\"invalid module name: #{inspect(special_atom)}\"\n\n        assert_raise ArgumentError, msg, fn ->\n          defmodule special_atom, do: :ok\n        end\n      end)\n    end\n\n    test \"does not accept slashes in module names\" do\n      assert_raise ArgumentError, ~r(invalid module name: :\"foo/bar\"), fn ->\n        defmodule :\"foo/bar\", do: :ok\n      end\n\n      assert_raise ArgumentError, ~r(invalid module name: :\"foo\\\\\\\\bar\"), fn ->\n        defmodule :\"foo\\\\bar\", do: :ok\n      end\n    end\n  end\n\n  describe \"access\" do\n    defmodule StructAccess do\n      defstruct [:foo, :bar]\n    end\n\n    test \"get_in/1\" do\n      users = %{\"john\" => %{age: 27}, :meg => %{age: 23}}\n      assert get_in(users[\"john\"][:age]) == 27\n      assert get_in(users[\"dave\"][:age]) == nil\n      assert get_in(users[\"john\"].age) == 27\n      assert get_in(users[\"dave\"].age) == nil\n      assert get_in(users.meg[:age]) == 23\n      assert get_in(users.meg.age) == 23\n\n      is_nil = nil\n      assert get_in(is_nil.age) == nil\n\n      assert_raise KeyError, ~r\"key :unknown not found\", fn -> get_in(users.unknown) end\n      assert_raise KeyError, ~r\"key :unknown not found\", fn -> get_in(users.meg.unknown) end\n    end\n\n    test \"get_in/2\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n      assert get_in(users, [\"john\", :age]) == 27\n      assert get_in(users, [\"dave\", :age]) == nil\n      assert get_in(nil, [\"john\", :age]) == nil\n\n      map = %{\"fruits\" => [\"banana\", \"apple\", \"orange\"]}\n      assert get_in(map, [\"fruits\", by_index(0)]) == \"banana\"\n      assert get_in(map, [\"fruits\", by_index(3)]) == nil\n      assert get_in(map, [\"unknown\", by_index(3)]) == nil\n    end\n\n    test \"put_in/3\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n\n      assert put_in(users, [\"john\", :age], 28) == %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n      assert_raise ArgumentError, \"could not put/update key \\\"john\\\" on a nil value\", fn ->\n        put_in(nil, [\"john\", :age], 28)\n      end\n    end\n\n    test \"put_in/2\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n\n      assert put_in(users[\"john\"][:age], 28) == %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n      assert put_in(users[\"john\"].age, 28) == %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n      struct = %StructAccess{foo: %StructAccess{}}\n\n      assert put_in(struct.foo.bar, :baz) ==\n               %StructAccess{bar: nil, foo: %StructAccess{bar: :baz, foo: nil}}\n\n      assert_raise BadMapError, fn ->\n        put_in(users[\"dave\"].age, 19)\n      end\n\n      assert_raise KeyError, fn ->\n        put_in(users[\"meg\"].unknown, \"value\")\n      end\n    end\n\n    test \"update_in/3\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n\n      assert update_in(users, [\"john\", :age], &(&1 + 1)) ==\n               %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n      assert_raise ArgumentError, \"could not put/update key \\\"john\\\" on a nil value\", fn ->\n        update_in(nil, [\"john\", :age], fn _ -> %{} end)\n      end\n\n      assert_raise UndefinedFunctionError, fn ->\n        pop_in(struct(Sample, []), [:name])\n      end\n    end\n\n    test \"update_in/2\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n\n      assert update_in(users[\"john\"][:age], &(&1 + 1)) ==\n               %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n      assert update_in(users[\"john\"].age, &(&1 + 1)) ==\n               %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}\n\n      struct = %StructAccess{foo: %StructAccess{bar: 41}}\n\n      assert update_in(struct.foo.bar, &(&1 + 1)) ==\n               %StructAccess{bar: nil, foo: %StructAccess{bar: 42, foo: nil}}\n\n      assert_raise BadMapError, fn ->\n        update_in(users[\"dave\"].age, &(&1 + 1))\n      end\n\n      assert_raise KeyError, fn ->\n        put_in(users[\"meg\"].unknown, &(&1 + 1))\n      end\n    end\n\n    test \"get_and_update_in/3\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n\n      assert get_and_update_in(users, [\"john\", :age], &{&1, &1 + 1}) ==\n               {27, %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}}\n\n      map = %{\"fruits\" => [\"banana\", \"apple\", \"orange\"]}\n\n      assert get_and_update_in(map, [\"fruits\", by_index(0)], &{&1, String.reverse(&1)}) ==\n               {\"banana\", %{\"fruits\" => [\"ananab\", \"apple\", \"orange\"]}}\n\n      assert get_and_update_in(map, [\"fruits\", by_index(3)], &{&1, &1}) ==\n               {nil, %{\"fruits\" => [\"banana\", \"apple\", \"orange\"]}}\n\n      assert get_and_update_in(map, [\"unknown\", by_index(3)], &{&1, []}) ==\n               {:oops, %{\"fruits\" => [\"banana\", \"apple\", \"orange\"], \"unknown\" => []}}\n    end\n\n    test \"get_and_update_in/2\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n\n      assert get_and_update_in(users[\"john\"].age, &{&1, &1 + 1}) ==\n               {27, %{\"john\" => %{age: 28}, \"meg\" => %{age: 23}}}\n\n      struct = %StructAccess{foo: %StructAccess{bar: 41}}\n\n      assert get_and_update_in(struct.foo.bar, &{&1, &1 + 1}) ==\n               {41, %StructAccess{bar: nil, foo: %StructAccess{bar: 42, foo: nil}}}\n\n      assert_raise ArgumentError, \"could not put/update key \\\"john\\\" on a nil value\", fn ->\n        get_and_update_in(nil[\"john\"][:age], fn nil -> {:ok, 28} end)\n      end\n\n      assert_raise BadMapError, fn ->\n        get_and_update_in(users[\"dave\"].age, &{&1, &1 + 1})\n      end\n\n      assert_raise KeyError, fn ->\n        get_and_update_in(users[\"meg\"].unknown, &{&1, &1 + 1})\n      end\n    end\n\n    test \"pop_in/2\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n\n      assert pop_in(users, [\"john\", :age]) ==\n               {27, %{\"john\" => %{}, \"meg\" => %{age: 23}}}\n\n      assert pop_in(users, [\"bob\", :age]) ==\n               {nil, %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}}\n\n      assert pop_in([], [:foo, :bar]) ==\n               {nil, []}\n    end\n\n    test \"pop_in/2 with paths\" do\n      map = %{\"fruits\" => [\"banana\", \"apple\", \"orange\"]}\n\n      assert pop_in(map, [\"fruits\", by_index(0)]) ==\n               {\"banana\", %{\"fruits\" => [\"apple\", \"orange\"]}}\n\n      assert pop_in(map, [\"fruits\", by_index(3)]) == {nil, map}\n\n      map = %{\"fruits\" => [%{name: \"banana\"}, %{name: \"apple\"}]}\n\n      assert pop_in(map, [\"fruits\", by_index(0), :name]) ==\n               {\"banana\", %{\"fruits\" => [%{}, %{name: \"apple\"}]}}\n\n      assert pop_in(map, [\"fruits\", by_index(3), :name]) == {nil, map}\n    end\n\n    test \"pop_in/1\" do\n      users = %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}\n\n      assert pop_in(users[\"john\"]) == {%{age: 27}, %{\"meg\" => %{age: 23}}}\n\n      assert pop_in(users[\"john\"][:age]) == {27, %{\"john\" => %{}, \"meg\" => %{age: 23}}}\n      assert pop_in(users[\"john\"][:name]) == {nil, %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}}\n      assert pop_in(users[\"bob\"][:age]) == {nil, %{\"john\" => %{age: 27}, \"meg\" => %{age: 23}}}\n\n      users = %{john: [age: 27], meg: [age: 23]}\n\n      assert pop_in(users.john[:age]) == {27, %{john: [], meg: [age: 23]}}\n      assert pop_in(users.john[:name]) == {nil, %{john: [age: 27], meg: [age: 23]}}\n\n      assert pop_in([][:foo][:bar]) == {nil, []}\n      assert_raise KeyError, fn -> pop_in(users.bob[:age]) end\n    end\n\n    test \"pop_in/1,2 with nils\" do\n      users = %{\"john\" => nil, \"meg\" => %{age: 23}}\n      assert pop_in(users[\"john\"][:age]) == {nil, %{\"meg\" => %{age: 23}}}\n      assert pop_in(users, [\"john\", :age]) == {nil, %{\"meg\" => %{age: 23}}}\n\n      users = %{john: nil, meg: %{age: 23}}\n      assert pop_in(users.john[:age]) == {nil, %{john: nil, meg: %{age: 23}}}\n      assert pop_in(users, [:john, :age]) == {nil, %{meg: %{age: 23}}}\n\n      x = nil\n      assert_raise ArgumentError, fn -> pop_in(x[\"john\"][:age]) end\n      assert_raise ArgumentError, fn -> pop_in(nil[\"john\"][:age]) end\n      assert_raise ArgumentError, fn -> pop_in(nil, [\"john\", :age]) end\n    end\n\n    test \"with dynamic paths\" do\n      map = empty_map()\n\n      assert put_in(map[:foo], \"bar\") == %{foo: \"bar\"}\n      assert put_in(empty_map()[:foo], \"bar\") == %{foo: \"bar\"}\n      assert put_in(KernelTest.empty_map()[:foo], \"bar\") == %{foo: \"bar\"}\n      assert put_in(__MODULE__.empty_map()[:foo], \"bar\") == %{foo: \"bar\"}\n\n      assert_raise ArgumentError, ~r\"access at least one element,\", fn ->\n        Code.eval_quoted(quote(do: put_in(map, \"bar\")), [])\n      end\n\n      assert_raise ArgumentError, ~r\"must start with a variable, local or remote call\", fn ->\n        Code.eval_quoted(quote(do: put_in(map.foo(1, 2)[:bar], \"baz\")), [])\n      end\n    end\n\n    def by_index(index) do\n      fn\n        :get, nil, _next ->\n          raise \"won't be invoked\"\n\n        :get, data, next ->\n          next.(Enum.at(data, index))\n\n        :get_and_update, nil, next ->\n          next.(:oops)\n\n        :get_and_update, data, next ->\n          current = Enum.at(data, index)\n\n          case next.(current) do\n            {get, update} -> {get, List.replace_at(data, index, update)}\n            :pop -> {current, List.delete_at(data, index)}\n          end\n      end\n    end\n  end\n\n  describe \"pipeline\" do\n    test \"simple\" do\n      assert [1, [2], 3] |> List.flatten() == [1, 2, 3]\n    end\n\n    test \"nested\" do\n      assert [1, [2], 3] |> List.flatten() |> Enum.map(&(&1 * 2)) == [2, 4, 6]\n    end\n\n    test \"local call\" do\n      assert [1, [2], 3] |> List.flatten() |> local() == [2, 4, 6]\n    end\n\n    test \"with capture\" do\n      assert Enum.map([1, 2, 3], &(&1 |> twice() |> twice())) == [4, 8, 12]\n    end\n\n    test \"with anonymous functions\" do\n      assert 1 |> (&(&1 * 2)).() == 2\n      assert [1] |> (&hd(&1)).() == 1\n    end\n\n    test \"reverse associativity\" do\n      assert [1, [2], 3] |> (List.flatten() |> Enum.map(&(&1 * 2))) == [2, 4, 6]\n    end\n\n    defp twice(a), do: a * 2\n\n    defp local(list) do\n      Enum.map(list, &(&1 * 2))\n    end\n  end\n\n  describe \"destructure\" do\n    test \"less args\" do\n      destructure [x, y, z], [1, 2, 3, 4, 5]\n      assert x == 1\n      assert y == 2\n      assert z == 3\n    end\n\n    test \"more args\" do\n      destructure [a, b, c, d, e], [1, 2, 3]\n      assert a == 1\n      assert b == 2\n      assert c == 3\n      assert d == nil\n      assert e == nil\n    end\n\n    test \"equal args\" do\n      destructure [a, b, c], [1, 2, 3]\n      assert a == 1\n      assert b == 2\n      assert c == 3\n    end\n\n    test \"no values\" do\n      destructure [a, b, c], []\n      assert a == nil\n      assert b == nil\n      assert c == nil\n    end\n\n    test \"works as match\" do\n      destructure [1, b, _], [1, 2, 3]\n      assert b == 2\n    end\n\n    test \"nil values\" do\n      destructure [a, b, c], a_nil()\n      assert a == nil\n      assert b == nil\n      assert c == nil\n    end\n\n    test \"invalid match\" do\n      a = List.first([3])\n\n      assert_raise MatchError, fn ->\n        destructure [^a, _b, _c], a_list()\n      end\n    end\n\n    defp a_list, do: [1, 2, 3]\n    defp a_nil, do: nil\n  end\n\n  describe \"use/2\" do\n    import ExUnit.CaptureIO\n\n    defmodule SampleA do\n      defmacro __using__(opts) do\n        prefix = Keyword.get(opts, :prefix, \"\")\n        IO.puts(prefix <> \"A\")\n      end\n    end\n\n    defmodule SampleB do\n      defmacro __using__(_) do\n        IO.puts(\"B\")\n      end\n    end\n\n    test \"invalid argument is literal\" do\n      message = \"invalid arguments for use, expected a compile time atom or alias, got: 42\"\n\n      assert_raise ArgumentError, message, fn ->\n        Code.eval_string(\"use 42\")\n      end\n    end\n\n    test \"invalid argument is variable\" do\n      message = \"invalid arguments for use, expected a compile time atom or alias, got: variable\"\n\n      assert_raise ArgumentError, message, fn ->\n        Code.eval_string(\"use variable\")\n      end\n    end\n\n    test \"multi-call\" do\n      assert capture_io(fn ->\n               Code.eval_string(\"use KernelTest.{SampleA, SampleB,}\", [], __ENV__)\n             end) == \"A\\nB\\n\"\n    end\n\n    test \"multi-call with options\" do\n      assert capture_io(fn ->\n               Code.eval_string(~S|use KernelTest.{SampleA}, prefix: \"-\"|, [], __ENV__)\n             end) == \"-A\\n\"\n    end\n\n    test \"multi-call with unquote\" do\n      assert capture_io(fn ->\n               string = \"\"\"\n               defmodule TestMod do\n                 def main() do\n                   use KernelTest.{SampleB, unquote(:SampleA)}\n                 end\n               end\n               \"\"\"\n\n               Code.eval_string(string, [], __ENV__)\n             end) == \"B\\nA\\n\"\n    after\n      purge(KernelTest.TestMod)\n    end\n  end\n\n  test \"is_map_key/2\" do\n    assert is_map_key(Map.new([]), :a) == false\n    assert is_map_key(Map.new(b: 1), :a) == false\n    assert is_map_key(Map.new(a: 1), :a) == true\n\n    assert_raise BadMapError, fn ->\n      is_map_key(Process.get(:unused, []), :a)\n    end\n\n    case Map.new(a: 1) do\n      map when is_map_key(map, :a) -> true\n      _ -> flunk(\"invalid guard\")\n    end\n  end\n\n  test \"tap/1\" do\n    import ExUnit.CaptureIO\n\n    assert capture_io(fn ->\n             tap(\"foo\", &IO.puts/1)\n           end) == \"foo\\n\"\n\n    assert 1 = tap(1, fn x -> x + 1 end)\n  end\n\n  test \"tl/1\" do\n    assert tl([:one]) == []\n    assert tl([1, 2, 3]) == [2, 3]\n    assert_raise ArgumentError, fn -> tl(Process.get(:unused, [])) end\n\n    assert tl([:a | :b]) == :b\n    assert tl([:a, :b | :c]) == [:b | :c]\n  end\n\n  test \"hd/1\" do\n    assert hd([1, 2, 3, 4]) == 1\n    assert_raise ArgumentError, fn -> hd(Process.get(:unused, [])) end\n    assert hd([1 | 2]) == 1\n  end\n\n  test \"floor/1\" do\n    assert floor(1) === 1\n    assert floor(1.0) === 1\n    assert floor(0) === 0\n    assert floor(0.0) === 0\n    assert floor(-0.0) === 0\n    assert floor(1.123) === 1\n    assert floor(-10.123) === -11\n    assert floor(-10) === -10\n    assert floor(-10.0) === -10\n\n    assert match?(x when floor(x) == 0, 0.2)\n  end\n\n  test \"ceil/1\" do\n    assert ceil(1) === 1\n    assert ceil(1.0) === 1\n    assert ceil(0) === 0\n    assert ceil(0.0) === 0\n    assert ceil(-0.0) === 0\n    assert ceil(1.123) === 2\n    assert ceil(-10.123) === -10\n    assert ceil(-10) === -10\n    assert ceil(-10.0) === -10\n\n    assert match?(x when ceil(x) == 1, 0.2)\n  end\n\n  test \"binary_slice/2\" do\n    assert binary_slice(\"abc\", -1..0) == \"\"\n    assert binary_slice(\"abc\", -5..-5) == \"\"\n    assert binary_slice(\"x\", 0..0//2) == \"x\"\n    assert binary_slice(\"abcde\", 1..3//2) == \"bd\"\n  end\n\n  test \"sigil_U/2\" do\n    assert ~U[2015-01-13 13:00:07.123Z] == %DateTime{\n             calendar: Calendar.ISO,\n             day: 13,\n             hour: 13,\n             microsecond: {123_000, 3},\n             minute: 0,\n             month: 1,\n             second: 7,\n             std_offset: 0,\n             time_zone: \"Etc/UTC\",\n             utc_offset: 0,\n             year: 2015,\n             zone_abbr: \"UTC\"\n           }\n\n    assert_raise ArgumentError, ~r\"reason: :invalid_format\", fn ->\n      Code.eval_string(~s{~U[2015-01-13 13:00]})\n    end\n\n    assert_raise ArgumentError, ~r\"reason: :invalid_format\", fn ->\n      Code.eval_string(~s{~U[20150113 130007Z]})\n    end\n\n    assert_raise ArgumentError, ~r\"reason: :missing_offset\", fn ->\n      Code.eval_string(~s{~U[2015-01-13 13:00:07]})\n    end\n\n    assert_raise ArgumentError, ~r\"reason: :non_utc_offset\", fn ->\n      Code.eval_string(~s{~U[2015-01-13 13:00:07+00:30]})\n    end\n  end\n\n  describe \"dbg/2\" do\n    import ExUnit.CaptureIO\n\n    test \"prints the given expression and returns its value\" do\n      output = capture_io(fn -> assert dbg(List.duplicate(:foo, 3)) == [:foo, :foo, :foo] end)\n      assert output =~ \"kernel_test.exs\"\n      assert output =~ \"KernelTest\"\n      assert output =~ \"List\"\n      assert output =~ \"duplicate\"\n      assert output =~ \":foo\"\n      assert output =~ \"3\"\n    end\n\n    test \"prints the given expression with complex options\" do\n      output = capture_io(fn -> assert dbg(123, [] ++ []) == 123 end)\n      assert output =~ \"kernel_test.exs\"\n    end\n\n    test \"doesn't print any colors if :syntax_colors is []\" do\n      output =\n        capture_io(fn ->\n          assert dbg(List.duplicate(:foo, 3), syntax_colors: []) == [:foo, :foo, :foo]\n        end)\n\n      assert output =~ \"kernel_test.exs\"\n      assert output =~ \"KernelTest.\"\n      assert output =~ \"List.duplicate(:foo, 3)\"\n      assert output =~ \"[:foo, :foo, :foo]\"\n      refute output =~ \"\\\\e[\"\n    end\n\n    test \"prints binding() if no arguments are given\" do\n      my_var = 1\n      my_other_var = :foo\n\n      output = capture_io(fn -> dbg() end)\n\n      assert output =~ \"binding()\"\n      assert output =~ \"my_var:\"\n      assert output =~ \"my_other_var:\"\n    end\n\n    test \"is not allowed in guards\" do\n      message = \"invalid expression in guard, dbg is not allowed in guards\"\n\n      assert_raise ArgumentError, Regex.compile!(message), fn ->\n        defmodule DbgGuard do\n          def dbg_guard() when dbg(1), do: true\n        end\n      end\n    end\n\n    test \"is not allowed in pattern matches\" do\n      message = \"invalid expression in match, dbg is not allowed in patterns\"\n\n      assert_eval_raise(ArgumentError, Regex.compile!(message), \"\"\"\n      {:ok, dbg()} = make_ref()\n      \"\"\")\n    end\n  end\n\n  describe \"to_timeout/1\" do\n    test \"works with keyword lists\" do\n      assert to_timeout(hour: 2) == 1000 * 60 * 60 * 2\n      assert to_timeout(minute: 74) == 1000 * 60 * 74\n      assert to_timeout(second: 1293) == 1_293_000\n      assert to_timeout(millisecond: 1_234_123) == 1_234_123\n\n      assert to_timeout(hour: 2, minute: 30) == 1000 * 60 * 60 * 2 + 1000 * 60 * 30\n      assert to_timeout(minute: 30, hour: 2) == 1000 * 60 * 60 * 2 + 1000 * 60 * 30\n      assert to_timeout(minute: 74, second: 30) == 1000 * 60 * 74 + 1000 * 30\n    end\n\n    test \"raises on invalid values with keyword lists\" do\n      for unit <- [:hour, :minute, :second, :millisecond],\n          value <- [-1, 1.0, :not_an_int] do\n        message =\n          \"timeout component #{inspect(unit)} must be a non-negative integer, \" <>\n            \"got: #{inspect(value)}\"\n\n        assert_raise ArgumentError, message, fn -> to_timeout([{unit, value}]) end\n      end\n    end\n\n    test \"raises on invalid keys with keyword lists\" do\n      message =\n        \"timeout component :not_a_unit is not a valid timeout component, valid values are: \" <>\n          \":week, :day, :hour, :minute, :second, :millisecond\"\n\n      assert_raise ArgumentError, message, fn -> to_timeout(minute: 3, not_a_unit: 1) end\n    end\n\n    test \"raises on duplicated components with keyword lists\" do\n      assert_raise ArgumentError, \"timeout component :minute is duplicated\", fn ->\n        to_timeout(minute: 3, hour: 2, minute: 1)\n      end\n    end\n\n    test \"works with durations\" do\n      assert to_timeout(Duration.new!(hour: 2)) == 1000 * 60 * 60 * 2\n      assert to_timeout(Duration.new!(minute: 74)) == 1000 * 60 * 74\n      assert to_timeout(Duration.new!(second: 1293)) == 1_293_000\n      assert to_timeout(Duration.new!(microsecond: {1_234_123, 4})) == 1_234\n\n      assert to_timeout(Duration.new!(hour: 2, minute: 30)) == 1000 * 60 * 60 * 2 + 1000 * 60 * 30\n      assert to_timeout(Duration.new!(minute: 30, hour: 2)) == 1000 * 60 * 60 * 2 + 1000 * 60 * 30\n      assert to_timeout(Duration.new!(minute: 74, second: 30)) == 1000 * 60 * 74 + 1000 * 30\n    end\n\n    test \"raises on durations with non-zero months or days\" do\n      message = \"duration with a non-zero month cannot be reliably converted to timeouts\"\n\n      assert_raise ArgumentError, message, fn ->\n        to_timeout(Duration.new!(month: 3))\n      end\n\n      message = \"duration with a non-zero year cannot be reliably converted to timeouts\"\n\n      assert_raise ArgumentError, message, fn ->\n        to_timeout(Duration.new!(year: 1))\n      end\n    end\n\n    test \"works with timeouts\" do\n      assert to_timeout(1_000) == 1_000\n      assert to_timeout(0) == 0\n      assert to_timeout(:infinity) == :infinity\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/keyword_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule KeywordTest do\n  use ExUnit.Case, async: true\n\n  doctest Keyword\n\n  test \"has a literal syntax\" do\n    assert [B: 1] == [{:B, 1}]\n    assert [foo?: :bar] == [{:foo?, :bar}]\n    assert [||: 2, +: 1] == [{:||, 2}, {:+, 1}]\n    assert [1, 2, three: :four] == [1, 2, {:three, :four}]\n  end\n\n  test \"is a :: operator on ambiguity\" do\n    assert [{:\"::\", _, [{:a, _, _}, {:b, _, _}]}] = quote(do: [a :: b])\n  end\n\n  test \"supports optional comma\" do\n    assert Code.eval_string(\"[a: 1, b: 2, c: 3,]\") == {[a: 1, b: 2, c: 3], []}\n  end\n\n  test \"implements (almost) all functions in Map\" do\n    assert Map.__info__(:functions) -- Keyword.__info__(:functions) == [from_struct: 1]\n  end\n\n  test \"get_and_update/3 removes duplicates from the input keyword list\" do\n    assert Keyword.get_and_update([a: 1, b: 2, a: 3], :a, fn value -> {value, value + 10} end) ==\n             {1, [a: 11, b: 2]}\n  end\n\n  test \"get_and_update/3 raises on bad return value from the argument function\" do\n    message = \"the given function must return a two-element tuple or :pop, got: 1\"\n\n    assert_raise RuntimeError, message, fn ->\n      Keyword.get_and_update([a: 1], :a, fn value -> value end)\n    end\n\n    message = \"the given function must return a two-element tuple or :pop, got: nil\"\n\n    assert_raise RuntimeError, message, fn ->\n      Keyword.get_and_update([], :a, fn value -> value end)\n    end\n  end\n\n  test \"get_and_update!/3 removes duplicates from the input keyword list\" do\n    assert Keyword.get_and_update!([a: 1, b: 2, a: 3], :a, fn value -> {value, value + 10} end) ==\n             {1, [a: 11, b: 2]}\n  end\n\n  test \"get_and_update!/3 raises on bad return value from the argument function\" do\n    message = \"the given function must return a two-element tuple or :pop, got: 1\"\n\n    assert_raise RuntimeError, message, fn ->\n      Keyword.get_and_update!([a: 1], :a, fn value -> value end)\n    end\n  end\n\n  test \"update!\" do\n    assert Keyword.update!([a: 1, b: 2, a: 3], :a, &(&1 * 2)) == [a: 2, b: 2]\n    assert Keyword.update!([a: 1, b: 2, c: 3], :b, &(&1 * 2)) == [a: 1, b: 4, c: 3]\n  end\n\n  test \"replace\" do\n    assert Keyword.replace([a: 1, b: 2, a: 3], :a, :new) == [a: :new, b: 2]\n    assert Keyword.replace([a: 1, b: 2, a: 3], :a, 1) == [a: 1, b: 2]\n    assert Keyword.replace([a: 1, b: 2, a: 3, b: 4], :a, 1) == [a: 1, b: 2, b: 4]\n    assert Keyword.replace([a: 1, b: 2, c: 3, b: 4], :b, :new) == [a: 1, b: :new, c: 3]\n    assert Keyword.replace([], :b, :new) == []\n    assert Keyword.replace([a: 1, b: 2, a: 3], :c, :new) == [a: 1, b: 2, a: 3]\n  end\n\n  test \"replace!\" do\n    assert Keyword.replace!([a: 1, b: 2, a: 3], :a, :new) == [a: :new, b: 2]\n    assert Keyword.replace!([a: 1, b: 2, a: 3], :a, 1) == [a: 1, b: 2]\n    assert Keyword.replace!([a: 1, b: 2, a: 3, b: 4], :a, 1) == [a: 1, b: 2, b: 4]\n    assert Keyword.replace!([a: 1, b: 2, c: 3, b: 4], :b, :new) == [a: 1, b: :new, c: 3]\n\n    assert_raise KeyError, \"key :b not found in:\\n\\n    []\\n\", fn ->\n      Keyword.replace!([], :b, :new)\n    end\n\n    assert_raise KeyError, \"key :c not found in:\\n\\n    [a: 1, b: 2, a: 3]\\n\", fn ->\n      Keyword.replace!([a: 1, b: 2, a: 3], :c, :new)\n    end\n  end\n\n  test \"merge/2\" do\n    assert Keyword.merge([a: 1, b: 2], c: 11, d: 12) == [a: 1, b: 2, c: 11, d: 12]\n    assert Keyword.merge([], c: 11, d: 12) == [c: 11, d: 12]\n    assert Keyword.merge([a: 1, b: 2], []) == [a: 1, b: 2]\n\n    message = \"expected a keyword list as the first argument, got: [1, 2]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([1, 2], c: 11, d: 12)\n    end\n\n    message = \"expected a keyword list as the first argument, got: [1 | 2]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([1 | 2], c: 11, d: 12)\n    end\n\n    message = \"expected a keyword list as the second argument, got: [11, 12, 0]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([a: 1, b: 2], [11, 12, 0])\n    end\n\n    message = \"expected a keyword list as the second argument, got: [11 | 12]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([a: 1, b: 2], [11 | 12])\n    end\n\n    # duplicate keys in keywords1 are kept if key is not present in keywords2\n    result = [a: 1, b: 2, a: 3, c: 11, d: 12]\n    assert Keyword.merge([a: 1, b: 2, a: 3], c: 11, d: 12) == result\n\n    result = [b: 2, a: 11]\n    assert Keyword.merge([a: 1, b: 2, a: 3], a: 11) == result\n\n    # duplicate keys in keywords2 are always kept\n    result = [a: 1, b: 2, c: 11, c: 12, d: 13]\n    assert Keyword.merge([a: 1, b: 2], c: 11, c: 12, d: 13) == result\n\n    # any key in keywords1 is removed if key is present in keyword2\n    result = [a: 1, b: 2, c: 11, c: 12, d: 13]\n    assert Keyword.merge([a: 1, b: 2, c: 3, c: 4], c: 11, c: 12, d: 13) == result\n  end\n\n  test \"merge/3\" do\n    fun = fn _key, value1, value2 -> value1 + value2 end\n\n    assert Keyword.merge([a: 1, b: 2], [c: 11, d: 12], fun) == [a: 1, b: 2, c: 11, d: 12]\n    assert Keyword.merge([], [c: 11, d: 12], fun) == [c: 11, d: 12]\n    assert Keyword.merge([a: 1, b: 2], [], fun) == [a: 1, b: 2]\n\n    message = \"expected a keyword list as the first argument, got: [1, 2]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([1, 2], [c: 11, d: 12], fun)\n    end\n\n    message = \"expected a keyword list as the first argument, got: [1 | 2]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([1 | 2], [c: 11, d: 12], fun)\n    end\n\n    message = \"expected a keyword list as the second argument, got: [{:x, 1}, :y, :z]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([a: 1, b: 2], [{:x, 1}, :y, :z], fun)\n    end\n\n    message = \"expected a keyword list as the second argument, got: [:x | :y]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([a: 1, b: 2], [:x | :y], fun)\n    end\n\n    message = \"expected a keyword list as the second argument, got: [{:x, 1} | :y]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Keyword.merge([a: 1, b: 2], [{:x, 1} | :y], fun)\n    end\n\n    # duplicate keys in keywords1 are left untouched if key is not present in keywords2\n    result = [a: 1, b: 2, a: 3, c: 11, d: 12]\n    assert Keyword.merge([a: 1, b: 2, a: 3], [c: 11, d: 12], fun) == result\n\n    result = [b: 2, a: 12]\n    assert Keyword.merge([a: 1, b: 2, a: 3], [a: 11], fun) == result\n\n    # duplicate keys in keywords2 are always kept\n    result = [a: 1, b: 2, c: 11, c: 12, d: 13]\n    assert Keyword.merge([a: 1, b: 2], [c: 11, c: 12, d: 13], fun) == result\n\n    # every key in keywords1 is replaced with fun result if key is present in keyword2\n    result = [a: 1, b: 2, c: 14, c: 54, d: 13]\n    assert Keyword.merge([a: 1, b: 2, c: 3, c: 4], [c: 11, c: 50, d: 13], fun) == result\n  end\n\n  test \"merge/2 and merge/3 behave exactly the same way\" do\n    fun = fn _key, _value1, value2 -> value2 end\n\n    args = [\n      {[a: 1, b: 2], [c: 11, d: 12]},\n      {[], [c: 11, d: 12]},\n      {[a: 1, b: 2], []},\n      {[a: 1, b: 2, a: 3], [c: 11, d: 12]},\n      {[a: 1, b: 2, a: 3], [a: 11]},\n      {[a: 1, b: 2], [c: 11, c: 12, d: 13]},\n      {[a: 1, b: 2, c: 3, c: 4], [c: 11, c: 12, d: 13]}\n    ]\n\n    args_error = [\n      {[1, 2], [c: 11, d: 12]},\n      {[1 | 2], [c: 11, d: 12]},\n      {[a: 1, b: 2], [11, 12, 0]},\n      {[a: 1, b: 2], [11 | 12]},\n      {[a: 1, b: 2], [{:x, 1}, :y, :z]},\n      {[a: 1, b: 2], [:x | :y]},\n      {[a: 1, b: 2], [{:x, 1} | :y]}\n    ]\n\n    for {arg1, arg2} <- args do\n      assert Keyword.merge(arg1, arg2) == Keyword.merge(arg1, arg2, fun)\n    end\n\n    for {arg1, arg2} <- args_error do\n      error = assert_raise ArgumentError, fn -> Keyword.merge(arg1, arg2) end\n      assert_raise ArgumentError, error.message, fn -> Keyword.merge(arg1, arg2, fun) end\n    end\n  end\n\n  test \"validate/2 raises on invalid arguments\" do\n    assert_raise ArgumentError,\n                 \"expected a keyword list as first argument, got invalid entry: :three\",\n                 fn -> Keyword.validate([:three], one: 1, two: 2) end\n\n    assert_raise ArgumentError,\n                 \"expected the second argument to be a list of atoms or tuples, got: 3\",\n                 fn -> Keyword.validate([three: 3], [:three, 3, :two]) end\n  end\n\n  test \"split_with/2\" do\n    assert Keyword.split_with([], fn {_k, v} -> rem(v, 2) == 0 end) == {[], []}\n\n    assert Keyword.split_with([a: \"1\", a: 1, b: 2], fn {k, _v} -> k in [:a, :b] end) ==\n             {[a: \"1\", a: 1, b: 2], []}\n\n    assert Keyword.split_with([a: \"1\", a: 1, b: 2], fn {_k, v} -> v == 5 end) ==\n             {[], [a: \"1\", a: 1, b: 2]}\n\n    assert Keyword.split_with([a: \"1\", a: 1, b: 2], fn {k, v} -> k in [:a] and is_integer(v) end) ==\n             {[a: 1], [a: \"1\", b: 2]}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/list/chars_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule List.Chars.AtomTest do\n  use ExUnit.Case, async: true\n\n  test \"basic\" do\n    assert to_charlist(:foo) == ~c\"foo\"\n  end\n\n  test \"true false nil\" do\n    assert to_charlist(false) == ~c\"false\"\n    assert to_charlist(true) == ~c\"true\"\n    assert to_charlist(nil) == ~c\"\"\n  end\nend\n\ndefmodule List.Chars.BitStringTest do\n  use ExUnit.Case, async: true\n\n  test \"basic\" do\n    assert to_charlist(\"foo\") == ~c\"foo\"\n  end\nend\n\ndefmodule List.Chars.NumberTest do\n  use ExUnit.Case, async: true\n\n  test \"integer\" do\n    assert to_charlist(1) == ~c\"1\"\n  end\n\n  test \"float\" do\n    assert to_charlist(1.0) == ~c\"1.0\"\n  end\nend\n\ndefmodule List.Chars.ListTest do\n  use ExUnit.Case, async: true\n\n  test \"basic\" do\n    assert to_charlist([1, \"b\", 3]) == [1, \"b\", 3]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/list_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule ListTest do\n  use ExUnit.Case, async: true\n\n  doctest List\n\n  test \"cons cell precedence\" do\n    assert [1 | List.flatten([2, 3])] == [1, 2, 3]\n  end\n\n  test \"optional comma\" do\n    assert Code.eval_string(\"[1,]\") == {[1], []}\n    assert Code.eval_string(\"[1, 2, 3,]\") == {[1, 2, 3], []}\n  end\n\n  test \"partial application\" do\n    assert (&[&1, 2]).(1) == [1, 2]\n    assert (&[&1, &2]).(1, 2) == [1, 2]\n    assert (&[&2, &1]).(2, 1) == [1, 2]\n    assert (&[&1 | &2]).(1, 2) == [1 | 2]\n    assert (&[&1, &2 | &3]).(1, 2, 3) == [1, 2 | 3]\n  end\n\n  test \"delete/2\" do\n    assert List.delete([:a, :b, :c], :a) == [:b, :c]\n    assert List.delete([:a, :b, :c], :d) == [:a, :b, :c]\n    assert List.delete([:a, :b, :b, :c], :b) == [:a, :b, :c]\n    assert List.delete([], :b) == []\n  end\n\n  test \"wrap/1\" do\n    assert List.wrap([1, 2, 3]) == [1, 2, 3]\n    assert List.wrap(1) == [1]\n    assert List.wrap(nil) == []\n  end\n\n  test \"flatten/1\" do\n    assert List.flatten([1, 2, 3]) == [1, 2, 3]\n    assert List.flatten([1, [2], 3]) == [1, 2, 3]\n    assert List.flatten([[1, [2], 3]]) == [1, 2, 3]\n\n    assert List.flatten([]) == []\n    assert List.flatten([[]]) == []\n    assert List.flatten([[], [[], []]]) == []\n  end\n\n  test \"flatten/2\" do\n    assert List.flatten([1, 2, 3], [4, 5]) == [1, 2, 3, 4, 5]\n    assert List.flatten([1, [2], 3], [4, 5]) == [1, 2, 3, 4, 5]\n    assert List.flatten([[1, [2], 3]], [4, 5]) == [1, 2, 3, 4, 5]\n    assert List.flatten([1, [], 2], [3, [], 4]) == [1, 2, 3, [], 4]\n  end\n\n  test \"foldl/3\" do\n    assert List.foldl([1, 2, 3], 0, fn x, y -> x + y end) == 6\n    assert List.foldl([1, 2, 3], 10, fn x, y -> x + y end) == 16\n    assert List.foldl([1, 2, 3, 4], 0, fn x, y -> x - y end) == 2\n  end\n\n  test \"foldr/3\" do\n    assert List.foldr([1, 2, 3], 0, fn x, y -> x + y end) == 6\n    assert List.foldr([1, 2, 3], 10, fn x, y -> x + y end) == 16\n    assert List.foldr([1, 2, 3, 4], 0, fn x, y -> x - y end) == -2\n  end\n\n  test \"duplicate/2\" do\n    assert List.duplicate(1, 0) == []\n    assert List.duplicate(1, 3) == [1, 1, 1]\n    assert List.duplicate([1], 1) == [[1]]\n  end\n\n  test \"first/1\" do\n    assert List.first([]) == nil\n    assert List.first([1]) == 1\n    assert List.first([1, 2, 3]) == 1\n  end\n\n  test \"first/2\" do\n    assert List.first([], 1) == 1\n    assert List.first([2], 1) == 2\n    assert List.first([1, 2, 3], 1) == 1\n  end\n\n  test \"first!/1\" do\n    assert List.first!([1]) == 1\n    assert List.first!([1, 2, 3]) == 1\n\n    assert_raise ArgumentError, \"attempted to get the first element of an empty list\", fn ->\n      List.first!([])\n    end\n  end\n\n  test \"last/1\" do\n    assert List.last([]) == nil\n    assert List.last([1]) == 1\n    assert List.last([1, 2, 3]) == 3\n  end\n\n  test \"last/2\" do\n    assert List.last([], 1) == 1\n    assert List.last([2], 1) == 2\n    assert List.last([1, 2, 3], 1) == 3\n  end\n\n  test \"last!/1\" do\n    assert List.last!([1]) == 1\n    assert List.last!([1, 2, 3]) == 3\n\n    assert_raise ArgumentError, \"attempted to get the last element of an empty list\", fn ->\n      List.last!([])\n    end\n  end\n\n  test \"keyfind/4\" do\n    assert List.keyfind([a: 1, b: 2], :a, 0) == {:a, 1}\n    assert List.keyfind([a: 1, b: 2], 2, 1) == {:b, 2}\n    assert List.keyfind([a: 1, b: 2], :c, 0) == nil\n  end\n\n  test \"keyreplace/4\" do\n    assert List.keyreplace([a: 1, b: 2], :a, 0, {:a, 3}) == [a: 3, b: 2]\n    assert List.keyreplace([a: 1], :b, 0, {:b, 2}) == [a: 1]\n  end\n\n  test \"keysort/2\" do\n    assert List.keysort([a: 4, b: 3, c: 5], 1) == [b: 3, a: 4, c: 5]\n    assert List.keysort([a: 4, c: 1, b: 2], 0) == [a: 4, b: 2, c: 1]\n  end\n\n  test \"keysort/3 with stable sorting\" do\n    collection = [\n      {2, 4},\n      {1, 5},\n      {2, 2},\n      {3, 1},\n      {4, 3}\n    ]\n\n    # Stable sorting\n    assert List.keysort(collection, 0) == [\n             {1, 5},\n             {2, 4},\n             {2, 2},\n             {3, 1},\n             {4, 3}\n           ]\n\n    assert List.keysort(collection, 0) ==\n             List.keysort(collection, 0, :asc)\n\n    assert List.keysort(collection, 0, &</2) == [\n             {1, 5},\n             {2, 2},\n             {2, 4},\n             {3, 1},\n             {4, 3}\n           ]\n\n    assert List.keysort(collection, 0, :desc) == [\n             {4, 3},\n             {3, 1},\n             {2, 4},\n             {2, 2},\n             {1, 5}\n           ]\n  end\n\n  test \"keysort/3 with module and stable sorting\" do\n    collection = [\n      {~D[2010-01-02], 4},\n      {~D[2010-01-01], 5},\n      {~D[2010-01-02], 2},\n      {~D[2010-01-03], 1},\n      {~D[2010-01-04], 3}\n    ]\n\n    # Stable sorting\n    assert List.keysort(collection, 0, Date) == [\n             {~D[2010-01-01], 5},\n             {~D[2010-01-02], 4},\n             {~D[2010-01-02], 2},\n             {~D[2010-01-03], 1},\n             {~D[2010-01-04], 3}\n           ]\n\n    assert List.keysort(collection, 0, Date) ==\n             List.keysort(collection, 0, {:asc, Date})\n\n    assert List.keysort(collection, 0, {:desc, Date}) == [\n             {~D[2010-01-04], 3},\n             {~D[2010-01-03], 1},\n             {~D[2010-01-02], 4},\n             {~D[2010-01-02], 2},\n             {~D[2010-01-01], 5}\n           ]\n  end\n\n  test \"keystore/4\" do\n    assert List.keystore([a: 1, b: 2], :a, 0, {:a, 3}) == [a: 3, b: 2]\n    assert List.keystore([a: 1], :b, 0, {:b, 2}) == [a: 1, b: 2]\n  end\n\n  test \"keymember?/3\" do\n    assert List.keymember?([a: 1, b: 2], :a, 0) == true\n    assert List.keymember?([a: 1, b: 2], 2, 1) == true\n    assert List.keymember?([a: 1, b: 2], :c, 0) == false\n  end\n\n  test \"keydelete/3\" do\n    assert List.keydelete([a: 1, b: 2], :a, 0) == [{:b, 2}]\n    assert List.keydelete([a: 1, b: 2], 2, 1) == [{:a, 1}]\n    assert List.keydelete([a: 1, b: 2], :c, 0) == [{:a, 1}, {:b, 2}]\n  end\n\n  test \"keytake/3\" do\n    assert List.keytake([a: 1, b: 2], :a, 0) == {{:a, 1}, [b: 2]}\n    assert List.keytake([a: 1, b: 2], 2, 1) == {{:b, 2}, [a: 1]}\n    assert List.keytake([a: 1, b: 2], :c, 0) == nil\n  end\n\n  test \"insert_at/3\" do\n    assert List.insert_at([1, 2, 3], 0, 0) == [0, 1, 2, 3]\n    assert List.insert_at([1, 2, 3], 3, 0) == [1, 2, 3, 0]\n    assert List.insert_at([1, 2, 3], 2, 0) == [1, 2, 0, 3]\n    assert List.insert_at([1, 2, 3], 10, 0) == [1, 2, 3, 0]\n    assert List.insert_at([1, 2, 3], -1, 0) == [1, 2, 3, 0]\n    assert List.insert_at([1, 2, 3], -4, 0) == [0, 1, 2, 3]\n    assert List.insert_at([1, 2, 3], -10, 0) == [0, 1, 2, 3]\n  end\n\n  test \"replace_at/3\" do\n    assert List.replace_at([1, 2, 3], 0, 0) == [0, 2, 3]\n    assert List.replace_at([1, 2, 3], 1, 0) == [1, 0, 3]\n    assert List.replace_at([1, 2, 3], 2, 0) == [1, 2, 0]\n    assert List.replace_at([1, 2, 3], 3, 0) == [1, 2, 3]\n    assert List.replace_at([1, 2, 3], -1, 0) == [1, 2, 0]\n    assert List.replace_at([1, 2, 3], -4, 0) == [1, 2, 3]\n  end\n\n  test \"update_at/3\" do\n    assert List.update_at([1, 2, 3], 0, &(&1 + 1)) == [2, 2, 3]\n    assert List.update_at([1, 2, 3], 1, &(&1 + 1)) == [1, 3, 3]\n    assert List.update_at([1, 2, 3], 2, &(&1 + 1)) == [1, 2, 4]\n    assert List.update_at([1, 2, 3], 3, &(&1 + 1)) == [1, 2, 3]\n    assert List.update_at([1, 2, 3], -1, &(&1 + 1)) == [1, 2, 4]\n    assert List.update_at([1, 2, 3], -4, &(&1 + 1)) == [1, 2, 3]\n  end\n\n  test \"delete_at/2\" do\n    for index <- [-1, 0, 1] do\n      assert List.delete_at([], index) == []\n    end\n\n    assert List.delete_at([1, 2, 3], 0) == [2, 3]\n    assert List.delete_at([1, 2, 3], 2) == [1, 2]\n    assert List.delete_at([1, 2, 3], 3) == [1, 2, 3]\n    assert List.delete_at([1, 2, 3], -1) == [1, 2]\n    assert List.delete_at([1, 2, 3], -3) == [2, 3]\n    assert List.delete_at([1, 2, 3], -4) == [1, 2, 3]\n  end\n\n  test \"pop_at/3\" do\n    for index <- [-1, 0, 1] do\n      assert List.pop_at([], index) == {nil, []}\n    end\n\n    assert List.pop_at([1], 1, 2) == {2, [1]}\n    assert List.pop_at([1, 2, 3], 0) == {1, [2, 3]}\n    assert List.pop_at([1, 2, 3], 2) == {3, [1, 2]}\n    assert List.pop_at([1, 2, 3], 3) == {nil, [1, 2, 3]}\n    assert List.pop_at([1, 2, 3], -1) == {3, [1, 2]}\n    assert List.pop_at([1, 2, 3], -3) == {1, [2, 3]}\n    assert List.pop_at([1, 2, 3], -4) == {nil, [1, 2, 3]}\n  end\n\n  describe \"starts_with?/2\" do\n    test \"list and prefix are equal\" do\n      assert List.starts_with?([], [])\n      assert List.starts_with?([1], [1])\n      assert List.starts_with?([1, 2, 3], [1, 2, 3])\n    end\n\n    test \"proper lists\" do\n      refute List.starts_with?([1], [1, 2])\n      assert List.starts_with?([1, 2, 3], [1, 2])\n      refute List.starts_with?([1, 2, 3], [1, 2, 3, 4])\n    end\n\n    test \"list is empty\" do\n      refute List.starts_with?([], [1])\n      refute List.starts_with?([], [1, 2])\n    end\n\n    test \"prefix is empty\" do\n      assert List.starts_with?([1], [])\n      assert List.starts_with?([1, 2], [])\n      assert List.starts_with?([1, 2, 3], [])\n    end\n\n    test \"only accepts proper lists\" do\n      message = \"no function clause matching in List.starts_with?/2\"\n\n      assert_raise FunctionClauseError, message, fn ->\n        List.starts_with?([1 | 2], [1 | 2])\n      end\n    end\n  end\n\n  describe \"ends_with?/2\" do\n    test \"list and prefix are equal\" do\n      assert List.ends_with?([], [])\n      assert List.ends_with?([1], [1])\n      assert List.ends_with?([1, 2, 3], [1, 2, 3])\n    end\n\n    test \"proper lists\" do\n      refute List.ends_with?([2], [1, 2])\n      assert List.ends_with?([1, 2, 3], [2, 3])\n      refute List.ends_with?([2, 3, 4], [1, 2, 3, 4])\n    end\n\n    test \"list is empty\" do\n      refute List.ends_with?([], [1])\n      refute List.ends_with?([], [1, 2])\n    end\n\n    test \"prefix is empty\" do\n      assert List.ends_with?([1], [])\n      assert List.ends_with?([1, 2], [])\n      assert List.ends_with?([1, 2, 3], [])\n    end\n\n    test \"only accepts proper lists\" do\n      assert_raise ArgumentError, ~r/not a list/, fn ->\n        List.ends_with?([1 | 2], [1 | 2])\n      end\n    end\n  end\n\n  test \"to_string/1\" do\n    assert List.to_string([?æ, ?ß]) == \"æß\"\n    assert List.to_string([?a, ?b, ?c]) == \"abc\"\n    assert List.to_string([]) == \"\"\n    assert List.to_string([[], []]) == \"\"\n\n    assert_raise UnicodeConversionError, \"invalid code point 57343\", fn ->\n      List.to_string([0xDFFF])\n    end\n\n    assert_raise UnicodeConversionError, \"invalid encoding starting at <<216, 0>>\", fn ->\n      List.to_string([\"a\", \"b\", <<0xD800::size(16)>>])\n    end\n\n    assert_raise ArgumentError, ~r\"cannot convert the given list to a string\", fn ->\n      List.to_string([:a, :b])\n    end\n  end\n\n  test \"to_charlist/1\" do\n    assert List.to_charlist([0x00E6, 0x00DF]) == ~c\"æß\"\n    assert List.to_charlist([0x0061, \"bc\"]) == ~c\"abc\"\n    assert List.to_charlist([0x0064, \"ee\", [~c\"p\"]]) == ~c\"deep\"\n\n    assert_raise UnicodeConversionError, \"invalid code point 57343\", fn ->\n      List.to_charlist([0xDFFF])\n    end\n\n    assert_raise UnicodeConversionError, \"invalid encoding starting at <<216, 0>>\", fn ->\n      List.to_charlist([\"a\", \"b\", <<0xD800::size(16)>>])\n    end\n\n    assert_raise ArgumentError, ~r\"cannot convert the given list to a charlist\", fn ->\n      List.to_charlist([:a, :b])\n    end\n  end\n\n  describe \"myers_difference/2\" do\n    test \"follows paper implementation\" do\n      assert List.myers_difference([], []) == []\n      assert List.myers_difference([], [1, 2, 3]) == [ins: [1, 2, 3]]\n      assert List.myers_difference([1, 2, 3], []) == [del: [1, 2, 3]]\n      assert List.myers_difference([1, 2, 3], [1, 2, 3]) == [eq: [1, 2, 3]]\n      assert List.myers_difference([1, 2, 3], [1, 4, 2, 3]) == [eq: [1], ins: [4], eq: [2, 3]]\n      assert List.myers_difference([1, 4, 2, 3], [1, 2, 3]) == [eq: [1], del: [4], eq: [2, 3]]\n      assert List.myers_difference([1], [[1]]) == [del: [1], ins: [[1]]]\n      assert List.myers_difference([[1]], [1]) == [del: [[1]], ins: [1]]\n    end\n\n    test \"rearranges inserts and equals for smaller diffs\" do\n      assert List.myers_difference([3, 2, 0, 2], [2, 2, 0, 2]) ==\n               [del: [3], ins: [2], eq: [2, 0, 2]]\n\n      assert List.myers_difference([3, 2, 1, 0, 2], [2, 1, 2, 1, 0, 2]) ==\n               [del: [3], ins: [2, 1], eq: [2, 1, 0, 2]]\n\n      assert List.myers_difference([3, 2, 2, 1, 0, 2], [2, 2, 1, 2, 1, 0, 2]) ==\n               [del: [3], eq: [2, 2, 1], ins: [2, 1], eq: [0, 2]]\n\n      assert List.myers_difference([3, 2, 0, 2], [2, 2, 1, 0, 2]) ==\n               [del: [3], eq: [2], ins: [2, 1], eq: [0, 2]]\n    end\n  end\n\n  test \"improper?/1\" do\n    assert List.improper?([1 | 2])\n    assert List.improper?([1, 2, 3 | 4])\n    refute List.improper?([])\n    refute List.improper?([1])\n    refute List.improper?([[1]])\n    refute List.improper?([1, 2])\n    refute List.improper?([1, 2, 3])\n  end\n\n  describe \"ascii_printable?/2\" do\n    test \"proper lists without limit\" do\n      assert List.ascii_printable?([])\n      assert List.ascii_printable?(~c\"abc\")\n      refute(List.ascii_printable?(~c\"abc\" ++ [0]))\n      refute List.ascii_printable?(~c\"mañana\")\n\n      printable_chars = ~c\"\\a\\b\\t\\n\\v\\f\\r\\e\" ++ Enum.to_list(32..126)\n      non_printable_chars = ~c\"🌢áéíóúźç©¢🂭\"\n\n      assert List.ascii_printable?(printable_chars)\n\n      for char <- printable_chars do\n        assert List.ascii_printable?([char])\n      end\n\n      refute List.ascii_printable?(non_printable_chars)\n\n      for char <- non_printable_chars do\n        refute List.ascii_printable?([char])\n      end\n    end\n\n    test \"proper lists with limit\" do\n      assert List.ascii_printable?([], 100)\n      assert List.ascii_printable?(~c\"abc\" ++ [0], 2)\n    end\n\n    test \"improper lists\" do\n      refute List.ascii_printable?(~c\"abc\" ++ ?d)\n      assert List.ascii_printable?(~c\"abc\" ++ ?d, 3)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/macro/env_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule MacroEnvMacros do\n  defmacro my_macro(arg) do\n    quote do: foo(unquote(arg))\n  end\n\n  @deprecated \"this is deprecated\"\n  defmacro my_deprecated_macro(arg), do: arg\nend\n\ndefmodule Macro.EnvTest do\n  use ExUnit.Case, async: true\n\n  import Macro.Env\n  import ExUnit.CaptureIO\n\n  alias List, as: CustomList, warn: false\n  import MacroEnvMacros, warn: false\n\n  def trace(event, _env) do\n    send(self(), event)\n    :ok\n  end\n\n  def meta, do: [file: \"some_file.exs\", line: 123]\n  def env, do: %{__ENV__ | tracers: [__MODULE__], line: 456}\n\n  doctest Macro.Env\n\n  test \"inspect\" do\n    assert inspect(__ENV__) =~ \"#Macro.Env<\"\n  end\n\n  test \"prune_compile_info\" do\n    assert %Macro.Env{lexical_tracker: nil, tracers: []} =\n             Macro.Env.prune_compile_info(%{__ENV__ | lexical_tracker: self(), tracers: [Foo]})\n  end\n\n  test \"stacktrace\" do\n    env = %{__ENV__ | file: \"foo\", line: 12}\n\n    assert Macro.Env.stacktrace(env) ==\n             [{__MODULE__, :\"test stacktrace\", 1, [file: ~c\"foo\", line: 12]}]\n\n    env = %{env | function: nil}\n\n    assert Macro.Env.stacktrace(env) == [\n             {__MODULE__, :__MODULE__, 0, [file: ~c\"foo\", line: 12]}\n           ]\n\n    env = %{env | module: nil}\n\n    assert Macro.Env.stacktrace(env) ==\n             [{:elixir_compiler, :__FILE__, 1, [file: ~c\"foo\", line: 12]}]\n  end\n\n  test \"context modules\" do\n    defmodule Foo.Bar do\n      assert __MODULE__ in __ENV__.context_modules\n    end\n\n    assert Foo.Bar in __ENV__.context_modules\n\n    Code.compile_string(\"\"\"\n    defmodule Foo.Bar.Compiled do\n      true = __MODULE__ in __ENV__.context_modules\n    end\n    \"\"\")\n  end\n\n  test \"to_match/1\" do\n    quote = quote(do: x in [])\n\n    assert {:__block__, [], [{:=, [], [{:_, [], Kernel}, {:x, [], Macro.EnvTest}]}, false]} =\n             Macro.expand_once(quote, __ENV__)\n\n    assert Macro.expand_once(quote, Macro.Env.to_match(__ENV__)) == false\n  end\n\n  test \"prepend_tracer\" do\n    assert %Macro.Env{tracers: [MyCustomTracer | _]} =\n             Macro.Env.prepend_tracer(__ENV__, MyCustomTracer)\n  end\n\n  describe \"define_import/4\" do\n    test \"with tracing\" do\n      define_import(env(), meta(), List)\n      assert_received {:import, _, List, []}\n\n      define_import(env(), meta(), Integer, only: :macros, trace: false)\n      refute_received {:import, _, Integer, _}\n    end\n\n    test \"with errors\" do\n      message =\n        \"invalid :only option for import, expected value to be an atom :functions, :macros, \" <>\n          \"or a literal keyword list of function names with arity as values, got: \"\n\n      assert define_import(env(), meta(), Integer, only: :unknown) ==\n               {:error, message <> \":unknown\"}\n\n      assert define_import(env(), meta(), Integer, only: [:unknown]) ==\n               {:error, message <> \"[:unknown]\"}\n    end\n\n    test \"with warnings\" do\n      assert capture_io(:stderr, fn ->\n               define_import(env(), meta(), Integer, only: [is_odd: 1, is_odd: 1])\n             end) =~ \"invalid :only option for import, is_odd/1 is duplicated\"\n\n      assert {:ok, _env} =\n               define_import(env(), meta(), Integer,\n                 only: [is_odd: 1, is_odd: 1],\n                 emit_warnings: false\n               )\n    end\n  end\n\n  describe \"expand_alias/4\" do\n    test \"with tracing\" do\n      {:alias, List} = expand_alias(env(), meta(), [:CustomList])\n      assert_received {:alias_expansion, _, Elixir.CustomList, List}\n\n      {:alias, List} = expand_alias(env(), meta(), [:CustomList], trace: false)\n      refute_received {:alias_expansion, _, Elixir.CustomList, List}\n\n      {:alias, List.Continues} = expand_alias(env(), meta(), [:CustomList, :Continues])\n      assert_received {:alias_expansion, _, Elixir.CustomList, List}\n    end\n  end\n\n  describe \"expand_require/6\" do\n    test \"returns :error for functions and unknown modules\" do\n      assert :error = expand_require(env(), meta(), List, :flatten, 1)\n      assert :error = expand_require(env(), meta(), Unknown, :flatten, 1)\n    end\n\n    test \"returns :error for unrequired modules\" do\n      assert :error = expand_require(env(), meta(), Integer, :is_odd, 1)\n    end\n\n    test \"expands required modules\" do\n      assert {:macro, Integer, _} =\n               expand_require(env(), [required: true] ++ meta(), Integer, :is_odd, 1)\n\n      assert {:macro, Integer, _} =\n               expand_require(%{env() | requires: [Integer]}, meta(), Integer, :is_odd, 1)\n\n      assert {:macro, Integer, _} =\n               expand_require(%{env() | module: Integer}, meta(), Integer, :is_odd, 1)\n    end\n\n    test \"expands with argument\" do\n      {:macro, MacroEnvMacros, fun} = expand_require(env(), meta(), MacroEnvMacros, :my_macro, 1)\n      assert fun.([], [quote(do: hello())]) == quote(do: foo(hello()))\n      assert fun.([line: 789], [quote(do: hello())]) == quote(line: 789, do: foo(hello()))\n\n      # do not propagate generated: true to arguments\n      assert {:foo, outer_meta, [{:hello, inner_meta, []}]} =\n               fun.([generated: true], [quote(do: hello())])\n\n      assert outer_meta[:generated]\n      refute inner_meta[:generated]\n    end\n\n    test \"with tracing and deprecations\" do\n      message = \"MacroEnvMacros.my_deprecated_macro/1 is deprecated\"\n\n      {:macro, MacroEnvMacros, fun} =\n        expand_require(env(), meta(), MacroEnvMacros, :my_deprecated_macro, 1)\n\n      assert capture_io(:stderr, fn -> fun.([], [quote(do: hello())]) end) =~ message\n      assert_received {:remote_macro, _, MacroEnvMacros, :my_deprecated_macro, 1}\n\n      {:macro, MacroEnvMacros, fun} =\n        expand_require(env(), meta(), MacroEnvMacros, :my_deprecated_macro, 1,\n          trace: false,\n          check_deprecations: false\n        )\n\n      refute capture_io(:stderr, fn -> fun.([], [quote(do: hello())]) end) =~ message\n      refute_received {:remote_macro, _, MacroEnvMacros, :my_deprecated_macro, 1}\n    end\n  end\n\n  describe \"expand_import/5\" do\n    test \"returns tagged :error for unknown imports\" do\n      assert {:error, :not_found} = expand_import(env(), meta(), :flatten, 1)\n    end\n\n    test \"returns tagged :error for special forms\" do\n      assert {:error, :not_found} = expand_import(env(), meta(), :case, 1)\n    end\n\n    test \"returns tagged :error for ambiguous\" do\n      import Date, warn: false\n      import Time, warn: false\n      assert {:error, {:ambiguous, mods}} = expand_import(__ENV__, meta(), :new, 3)\n      assert Enum.sort(mods) == [Date, Time]\n    end\n\n    test \"returns :function tuple\" do\n      assert {:function, ExUnit.CaptureIO, :capture_io} =\n               expand_import(env(), meta(), :capture_io, 1)\n    end\n\n    test \"expands with argument\" do\n      {:macro, MacroEnvMacros, fun} = expand_import(env(), meta(), :my_macro, 1)\n      assert fun.([], [quote(do: hello())]) == quote(do: foo(hello()))\n      assert fun.([line: 789], [quote(do: hello())]) == quote(line: 789, do: foo(hello()))\n\n      # do not propagate generated: true to arguments\n      assert {:foo, outer_meta, [{:hello, inner_meta, []}]} =\n               fun.([generated: true], [quote(do: hello())])\n\n      assert outer_meta[:generated]\n      refute inner_meta[:generated]\n    end\n\n    defmacro allow_locals_example, do: :ok\n\n    test \"allow_locals\" do\n      {:macro, Macro.EnvTest, fun} =\n        expand_import(env(), meta(), :allow_locals_example, 0)\n\n      assert fun.([], []) == :ok\n\n      assert expand_import(env(), meta(), :allow_locals_example, 0, allow_locals: false) ==\n               {:error, :not_found}\n\n      assert expand_import(env(), meta(), :allow_locals_example, 0,\n               allow_locals: fn -> send(self(), false) end\n             ) ==\n               {:error, :not_found}\n\n      assert_received false\n    end\n\n    test \"with tracing and deprecations\" do\n      message = \"MacroEnvMacros.my_deprecated_macro/1 is deprecated\"\n\n      {:macro, MacroEnvMacros, fun} = expand_import(env(), meta(), :my_deprecated_macro, 1)\n\n      assert capture_io(:stderr, fn -> fun.([], [quote(do: hello())]) end) =~ message\n      assert_received {:imported_macro, _, MacroEnvMacros, :my_deprecated_macro, 1}\n\n      {:macro, MacroEnvMacros, fun} =\n        expand_import(env(), meta(), :my_deprecated_macro, 1,\n          trace: false,\n          check_deprecations: false\n        )\n\n      refute capture_io(:stderr, fn -> fun.([], [quote(do: hello())]) end) =~ message\n      refute_received {:imported_macro, _, MacroEnvMacros, :my_deprecated_macro, 1}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/macro_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule Macro.ExternalTest do\n  defmacro external do\n    line = 18\n    file = __ENV__.file\n    ^line = __CALLER__.line\n    ^file = __CALLER__.file\n    ^line = Macro.Env.location(__CALLER__)[:line]\n    ^file = Macro.Env.location(__CALLER__)[:file]\n  end\n\n  defmacro oror(left, right) do\n    quote(do: unquote(left) || unquote(right))\n  end\nend\n\ndefmodule CustomIf do\n  def if(_cond, _expr) do\n    \"custom if result\"\n  end\nend\n\ndefmodule MacroTest do\n  use ExUnit.Case, async: true\n  doctest Macro\n\n  # Changing the lines above will make compilation\n  # fail since we are asserting on the caller lines\n  import Macro.ExternalTest\n\n  describe \"escape/2\" do\n    test \"returns tuples with size equal to two\" do\n      assert Macro.escape({:a, :b}) == {:a, :b}\n    end\n\n    test \"returns lists\" do\n      assert Macro.escape([1, 2, 3]) == [1, 2, 3]\n    end\n\n    test \"escapes tuples with size different than two\" do\n      assert Macro.escape({:a}) == {:{}, [], [:a]}\n      assert Macro.escape({:a, :b, :c}) == {:{}, [], [:a, :b, :c]}\n      assert Macro.escape({:a, {1, 2, 3}, :c}) == {:{}, [], [:a, {:{}, [], [1, 2, 3]}, :c]}\n\n      # False positives\n      assert Macro.escape({:quote, :foo, [:bar]}) == {:{}, [], [:quote, :foo, [:bar]]}\n      assert Macro.escape({:quote, :foo, [:bar, :baz]}) == {:{}, [], [:quote, :foo, [:bar, :baz]]}\n    end\n\n    test \"escapes maps\" do\n      assert Macro.escape(%{a: 1}) == {:%{}, [], [a: 1]}\n    end\n\n    test \"escapes bitstring\" do\n      assert {:<<>>, [], args} = Macro.escape(<<300::12>>)\n      assert [{:\"::\", [], [1, {:size, [], [4]}]}, {:\"::\", [], [\",\", {:binary, [], nil}]}] = args\n    end\n\n    test \"escapes recursively\" do\n      assert Macro.escape([1, {:a, :b, :c}, 3]) == [1, {:{}, [], [:a, :b, :c]}, 3]\n    end\n\n    test \"escapes improper lists\" do\n      assert Macro.escape([1 | 2]) == [{:|, [], [1, 2]}]\n      assert Macro.escape([1, 2 | 3]) == [1, {:|, [], [2, 3]}]\n    end\n\n    test \"prunes metadata\" do\n      meta = [nothing: :important, counter: 1]\n      assert Macro.escape({:foo, meta, []}) == {:{}, [], [:foo, meta, []]}\n      assert Macro.escape({:foo, meta, []}, prune_metadata: true) == {:{}, [], [:foo, [], []]}\n    end\n\n    test \"with unquote\" do\n      contents = quote(unquote: false, do: unquote(1))\n      assert Macro.escape(contents, unquote: true) == 1\n\n      contents = quote(unquote: false, do: unquote(x))\n      assert Macro.escape(contents, unquote: true) == {:x, [], MacroTest}\n\n      contents = %{foo: quote(unquote: false, do: unquote(1))}\n      assert Macro.escape(contents, unquote: true) == {:%{}, [], [foo: 1]}\n    end\n\n    test \"with generated\" do\n      assert Macro.escape(%{a: {}}, generated: true) ==\n               {:%{}, [generated: true], [a: {:{}, [], []}]}\n    end\n\n    defp eval_escaped(contents) do\n      {eval, []} = Code.eval_quoted(Macro.escape(contents, unquote: true))\n      eval\n    end\n\n    test \"with remote unquote\" do\n      contents = quote(unquote: false, do: Kernel.unquote(:is_atom)(:ok))\n      assert eval_escaped(contents) == quote(do: Kernel.is_atom(:ok))\n      assert eval_escaped(%{foo: contents}) == %{foo: quote(do: Kernel.is_atom(:ok))}\n    end\n\n    test \"with nested unquote\" do\n      contents =\n        quote do\n          quote(do: unquote(x))\n        end\n\n      assert eval_escaped(contents) == quote(do: quote(do: unquote(x)))\n    end\n\n    test \"with alias or no arguments remote unquote\" do\n      contents = quote(unquote: false, do: Kernel.unquote(:self)())\n      assert eval_escaped(contents) == quote(do: Kernel.self())\n\n      contents = quote(unquote: false, do: x.unquote(Foo))\n      assert eval_escaped(contents) == quote(do: x.unquote(Foo))\n    end\n\n    test \"with splicing\" do\n      contents = quote(unquote: false, do: [1, 2, 3, 4, 5])\n      assert Macro.escape(contents, unquote: true) == [1, 2, 3, 4, 5]\n\n      contents = quote(unquote: false, do: [1, 2, unquote_splicing([3, 4, 5])])\n      assert eval_escaped(contents) == [1, 2, 3, 4, 5]\n\n      contents = quote(unquote: false, do: [unquote_splicing([1, 2, 3]), 4, 5])\n      assert eval_escaped(contents) == [1, 2, 3, 4, 5]\n\n      contents =\n        quote(unquote: false, do: [unquote_splicing([1, 2, 3]), unquote_splicing([4, 5])])\n\n      assert eval_escaped(contents) == [1, 2, 3, 4, 5]\n\n      contents =\n        quote(unquote: false, do: [1, unquote_splicing([2]), 3, unquote_splicing([4]), 5])\n\n      assert eval_escaped(contents) == [1, 2, 3, 4, 5]\n\n      contents =\n        quote(unquote: false, do: [1, unquote_splicing([2]), 3, unquote_splicing([4]) | [5]])\n\n      assert eval_escaped(contents) == [1, 2, 3, 4, 5]\n\n      contents = %{foo: quote(unquote: false, do: [1, 2, unquote_splicing([3, 4, 5])])}\n      assert eval_escaped(contents) == %{foo: [1, 2, 3, 4, 5]}\n    end\n\n    test \"does not add context to quote\" do\n      assert Macro.escape({:quote, [], [[do: :foo]]}) == {:{}, [], [:quote, [], [[do: :foo]]]}\n    end\n\n    test \"escapes the content of :quote tuples\" do\n      assert Macro.escape({:quote, [%{}], [{}]}) ==\n               {:{}, [], [:quote, [{:%{}, [], []}], [{:{}, [], []}]]}\n\n      assert Macro.escape([:foo, {:quote, [%{}], [{}]}]) ==\n               [:foo, {:{}, [], [:quote, [{:%{}, [], []}], [{:{}, [], []}]]}]\n    end\n\n    @tag :re_import\n    test \"escape regex will remove references and replace it by a call to :re.import/1\" do\n      assert {\n               :%{},\n               [],\n               [\n                 __struct__: Regex,\n                 re_pattern:\n                   {{:., [], [{:__aliases__, _, [:Regex]}, :__import_pattern__]},\n                    [required: true], [{:{}, [], [:re_exported_pattern | _]}]},\n                 source: \"foo\",\n                 opts: []\n               ]\n             } = Macro.escape(~r/foo/)\n    end\n\n    @tag :re_import\n    test \"escape raises within structs fields\" do\n      assert_raise ArgumentError,\n                   ~r\"Regex defines custom escaping rules which are not supported in struct defaults\",\n                   fn ->\n                     defmodule Test do\n                       defstruct my_regex: ~r/^hi$/\n                     end\n                   end\n    end\n\n    defmodule EscapedStruct do\n      defstruct [:ast, :ref]\n\n      def __escape__(%{ast: ast}), do: ast\n    end\n\n    test \"escape struct with custom __escape__ (valid AST)\" do\n      struct = %EscapedStruct{ast: {:valid_ast, [], []}, ref: make_ref()}\n\n      assert {:valid_ast, [], []} = Macro.escape(struct)\n    end\n\n    test \"escape struct with custom __escape__ (shallow invalid AST)\" do\n      struct = %EscapedStruct{ast: %{invalid: :ast}, ref: make_ref()}\n\n      assert_raise ArgumentError,\n                   \"MacroTest.EscapedStruct.__escape__/1 returned invalid AST: %{invalid: :ast}\",\n                   fn -> Macro.escape(struct) end\n    end\n  end\n\n  describe \"expand_once/2\" do\n    test \"with external macro\" do\n      assert {:||, _, [1, false]} = Macro.expand_once(quote(do: oror(1, false)), __ENV__)\n    end\n\n    test \"with raw atom\" do\n      assert Macro.expand_once(quote(do: :foo), __ENV__) == :foo\n    end\n\n    test \"with current module\" do\n      assert Macro.expand_once(quote(do: __MODULE__), __ENV__) == __MODULE__\n    end\n\n    test \"with main\" do\n      assert Macro.expand_once(quote(do: Elixir), __ENV__) == Elixir\n    end\n\n    test \"with simple alias\" do\n      assert Macro.expand_once(quote(do: Foo), __ENV__) == Foo\n    end\n\n    test \"with current module plus alias\" do\n      assert Macro.expand_once(quote(do: __MODULE__.Foo), __ENV__) == __MODULE__.Foo\n    end\n\n    test \"with main plus alias\" do\n      assert Macro.expand_once(quote(do: Elixir.Foo), __ENV__) == Foo\n    end\n\n    test \"with custom alias\" do\n      alias Foo, as: Bar\n      assert Macro.expand_once(quote(do: Bar.Baz), __ENV__) == Foo.Baz\n    end\n\n    test \"with main plus custom alias\" do\n      alias Foo, as: Bar, warn: false\n      assert Macro.expand_once(quote(do: Elixir.Bar.Baz), __ENV__) == Elixir.Bar.Baz\n    end\n\n    test \"with call in alias\" do\n      assert Macro.expand_once(quote(do: Foo.bar().Baz), __ENV__) == quote(do: Foo.bar().Baz)\n    end\n\n    test \"env\" do\n      env = %{__ENV__ | line: 0, lexical_tracker: self()}\n\n      expanded = Macro.expand_once(quote(do: __ENV__), env)\n      assert Macro.validate(expanded) == :ok\n      assert Code.eval_quoted(expanded) == {env, []}\n\n      assert Macro.expand_once(quote(do: __ENV__.file), env) == env.file\n      assert Macro.expand_once(quote(do: __ENV__.unknown), env) == quote(do: __ENV__.unknown)\n\n      expanded = Macro.expand_once(quote(do: __ENV__.versioned_vars), env)\n      assert Macro.validate(expanded) == :ok\n      assert Code.eval_quoted(expanded) == {env.versioned_vars, []}\n    end\n\n    test \"env in :match context does not expand\" do\n      env = %{__ENV__ | line: 0, lexical_tracker: self(), context: :match}\n\n      expanded = Macro.expand_once(quote(do: __ENV__), env)\n      assert expanded == quote(do: __ENV__)\n\n      expanded = Macro.expand_once(quote(do: __ENV__.file), env)\n      assert expanded == quote(do: __ENV__.file)\n    end\n\n    defmacro local_macro(), do: raise(\"ignored\")\n\n    test \"vars\" do\n      expr = {:local_macro, [], nil}\n      assert Macro.expand_once(expr, __ENV__) == expr\n    end\n\n    defp expand_once_and_clean(quoted, env) do\n      cleaner = &Keyword.drop(&1, [:counter, :type_check, :generated])\n\n      quoted\n      |> Macro.expand_once(env)\n      |> Macro.prewalk(&Macro.update_meta(&1, cleaner))\n    end\n\n    test \"with imported macro\" do\n      temp_var = {:x, [], Kernel}\n\n      quoted =\n        quote context: Kernel do\n          case 1 do\n            unquote(temp_var)\n            when :erlang.orelse(\n                   :erlang.\"=:=\"(unquote(temp_var), false),\n                   :erlang.\"=:=\"(unquote(temp_var), nil)\n                 ) ->\n              false\n\n            unquote(temp_var) ->\n              unquote(temp_var)\n          end\n        end\n\n      assert expand_once_and_clean(quote(do: 1 || false), __ENV__) == quoted\n    end\n\n    test \"with require macro\" do\n      temp_var = {:x, [], Kernel}\n\n      quoted =\n        quote context: Kernel do\n          case 1 do\n            unquote(temp_var)\n            when :erlang.orelse(\n                   :erlang.\"=:=\"(unquote(temp_var), false),\n                   :erlang.\"=:=\"(unquote(temp_var), nil)\n                 ) ->\n              false\n\n            unquote(temp_var) ->\n              unquote(temp_var)\n          end\n        end\n\n      assert expand_once_and_clean(quote(do: Kernel.||(1, false)), __ENV__) == quoted\n    end\n\n    test \"with not expandable expression\" do\n      expr = quote(do: other(1, 2, 3))\n      assert Macro.expand_once(expr, __ENV__) == expr\n    end\n\n    test \"propagates :generated\" do\n      assert {:||, meta, [1, false]} = Macro.expand_once(quote(do: oror(1, false)), __ENV__)\n      refute meta[:generated]\n\n      assert {:||, meta, [1, false]} =\n               Macro.expand_once(quote(generated: true, do: oror(1, false)), __ENV__)\n\n      assert meta[:generated]\n    end\n\n    test \"does not propagate :generated to unquoted\" do\n      non_generated = quote do: foo()\n\n      assert {:||, outer_meta, [{:foo, inner_meta, []}, false]} =\n               Macro.expand_once(\n                 quote generated: true do\n                   oror(unquote(non_generated), false)\n                 end,\n                 __ENV__\n               )\n\n      assert outer_meta[:generated]\n      refute inner_meta[:generated]\n    end\n\n    defmacro foo_bar(x) do\n      y = quote do: bar(unquote(x))\n\n      quote do: foo(unquote(y))\n    end\n\n    test \"propagates :generated to unquote within macro\" do\n      non_generated = quote do: baz()\n\n      assert {:foo, foo_meta, [{:bar, bar_meta, [{:baz, baz_meta, []}]}]} =\n               Macro.expand_once(\n                 quote(generated: true, do: foo_bar(unquote(non_generated))),\n                 __ENV__\n               )\n\n      assert foo_meta[:generated]\n      assert bar_meta[:generated]\n      refute baz_meta[:generated]\n    end\n\n    test \"does not expand module attributes\" do\n      message =\n        \"could not call Module.get_attribute/2 because the module #{inspect(__MODULE__)} \" <>\n          \"is already compiled. Use the Module.__info__/1 callback or Code.fetch_docs/1 instead\"\n\n      assert_raise ArgumentError, message, fn ->\n        Macro.expand_once(quote(do: @foo), __ENV__)\n      end\n    end\n  end\n\n  defp expand_and_clean(quoted, env) do\n    cleaner = &Keyword.drop(&1, [:counter, :type_check, :generated])\n\n    quoted\n    |> Macro.expand(env)\n    |> Macro.prewalk(&Macro.update_meta(&1, cleaner))\n  end\n\n  test \"expand/2\" do\n    temp_var = {:x, [], Kernel}\n\n    quoted =\n      quote context: Kernel do\n        case 1 do\n          unquote(temp_var)\n          when :erlang.orelse(\n                 :erlang.\"=:=\"(unquote(temp_var), false),\n                 :erlang.\"=:=\"(unquote(temp_var), nil)\n               ) ->\n            false\n\n          unquote(temp_var) ->\n            unquote(temp_var)\n        end\n      end\n\n    assert expand_and_clean(quote(do: oror(1, false)), __ENV__) == quoted\n  end\n\n  test \"expand_literals/2\" do\n    assert Macro.expand_literals(quote(do: Foo), __ENV__) == Foo\n    assert Macro.expand_literals(quote(do: Foo + Bar), __ENV__) == quote(do: Foo + Bar)\n    assert Macro.expand_literals(quote(do: __MODULE__), __ENV__) == __MODULE__\n    assert Macro.expand_literals(quote(do: __MODULE__.Foo), __ENV__) == __MODULE__.Foo\n    assert Macro.expand_literals(quote(do: [Foo, 1 + 2]), __ENV__) == [Foo, quote(do: 1 + 2)]\n  end\n\n  test \"expand_literals/3\" do\n    fun = fn node, acc ->\n      expanded = Macro.expand(node, __ENV__)\n      {expanded, [expanded | acc]}\n    end\n\n    assert Macro.expand_literals(quote(do: Foo), [], fun) == {Foo, [Foo]}\n    assert Macro.expand_literals(quote(do: Foo + Bar), [], fun) == {quote(do: Foo + Bar), []}\n    assert Macro.expand_literals(quote(do: __MODULE__), [], fun) == {__MODULE__, [__MODULE__]}\n\n    assert Macro.expand_literals(quote(do: __MODULE__.Foo), [], fun) ==\n             {__MODULE__.Foo, [__MODULE__.Foo, __MODULE__]}\n  end\n\n  test \"var/2\" do\n    assert Macro.var(:foo, nil) == {:foo, [], nil}\n    assert Macro.var(:foo, Other) == {:foo, [], Other}\n  end\n\n  describe \"dbg/3\" do\n    defmacrop dbg_format_no_newline(ast, options \\\\ quote(do: [syntax_colors: []])) do\n      quote do\n        ExUnit.CaptureIO.with_io(fn ->\n          try do\n            unquote(Macro.dbg(ast, options, __CALLER__))\n          rescue\n            e -> e\n          end\n        end)\n      end\n    end\n\n    defmacrop dbg_format(ast, options \\\\ quote(do: [syntax_colors: []])) do\n      quote do\n        {result, formatted} =\n          dbg_format_no_newline(unquote(ast), unquote(options))\n\n        # Make sure there's an empty line after the output.\n        assert String.ends_with?(formatted, \"\\n\\n\") or\n                 String.ends_with?(formatted, \"\\n\\n\" <> IO.ANSI.reset())\n\n        {result, formatted}\n      end\n    end\n\n    test \"simple expression\" do\n      {result, formatted} = dbg_format(1 + 1)\n      assert result == 2\n      assert formatted =~ \"1 + 1 #=> 2\"\n    end\n\n    test \"variables\" do\n      my_var = 1 + 1\n      {result, formatted} = dbg_format(my_var)\n      assert result == 2\n      assert formatted =~ \"my_var #=> 2\"\n    end\n\n    test \"function call\" do\n      {result, formatted} = dbg_format(Atom.to_string(:foo))\n\n      assert result == \"foo\"\n      assert formatted =~ ~s[Atom.to_string(:foo) #=> \"foo\"]\n    end\n\n    test \"multiline input\" do\n      {result, formatted} =\n        dbg_format(\n          case 1 + 1 do\n            2 -> :two\n            _other -> :math_is_broken\n          end\n        )\n\n      assert result == :two\n\n      assert formatted =~ \"\"\"\n             case 1 + 1 do\n               2 -> :two\n               _other -> :math_is_broken\n             end #=> :two\n             \"\"\"\n    end\n\n    defp abc, do: [:a, :b, :c]\n\n    test \"pipeline on a single line\" do\n      {result, formatted} = dbg_format(abc() |> tl() |> tl |> Kernel.hd())\n      assert result == :c\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             \\nabc() #=> [:a, :b, :c]\n             |> tl() #=> [:b, :c]\n             |> tl #=> [:c]\n             |> Kernel.hd() #=> :c\n             \"\"\"\n\n      # Regression for pipes sometimes erroneously ending with three newlines (one\n      # extra than needed).\n      assert formatted =~ ~r/[^\\n]\\n\\n$/\n    end\n\n    test \"pipeline on multiple lines\" do\n      {result, formatted} =\n        dbg_format(\n          abc()\n          |> tl()\n          |> tl\n          |> Kernel.hd()\n        )\n\n      assert result == :c\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             \\nabc() #=> [:a, :b, :c]\n             |> tl() #=> [:b, :c]\n             |> tl #=> [:c]\n             |> Kernel.hd() #=> :c\n             \"\"\"\n\n      # Regression for pipes sometimes erroneously ending with three newlines (one\n      # extra than needed).\n      assert formatted =~ ~r/[^\\n]\\n\\n$/\n    end\n\n    test \"pipeline on multiple lines that raises\" do\n      {result, formatted} =\n        dbg_format_no_newline(\n          abc()\n          |> tl()\n          |> tl()\n          |> tl()\n          |> tl()\n        )\n\n      assert %ArgumentError{} = result\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             abc() #=> [:a, :b, :c]\n             |> tl() #=> [:b, :c]\n             |> tl() #=> [:c]\n             |> tl() #=> []\n             \"\"\"\n    end\n\n    test \"simple boolean expressions\" do\n      {result, formatted} = dbg_format(:rand.uniform() < 0.0 and length([]) == 0)\n      assert result == false\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             :rand.uniform() < 0.0 #=> false\n             :rand.uniform() < 0.0 and length([]) == 0 #=> false\n             \"\"\"\n    end\n\n    test \"left-associative operators\" do\n      {result, formatted} =\n        dbg_format(List.first([]) || Process.get(:unknown, \"yes\") || raise(\"foo\"))\n\n      assert result == \"yes\"\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             List.first([]) #=> nil\n             List.first([]) || Process.get(:unknown, \"yes\") #=> \"yes\"\n             List.first([]) || Process.get(:unknown, \"yes\") || raise \"foo\" #=> \"yes\"\n             \"\"\"\n    end\n\n    test \"composite boolean expressions\" do\n      true1 = length([]) == 0\n      true2 = length([]) == 0\n      {result, formatted} = dbg_format((true1 and true2) or (List.first([]) || true1))\n\n      assert result == true\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             true1 #=> true\n             true1 and true2 #=> true\n             (true1 and true2) or (List.first([]) || true1) #=> true\n             \"\"\"\n    end\n\n    test \"boolean expressions that raise\" do\n      falsy = length([]) != 0\n      x = 0\n\n      {result, formatted} = dbg_format_no_newline((falsy || x) && 1 / x)\n\n      assert %ArithmeticError{} = result\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             falsy #=> false\n             falsy || x #=> 0\n             \"\"\"\n    end\n\n    test \"block of code\" do\n      {result, formatted} =\n        dbg_format(\n          (\n            a = 1\n            b = a + 2\n            a + b\n          )\n        )\n\n      assert result == 4\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             a = 1 #=> 1\n             b = a + 2 #=> 3\n             a + b #=> 4\n             \"\"\"\n    end\n\n    test \"block that raises\" do\n      {result, formatted} =\n        dbg_format_no_newline(\n          (\n            a = 1\n            b = a - 1\n            a / b\n          )\n        )\n\n      assert result == %ArithmeticError{}\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             a = 1 #=> 1\n             b = a - 1 #=> 0\n             \"\"\"\n    end\n\n    test \"case\" do\n      list = List.flatten([1, 2, 3])\n\n      {result, formatted} =\n        dbg_format(\n          case list do\n            [] -> nil\n            _ -> Enum.sum(list)\n          end\n        )\n\n      assert result == 6\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             Case argument:\n             list #=> [1, 2, 3]\n\n             Case expression (clause #2 matched):\n             case list do\n               [] -> nil\n               _ -> Enum.sum(list)\n             end #=> 6\n             \"\"\"\n    end\n\n    test \"case that raises\" do\n      x = true\n\n      {result, formatted} =\n        dbg_format(\n          case true and x do\n            true -> raise \"oops\"\n            false -> :ok\n          end\n        )\n\n      assert %RuntimeError{} = result\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             Case argument:\n             true and x #=> true\n             \"\"\"\n    end\n\n    test \"case with guards\" do\n      {result, formatted} =\n        dbg_format(\n          case 0..100//5 do\n            %{first: first, last: last, step: step} when last > first ->\n              count = div(last - first, step)\n              {:ok, count}\n\n            _ ->\n              :error\n          end\n        )\n\n      assert result == {:ok, 20}\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             Case argument:\n             0..100//5 #=> 0..100//5\n\n             Case expression (clause #1 matched):\n             case 0..100//5 do\n               %{first: first, last: last, step: step} when last > first ->\n                 count = div(last - first, step)\n                 {:ok, count}\n\n               _ ->\n                 :error\n             end #=> {:ok, 20}\n             \"\"\"\n    end\n\n    test \"cond\" do\n      map = %{b: 5}\n\n      {result, formatted} =\n        dbg_format(\n          cond do\n            a = map[:a] -> a + 1\n            b = map[:b] -> b * 2\n            true -> nil\n          end\n        )\n\n      assert result == 10\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             Cond clause (clause #2 matched):\n             b = map[:b] #=> 5\n\n             Cond expression:\n             cond do\n               a = map[:a] -> a + 1\n               b = map[:b] -> b * 2\n               true -> nil\n             end #=> 10\n             \"\"\"\n    end\n\n    test \"if expression\" do\n      x = true\n      map = %{a: 5, b: 1}\n\n      {result, formatted} =\n        dbg_format(\n          if true and x do\n            map[:a] * 2\n          else\n            map[:b]\n          end\n        )\n\n      assert result == 10\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             If condition:\n             true and x #=> true\n\n             If expression:\n             if true and x do\n               map[:a] * 2\n             else\n               map[:b]\n             end #=> 10\n             \"\"\"\n    end\n\n    test \"if expression that raises\" do\n      x = true\n\n      {result, formatted} =\n        dbg_format(\n          if true and x do\n            raise \"oops\"\n          end\n        )\n\n      assert %RuntimeError{} = result\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             If condition:\n             true and x #=> true\n             \"\"\"\n    end\n\n    test \"if expression without else\" do\n      x = true\n      map = %{a: 5, b: 1}\n\n      {result, formatted} =\n        dbg_format(\n          if false and x do\n            map[:a] * 2\n          end\n        )\n\n      assert result == nil\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             If condition:\n             false and x #=> false\n\n             If expression:\n             if false and x do\n               map[:a] * 2\n             end #=> nil\n             \"\"\"\n    end\n\n    test \"custom if definition\" do\n      import Kernel, except: [if: 2]\n      import CustomIf, only: [if: 2]\n\n      {result, formatted} =\n        dbg_format(\n          if true do\n            \"something\"\n          end\n        )\n\n      assert result == \"custom if result\"\n\n      assert formatted =~ \"\"\"\n             if true do\n               \"something\"\n             end #=> \"custom if result\"\n             \"\"\"\n    end\n\n    test \"with/1 (all clauses match)\" do\n      opts = Process.get(:unused, %{width: 10, height: 15})\n\n      {result, formatted} =\n        dbg_format(\n          with {:ok, width} <- Map.fetch(opts, :width),\n               double_width = width * 2,\n               IO.puts(\"just a side effect\"),\n               {:ok, height} <- Map.fetch(opts, :height) do\n            {:ok, double_width * height}\n          end\n        )\n\n      assert result == {:ok, 300}\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             With clauses:\n             Map.fetch(opts, :width) #=> {:ok, 10}\n             width * 2 #=> 20\n             Map.fetch(opts, :height) #=> {:ok, 15}\n\n             With expression:\n             with {:ok, width} <- Map.fetch(opts, :width),\n                  double_width = width * 2,\n                  IO.puts(\"just a side effect\"),\n                  {:ok, height} <- Map.fetch(opts, :height) do\n               {:ok, double_width * height}\n             end #=> {:ok, 300}\n             \"\"\"\n    end\n\n    test \"with/1 (no else)\" do\n      opts = Process.get(:unused, %{width: 10})\n\n      {result, formatted} =\n        dbg_format(\n          with {:ok, width} <- Map.fetch(opts, :width),\n               {:ok, height} <- Map.fetch(opts, :height) do\n            {:ok, width * height}\n          end\n        )\n\n      assert result == :error\n\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             With clauses:\n             Map.fetch(opts, :width) #=> {:ok, 10}\n             Map.fetch(opts, :height) #=> :error\n\n             With expression:\n             with {:ok, width} <- Map.fetch(opts, :width),\n                  {:ok, height} <- Map.fetch(opts, :height) do\n               {:ok, width * height}\n             end #=> :error\n             \"\"\"\n    end\n\n    test \"with/1 (else clause)\" do\n      opts = Process.get(:unused, %{width: 10})\n\n      {result, formatted} =\n        dbg_format(\n          with {:ok, width} <- Map.fetch(opts, :width),\n               {:ok, height} <- Map.fetch(opts, :height) do\n            width * height\n          else\n            :error -> 0\n          end\n        )\n\n      assert result == 0\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             With clauses:\n             Map.fetch(opts, :width) #=> {:ok, 10}\n             Map.fetch(opts, :height) #=> :error\n\n             With expression:\n             with {:ok, width} <- Map.fetch(opts, :width),\n                  {:ok, height} <- Map.fetch(opts, :height) do\n               width * height\n             else\n               :error -> 0\n             end #=> 0\n             \"\"\"\n    end\n\n    test \"with/1 (guard)\" do\n      opts = Process.get(:unused, %{width: 10, height: 0.0})\n\n      {result, formatted} =\n        dbg_format(\n          with {:ok, width} when is_integer(width) <- Map.fetch(opts, :width),\n               {:ok, height} when is_integer(height) <- Map.fetch(opts, :height) do\n            width * height\n          else\n            _ -> nil\n          end\n        )\n\n      assert result == nil\n      assert formatted =~ \"macro_test.exs\"\n\n      assert formatted =~ \"\"\"\n             With clauses:\n             Map.fetch(opts, :width) #=> {:ok, 10}\n             Map.fetch(opts, :height) #=> {:ok, 0.0}\n\n             With expression:\n             with {:ok, width} when is_integer(width) <- Map.fetch(opts, :width),\n                  {:ok, height} when is_integer(height) <- Map.fetch(opts, :height) do\n               width * height\n             else\n               _ -> nil\n             end #=> nil\n             \"\"\"\n    end\n\n    test \"with/1 (guard in else)\" do\n      opts = Process.get(:unused, %{})\n\n      {result, _formatted} =\n        dbg_format(\n          with {:ok, width} <- Map.fetch(opts, :width) do\n            width\n          else\n            other when is_integer(other) -> :int\n            other when is_atom(other) -> :atom\n          end\n        )\n\n      assert result == :atom\n    end\n\n    test \"with/1 respects the WithClauseError\" do\n      value = Enum.random([:unexpected])\n\n      error =\n        assert_raise WithClauseError, fn ->\n          ExUnit.CaptureIO.capture_io(fn ->\n            dbg(\n              with :ok <- value do\n                true\n              else\n                :error -> false\n              end\n            )\n          end)\n        end\n\n      assert error.term == :unexpected\n    end\n\n    test \"with \\\"syntax_colors: []\\\" it doesn't print any color sequences\" do\n      {_result, formatted} = dbg_format(\"hello\")\n      refute formatted =~ \"\\e[\"\n    end\n\n    test \"with \\\"syntax_colors: [...]\\\" it forces color sequences\" do\n      {_result, formatted} = dbg_format(\"hello\", syntax_colors: [string: :cyan])\n      assert formatted =~ IO.iodata_to_binary(IO.ANSI.format([:cyan, ~s(\"hello\")]))\n    end\n\n    test \"forwards options to the underlying inspect calls\" do\n      value = ~c\"hello\"\n      assert {^value, formatted} = dbg_format(value, syntax_colors: [], charlists: :as_lists)\n      assert formatted =~ \"value #=> [104, 101, 108, 108, 111]\\n\"\n    end\n\n    test \"with the :print_location option set to false, doesn't print any header\" do\n      {result, formatted} = dbg_format(\"hello\", print_location: false)\n      assert result == \"hello\"\n      refute formatted =~ Path.basename(__ENV__.file)\n    end\n  end\n\n  describe \"to_string/1\" do\n    test \"converts quoted to string\" do\n      assert Macro.to_string(quote do: hello(world)) == \"hello(world)\"\n    end\n\n    test \"converts invalid AST with inspect\" do\n      assert Macro.to_string(1..3) == \"1..3\"\n    end\n  end\n\n  describe \"to_string/2\" do\n    defp macro_to_string(var, fun \\\\ fn _ast, string -> string end) do\n      module = String.to_atom(\"Elixir.Macro\")\n      module.to_string(var, fun)\n    end\n\n    test \"variable\" do\n      assert macro_to_string(quote(do: foo)) == \"foo\"\n    end\n\n    test \"local call\" do\n      assert macro_to_string(quote(do: foo(1, 2, 3))) == \"foo(1, 2, 3)\"\n      assert macro_to_string(quote(do: foo([1, 2, 3]))) == \"foo([1, 2, 3])\"\n    end\n\n    test \"remote call\" do\n      assert macro_to_string(quote(do: foo.bar(1, 2, 3))) == \"foo.bar(1, 2, 3)\"\n      assert macro_to_string(quote(do: foo.bar([1, 2, 3]))) == \"foo.bar([1, 2, 3])\"\n\n      quoted =\n        quote do\n          (foo do\n             :ok\n           end).bar([1, 2, 3])\n        end\n\n      assert macro_to_string(quoted) == \"(foo do\\n  :ok\\nend).bar([1, 2, 3])\"\n    end\n\n    test \"nullary remote call\" do\n      assert macro_to_string(quote do: foo.bar) == \"foo.bar\"\n      assert macro_to_string(quote do: foo.bar()) == \"foo.bar()\"\n    end\n\n    test \"atom remote call\" do\n      assert macro_to_string(quote(do: :foo.bar(1, 2, 3))) == \":foo.bar(1, 2, 3)\"\n    end\n\n    test \"remote and fun call\" do\n      assert macro_to_string(quote(do: foo.bar().(1, 2, 3))) == \"foo.bar().(1, 2, 3)\"\n      assert macro_to_string(quote(do: foo.bar().([1, 2, 3]))) == \"foo.bar().([1, 2, 3])\"\n    end\n\n    test \"unusual remote atom fun call\" do\n      assert macro_to_string(quote(do: Foo.\"42\"())) == ~s/Foo.\"42\"()/\n      assert macro_to_string(quote(do: Foo.\"Bar\"())) == ~s/Foo.\"Bar\"()/\n      assert macro_to_string(quote(do: Foo.\"bar baz\"().\"\"())) == ~s/Foo.\"bar baz\"().\"\"()/\n      assert macro_to_string(quote(do: Foo.\"%{}\"())) == ~s/Foo.\"%{}\"()/\n      assert macro_to_string(quote(do: Foo.\"...\"())) == ~s/Foo.\"...\"()/\n    end\n\n    test \"atom fun call\" do\n      assert macro_to_string(quote(do: :foo.(1, 2, 3))) == \":foo.(1, 2, 3)\"\n    end\n\n    test \"aliases call\" do\n      assert macro_to_string(quote(do: Elixir)) == \"Elixir\"\n      assert macro_to_string(quote(do: Foo)) == \"Foo\"\n      assert macro_to_string(quote(do: Foo.Bar.baz(1, 2, 3))) == \"Foo.Bar.baz(1, 2, 3)\"\n      assert macro_to_string(quote(do: Foo.Bar.baz([1, 2, 3]))) == \"Foo.Bar.baz([1, 2, 3])\"\n      assert macro_to_string(quote(do: Foo.bar(<<>>, []))) == \"Foo.bar(<<>>, [])\"\n    end\n\n    test \"keyword call\" do\n      assert macro_to_string(quote(do: Foo.bar(foo: :bar))) == \"Foo.bar(foo: :bar)\"\n      assert macro_to_string(quote(do: Foo.bar(\"Elixir.Foo\": :bar))) == \"Foo.bar([{Foo, :bar}])\"\n    end\n\n    test \"sigil call\" do\n      assert macro_to_string(quote(do: ~r\"123\")) == ~S/~r\"123\"/\n      assert macro_to_string(quote(do: ~r\"\\n123\")) == ~S/~r\"\\n123\"/\n      assert macro_to_string(quote(do: ~r\"12\\\"3\")) == ~S/~r\"12\\\"3\"/\n      assert macro_to_string(quote(do: ~r/12\\/3/u)) == ~S\"~r/12\\/3/u\"\n      assert macro_to_string(quote(do: ~r{\\n123})) == ~S/~r{\\n123}/\n      assert macro_to_string(quote(do: ~r((1\\)(2\\)3))) == ~S/~r((1\\)(2\\)3)/\n      assert macro_to_string(quote(do: ~r{\\n1{1\\}23})) == ~S/~r{\\n1{1\\}23}/\n      assert macro_to_string(quote(do: ~r|12\\|3|)) == ~S\"~r|12\\|3|\"\n\n      assert macro_to_string(quote(do: ~r[1#{two}3])) == ~S/~r[1#{two}3]/\n      assert macro_to_string(quote(do: ~r[1[#{two}\\]3])) == ~S/~r[1[#{two}\\]3]/\n      assert macro_to_string(quote(do: ~r'1#{two}3'u)) == ~S/~r'1#{two}3'u/\n\n      assert macro_to_string(quote(do: ~R\"123\")) == ~S/~R\"123\"/\n      assert macro_to_string(quote(do: ~R\"123\"u)) == ~S/~R\"123\"u/\n      assert macro_to_string(quote(do: ~R\"\\n123\")) == ~S/~R\"\\n123\"/\n\n      assert macro_to_string(quote(do: ~S[\"'(123)'\"])) == ~S/~S[\"'(123)'\"]/\n      assert macro_to_string(quote(do: ~s\"#{\"foo\"}\")) == ~S/~s\"#{\"foo\"}\"/\n\n      assert macro_to_string(quote(do: ~HTML[hi])) == ~S/~HTML[hi]/\n\n      assert macro_to_string(\n               quote do\n                 ~s\"\"\"\n                 \"\\\"\"foo\"\\\"\"\n                 \"\"\"\n               end\n             ) == ~s[~s\"\"\"\\n\"\\\\\"\"foo\"\\\\\"\"\\n\"\"\"]\n\n      assert macro_to_string(\n               quote do\n                 ~s'''\n                 '\\''foo'\\''\n                 '''\n               end\n             ) == ~s[~s'''\\n'\\\\''foo'\\\\''\\n''']\n\n      assert macro_to_string(\n               quote do\n                 ~s\"\"\"\n                 \"\\\"foo\\\"\"\n                 \"\"\"\n               end\n             ) == ~s[~s\"\"\"\\n\"\\\\\"foo\\\\\"\"\\n\"\"\"]\n\n      assert macro_to_string(\n               quote do\n                 ~s'''\n                 '\\\"foo\\\"'\n                 '''\n               end\n             ) == ~s[~s'''\\n'\\\\\"foo\\\\\"'\\n''']\n\n      assert macro_to_string(\n               quote do\n                 ~S\"\"\"\n                 \"123\"\n                 \"\"\"\n               end\n             ) == ~s[~S\"\"\"\\n\"123\"\\n\"\"\"]\n\n      assert macro_to_string(\n               quote do\n                 ~HTML\"\"\"\n                 \"123\"\n                 \"\"\"\n               end\n             ) == ~s[~HTML\"\"\"\\n\"123\"\\n\"\"\"]\n    end\n\n    test \"tuple call\" do\n      assert macro_to_string(quote(do: alias(Foo.{Bar, Baz, Bong}))) ==\n               \"alias(Foo.{Bar, Baz, Bong})\"\n\n      assert macro_to_string(quote(do: foo(Foo.{}))) == \"foo(Foo.{})\"\n    end\n\n    test \"arrow\" do\n      assert macro_to_string(quote(do: foo(1, (2 -> 3)))) == \"foo(1, (2 -> 3))\"\n    end\n\n    test \"block\" do\n      quoted =\n        quote do\n          1\n          2\n\n          (\n            :foo\n            :bar\n          )\n\n          3\n        end\n\n      expected = \"\"\"\n      (\n        1\n        2\n        (\n          :foo\n          :bar\n        )\n        3\n      )\n      \"\"\"\n\n      assert macro_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"not in\" do\n      assert macro_to_string(quote(do: false not in [])) == \"false not in []\"\n    end\n\n    test \"if else\" do\n      expected = \"\"\"\n      if(foo) do\n        bar\n      else\n        baz\n      end\n      \"\"\"\n\n      assert macro_to_string(quote(do: if(foo, do: bar, else: baz))) <> \"\\n\" == expected\n    end\n\n    test \"case\" do\n      quoted =\n        quote do\n          case foo do\n            true ->\n              0\n\n            false ->\n              1\n              2\n          end\n        end\n\n      expected = \"\"\"\n      case(foo) do\n        true ->\n          0\n        false ->\n          1\n          2\n      end\n      \"\"\"\n\n      assert macro_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"try\" do\n      quoted =\n        quote do\n          try do\n            foo\n          catch\n            _, _ ->\n              2\n          rescue\n            ArgumentError ->\n              1\n          after\n            4\n          else\n            _ ->\n              3\n          end\n        end\n\n      expected = \"\"\"\n      try do\n        foo\n      rescue\n        ArgumentError ->\n          1\n      catch\n        _, _ ->\n          2\n      else\n        _ ->\n          3\n      after\n        4\n      end\n      \"\"\"\n\n      assert macro_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"fn\" do\n      assert macro_to_string(quote(do: fn -> 1 + 2 end)) == \"fn -> 1 + 2 end\"\n      assert macro_to_string(quote(do: fn x -> x + 1 end)) == \"fn x -> x + 1 end\"\n\n      quoted =\n        quote do\n          fn x ->\n            y = x + 1\n            y\n          end\n        end\n\n      expected = \"\"\"\n      fn x ->\n        y = x + 1\n        y\n      end\n      \"\"\"\n\n      assert macro_to_string(quoted) <> \"\\n\" == expected\n\n      quoted =\n        quote do\n          fn\n            x ->\n              y = x + 1\n              y\n\n            z ->\n              z\n          end\n        end\n\n      expected = \"\"\"\n      fn\n        x ->\n          y = x + 1\n          y\n        z ->\n          z\n      end\n      \"\"\"\n\n      assert macro_to_string(quoted) <> \"\\n\" == expected\n\n      assert macro_to_string(quote(do: (fn x -> x end).(1))) == \"(fn x -> x end).(1)\"\n\n      quoted =\n        quote do\n          (fn\n             %{} -> :map\n             _ -> :other\n           end).(1)\n        end\n\n      expected = \"\"\"\n      (fn\n        %{} ->\n          :map\n        _ ->\n          :other\n      end).(1)\n      \"\"\"\n\n      assert macro_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"range\" do\n      assert macro_to_string(quote(do: -1..+2)) == \"-1..+2\"\n      assert macro_to_string(quote(do: Foo.integer()..3)) == \"Foo.integer()..3\"\n      assert macro_to_string(quote(do: -1..+2//-3)) == \"-1..+2//-3\"\n\n      assert macro_to_string(quote(do: Foo.integer()..3//Bar.bat())) ==\n               \"Foo.integer()..3//Bar.bat()\"\n\n      # invalid AST\n      assert macro_to_string(-1..+2) == \"-1..2\"\n      assert macro_to_string(-1..+2//-3) == \"-1..2//-3\"\n    end\n\n    test \"when\" do\n      assert macro_to_string(quote(do: (-> x))) == \"(() -> x)\"\n      assert macro_to_string(quote(do: (x when y -> z))) == \"(x when y -> z)\"\n      assert macro_to_string(quote(do: (x, y when z -> w))) == \"((x, y) when z -> w)\"\n      assert macro_to_string(quote(do: (x, y when z -> w))) == \"((x, y) when z -> w)\"\n    end\n\n    test \"nested\" do\n      quoted =\n        quote do\n          defmodule Foo do\n            def foo do\n              1 + 1\n            end\n          end\n        end\n\n      expected = \"\"\"\n      defmodule(Foo) do\n        def(foo) do\n          1 + 1\n        end\n      end\n      \"\"\"\n\n      assert macro_to_string(quoted) <> \"\\n\" == expected\n    end\n\n    test \"operator precedence\" do\n      assert macro_to_string(quote(do: (1 + 2) * (3 - 4))) == \"(1 + 2) * (3 - 4)\"\n      assert macro_to_string(quote(do: (1 + 2) * 3 - 4)) == \"(1 + 2) * 3 - 4\"\n      assert macro_to_string(quote(do: 1 + 2 + 3)) == \"1 + 2 + 3\"\n      assert macro_to_string(quote(do: 1 + 2 - 3)) == \"1 + 2 - 3\"\n    end\n\n    test \"capture operator\" do\n      assert macro_to_string(quote(do: &foo/0)) == \"&foo/0\"\n      assert macro_to_string(quote(do: &Foo.foo/0)) == \"&Foo.foo/0\"\n      assert macro_to_string(quote(do: &(&1 + &2))) == \"&(&1 + &2)\"\n      assert macro_to_string(quote(do: & &1)) == \"&(&1)\"\n      assert macro_to_string(quote(do: & &1.(:x))) == \"&(&1.(:x))\"\n      assert macro_to_string(quote(do: (& &1).(:x))) == \"(&(&1)).(:x)\"\n    end\n\n    test \"containers\" do\n      assert macro_to_string(quote(do: {})) == \"{}\"\n      assert macro_to_string(quote(do: [])) == \"[]\"\n      assert macro_to_string(quote(do: {1, 2, 3})) == \"{1, 2, 3}\"\n      assert macro_to_string(quote(do: [1, 2, 3])) == \"[1, 2, 3]\"\n      assert macro_to_string(quote(do: [\"Elixir.Foo\": :bar])) == \"[{Foo, :bar}]\"\n      assert macro_to_string(quote(do: %{})) == \"%{}\"\n      assert macro_to_string(quote(do: %{:foo => :bar})) == \"%{foo: :bar}\"\n      assert macro_to_string(quote(do: %{:\"Elixir.Foo\" => :bar})) == \"%{Foo => :bar}\"\n      assert macro_to_string(quote(do: %{{1, 2} => [1, 2, 3]})) == \"%{{1, 2} => [1, 2, 3]}\"\n      assert macro_to_string(quote(do: %{map | \"a\" => \"b\"})) == \"%{map | \\\"a\\\" => \\\"b\\\"}\"\n      assert macro_to_string(quote(do: [1, 2, 3])) == \"[1, 2, 3]\"\n    end\n\n    test \"struct\" do\n      assert macro_to_string(quote(do: %Test{})) == \"%Test{}\"\n      assert macro_to_string(quote(do: %Test{foo: 1, bar: 1})) == \"%Test{foo: 1, bar: 1}\"\n      assert macro_to_string(quote(do: %Test{struct | foo: 2})) == \"%Test{struct | foo: 2}\"\n      assert macro_to_string(quote(do: %Test{} + 1)) == \"%Test{} + 1\"\n      assert macro_to_string(quote(do: %Test{foo(1)} + 2)) == \"%Test{foo(1)} + 2\"\n    end\n\n    test \"binary operators\" do\n      assert macro_to_string(quote(do: 1 + 2)) == \"1 + 2\"\n      assert macro_to_string(quote(do: [1, 2 | 3])) == \"[1, 2 | 3]\"\n      assert macro_to_string(quote(do: [h | t] = [1, 2, 3])) == \"[h | t] = [1, 2, 3]\"\n      assert macro_to_string(quote(do: (x ++ y) ++ z)) == \"(x ++ y) ++ z\"\n      assert macro_to_string(quote(do: (x +++ y) +++ z)) == \"(x +++ y) +++ z\"\n    end\n\n    test \"unary operators\" do\n      assert macro_to_string(quote(do: not 1)) == \"not(1)\"\n      assert macro_to_string(quote(do: not foo)) == \"not(foo)\"\n      assert macro_to_string(quote(do: -1)) == \"-1\"\n      assert macro_to_string(quote(do: +(+1))) == \"+(+1)\"\n      assert macro_to_string(quote(do: !(foo > bar))) == \"!(foo > bar)\"\n      assert macro_to_string(quote(do: @foo(bar))) == \"@foo(bar)\"\n      assert macro_to_string(quote(do: identity(&1))) == \"identity(&1)\"\n    end\n\n    test \"access\" do\n      assert macro_to_string(quote(do: a[b])) == \"a[b]\"\n      assert macro_to_string(quote(do: a[1 + 2])) == \"a[1 + 2]\"\n      assert macro_to_string(quote(do: (a || [a: 1])[:a])) == \"(a || [a: 1])[:a]\"\n      assert macro_to_string(quote(do: Map.put(%{}, :a, 1)[:a])) == \"Map.put(%{}, :a, 1)[:a]\"\n    end\n\n    test \"keyword list\" do\n      assert macro_to_string(quote(do: [a: a, b: b])) == \"[a: a, b: b]\"\n      assert macro_to_string(quote(do: [a: 1, b: 1 + 2])) == \"[a: 1, b: 1 + 2]\"\n      assert macro_to_string(quote(do: [\"a.b\": 1, c: 1 + 2])) == \"[\\\"a.b\\\": 1, c: 1 + 2]\"\n    end\n\n    test \"interpolation\" do\n      assert macro_to_string(quote(do: \"foo#{bar}baz\")) == ~S[\"foo#{bar}baz\"]\n    end\n\n    test \"bit syntax\" do\n      ast = quote(do: <<1::8*4>>)\n      assert macro_to_string(ast) == \"<<1::8*4>>\"\n\n      ast = quote(do: @type(foo :: <<_::8, _::_*4>>))\n      assert macro_to_string(ast) == \"@type(foo :: <<_::8, _::_*4>>)\"\n\n      ast = quote(do: <<69 - 4::bits-size(8 - 4)-unit(1), 65>>)\n      assert macro_to_string(ast) == \"<<69 - 4::bits-size(8 - 4)-unit(1), 65>>\"\n\n      ast = quote(do: <<(<<65>>), 65>>)\n      assert macro_to_string(ast) == \"<<(<<65>>), 65>>\"\n\n      ast = quote(do: <<65, (<<65>>)>>)\n      assert macro_to_string(ast) == \"<<65, (<<65>>)>>\"\n\n      ast = quote(do: for(<<(a::4 <- <<1, 2>>)>>, do: a))\n      assert macro_to_string(ast) == \"for(<<(a :: 4 <- <<1, 2>>)>>) do\\n  a\\nend\"\n    end\n\n    test \"charlist\" do\n      assert macro_to_string(quote(do: [])) == \"[]\"\n      assert macro_to_string(quote(do: ~c\"abc\")) == ~S/~c\"abc\"/\n      assert macro_to_string(quote(do: [?a, ?b, ?c])) == ~S/~c\"abc\"/\n    end\n\n    test \"string\" do\n      assert macro_to_string(quote(do: \"\")) == ~S/\"\"/\n      assert macro_to_string(quote(do: \"abc\")) == ~S/\"abc\"/\n      assert macro_to_string(quote(do: \"#{\"abc\"}\")) == ~S/\"#{\"abc\"}\"/\n    end\n\n    test \"last arg keyword list\" do\n      assert macro_to_string(quote(do: foo([]))) == \"foo([])\"\n      assert macro_to_string(quote(do: foo(x: y))) == \"foo(x: y)\"\n      assert macro_to_string(quote(do: foo(x: 1 + 2))) == \"foo(x: 1 + 2)\"\n      assert macro_to_string(quote(do: foo(x: y, p: q))) == \"foo(x: y, p: q)\"\n      assert macro_to_string(quote(do: foo(a, x: y, p: q))) == \"foo(a, x: y, p: q)\"\n\n      assert macro_to_string(quote(do: {[]})) == \"{[]}\"\n      assert macro_to_string(quote(do: {[a: b]})) == \"{[a: b]}\"\n      assert macro_to_string(quote(do: {x, a: b})) == \"{x, [a: b]}\"\n      assert macro_to_string(quote(do: foo(else: a))) == \"foo(else: a)\"\n      assert macro_to_string(quote(do: foo(catch: a))) == \"foo(catch: a)\"\n    end\n\n    test \"with fun\" do\n      assert macro_to_string(quote(do: foo(1, 2, 3)), fn _, string -> \":#{string}:\" end) ==\n               \":foo(:1:, :2:, :3:):\"\n\n      assert macro_to_string(quote(do: Bar.foo(1, 2, 3)), fn _, string -> \":#{string}:\" end) ==\n               \"::Bar:.foo(:1:, :2:, :3:):\"\n    end\n  end\n\n  test \"validate/1\" do\n    ref = make_ref()\n\n    assert Macro.validate(1) == :ok\n    assert Macro.validate(1.0) == :ok\n    assert Macro.validate(:foo) == :ok\n    assert Macro.validate(\"bar\") == :ok\n    assert Macro.validate(<<0::8>>) == :ok\n    assert Macro.validate(self()) == :ok\n    assert Macro.validate({1, 2}) == :ok\n    assert Macro.validate({:foo, [], :baz}) == :ok\n    assert Macro.validate({:foo, [], []}) == :ok\n    assert Macro.validate([1, 2, 3]) == :ok\n\n    assert Macro.validate(<<0::4>>) == {:error, <<0::4>>}\n    assert Macro.validate(ref) == {:error, ref}\n    assert Macro.validate({1, ref}) == {:error, ref}\n    assert Macro.validate({ref, 2}) == {:error, ref}\n    assert Macro.validate([1, ref, 3]) == {:error, ref}\n    assert Macro.validate({:foo, [], 0}) == {:error, {:foo, [], 0}}\n    assert Macro.validate({:foo, 0, []}) == {:error, {:foo, 0, []}}\n  end\n\n  test \"decompose_call/1\" do\n    assert Macro.decompose_call(quote(do: foo)) == {:foo, []}\n    assert Macro.decompose_call(quote(do: foo())) == {:foo, []}\n    assert Macro.decompose_call(quote(do: foo(1, 2, 3))) == {:foo, [1, 2, 3]}\n\n    assert Macro.decompose_call(quote(do: M.N.foo(1, 2, 3))) ==\n             {{:__aliases__, [alias: false], [:M, :N]}, :foo, [1, 2, 3]}\n\n    assert Macro.decompose_call(quote(do: :foo.foo(1, 2, 3))) == {:foo, :foo, [1, 2, 3]}\n    assert Macro.decompose_call(quote(do: 1.(1, 2, 3))) == :error\n    assert Macro.decompose_call(quote(do: \"some string\")) == :error\n    assert Macro.decompose_call(quote(do: {:foo, :bar, :baz})) == :error\n    assert Macro.decompose_call(quote(do: {:foo, :bar, :baz, 42})) == :error\n  end\n\n  ## pipe/unpipe\n\n  test \"pipe/3\" do\n    assert Macro.pipe(1, quote(do: foo), 0) == quote(do: foo(1))\n    assert Macro.pipe(1, quote(do: foo(2)), 0) == quote(do: foo(1, 2))\n    assert Macro.pipe(1, quote(do: foo), -1) == quote(do: foo(1))\n    assert Macro.pipe(2, quote(do: foo(1)), -1) == quote(do: foo(1, 2))\n\n    assert Macro.pipe(quote(do: %{foo: \"bar\"}), quote(do: Access.get(:foo)), 0) ==\n             quote(do: Access.get(%{foo: \"bar\"}, :foo))\n\n    assert_raise ArgumentError, ~r\"cannot pipe 1 into 2\", fn ->\n      Macro.pipe(1, 2, 0)\n    end\n\n    assert_raise ArgumentError, ~r\"cannot pipe 1 into \\{2, 3\\}\", fn ->\n      Macro.pipe(1, {2, 3}, 0)\n    end\n\n    assert_raise ArgumentError, ~r\"cannot pipe 1 into 1 \\+ 1, the :\\+ operator can\", fn ->\n      Macro.pipe(1, quote(do: 1 + 1), 0) == quote(do: foo(1))\n    end\n\n    assert_raise ArgumentError, ~r\"cannot pipe 1 into <<1>>\", fn ->\n      Macro.pipe(1, quote(do: <<1>>), 0)\n    end\n\n    assert_raise ArgumentError, ~r\"cannot pipe 1 into the special form unquote/1\", fn ->\n      Macro.pipe(1, quote(do: unquote()), 0)\n    end\n\n    assert_raise ArgumentError, ~r\"piping into a unary operator is not supported\", fn ->\n      Macro.pipe(1, quote(do: +1), 0)\n    end\n\n    assert_raise ArgumentError, ~r\"cannot pipe Macro into Env\", fn ->\n      Macro.pipe(Macro, quote(do: Env), 0)\n    end\n\n    assert_raise ArgumentError, ~r\"cannot pipe 1 into 2 && 3\", fn ->\n      Macro.pipe(1, quote(do: 2 && 3), 0)\n    end\n\n    message = ~r\"cannot pipe :foo into an anonymous function without calling\"\n\n    assert_raise ArgumentError, message, fn ->\n      Macro.pipe(:foo, quote(do: fn x -> x end), 0)\n    end\n\n    message = ~r\"wrong operator precedence when piping into bracket-based access\"\n\n    assert_raise ArgumentError, message, fn ->\n      Macro.pipe(:foo, quote(do: %{foo: bar}[:foo]), 0)\n    end\n  end\n\n  test \"unpipe/1\" do\n    assert Macro.unpipe(quote(do: foo)) == quote(do: [{foo, 0}])\n    assert Macro.unpipe(quote(do: foo |> bar)) == quote(do: [{foo, 0}, {bar, 0}])\n    assert Macro.unpipe(quote(do: foo |> bar |> baz)) == quote(do: [{foo, 0}, {bar, 0}, {baz, 0}])\n  end\n\n  ## traverse/pre/postwalk\n\n  test \"traverse/4\" do\n    assert traverse({:foo, [], nil}) == [{:foo, [], nil}, {:foo, [], nil}]\n\n    assert traverse({:foo, [], [1, 2, 3]}) ==\n             [{:foo, [], [1, 2, 3]}, 1, 1, 2, 2, 3, 3, {:foo, [], [1, 2, 3]}]\n\n    assert traverse({{:., [], [:foo, :bar]}, [], [1, 2, 3]}) ==\n             [\n               {{:., [], [:foo, :bar]}, [], [1, 2, 3]},\n               {:., [], [:foo, :bar]},\n               :foo,\n               :foo,\n               :bar,\n               :bar,\n               {:., [], [:foo, :bar]},\n               1,\n               1,\n               2,\n               2,\n               3,\n               3,\n               {{:., [], [:foo, :bar]}, [], [1, 2, 3]}\n             ]\n\n    assert traverse({[1, 2, 3], [4, 5, 6]}) ==\n             [\n               {[1, 2, 3], [4, 5, 6]},\n               [1, 2, 3],\n               1,\n               1,\n               2,\n               2,\n               3,\n               3,\n               [1, 2, 3],\n               [4, 5, 6],\n               4,\n               4,\n               5,\n               5,\n               6,\n               6,\n               [4, 5, 6],\n               {[1, 2, 3], [4, 5, 6]}\n             ]\n  end\n\n  defp traverse(ast) do\n    Macro.traverse(ast, [], &{&1, [&1 | &2]}, &{&1, [&1 | &2]}) |> elem(1) |> Enum.reverse()\n  end\n\n  test \"prewalk/3\" do\n    assert prewalk({:foo, [], nil}) == [{:foo, [], nil}]\n\n    assert prewalk({:foo, [], [1, 2, 3]}) == [{:foo, [], [1, 2, 3]}, 1, 2, 3]\n\n    assert prewalk({{:., [], [:foo, :bar]}, [], [1, 2, 3]}) ==\n             [\n               {{:., [], [:foo, :bar]}, [], [1, 2, 3]},\n               {:., [], [:foo, :bar]},\n               :foo,\n               :bar,\n               1,\n               2,\n               3\n             ]\n\n    assert prewalk({[1, 2, 3], [4, 5, 6]}) ==\n             [{[1, 2, 3], [4, 5, 6]}, [1, 2, 3], 1, 2, 3, [4, 5, 6], 4, 5, 6]\n  end\n\n  defp prewalk(ast) do\n    Macro.prewalk(ast, [], &{&1, [&1 | &2]}) |> elem(1) |> Enum.reverse()\n  end\n\n  test \"postwalk/3\" do\n    assert postwalk({:foo, [], nil}) == [{:foo, [], nil}]\n\n    assert postwalk({:foo, [], [1, 2, 3]}) == [1, 2, 3, {:foo, [], [1, 2, 3]}]\n\n    assert postwalk({{:., [], [:foo, :bar]}, [], [1, 2, 3]}) ==\n             [\n               :foo,\n               :bar,\n               {:., [], [:foo, :bar]},\n               1,\n               2,\n               3,\n               {{:., [], [:foo, :bar]}, [], [1, 2, 3]}\n             ]\n\n    assert postwalk({[1, 2, 3], [4, 5, 6]}) ==\n             [1, 2, 3, [1, 2, 3], 4, 5, 6, [4, 5, 6], {[1, 2, 3], [4, 5, 6]}]\n  end\n\n  test \"generate_arguments/2\" do\n    assert Macro.generate_arguments(0, __MODULE__) == []\n    assert Macro.generate_arguments(1, __MODULE__) == [{:arg1, [], __MODULE__}]\n    assert Macro.generate_arguments(4, __MODULE__) |> length() == 4\n  end\n\n  defp postwalk(ast) do\n    Macro.postwalk(ast, [], &{&1, [&1 | &2]}) |> elem(1) |> Enum.reverse()\n  end\n\n  test \"struct_info!/2 expands structs multiple levels deep\" do\n    defmodule StructBang do\n      @enforce_keys [:b]\n      defstruct [:a, :b]\n\n      assert Macro.struct_info!(StructBang, __ENV__) == [\n               %{field: :a, default: nil, required: false},\n               %{field: :b, default: nil, required: true}\n             ]\n\n      def within_function do\n        assert Macro.struct_info!(StructBang, __ENV__) == [\n                 %{field: :a, default: nil, required: false},\n                 %{field: :b, default: nil, required: true}\n               ]\n      end\n\n      defmodule Nested do\n        assert Macro.struct_info!(StructBang, __ENV__) == [\n                 %{field: :a, default: nil, required: false},\n                 %{field: :b, default: nil, required: true}\n               ]\n      end\n    end\n\n    assert Macro.struct_info!(StructBang, __ENV__) == [\n             %{field: :a, default: nil, required: false},\n             %{field: :b, default: nil, required: true}\n           ]\n  end\n\n  test \"prewalker/1\" do\n    ast = quote do: :mod.foo(bar({1, 2}), [3, 4, five])\n    map = Enum.map(Macro.prewalker(ast), & &1)\n\n    assert map == [\n             {{:., [], [:mod, :foo]}, [], [{:bar, [], [{1, 2}]}, [3, 4, {:five, [], MacroTest}]]},\n             {:., [], [:mod, :foo]},\n             :mod,\n             :foo,\n             {:bar, [], [{1, 2}]},\n             {1, 2},\n             1,\n             2,\n             [3, 4, {:five, [], MacroTest}],\n             3,\n             4,\n             {:five, [], MacroTest}\n           ]\n\n    assert map == ast |> Macro.prewalk([], &{&1, [&1 | &2]}) |> elem(1) |> Enum.reverse()\n    assert Enum.zip(Macro.prewalker(ast), []) == Enum.zip(map, [])\n\n    for i <- 0..(length(map) + 1) do\n      assert Enum.take(Macro.prewalker(ast), i) == Enum.take(map, i)\n    end\n  end\n\n  test \"postwalker/1\" do\n    ast = quote do: :mod.foo(bar({1, 2}), [3, 4, five])\n    map = Enum.map(Macro.postwalker(ast), & &1)\n\n    assert map == [\n             :mod,\n             :foo,\n             {:., [], [:mod, :foo]},\n             1,\n             2,\n             {1, 2},\n             {:bar, [], [{1, 2}]},\n             3,\n             4,\n             {:five, [], MacroTest},\n             [3, 4, {:five, [], MacroTest}],\n             {{:., [], [:mod, :foo]}, [], [{:bar, [], [{1, 2}]}, [3, 4, {:five, [], MacroTest}]]}\n           ]\n\n    assert map == ast |> Macro.postwalk([], &{&1, [&1 | &2]}) |> elem(1) |> Enum.reverse()\n    assert Enum.zip(Macro.postwalker(ast), []) == Enum.zip(map, [])\n\n    for i <- 0..(length(map) + 1) do\n      assert Enum.take(Macro.postwalker(ast), i) == Enum.take(map, i)\n    end\n  end\n\n  test \"operator?/2\" do\n    assert Macro.operator?(:+, 2)\n    assert Macro.operator?(:+, 1)\n    refute Macro.operator?(:+, 0)\n  end\n\n  test \"quoted_literal?/1\" do\n    assert Macro.quoted_literal?(quote(do: \"foo\"))\n    assert Macro.quoted_literal?(quote(do: {\"foo\", 1}))\n    assert Macro.quoted_literal?(quote(do: %{foo: \"bar\"}))\n    assert Macro.quoted_literal?(quote(do: %URI{path: \"/\"}))\n    assert Macro.quoted_literal?(quote(do: <<>>))\n    assert Macro.quoted_literal?(quote(do: <<1, \"foo\", \"bar\"::utf16>>))\n    assert Macro.quoted_literal?(quote(do: <<1000::size(8)-unit(4)>>))\n    assert Macro.quoted_literal?(quote(do: <<1000::8*4>>))\n    assert Macro.quoted_literal?(quote(do: <<102::unsigned-big-integer-size(8)>>))\n    refute Macro.quoted_literal?(quote(do: {\"foo\", var}))\n    refute Macro.quoted_literal?(quote(do: <<\"foo\"::size(name_size)>>))\n    refute Macro.quoted_literal?(quote(do: <<\"foo\"::binary-size(name_size)>>))\n    refute Macro.quoted_literal?(quote(do: <<\"foo\"::custom_modifier()>>))\n    refute Macro.quoted_literal?(quote(do: <<102, rest::binary>>))\n  end\n\n  test \"underscore/1\" do\n    assert Macro.underscore(\"foo\") == \"foo\"\n    assert Macro.underscore(\"foo_bar\") == \"foo_bar\"\n    assert Macro.underscore(\"Foo\") == \"foo\"\n    assert Macro.underscore(\"FooBar\") == \"foo_bar\"\n    assert Macro.underscore(\"FOOBar\") == \"foo_bar\"\n    assert Macro.underscore(\"FooBAR\") == \"foo_bar\"\n    assert Macro.underscore(\"FOO_BAR\") == \"foo_bar\"\n    assert Macro.underscore(\"FoBaZa\") == \"fo_ba_za\"\n    assert Macro.underscore(\"Foo10\") == \"foo10\"\n    assert Macro.underscore(\"FOO10\") == \"foo10\"\n    assert Macro.underscore(\"10Foo\") == \"10_foo\"\n    assert Macro.underscore(\"FooBar10\") == \"foo_bar10\"\n    assert Macro.underscore(\"FooBAR10\") == \"foo_bar10\"\n    assert Macro.underscore(\"Foo10Bar\") == \"foo10_bar\"\n    assert Macro.underscore(\"Foo.Bar\") == \"foo/bar\"\n    assert Macro.underscore(Foo.Bar) == \"foo/bar\"\n    assert Macro.underscore(\"API.V1.User\") == \"api/v1/user\"\n    assert Macro.underscore(\"\") == \"\"\n  end\n\n  test \"camelize/1\" do\n    assert Macro.camelize(\"Foo\") == \"Foo\"\n    assert Macro.camelize(\"FooBar\") == \"FooBar\"\n    assert Macro.camelize(\"foo\") == \"Foo\"\n    assert Macro.camelize(\"foo_bar\") == \"FooBar\"\n    assert Macro.camelize(\"foo_\") == \"Foo\"\n    assert Macro.camelize(\"_foo\") == \"Foo\"\n    assert Macro.camelize(\"foo10\") == \"Foo10\"\n    assert Macro.camelize(\"_10foo\") == \"10foo\"\n    assert Macro.camelize(\"foo_10\") == \"Foo10\"\n    assert Macro.camelize(\"foo__10\") == \"Foo10\"\n    assert Macro.camelize(\"foo__bar\") == \"FooBar\"\n    assert Macro.camelize(\"foo/bar\") == \"Foo.Bar\"\n    assert Macro.camelize(\"Foo.Bar\") == \"Foo.Bar\"\n    assert Macro.camelize(\"foo1_0\") == \"Foo10\"\n    assert Macro.camelize(\"foo_123_4_567\") == \"Foo1234567\"\n    assert Macro.camelize(\"FOO_BAR\") == \"FOO_BAR\"\n    assert Macro.camelize(\"FOO.BAR\") == \"FOO.BAR\"\n    assert Macro.camelize(\"\") == \"\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/map_set_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule MapSetTest do\n  use ExUnit.Case, async: true\n\n  doctest MapSet\n\n  test \"new/1\" do\n    result = MapSet.new(1..5)\n    assert MapSet.equal?(result, Enum.into(1..5, MapSet.new()))\n  end\n\n  test \"new/2\" do\n    result = MapSet.new(1..5, &(&1 + 2))\n    assert MapSet.equal?(result, Enum.into(3..7, MapSet.new()))\n  end\n\n  test \"put/2\" do\n    result = MapSet.put(MapSet.new(), 1)\n    assert MapSet.equal?(result, MapSet.new([1]))\n\n    result = MapSet.put(MapSet.new([1, 3, 4]), 2)\n    assert MapSet.equal?(result, MapSet.new(1..4))\n\n    result = MapSet.put(MapSet.new(5..100), 10)\n    assert MapSet.equal?(result, MapSet.new(5..100))\n  end\n\n  test \"union/2\" do\n    result = MapSet.union(MapSet.new([1, 3, 4]), MapSet.new())\n    assert MapSet.equal?(result, MapSet.new([1, 3, 4]))\n\n    result = MapSet.union(MapSet.new(5..15), MapSet.new(10..25))\n    assert MapSet.equal?(result, MapSet.new(5..25))\n\n    result = MapSet.union(MapSet.new(1..120), MapSet.new(1..100))\n    assert MapSet.equal?(result, MapSet.new(1..120))\n  end\n\n  test \"intersection/2\" do\n    result = MapSet.intersection(MapSet.new(), MapSet.new(1..21))\n    assert MapSet.equal?(result, MapSet.new())\n\n    result = MapSet.intersection(MapSet.new(1..21), MapSet.new(4..24))\n    assert MapSet.equal?(result, MapSet.new(4..21))\n\n    result = MapSet.intersection(MapSet.new(2..100), MapSet.new(1..120))\n    assert MapSet.equal?(result, MapSet.new(2..100))\n  end\n\n  test \"difference/2\" do\n    result = MapSet.difference(MapSet.new(2..20), MapSet.new())\n    assert MapSet.equal?(result, MapSet.new(2..20))\n\n    result = MapSet.difference(MapSet.new(2..20), MapSet.new(1..21))\n    assert MapSet.equal?(result, MapSet.new())\n\n    result = MapSet.difference(MapSet.new(1..101), MapSet.new(2..100))\n    assert MapSet.equal?(result, MapSet.new([1, 101]))\n  end\n\n  test \"symmetric_difference/2\" do\n    result = MapSet.symmetric_difference(MapSet.new(1..5), MapSet.new(3..8))\n    assert MapSet.equal?(result, MapSet.new([1, 2, 6, 7, 8]))\n\n    result = MapSet.symmetric_difference(MapSet.new(), MapSet.new())\n    assert MapSet.equal?(result, MapSet.new())\n\n    result = MapSet.symmetric_difference(MapSet.new(1..5), MapSet.new(1..5))\n    assert MapSet.equal?(result, MapSet.new())\n\n    result = MapSet.symmetric_difference(MapSet.new([1, 2, 3]), MapSet.new())\n    assert MapSet.equal?(result, MapSet.new([1, 2, 3]))\n\n    result = MapSet.symmetric_difference(MapSet.new(), MapSet.new([1, 2, 3]))\n    assert MapSet.equal?(result, MapSet.new([1, 2, 3]))\n  end\n\n  test \"disjoint?/2\" do\n    assert MapSet.disjoint?(MapSet.new(), MapSet.new())\n    assert MapSet.disjoint?(MapSet.new(1..6), MapSet.new(8..20))\n    refute MapSet.disjoint?(MapSet.new(1..6), MapSet.new(5..15))\n    refute MapSet.disjoint?(MapSet.new(1..120), MapSet.new(1..6))\n  end\n\n  test \"subset?/2\" do\n    assert MapSet.subset?(MapSet.new(), MapSet.new())\n    assert MapSet.subset?(MapSet.new(1..6), MapSet.new(1..10))\n    assert MapSet.subset?(MapSet.new(1..6), MapSet.new(1..120))\n    refute MapSet.subset?(MapSet.new(1..120), MapSet.new(1..6))\n  end\n\n  test \"equal?/2\" do\n    assert MapSet.equal?(MapSet.new(), MapSet.new())\n    refute MapSet.equal?(MapSet.new(1..20), MapSet.new(2..21))\n    assert MapSet.equal?(MapSet.new(1..120), MapSet.new(1..120))\n  end\n\n  test \"delete/2\" do\n    result = MapSet.delete(MapSet.new(), 1)\n    assert MapSet.equal?(result, MapSet.new())\n\n    result = MapSet.delete(MapSet.new(1..4), 5)\n    assert MapSet.equal?(result, MapSet.new(1..4))\n\n    result = MapSet.delete(MapSet.new(1..4), 1)\n    assert MapSet.equal?(result, MapSet.new(2..4))\n\n    result = MapSet.delete(MapSet.new(1..4), 2)\n    assert MapSet.equal?(result, MapSet.new([1, 3, 4]))\n  end\n\n  test \"size/1\" do\n    assert MapSet.size(MapSet.new()) == 0\n    assert MapSet.size(MapSet.new(5..15)) == 11\n    assert MapSet.size(MapSet.new(2..100)) == 99\n  end\n\n  test \"to_list/1\" do\n    assert MapSet.to_list(MapSet.new()) == []\n\n    list = MapSet.to_list(MapSet.new(1..20))\n    assert Enum.sort(list) == Enum.to_list(1..20)\n\n    list = MapSet.to_list(MapSet.new(5..120))\n    assert Enum.sort(list) == Enum.to_list(5..120)\n  end\n\n  test \"filter/2\" do\n    result = MapSet.filter(MapSet.new([1, nil, 2, false]), & &1)\n    assert MapSet.equal?(result, MapSet.new(1..2))\n\n    result = MapSet.filter(MapSet.new(1..10), &(&1 < 2 or &1 > 9))\n    assert MapSet.equal?(result, MapSet.new([1, 10]))\n\n    result = MapSet.filter(MapSet.new(~w(A a B b)), fn x -> String.downcase(x) == x end)\n    assert MapSet.equal?(result, MapSet.new(~w(a b)))\n  end\n\n  test \"reject/2\" do\n    result = MapSet.reject(MapSet.new(1..10), &(&1 < 8))\n    assert MapSet.equal?(result, MapSet.new(8..10))\n\n    result = MapSet.reject(MapSet.new([\"a\", :b, 1, 1.0]), &is_integer/1)\n    assert MapSet.equal?(result, MapSet.new([\"a\", :b, 1.0]))\n\n    result = MapSet.reject(MapSet.new(1..3), fn x -> rem(x, 2) == 0 end)\n    assert MapSet.equal?(result, MapSet.new([1, 3]))\n  end\n\n  test \"split_with\" do\n    assert MapSet.split_with(MapSet.new(), fn v -> rem(v, 2) == 0 end) ==\n             {MapSet.new(), MapSet.new()}\n\n    assert MapSet.split_with(MapSet.new([1, 2, 3]), fn v -> rem(v, 2) == 0 end) ==\n             {MapSet.new([2]), MapSet.new([1, 3])}\n\n    assert MapSet.split_with(MapSet.new([2, 4, 6]), fn v -> rem(v, 2) == 0 end) ==\n             {MapSet.new([2, 4, 6]), MapSet.new([])}\n  end\n\n  test \"inspect\" do\n    assert inspect(MapSet.new([?a])) == \"MapSet.new([97])\"\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/map_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule MapTest do\n  use ExUnit.Case, async: true\n\n  doctest Map\n\n  @sample %{a: 1, b: 2}\n  defp sample, do: Process.get(:unused, %{a: 1, b: 2})\n\n  test \"maps in attributes\" do\n    assert @sample == %{a: 1, b: 2}\n  end\n\n  test \"maps when quoted\" do\n    assert quote(do: %{foo: 1}) == {:%{}, [], [{:foo, 1}]}\n  end\n\n  test \"maps keywords and atoms\" do\n    assert [%{}: :%] == [{:%{}, :%}]\n    assert [%: :%{}] == [{:%, :%{}}]\n  end\n\n  test \"maps with variables\" do\n    a = 0\n    assert %{a: a = 1, b: a} == %{a: 1, b: 0}\n    assert a == 1\n  end\n\n  test \"maps with generated variables in key\" do\n    assert %{\"#{1}\" => 1} == %{\"1\" => 1}\n    assert %{for(x <- 1..3, do: x) => 1} == %{[1, 2, 3] => 1}\n    assert %{with(x = 1, do: x) => 1} == %{1 => 1}\n    assert %{with({:ok, x} <- {:ok, 1}, do: x) => 1} == %{1 => 1}\n\n    assert %{\n             try do\n               raise \"error\"\n             rescue\n               _ -> 1\n             end => 1\n           } == %{1 => 1}\n\n    assert %{\n             try do\n               throw(1)\n             catch\n               x -> x\n             end => 1\n           } == %{1 => 1}\n\n    assert %{\n             try do\n               a = 1\n               a\n             rescue\n               _ -> 2\n             end => 1\n           } == %{1 => 1}\n\n    assert %{\n             try do\n               1\n             rescue\n               _exception -> flunk(\"should not be invoked\")\n             else\n               a -> a\n             end => 1\n           } == %{1 => 1}\n  end\n\n  test \"matching with map as a key\" do\n    assert %{%{1 => 2} => x} = %{%{1 => 2} => 3}\n    assert x == 3\n  end\n\n  test \"is_map/1\" do\n    assert is_map(Map.new())\n    refute is_map(Enum.to_list(%{}))\n  end\n\n  test \"map_size/1\" do\n    assert map_size(%{}) == 0\n    assert map_size(sample()) == 2\n  end\n\n  test \"new/1\" do\n    assert Map.new(%{a: 1, b: 2}) == %{a: 1, b: 2}\n    assert Map.new(MapSet.new(a: 1, b: 2, a: 3)) == %{b: 2, a: 3}\n  end\n\n  test \"new/2\" do\n    transformer = fn {key, value} -> {key, value * 2} end\n    assert Map.new(%{a: 1, b: 2}, transformer) == %{a: 2, b: 4}\n    assert Map.new(MapSet.new(a: 1, b: 2, a: 3), transformer) == %{b: 4, a: 6}\n  end\n\n  test \"take/2\" do\n    assert Map.take(%{a: 1, b: 2, c: 3}, [:b, :c]) == %{b: 2, c: 3}\n    assert Map.take(%{a: 1, b: 2, c: 3}, []) == %{}\n    assert_raise BadMapError, fn -> Map.take(:foo, []) end\n  end\n\n  test \"drop/2\" do\n    assert Map.drop(%{a: 1, b: 2, c: 3}, [:b, :c]) == %{a: 1}\n    assert_raise BadMapError, fn -> Map.drop(:foo, []) end\n  end\n\n  test \"split/2\" do\n    assert Map.split(%{a: 1, b: 2, c: 3}, [:b, :c]) == {%{b: 2, c: 3}, %{a: 1}}\n    assert_raise BadMapError, fn -> Map.split(:foo, []) end\n  end\n\n  test \"split_with/2\" do\n    assert Map.split_with(%{}, fn {_k, v} -> rem(v, 2) == 0 end) == {%{}, %{}}\n\n    assert Map.split_with(%{a: 1, b: 2, c: 3}, fn {_k, v} -> rem(v, 2) == 0 end) ==\n             {%{b: 2}, %{a: 1, c: 3}}\n\n    assert Map.split_with(%{a: 2, b: 4, c: 6}, fn {_k, v} -> rem(v, 2) == 0 end) ==\n             {%{a: 2, b: 4, c: 6}, %{}}\n\n    assert Map.split_with(%{1 => 1, 2 => 2, 3 => 3}, fn {k, _v} -> rem(k, 2) == 0 end) ==\n             {%{2 => 2}, %{1 => 1, 3 => 3}}\n\n    assert Map.split_with(%{1 => 2, 3 => 4, 5 => 6}, fn {k, _v} -> rem(k, 2) == 0 end) ==\n             {%{}, %{1 => 2, 3 => 4, 5 => 6}}\n  end\n\n  test \"get_and_update/3\" do\n    message = \"the given function must return a two-element tuple or :pop, got: 1\"\n\n    assert_raise RuntimeError, message, fn ->\n      Map.get_and_update(%{a: 1}, :a, fn value -> value end)\n    end\n  end\n\n  test \"get_and_update!/3\" do\n    message = \"the given function must return a two-element tuple or :pop, got: 1\"\n\n    assert_raise RuntimeError, message, fn ->\n      Map.get_and_update!(%{a: 1}, :a, fn value -> value end)\n    end\n  end\n\n  test \"maps with optional comma\" do\n    assert Code.eval_string(\"%{a: :b,}\") == {%{a: :b}, []}\n    assert Code.eval_string(\"%{1 => 2,}\") == {%{1 => 2}, []}\n    assert Code.eval_string(\"%{1 => 2, a: :b,}\") == {%{1 => 2, a: :b}, []}\n  end\n\n  test \"update maps\" do\n    assert %{sample() | a: 3} == %{a: 3, b: 2}\n\n    assert_raise KeyError, fn ->\n      %{sample() | c: 3}\n    end\n  end\n\n  test \"map dot access\" do\n    assert sample().a == 1\n\n    assert_raise KeyError, fn ->\n      sample().c\n    end\n  end\n\n  test \"put/3 optimized by the compiler\" do\n    map = %{a: 1, b: 2}\n\n    assert Map.put(map, :a, 2) == %{a: 2, b: 2}\n    assert Map.put(map, :c, 3) == %{a: 1, b: 2, c: 3}\n\n    assert Map.put(%{map | a: 2}, :a, 3) == %{a: 3, b: 2}\n    assert Map.put(%{map | a: 2}, :b, 3) == %{a: 2, b: 3}\n\n    assert Map.put(map, :a, 2) |> Map.put(:a, 3) == %{a: 3, b: 2}\n    assert Map.put(map, :a, 2) |> Map.put(:c, 3) == %{a: 2, b: 2, c: 3}\n    assert Map.put(map, :c, 3) |> Map.put(:a, 2) == %{a: 2, b: 2, c: 3}\n    assert Map.put(map, :c, 3) |> Map.put(:c, 4) == %{a: 1, b: 2, c: 4}\n  end\n\n  test \"merge/2 with map literals optimized by the compiler\" do\n    map = %{a: 1, b: 2}\n\n    assert Map.merge(map, %{a: 2}) == %{a: 2, b: 2}\n    assert Map.merge(map, %{c: 3}) == %{a: 1, b: 2, c: 3}\n    assert Map.merge(%{a: 2}, map) == %{a: 1, b: 2}\n    assert Map.merge(%{c: 3}, map) == %{a: 1, b: 2, c: 3}\n\n    assert Map.merge(%{map | a: 2}, %{a: 3}) == %{a: 3, b: 2}\n    assert Map.merge(%{map | a: 2}, %{b: 3}) == %{a: 2, b: 3}\n    assert Map.merge(%{a: 2}, %{map | a: 3}) == %{a: 3, b: 2}\n    assert Map.merge(%{a: 2}, %{map | b: 3}) == %{a: 1, b: 3}\n\n    assert Map.merge(map, %{a: 2}) |> Map.merge(%{a: 3, c: 3}) == %{a: 3, b: 2, c: 3}\n    assert Map.merge(map, %{c: 3}) |> Map.merge(%{c: 4}) == %{a: 1, b: 2, c: 4}\n    assert Map.merge(map, %{a: 3, c: 3}) |> Map.merge(%{a: 2}) == %{a: 2, b: 2, c: 3}\n  end\n\n  test \"merge/3\" do\n    # When first map is bigger\n    assert Map.merge(%{a: 1, b: 2, c: 3}, %{c: 4, d: 5}, fn :c, 3, 4 -> :x end) ==\n             %{a: 1, b: 2, c: :x, d: 5}\n\n    # When second map is bigger\n    assert Map.merge(%{b: 2, c: 3}, %{a: 1, c: 4, d: 5}, fn :c, 3, 4 -> :x end) ==\n             %{a: 1, b: 2, c: :x, d: 5}\n  end\n\n  test \"replace/3\" do\n    map = %{c: 3, b: 2, a: 1}\n    assert Map.replace(map, :b, 10) == %{c: 3, b: 10, a: 1}\n    assert Map.replace(map, :a, 1) == map\n    assert Map.replace(Process.get(:unused, map), :x, 1) == map\n  end\n\n  test \"replace!/3\" do\n    map = Process.get(:unused, %{c: 3, b: 2, a: 1})\n    assert Map.replace!(map, :b, 10) == %{c: 3, b: 10, a: 1}\n    assert Map.replace!(map, :a, 1) == map\n\n    assert_raise KeyError, ~r/key :x not found in:\\n\\n    %{.*a: 1.*}/, fn ->\n      Map.replace!(map, :x, 10)\n    end\n  end\n\n  test \"intersect/2\" do\n    map = %{a: 1, b: 2}\n\n    assert Map.intersect(map, %{a: 2}) == %{a: 2}\n    assert Map.intersect(map, %{c: 3}) == %{}\n    assert Map.intersect(%{a: 2}, map) == %{a: 1}\n    assert Map.intersect(%{c: 3}, map) == %{}\n\n    assert Map.intersect(map, %{a: 2}) |> Map.intersect(%{a: 3, c: 3}) == %{a: 3}\n    assert Map.intersect(map, %{c: 3}) |> Map.intersect(%{c: 4}) == %{}\n    assert Map.intersect(map, %{a: 3, c: 3}) |> Map.intersect(%{a: 2}) == %{a: 2}\n  end\n\n  test \"intersect/3\" do\n    # When first map is bigger\n    assert Map.intersect(%{a: 1, b: 2, c: 3}, %{c: 4, d: 5}, fn :c, 3, 4 -> :x end) ==\n             %{c: :x}\n\n    # When second map is bigger\n    assert Map.intersect(%{b: 2, c: 3}, %{a: 1, c: 4, d: 5}, fn :c, 3, 4 -> :x end) ==\n             %{c: :x}\n  end\n\n  test \"implements (almost) all functions in Keyword\" do\n    assert Keyword.__info__(:functions) -- Map.__info__(:functions) == [\n             delete: 3,\n             delete_first: 2,\n             get_values: 2,\n             keyword?: 1,\n             pop_first: 2,\n             pop_first: 3,\n             pop_values: 2,\n             validate: 2,\n             validate!: 2\n           ]\n  end\n\n  test \"variable keys\" do\n    x = :key\n    %{^x => :value} = %{x => :value}\n    assert %{x => :value} == %{key: :value}\n    assert (fn %{^x => :value} -> true end).(%{key: :value})\n\n    map = %{x => :value}\n    assert %{map | x => :new_value} == %{x => :new_value}\n  end\n\n  defmodule ExternalUser do\n    defstruct name: \"john\", age: 27\n  end\n\n  test \"structs\" do\n    assert %ExternalUser{} == %{__struct__: ExternalUser, name: \"john\", age: 27}\n    assert %ExternalUser{name: \"meg\"} == %{__struct__: ExternalUser, name: \"meg\", age: 27}\n\n    %ExternalUser{name: name} = %ExternalUser{}\n    assert name == \"john\"\n  end\n\n  describe \"structs with variable name\" do\n    test \"extracts the struct module\" do\n      %module{name: \"john\"} = %ExternalUser{name: \"john\", age: 27}\n      assert module == ExternalUser\n    end\n\n    test \"returns the struct on match\" do\n      assert Code.eval_string(\"%struct{} = %ExternalUser{}\", [], __ENV__) ==\n               {%ExternalUser{}, [struct: ExternalUser]}\n    end\n\n    test \"supports the pin operator\" do\n      module = ExternalUser\n      user = %ExternalUser{name: \"john\", age: 27}\n      %^module{name: \"john\"} = user\n    end\n\n    test \"is supported in case\" do\n      user = %ExternalUser{name: \"john\", age: 27}\n\n      case user do\n        %module{} = %{age: 27} -> assert module == ExternalUser\n      end\n    end\n\n    defp destruct1(%module{}), do: module\n    defp destruct2(%_{}), do: :ok\n\n    test \"does not match\" do\n      invalid_struct = Process.get(:unused, %{__struct__: \"foo\"})\n\n      assert_raise CaseClauseError, fn ->\n        case invalid_struct do\n          %module{} -> module\n        end\n      end\n\n      assert_raise CaseClauseError, fn ->\n        case invalid_struct do\n          %_{} -> :ok\n        end\n      end\n\n      assert_raise CaseClauseError, fn ->\n        foo = Process.get(:unused, \"foo\")\n\n        case invalid_struct do\n          %^foo{} -> :ok\n        end\n      end\n\n      assert_raise FunctionClauseError, fn ->\n        destruct1(invalid_struct)\n      end\n\n      assert_raise FunctionClauseError, fn ->\n        destruct2(invalid_struct)\n      end\n\n      assert_raise MatchError, fn ->\n        %module{} = invalid_struct\n        _ = module\n      end\n\n      assert_raise MatchError, fn ->\n        %_{} = invalid_struct\n      end\n\n      assert_raise MatchError, fn ->\n        foo = Process.get(:unused, \"foo\")\n        %^foo{} = invalid_struct\n      end\n    end\n  end\n\n  test \"structs when using dynamic modules\" do\n    defmodule Module.concat(MapTest, DynamicUser) do\n      defstruct [:name, :age]\n\n      def sample do\n        %__MODULE__{}\n      end\n    end\n  end\n\n  test \"structs when quoted\" do\n    quoted =\n      quote do\n        %User{foo: 1}\n      end\n\n    assert {:%, [], [aliases, {:%{}, [], [{:foo, 1}]}]} = quoted\n    assert aliases == {:__aliases__, [alias: false], [:User]}\n\n    quoted =\n      quote do\n        %unquote(User){foo: 1}\n      end\n\n    assert quoted == {:%, [], [User, {:%{}, [], [{:foo, 1}]}]}\n  end\n\n  test \"structs with bitstring defaults\" do\n    defmodule WithBitstring do\n      defstruct bitstring: <<255, 127::7>>\n    end\n\n    info = Macro.struct_info!(WithBitstring, __ENV__)\n    assert info == [%{default: <<255, 127::7>>, field: :bitstring, required: false}]\n  end\n\n  test \"defstruct can only be used once in a module\" do\n    message =\n      \"defstruct has already been called for TestMod, \" <>\n        \"defstruct can only be called once per module\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule TestMod do\n        defstruct [:foo]\n        defstruct [:foo]\n      end\n      \"\"\")\n    end\n  end\n\n  test \"defstruct allows keys to be enforced\" do\n    message = \"the following keys must also be given when building struct TestMod: [:foo]\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule TestMod do\n        @enforce_keys :foo\n        defstruct [:foo]\n\n        # Verify it remain set afterwards\n        :foo = @enforce_keys\n\n        def foo do\n          %TestMod{}\n        end\n      end\n      \"\"\")\n    end\n  end\n\n  test \"defstruct raises on invalid enforce_keys\" do\n    message = \"keys given to @enforce_keys must be atoms, got: \\\"foo\\\"\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule TestMod do\n        @enforce_keys \"foo\"\n        defstruct [:foo]\n      end\n      \"\"\")\n    end\n  end\n\n  test \"struct always expands context module\" do\n    Code.compiler_options(ignore_module_conflict: true)\n\n    defmodule LocalPoint do\n      defstruct x: 0\n      def new, do: %LocalPoint{}\n    end\n\n    assert LocalPoint.new() == %{__struct__: LocalPoint, x: 0}\n\n    defmodule LocalPoint do\n      defstruct x: 0, y: 0\n      def new, do: %LocalPoint{}\n    end\n\n    assert LocalPoint.new() == %{__struct__: LocalPoint, x: 0, y: 0}\n  after\n    Code.compiler_options(ignore_module_conflict: false)\n  end\n\n  defmodule LocalUser do\n    defmodule NestedUser do\n      defstruct []\n    end\n\n    defstruct name: \"john\", nested: struct(NestedUser), context: %{}\n\n    def new do\n      %LocalUser{}\n    end\n\n    defmodule Context do\n      def new do\n        %LocalUser{}\n      end\n    end\n  end\n\n  test \"local and nested structs\" do\n    assert LocalUser.new() == %LocalUser{name: \"john\", nested: %LocalUser.NestedUser{}}\n    assert LocalUser.Context.new() == %LocalUser{name: \"john\", nested: %LocalUser.NestedUser{}}\n  end\n\n  defmodule :elixir_struct_from_erlang_module do\n    defstruct [:hello]\n    def world(%:elixir_struct_from_erlang_module{} = struct), do: struct\n  end\n\n  test \"struct from erlang module\" do\n    struct = %:elixir_struct_from_erlang_module{}\n    assert :elixir_struct_from_erlang_module.world(struct) == struct\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module/types/descr_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"type_helper.exs\", __DIR__)\n\ndefmodule NoFieldsStruct do\n  defstruct []\nend\n\ndefmodule Decimal do\n  defstruct [:sign, :coef, :exp]\nend\n\ndefmodule Module.Types.DescrTest do\n  use ExUnit.Case, async: true\n\n  import Module.Types.Descr\n  defmacro domain_key(arg) when is_atom(arg), do: [arg]\n\n  defp number(), do: union(integer(), float())\n  defp empty_tuple(), do: tuple([])\n  defp tuple_of_size_at_least(n) when is_integer(n), do: open_tuple(List.duplicate(term(), n))\n  defp tuple_of_size(n) when is_integer(n) and n >= 0, do: tuple(List.duplicate(term(), n))\n  defp list(elem_type, tail_type), do: union(empty_list(), non_empty_list(elem_type, tail_type))\n  defp map_with_default(descr), do: open_map([{to_domain_keys(:term), descr}])\n\n  describe \"union\" do\n    test \"bitmap\" do\n      assert union(integer(), float()) == union(float(), integer())\n    end\n\n    test \"term\" do\n      assert union(term(), float()) == term()\n      assert union(term(), binary()) == term()\n      assert union(term(), if_set(binary())) == if_set(term())\n    end\n\n    test \"none\" do\n      assert union(none(), float()) == float()\n      assert union(none(), binary()) == binary()\n    end\n\n    test \"atom\" do\n      assert union(atom(), atom([:a])) == atom()\n      assert union(atom([:a]), atom([:b])) == atom([:a, :b])\n      assert union(atom([:a]), negation(atom([:b]))) == negation(atom([:b]))\n\n      assert union(negation(atom([:a, :b])), negation(atom([:b, :c])))\n             |> equal?(negation(atom([:b])))\n    end\n\n    test \"all primitive types\" do\n      all = [\n        atom(),\n        integer(),\n        float(),\n        bitstring(),\n        open_map(),\n        non_empty_list(term(), term()),\n        empty_list(),\n        tuple(),\n        fun(),\n        pid(),\n        port(),\n        reference()\n      ]\n\n      assert Enum.reduce(all, &union/2) |> equal?(term())\n    end\n\n    test \"dynamic\" do\n      assert equal?(union(dynamic(), dynamic()), dynamic())\n      assert equal?(union(dynamic(), term()), term())\n      assert equal?(union(term(), dynamic()), term())\n\n      assert equal?(union(dynamic(atom()), atom()), atom())\n      refute equal?(union(dynamic(atom()), atom()), dynamic(atom()))\n\n      assert equal?(union(term(), dynamic(if_set(integer()))), union(term(), dynamic(not_set())))\n      refute equal?(union(term(), dynamic(if_set(integer()))), dynamic(union(term(), not_set())))\n    end\n\n    test \"tuple\" do\n      assert equal?(union(tuple(), tuple()), tuple())\n\n      t = tuple([integer(), atom()])\n      assert equal?(union(t, t), t)\n\n      assert union(tuple([integer(), atom()]), tuple([float(), atom()]))\n             |> equal?(tuple([union(integer(), float()), atom()]))\n\n      assert union(tuple([integer(), atom()]), tuple([integer(), binary()]))\n             |> equal?(tuple([integer(), union(atom(), binary())]))\n\n      assert open_tuple([atom()])\n             |> union(tuple([atom(), integer()]))\n             |> equal?(open_tuple([atom()]))\n\n      assert tuple([union(integer(), atom())])\n             |> difference(open_tuple([atom()]))\n             |> equal?(tuple([integer()]))\n    end\n\n    test \"map\" do\n      assert equal?(union(open_map(), open_map()), open_map())\n      assert equal?(union(closed_map(a: integer()), open_map()), open_map())\n      assert equal?(union(closed_map(a: integer()), negation(closed_map(a: integer()))), term())\n\n      a_integer_open = open_map(a: integer())\n      assert equal?(union(closed_map(a: integer()), a_integer_open), a_integer_open)\n\n      # Domain key types\n      atom_to_atom = open_map([{domain_key(:atom), atom()}])\n      atom_to_integer = open_map([{domain_key(:atom), integer()}])\n\n      # Test union identity and different type maps\n      assert union(atom_to_atom, atom_to_atom) == atom_to_atom\n\n      # Test subtype relationships with domain key maps\n      refute open_map([{domain_key(:atom), union(atom(), integer())}])\n             |> subtype?(union(atom_to_atom, atom_to_integer))\n\n      assert union(atom_to_atom, atom_to_integer)\n             |> subtype?(open_map([{domain_key(:atom), union(atom(), integer())}]))\n\n      # Test unions with empty and open maps\n      assert union(empty_map(), open_map([{domain_key(:integer), atom()}]))\n             |> equal?(open_map([{domain_key(:integer), atom()}]))\n\n      assert union(open_map(), open_map([{domain_key(:integer), atom()}]))\n             |> equal?(open_map())\n\n      # Test union of open map and map with domain key\n      assert union(open_map(), open_map([{domain_key(:integer), atom()}]))\n             |> equal?(open_map())\n\n      # Ensure no duplicate, no matter the order\n      assert union(\n               open_map(a: integer()),\n               open_map(a: number(), b: binary())\n             )\n             |> union(open_map(a: integer())) ==\n               union(\n                 open_map(a: number(), b: binary()),\n                 open_map(a: integer())\n               )\n               |> union(open_map(a: integer()))\n    end\n\n    test \"list\" do\n      assert union(list(term()), list(term())) |> equal?(list(term()))\n      assert union(list(integer()), list(term())) |> equal?(list(term()))\n\n      assert union(difference(list(term()), list(integer())), list(integer()))\n             |> equal?(list(term()))\n    end\n\n    test \"fun\" do\n      assert equal?(union(fun(), fun()), fun())\n      assert equal?(union(fun(), none_fun(1)), fun())\n\n      dynamic_fun = intersection(fun(), dynamic())\n      assert equal?(union(dynamic_fun, fun()), fun())\n    end\n\n    test \"optimizations (maps)\" do\n      # The tests are checking the actual implementation, not the semantics.\n      # This is why we are using structural comparisons.\n      # It's fine to remove these if the implementation changes, but breaking\n      # these might have an important impact on compile times.\n\n      # Optimization one: same tags, all but one key are structurally equal\n      assert union(\n               open_map(a: float(), b: atom()),\n               open_map(a: integer(), b: atom())\n             )\n             |> equal?(open_map(a: union(float(), integer()), b: atom()))\n\n      assert union(\n               closed_map(a: float(), b: atom()),\n               closed_map(a: integer(), b: atom())\n             ) == closed_map(a: union(float(), integer()), b: atom())\n\n      # Optimization two: we can tell that one map is a subtype of the other:\n      assert union(\n               closed_map(a: term(), b: term()),\n               closed_map(a: float(), b: binary())\n             ) == closed_map(a: term(), b: term())\n\n      assert union(\n               open_map(a: term()),\n               closed_map(a: float(), b: binary())\n             ) == open_map(a: term())\n\n      assert union(\n               closed_map(a: float(), b: binary()),\n               open_map(a: term())\n             ) == open_map(a: term())\n\n      assert union(\n               closed_map(a: term(), b: tuple([term(), term()])),\n               closed_map(a: float(), b: tuple([atom(), binary()]))\n             ) == closed_map(a: term(), b: tuple([term(), term()]))\n    end\n\n    test \"optimizations (tuples)\" do\n      # Optimization one: same tags, all but one key are structurally equal\n      assert union(\n               open_tuple([float(), atom()]),\n               open_tuple([integer(), atom()])\n             ) == open_tuple([union(float(), integer()), atom()])\n\n      assert union(\n               tuple([float(), atom()]),\n               tuple([integer(), atom()])\n             ) == tuple([union(float(), integer()), atom()])\n\n      # Optimization two: we can tell that one tuple is a subtype of the other\n      assert union(\n               tuple([term(), term()]),\n               tuple([float(), binary()])\n             ) == tuple([term(), term()])\n\n      assert union(\n               open_tuple([term()]),\n               tuple([float(), binary()])\n             ) == open_tuple([term()])\n\n      assert union(\n               tuple([float(), binary()]),\n               open_tuple([term()])\n             ) == open_tuple([term()])\n    end\n  end\n\n  describe \"intersection\" do\n    test \"bitmap\" do\n      assert intersection(integer(), union(integer(), float())) == integer()\n      assert intersection(integer(), float()) == none()\n    end\n\n    test \"term\" do\n      assert intersection(term(), term()) == term()\n      assert intersection(term(), float()) == float()\n      assert intersection(term(), binary()) == binary()\n    end\n\n    test \"none\" do\n      assert intersection(none(), float()) == none()\n      assert intersection(none(), binary()) == none()\n    end\n\n    test \"atom\" do\n      assert intersection(atom(), atom()) == atom()\n      assert intersection(atom(), atom([:a])) == atom([:a])\n      assert intersection(atom([:a]), atom([:b])) == none()\n      assert intersection(atom([:a]), negation(atom([:b]))) == atom([:a])\n    end\n\n    test \"dynamic\" do\n      assert equal?(intersection(dynamic(), dynamic()), dynamic())\n      assert equal?(intersection(dynamic(), term()), dynamic())\n      assert equal?(intersection(term(), dynamic()), dynamic())\n      assert empty?(intersection(dynamic(), none()))\n      assert empty?(intersection(intersection(dynamic(), atom()), integer()))\n\n      assert empty?(intersection(dynamic(not_set()), term()))\n      refute empty?(intersection(dynamic(if_set(integer())), term()))\n\n      # Check for structural equivalence\n      assert intersection(dynamic(not_set()), term()) == none()\n    end\n\n    test \"tuple\" do\n      assert empty?(intersection(open_tuple([atom()]), open_tuple([integer()])))\n\n      assert intersection(open_tuple([atom()]), tuple([term(), integer()]))\n             |> equal?(tuple([atom(), integer()]))\n\n      assert intersection(tuple([term(), integer()]), tuple([atom(), term()]))\n             |> equal?(tuple([atom(), integer()]))\n    end\n\n    test \"map\" do\n      assert intersection(open_map(), open_map()) == open_map()\n      assert equal?(intersection(closed_map(a: integer()), open_map()), closed_map(a: integer()))\n\n      assert equal?(\n               intersection(closed_map(a: integer()), open_map(a: integer())),\n               closed_map(a: integer())\n             )\n\n      assert intersection(closed_map(a: integer()), open_map(b: not_set()))\n             |> equal?(closed_map(a: integer()))\n\n      assert intersection(closed_map(a: integer()), open_map(b: if_set(integer())))\n             |> equal?(closed_map(a: integer()))\n\n      assert equal?(\n               intersection(closed_map(a: integer()), closed_map(a: if_set(integer()))),\n               closed_map(a: integer())\n             )\n\n      assert empty?(intersection(closed_map(a: integer()), closed_map(a: atom())))\n\n      # Maps leaves are actually optimized, so some of the code branches\n      # can only be tested through negations. This is the intersection between\n      # open_map(a: integer()) and open_map(b: integer())\n      a_and_b =\n        negation(union(negation(open_map(a: integer())), negation(open_map(b: integer()))))\n\n      assert equal?(\n               # The additional parts we are intersecting are empty\n               intersection(\n                 union(a_and_b, closed_map(c: float())),\n                 union(a_and_b, closed_map(d: float()))\n               ),\n               a_and_b\n             )\n\n      # This is a regression triggered by an optimization\n      assert intersection(\n               closed_map(tag: atom([true]), halted: atom([true]), assigns: term()),\n               union(\n                 closed_map(tag: atom([true]), halted: atom([true]), assigns: term()),\n                 closed_map(tag: atom([true]), halted: term(), assigns: open_map())\n               )\n             )\n             |> equal?(closed_map(tag: atom([true]), halted: atom([true]), assigns: term()))\n    end\n\n    # Closed maps with not set keys should have no impact\n    test \"map closed with not set keys\" do\n      assert intersection(closed_map(a: integer()), closed_map(a: integer(), b: not_set())) ==\n               closed_map(a: integer())\n\n      assert intersection(closed_map(a: integer(), b: not_set()), closed_map(a: integer())) ==\n               closed_map(a: integer())\n\n      assert intersection(closed_map(a: integer()), closed_map(a: not_set())) ==\n               none()\n\n      assert intersection(\n               closed_map(a: integer(), b: not_set()),\n               closed_map(a: integer(), c: not_set())\n             ) ==\n               closed_map(a: integer())\n    end\n\n    test \"map with domain keys\" do\n      # %{..., int => t1, atom => t2} and %{int => t3}\n      # intersection is %{int => t1 and t3, atom => none}\n      map1 = open_map([{domain_key(:integer), integer()}, {domain_key(:atom), atom()}])\n      map2 = closed_map([{domain_key(:integer), number()}])\n\n      intersection = intersection(map1, map2)\n\n      expected =\n        closed_map([{domain_key(:integer), integer()}, {domain_key(:atom), none()}])\n\n      assert equal?(intersection, expected)\n\n      # %{..., int => t1, atom => t2} and %{int => t3, pid => t4}\n      # intersection is %{int =>t1 and t3, atom => none, pid => t4}\n      map1 = open_map([{domain_key(:integer), integer()}, {domain_key(:atom), atom()}])\n      map2 = closed_map([{domain_key(:integer), float()}, {domain_key(:pid), binary()}])\n\n      intersection = intersection(map1, map2)\n\n      expected =\n        closed_map([\n          {domain_key(:integer), intersection(integer(), float())},\n          {domain_key(:atom), none()},\n          {domain_key(:pid), binary()}\n        ])\n\n      assert equal?(intersection, expected)\n\n      # %{..., int => t1, string => t3} and %{int => t4}\n      # intersection is %{int => t1 and t4, string => none}\n      map1 = open_map([{domain_key(:integer), integer()}, {domain_key(:binary), binary()}])\n      map2 = closed_map([{domain_key(:integer), float()}])\n\n      intersection = intersection(map1, map2)\n\n      assert equal?(\n               intersection,\n               closed_map([\n                 {domain_key(:integer), intersection(integer(), float())},\n                 {domain_key(:binary), none()}\n               ])\n             )\n\n      assert subtype?(empty_map(), closed_map([{domain_key(:integer), atom()}]))\n\n      t1 = closed_map([{domain_key(:integer), atom()}])\n      t2 = closed_map([{domain_key(:integer), binary()}])\n      assert equal?(intersection(t1, t2), empty_map())\n\n      t1 = closed_map([{domain_key(:integer), atom()}])\n      t2 = closed_map([{domain_key(:atom), term()}])\n      refute empty?(intersection(t1, t2))\n      assert equal?(intersection(t1, t2), empty_map())\n    end\n\n    test \"list\" do\n      assert intersection(list(term()), list(term())) == list(term())\n      assert intersection(list(integer()), list(integer())) == list(integer())\n      assert intersection(list(integer()), list(number())) == list(integer())\n      assert intersection(list(integer()), list(atom())) == empty_list()\n\n      # Empty list intersections\n      assert intersection(empty_list(), list(term())) == empty_list()\n      assert intersection(empty_list(), list(integer())) == empty_list()\n      assert intersection(empty_list(), empty_list()) == empty_list()\n\n      # List with any type\n      assert intersection(list(term()), list(integer())) == list(integer())\n      assert intersection(list(term()), list(integer())) == list(integer())\n\n      # Intersection with more specific types\n      assert intersection(list(integer()), list(atom([:a, :b]))) == empty_list()\n\n      # Intersection with union types\n      assert intersection(list(union(integer(), atom())), list(number())) == list(integer())\n\n      # Intersection with dynamic\n      assert equal?(\n               intersection(dynamic(list(term())), list(integer())),\n               dynamic(list(integer()))\n             )\n\n      assert equal?(intersection(dynamic(list(term())), list(term())), dynamic(list(term())))\n\n      # Nested list intersections\n      assert intersection(list(list(integer())), list(list(number()))) == list(list(integer()))\n      assert intersection(list(list(integer())), list(list(atom()))) == list(empty_list())\n\n      # Intersection with non-list types\n      assert intersection(list(integer()), integer()) == none()\n\n      # Tests for list with last element\n      assert intersection(list(float(), atom()), list(number(), term())) == list(float(), atom())\n\n      assert intersection(list(number(), atom()), list(float(), boolean())) ==\n               list(float(), boolean())\n\n      assert intersection(list(integer(), float()), list(number(), integer())) == empty_list()\n\n      # Empty list with last element\n      assert intersection(empty_list(), list(integer(), atom())) == empty_list()\n      assert intersection(list(integer(), atom()), empty_list()) == empty_list()\n\n      # List with any type and specific last element\n      assert intersection(list(term(), atom()), list(float(), boolean())) ==\n               list(float(), boolean())\n\n      assert intersection(list(term(), term()), list(float(), atom())) == list(float(), atom())\n\n      # Nested lists with last element\n      assert intersection(list(list(integer()), atom()), list(list(number()), boolean())) ==\n               list(list(integer()), boolean())\n\n      assert list(list(integer(), atom()), float())\n             |> intersection(list(list(number(), boolean()), integer())) == empty_list()\n\n      # Union types in last element\n      assert intersection(list(integer(), union(atom(), binary())), list(number(), atom())) ==\n               list(integer(), atom())\n\n      # Dynamic with last element\n      assert intersection(dynamic(list(term(), atom())), list(integer(), boolean()))\n             |> equal?(dynamic(list(integer(), boolean())))\n\n      # Intersection with proper list (should result in empty list)\n      assert intersection(list(integer(), atom()), list(integer())) == empty_list()\n    end\n\n    test \"function\" do\n      assert not empty?(intersection(negation(none_fun(2)), negation(none_fun(3))))\n    end\n  end\n\n  describe \"difference\" do\n    test \"bitmap\" do\n      assert difference(float(), integer()) == float()\n      assert difference(union(float(), integer()), integer()) == float()\n      assert difference(union(float(), integer()), binary()) == union(float(), integer())\n    end\n\n    test \"term\" do\n      assert difference(float(), term()) == none()\n      assert difference(integer(), term()) == none()\n    end\n\n    test \"none\" do\n      assert difference(none(), integer()) == none()\n      assert difference(none(), float()) == none()\n\n      assert difference(integer(), none()) == integer()\n      assert difference(float(), none()) == float()\n    end\n\n    test \"atom\" do\n      assert difference(atom([:a]), atom()) == none()\n      assert difference(atom([:a]), atom([:b])) == atom([:a])\n    end\n\n    test \"dynamic\" do\n      assert equal?(dynamic(), difference(dynamic(), dynamic()))\n      assert equal?(dynamic(), difference(term(), dynamic()))\n      assert empty?(difference(dynamic(), term()))\n      assert empty?(difference(none(), dynamic()))\n      assert empty?(difference(dynamic(integer()), integer()))\n    end\n\n    test \"tuple\" do\n      assert empty?(difference(open_tuple([atom()]), open_tuple([term()])))\n      refute empty?(difference(tuple(), empty_tuple()))\n      refute tuple_of_size_at_least(2) |> difference(tuple_of_size(2)) |> empty?()\n      assert tuple_of_size_at_least(2) |> difference(tuple_of_size_at_least(1)) |> empty?()\n      assert tuple_of_size_at_least(3) |> difference(tuple_of_size_at_least(3)) |> empty?()\n      refute tuple_of_size_at_least(2) |> difference(tuple_of_size_at_least(3)) |> empty?()\n      refute tuple([term(), term()]) |> difference(tuple([atom(), term()])) |> empty?()\n      refute tuple([term(), term()]) |> difference(tuple([atom()])) |> empty?()\n      assert tuple([term(), term()]) |> difference(tuple([term(), term()])) |> empty?()\n\n      assert tuple_of_size_at_least(2)\n             |> difference(tuple_of_size(2))\n             |> difference(tuple_of_size_at_least(3))\n             |> empty?()\n\n      assert tuple([term(), term()])\n             |> difference(tuple([atom()]))\n             |> difference(open_tuple([term()]))\n             |> difference(empty_tuple())\n             |> empty?()\n\n      refute difference(tuple(), empty_tuple())\n             |> difference(open_tuple([term(), term()]))\n             |> empty?()\n\n      assert difference(open_tuple([term()]), open_tuple([term(), term()]))\n             |> difference(tuple([term()]))\n             |> empty?()\n\n      assert tuple([union(atom(), integer()), term()])\n             |> difference(open_tuple([atom(), term()]))\n             |> difference(open_tuple([integer(), term()]))\n             |> empty?()\n\n      assert tuple([union(atom(), integer()), term()])\n             |> difference(open_tuple([atom(), term()]))\n             |> equal?(tuple([integer(), term()]))\n\n      assert tuple([term(), union(atom(), integer()), term()])\n             |> difference(open_tuple([term(), integer()]))\n             |> equal?(tuple([term(), atom(), term()]))\n\n      assert difference(tuple(), open_tuple([term(), term()]))\n             |> equal?(union(tuple([term()]), tuple([])))\n    end\n\n    test \"tuple optimizations\" do\n      # We do direct assertions because we want to check how it works underneath\n      assert difference(tuple([]), tuple([atom()])) == tuple([])\n      assert difference(tuple([]), open_tuple([atom()])) == tuple([])\n      assert difference(open_tuple([atom()]), tuple([])) == open_tuple([atom()])\n      assert difference(tuple([atom([:ok])]), tuple([atom([:error])])) == tuple([atom([:ok])])\n      assert difference(tuple([atom([:ok])]), tuple([integer()])) == tuple([atom([:ok])])\n      assert difference(tuple([integer()]), tuple([atom()])) == tuple([integer()])\n    end\n\n    test \"map\" do\n      assert difference(open_map(), open_map()) == none()\n      assert difference(open_map(), term()) == none()\n      assert difference(open_map(), none()) == open_map()\n\n      assert empty?(difference(closed_map(a: integer()), open_map()))\n\n      assert difference(closed_map(a: integer(), b: if_set(atom())), closed_map(a: integer()))\n             |> difference(closed_map(a: integer(), b: atom()))\n             |> empty?()\n\n      refute empty?(difference(open_map(), empty_map()))\n\n      # Difference with single field closed map on rhs\n      assert difference(closed_map(a: integer()), closed_map(a: integer())) == none()\n\n      assert difference(open_map(a: atom()), closed_map(b: integer()))\n             |> equal?(open_map(a: atom()))\n\n      assert difference(open_map(a: integer()), closed_map(b: boolean()))\n             |> equal?(open_map(a: integer()))\n\n      # Difference with single field open map on rhs (they are optimized)\n      assert difference(closed_map(a: integer()), open_map(a: integer())) == none()\n      assert difference(closed_map(a: integer()), open_map(a: if_set(integer()))) == none()\n\n      assert difference(closed_map(a: integer()), open_map(b: integer())) ==\n               closed_map(a: integer())\n\n      assert difference(closed_map(a: integer()), open_map(b: if_set(integer()))) == none()\n    end\n\n    test \"map (struct optimizations)\" do\n      # We do direct assertions because we want to check how it works underneath\n      atom_foo = atom([:foo])\n      atom_bar = atom([:bar])\n\n      assert difference(open_map(__struct__: atom_foo), open_map(__struct__: atom_bar)) ==\n               open_map(__struct__: atom_foo)\n\n      assert difference(closed_map(__struct__: atom_foo), open_map(__struct__: atom_bar)) ==\n               closed_map(__struct__: atom_foo)\n\n      assert difference(open_map(__struct__: atom_foo), closed_map(__struct__: atom_bar)) ==\n               open_map(__struct__: atom_foo)\n\n      assert difference(closed_map(__struct__: atom_foo), closed_map(__struct__: atom_bar)) ==\n               closed_map(__struct__: atom_foo)\n\n      assert difference(closed_map(__struct__: atom_foo), closed_map(__struct__: term())) ==\n               none()\n\n      assert difference(closed_map(__struct__: atom()), closed_map(__struct__: atom_bar)) ==\n               closed_map(__struct__: difference(atom(), atom_bar))\n\n      # Explicitly assert we keep it as cascading differences\n      assert %{map: {{:closed, _}, :bdd_bot, :bdd_bot, _}} =\n               difference(\n                 difference(\n                   open_map(value: term()),\n                   closed_map(__struct__: atom_foo, value: term())\n                 ),\n                 closed_map(__struct__: atom_bar, name: term())\n               )\n    end\n\n    test \"map with domain keys\" do\n      # Non-overlapping domain keys\n      t1 = closed_map([{domain_key(:integer), atom()}])\n      t2 = closed_map([{domain_key(:atom), binary()}])\n\n      assert equal?(difference(t1, t2) |> union(empty_map()), t1)\n      assert empty?(difference(t1, t1))\n\n      # %{atom() => t1} and not %{atom() => t2} is not %{atom() => t1 and not t2}\n      t3 = closed_map([{domain_key(:integer), atom()}])\n      t4 = closed_map([{domain_key(:integer), atom([:ok])}])\n      assert subtype?(difference(t3, t4), t3)\n\n      refute difference(t3, t4)\n             |> equal?(closed_map([{domain_key(:integer), difference(atom(), atom([:ok]))}]))\n\n      # Difference with a non-domain key map\n      t5 = closed_map([{domain_key(:integer), union(atom(), integer())}])\n      t6 = closed_map(a: atom())\n      assert equal?(difference(t5, t6), t5)\n\n      # Removing atom keys from a map with defined atom keys\n      a_number = closed_map(a: number())\n      a_number_and_pids = closed_map([{:a, number()}, {domain_key(:atom), pid()}])\n      atom_to_float = closed_map([{domain_key(:atom), float()}])\n      atom_to_term = closed_map([{domain_key(:atom), term()}])\n      atom_to_pid = closed_map([{domain_key(:atom), pid()}])\n      t_diff = difference(a_number, atom_to_float)\n\n      # Removing atom keys that map to float, make the :a key point to integer only.\n      assert map_fetch_key(t_diff, :a) == {false, integer()}\n      # %{a => number, atom => pid} and not %{atom => float} gives numbers on :a\n      assert map_fetch_key(difference(a_number_and_pids, atom_to_float), :a) == {false, number()}\n\n      assert map_fetch_key(t_diff, :foo) == :badkey\n\n      assert subtype?(a_number, atom_to_term)\n      refute subtype?(a_number, atom_to_float)\n\n      # Removing all atom keys from map %{:a => type} means there is nothing left.\n      assert empty?(difference(a_number, atom_to_term))\n      refute empty?(intersection(atom_to_term, a_number))\n      assert empty?(intersection(atom_to_pid, a_number))\n\n      # (%{:a => number} and not %{:a => float}) is %{:a => integer}\n      assert equal?(difference(a_number, atom_to_float), closed_map(a: integer()))\n    end\n\n    test \"list\" do\n      # Basic list type differences\n      assert difference(list(term()), empty_list()) == non_empty_list(term())\n      assert difference(list(integer()), list(term())) |> empty?()\n\n      assert difference(list(integer()), list(float()))\n             |> equal?(non_empty_list(integer()))\n\n      # All list of integers and floats, minus all lists of integers, is NOT all lists of floats\n      refute difference(list(union(integer(), float())), list(integer()))\n             |> equal?(non_empty_list(float()))\n\n      # Interactions with empty_list()\n      assert difference(empty_list(), list(term())) == none()\n      assert difference(list(integer()), empty_list()) == non_empty_list(integer())\n\n      # Nested list structures\n      assert difference(list(list(integer())), list(list(float())))\n             |> equal?(difference(list(list(integer())), list(empty_list())))\n\n      # Lists with union types\n      refute difference(list(union(integer(), float())), list(integer())) == list(float())\n      refute difference(list(union(atom(), binary())), list(atom())) == list(binary())\n\n      # Tests for list with last element\n      assert difference(list(integer(), atom()), list(number(), term())) |> empty?()\n\n      assert difference(\n               list(atom(), term()),\n               difference(list(atom(), term()), list(atom()))\n             )\n             |> equal?(list(atom()))\n\n      assert difference(list(integer(), float()), list(number(), integer()))\n             |> equal?(non_empty_list(integer(), difference(float(), integer())))\n\n      # Empty list with last element\n      assert difference(empty_list(), list(integer(), atom())) == none()\n\n      assert difference(list(integer(), atom()), empty_list()) ==\n               non_empty_list(integer(), atom())\n\n      # List with any type and specific last element\n      assert difference(list(term(), term()), list(term(), integer()))\n             |> equal?(\n               non_empty_list(term(), negation(union(integer(), non_empty_list(term(), term()))))\n             )\n\n      # Nested lists with last element\n      # \"lists of (lists of integers), ending with atom\"\n      # minus\n      # \"lists of (lists of numbers), ending with boolean\"\n      # gives:\n      # \"non empty lists of (lists of integers), ending with (atom and not boolean)\"\n\n      assert difference(list(list(integer()), atom()), list(list(number()), boolean()))\n             |> equal?(non_empty_list(list(integer()), difference(atom(), boolean())))\n\n      # Union types in last element\n      assert difference(list(integer(), union(atom(), binary())), list(number(), atom()))\n             |> equal?(\n               union(\n                 non_empty_list(integer(), binary()),\n                 non_empty_list(difference(integer(), number()), union(atom(), binary()))\n               )\n             )\n\n      # Dynamic with last element\n      assert equal?(\n               difference(dynamic(list(term(), atom())), list(integer(), term())),\n               dynamic(difference(list(term(), atom()), list(integer(), term())))\n             )\n\n      # Difference with proper list\n      assert difference(list(integer(), atom()), list(integer()))\n             |> equal?(non_empty_list(integer(), atom()))\n    end\n\n    test \"fun\" do\n      for arity <- [0, 1, 2, 3] do\n        assert empty?(difference(none_fun(arity), none_fun(arity)))\n      end\n\n      assert empty?(difference(fun(), fun()))\n      assert empty?(difference(none_fun(3), fun()))\n      refute empty?(difference(fun(), none_fun(1)))\n      refute empty?(difference(none_fun(2), none_fun(3)))\n      assert empty?(intersection(none_fun(2), none_fun(3)))\n\n      f1f2 = union(none_fun(1), none_fun(2))\n      assert f1f2 |> difference(none_fun(1)) |> difference(none_fun(2)) |> empty?()\n      assert none_fun(1) |> difference(difference(f1f2, none_fun(2))) |> empty?()\n      assert f1f2 |> difference(none_fun(1)) |> equal?(none_fun(2))\n\n      assert fun([integer()], term()) |> difference(fun([none()], term())) |> empty?()\n    end\n  end\n\n  describe \"creation\" do\n    test \"map hoists dynamic\" do\n      assert dynamic(open_map(a: integer())) == open_map(a: dynamic(integer()))\n\n      assert dynamic(open_map(a: union(integer(), binary()))) ==\n               open_map(a: dynamic(integer()) |> union(binary()))\n\n      # For domains too\n      t1 = dynamic(open_map([{domain_key(:integer), integer()}]))\n      t2 = open_map([{domain_key(:integer), dynamic(integer())}])\n      assert t1 == t2\n\n      # if_set on dynamic fields also must work\n      t1 = dynamic(open_map(a: if_set(integer())))\n      t2 = open_map(a: if_set(dynamic(integer())))\n      assert t1 == t2\n    end\n  end\n\n  describe \"subtype\" do\n    test \"bitmap\" do\n      assert subtype?(integer(), union(integer(), float()))\n      assert subtype?(integer(), integer())\n      assert subtype?(integer(), term())\n      assert subtype?(none(), integer())\n      assert subtype?(integer(), negation(float()))\n    end\n\n    test \"atom\" do\n      assert subtype?(atom([:a]), atom())\n      assert subtype?(atom([:a]), atom([:a]))\n      assert subtype?(atom([:a]), term())\n      assert subtype?(none(), atom([:a]))\n      assert subtype?(atom([:a]), atom([:a, :b]))\n      assert subtype?(atom([:a]), negation(atom([:b])))\n    end\n\n    test \"dynamic\" do\n      assert subtype?(dynamic(), term())\n      assert subtype?(dynamic(), dynamic())\n      refute subtype?(term(), dynamic())\n      assert subtype?(intersection(dynamic(), integer()), integer())\n      assert subtype?(integer(), union(dynamic(), integer()))\n    end\n\n    test \"tuple\" do\n      assert subtype?(empty_tuple(), tuple())\n      assert subtype?(tuple([integer(), atom()]), tuple())\n      refute subtype?(empty_tuple(), open_tuple([term()]))\n      assert subtype?(tuple([integer(), atom()]), tuple([term(), term()]))\n      refute subtype?(tuple([integer(), atom()]), tuple([integer(), integer()]))\n      refute subtype?(tuple([integer(), atom()]), tuple([atom(), atom()]))\n\n      assert subtype?(tuple([integer(), atom()]), open_tuple([integer(), atom()]))\n      refute subtype?(tuple([term()]), open_tuple([term(), term()]))\n      refute subtype?(tuple([integer(), atom()]), open_tuple([integer(), integer()]))\n      refute subtype?(open_tuple([integer(), atom()]), tuple([integer(), integer()]))\n    end\n\n    test \"map\" do\n      assert subtype?(open_map(), term())\n      assert subtype?(closed_map(a: integer()), open_map())\n      assert subtype?(closed_map(a: integer()), closed_map(a: integer()))\n      assert subtype?(closed_map(a: integer()), open_map(a: integer()))\n      assert subtype?(closed_map(a: integer(), b: atom()), open_map(a: integer()))\n      assert subtype?(closed_map(a: integer()), closed_map(a: union(integer(), atom())))\n\n      # optional\n      refute subtype?(closed_map(a: if_set(integer())), closed_map(a: integer()))\n      assert subtype?(closed_map(a: integer()), closed_map(a: if_set(integer())))\n      refute subtype?(closed_map(a: if_set(term())), closed_map(a: term()))\n      assert subtype?(closed_map(a: term()), closed_map(a: if_set(term())))\n\n      # With domains\n      t1 = closed_map([{domain_key(:integer), number()}])\n      t2 = closed_map([{domain_key(:integer), integer()}])\n\n      assert subtype?(t2, t1)\n\n      t1_minus_t2 = difference(t1, t2)\n      refute empty?(t1_minus_t2)\n\n      assert subtype?(map_with_default(number()), open_map())\n      t = difference(open_map(), map_with_default(number()))\n      refute empty?(t)\n      refute subtype?(open_map(), map_with_default(number()))\n      assert subtype?(map_with_default(integer()), map_with_default(number()))\n      refute subtype?(map_with_default(float()), map_with_default(atom()))\n\n      assert equal?(\n               intersection(map_with_default(number()), map_with_default(float())),\n               map_with_default(float())\n             )\n    end\n\n    test \"optional\" do\n      refute subtype?(if_set(none()), term())\n      refute subtype?(if_set(term()), term())\n      assert subtype?(if_set(term()), if_set(term()))\n      refute subtype?(if_set(term()), if_set(dynamic(term())))\n    end\n\n    test \"list\" do\n      refute subtype?(non_empty_list(integer()), difference(list(number()), list(integer())))\n      assert subtype?(list(term(), boolean()), list(term(), atom()))\n      assert subtype?(list(integer()), list(term()))\n      assert subtype?(list(term()), list(term(), term()))\n    end\n\n    test \"fun\" do\n      assert equal?(fun([], term()), fun([], term()))\n      refute equal?(fun([], integer()), fun([], atom()))\n      refute subtype?(fun([none()], term()), fun([integer()], integer()))\n\n      # Difference with argument/return type variations\n      int_to_atom = fun([integer()], atom())\n      num_to_atom = fun([number()], atom())\n      int_to_bool = fun([integer()], boolean())\n\n      # number->atom is a subtype of int->atom\n      assert subtype?(num_to_atom, int_to_atom)\n      refute subtype?(int_to_atom, num_to_atom)\n      assert subtype?(int_to_bool, int_to_atom)\n      refute subtype?(int_to_bool, num_to_atom)\n\n      # Multi-arity\n      f1 = fun([integer(), atom()], boolean())\n      f2 = fun([number(), atom()], boolean())\n\n      # (int,atom)->boolean is a subtype of (number,atom)->boolean\n      # since number is a supertype of int\n      assert subtype?(f2, f1)\n      # f1 is not a subtype of f2\n      refute subtype?(f1, f2)\n\n      # Unary functions / Output covariance\n      assert subtype?(fun([], float()), fun([], term()))\n      refute subtype?(fun([], term()), fun([], float()))\n\n      # Contravariance of domain\n      refute subtype?(fun([integer()], boolean()), fun([number()], boolean()))\n      assert subtype?(fun([number()], boolean()), fun([integer()], boolean()))\n\n      # Nested function types\n      higher_order = fun([fun([integer()], atom())], boolean())\n      specific = fun([fun([number()], atom())], boolean())\n\n      assert subtype?(higher_order, specific)\n      refute subtype?(specific, higher_order)\n\n      ## Multi-arity\n      f = fun([none(), integer()], atom())\n      assert subtype?(f, f)\n      assert subtype?(f, fun([none(), integer()], term()))\n      assert subtype?(fun([none(), number()], atom()), f)\n      assert subtype?(fun([tuple(), number()], atom()), f)\n\n      # (none, float -> atom) is not a subtype of (none, integer -> atom)\n      # because float has an empty intersection with integer.\n      # it's only possible to find this out by doing the\n      # intersection one by one.\n      refute subtype?(fun([none(), float()], atom()), f)\n      refute subtype?(fun([pid(), float()], atom()), f)\n      # A function with the wrong arity is refused\n      refute subtype?(fun([none()], atom()), f)\n    end\n  end\n\n  describe \"compatible\" do\n    test \"intersection\" do\n      assert compatible?(integer(), intersection(dynamic(), integer()))\n      refute compatible?(intersection(dynamic(), integer()), atom())\n      refute compatible?(atom(), intersection(dynamic(), integer()))\n      refute compatible?(atom(), intersection(dynamic(), atom([:foo, :bar])))\n      assert compatible?(intersection(dynamic(), atom()), atom([:foo, :bar]))\n      assert compatible?(atom([:foo, :bar]), intersection(dynamic(), atom()))\n    end\n\n    test \"static\" do\n      refute compatible?(atom(), atom([:foo, :bar]))\n      refute compatible?(union(integer(), atom()), integer())\n      refute compatible?(none(), integer())\n      refute compatible?(union(atom(), dynamic()), integer())\n    end\n\n    test \"dynamic\" do\n      assert compatible?(dynamic(), term())\n      assert compatible?(term(), dynamic())\n      assert compatible?(dynamic(), integer())\n      assert compatible?(integer(), dynamic())\n    end\n\n    test \"tuple\" do\n      assert compatible?(dynamic(tuple()), tuple([integer(), atom()]))\n    end\n\n    test \"map\" do\n      assert compatible?(closed_map(a: integer()), open_map())\n      assert compatible?(intersection(dynamic(), open_map()), closed_map(a: integer()))\n    end\n\n    test \"list\" do\n      assert compatible?(dynamic(), list(term()))\n      assert compatible?(dynamic(list(term())), list(integer()))\n      assert compatible?(dynamic(list(term(), term())), list(integer(), integer()))\n    end\n  end\n\n  describe \"empty?\" do\n    test \"tuple\" do\n      assert tuple([none()]) |> empty?()\n      assert open_tuple([integer(), none()]) |> empty?()\n\n      assert intersection(tuple([integer(), atom()]), open_tuple([atom()])) |> empty?()\n      refute open_tuple([integer(), integer()]) |> difference(empty_tuple()) |> empty?()\n      refute open_tuple([integer(), integer()]) |> difference(open_tuple([atom()])) |> empty?()\n      refute open_tuple([term()]) |> difference(tuple([term()])) |> empty?()\n      assert difference(tuple(), empty_tuple()) |> difference(open_tuple([term()])) |> empty?()\n      assert difference(tuple(), open_tuple([term()])) |> difference(empty_tuple()) |> empty?()\n\n      refute open_tuple([term()])\n             |> difference(tuple([term()]))\n             |> difference(tuple([term()]))\n             |> empty?()\n\n      assert tuple([integer(), union(integer(), atom())])\n             |> difference(tuple([integer(), integer()]))\n             |> difference(tuple([integer(), atom()]))\n             |> empty?()\n    end\n\n    test \"map\" do\n      assert open_map(a: none()) |> empty?()\n      assert closed_map(a: integer(), b: none()) |> empty?()\n      assert intersection(closed_map(b: atom()), open_map(a: integer())) |> empty?()\n    end\n\n    test \"fun\" do\n      refute empty?(fun())\n      refute empty?(none_fun(1))\n      refute empty?(fun([integer()], atom()))\n\n      assert empty?(intersection(none_fun(1), none_fun(2)))\n      refute empty?(intersection(fun(), none_fun(1)))\n      assert empty?(difference(none_fun(1), union(none_fun(1), none_fun(2))))\n    end\n  end\n\n  describe \"function creation\" do\n    test \"fun_from_non_overlapping_clauses\" do\n      assert fun_from_non_overlapping_clauses([{[integer()], atom()}, {[float()], binary()}]) ==\n               intersection(fun([integer()], atom()), fun([float()], binary()))\n    end\n\n    test \"fun_from_inferred_clauses\" do\n      # No overlap\n      assert fun_from_inferred_clauses([{[integer()], atom()}, {[float()], binary()}])\n             |> equal?(\n               intersection(\n                 fun_from_non_overlapping_clauses([{[integer()], atom()}, {[float()], binary()}]),\n                 fun([number()], dynamic())\n               )\n             )\n\n      # Subsets\n      assert fun_from_inferred_clauses([{[integer()], atom()}, {[number()], binary()}])\n             |> equal?(\n               fun_from_non_overlapping_clauses([\n                 {[integer()], dynamic(union(atom(), binary()))},\n                 {[number()], dynamic(union(atom(), binary()))}\n               ])\n             )\n\n      assert fun_from_inferred_clauses([{[number()], binary()}, {[integer()], atom()}])\n             |> equal?(\n               fun_from_non_overlapping_clauses([\n                 {[integer()], dynamic(union(atom(), binary()))},\n                 {[number()], dynamic(union(atom(), binary()))}\n               ])\n             )\n\n      # Partial\n      assert fun_from_inferred_clauses([\n               {[union(integer(), pid())], atom()},\n               {[union(float(), pid())], binary()}\n             ])\n             |> equal?(\n               fun_from_non_overlapping_clauses([\n                 {[union(integer(), pid())], dynamic(union(atom(), binary()))},\n                 {[union(float(), pid())], dynamic(union(atom(), binary()))}\n               ])\n             )\n\n      # Difference\n      assert fun_from_inferred_clauses([\n               {[integer(), union(pid(), atom())], atom()},\n               {[number(), pid()], binary()}\n             ])\n             |> equal?(\n               fun_from_non_overlapping_clauses([\n                 {[integer(), union(pid(), atom())], dynamic(union(atom(), binary()))},\n                 {[number(), pid()], dynamic(union(atom(), binary()))}\n               ])\n             )\n    end\n  end\n\n  describe \"function application\" do\n    defp none_fun(arity), do: %{fun: {:union, %{arity => :bdd_top}}}\n\n    test \"non funs\" do\n      assert fun_apply(term(), [integer()]) == :badfun\n      assert fun_apply(integer(), [integer()]) == :badfun\n      assert fun_apply(union(integer(), none_fun(1)), [integer()]) == :badfun\n      assert fun_apply(union(integer(), fun([integer()], atom())), [integer()]) == :badfun\n      assert fun_apply(union(integer(), dynamic()), [integer()]) == :badfun\n    end\n\n    test \"static\" do\n      # Full static\n      assert fun_apply(fun(), [integer()]) == {:badarg, [none()]}\n      assert fun_apply(difference(fun(), none_fun(2)), [integer()]) == {:badarg, [none()]}\n\n      # Basic function application scenarios\n      assert fun_apply(fun([integer()], atom()), [integer()]) == {:ok, atom()}\n      assert fun_apply(fun([integer()], atom()), [float()]) == {:badarg, [integer()]}\n      assert fun_apply(fun([integer()], atom()), [term()]) == {:badarg, [integer()]}\n\n      # Union argument type: domain is int | float\n      assert fun_apply(fun([union(integer(), float())], atom()), [integer()]) == {:ok, atom()}\n      assert fun_apply(fun([union(integer(), float())], atom()), [float()]) == {:ok, atom()}\n\n      assert fun_apply(fun([union(integer(), float())], atom()), [atom()]) ==\n               {:badarg, [union(integer(), float())]}\n\n      # 2-arity function\n      assert fun_apply(fun([integer(), atom()], binary()), [integer(), atom()]) == {:ok, binary()}\n\n      assert fun_apply(fun([integer(), atom()], binary()), [boolean(), atom()]) ==\n               {:badarg, [integer(), atom()]}\n\n      # Return types\n      assert fun_apply(fun([integer()], none()), [integer()]) == {:ok, none()}\n      assert fun_apply(fun([integer()], term()), [integer()]) == {:ok, term()}\n\n      # Dynamic args\n      assert fun_apply(fun([term()], term()), [dynamic()]) == {:ok, term()}\n\n      assert fun_apply(fun([integer()], atom()), [dynamic(integer())])\n             |> elem(1)\n             |> equal?(atom())\n\n      assert fun_apply(fun([integer()], atom()), [dynamic(float())]) == {:badarg, [integer()]}\n      assert fun_apply(fun([integer()], atom()), [dynamic(term())]) == {:ok, dynamic()}\n\n      # Arity mismatches\n      assert fun_apply(fun([integer()], integer()), [term(), term()]) == {:badarity, [1]}\n      assert fun_apply(fun([integer(), atom()], boolean()), [integer()]) == {:badarity, [2]}\n\n      # Union of two different arities: always badarity regardless of which arity is called\n      fun_mixed = union(fun([integer()], integer()), fun([integer(), atom()], boolean()))\n      assert fun_apply(fun_mixed, [integer()]) == {:badarity, [1, 2]}\n      assert fun_apply(fun_mixed, [integer(), atom()]) == {:badarity, [2, 1]}\n\n      # Function intersection tests (no overlap)\n      fun0 = intersection(fun([integer()], atom()), fun([float()], binary()))\n      assert fun_apply(fun0, [integer()]) == {:ok, atom()}\n      assert fun_apply(fun0, [float()]) == {:ok, binary()}\n      assert fun_apply(fun0, [number()]) == {:ok, union(atom(), binary())}\n\n      assert fun_apply(fun0, [dynamic(integer())]) |> elem(1) |> equal?(atom())\n      assert fun_apply(fun0, [dynamic(float())]) |> elem(1) |> equal?(binary())\n      assert fun_apply(fun0, [dynamic(number())]) |> elem(1) |> equal?(union(atom(), binary()))\n      assert fun_apply(fun0, [dynamic()]) == {:ok, dynamic()}\n\n      # Function intersection tests (overlap)\n      fun1 = intersection(fun([integer()], atom()), fun([number()], term()))\n      assert fun_apply(fun1, [integer()]) == {:ok, atom()}\n      assert fun_apply(fun1, [float()]) == {:ok, term()}\n\n      # Function intersection with unions\n      fun2 =\n        intersection(\n          fun([union(integer(), atom())], term()),\n          fun([union(integer(), pid())], atom())\n        )\n\n      assert fun_apply(fun2, [integer()]) == {:ok, atom()}\n      assert fun_apply(fun2, [atom()]) == {:ok, term()}\n      assert fun_apply(fun2, [pid()]) == {:ok, atom()}\n\n      # Function intersection with same domain, different codomains\n      assert fun([integer()], term())\n             |> intersection(fun([integer()], atom()))\n             |> fun_apply([integer()]) == {:ok, atom()}\n\n      # Function intersection with singleton atoms\n      fun3 = intersection(fun([atom([:ok])], atom([:success])), fun([atom([:ok])], atom([:done])))\n      assert fun_apply(fun3, [atom([:ok])]) == {:ok, none()}\n    end\n\n    test \"static with dynamic signature\" do\n      assert fun_apply(fun([dynamic()], term()), [dynamic()]) == {:ok, term()}\n      assert fun_apply(fun([integer()], dynamic()), [integer()]) == {:ok, dynamic()}\n\n      assert fun_apply(fun([dynamic()], integer()), [dynamic()]) ==\n               {:ok, union(integer(), dynamic())}\n\n      assert fun_apply(fun([dynamic(), atom()], float()), [dynamic(), atom()]) ==\n               {:ok, union(float(), dynamic())}\n\n      fun = fun([dynamic(integer())], atom())\n      assert fun_apply(fun, [dynamic(integer())]) == {:ok, union(atom(), dynamic())}\n      assert fun_apply(fun, [dynamic(number())]) == {:ok, dynamic()}\n      assert fun_apply(fun, [integer()]) == {:ok, dynamic()}\n      assert fun_apply(fun, [float()]) == {:badarg, [dynamic(integer())]}\n    end\n\n    defp dynamic_fun(args, return), do: dynamic(fun(args, return))\n\n    test \"dynamic\" do\n      # Full dynamic\n      assert fun_apply(dynamic(), [integer()]) == {:ok, dynamic()}\n      assert fun_apply(dynamic(none_fun(1)), [integer()]) == {:ok, dynamic()}\n      assert fun_apply(difference(dynamic(), none_fun(2)), [integer()]) == {:ok, dynamic()}\n\n      # Basic function application scenarios\n      assert fun_apply(dynamic_fun([integer()], atom()), [integer()]) == {:ok, dynamic(atom())}\n      assert fun_apply(dynamic_fun([integer()], atom()), [float()]) == {:ok, dynamic()}\n      assert fun_apply(dynamic_fun([integer()], atom()), [term()]) == {:ok, dynamic()}\n      assert fun_apply(dynamic_fun([integer()], none()), [integer()]) == {:ok, dynamic(none())}\n      assert fun_apply(dynamic_fun([integer()], term()), [integer()]) == {:ok, dynamic()}\n\n      # Dynamic return and dynamic args\n      assert fun_apply(dynamic_fun([term()], term()), [dynamic()]) == {:ok, dynamic()}\n\n      fun = dynamic_fun([integer()], binary())\n      assert fun_apply(fun, [integer()]) == {:ok, dynamic(binary())}\n      assert fun_apply(fun, [dynamic(integer())]) == {:ok, dynamic(binary())}\n      assert fun_apply(fun, [dynamic(atom())]) == {:ok, dynamic()}\n\n      # Arity mismatches\n      assert fun_apply(dynamic_fun([integer()], integer()), [term(), term()]) == {:badarity, [1]}\n\n      assert fun_apply(dynamic_fun([integer(), atom()], boolean()), [integer()]) ==\n               {:badarity, [2]}\n\n      # Union of two dynamic functions with different arities: the call may succeed,\n      # so we pick the matching-arity arrows and wrap in dynamic().\n      fun_dyn_mixed =\n        union(dynamic_fun([integer()], integer()), dynamic_fun([integer(), atom()], boolean()))\n\n      # picks arity-1 arrows → dynamic(integer())\n      assert fun_apply(fun_dyn_mixed, [integer()]) == {:ok, dynamic(integer())}\n      # picks arity-2 arrows → dynamic(boolean())\n      assert fun_apply(fun_dyn_mixed, [integer(), atom()]) == {:ok, dynamic(boolean())}\n      # no matching arity → badarity (no dynamic escape here)\n      assert fun_apply(fun_dyn_mixed, [integer(), atom(), float()]) == {:badarity, [1, 2]}\n      # arg outside arity-1 domain but dynamic-compatible → dynamic()\n      assert fun_apply(fun_dyn_mixed, [atom()]) == {:ok, dynamic()}\n\n      # Function intersection tests\n      fun0 = intersection(dynamic_fun([integer()], atom()), dynamic_fun([float()], binary()))\n      assert fun_apply(fun0, [integer()]) == {:ok, dynamic(atom())}\n      assert fun_apply(fun0, [float()]) == {:ok, dynamic(binary())}\n      assert fun_apply(fun0, [dynamic(integer())]) == {:ok, dynamic(atom())}\n      assert fun_apply(fun0, [dynamic(float())]) == {:ok, dynamic(binary())}\n      assert fun_apply(fun0, [dynamic(number())]) == {:ok, dynamic(union(binary(), atom()))}\n\n      # Function intersection with subset domain\n      fun1 = intersection(dynamic_fun([integer()], atom()), dynamic_fun([number()], term()))\n      assert fun_apply(fun1, [integer()]) == {:ok, dynamic(atom())}\n      assert fun_apply(fun1, [float()]) == {:ok, dynamic()}\n      assert fun_apply(fun1, [dynamic(integer())]) == {:ok, dynamic(atom())}\n      assert fun_apply(fun1, [dynamic(float())]) == {:ok, dynamic()}\n\n      # Function intersection with same domain, different codomains\n      assert dynamic_fun([integer()], term())\n             |> intersection(dynamic_fun([integer()], atom()))\n             |> fun_apply([integer()]) == {:ok, dynamic(atom())}\n\n      # Function intersection with overlapping domains\n      fun2 =\n        intersection(\n          dynamic_fun([union(integer(), atom())], term()),\n          dynamic_fun([union(integer(), pid())], atom())\n        )\n\n      assert fun_apply(fun2, [integer()]) == {:ok, dynamic(atom())}\n      assert fun_apply(fun2, [atom()]) == {:ok, dynamic()}\n      assert fun_apply(fun2, [pid()]) |> elem(1) |> equal?(dynamic(atom()))\n\n      assert fun_apply(fun2, [dynamic(integer())]) == {:ok, dynamic(atom())}\n      assert fun_apply(fun2, [dynamic(atom())]) == {:ok, dynamic()}\n      assert fun_apply(fun2, [dynamic(pid())]) |> elem(1) |> equal?(dynamic(atom()))\n\n      # Function intersection with singleton atoms\n      fun3 =\n        intersection(\n          dynamic_fun([atom([:ok])], atom([:success])),\n          dynamic_fun([atom([:ok])], atom([:done]))\n        )\n\n      assert fun_apply(fun3, [atom([:ok])]) == {:ok, dynamic(none())}\n\n      # Testing the special case of uplifiting both the function and argument\n      # when the function is purely dynamic\n      fun4 =\n        intersection(\n          dynamic_fun([integer()], integer()),\n          dynamic_fun([boolean()], boolean())\n        )\n\n      # dynamic(int->int and bool->bool) applied to dynamic(int)\n      assert fun_apply(fun4, [dynamic(integer())]) == {:ok, dynamic(integer())}\n\n      # float escapes the domain so the result is dynamic()\n      arg = dynamic(union(integer(), float()))\n      assert fun_apply(fun4, [arg]) == {:ok, dynamic()}\n\n      assert fun_apply(dynamic(), [integer()]) == {:ok, dynamic()}\n    end\n\n    test \"static and dynamic\" do\n      # Bad arity\n      fun_arities =\n        union(\n          fun([atom()], integer()),\n          dynamic_fun([integer(), float()], binary())\n        )\n\n      assert fun_arities\n             |> fun_apply([atom()])\n             |> elem(1)\n             |> equal?(integer())\n\n      assert fun_arities |> fun_apply([integer(), float()]) == {:badarity, [1]}\n\n      # Bad argument\n      fun_args =\n        union(\n          fun([atom()], integer()),\n          dynamic_fun([integer()], binary())\n        )\n\n      assert fun_args |> fun_apply([atom()]) == {:ok, dynamic()}\n      assert fun_args |> fun_apply([integer()]) == {:badarg, [dynamic(atom())]}\n\n      # ((bool->bool) or dyn(int->int))\n      # booleans work, but not integers\n      fun_mixed_gdom = union(fun([boolean()], boolean()), dynamic_fun([integer()], integer()))\n      assert fun_apply(fun_mixed_gdom, [boolean()]) == {:ok, dynamic()}\n      assert fun_apply(fun_mixed_gdom, [dynamic(boolean())]) == {:ok, union(dynamic(), boolean())}\n      assert fun_apply(fun_mixed_gdom, [integer()]) == {:badarg, [dynamic(boolean())]}\n      assert fun_apply(fun_mixed_gdom, [dynamic(integer())]) == {:badarg, [dynamic(boolean())]}\n\n      # Badfun\n      assert union(\n               fun([atom()], integer()),\n               dynamic_fun([integer()], binary()) |> intersection(none_fun(2))\n             )\n             |> fun_apply([atom()])\n             |> elem(1)\n             |> equal?(integer())\n\n      assert union(\n               fun([atom()], integer()) |> intersection(none_fun(2)),\n               dynamic_fun([integer()], binary())\n             )\n             |> fun_apply([integer()]) == {:ok, dynamic(binary())}\n\n      # Applying (dynamic or int) -> bool to (dynamic and float).\n      # The domain is\n      #   gdom((dynamic or int) -> bool) = dom(int -> bool) or dynamic and dom(term -> bool)\n      #                                  = int or dynamic and term = int or dynamic\n\n      # The domain check dynamic and float <= int or dynamic succeeds.\n      # The static application (term -> bool) o float = bool is well-defined.\n      # The dynamic application (int -> bool) o float is not well-defined (float not <: int),\n      # but since it is dynamic it returns term wrapped in dynamic, which is dynamic.\n      # Result: bool or dynamic.\n      fun_type = fun([union(dynamic(), integer())], boolean())\n      arg = dynamic(float())\n\n      # Application yields bool or dynamic\n      assert {:ok, result} = fun_apply(fun_type, [arg])\n      assert equal?(union(boolean(), dynamic()), result)\n    end\n  end\n\n  describe \"singleton?\" do\n    test \"non-singleton?\" do\n      refute singleton?(term())\n      refute singleton?(none())\n      refute singleton?(dynamic())\n      refute singleton?(integer())\n      refute singleton?(float())\n      refute singleton?(pid())\n      refute singleton?(reference())\n      refute singleton?(fun(1))\n      refute singleton?(non_empty_list(atom([:foo])))\n    end\n\n    @disguised_empty_map closed_map(key: atom([:value]))\n                         |> difference(open_map(key: atom(), optional: if_set(atom())))\n\n    test \"atoms\" do\n      assert singleton?(atom([:foo]))\n      refute singleton?(atom([:foo, :bar]))\n      assert singleton?(atom([:foo]) |> union(@disguised_empty_map))\n      refute singleton?(atom() |> difference(atom([:foo])))\n    end\n\n    test \"empty list\" do\n      assert singleton?(empty_list())\n      refute singleton?(non_empty_list(term()))\n      refute singleton?(union(empty_list(), atom([:foo])))\n      assert singleton?(union(empty_list(), @disguised_empty_map))\n    end\n\n    test \"maps\" do\n      assert singleton?(empty_map())\n      assert singleton?(closed_map(key: atom([:value])))\n      assert singleton?(closed_map(key: atom([:value])) |> union(@disguised_empty_map))\n      refute singleton?(closed_map(key: binary()))\n      refute singleton?(closed_map(key: if_set(atom([:value]))))\n      refute singleton?(closed_map(__struct__: :term))\n      refute singleton?(open_map())\n      refute singleton?(open_map(key: atom([:value])))\n      refute singleton?(union(closed_map(key: atom([:value])), closed_map(other: atom([:value]))))\n    end\n\n    test \"tuples\" do\n      assert singleton?(tuple([]))\n      assert singleton?(tuple([atom([:foo])]))\n      refute singleton?(tuple([binary()]))\n      refute singleton?(open_tuple([]))\n      refute singleton?(union(tuple([atom([:value])]), tuple([atom([:other_value])])))\n      refute singleton?(union(tuple([atom([:value])]), closed_map(other: atom([:value]))))\n    end\n  end\n\n  describe \"projections\" do\n    test \"booleaness\" do\n      for type <- [none(), open_map(), negation(boolean()), difference(atom(), boolean())] do\n        assert booleaness(type) == :none\n        assert booleaness(dynamic(type)) == :none\n      end\n\n      for type <- [term(), dynamic(), atom(), boolean()] do\n        assert booleaness(type) == :maybe_both\n        assert booleaness(dynamic(type)) == :maybe_both\n      end\n\n      assert booleaness(atom([false])) == {false, :always}\n      assert booleaness(dynamic(atom([false]))) == {false, :always}\n      assert booleaness(dynamic(atom([false, :other]))) == {false, :maybe}\n      assert booleaness(negation(atom([false]))) == {true, :maybe}\n\n      assert booleaness(atom([true])) == {true, :always}\n      assert booleaness(dynamic(atom([true]))) == {true, :always}\n      assert booleaness(dynamic(atom([true, :other]))) == {true, :maybe}\n      assert booleaness(negation(atom([true]))) == {false, :maybe}\n    end\n\n    test \"truthiness\" do\n      for type <- [term(), none(), atom(), boolean(), union(atom([false]), integer())] do\n        assert truthiness(type) == :undefined\n        assert truthiness(dynamic(type)) == :undefined\n      end\n\n      for type <- [atom([false]), atom([nil]), atom([nil, false]), atom([false, nil])] do\n        assert truthiness(type) == :always_false\n        assert truthiness(dynamic(type)) == :always_false\n      end\n\n      for type <-\n            [negation(atom()), atom([true]), negation(atom([false, nil])), atom([:ok]), integer()] do\n        assert truthiness(type) == :always_true\n        assert truthiness(dynamic(type)) == :always_true\n      end\n    end\n\n    test \"atom_fetch\" do\n      assert atom_fetch(term()) == :error\n      assert atom_fetch(union(term(), dynamic(atom([:foo, :bar])))) == :error\n\n      assert atom_fetch(atom()) == {:infinite, []}\n      assert atom_fetch(dynamic()) == {:infinite, []}\n\n      assert atom_fetch(atom([:foo, :bar])) ==\n               {:finite, [:foo, :bar] |> :sets.from_list(version: 2) |> :sets.to_list()}\n\n      assert atom_fetch(union(atom([:foo, :bar]), dynamic(atom()))) == {:infinite, []}\n      assert atom_fetch(union(atom([:foo, :bar]), dynamic(term()))) == {:infinite, []}\n    end\n\n    test \"list_hd\" do\n      assert list_hd(none()) == :badnonemptylist\n      assert list_hd(term()) == :badnonemptylist\n      assert list_hd(list(term())) == :badnonemptylist\n      assert list_hd(empty_list()) == :badnonemptylist\n      assert list_hd(non_empty_list(term())) == {:ok, term()}\n      assert list_hd(non_empty_list(integer())) == {:ok, integer()}\n      assert list_hd(difference(list(number()), list(integer()))) == {:ok, number()}\n      assert list_hd(non_empty_list(atom(), float())) == {:ok, atom()}\n\n      assert list_hd(dynamic()) == {:ok, dynamic()}\n      assert list_hd(dynamic(list(integer()))) == {:ok, dynamic(integer())}\n      assert list_hd(union(dynamic(), atom())) == :badnonemptylist\n      assert list_hd(union(dynamic(), list(term()))) == :badnonemptylist\n\n      assert list_hd(difference(list(number()), list(number()))) == :badnonemptylist\n      assert list_hd(dynamic(difference(list(number()), list(number())))) == :badnonemptylist\n\n      assert list_hd(union(dynamic(list(float())), non_empty_list(atom()))) ==\n               {:ok, union(dynamic(float()), atom())}\n\n      # If term() is in the tail, it means list(term()) is in the tail\n      # and therefore any term can be returned from hd.\n      assert list_hd(non_empty_list(atom(), term())) == {:ok, term()}\n      assert list_hd(non_empty_list(atom(), negation(list(term(), term())))) == {:ok, atom()}\n    end\n\n    test \"list_of\" do\n      assert list_of(term()) == :badproperlist\n      assert list_of(none()) == :badproperlist\n      assert list_of(empty_list()) == {true, none()}\n      assert list_of(union(empty_list(), integer())) == :badproperlist\n      assert list_of(non_empty_list(integer())) == {false, integer()}\n      assert list_of(non_empty_list(integer(), atom())) == :badproperlist\n      assert list_of(non_empty_list(integer(), term())) == :badproperlist\n      assert list_of(non_empty_list(integer(), list(term()))) == {false, term()}\n      assert list_of(list(integer()) |> union(list(integer(), integer()))) == :badproperlist\n      assert list_of(list(integer()) |> union(integer())) == :badproperlist\n      assert list_of(dynamic(list(integer()))) == {true, dynamic(integer())}\n      assert list_of(dynamic(list(integer(), atom()))) == {true, nil}\n      assert list_of(dynamic(non_empty_list(integer(), atom()))) == :badproperlist\n      assert list_of(dynamic(union(empty_list(), integer()))) == {true, nil}\n\n      # A list that the difference resolves to nothing\n      list_with_tail =\n        non_empty_list(atom(), union(integer(), empty_list()))\n        |> difference(non_empty_list(atom([:ok]), integer()))\n        |> difference(non_empty_list(atom(), term()))\n\n      assert list_of(list_with_tail) == :badproperlist\n    end\n\n    test \"list_tl\" do\n      assert list_tl(none()) == :badnonemptylist\n      assert list_tl(term()) == :badnonemptylist\n      assert list_tl(empty_list()) == :badnonemptylist\n      assert list_tl(list(integer())) == :badnonemptylist\n      assert list_tl(difference(list(number()), list(number()))) == :badnonemptylist\n\n      assert list_tl(non_empty_list(integer())) == {:ok, list(integer())}\n\n      assert list_tl(non_empty_list(integer(), atom())) ==\n               {:ok, union(atom(), non_empty_list(integer(), atom()))}\n\n      # The tail of either a (non empty) list of integers with an atom tail or a (non empty) list\n      # of tuples with a float tail is either an atom, or a float, or a (possibly empty) list of\n      # integers with an atom tail, or a (possibly empty) list of tuples with a float tail.\n      assert list_tl(union(non_empty_list(integer(), atom()), non_empty_list(tuple(), float()))) ==\n               {:ok,\n                union(atom(), float())\n                |> union(non_empty_list(integer(), atom()))\n                |> union(non_empty_list(tuple(), float()))}\n\n      assert list_tl(dynamic()) == {:ok, dynamic()}\n      assert list_tl(dynamic(list(integer()))) == {:ok, dynamic(list(integer()))}\n\n      assert list_tl(dynamic(list(integer(), atom()))) ==\n               {:ok, dynamic(union(atom(), list(integer(), atom())))}\n    end\n\n    test \"tuple_fetch\" do\n      assert tuple_fetch(term(), 0) == :badtuple\n      assert tuple_fetch(integer(), 0) == :badtuple\n      assert tuple_fetch(tuple([none(), atom()]), 1) == :badtuple\n      assert tuple_fetch(tuple([none()]), 0) == :badtuple\n\n      assert tuple_fetch(tuple([integer(), atom()]), 0) == {false, integer()}\n      assert tuple_fetch(tuple([integer(), atom()]), 1) == {false, atom()}\n      assert tuple_fetch(tuple([integer(), atom()]), 2) == :badindex\n\n      assert tuple_fetch(open_tuple([integer(), atom()]), 0) == {false, integer()}\n      assert tuple_fetch(open_tuple([integer(), atom()]), 1) == {false, atom()}\n      assert tuple_fetch(open_tuple([integer(), atom()]), 2) == :badindex\n\n      assert tuple_fetch(tuple([integer(), atom()]), -1) == :badindex\n      assert tuple_fetch(empty_tuple(), 0) == :badindex\n      assert difference(tuple(), tuple()) |> tuple_fetch(0) == :badtuple\n\n      assert tuple([atom()]) |> difference(empty_tuple()) |> tuple_fetch(0) ==\n               {false, atom()}\n\n      assert difference(tuple([union(integer(), atom())]), open_tuple([atom()]))\n             |> tuple_fetch(0) == {false, integer()}\n\n      assert tuple_fetch(union(tuple([integer(), atom()]), dynamic(open_tuple([atom()]))), 1)\n             |> Kernel.then(fn {opt, ty} -> opt and equal?(ty, union(atom(), dynamic())) end)\n\n      assert tuple_fetch(union(tuple([integer()]), tuple([atom()])), 0) ==\n               {false, union(integer(), atom())}\n\n      assert tuple([integer(), atom(), union(atom(), integer())])\n             |> difference(tuple([integer(), term(), atom()]))\n             |> tuple_fetch(2) == {false, integer()}\n\n      assert tuple([integer(), atom(), union(union(atom(), integer()), list(term()))])\n             |> difference(tuple([integer(), term(), atom()]))\n             |> difference(open_tuple([term(), atom(), list(term())]))\n             |> tuple_fetch(2) == {false, integer()}\n\n      assert tuple([integer(), atom(), integer()])\n             |> difference(tuple([integer(), term(), integer()]))\n             |> tuple_fetch(1) == :badtuple\n\n      assert tuple([integer(), atom(), integer()])\n             |> difference(tuple([integer(), term(), atom()]))\n             |> tuple_fetch(2) == {false, integer()}\n\n      assert tuple_fetch(tuple(), 0) == :badindex\n    end\n\n    test \"tuple_fetch with dynamic\" do\n      assert tuple_fetch(dynamic(), 0) == {true, dynamic()}\n      assert tuple_fetch(dynamic(empty_tuple()), 0) == :badindex\n      assert tuple_fetch(dynamic(tuple([integer(), atom()])), 2) == :badindex\n      assert tuple_fetch(union(dynamic(), integer()), 0) == :badtuple\n\n      assert tuple_fetch(dynamic(tuple()), 0)\n             |> Kernel.then(fn {opt, type} -> opt and equal?(type, dynamic()) end)\n\n      assert tuple_fetch(union(dynamic(), open_tuple([atom()])), 0) ==\n               {true, union(atom(), dynamic())}\n    end\n\n    test \"tuple_delete_at\" do\n      assert tuple_delete_at(tuple([integer(), atom()]), 3) == :badindex\n      assert tuple_delete_at(tuple([integer(), atom()]), -1) == :badindex\n      assert tuple_delete_at(empty_tuple(), 0) == :badindex\n      assert tuple_delete_at(integer(), 0) == :badtuple\n      assert tuple_delete_at(term(), 0) == :badtuple\n      assert tuple_delete_at(tuple([none()]), 0) == :badtuple\n\n      # Test deleting an element from a closed tuple\n      assert tuple_delete_at(tuple([integer(), atom(), boolean()]), 1) ==\n               tuple([integer(), boolean()])\n\n      # Test deleting the last element from a closed tuple\n      assert tuple_delete_at(tuple([integer(), atom()]), 1) ==\n               tuple([integer()])\n\n      # Test deleting from an open tuple\n      assert tuple_delete_at(open_tuple([integer(), atom(), boolean()]), 1) ==\n               open_tuple([integer(), boolean()])\n\n      # Test deleting from a dynamic tuple\n      assert tuple_delete_at(dynamic(tuple([integer(), atom()])), 1) ==\n               dynamic(tuple([integer()]))\n\n      # Test deleting from a union of tuples\n      assert tuple_delete_at(union(tuple([integer(), atom()]), tuple([float(), binary()])), 1)\n             |> equal?(tuple([union(integer(), float())]))\n\n      # Test deleting from an intersection of tuples\n      assert intersection(tuple([integer(), atom()]), tuple([term(), boolean()]))\n             |> tuple_delete_at(1) == tuple([integer()])\n\n      # Test deleting from a difference of tuples\n      assert difference(tuple([integer(), atom(), boolean()]), tuple([term(), term()]))\n             |> tuple_delete_at(1)\n             |> equal?(tuple([integer(), boolean()]))\n\n      # Test deleting from a complex union involving dynamic\n      assert union(tuple([integer(), atom()]), dynamic(tuple([float(), binary()])))\n             |> tuple_delete_at(1)\n             |> equal?(union(tuple([integer()]), dynamic(tuple([float()]))))\n\n      # Successfully deleting at position `index` in a tuple means that the dynamic\n      # values that succeed are intersected with tuples of size at least `index`\n      assert dynamic(tuple()) |> tuple_delete_at(0) == dynamic(tuple())\n      assert dynamic(term()) |> tuple_delete_at(0) == dynamic(tuple())\n\n      assert dynamic(union(tuple(), integer()))\n             |> tuple_delete_at(1)\n             |> equal?(dynamic(tuple_of_size_at_least(1)))\n    end\n\n    test \"tuple_insert_at\" do\n      assert tuple_insert_at(tuple([integer(), atom()]), 3, boolean()) == :badindex\n      assert tuple_insert_at(tuple([integer(), atom()]), -1, boolean()) == :badindex\n      assert tuple_insert_at(integer(), 0, boolean()) == :badtuple\n      assert tuple_insert_at(term(), 0, boolean()) == :badtuple\n\n      # Out-of-bounds in a union\n      assert union(tuple([integer(), atom()]), tuple([float()]))\n             |> tuple_insert_at(2, boolean()) == :badindex\n\n      # Test inserting into a closed tuple\n      assert tuple_insert_at(tuple([integer(), atom()]), 1, boolean()) ==\n               tuple([integer(), boolean(), atom()])\n\n      # Test inserting at the beginning of a tuple\n      assert tuple_insert_at(tuple([integer(), atom()]), 0, boolean()) ==\n               tuple([boolean(), integer(), atom()])\n\n      # Test inserting at the end of a tuple\n      assert tuple_insert_at(tuple([integer(), atom()]), 2, boolean()) ==\n               tuple([integer(), atom(), boolean()])\n\n      # Test inserting into an empty tuple\n      assert tuple_insert_at(empty_tuple(), 0, integer()) == tuple([integer()])\n\n      # Test inserting into an open tuple\n      assert tuple_insert_at(open_tuple([integer(), atom()]), 1, boolean()) ==\n               open_tuple([integer(), boolean(), atom()])\n\n      # Test inserting a dynamic type\n      assert tuple_insert_at(tuple([integer(), atom()]), 1, dynamic()) ==\n               dynamic(tuple([integer(), term(), atom()]))\n\n      # Test inserting into a dynamic tuple\n      assert tuple_insert_at(dynamic(tuple([integer(), atom()])), 1, boolean()) ==\n               dynamic(tuple([integer(), boolean(), atom()]))\n\n      # Test inserting into a union of tuples\n      assert tuple_insert_at(union(tuple([integer()]), tuple([atom()])), 0, boolean()) ==\n               union(tuple([boolean(), integer()]), tuple([boolean(), atom()]))\n\n      # Test inserting into a difference of tuples\n      assert difference(tuple([integer(), atom(), boolean()]), tuple([term(), term()]))\n             |> tuple_insert_at(1, float())\n             |> equal?(tuple([integer(), float(), atom(), boolean()]))\n\n      # Test inserting into a complex union involving dynamic\n      assert union(tuple([integer(), atom()]), dynamic(tuple([float(), binary()])))\n             |> tuple_insert_at(1, boolean())\n             |> equal?(\n               union(\n                 tuple([integer(), boolean(), atom()]),\n                 dynamic(tuple([float(), boolean(), binary()]))\n               )\n             )\n\n      # If you successfully intersect at position index in a type, then the dynamic values\n      # that succeed are intersected with tuples of size at least index\n      assert dynamic(union(tuple(), integer()))\n             |> tuple_insert_at(1, boolean())\n             |> equal?(dynamic(open_tuple([term(), boolean()])))\n    end\n\n    test \"tuple_values\" do\n      assert tuple_values(integer()) == :badtuple\n      assert tuple_values(tuple([none()])) == :badtuple\n      assert tuple_values(tuple([])) == none()\n      assert tuple_values(tuple()) == term()\n      assert tuple_values(open_tuple([integer()])) == term()\n      assert tuple_values(tuple([integer(), atom()])) == union(integer(), atom())\n\n      assert tuple_values(union(tuple([float(), pid()]), tuple([reference()]))) ==\n               union(float(), union(pid(), reference()))\n\n      assert tuple_values(difference(tuple([number(), atom()]), tuple([float(), term()]))) ==\n               union(integer(), atom())\n\n      assert union(tuple([atom([:ok])]), open_tuple([integer()]))\n             |> difference(open_tuple([term(), term()]))\n             |> tuple_values() == union(atom([:ok]), integer())\n\n      assert tuple_values(difference(tuple([number(), atom()]), tuple([float(), atom([:ok])]))) ==\n               union(number(), atom())\n\n      assert tuple_values(dynamic(tuple())) == dynamic()\n      assert tuple_values(dynamic(tuple([integer()]))) == dynamic(integer())\n\n      assert tuple_values(union(dynamic(tuple([integer()])), tuple([atom()]))) ==\n               union(dynamic(integer()), atom())\n\n      assert tuple_values(union(dynamic(tuple()), integer())) == :badtuple\n      assert tuple_values(dynamic(union(integer(), tuple([atom()])))) == dynamic(atom())\n\n      assert tuple_values(union(dynamic(tuple([integer()])), tuple([integer()])))\n             |> equal?(integer())\n    end\n\n    test \"map_to_list\" do\n      assert map_to_list(:term) == :badmap\n      assert map_to_list(integer()) == :badmap\n      assert map_to_list(union(open_map(), integer())) == :badmap\n      assert map_to_list(none()) == :badmap\n      assert map_to_list(dynamic()) == {:ok, dynamic(list(tuple([term(), term()])))}\n\n      # A non existent map type is refused\n      assert open_map()\n             |> difference(open_map(a: if_set(term()), c: if_set(term())))\n             |> map_to_list() == :badmap\n\n      assert map_to_list(empty_map()) == {:ok, empty_list()}\n      assert map_to_list(open_map()) == {:ok, list(tuple([term(), term()]))}\n\n      assert map_to_list(closed_map(a: integer())) ==\n               {:ok, non_empty_list(tuple([atom([:a]), integer()]))}\n\n      assert map_to_list(closed_map(a: term())) ==\n               {:ok, non_empty_list(tuple([atom([:a]), term()]))}\n\n      assert map_to_list(closed_map(a: integer(), b: atom())) ==\n               {:ok,\n                non_empty_list(\n                  tuple([atom([:a]), integer()])\n                  |> union(tuple([atom([:b]), atom()]))\n                )}\n\n      assert map_to_list(union(closed_map(a: float()), closed_map(b: pid()))) ==\n               {:ok,\n                non_empty_list(\n                  tuple([atom([:a]), float()])\n                  |> union(tuple([atom([:b]), pid()]))\n                )}\n\n      # Test with struct-like descrs\n      assert map_to_list(closed_map(__struct__: term())) ==\n               {:ok, non_empty_list(tuple([atom([:__struct__]), term()]))}\n\n      # Test with domain keys\n      assert map_to_list(closed_map([{domain_key(:integer), binary()}])) ==\n               {:ok, list(tuple([integer(), binary()]))}\n\n      assert map_to_list(closed_map([{domain_key(:tuple), binary()}])) ==\n               {:ok, list(tuple([tuple(), binary()]))}\n\n      # Test with both atom keys and domain keys\n      map_with_both =\n        closed_map([\n          {:a, atom([:ok])},\n          {:b, float()},\n          {domain_key(:integer), binary()},\n          {domain_key(:tuple), pid()}\n        ])\n\n      assert map_to_list(map_with_both) ==\n               {:ok,\n                non_empty_list(\n                  tuple([atom([:a]), atom([:ok])])\n                  |> union(tuple([atom([:b]), float()]))\n                  |> union(tuple([integer(), binary()]))\n                  |> union(tuple([tuple(), pid()]))\n                )}\n\n      # Test open maps - should return list of key-value tuples\n      assert map_to_list(open_map()) == {:ok, list(tuple([term(), term()]))}\n      assert map_to_list(open_map(a: integer())) == {:ok, non_empty_list(tuple([term(), term()]))}\n\n      {:ok, list} = map_to_list(open_map([{domain_key(:integer), binary()}]))\n\n      assert list(\n               Enum.reduce(\n                 [binary(), float(), pid(), port(), reference()] ++\n                   [fun(), atom(), tuple(), open_map(), list(term(), term())],\n                 tuple([integer(), binary()]),\n                 fn domain, acc -> union(acc, tuple([domain, term()])) end\n               )\n             )\n             |> equal?(list)\n\n      # Test with multiple domain keys\n      multiple_domains =\n        closed_map([\n          {domain_key(:integer), atom([:int])},\n          {domain_key(:float), atom([:float])},\n          {domain_key(:atom), binary()},\n          {domain_key(:binary), integer()},\n          {domain_key(:tuple), float()}\n        ])\n\n      assert map_to_list(multiple_domains) ==\n               {:ok,\n                list(\n                  tuple([integer(), atom([:int])])\n                  |> union(tuple([float(), atom([:float])]))\n                  |> union(tuple([atom(), binary()]))\n                  |> union(tuple([binary(), integer()]))\n                  |> union(tuple([tuple(), float()]))\n                )}\n\n      # Test dynamic maps\n      assert map_to_list(dynamic(open_map())) ==\n               {:ok, dynamic(list(tuple([term(), term()])))}\n\n      assert map_to_list(dynamic(closed_map(a: integer()))) ==\n               {:ok, dynamic(non_empty_list(tuple([atom([:a]), integer()])))}\n\n      assert map_to_list(union(dynamic(closed_map(a: integer())), closed_map(b: atom()))) ==\n               {:ok,\n                union(\n                  non_empty_list(tuple([atom([:b]), atom()])),\n                  dynamic(\n                    non_empty_list(\n                      union(\n                        tuple([atom([:a]), integer()]),\n                        tuple([atom([:b]), atom()])\n                      )\n                    )\n                  )\n                )}\n\n      # A static integer is refused\n      assert map_to_list(union(dynamic(open_map()), integer())) == :badmap\n\n      # Test with negations\n      assert map_to_list(\n               difference(closed_map(a: integer(), b: atom()), closed_map(a: integer()))\n             ) ==\n               {:ok,\n                non_empty_list(\n                  tuple([atom([:a]), integer()])\n                  |> union(tuple([atom([:b]), atom()]))\n                )}\n\n      # If a key is removed entirely by a negation, it should not appear in the result\n      assert closed_map(a: if_set(integer()), b: atom())\n             |> difference(closed_map(a: integer(), b: term()))\n             |> map_to_list() ==\n               {:ok, non_empty_list(tuple([atom([:b]), atom()]))}\n    end\n\n    test \"domain_to_args\" do\n      # take complex tuples, normalize them, and check if they are still equal\n      complex_tuples = [\n        tuple([term(), atom(), number()])\n        |> difference(tuple([atom(), atom(), float()])),\n        # overlapping union and difference producing multiple variants\n        difference(\n          tuple([union(atom(), pid()), union(integer(), float())]),\n          tuple([union(atom(), pid()), float()])\n        )\n      ]\n\n      Enum.each(complex_tuples, fn domain ->\n        args = domain_to_args(domain)\n\n        assert Enum.reduce(args, none(), &union(args_to_domain(&1), &2))\n               |> equal?(domain)\n      end)\n    end\n\n    test \"map_fetch_key\" do\n      assert map_fetch_key(term(), :a) == :badmap\n      assert map_fetch_key(union(open_map(), integer()), :a) == :badmap\n      assert map_fetch_key(difference(open_map(), open_map()), :a) == :badmap\n\n      assert map_fetch_key(difference(closed_map(a: integer()), closed_map(a: term())), :a) ==\n               :badmap\n\n      assert map_fetch_key(open_map(), :a) == :badkey\n      assert map_fetch_key(open_map(a: not_set()), :a) == :badkey\n      assert map_fetch_key(union(closed_map(a: integer()), closed_map(b: atom())), :a) == :badkey\n\n      assert map_fetch_key(closed_map(a: integer()), :a) == {false, integer()}\n\n      assert map_fetch_key(union(closed_map(a: integer()), closed_map(a: atom())), :a) ==\n               {false, union(integer(), atom())}\n\n      {false, value_type} =\n        open_map(my_map: open_map(foo: integer()))\n        |> intersection(open_map(my_map: open_map(bar: boolean())))\n        |> map_fetch_key(:my_map)\n\n      assert equal?(value_type, open_map(foo: integer(), bar: boolean()))\n\n      {false, value_type} =\n        closed_map(a: union(integer(), atom()))\n        |> difference(open_map(a: integer()))\n        |> map_fetch_key(:a)\n\n      assert equal?(value_type, atom())\n\n      {false, value_type} =\n        closed_map(a: integer(), b: atom())\n        |> difference(closed_map(a: integer(), b: atom([:foo])))\n        |> map_fetch_key(:a)\n\n      assert equal?(value_type, integer())\n\n      {false, value_type} =\n        closed_map(a: integer())\n        |> difference(closed_map(a: atom()))\n        |> map_fetch_key(:a)\n\n      assert equal?(value_type, integer())\n\n      {false, value_type} =\n        open_map(a: integer(), b: atom())\n        |> union(closed_map(a: tuple()))\n        |> map_fetch_key(:a)\n\n      assert equal?(value_type, union(integer(), tuple()))\n\n      {false, value_type} =\n        closed_map(a: atom())\n        |> difference(closed_map(a: atom([:foo, :bar])))\n        |> difference(closed_map(a: atom([:bar])))\n        |> map_fetch_key(:a)\n\n      assert equal?(value_type, intersection(atom(), negation(atom([:foo, :bar]))))\n\n      assert closed_map(a: union(atom([:ok]), pid()), b: integer(), c: tuple())\n             |> difference(open_map(a: atom([:ok]), b: integer()))\n             |> difference(open_map(a: atom(), c: tuple()))\n             |> map_fetch_key(:a) == {false, pid()}\n\n      assert closed_map(a: union(atom([:foo]), pid()), b: integer(), c: tuple())\n             |> difference(open_map(a: atom([:foo]), b: integer()))\n             |> difference(open_map(a: atom(), c: tuple()))\n             |> map_fetch_key(:a) == {false, pid()}\n\n      assert closed_map(a: union(atom([:foo, :bar, :baz]), integer()))\n             |> difference(open_map(a: atom([:foo, :bar])))\n             |> difference(open_map(a: atom([:foo, :baz])))\n             |> map_fetch_key(:a) == {false, integer()}\n    end\n\n    test \"map_fetch_key with dynamic\" do\n      assert map_fetch_key(dynamic(), :a) == {true, dynamic()}\n      assert map_fetch_key(union(dynamic(), integer()), :a) == :badmap\n      assert map_fetch_key(union(dynamic(open_map(a: integer())), integer()), :a) == :badmap\n      assert map_fetch_key(union(dynamic(integer()), integer()), :a) == :badmap\n\n      assert intersection(dynamic(), open_map(a: integer()))\n             |> map_fetch_key(:a) == {false, intersection(integer(), dynamic())}\n\n      {false, type} = union(dynamic(integer()), open_map(a: integer())) |> map_fetch_key(:a)\n      assert equal?(type, integer())\n\n      assert union(dynamic(integer()), open_map(a: if_set(integer()))) |> map_fetch_key(:a) ==\n               :badkey\n\n      assert union(dynamic(open_map(a: atom())), open_map(a: integer()))\n             |> map_fetch_key(:a) == {false, union(dynamic(atom()), integer())}\n    end\n\n    test \"map_fetch_key with domain keys\" do\n      integer_to_atom = open_map([{domain_key(:integer), atom()}])\n      assert map_fetch_key(integer_to_atom, :foo) == :badkey\n\n      # the key :a is for sure of type pid and exists in type\n      # %{atom() => pid()} and not %{:a => not_set()}\n      t1 = closed_map([{domain_key(:atom), pid()}])\n      t2 = closed_map(a: not_set())\n      t3 = open_map(a: not_set())\n\n      # Indeed, t2 is equivalent to the empty map\n      assert map_fetch_key(difference(t1, t2), :a) == :badkey\n      assert map_fetch_key(difference(t1, t3), :a) == {false, pid()}\n\n      t4 = closed_map([{domain_key(:pid), atom()}])\n      assert map_fetch_key(difference(t1, t4) |> difference(t3), :a) == {false, pid()}\n\n      assert map_fetch_key(closed_map([{domain_key(:atom), pid()}]), :a) == :badkey\n\n      assert map_fetch_key(dynamic(closed_map([{domain_key(:atom), pid()}])), :a) ==\n               {true, dynamic(pid())}\n\n      assert closed_map([{domain_key(:atom), number()}])\n             |> difference(open_map(a: if_set(integer())))\n             |> map_fetch_key(:a) == {false, float()}\n\n      assert closed_map([{domain_key(:atom), number()}])\n             |> difference(closed_map(b: if_set(integer())))\n             |> map_fetch_key(:a) == :badkey\n    end\n  end\n\n  describe \"numberize\" do\n    test \"with static\" do\n      assert numberize(term()) == term()\n\n      assert open_map(list: list(integer(), atom()), tuple: tuple([float(), binary(), integer()]))\n             |> numberize() ==\n               open_map(\n                 list: list(number(), atom()),\n                 tuple: tuple([number(), binary(), number()])\n               )\n    end\n\n    test \"with dynamic\" do\n      assert numberize(dynamic()) == dynamic()\n\n      assert dynamic(list(binary(), float())) |> numberize() ==\n               dynamic(list(binary(), number()))\n    end\n  end\n\n  describe \"map_get\" do\n    test \"with domain keys\" do\n      assert map_get(term(), term()) == :badmap\n\n      map_type = closed_map([{domain_key(:tuple), binary()}])\n      assert map_get(map_type, tuple()) == {:ok, binary()}\n\n      # Type with all domain types\n      # %{:bar => :ok, integer() => :int, float() => :float, atom() => binary(), binary() => integer(), tuple() => float(), map() => pid(), reference() => port(), pid() => boolean()}\n      all_domains =\n        closed_map([\n          {:bar, atom([:ok])},\n          {domain_key(:integer), atom([:int])},\n          {domain_key(:float), atom([:float])},\n          {domain_key(:atom), binary()},\n          {domain_key(:binary), integer()},\n          {domain_key(:tuple), float()},\n          {domain_key(:map), pid()},\n          {domain_key(:reference), port()},\n          {domain_key(:pid), reference()},\n          {domain_key(:port), boolean()}\n        ])\n\n      assert map_get(all_domains, atom([:bar])) == {:ok, atom([:ok])}\n\n      assert map_get(all_domains, integer()) == {:ok, atom([:int])}\n      assert map_get(all_domains, number()) == {:ok, atom([:int, :float])}\n\n      assert map_get(all_domains, empty_list()) == :error\n      assert map_get(all_domains, atom([:foo])) == {:ok, binary()}\n      assert map_get(all_domains, binary()) == {:ok, integer()}\n      assert map_get(all_domains, tuple([integer(), atom()])) == {:ok, float()}\n      assert map_get(all_domains, empty_map()) == {:ok, pid()}\n\n      # Union\n      assert map_get(all_domains, union(tuple(), empty_map())) ==\n               {:ok, union(float(), pid())}\n\n      # Removing all maps with tuple keys\n      t_no_tuple = difference(all_domains, closed_map([{domain_key(:tuple), float()}]))\n      t_really_no_tuple = difference(all_domains, open_map([{domain_key(:tuple), float()}]))\n      assert subtype?(all_domains, open_map())\n      # It's only closed maps, so it should not change\n      assert map_get(t_no_tuple, tuple()) == {:ok, float()}\n      # This time we actually removed all tuple to float keys\n      assert map_get(t_really_no_tuple, tuple()) == :error\n\n      t1 = closed_map([{domain_key(:tuple), integer()}])\n      t2 = closed_map([{domain_key(:tuple), float()}])\n      t3 = union(t1, t2)\n      assert map_get(t3, tuple()) == {:ok, number()}\n    end\n\n    test \"with dynamic\" do\n      assert map_get(dynamic(), term()) == {:ok, dynamic()}\n    end\n\n    test \"with atom fall back\" do\n      map = closed_map([{:a, atom([:a])}, {:b, atom([:b])}, {domain_key(:atom), pid()}])\n\n      assert map_get(map, atom([:a, :b])) ==\n               {:ok, atom([:a, :b])}\n\n      assert map_get(map, atom([:a, :c])) ==\n               {:ok, union(atom([:a]), pid())}\n\n      assert map_get(map, atom() |> difference(atom([:a, :b]))) ==\n               {:ok, pid()}\n\n      assert map_get(map, atom() |> difference(atom([:a]))) ==\n               {:ok, union(atom([:b]), pid())}\n\n      assert map_get(closed_map(a: atom([:a]), b: atom([:b])), atom()) ==\n               {:ok, atom([:a, :b])}\n\n      assert map_get(closed_map([{domain_key(:atom), integer()}]), atom([:a, :b])) ==\n               {:ok, integer()}\n\n      # Have one of the keys be a __struct__\n      map = closed_map([{:a, atom([:a])}, {:__struct__, term()}, {domain_key(:atom), pid()}])\n      {:ok, term} = map_get(map, atom() |> difference(atom([:a])))\n      assert equal?(term, term())\n    end\n\n    test \"with lists\" do\n      # Verify that empty_list() bitmap type maps to :list domain (not :empty_list domain)\n      map_with_list_domain = closed_map([{domain_key(:list), atom([:empty])}])\n\n      # empty_list() should access the :list domain\n      assert map_get(map_with_list_domain, empty_list()) == {:ok, atom([:empty])}\n\n      # non_empty_list() should also access the :list domain\n      assert map_get(map_with_list_domain, non_empty_list(integer())) ==\n               {:ok, atom([:empty])}\n\n      # list() should also access the :list domain\n      assert map_get(map_with_list_domain, list(integer())) ==\n               {:ok, atom([:empty])}\n\n      # If I create a map and instantiate both empty_list() and non_empty_list(integer()), it should return the union of the two types\n      map =\n        closed_map([{domain_key(:list), atom([:empty])}, {domain_key(:list), atom([:non_empty])}])\n\n      assert map_get(map, empty_list()) == {:ok, atom([:empty, :non_empty])}\n\n      assert map_get(map, non_empty_list(integer())) ==\n               {:ok, atom([:empty, :non_empty])}\n\n      assert map_get(map, list(integer())) == {:ok, atom([:empty, :non_empty])}\n    end\n  end\n\n  describe \"map_update\" do\n    test \"with static atom keys\" do\n      assert map_update(open_map(key: binary()), atom([:key]), integer()) ==\n               {binary(), open_map(key: integer()), []}\n\n      assert map_update(dynamic(open_map(key: binary())), atom([:key]), integer()) ==\n               {dynamic(binary()), dynamic(open_map(key: integer())), []}\n\n      # Optional fail for static maps\n      assert map_update(open_map(key: if_set(atom([:value]))), atom([:key]), integer()) ==\n               {:error, [badkey: :key]}\n\n      # ...unless forcing\n      assert map_update(\n               open_map(key: if_set(atom([:value]))),\n               atom([:key]),\n               integer(),\n               true,\n               true\n             ) ==\n               {atom([:value]), open_map(key: integer()), []}\n\n      # But optional does not fail for dynamic ones\n      assert map_update(dynamic(open_map(key: if_set(atom([:value])))), atom([:key]), integer()) ==\n               {dynamic(atom([:value])), dynamic(open_map(key: integer())), []}\n\n      assert map_update(dynamic(), atom([:key]), integer()) ==\n               {dynamic(), dynamic(open_map(key: integer())), []}\n\n      # Empty value fails for static maps\n      assert map_update(closed_map(key: not_set()), atom([:key]), integer()) ==\n               {:error, [badkey: :key]}\n\n      # ...unless forcing\n      assert map_update(closed_map(key: not_set()), atom([:key]), integer(), true, true) ==\n               {none(), closed_map(key: integer()), []}\n\n      # When putting multiple keys, we don't know which one will be set\n      assert map_update(open_map(key1: atom(), key2: binary()), atom([:key1, :key2]), integer()) ==\n               {union(atom(), binary()),\n                union(\n                  open_map(key1: atom(), key2: integer()),\n                  open_map(key1: integer(), key2: binary())\n                ), []}\n\n      # When putting multiple keys, all have to be set\n      assert map_update(open_map(key1: atom(), key2: binary()), atom([:key1, :key3]), integer()) ==\n               {term(),\n                union(\n                  open_map(key1: integer(), key2: binary()),\n                  open_map(key1: atom(), key2: binary(), key3: integer())\n                ), [badkey: :key3]}\n\n      # ...unless forcing\n      assert map_update(\n               open_map(key1: atom(), key2: binary()),\n               atom([:key1, :key3]),\n               integer(),\n               true,\n               true\n             ) ==\n               {term(),\n                union(\n                  open_map(key1: integer(), key2: binary()),\n                  open_map(key1: atom(), key2: binary(), key3: integer())\n                ), []}\n\n      # ...unless dynamic\n      assert map_update(dynamic(open_map()), atom([:key1, :key2]), integer()) ==\n               {dynamic(), dynamic(union(open_map(key1: integer()), open_map(key2: integer()))),\n                []}\n\n      # A \"none\" map\n      assert open_map()\n             |> difference(open_map(a: if_set(term()), c: if_set(term())))\n             |> map_update(atom([:b]), integer()) == {:error, [badkey: :b]}\n\n      # ... even when forcing\n      assert open_map()\n             |> difference(open_map(a: if_set(term()), c: if_set(term())))\n             |> map_update(atom([:b]), integer(), true, true) == {none(), none(), []}\n    end\n\n    test \"with dynamic atom keys\" do\n      assert map_update(closed_map(key: atom([:value])), dynamic(), atom([:new_value])) ==\n               {atom([:value]), closed_map(key: atom([:value, :new_value])), []}\n\n      assert map_update(dynamic(closed_map(key: atom([:value]))), dynamic(), atom([:new_value])) ==\n               {dynamic(atom([:value])), dynamic(closed_map(key: atom([:value, :new_value]))), []}\n\n      # Check struct fields\n      assert map_update(open_map(__struct__: term()), dynamic(atom()), integer()) ==\n               {term(), open_map(__struct__: term()), []}\n\n      # When precise dynamic keys are given, at least one must succeed\n      assert map_update(\n               closed_map(key1: atom(), key2: binary()),\n               dynamic(atom([:key1, :key3])),\n               integer()\n             ) ==\n               {atom(), closed_map(key1: integer(), key2: binary()), []}\n\n      assert map_update(\n               closed_map(key1: atom(), key2: binary()),\n               dynamic(atom([:key3, :key4])),\n               integer()\n             ) == {:error, []}\n\n      # ...unless forcing\n      assert map_update(\n               closed_map(key1: atom(), key2: binary()),\n               dynamic(atom([:key3, :key4])),\n               integer(),\n               true,\n               true\n             ) ==\n               {none(),\n                union(\n                  closed_map(key1: atom(), key2: binary(), key3: integer()),\n                  closed_map(key1: atom(), key2: binary(), key4: integer())\n                ), []}\n\n      # ...unless open\n      assert map_update(\n               open_map(key1: atom(), key2: binary()),\n               dynamic(atom([:key1, :key3])),\n               integer()\n             ) ==\n               {term(),\n                union(\n                  open_map(key1: integer(), key2: binary()),\n                  open_map(key1: atom(), key2: binary(), key3: integer())\n                ), []}\n\n      assert map_update(\n               open_map(key1: atom(), key2: binary()),\n               dynamic(atom([:key3, :key4])),\n               integer()\n             ) == {:error, []}\n    end\n\n    test \"with domain keys\" do\n      map =\n        closed_map([\n          {domain_key(:integer), binary()},\n          {domain_key(:pid), binary()},\n          {domain_key(:port), binary()}\n        ])\n\n      assert map_update(map, none(), integer()) ==\n               {:error, []}\n\n      assert map_update(map, integer(), integer()) ==\n               {binary(),\n                closed_map([\n                  {domain_key(:integer), union(integer(), binary())},\n                  {domain_key(:pid), binary()},\n                  {domain_key(:port), binary()}\n                ]), []}\n\n      assert map_update(map, union(pid(), integer()), integer()) ==\n               {binary(),\n                closed_map([\n                  {domain_key(:integer), union(integer(), binary())},\n                  {domain_key(:pid), union(integer(), binary())},\n                  {domain_key(:port), binary()}\n                ]), []}\n\n      assert map_update(map, union(pid(), reference()), integer()) ==\n               {binary(),\n                closed_map([\n                  {domain_key(:integer), binary()},\n                  {domain_key(:pid), union(integer(), binary())},\n                  {domain_key(:port), binary()}\n                ]), [baddomain: reference()]}\n\n      assert map_update(map, union(pid(), dynamic(union(reference(), integer()))), integer()) ==\n               {binary(),\n                closed_map([\n                  {domain_key(:integer), union(integer(), binary())},\n                  {domain_key(:pid), union(integer(), binary())},\n                  {domain_key(:port), binary()}\n                ]), []}\n\n      assert map_update(map, union(pid(), dynamic(union(reference(), binary()))), integer()) ==\n               {binary(),\n                closed_map([\n                  {domain_key(:integer), binary()},\n                  {domain_key(:pid), union(integer(), binary())},\n                  {domain_key(:port), binary()}\n                ]), []}\n\n      assert map_update(map, dynamic(union(reference(), binary())), integer()) ==\n               {:error, []}\n\n      # ... unless forcing\n      assert map_update(map, dynamic(union(reference(), binary())), integer(), true, true) ==\n               {none(),\n                closed_map([\n                  {domain_key(:integer), binary()},\n                  {domain_key(:pid), binary()},\n                  {domain_key(:port), binary()},\n                  {domain_key(:binary), integer()},\n                  {domain_key(:reference), integer()}\n                ]), []}\n\n      # Putting dynamic atom over record keys\n      assert map_update(closed_map(key1: binary(), key2: pid()), atom(), integer()) ==\n               {union(binary(), pid()),\n                union(\n                  closed_map(key1: binary(), key2: integer()),\n                  closed_map(key1: union(integer(), binary()), key2: pid())\n                ), [baddomain: atom()]}\n\n      # ... unless forcing\n      assert map_update(closed_map(key1: binary(), key2: pid()), atom(), integer(), true, true) ==\n               {union(binary(), pid()),\n                [\n                  closed_map([{domain_key(:atom), integer()}, key1: binary(), key2: pid()]),\n                  closed_map(key1: integer(), key2: pid()),\n                  closed_map(key1: binary(), key2: integer())\n                ]\n                |> Enum.reduce(&union/2), [baddomain: atom()]}\n\n      assert map_update(closed_map(key1: binary(), key2: pid()), dynamic(atom()), integer()) ==\n               {union(binary(), pid()),\n                union(\n                  closed_map(key1: binary(), key2: integer()),\n                  closed_map(key1: union(integer(), binary()), key2: pid())\n                ), []}\n\n      # A \"none()\" map\n      assert open_map()\n             |> difference(open_map(a: if_set(term()), c: if_set(term())))\n             |> map_update(binary(), integer()) == {:error, [baddomain: binary()]}\n\n      # ... even when forcing\n      {type, descr, errors} =\n        open_map()\n        |> difference(open_map(a: if_set(term()), c: if_set(term())))\n        |> map_update(binary(), integer(), true, true)\n\n      assert empty?(type)\n      assert empty?(descr)\n      assert errors == [baddomain: binary()]\n    end\n\n    test \"with mixed keys\" do\n      assert map_update(dynamic(), union(atom([:key]), binary()), integer()) ==\n               {dynamic(), dynamic(open_map()), []}\n\n      # When precise dynamic keys are given, at least one must succeed\n      assert map_update(\n               closed_map([{:key, atom()}, {domain_key(:integer), binary()}]),\n               dynamic(union(atom([:key]), integer())),\n               integer()\n             ) ==\n               {union(atom(), binary()),\n                union(\n                  closed_map([{:key, integer()}, {domain_key(:integer), binary()}]),\n                  closed_map([{:key, atom()}, {domain_key(:integer), union(binary(), integer())}])\n                ), []}\n\n      # Negated keys\n      assert map_update(\n               closed_map(key1: binary(), key2: binary()),\n               difference(atom(), atom([:key1])),\n               integer()\n             ) ==\n               {binary(), closed_map(key1: binary(), key2: union(integer(), binary())),\n                [baddomain: atom()]}\n\n      assert map_update(\n               closed_map([key1: binary(), key2: binary()] ++ [{domain_key(:atom), pid()}]),\n               difference(atom(), atom([:key1])),\n               integer()\n             ) ==\n               {union(binary(), pid()),\n                union(\n                  closed_map([{domain_key(:atom), pid()}, key1: binary(), key2: integer()]),\n                  closed_map([\n                    {domain_key(:atom), union(pid(), integer())},\n                    key1: binary(),\n                    key2: binary()\n                  ])\n                ), []}\n\n      # Missing keys\n      assert map_update(\n               closed_map([{:key, atom()}, {domain_key(:integer), binary()}]),\n               dynamic(union(atom([:other_key]), pid())),\n               integer()\n             ) == {:error, []}\n\n      # ...unless forcing\n      assert map_update(\n               closed_map([{:key, atom()}, {domain_key(:integer), binary()}]),\n               dynamic(union(atom([:other_key]), pid())),\n               integer(),\n               true,\n               true\n             ) ==\n               {none(),\n                union(\n                  closed_map([\n                    {:key, atom()},\n                    {domain_key(:integer), binary()},\n                    {domain_key(:pid), integer()}\n                  ]),\n                  closed_map([\n                    {:key, atom()},\n                    {:other_key, integer()},\n                    {domain_key(:integer), binary()}\n                  ])\n                ), []}\n\n      # Popping dynamic keys\n      non_struct_map = difference(open_map(), open_map(__struct__: atom()))\n      {type, descr, []} = map_update(non_struct_map, dynamic(), not_set(), true, true)\n      assert type == term()\n      assert equal?(descr, open_map(__struct__: if_set(negation(atom()))))\n    end\n  end\n\n  describe \"map_put\" do\n    test \"with static atom keys\" do\n      assert map_put(open_map(key: binary()), atom([:key]), integer()) ==\n               {:ok, open_map(key: integer())}\n\n      assert map_put(dynamic(open_map(key: binary())), atom([:key]), integer()) ==\n               {:ok, dynamic(open_map(key: integer()))}\n\n      # Optional does not fail on put keys\n      assert map_put(open_map(key: if_set(atom([:value]))), atom([:key]), integer()) ==\n               {:ok, open_map(key: integer())}\n\n      # But optional does not fail for dynamic ones\n      assert map_put(dynamic(open_map(key: if_set(atom([:value])))), atom([:key]), integer()) ==\n               {:ok, dynamic(open_map(key: integer()))}\n\n      assert map_put(dynamic(), atom([:key]), integer()) ==\n               {:ok, dynamic(open_map(key: integer()))}\n\n      # Empty value does not fail for put\n      assert map_put(closed_map(key: not_set()), atom([:key]), integer()) ==\n               {:ok, closed_map(key: integer())}\n\n      # When putting multiple keys, we don't know which one will be set\n      assert map_put(open_map(key1: atom(), key2: binary()), atom([:key1, :key2]), integer()) ==\n               {:ok,\n                union(\n                  open_map(key1: atom(), key2: integer()),\n                  open_map(key1: integer(), key2: binary())\n                )}\n\n      # When putting multiple keys, set even missing keys\n      assert map_put(open_map(key1: atom(), key2: binary()), atom([:key1, :key3]), integer()) ==\n               {:ok,\n                union(\n                  open_map(key1: atom(), key2: binary(), key3: integer()),\n                  open_map(key1: integer(), key2: binary())\n                )}\n\n      assert map_put(dynamic(open_map()), atom([:key1, :key2]), integer()) ==\n               {:ok, dynamic(union(open_map(key1: integer()), open_map(key2: integer())))}\n    end\n\n    test \"with dynamic/term as key-value\" do\n      assert map_put(closed_map(key: atom([:value])), dynamic(), dynamic()) ==\n               {:ok, dynamic(open_map())}\n\n      assert map_put(closed_map(key: atom([:value])), dynamic(), term()) ==\n               {:ok, open_map()}\n\n      assert map_put(closed_map(key: atom([:value])), term(), dynamic()) ==\n               {:ok, dynamic(open_map())}\n\n      assert map_put(closed_map(key: atom([:value])), term(), term()) ==\n               {:ok, open_map()}\n\n      assert map_put(dynamic(closed_map(key: atom([:value]))), term(), term()) ==\n               {:ok, dynamic(open_map())}\n    end\n\n    test \"with dynamic atom keys\" do\n      assert map_put(\n               open_map(key1: atom(), key2: binary()),\n               dynamic(atom([:key1, :key3])),\n               integer()\n             ) ==\n               {:ok,\n                union(\n                  open_map(key1: atom(), key2: binary(), key3: integer()),\n                  open_map(key1: integer(), key2: binary())\n                )}\n\n      assert map_put(\n               open_map(key1: atom(), key2: binary()),\n               dynamic(atom([:key3, :key4])),\n               integer()\n             ) ==\n               {:ok,\n                union(\n                  open_map(key1: atom(), key2: binary(), key3: integer()),\n                  open_map(key1: atom(), key2: binary(), key4: integer())\n                )}\n    end\n\n    test \"with domain keys\" do\n      map =\n        closed_map([\n          {domain_key(:integer), binary()},\n          {domain_key(:pid), binary()},\n          {domain_key(:port), binary()}\n        ])\n\n      assert map_put(map, integer(), integer()) ==\n               {:ok,\n                closed_map([\n                  {domain_key(:integer), union(integer(), binary())},\n                  {domain_key(:pid), binary()},\n                  {domain_key(:port), binary()}\n                ])}\n\n      assert map_put(map, union(pid(), integer()), integer()) ==\n               {:ok,\n                closed_map([\n                  {domain_key(:integer), union(integer(), binary())},\n                  {domain_key(:pid), union(integer(), binary())},\n                  {domain_key(:port), binary()}\n                ])}\n\n      assert map_put(map, union(pid(), reference()), integer()) ==\n               {:ok,\n                closed_map([\n                  {domain_key(:integer), binary()},\n                  {domain_key(:pid), union(integer(), binary())},\n                  {domain_key(:port), binary()},\n                  {domain_key(:reference), integer()}\n                ])}\n\n      assert map_put(map, union(pid(), dynamic(union(reference(), integer()))), integer()) ==\n               {:ok,\n                closed_map([\n                  {domain_key(:integer), union(integer(), binary())},\n                  {domain_key(:pid), union(integer(), binary())},\n                  {domain_key(:port), binary()},\n                  {domain_key(:reference), integer()}\n                ])}\n\n      assert map_put(map, dynamic(union(reference(), binary())), integer()) ==\n               {:ok,\n                closed_map([\n                  {domain_key(:integer), binary()},\n                  {domain_key(:pid), binary()},\n                  {domain_key(:port), binary()},\n                  {domain_key(:reference), integer()},\n                  {domain_key(:binary), integer()}\n                ])}\n\n      # Putting dynamic atom over record keys\n      assert map_put(closed_map(key1: binary(), key2: binary()), atom(), integer()) ==\n               {:ok,\n                [\n                  closed_map(key1: binary(), key2: integer()),\n                  closed_map(key1: integer(), key2: binary()),\n                  closed_map([{domain_key(:atom), integer()}, key1: binary(), key2: binary()])\n                ]\n                |> Enum.reduce(&union/2)}\n    end\n\n    test \"with mixed keys\" do\n      assert map_put(dynamic(), union(atom([:key]), binary()), integer()) ==\n               {:ok, dynamic(open_map())}\n\n      # When precise dynamic keys are given, at least one must succeed\n      assert map_put(\n               closed_map([{:key, atom()}, {domain_key(:integer), binary()}]),\n               dynamic(union(atom([:key]), integer())),\n               integer()\n             ) ==\n               {:ok,\n                union(\n                  closed_map([{:key, integer()}, {domain_key(:integer), binary()}]),\n                  closed_map([{:key, atom()}, {domain_key(:integer), union(binary(), integer())}])\n                )}\n\n      assert map_put(\n               closed_map([{:key, atom()}, {domain_key(:integer), binary()}]),\n               dynamic(union(atom([:other_key]), pid())),\n               integer()\n             ) ==\n               {:ok,\n                union(\n                  closed_map([\n                    {:key, atom()},\n                    {:other_key, integer()},\n                    {domain_key(:integer), binary()}\n                  ]),\n                  closed_map([\n                    {:key, atom()},\n                    {domain_key(:integer), binary()},\n                    {domain_key(:pid), integer()}\n                  ])\n                )}\n\n      # Negated keys\n      assert map_put(\n               closed_map(key1: binary(), key2: binary()),\n               difference(atom(), atom([:key1])),\n               integer()\n             ) ==\n               {:ok,\n                union(\n                  closed_map(key1: binary(), key2: integer()),\n                  closed_map([{domain_key(:atom), integer()}, key1: binary(), key2: binary()])\n                )}\n\n      assert map_put(\n               closed_map([key1: binary(), key2: binary()] ++ [{domain_key(:atom), pid()}]),\n               difference(atom(), atom([:key1])),\n               integer()\n             ) ==\n               {:ok,\n                union(\n                  closed_map([{domain_key(:atom), pid()}, key1: binary(), key2: integer()]),\n                  closed_map([\n                    {domain_key(:atom), union(integer(), pid())},\n                    key1: binary(),\n                    key2: binary()\n                  ])\n                )}\n    end\n  end\n\n  describe \"disjoint\" do\n    test \"optional\" do\n      assert disjoint?(term(), if_set(none()))\n      assert disjoint?(term(), if_set(none()) |> union(non_empty_list(none())))\n    end\n\n    test \"map\" do\n      refute disjoint?(open_map(), open_map(a: integer()))\n    end\n  end\n\n  describe \"to_quoted\" do\n    test \"none\" do\n      assert none() |> to_quoted_string() == \"none()\"\n      assert dynamic(none()) |> to_quoted_string() == \"none()\"\n    end\n\n    test \"bitmap\" do\n      assert union(pid(), bitstring()) |> to_quoted_string() ==\n               \"bitstring() or pid()\"\n\n      assert union(integer(), union(float(), binary())) |> to_quoted_string() ==\n               \"binary() or float() or integer()\"\n\n      assert difference(bitstring(), binary()) |> union(integer()) |> to_quoted_string() ==\n               \"(bitstring() and not binary()) or integer()\"\n    end\n\n    test \"bitmap (negation)\" do\n      assert union(pid(), bitstring()) |> negation() |> to_quoted_string() ==\n               \"not bitstring() and not pid()\"\n\n      assert difference(bitstring(), binary())\n             |> union(integer())\n             |> negation()\n             |> to_quoted_string() ==\n               \"not (bitstring() and not binary()) and not integer()\"\n    end\n\n    test \"atom\" do\n      assert atom() |> to_quoted_string() == \"atom()\"\n      assert atom([:a]) |> to_quoted_string() == \":a\"\n      assert atom([:a, :b]) |> to_quoted_string() == \":a or :b\"\n      assert difference(atom(), atom([:a])) |> to_quoted_string() == \"atom() and not :a\"\n\n      assert atom([Elixir]) |> to_quoted_string() == \"Elixir\"\n      assert atom([Foo.Bar]) |> to_quoted_string() == \"Foo.Bar\"\n    end\n\n    test \"boolean\" do\n      assert boolean() |> to_quoted_string() == \"boolean()\"\n      assert atom([true, false, :a]) |> to_quoted_string() == \":a or boolean()\"\n      assert atom([true, :a]) |> to_quoted_string() == \":a or true\"\n      assert difference(atom(), boolean()) |> to_quoted_string() == \"atom() and not boolean()\"\n    end\n\n    test \"atom/boolean (negation)\" do\n      assert atom() |> negation() |> to_quoted_string() == \"not atom()\"\n      assert atom([:a, :b]) |> negation() |> to_quoted_string() == \"not :a and not :b\"\n      assert boolean() |> negation() |> to_quoted_string() == \"not boolean()\"\n\n      assert atom([true, false, :a]) |> negation() |> to_quoted_string() ==\n               \"not :a and not boolean()\"\n    end\n\n    test \"dynamic\" do\n      assert dynamic() |> to_quoted_string() == \"dynamic()\"\n\n      assert intersection(atom(), dynamic()) |> to_quoted_string() == \"dynamic(atom())\"\n\n      assert dynamic(union(atom(), integer())) |> union(integer()) |> to_quoted_string() ==\n               \"dynamic(atom()) or integer()\"\n\n      assert intersection(binary(), dynamic()) |> to_quoted_string() ==\n               \"binary()\"\n\n      assert intersection(bitstring(), dynamic()) |> to_quoted_string() ==\n               \"dynamic(bitstring())\"\n\n      assert intersection(bitstring_no_binary(), dynamic()) |> to_quoted_string() ==\n               \"bitstring() and not binary()\"\n\n      assert intersection(union(binary(), pid()), dynamic()) |> to_quoted_string() ==\n               \"dynamic(binary() or pid())\"\n\n      assert union(atom([:foo, :bar]), dynamic()) |> to_quoted_string() ==\n               \"dynamic() or :bar or :foo\"\n\n      assert intersection(dynamic(), closed_map(a: integer())) |> to_quoted_string() ==\n               \"dynamic(%{a: integer()})\"\n    end\n\n    test \"dynamic (negation)\" do\n      assert dynamic(negation(integer())) |> to_quoted_string() == \"dynamic(not integer())\"\n      assert negation(dynamic(integer())) |> to_quoted_string() == \"dynamic() or not integer()\"\n\n      assert union(atom(), dynamic(integer())) |> negation() |> to_quoted_string() ==\n               \"dynamic(not atom()) or (not atom() and not integer())\"\n\n      assert dynamic(union(atom(), integer()))\n             |> negation()\n             |> union(integer())\n             |> to_quoted_string() ==\n               \"dynamic() or not atom()\"\n    end\n\n    test \"list\" do\n      assert list(term()) |> to_quoted_string() == \"list(term())\"\n      assert list(integer()) |> to_quoted_string() == \"list(integer())\"\n\n      assert list(term()) |> difference(empty_list()) |> to_quoted_string() ==\n               \"non_empty_list(term())\"\n\n      assert list(term()) |> difference(list(integer())) |> to_quoted_string() ==\n               \"non_empty_list(term()) and not non_empty_list(integer())\"\n\n      assert list(term())\n             |> difference(list(integer()))\n             |> difference(list(atom()))\n             |> to_quoted_string() ==\n               \"non_empty_list(term()) and not (non_empty_list(integer()) or non_empty_list(atom()))\"\n\n      assert list(term(), integer()) |> to_quoted_string() ==\n               \"empty_list() or non_empty_list(term(), integer())\"\n\n      assert difference(list(term(), atom()), list(term(), boolean())) |> to_quoted_string() ==\n               \"non_empty_list(term(), atom() and not boolean())\"\n\n      assert list(term(), term()) |> to_quoted_string() ==\n               \"empty_list() or non_empty_list(term(), term())\"\n\n      # Test normalization\n\n      # Remove duplicates\n      assert union(list(integer()), list(integer())) |> to_quoted_string() == \"list(integer())\"\n\n      # Merge subtypes\n      assert union(list(float(), pid()), list(number(), pid())) |> to_quoted_string() ==\n               \"empty_list() or non_empty_list(float() or integer(), pid())\"\n\n      # Merge last element types\n      assert union(list(atom([:ok]), integer()), list(atom([:ok]), float()))\n             |> to_quoted_string() ==\n               \"empty_list() or non_empty_list(:ok, float() or integer())\"\n\n      assert union(dynamic(list(integer(), float())), dynamic(list(integer(), pid())))\n             |> to_quoted_string() ==\n               \"dynamic(empty_list() or non_empty_list(integer(), float() or pid()))\"\n\n      list_with_tail =\n        non_empty_list(atom(), union(integer(), empty_list()))\n        |> difference(non_empty_list(atom([:ok]), integer()))\n        |> difference(non_empty_list(atom(), integer()))\n\n      # Check that simplifications occur.\n      assert to_quoted_string(list_with_tail) == \"non_empty_list(atom())\"\n    end\n\n    test \"list (negation)\" do\n      assert list(term()) |> negation() |> to_quoted_string() == \"not list(term())\"\n      assert list(negation(integer())) |> to_quoted_string() == \"list(not integer())\"\n\n      assert list(term()) |> difference(empty_list()) |> negation() |> to_quoted_string() ==\n               \"not non_empty_list(term())\"\n\n      assert non_empty_list(integer(), integer()) |> negation() |> to_quoted_string() ==\n               \"not non_empty_list(integer(), integer())\"\n    end\n\n    test \"tuple\" do\n      assert tuple([integer(), atom()]) |> to_quoted_string() == \"{integer(), atom()}\"\n\n      assert tuple([integer(), dynamic(atom())]) |> to_quoted_string() ==\n               \"dynamic({integer(), atom()})\"\n\n      assert open_tuple([integer(), atom()]) |> to_quoted_string() == \"{integer(), atom(), ...}\"\n\n      assert union(tuple([integer(), atom()]), open_tuple([atom()])) |> to_quoted_string() ==\n               \"{atom(), ...} or {integer(), atom()}\"\n\n      assert difference(tuple([integer(), atom()]), open_tuple([atom()])) |> to_quoted_string() ==\n               \"{integer(), atom()}\"\n\n      assert tuple([closed_map(a: integer()), open_map()]) |> to_quoted_string() ==\n               \"{%{a: integer()}, map()}\"\n\n      assert union(tuple([integer(), atom()]), tuple([integer(), atom()])) |> to_quoted_string() ==\n               \"{integer(), atom()}\"\n\n      assert union(tuple([integer(), atom()]), tuple([float(), atom()])) |> to_quoted_string() ==\n               \"{float() or integer(), atom()}\"\n\n      assert union(tuple([integer(), atom()]), tuple([float(), atom()]))\n             |> union(tuple([pid(), pid(), port()]))\n             |> union(tuple([pid(), pid(), atom()]))\n             |> to_quoted_string() ==\n               \"{float() or integer(), atom()} or {pid(), pid(), atom() or port()}\"\n\n      assert union(open_tuple([integer()]), open_tuple([float()])) |> to_quoted_string() ==\n               \"{float() or integer(), ...}\"\n\n      # {:ok, {term(), integer()}} or {:ok, {term(), float()}} or {:exit, :kill} or {:exit, :timeout}\n      assert tuple([atom([:ok]), tuple([term(), empty_list()])])\n             |> union(tuple([atom([:ok]), tuple([term(), open_map()])]))\n             |> union(tuple([atom([:exit]), atom([:kill])]))\n             |> union(tuple([atom([:exit]), atom([:timeout])]))\n             |> to_quoted_string() ==\n               \"{:exit, :kill or :timeout} or {:ok, {term(), empty_list() or map()}}\"\n\n      # Detection of duplicates\n      assert tuple([atom([:ok]), term()])\n             |> union(tuple([atom([:ok]), term()]))\n             |> to_quoted_string() == \"{:ok, term()}\"\n\n      assert tuple([closed_map(a: integer(), b: atom()), open_map()])\n             |> union(tuple([closed_map(a: integer(), b: atom()), open_map()]))\n             |> to_quoted_string() ==\n               \"{%{a: integer(), b: atom()}, map()}\"\n\n      # Nested fusion\n      assert tuple([closed_map(a: integer(), b: atom()), open_map()])\n             |> union(tuple([closed_map(a: float(), b: atom()), open_map()]))\n             |> to_quoted_string() ==\n               \"{%{a: float() or integer(), b: atom()}, map()}\"\n\n      # Complex simplification of map/tuple combinations. Initial type is:\n      # ```\n      #   dynamic(\n      #     :error or\n      #     ({%Decimal{coef: :inf, exp: integer(), sign: integer()}, binary()} or\n      #       {%Decimal{coef: :NaN, exp: integer(), sign: integer()}, binary()} or\n      #       {%Decimal{coef: integer(), exp: integer(), sign: integer()}, term()} or\n      #       {%Decimal{coef: :inf, exp: integer(), sign: integer()} or\n      #           %Decimal{coef: :NaN, exp: integer(), sign: integer()} or\n      #           %Decimal{coef: integer(), exp: integer(), sign: integer()}, term()})\n      #   )\n      # ```\n      decimal_inf =\n        closed_map(\n          __struct__: atom([Decimal]),\n          coef: atom([:inf]),\n          exp: integer(),\n          sign: integer()\n        )\n\n      decimal_nan =\n        closed_map(\n          __struct__: atom([Decimal]),\n          coef: atom([:NaN]),\n          exp: integer(),\n          sign: integer()\n        )\n\n      decimal_int =\n        closed_map(\n          __struct__: atom([Decimal]),\n          coef: integer(),\n          exp: integer(),\n          sign: integer()\n        )\n\n      assert atom([:error])\n             |> union(\n               tuple([decimal_inf, binary()])\n               |> union(\n                 tuple([decimal_nan, binary()])\n                 |> union(\n                   tuple([decimal_int, term()])\n                   |> union(tuple([union(decimal_inf, union(decimal_nan, decimal_int)), term()]))\n                 )\n               )\n             )\n             |> dynamic()\n             |> to_quoted_string() ==\n               \"\"\"\n               dynamic(\n                 :error or {%Decimal{sign: integer(), coef: :NaN or :inf or integer(), exp: integer()}, term()}\n               )\\\n               \"\"\"\n    end\n\n    test \"tuple (negation)\" do\n      assert tuple([integer()]) |> negation() |> to_quoted_string() == \"not {integer()}\"\n      assert tuple([negation(integer())]) |> to_quoted_string() == \"{not integer()}\"\n    end\n\n    test \"fun\" do\n      assert fun() |> to_quoted_string() == \"fun()\"\n      assert none_fun(1) |> to_quoted_string() == \"(none() -> term())\"\n\n      assert none_fun(1)\n             |> intersection(none_fun(2))\n             |> to_quoted_string() == \"none()\"\n\n      assert fun([integer(), float()], boolean()) |> to_quoted_string() ==\n               \"(integer(), float() -> boolean())\"\n\n      assert fun([integer()], boolean())\n             |> union(fun([float()], boolean()))\n             |> to_quoted_string() ==\n               \"(integer() -> boolean()) or (float() -> boolean())\"\n\n      assert fun([integer()], boolean())\n             |> intersection(fun([float()], boolean()))\n             |> to_quoted_string() ==\n               \"(integer() -> boolean()) and (float() -> boolean())\"\n\n      # Thanks to lazy BDDs, consecutive union of functions come out as the original union\n      assert fun([integer()], integer())\n             |> union(fun([float()], float()))\n             |> union(fun([pid()], pid()))\n             |> to_quoted_string() ==\n               \"(integer() -> integer()) or (float() -> float()) or (pid() -> pid())\"\n\n      assert fun(3) |> to_quoted_string() == \"(none(), none(), none() -> term())\"\n\n      assert intersection(fun(), negation(fun())) |> to_quoted_string() == \"none()\"\n\n      assert intersection(fun(), negation(fun(3))) |> to_quoted_string() ==\n               \"fun() and not (none(), none(), none() -> term())\"\n    end\n\n    test \"fun with optimized intersections\" do\n      assert fun([integer()], atom()) |> intersection(none_fun(1)) |> to_quoted_string() ==\n               \"(integer() -> atom())\"\n\n      assert fun([integer()], atom())\n             |> difference(none_fun(2))\n             |> intersection(none_fun(1))\n             |> to_quoted_string() ==\n               \"(integer() -> atom())\"\n    end\n\n    test \"fun with dynamic signatures\" do\n      assert fun([dynamic(integer())], float()) |> to_quoted_string() ==\n               \"(dynamic(integer()) -> float())\"\n\n      assert fun([dynamic(atom())], float()) |> to_quoted_string() ==\n               \"(dynamic(atom()) -> float())\"\n\n      assert fun([integer(), float()], dynamic(atom())) |> to_quoted_string() ==\n               \"(integer(), float() -> dynamic(atom()))\"\n\n      domain_part = fun([dynamic(atom()) |> union(integer()), binary()], float())\n\n      assert domain_part |> to_quoted_string() ==\n               \"(dynamic(atom()) or integer(), binary() -> float())\"\n\n      codomain_part = fun([pid(), float()], dynamic(atom()) |> union(integer()))\n\n      assert codomain_part |> to_quoted_string() ==\n               \"(pid(), float() -> dynamic(atom()) or integer())\"\n\n      assert union(domain_part, codomain_part) |> to_quoted_string() ==\n               \"\"\"\n               (dynamic(atom()) or integer(), binary() -> float()) or\n                 (pid(), float() -> dynamic(atom()) or integer())\\\n               \"\"\"\n\n      assert intersection(domain_part, codomain_part) |> to_quoted_string() ==\n               \"\"\"\n               (dynamic(atom()) or integer(), binary() -> float()) and\n                 (pid(), float() -> dynamic(atom()) or integer())\\\n               \"\"\"\n    end\n\n    test \"fun (negation)\" do\n      assert fun([integer()], atom()) |> negation() |> to_quoted_string() ==\n               \"not (integer() -> atom())\"\n    end\n\n    test \"map as records\" do\n      assert empty_map() |> to_quoted_string() == \"empty_map()\"\n      assert open_map() |> to_quoted_string() == \"map()\"\n\n      assert closed_map(a: integer()) |> to_quoted_string() == \"%{a: integer()}\"\n      assert open_map(a: float()) |> to_quoted_string() == \"%{..., a: float()}\"\n\n      assert closed_map(\"Elixir.Foo.Bar\": integer()) |> to_quoted_string() ==\n               \"%{Foo.Bar => integer()}\"\n\n      assert open_map(\"Elixir.Foo.Bar\": float()) |> to_quoted_string() ==\n               \"%{..., Foo.Bar => float()}\"\n\n      assert difference(open_map(), open_map(a: term())) |> to_quoted_string() ==\n               \"map() and not %{..., a: term()}\"\n\n      assert closed_map(a: integer(), b: atom()) |> to_quoted_string() ==\n               \"%{a: integer(), b: atom()}\"\n\n      assert open_map(a: float())\n             |> difference(closed_map(a: float()))\n             |> to_quoted_string() == \"%{..., a: float()} and not %{a: float()}\"\n\n      assert difference(open_map(), empty_map()) |> to_quoted_string() ==\n               \"map() and not empty_map()\"\n\n      assert closed_map(foo: union(integer(), not_set())) |> to_quoted_string() ==\n               \"%{foo: if_set(integer())}\"\n\n      # Test normalization\n      assert open_map(a: integer(), b: atom())\n             |> difference(open_map(b: atom()))\n             |> union(open_map(a: integer()))\n             |> to_quoted_string() == \"%{..., a: integer()}\"\n\n      assert union(open_map(a: integer()), open_map(a: integer())) |> to_quoted_string() ==\n               \"%{..., a: integer()}\"\n\n      assert difference(open_map(a: number(), b: atom()), open_map(a: integer()))\n             |> to_quoted_string() == \"%{..., a: float(), b: atom()}\"\n\n      # Basic map fusion\n      assert union(closed_map(a: integer()), closed_map(a: integer())) |> to_quoted_string() ==\n               \"%{a: integer()}\"\n\n      assert union(closed_map(a: integer()), closed_map(a: float())) |> to_quoted_string() ==\n               \"%{a: float() or integer()}\"\n\n      # Nested fusion\n      assert union(closed_map(a: integer(), b: atom()), closed_map(a: float(), b: atom()))\n             |> union(closed_map(x: pid(), y: pid(), z: port()))\n             |> union(closed_map(x: pid(), y: pid(), z: atom()))\n             |> to_quoted_string() ==\n               \"%{a: float() or integer(), b: atom()} or %{x: pid(), y: pid(), z: atom() or port()}\"\n\n      # Open map fusion\n      assert union(open_map(a: integer()), open_map(a: float())) |> to_quoted_string() ==\n               \"%{..., a: float() or integer()}\"\n\n      # Fusing complex nested maps with unions\n      assert closed_map(\n               status: atom([:ok]),\n               data: closed_map(value: term(), count: empty_list())\n             )\n             |> union(\n               closed_map(\n                 status: atom([:ok]),\n                 data: closed_map(value: term(), count: open_map())\n               )\n             )\n             |> union(closed_map(status: atom([:error]), reason: atom([:timeout])))\n             |> union(closed_map(status: atom([:error]), reason: atom([:crash])))\n             |> to_quoted_string() ==\n               \"%{data: %{count: empty_list() or map(), value: term()}, status: :ok} or\\n  %{reason: :crash or :timeout, status: :error}\"\n\n      # Difference and union tests\n      assert closed_map(status: atom([:ok]), value: term())\n             |> difference(closed_map(status: atom([:ok]), value: float()))\n             |> union(\n               closed_map(status: atom([:ok]), value: term())\n               |> difference(closed_map(status: atom([:ok]), value: integer()))\n             )\n             |> to_quoted_string() ==\n               \"%{status: :ok, value: term()}\"\n\n      # Nested map fusion\n      assert closed_map(data: closed_map(x: integer(), y: atom()), meta: open_map())\n             |> union(closed_map(data: closed_map(x: float(), y: atom()), meta: open_map()))\n             |> to_quoted_string() ==\n               \"%{data: %{x: float() or integer(), y: atom()}, meta: map()}\"\n\n      # Test complex combinations\n      assert intersection(\n               open_map(a: number(), b: atom()),\n               open_map(a: integer(), c: boolean())\n             )\n             |> union(difference(open_map(x: atom()), open_map(x: boolean())))\n             |> to_quoted_string() ==\n               \"%{..., a: integer(), b: atom(), c: boolean()} or %{..., x: atom() and not boolean()}\"\n\n      assert closed_map(a: number(), b: atom(), c: pid())\n             |> difference(closed_map(a: integer(), b: atom(), c: pid()))\n             |> to_quoted_string() == \"%{a: float(), b: atom(), c: pid()}\"\n\n      # No simplification compared to above, as it is an open map\n      assert open_map(a: number(), b: atom())\n             |> difference(closed_map(a: integer(), b: atom()))\n             |> to_quoted_string() ==\n               \"%{..., a: float() or integer(), b: atom()} and not %{a: integer(), b: atom()}\"\n\n      # Remark: this simplification is order dependent. Having the first difference\n      # after the second gives a different result.\n      assert open_map(a: number(), b: atom(), c: union(pid(), port()))\n             |> difference(open_map(a: integer(), b: atom(), c: union(pid(), port())))\n             |> difference(open_map(a: float(), b: atom(), c: pid()))\n             |> to_quoted_string() == \"%{..., a: float(), b: atom(), c: port()}\"\n\n      assert open_map(a: number(), b: atom(), c: union(pid(), port()))\n             |> difference(open_map(a: float(), b: atom(), c: pid()))\n             |> difference(open_map(a: integer(), b: atom(), c: union(pid(), port())))\n             |> to_quoted_string() == \"%{..., a: float(), b: atom(), c: port()}\"\n    end\n\n    test \"map as dictionaries\" do\n      assert closed_map([{domain_key(:integer), integer()}])\n             |> to_quoted_string() == \"%{integer() => integer()}\"\n\n      assert closed_map([{domain_key(:integer), not_set()}, {:float, float()}])\n             |> to_quoted_string() == \"%{integer() => not_set(), float: float()}\"\n    end\n\n    test \"map (negation)\" do\n      assert open_map(a: integer()) |> negation() |> to_quoted_string() ==\n               \"not %{..., a: integer()}\"\n\n      assert open_map(a: negation(integer())) |> to_quoted_string() ==\n               \"%{..., a: not integer()}\"\n\n      assert closed_map(a: integer()) |> negation() |> to_quoted_string() ==\n               \"not %{a: integer()}\"\n\n      assert closed_map(a: negation(integer())) |> to_quoted_string() ==\n               \"%{a: not integer()}\"\n    end\n\n    test \"structs\" do\n      assert open_map(__struct__: term()) |> to_quoted_string() ==\n               \"%{..., __struct__: term()}\"\n\n      assert open_map(__struct__: atom([URI])) |> to_quoted_string() ==\n               \"%{..., __struct__: URI}\"\n\n      assert closed_map(__struct__: atom([URI])) |> to_quoted_string() ==\n               \"%{__struct__: URI}\"\n\n      assert closed_map(__struct__: atom([NoFieldsStruct])) |> to_quoted_string() ==\n               \"%NoFieldsStruct{}\"\n\n      assert closed_map(__struct__: atom([URI, Another])) |> to_quoted_string() ==\n               \"%{__struct__: Another or URI}\"\n\n      assert closed_map(__struct__: atom([Decimal]), coef: term(), exp: term(), sign: term())\n             |> to_quoted_string(collapse_structs: false) ==\n               \"%Decimal{sign: term(), coef: term(), exp: term()}\"\n\n      assert closed_map(__struct__: atom([Decimal]), coef: term(), exp: term(), sign: term())\n             |> to_quoted_string() ==\n               \"%Decimal{}\"\n\n      assert closed_map(__struct__: atom([Decimal]), coef: term(), exp: term(), sign: integer())\n             |> to_quoted_string() ==\n               \"%Decimal{sign: integer()}\"\n\n      # Does not fuse structs\n      assert union(closed_map(__struct__: atom([Foo])), closed_map(__struct__: atom([Bar])))\n             |> to_quoted_string() ==\n               \"%{__struct__: Bar} or %{__struct__: Foo}\"\n\n      # Properly format non_struct_map\n      assert open_map(__struct__: if_set(negation(atom()))) |> to_quoted_string() ==\n               \"non_struct_map()\"\n    end\n  end\n\n  describe \"performance\" do\n    test \"tuple difference\" do\n      # Large difference with no duplicates\n      descr1 =\n        union(\n          atom([:ignored, :reset]),\n          tuple([atom([:font_style]), atom([:italic])])\n        )\n\n      descr2 =\n        union(\n          atom([:ignored, :reset]),\n          union(\n            tuple([atom([:font_style]), atom([:italic])]),\n            Enum.reduce(\n              for elem1 <- 1..5, elem2 <- 1..5 do\n                tuple([atom([:\"f#{elem1}\"]), atom([:\"s#{elem2}\"])])\n              end,\n              &union/2\n            )\n          )\n        )\n\n      assert subtype?(descr1, descr2)\n      refute subtype?(descr2, descr1)\n    end\n\n    test \"map difference\" do\n      # Create a large map with various types\n      map1 =\n        open_map([\n          {:id, integer()},\n          {:name, binary()},\n          {:age, union(integer(), atom())},\n          {:email, binary()},\n          {:active, boolean()},\n          {:tags, list(atom())}\n        ])\n\n      # Create another large map with some differences and many more entries\n      map2 =\n        open_map(\n          [\n            {:id, integer()},\n            {:name, binary()},\n            {:age, integer()},\n            {:email, binary()},\n            {:active, boolean()},\n            {:tags, non_empty_list(atom())},\n            {:meta,\n             open_map([\n               {:created_at, binary()},\n               {:updated_at, binary()},\n               {:status, atom()}\n             ])},\n            {:permissions, tuple([atom(), integer(), atom()])},\n            {:profile,\n             open_map([\n               {:bio, binary()},\n               {:interests, non_empty_list(binary())},\n               {:social_media,\n                open_map([\n                  {:twitter, binary()},\n                  {:instagram, binary()},\n                  {:linkedin, binary()}\n                ])}\n             ])},\n            {:notifications, boolean()}\n          ] ++\n            Enum.map(1..50, fn i ->\n              {:\"field_#{i}\", atom([:\"value_#{i}\"])}\n            end)\n        )\n\n      refute subtype?(map1, map2)\n      assert subtype?(map2, map1)\n    end\n\n    test \"map intersection and then difference\" do\n      actual = open_map(__struct__: atom(), __exception__: atom([true]))\n\n      expected =\n        for i <- 1..50 do\n          name = :\"name_#{i}\"\n          closed_map([__struct__: atom([name])] ++ [{name, binary()}])\n        end\n        |> Enum.reduce(&union/2)\n\n      common = intersection(actual, expected)\n      difference(actual, common)\n    end\n\n    test \"struct difference\" do\n      entries =\n        [\n          closed_map(__struct__: atom([MapSet]), map: term()),\n          closed_map(__struct__: atom([Jason.OrderedObject]), values: term()),\n          closed_map(__struct__: atom([GenEvent.Stream]), timeout: term(), manager: term()),\n          closed_map(__struct__: atom([HashDict]), size: term(), root: term()),\n          closed_map(__struct__: atom([HashSet]), size: term(), root: term()),\n          closed_map(\n            __struct__: atom([IO.Stream]),\n            raw: term(),\n            device: term(),\n            line_or_bytes: term()\n          ),\n          closed_map(__struct__: atom([Range]), first: term(), last: term(), step: term()),\n          closed_map(\n            __struct__: atom([Stream]),\n            enum: term(),\n            done: term(),\n            funs: term(),\n            accs: term()\n          ),\n          closed_map(\n            __struct__: atom([Req.Response.Async]),\n            pid: term(),\n            ref: term(),\n            stream_fun: term(),\n            cancel_fun: term()\n          ),\n          closed_map(\n            __struct__: atom([Postgrex.Stream]),\n            options: term(),\n            params: term(),\n            query: term(),\n            conn: term()\n          ),\n          closed_map(\n            __struct__: atom([DBConnection.PrepareStream]),\n            opts: term(),\n            params: term(),\n            query: term(),\n            conn: term()\n          ),\n          closed_map(\n            __struct__: atom([DBConnection.Stream]),\n            opts: term(),\n            params: term(),\n            query: term(),\n            conn: term()\n          ),\n          closed_map(\n            __struct__: atom([Ecto.Adapters.SQL.Stream]),\n            meta: term(),\n            opts: term(),\n            params: term(),\n            statement: term()\n          ),\n          closed_map(\n            __struct__: atom([Date.Range]),\n            first: term(),\n            last: term(),\n            step: term(),\n            first_in_iso_days: term(),\n            last_in_iso_days: term()\n          ),\n          closed_map(\n            __struct__: atom([File.Stream]),\n            node: term(),\n            raw: term(),\n            path: term(),\n            modes: term(),\n            line_or_bytes: term()\n          ),\n          closed_map(\n            __struct__: atom([Phoenix.LiveView.LiveStream]),\n            name: term(),\n            ref: term(),\n            inserts: term(),\n            deletes: term(),\n            reset?: term(),\n            dom_id: term(),\n            consumable?: term()\n          )\n        ]\n\n      range =\n        closed_map(__struct__: atom([Range]), first: integer(), last: integer(), step: integer())\n\n      assert subtype?(range, Enum.reduce(entries, &union/2))\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module/types/expr_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"type_helper.exs\", __DIR__)\n\ndefmodule Module.Types.ExprTest do\n  use ExUnit.Case, async: true\n\n  import TypeHelper\n  import Module.Types.Descr\n  defmacro domain_key(arg) when is_atom(arg), do: [arg]\n\n  defmacro generated_foo_call(x) do\n    quote generated: true do\n      unquote(x).foo()\n    end\n  end\n\n  test \"literal\" do\n    assert typecheck!(true) == atom([true])\n    assert typecheck!(false) == atom([false])\n    assert typecheck!(:foo) == atom([:foo])\n    assert typecheck!(0) == integer()\n    assert typecheck!(0.0) == float()\n    assert typecheck!(\"foo\") == binary()\n    assert typecheck!([]) == empty_list()\n    assert typecheck!(%{}) == closed_map([])\n  end\n\n  test \"generated\" do\n    assert typecheck!([x = 1], generated_foo_call(x)) == dynamic()\n  end\n\n  describe \"bitstrings\" do\n    test \"integer alignment\" do\n      assert typecheck!(<<round(:rand.uniform())>>) == binary()\n      assert typecheck!(<<round(:rand.uniform())::1>>) == difference(bitstring(), binary())\n      assert typecheck!(<<round(:rand.uniform())::4, round(:rand.uniform())::4>>) == binary()\n      assert typecheck!([size], <<round(:rand.uniform())::size(size)>>) == bitstring()\n    end\n\n    test \"bitstring alignment\" do\n      assert typecheck!(\n               [coef, sign, exp],\n               <<Integer.to_string(coef * sign)::bitstring, \".0e\"::bitstring,\n                 Integer.to_string(exp)::bitstring>>\n             ) == binary()\n\n      # This will be truncated to size, so it is a bitstring\n      assert typecheck!([exp], <<Integer.to_string(exp)::bitstring-size(20)>>) ==\n               bitstring_no_binary()\n    end\n  end\n\n  describe \"lists\" do\n    test \"creating lists\" do\n      assert typecheck!([1, 2]) == non_empty_list(integer())\n      assert typecheck!([1, 2 | 3]) == non_empty_list(integer(), integer())\n      assert typecheck!([1, 2 | [3, 4]]) == non_empty_list(integer())\n\n      assert typecheck!([:ok, 123]) == non_empty_list(union(atom([:ok]), integer()))\n      assert typecheck!([:ok | 123]) == non_empty_list(atom([:ok]), integer())\n      assert typecheck!([x], [:ok, x]) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], [:ok | x]) == dynamic(non_empty_list(term(), term()))\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x, y, z],\n               (\n                 List.to_integer([x, y | z])\n                 {x, y, z}\n               )\n             ) == dynamic(tuple([integer(), integer(), list(integer())]))\n    end\n\n    test \"hd\" do\n      assert typecheck!([x = [123, :foo]], hd(x)) == dynamic(union(atom([:foo]), integer()))\n      assert typecheck!([x = [123 | :foo]], hd(x)) == dynamic(integer())\n\n      assert typeerror!(hd([])) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Kernel.hd/1:\n\n                   hd([])\n\n               given types:\n\n                   empty_list()\n\n               but expected one of:\n\n                   non_empty_list(term(), term())\n               \"\"\"\n\n      assert typeerror!(hd(123)) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Kernel.hd/1:\n\n                   hd(123)\n\n               given types:\n\n                   integer()\n\n               but expected one of:\n\n                   non_empty_list(term(), term())\n               \"\"\"\n    end\n\n    test \"tl\" do\n      assert typecheck!([x = [123, :foo]], tl(x)) == dynamic(list(union(atom([:foo]), integer())))\n\n      assert typecheck!([x = [123 | :foo]], tl(x)) ==\n               dynamic(union(atom([:foo]), non_empty_list(integer(), atom([:foo]))))\n\n      assert typeerror!(tl([])) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Kernel.tl/1:\n\n                   tl([])\n\n               given types:\n\n                   empty_list()\n\n               but expected one of:\n\n                   non_empty_list(term(), term())\n               \"\"\"\n\n      assert typeerror!(tl(123)) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Kernel.tl/1:\n\n                   tl(123)\n\n               given types:\n\n                   integer()\n\n               but expected one of:\n\n                   non_empty_list(term(), term())\n               \"\"\"\n    end\n  end\n\n  describe \"funs\" do\n    test \"infers calls\" do\n      assert typecheck!(\n               [x],\n               (\n                 x.(1, 2)\n                 x\n               )\n             ) == dynamic(fun(2))\n    end\n\n    test \"infers functions\" do\n      assert typecheck!(& &1) |> equal?(fun([term()], dynamic()))\n\n      assert typecheck!(fn -> :ok end) |> equal?(fun([], dynamic(atom([:ok]))))\n\n      assert typecheck!(fn\n               <<\"ok\">>, {} -> :ok\n               <<\"error\">>, {} -> :error\n               [_ | _], %{} -> :list\n             end)\n             |> equal?(\n               intersection(\n                 fun(\n                   [non_empty_list(term(), term()), open_map()],\n                   dynamic(atom([:list]))\n                 ),\n                 fun(\n                   [binary(), tuple([])],\n                   dynamic(atom([:ok, :error]))\n                 )\n               )\n             )\n\n      assert typecheck!(fn x -> Integer.to_string(x) end) ==\n               fun([integer()], dynamic(binary()))\n    end\n\n    test \"application\" do\n      assert typecheck!(\n               [map],\n               (fn\n                  %{a: a} = data -> %{data | b: a}\n                  %{} = data -> data\n                end).(map)\n             ) == dynamic()\n\n      assert typecheck!(\n               [],\n               [true, false]\n               |> Enum.random()\n               |> then(fn\n                 true -> :ok\n                 _ -> :error\n               end)\n             ) == dynamic(atom([:ok, :error]))\n    end\n\n    test \"warns on redundant clauses\" do\n      assert typewarn!(fn\n               x when is_binary(x) -> x\n               \"foo\" -> \"bar\"\n             end)\n             |> elem(1) == \"\"\"\n             the following clause is redundant:\n\n                 \"foo\" ->\n\n             previous clauses have already matched on the following types:\n\n                 binary()\n             \"\"\"\n    end\n\n    test \"bad function\" do\n      assert typeerror!([%x{}, a1, a2], x.(a1, a2)) == ~l\"\"\"\n             expected a 2-arity function on function call:\n\n                 x.(a1, a2)\n\n             but got type:\n\n                 dynamic(atom())\n\n             where \"x\" was given the type:\n\n                 # type: dynamic(atom())\n                 # from: types_test.ex:LINE\n                 %x{}\n             \"\"\"\n    end\n\n    test \"bad arity\" do\n      assert typeerror!([a1, a2], (&String.to_integer/1).(a1, a2)) == ~l\"\"\"\n             expected a 2-arity function on function call:\n\n                 (&String.to_integer/1).(a1, a2)\n\n             but got function with arity 1:\n\n                 (binary() -> integer())\n             \"\"\"\n    end\n\n    test \"bad argument\" do\n      assert typeerror!([], (&String.to_integer/1).(:foo))\n             |> strip_ansi() == ~l\"\"\"\n             incompatible types given on function call:\n\n                 (&String.to_integer/1).(:foo)\n\n             given types:\n\n                 :foo\n\n             but function has type:\n\n                 (binary() -> integer())\n             \"\"\"\n\n      assert typeerror!(\n               [x],\n               (if x do\n                  &String.to_integer/1\n                else\n                  &List.to_integer/1\n                end).(:foo)\n             )\n             |> strip_ansi() == ~l\"\"\"\n             incompatible types given on function call:\n\n                 (if x do\n                    &String.to_integer/1\n                  else\n                    &List.to_integer/1\n                  end).(:foo)\n\n             given types:\n\n                 :foo\n\n             but function has type:\n\n                 (binary() -> integer()) or (non_empty_list(integer()) -> integer())\n\n             hint: the function has an empty domain and therefore cannot be applied to any argument. \\\n             This may happen when you have a union of functions, which means the only valid argument \\\n             to said function are types that satisfy all sides of the union (which may be none)\n             \"\"\"\n    end\n\n    test \"bad arguments from inferred type\" do\n      assert typeerror!(\n               (\n                 fun = fn %{} -> :map end\n                 fun.(:error)\n               )\n             )\n             |> strip_ansi() == \"\"\"\n             incompatible types given on function call:\n\n                 fun.(:error)\n\n             given types:\n\n                 :error\n\n             but function has type:\n\n                 (map() -> dynamic(:map))\n             \"\"\"\n    end\n\n    test \"capture printing\" do\n      assert typeerror!(123 = &{:ok, &1}) == \"\"\"\n             the following pattern will never match:\n\n                 123 = &{:ok, &1}\n\n             because the right-hand side has type:\n\n                 (term() -> dynamic({:ok, term()}))\n             \"\"\"\n    end\n\n    test \"works when there are multiple clauses with lists and maps\" do\n      type =\n        typecheck!(fn\n          [:oban, :job, _event], _measure, _meta, _opts ->\n            :ok\n\n          [:oban, :notifier, :switch], _measure, %{status: _status}, _opts ->\n            :ok\n\n          [:oban, :peer, :election, :stop], _measure, _meta, _opts ->\n            :ok\n\n          [:oban, :plugin, :exception], _measure, _meta, _opts ->\n            :ok\n\n          [:oban, :plugin, :stop], _measure, _meta, _opts ->\n            :ok\n\n          [:oban, :queue, :shutdown], _measure, %{orphaned: [_ | _]}, _opts ->\n            :ok\n\n          [:oban, :stager, :switch], _measure, %{mode: _mode}, _opts ->\n            :ok\n\n          _event, _measure, _meta, _opts ->\n            :ok\n        end)\n\n      assert subtype?(type, fun([term(), term(), term(), term()], atom([:ok])))\n    end\n  end\n\n  describe \"remotes\" do\n    test \"dynamic calls\" do\n      assert typecheck!([%x{}], x.foo_bar()) == dynamic()\n    end\n\n    test \"infers atoms\" do\n      assert typecheck!(\n               [x],\n               (\n                 x.foo_bar()\n                 x\n               )\n             ) == dynamic(atom())\n\n      assert typecheck!(\n               [x],\n               (\n                 x.foo_bar(123)\n                 x\n               )\n             ) == dynamic(atom())\n\n      assert typecheck!(\n               [x],\n               (\n                 &x.foo_bar/1\n                 x\n               )\n             ) == dynamic(atom())\n    end\n\n    test \"infers maps\" do\n      assert typecheck!(\n               [x],\n               (\n                 :foo = x.foo_bar\n                 123 = x.baz_bat\n                 x\n               )\n             ) == dynamic(open_map(foo_bar: atom([:foo]), baz_bat: integer()))\n    end\n\n    test \"infers args\" do\n      assert typecheck!(\n               [x, y],\n               (\n                 z = Integer.to_string(x + y)\n                 {x, y, z}\n               )\n             ) == dynamic(tuple([integer(), integer(), binary()]))\n    end\n\n    test \"undefined function warnings\" do\n      assert typewarn!(URI.unknown(\"foo\")) ==\n               {dynamic(), \"URI.unknown/1 is undefined or private\"}\n\n      assert typewarn!(if(:rand.uniform() > 0.5, do: URI.unknown(\"foo\"))) ==\n               {dynamic() |> union(atom([nil])), \"URI.unknown/1 is undefined or private\"}\n\n      assert typewarn!(try(do: :ok, after: URI.unknown(\"foo\"))) ==\n               {atom([:ok]), \"URI.unknown/1 is undefined or private\"}\n\n      # Check it also emits over a union\n      assert typewarn!(\n               [x = Atom, y = GenServer, z],\n               (\n                 mod =\n                   cond do\n                     z -> x\n                     true -> y\n                   end\n\n                 mod.to_string(:atom)\n               )\n             ) ==\n               {union(dynamic(), binary()), \"GenServer.to_string/1 is undefined or private\"}\n    end\n\n    test \"calling a function with none()\" do\n      assert typeerror!(Integer.to_string(raise \"oops\")) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Integer.to_string/1:\n\n                   Integer.to_string(raise RuntimeError.exception(\"oops\"))\n\n               given types:\n\n                   none()\n\n               the 1st argument is empty (often represented as none()), \\\n               most likely because it is the result of an expression that \\\n               always fails, such as a `raise` or a previous invalid call. \\\n               This causes any function called with this value to fail\n               \"\"\"\n    end\n\n    test \"calling a nullary function on non atoms\" do\n      assert typeerror!([<<x::integer>>], x.foo_bar()) ==\n               ~l\"\"\"\n               expected a module (an atom) when invoking foo_bar/0 in expression:\n\n                   x.foo_bar()\n\n               where \"x\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   <<x::integer>>\n\n               #{hints(:dot)}\n               \"\"\"\n    end\n\n    test \"calling a function on non atoms with arguments\" do\n      assert typeerror!([<<x::integer>>], x.foo_bar(1, 2)) ==\n               ~l\"\"\"\n               expected a module (an atom) when invoking foo_bar/2 in expression:\n\n                   x.foo_bar(1, 2)\n\n               where \"x\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   <<x::integer>>\n               \"\"\"\n\n      assert typeerror!(\n               [<<x::integer>>, y = SomeMod, z],\n               (\n                 mod =\n                   cond do\n                     z -> x\n                     true -> y\n                   end\n\n                 mod.to_string(:atom)\n               )\n             ) ==\n               ~l\"\"\"\n               expected a module (an atom) when invoking to_string/1 in expression:\n\n                   mod.to_string(:atom)\n\n               where \"mod\" was given the type:\n\n                   # type: dynamic(SomeMod) or integer()\n                   # from: types_test.ex:LINE-9\n                   mod =\n                     cond do\n                       ...\n                     end\n               \"\"\"\n    end\n\n    test \"calling a function with invalid arguments on variables\" do\n      assert typeerror!(\n               (\n                 x = List\n                 x.to_tuple(123)\n               )\n             )\n             |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to List.to_tuple/1:\n\n                   x.to_tuple(123)\n\n               given types:\n\n                   integer()\n\n               but expected one of:\n\n                   list(term())\n\n               where \"x\" was given the type:\n\n                   # type: List\n                   # from: types_test.ex:LINE-5\n                   x = List\n               \"\"\"\n    end\n\n    test \"computes union of all combinations\" do\n      assert typecheck!(\n               [condition, arg],\n               (\n                 mod = if condition, do: String, else: List\n                 res = mod.to_integer(arg)\n                 {arg, res}\n               )\n             ) == dynamic(tuple([union(binary(), non_empty_list(integer())), integer()]))\n\n      assert typeerror!(\n               [condition],\n               (\n                 arg = if condition, do: \"foo\", else: [?f, ?o, ?o]\n                 mod = if condition, do: String, else: List\n                 mod.to_integer(arg)\n               )\n             )\n             |> strip_ansi() == ~l\"\"\"\n             incompatible types given to List.to_integer/1:\n\n                 mod.to_integer(arg)\n                 #=> invoked as List.to_integer/1\n\n             given types:\n\n                 binary() or non_empty_list(integer())\n\n             but expected one of:\n\n                 non_empty_list(integer())\n\n             where \"arg\" was given the type:\n\n                 # type: binary() or non_empty_list(integer())\n                 # from: types_test.ex:LINE-5\n                 arg =\n                   if condition do\n                     \"foo\"\n                   else\n                     ~c\"foo\"\n                   end\n\n             where \"mod\" was given the type:\n\n                 # type: List or String\n                 # from: types_test.ex:LINE-4\n                 mod =\n                   if condition do\n                     String\n                   else\n                     List\n                   end\n             \"\"\"\n    end\n\n    test \"calling a function with conditional variables excluside to the application\" do\n      assert typecheck!(\n               [condition, arg],\n               (\n                 mod = if condition, do: Integer, else: Float\n\n                 mod.parse(\n                   (\n                     query = \"+\" <> arg\n                     String.trim_trailing(query)\n                   )\n                 )\n               )\n             ) == dynamic()\n    end\n  end\n\n  describe \"remote capture\" do\n    test \"strong\" do\n      assert typecheck!(&String.to_atom/1) == fun([binary()], atom())\n      assert typecheck!(&:erlang.element/2) == fun([integer(), open_tuple([])], dynamic())\n    end\n\n    test \"unknown\" do\n      assert typecheck!(&Module.Types.ExprTest.__ex_unit__/1) == dynamic(fun(1))\n      assert typecheck!([x], &x.something/1) == dynamic(fun(1))\n    end\n\n    test \"capture a function with non atoms\" do\n      assert typeerror!([<<x::integer>>], &x.foo_bar/2) ==\n               ~l\"\"\"\n               expected a module (an atom) when invoking foo_bar/2 in expression:\n\n                   &x.foo_bar/2\n\n               but got type:\n\n                   integer()\n\n               where \"x\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   <<x::integer>>\n               \"\"\"\n    end\n  end\n\n  describe \"binaries\" do\n    test \"inference\" do\n      assert typecheck!(\n               [x, y],\n               (\n                 <<x::float-size(y)>>\n                 {x, y}\n               )\n             ) == dynamic(tuple([union(float(), integer()), integer()]))\n    end\n\n    test \"warnings\" do\n      assert typeerror!([<<x::binary-size(2)>>], <<x::float>>) ==\n               ~l\"\"\"\n               incompatible types in binary construction:\n\n                   <<x::float>>\n\n               got type:\n\n                   binary()\n\n               but expected type:\n\n                   float() or integer()\n\n               where \"x\" was given the type:\n\n                   # type: binary()\n                   # from: types_test.ex:LINE-1\n                   <<x::binary-size(2)>>\n               \"\"\"\n\n      assert typeerror!([<<x::binary>>], <<x>>) ==\n               ~l\"\"\"\n               incompatible types in binary construction:\n\n                   <<x>>\n\n               got type:\n\n                   binary()\n\n               but expected type:\n\n                   integer()\n\n               where \"x\" was given the type:\n\n                   # type: binary()\n                   # from: types_test.ex:LINE-1\n                   <<x::binary>>\n\n               #{hints(:inferred_bitstring_spec)}\n               \"\"\"\n\n      assert typeerror!([<<x>>], <<x::binary>>) ==\n               ~l\"\"\"\n               incompatible types in binary construction:\n\n                   <<x::binary>>\n\n               got type:\n\n                   integer()\n\n               but expected type:\n\n                   binary()\n\n               where \"x\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   <<x>>\n\n               #{hints(:inferred_bitstring_spec)}\n               \"\"\"\n    end\n\n    test \"size ok\" do\n      assert typecheck!([<<x, y>>, z], <<z::size(x - y)>>) == bitstring()\n      assert typedyn!([<<x, y>>, z], <<z::size(x - y)>>) == dynamic(bitstring())\n    end\n\n    test \"size error\" do\n      assert typeerror!([<<x::binary>>, y], <<y::size(x)>>) ==\n               ~l\"\"\"\n               expected an integer in binary size:\n\n                   size(x)\n\n               got type:\n\n                   binary()\n\n               where \"x\" was given the type:\n\n                   # type: binary()\n                   # from: types_test.ex:LINE-1\n                   <<x::binary>>\n               \"\"\"\n    end\n  end\n\n  describe \"tuples\" do\n    test \"creating tuples\" do\n      assert typecheck!({:ok, 123}) == tuple([atom([:ok]), integer()])\n      assert typecheck!([x], {:ok, x}) == dynamic(tuple([atom([:ok]), term()]))\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x, y],\n               (\n                 {:ok, :error} = {x, y}\n                 {x, y}\n               )\n             ) == dynamic(tuple([atom([:ok]), atom([:error])]))\n    end\n\n    test \"elem/2\" do\n      assert typecheck!(elem({:ok, 123}, 0)) == atom([:ok])\n      assert typecheck!(elem({:ok, 123}, 1)) == integer()\n      assert typecheck!([x], elem({:ok, x}, 0)) == dynamic(atom([:ok]))\n      assert typecheck!([x], elem({:ok, x}, 1)) == dynamic(term())\n\n      assert typeerror!([<<x::float>>], elem(x, 0)) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Kernel.elem/2:\n\n                   elem(x, 0)\n\n               given types:\n\n                   float(), integer()\n\n               but expected one of:\n\n                   {...}, integer()\n\n               where \"x\" was given the type:\n\n                   # type: float()\n                   # from: types_test.ex:LINE-1\n                   <<x::float>>\n               \"\"\"\n\n      assert typeerror!(elem({:ok, 123}, 2)) ==\n               ~l\"\"\"\n               expected a tuple with at least 3 elements in Kernel.elem/2:\n\n                   elem({:ok, 123}, 2)\n\n               the given type does not have the given index:\n\n                   {:ok, integer()}\n               \"\"\"\n    end\n\n    test \"Tuple.insert_at/3\" do\n      assert typecheck!(Tuple.insert_at({}, 0, \"foo\")) == tuple([binary()])\n\n      assert typecheck!(Tuple.insert_at({:ok, 123}, 0, \"foo\")) ==\n               tuple([binary(), atom([:ok]), integer()])\n\n      assert typecheck!(Tuple.insert_at({:ok, 123}, 1, \"foo\")) ==\n               tuple([atom([:ok]), binary(), integer()])\n\n      assert typecheck!(Tuple.insert_at({:ok, 123}, 2, \"foo\")) ==\n               tuple([atom([:ok]), integer(), binary()])\n\n      assert typeerror!([<<x::float>>], Tuple.insert_at(x, 0, \"foo\")) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Tuple.insert_at/3:\n\n                   Tuple.insert_at(x, 0, \"foo\")\n\n               given types:\n\n                   float(), integer(), binary()\n\n               but expected one of:\n\n                   {...}, integer(), term()\n\n               where \"x\" was given the type:\n\n                   # type: float()\n                   # from: types_test.ex:LINE-1\n                   <<x::float>>\n               \"\"\"\n\n      assert typeerror!(Tuple.insert_at({:ok, 123}, 3, \"foo\")) ==\n               ~l\"\"\"\n               expected a tuple with at least 3 elements in Tuple.insert_at/3:\n\n                   Tuple.insert_at({:ok, 123}, 3, \"foo\")\n\n               the given type does not have the given index:\n\n                   {:ok, integer()}\n               \"\"\"\n    end\n\n    test \"Tuple.delete_at/2\" do\n      assert typecheck!(Tuple.delete_at({:ok, 123}, 0)) == tuple([integer()])\n      assert typecheck!(Tuple.delete_at({:ok, 123}, 1)) == tuple([atom([:ok])])\n      assert typecheck!([x], Tuple.delete_at({:ok, x}, 0)) == dynamic(tuple([term()]))\n      assert typecheck!([x], Tuple.delete_at({:ok, x}, 1)) == dynamic(tuple([atom([:ok])]))\n\n      assert typeerror!([<<x::float>>], Tuple.delete_at(x, 0)) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Tuple.delete_at/2:\n\n                   Tuple.delete_at(x, 0)\n\n               given types:\n\n                   float(), integer()\n\n               but expected one of:\n\n                   {...}, integer()\n\n               where \"x\" was given the type:\n\n                   # type: float()\n                   # from: types_test.ex:LINE-1\n                   <<x::float>>\n               \"\"\"\n\n      assert typeerror!(Tuple.delete_at({:ok, 123}, 2)) ==\n               ~l\"\"\"\n               expected a tuple with at least 3 elements in Tuple.delete_at/2:\n\n                   Tuple.delete_at({:ok, 123}, 2)\n\n               the given type does not have the given index:\n\n                   {:ok, integer()}\n               \"\"\"\n    end\n\n    test \"Tuple.duplicate/2\" do\n      assert typecheck!(Tuple.duplicate(123, 0)) == tuple([])\n      assert typecheck!(Tuple.duplicate(123, 1)) == tuple([integer()])\n      assert typecheck!(Tuple.duplicate(123, 2)) == tuple([integer(), integer()])\n      assert typecheck!([x], Tuple.duplicate(x, 2)) == dynamic(tuple([term(), term()]))\n    end\n  end\n\n  describe \"maps\" do\n    test \"creating maps as records\" do\n      assert typecheck!(%{foo: :bar}) == closed_map(foo: atom([:bar]))\n      assert typecheck!([x], %{key: x}) == dynamic(closed_map(key: term()))\n    end\n\n    test \"creating maps as records with dynamic keys\" do\n      assert typecheck!(\n               (\n                 foo = :foo\n                 %{foo => :first, foo => :second}\n               )\n             ) == closed_map(foo: atom([:second]))\n\n      assert typecheck!(\n               (\n                 foo_or_bar =\n                   cond do\n                     :rand.uniform() > 0.5 -> :foo\n                     true -> :bar\n                   end\n\n                 %{foo_or_bar => :first, foo_or_bar => :second}\n               )\n             )\n             |> equal?(\n               closed_map(foo: atom([:second]))\n               |> union(closed_map(bar: atom([:second])))\n               |> union(closed_map(foo: atom([:first]), bar: atom([:second])))\n               |> union(closed_map(bar: atom([:first]), foo: atom([:second])))\n             )\n    end\n\n    test \"creating maps as dictionaries\" do\n      assert typecheck!(%{123 => 456}) == closed_map([{domain_key(:integer), integer()}])\n\n      # Since key cannot override :foo based on position, we preserve it\n      assert typecheck!([key], %{key => 456, foo: :bar}) ==\n               dynamic(\n                 closed_map([\n                   {to_domain_keys(:term), integer()},\n                   {:foo, atom([:bar])}\n                 ])\n               )\n\n      # Since key can override :foo based on position, we union it\n      assert typecheck!([key], %{:foo => :bar, key => :baz}) ==\n               dynamic(\n                 closed_map([\n                   {to_domain_keys(:term), atom([:baz])},\n                   {:foo, atom([:bar, :baz])}\n                 ])\n               )\n\n      # Since key cannot override :foo based on domain, we preserve it\n      assert typecheck!(\n               [arg],\n               (\n                 key = String.to_integer(arg)\n                 %{:foo => :bar, key => :baz}\n               )\n             ) ==\n               closed_map([\n                 {domain_key(:integer), atom([:baz])},\n                 {:foo, atom([:bar])}\n               ])\n\n      # Multiple keys are fully overridden for simplicity\n      assert typecheck!(\n               [arg],\n               (\n                 foo_or_bar = if String.starts_with?(arg, \"0\"), do: :foo, else: :bar\n                 key = String.to_integer(arg)\n                 %{foo_or_bar => :old, key => :new}\n               )\n             ) ==\n               union(\n                 closed_map([\n                   {domain_key(:integer), atom([:new])},\n                   {:foo, atom([:old])}\n                 ]),\n                 closed_map([\n                   {domain_key(:integer), atom([:new])},\n                   {:bar, atom([:old])}\n                 ])\n               )\n    end\n\n    test \"updating to maps as records\" do\n      assert typecheck!([x], %{x | x: :zero}) ==\n               dynamic(open_map(x: atom([:zero])))\n\n      assert typecheck!([x], %{%{x | x: :zero} | y: :one}) ==\n               dynamic(open_map(x: atom([:zero]), y: atom([:one])))\n\n      assert typecheck!(\n               (\n                 foo_or_bar =\n                   cond do\n                     :rand.uniform() > 0.5 -> :key1\n                     true -> :key2\n                   end\n\n                 x = %{key1: :one, key2: :two}\n                 %{x | foo_or_bar => :one!, foo_or_bar => :two!}\n               )\n             )\n             |> equal?(\n               closed_map(key1: atom([:one]), key2: atom([:two!]))\n               |> union(closed_map(key1: atom([:two!]), key2: atom([:one!])))\n               |> union(closed_map(key1: atom([:one!]), key2: atom([:two!])))\n               |> union(closed_map(key1: atom([:two!]), key2: atom([:two])))\n             )\n\n      assert typeerror!([x = :foo], %{x | x: :zero}) == ~l\"\"\"\n             expected a map within map update syntax:\n\n                 %{x | x: :zero}\n\n             but got type:\n\n                 dynamic(:foo)\n\n             where \"x\" was given the type:\n\n                 # type: dynamic(:foo)\n                 # from: types_test.ex:LINE\n                 x = :foo\n             \"\"\"\n\n      assert typeerror!(\n               (\n                 x = %{}\n                 %{x | x: :zero}\n               )\n             ) == ~l\"\"\"\n             expected a map with key :x in map update syntax:\n\n                 %{x | x: :zero}\n\n             but got type:\n\n                 empty_map()\n\n             where \"x\" was given the type:\n\n                 # type: empty_map()\n                 # from: types_test.ex:LINE-3\n                 x = %{}\n             \"\"\"\n\n      # Assert we check all possible combinations\n      assert typeerror!(\n               (\n                 foo_or_bar =\n                   cond do\n                     :rand.uniform() > 0.5 -> :foo\n                     true -> :bar\n                   end\n\n                 x = %{foo: :baz}\n                 %{x | foo_or_bar => :bat}\n               )\n             ) == ~l\"\"\"\n             expected a map with key :bar in map update syntax:\n\n                 %{x | foo_or_bar => :bat}\n\n             but got type:\n\n                 %{foo: :baz}\n\n             where \"foo_or_bar\" was given the type:\n\n                 # type: :bar or :foo\n                 # from: types_test.ex:LINE-9\n                 foo_or_bar =\n                   cond do\n                     ...\n                   end\n\n             where \"x\" was given the type:\n\n                 # type: %{foo: :baz}\n                 # from: types_test.ex:LINE-3\n                 x = %{foo: :baz}\n             \"\"\"\n\n      # The goal of this assertion is to verify we assert keys,\n      # even if they may be overridden later.\n      assert typeerror!(\n               [key],\n               (\n                 x = %{key: :value}\n                 %{x | :foo => :baz, key => :bat}\n               )\n             ) == ~l\"\"\"\n             expected a map with key :foo in map update syntax:\n\n                 %{x | :foo => :baz, key => :bat}\n\n             but got type:\n\n                 %{key: :value}\n\n             where \"key\" was given the type:\n\n                 # type: dynamic()\n                 # from: types_test.ex:LINE-5\n                 key\n\n             where \"x\" was given the type:\n\n                 # type: %{key: :value}\n                 # from: types_test.ex:LINE-3\n                 x = %{key: :value}\n             \"\"\"\n    end\n\n    test \"updating to maps as dictionaries\" do\n      assert typecheck!(\n               [key],\n               (\n                 x = %{foo: :bar}\n                 %{x | key => :baz}\n               )\n             ) == closed_map(foo: atom([:bar, :baz]))\n\n      # Override based on position\n      assert typecheck!(\n               [key],\n               (\n                 x = %{foo: :bar, baz: :bat}\n                 %{x | key => :old, foo: :new}\n               )\n             ) == closed_map(foo: atom([:new]), baz: atom([:old, :bat]))\n\n      assert typeerror!(\n               [key],\n               (\n                 x = %{String.to_integer(key) => :old}\n                 %{x | String.to_atom(key) => :new}\n               )\n             ) == ~l\"\"\"\n             expected a map with key of type atom() in map update syntax:\n\n                 %{x | String.to_atom(key) => :new}\n\n             but got type:\n\n                 %{integer() => :old}\n\n             where \"key\" was given the type:\n\n                 # type: binary()\n                 # from: types_test.ex:LINE-3\n                 String.to_integer(key)\n\n             where \"x\" was given the type:\n\n                 # type: %{integer() => :old}\n                 # from: types_test.ex:LINE-3\n                 x = %{String.to_integer(key) => :old}\n             \"\"\"\n\n      assert typeerror!(\n               [key],\n               (\n                 x = %{key: :old}\n                 %{x | String.to_atom(key) => :new}\n               )\n             ) == ~l\"\"\"\n             expected a map with key of type atom() in map update syntax:\n\n                 %{x | String.to_atom(key) => :new}\n\n             but got type:\n\n                 %{key: :old}\n\n             where \"key\" was given the type:\n\n                 # type: binary()\n                 # from: types_test.ex:LINE-2\n                 String.to_atom(key)\n\n             where \"x\" was given the type:\n\n                 # type: %{key: :old}\n                 # from: types_test.ex:LINE-3\n                 x = %{key: :old}\n             \"\"\"\n    end\n\n    test \"nested map\" do\n      assert typecheck!([x = %{}], x.foo.bar) == dynamic()\n    end\n\n    test \"accessing a field on not a map\" do\n      assert typeerror!([<<x::integer>>], x.foo_bar) ==\n               ~l\"\"\"\n               expected a map or struct when accessing .foo_bar in expression:\n\n                   x.foo_bar\n\n               where \"x\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   <<x::integer>>\n\n               #{hints(:dot)}\n               \"\"\"\n    end\n  end\n\n  describe \"structs\" do\n    test \"creating structs\" do\n      assert typecheck!(%Point{}) ==\n               closed_map(\n                 __struct__: atom([Point]),\n                 x: atom([nil]),\n                 y: atom([nil]),\n                 z: integer()\n               )\n\n      assert typecheck!(%Point{x: :zero}) ==\n               closed_map(\n                 __struct__: atom([Point]),\n                 x: atom([:zero]),\n                 y: atom([nil]),\n                 z: integer()\n               )\n    end\n\n    test \"updating unknown struct\" do\n      {_, [diagnostic]} = typediag!([x], %UNKNOWN.URI{x | foo: 123})\n      assert diagnostic.severity == :warning\n\n      assert diagnostic.message ==\n               \"struct UNKNOWN.URI is undefined (module UNKNOWN.URI is not available or is yet to be defined)\"\n\n      {_, [diagnostic]} = typediag!([x], %Enumerable{x | foo: 123})\n      assert diagnostic.severity == :warning\n\n      assert diagnostic.message ==\n               \"struct Enumerable is undefined (there is such module but it does not define a struct)\"\n    end\n\n    test \"updating field in unknown struct\" do\n      assert typeerror!(\n               [x],\n               (\n                 %UNKNOWN.URI{x | foo: y = 123}\n                 y\n               )\n             ) =~\n               \"struct UNKNOWN.URI is undefined (module UNKNOWN.URI is not available or is yet to be defined)\"\n    end\n\n    test \"updating unknown field\" do\n      {_, [diagnostic]} = typediag!([%URI{} = x], %URI{x | unknown: 123})\n      assert diagnostic.severity == :warning\n      assert diagnostic.message == \"unknown key :unknown for struct URI\"\n    end\n\n    test \"updating structs\" do\n      integer_date_type =\n        dynamic(\n          closed_map(\n            __struct__: atom([Date]),\n            day: integer(),\n            calendar: atom(),\n            month: term(),\n            year: term()\n          )\n        )\n\n      # When we know the type\n      assert typecheck!([], %Date{Date.new!(1, 1, 1) | day: 31}) ==\n               integer_date_type\n\n      assert typecheck!([], %Date{%Date{Date.new!(1, 1, 1) | day: 13} | day: 31}) ==\n               integer_date_type\n\n      # When we don't know the type of var\n      assert typeerror!([x], %Date{x | day: 31}) == ~l\"\"\"\n             a struct for Date is expected on struct update:\n\n                 %Date{x | day: 31}\n\n             but got type:\n\n                 dynamic()\n\n             where \"x\" was given the type:\n\n                 # type: dynamic()\n                 # from: types_test.ex:LINE\n                 x\n\n             when defining the variable \"x\", you must also pattern match on \"%Date{}\"\n             \"\"\"\n\n      # When we don't know the type of capture\n      assert typeerror!([], &%Date{&1 | day: 31}) =~ ~l\"\"\"\n             a struct for Date is expected on struct update:\n\n                 %Date{&1 | day: 31}\n\n             but got type:\n\n                 dynamic()\n\n             where \"capture\" was given the type:\n\n                 # type: dynamic()\n                 # from: types_test.ex:LINE\n                 &1\n\n             instead of using &1, you must define an anonymous function, define a variable and pattern match on \"%Date{}\"\n             \"\"\"\n\n      # When we don't know the type of expression\n      assert typeerror!([], %Date{SomeMod.fun() | day: 31}) =~ \"\"\"\n             a struct for Date is expected on struct update:\n\n                 %Date{SomeMod.fun() | day: 31}\n\n             but got type:\n\n                 dynamic()\n\n             you must assign \"SomeMod.fun()\" to variable and pattern match on \"%Date{}\"\n             \"\"\"\n    end\n\n    test \"accessing an unknown field on struct with diagnostic\" do\n      {type, [diagnostic]} = typediag!(%Point{}.foo_bar)\n      assert type == dynamic()\n      assert diagnostic.span == {__ENV__.line - 2, 56}\n\n      assert diagnostic.message == ~l\"\"\"\n             unknown key .foo_bar in expression:\n\n                 %Point{x: nil, y: nil, z: 0}.foo_bar\n\n             the given type does not have the given key:\n\n                 %Point{x: nil, y: nil, z: integer()}\n             \"\"\"\n    end\n\n    test \"accessing an unknown field on struct in a var with diagnostic\" do\n      {type, [diagnostic]} = typediag!([x = %URI{}], x.foo_bar)\n      assert type == dynamic()\n      assert diagnostic.span == {__ENV__.line - 2, 63}\n\n      assert diagnostic.message == ~l\"\"\"\n             unknown key .foo_bar in expression:\n\n                 x.foo_bar\n\n             the given type does not have the given key:\n\n                 dynamic(%URI{\n                   scheme: term(),\n                   authority: term(),\n                   userinfo: term(),\n                   host: term(),\n                   port: term(),\n                   path: term(),\n                   query: term(),\n                   fragment: term()\n                 })\n\n             where \"x\" was given the type:\n\n                 # type: dynamic(%URI{})\n                 # from: types_test.ex:LINE-4:43\n                 x = %URI{}\n             \"\"\"\n\n      assert [%{type: :variable, name: :x}] = diagnostic.details.typing_traces\n    end\n\n    test \"inspect struct definition\" do\n      assert typeerror!(\n               (\n                 p = %Point{x: 123}\n                 Integer.to_string(p)\n               )\n             )\n             |> strip_ansi() == ~l\"\"\"\n             incompatible types given to Integer.to_string/1:\n\n                 Integer.to_string(p)\n\n             given types:\n\n                 %Point{x: integer(), y: nil, z: integer()}\n\n             but expected one of:\n\n                 integer()\n\n             where \"p\" was given the type:\n\n                 # type: %Point{x: integer(), y: nil, z: integer()}\n                 # from: types_test.ex:LINE-4\n                 p = %Point{..., x: 123}\n             \"\"\"\n    end\n  end\n\n  describe \"comparison\" do\n    test \"in static mode\" do\n      assert typecheck!([x = 123, y = 456.0], x < y) == boolean()\n      assert typecheck!([x = 123, y = 456.0], x == y) == boolean()\n    end\n\n    test \"in dynamic mode\" do\n      assert typedyn!([x = 123, y = 456.0], x < y) == dynamic(boolean())\n      assert typedyn!([x = 123, y = 456.0], x == y) == dynamic(boolean())\n      assert typedyn!([x = 123, y = 456], x == y) == dynamic(boolean())\n    end\n\n    test \"using literals\" do\n      assert typecheck!(:foo == :bar) == boolean()\n    end\n\n    test \"min/max\" do\n      assert typecheck!(min(123, 456.0)) == union(integer(), float())\n      # min/max uses parametric types, which will carry dynamic regardless of being a strong arrow\n      assert typecheck!([x = 123, y = 456.0], min(x, y)) == dynamic(union(integer(), float()))\n    end\n\n    test \"warns when comparison is constant\" do\n      assert typeerror!([x = :foo, y = 321], min(x, y)) ==\n               ~l\"\"\"\n               comparison between distinct types found:\n\n                   min(x, y)\n\n               given types:\n\n                   min(dynamic(:foo), integer())\n\n               where \"x\" was given the type:\n\n                   # type: dynamic(:foo)\n                   # from: types_test.ex:LINE-1\n                   x = :foo\n\n               where \"y\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   y = 321\n\n               While Elixir can compare across all types, you are comparing across types \\\n               which are always disjoint, and the result is either always true or always false\n               \"\"\"\n\n      assert typeerror!([x = 123, y = 456.0], x === y) ==\n               ~l\"\"\"\n               comparison between distinct types found:\n\n                   x === y\n\n               given types:\n\n                   integer() === float()\n\n               where \"x\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   x = 123\n\n               where \"y\" was given the type:\n\n                   # type: float()\n                   # from: types_test.ex:LINE-1\n                   y = 456.0\n\n               While Elixir can compare across all types, you are comparing across types \\\n               which are always disjoint, and the result is either always true or always false\n               \"\"\"\n    end\n\n    test \"warns on comparison with struct across dynamic call\" do\n      assert typeerror!([x = %Point{}, y = %Point{}, mod = Kernel], mod.<=(x, y)) ==\n               ~l\"\"\"\n               comparison with structs found:\n\n                   mod.<=(x, y)\n\n               given types:\n\n                   dynamic(%Point{}) <= dynamic(%Point{})\n\n               where \"mod\" was given the type:\n\n                   # type: dynamic(Kernel)\n                   # from: types_test.ex:LINE-1\n                   mod = Kernel\n\n               where \"x\" was given the type:\n\n                   # type: dynamic(%Point{})\n                   # from: types_test.ex:LINE-1\n                   x = %Point{}\n\n               where \"y\" was given the type:\n\n                   # type: dynamic(%Point{})\n                   # from: types_test.ex:LINE-1\n                   y = %Point{}\n\n               Comparison operators (>, <, >=, <=, min, and max) perform structural and not semantic comparison. Comparing with a struct won't give meaningful results. Structs that can be compared typically define a compare/2 function within their modules that can be used for semantic comparison.\n               \"\"\"\n\n      assert typeerror!(\n               [x = %Point{}, mod = Kernel, condition],\n               (\n                 y = if condition, do: 456, else: %Point{}\n                 mod.<=(x, y)\n               )\n             ) =~ \"comparison with structs found:\"\n\n      assert typecheck!(\n               [x = 123, mod = Kernel, condition],\n               (\n                 y = if condition, do: 456, else: %Point{}\n                 mod.<=(x, y)\n               )\n             ) == boolean()\n\n      assert typeerror!(\n               [mod = Kernel, condition],\n               (\n                 x = if condition, do: 123, else: %Point{}\n                 y = if condition, do: 456, else: %Point{}\n                 mod.<=(x, y)\n               )\n             ) =~ \"comparison with structs found:\"\n    end\n  end\n\n  describe \":erlang rewrites\" do\n    test \"Kernel.not/1\" do\n      assert typecheck!([x], not is_list(x)) == boolean()\n    end\n\n    test \"Kernel.+/2\" do\n      assert typeerror!([x = :foo, y = 123], x + y) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Kernel.+/2:\n\n                   x + y\n\n               given types:\n\n                   dynamic(:foo), integer()\n\n               but expected one of:\n\n                   #1\n                   integer(), integer()\n\n                   #2\n                   integer(), float()\n\n                   #3\n                   float(), integer()\n\n                   #4\n                   float(), float()\n\n               where \"x\" was given the type:\n\n                   # type: dynamic(:foo)\n                   # from: types_test.ex:LINE-1\n                   x = :foo\n\n               where \"y\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   y = 123\n               \"\"\"\n    end\n\n    test \"Integer.to_string/1\" do\n      assert typecheck!([x = 123], Integer.to_string(x)) == binary()\n\n      assert typeerror!([x = :foo], Integer.to_string(x)) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Integer.to_string/1:\n\n                   Integer.to_string(x)\n\n               given types:\n\n                   dynamic(:foo)\n\n               but expected one of:\n\n                   integer()\n\n               where \"x\" was given the type:\n\n                   # type: dynamic(:foo)\n                   # from: types_test.ex:LINE-1\n                   x = :foo\n               \"\"\"\n    end\n\n    test \"Bitwise.bnot/1\" do\n      assert typecheck!([x = 123], Bitwise.bnot(x)) == integer()\n\n      assert typeerror!([x = :foo], Bitwise.bnot(x)) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Bitwise.bnot/1:\n\n                   Bitwise.bnot(x)\n\n               given types:\n\n                   dynamic(:foo)\n\n               but expected one of:\n\n                   integer()\n\n               where \"x\" was given the type:\n\n                   # type: dynamic(:foo)\n                   # from: types_test.ex:LINE-1\n                   x = :foo\n               \"\"\"\n    end\n\n    test \"Kernel.in/2\" do\n      assert typecheck!(\n               [x],\n               (\n                 true = x in [:foo, 1, :bar, 2.0, :baz]\n                 x\n               )\n             ) ==\n               dynamic(union(atom([:foo, :bar, :baz]), union(integer(), float())))\n\n      assert typecheck!(\n               [x],\n               (\n                 false = x in [:foo, 1, :bar, 2.0, :baz]\n                 x\n               )\n             ) ==\n               dynamic(negation(atom([:foo, :bar, :baz])))\n\n      assert typecheck!(\n               [x],\n               (\n                 true = x not in [:foo, 1, :bar, 2.0, :baz]\n                 x\n               )\n             ) ==\n               dynamic(negation(atom([:foo, :bar, :baz])))\n\n      assert typecheck!(\n               [x],\n               (\n                 false = x not in [:foo, 1, :bar, 2.0, :baz]\n                 x\n               )\n             ) ==\n               dynamic(union(atom([:foo, :bar, :baz]), union(integer(), float())))\n\n      assert typeerror!([x = :ok], true = x in [:foo, 1.0, :baz]) =~ ~l\"\"\"\n             comparison between distinct types found:\n\n                 x in [:foo, 1.0, :baz]\n\n             given types:\n\n                 dynamic(:ok) in list(:baz or :foo or float())\n\n             where \"x\" was given the type:\n\n                 # type: dynamic(:ok)\n                 # from: types_test.ex:LINE\n                 x = :ok\n             \"\"\"\n\n      assert typeerror!(\n               [x],\n               (\n                 true = x in [:foo, :bar]\n                 :baz = x\n               )\n             ) == ~l\"\"\"\n             the following pattern will never match:\n\n                 :baz = x\n\n             because the right-hand side has type:\n\n                 dynamic(:bar or :foo)\n\n             where \"x\" was given the type:\n\n                 # type: dynamic(:bar or :foo)\n                 # from: types_test.ex:LINE-3\n                 x in [:foo, :bar]\n             \"\"\"\n    end\n  end\n\n  describe \"case\" do\n    test \"does not type check literals\" do\n      assert typecheck!(\n               case :dev do\n                 :dev -> :ok\n                 :prod -> :error\n               end\n             ) == atom([:ok, :error])\n    end\n\n    test \"resets branches\" do\n      assert typecheck!(\n               [x],\n               (\n                 case :rand.uniform() do\n                   y when y < 0.5 -> x.foo\n                   y when y > 0.5 -> x.bar()\n                 end\n\n                 x\n               )\n             ) == dynamic()\n    end\n\n    test \"returns unions of all clauses\" do\n      assert typecheck!(\n               [x],\n               case x do\n                 :ok -> :ok\n                 :error -> :error\n               end\n             ) == atom([:ok, :error])\n\n      assert typedyn!(\n               [x],\n               case x do\n                 :ok -> :ok\n                 :error -> :error\n               end\n             ) == dynamic(atom([:ok, :error]))\n    end\n\n    defmacrop generated(op) do\n      Macro.update_meta(op, &([generated: true] ++ &1))\n    end\n\n    test \"ignores always failing guards\" do\n      assert typecheck!(\n               case System.get_env(\"foo\") do\n                 x when generated(x == false) or byte_size(x) >= 0 -> :binary\n                 _ -> nil\n               end\n             ) == atom([nil, :binary])\n\n      assert typecheck!(\n               case System.get_env(\"foo\") do\n                 x when generated(x == false) or x == nil -> nil\n                 _ -> :binary\n               end\n             ) == atom([nil, :binary])\n    end\n\n    test \"computes types based on previous branches\" do\n      assert typecheck!(\n               [condition],\n               case condition do\n                 x when is_binary(x) -> {:binary, x}\n                 x when is_bitstring(x) -> {:bitstring, x}\n               end\n             ) ==\n               dynamic(\n                 union(\n                   tuple([atom([:binary]), binary()]),\n                   tuple([atom([:bitstring]), bitstring_no_binary()])\n                 )\n               )\n\n      assert typecheck!(\n               [condition],\n               case condition do\n                 x = %{} when x != %{} -> :non_empty_map\n                 %{} -> :maybe_empty_map\n               end\n             ) ==\n               atom([:non_empty_map, :maybe_empty_map])\n    end\n\n    test \"warns on redundant clauses\" do\n      assert typewarn!(\n               [x],\n               case System.get_env(x) do\n                 nil -> 1\n                 b when is_binary(b) -> 2\n                 other -> other\n               end\n             )\n             |> elem(1) =~ ~l\"\"\"\n             the following clause cannot match because the previous clauses already matched all possible values:\n\n                 other ->\n\n             it attempts to match on the result of:\n\n                 System.get_env(x)\n\n             which has the already matched type:\n\n                 dynamic(nil or binary())\n             \"\"\"\n\n      assert typewarn!(\n               [x],\n               case String.to_atom(x) do\n                 :ok -> 1\n                 :ok -> 2\n               end\n             )\n             |> elem(1) == ~l\"\"\"\n             the following clause is redundant:\n\n                 :ok ->\n\n             previous clauses have already matched on the following types:\n\n                 :ok\n             \"\"\"\n\n      assert typewarn!(\n               [a, b],\n               case {a, b} do\n                 {x, y} when is_integer(x) and is_integer(y) -> 1\n                 {x, y} when is_integer(x) and is_integer(y) -> 2\n               end\n             )\n             |> elem(1) =~ ~l\"\"\"\n             the following clause is redundant:\n\n                 {x, y} when is_integer(x) and is_integer(y) ->\n\n             previous clauses have already matched on the following types:\n\n                 {integer(), integer()}\n             \"\"\"\n    end\n\n    test \"reports error from clause that will never match\" do\n      assert typeerror!(\n               [x],\n               case Atom.to_string(x) do\n                 :error -> :error\n                 x -> x\n               end\n             ) == ~l\"\"\"\n             the following clause will never match:\n\n                 :error ->\n\n             because it attempts to match on the result of:\n\n                 Atom.to_string(x)\n\n             which has type:\n\n                 binary()\n             \"\"\"\n    end\n\n    test \"reports errors from multiple clauses\" do\n      {type, [_, _]} =\n        typediag!(\n          [x],\n          case Atom.to_string(x) do\n            :ok -> :ok\n            :error -> :error\n          end\n        )\n\n      assert type == atom([:ok, :error])\n    end\n  end\n\n  describe \"conditionals\" do\n    test \"if does not report on literals\" do\n      assert typecheck!(\n               if true do\n                 :ok\n               end\n             ) == atom([:ok, nil])\n    end\n\n    test \"and/or does not report on literals\" do\n      assert typecheck!(false and true) == boolean()\n      assert typecheck!(false or true) == atom([true])\n    end\n\n    test \"and reports violations\" do\n      assert typeerror!([x = 123], x and true) =~ \"\"\"\n             the following conditional expression will always fail:\n\n                 x\n\n             because it evaluates to:\n\n                 integer()\n             \"\"\"\n\n      assert typeerror!([x = true], x and true) =~ \"\"\"\n             the following conditional expression will always succeed:\n\n                 x\n\n             because it evaluates to:\n\n                 dynamic(true)\n             \"\"\"\n\n      assert typeerror!([x = false], x and true) =~ \"\"\"\n             the following conditional expression will never succeed:\n\n                 x\n\n             because it evaluates to:\n\n                 dynamic(false)\n             \"\"\"\n    end\n\n    test \"or reports violations\" do\n      assert typeerror!([x = 123], x or true) =~ \"\"\"\n             the following conditional expression will always fail:\n\n                 x\n\n             because it evaluates to:\n\n                 integer()\n             \"\"\"\n\n      assert typeerror!([x = true], x or true) =~ \"\"\"\n             the following conditional expression will always succeed:\n\n                 x\n\n             because it evaluates to:\n\n                 dynamic(true)\n             \"\"\"\n\n      assert typeerror!([x = false], x or true) =~ \"\"\"\n             the following conditional expression will never succeed:\n\n                 x\n\n             because it evaluates to:\n\n                 dynamic(false)\n             \"\"\"\n    end\n\n    test \"|| reports violations\" do\n      assert typeerror!([x = 123], x || true) =~ \"\"\"\n             the right-hand side of || will never be executed:\n\n                 x || ...\n\n             because the left-hand side always evaluates to:\n\n                 integer()\n\n             \"\"\"\n\n      assert typeerror!([x = 123], System.get_env(\"foo\") || x || true) =~ \"\"\"\n             the right-hand side of || (shown as ... below) will never be executed:\n\n                 System.get_env(\"foo\") || x || ...\n\n             because the left-hand side always evaluates to:\n\n                 dynamic(binary() or integer())\n\n             \"\"\"\n\n      assert typewarn!([x = false], x || true) |> elem(1) =~ \"\"\"\n             the right-hand side of || will always execute:\n\n                 x\n\n             because the left-hand side always evaluates to:\n\n                 dynamic(false)\n             \"\"\"\n    end\n  end\n\n  describe \"receive\" do\n    test \"returns unions of all clauses\" do\n      assert typecheck!(\n               receive do\n                 :ok -> :ok\n                 :error -> :error\n               after\n                 0 -> :timeout\n               end\n             ) == atom([:ok, :error, :timeout])\n\n      assert typedyn!(\n               receive do\n                 :ok -> :ok\n                 :error -> :error\n               after\n                 0 -> :timeout\n               end\n             ) == dynamic(atom([:ok, :error, :timeout]))\n    end\n\n    test \"infers type for timeout\" do\n      assert typecheck!(\n               [x],\n               receive do\n               after\n                 x -> x\n               end\n             ) == dynamic(union(integer(), atom([:infinity])))\n    end\n\n    test \"resets branches\" do\n      assert typecheck!(\n               [x, timeout = :infinity],\n               (\n                 receive do\n                   y when y > 0.5 -> x.foo\n                   _ -> x.bar()\n                 after\n                   timeout -> <<^x::integer>> = :crypto.strong_rand_bytes(1)\n                 end\n\n                 x\n               )\n             ) == dynamic()\n    end\n\n    test \"computes difference across clauses\" do\n      assert typecheck!(\n               receive do\n                 x when is_binary(x) -> :ok\n                 y -> {:other, y}\n               end\n             ) == union(atom([:ok]), dynamic(tuple([atom([:other]), negation(binary())])))\n    end\n\n    test \"warns on redundant clauses\" do\n      assert typewarn!(\n               receive do\n                 x when is_binary(x) -> x\n                 \"foo\" -> \"bar\"\n               end\n             )\n             |> elem(1) == \"\"\"\n             the following clause is redundant:\n\n                 \"foo\" ->\n\n             previous clauses have already matched on the following types:\n\n                 binary()\n             \"\"\"\n    end\n\n    test \"errors on bad timeout\" do\n      assert typeerror!(\n               [x = :timeout],\n               receive do\n               after\n                 x -> :ok\n               end\n             ) == ~l\"\"\"\n             expected \"after\" timeout given to receive to be an integer:\n\n                 x\n\n             but got type:\n\n                 dynamic(:timeout)\n\n             where \"x\" was given the type:\n\n                 # type: dynamic(:timeout)\n                 # from: types_test.ex:LINE-5\n                 x = :timeout\n             \"\"\"\n\n      # Check for compatibility, not subtyping\n      assert typeerror!(\n               [<<x::integer, y::float>>],\n               receive do\n               after\n                 if(:rand.uniform(), do: x, else: y) -> :ok\n               end\n             ) =~ \"expected \"\n    after\n      \" timeout given to receive to be an integer\"\n    end\n  end\n\n  describe \"try\" do\n    test \"returns unions of all clauses\" do\n      assert typecheck!(\n               try do\n                 :do\n               rescue\n                 _ -> :rescue\n               catch\n                 :implicit_caught -> :caught1\n                 :throw, :explicit_caught -> :caught2\n               after\n                 :not_used\n               end\n             ) == atom([:do, :caught1, :caught2, :rescue])\n\n      assert typecheck!(\n               [x],\n               try do\n                 x\n               rescue\n                 _ -> :rescue\n               catch\n                 :implicit_caught -> :caught1\n                 :throw, :explicit_caught -> :caught2\n               after\n                 :not_used\n               else\n                 :match -> :else1\n                 _ -> :else2\n               end\n             ) == atom([:caught1, :caught2, :rescue, :else1, :else2])\n    end\n\n    test \"resets branches (except after)\" do\n      assert typecheck!(\n               [x],\n               (\n                 try do\n                   <<^x::float>> = :crypto.strong_rand_bytes(8)\n                 rescue\n                   ArgumentError -> x.foo\n                 catch\n                   _, _ -> x.bar()\n                 after\n                   <<^x::integer>> = :crypto.strong_rand_bytes(8)\n                 end\n\n                 x\n               )\n             ) == dynamic(integer())\n    end\n\n    test \"catch: computes difference across clauses\" do\n      assert typecheck!(\n               try do\n                 flunk(\"whatever\")\n               catch\n                 x when is_binary(x) -> :ok\n                 y -> {:other, y}\n               end\n             ) == union(atom([:ok]), dynamic(tuple([atom([:other]), negation(binary())])))\n    end\n\n    test \"catch: warns on redundant clauses\" do\n      assert typewarn!(\n               try do\n                 flunk(\"whatever\")\n               catch\n                 x when is_binary(x) -> x\n                 \"foo\" -> \"bar\"\n               end\n             )\n             |> elem(1) == \"\"\"\n             the following clause is redundant:\n\n                 :throw, \"foo\" ->\n\n             previous clauses have already matched on the following types:\n\n                 :throw, binary()\n             \"\"\"\n    end\n\n    test \"else: computes difference across clauses\" do\n      assert typecheck!(\n               try do\n                 Process.get(:x)\n               rescue\n                 _ -> :unused\n               else\n                 x when is_binary(x) -> :ok\n                 y -> {:other, y}\n               end\n             ) ==\n               union(atom([:ok, :unused]), dynamic(tuple([atom([:other]), negation(binary())])))\n    end\n\n    test \"else: warns on redundant clauses\" do\n      assert typewarn!(\n               try do\n                 Process.get(:x)\n               rescue\n                 _ -> :unused\n               else\n                 x when is_binary(x) -> x\n                 \"foo\" -> \"bar\"\n               end\n             )\n             |> elem(1) == \"\"\"\n             the following clause is redundant:\n\n                 \"foo\" ->\n\n             previous clauses have already matched on the following types:\n\n                 binary()\n             \"\"\"\n    end\n\n    test \"else: reports error from clause that will never match\" do\n      assert typeerror!(\n               [x],\n               try do\n                 Atom.to_string(x)\n               rescue\n                 _ -> :ok\n               else\n                 :error -> :error\n                 x -> x\n               end\n             ) == ~l\"\"\"\n             the following clause will never match:\n\n                 :error ->\n\n             because it attempts to match on the result of:\n\n                 Atom.to_string(x)\n\n             which has type:\n\n                 binary()\n             \"\"\"\n    end\n\n    test \"rescue: defines unions of exceptions\" do\n      assert typecheck!(\n               try do\n                 raise \"oops\"\n               rescue\n                 e in [RuntimeError, ArgumentError] ->\n                   e\n               end\n             ) ==\n               dynamic(\n                 union(\n                   closed_map(\n                     __struct__: atom([ArgumentError]),\n                     __exception__: atom([true]),\n                     message: term()\n                   ),\n                   closed_map(\n                     __struct__: atom([RuntimeError]),\n                     __exception__: atom([true]),\n                     message: term()\n                   )\n                 )\n               )\n    end\n\n    test \"rescue: defines an open map of two fields in anonymous rescue\" do\n      assert typecheck!(\n               try do\n                 raise \"oops\"\n               rescue\n                 e -> e\n               end\n             ) ==\n               open_map(\n                 __struct__: atom(),\n                 __exception__: atom([true])\n               )\n    end\n\n    test \"rescue: generates custom traces\" do\n      assert typeerror!(\n               try do\n                 raise \"oops\"\n               rescue\n                 e -> Integer.to_string(e)\n               end\n             )\n             |> strip_ansi() == ~l\"\"\"\n             incompatible types given to Integer.to_string/1:\n\n                 Integer.to_string(e)\n\n             given types:\n\n                 %{..., __exception__: true, __struct__: atom()}\n\n             but expected one of:\n\n                 integer()\n\n             where \"e\" was given the type:\n\n                 # type: %{..., __exception__: true, __struct__: atom()}\n                 # from: types_test.ex\n                 rescue e\n\n             hint: when you rescue without specifying exception names, the variable is assigned a type of a struct but all of its fields are unknown. If you are trying to access an exception's :message key, either specify the exception names or use `Exception.message/1`.\n             \"\"\"\n    end\n\n    test \"rescue: errors on undefined exceptions\" do\n      assert typeerror!(\n               try do\n                 :ok\n               rescue\n                 e in UnknownError -> e\n               end\n             ) ==\n               \"struct UnknownError is undefined (module UnknownError is not available or is yet to be defined)\"\n\n      assert typeerror!(\n               try do\n                 :ok\n               rescue\n                 e in Enumerable -> e\n               end\n             ) ==\n               \"struct Enumerable is undefined (there is such module but it does not define a struct)\"\n    end\n\n    test \"rescue: matches on stacktrace\" do\n      assert typeerror!(\n               try do\n                 :ok\n               rescue\n                 _ ->\n                   [{_, _, args_or_arity, _} | _] = __STACKTRACE__\n                   args_or_arity.fun()\n               end\n             ) =~ ~l\"\"\"\n             expected a module (an atom) when invoking fun/0 in expression:\n\n                 args_or_arity.fun()\n\n             where \"args_or_arity\" was given the type:\n\n                 # type: integer() or list(term())\n                 # from: types_test.ex:LINE-3\n                 [{_, _, args_or_arity, _} | _] = __STACKTRACE__\n             \"\"\"\n    end\n  end\n\n  describe \"cond\" do\n    test \"always true\" do\n      assert typecheck!(\n               cond do\n                 true -> :ok\n               end\n             ) == atom([:ok])\n\n      assert typecheck!(\n               [x, y],\n               cond do\n                 y -> :y\n                 x -> :x\n               end\n             ) == atom([:x, :y])\n\n      assert typedyn!(\n               [x, y],\n               cond do\n                 y -> :y\n                 x -> :x\n               end\n             ) == dynamic(atom([:x, :y]))\n\n      assert typewarn!(\n               [x, y = {:foo, :bar}],\n               cond do\n                 y -> :y\n                 x -> :x\n               end\n             ) ==\n               {atom([:x, :y]),\n                ~l\"\"\"\n                this clause in cond will always match:\n\n                    y\n\n                since it has type:\n\n                    dynamic({:foo, :bar})\n\n                where \"y\" was given the type:\n\n                    # type: dynamic({:foo, :bar})\n                    # from: types_test.ex:LINE-7\n                    y = {:foo, :bar}\n                \"\"\"}\n    end\n\n    test \"always false\" do\n      assert typewarn!(\n               [x, y = false],\n               cond do\n                 y -> :y\n                 x -> :x\n               end\n             ) ==\n               {atom([:x, :y]),\n                ~l\"\"\"\n                this clause in cond will never match:\n\n                    y\n\n                since it has type:\n\n                    dynamic(false)\n\n                where \"y\" was given the type:\n\n                    # type: dynamic(false)\n                    # from: types_test.ex:LINE-7\n                    y = false\n                \"\"\"}\n    end\n\n    test \"resets branches\" do\n      assert typecheck!(\n               [x],\n               (\n                 cond do\n                   :rand.uniform() > 0.5 -> x.foo\n                   true -> x.bar()\n                 end\n\n                 x\n               )\n             ) == dynamic()\n    end\n  end\n\n  describe \"comprehensions\" do\n    test \"bitstring generators\" do\n      assert typeerror!([<<x>>], for(<<y <- x>>, do: y)) ==\n               ~l\"\"\"\n               expected the right side of <- in a binary generator to be a binary (or bitstring):\n\n                   x\n\n               but got type:\n\n                   integer()\n\n               where \"x\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   <<x>>\n\n               #{hints(:inferred_bitstring_spec)}\n               \"\"\"\n\n      # Check for compatibility, not subtyping\n      assert typeerror!(\n               [<<x::integer, y::binary>>],\n               for(<<i <- if(:rand.uniform() > 0.5, do: x, else: y)>>, do: i)\n             ) =~\n               ~l\"\"\"\n               expected the right side of <- in a binary generator to be a binary (or bitstring):\n\n                   if :rand.uniform() > 0.5 do\n                     x\n                   else\n                     y\n                   end\n\n               but got type:\n\n                   binary() or integer()\n\n               where \"x\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-3\n                   <<x::integer, ...>>\n\n               where \"y\" was given the type:\n\n                   # type: binary()\n                   # from: types_test.ex:LINE-3\n                   <<..., y::binary>>\n               \"\"\"\n    end\n\n    test \"infers bitstring generators\" do\n      assert typecheck!(\n               [x],\n               (\n                 for <<_ <- x>>, do: :ok\n                 x\n               )\n             ) == dynamic(bitstring())\n    end\n\n    test \":into\" do\n      assert typecheck!([binary], for(<<x <- binary>>, do: x)) == list(integer())\n      assert typecheck!([binary], for(<<x <- binary>>, do: x, into: [])) == list(integer())\n      assert typecheck!([binary], for(<<x <- binary>>, do: <<x>>, into: \"\")) |> equal?(binary())\n      assert typecheck!([binary, other], for(<<x <- binary>>, do: x, into: other)) == dynamic()\n\n      assert typecheck!([enum], for(x <- enum, do: x)) ==\n               union(list(dynamic()), empty_list())\n\n      assert typecheck!([enum], for(x <- enum, do: x, into: [])) ==\n               union(list(dynamic()), empty_list())\n\n      assert typecheck!([enum], for(x <- enum, do: <<x>>, into: \"\")) |> equal?(binary())\n      assert typecheck!([enum, other], for(x <- enum, do: x, into: other)) == dynamic()\n\n      assert typecheck!(\n               [binary],\n               (\n                 into = if :rand.uniform() > 0.5, do: [], else: \"0\"\n                 for(<<x::float <- binary>>, do: x, into: into)\n               )\n             ) == union(bitstring(), list(term()))\n\n      assert typecheck!(\n               [binary, empty_list = []],\n               (\n                 into = if :rand.uniform() > 0.5, do: empty_list, else: \"0\"\n                 for(<<x::float <- binary>>, do: x, into: into)\n               )\n             ) == union(bitstring(), list(term()))\n    end\n\n    test \":into incompatibility\" do\n      assert typeerror!([binary], for(<<x <- binary>>, do: x, into: \"\")) =~ ~l\"\"\"\n             expected the body of a for-comprehension with into: binary() (or bitstring()) to be a binary (or bitstring):\n\n                 x\n\n             but got type:\n\n                 integer()\n\n             where \"x\" was given the type:\n\n                 # type: integer()\n                 # from: types_test.ex:LINE\n                 <<x>>\n             \"\"\"\n    end\n\n    test \":reduce checks\" do\n      assert typecheck!(\n               [list],\n               for _ <- list, reduce: :ok do\n                 :ok -> 1\n                 _ -> 2.0\n               end\n             ) == union(atom([:ok]), union(integer(), float()))\n    end\n\n    test \":reduce inference\" do\n      assert typecheck!(\n               [list, x],\n               (\n                 123 =\n                   for _ <- list, reduce: x do\n                     x -> x\n                   end\n\n                 x\n               )\n             ) == dynamic(integer())\n    end\n\n    test \":reduce warns on redundant clauses\" do\n      assert typewarn!(\n               [list, x],\n               for _ <- list, reduce: x do\n                 x when is_binary(x) -> x\n                 \"foo\" -> \"bar\"\n               end\n             )\n             |> elem(1) == \"\"\"\n             the following clause is redundant:\n\n                 \"foo\" ->\n\n             previous clauses have already matched on the following types:\n\n                 binary()\n             \"\"\"\n    end\n  end\n\n  describe \"with\" do\n    test \"warns on redundant clauses in else\" do\n      assert typewarn!(\n               [x],\n               with false <- x do\n                 x\n               else\n                 x when is_binary(x) -> x\n                 \"foo\" -> \"bar\"\n               end\n             )\n             |> elem(1) == ~l\"\"\"\n             the following clause is redundant:\n\n                 \"foo\" ->\n\n             previous clauses have already matched on the following types:\n\n                 binary()\n             \"\"\"\n    end\n  end\n\n  describe \"info\" do\n    test \"__info__/1\" do\n      assert typecheck!(GenServer.__info__(:functions)) == list(tuple([atom(), integer()]))\n\n      assert typewarn!(:string.__info__(:functions)) ==\n               {dynamic(), \":string.__info__/1 is undefined or private\"}\n\n      assert typecheck!([x], x.__info__(:functions)) == list(tuple([atom(), integer()]))\n\n      assert typeerror!([x], x.__info__(:whatever)) |> strip_ansi() =~ \"\"\"\n             incompatible types given to __info__/1:\n\n                 x.__info__(:whatever)\n\n             given types:\n\n                 :whatever\n             \"\"\"\n    end\n\n    test \"__info__/1 for struct information\" do\n      assert typecheck!(GenServer.__info__(:struct)) == atom([nil])\n\n      assert typecheck!(URI.__info__(:struct)) ==\n               list(closed_map(default: if_set(term()), field: atom()))\n\n      assert typecheck!([x], x.__info__(:struct)) ==\n               list(closed_map(default: if_set(term()), field: atom())) |> union(atom([nil]))\n    end\n\n    test \"behaviour_info/1\" do\n      assert typecheck!([x], x.behaviour_info(:callbacks)) == list(tuple([atom(), integer()]))\n\n      assert typecheck!(GenServer.behaviour_info(:callbacks)) == list(tuple([atom(), integer()]))\n\n      assert typewarn!(String.behaviour_info(:callbacks)) ==\n               {dynamic(), \"String.behaviour_info/1 is undefined or private\"}\n    end\n\n    test \"module_info/1\" do\n      assert typecheck!([x], x.module_info(:exports)) == list(tuple([atom(), integer()]))\n      assert typecheck!(GenServer.module_info(:exports)) == list(tuple([atom(), integer()]))\n    end\n\n    test \"module_info/0\" do\n      assert typecheck!([x], x.module_info()) |> subtype?(list(tuple([atom(), term()])))\n      assert typecheck!(GenServer.module_info()) |> subtype?(list(tuple([atom(), term()])))\n    end\n  end\n\n  describe \"regressions\" do\n    test \"clauses within multi-module apply\" do\n      assert typecheck!(\n               [value, format, debug?],\n               (\n                 module =\n                   case format do\n                     \".integer\" -> Integer\n                     \".float\" -> Float\n                   end\n\n                 value\n                 |> then(\n                   if debug? do\n                     &IO.inspect/1\n                   else\n                     &Function.identity/1\n                   end\n                 )\n                 |> module.to_string()\n               )\n             ) == dynamic() or binary()\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module/types/helpers_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"type_helper.exs\", __DIR__)\n\ndefmodule Module.Types.HelpersTest do\n  use ExUnit.Case, async: true\n  import Module.Types.Helpers\n\n  describe \"expr_to_string/1\" do\n    test \"common expressions\" do\n      assert expr_to_string({1, 2}) == \"{1, 2}\"\n      assert expr_to_string(quote(do: Foo.bar(arg))) == \"Foo.bar(arg)\"\n    end\n\n    test \"rewrites\" do\n      assert expr_to_string(quote(do: :erlang.band(a, b))) == \"Bitwise.band(a, b)\"\n      assert expr_to_string(quote(do: :erlang.orelse(a, b))) == \"a or b\"\n      assert expr_to_string(quote(do: :erlang.\"=:=\"(a, b))) == \"a === b\"\n      assert expr_to_string(quote(do: :erlang.list_to_atom(a))) == \"List.to_atom(a)\"\n      assert expr_to_string(quote(do: :maps.remove(a, b))) == \"Map.delete(b, a)\"\n      assert expr_to_string(quote(do: :erlang.element(1, a))) == \"elem(a, 0)\"\n      assert expr_to_string(quote(do: :erlang.element(:erlang.+(a, 1), b))) == \"elem(b, a)\"\n    end\n\n    test \"Kernel macros\" do\n      case = Macro.expand(quote(do: if(condition, do: :this, else: :that)), __ENV__)\n      assert expr_to_string(case) == \"if condition do\\n  :this\\nelse\\n  :that\\nend\"\n\n      case = Macro.expand(quote(do: :this || :that), __ENV__)\n      assert expr_to_string(case) == \":this || :that\"\n\n      case = Macro.expand(quote(do: :this && :that), __ENV__)\n      assert expr_to_string(case) == \":this && :that\"\n\n      case = Macro.expand(quote(do: !expr), __ENV__)\n      assert expr_to_string(case) == \"!expr\"\n    end\n\n    test \"case/try/receive/cond\" do\n      assert expr_to_string(\n               quote do\n                 case expr do\n                   :this -> :this!\n                   :that -> :that!\n                 end\n               end\n             ) == \"case expr do\\n  ...\\nend\"\n\n      assert expr_to_string(\n               quote do\n                 try do\n                   :this -> :this!\n                   :that -> :that!\n                 rescue\n                   _ ->\n                     nil\n                 end\n               end\n             ) == \"try do\\n  ...\\nend\"\n\n      assert expr_to_string(\n               quote do\n                 cond do\n                   :this -> :this!\n                   :that -> :that!\n                 end\n               end\n             ) == \"cond do\\n  ...\\nend\"\n\n      assert expr_to_string(\n               quote do\n                 receive do\n                   :this -> :this!\n                   :that -> :that!\n                 end\n               end\n             ) == \"receive do\\n  ...\\nend\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module/types/infer_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"type_helper.exs\", __DIR__)\n\ndefmodule Module.Types.InferTest do\n  use ExUnit.Case, async: true\n\n  import Module.Types.Descr\n\n  defmacro infer(config, do: block) do\n    quote do\n      runtime_infer(unquote(config).test, unquote(Macro.escape(block)))\n    end\n  end\n\n  defp runtime_infer(module, block) do\n    {{:module, _, binary, _}, []} =\n      Code.eval_quoted(\n        quote do\n          defmodule unquote(module), do: unquote(block)\n        end,\n        []\n      )\n\n    version = :elixir_erl.checker_version()\n    {:ok, {_, [{~c\"ExCk\", chunk}]}} = :beam_lib.chunks(binary, [~c\"ExCk\"])\n    {^version, data} = :erlang.binary_to_term(chunk)\n    for {fun, %{sig: sig}} <- data.exports, into: %{}, do: {fun, sig}\n  end\n\n  test \"infer types from patterns\", config do\n    types =\n      infer config do\n        def fun1(%y{}, %x{}, x = y, x = Point), do: :ok\n        def fun2(%x{}, %y{}, x = y, x = Point), do: :ok\n        def fun3(%y{}, %x{}, x = y, y = Point), do: :ok\n        def fun4(%x{}, %y{}, x = y, y = Point), do: :ok\n      end\n\n    args = [\n      open_map(__struct__: atom([Point])),\n      open_map(__struct__: atom([Point])),\n      atom([Point]),\n      atom([Point])\n    ]\n\n    assert types[{:fun1, 4}] == {:infer, nil, [{args, atom([:ok])}]}\n    assert types[{:fun2, 4}] == {:infer, nil, [{args, atom([:ok])}]}\n    assert types[{:fun3, 4}] == {:infer, nil, [{args, atom([:ok])}]}\n    assert types[{:fun4, 4}] == {:infer, nil, [{args, atom([:ok])}]}\n  end\n\n  test \"infer types from expressions\", config do\n    types =\n      infer config do\n        def fun(x) do\n          x.foo + x.bar\n        end\n      end\n\n    number = union(integer(), float())\n\n    assert types[{:fun, 1}] ==\n             {:infer, nil, [{[open_map(foo: number, bar: number)], dynamic(number)}]}\n  end\n\n  test \"infer with Elixir built-in\", config do\n    types =\n      infer config do\n        def parse(string), do: Integer.parse(string)\n      end\n\n    assert types[{:parse, 1}] ==\n             {:infer, nil,\n              [{[term()], dynamic(union(atom([:error]), tuple([integer(), binary()])))}]}\n  end\n\n  test \"merges patterns\", config do\n    types =\n      infer config do\n        def fun(:ok), do: :one\n        def fun(\"two\"), do: :two\n        def fun(\"three\"), do: :three\n        def fun(\"four\"), do: :four\n        def fun(:error), do: :five\n      end\n\n    assert types[{:fun, 1}] ==\n             {:infer, [union(atom([:ok, :error]), binary())],\n              [\n                {[atom([:ok])], atom([:one])},\n                {[binary()], atom([:two, :three, :four])},\n                {[atom([:error])], atom([:five])}\n              ]}\n  end\n\n  test \"infers return types from private functions\", config do\n    types =\n      infer config do\n        def pub(x), do: priv(x)\n        defp priv(:ok), do: :ok\n        defp priv(:error), do: :error\n      end\n\n    assert types[{:pub, 1}] ==\n             {:infer, nil, [{[atom([:ok, :error])], dynamic(atom([:ok, :error]))}]}\n\n    assert types[{:priv, 1}] == nil\n  end\n\n  test \"infers return types from super functions\", config do\n    types =\n      infer config do\n        def pub(:ok), do: :ok\n        def pub(:error), do: :error\n        defoverridable pub: 1\n        def pub(x), do: super(x)\n      end\n\n    assert types[{:pub, 1}] ==\n             {:infer, nil, [{[atom([:ok, :error])], dynamic(atom([:ok, :error]))}]}\n  end\n\n  test \"infers return types even with loops\", config do\n    types =\n      infer config do\n        def pub(x), do: pub(x)\n      end\n\n    assert types[{:pub, 1}] == {:infer, nil, [{[term()], dynamic()}]}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module/types/integration_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"type_helper.exs\", __DIR__)\n\ndefmodule Module.Types.IntegrationTest do\n  use ExUnit.Case\n\n  import ExUnit.CaptureIO\n  import Module.Types.Descr\n\n  defp builtin_protocols do\n    [\n      Collectable,\n      Enumerable,\n      IEx.Info,\n      Inspect,\n      JSON.Encoder,\n      List.Chars,\n      String.Chars\n    ]\n  end\n\n  test \"built-in protocols\" do\n    builtin_protocols =\n      for app <- ~w[eex elixir ex_unit iex logger mix]a,\n          Application.ensure_loaded(app),\n          module <- Application.spec(app, :modules),\n          Code.ensure_loaded(module),\n          function_exported?(module, :__protocol__, 1),\n          do: module\n\n    # If this test fails, update:\n    # * lib/elixir/scripts/elixir_docs.ex\n    assert Enum.sort(builtin_protocols) == builtin_protocols()\n  end\n\n  setup_all do\n    Application.put_env(:elixir, :ansi_enabled, false)\n\n    on_exit(fn ->\n      Application.put_env(:elixir, :ansi_enabled, true)\n    end)\n  end\n\n  describe \"ExCk chunk\" do\n    test \"writes exports\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          defp a, do: :ok\n          defmacrop b, do: a()\n          def c, do: b()\n          defmacro d, do: b()\n          @deprecated \"oops\"\n          def e, do: :ok\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          @callback f() :: :ok\n        end\n        \"\"\",\n        \"c.ex\" => \"\"\"\n        defmodule C do\n          @macrocallback g() :: :ok\n        end\n        \"\"\"\n      }\n\n      modules = compile_modules(files)\n\n      assert [\n               {{:c, 0}, %{}},\n               {{:e, 0}, %{deprecated: \"oops\", sig: {:infer, _, _}}}\n             ] = read_chunk(modules[A]).exports\n\n      assert read_chunk(modules[B]).exports == [\n               {{:behaviour_info, 1}, %{sig: :none}}\n             ]\n\n      assert read_chunk(modules[C]).exports == [\n               {{:behaviour_info, 1}, %{sig: :none}}\n             ]\n    end\n\n    test \"writes exports with inferred map types\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          defstruct [:x, :y, :z]\n\n          def struct_create_with_atom_keys(x) do\n            infer(y = %A{x: x})\n            {x, y}\n          end\n\n          def map_create_with_atom_keys(x) do\n            infer(%{__struct__: A, x: x, y: nil, z: nil})\n            x\n          end\n\n          def map_update_with_atom_keys(x) do\n            infer(%{x | y: nil})\n            x\n          end\n\n          def map_update_with_unknown_keys(x, key) do\n            infer(%{x | key => 123})\n            x\n          end\n\n          defp infer(%A{x: <<_::binary>>, y: nil}) do\n            :ok\n          end\n        end\n        \"\"\"\n      }\n\n      modules = compile_modules(files)\n      exports = read_chunk(modules[A]).exports |> Map.new()\n\n      return = fn name, arity ->\n        pair = {name, arity}\n        %{^pair => %{sig: {:infer, nil, [{_, return}]}}} = exports\n        return\n      end\n\n      assert return.(:struct_create_with_atom_keys, 1) ==\n               dynamic(\n                 tuple([\n                   binary(),\n                   closed_map(\n                     __struct__: atom([A]),\n                     x: binary(),\n                     y: atom([nil]),\n                     z: atom([nil])\n                   )\n                 ])\n               )\n\n      assert return.(:map_create_with_atom_keys, 1) == dynamic(binary())\n\n      assert return.(:map_update_with_atom_keys, 1) ==\n               dynamic(\n                 closed_map(\n                   __struct__: atom([A]),\n                   x: binary(),\n                   y: atom([nil]),\n                   z: term()\n                 )\n               )\n\n      assert return.(:map_update_with_unknown_keys, 2) ==\n               dynamic(\n                 closed_map(\n                   __struct__: atom([A]),\n                   x: binary(),\n                   y: atom([nil]),\n                   z: term()\n                 )\n               )\n    end\n\n    test \"writes exports with inferred function types\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def captured, do: &to_capture/1\n          defp to_capture(<<\"ok\">>), do: :ok\n          defp to_capture(<<\"error\">>), do: :error\n          defp to_capture([_ | _]), do: :list\n        end\n        \"\"\"\n      }\n\n      modules = compile_modules(files)\n      exports = read_chunk(modules[A]).exports |> Map.new()\n\n      return = fn name, arity ->\n        pair = {name, arity}\n        %{^pair => %{sig: {:infer, nil, [{_, return}]}}} = exports\n        return\n      end\n\n      assert return.(:captured, 0)\n             |> equal?(\n               fun_from_non_overlapping_clauses([\n                 {[binary()], dynamic(atom([:ok, :error]))},\n                 {[non_empty_list(term(), term())], dynamic(atom([:list]))}\n               ])\n             )\n    end\n\n    test \"writes exports for implementations\" do\n      files = %{\n        \"pi.ex\" => \"\"\"\n        defprotocol Itself do\n          @fallback_to_any true\n          def itself(data)\n        end\n\n        defimpl Itself,\n          for: [\n            Atom,\n            BitString,\n            Float,\n            Function,\n            Integer,\n            List,\n            Map,\n            Port,\n            PID,\n            Reference,\n            Tuple,\n            Any,\n            Range,\n            Unknown\n          ] do\n          def itself(data), do: data\n          def this_wont_warn(:ok), do: :ok\n        end\n        \"\"\"\n      }\n\n      {modules, stderr} = with_io(:stderr, fn -> compile_modules(files) end)\n\n      assert stderr =~\n               \"you are implementing a protocol for Unknown but said module is not available\"\n\n      refute stderr =~ \"this_wont_warn\"\n\n      itself_arg = fn mod ->\n        {_, %{sig: {:infer, nil, [{[domain], return}]}}} =\n          List.keyfind(read_chunk(modules[mod]).exports, {:itself, 1}, 0)\n\n        assert equal?(dynamic(domain), return)\n        return\n      end\n\n      assert itself_arg.(Itself.Atom) == dynamic(atom())\n      assert itself_arg.(Itself.BitString) == dynamic(bitstring())\n      assert itself_arg.(Itself.Float) == dynamic(float())\n      assert itself_arg.(Itself.Function) == dynamic(fun())\n      assert itself_arg.(Itself.Integer) == dynamic(integer())\n\n      assert itself_arg.(Itself.List) ==\n               dynamic(union(empty_list(), non_empty_list(term(), term())))\n\n      assert itself_arg.(Itself.Map) == dynamic(open_map(__struct__: if_set(negation(atom()))))\n      assert itself_arg.(Itself.Port) == dynamic(port())\n      assert itself_arg.(Itself.PID) == dynamic(pid())\n      assert itself_arg.(Itself.Reference) == dynamic(reference())\n      assert itself_arg.(Itself.Tuple) == dynamic(tuple())\n      assert itself_arg.(Itself.Any) == dynamic(term())\n\n      assert itself_arg.(Itself.Range) ==\n               dynamic(\n                 closed_map(__struct__: atom([Range]), first: term(), last: term(), step: term())\n               )\n\n      assert itself_arg.(Itself.Unknown) == dynamic(open_map(__struct__: atom([Unknown])))\n    end\n  end\n\n  describe \"type checking\" do\n    test \"inferred remote calls\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def fun(:ok), do: :doki\n          def fun(:error), do: :bad\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          def badarg do\n            A.fun(:unknown)\n          end\n\n          def badmatch do\n            :doki = A.fun(:error)\n          end\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"\"\"\n            warning: incompatible types given to A.fun/1:\n\n                A.fun(:unknown)\n        \"\"\",\n        \"\"\"\n            but expected one of:\n\n                #1\n                :ok\n\n                #2\n                :error\n        \"\"\",\n        \"\"\"\n            warning: the following pattern will never match:\n\n                :doki = A.fun(:error)\n\n            because the right-hand side has type:\n\n                dynamic(:bad)\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"redundant clauses\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def foo(x, _) when is_integer(x), do: :one\n          def foo(_, y) when is_integer(y), do: :two\n          def foo(x, y) when is_integer(x) and is_integer(y), do: :three\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"\"\"\n            warning: the following clause is redundant:\n\n                def foo(x, y) when is_integer(x) and is_integer(y)\n\n            it has type:\n\n                integer(), integer()\n\n            previous clauses have already matched on the following types:\n\n                term(), integer()\n                integer(), term()\n\n            │\n          4 │   def foo(x, y) when is_integer(x) and is_integer(y), do: :three\n            │       ~\n            │\n            └─ a.ex:4:7: A.foo/2\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"mismatched locals\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def error(), do: private(raise \"oops\")\n          def public(x), do: private(List.to_tuple(x))\n          defp private(:ok), do: nil\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"\"\"\n            warning: incompatible types given to private/1:\n\n                private(raise RuntimeError.exception(\"oops\"))\n\n        \"\"\",\n        \"the 1st argument is empty (often represented as none())\",\n        \"\"\"\n            type warning found at:\n            │\n          2 │   def error(), do: private(raise \"oops\")\n            │                    ~\n            │\n            └─ a.ex:2:20: A.error/0\n        \"\"\",\n        \"\"\"\n            warning: incompatible types given to private/1:\n\n                private(List.to_tuple(x))\n        \"\"\",\n        \"\"\"\n            type warning found at:\n            │\n          3 │   def public(x), do: private(List.to_tuple(x))\n            │                      ~\n            │\n            └─ a.ex:3:22: A.public/1\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"unused private clauses\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def public(x) do\n            private(List.to_tuple(x))\n          end\n\n          defp private(nil), do: nil\n          defp private(\"foo\"), do: \"foo\"\n          defp private({:ok, ok}), do: ok\n          defp private({:error, error}), do: error\n          defp private(\"bar\"), do: \"bar\"\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"\"\"\n            warning: this clause of defp private/1 is never used (or it will always fail when invoked)\n            │\n          6 │   defp private(nil), do: nil\n            │        ~\n            │\n            └─ a.ex:6:8: A.private/1\n        \"\"\",\n        \"\"\"\n            warning: this clause of defp private/1 is never used (or it will always fail when invoked)\n            │\n          7 │   defp private(\"foo\"), do: \"foo\"\n            │        ~\n            │\n            └─ a.ex:7:8: A.private/1\n        \"\"\",\n        \"\"\"\n            warning: this clause of defp private/1 is never used (or it will always fail when invoked)\n            │\n         10 │   defp private(\"bar\"), do: \"bar\"\n            │        ~\n            │\n            └─ a.ex:10:8: A.private/1\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"unused overridable private clauses\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          use B\n          def public(x), do: private(x)\n          defp private(x), do: super(List.to_tuple(x))\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          defmacro __using__(_) do\n            quote do\n              defp private({:ok, ok}), do: ok\n              defp private(:error), do: :error\n              defoverridable private: 1\n            end\n          end\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files)\n    end\n\n    test \"unused private clauses without warnings\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          use B\n\n          # Not all clauses are invoked, but do not warn since they are generated\n          def public1(x), do: generated(List.to_tuple(x))\n\n          # Avoid false positives caused by inference\n          def public2(x), do: (:ok = raising_private(x))\n\n          defp raising_private(true), do: :ok\n          defp raising_private(false), do: raise \"oops\"\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          defmacro __using__(_) do\n            quote generated: true do\n              defp generated({:ok, ok}), do: ok\n              defp generated(:error), do: :error\n            end\n          end\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files)\n    end\n\n    test \"mismatched implementation\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defprotocol Itself do\n          def itself(data)\n        end\n\n        defimpl Itself, for: Range do\n          def itself(nil), do: nil\n          def itself(%Range{} = range), do: range\n          def itself(%Range{}), do: raise \"oops\"\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"\"\"\n            warning: the 1st pattern in clause will never match:\n\n                nil\n\n            because it is expected to receive type:\n\n                dynamic(%Range{})\n\n            hint: defimpl for Range requires its callbacks to match exclusively on %Range{}\n\n            type warning found at:\n            │\n          6 │   def itself(nil), do: nil\n            │   ~~~~~~~~~~~~~~~~~~~~~~~~\n            │\n            └─ a.ex:6: Itself.Range.itself/1\n        \"\"\",\n        \"\"\"\n            warning: the following clause is redundant:\n\n                def itself(%Range{})\n\n            it has type:\n\n                %Range{}\n\n            previous clauses have already matched on the following types:\n\n                %Range{}\n\n            │\n          8 │   def itself(%Range{}), do: raise \"oops\"\n            │       ~\n            │\n            └─ a.ex:8:7: Itself.Range.itself/1\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    @tag :require_ast\n    test \"no implementation\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defprotocol NoImplProtocol do\n          def callback(data)\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule NoImplProtocol.Caller do\n          def run do\n            NoImplProtocol.callback(:hello)\n          end\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"\"\"\n            warning: incompatible types given to NoImplProtocol.callback/1:\n\n                NoImplProtocol.callback(:hello)\n\n            given types:\n\n                -:hello-\n\n            but the NoImplProtocol protocol was not yet implemented for any type and therefore will always fail.\n\n            This message will disappear once you define an implementation. If the protocol is part of a library, you may define a dummy implementation for development/test.\n\n            type warning found at:\n            │\n          3 │     NoImplProtocol.callback(:hello)\n            │                    ~\n            │\n            └─ b.ex:3:20: NoImplProtocol.Caller.run/0\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings, consolidate_protocols: true)\n    end\n\n    @tag :require_ast\n    test \"String.Chars protocol dispatch\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule FooBar do\n          def example1(_.._//_ = data), do: to_string(data)\n          def example2(_.._//_ = data), do: \"hello \\#{data} world\"\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"\"\"\n            warning: incompatible types given to String.Chars.to_string/1:\n\n                to_string(data)\n\n            given types:\n\n                -dynamic(%Range{})-\n\n            but expected a type that implements the String.Chars protocol.\n            You either passed the wrong value or you must:\n\n            1. convert the given value to a string explicitly\n               (use inspect/1 if you want to convert any data structure to a string)\n            2. implement the String.Chars protocol\n\n            where \"data\" was given the type:\n\n                # type: dynamic(%Range{})\n                # from: a.ex:2:24\n                _.._//_ = data\n\n            hint: the String.Chars protocol is implemented for the following types:\n\n                dynamic(\n                  %Date{} or %DateTime{} or %NaiveDateTime{} or %Time{} or %URI{} or %Version{} or\n                    %Version.Requirement{}\n                ) or atom() or bitstring() or empty_list() or float() or integer() or\n                  non_empty_list(term(), term())\n        \"\"\",\n        \"\"\"\n            warning: incompatible value given to string interpolation:\n\n                data\n\n            it has type:\n\n                -dynamic(%Range{})-\n\n            but expected a type that implements the String.Chars protocol.\n            You either passed the wrong value or you must:\n\n            1. convert the given value to a string explicitly\n               (use inspect/1 if you want to convert any data structure to a string)\n            2. implement the String.Chars protocol\n\n            where \"data\" was given the type:\n\n                # type: dynamic(%Range{})\n                # from: a.ex:3:24\n                _.._//_ = data\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings, consolidate_protocols: true)\n    end\n\n    @tag :require_ast\n    test \"Enumerable protocol dispatch\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule FooBar do\n          def example1(%Date{} = date), do: for(x <- date, do: x)\n          def example2(), do: for(i <- [1, 2, 3], into: Date.utc_today(), do: i * 2)\n          def example3(), do: for(i <- [1, 2, 3], into: 456, do: i * 2)\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"\"\"\n            warning: incompatible value given to for-comprehension:\n\n                x <- date\n\n            it has type:\n\n                -dynamic(%Date{})-\n\n            but expected a type that implements the Enumerable protocol.\n            You either passed the wrong value or you must:\n\n            1. convert the given value to an Enumerable explicitly\n            2. implement the Enumerable protocol\n\n            where \"date\" was given the type:\n\n                # type: dynamic(%Date{})\n                # from: a.ex:2:24\n                %Date{} = date\n\n            hint: the Enumerable protocol is implemented for the following types:\n\n                dynamic(\n                  %Date.Range{} or %File.Stream{} or %GenEvent.Stream{} or %HashDict{} or %HashSet{} or\n                    %IO.Stream{} or %MapSet{} or %Range{} or %Stream{}\n                ) or empty_list() or fun() or non_empty_list(term(), term()) or non_struct_map()\n        \"\"\",\n        \"\"\"\n            warning: incompatible value given to :into option in for-comprehension:\n\n                into: Date.utc_today()\n\n            it has type:\n\n                -dynamic(%Date{year: integer(), month: integer(), day: integer(), calendar: Calendar.ISO})-\n\n            but expected a type that implements the Collectable protocol.\n            You either passed the wrong value or you forgot to implement the protocol.\n\n            hint: the Collectable protocol is implemented for the following types:\n\n                dynamic(%File.Stream{} or %HashDict{} or %HashSet{} or %IO.Stream{} or %MapSet{}) or bitstring() or\n                  empty_list() or non_empty_list(term(), term()) or non_struct_map()\n        \"\"\",\n        \"\"\"\n            warning: incompatible value given to :into option in for-comprehension:\n\n                into: 456\n\n            it has type:\n\n                -integer()-\n\n            but expected a type that implements the Collectable protocol.\n            You either passed the wrong value or you forgot to implement the protocol.\n\n            hint: the Collectable protocol is implemented for the following types:\n\n                dynamic(%File.Stream{} or %HashDict{} or %HashSet{} or %IO.Stream{} or %MapSet{}) or bitstring() or\n                  empty_list() or non_empty_list(term(), term()) or non_struct_map()\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings, consolidate_protocols: true)\n    end\n\n    test \"incompatible default argument\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def ok(x = :ok \\\\\\\\ nil) do\n            x\n          end\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        ~S\"\"\"\n            warning: incompatible types given as default arguments to ok/1:\n\n                -nil-\n\n            but expected one of:\n\n                :ok\n\n            type warning found at:\n            │\n          2 │   def ok(x = :ok \\\\ nil) do\n            │                  ~\n            │\n            └─ a.ex:2:18: A.ok/0\n        \"\"\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"returns diagnostics with source and file\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @file \"generated.ex\"\n          def fun(arg) do\n            :ok = List.to_tuple(arg)\n          end\n        end\n        \"\"\"\n      }\n\n      {_modules, warnings} = with_compile_warnings(files)\n\n      assert [\n               %{\n                 message: \"the following pattern will never match\" <> _,\n                 file: file,\n                 source: source\n               }\n             ] = warnings.runtime_warnings\n\n      assert String.ends_with?(source, \"a.ex\")\n      assert Path.type(source) == :absolute\n      assert String.ends_with?(file, \"generated.ex\")\n      assert Path.type(file) == :absolute\n    after\n      purge(A)\n    end\n\n    @tag :require_ast\n    test \"regressions\" do\n      files = %{\n        # do not emit false positives from defguard\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          defguard is_non_nil_arity_function(fun, arity)\n                   when arity != nil and is_function(fun, arity)\n\n          def check(fun, args) do\n            is_non_nil_arity_function(fun, length(args))\n          end\n        end\n        \"\"\",\n        # do not parse binary segments as variables\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          def decode(byte) do\n            case byte do\n              enc when enc in [<<0x00>>, <<0x01>>] -> :ok\n            end\n          end\n        end\n        \"\"\",\n        # String.Chars protocol dispatch on improper lists\n        \"c.ex\" => \"\"\"\n        defmodule C do\n          def example, do: to_string([?a, ?b | \"!\"])\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files, consolidate_protocols: true)\n    end\n  end\n\n  describe \"performance regressions\" do\n    test \"redundant clause checking on structs with many fields\" do\n      files = %{\n        \"big_struct.ex\" => \"\"\"\n        defmodule BigStruct do\n          defstruct [:f1, :f2, :f3, :f4, :f5, :f6, :f7, :f8, :f9, :f10,\n                     :f11, :f12, :f13, :f14, :f15, :f16, :f17, :f18, :f19, :f20,\n                     :f21, :f22, :f23, :f24, :f25, :f26, :f27, :f28, :f29, :f30,\n                     :f31, :f32, :f33, :value, :schema]\n          def cast(%__MODULE__{value: nil, schema: %{k1: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k2: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k3: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k4: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k5: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k6: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k7: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k8: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k9: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k10: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k11: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k12: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k13: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k14: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k15: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k16: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k17: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k18: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k19: _}}), do: :ok\n          def cast(%__MODULE__{value: nil, schema: %{k20: _}}), do: :ok\n          # This different clause avoids optimizations from kick in many cases\n          def cast(%__MODULE__{schema: %{target_key: x}}), do: x\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files)\n    end\n\n    test \"redundant clause checking with nested open maps\" do\n      files = %{\n        \"nested_maps.ex\" => \"\"\"\n        defmodule NestedMapsIssue do\n          def foo(%{a: nil, b: %{c: true}}), do: :ok\n          def foo(%{a: nil, b: %{c: false}}), do: :ok\n          def foo(%{a: nil, b: %{d: x}}) when is_list(x), do: :ok\n          def foo(%{a: nil, b: %{e: x}}) when is_list(x), do: :ok\n          def foo(%{a: nil, b: %{f: x}}) when is_list(x), do: :ok\n          def foo(%{a: nil}), do: :ok\n          def foo(%{b: %{g: :one, h: x}}) when is_map(x), do: :ok\n          def foo(%{b: %{g: _, i: x}}) when is_list(x), do: :ok\n          def foo(%{b: %{g: _, j: x}}) when is_list(x), do: :ok\n          def foo(%{b: %{g: _, k: x}}) when is_list(x), do: :ok\n          def foo(%{b: %{g: :one}}), do: :ok\n          def foo(%{b: %{g: :two}}), do: :ok\n          def foo(%{b: %{g: :three}}), do: :ok\n          def foo(%{b: %{g: :four}}), do: :ok\n          def foo(%{b: %{g: :five}}), do: :ok\n          def foo(%{b: %{g: :six}}), do: :ok\n          def foo(%{b: %{l: x}}) when is_list(x), do: :ok\n          def foo(%{b: %{m: x}}) when is_list(x), do: :ok\n          def foo(%{b: %{n: x}}) when is_list(x), do: :ok\n          def foo(%{b: %{o: x}}) when is_list(x), do: :ok\n          def foo(%{b: %{p: x, q: y}}) when is_number(x) and is_number(y), do: :ok\n          def foo(%{b: %{p: x}}) when is_number(x), do: :ok\n          def foo(%{b: %{q: x}}) when is_number(x), do: :ok\n          def foo(%{b: %{r: x}}) when is_integer(x), do: :ok\n          def foo(%{b: %{s: x}}) when is_integer(x), do: :ok\n          def foo(%{b: %{t: x}}) when is_binary(x), do: :ok\n          def foo(%{b: %{u: x}}) when is_atom(x), do: :ok\n          def foo(%{b: %{v: x}}) when is_integer(x), do: :ok\n          def foo(%{b: %{w: x}}) when is_integer(x), do: :ok\n          def foo(_), do: :ok\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files)\n    end\n\n    test \"redundant clause checking of mixed open and closed maps\" do\n      files = %{\n        \"mixed_open_closed_maps.ex\" => \"\"\"\n        defmodule MixedOpenClosedMaps do\n          defmodule S1, do: defstruct([:name])\n          defmodule S2, do: defstruct([:name])\n          defmodule S3, do: defstruct([:name])\n          defmodule S4, do: defstruct([:name])\n          defmodule S5, do: defstruct([:name])\n          defmodule S6, do: defstruct([:name])\n          defmodule S7, do: defstruct([:name])\n          defmodule S8, do: defstruct([:name])\n          defmodule S9, do: defstruct([:name])\n          defmodule S10, do: defstruct([:name])\n          defmodule S11, do: defstruct([:name])\n          defmodule S12, do: defstruct([:name])\n          defmodule S13, do: defstruct([:name])\n          defmodule S14, do: defstruct([:name])\n          defmodule S15, do: defstruct([:name])\n          defmodule S16, do: defstruct([:name])\n          defmodule S17, do: defstruct([:name])\n          defmodule S18, do: defstruct([:name])\n\n          defmodule SValue do\n            defstruct [:value]\n          end\n\n          def render(%S1{}), do: :ok\n          def render(%S2{}), do: :ok\n          def render(%S3{}), do: :ok\n          def render(%S4{}), do: :ok\n          def render(%S5{}), do: :ok\n          def render(%S6{}), do: :ok\n          def render(%S7{}), do: :ok\n          def render(%S8{}), do: :ok\n          def render(%S9{}), do: :ok\n          def render(%S10{}), do: :ok\n          def render(%S11{}), do: :ok\n          def render(%S12{}), do: :ok\n          def render(%S13{}), do: :ok\n          def render(%S14{}), do: :ok\n          def render(%S15{}), do: :ok\n          def render(%S16{}), do: :ok\n          def render(%S17{}), do: :ok\n          def render(%S18{}), do: :ok\n          # Having the closed map and the struct overlap on a key is important\n          def render(%SValue{}), do: :ok\n          def render(%{value: value}), do: value\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files)\n    end\n\n    test \"redundant clause checking of open maps with distinct keys\" do\n      files = %{\n        \"large_head.ex\" => \"\"\"\n        defmodule LargeHead do\n          def id(%{node_id: id}) when is_binary(id), do: id\n          def id(%{node: %{id: id}}) when is_binary(id), do: id\n          def id(%{cluster: %{node_id: id}}) when is_binary(id), do: id\n          def id(%{graph: %{node_id: id}}) when is_binary(id), do: id\n          def id(%{vertex: %{node_id: id}}) when is_binary(id), do: id\n          def id(%{collection: %{graph_id: id} = collection}) when is_binary(id), do: id(collection)\n          def id(%{element: %{} = element}), do: id(element)\n          def id(%{cluster_id: id}) when is_binary(id), do: id\n          def id(%{region_id: id}) when is_binary(id), do: id\n          def id(%{graph_id: id}) when is_binary(id), do: id\n          def id(%{vertex_id: id}) when is_binary(id), do: id\n          def id(%{path_id: id}) when is_binary(id), do: id\n          def id(%{tree_id: id}) when is_binary(id), do: id\n          def id(%{collection_id: id}) when is_binary(id), do: id\n          def id(%{segment_id: id}) when is_binary(id), do: id\n          def id(%{edge_id: id}) when is_binary(id), do: id\n          def nested_access(%{graph: graph} = collection) do\n            <<_::binary>> = id(graph)\n            if collection.graph.cluster_id do\n              {graph.id, graph.node_id, collection.graph.cluster_id}\n            end\n          end\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files)\n    end\n\n    test \"pretty printing large tuples with negations\" do\n      files = %{\n        \"large_tuples.ex\" => \"\"\"\n        defmodule LargeTuplesWithNegations do\n          @abc [:a, :b]\n          defguard g1(t) when tuple_size(t) < 10\n          defguard g2(t, i) when elem(t, i) in @abc\n\n          def main() do\n            foo(Bar)\n          end\n\n          def foo(t) when g1(t) and g2(t, 0) and g2(t, 1) and g2(t, 2),\n            do: {bar(elem(t, 3)), bar(elem(t, 4))}\n\n          def foo(t) when g1(t) and g2(t, 1) and g2(t, 2) and g2(t, 3),\n            do: {bar(elem(t, 4)), bar(elem(t, 5))}\n\n          def foo(t) when g1(t) and g2(t, 2) and g2(t, 3) and g2(t, 4),\n            do: {bar(elem(t, 5)), bar(elem(t, 6))}\n\n          def foo(t) when g1(t) and g2(t, 3) and g2(t, 4) and g2(t, 5),\n            do: {bar(elem(t, 6)), bar(elem(t, 0))}\n\n          def foo(t) when g1(t) and g2(t, 4) and g2(t, 5) and g2(t, 6),\n            do: {bar(elem(t, 0)), bar(elem(t, 1))}\n\n          def foo(t) when g1(t) and g2(t, 5) and g2(t, 6) and g2(t, 0),\n            do: {bar(elem(t, 1)), bar(elem(t, 2))}\n\n          def foo(t) when g1(t) and g2(t, 6) and g2(t, 0) and g2(t, 1),\n            do: {bar(elem(t, 2)), bar(elem(t, 3))}\n\n          def bar(t) when g1(t) and g2(t, 0) and g2(t, 1) and g2(t, 2),\n            do: {baz(elem(t, 3)), baz(elem(t, 4))}\n\n          def bar(t) when g1(t) and g2(t, 1) and g2(t, 2) and g2(t, 3),\n            do: {baz(elem(t, 4)), baz(elem(t, 5))}\n\n          def bar(t) when g1(t) and g2(t, 2) and g2(t, 3) and g2(t, 4),\n            do: {baz(elem(t, 5)), baz(elem(t, 6))}\n\n          def bar(t) when g1(t) and g2(t, 3) and g2(t, 4) and g2(t, 5),\n            do: {baz(elem(t, 6)), baz(elem(t, 0))}\n\n          def bar(t) when g1(t) and g2(t, 4) and g2(t, 5) and g2(t, 6),\n            do: {baz(elem(t, 0)), baz(elem(t, 1))}\n\n          def bar(t) when g1(t) and g2(t, 5) and g2(t, 6) and g2(t, 0),\n            do: {baz(elem(t, 1)), baz(elem(t, 2))}\n\n          def bar(t) when g1(t) and g2(t, 6) and g2(t, 0) and g2(t, 1),\n            do: {baz(elem(t, 2)), baz(elem(t, 3))}\n\n          def baz(t) when g1(t) and elem(t, 0) in @abc and elem(t, 1) in @abc and elem(t, 2) in @abc,\n            do: 0\n\n          def baz(t) when g1(t) and elem(t, 1) in @abc and elem(t, 2) in @abc and elem(t, 3) in @abc,\n            do: 1\n\n          def baz(t) when g1(t) and elem(t, 2) in @abc and elem(t, 3) in @abc and elem(t, 4) in @abc,\n            do: 2\n\n          def baz(t) when g1(t) and elem(t, 3) in @abc and elem(t, 4) in @abc and elem(t, 5) in @abc,\n            do: 3\n\n          def baz(t) when g1(t) and elem(t, 4) in @abc and elem(t, 5) in @abc and elem(t, 6) in @abc,\n            do: 4\n\n          def baz(t) when g1(t) and elem(t, 5) in @abc and elem(t, 6) in @abc and elem(t, 0) in @abc,\n            do: 5\n\n          def baz(t) when g1(t) and elem(t, 6) in @abc and elem(t, 0) in @abc and elem(t, 1) in @abc,\n            do: 6\n        end\n        \"\"\"\n      }\n\n      assert_warnings(files, [\"incompatible types given to foo/1\"])\n    end\n  end\n\n  describe \"undefined warnings\" do\n    test \"handles Erlang modules\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: :not_a_module.no_module()\n          def b, do: :lists.no_func()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \":not_a_module.no_module/0 is undefined (module :not_a_module is not available or is yet to be defined)\",\n        \"a.ex:2:28: A.a/0\",\n        \":lists.no_func/0 is undefined or private\",\n        \"a.ex:3:21: A.b/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"handles built in functions\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: Kernel.module_info()\n          def b, do: Kernel.module_info(:functions)\n          def c, do: Kernel.__info__(:functions)\n          def d, do: GenServer.behaviour_info(:callbacks)\n          def e, do: Kernel.behaviour_info(:callbacks)\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"Kernel.behaviour_info/1 is undefined or private\",\n        \"a.ex:6:21: A.e/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"handles module body conditionals\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          if function_exported?(List, :flatten, 1) do\n            List.flatten([1, 2, 3])\n          else\n            List.old_flatten([1, 2, 3])\n          end\n\n          if function_exported?(List, :flatten, 1) do\n            def flatten(arg), do: List.flatten(arg)\n          else\n            def flatten(arg), do: List.old_flatten(arg)\n          end\n\n          if function_exported?(List, :flatten, 1) do\n            def flatten2(arg), do: List.old_flatten(arg)\n          else\n            def flatten2(arg), do: List.flatten(arg)\n          end\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"List.old_flatten/1 is undefined or private. Did you mean:\",\n        \"* flatten/1\",\n        \"* flatten/2\",\n        \"a.ex:15:33: A.flatten2/1\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports missing functions\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: A.no_func()\n          def b, do: A.a()\n\n          @file \"external_source.ex\"\n          def c, do: &A.no_func/1\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.no_func/0 is undefined or private\",\n        \"a.ex:2:16: A.a/0\",\n        \"A.no_func/1 is undefined or private\",\n        \"external_source.ex:6:17: A.c/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports missing functions respecting arity\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: :ok\n          def b, do: A.a(1)\n\n          @file \"external_source.ex\"\n          def c, do: A.b(1)\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.a/1 is undefined or private. Did you mean:\",\n        \"* a/0\",\n        \"a.ex:3:16: A.b/0\",\n        \"A.b/1 is undefined or private. Did you mean:\",\n        \"* b/0\",\n        \"external_source.ex:6:16: A.c/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports missing modules\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: D.no_module()\n\n          @file \"external_source.ex\"\n          def c, do: E.no_module()\n\n          def i, do: Io.puts \"hello\"\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"D.no_module/0 is undefined (module D is not available or is yet to be defined)\",\n        \"a.ex:2:16: A.a/0\",\n        \"E.no_module/0 is undefined (module E is not available or is yet to be defined)\",\n        \"external_source.ex:5:16: A.c/0\",\n        \"Io.puts/1 is undefined (module Io is not available or is yet to be defined)\",\n        \"a.ex:7:17: A.i/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports missing captures\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: &A.no_func/0\n\n          @file \"external_source.ex\"\n          def c, do: &A.no_func/1\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.no_func/0 is undefined or private\",\n        \"a.ex:2:17: A.a/0\",\n        \"A.no_func/1 is undefined or private\",\n        \"external_source.ex:5:17: A.c/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"doesn't report missing functions at compile time\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        Enum.map([], fn _ -> BadReferencer.no_func4() end)\n\n        if function_exported?(List, :flatten, 1) do\n          List.flatten([1, 2, 3])\n        else\n          List.old_flatten([1, 2, 3])\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files)\n    end\n\n    test \"handles multiple modules in one file\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: B.no_func()\n          def b, do: B.a()\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          def a, do: A.no_func()\n          def b, do: A.b()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"B.no_func/0 is undefined or private\",\n        \"a.ex:2:16: A.a/0\",\n        \"A.no_func/0 is undefined or private\",\n        \"b.ex:2:16: B.a/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"groups multiple warnings in one file\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: A.no_func()\n\n          @file \"external_source.ex\"\n          def b, do: A2.no_func()\n\n          def c, do: A.no_func()\n          def d, do: A2.no_func()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A2.no_func/0 is undefined (module A2 is not available or is yet to be defined)\",\n        \"└─ a.ex:8:17: A.d/0\",\n        \"└─ external_source.ex:5:17: A.b/0\",\n        \"A.no_func/0 is undefined or private\",\n        \"└─ a.ex:2:16: A.a/0\",\n        \"└─ a.ex:7:16: A.c/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"hints exclude deprecated functions\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def to_charlist(a), do: a\n\n          @deprecated \"Use String.to_charlist/1 instead\"\n          def to_char_list(a), do: a\n\n          def c(a), do: A.to_list(a)\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.to_list/1 is undefined or private. Did you mean:\",\n        \"* to_charlist/1\",\n        \"a.ex:7:19: A.c/1\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"do not warn of module defined in local (runtime) context\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          def a() do\n            defmodule B do\n              def b(), do: :ok\n            end\n\n            B.b()\n          end\n        end\n        \"\"\"\n      }\n\n      assert_no_warnings(files)\n    end\n\n    test \"warn of unrequired module\" do\n      files = %{\n        \"ab.ex\" => \"\"\"\n        defmodule A do\n          def a(), do: B.b()\n        end\n\n        defmodule B do\n          defmacro b(), do: :ok\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"Be sure to require B if you intend to invoke this macro\",\n        \"ab.ex:2:18: A.a/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"excludes local no_warn_undefined\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @compile {:no_warn_undefined, [MissingModule, {MissingModule2, :func, 2}]}\n          @compile {:no_warn_undefined, {B, :func, 2}}\n\n          def a, do: MissingModule.func(1)\n          def b, do: MissingModule2.func(1, 2)\n          def c, do: MissingModule2.func(1)\n          def d, do: MissingModule3.func(1, 2)\n          def e, do: B.func(1)\n          def f, do: B.func(1, 2)\n          def g, do: B.func(1, 2, 3)\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          def func(_), do: :ok\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"MissingModule2.func/1 is undefined (module MissingModule2 is not available or is yet to be defined)\",\n        \"a.ex:7:29: A.c/0\",\n        \"MissingModule3.func/2 is undefined (module MissingModule3 is not available or is yet to be defined)\",\n        \"a.ex:8:29: A.d/0\",\n        \"B.func/3 is undefined or private. Did you mean:\",\n        \"* func/1\",\n        \"a.ex:11:16: A.g/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"warn of external nested module\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A.B do\n          def a, do: :ok\n        end\n        defmodule A do\n          alias A.B\n          def a, do: B.a()\n          def b, do: B.a(1)\n          def c, do: B.no_func()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.B.a/1 is undefined or private. Did you mean:\",\n        \"* a/0\",\n        \" def b, do: B.a(1)\",\n        \"a.ex:7:16: A.b/0\",\n        \"A.B.no_func/0 is undefined or private\",\n        \"def c, do: B.no_func()\",\n        \"a.ex:8:16: A.c/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"warn of compile time context module defined before calls\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          defmodule B do\n            def a, do: :ok\n          end\n          def a, do: B.a()\n          def b, do: B.a(1)\n          def c, do: B.no_func()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.B.a/1 is undefined or private. Did you mean:\",\n        \"* a/0\",\n        \" def b, do: B.a(1)\",\n        \"a.ex:6:16: A.b/0\",\n        \"A.B.no_func/0 is undefined or private\",\n        \"def c, do: B.no_func()\",\n        \"a.ex:7:16: A.c/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"warn of compile time context module defined after calls and aliased\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          alias A.B\n          def a, do: B.a()\n          def b, do: B.a(1)\n          def c, do: B.no_func()\n          defmodule B do\n            def a, do: :ok\n          end\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.B.a/1 is undefined or private. Did you mean:\",\n        \"* a/0\",\n        \" def b, do: B.a(1)\",\n        \"a.ex:4:16: A.b/0\",\n        \"A.B.no_func/0 is undefined or private\",\n        \"def c, do: B.no_func()\",\n        \"a.ex:5:16: A.c/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"excludes global no_warn_undefined\" do\n      no_warn_undefined = Code.get_compiler_option(:no_warn_undefined)\n\n      try do\n        Code.compiler_options(\n          no_warn_undefined: [MissingModule, {MissingModule2, :func, 2}, {B, :func, 2}]\n        )\n\n        files = %{\n          \"a.ex\" => \"\"\"\n          defmodule A do\n            @compile {:no_warn_undefined, [MissingModule, {MissingModule2, :func, 2}]}\n            @compile {:no_warn_undefined, {B, :func, 2}}\n\n            def a, do: MissingModule.func(1)\n            def b, do: MissingModule2.func(1, 2)\n            def c, do: MissingModule2.func(1)\n            def d, do: MissingModule3.func(1, 2)\n            def e, do: B.func(1)\n            def f, do: B.func(1, 2)\n            def g, do: B.func(1, 2, 3)\n          end\n          \"\"\",\n          \"b.ex\" => \"\"\"\n          defmodule B do\n            def func(_), do: :ok\n          end\n          \"\"\"\n        }\n\n        warnings = [\n          \"MissingModule2.func/1 is undefined (module MissingModule2 is not available or is yet to be defined)\",\n          \"a.ex:7:29: A.c/0\",\n          \"MissingModule3.func/2 is undefined (module MissingModule3 is not available or is yet to be defined)\",\n          \"a.ex:8:29: A.d/0\",\n          \"B.func/3 is undefined or private. Did you mean:\",\n          \"* func/1\",\n          \"a.ex:11:16: A.g/0\"\n        ]\n\n        assert_warnings(files, warnings)\n      after\n        Code.compiler_options(no_warn_undefined: no_warn_undefined)\n      end\n    end\n\n    test \"global no_warn_undefined :all\" do\n      no_warn_undefined = Code.get_compiler_option(:no_warn_undefined)\n\n      try do\n        Code.compiler_options(no_warn_undefined: :all)\n\n        files = %{\n          \"a.ex\" => \"\"\"\n          defmodule A do\n            def a, do: MissingModule.func(1)\n          end\n          \"\"\"\n        }\n\n        assert_no_warnings(files)\n      after\n        Code.compiler_options(no_warn_undefined: no_warn_undefined)\n      end\n    end\n\n    test \"global no_warn_undefined :all and local exclude\" do\n      no_warn_undefined = Code.get_compiler_option(:no_warn_undefined)\n\n      try do\n        Code.compiler_options(no_warn_undefined: :all)\n\n        files = %{\n          \"a.ex\" => \"\"\"\n          defmodule A do\n            @compile {:no_warn_undefined, MissingModule}\n\n            def a, do: MissingModule.func(1)\n            def b, do: MissingModule2.func(1, 2)\n          end\n          \"\"\"\n        }\n\n        assert_no_warnings(files)\n      after\n        Code.compiler_options(no_warn_undefined: no_warn_undefined)\n      end\n    end\n  end\n\n  describe \"after_verify\" do\n    test \"reports functions\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @after_verify __MODULE__\n\n          def __after_verify__(__MODULE__) do\n            IO.warn \"from after_verify\", []\n          end\n        end\n        \"\"\"\n      }\n\n      warning = [\n        \"warning: \",\n        \"from after_verify\"\n      ]\n\n      assert_warnings(files, warning)\n    end\n  end\n\n  describe \"deprecated\" do\n    test \"reports functions\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @deprecated \"oops\"\n          def a, do: A.a()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.a/0 is deprecated. oops\",\n        \"a.ex:3:16: A.a/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports imported functions\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @deprecated \"oops\"\n          def a, do: :ok\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          import A\n          def b, do: a()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.a/0 is deprecated. oops\",\n        \"b.ex:3:14: B.b/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports structs\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @deprecated \"oops\"\n          defstruct [:x, :y]\n          def match(%A{}), do: :ok\n          def build(:ok), do: %A{}\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          def match(%A{}), do: :ok\n          def build(:ok), do: %A{}\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.__struct__/0 is deprecated. oops\",\n        \"└─ a.ex:4:13: A.match/1\",\n        \"└─ a.ex:5:23: A.build/1\",\n        \"A.__struct__/0 is deprecated. oops\",\n        \"└─ b.ex:2:13: B.match/1\",\n        \"└─ b.ex:3:23: B.build/1\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports module body\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @deprecated \"oops\"\n          def a, do: :ok\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          require A\n          A.a()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.a/0 is deprecated. oops\",\n        \"b.ex:3:5: B (module)\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports macro\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @deprecated \"oops\"\n          defmacro a, do: :ok\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          require A\n          def b, do: A.a()\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.a/0 is deprecated. oops\",\n        \"b.ex:3:16: B.b/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n\n    test \"reports unquote functions\" do\n      files = %{\n        \"a.ex\" => \"\"\"\n        defmodule A do\n          @deprecated \"oops\"\n          def a, do: :ok\n        end\n        \"\"\",\n        \"b.ex\" => \"\"\"\n        defmodule B do\n          def b, do: unquote(&A.a/0)\n        end\n        \"\"\"\n      }\n\n      warnings = [\n        \"A.a/0 is deprecated. oops\",\n        \"b.ex: B.b/0\"\n      ]\n\n      assert_warnings(files, warnings)\n    end\n  end\n\n  defp assert_warnings(files, expected, opts \\\\ [])\n\n  defp assert_warnings(files, expected, opts) when is_binary(expected) do\n    assert capture_compile_warnings(files, opts) == expected\n  end\n\n  defp assert_warnings(files, expecteds, opts) when is_list(expecteds) do\n    output = capture_compile_warnings(files, opts)\n\n    Enum.each(expecteds, fn expected ->\n      assert output =~ expected\n    end)\n  end\n\n  defp assert_no_warnings(files, opts \\\\ []) do\n    assert capture_compile_warnings(files, opts) == \"\"\n  end\n\n  defp capture_compile_warnings(files, opts) do\n    in_tmp(fn ->\n      paths = generate_files(files)\n      capture_io(:stderr, fn -> compile_to_path(paths, opts) end)\n    end)\n  end\n\n  defp with_compile_warnings(files) do\n    in_tmp(fn ->\n      paths = generate_files(files)\n      with_io(:stderr, fn -> compile_to_path(paths, []) end) |> elem(0)\n    end)\n  end\n\n  defp compile_modules(files) do\n    in_tmp(fn ->\n      paths = generate_files(files)\n      {modules, _warnings} = compile_to_path(paths, [])\n\n      Map.new(modules, fn module ->\n        {^module, binary, _filename} = :code.get_object_code(module)\n        {module, binary}\n      end)\n    end)\n  end\n\n  defp compile_to_path(paths, opts) do\n    if opts[:consolidate_protocols] do\n      Code.prepend_path(\".\")\n\n      result =\n        compile_to_path_with_after_compile(paths, fn ->\n          if Keyword.get(opts, :consolidate_protocols, false) do\n            paths = [\".\", Application.app_dir(:elixir, \"ebin\")]\n            protocols = Protocol.extract_protocols(paths)\n\n            for protocol <- protocols do\n              impls = Protocol.extract_impls(protocol, paths)\n              {:ok, binary} = Protocol.consolidate(protocol, impls)\n              File.write!(Atom.to_string(protocol) <> \".beam\", binary)\n              purge(protocol)\n            end\n          end\n        end)\n\n      Code.delete_path(\".\")\n      Enum.each(builtin_protocols(), &purge/1)\n\n      result\n    else\n      compile_to_path_with_after_compile(paths, fn -> :ok end)\n    end\n  end\n\n  defp compile_to_path_with_after_compile(paths, callback) do\n    {:ok, modules, warnings} =\n      Kernel.ParallelCompiler.compile_to_path(paths, \".\",\n        return_diagnostics: true,\n        after_compile: callback\n      )\n\n    for module <- modules do\n      purge(module)\n    end\n\n    {modules, warnings}\n  end\n\n  defp generate_files(files) do\n    for {file, contents} <- files do\n      File.write!(file, contents)\n      file\n    end\n  end\n\n  defp read_chunk(binary) do\n    assert {:ok, {_module, [{~c\"ExCk\", chunk}]}} = :beam_lib.chunks(binary, [~c\"ExCk\"])\n    assert {:elixir_checker_v7, map} = :erlang.binary_to_term(chunk)\n    map\n  end\n\n  defp purge(mod) do\n    :code.delete(mod)\n    :code.purge(mod)\n  end\n\n  defp in_tmp(fun) do\n    path = PathHelpers.tmp_path(\"checker\")\n\n    File.rm_rf!(path)\n    File.mkdir_p!(path)\n    File.cd!(path, fun)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module/types/map_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"type_helper.exs\", __DIR__)\n\ndefmodule Module.Types.MapTest do\n  # Tests for the Map module\n  use ExUnit.Case, async: true\n\n  import TypeHelper\n  import Module.Types.Descr\n  defmacro domain_key(arg) when is_atom(arg), do: [arg]\n\n  describe \"inferred\" do\n    test \"Map.new/0\" do\n      assert typecheck!(Map.new()) == dynamic(empty_map())\n    end\n\n    test \"Map.equal?/2\" do\n      assert typecheck!([x, y], {Map.equal?(x, y), x, y}) ==\n               dynamic(tuple([boolean(), open_map(), open_map()]))\n    end\n  end\n\n  describe \":maps.take/2\" do\n    test \"checking\" do\n      assert typecheck!(:maps.take(:key, %{key: 123})) ==\n               tuple([integer(), empty_map()]) |> union(atom([:error]))\n\n      assert typecheck!([x], :maps.take(:key, x)) ==\n               union(\n                 dynamic(tuple([term(), open_map(key: not_set())])),\n                 atom([:error])\n               )\n\n      assert typecheck!([condition?, x], :maps.take(if(condition?, do: :foo, else: :bar), x)) ==\n               union(\n                 dynamic(\n                   tuple([\n                     term(),\n                     union(\n                       open_map(foo: not_set()),\n                       open_map(bar: not_set())\n                     )\n                   ])\n                 ),\n                 atom([:error])\n               )\n\n      assert typecheck!([x], :maps.take(123, x)) ==\n               union(\n                 dynamic(tuple([term(), open_map()])),\n                 atom([:error])\n               )\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = :maps.take(:key, x)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], :maps.take(:foo, x)) =~\n               \"incompatible types given to :maps.take/2\"\n\n      assert typeerror!(:maps.take(:key, %{})) =~ \"\"\"\n             incompatible types given to :maps.take/2:\n\n                 :maps.take(:key, %{})\n\n             the map:\n\n                 empty_map()\n\n             does not have all required keys:\n\n                 :key\n\n             therefore this function will always return :error\n             \"\"\"\n    end\n  end\n\n  describe \"Map.delete/2\" do\n    test \"checking\" do\n      assert typecheck!(Map.delete(%{}, :key)) ==\n               empty_map()\n\n      assert typecheck!(Map.delete(%{key: 123}, :key)) ==\n               empty_map()\n\n      assert typecheck!([x], Map.delete(x, :key)) ==\n               dynamic(open_map(key: not_set()))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.delete(%{foo: 123}, if(condition?, do: :foo, else: :bar))\n             ) ==\n               union(\n                 empty_map(),\n                 closed_map(foo: integer())\n               )\n\n      assert typecheck!([x], Map.delete(x, 123)) == dynamic(open_map())\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.delete(x, :key)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.delete(x, :key)) =~\n               \"incompatible types given to Map.delete/2\"\n    end\n\n    test \"combined with put\" do\n      assert typecheck!([x], x |> Map.delete(:key) |> Map.put(:key, \"123\")) ==\n               dynamic(open_map(key: binary()))\n\n      assert typecheck!([x, y], x |> Map.delete(:key) |> Map.put(String.to_atom(y), \"123\")) ==\n               dynamic(open_map(key: if_set(binary())))\n    end\n  end\n\n  describe \"Map.fetch/2\" do\n    test \"checking\" do\n      assert typecheck!(Map.fetch(%{key: 123}, :key)) ==\n               tuple([atom([:ok]), integer()]) |> union(atom([:error]))\n\n      assert typecheck!([x], Map.fetch(x, :key)) ==\n               dynamic(tuple([atom([:ok]), term()])) |> union(atom([:error]))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.fetch(%{foo: 123}, if(condition?, do: :foo, else: :bar))\n             ) == tuple([atom([:ok]), integer()]) |> union(atom([:error]))\n\n      assert typecheck!([x], Map.fetch(x, 123)) ==\n               dynamic(tuple([atom([:ok]), term()])) |> union(atom([:error]))\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.fetch(x, :key)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.fetch(%{}, :foo)) =~\n               \"\"\"\n               incompatible types given to Map.fetch/2:\n\n                   Map.fetch(%{}, :foo)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :foo\n\n               therefore this function will always return :error\n               \"\"\"\n    end\n  end\n\n  describe \"Map.fetch!/2\" do\n    test \"checking\" do\n      assert typecheck!(Map.fetch!(%{key: 123}, :key)) == integer()\n\n      assert typecheck!([x], Map.fetch!(x, :key)) == dynamic()\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.fetch!(%{foo: 123}, if(condition?, do: :foo, else: :bar))\n             ) == integer()\n\n      assert typecheck!([x], Map.fetch!(x, 123)) == dynamic()\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 y = Integer.to_string(Map.fetch!(x, :key))\n                 {x, y}\n               )\n             ) == dynamic(tuple([open_map(key: integer()), binary()]))\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.fetch!(%{}, :foo)) =~\n               \"\"\"\n               incompatible types given to Map.fetch!/2:\n\n                   Map.fetch!(%{}, :foo)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :foo\n\n               therefore this function will always raise\n               \"\"\"\n\n      assert typeerror!(Map.fetch!(%{}, 123)) =~\n               \"\"\"\n               incompatible types given to Map.fetch!/2:\n\n                   Map.fetch!(%{}, 123)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   integer()\n\n               therefore this function will always raise\n               \"\"\"\n    end\n  end\n\n  describe \"Map.from_keys/2\" do\n    test \"checking\" do\n      assert typecheck!([], Map.from_keys([], :value)) ==\n               empty_map()\n\n      assert typecheck!([x], Map.from_keys(x, :value)) ==\n               open_map()\n\n      assert typecheck!(\n               (\n                 x = [:key1, :key2]\n                 Map.from_keys(x, 123)\n               )\n             ) ==\n               closed_map(key1: if_set(integer()), key2: if_set(integer()))\n               |> difference(empty_map())\n\n      assert typecheck!(\n               [condition?],\n               (\n                 x = if condition?, do: [123, \"123\"], else: []\n                 Map.from_keys(x, 123)\n               )\n             ) ==\n               closed_map([\n                 {domain_key(:integer), if_set(integer())},\n                 {domain_key(:binary), if_set(integer())}\n               ])\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.from_keys(x, :value)\n                 x\n               )\n             ) == dynamic(list(term()))\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = %{}], Map.from_keys(x, :value)) =~\n               \"incompatible types given to Map.from_keys/2\"\n    end\n  end\n\n  describe \"Map.from_struct/1\" do\n    test \"checking\" do\n      assert typecheck!(Map.from_struct(%{})) ==\n               empty_map()\n\n      assert typecheck!(Map.from_struct(%{key: 123})) ==\n               closed_map(key: integer())\n\n      assert typecheck!(Map.from_struct(%URI{})) ==\n               closed_map(\n                 authority: atom([nil]),\n                 fragment: atom([nil]),\n                 host: atom([nil]),\n                 path: atom([nil]),\n                 port: atom([nil]),\n                 query: atom([nil]),\n                 scheme: atom([nil]),\n                 userinfo: atom([nil])\n               )\n\n      assert typecheck!([x], Map.from_struct(x)) ==\n               dynamic(open_map(__struct__: not_set()))\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.from_struct(x)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.from_struct(x)) =~\n               \"incompatible types given to Map.from_struct/1\"\n    end\n  end\n\n  describe \"Map.get/2\" do\n    test \"checking\" do\n      assert typecheck!(Map.get(%{key: 123}, :key)) == integer() |> union(atom([nil]))\n\n      assert typecheck!([x], Map.get(x, :key)) == dynamic(term()) |> union(atom([nil]))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.get(%{foo: 123}, if(condition?, do: :foo, else: :bar))\n             ) == integer() |> union(atom([nil]))\n\n      assert typecheck!([x], Map.get(x, 123)) == dynamic(term()) |> union(atom([nil]))\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.get(x, :key)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.get(%{}, :foo)) =~\n               \"\"\"\n               incompatible types given to Map.get/2:\n\n                   Map.get(%{}, :foo)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :foo\n\n               therefore this function will always return nil\n               \"\"\"\n    end\n  end\n\n  describe \"Map.get/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.get(%{key: 123}, :key, 123)) == integer()\n\n      assert typecheck!([x], Map.get(x, :key, 123)) == dynamic(term()) |> union(integer())\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.get(%{foo: 123}, if(condition?, do: :foo, else: :bar), 123)\n             ) == integer()\n\n      assert typecheck!([x], Map.get(x, 123, 123)) == dynamic(term()) |> union(integer())\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.get(x, :key, 123)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.get(%{}, :foo, 123)) =~\n               \"\"\"\n               incompatible types given to Map.get/3:\n\n                   Map.get(%{}, :foo, 123)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :foo\n\n               therefore this function will always return integer()\n               \"\"\"\n    end\n  end\n\n  describe \"Map.get_lazy/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.get_lazy(%{key: 123}, :key, fn -> 123 end))\n             |> equal?(integer())\n\n      assert typecheck!([x], Map.get_lazy(x, :key, fn -> 123 end)) ==\n               dynamic(term())\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.get_lazy(%{foo: 123}, if(condition?, do: :foo, else: :bar), fn -> 123 end)\n             )\n             |> equal?(integer())\n\n      assert typecheck!([x], Map.get_lazy(x, 123, fn -> 123 end)) ==\n               dynamic(term())\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.get_lazy(x, :key, fn -> 123 end)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.get_lazy(%{}, :foo, fn -> 123 end)) =~\n               \"\"\"\n               incompatible types given to Map.get_lazy/3:\n\n                   Map.get_lazy(%{}, :foo, fn -> 123 end)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :foo\n\n               therefore this function will always return integer()\n               \"\"\"\n\n      assert typeerror!(Map.get_lazy(%{}, :foo, 123)) =~\n               \"\"\"\n               expected a 0-arity function on function call within Map.get_lazy/3:\n\n                   Map.get_lazy(%{}, :foo, 123)\n\n               but got type:\n\n                   integer()\n               \"\"\"\n    end\n  end\n\n  describe \"Map.keys/1\" do\n    test \"checking\" do\n      assert typecheck!([x = %{}], Map.keys(x)) == dynamic(list(term()))\n\n      assert typecheck!(\n               (\n                 x = %{}\n                 Map.keys(x)\n               )\n             ) == empty_list()\n\n      assert typecheck!(\n               (\n                 x = %{\"c\" => :three}\n                 Map.keys(x)\n               )\n             ) ==\n               list(binary())\n\n      assert typecheck!(\n               (\n                 x = %{a: 1, b: \"two\"}\n                 Map.keys(x)\n               )\n             ) ==\n               non_empty_list(union(atom([:a]), atom([:b])))\n\n      assert typecheck!(\n               (\n                 x = %{\"c\" => :three, a: 1, b: \"two\"}\n                 Map.keys(x)\n               )\n             ) ==\n               non_empty_list(\n                 atom([:a])\n                 |> union(atom([:b]))\n                 |> union(binary())\n               )\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.keys(x)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.keys(x)) =~ \"incompatible types given to Map.keys/1\"\n    end\n  end\n\n  describe \"Map.pop/2\" do\n    test \"checking\" do\n      assert typecheck!(Map.pop(%{key: 123}, :key)) ==\n               tuple([union(integer(), atom([nil])), empty_map()])\n\n      assert typecheck!([x], Map.pop(x, :key)) ==\n               dynamic(tuple([term(), open_map(key: not_set())]))\n\n      assert typecheck!([condition?, x], Map.pop(x, if(condition?, do: :foo, else: :bar))) ==\n               dynamic(\n                 tuple([\n                   term(),\n                   union(\n                     open_map(foo: not_set()),\n                     open_map(bar: not_set())\n                   )\n                 ])\n               )\n\n      assert typecheck!(\n               [x],\n               (\n                 x = %{String.to_integer(x) => :before}\n                 Map.pop(x, 123)\n               )\n             ) ==\n               tuple([\n                 atom([:before, nil]),\n                 closed_map([{domain_key(:integer), atom([:before])}])\n               ])\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.pop(x, :key)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.pop(x, :foo)) =~\n               \"incompatible types given to Map.pop/2\"\n\n      assert typeerror!(Map.pop(%{}, :key)) =~ \"\"\"\n             incompatible types given to Map.pop/2:\n\n                 Map.pop(%{}, :key)\n\n             the map:\n\n                 empty_map()\n\n             does not have all required keys:\n\n                 :key\n\n             \"\"\"\n    end\n  end\n\n  describe \"Map.pop_lazy/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.pop_lazy(%{key: 123}, :key, fn -> :error end)) ==\n               dynamic(tuple([union(integer(), atom([:error])), empty_map()]))\n\n      assert typecheck!([x], Map.pop_lazy(x, :key, fn -> :error end)) ==\n               dynamic(tuple([term(), open_map(key: not_set())]))\n\n      assert typecheck!(\n               [condition?, x],\n               Map.pop_lazy(x, if(condition?, do: :foo, else: :bar), fn -> :error end)\n             ) ==\n               dynamic(\n                 tuple([\n                   term(),\n                   union(\n                     open_map(foo: not_set()),\n                     open_map(bar: not_set())\n                   )\n                 ])\n               )\n\n      assert typecheck!(\n               [x],\n               (\n                 x = %{String.to_integer(x) => :before}\n                 Map.pop_lazy(x, 123, fn -> :after end)\n               )\n             ) ==\n               dynamic(\n                 tuple([\n                   atom([:before, :after]),\n                   closed_map([{domain_key(:integer), atom([:before])}])\n                 ])\n               )\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.pop_lazy(x, :key, fn -> :error end)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.pop_lazy(x, :foo, fn -> :error end)) =~\n               \"incompatible types given to Map.pop_lazy/3\"\n\n      assert typeerror!(Map.pop_lazy(%{}, :key, fn -> :error end)) =~ \"\"\"\n             incompatible types given to Map.pop_lazy/3:\n\n                 Map.pop_lazy(%{}, :key, fn -> :error end)\n\n             the map:\n\n                 empty_map()\n\n             does not have all required keys:\n\n                 :key\n\n             \"\"\"\n\n      assert typeerror!(Map.pop_lazy(%{}, :foo, 123)) =~\n               \"\"\"\n               expected a 0-arity function on function call within Map.pop_lazy/3:\n\n                   Map.pop_lazy(%{}, :foo, 123)\n\n               but got type:\n\n                   integer()\n               \"\"\"\n    end\n  end\n\n  describe \"Map.pop/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.pop(%{key: 123}, :key, :error)) ==\n               tuple([union(integer(), atom([:error])), empty_map()])\n\n      assert typecheck!([x], Map.pop(x, :key, :error)) ==\n               dynamic(tuple([term(), open_map(key: not_set())]))\n\n      assert typecheck!([condition?, x], Map.pop(x, if(condition?, do: :foo, else: :bar), :error)) ==\n               dynamic(\n                 tuple([\n                   term(),\n                   union(\n                     open_map(foo: not_set()),\n                     open_map(bar: not_set())\n                   )\n                 ])\n               )\n\n      assert typecheck!(\n               [x],\n               (\n                 x = %{String.to_integer(x) => :before}\n                 Map.pop(x, 123, :after)\n               )\n             ) ==\n               tuple([\n                 atom([:before, :after]),\n                 closed_map([{domain_key(:integer), atom([:before])}])\n               ])\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.pop(x, :key, :error)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.pop(x, :foo, :error)) =~\n               \"incompatible types given to Map.pop/3\"\n\n      assert typeerror!(Map.pop(%{}, :key, :error)) =~ \"\"\"\n             incompatible types given to Map.pop/3:\n\n                 Map.pop(%{}, :key, :error)\n\n             the map:\n\n                 empty_map()\n\n             does not have all required keys:\n\n                 :key\n\n             \"\"\"\n    end\n  end\n\n  describe \"Map.pop!/2\" do\n    test \"checking\" do\n      assert typecheck!(Map.pop!(%{key: 123}, :key)) ==\n               tuple([integer(), empty_map()])\n\n      assert typecheck!([x], Map.pop!(x, :key)) ==\n               dynamic(tuple([term(), open_map(key: not_set())]))\n\n      assert typecheck!([condition?, x], Map.pop!(x, if(condition?, do: :foo, else: :bar))) ==\n               dynamic(\n                 tuple([\n                   term(),\n                   union(\n                     open_map(foo: not_set()),\n                     open_map(bar: not_set())\n                   )\n                 ])\n               )\n\n      assert typecheck!([x], Map.pop!(x, 123)) ==\n               dynamic(tuple([term(), open_map()]))\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.pop!(x, :key)\n                 x\n               )\n             ) == dynamic(open_map(key: term()))\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.pop!(x, :foo)) =~\n               \"incompatible types given to Map.pop!/2\"\n\n      assert typeerror!(Map.pop!(%{}, :key)) =~ \"\"\"\n             incompatible types given to Map.pop!/2:\n\n                 Map.pop!(%{}, :key)\n\n             the map:\n\n                 empty_map()\n\n             does not have all required keys:\n\n                 :key\n\n             therefore this function will always raise\n             \"\"\"\n    end\n  end\n\n  describe \"Map.put/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.put(%{}, :key, :value)) ==\n               closed_map(key: atom([:value]))\n\n      assert typecheck!(Map.put(%{key: 123}, :key, :value)) ==\n               closed_map(key: atom([:value]))\n\n      assert typecheck!([x], Map.put(x, :key, :value)) ==\n               dynamic(open_map(key: atom([:value])))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.put(%{foo: 123}, if(condition?, do: :foo, else: :bar), \"123\")\n             ) ==\n               union(\n                 closed_map(foo: binary()),\n                 closed_map(foo: integer(), bar: binary())\n               )\n\n      assert typecheck!([x], Map.put(x, 123, 456)) == dynamic(open_map())\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.put(x, :key, :value)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.put(x, :key, :value)) =~\n               \"incompatible types given to Map.put/3\"\n    end\n  end\n\n  describe \"Map.put_new_lazy/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.put_new_lazy(%{}, :key, fn -> :value end)) ==\n               closed_map(key: atom([:value]))\n\n      assert typecheck!(Map.put_new_lazy(%{key: 123}, :key, fn -> :value end)) ==\n               closed_map(key: integer())\n\n      assert typecheck!([x], Map.put_new_lazy(x, :key, fn -> :value end)) ==\n               dynamic(open_map(key: term()))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.put_new_lazy(%{foo: 123}, if(condition?, do: :foo, else: :bar), fn -> \"123\" end)\n             ) == union(closed_map(foo: integer()), closed_map(foo: integer(), bar: binary()))\n\n      assert typecheck!([], Map.put_new_lazy(%{789 => \"binary\"}, 123, fn -> 456 end)) ==\n               closed_map([{domain_key(:integer), union(binary(), integer())}])\n\n      assert typecheck!([x], Map.put_new_lazy(x, 123, fn -> 456 end)) == dynamic(open_map())\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.put_new_lazy(x, :key, fn -> :value end)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.put_new_lazy(x, :key, fn -> :value end)) |> strip_ansi() =~\n               \"\"\"\n               incompatible types given to Map.put_new_lazy/3:\n\n                   Map.put_new_lazy(x, :key, fn -> :value end)\n\n               given types:\n\n                   empty_list(), :key, (-> dynamic(:value))\n\n               but expected one of:\n\n                   map(), term(), (-> term())\n               \"\"\"\n\n      assert typeerror!(Map.put_new_lazy(%{}, :foo, 123)) =~\n               \"\"\"\n               expected a 0-arity function on function call within Map.put_new_lazy/3:\n\n                   Map.put_new_lazy(%{}, :foo, 123)\n\n               but got type:\n\n                   integer()\n               \"\"\"\n    end\n  end\n\n  describe \"Map.put_new/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.put_new(%{}, :key, :value)) ==\n               closed_map(key: atom([:value]))\n\n      assert typecheck!(Map.put_new(%{key: 123}, :key, :value)) ==\n               closed_map(key: integer())\n\n      assert typecheck!([x], Map.put_new(x, :key, :value)) ==\n               dynamic(open_map(key: term()))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.put_new(%{foo: 123}, if(condition?, do: :foo, else: :bar), \"123\")\n             ) == union(closed_map(foo: integer()), closed_map(foo: integer(), bar: binary()))\n\n      assert typecheck!([], Map.put_new(%{789 => \"binary\"}, 123, 456)) ==\n               closed_map([{domain_key(:integer), union(binary(), integer())}])\n\n      assert typecheck!([x], Map.put_new(x, 123, 456)) == dynamic(open_map())\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.put_new(x, :key, :value)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.put_new(x, :key, :value)) |> strip_ansi() =~\n               \"\"\"\n               incompatible types given to Map.put_new/3:\n\n                   Map.put_new(x, :key, :value)\n\n               given types:\n\n                   empty_list(), :key, :value\n\n               but expected one of:\n\n                   map(), term(), term()\n               \"\"\"\n    end\n  end\n\n  describe \"Map.replace/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.replace(%{key: 123}, :key, :value)) ==\n               closed_map(key: atom([:value]))\n\n      assert typecheck!([x], Map.replace(x, :key, :value)) ==\n               dynamic(open_map(key: if_set(atom([:value]))))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.replace(%{foo: 123}, if(condition?, do: :foo, else: :bar), \"123\")\n             ) == closed_map(foo: binary())\n\n      assert typecheck!([x], Map.replace(x, 123, 456)) == dynamic(open_map())\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.replace(x, :key, :value)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.replace(%{}, :key, :value)) =~\n               \"\"\"\n               incompatible types given to Map.replace/3:\n\n                   Map.replace(%{}, :key, :value)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :key\n\n               therefore this function will always do nothing\n               \"\"\"\n    end\n  end\n\n  describe \"Map.replace_lazy/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.replace_lazy(%{key: 123}, :key, fn _ -> :value end)) ==\n               dynamic(closed_map(key: atom([:value])))\n\n      assert typecheck!([x], Map.replace_lazy(x, :key, fn _ -> :value end)) ==\n               dynamic(open_map(key: if_set(atom([:value]))))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.replace_lazy(%{foo: 123}, if(condition?, do: :foo, else: :bar), fn _ ->\n                 \"123\"\n               end)\n             ) == dynamic(closed_map(foo: binary()))\n\n      # Both succeed but different clauses\n      assert typecheck!(\n               [condition?],\n               Map.replace_lazy(\n                 %{key1: :foo, key2: :bar},\n                 if(condition?, do: :key1, else: :key2),\n                 fn\n                   :foo -> 123\n                   :bar -> 123.0\n                 end\n               )\n             ) ==\n               dynamic(\n                 union(\n                   closed_map(key1: atom([:foo]), key2: float()),\n                   closed_map(key1: integer(), key2: atom([:bar]))\n                 )\n               )\n\n      assert typecheck!([x], Map.replace_lazy(x, 123, fn _ -> 456 end)) == dynamic(open_map())\n\n      assert typecheck!([], Map.replace_lazy(%{123 => 456}, 123, fn x -> x * 1.0 end)) ==\n               dynamic(closed_map([{domain_key(:integer), union(integer(), float())}]))\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.replace_lazy(x, :key, fn _ -> :value end)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.replace_lazy(%{}, :key, fn _ -> :value end)) =~\n               \"\"\"\n               incompatible types given to Map.replace_lazy/3:\n\n                   Map.replace_lazy(%{}, :key, fn _ -> :value end)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :key\n\n               therefore this function will always do nothing\n               \"\"\"\n\n      assert typeerror!(Map.replace_lazy(%{key: :foo}, :key, fn :bar -> :value end))\n             |> strip_ansi() =~\n               \"\"\"\n               incompatible types given on function call within Map.replace_lazy/3:\n\n                   Map.replace_lazy(%{key: :foo}, :key, fn :bar -> :value end)\n\n               given types:\n\n                   dynamic(:foo)\n\n               but function has type:\n\n                   (:bar -> dynamic(:value))\n               \"\"\"\n    end\n  end\n\n  describe \"Map.replace!/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.replace!(%{key: 123}, :key, :value)) ==\n               closed_map(key: atom([:value]))\n\n      assert typecheck!([x], Map.replace!(x, :key, :value)) ==\n               dynamic(open_map(key: atom([:value])))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.replace!(%{foo: 123}, if(condition?, do: :foo, else: :bar), \"123\")\n             ) == closed_map(foo: binary())\n\n      assert typecheck!([x], Map.replace!(x, 123, 456)) == dynamic(open_map())\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.replace!(x, :key, :value)\n                 x\n               )\n             ) == dynamic(open_map(key: term()))\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.replace!(%{}, :key, :value)) =~\n               \"\"\"\n               incompatible types given to Map.replace!/3:\n\n                   Map.replace!(%{}, :key, :value)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :key\n\n               therefore this function will always raise\n               \"\"\"\n    end\n  end\n\n  describe \"Map.to_list/1\" do\n    test \"checking\" do\n      assert typecheck!([x = %{}], Map.to_list(x)) == dynamic(list(tuple([term(), term()])))\n\n      assert typecheck!(\n               (\n                 x = %{}\n                 Map.to_list(x)\n               )\n             ) == empty_list()\n\n      assert typecheck!(\n               (\n                 x = %{\"c\" => :three}\n                 Map.to_list(x)\n               )\n             ) ==\n               list(tuple([binary(), atom([:three])]))\n\n      assert typecheck!(\n               (\n                 x = %{a: 1, b: \"two\"}\n                 Map.to_list(x)\n               )\n             ) ==\n               non_empty_list(\n                 union(tuple([atom([:a]), integer()]), tuple([atom([:b]), binary()]))\n               )\n\n      assert typecheck!(\n               (\n                 x = %{\"c\" => :three, a: 1, b: \"two\"}\n                 Map.to_list(x)\n               )\n             ) ==\n               non_empty_list(\n                 tuple([atom([:a]), integer()])\n                 |> union(tuple([atom([:b]), binary()]))\n                 |> union(tuple([binary(), atom([:three])]))\n               )\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.to_list(x)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.to_list(x)) =~ \"incompatible types given to Map.to_list/1\"\n    end\n  end\n\n  describe \"Map.update/4\" do\n    test \"checking\" do\n      assert typecheck!(Map.update(%{}, :key, :default, fn _ -> :value end)) ==\n               dynamic(closed_map(key: atom([:default])))\n\n      assert typecheck!(Map.update(%{key: 123}, :key, :default, fn _ -> :value end)) ==\n               dynamic(closed_map(key: atom([:value])))\n\n      assert typecheck!([x], Map.update(x, :key, :default, fn _ -> :value end)) ==\n               dynamic(open_map(key: atom([:value, :default])))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.update(%{foo: 123}, if(condition?, do: :foo, else: :bar), :default, fn _ ->\n                 \"123\"\n               end)\n             ) ==\n               dynamic(\n                 union(\n                   closed_map(foo: binary()),\n                   closed_map(foo: integer(), bar: atom([:default]))\n                 )\n               )\n\n      # Both succeed but different clauses\n      assert typecheck!(\n               [condition?],\n               Map.update(\n                 %{key1: :foo, key2: :bar},\n                 if(condition?, do: :key1, else: :key2),\n                 :default,\n                 fn\n                   :foo -> 123\n                   :bar -> 123.0\n                 end\n               )\n             ) ==\n               dynamic(\n                 union(\n                   closed_map(key1: atom([:foo]), key2: float()),\n                   closed_map(key1: integer(), key2: atom([:bar]))\n                 )\n               )\n\n      assert typecheck!([x], Map.update(x, 123, :default, fn _ -> 456 end)) == dynamic(open_map())\n\n      integer_to_integer_float_atom =\n        dynamic(\n          closed_map([\n            {domain_key(:integer), integer() |> union(float()) |> union(atom([:default]))}\n          ])\n        )\n\n      assert typecheck!([], Map.update(%{123 => 456}, 123, :default, fn x -> x * 1.0 end)) ==\n               integer_to_integer_float_atom\n\n      assert typecheck!([], Map.update(%{123 => 456}, 456, :default, fn x -> x * 1.0 end)) ==\n               integer_to_integer_float_atom\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.update(x, :key, :default, fn _ -> :value end)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.update(%{key: :foo}, :key, :default, fn :bar -> :value end))\n             |> strip_ansi() =~\n               \"\"\"\n               incompatible types given on function call within Map.update/4:\n\n                   Map.update(%{key: :foo}, :key, :default, fn :bar -> :value end)\n\n               given types:\n\n                   dynamic(:foo)\n\n               but function has type:\n\n                   (:bar -> dynamic(:value))\n               \"\"\"\n    end\n  end\n\n  describe \"Map.update!/3\" do\n    test \"checking\" do\n      assert typecheck!(Map.update!(%{key: 123}, :key, fn _ -> :value end)) ==\n               dynamic(closed_map(key: atom([:value])))\n\n      assert typecheck!([x], Map.update!(x, :key, fn _ -> :value end)) ==\n               dynamic(open_map(key: atom([:value])))\n\n      # If one of them succeeds, we are still fine!\n      assert typecheck!(\n               [condition?],\n               Map.update!(%{foo: 123}, if(condition?, do: :foo, else: :bar), fn _ -> \"123\" end)\n             ) == dynamic(closed_map(foo: binary()))\n\n      # Both succeed but different clauses\n      assert typecheck!(\n               [condition?],\n               Map.update!(%{key1: :foo, key2: :bar}, if(condition?, do: :key1, else: :key2), fn\n                 :foo -> 123\n                 :bar -> 123.0\n               end)\n             ) ==\n               dynamic(\n                 union(\n                   closed_map(key1: atom([:foo]), key2: float()),\n                   closed_map(key1: integer(), key2: atom([:bar]))\n                 )\n               )\n\n      assert typecheck!([x], Map.update!(x, 123, fn _ -> 456 end)) == dynamic(open_map())\n\n      assert typecheck!([], Map.update!(%{123 => 456}, 123, fn x -> x * 1.0 end)) ==\n               dynamic(closed_map([{domain_key(:integer), union(integer(), float())}]))\n\n      assert typecheck!([], Map.update!(%{123 => 456}, 456, fn x -> x * 1.0 end)) ==\n               dynamic(closed_map([{domain_key(:integer), union(integer(), float())}]))\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.update!(x, :key, fn _ -> :value end)\n                 x\n               )\n             ) == dynamic(open_map(key: term()))\n    end\n\n    test \"errors\" do\n      assert typeerror!(Map.update!(%{}, :key, fn _ -> :value end)) =~\n               \"\"\"\n               incompatible types given to Map.update!/3:\n\n                   Map.update!(%{}, :key, fn _ -> :value end)\n\n               the map:\n\n                   empty_map()\n\n               does not have all required keys:\n\n                   :key\n\n               therefore this function will always raise\n               \"\"\"\n\n      assert typeerror!(Map.update!(%{key: :foo}, :key, fn :bar -> :value end)) |> strip_ansi() =~\n               \"\"\"\n               incompatible types given on function call within Map.update!/3:\n\n                   Map.update!(%{key: :foo}, :key, fn :bar -> :value end)\n\n               given types:\n\n                   dynamic(:foo)\n\n               but function has type:\n\n                   (:bar -> dynamic(:value))\n               \"\"\"\n    end\n\n    test \"with unknown function type\" do\n      assert typecheck!([x], Map.update!(x, :body, &:zlib.gunzip/1)) ==\n               dynamic(open_map(body: term()))\n    end\n  end\n\n  describe \"Map.values/1\" do\n    test \"checking\" do\n      assert typecheck!([x = %{}], Map.values(x)) == dynamic(list(term()))\n\n      assert typecheck!(\n               (\n                 x = %{}\n                 Map.values(x)\n               )\n             ) == empty_list()\n\n      assert typecheck!(\n               (\n                 x = %{\"c\" => :three}\n                 Map.values(x)\n               )\n             ) ==\n               list(atom([:three]))\n\n      assert typecheck!(\n               (\n                 x = %{a: 1, b: \"two\"}\n                 Map.values(x)\n               )\n             ) ==\n               non_empty_list(union(integer(), binary()))\n\n      assert typecheck!(\n               (\n                 x = %{\"c\" => :three, a: 1, b: \"two\"}\n                 Map.values(x)\n               )\n             ) ==\n               non_empty_list(\n                 integer()\n                 |> union(binary())\n                 |> union(atom([:three]))\n               )\n    end\n\n    test \"inference\" do\n      assert typecheck!(\n               [x],\n               (\n                 _ = Map.values(x)\n                 x\n               )\n             ) == dynamic(open_map())\n    end\n\n    test \"errors\" do\n      assert typeerror!([x = []], Map.values(x)) =~ \"incompatible types given to Map.values/1\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module/types/pattern_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"type_helper.exs\", __DIR__)\n\ndefmodule Module.Types.PatternTest do\n  use ExUnit.Case, async: true\n\n  import TypeHelper\n  import Module.Types.Descr\n\n  describe \"variables\" do\n    test \"captures variables from simple assignment in head\" do\n      assert typecheck!([x = :foo], x) == dynamic(atom([:foo]))\n      assert typecheck!([:foo = x], x) == dynamic(atom([:foo]))\n    end\n\n    test \"captures variables from simple assignment in =\" do\n      assert typecheck!(\n               (\n                 x = :foo\n                 x\n               )\n             ) == atom([:foo])\n    end\n\n    test \"refines information across patterns\" do\n      assert typecheck!([%y{}, %x{}, x = y, x = Point], y) == dynamic(atom([Point]))\n    end\n\n    test \"repeated refinements are ignored on reporting\" do\n      assert typeerror!([{name, arity}, arity = 123], hd(Atom.to_charlist(name))) |> strip_ansi() ==\n               ~l\"\"\"\n               incompatible types given to Kernel.hd/1:\n\n                   hd(Atom.to_charlist(name))\n\n               given types:\n\n                   empty_list() or non_empty_list(integer())\n\n               but expected one of:\n\n                   non_empty_list(term(), term())\n\n               where \"name\" was given the type:\n\n                   # type: dynamic(atom())\n                   # from: types_test.ex:LINE-1\n                   Atom.to_charlist(name)\n               \"\"\"\n    end\n\n    test \"can be accessed even if they don't match\" do\n      assert typeerror!(\n               (\n                 # This will never match, info should not be \"corrupted\"\n                 [info | _] = __ENV__.function\n                 info\n               )\n             ) =~ \"the following pattern will never match\"\n    end\n\n    test \"does not check underscore\" do\n      assert typecheck!(_ = raise(\"oops\")) == none()\n    end\n  end\n\n  describe \"=\" do\n    test \"precedence does not matter\" do\n      uri_type = typecheck!([x = %URI{}], x)\n\n      assert typecheck!(\n               (\n                 x = %URI{} = URI.new!(\"/\")\n                 x\n               )\n             ) == uri_type\n\n      assert typecheck!(\n               (\n                 %URI{} = x = URI.new!(\"/\")\n                 x\n               )\n             ) == uri_type\n    end\n\n    test \"refines types\" do\n      assert typecheck!(\n               [x, foo = :foo, bar = 123],\n               (\n                 {^foo, ^bar} = x\n                 x\n               )\n             ) == dynamic(tuple([atom([:foo]), integer()]))\n    end\n\n    test \"match propagation\" do\n      assert typecheck!([x = {:ok, y}], is_integer(y), x) ==\n               dynamic(tuple([atom([:ok]), integer()]))\n\n      assert typecheck!(\n               [x = {:ok, y}],\n               (\n                 _ = Integer.to_string(y)\n                 x\n               )\n             ) ==\n               dynamic(tuple([atom([:ok]), integer()]))\n    end\n\n    test \"reports incompatible types\" do\n      assert typeerror!([x = 123 = \"123\"], x) == ~l\"\"\"\n             the following pattern will never match:\n\n                 x = 123 = \"123\"\n             \"\"\"\n\n      assert typeerror!([x = {:ok, _} = {:error, _, _}], x) == ~l\"\"\"\n             the following pattern will never match:\n\n                 x = {:ok, _} = {:error, _, _}\n             \"\"\"\n\n      assert typeerror!([{x = {:ok, y} = {:error, z, w}}], {x, y, z, w}) == ~l\"\"\"\n             the following pattern will never match:\n\n                 {x = {:ok, y} = {:error, z, w}}\n             \"\"\"\n\n      assert typeerror!([a = b, a = :foo, b = :bar], {a, b}) == ~l\"\"\"\n             the following pattern will never match:\n\n                 a = b\n\n             where \"b\" was given the type:\n\n                 # type: dynamic(:bar)\n                 # from: types_test.ex:LINE\n                 b = :bar\n             \"\"\"\n\n      assert typeerror!([{x, _} = {y, _}, x = :foo, y = :bar], {x, y}) == ~l\"\"\"\n             the following pattern will never match:\n\n                 {x, _} = {y, _}\n\n             where \"x\" was given the type:\n\n                 # type: dynamic(:foo)\n                 # from: types_test.ex:LINE\n                 x = :foo\n\n             where \"y\" was given the type:\n\n                 # type: dynamic(:bar)\n                 # from: types_test.ex:LINE\n                 y = :bar\n             \"\"\"\n\n      assert typeerror!([{:ok, x} = {:ok, y}], is_integer(x) and is_atom(y), {x, y}) == ~l\"\"\"\n             the following pattern will never match:\n\n                 {:ok, x} = {:ok, y}\n\n             where \"x\" was given the type:\n\n                 # type: integer()\n                 # from: types_test.ex:LINE\n                 is_integer(x)\n\n             where \"y\" was given the type:\n\n                 # type: atom()\n                 # from: types_test.ex:LINE\n                 is_atom(y)\n             \"\"\"\n    end\n  end\n\n  describe \"structs\" do\n    test \"unknown struct\" do\n      {_, [diagnostic]} = typediag!([%UNKNOWN.URI{} = x], x)\n      assert diagnostic.severity == :error\n\n      assert diagnostic.message ==\n               \"struct UNKNOWN.URI is undefined (module UNKNOWN.URI is not available or is yet to be defined)\"\n\n      {_, [diagnostic]} = typediag!([%Enumerable{} = x], x)\n      assert diagnostic.severity == :error\n\n      assert diagnostic.message ==\n               \"struct Enumerable is undefined (there is such module but it does not define a struct)\"\n    end\n\n    test \"fields access on unknown struct\" do\n      assert typeerror!([%UNKNOWN.URI{reason: reason}], reason) =~\n               \"struct UNKNOWN.URI is undefined (module UNKNOWN.URI is not available or is yet to be defined)\"\n    end\n\n    test \"unknown field\" do\n      {_, [diagnostic]} = typediag!([%URI{unknown: _} = x], x)\n      assert diagnostic.severity == :error\n      assert diagnostic.message == \"unknown key :unknown for struct URI\"\n    end\n\n    test \"variable name\" do\n      assert typecheck!([%x{}], x) == dynamic(atom())\n    end\n\n    test \"variable name fields\" do\n      assert typecheck!([x = %_{}], x.__struct__) == dynamic(atom())\n      assert typecheck!([x = %_{}], x) == dynamic(open_map(__struct__: atom()))\n\n      assert typecheck!([x = %m{}, m = Point], x) ==\n               dynamic(open_map(__struct__: atom([Point])))\n\n      assert typecheck!([m = Point, x = %m{}], x) ==\n               dynamic(open_map(__struct__: atom([Point])))\n\n      assert typeerror!([m = 123], %^m{} = %Point{}) ==\n               ~l\"\"\"\n               expected an atom as struct name:\n\n                   %^m{}\n\n               got type:\n\n                   integer()\n\n               where \"m\" was given the type:\n\n                   # type: integer()\n                   # from: types_test.ex:LINE-1\n                   m = 123\n               \"\"\"\n    end\n  end\n\n  describe \"maps\" do\n    test \"atom keys in patterns\" do\n      assert typecheck!([x = %{foo: :bar}], x) == dynamic(open_map(foo: atom([:bar])))\n      assert typecheck!([x = %{123 => 456}], x) == dynamic(open_map())\n      assert typecheck!([x = %{123 => 456, foo: :bar}], x) == dynamic(open_map(foo: atom([:bar])))\n      assert typecheck!([%{foo: :bar = x}], x) == dynamic(atom([:bar]))\n\n      assert typecheck!(\n               [\n                 {:message, %{slug: slug}},\n                 %{assigns: %{app: %{slug: slug} = app}} = root\n               ],\n               {root, app, slug}\n             ) ==\n               dynamic(\n                 tuple([\n                   open_map(assigns: open_map(app: open_map(slug: term()))),\n                   open_map(slug: term()),\n                   term()\n                 ])\n               )\n\n      assert typecheck!(\n               [\n                 %{assigns: %{app: %{slug: slug} = app}} = root,\n                 {:message, %{slug: slug}}\n               ],\n               {root, app, slug}\n             ) ==\n               dynamic(\n                 tuple([\n                   open_map(assigns: open_map(app: open_map(slug: term()))),\n                   open_map(slug: term()),\n                   term()\n                 ])\n               )\n    end\n\n    test \"domain keys in patterns\" do\n      assert typecheck!([x = %{123 => 456}], x) == dynamic(open_map())\n      assert typecheck!([x = %{123 => 456, foo: :bar}], x) == dynamic(open_map(foo: atom([:bar])))\n      assert typecheck!([%{\"123\" => :bar = x}], x) == dynamic(atom([:bar]))\n    end\n\n    test \"pinned variable key in patterns\" do\n      assert typecheck!(\n               (\n                 key = 123\n                 %{^key => value} = %{123 => :value}\n                 value\n               )\n             ) == atom([:value])\n\n      assert typecheck!(\n               [size, map],\n               (\n                 %{<<123::size(^size)>> => _} = map\n                 {size, map}\n               )\n             ) == dynamic(tuple([integer(), open_map()]))\n\n      assert(\n        typecheck!(\n          [key, map],\n          (\n            %{{:module, ^key} => _} = map\n            {key, map}\n          )\n        ) == dynamic(tuple([term(), open_map()]))\n      )\n    end\n  end\n\n  describe \"tuples\" do\n    test \"in patterns\" do\n      assert typecheck!([x = {:ok, 123}], x) == dynamic(tuple([atom([:ok]), integer()]))\n      assert typecheck!([{:x, y} = {x, :y}], {x, y}) == dynamic(tuple([atom([:x]), atom([:y])]))\n    end\n  end\n\n  describe \"lists\" do\n    test \"in patterns\" do\n      assert typecheck!([x = [1, 2, 3]], x) ==\n               dynamic(non_empty_list(integer()))\n\n      assert typecheck!([x = [1, 2, 3 | y], y = :foo], x) ==\n               dynamic(non_empty_list(integer(), atom([:foo])))\n\n      assert typecheck!([x = [1, 2, 3 | y], y = [1.0, 2.0, 3.0]], x) ==\n               dynamic(non_empty_list(union(integer(), float())))\n\n      assert typecheck!([x = [:ok | z]], {x, z}) ==\n               dynamic(tuple([non_empty_list(term(), term()), term()]))\n\n      assert typecheck!([x = [a = :a, b = :b, c = :c]], {x, a, b, c}) ==\n               dynamic(\n                 tuple([non_empty_list(atom([:a, :b, :c])), atom([:a]), atom([:b]), atom([:c])])\n               )\n\n      assert typecheck!([x = [y | z]], {x, y, z}) ==\n               dynamic(tuple([non_empty_list(term(), term()), term(), term()]))\n    end\n\n    test \"in patterns through ++\" do\n      assert typecheck!([x = [] ++ []], x) == dynamic(empty_list())\n\n      assert typecheck!([x = [] ++ y, y = :foo], x) ==\n               dynamic(atom([:foo]))\n\n      assert typecheck!([x = [1, 2, 3] ++ y, y = :foo], x) ==\n               dynamic(non_empty_list(integer(), atom([:foo])))\n\n      assert typecheck!([x = [1, 2, 3] ++ y, y = [1.0, 2.0, 3.0]], x) ==\n               dynamic(non_empty_list(union(integer(), float())))\n    end\n\n    test \"with lists inside tuples inside lists\" do\n      assert typecheck!([[node_1 = {[arg]}, node_2 = {[arg]}]], {node_1, node_2, arg})\n             |> equal?(\n               dynamic(\n                 tuple([\n                   tuple([non_empty_list(term())]),\n                   tuple([non_empty_list(term())]),\n                   term()\n                 ])\n               )\n             )\n    end\n\n    test \"regressions\" do\n      # This is a regression that happens because stacktrace may be\n      # either three-element or four-element tuples, and it was failing\n      # when we tried to access the fourth element\n      assert typecheck!(\n               try do\n                 raise \"oops\"\n               rescue\n                 _ ->\n                   [{__MODULE__, fun, _args_or_arity, info} | _] = __STACKTRACE__\n                   {fun, length(info)}\n               end\n             ) == tuple([atom(), integer()])\n\n      assert typecheck!(\n               try do\n                 raise \"oops\"\n               rescue\n                 _ ->\n                   [tuple | _] = __STACKTRACE__\n                   {__MODULE__, fun, _args_or_arity, info} = tuple\n                   {fun, length(info)}\n               end\n             ) == tuple([atom(), integer()])\n    end\n  end\n\n  describe \"bitstrings\" do\n    test \"alignment\" do\n      assert typecheck!([<<_>> = x], x) == dynamic(binary())\n      assert typecheck!([<<_::1>> = x], x) == dynamic(difference(bitstring(), binary()))\n      assert typecheck!([<<_::4, _::4>> = x], x) == dynamic(binary())\n      assert typecheck!([<<size, _::size(size)>> = x], x) == dynamic(bitstring())\n    end\n\n    test \"ok\" do\n      assert typecheck!([<<x>>], x) == integer()\n      assert typecheck!([<<x::float>>], x) == float()\n      assert typecheck!([<<x::binary>>], x) == binary()\n      assert typecheck!([<<x::utf8>>], x) == integer()\n    end\n\n    test \"nested\" do\n      assert typecheck!([<<0, <<x::binary>>::binary>>], x) == binary()\n\n      assert typeerror!([<<0, <<x::bitstring>>::binary>>], x) == ~l\"\"\"\n             incompatible types in binary matching:\n\n                 <<..., <<x::bitstring>>::binary>>\n\n             got type:\n\n                 bitstring()\n\n             but expected type:\n\n                 binary()\n\n             where \"x\" was given the type:\n\n                 # type: bitstring()\n                 # from: types_test.ex:LINE\n                 <<x::bitstring>>\n             \"\"\"\n    end\n\n    test \"error\" do\n      assert typeerror!([<<x::binary-size(2), x::float>>], x) == ~l\"\"\"\n             incompatible types assigned to \"x\":\n\n                 binary() !~ float()\n\n             where \"x\" was given the types:\n\n                 # type: binary()\n                 # from: types_test.ex:LINE\n                 <<x::binary-size(2), ...>>\n\n                 # type: float()\n                 # from: types_test.ex:LINE\n                 <<..., x::float>>\n             \"\"\"\n\n      assert typeerror!([<<x::float, x>>], x) == ~l\"\"\"\n             incompatible types assigned to \"x\":\n\n                 float() !~ integer()\n\n             where \"x\" was given the types:\n\n                 # type: float()\n                 # from: types_test.ex:LINE\n                 <<x::float, ...>>\n\n                 # type: integer()\n                 # from: types_test.ex:LINE\n                 <<..., x>>\n\n             #{hints(:inferred_bitstring_spec)}\n             \"\"\"\n    end\n\n    test \"pin inference\" do\n      assert typecheck!(\n               [x, y],\n               (\n                 <<^x>> = y\n                 x\n               )\n             ) == dynamic(integer())\n    end\n\n    test \"size ok\" do\n      assert typecheck!([<<x, y, _::size(x - y)>>], :ok) == atom([:ok])\n    end\n\n    test \"size error\" do\n      assert typeerror!([<<x::float, _::size(x)>>], :ok) ==\n               ~l\"\"\"\n               expected an integer in binary size:\n\n                   size(x)\n\n               got type:\n\n                   float()\n\n               where \"x\" was given the type:\n\n                   # type: float()\n                   # from: types_test.ex:LINE-1\n                   <<x::float, ...>>\n               \"\"\"\n    end\n\n    test \"size pin inference\" do\n      assert typecheck!(\n               [x, y],\n               (\n                 <<_::size(^x)>> = y\n                 x\n               )\n             ) == dynamic(integer())\n    end\n  end\n\n  describe \"pin\" do\n    test \"propagates across matches\" do\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y ->\n                   case 123 do\n                     ^y -> x\n                   end\n               end\n             ) == dynamic(integer())\n\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y ->\n                   case 123 do\n                     ^x -> y\n                   end\n               end\n             ) == dynamic(integer())\n    end\n\n    test \"propagates across guards\" do\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y when is_integer(y) -> x\n               end\n             ) == dynamic(integer())\n    end\n\n    test \"propagates across matches and guards\" do\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y ->\n                   case true do\n                     true when is_integer(y) -> x\n                   end\n               end\n             ) == dynamic(integer())\n\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y ->\n                   case true do\n                     true when is_integer(x) -> y\n                   end\n               end\n             ) == dynamic(integer())\n    end\n\n    test \"propagates across binary size in match\" do\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y ->\n                   case Process.get(:another) do\n                     <<_::size(^y)>> -> x\n                   end\n               end\n             ) == dynamic(integer())\n\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y ->\n                   case Process.get(:another) do\n                     <<_::size(^x)>> -> y\n                   end\n               end\n             ) == dynamic(integer())\n    end\n\n    test \"propagates across binary size in match inside a key\" do\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y ->\n                   case Process.get(:another) do\n                     %{<<32::size(^y)>> => _} -> x\n                   end\n               end\n             ) == dynamic(integer())\n\n      assert typecheck!(\n               [x],\n               case Process.get(:unused) do\n                 ^x = y ->\n                   case Process.get(:another) do\n                     %{<<32::size(^x)>> => _} -> y\n                   end\n               end\n             ) == dynamic(integer())\n    end\n  end\n\n  describe \"guards\" do\n    test \"not\" do\n      assert typecheck!([x], not x, x) == dynamic(atom([false]))\n\n      assert typecheck!([x], not x.foo, x) == dynamic(open_map(foo: atom([false])))\n\n      assert typeerror!([x], not length(x), x) |> strip_ansi() == ~l\"\"\"\n             incompatible types given to Kernel.not/1:\n\n                 not length(x)\n\n             given types:\n\n                 integer()\n\n             but expected one of:\n\n                 #1\n                 true\n\n                 #2\n                 false\n\n             where \"x\" was given the type:\n\n                 # type: list(term())\n                 # from: types_test.ex:LINE\n                 length(x)\n             \"\"\"\n    end\n\n    test \"hd/tl\" do\n      assert typecheck!([x], is_list(x) and is_map(hd(x)) and is_map_key(hd(x), :tag), x) ==\n               dynamic(non_empty_list(term(), term()))\n\n      assert typeerror!([x], is_list(x) and is_map(hd(x)) and is_binary(hd(x)), x) =~ ~l\"\"\"\n             this guard will never succeed:\n\n                 is_list(x) and is_map(hd(x)) and is_binary(hd(x))\n\n             because it returns type:\n\n                 false\n\n             where \"x\" was given the types:\n\n                 # type: empty_list() or non_empty_list(term(), term())\n                 # from: types_test.ex:649\n                 is_list(x)\n\n                 # type: non_empty_list(term(), term())\n                 # from: types_test.ex:649\n                 hd(x)\n             \"\"\"\n    end\n\n    test \"is_struct/1\" do\n      assert typecheck!([x], is_struct(x), x) == dynamic(open_map(__struct__: atom()))\n      assert typecheck!([x], is_struct(x, URI), x) == dynamic(open_map(__struct__: atom([URI])))\n\n      assert typecheck!([x], not is_struct(x), x)\n             |> equal?(dynamic(negation(open_map(__struct__: atom()))))\n\n      assert typecheck!([x], not is_struct(x, URI), x) == dynamic()\n    end\n\n    test \"is_binary/1\" do\n      assert typecheck!([x], is_binary(x), x) == dynamic(binary())\n      assert typecheck!([x], not is_binary(x), x) == dynamic(negation(binary()))\n\n      assert typecheck!([x], is_bitstring(x), x) == dynamic(bitstring())\n      assert typecheck!([x], not is_bitstring(x), x) == dynamic(negation(bitstring()))\n    end\n\n    test \"is_function/2\" do\n      assert typecheck!([x], is_function(x, 3), x) == dynamic(fun(3))\n      assert typecheck!([x], not is_function(x, 3), x) == dynamic(negation(fun(3)))\n    end\n\n    test \"is_map_key/2\" do\n      assert typecheck!([x], is_map_key(x, :foo), x) == dynamic(open_map(foo: term()))\n      assert typecheck!([x], not is_map_key(x, :foo), x) == dynamic(open_map(foo: not_set()))\n    end\n\n    test \"elem\" do\n      assert typecheck!([x], elem(x, 1), x) ==\n               dynamic(open_tuple([term(), atom([true])]))\n\n      assert typecheck!([x], not elem(x, 1), x) ==\n               dynamic(open_tuple([term(), atom([false])]))\n\n      assert typecheck!([x], is_integer(elem(x, 1)), x) ==\n               dynamic(open_tuple([term(), integer()]))\n    end\n\n    test \"map.field\" do\n      assert typecheck!([x = %{foo: :bar}], x.bar, x) ==\n               dynamic(open_map(foo: atom([:bar]), bar: atom([true])))\n\n      assert typecheck!([x = %{foo: :bar}], not x.bar, x) ==\n               dynamic(open_map(foo: atom([:bar]), bar: atom([false])))\n\n      assert typeerror!([x = %Point{}], x.foo_bar, :ok) == ~l\"\"\"\n             the following pattern will never match:\n\n                 x = %Point{}\n\n             where \"x\" was given the type:\n\n                 # type: %{..., foo_bar: true}\n                 # from: types_test.ex:LINE\n                 x.foo_bar\n             \"\"\"\n    end\n\n    test \"when checks\" do\n      assert typecheck!([x], is_binary(x) when is_atom(x), x) == dynamic(union(binary(), atom()))\n\n      assert typecheck!([x], is_binary(x) when map_size(x) >= 0, x) ==\n               dynamic(union(binary(), open_map()))\n\n      assert typecheck!([x], tuple_size(x) >= 0 when map_size(x) >= 0, x) ==\n               dynamic(union(tuple(), open_map()))\n\n      assert typecheck!([x, y], is_binary(x) when is_atom(y), {x, y}) ==\n               dynamic(tuple([term(), term()]))\n    end\n\n    test \"conditional checks (andalso/orelse)\" do\n      assert typecheck!([x], is_binary(x) or is_atom(x), x) == dynamic(union(binary(), atom()))\n\n      assert typecheck!([x], is_binary(x) or map_size(x) >= 0, x) ==\n               dynamic(union(binary(), open_map()))\n\n      assert typecheck!([x, y], is_binary(x) or is_atom(y), {x, y}) ==\n               dynamic(tuple([term(), term()]))\n\n      assert typecheck!([x, y], is_binary(x) or map_size(y) >= 0, {x, y}) ==\n               dynamic(tuple([term(), term()]))\n\n      assert typecheck!([x], not (is_pid(x) and is_atom(x)), x) |> equal?(dynamic(term()))\n\n      assert typecheck!([x, y], not (is_pid(x) and is_atom(y)), {x, y}) ==\n               dynamic(tuple([term(), term()]))\n\n      # Error\n      assert typeerror!([x], is_pid(x) and is_atom(x), x) == ~l\"\"\"\n             this guard will never succeed:\n\n                 is_pid(x) and is_atom(x)\n\n             because it returns type:\n\n                 false\n\n             where \"x\" was given the type:\n\n                 # type: pid()\n                 # from: types_test.ex:LINE\n                 is_pid(x)\n             \"\"\"\n\n      assert typeerror!([x], (is_binary(x) or is_atom(x)) and is_pid(x), x) == ~l\"\"\"\n             this guard will never succeed:\n\n                 (is_binary(x) or is_atom(x)) and is_pid(x)\n\n             because it returns type:\n\n                 false\n\n             where \"x\" was given the type:\n\n                 # type: atom() or binary()\n                 # from: types_test.ex:LINE\n                 is_binary(x) or is_atom(x)\n             \"\"\"\n    end\n\n    test \"conditional checks (and/or)\" do\n      assert typecheck!([x], :erlang.or(is_binary(x), is_atom(x)), x) ==\n               dynamic(union(binary(), atom()))\n\n      assert typecheck!([x], :erlang.or(is_binary(x), map_size(x) >= 0), x) ==\n               dynamic(open_map())\n\n      assert typecheck!([x, y], :erlang.or(is_binary(x), is_atom(y)), {x, y}) ==\n               dynamic(tuple([term(), term()]))\n\n      assert typecheck!([x, y], :erlang.or(is_binary(x), map_size(y) >= 0), {x, y}) ==\n               dynamic(tuple([term(), open_map()]))\n\n      assert typecheck!([x], not :erlang.and(is_pid(x), is_atom(x)), x) |> equal?(dynamic(term()))\n\n      assert typecheck!([x, y], not :erlang.and(is_pid(x), is_atom(y)), {x, y}) ==\n               dynamic(tuple([term(), term()]))\n\n      # Error\n      assert typeerror!([x], :erlang.and(is_pid(x), is_atom(x)), x) == ~l\"\"\"\n             this guard will never succeed:\n\n                 :erlang.and(is_pid(x), is_atom(x))\n\n             because it returns type:\n\n                 false\n\n             where \"x\" was given the type:\n\n                 # type: pid()\n                 # from: types_test.ex:LINE\n                 is_pid(x)\n             \"\"\"\n\n      assert typeerror!([x], :erlang.and(:erlang.or(is_binary(x), is_atom(x)), is_pid(x)), x) ==\n               ~l\"\"\"\n               this guard will never succeed:\n\n                   :erlang.and(:erlang.or(is_binary(x), is_atom(x)), is_pid(x))\n\n               because it returns type:\n\n                   false\n\n               where \"x\" was given the type:\n\n                   # type: atom() or binary()\n                   # from: types_test.ex:LINE-1\n                   :erlang.or(is_binary(x), is_atom(x))\n               \"\"\"\n    end\n\n    test \"domain checks\" do\n      # Regular domain check\n      assert typecheck!([x, z], length(x) == z, x) == dynamic(list(term()))\n\n      # erlang-or propagates\n      assert typecheck!([x, y, z], :erlang.or(length(x) == z, map_size(y) == z), {x, y}) ==\n               dynamic(tuple([list(term()), open_map()]))\n\n      # erlang-and propagates\n      assert typecheck!([x, y, z], :erlang.and(length(x) == z, map_size(y) == z), {x, y}) ==\n               dynamic(tuple([list(term()), open_map()]))\n\n      # or with mixed checks\n      assert typecheck!([x, z], length(x) == z or is_map(x), x) ==\n               dynamic(list(term()))\n\n      # or does not propagate\n      assert typecheck!([x, y, z], length(x) == z or map_size(y) == z, {x, y}) ==\n               dynamic(tuple([list(term()), term()]))\n\n      # and propagates\n      assert typecheck!([x, y, z], length(x) == z and map_size(y) == z, {x, y}) ==\n               dynamic(tuple([list(term()), open_map()]))\n\n      # not or does propagate\n      assert typecheck!([x, y, z], not (length(x) == z or map_size(y) == z), {x, y}) ==\n               dynamic(tuple([list(term()), open_map()]))\n\n      # not and does not propagate\n      assert typecheck!([x, y, z], not (length(x) == z and map_size(y) == z), {x, y}) ==\n               dynamic(tuple([list(term()), term()]))\n    end\n\n    test \"incompatible pattern and guards\" do\n      assert typeerror!([x = {}], is_integer(x), x) == ~l\"\"\"\n             the following pattern will never match:\n\n                 x = {}\n\n             where \"x\" was given the type:\n\n                 # type: integer()\n                 # from: types_test.ex:LINE\n                 is_integer(x)\n             \"\"\"\n    end\n  end\n\n  describe \"equality in guards\" do\n    test \"with non-singleton literals\" do\n      assert typecheck!([x], x == \"foo\", x) == dynamic(binary())\n      assert typecheck!([x], x === \"foo\", x) == dynamic(binary())\n      assert typecheck!([x], x in [\"foo\", \"bar\", \"baz\"], x) == dynamic(binary())\n      assert typecheck!([x], not (x == \"foo\"), x) == dynamic()\n      assert typecheck!([x], not (x === \"foo\"), x) == dynamic()\n      assert typecheck!([x], x not in [\"foo\", \"bar\", \"baz\"], x) == dynamic()\n\n      assert typecheck!([x], x != \"foo\", x) == dynamic()\n      assert typecheck!([x], x !== \"foo\", x) == dynamic()\n      assert typecheck!([x], not (x != \"foo\"), x) == dynamic(binary())\n      assert typecheck!([x], not (x !== \"foo\"), x) == dynamic(binary())\n    end\n\n    test \"with binaries\" do\n      assert typecheck!([sep, token], token == <<sep::utf8>>, {sep, token}) ==\n               dynamic(tuple([integer(), binary()]))\n    end\n\n    test \"with number literals\" do\n      assert typecheck!([x], x == 1, x) == dynamic(union(integer(), float()))\n      assert typecheck!([x], x === 1, x) == dynamic(integer())\n      assert typecheck!([x], x in [1, 2, 3], x) == dynamic(integer())\n      assert typecheck!([x], not (x == 1), x) == dynamic()\n      assert typecheck!([x], not (x === 1), x) == dynamic()\n      assert typecheck!([x], x not in [1, 2, 3], x) == dynamic()\n\n      assert typecheck!([x], x != 1, x) == dynamic()\n      assert typecheck!([x], x !== 1, x) == dynamic()\n      assert typecheck!([x], not (x != 1), x) == dynamic(union(integer(), float()))\n      assert typecheck!([x], not (x !== 1), x) == dynamic(integer())\n\n      assert typecheck!([x], x == 1.0, x) == dynamic(union(integer(), float()))\n      assert typecheck!([x], x === 1.0, x) == dynamic(float())\n      assert typecheck!([x], x in [1.0, 2.0, 3.0], x) == dynamic(float())\n      assert typecheck!([x], not (x == 1.0), x) == dynamic()\n      assert typecheck!([x], not (x === 1.0), x) == dynamic()\n      assert typecheck!([x], x not in [1.0, 2.0, 3.0], x) == dynamic()\n\n      assert typecheck!([x], x != 1.0, x) == dynamic()\n      assert typecheck!([x], x !== 1.0, x) == dynamic()\n      assert typecheck!([x], not (x != 1.0), x) == dynamic(union(integer(), float()))\n      assert typecheck!([x], not (x !== 1.0), x) == dynamic(float())\n    end\n\n    test \"with singleton literals\" do\n      assert typecheck!([x], x == :foo, x) == dynamic(atom([:foo]))\n      assert typecheck!([x], x === :foo, x) == dynamic(atom([:foo]))\n      assert typecheck!([x], x in [:foo, :bar, :baz], x) == dynamic(atom([:foo, :bar, :baz]))\n      assert typecheck!([x], not (x == :foo), x) == dynamic(negation(atom([:foo])))\n      assert typecheck!([x], not (x === :foo), x) == dynamic(negation(atom([:foo])))\n      assert typecheck!([x], x not in [:foo, :bar], x) == dynamic(negation(atom([:foo, :bar])))\n\n      assert typecheck!([x], x != :foo, x) == dynamic(negation(atom([:foo])))\n      assert typecheck!([x], x !== :foo, x) == dynamic(negation(atom([:foo])))\n      assert typecheck!([x], not (x != :foo), x) == dynamic(atom([:foo]))\n      assert typecheck!([x], not (x !== :foo), x) == dynamic(atom([:foo]))\n\n      assert typecheck!([x], x == [], x) == dynamic(empty_list())\n      assert typecheck!([x], x === [], x) == dynamic(empty_list())\n      assert typecheck!([x], not (x == []), x) == dynamic(negation(empty_list()))\n      assert typecheck!([x], not (x === []), x) == dynamic(negation(empty_list()))\n\n      assert typecheck!([x], x != [], x) == dynamic(negation(empty_list()))\n      assert typecheck!([x], x !== [], x) == dynamic(negation(empty_list()))\n      assert typecheck!([x], not (x != []), x) == dynamic(empty_list())\n      assert typecheck!([x], not (x !== []), x) == dynamic(empty_list())\n\n      assert typecheck!([x], x != %{}, x) == dynamic(negation(empty_map()))\n      assert typecheck!([x = %{}], x != %{}, x) == dynamic(difference(open_map(), empty_map()))\n    end\n\n    test \"mixed-in\" do\n      assert typecheck!([x], x in [:foo, 1, :bar, 2.0, :baz], x) ==\n               dynamic(union(atom([:foo, :bar, :baz]), union(integer(), float())))\n\n      assert typecheck!([x], x not in [:foo, 1, :bar, 2.0, :baz], x) ==\n               dynamic(negation(atom([:foo, :bar, :baz])))\n    end\n\n    test \"with singleton literals and composite types\" do\n      assert typecheck!([x], x.key == :ok, x) == dynamic(open_map(key: atom([:ok])))\n      assert typecheck!([x], hd(x) == :ok, x) == dynamic(non_empty_list(term(), term()))\n      assert typecheck!([x], elem(x, 0) == :ok, x) == dynamic(open_tuple([atom([:ok])]))\n    end\n\n    test \"with expressions\" do\n      # With numbers\n      assert typecheck!([x, y], x == y and y === 42, {x, y}) ==\n               dynamic(tuple([union(integer(), float()), integer()]))\n\n      assert typecheck!([x, y], x == y and x === 42, {x, y}) ==\n               dynamic(tuple([integer(), union(integer(), float())]))\n\n      assert typecheck!([x, y], x != y and y === 42, {x, y}) ==\n               dynamic(tuple([term(), integer()]))\n\n      assert typecheck!([x, y], x === y and y === 42, {x, y}) ==\n               dynamic(tuple([integer(), integer()]))\n\n      assert typecheck!([x, y], x === y and x === 42, {x, y}) ==\n               dynamic(tuple([integer(), integer()]))\n\n      assert typecheck!([x, y], x !== y and y === 42, {x, y}) ==\n               dynamic(tuple([term(), integer()]))\n\n      # With non-singleton\n      assert typecheck!([x, y], x == y and y === \"42\", {x, y}) ==\n               dynamic(tuple([binary(), binary()]))\n\n      assert typecheck!([x, y], x == y and x === \"42\", {x, y}) ==\n               dynamic(tuple([binary(), binary()]))\n\n      assert typecheck!([x, y], x != y and y === \"42\", {x, y}) ==\n               dynamic(tuple([term(), binary()]))\n\n      # With singleton\n      assert typecheck!([x, y], x == y and y === :ok, {x, y}) ==\n               dynamic(tuple([atom([:ok]), atom([:ok])]))\n\n      assert typecheck!([x, y], x == y and x === :ok, {x, y}) ==\n               dynamic(tuple([atom([:ok]), atom([:ok])]))\n\n      assert typecheck!([x, y], x != y and y === :ok, {x, y}) ==\n               dynamic(tuple([term(), atom([:ok])]))\n\n      # With composite types\n      assert typecheck!([x, y], x == {:ok, y} and y === 42, {x, y}) ==\n               dynamic(tuple([tuple([atom([:ok]), union(integer(), float())]), integer()]))\n\n      assert typecheck!([x, y], x != {:ok, y} and y === 42, {x, y}) ==\n               dynamic(tuple([term(), integer()]))\n\n      assert typecheck!([x, y], x == elem(y, 0) and y === {1, :ok}, {x, y}) ==\n               dynamic(tuple([union(integer(), float()), tuple([integer(), atom([:ok])])]))\n\n      assert typecheck!([x, y], x != elem(y, 0) and y === {1, :ok}, {x, y}) ==\n               dynamic(tuple([term(), tuple([integer(), atom([:ok])])]))\n\n      assert typecheck!([x, y], x == elem(y, 1) and y === {1, :ok}, {x, y}) ==\n               dynamic(tuple([atom([:ok]), tuple([integer(), atom([:ok])])]))\n\n      assert typecheck!([x, y], x != elem(y, 1) and y === {1, :ok}, {x, y}) ==\n               dynamic(tuple([term(), tuple([integer(), atom([:ok])])]))\n    end\n\n    test \"warnings\" do\n      assert typeerror!([x = {}], x == 0, x) =~ ~l\"\"\"\n             the following pattern will never match:\n\n                 x = {}\n\n             where \"x\" was given the type:\n\n                 # type: float() or integer()\n                 # from: types_test.ex:LINE\n                 x == 0\n             \"\"\"\n\n      assert typeerror!([x = {}], x == :foo, x) =~ ~l\"\"\"\n             the following pattern will never match:\n\n                 x = {}\n\n             where \"x\" was given the type:\n\n                 # type: :foo\n                 # from: types_test.ex:LINE\n                 x == :foo\n             \"\"\"\n\n      assert typeerror!([x = {}], not (x != :foo), x) =~ ~l\"\"\"\n             the following pattern will never match:\n\n                 x = {}\n\n             where \"x\" was given the type:\n\n                 # type: :foo\n                 # from: types_test.ex:LINE\n                 x != :foo\n             \"\"\"\n\n      # We cannot warn in this case because the inference itself will lead to disjoint types\n      assert typecheck!([x = {}], not (x == :foo), x) == dynamic(tuple([]))\n      assert typecheck!([x = {}], x != :foo, x) == dynamic(tuple([]))\n    end\n  end\n\n  describe \"size comparison in guards\" do\n    test \"length equality\" do\n      assert typecheck!([x], length(x) != 0, x) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], not (length(x) != 0), x) == dynamic(empty_list())\n\n      assert typecheck!([x], 0 != length(x), x) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], not (0 != length(x)), x) == dynamic(empty_list())\n    end\n\n    test \"length ordered\" do\n      assert typecheck!([x], length(x) < 0, x) == dynamic(list(term()))\n      assert typecheck!([x], length(x) >= 0, x) == dynamic(list(term()))\n      assert typecheck!([x], length(x) <= 0, x) == dynamic(empty_list())\n\n      assert typecheck!([x], 0 <= length(x), x) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], 0 >= length(x), x) == dynamic(list(term()))\n      assert typecheck!([x], 0 < length(x), x) == dynamic(list(term()))\n      assert typecheck!([x], 0 > length(x), x) == dynamic(empty_list())\n\n      assert typecheck!([x], not (length(x) > 0), x) == dynamic(empty_list())\n      assert typecheck!([x], not (length(x) < 0), x) == dynamic(list(term()))\n      assert typecheck!([x], not (length(x) >= 0), x) == dynamic(list(term()))\n      assert typecheck!([x], not (length(x) <= 0), x) == dynamic(non_empty_list(term()))\n\n      assert typecheck!([x], length(x) < 1, x) == dynamic(empty_list())\n\n      assert typecheck!([x], length(x) > 2, x) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], length(x) < 2, x) == dynamic(list(term()))\n      assert typecheck!([x], length(x) >= 2, x) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], length(x) <= 2, x) == dynamic(list(term()))\n\n      assert typecheck!([x], 2 <= length(x), x) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], 2 >= length(x), x) == dynamic(list(term()))\n      assert typecheck!([x], 2 < length(x), x) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], 2 > length(x), x) == dynamic(list(term()))\n\n      assert typecheck!([x], not (length(x) > 2), x) == dynamic(list(term()))\n      assert typecheck!([x], not (length(x) < 2), x) == dynamic(non_empty_list(term()))\n      assert typecheck!([x], not (length(x) >= 2), x) == dynamic(list(term()))\n      assert typecheck!([x], not (length(x) <= 2), x) == dynamic(non_empty_list(term()))\n    end\n\n    @non_empty_map difference(open_map(), empty_map())\n\n    test \"map_size equality\" do\n      assert typecheck!([x], map_size(x) == 0, x) == dynamic(empty_map())\n      assert typecheck!([x], map_size(x) != 0, x) == dynamic(@non_empty_map)\n      assert typecheck!([x], not (map_size(x) == 0), x) == dynamic(@non_empty_map)\n      assert typecheck!([x], not (map_size(x) != 0), x) == dynamic(empty_map())\n\n      assert typecheck!([x], 0 == map_size(x), x) == dynamic(empty_map())\n      assert typecheck!([x], 0 != map_size(x), x) == dynamic(@non_empty_map)\n      assert typecheck!([x], not (0 == map_size(x)), x) == dynamic(@non_empty_map)\n      assert typecheck!([x], not (0 != map_size(x)), x) == dynamic(empty_map())\n    end\n\n    test \"map_size ordered\" do\n      assert typecheck!([x], map_size(x) > 0, x) == dynamic(@non_empty_map)\n      assert typecheck!([x], map_size(x) < 0, x) == dynamic(open_map())\n      assert typecheck!([x], map_size(x) >= 0, x) == dynamic(open_map())\n      assert typecheck!([x], map_size(x) <= 0, x) == dynamic(empty_map())\n\n      assert typecheck!([x], 0 <= map_size(x), x) == dynamic(@non_empty_map)\n      assert typecheck!([x], 0 >= map_size(x), x) == dynamic(open_map())\n      assert typecheck!([x], 0 < map_size(x), x) == dynamic(open_map())\n      assert typecheck!([x], 0 > map_size(x), x) == dynamic(empty_map())\n\n      assert typecheck!([x], not (map_size(x) > 0), x) == dynamic(empty_map())\n      assert typecheck!([x], not (map_size(x) < 0), x) == dynamic(open_map())\n      assert typecheck!([x], not (map_size(x) >= 0), x) == dynamic(open_map())\n      assert typecheck!([x], not (map_size(x) <= 0), x) == dynamic(@non_empty_map)\n\n      assert typecheck!([x], map_size(x) < 1, x) == dynamic(empty_map())\n\n      assert typecheck!([x], map_size(x) > 2, x) == dynamic(@non_empty_map)\n      assert typecheck!([x], map_size(x) < 2, x) == dynamic(open_map())\n      assert typecheck!([x], map_size(x) >= 2, x) == dynamic(@non_empty_map)\n      assert typecheck!([x], map_size(x) <= 2, x) == dynamic(open_map())\n\n      assert typecheck!([x], 2 <= map_size(x), x) == dynamic(@non_empty_map)\n      assert typecheck!([x], 2 >= map_size(x), x) == dynamic(open_map())\n      assert typecheck!([x], 2 < map_size(x), x) == dynamic(@non_empty_map)\n      assert typecheck!([x], 2 > map_size(x), x) == dynamic(open_map())\n\n      assert typecheck!([x], not (map_size(x) > 2), x) == dynamic(open_map())\n      assert typecheck!([x], not (map_size(x) < 2), x) == dynamic(@non_empty_map)\n      assert typecheck!([x], not (map_size(x) >= 2), x) == dynamic(open_map())\n      assert typecheck!([x], not (map_size(x) <= 2), x) == dynamic(@non_empty_map)\n    end\n\n    @non_empty_tuple difference(open_tuple([]), tuple([]))\n    @non_binary_tuple difference(open_tuple([]), tuple([term(), term()]))\n\n    @open_binary_tuple open_tuple([term(), term()])\n    @open_ternary_tuple open_tuple([term(), term(), term()])\n    @non_open_binary_tuple difference(open_tuple([]), open_tuple([term(), term()]))\n    @non_open_ternary_tuple difference(open_tuple([]), open_tuple([term(), term(), term()]))\n\n    test \"tuple_size equality\" do\n      assert typecheck!([x], tuple_size(x) == 0, x) == dynamic(tuple([]))\n      assert typecheck!([x], tuple_size(x) != 0, x) == dynamic(@non_empty_tuple)\n      assert typecheck!([x], not (tuple_size(x) == 0), x) == dynamic(@non_empty_tuple)\n      assert typecheck!([x], not (tuple_size(x) != 0), x) == dynamic(tuple([]))\n\n      assert typecheck!([x], 0 == tuple_size(x), x) == dynamic(tuple([]))\n      assert typecheck!([x], 0 != tuple_size(x), x) == dynamic(@non_empty_tuple)\n      assert typecheck!([x], not (0 == tuple_size(x)), x) == dynamic(@non_empty_tuple)\n      assert typecheck!([x], not (0 != tuple_size(x)), x) == dynamic(tuple([]))\n\n      assert typecheck!([x], tuple_size(x) == 2, x) == dynamic(tuple([term(), term()]))\n      assert typecheck!([x], tuple_size(x) != 2, x) == dynamic(@non_binary_tuple)\n      assert typecheck!([x], not (tuple_size(x) == 2), x) == dynamic(@non_binary_tuple)\n      assert typecheck!([x], not (tuple_size(x) != 2), x) == dynamic(tuple([term(), term()]))\n\n      assert typecheck!([x], 2 == tuple_size(x), x) == dynamic(tuple([term(), term()]))\n      assert typecheck!([x], 2 != tuple_size(x), x) == dynamic(@non_binary_tuple)\n      assert typecheck!([x], not (2 == tuple_size(x)), x) == dynamic(@non_binary_tuple)\n      assert typecheck!([x], not (2 != tuple_size(x)), x) == dynamic(tuple([term(), term()]))\n    end\n\n    test \"tuple_size ordered\" do\n      assert typecheck!([x], tuple_size(x) > 0, x) == dynamic(open_tuple([term()]))\n      assert typecheck!([x], tuple_size(x) < 0, x) == dynamic(open_tuple([]))\n      assert typecheck!([x], tuple_size(x) >= 0, x) == dynamic(open_tuple([]))\n      assert typecheck!([x], tuple_size(x) <= 0, x) == dynamic(tuple([]))\n\n      assert typecheck!([x], 0 <= tuple_size(x), x) == dynamic(open_tuple([term()]))\n      assert typecheck!([x], 0 >= tuple_size(x), x) == dynamic(open_tuple([]))\n      assert typecheck!([x], 0 < tuple_size(x), x) == dynamic(open_tuple([]))\n      assert typecheck!([x], 0 > tuple_size(x), x) == dynamic(tuple([]))\n\n      assert typecheck!([x], not (tuple_size(x) > 0), x) == dynamic(tuple([]))\n      assert typecheck!([x], not (tuple_size(x) < 0), x) == dynamic(open_tuple([]))\n      assert typecheck!([x], not (tuple_size(x) >= 0), x) == dynamic(open_tuple([]))\n      assert typecheck!([x], not (tuple_size(x) <= 0), x) == dynamic(open_tuple([term()]))\n\n      assert typecheck!([x], tuple_size(x) > 2, x) == dynamic(@open_ternary_tuple)\n      assert typecheck!([x], tuple_size(x) < 2, x) == dynamic(@non_open_binary_tuple)\n      assert typecheck!([x], tuple_size(x) >= 2, x) == dynamic(@open_binary_tuple)\n      assert typecheck!([x], tuple_size(x) <= 2, x) == dynamic(@non_open_ternary_tuple)\n\n      assert typecheck!([x], 2 <= tuple_size(x), x) == dynamic(@open_ternary_tuple)\n      assert typecheck!([x], 2 >= tuple_size(x), x) == dynamic(@non_open_binary_tuple)\n      assert typecheck!([x], 2 < tuple_size(x), x) == dynamic(@open_binary_tuple)\n      assert typecheck!([x], 2 > tuple_size(x), x) == dynamic(@non_open_ternary_tuple)\n\n      assert typecheck!([x], not (tuple_size(x) > 2), x) == dynamic(@non_open_ternary_tuple)\n      assert typecheck!([x], not (tuple_size(x) < 2), x) == dynamic(@open_binary_tuple)\n      assert typecheck!([x], not (tuple_size(x) >= 2), x) == dynamic(@non_open_binary_tuple)\n      assert typecheck!([x], not (tuple_size(x) <= 2), x) == dynamic(@open_ternary_tuple)\n    end\n  end\n\n  describe \"precision\" do\n    test \"literals in patterns\" do\n      assert precise?([:ok])\n      refute precise?([123])\n      refute precise?([123.0])\n      refute precise?([\"string\"])\n    end\n\n    test \"variables in patterns\" do\n      assert precise?([x])\n      assert precise?([x, y])\n      refute precise?([x, x])\n    end\n\n    test \"bitstrings in patterns\" do\n      assert precise?([<<_::binary>>])\n      assert precise?([<<_::bytes>>])\n      assert precise?([<<_::bitstring>>])\n      assert precise?([<<_::bits>>])\n      assert precise?([<<(<<_::binary>>)::bits>>])\n\n      refute precise?([<<>>])\n      refute precise?([<<1, _::binary>>])\n      refute precise?([<<1, _::bitstring>>])\n      refute precise?([<<_::binary-size(8)>>])\n      refute precise?([<<_::bitstring-size(8)>>])\n      refute precise?([<<(<<123>>)::bits>>])\n    end\n\n    test \"tuples in patterns\" do\n      assert precise?([{:ok, _}])\n      refute precise?([{:ok, 123}])\n    end\n\n    test \"maps in patterns\" do\n      assert precise?([%{ok: _}])\n      assert precise?([%URI{path: _}])\n\n      refute precise?([%{ok: 123}])\n      refute precise?([%{\"foo\" => _}])\n    end\n\n    test \"lists in patterns\" do\n      assert precise?([[]])\n      assert precise?([[_ | _]])\n      assert precise?([x, [y | z]])\n\n      refute precise?([[x | y]], is_integer(x))\n      refute precise?([[x | x]])\n      refute precise?([x, [x | y]])\n\n      refute precise?([[:ok | _]])\n      refute precise?([[_ | :ok]])\n    end\n\n    test \"guards\" do\n      assert precise?([x], is_integer(x))\n      assert precise?([x], not is_integer(x))\n      assert precise?([x], is_integer(x) or is_boolean(x))\n      assert precise?([x], x == :ok or x == :error)\n      assert precise?([x], x.key == :ok)\n      assert precise?([x], elem(x, 0) == :ok)\n      assert precise?([x], :erlang.map_get(:key, x) == :ok)\n      assert precise?([x], x != :ok)\n      assert precise?([x], not (x == :ok))\n      assert precise?([x], x.key != :ok)\n      assert precise?([x], not (x.key != :ok))\n      assert precise?([x, y], x == :ok and y == :error)\n\n      refute precise?([x, y], x == y)\n      refute precise?([x], x == 123)\n      refute precise?([x], x == 123.0)\n      refute precise?([x], x > 123)\n      refute precise?([x], x > :ok)\n      refute precise?([x, y], x == hd(y))\n      refute precise?([x], hd(x) == :ok)\n      refute precise?([x, y], x == :ok and y == 123)\n      refute precise?([x, y], x == :ok or y == :error)\n      refute precise?([x], x <= 0 or x == :infinity)\n    end\n\n    test \"when guards\" do\n      assert precise?([x, y], is_integer(x) when is_binary(x))\n      refute precise?([x, y], is_integer(x) when is_binary(y))\n    end\n\n    test \"sized guards\" do\n      # Tuples: everything goes\n      assert precise?([x], tuple_size(x) == 0)\n      assert precise?([x], tuple_size(x) != 0)\n      assert precise?([x], tuple_size(x) > 0)\n      assert precise?([x], tuple_size(x) >= 0)\n      assert precise?([x], tuple_size(x) > 10)\n      assert precise?([x], tuple_size(x) < 10)\n\n      # Lists: only when compared to 0\n      assert precise?([x], not (length(x) == 0))\n      assert precise?([x], length(x) != 0)\n      assert precise?([x], not (length(x) > 0))\n      assert precise?([x], length(x) >= 0)\n      assert precise?([x], length(x) < 1)\n\n      refute precise?([x], length(x) == 1)\n      refute precise?([x], length(x) != 1)\n      refute precise?([x], length(x) > 1)\n      refute precise?([x], length(x) <= 3)\n\n      # Maps: only when compared to 0\n      assert precise?([x], map_size(x) == 0)\n      assert precise?([x], map_size(x) != 0)\n      assert precise?([x], map_size(x) > 0)\n      assert precise?([x], map_size(x) >= 0)\n      assert precise?([x], map_size(x) < 1)\n\n      refute precise?([x], map_size(x) == 1)\n      refute precise?([x], map_size(x) != 1)\n      refute precise?([x], map_size(x) > 1)\n      refute precise?([x], map_size(x) <= 3)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module/types/type_helper.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Point do\n  defstruct [:x, :y, z: 0]\nend\n\ndefmodule TypeHelper do\n  alias Module.Types\n  alias Module.Types.{Pattern, Expr, Descr}\n\n  @doc \"\"\"\n  Main helper for checking the precise of pattern plus guards.\n  \"\"\"\n  defmacro precise?(patterns, guards \\\\ true) do\n    quote do\n      unquote(precise(patterns, guards, __CALLER__))\n    end\n  end\n\n  @doc \"\"\"\n  Main helper for checking the given AST type checks without warnings in dynamic mode.\n  \"\"\"\n  defmacro typedyn!(patterns \\\\ [], guards \\\\ true, body) do\n    quote do\n      unquote(typecheck(:dynamic, patterns, guards, body, __CALLER__))\n      |> TypeHelper.__typecheck__!()\n    end\n  end\n\n  @doc \"\"\"\n  Main helper for checking the given AST type checks without warnings in static mode.\n  \"\"\"\n  defmacro typecheck!(patterns \\\\ [], guards \\\\ true, body) do\n    quote do\n      unquote(typecheck(:static, patterns, guards, body, __CALLER__))\n      |> TypeHelper.__typecheck__!()\n    end\n  end\n\n  @doc \"\"\"\n  Main helper for checking the given AST type checks errors.\n  \"\"\"\n  defmacro typeerror!(patterns \\\\ [], guards \\\\ true, body) do\n    [patterns, guards, body] = prune_columns([patterns, guards, body])\n\n    quote do\n      unquote(typecheck(:static, patterns, guards, body, __CALLER__))\n      |> TypeHelper.__typeerror__!()\n    end\n  end\n\n  @doc \"\"\"\n  Main helper for checking the given AST type warns.\n  \"\"\"\n  defmacro typewarn!(patterns \\\\ [], guards \\\\ true, body) do\n    [patterns, guards, body] = prune_columns([patterns, guards, body])\n\n    quote do\n      unquote(typecheck(:static, patterns, guards, body, __CALLER__))\n      |> TypeHelper.__typewarn__!()\n    end\n  end\n\n  @doc \"\"\"\n  Main helper for checking the diagnostic of a given AST.\n  \"\"\"\n  defmacro typediag!(patterns \\\\ [], guards \\\\ true, body) do\n    quote do\n      unquote(typecheck(:static, patterns, guards, body, __CALLER__))\n      |> TypeHelper.__typediag__!()\n    end\n  end\n\n  @doc false\n  def __typecheck__!({type, %{warnings: []}}), do: type\n\n  def __typecheck__!({_type, %{warnings: warnings, failed: false}}),\n    do: raise(\"type checking ok but with warnings: #{inspect(warnings)}\")\n\n  def __typecheck__!({_type, %{warnings: warnings, failed: true}}),\n    do: raise(\"type checking errored with warnings: #{inspect(warnings)}\")\n\n  @doc false\n  def __typeerror__!({_type, %{warnings: [{module, warning, _locs} | _], failed: true}}),\n    do: module.format_diagnostic(warning).message\n\n  def __typeerror__!({_type, %{warnings: warnings, failed: false}}),\n    do: raise(\"type checking with warnings but expected error: #{inspect(warnings)}\")\n\n  def __typeerror__!({type, _}),\n    do: raise(\"type checking ok but expected error: #{Descr.to_quoted_string(type)}\")\n\n  @doc false\n  def __typediag__!({type, %{warnings: [_ | _] = warnings}}),\n    do: {type, for({module, arg, _} <- warnings, do: module.format_diagnostic(arg))}\n\n  def __typediag__!({type, %{warnings: []}}),\n    do: raise(\"type checking without diagnostics: #{Descr.to_quoted_string(type)}\")\n\n  @doc false\n  def __typewarn__!({type, %{warnings: [{module, warning, _locs}], failed: false}}),\n    do: {type, module.format_diagnostic(warning).message}\n\n  def __typewarn__!({type, %{warnings: []}}),\n    do: raise(\"type checking ok without warnings: #{Descr.to_quoted_string(type)}\")\n\n  def __typewarn__!({_type, %{warnings: warnings, failed: false}}),\n    do: raise(\"type checking ok but many warnings: #{inspect(warnings)}\")\n\n  def __typewarn__!({_type, %{warnings: warnings, failed: true}}),\n    do: raise(\"type checking errored with warnings: #{inspect(warnings)}\")\n\n  defp typecheck(mode, patterns, guards, body, env) do\n    {patterns, guards, body} = expand_and_unpack(patterns, guards, body, env)\n\n    quote do\n      TypeHelper.__typecheck__(\n        unquote(mode),\n        unquote(Macro.escape(patterns)),\n        unquote(Macro.escape(guards)),\n        unquote(Macro.escape(body))\n      )\n    end\n  end\n\n  defp precise(patterns, guards, env) do\n    {_, vars} =\n      Macro.prewalk(patterns, [], fn\n        {:\"::\", _, [left, _right]}, acc ->\n          {left, acc}\n\n        {name, _, ctx} = var, acc when is_atom(ctx) and name != :_ ->\n          {var, [var | acc]}\n\n        node, acc ->\n          {node, acc}\n      end)\n\n    {patterns, guards, _body} = expand_and_unpack(patterns, guards, vars, env)\n\n    quote do\n      TypeHelper.__precise__?(\n        unquote(Macro.escape(patterns)),\n        unquote(Macro.escape(guards))\n      )\n    end\n  end\n\n  def __precise__?(patterns, guards) do\n    stack = new_stack(:static)\n    expected = Enum.map(patterns, fn _ -> Descr.dynamic() end)\n    init_previous = Pattern.init_previous()\n    tag = {:fn, patterns}\n\n    {_trees, previous, _context} =\n      Pattern.of_head(patterns, guards, expected, init_previous, tag, [], stack, new_context())\n\n    previous != init_previous\n  end\n\n  def __typecheck__(mode, patterns, guards, body) do\n    stack = new_stack(mode)\n    expected = Enum.map(patterns, fn _ -> Descr.dynamic() end)\n    previous = Pattern.init_previous()\n    tag = {:fn, patterns}\n\n    {_trees, _precise?, context} =\n      Pattern.of_head(patterns, guards, expected, previous, tag, [], stack, new_context())\n\n    Expr.of_expr(body, Descr.term(), :ok, stack, context)\n  end\n\n  defp expand_and_unpack(patterns, guards, body, env) do\n    fun =\n      quote do\n        fn unquote_splicing(patterns) when unquote(guards) -> unquote(body) end\n      end\n\n    {ast, _, _} = :elixir_expand.expand(fun, :elixir_env.env_to_ex(env), env)\n    {:fn, _, [{:->, _, [[{:when, _, args}], body]}]} = ast\n    {patterns, [guards]} = Enum.split(args, -1)\n    {patterns, flatten_when(guards), body}\n  end\n\n  defp flatten_when({:when, _meta, [left, right]}), do: [left | flatten_when(right)]\n  defp flatten_when(other), do: [other]\n\n  defp new_stack(mode) do\n    cache =\n      if mode == :infer do\n        :none\n      else\n        {:ok, cache} = Module.ParallelChecker.start_link()\n        cache\n      end\n\n    handler = fn _, fun_arity, _, _ -> raise \"no local lookup for: #{inspect(fun_arity)}\" end\n    Types.stack(mode, \"types_test.ex\", TypesTest, {:test, 0}, [], cache, handler)\n  end\n\n  defp new_context() do\n    Types.context()\n  end\n\n  @doc \"\"\"\n  Interpolate the given hints.\n  \"\"\"\n  def hints(hints) do\n    hints\n    |> List.wrap()\n    |> Module.Types.Helpers.format_hints()\n    |> IO.iodata_to_binary()\n    |> String.trim()\n  end\n\n  @doc \"\"\"\n  A string-like sigil that replaces LINE references by actual line.\n  \"\"\"\n  defmacro sigil_l({:<<>>, meta, parts}, []) do\n    parts =\n      for part <- parts do\n        if is_binary(part) do\n          part\n          |> replace_line(__CALLER__.line)\n          |> :elixir_interpolation.unescape_string()\n        else\n          part\n        end\n      end\n\n    {:<<>>, meta, parts}\n  end\n\n  @strip_ansi [IO.ANSI.green(), IO.ANSI.red(), IO.ANSI.reset()]\n\n  @doc \"\"\"\n  Strip ansi escapes from message.\n  \"\"\"\n  def strip_ansi(doc) do\n    String.replace(doc, @strip_ansi, \"\")\n  end\n\n  defp replace_line(string, line) do\n    [head | rest] = String.split(string, \"LINE\")\n\n    rest =\n      for part <- rest do\n        case part do\n          <<?-, num, part::binary>> when num in ?0..?9 ->\n            [Integer.to_string(line - num + ?0), part]\n\n          part ->\n            [Integer.to_string(line), part]\n        end\n      end\n\n    IO.iodata_to_binary([head | rest])\n  end\n\n  defp prune_columns(ast) do\n    Macro.prewalk(ast, fn node ->\n      Macro.update_meta(node, &Keyword.delete(&1, :column))\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/module_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule ModuleTest.ToBeUsed do\n  def value, do: 1\n\n  defmacro __using__(_) do\n    target = __CALLER__.module\n    Module.put_attribute(target, :has_callback, true)\n    Module.put_attribute(target, :before_compile, __MODULE__)\n    Module.put_attribute(target, :after_compile, __MODULE__)\n    Module.put_attribute(target, :before_compile, {__MODULE__, :callback})\n    quote(do: def(line, do: __ENV__.line))\n  end\n\n  defmacro __before_compile__(env) do\n    quote(do: def(before_compile, do: unquote(Macro.Env.vars(env))))\n  end\n\n  defmacro __after_compile__(%Macro.Env{module: ModuleTest.ToUse} = env, bin)\n           when is_binary(bin) do\n    # Ensure module is not longer tracked as being loaded\n    false = __MODULE__ in :elixir_module.compiler_modules()\n    [] = Macro.Env.vars(env)\n    :ok\n  end\n\n  defmacro callback(env) do\n    value = Module.get_attribute(env.module, :has_callback)\n\n    quote do\n      def callback_value(true), do: unquote(value)\n    end\n  end\nend\n\ndefmodule ModuleTest.ToUse do\n  # Moving the next line around can make tests fail\n  42 = __ENV__.line\n  var = 1\n  # Not available in callbacks\n  _ = var\n  def callback_value(false), do: false\n  use ModuleTest.ToBeUsed\nend\n\ndefmodule ModuleTest do\n  use ExUnit.Case, async: true\n\n  doctest Module\n\n  Module.register_attribute(__MODULE__, :register_unset_example, persist: true)\n  Module.register_attribute(__MODULE__, :register_empty_example, accumulate: true, persist: true)\n  Module.register_attribute(__MODULE__, :register_example, accumulate: true, persist: true)\n  @register_example :it_works\n  @register_example :still_works\n\n  defp purge(module) do\n    :code.purge(module)\n    :code.delete(module)\n  end\n\n  defmacrop in_module(block) do\n    quote do\n      defmodule(Temp, unquote(block))\n      purge(Temp)\n    end\n  end\n\n  test \"module attributes returns value\" do\n    in_module do\n      assert @return([:foo, :bar]) == :ok\n      _ = @return\n    end\n  end\n\n  test \"raises on write access attempts from __after_compile__/2\" do\n    contents =\n      quote do\n        @after_compile __MODULE__\n\n        def __after_compile__(%Macro.Env{module: module}, bin) when is_binary(bin) do\n          Module.put_attribute(module, :foo, 42)\n        end\n      end\n\n    assert_raise ArgumentError,\n                 \"could not call Module.put_attribute/3 because the module ModuleTest.Raise is in read-only mode (@after_compile)\",\n                 fn ->\n                   Module.create(ModuleTest.Raise, contents, __ENV__)\n                 end\n  end\n\n  test \"supports read access to module from __after_compile__/2\" do\n    defmodule ModuleTest.NoRaise do\n      @after_compile __MODULE__\n      @foo 42\n\n      def __after_compile__(%Macro.Env{module: module}, bin) when is_binary(bin) do\n        send(self(), Module.get_attribute(module, :foo))\n      end\n    end\n\n    assert_received 42\n  end\n\n  test \"supports @after_verify for inlined modules\" do\n    defmodule ModuleTest.AfterVerify do\n      @after_verify __MODULE__\n\n      def __after_verify__(ModuleTest.AfterVerify) do\n        send(self(), ModuleTest.AfterVerify)\n      end\n    end\n\n    assert_received ModuleTest.AfterVerify\n  end\n\n  test \"in memory modules are tagged as so\" do\n    assert :code.which(__MODULE__) == ~c\"\"\n  end\n\n  ## Callbacks\n\n  test \"retrieves line from use callsite\" do\n    assert ModuleTest.ToUse.line() == 47\n  end\n\n  test \"executes custom before_compile callback\" do\n    assert ModuleTest.ToUse.callback_value(true) == true\n    assert ModuleTest.ToUse.callback_value(false) == false\n  end\n\n  test \"executes default before_compile callback\" do\n    assert ModuleTest.ToUse.before_compile() == []\n  end\n\n  def __on_definition__(env, kind, name, args, guards, expr) do\n    Process.put(env.module, {args, guards, expr})\n    assert env.module == ModuleTest.OnDefinition\n    assert kind == :def\n    assert name == :hello\n    assert Module.defines?(env.module, {:hello, 2})\n  end\n\n  test \"executes on definition callback\" do\n    defmodule OnDefinition do\n      @on_definition ModuleTest\n\n      def hello(foo, bar)\n\n      assert {[{:foo, _, _}, {:bar, _, _}], [], nil} = Process.get(ModuleTest.OnDefinition)\n\n      def hello(foo, bar) do\n        foo + bar\n      end\n\n      assert {[{:foo, _, _}, {:bar, _, _}], [], [do: {:+, _, [{:foo, _, nil}, {:bar, _, nil}]}]} =\n               Process.get(ModuleTest.OnDefinition)\n    end\n  end\n\n  defmacro __before_compile__(_) do\n    quote do\n      def constant, do: 1\n      defoverridable constant: 0\n    end\n  end\n\n  test \"may set overridable inside before_compile callback\" do\n    defmodule OverridableWithBeforeCompile do\n      @before_compile ModuleTest\n    end\n\n    assert OverridableWithBeforeCompile.constant() == 1\n  end\n\n  describe \"__info__(:attributes)\" do\n    test \"reserved attributes\" do\n      assert List.keyfind(ExUnit.Server.__info__(:attributes), :behaviour, 0) ==\n               {:behaviour, [GenServer]}\n    end\n\n    test \"registered attributes\" do\n      assert Enum.filter(__MODULE__.__info__(:attributes), &match?({:register_example, _}, &1)) ==\n               [{:register_example, [:it_works]}, {:register_example, [:still_works]}]\n    end\n\n    test \"registered attributes with no values are not present\" do\n      refute List.keyfind(__MODULE__.__info__(:attributes), :register_unset_example, 0)\n      refute List.keyfind(__MODULE__.__info__(:attributes), :register_empty_example, 0)\n    end\n  end\n\n  @some_attribute [1]\n  @other_attribute [3, 2, 1]\n\n  test \"inside function attributes\" do\n    assert @some_attribute == [1]\n    assert @other_attribute == [3, 2, 1]\n  end\n\n  ## Naming\n\n  test \"concat\" do\n    assert Module.concat(Foo, Bar) == Foo.Bar\n    assert Module.concat(Foo, :Bar) == Foo.Bar\n    assert Module.concat(Foo, \"Bar\") == Foo.Bar\n    assert Module.concat(Foo, Bar.Baz) == Foo.Bar.Baz\n    assert Module.concat(Foo, \"Bar.Baz\") == Foo.Bar.Baz\n    assert Module.concat(Bar, nil) == Elixir.Bar\n  end\n\n  test \"safe concat\" do\n    assert Module.safe_concat(Foo, :Bar) == Foo.Bar\n\n    assert_raise ArgumentError, fn ->\n      Module.safe_concat(SafeConcat, Doesnt.Exist)\n    end\n  end\n\n  test \"split\" do\n    module = Very.Long.Module.Name.And.Even.Longer\n    assert Module.split(module) == [\"Very\", \"Long\", \"Module\", \"Name\", \"And\", \"Even\", \"Longer\"]\n    assert Module.split(\"Elixir.Very.Long\") == [\"Very\", \"Long\"]\n\n    assert_raise ArgumentError, \"expected an Elixir module, got: :just_an_atom\", fn ->\n      Module.split(:just_an_atom)\n    end\n\n    assert_raise ArgumentError, \"expected an Elixir module, got: \\\"Foo\\\"\", fn ->\n      Module.split(\"Foo\")\n    end\n\n    assert Module.concat(Module.split(module)) == module\n  end\n\n  test \"__MODULE__\" do\n    assert Code.eval_string(\"__MODULE__.Foo\") |> elem(0) == Foo\n  end\n\n  test \"__ENV__.file\" do\n    assert Path.basename(__ENV__.file) == \"module_test.exs\"\n  end\n\n  @file \"sample.ex\"\n  test \"@file sets __ENV__.file\" do\n    assert __ENV__.file == Path.absname(\"sample.ex\")\n  end\n\n  test \"@file raises when invalid\" do\n    assert_raise ArgumentError, ~r\"@file is a built-in module attribute\", fn ->\n      defmodule BadFile do\n        @file :oops\n        def my_fun, do: :ok\n      end\n    end\n  end\n\n  ## Creation\n\n  test \"defmodule\" do\n    result =\n      defmodule Defmodule do\n        1 + 2\n      end\n\n    assert {:module, Defmodule, binary, 3} = result\n    assert is_binary(binary)\n  end\n\n  test \"defmodule with atom\" do\n    result =\n      defmodule :root_defmodule do\n        :ok\n      end\n\n    assert {:module, :root_defmodule, _, _} = result\n  end\n\n  test \"does not leak alias from atom\" do\n    defmodule :\"Elixir.ModuleTest.RawModule\" do\n      def hello, do: :world\n    end\n\n    refute __ENV__.aliases[Elixir.ModuleTest]\n    refute __ENV__.aliases[Elixir.RawModule]\n    assert ModuleTest.RawModule.hello() == :world\n  end\n\n  test \"does not leak alias from non-atom alias\" do\n    defmodule __MODULE__.NonAtomAlias do\n      def hello, do: :world\n    end\n\n    refute __ENV__.aliases[Elixir.ModuleTest]\n    refute __ENV__.aliases[Elixir.NonAtomAlias]\n    assert Elixir.ModuleTest.NonAtomAlias.hello() == :world\n  end\n\n  test \"does not leak alias from Elixir root alias\" do\n    defmodule Elixir.ModuleTest.ElixirRootAlias do\n      def hello, do: :world\n    end\n\n    refute __ENV__.aliases[Elixir.ModuleTest]\n    refute __ENV__.aliases[Elixir.ElixirRootAlias]\n    assert Elixir.ModuleTest.ElixirRootAlias.hello() == :world\n  end\n\n  test \"does not warn on captured underscored vars\" do\n    _unused = 123\n\n    defmodule __MODULE__.NoVarWarning do\n    end\n  end\n\n  @compile {:no_warn_undefined, ModuleCreateSample}\n\n  test \"create\" do\n    contents =\n      quote do\n        def world, do: true\n      end\n\n    {:module, ModuleCreateSample, _, _} = Module.create(ModuleCreateSample, contents, __ENV__)\n    assert ModuleCreateSample.world()\n  end\n\n  test \"create with a reserved module name\" do\n    contents =\n      quote do\n        def world, do: true\n      end\n\n    assert_raise CompileError, ~r/cannot compile module Elixir/, fn ->\n      Code.with_diagnostics(fn ->\n        Module.create(Elixir, contents, __ENV__)\n      end)\n    end\n  end\n\n  @compile {:no_warn_undefined, ModuleTracersSample}\n\n  test \"create with propagated tracers\" do\n    contents =\n      quote do\n        def world, do: true\n      end\n\n    env = %{__ENV__ | tracers: [:invalid]}\n    {:module, ModuleTracersSample, _, _} = Module.create(ModuleTracersSample, contents, env)\n    assert ModuleTracersSample.world()\n  end\n\n  @compile {:no_warn_undefined, ModuleHygiene}\n\n  test \"create with aliases/var hygiene\" do\n    contents =\n      quote do\n        alias List, as: L\n\n        def test do\n          L.flatten([1, [2], 3])\n        end\n      end\n\n    Module.create(ModuleHygiene, contents, __ENV__)\n    assert ModuleHygiene.test() == [1, 2, 3]\n  end\n\n  test \"ensure function clauses are sorted (to avoid non-determinism in module vsn)\" do\n    {_, _, binary, _} =\n      defmodule Ordered do\n        def foo(:foo), do: :bar\n        def baz(:baz), do: :bat\n      end\n\n    {:ok, {ModuleTest.Ordered, [abstract_code: {:raw_abstract_v1, abstract_code}]}} =\n      :beam_lib.chunks(binary, [:abstract_code])\n\n    # We need to traverse functions instead of using :exports as exports are sorted\n    funs = for {:function, _, name, arity, _} <- abstract_code, do: {name, arity}\n    assert funs == [__info__: 1, baz: 1, foo: 1]\n  end\n\n  @compile {:no_warn_undefined, ModuleCreateGenerated}\n\n  test \"create with generated true does not emit warnings\" do\n    contents =\n      quote generated: true do\n        def world, do: true\n        def world, do: false\n      end\n\n    {:module, ModuleCreateGenerated, _, _} =\n      Module.create(ModuleCreateGenerated, contents, __ENV__)\n\n    assert ModuleCreateGenerated.world()\n  end\n\n  test \"uses the debug_info chunk\" do\n    {:module, ModuleCreateDebugInfo, binary, _} =\n      Module.create(ModuleCreateDebugInfo, :ok, __ENV__)\n\n    {:ok, {_, [debug_info: {:debug_info_v1, backend, data}]}} =\n      :beam_lib.chunks(binary, [:debug_info])\n\n    {:ok, map} = backend.debug_info(:elixir_v1, ModuleCreateDebugInfo, data, [])\n    assert map.module == ModuleCreateDebugInfo\n  end\n\n  test \"uses the debug_info chunk when explicitly set to true\" do\n    {:module, ModuleCreateDebugInfoTrue, binary, _} =\n      Module.create(ModuleCreateDebugInfoTrue, quote(do: @compile({:debug_info, true})), __ENV__)\n\n    {:ok, {_, [debug_info: {:debug_info_v1, backend, data}]}} =\n      :beam_lib.chunks(binary, [:debug_info])\n\n    {:ok, map} = backend.debug_info(:elixir_v1, ModuleCreateDebugInfoTrue, data, [])\n    assert map.module == ModuleCreateDebugInfoTrue\n  end\n\n  test \"uses the debug_info chunk even if debug_info is set to false\" do\n    {:module, ModuleCreateNoDebugInfo, binary, _} =\n      Module.create(ModuleCreateNoDebugInfo, quote(do: @compile({:debug_info, false})), __ENV__)\n\n    {:ok, {_, [debug_info: {:debug_info_v1, backend, data}]}} =\n      :beam_lib.chunks(binary, [:debug_info])\n\n    assert backend.debug_info(:elixir_v1, ModuleCreateNoDebugInfo, data, []) == {:error, :missing}\n  end\n\n  test \"compiles to core\" do\n    import PathHelpers\n\n    write_beam(\n      defmodule ExampleModule do\n      end\n    )\n\n    {:ok, {ExampleModule, [{~c\"Dbgi\", dbgi}]}} =\n      ExampleModule |> :code.which() |> :beam_lib.chunks([~c\"Dbgi\"])\n\n    {:debug_info_v1, backend, data} = :erlang.binary_to_term(dbgi)\n    {:ok, core} = backend.debug_info(:core_v1, ExampleModule, data, [])\n    assert is_tuple(core)\n  end\n\n  test \"no function in module body\" do\n    in_module do\n      assert __ENV__.function == nil\n    end\n  end\n\n  test \"does not use ETS tables named after the module\" do\n    in_module do\n      assert :ets.info(__MODULE__) == :undefined\n    end\n  end\n\n  ## Definitions\n\n  test \"defines?\" do\n    in_module do\n      refute Module.defines?(__MODULE__, {:foo, 0})\n      def foo(), do: bar()\n      assert Module.defines?(__MODULE__, {:foo, 0})\n      assert Module.defines?(__MODULE__, {:foo, 0}, :def)\n\n      refute Module.defines?(__MODULE__, {:bar, 0}, :defp)\n      defp bar(), do: :ok\n      assert Module.defines?(__MODULE__, {:bar, 0}, :defp)\n\n      refute Module.defines?(__MODULE__, {:baz, 0}, :defmacro)\n      defmacro baz(), do: :ok\n      assert Module.defines?(__MODULE__, {:baz, 0}, :defmacro)\n    end\n  end\n\n  test \"definitions in\" do\n    in_module do\n      defp bar(), do: :ok\n      def foo(1, 2, 3), do: bar()\n\n      defmacrop macro_bar(), do: 4\n      defmacro macro_foo(1, 2, 3), do: macro_bar()\n\n      assert Module.definitions_in(__MODULE__) |> Enum.sort() ==\n               [{:bar, 0}, {:foo, 3}, {:macro_bar, 0}, {:macro_foo, 3}]\n\n      assert Module.definitions_in(__MODULE__, :def) == [foo: 3]\n      assert Module.definitions_in(__MODULE__, :defp) == [bar: 0]\n      assert Module.definitions_in(__MODULE__, :defmacro) == [macro_foo: 3]\n      assert Module.definitions_in(__MODULE__, :defmacrop) == [macro_bar: 0]\n\n      defoverridable foo: 3\n\n      assert Module.definitions_in(__MODULE__) |> Enum.sort() ==\n               [{:bar, 0}, {:macro_bar, 0}, {:macro_foo, 3}]\n\n      assert Module.definitions_in(__MODULE__, :def) == []\n    end\n  end\n\n  test \"get_definition/2 and delete_definition/2\" do\n    in_module do\n      def foo(a, b), do: a + b\n\n      assert {:v1, :def, def_meta,\n              [\n                {clause_meta, [{:a, _, nil}, {:b, _, nil}], [],\n                 {{:., _, [:erlang, :+]}, _, [{:a, _, nil}, {:b, _, nil}]}}\n              ]} = Module.get_definition(__MODULE__, {:foo, 2})\n\n      assert [line: _, column: _] = Keyword.take(def_meta, [:line, :column])\n      assert [line: _, column: _] = Keyword.take(clause_meta, [:line, :column])\n      assert {:v1, :def, _, []} = Module.get_definition(__MODULE__, {:foo, 2}, skip_clauses: true)\n\n      assert Module.delete_definition(__MODULE__, {:foo, 2})\n      assert Module.get_definition(__MODULE__, {:foo, 2}) == nil\n      refute Module.delete_definition(__MODULE__, {:foo, 2})\n    end\n  end\n\n  test \"make_overridable/2 with invalid arguments\" do\n    contents =\n      quote do\n        Module.make_overridable(__MODULE__, [{:foo, 256}])\n      end\n\n    message =\n      \"each element in tuple list has to be a {function_name :: atom, arity :: 0..255} \" <>\n        \"tuple, got: {:foo, 256}\"\n\n    assert_raise ArgumentError, message, fn ->\n      Module.create(MakeOverridable, contents, __ENV__)\n    end\n  after\n    purge(MakeOverridable)\n  end\n\n  test \"raise when called with already compiled module\" do\n    message =\n      \"could not call Module.get_attribute/2 because the module Enum is already compiled. \" <>\n        \"Use the Module.__info__/1 callback or Code.fetch_docs/1 instead\"\n\n    assert_raise ArgumentError, message, fn ->\n      Module.get_attribute(Enum, :moduledoc)\n    end\n  end\n\n  describe \"get_attribute/3\" do\n    test \"returns a list when the attribute is marked as `accumulate: true`\" do\n      in_module do\n        Module.register_attribute(__MODULE__, :value, accumulate: true)\n        assert Module.get_attribute(__MODULE__, :value) == []\n        Module.put_attribute(__MODULE__, :value, 1)\n        assert Module.get_attribute(__MODULE__, :value) == [1]\n        Module.put_attribute(__MODULE__, :value, 2)\n        assert Module.get_attribute(__MODULE__, :value) == [2, 1]\n      end\n    end\n\n    test \"returns the value of the attribute if it exists\" do\n      in_module do\n        Module.put_attribute(__MODULE__, :attribute, 1)\n        assert Module.get_attribute(__MODULE__, :attribute) == 1\n        assert Module.get_attribute(__MODULE__, :attribute, :default) == 1\n        Module.put_attribute(__MODULE__, :attribute, nil)\n        assert Module.get_attribute(__MODULE__, :attribute, :default) == nil\n      end\n    end\n\n    test \"returns the value of the attribute if persisted\" do\n      in_module do\n        Module.register_attribute(__MODULE__, :value, persist: true)\n        assert Module.get_attribute(__MODULE__, :value, 123) == 123\n        Module.put_attribute(__MODULE__, :value, 1)\n        assert Module.get_attribute(__MODULE__, :value) == 1\n        Module.put_attribute(__MODULE__, :value, 2)\n        assert Module.get_attribute(__MODULE__, :value) == 2\n        Module.delete_attribute(__MODULE__, :value)\n        assert Module.get_attribute(__MODULE__, :value, 123) == 123\n      end\n    end\n\n    test \"returns the passed default if the attribute does not exist\" do\n      in_module do\n        assert Module.get_attribute(__MODULE__, :attribute, :default) == :default\n      end\n    end\n  end\n\n  describe \"get_last_attribute/3\" do\n    test \"returns the last set value when the attribute is marked as `accumulate: true`\" do\n      in_module do\n        Module.register_attribute(__MODULE__, :value, accumulate: true)\n        Module.put_attribute(__MODULE__, :value, 1)\n        assert Module.get_last_attribute(__MODULE__, :value) == 1\n        Module.put_attribute(__MODULE__, :value, 2)\n        assert Module.get_last_attribute(__MODULE__, :value) == 2\n      end\n    end\n\n    test \"returns the value of the non-accumulate attribute if it exists\" do\n      in_module do\n        Module.put_attribute(__MODULE__, :attribute, 1)\n        assert Module.get_last_attribute(__MODULE__, :attribute) == 1\n        Module.put_attribute(__MODULE__, :attribute, nil)\n        assert Module.get_last_attribute(__MODULE__, :attribute, :default) == nil\n      end\n    end\n\n    test \"returns the passed default if the accumulate attribute has not yet been set\" do\n      in_module do\n        Module.register_attribute(__MODULE__, :value, accumulate: true)\n        assert Module.get_last_attribute(__MODULE__, :value) == nil\n        assert Module.get_last_attribute(__MODULE__, :value, :default) == :default\n      end\n    end\n\n    test \"returns the passed default if the non-accumulate attribute does not exist\" do\n      in_module do\n        assert Module.get_last_attribute(__MODULE__, :value, :default) == :default\n      end\n    end\n  end\n\n  describe \"has_attribute?/2 and attributes_in/2\" do\n    test \"returns true when attribute has been defined\" do\n      in_module do\n        @foo 1\n        Module.register_attribute(__MODULE__, :bar, [])\n        Module.register_attribute(__MODULE__, :baz, accumulate: true)\n        Module.put_attribute(__MODULE__, :qux, 2)\n\n        # silence warning\n        _ = @foo\n\n        assert Module.has_attribute?(__MODULE__, :foo)\n        assert :foo in Module.attributes_in(__MODULE__)\n        assert Module.has_attribute?(__MODULE__, :bar)\n        assert :bar in Module.attributes_in(__MODULE__)\n        assert Module.has_attribute?(__MODULE__, :baz)\n        assert :baz in Module.attributes_in(__MODULE__)\n        assert Module.has_attribute?(__MODULE__, :qux)\n        assert :qux in Module.attributes_in(__MODULE__)\n      end\n    end\n\n    test \"returns false when attribute has not been defined\" do\n      in_module do\n        refute Module.has_attribute?(__MODULE__, :foo)\n      end\n    end\n\n    test \"returns false when attribute has been deleted\" do\n      in_module do\n        @foo 1\n        Module.delete_attribute(__MODULE__, :foo)\n\n        refute Module.has_attribute?(__MODULE__, :foo)\n      end\n    end\n  end\n\n  test \"@on_load\" do\n    Process.register(self(), :on_load_test_process)\n\n    defmodule OnLoadTest do\n      @on_load :on_load\n\n      defp on_load do\n        send(:on_load_test_process, :on_loaded)\n        :ok\n      end\n    end\n\n    assert_received :on_loaded\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/option_parser_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule OptionParserTest do\n  use ExUnit.Case, async: true\n\n  doctest OptionParser\n\n  test \"parses --key value option\" do\n    assert OptionParser.parse([\"--source\", \"form_docs/\", \"other\"], switches: [source: :string]) ==\n             {[source: \"form_docs/\"], [\"other\"], []}\n  end\n\n  test \"parses --key=value option\" do\n    assert OptionParser.parse([\"--source=form_docs/\", \"other\"], switches: [source: :string]) ==\n             {[source: \"form_docs/\"], [\"other\"], []}\n  end\n\n  test \"parses overrides options by default\" do\n    assert OptionParser.parse(\n             [\"--require\", \"foo\", \"--require\", \"bar\", \"baz\"],\n             switches: [require: :string]\n           ) == {[require: \"bar\"], [\"baz\"], []}\n  end\n\n  test \"parses multi-word option\" do\n    config = [switches: [hello_world: :boolean]]\n    assert OptionParser.next([\"--hello-world\"], config) == {:ok, :hello_world, true, []}\n    assert OptionParser.next([\"--no-hello-world\"], config) == {:ok, :hello_world, false, []}\n\n    assert OptionParser.next([\"--no-hello-world\"], strict: []) ==\n             {:undefined, \"--no-hello-world\", nil, []}\n\n    assert OptionParser.next([\"--no-hello_world\"], strict: []) ==\n             {:undefined, \"--no-hello_world\", nil, []}\n\n    config = [strict: [hello_world: :boolean]]\n    assert OptionParser.next([\"--hello-world\"], config) == {:ok, :hello_world, true, []}\n    assert OptionParser.next([\"--no-hello-world\"], config) == {:ok, :hello_world, false, []}\n    assert OptionParser.next([\"--hello_world\"], config) == {:undefined, \"--hello_world\", nil, []}\n\n    assert OptionParser.next([\"--no-hello_world\"], config) ==\n             {:undefined, \"--no-hello_world\", nil, []}\n  end\n\n  test \"parses more than one key-value pair options using switches\" do\n    opts = [switches: [source: :string, docs: :string]]\n\n    assert OptionParser.parse([\"--source\", \"from_docs/\", \"--docs\", \"show\"], opts) ==\n             {[source: \"from_docs/\", docs: \"show\"], [], []}\n\n    assert OptionParser.parse([\"--source\", \"from_docs/\", \"--doc\", \"show\"], opts) ==\n             {[source: \"from_docs/\", doc: \"show\"], [], []}\n\n    assert OptionParser.parse([\"--source\", \"from_docs/\", \"--doc=show\"], opts) ==\n             {[source: \"from_docs/\", doc: \"show\"], [], []}\n\n    assert OptionParser.parse([\"--no-bool\"], strict: []) == {[], [], [{\"--no-bool\", nil}]}\n  end\n\n  test \"parses more than one key-value pair options using strict\" do\n    opts = [strict: [source: :string, docs: :string]]\n\n    assert OptionParser.parse([\"--source\", \"from_docs/\", \"--docs\", \"show\"], opts) ==\n             {[source: \"from_docs/\", docs: \"show\"], [], []}\n\n    assert OptionParser.parse([\"--source\", \"from_docs/\", \"--doc\", \"show\"], opts) ==\n             {[source: \"from_docs/\"], [\"show\"], [{\"--doc\", nil}]}\n\n    assert OptionParser.parse([\"--source\", \"from_docs/\", \"--doc=show\"], opts) ==\n             {[source: \"from_docs/\"], [], [{\"--doc\", nil}]}\n\n    assert OptionParser.parse([\"--no-bool\"], strict: []) == {[], [], [{\"--no-bool\", nil}]}\n  end\n\n  test \"collects multiple invalid options\" do\n    argv = [\"--bad\", \"opt\", \"foo\", \"-o\", \"bad\", \"bar\"]\n\n    assert OptionParser.parse(argv, switches: [bad: :integer]) ==\n             {[], [\"foo\", \"bar\"], [{\"--bad\", \"opt\"}]}\n  end\n\n  test \"parse/2 raises when using both options: switches and strict\" do\n    assert_raise ArgumentError, \":switches and :strict cannot be given together\", fn ->\n      OptionParser.parse([\"--elixir\"], switches: [ex: :string], strict: [elixir: :string])\n    end\n  end\n\n  test \"parse/2 raises an exception on invalid switch types/modifiers\" do\n    assert_raise ArgumentError, \"invalid switch types/modifiers: :bad\", fn ->\n      OptionParser.parse([\"--elixir\"], switches: [ex: :bad])\n    end\n\n    assert_raise ArgumentError, \"invalid switch types/modifiers: :bad, :bad_modifier\", fn ->\n      OptionParser.parse([\"--elixir\"], switches: [ex: [:bad, :bad_modifier]])\n    end\n  end\n\n  test \"parse!/2 raises an exception for an unknown option using strict\" do\n    msg =\n      \"\"\"\n      1 error found!\n      --doc-bar : Unknown option. Did you mean --docs-bar?\n\n      Supported options:\n        --docs-bar STRING\n        --source STRING\\\n      \"\"\"\n\n    assert_raise OptionParser.ParseError, msg, fn ->\n      argv = [\"--source\", \"from_docs/\", \"--doc-bar\", \"show\"]\n      OptionParser.parse!(argv, strict: [source: :string, docs_bar: :string])\n    end\n\n    assert_raise OptionParser.ParseError,\n                 \"\"\"\n                 1 error found!\n                 --foo : Unknown option\n\n                 Supported options:\n                   --docs STRING\n                   --source STRING\\\n                 \"\"\",\n                 fn ->\n                   argv = [\"--source\", \"from_docs/\", \"--foo\", \"show\"]\n                   OptionParser.parse!(argv, strict: [source: :string, docs: :string])\n                 end\n  end\n\n  test \"parse!/2 raises an exception for an unknown option using strict when it is only off by underscores\" do\n    msg =\n      \"\"\"\n      1 error found!\n      --docs_bar : Unknown option. Did you mean --docs-bar?\n\n      Supported options:\n        --docs-bar STRING\n        --source STRING\\\n      \"\"\"\n\n    assert_raise OptionParser.ParseError, msg, fn ->\n      argv = [\"--source\", \"from_docs/\", \"--docs_bar\", \"show\"]\n      OptionParser.parse!(argv, strict: [source: :string, docs_bar: :string])\n    end\n  end\n\n  test \"parse!/2 raises an exception when an option is of the wrong type\" do\n    assert_raise OptionParser.ParseError,\n                 \"\"\"\n                 1 error found!\n                 --bad : Expected type integer, got \"opt\"\n\n                 Supported options:\n                   --bad INTEGER\\\n                 \"\"\",\n                 fn ->\n                   argv = [\"--bad\", \"opt\", \"foo\", \"-o\", \"bad\", \"bar\"]\n                   OptionParser.parse!(argv, switches: [bad: :integer])\n                 end\n  end\n\n  test \"parse!/2 lists all supported options and aliases\" do\n    expected_suggestion =\n      \"\"\"\n      1 error found!\n      --verbos : Unknown option. Did you mean --verbose?\n\n      Supported options:\n        --count INTEGER (alias: -c)\n        --debug, --no-debug (alias: -d)\n        --files STRING (alias: -f) (may be given more than once)\n        --name STRING (alias: -n)\n        --verbose, --no-verbose (alias: -v)\\\n      \"\"\"\n\n    assert_raise OptionParser.ParseError, expected_suggestion, fn ->\n      OptionParser.parse!([\"--verbos\"],\n        strict: [\n          name: :string,\n          count: :integer,\n          verbose: :boolean,\n          debug: :boolean,\n          files: :keep\n        ],\n        aliases: [n: :name, c: :count, v: :verbose, d: :debug, f: :files]\n      )\n    end\n  end\n\n  test \"parse_head!/2 raises an exception when an option is of the wrong type\" do\n    message =\n      \"\"\"\n      1 error found!\n      --number : Expected type integer, got \"lib\"\n\n      Supported options:\n        --number INTEGER\\\n      \"\"\"\n\n    assert_raise OptionParser.ParseError, message, fn ->\n      argv = [\"--number\", \"lib\", \"test/enum_test.exs\"]\n      OptionParser.parse_head!(argv, strict: [number: :integer])\n    end\n  end\n\n  describe \"arguments\" do\n    test \"parses until --\" do\n      assert OptionParser.parse(\n               [\"--source\", \"foo\", \"--\", \"1\", \"2\", \"3\"],\n               switches: [source: :string]\n             ) == {[source: \"foo\"], [\"1\", \"2\", \"3\"], []}\n\n      assert OptionParser.parse_head(\n               [\"--source\", \"foo\", \"--\", \"1\", \"2\", \"3\"],\n               switches: [source: :string]\n             ) == {[source: \"foo\"], [\"1\", \"2\", \"3\"], []}\n\n      assert OptionParser.parse(\n               [\"--source\", \"foo\", \"bar\", \"--\", \"-x\"],\n               switches: [source: :string]\n             ) == {[source: \"foo\"], [\"bar\", \"-x\"], []}\n\n      assert OptionParser.parse_head(\n               [\"--source\", \"foo\", \"bar\", \"--\", \"-x\"],\n               switches: [source: :string]\n             ) == {[source: \"foo\"], [\"bar\", \"--\", \"-x\"], []}\n    end\n\n    test \"return separators\" do\n      assert OptionParser.parse_head([\"--\", \"foo\"],\n               switches: [],\n               return_separator: true\n             ) == {[], [\"--\", \"foo\"], []}\n\n      assert OptionParser.parse_head([\"--no-halt\", \"--\", \"foo\"],\n               switches: [halt: :boolean],\n               return_separator: true\n             ) == {[halt: false], [\"--\", \"foo\"], []}\n\n      assert OptionParser.parse_head([\"foo.exs\", \"--no-halt\", \"--\", \"foo\"],\n               switches: [halt: :boolean],\n               return_separator: true\n             ) == {[], [\"foo.exs\", \"--no-halt\", \"--\", \"foo\"], []}\n    end\n\n    test \"parses - as argument\" do\n      argv = [\"--foo\", \"-\", \"-b\", \"-\"]\n      opts = [strict: [foo: :boolean, boo: :string], aliases: [b: :boo]]\n      assert OptionParser.parse(argv, opts) == {[foo: true, boo: \"-\"], [\"-\"], []}\n    end\n\n    test \"parses until first non-option arguments\" do\n      argv = [\"--source\", \"from_docs/\", \"test/enum_test.exs\", \"--verbose\"]\n\n      assert OptionParser.parse_head(argv, switches: [source: :string]) ==\n               {[source: \"from_docs/\"], [\"test/enum_test.exs\", \"--verbose\"], []}\n    end\n  end\n\n  describe \"aliases\" do\n    test \"supports boolean aliases\" do\n      assert OptionParser.parse([\"-d\"], aliases: [d: :docs], switches: [docs: :boolean]) ==\n               {[docs: true], [], []}\n    end\n\n    test \"supports non-boolean aliases\" do\n      assert OptionParser.parse(\n               [\"-s\", \"from_docs/\"],\n               aliases: [s: :source],\n               switches: [source: :string]\n             ) == {[source: \"from_docs/\"], [], []}\n    end\n\n    test \"supports --key=value aliases\" do\n      assert OptionParser.parse(\n               [\"-s=from_docs/\", \"other\"],\n               aliases: [s: :source],\n               switches: [source: :string]\n             ) == {[source: \"from_docs/\"], [\"other\"], []}\n    end\n\n    test \"parses -ab as -a -b\" do\n      opts = [aliases: [a: :first, b: :second], switches: [second: :integer]]\n      assert OptionParser.parse([\"-ab=1\"], opts) == {[first: true, second: 1], [], []}\n      assert OptionParser.parse([\"-ab\", \"1\"], opts) == {[first: true, second: 1], [], []}\n\n      opts = [aliases: [a: :first, b: :second], switches: [first: :boolean, second: :boolean]]\n      assert OptionParser.parse([\"-ab\"], opts) == {[first: true, second: true], [], []}\n      assert OptionParser.parse([\"-ab3\"], opts) == {[first: true], [], [{\"-b\", \"3\"}]}\n      assert OptionParser.parse([\"-ab=bar\"], opts) == {[first: true], [], [{\"-b\", \"bar\"}]}\n      assert OptionParser.parse([\"-ab3=bar\"], opts) == {[first: true], [], [{\"-b\", \"3=bar\"}]}\n      assert OptionParser.parse([\"-3ab\"], opts) == {[], [\"-3ab\"], []}\n    end\n  end\n\n  describe \"types\" do\n    test \"parses configured booleans\" do\n      assert OptionParser.parse([\"--docs=false\"], switches: [docs: :boolean]) ==\n               {[docs: false], [], []}\n\n      assert OptionParser.parse([\"--docs=true\"], switches: [docs: :boolean]) ==\n               {[docs: true], [], []}\n\n      assert OptionParser.parse([\"--docs=other\"], switches: [docs: :boolean]) ==\n               {[], [], [{\"--docs\", \"other\"}]}\n\n      assert OptionParser.parse([\"--docs=\"], switches: [docs: :boolean]) ==\n               {[], [], [{\"--docs\", \"\"}]}\n\n      assert OptionParser.parse([\"--docs\", \"foo\"], switches: [docs: :boolean]) ==\n               {[docs: true], [\"foo\"], []}\n\n      assert OptionParser.parse([\"--no-docs\", \"foo\"], switches: [docs: :boolean]) ==\n               {[docs: false], [\"foo\"], []}\n\n      assert OptionParser.parse([\"--no-docs=foo\", \"bar\"], switches: [docs: :boolean]) ==\n               {[], [\"bar\"], [{\"--no-docs\", \"foo\"}]}\n\n      assert OptionParser.parse([\"--no-docs=\", \"bar\"], switches: [docs: :boolean]) ==\n               {[], [\"bar\"], [{\"--no-docs\", \"\"}]}\n    end\n\n    test \"does not set unparsed booleans\" do\n      assert OptionParser.parse([\"foo\"], switches: [docs: :boolean]) == {[], [\"foo\"], []}\n    end\n\n    test \"keeps options on configured keep\" do\n      argv = [\"--require\", \"foo\", \"--require\", \"bar\", \"baz\"]\n\n      assert OptionParser.parse(argv, switches: [require: :keep]) ==\n               {[require: \"foo\", require: \"bar\"], [\"baz\"], []}\n\n      assert OptionParser.parse([\"--require\"], switches: [require: :keep]) ==\n               {[], [], [{\"--require\", nil}]}\n    end\n\n    test \"parses configured strings\" do\n      assert OptionParser.parse([\"--value\", \"1\", \"foo\"], switches: [value: :string]) ==\n               {[value: \"1\"], [\"foo\"], []}\n\n      assert OptionParser.parse([\"--value=1\", \"foo\"], switches: [value: :string]) ==\n               {[value: \"1\"], [\"foo\"], []}\n\n      assert OptionParser.parse([\"--value\"], switches: [value: :string]) ==\n               {[], [], [{\"--value\", nil}]}\n\n      assert OptionParser.parse([\"--no-value\"], switches: [value: :string]) ==\n               {[no_value: true], [], []}\n    end\n\n    test \"parses configured counters\" do\n      assert OptionParser.parse([\"--verbose\"], switches: [verbose: :count]) ==\n               {[verbose: 1], [], []}\n\n      assert OptionParser.parse([\"--verbose\", \"--verbose\"], switches: [verbose: :count]) ==\n               {[verbose: 2], [], []}\n\n      argv = [\"--verbose\", \"-v\", \"-v\", \"--\", \"bar\"]\n      opts = [aliases: [v: :verbose], strict: [verbose: :count]]\n      assert OptionParser.parse(argv, opts) == {[verbose: 3], [\"bar\"], []}\n    end\n\n    test \"parses configured integers\" do\n      assert OptionParser.parse([\"--value\", \"1\", \"foo\"], switches: [value: :integer]) ==\n               {[value: 1], [\"foo\"], []}\n\n      assert OptionParser.parse([\"--value=1\", \"foo\"], switches: [value: :integer]) ==\n               {[value: 1], [\"foo\"], []}\n\n      assert OptionParser.parse([\"--value\", \"WAT\", \"foo\"], switches: [value: :integer]) ==\n               {[], [\"foo\"], [{\"--value\", \"WAT\"}]}\n    end\n\n    test \"parses configured integers with keep\" do\n      argv = [\"--value\", \"1\", \"--value\", \"2\", \"foo\"]\n\n      assert OptionParser.parse(argv, switches: [value: [:integer, :keep]]) ==\n               {[value: 1, value: 2], [\"foo\"], []}\n\n      argv = [\"--value=1\", \"foo\", \"--value=2\", \"bar\"]\n\n      assert OptionParser.parse(argv, switches: [value: [:integer, :keep]]) ==\n               {[value: 1, value: 2], [\"foo\", \"bar\"], []}\n    end\n\n    test \"parses configured floats\" do\n      assert OptionParser.parse([\"--value\", \"1.0\", \"foo\"], switches: [value: :float]) ==\n               {[value: 1.0], [\"foo\"], []}\n\n      assert OptionParser.parse([\"--value=1.0\", \"foo\"], switches: [value: :float]) ==\n               {[value: 1.0], [\"foo\"], []}\n\n      assert OptionParser.parse([\"--value\", \"WAT\", \"foo\"], switches: [value: :float]) ==\n               {[], [\"foo\"], [{\"--value\", \"WAT\"}]}\n    end\n\n    test \"correctly handles negative integers\" do\n      opts = [switches: [option: :integer], aliases: [o: :option]]\n      assert OptionParser.parse([\"arg1\", \"-o43\"], opts) == {[option: 43], [\"arg1\"], []}\n      assert OptionParser.parse([\"arg1\", \"-o\", \"-43\"], opts) == {[option: -43], [\"arg1\"], []}\n      assert OptionParser.parse([\"arg1\", \"--option=-43\"], opts) == {[option: -43], [\"arg1\"], []}\n\n      assert OptionParser.parse([\"arg1\", \"--option\", \"-43\"], opts) ==\n               {[option: -43], [\"arg1\"], []}\n    end\n\n    test \"correctly handles negative floating-point numbers\" do\n      opts = [switches: [option: :float], aliases: [o: :option]]\n      assert OptionParser.parse([\"arg1\", \"-o43.2\"], opts) == {[option: 43.2], [\"arg1\"], []}\n      assert OptionParser.parse([\"arg1\", \"-o\", \"-43.2\"], opts) == {[option: -43.2], [\"arg1\"], []}\n\n      assert OptionParser.parse([\"arg1\", \"--option=-43.2\"], switches: [option: :float]) ==\n               {[option: -43.2], [\"arg1\"], []}\n\n      assert OptionParser.parse([\"arg1\", \"--option\", \"-43.2\"], opts) ==\n               {[option: -43.2], [\"arg1\"], []}\n    end\n\n    test \"parses configured regexes\" do\n      assert {[pattern: regex], [\"foo\"], []} =\n               OptionParser.parse([\"--pattern\", \"a.*b\", \"foo\"], switches: [pattern: :regex])\n\n      assert Regex.match?(regex, \"aXXXb\")\n      refute Regex.match?(regex, \"xyz\")\n\n      assert {[pattern: regex], [\"foo\"], []} =\n               OptionParser.parse([\"--pattern=a.*b\", \"foo\"], switches: [pattern: :regex])\n\n      assert Regex.match?(regex, \"aXXXb\")\n\n      # Test Unicode support\n      assert {[pattern: regex], [\"foo\"], []} =\n               OptionParser.parse([\"--pattern\", \"café.*résumé\", \"foo\"],\n                 switches: [pattern: :regex]\n               )\n\n      assert Regex.match?(regex, \"café test résumé\")\n      refute Regex.match?(regex, \"ascii only\")\n\n      # Test invalid regex\n      assert OptionParser.parse([\"--pattern\", \"[invalid\", \"foo\"], switches: [pattern: :regex]) ==\n               {[], [\"foo\"], [{\"--pattern\", \"[invalid\"}]}\n    end\n\n    test \"parses configured regexes with keep\" do\n      argv = [\"--pattern\", \"a.*\", \"--pattern\", \"b.*\", \"foo\"]\n\n      assert {[pattern: regex1, pattern: regex2], [\"foo\"], []} =\n               OptionParser.parse(argv, switches: [pattern: [:regex, :keep]])\n\n      assert Regex.match?(regex1, \"aXXX\")\n      assert Regex.match?(regex2, \"bXXX\")\n      refute Regex.match?(regex1, \"bXXX\")\n      refute Regex.match?(regex2, \"aXXX\")\n\n      argv = [\"--pattern=a.*\", \"foo\", \"--pattern=b.*\", \"bar\"]\n\n      assert {[pattern: regex1, pattern: regex2], [\"foo\", \"bar\"], []} =\n               OptionParser.parse(argv, switches: [pattern: [:regex, :keep]])\n\n      assert Regex.match?(regex1, \"aXXX\")\n      assert Regex.match?(regex2, \"bXXX\")\n    end\n\n    test \"correctly handles regex compilation errors\" do\n      opts = [switches: [pattern: :regex]]\n\n      # Invalid regex patterns should be treated as errors\n      assert OptionParser.parse([\"--pattern\", \"*invalid\"], opts) ==\n               {[], [], [{\"--pattern\", \"*invalid\"}]}\n\n      assert OptionParser.parse([\"--pattern\", \"[unclosed\"], opts) ==\n               {[], [], [{\"--pattern\", \"[unclosed\"}]}\n\n      assert OptionParser.parse([\"--pattern\", \"(?invalid)\"], opts) ==\n               {[], [], [{\"--pattern\", \"(?invalid)\"}]}\n    end\n\n    test \"parse! raises an exception for invalid regex patterns\" do\n      assert_raise OptionParser.ParseError,\n                   ~r/Invalid regular expression \\\"\\[invalid\\\": missing terminating \\] for character class at position \\d/,\n                   fn ->\n                     OptionParser.parse!([\"--pattern\", \"[invalid\"], switches: [pattern: :regex])\n                   end\n\n      assert_raise OptionParser.ParseError,\n                   ~r/Invalid regular expression \\\"\\(\\?invalid\\)\\\": unrecognized character after \\(\\? or \\(\\?\\- at position \\d/,\n                   fn ->\n                     OptionParser.parse!([\"--pattern\", \"(?invalid)\"], switches: [pattern: :regex])\n                   end\n    end\n  end\n\n  describe \"next\" do\n    test \"with strict good options\" do\n      config = [strict: [str: :string, int: :integer, bool: :boolean]]\n      assert OptionParser.next([\"--str\", \"hello\", \"...\"], config) == {:ok, :str, \"hello\", [\"...\"]}\n      assert OptionParser.next([\"--int=13\", \"...\"], config) == {:ok, :int, 13, [\"...\"]}\n      assert OptionParser.next([\"--bool=false\", \"...\"], config) == {:ok, :bool, false, [\"...\"]}\n      assert OptionParser.next([\"--no-bool\", \"...\"], config) == {:ok, :bool, false, [\"...\"]}\n      assert OptionParser.next([\"--bool\", \"...\"], config) == {:ok, :bool, true, [\"...\"]}\n      assert OptionParser.next([\"...\"], config) == {:error, [\"...\"]}\n    end\n\n    test \"with strict unknown options\" do\n      config = [strict: [bool: :boolean]]\n\n      assert OptionParser.next([\"--str\", \"13\", \"...\"], config) ==\n               {:undefined, \"--str\", nil, [\"13\", \"...\"]}\n\n      assert OptionParser.next([\"--int=hello\", \"...\"], config) ==\n               {:undefined, \"--int\", \"hello\", [\"...\"]}\n\n      assert OptionParser.next([\"-no-bool=other\", \"...\"], config) ==\n               {:undefined, \"-no-bool\", \"other\", [\"...\"]}\n    end\n\n    test \"with strict bad type\" do\n      config = [strict: [str: :string, int: :integer, bool: :boolean]]\n      assert OptionParser.next([\"--str\", \"13\", \"...\"], config) == {:ok, :str, \"13\", [\"...\"]}\n\n      assert OptionParser.next([\"--int=hello\", \"...\"], config) ==\n               {:invalid, \"--int\", \"hello\", [\"...\"]}\n\n      assert OptionParser.next([\"--int\", \"hello\", \"...\"], config) ==\n               {:invalid, \"--int\", \"hello\", [\"...\"]}\n\n      assert OptionParser.next([\"--bool=other\", \"...\"], config) ==\n               {:invalid, \"--bool\", \"other\", [\"...\"]}\n    end\n\n    test \"with strict missing value\" do\n      config = [strict: [str: :string, int: :integer, bool: :boolean]]\n      assert OptionParser.next([\"--str\"], config) == {:invalid, \"--str\", nil, []}\n      assert OptionParser.next([\"--int\"], config) == {:invalid, \"--int\", nil, []}\n      assert OptionParser.next([\"--bool=\", \"...\"], config) == {:invalid, \"--bool\", \"\", [\"...\"]}\n\n      assert OptionParser.next([\"--no-bool=\", \"...\"], config) ==\n               {:invalid, \"--no-bool\", \"\", [\"...\"]}\n    end\n  end\n\n  test \"split\" do\n    assert OptionParser.split(~S[]) == []\n    assert OptionParser.split(~S[foo]) == [\"foo\"]\n    assert OptionParser.split(~S[foo bar]) == [\"foo\", \"bar\"]\n    assert OptionParser.split(~S[  foo  bar  ]) == [\"foo\", \"bar\"]\n    assert OptionParser.split(~S[foo\\ bar]) == [\"foo bar\"]\n    assert OptionParser.split(~S[foo\" bar\"]) == [\"foo bar\"]\n    assert OptionParser.split(~S[foo\\\" bar\\\"]) == [\"foo\\\"\", \"bar\\\"\"]\n    assert OptionParser.split(~S[foo \"\\ bar\\\"\"]) == [\"foo\", \"\\\\ bar\\\"\"]\n    assert OptionParser.split(~S[foo '\\\"bar\"\\'\\ ']) == [\"foo\", \"\\\\\\\"bar\\\"'\\\\ \"]\n  end\n\n  describe \"to_argv\" do\n    test \"converts options back to switches\" do\n      assert OptionParser.to_argv(foo_bar: \"baz\") == [\"--foo-bar\", \"baz\"]\n\n      assert OptionParser.to_argv(bool: true, bool: false, discarded: nil) ==\n               [\"--bool\", \"--no-bool\"]\n    end\n\n    test \"handles :count switch type\" do\n      original = [\"--counter\", \"--counter\"]\n      {opts, [], []} = OptionParser.parse(original, switches: [counter: :count])\n      assert original == OptionParser.to_argv(opts, switches: [counter: :count])\n    end\n  end\nend\n\ndefmodule OptionsParserDeprecationsTest do\n  use ExUnit.Case, async: true\n\n  def assert_deprecated(fun) do\n    assert ExUnit.CaptureIO.capture_io(:stderr, fun) =~\n             \"not passing the :switches or :strict option to OptionParser is deprecated\"\n  end\n\n  test \"parses boolean option\" do\n    assert_deprecated(fn ->\n      assert OptionParser.parse([\"--docs\"]) == {[docs: true], [], []}\n    end)\n  end\n\n  test \"parses more than one boolean option\" do\n    assert_deprecated(fn ->\n      assert OptionParser.parse([\"--docs\", \"--compile\"]) == {[docs: true, compile: true], [], []}\n    end)\n  end\n\n  test \"parses more than one boolean options as the alias\" do\n    assert_deprecated(fn ->\n      assert OptionParser.parse([\"-d\", \"--compile\"], aliases: [d: :docs]) ==\n               {[docs: true, compile: true], [], []}\n    end)\n  end\n\n  test \"parses --key value option\" do\n    assert_deprecated(fn ->\n      assert OptionParser.parse([\"--source\", \"form_docs/\"]) == {[source: \"form_docs/\"], [], []}\n    end)\n  end\n\n  test \"does not interpret undefined options with value as boolean\" do\n    assert_deprecated(fn ->\n      assert OptionParser.parse([\"--no-bool\"]) == {[no_bool: true], [], []}\n    end)\n\n    assert_deprecated(fn ->\n      assert OptionParser.parse([\"--no-bool=...\", \"other\"]) == {[no_bool: \"...\"], [\"other\"], []}\n    end)\n  end\n\n  test \"parses -ab as -a -b\" do\n    assert_deprecated(fn ->\n      assert OptionParser.parse([\"-ab\"], aliases: [a: :first, b: :second]) ==\n               {[first: true, second: true], [], []}\n    end)\n  end\n\n  test \"parses mixed options\" do\n    argv = [\"--source\", \"from_docs/\", \"--compile\", \"-x\"]\n\n    assert_deprecated(fn ->\n      assert OptionParser.parse(argv, aliases: [x: :x]) ==\n               {[source: \"from_docs/\", compile: true, x: true], [], []}\n    end)\n  end\n\n  test \"parses more than one key-value pair options\" do\n    assert_deprecated(fn ->\n      assert OptionParser.parse([\"--source\", \"from_docs/\", \"--docs\", \"show\"]) ==\n               {[source: \"from_docs/\", docs: \"show\"], [], []}\n    end)\n  end\n\n  test \"multi-word option\" do\n    assert_deprecated(fn ->\n      assert OptionParser.next([\"--hello-world\"], []) == {:ok, :hello_world, true, []}\n    end)\n\n    assert_deprecated(fn ->\n      assert OptionParser.next([\"--no-hello-world\"], []) == {:ok, :no_hello_world, true, []}\n    end)\n\n    assert_deprecated(fn ->\n      assert OptionParser.next([\"--hello_world\"], []) == {:undefined, \"--hello_world\", nil, []}\n    end)\n\n    assert_deprecated(fn ->\n      assert OptionParser.next([\"--no-hello_world\"], []) ==\n               {:undefined, \"--no-hello_world\", nil, []}\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/partition_supervisor_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule PartitionSupervisorTest do\n  use ExUnit.Case, async: true\n\n  describe \"child_spec\" do\n    test \"uses the atom name as id\" do\n      assert Supervisor.child_spec({PartitionSupervisor, name: Foo}, []) == %{\n               id: Foo,\n               start: {PartitionSupervisor, :start_link, [[name: Foo]]},\n               type: :supervisor\n             }\n    end\n\n    test \"uses the via value as id\" do\n      via = {:via, Foo, {:bar, :baz}}\n\n      assert Supervisor.child_spec({PartitionSupervisor, name: via}, []) == %{\n               id: {:bar, :baz},\n               start: {PartitionSupervisor, :start_link, [[name: via]]},\n               type: :supervisor\n             }\n    end\n  end\n\n  describe \"start_link/1\" do\n    test \"on success with atom name\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: DynamicSupervisor,\n          name: config.test\n        )\n\n      assert PartitionSupervisor.partitions(config.test) == System.schedulers_online()\n\n      refs =\n        for _ <- 1..100 do\n          ref = make_ref()\n\n          DynamicSupervisor.start_child(\n            {:via, PartitionSupervisor, {config.test, ref}},\n            {Agent, fn -> ref end}\n          )\n\n          ref\n        end\n\n      agents =\n        for {_, pid, _, _} <- PartitionSupervisor.which_children(config.test),\n            {_, pid, _, _} <- DynamicSupervisor.which_children(pid),\n            do: Agent.get(pid, & &1)\n\n      assert Enum.sort(refs) == Enum.sort(agents)\n    end\n\n    test \"on success with via name\", config do\n      {:ok, _} = Registry.start_link(keys: :unique, name: PartitionRegistry)\n\n      name = {:via, Registry, {PartitionRegistry, config.test}}\n\n      {:ok, _} = PartitionSupervisor.start_link(child_spec: {Agent, fn -> :hello end}, name: name)\n\n      assert PartitionSupervisor.partitions(name) == System.schedulers_online()\n\n      assert Agent.get({:via, PartitionSupervisor, {name, 0}}, & &1) == :hello\n    end\n\n    test \"with_arguments\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> raise \"unused\" end},\n          with_arguments: fn [_fun], partition -> [fn -> partition end] end,\n          partitions: 3,\n          name: config.test\n        )\n\n      assert PartitionSupervisor.partitions(config.test) == 3\n\n      assert Agent.get({:via, PartitionSupervisor, {config.test, 0}}, & &1) == 0\n      assert Agent.get({:via, PartitionSupervisor, {config.test, 1}}, & &1) == 1\n      assert Agent.get({:via, PartitionSupervisor, {config.test, 2}}, & &1) == 2\n\n      assert Agent.get({:via, PartitionSupervisor, {config.test, 3}}, & &1) == 0\n      assert Agent.get({:via, PartitionSupervisor, {config.test, -1}}, & &1) == 1\n    end\n\n    test \"raises without name\" do\n      assert_raise ArgumentError,\n                   \"the :name option must be given to PartitionSupervisor\",\n                   fn -> PartitionSupervisor.start_link(child_spec: DynamicSupervisor) end\n    end\n\n    test \"raises without child_spec\" do\n      assert_raise ArgumentError,\n                   \"the :child_spec option must be given to PartitionSupervisor\",\n                   fn -> PartitionSupervisor.start_link(name: Foo) end\n    end\n\n    test \"raises on bad partitions\" do\n      assert_raise ArgumentError,\n                   \"the :partitions option must be a positive integer, got: 0\",\n                   fn ->\n                     PartitionSupervisor.start_link(\n                       name: Foo,\n                       child_spec: DynamicSupervisor,\n                       partitions: 0\n                     )\n                   end\n    end\n\n    test \"raises on bad with_arguments\" do\n      assert_raise ArgumentError,\n                   ~r\"the :with_arguments option must be a function that receives two arguments\",\n                   fn ->\n                     PartitionSupervisor.start_link(\n                       name: Foo,\n                       child_spec: DynamicSupervisor,\n                       with_arguments: 123\n                     )\n                   end\n    end\n\n    test \"raises with bad auto_shutdown\" do\n      assert_raise ArgumentError,\n                   \"the :auto_shutdown option must be :never, got: :any_significant\",\n                   fn ->\n                     PartitionSupervisor.start_link(\n                       child_spec: DynamicSupervisor,\n                       name: Foo,\n                       auto_shutdown: :any_significant\n                     )\n                   end\n    end\n  end\n\n  describe \"stop/1\" do\n    test \"is synchronous\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> %{} end},\n          name: config.test\n        )\n\n      assert PartitionSupervisor.stop(config.test) == :ok\n      assert Process.whereis(config.test) == nil\n    end\n\n    test \"with via tuple\", config do\n      {:ok, _} = Registry.start_link(keys: :unique, name: config.test)\n\n      name = {:via, Registry, {config.test, :stop_test}}\n\n      {:ok, pid} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> %{} end},\n          name: name\n        )\n\n      assert Process.alive?(pid)\n      assert PartitionSupervisor.stop(name) == :ok\n      refute Process.alive?(pid)\n    end\n  end\n\n  describe \"partitions/1\" do\n    test \"raises noproc for unknown atom partition supervisor\" do\n      assert {:noproc, _} = catch_exit(PartitionSupervisor.partitions(:unknown))\n    end\n\n    test \"raises noproc for unknown via partition supervisor\", config do\n      {:ok, _} = Registry.start_link(keys: :unique, name: config.test)\n      via = {:via, Registry, {config.test, :unknown}}\n      assert {:noproc, _} = catch_exit(PartitionSupervisor.partitions(via))\n    end\n  end\n\n  describe \"resize!/1\" do\n    test \"resizes the number of children\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> %{} end},\n          name: config.test,\n          partitions: 8\n        )\n\n      for range <- [8..0//1, 0..8//1, Enum.shuffle(0..8)], i <- range do\n        PartitionSupervisor.resize!(config.test, i)\n        assert PartitionSupervisor.partitions(config.test) == i\n\n        assert PartitionSupervisor.count_children(config.test) ==\n                 %{active: i, specs: 8, supervisors: 0, workers: 8}\n\n        # Assert that we can still query across all range,\n        # but they are routed properly, as long as we have\n        # a single partition.\n        children =\n          for partition <- 0..7, i != 0, uniq: true do\n            GenServer.whereis({:via, PartitionSupervisor, {config.test, partition}})\n          end\n\n        assert length(children) == i\n      end\n    end\n\n    test \"raises on lookup after resizing to zero\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> %{} end},\n          name: config.test,\n          partitions: 8\n        )\n\n      assert PartitionSupervisor.resize!(config.test, 0) == 8\n\n      assert_raise ArgumentError, ~r\"has zero partitions\", fn ->\n        GenServer.whereis({:via, PartitionSupervisor, {config.test, 0}})\n      end\n\n      assert PartitionSupervisor.resize!(config.test, 8) == 0\n    end\n\n    test \"raises if trying to increase the number of partitions\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> %{} end},\n          name: config.test,\n          partitions: 8\n        )\n\n      assert_raise ArgumentError,\n                   \"the number of partitions to resize to must be a number between 0 and 8, got: 9\",\n                   fn -> PartitionSupervisor.resize!(config.test, 9) end\n    end\n  end\n\n  describe \"which_children/1\" do\n    test \"returns all partitions\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> %{} end},\n          name: config.test\n        )\n\n      assert PartitionSupervisor.partitions(config.test) == System.schedulers_online()\n\n      children =\n        config.test\n        |> PartitionSupervisor.which_children()\n        |> Enum.sort()\n\n      for {child, partition} <- Enum.zip(children, 0..(System.schedulers_online() - 1)) do\n        via = {:via, PartitionSupervisor, {config.test, partition}}\n        assert child == {partition, GenServer.whereis(via), :worker, [Agent]}\n      end\n    end\n  end\n\n  describe \"count_children/1\" do\n    test \"with workers\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> %{} end},\n          name: config.test\n        )\n\n      partitions = System.schedulers_online()\n\n      assert PartitionSupervisor.count_children(config.test) ==\n               %{active: partitions, specs: partitions, supervisors: 0, workers: partitions}\n    end\n\n    test \"with supervisors\", config do\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: DynamicSupervisor,\n          name: config.test\n        )\n\n      partitions = System.schedulers_online()\n\n      assert PartitionSupervisor.count_children(config.test) ==\n               %{active: partitions, specs: partitions, supervisors: partitions, workers: 0}\n    end\n\n    test \"raises noproc for unknown partition supervisor\" do\n      assert {:noproc, _} = catch_exit(PartitionSupervisor.count_children(:unknown))\n    end\n\n    test \"with via tuple\", config do\n      {:ok, _} = Registry.start_link(keys: :unique, name: config.test)\n\n      name = {:via, Registry, {config.test, :count_test}}\n\n      {:ok, _} =\n        PartitionSupervisor.start_link(\n          child_spec: {Agent, fn -> %{} end},\n          name: name\n        )\n\n      partitions = System.schedulers_online()\n\n      assert PartitionSupervisor.count_children(name) ==\n               %{active: partitions, specs: partitions, supervisors: 0, workers: partitions}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/path_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule PathTest do\n  use ExUnit.Case, async: true\n  doctest Path\n\n  if :file.native_name_encoding() == :utf8 do\n    @tag :tmp_dir\n    test \"wildcard with UTF-8\", config do\n      File.mkdir_p(Path.join(config.tmp_dir, \"héllò\"))\n\n      assert Path.wildcard(Path.join(config.tmp_dir, \"héllò\")) ==\n               [Path.join(config.tmp_dir, \"héllò\")]\n    after\n      File.rm_rf(Path.join(config.tmp_dir, \"héllò\"))\n    end\n  end\n\n  @tag :tmp_dir\n  test \"wildcard/2\", config do\n    hello = Path.join(config.tmp_dir, \"wildcard/.hello\")\n    world = Path.join(config.tmp_dir, \"wildcard/.hello/world\")\n    File.mkdir_p(world)\n\n    assert Path.wildcard(Path.join(config.tmp_dir, \"wildcard/*/*\")) == []\n    assert Path.wildcard(Path.join(config.tmp_dir, \"wildcard/**/*\")) == []\n    assert Path.wildcard(Path.join(config.tmp_dir, \"wildcard/?hello/world\")) == []\n\n    assert Path.wildcard(Path.join(config.tmp_dir, \"wildcard/*/*\"), match_dot: true) ==\n             [world]\n\n    assert Path.wildcard(Path.join(config.tmp_dir, \"wildcard/**/*\"), match_dot: true) ==\n             [hello, world]\n\n    assert Path.wildcard(Path.join(config.tmp_dir, \"wildcard/?hello/world\"), match_dot: true) ==\n             [world]\n  after\n    File.rm_rf(Path.join(config.tmp_dir, \"wildcard\"))\n  end\n\n  @tag :tmp_dir\n  test \"wildcard/2 follows ..\", config do\n    hello = Path.join(config.tmp_dir, \"wildcard/hello\")\n    world = Path.join(config.tmp_dir, \"wildcard/world\")\n    File.mkdir_p(hello)\n    File.touch(world)\n\n    assert Path.wildcard(Path.join(config.tmp_dir, \"wildcard/w*/../h*\")) == []\n\n    assert Path.wildcard(Path.join(config.tmp_dir, \"wildcard/h*/../w*\")) ==\n             [Path.join(config.tmp_dir, \"wildcard/hello/../world\")]\n  after\n    File.rm_rf(Path.join(config.tmp_dir, \"wildcard\"))\n  end\n\n  test \"wildcard/2 raises on null byte\" do\n    assert_raise ArgumentError, ~r/null byte/, fn -> Path.wildcard(\"foo\\0bar\") end\n  end\n\n  describe \"Windows\" do\n    @describetag :windows\n\n    test \"absname/1\" do\n      assert Path.absname(\"//host/path\") == \"//host/path\"\n      assert Path.absname(\"\\\\\\\\host\\\\path\") == \"//host/path\"\n      assert Path.absname(\"\\\\/host\\\\path\") == \"//host/path\"\n      assert Path.absname(\"/\\\\host\\\\path\") == \"//host/path\"\n\n      assert Path.absname(\"c:/\") == \"c:/\"\n      assert Path.absname(\"c:/host/path\") == \"c:/host/path\"\n\n      cwd = File.cwd!()\n      assert Path.absname(cwd |> String.split(\"/\") |> hd()) == cwd\n\n      <<letter, _::binary>> = cwd\n      random = Enum.random(Enum.to_list(?c..?z) -- [letter])\n      assert Path.absname(<<random, ?:>>) == <<random, ?:, ?/>>\n    end\n\n    test \"relative/1\" do\n      assert Path.relative(\"C:/usr/local/bin\") == \"usr/local/bin\"\n      assert Path.relative(\"C:\\\\usr\\\\local\\\\bin\") == \"usr\\\\local\\\\bin\"\n      assert Path.relative(\"C:usr\\\\local\\\\bin\") == \"usr\\\\local\\\\bin\"\n\n      assert Path.relative(\"/usr/local/bin\") == \"usr/local/bin\"\n      assert Path.relative(\"usr/local/bin\") == \"usr/local/bin\"\n      assert Path.relative(\"../usr/local/bin\") == \"../usr/local/bin\"\n    end\n\n    test \"relative_to/3\" do\n      # should give same relative paths for both force true and false\n      for force <- [true, false] do\n        assert Path.relative_to(\"//usr/local/foo\", \"//usr/\", force: force) == \"local/foo\"\n\n        assert Path.relative_to(\"D:/usr/local/foo\", \"D:/usr/\", force: force) == \"local/foo\"\n        assert Path.relative_to(\"D:/usr/local/foo\", \"d:/usr/\", force: force) == \"local/foo\"\n        assert Path.relative_to(\"d:/usr/local/foo\", \"D:/usr/\", force: force) == \"local/foo\"\n        assert Path.relative_to(\"D:/usr/local/foo\", \"d:/\", force: force) == \"usr/local/foo\"\n        assert Path.relative_to(\"D:/usr/local/foo\", \"D:/\", force: force) == \"usr/local/foo\"\n\n        assert Path.relative_to(\"d:/usr/local/foo/..\", \"d:/usr/local\", force: force) == \".\"\n        assert Path.relative_to(\"d:/usr/local/../foo\", \"d:/usr/foo\", force: force) == \".\"\n        assert Path.relative_to(\"d:/usr/local/../foo/bar\", \"d:/usr/foo\", force: force) == \"bar\"\n        assert Path.relative_to(\"d:/usr/local/../foo/./bar\", \"d:/usr/foo\", force: force) == \"bar\"\n\n        assert Path.relative_to(\"d:/usr/local/../foo/bar/..\", \"d:/usr/foo\", force: force) == \".\"\n        assert Path.relative_to(\"d:/usr/local/foo/..\", \"d:/usr/local/..\", force: force) == \"local\"\n        assert Path.relative_to(\"d:/usr/local/foo/..\", \"d:/usr/local/.\", force: force) == \".\"\n      end\n\n      # different results for force: true\n      assert Path.relative_to(\"d:/usr/local/../foo\", \"d:/usr/local\") == \"d:/usr/foo\"\n      assert Path.relative_to(\"d:/usr/local/../foo\", \"d:/usr/local\", force: true) == \"../foo\"\n\n      assert Path.relative_to(\"d:/usr/local/../foo/../bar\", \"d:/usr/foo\") == \"d:/usr/bar\"\n      assert Path.relative_to(\"d:/usr/local/../foo/../bar\", \"d:/usr/foo\", force: true) == \"../bar\"\n\n      # on different volumes with force: true it should return the original path\n      assert Path.relative_to(\"d:/usr/local\", \"c:/usr/local\", force: true) == \"d:/usr/local\"\n      assert Path.relative_to(\"d:/usr/local\", \"c:/another/local\", force: true) == \"d:/usr/local\"\n    end\n\n    test \"type/1\" do\n      assert Path.type(\"C:/usr/local/bin\") == :absolute\n      assert Path.type(~c\"C:\\\\usr\\\\local\\\\bin\") == :absolute\n      assert Path.type(\"C:usr\\\\local\\\\bin\") == :volumerelative\n\n      assert Path.type(\"/usr/local/bin\") == :volumerelative\n      assert Path.type(~c\"usr/local/bin\") == :relative\n      assert Path.type(\"../usr/local/bin\") == :relative\n\n      assert Path.type(\"//host/path\") == :absolute\n      assert Path.type(\"\\\\\\\\host\\\\path\") == :absolute\n      assert Path.type(\"/\\\\host\\\\path\") == :absolute\n      assert Path.type(\"\\\\/host\\\\path\") == :absolute\n    end\n\n    test \"split/1\" do\n      assert Path.split(\"C:\\\\foo\\\\bar\") == [\"c:/\", \"foo\", \"bar\"]\n      assert Path.split(\"C:/foo/bar\") == [\"c:/\", \"foo\", \"bar\"]\n    end\n\n    test \"safe_relative/1\" do\n      assert Path.safe_relative(\"local/foo\") == {:ok, \"local/foo\"}\n      assert Path.safe_relative(\"D:/usr/local/foo\") == :error\n      assert Path.safe_relative(\"d:/usr/local/foo\") == :error\n      assert Path.safe_relative(\"foo/../..\") == :error\n    end\n\n    test \"safe_relative/2\" do\n      assert Path.safe_relative(\"local/foo/bar\", \"local\") == {:ok, \"local/foo/bar\"}\n      assert Path.safe_relative(\"foo/..\", \"local\") == {:ok, \"\"}\n      assert Path.safe_relative(\"..\", \"local/foo\") == :error\n      assert Path.safe_relative(\"d:/usr/local/foo\", \"D:/\") == :error\n      assert Path.safe_relative(\"D:/usr/local/foo\", \"d:/\") == :error\n    end\n  end\n\n  describe \"Unix\" do\n    @describetag :unix\n\n    test \"relative/1\" do\n      assert Path.relative(\"/usr/local/bin\") == \"usr/local/bin\"\n      assert Path.relative(\"usr/local/bin\") == \"usr/local/bin\"\n      assert Path.relative(\"../usr/local/bin\") == \"../usr/local/bin\"\n      assert Path.relative(\"/\") == \".\"\n      assert Path.relative(~c\"/\") == \".\"\n      assert Path.relative([~c\"/usr\", ?/, \"local/bin\"]) == \"usr/local/bin\"\n    end\n\n    test \"relative_to/3\" do\n      # subpaths of cwd, should give the same result for both force true and false\n      for force <- [false, true] do\n        assert Path.relative_to(\"/usr/local/foo\", \"/usr/local\", force: force) == \"foo\"\n        assert Path.relative_to(\"/usr/local/foo\", \"/\", force: force) == \"usr/local/foo\"\n        assert Path.relative_to(\"/usr/local/foo\", \"/usr/local/foo\", force: force) == \".\"\n        assert Path.relative_to(\"/usr/local/foo/\", \"/usr/local/foo\", force: force) == \".\"\n        assert Path.relative_to(\"/usr/local/foo\", \"/usr/local/foo/\", force: force) == \".\"\n\n        assert Path.relative_to(\"/usr/local/foo/..\", \"/usr/local\", force: force) == \".\"\n        assert Path.relative_to(\"/usr/local/../foo\", \"/usr/foo\", force: force) == \".\"\n        assert Path.relative_to(\"/usr/local/../foo/bar\", \"/usr/foo\", force: force) == \"bar\"\n        assert Path.relative_to(\"/usr/local/../foo/./bar\", \"/usr/foo\", force: force) == \"bar\"\n        assert Path.relative_to(\"/usr/local/../foo/bar/..\", \"/usr/foo\", force: force) == \".\"\n\n        assert Path.relative_to(\"/usr/local/foo/..\", \"/usr/local/..\", force: force) == \"local\"\n        assert Path.relative_to(\"/usr/local/foo/..\", \"/usr/local/.\", force: force) == \".\"\n      end\n\n      # With relative second argument\n      assert Path.relative_to(\"/usr/local/foo\", \"etc\") == \"/usr/local/foo\"\n      assert Path.relative_to(\"/usr/local/foo\", \"etc\", force: true) == \"/usr/local/foo\"\n\n      # Different relative paths for force true/false\n      assert Path.relative_to(\"/usr/local/foo\", \"/etc\") == \"/usr/local/foo\"\n      assert Path.relative_to(\"/usr/local/foo\", \"/etc\", force: true) == \"../usr/local/foo\"\n\n      assert Path.relative_to(\"/usr/local/../foo\", \"/usr/local\") == \"/usr/foo\"\n      assert Path.relative_to(\"/usr/local/../foo\", \"/usr/local\", force: true) == \"../foo\"\n\n      assert Path.relative_to(\"/usr/local/../foo/../bar\", \"/usr/foo\") == \"/usr/bar\"\n      assert Path.relative_to(\"/usr/local/../foo/../bar\", \"/usr/foo\", force: true) == \"../bar\"\n\n      # More tests with force: true\n      assert Path.relative_to(\"/etc\", \"/usr/local/foo\", force: true) == \"../../../etc\"\n      assert Path.relative_to(~c\"/usr/local/foo\", \"/etc\", force: true) == \"../usr/local/foo\"\n      assert Path.relative_to(\"/usr/local\", \"/usr/local/foo\", force: true) == \"..\"\n      assert Path.relative_to(\"/usr/local/..\", \"/usr/local\", force: true) == \"..\"\n\n      assert Path.relative_to(\"/usr/../etc/foo/../../bar\", \"/log/foo/../../usr/\", force: true) ==\n               \"../bar\"\n    end\n\n    test \"type/1\" do\n      assert Path.type(\"/usr/local/bin\") == :absolute\n      assert Path.type(\"usr/local/bin\") == :relative\n      assert Path.type(\"../usr/local/bin\") == :relative\n\n      assert Path.type(~c\"/usr/local/bin\") == :absolute\n      assert Path.type(~c\"usr/local/bin\") == :relative\n      assert Path.type(~c\"../usr/local/bin\") == :relative\n\n      assert Path.type([~c\"/usr/\", ~c\"local/bin\"]) == :absolute\n      assert Path.type([~c\"usr/\", ~c\"local/bin\"]) == :relative\n      assert Path.type([~c\"../usr\", ~c\"/local/bin\"]) == :relative\n    end\n  end\n\n  test \"relative_to_cwd/2\" do\n    assert Path.relative_to_cwd(__ENV__.file) == Path.relative_to(__ENV__.file, File.cwd!())\n\n    assert Path.relative_to_cwd(to_charlist(__ENV__.file)) ==\n             Path.relative_to(to_charlist(__ENV__.file), to_charlist(File.cwd!()))\n\n    assert Path.relative_to_cwd(Path.dirname(File.cwd!()), force: true) == \"..\"\n\n    [slash | split_cwd] = Path.split(File.cwd!())\n    relative_to_root = List.duplicate(\"..\", length(split_cwd))\n\n    assert Path.relative_to_cwd(slash) == slash\n    assert Path.relative_to_cwd(slash, force: true) == Path.join(relative_to_root)\n  end\n\n  test \"absname/1,2\" do\n    assert Path.absname(\"/\") |> strip_drive_letter_if_windows() == \"/\"\n    assert Path.absname(\"/foo\") |> strip_drive_letter_if_windows() == \"/foo\"\n    assert Path.absname(\"/./foo\") |> strip_drive_letter_if_windows() == \"/foo\"\n    assert Path.absname(\"/foo/bar\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n    assert Path.absname(\"/foo/bar/\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n    assert Path.absname(\"/foo/bar/../bar\") |> strip_drive_letter_if_windows() == \"/foo/bar/../bar\"\n\n    assert Path.absname(\"bar\", \"/foo\") == \"/foo/bar\"\n    assert Path.absname(\"bar/\", \"/foo\") == \"/foo/bar\"\n    assert Path.absname(\"bar/.\", \"/foo\") == \"/foo/bar/.\"\n    assert Path.absname(\"bar/../bar\", \"/foo\") == \"/foo/bar/../bar\"\n    assert Path.absname(\"bar/../bar\", \"foo\") == \"foo/bar/../bar\"\n    assert Path.absname([\"bar/\", ?., ?., [\"/bar\"]], \"/foo\") == \"/foo/bar/../bar\"\n  end\n\n  test \"expand/1,2 with user home\" do\n    home = System.user_home!() |> Path.absname()\n\n    assert home == Path.expand(\"~\")\n    assert home == Path.expand(~c\"~\")\n    assert is_binary(Path.expand(\"~/foo\"))\n    assert is_binary(Path.expand(~c\"~/foo\"))\n\n    assert Path.expand(\"~/file\") == Path.join(home, \"file\")\n    assert Path.expand(\"~/file\", \"whatever\") == Path.join(home, \"file\")\n    assert Path.expand(\"file\", Path.expand(\"~\")) == Path.join(home, \"file\")\n    assert Path.expand(\"file\", \"~\") == Path.join(home, \"file\")\n    assert Path.expand(\"~file\") == Path.join(File.cwd!(), \"~file\")\n  end\n\n  test \"expand/1,2\" do\n    assert Path.expand(\"/\") |> strip_drive_letter_if_windows() == \"/\"\n    assert Path.expand(\"/foo/../..\") |> strip_drive_letter_if_windows() == \"/\"\n    assert Path.expand(\"/foo\") |> strip_drive_letter_if_windows() == \"/foo\"\n    assert Path.expand(\"/./foo\") |> strip_drive_letter_if_windows() == \"/foo\"\n    assert Path.expand(\"/../foo\") |> strip_drive_letter_if_windows() == \"/foo\"\n    assert Path.expand(\"/foo/bar\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n    assert Path.expand(\"/foo/bar/\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n    assert Path.expand(\"/foo/bar/.\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n    assert Path.expand(\"/foo/bar/../bar\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n\n    assert Path.expand(\"bar\", \"/foo\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n    assert Path.expand(\"bar/\", \"/foo\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n    assert Path.expand(\"bar/.\", \"/foo\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n    assert Path.expand(\"bar/../bar\", \"/foo\") |> strip_drive_letter_if_windows() == \"/foo/bar\"\n\n    drive_letter =\n      Path.expand(\"../bar/../bar\", \"/foo/../foo/../foo\") |> strip_drive_letter_if_windows()\n\n    assert drive_letter == \"/bar\"\n\n    drive_letter =\n      Path.expand([~c\"..\", ?/, \"bar/../bar\"], ~c\"/foo/../foo/../foo\")\n      |> strip_drive_letter_if_windows()\n\n    assert \"/bar\" == drive_letter\n\n    assert Path.expand(\"/..\") |> strip_drive_letter_if_windows() == \"/\"\n\n    assert Path.expand(\"bar/../bar\", \"foo\") == Path.expand(\"foo/bar\")\n  end\n\n  test \"relative_to/3 (with relative paths)\" do\n    # on cwd\n    assert Path.relative_to(\"foo\", File.cwd!()) == \"foo\"\n    assert Path.relative_to(\"./foo\", File.cwd!()) == \"foo\"\n    assert Path.relative_to(\"./foo/.\", File.cwd!()) == \"foo\"\n    assert Path.relative_to(\"./foo/./bar/.\", File.cwd!()) == \"foo/bar\"\n    assert Path.relative_to(\"../foo/./bar/.\", File.cwd!()) == \"../foo/bar\"\n    assert Path.relative_to(\"../foo/./bar/..\", File.cwd!()) == \"../foo\"\n    assert Path.relative_to(\"../foo/../bar/..\", File.cwd!()) == \"..\"\n    assert Path.relative_to(\"./foo/../bar/..\", File.cwd!()) == \".\"\n\n    # both relative\n    assert Path.relative_to(\"usr/local/foo\", \".\") == \"usr/local/foo\"\n    assert Path.relative_to(\".\", \"usr/local/foo\") == \".\"\n    assert Path.relative_to(\"usr/local/foo\", \"usr/local\") == \"foo\"\n    assert Path.relative_to(\"usr/local/foo\", \"etc\") == \"../usr/local/foo\"\n    assert Path.relative_to(~c\"usr/local/foo\", \"etc\") == \"../usr/local/foo\"\n    assert Path.relative_to(\"usr/local/foo\", \"usr/local\") == \"foo\"\n    assert Path.relative_to([\"usr\", ?/, ~c\"local/foo\"], ~c\"usr/local\") == \"foo\"\n  end\n\n  test \"safe_relative/1\" do\n    assert Path.safe_relative(\"foo/bar\") == {:ok, \"foo/bar\"}\n    assert Path.safe_relative(\"foo/..\") == {:ok, \"\"}\n    assert Path.safe_relative(\"./foo\") == {:ok, \"foo\"}\n\n    assert Path.safe_relative(\"/usr/local/foo\") == :error\n    assert Path.safe_relative(\"foo/../..\") == :error\n  end\n\n  test \"safe_relative/2\" do\n    assert Path.safe_relative(\"/usr/local/foo\", \"/usr/local\") == :error\n    assert Path.safe_relative(\"../../..\", \"foo/bar\") == :error\n    assert Path.safe_relative(\"../../..\", \"foo/bar\") == :error\n    assert Path.safe_relative(\"/usr/local/foo\", \"/\") == :error\n  end\n\n  test \"rootname/2\" do\n    assert Path.rootname(\"~/foo/bar.ex\", \".ex\") == \"~/foo/bar\"\n    assert Path.rootname(\"~/foo/bar.exs\", \".ex\") == \"~/foo/bar.exs\"\n    assert Path.rootname(\"~/foo/bar.old.ex\", \".ex\") == \"~/foo/bar.old\"\n    assert Path.rootname([?~, ~c\"/foo/bar\", \".old.ex\"], ~c\".ex\") == \"~/foo/bar.old\"\n  end\n\n  test \"extname/1\" do\n    assert Path.extname(\"foo.erl\") == \".erl\"\n    assert Path.extname(\"~/foo/bar\") == \"\"\n\n    assert Path.extname(~c\"foo.erl\") == \".erl\"\n    assert Path.extname(~c\"~/foo/bar\") == \"\"\n  end\n\n  test \"dirname/1\" do\n    assert Path.dirname(\"/foo/bar.ex\") == \"/foo\"\n    assert Path.dirname(\"foo/bar.ex\") == \"foo\"\n\n    assert Path.dirname(\"~/foo/bar.ex\") == \"~/foo\"\n    assert Path.dirname(\"/foo/bar/baz/\") == \"/foo/bar/baz\"\n\n    assert Path.dirname([?~, \"/foo\", ~c\"/bar.ex\"]) == \"~/foo\"\n  end\n\n  test \"basename/1,2\" do\n    assert Path.basename(\"foo\") == \"foo\"\n    assert Path.basename(\"/foo/bar\") == \"bar\"\n    assert Path.basename(\"/\") == \"\"\n\n    assert Path.basename(\"~/foo/bar.ex\", \".ex\") == \"bar\"\n    assert Path.basename(\"~/foo/bar.exs\", \".ex\") == \"bar.exs\"\n    assert Path.basename(\"~/for/bar.old.ex\", \".ex\") == \"bar.old\"\n\n    assert Path.basename([?~, \"/for/bar\", ~c\".old.ex\"], \".ex\") == \"bar.old\"\n  end\n\n  test \"join/1\" do\n    assert Path.join([\"\"]) == \"\"\n    assert Path.join([\"foo\"]) == \"foo\"\n    assert Path.join([\"/\", \"foo\", \"bar\"]) == \"/foo/bar\"\n    assert Path.join([\"/\", \"foo\", \"bar\", \"/\"]) == \"/foo/bar\"\n    assert Path.join([\"~\", \"foo\", \"bar\"]) == \"~/foo/bar\"\n    assert Path.join([~c\"/foo/\", \"/bar/\"]) == \"/foo/bar\"\n    assert Path.join([\"/\", \"\"]) == \"/\"\n    assert Path.join([\"/\", \"\", \"bar\"]) == \"/bar\"\n    assert Path.join([~c\"foo\", [?b, \"a\", ?r]]) == \"foo/bar\"\n    assert Path.join([[?f, ~c\"o\", \"o\"]]) == \"foo\"\n  end\n\n  test \"join/2\" do\n    assert Path.join(\"/foo\", \"bar\") == \"/foo/bar\"\n    assert Path.join(\"~\", \"foo\") == \"~/foo\"\n\n    assert Path.join(\"\", \"bar\") == \"bar\"\n    assert Path.join(\"bar\", \"\") == \"bar\"\n    assert Path.join(\"\", \"/bar\") == \"bar\"\n    assert Path.join(\"/bar\", \"\") == \"/bar\"\n\n    assert Path.join(\"foo\", \"/bar\") == \"foo/bar\"\n    assert Path.join(\"/foo\", \"/bar\") == \"/foo/bar\"\n    assert Path.join(\"/foo\", \"/bar\") == \"/foo/bar\"\n    assert Path.join(\"/foo\", \"./bar\") == \"/foo/./bar\"\n\n    assert Path.join(\"/foo\", \"/\") == \"/foo\"\n    assert Path.join(\"/foo\", \"/bar/zar/\") == \"/foo/bar/zar\"\n\n    assert Path.join([?/, \"foo\"], \"./bar\") == \"/foo/./bar\"\n    assert Path.join([\"/foo\", \"bar\"], [\"fiz\", \"buz\"]) == \"/foobar/fizbuz\"\n  end\n\n  test \"split/1\" do\n    assert Path.split(\"\") == []\n    assert Path.split(\"foo\") == [\"foo\"]\n    assert Path.split(\"/foo/bar\") == [\"/\", \"foo\", \"bar\"]\n    assert Path.split([?/, \"foo/bar\"]) == [\"/\", \"foo\", \"bar\"]\n  end\n\n  if PathHelpers.windows?() do\n    defp strip_drive_letter_if_windows([_d, ?: | rest]), do: rest\n    defp strip_drive_letter_if_windows(<<_d, ?:, rest::binary>>), do: rest\n  else\n    defp strip_drive_letter_if_windows(path), do: path\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/port_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule PortTest do\n  use ExUnit.Case, async: true\n\n  test \"info/1,2 with registered name\" do\n    {:ok, port} = :gen_udp.open(0)\n\n    assert Port.info(port, :links) == {:links, [self()]}\n    assert Port.info(port, :registered_name) == {:registered_name, []}\n\n    Process.register(port, __MODULE__)\n\n    assert Port.info(port, :registered_name) == {:registered_name, __MODULE__}\n\n    :ok = :gen_udp.close(port)\n\n    assert Port.info(port, :registered_name) == nil\n    assert Port.info(port) == nil\n  end\n\n  # In contrast with other inlined functions,\n  # it is important to test that monitor/1 is inlined,\n  # this way we gain the monitor receive optimisation.\n  test \"monitor/1 is inlined\" do\n    assert expand(quote(do: Port.monitor(port())), __ENV__) ==\n             quote(do: :erlang.monitor(:port, port()))\n  end\n\n  defp expand(expr, env) do\n    {expr, _, _} = :elixir_expand.expand(expr, :elixir_env.env_to_ex(env), env)\n    expr\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/process_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule ProcessTest do\n  use ExUnit.Case, async: true\n\n  doctest Process\n\n  test \"dictionary\" do\n    assert Process.put(:foo, :bar) == nil\n    assert Process.put(:foo, :baz) == :bar\n\n    assert Enum.member?(Process.get_keys(), :foo)\n    refute Enum.member?(Process.get_keys(), :bar)\n    refute Enum.member?(Process.get_keys(), :baz)\n    assert Process.get_keys(:bar) == []\n    assert Process.get_keys(:baz) == [:foo]\n\n    assert Process.get(:foo) == :baz\n    assert Process.delete(:foo) == :baz\n    assert Process.get(:foo) == nil\n  end\n\n  test \"group_leader/2 and group_leader/0\" do\n    another = spawn_link(fn -> Process.sleep(1000) end)\n    assert Process.group_leader(self(), another)\n    assert Process.group_leader() == another\n  end\n\n  # In contrast with other inlined functions,\n  # it is important to test that monitor/1,2 are inlined,\n  # this way we gain the monitor receive optimisation.\n  test \"monitor/1 and monitor/2 are inlined\" do\n    assert expand(quote(do: Process.monitor(pid())), __ENV__) ==\n             quote(do: :erlang.monitor(:process, pid()))\n\n    assert expand(quote(do: Process.monitor(pid(), alias: :demonitor)), __ENV__) ==\n             quote(do: :erlang.monitor(:process, pid(), alias: :demonitor))\n  end\n\n  test \"monitor/2 with monitor options\" do\n    pid =\n      spawn(fn ->\n        receive do\n          {:ping, source_alias} -> send(source_alias, :pong)\n        end\n      end)\n\n    ref_and_alias = Process.monitor(pid, alias: :explicit_unalias)\n\n    send(pid, {:ping, ref_and_alias})\n\n    assert_receive :pong\n    assert_receive {:DOWN, ^ref_and_alias, _, _, _}\n  end\n\n  test \"sleep/1\" do\n    assert Process.sleep(0) == :ok\n  end\n\n  test \"sleep/1 with 2^32\" do\n    {pid, monitor_ref} = spawn_monitor(fn -> Process.sleep(2 ** 32) end)\n    refute_receive {:DOWN, ^monitor_ref, :process, ^pid, {:timeout_value, _trace}}, 100\n    Process.exit(pid, :kill)\n  end\n\n  test \"info/2\" do\n    pid = spawn(fn -> Process.sleep(1000) end)\n    assert Process.info(pid, :priority) == {:priority, :normal}\n    assert Process.info(pid, [:priority]) == [priority: :normal]\n\n    Process.exit(pid, :kill)\n    assert Process.info(pid, :backtrace) == nil\n    assert Process.info(pid, [:backtrace, :status]) == nil\n  end\n\n  test \"info/2 with registered name\" do\n    pid = spawn(fn -> nil end)\n    Process.exit(pid, :kill)\n    assert Process.info(pid, :registered_name) == nil\n    assert Process.info(pid, [:registered_name]) == nil\n\n    assert Process.info(self(), :registered_name) == {:registered_name, []}\n    assert Process.info(self(), [:registered_name]) == [registered_name: []]\n\n    Process.register(self(), __MODULE__)\n    assert Process.info(self(), :registered_name) == {:registered_name, __MODULE__}\n    assert Process.info(self(), [:registered_name]) == [registered_name: __MODULE__]\n  end\n\n  test \"send_after/3 sends messages once expired\" do\n    Process.send_after(self(), :hello, 10)\n    assert_receive :hello\n  end\n\n  test \"send_after/4 with absolute time sends message once expired\" do\n    time = System.monotonic_time(:millisecond) + 10\n    Process.send_after(self(), :hello, time, abs: true)\n    assert_receive :hello\n  end\n\n  test \"send_after/3 returns a timer reference that can be read or cancelled\" do\n    timer = Process.send_after(self(), :hello, 100_000)\n    refute_received :hello\n    assert is_integer(Process.read_timer(timer))\n    assert is_integer(Process.cancel_timer(timer))\n\n    timer = Process.send_after(self(), :hello, 0)\n    assert_receive :hello\n    assert Process.read_timer(timer) == false\n    assert Process.cancel_timer(timer) == false\n\n    timer = Process.send_after(self(), :hello, 100_000)\n    assert Process.cancel_timer(timer, async: true)\n    assert_receive {:cancel_timer, ^timer, result}\n    assert is_integer(result)\n  end\n\n  test \"exit(pid, :normal) does not cause the target process to exit\" do\n    Process.flag(:trap_exit, true)\n\n    pid =\n      spawn_link(fn ->\n        receive do\n          :done -> nil\n        end\n      end)\n\n    true = Process.exit(pid, :normal)\n    refute_receive {:EXIT, ^pid, :normal}, 100\n    assert Process.alive?(pid)\n\n    # now exit the process for real so it doesn't hang around\n    true = Process.exit(pid, :abnormal)\n    assert_receive {:EXIT, ^pid, :abnormal}\n    refute Process.alive?(pid)\n  end\n\n  test \"exit(self(), :normal) causes the calling process to exit\" do\n    Process.flag(:trap_exit, true)\n    pid = spawn_link(fn -> Process.exit(self(), :normal) end)\n    assert_receive {:EXIT, ^pid, :normal}\n    refute Process.alive?(pid)\n  end\n\n  describe \"alias/0, alias/1, and unalias/1\" do\n    test \"simple alias + unalias flow\" do\n      server =\n        spawn(fn ->\n          receive do\n            {:ping, alias} -> send(alias, :pong)\n          end\n        end)\n\n      alias = Process.alias()\n      Process.unalias(alias)\n\n      send(server, {:ping, alias})\n      refute_receive :pong, 20\n    end\n\n    test \"with :reply option when aliasing\" do\n      server =\n        spawn(fn ->\n          receive do\n            {:ping, alias} ->\n              send(alias, :pong)\n              send(alias, :extra_pong)\n          end\n        end)\n\n      alias = Process.alias([:reply])\n\n      send(server, {:ping, alias})\n      assert_receive :pong\n      refute_receive :extra_pong, 20\n    end\n  end\n\n  describe \"get_label/1\" do\n    test \"gets a process label, compatible with `:proc_lib.set_label/1`\" do\n      label = {:some_label, :rand.uniform(99999)}\n      assert :ok = :proc_lib.set_label(label)\n\n      assert Process.get_label() == label\n      assert Process.get_label(self()) == label\n    end\n\n    test \"returns nil when not set\" do\n      pid = spawn(fn -> :ok end)\n      assert Process.get_label(pid) == nil\n    end\n  end\n\n  describe \"set_label/1\" do\n    test \"sets a process label, compatible with `:proc_lib.get_label/1`\" do\n      label = {:some_label, :rand.uniform(99999)}\n      assert :ok = Process.set_label(label)\n\n      assert :proc_lib.get_label(self()) == label\n    end\n  end\n\n  defp expand(expr, env) do\n    {expr, _, _} = :elixir_expand.expand(expr, :elixir_env.env_to_ex(env), env)\n    expr\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/protocol/consolidation_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\npath = Path.expand(\"../../ebin\", __DIR__)\nFile.mkdir_p!(path)\n\nfiles = Path.wildcard(PathHelpers.fixture_path(\"consolidation/*\"))\nKernel.ParallelCompiler.compile_to_path(files, path, return_diagnostics: true)\n\ndefmodule Protocol.ConsolidationTest do\n  use ExUnit.Case, async: true\n  alias Protocol.ConsolidationTest.{Sample, WithAny, NoImpl}\n\n  defimpl WithAny, for: Map do\n    def ok(map, _opts) do\n      {:ok, map}\n    end\n  end\n\n  defimpl WithAny, for: Any do\n    def ok(any, _opts) do\n      {:ok, any}\n    end\n  end\n\n  defmodule NoImplStruct do\n    defstruct a: 0, b: 0\n  end\n\n  defmodule ImplStruct do\n    @derive [WithAny]\n    defstruct a: 0, b: 0\n\n    defimpl Sample do\n      @compile {:no_warn_undefined, Unknown}\n\n      def ok(struct) do\n        Unknown.undefined(struct)\n      end\n    end\n  end\n\n  Code.append_path(path)\n\n  # Any is ignored because there is no fallback\n  :code.purge(Sample)\n  :code.delete(Sample)\n  {:ok, binary} = Protocol.consolidate(Sample, [Any, ImplStruct])\n  :code.load_binary(Sample, ~c\"protocol_test.exs\", binary)\n\n  defp sample_binary, do: unquote(binary)\n\n  # Any should be moved to the end\n  :code.purge(WithAny)\n  :code.delete(WithAny)\n  {:ok, binary} = Protocol.consolidate(WithAny, [Any, ImplStruct, Map])\n  :code.load_binary(WithAny, ~c\"protocol_test.exs\", binary)\n\n  defp with_any_binary, do: unquote(binary)\n\n  # No Any\n  :code.purge(NoImpl)\n  :code.delete(NoImpl)\n  {:ok, binary} = Protocol.consolidate(NoImpl, [])\n  :code.load_binary(NoImpl, ~c\"protocol_test.exs\", binary)\n\n  defp no_impl_binary, do: unquote(binary)\n\n  test \"consolidated?/1\" do\n    assert Protocol.consolidated?(WithAny)\n    refute Protocol.consolidated?(Enumerable)\n  end\n\n  test \"consolidation warns on new implementations\" do\n    output =\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        defimpl WithAny, for: Integer do\n          def ok(_any, _opts), do: :ok\n        end\n      end)\n\n    assert output =~ ~r\"the .+WithAny protocol has already been consolidated\"\n  after\n    :code.purge(WithAny.Integer)\n    :code.delete(WithAny.Integer)\n  end\n\n  test \"consolidation warns on new implementations unless disabled\" do\n    Code.put_compiler_option(:ignore_already_consolidated, true)\n\n    defimpl WithAny, for: Integer do\n      def ok(_any), do: :ok\n    end\n  after\n    Code.put_compiler_option(:ignore_already_consolidated, false)\n    :code.purge(WithAny.Integer)\n    :code.delete(WithAny.Integer)\n  end\n\n  test \"consolidated implementations without fallback to any\" do\n    assert is_nil(Sample.impl_for(:foo))\n    assert is_nil(Sample.impl_for(fn x -> x end))\n    assert is_nil(Sample.impl_for(1))\n    assert is_nil(Sample.impl_for(1.1))\n    assert is_nil(Sample.impl_for([]))\n    assert is_nil(Sample.impl_for([1, 2, 3]))\n    assert is_nil(Sample.impl_for({}))\n    assert is_nil(Sample.impl_for({1, 2, 3}))\n    assert is_nil(Sample.impl_for(\"foo\"))\n    assert is_nil(Sample.impl_for(<<1>>))\n    assert is_nil(Sample.impl_for(self()))\n    assert is_nil(Sample.impl_for(%{}))\n    assert is_nil(Sample.impl_for(hd(:erlang.ports())))\n    assert is_nil(Sample.impl_for(make_ref()))\n\n    assert Sample.impl_for(%ImplStruct{}) == Sample.Protocol.ConsolidationTest.ImplStruct\n    assert Sample.impl_for(%NoImplStruct{}) == nil\n  end\n\n  test \"consolidated implementations with fallback to any\" do\n    assert WithAny.impl_for(%NoImplStruct{}) == WithAny.Any\n\n    # Derived\n    assert WithAny.impl_for(%ImplStruct{}) ==\n             Protocol.ConsolidationTest.WithAny.Protocol.ConsolidationTest.ImplStruct\n\n    assert WithAny.impl_for(%{__struct__: \"foo\"}) == WithAny.Map\n    assert WithAny.impl_for(%{}) == WithAny.Map\n    assert WithAny.impl_for(self()) == WithAny.Any\n  end\n\n  test \"consolidation keeps docs\" do\n    {:ok, {Sample, [{~c\"Docs\", docs_bin}]}} = :beam_lib.chunks(sample_binary(), [~c\"Docs\"])\n    {:docs_v1, _, _, _, _, _, docs} = :erlang.binary_to_term(docs_bin)\n    ok_doc = List.keyfind(docs, {:function, :ok, 1}, 0)\n\n    assert {{:function, :ok, 1}, _, [\"ok(term)\"], %{\"en\" => \"Ok\"}, _} = ok_doc\n  end\n\n  @tag :requires_source\n  test \"consolidation keeps source\" do\n    assert Sample.__info__(:compile)[:source]\n  end\n\n  test \"consolidated keeps callbacks\" do\n    {:ok, callbacks} = Code.Typespec.fetch_callbacks(sample_binary())\n    assert callbacks != []\n  end\n\n  test \"consolidation updates attributes\" do\n    assert Sample.__protocol__(:consolidated?)\n    assert Sample.__protocol__(:impls) == {:consolidated, [ImplStruct]}\n    assert WithAny.__protocol__(:consolidated?)\n    assert WithAny.__protocol__(:impls) == {:consolidated, [Any, Map, ImplStruct]}\n    assert NoImpl.__protocol__(:consolidated?)\n    assert NoImpl.__protocol__(:impls) == {:consolidated, []}\n  end\n\n  describe \"exports\" do\n    import Module.Types.Descr\n    alias Module.Types.Of\n\n    defp exports(binary) do\n      {:ok, {_, [{~c\"ExCk\", check_bin}]}} = :beam_lib.chunks(binary, [~c\"ExCk\"])\n      assert {:elixir_checker_v7, contents} = :erlang.binary_to_term(check_bin)\n      Map.new(contents.exports)\n    end\n\n    test \"keeps deprecations\" do\n      deprecated = [{{:ok, 1}, \"Reason\"}]\n      assert deprecated == Sample.__info__(:deprecated)\n\n      assert %{{:ok, 1} => %{deprecated: \"Reason\", sig: _}} = exports(sample_binary())\n    end\n\n    test \"defines signatures without fallback to any\" do\n      exports = exports(sample_binary())\n\n      assert %{{:impl_for, 1} => %{sig: {:strong, domain, clauses}}} = exports\n      assert domain == [term()]\n\n      assert clauses == [\n               {[Of.impl(ImplStruct, :open)],\n                atom([Sample.Protocol.ConsolidationTest.ImplStruct])},\n               {[negation(Of.impl(ImplStruct, :open))], atom([nil])}\n             ]\n\n      assert %{{:impl_for!, 1} => %{sig: {:strong, domain, clauses}}} = exports\n      assert domain == [Of.impl(ImplStruct, :open)]\n\n      assert clauses == [\n               {[Of.impl(ImplStruct, :open)],\n                atom([Sample.Protocol.ConsolidationTest.ImplStruct])}\n             ]\n\n      assert %{{:ok, 1} => %{sig: {:strong, nil, clauses}}} = exports\n\n      assert clauses == [\n               {[Of.impl(ImplStruct, :open)], dynamic()}\n             ]\n    end\n\n    test \"defines signatures with fallback to any\" do\n      exports = exports(with_any_binary())\n\n      assert %{\n               {:impl_for, 1} => %{sig: {:strong, domain, clauses}},\n               {:impl_for!, 1} => %{sig: {:strong, domain, clauses}}\n             } = exports\n\n      assert domain == [term()]\n\n      assert clauses == [\n               {[Of.impl(Map, :open)], atom([WithAny.Map])},\n               {[Of.impl(ImplStruct, :open)],\n                atom([WithAny.Protocol.ConsolidationTest.ImplStruct])},\n               {[negation(union(Of.impl(ImplStruct, :open), Of.impl(Map, :open)))],\n                atom([WithAny.Any])}\n             ]\n\n      assert %{{:ok, 2} => %{sig: {:strong, nil, clauses}}} = exports\n\n      assert clauses == [\n               {[term(), term()], dynamic()}\n             ]\n    end\n\n    test \"defines signatures without implementation\" do\n      exports = exports(no_impl_binary())\n\n      assert %{{:impl_for, 1} => %{sig: {:strong, domain, clauses}}} = exports\n      assert domain == [term()]\n      assert clauses == [{[term()], atom([nil])}]\n\n      assert %{{:impl_for!, 1} => %{sig: {:strong, domain, clauses}}} = exports\n      assert domain == [none()]\n      assert clauses == [{[none()], none()}]\n\n      assert %{{:ok, 1} => %{sig: {:strong, nil, clauses}}} = exports\n      assert clauses == [{[none()], dynamic()}]\n    end\n  end\n\n  test \"consolidation errors on missing BEAM files\" do\n    import PathHelpers\n\n    write_beam(\n      defmodule ExampleModule do\n      end\n    )\n\n    defprotocol NoBeam do\n      def example(arg)\n    end\n\n    assert Protocol.consolidate(ExampleModule, []) == {:error, :not_a_protocol}\n    assert Protocol.consolidate(NoBeam, []) == {:error, :no_beam_info}\n  end\n\n  test \"protocol not implemented\" do\n    message =\n      \"protocol Protocol.ConsolidationTest.Sample not implemented for Atom. \" <>\n        \"This protocol is implemented for: Protocol.ConsolidationTest.ImplStruct\" <>\n        \"\\n\\nGot value:\\n\\n    :foo\\n\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      sample = String.to_atom(\"Elixir.Protocol.ConsolidationTest.Sample\")\n      sample.ok(:foo)\n    end\n  end\n\n  describe \"extraction\" do\n    test \"protocols\" do\n      protos = Protocol.extract_protocols([Application.app_dir(:elixir, \"ebin\")])\n      assert Enumerable in protos\n      assert Inspect in protos\n    end\n\n    test \"protocols with expanded path\" do\n      path = to_charlist(Application.app_dir(:elixir, \"ebin\"))\n      {:ok, mods} = :file.list_dir(path)\n      protos = Protocol.extract_protocols([{path, mods}])\n      assert Enumerable in protos\n      assert Inspect in protos\n    end\n\n    test \"implementations with charlist path\" do\n      impls =\n        Protocol.extract_impls(Enumerable, [to_charlist(Application.app_dir(:elixir, \"ebin\"))])\n\n      assert List in impls\n      assert Function in impls\n    end\n\n    test \"implementations with binary path\" do\n      impls = Protocol.extract_impls(Enumerable, [Application.app_dir(:elixir, \"ebin\")])\n      assert List in impls\n      assert Function in impls\n    end\n\n    test \"implementations with expanded path\" do\n      path = to_charlist(Application.app_dir(:elixir, \"ebin\"))\n      {:ok, mods} = :file.list_dir(path)\n      impls = Protocol.extract_impls(Enumerable, [{path, mods}])\n      assert List in impls\n      assert Function in impls\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/protocol_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule ProtocolTest do\n  use ExUnit.Case, async: true\n\n  doctest Protocol\n\n  {_, _, sample_binary, _} =\n    defprotocol Sample do\n      @type t :: any\n      @doc \"Ok\"\n      @deprecated \"Reason\"\n      @spec ok(t) :: boolean\n      def ok(term)\n    end\n\n  @sample_binary sample_binary\n\n  {_, _, with_any_binary, _} =\n    defprotocol WithAny do\n      @fallback_to_any true\n      @doc \"Ok\"\n      def ok(term)\n    end\n\n  @with_any_binary with_any_binary\n\n  defprotocol Derivable do\n    @undefined_impl_description \"you should try harder\"\n\n    @impl true\n    defmacro __deriving__(module, options) do\n      struct = Macro.struct!(module, __CALLER__)\n\n      quote do\n        defimpl Derivable, for: unquote(module) do\n          def ok(arg) do\n            {:ok, arg, unquote(Macro.escape(struct)), unquote(options)}\n          end\n        end\n      end\n    end\n\n    def ok(a)\n  end\n\n  defimpl Derivable, for: Any do\n    def ok(arg) do\n      {:ok, arg}\n    end\n  end\n\n  defimpl WithAny, for: Map do\n    def ok(map) do\n      {:ok, map}\n    end\n  end\n\n  defimpl WithAny, for: Any do\n    def ok(any) do\n      {:ok, any}\n    end\n  end\n\n  defmodule NoImplStruct do\n    defstruct a: 0, b: 0\n  end\n\n  defmodule ImplStruct do\n    @derive [WithAny, Derivable]\n    defstruct a: 0, b: 0\n\n    defimpl Sample do\n      @compile {:no_warn_undefined, Unknown}\n\n      def ok(struct) do\n        Unknown.undefined(struct)\n      end\n    end\n  end\n\n  defmodule ImplStructExplicitFor do\n    defstruct a: 0, b: 0\n\n    defimpl Sample, for: __MODULE__ do\n      def ok(_struct), do: true\n    end\n  end\n\n  test \"protocol implementations without any\" do\n    assert is_nil(Sample.impl_for(:foo))\n    assert is_nil(Sample.impl_for(fn x -> x end))\n    assert is_nil(Sample.impl_for(1))\n    assert is_nil(Sample.impl_for(1.1))\n    assert is_nil(Sample.impl_for([]))\n    assert is_nil(Sample.impl_for([1, 2, 3]))\n    assert is_nil(Sample.impl_for({}))\n    assert is_nil(Sample.impl_for({1, 2, 3}))\n    assert is_nil(Sample.impl_for(\"foo\"))\n    assert is_nil(Sample.impl_for(<<1>>))\n    assert is_nil(Sample.impl_for(%{}))\n    assert is_nil(Sample.impl_for(self()))\n    assert is_nil(Sample.impl_for(hd(:erlang.ports())))\n    assert is_nil(Sample.impl_for(make_ref()))\n\n    assert Sample.impl_for(%ImplStruct{}) == Sample.ProtocolTest.ImplStruct\n    assert Sample.impl_for(%ImplStructExplicitFor{}) == Sample.ProtocolTest.ImplStructExplicitFor\n    assert Sample.impl_for(%NoImplStruct{}) == nil\n    assert is_nil(Sample.impl_for(%{__struct__: nil}))\n  end\n\n  test \"protocol implementation with Any and struct fallbacks\" do\n    assert WithAny.impl_for(%NoImplStruct{}) == WithAny.Any\n    assert WithAny.impl_for(%{__struct__: nil}) == WithAny.Any\n    assert WithAny.impl_for(%{__struct__: \"foo\"}) == WithAny.Map\n    assert WithAny.impl_for(%{}) == WithAny.Map\n    assert WithAny.impl_for(self()) == WithAny.Any\n\n    # Derived\n    assert WithAny.impl_for(%ImplStruct{}) == ProtocolTest.WithAny.ProtocolTest.ImplStruct\n  end\n\n  test \"protocol not implemented\" do\n    message =\n      \"\"\"\n      protocol ProtocolTest.Sample not implemented for Atom\n\n      Got value:\n\n          :foo\n      \"\"\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      sample = String.to_atom(\"Elixir.ProtocolTest.Sample\")\n      sample.ok(:foo)\n    end\n  end\n\n  test \"protocol documentation and deprecated\" do\n    import PathHelpers\n\n    write_beam(\n      defprotocol SampleDocsProto do\n        @doc \"Ok\"\n        @deprecated \"Reason\"\n        @spec ok(t) :: boolean\n        def ok(term)\n      end\n    )\n\n    write_beam(\n      defimpl SampleDocsProto, for: List do\n        def ok(_), do: true\n      end\n    )\n\n    write_beam(\n      defimpl SampleDocsProto, for: Map do\n        @moduledoc \"for map\"\n\n        def ok(_), do: true\n      end\n    )\n\n    {:docs_v1, _, _, _, _, _, docs} = Code.fetch_docs(SampleDocsProto)\n\n    assert {{:type, :t, 0}, _, [], %{\"en\" => type_doc}, _} = List.keyfind(docs, {:type, :t, 0}, 0)\n    assert type_doc =~ \"All the types that implement this protocol\"\n\n    assert {{:function, :ok, 1}, _, [\"ok(term)\"], %{\"en\" => \"Ok\"}, _} =\n             List.keyfind(docs, {:function, :ok, 1}, 0)\n\n    deprecated = SampleDocsProto.__info__(:deprecated)\n    assert [{{:ok, 1}, \"Reason\"}] = deprecated\n\n    {:docs_v1, _, _, _, :hidden, _, _} = Code.fetch_docs(SampleDocsProto.List)\n    {:docs_v1, _, _, _, moduledoc, _, _} = Code.fetch_docs(SampleDocsProto.Map)\n    assert moduledoc == %{\"en\" => \"for map\"}\n  end\n\n  @compile {:no_warn_undefined, WithAll}\n\n  test \"protocol keeps underlying UndefinedFunctionError\" do\n    assert_raise UndefinedFunctionError, fn ->\n      WithAll.ok(%ImplStruct{})\n    end\n  end\n\n  test \"protocol defines callbacks\" do\n    assert [{:type, {17, 13}, :fun, args}] = get_callbacks(@sample_binary, :ok, 1)\n\n    assert args == [\n             {:type, {17, 13}, :product, [{:user_type, {17, 16}, :t, []}]},\n             {:type, {17, 22}, :boolean, []}\n           ]\n\n    assert [{:type, 27, :fun, args}] = get_callbacks(@with_any_binary, :ok, 1)\n    assert args == [{:type, 27, :product, [{:user_type, 27, :t, []}]}, {:type, 27, :term, []}]\n  end\n\n  test \"protocol defines t/0 type with documentation\" do\n    assert {:type, {:t, {_, _, :any, []}, []}} = get_type(@sample_binary, :t, 0)\n  end\n\n  test \"protocol defines functions and attributes\" do\n    assert Sample.__protocol__(:module) == Sample\n    assert Sample.__protocol__(:functions) == [ok: 1]\n    refute Sample.__protocol__(:consolidated?)\n    assert Sample.__protocol__(:impls) == :not_consolidated\n    assert Sample.__info__(:attributes)[:__protocol__] == [fallback_to_any: false]\n\n    assert WithAny.__protocol__(:module) == WithAny\n    assert WithAny.__protocol__(:functions) == [ok: 1]\n    refute WithAny.__protocol__(:consolidated?)\n    assert WithAny.__protocol__(:impls) == :not_consolidated\n    assert WithAny.__info__(:attributes)[:__protocol__] == [fallback_to_any: true]\n  end\n\n  test \"defimpl\" do\n    module = Module.concat(Sample, ImplStruct)\n    assert module.__impl__(:for) == ImplStruct\n    assert module.__impl__(:protocol) == Sample\n    assert module.__info__(:attributes)[:__impl__] == [protocol: Sample, for: ImplStruct]\n  end\n\n  test \"defimpl with implicit derive\" do\n    module = Module.concat(WithAny, ImplStruct)\n    assert module.__impl__(:for) == ImplStruct\n    assert module.__impl__(:protocol) == WithAny\n    assert module.__info__(:attributes)[:__impl__] == [protocol: WithAny, for: ImplStruct]\n  end\n\n  test \"defimpl with explicit derive\" do\n    module = Module.concat(Derivable, ImplStruct)\n    assert module.__impl__(:for) == ImplStruct\n    assert module.__impl__(:protocol) == Derivable\n    assert module.__info__(:attributes)[:__impl__] == [protocol: Derivable, for: ImplStruct]\n  end\n\n  test \"defimpl with multiple for\" do\n    defprotocol Multi do\n      def test(a)\n    end\n\n    defimpl Multi, for: [Atom, Integer] do\n      def test(a), do: a\n    end\n\n    assert Multi.test(1) == 1\n    assert Multi.test(:a) == :a\n  end\n\n  test \"defimpl without :for option when outside a module\" do\n    msg = \"defimpl/3 expects a :for option when declared outside a module\"\n\n    assert_raise ArgumentError, msg, fn ->\n      ast =\n        quote do\n          defimpl Sample do\n            def ok(_term), do: true\n          end\n        end\n\n      Code.eval_quoted(ast, [], %{__ENV__ | module: nil})\n    end\n  end\n\n  defp get_callbacks(beam, name, arity) do\n    {:ok, callbacks} = Code.Typespec.fetch_callbacks(beam)\n    List.keyfind(callbacks, {name, arity}, 0) |> elem(1)\n  end\n\n  defp get_type(beam, name, arity) do\n    {:ok, types} = Code.Typespec.fetch_types(beam)\n\n    assert {:value, value} =\n             :lists.search(&match?({_, {^name, _, args}} when length(args) == arity, &1), types)\n\n    value\n  end\n\n  test \"derives protocol implicitly\" do\n    struct = %ImplStruct{a: 1, b: 1}\n    assert WithAny.ok(struct) == {:ok, struct}\n\n    struct = %NoImplStruct{a: 1, b: 1}\n    assert WithAny.ok(struct) == {:ok, struct}\n  end\n\n  test \"derives protocol explicitly\" do\n    struct = %ImplStruct{a: 1, b: 1}\n    assert Derivable.ok(struct) == {:ok, struct, %ImplStruct{}, []}\n\n    assert_raise Protocol.UndefinedError,\n                 ~r\"protocol ProtocolTest.Derivable not implemented for ProtocolTest.NoImplStruct \\(a struct\\), you should try harder\",\n                 fn ->\n                   struct = %NoImplStruct{a: 1, b: 1}\n                   Derivable.ok(struct)\n                 end\n  end\n\n  test \"derives protocol explicitly with options\" do\n    defmodule AnotherStruct do\n      @derive [{Derivable, :ok}]\n      @derive [WithAny]\n      defstruct a: 0, b: 0\n    end\n\n    struct = struct(AnotherStruct, a: 1, b: 1)\n    assert Derivable.ok(struct) == {:ok, struct, struct(AnotherStruct), :ok}\n  end\n\n  test \"derive protocol explicitly via API\" do\n    defmodule InlineStruct do\n      defstruct a: 0, b: 0\n    end\n\n    require Protocol\n    assert Protocol.derive(Derivable, InlineStruct, :oops) == :ok\n\n    struct = struct(InlineStruct, a: 1, b: 1)\n    assert Derivable.ok(struct) == {:ok, struct, struct(InlineStruct), :oops}\n  end\n\n  @tag :requires_source\n  test \"derived implementation keeps local file/line info\" do\n    assert ProtocolTest.WithAny.ProtocolTest.ImplStruct.__info__(:compile)[:source] ==\n             String.to_charlist(__ENV__.file)\n  end\n\n  describe \"warnings\" do\n    import ExUnit.CaptureIO\n\n    test \"with no definitions\" do\n      assert capture_io(:stderr, fn ->\n               defprotocol SampleWithNoDefinitions do\n               end\n             end) =~ \"protocols must define at least one function, but none was defined\"\n    end\n\n    test \"when @callbacks and friends are defined inside a protocol\" do\n      message =\n        capture_io(:stderr, fn ->\n          defprotocol SampleWithCallbacks do\n            @spec with_specs(any(), keyword()) :: tuple()\n            def with_specs(term, options)\n\n            @spec with_specs_and_when(any(), opts) :: tuple() when opts: keyword\n            def with_specs_and_when(term, options)\n\n            def without_specs(term, options \\\\ [])\n\n            @callback foo :: {:ok, term}\n            @callback foo_when(x) :: {:ok, x} when x: term\n            @macrocallback bar(term) :: {:ok, term}\n\n            @optional_callbacks [foo: 0]\n            @optional_callbacks [without_specs: 2]\n          end\n        end)\n\n      assert message =~\n               \"default arguments in protocol definitions is deprecated\"\n\n      assert message =~\n               \"cannot define @callback foo/0 inside protocol, use def/1 to outline your protocol definition\"\n\n      assert message =~\n               \"cannot define @callback foo_when/1 inside protocol, use def/1 to outline your protocol definition\"\n\n      assert message =~\n               \"cannot define @macrocallback bar/1 inside protocol, use def/1 to outline your protocol definition\"\n\n      assert message =~\n               \"cannot define @optional_callbacks inside protocol, all of the protocol definitions are required\"\n    end\n\n    test \"when deriving after struct\" do\n      assert capture_io(:stderr, fn ->\n               defmodule DeriveTooLate do\n                 defstruct []\n                 @derive [{Derivable, :ok}]\n               end\n             end) =~\n               \"module attribute @derive was set after defstruct, all @derive calls must come before defstruct\"\n    end\n\n    test \"when deriving with no struct\" do\n      assert capture_io(:stderr, fn ->\n               defmodule DeriveNeverUsed do\n                 @derive [{Derivable, :ok}]\n               end\n             end) =~\n               \"module attribute @derive was set but never used (it must come before defstruct)\"\n    end\n  end\n\n  describe \"errors\" do\n    test \"cannot derive without any implementation\" do\n      assert_raise ArgumentError,\n                   ~r\"could not load module #{inspect(Sample.Any)} due to reason :nofile, cannot derive #{inspect(Sample)}\",\n                   fn ->\n                     defmodule NotCompiled do\n                       @derive [Sample]\n                       defstruct hello: :world\n                     end\n                   end\n    end\n  end\nend\n\ndefmodule Protocol.DebugInfoTest do\n  use ExUnit.Case\n\n  test \"protocols always keep debug_info\" do\n    Code.compiler_options(debug_info: false)\n\n    {:module, _, binary, _} =\n      defprotocol DebugInfoProto do\n        def example(info)\n      end\n\n    assert {:ok, {DebugInfoProto, [debug_info: debug_info]}} =\n             :beam_lib.chunks(binary, [:debug_info])\n\n    assert {:debug_info_v1, :elixir_erl, {:elixir_v1, _, _}} = debug_info\n  after\n    Code.compiler_options(debug_info: true)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/range_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule RangeTest do\n  use ExUnit.Case, async: true\n\n  doctest Range\n\n  defp reverse(first..last//step) do\n    last..first//-step\n  end\n\n  defp assert_disjoint(r1, r2) do\n    disjoint_assertions(r1, r2, true)\n  end\n\n  defp assert_overlap(r1, r2) do\n    disjoint_assertions(r1, r2, false)\n  end\n\n  defp disjoint_assertions(r1, r2, expected) do\n    # The caller should choose pairs of representative ranges, and we take care\n    # here of commuting them.\n    Enum.each([[r1, r2], [r2, r1]], fn [a, b] ->\n      assert Range.disjoint?(a, b) == expected\n      assert Range.disjoint?(reverse(a), b) == expected\n      assert Range.disjoint?(a, reverse(b)) == expected\n      assert Range.disjoint?(reverse(a), reverse(b)) == expected\n    end)\n  end\n\n  test \"new\" do\n    assert Range.new(1, 3) == 1..3//1\n    assert Range.new(1, 3, 2) == 1..3//2\n    assert Range.new(3, 1, -2) == 3..1//-2\n\n    assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n             assert Range.new(3, 1) == 3..1//-1\n           end) =~ \"default to a step of -1\"\n  end\n\n  test \"fields\" do\n    assert (1..3).first == 1\n    assert (1..3).last == 3\n    assert (1..3).step == 1\n    assert (3..1//-1).step == -1\n    assert (1..3//2).step == 2\n  end\n\n  test \"inspect\" do\n    assert inspect(1..3) == \"1..3\"\n    assert inspect(1..3//2) == \"1..3//2\"\n\n    assert inspect(3..1//-1) == \"3..1//-1\"\n    assert inspect(3..1//1) == \"3..1//1\"\n  end\n\n  test \"shift\" do\n    assert Range.shift(0..10//2, 2) == 4..14//2\n    assert Range.shift(0..10//2, 0) == 0..10//2\n    assert Range.shift(10..0//-2, 2) == 6..-4//-2\n    assert Range.shift(10..0//-2, -2) == 14..4//-2\n  end\n\n  test \"in guard equality\" do\n    case {1, 1..1} do\n      {n, range} when range == n..n//1 -> true\n    end\n  end\n\n  test \"step is a non-zero integer\" do\n    step = 1.0\n    message = ~r\"the step to be a non-zero integer\"\n    assert_raise ArgumentError, message, fn -> 1..3//step end\n\n    step = 0\n    message = ~r\"the step to be a non-zero integer\"\n    assert_raise ArgumentError, message, fn -> 1..3//step end\n  end\n\n  describe \"disjoint?\" do\n    test \"returns true for disjoint ranges\" do\n      assert_disjoint(1..5, 6..9)\n      assert_disjoint(-3..1, 2..3)\n      assert_disjoint(-7..-5, -3..-1)\n\n      assert Range.disjoint?(1..1, 2..2) == true\n      assert Range.disjoint?(2..2, 1..1) == true\n    end\n\n    test \"returns false for ranges with common endpoints\" do\n      assert_overlap(1..5, 5..9)\n      assert_overlap(-1..0, 0..1)\n      assert_overlap(-7..-5, -5..-1)\n    end\n\n    test \"returns false for ranges that overlap\" do\n      assert_overlap(1..5, 3..7)\n      assert_overlap(-3..1, -1..3)\n      assert_overlap(-7..-5, -5..-1)\n\n      assert Range.disjoint?(1..1, 1..1) == false\n    end\n  end\n\n  describe \"split\" do\n    @times 10\n\n    test \"increasing ranges\" do\n      for _ <- 1..@times do\n        left = Enum.random(-10..10)\n        right = Enum.random(-10..10)\n        input = min(left, right)..max(left, right)//Enum.random(1..3)\n\n        for split <- -3..3 do\n          {left, right} = Range.split(input, split)\n          assert input.first == left.first\n          assert input.last == right.last\n          assert input.step == left.step\n          assert input.step == right.step\n\n          assert Range.size(input) == Range.size(left) + Range.size(right),\n                 \"size mismatch: Range.split(#{inspect(input)}, #{split})\"\n        end\n      end\n    end\n\n    test \"decreasing ranges\" do\n      for _ <- 1..@times do\n        left = Enum.random(-10..10)\n        right = Enum.random(-10..10)\n        input = max(left, right)..min(left, right)//-Enum.random(1..3)\n\n        for split <- -3..3 do\n          {left, right} = Range.split(input, split)\n          assert input.first == left.first\n          assert input.last == right.last\n          assert input.step == left.step\n          assert input.step == right.step\n\n          assert Range.size(input) == Range.size(left) + Range.size(right),\n                 \"size mismatch: Range.split(#{inspect(input)}, #{split})\"\n        end\n      end\n    end\n\n    test \"empty increasing ranges\" do\n      for _ <- 1..@times,\n          left = Enum.random(-10..10),\n          right = Enum.random(-10..10),\n          left != right do\n        input = min(left, right)..max(left, right)//-Enum.random(1..3)\n\n        for split <- -3..3 do\n          {left, right} = Range.split(input, split)\n          assert input.first == left.first\n          assert input.last == right.last\n          assert input.step == left.step\n          assert input.step == right.step\n\n          assert Range.size(input) == Range.size(left) + Range.size(right),\n                 \"size mismatch: Range.split(#{inspect(input)}, #{split})\"\n        end\n      end\n    end\n\n    test \"empty decreasing ranges\" do\n      for _ <- 1..@times,\n          left = Enum.random(-10..10),\n          right = Enum.random(-10..10),\n          left != right do\n        input = max(left, right)..min(left, right)//Enum.random(1..3)\n\n        for split <- -3..3 do\n          {left, right} = Range.split(input, split)\n          assert input.first == left.first\n          assert input.last == right.last\n          assert input.step == left.step\n          assert input.step == right.step\n\n          assert Range.size(input) == Range.size(left) + Range.size(right),\n                 \"size mismatch: Range.split(#{inspect(input)}, #{split})\"\n        end\n      end\n    end\n  end\n\n  describe \"old ranges\" do\n    test \"enum\" do\n      asc = %{__struct__: Range, first: 1, last: 3}\n      desc = %{__struct__: Range, first: 3, last: 1}\n\n      assert Enum.to_list(asc) == [1, 2, 3]\n      assert Enum.member?(asc, 2)\n      assert Enum.count(asc) == 3\n      assert Enum.drop(asc, 1) == [2, 3]\n      assert Enum.slice([1, 2, 3, 4, 5, 6], asc) == [2, 3, 4]\n      # testing private Enum.aggregate\n      assert Enum.max(asc) == 3\n      assert Enum.sum(asc) == 6\n      assert Enum.min_max(asc) == {1, 3}\n      assert Enum.reduce(asc, 0, fn a, b -> a + b end) == 6\n\n      assert Enum.to_list(desc) == [3, 2, 1]\n      assert Enum.member?(desc, 2)\n      assert Enum.count(desc) == 3\n      assert Enum.drop(desc, 1) == [2, 1]\n\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               assert Enum.slice([1, 2, 3, 4, 5, 6], desc) == []\n             end) =~ \"negative steps are not supported in Enum.slice/2, pass 3..1//1 instead\"\n\n      # testing private Enum.aggregate\n      assert Enum.max(desc) == 3\n      assert Enum.sum(desc) == 6\n      assert Enum.min_max(desc) == {1, 3}\n      assert Enum.reduce(desc, 0, fn a, b -> a + b end) == 6\n    end\n\n    test \"string\" do\n      asc = %{__struct__: Range, first: 1, last: 3}\n      desc = %{__struct__: Range, first: 3, last: 1}\n\n      assert String.slice(\"elixir\", asc) == \"lix\"\n\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               assert String.slice(\"elixir\", desc) == \"\"\n             end) =~ \"negative steps are not supported in String.slice/2, pass 3..1//1 instead\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/record_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule RecordTest do\n  use ExUnit.Case, async: true\n\n  require Record\n  doctest Record\n\n  test \"extract/2 extracts information from an Erlang file\" do\n    assert Record.extract(:file_info, from_lib: \"kernel/include/file.hrl\") == [\n             size: :undefined,\n             type: :undefined,\n             access: :undefined,\n             atime: :undefined,\n             mtime: :undefined,\n             ctime: :undefined,\n             mode: :undefined,\n             links: :undefined,\n             major_device: :undefined,\n             minor_device: :undefined,\n             inode: :undefined,\n             uid: :undefined,\n             gid: :undefined\n           ]\n  end\n\n  test \"extract/2 handles nested records too\" do\n    namespace = Record.extract(:xmlElement, from_lib: \"xmerl/include/xmerl.hrl\")[:namespace]\n    assert is_tuple(namespace)\n    assert elem(namespace, 0) == :xmlNamespace\n  end\n\n  test \"extract/2 with defstruct\" do\n    defmodule StructExtract do\n      defstruct Record.extract(:file_info, from_lib: \"kernel/include/file.hrl\")\n    end\n\n    assert %{__struct__: StructExtract, size: :undefined} = StructExtract.__struct__()\n  end\n\n  test \"extract_all/1 extracts all records information from an Erlang file\" do\n    all_extract = Record.extract_all(from_lib: \"kernel/include/file.hrl\")\n    # has been stable over the very long time\n    assert length(all_extract) == 2\n    assert all_extract[:file_info]\n    assert all_extract[:file_descriptor]\n  end\n\n  # We need indirection to avoid warnings\n  defp record?(data, kind) do\n    Record.is_record(data, kind)\n  end\n\n  test \"is_record/2\" do\n    assert record?({User, \"meg\", 27}, User)\n    refute record?({User, \"meg\", 27}, Author)\n    refute record?(13, Author)\n    refute record?({\"user\", \"meg\", 27}, \"user\")\n    refute record?({}, User)\n    refute record?([], User)\n  end\n\n  # We need indirection to avoid warnings\n  defp record?(data) do\n    Record.is_record(data)\n  end\n\n  test \"is_record/1\" do\n    assert record?({User, \"john\", 27})\n    refute record?({\"john\", 27})\n    refute record?(13)\n    refute record?({})\n  end\n\n  def record_in_guard?(term) when Record.is_record(term), do: true\n  def record_in_guard?(_), do: false\n\n  def record_in_guard?(term, kind) when Record.is_record(term, kind), do: true\n  def record_in_guard?(_, _), do: false\n\n  test \"is_record/1,2 (in guard)\" do\n    assert record_in_guard?({User, \"john\", 27})\n    refute record_in_guard?({\"user\", \"john\", 27})\n\n    assert record_in_guard?({User, \"john\", 27}, User)\n    refute record_in_guard?({\"user\", \"john\", 27}, \"user\")\n  end\n\n  Record.defrecord(:timestamp, [:date, :time])\n  Record.defrecord(:user, __MODULE__, name: \"john\", age: 25)\n\n  Record.defrecordp(:file_info, Record.extract(:file_info, from_lib: \"kernel/include/file.hrl\"))\n\n  Record.defrecordp(\n    :certificate,\n    :OTPCertificate,\n    Record.extract(:OTPCertificate, from_lib: \"public_key/include/public_key.hrl\")\n  )\n\n  test \"records are tagged\" do\n    assert elem(file_info(), 0) == :file_info\n  end\n\n  test \"records macros\" do\n    record = user()\n    assert user(record, :name) == \"john\"\n    assert user(record, :age) == 25\n\n    record = user(record, name: \"meg\")\n    assert user(record, :name) == \"meg\"\n\n    assert elem(record, user(:name)) == \"meg\"\n    assert elem(record, 0) == RecordTest\n\n    user(name: name) = record\n    assert name == \"meg\"\n\n    assert user(:name) == 1\n  end\n\n  test \"records with default values\" do\n    record = user(_: :_, name: \"meg\")\n    assert user(record, :name) == \"meg\"\n    assert user(record, :age) == :_\n    assert match?(user(_: _), user())\n  end\n\n  test \"records preserve side-effects order\" do\n    user =\n      user(\n        age: send(self(), :age),\n        name: send(self(), :name)\n      )\n\n    assert Process.info(self(), :messages) == {:messages, [:age, :name]}\n\n    _ =\n      user(user,\n        age: send(self(), :update_age),\n        name: send(self(), :update_name)\n      )\n\n    assert Process.info(self(), :messages) ==\n             {:messages, [:age, :name, :update_age, :update_name]}\n  end\n\n  test \"nested records preserve side-effects order\" do\n    user =\n      user(\n        age:\n          user(\n            age: send(self(), :inner_age),\n            name: send(self(), :inner_name)\n          ),\n        name: send(self(), :name)\n      )\n\n    assert user == {RecordTest, :name, {RecordTest, :inner_name, :inner_age}}\n    assert for(_ <- 1..3, do: assert_receive(_)) == [:inner_age, :inner_name, :name]\n\n    user =\n      user(\n        name: send(self(), :name),\n        age:\n          user(\n            age: send(self(), :inner_age),\n            name: send(self(), :inner_name)\n          )\n      )\n\n    assert user == {RecordTest, :name, {RecordTest, :inner_name, :inner_age}}\n    assert for(_ <- 1..3, do: assert_receive(_)) == [:name, :inner_age, :inner_name]\n  end\n\n  Record.defrecord(\n    :defaults,\n    struct: ~D[2016-01-01],\n    map: %{},\n    tuple_zero: {},\n    tuple_one: {1},\n    tuple_two: {1, 2},\n    tuple_three: {1, 2, 3},\n    list: [1, 2, 3],\n    call: MapSet.new(),\n    string: \"abc\",\n    binary: <<1, 2, 3>>,\n    charlist: ~c\"abc\"\n  )\n\n  test \"records with literal defaults and on-the-fly record\" do\n    assert defaults(defaults()) == [\n             struct: ~D[2016-01-01],\n             map: %{},\n             tuple_zero: {},\n             tuple_one: {1},\n             tuple_two: {1, 2},\n             tuple_three: {1, 2, 3},\n             list: [1, 2, 3],\n             call: MapSet.new(),\n             string: \"abc\",\n             binary: <<1, 2, 3>>,\n             charlist: ~c\"abc\"\n           ]\n\n    assert defaults(defaults(), :struct) == ~D[2016-01-01]\n    assert defaults(defaults(), :map) == %{}\n    assert defaults(defaults(), :tuple_zero) == {}\n    assert defaults(defaults(), :tuple_one) == {1}\n    assert defaults(defaults(), :tuple_two) == {1, 2}\n    assert defaults(defaults(), :tuple_three) == {1, 2, 3}\n    assert defaults(defaults(), :list) == [1, 2, 3]\n    assert defaults(defaults(), :call) == MapSet.new()\n    assert defaults(defaults(), :string) == \"abc\"\n    assert defaults(defaults(), :binary) == <<1, 2, 3>>\n    assert defaults(defaults(), :charlist) == ~c\"abc\"\n  end\n\n  test \"records with literal defaults and record in a variable\" do\n    defaults = defaults()\n\n    assert defaults(defaults) == [\n             struct: ~D[2016-01-01],\n             map: %{},\n             tuple_zero: {},\n             tuple_one: {1},\n             tuple_two: {1, 2},\n             tuple_three: {1, 2, 3},\n             list: [1, 2, 3],\n             call: MapSet.new(),\n             string: \"abc\",\n             binary: <<1, 2, 3>>,\n             charlist: ~c\"abc\"\n           ]\n\n    assert defaults(defaults, :struct) == ~D[2016-01-01]\n    assert defaults(defaults, :map) == %{}\n    assert defaults(defaults, :tuple_zero) == {}\n    assert defaults(defaults, :tuple_one) == {1}\n    assert defaults(defaults, :tuple_two) == {1, 2}\n    assert defaults(defaults, :tuple_three) == {1, 2, 3}\n    assert defaults(defaults, :list) == [1, 2, 3]\n    assert defaults(defaults, :call) == MapSet.new()\n    assert defaults(defaults, :string) == \"abc\"\n    assert defaults(defaults, :binary) == <<1, 2, 3>>\n    assert defaults(defaults, :charlist) == ~c\"abc\"\n  end\n\n  test \"records with dynamic arguments\" do\n    record = file_info()\n    assert file_info(record, :size) == :undefined\n\n    record = user()\n    assert user(record) == [name: \"john\", age: 25]\n    assert user(user()) == [name: \"john\", age: 25]\n\n    msg =\n      \"expected argument to be a literal atom, literal keyword or a :file_info record, \" <>\n        \"got runtime: {RecordTest, \\\"john\\\", 25}\"\n\n    assert_raise ArgumentError, msg, fn ->\n      file_info(record)\n    end\n\n    pretender = {RecordTest, \"john\"}\n\n    msg =\n      \"expected argument to be a RecordTest record with 2 fields, \" <>\n        \"got: {RecordTest, \\\"john\\\"}\"\n\n    assert_raise ArgumentError, msg, fn ->\n      user(pretender)\n    end\n\n    pretender = {RecordTest, \"john\", 25, []}\n\n    msg =\n      \"expected argument to be a RecordTest record with 2 fields, \" <>\n        \"got: {RecordTest, \\\"john\\\", 25, []}\"\n\n    assert_raise ArgumentError, msg, fn ->\n      user(pretender)\n    end\n  end\n\n  test \"records visibility\" do\n    assert macro_exported?(__MODULE__, :user, 0)\n    refute macro_exported?(__MODULE__, :file_info, 1)\n  end\n\n  test \"records reflection\" do\n    assert %{fields: [:name, :age], kind: :defrecord, name: :user, tag: RecordTest} in @__records__\n\n    assert %{fields: [:date, :time], kind: :defrecord, name: :timestamp, tag: :timestamp} in @__records__\n  end\n\n  test \"records with no defaults\" do\n    record = timestamp()\n    assert timestamp(record, :date) == nil\n    assert timestamp(record, :time) == nil\n\n    record = timestamp(date: :foo, time: :bar)\n    assert timestamp(record, :date) == :foo\n    assert timestamp(record, :time) == :bar\n  end\n\n  test \"records defined multiple times\" do\n    msg = \"cannot define record :r because a definition r/0 already exists\"\n\n    assert_raise ArgumentError, msg, fn ->\n      defmodule M do\n        import Record\n        defrecord :r, [:a]\n        defrecord :r, [:a]\n      end\n    end\n  end\n\n  test \"macro and record with the same name defined\" do\n    msg = \"cannot define record :a because a definition a/1 already exists\"\n\n    assert_raise ArgumentError, msg, fn ->\n      defmodule M do\n        defmacro a(_) do\n        end\n\n        require Record\n        Record.defrecord(:a, [:a])\n      end\n    end\n\n    msg = \"cannot define record :a because a definition a/2 already exists\"\n\n    assert_raise ArgumentError, msg, fn ->\n      defmodule M do\n        defmacro a(_, _) do\n        end\n\n        require Record\n        Record.defrecord(:a, [:a])\n      end\n    end\n  end\n\n  test \"docs metadata\" do\n    import PathHelpers\n\n    write_beam(\n      defmodule Metadata do\n        Record.defrecord(:user, foo: 0, bar: \"baz\")\n      end\n    )\n\n    {:docs_v1, 352, :elixir, \"text/markdown\", _, %{}, docs} = Code.fetch_docs(RecordTest.Metadata)\n    {{:macro, :user, 1}, _meta, _sig, _docs, metadata} = List.keyfind(docs, {:macro, :user, 1}, 0)\n    assert %{record: {:user, [foo: 0, bar: \"baz\"]}} = metadata\n  end\n\n  describe \"warnings\" do\n    import ExUnit.CaptureIO\n\n    test \"warns on bad record update input\" do\n      assert capture_io(:stderr, fn ->\n               defmodule RecordSample do\n                 require Record\n                 Record.defrecord(:user, __MODULE__, name: \"john\", age: 25)\n\n                 def fun do\n                   user(user(), _: :_, name: \"meg\")\n                 end\n               end\n             end) =~\n               \"updating a record with a default (:_) is equivalent to creating a new record\"\n    after\n      purge(RecordSample)\n    end\n\n    test \"defrecord warns with duplicate keys\" do\n      assert capture_io(:stderr, fn ->\n               Code.eval_string(\"\"\"\n               defmodule RecordSample do\n                 import Record\n                 defrecord :r, [:foo, :bar, foo: 1]\n               end\n               \"\"\")\n             end) =~ \"duplicate key :foo found in record\"\n    after\n      purge(RecordSample)\n    end\n\n    defp purge(module) when is_atom(module) do\n      :code.purge(module)\n      :code.delete(module)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/regex_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule RegexTest do\n  use ExUnit.Case, async: true\n\n  doctest Regex\n\n  test \"module attribute\" do\n    defmodule ModAttr do\n      @regex ~r/example/\n      def regex, do: @regex\n\n      @bare_regex :erlang.term_to_binary(@regex)\n      def bare_regex, do: :erlang.binary_to_term(@bare_regex)\n\n      # We don't rewrite outside of functions\n      assert @regex.re_pattern == :erlang.binary_to_term(@bare_regex).re_pattern\n    end\n\n    if System.otp_release() >= \"28\" do\n      assert ModAttr.regex().re_pattern != ModAttr.bare_regex().re_pattern\n    else\n      assert ModAttr.regex().re_pattern == ModAttr.bare_regex().re_pattern\n    end\n  end\n\n  @tag :re_import\n  test \"module attribute in match context\" do\n    assert_raise(\n      ArgumentError,\n      ~r/escaped Regex structs are not allowed in match or guards/,\n      fn ->\n        Code.eval_quoted(\n          quote do\n            defmodule ModAttrGuard do\n              @regex ~r/example/\n              def example?(@regex), do: true\n              def example?(_), do: false\n            end\n          end\n        )\n      end\n    )\n  end\n\n  test \"multiline\" do\n    refute Regex.match?(~r/^b$/, \"a\\nb\\nc\")\n    assert Regex.match?(~r/^b$/m, \"a\\nb\\nc\")\n  end\n\n  @tag :re_import\n  test \"export\" do\n    # exported patterns have no structs, so these are structurally equal\n    assert ~r/foo/E == Regex.compile!(\"foo\", [:export])\n\n    assert Regex.match?(~r/foo/E, \"foo\")\n    refute Regex.match?(~r/foo/E, \"Foo\")\n\n    assert Regex.run(~r/c(d)/E, \"abcd\") == [\"cd\", \"d\"]\n    assert Regex.run(~r/e/E, \"abcd\") == nil\n\n    assert Regex.names(~r/(?<FOO>foo)/E) == [\"FOO\"]\n  end\n\n  test \"precedence\" do\n    assert {\"aa\", :unknown} |> elem(0) =~ ~r/(a)\\1/\n  end\n\n  test \"backreference\" do\n    assert \"aa\" =~ ~r/(a)\\1/\n  end\n\n  test \"source\" do\n    src = \"foo\"\n    assert Regex.source(Regex.compile!(src)) == src\n    assert Regex.source(~r/#{src}/) == src\n\n    src = \"\\a\\b\\d\\e\\f\\n\\r\\s\\t\\v\"\n    assert Regex.source(Regex.compile!(src)) == src\n    assert Regex.source(~r/#{src}/) == src\n\n    src = \"\\a\\\\b\\\\d\\\\e\\f\\n\\r\\\\s\\t\\v\"\n    assert Regex.source(Regex.compile!(src)) == src\n    assert Regex.source(~r/#{src}/) == src\n  end\n\n  test \"literal source\" do\n    assert Regex.source(Regex.compile!(\"foo\")) == \"foo\"\n    assert Regex.source(~r\"foo\") == \"foo\"\n\n    assert Regex.source(Regex.compile!(\"\\a\\b\\d\\e\\f\\n\\r\\s\\t\\v\")) == \"\\a\\b\\d\\e\\f\\n\\r\\s\\t\\v\"\n    assert Regex.source(~r<\\a\\b\\d\\e\\f\\n\\r\\s\\t\\v>) == \"\\\\a\\\\b\\\\d\\\\e\\\\f\\\\n\\\\r\\\\s\\\\t\\\\v\"\n  end\n\n  test \"Unicode\" do\n    assert \"olá\" =~ ~r\"\\p{Latin}$\"u\n    refute \"£\" =~ ~r/\\p{Lu}/u\n\n    # Non breaking space matches [[:space:]] with Unicode\n    assert <<0xA0::utf8>> =~ ~r/[[:space:]]/u\n    assert <<0xA0::utf8>> =~ ~r/\\s/u\n    assert <<?<, 255, ?>>> =~ ~r/<.>/\n  end\n\n  test \"ungreedy\" do\n    assert Regex.run(~r/[\\d ]+/, \"1 2 3 4 5\"), [\"1 2 3 4 5\"]\n    assert Regex.run(~r/[\\d ]?+/, \"1 2 3 4 5\"), [\"1\"]\n    assert Regex.run(~r/[\\d ]+/U, \"1 2 3 4 5\"), [\"1\"]\n  end\n\n  test \"compile/1\" do\n    {:ok, %Regex{}} = Regex.compile(\"foo\")\n    assert {:error, _} = Regex.compile(\"*foo\")\n    assert {:error, _} = Regex.compile(\"foo\", \"y\")\n    assert {:error, _} = Regex.compile(\"foo\", \"uy\")\n  end\n\n  test \"compile/1 with Erlang options\" do\n    {:ok, regex} = Regex.compile(\"foo\\\\sbar\", [:dotall, {:newline, :anycrlf}])\n    assert \"foo\\nbar\" =~ regex\n  end\n\n  test \"compile!/1\" do\n    assert %Regex{} = Regex.compile!(\"foo\")\n\n    # The exact position changed between Erlang/OTP 28.1 and 28.3\n    assert_raise Regex.CompileError, ~r/at position/, fn ->\n      Regex.compile!(\"*foo\")\n    end\n  end\n\n  test \"import/1\" do\n    # no-op for non-exported regexes\n    regex = ~r/foo/\n    assert Regex.import(regex) == regex\n\n    imported = Regex.import(~r/foo/E)\n\n    assert imported.opts == []\n    assert \"foo\" =~ imported\n    assert {:re_pattern, _, _, _, _} = imported.re_pattern\n  end\n\n  test \"opts/1\" do\n    assert Regex.opts(Regex.compile!(\"foo\", \"i\")) == [:caseless]\n    assert Regex.opts(Regex.compile!(\"foo\", [:ucp])) == [:ucp]\n  end\n\n  test \"names/1\" do\n    assert Regex.names(~r/(?<FOO>foo)/) == [\"FOO\"]\n  end\n\n  test \"match?/2\" do\n    assert Regex.match?(~r/foo/, \"foo\")\n    refute Regex.match?(~r/foo/, \"FOO\")\n    assert Regex.match?(~r/foo/i, \"FOO\")\n    assert Regex.match?(~r/\\d{1,3}/i, \"123\")\n\n    assert Regex.match?(~r/foo/, \"afooa\")\n    refute Regex.match?(~r/^foo/, \"afooa\")\n    assert Regex.match?(~r/^foo/, \"fooa\")\n    refute Regex.match?(~r/foo$/, \"afooa\")\n    assert Regex.match?(~r/foo$/, \"afoo\")\n  end\n\n  test \"named_captures/2\" do\n    assert Regex.named_captures(~r/(?<foo>c)(?<bar>d)/, \"abcd\") == %{\"bar\" => \"d\", \"foo\" => \"c\"}\n    assert Regex.named_captures(~r/c(?<foo>d)/, \"abcd\") == %{\"foo\" => \"d\"}\n    assert Regex.named_captures(~r/c(?<foo>d)/, \"no_match\") == nil\n    assert Regex.named_captures(~r/c(?<foo>d|e)/, \"abcd abce\") == %{\"foo\" => \"d\"}\n    assert Regex.named_captures(~r/c(.)/, \"cat\") == %{}\n  end\n\n  test \"run/2\" do\n    assert Regex.run(~r\"c(d)\", \"abcd\") == [\"cd\", \"d\"]\n    assert Regex.run(~r\"e\", \"abcd\") == nil\n  end\n\n  test \"run/3 with :all_names as the value of the :capture option\" do\n    assert Regex.run(~r/c(?<foo>d)/, \"abcd\", capture: :all_names) == [\"d\"]\n    assert Regex.run(~r/c(?<foo>d)/, \"no_match\", capture: :all_names) == nil\n    assert Regex.run(~r/c(?<foo>d|e)/, \"abcd abce\", capture: :all_names) == [\"d\"]\n  end\n\n  test \"run/3 with :index as the value of the :return option\" do\n    assert Regex.run(~r\"c(d)\", \"abcd\", return: :index) == [{2, 2}, {3, 1}]\n    assert Regex.run(~r\"e\", \"abcd\", return: :index) == nil\n  end\n\n  test \"run/3 with :offset\" do\n    assert Regex.run(~r\"^foo\", \"foobar\", offset: 0) == [\"foo\"]\n    assert Regex.run(~r\"^foo\", \"foobar\", offset: 2) == nil\n    assert Regex.run(~r\"^foo\", \"foobar\", offset: 2, return: :index) == nil\n    assert Regex.run(~r\"bar\", \"foobar\", offset: 2, return: :index) == [{3, 3}]\n  end\n\n  test \"scan/2\" do\n    assert Regex.scan(~r\"c(d|e)\", \"abcd abce\") == [[\"cd\", \"d\"], [\"ce\", \"e\"]]\n    assert Regex.scan(~r\"c(?:d|e)\", \"abcd abce\") == [[\"cd\"], [\"ce\"]]\n    assert Regex.scan(~r\"e\", \"abcd\") == []\n  end\n\n  test \"scan/2 with :all_names as the value of the :capture option\" do\n    assert Regex.scan(~r/cd/, \"abcd\", capture: :all_names) == []\n    assert Regex.scan(~r/c(?<foo>d)/, \"abcd\", capture: :all_names) == [[\"d\"]]\n    assert Regex.scan(~r/c(?<foo>d)/, \"no_match\", capture: :all_names) == []\n    assert Regex.scan(~r/c(?<foo>d|e)/, \"abcd abce\", capture: :all_names) == [[\"d\"], [\"e\"]]\n  end\n\n  test \"scan/2 with :offset\" do\n    assert Regex.scan(~r\"^foo\", \"foobar\", offset: 0) == [[\"foo\"]]\n    assert Regex.scan(~r\"^foo\", \"foobar\", offset: 1) == []\n  end\n\n  test \"split/2,3\" do\n    assert Regex.split(~r\",\", \"\") == [\"\"]\n    assert Regex.split(~r\",\", \"\", trim: true) == []\n    assert Regex.split(~r\",\", \"\", trim: true, parts: 2) == []\n\n    assert Regex.split(~r\"=\", \"key=\") == [\"key\", \"\"]\n    assert Regex.split(~r\"=\", \"=value\") == [\"\", \"value\"]\n\n    assert Regex.split(~r\" \", \"foo bar baz\") == [\"foo\", \"bar\", \"baz\"]\n    assert Regex.split(~r\" \", \"foo bar baz\", parts: :infinity) == [\"foo\", \"bar\", \"baz\"]\n    assert Regex.split(~r\" \", \"foo bar baz\", parts: 10) == [\"foo\", \"bar\", \"baz\"]\n    assert Regex.split(~r\" \", \"foo bar baz\", parts: 2) == [\"foo\", \"bar baz\"]\n\n    assert Regex.split(~r\" \", \" foo bar baz \") == [\"\", \"foo\", \"bar\", \"baz\", \"\"]\n    assert Regex.split(~r\" \", \" foo bar baz \", trim: true) == [\"foo\", \"bar\", \"baz\"]\n    assert Regex.split(~r\" \", \" foo bar baz \", parts: 2) == [\"\", \"foo bar baz \"]\n    assert Regex.split(~r\" \", \" foo bar baz \", trim: true, parts: 2) == [\"foo\", \"bar baz \"]\n\n    assert Regex.split(~r/b\\K/, \"ababab\") == [\"ab\", \"ab\", \"ab\", \"\"]\n  end\n\n  test \"split/3 with the :on option\" do\n    assert Regex.split(~r/()abc()/, \"xabcxabcx\", on: :none) == [\"xabcxabcx\"]\n\n    parts = [\"x\", \"abc\", \"x\", \"abc\", \"x\"]\n    assert Regex.split(~r/()abc()/, \"xabcxabcx\", on: :all_but_first) == parts\n\n    assert Regex.split(~r/(?<first>)abc(?<last>)/, \"xabcxabcx\", on: [:first, :last]) == parts\n\n    parts = [\"xabc\", \"xabc\", \"x\"]\n    assert Regex.split(~r/(?<first>)abc(?<last>)/, \"xabcxabcx\", on: [:last, :first]) == parts\n\n    assert Regex.split(~r/a(?<second>b)c/, \"abc\", on: [:second]) == [\"a\", \"c\"]\n\n    parts = [\"a\", \"c adc a\", \"c\"]\n    assert Regex.split(~r/a(?<second>b)c|a(?<fourth>d)c/, \"abc adc abc\", on: [:second]) == parts\n\n    assert Regex.split(~r/a(?<second>b)c|a(?<fourth>d)c/, \"abc adc abc\", on: [:second, :fourth]) ==\n             [\"a\", \"c a\", \"c a\", \"c\"]\n  end\n\n  test \"split/3 with the :include_captures option\" do\n    assert Regex.split(~r/([ln])/, \"Erlang\", include_captures: true) == [\"Er\", \"l\", \"a\", \"n\", \"g\"]\n    assert Regex.split(~r/([kw])/, \"Elixir\", include_captures: true) == [\"Elixir\"]\n\n    assert Regex.split(~r/([Ee]lixir)/, \"Elixir\", include_captures: true, trim: true) ==\n             [\"Elixir\"]\n\n    assert Regex.split(~r/([Ee]lixir)/, \"Elixir\", include_captures: true, trim: false) ==\n             [\"\", \"Elixir\", \"\"]\n\n    assert Regex.split(~r//, \"abc\", include_captures: true) ==\n             [\"\", \"\", \"a\", \"\", \"b\", \"\", \"c\", \"\", \"\"]\n\n    assert Regex.split(~r/a/, \"abc\", include_captures: true) == [\"\", \"a\", \"bc\"]\n    assert Regex.split(~r/c/, \"abc\", include_captures: true) == [\"ab\", \"c\", \"\"]\n\n    assert Regex.split(~r/[Ei]/, \"Elixir\", include_captures: true, parts: 2) ==\n             [\"\", \"E\", \"lixir\"]\n\n    assert Regex.split(~r/[Ei]/, \"Elixir\", include_captures: true, parts: 3) ==\n             [\"\", \"E\", \"l\", \"i\", \"xir\"]\n\n    assert Regex.split(~r/[Ei]/, \"Elixir\", include_captures: true, parts: 2, trim: true) ==\n             [\"E\", \"lixir\"]\n\n    assert Regex.split(~r/[Ei]/, \"Elixir\", include_captures: true, parts: 3, trim: true) ==\n             [\"E\", \"l\", \"i\", \"xir\"]\n\n    assert Regex.split(~r/b\\Kc/, \"abcabc\", include_captures: true) == [\"ab\", \"c\", \"ab\", \"c\", \"\"]\n    assert Regex.split(~r/(b\\K)/, \"abab\", include_captures: true) == [\"ab\", \"\", \"ab\", \"\", \"\"]\n\n    assert Regex.split(~r/(b\\K)/, \"abab\", include_captures: true, trim: true) == [\n             \"ab\",\n             \"\",\n             \"ab\",\n             \"\"\n           ]\n  end\n\n  test \"replace/3,4\" do\n    assert Regex.replace(~r/d/, \"abc\", \"d\") == \"abc\"\n    assert Regex.replace(~r/b/, \"abc\", \"d\") == \"adc\"\n    assert Regex.replace(~r/b/, \"abc\", \"[\\\\0]\") == \"a[b]c\"\n    assert Regex.replace(~r[(b)], \"abc\", \"[\\\\1]\") == \"a[b]c\"\n    assert Regex.replace(~r[(b)], \"abc\", \"[\\\\2]\") == \"a[]c\"\n    assert Regex.replace(~r[(b)], \"abc\", \"[\\\\3]\") == \"a[]c\"\n    assert Regex.replace(~r/b/, \"abc\", \"[\\\\g{0}]\") == \"a[b]c\"\n    assert Regex.replace(~r[(b)], \"abc\", \"[\\\\g{1}]\") == \"a[b]c\"\n\n    assert Regex.replace(~r/b/, \"abcbe\", \"d\") == \"adcde\"\n    assert Regex.replace(~r/b/, \"abcbe\", \"d\", global: false) == \"adcbe\"\n\n    assert Regex.replace(~r/ /, \"first third\", \"\\\\second\\\\\") == \"first\\\\second\\\\third\"\n    assert Regex.replace(~r/ /, \"first third\", \"\\\\\\\\second\\\\\\\\\") == \"first\\\\second\\\\third\"\n\n    assert Regex.replace(~r[a(b)c], \"abcabc\", fn -> \"ac\" end) == \"acac\"\n    assert Regex.replace(~r[a(b)c], \"abcabc\", fn \"abc\" -> \"ac\" end) == \"acac\"\n    assert Regex.replace(~r[a(b)c], \"abcabc\", fn \"abc\", \"b\" -> \"ac\" end) == \"acac\"\n    assert Regex.replace(~r[a(b)c], \"abcabc\", fn \"abc\", \"b\", \"\" -> \"ac\" end) == \"acac\"\n    assert Regex.replace(~r[a(b)c], \"abcabc\", fn \"abc\", \"b\" -> \"ac\" end, global: false) == \"acabc\"\n  end\n\n  test \"escape\" do\n    assert matches_escaped?(\".\")\n    refute matches_escaped?(\".\", \"x\")\n\n    assert matches_escaped?(\"[\\w]\")\n    refute matches_escaped?(\"[\\w]\", \"x\")\n\n    assert matches_escaped?(\"\\\\\")\n\n    assert matches_escaped?(\"\\\\xff\", \"\\\\xff\")\n    refute matches_escaped?(\"\\\\xff\", \"\\xff\")\n\n    assert matches_escaped?(\"(\")\n    assert matches_escaped?(\"()\")\n    assert matches_escaped?(\"(?:foo)\")\n\n    assert matches_escaped?(\"\\\\A  \\\\z\")\n    assert matches_escaped?(\"  x  \")\n    # Unicode spaces here\n    assert matches_escaped?(\"  x    x \")\n    assert matches_escaped?(\"# lol\")\n\n    assert matches_escaped?(\"\\\\A.^$*+?()[{\\\\| \\t\\n\\x20\\\\z #hello\\u202F\\u205F\")\n    assert Regex.match?(Regex.compile!(\"[\" <> Regex.escape(\"!-#\") <> \"]\"), \"-\")\n\n    assert Regex.escape(\"{}\") == \"\\\\{\\\\}\"\n    assert Regex.escape(\"[]\") == \"\\\\[\\\\]\"\n\n    assert Regex.escape(\"{foo}\") == \"\\\\{foo\\\\}\"\n    assert Regex.escape(\"[foo]\") == \"\\\\[foo\\\\]\"\n  end\n\n  defp matches_escaped?(string) do\n    matches_escaped?(string, string)\n  end\n\n  defp matches_escaped?(string, match) do\n    Regex.match?(~r/#{Regex.escape(string)}/simx, match)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/registry/duplicate_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Registry.DuplicateTest do\n  use ExUnit.Case,\n    async: true,\n    parameterize:\n      for(\n        keys <- [:duplicate, {:duplicate, :pid}, {:duplicate, :key}],\n        partitions <- [1, 8],\n        do: %{keys: keys, partitions: partitions}\n      )\n\n  setup config do\n    keys = config.keys\n    partitions = config.partitions\n\n    listeners =\n      List.wrap(config[:base_listener]) |> Enum.map(&:\"#{&1}_#{partitions}_#{inspect(keys)}\")\n\n    name = :\"#{config.test}_#{partitions}_#{inspect(keys)}\"\n    opts = [keys: config.keys, name: name, partitions: partitions, listeners: listeners]\n    {:ok, _} = start_supervised({Registry, opts})\n    %{registry: name, listeners: listeners}\n  end\n\n  test \"starts configured number of partitions\", %{registry: registry, partitions: partitions} do\n    assert length(Supervisor.which_children(registry)) == partitions\n  end\n\n  test \"counts 0 keys in an empty registry\", %{registry: registry} do\n    assert 0 == Registry.count(registry)\n  end\n\n  test \"counts the number of keys in a registry\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n\n    assert 2 == Registry.count(registry)\n  end\n\n  test \"has duplicate registrations\", %{registry: registry} do\n    {:ok, pid} = Registry.register(registry, \"hello\", :value)\n    assert is_pid(pid)\n    assert Registry.keys(registry, self()) == [\"hello\"]\n    assert Registry.values(registry, \"hello\", self()) == [:value]\n\n    assert {:ok, pid} = Registry.register(registry, \"hello\", :value)\n    assert is_pid(pid)\n    assert Registry.keys(registry, self()) == [\"hello\", \"hello\"]\n    assert Registry.values(registry, \"hello\", self()) == [:value, :value]\n\n    {:ok, pid} = Registry.register(registry, \"world\", :value)\n    assert is_pid(pid)\n    assert Registry.keys(registry, self()) |> Enum.sort() == [\"hello\", \"hello\", \"world\"]\n  end\n\n  test \"has duplicate registrations across processes\", %{registry: registry} do\n    {_, task} = register_task(registry, \"hello\", :world)\n    assert Registry.keys(registry, self()) == []\n    assert Registry.keys(registry, task) == [\"hello\"]\n    assert Registry.values(registry, \"hello\", self()) == []\n    assert Registry.values(registry, \"hello\", task) == [:world]\n\n    assert {:ok, _pid} = Registry.register(registry, \"hello\", :value)\n    assert Registry.keys(registry, self()) == [\"hello\"]\n    assert Registry.values(registry, \"hello\", self()) == [:value]\n  end\n\n  test \"compares using matches\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, 1.0, :value)\n    {:ok, _} = Registry.register(registry, 1, :value)\n    assert Registry.keys(registry, self()) |> Enum.sort() == [1, 1.0]\n  end\n\n  test \"dispatches to multiple keys in serial\", %{registry: registry} do\n    Process.flag(:trap_exit, true)\n    parent = self()\n\n    fun = fn _ -> raise \"will never be invoked\" end\n    assert Registry.dispatch(registry, \"hello\", fun, parallel: false) == :ok\n\n    {:ok, _} = Registry.register(registry, \"hello\", :value1)\n    {:ok, _} = Registry.register(registry, \"hello\", :value2)\n    {:ok, _} = Registry.register(registry, \"world\", :value3)\n\n    fun = fn entries ->\n      assert parent == self()\n      for {pid, value} <- entries, do: send(pid, {:dispatch, value})\n    end\n\n    assert Registry.dispatch(registry, \"hello\", fun, parallel: false)\n\n    assert_received {:dispatch, :value1}\n    assert_received {:dispatch, :value2}\n    refute_received {:dispatch, :value3}\n\n    fun = fn entries ->\n      assert parent == self()\n      for {pid, value} <- entries, do: send(pid, {:dispatch, value})\n    end\n\n    assert Registry.dispatch(registry, \"world\", fun, parallel: false)\n\n    refute_received {:dispatch, :value1}\n    refute_received {:dispatch, :value2}\n    assert_received {:dispatch, :value3}\n\n    refute_received {:EXIT, _, _}\n  end\n\n  test \"dispatches to multiple keys in parallel\", context do\n    %{registry: registry, partitions: partitions} = context\n    Process.flag(:trap_exit, true)\n    parent = self()\n\n    fun = fn _ -> raise \"will never be invoked\" end\n    assert Registry.dispatch(registry, \"hello\", fun, parallel: true) == :ok\n\n    {:ok, _} = Registry.register(registry, \"hello\", :value1)\n    {:ok, _} = Registry.register(registry, \"hello\", :value2)\n    {:ok, _} = Registry.register(registry, \"world\", :value3)\n\n    fun = fn entries ->\n      if partitions == 8 do\n        assert parent != self()\n      else\n        assert parent == self()\n      end\n\n      for {pid, value} <- entries, do: send(pid, {:dispatch, value})\n    end\n\n    assert Registry.dispatch(registry, \"hello\", fun, parallel: true)\n\n    assert_received {:dispatch, :value1}\n    assert_received {:dispatch, :value2}\n    refute_received {:dispatch, :value3}\n\n    fun = fn entries ->\n      if partitions == 8 do\n        assert parent != self()\n      else\n        assert parent == self()\n      end\n\n      for {pid, value} <- entries, do: send(pid, {:dispatch, value})\n    end\n\n    assert Registry.dispatch(registry, \"world\", fun, parallel: true)\n\n    refute_received {:dispatch, :value1}\n    refute_received {:dispatch, :value2}\n    assert_received {:dispatch, :value3}\n\n    refute_received {:EXIT, _, _}\n  end\n\n  test \"unregisters by key\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n    assert Registry.keys(registry, self()) |> Enum.sort() == [\"hello\", \"hello\", \"world\"]\n\n    :ok = Registry.unregister(registry, \"hello\")\n    assert Registry.keys(registry, self()) == [\"world\"]\n\n    :ok = Registry.unregister(registry, \"world\")\n    assert Registry.keys(registry, self()) == []\n  end\n\n  test \"unregisters with no entries\", %{registry: registry} do\n    assert Registry.unregister(registry, \"hello\") == :ok\n  end\n\n  test \"unregisters with tricky keys\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, :_, :foo)\n    {:ok, _} = Registry.register(registry, :_, :bar)\n    {:ok, _} = Registry.register(registry, \"hello\", \"a\")\n    {:ok, _} = Registry.register(registry, \"hello\", \"b\")\n\n    Registry.unregister(registry, :_)\n    assert Registry.keys(registry, self()) |> Enum.sort() == [\"hello\", \"hello\"]\n  end\n\n  test \"supports match patterns\", %{registry: registry} do\n    value1 = {1, :atom, 1}\n    value2 = {2, :atom, 2}\n\n    {:ok, _} = Registry.register(registry, \"hello\", value1)\n    {:ok, _} = Registry.register(registry, \"hello\", value2)\n\n    assert Registry.match(registry, \"hello\", {1, :_, :_}) == [{self(), value1}]\n    assert Registry.match(registry, \"hello\", {1.0, :_, :_}) == []\n\n    assert Registry.match(registry, \"hello\", {:_, :atom, :_}) |> Enum.sort() ==\n             [{self(), value1}, {self(), value2}]\n\n    assert Registry.match(registry, \"hello\", {:\"$1\", :_, :\"$1\"}) |> Enum.sort() ==\n             [{self(), value1}, {self(), value2}]\n\n    assert Registry.match(registry, \"hello\", {2, :_, :_}) == [{self(), value2}]\n    assert Registry.match(registry, \"hello\", {2.0, :_, :_}) == []\n  end\n\n  test \"supports guards\", %{registry: registry} do\n    value1 = {1, :atom, 1}\n    value2 = {2, :atom, 2}\n\n    {:ok, _} = Registry.register(registry, \"hello\", value1)\n    {:ok, _} = Registry.register(registry, \"hello\", value2)\n\n    assert Registry.match(registry, \"hello\", {:\"$1\", :_, :_}, [{:<, :\"$1\", 2}]) ==\n             [{self(), value1}]\n\n    assert Registry.match(registry, \"hello\", {:\"$1\", :_, :_}, [{:>, :\"$1\", 3}]) == []\n\n    assert Registry.match(registry, \"hello\", {:\"$1\", :_, :_}, [{:<, :\"$1\", 3}]) |> Enum.sort() ==\n             [{self(), value1}, {self(), value2}]\n\n    assert Registry.match(registry, \"hello\", {:_, :\"$1\", :_}, [{:is_atom, :\"$1\"}])\n           |> Enum.sort() == [{self(), value1}, {self(), value2}]\n  end\n\n  test \"count_match supports match patterns\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n    assert 1 == Registry.count_match(registry, \"hello\", {1, :_, :_})\n    assert 0 == Registry.count_match(registry, \"hello\", {1.0, :_, :_})\n    assert 1 == Registry.count_match(registry, \"hello\", {:_, :atom, :_})\n    assert 1 == Registry.count_match(registry, \"hello\", {:\"$1\", :_, :\"$1\"})\n    assert 1 == Registry.count_match(registry, \"hello\", :_)\n    assert 0 == Registry.count_match(registry, :_, :_)\n\n    value2 = %{a: \"a\", b: \"b\"}\n    {:ok, _} = Registry.register(registry, \"world\", value2)\n    assert 1 == Registry.count_match(registry, \"world\", %{b: \"b\"})\n  end\n\n  test \"count_match supports guard conditions\", %{registry: registry} do\n    value = {1, :atom, 2}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert 1 == Registry.count_match(registry, \"hello\", {:_, :_, :\"$1\"}, [{:>, :\"$1\", 1}])\n    assert 0 == Registry.count_match(registry, \"hello\", {:_, :_, :\"$1\"}, [{:>, :\"$1\", 2}])\n    assert 1 == Registry.count_match(registry, \"hello\", {:_, :\"$1\", :_}, [{:is_atom, :\"$1\"}])\n  end\n\n  test \"unregister_match supports patterns\", %{registry: registry} do\n    value1 = {1, :atom, 1}\n    value2 = {2, :atom, 2}\n\n    {:ok, _} = Registry.register(registry, \"hello\", value1)\n    {:ok, _} = Registry.register(registry, \"hello\", value2)\n\n    Registry.unregister_match(registry, \"hello\", {2, :_, :_})\n    assert Registry.lookup(registry, \"hello\") == [{self(), value1}]\n\n    {:ok, _} = Registry.register(registry, \"hello\", value2)\n    Registry.unregister_match(registry, \"hello\", {2.0, :_, :_})\n    assert Registry.lookup(registry, \"hello\") == [{self(), value1}, {self(), value2}]\n    Registry.unregister_match(registry, \"hello\", {:_, :atom, :_})\n    assert Registry.lookup(registry, \"hello\") == []\n  end\n\n  test \"unregister_match supports guards\", %{registry: registry} do\n    value1 = {1, :atom, 1}\n    value2 = {2, :atom, 2}\n\n    {:ok, _} = Registry.register(registry, \"hello\", value1)\n    {:ok, _} = Registry.register(registry, \"hello\", value2)\n\n    Registry.unregister_match(registry, \"hello\", {:\"$1\", :_, :_}, [{:<, :\"$1\", 2}])\n    assert Registry.lookup(registry, \"hello\") == [{self(), value2}]\n  end\n\n  test \"unregister_match supports tricky keys\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, :_, :foo)\n    {:ok, _} = Registry.register(registry, :_, :bar)\n    {:ok, _} = Registry.register(registry, \"hello\", \"a\")\n    {:ok, _} = Registry.register(registry, \"hello\", \"b\")\n\n    Registry.unregister_match(registry, :_, :foo)\n    assert Registry.lookup(registry, :_) == [{self(), :bar}]\n\n    assert Registry.keys(registry, self()) |> Enum.sort() == [:_, \"hello\", \"hello\"]\n  end\n\n  @tag base_listener: :unique_listener\n  test \"allows listeners\", %{registry: registry, listeners: [listener]} do\n    Process.register(self(), listener)\n    {_, task} = register_task(registry, \"hello\", :world)\n    assert_received {:register, ^registry, \"hello\", ^task, :world}\n\n    self = self()\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    assert_received {:register, ^registry, \"hello\", ^self, :value}\n\n    :ok = Registry.unregister(registry, \"hello\")\n    assert_received {:unregister, ^registry, \"hello\", ^self}\n  after\n    Process.unregister(listener)\n  end\n\n  test \"links and unlinks on register/unregister\", %{registry: registry} do\n    {:ok, pid} = Registry.register(registry, \"hello\", :value)\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    {:ok, pid} = Registry.register(registry, \"world\", :value)\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    :ok = Registry.unregister(registry, \"hello\")\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    :ok = Registry.unregister(registry, \"world\")\n    {:links, links} = Process.info(self(), :links)\n    refute pid in links\n  end\n\n  test \"raises on unknown registry name\" do\n    assert_raise ArgumentError, ~r/unknown registry/, fn ->\n      Registry.register(:unknown, \"hello\", :value)\n    end\n  end\n\n  test \"raises if attempt to be used on via\", %{registry: registry} do\n    assert_raise ArgumentError, \":via is not supported for duplicate registries\", fn ->\n      name = {:via, Registry, {registry, \"hello\"}}\n      Agent.start_link(fn -> 0 end, name: name)\n    end\n  end\n\n  test \"empty list for empty registry\", %{registry: registry} do\n    assert Registry.select(registry, [{{:_, :_, :_}, [], [:\"$_\"]}]) == []\n  end\n\n  test \"select all\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n\n    assert Registry.select(registry, [{{:\"$1\", :\"$2\", :\"$3\"}, [], [{{:\"$1\", :\"$2\", :\"$3\"}}]}])\n           |> Enum.sort() ==\n             [{\"hello\", self(), :value}, {\"hello\", self(), :value}]\n  end\n\n  test \"select supports full match specs\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert [{\"hello\", self(), value}] ==\n             Registry.select(registry, [\n               {{\"hello\", :\"$2\", :\"$3\"}, [], [{{\"hello\", :\"$2\", :\"$3\"}}]}\n             ])\n\n    assert [{\"hello\", self(), value}] ==\n             Registry.select(registry, [\n               {{:\"$1\", self(), :\"$3\"}, [], [{{:\"$1\", self(), :\"$3\"}}]}\n             ])\n\n    assert [{\"hello\", self(), value}] ==\n             Registry.select(registry, [\n               {{:\"$1\", :\"$2\", value}, [], [{{:\"$1\", :\"$2\", {value}}}]}\n             ])\n\n    assert [] ==\n             Registry.select(registry, [\n               {{\"world\", :\"$2\", :\"$3\"}, [], [{{\"world\", :\"$2\", :\"$3\"}}]}\n             ])\n\n    assert [] == Registry.select(registry, [{{:\"$1\", :\"$2\", {1.0, :_, :_}}, [], [:\"$_\"]}])\n\n    assert [{\"hello\", self(), value}] ==\n             Registry.select(registry, [\n               {{:\"$1\", :\"$2\", {:\"$3\", :atom, :\"$4\"}}, [],\n                [{{:\"$1\", :\"$2\", {{:\"$3\", :atom, :\"$4\"}}}}]}\n             ])\n\n    assert [{\"hello\", self(), {1, :atom, 1}}] ==\n             Registry.select(registry, [\n               {{:\"$1\", :\"$2\", {:\"$3\", :\"$4\", :\"$3\"}}, [],\n                [{{:\"$1\", :\"$2\", {{:\"$3\", :\"$4\", :\"$3\"}}}}]}\n             ])\n\n    value2 = %{a: \"a\", b: \"b\"}\n    {:ok, _} = Registry.register(registry, \"world\", value2)\n\n    assert [:match] ==\n             Registry.select(registry, [{{\"world\", self(), %{b: \"b\"}}, [], [:match]}])\n\n    assert [\"hello\", \"world\"] ==\n             Registry.select(registry, [{{:\"$1\", :_, :_}, [], [:\"$1\"]}]) |> Enum.sort()\n  end\n\n  test \"select supports guard conditions\", %{registry: registry} do\n    value = {1, :atom, 2}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert [{\"hello\", self(), {1, :atom, 2}}] ==\n             Registry.select(registry, [\n               {{:\"$1\", :\"$2\", {:\"$3\", :\"$4\", :\"$5\"}}, [{:>, :\"$5\", 1}],\n                [{{:\"$1\", :\"$2\", {{:\"$3\", :\"$4\", :\"$5\"}}}}]}\n             ])\n\n    assert [] ==\n             Registry.select(registry, [\n               {{:_, :_, {:_, :_, :\"$1\"}}, [{:>, :\"$1\", 2}], [:\"$_\"]}\n             ])\n\n    assert [\"hello\"] ==\n             Registry.select(registry, [\n               {{:\"$1\", :_, {:_, :\"$2\", :_}}, [{:is_atom, :\"$2\"}], [:\"$1\"]}\n             ])\n  end\n\n  test \"select allows multiple specs\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n\n    assert [\"hello\", \"world\"] ==\n             Registry.select(registry, [\n               {{\"hello\", :_, :_}, [], [{:element, 1, :\"$_\"}]},\n               {{\"world\", :_, :_}, [], [{:element, 1, :\"$_\"}]}\n             ])\n             |> Enum.sort()\n  end\n\n  test \"count_select supports match specs\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n    assert 1 == Registry.count_select(registry, [{{:_, :_, value}, [], [true]}])\n    assert 1 == Registry.count_select(registry, [{{\"hello\", :_, :_}, [], [true]}])\n    assert 1 == Registry.count_select(registry, [{{:_, :_, {1, :atom, :_}}, [], [true]}])\n    assert 1 == Registry.count_select(registry, [{{:_, :_, {:\"$1\", :_, :\"$1\"}}, [], [true]}])\n    assert 0 == Registry.count_select(registry, [{{\"hello\", :_, nil}, [], [true]}])\n\n    value2 = %{a: \"a\", b: \"b\"}\n    {:ok, _} = Registry.register(registry, \"world\", value2)\n    assert 1 == Registry.count_select(registry, [{{\"world\", :_, :_}, [], [true]}])\n  end\n\n  test \"count_select supports guard conditions\", %{registry: registry} do\n    value = {1, :atom, 2}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert 1 ==\n             Registry.count_select(registry, [\n               {{:_, :_, {:_, :\"$1\", :_}}, [{:is_atom, :\"$1\"}], [true]}\n             ])\n\n    assert 1 ==\n             Registry.count_select(registry, [\n               {{:_, :_, {:_, :_, :\"$1\"}}, [{:>, :\"$1\", 1}], [true]}\n             ])\n\n    assert 0 ==\n             Registry.count_select(registry, [\n               {{:_, :_, {:_, :_, :\"$1\"}}, [{:>, :\"$1\", 2}], [true]}\n             ])\n  end\n\n  test \"count_select allows multiple specs\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n\n    assert 2 ==\n             Registry.count_select(registry, [\n               {{\"hello\", :_, :_}, [], [true]},\n               {{\"world\", :_, :_}, [], [true]}\n             ])\n  end\n\n  test \"rejects invalid tuple syntax\", %{partitions: partitions} do\n    name = :\"test_invalid_tuple_#{partitions}\"\n\n    assert_raise ArgumentError, ~r/expected :keys to be given and be one of/, fn ->\n      Registry.start_link(keys: {:duplicate, :invalid}, name: name, partitions: partitions)\n    end\n  end\n\n  test \"update_value is not supported\", %{registry: registry} do\n    assert_raise ArgumentError, ~r/Registry.update_value\\/3 is not supported/, fn ->\n      Registry.update_value(registry, \"hello\", fn val -> val end)\n    end\n  end\n\n  defp register_task(registry, key, value) do\n    parent = self()\n\n    {:ok, task} =\n      Task.start(fn ->\n        send(parent, Registry.register(registry, key, value))\n        Process.sleep(:infinity)\n      end)\n\n    assert_receive {:ok, owner}\n    {owner, task}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/registry/unique_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Registry.UniqueTest do\n  use ExUnit.Case,\n    async: true,\n    parameterize: [\n      %{partitions: 1},\n      %{partitions: 8}\n    ]\n\n  @keys :unique\n\n  setup config do\n    partitions = config.partitions\n    listeners = List.wrap(config[:base_listener]) |> Enum.map(&:\"#{&1}_#{partitions}\")\n    name = :\"#{config.test}_#{partitions}\"\n    opts = [keys: @keys, name: name, partitions: partitions, listeners: listeners]\n    {:ok, _} = start_supervised({Registry, opts})\n    %{registry: name, listeners: listeners}\n  end\n\n  test \"starts configured number of partitions\", %{registry: registry, partitions: partitions} do\n    assert length(Supervisor.which_children(registry)) == partitions\n  end\n\n  test \"counts 0 keys in an empty registry\", %{registry: registry} do\n    assert 0 == Registry.count(registry)\n  end\n\n  test \"counts the number of keys in a registry\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n\n    assert 2 == Registry.count(registry)\n  end\n\n  test \"has unique registrations\", %{registry: registry} do\n    {:ok, pid} = Registry.register(registry, \"hello\", :value)\n    assert is_pid(pid)\n    assert Registry.keys(registry, self()) == [\"hello\"]\n    assert Registry.values(registry, \"hello\", self()) == [:value]\n\n    assert {:error, {:already_registered, pid}} = Registry.register(registry, \"hello\", :value)\n    assert pid == self()\n    assert Registry.keys(registry, self()) == [\"hello\"]\n    assert Registry.values(registry, \"hello\", self()) == [:value]\n\n    {:ok, pid} = Registry.register(registry, \"world\", :value)\n    assert is_pid(pid)\n    assert Registry.keys(registry, self()) |> Enum.sort() == [\"hello\", \"world\"]\n  end\n\n  test \"has unique registrations across processes\", %{registry: registry} do\n    {_, task} = register_task(registry, \"hello\", :value)\n    Process.link(Process.whereis(registry))\n    assert Registry.keys(registry, task) == [\"hello\"]\n    assert Registry.values(registry, \"hello\", task) == [:value]\n\n    assert {:error, {:already_registered, ^task}} =\n             Registry.register(registry, \"hello\", :recent)\n\n    assert Registry.keys(registry, self()) == []\n    assert Registry.values(registry, \"hello\", self()) == []\n\n    {:links, links} = Process.info(self(), :links)\n    assert Process.whereis(registry) in links\n  end\n\n  test \"has unique registrations even if partition is delayed\", %{registry: registry} do\n    {owner, task} = register_task(registry, \"hello\", :value)\n\n    assert Registry.register(registry, \"hello\", :other) ==\n             {:error, {:already_registered, task}}\n\n    :sys.suspend(owner)\n    kill_and_assert_down(task)\n    Registry.register(registry, \"hello\", :other)\n    assert Registry.lookup(registry, \"hello\") == [{self(), :other}]\n  end\n\n  test \"supports match patterns\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n    assert Registry.match(registry, \"hello\", {1, :_, :_}) == [{self(), value}]\n    assert Registry.match(registry, \"hello\", {1.0, :_, :_}) == []\n    assert Registry.match(registry, \"hello\", {:_, :atom, :_}) == [{self(), value}]\n    assert Registry.match(registry, \"hello\", {:\"$1\", :_, :\"$1\"}) == [{self(), value}]\n    assert Registry.match(registry, \"hello\", :_) == [{self(), value}]\n    assert Registry.match(registry, :_, :_) == []\n\n    value2 = %{a: \"a\", b: \"b\"}\n    {:ok, _} = Registry.register(registry, \"world\", value2)\n    assert Registry.match(registry, \"world\", %{b: \"b\"}) == [{self(), value2}]\n  end\n\n  test \"supports guard conditions\", %{registry: registry} do\n    value = {1, :atom, 2}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert Registry.match(registry, \"hello\", {:_, :_, :\"$1\"}, [{:>, :\"$1\", 1}]) ==\n             [{self(), value}]\n\n    assert Registry.match(registry, \"hello\", {:_, :_, :\"$1\"}, [{:>, :\"$1\", 2}]) == []\n\n    assert Registry.match(registry, \"hello\", {:_, :\"$1\", :_}, [{:is_atom, :\"$1\"}]) ==\n             [{self(), value}]\n  end\n\n  test \"count_match supports match patterns\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n    assert 1 == Registry.count_match(registry, \"hello\", {1, :_, :_})\n    assert 0 == Registry.count_match(registry, \"hello\", {1.0, :_, :_})\n    assert 1 == Registry.count_match(registry, \"hello\", {:_, :atom, :_})\n    assert 1 == Registry.count_match(registry, \"hello\", {:\"$1\", :_, :\"$1\"})\n    assert 1 == Registry.count_match(registry, \"hello\", :_)\n    assert 0 == Registry.count_match(registry, :_, :_)\n\n    value2 = %{a: \"a\", b: \"b\"}\n    {:ok, _} = Registry.register(registry, \"world\", value2)\n    assert 1 == Registry.count_match(registry, \"world\", %{b: \"b\"})\n  end\n\n  test \"count_match supports guard conditions\", %{registry: registry} do\n    value = {1, :atom, 2}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert 1 == Registry.count_match(registry, \"hello\", {:_, :_, :\"$1\"}, [{:>, :\"$1\", 1}])\n    assert 0 == Registry.count_match(registry, \"hello\", {:_, :_, :\"$1\"}, [{:>, :\"$1\", 2}])\n    assert 1 == Registry.count_match(registry, \"hello\", {:_, :\"$1\", :_}, [{:is_atom, :\"$1\"}])\n  end\n\n  test \"unregister_match supports patterns\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    Registry.unregister_match(registry, \"hello\", {2, :_, :_})\n    assert Registry.lookup(registry, \"hello\") == [{self(), value}]\n    Registry.unregister_match(registry, \"hello\", {1.0, :_, :_})\n    assert Registry.lookup(registry, \"hello\") == [{self(), value}]\n    Registry.unregister_match(registry, \"hello\", {:_, :atom, :_})\n    assert Registry.lookup(registry, \"hello\") == []\n  end\n\n  test \"unregister_match supports guards\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    Registry.unregister_match(registry, \"hello\", {:\"$1\", :_, :_}, [{:<, :\"$1\", 2}])\n    assert Registry.lookup(registry, \"hello\") == []\n  end\n\n  test \"unregister_match supports tricky keys\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, :_, :foo)\n    {:ok, _} = Registry.register(registry, \"hello\", \"b\")\n\n    Registry.unregister_match(registry, :_, :foo)\n    assert Registry.lookup(registry, :_) == []\n    assert Registry.keys(registry, self()) |> Enum.sort() == [\"hello\"]\n  end\n\n  test \"compares using ===\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, 1.0, :value)\n    {:ok, _} = Registry.register(registry, 1, :value)\n    assert Registry.keys(registry, self()) |> Enum.sort() == [1, 1.0]\n  end\n\n  test \"updates current process value\", %{registry: registry} do\n    assert Registry.update_value(registry, \"hello\", &raise/1) == :error\n    register_task(registry, \"hello\", :value)\n    assert Registry.update_value(registry, \"hello\", &raise/1) == :error\n\n    Registry.register(registry, \"world\", 1)\n    assert Registry.lookup(registry, \"world\") == [{self(), 1}]\n    assert Registry.update_value(registry, \"world\", &(&1 + 1)) == {2, 1}\n    assert Registry.lookup(registry, \"world\") == [{self(), 2}]\n  end\n\n  test \"dispatches to a single key\", %{registry: registry} do\n    fun = fn _ -> raise \"will never be invoked\" end\n    assert Registry.dispatch(registry, \"hello\", fun) == :ok\n\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n\n    fun = fn [{pid, value}] -> send(pid, {:dispatch, value}) end\n    assert Registry.dispatch(registry, \"hello\", fun)\n\n    assert_received {:dispatch, :value}\n  end\n\n  test \"unregisters process by key\", %{registry: registry} do\n    :ok = Registry.unregister(registry, \"hello\")\n\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n    assert Registry.keys(registry, self()) |> Enum.sort() == [\"hello\", \"world\"]\n\n    :ok = Registry.unregister(registry, \"hello\")\n    assert Registry.keys(registry, self()) == [\"world\"]\n\n    :ok = Registry.unregister(registry, \"world\")\n    assert Registry.keys(registry, self()) == []\n  end\n\n  test \"unregisters with no entries\", %{registry: registry} do\n    assert Registry.unregister(registry, \"hello\") == :ok\n  end\n\n  test \"unregisters with tricky keys\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, :_, :foo)\n    {:ok, _} = Registry.register(registry, \"hello\", \"b\")\n\n    Registry.unregister(registry, :_)\n    assert Registry.lookup(registry, :_) == []\n    assert Registry.keys(registry, self()) |> Enum.sort() == [\"hello\"]\n  end\n\n  @tag base_listener: :unique_listener\n  test \"allows listeners\", %{registry: registry, listeners: [listener]} do\n    Process.register(self(), listener)\n    {_, task} = register_task(registry, \"hello\", :world)\n    assert_received {:register, ^registry, \"hello\", ^task, :world}\n\n    self = self()\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n    assert_received {:register, ^registry, \"world\", ^self, :value}\n\n    :ok = Registry.unregister(registry, \"world\")\n    assert_received {:unregister, ^registry, \"world\", ^self}\n  after\n    Process.unregister(listener)\n  end\n\n  test \"links and unlinks on register/unregister\", %{registry: registry} do\n    {:ok, pid} = Registry.register(registry, \"hello\", :value)\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    {:ok, pid} = Registry.register(registry, \"world\", :value)\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    :ok = Registry.unregister(registry, \"hello\")\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    :ok = Registry.unregister(registry, \"world\")\n    {:links, links} = Process.info(self(), :links)\n    refute pid in links\n  end\n\n  test \"raises on unknown registry name\" do\n    assert_raise ArgumentError, ~r/unknown registry/, fn ->\n      Registry.register(:unknown, \"hello\", :value)\n    end\n  end\n\n  test \"via callbacks\", %{registry: registry} do\n    name = {:via, Registry, {registry, \"hello\"}}\n\n    # register_name\n    {:ok, pid} = Agent.start_link(fn -> 0 end, name: name)\n\n    # send\n    assert Agent.update(name, &(&1 + 1)) == :ok\n\n    # whereis_name\n    assert Agent.get(name, & &1) == 1\n\n    # unregister_name\n    assert {:error, _} = Agent.start(fn -> raise \"oops\" end)\n\n    # errors\n    assert {:error, {:already_started, ^pid}} = Agent.start(fn -> 0 end, name: name)\n  end\n\n  test \"uses value provided in via\", %{registry: registry} do\n    name = {:via, Registry, {registry, \"hello\", :value}}\n    {:ok, pid} = Agent.start_link(fn -> 0 end, name: name)\n    assert Registry.lookup(registry, \"hello\") == [{pid, :value}]\n  end\n\n  test \"empty list for empty registry\", %{registry: registry} do\n    assert Registry.select(registry, [{{:_, :_, :_}, [], [:\"$_\"]}]) == []\n  end\n\n  test \"select all\", %{registry: registry} do\n    name = {:via, Registry, {registry, \"hello\"}}\n    {:ok, pid} = Agent.start_link(fn -> 0 end, name: name)\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n\n    assert Registry.select(registry, [{{:\"$1\", :\"$2\", :\"$3\"}, [], [{{:\"$1\", :\"$2\", :\"$3\"}}]}])\n           |> Enum.sort() ==\n             [{\"hello\", pid, nil}, {\"world\", self(), :value}]\n  end\n\n  test \"select supports full match specs\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert [{\"hello\", self(), value}] ==\n             Registry.select(registry, [\n               {{\"hello\", :\"$2\", :\"$3\"}, [], [{{\"hello\", :\"$2\", :\"$3\"}}]}\n             ])\n\n    assert [{\"hello\", self(), value}] ==\n             Registry.select(registry, [\n               {{:\"$1\", self(), :\"$3\"}, [], [{{:\"$1\", self(), :\"$3\"}}]}\n             ])\n\n    assert [{\"hello\", self(), value}] ==\n             Registry.select(registry, [\n               {{:\"$1\", :\"$2\", value}, [], [{{:\"$1\", :\"$2\", {value}}}]}\n             ])\n\n    assert [] ==\n             Registry.select(registry, [\n               {{\"world\", :\"$2\", :\"$3\"}, [], [{{\"world\", :\"$2\", :\"$3\"}}]}\n             ])\n\n    assert [] == Registry.select(registry, [{{:\"$1\", :\"$2\", {1.0, :_, :_}}, [], [:\"$_\"]}])\n\n    assert [{\"hello\", self(), value}] ==\n             Registry.select(registry, [\n               {{:\"$1\", :\"$2\", {:\"$3\", :atom, :\"$4\"}}, [],\n                [{{:\"$1\", :\"$2\", {{:\"$3\", :atom, :\"$4\"}}}}]}\n             ])\n\n    assert [{\"hello\", self(), {1, :atom, 1}}] ==\n             Registry.select(registry, [\n               {{:\"$1\", :\"$2\", {:\"$3\", :\"$4\", :\"$3\"}}, [],\n                [{{:\"$1\", :\"$2\", {{:\"$3\", :\"$4\", :\"$3\"}}}}]}\n             ])\n\n    value2 = %{a: \"a\", b: \"b\"}\n    {:ok, _} = Registry.register(registry, \"world\", value2)\n\n    assert [:match] ==\n             Registry.select(registry, [{{\"world\", self(), %{b: \"b\"}}, [], [:match]}])\n\n    assert [\"hello\", \"world\"] ==\n             Registry.select(registry, [{{:\"$1\", :_, :_}, [], [:\"$1\"]}]) |> Enum.sort()\n  end\n\n  test \"select supports guard conditions\", %{registry: registry} do\n    value = {1, :atom, 2}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert [{\"hello\", self(), {1, :atom, 2}}] ==\n             Registry.select(registry, [\n               {{:\"$1\", :\"$2\", {:\"$3\", :\"$4\", :\"$5\"}}, [{:>, :\"$5\", 1}],\n                [{{:\"$1\", :\"$2\", {{:\"$3\", :\"$4\", :\"$5\"}}}}]}\n             ])\n\n    assert [] ==\n             Registry.select(registry, [\n               {{:_, :_, {:_, :_, :\"$1\"}}, [{:>, :\"$1\", 2}], [:\"$_\"]}\n             ])\n\n    assert [\"hello\"] ==\n             Registry.select(registry, [\n               {{:\"$1\", :_, {:_, :\"$2\", :_}}, [{:is_atom, :\"$2\"}], [:\"$1\"]}\n             ])\n  end\n\n  test \"select allows multiple specs\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n\n    assert [\"hello\", \"world\"] ==\n             Registry.select(registry, [\n               {{\"hello\", :_, :_}, [], [{:element, 1, :\"$_\"}]},\n               {{\"world\", :_, :_}, [], [{:element, 1, :\"$_\"}]}\n             ])\n             |> Enum.sort()\n  end\n\n  test \"select raises on incorrect shape of match spec\", %{registry: registry} do\n    assert_raise ArgumentError, fn ->\n      Registry.select(registry, [{:_, [], []}])\n    end\n  end\n\n  test \"count_select supports match specs\", %{registry: registry} do\n    value = {1, :atom, 1}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n    assert 1 == Registry.count_select(registry, [{{:_, :_, value}, [], [true]}])\n    assert 1 == Registry.count_select(registry, [{{\"hello\", :_, :_}, [], [true]}])\n    assert 1 == Registry.count_select(registry, [{{:_, :_, {1, :atom, :_}}, [], [true]}])\n    assert 1 == Registry.count_select(registry, [{{:_, :_, {:\"$1\", :_, :\"$1\"}}, [], [true]}])\n    assert 0 == Registry.count_select(registry, [{{\"hello\", :_, nil}, [], [true]}])\n\n    value2 = %{a: \"a\", b: \"b\"}\n    {:ok, _} = Registry.register(registry, \"world\", value2)\n    assert 1 == Registry.count_select(registry, [{{\"world\", :_, :_}, [], [true]}])\n  end\n\n  test \"count_select supports guard conditions\", %{registry: registry} do\n    value = {1, :atom, 2}\n    {:ok, _} = Registry.register(registry, \"hello\", value)\n\n    assert 1 ==\n             Registry.count_select(registry, [\n               {{:_, :_, {:_, :\"$1\", :_}}, [{:is_atom, :\"$1\"}], [true]}\n             ])\n\n    assert 1 ==\n             Registry.count_select(registry, [\n               {{:_, :_, {:_, :_, :\"$1\"}}, [{:>, :\"$1\", 1}], [true]}\n             ])\n\n    assert 0 ==\n             Registry.count_select(registry, [\n               {{:_, :_, {:_, :_, :\"$1\"}}, [{:>, :\"$1\", 2}], [true]}\n             ])\n  end\n\n  test \"count_select allows multiple specs\", %{registry: registry} do\n    {:ok, _} = Registry.register(registry, \"hello\", :value)\n    {:ok, _} = Registry.register(registry, \"world\", :value)\n\n    assert 2 ==\n             Registry.count_select(registry, [\n               {{\"hello\", :_, :_}, [], [true]},\n               {{\"world\", :_, :_}, [], [true]}\n             ])\n  end\n\n  test \"count_select raises on incorrect shape of match spec\", %{registry: registry} do\n    assert_raise ArgumentError, fn ->\n      Registry.count_select(registry, [{:_, [], []}])\n    end\n  end\n\n  test \"doesn't grow ets on already_registered\",\n       %{registry: registry, partitions: partitions} do\n    assert sum_pid_entries(registry, partitions) == 0\n\n    {:ok, pid} = Registry.register(registry, \"hello\", :value)\n    assert is_pid(pid)\n    assert sum_pid_entries(registry, partitions) == 1\n\n    {:ok, pid} = Registry.register(registry, \"world\", :value)\n    assert is_pid(pid)\n    assert sum_pid_entries(registry, partitions) == 2\n\n    assert {:error, {:already_registered, _pid}} =\n             Registry.register(registry, \"hello\", :value)\n\n    assert sum_pid_entries(registry, partitions) == 2\n  end\n\n  test \"doesn't grow ets on already_registered across processes\",\n       %{registry: registry, partitions: partitions} do\n    assert sum_pid_entries(registry, partitions) == 0\n\n    {_, task} = register_task(registry, \"hello\", :value)\n    Process.link(Process.whereis(registry))\n\n    assert sum_pid_entries(registry, partitions) == 1\n\n    {:ok, pid} = Registry.register(registry, \"world\", :value)\n    assert is_pid(pid)\n    assert sum_pid_entries(registry, partitions) == 2\n\n    assert {:error, {:already_registered, ^task}} =\n             Registry.register(registry, \"hello\", :recent)\n\n    assert sum_pid_entries(registry, partitions) == 2\n  end\n\n  defp register_task(registry, key, value) do\n    parent = self()\n\n    {:ok, task} =\n      Task.start(fn ->\n        send(parent, Registry.register(registry, key, value))\n        Process.sleep(:infinity)\n      end)\n\n    assert_receive {:ok, owner}\n    {owner, task}\n  end\n\n  defp kill_and_assert_down(pid) do\n    ref = Process.monitor(pid)\n    Process.exit(pid, :kill)\n    assert_receive {:DOWN, ^ref, _, _, _}\n  end\n\n  defp sum_pid_entries(registry, partitions) do\n    Enum.sum_by(0..(partitions - 1), fn partition ->\n      registry\n      |> Module.concat(\"PIDPartition#{partition}\")\n      |> ets_entries()\n    end)\n  end\n\n  defp ets_entries(table_name) do\n    :ets.all()\n    |> Enum.find_value(fn id -> :ets.info(id, :name) == table_name and :ets.info(id, :size) end)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/registry_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule Registry.CommonTest do\n  use ExUnit.Case, async: true\n  doctest Registry, except: [:moduledoc]\nend\n\ndefmodule Registry.Test do\n  use ExUnit.Case,\n    async: true,\n    parameterize:\n      for(\n        keys <- [:unique, :duplicate, {:duplicate, :pid}, {:duplicate, :key}],\n        partitions <- [1, 8],\n        do: %{keys: keys, partitions: partitions}\n      )\n\n  setup config do\n    keys = config.keys || :unique\n    partitions = config.partitions\n\n    listeners =\n      List.wrap(config[:base_listener]) |> Enum.map(&:\"#{&1}_#{partitions}_#{inspect(keys)}\")\n\n    name = :\"#{config.test}_#{partitions}_#{inspect(keys)}\"\n    opts = [keys: keys, name: name, partitions: partitions, listeners: listeners]\n    {:ok, _} = start_supervised({Registry, opts})\n    %{registry: name, listeners: listeners}\n  end\n\n  # Note: those tests relies on internals\n  test \"clean up registry on process crash\",\n       %{registry: registry, partitions: partitions} do\n    {_, task1} = register_task(registry, \"hello\", :value)\n    {_, task2} = register_task(registry, \"world\", :value)\n\n    kill_and_assert_down(task1)\n    kill_and_assert_down(task2)\n\n    # pid might be in different partition to key so need to sync with all\n    # partitions before checking ETS tables are empty.\n    if partitions > 1 do\n      for i <- 0..(partitions - 1) do\n        [{_, _, {partition, _}}] = :ets.lookup(registry, i)\n        GenServer.call(partition, :sync)\n      end\n\n      for i <- 0..(partitions - 1) do\n        [{_, key, {_, pid}}] = :ets.lookup(registry, i)\n        assert :ets.tab2list(key) == []\n        assert :ets.tab2list(pid) == []\n      end\n    else\n      [{-1, {_, _, key, {partition, pid}, _}}] = :ets.lookup(registry, -1)\n      GenServer.call(partition, :sync)\n      assert :ets.tab2list(key) == []\n      assert :ets.tab2list(pid) == []\n    end\n  end\n\n  defp register_task(registry, key, value) do\n    parent = self()\n\n    {:ok, task} =\n      Task.start(fn ->\n        send(parent, Registry.register(registry, key, value))\n        Process.sleep(:infinity)\n      end)\n\n    assert_receive {:ok, owner}\n    {owner, task}\n  end\n\n  defp kill_and_assert_down(pid) do\n    ref = Process.monitor(pid)\n    Process.exit(pid, :kill)\n    assert_receive {:DOWN, ^ref, _, _, _}\n  end\nend\n\ndefmodule Registry.LockTest do\n  use ExUnit.Case,\n    async: true,\n    parameterize: [\n      %{keys: :unique, partitions: 1},\n      %{keys: :unique, partitions: 8},\n      %{keys: :duplicate, partitions: 1},\n      %{keys: :duplicate, partitions: 8}\n    ]\n\n  setup config do\n    keys = config.keys\n    partitions = config.partitions\n    name = :\"#{config.test}_#{keys}_#{partitions}\"\n    opts = [keys: keys, name: name, partitions: partitions]\n    {:ok, _} = start_supervised({Registry, opts})\n    %{registry: name}\n  end\n\n  test \"does not lock when using different keys\", config do\n    parent = self()\n\n    task1 =\n      Task.async(fn ->\n        Registry.lock(config.registry, 1, fn ->\n          send(parent, :locked1)\n          assert_receive :unlock\n          :done\n        end)\n      end)\n\n    assert_receive :locked1\n\n    task2 =\n      Task.async(fn ->\n        Registry.lock(config.registry, 2, fn ->\n          send(parent, :locked2)\n          assert_receive :unlock\n          :done\n        end)\n      end)\n\n    assert_receive :locked2\n\n    send(task1.pid, :unlock)\n    send(task2.pid, :unlock)\n    assert Task.await(task1) == :done\n    assert Task.await(task2) == :done\n    assert Registry.lock(config.registry, 1, fn -> :done end) == :done\n    assert Registry.lock(config.registry, 2, fn -> :done end) == :done\n  end\n\n  test \"locks when using the same key\", config do\n    parent = self()\n\n    task1 =\n      Task.async(fn ->\n        Registry.lock(config.registry, :ok, fn ->\n          send(parent, :locked1)\n          assert_receive :unlock\n          :done\n        end)\n      end)\n\n    assert_receive :locked1\n\n    task2 =\n      Task.async(fn ->\n        Registry.lock(config.registry, :ok, fn ->\n          send(parent, :locked2)\n          :done\n        end)\n      end)\n\n    refute_receive :locked2, 100\n\n    send(task1.pid, :unlock)\n    assert Task.await(task1) == :done\n    assert_receive :locked2\n    assert Task.await(task2) == :done\n    assert Registry.lock(config.registry, :ok, fn -> :done end) == :done\n  end\n\n  @tag :capture_log\n  test \"locks when the one holding the lock raises\", config do\n    parent = self()\n\n    task1 =\n      Task.async(fn ->\n        Registry.lock(config.registry, :ok, fn ->\n          send(parent, :locked)\n          assert_receive :unlock\n          raise \"oops\"\n        end)\n      end)\n\n    Process.unlink(task1.pid)\n    assert_receive :locked\n\n    task2 =\n      Task.async(fn ->\n        Registry.lock(config.registry, :ok, fn ->\n          :done\n        end)\n      end)\n\n    send(task1.pid, :unlock)\n    assert {:exit, {%RuntimeError{message: \"oops\"}, [_ | _]}} = Task.yield(task1)\n    assert Task.await(task2) == :done\n    assert Registry.lock(config.registry, :ok, fn -> :done end) == :done\n  end\n\n  test \"locks when the one holding the lock terminates\", config do\n    parent = self()\n\n    task1 =\n      Task.async(fn ->\n        Registry.lock(config.registry, :ok, fn ->\n          send(parent, :locked)\n          assert_receive :unlock\n          :done\n        end)\n      end)\n\n    assert_receive :locked\n\n    task2 =\n      Task.async(fn ->\n        Registry.lock(config.registry, :ok, fn ->\n          :done\n        end)\n      end)\n\n    assert Task.shutdown(task1, :brutal_kill) == nil\n    assert Task.await(task2) == :done\n    assert Registry.lock(config.registry, :ok, fn -> :done end) == :done\n  end\n\n  test \"locks when the one waiting for the lock terminates\", config do\n    parent = self()\n\n    task1 =\n      Task.async(fn ->\n        Registry.lock(config.registry, :ok, fn ->\n          send(parent, :locked)\n          assert_receive :unlock\n          :done\n        end)\n      end)\n\n    assert_receive :locked\n\n    task2 =\n      Task.async(fn ->\n        Registry.lock(config.registry, :ok, fn ->\n          :done\n        end)\n      end)\n\n    :erlang.yield()\n    assert Task.shutdown(task2, :brutal_kill) == nil\n\n    send(task1.pid, :unlock)\n    assert Task.await(task1) == :done\n    assert Registry.lock(config.registry, :ok, fn -> :done end) == :done\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/stream_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule StreamTest do\n  use ExUnit.Case, async: true\n\n  doctest Stream\n\n  defmodule Pdict do\n    defstruct []\n\n    defimpl Collectable do\n      def into(struct) do\n        fun = fn\n          _, {:cont, x} -> Process.put(:stream_cont, [x | Process.get(:stream_cont)])\n          _, :done -> Process.put(:stream_done, true)\n          _, :halt -> Process.put(:stream_halt, true)\n        end\n\n        {struct, fun}\n      end\n    end\n  end\n\n  defmodule HaltAcc do\n    defstruct [:acc]\n\n    defimpl Enumerable do\n      def count(_lazy), do: {:error, __MODULE__}\n\n      def member?(_lazy, _value), do: {:error, __MODULE__}\n\n      def slice(_lazy), do: {:error, __MODULE__}\n\n      def reduce(lazy, _acc, _fun) do\n        {:halted, Enum.to_list(lazy.acc)}\n      end\n    end\n  end\n\n  test \"streams as enumerables\" do\n    stream = Stream.map([1, 2, 3], &(&1 * 2))\n\n    # Reduce\n    assert Enum.map(stream, &(&1 + 1)) == [3, 5, 7]\n    # Member\n    assert Enum.member?(stream, 4)\n    refute Enum.member?(stream, 1)\n    # Count\n    assert Enum.count(stream) == 3\n  end\n\n  test \"streams are composable\" do\n    stream = Stream.map([1, 2, 3], &(&1 * 2))\n    assert lazy?(stream)\n\n    stream = Stream.map(stream, &(&1 + 1))\n    assert lazy?(stream)\n\n    assert Enum.to_list(stream) == [3, 5, 7]\n  end\n\n  test \"chunk_every/2, chunk_every/3 and chunk_every/4\" do\n    assert Stream.chunk_every([1, 2, 3, 4, 5], 2) |> Enum.to_list() == [[1, 2], [3, 4], [5]]\n\n    assert Stream.chunk_every([1, 2, 3, 4, 5], 2, 2, [6]) |> Enum.to_list() ==\n             [[1, 2], [3, 4], [5, 6]]\n\n    assert Stream.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, :discard) |> Enum.to_list() ==\n             [[1, 2, 3], [3, 4, 5]]\n\n    assert Stream.chunk_every([1, 2, 3, 4, 5, 6], 2, 3, :discard) |> Enum.to_list() ==\n             [[1, 2], [4, 5]]\n\n    assert Stream.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, []) |> Enum.to_list() ==\n             [[1, 2, 3], [3, 4, 5], [5, 6]]\n\n    assert Stream.chunk_every([1, 2, 3, 4, 5, 6], 3, 3, []) |> Enum.to_list() ==\n             [[1, 2, 3], [4, 5, 6]]\n\n    assert Stream.chunk_every([1, 2, 3, 4, 5], 4, 4, 6..10) |> Enum.to_list() ==\n             [[1, 2, 3, 4], [5, 6, 7, 8]]\n  end\n\n  test \"chunk_every/4 is zippable\" do\n    stream = Stream.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, [])\n    list = Enum.to_list(stream)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n  end\n\n  test \"chunk_every/4 is haltable\" do\n    assert 1..10 |> Stream.take(6) |> Stream.chunk_every(4, 4, [7, 8]) |> Enum.to_list() ==\n             [[1, 2, 3, 4], [5, 6, 7, 8]]\n\n    assert 1..10\n           |> Stream.take(6)\n           |> Stream.chunk_every(4, 4, [7, 8])\n           |> Stream.take(3)\n           |> Enum.to_list() == [[1, 2, 3, 4], [5, 6, 7, 8]]\n\n    assert 1..10\n           |> Stream.take(6)\n           |> Stream.chunk_every(4, 4, [7, 8])\n           |> Stream.take(2)\n           |> Enum.to_list() == [[1, 2, 3, 4], [5, 6, 7, 8]]\n\n    assert 1..10\n           |> Stream.take(6)\n           |> Stream.chunk_every(4, 4, [7, 8])\n           |> Stream.take(1)\n           |> Enum.to_list() == [[1, 2, 3, 4]]\n\n    assert 1..6 |> Stream.take(6) |> Stream.chunk_every(4, 4, [7, 8]) |> Enum.to_list() ==\n             [[1, 2, 3, 4], [5, 6, 7, 8]]\n  end\n\n  test \"chunk_by/2\" do\n    stream = Stream.chunk_by([1, 2, 2, 3, 4, 4, 6, 7, 7], &(rem(&1, 2) == 1))\n\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [[1], [2, 2], [3], [4, 4, 6], [7, 7]]\n    assert stream |> Stream.take(3) |> Enum.to_list() == [[1], [2, 2], [3]]\n    assert 1..10 |> Stream.chunk_every(2) |> Enum.take(2) == [[1, 2], [3, 4]]\n  end\n\n  test \"chunk_by/2 is zippable\" do\n    stream = Stream.chunk_by([1, 2, 2, 3], &(rem(&1, 2) == 1))\n    list = Enum.to_list(stream)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n  end\n\n  test \"chunk_while/4\" do\n    chunk_fun = fn i, acc ->\n      cond do\n        i > 10 -> {:halt, acc}\n        rem(i, 2) == 0 -> {:cont, Enum.reverse([i | acc]), []}\n        true -> {:cont, [i | acc]}\n      end\n    end\n\n    after_fun = fn\n      [] -> {:cont, []}\n      acc -> {:cont, Enum.reverse(acc), []}\n    end\n\n    assert Stream.chunk_while([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [], chunk_fun, after_fun)\n           |> Enum.to_list() == [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]\n\n    assert Stream.chunk_while(0..9, [], chunk_fun, after_fun) |> Enum.to_list() ==\n             [[0], [1, 2], [3, 4], [5, 6], [7, 8], [9]]\n\n    assert Stream.chunk_while(0..10, [], chunk_fun, after_fun) |> Enum.to_list() ==\n             [[0], [1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]\n\n    assert Stream.chunk_while(0..11, [], chunk_fun, after_fun) |> Enum.to_list() ==\n             [[0], [1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]\n\n    assert Stream.chunk_while([5, 7, 9, 11], [], chunk_fun, after_fun) |> Enum.to_list() ==\n             [[5, 7, 9]]\n  end\n\n  test \"chunk_while/4 with inner halt\" do\n    chunk_fun = fn\n      i, [] ->\n        {:cont, [i]}\n\n      i, chunk ->\n        if rem(i, 2) == 0 do\n          {:cont, Enum.reverse(chunk), [i]}\n        else\n          {:cont, [i | chunk]}\n        end\n    end\n\n    after_fun = fn\n      [] -> {:cont, []}\n      chunk -> {:cont, Enum.reverse(chunk), []}\n    end\n\n    assert Stream.chunk_while([1, 2, 3, 4, 5], [], chunk_fun, after_fun) |> Enum.at(0) == [1]\n  end\n\n  test \"chunk_while/4 regression case with concat\" do\n    result =\n      [\"WrongHeader\\nJohn Doe\", \"skipped\"]\n      |> Stream.take(1)\n      |> Stream.chunk_while(\n        \"\",\n        fn element, acc ->\n          {acc, elements} = String.split(acc <> element, \"\\n\") |> List.pop_at(-1)\n          {:cont, elements, acc}\n        end,\n        &{:cont, [&1], []}\n      )\n      |> Stream.concat()\n      |> Enum.to_list()\n\n    assert result == [\"WrongHeader\", \"John Doe\"]\n  end\n\n  test \"concat/1\" do\n    stream = Stream.concat([1..3, [], [4, 5, 6], [], 7..9])\n    assert is_function(stream)\n\n    assert Enum.to_list(stream) == [1, 2, 3, 4, 5, 6, 7, 8, 9]\n    assert Enum.take(stream, 5) == [1, 2, 3, 4, 5]\n\n    stream = Stream.concat([1..3, [4, 5, 6], Stream.cycle(7..100)])\n    assert is_function(stream)\n\n    assert Enum.take(stream, 13) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]\n  end\n\n  test \"concat/2\" do\n    stream = Stream.concat(1..3, 4..6)\n    assert is_function(stream)\n\n    assert Stream.cycle(stream) |> Enum.take(16) ==\n             [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4]\n\n    stream = Stream.concat(1..3, [])\n    assert is_function(stream)\n    assert Stream.cycle(stream) |> Enum.take(5) == [1, 2, 3, 1, 2]\n\n    stream = Stream.concat(1..6, Stream.cycle(7..9))\n    assert is_function(stream)\n    assert Stream.drop(stream, 3) |> Enum.take(13) == [4, 5, 6, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7]\n\n    stream = Stream.concat(Stream.cycle(1..3), Stream.cycle(4..6))\n    assert is_function(stream)\n    assert Enum.take(stream, 13) == [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1]\n  end\n\n  test \"concat/2 is zippable\" do\n    stream = 1..2 |> Stream.take(2) |> Stream.concat(3..4)\n    assert Enum.zip(1..4, [1, 2, 3, 4]) == Enum.zip(1..4, stream)\n  end\n\n  test \"concat/2 does not intercept wrapped lazy enumeration\" do\n    # concat returns a lazy enumeration that does not halt\n    assert Stream.concat([[0], Stream.map([1, 2, 3], & &1), [4]])\n           |> Stream.take_while(fn x -> x <= 4 end)\n           |> Enum.to_list() == [0, 1, 2, 3, 4]\n\n    # concat returns a lazy enumeration that does halts\n    assert Stream.concat([[0], Stream.take_while(1..6, &(&1 <= 3)), [4]])\n           |> Stream.take_while(fn x -> x <= 4 end)\n           |> Enum.to_list() == [0, 1, 2, 3, 4]\n  end\n\n  test \"cycle/1\" do\n    stream = Stream.cycle([1, 2, 3])\n    assert is_function(stream)\n\n    assert_raise ArgumentError, \"cannot cycle over an empty enumerable\", fn ->\n      Stream.cycle([])\n    end\n\n    assert_raise ArgumentError, \"cannot cycle over an empty enumerable\", fn ->\n      Stream.cycle(%{}) |> Enum.to_list()\n    end\n\n    assert Stream.cycle([1, 2, 3]) |> Stream.take(5) |> Enum.to_list() == [1, 2, 3, 1, 2]\n    assert Enum.take(stream, 5) == [1, 2, 3, 1, 2]\n  end\n\n  test \"cycle/1 is zippable\" do\n    stream = Stream.cycle([1, 2, 3])\n    assert Enum.zip(1..6, [1, 2, 3, 1, 2, 3]) == Enum.zip(1..6, stream)\n  end\n\n  test \"cycle/1 with inner stream\" do\n    assert [1, 2, 3] |> Stream.take(2) |> Stream.cycle() |> Enum.take(4) == [1, 2, 1, 2]\n  end\n\n  test \"cycle/1 with cycle/1 with cycle/1\" do\n    assert [1] |> Stream.cycle() |> Stream.cycle() |> Stream.cycle() |> Enum.take(5) ==\n             [1, 1, 1, 1, 1]\n  end\n\n  test \"dedup/1 is lazy\" do\n    assert lazy?(Stream.dedup([1, 2, 3]))\n  end\n\n  test \"dedup/1\" do\n    assert Stream.dedup([1, 1, 2, 1, 1, 2, 1]) |> Enum.to_list() == [1, 2, 1, 2, 1]\n    assert Stream.dedup([2, 1, 1, 2, 1]) |> Enum.to_list() == [2, 1, 2, 1]\n    assert Stream.dedup([1, 2, 3, 4]) |> Enum.to_list() == [1, 2, 3, 4]\n    assert Stream.dedup([1, 1.0, 2.0, 2]) |> Enum.to_list() == [1, 1.0, 2.0, 2]\n    assert Stream.dedup([]) |> Enum.to_list() == []\n\n    assert Stream.dedup([nil, nil, true, {:value, true}]) |> Enum.to_list() ==\n             [nil, true, {:value, true}]\n\n    assert Stream.dedup([nil]) |> Enum.to_list() == [nil]\n  end\n\n  test \"dedup_by/2\" do\n    assert Stream.dedup_by([{1, :x}, {2, :y}, {2, :z}, {1, :x}], fn {x, _} -> x end)\n           |> Enum.to_list() == [{1, :x}, {2, :y}, {1, :x}]\n  end\n\n  test \"drop/2\" do\n    stream = Stream.drop(1..10, 5)\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [6, 7, 8, 9, 10]\n\n    assert Enum.to_list(Stream.drop(1..5, 0)) == [1, 2, 3, 4, 5]\n    assert Enum.to_list(Stream.drop(1..3, 5)) == []\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Stream.drop(nats, 2) |> Enum.take(5) == [3, 4, 5, 6, 7]\n  end\n\n  test \"drop/2 with negative count\" do\n    stream = Stream.drop(1..10, -5)\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 2, 3, 4, 5]\n\n    stream = Stream.drop(1..10, -5)\n    list = Enum.to_list(stream)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n  end\n\n  test \"drop/2 with negative count stream entries\" do\n    par = self()\n\n    pid =\n      spawn_link(fn ->\n        Enum.each(Stream.drop(&inbox_stream/2, -3), fn x -> send(par, {:stream, x}) end)\n      end)\n\n    send(pid, {:stream, 1})\n    send(pid, {:stream, 2})\n    send(pid, {:stream, 3})\n    refute_receive {:stream, 1}, 100\n\n    send(pid, {:stream, 4})\n    assert_receive {:stream, 1}\n\n    send(pid, {:stream, 5})\n    assert_receive {:stream, 2}\n    refute_receive {:stream, 3}, 100\n  end\n\n  test \"drop_every/2\" do\n    assert 1..10\n           |> Stream.drop_every(2)\n           |> Enum.to_list() == [2, 4, 6, 8, 10]\n\n    assert 1..10\n           |> Stream.drop_every(3)\n           |> Enum.to_list() == [2, 3, 5, 6, 8, 9]\n\n    assert 1..10\n           |> Stream.drop(2)\n           |> Stream.drop_every(2)\n           |> Stream.drop(1)\n           |> Enum.to_list() == [6, 8, 10]\n\n    assert 1..10\n           |> Stream.drop_every(0)\n           |> Enum.to_list() == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n    assert []\n           |> Stream.drop_every(10)\n           |> Enum.to_list() == []\n  end\n\n  test \"drop_every/2 with negative integer\" do\n    assert_raise FunctionClauseError, fn ->\n      Stream.drop_every(1..10, -1)\n    end\n  end\n\n  test \"drop_while/2\" do\n    stream = Stream.drop_while(1..10, &(&1 <= 5))\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [6, 7, 8, 9, 10]\n\n    assert Enum.to_list(Stream.drop_while(1..5, &(&1 <= 0))) == [1, 2, 3, 4, 5]\n    assert Enum.to_list(Stream.drop_while(1..3, &(&1 <= 5))) == []\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Stream.drop_while(nats, &(&1 <= 5)) |> Enum.take(5) == [6, 7, 8, 9, 10]\n  end\n\n  test \"duplicate/2\" do\n    stream = Stream.duplicate(7, 7)\n\n    assert is_function(stream)\n    assert stream |> Stream.take(5) |> Enum.to_list() == [7, 7, 7, 7, 7]\n    assert Enum.to_list(stream) == [7, 7, 7, 7, 7, 7, 7]\n  end\n\n  test \"each/2\" do\n    Process.put(:stream_each, [])\n\n    stream =\n      Stream.each([1, 2, 3], fn x ->\n        Process.put(:stream_each, [x | Process.get(:stream_each)])\n      end)\n\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 2, 3]\n    assert Process.get(:stream_each) == [3, 2, 1]\n  end\n\n  test \"filter/2\" do\n    stream = Stream.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end)\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [2]\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Stream.filter(nats, &(rem(&1, 2) == 0)) |> Enum.take(5) == [2, 4, 6, 8, 10]\n  end\n\n  test \"flat_map/2\" do\n    stream = Stream.flat_map([1, 2, 3], &[&1, &1 * 2])\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 2, 2, 4, 3, 6]\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Stream.flat_map(nats, &[&1, &1 * 2]) |> Enum.take(6) == [1, 2, 2, 4, 3, 6]\n  end\n\n  test \"flat_map/2 does not intercept wrapped lazy enumeration\" do\n    # flat_map returns a lazy enumeration that does not halt\n    assert [1, 2, 3, -1, -2]\n           |> Stream.flat_map(fn x -> Stream.map([x, x + 1], & &1) end)\n           |> Stream.take_while(fn x -> x >= 0 end)\n           |> Enum.to_list() == [1, 2, 2, 3, 3, 4]\n\n    # flat_map returns a lazy enumeration that does halts\n    assert [1, 2, 3, -1, -2]\n           |> Stream.flat_map(fn x -> Stream.take_while([x, x + 1, x + 2], &(&1 <= x + 1)) end)\n           |> Stream.take_while(fn x -> x >= 0 end)\n           |> Enum.to_list() == [1, 2, 2, 3, 3, 4]\n\n    # flat_map returns a lazy enumeration that does halts wrapped in an enumerable\n    assert [1, 2, 3, -1, -2]\n           |> Stream.flat_map(fn x ->\n             Stream.concat([x], Stream.take_while([x + 1, x + 2], &(&1 <= x + 1)))\n           end)\n           |> Stream.take_while(fn x -> x >= 0 end)\n           |> Enum.to_list() == [1, 2, 2, 3, 3, 4]\n  end\n\n  test \"flat_map/2 is zippable\" do\n    stream =\n      [1, 2, 3, -1, -2]\n      |> Stream.flat_map(fn x -> Stream.map([x, x + 1], & &1) end)\n      |> Stream.take_while(fn x -> x >= 0 end)\n\n    list = Enum.to_list(stream)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n  end\n\n  test \"flat_map/2 does not leave inner stream suspended\" do\n    stream =\n      Stream.flat_map([1, 2, 3], fn i ->\n        Stream.resource(fn -> i end, fn acc -> {[acc], acc + 1} end, fn _ ->\n          Process.put(:stream_flat_map, true)\n        end)\n      end)\n\n    Process.put(:stream_flat_map, false)\n    assert stream |> Enum.take(3) == [1, 2, 3]\n    assert Process.get(:stream_flat_map)\n  end\n\n  test \"flat_map/2 does not leave outer stream suspended\" do\n    stream =\n      Stream.resource(fn -> 1 end, fn acc -> {[acc], acc + 1} end, fn _ ->\n        Process.put(:stream_flat_map, true)\n      end)\n\n    stream = Stream.flat_map(stream, fn i -> [i, i + 1, i + 2] end)\n\n    Process.put(:stream_flat_map, false)\n    assert stream |> Enum.take(3) == [1, 2, 3]\n    assert Process.get(:stream_flat_map)\n  end\n\n  test \"flat_map/2 closes on error\" do\n    stream =\n      Stream.resource(fn -> 1 end, fn acc -> {[acc], acc + 1} end, fn _ ->\n        Process.put(:stream_flat_map, true)\n      end)\n\n    stream = Stream.flat_map(stream, fn _ -> throw(:error) end)\n\n    Process.put(:stream_flat_map, false)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_flat_map)\n  end\n\n  test \"flat_map/2 with inner flat_map/2\" do\n    stream =\n      Stream.flat_map(1..5, fn x ->\n        Stream.flat_map([x], fn x ->\n          x..(x * x)\n        end)\n        |> Stream.map(&(&1 * 1))\n      end)\n\n    assert Enum.take(stream, 5) == [1, 2, 3, 4, 3]\n  end\n\n  test \"flat_map/2 properly halts both inner and outer stream when inner stream is halted\" do\n    # Fixes a bug that, when the inner stream was done,\n    # sending it a halt would cause it to return the\n    # inner stream was halted, forcing flat_map to get\n    # the next value from the outer stream, evaluate it,\n    # get another inner stream, just to halt it.\n    # 2 should never be used\n    assert [1, 2]\n           |> Stream.flat_map(fn 1 -> Stream.repeatedly(fn -> 1 end) end)\n           |> Stream.flat_map(fn 1 -> Stream.repeatedly(fn -> 1 end) end)\n           |> Enum.take(1) == [1]\n  end\n\n  test \"interval/1\" do\n    stream = Stream.interval(10)\n    {time_us, value} = :timer.tc(fn -> Enum.take(stream, 5) end)\n\n    assert value == [0, 1, 2, 3, 4]\n    assert time_us >= 50000\n  end\n\n  test \"interval/1 with infinity\" do\n    stream = Stream.interval(:infinity)\n    spawn(Stream, :run, [stream])\n  end\n\n  test \"into/2 and run/1\" do\n    Process.put(:stream_cont, [])\n    Process.put(:stream_done, false)\n    Process.put(:stream_halt, false)\n\n    stream = Stream.into([1, 2, 3], %Pdict{})\n\n    assert lazy?(stream)\n    assert Stream.run(stream) == :ok\n    assert Process.get(:stream_cont) == [3, 2, 1]\n    assert Process.get(:stream_done)\n    refute Process.get(:stream_halt)\n\n    stream = Stream.into(fn _, _ -> raise \"error\" end, %Pdict{})\n    catch_error(Stream.run(stream))\n    assert Process.get(:stream_halt)\n  end\n\n  test \"into/3\" do\n    Process.put(:stream_cont, [])\n    Process.put(:stream_done, false)\n    Process.put(:stream_halt, false)\n\n    stream = Stream.into([1, 2, 3], %Pdict{}, fn x -> x * 2 end)\n\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 2, 3]\n    assert Process.get(:stream_cont) == [6, 4, 2]\n    assert Process.get(:stream_done)\n    refute Process.get(:stream_halt)\n  end\n\n  test \"into/2 with halting\" do\n    Process.put(:stream_cont, [])\n    Process.put(:stream_done, false)\n    Process.put(:stream_halt, false)\n\n    stream = Stream.into([1, 2, 3], %Pdict{})\n\n    assert lazy?(stream)\n    assert Enum.take(stream, 1) == [1]\n    assert Process.get(:stream_cont) == [1]\n    assert Process.get(:stream_done)\n    refute Process.get(:stream_halt)\n  end\n\n  test \"transform/3\" do\n    stream = Stream.transform([1, 2, 3], 0, &{[&1, &2], &1 + &2})\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 0, 2, 1, 3, 3]\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Stream.transform(nats, 0, &{[&1, &2], &1 + &2}) |> Enum.take(6) == [1, 0, 2, 1, 3, 3]\n  end\n\n  test \"transform/3 with early halt\" do\n    stream =\n      fn -> throw(:error) end\n      |> Stream.repeatedly()\n      |> Stream.transform(nil, &{[&1, &2], &1})\n\n    assert {:halted, nil} = Enumerable.reduce(stream, {:halt, nil}, fn _, _ -> throw(:error) end)\n  end\n\n  test \"transform/3 with early suspend\" do\n    stream =\n      Stream.repeatedly(fn -> throw(:error) end)\n      |> Stream.transform(nil, &{[&1, &2], &1})\n\n    assert {:suspended, nil, _} =\n             Enumerable.reduce(stream, {:suspend, nil}, fn _, _ -> throw(:error) end)\n  end\n\n  test \"transform/3 with halt\" do\n    stream =\n      Stream.resource(fn -> 1 end, fn acc -> {[acc], acc + 1} end, fn _ ->\n        Process.put(:stream_transform, true)\n      end)\n\n    stream =\n      Stream.transform(stream, 0, fn i, acc ->\n        if acc < 3, do: {[i], acc + 1}, else: {:halt, acc}\n      end)\n\n    Process.put(:stream_transform, false)\n    assert Enum.to_list(stream) == [1, 2, 3]\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/3 (via flat_map) handles multiple returns from suspension\" do\n    assert [false]\n           |> Stream.take(1)\n           |> Stream.concat([true])\n           |> Stream.flat_map(&[&1])\n           |> Enum.to_list() == [false, true]\n  end\n\n  test \"iterate/2\" do\n    stream = Stream.iterate(0, &(&1 + 2))\n    assert Enum.take(stream, 5) == [0, 2, 4, 6, 8]\n    stream = Stream.iterate(5, &(&1 + 2))\n    assert Enum.take(stream, 5) == [5, 7, 9, 11, 13]\n\n    # Only calculate values if needed\n    stream = Stream.iterate(\"HELLO\", &raise/1)\n    assert Enum.take(stream, 1) == [\"HELLO\"]\n  end\n\n  test \"map/2\" do\n    stream = Stream.map([1, 2, 3], &(&1 * 2))\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [2, 4, 6]\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Stream.map(nats, &(&1 * 2)) |> Enum.take(5) == [2, 4, 6, 8, 10]\n    assert Stream.map(nats, &(&1 - 2)) |> Stream.map(&(&1 * 2)) |> Enum.take(3) == [-2, 0, 2]\n  end\n\n  test \"map_every/3\" do\n    assert 1..10\n           |> Stream.map_every(2, &(&1 * 2))\n           |> Enum.to_list() == [2, 2, 6, 4, 10, 6, 14, 8, 18, 10]\n\n    assert 1..10\n           |> Stream.map_every(3, &(&1 * 2))\n           |> Enum.to_list() == [2, 2, 3, 8, 5, 6, 14, 8, 9, 20]\n\n    assert 1..10\n           |> Stream.drop(2)\n           |> Stream.map_every(2, &(&1 * 2))\n           |> Stream.drop(1)\n           |> Enum.to_list() == [4, 10, 6, 14, 8, 18, 10]\n\n    assert 1..5\n           |> Stream.map_every(0, &(&1 * 2))\n           |> Enum.to_list() == [1, 2, 3, 4, 5]\n\n    assert []\n           |> Stream.map_every(10, &(&1 * 2))\n           |> Enum.to_list() == []\n\n    assert_raise FunctionClauseError, fn ->\n      Stream.map_every(1..10, -1, &(&1 * 2))\n    end\n  end\n\n  test \"reject/2\" do\n    stream = Stream.reject([1, 2, 3], fn x -> rem(x, 2) == 0 end)\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 3]\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Stream.reject(nats, &(rem(&1, 2) == 0)) |> Enum.take(5) == [1, 3, 5, 7, 9]\n  end\n\n  test \"repeatedly/1\" do\n    stream = Stream.repeatedly(fn -> 1 end)\n    assert Enum.take(stream, 5) == [1, 1, 1, 1, 1]\n    stream = Stream.repeatedly(&:rand.uniform/0)\n    [r1, r2] = Enum.take(stream, 2)\n    assert r1 != r2\n  end\n\n  test \"resource/3 closes on outer errors\" do\n    stream =\n      Stream.resource(\n        fn -> 1 end,\n        fn\n          2 -> throw(:error)\n          acc -> {[acc], acc + 1}\n        end,\n        fn 2 -> Process.put(:stream_resource, true) end\n      )\n\n    Process.put(:stream_resource, false)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_resource)\n  end\n\n  test \"resource/3 closes with correct accumulator on outer errors with inner single-element list\" do\n    stream =\n      Stream.resource(\n        fn -> :start end,\n        fn _ -> {[:error], :end} end,\n        fn acc -> Process.put(:stream_resource, acc) end\n      )\n      |> Stream.map(fn :error -> throw(:error) end)\n\n    Process.put(:stream_resource, nil)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_resource) == :end\n  end\n\n  test \"resource/3 closes with correct accumulator on outer errors with inner list\" do\n    stream =\n      Stream.resource(\n        fn -> :start end,\n        fn _ -> {[:ok, :error], :end} end,\n        fn acc -> Process.put(:stream_resource, acc) end\n      )\n      |> Stream.map(fn acc -> if acc == :error, do: throw(:error), else: acc end)\n\n    Process.put(:stream_resource, nil)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_resource) == :end\n  end\n\n  test \"resource/3 closes with correct accumulator on outer errors with inner enum\" do\n    stream =\n      Stream.resource(\n        fn -> 1 end,\n        fn acc -> {acc..(acc + 2), acc + 1} end,\n        fn acc -> Process.put(:stream_resource, acc) end\n      )\n      |> Stream.map(fn x -> if x > 2, do: throw(:error), else: x end)\n\n    Process.put(:stream_resource, nil)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_resource) == 2\n  end\n\n  test \"resource/3 is zippable\" do\n    transform_fun = fn\n      10 -> {:halt, 10}\n      acc -> {[acc], acc + 1}\n    end\n\n    after_fun = fn _ -> Process.put(:stream_resource, true) end\n    stream = Stream.resource(fn -> 1 end, transform_fun, after_fun)\n\n    list = Enum.to_list(stream)\n    Process.put(:stream_resource, false)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n    assert Process.get(:stream_resource)\n  end\n\n  test \"resource/3 returning inner empty list\" do\n    transform_fun = fn acc -> if rem(acc, 2) == 0, do: {[], acc + 1}, else: {[acc], acc + 1} end\n    stream = Stream.resource(fn -> 1 end, transform_fun, fn _ -> :ok end)\n\n    assert Enum.take(stream, 5) == [1, 3, 5, 7, 9]\n  end\n\n  test \"resource/3 halts with inner list\" do\n    transform_fun = fn acc -> {[acc, acc + 1, acc + 2], acc + 1} end\n    after_fun = fn _ -> Process.put(:stream_resource, true) end\n    stream = Stream.resource(fn -> 1 end, transform_fun, after_fun)\n\n    Process.put(:stream_resource, false)\n    assert Enum.take(stream, 5) == [1, 2, 3, 2, 3]\n    assert Process.get(:stream_resource)\n  end\n\n  test \"resource/3 closes on errors with inner list\" do\n    transform_fun = fn acc -> {[acc, acc + 1, acc + 2], acc + 1} end\n    after_fun = fn _ -> Process.put(:stream_resource, true) end\n    stream = Stream.resource(fn -> 1 end, transform_fun, after_fun)\n\n    Process.put(:stream_resource, false)\n    stream = Stream.map(stream, fn x -> if x > 2, do: throw(:error), else: x end)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_resource)\n  end\n\n  test \"resource/3 is zippable with inner list\" do\n    transform_fun = fn\n      10 -> {:halt, 10}\n      acc -> {[acc, acc + 1, acc + 2], acc + 1}\n    end\n\n    after_fun = fn _ -> Process.put(:stream_resource, true) end\n    stream = Stream.resource(fn -> 1 end, transform_fun, after_fun)\n\n    list = Enum.to_list(stream)\n    Process.put(:stream_resource, false)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n    assert Process.get(:stream_resource)\n  end\n\n  test \"resource/3 halts with inner enum\" do\n    transform_fun = fn acc -> {acc..(acc + 2), acc + 1} end\n    after_fun = fn _ -> Process.put(:stream_resource, true) end\n    stream = Stream.resource(fn -> 1 end, transform_fun, after_fun)\n\n    Process.put(:stream_resource, false)\n    assert Enum.take(stream, 5) == [1, 2, 3, 2, 3]\n    assert Process.get(:stream_resource)\n  end\n\n  test \"resource/3 closes on errors with inner enum\" do\n    transform_fun = fn acc -> {acc..(acc + 2), acc + 1} end\n    after_fun = fn _ -> Process.put(:stream_resource, true) end\n    stream = Stream.resource(fn -> 1 end, transform_fun, after_fun)\n\n    Process.put(:stream_resource, false)\n    stream = Stream.map(stream, fn x -> if x > 2, do: throw(:error), else: x end)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_resource)\n  end\n\n  test \"resource/3 is zippable with inner enum\" do\n    transform_fun = fn\n      10 -> {:halt, 10}\n      acc -> {acc..(acc + 2), acc + 1}\n    end\n\n    after_fun = fn _ -> Process.put(:stream_resource, true) end\n    stream = Stream.resource(fn -> 1 end, transform_fun, after_fun)\n\n    list = Enum.to_list(stream)\n    Process.put(:stream_resource, false)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n    assert Process.get(:stream_resource)\n  end\n\n  test \"transform/4\" do\n    transform_fun = fn x, acc -> {[x, x + acc], x} end\n    after_fun = fn 10 -> Process.put(:stream_transform, true) end\n    stream = Stream.transform(1..10, fn -> 0 end, transform_fun, after_fun)\n    Process.put(:stream_transform, false)\n\n    assert Enum.to_list(stream) ==\n             [1, 1, 2, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19]\n\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 with early halt\" do\n    after_fun = fn nil -> Process.put(:stream_transform, true) end\n\n    stream =\n      fn -> throw(:error) end\n      |> Stream.repeatedly()\n      |> Stream.transform(fn -> nil end, &{[&1, &2], &1}, after_fun)\n\n    Process.put(:stream_transform, false)\n    assert {:halted, nil} = Enumerable.reduce(stream, {:halt, nil}, fn _, _ -> throw(:error) end)\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 with early suspend\" do\n    after_fun = fn nil -> Process.put(:stream_transform, true) end\n\n    stream =\n      fn -> throw(:error) end\n      |> Stream.repeatedly()\n      |> Stream.transform(fn -> nil end, &{[&1, &2], &1}, after_fun)\n\n    refute Process.get(:stream_transform)\n\n    assert {:suspended, nil, _} =\n             Enumerable.reduce(stream, {:suspend, nil}, fn _, _ -> throw(:error) end)\n  end\n\n  test \"transform/4 closes on outer errors\" do\n    transform_fun = fn\n      3, _ -> throw(:error)\n      x, acc -> {[x + acc], x}\n    end\n\n    after_fun = fn 2 -> Process.put(:stream_transform, true) end\n\n    stream = Stream.transform(1..10, fn -> 0 end, transform_fun, after_fun)\n\n    Process.put(:stream_transform, false)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 closes on nested errors\" do\n    transform_fun = fn\n      3, _ -> throw(:error)\n      x, acc -> {[x + acc], x}\n    end\n\n    after_fun = fn _ -> Process.put(:stream_transform_inner, true) end\n    outer_after_fun = fn 0 -> Process.put(:stream_transform_outer, true) end\n\n    stream =\n      1..10\n      |> Stream.transform(fn -> 0 end, transform_fun, after_fun)\n      |> Stream.transform(fn -> 0 end, fn x, acc -> {[x], acc} end, outer_after_fun)\n\n    Process.put(:stream_transform_inner, false)\n    Process.put(:stream_transform_outer, false)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_transform_inner)\n    assert Process.get(:stream_transform_outer)\n  end\n\n  test \"transform/4 is zippable\" do\n    transform_fun = fn\n      10, acc -> {:halt, acc}\n      x, acc -> {[x + acc], x}\n    end\n\n    after_fun = fn 9 -> Process.put(:stream_transform, true) end\n    stream = Stream.transform(1..20, fn -> 0 end, transform_fun, after_fun)\n\n    list = Enum.to_list(stream)\n    Process.put(:stream_transform, false)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 halts with inner list\" do\n    transform_fun = fn x, acc -> {[x, x + 1, x + 2], acc} end\n    after_fun = fn :acc -> Process.put(:stream_transform, true) end\n    stream = Stream.transform(1..10, fn -> :acc end, transform_fun, after_fun)\n\n    Process.put(:stream_transform, false)\n    assert Enum.take(stream, 5) == [1, 2, 3, 2, 3]\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 closes on errors with inner list\" do\n    transform_fun = fn x, acc -> {[x, x + 1, x + 2], acc} end\n    after_fun = fn :acc -> Process.put(:stream_transform, true) end\n    stream = Stream.transform(1..10, fn -> :acc end, transform_fun, after_fun)\n\n    Process.put(:stream_transform, false)\n    stream = Stream.map(stream, fn x -> if x > 2, do: throw(:error), else: x end)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 is zippable with inner list\" do\n    transform_fun = fn\n      10, acc -> {:halt, acc}\n      x, acc -> {[x, x + 1, x + 2], acc}\n    end\n\n    after_fun = fn :inner -> Process.put(:stream_transform, true) end\n\n    stream = Stream.transform(1..20, fn -> :inner end, transform_fun, after_fun)\n\n    list = Enum.to_list(stream)\n    Process.put(:stream_transform, false)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 halts with inner enum\" do\n    transform_fun = fn x, acc -> {x..(x + 2), acc} end\n    after_fun = fn :acc -> Process.put(:stream_transform, true) end\n    stream = Stream.transform(1..10, fn -> :acc end, transform_fun, after_fun)\n\n    Process.put(:stream_transform, false)\n    assert Enum.take(stream, 5) == [1, 2, 3, 2, 3]\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 closes on errors with inner enum\" do\n    transform_fun = fn x, acc -> {x..(x + 2), acc} end\n    after_fun = fn :acc -> Process.put(:stream_transform, true) end\n    stream = Stream.transform(1..10, fn -> :acc end, transform_fun, after_fun)\n\n    Process.put(:stream_transform, false)\n    stream = Stream.map(stream, fn x -> if x > 2, do: throw(:error), else: x end)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/4 is zippable with inner enum\" do\n    transform_fun = fn\n      10, acc -> {:halt, acc}\n      x, acc -> {x..(x + 2), acc}\n    end\n\n    after_fun = fn :inner -> Process.put(:stream_transform, true) end\n    stream = Stream.transform(1..20, fn -> :inner end, transform_fun, after_fun)\n\n    list = Enum.to_list(stream)\n    Process.put(:stream_transform, false)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n    assert Process.get(:stream_transform)\n  end\n\n  test \"transform/5 emits last elements on done\" do\n    stream =\n      Stream.transform(\n        1..5//2,\n        fn -> 0 end,\n        fn i, _acc -> {i..(i + 1), i + 1} end,\n        fn 6 -> {7..10, 10} end,\n        fn i when is_integer(i) -> Process.put(__MODULE__, i) end\n      )\n\n    assert Enum.to_list(stream) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n    assert Process.get(__MODULE__) == 10\n\n    assert Enum.take(stream, 3) == [1, 2, 3]\n    assert Process.get(__MODULE__) == 4\n\n    assert Enum.take(stream, 4) == [1, 2, 3, 4]\n    assert Process.get(__MODULE__) == 4\n\n    assert Enum.take(stream, 7) == [1, 2, 3, 4, 5, 6, 7]\n    assert Process.get(__MODULE__) == 10\n  end\n\n  test \"transform/5 emits last elements on inner halt done\" do\n    stream =\n      Stream.transform(\n        Stream.take(1..15//2, 3),\n        fn -> 0 end,\n        fn i, _acc -> {i..(i + 1), i + 1} end,\n        fn 6 -> {7..10, 10} end,\n        fn i when is_integer(i) -> Process.put(__MODULE__, i) end\n      )\n\n    assert Enum.to_list(stream) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n    assert Process.get(__MODULE__) == 10\n\n    assert Enum.take(stream, 3) == [1, 2, 3]\n    assert Process.get(__MODULE__) == 4\n\n    assert Enum.take(stream, 4) == [1, 2, 3, 4]\n    assert Process.get(__MODULE__) == 4\n\n    assert Enum.take(stream, 7) == [1, 2, 3, 4, 5, 6, 7]\n    assert Process.get(__MODULE__) == 10\n  end\n\n  test \"transform/5 does not halt twice\" do\n    resource_start = fn -> 0 end\n\n    resource_next = fn current ->\n      if current < 5 do\n        {[current], current + 1}\n      else\n        {:halt, current}\n      end\n    end\n\n    resource_after = fn _ ->\n      send(self(), {:halted, :resource})\n    end\n\n    transform_next = fn current, index -> {[current + 1], index} end\n    transform_last = fn index -> {:halt, index} end\n\n    transform_after = fn _ ->\n      send(self(), {:halted, :transform})\n    end\n\n    Stream.resource(resource_start, resource_next, resource_after)\n    |> Stream.transform(fn -> 1 end, transform_next, transform_last, transform_after)\n    |> Stream.run()\n\n    assert_received {:halted, :resource}\n    assert_received {:halted, :transform}\n    refute_received {:halted, :resource}\n    refute_received {:halted, :transform}\n  end\n\n  test \"scan/2\" do\n    stream = Stream.scan(1..5, &(&1 + &2))\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 3, 6, 10, 15]\n    assert Stream.scan([], &(&1 + &2)) |> Enum.to_list() == []\n  end\n\n  test \"scan/3\" do\n    stream = Stream.scan(1..5, 0, &(&1 + &2))\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 3, 6, 10, 15]\n    assert Stream.scan([], 0, &(&1 + &2)) |> Enum.to_list() == []\n  end\n\n  test \"take/2\" do\n    stream = Stream.take(1..1000, 5)\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 2, 3, 4, 5]\n\n    assert Enum.to_list(Stream.take(1..1000, 0)) == []\n    assert Enum.to_list(Stream.take([], 5)) == []\n    assert Enum.to_list(Stream.take(1..3, 5)) == [1, 2, 3]\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Enum.to_list(Stream.take(nats, 5)) == [1, 2, 3, 4, 5]\n\n    stream = Stream.drop(1..100, 5)\n    assert Stream.take(stream, 5) |> Enum.to_list() == [6, 7, 8, 9, 10]\n\n    stream = 1..5 |> Stream.take(10) |> Stream.drop(15)\n    assert {[], []} = Enum.split(stream, 5)\n\n    stream = 1..20 |> Stream.take(10 + 5) |> Stream.drop(4)\n    assert Enum.to_list(stream) == [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]\n  end\n\n  test \"take/2 does not consume next element on halt\" do\n    assert [false, true]\n           |> Stream.each(&(&1 && raise(\"oops\")))\n           |> Stream.take(1)\n           |> Stream.take_while(& &1)\n           |> Enum.to_list() == []\n  end\n\n  test \"take/2 does not consume next element on suspend\" do\n    assert [false, true]\n           |> Stream.each(&(&1 && raise(\"oops\")))\n           |> Stream.take(1)\n           |> Stream.flat_map(&[&1])\n           |> Enum.to_list() == [false]\n  end\n\n  test \"take/2 with negative count\" do\n    Process.put(:stream_each, [])\n\n    stream = Stream.take(1..100, -5)\n    assert lazy?(stream)\n\n    stream = Stream.each(stream, &Process.put(:stream_each, [&1 | Process.get(:stream_each)]))\n    assert Enum.to_list(stream) == [96, 97, 98, 99, 100]\n    assert Process.get(:stream_each) == [100, 99, 98, 97, 96]\n  end\n\n  test \"take/2 is zippable\" do\n    stream = Stream.take(1..1000, 5)\n    list = Enum.to_list(stream)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n  end\n\n  test \"take_every/2\" do\n    assert 1..10\n           |> Stream.take_every(2)\n           |> Enum.to_list() == [1, 3, 5, 7, 9]\n\n    assert 1..10\n           |> Stream.take_every(3)\n           |> Enum.to_list() == [1, 4, 7, 10]\n\n    assert 1..10\n           |> Stream.drop(2)\n           |> Stream.take_every(2)\n           |> Stream.drop(1)\n           |> Enum.to_list() == [5, 7, 9]\n\n    assert 1..10\n           |> Stream.take_every(0)\n           |> Enum.to_list() == []\n\n    assert []\n           |> Stream.take_every(10)\n           |> Enum.to_list() == []\n  end\n\n  test \"take_every/2 with negative integer\" do\n    assert_raise FunctionClauseError, fn ->\n      Stream.take_every(1..10, -1)\n    end\n  end\n\n  test \"take_while/2\" do\n    stream = Stream.take_while(1..1000, &(&1 <= 5))\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [1, 2, 3, 4, 5]\n\n    assert Enum.to_list(Stream.take_while(1..1000, &(&1 <= 0))) == []\n    assert Enum.to_list(Stream.take_while(1..3, &(&1 <= 5))) == [1, 2, 3]\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Enum.to_list(Stream.take_while(nats, &(&1 <= 5))) == [1, 2, 3, 4, 5]\n\n    stream = Stream.drop(1..100, 5)\n    assert Stream.take_while(stream, &(&1 < 11)) |> Enum.to_list() == [6, 7, 8, 9, 10]\n  end\n\n  test \"timer/1\" do\n    stream = Stream.timer(10)\n\n    {time_us, value} = :timer.tc(fn -> Enum.to_list(stream) end)\n\n    assert value == [0]\n    # We check for >= 5000 (us) instead of >= 10000 (us)\n    # because the resolution on Windows system is not high\n    # enough and we would get a difference of 9000 from\n    # time to time. So a value halfway is good enough.\n    assert time_us >= 5000\n  end\n\n  test \"timer/1 with infinity\" do\n    stream = Stream.timer(:infinity)\n    spawn(Stream, :run, [stream])\n  end\n\n  test \"unfold/2\" do\n    stream = Stream.unfold(10, fn x -> if x > 0, do: {x, x - 1} end)\n    assert Enum.take(stream, 5) == [10, 9, 8, 7, 6]\n    stream = Stream.unfold(5, fn x -> if x > 0, do: {x, x - 1} end)\n    assert Enum.to_list(stream) == [5, 4, 3, 2, 1]\n  end\n\n  test \"unfold/2 only calculates values if needed\" do\n    stream = Stream.unfold(1, fn x -> if x > 0, do: {x, x - 1}, else: throw(:boom) end)\n    assert Enum.take(stream, 1) == [1]\n\n    stream = Stream.unfold(5, fn x -> if x > 0, do: {x, x - 1} end)\n    assert Enum.to_list(Stream.take(stream, 2)) == [5, 4]\n  end\n\n  test \"unfold/2 is zippable\" do\n    stream = Stream.unfold(10, fn x -> if x > 0, do: {x, x - 1} end)\n    list = Enum.to_list(stream)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n  end\n\n  test \"uniq/1 & uniq/2\" do\n    assert Stream.uniq([1, 2, 3, 2, 1]) |> Enum.to_list() == [1, 2, 3]\n  end\n\n  test \"uniq_by/2\" do\n    assert Stream.uniq_by([{1, :x}, {2, :y}, {1, :z}], fn {x, _} -> x end) |> Enum.to_list() ==\n             [{1, :x}, {2, :y}]\n\n    assert Stream.uniq_by([a: {:tea, 2}, b: {:tea, 2}, c: {:coffee, 1}], fn {_, y} -> y end)\n           |> Enum.to_list() == [a: {:tea, 2}, c: {:coffee, 1}]\n  end\n\n  test \"zip/2\" do\n    concat = Stream.concat(1..3, 4..6)\n    cycle = Stream.cycle([:a, :b, :c])\n\n    assert Stream.zip(concat, cycle) |> Enum.to_list() ==\n             [{1, :a}, {2, :b}, {3, :c}, {4, :a}, {5, :b}, {6, :c}]\n  end\n\n  test \"zip_with/3\" do\n    concat = Stream.concat(1..3, 4..6)\n    cycle = Stream.cycle([:a, :b, :c])\n    zip_fun = &List.to_tuple([&1, &2])\n\n    assert Stream.zip_with(concat, cycle, zip_fun) |> Enum.to_list() ==\n             [{1, :a}, {2, :b}, {3, :c}, {4, :a}, {5, :b}, {6, :c}]\n\n    stream = Stream.concat(1..3, 4..6)\n    other_stream = fn _, _ -> {:cont, [1, 2]} end\n    result = Stream.zip_with(stream, other_stream, fn a, b -> a + b end) |> Enum.to_list()\n    assert result == [2, 4]\n  end\n\n  test \"zip_with/2\" do\n    concat = Stream.concat(1..3, 4..6)\n    cycle = Stream.cycle([:a, :b, :c])\n    zip_fun = &List.to_tuple/1\n\n    assert Stream.zip_with([concat, cycle], zip_fun) |> Enum.to_list() ==\n             [{1, :a}, {2, :b}, {3, :c}, {4, :a}, {5, :b}, {6, :c}]\n\n    assert Stream.chunk_every([0, 1, 2, 3], 2) |> Stream.zip_with(zip_fun) |> Enum.to_list() ==\n             [{0, 2}, {1, 3}]\n\n    stream = %HaltAcc{acc: 1..3}\n    assert Stream.zip_with([1..3, stream], zip_fun) |> Enum.to_list() == [{1, 1}, {2, 2}, {3, 3}]\n\n    range_cycle = Stream.cycle(1..2)\n\n    assert Stream.zip_with([1..3, range_cycle], zip_fun) |> Enum.to_list() == [\n             {1, 1},\n             {2, 2},\n             {3, 1}\n           ]\n  end\n\n  test \"zip_with/2 does not leave streams suspended\" do\n    zip_with_fun = &List.to_tuple/1\n\n    stream =\n      Stream.resource(fn -> 1 end, fn acc -> {[acc], acc + 1} end, fn _ ->\n        Process.put(:stream_zip_with, true)\n      end)\n\n    Process.put(:stream_zip_with, false)\n\n    assert Stream.zip_with([[:a, :b, :c], stream], zip_with_fun) |> Enum.to_list() == [\n             a: 1,\n             b: 2,\n             c: 3\n           ]\n\n    assert Process.get(:stream_zip_with)\n\n    Process.put(:stream_zip_with, false)\n\n    assert Stream.zip_with([stream, [:a, :b, :c]], zip_with_fun) |> Enum.to_list() == [\n             {1, :a},\n             {2, :b},\n             {3, :c}\n           ]\n\n    assert Process.get(:stream_zip_with)\n  end\n\n  test \"zip_with/2 does not leave streams suspended on halt\" do\n    zip_with_fun = &List.to_tuple/1\n\n    stream =\n      Stream.resource(fn -> 1 end, fn acc -> {[acc], acc + 1} end, fn _ ->\n        Process.put(:stream_zip_with, :done)\n      end)\n\n    assert Stream.zip_with([[:a, :b, :c, :d, :e], stream], zip_with_fun) |> Enum.take(3) == [\n             a: 1,\n             b: 2,\n             c: 3\n           ]\n\n    assert Process.get(:stream_zip_with) == :done\n  end\n\n  test \"zip_with/2 closes on inner error\" do\n    zip_with_fun = &List.to_tuple/1\n    stream = Stream.into([1, 2, 3], %Pdict{})\n\n    stream =\n      Stream.zip_with([stream, Stream.map([:a, :b, :c], fn _ -> throw(:error) end)], zip_with_fun)\n\n    Process.put(:stream_done, false)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_done)\n  end\n\n  test \"zip_with/2 closes on outer error\" do\n    zip_with_fun = &List.to_tuple/1\n\n    stream =\n      Stream.zip_with([Stream.into([1, 2, 3], %Pdict{}), [:a, :b, :c]], zip_with_fun)\n      |> Stream.map(fn _ -> throw(:error) end)\n\n    Process.put(:stream_done, false)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_done)\n  end\n\n  test \"zip/1\" do\n    concat = Stream.concat(1..3, 4..6)\n    cycle = Stream.cycle([:a, :b, :c])\n\n    assert Stream.zip([concat, cycle]) |> Enum.to_list() ==\n             [{1, :a}, {2, :b}, {3, :c}, {4, :a}, {5, :b}, {6, :c}]\n\n    assert Stream.chunk_every([0, 1, 2, 3], 2) |> Stream.zip() |> Enum.to_list() ==\n             [{0, 2}, {1, 3}]\n\n    assert Stream.zip([]) |> Enum.to_list() == []\n\n    stream = %HaltAcc{acc: 1..3}\n    assert Stream.zip([1..3, stream]) |> Enum.to_list() == [{1, 1}, {2, 2}, {3, 3}]\n\n    range_cycle = Stream.cycle(1..2)\n    assert Stream.zip([1..3, range_cycle]) |> Enum.to_list() == [{1, 1}, {2, 2}, {3, 1}]\n  end\n\n  test \"zip/1 does not leave streams suspended\" do\n    stream =\n      Stream.resource(fn -> 1 end, fn acc -> {[acc], acc + 1} end, fn _ ->\n        Process.put(:stream_zip, true)\n      end)\n\n    Process.put(:stream_zip, false)\n    assert Stream.zip([[:a, :b, :c], stream]) |> Enum.to_list() == [a: 1, b: 2, c: 3]\n    assert Process.get(:stream_zip)\n\n    Process.put(:stream_zip, false)\n    assert Stream.zip([stream, [:a, :b, :c]]) |> Enum.to_list() == [{1, :a}, {2, :b}, {3, :c}]\n    assert Process.get(:stream_zip)\n  end\n\n  test \"zip/1 does not leave streams suspended on halt\" do\n    stream =\n      Stream.resource(fn -> 1 end, fn acc -> {[acc], acc + 1} end, fn _ ->\n        Process.put(:stream_zip, :done)\n      end)\n\n    assert Stream.zip([[:a, :b, :c, :d, :e], stream]) |> Enum.take(3) == [a: 1, b: 2, c: 3]\n\n    assert Process.get(:stream_zip) == :done\n  end\n\n  test \"zip/1 closes on inner error\" do\n    stream = Stream.into([1, 2, 3], %Pdict{})\n    stream = Stream.zip([stream, Stream.map([:a, :b, :c], fn _ -> throw(:error) end)])\n\n    Process.put(:stream_done, false)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_done)\n  end\n\n  test \"zip/1 closes on outer error\" do\n    stream =\n      Stream.zip([Stream.into([1, 2, 3], %Pdict{}), [:a, :b, :c]])\n      |> Stream.map(fn _ -> throw(:error) end)\n\n    Process.put(:stream_done, false)\n    assert catch_throw(Enum.to_list(stream)) == :error\n    assert Process.get(:stream_done)\n  end\n\n  test \"with_index/2\" do\n    stream = Stream.with_index([1, 2, 3])\n    assert lazy?(stream)\n    assert Enum.to_list(stream) == [{1, 0}, {2, 1}, {3, 2}]\n\n    stream = Stream.with_index([1, 2, 3], 10)\n    assert Enum.to_list(stream) == [{1, 10}, {2, 11}, {3, 12}]\n\n    nats = Stream.iterate(1, &(&1 + 1))\n    assert Stream.with_index(nats) |> Enum.take(3) == [{1, 0}, {2, 1}, {3, 2}]\n  end\n\n  test \"intersperse/2 is lazy\" do\n    assert lazy?(Stream.intersperse([], 0))\n  end\n\n  test \"intersperse/2 on an empty list\" do\n    assert Enum.to_list(Stream.intersperse([], 0)) == []\n  end\n\n  test \"intersperse/2 on a single element list\" do\n    assert Enum.to_list(Stream.intersperse([1], 0)) == [1]\n  end\n\n  test \"intersperse/2 on a multiple elements list\" do\n    assert Enum.to_list(Stream.intersperse(1..3, 0)) == [1, 0, 2, 0, 3]\n  end\n\n  test \"intersperse/2 is zippable\" do\n    stream = Stream.intersperse(1..10, 0)\n    list = Enum.to_list(stream)\n    assert Enum.zip(list, list) == Enum.zip(stream, stream)\n  end\n\n  test \"inspect/1\" do\n    \"#Stream<[enum: 1..10, funs: \" <> _ = Stream.map(1..10, & &1) |> inspect()\n  end\n\n  defp lazy?(stream) do\n    match?(%Stream{}, stream) or is_function(stream, 2)\n  end\n\n  defp inbox_stream({:suspend, acc}, f) do\n    {:suspended, acc, &inbox_stream(&1, f)}\n  end\n\n  defp inbox_stream({:halt, acc}, _f) do\n    {:halted, acc}\n  end\n\n  defp inbox_stream({:cont, acc}, f) do\n    receive do\n      {:stream, element} ->\n        inbox_stream(f.(element, acc), f)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/string/chars_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule String.Chars.AtomTest do\n  use ExUnit.Case, async: true\n\n  doctest String.Chars\n\n  test \"basic\" do\n    assert to_string(:foo) == \"foo\"\n  end\n\n  test \"empty\" do\n    assert to_string(:\"\") == \"\"\n  end\n\n  test \"true false nil\" do\n    assert to_string(false) == \"false\"\n    assert to_string(true) == \"true\"\n    assert to_string(nil) == \"\"\n  end\n\n  test \"with uppercase\" do\n    assert to_string(:fOO) == \"fOO\"\n    assert to_string(:FOO) == \"FOO\"\n  end\n\n  test \"alias atom\" do\n    assert to_string(Foo.Bar) == \"Elixir.Foo.Bar\"\n  end\nend\n\ndefmodule String.Chars.BitStringTest do\n  use ExUnit.Case, async: true\n\n  test \"binary\" do\n    assert to_string(\"foo\") == \"foo\"\n    assert to_string(<<?a, ?b, ?c>>) == \"abc\"\n    assert to_string(\"我今天要学习.\") == \"我今天要学习.\"\n  end\nend\n\ndefmodule String.Chars.NumberTest do\n  use ExUnit.Case, async: true\n\n  test \"integer\" do\n    assert to_string(100) == \"100\"\n  end\n\n  test \"float\" do\n    assert to_string(1.0) == \"1.0\"\n    assert to_string(1.0e10) == \"1.0e10\"\n  end\nend\n\ndefmodule String.Chars.ListTest do\n  use ExUnit.Case, async: true\n\n  test \"basic\" do\n    assert to_string([1, \"b\", 3]) == <<1, 98, 3>>\n  end\n\n  test \"printable\" do\n    assert to_string(~c\"abc\") == \"abc\"\n  end\n\n  test \"charlist\" do\n    assert to_string([0, 1, 2, 3, 255]) == <<0, 1, 2, 3, 195, 191>>\n\n    assert to_string([0, [1, \"hello\"], 2, [[\"bye\"]]]) ==\n             <<0, 1, 104, 101, 108, 108, 111, 2, 98, 121, 101>>\n  end\n\n  test \"empty\" do\n    assert to_string([]) == \"\"\n  end\nend\n\ndefmodule String.Chars.Version.RequirementTest do\n  use ExUnit.Case, async: true\n\n  test \"version requirement\" do\n    {:ok, requirement} = Version.parse_requirement(\"== 2.0.1\")\n    assert String.Chars.to_string(requirement) == \"== 2.0.1\"\n  end\nend\n\ndefmodule String.Chars.URITest do\n  use ExUnit.Case, async: true\n\n  test \"uri\" do\n    uri = URI.parse(\"http://google.com\")\n    assert String.Chars.to_string(uri) == \"http://google.com\"\n\n    uri_no_host = URI.parse(\"/foo/bar\")\n    assert String.Chars.to_string(uri_no_host) == \"/foo/bar\"\n  end\nend\n\ndefmodule String.Chars.ErrorsTest do\n  use ExUnit.Case, async: true\n\n  defmodule Foo do\n    defstruct foo: \"bar\"\n  end\n\n  test \"bitstring\" do\n    message =\n      \"\"\"\n      protocol String.Chars not implemented for BitString, cannot convert a bitstring to a string\n\n      Got value:\n\n          <<0, 1::size(4)>>\n      \"\"\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      to_string(<<1::size(12)-integer-signed>>)\n    end\n  end\n\n  test \"tuple\" do\n    message = \"\"\"\n    protocol String.Chars not implemented for Tuple\n\n    Got value:\n\n        {1, 2, 3}\n    \"\"\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      to_string({1, 2, 3})\n    end\n  end\n\n  test \"PID\" do\n    message =\n      ~r\"^protocol String\\.Chars not implemented for PID\\n\\nGot value:\\n\\n    #PID<.+?>$\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      to_string(self())\n    end\n  end\n\n  test \"ref\" do\n    message =\n      ~r\"^protocol String\\.Chars not implemented for Reference\\n\\nGot value:\\n\\n    #Reference<.+?>$\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      to_string(make_ref()) == \"\"\n    end\n  end\n\n  test \"function\" do\n    message =\n      ~r\"^protocol String\\.Chars not implemented for Function\\n\\nGot value:\\n\\n    #Function<.+?>$\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      to_string(fn -> nil end)\n    end\n  end\n\n  test \"port\" do\n    [port | _] = Port.list()\n\n    message =\n      ~r\"^protocol String\\.Chars not implemented for Port\\n\\nGot value:\\n\\n    #Port<.+?>$\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      to_string(port)\n    end\n  end\n\n  test \"user-defined struct\" do\n    message =\n      \"protocol String\\.Chars not implemented for String.Chars.ErrorsTest.Foo (a struct)\\n\\nGot value:\\n\\n    %String.Chars.ErrorsTest.Foo{foo: \\\"bar\\\"}\\n\"\n\n    assert_raise Protocol.UndefinedError, message, fn ->\n      to_string(%Foo{})\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/string_io_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule StringIOTest do\n  use ExUnit.Case, async: true\n\n  doctest StringIO\n\n  test \"open and close\" do\n    {:ok, pid} = StringIO.open(\"\")\n    assert StringIO.close(pid) == {:ok, {\"\", \"\"}}\n  end\n\n  test \"contents\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    IO.write(pid, \"edf\")\n    assert StringIO.contents(pid) == {\"abc\", \"edf\"}\n  end\n\n  test \"flush\" do\n    {:ok, pid} = StringIO.open(\"\")\n    IO.write(pid, \"edf\")\n    assert StringIO.flush(pid) == \"edf\"\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  ## IO module\n\n  test \"IO.read :line with \\\\n\" do\n    {:ok, pid} = StringIO.open(\"abc\\n\")\n    assert IO.read(pid, :line) == \"abc\\n\"\n    assert IO.read(pid, :line) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.read :line with \\\\rn\" do\n    {:ok, pid} = StringIO.open(\"abc\\r\\n\")\n    assert IO.read(pid, :line) == \"abc\\n\"\n    assert IO.read(pid, :line) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.read :line without line break\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    assert IO.read(pid, :line) == \"abc\"\n    assert IO.read(pid, :line) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.read :line with UTF-8\" do\n    {:ok, pid} = StringIO.open(\"⼊\\n\")\n    assert IO.read(pid, :line) == \"⼊\\n\"\n    assert IO.read(pid, :line) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.read :line with invalid UTF-8\" do\n    {:ok, pid} = StringIO.open(<<130, 227, 129, 132, 227, 129, 134>>)\n    assert IO.read(pid, :line) == {:error, :collect_line}\n    assert StringIO.contents(pid) == {<<130, 227, 129, 132, 227, 129, 134>>, \"\"}\n  end\n\n  test \"IO.read count\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    assert IO.read(pid, 2) == \"ab\"\n    assert IO.read(pid, 8) == \"c\"\n    assert IO.read(pid, 1) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.read count with UTF-8\" do\n    {:ok, pid} = StringIO.open(\"あいう\")\n    assert IO.read(pid, 2) == \"あい\"\n    assert IO.read(pid, 8) == \"う\"\n    assert IO.read(pid, 1) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.read count with invalid UTF-8\" do\n    {:ok, pid} = StringIO.open(<<130, 227, 129, 132, 227, 129, 134>>)\n    assert IO.read(pid, 2) == {:error, :invalid_unicode}\n    assert StringIO.contents(pid) == {<<130, 227, 129, 132, 227, 129, 134>>, \"\"}\n  end\n\n  test \"IO.binread :line with \\\\n\" do\n    {:ok, pid} = StringIO.open(\"abc\\n\")\n    assert IO.binread(pid, :line) == \"abc\\n\"\n    assert IO.binread(pid, :line) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.binread :line with \\\\r\\\\n\" do\n    {:ok, pid} = StringIO.open(\"abc\\r\\n\")\n    assert IO.binread(pid, :line) == \"abc\\n\"\n    assert IO.binread(pid, :line) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.binread :line without line break\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    assert IO.binread(pid, :line) == \"abc\"\n    assert IO.binread(pid, :line) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.binread :line with raw bytes\" do\n    {:ok, pid} = StringIO.open(<<181, 255, 194, ?\\n>>)\n    assert IO.binread(pid, :line) == <<181, 255, 194, ?\\n>>\n    assert IO.binread(pid, :line) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.binread count\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    assert IO.binread(pid, 2) == \"ab\"\n    assert IO.binread(pid, 8) == \"c\"\n    assert IO.binread(pid, 1) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.binread count with UTF-8\" do\n    {:ok, pid} = StringIO.open(\"あいう\")\n    assert IO.binread(pid, 2) == <<227, 129>>\n    assert IO.binread(pid, 8) == <<130, 227, 129, 132, 227, 129, 134>>\n    assert IO.binread(pid, 1) == :eof\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.write\" do\n    {:ok, pid} = StringIO.open(\"\")\n    assert IO.write(pid, \"foo\") == :ok\n    assert StringIO.contents(pid) == {\"\", \"foo\"}\n  end\n\n  test \"IO.write with UTF-8\" do\n    {:ok, pid} = StringIO.open(\"\")\n    assert IO.write(pid, \"あいう\") == :ok\n    assert StringIO.contents(pid) == {\"\", \"あいう\"}\n  end\n\n  test \"IO.write with non-printable arguments\" do\n    {:ok, pid} = StringIO.open(\"\")\n\n    assert_raise ArgumentError, fn ->\n      IO.write(pid, [<<1::1>>])\n    end\n\n    assert_raise ErlangError, ~r/no_translation/, fn ->\n      IO.write(pid, <<222>>)\n    end\n  end\n\n  test \"IO.binwrite\" do\n    {:ok, pid} = StringIO.open(\"\")\n    assert IO.binwrite(pid, \"foo\") == :ok\n    assert StringIO.contents(pid) == {\"\", \"foo\"}\n  end\n\n  test \"IO.binwrite with UTF-8\" do\n    {:ok, pid} = StringIO.open(\"\")\n    assert IO.binwrite(pid, \"あいう\") == :ok\n\n    binary =\n      <<195, 163, 194, 129, 194, 130, 195, 163>> <>\n        <<194, 129, 194, 132, 195, 163, 194, 129, 194, 134>>\n\n    assert StringIO.contents(pid) == {\"\", binary}\n  end\n\n  test \"IO.binwrite with bytes\" do\n    {:ok, pid} = StringIO.open(\"\")\n    assert IO.binwrite(pid, <<127, 128>>) == :ok\n    assert StringIO.contents(pid) == {\"\", <<127, 194, 128>>}\n  end\n\n  test \"IO.binwrite with bytes and latin1 encoding\" do\n    {:ok, pid} = StringIO.open(\"\", encoding: :latin1)\n    assert IO.binwrite(pid, <<127, 128>>) == :ok\n    assert StringIO.contents(pid) == {\"\", <<127, 128>>}\n  end\n\n  test \"IO.puts\" do\n    {:ok, pid} = StringIO.open(\"\")\n    assert IO.puts(pid, \"abc\") == :ok\n    assert StringIO.contents(pid) == {\"\", \"abc\\n\"}\n  end\n\n  test \"IO.puts with non-printable arguments\" do\n    {:ok, pid} = StringIO.open(\"\")\n\n    assert_raise ArgumentError, fn ->\n      IO.puts(pid, [<<1::1>>])\n    end\n  end\n\n  test \"IO.inspect\" do\n    {:ok, pid} = StringIO.open(\"\")\n    assert IO.inspect(pid, {}, []) == {}\n    assert StringIO.contents(pid) == {\"\", \"{}\\n\"}\n  end\n\n  test \"IO.getn\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    assert IO.getn(pid, \">\", 2) == \"ab\"\n    assert StringIO.contents(pid) == {\"c\", \"\"}\n  end\n\n  test \"IO.getn with UTF-8\" do\n    {:ok, pid} = StringIO.open(\"あいう\")\n    assert IO.getn(pid, \">\", 2) == \"あい\"\n    assert StringIO.contents(pid) == {\"う\", \"\"}\n  end\n\n  test \"IO.getn with invalid UTF-8\" do\n    {:ok, pid} = StringIO.open(<<130, 227, 129, 132, 227, 129, 134>>)\n    assert IO.getn(pid, \">\", 2) == {:error, :invalid_unicode}\n    assert StringIO.contents(pid) == {<<130, 227, 129, 132, 227, 129, 134>>, \"\"}\n  end\n\n  test \"IO.getn with capture_prompt\" do\n    {:ok, pid} = StringIO.open(\"abc\", capture_prompt: true)\n    assert IO.getn(pid, \">\", 2) == \"ab\"\n    assert StringIO.contents(pid) == {\"c\", \">\"}\n  end\n\n  test \"IO.gets with \\\\n\" do\n    {:ok, pid} = StringIO.open(\"abc\\nd\")\n    assert IO.gets(pid, \">\") == \"abc\\n\"\n    assert StringIO.contents(pid) == {\"d\", \"\"}\n  end\n\n  test \"IO.gets with \\\\r\\\\n\" do\n    {:ok, pid} = StringIO.open(\"abc\\r\\nd\")\n    assert IO.gets(pid, \">\") == \"abc\\n\"\n    assert StringIO.contents(pid) == {\"d\", \"\"}\n  end\n\n  test \"IO.gets without line breaks\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    assert IO.gets(pid, \">\") == \"abc\"\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.gets with invalid UTF-8\" do\n    {:ok, pid} = StringIO.open(<<130, 227, 129, 132, 227, 129, 134>>)\n    assert IO.gets(pid, \">\") == {:error, :collect_line}\n    assert StringIO.contents(pid) == {<<130, 227, 129, 132, 227, 129, 134>>, \"\"}\n  end\n\n  test \"IO.gets with capture_prompt\" do\n    {:ok, pid} = StringIO.open(\"abc\\n\", capture_prompt: true)\n    assert IO.gets(pid, \">\") == \"abc\\n\"\n    assert StringIO.contents(pid) == {\"\", \">\"}\n  end\n\n  test \":io.get_password\" do\n    {:ok, pid} = StringIO.open(\"abc\\n\")\n    assert :io.get_password(pid) == \"abc\\n\"\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.stream\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    assert IO.stream(pid, 2) |> Enum.to_list() == [\"ab\", \"c\"]\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \"IO.stream with invalid UTF-8\" do\n    {:ok, pid} = StringIO.open(<<130, 227, 129, 132, 227, 129, 134>>)\n\n    assert_raise IO.StreamError, \"error during streaming: :invalid_unicode\", fn ->\n      IO.stream(pid, 2) |> Enum.to_list()\n    end\n\n    assert StringIO.contents(pid) == {<<130, 227, 129, 132, 227, 129, 134>>, \"\"}\n  end\n\n  test \"IO.binstream\" do\n    {:ok, pid} = StringIO.open(\"abc\")\n    assert IO.stream(pid, 2) |> Enum.to_list() == [\"ab\", \"c\"]\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  defp get_until(pid, encoding, prompt, module, function) do\n    :io.request(pid, {:get_until, encoding, prompt, module, function, []})\n  end\n\n  defmodule GetUntilCallbacks do\n    def until_eof(continuation, :eof) do\n      {:done, continuation, :eof}\n    end\n\n    def until_eof(continuation, content) do\n      {:more, continuation ++ content}\n    end\n\n    def until_eof_then_try_more(~c\"magic-stop-prefix\" ++ continuation, :eof) do\n      {:done, continuation, :eof}\n    end\n\n    def until_eof_then_try_more(continuation, :eof) do\n      {:more, ~c\"magic-stop-prefix\" ++ continuation}\n    end\n\n    def until_eof_then_try_more(continuation, content) do\n      {:more, continuation ++ content}\n    end\n\n    def up_to_3_bytes(continuation, :eof) do\n      {:done, continuation, :eof}\n    end\n\n    def up_to_3_bytes(continuation, content) do\n      case continuation ++ content do\n        [a, b, c | tail] -> {:done, [a, b, c], tail}\n        str -> {:more, str}\n      end\n    end\n\n    def up_to_3_bytes_discard_rest(continuation, :eof) do\n      {:done, continuation, :eof}\n    end\n\n    def up_to_3_bytes_discard_rest(continuation, content) do\n      case continuation ++ content do\n        [a, b, c | _tail] -> {:done, [a, b, c], :eof}\n        str -> {:more, str}\n      end\n    end\n  end\n\n  test \"get_until with up_to_3_bytes\" do\n    {:ok, pid} = StringIO.open(\"abcdefg\")\n    result = get_until(pid, :unicode, \"\", GetUntilCallbacks, :up_to_3_bytes)\n    assert result == \"abc\"\n    assert IO.read(pid, :eof) == \"defg\"\n  end\n\n  test \"get_until with up_to_3_bytes_discard_rest\" do\n    {:ok, pid} = StringIO.open(\"abcdefg\")\n    result = get_until(pid, :unicode, \"\", GetUntilCallbacks, :up_to_3_bytes_discard_rest)\n    assert result == \"abc\"\n    assert IO.read(pid, :eof) == :eof\n  end\n\n  test \"get_until with until_eof\" do\n    {:ok, pid} = StringIO.open(\"abc\\nd\")\n    result = get_until(pid, :unicode, \"\", GetUntilCallbacks, :until_eof)\n    assert result == \"abc\\nd\"\n  end\n\n  test \"get_until with until_eof and \\\\r\\\\n\" do\n    {:ok, pid} = StringIO.open(\"abc\\r\\nd\")\n    result = get_until(pid, :unicode, \"\", GetUntilCallbacks, :until_eof)\n    assert result == \"abc\\r\\nd\"\n  end\n\n  test \"get_until with until_eof capturing prompt\" do\n    {:ok, pid} = StringIO.open(\"abc\\nd\", capture_prompt: true)\n    result = get_until(pid, :unicode, \">\", GetUntilCallbacks, :until_eof)\n    assert result == \"abc\\nd\"\n    assert StringIO.contents(pid) == {\"\", \">>>\"}\n  end\n\n  test \"get_until with until_eof_then_try_more\" do\n    {:ok, pid} = StringIO.open(\"abc\\nd\")\n    result = get_until(pid, :unicode, \"\", GetUntilCallbacks, :until_eof_then_try_more)\n    assert result == \"abc\\nd\"\n  end\n\n  test \"get_until with invalid UTF-8\" do\n    {:ok, pid} = StringIO.open(<<130, 227, 129, 132, 227, 129, 134>>)\n    result = get_until(pid, :unicode, \"\", GetUntilCallbacks, :until_eof)\n    assert result == :error\n  end\n\n  test \"get_until with raw bytes (latin1)\" do\n    {:ok, pid} = StringIO.open(<<181, 255, 194, ?\\n>>)\n    result = get_until(pid, :latin1, \"\", GetUntilCallbacks, :until_eof)\n    assert result == <<181, 255, 194, ?\\n>>\n  end\n\n  test \":io.erl_scan_form/2\" do\n    {:ok, pid} = StringIO.open(\"1.\")\n    result = :io.scan_erl_form(pid, ~c\"p>\")\n    assert result == {:ok, [{:integer, 1, 1}, {:dot, 1}], 1}\n    assert StringIO.contents(pid) == {\"\", \"\"}\n  end\n\n  test \":io.erl_scan_form/2 with capture_prompt\" do\n    {:ok, pid} = StringIO.open(\"1.\", capture_prompt: true)\n    result = :io.scan_erl_form(pid, ~c\"p>\")\n    assert result == {:ok, [{:integer, 1, 1}, {:dot, 1}], 1}\n    assert StringIO.contents(pid) == {\"\", \"p>p>\"}\n  end\n\n  test \"returns enotsup for files\" do\n    {:ok, pid} = StringIO.open(\"123\")\n    assert :file.position(pid, :cur) == {:error, :enotsup}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/string_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule StringTest do\n  use ExUnit.Case, async: true\n\n  doctest String\n\n  test \"next_codepoint/1\" do\n    assert String.next_codepoint(\"ésoj\") == {\"é\", \"soj\"}\n    assert String.next_codepoint(<<255>>) == {<<255>>, \"\"}\n    assert String.next_codepoint(\"\") == nil\n  end\n\n  # test cases described in https://mortoray.com/2013/11/27/the-string-type-is-broken/\n  test \"Unicode\" do\n    assert String.reverse(\"noël\") == \"lëon\"\n    assert String.slice(\"noël\", 0..2) == \"noë\"\n    assert String.length(\"noël\") == 4\n\n    assert String.length(\"\") == 2\n    assert String.slice(\"\", 1..1) == \"\"\n    assert String.reverse(\"\") == \"\"\n\n    assert String.upcase(\"baﬄe\") == \"BAFFLE\"\n\n    assert String.equivalent?(\"noël\", \"noël\")\n  end\n\n  test \"split/1,2,3\" do\n    assert String.split(\"\") == []\n    assert String.split(\"foo bar\") == [\"foo\", \"bar\"]\n    assert String.split(\" foo bar\") == [\"foo\", \"bar\"]\n    assert String.split(\"foo bar \") == [\"foo\", \"bar\"]\n    assert String.split(\" foo bar \") == [\"foo\", \"bar\"]\n    assert String.split(\"foo\\t\\n\\v\\f\\r\\sbar\\n\") == [\"foo\", \"bar\"]\n    assert String.split(\"foo\" <> <<194, 133>> <> \"bar\") == [\"foo\", \"bar\"]\n    # information separators are not considered whitespace\n    assert String.split(\"foo\\u001Fbar\") == [\"foo\\u001Fbar\"]\n    # no-break space is excluded\n    assert String.split(\"foo\\00A0bar\") == [\"foo\\00A0bar\"]\n    assert String.split(\"foo\\u202Fbar\") == [\"foo\\u202Fbar\"]\n\n    assert String.split(\"a,b,c\", \",\") == [\"a\", \"b\", \"c\"]\n    assert String.split(\"a,b\", \".\") == [\"a,b\"]\n    assert String.split(\"1,2 3,4\", [\" \", \",\"]) == [\"1\", \"2\", \"3\", \"4\"]\n\n    assert String.split(\"\", \",\") == [\"\"]\n    assert String.split(\" a b c \", \" \") == [\"\", \"a\", \"b\", \"c\", \"\"]\n    assert String.split(\" a b c \", \" \", parts: :infinity) == [\"\", \"a\", \"b\", \"c\", \"\"]\n    assert String.split(\" a b c \", \" \", parts: 1) == [\" a b c \"]\n    assert String.split(\" a b c \", \" \", parts: 2) == [\"\", \"a b c \"]\n\n    assert String.split(\"\", \",\", trim: true) == []\n    assert String.split(\" a b c \", \" \", trim: true) == [\"a\", \"b\", \"c\"]\n    assert String.split(\" a b c \", \" \", trim: true, parts: :infinity) == [\"a\", \"b\", \"c\"]\n    assert String.split(\" a b c \", \" \", trim: true, parts: 1) == [\" a b c \"]\n    assert String.split(\" a b c \", \" \", trim: true, parts: 2) == [\"a\", \"b c \"]\n\n    assert String.split(\"abé\", \"\") == [\"\", \"a\", \"b\", \"é\", \"\"]\n    assert String.split(\"abé\", \"\", parts: :infinity) == [\"\", \"a\", \"b\", \"é\", \"\"]\n    assert String.split(\"abé\", \"\", parts: 1) == [\"abé\"]\n    assert String.split(\"abé\", \"\", parts: 2) == [\"\", \"abé\"]\n    assert String.split(\"abé\", \"\", parts: 3) == [\"\", \"a\", \"bé\"]\n    assert String.split(\"abé\", \"\", parts: 4) == [\"\", \"a\", \"b\", \"é\"]\n    assert String.split(\"abé\", \"\", parts: 5) == [\"\", \"a\", \"b\", \"é\", \"\"]\n    assert String.split(\"abé\", \"\", parts: 10) == [\"\", \"a\", \"b\", \"é\", \"\"]\n    assert String.split(\"abé\", \"\", trim: true) == [\"a\", \"b\", \"é\"]\n    assert String.split(\"abé\", \"\", trim: true, parts: :infinity) == [\"a\", \"b\", \"é\"]\n    assert String.split(\"abé\", \"\", trim: true, parts: 2) == [\"a\", \"bé\"]\n    assert String.split(\"abé\", \"\", trim: true, parts: 3) == [\"a\", \"b\", \"é\"]\n    assert String.split(\"abé\", \"\", trim: true, parts: 4) == [\"a\", \"b\", \"é\"]\n\n    assert String.split(\"noël\", \"\") == [\"\", \"n\", \"o\", \"ë\", \"l\", \"\"]\n    assert String.split(\"x-\", \"-\", parts: 2, trim: true) == [\"x\"]\n    assert String.split(\"x-x-\", \"-\", parts: 3, trim: true) == [\"x\", \"x\"]\n\n    assert String.split(\"hello\", []) == [\"hello\"]\n    assert String.split(\"hello\", [], trim: true) == [\"hello\"]\n    assert String.split(\"\", []) == [\"\"]\n    assert String.split(\"\", [], trim: true) == []\n\n    assert_raise ArgumentError, fn ->\n      String.split(\"a,b,c\", [\"\"])\n    end\n\n    assert_raise ArgumentError, fn ->\n      String.split(\"a,b,c\", [\"\"])\n    end\n  end\n\n  test \"split/2,3 with regex\" do\n    assert String.split(\"\", ~r{,}) == [\"\"]\n    assert String.split(\"\", ~r{,}, trim: true) == []\n    assert String.split(\"a,b\", ~r{,}) == [\"a\", \"b\"]\n    assert String.split(\"a,b,c\", ~r{,}) == [\"a\", \"b\", \"c\"]\n    assert String.split(\"a,b,c\", ~r{,}, parts: 2) == [\"a\", \"b,c\"]\n    assert String.split(\"a,b.c \", ~r{\\W}) == [\"a\", \"b\", \"c\", \"\"]\n    assert String.split(\"a,b.c \", ~r{\\W}, trim: false) == [\"a\", \"b\", \"c\", \"\"]\n    assert String.split(\"a,b\", ~r{\\.}) == [\"a,b\"]\n  end\n\n  test \"split/2,3 with compiled pattern\" do\n    pattern = :binary.compile_pattern(\"-\")\n\n    assert String.split(\"x-\", pattern) == [\"x\", \"\"]\n    assert String.split(\"x-\", pattern, parts: 2, trim: true) == [\"x\"]\n    assert String.split(\"x-x-\", pattern, parts: 3, trim: true) == [\"x\", \"x\"]\n  end\n\n  test \"split/2,3 with malformed\" do\n    assert String.split(<<225, 158, 128, 225, 158, 185, 225>>, \"\", parts: 1) ==\n             [<<225, 158, 128, 225, 158, 185, 225>>]\n\n    assert String.split(<<225, 158, 128, 225, 158, 185, 225>>, \"\", parts: 2) ==\n             [\"\", <<225, 158, 128, 225, 158, 185, 225>>]\n\n    assert String.split(<<225, 158, 128, 225, 158, 185, 225>>, \"\", parts: 3) ==\n             [\"\", \"កឹ\", <<225>>]\n\n    assert String.split(<<225, 158, 128, 225, 158, 185, 225>>, \"\", parts: 4) ==\n             [\"\", \"កឹ\", <<225>>, \"\"]\n  end\n\n  test \"splitter/2,3\" do\n    assert String.splitter(\"a,b,c\", \",\") |> Enum.to_list() == [\"a\", \"b\", \"c\"]\n    assert String.splitter(\"a,b\", \".\") |> Enum.to_list() == [\"a,b\"]\n    assert String.splitter(\"1,2 3,4\", [\" \", \",\"]) |> Enum.to_list() == [\"1\", \"2\", \"3\", \"4\"]\n    assert String.splitter(\"\", \",\") |> Enum.to_list() == [\"\"]\n\n    assert String.splitter(\"\", \",\", trim: true) |> Enum.to_list() == []\n    assert String.splitter(\" a b c \", \" \", trim: true) |> Enum.to_list() == [\"a\", \"b\", \"c\"]\n    assert String.splitter(\" a b c \", \" \", trim: true) |> Enum.take(1) == [\"a\"]\n    assert String.splitter(\" a b c \", \" \", trim: true) |> Enum.take(2) == [\"a\", \"b\"]\n\n    assert String.splitter(\"hello\", []) |> Enum.to_list() == [\"hello\"]\n    assert String.splitter(\"hello\", [], trim: true) |> Enum.to_list() == [\"hello\"]\n    assert String.splitter(\"\", []) |> Enum.to_list() == [\"\"]\n    assert String.splitter(\"\", [], trim: true) |> Enum.to_list() == []\n\n    assert String.splitter(\"1,2 3,4 5\", \"\") |> Enum.take(4) == [\"\", \"1\", \",\", \"2\"]\n\n    assert_raise ArgumentError, fn ->\n      String.splitter(\"a\", [\"\"])\n    end\n  end\n\n  test \"split_at/2\" do\n    assert String.split_at(\"\", 0) == {\"\", \"\"}\n    assert String.split_at(\"\", -1) == {\"\", \"\"}\n    assert String.split_at(\"\", 1) == {\"\", \"\"}\n\n    assert String.split_at(\"abc\", 0) == {\"\", \"abc\"}\n    assert String.split_at(\"abc\", 2) == {\"ab\", \"c\"}\n    assert String.split_at(\"abc\", 3) == {\"abc\", \"\"}\n    assert String.split_at(\"abc\", 4) == {\"abc\", \"\"}\n    assert String.split_at(\"abc\", 1000) == {\"abc\", \"\"}\n\n    assert String.split_at(\"abc\", -1) == {\"ab\", \"c\"}\n    assert String.split_at(\"abc\", -3) == {\"\", \"abc\"}\n    assert String.split_at(\"abc\", -4) == {\"\", \"abc\"}\n    assert String.split_at(\"abc\", -1000) == {\"\", \"abc\"}\n  end\n\n  test \"split_at/2 with malformed\" do\n    assert String.split_at(<<?a, 195, 10, ?a>>, 2) == {<<?a, 195>>, <<10, ?a>>}\n    assert String.split_at(<<107, 205, 135, 184>>, 1) == {<<107, 205, 135>>, <<184>>}\n\n    assert String.split_at(<<225, 158, 128, 225, 158, 185, 225>>, 0) ==\n             {\"\", <<225, 158, 128, 225, 158, 185, 225>>}\n\n    assert String.split_at(<<225, 158, 128, 225, 158, 185, 225>>, 1) ==\n             {\"កឹ\", <<225>>}\n\n    assert String.split_at(<<225, 158, 128, 225, 158, 185, 225>>, 2) ==\n             {<<225, 158, 128, 225, 158, 185, 225>>, \"\"}\n  end\n\n  test \"upcase/1\" do\n    assert String.upcase(\"123 abcd 456 efg hij ( %$#) kl mnop @ qrst = -_ uvwxyz\") ==\n             \"123 ABCD 456 EFG HIJ ( %$#) KL MNOP @ QRST = -_ UVWXYZ\"\n\n    assert String.upcase(\"\") == \"\"\n    assert String.upcase(\"abcD\") == \"ABCD\"\n  end\n\n  test \"upcase/1 with UTF-8\" do\n    assert String.upcase(\"& % # àáâ ãäå 1 2 ç æ\") == \"& % # ÀÁÂ ÃÄÅ 1 2 Ç Æ\"\n    assert String.upcase(\"àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ\") == \"ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ\"\n  end\n\n  test \"upcase/1 with UTF-8 multibyte\" do\n    assert String.upcase(\"straße\") == \"STRASSE\"\n    assert String.upcase(\"áüÈß\") == \"ÁÜÈSS\"\n  end\n\n  test \"upcase/1 with ascii\" do\n    assert String.upcase(\"olá\", :ascii) == \"OLá\"\n  end\n\n  test \"upcase/1 with turkic\" do\n    assert String.upcase(\"ıi\", :turkic) == \"Iİ\"\n    assert String.upcase(\"Iİ\", :turkic) == \"Iİ\"\n  end\n\n  test \"downcase/1\" do\n    assert String.downcase(\"123 ABcD 456 EfG HIJ ( %$#) KL MNOP @ QRST = -_ UVWXYZ\") ==\n             \"123 abcd 456 efg hij ( %$#) kl mnop @ qrst = -_ uvwxyz\"\n\n    assert String.downcase(\"abcD\") == \"abcd\"\n    assert String.downcase(\"\") == \"\"\n  end\n\n  test \"downcase/1 with UTF-8\" do\n    assert String.downcase(\"& % # ÀÁÂ ÃÄÅ 1 2 Ç Æ\") == \"& % # àáâ ãäå 1 2 ç æ\"\n    assert String.downcase(\"ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ\") == \"àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ\"\n    assert String.downcase(\"áüÈß\") == \"áüèß\"\n  end\n\n  test \"downcase/1 with greek final sigma\" do\n    assert String.downcase(\"Σ\") == \"σ\"\n    assert String.downcase(\"ΣΣ\") == \"σσ\"\n    assert String.downcase(\"Σ ΣΣ\") == \"σ σσ\"\n    assert String.downcase(\"ΜΕΣ'ΑΠΟ\") == \"μεσ'απο\"\n    assert String.downcase(\"ΑΣ'ΤΟΥΣ\") == \"ασ'τουσ\"\n\n    assert String.downcase(\"Σ\", :greek) == \"σ\"\n    assert String.downcase(\"Σ ΣΣ\", :greek) == \"σ σς\"\n    assert String.downcase(\"Σ ΣΑΣ Σ\", :greek) == \"σ σας σ\"\n    assert String.downcase(\"ΜΕΣ'ΑΠΟ\", :greek) == \"μεσ'απο\"\n    assert String.downcase(\"ΑΣ'ΤΟΥΣ\", :greek) == \"ασ'τους\"\n  end\n\n  test \"downcase/1 with ascii\" do\n    assert String.downcase(\"OLÁ\", :ascii) == \"olÁ\"\n  end\n\n  test \"downcase/1 with turkic\" do\n    assert String.downcase(\"Iİ\", :turkic) == \"ıi\"\n    assert String.downcase(\"İ\", :turkic) == \"i\"\n\n    assert String.downcase(\"ıi\", :turkic) == \"ıi\"\n    assert String.downcase(\"i\", :turkic) == \"i\"\n\n    assert String.downcase(\"İ\") == \"i̇\"\n  end\n\n  test \"capitalize/1\" do\n    assert String.capitalize(\"\") == \"\"\n    assert String.capitalize(\"1\") == \"1\"\n    assert String.capitalize(\"abc\") == \"Abc\"\n    assert String.capitalize(\"ABC\") == \"Abc\"\n    assert String.capitalize(\"c b a\") == \"C b a\"\n    assert String.capitalize(\"1ABC\") == \"1abc\"\n    assert String.capitalize(\"_aBc1\") == \"_abc1\"\n    assert String.capitalize(\" aBc1\") == \" abc1\"\n    assert String.capitalize(\"àáâ\") == \"Àáâ\"\n    assert String.capitalize(\"ÀÁÂ\") == \"Àáâ\"\n    assert String.capitalize(\"âáà\") == \"Âáà\"\n    assert String.capitalize(\"ÂÁÀ\") == \"Âáà\"\n    assert String.capitalize(\"òóôõö\") == \"Òóôõö\"\n    assert String.capitalize(\"ÒÓÔÕÖ\") == \"Òóôõö\"\n    assert String.capitalize(\"ﬁn\") == \"Fin\"\n\n    assert String.capitalize(\"ABC\", :ascii) == \"Abc\"\n    assert String.capitalize(\"àáâ\", :ascii) == \"àáâ\"\n    assert String.capitalize(\"aáA\", :ascii) == \"Aáa\"\n\n    assert String.capitalize(\"iii\", :turkic) == \"İii\"\n    assert String.capitalize(\"ııı\", :turkic) == \"Iıı\"\n    assert String.capitalize(\"İii\", :turkic) == \"İii\"\n    assert String.capitalize(\"Iıı\", :turkic) == \"Iıı\"\n\n    assert String.capitalize(<<138, ?B, ?C>>) == <<138, ?b, ?c>>\n\n    assert String.capitalize(<<225, 158, 128, 225, 158, 185, 225>>) ==\n             <<225, 158, 128, 225, 158, 185, 225>>\n  end\n\n  test \"replace_leading/3\" do\n    assert String.replace_leading(\"aa abc   \", \"a\", \"b\") == \"bb abc   \"\n    assert String.replace_leading(\"__ abc   \", \"_\", \"b\") == \"bb abc   \"\n    assert String.replace_leading(\"aaaaaaaa \", \"a\", \"b\") == \"bbbbbbbb \"\n    assert String.replace_leading(\"aaaaaaaa \", \"aaa\", \"b\") == \"bbaa \"\n    assert String.replace_leading(\"aaaaaaaaa\", \"a\", \"b\") == \"bbbbbbbbb\"\n    assert String.replace_leading(\"]]]]]]\", \"]\", \"[]\") == \"[][][][][][]\"\n    assert String.replace_leading(\"]]]]]]]]\", \"]\", \"\") == \"\"\n    assert String.replace_leading(\"]]]]]] ]\", \"]\", \"\") == \" ]\"\n    assert String.replace_leading(\"猫猫 cat  \", \"猫\", \"й\") == \"йй cat  \"\n    assert String.replace_leading(\"test\", \"t\", \"T\") == \"Test\"\n    assert String.replace_leading(\"t\", \"t\", \"T\") == \"T\"\n    assert String.replace_leading(\"aaa\", \"b\", \"c\") == \"aaa\"\n\n    message = ~r/cannot use an empty string/\n\n    assert_raise ArgumentError, message, fn ->\n      String.replace_leading(\"foo\", \"\", \"bar\")\n    end\n\n    assert_raise ArgumentError, message, fn ->\n      String.replace_leading(\"\", \"\", \"bar\")\n    end\n  end\n\n  test \"replace_trailing/3\" do\n    assert String.replace_trailing(\"   abc aa\", \"a\", \"b\") == \"   abc bb\"\n    assert String.replace_trailing(\"   abc __\", \"_\", \"b\") == \"   abc bb\"\n    assert String.replace_trailing(\" aaaaaaaa\", \"a\", \"b\") == \" bbbbbbbb\"\n    assert String.replace_trailing(\" aaaaaaaa\", \"aaa\", \"b\") == \" aabb\"\n    assert String.replace_trailing(\"aaaaaaaaa\", \"a\", \"b\") == \"bbbbbbbbb\"\n    assert String.replace_trailing(\"]]]]]]\", \"]\", \"[]\") == \"[][][][][][]\"\n    assert String.replace_trailing(\"]]]]]]]]\", \"]\", \"\") == \"\"\n    assert String.replace_trailing(\"] ]]]]]]\", \"]\", \"\") == \"] \"\n    assert String.replace_trailing(\"  cat 猫猫\", \"猫\", \"й\") == \"  cat йй\"\n    assert String.replace_trailing(\"test\", \"t\", \"T\") == \"tesT\"\n    assert String.replace_trailing(\"t\", \"t\", \"T\") == \"T\"\n    assert String.replace_trailing(\"aaa\", \"b\", \"c\") == \"aaa\"\n\n    message = ~r/cannot use an empty string/\n\n    assert_raise ArgumentError, message, fn ->\n      String.replace_trailing(\"foo\", \"\", \"bar\")\n    end\n\n    assert_raise ArgumentError, message, fn ->\n      String.replace_trailing(\"\", \"\", \"bar\")\n    end\n  end\n\n  test \"trim/1,2\" do\n    assert String.trim(\"\") == \"\"\n    assert String.trim(\"  abc \") == \"abc\"\n    assert String.trim(\"a  abc  a\\n\\n\") == \"a  abc  a\"\n    assert String.trim(\"a  abc  a\\t\\n\\v\\f\\r\\s\") == \"a  abc  a\"\n\n    assert String.trim(\"___  abc  ___\", \"_\") == \"  abc  \"\n    assert String.trim(\"猫猫猫cat猫猫猫\", \"猫猫\") == \"猫cat猫\"\n    # no-break space\n    assert String.trim(\"\\u00A0a  abc  a\\u00A0\") == \"a  abc  a\"\n    # whitespace defined as a range\n    assert String.trim(\"\\u2008a  abc  a\\u2005\") == \"a  abc  a\"\n  end\n\n  test \"trim_leading/1,2\" do\n    assert String.trim_leading(\"\") == \"\"\n    assert String.trim_leading(\"   abc  \") == \"abc  \"\n    assert String.trim_leading(\"a  abc  a\") == \"a  abc  a\"\n    assert String.trim_leading(\"\\n\\na  abc  a\") == \"a  abc  a\"\n    assert String.trim_leading(\"\\t\\n\\v\\f\\r\\sa  abc  a\") == \"a  abc  a\"\n    assert String.trim_leading(<<194, 133, \"a  abc  a\">>) == \"a  abc  a\"\n    # information separators are not whitespace\n    assert String.trim_leading(\"\\u001F a  abc  a\") == \"\\u001F a  abc  a\"\n    # no-break space\n    assert String.trim_leading(\"\\u00A0 a  abc  a\") == \"a  abc  a\"\n\n    assert String.trim_leading(\"aa aaa\", \"aaa\") == \"aa aaa\"\n    assert String.trim_leading(\"aaa aaa\", \"aa\") == \"a aaa\"\n    assert String.trim_leading(\"aa abc   \", \"a\") == \" abc   \"\n    assert String.trim_leading(\"__ abc   \", \"_\") == \" abc   \"\n    assert String.trim_leading(\"aaaaaaaaa \", \"a\") == \" \"\n    assert String.trim_leading(\"aaaaaaaaaa\", \"a\") == \"\"\n    assert String.trim_leading(\"]]]]]] ]\", \"]\") == \" ]\"\n    assert String.trim_leading(\"猫猫 cat   \", \"猫\") == \" cat   \"\n    assert String.trim_leading(\"test\", \"t\") == \"est\"\n    assert String.trim_leading(\"t\", \"t\") == \"\"\n    assert String.trim_leading(\"\", \"t\") == \"\"\n  end\n\n  test \"trim_trailing/1,2\" do\n    assert String.trim_trailing(\"\") == \"\"\n    assert String.trim_trailing(\"1\\n\") == \"1\"\n    assert String.trim_trailing(\"\\r\\n\") == \"\"\n    assert String.trim_trailing(\"   abc  \") == \"   abc\"\n    assert String.trim_trailing(\"   abc a\") == \"   abc a\"\n    assert String.trim_trailing(\"a  abc  a\\n\\n\") == \"a  abc  a\"\n    assert String.trim_trailing(\"a  abc  a\\t\\n\\v\\f\\r\\s\") == \"a  abc  a\"\n    assert String.trim_trailing(<<\"a  abc  a\", 194, 133>>) == \"a  abc  a\"\n    # information separators are not whitespace\n    assert String.trim_trailing(\"a  abc  a \\u001F\") == \"a  abc  a \\u001F\"\n    # no-break space\n    assert String.trim_trailing(\"a  abc  a \\u00A0\") == \"a  abc  a\"\n\n    assert String.trim_trailing(\"aaa aa\", \"aaa\") == \"aaa aa\"\n    assert String.trim_trailing(\"aaa aaa\", \"aa\") == \"aaa a\"\n    assert String.trim_trailing(\"   abc aa\", \"a\") == \"   abc \"\n    assert String.trim_trailing(\"   abc __\", \"_\") == \"   abc \"\n    assert String.trim_trailing(\" aaaaaaaaa\", \"a\") == \" \"\n    assert String.trim_trailing(\"aaaaaaaaaa\", \"a\") == \"\"\n    assert String.trim_trailing(\"] ]]]]]]\", \"]\") == \"] \"\n    assert String.trim_trailing(\"   cat 猫猫\", \"猫\") == \"   cat \"\n    assert String.trim_trailing(\"test\", \"t\") == \"tes\"\n    assert String.trim_trailing(\"t\", \"t\") == \"\"\n    assert String.trim_trailing(\"\", \"t\") == \"\"\n  end\n\n  test \"pad_leading/2,3\" do\n    assert String.pad_leading(\"\", 5) == \"     \"\n    assert String.pad_leading(\"abc\", 5) == \"  abc\"\n    assert String.pad_leading(\"  abc  \", 9) == \"    abc  \"\n    assert String.pad_leading(\"猫\", 5) == \"    猫\"\n    assert String.pad_leading(\"-\", 0) == \"-\"\n    assert String.pad_leading(\"-\", 1) == \"-\"\n\n    assert String.pad_leading(\"---\", 5, \"abc\") == \"ab---\"\n    assert String.pad_leading(\"---\", 9, \"abc\") == \"abcabc---\"\n\n    assert String.pad_leading(\"---\", 5, [\"abc\"]) == \"abcabc---\"\n    assert String.pad_leading(\"--\", 6, [\"a\", \"bc\"]) == \"abcabc--\"\n\n    message = \"expected a string padding element, got: 10\"\n\n    assert_raise ArgumentError, message, fn ->\n      String.pad_leading(\"-\", 3, [\"-\", 10])\n    end\n  end\n\n  test \"pad_trailing/2,3\" do\n    assert String.pad_trailing(\"\", 5) == \"     \"\n    assert String.pad_trailing(\"abc\", 5) == \"abc  \"\n    assert String.pad_trailing(\"  abc  \", 9) == \"  abc    \"\n    assert String.pad_trailing(\"猫\", 5) == \"猫    \"\n    assert String.pad_trailing(\"-\", 0) == \"-\"\n    assert String.pad_trailing(\"-\", 1) == \"-\"\n\n    assert String.pad_trailing(\"---\", 5, \"abc\") == \"---ab\"\n    assert String.pad_trailing(\"---\", 9, \"abc\") == \"---abcabc\"\n\n    assert String.pad_trailing(\"---\", 5, [\"abc\"]) == \"---abcabc\"\n    assert String.pad_trailing(\"--\", 6, [\"a\", \"bc\"]) == \"--abcabc\"\n\n    message = \"expected a string padding element, got: 10\"\n\n    assert_raise ArgumentError, message, fn ->\n      String.pad_trailing(\"-\", 3, [\"-\", 10])\n    end\n  end\n\n  test \"reverse/1\" do\n    assert String.reverse(\"\") == \"\"\n    assert String.reverse(\"abc\") == \"cba\"\n    assert String.reverse(\"Hello World\") == \"dlroW olleH\"\n    assert String.reverse(\"Hello ∂og\") == \"go∂ olleH\"\n    assert String.reverse(\"Ā̀stute\") == \"etutsĀ̀\"\n    assert String.reverse(String.reverse(\"Hello World\")) == \"Hello World\"\n    assert String.reverse(String.reverse(\"Hello \\r\\n World\")) == \"Hello \\r\\n World\"\n  end\n\n  describe \"replace/3\" do\n    test \"with empty string and string replacement\" do\n      assert String.replace(\"elixir\", \"\", \"\") == \"elixir\"\n      assert String.replace(\"ELIXIR\", \"\", \".\") == \".E.L.I.X.I.R.\"\n      assert String.replace(\"ELIXIR\", \"\", \".\", global: true) == \".E.L.I.X.I.R.\"\n      assert String.replace(\"ELIXIR\", \"\", \".\", global: false) == \".ELIXIR\"\n\n      assert_raise ArgumentError, fn ->\n        String.replace(\"elixir\", [\"\"], \"\")\n      end\n    end\n\n    test \"with empty string and string replacement with malformed\" do\n      assert String.replace(<<225, 158, 128, 225, 158, 185, 225>>, \"\", \".\") == \".កឹ.\\xE1.\"\n    end\n\n    test \"with empty pattern list\" do\n      assert String.replace(\"elixir\", [], \"anything\") == \"elixir\"\n    end\n\n    test \"with match pattern and string replacement\" do\n      assert String.replace(\"a,b,c\", \",\", \"-\") == \"a-b-c\"\n      assert String.replace(\"a,b,c\", [\",\", \"b\"], \"-\") == \"a---c\"\n\n      assert String.replace(\"a,b,c\", \",\", \"-\", global: false) == \"a-b,c\"\n      assert String.replace(\"a,b,c\", [\",\", \"b\"], \"-\", global: false) == \"a-b,c\"\n      assert String.replace(\"ãéã\", \"é\", \"e\", global: false) == \"ãeã\"\n    end\n\n    test \"with regex and string replacement\" do\n      assert String.replace(\"a,b,c\", ~r/,(.)/, \",\\\\1\\\\1\") == \"a,bb,cc\"\n      assert String.replace(\"a,b,c\", ~r/,(.)/, \",\\\\1\\\\1\", global: false) == \"a,bb,c\"\n    end\n\n    test \"with empty string and function replacement\" do\n      assert String.replace(\"elixir\", \"\", fn \"\" -> \"\" end) == \"elixir\"\n      assert String.replace(\"ELIXIR\", \"\", fn \"\" -> \".\" end) == \".E.L.I.X.I.R.\"\n      assert String.replace(\"ELIXIR\", \"\", fn \"\" -> \".\" end, global: true) == \".E.L.I.X.I.R.\"\n      assert String.replace(\"ELIXIR\", \"\", fn \"\" -> \".\" end, global: false) == \".ELIXIR\"\n\n      assert String.replace(\"elixir\", \"\", fn \"\" -> [\"\"] end) == \"elixir\"\n      assert String.replace(\"ELIXIR\", \"\", fn \"\" -> [\".\"] end) == \".E.L.I.X.I.R.\"\n      assert String.replace(\"ELIXIR\", \"\", fn \"\" -> [\".\"] end, global: true) == \".E.L.I.X.I.R.\"\n      assert String.replace(\"ELIXIR\", \"\", fn \"\" -> [\".\"] end, global: false) == \".ELIXIR\"\n    end\n\n    test \"with match pattern and function replacement\" do\n      assert String.replace(\"a,b,c\", \",\", fn \",\" -> \"-\" end) == \"a-b-c\"\n      assert String.replace(\"a,b,c\", [\",\", \"b\"], fn x -> \"[#{x}]\" end) == \"a[,][b][,]c\"\n      assert String.replace(\"a,b,c\", [\",\", \"b\"], fn x -> [?[, x, ?]] end) == \"a[,][b][,]c\"\n\n      assert String.replace(\"a,b,c\", \",\", fn \",\" -> \"-\" end, global: false) == \"a-b,c\"\n      assert String.replace(\"a,b,c\", [\",\", \"b\"], fn x -> \"[#{x}]\" end, global: false) == \"a[,]b,c\"\n      assert String.replace(\"ãéã\", \"é\", fn \"é\" -> \"e\" end, global: false) == \"ãeã\"\n    end\n\n    test \"with regex and function replacement\" do\n      assert String.replace(\"a,b,c\", ~r/,(.)/, fn x -> \"#{x}#{x}\" end) == \"a,b,b,c,c\"\n      assert String.replace(\"a,b,c\", ~r/,(.)/, fn x -> [x, x] end) == \"a,b,b,c,c\"\n      assert String.replace(\"a,b,c\", ~r/,(.)/, fn x -> \"#{x}#{x}\" end, global: false) == \"a,b,b,c\"\n      assert String.replace(\"a,b,c\", ~r/,(.)/, fn x -> [x, x] end, global: false) == \"a,b,b,c\"\n    end\n  end\n\n  test \"duplicate/2\" do\n    assert String.duplicate(\"abc\", 0) == \"\"\n    assert String.duplicate(\"abc\", 1) == \"abc\"\n    assert String.duplicate(\"abc\", 2) == \"abcabc\"\n    assert String.duplicate(\"&ã$\", 2) == \"&ã$&ã$\"\n\n    assert_raise ArgumentError, fn ->\n      String.duplicate(\"abc\", -1)\n    end\n  end\n\n  test \"codepoints/1\" do\n    assert String.codepoints(\"elixir\") == [\"e\", \"l\", \"i\", \"x\", \"i\", \"r\"]\n    # slovak\n    assert String.codepoints(\"elixír\") == [\"e\", \"l\", \"i\", \"x\", \"í\", \"r\"]\n    # armenian\n    assert String.codepoints(\"ոգելից ըմպելիք\") ==\n             [\"ո\", \"գ\", \"ե\", \"լ\", \"ի\", \"ց\", \" \", \"ը\", \"մ\", \"պ\", \"ե\", \"լ\", \"ի\", \"ք\"]\n\n    # belarussian\n    assert String.codepoints(\"эліксір\") == [\"э\", \"л\", \"і\", \"к\", \"с\", \"і\", \"р\"]\n    # greek\n    assert String.codepoints(\"ελιξήριο\") == [\"ε\", \"λ\", \"ι\", \"ξ\", \"ή\", \"ρ\", \"ι\", \"ο\"]\n    # hebraic\n    assert String.codepoints(\"סם חיים\") == [\"ס\", \"ם\", \" \", \"ח\", \"י\", \"י\", \"ם\"]\n    # hindi\n    assert String.codepoints(\"अमृत\") == [\"अ\", \"म\", \"ृ\", \"त\"]\n    # bengali\n    assert String.codepoints(\"স্পর্শমণি\") == [\"স\", \"্\", \"প\", \"র\", \"্\", \"শ\", \"ম\", \"ণ\", \"ি\"]\n    # gujarati\n    assert String.codepoints(\"સર્વશ્રેષ્ઠ ઇલાજ\") ==\n             [\"સ\", \"ર\", \"્\", \"વ\", \"શ\", \"્\", \"ર\", \"ે\", \"ષ\", \"્\", \"ઠ\", \" \", \"ઇ\", \"લ\", \"ા\", \"જ\"]\n\n    # japanese\n    assert String.codepoints(\"世界中の一番\") == [\"世\", \"界\", \"中\", \"の\", \"一\", \"番\"]\n    assert String.codepoints(\"がガちゃ\") == [\"が\", \"ガ\", \"ち\", \"ゃ\"]\n    assert String.codepoints(\"\") == []\n\n    assert String.codepoints(\"ϖͲϥЫݎߟΈټϘለДШव׆ש؇؊صلټܗݎޥޘ߉ऌ૫ሏᶆ℆ℙℱ ⅚Ⅷ↠∈⌘①ﬃ\") ==\n             [\"ϖ\", \"Ͳ\", \"ϥ\", \"Ы\", \"ݎ\", \"ߟ\", \"Έ\"] ++\n               [\"ټ\", \"Ϙ\", \"ለ\", \"Д\", \"Ш\", \"व\"] ++\n               [\"׆\", \"ש\", \"؇\", \"؊\", \"ص\", \"ل\", \"ټ\"] ++\n               [\"ܗ\", \"ݎ\", \"ޥ\", \"ޘ\", \"߉\", \"ऌ\", \"૫\"] ++\n               [\"ሏ\", \"ᶆ\", \"℆\", \"ℙ\", \"ℱ\", \" \", \"⅚\"] ++ [\"Ⅷ\", \"↠\", \"∈\", \"⌘\", \"①\", \"ﬃ\"]\n  end\n\n  test \"equivalent?/2\" do\n    assert String.equivalent?(\"\", \"\")\n    assert String.equivalent?(\"elixir\", \"elixir\")\n    assert String.equivalent?(\"뢴\", \"뢴\")\n    assert String.equivalent?(\"ṩ\", \"ṩ\")\n    refute String.equivalent?(\"ELIXIR\", \"elixir\")\n    refute String.equivalent?(\"døge\", \"dóge\")\n  end\n\n  test \"graphemes/1\" do\n    # Extended\n    assert String.graphemes(\"Ā̀stute\") == [\"Ā̀\", \"s\", \"t\", \"u\", \"t\", \"e\"]\n    # CLRF\n    assert String.graphemes(\"\\r\\n\\f\") == [\"\\r\\n\", \"\\f\"]\n    # Regional indicator\n    assert String.graphemes(\"\\u{1F1E6}\\u{1F1E7}\") == [\"\\u{1F1E6}\\u{1F1E7}\"]\n    assert String.graphemes(\"\\u{1F1E6}\\u{1F1E7}\\u{1F1E8}\") == [\"\\u{1F1E6}\\u{1F1E7}\", \"\\u{1F1E8}\"]\n    # Hangul\n    assert String.graphemes(\"\\u1100\\u115D\\uB4A4\") == [\"ᄀᅝ뒤\"]\n    # Special Marking with Extended\n    assert String.graphemes(\"a\\u0300\\u0903\") == [\"a\\u0300\\u0903\"]\n  end\n\n  test \"next_grapheme/1\" do\n    assert String.next_grapheme(\"Ā̀stute\") == {\"Ā̀\", \"stute\"}\n    assert String.next_grapheme(<<225, 158, 128, 225, 158, 185, 225>>) == {\"កឹ\", <<225>>}\n    assert String.next_grapheme(\"\") == nil\n  end\n\n  describe \"randomized\" do\n    test \"next_grapheme\" do\n      for _ <- 1..10 do\n        bin = :crypto.strong_rand_bytes(20)\n\n        try do\n          bin |> Stream.unfold(&String.next_grapheme/1) |> Enum.to_list()\n        rescue\n          # Ignore malformed pictographic sequences\n          _ -> :ok\n        else\n          list ->\n            assert Enum.all?(list, &is_binary/1), \"cannot build graphemes for #{inspect(bin)}\"\n        end\n      end\n    end\n\n    test \"split empty\" do\n      for _ <- 1..10 do\n        bin = :crypto.strong_rand_bytes(20)\n\n        try do\n          String.split(bin, \"\")\n        rescue\n          # Ignore malformed pictographic sequences\n          _ -> :ok\n        else\n          split ->\n            assert Enum.all?(split, &is_binary/1), \"cannot split #{inspect(bin)}\"\n            assert IO.iodata_to_binary(split) == bin\n        end\n      end\n    end\n\n    test \"graphemes\" do\n      for _ <- 1..10 do\n        bin = :crypto.strong_rand_bytes(20)\n\n        try do\n          String.graphemes(bin)\n        rescue\n          # Ignore malformed pictographic sequences\n          _ -> :ok\n        else\n          graphemes ->\n            assert Enum.all?(graphemes, &is_binary/1),\n                   \"cannot build graphemes for #{inspect(bin)}\"\n\n            assert IO.iodata_to_binary(graphemes) == bin\n        end\n      end\n    end\n  end\n\n  test \"first/1\" do\n    assert String.first(\"elixir\") == \"e\"\n    assert String.first(\"íelixr\") == \"í\"\n    assert String.first(\"եոգլից ըմպելիք\") == \"ե\"\n    assert String.first(\"лэіксір\") == \"л\"\n    assert String.first(\"ελιξήριο\") == \"ε\"\n    assert String.first(\"סם חיים\") == \"ס\"\n    assert String.first(\"がガちゃ\") == \"が\"\n    assert String.first(\"Ā̀stute\") == \"Ā̀\"\n    assert String.first(\"\") == nil\n  end\n\n  test \"last/1\" do\n    assert String.last(\"elixir\") == \"r\"\n    assert String.last(\"elixrí\") == \"í\"\n    assert String.last(\"եոգլից ըմպելիքե\") == \"ե\"\n    assert String.last(\"ліксірэ\") == \"э\"\n    assert String.last(\"ειξήριολ\") == \"λ\"\n    assert String.last(\"סם ייםח\") == \"ח\"\n    assert String.last(\"がガちゃ\") == \"ゃ\"\n    assert String.last(\"Ā̀\") == \"Ā̀\"\n    assert String.last(\"\") == nil\n  end\n\n  test \"length/1\" do\n    assert String.length(\"elixir\") == 6\n    assert String.length(\"elixrí\") == 6\n    assert String.length(\"եոգլից\") == 6\n    assert String.length(\"ліксрэ\") == 6\n    assert String.length(\"ειξήριολ\") == 8\n    assert String.length(\"סם ייםח\") == 7\n    assert String.length(\"がガちゃ\") == 4\n    assert String.length(\"Ā̀stute\") == 6\n    assert String.length(\"👨‍👩‍👧‍👦\") == 1\n    assert String.length(\"\") == 0\n  end\n\n  test \"at/2\" do\n    assert String.at(\"л\", 0) == \"л\"\n    assert String.at(\"elixir\", 1) == \"l\"\n    assert String.at(\"がガちゃ\", 2) == \"ち\"\n    assert String.at(\"л\", 10) == nil\n    assert String.at(\"elixir\", -1) == \"r\"\n    assert String.at(\"がガちゃ\", -2) == \"ち\"\n    assert String.at(\"л\", -3) == nil\n    assert String.at(\"Ā̀stute\", 1) == \"s\"\n    assert String.at(\"elixir\", 6) == nil\n  end\n\n  test \"slice/3\" do\n    assert String.slice(\"elixir\", 1, 3) == \"lix\"\n    assert String.slice(\"あいうえお\", 2, 2) == \"うえ\"\n    assert String.slice(\"ειξήριολ\", 2, 3) == \"ξήρ\"\n    assert String.slice(\"elixir\", 3, 4) == \"xir\"\n    assert String.slice(\"あいうえお\", 3, 5) == \"えお\"\n    assert String.slice(\"ειξήριολ\", 5, 4) == \"ιολ\"\n    assert String.slice(\"elixir\", -3, 2) == \"xi\"\n    assert String.slice(\"あいうえお\", -4, 3) == \"いうえ\"\n    assert String.slice(\"ειξήριολ\", -5, 3) == \"ήρι\"\n    assert String.slice(\"elixir\", -10, 1) == \"e\"\n    assert String.slice(\"あいうえお\", -10, 2) == \"あい\"\n    assert String.slice(\"ειξήριολ\", -10, 3) == \"ειξ\"\n    assert String.slice(\"elixir\", 8, 2) == \"\"\n    assert String.slice(\"あいうえお\", 6, 2) == \"\"\n    assert String.slice(\"ειξήριολ\", 8, 1) == \"\"\n    assert String.slice(\"ειξήριολ\", 9, 1) == \"\"\n    assert String.slice(\"elixir\", 0, 0) == \"\"\n    assert String.slice(\"elixir\", 5, 0) == \"\"\n    assert String.slice(\"elixir\", -5, 0) == \"\"\n    assert String.slice(\"elixir\", -10, 10) == \"elixir\"\n    assert String.slice(\"\", 0, 1) == \"\"\n    assert String.slice(\"\", 1, 1) == \"\"\n  end\n\n  test \"slice/2\" do\n    assert String.slice(\"elixir\", 0..-2//1) == \"elixi\"\n    assert String.slice(\"elixir\", 1..3) == \"lix\"\n    assert String.slice(\"elixir\", -5..-3) == \"lix\"\n    assert String.slice(\"elixir\", -5..3) == \"lix\"\n    assert String.slice(\"elixir\", -10..10) == \"elixir\"\n    assert String.slice(\"あいうえお\", 2..3) == \"うえ\"\n    assert String.slice(\"ειξήριολ\", 2..4) == \"ξήρ\"\n    assert String.slice(\"elixir\", 3..6) == \"xir\"\n    assert String.slice(\"あいうえお\", 3..7) == \"えお\"\n    assert String.slice(\"ειξήριολ\", 5..8) == \"ιολ\"\n    assert String.slice(\"elixir\", -3..-2) == \"xi\"\n    assert String.slice(\"あいうえお\", -4..-2) == \"いうえ\"\n    assert String.slice(\"ειξήριολ\", -5..-3) == \"ήρι\"\n    assert String.slice(\"elixir\", 8..9) == \"\"\n    assert String.slice(\"あいうえお\", 6..7) == \"\"\n    assert String.slice(\"ειξήριολ\", 8..8) == \"\"\n    assert String.slice(\"ειξήριολ\", 9..9) == \"\"\n    assert String.slice(\"\", 0..0) == \"\"\n    assert String.slice(\"\", 1..1) == \"\"\n    assert String.slice(\"あいうえお\", -2..-4//1) == \"\"\n    assert String.slice(\"あいうえお\", -10..-15//1) == \"\"\n    assert String.slice(\"hello あいうえお Unicode\", 8..-1//1) == \"うえお Unicode\"\n    assert String.slice(\"abc\", -1..14) == \"c\"\n    assert String.slice(\"a·̀ͯ‿.⁀:\", 0..-2//1) == \"a·̀ͯ‿.⁀\"\n\n    assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n             assert String.slice(\"elixir\", 0..-2//-1) == \"elixi\"\n           end) =~ \"negative steps are not supported in String.slice/2, pass 0..-2//1 instead\"\n  end\n\n  test \"slice/2 with steps\" do\n    assert String.slice(\"elixir\", 0..-2//2) == \"eii\"\n    assert String.slice(\"elixir\", 1..3//2) == \"lx\"\n    assert String.slice(\"elixir\", -5..-3//2) == \"lx\"\n    assert String.slice(\"elixir\", -5..3//2) == \"lx\"\n    assert String.slice(\"あいうえお\", 2..3//2) == \"う\"\n    assert String.slice(\"ειξήριολ\", 2..4//2) == \"ξρ\"\n    assert String.slice(\"elixir\", 3..6//2) == \"xr\"\n    assert String.slice(\"あいうえお\", 3..7//2) == \"え\"\n    assert String.slice(\"ειξήριολ\", 5..8//2) == \"ιλ\"\n    assert String.slice(\"elixir\", -3..-2//2) == \"x\"\n    assert String.slice(\"あいうえお\", -4..-2//2) == \"いえ\"\n    assert String.slice(\"ειξήριολ\", -5..-3//2) == \"ήι\"\n    assert String.slice(\"elixir\", 8..9//2) == \"\"\n    assert String.slice(\"\", 0..0//2) == \"\"\n    assert String.slice(\"\", 1..1//2) == \"\"\n    assert String.slice(\"あいうえお\", -2..-4//2) == \"\"\n    assert String.slice(\"あいうえお\", -10..-15//2) == \"\"\n    assert String.slice(\"hello あいうえお Unicode\", 8..-1//2) == \"うおUioe\"\n    assert String.slice(\"abc\", -1..14//2) == \"c\"\n    assert String.slice(\"a·̀ͯ‿.⁀:\", 0..-2//2) == \"a‿⁀\"\n  end\n\n  test \"byte_slice/2\" do\n    # ASCII\n    assert String.byte_slice(\"elixir\", 0, 6) == \"elixir\"\n    assert String.byte_slice(\"elixir\", 0, 5) == \"elixi\"\n    assert String.byte_slice(\"elixir\", 1, 4) == \"lixi\"\n    assert String.byte_slice(\"elixir\", 0, 10) == \"elixir\"\n    assert String.byte_slice(\"elixir\", -3, 10) == \"xir\"\n    assert String.byte_slice(\"elixir\", -10, 10) == \"elixir\"\n    assert String.byte_slice(\"elixir\", 1, 0) == \"\"\n    assert String.byte_slice(\"elixir\", 10, 10) == \"\"\n\n    # 2 byte\n    assert String.byte_slice(\"héllò\", 1, 4) == \"éll\"\n    assert String.byte_slice(\"héllò\", 1, 5) == \"éll\"\n    assert String.byte_slice(\"héllò\", 1, 6) == \"éllò\"\n    assert String.byte_slice(\"héllò\", 2, 4) == \"llò\"\n\n    # 3 byte\n    assert String.byte_slice(\"hかllか\", 1, 4) == \"かl\"\n    assert String.byte_slice(\"hかllか\", 1, 5) == \"かll\"\n    assert String.byte_slice(\"hかllか\", 1, 6) == \"かll\"\n    assert String.byte_slice(\"hかllか\", 1, 7) == \"かll\"\n    assert String.byte_slice(\"hかllか\", 1, 8) == \"かllか\"\n    assert String.byte_slice(\"hかllか\", 2, 4) == \"ll\"\n    assert String.byte_slice(\"hかllか\", 2, 5) == \"llか\"\n\n    # 4 byte\n    assert String.byte_slice(\"h😍ll😍\", 1, 4) == \"😍\"\n    assert String.byte_slice(\"h😍ll😍\", 1, 5) == \"😍l\"\n    assert String.byte_slice(\"h😍ll😍\", 1, 6) == \"😍ll\"\n    assert String.byte_slice(\"h😍ll😍\", 1, 7) == \"😍ll\"\n    assert String.byte_slice(\"h😍ll😍\", 1, 8) == \"😍ll\"\n    assert String.byte_slice(\"h😍ll😍\", 1, 9) == \"😍ll\"\n    assert String.byte_slice(\"h😍ll😍\", 1, 10) == \"😍ll😍\"\n    assert String.byte_slice(\"h😍ll😍\", 2, 5) == \"ll\"\n    assert String.byte_slice(\"h😍ll😍\", 2, 6) == \"ll😍\"\n\n    # Already truncated\n    assert String.byte_slice(<<178, \"ll\", 178>>, 0, 10) == \"ll\"\n\n    # Already invalid\n    assert String.byte_slice(<<255, \"ll\", 255>>, 0, 10) == <<255, \"ll\", 255>>\n  end\n\n  test \"valid?/1\" do\n    assert String.valid?(\"afds\")\n    assert String.valid?(\"øsdfh\")\n    assert String.valid?(\"dskfjあska\")\n    assert String.valid?(<<0xEF, 0xB7, 0x90>>)\n\n    refute String.valid?(<<0xFFFF::16>>)\n    refute String.valid?(\"asd\" <> <<0xFFFF::16>>)\n\n    assert String.valid?(\"afdsafdsafds\", :fast_ascii)\n    assert String.valid?(\"øsdfhøsdfh\", :fast_ascii)\n    assert String.valid?(\"dskfjあskadskfjあska\", :fast_ascii)\n    assert String.valid?(<<0xEF, 0xB7, 0x90, 0xEF, 0xB7, 0x90, 0xEF, 0xB7, 0x90>>, :fast_ascii)\n\n    refute String.valid?(<<0xFFFF::16>>, :fast_ascii)\n    refute String.valid?(\"asdasdasd\" <> <<0xFFFF::16>>, :fast_ascii)\n  end\n\n  test \"replace_invalid\" do\n    assert String.replace_invalid(\"\") === \"\"\n    assert String.replace_invalid(<<0xFF>>) === \"�\"\n    assert String.replace_invalid(<<0xFF, 0xFF, 0xFF>>) === \"���\"\n\n    # Valid ASCII\n    assert String.replace_invalid(\"hello\") === \"hello\"\n\n    # Valid UTF-8\n    assert String.replace_invalid(\"こんにちは\") === \"こんにちは\"\n\n    # 2/3 byte truncated \"ề\"\n    assert String.replace_invalid(<<225, 187>>) === \"�\"\n    assert String.replace_invalid(\"nem rán b\" <> <<225, 187>> <> \" bề\") === \"nem rán b� bề\"\n\n    # 2/4 byte truncated \"😔\"\n    assert String.replace_invalid(<<240, 159>>) === \"�\"\n    assert String.replace_invalid(\"It's so over \" <> <<240, 159>>) === \"It's so over �\"\n\n    # 3/4 byte truncated \"😃\"\n    assert String.replace_invalid(<<240, 159, 152>>) === \"�\"\n    assert String.replace_invalid(\"We're so back \" <> <<240, 159, 152>>) === \"We're so back �\"\n\n    # 3 byte overlong \"e\"\n    assert String.replace_invalid(<<0b11100000, 0b10000001, 0b10100101>>) === \"���\"\n  end\n\n  test \"chunk/2 with :valid trait\" do\n    assert String.chunk(\"\", :valid) == []\n\n    assert String.chunk(\"ødskfjあ\\x11ska\", :valid) == [\"ødskfjあ\\x11ska\"]\n  end\n\n  test \"chunk/2 with :printable trait\" do\n    assert String.chunk(\"\", :printable) == []\n\n    assert String.chunk(\"ødskfjあska\", :printable) == [\"ødskfjあska\"]\n    assert String.chunk(\"abc\\u{0FFFF}def\", :printable) == [\"abc\", <<0x0FFFF::utf8>>, \"def\"]\n\n    assert String.chunk(\"\\x06ab\\x05cdef\\x03\\0\", :printable) ==\n             [<<6>>, \"ab\", <<5>>, \"cdef\", <<3, 0>>]\n  end\n\n  test \"starts_with?/2\" do\n    assert String.starts_with?(\"hello\", \"he\")\n    assert String.starts_with?(\"hello\", \"hello\")\n    refute String.starts_with?(\"hello\", [])\n    assert String.starts_with?(\"hello\", \"\")\n    assert String.starts_with?(\"hello\", [\"\"])\n    assert String.starts_with?(\"hello\", [\"hellö\", \"hell\"])\n    assert String.starts_with?(\"エリクシア\", \"エリ\")\n    refute String.starts_with?(\"hello\", \"lo\")\n    refute String.starts_with?(\"hello\", \"hellö\")\n    refute String.starts_with?(\"hello\", [\"hellö\", \"goodbye\"])\n    refute String.starts_with?(\"エリクシア\", \"仙丹\")\n  end\n\n  test \"ends_with?/2\" do\n    assert String.ends_with?(\"hello\", \"lo\")\n    assert String.ends_with?(\"hello\", \"hello\")\n    refute String.ends_with?(\"hello\", [])\n    assert String.ends_with?(\"hello\", [\"hell\", \"lo\", \"xx\"])\n    assert String.ends_with?(\"hello\", [\"hellö\", \"lo\"])\n    assert String.ends_with?(\"エリクシア\", \"シア\")\n    refute String.ends_with?(\"hello\", \"he\")\n    refute String.ends_with?(\"hello\", \"hellö\")\n    refute String.ends_with?(\"hello\", [\"hel\", \"goodbye\"])\n    refute String.ends_with?(\"エリクシア\", \"仙丹\")\n  end\n\n  test \"contains?/2\" do\n    assert String.contains?(\"elixir of life\", \"of\")\n    assert String.contains?(\"エリクシア\", \"シ\")\n    refute String.contains?(\"elixir of life\", [])\n    assert String.contains?(\"elixir of life\", \"\")\n    assert String.contains?(\"elixir of life\", [\"\"])\n    assert String.contains?(\"elixir of life\", [\"mercury\", \"life\"])\n    refute String.contains?(\"elixir of life\", \"death\")\n    refute String.contains?(\"エリクシア\", \"仙\")\n    refute String.contains?(\"elixir of life\", [\"death\", \"mercury\", \"eternal life\"])\n  end\n\n  test \"to_charlist/1\" do\n    assert String.to_charlist(\"æß\") == [?æ, ?ß]\n    assert String.to_charlist(\"abc\") == [?a, ?b, ?c]\n\n    assert_raise UnicodeConversionError, \"invalid encoding starting at <<223, 255>>\", fn ->\n      String.to_charlist(<<0xDF, 0xFF>>)\n    end\n\n    assert_raise UnicodeConversionError, \"incomplete encoding starting at <<195>>\", fn ->\n      String.to_charlist(<<106, 111, 115, 195>>)\n    end\n  end\n\n  test \"to_float/1\" do\n    assert String.to_float(\"3.0\") == 3.0\n\n    three = fn -> \"3\" end\n    assert_raise ArgumentError, fn -> String.to_float(three.()) end\n\n    dot_three = fn -> \".3\" end\n    assert_raise ArgumentError, fn -> String.to_float(dot_three.()) end\n  end\n\n  test \"jaro_distance/2\" do\n    assert String.jaro_distance(\"same\", \"same\") == 1.0\n    assert String.jaro_distance(\"any\", \"\") == 0.0\n    assert String.jaro_distance(\"\", \"any\") == 0.0\n    assert String.jaro_distance(\"martha\", \"marhta\") == 0.9444444444444445\n    assert String.jaro_distance(\"martha\", \"marhha\") == 0.888888888888889\n    assert String.jaro_distance(\"marhha\", \"martha\") == 0.888888888888889\n    assert String.jaro_distance(\"dwayne\", \"duane\") == 0.8222222222222223\n    assert String.jaro_distance(\"dixon\", \"dicksonx\") == 0.7666666666666666\n    assert String.jaro_distance(\"xdicksonx\", \"dixon\") == 0.7518518518518519\n    assert String.jaro_distance(\"shackleford\", \"shackelford\") == 0.9696969696969697\n    assert String.jaro_distance(\"dunningham\", \"cunnigham\") == 0.8962962962962964\n    assert String.jaro_distance(\"nichleson\", \"nichulson\") == 0.9259259259259259\n    assert String.jaro_distance(\"jones\", \"johnson\") == 0.7904761904761904\n    assert String.jaro_distance(\"massey\", \"massie\") == 0.888888888888889\n    assert String.jaro_distance(\"abroms\", \"abrams\") == 0.888888888888889\n    assert String.jaro_distance(\"hardin\", \"martinez\") == 0.7222222222222222\n    assert String.jaro_distance(\"itman\", \"smith\") == 0.4666666666666666\n    assert String.jaro_distance(\"jeraldine\", \"geraldine\") == 0.9259259259259259\n    assert String.jaro_distance(\"michelle\", \"michael\") == 0.8690476190476191\n    assert String.jaro_distance(\"julies\", \"julius\") == 0.888888888888889\n    assert String.jaro_distance(\"tanya\", \"tonya\") == 0.8666666666666667\n    assert String.jaro_distance(\"sean\", \"susan\") == 0.7833333333333333\n    assert String.jaro_distance(\"jon\", \"john\") == 0.9166666666666666\n    assert String.jaro_distance(\"jon\", \"jan\") == 0.7777777777777777\n    assert String.jaro_distance(\"семена\", \"стремя\") == 0.6666666666666666\n    assert String.jaro_distance(\"Sunday\", \"Saturday\") == 0.7194444444444444\n  end\n\n  test \"myers_difference/2\" do\n    assert String.myers_difference(\"\", \"abc\") == [ins: \"abc\"]\n    assert String.myers_difference(\"abc\", \"\") == [del: \"abc\"]\n    assert String.myers_difference(\"\", \"\") == []\n    assert String.myers_difference(\"abc\", \"abc\") == [eq: \"abc\"]\n    assert String.myers_difference(\"abc\", \"aйbc\") == [eq: \"a\", ins: \"й\", eq: \"bc\"]\n    assert String.myers_difference(\"aйbc\", \"abc\") == [eq: \"a\", del: \"й\", eq: \"bc\"]\n  end\n\n  test \"normalize/2\" do\n    assert String.normalize(\"ŝ\", :nfd) == \"ŝ\"\n    assert String.normalize(\"ḇravô\", :nfd) == \"ḇravô\"\n    assert String.normalize(\"ṩierra\", :nfd) == \"ṩierra\"\n    assert String.normalize(\"뢴\", :nfd) == \"뢴\"\n    assert String.normalize(\"êchǭ\", :nfc) == \"êchǭ\"\n    assert String.normalize(\"거̄\", :nfc) == \"거̄\"\n    assert String.normalize(\"뢴\", :nfc) == \"뢴\"\n\n    ## Error cases\n    assert String.normalize(<<15, 216>>, :nfc) == <<15, 216>>\n    assert String.normalize(<<15, 216>>, :nfd) == <<15, 216>>\n    assert String.normalize(<<216, 15>>, :nfc) == <<216, 15>>\n    assert String.normalize(<<216, 15>>, :nfd) == <<216, 15>>\n\n    assert String.normalize(<<15, 216>>, :nfkc) == <<15, 216>>\n    assert String.normalize(<<15, 216>>, :nfkd) == <<15, 216>>\n    assert String.normalize(<<216, 15>>, :nfkc) == <<216, 15>>\n    assert String.normalize(<<216, 15>>, :nfkd) == <<216, 15>>\n\n    ## Cases from NormalizationTest.txt\n\n    # 05B8 05B9 05B1 0591 05C3 05B0 05AC 059F\n    # 05B1 05B8 05B9 0591 05C3 05B0 05AC 059F\n    # HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL,\n    # HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA,\n    # HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA\n    assert String.normalize(\"ֱָֹ֑׃ְ֬֟\", :nfc) == \"ֱָֹ֑׃ְ֬֟\"\n\n    # 095D (exclusion list)\n    # 0922 093C\n    # DEVANAGARI LETTER RHA\n    assert String.normalize(\"ढ़\", :nfc) == \"ढ़\"\n\n    # 0061 0315 0300 05AE 0340 0062\n    # 00E0 05AE 0300 0315 0062\n    # LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT,\n    # HEBREW ACCENT ZINOR, COMBINING GRAVE TONE MARK, LATIN SMALL LETTER B\n    assert String.normalize(\"à֮̀̕b\", :nfc) == \"à֮̀̕b\"\n\n    # 0344\n    # 0308 0301\n    # COMBINING GREEK DIALYTIKA TONOS\n    assert String.normalize(\"\\u0344\", :nfc) == \"\\u0308\\u0301\"\n\n    # 115B9 0334 115AF\n    # 115B9 0334 115AF\n    # SIDDHAM VOWEL SIGN AI, COMBINING TILDE OVERLAY, SIDDHAM VOWEL SIGN AA\n    assert String.normalize(\"𑖹̴𑖯\", :nfc) == \"𑖹̴𑖯\"\n\n    # HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA,\n    # HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA\n    assert String.normalize(\"ֱָֹ֑׃ְ֬֟\", :nfc) == \"ֱָֹ֑׃ְ֬֟\"\n\n    # 095D (exclusion list)\n    # HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA,\n    # HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA\n    assert String.normalize(\"ֱָֹ֑׃ְ֬֟\", :nfc) == \"ֱָֹ֑׃ְ֬֟\"\n\n    # 095D (exclusion list)\n    # 0922 093C\n    # DEVANAGARI LETTER RHA\n    assert String.normalize(\"ढ़\", :nfc) == \"ढ़\"\n\n    # 0061 0315 0300 05AE 0340 0062\n    # 00E0 05AE 0300 0315 0062\n    # LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT,\n    # HEBREW ACCENT ZINOR, COMBINING GRAVE TONE MARK, LATIN SMALL LETTER B\n    assert String.normalize(\"à֮̀̕b\", :nfc) == \"à֮̀̕b\"\n\n    # 0344\n    # 0308 0301\n    # COMBINING GREEK DIALYTIKA TONOS\n    assert String.normalize(\"\\u0344\", :nfc) == \"\\u0308\\u0301\"\n\n    # 115B9 0334 115AF\n    # 115B9 0334 115AF\n    # SIDDHAM VOWEL SIGN AI, COMBINING TILDE OVERLAY, SIDDHAM VOWEL SIGN AA\n    assert String.normalize(\"𑖹̴𑖯\", :nfc) == \"𑖹̴𑖯\"\n\n    # (ﬀ; ﬀ; ﬀ; ff; ff; ) LATIN SMALL LIGATURE FF\n    # FB00;FB00;FB00;0066 0066;0066 0066;\n    assert String.normalize(\"ﬀ\", :nfkd) == \"\\u0066\\u0066\"\n\n    # (ﬂ; ﬂ; ﬂ; fl; fl; ) LATIN SMALL LIGATURE FL\n    # FB02;FB02;FB02;0066 006C;0066 006C;\n    assert String.normalize(\"ﬂ\", :nfkd) == \"\\u0066\\u006C\"\n\n    # (ﬅ; ﬅ; ﬅ; st; st; ) LATIN SMALL LIGATURE LONG S T\n    # FB05;FB05;FB05;0073 0074;0073 0074;\n    assert String.normalize(\"ﬅ\", :nfkd) == \"\\u0073\\u0074\"\n\n    # (ﬆ; ﬆ; ﬆ; st; st; ) LATIN SMALL LIGATURE ST\n    # FB06;FB06;FB06;0073 0074;0073 0074;\n    assert String.normalize(\"\\u0073\\u0074\", :nfkc) == \"\\u0073\\u0074\"\n\n    # (ﬓ; ﬓ; ﬓ; մն; մն; ) ARMENIAN SMALL LIGATURE MEN NOW\n    # FB13;FB13;FB13;0574 0576;0574 0576;\n    assert String.normalize(\"\\u0574\\u0576\", :nfkc) == \"\\u0574\\u0576\"\n  end\n\n  # Carriage return can be a grapheme cluster if followed by\n  # newline so we test some corner cases here.\n  test \"carriage return\" do\n    assert String.at(\"\\r\\t\\v\", 0) == \"\\r\"\n    assert String.at(\"\\r\\t\\v\", 1) == \"\\t\"\n    assert String.at(\"\\r\\t\\v\", 2) == \"\\v\"\n    assert String.at(\"\\xFF\\r\\t\\v\", 1) == \"\\r\"\n    assert String.at(\"\\r\\xFF\\t\\v\", 2) == \"\\t\"\n    assert String.at(\"\\r\\t\\xFF\\v\", 3) == \"\\v\"\n\n    assert String.last(\"\\r\\t\\v\") == \"\\v\"\n    assert String.last(\"\\r\\xFF\\t\\xFF\\v\") == \"\\v\"\n\n    assert String.next_grapheme(\"\\r\\t\\v\") == {\"\\r\", \"\\t\\v\"}\n    assert String.next_grapheme(\"\\t\\v\") == {\"\\t\", \"\\v\"}\n    assert String.next_grapheme(\"\\v\") == {\"\\v\", \"\"}\n\n    assert String.length(\"\\r\\t\\v\") == 3\n    assert String.length(\"\\r\\xFF\\t\\v\") == 4\n    assert String.length(\"\\r\\t\\xFF\\v\") == 4\n\n    assert String.bag_distance(\"\\r\\t\\xFF\\v\", \"\\xFF\\r\\n\\xFF\") == 0.25\n    assert String.split(\"\\r\\t\\v\", \"\") == [\"\", \"\\r\", \"\\t\", \"\\v\", \"\"]\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/supervisor_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule SupervisorTest do\n  use ExUnit.Case, async: true\n\n  defmodule Stack do\n    use GenServer\n\n    def start_link({state, opts}) do\n      GenServer.start_link(__MODULE__, state, opts)\n    end\n\n    def init(args) do\n      {:ok, args}\n    end\n\n    def handle_call(:pop, _from, [h | t]) do\n      {:reply, h, t}\n    end\n\n    def handle_call(:stop, _from, stack) do\n      # There is a race condition between genserver terminations.\n      # So we will explicitly unregister it here.\n      try do\n        self() |> Process.info(:registered_name) |> elem(1) |> Process.unregister()\n      rescue\n        _ -> :ok\n      end\n\n      {:stop, :normal, :ok, stack}\n    end\n\n    def handle_cast({:push, h}, t) do\n      {:noreply, [h | t]}\n    end\n  end\n\n  defmodule Stack.Sup do\n    use Supervisor\n\n    def init(pair) do\n      Supervisor.init([{Stack, pair}], strategy: :one_for_one)\n    end\n  end\n\n  test \"generates child_spec/1\" do\n    assert Stack.Sup.child_spec([:hello]) == %{\n             id: Stack.Sup,\n             start: {Stack.Sup, :start_link, [[:hello]]},\n             type: :supervisor\n           }\n\n    defmodule CustomSup do\n      use Supervisor,\n        id: :id,\n        restart: :temporary,\n        start: {:foo, :bar, []}\n\n      def init(arg) do\n        arg\n      end\n    end\n\n    assert CustomSup.child_spec([:hello]) == %{\n             id: :id,\n             restart: :temporary,\n             start: {:foo, :bar, []},\n             type: :supervisor\n           }\n  end\n\n  test \"child_spec/2\" do\n    assert Supervisor.child_spec(Task, []) ==\n             %{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}}\n\n    assert Supervisor.child_spec({Task, :foo}, []) ==\n             %{id: Task, restart: :temporary, start: {Task, :start_link, [:foo]}}\n\n    assert Supervisor.child_spec(%{id: Task}, []) == %{id: Task}\n\n    assert Supervisor.child_spec(\n             Task,\n             id: :foo,\n             start: {:foo, :bar, []},\n             restart: :permanent,\n             shutdown: :infinity\n           ) == %{id: :foo, start: {:foo, :bar, []}, restart: :permanent, shutdown: :infinity}\n\n    message = ~r\"The module SupervisorTest was given as a child.*\\nbut it does not implement\"m\n\n    assert_raise ArgumentError, message, fn ->\n      Supervisor.child_spec(SupervisorTest, [])\n    end\n\n    message = ~r\"The module Unknown was given as a child.*but it does not exist\"m\n\n    assert_raise ArgumentError, message, fn ->\n      Supervisor.child_spec(Unknown, [])\n    end\n\n    message = ~r\"supervisors expect each child to be one of\"\n\n    assert_raise ArgumentError, message, fn ->\n      Supervisor.child_spec(\"other\", [])\n    end\n  end\n\n  test \"init/2\" do\n    flags = %{intensity: 3, period: 5, strategy: :one_for_one, auto_shutdown: :never}\n    children = [%{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}}]\n    assert Supervisor.init([Task], strategy: :one_for_one) == {:ok, {flags, children}}\n\n    flags = %{intensity: 1, period: 2, strategy: :one_for_all, auto_shutdown: :never}\n    children = [%{id: Task, restart: :temporary, start: {Task, :start_link, [:foo]}}]\n\n    assert Supervisor.init(\n             [{Task, :foo}],\n             strategy: :one_for_all,\n             max_restarts: 1,\n             max_seconds: 2\n           ) == {:ok, {flags, children}}\n\n    assert_raise ArgumentError, \"expected :strategy option to be given\", fn ->\n      Supervisor.init([], [])\n    end\n  end\n\n  test \"init/2 with old and new child specs\" do\n    flags = %{intensity: 3, period: 5, strategy: :one_for_one, auto_shutdown: :never}\n\n    children = [\n      %{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}},\n      old_spec = {Task, {Task, :start_link, []}, :permanent, 5000, :worker, [Task]}\n    ]\n\n    assert Supervisor.init([Task, old_spec], strategy: :one_for_one) ==\n             {:ok, {flags, children}}\n  end\n\n  test \"start_link/2 with via\" do\n    Supervisor.start_link([], strategy: :one_for_one, name: {:via, :global, :via_sup})\n    assert Supervisor.which_children({:via, :global, :via_sup}) == []\n  end\n\n  test \"start_link/3 with global\" do\n    Supervisor.start_link([], strategy: :one_for_one, name: {:global, :global_sup})\n    assert Supervisor.which_children({:global, :global_sup}) == []\n  end\n\n  test \"start_link/3 with local\" do\n    Supervisor.start_link([], strategy: :one_for_one, name: :my_sup)\n    assert Supervisor.which_children(:my_sup) == []\n  end\n\n  test \"start_link/2\" do\n    children = [{Stack, {[:hello], [name: :dyn_stack]}}]\n    {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)\n\n    wait_until_registered(:dyn_stack)\n    assert GenServer.call(:dyn_stack, :pop) == :hello\n    assert GenServer.call(:dyn_stack, :stop) == :ok\n\n    wait_until_registered(:dyn_stack)\n    assert GenServer.call(:dyn_stack, :pop) == :hello\n    Supervisor.stop(pid)\n\n    assert_raise ArgumentError, ~r\"expected :name option to be one of the following:\", fn ->\n      name = \"my_gen_server_name\"\n      Supervisor.start_link(children, name: name, strategy: :one_for_one)\n    end\n\n    assert_raise ArgumentError, ~r\"expected :name option to be one of the following:\", fn ->\n      name = {:invalid_tuple, \"my_gen_server_name\"}\n      Supervisor.start_link(children, name: name, strategy: :one_for_one)\n    end\n\n    assert_raise ArgumentError, ~r\"expected :name option to be one of the following:\", fn ->\n      name = {:via, \"Via\", \"my_gen_server_name\"}\n      Supervisor.start_link(children, name: name, strategy: :one_for_one)\n    end\n  end\n\n  test \"start_link/2 with old and new specs\" do\n    children = [\n      {Stack, {[:hello], []}},\n      {:old_stack, {SupervisorTest.Stack, :start_link, [{[:hello], []}]}, :permanent, 5000,\n       :worker, [SupervisorTest.Stack]}\n    ]\n\n    {:ok, _} = Supervisor.start_link(children, strategy: :one_for_one)\n  end\n\n  test \"start_link/3\" do\n    {:ok, pid} = Supervisor.start_link(Stack.Sup, {[:hello], [name: :stat_stack]})\n    wait_until_registered(:stat_stack)\n    assert GenServer.call(:stat_stack, :pop) == :hello\n    Supervisor.stop(pid)\n  end\n\n  describe \"start_child/2\" do\n    test \"supports old child spec\" do\n      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n      child = {Task, {Task, :start_link, [fn -> :ok end]}, :temporary, 5000, :worker, [Task]}\n      assert {:ok, pid} = Supervisor.start_child(pid, child)\n      assert is_pid(pid)\n    end\n\n    test \"supports new child spec as tuple\" do\n      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n      child = %{id: Task, restart: :temporary, start: {Task, :start_link, [fn -> :ok end]}}\n      assert {:ok, pid} = Supervisor.start_child(pid, child)\n      assert is_pid(pid)\n    end\n\n    test \"supports new child spec\" do\n      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n      child = {Task, fn -> :timer.sleep(:infinity) end}\n      assert {:ok, pid} = Supervisor.start_child(pid, child)\n      assert is_pid(pid)\n    end\n\n    test \"with invalid child spec\" do\n      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n\n      assert Supervisor.start_child(pid, %{}) == {:error, :missing_id}\n      assert Supervisor.start_child(pid, {1, 2, 3, 4, 5, 6}) == {:error, {:invalid_mfa, 2}}\n\n      assert Supervisor.start_child(pid, %{id: 1, start: {Task, :foo, :bar}}) ==\n               {:error, {:invalid_mfa, {Task, :foo, :bar}}}\n\n      assert Supervisor.start_child(pid, %{id: 1, start: {Task, :foo, [:bar]}, shutdown: -1}) ==\n               {:error, {:invalid_shutdown, -1}}\n    end\n\n    test \"with valid child spec\" do\n      Process.flag(:trap_exit, true)\n\n      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n\n      for n <- 0..1 do\n        assert {:ok, child_pid} =\n                 Supervisor.start_child(pid, %{\n                   id: n,\n                   start: {Task, :start_link, [fn -> Process.sleep(:infinity) end]},\n                   shutdown: n\n                 })\n\n        assert_kill(child_pid, :shutdown)\n      end\n    end\n  end\n\n  test \"child life cycle\" do\n    {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n\n    assert Supervisor.which_children(pid) == []\n    assert Supervisor.count_children(pid) == %{specs: 0, active: 0, supervisors: 0, workers: 0}\n\n    child_spec = Supervisor.child_spec({Stack, {[:hello], []}}, [])\n    {:ok, stack} = Supervisor.start_child(pid, child_spec)\n    assert GenServer.call(stack, :pop) == :hello\n\n    assert Supervisor.which_children(pid) ==\n             [{SupervisorTest.Stack, stack, :worker, [SupervisorTest.Stack]}]\n\n    assert Supervisor.count_children(pid) == %{specs: 1, active: 1, supervisors: 0, workers: 1}\n\n    assert Supervisor.delete_child(pid, Stack) == {:error, :running}\n    assert Supervisor.terminate_child(pid, Stack) == :ok\n\n    {:ok, stack} = Supervisor.restart_child(pid, Stack)\n    assert GenServer.call(stack, :pop) == :hello\n\n    assert Supervisor.terminate_child(pid, Stack) == :ok\n    assert Supervisor.delete_child(pid, Stack) == :ok\n    Supervisor.stop(pid)\n  end\n\n  defp wait_until_registered(name) do\n    if !Process.whereis(name) do\n      wait_until_registered(name)\n    end\n  end\n\n  defp assert_kill(pid, reason) do\n    ref = Process.monitor(pid)\n    Process.exit(pid, reason)\n    assert_receive {:DOWN, ^ref, _, _, _}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/system_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule SystemTest do\n  use ExUnit.Case\n  import PathHelpers\n\n  test \"build_info/0\" do\n    build_info = System.build_info()\n    assert is_map(build_info)\n    assert is_binary(build_info[:build])\n    assert is_binary(build_info[:date])\n    assert is_binary(build_info[:revision])\n    assert is_binary(build_info[:version])\n    assert is_binary(build_info[:otp_release])\n\n    if build_info[:revision] != \"\" do\n      assert String.length(build_info[:revision]) >= 7\n    end\n\n    version_file = Path.join([__DIR__, \"../../../..\", \"VERSION\"]) |> Path.expand()\n    {:ok, version} = File.read(version_file)\n    assert build_info[:version] == String.trim(version)\n    assert build_info[:build] =~ \"compiled with Erlang/OTP\"\n  end\n\n  test \"user_home/0\" do\n    assert is_binary(System.user_home())\n    assert is_binary(System.user_home!())\n  end\n\n  test \"tmp_dir/0\" do\n    assert is_binary(System.tmp_dir())\n    assert is_binary(System.tmp_dir!())\n  end\n\n  test \"endianness/0\" do\n    assert System.endianness() in [:little, :big]\n    assert System.endianness() == System.compiled_endianness()\n  end\n\n  test \"pid/0\" do\n    assert is_binary(System.pid())\n  end\n\n  test \"argv/0\" do\n    list = elixir(~c\"-e \\\"IO.inspect System.argv()\\\" -- -o opt arg1 arg2 --long-opt 10\")\n    {args, _} = Code.eval_string(list, [])\n    assert args == [\"-o\", \"opt\", \"arg1\", \"arg2\", \"--long-opt\", \"10\"]\n  end\n\n  @test_var \"SYSTEM_ELIXIR_ENV_TEST_VAR\"\n\n  test \"get_env/put_env/delete_env\" do\n    assert System.get_env(@test_var) == nil\n    assert System.get_env(@test_var, \"SAMPLE\") == \"SAMPLE\"\n    assert System.fetch_env(@test_var) == :error\n\n    message = \"could not fetch environment variable #{inspect(@test_var)} because it is not set\"\n    assert_raise System.EnvError, message, fn -> System.fetch_env!(@test_var) end\n\n    System.put_env(@test_var, \"SAMPLE\")\n\n    assert System.get_env(@test_var) == \"SAMPLE\"\n    assert System.get_env()[@test_var] == \"SAMPLE\"\n    assert System.fetch_env(@test_var) == {:ok, \"SAMPLE\"}\n    assert System.fetch_env!(@test_var) == \"SAMPLE\"\n\n    System.delete_env(@test_var)\n    assert System.get_env(@test_var) == nil\n\n    assert_raise ArgumentError, ~r[cannot execute System.put_env/2 for key with \\\"=\\\"], fn ->\n      System.put_env(\"FOO=BAR\", \"BAZ\")\n    end\n  end\n\n  test \"put_env/2\" do\n    System.put_env(%{@test_var => \"MAP_STRING\"})\n    assert System.get_env(@test_var) == \"MAP_STRING\"\n\n    System.put_env([{String.to_atom(@test_var), \"KW_ATOM\"}])\n    assert System.get_env(@test_var) == \"KW_ATOM\"\n\n    System.put_env([{String.to_atom(@test_var), nil}])\n    assert System.get_env(@test_var) == nil\n  end\n\n  test \"cmd/2 raises for null bytes\" do\n    assert_raise ArgumentError, ~r\"cannot execute System.cmd/3 for program with null byte\", fn ->\n      System.cmd(\"null\\0byte\", [])\n    end\n  end\n\n  test \"cmd/3 raises with non-binary arguments\" do\n    assert_raise ArgumentError, ~r\"all arguments for System.cmd/3 must be binaries\", fn ->\n      System.cmd(\"ls\", [~c\"/usr\"])\n    end\n  end\n\n  describe \"Windows\" do\n    @describetag :windows\n\n    test \"cmd/2\" do\n      assert {\"hello\\r\\n\", 0} = System.cmd(\"cmd\", ~w[/c echo hello])\n    end\n\n    test \"cmd/3 (with options)\" do\n      opts = [\n        into: [],\n        cd: File.cwd!(),\n        env: %{\"foo\" => \"bar\", \"baz\" => nil},\n        arg0: \"echo\",\n        stderr_to_stdout: true,\n        parallelism: true,\n        use_stdio: true\n      ]\n\n      assert {[\"hello\\r\\n\"], 0} = System.cmd(\"cmd\", ~w[/c echo hello], opts)\n    end\n\n    @echo \"echo-elixir-test\"\n    @tag :tmp_dir\n    test \"cmd/3 with absolute and relative paths\", config do\n      echo = Path.join(config.tmp_dir, @echo)\n      File.mkdir_p!(Path.dirname(echo))\n      File.ln_s!(System.find_executable(\"cmd\"), echo)\n\n      File.cd!(Path.dirname(echo), fn ->\n        # There is a bug in OTP where find_executable is finding\n        # entries on the current directory. If this is the case,\n        # we should avoid the assertion below.\n        if !System.find_executable(@echo) do\n          assert :enoent = catch_error(System.cmd(@echo, ~w[/c echo hello]))\n        end\n\n        assert {\"hello\\r\\n\", 0} =\n                 System.cmd(Path.join(File.cwd!(), @echo), ~w[/c echo hello], [{:arg0, \"echo\"}])\n      end)\n    end\n\n    test \"shell/1\" do\n      assert {\"hello\\r\\n\", 0} = System.shell(\"echo hello\")\n    end\n\n    test \"shell/2 (with options)\" do\n      opts = [\n        into: [],\n        cd: File.cwd!(),\n        env: %{\"foo\" => \"bar\", \"baz\" => nil},\n        stderr_to_stdout: true,\n        parallelism: true,\n        use_stdio: true\n      ]\n\n      assert {[\"bar\\r\\n\"], 0} = System.shell(\"echo %foo%\", opts)\n    end\n  end\n\n  describe \"Unix\" do\n    @describetag :unix\n\n    test \"cmd/2\" do\n      assert {\"hello\\n\", 0} = System.cmd(\"echo\", [\"hello\"])\n    end\n\n    test \"cmd/3 (with options)\" do\n      opts = [\n        into: [],\n        cd: File.cwd!(),\n        env: %{\"foo\" => \"bar\", \"baz\" => nil},\n        arg0: \"echo\",\n        stderr_to_stdout: true,\n        parallelism: true,\n        use_stdio: true\n      ]\n\n      assert {[\"hello\\n\"], 0} = System.cmd(\"echo\", [\"hello\"], opts)\n    end\n\n    test \"cmd/3 (can't use `use_stdio: false, stderr_to_stdout: true`)\" do\n      opts = [\n        into: [],\n        cd: File.cwd!(),\n        env: %{\"foo\" => \"bar\", \"baz\" => nil},\n        arg0: \"echo\",\n        stderr_to_stdout: true,\n        use_stdio: false\n      ]\n\n      message = ~r\"cannot use \\\"stderr_to_stdout: true\\\" and \\\"use_stdio: false\\\"\"\n\n      assert_raise ArgumentError, message, fn ->\n        System.cmd(\"echo\", [\"hello\"], opts)\n      end\n    end\n\n    test \"cmd/3 by line\" do\n      assert {[\"hello\", \"world\"], 0} =\n               System.cmd(\"echo\", [\"hello\\nworld\"], into: [], lines: 1024)\n\n      assert {[\"hello\", \"world\"], 0} =\n               System.cmd(\"echo\", [\"-n\", \"hello\\nworld\"], into: [], lines: 3)\n    end\n\n    @echo \"echo-elixir-test\"\n    @tag :tmp_dir\n    test \"cmd/3 with absolute and relative paths\", config do\n      echo = Path.join(config.tmp_dir, @echo)\n      File.mkdir_p!(Path.dirname(echo))\n      File.ln_s!(System.find_executable(\"echo\"), echo)\n\n      File.cd!(Path.dirname(echo), fn ->\n        # There is a bug in OTP where find_executable is finding\n        # entries on the current directory. If this is the case,\n        # we should avoid the assertion below.\n        if !System.find_executable(@echo) do\n          assert :enoent = catch_error(System.cmd(@echo, [\"hello\"]))\n        end\n\n        assert {\"hello\\n\", 0} =\n                 System.cmd(Path.join(File.cwd!(), @echo), [\"hello\"], [{:arg0, \"echo\"}])\n      end)\n    end\n\n    test \"shell/1\" do\n      assert {\"hello\\n\", 0} = System.shell(\"echo hello\")\n    end\n\n    test \"shell/1 with interpolation\" do\n      assert {\"1\\n2\\n\", 0} = System.shell(\"x=1; echo $x; echo '2'\")\n    end\n\n    test \"shell/1 with empty string\" do\n      assert {\"\", 0} = System.shell(\"\")\n      assert {\"\", 0} = System.shell(\"  \")\n    end\n\n    @tag timeout: 1_000\n    test \"shell/1 returns when command awaits input\" do\n      assert {\"\", 0} = System.shell(\"cat\", close_stdin: true)\n    end\n\n    test \"shell/1 with comment\" do\n      assert {\"1\\n\", 0} = System.shell(\"echo '1' # comment\")\n    end\n\n    test \"shell/2 (with options)\" do\n      opts = [\n        into: [],\n        cd: File.cwd!(),\n        env: %{\"foo\" => \"bar\", \"baz\" => nil},\n        stderr_to_stdout: true,\n        use_stdio: true\n      ]\n\n      assert {[\"bar\\n\"], 0} = System.shell(\"echo $foo\", opts)\n    end\n  end\n\n  @tag :unix\n  test \"vm signals\" do\n    assert System.trap_signal(:sigquit, :example, fn -> :ok end) == {:ok, :example}\n    assert System.trap_signal(:sigquit, :example, fn -> :ok end) == {:error, :already_registered}\n    assert {:ok, ref} = System.trap_signal(:sigquit, fn -> :ok end)\n\n    assert System.untrap_signal(:sigquit, :example) == :ok\n    assert System.trap_signal(:sigquit, :example, fn -> :ok end) == {:ok, :example}\n    assert System.trap_signal(:sigquit, ref, fn -> :ok end) == {:error, :already_registered}\n\n    assert System.untrap_signal(:sigusr1, :example) == {:error, :not_found}\n    assert System.untrap_signal(:sigquit, :example) == :ok\n    assert System.untrap_signal(:sigquit, :example) == {:error, :not_found}\n    assert System.untrap_signal(:sigquit, ref) == :ok\n    assert System.untrap_signal(:sigquit, ref) == {:error, :not_found}\n  end\n\n  @tag :unix\n  test \"os signals\" do\n    parent = self()\n\n    assert System.trap_signal(:sighup, :example, fn ->\n             send(parent, :sighup_called)\n             :ok\n           end) == {:ok, :example}\n\n    {\"\", 0} = System.cmd(\"kill\", [\"-s\", \"hup\", System.pid()])\n\n    assert_receive :sighup_called\n  after\n    System.untrap_signal(:sighup, :example)\n  end\n\n  test \"find_executable/1\" do\n    assert System.find_executable(\"erl\")\n    assert is_binary(System.find_executable(\"erl\"))\n    assert !System.find_executable(\"does-not-really-exist-from-elixir\")\n\n    message = ~r\"cannot execute System.find_executable/1 for program with null byte\"\n\n    assert_raise ArgumentError, message, fn ->\n      System.find_executable(\"null\\0byte\")\n    end\n  end\n\n  test \"monotonic_time/0\" do\n    assert is_integer(System.monotonic_time())\n  end\n\n  test \"monotonic_time/1\" do\n    assert is_integer(System.monotonic_time(:nanosecond))\n    assert abs(System.monotonic_time(:microsecond)) < abs(System.monotonic_time(:nanosecond))\n  end\n\n  test \"system_time/0\" do\n    assert is_integer(System.system_time())\n  end\n\n  test \"system_time/1\" do\n    assert is_integer(System.system_time(:nanosecond))\n    assert abs(System.system_time(:microsecond)) < abs(System.system_time(:nanosecond))\n  end\n\n  test \"time_offset/0 and time_offset/1\" do\n    assert is_integer(System.time_offset())\n    assert is_integer(System.time_offset(:second))\n  end\n\n  test \"os_time/0\" do\n    assert is_integer(System.os_time())\n  end\n\n  test \"os_time/1\" do\n    assert is_integer(System.os_time(:nanosecond))\n    assert abs(System.os_time(:microsecond)) < abs(System.os_time(:nanosecond))\n  end\n\n  test \"unique_integer/0 and unique_integer/1\" do\n    assert is_integer(System.unique_integer())\n    assert System.unique_integer([:positive]) > 0\n\n    assert System.unique_integer([:positive, :monotonic]) <\n             System.unique_integer([:positive, :monotonic])\n  end\n\n  test \"convert_time_unit/3\" do\n    time = System.monotonic_time(:nanosecond)\n    assert abs(System.convert_time_unit(time, :nanosecond, :microsecond)) < abs(time)\n  end\n\n  test \"schedulers/0\" do\n    assert System.schedulers() >= 1\n  end\n\n  test \"schedulers_online/0\" do\n    assert System.schedulers_online() >= 1\n  end\n\n  test \"otp_release/0\" do\n    assert is_binary(System.otp_release())\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/task/supervisor_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Task.SupervisorTest do\n  use ExUnit.Case\n\n  @moduletag :capture_log\n\n  setup do\n    {:ok, pid} = Task.Supervisor.start_link()\n    {:ok, supervisor: pid}\n  end\n\n  def wait_and_send(caller, atom) do\n    send(caller, :ready)\n    receive do: (true -> true)\n    send(caller, atom)\n  end\n\n  def sleep(number) do\n    Process.sleep(number)\n    number\n  end\n\n  test \"can be supervised directly\", config do\n    modules = [{Task.Supervisor, name: config.test}]\n    assert {:ok, _} = Supervisor.start_link(modules, strategy: :one_for_one)\n    assert Process.whereis(config.test)\n  end\n\n  test \"start with spawn_opt\" do\n    {:ok, pid} = Task.Supervisor.start_link(spawn_opt: [priority: :high])\n    assert Process.info(pid, :priority) == {:priority, :high}\n  end\n\n  test \"multiple supervisors can be supervised and identified with simple child spec\" do\n    {:ok, _} = Registry.start_link(keys: :unique, name: TaskSup.Registry)\n\n    children = [\n      {Task.Supervisor, strategy: :one_for_one, name: :simple_name},\n      {Task.Supervisor, strategy: :one_for_one, name: {:global, :global_name}},\n      {Task.Supervisor,\n       strategy: :one_for_one, name: {:via, Registry, {TaskSup.Registry, \"via_name\"}}}\n    ]\n\n    assert {:ok, supsup} = Supervisor.start_link(children, strategy: :one_for_one)\n\n    assert {:ok, no_name_dynsup} =\n             Supervisor.start_child(supsup, {Task.Supervisor, strategy: :one_for_one})\n\n    assert Task.Supervisor.children(:simple_name) == []\n    assert Task.Supervisor.children({:global, :global_name}) == []\n    assert Task.Supervisor.children({:via, Registry, {TaskSup.Registry, \"via_name\"}}) == []\n    assert Task.Supervisor.children(no_name_dynsup) == []\n\n    assert Supervisor.start_child(supsup, {Task.Supervisor, strategy: :one_for_one}) ==\n             {:error, {:already_started, no_name_dynsup}}\n  end\n\n  test \"counts and returns children\", config do\n    assert Task.Supervisor.children(config[:supervisor]) == []\n\n    assert Supervisor.count_children(config[:supervisor]) ==\n             %{active: 0, specs: 0, supervisors: 0, workers: 0}\n\n    assert DynamicSupervisor.count_children(config[:supervisor]) ==\n             %{active: 0, specs: 0, supervisors: 0, workers: 0}\n  end\n\n  describe \"async/1\" do\n    test \"spawns tasks under the supervisor\", config do\n      parent = self()\n      fun = fn -> wait_and_send(parent, :done) end\n      task = Task.Supervisor.async(config[:supervisor], fun)\n      assert Task.Supervisor.children(config[:supervisor]) == [task.pid]\n\n      # Assert the struct\n      assert task.__struct__ == Task\n      assert is_pid(task.pid)\n      assert is_reference(task.ref)\n\n      # Assert the link\n      {:links, links} = Process.info(self(), :links)\n      assert task.pid in links\n\n      receive do: (:ready -> :ok)\n\n      # Assert the initial call\n      {:name, fun_name} = Function.info(fun, :name)\n      assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(task.pid)\n\n      # Run the task\n      send(task.pid, true)\n\n      # Assert response and monitoring messages\n      ref = task.ref\n      assert_receive {^ref, :done}\n      assert_receive {:DOWN, ^ref, _, _, :normal}\n    end\n\n    test \"with custom shutdown\", config do\n      Process.flag(:trap_exit, true)\n      parent = self()\n\n      fun = fn -> wait_and_send(parent, :done) end\n      %{pid: pid} = Task.Supervisor.async(config[:supervisor], fun, shutdown: :brutal_kill)\n\n      Process.exit(config[:supervisor], :shutdown)\n      assert_receive {:DOWN, _, _, ^pid, :killed}\n    end\n\n    test \"raises when :max_children is reached\" do\n      {:ok, sup} = Task.Supervisor.start_link(max_children: 1)\n      Task.Supervisor.async(sup, fn -> Process.sleep(:infinity) end)\n\n      assert_raise RuntimeError, ~r/reached the maximum number of tasks/, fn ->\n        Task.Supervisor.async(sup, fn -> :ok end)\n      end\n    end\n\n    test \"with $callers\", config do\n      sup = config[:supervisor]\n      grandparent = self()\n\n      Task.Supervisor.async(sup, fn ->\n        parent = self()\n        assert Process.get(:\"$callers\") == [grandparent]\n        assert Process.get(:\"$ancestors\") == [sup, grandparent]\n\n        Task.Supervisor.async(sup, fn ->\n          assert Process.get(:\"$callers\") == [parent, grandparent]\n          assert Process.get(:\"$ancestors\") == [sup, grandparent]\n        end)\n        |> Task.await()\n      end)\n      |> Task.await()\n    end\n  end\n\n  test \"async/3\", config do\n    args = [self(), :done]\n    task = Task.Supervisor.async(config[:supervisor], __MODULE__, :wait_and_send, args)\n    assert Task.Supervisor.children(config[:supervisor]) == [task.pid]\n\n    receive do: (:ready -> :ok)\n    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(task.pid)\n\n    send(task.pid, true)\n    assert task.__struct__ == Task\n    assert task.mfa == {__MODULE__, :wait_and_send, 2}\n    assert Task.await(task) == :done\n  end\n\n  describe \"async_nolink/1\" do\n    test \"spawns a task under the supervisor without linking to the caller\", config do\n      parent = self()\n      fun = fn -> wait_and_send(parent, :done) end\n      task = Task.Supervisor.async_nolink(config[:supervisor], fun)\n      assert Task.Supervisor.children(config[:supervisor]) == [task.pid]\n\n      # Assert the struct\n      assert task.__struct__ == Task\n      assert is_pid(task.pid)\n      assert is_reference(task.ref)\n      assert task.mfa == {:erlang, :apply, 2}\n\n      # Refute the link\n      {:links, links} = Process.info(self(), :links)\n      refute task.pid in links\n\n      receive do: (:ready -> :ok)\n\n      # Assert the initial call\n      {:name, fun_name} = Function.info(fun, :name)\n      assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(task.pid)\n\n      # Run the task\n      send(task.pid, true)\n\n      # Assert response and monitoring messages\n      ref = task.ref\n      assert_receive {^ref, :done}\n      assert_receive {:DOWN, ^ref, _, _, :normal}\n    end\n\n    test \"with custom shutdown\", config do\n      Process.flag(:trap_exit, true)\n      parent = self()\n\n      fun = fn -> wait_and_send(parent, :done) end\n      %{pid: pid} = Task.Supervisor.async_nolink(config[:supervisor], fun, shutdown: :brutal_kill)\n\n      Process.exit(config[:supervisor], :shutdown)\n      assert_receive {:DOWN, _, _, ^pid, :killed}\n    end\n\n    test \"raises when :max_children is reached\" do\n      {:ok, sup} = Task.Supervisor.start_link(max_children: 1)\n\n      Task.Supervisor.async_nolink(sup, fn -> Process.sleep(:infinity) end)\n\n      assert_raise RuntimeError, ~r/reached the maximum number of tasks/, fn ->\n        Task.Supervisor.async_nolink(sup, fn -> :ok end)\n      end\n    end\n  end\n\n  test \"async_nolink/3\", config do\n    args = [self(), :done]\n    task = Task.Supervisor.async_nolink(config[:supervisor], __MODULE__, :wait_and_send, args)\n    assert Task.Supervisor.children(config[:supervisor]) == [task.pid]\n\n    receive do: (:ready -> :ok)\n    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(task.pid)\n\n    send(task.pid, true)\n    assert task.__struct__ == Task\n    assert task.mfa == {__MODULE__, :wait_and_send, 2}\n    assert Task.await(task) == :done\n  end\n\n  test \"start_child/1\", config do\n    parent = self()\n    fun = fn -> wait_and_send(parent, :done) end\n    {:ok, pid} = Task.Supervisor.start_child(config[:supervisor], fun)\n    assert Task.Supervisor.children(config[:supervisor]) == [pid]\n\n    {:links, links} = Process.info(self(), :links)\n    refute pid in links\n\n    receive do: (:ready -> :ok)\n    {:name, fun_name} = Function.info(fun, :name)\n    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(pid)\n\n    send(pid, true)\n    assert_receive :done\n  end\n\n  test \"start_child/3\", config do\n    args = [self(), :done]\n\n    {:ok, pid} =\n      Task.Supervisor.start_child(config[:supervisor], __MODULE__, :wait_and_send, args)\n\n    assert Task.Supervisor.children(config[:supervisor]) == [pid]\n\n    {:links, links} = Process.info(self(), :links)\n    refute pid in links\n\n    receive do: (:ready -> :ok)\n    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(pid)\n\n    send(pid, true)\n    assert_receive :done\n  end\n\n  test \"start_child/1 with custom shutdown\", config do\n    Process.flag(:trap_exit, true)\n    parent = self()\n\n    fun = fn -> wait_and_send(parent, :done) end\n    {:ok, pid} = Task.Supervisor.start_child(config[:supervisor], fun, shutdown: :brutal_kill)\n\n    Process.monitor(pid)\n    Process.exit(config[:supervisor], :shutdown)\n    assert_receive {:DOWN, _, _, ^pid, :killed}\n  end\n\n  test \"start_child/1 with custom restart\", config do\n    parent = self()\n\n    fun = fn -> wait_and_send(parent, :done) end\n    {:ok, pid} = Task.Supervisor.start_child(config[:supervisor], fun, restart: :permanent)\n\n    assert_receive :ready\n    Process.monitor(pid)\n    Process.exit(pid, :shutdown)\n    assert_receive {:DOWN, _, _, ^pid, :shutdown}\n    assert_receive :ready\n  end\n\n  test \"start_child/1 with $callers\", config do\n    sup = config[:supervisor]\n    grandparent = self()\n\n    Task.Supervisor.start_child(sup, fn ->\n      parent = self()\n      assert Process.get(:\"$callers\") == [grandparent]\n      assert Process.get(:\"$ancestors\") == [sup, grandparent]\n\n      Task.Supervisor.start_child(sup, fn ->\n        assert Process.get(:\"$callers\") == [parent, grandparent]\n        assert Process.get(:\"$ancestors\") == [sup, grandparent]\n        send(grandparent, :done)\n      end)\n    end)\n\n    assert_receive :done\n  end\n\n  test \"terminate_child/2\", config do\n    args = [self(), :done]\n\n    {:ok, pid} =\n      Task.Supervisor.start_child(config[:supervisor], __MODULE__, :wait_and_send, args)\n\n    assert Task.Supervisor.children(config[:supervisor]) == [pid]\n    assert Task.Supervisor.terminate_child(config[:supervisor], pid) == :ok\n    assert Task.Supervisor.children(config[:supervisor]) == []\n    assert Task.Supervisor.terminate_child(config[:supervisor], pid) == {:error, :not_found}\n  end\n\n  describe \"await/1\" do\n    test \"demonitors and unalias on timeout\", config do\n      task =\n        Task.Supervisor.async(config[:supervisor], fn ->\n          assert_receive :go\n          :done\n        end)\n\n      assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}\n      new_ref = Process.monitor(task.pid)\n      old_ref = task.ref\n\n      send(task.pid, :go)\n      assert_receive {:DOWN, ^new_ref, _, _, _}\n      refute_received {^old_ref, :done}\n      refute_received {:DOWN, ^old_ref, _, _, _}\n    end\n\n    test \"exits on task throw\", config do\n      Process.flag(:trap_exit, true)\n      task = Task.Supervisor.async(config[:supervisor], fn -> throw(:unknown) end)\n\n      assert {{{:nocatch, :unknown}, _}, {Task, :await, [^task, 5000]}} =\n               catch_exit(Task.await(task))\n    end\n\n    test \"exits on task error\", config do\n      Process.flag(:trap_exit, true)\n      task = Task.Supervisor.async(config[:supervisor], fn -> raise \"oops\" end)\n      assert {{%RuntimeError{}, _}, {Task, :await, [^task, 5000]}} = catch_exit(Task.await(task))\n    end\n\n    test \"exits on task exit\", config do\n      Process.flag(:trap_exit, true)\n      task = Task.Supervisor.async(config[:supervisor], fn -> exit(:unknown) end)\n      assert {:unknown, {Task, :await, [^task, 5000]}} = catch_exit(Task.await(task))\n    end\n  end\n\n  describe \"async_stream\" do\n    @opts []\n    test \"streams an enumerable with fun\", %{supervisor: supervisor} do\n      assert supervisor\n             |> Task.Supervisor.async_stream(1..4, &sleep/1, @opts)\n             |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n    end\n\n    test \"streams an enumerable with mfa\", %{supervisor: supervisor} do\n      assert supervisor\n             |> Task.Supervisor.async_stream(1..4, __MODULE__, :sleep, [], @opts)\n             |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n    end\n\n    test \"streams an enumerable without leaking tasks\", %{supervisor: supervisor} do\n      assert supervisor\n             |> Task.Supervisor.async_stream(1..4, &sleep/1, @opts)\n             |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n\n      refute_received _\n    end\n\n    test \"streams an enumerable with slowest first\", %{supervisor: supervisor} do\n      Process.flag(:trap_exit, true)\n\n      assert supervisor\n             |> Task.Supervisor.async_stream(4..1//-1, &sleep/1, @opts)\n             |> Enum.to_list() == [ok: 4, ok: 3, ok: 2, ok: 1]\n    end\n\n    test \"streams an enumerable with exits\", %{supervisor: supervisor} do\n      Process.flag(:trap_exit, true)\n\n      assert supervisor\n             |> Task.Supervisor.async_stream(1..4, &yield_and_exit(Integer.to_string(&1)), @opts)\n             |> Enum.to_list() == [exit: \"1\", exit: \"2\", exit: \"3\", exit: \"4\"]\n    end\n\n    test \"shuts down unused tasks\", %{supervisor: supervisor} do\n      collection = [0, :infinity, :infinity, :infinity]\n\n      assert supervisor\n             |> Task.Supervisor.async_stream(collection, &sleep/1, @opts)\n             |> Enum.take(1) == [ok: 0]\n\n      assert Process.info(self(), :links) == {:links, [supervisor]}\n    end\n\n    test \"shuts down unused tasks without leaking messages\", %{supervisor: supervisor} do\n      collection = [0, :infinity, :infinity, :infinity]\n\n      assert supervisor\n             |> Task.Supervisor.async_stream(collection, &sleep/1, @opts)\n             |> Enum.take(1) == [ok: 0]\n\n      refute_received _\n    end\n\n    test \"raises an error if :max_children is reached with clean stream shutdown\",\n         %{supervisor: unused_supervisor} do\n      {:ok, supervisor} = Task.Supervisor.start_link(max_children: 1)\n      collection = [:infinity, :infinity, :infinity]\n\n      assert_raise RuntimeError, ~r/reached the maximum number of tasks/, fn ->\n        supervisor\n        |> Task.Supervisor.async_stream(collection, &sleep/1, max_concurrency: 2)\n        |> Enum.to_list()\n      end\n\n      {:links, links} = Process.info(self(), :links)\n      assert MapSet.new(links) == MapSet.new([unused_supervisor, supervisor])\n      refute_received _\n    end\n\n    test \"with $callers\", config do\n      sup = config[:supervisor]\n      grandparent = self()\n\n      Task.Supervisor.async_stream(sup, [1], fn 1 ->\n        parent = self()\n        assert Process.get(:\"$callers\") == [grandparent]\n        assert Process.get(:\"$ancestors\") == [sup, grandparent]\n\n        Task.Supervisor.async_stream(sup, [1], fn 1 ->\n          assert Process.get(:\"$callers\") == [parent, grandparent]\n          assert Process.get(:\"$ancestors\") == [sup, grandparent]\n          send(grandparent, :done)\n        end)\n        |> Stream.run()\n      end)\n      |> Stream.run()\n\n      assert_receive :done\n    end\n\n    test \"consuming from another process\", config do\n      parent = self()\n      stream = Task.Supervisor.async_stream(config[:supervisor], [1, 2, 3], &send(parent, &1))\n      Task.start(Stream, :run, [stream])\n      assert_receive 1\n      assert_receive 2\n      assert_receive 3\n    end\n\n    test \"with timeout and :zip_input_on_exit set to true\", %{supervisor: supervisor} do\n      opts = Keyword.merge(@opts, zip_input_on_exit: true, on_timeout: :kill_task, timeout: 50)\n\n      assert supervisor\n             |> Task.Supervisor.async_stream([1, 100], &sleep/1, opts)\n             |> Enum.to_list() == [ok: 1, exit: {100, :timeout}]\n    end\n\n    test \"with outer halt on failure and :zip_input_on_exit\", %{supervisor: supervisor} do\n      Process.flag(:trap_exit, true)\n      opts = Keyword.merge(@opts, zip_input_on_exit: true)\n\n      assert supervisor\n             |> Task.Supervisor.async_stream(1..8, &exit/1, opts)\n             |> Enum.take(4) == [exit: {1, 1}, exit: {2, 2}, exit: {3, 3}, exit: {4, 4}]\n    end\n\n    test \"does not allow streaming with invalid :shutdown\", %{supervisor: supervisor} do\n      message = \":shutdown must be either a positive integer or :brutal_kill\"\n\n      assert_raise ArgumentError, message, fn ->\n        Task.Supervisor.async_stream(supervisor, [], fn _ -> :ok end, shutdown: :unknown)\n      end\n    end\n  end\n\n  describe \"async_stream_nolink\" do\n    @opts [max_concurrency: 4]\n\n    test \"streams an enumerable with fun\", %{supervisor: supervisor} do\n      assert supervisor\n             |> Task.Supervisor.async_stream_nolink(1..4, &sleep/1, @opts)\n             |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n    end\n\n    test \"streams an enumerable with mfa\", %{supervisor: supervisor} do\n      assert supervisor\n             |> Task.Supervisor.async_stream_nolink(1..4, __MODULE__, :sleep, [], @opts)\n             |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n    end\n\n    test \"streams an enumerable without leaking tasks\", %{supervisor: supervisor} do\n      assert supervisor\n             |> Task.Supervisor.async_stream_nolink(1..4, &sleep/1, @opts)\n             |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n\n      refute_received _\n    end\n\n    test \"streams an enumerable with slowest first\", %{supervisor: supervisor} do\n      assert supervisor\n             |> Task.Supervisor.async_stream_nolink(4..1//-1, &sleep/1, @opts)\n             |> Enum.to_list() == [ok: 4, ok: 3, ok: 2, ok: 1]\n    end\n\n    test \"streams an enumerable with exits\", %{supervisor: supervisor} do\n      assert supervisor\n             |> Task.Supervisor.async_stream_nolink(1..4, &yield_and_exit/1, @opts)\n             |> Enum.to_list() == [exit: 1, exit: 2, exit: 3, exit: 4]\n    end\n\n    test \"shuts down unused tasks\", %{supervisor: supervisor} do\n      collection = [0, :infinity, :infinity, :infinity]\n\n      assert supervisor\n             |> Task.Supervisor.async_stream_nolink(collection, &sleep/1, @opts)\n             |> Enum.take(1) == [ok: 0]\n\n      assert Process.info(self(), :links) == {:links, [supervisor]}\n    end\n\n    test \"shuts down unused tasks without leaking messages\", %{supervisor: supervisor} do\n      collection = [0, :infinity, :infinity, :infinity]\n\n      assert supervisor\n             |> Task.Supervisor.async_stream_nolink(collection, &sleep/1, @opts)\n             |> Enum.take(1) == [ok: 0]\n\n      refute_received _\n    end\n\n    test \"raises an error if :max_children is reached with clean stream shutdown\",\n         %{supervisor: unused_supervisor} do\n      {:ok, supervisor} = Task.Supervisor.start_link(max_children: 1)\n      collection = [:infinity, :infinity, :infinity]\n\n      assert_raise RuntimeError, ~r/reached the maximum number of tasks/, fn ->\n        supervisor\n        |> Task.Supervisor.async_stream_nolink(collection, &sleep/1, max_concurrency: 2)\n        |> Enum.to_list()\n      end\n\n      {:links, links} = Process.info(self(), :links)\n      assert MapSet.new(links) == MapSet.new([unused_supervisor, supervisor])\n      refute_received _\n    end\n  end\n\n  def yield_and_exit(value) do\n    # We call yield first so we give the parent a chance to monitor\n    :erlang.yield()\n    :erlang.exit(value)\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/task_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule TaskTest do\n  use ExUnit.Case\n  doctest Task\n  @moduletag :capture_log\n\n  def wait_and_send(caller, atom) do\n    send(caller, :ready)\n    receive do: (true -> true)\n    send(caller, atom)\n  end\n\n  defp create_task_in_other_process do\n    caller = self()\n    spawn(fn -> send(caller, Task.async(fn -> nil end)) end)\n    receive do: (task -> task)\n  end\n\n  defp create_dummy_task(reason) do\n    {pid, ref} = spawn_monitor(Kernel, :exit, [reason])\n\n    receive do\n      {:DOWN, ^ref, _, _, _} ->\n        %Task{ref: ref, pid: pid, owner: self(), mfa: {__MODULE__, :create_dummy_task, 1}}\n    end\n  end\n\n  def sleep(number) do\n    Process.sleep(number)\n    number\n  end\n\n  def wait_until_down(task) do\n    ref = Process.monitor(task.pid)\n    assert_receive {:DOWN, ^ref, _, _, _}\n  end\n\n  test \"can be supervised directly\" do\n    assert {:ok, _} = Supervisor.start_link([{Task, fn -> :ok end}], strategy: :one_for_one)\n  end\n\n  test \"generates child_spec/1\" do\n    defmodule MyTask do\n      use Task\n    end\n\n    assert MyTask.child_spec([:hello]) == %{\n             id: MyTask,\n             restart: :temporary,\n             start: {MyTask, :start_link, [[:hello]]}\n           }\n\n    defmodule CustomTask do\n      use Task, id: :id, restart: :permanent, shutdown: :infinity, start: {:foo, :bar, []}\n    end\n\n    assert CustomTask.child_spec([:hello]) == %{\n             id: :id,\n             restart: :permanent,\n             shutdown: :infinity,\n             start: {:foo, :bar, []}\n           }\n  end\n\n  test \"async/1\" do\n    parent = self()\n    fun = fn -> wait_and_send(parent, :done) end\n    task = Task.async(fun)\n\n    # Assert the struct\n    assert task.__struct__ == Task\n    assert is_pid(task.pid)\n    assert is_reference(task.ref)\n    assert task.mfa == {:erlang, :apply, 2}\n\n    # Assert the link\n    {:links, links} = Process.info(self(), :links)\n    assert task.pid in links\n\n    receive do: (:ready -> :ok)\n\n    # Assert the initial call\n    {:name, fun_name} = Function.info(fun, :name)\n    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(task.pid)\n\n    # Run the task\n    send(task.pid, true)\n\n    # Assert response and monitoring messages\n    ref = task.ref\n    assert_receive {^ref, :done}\n    assert_receive {:DOWN, ^ref, _, _, :normal}\n  end\n\n  test \"async/3\" do\n    task = Task.async(__MODULE__, :wait_and_send, [self(), :done])\n    assert task.__struct__ == Task\n    assert task.mfa == {__MODULE__, :wait_and_send, 2}\n\n    {:links, links} = Process.info(self(), :links)\n    assert task.pid in links\n\n    receive do: (:ready -> :ok)\n    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(task.pid)\n\n    send(task.pid, true)\n    assert Task.await(task) === :done\n    assert_receive :done\n  end\n\n  test \"async with $callers\" do\n    grandparent = self()\n\n    Task.async(fn ->\n      parent = self()\n      assert Process.get(:\"$callers\") == [grandparent]\n\n      Task.async(fn ->\n        assert Process.get(:\"$callers\") == [parent, grandparent]\n      end)\n      |> Task.await()\n    end)\n    |> Task.await()\n  end\n\n  test \"start/1\" do\n    parent = self()\n    fun = fn -> wait_and_send(parent, :done) end\n    {:ok, pid} = Task.start(fun)\n\n    {:links, links} = Process.info(self(), :links)\n    refute pid in links\n\n    receive do: (:ready -> :ok)\n\n    {:name, fun_name} = Function.info(fun, :name)\n    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(pid)\n\n    send(pid, true)\n    assert_receive :done\n  end\n\n  test \"start/3\" do\n    {:ok, pid} = Task.start(__MODULE__, :wait_and_send, [self(), :done])\n\n    {:links, links} = Process.info(self(), :links)\n    refute pid in links\n\n    receive do: (:ready -> :ok)\n\n    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(pid)\n\n    send(pid, true)\n    assert_receive :done\n  end\n\n  test \"completed/1\" do\n    task = Task.completed(:done)\n    assert task.__struct__ == Task\n\n    refute task.pid\n\n    assert Task.await(task) == :done\n  end\n\n  test \"start_link/1\" do\n    parent = self()\n    fun = fn -> wait_and_send(parent, :done) end\n    {:ok, pid} = Task.start_link(fun)\n\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    receive do: (:ready -> :ok)\n\n    {:name, fun_name} = Function.info(fun, :name)\n    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(pid)\n\n    send(pid, true)\n    assert_receive :done\n  end\n\n  test \"start_link/3\" do\n    {:ok, pid} = Task.start_link(__MODULE__, :wait_and_send, [self(), :done])\n\n    {:links, links} = Process.info(self(), :links)\n    assert pid in links\n\n    receive do: (:ready -> :ok)\n\n    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(pid)\n\n    send(pid, true)\n    assert_receive :done\n  end\n\n  test \"start_link with $callers\" do\n    grandparent = self()\n\n    Task.start_link(fn ->\n      parent = self()\n      assert Process.get(:\"$callers\") == [grandparent]\n\n      Task.start_link(fn ->\n        assert Process.get(:\"$callers\") == [parent, grandparent]\n        send(grandparent, :done)\n      end)\n    end)\n\n    assert_receive :done\n  end\n\n  describe \"ignore/1\" do\n    test \"discards on time replies\" do\n      task = Task.async(fn -> :ok end)\n      wait_until_down(task)\n      assert Task.ignore(task) == {:ok, :ok}\n      assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}\n    end\n\n    test \"discards late replies\" do\n      task =\n        Task.async(fn ->\n          assert_receive(:go)\n          :ok\n        end)\n\n      assert Task.ignore(task) == nil\n      send(task.pid, :go)\n      wait_until_down(task)\n      assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}\n    end\n\n    test \"discards on-time failures\" do\n      Process.flag(:trap_exit, true)\n      task = Task.async(fn -> exit(:oops) end)\n      wait_until_down(task)\n      assert Task.ignore(task) == {:exit, :oops}\n      assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}\n    end\n\n    test \"discards late failures\" do\n      task =\n        Task.async(fn ->\n          assert_receive(:go)\n          exit(:oops)\n        end)\n\n      assert Task.ignore(task) == nil\n      send(task.pid, :go)\n      wait_until_down(task)\n      assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}\n    end\n\n    test \"exits on :noconnection\" do\n      ref = make_ref()\n      task = %Task{ref: ref, pid: self(), owner: self(), mfa: {__MODULE__, :test, 1}}\n      send(self(), {:DOWN, ref, self(), self(), :noconnection})\n      assert catch_exit(Task.ignore(task)) |> elem(0) == {:nodedown, node()}\n    end\n\n    test \"can ignore completed tasks\" do\n      assert Task.ignore(Task.completed(:done)) == {:ok, :done}\n    end\n  end\n\n  describe \"await/2\" do\n    test \"demonitors and unalias on timeout\" do\n      task =\n        Task.async(fn ->\n          assert_receive :go\n          :done\n        end)\n\n      assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}\n      send(task.pid, :go)\n      ref = task.ref\n\n      wait_until_down(task)\n      refute_received {^ref, :done}\n      refute_received {:DOWN, ^ref, _, _, _}\n    end\n\n    test \"exits on timeout\" do\n      task = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}\n    end\n\n    test \"exits on normal exit\" do\n      task = Task.async(fn -> exit(:normal) end)\n      assert catch_exit(Task.await(task)) == {:normal, {Task, :await, [task, 5000]}}\n    end\n\n    test \"exits on task throw\" do\n      Process.flag(:trap_exit, true)\n      task = Task.async(fn -> throw(:unknown) end)\n\n      assert {{{:nocatch, :unknown}, _}, {Task, :await, [^task, 5000]}} =\n               catch_exit(Task.await(task))\n    end\n\n    test \"exits on task error\" do\n      Process.flag(:trap_exit, true)\n      task = Task.async(fn -> raise \"oops\" end)\n      assert {{%RuntimeError{}, _}, {Task, :await, [^task, 5000]}} = catch_exit(Task.await(task))\n    end\n\n    @compile {:no_warn_undefined, :module_does_not_exist}\n\n    test \"exits on task undef module error\" do\n      Process.flag(:trap_exit, true)\n      task = Task.async(&:module_does_not_exist.undef/0)\n\n      assert {exit_status, mfa} = catch_exit(Task.await(task))\n      assert {:undef, [{:module_does_not_exist, :undef, _, _} | _]} = exit_status\n      assert {Task, :await, [^task, 5000]} = mfa\n    end\n\n    @compile {:no_warn_undefined, {TaskTest, :undef, 0}}\n\n    test \"exits on task undef function error\" do\n      Process.flag(:trap_exit, true)\n      task = Task.async(&TaskTest.undef/0)\n\n      assert {{:undef, [{TaskTest, :undef, _, _} | _]}, {Task, :await, [^task, 5000]}} =\n               catch_exit(Task.await(task))\n    end\n\n    test \"exits on task exit\" do\n      Process.flag(:trap_exit, true)\n      task = Task.async(fn -> exit(:unknown) end)\n      assert {:unknown, {Task, :await, [^task, 5000]}} = catch_exit(Task.await(task))\n    end\n\n    test \"exits on :noconnection\" do\n      ref = make_ref()\n      task = %Task{ref: ref, pid: self(), owner: self(), mfa: {__MODULE__, :test, 1}}\n      send(self(), {:DOWN, ref, :process, self(), :noconnection})\n      assert catch_exit(Task.await(task)) |> elem(0) == {:nodedown, node()}\n    end\n\n    test \"exits on :noconnection from named monitor\" do\n      ref = make_ref()\n      task = %Task{ref: ref, owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      send(self(), {:DOWN, ref, :process, {:name, :node}, :noconnection})\n      assert catch_exit(Task.await(task)) |> elem(0) == {:nodedown, :node}\n    end\n\n    test \"raises when invoked from a non-owner process\" do\n      task = create_task_in_other_process()\n\n      message =\n        \"task #{inspect(task)} must be queried from the owner \" <>\n          \"but was queried from #{inspect(self())}\"\n\n      assert_raise ArgumentError, message, fn -> Task.await(task, 1) end\n    end\n  end\n\n  describe \"await_many/2\" do\n    test \"returns list of replies\" do\n      tasks = for val <- [1, 3, 9], do: Task.async(fn -> val end)\n      assert Task.await_many(tasks) == [1, 3, 9]\n    end\n\n    test \"returns replies in input order ignoring response order\" do\n      refs = [ref_1 = make_ref(), ref_2 = make_ref(), ref_3 = make_ref()]\n\n      tasks =\n        Enum.map(refs, fn ref ->\n          %Task{ref: ref, owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n        end)\n\n      send(self(), {ref_2, 3})\n      send(self(), {ref_3, 9})\n      send(self(), {ref_1, 1})\n      assert Task.await_many(tasks) == [1, 3, 9]\n    end\n\n    test \"returns an empty list immediately\" do\n      assert Task.await_many([]) == []\n    end\n\n    test \"ignores messages from other processes\" do\n      other_ref = make_ref()\n      tasks = for val <- [:a, :b], do: Task.async(fn -> val end)\n      send(self(), other_ref)\n      send(self(), {other_ref, :z})\n      send(self(), {:DOWN, other_ref, :process, 1, :goodbye})\n      assert Task.await_many(tasks) == [:a, :b]\n      assert_received ^other_ref\n      assert_received {^other_ref, :z}\n      assert_received {:DOWN, ^other_ref, :process, 1, :goodbye}\n    end\n\n    test \"ignores additional messages after reply\" do\n      refs = [ref_1 = make_ref(), ref_2 = make_ref()]\n\n      tasks =\n        Enum.map(refs, fn ref ->\n          %Task{ref: ref, owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n        end)\n\n      send(self(), {ref_2, :b})\n      send(self(), {ref_2, :other})\n      send(self(), {ref_1, :a})\n      assert Task.await_many(tasks) == [:a, :b]\n      assert_received {^ref_2, :other}\n    end\n\n    test \"exits on timeout\" do\n      tasks = [Task.async(fn -> Process.sleep(:infinity) end)]\n      assert catch_exit(Task.await_many(tasks, 0)) == {:timeout, {Task, :await_many, [tasks, 0]}}\n    end\n\n    test \"exits with same reason when task exits\" do\n      tasks = [Task.async(fn -> exit(:normal) end)]\n      assert catch_exit(Task.await_many(tasks)) == {:normal, {Task, :await_many, [tasks, 5000]}}\n    end\n\n    test \"exits immediately when any task exits\" do\n      tasks = [\n        Task.async(fn -> Process.sleep(:infinity) end),\n        Task.async(fn -> exit(:normal) end)\n      ]\n\n      assert catch_exit(Task.await_many(tasks)) == {:normal, {Task, :await_many, [tasks, 5000]}}\n    end\n\n    test \"exits immediately when any task crashes\" do\n      Process.flag(:trap_exit, true)\n\n      tasks = [\n        Task.async(fn -> Process.sleep(:infinity) end),\n        Task.async(fn -> exit(:unknown) end)\n      ]\n\n      assert catch_exit(Task.await_many(tasks)) == {:unknown, {Task, :await_many, [tasks, 5000]}}\n\n      # Make sure all monitors are cleared up afterwards too\n      Enum.each(tasks, &Process.exit(&1.pid, :kill))\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"exits immediately when any task throws\" do\n      Process.flag(:trap_exit, true)\n\n      tasks = [\n        Task.async(fn -> Process.sleep(:infinity) end),\n        Task.async(fn -> throw(:unknown) end)\n      ]\n\n      assert {{{:nocatch, :unknown}, _}, {Task, :await_many, [^tasks, 5000]}} =\n               catch_exit(Task.await_many(tasks))\n    end\n\n    test \"exits immediately on any task error\" do\n      Process.flag(:trap_exit, true)\n\n      tasks = [\n        Task.async(fn -> Process.sleep(:infinity) end),\n        Task.async(fn -> raise \"oops\" end)\n      ]\n\n      assert {{%RuntimeError{}, _}, {Task, :await_many, [^tasks, 5000]}} =\n               catch_exit(Task.await_many(tasks))\n    end\n\n    test \"exits immediately on :noconnection\" do\n      tasks = [\n        Task.async(fn -> Process.sleep(:infinity) end),\n        %Task{ref: ref = make_ref(), owner: self(), pid: self(), mfa: {__MODULE__, :test, 1}}\n      ]\n\n      send(self(), {:DOWN, ref, :process, self(), :noconnection})\n      assert catch_exit(Task.await_many(tasks)) |> elem(0) == {:nodedown, node()}\n    end\n\n    test \"exits immediately on :noconnection from named monitor\" do\n      tasks = [\n        Task.async(fn -> Process.sleep(:infinity) end),\n        %Task{ref: ref = make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      ]\n\n      send(self(), {:DOWN, ref, :process, {:name, :node}, :noconnection})\n      assert catch_exit(Task.await_many(tasks)) |> elem(0) == {:nodedown, :node}\n    end\n\n    test \"raises when invoked from a non-owner process\" do\n      tasks = [\n        Task.async(fn -> Process.sleep(:infinity) end),\n        bad_task = create_task_in_other_process()\n      ]\n\n      message =\n        \"task #{inspect(bad_task)} must be queried from the owner \" <>\n          \"but was queried from #{inspect(self())}\"\n\n      assert_raise ArgumentError, message, fn -> Task.await_many(tasks, 1) end\n    end\n  end\n\n  describe \"yield/2\" do\n    test \"returns {:ok, result} when reply and :DOWN in message queue\" do\n      task = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      send(self(), {task.ref, :result})\n      send(self(), {:DOWN, task.ref, :process, self(), :abnormal})\n      assert Task.yield(task, 0) == {:ok, :result}\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns nil on timeout\" do\n      task = %Task{ref: make_ref(), pid: nil, owner: self(), mfa: {__MODULE__, :test, 1}}\n      assert Task.yield(task, 0) == nil\n    end\n\n    test \"return exit on normal exit\" do\n      task = Task.async(fn -> exit(:normal) end)\n      assert Task.yield(task) == {:exit, :normal}\n    end\n\n    test \"exits on :noconnection\" do\n      ref = make_ref()\n      task = %Task{ref: ref, pid: self(), owner: self(), mfa: {__MODULE__, :test, 1}}\n      send(self(), {:DOWN, ref, self(), self(), :noconnection})\n      assert catch_exit(Task.yield(task)) |> elem(0) == {:nodedown, node()}\n    end\n\n    test \"raises when invoked from a non-owner process\" do\n      task = create_task_in_other_process()\n\n      message =\n        \"task #{inspect(task)} must be queried from the owner \" <>\n          \"but was queried from #{inspect(self())}\"\n\n      assert_raise ArgumentError, message, fn -> Task.yield(task, 1) end\n    end\n  end\n\n  describe \"yield_many/2\" do\n    test \"returns {:ok, result} when reply and :DOWN in message queue\" do\n      task = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      send(self(), {task.ref, :result})\n      send(self(), {:DOWN, task.ref, :process, self(), :abnormal})\n      assert Task.yield_many([task], 0) == [{task, {:ok, :result}}]\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns nil on timeout by default\" do\n      task = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      assert Task.yield_many([task], 0) == [{task, nil}]\n    end\n\n    test \"shuts down on timeout when configured\" do\n      Process.flag(:trap_exit, true)\n      task = Task.async(fn -> Process.sleep(:infinity) end)\n      assert Task.yield_many([task], timeout: 0, on_timeout: :kill_task) == [{task, nil}]\n      refute Process.alive?(task.pid)\n    end\n\n    test \"ignores on timeout when configured\" do\n      task =\n        Task.async(fn ->\n          receive do\n            :done -> :ok\n          end\n        end)\n\n      assert Task.yield_many([task], timeout: 0, on_timeout: :ignore) == [{task, nil}]\n      assert Process.alive?(task.pid)\n\n      ref = Process.monitor(task.pid)\n      send(task.pid, :done)\n      assert_receive {:DOWN, ^ref, _, _, _}\n\n      assert Task.yield(task, 0) == nil\n    end\n\n    test \"return exit on normal exit\" do\n      task = Task.async(fn -> exit(:normal) end)\n      assert Task.yield_many([task]) == [{task, {:exit, :normal}}]\n    end\n\n    test \"exits on :noconnection\" do\n      ref = make_ref()\n      task = %Task{ref: ref, pid: self(), owner: self(), mfa: {__MODULE__, :test, 1}}\n      send(self(), {:DOWN, ref, :process, self(), :noconnection})\n      assert catch_exit(Task.yield_many([task])) |> elem(0) == {:nodedown, node()}\n    end\n\n    test \"raises when invoked from a non-owner process\" do\n      task = create_task_in_other_process()\n\n      message =\n        \"task #{inspect(task)} must be queried from the owner \" <>\n          \"but was queried from #{inspect(self())}\"\n\n      assert_raise ArgumentError, message, fn -> Task.yield_many([task], 1) end\n    end\n\n    test \"returns results from multiple tasks\" do\n      task1 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      task2 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      task3 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n\n      send(self(), {task1.ref, :result})\n      send(self(), {:DOWN, task3.ref, :process, self(), :normal})\n\n      assert Task.yield_many([task1, task2, task3], 0) ==\n               [{task1, {:ok, :result}}, {task2, nil}, {task3, {:exit, :normal}}]\n    end\n\n    test \"returns results from multiple tasks with limit\" do\n      task1 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      task2 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      task3 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n\n      send(self(), {task1.ref, :result})\n      send(self(), {:DOWN, task3.ref, :process, self(), :normal})\n\n      assert Task.yield_many([task1, task2, task3], limit: 1, timeout: :infinity) ==\n               [{task1, {:ok, :result}}, {task2, nil}, {task3, nil}]\n\n      assert Task.yield_many([task2, task3], limit: 1, timeout: :infinity) ==\n               [{task2, nil}, {task3, {:exit, :normal}}]\n    end\n\n    test \"returns results from multiple tasks with limit and on timeout\" do\n      Process.flag(:trap_exit, true)\n      task1 = Task.async(fn -> Process.sleep(:infinity) end)\n      task2 = Task.async(fn -> :done end)\n\n      assert Task.yield_many([task1, task2], timeout: :infinity, on_timeout: :kill_task, limit: 1) ==\n               [{task1, nil}, {task2, {:ok, :done}}]\n\n      assert Process.alive?(task1.pid)\n\n      assert Task.yield_many([task1], timeout: 0, on_timeout: :kill_task, limit: 1) ==\n               [{task1, nil}]\n\n      refute Process.alive?(task1.pid)\n    end\n\n    test \"returns results on infinity timeout\" do\n      task1 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      task2 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n      task3 = %Task{ref: make_ref(), owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}\n\n      send(self(), {task1.ref, :result})\n      send(self(), {task2.ref, :result})\n      send(self(), {:DOWN, task3.ref, :process, self(), :normal})\n\n      assert Task.yield_many([task1, task2, task3], :infinity) ==\n               [{task1, {:ok, :result}}, {task2, {:ok, :result}}, {task3, {:exit, :normal}}]\n    end\n  end\n\n  describe \"shutdown/2\" do\n    test \"returns {:ok, result} when reply and abnormal :DOWN in message queue\" do\n      task = create_dummy_task(:abnormal)\n      send(self(), {task.ref, :result})\n      send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})\n      assert Task.shutdown(task) == {:ok, :result}\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns {:ok, result} when reply and normal :DOWN in message queue\" do\n      task = create_dummy_task(:normal)\n      send(self(), {task.ref, :result})\n      send(self(), {:DOWN, task.ref, :process, task.pid, :normal})\n      assert Task.shutdown(task) == {:ok, :result}\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns {:ok, result} when reply and shut down :DOWN in message queue\" do\n      task = create_dummy_task(:shutdown)\n      send(self(), {task.ref, :result})\n      send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})\n      assert Task.shutdown(task) == {:ok, :result}\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns nil on shutting down task\" do\n      task = Task.async(:timer, :sleep, [:infinity])\n      assert Task.shutdown(task) == nil\n    end\n\n    test \"returns exit on abnormal :DOWN in message queue\" do\n      task = create_dummy_task(:abnormal)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})\n      assert Task.shutdown(task) == {:exit, :abnormal}\n    end\n\n    test \"returns exit on normal :DOWN in message queue\" do\n      task = create_dummy_task(:normal)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :normal})\n      assert Task.shutdown(task) == {:exit, :normal}\n    end\n\n    test \"returns nil on shutdown :DOWN in message queue\" do\n      task = create_dummy_task(:shutdown)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})\n      assert Task.shutdown(task) == nil\n    end\n\n    test \"returns exit on killed :DOWN in message queue\" do\n      task = create_dummy_task(:killed)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :killed})\n      assert Task.shutdown(task) == {:exit, :killed}\n    end\n\n    test \"exits on noconnection :DOWN in message queue\" do\n      task = create_dummy_task(:noconnection)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :noconnection})\n\n      assert catch_exit(Task.shutdown(task)) ==\n               {{:nodedown, node()}, {Task, :shutdown, [task, 5000]}}\n    end\n\n    test \"ignores if task PID is nil\" do\n      ref = make_ref()\n      send(self(), {ref, :done})\n\n      assert Task.shutdown(%Task{ref: ref, owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}) ==\n               {:ok, :done}\n\n      ref = make_ref()\n      send(self(), {:DOWN, ref, :process, self(), :done})\n\n      assert Task.shutdown(%Task{ref: ref, owner: self(), pid: nil, mfa: {__MODULE__, :test, 1}}) ==\n               {:exit, :done}\n    end\n\n    test \"raises when invoked from a non-owner process\" do\n      task = create_task_in_other_process()\n\n      message =\n        \"task #{inspect(task)} must be queried from the owner \" <>\n          \"but was queried from #{inspect(self())}\"\n\n      assert_raise ArgumentError, message, fn -> Task.shutdown(task) end\n    end\n\n    test \"returns nil on killing task\" do\n      caller = self()\n\n      task =\n        Task.async(fn ->\n          Process.flag(:trap_exit, true)\n          wait_and_send(caller, :ready)\n          Process.sleep(:infinity)\n        end)\n\n      receive do: (:ready -> :ok)\n\n      assert Task.shutdown(task, :brutal_kill) == nil\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns {:exit, :noproc} if task handled\" do\n      task = create_dummy_task(:noproc)\n      assert Task.shutdown(task) == {:exit, :noproc}\n    end\n  end\n\n  describe \"shutdown/2 with :brutal_kill\" do\n    test \"returns {:ok, result} when reply and abnormal :DOWN in message queue\" do\n      task = create_dummy_task(:abnormal)\n      send(self(), {task.ref, :result})\n      send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})\n      assert Task.shutdown(task, :brutal_kill) == {:ok, :result}\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns {:ok, result} when reply and normal :DOWN in message queue\" do\n      task = create_dummy_task(:normal)\n      send(self(), {task.ref, :result})\n      send(self(), {:DOWN, task.ref, :process, task.pid, :normal})\n      assert Task.shutdown(task, :brutal_kill) == {:ok, :result}\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns {:ok, result} when reply and shut down :DOWN in message queue\" do\n      task = create_dummy_task(:shutdown)\n      send(self(), {task.ref, :result})\n      send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})\n      assert Task.shutdown(task, :brutal_kill) == {:ok, :result}\n      refute_received {:DOWN, _, _, _, _}\n    end\n\n    test \"returns nil on killed :DOWN in message queue\" do\n      task = create_dummy_task(:killed)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :killed})\n      assert Task.shutdown(task, :brutal_kill) == nil\n    end\n\n    test \"returns exit on abnormal :DOWN in message queue\" do\n      task = create_dummy_task(:abnormal)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})\n      assert Task.shutdown(task, :brutal_kill) == {:exit, :abnormal}\n    end\n\n    test \"returns exit on normal :DOWN in message queue\" do\n      task = create_dummy_task(:normal)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :normal})\n      assert Task.shutdown(task, :brutal_kill) == {:exit, :normal}\n    end\n\n    test \"returns exit on shutdown :DOWN in message queue\" do\n      task = create_dummy_task(:shutdown)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})\n      assert Task.shutdown(task, :brutal_kill) == {:exit, :shutdown}\n    end\n\n    test \"exits on noconnection :DOWN in message queue\" do\n      task = create_dummy_task(:noconnection)\n      send(self(), {:DOWN, task.ref, :process, task.pid, :noconnection})\n\n      assert catch_exit(Task.shutdown(task, :brutal_kill)) ==\n               {{:nodedown, node()}, {Task, :shutdown, [task, :brutal_kill]}}\n    end\n\n    test \"returns exit on killing task after shutdown timeout\" do\n      caller = self()\n\n      task =\n        Task.async(fn ->\n          Process.flag(:trap_exit, true)\n          wait_and_send(caller, :ready)\n          Process.sleep(:infinity)\n        end)\n\n      receive do: (:ready -> :ok)\n      assert Task.shutdown(task, 1) == {:exit, :killed}\n    end\n\n    test \"returns {:exit, :noproc} if task handled\" do\n      task = create_dummy_task(:noproc)\n      assert Task.shutdown(task, :brutal_kill) == {:exit, :noproc}\n    end\n  end\n\n  describe \"async_stream/2\" do\n    test \"timeout\" do\n      assert catch_exit([:infinity] |> Task.async_stream(&sleep/1, timeout: 0) |> Enum.to_list()) ==\n               {:timeout, {Task.Supervised, :stream, [0]}}\n\n      refute_received _\n    end\n\n    test \"streams an enumerable with ordered: false\" do\n      opts = [max_concurrency: 1, ordered: false]\n\n      assert 4..1//-1\n             |> Task.async_stream(&sleep(&1 * 100), opts)\n             |> Enum.to_list() == [ok: 400, ok: 300, ok: 200, ok: 100]\n\n      opts = [max_concurrency: 4, ordered: false]\n\n      assert 4..1//-1\n             |> Task.async_stream(&sleep(&1 * 100), opts)\n             |> Enum.to_list() == [ok: 100, ok: 200, ok: 300, ok: 400]\n    end\n\n    test \"streams an enumerable with ordered: false, on_timeout: :kill_task\" do\n      opts = [max_concurrency: 4, ordered: false, on_timeout: :kill_task, timeout: 50]\n\n      assert [100, 1, 100, 1]\n             |> Task.async_stream(&sleep/1, opts)\n             |> Enum.to_list() == [ok: 1, ok: 1, exit: :timeout, exit: :timeout]\n\n      refute_received _\n    end\n\n    test \"streams an enumerable with infinite timeout\" do\n      [ok: :ok] = Task.async_stream([1], fn _ -> :ok end, timeout: :infinity) |> Enum.to_list()\n    end\n\n    test \"does not allow streaming with max_concurrency = 0\" do\n      assert_raise ArgumentError, \":max_concurrency must be an integer greater than zero\", fn ->\n        Task.async_stream([1], fn _ -> :ok end, max_concurrency: 0)\n      end\n    end\n\n    test \"does not allow streaming with invalid :on_timeout\" do\n      assert_raise ArgumentError, \":on_timeout must be either :exit or :kill_task\", fn ->\n        Task.async_stream([1], fn _ -> :ok end, on_timeout: :unknown)\n      end\n    end\n\n    test \"does not allow streaming with invalid :timeout\" do\n      assert_raise ArgumentError, \":timeout must be either a positive integer or :infinity\", fn ->\n        Task.async_stream([1], fn _ -> :ok end, timeout: :unknown)\n      end\n    end\n\n    test \"streams with fake down messages on the inbox\" do\n      parent = self()\n\n      assert Task.async_stream([:ok], fn :ok ->\n               {:links, links} = Process.info(self(), :links)\n\n               for link <- links do\n                 send(link, {:DOWN, make_ref(), :process, parent, :oops})\n               end\n\n               :ok\n             end)\n             |> Enum.to_list() == [ok: :ok]\n    end\n\n    test \"with $callers\" do\n      grandparent = self()\n\n      Task.async_stream([1], fn 1 ->\n        parent = self()\n        assert Process.get(:\"$callers\") == [grandparent]\n\n        Task.async_stream([1], fn 1 ->\n          assert Process.get(:\"$callers\") == [parent, grandparent]\n          send(grandparent, :done)\n        end)\n        |> Stream.run()\n      end)\n      |> Stream.run()\n\n      assert_receive :done\n    end\n\n    test \"consuming from another process\" do\n      parent = self()\n      stream = Task.async_stream([1, 2, 3], &send(parent, &1))\n      Task.start(Stream, :run, [stream])\n      assert_receive 1\n      assert_receive 2\n      assert_receive 3\n    end\n\n    test \"wrapping a flat_map/concat with a haltable stream\" do\n      result =\n        Stream.take([:foo, :bar], 1)\n        |> Stream.concat([1, 2])\n        |> Task.async_stream(& &1)\n        |> Enum.to_list()\n\n      assert result == [ok: :foo, ok: 1, ok: 2]\n    end\n  end\n\n  for {desc, concurrency} <- [==: 4, <: 2, >: 8] do\n    describe \"async_stream with max_concurrency #{desc} tasks\" do\n      @opts [max_concurrency: concurrency]\n\n      test \"streams an enumerable with fun\" do\n        assert 1..4\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n      end\n\n      test \"streams an enumerable with mfa\" do\n        assert 1..4\n               |> Task.async_stream(__MODULE__, :sleep, [], @opts)\n               |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n      end\n\n      test \"streams an enumerable without leaking tasks\" do\n        assert 1..4\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n\n        refute_received _\n      end\n\n      test \"streams an enumerable with slowest first\" do\n        Process.flag(:trap_exit, true)\n\n        assert 4..1//-1\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.to_list() == [ok: 4, ok: 3, ok: 2, ok: 1]\n      end\n\n      test \"streams an enumerable with exits\" do\n        Process.flag(:trap_exit, true)\n\n        assert 1..4\n               |> Task.async_stream(&exit/1, @opts)\n               |> Enum.to_list() == [exit: 1, exit: 2, exit: 3, exit: 4]\n\n        refute_received {:EXIT, _, _}\n      end\n\n      test \"shuts down unused tasks\" do\n        assert [0, :infinity, :infinity, :infinity]\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.take(1) == [ok: 0]\n\n        assert Process.info(self(), :links) == {:links, []}\n      end\n\n      test \"shuts down unused tasks without leaking messages\" do\n        assert [0, :infinity, :infinity, :infinity]\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.take(1) == [ok: 0]\n\n        refute_received _\n      end\n\n      test \"is zippable on success\" do\n        task = 1..4 |> Task.async_stream(&sleep/1, @opts) |> Stream.map(&elem(&1, 1))\n        assert Enum.zip(task, task) == [{1, 1}, {2, 2}, {3, 3}, {4, 4}]\n      end\n\n      test \"is zippable on failure\" do\n        Process.flag(:trap_exit, true)\n        task = 1..4 |> Task.async_stream(&exit/1, @opts) |> Stream.map(&elem(&1, 1))\n        assert Enum.zip(task, task) == [{1, 1}, {2, 2}, {3, 3}, {4, 4}]\n      end\n\n      test \"is zippable with slowest first\" do\n        task = 4..1//-1 |> Task.async_stream(&sleep/1, @opts) |> Stream.map(&elem(&1, 1))\n        assert Enum.zip(task, task) == [{4, 4}, {3, 3}, {2, 2}, {1, 1}]\n      end\n\n      test \"with inner halt on success\" do\n        assert 1..8\n               |> Stream.take(4)\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.to_list() == [ok: 1, ok: 2, ok: 3, ok: 4]\n      end\n\n      test \"with inner halt on failure\" do\n        Process.flag(:trap_exit, true)\n\n        assert 1..8\n               |> Stream.take(4)\n               |> Task.async_stream(&exit/1, @opts)\n               |> Enum.to_list() == [exit: 1, exit: 2, exit: 3, exit: 4]\n      end\n\n      test \"with inner halt and slowest first\" do\n        assert 8..1//-1\n               |> Stream.take(4)\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.to_list() == [ok: 8, ok: 7, ok: 6, ok: 5]\n      end\n\n      test \"with outer halt on success\" do\n        assert 1..8\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.take(4) == [ok: 1, ok: 2, ok: 3, ok: 4]\n      end\n\n      test \"with outer halt on failure\" do\n        Process.flag(:trap_exit, true)\n\n        assert 1..8\n               |> Task.async_stream(&exit/1, @opts)\n               |> Enum.take(4) == [exit: 1, exit: 2, exit: 3, exit: 4]\n      end\n\n      test \"with outer halt and slowest first\" do\n        assert 8..1//-1\n               |> Task.async_stream(&sleep/1, @opts)\n               |> Enum.take(4) == [ok: 8, ok: 7, ok: 6, ok: 5]\n      end\n\n      test \"terminates inner effect\" do\n        stream =\n          1..4\n          |> Task.async_stream(&sleep/1, @opts)\n          |> Stream.transform(fn -> :ok end, fn x, acc -> {[x], acc} end, fn _ ->\n            Process.put(:stream_transform, true)\n          end)\n\n        Process.put(:stream_transform, false)\n        assert Enum.to_list(stream) == [ok: 1, ok: 2, ok: 3, ok: 4]\n        assert Process.get(:stream_transform)\n      end\n\n      test \"terminates outer effect\" do\n        stream =\n          1..4\n          |> Stream.transform(fn -> :ok end, fn x, acc -> {[x], acc} end, fn _ ->\n            Process.put(:stream_transform, true)\n          end)\n          |> Task.async_stream(&sleep/1, @opts)\n\n        Process.put(:stream_transform, false)\n        assert Enum.to_list(stream) == [ok: 1, ok: 2, ok: 3, ok: 4]\n        assert Process.get(:stream_transform)\n      end\n\n      test \"with :on_timeout set to :kill_task\" do\n        opts = Keyword.merge(@opts, on_timeout: :kill_task, timeout: 50)\n\n        assert [100, 1, 100, 1]\n               |> Task.async_stream(&sleep/1, opts)\n               |> Enum.to_list() == [exit: :timeout, ok: 1, exit: :timeout, ok: 1]\n\n        refute_received _\n      end\n\n      test \"with timeout and :zip_input_on_exit set to true\" do\n        opts = Keyword.merge(@opts, zip_input_on_exit: true, on_timeout: :kill_task, timeout: 50)\n\n        assert [1, 100]\n               |> Task.async_stream(&sleep/1, opts)\n               |> Enum.to_list() == [ok: 1, exit: {100, :timeout}]\n      end\n\n      test \"with outer halt on failure and :zip_input_on_exit\" do\n        Process.flag(:trap_exit, true)\n        opts = Keyword.merge(@opts, zip_input_on_exit: true)\n\n        assert 1..8\n               |> Task.async_stream(&exit/1, opts)\n               |> Enum.take(4) == [exit: {1, 1}, exit: {2, 2}, exit: {3, 3}, exit: {4, 4}]\n      end\n    end\n  end\n\n  describe \"default :logger reporter\" do\n    setup do\n      translator = :logger.get_primary_config().filters[:logger_translator]\n      assert :ok = :logger.remove_primary_filter(:logger_translator)\n      on_exit(fn -> :logger.add_primary_filter(:logger_translator, translator) end)\n    end\n\n    test \"logs a terminated task\" do\n      parent = self()\n      {:ok, pid} = Task.start_link(__MODULE__, :task, [parent])\n\n      assert ExUnit.CaptureLog.capture_log(fn ->\n               ref = Process.monitor(pid)\n               send(pid, :go)\n               receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n             end) =~ ~r\"\"\"\n             \\[error\\] \\*\\* Task #{inspect(pid)} terminating\n             \\*\\* Started from #{inspect(parent)}\n             \\*\\* When function  == &TaskTest.task/1\n             \\*\\*      arguments == \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\n             \\*\\* Reason for termination ==\\s\n             \\*\\* {%RuntimeError{message: \"oops\"},\n             \"\"\"\n    end\n\n    test \"logs a terminated task with a process label\" do\n      fun = fn ->\n        Process.set_label({:any, \"term\"})\n        raise \"oops\"\n      end\n\n      parent = self()\n      {:ok, pid} = Task.start_link(__MODULE__, :task, [parent, fun])\n\n      assert ExUnit.CaptureLog.capture_log(fn ->\n               ref = Process.monitor(pid)\n               send(pid, :go)\n               receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n             end) =~ ~r\"\"\"\n             \\[error\\] \\*\\* Task #PID<\\d+\\.\\d+\\.\\d+> terminating\n             \\*\\* Process Label == {:any, \"term\"}\n             \\*\\* Started from #PID<\\d+\\.\\d+\\.\\d+>\n             \\*\\* When function  == &TaskTest.task/2\n             \\*\\*      arguments == \\[#PID<\\d+\\.\\d+\\.\\d+>,\n              #Function<.+>\\]\n             \\*\\* Reason for termination ==\\s\n             \\*\\* {%RuntimeError{message: \"oops\"},\n             \"\"\"\n    end\n  end\n\n  def task(parent, fun \\\\ fn -> raise \"oops\" end) do\n    mon = Process.monitor(parent)\n    Process.unlink(parent)\n\n    receive do\n      :go ->\n        fun.()\n\n      {:DOWN, ^mon, _, _, _} ->\n        exit(:shutdown)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/test_helper.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Beam files compiled on demand\npath = Path.expand(\"../../tmp/beams\", __DIR__)\nFile.rm_rf!(path)\nFile.mkdir_p!(path)\nCode.prepend_path(path)\n\nApplication.put_env(:elixir, :ansi_enabled, true)\nCode.compiler_options(debug_info: true, infer_signatures: [:elixir])\n\ndefmodule PathHelpers do\n  def fixture_path() do\n    Path.expand(\"fixtures\", __DIR__)\n  end\n\n  def tmp_path() do\n    Path.expand(\"../../tmp\", __DIR__)\n  end\n\n  def fixture_path(extra) do\n    Path.join(fixture_path(), extra)\n  end\n\n  def tmp_path(extra) do\n    Path.join(tmp_path(), extra)\n  end\n\n  def elixir(args, executable_extension \\\\ \"\") do\n    run_cmd(elixir_executable(executable_extension), args)\n  end\n\n  def elixir_executable(extension \\\\ \"\") do\n    executable_path(\"elixir\", extension)\n  end\n\n  def elixirc(args, executable_extension \\\\ \"\") do\n    run_cmd(elixirc_executable(executable_extension), args)\n  end\n\n  def elixirc_executable(extension \\\\ \"\") do\n    executable_path(\"elixirc\", extension)\n  end\n\n  def iex(args, executable_extension \\\\ \"\") do\n    run_cmd(iex_executable(executable_extension), args)\n  end\n\n  def iex_executable(extension \\\\ \"\") do\n    executable_path(\"iex\", extension)\n  end\n\n  def write_beam({:module, name, bin, _} = res) do\n    File.mkdir_p!(unquote(path))\n    beam_path = Path.join(unquote(path), Atom.to_string(name) <> \".beam\")\n    File.write!(beam_path, bin)\n\n    :code.purge(name)\n    :code.delete(name)\n\n    res\n  end\n\n  defp run_cmd(executable, args) do\n    ~c\"#{executable} #{IO.chardata_to_string(args)}#{redirect_std_err_on_win()}\"\n    |> :os.cmd()\n    |> :unicode.characters_to_binary()\n  end\n\n  defp executable_path(name, extension) do\n    Path.expand(\"../../../../bin/#{name}#{extension}\", __DIR__)\n  end\n\n  if match?({:win32, _}, :os.type()) do\n    def windows?, do: true\n    def executable_extension, do: \".bat\"\n    def redirect_std_err_on_win, do: \" 2>&1\"\n  else\n    def windows?, do: false\n    def executable_extension, do: \"\"\n    def redirect_std_err_on_win, do: \"\"\n  end\nend\n\ndefmodule CodeFormatterHelpers do\n  defmacro assert_same(good, opts \\\\ []) do\n    quote bind_quoted: [good: good, opts: opts] do\n      assert IO.iodata_to_binary(Code.format_string!(good, opts)) == String.trim(good)\n    end\n  end\n\n  defmacro assert_format(bad, good, opts \\\\ []) do\n    quote bind_quoted: [bad: bad, good: good, opts: opts] do\n      result = String.trim(good)\n      assert IO.iodata_to_binary(Code.format_string!(bad, opts)) == result\n      assert IO.iodata_to_binary(Code.format_string!(good, opts)) == result\n    end\n  end\nend\n\nepmd_exclude = if match?({:win32, _}, :os.type()), do: [epmd: true], else: []\nos_exclude = if PathHelpers.windows?(), do: [unix: true], else: [windows: true]\n\n{line_exclude, line_include} =\n  if line = System.get_env(\"LINE\"), do: {[:test], [line: line]}, else: {[], []}\n\ndistributed_exclude =\n  if Code.ensure_loaded?(:peer) and Node.alive?() do\n    {:ok, _pid, node} = :peer.start(%{name: :secondary})\n    true = :erpc.call(node, :code, :set_path, [:code.get_path()])\n    {:ok, _} = :erpc.call(node, :application, :ensure_all_started, [:elixir])\n    []\n  else\n    [distributed: true]\n  end\n\nsource_exclude =\n  if :deterministic in :compile.env_compiler_options() do\n    [:requires_source]\n  else\n    []\n  end\n\nCode.require_file(\"../../scripts/cover_record.exs\", __DIR__)\n\ncover_exclude =\n  if CoverageRecorder.maybe_record(\"elixir\") do\n    [:require_ast]\n  else\n    []\n  end\n\n# OTP 28.1+\nre_import_exclude =\n  if Code.ensure_loaded?(:re) and function_exported?(:re, :import, 1) do\n    []\n  else\n    [:re_import]\n  end\n\nmaybe_seed_opt = if seed = System.get_env(\"SEED\"), do: [seed: String.to_integer(seed)], else: []\n\nex_unit_opts =\n  [\n    trace: !!System.get_env(\"TRACE\"),\n    exclude:\n      epmd_exclude ++\n        os_exclude ++\n        line_exclude ++\n        distributed_exclude ++ source_exclude ++ cover_exclude ++ re_import_exclude,\n    include: line_include,\n    assert_receive_timeout: String.to_integer(System.get_env(\"ELIXIR_ASSERT_TIMEOUT\", \"300\"))\n  ] ++ maybe_seed_opt\n\nExUnit.start(ex_unit_opts)\n"
  },
  {
    "path": "lib/elixir/test/elixir/tuple_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule TupleTest do\n  use ExUnit.Case, async: true\n\n  doctest Tuple\n\n  # Tuple-related functions in the Kernel module.\n\n  test \"Kernel.elem/2\" do\n    assert elem({:a, :b, :c}, 1) == :b\n  end\n\n  test \"Kernel.put_elem/3\" do\n    assert put_elem({:a, :b, :c}, 1, :d) == {:a, :d, :c}\n  end\n\n  test \"keyword syntax is supported in tuple literals\" do\n    assert {1, 2, three: :four} == {1, 2, [three: :four]}\n  end\n\n  test \"optional comma is supported in tuple literals\" do\n    assert Code.eval_string(\"{1,}\") == {{1}, []}\n    assert Code.eval_string(\"{1, 2, 3,}\") == {{1, 2, 3}, []}\n  end\n\n  test \"partial application\" do\n    assert (&{&1, 2}).(1) == {1, 2}\n    assert (&{&1, &2}).(1, 2) == {1, 2}\n    assert (&{&2, &1}).(2, 1) == {1, 2}\n  end\n\n  # Tuple module\n  # We check two variants of each function due to inlining.\n\n  test \"duplicate/2\" do\n    assert Tuple.duplicate(:foo, 0) == {}\n    assert Tuple.duplicate(:foo, 3) == {:foo, :foo, :foo}\n\n    mod = Tuple\n    assert mod.duplicate(:foo, 0) == {}\n    assert mod.duplicate(:foo, 3) == {:foo, :foo, :foo}\n  end\n\n  test \"insert_at/3\" do\n    assert Tuple.insert_at({:bar, :baz}, 0, :foo) == {:foo, :bar, :baz}\n\n    mod = Tuple\n    assert mod.insert_at({:bar, :baz}, 0, :foo) == {:foo, :bar, :baz}\n  end\n\n  test \"delete_at/2\" do\n    assert Tuple.delete_at({:foo, :bar, :baz}, 0) == {:bar, :baz}\n\n    mod = Tuple\n    assert mod.delete_at({:foo, :bar, :baz}, 0) == {:bar, :baz}\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/typespec_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\n# Holds tests for both Kernel.Typespec and Code.Typespec\ndefmodule TypespecTest do\n  use ExUnit.Case, async: true\n  alias TypespecTest.TypespecSample\n\n  defstruct [:hello]\n\n  defmacrop test_module(do: block) do\n    quote do\n      {:module, _, bytecode, _} =\n        defmodule TypespecSample do\n          unquote(block)\n        end\n\n      :code.purge(TypespecSample)\n      :code.delete(TypespecSample)\n      bytecode\n    end\n  end\n\n  defp types(bytecode) do\n    bytecode\n    |> Code.Typespec.fetch_types()\n    |> elem(1)\n    |> Enum.sort()\n  end\n\n  @skip_specs [__info__: 1]\n\n  defp specs(bytecode) do\n    bytecode\n    |> Code.Typespec.fetch_specs()\n    |> elem(1)\n    |> Enum.reject(fn {sign, _} -> sign in @skip_specs end)\n    |> Enum.sort()\n  end\n\n  defp callbacks(bytecode) do\n    bytecode\n    |> Code.Typespec.fetch_callbacks()\n    |> elem(1)\n    |> Enum.sort()\n  end\n\n  describe \"Kernel.Typespec errors\" do\n    test \"invalid type specification\" do\n      assert_raise Kernel.TypespecError, ~r\"invalid type specification: my_type = 1\", fn ->\n        test_module do\n          @type my_type = 1\n        end\n      end\n    end\n\n    test \"unexpected expression in typespec\" do\n      assert_raise Kernel.TypespecError, ~r\"unexpected expression in typespec: \\\"foobar\\\"\", fn ->\n        test_module do\n          @type my_type :: \"foobar\"\n        end\n      end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"unexpected expression in typespec: integer\\(\\)\\(\\)\",\n                   fn ->\n                     test_module do\n                       @type my_type :: integer()()\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"unexpected expression in typespec: %URI\\.t\\(\\)\\{\\}\",\n                   fn ->\n                     test_module do\n                       @type my_type :: %URI.t(){}\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"unexpected expression in typespec: t\\.Foo\",\n                   fn ->\n                     test_module do\n                       @type my_type :: t.Foo\n                     end\n                   end\n    end\n\n    test \"invalid function specification\" do\n      assert_raise Kernel.TypespecError, ~r\"invalid type specification: \\\"not a spec\\\"\", fn ->\n        test_module do\n          @spec \"not a spec\"\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"invalid type specification: 1 :: 2\", fn ->\n        test_module do\n          @spec 1 :: 2\n        end\n      end\n    end\n\n    test \"undefined type\" do\n      assert_raise Kernel.TypespecError, ~r\"type foo/0 undefined\", fn ->\n        test_module do\n          @type omg :: foo\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"type foo/2 undefined\", fn ->\n        test_module do\n          @type omg :: foo(atom, integer)\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"type bar/0 undefined\", fn ->\n        test_module do\n          @spec foo(bar, integer) :: {atom, integer}\n          def foo(var1, var2), do: {var1, var2}\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"type foo/0 undefined\", fn ->\n        test_module do\n          @type omg :: __MODULE__.foo()\n        end\n      end\n    end\n\n    test \"redefined type\" do\n      assert_raise Kernel.TypespecError,\n                   ~r\"type foo/0 is already defined in .*test/elixir/typespec_test.exs:138\",\n                   fn ->\n                     test_module do\n                       @type foo :: atom\n                       @type foo :: integer\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"type foo/2 is already defined in .*test/elixir/typespec_test.exs:148\",\n                   fn ->\n                     test_module do\n                       @type foo :: atom\n                       @type foo(var1, var2) :: {var1, var2}\n                       @type foo(x, y) :: {x, y}\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"type foo/0 is already defined in .*test/elixir/typespec_test.exs:157\",\n                   fn ->\n                     test_module do\n                       @type foo :: atom\n                       @typep foo :: integer\n                     end\n                   end\n    end\n\n    test \"type variable unused (singleton type variable)\" do\n      assert_raise Kernel.TypespecError, ~r\"type variable x is used only once\", fn ->\n        test_module do\n          @type foo(x) :: integer\n        end\n      end\n    end\n\n    test \"type variable starting with underscore\" do\n      test_module do\n        assert @type(foo(_hello) :: integer) == :ok\n      end\n    end\n\n    test \"type variable named _\" do\n      assert_raise Kernel.TypespecError, ~r\"type variable '_' is invalid\", fn ->\n        test_module do\n          @type foo(_) :: integer\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"type variable '_' is invalid\", fn ->\n        test_module do\n          @type foo(_, _) :: integer\n        end\n      end\n    end\n\n    test \"spec for undefined function\" do\n      assert_compile_error(~r\"spec for undefined function omg/0\", fn ->\n        test_module do\n          @spec omg :: atom\n        end\n      end)\n    end\n\n    test \"spec variable used only once (singleton type variable)\" do\n      assert_raise Kernel.TypespecError, ~r\"type variable x is used only once\", fn ->\n        test_module do\n          @spec foo(x, integer) :: integer when x: var\n          def foo(x, y), do: x + y\n        end\n      end\n    end\n\n    test \"spec with ... outside of fn and lists\" do\n      assert_raise Kernel.TypespecError, ~r\"... in typespecs is only allowed inside lists\", fn ->\n        test_module do\n          @spec foo(...) :: :ok\n          def foo(x), do: x\n        end\n      end\n    end\n\n    test \"invalid optional callback\" do\n      assert_compile_error(~r\"invalid optional callback :foo\", fn ->\n        test_module do\n          @optional_callbacks :foo\n        end\n      end)\n    end\n\n    test \"unknown optional callback\" do\n      assert_compile_error(~r\"unknown callback foo/1 given as optional callback\", fn ->\n        test_module do\n          @optional_callbacks foo: 1\n        end\n      end)\n    end\n\n    test \"repeated optional callback\" do\n      message = ~r\"foo/1 has been specified as optional callback more than once\"\n\n      assert_compile_error(message, fn ->\n        test_module do\n          @callback foo(:ok) :: :ok\n          @optional_callbacks foo: 1, foo: 1\n        end\n      end)\n    end\n\n    test \"behaviour_info/1 explicitly defined alongside @callback/@macrocallback\" do\n      message = ~r\"cannot define @callback attribute for foo/1 when behaviour_info/1\"\n\n      assert_compile_error(message, fn ->\n        test_module do\n          @callback foo(:ok) :: :ok\n          def behaviour_info(_), do: []\n        end\n      end)\n\n      message = ~r\"cannot define @macrocallback attribute for foo/1 when behaviour_info/1\"\n\n      assert_compile_error(message, fn ->\n        test_module do\n          @macrocallback foo(:ok) :: :ok\n          def behaviour_info(_), do: []\n        end\n      end)\n    end\n\n    test \"default is not supported\" do\n      assert_raise ArgumentError, fn ->\n        test_module do\n          @callback hello(num \\\\ 0 :: integer) :: integer\n        end\n      end\n\n      assert_raise ArgumentError, fn ->\n        test_module do\n          @callback hello(num :: integer \\\\ 0) :: integer\n        end\n      end\n\n      assert_raise ArgumentError, fn ->\n        test_module do\n          @macrocallback hello(num \\\\ 0 :: integer) :: Macro.t()\n        end\n      end\n\n      assert_raise ArgumentError, fn ->\n        test_module do\n          @macrocallback hello(num :: integer \\\\ 0) :: Macro.t()\n        end\n      end\n\n      assert_raise ArgumentError, fn ->\n        test_module do\n          @spec hello(num \\\\ 0 :: integer) :: integer\n        end\n      end\n\n      assert_raise ArgumentError, fn ->\n        test_module do\n          @spec hello(num :: integer \\\\ 0) :: integer\n        end\n      end\n    end\n\n    test \"@spec shows readable error message when return type is missing\" do\n      message = ~r\"type specification missing return type: my_fun\\(integer\\)\"\n\n      assert_raise Kernel.TypespecError, message, fn ->\n        test_module do\n          @spec my_fun(integer)\n        end\n      end\n    end\n  end\n\n  describe \"Kernel.Typespec definitions\" do\n    test \"typespec declarations return :ok\" do\n      test_module do\n        def foo(), do: nil\n\n        assert @type(foo :: any()) == :ok\n        assert @typep(foop :: any()) == :ok\n        assert @spec(foo() :: nil) == :ok\n        assert @opaque(my_type :: atom) == :ok\n        assert @callback(foo(foop) :: integer) == :ok\n        assert @macrocallback(foo(integer) :: integer) == :ok\n      end\n    end\n\n    test \"@type with a single type\" do\n      bytecode =\n        test_module do\n          @type my_type :: term\n        end\n\n      assert [type: {:my_type, {:type, _, :term, []}, []}] = types(bytecode)\n    end\n\n    test \"@type with an atom/alias\" do\n      bytecode =\n        test_module do\n          @type foo :: :foo\n          @type bar :: Bar\n        end\n\n      assert [\n               type: {:bar, {:atom, _, Bar}, []},\n               type: {:foo, {:atom, _, :foo}, []}\n             ] = types(bytecode)\n    end\n\n    test \"@type with an integer\" do\n      bytecode =\n        test_module do\n          @type pos :: 10\n          @type neg :: -10\n        end\n\n      assert [\n               type: {:neg, {:op, _, :-, {:integer, _, 10}}, []},\n               type: {:pos, {:integer, _, 10}, []}\n             ] = types(bytecode)\n    end\n\n    test \"@type with a tuple\" do\n      bytecode =\n        test_module do\n          @type tup :: tuple()\n          @type one :: {123}\n        end\n\n      assert [\n               type: {:one, {:type, _, :tuple, [{:integer, _, 123}]}, []},\n               type: {:tup, {:type, _, :tuple, :any}, []}\n             ] = types(bytecode)\n    end\n\n    test \"@type with a remote type\" do\n      bytecode =\n        test_module do\n          @type my_type :: Remote.Some.type()\n          @type my_type_arg :: Remote.type(integer)\n        end\n\n      assert [type: my_type, type: my_type_arg] = types(bytecode)\n\n      assert {:my_type, type, []} = my_type\n      assert {:remote_type, _, [{:atom, _, Remote.Some}, {:atom, _, :type}, []]} = type\n\n      assert {:my_type_arg, type, []} = my_type_arg\n      assert {:remote_type, _, args} = type\n      assert [{:atom, _, Remote}, {:atom, _, :type}, [{:type, _, :integer, []}]] = args\n    end\n\n    test \"@type with a binary\" do\n      bytecode =\n        test_module do\n          @type bin :: binary\n          @type empty :: <<>>\n          @type size :: <<_::3>>\n          @type unit :: <<_::_*8>>\n          @type size_and_unit :: <<_::3, _::_*8>>\n          @type size_prod_unit :: <<_::3*8>>\n        end\n\n      assert [\n               type: {:bin, {:type, _, :binary, []}, []},\n               type: {:empty, {:type, _, :binary, [{:integer, _, 0}, {:integer, _, 0}]}, []},\n               type: {:size, {:type, _, :binary, [{:integer, _, 3}, {:integer, _, 0}]}, []},\n               type:\n                 {:size_and_unit, {:type, _, :binary, [{:integer, _, 3}, {:integer, _, 8}]}, []},\n               type:\n                 {:size_prod_unit,\n                  {:type, _, :binary,\n                   [{:op, _, :*, {:integer, _, 3}, {:integer, _, 8}}, {:integer, _, 0}]}, []},\n               type: {:unit, {:type, _, :binary, [{:integer, _, 0}, {:integer, _, 8}]}, []}\n             ] = types(bytecode)\n    end\n\n    test \"@type with invalid binary spec\" do\n      assert_raise Kernel.TypespecError, ~r\"invalid binary specification\", fn ->\n        test_module do\n          @type my_type :: <<_::atom()>>\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"invalid binary specification\", fn ->\n        test_module do\n          @type my_type :: <<_::integer>>\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"invalid binary specification\", fn ->\n        test_module do\n          @type my_type :: <<_::(-4)>>\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"invalid binary specification\", fn ->\n        test_module do\n          @type my_type :: <<_::3, _::_*atom>>\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"invalid binary specification\", fn ->\n        test_module do\n          @type my_type :: <<_::3, _::_*(-8)>>\n        end\n      end\n\n      assert_raise Kernel.TypespecError, ~r\"invalid binary specification\", fn ->\n        test_module do\n          @type my_type :: <<_::3, _::_*257>>\n        end\n      end\n    end\n\n    test \"@type with a range op\" do\n      bytecode =\n        test_module do\n          @type range1 :: 1..10\n          @type range2 :: -1..1\n        end\n\n      assert [\n               {:type, {:range1, {:type, _, :range, range1_args}, []}},\n               {:type, {:range2, {:type, _, :range, range2_args}, []}}\n             ] = types(bytecode)\n\n      assert [{:integer, _, 1}, {:integer, _, 10}] = range1_args\n      assert [{:op, _, :-, {:integer, _, 1}}, {:integer, _, 1}] = range2_args\n    end\n\n    test \"@type with invalid range\" do\n      assert_raise Kernel.TypespecError, ~r\"invalid range specification\", fn ->\n        test_module do\n          @type my_type :: atom..10\n        end\n      end\n    end\n\n    test \"@type with a keyword map\" do\n      bytecode =\n        test_module do\n          @type my_type :: %{hello: :world}\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :map, [arg]} = type\n      assert {:type, _, :map_field_exact, [{:atom, _, :hello}, {:atom, _, :world}]} = arg\n    end\n\n    test \"@type with a map\" do\n      bytecode =\n        test_module do\n          @type my_type :: %{required(:a) => :b, optional(:c) => :d}\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :map, [arg1, arg2]} = type\n      assert {:type, _, :map_field_exact, [{:atom, _, :a}, {:atom, _, :b}]} = arg1\n      assert {:type, _, :map_field_assoc, [{:atom, _, :c}, {:atom, _, :d}]} = arg2\n    end\n\n    test \"@type with a struct\" do\n      bytecode =\n        test_module do\n          defstruct hello: nil, other: nil\n          @type my_type :: %TypespecSample{hello: :world}\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :map, [struct, arg1, arg2]} = type\n      assert {:type, _, :map_field_exact, struct_args} = struct\n      assert [{:atom, _, :__struct__}, {:atom, _, TypespecSample}] = struct_args\n      assert {:type, _, :map_field_exact, [{:atom, _, :hello}, {:atom, _, :world}]} = arg1\n      assert {:type, _, :map_field_exact, [{:atom, _, :other}, {:type, _, :term, []}]} = arg2\n    end\n\n    test \"@type with an exception struct\" do\n      bytecode =\n        test_module do\n          defexception [:message]\n          @type my_type :: %TypespecSample{}\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :map, [struct, arg1, arg2]} = type\n      assert {:type, _, :map_field_exact, struct_args} = struct\n      assert [{:atom, _, :__struct__}, {:atom, _, TypespecSample}] = struct_args\n      assert {:type, _, :map_field_exact, [{:atom, _, :__exception__}, {:atom, _, true}]} = arg1\n      assert {:type, _, :map_field_exact, [{:atom, _, :message}, {:type, _, :term, []}]} = arg2\n    end\n\n    @fields Enum.map(10..42, &{:\"f#{&1}\", :ok})\n\n    test \"@type with a large struct\" do\n      bytecode =\n        test_module do\n          defstruct unquote(@fields)\n          @type my_type :: %TypespecSample{unquote_splicing(@fields)}\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :map, [struct, arg1, arg2 | _]} = type\n      assert {:type, _, :map_field_exact, struct_args} = struct\n      assert [{:atom, _, :__struct__}, {:atom, _, TypespecSample}] = struct_args\n      assert {:type, _, :map_field_exact, [{:atom, _, :f10}, {:atom, _, :ok}]} = arg1\n      assert {:type, _, :map_field_exact, [{:atom, _, :f11}, {:atom, _, :ok}]} = arg2\n    end\n\n    test \"@type with struct does not @enforce_keys\" do\n      bytecode =\n        test_module do\n          @enforce_keys [:other]\n          defstruct hello: nil, other: nil\n          @type my_type :: %TypespecSample{hello: :world}\n        end\n\n      assert [type: {:my_type, _type, []}] = types(bytecode)\n    end\n\n    test \"@type with undefined struct\" do\n      assert_raise ArgumentError, ~r\"ThisModuleDoesNotExist.__struct__/1 is undefined\", fn ->\n        test_module do\n          @type my_type :: %ThisModuleDoesNotExist{}\n        end\n      end\n\n      assert_raise ArgumentError, ~r\"cannot access struct TypespecTest.TypespecSample\", fn ->\n        test_module do\n          @type my_type :: %TypespecSample{}\n        end\n      end\n    end\n\n    test \"@type with a struct with undefined field\" do\n      assert_raise Kernel.TypespecError,\n                   ~r\"undefined field :no_field on struct TypespecTest.TypespecSample\",\n                   fn ->\n                     test_module do\n                       defstruct [:hello, :eric]\n                       @type my_type :: %TypespecSample{no_field: :world}\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"undefined field :no_field on struct TypespecTest.TypespecSample\",\n                   fn ->\n                     test_module do\n                       defstruct [:hello, :eric]\n                       @type my_type :: %__MODULE__{no_field: :world}\n                     end\n                   end\n    end\n\n    test \"@type when overriding Elixir built-in\" do\n      assert_raise Kernel.TypespecError, ~r\"type struct/0 is a built-in type\", fn ->\n        test_module do\n          @type struct :: :oops\n        end\n      end\n    end\n\n    test \"@type when overriding Erlang built-in\" do\n      assert_raise Kernel.TypespecError, ~r\"type list/0 is a built-in type\", fn ->\n        test_module do\n          @type list :: :oops\n        end\n      end\n    end\n\n    test \"@type with public record\" do\n      bytecode =\n        test_module do\n          require Record\n          Record.defrecord(:timestamp, date: 1, time: 2)\n          @type my_type :: record(:timestamp, time: :foo)\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :tuple, [timestamp, term, foo]} = type\n      assert {:atom, 0, :timestamp} = timestamp\n      assert {:ann_type, 0, [{:var, 0, :date}, {:type, 0, :term, []}]} = term\n      assert {:ann_type, 0, [{:var, 0, :time}, {:atom, 0, :foo}]} = foo\n    end\n\n    test \"@type with private record\" do\n      bytecode =\n        test_module do\n          require Record\n          Record.defrecordp(:timestamp, date: 1, time: 2)\n          @type my_type :: record(:timestamp, time: :foo)\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :tuple, args} = type\n\n      assert [\n               {:atom, 0, :timestamp},\n               {:ann_type, 0, [{:var, 0, :date}, {:type, 0, :term, []}]},\n               {:ann_type, 0, [{:var, 0, :time}, {:atom, 0, :foo}]}\n             ] = args\n    end\n\n    test \"@type with named record\" do\n      bytecode =\n        test_module do\n          require Record\n          Record.defrecord(:timestamp, :my_timestamp, date: 1, time: 2)\n          @type my_type :: record(:timestamp, time: :foo)\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :tuple, [my_timestamp, term, _foo]} = type\n      assert {:atom, 0, :my_timestamp} = my_timestamp\n      assert {:ann_type, 0, [{:var, 0, :date}, {:type, 0, :term, []}]} = term\n      assert {:ann_type, 0, [{:var, 0, :time}, {:atom, 0, :foo}]}\n    end\n\n    test \"@type with undefined record\" do\n      assert_raise Kernel.TypespecError, ~r\"unknown record :this_record_does_not_exist\", fn ->\n        test_module do\n          @type my_type :: record(:this_record_does_not_exist, [])\n        end\n      end\n    end\n\n    test \"@type with a record with undefined field\" do\n      assert_raise Kernel.TypespecError, ~r\"undefined field no_field on record :timestamp\", fn ->\n        test_module do\n          require Record\n          Record.defrecord(:timestamp, date: 1, time: 2)\n          @type my_type :: record(:timestamp, no_field: :foo)\n        end\n      end\n    end\n\n    test \"@type with a record which declares the name as the type `atom` rather than an atom literal\" do\n      assert_raise Kernel.TypespecError, ~r\"expected the record name to be an atom literal\", fn ->\n        test_module do\n          @type my_type :: record(atom, field: :foo)\n        end\n      end\n    end\n\n    test \"@type named record/0 warns\" do\n      assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               bytecode =\n                 test_module do\n                   @type record :: binary\n                   @spec foo?(record) :: boolean\n                   def foo?(_), do: true\n                 end\n\n               assert [type: {:record, {:type, _, :binary, []}, []}] = types(bytecode)\n             end) =~ \"type record/0 is overriding a built-in type\"\n    end\n\n    test \"@type with an invalid map notation\" do\n      assert_raise Kernel.TypespecError, ~r\"invalid map specification\", fn ->\n        test_module do\n          @type content :: %{atom | String.t() => term}\n        end\n      end\n    end\n\n    test \"@type with list shortcuts\" do\n      bytecode =\n        test_module do\n          @type my_type :: []\n          @type my_type1 :: [integer]\n          @type my_type2 :: [integer, ...]\n        end\n\n      assert [\n               type: {:my_type, {:type, _, nil, []}, []},\n               type: {:my_type1, {:type, _, :list, [{:type, _, :integer, []}]}, []},\n               type: {:my_type2, {:type, _, :nonempty_list, [{:type, _, :integer, []}]}, []}\n             ] = types(bytecode)\n    end\n\n    test \"@type with a fun\" do\n      bytecode =\n        test_module do\n          @type my_type :: (... -> any)\n        end\n\n      assert [type: {:my_type, {:type, _, :fun, [{:type, _, :any}, {:type, _, :any, []}]}, []}] =\n               types(bytecode)\n    end\n\n    test \"@type with a fun with multiple arguments and return type\" do\n      bytecode =\n        test_module do\n          @type my_type :: (integer, integer -> integer)\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :fun, [args, return_type]} = type\n      assert {:type, _, :product, [{:type, _, :integer, []}, {:type, _, :integer, []}]} = args\n      assert {:type, _, :integer, []} = return_type\n    end\n\n    test \"@type with a fun with no arguments and return type\" do\n      bytecode =\n        test_module do\n          @type my_type :: (-> integer)\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :fun, [{:type, _, :product, []}, {:type, _, :integer, []}]} = type\n    end\n\n    test \"@type with a fun with any arity and return type\" do\n      bytecode =\n        test_module do\n          @type my_type :: (... -> integer)\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :fun, [{:type, _, :any}, {:type, _, :integer, []}]} = type\n    end\n\n    test \"@type with a union\" do\n      bytecode =\n        test_module do\n          @type my_type :: integer | charlist | atom\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :union, [integer, charlist, atom]} = type\n      assert {:type, _, :integer, []} = integer\n      assert {:remote_type, _, [{:atom, _, :elixir}, {:atom, _, :charlist}, []]} = charlist\n      assert {:type, _, :atom, []} = atom\n    end\n\n    test \"@type with keywords\" do\n      bytecode =\n        test_module do\n          @type my_type :: [first: integer, step: integer, last: integer]\n        end\n\n      assert [type: {:my_type, type, []}] = types(bytecode)\n      assert {:type, _, :list, [{:type, _, :union, union_types}]} = type\n\n      assert [\n               {:type, _, :tuple, [{:atom, _, :first}, {:type, _, :integer, []}]},\n               {:type, _, :tuple, [{:atom, _, :step}, {:type, _, :integer, []}]},\n               {:type, _, :tuple, [{:atom, _, :last}, {:type, _, :integer, []}]}\n             ] = union_types\n    end\n\n    test \"@type with parameters\" do\n      bytecode =\n        test_module do\n          @type my_type(x) :: x\n          @type my_type1(x) :: list(x)\n          @type my_type2(x, y) :: {x, y}\n        end\n\n      assert [\n               type: {:my_type, {:var, _, :x}, [{:var, _, :x}]},\n               type: {:my_type1, {:type, _, :list, [{:var, _, :x}]}, [{:var, _, :x}]},\n               type: {:my_type2, my_type2, [{:var, _, :x}, {:var, _, :y}]}\n             ] = types(bytecode)\n\n      assert {:type, _, :tuple, [{:var, _, :x}, {:var, _, :y}]} = my_type2\n    end\n\n    test \"@type with annotations\" do\n      bytecode =\n        test_module do\n          @type my_type :: named :: integer\n          @type my_type1 :: (a :: integer -> integer)\n        end\n\n      assert [type: {:my_type, my_type, []}, type: {:my_type1, my_type1, []}] = types(bytecode)\n\n      assert {:ann_type, _, [{:var, _, :named}, {:type, _, :integer, []}]} = my_type\n\n      assert {:type, _, :fun, [fun_args, fun_return]} = my_type1\n      assert {:type, _, :product, [{:ann_type, _, [a, {:type, _, :integer, []}]}]} = fun_args\n      assert {:var, _, :a} = a\n      assert {:type, _, :integer, []} = fun_return\n    end\n\n    test \"@type unquote fragment\" do\n      quoted =\n        quote unquote: false do\n          name = :my_type\n          type = :foo\n          @type unquote(name)() :: unquote(type)\n        end\n\n      bytecode =\n        test_module do\n          Code.eval_quoted(quoted, [], module: __MODULE__)\n        end\n\n      assert [type: {:my_type, {:atom, _, :foo}, []}] = types(bytecode)\n    end\n\n    test \"@type with module attributes\" do\n      bytecode =\n        test_module do\n          @keyword Keyword\n          @type kw :: @keyword.t\n          @type kw(value) :: @keyword.t(value)\n        end\n\n      assert [type: {:kw, kw, _}, type: {:kw, kw_with_value, [{:var, _, :value}]}] =\n               types(bytecode)\n\n      assert {:remote_type, _, [{:atom, _, Keyword}, {:atom, _, :t}, []]} = kw\n      assert {:remote_type, _, kw_with_value_args} = kw_with_value\n      assert [{:atom, _, Keyword}, {:atom, _, :t}, [{:var, _, :value}]] = kw_with_value_args\n    end\n\n    test \"@type with macro in alias\" do\n      bytecode =\n        test_module do\n          defmacro module() do\n            quote do: __MODULE__\n          end\n\n          @type my_type :: module().Foo\n        end\n\n      assert [type: {:my_type, {:atom, _, TypespecTest.TypespecSample.Foo}, []}] = types(bytecode)\n    end\n\n    test \"@type with a reserved signature\" do\n      assert_raise Kernel.TypespecError,\n                   ~r\"type required\\/1 is a reserved type and it cannot be defined\",\n                   fn ->\n                     test_module do\n                       @type required(arg) :: any()\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"type optional\\/1 is a reserved type and it cannot be defined\",\n                   fn ->\n                     test_module do\n                       @type optional(arg) :: any()\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"type required\\/1 is a reserved type and it cannot be defined\",\n                   fn ->\n                     test_module do\n                       @typep required(arg) :: any()\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"type optional\\/1 is a reserved type and it cannot be defined\",\n                   fn ->\n                     test_module do\n                       @typep optional(arg) :: any()\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"type required\\/1 is a reserved type and it cannot be defined\",\n                   fn ->\n                     test_module do\n                       @opaque required(arg) :: any()\n                     end\n                   end\n\n      assert_raise Kernel.TypespecError,\n                   ~r\"type optional\\/1 is a reserved type and it cannot be defined\",\n                   fn ->\n                     test_module do\n                       @opaque optional(arg) :: any()\n                     end\n                   end\n    end\n\n    test \"invalid remote @type with module attribute that does not evaluate to a module\" do\n      assert_raise Kernel.TypespecError, ~r/\\(@foo is \"bar\"\\)/, fn ->\n        test_module do\n          @foo \"bar\"\n          @type t :: @foo.t\n        end\n      end\n    end\n\n    test \"defines_type?\" do\n      test_module do\n        @type my_type :: tuple\n        @type my_type(a) :: [a]\n        assert Kernel.Typespec.defines_type?(__MODULE__, {:my_type, 0})\n        assert Kernel.Typespec.defines_type?(__MODULE__, {:my_type, 1})\n        refute Kernel.Typespec.defines_type?(__MODULE__, {:my_type, 2})\n      end\n    end\n\n    test \"spec_to_callback/2\" do\n      bytecode =\n        test_module do\n          @spec foo() :: term()\n          def foo(), do: :ok\n          Kernel.Typespec.spec_to_callback(__MODULE__, {:foo, 0})\n        end\n\n      assert specs(bytecode) == callbacks(bytecode)\n    end\n\n    test \"@opaque\" do\n      bytecode =\n        test_module do\n          @opaque my_type(x) :: x\n        end\n\n      assert [opaque: {:my_type, {:var, _, :x}, [{:var, _, :x}]}] = types(bytecode)\n    end\n\n    test \"@spec\" do\n      bytecode =\n        test_module do\n          def my_fun1(x), do: x\n          def my_fun2(), do: :ok\n          def my_fun3(x, y), do: {x, y}\n          def my_fun4(x), do: x\n          @spec my_fun1(integer) :: integer\n          @spec my_fun2() :: integer\n          @spec my_fun3(integer, integer) :: {integer, integer}\n          @spec my_fun4(x :: integer) :: integer\n        end\n\n      assert [my_fun1, my_fun2, my_fun3, my_fun4] = specs(bytecode)\n\n      assert {{:my_fun1, 1}, [{:type, _, :fun, args}]} = my_fun1\n      assert [{:type, _, :product, [{:type, _, :integer, []}]}, {:type, _, :integer, []}] = args\n\n      assert {{:my_fun2, 0}, [{:type, _, :fun, args}]} = my_fun2\n      assert [{:type, _, :product, []}, {:type, _, :integer, []}] = args\n\n      assert {{:my_fun3, 2}, [{:type, _, :fun, [arg1, arg2]}]} = my_fun3\n      assert {:type, _, :product, [{:type, _, :integer, []}, {:type, _, :integer, []}]} = arg1\n      assert {:type, _, :tuple, [{:type, _, :integer, []}, {:type, _, :integer, []}]} = arg2\n\n      assert {{:my_fun4, 1}, [{:type, _, :fun, args}]} = my_fun4\n      assert [x, {:type, _, :integer, []}] = args\n      assert {:type, _, :product, [{:ann_type, _, [{:var, _, :x}, {:type, _, :integer, []}]}]} = x\n    end\n\n    test \"@spec with vars matching built-ins\" do\n      bytecode =\n        test_module do\n          def my_fun1(x), do: x\n          def my_fun2(x), do: x\n          @spec my_fun1(tuple) :: tuple\n          @spec my_fun2(tuple) :: tuple when tuple: {integer, integer}\n        end\n\n      assert [my_fun1, my_fun2] = specs(bytecode)\n\n      assert {{:my_fun1, 1}, [{:type, _, :fun, args}]} = my_fun1\n      assert [{:type, _, :product, [{:type, _, :tuple, :any}]}, {:type, _, :tuple, :any}] = args\n\n      assert {{:my_fun2, 1}, [{:type, _, :bounded_fun, args}]} = my_fun2\n\n      assert [type, _] = args\n\n      assert {:type, _, :fun, [{:type, _, :product, [{:var, _, :tuple}]}, {:var, _, :tuple}]} =\n               type\n    end\n\n    test \"@spec with guards\" do\n      bytecode =\n        test_module do\n          def my_fun1(x), do: x\n          @spec my_fun1(x) :: boolean when x: integer\n\n          def my_fun2(x), do: x\n          @spec my_fun2(x) :: x when x: var\n\n          def my_fun3(_x, y), do: y\n          @spec my_fun3(x, y) :: y when y: x, x: var\n        end\n\n      assert [my_fun1, my_fun2, my_fun3] = specs(bytecode)\n\n      assert {{:my_fun1, 1}, [{:type, _, :bounded_fun, args}]} = my_fun1\n      assert [{:type, _, :fun, [product, {:type, _, :boolean, []}]}, constraints] = args\n      assert {:type, _, :product, [{:var, _, :x}]} = product\n      assert [{:type, _, :constraint, subtype}] = constraints\n      assert [{:atom, _, :is_subtype}, [{:var, _, :x}, {:type, _, :integer, []}]] = subtype\n\n      assert {{:my_fun2, 1}, [{:type, _, :fun, args}]} = my_fun2\n      assert [{:type, _, :product, [{:var, _, :x}]}, {:var, _, :x}] = args\n\n      assert {{:my_fun3, 2}, [{:type, _, :bounded_fun, args}]} = my_fun3\n      assert [{:type, _, :fun, fun_type}, [{:type, _, :constraint, constraint_type}]] = args\n      assert [{:type, _, :product, [{:var, _, :x}, {:var, _, :y}]}, {:var, _, :y}] = fun_type\n      assert [{:atom, _, :is_subtype}, [{:var, _, :y}, {:var, _, :x}]] = constraint_type\n    end\n\n    test \"@type, @opaque, and @typep as module attributes\" do\n      defmodule TypeModuleAttributes do\n        @type type1 :: boolean\n        @opaque opaque1 :: boolean\n        @typep typep1 :: boolean\n\n        def type1, do: @type\n        def opaque1, do: @opaque\n        def typep1, do: @typep\n\n        @type type2 :: atom\n        @type type3 :: pid\n        @opaque opaque2 :: atom\n        @opaque opaque3 :: pid\n        @typep typep2 :: atom\n\n        def type2, do: @type\n        def opaque2, do: @opaque\n        def typep2, do: @typep\n\n        # Avoid unused warnings\n        @spec foo(typep1) :: typep2\n        def foo(_x), do: :ok\n      end\n\n      assert [\n               {:type, {:\"::\", _, [{:type1, _, _}, {:boolean, _, _}]}, {TypeModuleAttributes, _}}\n             ] = TypeModuleAttributes.type1()\n\n      assert [\n               {:type, {:\"::\", _, [{:type3, _, _}, {:pid, _, _}]}, {TypeModuleAttributes, _}},\n               {:type, {:\"::\", _, [{:type2, _, _}, {:atom, _, _}]}, {TypeModuleAttributes, _}},\n               {:type, {:\"::\", _, [{:type1, _, _}, {:boolean, _, _}]}, {TypeModuleAttributes, _}}\n             ] = TypeModuleAttributes.type2()\n\n      assert [\n               {:opaque, {:\"::\", _, [{:opaque1, _, _}, {:boolean, _, _}]},\n                {TypeModuleAttributes, _}}\n             ] = TypeModuleAttributes.opaque1()\n\n      assert [\n               {:opaque, {:\"::\", _, [{:opaque3, _, _}, {:pid, _, _}]}, {TypeModuleAttributes, _}},\n               {:opaque, {:\"::\", _, [{:opaque2, _, _}, {:atom, _, _}]},\n                {TypeModuleAttributes, _}},\n               {:opaque, {:\"::\", _, [{:opaque1, _, _}, {:boolean, _, _}]},\n                {TypeModuleAttributes, _}}\n             ] = TypeModuleAttributes.opaque2()\n\n      assert [\n               {:typep, {:\"::\", _, [{:typep1, _, _}, {:boolean, _, _}]},\n                {TypeModuleAttributes, _}}\n             ] = TypeModuleAttributes.typep1()\n\n      assert [\n               {:typep, {:\"::\", _, [{:typep2, _, _}, {:atom, _, _}]}, {TypeModuleAttributes, _}},\n               {:typep, {:\"::\", _, [{:typep1, _, _}, {:boolean, _, _}]},\n                {TypeModuleAttributes, _}}\n             ] = TypeModuleAttributes.typep2()\n    after\n      :code.purge(TypeModuleAttributes)\n      :code.delete(TypeModuleAttributes)\n    end\n\n    test \"@spec, @callback, and @macrocallback as module attributes\" do\n      defmodule SpecModuleAttributes do\n        @callback callback1 :: integer\n        @macrocallback macrocallback1 :: integer\n\n        @spec spec1 :: boolean\n        def spec1, do: @spec\n\n        @callback callback2 :: var when var: boolean\n        @macrocallback macrocallback2 :: var when var: boolean\n\n        @spec spec2 :: atom\n        def spec2, do: @spec\n\n        @spec spec3 :: pid\n        def spec3, do: :ok\n        def spec4, do: @spec\n\n        def callback, do: @callback\n        def macrocallback, do: @macrocallback\n      end\n\n      assert [\n               {:spec, {:\"::\", _, [{:spec1, _, _}, {:boolean, _, _}]}, {SpecModuleAttributes, _}}\n             ] = SpecModuleAttributes.spec1()\n\n      assert [\n               {:spec, {:\"::\", _, [{:spec2, _, _}, {:atom, _, _}]}, {SpecModuleAttributes, _}},\n               {:spec, {:\"::\", _, [{:spec1, _, _}, {:boolean, _, _}]}, {SpecModuleAttributes, _}}\n             ] = SpecModuleAttributes.spec2()\n\n      assert [\n               {:spec, {:\"::\", _, [{:spec3, _, _}, {:pid, _, _}]}, {SpecModuleAttributes, _}},\n               {:spec, {:\"::\", _, [{:spec2, _, _}, {:atom, _, _}]}, {SpecModuleAttributes, _}},\n               {:spec, {:\"::\", _, [{:spec1, _, _}, {:boolean, _, _}]}, {SpecModuleAttributes, _}}\n             ] = SpecModuleAttributes.spec4()\n\n      assert [\n               {:callback,\n                {:when, _,\n                 [{:\"::\", _, [{:callback2, _, _}, {:var, _, _}]}, [var: {:boolean, _, _}]]},\n                {SpecModuleAttributes, _}},\n               {:callback, {:\"::\", _, [{:callback1, _, _}, {:integer, _, _}]},\n                {SpecModuleAttributes, _}}\n             ] = SpecModuleAttributes.callback()\n\n      assert [\n               {:macrocallback,\n                {:when, _,\n                 [{:\"::\", _, [{:macrocallback2, _, _}, {:var, _, _}]}, [var: {:boolean, _, _}]]},\n                {SpecModuleAttributes, _}},\n               {:macrocallback, {:\"::\", _, [{:macrocallback1, _, _}, {:integer, _, _}]},\n                {SpecModuleAttributes, _}}\n             ] = SpecModuleAttributes.macrocallback()\n    after\n      :code.purge(SpecModuleAttributes)\n      :code.delete(SpecModuleAttributes)\n    end\n\n    test \"@callback\" do\n      bytecode =\n        test_module do\n          @callback my_fun(integer) :: integer\n          @callback my_fun(list) :: list\n          @callback my_fun() :: integer\n          @callback my_fun(integer, integer) :: {integer, integer}\n        end\n\n      assert [my_fun_0, my_fun_1, my_fun_2] = callbacks(bytecode)\n\n      assert {{:my_fun, 0}, [{:type, _, :fun, args}]} = my_fun_0\n      assert [{:type, _, :product, []}, {:type, _, :integer, []}] = args\n\n      assert {{:my_fun, 1}, [clause1, clause2]} = my_fun_1\n      assert {:type, _, :fun, args1} = clause1\n      assert [{:type, _, :product, [{:type, _, :integer, []}]}, {:type, _, :integer, []}] = args1\n      assert {:type, _, :fun, args2} = clause2\n      assert [{:type, _, :product, [{:type, _, :list, []}]}, {:type, _, :list, []}] = args2\n\n      assert {{:my_fun, 2}, [{:type, _, :fun, [args_type, return_type]}]} = my_fun_2\n\n      assert {:type, _, :product, [{:type, _, :integer, []}, {:type, _, :integer, []}]} =\n               args_type\n\n      assert {:type, _, :tuple, [{:type, _, :integer, []}, {:type, _, :integer, []}]} =\n               return_type\n    end\n\n    test \"block handling\" do\n      bytecode =\n        test_module do\n          @spec foo((-> [integer])) :: integer\n          def foo(_), do: 1\n        end\n\n      assert [{{:foo, 1}, [{:type, _, :fun, [args, return]}]}] = specs(bytecode)\n      assert {:type, _, :product, [{:type, _, :fun, fun_args}]} = args\n      assert [{:type, _, :product, []}, {:type, _, :list, [{:type, _, :integer, []}]}] = fun_args\n      assert {:type, _, :integer, []} = return\n    end\n  end\n\n  describe \"Code.Typespec\" do\n    test \"type_to_quoted\" do\n      quoted =\n        Enum.sort([\n          quote(do: @type(tuple(arg) :: {:tuple, arg})),\n          quote(do: @type(with_ann() :: t :: atom())),\n          quote(do: @type(a_tuple() :: tuple())),\n          quote(do: @type(empty_tuple() :: {})),\n          quote(do: @type(one_tuple() :: {:foo})),\n          quote(do: @type(two_tuple() :: {:foo, :bar})),\n          quote(do: @type(custom_tuple() :: tuple(:foo))),\n          quote(do: @type(imm_type_1() :: 1)),\n          quote(do: @type(imm_type_2() :: :foo)),\n          quote(do: @type(simple_type() :: integer())),\n          quote(do: @type(param_type(p) :: [p])),\n          quote(do: @type(union_type() :: integer() | binary() | boolean())),\n          quote(do: @type(binary_type1() :: <<_::_*8>>)),\n          quote(do: @type(binary_type2() :: <<_::3>>)),\n          quote(do: @type(binary_type3() :: <<_::3, _::_*8>>)),\n          quote(do: @type(binary_type4() :: <<_::3*8>>)),\n          quote(do: @type(tuple_type() :: {integer()})),\n          quote(do: @type(ftype() :: (-> any()) | (-> integer()) | (integer() -> integer()))),\n          quote(do: @type(cl() :: charlist())),\n          quote(do: @type(st() :: struct())),\n          quote(do: @type(ab() :: as_boolean(term()))),\n          quote(do: @type(kw() :: keyword())),\n          quote(do: @type(kwt() :: keyword(term()))),\n          quote(do: @type(vaf() :: (... -> any()))),\n          quote(do: @type(rng() :: 1..10)),\n          quote(do: @type(opts() :: [first: integer(), step: integer(), last: integer()])),\n          quote(do: @type(ops() :: {+1, -1})),\n          quote(do: @type(map(arg) :: {:map, arg})),\n          quote(do: @type(a_map() :: map())),\n          quote(do: @type(empty_map() :: %{})),\n          quote(do: @type(my_map() :: %{hello: :world})),\n          quote(do: @type(my_req_map() :: %{required(0) => :foo})),\n          quote(do: @type(my_opt_map() :: %{optional(0) => :foo})),\n          quote(do: @type(my_struct() :: %TypespecTest{hello: :world})),\n          quote(do: @type(custom_map() :: map(:foo))),\n          quote(do: @type(list1() :: list())),\n          quote(do: @type(list2() :: [0])),\n          quote(do: @type(list3() :: [...])),\n          quote(do: @type(list4() :: [0, ...])),\n          quote(do: @type(nil_list() :: []))\n        ])\n\n      bytecode =\n        test_module do\n          Code.eval_quoted(quoted, [], module: __MODULE__)\n        end\n\n      types = types(bytecode)\n\n      Enum.each(Enum.zip(types, quoted), fn {{:type, type}, definition} ->\n        ast = Code.Typespec.type_to_quoted(type)\n        assert Macro.to_string(quote(do: @type(unquote(ast)))) == Macro.to_string(definition)\n      end)\n    end\n\n    test \"type_to_quoted for paren_type\" do\n      type = {:my_type, {:paren_type, 0, [{:type, 0, :integer, []}]}, []}\n\n      assert Code.Typespec.type_to_quoted(type) ==\n               {:\"::\", [], [{:my_type, [], []}, {:integer, [line: 0], []}]}\n    end\n\n    test \"spec_to_quoted\" do\n      quoted =\n        Enum.sort([\n          quote(do: @spec(foo() :: integer())),\n          quote(do: @spec(foo() :: union())),\n          quote(do: @spec(foo() :: union(integer()))),\n          quote(do: @spec(foo() :: truly_union())),\n          quote(do: @spec(foo(union()) :: union())),\n          quote(do: @spec(foo(union(integer())) :: union(integer()))),\n          quote(do: @spec(foo(truly_union()) :: truly_union())),\n          quote(do: @spec(foo(atom()) :: integer() | [{}])),\n          quote(do: @spec(foo(arg) :: integer() when [arg: integer()])),\n          quote(do: @spec(foo(arg) :: arg when [arg: var])),\n          quote(do: @spec(foo(arg :: atom()) :: atom()))\n        ])\n\n      bytecode =\n        test_module do\n          @type union :: any()\n          @type union(t) :: t\n          @type truly_union :: list | map | union\n\n          def foo(), do: 1\n          def foo(arg), do: arg\n          Code.eval_quoted(quote(do: (unquote_splicing(quoted))), [], module: __MODULE__)\n        end\n\n      specs =\n        Enum.flat_map(specs(bytecode), fn {{_, _}, specs} ->\n          Enum.map(specs, fn spec ->\n            quote(do: @spec(unquote(Code.Typespec.spec_to_quoted(:foo, spec))))\n          end)\n        end)\n\n      specs_with_quoted = specs |> Enum.sort() |> Enum.zip(quoted)\n\n      Enum.each(specs_with_quoted, fn {spec, definition} ->\n        assert Macro.to_string(spec) == Macro.to_string(definition)\n      end)\n    end\n\n    test \"spec_to_quoted with maps with __struct__ key\" do\n      defmodule StructA do\n        defstruct [:key]\n      end\n\n      defmodule StructB do\n        defstruct [:key]\n      end\n\n      bytecode =\n        test_module do\n          @spec single_struct(%StructA{}) :: :ok\n          def single_struct(arg), do: {:ok, arg}\n\n          @spec single_struct_key(%{__struct__: StructA}) :: :ok\n          def single_struct_key(arg), do: {:ok, arg}\n\n          @spec single_struct_key_type(%{__struct__: atom()}) :: :ok\n          def single_struct_key_type(arg), do: {:ok, arg}\n\n          @spec union_struct(%StructA{} | %StructB{}) :: :ok\n          def union_struct(arg), do: {:ok, arg}\n\n          @spec union_struct_key(%{__struct__: StructA | StructB}) :: :ok\n          def union_struct_key(arg), do: {:ok, arg}\n\n          @spec union_struct_key_type(%{__struct__: atom() | StructA | binary()}) :: :ok\n          def union_struct_key_type(arg), do: {:ok, arg}\n        end\n\n      [\n        {{:single_struct, 1}, [ast_single_struct]},\n        {{:single_struct_key, 1}, [ast_single_struct_key]},\n        {{:single_struct_key_type, 1}, [ast_single_struct_key_type]},\n        {{:union_struct, 1}, [ast_union_struct]},\n        {{:union_struct_key, 1}, [ast_union_struct_key]},\n        {{:union_struct_key_type, 1}, [ast_union_struct_key_type]}\n      ] = specs(bytecode)\n\n      assert Code.Typespec.spec_to_quoted(:single_struct, ast_single_struct)\n             |> Macro.to_string() ==\n               \"single_struct(%TypespecTest.StructA{key: term()}) :: :ok\"\n\n      assert Code.Typespec.spec_to_quoted(:single_struct_key, ast_single_struct_key)\n             |> Macro.to_string() ==\n               \"single_struct_key(%TypespecTest.StructA{}) :: :ok\"\n\n      assert Code.Typespec.spec_to_quoted(:single_struct_key_type, ast_single_struct_key_type)\n             |> Macro.to_string() ==\n               \"single_struct_key_type(%{__struct__: atom()}) :: :ok\"\n\n      assert Code.Typespec.spec_to_quoted(:union_struct, ast_union_struct) |> Macro.to_string() ==\n               \"union_struct(%TypespecTest.StructA{key: term()} | %TypespecTest.StructB{key: term()}) :: :ok\"\n\n      assert Code.Typespec.spec_to_quoted(:union_struct_key, ast_union_struct_key)\n             |> Macro.to_string() ==\n               \"union_struct_key(%{__struct__: TypespecTest.StructA | TypespecTest.StructB}) :: :ok\"\n\n      assert Code.Typespec.spec_to_quoted(:union_struct_key_type, ast_union_struct_key_type)\n             |> Macro.to_string() ==\n               \"union_struct_key_type(%{__struct__: atom() | TypespecTest.StructA | binary()}) :: :ok\"\n    end\n\n    test \"non-variables are given as arguments\" do\n      msg = ~r/The type one_bad_variable\\/1 has an invalid argument\\(s\\): String.t\\(\\)/\n\n      assert_raise Kernel.TypespecError, msg, fn ->\n        test_module do\n          @type one_bad_variable(String.t()) :: String.t()\n        end\n      end\n\n      msg = ~r/The type two_bad_variables\\/2 has an invalid argument\\(s\\): :ok, Enumerable.t\\(\\)/\n\n      assert_raise Kernel.TypespecError, msg, fn ->\n        test_module do\n          @type two_bad_variables(:ok, Enumerable.t()) :: {:ok, []}\n        end\n      end\n\n      msg = ~r/The type one_bad_one_good\\/2 has an invalid argument\\(s\\): \\\"\\\"/\n\n      assert_raise Kernel.TypespecError, msg, fn ->\n        test_module do\n          @type one_bad_one_good(input1, \"\") :: {:ok, input1}\n        end\n      end\n    end\n\n    test \"retrieval invalid data\" do\n      assert Code.Typespec.fetch_types(Unknown) == :error\n      assert Code.Typespec.fetch_specs(Unknown) == :error\n    end\n\n    # This is a test that implements all types specified in lib/elixir/pages/typespecs.md\n    test \"documented types and their AST\" do\n      defmodule SomeStruct do\n        defstruct [:key]\n      end\n\n      quoted =\n        Enum.sort([\n          ##  Basic types\n          quote(do: @type(basic_any() :: any())),\n          quote(do: @type(basic_none() :: none())),\n          quote(do: @type(basic_atom() :: atom())),\n          quote(do: @type(basic_map() :: map())),\n          quote(do: @type(basic_pid() :: pid())),\n          quote(do: @type(basic_port() :: port())),\n          quote(do: @type(basic_reference() :: reference())),\n          quote(do: @type(basic_struct() :: struct())),\n          quote(do: @type(basic_tuple() :: tuple())),\n\n          # Numbers\n          quote(do: @type(basic_float() :: float())),\n          quote(do: @type(basic_integer() :: integer())),\n          quote(do: @type(basic_neg_integer() :: neg_integer())),\n          quote(do: @type(basic_non_neg_integer() :: non_neg_integer())),\n          quote(do: @type(basic_pos_integer() :: pos_integer())),\n\n          # Lists\n          quote(do: @type(basic_list_type() :: list(integer()))),\n          quote(do: @type(basic_nonempty_list_type() :: nonempty_list(integer()))),\n          quote do\n            @type basic_maybe_improper_list_type() :: maybe_improper_list(integer(), atom())\n          end,\n          quote do\n            @type basic_nonempty_improper_list_type() :: nonempty_improper_list(integer(), atom())\n          end,\n          quote do\n            @type basic_nonempty_maybe_improper_list_type() ::\n                    nonempty_maybe_improper_list(integer(), atom())\n          end,\n\n          ## Literals\n          quote(do: @type(literal_atom() :: :atom)),\n          quote(do: @type(literal_integer() :: 1)),\n          quote(do: @type(literal_integers() :: 1..10)),\n          quote(do: @type(literal_empty_bitstring() :: <<>>)),\n          quote(do: @type(literal_size_0() :: <<_::0>>)),\n          quote(do: @type(literal_unit_1() :: <<_::_*1>>)),\n          quote(do: @type(literal_size_1_unit_8() :: <<_::100, _::_*256>>)),\n          quote(do: @type(literal_function_arity_any() :: (... -> integer()))),\n          quote(do: @type(literal_function_arity_0() :: (-> integer()))),\n          quote(do: @type(literal_function_arity_2() :: (integer(), atom() -> integer()))),\n          quote(do: @type(literal_list_type() :: [integer()])),\n          quote(do: @type(literal_empty_list() :: [])),\n          quote(do: @type(literal_list_nonempty() :: [...])),\n          quote(do: @type(literal_nonempty_list_type() :: [atom(), ...])),\n          quote(do: @type(literal_keyword_list_fixed_key() :: [key: integer()])),\n          quote(do: @type(literal_keyword_list_fixed_key2() :: [{:key, integer()}])),\n          quote(do: @type(literal_keyword_list_type_key() :: [{binary(), integer()}])),\n          quote(do: @type(literal_empty_map() :: %{})),\n          quote(do: @type(literal_map_with_key() :: %{key: integer()})),\n          quote(\n            do: @type(literal_map_with_required_key() :: %{required(bitstring()) => integer()})\n          ),\n          quote(\n            do: @type(literal_map_with_optional_key() :: %{optional(bitstring()) => integer()})\n          ),\n          quote(do: @type(literal_struct_all_fields_any_type() :: %SomeStruct{})),\n          quote(do: @type(literal_struct_all_fields_key_type() :: %SomeStruct{key: integer()})),\n          quote(do: @type(literal_empty_tuple() :: {})),\n          quote(do: @type(literal_2_element_tuple() :: {1, 2})),\n\n          ## Built-in types\n          quote(do: @type(built_in_term() :: term())),\n          quote(do: @type(built_in_arity() :: arity())),\n          quote(do: @type(built_in_as_boolean() :: as_boolean(:t))),\n          quote(do: @type(built_in_binary() :: binary())),\n          quote(do: @type(built_in_bitstring() :: bitstring())),\n          quote(do: @type(built_in_boolean() :: boolean())),\n          quote(do: @type(built_in_byte() :: byte())),\n          quote(do: @type(built_in_char() :: char())),\n          quote(do: @type(built_in_charlist() :: charlist())),\n          quote(do: @type(built_in_nonempty_charlist() :: nonempty_charlist())),\n          quote(do: @type(built_in_fun() :: fun())),\n          quote(do: @type(built_in_function() :: function())),\n          quote(do: @type(built_in_identifier() :: identifier())),\n          quote(do: @type(built_in_iodata() :: iodata())),\n          quote(do: @type(built_in_iolist() :: iolist())),\n          quote(do: @type(built_in_keyword() :: keyword())),\n          quote(do: @type(built_in_keyword_value_type() :: keyword(:t))),\n          quote(do: @type(built_in_list() :: list())),\n          quote(do: @type(built_in_nonempty_list() :: nonempty_list())),\n          quote(do: @type(built_in_maybe_improper_list() :: maybe_improper_list())),\n          quote(\n            do: @type(built_in_nonempty_maybe_improper_list() :: nonempty_maybe_improper_list())\n          ),\n          quote(do: @type(built_in_mfa() :: mfa())),\n          quote(do: @type(built_in_module() :: module())),\n          quote(do: @type(built_in_no_return() :: no_return())),\n          quote(do: @type(built_in_node() :: node())),\n          quote(do: @type(built_in_number() :: number())),\n          quote(do: @type(built_in_struct() :: struct())),\n          quote(do: @type(built_in_timeout() :: timeout())),\n\n          ## Remote types\n          quote(do: @type(remote_enum_t0() :: Enum.t())),\n          quote(do: @type(remote_keyword_t1() :: Keyword.t(integer())))\n        ])\n\n      bytecode =\n        test_module do\n          Code.eval_quoted(quoted, [], module: __MODULE__)\n        end\n\n      types = types(bytecode)\n\n      Enum.each(Enum.zip(types, quoted), fn {{:type, type}, definition} ->\n        ast = Code.Typespec.type_to_quoted(type)\n        ast_string = Macro.to_string(quote(do: @type(unquote(ast))))\n\n        case type do\n          # These cases do not translate directly to their own string version.\n          {:basic_list_type, _, _} ->\n            assert ast_string == \"@type basic_list_type() :: [integer()]\"\n\n          {:basic_nonempty_list_type, _, _} ->\n            assert ast_string == \"@type basic_nonempty_list_type() :: [integer(), ...]\"\n\n          {:literal_empty_bitstring, _, _} ->\n            assert ast_string == \"@type literal_empty_bitstring() :: <<_::0>>\"\n\n          {:literal_keyword_list_fixed_key, _, _} ->\n            assert ast_string == \"@type literal_keyword_list_fixed_key() :: [{:key, integer()}]\"\n\n          {:literal_keyword_list_fixed_key2, _, _} ->\n            assert ast_string == \"@type literal_keyword_list_fixed_key2() :: [{:key, integer()}]\"\n\n          {:literal_struct_all_fields_any_type, _, _} ->\n            assert ast_string ==\n                     \"@type literal_struct_all_fields_any_type() :: %TypespecTest.SomeStruct{key: term()}\"\n\n          {:literal_struct_all_fields_key_type, _, _} ->\n            assert ast_string ==\n                     \"@type literal_struct_all_fields_key_type() :: %TypespecTest.SomeStruct{key: integer()}\"\n\n          {:built_in_nonempty_list, _, _} ->\n            assert ast_string == \"@type built_in_nonempty_list() :: [...]\"\n\n          _ ->\n            assert ast_string == Macro.to_string(definition)\n        end\n      end)\n    end\n  end\n\n  describe \"behaviour_info\" do\n    defmodule SampleCallbacks do\n      @callback first(integer) :: integer\n      @callback foo(atom(), binary) :: binary\n      @callback bar(External.hello(), my_var :: binary) :: binary\n      @callback guarded(my_var) :: my_var when my_var: binary\n      @callback orr(atom | integer) :: atom\n      @callback literal(123, {atom}, :foo, [integer], true) :: atom\n      @macrocallback last(integer) :: Macro.t()\n      @macrocallback last() :: atom\n      @optional_callbacks bar: 2, last: 0\n      @optional_callbacks first: 1\n    end\n\n    test \"defines callbacks\" do\n      expected_callbacks = [\n        \"MACRO-last\": 1,\n        \"MACRO-last\": 2,\n        bar: 2,\n        first: 1,\n        foo: 2,\n        guarded: 1,\n        literal: 5,\n        orr: 1\n      ]\n\n      assert Enum.sort(SampleCallbacks.behaviour_info(:callbacks)) == expected_callbacks\n    end\n\n    test \"defines optional callbacks\" do\n      assert Enum.sort(SampleCallbacks.behaviour_info(:optional_callbacks)) ==\n               [\"MACRO-last\": 1, bar: 2, first: 1]\n    end\n  end\n\n  @tag tmp_dir: true\n  test \"erlang module\", c do\n    erlc(c, :typespec_test_mod, \"\"\"\n    -module(typespec_test_mod).\n    -export([f/1]).\n    -export_type([t/1]).\n\n    -type t(X) :: list(X).\n\n    -spec f(X) -> X.\n    f(X) -> X.\n    \"\"\")\n\n    [type: type] = types(:typespec_test_mod)\n\n    assert Code.Typespec.type_to_quoted(type) ==\n             {:\"::\", [],\n              [\n                {:t, [], [{:x, meta(5, 9), nil}]},\n                [{:x, meta(5, 20), nil}]\n              ]}\n\n    [{{:f, 1}, [spec]}] = specs(:typespec_test_mod)\n\n    assert Code.Typespec.spec_to_quoted(:f, spec) ==\n             {:when, meta(7, 8),\n              [\n                {:\"::\", meta(7, 8),\n                 [{:f, meta(7, 8), [{:x, meta(7, 9), nil}]}, {:x, meta(7, 15), nil}]},\n                [x: {:var, meta(7, 8), nil}]\n              ]}\n  end\n\n  defp meta(line, column) do\n    [line: line, column: column]\n  end\n\n  defp erlc(context, module, code) do\n    dir = context.tmp_dir\n\n    src_path = Path.join([dir, \"#{module}.erl\"])\n    src_path |> Path.dirname() |> File.mkdir_p!()\n    File.write!(src_path, code)\n\n    ebin_dir = Path.join(dir, \"ebin\")\n    File.mkdir_p!(ebin_dir)\n\n    {:ok, module} =\n      :compile.file(String.to_charlist(src_path), [\n        :debug_info,\n        outdir: String.to_charlist(ebin_dir)\n      ])\n\n    true = Code.prepend_path(ebin_dir)\n    {:module, ^module} = :code.load_file(module)\n\n    ExUnit.Callbacks.on_exit(fn ->\n      :code.purge(module)\n      :code.delete(module)\n      File.rm_rf!(dir)\n    end)\n\n    :ok\n  end\n\n  defp assert_compile_error(message, fun) do\n    assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n             assert_raise CompileError, fun\n           end) =~ message\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/uri_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule URITest do\n  use ExUnit.Case, async: true\n\n  doctest URI\n\n  test \"encode/1,2\" do\n    assert URI.encode(\"4_test.is-s~\") == \"4_test.is-s~\"\n\n    assert URI.encode(\"\\r\\n&<%>\\\" ゆ\", &URI.char_unreserved?/1) ==\n             \"%0D%0A%26%3C%25%3E%22%20%E3%82%86\"\n  end\n\n  test \"encode_www_form/1\" do\n    assert URI.encode_www_form(\"4test ~1.x\") == \"4test+~1.x\"\n    assert URI.encode_www_form(\"poll:146%\") == \"poll%3A146%25\"\n    assert URI.encode_www_form(\"/\\n+/ゆ\") == \"%2F%0A%2B%2F%E3%82%86\"\n  end\n\n  test \"encode_query/1,2\" do\n    assert URI.encode_query([{:foo, :bar}, {:baz, :quux}]) == \"foo=bar&baz=quux\"\n    assert URI.encode_query([{\"foo\", \"bar\"}, {\"baz\", \"quux\"}]) == \"foo=bar&baz=quux\"\n\n    assert URI.encode_query([{\"foo z\", :bar}]) == \"foo+z=bar\"\n    assert URI.encode_query([{\"foo z\", :bar}], :rfc3986) == \"foo%20z=bar\"\n    assert URI.encode_query([{\"foo z\", :bar}], :www_form) == \"foo+z=bar\"\n\n    assert URI.encode_query([{\"foo[]\", \"+=/?&# Ñ\"}]) ==\n             \"foo%5B%5D=%2B%3D%2F%3F%26%23+%C3%91\"\n\n    assert URI.encode_query([{\"foo[]\", \"+=/?&# Ñ\"}], :rfc3986) ==\n             \"foo%5B%5D=%2B%3D%2F%3F%26%23%20%C3%91\"\n\n    assert URI.encode_query([{\"foo[]\", \"+=/?&# Ñ\"}], :www_form) ==\n             \"foo%5B%5D=%2B%3D%2F%3F%26%23+%C3%91\"\n\n    assert_raise ArgumentError, fn ->\n      URI.encode_query([{\"foo\", ~c\"bar\"}])\n    end\n\n    assert_raise ArgumentError, fn ->\n      URI.encode_query([{~c\"foo\", \"bar\"}])\n    end\n  end\n\n  test \"decode_query/1,2,3\" do\n    assert URI.decode_query(\"\", %{}) == %{}\n\n    assert URI.decode_query(\"safe=off\", %{\"cookie\" => \"foo\"}) ==\n             %{\"safe\" => \"off\", \"cookie\" => \"foo\"}\n\n    assert URI.decode_query(\"q=search%20query&cookie=ab%26cd&block+buster=\") ==\n             %{\"block buster\" => \"\", \"cookie\" => \"ab&cd\", \"q\" => \"search query\"}\n\n    assert URI.decode_query(\"q=search%20query&cookie=ab%26cd&block+buster=\", %{}, :rfc3986) ==\n             %{\"block+buster\" => \"\", \"cookie\" => \"ab&cd\", \"q\" => \"search query\"}\n\n    assert URI.decode_query(\"something=weird%3Dhappening\") == %{\"something\" => \"weird=happening\"}\n\n    assert URI.decode_query(\"=\") == %{\"\" => \"\"}\n    assert URI.decode_query(\"key\") == %{\"key\" => \"\"}\n    assert URI.decode_query(\"key=\") == %{\"key\" => \"\"}\n    assert URI.decode_query(\"=value\") == %{\"\" => \"value\"}\n    assert URI.decode_query(\"something=weird=happening\") == %{\"something\" => \"weird=happening\"}\n  end\n\n  test \"query_decoder/1,2\" do\n    decoder = URI.query_decoder(\"q=search%20query&cookie=ab%26cd&block+buster=\")\n    expected = [{\"q\", \"search query\"}, {\"cookie\", \"ab&cd\"}, {\"block buster\", \"\"}]\n    assert Enum.map(decoder, & &1) == expected\n\n    decoder = URI.query_decoder(\"q=search%20query&cookie=ab%26cd&block+buster=\", :rfc3986)\n    expected = [{\"q\", \"search query\"}, {\"cookie\", \"ab&cd\"}, {\"block+buster\", \"\"}]\n    assert Enum.map(decoder, & &1) == expected\n  end\n\n  test \"decode/1\" do\n    assert URI.decode(\"%0D%0A%26%3C%25%3E%22%20%E3%82%86\") == \"\\r\\n&<%>\\\" ゆ\"\n    assert URI.decode(\"%2f%41%4a%55\") == \"/AJU\"\n    assert URI.decode(\"4_t+st.is-s~\") == \"4_t+st.is-s~\"\n    assert URI.decode(\"% invalid\") == \"% invalid\"\n    assert URI.decode(\"invalid %\") == \"invalid %\"\n    assert URI.decode(\"%%\") == \"%%\"\n  end\n\n  test \"decode_www_form/1\" do\n    assert URI.decode_www_form(\"%3Eval+ue%2B\") == \">val ue+\"\n    assert URI.decode_www_form(\"%E3%82%86+\") == \"ゆ \"\n    assert URI.decode_www_form(\"% invalid\") == \"% invalid\"\n    assert URI.decode_www_form(\"invalid %\") == \"invalid %\"\n    assert URI.decode_www_form(\"%%\") == \"%%\"\n  end\n\n  describe \"new/1\" do\n    test \"empty\" do\n      assert URI.new(\"\") == {:ok, %URI{}}\n    end\n\n    test \"errors on bad URIs\" do\n      assert URI.new(\"/>\") == {:error, \">\"}\n      assert URI.new(\":https\") == {:error, \":\"}\n      assert URI.new(\"ht\\0tps://foo.com\") == {:error, \"\\0\"}\n    end\n  end\n\n  describe \"new!/1\" do\n    test \"returns the given URI if a %URI{} struct is given\" do\n      assert URI.new!(uri = %URI{scheme: \"http\", host: \"foo.com\"}) == uri\n    end\n\n    test \"works with HTTP scheme\" do\n      expected_uri = %URI{\n        scheme: \"http\",\n        host: \"foo.com\",\n        path: \"/path/to/something\",\n        query: \"foo=bar&bar=foo\",\n        fragment: \"fragment\",\n        port: 80,\n        userinfo: nil\n      }\n\n      assert URI.new!(\"http://foo.com/path/to/something?foo=bar&bar=foo#fragment\") ==\n               expected_uri\n    end\n\n    test \"works with HTTPS scheme\" do\n      expected_uri = %URI{\n        scheme: \"https\",\n        host: \"foo.com\",\n        query: nil,\n        fragment: nil,\n        port: 443,\n        path: nil,\n        userinfo: nil\n      }\n\n      assert URI.new!(\"https://foo.com\") == expected_uri\n    end\n\n    test \"works with file scheme\" do\n      expected_uri = %URI{\n        scheme: \"file\",\n        host: \"\",\n        path: \"/foo/bar/baz\",\n        userinfo: nil,\n        query: nil,\n        fragment: nil,\n        port: nil\n      }\n\n      assert URI.new!(\"file:///foo/bar/baz\") == expected_uri\n    end\n\n    test \"works with FTP scheme\" do\n      expected_uri = %URI{\n        scheme: \"ftp\",\n        host: \"private.ftp-server.example.com\",\n        userinfo: \"user001:password\",\n        path: \"/my_directory/my_file.txt\",\n        query: nil,\n        fragment: nil,\n        port: 21\n      }\n\n      ftp = \"ftp://user001:password@private.ftp-server.example.com/my_directory/my_file.txt\"\n      assert URI.new!(ftp) == expected_uri\n    end\n\n    test \"works with SFTP scheme\" do\n      expected_uri = %URI{\n        scheme: \"sftp\",\n        host: \"private.ftp-server.example.com\",\n        userinfo: \"user001:password\",\n        path: \"/my_directory/my_file.txt\",\n        query: nil,\n        fragment: nil,\n        port: 22\n      }\n\n      sftp = \"sftp://user001:password@private.ftp-server.example.com/my_directory/my_file.txt\"\n      assert URI.new!(sftp) == expected_uri\n    end\n\n    test \"works with TFTP scheme\" do\n      expected_uri = %URI{\n        scheme: \"tftp\",\n        host: \"private.ftp-server.example.com\",\n        userinfo: \"user001:password\",\n        path: \"/my_directory/my_file.txt\",\n        query: nil,\n        fragment: nil,\n        port: 69\n      }\n\n      tftp = \"tftp://user001:password@private.ftp-server.example.com/my_directory/my_file.txt\"\n      assert URI.new!(tftp) == expected_uri\n    end\n\n    test \"works with LDAP scheme\" do\n      expected_uri = %URI{\n        scheme: \"ldap\",\n        host: \"\",\n        userinfo: nil,\n        path: \"/dc=example,dc=com\",\n        query: \"?sub?(givenName=John)\",\n        fragment: nil,\n        port: 389\n      }\n\n      assert URI.new!(\"ldap:///dc=example,dc=com??sub?(givenName=John)\") == expected_uri\n\n      expected_uri = %URI{\n        scheme: \"ldap\",\n        host: \"ldap.example.com\",\n        userinfo: nil,\n        path: \"/cn=John%20Doe,dc=foo,dc=com\",\n        fragment: nil,\n        port: 389,\n        query: nil\n      }\n\n      assert URI.new!(\"ldap://ldap.example.com/cn=John%20Doe,dc=foo,dc=com\") == expected_uri\n    end\n\n    test \"can parse IPv6 addresses\" do\n      addresses = [\n        # undefined\n        \"::\",\n        # loopback\n        \"::1\",\n        # unicast\n        \"1080::8:800:200C:417A\",\n        # multicast\n        \"FF01::101\",\n        # link-local\n        \"fe80::\",\n        # abbreviated\n        \"2607:f3f0:2:0:216:3cff:fef0:174a\",\n        # mixed hex case\n        \"2607:f3F0:2:0:216:3cFf:Fef0:174A\",\n        # complete\n        \"2051:0db8:2d5a:3521:8313:ffad:1242:8e2e\",\n        # embedded IPv4\n        \"::00:192.168.10.184\"\n      ]\n\n      Enum.each(addresses, fn addr ->\n        simple_uri = URI.new!(\"http://[#{addr}]/\")\n        assert simple_uri.host == addr\n\n        userinfo_uri = URI.new!(\"http://user:pass@[#{addr}]/\")\n        assert userinfo_uri.host == addr\n        assert userinfo_uri.userinfo == \"user:pass\"\n\n        port_uri = URI.new!(\"http://[#{addr}]:2222/\")\n        assert port_uri.host == addr\n        assert port_uri.port == 2222\n\n        userinfo_port_uri = URI.new!(\"http://user:pass@[#{addr}]:2222/\")\n        assert userinfo_port_uri.host == addr\n        assert userinfo_port_uri.userinfo == \"user:pass\"\n        assert userinfo_port_uri.port == 2222\n      end)\n    end\n\n    test \"downcases the scheme\" do\n      assert URI.new!(\"hTtP://google.com\").scheme == \"http\"\n    end\n\n    test \"preserves empty fragments\" do\n      assert URI.new!(\"http://example.com#\").fragment == \"\"\n      assert URI.new!(\"http://example.com/#\").fragment == \"\"\n      assert URI.new!(\"http://example.com/test#\").fragment == \"\"\n    end\n\n    test \"preserves an empty query\" do\n      assert URI.new!(\"http://foo.com/?\").query == \"\"\n    end\n\n    test \"without scheme, undefined port after host translates to nil\" do\n      assert URI.new!(\"//https://www.example.com\") ==\n               %URI{\n                 scheme: nil,\n                 userinfo: nil,\n                 host: \"https\",\n                 port: nil,\n                 path: \"//www.example.com\",\n                 query: nil,\n                 fragment: nil\n               }\n    end\n\n    test \"with scheme, undefined port after host translates to nil\" do\n      assert URI.new!(\"myscheme://myhost:/path/info\") ==\n               %URI{\n                 scheme: \"myscheme\",\n                 userinfo: nil,\n                 host: \"myhost\",\n                 port: nil,\n                 path: \"/path/info\",\n                 query: nil,\n                 fragment: nil\n               }\n    end\n  end\n\n  test \"http://http://http://@http://http://?http://#http://\" do\n    assert URI.parse(\"http://http://http://@http://http://?http://#http://\") ==\n             %URI{\n               scheme: \"http\",\n               authority: \"http:\",\n               userinfo: nil,\n               host: \"http\",\n               port: 80,\n               path: \"//http://@http://http://\",\n               query: \"http://\",\n               fragment: \"http://\"\n             }\n\n    assert URI.new!(\"http://http://http://@http://http://?http://#http://\") ==\n             %URI{\n               scheme: \"http\",\n               userinfo: nil,\n               host: \"http\",\n               port: 80,\n               path: \"//http://@http://http://\",\n               query: \"http://\",\n               fragment: \"http://\"\n             }\n  end\n\n  test \"default_port/1,2\" do\n    assert URI.default_port(\"http\") == 80\n\n    try do\n      URI.default_port(\"http\", 8000)\n      assert URI.default_port(\"http\") == 8000\n    after\n      URI.default_port(\"http\", 80)\n    end\n\n    assert URI.default_port(\"unknown\") == nil\n    URI.default_port(\"unknown\", 13)\n    assert URI.default_port(\"unknown\") == 13\n  end\n\n  test \"to_string/1 and Kernel.to_string/1\" do\n    assert to_string(URI.new!(\"http://google.com\")) == \"http://google.com\"\n    assert to_string(URI.new!(\"http://google.com:443\")) == \"http://google.com:443\"\n    assert to_string(URI.new!(\"https://google.com:443\")) == \"https://google.com\"\n    assert to_string(URI.new!(\"file:/path\")) == \"file:/path\"\n    assert to_string(URI.new!(\"file:///path\")) == \"file:///path\"\n    assert to_string(URI.new!(\"file://///path\")) == \"file://///path\"\n    assert to_string(URI.new!(\"http://lol:wut@google.com\")) == \"http://lol:wut@google.com\"\n    assert to_string(URI.new!(\"http://google.com/elixir\")) == \"http://google.com/elixir\"\n    assert to_string(URI.new!(\"http://google.com?q=lol\")) == \"http://google.com?q=lol\"\n    assert to_string(URI.new!(\"http://google.com?q=lol#omg\")) == \"http://google.com?q=lol#omg\"\n    assert to_string(URI.new!(\"//google.com/elixir\")) == \"//google.com/elixir\"\n    assert to_string(URI.new!(\"//google.com:8080/elixir\")) == \"//google.com:8080/elixir\"\n    assert to_string(URI.new!(\"//user:password@google.com/\")) == \"//user:password@google.com/\"\n    assert to_string(URI.new!(\"http://[2001:db8::]:8080\")) == \"http://[2001:db8::]:8080\"\n    assert to_string(URI.new!(\"http://[2001:db8::]\")) == \"http://[2001:db8::]\"\n\n    assert URI.to_string(URI.new!(\"http://google.com\")) == \"http://google.com\"\n    assert URI.to_string(URI.new!(\"gid:hello/123\")) == \"gid:hello/123\"\n\n    assert URI.to_string(URI.new!(\"//user:password@google.com/\")) ==\n             \"//user:password@google.com/\"\n\n    assert_raise ArgumentError,\n                 ~r\":path in URI must be empty or an absolute path if URL has a :host\",\n                 fn -> %URI{host: \"foo.com\", path: \"hello/123\"} |> URI.to_string() end\n  end\n\n  describe \"merge/2\" do\n    test \"with valid paths\" do\n      assert URI.merge(\"http://google.com/foo\", \"http://example.com/baz\")\n             |> to_string() == \"http://example.com/baz\"\n\n      assert URI.merge(\"http://google.com/foo\", \"http://example.com/.././bar/../../baz\")\n             |> to_string() == \"http://example.com/baz\"\n\n      assert URI.merge(\"http://google.com/foo\", \"//example.com/baz\")\n             |> to_string() == \"http://example.com/baz\"\n\n      assert URI.merge(\"http://google.com/foo\", URI.new!(\"//example.com/baz\"))\n             |> to_string() == \"http://example.com/baz\"\n\n      assert URI.merge(\"http://google.com/foo\", \"//example.com/.././bar/../../../baz\")\n             |> to_string() == \"http://example.com/baz\"\n\n      assert URI.merge(\"http://example.com\", URI.new!(\"/foo\"))\n             |> to_string() == \"http://example.com/foo\"\n\n      assert URI.merge(\"http://example.com\", URI.new!(\"/.././bar/../../../baz\"))\n             |> to_string() == \"http://example.com/baz\"\n\n      base = URI.new!(\"http://example.com/foo/bar\")\n      assert URI.merge(base, \"\") |> to_string() == \"http://example.com/foo/bar\"\n      assert URI.merge(base, \"#fragment\") |> to_string() == \"http://example.com/foo/bar#fragment\"\n      assert URI.merge(base, \"?query\") |> to_string() == \"http://example.com/foo/bar?query\"\n      assert URI.merge(base, %URI{}) |> to_string() == \"http://example.com/foo/bar\"\n\n      assert URI.merge(base, %URI{fragment: \"fragment\"})\n             |> to_string() == \"http://example.com/foo/bar#fragment\"\n\n      base = URI.new!(\"http://example.com\")\n      assert URI.merge(base, \"/foo\") |> to_string() == \"http://example.com/foo\"\n      assert URI.merge(base, \"foo\") |> to_string() == \"http://example.com/foo\"\n\n      base = URI.new!(\"http://example.com/foo/bar\")\n      assert URI.merge(base, \"/baz\") |> to_string() == \"http://example.com/baz\"\n      assert URI.merge(base, \"baz\") |> to_string() == \"http://example.com/foo/baz\"\n      assert URI.merge(base, \"../baz\") |> to_string() == \"http://example.com/baz\"\n      assert URI.merge(base, \".././baz\") |> to_string() == \"http://example.com/baz\"\n      assert URI.merge(base, \"./baz\") |> to_string() == \"http://example.com/foo/baz\"\n      assert URI.merge(base, \"bar/./baz\") |> to_string() == \"http://example.com/foo/bar/baz\"\n\n      base = URI.new!(\"http://example.com/foo/bar/\")\n      assert URI.merge(base, \"/baz\") |> to_string() == \"http://example.com/baz\"\n      assert URI.merge(base, \"baz\") |> to_string() == \"http://example.com/foo/bar/baz\"\n      assert URI.merge(base, \"../baz\") |> to_string() == \"http://example.com/foo/baz\"\n      assert URI.merge(base, \".././baz\") |> to_string() == \"http://example.com/foo/baz\"\n      assert URI.merge(base, \"./baz\") |> to_string() == \"http://example.com/foo/bar/baz\"\n      assert URI.merge(base, \"bar/./baz\") |> to_string() == \"http://example.com/foo/bar/bar/baz\"\n\n      base = URI.new!(\"http://example.com/foo/bar/baz\")\n      assert URI.merge(base, \"../../foobar\") |> to_string() == \"http://example.com/foobar\"\n      assert URI.merge(base, \"../../../foobar\") |> to_string() == \"http://example.com/foobar\"\n\n      assert URI.merge(base, \"../../../../../../foobar\") |> to_string() ==\n               \"http://example.com/foobar\"\n\n      base = URI.new!(\"http://example.com/foo/../bar\")\n      assert URI.merge(base, \"baz\") |> to_string() == \"http://example.com/baz\"\n\n      base = URI.new!(\"http://example.com/foo/./bar\")\n      assert URI.merge(base, \"baz\") |> to_string() == \"http://example.com/foo/baz\"\n\n      base = URI.new!(\"http://example.com/foo?query1\")\n      assert URI.merge(base, \"?query2\") |> to_string() == \"http://example.com/foo?query2\"\n      assert URI.merge(base, \"\") |> to_string() == \"http://example.com/foo?query1\"\n\n      base = URI.new!(\"http://example.com/foo#fragment1\")\n      assert URI.merge(base, \"#fragment2\") |> to_string() == \"http://example.com/foo#fragment2\"\n      assert URI.merge(base, \"\") |> to_string() == \"http://example.com/foo\"\n\n      page_url = \"https://example.com/guide/\"\n      image_url = \"https://images.example.com/t/1600x/https://images.example.com/foo.jpg\"\n\n      assert URI.merge(URI.new!(page_url), URI.new!(image_url)) |> to_string() ==\n               \"https://images.example.com/t/1600x/https://images.example.com/foo.jpg\"\n    end\n\n    test \"error on relative base\" do\n      assert_raise ArgumentError, \"you must merge onto an absolute URI\", fn ->\n        URI.merge(\"/relative\", \"\")\n      end\n    end\n\n    test \"base without host\" do\n      assert URI.merge(\"tag:example\", \"foo\") |> to_string == \"tag:foo\"\n      assert URI.merge(\"tag:example\", \"#fragment\") |> to_string == \"tag:example#fragment\"\n    end\n\n    test \"base without host and path\" do\n      assert URI.merge(\"ex:\", \"test\") |> to_string() == \"ex:test\"\n      assert URI.merge(\"ex:\", \"a/b/c\") |> to_string() == \"ex:a/b/c\"\n      assert URI.merge(\"ex:\", \"a/b/./../c\") |> to_string() == \"ex:a/c\"\n      assert URI.merge(\"ex:\", \"test?query=value\") |> to_string() == \"ex:test?query=value\"\n      assert URI.merge(\"mailto:\", \"user@example.com\") |> to_string() == \"mailto:user@example.com\"\n      assert URI.merge(\"urn:isbn\", \"0451450523\") |> to_string() == \"urn:0451450523\"\n    end\n\n    test \"with RFC examples\" do\n      # These are examples from:\n      #\n      # https://www.rfc-editor.org/rfc/rfc3986#section-5.4.1\n      # https://www.rfc-editor.org/rfc/rfc3986#section-5.4.2\n      #\n      # They are taken verbatim from the above document for easy comparison\n\n      base = \"http://a/b/c/d;p?q\"\n\n      rel_and_result = %{\n        \"g:h\" => \"g:h\",\n        \"g\" => \"http://a/b/c/g\",\n        \"./g\" => \"http://a/b/c/g\",\n        \"g/\" => \"http://a/b/c/g/\",\n        \"/g\" => \"http://a/g\",\n        \"//g\" => \"http://g\",\n        \"?y\" => \"http://a/b/c/d;p?y\",\n        \"g?y\" => \"http://a/b/c/g?y\",\n        \"#s\" => \"http://a/b/c/d;p?q#s\",\n        \"g#s\" => \"http://a/b/c/g#s\",\n        \"g?y#s\" => \"http://a/b/c/g?y#s\",\n        \";x\" => \"http://a/b/c/;x\",\n        \"g;x\" => \"http://a/b/c/g;x\",\n        \"g;x?y#s\" => \"http://a/b/c/g;x?y#s\",\n        \"\" => \"http://a/b/c/d;p?q\",\n        \".\" => \"http://a/b/c/\",\n        \"./\" => \"http://a/b/c/\",\n        \"..\" => \"http://a/b/\",\n        \"../\" => \"http://a/b/\",\n        \"../g\" => \"http://a/b/g\",\n        \"../..\" => \"http://a/\",\n        \"../../\" => \"http://a/\",\n        \"../../g\" => \"http://a/g\",\n        \"../../../g\" => \"http://a/g\",\n        \"../../../../g\" => \"http://a/g\",\n        \"/./g\" => \"http://a/g\",\n        \"/../g\" => \"http://a/g\",\n        \"g.\" => \"http://a/b/c/g.\",\n        \".g\" => \"http://a/b/c/.g\",\n        \"g..\" => \"http://a/b/c/g..\",\n        \"..g\" => \"http://a/b/c/..g\",\n        \"./../g\" => \"http://a/b/g\",\n        \"./g/.\" => \"http://a/b/c/g/\",\n        \"g/./h\" => \"http://a/b/c/g/h\",\n        \"g/../h\" => \"http://a/b/c/h\",\n        \"g;x=1/./y\" => \"http://a/b/c/g;x=1/y\",\n        \"g;x=1/../y\" => \"http://a/b/c/y\",\n        \"g?y/./x\" => \"http://a/b/c/g?y/./x\",\n        \"g?y/../x\" => \"http://a/b/c/g?y/../x\",\n        \"g#s/./x\" => \"http://a/b/c/g#s/./x\",\n        \"g#s/../x\" => \"http://a/b/c/g#s/../x\",\n        \"http:g\" => \"http:g\"\n      }\n\n      for {rel, result} <- rel_and_result do\n        assert URI.merge(base, rel) |> URI.to_string() == result\n      end\n    end\n\n    test \"with W3C examples\" do\n      # These examples are from the W3C JSON-LD test suite:\n      #\n      # https://w3c.github.io/json-ld-api/tests/toRdf-manifest#t0124\n      # https://w3c.github.io/json-ld-api/tests/toRdf-manifest#t0125\n      # https://w3c.github.io/json-ld-api/tests/toRdf-manifest#t0123\n\n      base1 = \"http://a/bb/ccc/.\"\n\n      rel_and_result1 = %{\n        \"g:h\" => \"g:h\",\n        \"g\" => \"http://a/bb/ccc/g\",\n        \"./g\" => \"http://a/bb/ccc/g\",\n        \"g/\" => \"http://a/bb/ccc/g/\",\n        \"/g\" => \"http://a/g\",\n        \"//g\" => \"http://g\",\n        \"?y\" => \"http://a/bb/ccc/.?y\",\n        \"g?y\" => \"http://a/bb/ccc/g?y\",\n        \"#s\" => \"http://a/bb/ccc/.#s\",\n        \"g#s\" => \"http://a/bb/ccc/g#s\",\n        \"g?y#s\" => \"http://a/bb/ccc/g?y#s\",\n        \";x\" => \"http://a/bb/ccc/;x\",\n        \"g;x\" => \"http://a/bb/ccc/g;x\",\n        \"g;x?y#s\" => \"http://a/bb/ccc/g;x?y#s\",\n        \"\" => \"http://a/bb/ccc/.\",\n        \".\" => \"http://a/bb/ccc/\",\n        \"./\" => \"http://a/bb/ccc/\",\n        \"..\" => \"http://a/bb/\",\n        \"../\" => \"http://a/bb/\",\n        \"../g\" => \"http://a/bb/g\",\n        \"../..\" => \"http://a/\",\n        \"../../\" => \"http://a/\",\n        \"../../g\" => \"http://a/g\",\n        \"../../../g\" => \"http://a/g\",\n        \"../../../../g\" => \"http://a/g\",\n        \"/./g\" => \"http://a/g\",\n        \"/../g\" => \"http://a/g\",\n        \"g.\" => \"http://a/bb/ccc/g.\",\n        \".g\" => \"http://a/bb/ccc/.g\",\n        \"g..\" => \"http://a/bb/ccc/g..\",\n        \"..g\" => \"http://a/bb/ccc/..g\",\n        \"./../g\" => \"http://a/bb/g\",\n        \"./g/.\" => \"http://a/bb/ccc/g/\",\n        \"g/./h\" => \"http://a/bb/ccc/g/h\",\n        \"g/../h\" => \"http://a/bb/ccc/h\",\n        \"g;x=1/./y\" => \"http://a/bb/ccc/g;x=1/y\",\n        \"g;x=1/../y\" => \"http://a/bb/ccc/y\",\n        \"g?y/./x\" => \"http://a/bb/ccc/g?y/./x\",\n        \"g?y/../x\" => \"http://a/bb/ccc/g?y/../x\",\n        \"g#s/./x\" => \"http://a/bb/ccc/g#s/./x\",\n        \"g#s/../x\" => \"http://a/bb/ccc/g#s/../x\",\n        \"http:g\" => \"http:g\"\n      }\n\n      for {rel, result} <- rel_and_result1 do\n        assert URI.merge(base1, rel) |> URI.to_string() == result\n      end\n\n      base2 = \"http://a/bb/ccc/..\"\n\n      rel_and_result2 = %{\n        \"g:h\" => \"g:h\",\n        \"g\" => \"http://a/bb/ccc/g\",\n        \"./g\" => \"http://a/bb/ccc/g\",\n        \"g/\" => \"http://a/bb/ccc/g/\",\n        \"/g\" => \"http://a/g\",\n        \"//g\" => \"http://g\",\n        \"?y\" => \"http://a/bb/ccc/..?y\",\n        \"g?y\" => \"http://a/bb/ccc/g?y\",\n        \"#s\" => \"http://a/bb/ccc/..#s\",\n        \"g#s\" => \"http://a/bb/ccc/g#s\",\n        \"g?y#s\" => \"http://a/bb/ccc/g?y#s\",\n        \";x\" => \"http://a/bb/ccc/;x\",\n        \"g;x\" => \"http://a/bb/ccc/g;x\",\n        \"g;x?y#s\" => \"http://a/bb/ccc/g;x?y#s\",\n        \"\" => \"http://a/bb/ccc/..\",\n        \".\" => \"http://a/bb/ccc/\",\n        \"./\" => \"http://a/bb/ccc/\",\n        \"..\" => \"http://a/bb/\",\n        \"../\" => \"http://a/bb/\",\n        \"../g\" => \"http://a/bb/g\",\n        \"../..\" => \"http://a/\",\n        \"../../\" => \"http://a/\",\n        \"../../g\" => \"http://a/g\",\n        \"../../../g\" => \"http://a/g\",\n        \"../../../../g\" => \"http://a/g\",\n        \"/./g\" => \"http://a/g\",\n        \"/../g\" => \"http://a/g\",\n        \"g.\" => \"http://a/bb/ccc/g.\",\n        \".g\" => \"http://a/bb/ccc/.g\",\n        \"g..\" => \"http://a/bb/ccc/g..\",\n        \"..g\" => \"http://a/bb/ccc/..g\",\n        \"./../g\" => \"http://a/bb/g\",\n        \"./g/.\" => \"http://a/bb/ccc/g/\",\n        \"g/./h\" => \"http://a/bb/ccc/g/h\",\n        \"g/../h\" => \"http://a/bb/ccc/h\",\n        \"g;x=1/./y\" => \"http://a/bb/ccc/g;x=1/y\",\n        \"g;x=1/../y\" => \"http://a/bb/ccc/y\",\n        \"g?y/./x\" => \"http://a/bb/ccc/g?y/./x\",\n        \"g?y/../x\" => \"http://a/bb/ccc/g?y/../x\",\n        \"g#s/./x\" => \"http://a/bb/ccc/g#s/./x\",\n        \"g#s/../x\" => \"http://a/bb/ccc/g#s/../x\",\n        \"http:g\" => \"http:g\"\n      }\n\n      for {rel, result} <- rel_and_result2 do\n        assert URI.merge(base2, rel) |> URI.to_string() == result\n      end\n\n      base3 = \"http://a/bb/ccc/../d;p?q\"\n\n      rel_and_result = %{\n        \"g:h\" => \"g:h\",\n        \"g\" => \"http://a/bb/g\",\n        \"./g\" => \"http://a/bb/g\",\n        \"g/\" => \"http://a/bb/g/\",\n        \"/g\" => \"http://a/g\",\n        \"//g\" => \"http://g\",\n        \"?y\" => \"http://a/bb/ccc/../d;p?y\",\n        \"g?y\" => \"http://a/bb/g?y\",\n        \"#s\" => \"http://a/bb/ccc/../d;p?q#s\",\n        \"g#s\" => \"http://a/bb/g#s\",\n        \"g?y#s\" => \"http://a/bb/g?y#s\",\n        \";x\" => \"http://a/bb/;x\",\n        \"g;x\" => \"http://a/bb/g;x\",\n        \"g;x?y#s\" => \"http://a/bb/g;x?y#s\",\n        \"\" => \"http://a/bb/ccc/../d;p?q\",\n        \".\" => \"http://a/bb/\",\n        \"./\" => \"http://a/bb/\",\n        \"..\" => \"http://a/\",\n        \"../\" => \"http://a/\",\n        \"../g\" => \"http://a/g\",\n        \"../..\" => \"http://a/\",\n        \"../../\" => \"http://a/\",\n        \"../../g\" => \"http://a/g\",\n        \"../../../g\" => \"http://a/g\",\n        \"../../../../g\" => \"http://a/g\",\n        \"/./g\" => \"http://a/g\",\n        \"/../g\" => \"http://a/g\",\n        \"g.\" => \"http://a/bb/g.\",\n        \".g\" => \"http://a/bb/.g\",\n        \"g..\" => \"http://a/bb/g..\",\n        \"..g\" => \"http://a/bb/..g\",\n        \"./../g\" => \"http://a/g\",\n        \"./g/.\" => \"http://a/bb/g/\",\n        \"g/./h\" => \"http://a/bb/g/h\",\n        \"g/../h\" => \"http://a/bb/h\",\n        \"g;x=1/./y\" => \"http://a/bb/g;x=1/y\",\n        \"g;x=1/../y\" => \"http://a/bb/y\",\n        \"g?y/./x\" => \"http://a/bb/g?y/./x\",\n        \"g?y/../x\" => \"http://a/bb/g?y/../x\",\n        \"g#s/./x\" => \"http://a/bb/g#s/./x\",\n        \"g#s/../x\" => \"http://a/bb/g#s/../x\",\n        \"http:g\" => \"http:g\"\n      }\n\n      for {rel, result} <- rel_and_result do\n        assert URI.merge(base3, rel) |> URI.to_string() == result\n      end\n    end\n  end\n\n  test \"append_query/2\" do\n    assert URI.append_query(URI.parse(\"http://example.com/?x=1\"), \"x=2\").query == \"x=1&x=2\"\n    assert URI.append_query(URI.parse(\"http://example.com/?x=1&\"), \"x=2\").query == \"x=1&x=2\"\n  end\n\n  describe \"append_path/2\" do\n    test \"with valid paths\" do\n      examples = [\n        {\"http://example.com\", \"/\", \"http://example.com/\"},\n        {\"http://example.com/\", \"/foo\", \"http://example.com/foo\"},\n        {\"http://example.com/foo\", \"/bar\", \"http://example.com/foo/bar\"},\n        {\"http://example.com/foo\", \"/bar/\", \"http://example.com/foo/bar/\"},\n        {\"http://example.com/foo\", \"/bar/baz\", \"http://example.com/foo/bar/baz\"},\n        {\"http://example.com/foo?var=1\", \"/bar/\", \"http://example.com/foo/bar/?var=1\"},\n        {\"https://example.com/page/\", \"/urn:example:page\",\n         \"https://example.com/page/urn:example:page\"}\n      ]\n\n      for {base_url, path, expected_result} <- examples do\n        result =\n          base_url\n          |> URI.parse()\n          |> URI.append_path(path)\n          |> URI.to_string()\n\n        assert result == expected_result, \"\"\"\n        Path did not append as expected\n\n          base_url: #{inspect(base_url)}\n          path: #{inspect(path)}\n\n          result:          #{inspect(result)}\n          expected_result: #{inspect(expected_result)}\n        \"\"\"\n      end\n    end\n\n    test \"errors on invalid paths\" do\n      base_uri = URI.parse(\"http://example.com\")\n\n      assert_raise ArgumentError,\n                   ~S|path must start with \"/\", got: \"foo\"|,\n                   fn ->\n                     URI.append_path(base_uri, \"foo\")\n                   end\n\n      assert_raise ArgumentError,\n                   ~S|path cannot start with \"//\", got: \"//foo\"|,\n                   fn ->\n                     URI.append_path(base_uri, \"//foo\")\n                   end\n    end\n  end\n\n  ## Deprecate API\n\n  describe \"authority\" do\n    test \"to_string\" do\n      assert URI.to_string(%URI{authority: \"foo@example.com:80\"}) ==\n               \"//foo@example.com:80\"\n\n      assert URI.to_string(%URI{userinfo: \"bar\", host: \"example.org\", port: 81}) ==\n               \"//bar@example.org:81\"\n\n      assert URI.to_string(%URI{\n               authority: \"foo@example.com:80\",\n               userinfo: \"bar\",\n               host: \"example.org\",\n               port: 81\n             }) ==\n               \"//bar@example.org:81\"\n    end\n  end\n\n  describe \"parse/1\" do\n    test \"returns the given URI if a %URI{} struct is given\" do\n      assert URI.parse(uri = %URI{scheme: \"http\", host: \"foo.com\"}) == uri\n    end\n\n    test \"works with HTTP scheme\" do\n      expected_uri = %URI{\n        scheme: \"http\",\n        host: \"foo.com\",\n        path: \"/path/to/something\",\n        query: \"foo=bar&bar=foo\",\n        fragment: \"fragment\",\n        port: 80,\n        authority: \"foo.com\",\n        userinfo: nil\n      }\n\n      assert URI.parse(\"http://foo.com/path/to/something?foo=bar&bar=foo#fragment\") ==\n               expected_uri\n    end\n\n    test \"works with HTTPS scheme\" do\n      expected_uri = %URI{\n        scheme: \"https\",\n        host: \"foo.com\",\n        authority: \"foo.com\",\n        query: nil,\n        fragment: nil,\n        port: 443,\n        path: nil,\n        userinfo: nil\n      }\n\n      assert URI.parse(\"https://foo.com\") == expected_uri\n    end\n\n    test \"works with \\\"file\\\" scheme\" do\n      expected_uri = %URI{\n        scheme: \"file\",\n        host: \"\",\n        path: \"/foo/bar/baz\",\n        userinfo: nil,\n        query: nil,\n        fragment: nil,\n        port: nil,\n        authority: \"\"\n      }\n\n      assert URI.parse(\"file:///foo/bar/baz\") == expected_uri\n    end\n\n    test \"works with FTP scheme\" do\n      expected_uri = %URI{\n        scheme: \"ftp\",\n        host: \"private.ftp-server.example.com\",\n        userinfo: \"user001:password\",\n        authority: \"user001:password@private.ftp-server.example.com\",\n        path: \"/my_directory/my_file.txt\",\n        query: nil,\n        fragment: nil,\n        port: 21\n      }\n\n      ftp = \"ftp://user001:password@private.ftp-server.example.com/my_directory/my_file.txt\"\n      assert URI.parse(ftp) == expected_uri\n    end\n\n    test \"works with SFTP scheme\" do\n      expected_uri = %URI{\n        scheme: \"sftp\",\n        host: \"private.ftp-server.example.com\",\n        userinfo: \"user001:password\",\n        authority: \"user001:password@private.ftp-server.example.com\",\n        path: \"/my_directory/my_file.txt\",\n        query: nil,\n        fragment: nil,\n        port: 22\n      }\n\n      sftp = \"sftp://user001:password@private.ftp-server.example.com/my_directory/my_file.txt\"\n      assert URI.parse(sftp) == expected_uri\n    end\n\n    test \"works with TFTP scheme\" do\n      expected_uri = %URI{\n        scheme: \"tftp\",\n        host: \"private.ftp-server.example.com\",\n        userinfo: \"user001:password\",\n        authority: \"user001:password@private.ftp-server.example.com\",\n        path: \"/my_directory/my_file.txt\",\n        query: nil,\n        fragment: nil,\n        port: 69\n      }\n\n      tftp = \"tftp://user001:password@private.ftp-server.example.com/my_directory/my_file.txt\"\n      assert URI.parse(tftp) == expected_uri\n    end\n\n    test \"works with LDAP scheme\" do\n      expected_uri = %URI{\n        scheme: \"ldap\",\n        host: \"\",\n        authority: \"\",\n        userinfo: nil,\n        path: \"/dc=example,dc=com\",\n        query: \"?sub?(givenName=John)\",\n        fragment: nil,\n        port: 389\n      }\n\n      assert URI.parse(\"ldap:///dc=example,dc=com??sub?(givenName=John)\") == expected_uri\n\n      expected_uri = %URI{\n        scheme: \"ldap\",\n        host: \"ldap.example.com\",\n        authority: \"ldap.example.com\",\n        userinfo: nil,\n        path: \"/cn=John%20Doe,dc=foo,dc=com\",\n        fragment: nil,\n        port: 389,\n        query: nil\n      }\n\n      assert URI.parse(\"ldap://ldap.example.com/cn=John%20Doe,dc=foo,dc=com\") == expected_uri\n    end\n\n    test \"works with WebSocket scheme\" do\n      expected_uri = %URI{\n        authority: \"ws.example.com\",\n        fragment: \"content\",\n        host: \"ws.example.com\",\n        path: \"/path/to\",\n        port: 80,\n        query: \"here\",\n        scheme: \"ws\",\n        userinfo: nil\n      }\n\n      assert URI.parse(\"ws://ws.example.com/path/to?here#content\") == expected_uri\n    end\n\n    test \"works with WebSocket Secure scheme\" do\n      expected_uri = %URI{\n        authority: \"ws.example.com\",\n        fragment: \"content\",\n        host: \"ws.example.com\",\n        path: \"/path/to\",\n        port: 443,\n        query: \"here\",\n        scheme: \"wss\",\n        userinfo: nil\n      }\n\n      assert URI.parse(\"wss://ws.example.com/path/to?here#content\") == expected_uri\n    end\n\n    test \"splits authority\" do\n      expected_uri = %URI{\n        scheme: \"http\",\n        host: \"foo.com\",\n        path: nil,\n        query: nil,\n        fragment: nil,\n        port: 4444,\n        authority: \"foo:bar@foo.com:4444\",\n        userinfo: \"foo:bar\"\n      }\n\n      assert URI.parse(\"http://foo:bar@foo.com:4444\") == expected_uri\n\n      expected_uri = %URI{\n        scheme: \"https\",\n        host: \"foo.com\",\n        path: nil,\n        query: nil,\n        fragment: nil,\n        port: 443,\n        authority: \"foo:bar@foo.com\",\n        userinfo: \"foo:bar\"\n      }\n\n      assert URI.parse(\"https://foo:bar@foo.com\") == expected_uri\n\n      expected_uri = %URI{\n        scheme: \"http\",\n        host: \"foo.com\",\n        path: nil,\n        query: nil,\n        fragment: nil,\n        port: 4444,\n        authority: \"foo.com:4444\",\n        userinfo: nil\n      }\n\n      assert URI.parse(\"http://foo.com:4444\") == expected_uri\n    end\n\n    test \"can parse bad URIs\" do\n      assert URI.parse(\"\")\n      assert URI.parse(\"https:??@?F?@#>F//23/\")\n\n      assert URI.parse(\":https\").path == \":https\"\n      assert URI.parse(\"https\").path == \"https\"\n      assert URI.parse(\"ht\\0tps://foo.com\").path == \"ht\\0tps://foo.com\"\n    end\n\n    test \"can parse IPv6 addresses\" do\n      addresses = [\n        # undefined\n        \"::\",\n        # loopback\n        \"::1\",\n        # unicast\n        \"1080::8:800:200C:417A\",\n        # multicast\n        \"FF01::101\",\n        # link-local\n        \"fe80::\",\n        # abbreviated\n        \"2607:f3f0:2:0:216:3cff:fef0:174a\",\n        # mixed hex case\n        \"2607:f3F0:2:0:216:3cFf:Fef0:174A\",\n        # complete\n        \"2051:0db8:2d5a:3521:8313:ffad:1242:8e2e\",\n        # embedded IPv4\n        \"::00:192.168.10.184\"\n      ]\n\n      Enum.each(addresses, fn addr ->\n        simple_uri = URI.parse(\"http://[#{addr}]/\")\n        assert simple_uri.authority == \"[#{addr}]\"\n        assert simple_uri.host == addr\n\n        userinfo_uri = URI.parse(\"http://user:pass@[#{addr}]/\")\n        assert userinfo_uri.authority == \"user:pass@[#{addr}]\"\n        assert userinfo_uri.host == addr\n        assert userinfo_uri.userinfo == \"user:pass\"\n\n        port_uri = URI.parse(\"http://[#{addr}]:2222/\")\n        assert port_uri.authority == \"[#{addr}]:2222\"\n        assert port_uri.host == addr\n        assert port_uri.port == 2222\n\n        userinfo_port_uri = URI.parse(\"http://user:pass@[#{addr}]:2222/\")\n        assert userinfo_port_uri.authority == \"user:pass@[#{addr}]:2222\"\n        assert userinfo_port_uri.host == addr\n        assert userinfo_port_uri.userinfo == \"user:pass\"\n        assert userinfo_port_uri.port == 2222\n      end)\n    end\n\n    test \"downcases the scheme\" do\n      assert URI.parse(\"hTtP://google.com\").scheme == \"http\"\n    end\n\n    test \"preserves empty fragments\" do\n      assert URI.parse(\"http://example.com#\").fragment == \"\"\n      assert URI.parse(\"http://example.com/#\").fragment == \"\"\n      assert URI.parse(\"http://example.com/test#\").fragment == \"\"\n    end\n\n    test \"preserves an empty query\" do\n      assert URI.parse(\"http://foo.com/?\").query == \"\"\n    end\n\n    test \"merges empty path\" do\n      base = URI.parse(\"http://example.com\")\n      assert URI.merge(base, \"/foo\") |> to_string() == \"http://example.com/foo\"\n      assert URI.merge(base, \"foo\") |> to_string() == \"http://example.com/foo\"\n    end\n\n    test \"merges when base path is empty string\" do\n      base = %URI{scheme: \"http\", host: \"example.com\", path: \"\"}\n      assert URI.merge(base, \"foo\") |> to_string() == \"http://example.com/foo\"\n      assert URI.merge(base, \"/bar\") |> to_string() == \"http://example.com/bar\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/elixir/version_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule VersionTest do\n  use ExUnit.Case, async: true\n\n  doctest Version\n\n  alias Version.Parser\n\n  test \"compare/2 with valid versions\" do\n    assert Version.compare(\"1.0.1\", \"1.0.0\") == :gt\n    assert Version.compare(\"1.1.0\", \"1.0.1\") == :gt\n    assert Version.compare(\"2.1.1\", \"1.2.2\") == :gt\n    assert Version.compare(\"1.0.0\", \"1.0.0-dev\") == :gt\n    assert Version.compare(\"1.2.3-dev\", \"0.1.2\") == :gt\n    assert Version.compare(\"1.0.0-a.b\", \"1.0.0-a\") == :gt\n    assert Version.compare(\"1.0.0-b\", \"1.0.0-a.b\") == :gt\n    assert Version.compare(\"1.0.0-a\", \"1.0.0-0\") == :gt\n    assert Version.compare(\"1.0.0-a.b\", \"1.0.0-a.a\") == :gt\n\n    assert Version.compare(\"1.0.0\", \"1.0.1\") == :lt\n    assert Version.compare(\"1.0.1\", \"1.1.0\") == :lt\n    assert Version.compare(\"1.2.2\", \"2.1.1\") == :lt\n    assert Version.compare(\"1.0.0-dev\", \"1.0.0\") == :lt\n    assert Version.compare(\"0.1.2\", \"1.2.3-dev\") == :lt\n    assert Version.compare(\"1.0.0-a\", \"1.0.0-a.b\") == :lt\n    assert Version.compare(\"1.0.0-a.b\", \"1.0.0-b\") == :lt\n    assert Version.compare(\"1.0.0-0\", \"1.0.0-a\") == :lt\n    assert Version.compare(\"1.0.0-a.a\", \"1.0.0-a.b\") == :lt\n\n    assert Version.compare(\"1.0.0\", \"1.0.0\") == :eq\n    assert Version.compare(\"1.0.0-dev\", \"1.0.0-dev\") == :eq\n    assert Version.compare(\"1.0.0-a\", \"1.0.0-a\") == :eq\n    assert Version.compare(\"1.5.0-rc.0\", \"1.5.0-rc0\") == :lt\n  end\n\n  test \"compare/2 with invalid versions\" do\n    assert_raise Version.InvalidVersionError, fn ->\n      Version.compare(\"1.0\", \"1.0.0\")\n    end\n\n    assert_raise Version.InvalidVersionError, fn ->\n      Version.compare(\"1.0.0-dev\", \"1.0\")\n    end\n\n    assert_raise Version.InvalidVersionError, fn ->\n      Version.compare(\"foo\", \"1.0.0-a\")\n    end\n  end\n\n  test \"lexes specifications properly\" do\n    assert Parser.lexer(\"== > >= < <= ~>\") |> Enum.reverse() == [:==, :>, :>=, :<, :<=, :~>]\n    assert Parser.lexer(\"2.3.0\") |> Enum.reverse() == [:==, \"2.3.0\"]\n    assert Parser.lexer(\">>=\") |> Enum.reverse() == [:>, :>=]\n    assert Parser.lexer(\">2.4.0\") |> Enum.reverse() == [:>, \"2.4.0\"]\n    assert Parser.lexer(\"> 2.4.0\") |> Enum.reverse() == [:>, \"2.4.0\"]\n    assert Parser.lexer(\"    >     2.4.0\") |> Enum.reverse() == [:>, \"2.4.0\"]\n    assert Parser.lexer(\" or 2.1.0\") |> Enum.reverse() == [:or, :==, \"2.1.0\"]\n    assert Parser.lexer(\" and 2.1.0\") |> Enum.reverse() == [:and, :==, \"2.1.0\"]\n\n    assert Parser.lexer(\">= 2.0.0 and < 2.1.0\") |> Enum.reverse() ==\n             [:>=, \"2.0.0\", :and, :<, \"2.1.0\"]\n\n    assert Parser.lexer(\">= 2.0.0 or < 2.1.0\") |> Enum.reverse() ==\n             [:>=, \"2.0.0\", :or, :<, \"2.1.0\"]\n  end\n\n  test \"parse/1\" do\n    assert {:ok, %Version{major: 1, minor: 2, patch: 3}} = Version.parse(\"1.2.3\")\n\n    assert {:ok, %Version{major: 1, minor: 4, patch: 5, build: \"ignore\"}} =\n             Version.parse(\"1.4.5+ignore\")\n\n    assert {:ok, %Version{major: 0, minor: 0, patch: 1, build: \"sha.0702245\"}} =\n             Version.parse(\"0.0.1+sha.0702245\")\n\n    assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: [\"6-g3318bd5\"]}} =\n             Version.parse(\"1.4.5-6-g3318bd5\")\n\n    assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: [6, 7, \"eight\"]}} =\n             Version.parse(\"1.4.5-6.7.eight\")\n\n    assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: [\"6-g3318bd5\"]}} =\n             Version.parse(\"1.4.5-6-g3318bd5+ignore\")\n\n    assert Version.parse(\"foobar\") == :error\n    assert Version.parse(\"2\") == :error\n    assert Version.parse(\"2.\") == :error\n    assert Version.parse(\"2.3\") == :error\n    assert Version.parse(\"2.3.\") == :error\n    assert Version.parse(\"2.3.0-\") == :error\n    assert Version.parse(\"2.3.0+\") == :error\n    assert Version.parse(\"2.3.0.\") == :error\n    assert Version.parse(\"2.3.0.4\") == :error\n    assert Version.parse(\"2.3.-rc.1\") == :error\n    assert Version.parse(\"2.3.+rc.1\") == :error\n    assert Version.parse(\"2.3.0-01\") == :error\n    assert Version.parse(\"2.3.00-1\") == :error\n    assert Version.parse(\"2.3.00\") == :error\n    assert Version.parse(\"2.03.0\") == :error\n    assert Version.parse(\"02.3.0\") == :error\n    assert Version.parse(\"0. 0.0\") == :error\n    assert Version.parse(\"0.1.0-&&pre\") == :error\n  end\n\n  test \"to_string/1\" do\n    assert Version.parse!(\"1.0.0\") |> Version.to_string() == \"1.0.0\"\n    assert Version.parse!(\"1.0.0-dev\") |> Version.to_string() == \"1.0.0-dev\"\n    assert Version.parse!(\"1.0.0+lol\") |> Version.to_string() == \"1.0.0+lol\"\n    assert Version.parse!(\"1.0.0-dev+lol\") |> Version.to_string() == \"1.0.0-dev+lol\"\n    assert Version.parse!(\"1.0.0-dev+lol.4\") |> Version.to_string() == \"1.0.0-dev+lol.4\"\n    assert Version.parse!(\"1.0.0-0\") |> Version.to_string() == \"1.0.0-0\"\n    assert Version.parse!(\"1.0.0-rc.0\") |> Version.to_string() == \"1.0.0-rc.0\"\n    assert %Version{major: 1, minor: 0, patch: 0} |> Version.to_string() == \"1.0.0\"\n  end\n\n  test \"to_string/1 via protocol\" do\n    assert Version.parse!(\"1.0.0\") |> to_string() == \"1.0.0\"\n  end\n\n  test \"inspect/1\" do\n    assert Version.parse!(\"1.0.0\") |> inspect() == \"%Version{major: 1, minor: 0, patch: 0}\"\n  end\n\n  test \"match?/2 with invalid versions\" do\n    assert_raise Version.InvalidVersionError, fn ->\n      Version.match?(\"foo\", \"2.3.0\")\n    end\n\n    assert_raise Version.InvalidVersionError, fn ->\n      Version.match?(\"2.3\", \"2.3.0\")\n    end\n\n    assert_raise Version.InvalidRequirementError, fn ->\n      Version.match?(\"2.3.0\", \"foo\")\n    end\n\n    assert_raise Version.InvalidRequirementError, fn ->\n      Version.match?(\"2.3.0\", \"2.3\")\n    end\n  end\n\n  test \"==\" do\n    assert Version.match?(\"2.3.0\", \"2.3.0\")\n    refute Version.match?(\"2.4.0\", \"2.3.0\")\n\n    assert Version.match?(\"2.3.0\", \"== 2.3.0\")\n    refute Version.match?(\"2.4.0\", \"== 2.3.0\")\n\n    assert Version.match?(\"1.0.0\", \"1.0.0\")\n    assert Version.match?(\"1.0.0\", \"1.0.0\")\n\n    assert Version.match?(\"1.2.3-alpha\", \"1.2.3-alpha\")\n\n    assert Version.match?(\"0.9.3\", \"== 0.9.3+dev\")\n\n    {:ok, vsn} = Version.parse(\"2.3.0\")\n    assert Version.match?(vsn, \"2.3.0\")\n  end\n\n  test \"!=\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      assert Version.match?(\"2.4.0\", \"!2.3.0\")\n      refute Version.match?(\"2.3.0\", \"!2.3.0\")\n\n      assert Version.match?(\"2.4.0\", \"!= 2.3.0\")\n      refute Version.match?(\"2.3.0\", \"!= 2.3.0\")\n    end)\n  end\n\n  test \">\" do\n    assert Version.match?(\"2.4.0\", \"> 2.3.0\")\n    refute Version.match?(\"2.2.0\", \"> 2.3.0\")\n    refute Version.match?(\"2.3.0\", \"> 2.3.0\")\n\n    assert Version.match?(\"1.2.3\", \"> 1.2.3-alpha\")\n    assert Version.match?(\"1.2.3-alpha.1\", \"> 1.2.3-alpha\")\n    assert Version.match?(\"1.2.3-alpha.beta.sigma\", \"> 1.2.3-alpha.beta\")\n    refute Version.match?(\"1.2.3-alpha.10\", \"< 1.2.3-alpha.1\")\n    refute Version.match?(\"0.10.2-dev\", \"> 0.10.2\")\n\n    refute Version.match?(\"1.5.0-rc.0\", \"> 1.5.0-rc0\")\n    assert Version.match?(\"1.5.0-rc0\", \"> 1.5.0-rc.0\")\n  end\n\n  test \">=\" do\n    assert Version.match?(\"2.4.0\", \">= 2.3.0\")\n    refute Version.match?(\"2.2.0\", \">= 2.3.0\")\n    assert Version.match?(\"2.3.0\", \">= 2.3.0\")\n\n    assert Version.match?(\"2.0.0\", \">= 1.0.0\")\n    assert Version.match?(\"1.0.0\", \">= 1.0.0\")\n\n    refute Version.match?(\"1.5.0-rc.0\", \">= 1.5.0-rc0\")\n    assert Version.match?(\"1.5.0-rc0\", \">= 1.5.0-rc.0\")\n  end\n\n  test \"<\" do\n    assert Version.match?(\"2.2.0\", \"< 2.3.0\")\n    refute Version.match?(\"2.4.0\", \"< 2.3.0\")\n    refute Version.match?(\"2.3.0\", \"< 2.3.0\")\n\n    assert Version.match?(\"0.10.2-dev\", \"< 0.10.2\")\n\n    refute Version.match?(\"1.0.0\", \"< 1.0.0-dev\")\n    refute Version.match?(\"1.2.3-dev\", \"< 0.1.2\")\n  end\n\n  test \"<=\" do\n    assert Version.match?(\"2.2.0\", \"<= 2.3.0\")\n    refute Version.match?(\"2.4.0\", \"<= 2.3.0\")\n    assert Version.match?(\"2.3.0\", \"<= 2.3.0\")\n  end\n\n  describe \"~>\" do\n    test \"regular cases\" do\n      assert Version.match?(\"3.0.0\", \"~> 3.0\")\n      assert Version.match?(\"3.2.0\", \"~> 3.0\")\n      refute Version.match?(\"4.0.0\", \"~> 3.0\")\n      refute Version.match?(\"4.4.0\", \"~> 3.0\")\n\n      assert Version.match?(\"3.0.2\", \"~> 3.0.0\")\n      assert Version.match?(\"3.0.0\", \"~> 3.0.0\")\n      refute Version.match?(\"3.1.0\", \"~> 3.0.0\")\n      refute Version.match?(\"3.4.0\", \"~> 3.0.0\")\n\n      assert Version.match?(\"3.6.0\", \"~> 3.5\")\n      assert Version.match?(\"3.5.0\", \"~> 3.5\")\n      refute Version.match?(\"4.0.0\", \"~> 3.5\")\n      refute Version.match?(\"5.0.0\", \"~> 3.5\")\n\n      assert Version.match?(\"3.5.2\", \"~> 3.5.0\")\n      assert Version.match?(\"3.5.4\", \"~> 3.5.0\")\n      refute Version.match?(\"3.6.0\", \"~> 3.5.0\")\n      refute Version.match?(\"3.6.3\", \"~> 3.5.0\")\n\n      assert Version.match?(\"0.9.3\", \"~> 0.9.3-dev\")\n      refute Version.match?(\"0.10.0\", \"~> 0.9.3-dev\")\n\n      refute Version.match?(\"0.3.0-dev\", \"~> 0.2.0\")\n\n      assert Version.match?(\"1.11.0-dev\", \"~> 1.11-dev\")\n      assert Version.match?(\"1.11.0\", \"~> 1.11-dev\")\n      assert Version.match?(\"1.12.0\", \"~> 1.11-dev\")\n      refute Version.match?(\"1.10.0\", \"~> 1.11-dev\")\n      refute Version.match?(\"2.0.0\", \"~> 1.11-dev\")\n\n      refute Version.match?(\"1.5.0-rc.0\", \"~> 1.5.0-rc0\")\n      assert Version.match?(\"1.5.0-rc0\", \"~> 1.5.0-rc.0\")\n\n      assert_raise Version.InvalidRequirementError, fn ->\n        Version.match?(\"3.0.0\", \"~> 3\")\n      end\n    end\n\n    test \"~> will never include pre-release versions of its upper bound\" do\n      refute Version.match?(\"2.2.0-dev\", \"~> 2.1.0\")\n      refute Version.match?(\"2.2.0-dev\", \"~> 2.1.0\", allow_pre: false)\n      refute Version.match?(\"2.2.0-dev\", \"~> 2.1.0-dev\")\n      refute Version.match?(\"2.2.0-dev\", \"~> 2.1.0-dev\", allow_pre: false)\n    end\n  end\n\n  test \"allow_pre\" do\n    assert Version.match?(\"1.1.0\", \"~> 1.0\", allow_pre: true)\n    assert Version.match?(\"1.1.0\", \"~> 1.0\", allow_pre: false)\n    assert Version.match?(\"1.1.0-beta\", \"~> 1.0\", allow_pre: true)\n    refute Version.match?(\"1.1.0-beta\", \"~> 1.0\", allow_pre: false)\n    assert Version.match?(\"1.0.1-beta\", \"~> 1.0.0-beta\", allow_pre: false)\n\n    assert Version.match?(\"1.1.0\", \">= 1.0.0\", allow_pre: true)\n    assert Version.match?(\"1.1.0\", \">= 1.0.0\", allow_pre: false)\n    assert Version.match?(\"1.1.0-beta\", \">= 1.0.0\", allow_pre: true)\n    refute Version.match?(\"1.1.0-beta\", \">= 1.0.0\", allow_pre: false)\n    assert Version.match?(\"1.1.0-beta\", \">= 1.0.0-beta\", allow_pre: false)\n  end\n\n  test \"and\" do\n    assert Version.match?(\"0.9.3\", \"> 0.9.0 and < 0.10.0\")\n    refute Version.match?(\"0.10.2\", \"> 0.9.0 and < 0.10.0\")\n  end\n\n  test \"or\" do\n    assert Version.match?(\"0.9.1\", \"0.9.1 or 0.9.3 or 0.9.5\")\n    assert Version.match?(\"0.9.3\", \"0.9.1 or 0.9.3 or 0.9.5\")\n    assert Version.match?(\"0.9.5\", \"0.9.1 or 0.9.3 or 0.9.5\")\n    refute Version.match?(\"0.9.6\", \"0.9.1 or 0.9.3 or 0.9.5\")\n  end\n\n  test \"and/or\" do\n    req = \"< 0.2.0 and >= 0.1.0 or >= 0.7.0\"\n    assert Version.match?(\"0.1.0\", req)\n    assert Version.match?(\"0.1.5\", req)\n    refute Version.match?(\"0.3.0\", req)\n    refute Version.match?(\"0.6.0\", req)\n    assert Version.match?(\"0.7.0\", req)\n    assert Version.match?(\"0.7.5\", req)\n\n    req = \">= 0.7.0 or < 0.2.0 and >= 0.1.0\"\n    assert Version.match?(\"0.1.0\", req)\n    assert Version.match?(\"0.1.5\", req)\n    refute Version.match?(\"0.3.0\", req)\n    refute Version.match?(\"0.6.0\", req)\n    assert Version.match?(\"0.7.0\", req)\n    assert Version.match?(\"0.7.5\", req)\n\n    req = \"< 0.2.0 and >= 0.1.0 or < 0.8.0 and >= 0.7.0\"\n    assert Version.match?(\"0.1.0\", req)\n    assert Version.match?(\"0.1.5\", req)\n    refute Version.match?(\"0.3.0\", req)\n    refute Version.match?(\"0.6.0\", req)\n    assert Version.match?(\"0.7.0\", req)\n    assert Version.match?(\"0.7.5\", req)\n\n    req = \"== 0.2.0 or >= 0.3.0 and < 0.4.0 or == 0.7.0\"\n    assert Version.match?(\"0.2.0\", req)\n    refute Version.match?(\"0.2.5\", req)\n    assert Version.match?(\"0.3.0\", req)\n    assert Version.match?(\"0.3.5\", req)\n    refute Version.match?(\"0.4.0\", req)\n    assert Version.match?(\"0.7.0\", req)\n  end\n\n  describe \"requirement\" do\n    test \"compile_requirement/1\" do\n      {:ok, req} = Version.parse_requirement(\"1.2.3\")\n      assert req == Version.compile_requirement(req)\n\n      assert Version.match?(\"1.2.3\", req)\n      refute Version.match?(\"1.2.4\", req)\n\n      assert Version.parse_requirement(\"1 . 2 . 3\") == :error\n      assert Version.parse_requirement(\"== >= 1.2.3\") == :error\n      assert Version.parse_requirement(\"1.2.3 and or 4.5.6\") == :error\n      assert Version.parse_requirement(\">= 1\") == :error\n      assert Version.parse_requirement(\"1.2.3 >=\") == :error\n    end\n\n    test \"inspect/1\" do\n      assert Version.parse_requirement!(\"1.0.0\") |> inspect() ==\n               \"Version.parse_requirement!(\\\"1.0.0\\\")\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/test/erlang/atom_test.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(atom_test).\n-export([kv/1]).\n-include_lib(\"eunit/include/eunit.hrl\").\n\neval(Content) ->\n  Quoted = elixir:'string_to_quoted!'(Content, 1, 1, <<\"nofile\">>, []),\n  {Value, Binding, _} = elixir:eval_forms(Quoted, [], elixir:env_for_eval([])),\n  {Value, Binding}.\n\nkv([{Key, nil}]) -> Key.\n\natom_with_punctuation_test() ->\n  {foo@bar, []} = eval(\":foo@bar\"),\n  {'a?', []} = eval(\":a?\"),\n  {'a!', []} = eval(\":a!\"),\n  {'||', []} = eval(\":||\"),\n  {'...', []} = eval(\":...\").\n\natom_quoted_call_test() ->\n  {3, []} = eval(\"Kernel.\\\"+\\\"(1, 2)\").\n\nkv_with_quotes_test() ->\n  {'foo bar', []} = eval(\":atom_test.kv(\\\"foo bar\\\": nil)\").\n\nkv_with_interpolation_test() ->\n  {'foo', []} = eval(\":atom_test.kv(\\\"#{\\\"foo\\\"}\\\": nil)\"),\n  {'foo', []} = eval(\":atom_test.kv(\\\"#{\\\"fo\\\"}o\\\": nil)\"),\n  {'foo', _} = eval(\"a = \\\"f\\\"; :atom_test.kv(\\\"#{a}#{\\\"o\\\"}o\\\": nil)\").\n\nquoted_atom_test() ->\n  {'+', []} = eval(\":\\\"+\\\"\"),\n  {'foo bar', []} = eval(\":\\\"foo bar\\\"\").\n\natom_with_interpolation_test() ->\n  {foo, []} = eval(\":\\\"f#{\\\"o\\\"}o\\\"\"),\n  {foo, _}  = eval(\"a=\\\"foo\\\"; :\\\"#{a}\\\"\"),\n  {foo, _}  = eval(\"a=\\\"oo\\\"; :\\\"f#{a}\\\"\"),\n  {foo, _}  = eval(\"a=\\\"fo\\\"; :\\\"#{a}o\\\"\"),\n  {fof, _}  = eval(\"a=\\\"f\\\"; :\\\"#{a}o#{a}\\\"\").\n\nquoted_atom_chars_are_escaped_test() ->\n  {'\"', []} = eval(\":\\\"\\\\\\\"\\\"\").\n"
  },
  {
    "path": "lib/elixir/test/erlang/control_test.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(control_test).\n-include_lib(\"eunit/include/eunit.hrl\").\n\nto_erl(String) ->\n  Forms = elixir:'string_to_quoted!'(String, 1, 1, <<\"nofile\">>, []),\n  {Expr, _, _, _} = elixir:quoted_to_erl(Forms, elixir:env_for_eval([])),\n  Expr.\n\ncond_line_test() ->\n  {'case', 1, _,\n    [{clause, 2, _, _, _},\n     {clause, 3, _, _, _}]\n  } = to_erl(\"cond do\\n  1 -> :ok\\n  2 -> :ok\\nend\").\n\nfloat_match_test() ->\n  {'case', _, _,\n    [{clause, _, [{op, _, '+', {float, _, +0.0}}], [], [{atom, _, pos}]},\n     {clause, _, [{op, _, '-', {float, _, +0.0}}], [], [{atom, _, neg}]}]\n  } = to_erl(\"case X do\\n  +0.0 -> :pos\\n  -0.0 -> :neg\\nend\").\n\n% Optimized\n\noptimized_if_test() ->\n  {'case', _, _,\n    [{clause, _, [{atom, _, false}], [], [{atom, _, 'else'}]},\n     {clause, _, [{atom, _, true}], [], [{atom, _, do}]}]\n  } = to_erl(\"if is_list([]), do: :do, else: :else\").\n\noptimized_andand_test() ->\n  {'case', _, _,\n    [{clause, _,\n      [{var, _, Var}],\n      [[{op, _, 'orelse', _, _}]],\n      [{var, _, Var}]},\n    {clause, _, [{var, _, '_'}], [], [{atom, 1, done}]}]\n  } = to_erl(\"is_list([]) && :done\").\n\noptimized_oror_test() ->\n  {'case', _, _,\n    [{clause, 1,\n      [{var, 1, _}],\n      [[{op, _, 'orelse', _, _}]],\n      [{atom, 1, done}]},\n    {clause, 1, [{var, 1, Var}], [], [{var, 1, Var}]}]\n  } = to_erl(\"is_list([]) || :done\").\n\noptimized_and_test() ->\n  {'case',_, _,\n   [{clause, _, [{atom, _, false}], [], [{atom, _, false}]},\n    {clause, _, [{atom, _, true}], [], [{atom, _, done}]}]\n  } = to_erl(\"is_list([]) and :done\").\n\noptimized_or_test() ->\n  {'case', _, _,\n    [{clause, _, [{atom, _, false}], [], [{atom, _, done}]},\n     {clause, _, [{atom, _, true}], [], [{atom, _, true}]}]\n  } = to_erl(\"is_list([]) or :done\").\n\nno_after_in_try_test() ->\n  {'try', _, [_], [], [_], []} = to_erl(\"try do :foo.bar() catch _ -> :ok end\").\n\noptimized_inspect_interpolation_test() ->\n    {bin, _,\n     [{bin_element, _,\n       {call, _, {remote, _,{atom, _, 'Elixir.Kernel'}, {atom, _, inspect}}, [_]},\n       default, [binary]}]} = to_erl(\"\\\"#{inspect(1)}\\\"\").\n\noptimized_map_put_test() ->\n  {map, _,\n    [{map_field_assoc, _, {atom, _, a}, {integer, _, 1}},\n     {map_field_assoc, _, {atom, _, b}, {integer, _, 2}}]\n  } = to_erl(\"Map.put(%{a: 1}, :b, 2)\").\n\noptimized_map_put_variable_test() ->\n  {block, _,\n    [_,\n     {map, _, {var, _, _},\n       [{map_field_assoc, _, {atom, _, a}, {integer, _, 1}}]\n     }]\n  } = to_erl(\"x = %{}; Map.put(x, :a, 1)\").\n\noptimized_nested_map_put_variable_test() ->\n  {block, _,\n    [_,\n     {map, _, {var, _, _},\n       [{map_field_assoc, _, {atom, _, a}, {integer, _, 1}},\n        {map_field_assoc, _, {atom, _, b}, {integer, _, 2}}]\n     }]\n  } = to_erl(\"x = %{}; Map.put(Map.put(x, :a, 1), :b, 2)\").\n\noptimized_map_merge_test() ->\n  {map, _,\n    [{map_field_assoc, _, {atom, _, a}, {integer, _, 1}},\n     {map_field_assoc, _, {atom, _, b}, {integer, _, 2}},\n     {map_field_assoc, _, {atom, _, c}, {integer, _, 3}}]\n  } = to_erl(\"Map.merge(%{a: 1, b: 2}, %{c: 3})\").\n\noptimized_map_merge_variable_test() ->\n  {block, _,\n    [_,\n     {map, _, {var, _, _},\n       [{map_field_assoc, _, {atom, _, a}, {integer, _, 1}}]\n     }]\n  } = to_erl(\"x = %{}; Map.merge(x, %{a: 1})\").\n\noptimized_map_update_and_merge_test() ->\n  {block, _,\n    [_,\n     {map, _, {var, _, _},\n       [{map_field_exact, _, {atom, _, a}, {integer, _, 2}},\n        {map_field_assoc, _, {atom, _, b}, {integer, _, 3}}]\n     }]\n  } = to_erl(\"x = %{a: 1}; Map.merge(%{x | a: 2}, %{b: 3})\"),\n  {block, _,\n    [_,\n     {call, _, {remote, _, {atom, _, maps}, {atom, _, merge}},\n       [{map, _,\n          [{map_field_assoc, _, {atom, _, a}, {integer, _, 2}}]},\n        {map, _, {var, _, _},\n          [{map_field_exact, _, {atom, _, b}, {integer, _, 3}}]}]\n     }]\n  } = to_erl(\"x = %{a: 1}; Map.merge(%{a: 2}, %{x | b: 3})\").\n\noptimized_nested_map_merge_variable_test() ->\n  {block, _,\n    [_,\n     {map, _, {var, _, _},\n       [{map_field_assoc, _, {atom, _, a}, {integer, _, 1}},\n        {map_field_assoc, _, {atom, _, b}, {integer, _, 2}}]\n     }]\n  } = to_erl(\"x = %{}; Map.merge(Map.merge(x, %{a: 1}), %{b: 2})\").\n\noptimized_map_set_new_test() ->\n  {map, _,\n    [\n      {map_field_assoc, _, {atom, _, '__struct__'}, {atom, _, 'Elixir.MapSet'}},\n      {map_field_assoc, _,\n        {atom, _, map},\n        {map, _, [\n          {map_field_assoc, _, {integer, _, 1}, {nil, _}},\n          {map_field_assoc, _, {integer, _, 2}, {nil, _}},\n          {map_field_assoc, _, {integer, _, 3}, {nil, _}}\n        ]}\n      }\n    ]\n  } = to_erl(\"MapSet.new([1, 2, 3])\").\n\nnot_optimized_map_set_new_with_range_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.MapSet'}, {atom, _, new}}, [\n      {map, _, [\n        {map_field_assoc, _, {atom, _, '__struct__'}, {atom, _, 'Elixir.Range'}},\n        {map_field_assoc, _, {atom, _, first}, {integer, _, 1}},\n        {map_field_assoc, _, {atom, _, last}, {integer, _, 3}},\n        {map_field_assoc, _, {atom, _, step}, {integer, _, 1}}\n      ]}\n    ]\n  } = to_erl(\"MapSet.new(1..3)\").\n\nmap_set_new_with_failing_args_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.MapSet'}, {atom, _, new}}, [\n      {atom, _, not_an_enumerable}\n    ]\n  } = to_erl(\"MapSet.new(:not_an_enumerable)\").\n\noptimized_date_shift_duration_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.Date'}, {atom, _, shift}}, [\n      {atom, _, non_important},\n      {map, _, [\n        {map_field_assoc, _, {atom, _, '__struct__'}, {atom, _, 'Elixir.Duration'}},\n        {map_field_assoc, _, {atom, _, day}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, hour}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, microsecond}, {tuple, _, [{integer, _, 0}, {integer, _, 0}]}},\n        {map_field_assoc, _, {atom, _, minute}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, month}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, second}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, week}, {integer, _, 1}},\n        {map_field_assoc, _, {atom, _, year}, {integer, _, 0}}\n      ]}\n    ]\n  } = to_erl(\"Date.shift(:non_important, week: 1)\").\n\nnot_optimized_date_shift_duration_unsupported_unit_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.Date'}, {atom, _, shift}}, [\n      {atom, _, non_important},\n      {cons, _, {tuple, _, [{atom, _, hour}, {integer, _, 1}]}, {nil, _}}\n    ]\n  } = to_erl(\"Date.shift(:non_important, hour: 1)\").\n\noptimized_time_shift_duration_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.Time'}, {atom, _, shift}}, [\n      {atom, _, non_important},\n      {map, _, [\n        {map_field_assoc, _, {atom, _, '__struct__'}, {atom, _, 'Elixir.Duration'}},\n        {map_field_assoc, _, {atom, _, day}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, hour}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, microsecond}, {tuple, _, [{integer, _, 0}, {integer, _, 0}]}},\n        {map_field_assoc, _, {atom, _, minute}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, month}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, second}, {integer, _, 2}},\n        {map_field_assoc, _, {atom, _, week}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, year}, {integer, _, 0}}\n      ]}\n    ]\n  } = to_erl(\"Time.shift(:non_important, second: 2)\").\n\nnot_optimized_time_shift_duration_unsupported_unit_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.Time'}, {atom, _, shift}}, [\n      {atom, _, non_important},\n      {cons, _, {tuple, _, [{atom, _, day}, {integer, _, 2}]}, {nil, _}}\n    ]\n  } = to_erl(\"Time.shift(:non_important, day: 2)\").\n\noptimized_date_time_shift_duration_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.DateTime'}, {atom, _, shift}}, [\n      {atom, _, non_important},\n      {map, _, [\n        {map_field_assoc, _, {atom, _, '__struct__'}, {atom, _, 'Elixir.Duration'}},\n        {map_field_assoc, _, {atom, _, day}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, hour}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, microsecond}, {tuple, _, [{integer, _, 0}, {integer, _, 0}]}},\n        {map_field_assoc, _, {atom, _, minute}, {integer, _, 3}},\n        {map_field_assoc, _, {atom, _, month}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, second}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, week}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, year}, {integer, _, 0}}\n      ]}\n    ]\n  } = to_erl(\"DateTime.shift(:non_important, minute: 3)\").\n\nnon_optimized_date_time_shift_duration_unknown_unit_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.DateTime'}, {atom, _, shift}}, [\n      {atom, _, non_important},\n      {cons, _, {tuple, _, [{atom, _, unknown}, {integer, _, 3}]}, {nil, _}}\n    ]\n  } = to_erl(\"DateTime.shift(:non_important, unknown: 3)\").\n\noptimized_naive_date_time_shift_duration_test() ->\n  {call, _,\n    {remote, _, {atom, _, 'Elixir.NaiveDateTime'}, {atom, _, shift}}, [\n      {atom, _, non_important},\n      {map, _, [\n        {map_field_assoc, _, {atom, _, '__struct__'}, {atom, _, 'Elixir.Duration'}},\n        {map_field_assoc, _, {atom, _, day}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, hour}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, microsecond}, {tuple, _, [{integer, _, 0}, {integer, _, 0}]}},\n        {map_field_assoc, _, {atom, _, minute}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, month}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, second}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, week}, {integer, _, 0}},\n        {map_field_assoc, _, {atom, _, year}, {integer, _, 4}}\n      ]}\n    ]\n  } = to_erl(\"NaiveDateTime.shift(:non_important, year: 4)\")."
  },
  {
    "path": "lib/elixir/test/erlang/function_test.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(function_test).\n-include_lib(\"eunit/include/eunit.hrl\").\n\neval(Content) ->\n  Quoted = elixir:'string_to_quoted!'(Content, 1, 1, <<\"nofile\">>, []),\n  {Value, Binding, _} = elixir:eval_forms(Quoted, [], elixir:env_for_eval([])),\n  {Value, lists:sort(Binding)}.\n\nfunction_arg_do_end_test() ->\n  {3, _} = eval(\"if true do\\n1 + 2\\nend\"),\n  {nil, _} = eval(\"if true do end\").\n\nfunction_stab_end_test() ->\n  {_, [{a, Fun3}]} = eval(\"a = fn -> 1 + 2 end\"),\n  3 = Fun3().\n\nfunction_stab_newlines_test() ->\n  {_, [{a, Fun3}]} = eval(\"a = fn\\n->\\n1 + 2\\nend\"),\n  3 = Fun3().\n\nfunction_stab_many_test() ->\n  {_, [{a, Fun}]} = eval(\"a = fn\\n{:foo, x} -> x\\n{:bar, x} -> x\\nend\"),\n  1 = Fun({foo, 1}),\n  2 = Fun({bar, 2}).\n\nfunction_stab_inline_test() ->\n  {_, [{a, Fun}]} = eval(\"a = fn {:foo, x} -> x; {:bar, x} -> x end\"),\n  1 = Fun({foo, 1}),\n  2 = Fun({bar, 2}).\n\nfunction_with_args_test() ->\n  {Fun, _} = eval(\"fn(a, b) -> a + b end\"),\n  3 = Fun(1, 2).\n\nfunction_with_kv_args_test() ->\n  {Fun, _} = eval(\"fn(a, [other: b, another: c]) -> a + b + c end\"),\n  6 = Fun(1, [{other, 2}, {another, 3}]).\n\nfunction_as_closure_test() ->\n  {_, [{a, Res1} | _]} = eval(\"b = 1; a = fn -> b + 2 end\"),\n  3 = Res1().\n\nfunction_apply_test() ->\n  {3, _} = eval(\"a = fn -> 3 end; apply a, []\").\n\nfunction_apply_with_args_test() ->\n  {3, _} = eval(\"a = fn b -> b + 2 end; apply a, [1]\").\n\nfunction_apply_and_clojure_test() ->\n  {3, _} = eval(\"b = 1; a = fn -> b + 2 end; apply a, []\").\n\nfunction_parens_test() ->\n  {0, _} = eval(\"(fn() -> 0 end).()\"),\n  {1, _} = eval(\"(fn(1) -> 1 end).(1)\"),\n  {3, _} = eval(\"(fn(1, 2) -> 3 end).(1, 2)\"),\n\n  {0, _} = eval(\"(fn() -> 0 end).()\"),\n  {1, _} = eval(\"(fn(1) -> 1 end).(1)\"),\n  {3, _} = eval(\"(fn(1, 2) -> 3 end).(1, 2)\").\n\n%% Function calls\n\nfunction_call_test() ->\n  {3, _} = eval(\"x = fn a, b -> a + b end\\nx.(1, 2)\").\n\nfunction_call_without_arg_test() ->\n  {3, _} = eval(\"x = fn -> 2 + 1 end\\nx.()\").\n\nfunction_call_do_end_test() ->\n  {[1, [{do, 2}, {'else', 3}]], _} = eval(\"x = fn a, b -> [a, b] end\\nx.(1) do\\n2\\nelse 3\\nend\").\n\nfunction_call_with_assignment_test() ->\n  {3, [{a, _}, {c, 3}]} = eval(\"a = fn x -> x + 2 end; c = a.(1)\").\n\nfunction_calls_with_multiple_expressions_test() ->\n  {26, _} = eval(\"a = fn a, b -> a + b end; a.((3 + 4 - 1), (2 * 10))\").\n\nfunction_calls_with_multiple_args_with_line_breaks_test() ->\n  {5, _} = eval(\"a = fn a, b -> a + b end; a.(\\n3,\\n2\\n)\").\n\nfunction_calls_with_parenthesis_test() ->\n  {3, [{a, _}, {b, 1}]} = eval(\"a = (fn x -> x + 2 end).(b = 1)\").\n\nfunction_call_with_a_single_space_test() ->\n  {3, _} = eval(\"a = fn a, b -> a + b end; a. (1, 2)\"),\n  {3, _} = eval(\"a = fn a, b -> a + b end; a .(1, 2)\").\n\nfunction_call_with_spaces_test() ->\n  {3, _} = eval(\"a = fn a, b -> a + b end; a . (1, 2)\").\n\nfunction_call_without_assigning_with_spaces_test() ->\n  {3, _} = eval(\"(fn a, b -> a + b end) . (1, 2)\").\n\nfunction_call_with_assignment_and_spaces_test() ->\n  {3, [{a, _}, {c, 3}]} = eval(\"a = fn x -> x + 2 end; c = a . (1)\").\n\nfunction_call_with_multiple_spaces_test() ->\n  {3, _} = eval(\"a = fn a, b -> a + b end; a .         (1, 2)\").\n\nfunction_call_with_multiline_test() ->\n  {3, _} = eval(\"a = fn a, b -> a + b end; a .   \\n      (1, 2)\").\n\nfunction_call_with_tabs_test() ->\n  {3, _} = eval(\"a = fn a, b -> a + b end; a .\\n\\t(1, 2)\").\n\nfunction_call_with_args_and_nested_when_test() ->\n  {Fun, _} = eval(\"fn a, b when a == 1 when b == 2 -> a + b end\"),\n  3 = Fun(1, 2),\n  2 = Fun(0, 2),\n  1 = Fun(1, 0),\n  ?assertError(function_clause, Fun(0, 0)).\n\nfunction_call_with_parens_args_and_nested_when_test() ->\n  {Fun, _} = eval(\"fn\\n(a, b) when a == 1 when b == 2 -> a + b\\nend\"),\n  3 = Fun(1, 2),\n  2 = Fun(0, 2),\n  1 = Fun(1, 0),\n  ?assertError(function_clause, Fun(0, 0)).\n\n%% Partial application\n\nrequire_partial_application_test() ->\n  {Fun, _} = eval(\"&List.flatten(&1)\"),\n  Fun = fun 'Elixir.List':flatten/1.\n\nimport_partial_application_test() ->\n  {Fun, _} = eval(\"&is_atom(&1)\"),\n  Fun = fun erlang:is_atom/1.\n"
  },
  {
    "path": "lib/elixir/test/erlang/string_test.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(string_test).\n-include(\"../../src/elixir.hrl\").\n-include_lib(\"eunit/include/eunit.hrl\").\n\neval(Content) ->\n  Quoted = elixir:'string_to_quoted!'(Content, 1, 1, <<\"nofile\">>, []),\n  {Value, Binding, _} = elixir:eval_forms(Quoted, [], elixir:env_for_eval([])),\n  {Value, Binding}.\n\nextract_interpolations(String) ->\n  case elixir_interpolation:extract(1, 1, #elixir_tokenizer{}, true, String ++ [$\"], $\") of\n    {error, Error} ->\n      Error;\n    {_, _, Parts, _, _, _} ->\n      Parts\n   end.\n\n% Interpolations\n\nextract_interpolations_without_interpolation_test() ->\n  [\"foo\"] = extract_interpolations(\"foo\").\n\nextract_interpolations_with_escaped_interpolation_test() ->\n  [\"f\\\\#{o}o\"] = extract_interpolations(\"f\\\\#{o}o\"),\n  {1, 10, [\"f\\\\#{o}o\"], [], _, _} =\n    elixir_interpolation:extract(1, 2, #elixir_tokenizer{}, true, \"f\\\\#{o}o\\\"\", $\").\n\nextract_interpolations_with_interpolation_test() ->\n  [\"f\",\n   {{1, 2, nil}, {1, 6, nil}, [{atom, {1, 4, _}, o}]},\n   \"o\"] = extract_interpolations(\"f#{:o}o\").\n\nextract_interpolations_with_two_interpolations_test() ->\n  [\"f\",\n   {{1, 2, nil}, {1, 6, nil}, [{atom, {1, 4, _}, o}]},\n   {{1, 7, nil}, {1, 11, nil}, [{atom, {1, 9, _}, o}]},\n   \"o\"] = extract_interpolations(\"f#{:o}#{:o}o\").\n\nextract_interpolations_with_only_two_interpolations_test() ->\n  [{{1, 1, nil}, {1, 5, nil}, [{atom, {1, 3, _}, o}]},\n   {{1, 6, nil}, {1, 10, nil}, [{atom, {1, 8, _}, o}]}] = extract_interpolations(\"#{:o}#{:o}\").\n\nextract_interpolations_with_tuple_inside_interpolation_test() ->\n  [\"f\",\n   {{1, 2, nil}, {1, 7, nil}, [{'{', {1, 4, nil}}, {int, {1, 5, 1}, \"1\"}, {'}', {1, 6, nil}}]},\n   \"o\"] = extract_interpolations(\"f#{{1}}o\").\n\nextract_interpolations_with_many_expressions_inside_interpolation_test() ->\n  [\"f\",\n   {{1, 2, nil}, {2, 2, nil}, [{int, {1, 4, 1}, \"1\"}, {eol, {1, 5, 1}}, {int, {2, 1, 2}, \"2\"}]},\n    \"o\"] = extract_interpolations(\"f#{1\\n2}o\").\n\nextract_interpolations_with_right_curly_inside_string_inside_interpolation_test() ->\n  [\"f\",\n   {{1, 2, nil}, {1, 9, nil}, [{bin_string, {1, 4, nil}, [<<\"f}o\">>]}]},\n   \"o\"] = extract_interpolations(\"f#{\\\"f}o\\\"}o\").\n\nextract_interpolations_with_left_curly_inside_string_inside_interpolation_test() ->\n  [\"f\",\n   {{1, 2, nil}, {1, 9, nil}, [{bin_string, {1, 4, nil}, [<<\"f{o\">>]}]},\n   \"o\"] = extract_interpolations(\"f#{\\\"f{o\\\"}o\").\n\nextract_interpolations_with_escaped_quote_inside_string_inside_interpolation_test() ->\n  [\"f\",\n   {{1, 2, nil}, {1, 10, nil}, [{bin_string, {1, 4, nil}, [<<\"f\\\"o\">>]}]},\n   \"o\"] = extract_interpolations(\"f#{\\\"f\\\\\\\"o\\\"}o\").\n\nextract_interpolations_with_less_than_operation_inside_interpolation_test() ->\n  [\"f\",\n   {{1, 2, nil}, {1, 7, nil}, [{int, {1, 4, 1}, \"1\"}, {rel_op, {1, 5, nil}, '<'}, {int, {1, 6, 2}, \"2\"}]},\n   \"o\"] = extract_interpolations(\"f#{1<2}o\").\n\nextract_interpolations_with_an_escaped_character_test() ->\n  [\"f\",\n   {{1, 2, nil}, {1, 16, nil}, [{char, {1, 4, \"?\\\\a\"}, 7}, {rel_op, {1, 8, nil}, '>'}, {char, {1, 10, \"?\\\\a\"}, 7}]}\n   ] = extract_interpolations(\"f#{?\\\\a > ?\\\\a   }\").\n\nextract_interpolations_with_invalid_expression_inside_interpolation_test() ->\n  {[{line, 1}, {column, 4}], \"unexpected token: \", _} = extract_interpolations(\"f#{:1}o\").\n\n%% Bin strings\n\nempty_test() ->\n  {<<\"\">>, _} = eval(\"\\\"\\\"\").\n\nstring_with_double_quotes_test() ->\n  {<<\"f\\\"o\\\"o\">>, _} = eval(\"\\\"f\\\\\\\"o\\\\\\\"o\\\"\").\n\nstring_with_newline_test() ->\n  {<<\"f\\no\">>, _} = eval(\"\\\"f\\no\\\"\").\n\nstring_with_slash_test() ->\n  {<<\"f\\\\o\">>, _} = eval(\"\\\"f\\\\\\\\o\\\"\").\n\nstring_with_bell_character_test() ->\n  {<<\"f\\ao\">>, _} = eval(\"\\\"f\\ao\\\"\").\n\nstring_with_interpolation_test() ->\n  {<<\"foo\">>, _} = eval(\"\\\"f#{\\\"o\\\"}o\\\"\").\n\nstring_with_another_string_inside_string_inside_interpolation_test() ->\n  {<<\"fbaro\">>, _} = eval(\"\\\"f#{\\\"b#{\\\"a\\\"}r\\\"}o\\\"\").\n\nstring_with_another_string_with_curly_inside_interpolation_test() ->\n  {<<\"fb}ro\">>, _} = eval(\"\\\"f#{\\\"b}r\\\"}o\\\"\").\n\nstring_with_atom_with_separator_inside_interpolation_test() ->\n  {<<\"f}o\">>, _} = eval(\"\\\"f#{\\\"}\\\"}o\\\"\").\n\nstring_with_lower_case_hex_interpolation_test() ->\n  {<<\"jklmno\">>, _} = eval(\"\\\"\\\\x6a\\\\x6b\\\\x6c\\\\x6d\\\\x6e\\\\x6f\\\"\").\n\nstring_with_upper_case_hex_interpolation_test() ->\n  {<<\"jklmno\">>, _} = eval(\"\\\"\\\\x6A\\\\x6B\\\\x6C\\\\x6D\\\\x6E\\\\x6F\\\"\").\n\nstring_without_interpolation_and_escaped_test() ->\n  {<<\"f#o\">>, _} = eval(\"\\\"f\\\\#o\\\"\").\n\nstring_with_escaped_interpolation_test() ->\n  {<<\"f#{'o}o\">>, _} = eval(\"\\\"f\\\\#{'o}o\\\"\").\n\nstring_with_the_end_of_line_slash_test() ->\n  {<<\"fo\">>, _} = eval(\"\\\"f\\\\\\no\\\"\"),\n  {<<\"fo\">>, _} = eval(\"\\\"f\\\\\\r\\no\\\"\").\n\ninvalid_string_interpolation_test() ->\n  ?assertError(#{'__struct__' := 'Elixir.TokenMissingError'}, eval(\"\\\"f#{some\\\"\")),\n  ?assertError(#{'__struct__' := 'Elixir.TokenMissingError'}, eval(\"\\\"f#{1+\")).\n\nunterminated_string_interpolation_test() ->\n  ?assertError(#{'__struct__' := 'Elixir.TokenMissingError'}, eval(\"\\\"foo\")).\n\nchar_test() ->\n  {99, []} = eval(\"?1 + ?2\"),\n  {10, []} = eval(\"?\\\\n\"),\n  {40, []} = eval(\"?(\").\n"
  },
  {
    "path": "lib/elixir/test/erlang/test_helper.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(test_helper).\n-export([test/0, run_and_remove/2, throw_elixir/1, throw_erlang/1]).\n-define(TESTS, [\n  atom_test,\n  control_test,\n  function_test,\n  string_test,\n  tokenizer_test\n]).\n\ntest() ->\n  application:ensure_all_started(elixir),\n  case eunit:test(?TESTS) of\n    error -> erlang:halt(1);\n    _Res  -> erlang:halt(0)\n  end.\n\n% Execute a piece of code and purge given modules right after\nrun_and_remove(Fun, Modules) ->\n  try\n    Fun()\n  after\n    [code:purge(Module)  || Module <- Modules],\n    [code:delete(Module) || Module <- Modules]\n  end.\n\n% Throws an error with the Erlang Abstract Form from the Elixir string\nthrow_elixir(String) ->\n  Forms = elixir:'string_to_quoted!'(String, 1, 1, <<\"nofile\">>, []),\n  {Expr, _, _, _} = elixir:quoted_to_erl(Forms, elixir:env_for_eval([])),\n  erlang:error(io:format(\"~p~n\", [Expr])).\n\n% Throws an error with the Erlang Abstract Form from the Erlang string\nthrow_erlang(String) ->\n  {ok, Tokens, _} = erl_scan:string(String),\n  {ok, [Form]} = erl_parse:parse_exprs(Tokens),\n  erlang:error(io:format(\"~p~n\", [Form])).\n"
  },
  {
    "path": "lib/elixir/test/erlang/tokenizer_test.erl",
    "content": "%% SPDX-License-Identifier: Apache-2.0\n%% SPDX-FileCopyrightText: 2021 The Elixir Team\n%% SPDX-FileCopyrightText: 2012 Plataformatec\n\n-module(tokenizer_test).\n-include_lib(\"eunit/include/eunit.hrl\").\n\ntokenize(String) ->\n  tokenize(String, []).\n\ntokenize(String, Opts) ->\n  {ok, _Line, _Column, _Warnings, Result, []} = elixir_tokenizer:tokenize(String, 1, Opts),\n  lists:reverse(Result).\n\ntokenize_error(String) ->\n  {error, Error, _, _, _} = elixir_tokenizer:tokenize(String, 1, []),\n  Error.\n\ntokenize_warnings(String) ->\n  {ok, _Line, _Column, Warnings, Result, []} = elixir_tokenizer:tokenize(String, 1, []),\n  {lists:reverse(Result), Warnings}.\n\ntype_test() ->\n  [{int, {1, 1, 1}, \"1\"},\n   {type_op, {1, 3, nil}, '::'},\n   {int, {1, 6, 3}, \"3\"}] = tokenize(\"1 :: 3\"),\n  [{'true', {1, 1, nil}},\n   {type_op, {1, 5, nil}, '::'},\n   {int, {1, 7, 3}, \"3\"}] = tokenize(\"true::3\"),\n  [{identifier, {1, 1, _}, name},\n   {'.', {1, 5, nil}},\n   {paren_identifier, {1, 6, _}, '::'},\n   {'(', {1, 8, nil}},\n   {int, {1, 9, 3}, \"3\"},\n   {')', {1, 10, nil}}] = tokenize(\"name.::(3)\").\n\narithmetic_test() ->\n  [{int, {1, 1, 1}, \"1\"},\n   {dual_op, {1, 3, nil}, '+'},\n   {int, {1, 5, 2}, \"2\"},\n   {dual_op, {1, 7, nil}, '+'},\n   {int, {1, 9, 3}, \"3\"}] = tokenize(\"1 + 2 + 3\").\n\nop_kw_test() ->\n  [{atom, {1, 1, _}, foo},\n   {dual_op, {1, 5, nil}, '+'},\n   {atom, {1, 6, _}, bar}] = tokenize(\":foo+:bar\").\n\nscientific_test() ->\n  [{flt, {1, 1, 0.1}, \"1.0e-1\"}] = tokenize(\"1.0e-1\"),\n  [{flt, {1, 1, 0.1}, \"1.0E-1\"}] = tokenize(\"1.0E-1\"),\n  [{flt, {1, 1, 1.2345678e-7}, \"1_234.567_8e-10\"}] = tokenize(\"1_234.567_8e-10\"),\n  {[{line, 1}, {column, 1}], \"invalid float number \", \"1.0e309\"} = tokenize_error(\"1.0e309\").\n\nhex_bin_octal_test() ->\n  [{int, {1, 1, 255}, \"0xFF\"}] = tokenize(\"0xFF\"),\n  [{int, {1, 1, 255}, \"0xF_F\"}] = tokenize(\"0xF_F\"),\n  [{int, {1, 1, 63}, \"0o77\"}] = tokenize(\"0o77\"),\n  [{int, {1, 1, 63}, \"0o7_7\"}] = tokenize(\"0o7_7\"),\n  [{int, {1, 1, 3}, \"0b11\"}] = tokenize(\"0b11\"),\n  [{int, {1, 1, 3}, \"0b1_1\"}] = tokenize(\"0b1_1\").\n\nunquoted_atom_test() ->\n  [{atom, {1, 1, _}, '+'}] = tokenize(\":+\"),\n  [{atom, {1, 1, _}, '-'}] = tokenize(\":-\"),\n  [{atom, {1, 1, _}, '*'}] = tokenize(\":*\"),\n  [{atom, {1, 1, _}, '/'}] = tokenize(\":/\"),\n  [{atom, {1, 1, _}, '='}] = tokenize(\":=\"),\n  [{atom, {1, 1, _}, '&&'}] = tokenize(\":&&\").\n\nquoted_atom_test() ->\n  [{atom_quoted, {1, 1, $\"}, 'foo bar'}] = tokenize(\":\\\"foo bar\\\"\").\n\noversized_atom_test() ->\n  OversizedAtom = string:copies(\"a\", 256),\n  {[{line, 1}, {column, 1}], \"atom length must be less than system limit: \", OversizedAtom} =\n    tokenize_error([$: | OversizedAtom]).\n\nop_atom_test() ->\n  [{atom, {1, 1, _}, f0_1}] = tokenize(\":f0_1\").\n\nkw_test() ->\n  [{kw_identifier, {1, 1, _}, do}] = tokenize(\"do: \"),\n  [{kw_identifier, {1, 1, _}, a@}] = tokenize(\"a@: \"),\n  [{kw_identifier, {1, 1, _}, 'A@'}] = tokenize(\"A@: \"),\n  [{kw_identifier, {1, 1, _}, a@b}] = tokenize(\"a@b: \"),\n  [{kw_identifier, {1, 1, _}, 'A@!'}] = tokenize(\"A@!: \"),\n  [{kw_identifier, {1, 1, _}, 'a@!'}] = tokenize(\"a@!: \"),\n  [{kw_identifier, {1, 1, _}, foo}, {bin_string, {1, 6, nil}, [<<\"bar\">>]}] = tokenize(\"foo: \\\"bar\\\"\"),\n  [{kw_identifier, {1, 1, _}, '+'}, {bin_string, {1, 6, nil}, [<<\"bar\">>]}] = tokenize(\"\\\"+\\\": \\\"bar\\\"\").\n\nint_test() ->\n  [{int, {1, 1, 123}, \"123\"}] = tokenize(\"123\"),\n  [{int, {1, 1, 123}, \"123\"}, {';', {1, 4, 0}}] = tokenize(\"123;\"),\n  [{eol, {1, 1, 2}}, {int, {3, 1, 123}, \"123\"}] = tokenize(\"\\n\\n123\"),\n  [{int, {1, 3, 123}, \"123\"}, {int, {1, 8, 234}, \"234\"}] = tokenize(\"  123  234  \"),\n  [{int, {1, 1, 7}, \"007\"}] = tokenize(\"007\"),\n  [{int, {1, 1, 100000}, \"0100000\"}] = tokenize(\"0100000\").\n\nfloat_test() ->\n  [{flt, {1, 1, 12.3}, \"12.3\"}] = tokenize(\"12.3\"),\n  [{flt, {1, 1, 12.3}, \"12.3\"}, {';', {1, 5, 0}}] = tokenize(\"12.3;\"),\n  [{eol, {1, 1, 2}}, {flt, {3, 1, 12.3}, \"12.3\"}] = tokenize(\"\\n\\n12.3\"),\n  [{flt, {1, 3, 12.3}, \"12.3\"}, {flt, {1, 9, 23.4}, \"23.4\"}] = tokenize(\"  12.3  23.4  \"),\n  [{flt, {1, 1, 12.3}, \"00_12.3_00\"}] = tokenize(\"00_12.3_00\"),\n  OversizedFloat = string:copies(\"9\", 310) ++ \".0\",\n  {[{line, 1}, {column, 1}], \"invalid float number \", OversizedFloat} = tokenize_error(OversizedFloat).\n\nidentifier_test() ->\n  [{identifier, {1, 1, _}, abc}] = tokenize(\"abc \"),\n  [{identifier, {1, 1, _}, 'abc?'}] = tokenize(\"abc?\"),\n  [{identifier, {1, 1, _}, 'abc!'}] = tokenize(\"abc!\"),\n  [{identifier, {1, 1, _}, 'a0c!'}] = tokenize(\"a0c!\"),\n  [{paren_identifier, {1, 1, _}, 'a0c'}, {'(', {1, 4, nil}}, {')', {1, 5, nil}}] = tokenize(\"a0c()\"),\n  [{paren_identifier, {1, 1, _}, 'a0c!'}, {'(', {1, 5, nil}}, {')', {1, 6, nil}}] = tokenize(\"a0c!()\").\n\nmodule_macro_test() ->\n  [{identifier, {1, 1, _}, '__MODULE__'}] = tokenize(\"__MODULE__\").\n\ndot_test() ->\n  [{identifier, {1, 1, _}, foo},\n   {'.', {1, 4, nil}},\n   {identifier, {1, 5, _}, bar},\n   {'.', {1, 8, nil}},\n   {identifier, {1, 9, _}, baz}] = tokenize(\"foo.bar.baz\").\n\ndot_keyword_test() ->\n [{identifier, {1, 1, _}, foo},\n  {'.', {1, 4, nil}},\n  {identifier, {1, 5, _}, do}] = tokenize(\"foo.do\").\n\nnewline_test() ->\n  [{identifier, {1, 1, _}, foo},\n   {'.', {2, 1, nil}},\n   {identifier, {2, 2, _}, bar}]  = tokenize(\"foo\\n.bar\"),\n  [{int, {1, 1, 1}, \"1\"},\n   {concat_op, {2, 1, 1}, '++'},\n   {int, {2, 3, 2}, \"2\"}]  = tokenize(\"1\\n++2\").\n\ndot_newline_operator_test() ->\n  [{identifier, {1, 1, _}, foo},\n   {'.', {1, 4, nil}},\n   {identifier, {2, 1, _}, '+'},\n   {int, {2, 2, 1}, \"1\"}] = tokenize(\"foo.\\n+1\"),\n  [{identifier, {1, 1, _}, foo},\n   {'.', {1, 4, nil}},\n   {identifier, {2, 1, _}, '+'},\n   {int, {2, 2, 1}, \"1\"}] = tokenize(\"foo.#bar\\n+1\").\n\ndot_call_operator_test() ->\n  [{identifier, {1, 1, _}, f},\n   {dot_call_op, {1, 2, nil}, '.'},\n   {'(', {1, 3, nil}},\n   {')', {1, 4, nil}}] = tokenize(\"f.()\").\n\naliases_test() ->\n  [{'alias', {1, 1, _}, 'Foo'}] = tokenize(\"Foo\"),\n  [{'alias', {1, 1, _}, 'Foo'},\n   {'.', {1, 4, nil}},\n   {'alias', {1, 5, _}, 'Bar'},\n   {'.', {1, 8, nil}},\n   {'alias', {1, 9, _}, 'Baz'}] = tokenize(\"Foo.Bar.Baz\").\n\nstring_test() ->\n  [{bin_string, {1, 1, nil}, [<<\"foo\">>]}] = tokenize(\"\\\"foo\\\"\"),\n  [{bin_string, {1, 1, nil}, [<<\"f\\\"\">>]}] = tokenize(\"\\\"f\\\\\\\"\\\"\").\n\nheredoc_test() ->\n  [{bin_heredoc, {1, 1, nil}, 0, [<<\"heredoc\\n\">>]}] = tokenize(\"\\\"\\\"\\\"\\nheredoc\\n\\\"\\\"\\\"\"),\n  [{bin_heredoc, {1, 1, nil}, 1, [<<\"heredoc\\n\">>]}, {';', {3, 5, 0}}] = tokenize(\"\\\"\\\"\\\"\\n heredoc\\n \\\"\\\"\\\";\").\n\nempty_string_test() ->\n  [{bin_string, {1, 1, nil}, [<<>>]}] = tokenize(\"\\\"\\\"\").\n\nconcat_test() ->\n  [{identifier, {1, 1, _}, x},\n   {concat_op, {1, 3, nil}, '++'},\n   {identifier, {1, 6, _}, y}] = tokenize(\"x ++ y\"),\n  [{identifier, {1, 1, _}, x},\n   {concat_op, {1, 3, nil}, '+++'},\n   {identifier, {1, 7, _}, y}] = tokenize(\"x +++ y\").\n\nspace_test() ->\n  [{op_identifier, {1, 1, _}, foo},\n   {dual_op, {1, 5, nil}, '-'},\n   {int, {1, 6, 2}, \"2\"}] = tokenize(\"foo -2\"),\n  [{op_identifier, {1, 1, _}, foo},\n   {dual_op, {1, 6, nil}, '-'},\n   {int, {1, 7, 2}, \"2\"}] = tokenize(\"foo  -2\").\n\nchars_test() ->\n  [{char, {1, 1, \"?a\"}, 97}] = tokenize(\"?a\"),\n  [{char, {1, 1, \"?c\"}, 99}] = tokenize(\"?c\"),\n  [{char, {1, 1, \"?\\\\0\"}, 0}]  = tokenize(\"?\\\\0\"),\n  [{char, {1, 1, \"?\\\\a\"}, 7}]  = tokenize(\"?\\\\a\"),\n  [{char, {1, 1, \"?\\\\n\"}, 10}] = tokenize(\"?\\\\n\"),\n  [{char, {1, 1, \"?\\\\\\\\\"}, 92}] = tokenize(\"?\\\\\\\\\").\n\ninterpolation_test() ->\n  [{bin_string, {1, 1, nil}, [<<\"f\">>, {{1, 3, nil},{1, 7, nil}, [{identifier, {1, 5, _}, oo}]}]},\n   {concat_op, {1, 10, nil}, '<>'},\n   {bin_string, {1, 13, nil}, [<<>>]}] = tokenize(\"\\\"f#{oo}\\\" <> \\\"\\\"\").\n\nescaped_interpolation_test() ->\n  [{bin_string, {1, 1, nil}, [<<\"f#{oo}\">>]},\n   {concat_op, {1, 11, nil}, '<>'},\n   {bin_string, {1, 14, nil}, [<<>>]}] = tokenize(\"\\\"f\\\\#{oo}\\\" <> \\\"\\\"\").\n\ncapture_test() ->\n  % Parens precedence\n  [{capture_op, {1, 1, nil}, '&'},\n   {unary_op, {1, 2, nil}, 'not'},\n   {int, {1, 6, 1}, \"1\"},\n   {',', {1, 7, 0}},\n   {int, {1, 9, 2}, \"2\"}] = tokenize(\"&not 1, 2\"),\n\n  % Operators\n  [{capture_op, {1, 1, nil}, '&'},\n   {identifier, {1, 2, _}, '||'},\n   {mult_op, {1, 4, nil}, '/'},\n   {int, {1, 5, 2}, \"2\"}] = tokenize(\"&||/2\"),\n  [{capture_op, {1, 1, nil}, '&'},\n   {identifier, {1, 2, _}, 'or'},\n   {mult_op, {1, 4, nil}, '/'},\n   {int, {1, 5, 2}, \"2\"}] = tokenize(\"&or/2\"),\n  [{capture_op,{1,1,nil},'&'},\n   {identifier,{1,3,_},'+'},\n   {mult_op,{1,4,nil},'/'},\n   {int,{1,5,1},\"1\"}] = tokenize(\"& +/1\"),\n  [{capture_op,{1,1,nil},'&'},\n   {identifier,{1,3,_},'&'},\n   {mult_op,{1,4,nil},'/'},\n   {int,{1,5,1},\"1\"}] = tokenize(\"& &/1\"),\n  [{capture_op,{1,1,nil},'&'},\n   {identifier,{1,3,_},'..//'},\n   {mult_op,{1,7,nil},'/'},\n   {int,{1,8,3},\"3\"}] = tokenize(\"& ..///3\"),\n  [{capture_op, {1,1,nil}, '&'},\n   {identifier, {1,3,_}, '/'},\n   {mult_op, {1,5,nil}, '/'},\n   {int, {1,6,2}, \"2\"}] = tokenize(\"& / /2\"),\n  [{capture_op, {1,1,nil}, '&'},\n   {identifier, {1,2,_}, '/'},\n   {mult_op, {1,4,nil}, '/'},\n   {int, {1,5,2}, \"2\"}] = tokenize(\"&/ /2\"),\n\n  % Only operators\n  [{identifier,{1,1,_},'&'},\n   {mult_op,{1,2,nil},'/'},\n   {int,{1,3,1},\"1\"}] = tokenize(\"&/1\"),\n  [{identifier,{1,1,_},'+'},\n   {mult_op,{1,2,nil},'/'},\n   {int,{1,3,1},\"1\"}] = tokenize(\"+/1\"),\n  [{identifier, {1,1,_}, '/'},\n   {mult_op, {1,3,nil}, '/'},\n   {int, {1,4,2}, \"2\"}] = tokenize(\"/ /2\"),\n  [{identifier, {1,1,_}, '..//'},\n   {mult_op, {1,5,nil}, '/'},\n   {int, {1,6,3}, \"3\"}] = tokenize(\"..///3\").\n\nvc_merge_conflict_test() ->\n  {[{line, 1}, {column, 1}], \"found an unexpected version control marker, please resolve the conflicts: \", \"<<<<<<< HEAD\"} =\n    tokenize_error(\"<<<<<<< HEAD\\n[1, 2, 3]\").\n\nsigil_terminator_test() ->\n  [{sigil, {1, 1, {1, 8}}, sigil_r, [<<\"foo\">>], [], nil, <<\"/\">>}] = tokenize(\"~r/foo/\"),\n  [{sigil, {1, 1, {1, 8}}, sigil_r, [<<\"foo\">>], [], nil, <<\"[\">>}] = tokenize(\"~r[foo]\"),\n  [{sigil, {1, 1, {1, 8}}, sigil_r, [<<\"foo\">>], [], nil, <<\"\\\"\">>}] = tokenize(\"~r\\\"foo\\\"\"),\n  [{sigil, {1, 1, {1, 8}}, sigil_r, [<<\"foo\">>], [], nil, <<\"/\">>},\n   {comp_op, {1, 9, nil}, '=='},\n   {identifier, {1, 12, _}, bar}] = tokenize(\"~r/foo/ == bar\"),\n  [{sigil, {1, 1, {1, 10}}, sigil_r, [<<\"foo\">>], \"iu\", nil, <<\"/\">>},\n   {comp_op, {1, 11, nil}, '=='},\n   {identifier, {1, 14, _}, bar}] = tokenize(\"~r/foo/iu == bar\"),\n  [{sigil, {1, 1, {1, 12}}, sigil_M, [<<\"1 2 3\">>], \"u8\", nil, <<\"[\">>}] = tokenize(\"~M[1 2 3]u8\").\n\nsigil_heredoc_test() ->\n  [{sigil, {1, 1, {3, 4}}, sigil_S, [<<\"sigil heredoc\\n\">>], [], 0, <<\"\\\"\\\"\\\"\">>}] = tokenize(\"~S\\\"\\\"\\\"\\nsigil heredoc\\n\\\"\\\"\\\"\"),\n  [{sigil, {1, 1, {3, 4}}, sigil_S, [<<\"sigil heredoc\\n\">>], [], 0, <<\"'''\">>}] = tokenize(\"~S'''\\nsigil heredoc\\n'''\"),\n  [{sigil, {1, 1, {3, 6}}, sigil_S, [<<\"sigil heredoc\\n\">>], [], 2, <<\"\\\"\\\"\\\"\">>}] = tokenize(\"~S\\\"\\\"\\\"\\n  sigil heredoc\\n  \\\"\\\"\\\"\"),\n  [{sigil, {1, 1, {3, 6}}, sigil_s, [<<\"sigil heredoc\\n\">>], [], 2, <<\"\\\"\\\"\\\"\">>}] = tokenize(\"~s\\\"\\\"\\\"\\n  sigil heredoc\\n  \\\"\\\"\\\"\").\n\ninvalid_sigil_delimiter_test() ->\n  {[{line, 1}, {column, 1}], \"invalid sigil delimiter: \", Message} = tokenize_error(\"~s\\\\\"),\n  true = lists:prefix(\"\\\"\\\\\\\" (column 3, code point U+005C)\", lists:flatten(Message)).\n\ndeprecated_operators_test() ->\n  {\n    [{xor_op, {1, 1, nil}, '^^^'}, {int, {1, 4, 1}, \"1\"}],\n    [{{1, 1}, \"^^^ is deprecated. It is typically used as xor but it has the wrong precedence, use Bitwise.bxor/2 instead\"}]\n  } = tokenize_warnings(\"^^^1\"),\n  {\n    [{unary_op, {1, 1, nil}, '~~~'}, {int, {1, 4, 1}, \"1\"}],\n    [{{1, 1}, \"~~~ is deprecated. Use Bitwise.bnot/1 instead for clarity\"}]\n  } = tokenize_warnings(\"~~~1\").\n"
  },
  {
    "path": "lib/elixir/unicode/IdentifierType.txt",
    "content": "# IdentifierType.txt\n# Date: 2025-08-04, 21:58:43 GMT\n# © 2025 Unicode®, Inc.\n# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.\n# For terms of use and license, see https://www.unicode.org/terms_of_use.html\n#\n# Unicode Security Mechanisms for UTS #39\n# Version: 17.0.0\n#\n# For documentation and usage, see https://www.unicode.org/reports/tr39\n#\n# Format\n#\n# Field 0: code point\n# Field 1: set of Identifier_Type values\n#          See the \"Identifier_Status and Identifier_Type\" table of UTS #39:\n#          https://www.unicode.org/reports/tr39/#Identifier_Status_and_Type\n\n#\n# For the purpose of regular expressions, the property Identifier_Type is defined as\n# mapping each code point to a set of enumerated values.\n# The short name of Identifier_Type is ID_Type.\n# The possible values are:\n#   Not_Character, Deprecated, Default_Ignorable, Not_NFKC, Not_XID,\n#   Exclusion, Obsolete, Technical, Uncommon_Use, Limited_Use, Inclusion, Recommended\n# The short name of each value is the same as its long name.\n\n# All code points not explicitly listed for Identifier_Type\n# have the value Not_Character.\n\n# @missing: 0000..10FFFF; Not_Character\n\n# As usual, sets are unordered, with no duplicate values.\n\n\n#\tIdentifier_Type:\tRecommended\n\n0030..0039    ; Recommended                    # 1.1   [10] DIGIT ZERO..DIGIT NINE\n0041..005A    ; Recommended                    # 1.1   [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z\n005F          ; Recommended                    # 1.1        LOW LINE\n0061..007A    ; Recommended                    # 1.1   [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z\n00C0..00D6    ; Recommended                    # 1.1   [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS\n00D8..00F6    ; Recommended                    # 1.1   [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS\n00F8..0113    ; Recommended                    # 1.1   [28] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER E WITH MACRON\n0116..012B    ; Recommended                    # 1.1   [22] LATIN CAPITAL LETTER E WITH DOT ABOVE..LATIN SMALL LETTER I WITH MACRON\n012E..0131    ; Recommended                    # 1.1    [4] LATIN CAPITAL LETTER I WITH OGONEK..LATIN SMALL LETTER DOTLESS I\n0134..0137    ; Recommended                    # 1.1    [4] LATIN CAPITAL LETTER J WITH CIRCUMFLEX..LATIN SMALL LETTER K WITH CEDILLA\n0139..013E    ; Recommended                    # 1.1    [6] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER L WITH CARON\n0141..0148    ; Recommended                    # 1.1    [8] LATIN CAPITAL LETTER L WITH STROKE..LATIN SMALL LETTER N WITH CARON\n014A..014D    ; Recommended                    # 1.1    [4] LATIN CAPITAL LETTER ENG..LATIN SMALL LETTER O WITH MACRON\n0150..0155    ; Recommended                    # 1.1    [6] LATIN CAPITAL LETTER O WITH DOUBLE ACUTE..LATIN SMALL LETTER R WITH ACUTE\n0158..0161    ; Recommended                    # 1.1   [10] LATIN CAPITAL LETTER R WITH CARON..LATIN SMALL LETTER S WITH CARON\n0164..017E    ; Recommended                    # 1.1   [27] LATIN CAPITAL LETTER T WITH CARON..LATIN SMALL LETTER Z WITH CARON\n0181          ; Recommended                    # 1.1        LATIN CAPITAL LETTER B WITH HOOK\n0186          ; Recommended                    # 1.1        LATIN CAPITAL LETTER OPEN O\n0189..018A    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER AFRICAN D..LATIN CAPITAL LETTER D WITH HOOK\n018E..0192    ; Recommended                    # 1.1    [5] LATIN CAPITAL LETTER REVERSED E..LATIN SMALL LETTER F WITH HOOK\n0194          ; Recommended                    # 1.1        LATIN CAPITAL LETTER GAMMA\n0196..0199    ; Recommended                    # 1.1    [4] LATIN CAPITAL LETTER IOTA..LATIN SMALL LETTER K WITH HOOK\n019D          ; Recommended                    # 1.1        LATIN CAPITAL LETTER N WITH LEFT HOOK\n01A0..01A1    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER O WITH HORN..LATIN SMALL LETTER O WITH HORN\n01AF..01B0    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER U WITH HORN..LATIN SMALL LETTER U WITH HORN\n01B2..01B4    ; Recommended                    # 1.1    [3] LATIN CAPITAL LETTER V WITH HOOK..LATIN SMALL LETTER Y WITH HOOK\n01B7          ; Recommended                    # 1.1        LATIN CAPITAL LETTER EZH\n01CD..01D4    ; Recommended                    # 1.1    [8] LATIN CAPITAL LETTER A WITH CARON..LATIN SMALL LETTER U WITH CARON\n01DD          ; Recommended                    # 1.1        LATIN SMALL LETTER TURNED E\n01E6..01E9    ; Recommended                    # 1.1    [4] LATIN CAPITAL LETTER G WITH CARON..LATIN SMALL LETTER K WITH CARON\n01EE..01EF    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER EZH WITH CARON..LATIN SMALL LETTER EZH WITH CARON\n01F8..01F9    ; Recommended                    # 3.0    [2] LATIN CAPITAL LETTER N WITH GRAVE..LATIN SMALL LETTER N WITH GRAVE\n0218..021B    ; Recommended                    # 3.0    [4] LATIN CAPITAL LETTER S WITH COMMA BELOW..LATIN SMALL LETTER T WITH COMMA BELOW\n0244          ; Recommended                    # 5.0        LATIN CAPITAL LETTER U BAR\n024C..024D    ; Recommended                    # 5.0    [2] LATIN CAPITAL LETTER R WITH STROKE..LATIN SMALL LETTER R WITH STROKE\n0253..0254    ; Recommended                    # 1.1    [2] LATIN SMALL LETTER B WITH HOOK..LATIN SMALL LETTER OPEN O\n0256..0257    ; Recommended                    # 1.1    [2] LATIN SMALL LETTER D WITH TAIL..LATIN SMALL LETTER D WITH HOOK\n0259          ; Recommended                    # 1.1        LATIN SMALL LETTER SCHWA\n025B          ; Recommended                    # 1.1        LATIN SMALL LETTER OPEN E\n0263          ; Recommended                    # 1.1        LATIN SMALL LETTER GAMMA\n0268..0269    ; Recommended                    # 1.1    [2] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER IOTA\n0272          ; Recommended                    # 1.1        LATIN SMALL LETTER N WITH LEFT HOOK\n0289          ; Recommended                    # 1.1        LATIN SMALL LETTER U BAR\n028B          ; Recommended                    # 1.1        LATIN SMALL LETTER V WITH HOOK\n0292          ; Recommended                    # 1.1        LATIN SMALL LETTER EZH\n0300..0304    ; Recommended                    # 1.1    [5] COMBINING GRAVE ACCENT..COMBINING MACRON\n0306..030C    ; Recommended                    # 1.1    [7] COMBINING BREVE..COMBINING CARON\n031B          ; Recommended                    # 1.1        COMBINING HORN\n0323          ; Recommended                    # 1.1        COMBINING DOT BELOW\n0326..0328    ; Recommended                    # 1.1    [3] COMBINING COMMA BELOW..COMBINING OGONEK\n0331          ; Recommended                    # 1.1        COMBINING MACRON BELOW\n0386          ; Recommended                    # 1.1        GREEK CAPITAL LETTER ALPHA WITH TONOS\n0388..038A    ; Recommended                    # 1.1    [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS\n038C          ; Recommended                    # 1.1        GREEK CAPITAL LETTER OMICRON WITH TONOS\n038E..03A1    ; Recommended                    # 1.1   [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO\n03A3..03CE    ; Recommended                    # 1.1   [44] GREEK CAPITAL LETTER SIGMA..GREEK SMALL LETTER OMEGA WITH TONOS\n0401..040C    ; Recommended                    # 1.1   [12] CYRILLIC CAPITAL LETTER IO..CYRILLIC CAPITAL LETTER KJE\n040E..044F    ; Recommended                    # 1.1   [66] CYRILLIC CAPITAL LETTER SHORT U..CYRILLIC SMALL LETTER YA\n0451..045C    ; Recommended                    # 1.1   [12] CYRILLIC SMALL LETTER IO..CYRILLIC SMALL LETTER KJE\n045E..045F    ; Recommended                    # 1.1    [2] CYRILLIC SMALL LETTER SHORT U..CYRILLIC SMALL LETTER DZHE\n0490..049B    ; Recommended                    # 1.1   [12] CYRILLIC CAPITAL LETTER GHE WITH UPTURN..CYRILLIC SMALL LETTER KA WITH DESCENDER\n049E..04A5    ; Recommended                    # 1.1    [8] CYRILLIC CAPITAL LETTER KA WITH STROKE..CYRILLIC SMALL LIGATURE EN GHE\n04A8..04B7    ; Recommended                    # 1.1   [16] CYRILLIC CAPITAL LETTER ABKHASIAN HA..CYRILLIC SMALL LETTER CHE WITH DESCENDER\n04BA..04C0    ; Recommended                    # 1.1    [7] CYRILLIC CAPITAL LETTER SHHA..CYRILLIC LETTER PALOCHKA\n04CF          ; Recommended                    # 5.0        CYRILLIC SMALL LETTER PALOCHKA\n04D0..04D9    ; Recommended                    # 1.1   [10] CYRILLIC CAPITAL LETTER A WITH BREVE..CYRILLIC SMALL LETTER SCHWA\n04DC..04E9    ; Recommended                    # 1.1   [14] CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS..CYRILLIC SMALL LETTER BARRED O\n04EE..04F5    ; Recommended                    # 1.1    [8] CYRILLIC CAPITAL LETTER U WITH MACRON..CYRILLIC SMALL LETTER CHE WITH DIAERESIS\n04F8..04F9    ; Recommended                    # 1.1    [2] CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS..CYRILLIC SMALL LETTER YERU WITH DIAERESIS\n0524..0525    ; Recommended                    # 5.2    [2] CYRILLIC CAPITAL LETTER PE WITH DESCENDER..CYRILLIC SMALL LETTER PE WITH DESCENDER\n0531..0556    ; Recommended                    # 1.1   [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH\n0561..0586    ; Recommended                    # 1.1   [38] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LETTER FEH\n05D0..05EA    ; Recommended                    # 1.1   [27] HEBREW LETTER ALEF..HEBREW LETTER TAV\n0620          ; Recommended                    # 6.0        ARABIC LETTER KASHMIRI YEH\n0621..063A    ; Recommended                    # 1.1   [26] ARABIC LETTER HAMZA..ARABIC LETTER GHAIN\n063D          ; Recommended                    # 5.1        ARABIC LETTER FARSI YEH WITH INVERTED V\n0641..0652    ; Recommended                    # 1.1   [18] ARABIC LETTER FEH..ARABIC SUKUN\n0654..0655    ; Recommended                    # 3.0    [2] ARABIC HAMZA ABOVE..ARABIC HAMZA BELOW\n0660..0669    ; Recommended                    # 1.1   [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE\n0670          ; Recommended                    # 1.1        ARABIC LETTER SUPERSCRIPT ALEF\n0672          ; Recommended                    # 1.1        ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE\n0674          ; Recommended                    # 1.1        ARABIC LETTER HIGH HAMZA\n0679..068F    ; Recommended                    # 1.1   [23] ARABIC LETTER TTEH..ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS\n0691..069A    ; Recommended                    # 1.1   [10] ARABIC LETTER RREH..ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE\n069F..06A0    ; Recommended                    # 1.1    [2] ARABIC LETTER TAH WITH THREE DOTS ABOVE..ARABIC LETTER AIN WITH THREE DOTS ABOVE\n06A2          ; Recommended                    # 1.1        ARABIC LETTER FEH WITH DOT MOVED BELOW\n06A4..06AB    ; Recommended                    # 1.1    [8] ARABIC LETTER VEH..ARABIC LETTER KAF WITH RING\n06AD..06B1    ; Recommended                    # 1.1    [5] ARABIC LETTER NG..ARABIC LETTER NGOEH\n06B3          ; Recommended                    # 1.1        ARABIC LETTER GUEH\n06B5..06B7    ; Recommended                    # 1.1    [3] ARABIC LETTER LAM WITH SMALL V..ARABIC LETTER LAM WITH THREE DOTS ABOVE\n06BA..06BE    ; Recommended                    # 1.1    [5] ARABIC LETTER NOON GHUNNA..ARABIC LETTER HEH DOACHASHMEE\n06C0..06CE    ; Recommended                    # 1.1   [15] ARABIC LETTER HEH WITH YEH ABOVE..ARABIC LETTER YEH WITH SMALL V\n06CF          ; Recommended                    # 3.0        ARABIC LETTER WAW WITH DOT ABOVE\n06D0..06D3    ; Recommended                    # 1.1    [4] ARABIC LETTER E..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE\n06D5          ; Recommended                    # 1.1        ARABIC LETTER AE\n06EE..06EF    ; Recommended                    # 4.0    [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V\n06F0..06F9    ; Recommended                    # 1.1   [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE\n06FF          ; Recommended                    # 4.0        ARABIC LETTER HEH WITH INVERTED V\n0751..0752    ; Recommended                    # 4.1    [2] ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE..ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW\n0756          ; Recommended                    # 4.1        ARABIC LETTER BEH WITH SMALL V\n0760          ; Recommended                    # 4.1        ARABIC LETTER FEH WITH TWO DOTS BELOW\n0762..0763    ; Recommended                    # 4.1    [2] ARABIC LETTER KEHEH WITH DOT ABOVE..ARABIC LETTER KEHEH WITH THREE DOTS ABOVE\n0766..0768    ; Recommended                    # 4.1    [3] ARABIC LETTER MEEM WITH DOT BELOW..ARABIC LETTER NOON WITH SMALL TAH\n076A          ; Recommended                    # 4.1        ARABIC LETTER LAM WITH BAR\n076E..0771    ; Recommended                    # 5.1    [4] ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW..ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS\n0780..07B0    ; Recommended                    # 3.0   [49] THAANA LETTER HAA..THAANA SUKUN\n07B1          ; Recommended                    # 3.2        THAANA LETTER NAA\n088F          ; Recommended                    # 17.0       ARABIC LETTER NOON WITH RING ABOVE\n08A0          ; Recommended                    # 6.1        ARABIC LETTER BEH WITH SMALL V BELOW\n08A2..08A9    ; Recommended                    # 6.1    [8] ARABIC LETTER JEEM WITH TWO DOTS ABOVE..ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE\n08BB..08BD    ; Recommended                    # 9.0    [3] ARABIC LETTER AFRICAN FEH..ARABIC LETTER AFRICAN NOON\n08BE..08C2    ; Recommended                    # 13.0   [5] ARABIC LETTER PEH WITH SMALL V..ARABIC LETTER KEHEH WITH SMALL V\n08C7          ; Recommended                    # 13.0       ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE\n0901..0903    ; Recommended                    # 1.1    [3] DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN VISARGA\n0905..090B    ; Recommended                    # 1.1    [7] DEVANAGARI LETTER A..DEVANAGARI LETTER VOCALIC R\n090D..0928    ; Recommended                    # 1.1   [28] DEVANAGARI LETTER CANDRA E..DEVANAGARI LETTER NA\n092A..0933    ; Recommended                    # 1.1   [10] DEVANAGARI LETTER PA..DEVANAGARI LETTER LLA\n0935..0939    ; Recommended                    # 1.1    [5] DEVANAGARI LETTER VA..DEVANAGARI LETTER HA\n093A..093B    ; Recommended                    # 6.0    [2] DEVANAGARI VOWEL SIGN OE..DEVANAGARI VOWEL SIGN OOE\n093C          ; Recommended                    # 1.1        DEVANAGARI SIGN NUKTA\n093E..0943    ; Recommended                    # 1.1    [6] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN VOCALIC R\n0945..094D    ; Recommended                    # 1.1    [9] DEVANAGARI VOWEL SIGN CANDRA E..DEVANAGARI SIGN VIRAMA\n094F          ; Recommended                    # 6.0        DEVANAGARI VOWEL SIGN AW\n0956..0957    ; Recommended                    # 6.0    [2] DEVANAGARI VOWEL SIGN UE..DEVANAGARI VOWEL SIGN UUE\n0966..096F    ; Recommended                    # 1.1   [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE\n0972          ; Recommended                    # 5.1        DEVANAGARI LETTER CANDRA A\n0973..0977    ; Recommended                    # 6.0    [5] DEVANAGARI LETTER OE..DEVANAGARI LETTER UUE\n097B..097C    ; Recommended                    # 5.0    [2] DEVANAGARI LETTER GGA..DEVANAGARI LETTER JJA\n097E..097F    ; Recommended                    # 5.0    [2] DEVANAGARI LETTER DDDA..DEVANAGARI LETTER BBA\n0981..0983    ; Recommended                    # 1.1    [3] BENGALI SIGN CANDRABINDU..BENGALI SIGN VISARGA\n0985..098B    ; Recommended                    # 1.1    [7] BENGALI LETTER A..BENGALI LETTER VOCALIC R\n098F..0990    ; Recommended                    # 1.1    [2] BENGALI LETTER E..BENGALI LETTER AI\n0993..09A8    ; Recommended                    # 1.1   [22] BENGALI LETTER O..BENGALI LETTER NA\n09AA..09B0    ; Recommended                    # 1.1    [7] BENGALI LETTER PA..BENGALI LETTER RA\n09B2          ; Recommended                    # 1.1        BENGALI LETTER LA\n09B6..09B9    ; Recommended                    # 1.1    [4] BENGALI LETTER SHA..BENGALI LETTER HA\n09BC          ; Recommended                    # 1.1        BENGALI SIGN NUKTA\n09BE..09C4    ; Recommended                    # 1.1    [7] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN VOCALIC RR\n09C7..09C8    ; Recommended                    # 1.1    [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI\n09CB..09CD    ; Recommended                    # 1.1    [3] BENGALI VOWEL SIGN O..BENGALI SIGN VIRAMA\n09CE          ; Recommended                    # 4.1        BENGALI LETTER KHANDA TA\n09E6..09F1    ; Recommended                    # 1.1   [12] BENGALI DIGIT ZERO..BENGALI LETTER RA WITH LOWER DIAGONAL\n0A02          ; Recommended                    # 1.1        GURMUKHI SIGN BINDI\n0A05..0A0A    ; Recommended                    # 1.1    [6] GURMUKHI LETTER A..GURMUKHI LETTER UU\n0A0F..0A10    ; Recommended                    # 1.1    [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI\n0A13..0A28    ; Recommended                    # 1.1   [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA\n0A2A..0A30    ; Recommended                    # 1.1    [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA\n0A32          ; Recommended                    # 1.1        GURMUKHI LETTER LA\n0A35          ; Recommended                    # 1.1        GURMUKHI LETTER VA\n0A38..0A39    ; Recommended                    # 1.1    [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA\n0A3C          ; Recommended                    # 1.1        GURMUKHI SIGN NUKTA\n0A3E..0A42    ; Recommended                    # 1.1    [5] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN UU\n0A47..0A48    ; Recommended                    # 1.1    [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI\n0A4B..0A4D    ; Recommended                    # 1.1    [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA\n0A5C          ; Recommended                    # 1.1        GURMUKHI LETTER RRA\n0A70..0A71    ; Recommended                    # 1.1    [2] GURMUKHI TIPPI..GURMUKHI ADDAK\n0A82..0A83    ; Recommended                    # 1.1    [2] GUJARATI SIGN ANUSVARA..GUJARATI SIGN VISARGA\n0A85..0A8B    ; Recommended                    # 1.1    [7] GUJARATI LETTER A..GUJARATI LETTER VOCALIC R\n0A8C          ; Recommended                    # 4.0        GUJARATI LETTER VOCALIC L\n0A8D          ; Recommended                    # 1.1        GUJARATI VOWEL CANDRA E\n0A8F..0A91    ; Recommended                    # 1.1    [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O\n0A93..0AA8    ; Recommended                    # 1.1   [22] GUJARATI LETTER O..GUJARATI LETTER NA\n0AAA..0AB0    ; Recommended                    # 1.1    [7] GUJARATI LETTER PA..GUJARATI LETTER RA\n0AB2..0AB3    ; Recommended                    # 1.1    [2] GUJARATI LETTER LA..GUJARATI LETTER LLA\n0AB5..0AB9    ; Recommended                    # 1.1    [5] GUJARATI LETTER VA..GUJARATI LETTER HA\n0ABC          ; Recommended                    # 1.1        GUJARATI SIGN NUKTA\n0ABE..0AC5    ; Recommended                    # 1.1    [8] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN CANDRA E\n0AC7..0AC9    ; Recommended                    # 1.1    [3] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN CANDRA O\n0ACB..0ACD    ; Recommended                    # 1.1    [3] GUJARATI VOWEL SIGN O..GUJARATI SIGN VIRAMA\n0AE6..0AEF    ; Recommended                    # 1.1   [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE\n0B01..0B03    ; Recommended                    # 1.1    [3] ORIYA SIGN CANDRABINDU..ORIYA SIGN VISARGA\n0B05..0B0B    ; Recommended                    # 1.1    [7] ORIYA LETTER A..ORIYA LETTER VOCALIC R\n0B0F..0B10    ; Recommended                    # 1.1    [2] ORIYA LETTER E..ORIYA LETTER AI\n0B13..0B28    ; Recommended                    # 1.1   [22] ORIYA LETTER O..ORIYA LETTER NA\n0B2A..0B30    ; Recommended                    # 1.1    [7] ORIYA LETTER PA..ORIYA LETTER RA\n0B32..0B33    ; Recommended                    # 1.1    [2] ORIYA LETTER LA..ORIYA LETTER LLA\n0B36..0B39    ; Recommended                    # 1.1    [4] ORIYA LETTER SHA..ORIYA LETTER HA\n0B3C          ; Recommended                    # 1.1        ORIYA SIGN NUKTA\n0B3E..0B43    ; Recommended                    # 1.1    [6] ORIYA VOWEL SIGN AA..ORIYA VOWEL SIGN VOCALIC R\n0B47..0B48    ; Recommended                    # 1.1    [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI\n0B4B..0B4D    ; Recommended                    # 1.1    [3] ORIYA VOWEL SIGN O..ORIYA SIGN VIRAMA\n0B56          ; Recommended                    # 1.1        ORIYA AI LENGTH MARK\n0B5F          ; Recommended                    # 1.1        ORIYA LETTER YYA\n0B71          ; Recommended                    # 4.0        ORIYA LETTER WA\n0B83          ; Recommended                    # 1.1        TAMIL SIGN VISARGA\n0B85..0B8A    ; Recommended                    # 1.1    [6] TAMIL LETTER A..TAMIL LETTER UU\n0B8E..0B90    ; Recommended                    # 1.1    [3] TAMIL LETTER E..TAMIL LETTER AI\n0B92..0B95    ; Recommended                    # 1.1    [4] TAMIL LETTER O..TAMIL LETTER KA\n0B99..0B9A    ; Recommended                    # 1.1    [2] TAMIL LETTER NGA..TAMIL LETTER CA\n0B9C          ; Recommended                    # 1.1        TAMIL LETTER JA\n0B9E..0B9F    ; Recommended                    # 1.1    [2] TAMIL LETTER NYA..TAMIL LETTER TTA\n0BA3..0BA4    ; Recommended                    # 1.1    [2] TAMIL LETTER NNA..TAMIL LETTER TA\n0BA8..0BAA    ; Recommended                    # 1.1    [3] TAMIL LETTER NA..TAMIL LETTER PA\n0BAE..0BB5    ; Recommended                    # 1.1    [8] TAMIL LETTER MA..TAMIL LETTER VA\n0BB6          ; Recommended                    # 4.1        TAMIL LETTER SHA\n0BB7..0BB9    ; Recommended                    # 1.1    [3] TAMIL LETTER SSA..TAMIL LETTER HA\n0BBE..0BC2    ; Recommended                    # 1.1    [5] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN UU\n0BC6..0BC8    ; Recommended                    # 1.1    [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI\n0BCA..0BCD    ; Recommended                    # 1.1    [4] TAMIL VOWEL SIGN O..TAMIL SIGN VIRAMA\n0C02..0C03    ; Recommended                    # 1.1    [2] TELUGU SIGN ANUSVARA..TELUGU SIGN VISARGA\n0C05..0C0B    ; Recommended                    # 1.1    [7] TELUGU LETTER A..TELUGU LETTER VOCALIC R\n0C0E..0C10    ; Recommended                    # 1.1    [3] TELUGU LETTER E..TELUGU LETTER AI\n0C12..0C28    ; Recommended                    # 1.1   [23] TELUGU LETTER O..TELUGU LETTER NA\n0C2A..0C30    ; Recommended                    # 1.1    [7] TELUGU LETTER PA..TELUGU LETTER RA\n0C32..0C33    ; Recommended                    # 1.1    [2] TELUGU LETTER LA..TELUGU LETTER LLA\n0C35..0C39    ; Recommended                    # 1.1    [5] TELUGU LETTER VA..TELUGU LETTER HA\n0C3E..0C44    ; Recommended                    # 1.1    [7] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN VOCALIC RR\n0C46..0C48    ; Recommended                    # 1.1    [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI\n0C4A..0C4D    ; Recommended                    # 1.1    [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA\n0C82..0C83    ; Recommended                    # 1.1    [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA\n0C85..0C8B    ; Recommended                    # 1.1    [7] KANNADA LETTER A..KANNADA LETTER VOCALIC R\n0C8E..0C90    ; Recommended                    # 1.1    [3] KANNADA LETTER E..KANNADA LETTER AI\n0C92..0CA8    ; Recommended                    # 1.1   [23] KANNADA LETTER O..KANNADA LETTER NA\n0CAA..0CB0    ; Recommended                    # 1.1    [7] KANNADA LETTER PA..KANNADA LETTER RA\n0CB2..0CB3    ; Recommended                    # 1.1    [2] KANNADA LETTER LA..KANNADA LETTER LLA\n0CB5..0CB9    ; Recommended                    # 1.1    [5] KANNADA LETTER VA..KANNADA LETTER HA\n0CBE..0CC3    ; Recommended                    # 1.1    [6] KANNADA VOWEL SIGN AA..KANNADA VOWEL SIGN VOCALIC R\n0CC6..0CC8    ; Recommended                    # 1.1    [3] KANNADA VOWEL SIGN E..KANNADA VOWEL SIGN AI\n0CCA..0CCD    ; Recommended                    # 1.1    [4] KANNADA VOWEL SIGN O..KANNADA SIGN VIRAMA\n0CE6..0CEF    ; Recommended                    # 1.1   [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE\n0D02..0D03    ; Recommended                    # 1.1    [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA\n0D05..0D0B    ; Recommended                    # 1.1    [7] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC R\n0D0E..0D10    ; Recommended                    # 1.1    [3] MALAYALAM LETTER E..MALAYALAM LETTER AI\n0D12..0D28    ; Recommended                    # 1.1   [23] MALAYALAM LETTER O..MALAYALAM LETTER NA\n0D2A..0D39    ; Recommended                    # 1.1   [16] MALAYALAM LETTER PA..MALAYALAM LETTER HA\n0D3E..0D43    ; Recommended                    # 1.1    [6] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN VOCALIC R\n0D46..0D48    ; Recommended                    # 1.1    [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI\n0D4A..0D4B    ; Recommended                    # 1.1    [2] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN OO\n0D4D          ; Recommended                    # 1.1        MALAYALAM SIGN VIRAMA\n0D57          ; Recommended                    # 1.1        MALAYALAM AU LENGTH MARK\n0D7A..0D7F    ; Recommended                    # 5.1    [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K\n0D82..0D83    ; Recommended                    # 3.0    [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA\n0D85..0D8D    ; Recommended                    # 3.0    [9] SINHALA LETTER AYANNA..SINHALA LETTER IRUYANNA\n0D91..0D96    ; Recommended                    # 3.0    [6] SINHALA LETTER EYANNA..SINHALA LETTER AUYANNA\n0D9A..0D9D    ; Recommended                    # 3.0    [4] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER MAHAAPRAANA GAYANNA\n0D9F..0DB1    ; Recommended                    # 3.0   [19] SINHALA LETTER SANYAKA GAYANNA..SINHALA LETTER DANTAJA NAYANNA\n0DB3..0DBB    ; Recommended                    # 3.0    [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA\n0DBD          ; Recommended                    # 3.0        SINHALA LETTER DANTAJA LAYANNA\n0DC0..0DC6    ; Recommended                    # 3.0    [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA\n0DCA          ; Recommended                    # 3.0        SINHALA SIGN AL-LAKUNA\n0DCF..0DD4    ; Recommended                    # 3.0    [6] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA\n0DD6          ; Recommended                    # 3.0        SINHALA VOWEL SIGN DIGA PAA-PILLA\n0DD8..0DDE    ; Recommended                    # 3.0    [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA\n0DF2          ; Recommended                    # 3.0        SINHALA VOWEL SIGN DIGA GAETTA-PILLA\n0E01..0E32    ; Recommended                    # 1.1   [50] THAI CHARACTER KO KAI..THAI CHARACTER SARA AA\n0E34..0E3A    ; Recommended                    # 1.1    [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU\n0E40..0E4D    ; Recommended                    # 1.1   [14] THAI CHARACTER SARA E..THAI CHARACTER NIKHAHIT\n0E50..0E59    ; Recommended                    # 1.1   [10] THAI DIGIT ZERO..THAI DIGIT NINE\n0E81..0E82    ; Recommended                    # 1.1    [2] LAO LETTER KO..LAO LETTER KHO SUNG\n0E84          ; Recommended                    # 1.1        LAO LETTER KHO TAM\n0E87..0E88    ; Recommended                    # 1.1    [2] LAO LETTER NGO..LAO LETTER CO\n0E8A          ; Recommended                    # 1.1        LAO LETTER SO TAM\n0E8D          ; Recommended                    # 1.1        LAO LETTER NYO\n0E94..0E97    ; Recommended                    # 1.1    [4] LAO LETTER DO..LAO LETTER THO TAM\n0E99..0E9F    ; Recommended                    # 1.1    [7] LAO LETTER NO..LAO LETTER FO SUNG\n0EA1..0EA3    ; Recommended                    # 1.1    [3] LAO LETTER MO..LAO LETTER LO LING\n0EA5          ; Recommended                    # 1.1        LAO LETTER LO LOOT\n0EA7          ; Recommended                    # 1.1        LAO LETTER WO\n0EAA..0EAB    ; Recommended                    # 1.1    [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG\n0EAD..0EAE    ; Recommended                    # 1.1    [2] LAO LETTER O..LAO LETTER HO TAM\n0EB0..0EB2    ; Recommended                    # 1.1    [3] LAO VOWEL SIGN A..LAO VOWEL SIGN AA\n0EB4..0EB9    ; Recommended                    # 1.1    [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU\n0EBB..0EBD    ; Recommended                    # 1.1    [3] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN NYO\n0EC0..0EC4    ; Recommended                    # 1.1    [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI\n0EC6          ; Recommended                    # 1.1        LAO KO LA\n0EC8..0ECD    ; Recommended                    # 1.1    [6] LAO TONE MAI EK..LAO NIGGAHITA\n0ED0..0ED9    ; Recommended                    # 1.1   [10] LAO DIGIT ZERO..LAO DIGIT NINE\n0F20..0F29    ; Recommended                    # 2.0   [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE\n0F40..0F42    ; Recommended                    # 2.0    [3] TIBETAN LETTER KA..TIBETAN LETTER GA\n0F44..0F47    ; Recommended                    # 2.0    [4] TIBETAN LETTER NGA..TIBETAN LETTER JA\n0F49..0F4C    ; Recommended                    # 2.0    [4] TIBETAN LETTER NYA..TIBETAN LETTER DDA\n0F4E..0F51    ; Recommended                    # 2.0    [4] TIBETAN LETTER NNA..TIBETAN LETTER DA\n0F53..0F56    ; Recommended                    # 2.0    [4] TIBETAN LETTER NA..TIBETAN LETTER BA\n0F58..0F5B    ; Recommended                    # 2.0    [4] TIBETAN LETTER MA..TIBETAN LETTER DZA\n0F5D..0F68    ; Recommended                    # 2.0   [12] TIBETAN LETTER WA..TIBETAN LETTER A\n0F71..0F72    ; Recommended                    # 2.0    [2] TIBETAN VOWEL SIGN AA..TIBETAN VOWEL SIGN I\n0F74          ; Recommended                    # 2.0        TIBETAN VOWEL SIGN U\n0F7A..0F80    ; Recommended                    # 2.0    [7] TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN REVERSED I\n0F84          ; Recommended                    # 2.0        TIBETAN MARK HALANTA\n0F90..0F92    ; Recommended                    # 2.0    [3] TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER GA\n0F94..0F95    ; Recommended                    # 2.0    [2] TIBETAN SUBJOINED LETTER NGA..TIBETAN SUBJOINED LETTER CA\n0F96          ; Recommended                    # 3.0        TIBETAN SUBJOINED LETTER CHA\n0F97          ; Recommended                    # 2.0        TIBETAN SUBJOINED LETTER JA\n0F99..0F9C    ; Recommended                    # 2.0    [4] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER DDA\n0F9E..0FA1    ; Recommended                    # 2.0    [4] TIBETAN SUBJOINED LETTER NNA..TIBETAN SUBJOINED LETTER DA\n0FA3..0FA6    ; Recommended                    # 2.0    [4] TIBETAN SUBJOINED LETTER NA..TIBETAN SUBJOINED LETTER BA\n0FA8..0FAB    ; Recommended                    # 2.0    [4] TIBETAN SUBJOINED LETTER MA..TIBETAN SUBJOINED LETTER DZA\n0FAD          ; Recommended                    # 2.0        TIBETAN SUBJOINED LETTER WA\n0FB1..0FB7    ; Recommended                    # 2.0    [7] TIBETAN SUBJOINED LETTER YA..TIBETAN SUBJOINED LETTER HA\n0FB8          ; Recommended                    # 3.0        TIBETAN SUBJOINED LETTER A\n0FBA..0FBC    ; Recommended                    # 3.0    [3] TIBETAN SUBJOINED LETTER FIXED-FORM WA..TIBETAN SUBJOINED LETTER FIXED-FORM RA\n1000..1021    ; Recommended                    # 3.0   [34] MYANMAR LETTER KA..MYANMAR LETTER A\n1022          ; Recommended                    # 5.1        MYANMAR LETTER SHAN A\n1023..1027    ; Recommended                    # 3.0    [5] MYANMAR LETTER I..MYANMAR LETTER E\n1028          ; Recommended                    # 5.1        MYANMAR LETTER MON E\n1029..102A    ; Recommended                    # 3.0    [2] MYANMAR LETTER O..MYANMAR LETTER AU\n102B          ; Recommended                    # 5.1        MYANMAR VOWEL SIGN TALL AA\n102C..1032    ; Recommended                    # 3.0    [7] MYANMAR VOWEL SIGN AA..MYANMAR VOWEL SIGN AI\n1033..1035    ; Recommended                    # 5.1    [3] MYANMAR VOWEL SIGN MON II..MYANMAR VOWEL SIGN E ABOVE\n1036..1039    ; Recommended                    # 3.0    [4] MYANMAR SIGN ANUSVARA..MYANMAR SIGN VIRAMA\n103A..103F    ; Recommended                    # 5.1    [6] MYANMAR SIGN ASAT..MYANMAR LETTER GREAT SA\n1040..1049    ; Recommended                    # 3.0   [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE\n105A..1064    ; Recommended                    # 5.1   [11] MYANMAR LETTER MON NGA..MYANMAR TONE MARK SGAW KAREN KE PHO\n1075..108A    ; Recommended                    # 5.1   [22] MYANMAR LETTER SHAN KA..MYANMAR SIGN SHAN TONE-6\n108F          ; Recommended                    # 5.1        MYANMAR SIGN RUMAI PALAUNG TONE-5\n10C7          ; Recommended                    # 6.1        GEORGIAN CAPITAL LETTER YN\n10CD          ; Recommended                    # 6.1        GEORGIAN CAPITAL LETTER AEN\n10D0..10F0    ; Recommended                    # 1.1   [33] GEORGIAN LETTER AN..GEORGIAN LETTER HAE\n1200..1206    ; Recommended                    # 3.0    [7] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE HO\n1208..1246    ; Recommended                    # 3.0   [63] ETHIOPIC SYLLABLE LA..ETHIOPIC SYLLABLE QO\n1247          ; Recommended                    # 4.1        ETHIOPIC SYLLABLE QOA\n1248          ; Recommended                    # 3.0        ETHIOPIC SYLLABLE QWA\n124A..124D    ; Recommended                    # 3.0    [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE\n1250..1256    ; Recommended                    # 3.0    [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO\n1258          ; Recommended                    # 3.0        ETHIOPIC SYLLABLE QHWA\n125A..125D    ; Recommended                    # 3.0    [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE\n1260..1286    ; Recommended                    # 3.0   [39] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XO\n1288          ; Recommended                    # 3.0        ETHIOPIC SYLLABLE XWA\n128A..128D    ; Recommended                    # 3.0    [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE\n1290..12AE    ; Recommended                    # 3.0   [31] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KO\n12B0          ; Recommended                    # 3.0        ETHIOPIC SYLLABLE KWA\n12B2..12B5    ; Recommended                    # 3.0    [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE\n12B8..12BE    ; Recommended                    # 3.0    [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO\n12C0          ; Recommended                    # 3.0        ETHIOPIC SYLLABLE KXWA\n12C2..12C5    ; Recommended                    # 3.0    [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE\n12C8..12CE    ; Recommended                    # 3.0    [7] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE WO\n12CF          ; Recommended                    # 4.1        ETHIOPIC SYLLABLE WOA\n12D0..12D6    ; Recommended                    # 3.0    [7] ETHIOPIC SYLLABLE PHARYNGEAL A..ETHIOPIC SYLLABLE PHARYNGEAL O\n12D8..12EE    ; Recommended                    # 3.0   [23] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE YO\n12EF          ; Recommended                    # 4.1        ETHIOPIC SYLLABLE YOA\n12F0..12F7    ; Recommended                    # 3.0    [8] ETHIOPIC SYLLABLE DA..ETHIOPIC SYLLABLE DWA\n1300..130E    ; Recommended                    # 3.0   [15] ETHIOPIC SYLLABLE JA..ETHIOPIC SYLLABLE GO\n1310          ; Recommended                    # 3.0        ETHIOPIC SYLLABLE GWA\n1312..1315    ; Recommended                    # 3.0    [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE\n1318..131E    ; Recommended                    # 3.0    [7] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE GGO\n1320..1346    ; Recommended                    # 3.0   [39] ETHIOPIC SYLLABLE THA..ETHIOPIC SYLLABLE TZO\n1348..1359    ; Recommended                    # 3.0   [18] ETHIOPIC SYLLABLE FA..ETHIOPIC SYLLABLE MYA\n1780..179C    ; Recommended                    # 3.0   [29] KHMER LETTER KA..KHMER LETTER VO\n179F..17A2    ; Recommended                    # 3.0    [4] KHMER LETTER SA..KHMER LETTER QA\n17A5..17A7    ; Recommended                    # 3.0    [3] KHMER INDEPENDENT VOWEL QI..KHMER INDEPENDENT VOWEL QU\n17AA..17B3    ; Recommended                    # 3.0   [10] KHMER INDEPENDENT VOWEL QUUV..KHMER INDEPENDENT VOWEL QAU\n17B6..17CD    ; Recommended                    # 3.0   [24] KHMER VOWEL SIGN AA..KHMER SIGN TOANDAKHIAT\n17D0          ; Recommended                    # 3.0        KHMER SIGN SAMYOK SANNYA\n17D2          ; Recommended                    # 3.0        KHMER SIGN COENG\n17E0..17E9    ; Recommended                    # 3.0   [10] KHMER DIGIT ZERO..KHMER DIGIT NINE\n1C90..1CBA    ; Recommended                    # 11.0  [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN\n1CBD..1CBF    ; Recommended                    # 11.0   [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN\n1E0C..1E0D    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER D WITH DOT BELOW..LATIN SMALL LETTER D WITH DOT BELOW\n1E12..1E13    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW..LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW\n1E20..1E21    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER G WITH MACRON..LATIN SMALL LETTER G WITH MACRON\n1E24..1E25    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER H WITH DOT BELOW..LATIN SMALL LETTER H WITH DOT BELOW\n1E36..1E37    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER L WITH DOT BELOW..LATIN SMALL LETTER L WITH DOT BELOW\n1E3C..1E3F    ; Recommended                    # 1.1    [4] LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW..LATIN SMALL LETTER M WITH ACUTE\n1E42..1E4B    ; Recommended                    # 1.1   [10] LATIN CAPITAL LETTER M WITH DOT BELOW..LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW\n1E5A..1E5B    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER R WITH DOT BELOW..LATIN SMALL LETTER R WITH DOT BELOW\n1E62..1E63    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER S WITH DOT BELOW..LATIN SMALL LETTER S WITH DOT BELOW\n1E6C..1E6D    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER T WITH DOT BELOW..LATIN SMALL LETTER T WITH DOT BELOW\n1E70..1E71    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW..LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW\n1E8C..1E8D    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER X WITH DIAERESIS..LATIN SMALL LETTER X WITH DIAERESIS\n1E92..1E93    ; Recommended                    # 1.1    [2] LATIN CAPITAL LETTER Z WITH DOT BELOW..LATIN SMALL LETTER Z WITH DOT BELOW\n1E9E          ; Recommended                    # 5.1        LATIN CAPITAL LETTER SHARP S\n1EA0..1EF9    ; Recommended                    # 1.1   [90] LATIN CAPITAL LETTER A WITH DOT BELOW..LATIN SMALL LETTER Y WITH TILDE\n1FA0..1FAF    ; Recommended                    # 1.1   [16] GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI..GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n1FB2..1FB4    ; Recommended                    # 1.1    [3] GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI\n1FEC          ; Recommended                    # 1.1        GREEK CAPITAL LETTER RHO WITH DASIA\n3005..3007    ; Recommended                    # 1.1    [3] IDEOGRAPHIC ITERATION MARK..IDEOGRAPHIC NUMBER ZERO\n3041..3094    ; Recommended                    # 1.1   [84] HIRAGANA LETTER SMALL A..HIRAGANA LETTER VU\n3095..3096    ; Recommended                    # 3.2    [2] HIRAGANA LETTER SMALL KA..HIRAGANA LETTER SMALL KE\n309D..309E    ; Recommended                    # 1.1    [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK\n30A1..30FA    ; Recommended                    # 1.1   [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO\n30FC..30FE    ; Recommended                    # 1.1    [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK\n3447          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3447\n3473          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3473\n34E4          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-34E4\n3577          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3577\n359E          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-359E\n35A1          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-35A1\n35AD          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-35AD\n35BF          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-35BF\n35CE          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-35CE\n35F3          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-35F3\n35FE          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-35FE\n360E          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-360E\n361A          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-361A\n3918          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3918\n3960          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3960\n396E          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-396E\n39CF..39D0    ; Recommended                    # 3.0    [2] CJK UNIFIED IDEOGRAPH-39CF..CJK UNIFIED IDEOGRAPH-39D0\n39DB          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-39DB\n39DF          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-39DF\n39F8          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-39F8\n39FE          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-39FE\n3A18          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3A18\n3A52          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3A52\n3A5C          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3A5C\n3A67          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3A67\n3A73          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3A73\n3B39          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3B39\n3B4E          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3B4E\n3BA3          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3BA3\n3C6E          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3C6E\n3CE0          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3CE0\n3DE7          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3DE7\n3DEB          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3DEB\n3E74          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3E74\n3ED0          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-3ED0\n4056          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4056\n4065          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4065\n406A          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-406A\n40BB          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-40BB\n40DF          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-40DF\n4137          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4137\n415F          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-415F\n4337          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4337\n43AC          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-43AC\n43B1          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-43B1\n43D3          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-43D3\n43DD          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-43DD\n4443          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4443\n44D6          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-44D6\n44EA          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-44EA\n4606          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4606\n464C          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-464C\n4661          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4661\n4723          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4723\n4729          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4729\n477C          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-477C\n478D          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-478D\n47F4          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-47F4\n4882          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4882\n4947          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4947\n497A          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-497A\n497D          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-497D\n4982..4983    ; Recommended                    # 3.0    [2] CJK UNIFIED IDEOGRAPH-4982..CJK UNIFIED IDEOGRAPH-4983\n4985..4986    ; Recommended                    # 3.0    [2] CJK UNIFIED IDEOGRAPH-4985..CJK UNIFIED IDEOGRAPH-4986\n499B          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-499B\n499F          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-499F\n49B6..49B7    ; Recommended                    # 3.0    [2] CJK UNIFIED IDEOGRAPH-49B6..CJK UNIFIED IDEOGRAPH-49B7\n4A12          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4A12\n4AB8          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4AB8\n4C77          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4C77\n4C7D          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4C7D\n4C81          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4C81\n4C85          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4C85\n4C9D..4CA3    ; Recommended                    # 3.0    [7] CJK UNIFIED IDEOGRAPH-4C9D..CJK UNIFIED IDEOGRAPH-4CA3\n4D13..4D19    ; Recommended                    # 3.0    [7] CJK UNIFIED IDEOGRAPH-4D13..CJK UNIFIED IDEOGRAPH-4D19\n4DAE          ; Recommended                    # 3.0        CJK UNIFIED IDEOGRAPH-4DAE\n4E00..4E11    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-4E11\n4E13..4E28    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-4E13..CJK UNIFIED IDEOGRAPH-4E28\n4E2A..4E67    ; Recommended                    # 1.1   [62] CJK UNIFIED IDEOGRAPH-4E2A..CJK UNIFIED IDEOGRAPH-4E67\n4E69..4E78    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-4E69..CJK UNIFIED IDEOGRAPH-4E78\n4E7A..4E95    ; Recommended                    # 1.1   [28] CJK UNIFIED IDEOGRAPH-4E7A..CJK UNIFIED IDEOGRAPH-4E95\n4E97..4EA2    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-4E97..CJK UNIFIED IDEOGRAPH-4EA2\n4EA4..4EBB    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-4EA4..CJK UNIFIED IDEOGRAPH-4EBB\n4EBD..4ECB    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-4EBD..CJK UNIFIED IDEOGRAPH-4ECB\n4ECD..4EE6    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-4ECD..CJK UNIFIED IDEOGRAPH-4EE6\n4EE8..4EF7    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-4EE8..CJK UNIFIED IDEOGRAPH-4EF7\n4EFB          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-4EFB\n4EFD          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-4EFD\n4EFF..4F06    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-4EFF..CJK UNIFIED IDEOGRAPH-4F06\n4F08..4F15    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-4F08..CJK UNIFIED IDEOGRAPH-4F15\n4F17..4F27    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-4F17..CJK UNIFIED IDEOGRAPH-4F27\n4F29..4F30    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-4F29..CJK UNIFIED IDEOGRAPH-4F30\n4F32..4F34    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-4F32..CJK UNIFIED IDEOGRAPH-4F34\n4F36          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-4F36\n4F38..4F3F    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-4F38..CJK UNIFIED IDEOGRAPH-4F3F\n4F41..4F43    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-4F41..CJK UNIFIED IDEOGRAPH-4F43\n4F45..4F70    ; Recommended                    # 1.1   [44] CJK UNIFIED IDEOGRAPH-4F45..CJK UNIFIED IDEOGRAPH-4F70\n4F72..4F8B    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-4F72..CJK UNIFIED IDEOGRAPH-4F8B\n4F8D          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-4F8D\n4F8F..4FA1    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-4F8F..CJK UNIFIED IDEOGRAPH-4FA1\n4FA3..4FBC    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-4FA3..CJK UNIFIED IDEOGRAPH-4FBC\n4FBE..4FC5    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-4FBE..CJK UNIFIED IDEOGRAPH-4FC5\n4FC7          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-4FC7\n4FC9..4FCB    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-4FC9..CJK UNIFIED IDEOGRAPH-4FCB\n4FCD..4FE1    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-4FCD..CJK UNIFIED IDEOGRAPH-4FE1\n4FE3..4FFB    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-4FE3..CJK UNIFIED IDEOGRAPH-4FFB\n4FFE..500F    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-4FFE..CJK UNIFIED IDEOGRAPH-500F\n5011..5033    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-5011..CJK UNIFIED IDEOGRAPH-5033\n5035..5037    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-5035..CJK UNIFIED IDEOGRAPH-5037\n5039..503C    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5039..CJK UNIFIED IDEOGRAPH-503C\n503E..5041    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-503E..CJK UNIFIED IDEOGRAPH-5041\n5043..5051    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-5043..CJK UNIFIED IDEOGRAPH-5051\n5053..5057    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5053..CJK UNIFIED IDEOGRAPH-5057\n5059..507B    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-5059..CJK UNIFIED IDEOGRAPH-507B\n507D..5080    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-507D..CJK UNIFIED IDEOGRAPH-5080\n5082..5092    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-5082..CJK UNIFIED IDEOGRAPH-5092\n5094..5096    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-5094..CJK UNIFIED IDEOGRAPH-5096\n5098..509E    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5098..CJK UNIFIED IDEOGRAPH-509E\n50A2..50B8    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-50A2..CJK UNIFIED IDEOGRAPH-50B8\n50BA..50C2    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-50BA..CJK UNIFIED IDEOGRAPH-50C2\n50C4..50D7    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-50C4..CJK UNIFIED IDEOGRAPH-50D7\n50D9..50DE    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-50D9..CJK UNIFIED IDEOGRAPH-50DE\n50E0          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-50E0\n50E3..50EA    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-50E3..CJK UNIFIED IDEOGRAPH-50EA\n50EC..50F3    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-50EC..CJK UNIFIED IDEOGRAPH-50F3\n50F5..50F6    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-50F5..CJK UNIFIED IDEOGRAPH-50F6\n50F8..511A    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-50F8..CJK UNIFIED IDEOGRAPH-511A\n511C..5127    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-511C..CJK UNIFIED IDEOGRAPH-5127\n5129..512A    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5129..CJK UNIFIED IDEOGRAPH-512A\n512C..5141    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-512C..CJK UNIFIED IDEOGRAPH-5141\n5143..5149    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5143..CJK UNIFIED IDEOGRAPH-5149\n514B..514E    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-514B..CJK UNIFIED IDEOGRAPH-514E\n5150..5152    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-5150..CJK UNIFIED IDEOGRAPH-5152\n5154..5157    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5154..CJK UNIFIED IDEOGRAPH-5157\n5159..515F    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5159..CJK UNIFIED IDEOGRAPH-515F\n5161..5163    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-5161..CJK UNIFIED IDEOGRAPH-5163\n5165..5171    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-5165..CJK UNIFIED IDEOGRAPH-5171\n5173..517D    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-5173..CJK UNIFIED IDEOGRAPH-517D\n517F..5182    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-517F..CJK UNIFIED IDEOGRAPH-5182\n5185..518D    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-5185..CJK UNIFIED IDEOGRAPH-518D\n518F..51A0    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-518F..CJK UNIFIED IDEOGRAPH-51A0\n51A2          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-51A2\n51A4..51AC    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-51A4..CJK UNIFIED IDEOGRAPH-51AC\n51AE..51B7    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-51AE..CJK UNIFIED IDEOGRAPH-51B7\n51B9          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-51B9\n51BB..51C1    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-51BB..CJK UNIFIED IDEOGRAPH-51C1\n51C3..51D1    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-51C3..CJK UNIFIED IDEOGRAPH-51D1\n51D4..51DE    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-51D4..CJK UNIFIED IDEOGRAPH-51DE\n51E0..51EB    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-51E0..CJK UNIFIED IDEOGRAPH-51EB\n51ED          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-51ED\n51EF..51F1    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-51EF..CJK UNIFIED IDEOGRAPH-51F1\n51F3..5252    ; Recommended                    # 1.1   [96] CJK UNIFIED IDEOGRAPH-51F3..CJK UNIFIED IDEOGRAPH-5252\n5254..5265    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-5254..CJK UNIFIED IDEOGRAPH-5265\n5267..5278    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-5267..CJK UNIFIED IDEOGRAPH-5278\n527A..5284    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-527A..CJK UNIFIED IDEOGRAPH-5284\n5286..528D    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5286..CJK UNIFIED IDEOGRAPH-528D\n528F..52C3    ; Recommended                    # 1.1   [53] CJK UNIFIED IDEOGRAPH-528F..CJK UNIFIED IDEOGRAPH-52C3\n52C5..52C7    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-52C5..CJK UNIFIED IDEOGRAPH-52C7\n52C9..52CB    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-52C9..CJK UNIFIED IDEOGRAPH-52CB\n52CD          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-52CD\n52CF..52D0    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-52CF..CJK UNIFIED IDEOGRAPH-52D0\n52D2..52D3    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-52D2..CJK UNIFIED IDEOGRAPH-52D3\n52D5..52E0    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-52D5..CJK UNIFIED IDEOGRAPH-52E0\n52E2..52E4    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-52E2..CJK UNIFIED IDEOGRAPH-52E4\n52E6..52ED    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-52E6..CJK UNIFIED IDEOGRAPH-52ED\n52EF..5302    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-52EF..CJK UNIFIED IDEOGRAPH-5302\n5305..5317    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-5305..CJK UNIFIED IDEOGRAPH-5317\n5319..531A    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5319..CJK UNIFIED IDEOGRAPH-531A\n531C..531D    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-531C..CJK UNIFIED IDEOGRAPH-531D\n531F..5326    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-531F..CJK UNIFIED IDEOGRAPH-5326\n5328          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-5328\n532A..5331    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-532A..CJK UNIFIED IDEOGRAPH-5331\n5333..5334    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5333..CJK UNIFIED IDEOGRAPH-5334\n5337..5341    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-5337..CJK UNIFIED IDEOGRAPH-5341\n5343..535A    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-5343..CJK UNIFIED IDEOGRAPH-535A\n535C          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-535C\n535E..5369    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-535E..CJK UNIFIED IDEOGRAPH-5369\n536B..536C    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-536B..CJK UNIFIED IDEOGRAPH-536C\n536E..537F    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-536E..CJK UNIFIED IDEOGRAPH-537F\n5381..53A0    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-5381..CJK UNIFIED IDEOGRAPH-53A0\n53A2..53A9    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-53A2..CJK UNIFIED IDEOGRAPH-53A9\n53AC..53AE    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-53AC..CJK UNIFIED IDEOGRAPH-53AE\n53B0..53B9    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-53B0..CJK UNIFIED IDEOGRAPH-53B9\n53BB..53C4    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-53BB..CJK UNIFIED IDEOGRAPH-53C4\n53C6..53CE    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-53C6..CJK UNIFIED IDEOGRAPH-53CE\n53D0..53DC    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-53D0..CJK UNIFIED IDEOGRAPH-53DC\n53DF..53E6    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-53DF..CJK UNIFIED IDEOGRAPH-53E6\n53E8..53FE    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-53E8..CJK UNIFIED IDEOGRAPH-53FE\n5401..5419    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-5401..CJK UNIFIED IDEOGRAPH-5419\n541B..5421    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-541B..CJK UNIFIED IDEOGRAPH-5421\n5423..544B    ; Recommended                    # 1.1   [41] CJK UNIFIED IDEOGRAPH-5423..CJK UNIFIED IDEOGRAPH-544B\n544D..545C    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-544D..CJK UNIFIED IDEOGRAPH-545C\n545E..5468    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-545E..CJK UNIFIED IDEOGRAPH-5468\n546A..5489    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-546A..CJK UNIFIED IDEOGRAPH-5489\n548B..54B4    ; Recommended                    # 1.1   [42] CJK UNIFIED IDEOGRAPH-548B..CJK UNIFIED IDEOGRAPH-54B4\n54B6..54F5    ; Recommended                    # 1.1   [64] CJK UNIFIED IDEOGRAPH-54B6..CJK UNIFIED IDEOGRAPH-54F5\n54F7..5514    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-54F7..CJK UNIFIED IDEOGRAPH-5514\n5516..5517    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5516..CJK UNIFIED IDEOGRAPH-5517\n551A..5546    ; Recommended                    # 1.1   [45] CJK UNIFIED IDEOGRAPH-551A..CJK UNIFIED IDEOGRAPH-5546\n5548..555F    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-5548..CJK UNIFIED IDEOGRAPH-555F\n5561..5579    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-5561..CJK UNIFIED IDEOGRAPH-5579\n557B..55DF    ; Recommended                    # 1.1  [101] CJK UNIFIED IDEOGRAPH-557B..CJK UNIFIED IDEOGRAPH-55DF\n55E1..55F7    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-55E1..CJK UNIFIED IDEOGRAPH-55F7\n55F9..5609    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-55F9..CJK UNIFIED IDEOGRAPH-5609\n560C..561F    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-560C..CJK UNIFIED IDEOGRAPH-561F\n5621..562A    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-5621..CJK UNIFIED IDEOGRAPH-562A\n562C..5636    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-562C..CJK UNIFIED IDEOGRAPH-5636\n5638..563B    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5638..CJK UNIFIED IDEOGRAPH-563B\n563D..5643    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-563D..CJK UNIFIED IDEOGRAPH-5643\n5645..564A    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-5645..CJK UNIFIED IDEOGRAPH-564A\n564C..5650    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-564C..CJK UNIFIED IDEOGRAPH-5650\n5652..5655    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5652..CJK UNIFIED IDEOGRAPH-5655\n5657..565E    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5657..CJK UNIFIED IDEOGRAPH-565E\n5660          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-5660\n5662..5674    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-5662..CJK UNIFIED IDEOGRAPH-5674\n5676..567C    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5676..CJK UNIFIED IDEOGRAPH-567C\n567E..5687    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-567E..CJK UNIFIED IDEOGRAPH-5687\n5689..568A    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5689..CJK UNIFIED IDEOGRAPH-568A\n568C..5695    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-568C..CJK UNIFIED IDEOGRAPH-5695\n5697..569D    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5697..CJK UNIFIED IDEOGRAPH-569D\n569F..56B9    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-569F..CJK UNIFIED IDEOGRAPH-56B9\n56BB..56CE    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-56BB..CJK UNIFIED IDEOGRAPH-56CE\n56D0..56D8    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-56D0..CJK UNIFIED IDEOGRAPH-56D8\n56DA..56E5    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-56DA..CJK UNIFIED IDEOGRAPH-56E5\n56E7..56F5    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-56E7..CJK UNIFIED IDEOGRAPH-56F5\n56F7          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-56F7\n56F9..56FA    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-56F9..CJK UNIFIED IDEOGRAPH-56FA\n56FD..5704    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-56FD..CJK UNIFIED IDEOGRAPH-5704\n5706..5710    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-5706..CJK UNIFIED IDEOGRAPH-5710\n5712..5716    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5712..CJK UNIFIED IDEOGRAPH-5716\n5718..5720    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-5718..CJK UNIFIED IDEOGRAPH-5720\n5722..5723    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5722..CJK UNIFIED IDEOGRAPH-5723\n5725..573C    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-5725..CJK UNIFIED IDEOGRAPH-573C\n573E..5742    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-573E..CJK UNIFIED IDEOGRAPH-5742\n5744..5747    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5744..CJK UNIFIED IDEOGRAPH-5747\n5749..5754    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-5749..CJK UNIFIED IDEOGRAPH-5754\n5757          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-5757\n5759..5762    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-5759..CJK UNIFIED IDEOGRAPH-5762\n5764..5777    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-5764..CJK UNIFIED IDEOGRAPH-5777\n5779..5780    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5779..CJK UNIFIED IDEOGRAPH-5780\n5782..5786    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5782..CJK UNIFIED IDEOGRAPH-5786\n5788..5795    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-5788..CJK UNIFIED IDEOGRAPH-5795\n5797..57A7    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-5797..CJK UNIFIED IDEOGRAPH-57A7\n57A9..57C9    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-57A9..CJK UNIFIED IDEOGRAPH-57C9\n57CB..57D0    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-57CB..CJK UNIFIED IDEOGRAPH-57D0\n57D2..57DA    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-57D2..CJK UNIFIED IDEOGRAPH-57DA\n57DC..5816    ; Recommended                    # 1.1   [59] CJK UNIFIED IDEOGRAPH-57DC..CJK UNIFIED IDEOGRAPH-5816\n5819..584F    ; Recommended                    # 1.1   [55] CJK UNIFIED IDEOGRAPH-5819..CJK UNIFIED IDEOGRAPH-584F\n5851..5855    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5851..CJK UNIFIED IDEOGRAPH-5855\n5857..585F    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-5857..CJK UNIFIED IDEOGRAPH-585F\n5861..5865    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5861..CJK UNIFIED IDEOGRAPH-5865\n5868..5876    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-5868..CJK UNIFIED IDEOGRAPH-5876\n5878..5894    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-5878..CJK UNIFIED IDEOGRAPH-5894\n5896..58A9    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-5896..CJK UNIFIED IDEOGRAPH-58A9\n58AB..58B5    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-58AB..CJK UNIFIED IDEOGRAPH-58B5\n58B7..58BF    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-58B7..CJK UNIFIED IDEOGRAPH-58BF\n58C1..58C2    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-58C1..CJK UNIFIED IDEOGRAPH-58C2\n58C5..58CC    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-58C5..CJK UNIFIED IDEOGRAPH-58CC\n58CE..58CF    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-58CE..CJK UNIFIED IDEOGRAPH-58CF\n58D1..58E0    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-58D1..CJK UNIFIED IDEOGRAPH-58E0\n58E2..58E5    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-58E2..CJK UNIFIED IDEOGRAPH-58E5\n58E7..58F4    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-58E7..CJK UNIFIED IDEOGRAPH-58F4\n58F6..5900    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-58F6..CJK UNIFIED IDEOGRAPH-5900\n5902..5904    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-5902..CJK UNIFIED IDEOGRAPH-5904\n5906..5907    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5906..CJK UNIFIED IDEOGRAPH-5907\n5909..5910    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5909..CJK UNIFIED IDEOGRAPH-5910\n5912          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-5912\n5914..5922    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-5914..CJK UNIFIED IDEOGRAPH-5922\n5924..5932    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-5924..CJK UNIFIED IDEOGRAPH-5932\n5934..5935    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5934..CJK UNIFIED IDEOGRAPH-5935\n5937..5958    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-5937..CJK UNIFIED IDEOGRAPH-5958\n595A          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-595A\n595C..59B6    ; Recommended                    # 1.1   [91] CJK UNIFIED IDEOGRAPH-595C..CJK UNIFIED IDEOGRAPH-59B6\n59B8..59E6    ; Recommended                    # 1.1   [47] CJK UNIFIED IDEOGRAPH-59B8..CJK UNIFIED IDEOGRAPH-59E6\n59E8..5A23    ; Recommended                    # 1.1   [60] CJK UNIFIED IDEOGRAPH-59E8..CJK UNIFIED IDEOGRAPH-5A23\n5A25          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-5A25\n5A27..5A2B    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5A27..CJK UNIFIED IDEOGRAPH-5A2B\n5A2D..5A2F    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-5A2D..CJK UNIFIED IDEOGRAPH-5A2F\n5A31..5A53    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-5A31..CJK UNIFIED IDEOGRAPH-5A53\n5A55..5A58    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5A55..CJK UNIFIED IDEOGRAPH-5A58\n5A5A..5A6E    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-5A5A..CJK UNIFIED IDEOGRAPH-5A6E\n5A70          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-5A70\n5A72..5A86    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-5A72..CJK UNIFIED IDEOGRAPH-5A86\n5A88..5A8C    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5A88..CJK UNIFIED IDEOGRAPH-5A8C\n5A8E..5AAA    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-5A8E..CJK UNIFIED IDEOGRAPH-5AAA\n5AAC..5AD2    ; Recommended                    # 1.1   [39] CJK UNIFIED IDEOGRAPH-5AAC..CJK UNIFIED IDEOGRAPH-5AD2\n5AD4..5AEE    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-5AD4..CJK UNIFIED IDEOGRAPH-5AEE\n5AF1..5B09    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-5AF1..CJK UNIFIED IDEOGRAPH-5B09\n5B0B..5B0C    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5B0B..CJK UNIFIED IDEOGRAPH-5B0C\n5B0E..5B38    ; Recommended                    # 1.1   [43] CJK UNIFIED IDEOGRAPH-5B0E..CJK UNIFIED IDEOGRAPH-5B38\n5B3A..5B45    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-5B3A..CJK UNIFIED IDEOGRAPH-5B45\n5B47..5B4E    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5B47..CJK UNIFIED IDEOGRAPH-5B4E\n5B50..5B51    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5B50..CJK UNIFIED IDEOGRAPH-5B51\n5B53..5B5F    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-5B53..CJK UNIFIED IDEOGRAPH-5B5F\n5B62..5B6E    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-5B62..CJK UNIFIED IDEOGRAPH-5B6E\n5B70..5B78    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-5B70..CJK UNIFIED IDEOGRAPH-5B78\n5B7A..5B7D    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5B7A..CJK UNIFIED IDEOGRAPH-5B7D\n5B7F..5B85    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5B7F..CJK UNIFIED IDEOGRAPH-5B85\n5B87..5B8F    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-5B87..CJK UNIFIED IDEOGRAPH-5B8F\n5B91..5BA8    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-5B91..CJK UNIFIED IDEOGRAPH-5BA8\n5BAA..5BB1    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5BAA..CJK UNIFIED IDEOGRAPH-5BB1\n5BB3..5BB6    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5BB3..CJK UNIFIED IDEOGRAPH-5BB6\n5BB8..5BBB    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5BB8..CJK UNIFIED IDEOGRAPH-5BBB\n5BBD..5BC7    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-5BBD..CJK UNIFIED IDEOGRAPH-5BC7\n5BC9..5BD9    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-5BC9..CJK UNIFIED IDEOGRAPH-5BD9\n5BDB..5BFF    ; Recommended                    # 1.1   [37] CJK UNIFIED IDEOGRAPH-5BDB..CJK UNIFIED IDEOGRAPH-5BFF\n5C01..5C1A    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-5C01..CJK UNIFIED IDEOGRAPH-5C1A\n5C1C..5C22    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5C1C..CJK UNIFIED IDEOGRAPH-5C22\n5C24..5C25    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5C24..CJK UNIFIED IDEOGRAPH-5C25\n5C27..5C28    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5C27..CJK UNIFIED IDEOGRAPH-5C28\n5C2A..5C35    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-5C2A..CJK UNIFIED IDEOGRAPH-5C35\n5C37..5C59    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-5C37..CJK UNIFIED IDEOGRAPH-5C59\n5C5B..5C84    ; Recommended                    # 1.1   [42] CJK UNIFIED IDEOGRAPH-5C5B..CJK UNIFIED IDEOGRAPH-5C84\n5C86..5CB3    ; Recommended                    # 1.1   [46] CJK UNIFIED IDEOGRAPH-5C86..CJK UNIFIED IDEOGRAPH-5CB3\n5CB5..5CB8    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-5CB5..CJK UNIFIED IDEOGRAPH-5CB8\n5CBA..5CD4    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-5CBA..CJK UNIFIED IDEOGRAPH-5CD4\n5CD6..5CDC    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5CD6..CJK UNIFIED IDEOGRAPH-5CDC\n5CDE..5CF4    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-5CDE..CJK UNIFIED IDEOGRAPH-5CF4\n5CF6..5D2A    ; Recommended                    # 1.1   [53] CJK UNIFIED IDEOGRAPH-5CF6..CJK UNIFIED IDEOGRAPH-5D2A\n5D2C..5D2E    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-5D2C..CJK UNIFIED IDEOGRAPH-5D2E\n5D30..5D3A    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-5D30..CJK UNIFIED IDEOGRAPH-5D3A\n5D3C..5D52    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-5D3C..CJK UNIFIED IDEOGRAPH-5D52\n5D54..5D56    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-5D54..CJK UNIFIED IDEOGRAPH-5D56\n5D58..5D5F    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5D58..CJK UNIFIED IDEOGRAPH-5D5F\n5D61..5D82    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-5D61..CJK UNIFIED IDEOGRAPH-5D82\n5D84..5D95    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-5D84..CJK UNIFIED IDEOGRAPH-5D95\n5D97..5DA2    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-5D97..CJK UNIFIED IDEOGRAPH-5DA2\n5DA5..5DAA    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-5DA5..CJK UNIFIED IDEOGRAPH-5DAA\n5DAC..5DB2    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-5DAC..CJK UNIFIED IDEOGRAPH-5DB2\n5DB4..5DB8    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5DB4..CJK UNIFIED IDEOGRAPH-5DB8\n5DBA..5DC3    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-5DBA..CJK UNIFIED IDEOGRAPH-5DC3\n5DC5..5DD6    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-5DC5..CJK UNIFIED IDEOGRAPH-5DD6\n5DD8..5DD9    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-5DD8..CJK UNIFIED IDEOGRAPH-5DD9\n5DDB          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-5DDB\n5DDD..5DF5    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-5DDD..CJK UNIFIED IDEOGRAPH-5DF5\n5DF7..5E11    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-5DF7..CJK UNIFIED IDEOGRAPH-5E11\n5E13..5E47    ; Recommended                    # 1.1   [53] CJK UNIFIED IDEOGRAPH-5E13..CJK UNIFIED IDEOGRAPH-5E47\n5E49..5E50    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5E49..CJK UNIFIED IDEOGRAPH-5E50\n5E52..5E91    ; Recommended                    # 1.1   [64] CJK UNIFIED IDEOGRAPH-5E52..CJK UNIFIED IDEOGRAPH-5E91\n5E93..5EB9    ; Recommended                    # 1.1   [39] CJK UNIFIED IDEOGRAPH-5E93..CJK UNIFIED IDEOGRAPH-5EB9\n5EBB..5EBF    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-5EBB..CJK UNIFIED IDEOGRAPH-5EBF\n5EC1..5EEA    ; Recommended                    # 1.1   [42] CJK UNIFIED IDEOGRAPH-5EC1..CJK UNIFIED IDEOGRAPH-5EEA\n5EEC..5EF8    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-5EEC..CJK UNIFIED IDEOGRAPH-5EF8\n5EFA..5F0D    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-5EFA..CJK UNIFIED IDEOGRAPH-5F0D\n5F0F..5F3A    ; Recommended                    # 1.1   [44] CJK UNIFIED IDEOGRAPH-5F0F..CJK UNIFIED IDEOGRAPH-5F3A\n5F3C          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-5F3C\n5F3E..5F8E    ; Recommended                    # 1.1   [81] CJK UNIFIED IDEOGRAPH-5F3E..CJK UNIFIED IDEOGRAPH-5F8E\n5F90..5F99    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-5F90..CJK UNIFIED IDEOGRAPH-5F99\n5F9B..5FA2    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-5F9B..CJK UNIFIED IDEOGRAPH-5FA2\n5FA5..5FAF    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-5FA5..CJK UNIFIED IDEOGRAPH-5FAF\n5FB1..5FC1    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-5FB1..CJK UNIFIED IDEOGRAPH-5FC1\n5FC3..5FCD    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-5FC3..CJK UNIFIED IDEOGRAPH-5FCD\n5FCF..5FDA    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-5FCF..CJK UNIFIED IDEOGRAPH-5FDA\n5FDC..5FE1    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-5FDC..CJK UNIFIED IDEOGRAPH-5FE1\n5FE3..5FEB    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-5FE3..CJK UNIFIED IDEOGRAPH-5FEB\n5FED..5FFB    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-5FED..CJK UNIFIED IDEOGRAPH-5FFB\n5FFD..6022    ; Recommended                    # 1.1   [38] CJK UNIFIED IDEOGRAPH-5FFD..CJK UNIFIED IDEOGRAPH-6022\n6024..6055    ; Recommended                    # 1.1   [50] CJK UNIFIED IDEOGRAPH-6024..CJK UNIFIED IDEOGRAPH-6055\n6057..6060    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-6057..CJK UNIFIED IDEOGRAPH-6060\n6062..6070    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-6062..CJK UNIFIED IDEOGRAPH-6070\n6072..6073    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-6072..CJK UNIFIED IDEOGRAPH-6073\n6075..6090    ; Recommended                    # 1.1   [28] CJK UNIFIED IDEOGRAPH-6075..CJK UNIFIED IDEOGRAPH-6090\n6092          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6092\n6094..60A4    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-6094..CJK UNIFIED IDEOGRAPH-60A4\n60A6..60D1    ; Recommended                    # 1.1   [44] CJK UNIFIED IDEOGRAPH-60A6..CJK UNIFIED IDEOGRAPH-60D1\n60D3..60D5    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-60D3..CJK UNIFIED IDEOGRAPH-60D5\n60D7..60DD    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-60D7..CJK UNIFIED IDEOGRAPH-60DD\n60DF..60E4    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-60DF..CJK UNIFIED IDEOGRAPH-60E4\n60E6..60FC    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-60E6..CJK UNIFIED IDEOGRAPH-60FC\n60FE..6101    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-60FE..CJK UNIFIED IDEOGRAPH-6101\n6103..6106    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6103..CJK UNIFIED IDEOGRAPH-6106\n6108..6110    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-6108..CJK UNIFIED IDEOGRAPH-6110\n6112..611D    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-6112..CJK UNIFIED IDEOGRAPH-611D\n611F..6130    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-611F..CJK UNIFIED IDEOGRAPH-6130\n6132          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6132\n6134          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6134\n6136..6137    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-6136..CJK UNIFIED IDEOGRAPH-6137\n613A..615F    ; Recommended                    # 1.1   [38] CJK UNIFIED IDEOGRAPH-613A..CJK UNIFIED IDEOGRAPH-615F\n6161..617A    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-6161..CJK UNIFIED IDEOGRAPH-617A\n617C..617E    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-617C..CJK UNIFIED IDEOGRAPH-617E\n6180..6185    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-6180..CJK UNIFIED IDEOGRAPH-6185\n6187..6196    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-6187..CJK UNIFIED IDEOGRAPH-6196\n6198..619B    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6198..CJK UNIFIED IDEOGRAPH-619B\n619D..61B8    ; Recommended                    # 1.1   [28] CJK UNIFIED IDEOGRAPH-619D..CJK UNIFIED IDEOGRAPH-61B8\n61BA          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-61BA\n61BC..61D2    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-61BC..CJK UNIFIED IDEOGRAPH-61D2\n61D4          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-61D4\n61D6..61EB    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-61D6..CJK UNIFIED IDEOGRAPH-61EB\n61ED..61EE    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-61ED..CJK UNIFIED IDEOGRAPH-61EE\n61F0..6204    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-61F0..CJK UNIFIED IDEOGRAPH-6204\n6206..6234    ; Recommended                    # 1.1   [47] CJK UNIFIED IDEOGRAPH-6206..CJK UNIFIED IDEOGRAPH-6234\n6236..6238    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-6236..CJK UNIFIED IDEOGRAPH-6238\n623A..6256    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-623A..CJK UNIFIED IDEOGRAPH-6256\n6258..628C    ; Recommended                    # 1.1   [53] CJK UNIFIED IDEOGRAPH-6258..CJK UNIFIED IDEOGRAPH-628C\n628E..629C    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-628E..CJK UNIFIED IDEOGRAPH-629C\n629E..62DD    ; Recommended                    # 1.1   [64] CJK UNIFIED IDEOGRAPH-629E..CJK UNIFIED IDEOGRAPH-62DD\n62DF..62E9    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-62DF..CJK UNIFIED IDEOGRAPH-62E9\n62EB..6309    ; Recommended                    # 1.1   [31] CJK UNIFIED IDEOGRAPH-62EB..CJK UNIFIED IDEOGRAPH-6309\n630B..6316    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-630B..CJK UNIFIED IDEOGRAPH-6316\n6318..6330    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-6318..CJK UNIFIED IDEOGRAPH-6330\n6332..6336    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-6332..CJK UNIFIED IDEOGRAPH-6336\n6338..635A    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-6338..CJK UNIFIED IDEOGRAPH-635A\n635C..638A    ; Recommended                    # 1.1   [47] CJK UNIFIED IDEOGRAPH-635C..CJK UNIFIED IDEOGRAPH-638A\n638C..6392    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-638C..CJK UNIFIED IDEOGRAPH-6392\n6394..63D0    ; Recommended                    # 1.1   [61] CJK UNIFIED IDEOGRAPH-6394..CJK UNIFIED IDEOGRAPH-63D0\n63D2..643A    ; Recommended                    # 1.1  [105] CJK UNIFIED IDEOGRAPH-63D2..CJK UNIFIED IDEOGRAPH-643A\n643D..6448    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-643D..CJK UNIFIED IDEOGRAPH-6448\n644A..6459    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-644A..CJK UNIFIED IDEOGRAPH-6459\n645B..647D    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-645B..CJK UNIFIED IDEOGRAPH-647D\n647F..6485    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-647F..CJK UNIFIED IDEOGRAPH-6485\n6487..64A0    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-6487..CJK UNIFIED IDEOGRAPH-64A0\n64A2..64AE    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-64A2..CJK UNIFIED IDEOGRAPH-64AE\n64B0..64B5    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-64B0..CJK UNIFIED IDEOGRAPH-64B5\n64B7..64C7    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-64B7..CJK UNIFIED IDEOGRAPH-64C7\n64C9..64D4    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-64C9..CJK UNIFIED IDEOGRAPH-64D4\n64D6..64ED    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-64D6..CJK UNIFIED IDEOGRAPH-64ED\n64EF..64F4    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-64EF..CJK UNIFIED IDEOGRAPH-64F4\n64F6..64F8    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-64F6..CJK UNIFIED IDEOGRAPH-64F8\n64FA..6501    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-64FA..CJK UNIFIED IDEOGRAPH-6501\n6503..6509    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-6503..CJK UNIFIED IDEOGRAPH-6509\n650B..651E    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-650B..CJK UNIFIED IDEOGRAPH-651E\n6520..6527    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-6520..CJK UNIFIED IDEOGRAPH-6527\n6529..653F    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-6529..CJK UNIFIED IDEOGRAPH-653F\n6541          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6541\n6543..6559    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-6543..CJK UNIFIED IDEOGRAPH-6559\n655B..655E    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-655B..CJK UNIFIED IDEOGRAPH-655E\n6560..657C    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-6560..CJK UNIFIED IDEOGRAPH-657C\n657E..6589    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-657E..CJK UNIFIED IDEOGRAPH-6589\n658B..6599    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-658B..CJK UNIFIED IDEOGRAPH-6599\n659B..65B4    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-659B..CJK UNIFIED IDEOGRAPH-65B4\n65B6..65BD    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-65B6..CJK UNIFIED IDEOGRAPH-65BD\n65BF..65C7    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-65BF..CJK UNIFIED IDEOGRAPH-65C7\n65CA..65D0    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-65CA..CJK UNIFIED IDEOGRAPH-65D0\n65D2..65D7    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-65D2..CJK UNIFIED IDEOGRAPH-65D7\n65D9..65DB    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-65D9..CJK UNIFIED IDEOGRAPH-65DB\n65DD..65E3    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-65DD..CJK UNIFIED IDEOGRAPH-65E3\n65E5..65E9    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-65E5..CJK UNIFIED IDEOGRAPH-65E9\n65EB..65F8    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-65EB..CJK UNIFIED IDEOGRAPH-65F8\n65FA..65FD    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-65FA..CJK UNIFIED IDEOGRAPH-65FD\n65FF..6616    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-65FF..CJK UNIFIED IDEOGRAPH-6616\n6618..662B    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-6618..CJK UNIFIED IDEOGRAPH-662B\n662D..6636    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-662D..CJK UNIFIED IDEOGRAPH-6636\n6639..6647    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-6639..CJK UNIFIED IDEOGRAPH-6647\n6649..664C    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6649..CJK UNIFIED IDEOGRAPH-664C\n664E..665F    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-664E..CJK UNIFIED IDEOGRAPH-665F\n6661..6662    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-6661..CJK UNIFIED IDEOGRAPH-6662\n6664..6691    ; Recommended                    # 1.1   [46] CJK UNIFIED IDEOGRAPH-6664..CJK UNIFIED IDEOGRAPH-6691\n6693..669B    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-6693..CJK UNIFIED IDEOGRAPH-669B\n669D          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-669D\n669F..66AB    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-669F..CJK UNIFIED IDEOGRAPH-66AB\n66AE..66CF    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-66AE..CJK UNIFIED IDEOGRAPH-66CF\n66D1..66D2    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-66D1..CJK UNIFIED IDEOGRAPH-66D2\n66D4..66D6    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-66D4..CJK UNIFIED IDEOGRAPH-66D6\n66D8..66DE    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-66D8..CJK UNIFIED IDEOGRAPH-66DE\n66E0..66EE    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-66E0..CJK UNIFIED IDEOGRAPH-66EE\n66F0..6701    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-66F0..CJK UNIFIED IDEOGRAPH-6701\n6703..6706    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6703..CJK UNIFIED IDEOGRAPH-6706\n6708..6718    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-6708..CJK UNIFIED IDEOGRAPH-6718\n671A..6723    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-671A..CJK UNIFIED IDEOGRAPH-6723\n6725..6728    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6725..CJK UNIFIED IDEOGRAPH-6728\n672A..6766    ; Recommended                    # 1.1   [61] CJK UNIFIED IDEOGRAPH-672A..CJK UNIFIED IDEOGRAPH-6766\n6768..6787    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-6768..CJK UNIFIED IDEOGRAPH-6787\n6789..6795    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-6789..CJK UNIFIED IDEOGRAPH-6795\n6797..67BC    ; Recommended                    # 1.1   [38] CJK UNIFIED IDEOGRAPH-6797..CJK UNIFIED IDEOGRAPH-67BC\n67BE          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-67BE\n67C0..67D4    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-67C0..CJK UNIFIED IDEOGRAPH-67D4\n67D6          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-67D6\n67D8..67F8    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-67D8..CJK UNIFIED IDEOGRAPH-67F8\n67FA..6800    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-67FA..CJK UNIFIED IDEOGRAPH-6800\n6802..6814    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-6802..CJK UNIFIED IDEOGRAPH-6814\n6816..6826    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-6816..CJK UNIFIED IDEOGRAPH-6826\n6828..682F    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-6828..CJK UNIFIED IDEOGRAPH-682F\n6831..6857    ; Recommended                    # 1.1   [39] CJK UNIFIED IDEOGRAPH-6831..CJK UNIFIED IDEOGRAPH-6857\n6859          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6859\n685B..685D    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-685B..CJK UNIFIED IDEOGRAPH-685D\n685F..6879    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-685F..CJK UNIFIED IDEOGRAPH-6879\n687B..6894    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-687B..CJK UNIFIED IDEOGRAPH-6894\n6896..6898    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-6896..CJK UNIFIED IDEOGRAPH-6898\n689A..68A4    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-689A..CJK UNIFIED IDEOGRAPH-68A4\n68A6..68B7    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-68A6..CJK UNIFIED IDEOGRAPH-68B7\n68B9..68C2    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-68B9..CJK UNIFIED IDEOGRAPH-68C2\n68C4..68D8    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-68C4..CJK UNIFIED IDEOGRAPH-68D8\n68DA..68E1    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-68DA..CJK UNIFIED IDEOGRAPH-68E1\n68E3..68E4    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-68E3..CJK UNIFIED IDEOGRAPH-68E4\n68E6..6908    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-68E6..CJK UNIFIED IDEOGRAPH-6908\n690A..693D    ; Recommended                    # 1.1   [52] CJK UNIFIED IDEOGRAPH-690A..CJK UNIFIED IDEOGRAPH-693D\n693F..694C    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-693F..CJK UNIFIED IDEOGRAPH-694C\n694E..699E    ; Recommended                    # 1.1   [81] CJK UNIFIED IDEOGRAPH-694E..CJK UNIFIED IDEOGRAPH-699E\n69A0..69A1    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-69A0..CJK UNIFIED IDEOGRAPH-69A1\n69A3..69BF    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-69A3..CJK UNIFIED IDEOGRAPH-69BF\n69C1..69D0    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-69C1..CJK UNIFIED IDEOGRAPH-69D0\n69D3..69D4    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-69D3..CJK UNIFIED IDEOGRAPH-69D4\n69D8..6A02    ; Recommended                    # 1.1   [43] CJK UNIFIED IDEOGRAPH-69D8..CJK UNIFIED IDEOGRAPH-6A02\n6A04..6A1B    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-6A04..CJK UNIFIED IDEOGRAPH-6A1B\n6A1D..6A23    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-6A1D..CJK UNIFIED IDEOGRAPH-6A23\n6A25..6A36    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-6A25..CJK UNIFIED IDEOGRAPH-6A36\n6A38..6A49    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-6A38..CJK UNIFIED IDEOGRAPH-6A49\n6A4B..6A5B    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-6A4B..CJK UNIFIED IDEOGRAPH-6A5B\n6A5D..6A6D    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-6A5D..CJK UNIFIED IDEOGRAPH-6A6D\n6A6F          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6A6F\n6A71..6A85    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-6A71..CJK UNIFIED IDEOGRAPH-6A85\n6A87..6A89    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-6A87..CJK UNIFIED IDEOGRAPH-6A89\n6A8B..6A8E    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6A8B..CJK UNIFIED IDEOGRAPH-6A8E\n6A90..6A98    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-6A90..CJK UNIFIED IDEOGRAPH-6A98\n6A9A..6A9C    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-6A9A..CJK UNIFIED IDEOGRAPH-6A9C\n6A9E..6AB0    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-6A9E..CJK UNIFIED IDEOGRAPH-6AB0\n6AB2..6ABD    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-6AB2..CJK UNIFIED IDEOGRAPH-6ABD\n6ABF          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6ABF\n6AC1..6AC3    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-6AC1..CJK UNIFIED IDEOGRAPH-6AC3\n6AC5..6AC8    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6AC5..CJK UNIFIED IDEOGRAPH-6AC8\n6ACA..6AD7    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-6ACA..CJK UNIFIED IDEOGRAPH-6AD7\n6AD9..6AE8    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-6AD9..CJK UNIFIED IDEOGRAPH-6AE8\n6AEA..6B0D    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-6AEA..CJK UNIFIED IDEOGRAPH-6B0D\n6B0F..6B1A    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-6B0F..CJK UNIFIED IDEOGRAPH-6B1A\n6B1C..6B2D    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-6B1C..CJK UNIFIED IDEOGRAPH-6B2D\n6B2F..6B34    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-6B2F..CJK UNIFIED IDEOGRAPH-6B34\n6B36..6B3F    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-6B36..CJK UNIFIED IDEOGRAPH-6B3F\n6B41..6B56    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-6B41..CJK UNIFIED IDEOGRAPH-6B56\n6B59..6B5C    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6B59..CJK UNIFIED IDEOGRAPH-6B5C\n6B5E..6B67    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-6B5E..CJK UNIFIED IDEOGRAPH-6B67\n6B69..6B6B    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-6B69..CJK UNIFIED IDEOGRAPH-6B6B\n6B6D          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6B6D\n6B6F..6B70    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-6B6F..CJK UNIFIED IDEOGRAPH-6B70\n6B72..6B74    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-6B72..CJK UNIFIED IDEOGRAPH-6B74\n6B76..6B7C    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-6B76..CJK UNIFIED IDEOGRAPH-6B7C\n6B7E..6BB7    ; Recommended                    # 1.1   [58] CJK UNIFIED IDEOGRAPH-6B7E..CJK UNIFIED IDEOGRAPH-6BB7\n6BB9..6BE8    ; Recommended                    # 1.1   [48] CJK UNIFIED IDEOGRAPH-6BB9..CJK UNIFIED IDEOGRAPH-6BE8\n6BEA..6BF0    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-6BEA..CJK UNIFIED IDEOGRAPH-6BF0\n6BF2..6BF3    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-6BF2..CJK UNIFIED IDEOGRAPH-6BF3\n6BF5..6BF9    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-6BF5..CJK UNIFIED IDEOGRAPH-6BF9\n6BFB..6C09    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-6BFB..CJK UNIFIED IDEOGRAPH-6C09\n6C0B..6C1B    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-6C0B..CJK UNIFIED IDEOGRAPH-6C1B\n6C1D..6C2C    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-6C1D..CJK UNIFIED IDEOGRAPH-6C2C\n6C2E..6C3B    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-6C2E..CJK UNIFIED IDEOGRAPH-6C3B\n6C3D..6C44    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-6C3D..CJK UNIFIED IDEOGRAPH-6C44\n6C46..6C6B    ; Recommended                    # 1.1   [38] CJK UNIFIED IDEOGRAPH-6C46..CJK UNIFIED IDEOGRAPH-6C6B\n6C6D          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6C6D\n6C6F..6C9F    ; Recommended                    # 1.1   [49] CJK UNIFIED IDEOGRAPH-6C6F..CJK UNIFIED IDEOGRAPH-6C9F\n6CA1..6CD7    ; Recommended                    # 1.1   [55] CJK UNIFIED IDEOGRAPH-6CA1..CJK UNIFIED IDEOGRAPH-6CD7\n6CD9..6CF3    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-6CD9..CJK UNIFIED IDEOGRAPH-6CF3\n6CF5..6D01    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-6CF5..CJK UNIFIED IDEOGRAPH-6D01\n6D03..6D1B    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-6D03..CJK UNIFIED IDEOGRAPH-6D1B\n6D1D..6D23    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-6D1D..CJK UNIFIED IDEOGRAPH-6D23\n6D25..6D70    ; Recommended                    # 1.1   [76] CJK UNIFIED IDEOGRAPH-6D25..CJK UNIFIED IDEOGRAPH-6D70\n6D72..6D80    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-6D72..CJK UNIFIED IDEOGRAPH-6D80\n6D82..6D95    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-6D82..CJK UNIFIED IDEOGRAPH-6D95\n6D97..6DAF    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-6D97..CJK UNIFIED IDEOGRAPH-6DAF\n6DB2..6DB5    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6DB2..CJK UNIFIED IDEOGRAPH-6DB5\n6DB7..6DFD    ; Recommended                    # 1.1   [71] CJK UNIFIED IDEOGRAPH-6DB7..CJK UNIFIED IDEOGRAPH-6DFD\n6E00          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6E00\n6E03..6E05    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-6E03..CJK UNIFIED IDEOGRAPH-6E05\n6E07..6E11    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-6E07..CJK UNIFIED IDEOGRAPH-6E11\n6E13..6E17    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-6E13..CJK UNIFIED IDEOGRAPH-6E17\n6E19..6E29    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-6E19..CJK UNIFIED IDEOGRAPH-6E29\n6E2B..6E4B    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-6E2B..CJK UNIFIED IDEOGRAPH-6E4B\n6E4D..6E6B    ; Recommended                    # 1.1   [31] CJK UNIFIED IDEOGRAPH-6E4D..CJK UNIFIED IDEOGRAPH-6E6B\n6E6D..6E7A    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-6E6D..CJK UNIFIED IDEOGRAPH-6E7A\n6E7E..6E8A    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-6E7E..CJK UNIFIED IDEOGRAPH-6E8A\n6E8C..6E94    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-6E8C..CJK UNIFIED IDEOGRAPH-6E94\n6E96..6EDA    ; Recommended                    # 1.1   [69] CJK UNIFIED IDEOGRAPH-6E96..CJK UNIFIED IDEOGRAPH-6EDA\n6EDC..6EE2    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-6EDC..CJK UNIFIED IDEOGRAPH-6EE2\n6EE4..6F03    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-6EE4..CJK UNIFIED IDEOGRAPH-6F03\n6F05..6F0A    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-6F05..CJK UNIFIED IDEOGRAPH-6F0A\n6F0C..6F41    ; Recommended                    # 1.1   [54] CJK UNIFIED IDEOGRAPH-6F0C..CJK UNIFIED IDEOGRAPH-6F41\n6F43..6F47    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-6F43..CJK UNIFIED IDEOGRAPH-6F47\n6F49          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6F49\n6F4B..6F78    ; Recommended                    # 1.1   [46] CJK UNIFIED IDEOGRAPH-6F4B..CJK UNIFIED IDEOGRAPH-6F78\n6F7A..6F97    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-6F7A..CJK UNIFIED IDEOGRAPH-6F97\n6F99          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-6F99\n6F9B..6F9E    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-6F9B..CJK UNIFIED IDEOGRAPH-6F9E\n6FA0..6FB6    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-6FA0..CJK UNIFIED IDEOGRAPH-6FB6\n6FB8..6FC4    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-6FB8..CJK UNIFIED IDEOGRAPH-6FC4\n6FC6..6FCF    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-6FC6..CJK UNIFIED IDEOGRAPH-6FCF\n6FD1..6FD2    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-6FD1..CJK UNIFIED IDEOGRAPH-6FD2\n6FD4..6FF4    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-6FD4..CJK UNIFIED IDEOGRAPH-6FF4\n6FF6..6FFC    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-6FF6..CJK UNIFIED IDEOGRAPH-6FFC\n6FFE..700F    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-6FFE..CJK UNIFIED IDEOGRAPH-700F\n7011..7012    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-7011..CJK UNIFIED IDEOGRAPH-7012\n7014..7046    ; Recommended                    # 1.1   [51] CJK UNIFIED IDEOGRAPH-7014..CJK UNIFIED IDEOGRAPH-7046\n7048..704A    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7048..CJK UNIFIED IDEOGRAPH-704A\n704C..704D    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-704C..CJK UNIFIED IDEOGRAPH-704D\n704F..7071    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-704F..CJK UNIFIED IDEOGRAPH-7071\n7074..707A    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-7074..CJK UNIFIED IDEOGRAPH-707A\n707C..7080    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-707C..CJK UNIFIED IDEOGRAPH-7080\n7082..708C    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7082..CJK UNIFIED IDEOGRAPH-708C\n708E..7096    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-708E..CJK UNIFIED IDEOGRAPH-7096\n7098..709A    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7098..CJK UNIFIED IDEOGRAPH-709A\n709C..70A9    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-709C..CJK UNIFIED IDEOGRAPH-70A9\n70AB..70B1    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-70AB..CJK UNIFIED IDEOGRAPH-70B1\n70B3..70B5    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-70B3..CJK UNIFIED IDEOGRAPH-70B5\n70B7..70D4    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-70B7..CJK UNIFIED IDEOGRAPH-70D4\n70D6..70FD    ; Recommended                    # 1.1   [40] CJK UNIFIED IDEOGRAPH-70D6..CJK UNIFIED IDEOGRAPH-70FD\n70FF..7107    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-70FF..CJK UNIFIED IDEOGRAPH-7107\n7109..7123    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-7109..CJK UNIFIED IDEOGRAPH-7123\n7125..7132    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-7125..CJK UNIFIED IDEOGRAPH-7132\n7135..7156    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-7135..CJK UNIFIED IDEOGRAPH-7156\n7158..716A    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-7158..CJK UNIFIED IDEOGRAPH-716A\n716C          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-716C\n716E..718C    ; Recommended                    # 1.1   [31] CJK UNIFIED IDEOGRAPH-716E..CJK UNIFIED IDEOGRAPH-718C\n718E..7195    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-718E..CJK UNIFIED IDEOGRAPH-7195\n7197..71A5    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-7197..CJK UNIFIED IDEOGRAPH-71A5\n71A7..71AA    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-71A7..CJK UNIFIED IDEOGRAPH-71AA\n71AC..71B5    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-71AC..CJK UNIFIED IDEOGRAPH-71B5\n71B7..71CB    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-71B7..CJK UNIFIED IDEOGRAPH-71CB\n71CD..71D2    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-71CD..CJK UNIFIED IDEOGRAPH-71D2\n71D4..71F2    ; Recommended                    # 1.1   [31] CJK UNIFIED IDEOGRAPH-71D4..CJK UNIFIED IDEOGRAPH-71F2\n71F4..71F9    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-71F4..CJK UNIFIED IDEOGRAPH-71F9\n71FB..720A    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-71FB..CJK UNIFIED IDEOGRAPH-720A\n720C..7210    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-720C..CJK UNIFIED IDEOGRAPH-7210\n7212..7214    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7212..CJK UNIFIED IDEOGRAPH-7214\n7216          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7216\n7218..721F    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-7218..CJK UNIFIED IDEOGRAPH-721F\n7221..7223    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7221..CJK UNIFIED IDEOGRAPH-7223\n7226..722E    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-7226..CJK UNIFIED IDEOGRAPH-722E\n7230..7233    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7230..CJK UNIFIED IDEOGRAPH-7233\n7235..7244    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-7235..CJK UNIFIED IDEOGRAPH-7244\n7246..724D    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-7246..CJK UNIFIED IDEOGRAPH-724D\n724F          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-724F\n7251..7254    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7251..CJK UNIFIED IDEOGRAPH-7254\n7256..72AA    ; Recommended                    # 1.1   [85] CJK UNIFIED IDEOGRAPH-7256..CJK UNIFIED IDEOGRAPH-72AA\n72AC..72BD    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-72AC..CJK UNIFIED IDEOGRAPH-72BD\n72BF..7301    ; Recommended                    # 1.1   [67] CJK UNIFIED IDEOGRAPH-72BF..CJK UNIFIED IDEOGRAPH-7301\n7303..730F    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-7303..CJK UNIFIED IDEOGRAPH-730F\n7311..7327    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-7311..CJK UNIFIED IDEOGRAPH-7327\n7329..7352    ; Recommended                    # 1.1   [42] CJK UNIFIED IDEOGRAPH-7329..CJK UNIFIED IDEOGRAPH-7352\n7354..739B    ; Recommended                    # 1.1   [72] CJK UNIFIED IDEOGRAPH-7354..CJK UNIFIED IDEOGRAPH-739B\n739D..73C0    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-739D..CJK UNIFIED IDEOGRAPH-73C0\n73C2..73F2    ; Recommended                    # 1.1   [49] CJK UNIFIED IDEOGRAPH-73C2..CJK UNIFIED IDEOGRAPH-73F2\n73F4..73FA    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-73F4..CJK UNIFIED IDEOGRAPH-73FA\n73FC..7417    ; Recommended                    # 1.1   [28] CJK UNIFIED IDEOGRAPH-73FC..CJK UNIFIED IDEOGRAPH-7417\n7419..7438    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-7419..CJK UNIFIED IDEOGRAPH-7438\n743A..743D    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-743A..CJK UNIFIED IDEOGRAPH-743D\n743F..7446    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-743F..CJK UNIFIED IDEOGRAPH-7446\n7448          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7448\n744A..7457    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-744A..CJK UNIFIED IDEOGRAPH-7457\n7459..747A    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-7459..CJK UNIFIED IDEOGRAPH-747A\n747C..7483    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-747C..CJK UNIFIED IDEOGRAPH-7483\n7485..7495    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-7485..CJK UNIFIED IDEOGRAPH-7495\n7497..749C    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-7497..CJK UNIFIED IDEOGRAPH-749C\n749E..74C6    ; Recommended                    # 1.1   [41] CJK UNIFIED IDEOGRAPH-749E..CJK UNIFIED IDEOGRAPH-74C6\n74C8          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-74C8\n74CA..74CB    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-74CA..CJK UNIFIED IDEOGRAPH-74CB\n74CD..74EA    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-74CD..CJK UNIFIED IDEOGRAPH-74EA\n74EC..751F    ; Recommended                    # 1.1   [52] CJK UNIFIED IDEOGRAPH-74EC..CJK UNIFIED IDEOGRAPH-751F\n7521..7540    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-7521..CJK UNIFIED IDEOGRAPH-7540\n7542..7551    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-7542..CJK UNIFIED IDEOGRAPH-7551\n7553..7554    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-7553..CJK UNIFIED IDEOGRAPH-7554\n7556..755D    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-7556..CJK UNIFIED IDEOGRAPH-755D\n755F..7560    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-755F..CJK UNIFIED IDEOGRAPH-7560\n7562..7570    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-7562..CJK UNIFIED IDEOGRAPH-7570\n7572..757A    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-7572..CJK UNIFIED IDEOGRAPH-757A\n757C..7584    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-757C..CJK UNIFIED IDEOGRAPH-7584\n7586..75A8    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-7586..CJK UNIFIED IDEOGRAPH-75A8\n75AA..75B6    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-75AA..CJK UNIFIED IDEOGRAPH-75B6\n75B8..75DB    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-75B8..CJK UNIFIED IDEOGRAPH-75DB\n75DD..75ED    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-75DD..CJK UNIFIED IDEOGRAPH-75ED\n75EF..762B    ; Recommended                    # 1.1   [61] CJK UNIFIED IDEOGRAPH-75EF..CJK UNIFIED IDEOGRAPH-762B\n762D..7643    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-762D..CJK UNIFIED IDEOGRAPH-7643\n7646..7650    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7646..CJK UNIFIED IDEOGRAPH-7650\n7652..7654    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7652..CJK UNIFIED IDEOGRAPH-7654\n7656..7672    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-7656..CJK UNIFIED IDEOGRAPH-7672\n7674..768C    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-7674..CJK UNIFIED IDEOGRAPH-768C\n768E..76A0    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-768E..CJK UNIFIED IDEOGRAPH-76A0\n76A3..76A4    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-76A3..CJK UNIFIED IDEOGRAPH-76A4\n76A6..76A7    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-76A6..CJK UNIFIED IDEOGRAPH-76A7\n76A9..76B2    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-76A9..CJK UNIFIED IDEOGRAPH-76B2\n76B4..76B5    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-76B4..CJK UNIFIED IDEOGRAPH-76B5\n76B7..76C0    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-76B7..CJK UNIFIED IDEOGRAPH-76C0\n76C2..76CA    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-76C2..CJK UNIFIED IDEOGRAPH-76CA\n76CC..76D8    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-76CC..CJK UNIFIED IDEOGRAPH-76D8\n76DA..76EA    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-76DA..CJK UNIFIED IDEOGRAPH-76EA\n76EC..76FF    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-76EC..CJK UNIFIED IDEOGRAPH-76FF\n7701          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7701\n7703..770D    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7703..CJK UNIFIED IDEOGRAPH-770D\n770F..7720    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-770F..CJK UNIFIED IDEOGRAPH-7720\n7722..772A    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-7722..CJK UNIFIED IDEOGRAPH-772A\n772C..773E    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-772C..CJK UNIFIED IDEOGRAPH-773E\n7740..7741    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-7740..CJK UNIFIED IDEOGRAPH-7741\n7743..7763    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-7743..CJK UNIFIED IDEOGRAPH-7763\n7765..7795    ; Recommended                    # 1.1   [49] CJK UNIFIED IDEOGRAPH-7765..CJK UNIFIED IDEOGRAPH-7795\n7797..77A3    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-7797..CJK UNIFIED IDEOGRAPH-77A3\n77A5..77BD    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-77A5..CJK UNIFIED IDEOGRAPH-77BD\n77BF..77C0    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-77BF..CJK UNIFIED IDEOGRAPH-77C0\n77C2..77D1    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-77C2..CJK UNIFIED IDEOGRAPH-77D1\n77D3..77DC    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-77D3..CJK UNIFIED IDEOGRAPH-77DC\n77DE..77E3    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-77DE..CJK UNIFIED IDEOGRAPH-77E3\n77E5          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-77E5\n77E7..77F3    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-77E7..CJK UNIFIED IDEOGRAPH-77F3\n77F6..7823    ; Recommended                    # 1.1   [46] CJK UNIFIED IDEOGRAPH-77F6..CJK UNIFIED IDEOGRAPH-7823\n7825..7835    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-7825..CJK UNIFIED IDEOGRAPH-7835\n7837..7841    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7837..CJK UNIFIED IDEOGRAPH-7841\n7843..7845    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7843..CJK UNIFIED IDEOGRAPH-7845\n7847..784A    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7847..CJK UNIFIED IDEOGRAPH-784A\n784C..7875    ; Recommended                    # 1.1   [42] CJK UNIFIED IDEOGRAPH-784C..CJK UNIFIED IDEOGRAPH-7875\n7877..7887    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-7877..CJK UNIFIED IDEOGRAPH-7887\n7889..78C1    ; Recommended                    # 1.1   [57] CJK UNIFIED IDEOGRAPH-7889..CJK UNIFIED IDEOGRAPH-78C1\n78C3..78C6    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-78C3..CJK UNIFIED IDEOGRAPH-78C6\n78C8..78D1    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-78C8..CJK UNIFIED IDEOGRAPH-78D1\n78D3..78EF    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-78D3..CJK UNIFIED IDEOGRAPH-78EF\n78F1..78F7    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-78F1..CJK UNIFIED IDEOGRAPH-78F7\n78F9..78FF    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-78F9..CJK UNIFIED IDEOGRAPH-78FF\n7901..7907    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-7901..CJK UNIFIED IDEOGRAPH-7907\n7909..790C    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7909..CJK UNIFIED IDEOGRAPH-790C\n790E..7914    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-790E..CJK UNIFIED IDEOGRAPH-7914\n7916..791E    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-7916..CJK UNIFIED IDEOGRAPH-791E\n7921..7931    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-7921..CJK UNIFIED IDEOGRAPH-7931\n7933..7935    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7933..CJK UNIFIED IDEOGRAPH-7935\n7937..7958    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-7937..CJK UNIFIED IDEOGRAPH-7958\n795A..796B    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-795A..CJK UNIFIED IDEOGRAPH-796B\n796D          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-796D\n796F..7974    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-796F..CJK UNIFIED IDEOGRAPH-7974\n7977..7985    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-7977..CJK UNIFIED IDEOGRAPH-7985\n7988..799D    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-7988..CJK UNIFIED IDEOGRAPH-799D\n799F..79A8    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-799F..CJK UNIFIED IDEOGRAPH-79A8\n79AA..79BB    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-79AA..CJK UNIFIED IDEOGRAPH-79BB\n79BD..79C3    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-79BD..CJK UNIFIED IDEOGRAPH-79C3\n79C5..79C6    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-79C5..CJK UNIFIED IDEOGRAPH-79C6\n79C8..79CB    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-79C8..CJK UNIFIED IDEOGRAPH-79CB\n79CD..79D3    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-79CD..CJK UNIFIED IDEOGRAPH-79D3\n79D5..79D6    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-79D5..CJK UNIFIED IDEOGRAPH-79D6\n79D8..7A00    ; Recommended                    # 1.1   [41] CJK UNIFIED IDEOGRAPH-79D8..CJK UNIFIED IDEOGRAPH-7A00\n7A02..7A06    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-7A02..CJK UNIFIED IDEOGRAPH-7A06\n7A08          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7A08\n7A0A..7A2B    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-7A0A..CJK UNIFIED IDEOGRAPH-7A2B\n7A2D..7A37    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7A2D..CJK UNIFIED IDEOGRAPH-7A37\n7A39          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7A39\n7A3B..7A63    ; Recommended                    # 1.1   [41] CJK UNIFIED IDEOGRAPH-7A3B..CJK UNIFIED IDEOGRAPH-7A63\n7A65..7A69    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-7A65..CJK UNIFIED IDEOGRAPH-7A69\n7A6B..7A6E    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7A6B..CJK UNIFIED IDEOGRAPH-7A6E\n7A70..7A81    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-7A70..CJK UNIFIED IDEOGRAPH-7A81\n7A83..7A99    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-7A83..CJK UNIFIED IDEOGRAPH-7A99\n7A9C..7AB8    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-7A9C..CJK UNIFIED IDEOGRAPH-7AB8\n7ABA          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7ABA\n7ABE..7AC1    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7ABE..CJK UNIFIED IDEOGRAPH-7AC1\n7AC3..7AC5    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7AC3..CJK UNIFIED IDEOGRAPH-7AC5\n7AC7..7AE8    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-7AC7..CJK UNIFIED IDEOGRAPH-7AE8\n7AEA..7AF4    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7AEA..CJK UNIFIED IDEOGRAPH-7AF4\n7AF6..7AFB    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-7AF6..CJK UNIFIED IDEOGRAPH-7AFB\n7AFD..7B06    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-7AFD..CJK UNIFIED IDEOGRAPH-7B06\n7B08..7B1E    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-7B08..CJK UNIFIED IDEOGRAPH-7B1E\n7B20..7B26    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-7B20..CJK UNIFIED IDEOGRAPH-7B26\n7B28          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7B28\n7B2A..7B41    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-7B2A..CJK UNIFIED IDEOGRAPH-7B41\n7B43..7B52    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-7B43..CJK UNIFIED IDEOGRAPH-7B52\n7B54..7BA2    ; Recommended                    # 1.1   [79] CJK UNIFIED IDEOGRAPH-7B54..CJK UNIFIED IDEOGRAPH-7BA2\n7BA4          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7BA4\n7BA6..7BAF    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-7BA6..CJK UNIFIED IDEOGRAPH-7BAF\n7BB1          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7BB1\n7BB3..7BF9    ; Recommended                    # 1.1   [71] CJK UNIFIED IDEOGRAPH-7BB3..CJK UNIFIED IDEOGRAPH-7BF9\n7BFB..7C1A    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-7BFB..CJK UNIFIED IDEOGRAPH-7C1A\n7C1C..7C2D    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-7C1C..CJK UNIFIED IDEOGRAPH-7C2D\n7C30..7C51    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-7C30..CJK UNIFIED IDEOGRAPH-7C51\n7C53..7C54    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-7C53..CJK UNIFIED IDEOGRAPH-7C54\n7C56..7C5C    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-7C56..CJK UNIFIED IDEOGRAPH-7C5C\n7C5E..7C75    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-7C5E..CJK UNIFIED IDEOGRAPH-7C75\n7C77..7C86    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-7C77..CJK UNIFIED IDEOGRAPH-7C86\n7C88..7C92    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7C88..CJK UNIFIED IDEOGRAPH-7C92\n7C94..7C99    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-7C94..CJK UNIFIED IDEOGRAPH-7C99\n7C9B..7CAB    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-7C9B..CJK UNIFIED IDEOGRAPH-7CAB\n7CAD..7CD2    ; Recommended                    # 1.1   [38] CJK UNIFIED IDEOGRAPH-7CAD..CJK UNIFIED IDEOGRAPH-7CD2\n7CD4..7CD9    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-7CD4..CJK UNIFIED IDEOGRAPH-7CD9\n7CDC..7CE0    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-7CDC..CJK UNIFIED IDEOGRAPH-7CE0\n7CE2          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7CE2\n7CE4          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7CE4\n7CE7..7CFB    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-7CE7..CJK UNIFIED IDEOGRAPH-7CFB\n7CFD..7CFE    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-7CFD..CJK UNIFIED IDEOGRAPH-7CFE\n7D00..7D22    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-7D00..CJK UNIFIED IDEOGRAPH-7D22\n7D24..7D29    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-7D24..CJK UNIFIED IDEOGRAPH-7D29\n7D2B..7D2C    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-7D2B..CJK UNIFIED IDEOGRAPH-7D2C\n7D2E..7D47    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-7D2E..CJK UNIFIED IDEOGRAPH-7D47\n7D49..7D4C    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7D49..CJK UNIFIED IDEOGRAPH-7D4C\n7D4E..7D59    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-7D4E..CJK UNIFIED IDEOGRAPH-7D59\n7D5B..7D63    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-7D5B..CJK UNIFIED IDEOGRAPH-7D63\n7D65..7D77    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-7D65..CJK UNIFIED IDEOGRAPH-7D77\n7D79..7D81    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-7D79..CJK UNIFIED IDEOGRAPH-7D81\n7D83..7D94    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-7D83..CJK UNIFIED IDEOGRAPH-7D94\n7D96..7D97    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-7D96..CJK UNIFIED IDEOGRAPH-7D97\n7D99..7DA3    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7D99..CJK UNIFIED IDEOGRAPH-7DA3\n7DA5..7DA7    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-7DA5..CJK UNIFIED IDEOGRAPH-7DA7\n7DA9..7DCC    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-7DA9..CJK UNIFIED IDEOGRAPH-7DCC\n7DCE..7DD2    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-7DCE..CJK UNIFIED IDEOGRAPH-7DD2\n7DD4..7DE4    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-7DD4..CJK UNIFIED IDEOGRAPH-7DE4\n7DE6..7DEA    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-7DE6..CJK UNIFIED IDEOGRAPH-7DEA\n7DEC..7DFC    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-7DEC..CJK UNIFIED IDEOGRAPH-7DFC\n7E00..7E17    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-7E00..CJK UNIFIED IDEOGRAPH-7E17\n7E19..7E5A    ; Recommended                    # 1.1   [66] CJK UNIFIED IDEOGRAPH-7E19..CJK UNIFIED IDEOGRAPH-7E5A\n7E5C..7E63    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-7E5C..CJK UNIFIED IDEOGRAPH-7E63\n7E65..7E9C    ; Recommended                    # 1.1   [56] CJK UNIFIED IDEOGRAPH-7E65..CJK UNIFIED IDEOGRAPH-7E9C\n7E9E..7F3A    ; Recommended                    # 1.1  [157] CJK UNIFIED IDEOGRAPH-7E9E..CJK UNIFIED IDEOGRAPH-7F3A\n7F3D..7F40    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7F3D..CJK UNIFIED IDEOGRAPH-7F40\n7F42..7F45    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-7F42..CJK UNIFIED IDEOGRAPH-7F45\n7F47..7F58    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-7F47..CJK UNIFIED IDEOGRAPH-7F58\n7F5A..7F83    ; Recommended                    # 1.1   [42] CJK UNIFIED IDEOGRAPH-7F5A..CJK UNIFIED IDEOGRAPH-7F83\n7F85..7F8F    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-7F85..CJK UNIFIED IDEOGRAPH-7F8F\n7F91..7F96    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-7F91..CJK UNIFIED IDEOGRAPH-7F96\n7F98          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-7F98\n7F9A..7FB3    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-7F9A..CJK UNIFIED IDEOGRAPH-7FB3\n7FB5..7FD5    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-7FB5..CJK UNIFIED IDEOGRAPH-7FD5\n7FD7..7FDC    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-7FD7..CJK UNIFIED IDEOGRAPH-7FDC\n7FDE..7FE3    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-7FDE..CJK UNIFIED IDEOGRAPH-7FE3\n7FE5..8009    ; Recommended                    # 1.1   [37] CJK UNIFIED IDEOGRAPH-7FE5..CJK UNIFIED IDEOGRAPH-8009\n800B..802E    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-800B..CJK UNIFIED IDEOGRAPH-802E\n8030..803B    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-8030..CJK UNIFIED IDEOGRAPH-803B\n803D..803F    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-803D..CJK UNIFIED IDEOGRAPH-803F\n8041..8065    ; Recommended                    # 1.1   [37] CJK UNIFIED IDEOGRAPH-8041..CJK UNIFIED IDEOGRAPH-8065\n8067..8087    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-8067..CJK UNIFIED IDEOGRAPH-8087\n8089..808D    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-8089..CJK UNIFIED IDEOGRAPH-808D\n808F..8093    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-808F..CJK UNIFIED IDEOGRAPH-8093\n8095..80A5    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-8095..CJK UNIFIED IDEOGRAPH-80A5\n80A9..80B2    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-80A9..CJK UNIFIED IDEOGRAPH-80B2\n80B4..80B8    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-80B4..CJK UNIFIED IDEOGRAPH-80B8\n80BA..80DE    ; Recommended                    # 1.1   [37] CJK UNIFIED IDEOGRAPH-80BA..CJK UNIFIED IDEOGRAPH-80DE\n80E0..8102    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-80E0..CJK UNIFIED IDEOGRAPH-8102\n8105..8133    ; Recommended                    # 1.1   [47] CJK UNIFIED IDEOGRAPH-8105..CJK UNIFIED IDEOGRAPH-8133\n8136..8183    ; Recommended                    # 1.1   [78] CJK UNIFIED IDEOGRAPH-8136..CJK UNIFIED IDEOGRAPH-8183\n8185..818F    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-8185..CJK UNIFIED IDEOGRAPH-818F\n8191..8195    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-8191..CJK UNIFIED IDEOGRAPH-8195\n8197..81CA    ; Recommended                    # 1.1   [52] CJK UNIFIED IDEOGRAPH-8197..CJK UNIFIED IDEOGRAPH-81CA\n81CC..81E3    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-81CC..CJK UNIFIED IDEOGRAPH-81E3\n81E5..81EE    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-81E5..CJK UNIFIED IDEOGRAPH-81EE\n81F1..8212    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-81F1..CJK UNIFIED IDEOGRAPH-8212\n8214..8223    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-8214..CJK UNIFIED IDEOGRAPH-8223\n8225..8240    ; Recommended                    # 1.1   [28] CJK UNIFIED IDEOGRAPH-8225..CJK UNIFIED IDEOGRAPH-8240\n8242..8264    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-8242..CJK UNIFIED IDEOGRAPH-8264\n8266..828B    ; Recommended                    # 1.1   [38] CJK UNIFIED IDEOGRAPH-8266..CJK UNIFIED IDEOGRAPH-828B\n828D..82B1    ; Recommended                    # 1.1   [37] CJK UNIFIED IDEOGRAPH-828D..CJK UNIFIED IDEOGRAPH-82B1\n82B3..82E1    ; Recommended                    # 1.1   [47] CJK UNIFIED IDEOGRAPH-82B3..CJK UNIFIED IDEOGRAPH-82E1\n82E3..82FB    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-82E3..CJK UNIFIED IDEOGRAPH-82FB\n82FD..8309    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-82FD..CJK UNIFIED IDEOGRAPH-8309\n830B..830F    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-830B..CJK UNIFIED IDEOGRAPH-830F\n8311..832F    ; Recommended                    # 1.1   [31] CJK UNIFIED IDEOGRAPH-8311..CJK UNIFIED IDEOGRAPH-832F\n8331..8354    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-8331..CJK UNIFIED IDEOGRAPH-8354\n8356..83BD    ; Recommended                    # 1.1  [104] CJK UNIFIED IDEOGRAPH-8356..CJK UNIFIED IDEOGRAPH-83BD\n83BF..83E5    ; Recommended                    # 1.1   [39] CJK UNIFIED IDEOGRAPH-83BF..CJK UNIFIED IDEOGRAPH-83E5\n83E7..83EC    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-83E7..CJK UNIFIED IDEOGRAPH-83EC\n83EE..8413    ; Recommended                    # 1.1   [38] CJK UNIFIED IDEOGRAPH-83EE..CJK UNIFIED IDEOGRAPH-8413\n8415          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-8415\n8418..841E    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-8418..CJK UNIFIED IDEOGRAPH-841E\n8420..8457    ; Recommended                    # 1.1   [56] CJK UNIFIED IDEOGRAPH-8420..CJK UNIFIED IDEOGRAPH-8457\n8459..8482    ; Recommended                    # 1.1   [42] CJK UNIFIED IDEOGRAPH-8459..CJK UNIFIED IDEOGRAPH-8482\n8484..8494    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-8484..CJK UNIFIED IDEOGRAPH-8494\n8496..84B6    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-8496..CJK UNIFIED IDEOGRAPH-84B6\n84B8..84C2    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-84B8..CJK UNIFIED IDEOGRAPH-84C2\n84C4..84EC    ; Recommended                    # 1.1   [41] CJK UNIFIED IDEOGRAPH-84C4..CJK UNIFIED IDEOGRAPH-84EC\n84EE..8504    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-84EE..CJK UNIFIED IDEOGRAPH-8504\n8506..850F    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-8506..CJK UNIFIED IDEOGRAPH-850F\n8511..8531    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-8511..CJK UNIFIED IDEOGRAPH-8531\n8534..854B    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-8534..CJK UNIFIED IDEOGRAPH-854B\n854D..854F    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-854D..CJK UNIFIED IDEOGRAPH-854F\n8551..857E    ; Recommended                    # 1.1   [46] CJK UNIFIED IDEOGRAPH-8551..CJK UNIFIED IDEOGRAPH-857E\n8580..8592    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-8580..CJK UNIFIED IDEOGRAPH-8592\n8594..85B1    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-8594..CJK UNIFIED IDEOGRAPH-85B1\n85B3..85BA    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-85B3..CJK UNIFIED IDEOGRAPH-85BA\n85BC..85CB    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-85BC..CJK UNIFIED IDEOGRAPH-85CB\n85CD..85ED    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-85CD..CJK UNIFIED IDEOGRAPH-85ED\n85EF..85F2    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-85EF..CJK UNIFIED IDEOGRAPH-85F2\n85F4..85FB    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-85F4..CJK UNIFIED IDEOGRAPH-85FB\n85FD..8602    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-85FD..CJK UNIFIED IDEOGRAPH-8602\n8604..860C    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-8604..CJK UNIFIED IDEOGRAPH-860C\n860F          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-860F\n8611..8614    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-8611..CJK UNIFIED IDEOGRAPH-8614\n8616..861C    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-8616..CJK UNIFIED IDEOGRAPH-861C\n861E..8636    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-861E..CJK UNIFIED IDEOGRAPH-8636\n8638..8656    ; Recommended                    # 1.1   [31] CJK UNIFIED IDEOGRAPH-8638..CJK UNIFIED IDEOGRAPH-8656\n8658..8674    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-8658..CJK UNIFIED IDEOGRAPH-8674\n8676..8688    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-8676..CJK UNIFIED IDEOGRAPH-8688\n868A..8691    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-868A..CJK UNIFIED IDEOGRAPH-8691\n8693..869F    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-8693..CJK UNIFIED IDEOGRAPH-869F\n86A1..86A5    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-86A1..CJK UNIFIED IDEOGRAPH-86A5\n86A7..86D4    ; Recommended                    # 1.1   [46] CJK UNIFIED IDEOGRAPH-86A7..CJK UNIFIED IDEOGRAPH-86D4\n86D6..86DF    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-86D6..CJK UNIFIED IDEOGRAPH-86DF\n86E1..86E6    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-86E1..CJK UNIFIED IDEOGRAPH-86E6\n86E8..86FC    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-86E8..CJK UNIFIED IDEOGRAPH-86FC\n86FE..871C    ; Recommended                    # 1.1   [31] CJK UNIFIED IDEOGRAPH-86FE..CJK UNIFIED IDEOGRAPH-871C\n871E..872E    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-871E..CJK UNIFIED IDEOGRAPH-872E\n8730..873C    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-8730..CJK UNIFIED IDEOGRAPH-873C\n873E..8744    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-873E..CJK UNIFIED IDEOGRAPH-8744\n8746..8770    ; Recommended                    # 1.1   [43] CJK UNIFIED IDEOGRAPH-8746..CJK UNIFIED IDEOGRAPH-8770\n8772..878D    ; Recommended                    # 1.1   [28] CJK UNIFIED IDEOGRAPH-8772..CJK UNIFIED IDEOGRAPH-878D\n878F..8798    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-878F..CJK UNIFIED IDEOGRAPH-8798\n879A..87D9    ; Recommended                    # 1.1   [64] CJK UNIFIED IDEOGRAPH-879A..CJK UNIFIED IDEOGRAPH-87D9\n87DB..87EF    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-87DB..CJK UNIFIED IDEOGRAPH-87EF\n87F1..8806    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-87F1..CJK UNIFIED IDEOGRAPH-8806\n8808..8811    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-8808..CJK UNIFIED IDEOGRAPH-8811\n8813..882C    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-8813..CJK UNIFIED IDEOGRAPH-882C\n882E..8839    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-882E..CJK UNIFIED IDEOGRAPH-8839\n883B..8846    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-883B..CJK UNIFIED IDEOGRAPH-8846\n8848..8857    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-8848..CJK UNIFIED IDEOGRAPH-8857\n8859..885B    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-8859..CJK UNIFIED IDEOGRAPH-885B\n885D..885E    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-885D..CJK UNIFIED IDEOGRAPH-885E\n8860..8879    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-8860..CJK UNIFIED IDEOGRAPH-8879\n887B..88E5    ; Recommended                    # 1.1  [107] CJK UNIFIED IDEOGRAPH-887B..CJK UNIFIED IDEOGRAPH-88E5\n88E7..88E8    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-88E7..CJK UNIFIED IDEOGRAPH-88E8\n88EA..88EC    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-88EA..CJK UNIFIED IDEOGRAPH-88EC\n88EE..8902    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-88EE..CJK UNIFIED IDEOGRAPH-8902\n8904..890E    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-8904..CJK UNIFIED IDEOGRAPH-890E\n8910..8923    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-8910..CJK UNIFIED IDEOGRAPH-8923\n8925..8964    ; Recommended                    # 1.1   [64] CJK UNIFIED IDEOGRAPH-8925..CJK UNIFIED IDEOGRAPH-8964\n8966..8974    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-8966..CJK UNIFIED IDEOGRAPH-8974\n8976..897C    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-8976..CJK UNIFIED IDEOGRAPH-897C\n897E..898C    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-897E..CJK UNIFIED IDEOGRAPH-898C\n898E..898F    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-898E..CJK UNIFIED IDEOGRAPH-898F\n8991..8993    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-8991..CJK UNIFIED IDEOGRAPH-8993\n8995..8998    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-8995..CJK UNIFIED IDEOGRAPH-8998\n899A..89AF    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-899A..CJK UNIFIED IDEOGRAPH-89AF\n89B1..89B3    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-89B1..CJK UNIFIED IDEOGRAPH-89B3\n89B5..89BA    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-89B5..CJK UNIFIED IDEOGRAPH-89BA\n89BD..89ED    ; Recommended                    # 1.1   [49] CJK UNIFIED IDEOGRAPH-89BD..CJK UNIFIED IDEOGRAPH-89ED\n89EF..89F4    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-89EF..CJK UNIFIED IDEOGRAPH-89F4\n89F6..89F8    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-89F6..CJK UNIFIED IDEOGRAPH-89F8\n89FA..89FC    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-89FA..CJK UNIFIED IDEOGRAPH-89FC\n89FE..8A04    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-89FE..CJK UNIFIED IDEOGRAPH-8A04\n8A07..8A13    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-8A07..CJK UNIFIED IDEOGRAPH-8A13\n8A15..8A18    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-8A15..CJK UNIFIED IDEOGRAPH-8A18\n8A1A..8A1F    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8A1A..CJK UNIFIED IDEOGRAPH-8A1F\n8A22..8A2A    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-8A22..CJK UNIFIED IDEOGRAPH-8A2A\n8A2C..8A3C    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-8A2C..CJK UNIFIED IDEOGRAPH-8A3C\n8A3E..8A4A    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-8A3E..CJK UNIFIED IDEOGRAPH-8A4A\n8A4C..8A63    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-8A4C..CJK UNIFIED IDEOGRAPH-8A63\n8A65..8A77    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-8A65..CJK UNIFIED IDEOGRAPH-8A77\n8A79..8A7C    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-8A79..CJK UNIFIED IDEOGRAPH-8A7C\n8A7E..8A87    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-8A7E..CJK UNIFIED IDEOGRAPH-8A87\n8A89..8A9E    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-8A89..CJK UNIFIED IDEOGRAPH-8A9E\n8AA0..8AAE    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-8AA0..CJK UNIFIED IDEOGRAPH-8AAE\n8AB0..8AB6    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-8AB0..CJK UNIFIED IDEOGRAPH-8AB6\n8AB8..8ACF    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-8AB8..CJK UNIFIED IDEOGRAPH-8ACF\n8AD1..8AEB    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-8AD1..CJK UNIFIED IDEOGRAPH-8AEB\n8AED..8B28    ; Recommended                    # 1.1   [60] CJK UNIFIED IDEOGRAPH-8AED..CJK UNIFIED IDEOGRAPH-8B28\n8B2A..8B31    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-8B2A..CJK UNIFIED IDEOGRAPH-8B31\n8B33..8B37    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-8B33..CJK UNIFIED IDEOGRAPH-8B37\n8B39..8B3E    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8B39..CJK UNIFIED IDEOGRAPH-8B3E\n8B40..8B60    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-8B40..CJK UNIFIED IDEOGRAPH-8B60\n8B63..8B68    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8B63..CJK UNIFIED IDEOGRAPH-8B68\n8B6A..8B74    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-8B6A..CJK UNIFIED IDEOGRAPH-8B74\n8B76..8B7B    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8B76..CJK UNIFIED IDEOGRAPH-8B7B\n8B7D..8B80    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-8B7D..CJK UNIFIED IDEOGRAPH-8B80\n8B82..8B86    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-8B82..CJK UNIFIED IDEOGRAPH-8B86\n8B88..8B8C    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-8B88..CJK UNIFIED IDEOGRAPH-8B8C\n8B8E          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-8B8E\n8B90..8B9A    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-8B90..CJK UNIFIED IDEOGRAPH-8B9A\n8B9C..8C37    ; Recommended                    # 1.1  [156] CJK UNIFIED IDEOGRAPH-8B9C..CJK UNIFIED IDEOGRAPH-8C37\n8C39..8C3F    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-8C39..CJK UNIFIED IDEOGRAPH-8C3F\n8C41..8C43    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-8C41..CJK UNIFIED IDEOGRAPH-8C43\n8C45..8C50    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-8C45..CJK UNIFIED IDEOGRAPH-8C50\n8C54..8C57    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-8C54..CJK UNIFIED IDEOGRAPH-8C57\n8C59..8C73    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-8C59..CJK UNIFIED IDEOGRAPH-8C73\n8C75..8C7E    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-8C75..CJK UNIFIED IDEOGRAPH-8C7E\n8C80..8C82    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-8C80..CJK UNIFIED IDEOGRAPH-8C82\n8C84..8C86    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-8C84..CJK UNIFIED IDEOGRAPH-8C86\n8C88..8C8A    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-8C88..CJK UNIFIED IDEOGRAPH-8C8A\n8C8C..8C9A    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-8C8C..CJK UNIFIED IDEOGRAPH-8C9A\n8C9C..8CA5    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-8C9C..CJK UNIFIED IDEOGRAPH-8CA5\n8CA7..8CCA    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-8CA7..CJK UNIFIED IDEOGRAPH-8CCA\n8CCC..8CD5    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-8CCC..CJK UNIFIED IDEOGRAPH-8CD5\n8CD7          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-8CD7\n8CD9..8CE8    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-8CD9..CJK UNIFIED IDEOGRAPH-8CE8\n8CEA..8CF6    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-8CEA..CJK UNIFIED IDEOGRAPH-8CF6\n8CF8..8D00    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-8CF8..CJK UNIFIED IDEOGRAPH-8D00\n8D02..8D10    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-8D02..CJK UNIFIED IDEOGRAPH-8D10\n8D13..8D7B    ; Recommended                    # 1.1  [105] CJK UNIFIED IDEOGRAPH-8D13..CJK UNIFIED IDEOGRAPH-8D7B\n8D7D..8DA5    ; Recommended                    # 1.1   [41] CJK UNIFIED IDEOGRAPH-8D7D..CJK UNIFIED IDEOGRAPH-8DA5\n8DA7..8DBF    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-8DA7..CJK UNIFIED IDEOGRAPH-8DBF\n8DC1..8DE4    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-8DC1..CJK UNIFIED IDEOGRAPH-8DE4\n8DE6..8E00    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-8DE6..CJK UNIFIED IDEOGRAPH-8E00\n8E02..8E0A    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-8E02..CJK UNIFIED IDEOGRAPH-8E0A\n8E0C..8E31    ; Recommended                    # 1.1   [38] CJK UNIFIED IDEOGRAPH-8E0C..CJK UNIFIED IDEOGRAPH-8E31\n8E33..8E45    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-8E33..CJK UNIFIED IDEOGRAPH-8E45\n8E47..8E4E    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-8E47..CJK UNIFIED IDEOGRAPH-8E4E\n8E50..8E6D    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-8E50..CJK UNIFIED IDEOGRAPH-8E6D\n8E6F..8E74    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8E6F..CJK UNIFIED IDEOGRAPH-8E74\n8E76          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-8E76\n8E78          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-8E78\n8E7A..8E9A    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-8E7A..CJK UNIFIED IDEOGRAPH-8E9A\n8E9C..8EA1    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8E9C..CJK UNIFIED IDEOGRAPH-8EA1\n8EA3..8EB2    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-8EA3..CJK UNIFIED IDEOGRAPH-8EB2\n8EB4..8EB5    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-8EB4..CJK UNIFIED IDEOGRAPH-8EB5\n8EB8..8EC0    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-8EB8..CJK UNIFIED IDEOGRAPH-8EC0\n8EC2..8EC3    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-8EC2..CJK UNIFIED IDEOGRAPH-8EC3\n8EC5..8ED8    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-8EC5..CJK UNIFIED IDEOGRAPH-8ED8\n8EDA..8EEF    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-8EDA..CJK UNIFIED IDEOGRAPH-8EEF\n8EF1..8F0E    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-8EF1..CJK UNIFIED IDEOGRAPH-8F0E\n8F10..8F2C    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-8F10..CJK UNIFIED IDEOGRAPH-8F2C\n8F2E..8F39    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-8F2E..CJK UNIFIED IDEOGRAPH-8F39\n8F3B..8F40    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8F3B..CJK UNIFIED IDEOGRAPH-8F40\n8F42..8F9C    ; Recommended                    # 1.1   [91] CJK UNIFIED IDEOGRAPH-8F42..CJK UNIFIED IDEOGRAPH-8F9C\n8F9E..8FA3    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8F9E..CJK UNIFIED IDEOGRAPH-8FA3\n8FA5..8FB2    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-8FA5..CJK UNIFIED IDEOGRAPH-8FB2\n8FB4..8FC2    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-8FB4..CJK UNIFIED IDEOGRAPH-8FC2\n8FC4..8FC9    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-8FC4..CJK UNIFIED IDEOGRAPH-8FC9\n8FCB..8FE6    ; Recommended                    # 1.1   [28] CJK UNIFIED IDEOGRAPH-8FCB..CJK UNIFIED IDEOGRAPH-8FE6\n8FE8..9029    ; Recommended                    # 1.1   [66] CJK UNIFIED IDEOGRAPH-8FE8..CJK UNIFIED IDEOGRAPH-9029\n902B          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-902B\n902D..9036    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-902D..CJK UNIFIED IDEOGRAPH-9036\n9038..903F    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-9038..CJK UNIFIED IDEOGRAPH-903F\n9041..9045    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-9041..CJK UNIFIED IDEOGRAPH-9045\n9047..90AA    ; Recommended                    # 1.1  [100] CJK UNIFIED IDEOGRAPH-9047..CJK UNIFIED IDEOGRAPH-90AA\n90AC..90CB    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-90AC..CJK UNIFIED IDEOGRAPH-90CB\n90CE..90D1    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-90CE..CJK UNIFIED IDEOGRAPH-90D1\n90D3..90F5    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-90D3..CJK UNIFIED IDEOGRAPH-90F5\n90F7..9109    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-90F7..CJK UNIFIED IDEOGRAPH-9109\n910B..913B    ; Recommended                    # 1.1   [49] CJK UNIFIED IDEOGRAPH-910B..CJK UNIFIED IDEOGRAPH-913B\n913E..9158    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-913E..CJK UNIFIED IDEOGRAPH-9158\n915A..917A    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-915A..CJK UNIFIED IDEOGRAPH-917A\n917C..9194    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-917C..CJK UNIFIED IDEOGRAPH-9194\n9196..9197    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9196..CJK UNIFIED IDEOGRAPH-9197\n9199..91A8    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-9199..CJK UNIFIED IDEOGRAPH-91A8\n91AA..91BE    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-91AA..CJK UNIFIED IDEOGRAPH-91BE\n91C0..91C3    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-91C0..CJK UNIFIED IDEOGRAPH-91C3\n91C5..91DF    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-91C5..CJK UNIFIED IDEOGRAPH-91DF\n91E1..91EE    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-91E1..CJK UNIFIED IDEOGRAPH-91EE\n91F0..9212    ; Recommended                    # 1.1   [35] CJK UNIFIED IDEOGRAPH-91F0..CJK UNIFIED IDEOGRAPH-9212\n9214..921E    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-9214..CJK UNIFIED IDEOGRAPH-921E\n9220..9221    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9220..CJK UNIFIED IDEOGRAPH-9221\n9223..9242    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-9223..CJK UNIFIED IDEOGRAPH-9242\n9244..9268    ; Recommended                    # 1.1   [37] CJK UNIFIED IDEOGRAPH-9244..CJK UNIFIED IDEOGRAPH-9268\n926B..9280    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-926B..CJK UNIFIED IDEOGRAPH-9280\n9282..9283    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9282..CJK UNIFIED IDEOGRAPH-9283\n9285..929D    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-9285..CJK UNIFIED IDEOGRAPH-929D\n929F..92BC    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-929F..CJK UNIFIED IDEOGRAPH-92BC\n92BE..92D3    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-92BE..CJK UNIFIED IDEOGRAPH-92D3\n92D5..92DA    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-92D5..CJK UNIFIED IDEOGRAPH-92DA\n92DC..92E1    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-92DC..CJK UNIFIED IDEOGRAPH-92E1\n92E3..931B    ; Recommended                    # 1.1   [57] CJK UNIFIED IDEOGRAPH-92E3..CJK UNIFIED IDEOGRAPH-931B\n931D..932F    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-931D..CJK UNIFIED IDEOGRAPH-932F\n9332..9361    ; Recommended                    # 1.1   [48] CJK UNIFIED IDEOGRAPH-9332..CJK UNIFIED IDEOGRAPH-9361\n9363..9367    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-9363..CJK UNIFIED IDEOGRAPH-9367\n9369..936A    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9369..CJK UNIFIED IDEOGRAPH-936A\n936C..936E    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-936C..CJK UNIFIED IDEOGRAPH-936E\n9370..9372    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-9370..CJK UNIFIED IDEOGRAPH-9372\n9374..9377    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-9374..CJK UNIFIED IDEOGRAPH-9377\n9379..937E    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9379..CJK UNIFIED IDEOGRAPH-937E\n9380          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-9380\n9382..938A    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-9382..CJK UNIFIED IDEOGRAPH-938A\n938C..939B    ; Recommended                    # 1.1   [16] CJK UNIFIED IDEOGRAPH-938C..CJK UNIFIED IDEOGRAPH-939B\n939D..939F    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-939D..CJK UNIFIED IDEOGRAPH-939F\n93A1..93AA    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-93A1..CJK UNIFIED IDEOGRAPH-93AA\n93AC..93BA    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-93AC..CJK UNIFIED IDEOGRAPH-93BA\n93BC..93DF    ; Recommended                    # 1.1   [36] CJK UNIFIED IDEOGRAPH-93BC..CJK UNIFIED IDEOGRAPH-93DF\n93E1..93F2    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-93E1..CJK UNIFIED IDEOGRAPH-93F2\n93F4..9401    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-93F4..CJK UNIFIED IDEOGRAPH-9401\n9403..9416    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-9403..CJK UNIFIED IDEOGRAPH-9416\n9418..941B    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-9418..CJK UNIFIED IDEOGRAPH-941B\n941D          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-941D\n9420..9423    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-9420..CJK UNIFIED IDEOGRAPH-9423\n9425..9442    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-9425..CJK UNIFIED IDEOGRAPH-9442\n9444..944D    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-9444..CJK UNIFIED IDEOGRAPH-944D\n944F..946B    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-944F..CJK UNIFIED IDEOGRAPH-946B\n946D..947A    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-946D..CJK UNIFIED IDEOGRAPH-947A\n947C..9577    ; Recommended                    # 1.1  [252] CJK UNIFIED IDEOGRAPH-947C..CJK UNIFIED IDEOGRAPH-9577\n957A..957D    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-957A..CJK UNIFIED IDEOGRAPH-957D\n957F..9584    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-957F..CJK UNIFIED IDEOGRAPH-9584\n9586..9596    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-9586..CJK UNIFIED IDEOGRAPH-9596\n9598..95B2    ; Recommended                    # 1.1   [27] CJK UNIFIED IDEOGRAPH-9598..CJK UNIFIED IDEOGRAPH-95B2\n95B5..95B7    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-95B5..CJK UNIFIED IDEOGRAPH-95B7\n95B9..95C0    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-95B9..CJK UNIFIED IDEOGRAPH-95C0\n95C2..95D8    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-95C2..CJK UNIFIED IDEOGRAPH-95D8\n95DA..95DC    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-95DA..CJK UNIFIED IDEOGRAPH-95DC\n95DE..9624    ; Recommended                    # 1.1   [71] CJK UNIFIED IDEOGRAPH-95DE..CJK UNIFIED IDEOGRAPH-9624\n9627..9628    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9627..CJK UNIFIED IDEOGRAPH-9628\n962A..963D    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-962A..CJK UNIFIED IDEOGRAPH-963D\n963F..9655    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-963F..CJK UNIFIED IDEOGRAPH-9655\n9658..9678    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-9658..CJK UNIFIED IDEOGRAPH-9678\n967A          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-967A\n967C..967E    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-967C..CJK UNIFIED IDEOGRAPH-967E\n9680          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-9680\n9683..968B    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-9683..CJK UNIFIED IDEOGRAPH-968B\n968D..9695    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-968D..CJK UNIFIED IDEOGRAPH-9695\n9697..9699    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-9697..CJK UNIFIED IDEOGRAPH-9699\n969B..969C    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-969B..CJK UNIFIED IDEOGRAPH-969C\n969E          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-969E\n96A0..96AA    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-96A0..CJK UNIFIED IDEOGRAPH-96AA\n96AC..96AE    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-96AC..CJK UNIFIED IDEOGRAPH-96AE\n96B0..96B4    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-96B0..CJK UNIFIED IDEOGRAPH-96B4\n96B6..96E3    ; Recommended                    # 1.1   [46] CJK UNIFIED IDEOGRAPH-96B6..CJK UNIFIED IDEOGRAPH-96E3\n96E5          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-96E5\n96E8..96FB    ; Recommended                    # 1.1   [20] CJK UNIFIED IDEOGRAPH-96E8..CJK UNIFIED IDEOGRAPH-96FB\n96FD..9713    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-96FD..CJK UNIFIED IDEOGRAPH-9713\n9715..9716    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9715..CJK UNIFIED IDEOGRAPH-9716\n9718..9719    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9718..CJK UNIFIED IDEOGRAPH-9719\n971C..9732    ; Recommended                    # 1.1   [23] CJK UNIFIED IDEOGRAPH-971C..CJK UNIFIED IDEOGRAPH-9732\n9735..9736    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9735..CJK UNIFIED IDEOGRAPH-9736\n9738..973F    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-9738..CJK UNIFIED IDEOGRAPH-973F\n9742..974C    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-9742..CJK UNIFIED IDEOGRAPH-974C\n974E..9756    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-974E..CJK UNIFIED IDEOGRAPH-9756\n9758..9762    ; Recommended                    # 1.1   [11] CJK UNIFIED IDEOGRAPH-9758..CJK UNIFIED IDEOGRAPH-9762\n9764..9774    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-9764..CJK UNIFIED IDEOGRAPH-9774\n9776..9786    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-9776..CJK UNIFIED IDEOGRAPH-9786\n9788          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-9788\n978A..979A    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-978A..CJK UNIFIED IDEOGRAPH-979A\n979C..97A8    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-979C..CJK UNIFIED IDEOGRAPH-97A8\n97AA..97AF    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-97AA..CJK UNIFIED IDEOGRAPH-97AF\n97B2..97B4    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-97B2..CJK UNIFIED IDEOGRAPH-97B4\n97B6..97BD    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-97B6..CJK UNIFIED IDEOGRAPH-97BD\n97BF          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-97BF\n97C1..97D1    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-97C1..CJK UNIFIED IDEOGRAPH-97D1\n97D3..97FB    ; Recommended                    # 1.1   [41] CJK UNIFIED IDEOGRAPH-97D3..CJK UNIFIED IDEOGRAPH-97FB\n97FD..981E    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-97FD..CJK UNIFIED IDEOGRAPH-981E\n9820..9824    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-9820..CJK UNIFIED IDEOGRAPH-9824\n9826..9829    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-9826..CJK UNIFIED IDEOGRAPH-9829\n982B..9832    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-982B..CJK UNIFIED IDEOGRAPH-9832\n9834..9839    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9834..CJK UNIFIED IDEOGRAPH-9839\n983B..983D    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-983B..CJK UNIFIED IDEOGRAPH-983D\n983F..9841    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-983F..CJK UNIFIED IDEOGRAPH-9841\n9843..9846    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-9843..CJK UNIFIED IDEOGRAPH-9846\n9848..9855    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-9848..CJK UNIFIED IDEOGRAPH-9855\n9857..9865    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-9857..CJK UNIFIED IDEOGRAPH-9865\n9867          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-9867\n9869..98B6    ; Recommended                    # 1.1   [78] CJK UNIFIED IDEOGRAPH-9869..CJK UNIFIED IDEOGRAPH-98B6\n98B8..98C9    ; Recommended                    # 1.1   [18] CJK UNIFIED IDEOGRAPH-98B8..CJK UNIFIED IDEOGRAPH-98C9\n98CB..98E3    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-98CB..CJK UNIFIED IDEOGRAPH-98E3\n98E5..98EB    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-98E5..CJK UNIFIED IDEOGRAPH-98EB\n98ED..98F0    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-98ED..CJK UNIFIED IDEOGRAPH-98F0\n98F2..98F7    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-98F2..CJK UNIFIED IDEOGRAPH-98F7\n98F9..98FA    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-98F9..CJK UNIFIED IDEOGRAPH-98FA\n98FC..9918    ; Recommended                    # 1.1   [29] CJK UNIFIED IDEOGRAPH-98FC..CJK UNIFIED IDEOGRAPH-9918\n991A..993A    ; Recommended                    # 1.1   [33] CJK UNIFIED IDEOGRAPH-991A..CJK UNIFIED IDEOGRAPH-993A\n993C..9943    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-993C..CJK UNIFIED IDEOGRAPH-9943\n9945..9959    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-9945..CJK UNIFIED IDEOGRAPH-9959\n995B..995C    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-995B..CJK UNIFIED IDEOGRAPH-995C\n995E..99BE    ; Recommended                    # 1.1   [97] CJK UNIFIED IDEOGRAPH-995E..CJK UNIFIED IDEOGRAPH-99BE\n99C0..99DF    ; Recommended                    # 1.1   [32] CJK UNIFIED IDEOGRAPH-99C0..CJK UNIFIED IDEOGRAPH-99DF\n99E1..99E5    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-99E1..CJK UNIFIED IDEOGRAPH-99E5\n99E7..99EA    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-99E7..CJK UNIFIED IDEOGRAPH-99EA\n99EC..99F4    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-99EC..CJK UNIFIED IDEOGRAPH-99F4\n99F6..9A0F    ; Recommended                    # 1.1   [26] CJK UNIFIED IDEOGRAPH-99F6..CJK UNIFIED IDEOGRAPH-9A0F\n9A11..9A16    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9A11..CJK UNIFIED IDEOGRAPH-9A16\n9A19..9A3A    ; Recommended                    # 1.1   [34] CJK UNIFIED IDEOGRAPH-9A19..CJK UNIFIED IDEOGRAPH-9A3A\n9A3C..9A50    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-9A3C..CJK UNIFIED IDEOGRAPH-9A50\n9A52..9A57    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9A52..CJK UNIFIED IDEOGRAPH-9A57\n9A59..9A5C    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-9A59..CJK UNIFIED IDEOGRAPH-9A5C\n9A5E..9A62    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-9A5E..CJK UNIFIED IDEOGRAPH-9A62\n9A64..9AA8    ; Recommended                    # 1.1   [69] CJK UNIFIED IDEOGRAPH-9A64..CJK UNIFIED IDEOGRAPH-9AA8\n9AAA..9ABC    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-9AAA..CJK UNIFIED IDEOGRAPH-9ABC\n9ABE..9AC7    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-9ABE..CJK UNIFIED IDEOGRAPH-9AC7\n9AC9..9AD6    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-9AC9..CJK UNIFIED IDEOGRAPH-9AD6\n9AD8..9ADF    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-9AD8..CJK UNIFIED IDEOGRAPH-9ADF\n9AE1..9AE3    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-9AE1..CJK UNIFIED IDEOGRAPH-9AE3\n9AE5..9AE7    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-9AE5..CJK UNIFIED IDEOGRAPH-9AE7\n9AEA..9AEF    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9AEA..CJK UNIFIED IDEOGRAPH-9AEF\n9AF1..9AFF    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-9AF1..CJK UNIFIED IDEOGRAPH-9AFF\n9B01          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-9B01\n9B03..9B08    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9B03..CJK UNIFIED IDEOGRAPH-9B08\n9B0A..9B13    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-9B0A..CJK UNIFIED IDEOGRAPH-9B13\n9B15..9B1A    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9B15..CJK UNIFIED IDEOGRAPH-9B1A\n9B1C..9B33    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-9B1C..CJK UNIFIED IDEOGRAPH-9B33\n9B35..9B3C    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-9B35..CJK UNIFIED IDEOGRAPH-9B3C\n9B3E..9B3F    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9B3E..CJK UNIFIED IDEOGRAPH-9B3F\n9B41..9B4F    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-9B41..CJK UNIFIED IDEOGRAPH-9B4F\n9B51..9B56    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9B51..CJK UNIFIED IDEOGRAPH-9B56\n9B58..9B61    ; Recommended                    # 1.1   [10] CJK UNIFIED IDEOGRAPH-9B58..CJK UNIFIED IDEOGRAPH-9B61\n9B63..9B71    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-9B63..CJK UNIFIED IDEOGRAPH-9B71\n9B73..9B88    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-9B73..CJK UNIFIED IDEOGRAPH-9B88\n9B8A..9B8B    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9B8A..CJK UNIFIED IDEOGRAPH-9B8B\n9B8D..9B98    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-9B8D..CJK UNIFIED IDEOGRAPH-9B98\n9B9A..9BC1    ; Recommended                    # 1.1   [40] CJK UNIFIED IDEOGRAPH-9B9A..CJK UNIFIED IDEOGRAPH-9BC1\n9BC3..9BF5    ; Recommended                    # 1.1   [51] CJK UNIFIED IDEOGRAPH-9BC3..CJK UNIFIED IDEOGRAPH-9BF5\n9BF7..9BFF    ; Recommended                    # 1.1    [9] CJK UNIFIED IDEOGRAPH-9BF7..CJK UNIFIED IDEOGRAPH-9BFF\n9C02          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-9C02\n9C04..9C41    ; Recommended                    # 1.1   [62] CJK UNIFIED IDEOGRAPH-9C04..CJK UNIFIED IDEOGRAPH-9C41\n9C43..9C4E    ; Recommended                    # 1.1   [12] CJK UNIFIED IDEOGRAPH-9C43..CJK UNIFIED IDEOGRAPH-9C4E\n9C50          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-9C50\n9C52..9C60    ; Recommended                    # 1.1   [15] CJK UNIFIED IDEOGRAPH-9C52..CJK UNIFIED IDEOGRAPH-9C60\n9C62..9C63    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9C62..CJK UNIFIED IDEOGRAPH-9C63\n9C65..9C7A    ; Recommended                    # 1.1   [22] CJK UNIFIED IDEOGRAPH-9C65..CJK UNIFIED IDEOGRAPH-9C7A\n9C7C..9D0B    ; Recommended                    # 1.1  [144] CJK UNIFIED IDEOGRAPH-9C7C..CJK UNIFIED IDEOGRAPH-9D0B\n9D0E..9D10    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-9D0E..CJK UNIFIED IDEOGRAPH-9D10\n9D12..9D26    ; Recommended                    # 1.1   [21] CJK UNIFIED IDEOGRAPH-9D12..CJK UNIFIED IDEOGRAPH-9D26\n9D28..9D34    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-9D28..CJK UNIFIED IDEOGRAPH-9D34\n9D36..9D3B    ; Recommended                    # 1.1    [6] CJK UNIFIED IDEOGRAPH-9D36..CJK UNIFIED IDEOGRAPH-9D3B\n9D3D..9D6C    ; Recommended                    # 1.1   [48] CJK UNIFIED IDEOGRAPH-9D3D..CJK UNIFIED IDEOGRAPH-9D6C\n9D6E..9D94    ; Recommended                    # 1.1   [39] CJK UNIFIED IDEOGRAPH-9D6E..CJK UNIFIED IDEOGRAPH-9D94\n9D96..9DAD    ; Recommended                    # 1.1   [24] CJK UNIFIED IDEOGRAPH-9D96..CJK UNIFIED IDEOGRAPH-9DAD\n9DAF..9DBC    ; Recommended                    # 1.1   [14] CJK UNIFIED IDEOGRAPH-9DAF..CJK UNIFIED IDEOGRAPH-9DBC\n9DBE..9DBF    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9DBE..CJK UNIFIED IDEOGRAPH-9DBF\n9DC1..9DE9    ; Recommended                    # 1.1   [41] CJK UNIFIED IDEOGRAPH-9DC1..CJK UNIFIED IDEOGRAPH-9DE9\n9DEB..9DFB    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-9DEB..CJK UNIFIED IDEOGRAPH-9DFB\n9DFD..9E0D    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-9DFD..CJK UNIFIED IDEOGRAPH-9E0D\n9E0F..9E15    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-9E0F..CJK UNIFIED IDEOGRAPH-9E15\n9E17..9E1B    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-9E17..CJK UNIFIED IDEOGRAPH-9E1B\n9E1D..9E7A    ; Recommended                    # 1.1   [94] CJK UNIFIED IDEOGRAPH-9E1D..CJK UNIFIED IDEOGRAPH-9E7A\n9E7C..9E8E    ; Recommended                    # 1.1   [19] CJK UNIFIED IDEOGRAPH-9E7C..CJK UNIFIED IDEOGRAPH-9E8E\n9E91..9E97    ; Recommended                    # 1.1    [7] CJK UNIFIED IDEOGRAPH-9E91..CJK UNIFIED IDEOGRAPH-9E97\n9E99..9E9D    ; Recommended                    # 1.1    [5] CJK UNIFIED IDEOGRAPH-9E99..CJK UNIFIED IDEOGRAPH-9E9D\n9E9F..9EA1    ; Recommended                    # 1.1    [3] CJK UNIFIED IDEOGRAPH-9E9F..CJK UNIFIED IDEOGRAPH-9EA1\n9EA3..9EAA    ; Recommended                    # 1.1    [8] CJK UNIFIED IDEOGRAPH-9EA3..CJK UNIFIED IDEOGRAPH-9EAA\n9EAD..9EB0    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-9EAD..CJK UNIFIED IDEOGRAPH-9EB0\n9EB2..9EEB    ; Recommended                    # 1.1   [58] CJK UNIFIED IDEOGRAPH-9EB2..CJK UNIFIED IDEOGRAPH-9EEB\n9EED..9EF0    ; Recommended                    # 1.1    [4] CJK UNIFIED IDEOGRAPH-9EED..CJK UNIFIED IDEOGRAPH-9EF0\n9EF2..9F02    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-9EF2..CJK UNIFIED IDEOGRAPH-9F02\n9F04..9F10    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-9F04..CJK UNIFIED IDEOGRAPH-9F10\n9F12..9F13    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9F12..CJK UNIFIED IDEOGRAPH-9F13\n9F15..9F25    ; Recommended                    # 1.1   [17] CJK UNIFIED IDEOGRAPH-9F15..CJK UNIFIED IDEOGRAPH-9F25\n9F27..9F44    ; Recommended                    # 1.1   [30] CJK UNIFIED IDEOGRAPH-9F27..CJK UNIFIED IDEOGRAPH-9F44\n9F46..9F52    ; Recommended                    # 1.1   [13] CJK UNIFIED IDEOGRAPH-9F46..CJK UNIFIED IDEOGRAPH-9F52\n9F54..9F6C    ; Recommended                    # 1.1   [25] CJK UNIFIED IDEOGRAPH-9F54..CJK UNIFIED IDEOGRAPH-9F6C\n9F6E..9FA0    ; Recommended                    # 1.1   [51] CJK UNIFIED IDEOGRAPH-9F6E..CJK UNIFIED IDEOGRAPH-9FA0\n9FA2          ; Recommended                    # 1.1        CJK UNIFIED IDEOGRAPH-9FA2\n9FA4..9FA5    ; Recommended                    # 1.1    [2] CJK UNIFIED IDEOGRAPH-9FA4..CJK UNIFIED IDEOGRAPH-9FA5\nA78D          ; Recommended                    # 6.0        LATIN CAPITAL LETTER TURNED H\nA7AA          ; Recommended                    # 6.1        LATIN CAPITAL LETTER H WITH HOOK\nAA7B          ; Recommended                    # 5.2        MYANMAR SIGN PAO KAREN TONE\nAC00..D7A3    ; Recommended                    # 2.0 [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH\n11301         ; Recommended                    # 7.0        GRANTHA SIGN CANDRABINDU\n11303         ; Recommended                    # 7.0        GRANTHA SIGN VISARGA\n1133C         ; Recommended                    # 7.0        GRANTHA SIGN NUKTA\n1E7E0..1E7E6  ; Recommended                    # 14.0   [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO\n1E7E8..1E7EB  ; Recommended                    # 14.0   [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE\n1E7ED..1E7EE  ; Recommended                    # 14.0   [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE\n1E7F0..1E7FE  ; Recommended                    # 14.0  [15] ETHIOPIC SYLLABLE GURAGE QWI..ETHIOPIC SYLLABLE GURAGE PWEE\n2070E         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-2070E\n20731         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20731\n20779         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20779\n20C53         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20C53\n20C78         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20C78\n20C96         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20C96\n20CCF         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20CCF\n20CD5         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20CD5\n20D15         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20D15\n20D7C         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20D7C\n20D7F         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20D7F\n20E0E..20E0F  ; Recommended                    # 3.1    [2] CJK UNIFIED IDEOGRAPH-20E0E..CJK UNIFIED IDEOGRAPH-20E0F\n20E77         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20E77\n20E9D         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20E9D\n20EA2         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20EA2\n20ED7         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20ED7\n20EF9..20EFA  ; Recommended                    # 3.1    [2] CJK UNIFIED IDEOGRAPH-20EF9..CJK UNIFIED IDEOGRAPH-20EFA\n20F2D..20F2E  ; Recommended                    # 3.1    [2] CJK UNIFIED IDEOGRAPH-20F2D..CJK UNIFIED IDEOGRAPH-20F2E\n20F4C         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20F4C\n20FB4         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20FB4\n20FBC         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20FBC\n20FEA         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-20FEA\n2105C         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-2105C\n2106F         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-2106F\n21075..21076  ; Recommended                    # 3.1    [2] CJK UNIFIED IDEOGRAPH-21075..CJK UNIFIED IDEOGRAPH-21076\n2107B         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-2107B\n210C1         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-210C1\n210C9         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-210C9\n211D9         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-211D9\n220C7         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-220C7\n227B5         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-227B5\n22AD5         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22AD5\n22B43         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22B43\n22BCA         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22BCA\n22C51         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22C51\n22C55         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22C55\n22CC2         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22CC2\n22D08         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22D08\n22D4C         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22D4C\n22D67         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22D67\n22EB3         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-22EB3\n23CB7         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-23CB7\n244D3         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-244D3\n24DB8         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-24DB8\n24DEA         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-24DEA\n2512B         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-2512B\n26258         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-26258\n267CC         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-267CC\n269F2         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-269F2\n269FA         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-269FA\n27A3E         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-27A3E\n2815D         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-2815D\n28207         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-28207\n282E2         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-282E2\n28CCA         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-28CCA\n28CCD         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-28CCD\n28CD2         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-28CD2\n29D98         ; Recommended                    # 3.1        CJK UNIFIED IDEOGRAPH-29D98\n\n# Total code points: 33773\n\n#\tIdentifier_Type:\tInclusion\n\n0027          ; Inclusion                      # 1.1        APOSTROPHE\n002D..002E    ; Inclusion                      # 1.1    [2] HYPHEN-MINUS..FULL STOP\n003A          ; Inclusion                      # 1.1        COLON\n00B7          ; Inclusion                      # 1.1        MIDDLE DOT\n02BB..02BC    ; Inclusion                      # 1.1    [2] MODIFIER LETTER TURNED COMMA..MODIFIER LETTER APOSTROPHE\n058A          ; Inclusion                      # 3.0        ARMENIAN HYPHEN\n05F3..05F4    ; Inclusion                      # 1.1    [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM\n06FD..06FE    ; Inclusion                      # 3.0    [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN\n0F0B          ; Inclusion                      # 2.0        TIBETAN MARK INTERSYLLABIC TSHEG\n2010          ; Inclusion                      # 1.1        HYPHEN\n2019          ; Inclusion                      # 1.1        RIGHT SINGLE QUOTATION MARK\n2027          ; Inclusion                      # 1.1        HYPHENATION POINT\n30A0          ; Inclusion                      # 3.2        KATAKANA-HIRAGANA DOUBLE HYPHEN\n30FB          ; Inclusion                      # 1.1        KATAKANA MIDDLE DOT\n\n# Total code points: 18\n\n#\tIdentifier_Type:\tLimited_Use\n\n0710..072C    ; Limited_Use                    # 3.0   [29] SYRIAC LETTER ALAPH..SYRIAC LETTER TAW\n072D..072F    ; Limited_Use                    # 4.0    [3] SYRIAC LETTER PERSIAN BHETH..SYRIAC LETTER PERSIAN DHALATH\n0730..073F    ; Limited_Use                    # 3.0   [16] SYRIAC PTHAHA ABOVE..SYRIAC RWAHA\n074D..074F    ; Limited_Use                    # 4.0    [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE\n07C0..07E7    ; Limited_Use                    # 5.0   [40] NKO DIGIT ZERO..NKO LETTER NYA WOLOSO\n07EB..07F5    ; Limited_Use                    # 5.0   [11] NKO COMBINING SHORT HIGH TONE..NKO LOW TONE APOSTROPHE\n07FD          ; Limited_Use                    # 11.0       NKO DANTAYALAN\n0840..085B    ; Limited_Use                    # 6.0   [28] MANDAIC LETTER HALQA..MANDAIC GEMINATION MARK\n0860..086A    ; Limited_Use                    # 10.0  [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA\n13A0..13F4    ; Limited_Use                    # 3.0   [85] CHEROKEE LETTER A..CHEROKEE LETTER YV\n13F5          ; Limited_Use                    # 8.0        CHEROKEE LETTER MV\n13F8..13FD    ; Limited_Use                    # 8.0    [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV\n1401..166C    ; Limited_Use                    # 3.0  [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA\n166F..1676    ; Limited_Use                    # 3.0    [8] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS NNGAA\n1677..167F    ; Limited_Use                    # 5.2    [9] CANADIAN SYLLABICS WOODS-CREE THWEE..CANADIAN SYLLABICS BLACKFOOT W\n18B0..18F5    ; Limited_Use                    # 5.2   [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S\n1900..191C    ; Limited_Use                    # 4.0   [29] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER HA\n191D..191E    ; Limited_Use                    # 7.0    [2] LIMBU LETTER GYAN..LIMBU LETTER TRA\n1920..192B    ; Limited_Use                    # 4.0   [12] LIMBU VOWEL SIGN A..LIMBU SUBJOINED LETTER WA\n1930..193B    ; Limited_Use                    # 4.0   [12] LIMBU SMALL LETTER KA..LIMBU SIGN SA-I\n1946..196D    ; Limited_Use                    # 4.0   [40] LIMBU DIGIT ZERO..TAI LE LETTER AI\n1970..1974    ; Limited_Use                    # 4.0    [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6\n1980..19A9    ; Limited_Use                    # 4.1   [42] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW XVA\n19AA..19AB    ; Limited_Use                    # 5.2    [2] NEW TAI LUE LETTER HIGH SUA..NEW TAI LUE LETTER LOW SUA\n19B0..19C9    ; Limited_Use                    # 4.1   [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2\n19D0..19D9    ; Limited_Use                    # 4.1   [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE\n19DA          ; Limited_Use                    # 5.2        NEW TAI LUE THAM DIGIT ONE\n1A20..1A5E    ; Limited_Use                    # 5.2   [63] TAI THAM LETTER HIGH KA..TAI THAM CONSONANT SIGN SA\n1A60..1A7C    ; Limited_Use                    # 5.2   [29] TAI THAM SIGN SAKOT..TAI THAM SIGN KHUEN-LUE KARAN\n1A7F..1A89    ; Limited_Use                    # 5.2   [11] TAI THAM COMBINING CRYPTOGRAMMIC DOT..TAI THAM HORA DIGIT NINE\n1A90..1A99    ; Limited_Use                    # 5.2   [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE\n1AA7          ; Limited_Use                    # 5.2        TAI THAM SIGN MAI YAMOK\n1B00..1B4B    ; Limited_Use                    # 5.0   [76] BALINESE SIGN ULU RICEM..BALINESE LETTER ASYURA SASAK\n1B4C          ; Limited_Use                    # 14.0       BALINESE LETTER ARCHAIC JNYA\n1B50..1B59    ; Limited_Use                    # 5.0   [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE\n1B80..1BAA    ; Limited_Use                    # 5.1   [43] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PAMAAEH\n1BAB..1BAD    ; Limited_Use                    # 6.1    [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA\n1BAE..1BB9    ; Limited_Use                    # 5.1   [12] SUNDANESE LETTER KHA..SUNDANESE DIGIT NINE\n1BBA..1BBF    ; Limited_Use                    # 6.1    [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M\n1BC0..1BF3    ; Limited_Use                    # 6.0   [52] BATAK LETTER A..BATAK PANONGONAN\n1C00..1C37    ; Limited_Use                    # 5.1   [56] LEPCHA LETTER KA..LEPCHA SIGN NUKTA\n1C40..1C49    ; Limited_Use                    # 5.1   [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE\n1C4D..1C7D    ; Limited_Use                    # 5.1   [49] LEPCHA LETTER TTA..OL CHIKI AHAD\n2D30..2D65    ; Limited_Use                    # 4.1   [54] TIFINAGH LETTER YA..TIFINAGH LETTER YAZZ\n2D66..2D67    ; Limited_Use                    # 6.1    [2] TIFINAGH LETTER YE..TIFINAGH LETTER YO\n2D7F          ; Limited_Use                    # 6.0        TIFINAGH CONSONANT JOINER\n3105..312C    ; Limited_Use                    # 1.1   [40] BOPOMOFO LETTER B..BOPOMOFO LETTER GN\n312D          ; Limited_Use                    # 5.1        BOPOMOFO LETTER IH\n312F          ; Limited_Use                    # 11.0       BOPOMOFO LETTER NN\n31A0..31B7    ; Limited_Use                    # 3.0   [24] BOPOMOFO LETTER BU..BOPOMOFO FINAL LETTER H\n31B8..31BA    ; Limited_Use                    # 6.0    [3] BOPOMOFO LETTER GH..BOPOMOFO LETTER ZY\n31BB..31BF    ; Limited_Use                    # 13.0   [5] BOPOMOFO FINAL LETTER G..BOPOMOFO LETTER AH\nA000..A48C    ; Limited_Use                    # 3.0 [1165] YI SYLLABLE IT..YI SYLLABLE YYR\nA4D0..A4FD    ; Limited_Use                    # 5.2   [46] LISU LETTER BA..LISU LETTER TONE MYA JEU\nA500..A60C    ; Limited_Use                    # 5.1  [269] VAI SYLLABLE EE..VAI SYLLABLE LENGTHENER\nA613..A629    ; Limited_Use                    # 5.1   [23] VAI SYMBOL FEENG..VAI DIGIT NINE\nA6A0..A6F1    ; Limited_Use                    # 5.2   [82] BAMUM LETTER A..BAMUM COMBINING MARK TUKWENTIS\nA800..A827    ; Limited_Use                    # 4.1   [40] SYLOTI NAGRI LETTER A..SYLOTI NAGRI VOWEL SIGN OO\nA82C          ; Limited_Use                    # 13.0       SYLOTI NAGRI SIGN ALTERNATE HASANTA\nA880..A8C4    ; Limited_Use                    # 5.1   [69] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VIRAMA\nA8C5          ; Limited_Use                    # 9.0        SAURASHTRA SIGN CANDRABINDU\nA8D0..A8D9    ; Limited_Use                    # 5.1   [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE\nA900..A92D    ; Limited_Use                    # 5.1   [46] KAYAH LI DIGIT ZERO..KAYAH LI TONE CALYA PLOPHU\nA980..A9C0    ; Limited_Use                    # 5.2   [65] JAVANESE SIGN PANYANGGA..JAVANESE PANGKON\nA9D0..A9D9    ; Limited_Use                    # 5.2   [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE\nAA00..AA36    ; Limited_Use                    # 5.1   [55] CHAM LETTER A..CHAM CONSONANT SIGN WA\nAA40..AA4D    ; Limited_Use                    # 5.1   [14] CHAM LETTER FINAL K..CHAM CONSONANT SIGN FINAL H\nAA50..AA59    ; Limited_Use                    # 5.1   [10] CHAM DIGIT ZERO..CHAM DIGIT NINE\nAA80..AAC2    ; Limited_Use                    # 5.2   [67] TAI VIET LETTER LOW KO..TAI VIET TONE MAI SONG\nAADB..AADD    ; Limited_Use                    # 5.2    [3] TAI VIET SYMBOL KON..TAI VIET SYMBOL SAM\nAAE0..AAEF    ; Limited_Use                    # 6.1   [16] MEETEI MAYEK LETTER E..MEETEI MAYEK VOWEL SIGN AAU\nAAF2..AAF6    ; Limited_Use                    # 6.1    [5] MEETEI MAYEK ANJI..MEETEI MAYEK VIRAMA\nAB70..ABBF    ; Limited_Use                    # 8.0   [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA\nABC0..ABEA    ; Limited_Use                    # 5.2   [43] MEETEI MAYEK LETTER KOK..MEETEI MAYEK VOWEL SIGN NUNG\nABEC..ABED    ; Limited_Use                    # 5.2    [2] MEETEI MAYEK LUM IYEK..MEETEI MAYEK APUN IYEK\nABF0..ABF9    ; Limited_Use                    # 5.2   [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE\n104B0..104D3  ; Limited_Use                    # 9.0   [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA\n104D8..104FB  ; Limited_Use                    # 9.0   [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA\n10D00..10D27  ; Limited_Use                    # 11.0  [40] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA SIGN TASSI\n10D30..10D39  ; Limited_Use                    # 11.0  [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE\n11100..11134  ; Limited_Use                    # 6.1   [53] CHAKMA SIGN CANDRABINDU..CHAKMA MAAYYAA\n11136..1113F  ; Limited_Use                    # 6.1   [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE\n11144..11146  ; Limited_Use                    # 11.0   [3] CHAKMA LETTER LHAA..CHAKMA VOWEL SIGN EI\n11147         ; Limited_Use                    # 13.0       CHAKMA LETTER VAA\n11400..1144A  ; Limited_Use                    # 9.0   [75] NEWA LETTER A..NEWA SIDDHI\n11450..11459  ; Limited_Use                    # 9.0   [10] NEWA DIGIT ZERO..NEWA DIGIT NINE\n1145E         ; Limited_Use                    # 11.0       NEWA SANDHI MARK\n1145F         ; Limited_Use                    # 12.0       NEWA LETTER VEDIC ANUSVARA\n11460..11461  ; Limited_Use                    # 13.0   [2] NEWA SIGN JIHVAMULIYA..NEWA SIGN UPADHMANIYA\n11AB0..11ABF  ; Limited_Use                    # 14.0  [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA\n11FB0         ; Limited_Use                    # 13.0       LISU LETTER YHA\n16800..16A38  ; Limited_Use                    # 6.0  [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ\n16F00..16F44  ; Limited_Use                    # 6.1   [69] MIAO LETTER PA..MIAO LETTER HHA\n16F45..16F4A  ; Limited_Use                    # 12.0   [6] MIAO LETTER BRI..MIAO LETTER RTE\n16F4F         ; Limited_Use                    # 12.0       MIAO SIGN CONSONANT MODIFIER BAR\n16F50..16F7E  ; Limited_Use                    # 6.1   [47] MIAO LETTER NASALIZATION..MIAO VOWEL SIGN NG\n16F7F..16F87  ; Limited_Use                    # 12.0   [9] MIAO VOWEL SIGN UOG..MIAO VOWEL SIGN UI\n16F8F..16F9F  ; Limited_Use                    # 6.1   [17] MIAO TONE RIGHT..MIAO LETTER REFORMED TONE-8\n1E100..1E12C  ; Limited_Use                    # 12.0  [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W\n1E130..1E13D  ; Limited_Use                    # 12.0  [14] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER\n1E140..1E149  ; Limited_Use                    # 12.0  [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE\n1E14E         ; Limited_Use                    # 12.0       NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ\n1E2C0..1E2F9  ; Limited_Use                    # 12.0  [58] WANCHO LETTER AA..WANCHO DIGIT NINE\n1E900..1E94A  ; Limited_Use                    # 9.0   [75] ADLAM CAPITAL LETTER ALIF..ADLAM NUKTA\n1E94B         ; Limited_Use                    # 12.0       ADLAM NASALIZATION MARK\n1E950..1E959  ; Limited_Use                    # 9.0   [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE\n\n# Total code points: 5044\n\n#\tIdentifier_Type:\tLimited_Use Uncommon_Use\n\nA9CF          ; Limited_Use Uncommon_Use       # 5.2        JAVANESE PANGRANGKEP\n\n# Total code points: 1\n\n#\tIdentifier_Type:\tLimited_Use Technical\n\n0740..074A    ; Limited_Use Technical          # 3.0   [11] SYRIAC FEMININE DOT..SYRIAC BARREKH\n1B6B..1B73    ; Limited_Use Technical          # 5.0    [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG\n1DFA          ; Limited_Use Technical          # 14.0       COMBINING DOT BELOW LEFT\n\n# Total code points: 21\n\n#\tIdentifier_Type:\tLimited_Use Obsolete\n\n07E8..07EA    ; Limited_Use Obsolete           # 5.0    [3] NKO LETTER JONA JA..NKO LETTER JONA RA\n07FA          ; Limited_Use Obsolete           # 5.0        NKO LAJANYALAN\n312E          ; Limited_Use Obsolete           # 10.0       BOPOMOFO LETTER O WITH DOT ABOVE\nA610..A612    ; Limited_Use Obsolete           # 5.1    [3] VAI SYLLABLE NDOLE FA..VAI SYLLABLE NDOLE SOO\nA62A..A62B    ; Limited_Use Obsolete           # 5.1    [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO\n\n# Total code points: 10\n\n#\tIdentifier_Type:\tLimited_Use Not_XID\n\n02EA..02EB    ; Limited_Use Not_XID            # 3.0    [2] MODIFIER LETTER YIN DEPARTING TONE MARK..MODIFIER LETTER YANG DEPARTING TONE MARK\n0700..070D    ; Limited_Use Not_XID            # 3.0   [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS\n070F          ; Limited_Use Not_XID            # 3.0        SYRIAC ABBREVIATION MARK\n07F6..07F9    ; Limited_Use Not_XID            # 5.0    [4] NKO SYMBOL OO DENNEN..NKO EXCLAMATION MARK\n07FE..07FF    ; Limited_Use Not_XID            # 11.0   [2] NKO DOROME SIGN..NKO TAMAN SIGN\n085E          ; Limited_Use Not_XID            # 6.0        MANDAIC PUNCTUATION\n1400          ; Limited_Use Not_XID            # 5.2        CANADIAN SYLLABICS HYPHEN\n166D..166E    ; Limited_Use Not_XID            # 3.0    [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP\n1940          ; Limited_Use Not_XID            # 4.0        LIMBU SIGN LOO\n1944..1945    ; Limited_Use Not_XID            # 4.0    [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK\n19DE..19DF    ; Limited_Use Not_XID            # 4.1    [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV\n1AA0..1AA6    ; Limited_Use Not_XID            # 5.2    [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA\n1AA8..1AAD    ; Limited_Use Not_XID            # 5.2    [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG\n1B4E..1B4F    ; Limited_Use Not_XID            # 16.0   [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN\n1B5A..1B6A    ; Limited_Use Not_XID            # 5.0   [17] BALINESE PANTI..BALINESE MUSICAL SYMBOL DANG GEDE\n1B74..1B7C    ; Limited_Use Not_XID            # 5.0    [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING\n1B7D..1B7E    ; Limited_Use Not_XID            # 14.0   [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG\n1B7F          ; Limited_Use Not_XID            # 16.0       BALINESE PANTI BAWAK\n1BFC..1BFF    ; Limited_Use Not_XID            # 6.0    [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT\n1C3B..1C3F    ; Limited_Use Not_XID            # 5.1    [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK\n1C7E..1C7F    ; Limited_Use Not_XID            # 5.1    [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD\n1CC0..1CC7    ; Limited_Use Not_XID            # 6.1    [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA\n2D70          ; Limited_Use Not_XID            # 6.0        TIFINAGH SEPARATOR MARK\nA490..A4A1    ; Limited_Use Not_XID            # 3.0   [18] YI RADICAL QOT..YI RADICAL GA\nA4A2..A4A3    ; Limited_Use Not_XID            # 3.2    [2] YI RADICAL ZUP..YI RADICAL CYT\nA4A4..A4B3    ; Limited_Use Not_XID            # 3.0   [16] YI RADICAL DDUR..YI RADICAL JO\nA4B4          ; Limited_Use Not_XID            # 3.2        YI RADICAL NZUP\nA4B5..A4C0    ; Limited_Use Not_XID            # 3.0   [12] YI RADICAL JJY..YI RADICAL SHAT\nA4C1          ; Limited_Use Not_XID            # 3.2        YI RADICAL ZUR\nA4C2..A4C4    ; Limited_Use Not_XID            # 3.0    [3] YI RADICAL SHOP..YI RADICAL ZZIET\nA4C5          ; Limited_Use Not_XID            # 3.2        YI RADICAL NBIE\nA4C6          ; Limited_Use Not_XID            # 3.0        YI RADICAL KE\nA4FE..A4FF    ; Limited_Use Not_XID            # 5.2    [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP\nA60D..A60F    ; Limited_Use Not_XID            # 5.1    [3] VAI COMMA..VAI QUESTION MARK\nA6F2..A6F7    ; Limited_Use Not_XID            # 5.2    [6] BAMUM NJAEMLI..BAMUM QUESTION MARK\nA828..A82B    ; Limited_Use Not_XID            # 4.1    [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4\nA8CE..A8CF    ; Limited_Use Not_XID            # 5.1    [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA\nA92F          ; Limited_Use Not_XID            # 5.1        KAYAH LI SIGN SHYA\nA9C1..A9CD    ; Limited_Use Not_XID            # 5.2   [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH\nA9DE..A9DF    ; Limited_Use Not_XID            # 5.2    [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN\nAA5C..AA5F    ; Limited_Use Not_XID            # 5.1    [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA\nAADE..AADF    ; Limited_Use Not_XID            # 5.2    [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI\nAAF0..AAF1    ; Limited_Use Not_XID            # 6.1    [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM\nABEB          ; Limited_Use Not_XID            # 5.2        MEETEI MAYEK CHEIKHEI\n11140..11143  ; Limited_Use Not_XID            # 6.1    [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK\n1144B..1144F  ; Limited_Use Not_XID            # 9.0    [5] NEWA DANDA..NEWA ABBREVIATION SIGN\n1145A         ; Limited_Use Not_XID            # 13.0       NEWA DOUBLE COMMA\n1145B         ; Limited_Use Not_XID            # 9.0        NEWA PLACEHOLDER MARK\n1145D         ; Limited_Use Not_XID            # 9.0        NEWA INSERTION SIGN\n1E14F         ; Limited_Use Not_XID            # 12.0       NYIAKENG PUACHUE HMONG CIRCLED CA\n1E2FF         ; Limited_Use Not_XID            # 12.0       WANCHO NGUN SIGN\n1E95E..1E95F  ; Limited_Use Not_XID            # 9.0    [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK\n\n# Total code points: 209\n\n#\tIdentifier_Type:\tUncommon_Use\n\n0114..0115    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER E WITH BREVE..LATIN SMALL LETTER E WITH BREVE\n012C..012D    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER I WITH BREVE..LATIN SMALL LETTER I WITH BREVE\n014E..014F    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER O WITH BREVE..LATIN SMALL LETTER O WITH BREVE\n0156..0157    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER R WITH CEDILLA..LATIN SMALL LETTER R WITH CEDILLA\n0162..0163    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER T WITH CEDILLA..LATIN SMALL LETTER T WITH CEDILLA\n0182..0185    ; Uncommon_Use                   # 1.1    [4] LATIN CAPITAL LETTER B WITH TOPBAR..LATIN SMALL LETTER TONE SIX\n0187..0188    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER C WITH HOOK..LATIN SMALL LETTER C WITH HOOK\n018B..018C    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER D WITH TOPBAR..LATIN SMALL LETTER D WITH TOPBAR\n0193          ; Uncommon_Use                   # 1.1        LATIN CAPITAL LETTER G WITH HOOK\n0195          ; Uncommon_Use                   # 1.1        LATIN SMALL LETTER HV\n019A..019C    ; Uncommon_Use                   # 1.1    [3] LATIN SMALL LETTER L WITH BAR..LATIN CAPITAL LETTER TURNED M\n019E..019F    ; Uncommon_Use                   # 1.1    [2] LATIN SMALL LETTER N WITH LONG RIGHT LEG..LATIN CAPITAL LETTER O WITH MIDDLE TILDE\n01A2..01A9    ; Uncommon_Use                   # 1.1    [8] LATIN CAPITAL LETTER OI..LATIN CAPITAL LETTER ESH\n01AC..01AE    ; Uncommon_Use                   # 1.1    [3] LATIN CAPITAL LETTER T WITH HOOK..LATIN CAPITAL LETTER T WITH RETROFLEX HOOK\n01B1          ; Uncommon_Use                   # 1.1        LATIN CAPITAL LETTER UPSILON\n01B5..01B6    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER Z WITH STROKE..LATIN SMALL LETTER Z WITH STROKE\n01B8          ; Uncommon_Use                   # 1.1        LATIN CAPITAL LETTER EZH REVERSED\n01BC..01BD    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER TONE FIVE..LATIN SMALL LETTER TONE FIVE\n01D5..01DC    ; Uncommon_Use                   # 1.1    [8] LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON..LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE\n01DE..01E5    ; Uncommon_Use                   # 1.1    [8] LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON..LATIN SMALL LETTER G WITH STROKE\n01EA..01ED    ; Uncommon_Use                   # 1.1    [4] LATIN CAPITAL LETTER O WITH OGONEK..LATIN SMALL LETTER O WITH OGONEK AND MACRON\n01F0          ; Uncommon_Use                   # 1.1        LATIN SMALL LETTER J WITH CARON\n01F4..01F5    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER G WITH ACUTE..LATIN SMALL LETTER G WITH ACUTE\n01FA..01FF    ; Uncommon_Use                   # 1.1    [6] LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE..LATIN SMALL LETTER O WITH STROKE AND ACUTE\n021E..021F    ; Uncommon_Use                   # 3.0    [2] LATIN CAPITAL LETTER H WITH CARON..LATIN SMALL LETTER H WITH CARON\n0220          ; Uncommon_Use                   # 3.2        LATIN CAPITAL LETTER N WITH LONG RIGHT LEG\n0221          ; Uncommon_Use                   # 4.0        LATIN SMALL LETTER D WITH CURL\n0222..0233    ; Uncommon_Use                   # 3.0   [18] LATIN CAPITAL LETTER OU..LATIN SMALL LETTER Y WITH MACRON\n0237..0241    ; Uncommon_Use                   # 4.1   [11] LATIN SMALL LETTER DOTLESS J..LATIN CAPITAL LETTER GLOTTAL STOP\n0242..0243    ; Uncommon_Use                   # 5.0    [2] LATIN SMALL LETTER GLOTTAL STOP..LATIN CAPITAL LETTER B WITH STROKE\n0245..024B    ; Uncommon_Use                   # 5.0    [7] LATIN CAPITAL LETTER TURNED V..LATIN SMALL LETTER Q WITH HOOK TAIL\n024E..024F    ; Uncommon_Use                   # 5.0    [2] LATIN CAPITAL LETTER Y WITH STROKE..LATIN SMALL LETTER Y WITH STROKE\n0305          ; Uncommon_Use                   # 1.1        COMBINING OVERLINE\n030D          ; Uncommon_Use                   # 1.1        COMBINING VERTICAL LINE ABOVE\n0316          ; Uncommon_Use                   # 1.1        COMBINING GRAVE ACCENT BELOW\n0321..0322    ; Uncommon_Use                   # 1.1    [2] COMBINING PALATALIZED HOOK BELOW..COMBINING RETROFLEX HOOK BELOW\n0332          ; Uncommon_Use                   # 1.1        COMBINING LOW LINE\n0334          ; Uncommon_Use                   # 1.1        COMBINING TILDE OVERLAY\n0336          ; Uncommon_Use                   # 1.1        COMBINING LONG STROKE OVERLAY\n0358          ; Uncommon_Use                   # 4.1        COMBINING DOT ABOVE RIGHT\n0400          ; Uncommon_Use                   # 3.0        CYRILLIC CAPITAL LETTER IE WITH GRAVE\n040D          ; Uncommon_Use                   # 3.0        CYRILLIC CAPITAL LETTER I WITH GRAVE\n0450          ; Uncommon_Use                   # 3.0        CYRILLIC SMALL LETTER IE WITH GRAVE\n045D          ; Uncommon_Use                   # 3.0        CYRILLIC SMALL LETTER I WITH GRAVE\n048A..048B    ; Uncommon_Use                   # 3.2    [2] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER SHORT I WITH TAIL\n048C..048F    ; Uncommon_Use                   # 3.0    [4] CYRILLIC CAPITAL LETTER SEMISOFT SIGN..CYRILLIC SMALL LETTER ER WITH TICK\n04C1..04C4    ; Uncommon_Use                   # 1.1    [4] CYRILLIC CAPITAL LETTER ZHE WITH BREVE..CYRILLIC SMALL LETTER KA WITH HOOK\n04C5..04C6    ; Uncommon_Use                   # 3.2    [2] CYRILLIC CAPITAL LETTER EL WITH TAIL..CYRILLIC SMALL LETTER EL WITH TAIL\n04C7..04C8    ; Uncommon_Use                   # 1.1    [2] CYRILLIC CAPITAL LETTER EN WITH HOOK..CYRILLIC SMALL LETTER EN WITH HOOK\n04C9..04CA    ; Uncommon_Use                   # 3.2    [2] CYRILLIC CAPITAL LETTER EN WITH TAIL..CYRILLIC SMALL LETTER EN WITH TAIL\n04CB..04CC    ; Uncommon_Use                   # 1.1    [2] CYRILLIC CAPITAL LETTER KHAKASSIAN CHE..CYRILLIC SMALL LETTER KHAKASSIAN CHE\n04CD..04CE    ; Uncommon_Use                   # 3.2    [2] CYRILLIC CAPITAL LETTER EM WITH TAIL..CYRILLIC SMALL LETTER EM WITH TAIL\n04DA..04DB    ; Uncommon_Use                   # 1.1    [2] CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS..CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS\n04EA..04EB    ; Uncommon_Use                   # 1.1    [2] CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS..CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS\n04EC..04ED    ; Uncommon_Use                   # 3.0    [2] CYRILLIC CAPITAL LETTER E WITH DIAERESIS..CYRILLIC SMALL LETTER E WITH DIAERESIS\n04F6..04F7    ; Uncommon_Use                   # 4.1    [2] CYRILLIC CAPITAL LETTER GHE WITH DESCENDER..CYRILLIC SMALL LETTER GHE WITH DESCENDER\n04FA..04FF    ; Uncommon_Use                   # 5.0    [6] CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK..CYRILLIC SMALL LETTER HA WITH STROKE\n0510..0513    ; Uncommon_Use                   # 5.0    [4] CYRILLIC CAPITAL LETTER REVERSED ZE..CYRILLIC SMALL LETTER EL WITH HOOK\n0591..05A1    ; Uncommon_Use                   # 2.0   [17] HEBREW ACCENT ETNAHTA..HEBREW ACCENT PAZER\n05A3..05AF    ; Uncommon_Use                   # 2.0   [13] HEBREW ACCENT MUNAH..HEBREW MARK MASORA CIRCLE\n05B0..05B9    ; Uncommon_Use                   # 1.1   [10] HEBREW POINT SHEVA..HEBREW POINT HOLAM\n05BA          ; Uncommon_Use                   # 5.0        HEBREW POINT HOLAM HASER FOR VAV\n05BB..05BD    ; Uncommon_Use                   # 1.1    [3] HEBREW POINT QUBUTS..HEBREW POINT METEG\n05BF          ; Uncommon_Use                   # 1.1        HEBREW POINT RAFE\n05C1..05C2    ; Uncommon_Use                   # 1.1    [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT\n05C4          ; Uncommon_Use                   # 2.0        HEBREW MARK UPPER DOT\n05EF          ; Uncommon_Use                   # 11.0       HEBREW YOD TRIANGLE\n05F0..05F2    ; Uncommon_Use                   # 1.1    [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD\n0610..0615    ; Uncommon_Use                   # 4.0    [6] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL HIGH TAH\n0616..061A    ; Uncommon_Use                   # 5.1    [5] ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH..ARABIC SMALL KASRA\n0656..0658    ; Uncommon_Use                   # 4.0    [3] ARABIC SUBSCRIPT ALEF..ARABIC MARK NOON GHUNNA\n0659..065E    ; Uncommon_Use                   # 4.1    [6] ARABIC ZWARAKAY..ARABIC FATHA WITH TWO DOTS\n065F          ; Uncommon_Use                   # 6.0        ARABIC WAVY HAMZA BELOW\n069B..069E    ; Uncommon_Use                   # 1.1    [4] ARABIC LETTER SEEN WITH THREE DOTS BELOW..ARABIC LETTER SAD WITH THREE DOTS ABOVE\n06A1          ; Uncommon_Use                   # 1.1        ARABIC LETTER DOTLESS FEH\n06A3          ; Uncommon_Use                   # 1.1        ARABIC LETTER FEH WITH DOT BELOW\n06B2          ; Uncommon_Use                   # 1.1        ARABIC LETTER GAF WITH TWO DOTS BELOW\n06B4          ; Uncommon_Use                   # 1.1        ARABIC LETTER GAF WITH THREE DOTS ABOVE\n06B8..06B9    ; Uncommon_Use                   # 3.0    [2] ARABIC LETTER LAM WITH THREE DOTS BELOW..ARABIC LETTER NOON WITH DOT BELOW\n06BF          ; Uncommon_Use                   # 3.0        ARABIC LETTER TCHEH WITH DOT ABOVE\n06D6..06DC    ; Uncommon_Use                   # 1.1    [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN\n06DF..06E4    ; Uncommon_Use                   # 1.1    [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA\n06E7..06E8    ; Uncommon_Use                   # 1.1    [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON\n06EA..06ED    ; Uncommon_Use                   # 1.1    [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM\n06FA..06FC    ; Uncommon_Use                   # 3.0    [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW\n0750          ; Uncommon_Use                   # 4.1        ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW\n0753..0755    ; Uncommon_Use                   # 4.1    [3] ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE..ARABIC LETTER BEH WITH INVERTED SMALL V BELOW\n0757..075F    ; Uncommon_Use                   # 4.1    [9] ARABIC LETTER HAH WITH TWO DOTS ABOVE..ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE\n0761          ; Uncommon_Use                   # 4.1        ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW\n0764..0765    ; Uncommon_Use                   # 4.1    [2] ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW..ARABIC LETTER MEEM WITH DOT ABOVE\n0769          ; Uncommon_Use                   # 4.1        ARABIC LETTER NOON WITH SMALL V\n076B..076D    ; Uncommon_Use                   # 4.1    [3] ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE..ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE\n0772..077D    ; Uncommon_Use                   # 5.1   [12] ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE..ARABIC LETTER SEEN WITH EXTENDED ARABIC-INDIC DIGIT FOUR ABOVE\n0889..088D    ; Uncommon_Use                   # 14.0   [5] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER KEHEH WITH TWO DOTS VERTICALLY BELOW\n0897          ; Uncommon_Use                   # 16.0       ARABIC PEPET\n0898..089F    ; Uncommon_Use                   # 14.0   [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA\n08A1          ; Uncommon_Use                   # 7.0        ARABIC LETTER BEH WITH HAMZA ABOVE\n08AA..08AC    ; Uncommon_Use                   # 6.1    [3] ARABIC LETTER REH WITH LOOP..ARABIC LETTER ROHINGYA YEH\n08B2          ; Uncommon_Use                   # 7.0        ARABIC LETTER ZAIN WITH INVERTED V ABOVE\n08B3..08B4    ; Uncommon_Use                   # 8.0    [2] ARABIC LETTER AIN WITH THREE DOTS BELOW..ARABIC LETTER KAF WITH DOT BELOW\n08B6..08BA    ; Uncommon_Use                   # 9.0    [5] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE\n08C3..08C6    ; Uncommon_Use                   # 13.0   [4] ARABIC LETTER GHAIN WITH THREE DOTS ABOVE..ARABIC LETTER JEEM WITH THREE DOTS BELOW\n08C8          ; Uncommon_Use                   # 14.0       ARABIC LETTER GRAF\n08CA..08D2    ; Uncommon_Use                   # 14.0   [9] ARABIC SMALL HIGH FARSI YEH..ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW\n08D3          ; Uncommon_Use                   # 11.0       ARABIC SMALL LOW WAW\n08D4..08E1    ; Uncommon_Use                   # 9.0   [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA\n08E3          ; Uncommon_Use                   # 8.0        ARABIC TURNED DAMMA BELOW\n08E4..08FE    ; Uncommon_Use                   # 6.1   [27] ARABIC CURLY FATHA..ARABIC DAMMA WITH DOT\n08FF          ; Uncommon_Use                   # 7.0        ARABIC MARK SIDEWAYS NOON GHUNNA\n0900          ; Uncommon_Use                   # 5.2        DEVANAGARI SIGN INVERTED CANDRABINDU\n0904          ; Uncommon_Use                   # 4.0        DEVANAGARI LETTER SHORT A\n0929          ; Uncommon_Use                   # 1.1        DEVANAGARI LETTER NNNA\n0934          ; Uncommon_Use                   # 1.1        DEVANAGARI LETTER LLLA\n0944          ; Uncommon_Use                   # 1.1        DEVANAGARI VOWEL SIGN VOCALIC RR\n0955          ; Uncommon_Use                   # 5.2        DEVANAGARI VOWEL SIGN CANDRA LONG E\n0979..097A    ; Uncommon_Use                   # 5.2    [2] DEVANAGARI LETTER ZHA..DEVANAGARI LETTER HEAVY YA\n098C          ; Uncommon_Use                   # 1.1        BENGALI LETTER VOCALIC L\n09D7          ; Uncommon_Use                   # 1.1        BENGALI AU LENGTH MARK\n09FE          ; Uncommon_Use                   # 11.0       BENGALI SANDHI MARK\n0A01          ; Uncommon_Use                   # 4.0        GURMUKHI SIGN ADAK BINDI\n0A03          ; Uncommon_Use                   # 4.0        GURMUKHI SIGN VISARGA\n0A51          ; Uncommon_Use                   # 5.1        GURMUKHI SIGN UDAAT\n0A66..0A6F    ; Uncommon_Use                   # 1.1   [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE\n0A72..0A73    ; Uncommon_Use                   # 1.1    [2] GURMUKHI IRI..GURMUKHI URA\n0A75          ; Uncommon_Use                   # 5.1        GURMUKHI SIGN YAKASH\n0A81          ; Uncommon_Use                   # 1.1        GUJARATI SIGN CANDRABINDU\n0AF9          ; Uncommon_Use                   # 8.0        GUJARATI LETTER ZHA\n0AFA..0AFF    ; Uncommon_Use                   # 10.0   [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE\n0B0C          ; Uncommon_Use                   # 1.1        ORIYA LETTER VOCALIC L\n0B35          ; Uncommon_Use                   # 4.0        ORIYA LETTER VA\n0B44          ; Uncommon_Use                   # 5.1        ORIYA VOWEL SIGN VOCALIC RR\n0B55          ; Uncommon_Use                   # 13.0       ORIYA SIGN OVERLINE\n0B57          ; Uncommon_Use                   # 1.1        ORIYA AU LENGTH MARK\n0B62..0B63    ; Uncommon_Use                   # 5.1    [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL\n0B66..0B6F    ; Uncommon_Use                   # 1.1   [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE\n0BD7          ; Uncommon_Use                   # 1.1        TAMIL AU LENGTH MARK\n0BE6          ; Uncommon_Use                   # 4.1        TAMIL DIGIT ZERO\n0BE7..0BEF    ; Uncommon_Use                   # 1.1    [9] TAMIL DIGIT ONE..TAMIL DIGIT NINE\n0C01          ; Uncommon_Use                   # 1.1        TELUGU SIGN CANDRABINDU\n0C04          ; Uncommon_Use                   # 11.0       TELUGU SIGN COMBINING ANUSVARA ABOVE\n0C0C          ; Uncommon_Use                   # 1.1        TELUGU LETTER VOCALIC L\n0C31          ; Uncommon_Use                   # 1.1        TELUGU LETTER RRA\n0C3C          ; Uncommon_Use                   # 14.0       TELUGU SIGN NUKTA\n0C55..0C56    ; Uncommon_Use                   # 1.1    [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK\n0C5A          ; Uncommon_Use                   # 8.0        TELUGU LETTER RRRA\n0C5D          ; Uncommon_Use                   # 14.0       TELUGU LETTER NAKAARA POLLU\n0C62..0C63    ; Uncommon_Use                   # 5.1    [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL\n0C66..0C6F    ; Uncommon_Use                   # 1.1   [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE\n0C80          ; Uncommon_Use                   # 9.0        KANNADA SIGN SPACING CANDRABINDU\n0CBC          ; Uncommon_Use                   # 4.0        KANNADA SIGN NUKTA\n0CC4          ; Uncommon_Use                   # 1.1        KANNADA VOWEL SIGN VOCALIC RR\n0CD5..0CD6    ; Uncommon_Use                   # 1.1    [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK\n0CDD          ; Uncommon_Use                   # 14.0       KANNADA LETTER NAKAARA POLLU\n0CF3          ; Uncommon_Use                   # 15.0       KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT\n0D00          ; Uncommon_Use                   # 10.0       MALAYALAM SIGN COMBINING ANUSVARA ABOVE\n0D0C          ; Uncommon_Use                   # 1.1        MALAYALAM LETTER VOCALIC L\n0D29          ; Uncommon_Use                   # 6.0        MALAYALAM LETTER NNNA\n0D44          ; Uncommon_Use                   # 5.1        MALAYALAM VOWEL SIGN VOCALIC RR\n0D54..0D56    ; Uncommon_Use                   # 9.0    [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL\n0D62..0D63    ; Uncommon_Use                   # 5.1    [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL\n0D66..0D6F    ; Uncommon_Use                   # 1.1   [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE\n0D8E          ; Uncommon_Use                   # 3.0        SINHALA LETTER IRUUYANNA\n0DE6..0DEF    ; Uncommon_Use                   # 7.0   [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE\n0E4E          ; Uncommon_Use                   # 1.1        THAI CHARACTER YAMAKKAN\n0E86          ; Uncommon_Use                   # 12.0       LAO LETTER PALI GHA\n0E89          ; Uncommon_Use                   # 12.0       LAO LETTER PALI CHA\n0E8C          ; Uncommon_Use                   # 12.0       LAO LETTER PALI JHA\n0E8E..0E93    ; Uncommon_Use                   # 12.0   [6] LAO LETTER PALI NYA..LAO LETTER PALI NNA\n0E98          ; Uncommon_Use                   # 12.0       LAO LETTER PALI DHA\n0EA0          ; Uncommon_Use                   # 12.0       LAO LETTER PALI BHA\n0EA8..0EA9    ; Uncommon_Use                   # 12.0   [2] LAO LETTER SANSKRIT SHA..LAO LETTER SANSKRIT SSA\n0EAC          ; Uncommon_Use                   # 12.0       LAO LETTER PALI LLA\n0EBA          ; Uncommon_Use                   # 12.0       LAO SIGN PALI VIRAMA\n0ECE          ; Uncommon_Use                   # 15.0       LAO YAMAKKAN\n0EDE..0EDF    ; Uncommon_Use                   # 6.1    [2] LAO LETTER KHMU GO..LAO LETTER KHMU NYO\n0F39          ; Uncommon_Use                   # 2.0        TIBETAN MARK TSA -PHRU\n0F6B..0F6C    ; Uncommon_Use                   # 5.1    [2] TIBETAN LETTER KKA..TIBETAN LETTER RRA\n0FAE..0FB0    ; Uncommon_Use                   # 3.0    [3] TIBETAN SUBJOINED LETTER ZHA..TIBETAN SUBJOINED LETTER -A\n1065..1074    ; Uncommon_Use                   # 5.1   [16] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR VOWEL SIGN KAYAH EE\n108B..108E    ; Uncommon_Use                   # 5.1    [4] MYANMAR SIGN SHAN COUNCIL TONE-2..MYANMAR LETTER RUMAI PALAUNG FA\n1090..1099    ; Uncommon_Use                   # 5.1   [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE\n109A..109D    ; Uncommon_Use                   # 5.2    [4] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON AI\n10F7..10F8    ; Uncommon_Use                   # 3.2    [2] GEORGIAN LETTER YN..GEORGIAN LETTER ELIFI\n10FD..10FF    ; Uncommon_Use                   # 6.1    [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN\n1207          ; Uncommon_Use                   # 4.1        ETHIOPIC SYLLABLE HOA\n1287          ; Uncommon_Use                   # 4.1        ETHIOPIC SYLLABLE XOA\n12AF          ; Uncommon_Use                   # 4.1        ETHIOPIC SYLLABLE KOA\n12F8..12FF    ; Uncommon_Use                   # 3.0    [8] ETHIOPIC SYLLABLE DDA..ETHIOPIC SYLLABLE DDWA\n130F          ; Uncommon_Use                   # 4.1        ETHIOPIC SYLLABLE GOA\n131F          ; Uncommon_Use                   # 4.1        ETHIOPIC SYLLABLE GGWAA\n1347          ; Uncommon_Use                   # 4.1        ETHIOPIC SYLLABLE TZOA\n135A          ; Uncommon_Use                   # 3.0        ETHIOPIC SYLLABLE FYA\n135D..135E    ; Uncommon_Use                   # 6.0    [2] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING VOWEL LENGTH MARK\n135F          ; Uncommon_Use                   # 4.1        ETHIOPIC COMBINING GEMINATION MARK\n1380..138F    ; Uncommon_Use                   # 4.1   [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE\n179D..179E    ; Uncommon_Use                   # 3.0    [2] KHMER LETTER SHA..KHMER LETTER SSO\n17A9          ; Uncommon_Use                   # 3.0        KHMER INDEPENDENT VOWEL QUU\n17D7          ; Uncommon_Use                   # 3.0        KHMER SIGN LEK TOO\n1AC1..1ACE    ; Uncommon_Use                   # 14.0  [14] COMBINING LEFT PARENTHESIS ABOVE LEFT..COMBINING LATIN SMALL LETTER INSULAR T\n1C89..1C8A    ; Uncommon_Use                   # 16.0   [2] CYRILLIC CAPITAL LETTER TJE..CYRILLIC SMALL LETTER TJE\n1E02..1E0B    ; Uncommon_Use                   # 1.1   [10] LATIN CAPITAL LETTER B WITH DOT ABOVE..LATIN SMALL LETTER D WITH DOT ABOVE\n1E0E..1E11    ; Uncommon_Use                   # 1.1    [4] LATIN CAPITAL LETTER D WITH LINE BELOW..LATIN SMALL LETTER D WITH CEDILLA\n1E14..1E17    ; Uncommon_Use                   # 1.1    [4] LATIN CAPITAL LETTER E WITH MACRON AND GRAVE..LATIN SMALL LETTER E WITH MACRON AND ACUTE\n1E1C..1E1F    ; Uncommon_Use                   # 1.1    [4] LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE..LATIN SMALL LETTER F WITH DOT ABOVE\n1E22..1E23    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER H WITH DOT ABOVE..LATIN SMALL LETTER H WITH DOT ABOVE\n1E26..1E29    ; Uncommon_Use                   # 1.1    [4] LATIN CAPITAL LETTER H WITH DIAERESIS..LATIN SMALL LETTER H WITH CEDILLA\n1E2E..1E35    ; Uncommon_Use                   # 1.1    [8] LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE..LATIN SMALL LETTER K WITH LINE BELOW\n1E38..1E3B    ; Uncommon_Use                   # 1.1    [4] LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON..LATIN SMALL LETTER L WITH LINE BELOW\n1E40..1E41    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER M WITH DOT ABOVE..LATIN SMALL LETTER M WITH DOT ABOVE\n1E4C..1E59    ; Uncommon_Use                   # 1.1   [14] LATIN CAPITAL LETTER O WITH TILDE AND ACUTE..LATIN SMALL LETTER R WITH DOT ABOVE\n1E5C..1E61    ; Uncommon_Use                   # 1.1    [6] LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON..LATIN SMALL LETTER S WITH DOT ABOVE\n1E64..1E6B    ; Uncommon_Use                   # 1.1    [8] LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE..LATIN SMALL LETTER T WITH DOT ABOVE\n1E6E..1E6F    ; Uncommon_Use                   # 1.1    [2] LATIN CAPITAL LETTER T WITH LINE BELOW..LATIN SMALL LETTER T WITH LINE BELOW\n1E78..1E8B    ; Uncommon_Use                   # 1.1   [20] LATIN CAPITAL LETTER U WITH TILDE AND ACUTE..LATIN SMALL LETTER X WITH DOT ABOVE\n1E8E..1E91    ; Uncommon_Use                   # 1.1    [4] LATIN CAPITAL LETTER Y WITH DOT ABOVE..LATIN SMALL LETTER Z WITH CIRCUMFLEX\n1E94..1E99    ; Uncommon_Use                   # 1.1    [6] LATIN CAPITAL LETTER Z WITH LINE BELOW..LATIN SMALL LETTER Y WITH RING ABOVE\n2054          ; Uncommon_Use                   # 4.0        INVERTED UNDERTIE\n2C68..2C6C    ; Uncommon_Use                   # 5.0    [5] LATIN SMALL LETTER H WITH DESCENDER..LATIN SMALL LETTER Z WITH DESCENDER\n2D80..2D96    ; Uncommon_Use                   # 4.1   [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE\n2DA0..2DA6    ; Uncommon_Use                   # 4.1    [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO\n2DA8..2DAE    ; Uncommon_Use                   # 4.1    [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO\n2DB0..2DB6    ; Uncommon_Use                   # 4.1    [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO\n2DB8..2DBE    ; Uncommon_Use                   # 4.1    [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO\n2DC0..2DC6    ; Uncommon_Use                   # 4.1    [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO\n2DC8..2DCE    ; Uncommon_Use                   # 4.1    [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO\n2DD0..2DD6    ; Uncommon_Use                   # 4.1    [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO\n2DD8..2DDE    ; Uncommon_Use                   # 4.1    [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO\n3099..309A    ; Uncommon_Use                   # 1.1    [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n3400..3446    ; Uncommon_Use                   # 3.0   [71] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-3446\n3448..3472    ; Uncommon_Use                   # 3.0   [43] CJK UNIFIED IDEOGRAPH-3448..CJK UNIFIED IDEOGRAPH-3472\n3474..34E3    ; Uncommon_Use                   # 3.0  [112] CJK UNIFIED IDEOGRAPH-3474..CJK UNIFIED IDEOGRAPH-34E3\n34E5..3576    ; Uncommon_Use                   # 3.0  [146] CJK UNIFIED IDEOGRAPH-34E5..CJK UNIFIED IDEOGRAPH-3576\n3578..359D    ; Uncommon_Use                   # 3.0   [38] CJK UNIFIED IDEOGRAPH-3578..CJK UNIFIED IDEOGRAPH-359D\n359F..35A0    ; Uncommon_Use                   # 3.0    [2] CJK UNIFIED IDEOGRAPH-359F..CJK UNIFIED IDEOGRAPH-35A0\n35A2..35AC    ; Uncommon_Use                   # 3.0   [11] CJK UNIFIED IDEOGRAPH-35A2..CJK UNIFIED IDEOGRAPH-35AC\n35AE..35BE    ; Uncommon_Use                   # 3.0   [17] CJK UNIFIED IDEOGRAPH-35AE..CJK UNIFIED IDEOGRAPH-35BE\n35C0..35CD    ; Uncommon_Use                   # 3.0   [14] CJK UNIFIED IDEOGRAPH-35C0..CJK UNIFIED IDEOGRAPH-35CD\n35CF..35F2    ; Uncommon_Use                   # 3.0   [36] CJK UNIFIED IDEOGRAPH-35CF..CJK UNIFIED IDEOGRAPH-35F2\n35F4..35FD    ; Uncommon_Use                   # 3.0   [10] CJK UNIFIED IDEOGRAPH-35F4..CJK UNIFIED IDEOGRAPH-35FD\n35FF..360D    ; Uncommon_Use                   # 3.0   [15] CJK UNIFIED IDEOGRAPH-35FF..CJK UNIFIED IDEOGRAPH-360D\n360F..3619    ; Uncommon_Use                   # 3.0   [11] CJK UNIFIED IDEOGRAPH-360F..CJK UNIFIED IDEOGRAPH-3619\n361B..3917    ; Uncommon_Use                   # 3.0  [765] CJK UNIFIED IDEOGRAPH-361B..CJK UNIFIED IDEOGRAPH-3917\n3919..395F    ; Uncommon_Use                   # 3.0   [71] CJK UNIFIED IDEOGRAPH-3919..CJK UNIFIED IDEOGRAPH-395F\n3961..396D    ; Uncommon_Use                   # 3.0   [13] CJK UNIFIED IDEOGRAPH-3961..CJK UNIFIED IDEOGRAPH-396D\n396F..39CE    ; Uncommon_Use                   # 3.0   [96] CJK UNIFIED IDEOGRAPH-396F..CJK UNIFIED IDEOGRAPH-39CE\n39D1..39DA    ; Uncommon_Use                   # 3.0   [10] CJK UNIFIED IDEOGRAPH-39D1..CJK UNIFIED IDEOGRAPH-39DA\n39DC..39DE    ; Uncommon_Use                   # 3.0    [3] CJK UNIFIED IDEOGRAPH-39DC..CJK UNIFIED IDEOGRAPH-39DE\n39E0..39F7    ; Uncommon_Use                   # 3.0   [24] CJK UNIFIED IDEOGRAPH-39E0..CJK UNIFIED IDEOGRAPH-39F7\n39F9..39FD    ; Uncommon_Use                   # 3.0    [5] CJK UNIFIED IDEOGRAPH-39F9..CJK UNIFIED IDEOGRAPH-39FD\n39FF..3A17    ; Uncommon_Use                   # 3.0   [25] CJK UNIFIED IDEOGRAPH-39FF..CJK UNIFIED IDEOGRAPH-3A17\n3A19..3A51    ; Uncommon_Use                   # 3.0   [57] CJK UNIFIED IDEOGRAPH-3A19..CJK UNIFIED IDEOGRAPH-3A51\n3A53..3A5B    ; Uncommon_Use                   # 3.0    [9] CJK UNIFIED IDEOGRAPH-3A53..CJK UNIFIED IDEOGRAPH-3A5B\n3A5D..3A66    ; Uncommon_Use                   # 3.0   [10] CJK UNIFIED IDEOGRAPH-3A5D..CJK UNIFIED IDEOGRAPH-3A66\n3A68..3A72    ; Uncommon_Use                   # 3.0   [11] CJK UNIFIED IDEOGRAPH-3A68..CJK UNIFIED IDEOGRAPH-3A72\n3A74..3B38    ; Uncommon_Use                   # 3.0  [197] CJK UNIFIED IDEOGRAPH-3A74..CJK UNIFIED IDEOGRAPH-3B38\n3B3A..3B4D    ; Uncommon_Use                   # 3.0   [20] CJK UNIFIED IDEOGRAPH-3B3A..CJK UNIFIED IDEOGRAPH-3B4D\n3B4F..3BA2    ; Uncommon_Use                   # 3.0   [84] CJK UNIFIED IDEOGRAPH-3B4F..CJK UNIFIED IDEOGRAPH-3BA2\n3BA4..3C6D    ; Uncommon_Use                   # 3.0  [202] CJK UNIFIED IDEOGRAPH-3BA4..CJK UNIFIED IDEOGRAPH-3C6D\n3C6F..3CDF    ; Uncommon_Use                   # 3.0  [113] CJK UNIFIED IDEOGRAPH-3C6F..CJK UNIFIED IDEOGRAPH-3CDF\n3CE1..3DE6    ; Uncommon_Use                   # 3.0  [262] CJK UNIFIED IDEOGRAPH-3CE1..CJK UNIFIED IDEOGRAPH-3DE6\n3DE8..3DEA    ; Uncommon_Use                   # 3.0    [3] CJK UNIFIED IDEOGRAPH-3DE8..CJK UNIFIED IDEOGRAPH-3DEA\n3DEC..3E73    ; Uncommon_Use                   # 3.0  [136] CJK UNIFIED IDEOGRAPH-3DEC..CJK UNIFIED IDEOGRAPH-3E73\n3E75..3ECF    ; Uncommon_Use                   # 3.0   [91] CJK UNIFIED IDEOGRAPH-3E75..CJK UNIFIED IDEOGRAPH-3ECF\n3ED1..4055    ; Uncommon_Use                   # 3.0  [389] CJK UNIFIED IDEOGRAPH-3ED1..CJK UNIFIED IDEOGRAPH-4055\n4057..4064    ; Uncommon_Use                   # 3.0   [14] CJK UNIFIED IDEOGRAPH-4057..CJK UNIFIED IDEOGRAPH-4064\n4066..4069    ; Uncommon_Use                   # 3.0    [4] CJK UNIFIED IDEOGRAPH-4066..CJK UNIFIED IDEOGRAPH-4069\n406B..40BA    ; Uncommon_Use                   # 3.0   [80] CJK UNIFIED IDEOGRAPH-406B..CJK UNIFIED IDEOGRAPH-40BA\n40BC..40DE    ; Uncommon_Use                   # 3.0   [35] CJK UNIFIED IDEOGRAPH-40BC..CJK UNIFIED IDEOGRAPH-40DE\n40E0..4136    ; Uncommon_Use                   # 3.0   [87] CJK UNIFIED IDEOGRAPH-40E0..CJK UNIFIED IDEOGRAPH-4136\n4138..415E    ; Uncommon_Use                   # 3.0   [39] CJK UNIFIED IDEOGRAPH-4138..CJK UNIFIED IDEOGRAPH-415E\n4160..4336    ; Uncommon_Use                   # 3.0  [471] CJK UNIFIED IDEOGRAPH-4160..CJK UNIFIED IDEOGRAPH-4336\n4338..43AB    ; Uncommon_Use                   # 3.0  [116] CJK UNIFIED IDEOGRAPH-4338..CJK UNIFIED IDEOGRAPH-43AB\n43AD..43B0    ; Uncommon_Use                   # 3.0    [4] CJK UNIFIED IDEOGRAPH-43AD..CJK UNIFIED IDEOGRAPH-43B0\n43B2..43D2    ; Uncommon_Use                   # 3.0   [33] CJK UNIFIED IDEOGRAPH-43B2..CJK UNIFIED IDEOGRAPH-43D2\n43D4..43DC    ; Uncommon_Use                   # 3.0    [9] CJK UNIFIED IDEOGRAPH-43D4..CJK UNIFIED IDEOGRAPH-43DC\n43DE..4442    ; Uncommon_Use                   # 3.0  [101] CJK UNIFIED IDEOGRAPH-43DE..CJK UNIFIED IDEOGRAPH-4442\n4444..44D5    ; Uncommon_Use                   # 3.0  [146] CJK UNIFIED IDEOGRAPH-4444..CJK UNIFIED IDEOGRAPH-44D5\n44D7..44E9    ; Uncommon_Use                   # 3.0   [19] CJK UNIFIED IDEOGRAPH-44D7..CJK UNIFIED IDEOGRAPH-44E9\n44EB..4605    ; Uncommon_Use                   # 3.0  [283] CJK UNIFIED IDEOGRAPH-44EB..CJK UNIFIED IDEOGRAPH-4605\n4607..464B    ; Uncommon_Use                   # 3.0   [69] CJK UNIFIED IDEOGRAPH-4607..CJK UNIFIED IDEOGRAPH-464B\n464D..4660    ; Uncommon_Use                   # 3.0   [20] CJK UNIFIED IDEOGRAPH-464D..CJK UNIFIED IDEOGRAPH-4660\n4662..4722    ; Uncommon_Use                   # 3.0  [193] CJK UNIFIED IDEOGRAPH-4662..CJK UNIFIED IDEOGRAPH-4722\n4724..4728    ; Uncommon_Use                   # 3.0    [5] CJK UNIFIED IDEOGRAPH-4724..CJK UNIFIED IDEOGRAPH-4728\n472A..477B    ; Uncommon_Use                   # 3.0   [82] CJK UNIFIED IDEOGRAPH-472A..CJK UNIFIED IDEOGRAPH-477B\n477D..478C    ; Uncommon_Use                   # 3.0   [16] CJK UNIFIED IDEOGRAPH-477D..CJK UNIFIED IDEOGRAPH-478C\n478E..47F3    ; Uncommon_Use                   # 3.0  [102] CJK UNIFIED IDEOGRAPH-478E..CJK UNIFIED IDEOGRAPH-47F3\n47F5..4881    ; Uncommon_Use                   # 3.0  [141] CJK UNIFIED IDEOGRAPH-47F5..CJK UNIFIED IDEOGRAPH-4881\n4883..4946    ; Uncommon_Use                   # 3.0  [196] CJK UNIFIED IDEOGRAPH-4883..CJK UNIFIED IDEOGRAPH-4946\n4948..4979    ; Uncommon_Use                   # 3.0   [50] CJK UNIFIED IDEOGRAPH-4948..CJK UNIFIED IDEOGRAPH-4979\n497B..497C    ; Uncommon_Use                   # 3.0    [2] CJK UNIFIED IDEOGRAPH-497B..CJK UNIFIED IDEOGRAPH-497C\n497E..4981    ; Uncommon_Use                   # 3.0    [4] CJK UNIFIED IDEOGRAPH-497E..CJK UNIFIED IDEOGRAPH-4981\n4984          ; Uncommon_Use                   # 3.0        CJK UNIFIED IDEOGRAPH-4984\n4987..499A    ; Uncommon_Use                   # 3.0   [20] CJK UNIFIED IDEOGRAPH-4987..CJK UNIFIED IDEOGRAPH-499A\n499C..499E    ; Uncommon_Use                   # 3.0    [3] CJK UNIFIED IDEOGRAPH-499C..CJK UNIFIED IDEOGRAPH-499E\n49A0..49B5    ; Uncommon_Use                   # 3.0   [22] CJK UNIFIED IDEOGRAPH-49A0..CJK UNIFIED IDEOGRAPH-49B5\n49B8..4A11    ; Uncommon_Use                   # 3.0   [90] CJK UNIFIED IDEOGRAPH-49B8..CJK UNIFIED IDEOGRAPH-4A11\n4A13..4AB7    ; Uncommon_Use                   # 3.0  [165] CJK UNIFIED IDEOGRAPH-4A13..CJK UNIFIED IDEOGRAPH-4AB7\n4AB9..4C76    ; Uncommon_Use                   # 3.0  [446] CJK UNIFIED IDEOGRAPH-4AB9..CJK UNIFIED IDEOGRAPH-4C76\n4C78..4C7C    ; Uncommon_Use                   # 3.0    [5] CJK UNIFIED IDEOGRAPH-4C78..CJK UNIFIED IDEOGRAPH-4C7C\n4C7E..4C80    ; Uncommon_Use                   # 3.0    [3] CJK UNIFIED IDEOGRAPH-4C7E..CJK UNIFIED IDEOGRAPH-4C80\n4C82..4C84    ; Uncommon_Use                   # 3.0    [3] CJK UNIFIED IDEOGRAPH-4C82..CJK UNIFIED IDEOGRAPH-4C84\n4C86..4C9C    ; Uncommon_Use                   # 3.0   [23] CJK UNIFIED IDEOGRAPH-4C86..CJK UNIFIED IDEOGRAPH-4C9C\n4CA4..4D12    ; Uncommon_Use                   # 3.0  [111] CJK UNIFIED IDEOGRAPH-4CA4..CJK UNIFIED IDEOGRAPH-4D12\n4D1A..4DAD    ; Uncommon_Use                   # 3.0  [148] CJK UNIFIED IDEOGRAPH-4D1A..CJK UNIFIED IDEOGRAPH-4DAD\n4DAF..4DB5    ; Uncommon_Use                   # 3.0    [7] CJK UNIFIED IDEOGRAPH-4DAF..CJK UNIFIED IDEOGRAPH-4DB5\n4DB6..4DBF    ; Uncommon_Use                   # 13.0  [10] CJK UNIFIED IDEOGRAPH-4DB6..CJK UNIFIED IDEOGRAPH-4DBF\n4E12          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4E12\n4E29          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4E29\n4E68          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4E68\n4E79          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4E79\n4E96          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4E96\n4EA3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4EA3\n4EBC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4EBC\n4ECC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4ECC\n4EE7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4EE7\n4EF8..4EFA    ; Uncommon_Use                   # 1.1    [3] CJK UNIFIED IDEOGRAPH-4EF8..CJK UNIFIED IDEOGRAPH-4EFA\n4EFC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4EFC\n4EFE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4EFE\n4F07          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F07\n4F16          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F16\n4F28          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F28\n4F31          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F31\n4F35          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F35\n4F37          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F37\n4F40          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F40\n4F44          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F44\n4F71          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F71\n4F8C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F8C\n4F8E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4F8E\n4FA2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4FA2\n4FBD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4FBD\n4FC6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4FC6\n4FC8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4FC8\n4FCC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4FCC\n4FE2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-4FE2\n4FFC..4FFD    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-4FFC..CJK UNIFIED IDEOGRAPH-4FFD\n5010          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5010\n5034          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5034\n5038          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5038\n503D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-503D\n5042          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5042\n5052          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5052\n5058          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5058\n507C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-507C\n5081          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5081\n5093          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5093\n5097          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5097\n509F..50A1    ; Uncommon_Use                   # 1.1    [3] CJK UNIFIED IDEOGRAPH-509F..CJK UNIFIED IDEOGRAPH-50A1\n50B9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-50B9\n50C3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-50C3\n50D8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-50D8\n50DF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-50DF\n50E1..50E2    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-50E1..CJK UNIFIED IDEOGRAPH-50E2\n50EB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-50EB\n50F4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-50F4\n50F7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-50F7\n511B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-511B\n5128          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5128\n512B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-512B\n5142          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5142\n514A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-514A\n514F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-514F\n5153          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5153\n5158          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5158\n5160          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5160\n5164          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5164\n5172          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5172\n517E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-517E\n5183..5184    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5183..CJK UNIFIED IDEOGRAPH-5184\n518E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-518E\n51A1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51A1\n51A3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51A3\n51AD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51AD\n51B8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51B8\n51BA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51BA\n51C2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51C2\n51D2..51D3    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-51D2..CJK UNIFIED IDEOGRAPH-51D3\n51DF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51DF\n51EC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51EC\n51EE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51EE\n51F2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-51F2\n5253          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5253\n5266          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5266\n5279          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5279\n5285          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5285\n528E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-528E\n52C4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52C4\n52C8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52C8\n52CC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52CC\n52CE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52CE\n52D1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52D1\n52D4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52D4\n52E1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52E1\n52E5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52E5\n52EE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-52EE\n5303..5304    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5303..CJK UNIFIED IDEOGRAPH-5304\n5318          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5318\n531B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-531B\n531E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-531E\n5327          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5327\n5329          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5329\n5332          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5332\n5335..5336    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5335..CJK UNIFIED IDEOGRAPH-5336\n5342          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5342\n535B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-535B\n535D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-535D\n536A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-536A\n536D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-536D\n5380          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5380\n53A1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-53A1\n53AA..53AB    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-53AA..CJK UNIFIED IDEOGRAPH-53AB\n53AF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-53AF\n53BA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-53BA\n53C5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-53C5\n53CF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-53CF\n53DD..53DE    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-53DD..CJK UNIFIED IDEOGRAPH-53DE\n53E7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-53E7\n53FF..5400    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-53FF..CJK UNIFIED IDEOGRAPH-5400\n541A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-541A\n5422          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5422\n544C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-544C\n545D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-545D\n5469          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5469\n548A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-548A\n54B5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-54B5\n54F6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-54F6\n5515          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5515\n5518..5519    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5518..CJK UNIFIED IDEOGRAPH-5519\n5547          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5547\n5560          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5560\n557A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-557A\n55E0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-55E0\n55F8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-55F8\n560A..560B    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-560A..CJK UNIFIED IDEOGRAPH-560B\n5620          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5620\n562B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-562B\n5637          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5637\n563C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-563C\n5644          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5644\n564B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-564B\n5651          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5651\n5656          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5656\n565F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-565F\n5661          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5661\n5675          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5675\n567D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-567D\n5688          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5688\n568B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-568B\n5696          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5696\n569E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-569E\n56BA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-56BA\n56CF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-56CF\n56D9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-56D9\n56E6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-56E6\n56F6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-56F6\n56F8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-56F8\n56FB..56FC    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-56FB..CJK UNIFIED IDEOGRAPH-56FC\n5705          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5705\n5711          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5711\n5717          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5717\n5721          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5721\n5724          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5724\n573D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-573D\n5743          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5743\n5748          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5748\n5755..5756    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5755..CJK UNIFIED IDEOGRAPH-5756\n5758          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5758\n5763          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5763\n5778          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5778\n5781          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5781\n5787          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5787\n5796          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5796\n57A8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-57A8\n57CA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-57CA\n57D1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-57D1\n57DB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-57DB\n5817..5818    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5817..CJK UNIFIED IDEOGRAPH-5818\n5850          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5850\n5856          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5856\n5860          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5860\n5866..5867    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5866..CJK UNIFIED IDEOGRAPH-5867\n5877          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5877\n5895          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5895\n58AA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-58AA\n58B6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-58B6\n58C0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-58C0\n58C3..58C4    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-58C3..CJK UNIFIED IDEOGRAPH-58C4\n58CD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-58CD\n58D0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-58D0\n58E1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-58E1\n58E6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-58E6\n58F5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-58F5\n5901          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5901\n5905          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5905\n5908          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5908\n5911          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5911\n5913          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5913\n5923          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5923\n5933          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5933\n5936          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5936\n5959          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5959\n595B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-595B\n59B7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-59B7\n59E7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-59E7\n5A24          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A24\n5A26          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A26\n5A2C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A2C\n5A30          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A30\n5A54          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A54\n5A59          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A59\n5A6F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A6F\n5A71          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A71\n5A87          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A87\n5A8D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5A8D\n5AAB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5AAB\n5AD3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5AD3\n5AEF..5AF0    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5AEF..CJK UNIFIED IDEOGRAPH-5AF0\n5B0A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B0A\n5B0D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B0D\n5B39          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B39\n5B46          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B46\n5B4F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B4F\n5B52          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B52\n5B60..5B61    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5B60..CJK UNIFIED IDEOGRAPH-5B61\n5B6F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B6F\n5B79          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B79\n5B7E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B7E\n5B86          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B86\n5B90          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5B90\n5BA9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5BA9\n5BB2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5BB2\n5BB7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5BB7\n5BBC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5BBC\n5BC8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5BC8\n5BDA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5BDA\n5C00          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5C00\n5C1B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5C1B\n5C23          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5C23\n5C26          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5C26\n5C29          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5C29\n5C36          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5C36\n5C5A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5C5A\n5C85          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5C85\n5CB4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5CB4\n5CB9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5CB9\n5CD5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5CD5\n5CDD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5CDD\n5CF5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5CF5\n5D2B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5D2B\n5D2F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5D2F\n5D3B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5D3B\n5D53          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5D53\n5D57          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5D57\n5D60          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5D60\n5D83          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5D83\n5D96          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5D96\n5DA3..5DA4    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5DA3..CJK UNIFIED IDEOGRAPH-5DA4\n5DAB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5DAB\n5DB3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5DB3\n5DB9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5DB9\n5DC4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5DC4\n5DD7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5DD7\n5DDA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5DDA\n5DDC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5DDC\n5DF6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5DF6\n5E12          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5E12\n5E48          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5E48\n5E51          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5E51\n5E92          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5E92\n5EBA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5EBA\n5EC0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5EC0\n5EEB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5EEB\n5EF9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5EF9\n5F0E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5F0E\n5F3B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5F3B\n5F3D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5F3D\n5F8F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5F8F\n5F9A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5F9A\n5FA3..5FA4    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-5FA3..CJK UNIFIED IDEOGRAPH-5FA4\n5FB0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5FB0\n5FC2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5FC2\n5FCE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5FCE\n5FDB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5FDB\n5FE2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5FE2\n5FEC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5FEC\n5FFC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-5FFC\n6023          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6023\n6056          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6056\n6061          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6061\n6071          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6071\n6074          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6074\n6091          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6091\n6093          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6093\n60A5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-60A5\n60D2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-60D2\n60D6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-60D6\n60DE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-60DE\n60E5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-60E5\n60FD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-60FD\n6102          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6102\n6107          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6107\n6111          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6111\n611E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-611E\n6131          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6131\n6133          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6133\n6135          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6135\n6138..6139    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-6138..CJK UNIFIED IDEOGRAPH-6139\n6160          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6160\n617B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-617B\n617F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-617F\n6186          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6186\n6197          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6197\n619C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-619C\n61B9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-61B9\n61BB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-61BB\n61D3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-61D3\n61D5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-61D5\n61EC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-61EC\n61EF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-61EF\n6205          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6205\n6235          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6235\n6239          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6239\n6257          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6257\n628D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-628D\n629D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-629D\n62DE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-62DE\n62EA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-62EA\n630A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-630A\n6317          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6317\n6331          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6331\n6337          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6337\n635B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-635B\n638B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-638B\n6393          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6393\n63D1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-63D1\n643B..643C    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-643B..CJK UNIFIED IDEOGRAPH-643C\n6449          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6449\n645A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-645A\n647E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-647E\n6486          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6486\n64A1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-64A1\n64AF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-64AF\n64B6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-64B6\n64C8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-64C8\n64D5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-64D5\n64EE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-64EE\n64F5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-64F5\n64F9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-64F9\n6502          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6502\n650A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-650A\n651F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-651F\n6528          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6528\n6540          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6540\n6542          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6542\n655A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-655A\n655F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-655F\n657D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-657D\n658A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-658A\n659A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-659A\n65B5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65B5\n65BE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65BE\n65C8..65C9    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-65C8..CJK UNIFIED IDEOGRAPH-65C9\n65D1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65D1\n65D8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65D8\n65DC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65DC\n65E4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65E4\n65EA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65EA\n65F9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65F9\n65FE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-65FE\n6617          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6617\n662C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-662C\n6637..6638    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-6637..CJK UNIFIED IDEOGRAPH-6638\n6648          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6648\n664D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-664D\n6660          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6660\n6663          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6663\n6692          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6692\n669C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-669C\n669E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-669E\n66AC..66AD    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-66AC..CJK UNIFIED IDEOGRAPH-66AD\n66D0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-66D0\n66D3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-66D3\n66D7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-66D7\n66DF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-66DF\n66EF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-66EF\n6702          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6702\n6707          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6707\n6719          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6719\n6724          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6724\n6729          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6729\n6767          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6767\n6788          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6788\n6796          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6796\n67BD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-67BD\n67BF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-67BF\n67D5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-67D5\n67D7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-67D7\n67F9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-67F9\n6801          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6801\n6815          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6815\n6827          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6827\n6830          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6830\n6858          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6858\n685A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-685A\n685E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-685E\n687A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-687A\n6895          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6895\n6899          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6899\n68A5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-68A5\n68B8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-68B8\n68C3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-68C3\n68D9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-68D9\n68E2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-68E2\n68E5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-68E5\n6909          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6909\n693E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-693E\n694D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-694D\n699F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-699F\n69A2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-69A2\n69C0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-69C0\n69D1..69D2    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-69D1..CJK UNIFIED IDEOGRAPH-69D2\n69D5..69D7    ; Uncommon_Use                   # 1.1    [3] CJK UNIFIED IDEOGRAPH-69D5..CJK UNIFIED IDEOGRAPH-69D7\n6A03          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A03\n6A1C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A1C\n6A24          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A24\n6A37          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A37\n6A4A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A4A\n6A5C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A5C\n6A6E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A6E\n6A70          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A70\n6A86          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A86\n6A8A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A8A\n6A8F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A8F\n6A99          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A99\n6A9D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6A9D\n6AB1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6AB1\n6ABE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6ABE\n6AC0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6AC0\n6AC4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6AC4\n6AC9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6AC9\n6AD8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6AD8\n6AE9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6AE9\n6B0E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B0E\n6B1B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B1B\n6B2E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B2E\n6B35          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B35\n6B40          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B40\n6B57..6B58    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-6B57..CJK UNIFIED IDEOGRAPH-6B58\n6B5D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B5D\n6B68          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B68\n6B6C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B6C\n6B6E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B6E\n6B71          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B71\n6B75          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B75\n6B7D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6B7D\n6BB8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6BB8\n6BE9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6BE9\n6BF1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6BF1\n6BF4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6BF4\n6BFA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6BFA\n6C0A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6C0A\n6C1C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6C1C\n6C2D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6C2D\n6C3C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6C3C\n6C45          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6C45\n6C6C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6C6C\n6C6E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6C6E\n6CA0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6CA0\n6CD8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6CD8\n6CF4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6CF4\n6D02          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6D02\n6D1C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6D1C\n6D24          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6D24\n6D71          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6D71\n6D81          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6D81\n6D96          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6D96\n6DB0..6DB1    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-6DB0..CJK UNIFIED IDEOGRAPH-6DB1\n6DB6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6DB6\n6DFE..6DFF    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-6DFE..CJK UNIFIED IDEOGRAPH-6DFF\n6E01..6E02    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-6E01..CJK UNIFIED IDEOGRAPH-6E02\n6E06          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6E06\n6E12          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6E12\n6E18          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6E18\n6E2A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6E2A\n6E4C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6E4C\n6E6C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6E6C\n6E7B..6E7D    ; Uncommon_Use                   # 1.1    [3] CJK UNIFIED IDEOGRAPH-6E7B..CJK UNIFIED IDEOGRAPH-6E7D\n6E8B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6E8B\n6E95          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6E95\n6EDB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6EDB\n6EE3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6EE3\n6F04          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F04\n6F0B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F0B\n6F42          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F42\n6F48          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F48\n6F4A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F4A\n6F79          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F79\n6F98          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F98\n6F9A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F9A\n6F9F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6F9F\n6FB7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6FB7\n6FC5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6FC5\n6FD0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6FD0\n6FD3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6FD3\n6FF5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6FF5\n6FFD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-6FFD\n7010          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7010\n7013          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7013\n7047          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7047\n704B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-704B\n704E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-704E\n7072..7073    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7072..CJK UNIFIED IDEOGRAPH-7073\n707B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-707B\n7081          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7081\n708D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-708D\n7097          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7097\n709B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-709B\n70AA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-70AA\n70B2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-70B2\n70B6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-70B6\n70D5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-70D5\n70FE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-70FE\n7108          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7108\n7124          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7124\n7133..7134    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7133..CJK UNIFIED IDEOGRAPH-7134\n7157          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7157\n716B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-716B\n716D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-716D\n718D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-718D\n7196          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7196\n71A6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-71A6\n71AB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-71AB\n71B6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-71B6\n71CC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-71CC\n71D3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-71D3\n71F3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-71F3\n71FA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-71FA\n720B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-720B\n7211          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7211\n7215          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7215\n7217          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7217\n7220          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7220\n7224..7225    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7224..CJK UNIFIED IDEOGRAPH-7225\n722F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-722F\n7234          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7234\n7245          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7245\n724E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-724E\n7250          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7250\n7255          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7255\n72AB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-72AB\n72BE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-72BE\n7302          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7302\n7310          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7310\n7328          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7328\n7353          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7353\n739C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-739C\n73C1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-73C1\n73F3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-73F3\n73FB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-73FB\n7418          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7418\n7439          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7439\n743E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-743E\n7447          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7447\n7449          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7449\n7458          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7458\n747B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-747B\n7484          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7484\n7496          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7496\n749D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-749D\n74C7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-74C7\n74C9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-74C9\n74CC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-74CC\n74EB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-74EB\n7520          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7520\n7541          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7541\n7552          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7552\n7555          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7555\n755E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-755E\n7561          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7561\n7571          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7571\n757B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-757B\n7585          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7585\n75A9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-75A9\n75B7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-75B7\n75DC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-75DC\n75EE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-75EE\n762C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-762C\n7644..7645    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7644..CJK UNIFIED IDEOGRAPH-7645\n7651          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7651\n7655          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7655\n7673          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7673\n768D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-768D\n76A1..76A2    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-76A1..CJK UNIFIED IDEOGRAPH-76A2\n76A5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-76A5\n76A8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-76A8\n76B3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-76B3\n76B6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-76B6\n76C1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-76C1\n76CB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-76CB\n76D9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-76D9\n76EB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-76EB\n7700          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7700\n7702          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7702\n770E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-770E\n7721          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7721\n772B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-772B\n773F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-773F\n7742          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7742\n7764          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7764\n7796          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7796\n77A4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-77A4\n77BE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-77BE\n77C1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-77C1\n77D2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-77D2\n77DD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-77DD\n77E4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-77E4\n77E6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-77E6\n77F4..77F5    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-77F4..CJK UNIFIED IDEOGRAPH-77F5\n7824          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7824\n7836          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7836\n7842          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7842\n7846          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7846\n784B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-784B\n7876          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7876\n7888          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7888\n78C2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-78C2\n78C7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-78C7\n78D2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-78D2\n78F0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-78F0\n78F8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-78F8\n7900          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7900\n7908          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7908\n790D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-790D\n7915          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7915\n791F..7920    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-791F..CJK UNIFIED IDEOGRAPH-7920\n7932          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7932\n7936          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7936\n7959          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7959\n796C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-796C\n796E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-796E\n7975..7976    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7975..CJK UNIFIED IDEOGRAPH-7976\n7986..7987    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7986..CJK UNIFIED IDEOGRAPH-7987\n799E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-799E\n79A9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-79A9\n79BC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-79BC\n79C4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-79C4\n79C7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-79C7\n79CC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-79CC\n79D4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-79D4\n79D7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-79D7\n7A01          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A01\n7A07          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A07\n7A09          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A09\n7A2C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A2C\n7A38          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A38\n7A3A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A3A\n7A64          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A64\n7A6A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A6A\n7A6F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A6F\n7A82          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7A82\n7A9A..7A9B    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7A9A..CJK UNIFIED IDEOGRAPH-7A9B\n7AB9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7AB9\n7ABB..7ABD    ; Uncommon_Use                   # 1.1    [3] CJK UNIFIED IDEOGRAPH-7ABB..CJK UNIFIED IDEOGRAPH-7ABD\n7AC2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7AC2\n7AC6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7AC6\n7AE9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7AE9\n7AF5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7AF5\n7AFC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7AFC\n7B07          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7B07\n7B1F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7B1F\n7B27          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7B27\n7B29          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7B29\n7B42          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7B42\n7B53          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7B53\n7BA3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7BA3\n7BA5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7BA5\n7BB0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7BB0\n7BB2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7BB2\n7BFA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7BFA\n7C1B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7C1B\n7C2E..7C2F    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7C2E..CJK UNIFIED IDEOGRAPH-7C2F\n7C52          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7C52\n7C55          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7C55\n7C5D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7C5D\n7C76          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7C76\n7C87          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7C87\n7C93          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7C93\n7C9A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7C9A\n7CAC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7CAC\n7CD3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7CD3\n7CDA..7CDB    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7CDA..CJK UNIFIED IDEOGRAPH-7CDB\n7CE1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7CE1\n7CE3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7CE3\n7CE5..7CE6    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7CE5..CJK UNIFIED IDEOGRAPH-7CE6\n7CFC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7CFC\n7CFF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7CFF\n7D23          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D23\n7D2A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D2A\n7D2D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D2D\n7D48          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D48\n7D4D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D4D\n7D5A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D5A\n7D64          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D64\n7D78          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D78\n7D82          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D82\n7D95          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D95\n7D98          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7D98\n7DA4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7DA4\n7DA8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7DA8\n7DCD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7DCD\n7DD3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7DD3\n7DE5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7DE5\n7DEB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7DEB\n7DFD..7DFF    ; Uncommon_Use                   # 1.1    [3] CJK UNIFIED IDEOGRAPH-7DFD..CJK UNIFIED IDEOGRAPH-7DFF\n7E18          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7E18\n7E5B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7E5B\n7E64          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7E64\n7E9D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7E9D\n7F3B..7F3C    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-7F3B..CJK UNIFIED IDEOGRAPH-7F3C\n7F41          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7F41\n7F46          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7F46\n7F59          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7F59\n7F84          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7F84\n7F90          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7F90\n7F97          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7F97\n7F99          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7F99\n7FB4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7FB4\n7FD6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7FD6\n7FDD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7FDD\n7FE4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-7FE4\n800A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-800A\n802F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-802F\n803C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-803C\n8040          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8040\n8066          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8066\n8088          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8088\n808E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-808E\n8094          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8094\n80A6..80A8    ; Uncommon_Use                   # 1.1    [3] CJK UNIFIED IDEOGRAPH-80A6..CJK UNIFIED IDEOGRAPH-80A8\n80B3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-80B3\n80B9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-80B9\n80DF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-80DF\n8103..8104    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8103..CJK UNIFIED IDEOGRAPH-8104\n8134..8135    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8134..CJK UNIFIED IDEOGRAPH-8135\n8184          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8184\n8190          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8190\n8196          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8196\n81CB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-81CB\n81E4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-81E4\n81EF..81F0    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-81EF..CJK UNIFIED IDEOGRAPH-81F0\n8213          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8213\n8224          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8224\n8241          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8241\n8265          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8265\n828C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-828C\n82B2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-82B2\n82E2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-82E2\n82FC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-82FC\n830A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-830A\n8310          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8310\n8330          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8330\n8355          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8355\n83BE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-83BE\n83E6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-83E6\n83ED          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-83ED\n8414          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8414\n8416..8417    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8416..CJK UNIFIED IDEOGRAPH-8417\n841F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-841F\n8458          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8458\n8483          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8483\n8495          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8495\n84B7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-84B7\n84C3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-84C3\n84ED          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-84ED\n8505          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8505\n8510          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8510\n8532..8533    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8532..CJK UNIFIED IDEOGRAPH-8533\n854C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-854C\n8550          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8550\n857F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-857F\n8593          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8593\n85B2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-85B2\n85BB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-85BB\n85CC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-85CC\n85EE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-85EE\n85F3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-85F3\n85FC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-85FC\n8603          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8603\n860D..860E    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-860D..CJK UNIFIED IDEOGRAPH-860E\n8610          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8610\n8615          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8615\n861D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-861D\n8637          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8637\n8657          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8657\n8675          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8675\n8689          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8689\n8692          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8692\n86A0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-86A0\n86A6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-86A6\n86D5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-86D5\n86E0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-86E0\n86E7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-86E7\n86FD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-86FD\n871D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-871D\n872F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-872F\n873D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-873D\n8745          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8745\n8771          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8771\n878E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-878E\n8799          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8799\n87DA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-87DA\n87F0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-87F0\n8807          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8807\n8812          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8812\n882D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-882D\n883A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-883A\n8847          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8847\n8858          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8858\n885C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-885C\n885F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-885F\n887A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-887A\n88E6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-88E6\n88E9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-88E9\n88ED          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-88ED\n8903          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8903\n890F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-890F\n8924          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8924\n8965          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8965\n8975          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8975\n897D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-897D\n898D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-898D\n8990          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8990\n8994          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8994\n8999          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8999\n89B0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-89B0\n89B4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-89B4\n89BB..89BC    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-89BB..CJK UNIFIED IDEOGRAPH-89BC\n89EE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-89EE\n89F5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-89F5\n89F9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-89F9\n89FD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-89FD\n8A05..8A06    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8A05..CJK UNIFIED IDEOGRAPH-8A06\n8A14          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A14\n8A19          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A19\n8A20..8A21    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8A20..CJK UNIFIED IDEOGRAPH-8A21\n8A2B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A2B\n8A3D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A3D\n8A4B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A4B\n8A64          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A64\n8A78          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A78\n8A7D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A7D\n8A88          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A88\n8A9F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8A9F\n8AAF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8AAF\n8AB7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8AB7\n8AD0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8AD0\n8AEC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8AEC\n8B29          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B29\n8B32          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B32\n8B38          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B38\n8B3F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B3F\n8B61..8B62    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8B61..CJK UNIFIED IDEOGRAPH-8B62\n8B69          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B69\n8B75          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B75\n8B7C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B7C\n8B81          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B81\n8B87          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B87\n8B8D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B8D\n8B8F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B8F\n8B9B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8B9B\n8C38          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C38\n8C40          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C40\n8C44          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C44\n8C51..8C53    ; Uncommon_Use                   # 1.1    [3] CJK UNIFIED IDEOGRAPH-8C51..CJK UNIFIED IDEOGRAPH-8C53\n8C58          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C58\n8C74          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C74\n8C7F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C7F\n8C83          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C83\n8C87          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C87\n8C8B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C8B\n8C9B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8C9B\n8CA6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8CA6\n8CCB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8CCB\n8CD6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8CD6\n8CD8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8CD8\n8CE9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8CE9\n8CF7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8CF7\n8D01          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8D01\n8D11..8D12    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8D11..CJK UNIFIED IDEOGRAPH-8D12\n8D7C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8D7C\n8DA6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8DA6\n8DC0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8DC0\n8DE5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8DE5\n8E01          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E01\n8E0B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E0B\n8E32          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E32\n8E46          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E46\n8E4F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E4F\n8E6E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E6E\n8E75          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E75\n8E77          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E77\n8E79          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E79\n8E9B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8E9B\n8EA2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8EA2\n8EB3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8EB3\n8EB6..8EB7    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-8EB6..CJK UNIFIED IDEOGRAPH-8EB7\n8EC1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8EC1\n8EC4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8EC4\n8ED9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8ED9\n8EF0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8EF0\n8F0F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8F0F\n8F2D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8F2D\n8F3A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8F3A\n8F41          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8F41\n8F9D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8F9D\n8FA4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8FA4\n8FB3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8FB3\n8FC3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8FC3\n8FCA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8FCA\n8FE7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-8FE7\n902A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-902A\n902C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-902C\n9037          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9037\n9040          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9040\n9046          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9046\n90AB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-90AB\n90CC..90CD    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-90CC..CJK UNIFIED IDEOGRAPH-90CD\n90D2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-90D2\n90F6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-90F6\n910A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-910A\n913C..913D    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-913C..CJK UNIFIED IDEOGRAPH-913D\n9159          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9159\n917B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-917B\n9195          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9195\n9198          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9198\n91A9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-91A9\n91BF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-91BF\n91C4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-91C4\n91E0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-91E0\n91EF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-91EF\n9213          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9213\n921F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-921F\n9222          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9222\n9243          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9243\n9269..926A    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9269..CJK UNIFIED IDEOGRAPH-926A\n9281          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9281\n9284          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9284\n929E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-929E\n92BD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-92BD\n92D4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-92D4\n92DB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-92DB\n92E2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-92E2\n931C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-931C\n9330..9331    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9330..CJK UNIFIED IDEOGRAPH-9331\n9362          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9362\n9368          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9368\n936B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-936B\n936F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-936F\n9373          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9373\n9378          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9378\n937F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-937F\n9381          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9381\n938B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-938B\n939C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-939C\n93A0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-93A0\n93AB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-93AB\n93BB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-93BB\n93E0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-93E0\n93F3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-93F3\n9402          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9402\n9417          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9417\n941C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-941C\n941E..941F    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-941E..CJK UNIFIED IDEOGRAPH-941F\n9424          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9424\n9443          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9443\n944E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-944E\n946C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-946C\n947B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-947B\n9578..9579    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9578..CJK UNIFIED IDEOGRAPH-9579\n957E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-957E\n9585          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9585\n9597          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9597\n95B3..95B4    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-95B3..CJK UNIFIED IDEOGRAPH-95B4\n95B8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-95B8\n95C1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-95C1\n95D9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-95D9\n95DD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-95DD\n9625..9626    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9625..CJK UNIFIED IDEOGRAPH-9626\n9629          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9629\n963E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-963E\n9656..9657    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9656..CJK UNIFIED IDEOGRAPH-9657\n9679          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9679\n967B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-967B\n967F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-967F\n9681..9682    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9681..CJK UNIFIED IDEOGRAPH-9682\n968C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-968C\n9696          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9696\n969A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-969A\n969D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-969D\n969F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-969F\n96AB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-96AB\n96AF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-96AF\n96B5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-96B5\n96E4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-96E4\n96E6..96E7    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-96E6..CJK UNIFIED IDEOGRAPH-96E7\n96FC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-96FC\n9714          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9714\n9717          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9717\n971A..971B    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-971A..CJK UNIFIED IDEOGRAPH-971B\n9733..9734    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9733..CJK UNIFIED IDEOGRAPH-9734\n9737          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9737\n9740..9741    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9740..CJK UNIFIED IDEOGRAPH-9741\n974D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-974D\n9757          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9757\n9763          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9763\n9775          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9775\n9787          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9787\n9789          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9789\n979B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-979B\n97A9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-97A9\n97B0..97B1    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-97B0..CJK UNIFIED IDEOGRAPH-97B1\n97B5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-97B5\n97BE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-97BE\n97C0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-97C0\n97D2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-97D2\n97FC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-97FC\n981F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-981F\n9825          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9825\n982A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-982A\n9833          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9833\n983A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-983A\n983E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-983E\n9842          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9842\n9847          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9847\n9856          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9856\n9866          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9866\n9868          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9868\n98B7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-98B7\n98CA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-98CA\n98E4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-98E4\n98EC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-98EC\n98F1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-98F1\n98F8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-98F8\n98FB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-98FB\n9919          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9919\n993B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-993B\n9944          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9944\n995A          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-995A\n995D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-995D\n99BF          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-99BF\n99E0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-99E0\n99E6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-99E6\n99EB          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-99EB\n99F5          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-99F5\n9A10          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9A10\n9A17..9A18    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9A17..CJK UNIFIED IDEOGRAPH-9A18\n9A3B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9A3B\n9A51          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9A51\n9A58          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9A58\n9A5D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9A5D\n9A63          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9A63\n9AA9          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9AA9\n9ABD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9ABD\n9AC8          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9AC8\n9AD7          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9AD7\n9AE0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9AE0\n9AE4          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9AE4\n9AE8..9AE9    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9AE8..CJK UNIFIED IDEOGRAPH-9AE9\n9AF0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9AF0\n9B00          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B00\n9B02          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B02\n9B09          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B09\n9B14          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B14\n9B1B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B1B\n9B34          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B34\n9B3D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B3D\n9B40          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B40\n9B50          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B50\n9B57          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B57\n9B62          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B62\n9B72          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B72\n9B89          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B89\n9B8C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B8C\n9B99          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9B99\n9BC2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9BC2\n9BF6          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9BF6\n9C00..9C01    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9C00..CJK UNIFIED IDEOGRAPH-9C01\n9C03          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9C03\n9C42          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9C42\n9C4F          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9C4F\n9C51          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9C51\n9C61          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9C61\n9C64          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9C64\n9C7B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9C7B\n9D0C..9D0D    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9D0C..CJK UNIFIED IDEOGRAPH-9D0D\n9D11          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9D11\n9D27          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9D27\n9D35          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9D35\n9D3C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9D3C\n9D6D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9D6D\n9D95          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9D95\n9DAE          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9DAE\n9DBD          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9DBD\n9DC0          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9DC0\n9DEA          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9DEA\n9DFC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9DFC\n9E0E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9E0E\n9E16          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9E16\n9E1C          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9E1C\n9E7B          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9E7B\n9E8F..9E90    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9E8F..CJK UNIFIED IDEOGRAPH-9E90\n9E98          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9E98\n9E9E          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9E9E\n9EA2          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9EA2\n9EAB..9EAC    ; Uncommon_Use                   # 1.1    [2] CJK UNIFIED IDEOGRAPH-9EAB..CJK UNIFIED IDEOGRAPH-9EAC\n9EB1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9EB1\n9EEC          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9EEC\n9EF1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9EF1\n9F03          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9F03\n9F11          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9F11\n9F14          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9F14\n9F26          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9F26\n9F45          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9F45\n9F53          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9F53\n9F6D          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9F6D\n9FA1          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9FA1\n9FA3          ; Uncommon_Use                   # 1.1        CJK UNIFIED IDEOGRAPH-9FA3\n9FA6..9FBB    ; Uncommon_Use                   # 4.1   [22] CJK UNIFIED IDEOGRAPH-9FA6..CJK UNIFIED IDEOGRAPH-9FBB\n9FBC..9FC3    ; Uncommon_Use                   # 5.1    [8] CJK UNIFIED IDEOGRAPH-9FBC..CJK UNIFIED IDEOGRAPH-9FC3\n9FC4..9FCB    ; Uncommon_Use                   # 5.2    [8] CJK UNIFIED IDEOGRAPH-9FC4..CJK UNIFIED IDEOGRAPH-9FCB\n9FCC          ; Uncommon_Use                   # 6.1        CJK UNIFIED IDEOGRAPH-9FCC\n9FCD..9FD5    ; Uncommon_Use                   # 8.0    [9] CJK UNIFIED IDEOGRAPH-9FCD..CJK UNIFIED IDEOGRAPH-9FD5\n9FD6..9FEA    ; Uncommon_Use                   # 10.0  [21] CJK UNIFIED IDEOGRAPH-9FD6..CJK UNIFIED IDEOGRAPH-9FEA\n9FEB..9FEF    ; Uncommon_Use                   # 11.0   [5] CJK UNIFIED IDEOGRAPH-9FEB..CJK UNIFIED IDEOGRAPH-9FEF\n9FF0..9FFC    ; Uncommon_Use                   # 13.0  [13] CJK UNIFIED IDEOGRAPH-9FF0..CJK UNIFIED IDEOGRAPH-9FFC\n9FFD..9FFF    ; Uncommon_Use                   # 14.0   [3] CJK UNIFIED IDEOGRAPH-9FFD..CJK UNIFIED IDEOGRAPH-9FFF\nA66F          ; Uncommon_Use                   # 5.1        COMBINING CYRILLIC VZMET\nA67C..A67D    ; Uncommon_Use                   # 5.1    [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK\nA78B..A78C    ; Uncommon_Use                   # 5.1    [2] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER SALTILLO\nA78F          ; Uncommon_Use                   # 8.0        LATIN LETTER SINOLOGICAL DOT\nA792..A793    ; Uncommon_Use                   # 6.1    [2] LATIN CAPITAL LETTER C WITH BAR..LATIN SMALL LETTER C WITH BAR\nA7B2..A7B7    ; Uncommon_Use                   # 8.0    [6] LATIN CAPITAL LETTER J WITH CROSSED-TAIL..LATIN SMALL LETTER OMEGA\nA7B8..A7B9    ; Uncommon_Use                   # 11.0   [2] LATIN CAPITAL LETTER U WITH STROKE..LATIN SMALL LETTER U WITH STROKE\nA7C2..A7C3    ; Uncommon_Use                   # 12.0   [2] LATIN CAPITAL LETTER ANGLICANA W..LATIN SMALL LETTER ANGLICANA W\nA7CB..A7CD    ; Uncommon_Use                   # 16.0   [3] LATIN CAPITAL LETTER RAMS HORN..LATIN SMALL LETTER S WITH DIAGONAL STROKE\nA7CE..A7CF    ; Uncommon_Use                   # 17.0   [2] LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE\nA7DA..A7DC    ; Uncommon_Use                   # 16.0   [3] LATIN CAPITAL LETTER LAMBDA..LATIN CAPITAL LETTER LAMBDA WITH STROKE\nA9E7..A9FE    ; Uncommon_Use                   # 7.0   [24] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING BHA\nAA60..AA76    ; Uncommon_Use                   # 5.2   [23] MYANMAR LETTER KHAMTI GA..MYANMAR LOGOGRAM KHAMTI HM\nAA7A          ; Uncommon_Use                   # 5.2        MYANMAR LETTER AITON RA\nAA7C..AA7F    ; Uncommon_Use                   # 7.0    [4] MYANMAR SIGN TAI LAING TONE-2..MYANMAR LETTER SHWE PALAUNG SHA\nAB01..AB06    ; Uncommon_Use                   # 6.0    [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO\nAB09..AB0E    ; Uncommon_Use                   # 6.0    [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO\nAB11..AB16    ; Uncommon_Use                   # 6.0    [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO\nAB20..AB26    ; Uncommon_Use                   # 6.0    [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO\nAB28..AB2E    ; Uncommon_Use                   # 6.0    [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO\nAB60..AB63    ; Uncommon_Use                   # 8.0    [4] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER UO\nAB66..AB67    ; Uncommon_Use                   # 12.0   [2] LATIN SMALL LETTER DZ DIGRAPH WITH RETROFLEX HOOK..LATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX HOOK\nFA0E..FA0F    ; Uncommon_Use                   # 1.1    [2] CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F\nFA11          ; Uncommon_Use                   # 1.1        CJK COMPATIBILITY IDEOGRAPH-FA11\nFA13..FA14    ; Uncommon_Use                   # 1.1    [2] CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14\nFA1F          ; Uncommon_Use                   # 1.1        CJK COMPATIBILITY IDEOGRAPH-FA1F\nFA21          ; Uncommon_Use                   # 1.1        CJK COMPATIBILITY IDEOGRAPH-FA21\nFA23..FA24    ; Uncommon_Use                   # 1.1    [2] CJK COMPATIBILITY IDEOGRAPH-FA23..CJK COMPATIBILITY IDEOGRAPH-FA24\nFA27..FA29    ; Uncommon_Use                   # 1.1    [3] CJK COMPATIBILITY IDEOGRAPH-FA27..CJK COMPATIBILITY IDEOGRAPH-FA29\n10780         ; Uncommon_Use                   # 14.0       MODIFIER LETTER SMALL CAPITAL AA\n10EC2..10EC4  ; Uncommon_Use                   # 16.0   [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW\n10EC7         ; Uncommon_Use                   # 17.0       ARABIC LETTER YEH WITH FOUR DOTS BELOW\n10EFA         ; Uncommon_Use                   # 17.0       ARABIC DOUBLE VERTICAL BAR BELOW\n10EFC         ; Uncommon_Use                   # 16.0       ARABIC COMBINING ALEF OVERLAY\n10EFD..10EFF  ; Uncommon_Use                   # 15.0   [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA\n1133B         ; Uncommon_Use                   # 11.0       COMBINING BINDU BELOW\n116D0..116E3  ; Uncommon_Use                   # 16.0  [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE\n1AFF0..1AFF3  ; Uncommon_Use                   # 14.0   [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5\n1AFF5..1AFFB  ; Uncommon_Use                   # 14.0   [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5\n1AFFD..1AFFE  ; Uncommon_Use                   # 14.0   [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8\n20000..2070D  ; Uncommon_Use                   # 3.1 [1806] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2070D\n2070F..20730  ; Uncommon_Use                   # 3.1   [34] CJK UNIFIED IDEOGRAPH-2070F..CJK UNIFIED IDEOGRAPH-20730\n20732..20778  ; Uncommon_Use                   # 3.1   [71] CJK UNIFIED IDEOGRAPH-20732..CJK UNIFIED IDEOGRAPH-20778\n2077A..20C52  ; Uncommon_Use                   # 3.1 [1241] CJK UNIFIED IDEOGRAPH-2077A..CJK UNIFIED IDEOGRAPH-20C52\n20C54..20C77  ; Uncommon_Use                   # 3.1   [36] CJK UNIFIED IDEOGRAPH-20C54..CJK UNIFIED IDEOGRAPH-20C77\n20C79..20C95  ; Uncommon_Use                   # 3.1   [29] CJK UNIFIED IDEOGRAPH-20C79..CJK UNIFIED IDEOGRAPH-20C95\n20C97..20CCE  ; Uncommon_Use                   # 3.1   [56] CJK UNIFIED IDEOGRAPH-20C97..CJK UNIFIED IDEOGRAPH-20CCE\n20CD0..20CD4  ; Uncommon_Use                   # 3.1    [5] CJK UNIFIED IDEOGRAPH-20CD0..CJK UNIFIED IDEOGRAPH-20CD4\n20CD6..20D14  ; Uncommon_Use                   # 3.1   [63] CJK UNIFIED IDEOGRAPH-20CD6..CJK UNIFIED IDEOGRAPH-20D14\n20D16..20D7B  ; Uncommon_Use                   # 3.1  [102] CJK UNIFIED IDEOGRAPH-20D16..CJK UNIFIED IDEOGRAPH-20D7B\n20D7D..20D7E  ; Uncommon_Use                   # 3.1    [2] CJK UNIFIED IDEOGRAPH-20D7D..CJK UNIFIED IDEOGRAPH-20D7E\n20D80..20E0D  ; Uncommon_Use                   # 3.1  [142] CJK UNIFIED IDEOGRAPH-20D80..CJK UNIFIED IDEOGRAPH-20E0D\n20E10..20E76  ; Uncommon_Use                   # 3.1  [103] CJK UNIFIED IDEOGRAPH-20E10..CJK UNIFIED IDEOGRAPH-20E76\n20E78..20E9C  ; Uncommon_Use                   # 3.1   [37] CJK UNIFIED IDEOGRAPH-20E78..CJK UNIFIED IDEOGRAPH-20E9C\n20E9E..20EA1  ; Uncommon_Use                   # 3.1    [4] CJK UNIFIED IDEOGRAPH-20E9E..CJK UNIFIED IDEOGRAPH-20EA1\n20EA3..20ED6  ; Uncommon_Use                   # 3.1   [52] CJK UNIFIED IDEOGRAPH-20EA3..CJK UNIFIED IDEOGRAPH-20ED6\n20ED8..20EF8  ; Uncommon_Use                   # 3.1   [33] CJK UNIFIED IDEOGRAPH-20ED8..CJK UNIFIED IDEOGRAPH-20EF8\n20EFB..20F2C  ; Uncommon_Use                   # 3.1   [50] CJK UNIFIED IDEOGRAPH-20EFB..CJK UNIFIED IDEOGRAPH-20F2C\n20F2F..20F4B  ; Uncommon_Use                   # 3.1   [29] CJK UNIFIED IDEOGRAPH-20F2F..CJK UNIFIED IDEOGRAPH-20F4B\n20F4D..20FB3  ; Uncommon_Use                   # 3.1  [103] CJK UNIFIED IDEOGRAPH-20F4D..CJK UNIFIED IDEOGRAPH-20FB3\n20FB5..20FBB  ; Uncommon_Use                   # 3.1    [7] CJK UNIFIED IDEOGRAPH-20FB5..CJK UNIFIED IDEOGRAPH-20FBB\n20FBD..20FE9  ; Uncommon_Use                   # 3.1   [45] CJK UNIFIED IDEOGRAPH-20FBD..CJK UNIFIED IDEOGRAPH-20FE9\n20FEB..2105B  ; Uncommon_Use                   # 3.1  [113] CJK UNIFIED IDEOGRAPH-20FEB..CJK UNIFIED IDEOGRAPH-2105B\n2105D..2106E  ; Uncommon_Use                   # 3.1   [18] CJK UNIFIED IDEOGRAPH-2105D..CJK UNIFIED IDEOGRAPH-2106E\n21070..21074  ; Uncommon_Use                   # 3.1    [5] CJK UNIFIED IDEOGRAPH-21070..CJK UNIFIED IDEOGRAPH-21074\n21077..2107A  ; Uncommon_Use                   # 3.1    [4] CJK UNIFIED IDEOGRAPH-21077..CJK UNIFIED IDEOGRAPH-2107A\n2107C..210C0  ; Uncommon_Use                   # 3.1   [69] CJK UNIFIED IDEOGRAPH-2107C..CJK UNIFIED IDEOGRAPH-210C0\n210C2..210C8  ; Uncommon_Use                   # 3.1    [7] CJK UNIFIED IDEOGRAPH-210C2..CJK UNIFIED IDEOGRAPH-210C8\n210CA..211D8  ; Uncommon_Use                   # 3.1  [271] CJK UNIFIED IDEOGRAPH-210CA..CJK UNIFIED IDEOGRAPH-211D8\n211DA..220C6  ; Uncommon_Use                   # 3.1 [3821] CJK UNIFIED IDEOGRAPH-211DA..CJK UNIFIED IDEOGRAPH-220C6\n220C8..227B4  ; Uncommon_Use                   # 3.1 [1773] CJK UNIFIED IDEOGRAPH-220C8..CJK UNIFIED IDEOGRAPH-227B4\n227B6..22AD4  ; Uncommon_Use                   # 3.1  [799] CJK UNIFIED IDEOGRAPH-227B6..CJK UNIFIED IDEOGRAPH-22AD4\n22AD6..22B42  ; Uncommon_Use                   # 3.1  [109] CJK UNIFIED IDEOGRAPH-22AD6..CJK UNIFIED IDEOGRAPH-22B42\n22B44..22BC9  ; Uncommon_Use                   # 3.1  [134] CJK UNIFIED IDEOGRAPH-22B44..CJK UNIFIED IDEOGRAPH-22BC9\n22BCB..22C50  ; Uncommon_Use                   # 3.1  [134] CJK UNIFIED IDEOGRAPH-22BCB..CJK UNIFIED IDEOGRAPH-22C50\n22C52..22C54  ; Uncommon_Use                   # 3.1    [3] CJK UNIFIED IDEOGRAPH-22C52..CJK UNIFIED IDEOGRAPH-22C54\n22C56..22CC1  ; Uncommon_Use                   # 3.1  [108] CJK UNIFIED IDEOGRAPH-22C56..CJK UNIFIED IDEOGRAPH-22CC1\n22CC3..22D07  ; Uncommon_Use                   # 3.1   [69] CJK UNIFIED IDEOGRAPH-22CC3..CJK UNIFIED IDEOGRAPH-22D07\n22D09..22D4B  ; Uncommon_Use                   # 3.1   [67] CJK UNIFIED IDEOGRAPH-22D09..CJK UNIFIED IDEOGRAPH-22D4B\n22D4D..22D66  ; Uncommon_Use                   # 3.1   [26] CJK UNIFIED IDEOGRAPH-22D4D..CJK UNIFIED IDEOGRAPH-22D66\n22D68..22EB2  ; Uncommon_Use                   # 3.1  [331] CJK UNIFIED IDEOGRAPH-22D68..CJK UNIFIED IDEOGRAPH-22EB2\n22EB4..23CB6  ; Uncommon_Use                   # 3.1 [3587] CJK UNIFIED IDEOGRAPH-22EB4..CJK UNIFIED IDEOGRAPH-23CB6\n23CB8..244D2  ; Uncommon_Use                   # 3.1 [2075] CJK UNIFIED IDEOGRAPH-23CB8..CJK UNIFIED IDEOGRAPH-244D2\n244D4..24DB7  ; Uncommon_Use                   # 3.1 [2276] CJK UNIFIED IDEOGRAPH-244D4..CJK UNIFIED IDEOGRAPH-24DB7\n24DB9..24DE9  ; Uncommon_Use                   # 3.1   [49] CJK UNIFIED IDEOGRAPH-24DB9..CJK UNIFIED IDEOGRAPH-24DE9\n24DEB..2512A  ; Uncommon_Use                   # 3.1  [832] CJK UNIFIED IDEOGRAPH-24DEB..CJK UNIFIED IDEOGRAPH-2512A\n2512C..26257  ; Uncommon_Use                   # 3.1 [4396] CJK UNIFIED IDEOGRAPH-2512C..CJK UNIFIED IDEOGRAPH-26257\n26259..267CB  ; Uncommon_Use                   # 3.1 [1395] CJK UNIFIED IDEOGRAPH-26259..CJK UNIFIED IDEOGRAPH-267CB\n267CD..269F1  ; Uncommon_Use                   # 3.1  [549] CJK UNIFIED IDEOGRAPH-267CD..CJK UNIFIED IDEOGRAPH-269F1\n269F3..269F9  ; Uncommon_Use                   # 3.1    [7] CJK UNIFIED IDEOGRAPH-269F3..CJK UNIFIED IDEOGRAPH-269F9\n269FB..27A3D  ; Uncommon_Use                   # 3.1 [4163] CJK UNIFIED IDEOGRAPH-269FB..CJK UNIFIED IDEOGRAPH-27A3D\n27A3F..2815C  ; Uncommon_Use                   # 3.1 [1822] CJK UNIFIED IDEOGRAPH-27A3F..CJK UNIFIED IDEOGRAPH-2815C\n2815E..28206  ; Uncommon_Use                   # 3.1  [169] CJK UNIFIED IDEOGRAPH-2815E..CJK UNIFIED IDEOGRAPH-28206\n28208..282E1  ; Uncommon_Use                   # 3.1  [218] CJK UNIFIED IDEOGRAPH-28208..CJK UNIFIED IDEOGRAPH-282E1\n282E3..28CC9  ; Uncommon_Use                   # 3.1 [2535] CJK UNIFIED IDEOGRAPH-282E3..CJK UNIFIED IDEOGRAPH-28CC9\n28CCB..28CCC  ; Uncommon_Use                   # 3.1    [2] CJK UNIFIED IDEOGRAPH-28CCB..CJK UNIFIED IDEOGRAPH-28CCC\n28CCE..28CD1  ; Uncommon_Use                   # 3.1    [4] CJK UNIFIED IDEOGRAPH-28CCE..CJK UNIFIED IDEOGRAPH-28CD1\n28CD3..29D97  ; Uncommon_Use                   # 3.1 [4293] CJK UNIFIED IDEOGRAPH-28CD3..CJK UNIFIED IDEOGRAPH-29D97\n29D99..2A6D6  ; Uncommon_Use                   # 3.1 [2366] CJK UNIFIED IDEOGRAPH-29D99..CJK UNIFIED IDEOGRAPH-2A6D6\n2A6D7..2A6DD  ; Uncommon_Use                   # 13.0   [7] CJK UNIFIED IDEOGRAPH-2A6D7..CJK UNIFIED IDEOGRAPH-2A6DD\n2A6DE..2A6DF  ; Uncommon_Use                   # 14.0   [2] CJK UNIFIED IDEOGRAPH-2A6DE..CJK UNIFIED IDEOGRAPH-2A6DF\n2A700..2B734  ; Uncommon_Use                   # 5.2 [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734\n2B735..2B738  ; Uncommon_Use                   # 14.0   [4] CJK UNIFIED IDEOGRAPH-2B735..CJK UNIFIED IDEOGRAPH-2B738\n2B739         ; Uncommon_Use                   # 15.0       CJK UNIFIED IDEOGRAPH-2B739\n2B73A..2B73F  ; Uncommon_Use                   # 17.0   [6] CJK UNIFIED IDEOGRAPH-2B73A..CJK UNIFIED IDEOGRAPH-2B73F\n2B740..2B81D  ; Uncommon_Use                   # 6.0  [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D\n2B820..2CEA1  ; Uncommon_Use                   # 8.0 [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1\n2CEA2..2CEAD  ; Uncommon_Use                   # 17.0  [12] CJK UNIFIED IDEOGRAPH-2CEA2..CJK UNIFIED IDEOGRAPH-2CEAD\n2CEB0..2EBE0  ; Uncommon_Use                   # 10.0 [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0\n2EBF0..2EE5D  ; Uncommon_Use                   # 15.1 [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D\n30000..3134A  ; Uncommon_Use                   # 13.0 [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A\n31350..323AF  ; Uncommon_Use                   # 15.0 [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF\n323B0..33479  ; Uncommon_Use                   # 17.0 [4298] CJK UNIFIED IDEOGRAPH-323B0..CJK UNIFIED IDEOGRAPH-33479\n\n# Total code points: 83130\n\n#\tIdentifier_Type:\tUncommon_Use Technical\n\n05C7          ; Uncommon_Use Technical         # 4.1        HEBREW POINT QAMATS QATAN\n0653          ; Uncommon_Use Technical         # 3.0        ARABIC MADDAH ABOVE\n0D8F..0D90    ; Uncommon_Use Technical         # 3.0    [2] SINHALA LETTER ILUYANNA..SINHALA LETTER ILUUYANNA\n0DDF          ; Uncommon_Use Technical         # 3.0        SINHALA VOWEL SIGN GAYANUKITTA\n0DF3          ; Uncommon_Use Technical         # 3.0        SINHALA VOWEL SIGN DIGA GAYANUKITTA\n0FC6          ; Uncommon_Use Technical         # 3.0        TIBETAN SYMBOL PADMA GDAN\n10F9..10FA    ; Uncommon_Use Technical         # 4.1    [2] GEORGIAN LETTER TURNED GAN..GEORGIAN LETTER AIN\nFB1E          ; Uncommon_Use Technical         # 1.1        HEBREW POINT JUDEO-SPANISH VARIKA\nFE2E..FE2F    ; Uncommon_Use Technical         # 8.0    [2] COMBINING CYRILLIC TITLO LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF\n\n# Total code points: 12\n\n#\tIdentifier_Type:\tUncommon_Use Technical Not_XID\n\n1D1DE..1D1E8  ; Uncommon_Use Technical Not_XID # 8.0   [11] MUSICAL SYMBOL KIEVAN C CLEF..MUSICAL SYMBOL KIEVAN FLAT SIGN\n\n# Total code points: 11\n\n#\tIdentifier_Type:\tUncommon_Use Exclusion\n\n18A9          ; Uncommon_Use Exclusion         # 3.0        MONGOLIAN LETTER ALI GALI DAGALGA\n16A40..16A5E  ; Uncommon_Use Exclusion         # 7.0   [31] MRO LETTER TA..MRO LETTER TEK\n16A60..16A69  ; Uncommon_Use Exclusion         # 7.0   [10] MRO DIGIT ZERO..MRO DIGIT NINE\n\n# Total code points: 42\n\n#\tIdentifier_Type:\tUncommon_Use Obsolete\n\n05A2          ; Uncommon_Use Obsolete          # 4.1        HEBREW ACCENT ATNAH HAFUKH\n05C5          ; Uncommon_Use Obsolete          # 4.1        HEBREW MARK LOWER DOT\n0F6A          ; Uncommon_Use Obsolete          # 3.0        TIBETAN LETTER FIXED-FORM RA\n0F82..0F83    ; Uncommon_Use Obsolete          # 2.0    [2] TIBETAN SIGN NYI ZLA NAA DA..TIBETAN SIGN SNA LDAN\n1050..1059    ; Uncommon_Use Obsolete          # 3.0   [10] MYANMAR LETTER SHA..MYANMAR VOWEL SIGN VOCALIC LL\nA69E          ; Uncommon_Use Obsolete          # 8.0        COMBINING CYRILLIC LETTER EF\nA8FD          ; Uncommon_Use Obsolete          # 8.0        DEVANAGARI JAIN OM\n\n# Total code points: 17\n\n#\tIdentifier_Type:\tUncommon_Use Obsolete Not_XID\n\nA8FC          ; Uncommon_Use Obsolete Not_XID  # 8.0        DEVANAGARI SIGN SIDDHAM\n\n# Total code points: 1\n\n#\tIdentifier_Type:\tUncommon_Use Not_XID\n\n218A..218B    ; Uncommon_Use Not_XID           # 8.0    [2] TURNED DIGIT TWO..TURNED DIGIT THREE\n2BEC..2BEF    ; Uncommon_Use Not_XID           # 8.0    [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS\n1F54F         ; Uncommon_Use Not_XID           # 8.0        BOWL OF HYGIEIA\n\n# Total code points: 7\n\n#\tIdentifier_Type:\tTechnical\n\n0180          ; Technical                      # 1.1        LATIN SMALL LETTER B WITH STROKE\n01C0..01C3    ; Technical                      # 1.1    [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK\n0200..0217    ; Technical                      # 1.1   [24] LATIN CAPITAL LETTER A WITH DOUBLE GRAVE..LATIN SMALL LETTER U WITH INVERTED BREVE\n0234..0236    ; Technical                      # 4.0    [3] LATIN SMALL LETTER L WITH CURL..LATIN SMALL LETTER T WITH CURL\n0250..0252    ; Technical                      # 1.1    [3] LATIN SMALL LETTER TURNED A..LATIN SMALL LETTER TURNED ALPHA\n0255          ; Technical                      # 1.1        LATIN SMALL LETTER C WITH CURL\n0258          ; Technical                      # 1.1        LATIN SMALL LETTER REVERSED E\n025A          ; Technical                      # 1.1        LATIN SMALL LETTER SCHWA WITH HOOK\n025C..0262    ; Technical                      # 1.1    [7] LATIN SMALL LETTER REVERSED OPEN E..LATIN LETTER SMALL CAPITAL G\n0264..0267    ; Technical                      # 1.1    [4] LATIN SMALL LETTER RAMS HORN..LATIN SMALL LETTER HENG WITH HOOK\n026A..0271    ; Technical                      # 1.1    [8] LATIN LETTER SMALL CAPITAL I..LATIN SMALL LETTER M WITH HOOK\n0273..0276    ; Technical                      # 1.1    [4] LATIN SMALL LETTER N WITH RETROFLEX HOOK..LATIN LETTER SMALL CAPITAL OE\n0278..027B    ; Technical                      # 1.1    [4] LATIN SMALL LETTER PHI..LATIN SMALL LETTER TURNED R WITH HOOK\n027D..0288    ; Technical                      # 1.1   [12] LATIN SMALL LETTER R WITH TAIL..LATIN SMALL LETTER T WITH RETROFLEX HOOK\n028A          ; Technical                      # 1.1        LATIN SMALL LETTER UPSILON\n028C..0291    ; Technical                      # 1.1    [6] LATIN SMALL LETTER TURNED V..LATIN SMALL LETTER Z WITH CURL\n0293..029D    ; Technical                      # 1.1   [11] LATIN SMALL LETTER EZH WITH CURL..LATIN SMALL LETTER J WITH CROSSED-TAIL\n029F..02A8    ; Technical                      # 1.1   [10] LATIN LETTER SMALL CAPITAL L..LATIN SMALL LETTER TC DIGRAPH WITH CURL\n02A9..02AD    ; Technical                      # 3.0    [5] LATIN SMALL LETTER FENG DIGRAPH..LATIN LETTER BIDENTAL PERCUSSIVE\n02AE..02AF    ; Technical                      # 4.0    [2] LATIN SMALL LETTER TURNED H WITH FISHHOOK..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL\n02B9..02BA    ; Technical                      # 1.1    [2] MODIFIER LETTER PRIME..MODIFIER LETTER DOUBLE PRIME\n02BD..02C1    ; Technical                      # 1.1    [5] MODIFIER LETTER REVERSED COMMA..MODIFIER LETTER REVERSED GLOTTAL STOP\n02C6..02D1    ; Technical                      # 1.1   [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON\n02EC          ; Technical                      # 3.0        MODIFIER LETTER VOICING\n02EE          ; Technical                      # 3.0        MODIFIER LETTER DOUBLE APOSTROPHE\n030E..0315    ; Technical                      # 1.1    [8] COMBINING DOUBLE VERTICAL LINE ABOVE..COMBINING COMMA ABOVE RIGHT\n0317..031A    ; Technical                      # 1.1    [4] COMBINING ACUTE ACCENT BELOW..COMBINING LEFT ANGLE ABOVE\n031C..0320    ; Technical                      # 1.1    [5] COMBINING LEFT HALF RING BELOW..COMBINING MINUS SIGN BELOW\n0324..0325    ; Technical                      # 1.1    [2] COMBINING DIAERESIS BELOW..COMBINING RING BELOW\n0329..0330    ; Technical                      # 1.1    [8] COMBINING VERTICAL LINE BELOW..COMBINING TILDE BELOW\n0333          ; Technical                      # 1.1        COMBINING DOUBLE LOW LINE\n0335          ; Technical                      # 1.1        COMBINING SHORT STROKE OVERLAY\n0337..033F    ; Technical                      # 1.1    [9] COMBINING SHORT SOLIDUS OVERLAY..COMBINING DOUBLE OVERLINE\n0342          ; Technical                      # 1.1        COMBINING GREEK PERISPOMENI\n0346..034E    ; Technical                      # 3.0    [9] COMBINING BRIDGE ABOVE..COMBINING UPWARDS ARROW BELOW\n0350..0357    ; Technical                      # 4.0    [8] COMBINING RIGHT ARROWHEAD ABOVE..COMBINING RIGHT HALF RING ABOVE\n0359..035C    ; Technical                      # 4.1    [4] COMBINING ASTERISK BELOW..COMBINING DOUBLE BREVE BELOW\n035D..035F    ; Technical                      # 4.0    [3] COMBINING DOUBLE BREVE..COMBINING DOUBLE MACRON BELOW\n0360..0361    ; Technical                      # 1.1    [2] COMBINING DOUBLE TILDE..COMBINING DOUBLE INVERTED BREVE\n0362          ; Technical                      # 3.0        COMBINING DOUBLE RIGHTWARDS ARROW BELOW\n03CF          ; Technical                      # 5.1        GREEK CAPITAL KAI SYMBOL\n03D7          ; Technical                      # 3.0        GREEK KAI SYMBOL\n0559          ; Technical                      # 1.1        ARMENIAN MODIFIER LETTER LEFT HALF RING\n0560          ; Technical                      # 11.0       ARMENIAN SMALL LETTER TURNED AYB\n0588          ; Technical                      # 11.0       ARMENIAN SMALL LETTER YI WITH STROKE\n0671          ; Technical                      # 1.1        ARABIC LETTER ALEF WASLA\n06E5..06E6    ; Technical                      # 1.1    [2] ARABIC SMALL WAW..ARABIC SMALL YEH\n0870..0887    ; Technical                      # 14.0  [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT\n08C9          ; Technical                      # 14.0       ARABIC SMALL FARSI YEH\n0950          ; Technical                      # 1.1        DEVANAGARI OM\n0953..0954    ; Technical                      # 1.1    [2] DEVANAGARI GRAVE ACCENT..DEVANAGARI ACUTE ACCENT\n097D          ; Technical                      # 4.1        DEVANAGARI LETTER GLOTTAL STOP\n0A74          ; Technical                      # 1.1        GURMUKHI EK ONKAR\n0AD0          ; Technical                      # 1.1        GUJARATI OM\n0B82          ; Technical                      # 1.1        TAMIL SIGN ANUSVARA\n0BD0          ; Technical                      # 5.1        TAMIL OM\n0D81          ; Technical                      # 13.0       SINHALA SIGN CANDRABINDU\n0EAF          ; Technical                      # 1.1        LAO ELLIPSIS\n0F00          ; Technical                      # 2.0        TIBETAN SYLLABLE OM\n0F18..0F19    ; Technical                      # 2.0    [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS\n0F35          ; Technical                      # 2.0        TIBETAN MARK NGAS BZUNG NYI ZLA\n0F37          ; Technical                      # 2.0        TIBETAN MARK NGAS BZUNG SGOR RTAGS\n0F3E..0F3F    ; Technical                      # 2.0    [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES\n17CE..17CF    ; Technical                      # 3.0    [2] KHMER SIGN KAKABAT..KHMER SIGN AHSDA\n1ABF..1AC0    ; Technical                      # 13.0   [2] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER TURNED W BELOW\n1ACF..1ADD    ; Technical                      # 17.0  [15] COMBINING DOUBLE CARON..COMBINING DOT-AND-RING BELOW\n1AE0..1AEB    ; Technical                      # 17.0  [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE\n1D00..1D2B    ; Technical                      # 4.0   [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL\n1D2F          ; Technical                      # 4.0        MODIFIER LETTER CAPITAL BARRED B\n1D3B          ; Technical                      # 4.0        MODIFIER LETTER CAPITAL REVERSED N\n1D4E          ; Technical                      # 4.0        MODIFIER LETTER SMALL TURNED I\n1D6B          ; Technical                      # 4.0        LATIN SMALL LETTER UE\n1D6C..1D77    ; Technical                      # 4.1   [12] LATIN SMALL LETTER B WITH MIDDLE TILDE..LATIN SMALL LETTER TURNED G\n1D79..1D9A    ; Technical                      # 4.1   [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK\n1DC4..1DCA    ; Technical                      # 5.0    [7] COMBINING MACRON-ACUTE..COMBINING LATIN SMALL LETTER R BELOW\n1DCB..1DCD    ; Technical                      # 5.1    [3] COMBINING BREVE-MACRON..COMBINING DOUBLE CIRCUMFLEX ABOVE\n1DCF..1DD0    ; Technical                      # 5.1    [2] COMBINING ZIGZAG BELOW..COMBINING IS BELOW\n1DE7..1DF5    ; Technical                      # 7.0   [15] COMBINING LATIN SMALL LETTER ALPHA..COMBINING UP TACK ABOVE\n1DF6..1DF9    ; Technical                      # 10.0   [4] COMBINING KAVYKA ABOVE RIGHT..COMBINING WIDE INVERTED BRIDGE BELOW\n1DFB          ; Technical                      # 9.0        COMBINING DELETION MARK\n1DFC          ; Technical                      # 6.0        COMBINING DOUBLE INVERTED BREVE BELOW\n1DFD          ; Technical                      # 5.2        COMBINING ALMOST EQUAL TO BELOW\n1DFE..1DFF    ; Technical                      # 5.0    [2] COMBINING LEFT ARROWHEAD ABOVE..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW\n1E00..1E01    ; Technical                      # 1.1    [2] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER A WITH RING BELOW\n1E18..1E1B    ; Technical                      # 1.1    [4] LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW..LATIN SMALL LETTER E WITH TILDE BELOW\n1E2A..1E2D    ; Technical                      # 1.1    [4] LATIN CAPITAL LETTER H WITH BREVE BELOW..LATIN SMALL LETTER I WITH TILDE BELOW\n1E72..1E77    ; Technical                      # 1.1    [6] LATIN CAPITAL LETTER U WITH DIAERESIS BELOW..LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW\n1E9C..1E9D    ; Technical                      # 5.1    [2] LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE..LATIN SMALL LETTER LONG S WITH HIGH STROKE\n1E9F          ; Technical                      # 5.1        LATIN SMALL LETTER DELTA\n1EFA..1EFF    ; Technical                      # 5.1    [6] LATIN CAPITAL LETTER MIDDLE-WELSH LL..LATIN SMALL LETTER Y WITH LOOP\n203F..2040    ; Technical                      # 1.1    [2] UNDERTIE..CHARACTER TIE\n20D0..20DC    ; Technical                      # 1.1   [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE\n20E1          ; Technical                      # 1.1        COMBINING LEFT RIGHT ARROW ABOVE\n20E5..20EA    ; Technical                      # 3.2    [6] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING LEFTWARDS ARROW OVERLAY\n20EB          ; Technical                      # 4.1        COMBINING LONG DOUBLE SOLIDUS OVERLAY\n20EC..20EF    ; Technical                      # 5.0    [4] COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS..COMBINING RIGHT ARROW BELOW\n20F0          ; Technical                      # 5.1        COMBINING ASTERISK ABOVE\n2118          ; Technical                      # 1.1        SCRIPT CAPITAL P\n212E          ; Technical                      # 1.1        ESTIMATED SYMBOL\n2C60..2C67    ; Technical                      # 5.0    [8] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN CAPITAL LETTER H WITH DESCENDER\n2C77          ; Technical                      # 5.0        LATIN SMALL LETTER TAILLESS PHI\n2C78..2C7B    ; Technical                      # 5.1    [4] LATIN SMALL LETTER E WITH NOTCH..LATIN LETTER SMALL CAPITAL TURNED E\n2D27          ; Technical                      # 6.1        GEORGIAN SMALL LETTER YN\n2D2D          ; Technical                      # 6.1        GEORGIAN SMALL LETTER AEN\n3021..302D    ; Technical                      # 1.1   [13] HANGZHOU NUMERAL ONE..IDEOGRAPHIC ENTERING TONE MARK\n3031..3035    ; Technical                      # 1.1    [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF\n303B..303C    ; Technical                      # 3.2    [2] VERTICAL IDEOGRAPHIC ITERATION MARK..MASU MARK\nA717..A71A    ; Technical                      # 5.0    [4] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOWER RIGHT CORNER ANGLE\nA71B..A71F    ; Technical                      # 5.1    [5] MODIFIER LETTER RAISED UP ARROW..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK\nA788          ; Technical                      # 5.1        MODIFIER LETTER LOW CIRCUMFLEX ACCENT\nA78E          ; Technical                      # 6.0        LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT\nA7AE          ; Technical                      # 9.0        LATIN CAPITAL LETTER SMALL CAPITAL I\nA7AF          ; Technical                      # 11.0       LATIN LETTER SMALL CAPITAL Q\nA7BA..A7BF    ; Technical                      # 12.0   [6] LATIN CAPITAL LETTER GLOTTAL A..LATIN SMALL LETTER GLOTTAL U\nA7C5..A7C6    ; Technical                      # 12.0   [2] LATIN CAPITAL LETTER S WITH HOOK..LATIN CAPITAL LETTER Z WITH PALATAL HOOK\nA7FA          ; Technical                      # 6.0        LATIN LETTER SMALL CAPITAL TURNED M\nAB68          ; Technical                      # 13.0       LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE\nFE20..FE23    ; Technical                      # 1.1    [4] COMBINING LIGATURE LEFT HALF..COMBINING DOUBLE TILDE RIGHT HALF\nFE24..FE26    ; Technical                      # 5.1    [3] COMBINING MACRON LEFT HALF..COMBINING CONJOINING MACRON\nFE27..FE2D    ; Technical                      # 7.0    [7] COMBINING LIGATURE LEFT HALF BELOW..COMBINING CONJOINING MACRON BELOW\nFE73          ; Technical                      # 3.2        ARABIC TAIL FRAGMENT\n10EC5..10EC6  ; Technical                      # 17.0   [2] ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW..ARABIC LETTER THIN NOON\n10EFB         ; Technical                      # 17.0       ARABIC SMALL LOW NOON\n16FF2..16FF6  ; Technical                      # 17.0   [5] CHINESE SMALL SIMPLIFIED ER..YANGQIN SIGN SLOW TWO BEATS\n1CF00..1CF2D  ; Technical                      # 14.0  [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT\n1CF30..1CF46  ; Technical                      # 14.0  [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG\n1D165..1D169  ; Technical                      # 3.1    [5] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING TREMOLO-3\n1D16D..1D172  ; Technical                      # 3.1    [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5\n1D17B..1D182  ; Technical                      # 3.1    [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE\n1D185..1D18B  ; Technical                      # 3.1    [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE\n1D1AA..1D1AD  ; Technical                      # 3.1    [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO\n1DF00..1DF1E  ; Technical                      # 14.0  [31] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER S WITH CURL\n1DF25..1DF2A  ; Technical                      # 15.0   [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK\n\n# Total code points: 682\n\n#\tIdentifier_Type:\tTechnical Exclusion\n\n2CF0..2CF1    ; Technical Exclusion            # 5.2    [2] COPTIC COMBINING SPIRITUS ASPER..COPTIC COMBINING SPIRITUS LENIS\n\n# Total code points: 2\n\n#\tIdentifier_Type:\tTechnical Obsolete\n\n018D          ; Technical Obsolete             # 1.1        LATIN SMALL LETTER TURNED DELTA\n01AA..01AB    ; Technical Obsolete             # 1.1    [2] LATIN LETTER REVERSED ESH LOOP..LATIN SMALL LETTER T WITH PALATAL HOOK\n01BA..01BB    ; Technical Obsolete             # 1.1    [2] LATIN SMALL LETTER EZH WITH TAIL..LATIN LETTER TWO WITH STROKE\n01BE          ; Technical Obsolete             # 1.1        LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE\n0277          ; Technical Obsolete             # 1.1        LATIN SMALL LETTER CLOSED OMEGA\n027C          ; Technical Obsolete             # 1.1        LATIN SMALL LETTER R WITH LONG LEG\n029E          ; Technical Obsolete             # 1.1        LATIN SMALL LETTER TURNED K\n03F3          ; Technical Obsolete             # 1.1        GREEK LETTER YOT\n03FC          ; Technical Obsolete             # 4.1        GREEK RHO WITH STROKE SYMBOL\n0484..0486    ; Technical Obsolete             # 1.1    [3] COMBINING CYRILLIC PALATALIZATION..COMBINING CYRILLIC PSILI PNEUMATA\n0487          ; Technical Obsolete             # 5.1        COMBINING CYRILLIC POKRYTIE\n0D04          ; Technical Obsolete             # 13.0       MALAYALAM LETTER VEDIC ANUSVARA\n17D1          ; Technical Obsolete             # 3.0        KHMER SIGN VIRIAM\n17DD          ; Technical Obsolete             # 4.0        KHMER SIGN ATTHACAN\n1DC0..1DC3    ; Technical Obsolete             # 4.1    [4] COMBINING DOTTED GRAVE ACCENT..COMBINING SUSPENSION MARK\n1DCE          ; Technical Obsolete             # 5.1        COMBINING OGONEK ABOVE\n1DD1..1DE6    ; Technical Obsolete             # 5.1   [22] COMBINING UR ABOVE..COMBINING LATIN SMALL LETTER Z\n1FB0..1FB1    ; Technical Obsolete             # 1.1    [2] GREEK SMALL LETTER ALPHA WITH VRACHY..GREEK SMALL LETTER ALPHA WITH MACRON\n2180..2182    ; Technical Obsolete             # 1.1    [3] ROMAN NUMERAL ONE THOUSAND C D..ROMAN NUMERAL TEN THOUSAND\n2183          ; Technical Obsolete             # 3.0        ROMAN NUMERAL REVERSED ONE HUNDRED\n302E..302F    ; Technical Obsolete             # 1.1    [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK\nA722..A72F    ; Technical Obsolete             # 5.1   [14] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CUATRILLO WITH COMMA\n1D242..1D244  ; Technical Obsolete             # 4.1    [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME\n\n# Total code points: 70\n\n#\tIdentifier_Type:\tTechnical Obsolete Not_XID\n\n2E00..2E0D    ; Technical Obsolete Not_XID     # 4.1   [14] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT RAISED OMISSION BRACKET\n\n# Total code points: 14\n\n#\tIdentifier_Type:\tTechnical Not_XID\n\n0375          ; Technical Not_XID              # 1.1        GREEK LOWER NUMERAL SIGN\n0888          ; Technical Not_XID              # 14.0       ARABIC RAISED ROUND DOT\n20DD..20E0    ; Technical Not_XID              # 1.1    [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH\n20E2..20E3    ; Technical Not_XID              # 3.0    [2] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING KEYCAP\n20E4          ; Technical Not_XID              # 3.2        COMBINING ENCLOSING UPWARD POINTING TRIANGLE\n24EB..24FE    ; Technical Not_XID              # 3.2   [20] NEGATIVE CIRCLED NUMBER ELEVEN..DOUBLE CIRCLED NUMBER TEN\n24FF          ; Technical Not_XID              # 4.0        NEGATIVE CIRCLED DIGIT ZERO\n2800..28FF    ; Technical Not_XID              # 3.0  [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678\n327F          ; Technical Not_XID              # 1.1        KOREAN STANDARD SYMBOL\n4DC0..4DFF    ; Technical Not_XID              # 4.0   [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION\nA708..A716    ; Technical Not_XID              # 4.1   [15] MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR\nFBB2..FBC1    ; Technical Not_XID              # 6.0   [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW\nFBC2          ; Technical Not_XID              # 14.0       ARABIC SYMBOL WASLA ABOVE\nFBC3..FBD2    ; Technical Not_XID              # 17.0  [16] ARABIC LIGATURE JALLA WA-ALAA..ARABIC LIGATURE ALAYHI AR-RAHMAH\nFD3E..FD3F    ; Technical Not_XID              # 1.1    [2] ORNATE LEFT PARENTHESIS..ORNATE RIGHT PARENTHESIS\nFD40..FD4F    ; Technical Not_XID              # 14.0  [16] ARABIC LIGATURE RAHIMAHU ALLAAH..ARABIC LIGATURE RAHIMAHUM ALLAAH\nFD90..FD91    ; Technical Not_XID              # 17.0   [2] ARABIC LIGATURE RAHMATU ALLAAHI ALAYH..ARABIC LIGATURE RAHMATU ALLAAHI ALAYHAA\nFDC8..FDCE    ; Technical Not_XID              # 17.0   [7] ARABIC LIGATURE RAHIMAHU ALLAAH TAAALAA..ARABIC LIGATURE KARRAMA ALLAAHU WAJHAH\nFDCF          ; Technical Not_XID              # 14.0       ARABIC LIGATURE SALAAMUHU ALAYNAA\nFDFD          ; Technical Not_XID              # 4.0        ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM\nFDFE..FDFF    ; Technical Not_XID              # 14.0   [2] ARABIC LIGATURE SUBHAANAHU WA TAAALAA..ARABIC LIGATURE AZZA WA JALL\nFE45..FE46    ; Technical Not_XID              # 3.2    [2] SESAME DOT..WHITE SESAME DOT\n1CF50..1CFC3  ; Technical Not_XID              # 14.0 [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK\n1D000..1D0F5  ; Technical Not_XID              # 3.1  [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO\n1D100..1D126  ; Technical Not_XID              # 3.1   [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2\n1D129         ; Technical Not_XID              # 5.1        MUSICAL SYMBOL MULTIPLE MEASURE REST\n1D12A..1D15D  ; Technical Not_XID              # 3.1   [52] MUSICAL SYMBOL DOUBLE SHARP..MUSICAL SYMBOL WHOLE NOTE\n1D16A..1D16C  ; Technical Not_XID              # 3.1    [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3\n1D183..1D184  ; Technical Not_XID              # 3.1    [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN\n1D18C..1D1A9  ; Technical Not_XID              # 3.1   [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH\n1D1AE..1D1BA  ; Technical Not_XID              # 3.1   [13] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL SEMIBREVIS BLACK\n1D1C1..1D1DD  ; Technical Not_XID              # 3.1   [29] MUSICAL SYMBOL LONGA PERFECTA REST..MUSICAL SYMBOL PES SUBPUNCTIS\n1D1E9..1D1EA  ; Technical Not_XID              # 14.0   [2] MUSICAL SYMBOL SORI..MUSICAL SYMBOL KORON\n1D300..1D356  ; Technical Not_XID              # 4.0   [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING\n\n# Total code points: 1052\n\n#\tIdentifier_Type:\tExclusion\n\n03E2..03EF    ; Exclusion                      # 1.1   [14] COPTIC CAPITAL LETTER SHEI..COPTIC SMALL LETTER DEI\n0800..082D    ; Exclusion                      # 5.2   [46] SAMARITAN LETTER ALAF..SAMARITAN MARK NEQUDAA\n1681..169A    ; Exclusion                      # 3.0   [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH\n16A0..16EA    ; Exclusion                      # 3.0   [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X\n16EE..16F0    ; Exclusion                      # 3.0    [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL\n16F1..16F8    ; Exclusion                      # 7.0    [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC\n1700..170C    ; Exclusion                      # 3.2   [13] TAGALOG LETTER A..TAGALOG LETTER YA\n170D          ; Exclusion                      # 14.0       TAGALOG LETTER RA\n170E..1714    ; Exclusion                      # 3.2    [7] TAGALOG LETTER LA..TAGALOG SIGN VIRAMA\n1715          ; Exclusion                      # 14.0       TAGALOG SIGN PAMUDPOD\n171F          ; Exclusion                      # 14.0       TAGALOG LETTER ARCHAIC RA\n1720..1734    ; Exclusion                      # 3.2   [21] HANUNOO LETTER A..HANUNOO SIGN PAMUDPOD\n1740..1753    ; Exclusion                      # 3.2   [20] BUHID LETTER A..BUHID VOWEL SIGN U\n1760..176C    ; Exclusion                      # 3.2   [13] TAGBANWA LETTER A..TAGBANWA LETTER YA\n176E..1770    ; Exclusion                      # 3.2    [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA\n1772..1773    ; Exclusion                      # 3.2    [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U\n1810..1819    ; Exclusion                      # 3.0   [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE\n1820..1877    ; Exclusion                      # 3.0   [88] MONGOLIAN LETTER A..MONGOLIAN LETTER MANCHU ZHA\n1878          ; Exclusion                      # 11.0       MONGOLIAN LETTER CHA WITH TWO DOTS\n1880..18A8    ; Exclusion                      # 3.0   [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA\n18AA          ; Exclusion                      # 5.1        MONGOLIAN LETTER MANCHU ALI GALI LHA\n1A00..1A1B    ; Exclusion                      # 4.1   [28] BUGINESE LETTER KA..BUGINESE VOWEL SIGN AE\n1CFA          ; Exclusion                      # 12.0       VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA\n2C00..2C2E    ; Exclusion                      # 4.1   [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE\n2C2F          ; Exclusion                      # 14.0       GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI\n2C30..2C5E    ; Exclusion                      # 4.1   [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE\n2C5F          ; Exclusion                      # 14.0       GLAGOLITIC SMALL LETTER CAUDATE CHRIVI\n2C80..2CE4    ; Exclusion                      # 4.1  [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI\n2CEB..2CEF    ; Exclusion                      # 5.2    [5] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC COMBINING NI ABOVE\n2CF2..2CF3    ; Exclusion                      # 6.1    [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI\nA840..A873    ; Exclusion                      # 5.0   [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU\nA930..A953    ; Exclusion                      # 5.1   [36] REJANG LETTER KA..REJANG VIRAMA\n10000..1000B  ; Exclusion                      # 4.0   [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE\n1000D..10026  ; Exclusion                      # 4.0   [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO\n10028..1003A  ; Exclusion                      # 4.0   [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO\n1003C..1003D  ; Exclusion                      # 4.0    [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE\n1003F..1004D  ; Exclusion                      # 4.0   [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO\n10050..1005D  ; Exclusion                      # 4.0   [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089\n10080..100FA  ; Exclusion                      # 4.0  [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305\n10280..1029C  ; Exclusion                      # 5.1   [29] LYCIAN LETTER A..LYCIAN LETTER X\n102A0..102D0  ; Exclusion                      # 5.1   [49] CARIAN LETTER A..CARIAN LETTER UUU3\n10300..1031E  ; Exclusion                      # 3.1   [31] OLD ITALIC LETTER A..OLD ITALIC LETTER UU\n1031F         ; Exclusion                      # 7.0        OLD ITALIC LETTER ESS\n1032D..1032F  ; Exclusion                      # 10.0   [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE\n10330..1034A  ; Exclusion                      # 3.1   [27] GOTHIC LETTER AHSA..GOTHIC LETTER NINE HUNDRED\n10350..1037A  ; Exclusion                      # 7.0   [43] OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII\n10380..1039D  ; Exclusion                      # 4.0   [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU\n103A0..103C3  ; Exclusion                      # 4.1   [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA\n103C8..103CF  ; Exclusion                      # 4.1    [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH\n103D1..103D5  ; Exclusion                      # 4.1    [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED\n10400..10425  ; Exclusion                      # 3.1   [38] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER ENG\n10426..10427  ; Exclusion                      # 4.0    [2] DESERET CAPITAL LETTER OI..DESERET CAPITAL LETTER EW\n10428..1044D  ; Exclusion                      # 3.1   [38] DESERET SMALL LETTER LONG I..DESERET SMALL LETTER ENG\n1044E..1049D  ; Exclusion                      # 4.0   [80] DESERET SMALL LETTER OI..OSMANYA LETTER OO\n104A0..104A9  ; Exclusion                      # 4.0   [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE\n10500..10527  ; Exclusion                      # 7.0   [40] ELBASAN LETTER A..ELBASAN LETTER KHE\n10530..10563  ; Exclusion                      # 7.0   [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW\n10570..1057A  ; Exclusion                      # 14.0  [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA\n1057C..1058A  ; Exclusion                      # 14.0  [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE\n1058C..10592  ; Exclusion                      # 14.0   [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE\n10594..10595  ; Exclusion                      # 14.0   [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE\n10597..105A1  ; Exclusion                      # 14.0  [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA\n105A3..105B1  ; Exclusion                      # 14.0  [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE\n105B3..105B9  ; Exclusion                      # 14.0   [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE\n105BB..105BC  ; Exclusion                      # 14.0   [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE\n105C0..105F3  ; Exclusion                      # 16.0  [52] TODHRI LETTER A..TODHRI LETTER OO\n10600..10736  ; Exclusion                      # 7.0  [311] LINEAR A SIGN AB001..LINEAR A SIGN A664\n10740..10755  ; Exclusion                      # 7.0   [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE\n10760..10767  ; Exclusion                      # 7.0    [8] LINEAR A SIGN A800..LINEAR A SIGN A807\n10800..10805  ; Exclusion                      # 4.0    [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA\n10808         ; Exclusion                      # 4.0        CYPRIOT SYLLABLE JO\n1080A..10835  ; Exclusion                      # 4.0   [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO\n10837..10838  ; Exclusion                      # 4.0    [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE\n1083C         ; Exclusion                      # 4.0        CYPRIOT SYLLABLE ZA\n1083F         ; Exclusion                      # 4.0        CYPRIOT SYLLABLE ZO\n10840..10855  ; Exclusion                      # 5.2   [22] IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW\n10860..10876  ; Exclusion                      # 7.0   [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW\n10880..1089E  ; Exclusion                      # 7.0   [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW\n108E0..108F2  ; Exclusion                      # 8.0   [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH\n108F4..108F5  ; Exclusion                      # 8.0    [2] HATRAN LETTER SHIN..HATRAN LETTER TAW\n10900..10915  ; Exclusion                      # 5.0   [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU\n10920..10939  ; Exclusion                      # 5.1   [26] LYDIAN LETTER A..LYDIAN LETTER C\n10940..10959  ; Exclusion                      # 17.0  [26] SIDETIC LETTER N01..SIDETIC LETTER N26\n10980..109B7  ; Exclusion                      # 6.1   [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA\n109BE..109BF  ; Exclusion                      # 6.1    [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN\n10A00..10A03  ; Exclusion                      # 4.1    [4] KHAROSHTHI LETTER A..KHAROSHTHI VOWEL SIGN VOCALIC R\n10A05..10A06  ; Exclusion                      # 4.1    [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O\n10A0C..10A13  ; Exclusion                      # 4.1    [8] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI LETTER GHA\n10A15..10A17  ; Exclusion                      # 4.1    [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA\n10A19..10A33  ; Exclusion                      # 4.1   [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA\n10A34..10A35  ; Exclusion                      # 11.0   [2] KHAROSHTHI LETTER TTTA..KHAROSHTHI LETTER VHA\n10A38..10A3A  ; Exclusion                      # 4.1    [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW\n10A3F         ; Exclusion                      # 4.1        KHAROSHTHI VIRAMA\n10A60..10A7C  ; Exclusion                      # 5.2   [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH\n10A80..10A9C  ; Exclusion                      # 7.0   [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH\n10AC0..10AC7  ; Exclusion                      # 7.0    [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW\n10AC9..10AE6  ; Exclusion                      # 7.0   [30] MANICHAEAN LETTER ZAYIN..MANICHAEAN ABBREVIATION MARK BELOW\n10B00..10B35  ; Exclusion                      # 5.2   [54] AVESTAN LETTER A..AVESTAN LETTER HE\n10B40..10B55  ; Exclusion                      # 5.2   [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW\n10B60..10B72  ; Exclusion                      # 5.2   [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW\n10B80..10B91  ; Exclusion                      # 7.0   [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW\n10C00..10C48  ; Exclusion                      # 5.2   [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH\n10C80..10CB2  ; Exclusion                      # 8.0   [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US\n10CC0..10CF2  ; Exclusion                      # 8.0   [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US\n10D40..10D65  ; Exclusion                      # 16.0  [38] GARAY DIGIT ZERO..GARAY CAPITAL LETTER OLD NA\n10D69..10D6D  ; Exclusion                      # 16.0   [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK\n10D6F..10D85  ; Exclusion                      # 16.0  [23] GARAY REDUPLICATION MARK..GARAY SMALL LETTER OLD NA\n10E80..10EA9  ; Exclusion                      # 13.0  [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET\n10EAB..10EAC  ; Exclusion                      # 13.0   [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK\n10EB0..10EB1  ; Exclusion                      # 13.0   [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE\n10F00..10F1C  ; Exclusion                      # 11.0  [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL\n10F27         ; Exclusion                      # 11.0       OLD SOGDIAN LIGATURE AYIN-DALETH\n10F30..10F50  ; Exclusion                      # 11.0  [33] SOGDIAN LETTER ALEPH..SOGDIAN COMBINING STROKE BELOW\n10F70..10F85  ; Exclusion                      # 14.0  [22] OLD UYGHUR LETTER ALEPH..OLD UYGHUR COMBINING TWO DOTS BELOW\n10FB0..10FC4  ; Exclusion                      # 13.0  [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW\n10FE0..10FF6  ; Exclusion                      # 12.0  [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH\n11000..11046  ; Exclusion                      # 6.0   [71] BRAHMI SIGN CANDRABINDU..BRAHMI VIRAMA\n11066..1106F  ; Exclusion                      # 6.0   [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE\n11070..11075  ; Exclusion                      # 14.0   [6] BRAHMI SIGN OLD TAMIL VIRAMA..BRAHMI LETTER OLD TAMIL LLA\n1107F         ; Exclusion                      # 7.0        BRAHMI NUMBER JOINER\n11080..110BA  ; Exclusion                      # 5.2   [59] KAITHI SIGN CANDRABINDU..KAITHI SIGN NUKTA\n110C2         ; Exclusion                      # 14.0       KAITHI VOWEL SIGN VOCALIC R\n110D0..110E8  ; Exclusion                      # 6.1   [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE\n110F0..110F9  ; Exclusion                      # 6.1   [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE\n11150..11173  ; Exclusion                      # 7.0   [36] MAHAJANI LETTER A..MAHAJANI SIGN NUKTA\n11176         ; Exclusion                      # 7.0        MAHAJANI LIGATURE SHRI\n11180..111C4  ; Exclusion                      # 6.1   [69] SHARADA SIGN CANDRABINDU..SHARADA OM\n111C9..111CC  ; Exclusion                      # 8.0    [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK\n111CE..111CF  ; Exclusion                      # 13.0   [2] SHARADA VOWEL SIGN PRISHTHAMATRA E..SHARADA SIGN INVERTED CANDRABINDU\n111D0..111D9  ; Exclusion                      # 6.1   [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE\n111DA         ; Exclusion                      # 7.0        SHARADA EKAM\n111DC         ; Exclusion                      # 8.0        SHARADA HEADSTROKE\n11200..11211  ; Exclusion                      # 7.0   [18] KHOJKI LETTER A..KHOJKI LETTER JJA\n11213..11237  ; Exclusion                      # 7.0   [37] KHOJKI LETTER NYA..KHOJKI SIGN SHADDA\n1123E         ; Exclusion                      # 9.0        KHOJKI SIGN SUKUN\n1123F..11241  ; Exclusion                      # 15.0   [3] KHOJKI LETTER QA..KHOJKI VOWEL SIGN VOCALIC R\n11280..11286  ; Exclusion                      # 8.0    [7] MULTANI LETTER A..MULTANI LETTER GA\n11288         ; Exclusion                      # 8.0        MULTANI LETTER GHA\n1128A..1128D  ; Exclusion                      # 8.0    [4] MULTANI LETTER CA..MULTANI LETTER JJA\n1128F..1129D  ; Exclusion                      # 8.0   [15] MULTANI LETTER NYA..MULTANI LETTER BA\n1129F..112A8  ; Exclusion                      # 8.0   [10] MULTANI LETTER BHA..MULTANI LETTER RHA\n112B0..112EA  ; Exclusion                      # 7.0   [59] KHUDAWADI LETTER A..KHUDAWADI SIGN VIRAMA\n112F0..112F9  ; Exclusion                      # 7.0   [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE\n11300         ; Exclusion                      # 8.0        GRANTHA SIGN COMBINING ANUSVARA ABOVE\n11302         ; Exclusion                      # 7.0        GRANTHA SIGN ANUSVARA\n11305..1130C  ; Exclusion                      # 7.0    [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L\n1130F..11310  ; Exclusion                      # 7.0    [2] GRANTHA LETTER EE..GRANTHA LETTER AI\n11313..11328  ; Exclusion                      # 7.0   [22] GRANTHA LETTER OO..GRANTHA LETTER NA\n1132A..11330  ; Exclusion                      # 7.0    [7] GRANTHA LETTER PA..GRANTHA LETTER RA\n11332..11333  ; Exclusion                      # 7.0    [2] GRANTHA LETTER LA..GRANTHA LETTER LLA\n11335..11339  ; Exclusion                      # 7.0    [5] GRANTHA LETTER VA..GRANTHA LETTER HA\n1133D..11344  ; Exclusion                      # 7.0    [8] GRANTHA SIGN AVAGRAHA..GRANTHA VOWEL SIGN VOCALIC RR\n11347..11348  ; Exclusion                      # 7.0    [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI\n1134B..1134D  ; Exclusion                      # 7.0    [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA\n11350         ; Exclusion                      # 8.0        GRANTHA OM\n11357         ; Exclusion                      # 7.0        GRANTHA AU LENGTH MARK\n1135D..11363  ; Exclusion                      # 7.0    [7] GRANTHA SIGN PLUTA..GRANTHA VOWEL SIGN VOCALIC LL\n11366..1136C  ; Exclusion                      # 7.0    [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX\n11370..11374  ; Exclusion                      # 7.0    [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA\n11380..11389  ; Exclusion                      # 16.0  [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL\n1138B         ; Exclusion                      # 16.0       TULU-TIGALARI LETTER EE\n1138E         ; Exclusion                      # 16.0       TULU-TIGALARI LETTER AI\n11390..113B5  ; Exclusion                      # 16.0  [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA\n113B7..113C0  ; Exclusion                      # 16.0  [10] TULU-TIGALARI SIGN AVAGRAHA..TULU-TIGALARI VOWEL SIGN VOCALIC LL\n113C2         ; Exclusion                      # 16.0       TULU-TIGALARI VOWEL SIGN EE\n113C5         ; Exclusion                      # 16.0       TULU-TIGALARI VOWEL SIGN AI\n113C7..113CA  ; Exclusion                      # 16.0   [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA\n113CC..113D3  ; Exclusion                      # 16.0   [8] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN PLUTA\n113E1..113E2  ; Exclusion                      # 16.0   [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA\n11480..114C5  ; Exclusion                      # 7.0   [70] TIRHUTA ANJI..TIRHUTA GVANG\n114C7         ; Exclusion                      # 7.0        TIRHUTA OM\n114D0..114D9  ; Exclusion                      # 7.0   [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE\n11580..115B5  ; Exclusion                      # 7.0   [54] SIDDHAM LETTER A..SIDDHAM VOWEL SIGN VOCALIC RR\n115B8..115C0  ; Exclusion                      # 7.0    [9] SIDDHAM VOWEL SIGN E..SIDDHAM SIGN NUKTA\n115D8..115DD  ; Exclusion                      # 8.0    [6] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM VOWEL SIGN ALTERNATE UU\n11600..11640  ; Exclusion                      # 7.0   [65] MODI LETTER A..MODI SIGN ARDHACANDRA\n11644         ; Exclusion                      # 7.0        MODI SIGN HUVA\n11650..11659  ; Exclusion                      # 7.0   [10] MODI DIGIT ZERO..MODI DIGIT NINE\n11680..116B7  ; Exclusion                      # 6.1   [56] TAKRI LETTER A..TAKRI SIGN NUKTA\n116B8         ; Exclusion                      # 12.0       TAKRI LETTER ARCHAIC KHA\n116C0..116C9  ; Exclusion                      # 6.1   [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE\n11700..11719  ; Exclusion                      # 8.0   [26] AHOM LETTER KA..AHOM LETTER JHA\n1171A         ; Exclusion                      # 11.0       AHOM LETTER ALTERNATE BA\n1171D..1172B  ; Exclusion                      # 8.0   [15] AHOM CONSONANT SIGN MEDIAL LA..AHOM SIGN KILLER\n11730..11739  ; Exclusion                      # 8.0   [10] AHOM DIGIT ZERO..AHOM DIGIT NINE\n11740..11746  ; Exclusion                      # 14.0   [7] AHOM LETTER CA..AHOM LETTER LLA\n11800..1183A  ; Exclusion                      # 11.0  [59] DOGRA LETTER A..DOGRA SIGN NUKTA\n118A0..118E9  ; Exclusion                      # 7.0   [74] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI DIGIT NINE\n118FF         ; Exclusion                      # 7.0        WARANG CITI OM\n11900..11906  ; Exclusion                      # 13.0   [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E\n11909         ; Exclusion                      # 13.0       DIVES AKURU LETTER O\n1190C..11913  ; Exclusion                      # 13.0   [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA\n11915..11916  ; Exclusion                      # 13.0   [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA\n11918..11935  ; Exclusion                      # 13.0  [30] DIVES AKURU LETTER DDA..DIVES AKURU VOWEL SIGN E\n11937..11938  ; Exclusion                      # 13.0   [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O\n1193B..11943  ; Exclusion                      # 13.0   [9] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN NUKTA\n11950..11959  ; Exclusion                      # 13.0  [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE\n119A0..119A7  ; Exclusion                      # 12.0   [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR\n119AA..119D7  ; Exclusion                      # 12.0  [46] NANDINAGARI LETTER E..NANDINAGARI VOWEL SIGN VOCALIC RR\n119DA..119E1  ; Exclusion                      # 12.0   [8] NANDINAGARI VOWEL SIGN E..NANDINAGARI SIGN AVAGRAHA\n119E3..119E4  ; Exclusion                      # 12.0   [2] NANDINAGARI HEADSTROKE..NANDINAGARI VOWEL SIGN PRISHTHAMATRA E\n11A00..11A3E  ; Exclusion                      # 10.0  [63] ZANABAZAR SQUARE LETTER A..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA\n11A47         ; Exclusion                      # 10.0       ZANABAZAR SQUARE SUBJOINER\n11A50..11A83  ; Exclusion                      # 10.0  [52] SOYOMBO LETTER A..SOYOMBO LETTER KSSA\n11A84..11A85  ; Exclusion                      # 12.0   [2] SOYOMBO SIGN JIHVAMULIYA..SOYOMBO SIGN UPADHMANIYA\n11A86..11A99  ; Exclusion                      # 10.0  [20] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO SUBJOINER\n11A9D         ; Exclusion                      # 11.0       SOYOMBO MARK PLUTA\n11AC0..11AF8  ; Exclusion                      # 7.0   [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL\n11B60..11B67  ; Exclusion                      # 17.0   [8] SHARADA VOWEL SIGN OE..SHARADA VOWEL SIGN CANDRA O\n11BC0..11BE0  ; Exclusion                      # 16.0  [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO\n11BF0..11BF9  ; Exclusion                      # 16.0  [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE\n11C00..11C08  ; Exclusion                      # 9.0    [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L\n11C0A..11C36  ; Exclusion                      # 9.0   [45] BHAIKSUKI LETTER E..BHAIKSUKI VOWEL SIGN VOCALIC L\n11C38..11C40  ; Exclusion                      # 9.0    [9] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN AVAGRAHA\n11C50..11C59  ; Exclusion                      # 9.0   [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE\n11C72..11C8F  ; Exclusion                      # 9.0   [30] MARCHEN LETTER KA..MARCHEN LETTER A\n11C92..11CA7  ; Exclusion                      # 9.0   [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA\n11CA9..11CB6  ; Exclusion                      # 9.0   [14] MARCHEN SUBJOINED LETTER YA..MARCHEN SIGN CANDRABINDU\n11D00..11D06  ; Exclusion                      # 10.0   [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E\n11D08..11D09  ; Exclusion                      # 10.0   [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O\n11D0B..11D36  ; Exclusion                      # 10.0  [44] MASARAM GONDI LETTER AU..MASARAM GONDI VOWEL SIGN VOCALIC R\n11D3A         ; Exclusion                      # 10.0       MASARAM GONDI VOWEL SIGN E\n11D3C..11D3D  ; Exclusion                      # 10.0   [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O\n11D3F..11D47  ; Exclusion                      # 10.0   [9] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI RA-KARA\n11D50..11D59  ; Exclusion                      # 10.0  [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE\n11D60..11D65  ; Exclusion                      # 11.0   [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU\n11D67..11D68  ; Exclusion                      # 11.0   [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI\n11D6A..11D8E  ; Exclusion                      # 11.0  [37] GUNJALA GONDI LETTER OO..GUNJALA GONDI VOWEL SIGN UU\n11D90..11D91  ; Exclusion                      # 11.0   [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI\n11D93..11D98  ; Exclusion                      # 11.0   [6] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI OM\n11DA0..11DA9  ; Exclusion                      # 11.0  [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE\n11DB0..11DDB  ; Exclusion                      # 17.0  [44] TOLONG SIKI LETTER I..TOLONG SIKI UNGGA\n11DE0..11DE9  ; Exclusion                      # 17.0  [10] TOLONG SIKI DIGIT ZERO..TOLONG SIKI DIGIT NINE\n11EE0..11EF6  ; Exclusion                      # 11.0  [23] MAKASAR LETTER KA..MAKASAR VOWEL SIGN O\n11F00..11F10  ; Exclusion                      # 15.0  [17] KAWI SIGN CANDRABINDU..KAWI LETTER O\n11F12..11F3A  ; Exclusion                      # 15.0  [41] KAWI LETTER KA..KAWI VOWEL SIGN VOCALIC R\n11F3E..11F42  ; Exclusion                      # 15.0   [5] KAWI VOWEL SIGN E..KAWI CONJOINER\n11F50..11F59  ; Exclusion                      # 15.0  [10] KAWI DIGIT ZERO..KAWI DIGIT NINE\n11F5A         ; Exclusion                      # 16.0       KAWI SIGN NUKTA\n12000..1236E  ; Exclusion                      # 5.0  [879] CUNEIFORM SIGN A..CUNEIFORM SIGN ZUM\n1236F..12398  ; Exclusion                      # 7.0   [42] CUNEIFORM SIGN KAP ELAMITE..CUNEIFORM SIGN UM TIMES ME\n12399         ; Exclusion                      # 8.0        CUNEIFORM SIGN U U\n12400..12462  ; Exclusion                      # 5.0   [99] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER\n12463..1246E  ; Exclusion                      # 7.0   [12] CUNEIFORM NUMERIC SIGN ONE QUARTER GUR..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM\n12480..12543  ; Exclusion                      # 8.0  [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU\n12F90..12FF0  ; Exclusion                      # 14.0  [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114\n13000..1342E  ; Exclusion                      # 5.2 [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032\n1342F         ; Exclusion                      # 15.0       EGYPTIAN HIEROGLYPH V011D\n13440..13455  ; Exclusion                      # 15.0  [22] EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED\n13460..143FA  ; Exclusion                      # 16.0 [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA\n14400..14646  ; Exclusion                      # 8.0  [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530\n16100..16139  ; Exclusion                      # 16.0  [58] GURUNG KHEMA LETTER A..GURUNG KHEMA DIGIT NINE\n16A70..16ABE  ; Exclusion                      # 14.0  [79] TANGSA LETTER OZ..TANGSA LETTER ZA\n16AC0..16AC9  ; Exclusion                      # 14.0  [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE\n16AD0..16AED  ; Exclusion                      # 7.0   [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I\n16AF0..16AF4  ; Exclusion                      # 7.0    [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE\n16B00..16B36  ; Exclusion                      # 7.0   [55] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG MARK CIM TAUM\n16B40..16B43  ; Exclusion                      # 7.0    [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM\n16B50..16B59  ; Exclusion                      # 7.0   [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE\n16B63..16B77  ; Exclusion                      # 7.0   [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS\n16B7D..16B8F  ; Exclusion                      # 7.0   [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ\n16D40..16D6C  ; Exclusion                      # 16.0  [45] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN SAAT\n16D70..16D79  ; Exclusion                      # 16.0  [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE\n16E40..16E7F  ; Exclusion                      # 11.0  [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y\n16EA0..16EB8  ; Exclusion                      # 17.0  [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY\n16EBB..16ED3  ; Exclusion                      # 17.0  [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY\n16FE0         ; Exclusion                      # 9.0        TANGUT ITERATION MARK\n16FE1         ; Exclusion                      # 10.0       NUSHU ITERATION MARK\n16FE4         ; Exclusion                      # 13.0       KHITAN SMALL SCRIPT FILLER\n17000..187EC  ; Exclusion                      # 9.0 [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC\n187ED..187F1  ; Exclusion                      # 11.0   [5] TANGUT IDEOGRAPH-187ED..TANGUT IDEOGRAPH-187F1\n187F2..187F7  ; Exclusion                      # 12.0   [6] TANGUT IDEOGRAPH-187F2..TANGUT IDEOGRAPH-187F7\n187F8..187FF  ; Exclusion                      # 17.0   [8] TANGUT IDEOGRAPH-187F8..TANGUT IDEOGRAPH-187FF\n18800..18AF2  ; Exclusion                      # 9.0  [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755\n18AF3..18CD5  ; Exclusion                      # 13.0 [483] TANGUT COMPONENT-756..KHITAN SMALL SCRIPT CHARACTER-18CD5\n18CFF         ; Exclusion                      # 16.0       KHITAN SMALL SCRIPT CHARACTER-18CFF\n18D00..18D08  ; Exclusion                      # 13.0   [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08\n18D09..18D1E  ; Exclusion                      # 17.0  [22] TANGUT IDEOGRAPH-18D09..TANGUT IDEOGRAPH-18D1E\n18D80..18DF2  ; Exclusion                      # 17.0 [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883\n1B170..1B2FB  ; Exclusion                      # 10.0 [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB\n1BC00..1BC6A  ; Exclusion                      # 7.0  [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M\n1BC70..1BC7C  ; Exclusion                      # 7.0   [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK\n1BC80..1BC88  ; Exclusion                      # 7.0    [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL\n1BC90..1BC99  ; Exclusion                      # 7.0   [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW\n1BC9D..1BC9E  ; Exclusion                      # 7.0    [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK\n1DA00..1DA36  ; Exclusion                      # 8.0   [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN\n1DA3B..1DA6C  ; Exclusion                      # 8.0   [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT\n1DA75         ; Exclusion                      # 8.0        SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS\n1DA84         ; Exclusion                      # 8.0        SIGNWRITING LOCATION HEAD NECK\n1DA9B..1DA9F  ; Exclusion                      # 8.0    [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6\n1DAA1..1DAAF  ; Exclusion                      # 8.0   [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16\n1E000..1E006  ; Exclusion                      # 9.0    [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE\n1E008..1E018  ; Exclusion                      # 9.0   [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU\n1E01B..1E021  ; Exclusion                      # 9.0    [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI\n1E023..1E024  ; Exclusion                      # 9.0    [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS\n1E026..1E02A  ; Exclusion                      # 9.0    [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA\n1E290..1E2AE  ; Exclusion                      # 14.0  [31] TOTO LETTER PA..TOTO SIGN RISING TONE\n1E4D0..1E4F9  ; Exclusion                      # 15.0  [42] NAG MUNDARI LETTER O..NAG MUNDARI DIGIT NINE\n1E5D0..1E5FA  ; Exclusion                      # 16.0  [43] OL ONAL LETTER O..OL ONAL DIGIT NINE\n1E6C0..1E6DE  ; Exclusion                      # 17.0  [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO\n1E6E0..1E6F5  ; Exclusion                      # 17.0  [22] TAI YO LETTER AA..TAI YO SIGN OM\n1E6FE..1E6FF  ; Exclusion                      # 17.0   [2] TAI YO SYMBOL MUEANG..TAI YO XAM LAI\n1E800..1E8C4  ; Exclusion                      # 7.0  [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON\n1E8D0..1E8D6  ; Exclusion                      # 7.0    [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS\n\n# Total code points: 20862\n\n#\tIdentifier_Type:\tExclusion Not_XID\n\n0830..083E    ; Exclusion Not_XID              # 5.2   [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU\n1680          ; Exclusion Not_XID              # 3.0        OGHAM SPACE MARK\n169B..169C    ; Exclusion Not_XID              # 3.0    [2] OGHAM FEATHER MARK..OGHAM REVERSED FEATHER MARK\n16EB..16ED    ; Exclusion Not_XID              # 3.0    [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION\n1735..1736    ; Exclusion Not_XID              # 3.2    [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION\n1800..180A    ; Exclusion Not_XID              # 3.0   [11] MONGOLIAN BIRGA..MONGOLIAN NIRUGU\n1A1E..1A1F    ; Exclusion Not_XID              # 4.1    [2] BUGINESE PALLAWA..BUGINESE END OF SECTION\n2CE5..2CEA    ; Exclusion Not_XID              # 4.1    [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA\n2CF9..2CFF    ; Exclusion Not_XID              # 4.1    [7] COPTIC OLD NUBIAN FULL STOP..COPTIC MORPHOLOGICAL DIVIDER\n2E30          ; Exclusion Not_XID              # 5.1        RING POINT\n2E3C          ; Exclusion Not_XID              # 7.0        STENOGRAPHIC FULL STOP\nA874..A877    ; Exclusion Not_XID              # 5.0    [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD\nA95F          ; Exclusion Not_XID              # 5.1        REJANG SECTION MARK\n10100..10102  ; Exclusion Not_XID              # 4.0    [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK\n10107..10133  ; Exclusion Not_XID              # 4.0   [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND\n10137..1013F  ; Exclusion Not_XID              # 4.0    [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT\n10320..10323  ; Exclusion Not_XID              # 3.1    [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY\n1039F         ; Exclusion Not_XID              # 4.0        UGARITIC WORD DIVIDER\n103D0         ; Exclusion Not_XID              # 4.1        OLD PERSIAN WORD DIVIDER\n1056F         ; Exclusion Not_XID              # 7.0        CAUCASIAN ALBANIAN CITATION MARK\n10857..1085F  ; Exclusion Not_XID              # 5.2    [9] IMPERIAL ARAMAIC SECTION SIGN..IMPERIAL ARAMAIC NUMBER TEN THOUSAND\n10877..1087F  ; Exclusion Not_XID              # 7.0    [9] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE NUMBER TWENTY\n108A7..108AF  ; Exclusion Not_XID              # 7.0    [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED\n108FB..108FF  ; Exclusion Not_XID              # 8.0    [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED\n10916..10919  ; Exclusion Not_XID              # 5.0    [4] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER ONE HUNDRED\n1091A..1091B  ; Exclusion Not_XID              # 5.2    [2] PHOENICIAN NUMBER TWO..PHOENICIAN NUMBER THREE\n1091F         ; Exclusion Not_XID              # 5.0        PHOENICIAN WORD SEPARATOR\n1093F         ; Exclusion Not_XID              # 5.1        LYDIAN TRIANGULAR MARK\n109BC..109BD  ; Exclusion Not_XID              # 8.0    [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF\n109C0..109CF  ; Exclusion Not_XID              # 8.0   [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY\n109D2..109FF  ; Exclusion Not_XID              # 8.0   [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS\n10A40..10A47  ; Exclusion Not_XID              # 4.1    [8] KHAROSHTHI DIGIT ONE..KHAROSHTHI NUMBER ONE THOUSAND\n10A48         ; Exclusion Not_XID              # 11.0       KHAROSHTHI FRACTION ONE HALF\n10A50..10A58  ; Exclusion Not_XID              # 4.1    [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES\n10A7D..10A7F  ; Exclusion Not_XID              # 5.2    [3] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMERIC INDICATOR\n10A9D..10A9F  ; Exclusion Not_XID              # 7.0    [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY\n10AC8         ; Exclusion Not_XID              # 7.0        MANICHAEAN SIGN UD\n10AEB..10AF6  ; Exclusion Not_XID              # 7.0   [12] MANICHAEAN NUMBER ONE..MANICHAEAN PUNCTUATION LINE FILLER\n10B39..10B3F  ; Exclusion Not_XID              # 5.2    [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION\n10B58..10B5F  ; Exclusion Not_XID              # 5.2    [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND\n10B78..10B7F  ; Exclusion Not_XID              # 5.2    [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND\n10B99..10B9C  ; Exclusion Not_XID              # 7.0    [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT\n10BA9..10BAF  ; Exclusion Not_XID              # 7.0    [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED\n10CFA..10CFF  ; Exclusion Not_XID              # 8.0    [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND\n10D6E         ; Exclusion Not_XID              # 16.0       GARAY HYPHEN\n10D8E..10D8F  ; Exclusion Not_XID              # 16.0   [2] GARAY PLUS SIGN..GARAY MINUS SIGN\n10EAD         ; Exclusion Not_XID              # 13.0       YEZIDI HYPHENATION MARK\n10F1D..10F26  ; Exclusion Not_XID              # 11.0  [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF\n10F51..10F59  ; Exclusion Not_XID              # 11.0   [9] SOGDIAN NUMBER ONE..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT\n10F86..10F89  ; Exclusion Not_XID              # 14.0   [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS\n10FC5..10FCB  ; Exclusion Not_XID              # 13.0   [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED\n11047..1104D  ; Exclusion Not_XID              # 6.0    [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS\n11052..11065  ; Exclusion Not_XID              # 6.0   [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND\n110BB..110BC  ; Exclusion Not_XID              # 5.2    [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN\n110BD         ; Exclusion Not_XID              # 5.2        KAITHI NUMBER SIGN\n110BE..110C1  ; Exclusion Not_XID              # 5.2    [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA\n110CD         ; Exclusion Not_XID              # 11.0       KAITHI NUMBER SIGN ABOVE\n11174..11175  ; Exclusion Not_XID              # 7.0    [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK\n111C5..111C8  ; Exclusion Not_XID              # 6.1    [4] SHARADA DANDA..SHARADA SEPARATOR\n111CD         ; Exclusion Not_XID              # 7.0        SHARADA SUTRA MARK\n111DB         ; Exclusion Not_XID              # 8.0        SHARADA SIGN SIDDHAM\n111DD..111DF  ; Exclusion Not_XID              # 8.0    [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2\n11238..1123D  ; Exclusion Not_XID              # 7.0    [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN\n112A9         ; Exclusion Not_XID              # 8.0        MULTANI SECTION MARK\n113D4..113D5  ; Exclusion Not_XID              # 16.0   [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA\n113D7..113D8  ; Exclusion Not_XID              # 16.0   [2] TULU-TIGALARI SIGN OM PUSHPIKA..TULU-TIGALARI SIGN SHRII PUSHPIKA\n114C6         ; Exclusion Not_XID              # 7.0        TIRHUTA ABBREVIATION SIGN\n115C1..115C9  ; Exclusion Not_XID              # 7.0    [9] SIDDHAM SIGN SIDDHAM..SIDDHAM END OF TEXT MARK\n115CA..115D7  ; Exclusion Not_XID              # 8.0   [14] SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES\n11641..11643  ; Exclusion Not_XID              # 7.0    [3] MODI DANDA..MODI ABBREVIATION SIGN\n11660..1166C  ; Exclusion Not_XID              # 9.0   [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT\n116B9         ; Exclusion Not_XID              # 14.0       TAKRI ABBREVIATION SIGN\n1173A..1173F  ; Exclusion Not_XID              # 8.0    [6] AHOM NUMBER TEN..AHOM SYMBOL VI\n1183B         ; Exclusion Not_XID              # 11.0       DOGRA ABBREVIATION SIGN\n118EA..118F2  ; Exclusion Not_XID              # 7.0    [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY\n11944..11946  ; Exclusion Not_XID              # 13.0   [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK\n119E2         ; Exclusion Not_XID              # 12.0       NANDINAGARI SIGN SIDDHAM\n11A3F..11A46  ; Exclusion Not_XID              # 10.0   [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK\n11A9A..11A9C  ; Exclusion Not_XID              # 10.0   [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD\n11A9E..11AA2  ; Exclusion Not_XID              # 10.0   [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2\n11BE1         ; Exclusion Not_XID              # 16.0       SUNUWAR SIGN PVO\n11C41..11C45  ; Exclusion Not_XID              # 9.0    [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2\n11C5A..11C6C  ; Exclusion Not_XID              # 9.0   [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK\n11C70..11C71  ; Exclusion Not_XID              # 9.0    [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD\n11EF7..11EF8  ; Exclusion Not_XID              # 11.0   [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION\n11F43..11F4F  ; Exclusion Not_XID              # 15.0  [13] KAWI DANDA..KAWI PUNCTUATION CLOSING SPIRAL\n12470..12473  ; Exclusion Not_XID              # 5.0    [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON\n12474         ; Exclusion Not_XID              # 7.0        CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON\n12FF1..12FF2  ; Exclusion Not_XID              # 14.0   [2] CYPRO-MINOAN SIGN CM301..CYPRO-MINOAN SIGN CM302\n13430..13438  ; Exclusion Not_XID              # 12.0   [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT\n13439..1343F  ; Exclusion Not_XID              # 15.0   [7] EGYPTIAN HIEROGLYPH INSERT AT MIDDLE..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE\n16A6E..16A6F  ; Exclusion Not_XID              # 7.0    [2] MRO DANDA..MRO DOUBLE DANDA\n16AF5         ; Exclusion Not_XID              # 7.0        BASSA VAH FULL STOP\n16B37..16B3F  ; Exclusion Not_XID              # 7.0    [9] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN XYEEM FAIB\n16B44..16B45  ; Exclusion Not_XID              # 7.0    [2] PAHAWH HMONG SIGN XAUS..PAHAWH HMONG SIGN CIM TSOV ROG\n16B5B..16B61  ; Exclusion Not_XID              # 7.0    [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS\n16D6D..16D6F  ; Exclusion Not_XID              # 16.0   [3] KIRAT RAI SIGN YUPI..KIRAT RAI DOUBLE DANDA\n16E80..16E9A  ; Exclusion Not_XID              # 11.0  [27] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN EXCLAMATION OH\n1BC9C         ; Exclusion Not_XID              # 7.0        DUPLOYAN SIGN O WITH CROSS\n1BC9F         ; Exclusion Not_XID              # 7.0        DUPLOYAN PUNCTUATION CHINOOK FULL STOP\n1D800..1D9FF  ; Exclusion Not_XID              # 8.0  [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD\n1DA37..1DA3A  ; Exclusion Not_XID              # 8.0    [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE\n1DA6D..1DA74  ; Exclusion Not_XID              # 8.0    [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING\n1DA76..1DA83  ; Exclusion Not_XID              # 8.0   [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH\n1DA85..1DA8B  ; Exclusion Not_XID              # 8.0    [7] SIGNWRITING LOCATION TORSO..SIGNWRITING PARENTHESIS\n1E5FF         ; Exclusion Not_XID              # 16.0       OL ONAL ABBREVIATION SIGN\n1E8C7..1E8CF  ; Exclusion Not_XID              # 7.0    [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE\n\n# Total code points: 1142\n\n#\tIdentifier_Type:\tObsolete\n\n0138          ; Obsolete                       # 1.1        LATIN SMALL LETTER KRA\n01B9          ; Obsolete                       # 1.1        LATIN SMALL LETTER EZH REVERSED\n01BF          ; Obsolete                       # 1.1        LATIN LETTER WYNN\n01F6..01F7    ; Obsolete                       # 3.0    [2] LATIN CAPITAL LETTER HWAIR..LATIN CAPITAL LETTER WYNN\n021C..021D    ; Obsolete                       # 3.0    [2] LATIN CAPITAL LETTER YOGH..LATIN SMALL LETTER YOGH\n0345          ; Obsolete                       # 1.1        COMBINING GREEK YPOGEGRAMMENI\n0363..036F    ; Obsolete                       # 3.2   [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X\n0370..0373    ; Obsolete                       # 5.1    [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI\n0376..0377    ; Obsolete                       # 5.1    [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA\n037B..037D    ; Obsolete                       # 5.0    [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL\n037F          ; Obsolete                       # 7.0        GREEK CAPITAL LETTER YOT\n03D8..03D9    ; Obsolete                       # 3.2    [2] GREEK LETTER ARCHAIC KOPPA..GREEK SMALL LETTER ARCHAIC KOPPA\n03DA          ; Obsolete                       # 1.1        GREEK LETTER STIGMA\n03DB          ; Obsolete                       # 3.0        GREEK SMALL LETTER STIGMA\n03DC          ; Obsolete                       # 1.1        GREEK LETTER DIGAMMA\n03DD          ; Obsolete                       # 3.0        GREEK SMALL LETTER DIGAMMA\n03DE          ; Obsolete                       # 1.1        GREEK LETTER KOPPA\n03DF          ; Obsolete                       # 3.0        GREEK SMALL LETTER KOPPA\n03E0          ; Obsolete                       # 1.1        GREEK LETTER SAMPI\n03E1          ; Obsolete                       # 3.0        GREEK SMALL LETTER SAMPI\n03F7..03F8    ; Obsolete                       # 4.0    [2] GREEK CAPITAL LETTER SHO..GREEK SMALL LETTER SHO\n03FA..03FB    ; Obsolete                       # 4.0    [2] GREEK CAPITAL LETTER SAN..GREEK SMALL LETTER SAN\n03FD..03FF    ; Obsolete                       # 4.1    [3] GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL\n0460..0481    ; Obsolete                       # 1.1   [34] CYRILLIC CAPITAL LETTER OMEGA..CYRILLIC SMALL LETTER KOPPA\n0483          ; Obsolete                       # 1.1        COMBINING CYRILLIC TITLO\n049C..049D    ; Obsolete                       # 1.1    [2] CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE..CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE\n04A6..04A7    ; Obsolete                       # 1.1    [2] CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK..CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK\n04B8..04B9    ; Obsolete                       # 1.1    [2] CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE..CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE\n0500..050F    ; Obsolete                       # 3.2   [16] CYRILLIC CAPITAL LETTER KOMI DE..CYRILLIC SMALL LETTER KOMI TJE\n0514..0523    ; Obsolete                       # 5.1   [16] CYRILLIC CAPITAL LETTER LHA..CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK\n0526..0527    ; Obsolete                       # 6.0    [2] CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER..CYRILLIC SMALL LETTER SHHA WITH DESCENDER\n0528..052F    ; Obsolete                       # 7.0    [8] CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK..CYRILLIC SMALL LETTER EL WITH DESCENDER\n063B..063C    ; Obsolete                       # 5.1    [2] ARABIC LETTER KEHEH WITH TWO DOTS ABOVE..ARABIC LETTER KEHEH WITH THREE DOTS BELOW\n063E..063F    ; Obsolete                       # 5.1    [2] ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE\n0640          ; Obsolete                       # 1.1        ARABIC TATWEEL\n066E..066F    ; Obsolete                       # 3.2    [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF\n0690          ; Obsolete                       # 1.1        ARABIC LETTER DAL WITH FOUR DOTS ABOVE\n06AC          ; Obsolete                       # 1.1        ARABIC LETTER KAF WITH DOT ABOVE\n077E..077F    ; Obsolete                       # 5.1    [2] ARABIC LETTER SEEN WITH INVERTED V..ARABIC LETTER KAF WITH TWO DOTS ABOVE\n088E          ; Obsolete                       # 14.0       ARABIC VERTICAL TAIL\n08AD..08B1    ; Obsolete                       # 7.0    [5] ARABIC LETTER LOW ALEF..ARABIC LETTER STRAIGHT WAW\n08B5          ; Obsolete                       # 14.0       ARABIC LETTER QAF WITH DOT BELOW AND NO DOTS ABOVE\n090C          ; Obsolete                       # 1.1        DEVANAGARI LETTER VOCALIC L\n093D          ; Obsolete                       # 1.1        DEVANAGARI SIGN AVAGRAHA\n094E          ; Obsolete                       # 5.2        DEVANAGARI VOWEL SIGN PRISHTHAMATRA E\n0951..0952    ; Obsolete                       # 1.1    [2] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI STRESS SIGN ANUDATTA\n0960..0963    ; Obsolete                       # 1.1    [4] DEVANAGARI LETTER VOCALIC RR..DEVANAGARI VOWEL SIGN VOCALIC LL\n0971          ; Obsolete                       # 5.1        DEVANAGARI SIGN HIGH SPACING DOT\n0978          ; Obsolete                       # 7.0        DEVANAGARI LETTER MARWARI DDA\n0980          ; Obsolete                       # 7.0        BENGALI ANJI\n09BD          ; Obsolete                       # 4.0        BENGALI SIGN AVAGRAHA\n09E0..09E3    ; Obsolete                       # 1.1    [4] BENGALI LETTER VOCALIC RR..BENGALI VOWEL SIGN VOCALIC LL\n09FC          ; Obsolete                       # 10.0       BENGALI LETTER VEDIC ANUSVARA\n0ABD          ; Obsolete                       # 1.1        GUJARATI SIGN AVAGRAHA\n0AE0          ; Obsolete                       # 1.1        GUJARATI LETTER VOCALIC RR\n0AE1..0AE3    ; Obsolete                       # 4.0    [3] GUJARATI LETTER VOCALIC LL..GUJARATI VOWEL SIGN VOCALIC LL\n0B3D          ; Obsolete                       # 1.1        ORIYA SIGN AVAGRAHA\n0B60..0B61    ; Obsolete                       # 1.1    [2] ORIYA LETTER VOCALIC RR..ORIYA LETTER VOCALIC LL\n0C00          ; Obsolete                       # 7.0        TELUGU SIGN COMBINING CANDRABINDU ABOVE\n0C34          ; Obsolete                       # 7.0        TELUGU LETTER LLLA\n0C3D          ; Obsolete                       # 5.1        TELUGU SIGN AVAGRAHA\n0C58..0C59    ; Obsolete                       # 5.1    [2] TELUGU LETTER TSA..TELUGU LETTER DZA\n0C5C          ; Obsolete                       # 17.0       TELUGU ARCHAIC SHRII\n0C60..0C61    ; Obsolete                       # 1.1    [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL\n0C81          ; Obsolete                       # 7.0        KANNADA SIGN CANDRABINDU\n0C8C          ; Obsolete                       # 1.1        KANNADA LETTER VOCALIC L\n0CB1          ; Obsolete                       # 1.1        KANNADA LETTER RRA\n0CBD          ; Obsolete                       # 4.0        KANNADA SIGN AVAGRAHA\n0CDC          ; Obsolete                       # 17.0       KANNADA ARCHAIC SHRII\n0CDE          ; Obsolete                       # 1.1        KANNADA LETTER FA\n0CE0..0CE1    ; Obsolete                       # 1.1    [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL\n0CE2..0CE3    ; Obsolete                       # 5.0    [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL\n0CF1..0CF2    ; Obsolete                       # 5.0    [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA\n0D01          ; Obsolete                       # 7.0        MALAYALAM SIGN CANDRABINDU\n0D3A          ; Obsolete                       # 6.0        MALAYALAM LETTER TTTA\n0D3B..0D3C    ; Obsolete                       # 10.0   [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA\n0D3D          ; Obsolete                       # 5.1        MALAYALAM SIGN AVAGRAHA\n0D4C          ; Obsolete                       # 1.1        MALAYALAM VOWEL SIGN AU\n0D4E          ; Obsolete                       # 6.0        MALAYALAM LETTER DOT REPH\n0D5F          ; Obsolete                       # 8.0        MALAYALAM LETTER ARCHAIC II\n0D60..0D61    ; Obsolete                       # 1.1    [2] MALAYALAM LETTER VOCALIC RR..MALAYALAM LETTER VOCALIC LL\n0D9E          ; Obsolete                       # 3.0        SINHALA LETTER KANTAJA NAASIKYAYA\n0F86..0F8B    ; Obsolete                       # 2.0    [6] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN GRU MED RGYINGS\n0F8C..0F8F    ; Obsolete                       # 6.0    [4] TIBETAN SIGN INVERTED MCHU CAN..TIBETAN SUBJOINED SIGN INVERTED MCHU CAN\n10A0..10C5    ; Obsolete                       # 1.1   [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE\n10F1..10F6    ; Obsolete                       # 1.1    [6] GEORGIAN LETTER HE..GEORGIAN LETTER FI\n1100..1159    ; Obsolete                       # 1.1   [90] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG YEORINHIEUH\n115A..115E    ; Obsolete                       # 5.2    [5] HANGUL CHOSEONG KIYEOK-TIKEUT..HANGUL CHOSEONG TIKEUT-RIEUL\n1161..11A2    ; Obsolete                       # 1.1   [66] HANGUL JUNGSEONG A..HANGUL JUNGSEONG SSANGARAEA\n11A3..11A7    ; Obsolete                       # 5.2    [5] HANGUL JUNGSEONG A-EU..HANGUL JUNGSEONG O-YAE\n11A8..11F9    ; Obsolete                       # 1.1   [82] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG YEORINHIEUH\n11FA..11FF    ; Obsolete                       # 5.2    [6] HANGUL JONGSEONG KIYEOK-NIEUN..HANGUL JONGSEONG SSANGNIEUN\n1369..1371    ; Obsolete                       # 3.0    [9] ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE\n17A8          ; Obsolete                       # 3.0        KHMER INDEPENDENT VOWEL QUK\n17D3          ; Obsolete                       # 3.0        KHMER SIGN BATHAMASAT\n17DC          ; Obsolete                       # 3.0        KHMER SIGN AVAKRAHASANYA\n1AB0..1ABD    ; Obsolete                       # 7.0   [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW\n1C80..1C88    ; Obsolete                       # 9.0    [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK\n1CD0..1CD2    ; Obsolete                       # 5.2    [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA\n1CD4..1CF2    ; Obsolete                       # 5.2   [31] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC SIGN ARDHAVISARGA\n1CF3..1CF6    ; Obsolete                       # 6.1    [4] VEDIC SIGN ROTATED ARDHAVISARGA..VEDIC SIGN UPADHMANIYA\n1CF7          ; Obsolete                       # 10.0       VEDIC SIGN ATIKRAMA\n1CF8..1CF9    ; Obsolete                       # 7.0    [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE\n1F00..1F15    ; Obsolete                       # 1.1   [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA\n1F18..1F1D    ; Obsolete                       # 1.1    [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA\n1F20..1F45    ; Obsolete                       # 1.1   [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA\n1F48..1F4D    ; Obsolete                       # 1.1    [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA\n1F50..1F57    ; Obsolete                       # 1.1    [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI\n1F59          ; Obsolete                       # 1.1        GREEK CAPITAL LETTER UPSILON WITH DASIA\n1F5B          ; Obsolete                       # 1.1        GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA\n1F5D          ; Obsolete                       # 1.1        GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA\n1F5F..1F70    ; Obsolete                       # 1.1   [18] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER ALPHA WITH VARIA\n1F72          ; Obsolete                       # 1.1        GREEK SMALL LETTER EPSILON WITH VARIA\n1F74          ; Obsolete                       # 1.1        GREEK SMALL LETTER ETA WITH VARIA\n1F76          ; Obsolete                       # 1.1        GREEK SMALL LETTER IOTA WITH VARIA\n1F78          ; Obsolete                       # 1.1        GREEK SMALL LETTER OMICRON WITH VARIA\n1F7A          ; Obsolete                       # 1.1        GREEK SMALL LETTER UPSILON WITH VARIA\n1F7C          ; Obsolete                       # 1.1        GREEK SMALL LETTER OMEGA WITH VARIA\n1F80..1F9F    ; Obsolete                       # 1.1   [32] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n1FB6..1FBA    ; Obsolete                       # 1.1    [5] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH VARIA\n1FBC          ; Obsolete                       # 1.1        GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI\n1FC2..1FC4    ; Obsolete                       # 1.1    [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI\n1FC6..1FC8    ; Obsolete                       # 1.1    [3] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER EPSILON WITH VARIA\n1FCA          ; Obsolete                       # 1.1        GREEK CAPITAL LETTER ETA WITH VARIA\n1FCC          ; Obsolete                       # 1.1        GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI\n1FD0..1FD2    ; Obsolete                       # 1.1    [3] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA\n1FD6..1FDA    ; Obsolete                       # 1.1    [5] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH VARIA\n1FE0..1FE2    ; Obsolete                       # 1.1    [3] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA\n1FE4..1FEA    ; Obsolete                       # 1.1    [7] GREEK SMALL LETTER RHO WITH PSILI..GREEK CAPITAL LETTER UPSILON WITH VARIA\n1FF2..1FF4    ; Obsolete                       # 1.1    [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI\n1FF6..1FF8    ; Obsolete                       # 1.1    [3] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMICRON WITH VARIA\n1FFA          ; Obsolete                       # 1.1        GREEK CAPITAL LETTER OMEGA WITH VARIA\n1FFC          ; Obsolete                       # 1.1        GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI\n2132          ; Obsolete                       # 1.1        TURNED CAPITAL F\n214E          ; Obsolete                       # 5.0        TURNED SMALL F\n2184          ; Obsolete                       # 5.0        LATIN SMALL LETTER REVERSED C\n2185..2188    ; Obsolete                       # 5.1    [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND\n2C6D..2C6F    ; Obsolete                       # 5.1    [3] LATIN CAPITAL LETTER ALPHA..LATIN CAPITAL LETTER TURNED A\n2C70          ; Obsolete                       # 5.2        LATIN CAPITAL LETTER TURNED ALPHA\n2C71..2C73    ; Obsolete                       # 5.1    [3] LATIN SMALL LETTER V WITH RIGHT HOOK..LATIN SMALL LETTER W WITH HOOK\n2C74..2C76    ; Obsolete                       # 5.0    [3] LATIN SMALL LETTER V WITH CURL..LATIN SMALL LETTER HALF H\n2C7E..2C7F    ; Obsolete                       # 5.2    [2] LATIN CAPITAL LETTER S WITH SWASH TAIL..LATIN CAPITAL LETTER Z WITH SWASH TAIL\n2D00..2D25    ; Obsolete                       # 4.1   [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE\n2DE0..2DFF    ; Obsolete                       # 5.1   [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS\n31F0..31FF    ; Obsolete                       # 3.2   [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO\nA640..A65F    ; Obsolete                       # 5.1   [32] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER YN\nA660..A661    ; Obsolete                       # 6.0    [2] CYRILLIC CAPITAL LETTER REVERSED TSE..CYRILLIC SMALL LETTER REVERSED TSE\nA662..A66E    ; Obsolete                       # 5.1   [13] CYRILLIC CAPITAL LETTER SOFT DE..CYRILLIC LETTER MULTIOCULAR O\nA674..A67B    ; Obsolete                       # 6.1    [8] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA\nA67F..A697    ; Obsolete                       # 5.1   [25] CYRILLIC PAYEROK..CYRILLIC SMALL LETTER SHWE\nA698..A69B    ; Obsolete                       # 7.0    [4] CYRILLIC CAPITAL LETTER DOUBLE O..CYRILLIC SMALL LETTER CROSSED O\nA69F          ; Obsolete                       # 6.1        COMBINING CYRILLIC LETTER IOTIFIED E\nA730..A76F    ; Obsolete                       # 5.1   [64] LATIN LETTER SMALL CAPITAL F..LATIN SMALL LETTER CON\nA771..A787    ; Obsolete                       # 5.1   [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T\nA790..A791    ; Obsolete                       # 6.0    [2] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER N WITH DESCENDER\nA794..A79F    ; Obsolete                       # 7.0   [12] LATIN SMALL LETTER C WITH PALATAL HOOK..LATIN SMALL LETTER VOLAPUK UE\nA7A0..A7A9    ; Obsolete                       # 6.0   [10] LATIN CAPITAL LETTER G WITH OBLIQUE STROKE..LATIN SMALL LETTER S WITH OBLIQUE STROKE\nA7AB..A7AD    ; Obsolete                       # 7.0    [3] LATIN CAPITAL LETTER REVERSED OPEN E..LATIN CAPITAL LETTER L WITH BELT\nA7B0..A7B1    ; Obsolete                       # 7.0    [2] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER TURNED T\nA7C0..A7C1    ; Obsolete                       # 14.0   [2] LATIN CAPITAL LETTER OLD POLISH O..LATIN SMALL LETTER OLD POLISH O\nA7C4          ; Obsolete                       # 12.0       LATIN CAPITAL LETTER C WITH PALATAL HOOK\nA7C7..A7CA    ; Obsolete                       # 13.0   [4] LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY\nA7D0..A7D1    ; Obsolete                       # 14.0   [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G\nA7D2          ; Obsolete                       # 17.0       LATIN CAPITAL LETTER DOUBLE THORN\nA7D3          ; Obsolete                       # 14.0       LATIN SMALL LETTER DOUBLE THORN\nA7D4          ; Obsolete                       # 17.0       LATIN CAPITAL LETTER DOUBLE WYNN\nA7D5..A7D9    ; Obsolete                       # 14.0   [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S\nA7F5..A7F6    ; Obsolete                       # 13.0   [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H\nA7F7          ; Obsolete                       # 7.0        LATIN EPIGRAPHIC LETTER SIDEWAYS I\nA7FB..A7FF    ; Obsolete                       # 5.1    [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M\nA8E0..A8F7    ; Obsolete                       # 5.2   [24] COMBINING DEVANAGARI DIGIT ZERO..DEVANAGARI SIGN CANDRABINDU AVAGRAHA\nA8FB          ; Obsolete                       # 5.2        DEVANAGARI HEADSTROKE\nA8FE..A8FF    ; Obsolete                       # 11.0   [2] DEVANAGARI LETTER AY..DEVANAGARI VOWEL SIGN AY\nA960..A97C    ; Obsolete                       # 5.2   [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH\nA9E0..A9E6    ; Obsolete                       # 7.0    [7] MYANMAR LETTER SHAN GHA..MYANMAR MODIFIER LETTER SHAN REDUPLICATION\nAB30..AB5A    ; Obsolete                       # 7.0   [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG\nAB64..AB65    ; Obsolete                       # 7.0    [2] LATIN SMALL LETTER INVERTED ALPHA..GREEK LETTER SMALL CAPITAL OMEGA\nD7B0..D7C6    ; Obsolete                       # 5.2   [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E\nD7CB..D7FB    ; Obsolete                       # 5.2   [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH\n10140..10174  ; Obsolete                       # 4.1   [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS\n101FD         ; Obsolete                       # 5.1        PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE\n102E0         ; Obsolete                       # 7.0        COPTIC EPACT THOUSANDS MARK\n16FE3         ; Obsolete                       # 12.0       OLD CHINESE ITERATION MARK\n16FF0..16FF1  ; Obsolete                       # 13.0   [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY\n1B000..1B001  ; Obsolete                       # 6.0    [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE\n1B002..1B11E  ; Obsolete                       # 10.0 [285] HENTAIGANA LETTER A-1..HENTAIGANA LETTER N-MU-MO-2\n1B11F..1B122  ; Obsolete                       # 14.0   [4] HIRAGANA LETTER ARCHAIC WU..KATAKANA LETTER ARCHAIC WU\n1B132         ; Obsolete                       # 15.0       HIRAGANA LETTER SMALL KO\n1B150..1B152  ; Obsolete                       # 12.0   [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO\n1B155         ; Obsolete                       # 15.0       KATAKANA LETTER SMALL KO\n1B164..1B167  ; Obsolete                       # 12.0   [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N\n1E08F         ; Obsolete                       # 15.0       COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I\n\n# Total code points: 1639\n\n#\tIdentifier_Type:\tObsolete Not_XID\n\n0482          ; Obsolete Not_XID               # 1.1        CYRILLIC THOUSANDS SIGN\n0488..0489    ; Obsolete Not_XID               # 3.0    [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN\n05C6          ; Obsolete Not_XID               # 4.1        HEBREW PUNCTUATION NUN HAFUKHA\n17D8          ; Obsolete Not_XID               # 3.0        KHMER SIGN BEYYAL\n1CD3          ; Obsolete Not_XID               # 5.2        VEDIC SIGN NIHSHVASA\n2056          ; Obsolete Not_XID               # 4.1        THREE DOT PUNCTUATION\n2058..205E    ; Obsolete Not_XID               # 4.1    [7] FOUR DOT PUNCTUATION..VERTICAL FOUR DOTS\n2127          ; Obsolete Not_XID               # 1.1        INVERTED OHM SIGN\n214F          ; Obsolete Not_XID               # 5.1        SYMBOL FOR SAMARITAN SOURCE\n2E0E..2E16    ; Obsolete Not_XID               # 4.1    [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE\n2E2A..2E2F    ; Obsolete Not_XID               # 5.1    [6] TWO DOTS OVER ONE DOT PUNCTUATION..VERTICAL TILDE\n2E31          ; Obsolete Not_XID               # 5.2        WORD SEPARATOR MIDDLE DOT\n2E32          ; Obsolete Not_XID               # 6.1        TURNED COMMA\n2E35          ; Obsolete Not_XID               # 6.1        TURNED SEMICOLON\n2E39          ; Obsolete Not_XID               # 6.1        TOP HALF SECTION SIGN\n301E          ; Obsolete Not_XID               # 1.1        DOUBLE PRIME QUOTATION MARK\nA670..A673    ; Obsolete Not_XID               # 5.1    [4] COMBINING CYRILLIC TEN MILLIONS SIGN..SLAVONIC ASTERISK\nA700..A707    ; Obsolete Not_XID               # 4.1    [8] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER CHINESE TONE YANG RU\nA8F8..A8FA    ; Obsolete Not_XID               # 5.2    [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET\n101D0..101FC  ; Obsolete Not_XID               # 5.1   [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND\n102E1..102FB  ; Obsolete Not_XID               # 7.0   [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED\n1D200..1D241  ; Obsolete Not_XID               # 4.1   [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54\n1D245         ; Obsolete Not_XID               # 4.1        GREEK MUSICAL LEIMMA\n\n# Total code points: 190\n\n#\tIdentifier_Type:\tNot_XID\n\n0009..000D    ; Not_XID                        # 1.1    [5] <control-0009>..<control-000D>\n0020..0026    ; Not_XID                        # 1.1    [7] SPACE..AMPERSAND\n0028..002C    ; Not_XID                        # 1.1    [5] LEFT PARENTHESIS..COMMA\n002F          ; Not_XID                        # 1.1        SOLIDUS\n003B..0040    ; Not_XID                        # 1.1    [6] SEMICOLON..COMMERCIAL AT\n005B..005E    ; Not_XID                        # 1.1    [4] LEFT SQUARE BRACKET..CIRCUMFLEX ACCENT\n0060          ; Not_XID                        # 1.1        GRAVE ACCENT\n007B..007E    ; Not_XID                        # 1.1    [4] LEFT CURLY BRACKET..TILDE\n0085          ; Not_XID                        # 1.1        <control-0085>\n00A1..00A7    ; Not_XID                        # 1.1    [7] INVERTED EXCLAMATION MARK..SECTION SIGN\n00A9          ; Not_XID                        # 1.1        COPYRIGHT SIGN\n00AB..00AC    ; Not_XID                        # 1.1    [2] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK..NOT SIGN\n00AE          ; Not_XID                        # 1.1        REGISTERED SIGN\n00B0..00B1    ; Not_XID                        # 1.1    [2] DEGREE SIGN..PLUS-MINUS SIGN\n00B6          ; Not_XID                        # 1.1        PILCROW SIGN\n00BB          ; Not_XID                        # 1.1        RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK\n00BF          ; Not_XID                        # 1.1        INVERTED QUESTION MARK\n00D7          ; Not_XID                        # 1.1        MULTIPLICATION SIGN\n00F7          ; Not_XID                        # 1.1        DIVISION SIGN\n02C2..02C5    ; Not_XID                        # 1.1    [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD\n02D2..02D7    ; Not_XID                        # 1.1    [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN\n02DE          ; Not_XID                        # 1.1        MODIFIER LETTER RHOTIC HOOK\n02DF          ; Not_XID                        # 3.0        MODIFIER LETTER CROSS ACCENT\n02E5..02E9    ; Not_XID                        # 1.1    [5] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER EXTRA-LOW TONE BAR\n02ED          ; Not_XID                        # 3.0        MODIFIER LETTER UNASPIRATED\n02EF..02FF    ; Not_XID                        # 4.0   [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW\n03F6          ; Not_XID                        # 3.2        GREEK REVERSED LUNATE EPSILON SYMBOL\n055A..055F    ; Not_XID                        # 1.1    [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK\n0589          ; Not_XID                        # 1.1        ARMENIAN FULL STOP\n058D..058E    ; Not_XID                        # 7.0    [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN\n058F          ; Not_XID                        # 6.1        ARMENIAN DRAM SIGN\n05BE          ; Not_XID                        # 1.1        HEBREW PUNCTUATION MAQAF\n05C0          ; Not_XID                        # 1.1        HEBREW PUNCTUATION PASEQ\n05C3          ; Not_XID                        # 1.1        HEBREW PUNCTUATION SOF PASUQ\n0600..0603    ; Not_XID                        # 4.0    [4] ARABIC NUMBER SIGN..ARABIC SIGN SAFHA\n0604          ; Not_XID                        # 6.1        ARABIC SIGN SAMVAT\n0605          ; Not_XID                        # 7.0        ARABIC NUMBER MARK ABOVE\n0606..060A    ; Not_XID                        # 5.1    [5] ARABIC-INDIC CUBE ROOT..ARABIC-INDIC PER TEN THOUSAND SIGN\n060B          ; Not_XID                        # 4.1        AFGHANI SIGN\n060C          ; Not_XID                        # 1.1        ARABIC COMMA\n060D..060F    ; Not_XID                        # 4.0    [3] ARABIC DATE SEPARATOR..ARABIC SIGN MISRA\n061B          ; Not_XID                        # 1.1        ARABIC SEMICOLON\n061D          ; Not_XID                        # 14.0       ARABIC END OF TEXT MARK\n061E          ; Not_XID                        # 4.1        ARABIC TRIPLE DOT PUNCTUATION MARK\n061F          ; Not_XID                        # 1.1        ARABIC QUESTION MARK\n066A..066D    ; Not_XID                        # 1.1    [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR\n06D4          ; Not_XID                        # 1.1        ARABIC FULL STOP\n06DD          ; Not_XID                        # 1.1        ARABIC END OF AYAH\n06DE          ; Not_XID                        # 1.1        ARABIC START OF RUB EL HIZB\n06E9          ; Not_XID                        # 1.1        ARABIC PLACE OF SAJDAH\n0890..0891    ; Not_XID                        # 14.0   [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE\n08E2          ; Not_XID                        # 9.0        ARABIC DISPUTED END OF AYAH\n0964..0965    ; Not_XID                        # 1.1    [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA\n0970          ; Not_XID                        # 1.1        DEVANAGARI ABBREVIATION SIGN\n09F2..09FA    ; Not_XID                        # 1.1    [9] BENGALI RUPEE MARK..BENGALI ISSHAR\n09FB          ; Not_XID                        # 5.2        BENGALI GANDA MARK\n09FD          ; Not_XID                        # 10.0       BENGALI ABBREVIATION SIGN\n0A76          ; Not_XID                        # 11.0       GURMUKHI ABBREVIATION SIGN\n0AF0          ; Not_XID                        # 6.1        GUJARATI ABBREVIATION SIGN\n0AF1          ; Not_XID                        # 4.0        GUJARATI RUPEE SIGN\n0B70          ; Not_XID                        # 1.1        ORIYA ISSHAR\n0B72..0B77    ; Not_XID                        # 6.0    [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS\n0BF0..0BF2    ; Not_XID                        # 1.1    [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND\n0BF3..0BFA    ; Not_XID                        # 4.0    [8] TAMIL DAY SIGN..TAMIL NUMBER SIGN\n0C77          ; Not_XID                        # 12.0       TELUGU SIGN SIDDHAM\n0C78..0C7F    ; Not_XID                        # 5.1    [8] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU SIGN TUUMU\n0C84          ; Not_XID                        # 11.0       KANNADA SIGN SIDDHAM\n0D4F          ; Not_XID                        # 9.0        MALAYALAM SIGN PARA\n0D58..0D5E    ; Not_XID                        # 9.0    [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH\n0D70..0D75    ; Not_XID                        # 5.1    [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS\n0D76..0D78    ; Not_XID                        # 9.0    [3] MALAYALAM FRACTION ONE SIXTEENTH..MALAYALAM FRACTION THREE SIXTEENTHS\n0D79          ; Not_XID                        # 5.1        MALAYALAM DATE MARK\n0DF4          ; Not_XID                        # 3.0        SINHALA PUNCTUATION KUNDDALIYA\n0E3F          ; Not_XID                        # 1.1        THAI CURRENCY SYMBOL BAHT\n0E4F          ; Not_XID                        # 1.1        THAI CHARACTER FONGMAN\n0E5A..0E5B    ; Not_XID                        # 1.1    [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT\n0F01..0F0A    ; Not_XID                        # 2.0   [10] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK BKA- SHOG YIG MGO\n0F0D..0F17    ; Not_XID                        # 2.0   [11] TIBETAN MARK SHAD..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS\n0F1A..0F1F    ; Not_XID                        # 2.0    [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG\n0F2A..0F34    ; Not_XID                        # 2.0   [11] TIBETAN DIGIT HALF ONE..TIBETAN MARK BSDUS RTAGS\n0F36          ; Not_XID                        # 2.0        TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN\n0F38          ; Not_XID                        # 2.0        TIBETAN MARK CHE MGO\n0F3A..0F3D    ; Not_XID                        # 2.0    [4] TIBETAN MARK GUG RTAGS GYON..TIBETAN MARK ANG KHANG GYAS\n0F85          ; Not_XID                        # 2.0        TIBETAN MARK PALUTA\n0FBE..0FC5    ; Not_XID                        # 3.0    [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE\n0FC7..0FCC    ; Not_XID                        # 3.0    [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL\n0FCE          ; Not_XID                        # 5.1        TIBETAN SIGN RDEL NAG RDEL DKAR\n0FCF          ; Not_XID                        # 3.0        TIBETAN SIGN RDEL NAG GSUM\n0FD0..0FD1    ; Not_XID                        # 4.1    [2] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK MNYAM YIG GI MGO RGYAN\n0FD2..0FD4    ; Not_XID                        # 5.1    [3] TIBETAN MARK NYIS TSHEG..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA\n0FD5..0FD8    ; Not_XID                        # 5.2    [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS\n0FD9..0FDA    ; Not_XID                        # 6.0    [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS\n104A..104F    ; Not_XID                        # 3.0    [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE\n109E..109F    ; Not_XID                        # 5.1    [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION\n10FB          ; Not_XID                        # 1.1        GEORGIAN PARAGRAPH SEPARATOR\n1360          ; Not_XID                        # 4.1        ETHIOPIC SECTION MARK\n1361..1368    ; Not_XID                        # 3.0    [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR\n1372..137C    ; Not_XID                        # 3.0   [11] ETHIOPIC NUMBER TEN..ETHIOPIC NUMBER TEN THOUSAND\n1390..1399    ; Not_XID                        # 4.1   [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT\n17D4..17D6    ; Not_XID                        # 3.0    [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH\n17D9..17DB    ; Not_XID                        # 3.0    [3] KHMER SIGN PHNAEK MUAN..KHMER CURRENCY SYMBOL RIEL\n17F0..17F9    ; Not_XID                        # 4.0   [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON\n19E0..19FF    ; Not_XID                        # 4.0   [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC\n1ABE          ; Not_XID                        # 7.0        COMBINING PARENTHESES OVERLAY\n2012..2016    ; Not_XID                        # 1.1    [5] FIGURE DASH..DOUBLE VERTICAL LINE\n2018          ; Not_XID                        # 1.1        LEFT SINGLE QUOTATION MARK\n201A..2023    ; Not_XID                        # 1.1   [10] SINGLE LOW-9 QUOTATION MARK..TRIANGULAR BULLET\n2028..2029    ; Not_XID                        # 1.1    [2] LINE SEPARATOR..PARAGRAPH SEPARATOR\n2030..2032    ; Not_XID                        # 1.1    [3] PER MILLE SIGN..PRIME\n2035          ; Not_XID                        # 1.1        REVERSED PRIME\n2038..203B    ; Not_XID                        # 1.1    [4] CARET..REFERENCE MARK\n203D          ; Not_XID                        # 1.1        INTERROBANG\n2041..2046    ; Not_XID                        # 1.1    [6] CARET INSERTION POINT..RIGHT SQUARE BRACKET WITH QUILL\n204A..204D    ; Not_XID                        # 3.0    [4] TIRONIAN SIGN ET..BLACK RIGHTWARDS BULLET\n204E..2052    ; Not_XID                        # 3.2    [5] LOW ASTERISK..COMMERCIAL MINUS SIGN\n2053          ; Not_XID                        # 4.0        SWUNG DASH\n2055          ; Not_XID                        # 4.1        FLOWER PUNCTUATION MARK\n20A0..20A7    ; Not_XID                        # 1.1    [8] EURO-CURRENCY SIGN..PESETA SIGN\n20A9..20AA    ; Not_XID                        # 1.1    [2] WON SIGN..NEW SHEQEL SIGN\n20AB          ; Not_XID                        # 2.0        DONG SIGN\n20AC          ; Not_XID                        # 2.1        EURO SIGN\n20AD..20AF    ; Not_XID                        # 3.0    [3] KIP SIGN..DRACHMA SIGN\n20B0..20B1    ; Not_XID                        # 3.2    [2] GERMAN PENNY SIGN..PESO SIGN\n20B2..20B5    ; Not_XID                        # 4.1    [4] GUARANI SIGN..CEDI SIGN\n20B6..20B8    ; Not_XID                        # 5.2    [3] LIVRE TOURNOIS SIGN..TENGE SIGN\n20B9          ; Not_XID                        # 6.0        INDIAN RUPEE SIGN\n20BA          ; Not_XID                        # 6.2        TURKISH LIRA SIGN\n20BB..20BD    ; Not_XID                        # 7.0    [3] NORDIC MARK SIGN..RUBLE SIGN\n20BE          ; Not_XID                        # 8.0        LARI SIGN\n20BF          ; Not_XID                        # 10.0       BITCOIN SIGN\n20C0          ; Not_XID                        # 14.0       SOM SIGN\n20C1          ; Not_XID                        # 17.0       SAUDI RIYAL SIGN\n2104          ; Not_XID                        # 1.1        CENTRE LINE SYMBOL\n2108          ; Not_XID                        # 1.1        SCRUPLE\n2114          ; Not_XID                        # 1.1        L B BAR SYMBOL\n2117          ; Not_XID                        # 1.1        SOUND RECORDING COPYRIGHT\n211E..211F    ; Not_XID                        # 1.1    [2] PRESCRIPTION TAKE..RESPONSE\n2123          ; Not_XID                        # 1.1        VERSICLE\n2125          ; Not_XID                        # 1.1        OUNCE SIGN\n2129          ; Not_XID                        # 1.1        TURNED GREEK SMALL LETTER IOTA\n213A          ; Not_XID                        # 3.0        ROTATED CAPITAL Q\n2141..2144    ; Not_XID                        # 3.2    [4] TURNED SANS-SERIF CAPITAL G..TURNED SANS-SERIF CAPITAL Y\n214A..214B    ; Not_XID                        # 3.2    [2] PROPERTY LINE..TURNED AMPERSAND\n214C          ; Not_XID                        # 4.1        PER SIGN\n214D          ; Not_XID                        # 5.0        AKTIESELSKAB\n2190..21EA    ; Not_XID                        # 1.1   [91] LEFTWARDS ARROW..UPWARDS WHITE ARROW FROM BAR\n21EB..21F3    ; Not_XID                        # 3.0    [9] UPWARDS WHITE ARROW ON PEDESTAL..UP DOWN WHITE ARROW\n21F4..21FF    ; Not_XID                        # 3.2   [12] RIGHT ARROW WITH SMALL CIRCLE..LEFT RIGHT OPEN-HEADED ARROW\n2200..222B    ; Not_XID                        # 1.1   [44] FOR ALL..INTEGRAL\n222E          ; Not_XID                        # 1.1        CONTOUR INTEGRAL\n2231..22F1    ; Not_XID                        # 1.1  [193] CLOCKWISE INTEGRAL..DOWN RIGHT DIAGONAL ELLIPSIS\n22F2..22FF    ; Not_XID                        # 3.2   [14] ELEMENT OF WITH LONG HORIZONTAL STROKE..Z NOTATION BAG MEMBERSHIP\n2300          ; Not_XID                        # 1.1        DIAMETER SIGN\n2301          ; Not_XID                        # 3.0        ELECTRIC ARROW\n2302..2328    ; Not_XID                        # 1.1   [39] HOUSE..KEYBOARD\n232B..237A    ; Not_XID                        # 1.1   [80] ERASE TO THE LEFT..APL FUNCTIONAL SYMBOL ALPHA\n237B          ; Not_XID                        # 3.0        NOT CHECK MARK\n237C          ; Not_XID                        # 3.2        RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW\n237D..239A    ; Not_XID                        # 3.0   [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL\n239B..23CE    ; Not_XID                        # 3.2   [52] LEFT PARENTHESIS UPPER HOOK..RETURN SYMBOL\n23CF..23D0    ; Not_XID                        # 4.0    [2] EJECT SYMBOL..VERTICAL LINE EXTENSION\n23D1..23DB    ; Not_XID                        # 4.1   [11] METRICAL BREVE..FUSE\n23DC..23E7    ; Not_XID                        # 5.0   [12] TOP PARENTHESIS..ELECTRICAL INTERSECTION\n23E8          ; Not_XID                        # 5.2        DECIMAL EXPONENT SYMBOL\n23E9..23F3    ; Not_XID                        # 6.0   [11] BLACK RIGHT-POINTING DOUBLE TRIANGLE..HOURGLASS WITH FLOWING SAND\n23F4..23FA    ; Not_XID                        # 7.0    [7] BLACK MEDIUM LEFT-POINTING TRIANGLE..BLACK CIRCLE FOR RECORD\n23FB..23FE    ; Not_XID                        # 9.0    [4] POWER SYMBOL..POWER SLEEP SYMBOL\n23FF          ; Not_XID                        # 10.0       OBSERVER EYE SYMBOL\n2400..2424    ; Not_XID                        # 1.1   [37] SYMBOL FOR NULL..SYMBOL FOR NEWLINE\n2425..2426    ; Not_XID                        # 3.0    [2] SYMBOL FOR DELETE FORM TWO..SYMBOL FOR SUBSTITUTE FORM TWO\n2427..2429    ; Not_XID                        # 16.0   [3] SYMBOL FOR DELETE SQUARE CHECKER BOARD FORM..SYMBOL FOR DELETE MEDIUM SHADE FORM\n2440..244A    ; Not_XID                        # 1.1   [11] OCR HOOK..OCR DOUBLE BACKSLASH\n2500..2595    ; Not_XID                        # 1.1  [150] BOX DRAWINGS LIGHT HORIZONTAL..RIGHT ONE EIGHTH BLOCK\n2596..259F    ; Not_XID                        # 3.2   [10] QUADRANT LOWER LEFT..QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT\n25A0..25EF    ; Not_XID                        # 1.1   [80] BLACK SQUARE..LARGE CIRCLE\n25F0..25F7    ; Not_XID                        # 3.0    [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT\n25F8..25FF    ; Not_XID                        # 3.2    [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE\n2600..2613    ; Not_XID                        # 1.1   [20] BLACK SUN WITH RAYS..SALTIRE\n2614..2615    ; Not_XID                        # 4.0    [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE\n2616..2617    ; Not_XID                        # 3.2    [2] WHITE SHOGI PIECE..BLACK SHOGI PIECE\n2618          ; Not_XID                        # 4.1        SHAMROCK\n2619          ; Not_XID                        # 3.0        REVERSED ROTATED FLORAL HEART BULLET\n261A..266F    ; Not_XID                        # 1.1   [86] BLACK LEFT POINTING INDEX..MUSIC SHARP SIGN\n2670..2671    ; Not_XID                        # 3.0    [2] WEST SYRIAC CROSS..EAST SYRIAC CROSS\n2672..267D    ; Not_XID                        # 3.2   [12] UNIVERSAL RECYCLING SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL\n267E..267F    ; Not_XID                        # 4.1    [2] PERMANENT PAPER SIGN..WHEELCHAIR SYMBOL\n2680..2689    ; Not_XID                        # 3.2   [10] DIE FACE-1..BLACK CIRCLE WITH TWO WHITE DOTS\n268A..2691    ; Not_XID                        # 4.0    [8] MONOGRAM FOR YANG..BLACK FLAG\n2692..269C    ; Not_XID                        # 4.1   [11] HAMMER AND PICK..FLEUR-DE-LIS\n269D          ; Not_XID                        # 5.1        OUTLINED WHITE STAR\n269E..269F    ; Not_XID                        # 5.2    [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT\n26A0..26A1    ; Not_XID                        # 4.0    [2] WARNING SIGN..HIGH VOLTAGE SIGN\n26A2..26B1    ; Not_XID                        # 4.1   [16] DOUBLED FEMALE SIGN..FUNERAL URN\n26B2          ; Not_XID                        # 5.0        NEUTER\n26B3..26BC    ; Not_XID                        # 5.1   [10] CERES..SESQUIQUADRATE\n26BD..26BF    ; Not_XID                        # 5.2    [3] SOCCER BALL..SQUARED KEY\n26C0..26C3    ; Not_XID                        # 5.1    [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING\n26C4..26CD    ; Not_XID                        # 5.2   [10] SNOWMAN WITHOUT SNOW..DISABLED CAR\n26CE          ; Not_XID                        # 6.0        OPHIUCHUS\n26CF..26E1    ; Not_XID                        # 5.2   [19] PICK..RESTRICTED LEFT ENTRY-2\n26E2          ; Not_XID                        # 6.0        ASTRONOMICAL SYMBOL FOR URANUS\n26E3          ; Not_XID                        # 5.2        HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE\n26E4..26E7    ; Not_XID                        # 6.0    [4] PENTAGRAM..INVERTED PENTAGRAM\n26E8..26FF    ; Not_XID                        # 5.2   [24] BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE\n2700          ; Not_XID                        # 7.0        BLACK SAFETY SCISSORS\n2701..2704    ; Not_XID                        # 1.1    [4] UPPER BLADE SCISSORS..WHITE SCISSORS\n2705          ; Not_XID                        # 6.0        WHITE HEAVY CHECK MARK\n2706..2709    ; Not_XID                        # 1.1    [4] TELEPHONE LOCATION SIGN..ENVELOPE\n270A..270B    ; Not_XID                        # 6.0    [2] RAISED FIST..RAISED HAND\n270C..2727    ; Not_XID                        # 1.1   [28] VICTORY HAND..WHITE FOUR POINTED STAR\n2728          ; Not_XID                        # 6.0        SPARKLES\n2729..274B    ; Not_XID                        # 1.1   [35] STRESS OUTLINED WHITE STAR..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK\n274C          ; Not_XID                        # 6.0        CROSS MARK\n274D          ; Not_XID                        # 1.1        SHADOWED WHITE CIRCLE\n274E          ; Not_XID                        # 6.0        NEGATIVE SQUARED CROSS MARK\n274F..2752    ; Not_XID                        # 1.1    [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE\n2753..2755    ; Not_XID                        # 6.0    [3] BLACK QUESTION MARK ORNAMENT..WHITE EXCLAMATION MARK ORNAMENT\n2756          ; Not_XID                        # 1.1        BLACK DIAMOND MINUS WHITE X\n2757          ; Not_XID                        # 5.2        HEAVY EXCLAMATION MARK SYMBOL\n2758..275E    ; Not_XID                        # 1.1    [7] LIGHT VERTICAL BAR..HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT\n275F..2760    ; Not_XID                        # 6.0    [2] HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT..HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT\n2761..2767    ; Not_XID                        # 1.1    [7] CURVED STEM PARAGRAPH SIGN ORNAMENT..ROTATED FLORAL HEART BULLET\n2768..2775    ; Not_XID                        # 3.2   [14] MEDIUM LEFT PARENTHESIS ORNAMENT..MEDIUM RIGHT CURLY BRACKET ORNAMENT\n2776..2794    ; Not_XID                        # 1.1   [31] DINGBAT NEGATIVE CIRCLED DIGIT ONE..HEAVY WIDE-HEADED RIGHTWARDS ARROW\n2795..2797    ; Not_XID                        # 6.0    [3] HEAVY PLUS SIGN..HEAVY DIVISION SIGN\n2798..27AF    ; Not_XID                        # 1.1   [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW\n27B0          ; Not_XID                        # 6.0        CURLY LOOP\n27B1..27BE    ; Not_XID                        # 1.1   [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW\n27BF          ; Not_XID                        # 6.0        DOUBLE CURLY LOOP\n27C0..27C6    ; Not_XID                        # 4.1    [7] THREE DIMENSIONAL ANGLE..RIGHT S-SHAPED BAG DELIMITER\n27C7..27CA    ; Not_XID                        # 5.0    [4] OR WITH DOT INSIDE..VERTICAL BAR WITH HORIZONTAL STROKE\n27CB          ; Not_XID                        # 6.1        MATHEMATICAL RISING DIAGONAL\n27CC          ; Not_XID                        # 5.1        LONG DIVISION\n27CD          ; Not_XID                        # 6.1        MATHEMATICAL FALLING DIAGONAL\n27CE..27CF    ; Not_XID                        # 6.0    [2] SQUARED LOGICAL AND..SQUARED LOGICAL OR\n27D0..27EB    ; Not_XID                        # 3.2   [28] WHITE DIAMOND WITH CENTRED DOT..MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET\n27EC..27EF    ; Not_XID                        # 5.1    [4] MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET..MATHEMATICAL RIGHT FLATTENED PARENTHESIS\n27F0..27FF    ; Not_XID                        # 3.2   [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW\n2900..2A0B    ; Not_XID                        # 3.2  [268] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..SUMMATION WITH INTEGRAL\n2A0D..2A73    ; Not_XID                        # 3.2  [103] FINITE PART INTEGRAL..EQUALS SIGN ABOVE TILDE OPERATOR\n2A77..2ADB    ; Not_XID                        # 3.2  [101] EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW..TRANSVERSAL INTERSECTION\n2ADD..2AFF    ; Not_XID                        # 3.2   [35] NONFORKING..N-ARY WHITE VERTICAL BAR\n2B00..2B0D    ; Not_XID                        # 4.0   [14] NORTH EAST WHITE ARROW..UP DOWN BLACK ARROW\n2B0E..2B13    ; Not_XID                        # 4.1    [6] RIGHTWARDS ARROW WITH TIP DOWNWARDS..SQUARE WITH BOTTOM HALF BLACK\n2B14..2B1A    ; Not_XID                        # 5.0    [7] SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK..DOTTED SQUARE\n2B1B..2B1F    ; Not_XID                        # 5.1    [5] BLACK LARGE SQUARE..BLACK PENTAGON\n2B20..2B23    ; Not_XID                        # 5.0    [4] WHITE PENTAGON..HORIZONTAL BLACK HEXAGON\n2B24..2B4C    ; Not_XID                        # 5.1   [41] BLACK LARGE CIRCLE..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR\n2B4D..2B4F    ; Not_XID                        # 7.0    [3] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..SHORT BACKSLANTED SOUTH ARROW\n2B50..2B54    ; Not_XID                        # 5.1    [5] WHITE MEDIUM STAR..WHITE RIGHT-POINTING PENTAGON\n2B55..2B59    ; Not_XID                        # 5.2    [5] HEAVY LARGE CIRCLE..HEAVY CIRCLED SALTIRE\n2B5A..2B73    ; Not_XID                        # 7.0   [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR\n2B76..2B95    ; Not_XID                        # 7.0   [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW\n2B96          ; Not_XID                        # 17.0       EQUALS SIGN WITH INFINITY ABOVE\n2B97          ; Not_XID                        # 13.0       SYMBOL FOR TYPE A ELECTRONICS\n2B98..2BB9    ; Not_XID                        # 7.0   [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX\n2BBA..2BBC    ; Not_XID                        # 11.0   [3] OVERLAPPING WHITE SQUARES..OVERLAPPING BLACK SQUARES\n2BBD..2BC8    ; Not_XID                        # 7.0   [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED\n2BC9          ; Not_XID                        # 12.0       NEPTUNE FORM TWO\n2BCA..2BD1    ; Not_XID                        # 7.0    [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN\n2BD2          ; Not_XID                        # 10.0       GROUP MARK\n2BD3..2BEB    ; Not_XID                        # 11.0  [25] PLUTO FORM TWO..STAR WITH RIGHT HALF BLACK\n2BF0..2BFE    ; Not_XID                        # 11.0  [15] ERIS FORM ONE..REVERSED RIGHT ANGLE\n2BFF          ; Not_XID                        # 12.0       HELLSCHREIBER PAUSE SYMBOL\n2E17          ; Not_XID                        # 4.1        DOUBLE OBLIQUE HYPHEN\n2E18..2E1B    ; Not_XID                        # 5.1    [4] INVERTED INTERROBANG..TILDE WITH RING ABOVE\n2E1C..2E1D    ; Not_XID                        # 4.1    [2] LEFT LOW PARAPHRASE BRACKET..RIGHT LOW PARAPHRASE BRACKET\n2E1E..2E29    ; Not_XID                        # 5.1   [12] TILDE WITH DOT ABOVE..RIGHT DOUBLE PARENTHESIS\n2E33..2E34    ; Not_XID                        # 6.1    [2] RAISED DOT..RAISED COMMA\n2E36..2E38    ; Not_XID                        # 6.1    [3] DAGGER WITH LEFT GUARD..TURNED DAGGER\n2E3A..2E3B    ; Not_XID                        # 6.1    [2] TWO-EM DASH..THREE-EM DASH\n2E3D..2E42    ; Not_XID                        # 7.0    [6] VERTICAL SIX DOTS..DOUBLE LOW-REVERSED-9 QUOTATION MARK\n2E43..2E44    ; Not_XID                        # 9.0    [2] DASH WITH LEFT UPTURN..DOUBLE SUSPENSION MARK\n2E45..2E49    ; Not_XID                        # 10.0   [5] INVERTED LOW KAVYKA..DOUBLE STACKED COMMA\n2E4A..2E4E    ; Not_XID                        # 11.0   [5] DOTTED SOLIDUS..PUNCTUS ELEVATUS MARK\n2E4F          ; Not_XID                        # 12.0       CORNISH VERSE DIVIDER\n2E50..2E52    ; Not_XID                        # 13.0   [3] CROSS PATTY WITH RIGHT CROSSBAR..TIRONIAN SIGN CAPITAL ET\n2E53..2E5D    ; Not_XID                        # 14.0  [11] MEDIEVAL EXCLAMATION MARK..OBLIQUE HYPHEN\n2E80..2E99    ; Not_XID                        # 3.0   [26] CJK RADICAL REPEAT..CJK RADICAL RAP\n2E9B..2E9E    ; Not_XID                        # 3.0    [4] CJK RADICAL CHOKE..CJK RADICAL DEATH\n2EA0..2EF2    ; Not_XID                        # 3.0   [83] CJK RADICAL CIVILIAN..CJK RADICAL J-SIMPLIFIED TURTLE\n2FF0..2FFB    ; Not_XID                        # 3.0   [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID\n2FFC..2FFF    ; Not_XID                        # 15.1   [4] IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION\n3001..3004    ; Not_XID                        # 1.1    [4] IDEOGRAPHIC COMMA..JAPANESE INDUSTRIAL STANDARD SYMBOL\n3008..301D    ; Not_XID                        # 1.1   [22] LEFT ANGLE BRACKET..REVERSED DOUBLE PRIME QUOTATION MARK\n301F..3020    ; Not_XID                        # 1.1    [2] LOW DOUBLE PRIME QUOTATION MARK..POSTAL MARK FACE\n3030          ; Not_XID                        # 1.1        WAVY DASH\n3037          ; Not_XID                        # 1.1        IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL\n303D          ; Not_XID                        # 3.2        PART ALTERNATION MARK\n303E          ; Not_XID                        # 3.0        IDEOGRAPHIC VARIATION INDICATOR\n303F          ; Not_XID                        # 1.1        IDEOGRAPHIC HALF FILL SPACE\n3190..3191    ; Not_XID                        # 1.1    [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK\n31C0..31CF    ; Not_XID                        # 4.1   [16] CJK STROKE T..CJK STROKE N\n31D0..31E3    ; Not_XID                        # 5.1   [20] CJK STROKE H..CJK STROKE Q\n31E4..31E5    ; Not_XID                        # 16.0   [2] CJK STROKE HXG..CJK STROKE SZP\n31EF          ; Not_XID                        # 15.1       IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION\n3248..324F    ; Not_XID                        # 5.2    [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE\nA67E          ; Not_XID                        # 5.1        CYRILLIC KAVYKA\nA720..A721    ; Not_XID                        # 5.0    [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE\nA789..A78A    ; Not_XID                        # 5.1    [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN\nA830..A839    ; Not_XID                        # 5.2   [10] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC QUANTITY MARK\nA92E          ; Not_XID                        # 5.1        KAYAH LI SIGN CWI\nAA77..AA79    ; Not_XID                        # 5.2    [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO\nAB5B          ; Not_XID                        # 7.0        MODIFIER BREVE WITH INVERTED BREVE\nAB6A..AB6B    ; Not_XID                        # 13.0   [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK\nFFF9..FFFB    ; Not_XID                        # 3.0    [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR\nFFFC          ; Not_XID                        # 2.1        OBJECT REPLACEMENT CHARACTER\nFFFD          ; Not_XID                        # 1.1        REPLACEMENT CHARACTER\n10175..1018A  ; Not_XID                        # 4.1   [22] GREEK ONE HALF SIGN..GREEK ZERO SIGN\n1018B..1018C  ; Not_XID                        # 7.0    [2] GREEK ONE QUARTER SIGN..GREEK SINUSOID SIGN\n1018D..1018E  ; Not_XID                        # 9.0    [2] GREEK INDICTION SIGN..NOMISMA SIGN\n10190..1019B  ; Not_XID                        # 5.1   [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN\n1019C         ; Not_XID                        # 13.0       ASCIA SYMBOL\n101A0         ; Not_XID                        # 7.0        GREEK SYMBOL TAU RHO\n10E60..10E7E  ; Not_XID                        # 5.2   [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS\n10ED0..10ED8  ; Not_XID                        # 17.0   [9] ARABIC BIBLICAL END OF VERSE..ARABIC LIGATURE NAWWARA ALLAAHU MARQADAH\n111E1..111F4  ; Not_XID                        # 7.0   [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND\n11B00..11B09  ; Not_XID                        # 15.0  [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU\n11FC0..11FF1  ; Not_XID                        # 12.0  [50] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL SIGN VAKAIYARAA\n11FFF         ; Not_XID                        # 12.0       TAMIL PUNCTUATION END OF TEXT\n16FE2         ; Not_XID                        # 12.0       OLD CHINESE HOOK MARK\n1CC00..1CCD5  ; Not_XID                        # 16.0 [214] UP-POINTING GO-KART..LOWER RIGHT QUADRANT STANDING KNIGHT\n1CCFA..1CCFC  ; Not_XID                        # 17.0   [3] SNAKE SYMBOL..NOSE SYMBOL\n1CD00..1CEB3  ; Not_XID                        # 16.0 [436] BLOCK OCTANT-3..BLACK RIGHT TRIANGLE CARET\n1CEBA..1CED0  ; Not_XID                        # 17.0  [23] FRAGILE SYMBOL..LEUKOTHEA\n1CEE0..1CEF0  ; Not_XID                        # 17.0  [17] GEOMANTIC FIGURE POPULUS..MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR\n1D2C0..1D2D3  ; Not_XID                        # 15.0  [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN\n1D2E0..1D2F3  ; Not_XID                        # 11.0  [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN\n1D360..1D371  ; Not_XID                        # 5.0   [18] COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE\n1D372..1D378  ; Not_XID                        # 11.0   [7] IDEOGRAPHIC TALLY MARK ONE..TALLY MARK FIVE\n1EC71..1ECB4  ; Not_XID                        # 11.0  [68] INDIC SIYAQ NUMBER ONE..INDIC SIYAQ ALTERNATE LAKH MARK\n1ED01..1ED3D  ; Not_XID                        # 12.0  [61] OTTOMAN SIYAQ NUMBER ONE..OTTOMAN SIYAQ FRACTION ONE SIXTH\n1EEF0..1EEF1  ; Not_XID                        # 6.1    [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL\n1F000..1F02B  ; Not_XID                        # 5.1   [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK\n1F030..1F093  ; Not_XID                        # 5.1  [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06\n1F0A0..1F0AE  ; Not_XID                        # 6.0   [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES\n1F0B1..1F0BE  ; Not_XID                        # 6.0   [14] PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS\n1F0BF         ; Not_XID                        # 7.0        PLAYING CARD RED JOKER\n1F0C1..1F0CF  ; Not_XID                        # 6.0   [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER\n1F0D1..1F0DF  ; Not_XID                        # 6.0   [15] PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER\n1F0E0..1F0F5  ; Not_XID                        # 7.0   [22] PLAYING CARD FOOL..PLAYING CARD TRUMP-21\n1F10B..1F10C  ; Not_XID                        # 7.0    [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO\n1F10D..1F10F  ; Not_XID                        # 13.0   [3] CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH\n1F12F         ; Not_XID                        # 11.0       COPYLEFT SYMBOL\n1F150..1F156  ; Not_XID                        # 6.0    [7] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER G\n1F157         ; Not_XID                        # 5.2        NEGATIVE CIRCLED LATIN CAPITAL LETTER H\n1F158..1F15E  ; Not_XID                        # 6.0    [7] NEGATIVE CIRCLED LATIN CAPITAL LETTER I..NEGATIVE CIRCLED LATIN CAPITAL LETTER O\n1F15F         ; Not_XID                        # 5.2        NEGATIVE CIRCLED LATIN CAPITAL LETTER P\n1F160..1F169  ; Not_XID                        # 6.0   [10] NEGATIVE CIRCLED LATIN CAPITAL LETTER Q..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z\n1F16D..1F16F  ; Not_XID                        # 13.0   [3] CIRCLED CC..CIRCLED HUMAN FIGURE\n1F170..1F178  ; Not_XID                        # 6.0    [9] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER I\n1F179         ; Not_XID                        # 5.2        NEGATIVE SQUARED LATIN CAPITAL LETTER J\n1F17A         ; Not_XID                        # 6.0        NEGATIVE SQUARED LATIN CAPITAL LETTER K\n1F17B..1F17C  ; Not_XID                        # 5.2    [2] NEGATIVE SQUARED LATIN CAPITAL LETTER L..NEGATIVE SQUARED LATIN CAPITAL LETTER M\n1F17D..1F17E  ; Not_XID                        # 6.0    [2] NEGATIVE SQUARED LATIN CAPITAL LETTER N..NEGATIVE SQUARED LATIN CAPITAL LETTER O\n1F17F         ; Not_XID                        # 5.2        NEGATIVE SQUARED LATIN CAPITAL LETTER P\n1F180..1F189  ; Not_XID                        # 6.0   [10] NEGATIVE SQUARED LATIN CAPITAL LETTER Q..NEGATIVE SQUARED LATIN CAPITAL LETTER Z\n1F18A..1F18D  ; Not_XID                        # 5.2    [4] CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P..NEGATIVE SQUARED SA\n1F18E..1F18F  ; Not_XID                        # 6.0    [2] NEGATIVE SQUARED AB..NEGATIVE SQUARED WC\n1F191..1F19A  ; Not_XID                        # 6.0   [10] SQUARED CL..SQUARED VS\n1F19B..1F1AC  ; Not_XID                        # 9.0   [18] SQUARED THREE D..SQUARED VOD\n1F1AD         ; Not_XID                        # 13.0       MASK WORK SYMBOL\n1F1E6..1F1FF  ; Not_XID                        # 6.0   [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z\n1F260..1F265  ; Not_XID                        # 10.0   [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI\n1F300..1F320  ; Not_XID                        # 6.0   [33] CYCLONE..SHOOTING STAR\n1F321..1F32C  ; Not_XID                        # 7.0   [12] THERMOMETER..WIND BLOWING FACE\n1F32D..1F32F  ; Not_XID                        # 8.0    [3] HOT DOG..BURRITO\n1F330..1F335  ; Not_XID                        # 6.0    [6] CHESTNUT..CACTUS\n1F336         ; Not_XID                        # 7.0        HOT PEPPER\n1F337..1F37C  ; Not_XID                        # 6.0   [70] TULIP..BABY BOTTLE\n1F37D         ; Not_XID                        # 7.0        FORK AND KNIFE WITH PLATE\n1F37E..1F37F  ; Not_XID                        # 8.0    [2] BOTTLE WITH POPPING CORK..POPCORN\n1F380..1F393  ; Not_XID                        # 6.0   [20] RIBBON..GRADUATION CAP\n1F394..1F39F  ; Not_XID                        # 7.0   [12] HEART WITH TIP ON THE LEFT..ADMISSION TICKETS\n1F3A0..1F3C4  ; Not_XID                        # 6.0   [37] CAROUSEL HORSE..SURFER\n1F3C5         ; Not_XID                        # 7.0        SPORTS MEDAL\n1F3C6..1F3CA  ; Not_XID                        # 6.0    [5] TROPHY..SWIMMER\n1F3CB..1F3CE  ; Not_XID                        # 7.0    [4] WEIGHT LIFTER..RACING CAR\n1F3CF..1F3D3  ; Not_XID                        # 8.0    [5] CRICKET BAT AND BALL..TABLE TENNIS PADDLE AND BALL\n1F3D4..1F3DF  ; Not_XID                        # 7.0   [12] SNOW CAPPED MOUNTAIN..STADIUM\n1F3E0..1F3F0  ; Not_XID                        # 6.0   [17] HOUSE BUILDING..EUROPEAN CASTLE\n1F3F1..1F3F7  ; Not_XID                        # 7.0    [7] WHITE PENNANT..LABEL\n1F3F8..1F3FF  ; Not_XID                        # 8.0    [8] BADMINTON RACQUET AND SHUTTLECOCK..EMOJI MODIFIER FITZPATRICK TYPE-6\n1F400..1F43E  ; Not_XID                        # 6.0   [63] RAT..PAW PRINTS\n1F43F         ; Not_XID                        # 7.0        CHIPMUNK\n1F440         ; Not_XID                        # 6.0        EYES\n1F441         ; Not_XID                        # 7.0        EYE\n1F442..1F4F7  ; Not_XID                        # 6.0  [182] EAR..CAMERA\n1F4F8         ; Not_XID                        # 7.0        CAMERA WITH FLASH\n1F4F9..1F4FC  ; Not_XID                        # 6.0    [4] VIDEO CAMERA..VIDEOCASSETTE\n1F4FD..1F4FE  ; Not_XID                        # 7.0    [2] FILM PROJECTOR..PORTABLE STEREO\n1F4FF         ; Not_XID                        # 8.0        PRAYER BEADS\n1F500..1F53D  ; Not_XID                        # 6.0   [62] TWISTED RIGHTWARDS ARROWS..DOWN-POINTING SMALL RED TRIANGLE\n1F53E..1F53F  ; Not_XID                        # 7.0    [2] LOWER RIGHT SHADOWED WHITE CIRCLE..UPPER RIGHT SHADOWED WHITE CIRCLE\n1F540..1F543  ; Not_XID                        # 6.1    [4] CIRCLED CROSS POMMEE..NOTCHED LEFT SEMICIRCLE WITH THREE DOTS\n1F544..1F54A  ; Not_XID                        # 7.0    [7] NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS..DOVE OF PEACE\n1F54B..1F54E  ; Not_XID                        # 8.0    [4] KAABA..MENORAH WITH NINE BRANCHES\n1F550..1F567  ; Not_XID                        # 6.0   [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY\n1F568..1F579  ; Not_XID                        # 7.0   [18] RIGHT SPEAKER..JOYSTICK\n1F57A         ; Not_XID                        # 9.0        MAN DANCING\n1F57B..1F5A3  ; Not_XID                        # 7.0   [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX\n1F5A4         ; Not_XID                        # 9.0        BLACK HEART\n1F5A5..1F5FA  ; Not_XID                        # 7.0   [86] DESKTOP COMPUTER..WORLD MAP\n1F5FB..1F5FF  ; Not_XID                        # 6.0    [5] MOUNT FUJI..MOYAI\n1F600         ; Not_XID                        # 6.1        GRINNING FACE\n1F601..1F610  ; Not_XID                        # 6.0   [16] GRINNING FACE WITH SMILING EYES..NEUTRAL FACE\n1F611         ; Not_XID                        # 6.1        EXPRESSIONLESS FACE\n1F612..1F614  ; Not_XID                        # 6.0    [3] UNAMUSED FACE..PENSIVE FACE\n1F615         ; Not_XID                        # 6.1        CONFUSED FACE\n1F616         ; Not_XID                        # 6.0        CONFOUNDED FACE\n1F617         ; Not_XID                        # 6.1        KISSING FACE\n1F618         ; Not_XID                        # 6.0        FACE THROWING A KISS\n1F619         ; Not_XID                        # 6.1        KISSING FACE WITH SMILING EYES\n1F61A         ; Not_XID                        # 6.0        KISSING FACE WITH CLOSED EYES\n1F61B         ; Not_XID                        # 6.1        FACE WITH STUCK-OUT TONGUE\n1F61C..1F61E  ; Not_XID                        # 6.0    [3] FACE WITH STUCK-OUT TONGUE AND WINKING EYE..DISAPPOINTED FACE\n1F61F         ; Not_XID                        # 6.1        WORRIED FACE\n1F620..1F625  ; Not_XID                        # 6.0    [6] ANGRY FACE..DISAPPOINTED BUT RELIEVED FACE\n1F626..1F627  ; Not_XID                        # 6.1    [2] FROWNING FACE WITH OPEN MOUTH..ANGUISHED FACE\n1F628..1F62B  ; Not_XID                        # 6.0    [4] FEARFUL FACE..TIRED FACE\n1F62C         ; Not_XID                        # 6.1        GRIMACING FACE\n1F62D         ; Not_XID                        # 6.0        LOUDLY CRYING FACE\n1F62E..1F62F  ; Not_XID                        # 6.1    [2] FACE WITH OPEN MOUTH..HUSHED FACE\n1F630..1F633  ; Not_XID                        # 6.0    [4] FACE WITH OPEN MOUTH AND COLD SWEAT..FLUSHED FACE\n1F634         ; Not_XID                        # 6.1        SLEEPING FACE\n1F635..1F640  ; Not_XID                        # 6.0   [12] DIZZY FACE..WEARY CAT FACE\n1F641..1F642  ; Not_XID                        # 7.0    [2] SLIGHTLY FROWNING FACE..SLIGHTLY SMILING FACE\n1F643..1F644  ; Not_XID                        # 8.0    [2] UPSIDE-DOWN FACE..FACE WITH ROLLING EYES\n1F645..1F64F  ; Not_XID                        # 6.0   [11] FACE WITH NO GOOD GESTURE..PERSON WITH FOLDED HANDS\n1F650..1F67F  ; Not_XID                        # 7.0   [48] NORTH WEST POINTING LEAF..REVERSE CHECKER BOARD\n1F680..1F6C5  ; Not_XID                        # 6.0   [70] ROCKET..LEFT LUGGAGE\n1F6C6..1F6CF  ; Not_XID                        # 7.0   [10] TRIANGLE WITH ROUNDED CORNERS..BED\n1F6D0         ; Not_XID                        # 8.0        PLACE OF WORSHIP\n1F6D1..1F6D2  ; Not_XID                        # 9.0    [2] OCTAGONAL SIGN..SHOPPING TROLLEY\n1F6D3..1F6D4  ; Not_XID                        # 10.0   [2] STUPA..PAGODA\n1F6D5         ; Not_XID                        # 12.0       HINDU TEMPLE\n1F6D6..1F6D7  ; Not_XID                        # 13.0   [2] HUT..ELEVATOR\n1F6D8         ; Not_XID                        # 17.0       LANDSLIDE\n1F6DC         ; Not_XID                        # 15.0       WIRELESS\n1F6DD..1F6DF  ; Not_XID                        # 14.0   [3] PLAYGROUND SLIDE..RING BUOY\n1F6E0..1F6EC  ; Not_XID                        # 7.0   [13] HAMMER AND WRENCH..AIRPLANE ARRIVING\n1F6F0..1F6F3  ; Not_XID                        # 7.0    [4] SATELLITE..PASSENGER SHIP\n1F6F4..1F6F6  ; Not_XID                        # 9.0    [3] SCOOTER..CANOE\n1F6F7..1F6F8  ; Not_XID                        # 10.0   [2] SLED..FLYING SAUCER\n1F6F9         ; Not_XID                        # 11.0       SKATEBOARD\n1F6FA         ; Not_XID                        # 12.0       AUTO RICKSHAW\n1F6FB..1F6FC  ; Not_XID                        # 13.0   [2] PICKUP TRUCK..ROLLER SKATE\n1F700..1F773  ; Not_XID                        # 6.0  [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE\n1F774..1F776  ; Not_XID                        # 15.0   [3] LOT OF FORTUNE..LUNAR ECLIPSE\n1F777..1F77A  ; Not_XID                        # 17.0   [4] VESTA FORM TWO..PARTHENOPE FORM TWO\n1F77B..1F77F  ; Not_XID                        # 15.0   [5] HAUMEA..ORCUS\n1F780..1F7D4  ; Not_XID                        # 7.0   [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR\n1F7D5..1F7D8  ; Not_XID                        # 11.0   [4] CIRCLED TRIANGLE..NEGATIVE CIRCLED SQUARE\n1F7D9         ; Not_XID                        # 15.0       NINE POINTED WHITE STAR\n1F7E0..1F7EB  ; Not_XID                        # 12.0  [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE\n1F7F0         ; Not_XID                        # 14.0       HEAVY EQUALS SIGN\n1F800..1F80B  ; Not_XID                        # 7.0   [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD\n1F810..1F847  ; Not_XID                        # 7.0   [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW\n1F850..1F859  ; Not_XID                        # 7.0   [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW\n1F860..1F887  ; Not_XID                        # 7.0   [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW\n1F890..1F8AD  ; Not_XID                        # 7.0   [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS\n1F8B0..1F8B1  ; Not_XID                        # 13.0   [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST\n1F8B2..1F8BB  ; Not_XID                        # 16.0  [10] RIGHTWARDS ARROW WITH LOWER HOOK..SOUTH WEST ARROW FROM BAR\n1F8C0..1F8C1  ; Not_XID                        # 16.0   [2] LEFTWARDS ARROW FROM DOWNWARDS ARROW..RIGHTWARDS ARROW FROM DOWNWARDS ARROW\n1F8D0..1F8D8  ; Not_XID                        # 17.0   [9] LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW..LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE\n1F900..1F90B  ; Not_XID                        # 10.0  [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT\n1F90C         ; Not_XID                        # 13.0       PINCHED FINGERS\n1F90D..1F90F  ; Not_XID                        # 12.0   [3] WHITE HEART..PINCHING HAND\n1F910..1F918  ; Not_XID                        # 8.0    [9] ZIPPER-MOUTH FACE..SIGN OF THE HORNS\n1F919..1F91E  ; Not_XID                        # 9.0    [6] CALL ME HAND..HAND WITH INDEX AND MIDDLE FINGERS CROSSED\n1F91F         ; Not_XID                        # 10.0       I LOVE YOU HAND SIGN\n1F920..1F927  ; Not_XID                        # 9.0    [8] FACE WITH COWBOY HAT..SNEEZING FACE\n1F928..1F92F  ; Not_XID                        # 10.0   [8] FACE WITH ONE EYEBROW RAISED..SHOCKED FACE WITH EXPLODING HEAD\n1F930         ; Not_XID                        # 9.0        PREGNANT WOMAN\n1F931..1F932  ; Not_XID                        # 10.0   [2] BREAST-FEEDING..PALMS UP TOGETHER\n1F933..1F93E  ; Not_XID                        # 9.0   [12] SELFIE..HANDBALL\n1F93F         ; Not_XID                        # 12.0       DIVING MASK\n1F940..1F94B  ; Not_XID                        # 9.0   [12] WILTED FLOWER..MARTIAL ARTS UNIFORM\n1F94C         ; Not_XID                        # 10.0       CURLING STONE\n1F94D..1F94F  ; Not_XID                        # 11.0   [3] LACROSSE STICK AND BALL..FLYING DISC\n1F950..1F95E  ; Not_XID                        # 9.0   [15] CROISSANT..PANCAKES\n1F95F..1F96B  ; Not_XID                        # 10.0  [13] DUMPLING..CANNED FOOD\n1F96C..1F970  ; Not_XID                        # 11.0   [5] LEAFY GREEN..SMILING FACE WITH SMILING EYES AND THREE HEARTS\n1F971         ; Not_XID                        # 12.0       YAWNING FACE\n1F972         ; Not_XID                        # 13.0       SMILING FACE WITH TEAR\n1F973..1F976  ; Not_XID                        # 11.0   [4] FACE WITH PARTY HORN AND PARTY HAT..FREEZING FACE\n1F977..1F978  ; Not_XID                        # 13.0   [2] NINJA..DISGUISED FACE\n1F979         ; Not_XID                        # 14.0       FACE HOLDING BACK TEARS\n1F97A         ; Not_XID                        # 11.0       FACE WITH PLEADING EYES\n1F97B         ; Not_XID                        # 12.0       SARI\n1F97C..1F97F  ; Not_XID                        # 11.0   [4] LAB COAT..FLAT SHOE\n1F980..1F984  ; Not_XID                        # 8.0    [5] CRAB..UNICORN FACE\n1F985..1F991  ; Not_XID                        # 9.0   [13] EAGLE..SQUID\n1F992..1F997  ; Not_XID                        # 10.0   [6] GIRAFFE FACE..CRICKET\n1F998..1F9A2  ; Not_XID                        # 11.0  [11] KANGAROO..SWAN\n1F9A3..1F9A4  ; Not_XID                        # 13.0   [2] MAMMOTH..DODO\n1F9A5..1F9AA  ; Not_XID                        # 12.0   [6] SLOTH..OYSTER\n1F9AB..1F9AD  ; Not_XID                        # 13.0   [3] BEAVER..SEAL\n1F9AE..1F9AF  ; Not_XID                        # 12.0   [2] GUIDE DOG..PROBING CANE\n1F9B0..1F9B9  ; Not_XID                        # 11.0  [10] EMOJI COMPONENT RED HAIR..SUPERVILLAIN\n1F9BA..1F9BF  ; Not_XID                        # 12.0   [6] SAFETY VEST..MECHANICAL LEG\n1F9C0         ; Not_XID                        # 8.0        CHEESE WEDGE\n1F9C1..1F9C2  ; Not_XID                        # 11.0   [2] CUPCAKE..SALT SHAKER\n1F9C3..1F9CA  ; Not_XID                        # 12.0   [8] BEVERAGE BOX..ICE CUBE\n1F9CB         ; Not_XID                        # 13.0       BUBBLE TEA\n1F9CC         ; Not_XID                        # 14.0       TROLL\n1F9CD..1F9CF  ; Not_XID                        # 12.0   [3] STANDING PERSON..DEAF PERSON\n1F9D0..1F9E6  ; Not_XID                        # 10.0  [23] FACE WITH MONOCLE..SOCKS\n1F9E7..1F9FF  ; Not_XID                        # 11.0  [25] RED GIFT ENVELOPE..NAZAR AMULET\n1FA00..1FA53  ; Not_XID                        # 12.0  [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP\n1FA54..1FA57  ; Not_XID                        # 17.0   [4] WHITE CHESS FERZ..BLACK CHESS ALFIL\n1FA60..1FA6D  ; Not_XID                        # 11.0  [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER\n1FA70..1FA73  ; Not_XID                        # 12.0   [4] BALLET SHOES..SHORTS\n1FA74         ; Not_XID                        # 13.0       THONG SANDAL\n1FA75..1FA77  ; Not_XID                        # 15.0   [3] LIGHT BLUE HEART..PINK HEART\n1FA78..1FA7A  ; Not_XID                        # 12.0   [3] DROP OF BLOOD..STETHOSCOPE\n1FA7B..1FA7C  ; Not_XID                        # 14.0   [2] X-RAY..CRUTCH\n1FA80..1FA82  ; Not_XID                        # 12.0   [3] YO-YO..PARACHUTE\n1FA83..1FA86  ; Not_XID                        # 13.0   [4] BOOMERANG..NESTING DOLLS\n1FA87..1FA88  ; Not_XID                        # 15.0   [2] MARACAS..FLUTE\n1FA89         ; Not_XID                        # 16.0       HARP\n1FA8A         ; Not_XID                        # 17.0       TROMBONE\n1FA8E         ; Not_XID                        # 17.0       TREASURE CHEST\n1FA8F         ; Not_XID                        # 16.0       SHOVEL\n1FA90..1FA95  ; Not_XID                        # 12.0   [6] RINGED PLANET..BANJO\n1FA96..1FAA8  ; Not_XID                        # 13.0  [19] MILITARY HELMET..ROCK\n1FAA9..1FAAC  ; Not_XID                        # 14.0   [4] MIRROR BALL..HAMSA\n1FAAD..1FAAF  ; Not_XID                        # 15.0   [3] FOLDING HAND FAN..KHANDA\n1FAB0..1FAB6  ; Not_XID                        # 13.0   [7] FLY..FEATHER\n1FAB7..1FABA  ; Not_XID                        # 14.0   [4] LOTUS..NEST WITH EGGS\n1FABB..1FABD  ; Not_XID                        # 15.0   [3] HYACINTH..WING\n1FABE         ; Not_XID                        # 16.0       LEAFLESS TREE\n1FABF         ; Not_XID                        # 15.0       GOOSE\n1FAC0..1FAC2  ; Not_XID                        # 13.0   [3] ANATOMICAL HEART..PEOPLE HUGGING\n1FAC3..1FAC5  ; Not_XID                        # 14.0   [3] PREGNANT MAN..PERSON WITH CROWN\n1FAC6         ; Not_XID                        # 16.0       FINGERPRINT\n1FAC8         ; Not_XID                        # 17.0       HAIRY CREATURE\n1FACD         ; Not_XID                        # 17.0       ORCA\n1FACE..1FACF  ; Not_XID                        # 15.0   [2] MOOSE..DONKEY\n1FAD0..1FAD6  ; Not_XID                        # 13.0   [7] BLUEBERRIES..TEAPOT\n1FAD7..1FAD9  ; Not_XID                        # 14.0   [3] POURING LIQUID..JAR\n1FADA..1FADB  ; Not_XID                        # 15.0   [2] GINGER ROOT..PEA POD\n1FADC         ; Not_XID                        # 16.0       ROOT VEGETABLE\n1FADF         ; Not_XID                        # 16.0       SPLATTER\n1FAE0..1FAE7  ; Not_XID                        # 14.0   [8] MELTING FACE..BUBBLES\n1FAE8         ; Not_XID                        # 15.0       SHAKING FACE\n1FAE9         ; Not_XID                        # 16.0       FACE WITH BAGS UNDER EYES\n1FAEA         ; Not_XID                        # 17.0       DISTORTED FACE\n1FAEF         ; Not_XID                        # 17.0       FIGHT CLOUD\n1FAF0..1FAF6  ; Not_XID                        # 14.0   [7] HAND WITH INDEX FINGER AND THUMB CROSSED..HEART HANDS\n1FAF7..1FAF8  ; Not_XID                        # 15.0   [2] LEFTWARDS PUSHING HAND..RIGHTWARDS PUSHING HAND\n1FB00..1FB92  ; Not_XID                        # 13.0 [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK\n1FB94..1FBCA  ; Not_XID                        # 13.0  [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON\n1FBCB..1FBEF  ; Not_XID                        # 16.0  [37] WHITE CROSS MARK..TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE\n1FBFA         ; Not_XID                        # 17.0       ALARM BELL SYMBOL\n\n# Total code points: 6487\n\n#\tIdentifier_Type:\tNot_NFKC\n\n00A0          ; Not_NFKC                       # 1.1        NO-BREAK SPACE\n00A8          ; Not_NFKC                       # 1.1        DIAERESIS\n00AA          ; Not_NFKC                       # 1.1        FEMININE ORDINAL INDICATOR\n00AF          ; Not_NFKC                       # 1.1        MACRON\n00B2..00B5    ; Not_NFKC                       # 1.1    [4] SUPERSCRIPT TWO..MICRO SIGN\n00B8..00BA    ; Not_NFKC                       # 1.1    [3] CEDILLA..MASCULINE ORDINAL INDICATOR\n00BC..00BE    ; Not_NFKC                       # 1.1    [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS\n0132..0133    ; Not_NFKC                       # 1.1    [2] LATIN CAPITAL LIGATURE IJ..LATIN SMALL LIGATURE IJ\n013F..0140    ; Not_NFKC                       # 1.1    [2] LATIN CAPITAL LETTER L WITH MIDDLE DOT..LATIN SMALL LETTER L WITH MIDDLE DOT\n017F          ; Not_NFKC                       # 1.1        LATIN SMALL LETTER LONG S\n01C4..01CC    ; Not_NFKC                       # 1.1    [9] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER NJ\n01F1..01F3    ; Not_NFKC                       # 1.1    [3] LATIN CAPITAL LETTER DZ..LATIN SMALL LETTER DZ\n02B0..02B8    ; Not_NFKC                       # 1.1    [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y\n02D8..02DD    ; Not_NFKC                       # 1.1    [6] BREVE..DOUBLE ACUTE ACCENT\n02E0..02E4    ; Not_NFKC                       # 1.1    [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP\n0340..0341    ; Not_NFKC                       # 1.1    [2] COMBINING GRAVE TONE MARK..COMBINING ACUTE TONE MARK\n0343..0344    ; Not_NFKC                       # 1.1    [2] COMBINING GREEK KORONIS..COMBINING GREEK DIALYTIKA TONOS\n0374          ; Not_NFKC                       # 1.1        GREEK NUMERAL SIGN\n037A          ; Not_NFKC                       # 1.1        GREEK YPOGEGRAMMENI\n037E          ; Not_NFKC                       # 1.1        GREEK QUESTION MARK\n0384..0385    ; Not_NFKC                       # 1.1    [2] GREEK TONOS..GREEK DIALYTIKA TONOS\n0387          ; Not_NFKC                       # 1.1        GREEK ANO TELEIA\n03D0..03D6    ; Not_NFKC                       # 1.1    [7] GREEK BETA SYMBOL..GREEK PI SYMBOL\n03F0..03F2    ; Not_NFKC                       # 1.1    [3] GREEK KAPPA SYMBOL..GREEK LUNATE SIGMA SYMBOL\n03F4..03F5    ; Not_NFKC                       # 3.1    [2] GREEK CAPITAL THETA SYMBOL..GREEK LUNATE EPSILON SYMBOL\n03F9          ; Not_NFKC                       # 4.0        GREEK CAPITAL LUNATE SIGMA SYMBOL\n0587          ; Not_NFKC                       # 1.1        ARMENIAN SMALL LIGATURE ECH YIWN\n0675..0678    ; Not_NFKC                       # 1.1    [4] ARABIC LETTER HIGH HAMZA ALEF..ARABIC LETTER HIGH HAMZA YEH\n0958..095F    ; Not_NFKC                       # 1.1    [8] DEVANAGARI LETTER QA..DEVANAGARI LETTER YYA\n09DC..09DD    ; Not_NFKC                       # 1.1    [2] BENGALI LETTER RRA..BENGALI LETTER RHA\n09DF          ; Not_NFKC                       # 1.1        BENGALI LETTER YYA\n0A33          ; Not_NFKC                       # 1.1        GURMUKHI LETTER LLA\n0A36          ; Not_NFKC                       # 1.1        GURMUKHI LETTER SHA\n0A59..0A5B    ; Not_NFKC                       # 1.1    [3] GURMUKHI LETTER KHHA..GURMUKHI LETTER ZA\n0A5E          ; Not_NFKC                       # 1.1        GURMUKHI LETTER FA\n0B5C..0B5D    ; Not_NFKC                       # 1.1    [2] ORIYA LETTER RRA..ORIYA LETTER RHA\n0E33          ; Not_NFKC                       # 1.1        THAI CHARACTER SARA AM\n0EB3          ; Not_NFKC                       # 1.1        LAO VOWEL SIGN AM\n0EDC..0EDD    ; Not_NFKC                       # 1.1    [2] LAO HO NO..LAO HO MO\n0F0C          ; Not_NFKC                       # 2.0        TIBETAN MARK DELIMITER TSHEG BSTAR\n0F43          ; Not_NFKC                       # 2.0        TIBETAN LETTER GHA\n0F4D          ; Not_NFKC                       # 2.0        TIBETAN LETTER DDHA\n0F52          ; Not_NFKC                       # 2.0        TIBETAN LETTER DHA\n0F57          ; Not_NFKC                       # 2.0        TIBETAN LETTER BHA\n0F5C          ; Not_NFKC                       # 2.0        TIBETAN LETTER DZHA\n0F69          ; Not_NFKC                       # 2.0        TIBETAN LETTER KSSA\n0F73          ; Not_NFKC                       # 2.0        TIBETAN VOWEL SIGN II\n0F75..0F76    ; Not_NFKC                       # 2.0    [2] TIBETAN VOWEL SIGN UU..TIBETAN VOWEL SIGN VOCALIC R\n0F78          ; Not_NFKC                       # 2.0        TIBETAN VOWEL SIGN VOCALIC L\n0F81          ; Not_NFKC                       # 2.0        TIBETAN VOWEL SIGN REVERSED II\n0F93          ; Not_NFKC                       # 2.0        TIBETAN SUBJOINED LETTER GHA\n0F9D          ; Not_NFKC                       # 2.0        TIBETAN SUBJOINED LETTER DDHA\n0FA2          ; Not_NFKC                       # 2.0        TIBETAN SUBJOINED LETTER DHA\n0FA7          ; Not_NFKC                       # 2.0        TIBETAN SUBJOINED LETTER BHA\n0FAC          ; Not_NFKC                       # 2.0        TIBETAN SUBJOINED LETTER DZHA\n0FB9          ; Not_NFKC                       # 2.0        TIBETAN SUBJOINED LETTER KSSA\n10FC          ; Not_NFKC                       # 4.1        MODIFIER LETTER GEORGIAN NAR\n1D2C..1D2E    ; Not_NFKC                       # 4.0    [3] MODIFIER LETTER CAPITAL A..MODIFIER LETTER CAPITAL B\n1D30..1D3A    ; Not_NFKC                       # 4.0   [11] MODIFIER LETTER CAPITAL D..MODIFIER LETTER CAPITAL N\n1D3C..1D4D    ; Not_NFKC                       # 4.0   [18] MODIFIER LETTER CAPITAL O..MODIFIER LETTER SMALL G\n1D4F..1D6A    ; Not_NFKC                       # 4.0   [28] MODIFIER LETTER SMALL K..GREEK SUBSCRIPT SMALL LETTER CHI\n1D78          ; Not_NFKC                       # 4.1        MODIFIER LETTER CYRILLIC EN\n1D9B..1DBF    ; Not_NFKC                       # 4.1   [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA\n1E9A          ; Not_NFKC                       # 1.1        LATIN SMALL LETTER A WITH RIGHT HALF RING\n1E9B          ; Not_NFKC                       # 2.0        LATIN SMALL LETTER LONG S WITH DOT ABOVE\n1F71          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER ALPHA WITH OXIA\n1F73          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER EPSILON WITH OXIA\n1F75          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER ETA WITH OXIA\n1F77          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER IOTA WITH OXIA\n1F79          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER OMICRON WITH OXIA\n1F7B          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER UPSILON WITH OXIA\n1F7D          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER OMEGA WITH OXIA\n1FBB          ; Not_NFKC                       # 1.1        GREEK CAPITAL LETTER ALPHA WITH OXIA\n1FBD..1FC1    ; Not_NFKC                       # 1.1    [5] GREEK KORONIS..GREEK DIALYTIKA AND PERISPOMENI\n1FC9          ; Not_NFKC                       # 1.1        GREEK CAPITAL LETTER EPSILON WITH OXIA\n1FCB          ; Not_NFKC                       # 1.1        GREEK CAPITAL LETTER ETA WITH OXIA\n1FCD..1FCF    ; Not_NFKC                       # 1.1    [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI\n1FD3          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA\n1FDB          ; Not_NFKC                       # 1.1        GREEK CAPITAL LETTER IOTA WITH OXIA\n1FDD..1FDF    ; Not_NFKC                       # 1.1    [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI\n1FE3          ; Not_NFKC                       # 1.1        GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA\n1FEB          ; Not_NFKC                       # 1.1        GREEK CAPITAL LETTER UPSILON WITH OXIA\n1FED..1FEF    ; Not_NFKC                       # 1.1    [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA\n1FF9          ; Not_NFKC                       # 1.1        GREEK CAPITAL LETTER OMICRON WITH OXIA\n1FFB          ; Not_NFKC                       # 1.1        GREEK CAPITAL LETTER OMEGA WITH OXIA\n1FFD..1FFE    ; Not_NFKC                       # 1.1    [2] GREEK OXIA..GREEK DASIA\n2000..200A    ; Not_NFKC                       # 1.1   [11] EN QUAD..HAIR SPACE\n2011          ; Not_NFKC                       # 1.1        NON-BREAKING HYPHEN\n2017          ; Not_NFKC                       # 1.1        DOUBLE LOW LINE\n2024..2026    ; Not_NFKC                       # 1.1    [3] ONE DOT LEADER..HORIZONTAL ELLIPSIS\n202F          ; Not_NFKC                       # 3.0        NARROW NO-BREAK SPACE\n2033..2034    ; Not_NFKC                       # 1.1    [2] DOUBLE PRIME..TRIPLE PRIME\n2036..2037    ; Not_NFKC                       # 1.1    [2] REVERSED DOUBLE PRIME..REVERSED TRIPLE PRIME\n203C          ; Not_NFKC                       # 1.1        DOUBLE EXCLAMATION MARK\n203E          ; Not_NFKC                       # 1.1        OVERLINE\n2047          ; Not_NFKC                       # 3.2        DOUBLE QUESTION MARK\n2048..2049    ; Not_NFKC                       # 3.0    [2] QUESTION EXCLAMATION MARK..EXCLAMATION QUESTION MARK\n2057          ; Not_NFKC                       # 3.2        QUADRUPLE PRIME\n205F          ; Not_NFKC                       # 3.2        MEDIUM MATHEMATICAL SPACE\n2070          ; Not_NFKC                       # 1.1        SUPERSCRIPT ZERO\n2071          ; Not_NFKC                       # 3.2        SUPERSCRIPT LATIN SMALL LETTER I\n2074..208E    ; Not_NFKC                       # 1.1   [27] SUPERSCRIPT FOUR..SUBSCRIPT RIGHT PARENTHESIS\n2090..2094    ; Not_NFKC                       # 4.1    [5] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER SCHWA\n2095..209C    ; Not_NFKC                       # 6.0    [8] LATIN SUBSCRIPT SMALL LETTER H..LATIN SUBSCRIPT SMALL LETTER T\n20A8          ; Not_NFKC                       # 1.1        RUPEE SIGN\n2100..2103    ; Not_NFKC                       # 1.1    [4] ACCOUNT OF..DEGREE CELSIUS\n2105..2107    ; Not_NFKC                       # 1.1    [3] CARE OF..EULER CONSTANT\n2109..2113    ; Not_NFKC                       # 1.1   [11] DEGREE FAHRENHEIT..SCRIPT SMALL L\n2115..2116    ; Not_NFKC                       # 1.1    [2] DOUBLE-STRUCK CAPITAL N..NUMERO SIGN\n2119..211D    ; Not_NFKC                       # 1.1    [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R\n2120..2122    ; Not_NFKC                       # 1.1    [3] SERVICE MARK..TRADE MARK SIGN\n2124          ; Not_NFKC                       # 1.1        DOUBLE-STRUCK CAPITAL Z\n2126          ; Not_NFKC                       # 1.1        OHM SIGN\n2128          ; Not_NFKC                       # 1.1        BLACK-LETTER CAPITAL Z\n212A..212D    ; Not_NFKC                       # 1.1    [4] KELVIN SIGN..BLACK-LETTER CAPITAL C\n212F..2131    ; Not_NFKC                       # 1.1    [3] SCRIPT SMALL E..SCRIPT CAPITAL F\n2133..2138    ; Not_NFKC                       # 1.1    [6] SCRIPT CAPITAL M..DALET SYMBOL\n2139          ; Not_NFKC                       # 3.0        INFORMATION SOURCE\n213B          ; Not_NFKC                       # 4.0        FACSIMILE SIGN\n213C          ; Not_NFKC                       # 4.1        DOUBLE-STRUCK SMALL PI\n213D..2140    ; Not_NFKC                       # 3.2    [4] DOUBLE-STRUCK SMALL GAMMA..DOUBLE-STRUCK N-ARY SUMMATION\n2145..2149    ; Not_NFKC                       # 3.2    [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J\n2150..2152    ; Not_NFKC                       # 5.2    [3] VULGAR FRACTION ONE SEVENTH..VULGAR FRACTION ONE TENTH\n2153..217F    ; Not_NFKC                       # 1.1   [45] VULGAR FRACTION ONE THIRD..SMALL ROMAN NUMERAL ONE THOUSAND\n2189          ; Not_NFKC                       # 5.2        VULGAR FRACTION ZERO THIRDS\n222C..222D    ; Not_NFKC                       # 1.1    [2] DOUBLE INTEGRAL..TRIPLE INTEGRAL\n222F..2230    ; Not_NFKC                       # 1.1    [2] SURFACE INTEGRAL..VOLUME INTEGRAL\n2460..24EA    ; Not_NFKC                       # 1.1  [139] CIRCLED DIGIT ONE..CIRCLED DIGIT ZERO\n2A0C          ; Not_NFKC                       # 3.2        QUADRUPLE INTEGRAL OPERATOR\n2A74..2A76    ; Not_NFKC                       # 3.2    [3] DOUBLE COLON EQUAL..THREE CONSECUTIVE EQUALS SIGNS\n2ADC          ; Not_NFKC                       # 3.2        FORKING\n2C7C..2C7D    ; Not_NFKC                       # 5.1    [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V\n2D6F          ; Not_NFKC                       # 4.1        TIFINAGH MODIFIER LETTER LABIALIZATION MARK\n2E9F          ; Not_NFKC                       # 3.0        CJK RADICAL MOTHER\n2EF3          ; Not_NFKC                       # 3.0        CJK RADICAL C-SIMPLIFIED TURTLE\n2F00..2FD5    ; Not_NFKC                       # 3.0  [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE\n3000          ; Not_NFKC                       # 1.1        IDEOGRAPHIC SPACE\n3036          ; Not_NFKC                       # 1.1        CIRCLED POSTAL MARK\n3038..303A    ; Not_NFKC                       # 3.0    [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY\n309B..309C    ; Not_NFKC                       # 1.1    [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n309F          ; Not_NFKC                       # 3.2        HIRAGANA DIGRAPH YORI\n30FF          ; Not_NFKC                       # 3.2        KATAKANA DIGRAPH KOTO\n3131..3163    ; Not_NFKC                       # 1.1   [51] HANGUL LETTER KIYEOK..HANGUL LETTER I\n3165..318E    ; Not_NFKC                       # 1.1   [42] HANGUL LETTER SSANGNIEUN..HANGUL LETTER ARAEAE\n3192..319F    ; Not_NFKC                       # 1.1   [14] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION MAN MARK\n3200..321C    ; Not_NFKC                       # 1.1   [29] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED HANGUL CIEUC U\n321D..321E    ; Not_NFKC                       # 4.0    [2] PARENTHESIZED KOREAN CHARACTER OJEON..PARENTHESIZED KOREAN CHARACTER O HU\n3220..3243    ; Not_NFKC                       # 1.1   [36] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH REACH\n3244..3247    ; Not_NFKC                       # 5.2    [4] CIRCLED IDEOGRAPH QUESTION..CIRCLED IDEOGRAPH KOTO\n3250          ; Not_NFKC                       # 4.0        PARTNERSHIP SIGN\n3251..325F    ; Not_NFKC                       # 3.2   [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE\n3260..327B    ; Not_NFKC                       # 1.1   [28] CIRCLED HANGUL KIYEOK..CIRCLED HANGUL HIEUH A\n327C..327D    ; Not_NFKC                       # 4.0    [2] CIRCLED KOREAN CHARACTER CHAMKO..CIRCLED KOREAN CHARACTER JUEUI\n327E          ; Not_NFKC                       # 4.1        CIRCLED HANGUL IEUNG U\n3280..32B0    ; Not_NFKC                       # 1.1   [49] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH NIGHT\n32B1..32BF    ; Not_NFKC                       # 3.2   [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY\n32C0..32CB    ; Not_NFKC                       # 1.1   [12] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER\n32CC..32CF    ; Not_NFKC                       # 4.0    [4] SQUARE HG..LIMITED LIABILITY SIGN\n32D0..32FE    ; Not_NFKC                       # 1.1   [47] CIRCLED KATAKANA A..CIRCLED KATAKANA WO\n32FF          ; Not_NFKC                       # 12.1       SQUARE ERA NAME REIWA\n3300..3376    ; Not_NFKC                       # 1.1  [119] SQUARE APAATO..SQUARE PC\n3377..337A    ; Not_NFKC                       # 4.0    [4] SQUARE DM..SQUARE IU\n337B..33DD    ; Not_NFKC                       # 1.1   [99] SQUARE ERA NAME HEISEI..SQUARE WB\n33DE..33DF    ; Not_NFKC                       # 4.0    [2] SQUARE V OVER M..SQUARE A OVER M\n33E0..33FE    ; Not_NFKC                       # 1.1   [31] IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE\n33FF          ; Not_NFKC                       # 4.0        SQUARE GAL\nA69C..A69D    ; Not_NFKC                       # 7.0    [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN\nA770          ; Not_NFKC                       # 5.1        MODIFIER LETTER US\nA7F1          ; Not_NFKC                       # 17.0       MODIFIER LETTER CAPITAL S\nA7F2..A7F4    ; Not_NFKC                       # 14.0   [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q\nA7F8..A7F9    ; Not_NFKC                       # 6.1    [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE\nAB5C..AB5F    ; Not_NFKC                       # 7.0    [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK\nAB69          ; Not_NFKC                       # 13.0       MODIFIER LETTER SMALL TURNED W\nF900..FA0D    ; Not_NFKC                       # 1.1  [270] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA0D\nFA10          ; Not_NFKC                       # 1.1        CJK COMPATIBILITY IDEOGRAPH-FA10\nFA12          ; Not_NFKC                       # 1.1        CJK COMPATIBILITY IDEOGRAPH-FA12\nFA15..FA1E    ; Not_NFKC                       # 1.1   [10] CJK COMPATIBILITY IDEOGRAPH-FA15..CJK COMPATIBILITY IDEOGRAPH-FA1E\nFA20          ; Not_NFKC                       # 1.1        CJK COMPATIBILITY IDEOGRAPH-FA20\nFA22          ; Not_NFKC                       # 1.1        CJK COMPATIBILITY IDEOGRAPH-FA22\nFA25..FA26    ; Not_NFKC                       # 1.1    [2] CJK COMPATIBILITY IDEOGRAPH-FA25..CJK COMPATIBILITY IDEOGRAPH-FA26\nFA2A..FA2D    ; Not_NFKC                       # 1.1    [4] CJK COMPATIBILITY IDEOGRAPH-FA2A..CJK COMPATIBILITY IDEOGRAPH-FA2D\nFA2E..FA2F    ; Not_NFKC                       # 6.1    [2] CJK COMPATIBILITY IDEOGRAPH-FA2E..CJK COMPATIBILITY IDEOGRAPH-FA2F\nFA30..FA6A    ; Not_NFKC                       # 3.2   [59] CJK COMPATIBILITY IDEOGRAPH-FA30..CJK COMPATIBILITY IDEOGRAPH-FA6A\nFA6B..FA6D    ; Not_NFKC                       # 5.2    [3] CJK COMPATIBILITY IDEOGRAPH-FA6B..CJK COMPATIBILITY IDEOGRAPH-FA6D\nFA70..FAD9    ; Not_NFKC                       # 4.1  [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9\nFB00..FB06    ; Not_NFKC                       # 1.1    [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST\nFB13..FB17    ; Not_NFKC                       # 1.1    [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH\nFB1D          ; Not_NFKC                       # 3.0        HEBREW LETTER YOD WITH HIRIQ\nFB1F..FB36    ; Not_NFKC                       # 1.1   [24] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER ZAYIN WITH DAGESH\nFB38..FB3C    ; Not_NFKC                       # 1.1    [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH\nFB3E          ; Not_NFKC                       # 1.1        HEBREW LETTER MEM WITH DAGESH\nFB40..FB41    ; Not_NFKC                       # 1.1    [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH\nFB43..FB44    ; Not_NFKC                       # 1.1    [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH\nFB46..FBB1    ; Not_NFKC                       # 1.1  [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM\nFBD3..FD3D    ; Not_NFKC                       # 1.1  [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM\nFD50..FD8F    ; Not_NFKC                       # 1.1   [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM\nFD92..FDC7    ; Not_NFKC                       # 1.1   [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM\nFDF0..FDFB    ; Not_NFKC                       # 1.1   [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU\nFDFC          ; Not_NFKC                       # 3.2        RIAL SIGN\nFE10..FE19    ; Not_NFKC                       # 4.1   [10] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS\nFE30..FE44    ; Not_NFKC                       # 1.1   [21] PRESENTATION FORM FOR VERTICAL TWO DOT LEADER..PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET\nFE47..FE48    ; Not_NFKC                       # 4.0    [2] PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET..PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET\nFE49..FE52    ; Not_NFKC                       # 1.1   [10] DASHED OVERLINE..SMALL FULL STOP\nFE54..FE66    ; Not_NFKC                       # 1.1   [19] SMALL SEMICOLON..SMALL EQUALS SIGN\nFE68..FE6B    ; Not_NFKC                       # 1.1    [4] SMALL REVERSE SOLIDUS..SMALL COMMERCIAL AT\nFE70..FE72    ; Not_NFKC                       # 1.1    [3] ARABIC FATHATAN ISOLATED FORM..ARABIC DAMMATAN ISOLATED FORM\nFE74          ; Not_NFKC                       # 1.1        ARABIC KASRATAN ISOLATED FORM\nFE76..FEFC    ; Not_NFKC                       # 1.1  [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM\nFF01..FF5E    ; Not_NFKC                       # 1.1   [94] FULLWIDTH EXCLAMATION MARK..FULLWIDTH TILDE\nFF5F..FF60    ; Not_NFKC                       # 3.2    [2] FULLWIDTH LEFT WHITE PARENTHESIS..FULLWIDTH RIGHT WHITE PARENTHESIS\nFF61..FF9F    ; Not_NFKC                       # 1.1   [63] HALFWIDTH IDEOGRAPHIC FULL STOP..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK\nFFA1..FFBE    ; Not_NFKC                       # 1.1   [30] HALFWIDTH HANGUL LETTER KIYEOK..HALFWIDTH HANGUL LETTER HIEUH\nFFC2..FFC7    ; Not_NFKC                       # 1.1    [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E\nFFCA..FFCF    ; Not_NFKC                       # 1.1    [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE\nFFD2..FFD7    ; Not_NFKC                       # 1.1    [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU\nFFDA..FFDC    ; Not_NFKC                       # 1.1    [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I\nFFE0..FFE6    ; Not_NFKC                       # 1.1    [7] FULLWIDTH CENT SIGN..FULLWIDTH WON SIGN\nFFE8..FFEE    ; Not_NFKC                       # 1.1    [7] HALFWIDTH FORMS LIGHT VERTICAL..HALFWIDTH WHITE CIRCLE\n10781..10785  ; Not_NFKC                       # 14.0   [5] MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON..MODIFIER LETTER SMALL B WITH HOOK\n10787..107B0  ; Not_NFKC                       # 14.0  [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK\n107B2..107BA  ; Not_NFKC                       # 14.0   [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL\n1CCD6..1CCF9  ; Not_NFKC                       # 16.0  [36] OUTLINED LATIN CAPITAL LETTER A..OUTLINED DIGIT NINE\n1D15E..1D164  ; Not_NFKC                       # 3.1    [7] MUSICAL SYMBOL HALF NOTE..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE\n1D1BB..1D1C0  ; Not_NFKC                       # 3.1    [6] MUSICAL SYMBOL MINIMA..MUSICAL SYMBOL FUSA BLACK\n1D400..1D454  ; Not_NFKC                       # 3.1   [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G\n1D456..1D49C  ; Not_NFKC                       # 3.1   [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A\n1D49E..1D49F  ; Not_NFKC                       # 3.1    [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D\n1D4A2         ; Not_NFKC                       # 3.1        MATHEMATICAL SCRIPT CAPITAL G\n1D4A5..1D4A6  ; Not_NFKC                       # 3.1    [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K\n1D4A9..1D4AC  ; Not_NFKC                       # 3.1    [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q\n1D4AE..1D4B9  ; Not_NFKC                       # 3.1   [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D\n1D4BB         ; Not_NFKC                       # 3.1        MATHEMATICAL SCRIPT SMALL F\n1D4BD..1D4C0  ; Not_NFKC                       # 3.1    [4] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL K\n1D4C1         ; Not_NFKC                       # 4.0        MATHEMATICAL SCRIPT SMALL L\n1D4C2..1D4C3  ; Not_NFKC                       # 3.1    [2] MATHEMATICAL SCRIPT SMALL M..MATHEMATICAL SCRIPT SMALL N\n1D4C5..1D505  ; Not_NFKC                       # 3.1   [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B\n1D507..1D50A  ; Not_NFKC                       # 3.1    [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G\n1D50D..1D514  ; Not_NFKC                       # 3.1    [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q\n1D516..1D51C  ; Not_NFKC                       # 3.1    [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y\n1D51E..1D539  ; Not_NFKC                       # 3.1   [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B\n1D53B..1D53E  ; Not_NFKC                       # 3.1    [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G\n1D540..1D544  ; Not_NFKC                       # 3.1    [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M\n1D546         ; Not_NFKC                       # 3.1        MATHEMATICAL DOUBLE-STRUCK CAPITAL O\n1D54A..1D550  ; Not_NFKC                       # 3.1    [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y\n1D552..1D6A3  ; Not_NFKC                       # 3.1  [338] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL MONOSPACE SMALL Z\n1D6A4..1D6A5  ; Not_NFKC                       # 4.1    [2] MATHEMATICAL ITALIC SMALL DOTLESS I..MATHEMATICAL ITALIC SMALL DOTLESS J\n1D6A8..1D7C9  ; Not_NFKC                       # 3.1  [290] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL\n1D7CA..1D7CB  ; Not_NFKC                       # 5.0    [2] MATHEMATICAL BOLD CAPITAL DIGAMMA..MATHEMATICAL BOLD SMALL DIGAMMA\n1D7CE..1D7FF  ; Not_NFKC                       # 3.1   [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE\n1E030..1E06D  ; Not_NFKC                       # 15.0  [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE\n1EE00..1EE03  ; Not_NFKC                       # 6.1    [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL\n1EE05..1EE1F  ; Not_NFKC                       # 6.1   [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF\n1EE21..1EE22  ; Not_NFKC                       # 6.1    [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM\n1EE24         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL INITIAL HEH\n1EE27         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL INITIAL HAH\n1EE29..1EE32  ; Not_NFKC                       # 6.1   [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF\n1EE34..1EE37  ; Not_NFKC                       # 6.1    [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH\n1EE39         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL INITIAL DAD\n1EE3B         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL INITIAL GHAIN\n1EE42         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED JEEM\n1EE47         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED HAH\n1EE49         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED YEH\n1EE4B         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED LAM\n1EE4D..1EE4F  ; Not_NFKC                       # 6.1    [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN\n1EE51..1EE52  ; Not_NFKC                       # 6.1    [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF\n1EE54         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED SHEEN\n1EE57         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED KHAH\n1EE59         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED DAD\n1EE5B         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED GHAIN\n1EE5D         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED DOTLESS NOON\n1EE5F         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL TAILED DOTLESS QAF\n1EE61..1EE62  ; Not_NFKC                       # 6.1    [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM\n1EE64         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL STRETCHED HEH\n1EE67..1EE6A  ; Not_NFKC                       # 6.1    [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF\n1EE6C..1EE72  ; Not_NFKC                       # 6.1    [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF\n1EE74..1EE77  ; Not_NFKC                       # 6.1    [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH\n1EE79..1EE7C  ; Not_NFKC                       # 6.1    [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH\n1EE7E         ; Not_NFKC                       # 6.1        ARABIC MATHEMATICAL STRETCHED DOTLESS FEH\n1EE80..1EE89  ; Not_NFKC                       # 6.1   [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH\n1EE8B..1EE9B  ; Not_NFKC                       # 6.1   [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN\n1EEA1..1EEA3  ; Not_NFKC                       # 6.1    [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL\n1EEA5..1EEA9  ; Not_NFKC                       # 6.1    [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH\n1EEAB..1EEBB  ; Not_NFKC                       # 6.1   [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN\n1F100..1F10A  ; Not_NFKC                       # 5.2   [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA\n1F110..1F12E  ; Not_NFKC                       # 5.2   [31] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED WZ\n1F130         ; Not_NFKC                       # 6.0        SQUARED LATIN CAPITAL LETTER A\n1F131         ; Not_NFKC                       # 5.2        SQUARED LATIN CAPITAL LETTER B\n1F132..1F13C  ; Not_NFKC                       # 6.0   [11] SQUARED LATIN CAPITAL LETTER C..SQUARED LATIN CAPITAL LETTER M\n1F13D         ; Not_NFKC                       # 5.2        SQUARED LATIN CAPITAL LETTER N\n1F13E         ; Not_NFKC                       # 6.0        SQUARED LATIN CAPITAL LETTER O\n1F13F         ; Not_NFKC                       # 5.2        SQUARED LATIN CAPITAL LETTER P\n1F140..1F141  ; Not_NFKC                       # 6.0    [2] SQUARED LATIN CAPITAL LETTER Q..SQUARED LATIN CAPITAL LETTER R\n1F142         ; Not_NFKC                       # 5.2        SQUARED LATIN CAPITAL LETTER S\n1F143..1F145  ; Not_NFKC                       # 6.0    [3] SQUARED LATIN CAPITAL LETTER T..SQUARED LATIN CAPITAL LETTER V\n1F146         ; Not_NFKC                       # 5.2        SQUARED LATIN CAPITAL LETTER W\n1F147..1F149  ; Not_NFKC                       # 6.0    [3] SQUARED LATIN CAPITAL LETTER X..SQUARED LATIN CAPITAL LETTER Z\n1F14A..1F14E  ; Not_NFKC                       # 5.2    [5] SQUARED HV..SQUARED PPV\n1F14F         ; Not_NFKC                       # 6.0        SQUARED WC\n1F16A..1F16B  ; Not_NFKC                       # 6.1    [2] RAISED MC SIGN..RAISED MD SIGN\n1F16C         ; Not_NFKC                       # 12.0       RAISED MR SIGN\n1F190         ; Not_NFKC                       # 5.2        SQUARE DJ\n1F200         ; Not_NFKC                       # 5.2        SQUARE HIRAGANA HOKA\n1F201..1F202  ; Not_NFKC                       # 6.0    [2] SQUARED KATAKANA KOKO..SQUARED KATAKANA SA\n1F210..1F231  ; Not_NFKC                       # 5.2   [34] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-6253\n1F232..1F23A  ; Not_NFKC                       # 6.0    [9] SQUARED CJK UNIFIED IDEOGRAPH-7981..SQUARED CJK UNIFIED IDEOGRAPH-55B6\n1F23B         ; Not_NFKC                       # 9.0        SQUARED CJK UNIFIED IDEOGRAPH-914D\n1F240..1F248  ; Not_NFKC                       # 5.2    [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557\n1F250..1F251  ; Not_NFKC                       # 6.0    [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT\n1FBF0..1FBF9  ; Not_NFKC                       # 13.0  [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE\n2F800..2FA1D  ; Not_NFKC                       # 3.1  [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D\n\n# Total code points: 4958\n\n#\tIdentifier_Type:\tDefault_Ignorable\n\n00AD          ; Default_Ignorable              # 1.1        SOFT HYPHEN\n034F          ; Default_Ignorable              # 3.2        COMBINING GRAPHEME JOINER\n061C          ; Default_Ignorable              # 6.3        ARABIC LETTER MARK\n115F..1160    ; Default_Ignorable              # 1.1    [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER\n17B4..17B5    ; Default_Ignorable              # 3.0    [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA\n180B..180D    ; Default_Ignorable              # 3.0    [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE\n180E          ; Default_Ignorable              # 3.0        MONGOLIAN VOWEL SEPARATOR\n180F          ; Default_Ignorable              # 14.0       MONGOLIAN FREE VARIATION SELECTOR FOUR\n200B..200F    ; Default_Ignorable              # 1.1    [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK\n202A..202E    ; Default_Ignorable              # 1.1    [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE\n2060..2063    ; Default_Ignorable              # 3.2    [4] WORD JOINER..INVISIBLE SEPARATOR\n2064          ; Default_Ignorable              # 5.1        INVISIBLE PLUS\n2066..2069    ; Default_Ignorable              # 6.3    [4] LEFT-TO-RIGHT ISOLATE..POP DIRECTIONAL ISOLATE\n3164          ; Default_Ignorable              # 1.1        HANGUL FILLER\nFE00..FE0F    ; Default_Ignorable              # 3.2   [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16\nFEFF          ; Default_Ignorable              # 1.1        ZERO WIDTH NO-BREAK SPACE\nFFA0          ; Default_Ignorable              # 1.1        HALFWIDTH HANGUL FILLER\n1BCA0..1BCA3  ; Default_Ignorable              # 7.0    [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP\n1D173..1D17A  ; Default_Ignorable              # 3.1    [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE\nE0020..E007F  ; Default_Ignorable              # 3.1   [96] TAG SPACE..CANCEL TAG\nE0100..E01EF  ; Default_Ignorable              # 4.0  [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256\n\n# Total code points: 398\n\n#\tIdentifier_Type:\tDeprecated\n\n0149          ; Deprecated                     # 1.1        LATIN SMALL LETTER N PRECEDED BY APOSTROPHE\n0673          ; Deprecated                     # 1.1        ARABIC LETTER ALEF WITH WAVY HAMZA BELOW\n0F77          ; Deprecated                     # 2.0        TIBETAN VOWEL SIGN VOCALIC RR\n0F79          ; Deprecated                     # 2.0        TIBETAN VOWEL SIGN VOCALIC LL\n17A3..17A4    ; Deprecated                     # 3.0    [2] KHMER INDEPENDENT VOWEL QAQ..KHMER INDEPENDENT VOWEL QAA\n206A..206F    ; Deprecated                     # 1.1    [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES\n2329..232A    ; Deprecated                     # 1.1    [2] LEFT-POINTING ANGLE BRACKET..RIGHT-POINTING ANGLE BRACKET\nE0001         ; Deprecated                     # 3.1        LANGUAGE TAG\n\n# Total code points: 15\n"
  },
  {
    "path": "lib/elixir/unicode/PropList.txt",
    "content": "# PropList-17.0.0.txt\n# Date: 2025-06-30, 06:19:01 GMT\n# © 2025 Unicode®, Inc.\n# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.\n# For terms of use and license, see https://www.unicode.org/terms_of_use.html\n#\n# Unicode Character Database\n#   For documentation, see https://www.unicode.org/reports/tr44/\n\n# ================================================\n\n0009..000D    ; White_Space # Cc   [5] <control-0009>..<control-000D>\n0020          ; White_Space # Zs       SPACE\n0085          ; White_Space # Cc       <control-0085>\n00A0          ; White_Space # Zs       NO-BREAK SPACE\n1680          ; White_Space # Zs       OGHAM SPACE MARK\n2000..200A    ; White_Space # Zs  [11] EN QUAD..HAIR SPACE\n2028          ; White_Space # Zl       LINE SEPARATOR\n2029          ; White_Space # Zp       PARAGRAPH SEPARATOR\n202F          ; White_Space # Zs       NARROW NO-BREAK SPACE\n205F          ; White_Space # Zs       MEDIUM MATHEMATICAL SPACE\n3000          ; White_Space # Zs       IDEOGRAPHIC SPACE\n\n# Total code points: 25\n\n# ================================================\n\n061C          ; Bidi_Control # Cf       ARABIC LETTER MARK\n200E..200F    ; Bidi_Control # Cf   [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK\n202A..202E    ; Bidi_Control # Cf   [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE\n2066..2069    ; Bidi_Control # Cf   [4] LEFT-TO-RIGHT ISOLATE..POP DIRECTIONAL ISOLATE\n\n# Total code points: 12\n\n# ================================================\n\n200C..200D    ; Join_Control # Cf   [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER\n\n# Total code points: 2\n\n# ================================================\n\n002D          ; Dash # Pd       HYPHEN-MINUS\n058A          ; Dash # Pd       ARMENIAN HYPHEN\n05BE          ; Dash # Pd       HEBREW PUNCTUATION MAQAF\n1400          ; Dash # Pd       CANADIAN SYLLABICS HYPHEN\n1806          ; Dash # Pd       MONGOLIAN TODO SOFT HYPHEN\n2010..2015    ; Dash # Pd   [6] HYPHEN..HORIZONTAL BAR\n2053          ; Dash # Po       SWUNG DASH\n207B          ; Dash # Sm       SUPERSCRIPT MINUS\n208B          ; Dash # Sm       SUBSCRIPT MINUS\n2212          ; Dash # Sm       MINUS SIGN\n2E17          ; Dash # Pd       DOUBLE OBLIQUE HYPHEN\n2E1A          ; Dash # Pd       HYPHEN WITH DIAERESIS\n2E3A..2E3B    ; Dash # Pd   [2] TWO-EM DASH..THREE-EM DASH\n2E40          ; Dash # Pd       DOUBLE HYPHEN\n2E5D          ; Dash # Pd       OBLIQUE HYPHEN\n301C          ; Dash # Pd       WAVE DASH\n3030          ; Dash # Pd       WAVY DASH\n30A0          ; Dash # Pd       KATAKANA-HIRAGANA DOUBLE HYPHEN\nFE31..FE32    ; Dash # Pd   [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH\nFE58          ; Dash # Pd       SMALL EM DASH\nFE63          ; Dash # Pd       SMALL HYPHEN-MINUS\nFF0D          ; Dash # Pd       FULLWIDTH HYPHEN-MINUS\n10D6E         ; Dash # Pd       GARAY HYPHEN\n10EAD         ; Dash # Pd       YEZIDI HYPHENATION MARK\n\n# Total code points: 31\n\n# ================================================\n\n002D          ; Hyphen # Pd       HYPHEN-MINUS\n00AD          ; Hyphen # Cf       SOFT HYPHEN\n058A          ; Hyphen # Pd       ARMENIAN HYPHEN\n1806          ; Hyphen # Pd       MONGOLIAN TODO SOFT HYPHEN\n2010..2011    ; Hyphen # Pd   [2] HYPHEN..NON-BREAKING HYPHEN\n2E17          ; Hyphen # Pd       DOUBLE OBLIQUE HYPHEN\n30FB          ; Hyphen # Po       KATAKANA MIDDLE DOT\nFE63          ; Hyphen # Pd       SMALL HYPHEN-MINUS\nFF0D          ; Hyphen # Pd       FULLWIDTH HYPHEN-MINUS\nFF65          ; Hyphen # Po       HALFWIDTH KATAKANA MIDDLE DOT\n\n# Total code points: 11\n\n# ================================================\n\n0022          ; Quotation_Mark # Po       QUOTATION MARK\n0027          ; Quotation_Mark # Po       APOSTROPHE\n00AB          ; Quotation_Mark # Pi       LEFT-POINTING DOUBLE ANGLE QUOTATION MARK\n00BB          ; Quotation_Mark # Pf       RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK\n2018          ; Quotation_Mark # Pi       LEFT SINGLE QUOTATION MARK\n2019          ; Quotation_Mark # Pf       RIGHT SINGLE QUOTATION MARK\n201A          ; Quotation_Mark # Ps       SINGLE LOW-9 QUOTATION MARK\n201B..201C    ; Quotation_Mark # Pi   [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK\n201D          ; Quotation_Mark # Pf       RIGHT DOUBLE QUOTATION MARK\n201E          ; Quotation_Mark # Ps       DOUBLE LOW-9 QUOTATION MARK\n201F          ; Quotation_Mark # Pi       DOUBLE HIGH-REVERSED-9 QUOTATION MARK\n2039          ; Quotation_Mark # Pi       SINGLE LEFT-POINTING ANGLE QUOTATION MARK\n203A          ; Quotation_Mark # Pf       SINGLE RIGHT-POINTING ANGLE QUOTATION MARK\n2E42          ; Quotation_Mark # Ps       DOUBLE LOW-REVERSED-9 QUOTATION MARK\n300C          ; Quotation_Mark # Ps       LEFT CORNER BRACKET\n300D          ; Quotation_Mark # Pe       RIGHT CORNER BRACKET\n300E          ; Quotation_Mark # Ps       LEFT WHITE CORNER BRACKET\n300F          ; Quotation_Mark # Pe       RIGHT WHITE CORNER BRACKET\n301D          ; Quotation_Mark # Ps       REVERSED DOUBLE PRIME QUOTATION MARK\n301E..301F    ; Quotation_Mark # Pe   [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK\nFE41          ; Quotation_Mark # Ps       PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET\nFE42          ; Quotation_Mark # Pe       PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET\nFE43          ; Quotation_Mark # Ps       PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET\nFE44          ; Quotation_Mark # Pe       PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET\nFF02          ; Quotation_Mark # Po       FULLWIDTH QUOTATION MARK\nFF07          ; Quotation_Mark # Po       FULLWIDTH APOSTROPHE\nFF62          ; Quotation_Mark # Ps       HALFWIDTH LEFT CORNER BRACKET\nFF63          ; Quotation_Mark # Pe       HALFWIDTH RIGHT CORNER BRACKET\n\n# Total code points: 30\n\n# ================================================\n\n0021          ; Terminal_Punctuation # Po       EXCLAMATION MARK\n002C          ; Terminal_Punctuation # Po       COMMA\n002E          ; Terminal_Punctuation # Po       FULL STOP\n003A..003B    ; Terminal_Punctuation # Po   [2] COLON..SEMICOLON\n003F          ; Terminal_Punctuation # Po       QUESTION MARK\n037E          ; Terminal_Punctuation # Po       GREEK QUESTION MARK\n0387          ; Terminal_Punctuation # Po       GREEK ANO TELEIA\n0589          ; Terminal_Punctuation # Po       ARMENIAN FULL STOP\n05C3          ; Terminal_Punctuation # Po       HEBREW PUNCTUATION SOF PASUQ\n060C          ; Terminal_Punctuation # Po       ARABIC COMMA\n061B          ; Terminal_Punctuation # Po       ARABIC SEMICOLON\n061D..061F    ; Terminal_Punctuation # Po   [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK\n06D4          ; Terminal_Punctuation # Po       ARABIC FULL STOP\n0700..070A    ; Terminal_Punctuation # Po  [11] SYRIAC END OF PARAGRAPH..SYRIAC CONTRACTION\n070C          ; Terminal_Punctuation # Po       SYRIAC HARKLEAN METOBELUS\n07F8..07F9    ; Terminal_Punctuation # Po   [2] NKO COMMA..NKO EXCLAMATION MARK\n0830..0835    ; Terminal_Punctuation # Po   [6] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION SHIYYAALAA\n0837..083E    ; Terminal_Punctuation # Po   [8] SAMARITAN PUNCTUATION MELODIC QITSA..SAMARITAN PUNCTUATION ANNAAU\n085E          ; Terminal_Punctuation # Po       MANDAIC PUNCTUATION\n0964..0965    ; Terminal_Punctuation # Po   [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA\n0E5A..0E5B    ; Terminal_Punctuation # Po   [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT\n0F08          ; Terminal_Punctuation # Po       TIBETAN MARK SBRUL SHAD\n0F0D..0F12    ; Terminal_Punctuation # Po   [6] TIBETAN MARK SHAD..TIBETAN MARK RGYA GRAM SHAD\n104A..104B    ; Terminal_Punctuation # Po   [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION\n1361..1368    ; Terminal_Punctuation # Po   [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR\n166E          ; Terminal_Punctuation # Po       CANADIAN SYLLABICS FULL STOP\n16EB..16ED    ; Terminal_Punctuation # Po   [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION\n1735..1736    ; Terminal_Punctuation # Po   [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION\n17D4..17D6    ; Terminal_Punctuation # Po   [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH\n17DA          ; Terminal_Punctuation # Po       KHMER SIGN KOOMUUT\n1802..1805    ; Terminal_Punctuation # Po   [4] MONGOLIAN COMMA..MONGOLIAN FOUR DOTS\n1808..1809    ; Terminal_Punctuation # Po   [2] MONGOLIAN MANCHU COMMA..MONGOLIAN MANCHU FULL STOP\n1944..1945    ; Terminal_Punctuation # Po   [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK\n1AA8..1AAB    ; Terminal_Punctuation # Po   [4] TAI THAM SIGN KAAN..TAI THAM SIGN SATKAANKUU\n1B4E..1B4F    ; Terminal_Punctuation # Po   [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN\n1B5A..1B5B    ; Terminal_Punctuation # Po   [2] BALINESE PANTI..BALINESE PAMADA\n1B5D..1B5F    ; Terminal_Punctuation # Po   [3] BALINESE CARIK PAMUNGKAH..BALINESE CARIK PAREREN\n1B7D..1B7F    ; Terminal_Punctuation # Po   [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK\n1C3B..1C3F    ; Terminal_Punctuation # Po   [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK\n1C7E..1C7F    ; Terminal_Punctuation # Po   [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD\n2024          ; Terminal_Punctuation # Po       ONE DOT LEADER\n203C..203D    ; Terminal_Punctuation # Po   [2] DOUBLE EXCLAMATION MARK..INTERROBANG\n2047..2049    ; Terminal_Punctuation # Po   [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK\n2CF9..2CFB    ; Terminal_Punctuation # Po   [3] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN INDIRECT QUESTION MARK\n2E2E          ; Terminal_Punctuation # Po       REVERSED QUESTION MARK\n2E3C          ; Terminal_Punctuation # Po       STENOGRAPHIC FULL STOP\n2E41          ; Terminal_Punctuation # Po       REVERSED COMMA\n2E4C          ; Terminal_Punctuation # Po       MEDIEVAL COMMA\n2E4E..2E4F    ; Terminal_Punctuation # Po   [2] PUNCTUS ELEVATUS MARK..CORNISH VERSE DIVIDER\n2E53..2E54    ; Terminal_Punctuation # Po   [2] MEDIEVAL EXCLAMATION MARK..MEDIEVAL QUESTION MARK\n3001..3002    ; Terminal_Punctuation # Po   [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP\nA4FE..A4FF    ; Terminal_Punctuation # Po   [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP\nA60D..A60F    ; Terminal_Punctuation # Po   [3] VAI COMMA..VAI QUESTION MARK\nA6F3..A6F7    ; Terminal_Punctuation # Po   [5] BAMUM FULL STOP..BAMUM QUESTION MARK\nA876..A877    ; Terminal_Punctuation # Po   [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD\nA8CE..A8CF    ; Terminal_Punctuation # Po   [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA\nA92F          ; Terminal_Punctuation # Po       KAYAH LI SIGN SHYA\nA9C7..A9C9    ; Terminal_Punctuation # Po   [3] JAVANESE PADA PANGKAT..JAVANESE PADA LUNGSI\nAA5D..AA5F    ; Terminal_Punctuation # Po   [3] CHAM PUNCTUATION DANDA..CHAM PUNCTUATION TRIPLE DANDA\nAADF          ; Terminal_Punctuation # Po       TAI VIET SYMBOL KOI KOI\nAAF0..AAF1    ; Terminal_Punctuation # Po   [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM\nABEB          ; Terminal_Punctuation # Po       MEETEI MAYEK CHEIKHEI\nFE12          ; Terminal_Punctuation # Po       PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP\nFE15..FE16    ; Terminal_Punctuation # Po   [2] PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK..PRESENTATION FORM FOR VERTICAL QUESTION MARK\nFE50..FE52    ; Terminal_Punctuation # Po   [3] SMALL COMMA..SMALL FULL STOP\nFE54..FE57    ; Terminal_Punctuation # Po   [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK\nFF01          ; Terminal_Punctuation # Po       FULLWIDTH EXCLAMATION MARK\nFF0C          ; Terminal_Punctuation # Po       FULLWIDTH COMMA\nFF0E          ; Terminal_Punctuation # Po       FULLWIDTH FULL STOP\nFF1A..FF1B    ; Terminal_Punctuation # Po   [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON\nFF1F          ; Terminal_Punctuation # Po       FULLWIDTH QUESTION MARK\nFF61          ; Terminal_Punctuation # Po       HALFWIDTH IDEOGRAPHIC FULL STOP\nFF64          ; Terminal_Punctuation # Po       HALFWIDTH IDEOGRAPHIC COMMA\n1039F         ; Terminal_Punctuation # Po       UGARITIC WORD DIVIDER\n103D0         ; Terminal_Punctuation # Po       OLD PERSIAN WORD DIVIDER\n10857         ; Terminal_Punctuation # Po       IMPERIAL ARAMAIC SECTION SIGN\n1091F         ; Terminal_Punctuation # Po       PHOENICIAN WORD SEPARATOR\n10A56..10A57  ; Terminal_Punctuation # Po   [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA\n10AF0..10AF5  ; Terminal_Punctuation # Po   [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS\n10B3A..10B3F  ; Terminal_Punctuation # Po   [6] TINY TWO DOTS OVER ONE DOT PUNCTUATION..LARGE ONE RING OVER TWO RINGS PUNCTUATION\n10B99..10B9C  ; Terminal_Punctuation # Po   [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT\n10F55..10F59  ; Terminal_Punctuation # Po   [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT\n10F86..10F89  ; Terminal_Punctuation # Po   [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS\n11047..1104D  ; Terminal_Punctuation # Po   [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS\n110BE..110C1  ; Terminal_Punctuation # Po   [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA\n11141..11143  ; Terminal_Punctuation # Po   [3] CHAKMA DANDA..CHAKMA QUESTION MARK\n111C5..111C6  ; Terminal_Punctuation # Po   [2] SHARADA DANDA..SHARADA DOUBLE DANDA\n111CD         ; Terminal_Punctuation # Po       SHARADA SUTRA MARK\n111DE..111DF  ; Terminal_Punctuation # Po   [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2\n11238..1123C  ; Terminal_Punctuation # Po   [5] KHOJKI DANDA..KHOJKI DOUBLE SECTION MARK\n112A9         ; Terminal_Punctuation # Po       MULTANI SECTION MARK\n113D4..113D5  ; Terminal_Punctuation # Po   [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA\n1144B..1144D  ; Terminal_Punctuation # Po   [3] NEWA DANDA..NEWA COMMA\n1145A..1145B  ; Terminal_Punctuation # Po   [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK\n115C2..115C5  ; Terminal_Punctuation # Po   [4] SIDDHAM DANDA..SIDDHAM SEPARATOR BAR\n115C9..115D7  ; Terminal_Punctuation # Po  [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES\n11641..11642  ; Terminal_Punctuation # Po   [2] MODI DANDA..MODI DOUBLE DANDA\n1173C..1173E  ; Terminal_Punctuation # Po   [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI\n11944         ; Terminal_Punctuation # Po       DIVES AKURU DOUBLE DANDA\n11946         ; Terminal_Punctuation # Po       DIVES AKURU END OF TEXT MARK\n11A42..11A43  ; Terminal_Punctuation # Po   [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD\n11A9B..11A9C  ; Terminal_Punctuation # Po   [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD\n11AA1..11AA2  ; Terminal_Punctuation # Po   [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2\n11C41..11C43  ; Terminal_Punctuation # Po   [3] BHAIKSUKI DANDA..BHAIKSUKI WORD SEPARATOR\n11C71         ; Terminal_Punctuation # Po       MARCHEN MARK SHAD\n11EF7..11EF8  ; Terminal_Punctuation # Po   [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION\n11F43..11F44  ; Terminal_Punctuation # Po   [2] KAWI DANDA..KAWI DOUBLE DANDA\n12470..12474  ; Terminal_Punctuation # Po   [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON\n16A6E..16A6F  ; Terminal_Punctuation # Po   [2] MRO DANDA..MRO DOUBLE DANDA\n16AF5         ; Terminal_Punctuation # Po       BASSA VAH FULL STOP\n16B37..16B39  ; Terminal_Punctuation # Po   [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM\n16B44         ; Terminal_Punctuation # Po       PAHAWH HMONG SIGN XAUS\n16D6E..16D6F  ; Terminal_Punctuation # Po   [2] KIRAT RAI DANDA..KIRAT RAI DOUBLE DANDA\n16E97..16E98  ; Terminal_Punctuation # Po   [2] MEDEFAIDRIN COMMA..MEDEFAIDRIN FULL STOP\n1BC9F         ; Terminal_Punctuation # Po       DUPLOYAN PUNCTUATION CHINOOK FULL STOP\n1DA87..1DA8A  ; Terminal_Punctuation # Po   [4] SIGNWRITING COMMA..SIGNWRITING COLON\n\n# Total code points: 291\n\n# ================================================\n\n005E          ; Other_Math # Sk       CIRCUMFLEX ACCENT\n03D0..03D2    ; Other_Math # L&   [3] GREEK BETA SYMBOL..GREEK UPSILON WITH HOOK SYMBOL\n03D5          ; Other_Math # L&       GREEK PHI SYMBOL\n03F0..03F1    ; Other_Math # L&   [2] GREEK KAPPA SYMBOL..GREEK RHO SYMBOL\n03F4..03F5    ; Other_Math # L&   [2] GREEK CAPITAL THETA SYMBOL..GREEK LUNATE EPSILON SYMBOL\n2016          ; Other_Math # Po       DOUBLE VERTICAL LINE\n2032..2034    ; Other_Math # Po   [3] PRIME..TRIPLE PRIME\n2040          ; Other_Math # Pc       CHARACTER TIE\n2061..2064    ; Other_Math # Cf   [4] FUNCTION APPLICATION..INVISIBLE PLUS\n207D          ; Other_Math # Ps       SUPERSCRIPT LEFT PARENTHESIS\n207E          ; Other_Math # Pe       SUPERSCRIPT RIGHT PARENTHESIS\n208D          ; Other_Math # Ps       SUBSCRIPT LEFT PARENTHESIS\n208E          ; Other_Math # Pe       SUBSCRIPT RIGHT PARENTHESIS\n20D0..20DC    ; Other_Math # Mn  [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE\n20E1          ; Other_Math # Mn       COMBINING LEFT RIGHT ARROW ABOVE\n20E5..20E6    ; Other_Math # Mn   [2] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING DOUBLE VERTICAL STROKE OVERLAY\n20EB..20EF    ; Other_Math # Mn   [5] COMBINING LONG DOUBLE SOLIDUS OVERLAY..COMBINING RIGHT ARROW BELOW\n2102          ; Other_Math # L&       DOUBLE-STRUCK CAPITAL C\n2107          ; Other_Math # L&       EULER CONSTANT\n210A..2113    ; Other_Math # L&  [10] SCRIPT SMALL G..SCRIPT SMALL L\n2115          ; Other_Math # L&       DOUBLE-STRUCK CAPITAL N\n2119..211D    ; Other_Math # L&   [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R\n2124          ; Other_Math # L&       DOUBLE-STRUCK CAPITAL Z\n2128          ; Other_Math # L&       BLACK-LETTER CAPITAL Z\n2129          ; Other_Math # So       TURNED GREEK SMALL LETTER IOTA\n212C..212D    ; Other_Math # L&   [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C\n212F..2131    ; Other_Math # L&   [3] SCRIPT SMALL E..SCRIPT CAPITAL F\n2133..2134    ; Other_Math # L&   [2] SCRIPT CAPITAL M..SCRIPT SMALL O\n2135..2138    ; Other_Math # Lo   [4] ALEF SYMBOL..DALET SYMBOL\n213C..213F    ; Other_Math # L&   [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI\n2145..2149    ; Other_Math # L&   [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J\n2195..2199    ; Other_Math # So   [5] UP DOWN ARROW..SOUTH WEST ARROW\n219C..219F    ; Other_Math # So   [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW\n21A1..21A2    ; Other_Math # So   [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL\n21A4..21A5    ; Other_Math # So   [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR\n21A7          ; Other_Math # So       DOWNWARDS ARROW FROM BAR\n21A9..21AD    ; Other_Math # So   [5] LEFTWARDS ARROW WITH HOOK..LEFT RIGHT WAVE ARROW\n21B0..21B1    ; Other_Math # So   [2] UPWARDS ARROW WITH TIP LEFTWARDS..UPWARDS ARROW WITH TIP RIGHTWARDS\n21B6..21B7    ; Other_Math # So   [2] ANTICLOCKWISE TOP SEMICIRCLE ARROW..CLOCKWISE TOP SEMICIRCLE ARROW\n21BC..21CD    ; Other_Math # So  [18] LEFTWARDS HARPOON WITH BARB UPWARDS..LEFTWARDS DOUBLE ARROW WITH STROKE\n21D0..21D1    ; Other_Math # So   [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW\n21D3          ; Other_Math # So       DOWNWARDS DOUBLE ARROW\n21D5..21DB    ; Other_Math # So   [7] UP DOWN DOUBLE ARROW..RIGHTWARDS TRIPLE ARROW\n21DD          ; Other_Math # So       RIGHTWARDS SQUIGGLE ARROW\n21E4..21E5    ; Other_Math # So   [2] LEFTWARDS ARROW TO BAR..RIGHTWARDS ARROW TO BAR\n2308          ; Other_Math # Ps       LEFT CEILING\n2309          ; Other_Math # Pe       RIGHT CEILING\n230A          ; Other_Math # Ps       LEFT FLOOR\n230B          ; Other_Math # Pe       RIGHT FLOOR\n23B4..23B5    ; Other_Math # So   [2] TOP SQUARE BRACKET..BOTTOM SQUARE BRACKET\n23B7          ; Other_Math # So       RADICAL SYMBOL BOTTOM\n23D0          ; Other_Math # So       VERTICAL LINE EXTENSION\n23E2          ; Other_Math # So       WHITE TRAPEZIUM\n25A0..25A1    ; Other_Math # So   [2] BLACK SQUARE..WHITE SQUARE\n25AE..25B6    ; Other_Math # So   [9] BLACK VERTICAL RECTANGLE..BLACK RIGHT-POINTING TRIANGLE\n25BC..25C0    ; Other_Math # So   [5] BLACK DOWN-POINTING TRIANGLE..BLACK LEFT-POINTING TRIANGLE\n25C6..25C7    ; Other_Math # So   [2] BLACK DIAMOND..WHITE DIAMOND\n25CA..25CB    ; Other_Math # So   [2] LOZENGE..WHITE CIRCLE\n25CF..25D3    ; Other_Math # So   [5] BLACK CIRCLE..CIRCLE WITH UPPER HALF BLACK\n25E2          ; Other_Math # So       BLACK LOWER RIGHT TRIANGLE\n25E4          ; Other_Math # So       BLACK UPPER LEFT TRIANGLE\n25E7..25EC    ; Other_Math # So   [6] SQUARE WITH LEFT HALF BLACK..WHITE UP-POINTING TRIANGLE WITH DOT\n2605..2606    ; Other_Math # So   [2] BLACK STAR..WHITE STAR\n2640          ; Other_Math # So       FEMALE SIGN\n2642          ; Other_Math # So       MALE SIGN\n2660..2663    ; Other_Math # So   [4] BLACK SPADE SUIT..BLACK CLUB SUIT\n266D..266E    ; Other_Math # So   [2] MUSIC FLAT SIGN..MUSIC NATURAL SIGN\n27C5          ; Other_Math # Ps       LEFT S-SHAPED BAG DELIMITER\n27C6          ; Other_Math # Pe       RIGHT S-SHAPED BAG DELIMITER\n27E6          ; Other_Math # Ps       MATHEMATICAL LEFT WHITE SQUARE BRACKET\n27E7          ; Other_Math # Pe       MATHEMATICAL RIGHT WHITE SQUARE BRACKET\n27E8          ; Other_Math # Ps       MATHEMATICAL LEFT ANGLE BRACKET\n27E9          ; Other_Math # Pe       MATHEMATICAL RIGHT ANGLE BRACKET\n27EA          ; Other_Math # Ps       MATHEMATICAL LEFT DOUBLE ANGLE BRACKET\n27EB          ; Other_Math # Pe       MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET\n27EC          ; Other_Math # Ps       MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET\n27ED          ; Other_Math # Pe       MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET\n27EE          ; Other_Math # Ps       MATHEMATICAL LEFT FLATTENED PARENTHESIS\n27EF          ; Other_Math # Pe       MATHEMATICAL RIGHT FLATTENED PARENTHESIS\n2983          ; Other_Math # Ps       LEFT WHITE CURLY BRACKET\n2984          ; Other_Math # Pe       RIGHT WHITE CURLY BRACKET\n2985          ; Other_Math # Ps       LEFT WHITE PARENTHESIS\n2986          ; Other_Math # Pe       RIGHT WHITE PARENTHESIS\n2987          ; Other_Math # Ps       Z NOTATION LEFT IMAGE BRACKET\n2988          ; Other_Math # Pe       Z NOTATION RIGHT IMAGE BRACKET\n2989          ; Other_Math # Ps       Z NOTATION LEFT BINDING BRACKET\n298A          ; Other_Math # Pe       Z NOTATION RIGHT BINDING BRACKET\n298B          ; Other_Math # Ps       LEFT SQUARE BRACKET WITH UNDERBAR\n298C          ; Other_Math # Pe       RIGHT SQUARE BRACKET WITH UNDERBAR\n298D          ; Other_Math # Ps       LEFT SQUARE BRACKET WITH TICK IN TOP CORNER\n298E          ; Other_Math # Pe       RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER\n298F          ; Other_Math # Ps       LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER\n2990          ; Other_Math # Pe       RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER\n2991          ; Other_Math # Ps       LEFT ANGLE BRACKET WITH DOT\n2992          ; Other_Math # Pe       RIGHT ANGLE BRACKET WITH DOT\n2993          ; Other_Math # Ps       LEFT ARC LESS-THAN BRACKET\n2994          ; Other_Math # Pe       RIGHT ARC GREATER-THAN BRACKET\n2995          ; Other_Math # Ps       DOUBLE LEFT ARC GREATER-THAN BRACKET\n2996          ; Other_Math # Pe       DOUBLE RIGHT ARC LESS-THAN BRACKET\n2997          ; Other_Math # Ps       LEFT BLACK TORTOISE SHELL BRACKET\n2998          ; Other_Math # Pe       RIGHT BLACK TORTOISE SHELL BRACKET\n29D8          ; Other_Math # Ps       LEFT WIGGLY FENCE\n29D9          ; Other_Math # Pe       RIGHT WIGGLY FENCE\n29DA          ; Other_Math # Ps       LEFT DOUBLE WIGGLY FENCE\n29DB          ; Other_Math # Pe       RIGHT DOUBLE WIGGLY FENCE\n29FC          ; Other_Math # Ps       LEFT-POINTING CURVED ANGLE BRACKET\n29FD          ; Other_Math # Pe       RIGHT-POINTING CURVED ANGLE BRACKET\nFE61          ; Other_Math # Po       SMALL ASTERISK\nFE63          ; Other_Math # Pd       SMALL HYPHEN-MINUS\nFE68          ; Other_Math # Po       SMALL REVERSE SOLIDUS\nFF3C          ; Other_Math # Po       FULLWIDTH REVERSE SOLIDUS\nFF3E          ; Other_Math # Sk       FULLWIDTH CIRCUMFLEX ACCENT\n1D400..1D454  ; Other_Math # L&  [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G\n1D456..1D49C  ; Other_Math # L&  [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A\n1D49E..1D49F  ; Other_Math # L&   [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D\n1D4A2         ; Other_Math # L&       MATHEMATICAL SCRIPT CAPITAL G\n1D4A5..1D4A6  ; Other_Math # L&   [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K\n1D4A9..1D4AC  ; Other_Math # L&   [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q\n1D4AE..1D4B9  ; Other_Math # L&  [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D\n1D4BB         ; Other_Math # L&       MATHEMATICAL SCRIPT SMALL F\n1D4BD..1D4C3  ; Other_Math # L&   [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N\n1D4C5..1D505  ; Other_Math # L&  [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B\n1D507..1D50A  ; Other_Math # L&   [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G\n1D50D..1D514  ; Other_Math # L&   [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q\n1D516..1D51C  ; Other_Math # L&   [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y\n1D51E..1D539  ; Other_Math # L&  [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B\n1D53B..1D53E  ; Other_Math # L&   [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G\n1D540..1D544  ; Other_Math # L&   [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M\n1D546         ; Other_Math # L&       MATHEMATICAL DOUBLE-STRUCK CAPITAL O\n1D54A..1D550  ; Other_Math # L&   [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y\n1D552..1D6A5  ; Other_Math # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J\n1D6A8..1D6C0  ; Other_Math # L&  [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA\n1D6C2..1D6DA  ; Other_Math # L&  [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA\n1D6DC..1D6FA  ; Other_Math # L&  [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA\n1D6FC..1D714  ; Other_Math # L&  [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA\n1D716..1D734  ; Other_Math # L&  [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA\n1D736..1D74E  ; Other_Math # L&  [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA\n1D750..1D76E  ; Other_Math # L&  [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA\n1D770..1D788  ; Other_Math # L&  [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA\n1D78A..1D7A8  ; Other_Math # L&  [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA\n1D7AA..1D7C2  ; Other_Math # L&  [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA\n1D7C4..1D7CB  ; Other_Math # L&   [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA\n1D7CE..1D7FF  ; Other_Math # Nd  [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE\n1EE00..1EE03  ; Other_Math # Lo   [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL\n1EE05..1EE1F  ; Other_Math # Lo  [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF\n1EE21..1EE22  ; Other_Math # Lo   [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM\n1EE24         ; Other_Math # Lo       ARABIC MATHEMATICAL INITIAL HEH\n1EE27         ; Other_Math # Lo       ARABIC MATHEMATICAL INITIAL HAH\n1EE29..1EE32  ; Other_Math # Lo  [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF\n1EE34..1EE37  ; Other_Math # Lo   [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH\n1EE39         ; Other_Math # Lo       ARABIC MATHEMATICAL INITIAL DAD\n1EE3B         ; Other_Math # Lo       ARABIC MATHEMATICAL INITIAL GHAIN\n1EE42         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED JEEM\n1EE47         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED HAH\n1EE49         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED YEH\n1EE4B         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED LAM\n1EE4D..1EE4F  ; Other_Math # Lo   [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN\n1EE51..1EE52  ; Other_Math # Lo   [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF\n1EE54         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED SHEEN\n1EE57         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED KHAH\n1EE59         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED DAD\n1EE5B         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED GHAIN\n1EE5D         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED DOTLESS NOON\n1EE5F         ; Other_Math # Lo       ARABIC MATHEMATICAL TAILED DOTLESS QAF\n1EE61..1EE62  ; Other_Math # Lo   [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM\n1EE64         ; Other_Math # Lo       ARABIC MATHEMATICAL STRETCHED HEH\n1EE67..1EE6A  ; Other_Math # Lo   [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF\n1EE6C..1EE72  ; Other_Math # Lo   [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF\n1EE74..1EE77  ; Other_Math # Lo   [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH\n1EE79..1EE7C  ; Other_Math # Lo   [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH\n1EE7E         ; Other_Math # Lo       ARABIC MATHEMATICAL STRETCHED DOTLESS FEH\n1EE80..1EE89  ; Other_Math # Lo  [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH\n1EE8B..1EE9B  ; Other_Math # Lo  [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN\n1EEA1..1EEA3  ; Other_Math # Lo   [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL\n1EEA5..1EEA9  ; Other_Math # Lo   [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH\n1EEAB..1EEBB  ; Other_Math # Lo  [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN\n\n# Total code points: 1362\n\n# ================================================\n\n0030..0039    ; Hex_Digit # Nd  [10] DIGIT ZERO..DIGIT NINE\n0041..0046    ; Hex_Digit # L&   [6] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER F\n0061..0066    ; Hex_Digit # L&   [6] LATIN SMALL LETTER A..LATIN SMALL LETTER F\nFF10..FF19    ; Hex_Digit # Nd  [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE\nFF21..FF26    ; Hex_Digit # L&   [6] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER F\nFF41..FF46    ; Hex_Digit # L&   [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER F\n\n# Total code points: 44\n\n# ================================================\n\n0030..0039    ; ASCII_Hex_Digit # Nd  [10] DIGIT ZERO..DIGIT NINE\n0041..0046    ; ASCII_Hex_Digit # L&   [6] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER F\n0061..0066    ; ASCII_Hex_Digit # L&   [6] LATIN SMALL LETTER A..LATIN SMALL LETTER F\n\n# Total code points: 22\n\n# ================================================\n\n0345          ; Other_Alphabetic # Mn       COMBINING GREEK YPOGEGRAMMENI\n0363..036F    ; Other_Alphabetic # Mn  [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X\n05B0..05BD    ; Other_Alphabetic # Mn  [14] HEBREW POINT SHEVA..HEBREW POINT METEG\n05BF          ; Other_Alphabetic # Mn       HEBREW POINT RAFE\n05C1..05C2    ; Other_Alphabetic # Mn   [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT\n05C4..05C5    ; Other_Alphabetic # Mn   [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT\n05C7          ; Other_Alphabetic # Mn       HEBREW POINT QAMATS QATAN\n0610..061A    ; Other_Alphabetic # Mn  [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA\n064B..0657    ; Other_Alphabetic # Mn  [13] ARABIC FATHATAN..ARABIC INVERTED DAMMA\n0659..065F    ; Other_Alphabetic # Mn   [7] ARABIC ZWARAKAY..ARABIC WAVY HAMZA BELOW\n0670          ; Other_Alphabetic # Mn       ARABIC LETTER SUPERSCRIPT ALEF\n06D6..06DC    ; Other_Alphabetic # Mn   [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN\n06E1..06E4    ; Other_Alphabetic # Mn   [4] ARABIC SMALL HIGH DOTLESS HEAD OF KHAH..ARABIC SMALL HIGH MADDA\n06E7..06E8    ; Other_Alphabetic # Mn   [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON\n06ED          ; Other_Alphabetic # Mn       ARABIC SMALL LOW MEEM\n0711          ; Other_Alphabetic # Mn       SYRIAC LETTER SUPERSCRIPT ALAPH\n0730..073F    ; Other_Alphabetic # Mn  [16] SYRIAC PTHAHA ABOVE..SYRIAC RWAHA\n07A6..07B0    ; Other_Alphabetic # Mn  [11] THAANA ABAFILI..THAANA SUKUN\n0816..0817    ; Other_Alphabetic # Mn   [2] SAMARITAN MARK IN..SAMARITAN MARK IN-ALAF\n081B..0823    ; Other_Alphabetic # Mn   [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A\n0825..0827    ; Other_Alphabetic # Mn   [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U\n0829..082C    ; Other_Alphabetic # Mn   [4] SAMARITAN VOWEL SIGN LONG I..SAMARITAN VOWEL SIGN SUKUN\n0897          ; Other_Alphabetic # Mn       ARABIC PEPET\n08D4..08DF    ; Other_Alphabetic # Mn  [12] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH WORD WAQFA\n08E3..08E9    ; Other_Alphabetic # Mn   [7] ARABIC TURNED DAMMA BELOW..ARABIC CURLY KASRATAN\n08F0..0902    ; Other_Alphabetic # Mn  [19] ARABIC OPEN FATHATAN..DEVANAGARI SIGN ANUSVARA\n0903          ; Other_Alphabetic # Mc       DEVANAGARI SIGN VISARGA\n093A          ; Other_Alphabetic # Mn       DEVANAGARI VOWEL SIGN OE\n093B          ; Other_Alphabetic # Mc       DEVANAGARI VOWEL SIGN OOE\n093E..0940    ; Other_Alphabetic # Mc   [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II\n0941..0948    ; Other_Alphabetic # Mn   [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI\n0949..094C    ; Other_Alphabetic # Mc   [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU\n094E..094F    ; Other_Alphabetic # Mc   [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW\n0955..0957    ; Other_Alphabetic # Mn   [3] DEVANAGARI VOWEL SIGN CANDRA LONG E..DEVANAGARI VOWEL SIGN UUE\n0962..0963    ; Other_Alphabetic # Mn   [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL\n0981          ; Other_Alphabetic # Mn       BENGALI SIGN CANDRABINDU\n0982..0983    ; Other_Alphabetic # Mc   [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA\n09BE..09C0    ; Other_Alphabetic # Mc   [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II\n09C1..09C4    ; Other_Alphabetic # Mn   [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR\n09C7..09C8    ; Other_Alphabetic # Mc   [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI\n09CB..09CC    ; Other_Alphabetic # Mc   [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU\n09D7          ; Other_Alphabetic # Mc       BENGALI AU LENGTH MARK\n09E2..09E3    ; Other_Alphabetic # Mn   [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL\n0A01..0A02    ; Other_Alphabetic # Mn   [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI\n0A03          ; Other_Alphabetic # Mc       GURMUKHI SIGN VISARGA\n0A3E..0A40    ; Other_Alphabetic # Mc   [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II\n0A41..0A42    ; Other_Alphabetic # Mn   [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU\n0A47..0A48    ; Other_Alphabetic # Mn   [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI\n0A4B..0A4C    ; Other_Alphabetic # Mn   [2] GURMUKHI VOWEL SIGN OO..GURMUKHI VOWEL SIGN AU\n0A51          ; Other_Alphabetic # Mn       GURMUKHI SIGN UDAAT\n0A70..0A71    ; Other_Alphabetic # Mn   [2] GURMUKHI TIPPI..GURMUKHI ADDAK\n0A75          ; Other_Alphabetic # Mn       GURMUKHI SIGN YAKASH\n0A81..0A82    ; Other_Alphabetic # Mn   [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA\n0A83          ; Other_Alphabetic # Mc       GUJARATI SIGN VISARGA\n0ABE..0AC0    ; Other_Alphabetic # Mc   [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II\n0AC1..0AC5    ; Other_Alphabetic # Mn   [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E\n0AC7..0AC8    ; Other_Alphabetic # Mn   [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI\n0AC9          ; Other_Alphabetic # Mc       GUJARATI VOWEL SIGN CANDRA O\n0ACB..0ACC    ; Other_Alphabetic # Mc   [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU\n0AE2..0AE3    ; Other_Alphabetic # Mn   [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL\n0AFA..0AFC    ; Other_Alphabetic # Mn   [3] GUJARATI SIGN SUKUN..GUJARATI SIGN MADDAH\n0B01          ; Other_Alphabetic # Mn       ORIYA SIGN CANDRABINDU\n0B02..0B03    ; Other_Alphabetic # Mc   [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA\n0B3E          ; Other_Alphabetic # Mc       ORIYA VOWEL SIGN AA\n0B3F          ; Other_Alphabetic # Mn       ORIYA VOWEL SIGN I\n0B40          ; Other_Alphabetic # Mc       ORIYA VOWEL SIGN II\n0B41..0B44    ; Other_Alphabetic # Mn   [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR\n0B47..0B48    ; Other_Alphabetic # Mc   [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI\n0B4B..0B4C    ; Other_Alphabetic # Mc   [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU\n0B56          ; Other_Alphabetic # Mn       ORIYA AI LENGTH MARK\n0B57          ; Other_Alphabetic # Mc       ORIYA AU LENGTH MARK\n0B62..0B63    ; Other_Alphabetic # Mn   [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL\n0B82          ; Other_Alphabetic # Mn       TAMIL SIGN ANUSVARA\n0BBE..0BBF    ; Other_Alphabetic # Mc   [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I\n0BC0          ; Other_Alphabetic # Mn       TAMIL VOWEL SIGN II\n0BC1..0BC2    ; Other_Alphabetic # Mc   [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU\n0BC6..0BC8    ; Other_Alphabetic # Mc   [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI\n0BCA..0BCC    ; Other_Alphabetic # Mc   [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU\n0BD7          ; Other_Alphabetic # Mc       TAMIL AU LENGTH MARK\n0C00          ; Other_Alphabetic # Mn       TELUGU SIGN COMBINING CANDRABINDU ABOVE\n0C01..0C03    ; Other_Alphabetic # Mc   [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA\n0C04          ; Other_Alphabetic # Mn       TELUGU SIGN COMBINING ANUSVARA ABOVE\n0C3E..0C40    ; Other_Alphabetic # Mn   [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II\n0C41..0C44    ; Other_Alphabetic # Mc   [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR\n0C46..0C48    ; Other_Alphabetic # Mn   [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI\n0C4A..0C4C    ; Other_Alphabetic # Mn   [3] TELUGU VOWEL SIGN O..TELUGU VOWEL SIGN AU\n0C55..0C56    ; Other_Alphabetic # Mn   [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK\n0C62..0C63    ; Other_Alphabetic # Mn   [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL\n0C81          ; Other_Alphabetic # Mn       KANNADA SIGN CANDRABINDU\n0C82..0C83    ; Other_Alphabetic # Mc   [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA\n0CBE          ; Other_Alphabetic # Mc       KANNADA VOWEL SIGN AA\n0CBF          ; Other_Alphabetic # Mn       KANNADA VOWEL SIGN I\n0CC0..0CC4    ; Other_Alphabetic # Mc   [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR\n0CC6          ; Other_Alphabetic # Mn       KANNADA VOWEL SIGN E\n0CC7..0CC8    ; Other_Alphabetic # Mc   [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI\n0CCA..0CCB    ; Other_Alphabetic # Mc   [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO\n0CCC          ; Other_Alphabetic # Mn       KANNADA VOWEL SIGN AU\n0CD5..0CD6    ; Other_Alphabetic # Mc   [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK\n0CE2..0CE3    ; Other_Alphabetic # Mn   [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL\n0CF3          ; Other_Alphabetic # Mc       KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT\n0D00..0D01    ; Other_Alphabetic # Mn   [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU\n0D02..0D03    ; Other_Alphabetic # Mc   [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA\n0D3E..0D40    ; Other_Alphabetic # Mc   [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II\n0D41..0D44    ; Other_Alphabetic # Mn   [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR\n0D46..0D48    ; Other_Alphabetic # Mc   [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI\n0D4A..0D4C    ; Other_Alphabetic # Mc   [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU\n0D57          ; Other_Alphabetic # Mc       MALAYALAM AU LENGTH MARK\n0D62..0D63    ; Other_Alphabetic # Mn   [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL\n0D81          ; Other_Alphabetic # Mn       SINHALA SIGN CANDRABINDU\n0D82..0D83    ; Other_Alphabetic # Mc   [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA\n0DCF..0DD1    ; Other_Alphabetic # Mc   [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA\n0DD2..0DD4    ; Other_Alphabetic # Mn   [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA\n0DD6          ; Other_Alphabetic # Mn       SINHALA VOWEL SIGN DIGA PAA-PILLA\n0DD8..0DDF    ; Other_Alphabetic # Mc   [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA\n0DF2..0DF3    ; Other_Alphabetic # Mc   [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA\n0E31          ; Other_Alphabetic # Mn       THAI CHARACTER MAI HAN-AKAT\n0E34..0E3A    ; Other_Alphabetic # Mn   [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU\n0E4D          ; Other_Alphabetic # Mn       THAI CHARACTER NIKHAHIT\n0EB1          ; Other_Alphabetic # Mn       LAO VOWEL SIGN MAI KAN\n0EB4..0EB9    ; Other_Alphabetic # Mn   [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU\n0EBB..0EBC    ; Other_Alphabetic # Mn   [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO\n0ECD          ; Other_Alphabetic # Mn       LAO NIGGAHITA\n0F71..0F7E    ; Other_Alphabetic # Mn  [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO\n0F7F          ; Other_Alphabetic # Mc       TIBETAN SIGN RNAM BCAD\n0F80..0F83    ; Other_Alphabetic # Mn   [4] TIBETAN VOWEL SIGN REVERSED I..TIBETAN SIGN SNA LDAN\n0F8D..0F97    ; Other_Alphabetic # Mn  [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA\n0F99..0FBC    ; Other_Alphabetic # Mn  [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA\n102B..102C    ; Other_Alphabetic # Mc   [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA\n102D..1030    ; Other_Alphabetic # Mn   [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU\n1031          ; Other_Alphabetic # Mc       MYANMAR VOWEL SIGN E\n1032..1036    ; Other_Alphabetic # Mn   [5] MYANMAR VOWEL SIGN AI..MYANMAR SIGN ANUSVARA\n1038          ; Other_Alphabetic # Mc       MYANMAR SIGN VISARGA\n103B..103C    ; Other_Alphabetic # Mc   [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA\n103D..103E    ; Other_Alphabetic # Mn   [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA\n1056..1057    ; Other_Alphabetic # Mc   [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR\n1058..1059    ; Other_Alphabetic # Mn   [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL\n105E..1060    ; Other_Alphabetic # Mn   [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA\n1062..1064    ; Other_Alphabetic # Mc   [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO\n1067..106D    ; Other_Alphabetic # Mc   [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5\n1071..1074    ; Other_Alphabetic # Mn   [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE\n1082          ; Other_Alphabetic # Mn       MYANMAR CONSONANT SIGN SHAN MEDIAL WA\n1083..1084    ; Other_Alphabetic # Mc   [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E\n1085..1086    ; Other_Alphabetic # Mn   [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y\n1087..108C    ; Other_Alphabetic # Mc   [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3\n108D          ; Other_Alphabetic # Mn       MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE\n108F          ; Other_Alphabetic # Mc       MYANMAR SIGN RUMAI PALAUNG TONE-5\n109A..109C    ; Other_Alphabetic # Mc   [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A\n109D          ; Other_Alphabetic # Mn       MYANMAR VOWEL SIGN AITON AI\n1712..1713    ; Other_Alphabetic # Mn   [2] TAGALOG VOWEL SIGN I..TAGALOG VOWEL SIGN U\n1732..1733    ; Other_Alphabetic # Mn   [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U\n1752..1753    ; Other_Alphabetic # Mn   [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U\n1772..1773    ; Other_Alphabetic # Mn   [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U\n17B6          ; Other_Alphabetic # Mc       KHMER VOWEL SIGN AA\n17B7..17BD    ; Other_Alphabetic # Mn   [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA\n17BE..17C5    ; Other_Alphabetic # Mc   [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU\n17C6          ; Other_Alphabetic # Mn       KHMER SIGN NIKAHIT\n17C7..17C8    ; Other_Alphabetic # Mc   [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU\n1885..1886    ; Other_Alphabetic # Mn   [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA\n18A9          ; Other_Alphabetic # Mn       MONGOLIAN LETTER ALI GALI DAGALGA\n1920..1922    ; Other_Alphabetic # Mn   [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U\n1923..1926    ; Other_Alphabetic # Mc   [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU\n1927..1928    ; Other_Alphabetic # Mn   [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O\n1929..192B    ; Other_Alphabetic # Mc   [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA\n1930..1931    ; Other_Alphabetic # Mc   [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA\n1932          ; Other_Alphabetic # Mn       LIMBU SMALL LETTER ANUSVARA\n1933..1938    ; Other_Alphabetic # Mc   [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA\n1A17..1A18    ; Other_Alphabetic # Mn   [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U\n1A19..1A1A    ; Other_Alphabetic # Mc   [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O\n1A1B          ; Other_Alphabetic # Mn       BUGINESE VOWEL SIGN AE\n1A55          ; Other_Alphabetic # Mc       TAI THAM CONSONANT SIGN MEDIAL RA\n1A56          ; Other_Alphabetic # Mn       TAI THAM CONSONANT SIGN MEDIAL LA\n1A57          ; Other_Alphabetic # Mc       TAI THAM CONSONANT SIGN LA TANG LAI\n1A58..1A5E    ; Other_Alphabetic # Mn   [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA\n1A61          ; Other_Alphabetic # Mc       TAI THAM VOWEL SIGN A\n1A62          ; Other_Alphabetic # Mn       TAI THAM VOWEL SIGN MAI SAT\n1A63..1A64    ; Other_Alphabetic # Mc   [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA\n1A65..1A6C    ; Other_Alphabetic # Mn   [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW\n1A6D..1A72    ; Other_Alphabetic # Mc   [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI\n1A73..1A74    ; Other_Alphabetic # Mn   [2] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN MAI KANG\n1ABF..1AC0    ; Other_Alphabetic # Mn   [2] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER TURNED W BELOW\n1ACC..1ACE    ; Other_Alphabetic # Mn   [3] COMBINING LATIN SMALL LETTER INSULAR G..COMBINING LATIN SMALL LETTER INSULAR T\n1B00..1B03    ; Other_Alphabetic # Mn   [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG\n1B04          ; Other_Alphabetic # Mc       BALINESE SIGN BISAH\n1B35          ; Other_Alphabetic # Mc       BALINESE VOWEL SIGN TEDUNG\n1B36..1B3A    ; Other_Alphabetic # Mn   [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA\n1B3B          ; Other_Alphabetic # Mc       BALINESE VOWEL SIGN RA REPA TEDUNG\n1B3C          ; Other_Alphabetic # Mn       BALINESE VOWEL SIGN LA LENGA\n1B3D..1B41    ; Other_Alphabetic # Mc   [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG\n1B42          ; Other_Alphabetic # Mn       BALINESE VOWEL SIGN PEPET\n1B43          ; Other_Alphabetic # Mc       BALINESE VOWEL SIGN PEPET TEDUNG\n1B80..1B81    ; Other_Alphabetic # Mn   [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR\n1B82          ; Other_Alphabetic # Mc       SUNDANESE SIGN PANGWISAD\n1BA1          ; Other_Alphabetic # Mc       SUNDANESE CONSONANT SIGN PAMINGKAL\n1BA2..1BA5    ; Other_Alphabetic # Mn   [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU\n1BA6..1BA7    ; Other_Alphabetic # Mc   [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG\n1BA8..1BA9    ; Other_Alphabetic # Mn   [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG\n1BAC..1BAD    ; Other_Alphabetic # Mn   [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA\n1BE7          ; Other_Alphabetic # Mc       BATAK VOWEL SIGN E\n1BE8..1BE9    ; Other_Alphabetic # Mn   [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE\n1BEA..1BEC    ; Other_Alphabetic # Mc   [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O\n1BED          ; Other_Alphabetic # Mn       BATAK VOWEL SIGN KARO O\n1BEE          ; Other_Alphabetic # Mc       BATAK VOWEL SIGN U\n1BEF..1BF1    ; Other_Alphabetic # Mn   [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H\n1C24..1C2B    ; Other_Alphabetic # Mc   [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU\n1C2C..1C33    ; Other_Alphabetic # Mn   [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T\n1C34..1C35    ; Other_Alphabetic # Mc   [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG\n1C36          ; Other_Alphabetic # Mn       LEPCHA SIGN RAN\n1DD3..1DF4    ; Other_Alphabetic # Mn  [34] COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE..COMBINING LATIN SMALL LETTER U WITH DIAERESIS\n24B6..24E9    ; Other_Alphabetic # So  [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z\n2DE0..2DFF    ; Other_Alphabetic # Mn  [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS\nA674..A67B    ; Other_Alphabetic # Mn   [8] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA\nA69E..A69F    ; Other_Alphabetic # Mn   [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E\nA802          ; Other_Alphabetic # Mn       SYLOTI NAGRI SIGN DVISVARA\nA80B          ; Other_Alphabetic # Mn       SYLOTI NAGRI SIGN ANUSVARA\nA823..A824    ; Other_Alphabetic # Mc   [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I\nA825..A826    ; Other_Alphabetic # Mn   [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E\nA827          ; Other_Alphabetic # Mc       SYLOTI NAGRI VOWEL SIGN OO\nA880..A881    ; Other_Alphabetic # Mc   [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA\nA8B4..A8C3    ; Other_Alphabetic # Mc  [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU\nA8C5          ; Other_Alphabetic # Mn       SAURASHTRA SIGN CANDRABINDU\nA8FF          ; Other_Alphabetic # Mn       DEVANAGARI VOWEL SIGN AY\nA926..A92A    ; Other_Alphabetic # Mn   [5] KAYAH LI VOWEL UE..KAYAH LI VOWEL O\nA947..A951    ; Other_Alphabetic # Mn  [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R\nA952          ; Other_Alphabetic # Mc       REJANG CONSONANT SIGN H\nA980..A982    ; Other_Alphabetic # Mn   [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR\nA983          ; Other_Alphabetic # Mc       JAVANESE SIGN WIGNYAN\nA9B4..A9B5    ; Other_Alphabetic # Mc   [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG\nA9B6..A9B9    ; Other_Alphabetic # Mn   [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT\nA9BA..A9BB    ; Other_Alphabetic # Mc   [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE\nA9BC..A9BD    ; Other_Alphabetic # Mn   [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET\nA9BE..A9BF    ; Other_Alphabetic # Mc   [2] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE CONSONANT SIGN CAKRA\nA9E5          ; Other_Alphabetic # Mn       MYANMAR SIGN SHAN SAW\nAA29..AA2E    ; Other_Alphabetic # Mn   [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE\nAA2F..AA30    ; Other_Alphabetic # Mc   [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI\nAA31..AA32    ; Other_Alphabetic # Mn   [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE\nAA33..AA34    ; Other_Alphabetic # Mc   [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA\nAA35..AA36    ; Other_Alphabetic # Mn   [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA\nAA43          ; Other_Alphabetic # Mn       CHAM CONSONANT SIGN FINAL NG\nAA4C          ; Other_Alphabetic # Mn       CHAM CONSONANT SIGN FINAL M\nAA4D          ; Other_Alphabetic # Mc       CHAM CONSONANT SIGN FINAL H\nAA7B          ; Other_Alphabetic # Mc       MYANMAR SIGN PAO KAREN TONE\nAA7C          ; Other_Alphabetic # Mn       MYANMAR SIGN TAI LAING TONE-2\nAA7D          ; Other_Alphabetic # Mc       MYANMAR SIGN TAI LAING TONE-5\nAAB0          ; Other_Alphabetic # Mn       TAI VIET MAI KANG\nAAB2..AAB4    ; Other_Alphabetic # Mn   [3] TAI VIET VOWEL I..TAI VIET VOWEL U\nAAB7..AAB8    ; Other_Alphabetic # Mn   [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA\nAABE          ; Other_Alphabetic # Mn       TAI VIET VOWEL AM\nAAEB          ; Other_Alphabetic # Mc       MEETEI MAYEK VOWEL SIGN II\nAAEC..AAED    ; Other_Alphabetic # Mn   [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI\nAAEE..AAEF    ; Other_Alphabetic # Mc   [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU\nAAF5          ; Other_Alphabetic # Mc       MEETEI MAYEK VOWEL SIGN VISARGA\nABE3..ABE4    ; Other_Alphabetic # Mc   [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP\nABE5          ; Other_Alphabetic # Mn       MEETEI MAYEK VOWEL SIGN ANAP\nABE6..ABE7    ; Other_Alphabetic # Mc   [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP\nABE8          ; Other_Alphabetic # Mn       MEETEI MAYEK VOWEL SIGN UNAP\nABE9..ABEA    ; Other_Alphabetic # Mc   [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG\nFB1E          ; Other_Alphabetic # Mn       HEBREW POINT JUDEO-SPANISH VARIKA\n10376..1037A  ; Other_Alphabetic # Mn   [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII\n10A01..10A03  ; Other_Alphabetic # Mn   [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R\n10A05..10A06  ; Other_Alphabetic # Mn   [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O\n10A0C..10A0F  ; Other_Alphabetic # Mn   [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA\n10D24..10D27  ; Other_Alphabetic # Mn   [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI\n10D69         ; Other_Alphabetic # Mn       GARAY VOWEL SIGN E\n10EAB..10EAC  ; Other_Alphabetic # Mn   [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK\n10EFA..10EFC  ; Other_Alphabetic # Mn   [3] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC COMBINING ALEF OVERLAY\n11000         ; Other_Alphabetic # Mc       BRAHMI SIGN CANDRABINDU\n11001         ; Other_Alphabetic # Mn       BRAHMI SIGN ANUSVARA\n11002         ; Other_Alphabetic # Mc       BRAHMI SIGN VISARGA\n11038..11045  ; Other_Alphabetic # Mn  [14] BRAHMI VOWEL SIGN AA..BRAHMI VOWEL SIGN AU\n11073..11074  ; Other_Alphabetic # Mn   [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O\n11080..11081  ; Other_Alphabetic # Mn   [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA\n11082         ; Other_Alphabetic # Mc       KAITHI SIGN VISARGA\n110B0..110B2  ; Other_Alphabetic # Mc   [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II\n110B3..110B6  ; Other_Alphabetic # Mn   [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI\n110B7..110B8  ; Other_Alphabetic # Mc   [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU\n110C2         ; Other_Alphabetic # Mn       KAITHI VOWEL SIGN VOCALIC R\n11100..11102  ; Other_Alphabetic # Mn   [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA\n11127..1112B  ; Other_Alphabetic # Mn   [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU\n1112C         ; Other_Alphabetic # Mc       CHAKMA VOWEL SIGN E\n1112D..11132  ; Other_Alphabetic # Mn   [6] CHAKMA VOWEL SIGN AI..CHAKMA AU MARK\n11145..11146  ; Other_Alphabetic # Mc   [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI\n11180..11181  ; Other_Alphabetic # Mn   [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA\n11182         ; Other_Alphabetic # Mc       SHARADA SIGN VISARGA\n111B3..111B5  ; Other_Alphabetic # Mc   [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II\n111B6..111BE  ; Other_Alphabetic # Mn   [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O\n111BF         ; Other_Alphabetic # Mc       SHARADA VOWEL SIGN AU\n111CE         ; Other_Alphabetic # Mc       SHARADA VOWEL SIGN PRISHTHAMATRA E\n111CF         ; Other_Alphabetic # Mn       SHARADA SIGN INVERTED CANDRABINDU\n1122C..1122E  ; Other_Alphabetic # Mc   [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II\n1122F..11231  ; Other_Alphabetic # Mn   [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI\n11232..11233  ; Other_Alphabetic # Mc   [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU\n11234         ; Other_Alphabetic # Mn       KHOJKI SIGN ANUSVARA\n11237         ; Other_Alphabetic # Mn       KHOJKI SIGN SHADDA\n1123E         ; Other_Alphabetic # Mn       KHOJKI SIGN SUKUN\n11241         ; Other_Alphabetic # Mn       KHOJKI VOWEL SIGN VOCALIC R\n112DF         ; Other_Alphabetic # Mn       KHUDAWADI SIGN ANUSVARA\n112E0..112E2  ; Other_Alphabetic # Mc   [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II\n112E3..112E8  ; Other_Alphabetic # Mn   [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU\n11300..11301  ; Other_Alphabetic # Mn   [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU\n11302..11303  ; Other_Alphabetic # Mc   [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA\n1133E..1133F  ; Other_Alphabetic # Mc   [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I\n11340         ; Other_Alphabetic # Mn       GRANTHA VOWEL SIGN II\n11341..11344  ; Other_Alphabetic # Mc   [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR\n11347..11348  ; Other_Alphabetic # Mc   [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI\n1134B..1134C  ; Other_Alphabetic # Mc   [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU\n11357         ; Other_Alphabetic # Mc       GRANTHA AU LENGTH MARK\n11362..11363  ; Other_Alphabetic # Mc   [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL\n113B8..113BA  ; Other_Alphabetic # Mc   [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II\n113BB..113C0  ; Other_Alphabetic # Mn   [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL\n113C2         ; Other_Alphabetic # Mc       TULU-TIGALARI VOWEL SIGN EE\n113C5         ; Other_Alphabetic # Mc       TULU-TIGALARI VOWEL SIGN AI\n113C7..113CA  ; Other_Alphabetic # Mc   [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA\n113CC..113CD  ; Other_Alphabetic # Mc   [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA\n11435..11437  ; Other_Alphabetic # Mc   [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II\n11438..1143F  ; Other_Alphabetic # Mn   [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI\n11440..11441  ; Other_Alphabetic # Mc   [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU\n11443..11444  ; Other_Alphabetic # Mn   [2] NEWA SIGN CANDRABINDU..NEWA SIGN ANUSVARA\n11445         ; Other_Alphabetic # Mc       NEWA SIGN VISARGA\n114B0..114B2  ; Other_Alphabetic # Mc   [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II\n114B3..114B8  ; Other_Alphabetic # Mn   [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL\n114B9         ; Other_Alphabetic # Mc       TIRHUTA VOWEL SIGN E\n114BA         ; Other_Alphabetic # Mn       TIRHUTA VOWEL SIGN SHORT E\n114BB..114BE  ; Other_Alphabetic # Mc   [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU\n114BF..114C0  ; Other_Alphabetic # Mn   [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA\n114C1         ; Other_Alphabetic # Mc       TIRHUTA SIGN VISARGA\n115AF..115B1  ; Other_Alphabetic # Mc   [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II\n115B2..115B5  ; Other_Alphabetic # Mn   [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR\n115B8..115BB  ; Other_Alphabetic # Mc   [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU\n115BC..115BD  ; Other_Alphabetic # Mn   [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA\n115BE         ; Other_Alphabetic # Mc       SIDDHAM SIGN VISARGA\n115DC..115DD  ; Other_Alphabetic # Mn   [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU\n11630..11632  ; Other_Alphabetic # Mc   [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II\n11633..1163A  ; Other_Alphabetic # Mn   [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI\n1163B..1163C  ; Other_Alphabetic # Mc   [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU\n1163D         ; Other_Alphabetic # Mn       MODI SIGN ANUSVARA\n1163E         ; Other_Alphabetic # Mc       MODI SIGN VISARGA\n11640         ; Other_Alphabetic # Mn       MODI SIGN ARDHACANDRA\n116AB         ; Other_Alphabetic # Mn       TAKRI SIGN ANUSVARA\n116AC         ; Other_Alphabetic # Mc       TAKRI SIGN VISARGA\n116AD         ; Other_Alphabetic # Mn       TAKRI VOWEL SIGN AA\n116AE..116AF  ; Other_Alphabetic # Mc   [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II\n116B0..116B5  ; Other_Alphabetic # Mn   [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU\n1171D         ; Other_Alphabetic # Mn       AHOM CONSONANT SIGN MEDIAL LA\n1171E         ; Other_Alphabetic # Mc       AHOM CONSONANT SIGN MEDIAL RA\n1171F         ; Other_Alphabetic # Mn       AHOM CONSONANT SIGN MEDIAL LIGATING RA\n11720..11721  ; Other_Alphabetic # Mc   [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA\n11722..11725  ; Other_Alphabetic # Mn   [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU\n11726         ; Other_Alphabetic # Mc       AHOM VOWEL SIGN E\n11727..1172A  ; Other_Alphabetic # Mn   [4] AHOM VOWEL SIGN AW..AHOM VOWEL SIGN AM\n1182C..1182E  ; Other_Alphabetic # Mc   [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II\n1182F..11837  ; Other_Alphabetic # Mn   [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA\n11838         ; Other_Alphabetic # Mc       DOGRA SIGN VISARGA\n11930..11935  ; Other_Alphabetic # Mc   [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E\n11937..11938  ; Other_Alphabetic # Mc   [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O\n1193B..1193C  ; Other_Alphabetic # Mn   [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU\n11940         ; Other_Alphabetic # Mc       DIVES AKURU MEDIAL YA\n11942         ; Other_Alphabetic # Mc       DIVES AKURU MEDIAL RA\n119D1..119D3  ; Other_Alphabetic # Mc   [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II\n119D4..119D7  ; Other_Alphabetic # Mn   [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR\n119DA..119DB  ; Other_Alphabetic # Mn   [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI\n119DC..119DF  ; Other_Alphabetic # Mc   [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA\n119E4         ; Other_Alphabetic # Mc       NANDINAGARI VOWEL SIGN PRISHTHAMATRA E\n11A01..11A0A  ; Other_Alphabetic # Mn  [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK\n11A35..11A38  ; Other_Alphabetic # Mn   [4] ZANABAZAR SQUARE SIGN CANDRABINDU..ZANABAZAR SQUARE SIGN ANUSVARA\n11A39         ; Other_Alphabetic # Mc       ZANABAZAR SQUARE SIGN VISARGA\n11A3B..11A3E  ; Other_Alphabetic # Mn   [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA\n11A51..11A56  ; Other_Alphabetic # Mn   [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE\n11A57..11A58  ; Other_Alphabetic # Mc   [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU\n11A59..11A5B  ; Other_Alphabetic # Mn   [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK\n11A8A..11A96  ; Other_Alphabetic # Mn  [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA\n11A97         ; Other_Alphabetic # Mc       SOYOMBO SIGN VISARGA\n11B60         ; Other_Alphabetic # Mn       SHARADA VOWEL SIGN OE\n11B61         ; Other_Alphabetic # Mc       SHARADA VOWEL SIGN OOE\n11B62..11B64  ; Other_Alphabetic # Mn   [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E\n11B65         ; Other_Alphabetic # Mc       SHARADA VOWEL SIGN SHORT O\n11B66         ; Other_Alphabetic # Mn       SHARADA VOWEL SIGN CANDRA E\n11B67         ; Other_Alphabetic # Mc       SHARADA VOWEL SIGN CANDRA O\n11C2F         ; Other_Alphabetic # Mc       BHAIKSUKI VOWEL SIGN AA\n11C30..11C36  ; Other_Alphabetic # Mn   [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L\n11C38..11C3D  ; Other_Alphabetic # Mn   [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA\n11C3E         ; Other_Alphabetic # Mc       BHAIKSUKI SIGN VISARGA\n11C92..11CA7  ; Other_Alphabetic # Mn  [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA\n11CA9         ; Other_Alphabetic # Mc       MARCHEN SUBJOINED LETTER YA\n11CAA..11CB0  ; Other_Alphabetic # Mn   [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA\n11CB1         ; Other_Alphabetic # Mc       MARCHEN VOWEL SIGN I\n11CB2..11CB3  ; Other_Alphabetic # Mn   [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E\n11CB4         ; Other_Alphabetic # Mc       MARCHEN VOWEL SIGN O\n11CB5..11CB6  ; Other_Alphabetic # Mn   [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU\n11D31..11D36  ; Other_Alphabetic # Mn   [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R\n11D3A         ; Other_Alphabetic # Mn       MASARAM GONDI VOWEL SIGN E\n11D3C..11D3D  ; Other_Alphabetic # Mn   [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O\n11D3F..11D41  ; Other_Alphabetic # Mn   [3] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI SIGN VISARGA\n11D43         ; Other_Alphabetic # Mn       MASARAM GONDI SIGN CANDRA\n11D47         ; Other_Alphabetic # Mn       MASARAM GONDI RA-KARA\n11D8A..11D8E  ; Other_Alphabetic # Mc   [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU\n11D90..11D91  ; Other_Alphabetic # Mn   [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI\n11D93..11D94  ; Other_Alphabetic # Mc   [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU\n11D95         ; Other_Alphabetic # Mn       GUNJALA GONDI SIGN ANUSVARA\n11D96         ; Other_Alphabetic # Mc       GUNJALA GONDI SIGN VISARGA\n11EF3..11EF4  ; Other_Alphabetic # Mn   [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U\n11EF5..11EF6  ; Other_Alphabetic # Mc   [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O\n11F00..11F01  ; Other_Alphabetic # Mn   [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA\n11F03         ; Other_Alphabetic # Mc       KAWI SIGN VISARGA\n11F34..11F35  ; Other_Alphabetic # Mc   [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA\n11F36..11F3A  ; Other_Alphabetic # Mn   [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R\n11F3E..11F3F  ; Other_Alphabetic # Mc   [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI\n11F40         ; Other_Alphabetic # Mn       KAWI VOWEL SIGN EU\n1611E..16129  ; Other_Alphabetic # Mn  [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK\n1612A..1612C  ; Other_Alphabetic # Mc   [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA\n1612D..1612E  ; Other_Alphabetic # Mn   [2] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA CONSONANT SIGN MEDIAL RA\n16F4F         ; Other_Alphabetic # Mn       MIAO SIGN CONSONANT MODIFIER BAR\n16F51..16F87  ; Other_Alphabetic # Mc  [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI\n16F8F..16F92  ; Other_Alphabetic # Mn   [4] MIAO TONE RIGHT..MIAO TONE BELOW\n16FF0..16FF1  ; Other_Alphabetic # Mc   [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY\n1BC9E         ; Other_Alphabetic # Mn       DUPLOYAN DOUBLE MARK\n1E000..1E006  ; Other_Alphabetic # Mn   [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE\n1E008..1E018  ; Other_Alphabetic # Mn  [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU\n1E01B..1E021  ; Other_Alphabetic # Mn   [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI\n1E023..1E024  ; Other_Alphabetic # Mn   [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS\n1E026..1E02A  ; Other_Alphabetic # Mn   [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA\n1E08F         ; Other_Alphabetic # Mn       COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I\n1E6E3         ; Other_Alphabetic # Mn       TAI YO SIGN UE\n1E6E6         ; Other_Alphabetic # Mn       TAI YO SIGN AU\n1E6EE..1E6EF  ; Other_Alphabetic # Mn   [2] TAI YO SIGN AY..TAI YO SIGN ANG\n1E6F5         ; Other_Alphabetic # Mn       TAI YO SIGN OM\n1E947         ; Other_Alphabetic # Mn       ADLAM HAMZA\n1F130..1F149  ; Other_Alphabetic # So  [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z\n1F150..1F169  ; Other_Alphabetic # So  [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z\n1F170..1F189  ; Other_Alphabetic # So  [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z\n\n# Total code points: 1510\n\n# ================================================\n\n3006          ; Ideographic # Lo       IDEOGRAPHIC CLOSING MARK\n3007          ; Ideographic # Nl       IDEOGRAPHIC NUMBER ZERO\n3021..3029    ; Ideographic # Nl   [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE\n3038..303A    ; Ideographic # Nl   [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY\n3400..4DBF    ; Ideographic # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF\n4E00..9FFF    ; Ideographic # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF\nF900..FA6D    ; Ideographic # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D\nFA70..FAD9    ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9\n16FE4         ; Ideographic # Mn       KHITAN SMALL SCRIPT FILLER\n16FF2..16FF3  ; Ideographic # Lm   [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER\n16FF4..16FF6  ; Ideographic # Nl   [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS\n17000..18CD5  ; Ideographic # Lo [7382] TANGUT IDEOGRAPH-17000..KHITAN SMALL SCRIPT CHARACTER-18CD5\n18CFF..18D1E  ; Ideographic # Lo  [32] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D1E\n18D80..18DF2  ; Ideographic # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883\n1B170..1B2FB  ; Ideographic # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB\n20000..2A6DF  ; Ideographic # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF\n2A700..2B81D  ; Ideographic # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D\n2B820..2CEAD  ; Ideographic # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD\n2CEB0..2EBE0  ; Ideographic # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0\n2EBF0..2EE5D  ; Ideographic # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D\n2F800..2FA1D  ; Ideographic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D\n30000..3134A  ; Ideographic # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A\n31350..33479  ; Ideographic # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479\n\n# Total code points: 110943\n\n# ================================================\n\n005E          ; Diacritic # Sk       CIRCUMFLEX ACCENT\n0060          ; Diacritic # Sk       GRAVE ACCENT\n00A8          ; Diacritic # Sk       DIAERESIS\n00AF          ; Diacritic # Sk       MACRON\n00B4          ; Diacritic # Sk       ACUTE ACCENT\n00B7          ; Diacritic # Po       MIDDLE DOT\n00B8          ; Diacritic # Sk       CEDILLA\n02B0..02C1    ; Diacritic # Lm  [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP\n02C2..02C5    ; Diacritic # Sk   [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD\n02C6..02D1    ; Diacritic # Lm  [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON\n02D2..02DF    ; Diacritic # Sk  [14] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER CROSS ACCENT\n02E0..02E4    ; Diacritic # Lm   [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP\n02E5..02EB    ; Diacritic # Sk   [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK\n02EC          ; Diacritic # Lm       MODIFIER LETTER VOICING\n02ED          ; Diacritic # Sk       MODIFIER LETTER UNASPIRATED\n02EE          ; Diacritic # Lm       MODIFIER LETTER DOUBLE APOSTROPHE\n02EF..02FF    ; Diacritic # Sk  [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW\n0300..034E    ; Diacritic # Mn  [79] COMBINING GRAVE ACCENT..COMBINING UPWARDS ARROW BELOW\n0350..0357    ; Diacritic # Mn   [8] COMBINING RIGHT ARROWHEAD ABOVE..COMBINING RIGHT HALF RING ABOVE\n035D..0362    ; Diacritic # Mn   [6] COMBINING DOUBLE BREVE..COMBINING DOUBLE RIGHTWARDS ARROW BELOW\n0374          ; Diacritic # Lm       GREEK NUMERAL SIGN\n0375          ; Diacritic # Sk       GREEK LOWER NUMERAL SIGN\n037A          ; Diacritic # Lm       GREEK YPOGEGRAMMENI\n0384..0385    ; Diacritic # Sk   [2] GREEK TONOS..GREEK DIALYTIKA TONOS\n0483..0487    ; Diacritic # Mn   [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE\n0559          ; Diacritic # Lm       ARMENIAN MODIFIER LETTER LEFT HALF RING\n0591..05BD    ; Diacritic # Mn  [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG\n05BF          ; Diacritic # Mn       HEBREW POINT RAFE\n05C1..05C2    ; Diacritic # Mn   [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT\n05C4..05C5    ; Diacritic # Mn   [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT\n05C7          ; Diacritic # Mn       HEBREW POINT QAMATS QATAN\n064B..0652    ; Diacritic # Mn   [8] ARABIC FATHATAN..ARABIC SUKUN\n0657..0658    ; Diacritic # Mn   [2] ARABIC INVERTED DAMMA..ARABIC MARK NOON GHUNNA\n06DF..06E0    ; Diacritic # Mn   [2] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO\n06E5..06E6    ; Diacritic # Lm   [2] ARABIC SMALL WAW..ARABIC SMALL YEH\n06EA..06EC    ; Diacritic # Mn   [3] ARABIC EMPTY CENTRE LOW STOP..ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE\n0730..074A    ; Diacritic # Mn  [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH\n07A6..07B0    ; Diacritic # Mn  [11] THAANA ABAFILI..THAANA SUKUN\n07EB..07F3    ; Diacritic # Mn   [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE\n07F4..07F5    ; Diacritic # Lm   [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE\n0818..0819    ; Diacritic # Mn   [2] SAMARITAN MARK OCCLUSION..SAMARITAN MARK DAGESH\n0898..089F    ; Diacritic # Mn   [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA\n08C9          ; Diacritic # Lm       ARABIC SMALL FARSI YEH\n08CA..08D2    ; Diacritic # Mn   [9] ARABIC SMALL HIGH FARSI YEH..ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW\n08E3..08FE    ; Diacritic # Mn  [28] ARABIC TURNED DAMMA BELOW..ARABIC DAMMA WITH DOT\n093C          ; Diacritic # Mn       DEVANAGARI SIGN NUKTA\n094D          ; Diacritic # Mn       DEVANAGARI SIGN VIRAMA\n0951..0954    ; Diacritic # Mn   [4] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT\n0971          ; Diacritic # Lm       DEVANAGARI SIGN HIGH SPACING DOT\n09BC          ; Diacritic # Mn       BENGALI SIGN NUKTA\n09CD          ; Diacritic # Mn       BENGALI SIGN VIRAMA\n0A3C          ; Diacritic # Mn       GURMUKHI SIGN NUKTA\n0A4D          ; Diacritic # Mn       GURMUKHI SIGN VIRAMA\n0ABC          ; Diacritic # Mn       GUJARATI SIGN NUKTA\n0ACD          ; Diacritic # Mn       GUJARATI SIGN VIRAMA\n0AFD..0AFF    ; Diacritic # Mn   [3] GUJARATI SIGN THREE-DOT NUKTA ABOVE..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE\n0B3C          ; Diacritic # Mn       ORIYA SIGN NUKTA\n0B4D          ; Diacritic # Mn       ORIYA SIGN VIRAMA\n0B55          ; Diacritic # Mn       ORIYA SIGN OVERLINE\n0BCD          ; Diacritic # Mn       TAMIL SIGN VIRAMA\n0C3C          ; Diacritic # Mn       TELUGU SIGN NUKTA\n0C4D          ; Diacritic # Mn       TELUGU SIGN VIRAMA\n0CBC          ; Diacritic # Mn       KANNADA SIGN NUKTA\n0CCD          ; Diacritic # Mn       KANNADA SIGN VIRAMA\n0D3B..0D3C    ; Diacritic # Mn   [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA\n0D4D          ; Diacritic # Mn       MALAYALAM SIGN VIRAMA\n0DCA          ; Diacritic # Mn       SINHALA SIGN AL-LAKUNA\n0E3A          ; Diacritic # Mn       THAI CHARACTER PHINTHU\n0E47..0E4C    ; Diacritic # Mn   [6] THAI CHARACTER MAITAIKHU..THAI CHARACTER THANTHAKHAT\n0E4E          ; Diacritic # Mn       THAI CHARACTER YAMAKKAN\n0EBA          ; Diacritic # Mn       LAO SIGN PALI VIRAMA\n0EC8..0ECC    ; Diacritic # Mn   [5] LAO TONE MAI EK..LAO CANCELLATION MARK\n0F18..0F19    ; Diacritic # Mn   [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS\n0F35          ; Diacritic # Mn       TIBETAN MARK NGAS BZUNG NYI ZLA\n0F37          ; Diacritic # Mn       TIBETAN MARK NGAS BZUNG SGOR RTAGS\n0F39          ; Diacritic # Mn       TIBETAN MARK TSA -PHRU\n0F3E..0F3F    ; Diacritic # Mc   [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES\n0F82..0F84    ; Diacritic # Mn   [3] TIBETAN SIGN NYI ZLA NAA DA..TIBETAN MARK HALANTA\n0F86..0F87    ; Diacritic # Mn   [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS\n0FC6          ; Diacritic # Mn       TIBETAN SYMBOL PADMA GDAN\n1037          ; Diacritic # Mn       MYANMAR SIGN DOT BELOW\n1039..103A    ; Diacritic # Mn   [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT\n1063..1064    ; Diacritic # Mc   [2] MYANMAR TONE MARK SGAW KAREN HATHI..MYANMAR TONE MARK SGAW KAREN KE PHO\n1069..106D    ; Diacritic # Mc   [5] MYANMAR SIGN WESTERN PWO KAREN TONE-1..MYANMAR SIGN WESTERN PWO KAREN TONE-5\n1087..108C    ; Diacritic # Mc   [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3\n108D          ; Diacritic # Mn       MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE\n108F          ; Diacritic # Mc       MYANMAR SIGN RUMAI PALAUNG TONE-5\n109A..109B    ; Diacritic # Mc   [2] MYANMAR SIGN KHAMTI TONE-1..MYANMAR SIGN KHAMTI TONE-3\n135D..135F    ; Diacritic # Mn   [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK\n1714          ; Diacritic # Mn       TAGALOG SIGN VIRAMA\n1715          ; Diacritic # Mc       TAGALOG SIGN PAMUDPOD\n1734          ; Diacritic # Mc       HANUNOO SIGN PAMUDPOD\n17C9..17D3    ; Diacritic # Mn  [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT\n17DD          ; Diacritic # Mn       KHMER SIGN ATTHACAN\n1939..193B    ; Diacritic # Mn   [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I\n1A60          ; Diacritic # Mn       TAI THAM SIGN SAKOT\n1A75..1A7C    ; Diacritic # Mn   [8] TAI THAM SIGN TONE-1..TAI THAM SIGN KHUEN-LUE KARAN\n1A7F          ; Diacritic # Mn       TAI THAM COMBINING CRYPTOGRAMMIC DOT\n1AB0..1ABD    ; Diacritic # Mn  [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW\n1ABE          ; Diacritic # Me       COMBINING PARENTHESES OVERLAY\n1AC1..1ACB    ; Diacritic # Mn  [11] COMBINING LEFT PARENTHESIS ABOVE LEFT..COMBINING TRIPLE ACUTE ACCENT\n1ACF..1ADD    ; Diacritic # Mn  [15] COMBINING DOUBLE CARON..COMBINING DOT-AND-RING BELOW\n1AE0..1AEB    ; Diacritic # Mn  [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE\n1B34          ; Diacritic # Mn       BALINESE SIGN REREKAN\n1B44          ; Diacritic # Mc       BALINESE ADEG ADEG\n1B6B..1B73    ; Diacritic # Mn   [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG\n1BAA          ; Diacritic # Mc       SUNDANESE SIGN PAMAAEH\n1BAB          ; Diacritic # Mn       SUNDANESE SIGN VIRAMA\n1BE6          ; Diacritic # Mn       BATAK SIGN TOMPI\n1BF2..1BF3    ; Diacritic # Mc   [2] BATAK PANGOLAT..BATAK PANONGONAN\n1C36..1C37    ; Diacritic # Mn   [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA\n1C78..1C7D    ; Diacritic # Lm   [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD\n1CD0..1CD2    ; Diacritic # Mn   [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA\n1CD3          ; Diacritic # Po       VEDIC SIGN NIHSHVASA\n1CD4..1CE0    ; Diacritic # Mn  [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA\n1CE1          ; Diacritic # Mc       VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA\n1CE2..1CE8    ; Diacritic # Mn   [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL\n1CED          ; Diacritic # Mn       VEDIC SIGN TIRYAK\n1CF4          ; Diacritic # Mn       VEDIC TONE CANDRA ABOVE\n1CF7          ; Diacritic # Mc       VEDIC SIGN ATIKRAMA\n1CF8..1CF9    ; Diacritic # Mn   [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE\n1D2C..1D6A    ; Diacritic # Lm  [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI\n1D9B..1DBE    ; Diacritic # Lm  [36] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL EZH\n1DC4..1DCF    ; Diacritic # Mn  [12] COMBINING MACRON-ACUTE..COMBINING ZIGZAG BELOW\n1DF5..1DFF    ; Diacritic # Mn  [11] COMBINING UP TACK ABOVE..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW\n1FBD          ; Diacritic # Sk       GREEK KORONIS\n1FBF..1FC1    ; Diacritic # Sk   [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI\n1FCD..1FCF    ; Diacritic # Sk   [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI\n1FDD..1FDF    ; Diacritic # Sk   [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI\n1FED..1FEF    ; Diacritic # Sk   [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA\n1FFD..1FFE    ; Diacritic # Sk   [2] GREEK OXIA..GREEK DASIA\n2CEF..2CF1    ; Diacritic # Mn   [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS\n2E2F          ; Diacritic # Lm       VERTICAL TILDE\n302A..302D    ; Diacritic # Mn   [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK\n302E..302F    ; Diacritic # Mc   [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK\n3099..309A    ; Diacritic # Mn   [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n309B..309C    ; Diacritic # Sk   [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n30FC          ; Diacritic # Lm       KATAKANA-HIRAGANA PROLONGED SOUND MARK\nA66F          ; Diacritic # Mn       COMBINING CYRILLIC VZMET\nA67C..A67D    ; Diacritic # Mn   [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK\nA67F          ; Diacritic # Lm       CYRILLIC PAYEROK\nA69C..A69D    ; Diacritic # Lm   [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN\nA6F0..A6F1    ; Diacritic # Mn   [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS\nA700..A716    ; Diacritic # Sk  [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR\nA717..A71F    ; Diacritic # Lm   [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK\nA720..A721    ; Diacritic # Sk   [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE\nA788          ; Diacritic # Lm       MODIFIER LETTER LOW CIRCUMFLEX ACCENT\nA789..A78A    ; Diacritic # Sk   [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN\nA7F1          ; Diacritic # Lm       MODIFIER LETTER CAPITAL S\nA7F8..A7F9    ; Diacritic # Lm   [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE\nA806          ; Diacritic # Mn       SYLOTI NAGRI SIGN HASANTA\nA82C          ; Diacritic # Mn       SYLOTI NAGRI SIGN ALTERNATE HASANTA\nA8C4          ; Diacritic # Mn       SAURASHTRA SIGN VIRAMA\nA8E0..A8F1    ; Diacritic # Mn  [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA\nA92B..A92D    ; Diacritic # Mn   [3] KAYAH LI TONE PLOPHU..KAYAH LI TONE CALYA PLOPHU\nA92E          ; Diacritic # Po       KAYAH LI SIGN CWI\nA953          ; Diacritic # Mc       REJANG VIRAMA\nA9B3          ; Diacritic # Mn       JAVANESE SIGN CECAK TELU\nA9C0          ; Diacritic # Mc       JAVANESE PANGKON\nA9E5          ; Diacritic # Mn       MYANMAR SIGN SHAN SAW\nAA7B          ; Diacritic # Mc       MYANMAR SIGN PAO KAREN TONE\nAA7C          ; Diacritic # Mn       MYANMAR SIGN TAI LAING TONE-2\nAA7D          ; Diacritic # Mc       MYANMAR SIGN TAI LAING TONE-5\nAABF          ; Diacritic # Mn       TAI VIET TONE MAI EK\nAAC0          ; Diacritic # Lo       TAI VIET TONE MAI NUENG\nAAC1          ; Diacritic # Mn       TAI VIET TONE MAI THO\nAAC2          ; Diacritic # Lo       TAI VIET TONE MAI SONG\nAAF6          ; Diacritic # Mn       MEETEI MAYEK VIRAMA\nAB5B          ; Diacritic # Sk       MODIFIER BREVE WITH INVERTED BREVE\nAB5C..AB5F    ; Diacritic # Lm   [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK\nAB69          ; Diacritic # Lm       MODIFIER LETTER SMALL TURNED W\nAB6A..AB6B    ; Diacritic # Sk   [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK\nABEC          ; Diacritic # Mc       MEETEI MAYEK LUM IYEK\nABED          ; Diacritic # Mn       MEETEI MAYEK APUN IYEK\nFB1E          ; Diacritic # Mn       HEBREW POINT JUDEO-SPANISH VARIKA\nFE20..FE2F    ; Diacritic # Mn  [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF\nFF3E          ; Diacritic # Sk       FULLWIDTH CIRCUMFLEX ACCENT\nFF40          ; Diacritic # Sk       FULLWIDTH GRAVE ACCENT\nFF70          ; Diacritic # Lm       HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK\nFF9E..FF9F    ; Diacritic # Lm   [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK\nFFE3          ; Diacritic # Sk       FULLWIDTH MACRON\n102E0         ; Diacritic # Mn       COPTIC EPACT THOUSANDS MARK\n10780..10785  ; Diacritic # Lm   [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK\n10787..107B0  ; Diacritic # Lm  [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK\n107B2..107BA  ; Diacritic # Lm   [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL\n10A38..10A3A  ; Diacritic # Mn   [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW\n10A3F         ; Diacritic # Mn       KHAROSHTHI VIRAMA\n10AE5..10AE6  ; Diacritic # Mn   [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW\n10D22..10D23  ; Diacritic # Lo   [2] HANIFI ROHINGYA MARK SAKIN..HANIFI ROHINGYA MARK NA KHONNA\n10D24..10D27  ; Diacritic # Mn   [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI\n10D4E         ; Diacritic # Lm       GARAY VOWEL LENGTH MARK\n10D69..10D6D  ; Diacritic # Mn   [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK\n10EFA         ; Diacritic # Mn       ARABIC DOUBLE VERTICAL BAR BELOW\n10EFD..10EFF  ; Diacritic # Mn   [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA\n10F46..10F50  ; Diacritic # Mn  [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW\n10F82..10F85  ; Diacritic # Mn   [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW\n11046         ; Diacritic # Mn       BRAHMI VIRAMA\n11070         ; Diacritic # Mn       BRAHMI SIGN OLD TAMIL VIRAMA\n110B9..110BA  ; Diacritic # Mn   [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA\n11133..11134  ; Diacritic # Mn   [2] CHAKMA VIRAMA..CHAKMA MAAYYAA\n11173         ; Diacritic # Mn       MAHAJANI SIGN NUKTA\n111C0         ; Diacritic # Mc       SHARADA SIGN VIRAMA\n111CA..111CC  ; Diacritic # Mn   [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK\n11235         ; Diacritic # Mc       KHOJKI SIGN VIRAMA\n11236         ; Diacritic # Mn       KHOJKI SIGN NUKTA\n112E9..112EA  ; Diacritic # Mn   [2] KHUDAWADI SIGN NUKTA..KHUDAWADI SIGN VIRAMA\n1133B..1133C  ; Diacritic # Mn   [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA\n1134D         ; Diacritic # Mc       GRANTHA SIGN VIRAMA\n11366..1136C  ; Diacritic # Mn   [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX\n11370..11374  ; Diacritic # Mn   [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA\n113CE         ; Diacritic # Mn       TULU-TIGALARI SIGN VIRAMA\n113CF         ; Diacritic # Mc       TULU-TIGALARI SIGN LOOPED VIRAMA\n113D0         ; Diacritic # Mn       TULU-TIGALARI CONJOINER\n113D2         ; Diacritic # Mn       TULU-TIGALARI GEMINATION MARK\n113D3         ; Diacritic # Lo       TULU-TIGALARI SIGN PLUTA\n113E1..113E2  ; Diacritic # Mn   [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA\n11442         ; Diacritic # Mn       NEWA SIGN VIRAMA\n11446         ; Diacritic # Mn       NEWA SIGN NUKTA\n114C2..114C3  ; Diacritic # Mn   [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA\n115BF..115C0  ; Diacritic # Mn   [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA\n1163F         ; Diacritic # Mn       MODI SIGN VIRAMA\n116B6         ; Diacritic # Mc       TAKRI SIGN VIRAMA\n116B7         ; Diacritic # Mn       TAKRI SIGN NUKTA\n1172B         ; Diacritic # Mn       AHOM SIGN KILLER\n11839..1183A  ; Diacritic # Mn   [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA\n1193D         ; Diacritic # Mc       DIVES AKURU SIGN HALANTA\n1193E         ; Diacritic # Mn       DIVES AKURU VIRAMA\n11943         ; Diacritic # Mn       DIVES AKURU SIGN NUKTA\n119E0         ; Diacritic # Mn       NANDINAGARI SIGN VIRAMA\n11A34         ; Diacritic # Mn       ZANABAZAR SQUARE SIGN VIRAMA\n11A47         ; Diacritic # Mn       ZANABAZAR SQUARE SUBJOINER\n11A99         ; Diacritic # Mn       SOYOMBO SUBJOINER\n11C3F         ; Diacritic # Mn       BHAIKSUKI SIGN VIRAMA\n11D42         ; Diacritic # Mn       MASARAM GONDI SIGN NUKTA\n11D44..11D45  ; Diacritic # Mn   [2] MASARAM GONDI SIGN HALANTA..MASARAM GONDI VIRAMA\n11D97         ; Diacritic # Mn       GUNJALA GONDI VIRAMA\n11DD9         ; Diacritic # Lm       TOLONG SIKI SIGN SELA\n11F41         ; Diacritic # Mc       KAWI SIGN KILLER\n11F42         ; Diacritic # Mn       KAWI CONJOINER\n11F5A         ; Diacritic # Mn       KAWI SIGN NUKTA\n13447..13455  ; Diacritic # Mn  [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED\n1612F         ; Diacritic # Mn       GURUNG KHEMA SIGN THOLHOMA\n16AF0..16AF4  ; Diacritic # Mn   [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE\n16B30..16B36  ; Diacritic # Mn   [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM\n16D6B..16D6C  ; Diacritic # Lm   [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT\n16F8F..16F92  ; Diacritic # Mn   [4] MIAO TONE RIGHT..MIAO TONE BELOW\n16F93..16F9F  ; Diacritic # Lm  [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8\n16FF0..16FF1  ; Diacritic # Mc   [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY\n1AFF0..1AFF3  ; Diacritic # Lm   [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5\n1AFF5..1AFFB  ; Diacritic # Lm   [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5\n1AFFD..1AFFE  ; Diacritic # Lm   [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8\n1CF00..1CF2D  ; Diacritic # Mn  [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT\n1CF30..1CF46  ; Diacritic # Mn  [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG\n1D167..1D169  ; Diacritic # Mn   [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3\n1D16D..1D172  ; Diacritic # Mc   [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5\n1D17B..1D182  ; Diacritic # Mn   [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE\n1D185..1D18B  ; Diacritic # Mn   [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE\n1D1AA..1D1AD  ; Diacritic # Mn   [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO\n1E030..1E06D  ; Diacritic # Lm  [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE\n1E130..1E136  ; Diacritic # Mn   [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D\n1E2AE         ; Diacritic # Mn       TOTO SIGN RISING TONE\n1E2EC..1E2EF  ; Diacritic # Mn   [4] WANCHO TONE TUP..WANCHO TONE KOINI\n1E5EE..1E5EF  ; Diacritic # Mn   [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR\n1E8D0..1E8D6  ; Diacritic # Mn   [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS\n1E944..1E946  ; Diacritic # Mn   [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK\n1E948..1E94A  ; Diacritic # Mn   [3] ADLAM CONSONANT MODIFIER..ADLAM NUKTA\n\n# Total code points: 1247\n\n# ================================================\n\n00B7          ; Extender # Po       MIDDLE DOT\n02D0..02D1    ; Extender # Lm   [2] MODIFIER LETTER TRIANGULAR COLON..MODIFIER LETTER HALF TRIANGULAR COLON\n0640          ; Extender # Lm       ARABIC TATWEEL\n07FA          ; Extender # Lm       NKO LAJANYALAN\n0A71          ; Extender # Mn       GURMUKHI ADDAK\n0AFB          ; Extender # Mn       GUJARATI SIGN SHADDA\n0B55          ; Extender # Mn       ORIYA SIGN OVERLINE\n0E46          ; Extender # Lm       THAI CHARACTER MAIYAMOK\n0EC6          ; Extender # Lm       LAO KO LA\n180A          ; Extender # Po       MONGOLIAN NIRUGU\n1843          ; Extender # Lm       MONGOLIAN LETTER TODO LONG VOWEL SIGN\n1AA7          ; Extender # Lm       TAI THAM SIGN MAI YAMOK\n1C36          ; Extender # Mn       LEPCHA SIGN RAN\n1C7B          ; Extender # Lm       OL CHIKI RELAA\n3005          ; Extender # Lm       IDEOGRAPHIC ITERATION MARK\n3031..3035    ; Extender # Lm   [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF\n309D..309E    ; Extender # Lm   [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK\n30FC..30FE    ; Extender # Lm   [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK\nA015          ; Extender # Lm       YI SYLLABLE WU\nA60C          ; Extender # Lm       VAI SYLLABLE LENGTHENER\nA9CF          ; Extender # Lm       JAVANESE PANGRANGKEP\nA9E6          ; Extender # Lm       MYANMAR MODIFIER LETTER SHAN REDUPLICATION\nAA70          ; Extender # Lm       MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION\nAADD          ; Extender # Lm       TAI VIET SYMBOL SAM\nAAF3..AAF4    ; Extender # Lm   [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK\nFF70          ; Extender # Lm       HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK\n10781..10782  ; Extender # Lm   [2] MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON..MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON\n10D4E         ; Extender # Lm       GARAY VOWEL LENGTH MARK\n10D6A         ; Extender # Mn       GARAY CONSONANT GEMINATION MARK\n10D6F         ; Extender # Lm       GARAY REDUPLICATION MARK\n11237         ; Extender # Mn       KHOJKI SIGN SHADDA\n1135D         ; Extender # Lo       GRANTHA SIGN PLUTA\n113D2         ; Extender # Mn       TULU-TIGALARI GEMINATION MARK\n113D3         ; Extender # Lo       TULU-TIGALARI SIGN PLUTA\n115C6..115C8  ; Extender # Po   [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3\n11A98         ; Extender # Mn       SOYOMBO GEMINATION MARK\n11DD9         ; Extender # Lm       TOLONG SIKI SIGN SELA\n16B42..16B43  ; Extender # Lm   [2] PAHAWH HMONG SIGN VOS NRUA..PAHAWH HMONG SIGN IB YAM\n16FE0..16FE1  ; Extender # Lm   [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK\n16FE3         ; Extender # Lm       OLD CHINESE ITERATION MARK\n16FF2..16FF3  ; Extender # Lm   [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER\n1E13C..1E13D  ; Extender # Lm   [2] NYIAKENG PUACHUE HMONG SIGN XW XW..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER\n1E5EF         ; Extender # Mn       OL ONAL SIGN IKIR\n1E944..1E946  ; Extender # Mn   [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK\n\n# Total code points: 62\n\n# ================================================\n\n00AA          ; Other_Lowercase # Lo       FEMININE ORDINAL INDICATOR\n00BA          ; Other_Lowercase # Lo       MASCULINE ORDINAL INDICATOR\n02B0..02B8    ; Other_Lowercase # Lm   [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y\n02C0..02C1    ; Other_Lowercase # Lm   [2] MODIFIER LETTER GLOTTAL STOP..MODIFIER LETTER REVERSED GLOTTAL STOP\n02E0..02E4    ; Other_Lowercase # Lm   [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP\n0345          ; Other_Lowercase # Mn       COMBINING GREEK YPOGEGRAMMENI\n037A          ; Other_Lowercase # Lm       GREEK YPOGEGRAMMENI\n10FC          ; Other_Lowercase # Lm       MODIFIER LETTER GEORGIAN NAR\n1D2C..1D6A    ; Other_Lowercase # Lm  [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI\n1D78          ; Other_Lowercase # Lm       MODIFIER LETTER CYRILLIC EN\n1D9B..1DBF    ; Other_Lowercase # Lm  [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA\n2071          ; Other_Lowercase # Lm       SUPERSCRIPT LATIN SMALL LETTER I\n207F          ; Other_Lowercase # Lm       SUPERSCRIPT LATIN SMALL LETTER N\n2090..209C    ; Other_Lowercase # Lm  [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T\n2170..217F    ; Other_Lowercase # Nl  [16] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND\n24D0..24E9    ; Other_Lowercase # So  [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z\n2C7C..2C7D    ; Other_Lowercase # Lm   [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V\nA69C..A69D    ; Other_Lowercase # Lm   [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN\nA770          ; Other_Lowercase # Lm       MODIFIER LETTER US\nA7F1..A7F4    ; Other_Lowercase # Lm   [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q\nA7F8..A7F9    ; Other_Lowercase # Lm   [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE\nAB5C..AB5F    ; Other_Lowercase # Lm   [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK\nAB69          ; Other_Lowercase # Lm       MODIFIER LETTER SMALL TURNED W\n10780         ; Other_Lowercase # Lm       MODIFIER LETTER SMALL CAPITAL AA\n10783..10785  ; Other_Lowercase # Lm   [3] MODIFIER LETTER SMALL AE..MODIFIER LETTER SMALL B WITH HOOK\n10787..107B0  ; Other_Lowercase # Lm  [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK\n107B2..107BA  ; Other_Lowercase # Lm   [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL\n1E030..1E06D  ; Other_Lowercase # Lm  [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE\n\n# Total code points: 312\n\n# ================================================\n\n2160..216F    ; Other_Uppercase # Nl  [16] ROMAN NUMERAL ONE..ROMAN NUMERAL ONE THOUSAND\n24B6..24CF    ; Other_Uppercase # So  [26] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN CAPITAL LETTER Z\n1F130..1F149  ; Other_Uppercase # So  [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z\n1F150..1F169  ; Other_Uppercase # So  [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z\n1F170..1F189  ; Other_Uppercase # So  [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z\n\n# Total code points: 120\n\n# ================================================\n\nFDD0..FDEF    ; Noncharacter_Code_Point # Cn  [32] <noncharacter-FDD0>..<noncharacter-FDEF>\nFFFE..FFFF    ; Noncharacter_Code_Point # Cn   [2] <noncharacter-FFFE>..<noncharacter-FFFF>\n1FFFE..1FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-1FFFE>..<noncharacter-1FFFF>\n2FFFE..2FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-2FFFE>..<noncharacter-2FFFF>\n3FFFE..3FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-3FFFE>..<noncharacter-3FFFF>\n4FFFE..4FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-4FFFE>..<noncharacter-4FFFF>\n5FFFE..5FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-5FFFE>..<noncharacter-5FFFF>\n6FFFE..6FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-6FFFE>..<noncharacter-6FFFF>\n7FFFE..7FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-7FFFE>..<noncharacter-7FFFF>\n8FFFE..8FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-8FFFE>..<noncharacter-8FFFF>\n9FFFE..9FFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-9FFFE>..<noncharacter-9FFFF>\nAFFFE..AFFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-AFFFE>..<noncharacter-AFFFF>\nBFFFE..BFFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-BFFFE>..<noncharacter-BFFFF>\nCFFFE..CFFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-CFFFE>..<noncharacter-CFFFF>\nDFFFE..DFFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-DFFFE>..<noncharacter-DFFFF>\nEFFFE..EFFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-EFFFE>..<noncharacter-EFFFF>\nFFFFE..FFFFF  ; Noncharacter_Code_Point # Cn   [2] <noncharacter-FFFFE>..<noncharacter-FFFFF>\n10FFFE..10FFFF; Noncharacter_Code_Point # Cn   [2] <noncharacter-10FFFE>..<noncharacter-10FFFF>\n\n# Total code points: 66\n\n# ================================================\n\n09BE          ; Other_Grapheme_Extend # Mc       BENGALI VOWEL SIGN AA\n09D7          ; Other_Grapheme_Extend # Mc       BENGALI AU LENGTH MARK\n0B3E          ; Other_Grapheme_Extend # Mc       ORIYA VOWEL SIGN AA\n0B57          ; Other_Grapheme_Extend # Mc       ORIYA AU LENGTH MARK\n0BBE          ; Other_Grapheme_Extend # Mc       TAMIL VOWEL SIGN AA\n0BD7          ; Other_Grapheme_Extend # Mc       TAMIL AU LENGTH MARK\n0CC0          ; Other_Grapheme_Extend # Mc       KANNADA VOWEL SIGN II\n0CC2          ; Other_Grapheme_Extend # Mc       KANNADA VOWEL SIGN UU\n0CC7..0CC8    ; Other_Grapheme_Extend # Mc   [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI\n0CCA..0CCB    ; Other_Grapheme_Extend # Mc   [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO\n0CD5..0CD6    ; Other_Grapheme_Extend # Mc   [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK\n0D3E          ; Other_Grapheme_Extend # Mc       MALAYALAM VOWEL SIGN AA\n0D57          ; Other_Grapheme_Extend # Mc       MALAYALAM AU LENGTH MARK\n0DCF          ; Other_Grapheme_Extend # Mc       SINHALA VOWEL SIGN AELA-PILLA\n0DDF          ; Other_Grapheme_Extend # Mc       SINHALA VOWEL SIGN GAYANUKITTA\n1715          ; Other_Grapheme_Extend # Mc       TAGALOG SIGN PAMUDPOD\n1734          ; Other_Grapheme_Extend # Mc       HANUNOO SIGN PAMUDPOD\n1B35          ; Other_Grapheme_Extend # Mc       BALINESE VOWEL SIGN TEDUNG\n1B3B          ; Other_Grapheme_Extend # Mc       BALINESE VOWEL SIGN RA REPA TEDUNG\n1B3D          ; Other_Grapheme_Extend # Mc       BALINESE VOWEL SIGN LA LENGA TEDUNG\n1B43..1B44    ; Other_Grapheme_Extend # Mc   [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG\n1BAA          ; Other_Grapheme_Extend # Mc       SUNDANESE SIGN PAMAAEH\n1BF2..1BF3    ; Other_Grapheme_Extend # Mc   [2] BATAK PANGOLAT..BATAK PANONGONAN\n200C          ; Other_Grapheme_Extend # Cf       ZERO WIDTH NON-JOINER\n302E..302F    ; Other_Grapheme_Extend # Mc   [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK\nA953          ; Other_Grapheme_Extend # Mc       REJANG VIRAMA\nA9C0          ; Other_Grapheme_Extend # Mc       JAVANESE PANGKON\nFF9E..FF9F    ; Other_Grapheme_Extend # Lm   [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK\n111C0         ; Other_Grapheme_Extend # Mc       SHARADA SIGN VIRAMA\n11235         ; Other_Grapheme_Extend # Mc       KHOJKI SIGN VIRAMA\n1133E         ; Other_Grapheme_Extend # Mc       GRANTHA VOWEL SIGN AA\n1134D         ; Other_Grapheme_Extend # Mc       GRANTHA SIGN VIRAMA\n11357         ; Other_Grapheme_Extend # Mc       GRANTHA AU LENGTH MARK\n113B8         ; Other_Grapheme_Extend # Mc       TULU-TIGALARI VOWEL SIGN AA\n113C2         ; Other_Grapheme_Extend # Mc       TULU-TIGALARI VOWEL SIGN EE\n113C5         ; Other_Grapheme_Extend # Mc       TULU-TIGALARI VOWEL SIGN AI\n113C7..113C9  ; Other_Grapheme_Extend # Mc   [3] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI AU LENGTH MARK\n113CF         ; Other_Grapheme_Extend # Mc       TULU-TIGALARI SIGN LOOPED VIRAMA\n114B0         ; Other_Grapheme_Extend # Mc       TIRHUTA VOWEL SIGN AA\n114BD         ; Other_Grapheme_Extend # Mc       TIRHUTA VOWEL SIGN SHORT O\n115AF         ; Other_Grapheme_Extend # Mc       SIDDHAM VOWEL SIGN AA\n116B6         ; Other_Grapheme_Extend # Mc       TAKRI SIGN VIRAMA\n11930         ; Other_Grapheme_Extend # Mc       DIVES AKURU VOWEL SIGN AA\n1193D         ; Other_Grapheme_Extend # Mc       DIVES AKURU SIGN HALANTA\n11F41         ; Other_Grapheme_Extend # Mc       KAWI SIGN KILLER\n16FF0..16FF1  ; Other_Grapheme_Extend # Mc   [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY\n1D165..1D166  ; Other_Grapheme_Extend # Mc   [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM\n1D16D..1D172  ; Other_Grapheme_Extend # Mc   [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5\nE0020..E007F  ; Other_Grapheme_Extend # Cf  [96] TAG SPACE..CANCEL TAG\n\n# Total code points: 160\n\n# ================================================\n\n2FF0..2FF1    ; IDS_Binary_Operator # So   [2] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW\n2FF4..2FFD    ; IDS_Binary_Operator # So  [10] IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND..IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER RIGHT\n31EF          ; IDS_Binary_Operator # So       IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION\n\n# Total code points: 13\n\n# ================================================\n\n2FF2..2FF3    ; IDS_Trinary_Operator # So   [2] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW\n\n# Total code points: 2\n\n# ================================================\n\n2FFE..2FFF    ; IDS_Unary_Operator # So   [2] IDEOGRAPHIC DESCRIPTION CHARACTER HORIZONTAL REFLECTION..IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION\n\n# Total code points: 2\n\n# ================================================\n\n2E80..2E99    ; Radical # So  [26] CJK RADICAL REPEAT..CJK RADICAL RAP\n2E9B..2EF3    ; Radical # So  [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE\n2F00..2FD5    ; Radical # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE\n\n# Total code points: 329\n\n# ================================================\n\n3400..4DBF    ; Unified_Ideograph # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF\n4E00..9FFF    ; Unified_Ideograph # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF\nFA0E..FA0F    ; Unified_Ideograph # Lo   [2] CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F\nFA11          ; Unified_Ideograph # Lo       CJK COMPATIBILITY IDEOGRAPH-FA11\nFA13..FA14    ; Unified_Ideograph # Lo   [2] CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14\nFA1F          ; Unified_Ideograph # Lo       CJK COMPATIBILITY IDEOGRAPH-FA1F\nFA21          ; Unified_Ideograph # Lo       CJK COMPATIBILITY IDEOGRAPH-FA21\nFA23..FA24    ; Unified_Ideograph # Lo   [2] CJK COMPATIBILITY IDEOGRAPH-FA23..CJK COMPATIBILITY IDEOGRAPH-FA24\nFA27..FA29    ; Unified_Ideograph # Lo   [3] CJK COMPATIBILITY IDEOGRAPH-FA27..CJK COMPATIBILITY IDEOGRAPH-FA29\n20000..2A6DF  ; Unified_Ideograph # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF\n2A700..2B81D  ; Unified_Ideograph # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D\n2B820..2CEAD  ; Unified_Ideograph # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD\n2CEB0..2EBE0  ; Unified_Ideograph # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0\n2EBF0..2EE5D  ; Unified_Ideograph # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D\n30000..3134A  ; Unified_Ideograph # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A\n31350..33479  ; Unified_Ideograph # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479\n\n# Total code points: 101996\n\n# ================================================\n\n034F          ; Other_Default_Ignorable_Code_Point # Mn       COMBINING GRAPHEME JOINER\n115F..1160    ; Other_Default_Ignorable_Code_Point # Lo   [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER\n17B4..17B5    ; Other_Default_Ignorable_Code_Point # Mn   [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA\n2065          ; Other_Default_Ignorable_Code_Point # Cn       <reserved-2065>\n3164          ; Other_Default_Ignorable_Code_Point # Lo       HANGUL FILLER\nFFA0          ; Other_Default_Ignorable_Code_Point # Lo       HALFWIDTH HANGUL FILLER\nFFF0..FFF8    ; Other_Default_Ignorable_Code_Point # Cn   [9] <reserved-FFF0>..<reserved-FFF8>\nE0000         ; Other_Default_Ignorable_Code_Point # Cn       <reserved-E0000>\nE0002..E001F  ; Other_Default_Ignorable_Code_Point # Cn  [30] <reserved-E0002>..<reserved-E001F>\nE0080..E00FF  ; Other_Default_Ignorable_Code_Point # Cn [128] <reserved-E0080>..<reserved-E00FF>\nE01F0..E0FFF  ; Other_Default_Ignorable_Code_Point # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>\n\n# Total code points: 3776\n\n# ================================================\n\n0149          ; Deprecated # L&       LATIN SMALL LETTER N PRECEDED BY APOSTROPHE\n0673          ; Deprecated # Lo       ARABIC LETTER ALEF WITH WAVY HAMZA BELOW\n0F77          ; Deprecated # Mn       TIBETAN VOWEL SIGN VOCALIC RR\n0F79          ; Deprecated # Mn       TIBETAN VOWEL SIGN VOCALIC LL\n17A3..17A4    ; Deprecated # Lo   [2] KHMER INDEPENDENT VOWEL QAQ..KHMER INDEPENDENT VOWEL QAA\n206A..206F    ; Deprecated # Cf   [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES\n2329          ; Deprecated # Ps       LEFT-POINTING ANGLE BRACKET\n232A          ; Deprecated # Pe       RIGHT-POINTING ANGLE BRACKET\nE0001         ; Deprecated # Cf       LANGUAGE TAG\n\n# Total code points: 15\n\n# ================================================\n\n0069..006A    ; Soft_Dotted # L&   [2] LATIN SMALL LETTER I..LATIN SMALL LETTER J\n012F          ; Soft_Dotted # L&       LATIN SMALL LETTER I WITH OGONEK\n0249          ; Soft_Dotted # L&       LATIN SMALL LETTER J WITH STROKE\n0268          ; Soft_Dotted # L&       LATIN SMALL LETTER I WITH STROKE\n029D          ; Soft_Dotted # L&       LATIN SMALL LETTER J WITH CROSSED-TAIL\n02B2          ; Soft_Dotted # Lm       MODIFIER LETTER SMALL J\n03F3          ; Soft_Dotted # L&       GREEK LETTER YOT\n0456          ; Soft_Dotted # L&       CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I\n0458          ; Soft_Dotted # L&       CYRILLIC SMALL LETTER JE\n1D62          ; Soft_Dotted # Lm       LATIN SUBSCRIPT SMALL LETTER I\n1D96          ; Soft_Dotted # L&       LATIN SMALL LETTER I WITH RETROFLEX HOOK\n1DA4          ; Soft_Dotted # Lm       MODIFIER LETTER SMALL I WITH STROKE\n1DA8          ; Soft_Dotted # Lm       MODIFIER LETTER SMALL J WITH CROSSED-TAIL\n1E2D          ; Soft_Dotted # L&       LATIN SMALL LETTER I WITH TILDE BELOW\n1ECB          ; Soft_Dotted # L&       LATIN SMALL LETTER I WITH DOT BELOW\n2071          ; Soft_Dotted # Lm       SUPERSCRIPT LATIN SMALL LETTER I\n2148..2149    ; Soft_Dotted # L&   [2] DOUBLE-STRUCK ITALIC SMALL I..DOUBLE-STRUCK ITALIC SMALL J\n2C7C          ; Soft_Dotted # Lm       LATIN SUBSCRIPT SMALL LETTER J\n1D422..1D423  ; Soft_Dotted # L&   [2] MATHEMATICAL BOLD SMALL I..MATHEMATICAL BOLD SMALL J\n1D456..1D457  ; Soft_Dotted # L&   [2] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL ITALIC SMALL J\n1D48A..1D48B  ; Soft_Dotted # L&   [2] MATHEMATICAL BOLD ITALIC SMALL I..MATHEMATICAL BOLD ITALIC SMALL J\n1D4BE..1D4BF  ; Soft_Dotted # L&   [2] MATHEMATICAL SCRIPT SMALL I..MATHEMATICAL SCRIPT SMALL J\n1D4F2..1D4F3  ; Soft_Dotted # L&   [2] MATHEMATICAL BOLD SCRIPT SMALL I..MATHEMATICAL BOLD SCRIPT SMALL J\n1D526..1D527  ; Soft_Dotted # L&   [2] MATHEMATICAL FRAKTUR SMALL I..MATHEMATICAL FRAKTUR SMALL J\n1D55A..1D55B  ; Soft_Dotted # L&   [2] MATHEMATICAL DOUBLE-STRUCK SMALL I..MATHEMATICAL DOUBLE-STRUCK SMALL J\n1D58E..1D58F  ; Soft_Dotted # L&   [2] MATHEMATICAL BOLD FRAKTUR SMALL I..MATHEMATICAL BOLD FRAKTUR SMALL J\n1D5C2..1D5C3  ; Soft_Dotted # L&   [2] MATHEMATICAL SANS-SERIF SMALL I..MATHEMATICAL SANS-SERIF SMALL J\n1D5F6..1D5F7  ; Soft_Dotted # L&   [2] MATHEMATICAL SANS-SERIF BOLD SMALL I..MATHEMATICAL SANS-SERIF BOLD SMALL J\n1D62A..1D62B  ; Soft_Dotted # L&   [2] MATHEMATICAL SANS-SERIF ITALIC SMALL I..MATHEMATICAL SANS-SERIF ITALIC SMALL J\n1D65E..1D65F  ; Soft_Dotted # L&   [2] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J\n1D692..1D693  ; Soft_Dotted # L&   [2] MATHEMATICAL MONOSPACE SMALL I..MATHEMATICAL MONOSPACE SMALL J\n1DF1A         ; Soft_Dotted # L&       LATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOK\n1E04C..1E04D  ; Soft_Dotted # Lm   [2] MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I..MODIFIER LETTER CYRILLIC SMALL JE\n1E068         ; Soft_Dotted # Lm       CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I\n\n# Total code points: 50\n\n# ================================================\n\n0E40..0E44    ; Logical_Order_Exception # Lo   [5] THAI CHARACTER SARA E..THAI CHARACTER SARA AI MAIMALAI\n0EC0..0EC4    ; Logical_Order_Exception # Lo   [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI\n19B5..19B7    ; Logical_Order_Exception # Lo   [3] NEW TAI LUE VOWEL SIGN E..NEW TAI LUE VOWEL SIGN O\n19BA          ; Logical_Order_Exception # Lo       NEW TAI LUE VOWEL SIGN AY\nAAB5..AAB6    ; Logical_Order_Exception # Lo   [2] TAI VIET VOWEL E..TAI VIET VOWEL O\nAAB9          ; Logical_Order_Exception # Lo       TAI VIET VOWEL UEA\nAABB..AABC    ; Logical_Order_Exception # Lo   [2] TAI VIET VOWEL AUE..TAI VIET VOWEL AY\n\n# Total code points: 19\n\n# ================================================\n\n1885..1886    ; Other_ID_Start # Mn   [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA\n2118          ; Other_ID_Start # Sm       SCRIPT CAPITAL P\n212E          ; Other_ID_Start # So       ESTIMATED SYMBOL\n309B..309C    ; Other_ID_Start # Sk   [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n\n# Total code points: 6\n\n# ================================================\n\n00B7          ; Other_ID_Continue # Po       MIDDLE DOT\n0387          ; Other_ID_Continue # Po       GREEK ANO TELEIA\n1369..1371    ; Other_ID_Continue # No   [9] ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE\n19DA          ; Other_ID_Continue # No       NEW TAI LUE THAM DIGIT ONE\n200C..200D    ; Other_ID_Continue # Cf   [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER\n30FB          ; Other_ID_Continue # Po       KATAKANA MIDDLE DOT\nFF65          ; Other_ID_Continue # Po       HALFWIDTH KATAKANA MIDDLE DOT\n\n# Total code points: 16\n\n# ================================================\n\n00B2..00B3    ; ID_Compat_Math_Continue # No   [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE\n00B9          ; ID_Compat_Math_Continue # No       SUPERSCRIPT ONE\n2070          ; ID_Compat_Math_Continue # No       SUPERSCRIPT ZERO\n2074..2079    ; ID_Compat_Math_Continue # No   [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE\n207A..207C    ; ID_Compat_Math_Continue # Sm   [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN\n207D          ; ID_Compat_Math_Continue # Ps       SUPERSCRIPT LEFT PARENTHESIS\n207E          ; ID_Compat_Math_Continue # Pe       SUPERSCRIPT RIGHT PARENTHESIS\n2080..2089    ; ID_Compat_Math_Continue # No  [10] SUBSCRIPT ZERO..SUBSCRIPT NINE\n208A..208C    ; ID_Compat_Math_Continue # Sm   [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN\n208D          ; ID_Compat_Math_Continue # Ps       SUBSCRIPT LEFT PARENTHESIS\n208E          ; ID_Compat_Math_Continue # Pe       SUBSCRIPT RIGHT PARENTHESIS\n2202          ; ID_Compat_Math_Continue # Sm       PARTIAL DIFFERENTIAL\n2207          ; ID_Compat_Math_Continue # Sm       NABLA\n221E          ; ID_Compat_Math_Continue # Sm       INFINITY\n1D6C1         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL BOLD NABLA\n1D6DB         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL BOLD PARTIAL DIFFERENTIAL\n1D6FB         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL ITALIC NABLA\n1D715         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL\n1D735         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL BOLD ITALIC NABLA\n1D74F         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL\n1D76F         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL SANS-SERIF BOLD NABLA\n1D789         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL\n1D7A9         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA\n1D7C3         ; ID_Compat_Math_Continue # Sm       MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL\n\n# Total code points: 43\n\n# ================================================\n\n2202          ; ID_Compat_Math_Start # Sm       PARTIAL DIFFERENTIAL\n2207          ; ID_Compat_Math_Start # Sm       NABLA\n221E          ; ID_Compat_Math_Start # Sm       INFINITY\n1D6C1         ; ID_Compat_Math_Start # Sm       MATHEMATICAL BOLD NABLA\n1D6DB         ; ID_Compat_Math_Start # Sm       MATHEMATICAL BOLD PARTIAL DIFFERENTIAL\n1D6FB         ; ID_Compat_Math_Start # Sm       MATHEMATICAL ITALIC NABLA\n1D715         ; ID_Compat_Math_Start # Sm       MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL\n1D735         ; ID_Compat_Math_Start # Sm       MATHEMATICAL BOLD ITALIC NABLA\n1D74F         ; ID_Compat_Math_Start # Sm       MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL\n1D76F         ; ID_Compat_Math_Start # Sm       MATHEMATICAL SANS-SERIF BOLD NABLA\n1D789         ; ID_Compat_Math_Start # Sm       MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL\n1D7A9         ; ID_Compat_Math_Start # Sm       MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA\n1D7C3         ; ID_Compat_Math_Start # Sm       MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL\n\n# Total code points: 13\n\n# ================================================\n\n0021          ; Sentence_Terminal # Po       EXCLAMATION MARK\n002E          ; Sentence_Terminal # Po       FULL STOP\n003F          ; Sentence_Terminal # Po       QUESTION MARK\n0589          ; Sentence_Terminal # Po       ARMENIAN FULL STOP\n061D..061F    ; Sentence_Terminal # Po   [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK\n06D4          ; Sentence_Terminal # Po       ARABIC FULL STOP\n0700..0702    ; Sentence_Terminal # Po   [3] SYRIAC END OF PARAGRAPH..SYRIAC SUBLINEAR FULL STOP\n07F9          ; Sentence_Terminal # Po       NKO EXCLAMATION MARK\n0837          ; Sentence_Terminal # Po       SAMARITAN PUNCTUATION MELODIC QITSA\n0839          ; Sentence_Terminal # Po       SAMARITAN PUNCTUATION QITSA\n083D..083E    ; Sentence_Terminal # Po   [2] SAMARITAN PUNCTUATION SOF MASHFAAT..SAMARITAN PUNCTUATION ANNAAU\n0964..0965    ; Sentence_Terminal # Po   [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA\n104A..104B    ; Sentence_Terminal # Po   [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION\n1362          ; Sentence_Terminal # Po       ETHIOPIC FULL STOP\n1367..1368    ; Sentence_Terminal # Po   [2] ETHIOPIC QUESTION MARK..ETHIOPIC PARAGRAPH SEPARATOR\n166E          ; Sentence_Terminal # Po       CANADIAN SYLLABICS FULL STOP\n1735..1736    ; Sentence_Terminal # Po   [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION\n17D4..17D5    ; Sentence_Terminal # Po   [2] KHMER SIGN KHAN..KHMER SIGN BARIYOOSAN\n1803          ; Sentence_Terminal # Po       MONGOLIAN FULL STOP\n1809          ; Sentence_Terminal # Po       MONGOLIAN MANCHU FULL STOP\n1944..1945    ; Sentence_Terminal # Po   [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK\n1AA8..1AAB    ; Sentence_Terminal # Po   [4] TAI THAM SIGN KAAN..TAI THAM SIGN SATKAANKUU\n1B4E..1B4F    ; Sentence_Terminal # Po   [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN\n1B5A..1B5B    ; Sentence_Terminal # Po   [2] BALINESE PANTI..BALINESE PAMADA\n1B5E..1B5F    ; Sentence_Terminal # Po   [2] BALINESE CARIK SIKI..BALINESE CARIK PAREREN\n1B7D..1B7F    ; Sentence_Terminal # Po   [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK\n1C3B..1C3C    ; Sentence_Terminal # Po   [2] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION NYET THYOOM TA-ROL\n1C7E..1C7F    ; Sentence_Terminal # Po   [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD\n2024          ; Sentence_Terminal # Po       ONE DOT LEADER\n203C..203D    ; Sentence_Terminal # Po   [2] DOUBLE EXCLAMATION MARK..INTERROBANG\n2047..2049    ; Sentence_Terminal # Po   [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK\n2CF9..2CFB    ; Sentence_Terminal # Po   [3] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN INDIRECT QUESTION MARK\n2E2E          ; Sentence_Terminal # Po       REVERSED QUESTION MARK\n2E3C          ; Sentence_Terminal # Po       STENOGRAPHIC FULL STOP\n2E53..2E54    ; Sentence_Terminal # Po   [2] MEDIEVAL EXCLAMATION MARK..MEDIEVAL QUESTION MARK\n3002          ; Sentence_Terminal # Po       IDEOGRAPHIC FULL STOP\nA4FF          ; Sentence_Terminal # Po       LISU PUNCTUATION FULL STOP\nA60E..A60F    ; Sentence_Terminal # Po   [2] VAI FULL STOP..VAI QUESTION MARK\nA6F3          ; Sentence_Terminal # Po       BAMUM FULL STOP\nA6F7          ; Sentence_Terminal # Po       BAMUM QUESTION MARK\nA876..A877    ; Sentence_Terminal # Po   [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD\nA8CE..A8CF    ; Sentence_Terminal # Po   [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA\nA92F          ; Sentence_Terminal # Po       KAYAH LI SIGN SHYA\nA9C8..A9C9    ; Sentence_Terminal # Po   [2] JAVANESE PADA LINGSA..JAVANESE PADA LUNGSI\nAA5D..AA5F    ; Sentence_Terminal # Po   [3] CHAM PUNCTUATION DANDA..CHAM PUNCTUATION TRIPLE DANDA\nAAF0..AAF1    ; Sentence_Terminal # Po   [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM\nABEB          ; Sentence_Terminal # Po       MEETEI MAYEK CHEIKHEI\nFE12          ; Sentence_Terminal # Po       PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP\nFE15..FE16    ; Sentence_Terminal # Po   [2] PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK..PRESENTATION FORM FOR VERTICAL QUESTION MARK\nFE52          ; Sentence_Terminal # Po       SMALL FULL STOP\nFE56..FE57    ; Sentence_Terminal # Po   [2] SMALL QUESTION MARK..SMALL EXCLAMATION MARK\nFF01          ; Sentence_Terminal # Po       FULLWIDTH EXCLAMATION MARK\nFF0E          ; Sentence_Terminal # Po       FULLWIDTH FULL STOP\nFF1F          ; Sentence_Terminal # Po       FULLWIDTH QUESTION MARK\nFF61          ; Sentence_Terminal # Po       HALFWIDTH IDEOGRAPHIC FULL STOP\n10A56..10A57  ; Sentence_Terminal # Po   [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA\n10F55..10F59  ; Sentence_Terminal # Po   [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT\n10F86..10F89  ; Sentence_Terminal # Po   [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS\n11047..11048  ; Sentence_Terminal # Po   [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA\n110BE..110C1  ; Sentence_Terminal # Po   [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA\n11141..11143  ; Sentence_Terminal # Po   [3] CHAKMA DANDA..CHAKMA QUESTION MARK\n111C5..111C6  ; Sentence_Terminal # Po   [2] SHARADA DANDA..SHARADA DOUBLE DANDA\n111CD         ; Sentence_Terminal # Po       SHARADA SUTRA MARK\n111DE..111DF  ; Sentence_Terminal # Po   [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2\n11238..11239  ; Sentence_Terminal # Po   [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA\n1123B..1123C  ; Sentence_Terminal # Po   [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK\n112A9         ; Sentence_Terminal # Po       MULTANI SECTION MARK\n113D4..113D5  ; Sentence_Terminal # Po   [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA\n1144B..1144C  ; Sentence_Terminal # Po   [2] NEWA DANDA..NEWA DOUBLE DANDA\n115C2..115C3  ; Sentence_Terminal # Po   [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA\n115C9..115D7  ; Sentence_Terminal # Po  [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES\n11641..11642  ; Sentence_Terminal # Po   [2] MODI DANDA..MODI DOUBLE DANDA\n1173C..1173E  ; Sentence_Terminal # Po   [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI\n11944         ; Sentence_Terminal # Po       DIVES AKURU DOUBLE DANDA\n11946         ; Sentence_Terminal # Po       DIVES AKURU END OF TEXT MARK\n11A42..11A43  ; Sentence_Terminal # Po   [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD\n11A9B..11A9C  ; Sentence_Terminal # Po   [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD\n11C41..11C42  ; Sentence_Terminal # Po   [2] BHAIKSUKI DANDA..BHAIKSUKI DOUBLE DANDA\n11EF7..11EF8  ; Sentence_Terminal # Po   [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION\n11F43..11F44  ; Sentence_Terminal # Po   [2] KAWI DANDA..KAWI DOUBLE DANDA\n16A6E..16A6F  ; Sentence_Terminal # Po   [2] MRO DANDA..MRO DOUBLE DANDA\n16AF5         ; Sentence_Terminal # Po       BASSA VAH FULL STOP\n16B37..16B38  ; Sentence_Terminal # Po   [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB\n16B44         ; Sentence_Terminal # Po       PAHAWH HMONG SIGN XAUS\n16D6E..16D6F  ; Sentence_Terminal # Po   [2] KIRAT RAI DANDA..KIRAT RAI DOUBLE DANDA\n16E98         ; Sentence_Terminal # Po       MEDEFAIDRIN FULL STOP\n1BC9F         ; Sentence_Terminal # Po       DUPLOYAN PUNCTUATION CHINOOK FULL STOP\n1DA88         ; Sentence_Terminal # Po       SIGNWRITING FULL STOP\n\n# Total code points: 170\n\n# ================================================\n\n180B..180D    ; Variation_Selector # Mn   [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE\n180F          ; Variation_Selector # Mn       MONGOLIAN FREE VARIATION SELECTOR FOUR\nFE00..FE0F    ; Variation_Selector # Mn  [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16\nE0100..E01EF  ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256\n\n# Total code points: 260\n\n# ================================================\n\n0009..000D    ; Pattern_White_Space # Cc   [5] <control-0009>..<control-000D>\n0020          ; Pattern_White_Space # Zs       SPACE\n0085          ; Pattern_White_Space # Cc       <control-0085>\n200E..200F    ; Pattern_White_Space # Cf   [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK\n2028          ; Pattern_White_Space # Zl       LINE SEPARATOR\n2029          ; Pattern_White_Space # Zp       PARAGRAPH SEPARATOR\n\n# Total code points: 11\n\n# ================================================\n\n0021..0023    ; Pattern_Syntax # Po   [3] EXCLAMATION MARK..NUMBER SIGN\n0024          ; Pattern_Syntax # Sc       DOLLAR SIGN\n0025..0027    ; Pattern_Syntax # Po   [3] PERCENT SIGN..APOSTROPHE\n0028          ; Pattern_Syntax # Ps       LEFT PARENTHESIS\n0029          ; Pattern_Syntax # Pe       RIGHT PARENTHESIS\n002A          ; Pattern_Syntax # Po       ASTERISK\n002B          ; Pattern_Syntax # Sm       PLUS SIGN\n002C          ; Pattern_Syntax # Po       COMMA\n002D          ; Pattern_Syntax # Pd       HYPHEN-MINUS\n002E..002F    ; Pattern_Syntax # Po   [2] FULL STOP..SOLIDUS\n003A..003B    ; Pattern_Syntax # Po   [2] COLON..SEMICOLON\n003C..003E    ; Pattern_Syntax # Sm   [3] LESS-THAN SIGN..GREATER-THAN SIGN\n003F..0040    ; Pattern_Syntax # Po   [2] QUESTION MARK..COMMERCIAL AT\n005B          ; Pattern_Syntax # Ps       LEFT SQUARE BRACKET\n005C          ; Pattern_Syntax # Po       REVERSE SOLIDUS\n005D          ; Pattern_Syntax # Pe       RIGHT SQUARE BRACKET\n005E          ; Pattern_Syntax # Sk       CIRCUMFLEX ACCENT\n0060          ; Pattern_Syntax # Sk       GRAVE ACCENT\n007B          ; Pattern_Syntax # Ps       LEFT CURLY BRACKET\n007C          ; Pattern_Syntax # Sm       VERTICAL LINE\n007D          ; Pattern_Syntax # Pe       RIGHT CURLY BRACKET\n007E          ; Pattern_Syntax # Sm       TILDE\n00A1          ; Pattern_Syntax # Po       INVERTED EXCLAMATION MARK\n00A2..00A5    ; Pattern_Syntax # Sc   [4] CENT SIGN..YEN SIGN\n00A6          ; Pattern_Syntax # So       BROKEN BAR\n00A7          ; Pattern_Syntax # Po       SECTION SIGN\n00A9          ; Pattern_Syntax # So       COPYRIGHT SIGN\n00AB          ; Pattern_Syntax # Pi       LEFT-POINTING DOUBLE ANGLE QUOTATION MARK\n00AC          ; Pattern_Syntax # Sm       NOT SIGN\n00AE          ; Pattern_Syntax # So       REGISTERED SIGN\n00B0          ; Pattern_Syntax # So       DEGREE SIGN\n00B1          ; Pattern_Syntax # Sm       PLUS-MINUS SIGN\n00B6          ; Pattern_Syntax # Po       PILCROW SIGN\n00BB          ; Pattern_Syntax # Pf       RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK\n00BF          ; Pattern_Syntax # Po       INVERTED QUESTION MARK\n00D7          ; Pattern_Syntax # Sm       MULTIPLICATION SIGN\n00F7          ; Pattern_Syntax # Sm       DIVISION SIGN\n2010..2015    ; Pattern_Syntax # Pd   [6] HYPHEN..HORIZONTAL BAR\n2016..2017    ; Pattern_Syntax # Po   [2] DOUBLE VERTICAL LINE..DOUBLE LOW LINE\n2018          ; Pattern_Syntax # Pi       LEFT SINGLE QUOTATION MARK\n2019          ; Pattern_Syntax # Pf       RIGHT SINGLE QUOTATION MARK\n201A          ; Pattern_Syntax # Ps       SINGLE LOW-9 QUOTATION MARK\n201B..201C    ; Pattern_Syntax # Pi   [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK\n201D          ; Pattern_Syntax # Pf       RIGHT DOUBLE QUOTATION MARK\n201E          ; Pattern_Syntax # Ps       DOUBLE LOW-9 QUOTATION MARK\n201F          ; Pattern_Syntax # Pi       DOUBLE HIGH-REVERSED-9 QUOTATION MARK\n2020..2027    ; Pattern_Syntax # Po   [8] DAGGER..HYPHENATION POINT\n2030..2038    ; Pattern_Syntax # Po   [9] PER MILLE SIGN..CARET\n2039          ; Pattern_Syntax # Pi       SINGLE LEFT-POINTING ANGLE QUOTATION MARK\n203A          ; Pattern_Syntax # Pf       SINGLE RIGHT-POINTING ANGLE QUOTATION MARK\n203B..203E    ; Pattern_Syntax # Po   [4] REFERENCE MARK..OVERLINE\n2041..2043    ; Pattern_Syntax # Po   [3] CARET INSERTION POINT..HYPHEN BULLET\n2044          ; Pattern_Syntax # Sm       FRACTION SLASH\n2045          ; Pattern_Syntax # Ps       LEFT SQUARE BRACKET WITH QUILL\n2046          ; Pattern_Syntax # Pe       RIGHT SQUARE BRACKET WITH QUILL\n2047..2051    ; Pattern_Syntax # Po  [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY\n2052          ; Pattern_Syntax # Sm       COMMERCIAL MINUS SIGN\n2053          ; Pattern_Syntax # Po       SWUNG DASH\n2055..205E    ; Pattern_Syntax # Po  [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS\n2190..2194    ; Pattern_Syntax # Sm   [5] LEFTWARDS ARROW..LEFT RIGHT ARROW\n2195..2199    ; Pattern_Syntax # So   [5] UP DOWN ARROW..SOUTH WEST ARROW\n219A..219B    ; Pattern_Syntax # Sm   [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE\n219C..219F    ; Pattern_Syntax # So   [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW\n21A0          ; Pattern_Syntax # Sm       RIGHTWARDS TWO HEADED ARROW\n21A1..21A2    ; Pattern_Syntax # So   [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL\n21A3          ; Pattern_Syntax # Sm       RIGHTWARDS ARROW WITH TAIL\n21A4..21A5    ; Pattern_Syntax # So   [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR\n21A6          ; Pattern_Syntax # Sm       RIGHTWARDS ARROW FROM BAR\n21A7..21AD    ; Pattern_Syntax # So   [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW\n21AE          ; Pattern_Syntax # Sm       LEFT RIGHT ARROW WITH STROKE\n21AF..21CD    ; Pattern_Syntax # So  [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE\n21CE..21CF    ; Pattern_Syntax # Sm   [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE\n21D0..21D1    ; Pattern_Syntax # So   [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW\n21D2          ; Pattern_Syntax # Sm       RIGHTWARDS DOUBLE ARROW\n21D3          ; Pattern_Syntax # So       DOWNWARDS DOUBLE ARROW\n21D4          ; Pattern_Syntax # Sm       LEFT RIGHT DOUBLE ARROW\n21D5..21F3    ; Pattern_Syntax # So  [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW\n21F4..22FF    ; Pattern_Syntax # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP\n2300..2307    ; Pattern_Syntax # So   [8] DIAMETER SIGN..WAVY LINE\n2308          ; Pattern_Syntax # Ps       LEFT CEILING\n2309          ; Pattern_Syntax # Pe       RIGHT CEILING\n230A          ; Pattern_Syntax # Ps       LEFT FLOOR\n230B          ; Pattern_Syntax # Pe       RIGHT FLOOR\n230C..231F    ; Pattern_Syntax # So  [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER\n2320..2321    ; Pattern_Syntax # Sm   [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL\n2322..2328    ; Pattern_Syntax # So   [7] FROWN..KEYBOARD\n2329          ; Pattern_Syntax # Ps       LEFT-POINTING ANGLE BRACKET\n232A          ; Pattern_Syntax # Pe       RIGHT-POINTING ANGLE BRACKET\n232B..237B    ; Pattern_Syntax # So  [81] ERASE TO THE LEFT..NOT CHECK MARK\n237C          ; Pattern_Syntax # Sm       RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW\n237D..239A    ; Pattern_Syntax # So  [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL\n239B..23B3    ; Pattern_Syntax # Sm  [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM\n23B4..23DB    ; Pattern_Syntax # So  [40] TOP SQUARE BRACKET..FUSE\n23DC..23E1    ; Pattern_Syntax # Sm   [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET\n23E2..2429    ; Pattern_Syntax # So  [72] WHITE TRAPEZIUM..SYMBOL FOR DELETE MEDIUM SHADE FORM\n242A..243F    ; Pattern_Syntax # Cn  [22] <reserved-242A>..<reserved-243F>\n2440..244A    ; Pattern_Syntax # So  [11] OCR HOOK..OCR DOUBLE BACKSLASH\n244B..245F    ; Pattern_Syntax # Cn  [21] <reserved-244B>..<reserved-245F>\n2500..25B6    ; Pattern_Syntax # So [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE\n25B7          ; Pattern_Syntax # Sm       WHITE RIGHT-POINTING TRIANGLE\n25B8..25C0    ; Pattern_Syntax # So   [9] BLACK RIGHT-POINTING SMALL TRIANGLE..BLACK LEFT-POINTING TRIANGLE\n25C1          ; Pattern_Syntax # Sm       WHITE LEFT-POINTING TRIANGLE\n25C2..25F7    ; Pattern_Syntax # So  [54] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE CIRCLE WITH UPPER RIGHT QUADRANT\n25F8..25FF    ; Pattern_Syntax # Sm   [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE\n2600..266E    ; Pattern_Syntax # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN\n266F          ; Pattern_Syntax # Sm       MUSIC SHARP SIGN\n2670..2767    ; Pattern_Syntax # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET\n2768          ; Pattern_Syntax # Ps       MEDIUM LEFT PARENTHESIS ORNAMENT\n2769          ; Pattern_Syntax # Pe       MEDIUM RIGHT PARENTHESIS ORNAMENT\n276A          ; Pattern_Syntax # Ps       MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT\n276B          ; Pattern_Syntax # Pe       MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT\n276C          ; Pattern_Syntax # Ps       MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT\n276D          ; Pattern_Syntax # Pe       MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT\n276E          ; Pattern_Syntax # Ps       HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT\n276F          ; Pattern_Syntax # Pe       HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT\n2770          ; Pattern_Syntax # Ps       HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT\n2771          ; Pattern_Syntax # Pe       HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT\n2772          ; Pattern_Syntax # Ps       LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT\n2773          ; Pattern_Syntax # Pe       LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT\n2774          ; Pattern_Syntax # Ps       MEDIUM LEFT CURLY BRACKET ORNAMENT\n2775          ; Pattern_Syntax # Pe       MEDIUM RIGHT CURLY BRACKET ORNAMENT\n2794..27BF    ; Pattern_Syntax # So  [44] HEAVY WIDE-HEADED RIGHTWARDS ARROW..DOUBLE CURLY LOOP\n27C0..27C4    ; Pattern_Syntax # Sm   [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET\n27C5          ; Pattern_Syntax # Ps       LEFT S-SHAPED BAG DELIMITER\n27C6          ; Pattern_Syntax # Pe       RIGHT S-SHAPED BAG DELIMITER\n27C7..27E5    ; Pattern_Syntax # Sm  [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK\n27E6          ; Pattern_Syntax # Ps       MATHEMATICAL LEFT WHITE SQUARE BRACKET\n27E7          ; Pattern_Syntax # Pe       MATHEMATICAL RIGHT WHITE SQUARE BRACKET\n27E8          ; Pattern_Syntax # Ps       MATHEMATICAL LEFT ANGLE BRACKET\n27E9          ; Pattern_Syntax # Pe       MATHEMATICAL RIGHT ANGLE BRACKET\n27EA          ; Pattern_Syntax # Ps       MATHEMATICAL LEFT DOUBLE ANGLE BRACKET\n27EB          ; Pattern_Syntax # Pe       MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET\n27EC          ; Pattern_Syntax # Ps       MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET\n27ED          ; Pattern_Syntax # Pe       MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET\n27EE          ; Pattern_Syntax # Ps       MATHEMATICAL LEFT FLATTENED PARENTHESIS\n27EF          ; Pattern_Syntax # Pe       MATHEMATICAL RIGHT FLATTENED PARENTHESIS\n27F0..27FF    ; Pattern_Syntax # Sm  [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW\n2800..28FF    ; Pattern_Syntax # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678\n2900..2982    ; Pattern_Syntax # Sm [131] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..Z NOTATION TYPE COLON\n2983          ; Pattern_Syntax # Ps       LEFT WHITE CURLY BRACKET\n2984          ; Pattern_Syntax # Pe       RIGHT WHITE CURLY BRACKET\n2985          ; Pattern_Syntax # Ps       LEFT WHITE PARENTHESIS\n2986          ; Pattern_Syntax # Pe       RIGHT WHITE PARENTHESIS\n2987          ; Pattern_Syntax # Ps       Z NOTATION LEFT IMAGE BRACKET\n2988          ; Pattern_Syntax # Pe       Z NOTATION RIGHT IMAGE BRACKET\n2989          ; Pattern_Syntax # Ps       Z NOTATION LEFT BINDING BRACKET\n298A          ; Pattern_Syntax # Pe       Z NOTATION RIGHT BINDING BRACKET\n298B          ; Pattern_Syntax # Ps       LEFT SQUARE BRACKET WITH UNDERBAR\n298C          ; Pattern_Syntax # Pe       RIGHT SQUARE BRACKET WITH UNDERBAR\n298D          ; Pattern_Syntax # Ps       LEFT SQUARE BRACKET WITH TICK IN TOP CORNER\n298E          ; Pattern_Syntax # Pe       RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER\n298F          ; Pattern_Syntax # Ps       LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER\n2990          ; Pattern_Syntax # Pe       RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER\n2991          ; Pattern_Syntax # Ps       LEFT ANGLE BRACKET WITH DOT\n2992          ; Pattern_Syntax # Pe       RIGHT ANGLE BRACKET WITH DOT\n2993          ; Pattern_Syntax # Ps       LEFT ARC LESS-THAN BRACKET\n2994          ; Pattern_Syntax # Pe       RIGHT ARC GREATER-THAN BRACKET\n2995          ; Pattern_Syntax # Ps       DOUBLE LEFT ARC GREATER-THAN BRACKET\n2996          ; Pattern_Syntax # Pe       DOUBLE RIGHT ARC LESS-THAN BRACKET\n2997          ; Pattern_Syntax # Ps       LEFT BLACK TORTOISE SHELL BRACKET\n2998          ; Pattern_Syntax # Pe       RIGHT BLACK TORTOISE SHELL BRACKET\n2999..29D7    ; Pattern_Syntax # Sm  [63] DOTTED FENCE..BLACK HOURGLASS\n29D8          ; Pattern_Syntax # Ps       LEFT WIGGLY FENCE\n29D9          ; Pattern_Syntax # Pe       RIGHT WIGGLY FENCE\n29DA          ; Pattern_Syntax # Ps       LEFT DOUBLE WIGGLY FENCE\n29DB          ; Pattern_Syntax # Pe       RIGHT DOUBLE WIGGLY FENCE\n29DC..29FB    ; Pattern_Syntax # Sm  [32] INCOMPLETE INFINITY..TRIPLE PLUS\n29FC          ; Pattern_Syntax # Ps       LEFT-POINTING CURVED ANGLE BRACKET\n29FD          ; Pattern_Syntax # Pe       RIGHT-POINTING CURVED ANGLE BRACKET\n29FE..2AFF    ; Pattern_Syntax # Sm [258] TINY..N-ARY WHITE VERTICAL BAR\n2B00..2B2F    ; Pattern_Syntax # So  [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE\n2B30..2B44    ; Pattern_Syntax # Sm  [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET\n2B45..2B46    ; Pattern_Syntax # So   [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW\n2B47..2B4C    ; Pattern_Syntax # Sm   [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR\n2B4D..2B73    ; Pattern_Syntax # So  [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR\n2B74..2B75    ; Pattern_Syntax # Cn   [2] <reserved-2B74>..<reserved-2B75>\n2B76..2BFF    ; Pattern_Syntax # So [138] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..HELLSCHREIBER PAUSE SYMBOL\n2E00..2E01    ; Pattern_Syntax # Po   [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER\n2E02          ; Pattern_Syntax # Pi       LEFT SUBSTITUTION BRACKET\n2E03          ; Pattern_Syntax # Pf       RIGHT SUBSTITUTION BRACKET\n2E04          ; Pattern_Syntax # Pi       LEFT DOTTED SUBSTITUTION BRACKET\n2E05          ; Pattern_Syntax # Pf       RIGHT DOTTED SUBSTITUTION BRACKET\n2E06..2E08    ; Pattern_Syntax # Po   [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER\n2E09          ; Pattern_Syntax # Pi       LEFT TRANSPOSITION BRACKET\n2E0A          ; Pattern_Syntax # Pf       RIGHT TRANSPOSITION BRACKET\n2E0B          ; Pattern_Syntax # Po       RAISED SQUARE\n2E0C          ; Pattern_Syntax # Pi       LEFT RAISED OMISSION BRACKET\n2E0D          ; Pattern_Syntax # Pf       RIGHT RAISED OMISSION BRACKET\n2E0E..2E16    ; Pattern_Syntax # Po   [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE\n2E17          ; Pattern_Syntax # Pd       DOUBLE OBLIQUE HYPHEN\n2E18..2E19    ; Pattern_Syntax # Po   [2] INVERTED INTERROBANG..PALM BRANCH\n2E1A          ; Pattern_Syntax # Pd       HYPHEN WITH DIAERESIS\n2E1B          ; Pattern_Syntax # Po       TILDE WITH RING ABOVE\n2E1C          ; Pattern_Syntax # Pi       LEFT LOW PARAPHRASE BRACKET\n2E1D          ; Pattern_Syntax # Pf       RIGHT LOW PARAPHRASE BRACKET\n2E1E..2E1F    ; Pattern_Syntax # Po   [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW\n2E20          ; Pattern_Syntax # Pi       LEFT VERTICAL BAR WITH QUILL\n2E21          ; Pattern_Syntax # Pf       RIGHT VERTICAL BAR WITH QUILL\n2E22          ; Pattern_Syntax # Ps       TOP LEFT HALF BRACKET\n2E23          ; Pattern_Syntax # Pe       TOP RIGHT HALF BRACKET\n2E24          ; Pattern_Syntax # Ps       BOTTOM LEFT HALF BRACKET\n2E25          ; Pattern_Syntax # Pe       BOTTOM RIGHT HALF BRACKET\n2E26          ; Pattern_Syntax # Ps       LEFT SIDEWAYS U BRACKET\n2E27          ; Pattern_Syntax # Pe       RIGHT SIDEWAYS U BRACKET\n2E28          ; Pattern_Syntax # Ps       LEFT DOUBLE PARENTHESIS\n2E29          ; Pattern_Syntax # Pe       RIGHT DOUBLE PARENTHESIS\n2E2A..2E2E    ; Pattern_Syntax # Po   [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK\n2E2F          ; Pattern_Syntax # Lm       VERTICAL TILDE\n2E30..2E39    ; Pattern_Syntax # Po  [10] RING POINT..TOP HALF SECTION SIGN\n2E3A..2E3B    ; Pattern_Syntax # Pd   [2] TWO-EM DASH..THREE-EM DASH\n2E3C..2E3F    ; Pattern_Syntax # Po   [4] STENOGRAPHIC FULL STOP..CAPITULUM\n2E40          ; Pattern_Syntax # Pd       DOUBLE HYPHEN\n2E41          ; Pattern_Syntax # Po       REVERSED COMMA\n2E42          ; Pattern_Syntax # Ps       DOUBLE LOW-REVERSED-9 QUOTATION MARK\n2E43..2E4F    ; Pattern_Syntax # Po  [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER\n2E50..2E51    ; Pattern_Syntax # So   [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR\n2E52..2E54    ; Pattern_Syntax # Po   [3] TIRONIAN SIGN CAPITAL ET..MEDIEVAL QUESTION MARK\n2E55          ; Pattern_Syntax # Ps       LEFT SQUARE BRACKET WITH STROKE\n2E56          ; Pattern_Syntax # Pe       RIGHT SQUARE BRACKET WITH STROKE\n2E57          ; Pattern_Syntax # Ps       LEFT SQUARE BRACKET WITH DOUBLE STROKE\n2E58          ; Pattern_Syntax # Pe       RIGHT SQUARE BRACKET WITH DOUBLE STROKE\n2E59          ; Pattern_Syntax # Ps       TOP HALF LEFT PARENTHESIS\n2E5A          ; Pattern_Syntax # Pe       TOP HALF RIGHT PARENTHESIS\n2E5B          ; Pattern_Syntax # Ps       BOTTOM HALF LEFT PARENTHESIS\n2E5C          ; Pattern_Syntax # Pe       BOTTOM HALF RIGHT PARENTHESIS\n2E5D          ; Pattern_Syntax # Pd       OBLIQUE HYPHEN\n2E5E..2E7F    ; Pattern_Syntax # Cn  [34] <reserved-2E5E>..<reserved-2E7F>\n3001..3003    ; Pattern_Syntax # Po   [3] IDEOGRAPHIC COMMA..DITTO MARK\n3008          ; Pattern_Syntax # Ps       LEFT ANGLE BRACKET\n3009          ; Pattern_Syntax # Pe       RIGHT ANGLE BRACKET\n300A          ; Pattern_Syntax # Ps       LEFT DOUBLE ANGLE BRACKET\n300B          ; Pattern_Syntax # Pe       RIGHT DOUBLE ANGLE BRACKET\n300C          ; Pattern_Syntax # Ps       LEFT CORNER BRACKET\n300D          ; Pattern_Syntax # Pe       RIGHT CORNER BRACKET\n300E          ; Pattern_Syntax # Ps       LEFT WHITE CORNER BRACKET\n300F          ; Pattern_Syntax # Pe       RIGHT WHITE CORNER BRACKET\n3010          ; Pattern_Syntax # Ps       LEFT BLACK LENTICULAR BRACKET\n3011          ; Pattern_Syntax # Pe       RIGHT BLACK LENTICULAR BRACKET\n3012..3013    ; Pattern_Syntax # So   [2] POSTAL MARK..GETA MARK\n3014          ; Pattern_Syntax # Ps       LEFT TORTOISE SHELL BRACKET\n3015          ; Pattern_Syntax # Pe       RIGHT TORTOISE SHELL BRACKET\n3016          ; Pattern_Syntax # Ps       LEFT WHITE LENTICULAR BRACKET\n3017          ; Pattern_Syntax # Pe       RIGHT WHITE LENTICULAR BRACKET\n3018          ; Pattern_Syntax # Ps       LEFT WHITE TORTOISE SHELL BRACKET\n3019          ; Pattern_Syntax # Pe       RIGHT WHITE TORTOISE SHELL BRACKET\n301A          ; Pattern_Syntax # Ps       LEFT WHITE SQUARE BRACKET\n301B          ; Pattern_Syntax # Pe       RIGHT WHITE SQUARE BRACKET\n301C          ; Pattern_Syntax # Pd       WAVE DASH\n301D          ; Pattern_Syntax # Ps       REVERSED DOUBLE PRIME QUOTATION MARK\n301E..301F    ; Pattern_Syntax # Pe   [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK\n3020          ; Pattern_Syntax # So       POSTAL MARK FACE\n3030          ; Pattern_Syntax # Pd       WAVY DASH\nFD3E          ; Pattern_Syntax # Pe       ORNATE LEFT PARENTHESIS\nFD3F          ; Pattern_Syntax # Ps       ORNATE RIGHT PARENTHESIS\nFE45..FE46    ; Pattern_Syntax # Po   [2] SESAME DOT..WHITE SESAME DOT\n\n# Total code points: 2760\n\n# ================================================\n\n0600..0605    ; Prepended_Concatenation_Mark # Cf   [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE\n06DD          ; Prepended_Concatenation_Mark # Cf       ARABIC END OF AYAH\n070F          ; Prepended_Concatenation_Mark # Cf       SYRIAC ABBREVIATION MARK\n0890..0891    ; Prepended_Concatenation_Mark # Cf   [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE\n08E2          ; Prepended_Concatenation_Mark # Cf       ARABIC DISPUTED END OF AYAH\n110BD         ; Prepended_Concatenation_Mark # Cf       KAITHI NUMBER SIGN\n110CD         ; Prepended_Concatenation_Mark # Cf       KAITHI NUMBER SIGN ABOVE\n\n# Total code points: 13\n\n# ================================================\n\n1F1E6..1F1FF  ; Regional_Indicator # So  [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z\n\n# Total code points: 26\n\n# ================================================\n\n0654..0655    ; Modifier_Combining_Mark # Mn   [2] ARABIC HAMZA ABOVE..ARABIC HAMZA BELOW\n0658          ; Modifier_Combining_Mark # Mn       ARABIC MARK NOON GHUNNA\n06DC          ; Modifier_Combining_Mark # Mn       ARABIC SMALL HIGH SEEN\n06E3          ; Modifier_Combining_Mark # Mn       ARABIC SMALL LOW SEEN\n06E7..06E8    ; Modifier_Combining_Mark # Mn   [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON\n08CA..08CB    ; Modifier_Combining_Mark # Mn   [2] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW\n08CD..08CF    ; Modifier_Combining_Mark # Mn   [3] ARABIC SMALL HIGH ZAH..ARABIC LARGE ROUND DOT BELOW\n08D3          ; Modifier_Combining_Mark # Mn       ARABIC SMALL LOW WAW\n08F3          ; Modifier_Combining_Mark # Mn       ARABIC SMALL HIGH WAW\n\n# Total code points: 14\n\n# EOF\n"
  },
  {
    "path": "lib/elixir/unicode/PropertyValueAliases.txt",
    "content": "# PropertyValueAliases-17.0.0.txt\n# Date: 2025-06-30, 06:16:21 GMT\n# © 2025 Unicode®, Inc.\n# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.\n# For terms of use and license, see https://www.unicode.org/terms_of_use.html\n#\n# Unicode Character Database\n#   For documentation, see https://www.unicode.org/reports/tr44/\n#\n# This file contains aliases for property values used in the UCD.\n# These names can be used for XML formats of UCD data, for regular-expression\n# property tests, and other programmatic textual descriptions of Unicode data.\n#\n# The names may be translated in appropriate environments, and additional\n# aliases may be useful.\n#\n# FORMAT\n#\n# Each line describes a property value name.\n# This consists of three or more fields, separated by semicolons.\n#\n# First Field: The first field describes the property for which that\n# property value name is used.\n#\n# Second Field: The second field is the short name for the property value.\n# It is typically an abbreviation, but in a number of cases it is simply\n# a duplicate of the \"long name\" in the third field.\n#\n# Third Field: The third field is the long name for the property value, \n# typically the formal name used in documentation about the property value.\n#\n# In the case of Canonical_Combining_Class (ccc), there are 4 fields: \n# The second field is numeric, the third is the short name, and the fourth is the long name.\n#\n# The above are the preferred aliases. Other aliases may be listed in additional fields.\n#\n# Loose matching should be applied to all property names and property values, with\n# the exception of String Property values. With loose matching of property names and\n# values, the case distinctions, whitespace, hyphens, and '_' are ignored.\n# For Numeric Property values, numeric equivalence is applied: thus \"01.00\"\n# is equivalent to \"1\".\n#\n# NOTE: Property value names are NOT unique across properties. For example:\n#\n#   AL means Arabic Letter for the Bidi_Class property, and\n#   AL means Above_Left for the Canonical_Combining_Class property, and\n#   AL means Alphabetic for the Line_Break property.\n#\n# In addition, some property names may be the same as some property value names.\n# For example:\n#\n#   sc means the Script property, and\n#   Sc means the General_Category property value Currency_Symbol (Sc)\n#\n# The combination of property value and property name is, however, unique.\n#\n# For more information, see UAX #44, Unicode Character Database, and\n# UTS #18, Unicode Regular Expressions.\n# ================================================\n\n\n# ASCII_Hex_Digit (AHex)\n\nAHex; N                               ; No                               ; F                                ; False\nAHex; Y                               ; Yes                              ; T                                ; True\n\n# Age (age)\n\nage; 1.1                              ; V1_1\nage; 2.0                              ; V2_0\nage; 2.1                              ; V2_1\nage; 3.0                              ; V3_0\nage; 3.1                              ; V3_1\nage; 3.2                              ; V3_2\nage; 4.0                              ; V4_0\nage; 4.1                              ; V4_1\nage; 5.0                              ; V5_0\nage; 5.1                              ; V5_1\nage; 5.2                              ; V5_2\nage; 6.0                              ; V6_0\nage; 6.1                              ; V6_1\nage; 6.2                              ; V6_2\nage; 6.3                              ; V6_3\nage; 7.0                              ; V7_0\nage; 8.0                              ; V8_0\nage; 9.0                              ; V9_0\nage; 10.0                             ; V10_0\nage; 11.0                             ; V11_0\nage; 12.0                             ; V12_0\nage; 12.1                             ; V12_1\nage; 13.0                             ; V13_0\nage; 14.0                             ; V14_0\nage; 15.0                             ; V15_0\nage; 15.1                             ; V15_1\nage; 16.0                             ; V16_0\nage; 17.0                             ; V17_0\nage; NA                               ; Unassigned\n\n# Alphabetic (Alpha)\n\nAlpha; N                              ; No                               ; F                                ; False\nAlpha; Y                              ; Yes                              ; T                                ; True\n\n# Bidi_Class (bc)\n\nbc ; AL                               ; Arabic_Letter\nbc ; AN                               ; Arabic_Number\nbc ; B                                ; Paragraph_Separator\nbc ; BN                               ; Boundary_Neutral\nbc ; CS                               ; Common_Separator\nbc ; EN                               ; European_Number\nbc ; ES                               ; European_Separator\nbc ; ET                               ; European_Terminator\nbc ; FSI                              ; First_Strong_Isolate\nbc ; L                                ; Left_To_Right\nbc ; LRE                              ; Left_To_Right_Embedding\nbc ; LRI                              ; Left_To_Right_Isolate\nbc ; LRO                              ; Left_To_Right_Override\nbc ; NSM                              ; Nonspacing_Mark\nbc ; ON                               ; Other_Neutral\nbc ; PDF                              ; Pop_Directional_Format\nbc ; PDI                              ; Pop_Directional_Isolate\nbc ; R                                ; Right_To_Left\nbc ; RLE                              ; Right_To_Left_Embedding\nbc ; RLI                              ; Right_To_Left_Isolate\nbc ; RLO                              ; Right_To_Left_Override\nbc ; S                                ; Segment_Separator\nbc ; WS                               ; White_Space\n\n# Bidi_Control (Bidi_C)\n\nBidi_C; N                             ; No                               ; F                                ; False\nBidi_C; Y                             ; Yes                              ; T                                ; True\n\n# Bidi_Mirrored (Bidi_M)\n\nBidi_M; N                             ; No                               ; F                                ; False\nBidi_M; Y                             ; Yes                              ; T                                ; True\n\n# Bidi_Mirroring_Glyph (bmg)\n\n\n# Bidi_Paired_Bracket (bpb)\n\n# @missing: 0000..10FFFF; Bidi_Paired_Bracket; <none>\n\n# Bidi_Paired_Bracket_Type (bpt)\n\nbpt; c                                ; Close\nbpt; n                                ; None\nbpt; o                                ; Open\n# @missing: 0000..10FFFF; Bidi_Paired_Bracket_Type; n\n\n# Block (blk)\n\nblk; Adlam                            ; Adlam\nblk; Aegean_Numbers                   ; Aegean_Numbers\nblk; Ahom                             ; Ahom\nblk; Alchemical                       ; Alchemical_Symbols\nblk; Alphabetic_PF                    ; Alphabetic_Presentation_Forms\nblk; Anatolian_Hieroglyphs            ; Anatolian_Hieroglyphs\nblk; Ancient_Greek_Music              ; Ancient_Greek_Musical_Notation\nblk; Ancient_Greek_Numbers            ; Ancient_Greek_Numbers\nblk; Ancient_Symbols                  ; Ancient_Symbols\nblk; Arabic                           ; Arabic\nblk; Arabic_Ext_A                     ; Arabic_Extended_A\nblk; Arabic_Ext_B                     ; Arabic_Extended_B\nblk; Arabic_Ext_C                     ; Arabic_Extended_C\nblk; Arabic_Math                      ; Arabic_Mathematical_Alphabetic_Symbols\nblk; Arabic_PF_A                      ; Arabic_Presentation_Forms_A      ; Arabic_Presentation_Forms-A\nblk; Arabic_PF_B                      ; Arabic_Presentation_Forms_B\nblk; Arabic_Sup                       ; Arabic_Supplement\nblk; Armenian                         ; Armenian\nblk; Arrows                           ; Arrows\nblk; ASCII                            ; Basic_Latin\nblk; Avestan                          ; Avestan\nblk; Balinese                         ; Balinese\nblk; Bamum                            ; Bamum\nblk; Bamum_Sup                        ; Bamum_Supplement\nblk; Bassa_Vah                        ; Bassa_Vah\nblk; Batak                            ; Batak\nblk; Bengali                          ; Bengali\nblk; Beria_Erfe                       ; Beria_Erfe\nblk; Bhaiksuki                        ; Bhaiksuki\nblk; Block_Elements                   ; Block_Elements\nblk; Bopomofo                         ; Bopomofo\nblk; Bopomofo_Ext                     ; Bopomofo_Extended\nblk; Box_Drawing                      ; Box_Drawing\nblk; Brahmi                           ; Brahmi\nblk; Braille                          ; Braille_Patterns\nblk; Buginese                         ; Buginese\nblk; Buhid                            ; Buhid\nblk; Byzantine_Music                  ; Byzantine_Musical_Symbols\nblk; Carian                           ; Carian\nblk; Caucasian_Albanian               ; Caucasian_Albanian\nblk; Chakma                           ; Chakma\nblk; Cham                             ; Cham\nblk; Cherokee                         ; Cherokee\nblk; Cherokee_Sup                     ; Cherokee_Supplement\nblk; Chess_Symbols                    ; Chess_Symbols\nblk; Chorasmian                       ; Chorasmian\nblk; CJK                              ; CJK_Unified_Ideographs\nblk; CJK_Compat                       ; CJK_Compatibility\nblk; CJK_Compat_Forms                 ; CJK_Compatibility_Forms\nblk; CJK_Compat_Ideographs            ; CJK_Compatibility_Ideographs\nblk; CJK_Compat_Ideographs_Sup        ; CJK_Compatibility_Ideographs_Supplement\nblk; CJK_Ext_A                        ; CJK_Unified_Ideographs_Extension_A\nblk; CJK_Ext_B                        ; CJK_Unified_Ideographs_Extension_B\nblk; CJK_Ext_C                        ; CJK_Unified_Ideographs_Extension_C\nblk; CJK_Ext_D                        ; CJK_Unified_Ideographs_Extension_D\nblk; CJK_Ext_E                        ; CJK_Unified_Ideographs_Extension_E\nblk; CJK_Ext_F                        ; CJK_Unified_Ideographs_Extension_F\nblk; CJK_Ext_G                        ; CJK_Unified_Ideographs_Extension_G\nblk; CJK_Ext_H                        ; CJK_Unified_Ideographs_Extension_H\nblk; CJK_Ext_I                        ; CJK_Unified_Ideographs_Extension_I\nblk; CJK_Ext_J                        ; CJK_Unified_Ideographs_Extension_J\nblk; CJK_Radicals_Sup                 ; CJK_Radicals_Supplement\nblk; CJK_Strokes                      ; CJK_Strokes\nblk; CJK_Symbols                      ; CJK_Symbols_And_Punctuation\nblk; Compat_Jamo                      ; Hangul_Compatibility_Jamo\nblk; Control_Pictures                 ; Control_Pictures\nblk; Coptic                           ; Coptic\nblk; Coptic_Epact_Numbers             ; Coptic_Epact_Numbers\nblk; Counting_Rod                     ; Counting_Rod_Numerals\nblk; Cuneiform                        ; Cuneiform\nblk; Cuneiform_Numbers                ; Cuneiform_Numbers_And_Punctuation\nblk; Currency_Symbols                 ; Currency_Symbols\nblk; Cypriot_Syllabary                ; Cypriot_Syllabary\nblk; Cypro_Minoan                     ; Cypro_Minoan\nblk; Cyrillic                         ; Cyrillic\nblk; Cyrillic_Ext_A                   ; Cyrillic_Extended_A\nblk; Cyrillic_Ext_B                   ; Cyrillic_Extended_B\nblk; Cyrillic_Ext_C                   ; Cyrillic_Extended_C\nblk; Cyrillic_Ext_D                   ; Cyrillic_Extended_D\nblk; Cyrillic_Sup                     ; Cyrillic_Supplement              ; Cyrillic_Supplementary\nblk; Deseret                          ; Deseret\nblk; Devanagari                       ; Devanagari\nblk; Devanagari_Ext                   ; Devanagari_Extended\nblk; Devanagari_Ext_A                 ; Devanagari_Extended_A\nblk; Diacriticals                     ; Combining_Diacritical_Marks\nblk; Diacriticals_Ext                 ; Combining_Diacritical_Marks_Extended\nblk; Diacriticals_For_Symbols         ; Combining_Diacritical_Marks_For_Symbols; Combining_Marks_For_Symbols\nblk; Diacriticals_Sup                 ; Combining_Diacritical_Marks_Supplement\nblk; Dingbats                         ; Dingbats\nblk; Dives_Akuru                      ; Dives_Akuru\nblk; Dogra                            ; Dogra\nblk; Domino                           ; Domino_Tiles\nblk; Duployan                         ; Duployan\nblk; Early_Dynastic_Cuneiform         ; Early_Dynastic_Cuneiform\nblk; Egyptian_Hieroglyph_Format_Controls; Egyptian_Hieroglyph_Format_Controls\nblk; Egyptian_Hieroglyphs             ; Egyptian_Hieroglyphs\nblk; Egyptian_Hieroglyphs_Ext_A       ; Egyptian_Hieroglyphs_Extended_A\nblk; Elbasan                          ; Elbasan\nblk; Elymaic                          ; Elymaic\nblk; Emoticons                        ; Emoticons\nblk; Enclosed_Alphanum                ; Enclosed_Alphanumerics\nblk; Enclosed_Alphanum_Sup            ; Enclosed_Alphanumeric_Supplement\nblk; Enclosed_CJK                     ; Enclosed_CJK_Letters_And_Months\nblk; Enclosed_Ideographic_Sup         ; Enclosed_Ideographic_Supplement\nblk; Ethiopic                         ; Ethiopic\nblk; Ethiopic_Ext                     ; Ethiopic_Extended\nblk; Ethiopic_Ext_A                   ; Ethiopic_Extended_A\nblk; Ethiopic_Ext_B                   ; Ethiopic_Extended_B\nblk; Ethiopic_Sup                     ; Ethiopic_Supplement\nblk; Garay                            ; Garay\nblk; Geometric_Shapes                 ; Geometric_Shapes\nblk; Geometric_Shapes_Ext             ; Geometric_Shapes_Extended\nblk; Georgian                         ; Georgian\nblk; Georgian_Ext                     ; Georgian_Extended\nblk; Georgian_Sup                     ; Georgian_Supplement\nblk; Glagolitic                       ; Glagolitic\nblk; Glagolitic_Sup                   ; Glagolitic_Supplement\nblk; Gothic                           ; Gothic\nblk; Grantha                          ; Grantha\nblk; Greek                            ; Greek_And_Coptic\nblk; Greek_Ext                        ; Greek_Extended\nblk; Gujarati                         ; Gujarati\nblk; Gunjala_Gondi                    ; Gunjala_Gondi\nblk; Gurmukhi                         ; Gurmukhi\nblk; Gurung_Khema                     ; Gurung_Khema\nblk; Half_And_Full_Forms              ; Halfwidth_And_Fullwidth_Forms\nblk; Half_Marks                       ; Combining_Half_Marks\nblk; Hangul                           ; Hangul_Syllables\nblk; Hanifi_Rohingya                  ; Hanifi_Rohingya\nblk; Hanunoo                          ; Hanunoo\nblk; Hatran                           ; Hatran\nblk; Hebrew                           ; Hebrew\nblk; High_PU_Surrogates               ; High_Private_Use_Surrogates\nblk; High_Surrogates                  ; High_Surrogates\nblk; Hiragana                         ; Hiragana\nblk; IDC                              ; Ideographic_Description_Characters\nblk; Ideographic_Symbols              ; Ideographic_Symbols_And_Punctuation\nblk; Imperial_Aramaic                 ; Imperial_Aramaic\nblk; Indic_Number_Forms               ; Common_Indic_Number_Forms\nblk; Indic_Siyaq_Numbers              ; Indic_Siyaq_Numbers\nblk; Inscriptional_Pahlavi            ; Inscriptional_Pahlavi\nblk; Inscriptional_Parthian           ; Inscriptional_Parthian\nblk; IPA_Ext                          ; IPA_Extensions\nblk; Jamo                             ; Hangul_Jamo\nblk; Jamo_Ext_A                       ; Hangul_Jamo_Extended_A\nblk; Jamo_Ext_B                       ; Hangul_Jamo_Extended_B\nblk; Javanese                         ; Javanese\nblk; Kaithi                           ; Kaithi\nblk; Kaktovik_Numerals                ; Kaktovik_Numerals\nblk; Kana_Ext_A                       ; Kana_Extended_A\nblk; Kana_Ext_B                       ; Kana_Extended_B\nblk; Kana_Sup                         ; Kana_Supplement\nblk; Kanbun                           ; Kanbun\nblk; Kangxi                           ; Kangxi_Radicals\nblk; Kannada                          ; Kannada\nblk; Katakana                         ; Katakana\nblk; Katakana_Ext                     ; Katakana_Phonetic_Extensions\nblk; Kawi                             ; Kawi\nblk; Kayah_Li                         ; Kayah_Li\nblk; Kharoshthi                       ; Kharoshthi\nblk; Khitan_Small_Script              ; Khitan_Small_Script\nblk; Khmer                            ; Khmer\nblk; Khmer_Symbols                    ; Khmer_Symbols\nblk; Khojki                           ; Khojki\nblk; Khudawadi                        ; Khudawadi\nblk; Kirat_Rai                        ; Kirat_Rai\nblk; Lao                              ; Lao\nblk; Latin_1_Sup                      ; Latin_1_Supplement               ; Latin_1\nblk; Latin_Ext_A                      ; Latin_Extended_A\nblk; Latin_Ext_Additional             ; Latin_Extended_Additional\nblk; Latin_Ext_B                      ; Latin_Extended_B\nblk; Latin_Ext_C                      ; Latin_Extended_C\nblk; Latin_Ext_D                      ; Latin_Extended_D\nblk; Latin_Ext_E                      ; Latin_Extended_E\nblk; Latin_Ext_F                      ; Latin_Extended_F\nblk; Latin_Ext_G                      ; Latin_Extended_G\nblk; Lepcha                           ; Lepcha\nblk; Letterlike_Symbols               ; Letterlike_Symbols\nblk; Limbu                            ; Limbu\nblk; Linear_A                         ; Linear_A\nblk; Linear_B_Ideograms               ; Linear_B_Ideograms\nblk; Linear_B_Syllabary               ; Linear_B_Syllabary\nblk; Lisu                             ; Lisu\nblk; Lisu_Sup                         ; Lisu_Supplement\nblk; Low_Surrogates                   ; Low_Surrogates\nblk; Lycian                           ; Lycian\nblk; Lydian                           ; Lydian\nblk; Mahajani                         ; Mahajani\nblk; Mahjong                          ; Mahjong_Tiles\nblk; Makasar                          ; Makasar\nblk; Malayalam                        ; Malayalam\nblk; Mandaic                          ; Mandaic\nblk; Manichaean                       ; Manichaean\nblk; Marchen                          ; Marchen\nblk; Masaram_Gondi                    ; Masaram_Gondi\nblk; Math_Alphanum                    ; Mathematical_Alphanumeric_Symbols\nblk; Math_Operators                   ; Mathematical_Operators\nblk; Mayan_Numerals                   ; Mayan_Numerals\nblk; Medefaidrin                      ; Medefaidrin\nblk; Meetei_Mayek                     ; Meetei_Mayek\nblk; Meetei_Mayek_Ext                 ; Meetei_Mayek_Extensions\nblk; Mende_Kikakui                    ; Mende_Kikakui\nblk; Meroitic_Cursive                 ; Meroitic_Cursive\nblk; Meroitic_Hieroglyphs             ; Meroitic_Hieroglyphs\nblk; Miao                             ; Miao\nblk; Misc_Arrows                      ; Miscellaneous_Symbols_And_Arrows\nblk; Misc_Math_Symbols_A              ; Miscellaneous_Mathematical_Symbols_A\nblk; Misc_Math_Symbols_B              ; Miscellaneous_Mathematical_Symbols_B\nblk; Misc_Pictographs                 ; Miscellaneous_Symbols_And_Pictographs\nblk; Misc_Symbols                     ; Miscellaneous_Symbols\nblk; Misc_Symbols_Sup                 ; Miscellaneous_Symbols_Supplement\nblk; Misc_Technical                   ; Miscellaneous_Technical\nblk; Modi                             ; Modi\nblk; Modifier_Letters                 ; Spacing_Modifier_Letters\nblk; Modifier_Tone_Letters            ; Modifier_Tone_Letters\nblk; Mongolian                        ; Mongolian\nblk; Mongolian_Sup                    ; Mongolian_Supplement\nblk; Mro                              ; Mro\nblk; Multani                          ; Multani\nblk; Music                            ; Musical_Symbols\nblk; Myanmar                          ; Myanmar\nblk; Myanmar_Ext_A                    ; Myanmar_Extended_A\nblk; Myanmar_Ext_B                    ; Myanmar_Extended_B\nblk; Myanmar_Ext_C                    ; Myanmar_Extended_C\nblk; Nabataean                        ; Nabataean\nblk; Nag_Mundari                      ; Nag_Mundari\nblk; Nandinagari                      ; Nandinagari\nblk; NB                               ; No_Block\nblk; New_Tai_Lue                      ; New_Tai_Lue\nblk; Newa                             ; Newa\nblk; NKo                              ; NKo\nblk; Number_Forms                     ; Number_Forms\nblk; Nushu                            ; Nushu\nblk; Nyiakeng_Puachue_Hmong           ; Nyiakeng_Puachue_Hmong\nblk; OCR                              ; Optical_Character_Recognition\nblk; Ogham                            ; Ogham\nblk; Ol_Chiki                         ; Ol_Chiki\nblk; Ol_Onal                          ; Ol_Onal\nblk; Old_Hungarian                    ; Old_Hungarian\nblk; Old_Italic                       ; Old_Italic\nblk; Old_North_Arabian                ; Old_North_Arabian\nblk; Old_Permic                       ; Old_Permic\nblk; Old_Persian                      ; Old_Persian\nblk; Old_Sogdian                      ; Old_Sogdian\nblk; Old_South_Arabian                ; Old_South_Arabian\nblk; Old_Turkic                       ; Old_Turkic\nblk; Old_Uyghur                       ; Old_Uyghur\nblk; Oriya                            ; Oriya\nblk; Ornamental_Dingbats              ; Ornamental_Dingbats\nblk; Osage                            ; Osage\nblk; Osmanya                          ; Osmanya\nblk; Ottoman_Siyaq_Numbers            ; Ottoman_Siyaq_Numbers\nblk; Pahawh_Hmong                     ; Pahawh_Hmong\nblk; Palmyrene                        ; Palmyrene\nblk; Pau_Cin_Hau                      ; Pau_Cin_Hau\nblk; Phags_Pa                         ; Phags_Pa\nblk; Phaistos                         ; Phaistos_Disc\nblk; Phoenician                       ; Phoenician\nblk; Phonetic_Ext                     ; Phonetic_Extensions\nblk; Phonetic_Ext_Sup                 ; Phonetic_Extensions_Supplement\nblk; Playing_Cards                    ; Playing_Cards\nblk; Psalter_Pahlavi                  ; Psalter_Pahlavi\nblk; PUA                              ; Private_Use_Area                 ; Private_Use\nblk; Punctuation                      ; General_Punctuation\nblk; Rejang                           ; Rejang\nblk; Rumi                             ; Rumi_Numeral_Symbols\nblk; Runic                            ; Runic\nblk; Samaritan                        ; Samaritan\nblk; Saurashtra                       ; Saurashtra\nblk; Sharada                          ; Sharada\nblk; Sharada_Sup                      ; Sharada_Supplement\nblk; Shavian                          ; Shavian\nblk; Shorthand_Format_Controls        ; Shorthand_Format_Controls\nblk; Siddham                          ; Siddham\nblk; Sidetic                          ; Sidetic\nblk; Sinhala                          ; Sinhala\nblk; Sinhala_Archaic_Numbers          ; Sinhala_Archaic_Numbers\nblk; Small_Forms                      ; Small_Form_Variants\nblk; Small_Kana_Ext                   ; Small_Kana_Extension\nblk; Sogdian                          ; Sogdian\nblk; Sora_Sompeng                     ; Sora_Sompeng\nblk; Soyombo                          ; Soyombo\nblk; Specials                         ; Specials\nblk; Sundanese                        ; Sundanese\nblk; Sundanese_Sup                    ; Sundanese_Supplement\nblk; Sunuwar                          ; Sunuwar\nblk; Sup_Arrows_A                     ; Supplemental_Arrows_A\nblk; Sup_Arrows_B                     ; Supplemental_Arrows_B\nblk; Sup_Arrows_C                     ; Supplemental_Arrows_C\nblk; Sup_Math_Operators               ; Supplemental_Mathematical_Operators\nblk; Sup_PUA_A                        ; Supplementary_Private_Use_Area_A\nblk; Sup_PUA_B                        ; Supplementary_Private_Use_Area_B\nblk; Sup_Punctuation                  ; Supplemental_Punctuation\nblk; Sup_Symbols_And_Pictographs      ; Supplemental_Symbols_And_Pictographs\nblk; Super_And_Sub                    ; Superscripts_And_Subscripts\nblk; Sutton_SignWriting               ; Sutton_SignWriting\nblk; Syloti_Nagri                     ; Syloti_Nagri\nblk; Symbols_And_Pictographs_Ext_A    ; Symbols_And_Pictographs_Extended_A\nblk; Symbols_For_Legacy_Computing     ; Symbols_For_Legacy_Computing\nblk; Symbols_For_Legacy_Computing_Sup ; Symbols_For_Legacy_Computing_Supplement\nblk; Syriac                           ; Syriac\nblk; Syriac_Sup                       ; Syriac_Supplement\nblk; Tagalog                          ; Tagalog\nblk; Tagbanwa                         ; Tagbanwa\nblk; Tags                             ; Tags\nblk; Tai_Le                           ; Tai_Le\nblk; Tai_Tham                         ; Tai_Tham\nblk; Tai_Viet                         ; Tai_Viet\nblk; Tai_Xuan_Jing                    ; Tai_Xuan_Jing_Symbols\nblk; Tai_Yo                           ; Tai_Yo\nblk; Takri                            ; Takri\nblk; Tamil                            ; Tamil\nblk; Tamil_Sup                        ; Tamil_Supplement\nblk; Tangsa                           ; Tangsa\nblk; Tangut                           ; Tangut\nblk; Tangut_Components                ; Tangut_Components\nblk; Tangut_Components_Sup            ; Tangut_Components_Supplement\nblk; Tangut_Sup                       ; Tangut_Supplement\nblk; Telugu                           ; Telugu\nblk; Thaana                           ; Thaana\nblk; Thai                             ; Thai\nblk; Tibetan                          ; Tibetan\nblk; Tifinagh                         ; Tifinagh\nblk; Tirhuta                          ; Tirhuta\nblk; Todhri                           ; Todhri\nblk; Tolong_Siki                      ; Tolong_Siki\nblk; Toto                             ; Toto\nblk; Transport_And_Map                ; Transport_And_Map_Symbols\nblk; Tulu_Tigalari                    ; Tulu_Tigalari\nblk; UCAS                             ; Unified_Canadian_Aboriginal_Syllabics; Canadian_Syllabics\nblk; UCAS_Ext                         ; Unified_Canadian_Aboriginal_Syllabics_Extended\nblk; UCAS_Ext_A                       ; Unified_Canadian_Aboriginal_Syllabics_Extended_A\nblk; Ugaritic                         ; Ugaritic\nblk; Vai                              ; Vai\nblk; Vedic_Ext                        ; Vedic_Extensions\nblk; Vertical_Forms                   ; Vertical_Forms\nblk; Vithkuqi                         ; Vithkuqi\nblk; VS                               ; Variation_Selectors\nblk; VS_Sup                           ; Variation_Selectors_Supplement\nblk; Wancho                           ; Wancho\nblk; Warang_Citi                      ; Warang_Citi\nblk; Yezidi                           ; Yezidi\nblk; Yi_Radicals                      ; Yi_Radicals\nblk; Yi_Syllables                     ; Yi_Syllables\nblk; Yijing                           ; Yijing_Hexagram_Symbols\nblk; Zanabazar_Square                 ; Zanabazar_Square\nblk; Znamenny_Music                   ; Znamenny_Musical_Notation\n\n# Canonical_Combining_Class (ccc)\n\nccc;   0; NR                         ; Not_Reordered\nccc;   1; OV                         ; Overlay\nccc;   6; HANR                       ; Han_Reading\nccc;   7; NK                         ; Nukta\nccc;   8; KV                         ; Kana_Voicing\nccc;   9; VR                         ; Virama\nccc;  10; CCC10                      ; CCC10\nccc;  11; CCC11                      ; CCC11\nccc;  12; CCC12                      ; CCC12\nccc;  13; CCC13                      ; CCC13\nccc;  14; CCC14                      ; CCC14\nccc;  15; CCC15                      ; CCC15\nccc;  16; CCC16                      ; CCC16\nccc;  17; CCC17                      ; CCC17\nccc;  18; CCC18                      ; CCC18\nccc;  19; CCC19                      ; CCC19\nccc;  20; CCC20                      ; CCC20\nccc;  21; CCC21                      ; CCC21\nccc;  22; CCC22                      ; CCC22\nccc;  23; CCC23                      ; CCC23\nccc;  24; CCC24                      ; CCC24\nccc;  25; CCC25                      ; CCC25\nccc;  26; CCC26                      ; CCC26\nccc;  27; CCC27                      ; CCC27\nccc;  28; CCC28                      ; CCC28\nccc;  29; CCC29                      ; CCC29\nccc;  30; CCC30                      ; CCC30\nccc;  31; CCC31                      ; CCC31\nccc;  32; CCC32                      ; CCC32\nccc;  33; CCC33                      ; CCC33\nccc;  34; CCC34                      ; CCC34\nccc;  35; CCC35                      ; CCC35\nccc;  36; CCC36                      ; CCC36\nccc;  84; CCC84                      ; CCC84\nccc;  91; CCC91                      ; CCC91\nccc; 103; CCC103                     ; CCC103\nccc; 107; CCC107                     ; CCC107\nccc; 118; CCC118                     ; CCC118\nccc; 122; CCC122                     ; CCC122\nccc; 129; CCC129                     ; CCC129\nccc; 130; CCC130                     ; CCC130\nccc; 132; CCC132                     ; CCC132\nccc; 133; CCC133                     ; CCC133 # RESERVED\nccc; 200; ATBL                       ; Attached_Below_Left\nccc; 202; ATB                        ; Attached_Below\nccc; 214; ATA                        ; Attached_Above\nccc; 216; ATAR                       ; Attached_Above_Right\nccc; 218; BL                         ; Below_Left\nccc; 220; B                          ; Below\nccc; 222; BR                         ; Below_Right\nccc; 224; L                          ; Left\nccc; 226; R                          ; Right\nccc; 228; AL                         ; Above_Left\nccc; 230; A                          ; Above\nccc; 232; AR                         ; Above_Right\nccc; 233; DB                         ; Double_Below\nccc; 234; DA                         ; Double_Above\nccc; 240; IS                         ; Iota_Subscript\n\n# Case_Folding (cf)\n\n# @missing: 0000..10FFFF; Case_Folding; <code point>\n\n# Case_Ignorable (CI)\n\nCI ; N                                ; No                               ; F                                ; False\nCI ; Y                                ; Yes                              ; T                                ; True\n\n# Cased (Cased)\n\nCased; N                              ; No                               ; F                                ; False\nCased; Y                              ; Yes                              ; T                                ; True\n\n# Changes_When_Casefolded (CWCF)\n\nCWCF; N                               ; No                               ; F                                ; False\nCWCF; Y                               ; Yes                              ; T                                ; True\n\n# Changes_When_Casemapped (CWCM)\n\nCWCM; N                               ; No                               ; F                                ; False\nCWCM; Y                               ; Yes                              ; T                                ; True\n\n# Changes_When_Lowercased (CWL)\n\nCWL; N                                ; No                               ; F                                ; False\nCWL; Y                                ; Yes                              ; T                                ; True\n\n# Changes_When_NFKC_Casefolded (CWKCF)\n\nCWKCF; N                              ; No                               ; F                                ; False\nCWKCF; Y                              ; Yes                              ; T                                ; True\n\n# Changes_When_Titlecased (CWT)\n\nCWT; N                                ; No                               ; F                                ; False\nCWT; Y                                ; Yes                              ; T                                ; True\n\n# Changes_When_Uppercased (CWU)\n\nCWU; N                                ; No                               ; F                                ; False\nCWU; Y                                ; Yes                              ; T                                ; True\n\n# Composition_Exclusion (CE)\n\nCE ; N                                ; No                               ; F                                ; False\nCE ; Y                                ; Yes                              ; T                                ; True\n\n# Dash (Dash)\n\nDash; N                               ; No                               ; F                                ; False\nDash; Y                               ; Yes                              ; T                                ; True\n\n# Decomposition_Mapping (dm)\n\n# @missing: 0000..10FFFF; Decomposition_Mapping; <code point>\n\n# Decomposition_Type (dt)\n\ndt ; Can                              ; Canonical                        ; can\ndt ; Com                              ; Compat                           ; com\ndt ; Enc                              ; Circle                           ; enc\ndt ; Fin                              ; Final                            ; fin\ndt ; Font                             ; Font                             ; font\ndt ; Fra                              ; Fraction                         ; fra\ndt ; Init                             ; Initial                          ; init\ndt ; Iso                              ; Isolated                         ; iso\ndt ; Med                              ; Medial                           ; med\ndt ; Nar                              ; Narrow                           ; nar\ndt ; Nb                               ; Nobreak                          ; nb\ndt ; None                             ; None                             ; none\ndt ; Sml                              ; Small                            ; sml\ndt ; Sqr                              ; Square                           ; sqr\ndt ; Sub                              ; Sub                              ; sub\ndt ; Sup                              ; Super                            ; sup\ndt ; Vert                             ; Vertical                         ; vert\ndt ; Wide                             ; Wide                             ; wide\n\n# Default_Ignorable_Code_Point (DI)\n\nDI ; N                                ; No                               ; F                                ; False\nDI ; Y                                ; Yes                              ; T                                ; True\n\n# Deprecated (Dep)\n\nDep; N                                ; No                               ; F                                ; False\nDep; Y                                ; Yes                              ; T                                ; True\n\n# Diacritic (Dia)\n\nDia; N                                ; No                               ; F                                ; False\nDia; Y                                ; Yes                              ; T                                ; True\n\n# East_Asian_Width (ea)\n\nea ; A                                ; Ambiguous\nea ; F                                ; Fullwidth\nea ; H                                ; Halfwidth\nea ; N                                ; Neutral\nea ; Na                               ; Narrow\nea ; W                                ; Wide\n\n# Emoji (Emoji)\n\nEmoji; N                              ; No                               ; F                                ; False\nEmoji; Y                              ; Yes                              ; T                                ; True\n\n# Emoji_Component (EComp)\n\nEComp; N                              ; No                               ; F                                ; False\nEComp; Y                              ; Yes                              ; T                                ; True\n\n# Emoji_Modifier (EMod)\n\nEMod; N                               ; No                               ; F                                ; False\nEMod; Y                               ; Yes                              ; T                                ; True\n\n# Emoji_Modifier_Base (EBase)\n\nEBase; N                              ; No                               ; F                                ; False\nEBase; Y                              ; Yes                              ; T                                ; True\n\n# Emoji_Presentation (EPres)\n\nEPres; N                              ; No                               ; F                                ; False\nEPres; Y                              ; Yes                              ; T                                ; True\n\n# Equivalent_Unified_Ideograph (EqUIdeo)\n\n\n# Expands_On_NFC (XO_NFC)\n\nXO_NFC; N                             ; No                               ; F                                ; False\nXO_NFC; Y                             ; Yes                              ; T                                ; True\n\n# Expands_On_NFD (XO_NFD)\n\nXO_NFD; N                             ; No                               ; F                                ; False\nXO_NFD; Y                             ; Yes                              ; T                                ; True\n\n# Expands_On_NFKC (XO_NFKC)\n\nXO_NFKC; N                            ; No                               ; F                                ; False\nXO_NFKC; Y                            ; Yes                              ; T                                ; True\n\n# Expands_On_NFKD (XO_NFKD)\n\nXO_NFKD; N                            ; No                               ; F                                ; False\nXO_NFKD; Y                            ; Yes                              ; T                                ; True\n\n# Extended_Pictographic (ExtPict)\n\nExtPict; N                            ; No                               ; F                                ; False\nExtPict; Y                            ; Yes                              ; T                                ; True\n\n# Extender (Ext)\n\nExt; N                                ; No                               ; F                                ; False\nExt; Y                                ; Yes                              ; T                                ; True\n\n# FC_NFKC_Closure (FC_NFKC)\n\n# @missing: 0000..10FFFF; FC_NFKC_Closure; <code point>\n\n# Full_Composition_Exclusion (Comp_Ex)\n\nComp_Ex; N                            ; No                               ; F                                ; False\nComp_Ex; Y                            ; Yes                              ; T                                ; True\n\n# General_Category (gc)\n\ngc ; C                                ; Other                            # Cc | Cf | Cn | Co | Cs\ngc ; Cc                               ; Control                          ; cntrl\ngc ; Cf                               ; Format\ngc ; Cn                               ; Unassigned\ngc ; Co                               ; Private_Use\ngc ; Cs                               ; Surrogate\ngc ; L                                ; Letter                           # Ll | Lm | Lo | Lt | Lu\ngc ; LC                               ; Cased_Letter                     # Ll | Lt | Lu\ngc ; Ll                               ; Lowercase_Letter\ngc ; Lm                               ; Modifier_Letter\ngc ; Lo                               ; Other_Letter\ngc ; Lt                               ; Titlecase_Letter\ngc ; Lu                               ; Uppercase_Letter\ngc ; M                                ; Mark                             ; Combining_Mark                   # Mc | Me | Mn\ngc ; Mc                               ; Spacing_Mark\ngc ; Me                               ; Enclosing_Mark\ngc ; Mn                               ; Nonspacing_Mark\ngc ; N                                ; Number                           # Nd | Nl | No\ngc ; Nd                               ; Decimal_Number                   ; digit\ngc ; Nl                               ; Letter_Number\ngc ; No                               ; Other_Number\ngc ; P                                ; Punctuation                      ; punct                            # Pc | Pd | Pe | Pf | Pi | Po | Ps\ngc ; Pc                               ; Connector_Punctuation\ngc ; Pd                               ; Dash_Punctuation\ngc ; Pe                               ; Close_Punctuation\ngc ; Pf                               ; Final_Punctuation\ngc ; Pi                               ; Initial_Punctuation\ngc ; Po                               ; Other_Punctuation\ngc ; Ps                               ; Open_Punctuation\ngc ; S                                ; Symbol                           # Sc | Sk | Sm | So\ngc ; Sc                               ; Currency_Symbol\ngc ; Sk                               ; Modifier_Symbol\ngc ; Sm                               ; Math_Symbol\ngc ; So                               ; Other_Symbol\ngc ; Z                                ; Separator                        # Zl | Zp | Zs\ngc ; Zl                               ; Line_Separator\ngc ; Zp                               ; Paragraph_Separator\ngc ; Zs                               ; Space_Separator\n# @missing: 0000..10FFFF; General_Category; Unassigned\n\n# Grapheme_Base (Gr_Base)\n\nGr_Base; N                            ; No                               ; F                                ; False\nGr_Base; Y                            ; Yes                              ; T                                ; True\n\n# Grapheme_Cluster_Break (GCB)\n\nGCB; CN                               ; Control\nGCB; CR                               ; CR\nGCB; EB                               ; E_Base\nGCB; EBG                              ; E_Base_GAZ\nGCB; EM                               ; E_Modifier\nGCB; EX                               ; Extend\nGCB; GAZ                              ; Glue_After_Zwj\nGCB; L                                ; L\nGCB; LF                               ; LF\nGCB; LV                               ; LV\nGCB; LVT                              ; LVT\nGCB; PP                               ; Prepend\nGCB; RI                               ; Regional_Indicator\nGCB; SM                               ; SpacingMark\nGCB; T                                ; T\nGCB; V                                ; V\nGCB; XX                               ; Other\nGCB; ZWJ                              ; ZWJ\n\n# Grapheme_Extend (Gr_Ext)\n\nGr_Ext; N                             ; No                               ; F                                ; False\nGr_Ext; Y                             ; Yes                              ; T                                ; True\n\n# Grapheme_Link (Gr_Link)\n\nGr_Link; N                            ; No                               ; F                                ; False\nGr_Link; Y                            ; Yes                              ; T                                ; True\n\n# Hangul_Syllable_Type (hst)\n\nhst; L                                ; Leading_Jamo\nhst; LV                               ; LV_Syllable\nhst; LVT                              ; LVT_Syllable\nhst; NA                               ; Not_Applicable\nhst; T                                ; Trailing_Jamo\nhst; V                                ; Vowel_Jamo\n\n# Hex_Digit (Hex)\n\nHex; N                                ; No                               ; F                                ; False\nHex; Y                                ; Yes                              ; T                                ; True\n\n# Hyphen (Hyphen)\n\nHyphen; N                             ; No                               ; F                                ; False\nHyphen; Y                             ; Yes                              ; T                                ; True\n\n# IDS_Binary_Operator (IDSB)\n\nIDSB; N                               ; No                               ; F                                ; False\nIDSB; Y                               ; Yes                              ; T                                ; True\n\n# IDS_Trinary_Operator (IDST)\n\nIDST; N                               ; No                               ; F                                ; False\nIDST; Y                               ; Yes                              ; T                                ; True\n\n# IDS_Unary_Operator (IDSU)\n\nIDSU; N                               ; No                               ; F                                ; False\nIDSU; Y                               ; Yes                              ; T                                ; True\n\n# ID_Compat_Math_Continue (ID_Compat_Math_Continue)\n\nID_Compat_Math_Continue; N            ; No                               ; F                                ; False\nID_Compat_Math_Continue; Y            ; Yes                              ; T                                ; True\n\n# ID_Compat_Math_Start (ID_Compat_Math_Start)\n\nID_Compat_Math_Start; N               ; No                               ; F                                ; False\nID_Compat_Math_Start; Y               ; Yes                              ; T                                ; True\n\n# ID_Continue (IDC)\n\nIDC; N                                ; No                               ; F                                ; False\nIDC; Y                                ; Yes                              ; T                                ; True\n\n# ID_Start (IDS)\n\nIDS; N                                ; No                               ; F                                ; False\nIDS; Y                                ; Yes                              ; T                                ; True\n\n# ISO_Comment (isc)\n\n# @missing: 0000..10FFFF; ISO_Comment; <none>\n\n# Ideographic (Ideo)\n\nIdeo; N                               ; No                               ; F                                ; False\nIdeo; Y                               ; Yes                              ; T                                ; True\n\n# Indic_Conjunct_Break (InCB)\n\nInCB; Consonant                       ; Consonant\nInCB; Extend                          ; Extend\nInCB; Linker                          ; Linker\nInCB; None                            ; None\n\n# Indic_Positional_Category (InPC)\n\nInPC; Bottom                          ; Bottom\nInPC; Bottom_And_Left                 ; Bottom_And_Left\nInPC; Bottom_And_Right                ; Bottom_And_Right\nInPC; Left                            ; Left\nInPC; Left_And_Right                  ; Left_And_Right\nInPC; NA                              ; Not_Applicable\nInPC; Overstruck                      ; Overstruck\nInPC; Right                           ; Right\nInPC; Top                             ; Top\nInPC; Top_And_Bottom                  ; Top_And_Bottom\nInPC; Top_And_Bottom_And_Left         ; Top_And_Bottom_And_Left\nInPC; Top_And_Bottom_And_Right        ; Top_And_Bottom_And_Right\nInPC; Top_And_Left                    ; Top_And_Left\nInPC; Top_And_Left_And_Right          ; Top_And_Left_And_Right\nInPC; Top_And_Right                   ; Top_And_Right\nInPC; Visual_Order_Left               ; Visual_Order_Left\n\n# Indic_Syllabic_Category (InSC)\n\nInSC; Avagraha                        ; Avagraha\nInSC; Bindu                           ; Bindu\nInSC; Brahmi_Joining_Number           ; Brahmi_Joining_Number\nInSC; Cantillation_Mark               ; Cantillation_Mark\nInSC; Consonant                       ; Consonant\nInSC; Consonant_Dead                  ; Consonant_Dead\nInSC; Consonant_Final                 ; Consonant_Final\nInSC; Consonant_Head_Letter           ; Consonant_Head_Letter\nInSC; Consonant_Initial_Postfixed     ; Consonant_Initial_Postfixed\nInSC; Consonant_Killer                ; Consonant_Killer\nInSC; Consonant_Medial                ; Consonant_Medial\nInSC; Consonant_Placeholder           ; Consonant_Placeholder\nInSC; Consonant_Preceding_Repha       ; Consonant_Preceding_Repha\nInSC; Consonant_Prefixed              ; Consonant_Prefixed\nInSC; Consonant_Subjoined             ; Consonant_Subjoined\nInSC; Consonant_Succeeding_Repha      ; Consonant_Succeeding_Repha\nInSC; Consonant_With_Stacker          ; Consonant_With_Stacker\nInSC; Gemination_Mark                 ; Gemination_Mark\nInSC; Invisible_Stacker               ; Invisible_Stacker\nInSC; Joiner                          ; Joiner\nInSC; Modifying_Letter                ; Modifying_Letter\nInSC; Non_Joiner                      ; Non_Joiner\nInSC; Nukta                           ; Nukta\nInSC; Number                          ; Number\nInSC; Number_Joiner                   ; Number_Joiner\nInSC; Other                           ; Other\nInSC; Pure_Killer                     ; Pure_Killer\nInSC; Register_Shifter                ; Register_Shifter\nInSC; Reordering_Killer               ; Reordering_Killer\nInSC; Syllable_Modifier               ; Syllable_Modifier\nInSC; Tone_Letter                     ; Tone_Letter\nInSC; Tone_Mark                       ; Tone_Mark\nInSC; Virama                          ; Virama\nInSC; Visarga                         ; Visarga\nInSC; Vowel                           ; Vowel\nInSC; Vowel_Dependent                 ; Vowel_Dependent\nInSC; Vowel_Independent               ; Vowel_Independent\n\n# Jamo_Short_Name (JSN)\n\nJSN; A                                ; A\nJSN; AE                               ; AE\nJSN; B                                ; B\nJSN; BB                               ; BB\nJSN; BS                               ; BS\nJSN; C                                ; C\nJSN; D                                ; D\nJSN; DD                               ; DD\nJSN; E                                ; E\nJSN; EO                               ; EO\nJSN; EU                               ; EU\nJSN; G                                ; G\nJSN; GG                               ; GG\nJSN; GS                               ; GS\nJSN; H                                ; H\nJSN; I                                ; I\nJSN; J                                ; J\nJSN; JJ                               ; JJ\nJSN; K                                ; K\nJSN; L                                ; L\nJSN; LB                               ; LB\nJSN; LG                               ; LG\nJSN; LH                               ; LH\nJSN; LM                               ; LM\nJSN; LP                               ; LP\nJSN; LS                               ; LS\nJSN; LT                               ; LT\nJSN; M                                ; M\nJSN; N                                ; N\nJSN; NG                               ; NG\nJSN; NH                               ; NH\nJSN; NJ                               ; NJ\nJSN; O                                ; O\nJSN; OE                               ; OE\nJSN; P                                ; P\nJSN; R                                ; R\nJSN; S                                ; S\nJSN; SS                               ; SS\nJSN; T                                ; T\nJSN; U                                ; U\nJSN; WA                               ; WA\nJSN; WAE                              ; WAE\nJSN; WE                               ; WE\nJSN; WEO                              ; WEO\nJSN; WI                               ; WI\nJSN; YA                               ; YA\nJSN; YAE                              ; YAE\nJSN; YE                               ; YE\nJSN; YEO                              ; YEO\nJSN; YI                               ; YI\nJSN; YO                               ; YO\nJSN; YU                               ; YU\n# @missing: 0000..10FFFF; Jamo_Short_Name; <none>\n\n# Join_Control (Join_C)\n\nJoin_C; N                             ; No                               ; F                                ; False\nJoin_C; Y                             ; Yes                              ; T                                ; True\n\n# Joining_Group (jg)\n\njg ; African_Feh                      ; African_Feh\njg ; African_Noon                     ; African_Noon\njg ; African_Qaf                      ; African_Qaf\njg ; Ain                              ; Ain\njg ; Alaph                            ; Alaph\njg ; Alef                             ; Alef\njg ; Beh                              ; Beh\njg ; Beth                             ; Beth\njg ; Burushaski_Yeh_Barree            ; Burushaski_Yeh_Barree\njg ; Dal                              ; Dal\njg ; Dalath_Rish                      ; Dalath_Rish\njg ; E                                ; E\njg ; Farsi_Yeh                        ; Farsi_Yeh\njg ; Fe                               ; Fe\njg ; Feh                              ; Feh\njg ; Final_Semkath                    ; Final_Semkath\njg ; Gaf                              ; Gaf\njg ; Gamal                            ; Gamal\njg ; Hah                              ; Hah\njg ; Hanifi_Rohingya_Kinna_Ya         ; Hanifi_Rohingya_Kinna_Ya\njg ; Hanifi_Rohingya_Pa               ; Hanifi_Rohingya_Pa\njg ; He                               ; He\njg ; Heh                              ; Heh\njg ; Heh_Goal                         ; Heh_Goal\njg ; Heth                             ; Heth\njg ; Kaf                              ; Kaf\njg ; Kaph                             ; Kaph\njg ; Kashmiri_Yeh                     ; Kashmiri_Yeh\njg ; Khaph                            ; Khaph\njg ; Knotted_Heh                      ; Knotted_Heh\njg ; Lam                              ; Lam\njg ; Lamadh                           ; Lamadh\njg ; Malayalam_Bha                    ; Malayalam_Bha\njg ; Malayalam_Ja                     ; Malayalam_Ja\njg ; Malayalam_Lla                    ; Malayalam_Lla\njg ; Malayalam_Llla                   ; Malayalam_Llla\njg ; Malayalam_Nga                    ; Malayalam_Nga\njg ; Malayalam_Nna                    ; Malayalam_Nna\njg ; Malayalam_Nnna                   ; Malayalam_Nnna\njg ; Malayalam_Nya                    ; Malayalam_Nya\njg ; Malayalam_Ra                     ; Malayalam_Ra\njg ; Malayalam_Ssa                    ; Malayalam_Ssa\njg ; Malayalam_Tta                    ; Malayalam_Tta\njg ; Manichaean_Aleph                 ; Manichaean_Aleph\njg ; Manichaean_Ayin                  ; Manichaean_Ayin\njg ; Manichaean_Beth                  ; Manichaean_Beth\njg ; Manichaean_Daleth                ; Manichaean_Daleth\njg ; Manichaean_Dhamedh               ; Manichaean_Dhamedh\njg ; Manichaean_Five                  ; Manichaean_Five\njg ; Manichaean_Gimel                 ; Manichaean_Gimel\njg ; Manichaean_Heth                  ; Manichaean_Heth\njg ; Manichaean_Hundred               ; Manichaean_Hundred\njg ; Manichaean_Kaph                  ; Manichaean_Kaph\njg ; Manichaean_Lamedh                ; Manichaean_Lamedh\njg ; Manichaean_Mem                   ; Manichaean_Mem\njg ; Manichaean_Nun                   ; Manichaean_Nun\njg ; Manichaean_One                   ; Manichaean_One\njg ; Manichaean_Pe                    ; Manichaean_Pe\njg ; Manichaean_Qoph                  ; Manichaean_Qoph\njg ; Manichaean_Resh                  ; Manichaean_Resh\njg ; Manichaean_Sadhe                 ; Manichaean_Sadhe\njg ; Manichaean_Samekh                ; Manichaean_Samekh\njg ; Manichaean_Taw                   ; Manichaean_Taw\njg ; Manichaean_Ten                   ; Manichaean_Ten\njg ; Manichaean_Teth                  ; Manichaean_Teth\njg ; Manichaean_Thamedh               ; Manichaean_Thamedh\njg ; Manichaean_Twenty                ; Manichaean_Twenty\njg ; Manichaean_Waw                   ; Manichaean_Waw\njg ; Manichaean_Yodh                  ; Manichaean_Yodh\njg ; Manichaean_Zayin                 ; Manichaean_Zayin\njg ; Meem                             ; Meem\njg ; Mim                              ; Mim\njg ; No_Joining_Group                 ; No_Joining_Group\njg ; Noon                             ; Noon\njg ; Nun                              ; Nun\njg ; Nya                              ; Nya\njg ; Pe                               ; Pe\njg ; Qaf                              ; Qaf\njg ; Qaph                             ; Qaph\njg ; Reh                              ; Reh\njg ; Reversed_Pe                      ; Reversed_Pe\njg ; Rohingya_Yeh                     ; Rohingya_Yeh\njg ; Sad                              ; Sad\njg ; Sadhe                            ; Sadhe\njg ; Seen                             ; Seen\njg ; Semkath                          ; Semkath\njg ; Shin                             ; Shin\njg ; Straight_Waw                     ; Straight_Waw\njg ; Swash_Kaf                        ; Swash_Kaf\njg ; Syriac_Waw                       ; Syriac_Waw\njg ; Tah                              ; Tah\njg ; Taw                              ; Taw\njg ; Teh_Marbuta                      ; Teh_Marbuta\njg ; Teh_Marbuta_Goal                 ; Teh_Marbuta_Goal                 ; Hamza_On_Heh_Goal\njg ; Teth                             ; Teth\njg ; Thin_Noon                        ; Thin_Noon\njg ; Thin_Yeh                         ; Thin_Yeh\njg ; Vertical_Tail                    ; Vertical_Tail\njg ; Waw                              ; Waw\njg ; Yeh                              ; Yeh\njg ; Yeh_Barree                       ; Yeh_Barree\njg ; Yeh_With_Tail                    ; Yeh_With_Tail\njg ; Yudh                             ; Yudh\njg ; Yudh_He                          ; Yudh_He\njg ; Zain                             ; Zain\njg ; Zhain                            ; Zhain\n\n# Joining_Type (jt)\n\njt ; C                                ; Join_Causing\njt ; D                                ; Dual_Joining\njt ; L                                ; Left_Joining\njt ; R                                ; Right_Joining\njt ; T                                ; Transparent\njt ; U                                ; Non_Joining\n\n# Line_Break (lb)\n\nlb ; AI                               ; Ambiguous\nlb ; AK                               ; Aksara\nlb ; AL                               ; Alphabetic\nlb ; AP                               ; Aksara_Prebase\nlb ; AS                               ; Aksara_Start\nlb ; B2                               ; Break_Both\nlb ; BA                               ; Break_After\nlb ; BB                               ; Break_Before\nlb ; BK                               ; Mandatory_Break\nlb ; CB                               ; Contingent_Break\nlb ; CJ                               ; Conditional_Japanese_Starter\nlb ; CL                               ; Close_Punctuation\nlb ; CM                               ; Combining_Mark\nlb ; CP                               ; Close_Parenthesis\nlb ; CR                               ; Carriage_Return\nlb ; EB                               ; E_Base\nlb ; EM                               ; E_Modifier\nlb ; EX                               ; Exclamation\nlb ; GL                               ; Glue\nlb ; H2                               ; H2\nlb ; H3                               ; H3\nlb ; HH                               ; Unambiguous_Hyphen\nlb ; HL                               ; Hebrew_Letter\nlb ; HY                               ; Hyphen\nlb ; ID                               ; Ideographic\nlb ; IN                               ; Inseparable                      ; Inseperable\nlb ; IS                               ; Infix_Numeric\nlb ; JL                               ; JL\nlb ; JT                               ; JT\nlb ; JV                               ; JV\nlb ; LF                               ; Line_Feed\nlb ; NL                               ; Next_Line\nlb ; NS                               ; Nonstarter\nlb ; NU                               ; Numeric\nlb ; OP                               ; Open_Punctuation\nlb ; PO                               ; Postfix_Numeric\nlb ; PR                               ; Prefix_Numeric\nlb ; QU                               ; Quotation\nlb ; RI                               ; Regional_Indicator\nlb ; SA                               ; Complex_Context\nlb ; SG                               ; Surrogate\nlb ; SP                               ; Space\nlb ; SY                               ; Break_Symbols\nlb ; VF                               ; Virama_Final\nlb ; VI                               ; Virama\nlb ; WJ                               ; Word_Joiner\nlb ; XX                               ; Unknown\nlb ; ZW                               ; ZWSpace\nlb ; ZWJ                              ; ZWJ\n\n# Logical_Order_Exception (LOE)\n\nLOE; N                                ; No                               ; F                                ; False\nLOE; Y                                ; Yes                              ; T                                ; True\n\n# Lowercase (Lower)\n\nLower; N                              ; No                               ; F                                ; False\nLower; Y                              ; Yes                              ; T                                ; True\n\n# Lowercase_Mapping (lc)\n\n# @missing: 0000..10FFFF; Lowercase_Mapping; <code point>\n\n# Math (Math)\n\nMath; N                               ; No                               ; F                                ; False\nMath; Y                               ; Yes                              ; T                                ; True\n\n# Modifier_Combining_Mark (MCM)\n\nMCM; N                                ; No                               ; F                                ; False\nMCM; Y                                ; Yes                              ; T                                ; True\n\n# NFC_Quick_Check (NFC_QC)\n\nNFC_QC; M                             ; Maybe\nNFC_QC; N                             ; No\nNFC_QC; Y                             ; Yes\n\n# NFD_Quick_Check (NFD_QC)\n\nNFD_QC; N                             ; No\nNFD_QC; Y                             ; Yes\n\n# NFKC_Casefold (NFKC_CF)\n\n\n# NFKC_Quick_Check (NFKC_QC)\n\nNFKC_QC; M                            ; Maybe\nNFKC_QC; N                            ; No\nNFKC_QC; Y                            ; Yes\n\n# NFKC_Simple_Casefold (NFKC_SCF)\n\n\n# NFKD_Quick_Check (NFKD_QC)\n\nNFKD_QC; N                            ; No\nNFKD_QC; Y                            ; Yes\n\n# Name (na)\n\n# @missing: 0000..10FFFF; Name; <none>\n\n# Name_Alias (Name_Alias)\n\n# @missing: 0000..10FFFF; Name_Alias; <none>\n\n# Noncharacter_Code_Point (NChar)\n\nNChar; N                              ; No                               ; F                                ; False\nNChar; Y                              ; Yes                              ; T                                ; True\n\n# Numeric_Type (nt)\n\nnt ; De                               ; Decimal\nnt ; Di                               ; Digit\nnt ; None                             ; None\nnt ; Nu                               ; Numeric\n\n# Numeric_Value (nv)\n\n# @missing: 0000..10FFFF; Numeric_Value; NaN\n\n# Other_Alphabetic (OAlpha)\n\nOAlpha; N                             ; No                               ; F                                ; False\nOAlpha; Y                             ; Yes                              ; T                                ; True\n\n# Other_Default_Ignorable_Code_Point (ODI)\n\nODI; N                                ; No                               ; F                                ; False\nODI; Y                                ; Yes                              ; T                                ; True\n\n# Other_Grapheme_Extend (OGr_Ext)\n\nOGr_Ext; N                            ; No                               ; F                                ; False\nOGr_Ext; Y                            ; Yes                              ; T                                ; True\n\n# Other_ID_Continue (OIDC)\n\nOIDC; N                               ; No                               ; F                                ; False\nOIDC; Y                               ; Yes                              ; T                                ; True\n\n# Other_ID_Start (OIDS)\n\nOIDS; N                               ; No                               ; F                                ; False\nOIDS; Y                               ; Yes                              ; T                                ; True\n\n# Other_Lowercase (OLower)\n\nOLower; N                             ; No                               ; F                                ; False\nOLower; Y                             ; Yes                              ; T                                ; True\n\n# Other_Math (OMath)\n\nOMath; N                              ; No                               ; F                                ; False\nOMath; Y                              ; Yes                              ; T                                ; True\n\n# Other_Uppercase (OUpper)\n\nOUpper; N                             ; No                               ; F                                ; False\nOUpper; Y                             ; Yes                              ; T                                ; True\n\n# Pattern_Syntax (Pat_Syn)\n\nPat_Syn; N                            ; No                               ; F                                ; False\nPat_Syn; Y                            ; Yes                              ; T                                ; True\n\n# Pattern_White_Space (Pat_WS)\n\nPat_WS; N                             ; No                               ; F                                ; False\nPat_WS; Y                             ; Yes                              ; T                                ; True\n\n# Prepended_Concatenation_Mark (PCM)\n\nPCM; N                                ; No                               ; F                                ; False\nPCM; Y                                ; Yes                              ; T                                ; True\n\n# Quotation_Mark (QMark)\n\nQMark; N                              ; No                               ; F                                ; False\nQMark; Y                              ; Yes                              ; T                                ; True\n\n# Radical (Radical)\n\nRadical; N                            ; No                               ; F                                ; False\nRadical; Y                            ; Yes                              ; T                                ; True\n\n# Regional_Indicator (RI)\n\nRI ; N                                ; No                               ; F                                ; False\nRI ; Y                                ; Yes                              ; T                                ; True\n\n# Script (sc)\n\nsc ; Adlm                             ; Adlam\nsc ; Aghb                             ; Caucasian_Albanian\nsc ; Ahom                             ; Ahom\nsc ; Arab                             ; Arabic\nsc ; Armi                             ; Imperial_Aramaic\nsc ; Armn                             ; Armenian\nsc ; Avst                             ; Avestan\nsc ; Bali                             ; Balinese\nsc ; Bamu                             ; Bamum\nsc ; Bass                             ; Bassa_Vah\nsc ; Batk                             ; Batak\nsc ; Beng                             ; Bengali\nsc ; Berf                             ; Beria_Erfe\nsc ; Bhks                             ; Bhaiksuki\nsc ; Bopo                             ; Bopomofo\nsc ; Brah                             ; Brahmi\nsc ; Brai                             ; Braille\nsc ; Bugi                             ; Buginese\nsc ; Buhd                             ; Buhid\nsc ; Cakm                             ; Chakma\nsc ; Cans                             ; Canadian_Aboriginal\nsc ; Cari                             ; Carian\nsc ; Cham                             ; Cham\nsc ; Cher                             ; Cherokee\nsc ; Chrs                             ; Chorasmian\nsc ; Copt                             ; Coptic                           ; Qaac\nsc ; Cpmn                             ; Cypro_Minoan\nsc ; Cprt                             ; Cypriot\nsc ; Cyrl                             ; Cyrillic\nsc ; Deva                             ; Devanagari\nsc ; Diak                             ; Dives_Akuru\nsc ; Dogr                             ; Dogra\nsc ; Dsrt                             ; Deseret\nsc ; Dupl                             ; Duployan\nsc ; Egyp                             ; Egyptian_Hieroglyphs\nsc ; Elba                             ; Elbasan\nsc ; Elym                             ; Elymaic\nsc ; Ethi                             ; Ethiopic\nsc ; Gara                             ; Garay\nsc ; Geor                             ; Georgian\nsc ; Glag                             ; Glagolitic\nsc ; Gong                             ; Gunjala_Gondi\nsc ; Gonm                             ; Masaram_Gondi\nsc ; Goth                             ; Gothic\nsc ; Gran                             ; Grantha\nsc ; Grek                             ; Greek\nsc ; Gujr                             ; Gujarati\nsc ; Gukh                             ; Gurung_Khema\nsc ; Guru                             ; Gurmukhi\nsc ; Hang                             ; Hangul\nsc ; Hani                             ; Han\nsc ; Hano                             ; Hanunoo\nsc ; Hatr                             ; Hatran\nsc ; Hebr                             ; Hebrew\nsc ; Hira                             ; Hiragana\nsc ; Hluw                             ; Anatolian_Hieroglyphs\nsc ; Hmng                             ; Pahawh_Hmong\nsc ; Hmnp                             ; Nyiakeng_Puachue_Hmong\nsc ; Hrkt                             ; Katakana_Or_Hiragana\nsc ; Hung                             ; Old_Hungarian\nsc ; Ital                             ; Old_Italic\nsc ; Java                             ; Javanese\nsc ; Kali                             ; Kayah_Li\nsc ; Kana                             ; Katakana\nsc ; Kawi                             ; Kawi\nsc ; Khar                             ; Kharoshthi\nsc ; Khmr                             ; Khmer\nsc ; Khoj                             ; Khojki\nsc ; Kits                             ; Khitan_Small_Script\nsc ; Knda                             ; Kannada\nsc ; Krai                             ; Kirat_Rai\nsc ; Kthi                             ; Kaithi\nsc ; Lana                             ; Tai_Tham\nsc ; Laoo                             ; Lao\nsc ; Latn                             ; Latin\nsc ; Lepc                             ; Lepcha\nsc ; Limb                             ; Limbu\nsc ; Lina                             ; Linear_A\nsc ; Linb                             ; Linear_B\nsc ; Lisu                             ; Lisu\nsc ; Lyci                             ; Lycian\nsc ; Lydi                             ; Lydian\nsc ; Mahj                             ; Mahajani\nsc ; Maka                             ; Makasar\nsc ; Mand                             ; Mandaic\nsc ; Mani                             ; Manichaean\nsc ; Marc                             ; Marchen\nsc ; Medf                             ; Medefaidrin\nsc ; Mend                             ; Mende_Kikakui\nsc ; Merc                             ; Meroitic_Cursive\nsc ; Mero                             ; Meroitic_Hieroglyphs\nsc ; Mlym                             ; Malayalam\nsc ; Modi                             ; Modi\nsc ; Mong                             ; Mongolian\nsc ; Mroo                             ; Mro\nsc ; Mtei                             ; Meetei_Mayek\nsc ; Mult                             ; Multani\nsc ; Mymr                             ; Myanmar\nsc ; Nagm                             ; Nag_Mundari\nsc ; Nand                             ; Nandinagari\nsc ; Narb                             ; Old_North_Arabian\nsc ; Nbat                             ; Nabataean\nsc ; Newa                             ; Newa\nsc ; Nkoo                             ; Nko\nsc ; Nshu                             ; Nushu\nsc ; Ogam                             ; Ogham\nsc ; Olck                             ; Ol_Chiki\nsc ; Onao                             ; Ol_Onal\nsc ; Orkh                             ; Old_Turkic\nsc ; Orya                             ; Oriya\nsc ; Osge                             ; Osage\nsc ; Osma                             ; Osmanya\nsc ; Ougr                             ; Old_Uyghur\nsc ; Palm                             ; Palmyrene\nsc ; Pauc                             ; Pau_Cin_Hau\nsc ; Perm                             ; Old_Permic\nsc ; Phag                             ; Phags_Pa\nsc ; Phli                             ; Inscriptional_Pahlavi\nsc ; Phlp                             ; Psalter_Pahlavi\nsc ; Phnx                             ; Phoenician\nsc ; Plrd                             ; Miao\nsc ; Prti                             ; Inscriptional_Parthian\nsc ; Rjng                             ; Rejang\nsc ; Rohg                             ; Hanifi_Rohingya\nsc ; Runr                             ; Runic\nsc ; Samr                             ; Samaritan\nsc ; Sarb                             ; Old_South_Arabian\nsc ; Saur                             ; Saurashtra\nsc ; Sgnw                             ; SignWriting\nsc ; Shaw                             ; Shavian\nsc ; Shrd                             ; Sharada\nsc ; Sidd                             ; Siddham\nsc ; Sidt                             ; Sidetic\nsc ; Sind                             ; Khudawadi\nsc ; Sinh                             ; Sinhala\nsc ; Sogd                             ; Sogdian\nsc ; Sogo                             ; Old_Sogdian\nsc ; Sora                             ; Sora_Sompeng\nsc ; Soyo                             ; Soyombo\nsc ; Sund                             ; Sundanese\nsc ; Sunu                             ; Sunuwar\nsc ; Sylo                             ; Syloti_Nagri\nsc ; Syrc                             ; Syriac\nsc ; Tagb                             ; Tagbanwa\nsc ; Takr                             ; Takri\nsc ; Tale                             ; Tai_Le\nsc ; Talu                             ; New_Tai_Lue\nsc ; Taml                             ; Tamil\nsc ; Tang                             ; Tangut\nsc ; Tavt                             ; Tai_Viet\nsc ; Tayo                             ; Tai_Yo\nsc ; Telu                             ; Telugu\nsc ; Tfng                             ; Tifinagh\nsc ; Tglg                             ; Tagalog\nsc ; Thaa                             ; Thaana\nsc ; Thai                             ; Thai\nsc ; Tibt                             ; Tibetan\nsc ; Tirh                             ; Tirhuta\nsc ; Tnsa                             ; Tangsa\nsc ; Todr                             ; Todhri\nsc ; Tols                             ; Tolong_Siki\nsc ; Toto                             ; Toto\nsc ; Tutg                             ; Tulu_Tigalari\nsc ; Ugar                             ; Ugaritic\nsc ; Vaii                             ; Vai\nsc ; Vith                             ; Vithkuqi\nsc ; Wara                             ; Warang_Citi\nsc ; Wcho                             ; Wancho\nsc ; Xpeo                             ; Old_Persian\nsc ; Xsux                             ; Cuneiform\nsc ; Yezi                             ; Yezidi\nsc ; Yiii                             ; Yi\nsc ; Zanb                             ; Zanabazar_Square\nsc ; Zinh                             ; Inherited                        ; Qaai\nsc ; Zyyy                             ; Common\nsc ; Zzzz                             ; Unknown\n\n# Script_Extensions (scx)\n\n\n# Sentence_Break (SB)\n\nSB ; AT                               ; ATerm\nSB ; CL                               ; Close\nSB ; CR                               ; CR\nSB ; EX                               ; Extend\nSB ; FO                               ; Format\nSB ; LE                               ; OLetter\nSB ; LF                               ; LF\nSB ; LO                               ; Lower\nSB ; NU                               ; Numeric\nSB ; SC                               ; SContinue\nSB ; SE                               ; Sep\nSB ; SP                               ; Sp\nSB ; ST                               ; STerm\nSB ; UP                               ; Upper\nSB ; XX                               ; Other\n\n# Sentence_Terminal (STerm)\n\nSTerm; N                              ; No                               ; F                                ; False\nSTerm; Y                              ; Yes                              ; T                                ; True\n\n# Simple_Case_Folding (scf)\n\n# @missing: 0000..10FFFF; Simple_Case_Folding; <code point>\n\n# Simple_Lowercase_Mapping (slc)\n\n# @missing: 0000..10FFFF; Simple_Lowercase_Mapping; <code point>\n\n# Simple_Titlecase_Mapping (stc)\n\n# @missing: 0000..10FFFF; Simple_Titlecase_Mapping; <code point>\n\n# Simple_Uppercase_Mapping (suc)\n\n# @missing: 0000..10FFFF; Simple_Uppercase_Mapping; <code point>\n\n# Soft_Dotted (SD)\n\nSD ; N                                ; No                               ; F                                ; False\nSD ; Y                                ; Yes                              ; T                                ; True\n\n# Terminal_Punctuation (Term)\n\nTerm; N                               ; No                               ; F                                ; False\nTerm; Y                               ; Yes                              ; T                                ; True\n\n# Titlecase_Mapping (tc)\n\n# @missing: 0000..10FFFF; Titlecase_Mapping; <code point>\n\n# Unicode_1_Name (na1)\n\n# @missing: 0000..10FFFF; Unicode_1_Name; <none>\n\n# Unified_Ideograph (UIdeo)\n\nUIdeo; N                              ; No                               ; F                                ; False\nUIdeo; Y                              ; Yes                              ; T                                ; True\n\n# Uppercase (Upper)\n\nUpper; N                              ; No                               ; F                                ; False\nUpper; Y                              ; Yes                              ; T                                ; True\n\n# Uppercase_Mapping (uc)\n\n# @missing: 0000..10FFFF; Uppercase_Mapping; <code point>\n\n# Variation_Selector (VS)\n\nVS ; N                                ; No                               ; F                                ; False\nVS ; Y                                ; Yes                              ; T                                ; True\n\n# Vertical_Orientation (vo)\n\nvo ; R                                ; Rotated\nvo ; Tr                               ; Transformed_Rotated\nvo ; Tu                               ; Transformed_Upright\nvo ; U                                ; Upright\n\n# White_Space (WSpace)\n\nWSpace; N                             ; No                               ; F                                ; False\nWSpace; Y                             ; Yes                              ; T                                ; True\n\n# Word_Break (WB)\n\nWB ; CR                               ; CR\nWB ; DQ                               ; Double_Quote\nWB ; EB                               ; E_Base\nWB ; EBG                              ; E_Base_GAZ\nWB ; EM                               ; E_Modifier\nWB ; EX                               ; ExtendNumLet\nWB ; Extend                           ; Extend\nWB ; FO                               ; Format\nWB ; GAZ                              ; Glue_After_Zwj\nWB ; HL                               ; Hebrew_Letter\nWB ; KA                               ; Katakana\nWB ; LE                               ; ALetter\nWB ; LF                               ; LF\nWB ; MB                               ; MidNumLet\nWB ; ML                               ; MidLetter\nWB ; MN                               ; MidNum\nWB ; NL                               ; Newline\nWB ; NU                               ; Numeric\nWB ; RI                               ; Regional_Indicator\nWB ; SQ                               ; Single_Quote\nWB ; WSegSpace                        ; WSegSpace\nWB ; XX                               ; Other\nWB ; ZWJ                              ; ZWJ\n\n# XID_Continue (XIDC)\n\nXIDC; N                               ; No                               ; F                                ; False\nXIDC; Y                               ; Yes                              ; T                                ; True\n\n# XID_Start (XIDS)\n\nXIDS; N                               ; No                               ; F                                ; False\nXIDS; Y                               ; Yes                              ; T                                ; True\n\n# cjkAccountingNumeric (cjkAccountingNumeric)\n\n# @missing: 0000..10FFFF; cjkAccountingNumeric; NaN\n\n# cjkCompatibilityVariant (cjkCompatibilityVariant)\n\n# @missing: 0000..10FFFF; cjkCompatibilityVariant; <code point>\n\n# cjkIICore (cjkIICore)\n\n# @missing: 0000..10FFFF; cjkIICore; <none>\n\n# cjkIRG_GSource (cjkIRG_GSource)\n\n# @missing: 0000..10FFFF; cjkIRG_GSource; <none>\n\n# cjkIRG_HSource (cjkIRG_HSource)\n\n# @missing: 0000..10FFFF; cjkIRG_HSource; <none>\n\n# cjkIRG_JSource (cjkIRG_JSource)\n\n# @missing: 0000..10FFFF; cjkIRG_JSource; <none>\n\n# cjkIRG_KPSource (cjkIRG_KPSource)\n\n# @missing: 0000..10FFFF; cjkIRG_KPSource; <none>\n\n# cjkIRG_KSource (cjkIRG_KSource)\n\n# @missing: 0000..10FFFF; cjkIRG_KSource; <none>\n\n# cjkIRG_MSource (cjkIRG_MSource)\n\n# @missing: 0000..10FFFF; cjkIRG_MSource; <none>\n\n# cjkIRG_SSource (cjkIRG_SSource)\n\n# @missing: 0000..10FFFF; cjkIRG_SSource; <none>\n\n# cjkIRG_TSource (cjkIRG_TSource)\n\n# @missing: 0000..10FFFF; cjkIRG_TSource; <none>\n\n# cjkIRG_UKSource (cjkIRG_UKSource)\n\n# @missing: 0000..10FFFF; cjkIRG_UKSource; <none>\n\n# cjkIRG_USource (cjkIRG_USource)\n\n# @missing: 0000..10FFFF; cjkIRG_USource; <none>\n\n# cjkIRG_VSource (cjkIRG_VSource)\n\n# @missing: 0000..10FFFF; cjkIRG_VSource; <none>\n\n# cjkOtherNumeric (cjkOtherNumeric)\n\n# @missing: 0000..10FFFF; cjkOtherNumeric; NaN\n\n# cjkPrimaryNumeric (cjkPrimaryNumeric)\n\n# @missing: 0000..10FFFF; cjkPrimaryNumeric; NaN\n\n# cjkRSUnicode (cjkRSUnicode)\n\n# @missing: 0000..10FFFF; cjkRSUnicode; <none>\n\n# kEH_Cat (kEH_Cat)\n\n# @missing: 0000..10FFFF; kEH_Cat; <none>\n\n# kEH_Desc (kEH_Desc)\n\n# @missing: 0000..10FFFF; kEH_Desc; <none>\n\n# kEH_HG (kEH_HG)\n\n# @missing: 0000..10FFFF; kEH_HG; <none>\n\n# kEH_IFAO (kEH_IFAO)\n\n# @missing: 0000..10FFFF; kEH_IFAO; <none>\n\n# kEH_JSesh (kEH_JSesh)\n\n# @missing: 0000..10FFFF; kEH_JSesh; <none>\n\n# kEH_NoMirror (kEH_NoMirror)\n\nkEH_NoMirror; N                       ; No                               ; F                                ; False\nkEH_NoMirror; Y                       ; Yes                              ; T                                ; True\n\n# kEH_NoRotate (kEH_NoRotate)\n\nkEH_NoRotate; N                       ; No                               ; F                                ; False\nkEH_NoRotate; Y                       ; Yes                              ; T                                ; True\n\n# kMandarin (cjkMandarin)\n\n# @missing: 0000..10FFFF; kMandarin; <none>\n\n# kTotalStrokes (cjkTotalStrokes)\n\n# @missing: 0000..10FFFF; kTotalStrokes; <none>\n\n# kUnihanCore2020 (cjkUnihanCore2020)\n\n# @missing: 0000..10FFFF; kUnihanCore2020; <none>\n\n# EOF\n"
  },
  {
    "path": "lib/elixir/unicode/ScriptExtensions.txt",
    "content": "# ScriptExtensions-17.0.0.txt\n# Date: 2025-08-01, 21:42:00 GMT\n# © 2025 Unicode®, Inc.\n# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.\n# For terms of use and license, see https://www.unicode.org/terms_of_use.html\n#\n# Unicode Character Database\n#   For documentation, see https://www.unicode.org/reports/tr44/\n#\n# The Script_Extensions property indicates which characters are commonly used\n# with more than one script, but with a limited number of scripts.\n# For each code point, there is one or more property values.  Each such value is a Script property value.\n# For more information, see:\n#   UAX #24, Unicode Script Property: https://www.unicode.org/reports/tr24/\n#     Especially the sections:\n#       https://www.unicode.org/reports/tr24/#Assignment_Script_Values\n#       https://www.unicode.org/reports/tr24/#Assignment_ScriptX_Values\n#\n# Each Script_Extensions value in this file consists of a set\n# of one or more abbreviated Script property values. The ordering of the\n# values in that set is not material, but for stability in presentation\n# it is given here as alphabetical.\n#\n# All code points not explicitly listed for Script_Extensions\n# have as their value the corresponding Script property value.\n#\n# @missing: 0000..10FFFF; <script>\n00B7          ; Avst Cari Copt Dupl Elba Geor Glag Gong Goth Grek Hani Latn Lydi Mahj Perm Shaw #Po MIDDLE DOT\n02BC          ; Beng Cyrl Deva Latn Lisu Thai Toto #Lm   MODIFIER LETTER APOSTROPHE\n02C7          ; Bopo Latn                      # Lm      CARON\n02C9..02CB    ; Bopo Latn                      # Lm  [3] MODIFIER LETTER MACRON..MODIFIER LETTER GRAVE ACCENT\n02CD          ; Latn Lisu                      # Lm      MODIFIER LETTER LOW MACRON\n02D7          ; Latn Thai                      # Sk      MODIFIER LETTER MINUS SIGN\n02D9          ; Bopo Latn                      # Sk      DOT ABOVE\n0300          ; Cher Copt Cyrl Grek Latn Perm Sunu Tale #Mn COMBINING GRAVE ACCENT\n0301          ; Cher Cyrl Grek Latn Osge Sunu Tale Todr #Mn COMBINING ACUTE ACCENT\n0302          ; Cher Cyrl Latn Tfng            # Mn      COMBINING CIRCUMFLEX ACCENT\n0303          ; Glag Latn Sunu Syrc Thai       # Mn      COMBINING TILDE\n0304          ; Aghb Cher Copt Cyrl Goth Grek Latn Osge Syrc Tfng Todr #Mn COMBINING MACRON\n0305          ; Copt Elba Glag Goth Kana Latn  # Mn      COMBINING OVERLINE\n0306          ; Cyrl Grek Latn Perm Tfng       # Mn      COMBINING BREVE\n0307          ; Copt Dupl Hebr Latn Perm Syrc Tale Tfng Todr #Mn COMBINING DOT ABOVE\n0308          ; Armn Cyrl Dupl Goth Grek Hebr Latn Perm Syrc Tale Tfng #Mn COMBINING DIAERESIS\n0309          ; Latn Tfng                      # Mn      COMBINING HOOK ABOVE\n030A          ; Dupl Latn Syrc                 # Mn      COMBINING RING ABOVE\n030B          ; Cher Cyrl Latn Osge            # Mn      COMBINING DOUBLE ACUTE ACCENT\n030C          ; Cher Latn Tale                 # Mn      COMBINING CARON\n030D          ; Latn Sunu                      # Mn      COMBINING VERTICAL LINE ABOVE\n030E          ; Ethi Latn                      # Mn      COMBINING DOUBLE VERTICAL LINE ABOVE\n0310          ; Latn Sunu                      # Mn      COMBINING CANDRABINDU\n0311          ; Cyrl Latn Todr                 # Mn      COMBINING INVERTED BREVE\n0313          ; Grek Latn Perm Todr            # Mn      COMBINING COMMA ABOVE\n0323          ; Cher Dupl Kana Latn Syrc Tfng  # Mn      COMBINING DOT BELOW\n0324          ; Cher Dupl Latn Syrc            # Mn      COMBINING DIAERESIS BELOW\n0325          ; Latn Syrc                      # Mn      COMBINING RING BELOW\n032D          ; Latn Sunu Syrc                 # Mn      COMBINING CIRCUMFLEX ACCENT BELOW\n032E          ; Latn Syrc                      # Mn      COMBINING BREVE BELOW\n0330          ; Cher Latn Syrc                 # Mn      COMBINING TILDE BELOW\n0331          ; Aghb Cher Goth Latn Sunu Syrc Thai #Mn   COMBINING MACRON BELOW\n0342          ; Grek                           # Mn      COMBINING GREEK PERISPOMENI\n0345          ; Grek                           # Mn      COMBINING GREEK YPOGEGRAMMENI\n0358          ; Latn Osge                      # Mn      COMBINING DOT ABOVE RIGHT\n035E          ; Aghb Latn Todr                 # Mn      COMBINING DOUBLE MACRON\n0363..036F    ; Latn                           # Mn [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X\n0374          ; Copt Grek                      # Lm      GREEK NUMERAL SIGN\n0375          ; Copt Grek                      # Sk      GREEK LOWER NUMERAL SIGN\n0483          ; Cyrl Perm                      # Mn      COMBINING CYRILLIC TITLO\n0484          ; Cyrl Glag                      # Mn      COMBINING CYRILLIC PALATALIZATION\n0485..0486    ; Cyrl Latn                      # Mn  [2] COMBINING CYRILLIC DASIA PNEUMATA..COMBINING CYRILLIC PSILI PNEUMATA\n0487          ; Cyrl Glag                      # Mn      COMBINING CYRILLIC POKRYTIE\n0589          ; Armn Geor Glag                 # Po      ARMENIAN FULL STOP\n060C          ; Arab Gara Nkoo Rohg Syrc Thaa Yezi #Po   ARABIC COMMA\n061B          ; Arab Gara Nkoo Rohg Syrc Thaa Yezi #Po   ARABIC SEMICOLON\n061C          ; Arab Syrc Thaa                 # Cf      ARABIC LETTER MARK\n061F          ; Adlm Arab Gara Nkoo Rohg Syrc Thaa Yezi #Po ARABIC QUESTION MARK\n0640          ; Adlm Arab Mand Mani Ougr Phlp Rohg Sogd Syrc #Lm ARABIC TATWEEL\n064B..0655    ; Arab Syrc                      # Mn [11] ARABIC FATHATAN..ARABIC HAMZA BELOW\n0660..0669    ; Arab Thaa Yezi                 # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE\n0670          ; Arab Syrc                      # Mn      ARABIC LETTER SUPERSCRIPT ALEF\n06D4          ; Arab Rohg                      # Po      ARABIC FULL STOP\n0951          ; Beng Deva Gran Gujr Guru Knda Latn Mlym Nand Newa Orya Shrd Taml Telu Tirh #Mn DEVANAGARI STRESS SIGN UDATTA\n0952          ; Beng Deva Gran Gujr Guru Knda Latn Mlym Newa Orya Taml Telu Tirh #Mn DEVANAGARI STRESS SIGN ANUDATTA\n0964          ; Beng Deva Dogr Gong Gonm Gran Gujr Guru Knda Mahj Mlym Nand Onao Orya Sind Sinh Sylo Takr Taml Telu Tirh #Po DEVANAGARI DANDA\n0965          ; Beng Deva Dogr Gong Gonm Gran Gujr Gukh Guru Knda Limb Mahj Mlym Nand Onao Orya Sind Sinh Sylo Takr Taml Telu Tirh #Po DEVANAGARI DOUBLE DANDA\n0966..096F    ; Deva Dogr Kthi Mahj            # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE\n09E6..09EF    ; Beng Cakm Sylo                 # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE\n0A66..0A6F    ; Guru Mult                      # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE\n0AE6..0AEF    ; Gujr Khoj                      # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE\n0BE6..0BEF    ; Gran Taml                      # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE\n0BF0..0BF2    ; Gran Taml                      # No  [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND\n0BF3          ; Gran Taml                      # So      TAMIL DAY SIGN\n0CE6..0CEF    ; Knda Nand Tutg                 # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE\n1040..1049    ; Cakm Mymr Tale                 # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE\n10FB          ; Geor Glag Latn                 # Po      GEORGIAN PARAGRAPH SEPARATOR\n16EB..16ED    ; Runr                           # Po  [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION\n1735..1736    ; Buhd Hano Tagb Tglg            # Po  [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION\n1802..1803    ; Mong Phag                      # Po  [2] MONGOLIAN COMMA..MONGOLIAN FULL STOP\n1805          ; Mong Phag                      # Po      MONGOLIAN FOUR DOTS\n1CD0          ; Beng Deva Gran Knda            # Mn      VEDIC TONE KARSHANA\n1CD1          ; Deva                           # Mn      VEDIC TONE SHARA\n1CD2          ; Beng Deva Gran Knda            # Mn      VEDIC TONE PRENKHA\n1CD3          ; Deva Gran Knda                 # Po      VEDIC SIGN NIHSHVASA\n1CD4          ; Deva                           # Mn      VEDIC SIGN YAJURVEDIC MIDLINE SVARITA\n1CD5          ; Beng Deva Newa Telu Tirh       # Mn      VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA\n1CD6          ; Beng Deva Telu                 # Mn      VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA\n1CD7          ; Deva Newa Shrd                 # Mn      VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA\n1CD8          ; Beng Deva Newa Telu            # Mn      VEDIC TONE CANDRA BELOW\n1CD9          ; Deva Shrd                      # Mn      VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER\n1CDA          ; Deva Knda Mlym Orya Taml Telu  # Mn      VEDIC TONE DOUBLE SVARITA\n1CDB          ; Deva                           # Mn      VEDIC TONE TRIPLE SVARITA\n1CDC..1CDD    ; Deva Shrd                      # Mn  [2] VEDIC TONE KATHAKA ANUDATTA..VEDIC TONE DOT BELOW\n1CDE..1CDF    ; Deva                           # Mn  [2] VEDIC TONE TWO DOTS BELOW..VEDIC TONE THREE DOTS BELOW\n1CE0          ; Deva Shrd                      # Mn      VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA\n1CE1          ; Beng Deva                      # Mc      VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA\n1CE2          ; Deva Newa Tirh                 # Mn      VEDIC SIGN VISARGA SVARITA\n1CE3..1CE8    ; Deva                           # Mn  [6] VEDIC SIGN VISARGA UDATTA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL\n1CE9          ; Deva Nand Newa                 # Lo      VEDIC SIGN ANUSVARA ANTARGOMUKHA\n1CEA          ; Beng Deva Shrd                 # Lo      VEDIC SIGN ANUSVARA BAHIRGOMUKHA\n1CEB          ; Deva Newa                      # Lo      VEDIC SIGN ANUSVARA VAMAGOMUKHA\n1CEC          ; Deva                           # Lo      VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL\n1CED          ; Beng Deva Newa Shrd            # Mn      VEDIC SIGN TIRYAK\n1CEE..1CF1    ; Deva                           # Lo  [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA\n1CF2          ; Beng Deva Gran Knda Mlym Nand Orya Sinh Telu Tirh Tutg #Lo VEDIC SIGN ARDHAVISARGA\n1CF3          ; Deva Gran                      # Lo      VEDIC SIGN ROTATED ARDHAVISARGA\n1CF4          ; Deva Gran Knda Tutg            # Mn      VEDIC TONE CANDRA ABOVE\n1CF5..1CF6    ; Beng Deva                      # Lo  [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA\n1CF7          ; Beng                           # Mc      VEDIC SIGN ATIKRAMA\n1CF8..1CF9    ; Deva Gran                      # Mn  [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE\n1CFA          ; Nand                           # Lo      VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA\n1DC0..1DC1    ; Grek                           # Mn  [2] COMBINING DOTTED GRAVE ACCENT..COMBINING DOTTED ACUTE ACCENT\n1DF8          ; Cyrl Latn Syrc                 # Mn      COMBINING DOT ABOVE LEFT\n1DFA          ; Syrc                           # Mn      COMBINING DOT BELOW LEFT\n202F          ; Latn Mong Phag                 # Zs      NARROW NO-BREAK SPACE\n204F          ; Adlm Arab                      # Po      REVERSED SEMICOLON\n205A          ; Cari Geor Glag Hung Lyci Orkh  # Po      TWO DOT PUNCTUATION\n205D          ; Cari Grek Hung Mero            # Po      TRICOLON\n20F0          ; Deva Gran Latn                 # Mn      COMBINING ASTERISK ABOVE\n2E17          ; Copt Latn                      # Pd      DOUBLE OBLIQUE HYPHEN\n2E30          ; Avst Orkh                      # Po      RING POINT\n2E31          ; Avst Cari Geor Hung Kthi Lydi Samr #Po   WORD SEPARATOR MIDDLE DOT\n2E3C          ; Dupl                           # Po      STENOGRAPHIC FULL STOP\n2E41          ; Adlm Arab Hung                 # Po      REVERSED COMMA\n2E43          ; Cyrl Glag                      # Po      DASH WITH LEFT UPTURN\n2FF0..2FFF    ; Hani Tang                      # So [16] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION\n3001          ; Bopo Hang Hani Hira Kana Mong Yiii #Po   IDEOGRAPHIC COMMA\n3002          ; Bopo Hang Hani Hira Kana Mong Phag Yiii #Po IDEOGRAPHIC FULL STOP\n3003          ; Bopo Hang Hani Hira Kana       # Po      DITTO MARK\n3006          ; Hani                           # Lo      IDEOGRAPHIC CLOSING MARK\n3008          ; Bopo Hang Hani Hira Kana Mong Tibt Yiii #Ps LEFT ANGLE BRACKET\n3009          ; Bopo Hang Hani Hira Kana Mong Tibt Yiii #Pe RIGHT ANGLE BRACKET\n300A          ; Bopo Hang Hani Hira Kana Lisu Mong Tibt Yiii #Ps LEFT DOUBLE ANGLE BRACKET\n300B          ; Bopo Hang Hani Hira Kana Lisu Mong Tibt Yiii #Pe RIGHT DOUBLE ANGLE BRACKET\n300C          ; Bopo Hang Hani Hira Kana Yiii  # Ps      LEFT CORNER BRACKET\n300D          ; Bopo Hang Hani Hira Kana Yiii  # Pe      RIGHT CORNER BRACKET\n300E          ; Bopo Hang Hani Hira Kana Yiii  # Ps      LEFT WHITE CORNER BRACKET\n300F          ; Bopo Hang Hani Hira Kana Yiii  # Pe      RIGHT WHITE CORNER BRACKET\n3010          ; Bopo Hang Hani Hira Kana Yiii  # Ps      LEFT BLACK LENTICULAR BRACKET\n3011          ; Bopo Hang Hani Hira Kana Yiii  # Pe      RIGHT BLACK LENTICULAR BRACKET\n3013          ; Bopo Hang Hani Hira Kana       # So      GETA MARK\n3014          ; Bopo Hang Hani Hira Kana Yiii  # Ps      LEFT TORTOISE SHELL BRACKET\n3015          ; Bopo Hang Hani Hira Kana Yiii  # Pe      RIGHT TORTOISE SHELL BRACKET\n3016          ; Bopo Hang Hani Hira Kana Yiii  # Ps      LEFT WHITE LENTICULAR BRACKET\n3017          ; Bopo Hang Hani Hira Kana Yiii  # Pe      RIGHT WHITE LENTICULAR BRACKET\n3018          ; Bopo Hang Hani Hira Kana Yiii  # Ps      LEFT WHITE TORTOISE SHELL BRACKET\n3019          ; Bopo Hang Hani Hira Kana Yiii  # Pe      RIGHT WHITE TORTOISE SHELL BRACKET\n301A          ; Bopo Hang Hani Hira Kana Yiii  # Ps      LEFT WHITE SQUARE BRACKET\n301B          ; Bopo Hang Hani Hira Kana Yiii  # Pe      RIGHT WHITE SQUARE BRACKET\n301C          ; Bopo Hang Hani Hira Kana       # Pd      WAVE DASH\n301D          ; Bopo Hang Hani Hira Kana       # Ps      REVERSED DOUBLE PRIME QUOTATION MARK\n301E..301F    ; Bopo Hang Hani Hira Kana       # Pe  [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK\n302A..302D    ; Bopo Hani                      # Mn  [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK\n3030          ; Bopo Hang Hani Hira Kana       # Pd      WAVY DASH\n3031..3035    ; Hira Kana                      # Lm  [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF\n3037          ; Bopo Hang Hani Hira Kana       # So      IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL\n303C          ; Hani Hira Kana                 # Lo      MASU MARK\n303D          ; Hani Hira Kana                 # Po      PART ALTERNATION MARK\n303E..303F    ; Hani                           # So  [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE\n3099..309A    ; Hira Kana                      # Mn  [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n309B..309C    ; Hira Kana                      # Sk  [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n30A0          ; Hira Kana                      # Pd      KATAKANA-HIRAGANA DOUBLE HYPHEN\n30FB          ; Bopo Hang Hani Hira Kana Yiii  # Po      KATAKANA MIDDLE DOT\n30FC          ; Hira Kana                      # Lm      KATAKANA-HIRAGANA PROLONGED SOUND MARK\n3190..3191    ; Hani                           # So  [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK\n3192..3195    ; Hani                           # No  [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK\n3196..319F    ; Hani                           # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK\n31C0..31E5    ; Hani                           # So [38] CJK STROKE T..CJK STROKE SZP\n31EF          ; Hani Tang                      # So      IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION\n3220..3229    ; Hani                           # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN\n322A..3247    ; Hani                           # So [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO\n3280..3289    ; Hani                           # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN\n328A..32B0    ; Hani                           # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT\n32C0..32CB    ; Hani                           # So [12] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER\n32FF          ; Hani                           # So      SQUARE ERA NAME REIWA\n3358..3370    ; Hani                           # So [25] IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO..IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR\n337B..337F    ; Hani                           # So  [5] SQUARE ERA NAME HEISEI..SQUARE CORPORATION\n33E0..33FE    ; Hani                           # So [31] IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE\nA66F          ; Cyrl Glag                      # Mn      COMBINING CYRILLIC VZMET\nA700..A707    ; Hani Latn                      # Sk  [8] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER CHINESE TONE YANG RU\nA830..A832    ; Deva Dogr Gujr Guru Khoj Knda Kthi Mahj Mlym Modi Nand Shrd Sind Takr Tirh Tutg #No [3] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE QUARTERS\nA833..A835    ; Deva Dogr Gujr Guru Khoj Knda Kthi Mahj Modi Nand Shrd Sind Takr Tirh Tutg #No [3] NORTH INDIC FRACTION ONE SIXTEENTH..NORTH INDIC FRACTION THREE SIXTEENTHS\nA836..A837    ; Deva Dogr Gujr Guru Khoj Kthi Mahj Modi Sind Takr Tirh #So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK\nA838          ; Deva Dogr Gujr Guru Khoj Kthi Mahj Modi Shrd Sind Takr Tirh #Sc NORTH INDIC RUPEE MARK\nA839          ; Deva Dogr Gujr Guru Khoj Kthi Mahj Modi Sind Takr Tirh #So NORTH INDIC QUANTITY MARK\nA8F1          ; Beng Deva Tutg                 # Mn      COMBINING DEVANAGARI SIGN AVAGRAHA\nA8F3          ; Deva Taml                      # Lo      DEVANAGARI SIGN CANDRABINDU VIRAMA\nA92E          ; Kali Latn Mymr                 # Po      KAYAH LI SIGN CWI\nA9CF          ; Bugi Java                      # Lm      JAVANESE PANGRANGKEP\nFD3E          ; Arab Nkoo                      # Pe      ORNATE LEFT PARENTHESIS\nFD3F          ; Arab Nkoo                      # Ps      ORNATE RIGHT PARENTHESIS\nFDF2          ; Arab Thaa                      # Lo      ARABIC LIGATURE ALLAH ISOLATED FORM\nFDFD          ; Arab Thaa                      # So      ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM\nFE45..FE46    ; Bopo Hang Hani Hira Kana       # Po  [2] SESAME DOT..WHITE SESAME DOT\nFF61          ; Bopo Hang Hani Hira Kana Yiii  # Po      HALFWIDTH IDEOGRAPHIC FULL STOP\nFF62          ; Bopo Hang Hani Hira Kana Yiii  # Ps      HALFWIDTH LEFT CORNER BRACKET\nFF63          ; Bopo Hang Hani Hira Kana Yiii  # Pe      HALFWIDTH RIGHT CORNER BRACKET\nFF64..FF65    ; Bopo Hang Hani Hira Kana Yiii  # Po  [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT\nFF70          ; Hira Kana                      # Lm      HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK\nFF9E..FF9F    ; Hira Kana                      # Lm  [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK\n10100..10101  ; Cpmn Cprt Linb                 # Po  [2] AEGEAN WORD SEPARATOR LINE..AEGEAN WORD SEPARATOR DOT\n10102         ; Cprt Linb                      # Po      AEGEAN CHECK MARK\n10107..10133  ; Cprt Lina Linb                 # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND\n10137..1013F  ; Cprt Linb                      # So  [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT\n102E0         ; Arab Copt                      # Mn      COPTIC EPACT THOUSANDS MARK\n102E1..102FB  ; Arab Copt                      # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED\n10AF2         ; Mani Ougr                      # Po      MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT\n11301         ; Gran Taml                      # Mn      GRANTHA SIGN CANDRABINDU\n11303         ; Gran Taml                      # Mc      GRANTHA SIGN VISARGA\n1133B..1133C  ; Gran Taml                      # Mn  [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA\n11FD0..11FD1  ; Gran Taml                      # No  [2] TAMIL FRACTION ONE QUARTER..TAMIL FRACTION ONE HALF-1\n11FD3         ; Gran Taml                      # No      TAMIL FRACTION THREE QUARTERS\n1BCA0..1BCA3  ; Dupl                           # Cf  [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP\n1D360..1D371  ; Hani                           # No [18] COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE\n1F250..1F251  ; Hani                           # So  [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT\n\n# EOF\n"
  },
  {
    "path": "lib/elixir/unicode/Scripts.txt",
    "content": "# Scripts-17.0.0.txt\n# Date: 2025-07-24, 13:28:55 GMT\n# © 2025 Unicode®, Inc.\n# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.\n# For terms of use and license, see https://www.unicode.org/terms_of_use.html\n#\n# Unicode Character Database\n#   For documentation, see https://www.unicode.org/reports/tr44/\n# For more information, see:\n#   UAX #24, Unicode Script Property: https://www.unicode.org/reports/tr24/\n#     Especially the sections:\n#       https://www.unicode.org/reports/tr24/#Assignment_Script_Values\n#       https://www.unicode.org/reports/tr24/#Assignment_ScriptX_Values\n#\n\n# ================================================\n\n# Property:\tScript\n\n#  All code points not explicitly listed for Script\n#  have the value Unknown (Zzzz).\n\n# @missing: 0000..10FFFF; Unknown\n\n# ================================================\n\n0000..001F    ; Common # Cc  [32] <control-0000>..<control-001F>\n0020          ; Common # Zs       SPACE\n0021..0023    ; Common # Po   [3] EXCLAMATION MARK..NUMBER SIGN\n0024          ; Common # Sc       DOLLAR SIGN\n0025..0027    ; Common # Po   [3] PERCENT SIGN..APOSTROPHE\n0028          ; Common # Ps       LEFT PARENTHESIS\n0029          ; Common # Pe       RIGHT PARENTHESIS\n002A          ; Common # Po       ASTERISK\n002B          ; Common # Sm       PLUS SIGN\n002C          ; Common # Po       COMMA\n002D          ; Common # Pd       HYPHEN-MINUS\n002E..002F    ; Common # Po   [2] FULL STOP..SOLIDUS\n0030..0039    ; Common # Nd  [10] DIGIT ZERO..DIGIT NINE\n003A..003B    ; Common # Po   [2] COLON..SEMICOLON\n003C..003E    ; Common # Sm   [3] LESS-THAN SIGN..GREATER-THAN SIGN\n003F..0040    ; Common # Po   [2] QUESTION MARK..COMMERCIAL AT\n005B          ; Common # Ps       LEFT SQUARE BRACKET\n005C          ; Common # Po       REVERSE SOLIDUS\n005D          ; Common # Pe       RIGHT SQUARE BRACKET\n005E          ; Common # Sk       CIRCUMFLEX ACCENT\n005F          ; Common # Pc       LOW LINE\n0060          ; Common # Sk       GRAVE ACCENT\n007B          ; Common # Ps       LEFT CURLY BRACKET\n007C          ; Common # Sm       VERTICAL LINE\n007D          ; Common # Pe       RIGHT CURLY BRACKET\n007E          ; Common # Sm       TILDE\n007F..009F    ; Common # Cc  [33] <control-007F>..<control-009F>\n00A0          ; Common # Zs       NO-BREAK SPACE\n00A1          ; Common # Po       INVERTED EXCLAMATION MARK\n00A2..00A5    ; Common # Sc   [4] CENT SIGN..YEN SIGN\n00A6          ; Common # So       BROKEN BAR\n00A7          ; Common # Po       SECTION SIGN\n00A8          ; Common # Sk       DIAERESIS\n00A9          ; Common # So       COPYRIGHT SIGN\n00AB          ; Common # Pi       LEFT-POINTING DOUBLE ANGLE QUOTATION MARK\n00AC          ; Common # Sm       NOT SIGN\n00AD          ; Common # Cf       SOFT HYPHEN\n00AE          ; Common # So       REGISTERED SIGN\n00AF          ; Common # Sk       MACRON\n00B0          ; Common # So       DEGREE SIGN\n00B1          ; Common # Sm       PLUS-MINUS SIGN\n00B2..00B3    ; Common # No   [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE\n00B4          ; Common # Sk       ACUTE ACCENT\n00B5          ; Common # L&       MICRO SIGN\n00B6..00B7    ; Common # Po   [2] PILCROW SIGN..MIDDLE DOT\n00B8          ; Common # Sk       CEDILLA\n00B9          ; Common # No       SUPERSCRIPT ONE\n00BB          ; Common # Pf       RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK\n00BC..00BE    ; Common # No   [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS\n00BF          ; Common # Po       INVERTED QUESTION MARK\n00D7          ; Common # Sm       MULTIPLICATION SIGN\n00F7          ; Common # Sm       DIVISION SIGN\n02B9..02C1    ; Common # Lm   [9] MODIFIER LETTER PRIME..MODIFIER LETTER REVERSED GLOTTAL STOP\n02C2..02C5    ; Common # Sk   [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD\n02C6..02D1    ; Common # Lm  [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON\n02D2..02DF    ; Common # Sk  [14] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER CROSS ACCENT\n02E5..02E9    ; Common # Sk   [5] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER EXTRA-LOW TONE BAR\n02EC          ; Common # Lm       MODIFIER LETTER VOICING\n02ED          ; Common # Sk       MODIFIER LETTER UNASPIRATED\n02EE          ; Common # Lm       MODIFIER LETTER DOUBLE APOSTROPHE\n02EF..02FF    ; Common # Sk  [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW\n0374          ; Common # Lm       GREEK NUMERAL SIGN\n037E          ; Common # Po       GREEK QUESTION MARK\n0385          ; Common # Sk       GREEK DIALYTIKA TONOS\n0387          ; Common # Po       GREEK ANO TELEIA\n0605          ; Common # Cf       ARABIC NUMBER MARK ABOVE\n060C          ; Common # Po       ARABIC COMMA\n061B          ; Common # Po       ARABIC SEMICOLON\n061F          ; Common # Po       ARABIC QUESTION MARK\n0640          ; Common # Lm       ARABIC TATWEEL\n06DD          ; Common # Cf       ARABIC END OF AYAH\n08E2          ; Common # Cf       ARABIC DISPUTED END OF AYAH\n0964..0965    ; Common # Po   [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA\n0E3F          ; Common # Sc       THAI CURRENCY SYMBOL BAHT\n0FD5..0FD8    ; Common # So   [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS\n10FB          ; Common # Po       GEORGIAN PARAGRAPH SEPARATOR\n16EB..16ED    ; Common # Po   [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION\n1735..1736    ; Common # Po   [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION\n1802..1803    ; Common # Po   [2] MONGOLIAN COMMA..MONGOLIAN FULL STOP\n1805          ; Common # Po       MONGOLIAN FOUR DOTS\n1CD3          ; Common # Po       VEDIC SIGN NIHSHVASA\n1CE1          ; Common # Mc       VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA\n1CE9..1CEC    ; Common # Lo   [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL\n1CEE..1CF3    ; Common # Lo   [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA\n1CF5..1CF6    ; Common # Lo   [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA\n1CF7          ; Common # Mc       VEDIC SIGN ATIKRAMA\n1CFA          ; Common # Lo       VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA\n2000..200A    ; Common # Zs  [11] EN QUAD..HAIR SPACE\n200B          ; Common # Cf       ZERO WIDTH SPACE\n200E..200F    ; Common # Cf   [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK\n2010..2015    ; Common # Pd   [6] HYPHEN..HORIZONTAL BAR\n2016..2017    ; Common # Po   [2] DOUBLE VERTICAL LINE..DOUBLE LOW LINE\n2018          ; Common # Pi       LEFT SINGLE QUOTATION MARK\n2019          ; Common # Pf       RIGHT SINGLE QUOTATION MARK\n201A          ; Common # Ps       SINGLE LOW-9 QUOTATION MARK\n201B..201C    ; Common # Pi   [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK\n201D          ; Common # Pf       RIGHT DOUBLE QUOTATION MARK\n201E          ; Common # Ps       DOUBLE LOW-9 QUOTATION MARK\n201F          ; Common # Pi       DOUBLE HIGH-REVERSED-9 QUOTATION MARK\n2020..2027    ; Common # Po   [8] DAGGER..HYPHENATION POINT\n2028          ; Common # Zl       LINE SEPARATOR\n2029          ; Common # Zp       PARAGRAPH SEPARATOR\n202A..202E    ; Common # Cf   [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE\n202F          ; Common # Zs       NARROW NO-BREAK SPACE\n2030..2038    ; Common # Po   [9] PER MILLE SIGN..CARET\n2039          ; Common # Pi       SINGLE LEFT-POINTING ANGLE QUOTATION MARK\n203A          ; Common # Pf       SINGLE RIGHT-POINTING ANGLE QUOTATION MARK\n203B..203E    ; Common # Po   [4] REFERENCE MARK..OVERLINE\n203F..2040    ; Common # Pc   [2] UNDERTIE..CHARACTER TIE\n2041..2043    ; Common # Po   [3] CARET INSERTION POINT..HYPHEN BULLET\n2044          ; Common # Sm       FRACTION SLASH\n2045          ; Common # Ps       LEFT SQUARE BRACKET WITH QUILL\n2046          ; Common # Pe       RIGHT SQUARE BRACKET WITH QUILL\n2047..2051    ; Common # Po  [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY\n2052          ; Common # Sm       COMMERCIAL MINUS SIGN\n2053          ; Common # Po       SWUNG DASH\n2054          ; Common # Pc       INVERTED UNDERTIE\n2055..205E    ; Common # Po  [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS\n205F          ; Common # Zs       MEDIUM MATHEMATICAL SPACE\n2060..2064    ; Common # Cf   [5] WORD JOINER..INVISIBLE PLUS\n2066..206F    ; Common # Cf  [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES\n2070          ; Common # No       SUPERSCRIPT ZERO\n2074..2079    ; Common # No   [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE\n207A..207C    ; Common # Sm   [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN\n207D          ; Common # Ps       SUPERSCRIPT LEFT PARENTHESIS\n207E          ; Common # Pe       SUPERSCRIPT RIGHT PARENTHESIS\n2080..2089    ; Common # No  [10] SUBSCRIPT ZERO..SUBSCRIPT NINE\n208A..208C    ; Common # Sm   [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN\n208D          ; Common # Ps       SUBSCRIPT LEFT PARENTHESIS\n208E          ; Common # Pe       SUBSCRIPT RIGHT PARENTHESIS\n20A0..20C1    ; Common # Sc  [34] EURO-CURRENCY SIGN..SAUDI RIYAL SIGN\n2100..2101    ; Common # So   [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT\n2102          ; Common # L&       DOUBLE-STRUCK CAPITAL C\n2103..2106    ; Common # So   [4] DEGREE CELSIUS..CADA UNA\n2107          ; Common # L&       EULER CONSTANT\n2108..2109    ; Common # So   [2] SCRUPLE..DEGREE FAHRENHEIT\n210A..2113    ; Common # L&  [10] SCRIPT SMALL G..SCRIPT SMALL L\n2114          ; Common # So       L B BAR SYMBOL\n2115          ; Common # L&       DOUBLE-STRUCK CAPITAL N\n2116..2117    ; Common # So   [2] NUMERO SIGN..SOUND RECORDING COPYRIGHT\n2118          ; Common # Sm       SCRIPT CAPITAL P\n2119..211D    ; Common # L&   [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R\n211E..2123    ; Common # So   [6] PRESCRIPTION TAKE..VERSICLE\n2124          ; Common # L&       DOUBLE-STRUCK CAPITAL Z\n2125          ; Common # So       OUNCE SIGN\n2127          ; Common # So       INVERTED OHM SIGN\n2128          ; Common # L&       BLACK-LETTER CAPITAL Z\n2129          ; Common # So       TURNED GREEK SMALL LETTER IOTA\n212C..212D    ; Common # L&   [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C\n212E          ; Common # So       ESTIMATED SYMBOL\n212F..2131    ; Common # L&   [3] SCRIPT SMALL E..SCRIPT CAPITAL F\n2133..2134    ; Common # L&   [2] SCRIPT CAPITAL M..SCRIPT SMALL O\n2135..2138    ; Common # Lo   [4] ALEF SYMBOL..DALET SYMBOL\n2139          ; Common # L&       INFORMATION SOURCE\n213A..213B    ; Common # So   [2] ROTATED CAPITAL Q..FACSIMILE SIGN\n213C..213F    ; Common # L&   [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI\n2140..2144    ; Common # Sm   [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y\n2145..2149    ; Common # L&   [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J\n214A          ; Common # So       PROPERTY LINE\n214B          ; Common # Sm       TURNED AMPERSAND\n214C..214D    ; Common # So   [2] PER SIGN..AKTIESELSKAB\n214F          ; Common # So       SYMBOL FOR SAMARITAN SOURCE\n2150..215F    ; Common # No  [16] VULGAR FRACTION ONE SEVENTH..FRACTION NUMERATOR ONE\n2189          ; Common # No       VULGAR FRACTION ZERO THIRDS\n218A..218B    ; Common # So   [2] TURNED DIGIT TWO..TURNED DIGIT THREE\n2190..2194    ; Common # Sm   [5] LEFTWARDS ARROW..LEFT RIGHT ARROW\n2195..2199    ; Common # So   [5] UP DOWN ARROW..SOUTH WEST ARROW\n219A..219B    ; Common # Sm   [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE\n219C..219F    ; Common # So   [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW\n21A0          ; Common # Sm       RIGHTWARDS TWO HEADED ARROW\n21A1..21A2    ; Common # So   [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL\n21A3          ; Common # Sm       RIGHTWARDS ARROW WITH TAIL\n21A4..21A5    ; Common # So   [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR\n21A6          ; Common # Sm       RIGHTWARDS ARROW FROM BAR\n21A7..21AD    ; Common # So   [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW\n21AE          ; Common # Sm       LEFT RIGHT ARROW WITH STROKE\n21AF..21CD    ; Common # So  [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE\n21CE..21CF    ; Common # Sm   [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE\n21D0..21D1    ; Common # So   [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW\n21D2          ; Common # Sm       RIGHTWARDS DOUBLE ARROW\n21D3          ; Common # So       DOWNWARDS DOUBLE ARROW\n21D4          ; Common # Sm       LEFT RIGHT DOUBLE ARROW\n21D5..21F3    ; Common # So  [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW\n21F4..22FF    ; Common # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP\n2300..2307    ; Common # So   [8] DIAMETER SIGN..WAVY LINE\n2308          ; Common # Ps       LEFT CEILING\n2309          ; Common # Pe       RIGHT CEILING\n230A          ; Common # Ps       LEFT FLOOR\n230B          ; Common # Pe       RIGHT FLOOR\n230C..231F    ; Common # So  [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER\n2320..2321    ; Common # Sm   [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL\n2322..2328    ; Common # So   [7] FROWN..KEYBOARD\n2329          ; Common # Ps       LEFT-POINTING ANGLE BRACKET\n232A          ; Common # Pe       RIGHT-POINTING ANGLE BRACKET\n232B..237B    ; Common # So  [81] ERASE TO THE LEFT..NOT CHECK MARK\n237C          ; Common # Sm       RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW\n237D..239A    ; Common # So  [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL\n239B..23B3    ; Common # Sm  [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM\n23B4..23DB    ; Common # So  [40] TOP SQUARE BRACKET..FUSE\n23DC..23E1    ; Common # Sm   [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET\n23E2..2429    ; Common # So  [72] WHITE TRAPEZIUM..SYMBOL FOR DELETE MEDIUM SHADE FORM\n2440..244A    ; Common # So  [11] OCR HOOK..OCR DOUBLE BACKSLASH\n2460..249B    ; Common # No  [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP\n249C..24E9    ; Common # So  [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z\n24EA..24FF    ; Common # No  [22] CIRCLED DIGIT ZERO..NEGATIVE CIRCLED DIGIT ZERO\n2500..25B6    ; Common # So [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE\n25B7          ; Common # Sm       WHITE RIGHT-POINTING TRIANGLE\n25B8..25C0    ; Common # So   [9] BLACK RIGHT-POINTING SMALL TRIANGLE..BLACK LEFT-POINTING TRIANGLE\n25C1          ; Common # Sm       WHITE LEFT-POINTING TRIANGLE\n25C2..25F7    ; Common # So  [54] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE CIRCLE WITH UPPER RIGHT QUADRANT\n25F8..25FF    ; Common # Sm   [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE\n2600..266E    ; Common # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN\n266F          ; Common # Sm       MUSIC SHARP SIGN\n2670..2767    ; Common # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET\n2768          ; Common # Ps       MEDIUM LEFT PARENTHESIS ORNAMENT\n2769          ; Common # Pe       MEDIUM RIGHT PARENTHESIS ORNAMENT\n276A          ; Common # Ps       MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT\n276B          ; Common # Pe       MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT\n276C          ; Common # Ps       MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT\n276D          ; Common # Pe       MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT\n276E          ; Common # Ps       HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT\n276F          ; Common # Pe       HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT\n2770          ; Common # Ps       HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT\n2771          ; Common # Pe       HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT\n2772          ; Common # Ps       LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT\n2773          ; Common # Pe       LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT\n2774          ; Common # Ps       MEDIUM LEFT CURLY BRACKET ORNAMENT\n2775          ; Common # Pe       MEDIUM RIGHT CURLY BRACKET ORNAMENT\n2776..2793    ; Common # No  [30] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN\n2794..27BF    ; Common # So  [44] HEAVY WIDE-HEADED RIGHTWARDS ARROW..DOUBLE CURLY LOOP\n27C0..27C4    ; Common # Sm   [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET\n27C5          ; Common # Ps       LEFT S-SHAPED BAG DELIMITER\n27C6          ; Common # Pe       RIGHT S-SHAPED BAG DELIMITER\n27C7..27E5    ; Common # Sm  [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK\n27E6          ; Common # Ps       MATHEMATICAL LEFT WHITE SQUARE BRACKET\n27E7          ; Common # Pe       MATHEMATICAL RIGHT WHITE SQUARE BRACKET\n27E8          ; Common # Ps       MATHEMATICAL LEFT ANGLE BRACKET\n27E9          ; Common # Pe       MATHEMATICAL RIGHT ANGLE BRACKET\n27EA          ; Common # Ps       MATHEMATICAL LEFT DOUBLE ANGLE BRACKET\n27EB          ; Common # Pe       MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET\n27EC          ; Common # Ps       MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET\n27ED          ; Common # Pe       MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET\n27EE          ; Common # Ps       MATHEMATICAL LEFT FLATTENED PARENTHESIS\n27EF          ; Common # Pe       MATHEMATICAL RIGHT FLATTENED PARENTHESIS\n27F0..27FF    ; Common # Sm  [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW\n2900..2982    ; Common # Sm [131] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..Z NOTATION TYPE COLON\n2983          ; Common # Ps       LEFT WHITE CURLY BRACKET\n2984          ; Common # Pe       RIGHT WHITE CURLY BRACKET\n2985          ; Common # Ps       LEFT WHITE PARENTHESIS\n2986          ; Common # Pe       RIGHT WHITE PARENTHESIS\n2987          ; Common # Ps       Z NOTATION LEFT IMAGE BRACKET\n2988          ; Common # Pe       Z NOTATION RIGHT IMAGE BRACKET\n2989          ; Common # Ps       Z NOTATION LEFT BINDING BRACKET\n298A          ; Common # Pe       Z NOTATION RIGHT BINDING BRACKET\n298B          ; Common # Ps       LEFT SQUARE BRACKET WITH UNDERBAR\n298C          ; Common # Pe       RIGHT SQUARE BRACKET WITH UNDERBAR\n298D          ; Common # Ps       LEFT SQUARE BRACKET WITH TICK IN TOP CORNER\n298E          ; Common # Pe       RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER\n298F          ; Common # Ps       LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER\n2990          ; Common # Pe       RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER\n2991          ; Common # Ps       LEFT ANGLE BRACKET WITH DOT\n2992          ; Common # Pe       RIGHT ANGLE BRACKET WITH DOT\n2993          ; Common # Ps       LEFT ARC LESS-THAN BRACKET\n2994          ; Common # Pe       RIGHT ARC GREATER-THAN BRACKET\n2995          ; Common # Ps       DOUBLE LEFT ARC GREATER-THAN BRACKET\n2996          ; Common # Pe       DOUBLE RIGHT ARC LESS-THAN BRACKET\n2997          ; Common # Ps       LEFT BLACK TORTOISE SHELL BRACKET\n2998          ; Common # Pe       RIGHT BLACK TORTOISE SHELL BRACKET\n2999..29D7    ; Common # Sm  [63] DOTTED FENCE..BLACK HOURGLASS\n29D8          ; Common # Ps       LEFT WIGGLY FENCE\n29D9          ; Common # Pe       RIGHT WIGGLY FENCE\n29DA          ; Common # Ps       LEFT DOUBLE WIGGLY FENCE\n29DB          ; Common # Pe       RIGHT DOUBLE WIGGLY FENCE\n29DC..29FB    ; Common # Sm  [32] INCOMPLETE INFINITY..TRIPLE PLUS\n29FC          ; Common # Ps       LEFT-POINTING CURVED ANGLE BRACKET\n29FD          ; Common # Pe       RIGHT-POINTING CURVED ANGLE BRACKET\n29FE..2AFF    ; Common # Sm [258] TINY..N-ARY WHITE VERTICAL BAR\n2B00..2B2F    ; Common # So  [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE\n2B30..2B44    ; Common # Sm  [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET\n2B45..2B46    ; Common # So   [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW\n2B47..2B4C    ; Common # Sm   [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR\n2B4D..2B73    ; Common # So  [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR\n2B76..2BFF    ; Common # So [138] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..HELLSCHREIBER PAUSE SYMBOL\n2E00..2E01    ; Common # Po   [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER\n2E02          ; Common # Pi       LEFT SUBSTITUTION BRACKET\n2E03          ; Common # Pf       RIGHT SUBSTITUTION BRACKET\n2E04          ; Common # Pi       LEFT DOTTED SUBSTITUTION BRACKET\n2E05          ; Common # Pf       RIGHT DOTTED SUBSTITUTION BRACKET\n2E06..2E08    ; Common # Po   [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER\n2E09          ; Common # Pi       LEFT TRANSPOSITION BRACKET\n2E0A          ; Common # Pf       RIGHT TRANSPOSITION BRACKET\n2E0B          ; Common # Po       RAISED SQUARE\n2E0C          ; Common # Pi       LEFT RAISED OMISSION BRACKET\n2E0D          ; Common # Pf       RIGHT RAISED OMISSION BRACKET\n2E0E..2E16    ; Common # Po   [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE\n2E17          ; Common # Pd       DOUBLE OBLIQUE HYPHEN\n2E18..2E19    ; Common # Po   [2] INVERTED INTERROBANG..PALM BRANCH\n2E1A          ; Common # Pd       HYPHEN WITH DIAERESIS\n2E1B          ; Common # Po       TILDE WITH RING ABOVE\n2E1C          ; Common # Pi       LEFT LOW PARAPHRASE BRACKET\n2E1D          ; Common # Pf       RIGHT LOW PARAPHRASE BRACKET\n2E1E..2E1F    ; Common # Po   [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW\n2E20          ; Common # Pi       LEFT VERTICAL BAR WITH QUILL\n2E21          ; Common # Pf       RIGHT VERTICAL BAR WITH QUILL\n2E22          ; Common # Ps       TOP LEFT HALF BRACKET\n2E23          ; Common # Pe       TOP RIGHT HALF BRACKET\n2E24          ; Common # Ps       BOTTOM LEFT HALF BRACKET\n2E25          ; Common # Pe       BOTTOM RIGHT HALF BRACKET\n2E26          ; Common # Ps       LEFT SIDEWAYS U BRACKET\n2E27          ; Common # Pe       RIGHT SIDEWAYS U BRACKET\n2E28          ; Common # Ps       LEFT DOUBLE PARENTHESIS\n2E29          ; Common # Pe       RIGHT DOUBLE PARENTHESIS\n2E2A..2E2E    ; Common # Po   [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK\n2E2F          ; Common # Lm       VERTICAL TILDE\n2E30..2E39    ; Common # Po  [10] RING POINT..TOP HALF SECTION SIGN\n2E3A..2E3B    ; Common # Pd   [2] TWO-EM DASH..THREE-EM DASH\n2E3C..2E3F    ; Common # Po   [4] STENOGRAPHIC FULL STOP..CAPITULUM\n2E40          ; Common # Pd       DOUBLE HYPHEN\n2E41          ; Common # Po       REVERSED COMMA\n2E42          ; Common # Ps       DOUBLE LOW-REVERSED-9 QUOTATION MARK\n2E43..2E4F    ; Common # Po  [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER\n2E50..2E51    ; Common # So   [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR\n2E52..2E54    ; Common # Po   [3] TIRONIAN SIGN CAPITAL ET..MEDIEVAL QUESTION MARK\n2E55          ; Common # Ps       LEFT SQUARE BRACKET WITH STROKE\n2E56          ; Common # Pe       RIGHT SQUARE BRACKET WITH STROKE\n2E57          ; Common # Ps       LEFT SQUARE BRACKET WITH DOUBLE STROKE\n2E58          ; Common # Pe       RIGHT SQUARE BRACKET WITH DOUBLE STROKE\n2E59          ; Common # Ps       TOP HALF LEFT PARENTHESIS\n2E5A          ; Common # Pe       TOP HALF RIGHT PARENTHESIS\n2E5B          ; Common # Ps       BOTTOM HALF LEFT PARENTHESIS\n2E5C          ; Common # Pe       BOTTOM HALF RIGHT PARENTHESIS\n2E5D          ; Common # Pd       OBLIQUE HYPHEN\n2FF0..2FFF    ; Common # So  [16] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION\n3000          ; Common # Zs       IDEOGRAPHIC SPACE\n3001..3003    ; Common # Po   [3] IDEOGRAPHIC COMMA..DITTO MARK\n3004          ; Common # So       JAPANESE INDUSTRIAL STANDARD SYMBOL\n3006          ; Common # Lo       IDEOGRAPHIC CLOSING MARK\n3008          ; Common # Ps       LEFT ANGLE BRACKET\n3009          ; Common # Pe       RIGHT ANGLE BRACKET\n300A          ; Common # Ps       LEFT DOUBLE ANGLE BRACKET\n300B          ; Common # Pe       RIGHT DOUBLE ANGLE BRACKET\n300C          ; Common # Ps       LEFT CORNER BRACKET\n300D          ; Common # Pe       RIGHT CORNER BRACKET\n300E          ; Common # Ps       LEFT WHITE CORNER BRACKET\n300F          ; Common # Pe       RIGHT WHITE CORNER BRACKET\n3010          ; Common # Ps       LEFT BLACK LENTICULAR BRACKET\n3011          ; Common # Pe       RIGHT BLACK LENTICULAR BRACKET\n3012..3013    ; Common # So   [2] POSTAL MARK..GETA MARK\n3014          ; Common # Ps       LEFT TORTOISE SHELL BRACKET\n3015          ; Common # Pe       RIGHT TORTOISE SHELL BRACKET\n3016          ; Common # Ps       LEFT WHITE LENTICULAR BRACKET\n3017          ; Common # Pe       RIGHT WHITE LENTICULAR BRACKET\n3018          ; Common # Ps       LEFT WHITE TORTOISE SHELL BRACKET\n3019          ; Common # Pe       RIGHT WHITE TORTOISE SHELL BRACKET\n301A          ; Common # Ps       LEFT WHITE SQUARE BRACKET\n301B          ; Common # Pe       RIGHT WHITE SQUARE BRACKET\n301C          ; Common # Pd       WAVE DASH\n301D          ; Common # Ps       REVERSED DOUBLE PRIME QUOTATION MARK\n301E..301F    ; Common # Pe   [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK\n3020          ; Common # So       POSTAL MARK FACE\n3030          ; Common # Pd       WAVY DASH\n3031..3035    ; Common # Lm   [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF\n3036..3037    ; Common # So   [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL\n303C          ; Common # Lo       MASU MARK\n303D          ; Common # Po       PART ALTERNATION MARK\n303E..303F    ; Common # So   [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE\n309B..309C    ; Common # Sk   [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n30A0          ; Common # Pd       KATAKANA-HIRAGANA DOUBLE HYPHEN\n30FB          ; Common # Po       KATAKANA MIDDLE DOT\n30FC          ; Common # Lm       KATAKANA-HIRAGANA PROLONGED SOUND MARK\n3190..3191    ; Common # So   [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK\n3192..3195    ; Common # No   [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK\n3196..319F    ; Common # So  [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK\n31C0..31E5    ; Common # So  [38] CJK STROKE T..CJK STROKE SZP\n31EF          ; Common # So       IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION\n3220..3229    ; Common # No  [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN\n322A..3247    ; Common # So  [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO\n3248..324F    ; Common # No   [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE\n3250          ; Common # So       PARTNERSHIP SIGN\n3251..325F    ; Common # No  [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE\n327F          ; Common # So       KOREAN STANDARD SYMBOL\n3280..3289    ; Common # No  [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN\n328A..32B0    ; Common # So  [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT\n32B1..32BF    ; Common # No  [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY\n32C0..32CF    ; Common # So  [16] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..LIMITED LIABILITY SIGN\n32FF          ; Common # So       SQUARE ERA NAME REIWA\n3358..33FF    ; Common # So [168] IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO..SQUARE GAL\n4DC0..4DFF    ; Common # So  [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION\nA700..A716    ; Common # Sk  [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR\nA717..A71F    ; Common # Lm   [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK\nA720..A721    ; Common # Sk   [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE\nA788          ; Common # Lm       MODIFIER LETTER LOW CIRCUMFLEX ACCENT\nA789..A78A    ; Common # Sk   [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN\nA830..A835    ; Common # No   [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS\nA836..A837    ; Common # So   [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK\nA838          ; Common # Sc       NORTH INDIC RUPEE MARK\nA839          ; Common # So       NORTH INDIC QUANTITY MARK\nA92E          ; Common # Po       KAYAH LI SIGN CWI\nA9CF          ; Common # Lm       JAVANESE PANGRANGKEP\nAB5B          ; Common # Sk       MODIFIER BREVE WITH INVERTED BREVE\nAB6A..AB6B    ; Common # Sk   [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK\nFD3E          ; Common # Pe       ORNATE LEFT PARENTHESIS\nFD3F          ; Common # Ps       ORNATE RIGHT PARENTHESIS\nFE10..FE16    ; Common # Po   [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK\nFE17          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET\nFE18          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET\nFE19          ; Common # Po       PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS\nFE30          ; Common # Po       PRESENTATION FORM FOR VERTICAL TWO DOT LEADER\nFE31..FE32    ; Common # Pd   [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH\nFE33..FE34    ; Common # Pc   [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE\nFE35          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS\nFE36          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS\nFE37          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET\nFE38          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET\nFE39          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET\nFE3A          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET\nFE3B          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET\nFE3C          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET\nFE3D          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET\nFE3E          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET\nFE3F          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET\nFE40          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET\nFE41          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET\nFE42          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET\nFE43          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET\nFE44          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET\nFE45..FE46    ; Common # Po   [2] SESAME DOT..WHITE SESAME DOT\nFE47          ; Common # Ps       PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET\nFE48          ; Common # Pe       PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET\nFE49..FE4C    ; Common # Po   [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE\nFE4D..FE4F    ; Common # Pc   [3] DASHED LOW LINE..WAVY LOW LINE\nFE50..FE52    ; Common # Po   [3] SMALL COMMA..SMALL FULL STOP\nFE54..FE57    ; Common # Po   [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK\nFE58          ; Common # Pd       SMALL EM DASH\nFE59          ; Common # Ps       SMALL LEFT PARENTHESIS\nFE5A          ; Common # Pe       SMALL RIGHT PARENTHESIS\nFE5B          ; Common # Ps       SMALL LEFT CURLY BRACKET\nFE5C          ; Common # Pe       SMALL RIGHT CURLY BRACKET\nFE5D          ; Common # Ps       SMALL LEFT TORTOISE SHELL BRACKET\nFE5E          ; Common # Pe       SMALL RIGHT TORTOISE SHELL BRACKET\nFE5F..FE61    ; Common # Po   [3] SMALL NUMBER SIGN..SMALL ASTERISK\nFE62          ; Common # Sm       SMALL PLUS SIGN\nFE63          ; Common # Pd       SMALL HYPHEN-MINUS\nFE64..FE66    ; Common # Sm   [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN\nFE68          ; Common # Po       SMALL REVERSE SOLIDUS\nFE69          ; Common # Sc       SMALL DOLLAR SIGN\nFE6A..FE6B    ; Common # Po   [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT\nFEFF          ; Common # Cf       ZERO WIDTH NO-BREAK SPACE\nFF01..FF03    ; Common # Po   [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN\nFF04          ; Common # Sc       FULLWIDTH DOLLAR SIGN\nFF05..FF07    ; Common # Po   [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE\nFF08          ; Common # Ps       FULLWIDTH LEFT PARENTHESIS\nFF09          ; Common # Pe       FULLWIDTH RIGHT PARENTHESIS\nFF0A          ; Common # Po       FULLWIDTH ASTERISK\nFF0B          ; Common # Sm       FULLWIDTH PLUS SIGN\nFF0C          ; Common # Po       FULLWIDTH COMMA\nFF0D          ; Common # Pd       FULLWIDTH HYPHEN-MINUS\nFF0E..FF0F    ; Common # Po   [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS\nFF10..FF19    ; Common # Nd  [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE\nFF1A..FF1B    ; Common # Po   [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON\nFF1C..FF1E    ; Common # Sm   [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN\nFF1F..FF20    ; Common # Po   [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT\nFF3B          ; Common # Ps       FULLWIDTH LEFT SQUARE BRACKET\nFF3C          ; Common # Po       FULLWIDTH REVERSE SOLIDUS\nFF3D          ; Common # Pe       FULLWIDTH RIGHT SQUARE BRACKET\nFF3E          ; Common # Sk       FULLWIDTH CIRCUMFLEX ACCENT\nFF3F          ; Common # Pc       FULLWIDTH LOW LINE\nFF40          ; Common # Sk       FULLWIDTH GRAVE ACCENT\nFF5B          ; Common # Ps       FULLWIDTH LEFT CURLY BRACKET\nFF5C          ; Common # Sm       FULLWIDTH VERTICAL LINE\nFF5D          ; Common # Pe       FULLWIDTH RIGHT CURLY BRACKET\nFF5E          ; Common # Sm       FULLWIDTH TILDE\nFF5F          ; Common # Ps       FULLWIDTH LEFT WHITE PARENTHESIS\nFF60          ; Common # Pe       FULLWIDTH RIGHT WHITE PARENTHESIS\nFF61          ; Common # Po       HALFWIDTH IDEOGRAPHIC FULL STOP\nFF62          ; Common # Ps       HALFWIDTH LEFT CORNER BRACKET\nFF63          ; Common # Pe       HALFWIDTH RIGHT CORNER BRACKET\nFF64..FF65    ; Common # Po   [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT\nFF70          ; Common # Lm       HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK\nFF9E..FF9F    ; Common # Lm   [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK\nFFE0..FFE1    ; Common # Sc   [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN\nFFE2          ; Common # Sm       FULLWIDTH NOT SIGN\nFFE3          ; Common # Sk       FULLWIDTH MACRON\nFFE4          ; Common # So       FULLWIDTH BROKEN BAR\nFFE5..FFE6    ; Common # Sc   [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN\nFFE8          ; Common # So       HALFWIDTH FORMS LIGHT VERTICAL\nFFE9..FFEC    ; Common # Sm   [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW\nFFED..FFEE    ; Common # So   [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE\nFFF9..FFFB    ; Common # Cf   [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR\nFFFC..FFFD    ; Common # So   [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER\n10100..10102  ; Common # Po   [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK\n10107..10133  ; Common # No  [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND\n10137..1013F  ; Common # So   [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT\n10190..1019C  ; Common # So  [13] ROMAN SEXTANS SIGN..ASCIA SYMBOL\n101D0..101FC  ; Common # So  [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND\n102E1..102FB  ; Common # No  [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED\n1BCA0..1BCA3  ; Common # Cf   [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP\n1CC00..1CCEF  ; Common # So [240] UP-POINTING GO-KART..OUTLINED LATIN CAPITAL LETTER Z\n1CCF0..1CCF9  ; Common # Nd  [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE\n1CCFA..1CCFC  ; Common # So   [3] SNAKE SYMBOL..NOSE SYMBOL\n1CD00..1CEB3  ; Common # So [436] BLOCK OCTANT-3..BLACK RIGHT TRIANGLE CARET\n1CEBA..1CED0  ; Common # So  [23] FRAGILE SYMBOL..LEUKOTHEA\n1CEE0..1CEEF  ; Common # So  [16] GEOMANTIC FIGURE POPULUS..GEOMANTIC FIGURE VIA\n1CEF0         ; Common # Sm       MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR\n1CF50..1CFC3  ; Common # So [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK\n1D000..1D0F5  ; Common # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO\n1D100..1D126  ; Common # So  [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2\n1D129..1D164  ; Common # So  [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE\n1D165..1D166  ; Common # Mc   [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM\n1D16A..1D16C  ; Common # So   [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3\n1D16D..1D172  ; Common # Mc   [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5\n1D173..1D17A  ; Common # Cf   [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE\n1D183..1D184  ; Common # So   [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN\n1D18C..1D1A9  ; Common # So  [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH\n1D1AE..1D1EA  ; Common # So  [61] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KORON\n1D2C0..1D2D3  ; Common # No  [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN\n1D2E0..1D2F3  ; Common # No  [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN\n1D300..1D356  ; Common # So  [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING\n1D360..1D378  ; Common # No  [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE\n1D400..1D454  ; Common # L&  [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G\n1D456..1D49C  ; Common # L&  [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A\n1D49E..1D49F  ; Common # L&   [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D\n1D4A2         ; Common # L&       MATHEMATICAL SCRIPT CAPITAL G\n1D4A5..1D4A6  ; Common # L&   [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K\n1D4A9..1D4AC  ; Common # L&   [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q\n1D4AE..1D4B9  ; Common # L&  [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D\n1D4BB         ; Common # L&       MATHEMATICAL SCRIPT SMALL F\n1D4BD..1D4C3  ; Common # L&   [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N\n1D4C5..1D505  ; Common # L&  [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B\n1D507..1D50A  ; Common # L&   [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G\n1D50D..1D514  ; Common # L&   [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q\n1D516..1D51C  ; Common # L&   [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y\n1D51E..1D539  ; Common # L&  [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B\n1D53B..1D53E  ; Common # L&   [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G\n1D540..1D544  ; Common # L&   [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M\n1D546         ; Common # L&       MATHEMATICAL DOUBLE-STRUCK CAPITAL O\n1D54A..1D550  ; Common # L&   [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y\n1D552..1D6A5  ; Common # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J\n1D6A8..1D6C0  ; Common # L&  [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA\n1D6C1         ; Common # Sm       MATHEMATICAL BOLD NABLA\n1D6C2..1D6DA  ; Common # L&  [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA\n1D6DB         ; Common # Sm       MATHEMATICAL BOLD PARTIAL DIFFERENTIAL\n1D6DC..1D6FA  ; Common # L&  [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA\n1D6FB         ; Common # Sm       MATHEMATICAL ITALIC NABLA\n1D6FC..1D714  ; Common # L&  [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA\n1D715         ; Common # Sm       MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL\n1D716..1D734  ; Common # L&  [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA\n1D735         ; Common # Sm       MATHEMATICAL BOLD ITALIC NABLA\n1D736..1D74E  ; Common # L&  [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA\n1D74F         ; Common # Sm       MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL\n1D750..1D76E  ; Common # L&  [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA\n1D76F         ; Common # Sm       MATHEMATICAL SANS-SERIF BOLD NABLA\n1D770..1D788  ; Common # L&  [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA\n1D789         ; Common # Sm       MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL\n1D78A..1D7A8  ; Common # L&  [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA\n1D7A9         ; Common # Sm       MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA\n1D7AA..1D7C2  ; Common # L&  [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA\n1D7C3         ; Common # Sm       MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL\n1D7C4..1D7CB  ; Common # L&   [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA\n1D7CE..1D7FF  ; Common # Nd  [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE\n1EC71..1ECAB  ; Common # No  [59] INDIC SIYAQ NUMBER ONE..INDIC SIYAQ NUMBER PREFIXED NINE\n1ECAC         ; Common # So       INDIC SIYAQ PLACEHOLDER\n1ECAD..1ECAF  ; Common # No   [3] INDIC SIYAQ FRACTION ONE QUARTER..INDIC SIYAQ FRACTION THREE QUARTERS\n1ECB0         ; Common # Sc       INDIC SIYAQ RUPEE MARK\n1ECB1..1ECB4  ; Common # No   [4] INDIC SIYAQ NUMBER ALTERNATE ONE..INDIC SIYAQ ALTERNATE LAKH MARK\n1ED01..1ED2D  ; Common # No  [45] OTTOMAN SIYAQ NUMBER ONE..OTTOMAN SIYAQ NUMBER NINETY THOUSAND\n1ED2E         ; Common # So       OTTOMAN SIYAQ MARRATAN\n1ED2F..1ED3D  ; Common # No  [15] OTTOMAN SIYAQ ALTERNATE NUMBER TWO..OTTOMAN SIYAQ FRACTION ONE SIXTH\n1F000..1F02B  ; Common # So  [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK\n1F030..1F093  ; Common # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06\n1F0A0..1F0AE  ; Common # So  [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES\n1F0B1..1F0BF  ; Common # So  [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER\n1F0C1..1F0CF  ; Common # So  [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER\n1F0D1..1F0F5  ; Common # So  [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21\n1F100..1F10C  ; Common # No  [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO\n1F10D..1F1AD  ; Common # So [161] CIRCLED ZERO WITH SLASH..MASK WORK SYMBOL\n1F1E6..1F1FF  ; Common # So  [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z\n1F201..1F202  ; Common # So   [2] SQUARED KATAKANA KOKO..SQUARED KATAKANA SA\n1F210..1F23B  ; Common # So  [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D\n1F240..1F248  ; Common # So   [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557\n1F250..1F251  ; Common # So   [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT\n1F260..1F265  ; Common # So   [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI\n1F300..1F3FA  ; Common # So [251] CYCLONE..AMPHORA\n1F3FB..1F3FF  ; Common # Sk   [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6\n1F400..1F6D8  ; Common # So [729] RAT..LANDSLIDE\n1F6DC..1F6EC  ; Common # So  [17] WIRELESS..AIRPLANE ARRIVING\n1F6F0..1F6FC  ; Common # So  [13] SATELLITE..ROLLER SKATE\n1F700..1F7D9  ; Common # So [218] ALCHEMICAL SYMBOL FOR QUINTESSENCE..NINE POINTED WHITE STAR\n1F7E0..1F7EB  ; Common # So  [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE\n1F7F0         ; Common # So       HEAVY EQUALS SIGN\n1F800..1F80B  ; Common # So  [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD\n1F810..1F847  ; Common # So  [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW\n1F850..1F859  ; Common # So  [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW\n1F860..1F887  ; Common # So  [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW\n1F890..1F8AD  ; Common # So  [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS\n1F8B0..1F8BB  ; Common # So  [12] ARROW POINTING UPWARDS THEN NORTH WEST..SOUTH WEST ARROW FROM BAR\n1F8C0..1F8C1  ; Common # So   [2] LEFTWARDS ARROW FROM DOWNWARDS ARROW..RIGHTWARDS ARROW FROM DOWNWARDS ARROW\n1F8D0..1F8D8  ; Common # Sm   [9] LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW..LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE\n1F900..1FA57  ; Common # So [344] CIRCLED CROSS FORMEE WITH FOUR DOTS..BLACK CHESS ALFIL\n1FA60..1FA6D  ; Common # So  [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER\n1FA70..1FA7C  ; Common # So  [13] BALLET SHOES..CRUTCH\n1FA80..1FA8A  ; Common # So  [11] YO-YO..TROMBONE\n1FA8E..1FAC6  ; Common # So  [57] TREASURE CHEST..FINGERPRINT\n1FAC8         ; Common # So       HAIRY CREATURE\n1FACD..1FADC  ; Common # So  [16] ORCA..ROOT VEGETABLE\n1FADF..1FAEA  ; Common # So  [12] SPLATTER..DISTORTED FACE\n1FAEF..1FAF8  ; Common # So  [10] FIGHT CLOUD..RIGHTWARDS PUSHING HAND\n1FB00..1FB92  ; Common # So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK\n1FB94..1FBEF  ; Common # So  [92] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE\n1FBF0..1FBF9  ; Common # Nd  [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE\n1FBFA         ; Common # So       ALARM BELL SYMBOL\nE0001         ; Common # Cf       LANGUAGE TAG\nE0020..E007F  ; Common # Cf  [96] TAG SPACE..CANCEL TAG\n\n# Total code points: 9123\n\n# ================================================\n\n0041..005A    ; Latin # L&  [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z\n0061..007A    ; Latin # L&  [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z\n00AA          ; Latin # Lo       FEMININE ORDINAL INDICATOR\n00BA          ; Latin # Lo       MASCULINE ORDINAL INDICATOR\n00C0..00D6    ; Latin # L&  [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS\n00D8..00F6    ; Latin # L&  [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS\n00F8..01BA    ; Latin # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL\n01BB          ; Latin # Lo       LATIN LETTER TWO WITH STROKE\n01BC..01BF    ; Latin # L&   [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN\n01C0..01C3    ; Latin # Lo   [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK\n01C4..0293    ; Latin # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL\n0294..0295    ; Latin # Lo   [2] LATIN LETTER GLOTTAL STOP..LATIN LETTER PHARYNGEAL VOICED FRICATIVE\n0296..02AF    ; Latin # L&  [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL\n02B0..02B8    ; Latin # Lm   [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y\n02E0..02E4    ; Latin # Lm   [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP\n1D00..1D25    ; Latin # L&  [38] LATIN LETTER SMALL CAPITAL A..LATIN LETTER AIN\n1D2C..1D5C    ; Latin # Lm  [49] MODIFIER LETTER CAPITAL A..MODIFIER LETTER SMALL AIN\n1D62..1D65    ; Latin # Lm   [4] LATIN SUBSCRIPT SMALL LETTER I..LATIN SUBSCRIPT SMALL LETTER V\n1D6B..1D77    ; Latin # L&  [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G\n1D79..1D9A    ; Latin # L&  [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK\n1D9B..1DBE    ; Latin # Lm  [36] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL EZH\n1E00..1EFF    ; Latin # L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP\n2071          ; Latin # Lm       SUPERSCRIPT LATIN SMALL LETTER I\n207F          ; Latin # Lm       SUPERSCRIPT LATIN SMALL LETTER N\n2090..209C    ; Latin # Lm  [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T\n212A..212B    ; Latin # L&   [2] KELVIN SIGN..ANGSTROM SIGN\n2132          ; Latin # L&       TURNED CAPITAL F\n214E          ; Latin # L&       TURNED SMALL F\n2160..2182    ; Latin # Nl  [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND\n2183..2184    ; Latin # L&   [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C\n2185..2188    ; Latin # Nl   [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND\n2C60..2C7B    ; Latin # L&  [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E\n2C7C..2C7D    ; Latin # Lm   [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V\n2C7E..2C7F    ; Latin # L&   [2] LATIN CAPITAL LETTER S WITH SWASH TAIL..LATIN CAPITAL LETTER Z WITH SWASH TAIL\nA722..A76F    ; Latin # L&  [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON\nA770          ; Latin # Lm       MODIFIER LETTER US\nA771..A787    ; Latin # L&  [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T\nA78B..A78E    ; Latin # L&   [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT\nA78F          ; Latin # Lo       LATIN LETTER SINOLOGICAL DOT\nA790..A7DC    ; Latin # L&  [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE\nA7F1..A7F4    ; Latin # Lm   [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q\nA7F5..A7F6    ; Latin # L&   [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H\nA7F7          ; Latin # Lo       LATIN EPIGRAPHIC LETTER SIDEWAYS I\nA7F8..A7F9    ; Latin # Lm   [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE\nA7FA          ; Latin # L&       LATIN LETTER SMALL CAPITAL TURNED M\nA7FB..A7FF    ; Latin # Lo   [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M\nAB30..AB5A    ; Latin # L&  [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG\nAB5C..AB5F    ; Latin # Lm   [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK\nAB60..AB64    ; Latin # L&   [5] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER INVERTED ALPHA\nAB66..AB68    ; Latin # L&   [3] LATIN SMALL LETTER DZ DIGRAPH WITH RETROFLEX HOOK..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE\nAB69          ; Latin # Lm       MODIFIER LETTER SMALL TURNED W\nFB00..FB06    ; Latin # L&   [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST\nFF21..FF3A    ; Latin # L&  [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z\nFF41..FF5A    ; Latin # L&  [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z\n10780..10785  ; Latin # Lm   [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK\n10787..107B0  ; Latin # Lm  [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK\n107B2..107BA  ; Latin # Lm   [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL\n1DF00..1DF09  ; Latin # L&  [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK\n1DF0A         ; Latin # Lo       LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK\n1DF0B..1DF1E  ; Latin # L&  [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL\n1DF25..1DF2A  ; Latin # L&   [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK\n\n# Total code points: 1492\n\n# ================================================\n\n0370..0373    ; Greek # L&   [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI\n0375          ; Greek # Sk       GREEK LOWER NUMERAL SIGN\n0376..0377    ; Greek # L&   [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA\n037A          ; Greek # Lm       GREEK YPOGEGRAMMENI\n037B..037D    ; Greek # L&   [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL\n037F          ; Greek # L&       GREEK CAPITAL LETTER YOT\n0384          ; Greek # Sk       GREEK TONOS\n0386          ; Greek # L&       GREEK CAPITAL LETTER ALPHA WITH TONOS\n0388..038A    ; Greek # L&   [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS\n038C          ; Greek # L&       GREEK CAPITAL LETTER OMICRON WITH TONOS\n038E..03A1    ; Greek # L&  [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO\n03A3..03E1    ; Greek # L&  [63] GREEK CAPITAL LETTER SIGMA..GREEK SMALL LETTER SAMPI\n03F0..03F5    ; Greek # L&   [6] GREEK KAPPA SYMBOL..GREEK LUNATE EPSILON SYMBOL\n03F6          ; Greek # Sm       GREEK REVERSED LUNATE EPSILON SYMBOL\n03F7..03FF    ; Greek # L&   [9] GREEK CAPITAL LETTER SHO..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL\n1D26..1D2A    ; Greek # L&   [5] GREEK LETTER SMALL CAPITAL GAMMA..GREEK LETTER SMALL CAPITAL PSI\n1D5D..1D61    ; Greek # Lm   [5] MODIFIER LETTER SMALL BETA..MODIFIER LETTER SMALL CHI\n1D66..1D6A    ; Greek # Lm   [5] GREEK SUBSCRIPT SMALL LETTER BETA..GREEK SUBSCRIPT SMALL LETTER CHI\n1DBF          ; Greek # Lm       MODIFIER LETTER SMALL THETA\n1F00..1F15    ; Greek # L&  [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA\n1F18..1F1D    ; Greek # L&   [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA\n1F20..1F45    ; Greek # L&  [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA\n1F48..1F4D    ; Greek # L&   [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA\n1F50..1F57    ; Greek # L&   [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI\n1F59          ; Greek # L&       GREEK CAPITAL LETTER UPSILON WITH DASIA\n1F5B          ; Greek # L&       GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA\n1F5D          ; Greek # L&       GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA\n1F5F..1F7D    ; Greek # L&  [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA\n1F80..1FB4    ; Greek # L&  [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI\n1FB6..1FBC    ; Greek # L&   [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI\n1FBD          ; Greek # Sk       GREEK KORONIS\n1FBE          ; Greek # L&       GREEK PROSGEGRAMMENI\n1FBF..1FC1    ; Greek # Sk   [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI\n1FC2..1FC4    ; Greek # L&   [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI\n1FC6..1FCC    ; Greek # L&   [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI\n1FCD..1FCF    ; Greek # Sk   [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI\n1FD0..1FD3    ; Greek # L&   [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA\n1FD6..1FDB    ; Greek # L&   [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA\n1FDD..1FDF    ; Greek # Sk   [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI\n1FE0..1FEC    ; Greek # L&  [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA\n1FED..1FEF    ; Greek # Sk   [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA\n1FF2..1FF4    ; Greek # L&   [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI\n1FF6..1FFC    ; Greek # L&   [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI\n1FFD..1FFE    ; Greek # Sk   [2] GREEK OXIA..GREEK DASIA\n2126          ; Greek # L&       OHM SIGN\nAB65          ; Greek # L&       GREEK LETTER SMALL CAPITAL OMEGA\n10140..10174  ; Greek # Nl  [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS\n10175..10178  ; Greek # No   [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN\n10179..10189  ; Greek # So  [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN\n1018A..1018B  ; Greek # No   [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN\n1018C..1018E  ; Greek # So   [3] GREEK SINUSOID SIGN..NOMISMA SIGN\n101A0         ; Greek # So       GREEK SYMBOL TAU RHO\n1D200..1D241  ; Greek # So  [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54\n1D242..1D244  ; Greek # Mn   [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME\n1D245         ; Greek # So       GREEK MUSICAL LEIMMA\n\n# Total code points: 518\n\n# ================================================\n\n0400..0481    ; Cyrillic # L& [130] CYRILLIC CAPITAL LETTER IE WITH GRAVE..CYRILLIC SMALL LETTER KOPPA\n0482          ; Cyrillic # So       CYRILLIC THOUSANDS SIGN\n0483..0484    ; Cyrillic # Mn   [2] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC PALATALIZATION\n0487          ; Cyrillic # Mn       COMBINING CYRILLIC POKRYTIE\n0488..0489    ; Cyrillic # Me   [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN\n048A..052F    ; Cyrillic # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER\n1C80..1C8A    ; Cyrillic # L&  [11] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER TJE\n1D2B          ; Cyrillic # L&       CYRILLIC LETTER SMALL CAPITAL EL\n1D78          ; Cyrillic # Lm       MODIFIER LETTER CYRILLIC EN\n2DE0..2DFF    ; Cyrillic # Mn  [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS\nA640..A66D    ; Cyrillic # L&  [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O\nA66E          ; Cyrillic # Lo       CYRILLIC LETTER MULTIOCULAR O\nA66F          ; Cyrillic # Mn       COMBINING CYRILLIC VZMET\nA670..A672    ; Cyrillic # Me   [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN\nA673          ; Cyrillic # Po       SLAVONIC ASTERISK\nA674..A67D    ; Cyrillic # Mn  [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK\nA67E          ; Cyrillic # Po       CYRILLIC KAVYKA\nA67F          ; Cyrillic # Lm       CYRILLIC PAYEROK\nA680..A69B    ; Cyrillic # L&  [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O\nA69C..A69D    ; Cyrillic # Lm   [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN\nA69E..A69F    ; Cyrillic # Mn   [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E\nFE2E..FE2F    ; Cyrillic # Mn   [2] COMBINING CYRILLIC TITLO LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF\n1E030..1E06D  ; Cyrillic # Lm  [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE\n1E08F         ; Cyrillic # Mn       COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I\n\n# Total code points: 508\n\n# ================================================\n\n0531..0556    ; Armenian # L&  [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH\n0559          ; Armenian # Lm       ARMENIAN MODIFIER LETTER LEFT HALF RING\n055A..055F    ; Armenian # Po   [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK\n0560..0588    ; Armenian # L&  [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE\n0589          ; Armenian # Po       ARMENIAN FULL STOP\n058A          ; Armenian # Pd       ARMENIAN HYPHEN\n058D..058E    ; Armenian # So   [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN\n058F          ; Armenian # Sc       ARMENIAN DRAM SIGN\nFB13..FB17    ; Armenian # L&   [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH\n\n# Total code points: 96\n\n# ================================================\n\n0591..05BD    ; Hebrew # Mn  [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG\n05BE          ; Hebrew # Pd       HEBREW PUNCTUATION MAQAF\n05BF          ; Hebrew # Mn       HEBREW POINT RAFE\n05C0          ; Hebrew # Po       HEBREW PUNCTUATION PASEQ\n05C1..05C2    ; Hebrew # Mn   [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT\n05C3          ; Hebrew # Po       HEBREW PUNCTUATION SOF PASUQ\n05C4..05C5    ; Hebrew # Mn   [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT\n05C6          ; Hebrew # Po       HEBREW PUNCTUATION NUN HAFUKHA\n05C7          ; Hebrew # Mn       HEBREW POINT QAMATS QATAN\n05D0..05EA    ; Hebrew # Lo  [27] HEBREW LETTER ALEF..HEBREW LETTER TAV\n05EF..05F2    ; Hebrew # Lo   [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD\n05F3..05F4    ; Hebrew # Po   [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM\nFB1D          ; Hebrew # Lo       HEBREW LETTER YOD WITH HIRIQ\nFB1E          ; Hebrew # Mn       HEBREW POINT JUDEO-SPANISH VARIKA\nFB1F..FB28    ; Hebrew # Lo  [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV\nFB29          ; Hebrew # Sm       HEBREW LETTER ALTERNATIVE PLUS SIGN\nFB2A..FB36    ; Hebrew # Lo  [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH\nFB38..FB3C    ; Hebrew # Lo   [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH\nFB3E          ; Hebrew # Lo       HEBREW LETTER MEM WITH DAGESH\nFB40..FB41    ; Hebrew # Lo   [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH\nFB43..FB44    ; Hebrew # Lo   [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH\nFB46..FB4F    ; Hebrew # Lo  [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED\n\n# Total code points: 134\n\n# ================================================\n\n0600..0604    ; Arabic # Cf   [5] ARABIC NUMBER SIGN..ARABIC SIGN SAMVAT\n0606..0608    ; Arabic # Sm   [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY\n0609..060A    ; Arabic # Po   [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN\n060B          ; Arabic # Sc       AFGHANI SIGN\n060D          ; Arabic # Po       ARABIC DATE SEPARATOR\n060E..060F    ; Arabic # So   [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA\n0610..061A    ; Arabic # Mn  [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA\n061C          ; Arabic # Cf       ARABIC LETTER MARK\n061D..061E    ; Arabic # Po   [2] ARABIC END OF TEXT MARK..ARABIC TRIPLE DOT PUNCTUATION MARK\n0620..063F    ; Arabic # Lo  [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE\n0641..064A    ; Arabic # Lo  [10] ARABIC LETTER FEH..ARABIC LETTER YEH\n0656..065F    ; Arabic # Mn  [10] ARABIC SUBSCRIPT ALEF..ARABIC WAVY HAMZA BELOW\n0660..0669    ; Arabic # Nd  [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE\n066A..066D    ; Arabic # Po   [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR\n066E..066F    ; Arabic # Lo   [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF\n0671..06D3    ; Arabic # Lo  [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE\n06D4          ; Arabic # Po       ARABIC FULL STOP\n06D5          ; Arabic # Lo       ARABIC LETTER AE\n06D6..06DC    ; Arabic # Mn   [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN\n06DE          ; Arabic # So       ARABIC START OF RUB EL HIZB\n06DF..06E4    ; Arabic # Mn   [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA\n06E5..06E6    ; Arabic # Lm   [2] ARABIC SMALL WAW..ARABIC SMALL YEH\n06E7..06E8    ; Arabic # Mn   [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON\n06E9          ; Arabic # So       ARABIC PLACE OF SAJDAH\n06EA..06ED    ; Arabic # Mn   [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM\n06EE..06EF    ; Arabic # Lo   [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V\n06F0..06F9    ; Arabic # Nd  [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE\n06FA..06FC    ; Arabic # Lo   [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW\n06FD..06FE    ; Arabic # So   [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN\n06FF          ; Arabic # Lo       ARABIC LETTER HEH WITH INVERTED V\n0750..077F    ; Arabic # Lo  [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE\n0870..0887    ; Arabic # Lo  [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT\n0888          ; Arabic # Sk       ARABIC RAISED ROUND DOT\n0889..088F    ; Arabic # Lo   [7] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER NOON WITH RING ABOVE\n0890..0891    ; Arabic # Cf   [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE\n0897..089F    ; Arabic # Mn   [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA\n08A0..08C8    ; Arabic # Lo  [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF\n08C9          ; Arabic # Lm       ARABIC SMALL FARSI YEH\n08CA..08E1    ; Arabic # Mn  [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA\n08E3..08FF    ; Arabic # Mn  [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA\nFB50..FBB1    ; Arabic # Lo  [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM\nFBB2..FBC2    ; Arabic # Sk  [17] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL WASLA ABOVE\nFBC3..FBD2    ; Arabic # So  [16] ARABIC LIGATURE JALLA WA-ALAA..ARABIC LIGATURE ALAYHI AR-RAHMAH\nFBD3..FD3D    ; Arabic # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM\nFD40..FD4F    ; Arabic # So  [16] ARABIC LIGATURE RAHIMAHU ALLAAH..ARABIC LIGATURE RAHIMAHUM ALLAAH\nFD50..FD8F    ; Arabic # Lo  [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM\nFD90..FD91    ; Arabic # So   [2] ARABIC LIGATURE RAHMATU ALLAAHI ALAYH..ARABIC LIGATURE RAHMATU ALLAAHI ALAYHAA\nFD92..FDC7    ; Arabic # Lo  [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM\nFDC8..FDCF    ; Arabic # So   [8] ARABIC LIGATURE RAHIMAHU ALLAAH TAAALAA..ARABIC LIGATURE SALAAMUHU ALAYNAA\nFDF0..FDFB    ; Arabic # Lo  [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU\nFDFC          ; Arabic # Sc       RIAL SIGN\nFDFD..FDFF    ; Arabic # So   [3] ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM..ARABIC LIGATURE AZZA WA JALL\nFE70..FE74    ; Arabic # Lo   [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM\nFE76..FEFC    ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM\n10E60..10E7E  ; Arabic # No  [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS\n10EC2..10EC4  ; Arabic # Lo   [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW\n10EC5         ; Arabic # Lm       ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW\n10EC6..10EC7  ; Arabic # Lo   [2] ARABIC LETTER THIN NOON..ARABIC LETTER YEH WITH FOUR DOTS BELOW\n10ED0         ; Arabic # Po       ARABIC BIBLICAL END OF VERSE\n10ED1..10ED8  ; Arabic # So   [8] ARABIC LIGATURE ALAYHAA AS-SALAATU WAS-SALAAM..ARABIC LIGATURE NAWWARA ALLAAHU MARQADAH\n10EFA..10EFF  ; Arabic # Mn   [6] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC SMALL LOW WORD MADDA\n1EE00..1EE03  ; Arabic # Lo   [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL\n1EE05..1EE1F  ; Arabic # Lo  [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF\n1EE21..1EE22  ; Arabic # Lo   [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM\n1EE24         ; Arabic # Lo       ARABIC MATHEMATICAL INITIAL HEH\n1EE27         ; Arabic # Lo       ARABIC MATHEMATICAL INITIAL HAH\n1EE29..1EE32  ; Arabic # Lo  [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF\n1EE34..1EE37  ; Arabic # Lo   [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH\n1EE39         ; Arabic # Lo       ARABIC MATHEMATICAL INITIAL DAD\n1EE3B         ; Arabic # Lo       ARABIC MATHEMATICAL INITIAL GHAIN\n1EE42         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED JEEM\n1EE47         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED HAH\n1EE49         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED YEH\n1EE4B         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED LAM\n1EE4D..1EE4F  ; Arabic # Lo   [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN\n1EE51..1EE52  ; Arabic # Lo   [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF\n1EE54         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED SHEEN\n1EE57         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED KHAH\n1EE59         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED DAD\n1EE5B         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED GHAIN\n1EE5D         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED DOTLESS NOON\n1EE5F         ; Arabic # Lo       ARABIC MATHEMATICAL TAILED DOTLESS QAF\n1EE61..1EE62  ; Arabic # Lo   [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM\n1EE64         ; Arabic # Lo       ARABIC MATHEMATICAL STRETCHED HEH\n1EE67..1EE6A  ; Arabic # Lo   [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF\n1EE6C..1EE72  ; Arabic # Lo   [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF\n1EE74..1EE77  ; Arabic # Lo   [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH\n1EE79..1EE7C  ; Arabic # Lo   [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH\n1EE7E         ; Arabic # Lo       ARABIC MATHEMATICAL STRETCHED DOTLESS FEH\n1EE80..1EE89  ; Arabic # Lo  [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH\n1EE8B..1EE9B  ; Arabic # Lo  [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN\n1EEA1..1EEA3  ; Arabic # Lo   [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL\n1EEA5..1EEA9  ; Arabic # Lo   [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH\n1EEAB..1EEBB  ; Arabic # Lo  [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN\n1EEF0..1EEF1  ; Arabic # Sm   [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL\n\n# Total code points: 1413\n\n# ================================================\n\n0700..070D    ; Syriac # Po  [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS\n070F          ; Syriac # Cf       SYRIAC ABBREVIATION MARK\n0710          ; Syriac # Lo       SYRIAC LETTER ALAPH\n0711          ; Syriac # Mn       SYRIAC LETTER SUPERSCRIPT ALAPH\n0712..072F    ; Syriac # Lo  [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH\n0730..074A    ; Syriac # Mn  [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH\n074D..074F    ; Syriac # Lo   [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE\n0860..086A    ; Syriac # Lo  [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA\n\n# Total code points: 88\n\n# ================================================\n\n0780..07A5    ; Thaana # Lo  [38] THAANA LETTER HAA..THAANA LETTER WAAVU\n07A6..07B0    ; Thaana # Mn  [11] THAANA ABAFILI..THAANA SUKUN\n07B1          ; Thaana # Lo       THAANA LETTER NAA\n\n# Total code points: 50\n\n# ================================================\n\n0900..0902    ; Devanagari # Mn   [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA\n0903          ; Devanagari # Mc       DEVANAGARI SIGN VISARGA\n0904..0939    ; Devanagari # Lo  [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA\n093A          ; Devanagari # Mn       DEVANAGARI VOWEL SIGN OE\n093B          ; Devanagari # Mc       DEVANAGARI VOWEL SIGN OOE\n093C          ; Devanagari # Mn       DEVANAGARI SIGN NUKTA\n093D          ; Devanagari # Lo       DEVANAGARI SIGN AVAGRAHA\n093E..0940    ; Devanagari # Mc   [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II\n0941..0948    ; Devanagari # Mn   [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI\n0949..094C    ; Devanagari # Mc   [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU\n094D          ; Devanagari # Mn       DEVANAGARI SIGN VIRAMA\n094E..094F    ; Devanagari # Mc   [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW\n0950          ; Devanagari # Lo       DEVANAGARI OM\n0955..0957    ; Devanagari # Mn   [3] DEVANAGARI VOWEL SIGN CANDRA LONG E..DEVANAGARI VOWEL SIGN UUE\n0958..0961    ; Devanagari # Lo  [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL\n0962..0963    ; Devanagari # Mn   [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL\n0966..096F    ; Devanagari # Nd  [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE\n0970          ; Devanagari # Po       DEVANAGARI ABBREVIATION SIGN\n0971          ; Devanagari # Lm       DEVANAGARI SIGN HIGH SPACING DOT\n0972..097F    ; Devanagari # Lo  [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA\nA8E0..A8F1    ; Devanagari # Mn  [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA\nA8F2..A8F7    ; Devanagari # Lo   [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA\nA8F8..A8FA    ; Devanagari # Po   [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET\nA8FB          ; Devanagari # Lo       DEVANAGARI HEADSTROKE\nA8FC          ; Devanagari # Po       DEVANAGARI SIGN SIDDHAM\nA8FD..A8FE    ; Devanagari # Lo   [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY\nA8FF          ; Devanagari # Mn       DEVANAGARI VOWEL SIGN AY\n11B00..11B09  ; Devanagari # Po  [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU\n\n# Total code points: 164\n\n# ================================================\n\n0980          ; Bengali # Lo       BENGALI ANJI\n0981          ; Bengali # Mn       BENGALI SIGN CANDRABINDU\n0982..0983    ; Bengali # Mc   [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA\n0985..098C    ; Bengali # Lo   [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L\n098F..0990    ; Bengali # Lo   [2] BENGALI LETTER E..BENGALI LETTER AI\n0993..09A8    ; Bengali # Lo  [22] BENGALI LETTER O..BENGALI LETTER NA\n09AA..09B0    ; Bengali # Lo   [7] BENGALI LETTER PA..BENGALI LETTER RA\n09B2          ; Bengali # Lo       BENGALI LETTER LA\n09B6..09B9    ; Bengali # Lo   [4] BENGALI LETTER SHA..BENGALI LETTER HA\n09BC          ; Bengali # Mn       BENGALI SIGN NUKTA\n09BD          ; Bengali # Lo       BENGALI SIGN AVAGRAHA\n09BE..09C0    ; Bengali # Mc   [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II\n09C1..09C4    ; Bengali # Mn   [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR\n09C7..09C8    ; Bengali # Mc   [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI\n09CB..09CC    ; Bengali # Mc   [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU\n09CD          ; Bengali # Mn       BENGALI SIGN VIRAMA\n09CE          ; Bengali # Lo       BENGALI LETTER KHANDA TA\n09D7          ; Bengali # Mc       BENGALI AU LENGTH MARK\n09DC..09DD    ; Bengali # Lo   [2] BENGALI LETTER RRA..BENGALI LETTER RHA\n09DF..09E1    ; Bengali # Lo   [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL\n09E2..09E3    ; Bengali # Mn   [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL\n09E6..09EF    ; Bengali # Nd  [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE\n09F0..09F1    ; Bengali # Lo   [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL\n09F2..09F3    ; Bengali # Sc   [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN\n09F4..09F9    ; Bengali # No   [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN\n09FA          ; Bengali # So       BENGALI ISSHAR\n09FB          ; Bengali # Sc       BENGALI GANDA MARK\n09FC          ; Bengali # Lo       BENGALI LETTER VEDIC ANUSVARA\n09FD          ; Bengali # Po       BENGALI ABBREVIATION SIGN\n09FE          ; Bengali # Mn       BENGALI SANDHI MARK\n\n# Total code points: 96\n\n# ================================================\n\n0A01..0A02    ; Gurmukhi # Mn   [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI\n0A03          ; Gurmukhi # Mc       GURMUKHI SIGN VISARGA\n0A05..0A0A    ; Gurmukhi # Lo   [6] GURMUKHI LETTER A..GURMUKHI LETTER UU\n0A0F..0A10    ; Gurmukhi # Lo   [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI\n0A13..0A28    ; Gurmukhi # Lo  [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA\n0A2A..0A30    ; Gurmukhi # Lo   [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA\n0A32..0A33    ; Gurmukhi # Lo   [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA\n0A35..0A36    ; Gurmukhi # Lo   [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA\n0A38..0A39    ; Gurmukhi # Lo   [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA\n0A3C          ; Gurmukhi # Mn       GURMUKHI SIGN NUKTA\n0A3E..0A40    ; Gurmukhi # Mc   [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II\n0A41..0A42    ; Gurmukhi # Mn   [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU\n0A47..0A48    ; Gurmukhi # Mn   [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI\n0A4B..0A4D    ; Gurmukhi # Mn   [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA\n0A51          ; Gurmukhi # Mn       GURMUKHI SIGN UDAAT\n0A59..0A5C    ; Gurmukhi # Lo   [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA\n0A5E          ; Gurmukhi # Lo       GURMUKHI LETTER FA\n0A66..0A6F    ; Gurmukhi # Nd  [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE\n0A70..0A71    ; Gurmukhi # Mn   [2] GURMUKHI TIPPI..GURMUKHI ADDAK\n0A72..0A74    ; Gurmukhi # Lo   [3] GURMUKHI IRI..GURMUKHI EK ONKAR\n0A75          ; Gurmukhi # Mn       GURMUKHI SIGN YAKASH\n0A76          ; Gurmukhi # Po       GURMUKHI ABBREVIATION SIGN\n\n# Total code points: 80\n\n# ================================================\n\n0A81..0A82    ; Gujarati # Mn   [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA\n0A83          ; Gujarati # Mc       GUJARATI SIGN VISARGA\n0A85..0A8D    ; Gujarati # Lo   [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E\n0A8F..0A91    ; Gujarati # Lo   [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O\n0A93..0AA8    ; Gujarati # Lo  [22] GUJARATI LETTER O..GUJARATI LETTER NA\n0AAA..0AB0    ; Gujarati # Lo   [7] GUJARATI LETTER PA..GUJARATI LETTER RA\n0AB2..0AB3    ; Gujarati # Lo   [2] GUJARATI LETTER LA..GUJARATI LETTER LLA\n0AB5..0AB9    ; Gujarati # Lo   [5] GUJARATI LETTER VA..GUJARATI LETTER HA\n0ABC          ; Gujarati # Mn       GUJARATI SIGN NUKTA\n0ABD          ; Gujarati # Lo       GUJARATI SIGN AVAGRAHA\n0ABE..0AC0    ; Gujarati # Mc   [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II\n0AC1..0AC5    ; Gujarati # Mn   [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E\n0AC7..0AC8    ; Gujarati # Mn   [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI\n0AC9          ; Gujarati # Mc       GUJARATI VOWEL SIGN CANDRA O\n0ACB..0ACC    ; Gujarati # Mc   [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU\n0ACD          ; Gujarati # Mn       GUJARATI SIGN VIRAMA\n0AD0          ; Gujarati # Lo       GUJARATI OM\n0AE0..0AE1    ; Gujarati # Lo   [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL\n0AE2..0AE3    ; Gujarati # Mn   [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL\n0AE6..0AEF    ; Gujarati # Nd  [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE\n0AF0          ; Gujarati # Po       GUJARATI ABBREVIATION SIGN\n0AF1          ; Gujarati # Sc       GUJARATI RUPEE SIGN\n0AF9          ; Gujarati # Lo       GUJARATI LETTER ZHA\n0AFA..0AFF    ; Gujarati # Mn   [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE\n\n# Total code points: 91\n\n# ================================================\n\n0B01          ; Oriya # Mn       ORIYA SIGN CANDRABINDU\n0B02..0B03    ; Oriya # Mc   [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA\n0B05..0B0C    ; Oriya # Lo   [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L\n0B0F..0B10    ; Oriya # Lo   [2] ORIYA LETTER E..ORIYA LETTER AI\n0B13..0B28    ; Oriya # Lo  [22] ORIYA LETTER O..ORIYA LETTER NA\n0B2A..0B30    ; Oriya # Lo   [7] ORIYA LETTER PA..ORIYA LETTER RA\n0B32..0B33    ; Oriya # Lo   [2] ORIYA LETTER LA..ORIYA LETTER LLA\n0B35..0B39    ; Oriya # Lo   [5] ORIYA LETTER VA..ORIYA LETTER HA\n0B3C          ; Oriya # Mn       ORIYA SIGN NUKTA\n0B3D          ; Oriya # Lo       ORIYA SIGN AVAGRAHA\n0B3E          ; Oriya # Mc       ORIYA VOWEL SIGN AA\n0B3F          ; Oriya # Mn       ORIYA VOWEL SIGN I\n0B40          ; Oriya # Mc       ORIYA VOWEL SIGN II\n0B41..0B44    ; Oriya # Mn   [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR\n0B47..0B48    ; Oriya # Mc   [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI\n0B4B..0B4C    ; Oriya # Mc   [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU\n0B4D          ; Oriya # Mn       ORIYA SIGN VIRAMA\n0B55..0B56    ; Oriya # Mn   [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK\n0B57          ; Oriya # Mc       ORIYA AU LENGTH MARK\n0B5C..0B5D    ; Oriya # Lo   [2] ORIYA LETTER RRA..ORIYA LETTER RHA\n0B5F..0B61    ; Oriya # Lo   [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL\n0B62..0B63    ; Oriya # Mn   [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL\n0B66..0B6F    ; Oriya # Nd  [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE\n0B70          ; Oriya # So       ORIYA ISSHAR\n0B71          ; Oriya # Lo       ORIYA LETTER WA\n0B72..0B77    ; Oriya # No   [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS\n\n# Total code points: 91\n\n# ================================================\n\n0B82          ; Tamil # Mn       TAMIL SIGN ANUSVARA\n0B83          ; Tamil # Lo       TAMIL SIGN VISARGA\n0B85..0B8A    ; Tamil # Lo   [6] TAMIL LETTER A..TAMIL LETTER UU\n0B8E..0B90    ; Tamil # Lo   [3] TAMIL LETTER E..TAMIL LETTER AI\n0B92..0B95    ; Tamil # Lo   [4] TAMIL LETTER O..TAMIL LETTER KA\n0B99..0B9A    ; Tamil # Lo   [2] TAMIL LETTER NGA..TAMIL LETTER CA\n0B9C          ; Tamil # Lo       TAMIL LETTER JA\n0B9E..0B9F    ; Tamil # Lo   [2] TAMIL LETTER NYA..TAMIL LETTER TTA\n0BA3..0BA4    ; Tamil # Lo   [2] TAMIL LETTER NNA..TAMIL LETTER TA\n0BA8..0BAA    ; Tamil # Lo   [3] TAMIL LETTER NA..TAMIL LETTER PA\n0BAE..0BB9    ; Tamil # Lo  [12] TAMIL LETTER MA..TAMIL LETTER HA\n0BBE..0BBF    ; Tamil # Mc   [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I\n0BC0          ; Tamil # Mn       TAMIL VOWEL SIGN II\n0BC1..0BC2    ; Tamil # Mc   [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU\n0BC6..0BC8    ; Tamil # Mc   [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI\n0BCA..0BCC    ; Tamil # Mc   [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU\n0BCD          ; Tamil # Mn       TAMIL SIGN VIRAMA\n0BD0          ; Tamil # Lo       TAMIL OM\n0BD7          ; Tamil # Mc       TAMIL AU LENGTH MARK\n0BE6..0BEF    ; Tamil # Nd  [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE\n0BF0..0BF2    ; Tamil # No   [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND\n0BF3..0BF8    ; Tamil # So   [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN\n0BF9          ; Tamil # Sc       TAMIL RUPEE SIGN\n0BFA          ; Tamil # So       TAMIL NUMBER SIGN\n11FC0..11FD4  ; Tamil # No  [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH\n11FD5..11FDC  ; Tamil # So   [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI\n11FDD..11FE0  ; Tamil # Sc   [4] TAMIL SIGN KAACU..TAMIL SIGN VARAAKAN\n11FE1..11FF1  ; Tamil # So  [17] TAMIL SIGN PAARAM..TAMIL SIGN VAKAIYARAA\n11FFF         ; Tamil # Po       TAMIL PUNCTUATION END OF TEXT\n\n# Total code points: 123\n\n# ================================================\n\n0C00          ; Telugu # Mn       TELUGU SIGN COMBINING CANDRABINDU ABOVE\n0C01..0C03    ; Telugu # Mc   [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA\n0C04          ; Telugu # Mn       TELUGU SIGN COMBINING ANUSVARA ABOVE\n0C05..0C0C    ; Telugu # Lo   [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L\n0C0E..0C10    ; Telugu # Lo   [3] TELUGU LETTER E..TELUGU LETTER AI\n0C12..0C28    ; Telugu # Lo  [23] TELUGU LETTER O..TELUGU LETTER NA\n0C2A..0C39    ; Telugu # Lo  [16] TELUGU LETTER PA..TELUGU LETTER HA\n0C3C          ; Telugu # Mn       TELUGU SIGN NUKTA\n0C3D          ; Telugu # Lo       TELUGU SIGN AVAGRAHA\n0C3E..0C40    ; Telugu # Mn   [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II\n0C41..0C44    ; Telugu # Mc   [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR\n0C46..0C48    ; Telugu # Mn   [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI\n0C4A..0C4D    ; Telugu # Mn   [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA\n0C55..0C56    ; Telugu # Mn   [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK\n0C58..0C5A    ; Telugu # Lo   [3] TELUGU LETTER TSA..TELUGU LETTER RRRA\n0C5C..0C5D    ; Telugu # Lo   [2] TELUGU ARCHAIC SHRII..TELUGU LETTER NAKAARA POLLU\n0C60..0C61    ; Telugu # Lo   [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL\n0C62..0C63    ; Telugu # Mn   [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL\n0C66..0C6F    ; Telugu # Nd  [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE\n0C77          ; Telugu # Po       TELUGU SIGN SIDDHAM\n0C78..0C7E    ; Telugu # No   [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR\n0C7F          ; Telugu # So       TELUGU SIGN TUUMU\n\n# Total code points: 101\n\n# ================================================\n\n0C80          ; Kannada # Lo       KANNADA SIGN SPACING CANDRABINDU\n0C81          ; Kannada # Mn       KANNADA SIGN CANDRABINDU\n0C82..0C83    ; Kannada # Mc   [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA\n0C84          ; Kannada # Po       KANNADA SIGN SIDDHAM\n0C85..0C8C    ; Kannada # Lo   [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L\n0C8E..0C90    ; Kannada # Lo   [3] KANNADA LETTER E..KANNADA LETTER AI\n0C92..0CA8    ; Kannada # Lo  [23] KANNADA LETTER O..KANNADA LETTER NA\n0CAA..0CB3    ; Kannada # Lo  [10] KANNADA LETTER PA..KANNADA LETTER LLA\n0CB5..0CB9    ; Kannada # Lo   [5] KANNADA LETTER VA..KANNADA LETTER HA\n0CBC          ; Kannada # Mn       KANNADA SIGN NUKTA\n0CBD          ; Kannada # Lo       KANNADA SIGN AVAGRAHA\n0CBE          ; Kannada # Mc       KANNADA VOWEL SIGN AA\n0CBF          ; Kannada # Mn       KANNADA VOWEL SIGN I\n0CC0..0CC4    ; Kannada # Mc   [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR\n0CC6          ; Kannada # Mn       KANNADA VOWEL SIGN E\n0CC7..0CC8    ; Kannada # Mc   [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI\n0CCA..0CCB    ; Kannada # Mc   [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO\n0CCC..0CCD    ; Kannada # Mn   [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA\n0CD5..0CD6    ; Kannada # Mc   [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK\n0CDC..0CDE    ; Kannada # Lo   [3] KANNADA ARCHAIC SHRII..KANNADA LETTER FA\n0CE0..0CE1    ; Kannada # Lo   [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL\n0CE2..0CE3    ; Kannada # Mn   [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL\n0CE6..0CEF    ; Kannada # Nd  [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE\n0CF1..0CF2    ; Kannada # Lo   [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA\n0CF3          ; Kannada # Mc       KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT\n\n# Total code points: 92\n\n# ================================================\n\n0D00..0D01    ; Malayalam # Mn   [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU\n0D02..0D03    ; Malayalam # Mc   [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA\n0D04..0D0C    ; Malayalam # Lo   [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L\n0D0E..0D10    ; Malayalam # Lo   [3] MALAYALAM LETTER E..MALAYALAM LETTER AI\n0D12..0D3A    ; Malayalam # Lo  [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA\n0D3B..0D3C    ; Malayalam # Mn   [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA\n0D3D          ; Malayalam # Lo       MALAYALAM SIGN AVAGRAHA\n0D3E..0D40    ; Malayalam # Mc   [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II\n0D41..0D44    ; Malayalam # Mn   [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR\n0D46..0D48    ; Malayalam # Mc   [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI\n0D4A..0D4C    ; Malayalam # Mc   [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU\n0D4D          ; Malayalam # Mn       MALAYALAM SIGN VIRAMA\n0D4E          ; Malayalam # Lo       MALAYALAM LETTER DOT REPH\n0D4F          ; Malayalam # So       MALAYALAM SIGN PARA\n0D54..0D56    ; Malayalam # Lo   [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL\n0D57          ; Malayalam # Mc       MALAYALAM AU LENGTH MARK\n0D58..0D5E    ; Malayalam # No   [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH\n0D5F..0D61    ; Malayalam # Lo   [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL\n0D62..0D63    ; Malayalam # Mn   [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL\n0D66..0D6F    ; Malayalam # Nd  [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE\n0D70..0D78    ; Malayalam # No   [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS\n0D79          ; Malayalam # So       MALAYALAM DATE MARK\n0D7A..0D7F    ; Malayalam # Lo   [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K\n\n# Total code points: 118\n\n# ================================================\n\n0D81          ; Sinhala # Mn       SINHALA SIGN CANDRABINDU\n0D82..0D83    ; Sinhala # Mc   [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA\n0D85..0D96    ; Sinhala # Lo  [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA\n0D9A..0DB1    ; Sinhala # Lo  [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA\n0DB3..0DBB    ; Sinhala # Lo   [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA\n0DBD          ; Sinhala # Lo       SINHALA LETTER DANTAJA LAYANNA\n0DC0..0DC6    ; Sinhala # Lo   [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA\n0DCA          ; Sinhala # Mn       SINHALA SIGN AL-LAKUNA\n0DCF..0DD1    ; Sinhala # Mc   [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA\n0DD2..0DD4    ; Sinhala # Mn   [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA\n0DD6          ; Sinhala # Mn       SINHALA VOWEL SIGN DIGA PAA-PILLA\n0DD8..0DDF    ; Sinhala # Mc   [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA\n0DE6..0DEF    ; Sinhala # Nd  [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE\n0DF2..0DF3    ; Sinhala # Mc   [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA\n0DF4          ; Sinhala # Po       SINHALA PUNCTUATION KUNDDALIYA\n111E1..111F4  ; Sinhala # No  [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND\n\n# Total code points: 111\n\n# ================================================\n\n0E01..0E30    ; Thai # Lo  [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A\n0E31          ; Thai # Mn       THAI CHARACTER MAI HAN-AKAT\n0E32..0E33    ; Thai # Lo   [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM\n0E34..0E3A    ; Thai # Mn   [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU\n0E40..0E45    ; Thai # Lo   [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO\n0E46          ; Thai # Lm       THAI CHARACTER MAIYAMOK\n0E47..0E4E    ; Thai # Mn   [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN\n0E4F          ; Thai # Po       THAI CHARACTER FONGMAN\n0E50..0E59    ; Thai # Nd  [10] THAI DIGIT ZERO..THAI DIGIT NINE\n0E5A..0E5B    ; Thai # Po   [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT\n\n# Total code points: 86\n\n# ================================================\n\n0E81..0E82    ; Lao # Lo   [2] LAO LETTER KO..LAO LETTER KHO SUNG\n0E84          ; Lao # Lo       LAO LETTER KHO TAM\n0E86..0E8A    ; Lao # Lo   [5] LAO LETTER PALI GHA..LAO LETTER SO TAM\n0E8C..0EA3    ; Lao # Lo  [24] LAO LETTER PALI JHA..LAO LETTER LO LING\n0EA5          ; Lao # Lo       LAO LETTER LO LOOT\n0EA7..0EB0    ; Lao # Lo  [10] LAO LETTER WO..LAO VOWEL SIGN A\n0EB1          ; Lao # Mn       LAO VOWEL SIGN MAI KAN\n0EB2..0EB3    ; Lao # Lo   [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM\n0EB4..0EBC    ; Lao # Mn   [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO\n0EBD          ; Lao # Lo       LAO SEMIVOWEL SIGN NYO\n0EC0..0EC4    ; Lao # Lo   [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI\n0EC6          ; Lao # Lm       LAO KO LA\n0EC8..0ECE    ; Lao # Mn   [7] LAO TONE MAI EK..LAO YAMAKKAN\n0ED0..0ED9    ; Lao # Nd  [10] LAO DIGIT ZERO..LAO DIGIT NINE\n0EDC..0EDF    ; Lao # Lo   [4] LAO HO NO..LAO LETTER KHMU NYO\n\n# Total code points: 83\n\n# ================================================\n\n0F00          ; Tibetan # Lo       TIBETAN SYLLABLE OM\n0F01..0F03    ; Tibetan # So   [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA\n0F04..0F12    ; Tibetan # Po  [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD\n0F13          ; Tibetan # So       TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN\n0F14          ; Tibetan # Po       TIBETAN MARK GTER TSHEG\n0F15..0F17    ; Tibetan # So   [3] TIBETAN LOGOTYPE SIGN CHAD RTAGS..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS\n0F18..0F19    ; Tibetan # Mn   [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS\n0F1A..0F1F    ; Tibetan # So   [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG\n0F20..0F29    ; Tibetan # Nd  [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE\n0F2A..0F33    ; Tibetan # No  [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO\n0F34          ; Tibetan # So       TIBETAN MARK BSDUS RTAGS\n0F35          ; Tibetan # Mn       TIBETAN MARK NGAS BZUNG NYI ZLA\n0F36          ; Tibetan # So       TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN\n0F37          ; Tibetan # Mn       TIBETAN MARK NGAS BZUNG SGOR RTAGS\n0F38          ; Tibetan # So       TIBETAN MARK CHE MGO\n0F39          ; Tibetan # Mn       TIBETAN MARK TSA -PHRU\n0F3A          ; Tibetan # Ps       TIBETAN MARK GUG RTAGS GYON\n0F3B          ; Tibetan # Pe       TIBETAN MARK GUG RTAGS GYAS\n0F3C          ; Tibetan # Ps       TIBETAN MARK ANG KHANG GYON\n0F3D          ; Tibetan # Pe       TIBETAN MARK ANG KHANG GYAS\n0F3E..0F3F    ; Tibetan # Mc   [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES\n0F40..0F47    ; Tibetan # Lo   [8] TIBETAN LETTER KA..TIBETAN LETTER JA\n0F49..0F6C    ; Tibetan # Lo  [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA\n0F71..0F7E    ; Tibetan # Mn  [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO\n0F7F          ; Tibetan # Mc       TIBETAN SIGN RNAM BCAD\n0F80..0F84    ; Tibetan # Mn   [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA\n0F85          ; Tibetan # Po       TIBETAN MARK PALUTA\n0F86..0F87    ; Tibetan # Mn   [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS\n0F88..0F8C    ; Tibetan # Lo   [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN\n0F8D..0F97    ; Tibetan # Mn  [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA\n0F99..0FBC    ; Tibetan # Mn  [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA\n0FBE..0FC5    ; Tibetan # So   [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE\n0FC6          ; Tibetan # Mn       TIBETAN SYMBOL PADMA GDAN\n0FC7..0FCC    ; Tibetan # So   [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL\n0FCE..0FCF    ; Tibetan # So   [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM\n0FD0..0FD4    ; Tibetan # Po   [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA\n0FD9..0FDA    ; Tibetan # Po   [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS\n\n# Total code points: 207\n\n# ================================================\n\n1000..102A    ; Myanmar # Lo  [43] MYANMAR LETTER KA..MYANMAR LETTER AU\n102B..102C    ; Myanmar # Mc   [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA\n102D..1030    ; Myanmar # Mn   [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU\n1031          ; Myanmar # Mc       MYANMAR VOWEL SIGN E\n1032..1037    ; Myanmar # Mn   [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW\n1038          ; Myanmar # Mc       MYANMAR SIGN VISARGA\n1039..103A    ; Myanmar # Mn   [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT\n103B..103C    ; Myanmar # Mc   [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA\n103D..103E    ; Myanmar # Mn   [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA\n103F          ; Myanmar # Lo       MYANMAR LETTER GREAT SA\n1040..1049    ; Myanmar # Nd  [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE\n104A..104F    ; Myanmar # Po   [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE\n1050..1055    ; Myanmar # Lo   [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL\n1056..1057    ; Myanmar # Mc   [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR\n1058..1059    ; Myanmar # Mn   [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL\n105A..105D    ; Myanmar # Lo   [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE\n105E..1060    ; Myanmar # Mn   [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA\n1061          ; Myanmar # Lo       MYANMAR LETTER SGAW KAREN SHA\n1062..1064    ; Myanmar # Mc   [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO\n1065..1066    ; Myanmar # Lo   [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA\n1067..106D    ; Myanmar # Mc   [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5\n106E..1070    ; Myanmar # Lo   [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA\n1071..1074    ; Myanmar # Mn   [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE\n1075..1081    ; Myanmar # Lo  [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA\n1082          ; Myanmar # Mn       MYANMAR CONSONANT SIGN SHAN MEDIAL WA\n1083..1084    ; Myanmar # Mc   [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E\n1085..1086    ; Myanmar # Mn   [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y\n1087..108C    ; Myanmar # Mc   [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3\n108D          ; Myanmar # Mn       MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE\n108E          ; Myanmar # Lo       MYANMAR LETTER RUMAI PALAUNG FA\n108F          ; Myanmar # Mc       MYANMAR SIGN RUMAI PALAUNG TONE-5\n1090..1099    ; Myanmar # Nd  [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE\n109A..109C    ; Myanmar # Mc   [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A\n109D          ; Myanmar # Mn       MYANMAR VOWEL SIGN AITON AI\n109E..109F    ; Myanmar # So   [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION\nA9E0..A9E4    ; Myanmar # Lo   [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA\nA9E5          ; Myanmar # Mn       MYANMAR SIGN SHAN SAW\nA9E6          ; Myanmar # Lm       MYANMAR MODIFIER LETTER SHAN REDUPLICATION\nA9E7..A9EF    ; Myanmar # Lo   [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA\nA9F0..A9F9    ; Myanmar # Nd  [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE\nA9FA..A9FE    ; Myanmar # Lo   [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA\nAA60..AA6F    ; Myanmar # Lo  [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA\nAA70          ; Myanmar # Lm       MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION\nAA71..AA76    ; Myanmar # Lo   [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM\nAA77..AA79    ; Myanmar # So   [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO\nAA7A          ; Myanmar # Lo       MYANMAR LETTER AITON RA\nAA7B          ; Myanmar # Mc       MYANMAR SIGN PAO KAREN TONE\nAA7C          ; Myanmar # Mn       MYANMAR SIGN TAI LAING TONE-2\nAA7D          ; Myanmar # Mc       MYANMAR SIGN TAI LAING TONE-5\nAA7E..AA7F    ; Myanmar # Lo   [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA\n116D0..116E3  ; Myanmar # Nd  [20] MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE\n\n# Total code points: 243\n\n# ================================================\n\n10A0..10C5    ; Georgian # L&  [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE\n10C7          ; Georgian # L&       GEORGIAN CAPITAL LETTER YN\n10CD          ; Georgian # L&       GEORGIAN CAPITAL LETTER AEN\n10D0..10FA    ; Georgian # L&  [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN\n10FC          ; Georgian # Lm       MODIFIER LETTER GEORGIAN NAR\n10FD..10FF    ; Georgian # L&   [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN\n1C90..1CBA    ; Georgian # L&  [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN\n1CBD..1CBF    ; Georgian # L&   [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN\n2D00..2D25    ; Georgian # L&  [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE\n2D27          ; Georgian # L&       GEORGIAN SMALL LETTER YN\n2D2D          ; Georgian # L&       GEORGIAN SMALL LETTER AEN\n\n# Total code points: 173\n\n# ================================================\n\n1100..11FF    ; Hangul # Lo [256] HANGUL CHOSEONG KIYEOK..HANGUL JONGSEONG SSANGNIEUN\n302E..302F    ; Hangul # Mc   [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK\n3131..318E    ; Hangul # Lo  [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE\n3200..321E    ; Hangul # So  [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU\n3260..327E    ; Hangul # So  [31] CIRCLED HANGUL KIYEOK..CIRCLED HANGUL IEUNG U\nA960..A97C    ; Hangul # Lo  [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH\nAC00..D7A3    ; Hangul # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH\nD7B0..D7C6    ; Hangul # Lo  [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E\nD7CB..D7FB    ; Hangul # Lo  [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH\nFFA0..FFBE    ; Hangul # Lo  [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH\nFFC2..FFC7    ; Hangul # Lo   [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E\nFFCA..FFCF    ; Hangul # Lo   [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE\nFFD2..FFD7    ; Hangul # Lo   [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU\nFFDA..FFDC    ; Hangul # Lo   [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I\n\n# Total code points: 11739\n\n# ================================================\n\n1200..1248    ; Ethiopic # Lo  [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA\n124A..124D    ; Ethiopic # Lo   [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE\n1250..1256    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO\n1258          ; Ethiopic # Lo       ETHIOPIC SYLLABLE QHWA\n125A..125D    ; Ethiopic # Lo   [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE\n1260..1288    ; Ethiopic # Lo  [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA\n128A..128D    ; Ethiopic # Lo   [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE\n1290..12B0    ; Ethiopic # Lo  [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA\n12B2..12B5    ; Ethiopic # Lo   [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE\n12B8..12BE    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO\n12C0          ; Ethiopic # Lo       ETHIOPIC SYLLABLE KXWA\n12C2..12C5    ; Ethiopic # Lo   [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE\n12C8..12D6    ; Ethiopic # Lo  [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O\n12D8..1310    ; Ethiopic # Lo  [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA\n1312..1315    ; Ethiopic # Lo   [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE\n1318..135A    ; Ethiopic # Lo  [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA\n135D..135F    ; Ethiopic # Mn   [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK\n1360..1368    ; Ethiopic # Po   [9] ETHIOPIC SECTION MARK..ETHIOPIC PARAGRAPH SEPARATOR\n1369..137C    ; Ethiopic # No  [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND\n1380..138F    ; Ethiopic # Lo  [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE\n1390..1399    ; Ethiopic # So  [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT\n2D80..2D96    ; Ethiopic # Lo  [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE\n2DA0..2DA6    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO\n2DA8..2DAE    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO\n2DB0..2DB6    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO\n2DB8..2DBE    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO\n2DC0..2DC6    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO\n2DC8..2DCE    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO\n2DD0..2DD6    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO\n2DD8..2DDE    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO\nAB01..AB06    ; Ethiopic # Lo   [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO\nAB09..AB0E    ; Ethiopic # Lo   [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO\nAB11..AB16    ; Ethiopic # Lo   [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO\nAB20..AB26    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO\nAB28..AB2E    ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO\n1E7E0..1E7E6  ; Ethiopic # Lo   [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO\n1E7E8..1E7EB  ; Ethiopic # Lo   [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE\n1E7ED..1E7EE  ; Ethiopic # Lo   [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE\n1E7F0..1E7FE  ; Ethiopic # Lo  [15] ETHIOPIC SYLLABLE GURAGE QWI..ETHIOPIC SYLLABLE GURAGE PWEE\n\n# Total code points: 523\n\n# ================================================\n\n13A0..13F5    ; Cherokee # L&  [86] CHEROKEE LETTER A..CHEROKEE LETTER MV\n13F8..13FD    ; Cherokee # L&   [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV\nAB70..ABBF    ; Cherokee # L&  [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA\n\n# Total code points: 172\n\n# ================================================\n\n1400          ; Canadian_Aboriginal # Pd       CANADIAN SYLLABICS HYPHEN\n1401..166C    ; Canadian_Aboriginal # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA\n166D          ; Canadian_Aboriginal # So       CANADIAN SYLLABICS CHI SIGN\n166E          ; Canadian_Aboriginal # Po       CANADIAN SYLLABICS FULL STOP\n166F..167F    ; Canadian_Aboriginal # Lo  [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W\n18B0..18F5    ; Canadian_Aboriginal # Lo  [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S\n11AB0..11ABF  ; Canadian_Aboriginal # Lo  [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA\n\n# Total code points: 726\n\n# ================================================\n\n1680          ; Ogham # Zs       OGHAM SPACE MARK\n1681..169A    ; Ogham # Lo  [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH\n169B          ; Ogham # Ps       OGHAM FEATHER MARK\n169C          ; Ogham # Pe       OGHAM REVERSED FEATHER MARK\n\n# Total code points: 29\n\n# ================================================\n\n16A0..16EA    ; Runic # Lo  [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X\n16EE..16F0    ; Runic # Nl   [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL\n16F1..16F8    ; Runic # Lo   [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC\n\n# Total code points: 86\n\n# ================================================\n\n1780..17B3    ; Khmer # Lo  [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU\n17B4..17B5    ; Khmer # Mn   [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA\n17B6          ; Khmer # Mc       KHMER VOWEL SIGN AA\n17B7..17BD    ; Khmer # Mn   [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA\n17BE..17C5    ; Khmer # Mc   [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU\n17C6          ; Khmer # Mn       KHMER SIGN NIKAHIT\n17C7..17C8    ; Khmer # Mc   [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU\n17C9..17D3    ; Khmer # Mn  [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT\n17D4..17D6    ; Khmer # Po   [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH\n17D7          ; Khmer # Lm       KHMER SIGN LEK TOO\n17D8..17DA    ; Khmer # Po   [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT\n17DB          ; Khmer # Sc       KHMER CURRENCY SYMBOL RIEL\n17DC          ; Khmer # Lo       KHMER SIGN AVAKRAHASANYA\n17DD          ; Khmer # Mn       KHMER SIGN ATTHACAN\n17E0..17E9    ; Khmer # Nd  [10] KHMER DIGIT ZERO..KHMER DIGIT NINE\n17F0..17F9    ; Khmer # No  [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON\n19E0..19FF    ; Khmer # So  [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC\n\n# Total code points: 146\n\n# ================================================\n\n1800..1801    ; Mongolian # Po   [2] MONGOLIAN BIRGA..MONGOLIAN ELLIPSIS\n1804          ; Mongolian # Po       MONGOLIAN COLON\n1806          ; Mongolian # Pd       MONGOLIAN TODO SOFT HYPHEN\n1807..180A    ; Mongolian # Po   [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU\n180B..180D    ; Mongolian # Mn   [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE\n180E          ; Mongolian # Cf       MONGOLIAN VOWEL SEPARATOR\n180F          ; Mongolian # Mn       MONGOLIAN FREE VARIATION SELECTOR FOUR\n1810..1819    ; Mongolian # Nd  [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE\n1820..1842    ; Mongolian # Lo  [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI\n1843          ; Mongolian # Lm       MONGOLIAN LETTER TODO LONG VOWEL SIGN\n1844..1878    ; Mongolian # Lo  [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS\n1880..1884    ; Mongolian # Lo   [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA\n1885..1886    ; Mongolian # Mn   [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA\n1887..18A8    ; Mongolian # Lo  [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA\n18A9          ; Mongolian # Mn       MONGOLIAN LETTER ALI GALI DAGALGA\n18AA          ; Mongolian # Lo       MONGOLIAN LETTER MANCHU ALI GALI LHA\n11660..1166C  ; Mongolian # Po  [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT\n\n# Total code points: 168\n\n# ================================================\n\n3041..3096    ; Hiragana # Lo  [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE\n309D..309E    ; Hiragana # Lm   [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK\n309F          ; Hiragana # Lo       HIRAGANA DIGRAPH YORI\n1B001..1B11F  ; Hiragana # Lo [287] HIRAGANA LETTER ARCHAIC YE..HIRAGANA LETTER ARCHAIC WU\n1B132         ; Hiragana # Lo       HIRAGANA LETTER SMALL KO\n1B150..1B152  ; Hiragana # Lo   [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO\n1F200         ; Hiragana # So       SQUARE HIRAGANA HOKA\n\n# Total code points: 381\n\n# ================================================\n\n30A1..30FA    ; Katakana # Lo  [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO\n30FD..30FE    ; Katakana # Lm   [2] KATAKANA ITERATION MARK..KATAKANA VOICED ITERATION MARK\n30FF          ; Katakana # Lo       KATAKANA DIGRAPH KOTO\n31F0..31FF    ; Katakana # Lo  [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO\n32D0..32FE    ; Katakana # So  [47] CIRCLED KATAKANA A..CIRCLED KATAKANA WO\n3300..3357    ; Katakana # So  [88] SQUARE APAATO..SQUARE WATTO\nFF66..FF6F    ; Katakana # Lo  [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU\nFF71..FF9D    ; Katakana # Lo  [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N\n1AFF0..1AFF3  ; Katakana # Lm   [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5\n1AFF5..1AFFB  ; Katakana # Lm   [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5\n1AFFD..1AFFE  ; Katakana # Lm   [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8\n1B000         ; Katakana # Lo       KATAKANA LETTER ARCHAIC E\n1B120..1B122  ; Katakana # Lo   [3] KATAKANA LETTER ARCHAIC YI..KATAKANA LETTER ARCHAIC WU\n1B155         ; Katakana # Lo       KATAKANA LETTER SMALL KO\n1B164..1B167  ; Katakana # Lo   [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N\n\n# Total code points: 321\n\n# ================================================\n\n02EA..02EB    ; Bopomofo # Sk   [2] MODIFIER LETTER YIN DEPARTING TONE MARK..MODIFIER LETTER YANG DEPARTING TONE MARK\n3105..312F    ; Bopomofo # Lo  [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN\n31A0..31BF    ; Bopomofo # Lo  [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH\n\n# Total code points: 77\n\n# ================================================\n\n2E80..2E99    ; Han # So  [26] CJK RADICAL REPEAT..CJK RADICAL RAP\n2E9B..2EF3    ; Han # So  [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE\n2F00..2FD5    ; Han # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE\n3005          ; Han # Lm       IDEOGRAPHIC ITERATION MARK\n3007          ; Han # Nl       IDEOGRAPHIC NUMBER ZERO\n3021..3029    ; Han # Nl   [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE\n3038..303A    ; Han # Nl   [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY\n303B          ; Han # Lm       VERTICAL IDEOGRAPHIC ITERATION MARK\n3400..4DBF    ; Han # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF\n4E00..9FFF    ; Han # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF\nF900..FA6D    ; Han # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D\nFA70..FAD9    ; Han # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9\n16FE2         ; Han # Po       OLD CHINESE HOOK MARK\n16FE3         ; Han # Lm       OLD CHINESE ITERATION MARK\n16FF0..16FF1  ; Han # Mc   [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY\n16FF2..16FF3  ; Han # Lm   [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER\n16FF4..16FF6  ; Han # Nl   [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS\n20000..2A6DF  ; Han # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF\n2A700..2B81D  ; Han # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D\n2B820..2CEAD  ; Han # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD\n2CEB0..2EBE0  ; Han # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0\n2EBF0..2EE5D  ; Han # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D\n2F800..2FA1D  ; Han # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D\n30000..3134A  ; Han # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A\n31350..33479  ; Han # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479\n\n# Total code points: 103351\n\n# ================================================\n\nA000..A014    ; Yi # Lo  [21] YI SYLLABLE IT..YI SYLLABLE E\nA015          ; Yi # Lm       YI SYLLABLE WU\nA016..A48C    ; Yi # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR\nA490..A4C6    ; Yi # So  [55] YI RADICAL QOT..YI RADICAL KE\n\n# Total code points: 1220\n\n# ================================================\n\n10300..1031F  ; Old_Italic # Lo  [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS\n10320..10323  ; Old_Italic # No   [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY\n1032D..1032F  ; Old_Italic # Lo   [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE\n\n# Total code points: 39\n\n# ================================================\n\n10330..10340  ; Gothic # Lo  [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA\n10341         ; Gothic # Nl       GOTHIC LETTER NINETY\n10342..10349  ; Gothic # Lo   [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL\n1034A         ; Gothic # Nl       GOTHIC LETTER NINE HUNDRED\n\n# Total code points: 27\n\n# ================================================\n\n10400..1044F  ; Deseret # L&  [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW\n\n# Total code points: 80\n\n# ================================================\n\n0300..036F    ; Inherited # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X\n0485..0486    ; Inherited # Mn   [2] COMBINING CYRILLIC DASIA PNEUMATA..COMBINING CYRILLIC PSILI PNEUMATA\n064B..0655    ; Inherited # Mn  [11] ARABIC FATHATAN..ARABIC HAMZA BELOW\n0670          ; Inherited # Mn       ARABIC LETTER SUPERSCRIPT ALEF\n0951..0954    ; Inherited # Mn   [4] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT\n1AB0..1ABD    ; Inherited # Mn  [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW\n1ABE          ; Inherited # Me       COMBINING PARENTHESES OVERLAY\n1ABF..1ADD    ; Inherited # Mn  [31] COMBINING LATIN SMALL LETTER W BELOW..COMBINING DOT-AND-RING BELOW\n1AE0..1AEB    ; Inherited # Mn  [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE\n1CD0..1CD2    ; Inherited # Mn   [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA\n1CD4..1CE0    ; Inherited # Mn  [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA\n1CE2..1CE8    ; Inherited # Mn   [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL\n1CED          ; Inherited # Mn       VEDIC SIGN TIRYAK\n1CF4          ; Inherited # Mn       VEDIC TONE CANDRA ABOVE\n1CF8..1CF9    ; Inherited # Mn   [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE\n1DC0..1DFF    ; Inherited # Mn  [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW\n200C..200D    ; Inherited # Cf   [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER\n20D0..20DC    ; Inherited # Mn  [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE\n20DD..20E0    ; Inherited # Me   [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH\n20E1          ; Inherited # Mn       COMBINING LEFT RIGHT ARROW ABOVE\n20E2..20E4    ; Inherited # Me   [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE\n20E5..20F0    ; Inherited # Mn  [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE\n302A..302D    ; Inherited # Mn   [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK\n3099..309A    ; Inherited # Mn   [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\nFE00..FE0F    ; Inherited # Mn  [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16\nFE20..FE2D    ; Inherited # Mn  [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW\n101FD         ; Inherited # Mn       PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE\n102E0         ; Inherited # Mn       COPTIC EPACT THOUSANDS MARK\n1133B         ; Inherited # Mn       COMBINING BINDU BELOW\n1CF00..1CF2D  ; Inherited # Mn  [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT\n1CF30..1CF46  ; Inherited # Mn  [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG\n1D167..1D169  ; Inherited # Mn   [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3\n1D17B..1D182  ; Inherited # Mn   [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE\n1D185..1D18B  ; Inherited # Mn   [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE\n1D1AA..1D1AD  ; Inherited # Mn   [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO\nE0100..E01EF  ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256\n\n# Total code points: 684\n\n# ================================================\n\n1700..1711    ; Tagalog # Lo  [18] TAGALOG LETTER A..TAGALOG LETTER HA\n1712..1714    ; Tagalog # Mn   [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA\n1715          ; Tagalog # Mc       TAGALOG SIGN PAMUDPOD\n171F          ; Tagalog # Lo       TAGALOG LETTER ARCHAIC RA\n\n# Total code points: 23\n\n# ================================================\n\n1720..1731    ; Hanunoo # Lo  [18] HANUNOO LETTER A..HANUNOO LETTER HA\n1732..1733    ; Hanunoo # Mn   [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U\n1734          ; Hanunoo # Mc       HANUNOO SIGN PAMUDPOD\n\n# Total code points: 21\n\n# ================================================\n\n1740..1751    ; Buhid # Lo  [18] BUHID LETTER A..BUHID LETTER HA\n1752..1753    ; Buhid # Mn   [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U\n\n# Total code points: 20\n\n# ================================================\n\n1760..176C    ; Tagbanwa # Lo  [13] TAGBANWA LETTER A..TAGBANWA LETTER YA\n176E..1770    ; Tagbanwa # Lo   [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA\n1772..1773    ; Tagbanwa # Mn   [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U\n\n# Total code points: 18\n\n# ================================================\n\n1900..191E    ; Limbu # Lo  [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA\n1920..1922    ; Limbu # Mn   [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U\n1923..1926    ; Limbu # Mc   [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU\n1927..1928    ; Limbu # Mn   [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O\n1929..192B    ; Limbu # Mc   [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA\n1930..1931    ; Limbu # Mc   [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA\n1932          ; Limbu # Mn       LIMBU SMALL LETTER ANUSVARA\n1933..1938    ; Limbu # Mc   [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA\n1939..193B    ; Limbu # Mn   [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I\n1940          ; Limbu # So       LIMBU SIGN LOO\n1944..1945    ; Limbu # Po   [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK\n1946..194F    ; Limbu # Nd  [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE\n\n# Total code points: 68\n\n# ================================================\n\n1950..196D    ; Tai_Le # Lo  [30] TAI LE LETTER KA..TAI LE LETTER AI\n1970..1974    ; Tai_Le # Lo   [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6\n\n# Total code points: 35\n\n# ================================================\n\n10000..1000B  ; Linear_B # Lo  [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE\n1000D..10026  ; Linear_B # Lo  [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO\n10028..1003A  ; Linear_B # Lo  [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO\n1003C..1003D  ; Linear_B # Lo   [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE\n1003F..1004D  ; Linear_B # Lo  [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO\n10050..1005D  ; Linear_B # Lo  [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089\n10080..100FA  ; Linear_B # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305\n\n# Total code points: 211\n\n# ================================================\n\n10380..1039D  ; Ugaritic # Lo  [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU\n1039F         ; Ugaritic # Po       UGARITIC WORD DIVIDER\n\n# Total code points: 31\n\n# ================================================\n\n10450..1047F  ; Shavian # Lo  [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW\n\n# Total code points: 48\n\n# ================================================\n\n10480..1049D  ; Osmanya # Lo  [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO\n104A0..104A9  ; Osmanya # Nd  [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE\n\n# Total code points: 40\n\n# ================================================\n\n10800..10805  ; Cypriot # Lo   [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA\n10808         ; Cypriot # Lo       CYPRIOT SYLLABLE JO\n1080A..10835  ; Cypriot # Lo  [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO\n10837..10838  ; Cypriot # Lo   [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE\n1083C         ; Cypriot # Lo       CYPRIOT SYLLABLE ZA\n1083F         ; Cypriot # Lo       CYPRIOT SYLLABLE ZO\n\n# Total code points: 55\n\n# ================================================\n\n2800..28FF    ; Braille # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678\n\n# Total code points: 256\n\n# ================================================\n\n1A00..1A16    ; Buginese # Lo  [23] BUGINESE LETTER KA..BUGINESE LETTER HA\n1A17..1A18    ; Buginese # Mn   [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U\n1A19..1A1A    ; Buginese # Mc   [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O\n1A1B          ; Buginese # Mn       BUGINESE VOWEL SIGN AE\n1A1E..1A1F    ; Buginese # Po   [2] BUGINESE PALLAWA..BUGINESE END OF SECTION\n\n# Total code points: 30\n\n# ================================================\n\n03E2..03EF    ; Coptic # L&  [14] COPTIC CAPITAL LETTER SHEI..COPTIC SMALL LETTER DEI\n2C80..2CE4    ; Coptic # L& [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI\n2CE5..2CEA    ; Coptic # So   [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA\n2CEB..2CEE    ; Coptic # L&   [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA\n2CEF..2CF1    ; Coptic # Mn   [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS\n2CF2..2CF3    ; Coptic # L&   [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI\n2CF9..2CFC    ; Coptic # Po   [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER\n2CFD          ; Coptic # No       COPTIC FRACTION ONE HALF\n2CFE..2CFF    ; Coptic # Po   [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER\n\n# Total code points: 137\n\n# ================================================\n\n1980..19AB    ; New_Tai_Lue # Lo  [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA\n19B0..19C9    ; New_Tai_Lue # Lo  [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2\n19D0..19D9    ; New_Tai_Lue # Nd  [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE\n19DA          ; New_Tai_Lue # No       NEW TAI LUE THAM DIGIT ONE\n19DE..19DF    ; New_Tai_Lue # So   [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV\n\n# Total code points: 83\n\n# ================================================\n\n2C00..2C5F    ; Glagolitic # L&  [96] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC SMALL LETTER CAUDATE CHRIVI\n1E000..1E006  ; Glagolitic # Mn   [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE\n1E008..1E018  ; Glagolitic # Mn  [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU\n1E01B..1E021  ; Glagolitic # Mn   [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI\n1E023..1E024  ; Glagolitic # Mn   [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS\n1E026..1E02A  ; Glagolitic # Mn   [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA\n\n# Total code points: 134\n\n# ================================================\n\n2D30..2D67    ; Tifinagh # Lo  [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO\n2D6F          ; Tifinagh # Lm       TIFINAGH MODIFIER LETTER LABIALIZATION MARK\n2D70          ; Tifinagh # Po       TIFINAGH SEPARATOR MARK\n2D7F          ; Tifinagh # Mn       TIFINAGH CONSONANT JOINER\n\n# Total code points: 59\n\n# ================================================\n\nA800..A801    ; Syloti_Nagri # Lo   [2] SYLOTI NAGRI LETTER A..SYLOTI NAGRI LETTER I\nA802          ; Syloti_Nagri # Mn       SYLOTI NAGRI SIGN DVISVARA\nA803..A805    ; Syloti_Nagri # Lo   [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O\nA806          ; Syloti_Nagri # Mn       SYLOTI NAGRI SIGN HASANTA\nA807..A80A    ; Syloti_Nagri # Lo   [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO\nA80B          ; Syloti_Nagri # Mn       SYLOTI NAGRI SIGN ANUSVARA\nA80C..A822    ; Syloti_Nagri # Lo  [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO\nA823..A824    ; Syloti_Nagri # Mc   [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I\nA825..A826    ; Syloti_Nagri # Mn   [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E\nA827          ; Syloti_Nagri # Mc       SYLOTI NAGRI VOWEL SIGN OO\nA828..A82B    ; Syloti_Nagri # So   [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4\nA82C          ; Syloti_Nagri # Mn       SYLOTI NAGRI SIGN ALTERNATE HASANTA\n\n# Total code points: 45\n\n# ================================================\n\n103A0..103C3  ; Old_Persian # Lo  [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA\n103C8..103CF  ; Old_Persian # Lo   [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH\n103D0         ; Old_Persian # Po       OLD PERSIAN WORD DIVIDER\n103D1..103D5  ; Old_Persian # Nl   [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED\n\n# Total code points: 50\n\n# ================================================\n\n10A00         ; Kharoshthi # Lo       KHAROSHTHI LETTER A\n10A01..10A03  ; Kharoshthi # Mn   [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R\n10A05..10A06  ; Kharoshthi # Mn   [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O\n10A0C..10A0F  ; Kharoshthi # Mn   [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA\n10A10..10A13  ; Kharoshthi # Lo   [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA\n10A15..10A17  ; Kharoshthi # Lo   [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA\n10A19..10A35  ; Kharoshthi # Lo  [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA\n10A38..10A3A  ; Kharoshthi # Mn   [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW\n10A3F         ; Kharoshthi # Mn       KHAROSHTHI VIRAMA\n10A40..10A48  ; Kharoshthi # No   [9] KHAROSHTHI DIGIT ONE..KHAROSHTHI FRACTION ONE HALF\n10A50..10A58  ; Kharoshthi # Po   [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES\n\n# Total code points: 68\n\n# ================================================\n\n1B00..1B03    ; Balinese # Mn   [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG\n1B04          ; Balinese # Mc       BALINESE SIGN BISAH\n1B05..1B33    ; Balinese # Lo  [47] BALINESE LETTER AKARA..BALINESE LETTER HA\n1B34          ; Balinese # Mn       BALINESE SIGN REREKAN\n1B35          ; Balinese # Mc       BALINESE VOWEL SIGN TEDUNG\n1B36..1B3A    ; Balinese # Mn   [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA\n1B3B          ; Balinese # Mc       BALINESE VOWEL SIGN RA REPA TEDUNG\n1B3C          ; Balinese # Mn       BALINESE VOWEL SIGN LA LENGA\n1B3D..1B41    ; Balinese # Mc   [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG\n1B42          ; Balinese # Mn       BALINESE VOWEL SIGN PEPET\n1B43..1B44    ; Balinese # Mc   [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG\n1B45..1B4C    ; Balinese # Lo   [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA\n1B4E..1B4F    ; Balinese # Po   [2] BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN\n1B50..1B59    ; Balinese # Nd  [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE\n1B5A..1B60    ; Balinese # Po   [7] BALINESE PANTI..BALINESE PAMENENG\n1B61..1B6A    ; Balinese # So  [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE\n1B6B..1B73    ; Balinese # Mn   [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG\n1B74..1B7C    ; Balinese # So   [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING\n1B7D..1B7F    ; Balinese # Po   [3] BALINESE PANTI LANTANG..BALINESE PANTI BAWAK\n\n# Total code points: 127\n\n# ================================================\n\n12000..12399  ; Cuneiform # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U\n12400..1246E  ; Cuneiform # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM\n12470..12474  ; Cuneiform # Po   [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON\n12480..12543  ; Cuneiform # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU\n\n# Total code points: 1234\n\n# ================================================\n\n10900..10915  ; Phoenician # Lo  [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU\n10916..1091B  ; Phoenician # No   [6] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER THREE\n1091F         ; Phoenician # Po       PHOENICIAN WORD SEPARATOR\n\n# Total code points: 29\n\n# ================================================\n\nA840..A873    ; Phags_Pa # Lo  [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU\nA874..A877    ; Phags_Pa # Po   [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD\n\n# Total code points: 56\n\n# ================================================\n\n07C0..07C9    ; Nko # Nd  [10] NKO DIGIT ZERO..NKO DIGIT NINE\n07CA..07EA    ; Nko # Lo  [33] NKO LETTER A..NKO LETTER JONA RA\n07EB..07F3    ; Nko # Mn   [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE\n07F4..07F5    ; Nko # Lm   [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE\n07F6          ; Nko # So       NKO SYMBOL OO DENNEN\n07F7..07F9    ; Nko # Po   [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK\n07FA          ; Nko # Lm       NKO LAJANYALAN\n07FD          ; Nko # Mn       NKO DANTAYALAN\n07FE..07FF    ; Nko # Sc   [2] NKO DOROME SIGN..NKO TAMAN SIGN\n\n# Total code points: 62\n\n# ================================================\n\n1B80..1B81    ; Sundanese # Mn   [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR\n1B82          ; Sundanese # Mc       SUNDANESE SIGN PANGWISAD\n1B83..1BA0    ; Sundanese # Lo  [30] SUNDANESE LETTER A..SUNDANESE LETTER HA\n1BA1          ; Sundanese # Mc       SUNDANESE CONSONANT SIGN PAMINGKAL\n1BA2..1BA5    ; Sundanese # Mn   [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU\n1BA6..1BA7    ; Sundanese # Mc   [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG\n1BA8..1BA9    ; Sundanese # Mn   [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG\n1BAA          ; Sundanese # Mc       SUNDANESE SIGN PAMAAEH\n1BAB..1BAD    ; Sundanese # Mn   [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA\n1BAE..1BAF    ; Sundanese # Lo   [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA\n1BB0..1BB9    ; Sundanese # Nd  [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE\n1BBA..1BBF    ; Sundanese # Lo   [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M\n1CC0..1CC7    ; Sundanese # Po   [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA\n\n# Total code points: 72\n\n# ================================================\n\n1C00..1C23    ; Lepcha # Lo  [36] LEPCHA LETTER KA..LEPCHA LETTER A\n1C24..1C2B    ; Lepcha # Mc   [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU\n1C2C..1C33    ; Lepcha # Mn   [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T\n1C34..1C35    ; Lepcha # Mc   [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG\n1C36..1C37    ; Lepcha # Mn   [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA\n1C3B..1C3F    ; Lepcha # Po   [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK\n1C40..1C49    ; Lepcha # Nd  [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE\n1C4D..1C4F    ; Lepcha # Lo   [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA\n\n# Total code points: 74\n\n# ================================================\n\n1C50..1C59    ; Ol_Chiki # Nd  [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE\n1C5A..1C77    ; Ol_Chiki # Lo  [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH\n1C78..1C7D    ; Ol_Chiki # Lm   [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD\n1C7E..1C7F    ; Ol_Chiki # Po   [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD\n\n# Total code points: 48\n\n# ================================================\n\nA500..A60B    ; Vai # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG\nA60C          ; Vai # Lm       VAI SYLLABLE LENGTHENER\nA60D..A60F    ; Vai # Po   [3] VAI COMMA..VAI QUESTION MARK\nA610..A61F    ; Vai # Lo  [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG\nA620..A629    ; Vai # Nd  [10] VAI DIGIT ZERO..VAI DIGIT NINE\nA62A..A62B    ; Vai # Lo   [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO\n\n# Total code points: 300\n\n# ================================================\n\nA880..A881    ; Saurashtra # Mc   [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA\nA882..A8B3    ; Saurashtra # Lo  [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA\nA8B4..A8C3    ; Saurashtra # Mc  [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU\nA8C4..A8C5    ; Saurashtra # Mn   [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU\nA8CE..A8CF    ; Saurashtra # Po   [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA\nA8D0..A8D9    ; Saurashtra # Nd  [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE\n\n# Total code points: 82\n\n# ================================================\n\nA900..A909    ; Kayah_Li # Nd  [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE\nA90A..A925    ; Kayah_Li # Lo  [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO\nA926..A92D    ; Kayah_Li # Mn   [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU\nA92F          ; Kayah_Li # Po       KAYAH LI SIGN SHYA\n\n# Total code points: 47\n\n# ================================================\n\nA930..A946    ; Rejang # Lo  [23] REJANG LETTER KA..REJANG LETTER A\nA947..A951    ; Rejang # Mn  [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R\nA952..A953    ; Rejang # Mc   [2] REJANG CONSONANT SIGN H..REJANG VIRAMA\nA95F          ; Rejang # Po       REJANG SECTION MARK\n\n# Total code points: 37\n\n# ================================================\n\n10280..1029C  ; Lycian # Lo  [29] LYCIAN LETTER A..LYCIAN LETTER X\n\n# Total code points: 29\n\n# ================================================\n\n102A0..102D0  ; Carian # Lo  [49] CARIAN LETTER A..CARIAN LETTER UUU3\n\n# Total code points: 49\n\n# ================================================\n\n10920..10939  ; Lydian # Lo  [26] LYDIAN LETTER A..LYDIAN LETTER C\n1093F         ; Lydian # Po       LYDIAN TRIANGULAR MARK\n\n# Total code points: 27\n\n# ================================================\n\nAA00..AA28    ; Cham # Lo  [41] CHAM LETTER A..CHAM LETTER HA\nAA29..AA2E    ; Cham # Mn   [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE\nAA2F..AA30    ; Cham # Mc   [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI\nAA31..AA32    ; Cham # Mn   [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE\nAA33..AA34    ; Cham # Mc   [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA\nAA35..AA36    ; Cham # Mn   [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA\nAA40..AA42    ; Cham # Lo   [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG\nAA43          ; Cham # Mn       CHAM CONSONANT SIGN FINAL NG\nAA44..AA4B    ; Cham # Lo   [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS\nAA4C          ; Cham # Mn       CHAM CONSONANT SIGN FINAL M\nAA4D          ; Cham # Mc       CHAM CONSONANT SIGN FINAL H\nAA50..AA59    ; Cham # Nd  [10] CHAM DIGIT ZERO..CHAM DIGIT NINE\nAA5C..AA5F    ; Cham # Po   [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA\n\n# Total code points: 83\n\n# ================================================\n\n1A20..1A54    ; Tai_Tham # Lo  [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA\n1A55          ; Tai_Tham # Mc       TAI THAM CONSONANT SIGN MEDIAL RA\n1A56          ; Tai_Tham # Mn       TAI THAM CONSONANT SIGN MEDIAL LA\n1A57          ; Tai_Tham # Mc       TAI THAM CONSONANT SIGN LA TANG LAI\n1A58..1A5E    ; Tai_Tham # Mn   [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA\n1A60          ; Tai_Tham # Mn       TAI THAM SIGN SAKOT\n1A61          ; Tai_Tham # Mc       TAI THAM VOWEL SIGN A\n1A62          ; Tai_Tham # Mn       TAI THAM VOWEL SIGN MAI SAT\n1A63..1A64    ; Tai_Tham # Mc   [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA\n1A65..1A6C    ; Tai_Tham # Mn   [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW\n1A6D..1A72    ; Tai_Tham # Mc   [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI\n1A73..1A7C    ; Tai_Tham # Mn  [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN\n1A7F          ; Tai_Tham # Mn       TAI THAM COMBINING CRYPTOGRAMMIC DOT\n1A80..1A89    ; Tai_Tham # Nd  [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE\n1A90..1A99    ; Tai_Tham # Nd  [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE\n1AA0..1AA6    ; Tai_Tham # Po   [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA\n1AA7          ; Tai_Tham # Lm       TAI THAM SIGN MAI YAMOK\n1AA8..1AAD    ; Tai_Tham # Po   [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG\n\n# Total code points: 127\n\n# ================================================\n\nAA80..AAAF    ; Tai_Viet # Lo  [48] TAI VIET LETTER LOW KO..TAI VIET LETTER HIGH O\nAAB0          ; Tai_Viet # Mn       TAI VIET MAI KANG\nAAB1          ; Tai_Viet # Lo       TAI VIET VOWEL AA\nAAB2..AAB4    ; Tai_Viet # Mn   [3] TAI VIET VOWEL I..TAI VIET VOWEL U\nAAB5..AAB6    ; Tai_Viet # Lo   [2] TAI VIET VOWEL E..TAI VIET VOWEL O\nAAB7..AAB8    ; Tai_Viet # Mn   [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA\nAAB9..AABD    ; Tai_Viet # Lo   [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN\nAABE..AABF    ; Tai_Viet # Mn   [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK\nAAC0          ; Tai_Viet # Lo       TAI VIET TONE MAI NUENG\nAAC1          ; Tai_Viet # Mn       TAI VIET TONE MAI THO\nAAC2          ; Tai_Viet # Lo       TAI VIET TONE MAI SONG\nAADB..AADC    ; Tai_Viet # Lo   [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG\nAADD          ; Tai_Viet # Lm       TAI VIET SYMBOL SAM\nAADE..AADF    ; Tai_Viet # Po   [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI\n\n# Total code points: 72\n\n# ================================================\n\n10B00..10B35  ; Avestan # Lo  [54] AVESTAN LETTER A..AVESTAN LETTER HE\n10B39..10B3F  ; Avestan # Po   [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION\n\n# Total code points: 61\n\n# ================================================\n\n13000..1342F  ; Egyptian_Hieroglyphs # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D\n13430..1343F  ; Egyptian_Hieroglyphs # Cf  [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE\n13440         ; Egyptian_Hieroglyphs # Mn       EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY\n13441..13446  ; Egyptian_Hieroglyphs # Lo   [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN\n13447..13455  ; Egyptian_Hieroglyphs # Mn  [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED\n13460..143FA  ; Egyptian_Hieroglyphs # Lo [3995] EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA\n\n# Total code points: 5105\n\n# ================================================\n\n0800..0815    ; Samaritan # Lo  [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF\n0816..0819    ; Samaritan # Mn   [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH\n081A          ; Samaritan # Lm       SAMARITAN MODIFIER LETTER EPENTHETIC YUT\n081B..0823    ; Samaritan # Mn   [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A\n0824          ; Samaritan # Lm       SAMARITAN MODIFIER LETTER SHORT A\n0825..0827    ; Samaritan # Mn   [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U\n0828          ; Samaritan # Lm       SAMARITAN MODIFIER LETTER I\n0829..082D    ; Samaritan # Mn   [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA\n0830..083E    ; Samaritan # Po  [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU\n\n# Total code points: 61\n\n# ================================================\n\nA4D0..A4F7    ; Lisu # Lo  [40] LISU LETTER BA..LISU LETTER OE\nA4F8..A4FD    ; Lisu # Lm   [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU\nA4FE..A4FF    ; Lisu # Po   [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP\n11FB0         ; Lisu # Lo       LISU LETTER YHA\n\n# Total code points: 49\n\n# ================================================\n\nA6A0..A6E5    ; Bamum # Lo  [70] BAMUM LETTER A..BAMUM LETTER KI\nA6E6..A6EF    ; Bamum # Nl  [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM\nA6F0..A6F1    ; Bamum # Mn   [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS\nA6F2..A6F7    ; Bamum # Po   [6] BAMUM NJAEMLI..BAMUM QUESTION MARK\n16800..16A38  ; Bamum # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ\n\n# Total code points: 657\n\n# ================================================\n\nA980..A982    ; Javanese # Mn   [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR\nA983          ; Javanese # Mc       JAVANESE SIGN WIGNYAN\nA984..A9B2    ; Javanese # Lo  [47] JAVANESE LETTER A..JAVANESE LETTER HA\nA9B3          ; Javanese # Mn       JAVANESE SIGN CECAK TELU\nA9B4..A9B5    ; Javanese # Mc   [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG\nA9B6..A9B9    ; Javanese # Mn   [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT\nA9BA..A9BB    ; Javanese # Mc   [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE\nA9BC..A9BD    ; Javanese # Mn   [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET\nA9BE..A9C0    ; Javanese # Mc   [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON\nA9C1..A9CD    ; Javanese # Po  [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH\nA9D0..A9D9    ; Javanese # Nd  [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE\nA9DE..A9DF    ; Javanese # Po   [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN\n\n# Total code points: 90\n\n# ================================================\n\nAAE0..AAEA    ; Meetei_Mayek # Lo  [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA\nAAEB          ; Meetei_Mayek # Mc       MEETEI MAYEK VOWEL SIGN II\nAAEC..AAED    ; Meetei_Mayek # Mn   [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI\nAAEE..AAEF    ; Meetei_Mayek # Mc   [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU\nAAF0..AAF1    ; Meetei_Mayek # Po   [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM\nAAF2          ; Meetei_Mayek # Lo       MEETEI MAYEK ANJI\nAAF3..AAF4    ; Meetei_Mayek # Lm   [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK\nAAF5          ; Meetei_Mayek # Mc       MEETEI MAYEK VOWEL SIGN VISARGA\nAAF6          ; Meetei_Mayek # Mn       MEETEI MAYEK VIRAMA\nABC0..ABE2    ; Meetei_Mayek # Lo  [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM\nABE3..ABE4    ; Meetei_Mayek # Mc   [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP\nABE5          ; Meetei_Mayek # Mn       MEETEI MAYEK VOWEL SIGN ANAP\nABE6..ABE7    ; Meetei_Mayek # Mc   [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP\nABE8          ; Meetei_Mayek # Mn       MEETEI MAYEK VOWEL SIGN UNAP\nABE9..ABEA    ; Meetei_Mayek # Mc   [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG\nABEB          ; Meetei_Mayek # Po       MEETEI MAYEK CHEIKHEI\nABEC          ; Meetei_Mayek # Mc       MEETEI MAYEK LUM IYEK\nABED          ; Meetei_Mayek # Mn       MEETEI MAYEK APUN IYEK\nABF0..ABF9    ; Meetei_Mayek # Nd  [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE\n\n# Total code points: 79\n\n# ================================================\n\n10840..10855  ; Imperial_Aramaic # Lo  [22] IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW\n10857         ; Imperial_Aramaic # Po       IMPERIAL ARAMAIC SECTION SIGN\n10858..1085F  ; Imperial_Aramaic # No   [8] IMPERIAL ARAMAIC NUMBER ONE..IMPERIAL ARAMAIC NUMBER TEN THOUSAND\n\n# Total code points: 31\n\n# ================================================\n\n10A60..10A7C  ; Old_South_Arabian # Lo  [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH\n10A7D..10A7E  ; Old_South_Arabian # No   [2] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMBER FIFTY\n10A7F         ; Old_South_Arabian # Po       OLD SOUTH ARABIAN NUMERIC INDICATOR\n\n# Total code points: 32\n\n# ================================================\n\n10B40..10B55  ; Inscriptional_Parthian # Lo  [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW\n10B58..10B5F  ; Inscriptional_Parthian # No   [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND\n\n# Total code points: 30\n\n# ================================================\n\n10B60..10B72  ; Inscriptional_Pahlavi # Lo  [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW\n10B78..10B7F  ; Inscriptional_Pahlavi # No   [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND\n\n# Total code points: 27\n\n# ================================================\n\n10C00..10C48  ; Old_Turkic # Lo  [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH\n\n# Total code points: 73\n\n# ================================================\n\n11080..11081  ; Kaithi # Mn   [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA\n11082         ; Kaithi # Mc       KAITHI SIGN VISARGA\n11083..110AF  ; Kaithi # Lo  [45] KAITHI LETTER A..KAITHI LETTER HA\n110B0..110B2  ; Kaithi # Mc   [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II\n110B3..110B6  ; Kaithi # Mn   [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI\n110B7..110B8  ; Kaithi # Mc   [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU\n110B9..110BA  ; Kaithi # Mn   [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA\n110BB..110BC  ; Kaithi # Po   [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN\n110BD         ; Kaithi # Cf       KAITHI NUMBER SIGN\n110BE..110C1  ; Kaithi # Po   [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA\n110C2         ; Kaithi # Mn       KAITHI VOWEL SIGN VOCALIC R\n110CD         ; Kaithi # Cf       KAITHI NUMBER SIGN ABOVE\n\n# Total code points: 68\n\n# ================================================\n\n1BC0..1BE5    ; Batak # Lo  [38] BATAK LETTER A..BATAK LETTER U\n1BE6          ; Batak # Mn       BATAK SIGN TOMPI\n1BE7          ; Batak # Mc       BATAK VOWEL SIGN E\n1BE8..1BE9    ; Batak # Mn   [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE\n1BEA..1BEC    ; Batak # Mc   [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O\n1BED          ; Batak # Mn       BATAK VOWEL SIGN KARO O\n1BEE          ; Batak # Mc       BATAK VOWEL SIGN U\n1BEF..1BF1    ; Batak # Mn   [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H\n1BF2..1BF3    ; Batak # Mc   [2] BATAK PANGOLAT..BATAK PANONGONAN\n1BFC..1BFF    ; Batak # Po   [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT\n\n# Total code points: 56\n\n# ================================================\n\n11000         ; Brahmi # Mc       BRAHMI SIGN CANDRABINDU\n11001         ; Brahmi # Mn       BRAHMI SIGN ANUSVARA\n11002         ; Brahmi # Mc       BRAHMI SIGN VISARGA\n11003..11037  ; Brahmi # Lo  [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA\n11038..11046  ; Brahmi # Mn  [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA\n11047..1104D  ; Brahmi # Po   [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS\n11052..11065  ; Brahmi # No  [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND\n11066..1106F  ; Brahmi # Nd  [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE\n11070         ; Brahmi # Mn       BRAHMI SIGN OLD TAMIL VIRAMA\n11071..11072  ; Brahmi # Lo   [2] BRAHMI LETTER OLD TAMIL SHORT E..BRAHMI LETTER OLD TAMIL SHORT O\n11073..11074  ; Brahmi # Mn   [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O\n11075         ; Brahmi # Lo       BRAHMI LETTER OLD TAMIL LLA\n1107F         ; Brahmi # Mn       BRAHMI NUMBER JOINER\n\n# Total code points: 115\n\n# ================================================\n\n0840..0858    ; Mandaic # Lo  [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN\n0859..085B    ; Mandaic # Mn   [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK\n085E          ; Mandaic # Po       MANDAIC PUNCTUATION\n\n# Total code points: 29\n\n# ================================================\n\n11100..11102  ; Chakma # Mn   [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA\n11103..11126  ; Chakma # Lo  [36] CHAKMA LETTER AA..CHAKMA LETTER HAA\n11127..1112B  ; Chakma # Mn   [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU\n1112C         ; Chakma # Mc       CHAKMA VOWEL SIGN E\n1112D..11134  ; Chakma # Mn   [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA\n11136..1113F  ; Chakma # Nd  [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE\n11140..11143  ; Chakma # Po   [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK\n11144         ; Chakma # Lo       CHAKMA LETTER LHAA\n11145..11146  ; Chakma # Mc   [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI\n11147         ; Chakma # Lo       CHAKMA LETTER VAA\n\n# Total code points: 71\n\n# ================================================\n\n109A0..109B7  ; Meroitic_Cursive # Lo  [24] MEROITIC CURSIVE LETTER A..MEROITIC CURSIVE LETTER DA\n109BC..109BD  ; Meroitic_Cursive # No   [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF\n109BE..109BF  ; Meroitic_Cursive # Lo   [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN\n109C0..109CF  ; Meroitic_Cursive # No  [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY\n109D2..109FF  ; Meroitic_Cursive # No  [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS\n\n# Total code points: 90\n\n# ================================================\n\n10980..1099F  ; Meroitic_Hieroglyphs # Lo  [32] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2\n\n# Total code points: 32\n\n# ================================================\n\n16F00..16F4A  ; Miao # Lo  [75] MIAO LETTER PA..MIAO LETTER RTE\n16F4F         ; Miao # Mn       MIAO SIGN CONSONANT MODIFIER BAR\n16F50         ; Miao # Lo       MIAO LETTER NASALIZATION\n16F51..16F87  ; Miao # Mc  [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI\n16F8F..16F92  ; Miao # Mn   [4] MIAO TONE RIGHT..MIAO TONE BELOW\n16F93..16F9F  ; Miao # Lm  [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8\n\n# Total code points: 149\n\n# ================================================\n\n11180..11181  ; Sharada # Mn   [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA\n11182         ; Sharada # Mc       SHARADA SIGN VISARGA\n11183..111B2  ; Sharada # Lo  [48] SHARADA LETTER A..SHARADA LETTER HA\n111B3..111B5  ; Sharada # Mc   [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II\n111B6..111BE  ; Sharada # Mn   [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O\n111BF..111C0  ; Sharada # Mc   [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA\n111C1..111C4  ; Sharada # Lo   [4] SHARADA SIGN AVAGRAHA..SHARADA OM\n111C5..111C8  ; Sharada # Po   [4] SHARADA DANDA..SHARADA SEPARATOR\n111C9..111CC  ; Sharada # Mn   [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK\n111CD         ; Sharada # Po       SHARADA SUTRA MARK\n111CE         ; Sharada # Mc       SHARADA VOWEL SIGN PRISHTHAMATRA E\n111CF         ; Sharada # Mn       SHARADA SIGN INVERTED CANDRABINDU\n111D0..111D9  ; Sharada # Nd  [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE\n111DA         ; Sharada # Lo       SHARADA EKAM\n111DB         ; Sharada # Po       SHARADA SIGN SIDDHAM\n111DC         ; Sharada # Lo       SHARADA HEADSTROKE\n111DD..111DF  ; Sharada # Po   [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2\n11B60         ; Sharada # Mn       SHARADA VOWEL SIGN OE\n11B61         ; Sharada # Mc       SHARADA VOWEL SIGN OOE\n11B62..11B64  ; Sharada # Mn   [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E\n11B65         ; Sharada # Mc       SHARADA VOWEL SIGN SHORT O\n11B66         ; Sharada # Mn       SHARADA VOWEL SIGN CANDRA E\n11B67         ; Sharada # Mc       SHARADA VOWEL SIGN CANDRA O\n\n# Total code points: 104\n\n# ================================================\n\n110D0..110E8  ; Sora_Sompeng # Lo  [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE\n110F0..110F9  ; Sora_Sompeng # Nd  [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE\n\n# Total code points: 35\n\n# ================================================\n\n11680..116AA  ; Takri # Lo  [43] TAKRI LETTER A..TAKRI LETTER RRA\n116AB         ; Takri # Mn       TAKRI SIGN ANUSVARA\n116AC         ; Takri # Mc       TAKRI SIGN VISARGA\n116AD         ; Takri # Mn       TAKRI VOWEL SIGN AA\n116AE..116AF  ; Takri # Mc   [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II\n116B0..116B5  ; Takri # Mn   [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU\n116B6         ; Takri # Mc       TAKRI SIGN VIRAMA\n116B7         ; Takri # Mn       TAKRI SIGN NUKTA\n116B8         ; Takri # Lo       TAKRI LETTER ARCHAIC KHA\n116B9         ; Takri # Po       TAKRI ABBREVIATION SIGN\n116C0..116C9  ; Takri # Nd  [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE\n\n# Total code points: 68\n\n# ================================================\n\n10530..10563  ; Caucasian_Albanian # Lo  [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW\n1056F         ; Caucasian_Albanian # Po       CAUCASIAN ALBANIAN CITATION MARK\n\n# Total code points: 53\n\n# ================================================\n\n16AD0..16AED  ; Bassa_Vah # Lo  [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I\n16AF0..16AF4  ; Bassa_Vah # Mn   [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE\n16AF5         ; Bassa_Vah # Po       BASSA VAH FULL STOP\n\n# Total code points: 36\n\n# ================================================\n\n1BC00..1BC6A  ; Duployan # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M\n1BC70..1BC7C  ; Duployan # Lo  [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK\n1BC80..1BC88  ; Duployan # Lo   [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL\n1BC90..1BC99  ; Duployan # Lo  [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW\n1BC9C         ; Duployan # So       DUPLOYAN SIGN O WITH CROSS\n1BC9D..1BC9E  ; Duployan # Mn   [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK\n1BC9F         ; Duployan # Po       DUPLOYAN PUNCTUATION CHINOOK FULL STOP\n\n# Total code points: 143\n\n# ================================================\n\n10500..10527  ; Elbasan # Lo  [40] ELBASAN LETTER A..ELBASAN LETTER KHE\n\n# Total code points: 40\n\n# ================================================\n\n11300..11301  ; Grantha # Mn   [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU\n11302..11303  ; Grantha # Mc   [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA\n11305..1130C  ; Grantha # Lo   [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L\n1130F..11310  ; Grantha # Lo   [2] GRANTHA LETTER EE..GRANTHA LETTER AI\n11313..11328  ; Grantha # Lo  [22] GRANTHA LETTER OO..GRANTHA LETTER NA\n1132A..11330  ; Grantha # Lo   [7] GRANTHA LETTER PA..GRANTHA LETTER RA\n11332..11333  ; Grantha # Lo   [2] GRANTHA LETTER LA..GRANTHA LETTER LLA\n11335..11339  ; Grantha # Lo   [5] GRANTHA LETTER VA..GRANTHA LETTER HA\n1133C         ; Grantha # Mn       GRANTHA SIGN NUKTA\n1133D         ; Grantha # Lo       GRANTHA SIGN AVAGRAHA\n1133E..1133F  ; Grantha # Mc   [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I\n11340         ; Grantha # Mn       GRANTHA VOWEL SIGN II\n11341..11344  ; Grantha # Mc   [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR\n11347..11348  ; Grantha # Mc   [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI\n1134B..1134D  ; Grantha # Mc   [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA\n11350         ; Grantha # Lo       GRANTHA OM\n11357         ; Grantha # Mc       GRANTHA AU LENGTH MARK\n1135D..11361  ; Grantha # Lo   [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL\n11362..11363  ; Grantha # Mc   [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL\n11366..1136C  ; Grantha # Mn   [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX\n11370..11374  ; Grantha # Mn   [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA\n\n# Total code points: 85\n\n# ================================================\n\n16B00..16B2F  ; Pahawh_Hmong # Lo  [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU\n16B30..16B36  ; Pahawh_Hmong # Mn   [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM\n16B37..16B3B  ; Pahawh_Hmong # Po   [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM\n16B3C..16B3F  ; Pahawh_Hmong # So   [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB\n16B40..16B43  ; Pahawh_Hmong # Lm   [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM\n16B44         ; Pahawh_Hmong # Po       PAHAWH HMONG SIGN XAUS\n16B45         ; Pahawh_Hmong # So       PAHAWH HMONG SIGN CIM TSOV ROG\n16B50..16B59  ; Pahawh_Hmong # Nd  [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE\n16B5B..16B61  ; Pahawh_Hmong # No   [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS\n16B63..16B77  ; Pahawh_Hmong # Lo  [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS\n16B7D..16B8F  ; Pahawh_Hmong # Lo  [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ\n\n# Total code points: 127\n\n# ================================================\n\n11200..11211  ; Khojki # Lo  [18] KHOJKI LETTER A..KHOJKI LETTER JJA\n11213..1122B  ; Khojki # Lo  [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA\n1122C..1122E  ; Khojki # Mc   [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II\n1122F..11231  ; Khojki # Mn   [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI\n11232..11233  ; Khojki # Mc   [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU\n11234         ; Khojki # Mn       KHOJKI SIGN ANUSVARA\n11235         ; Khojki # Mc       KHOJKI SIGN VIRAMA\n11236..11237  ; Khojki # Mn   [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA\n11238..1123D  ; Khojki # Po   [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN\n1123E         ; Khojki # Mn       KHOJKI SIGN SUKUN\n1123F..11240  ; Khojki # Lo   [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I\n11241         ; Khojki # Mn       KHOJKI VOWEL SIGN VOCALIC R\n\n# Total code points: 65\n\n# ================================================\n\n10600..10736  ; Linear_A # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664\n10740..10755  ; Linear_A # Lo  [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE\n10760..10767  ; Linear_A # Lo   [8] LINEAR A SIGN A800..LINEAR A SIGN A807\n\n# Total code points: 341\n\n# ================================================\n\n11150..11172  ; Mahajani # Lo  [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA\n11173         ; Mahajani # Mn       MAHAJANI SIGN NUKTA\n11174..11175  ; Mahajani # Po   [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK\n11176         ; Mahajani # Lo       MAHAJANI LIGATURE SHRI\n\n# Total code points: 39\n\n# ================================================\n\n10AC0..10AC7  ; Manichaean # Lo   [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW\n10AC8         ; Manichaean # So       MANICHAEAN SIGN UD\n10AC9..10AE4  ; Manichaean # Lo  [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW\n10AE5..10AE6  ; Manichaean # Mn   [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW\n10AEB..10AEF  ; Manichaean # No   [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED\n10AF0..10AF6  ; Manichaean # Po   [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER\n\n# Total code points: 51\n\n# ================================================\n\n1E800..1E8C4  ; Mende_Kikakui # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON\n1E8C7..1E8CF  ; Mende_Kikakui # No   [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE\n1E8D0..1E8D6  ; Mende_Kikakui # Mn   [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS\n\n# Total code points: 213\n\n# ================================================\n\n11600..1162F  ; Modi # Lo  [48] MODI LETTER A..MODI LETTER LLA\n11630..11632  ; Modi # Mc   [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II\n11633..1163A  ; Modi # Mn   [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI\n1163B..1163C  ; Modi # Mc   [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU\n1163D         ; Modi # Mn       MODI SIGN ANUSVARA\n1163E         ; Modi # Mc       MODI SIGN VISARGA\n1163F..11640  ; Modi # Mn   [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA\n11641..11643  ; Modi # Po   [3] MODI DANDA..MODI ABBREVIATION SIGN\n11644         ; Modi # Lo       MODI SIGN HUVA\n11650..11659  ; Modi # Nd  [10] MODI DIGIT ZERO..MODI DIGIT NINE\n\n# Total code points: 79\n\n# ================================================\n\n16A40..16A5E  ; Mro # Lo  [31] MRO LETTER TA..MRO LETTER TEK\n16A60..16A69  ; Mro # Nd  [10] MRO DIGIT ZERO..MRO DIGIT NINE\n16A6E..16A6F  ; Mro # Po   [2] MRO DANDA..MRO DOUBLE DANDA\n\n# Total code points: 43\n\n# ================================================\n\n10A80..10A9C  ; Old_North_Arabian # Lo  [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH\n10A9D..10A9F  ; Old_North_Arabian # No   [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY\n\n# Total code points: 32\n\n# ================================================\n\n10880..1089E  ; Nabataean # Lo  [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW\n108A7..108AF  ; Nabataean # No   [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED\n\n# Total code points: 40\n\n# ================================================\n\n10860..10876  ; Palmyrene # Lo  [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW\n10877..10878  ; Palmyrene # So   [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON\n10879..1087F  ; Palmyrene # No   [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY\n\n# Total code points: 32\n\n# ================================================\n\n11AC0..11AF8  ; Pau_Cin_Hau # Lo  [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL\n\n# Total code points: 57\n\n# ================================================\n\n10350..10375  ; Old_Permic # Lo  [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA\n10376..1037A  ; Old_Permic # Mn   [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII\n\n# Total code points: 43\n\n# ================================================\n\n10B80..10B91  ; Psalter_Pahlavi # Lo  [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW\n10B99..10B9C  ; Psalter_Pahlavi # Po   [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT\n10BA9..10BAF  ; Psalter_Pahlavi # No   [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED\n\n# Total code points: 29\n\n# ================================================\n\n11580..115AE  ; Siddham # Lo  [47] SIDDHAM LETTER A..SIDDHAM LETTER HA\n115AF..115B1  ; Siddham # Mc   [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II\n115B2..115B5  ; Siddham # Mn   [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR\n115B8..115BB  ; Siddham # Mc   [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU\n115BC..115BD  ; Siddham # Mn   [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA\n115BE         ; Siddham # Mc       SIDDHAM SIGN VISARGA\n115BF..115C0  ; Siddham # Mn   [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA\n115C1..115D7  ; Siddham # Po  [23] SIDDHAM SIGN SIDDHAM..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES\n115D8..115DB  ; Siddham # Lo   [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U\n115DC..115DD  ; Siddham # Mn   [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU\n\n# Total code points: 92\n\n# ================================================\n\n112B0..112DE  ; Khudawadi # Lo  [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA\n112DF         ; Khudawadi # Mn       KHUDAWADI SIGN ANUSVARA\n112E0..112E2  ; Khudawadi # Mc   [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II\n112E3..112EA  ; Khudawadi # Mn   [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA\n112F0..112F9  ; Khudawadi # Nd  [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE\n\n# Total code points: 69\n\n# ================================================\n\n11480..114AF  ; Tirhuta # Lo  [48] TIRHUTA ANJI..TIRHUTA LETTER HA\n114B0..114B2  ; Tirhuta # Mc   [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II\n114B3..114B8  ; Tirhuta # Mn   [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL\n114B9         ; Tirhuta # Mc       TIRHUTA VOWEL SIGN E\n114BA         ; Tirhuta # Mn       TIRHUTA VOWEL SIGN SHORT E\n114BB..114BE  ; Tirhuta # Mc   [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU\n114BF..114C0  ; Tirhuta # Mn   [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA\n114C1         ; Tirhuta # Mc       TIRHUTA SIGN VISARGA\n114C2..114C3  ; Tirhuta # Mn   [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA\n114C4..114C5  ; Tirhuta # Lo   [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG\n114C6         ; Tirhuta # Po       TIRHUTA ABBREVIATION SIGN\n114C7         ; Tirhuta # Lo       TIRHUTA OM\n114D0..114D9  ; Tirhuta # Nd  [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE\n\n# Total code points: 82\n\n# ================================================\n\n118A0..118DF  ; Warang_Citi # L&  [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO\n118E0..118E9  ; Warang_Citi # Nd  [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE\n118EA..118F2  ; Warang_Citi # No   [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY\n118FF         ; Warang_Citi # Lo       WARANG CITI OM\n\n# Total code points: 84\n\n# ================================================\n\n11700..1171A  ; Ahom # Lo  [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA\n1171D         ; Ahom # Mn       AHOM CONSONANT SIGN MEDIAL LA\n1171E         ; Ahom # Mc       AHOM CONSONANT SIGN MEDIAL RA\n1171F         ; Ahom # Mn       AHOM CONSONANT SIGN MEDIAL LIGATING RA\n11720..11721  ; Ahom # Mc   [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA\n11722..11725  ; Ahom # Mn   [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU\n11726         ; Ahom # Mc       AHOM VOWEL SIGN E\n11727..1172B  ; Ahom # Mn   [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER\n11730..11739  ; Ahom # Nd  [10] AHOM DIGIT ZERO..AHOM DIGIT NINE\n1173A..1173B  ; Ahom # No   [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY\n1173C..1173E  ; Ahom # Po   [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI\n1173F         ; Ahom # So       AHOM SYMBOL VI\n11740..11746  ; Ahom # Lo   [7] AHOM LETTER CA..AHOM LETTER LLA\n\n# Total code points: 65\n\n# ================================================\n\n14400..14646  ; Anatolian_Hieroglyphs # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530\n\n# Total code points: 583\n\n# ================================================\n\n108E0..108F2  ; Hatran # Lo  [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH\n108F4..108F5  ; Hatran # Lo   [2] HATRAN LETTER SHIN..HATRAN LETTER TAW\n108FB..108FF  ; Hatran # No   [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED\n\n# Total code points: 26\n\n# ================================================\n\n11280..11286  ; Multani # Lo   [7] MULTANI LETTER A..MULTANI LETTER GA\n11288         ; Multani # Lo       MULTANI LETTER GHA\n1128A..1128D  ; Multani # Lo   [4] MULTANI LETTER CA..MULTANI LETTER JJA\n1128F..1129D  ; Multani # Lo  [15] MULTANI LETTER NYA..MULTANI LETTER BA\n1129F..112A8  ; Multani # Lo  [10] MULTANI LETTER BHA..MULTANI LETTER RHA\n112A9         ; Multani # Po       MULTANI SECTION MARK\n\n# Total code points: 38\n\n# ================================================\n\n10C80..10CB2  ; Old_Hungarian # L&  [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US\n10CC0..10CF2  ; Old_Hungarian # L&  [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US\n10CFA..10CFF  ; Old_Hungarian # No   [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND\n\n# Total code points: 108\n\n# ================================================\n\n1D800..1D9FF  ; SignWriting # So [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD\n1DA00..1DA36  ; SignWriting # Mn  [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN\n1DA37..1DA3A  ; SignWriting # So   [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE\n1DA3B..1DA6C  ; SignWriting # Mn  [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT\n1DA6D..1DA74  ; SignWriting # So   [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING\n1DA75         ; SignWriting # Mn       SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS\n1DA76..1DA83  ; SignWriting # So  [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH\n1DA84         ; SignWriting # Mn       SIGNWRITING LOCATION HEAD NECK\n1DA85..1DA86  ; SignWriting # So   [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS\n1DA87..1DA8B  ; SignWriting # Po   [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS\n1DA9B..1DA9F  ; SignWriting # Mn   [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6\n1DAA1..1DAAF  ; SignWriting # Mn  [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16\n\n# Total code points: 672\n\n# ================================================\n\n1E900..1E943  ; Adlam # L&  [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA\n1E944..1E94A  ; Adlam # Mn   [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA\n1E94B         ; Adlam # Lm       ADLAM NASALIZATION MARK\n1E950..1E959  ; Adlam # Nd  [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE\n1E95E..1E95F  ; Adlam # Po   [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK\n\n# Total code points: 88\n\n# ================================================\n\n11C00..11C08  ; Bhaiksuki # Lo   [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L\n11C0A..11C2E  ; Bhaiksuki # Lo  [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA\n11C2F         ; Bhaiksuki # Mc       BHAIKSUKI VOWEL SIGN AA\n11C30..11C36  ; Bhaiksuki # Mn   [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L\n11C38..11C3D  ; Bhaiksuki # Mn   [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA\n11C3E         ; Bhaiksuki # Mc       BHAIKSUKI SIGN VISARGA\n11C3F         ; Bhaiksuki # Mn       BHAIKSUKI SIGN VIRAMA\n11C40         ; Bhaiksuki # Lo       BHAIKSUKI SIGN AVAGRAHA\n11C41..11C45  ; Bhaiksuki # Po   [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2\n11C50..11C59  ; Bhaiksuki # Nd  [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE\n11C5A..11C6C  ; Bhaiksuki # No  [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK\n\n# Total code points: 97\n\n# ================================================\n\n11C70..11C71  ; Marchen # Po   [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD\n11C72..11C8F  ; Marchen # Lo  [30] MARCHEN LETTER KA..MARCHEN LETTER A\n11C92..11CA7  ; Marchen # Mn  [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA\n11CA9         ; Marchen # Mc       MARCHEN SUBJOINED LETTER YA\n11CAA..11CB0  ; Marchen # Mn   [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA\n11CB1         ; Marchen # Mc       MARCHEN VOWEL SIGN I\n11CB2..11CB3  ; Marchen # Mn   [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E\n11CB4         ; Marchen # Mc       MARCHEN VOWEL SIGN O\n11CB5..11CB6  ; Marchen # Mn   [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU\n\n# Total code points: 68\n\n# ================================================\n\n11400..11434  ; Newa # Lo  [53] NEWA LETTER A..NEWA LETTER HA\n11435..11437  ; Newa # Mc   [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II\n11438..1143F  ; Newa # Mn   [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI\n11440..11441  ; Newa # Mc   [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU\n11442..11444  ; Newa # Mn   [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA\n11445         ; Newa # Mc       NEWA SIGN VISARGA\n11446         ; Newa # Mn       NEWA SIGN NUKTA\n11447..1144A  ; Newa # Lo   [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI\n1144B..1144F  ; Newa # Po   [5] NEWA DANDA..NEWA ABBREVIATION SIGN\n11450..11459  ; Newa # Nd  [10] NEWA DIGIT ZERO..NEWA DIGIT NINE\n1145A..1145B  ; Newa # Po   [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK\n1145D         ; Newa # Po       NEWA INSERTION SIGN\n1145E         ; Newa # Mn       NEWA SANDHI MARK\n1145F..11461  ; Newa # Lo   [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA\n\n# Total code points: 97\n\n# ================================================\n\n104B0..104D3  ; Osage # L&  [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA\n104D8..104FB  ; Osage # L&  [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA\n\n# Total code points: 72\n\n# ================================================\n\n16FE0         ; Tangut # Lm       TANGUT ITERATION MARK\n17000..18AFF  ; Tangut # Lo [6912] TANGUT IDEOGRAPH-17000..TANGUT COMPONENT-768\n18D00..18D1E  ; Tangut # Lo  [31] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D1E\n18D80..18DF2  ; Tangut # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883\n\n# Total code points: 7059\n\n# ================================================\n\n11D00..11D06  ; Masaram_Gondi # Lo   [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E\n11D08..11D09  ; Masaram_Gondi # Lo   [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O\n11D0B..11D30  ; Masaram_Gondi # Lo  [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA\n11D31..11D36  ; Masaram_Gondi # Mn   [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R\n11D3A         ; Masaram_Gondi # Mn       MASARAM GONDI VOWEL SIGN E\n11D3C..11D3D  ; Masaram_Gondi # Mn   [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O\n11D3F..11D45  ; Masaram_Gondi # Mn   [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA\n11D46         ; Masaram_Gondi # Lo       MASARAM GONDI REPHA\n11D47         ; Masaram_Gondi # Mn       MASARAM GONDI RA-KARA\n11D50..11D59  ; Masaram_Gondi # Nd  [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE\n\n# Total code points: 75\n\n# ================================================\n\n16FE1         ; Nushu # Lm       NUSHU ITERATION MARK\n1B170..1B2FB  ; Nushu # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB\n\n# Total code points: 397\n\n# ================================================\n\n11A50         ; Soyombo # Lo       SOYOMBO LETTER A\n11A51..11A56  ; Soyombo # Mn   [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE\n11A57..11A58  ; Soyombo # Mc   [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU\n11A59..11A5B  ; Soyombo # Mn   [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK\n11A5C..11A89  ; Soyombo # Lo  [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA\n11A8A..11A96  ; Soyombo # Mn  [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA\n11A97         ; Soyombo # Mc       SOYOMBO SIGN VISARGA\n11A98..11A99  ; Soyombo # Mn   [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER\n11A9A..11A9C  ; Soyombo # Po   [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD\n11A9D         ; Soyombo # Lo       SOYOMBO MARK PLUTA\n11A9E..11AA2  ; Soyombo # Po   [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2\n\n# Total code points: 83\n\n# ================================================\n\n11A00         ; Zanabazar_Square # Lo       ZANABAZAR SQUARE LETTER A\n11A01..11A0A  ; Zanabazar_Square # Mn  [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK\n11A0B..11A32  ; Zanabazar_Square # Lo  [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA\n11A33..11A38  ; Zanabazar_Square # Mn   [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA\n11A39         ; Zanabazar_Square # Mc       ZANABAZAR SQUARE SIGN VISARGA\n11A3A         ; Zanabazar_Square # Lo       ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA\n11A3B..11A3E  ; Zanabazar_Square # Mn   [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA\n11A3F..11A46  ; Zanabazar_Square # Po   [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK\n11A47         ; Zanabazar_Square # Mn       ZANABAZAR SQUARE SUBJOINER\n\n# Total code points: 72\n\n# ================================================\n\n11800..1182B  ; Dogra # Lo  [44] DOGRA LETTER A..DOGRA LETTER RRA\n1182C..1182E  ; Dogra # Mc   [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II\n1182F..11837  ; Dogra # Mn   [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA\n11838         ; Dogra # Mc       DOGRA SIGN VISARGA\n11839..1183A  ; Dogra # Mn   [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA\n1183B         ; Dogra # Po       DOGRA ABBREVIATION SIGN\n\n# Total code points: 60\n\n# ================================================\n\n11D60..11D65  ; Gunjala_Gondi # Lo   [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU\n11D67..11D68  ; Gunjala_Gondi # Lo   [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI\n11D6A..11D89  ; Gunjala_Gondi # Lo  [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA\n11D8A..11D8E  ; Gunjala_Gondi # Mc   [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU\n11D90..11D91  ; Gunjala_Gondi # Mn   [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI\n11D93..11D94  ; Gunjala_Gondi # Mc   [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU\n11D95         ; Gunjala_Gondi # Mn       GUNJALA GONDI SIGN ANUSVARA\n11D96         ; Gunjala_Gondi # Mc       GUNJALA GONDI SIGN VISARGA\n11D97         ; Gunjala_Gondi # Mn       GUNJALA GONDI VIRAMA\n11D98         ; Gunjala_Gondi # Lo       GUNJALA GONDI OM\n11DA0..11DA9  ; Gunjala_Gondi # Nd  [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE\n\n# Total code points: 63\n\n# ================================================\n\n11EE0..11EF2  ; Makasar # Lo  [19] MAKASAR LETTER KA..MAKASAR ANGKA\n11EF3..11EF4  ; Makasar # Mn   [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U\n11EF5..11EF6  ; Makasar # Mc   [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O\n11EF7..11EF8  ; Makasar # Po   [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION\n\n# Total code points: 25\n\n# ================================================\n\n16E40..16E7F  ; Medefaidrin # L&  [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y\n16E80..16E96  ; Medefaidrin # No  [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM\n16E97..16E9A  ; Medefaidrin # Po   [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH\n\n# Total code points: 91\n\n# ================================================\n\n10D00..10D23  ; Hanifi_Rohingya # Lo  [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA\n10D24..10D27  ; Hanifi_Rohingya # Mn   [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI\n10D30..10D39  ; Hanifi_Rohingya # Nd  [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE\n\n# Total code points: 50\n\n# ================================================\n\n10F30..10F45  ; Sogdian # Lo  [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN\n10F46..10F50  ; Sogdian # Mn  [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW\n10F51..10F54  ; Sogdian # No   [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED\n10F55..10F59  ; Sogdian # Po   [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT\n\n# Total code points: 42\n\n# ================================================\n\n10F00..10F1C  ; Old_Sogdian # Lo  [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL\n10F1D..10F26  ; Old_Sogdian # No  [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF\n10F27         ; Old_Sogdian # Lo       OLD SOGDIAN LIGATURE AYIN-DALETH\n\n# Total code points: 40\n\n# ================================================\n\n10FE0..10FF6  ; Elymaic # Lo  [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH\n\n# Total code points: 23\n\n# ================================================\n\n119A0..119A7  ; Nandinagari # Lo   [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR\n119AA..119D0  ; Nandinagari # Lo  [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA\n119D1..119D3  ; Nandinagari # Mc   [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II\n119D4..119D7  ; Nandinagari # Mn   [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR\n119DA..119DB  ; Nandinagari # Mn   [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI\n119DC..119DF  ; Nandinagari # Mc   [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA\n119E0         ; Nandinagari # Mn       NANDINAGARI SIGN VIRAMA\n119E1         ; Nandinagari # Lo       NANDINAGARI SIGN AVAGRAHA\n119E2         ; Nandinagari # Po       NANDINAGARI SIGN SIDDHAM\n119E3         ; Nandinagari # Lo       NANDINAGARI HEADSTROKE\n119E4         ; Nandinagari # Mc       NANDINAGARI VOWEL SIGN PRISHTHAMATRA E\n\n# Total code points: 65\n\n# ================================================\n\n1E100..1E12C  ; Nyiakeng_Puachue_Hmong # Lo  [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W\n1E130..1E136  ; Nyiakeng_Puachue_Hmong # Mn   [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D\n1E137..1E13D  ; Nyiakeng_Puachue_Hmong # Lm   [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER\n1E140..1E149  ; Nyiakeng_Puachue_Hmong # Nd  [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE\n1E14E         ; Nyiakeng_Puachue_Hmong # Lo       NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ\n1E14F         ; Nyiakeng_Puachue_Hmong # So       NYIAKENG PUACHUE HMONG CIRCLED CA\n\n# Total code points: 71\n\n# ================================================\n\n1E2C0..1E2EB  ; Wancho # Lo  [44] WANCHO LETTER AA..WANCHO LETTER YIH\n1E2EC..1E2EF  ; Wancho # Mn   [4] WANCHO TONE TUP..WANCHO TONE KOINI\n1E2F0..1E2F9  ; Wancho # Nd  [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE\n1E2FF         ; Wancho # Sc       WANCHO NGUN SIGN\n\n# Total code points: 59\n\n# ================================================\n\n10FB0..10FC4  ; Chorasmian # Lo  [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW\n10FC5..10FCB  ; Chorasmian # No   [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED\n\n# Total code points: 28\n\n# ================================================\n\n11900..11906  ; Dives_Akuru # Lo   [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E\n11909         ; Dives_Akuru # Lo       DIVES AKURU LETTER O\n1190C..11913  ; Dives_Akuru # Lo   [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA\n11915..11916  ; Dives_Akuru # Lo   [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA\n11918..1192F  ; Dives_Akuru # Lo  [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA\n11930..11935  ; Dives_Akuru # Mc   [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E\n11937..11938  ; Dives_Akuru # Mc   [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O\n1193B..1193C  ; Dives_Akuru # Mn   [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU\n1193D         ; Dives_Akuru # Mc       DIVES AKURU SIGN HALANTA\n1193E         ; Dives_Akuru # Mn       DIVES AKURU VIRAMA\n1193F         ; Dives_Akuru # Lo       DIVES AKURU PREFIXED NASAL SIGN\n11940         ; Dives_Akuru # Mc       DIVES AKURU MEDIAL YA\n11941         ; Dives_Akuru # Lo       DIVES AKURU INITIAL RA\n11942         ; Dives_Akuru # Mc       DIVES AKURU MEDIAL RA\n11943         ; Dives_Akuru # Mn       DIVES AKURU SIGN NUKTA\n11944..11946  ; Dives_Akuru # Po   [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK\n11950..11959  ; Dives_Akuru # Nd  [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE\n\n# Total code points: 72\n\n# ================================================\n\n16FE4         ; Khitan_Small_Script # Mn       KHITAN SMALL SCRIPT FILLER\n18B00..18CD5  ; Khitan_Small_Script # Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5\n18CFF         ; Khitan_Small_Script # Lo       KHITAN SMALL SCRIPT CHARACTER-18CFF\n\n# Total code points: 472\n\n# ================================================\n\n10E80..10EA9  ; Yezidi # Lo  [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET\n10EAB..10EAC  ; Yezidi # Mn   [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK\n10EAD         ; Yezidi # Pd       YEZIDI HYPHENATION MARK\n10EB0..10EB1  ; Yezidi # Lo   [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE\n\n# Total code points: 47\n\n# ================================================\n\n12F90..12FF0  ; Cypro_Minoan # Lo  [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114\n12FF1..12FF2  ; Cypro_Minoan # Po   [2] CYPRO-MINOAN SIGN CM301..CYPRO-MINOAN SIGN CM302\n\n# Total code points: 99\n\n# ================================================\n\n10F70..10F81  ; Old_Uyghur # Lo  [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH\n10F82..10F85  ; Old_Uyghur # Mn   [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW\n10F86..10F89  ; Old_Uyghur # Po   [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS\n\n# Total code points: 26\n\n# ================================================\n\n16A70..16ABE  ; Tangsa # Lo  [79] TANGSA LETTER OZ..TANGSA LETTER ZA\n16AC0..16AC9  ; Tangsa # Nd  [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE\n\n# Total code points: 89\n\n# ================================================\n\n1E290..1E2AD  ; Toto # Lo  [30] TOTO LETTER PA..TOTO LETTER A\n1E2AE         ; Toto # Mn       TOTO SIGN RISING TONE\n\n# Total code points: 31\n\n# ================================================\n\n10570..1057A  ; Vithkuqi # L&  [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA\n1057C..1058A  ; Vithkuqi # L&  [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE\n1058C..10592  ; Vithkuqi # L&   [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE\n10594..10595  ; Vithkuqi # L&   [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE\n10597..105A1  ; Vithkuqi # L&  [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA\n105A3..105B1  ; Vithkuqi # L&  [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE\n105B3..105B9  ; Vithkuqi # L&   [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE\n105BB..105BC  ; Vithkuqi # L&   [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE\n\n# Total code points: 70\n\n# ================================================\n\n11F00..11F01  ; Kawi # Mn   [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA\n11F02         ; Kawi # Lo       KAWI SIGN REPHA\n11F03         ; Kawi # Mc       KAWI SIGN VISARGA\n11F04..11F10  ; Kawi # Lo  [13] KAWI LETTER A..KAWI LETTER O\n11F12..11F33  ; Kawi # Lo  [34] KAWI LETTER KA..KAWI LETTER JNYA\n11F34..11F35  ; Kawi # Mc   [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA\n11F36..11F3A  ; Kawi # Mn   [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R\n11F3E..11F3F  ; Kawi # Mc   [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI\n11F40         ; Kawi # Mn       KAWI VOWEL SIGN EU\n11F41         ; Kawi # Mc       KAWI SIGN KILLER\n11F42         ; Kawi # Mn       KAWI CONJOINER\n11F43..11F4F  ; Kawi # Po  [13] KAWI DANDA..KAWI PUNCTUATION CLOSING SPIRAL\n11F50..11F59  ; Kawi # Nd  [10] KAWI DIGIT ZERO..KAWI DIGIT NINE\n11F5A         ; Kawi # Mn       KAWI SIGN NUKTA\n\n# Total code points: 87\n\n# ================================================\n\n1E4D0..1E4EA  ; Nag_Mundari # Lo  [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL\n1E4EB         ; Nag_Mundari # Lm       NAG MUNDARI SIGN OJOD\n1E4EC..1E4EF  ; Nag_Mundari # Mn   [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH\n1E4F0..1E4F9  ; Nag_Mundari # Nd  [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE\n\n# Total code points: 42\n\n# ================================================\n\n10D40..10D49  ; Garay # Nd  [10] GARAY DIGIT ZERO..GARAY DIGIT NINE\n10D4A..10D4D  ; Garay # Lo   [4] GARAY VOWEL SIGN A..GARAY VOWEL SIGN EE\n10D4E         ; Garay # Lm       GARAY VOWEL LENGTH MARK\n10D4F         ; Garay # Lo       GARAY SUKUN\n10D50..10D65  ; Garay # L&  [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA\n10D69..10D6D  ; Garay # Mn   [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK\n10D6E         ; Garay # Pd       GARAY HYPHEN\n10D6F         ; Garay # Lm       GARAY REDUPLICATION MARK\n10D70..10D85  ; Garay # L&  [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA\n10D8E..10D8F  ; Garay # Sm   [2] GARAY PLUS SIGN..GARAY MINUS SIGN\n\n# Total code points: 69\n\n# ================================================\n\n16100..1611D  ; Gurung_Khema # Lo  [30] GURUNG KHEMA LETTER A..GURUNG KHEMA LETTER SA\n1611E..16129  ; Gurung_Khema # Mn  [12] GURUNG KHEMA VOWEL SIGN AA..GURUNG KHEMA VOWEL LENGTH MARK\n1612A..1612C  ; Gurung_Khema # Mc   [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA\n1612D..1612F  ; Gurung_Khema # Mn   [3] GURUNG KHEMA SIGN ANUSVARA..GURUNG KHEMA SIGN THOLHOMA\n16130..16139  ; Gurung_Khema # Nd  [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE\n\n# Total code points: 58\n\n# ================================================\n\n16D40..16D42  ; Kirat_Rai # Lm   [3] KIRAT RAI SIGN ANUSVARA..KIRAT RAI SIGN VISARGA\n16D43..16D6A  ; Kirat_Rai # Lo  [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU\n16D6B..16D6C  ; Kirat_Rai # Lm   [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT\n16D6D..16D6F  ; Kirat_Rai # Po   [3] KIRAT RAI SIGN YUPI..KIRAT RAI DOUBLE DANDA\n16D70..16D79  ; Kirat_Rai # Nd  [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE\n\n# Total code points: 58\n\n# ================================================\n\n1E5D0..1E5ED  ; Ol_Onal # Lo  [30] OL ONAL LETTER O..OL ONAL LETTER EG\n1E5EE..1E5EF  ; Ol_Onal # Mn   [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR\n1E5F0         ; Ol_Onal # Lo       OL ONAL SIGN HODDOND\n1E5F1..1E5FA  ; Ol_Onal # Nd  [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE\n1E5FF         ; Ol_Onal # Po       OL ONAL ABBREVIATION SIGN\n\n# Total code points: 44\n\n# ================================================\n\n11BC0..11BE0  ; Sunuwar # Lo  [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO\n11BE1         ; Sunuwar # Po       SUNUWAR SIGN PVO\n11BF0..11BF9  ; Sunuwar # Nd  [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE\n\n# Total code points: 44\n\n# ================================================\n\n105C0..105F3  ; Todhri # Lo  [52] TODHRI LETTER A..TODHRI LETTER OO\n\n# Total code points: 52\n\n# ================================================\n\n11380..11389  ; Tulu_Tigalari # Lo  [10] TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL\n1138B         ; Tulu_Tigalari # Lo       TULU-TIGALARI LETTER EE\n1138E         ; Tulu_Tigalari # Lo       TULU-TIGALARI LETTER AI\n11390..113B5  ; Tulu_Tigalari # Lo  [38] TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA\n113B7         ; Tulu_Tigalari # Lo       TULU-TIGALARI SIGN AVAGRAHA\n113B8..113BA  ; Tulu_Tigalari # Mc   [3] TULU-TIGALARI VOWEL SIGN AA..TULU-TIGALARI VOWEL SIGN II\n113BB..113C0  ; Tulu_Tigalari # Mn   [6] TULU-TIGALARI VOWEL SIGN U..TULU-TIGALARI VOWEL SIGN VOCALIC LL\n113C2         ; Tulu_Tigalari # Mc       TULU-TIGALARI VOWEL SIGN EE\n113C5         ; Tulu_Tigalari # Mc       TULU-TIGALARI VOWEL SIGN AI\n113C7..113CA  ; Tulu_Tigalari # Mc   [4] TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA\n113CC..113CD  ; Tulu_Tigalari # Mc   [2] TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI SIGN VISARGA\n113CE         ; Tulu_Tigalari # Mn       TULU-TIGALARI SIGN VIRAMA\n113CF         ; Tulu_Tigalari # Mc       TULU-TIGALARI SIGN LOOPED VIRAMA\n113D0         ; Tulu_Tigalari # Mn       TULU-TIGALARI CONJOINER\n113D1         ; Tulu_Tigalari # Lo       TULU-TIGALARI REPHA\n113D2         ; Tulu_Tigalari # Mn       TULU-TIGALARI GEMINATION MARK\n113D3         ; Tulu_Tigalari # Lo       TULU-TIGALARI SIGN PLUTA\n113D4..113D5  ; Tulu_Tigalari # Po   [2] TULU-TIGALARI DANDA..TULU-TIGALARI DOUBLE DANDA\n113D7..113D8  ; Tulu_Tigalari # Po   [2] TULU-TIGALARI SIGN OM PUSHPIKA..TULU-TIGALARI SIGN SHRII PUSHPIKA\n113E1..113E2  ; Tulu_Tigalari # Mn   [2] TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA\n\n# Total code points: 80\n\n# ================================================\n\n10940..10959  ; Sidetic # Lo  [26] SIDETIC LETTER N01..SIDETIC LETTER N26\n\n# Total code points: 26\n\n# ================================================\n\n1E6C0..1E6DE  ; Tai_Yo # Lo  [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO\n1E6E0..1E6E2  ; Tai_Yo # Lo   [3] TAI YO LETTER AA..TAI YO LETTER UE\n1E6E3         ; Tai_Yo # Mn       TAI YO SIGN UE\n1E6E4..1E6E5  ; Tai_Yo # Lo   [2] TAI YO LETTER U..TAI YO LETTER AE\n1E6E6         ; Tai_Yo # Mn       TAI YO SIGN AU\n1E6E7..1E6ED  ; Tai_Yo # Lo   [7] TAI YO LETTER O..TAI YO LETTER AUE\n1E6EE..1E6EF  ; Tai_Yo # Mn   [2] TAI YO SIGN AY..TAI YO SIGN ANG\n1E6F0..1E6F4  ; Tai_Yo # Lo   [5] TAI YO LETTER AN..TAI YO LETTER AP\n1E6F5         ; Tai_Yo # Mn       TAI YO SIGN OM\n1E6FE         ; Tai_Yo # Lo       TAI YO SYMBOL MUEANG\n1E6FF         ; Tai_Yo # Lm       TAI YO XAM LAI\n\n# Total code points: 55\n\n# ================================================\n\n11DB0..11DD8  ; Tolong_Siki # Lo  [41] TOLONG SIKI LETTER I..TOLONG SIKI LETTER RRH\n11DD9         ; Tolong_Siki # Lm       TOLONG SIKI SIGN SELA\n11DDA..11DDB  ; Tolong_Siki # Lo   [2] TOLONG SIKI SIGN HECAKA..TOLONG SIKI UNGGA\n11DE0..11DE9  ; Tolong_Siki # Nd  [10] TOLONG SIKI DIGIT ZERO..TOLONG SIKI DIGIT NINE\n\n# Total code points: 54\n\n# ================================================\n\n16EA0..16EB8  ; Beria_Erfe # L&  [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY\n16EBB..16ED3  ; Beria_Erfe # L&  [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY\n\n# Total code points: 50\n\n# EOF\n"
  },
  {
    "path": "lib/elixir/unicode/SpecialCasing.txt",
    "content": "# SpecialCasing-17.0.0.txt\n# Date: 2025-07-31, 22:11:55 GMT\n# © 2025 Unicode®, Inc.\n# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.\n# For terms of use and license, see https://www.unicode.org/terms_of_use.html\n#\n# Unicode Character Database\n#   For documentation, see https://www.unicode.org/reports/tr44/\n#\n# Special Casing\n#\n# This file is a supplement to the UnicodeData.txt file. The data in this file, combined with\n# the simple case mappings in UnicodeData.txt, defines the full case mappings\n# Lowercase_Mapping (lc), Titlecase_Mapping (tc), and Uppercase_Mapping (uc).\n# For compatibility, the UnicodeData.txt file only contains simple case mappings\n# for characters where they are one-to-one (and independent of context and language).\n#\n# For historical reasons, this file also provides additional information about the casing\n# of Unicode characters for selected situations when casing is dependent on context or locale.\n#\n# Note that the preferred mechanism for defining tailored casing operations is\n# the Unicode Common Locale Data Repository (CLDR). For more information, see the\n# discussion of case mappings and case algorithms in the Unicode Standard.\n#\n# All code points not listed in this file that do not have simple case mappings\n# in UnicodeData.txt map to themselves.\n# ================================================================================\n# Format\n# ================================================================================\n# The entries in this file are in the following machine-readable format:\n#\n# <code>; <lower>; <title>; <upper>; (<condition_list>;)? # <comment>\n#\n# <code>, <lower>, <title>, and <upper> provide the respective full case mappings\n# of <code>, expressed as character values in hex. If there is more than one character,\n# they are separated by spaces. Other than as used to separate elements, spaces are\n# to be ignored.\n#\n# The <condition_list> is optional. Where present, it consists of one or more language IDs\n# or casing contexts, separated by spaces. In these conditions:\n# - A condition list overrides the normal behavior if all of the listed conditions are true.\n# - The casing context is always the context of the characters in the original string,\n#   NOT in the resulting string.\n# - Case distinctions in the condition list are not significant.\n# - Conditions preceded by \"Not_\" represent the negation of the condition.\n# The condition list is not represented in the UCD as a formal property.\n#\n# A language ID is defined by BCP 47, with '-' and '_' treated equivalently.\n#\n# A casing context for a character is defined in the\n# \"Conformance\" / \"Default Case Algorithms\" section of the core specification.\n#\n# Parsers of this file must be prepared to deal with future additions to this format:\n#  * Additional contexts\n#  * Additional fields\n# ================================================================================\n\n# ================================================================================\n# Unconditional mappings\n# The mappings in this section are not language-sensitive nor context-sensitive.\n#\n# Note that comments provide additional information but\n# do not modify the case mapping algorithms in the core specification, chapter 3.\n# ================================================================================\n\n# The German es-zed is special--the normal mapping is to SS.\n# Note: the titlecase should never occur in practice. It is equal to titlecase(uppercase(<es-zed>))\n\n00DF; 00DF; 0053 0073; 0053 0053; # LATIN SMALL LETTER SHARP S\n\n# Preserve canonical equivalence for I with dot. Turkic is handled below.\n\n0130; 0069 0307; 0130; 0130; # LATIN CAPITAL LETTER I WITH DOT ABOVE\n\n# Ligatures\n\nFB00; FB00; 0046 0066; 0046 0046; # LATIN SMALL LIGATURE FF\nFB01; FB01; 0046 0069; 0046 0049; # LATIN SMALL LIGATURE FI\nFB02; FB02; 0046 006C; 0046 004C; # LATIN SMALL LIGATURE FL\nFB03; FB03; 0046 0066 0069; 0046 0046 0049; # LATIN SMALL LIGATURE FFI\nFB04; FB04; 0046 0066 006C; 0046 0046 004C; # LATIN SMALL LIGATURE FFL\nFB05; FB05; 0053 0074; 0053 0054; # LATIN SMALL LIGATURE LONG S T\nFB06; FB06; 0053 0074; 0053 0054; # LATIN SMALL LIGATURE ST\n\n0587; 0587; 0535 0582; 0535 0552; # ARMENIAN SMALL LIGATURE ECH YIWN\nFB13; FB13; 0544 0576; 0544 0546; # ARMENIAN SMALL LIGATURE MEN NOW\nFB14; FB14; 0544 0565; 0544 0535; # ARMENIAN SMALL LIGATURE MEN ECH\nFB15; FB15; 0544 056B; 0544 053B; # ARMENIAN SMALL LIGATURE MEN INI\nFB16; FB16; 054E 0576; 054E 0546; # ARMENIAN SMALL LIGATURE VEW NOW\nFB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH\n\n# No corresponding uppercase precomposed character\n\n0149; 0149; 02BC 004E; 02BC 004E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE\n0390; 0390; 0399 0308 0301; 0399 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS\n03B0; 03B0; 03A5 0308 0301; 03A5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS\n01F0; 01F0; 004A 030C; 004A 030C; # LATIN SMALL LETTER J WITH CARON\n1E96; 1E96; 0048 0331; 0048 0331; # LATIN SMALL LETTER H WITH LINE BELOW\n1E97; 1E97; 0054 0308; 0054 0308; # LATIN SMALL LETTER T WITH DIAERESIS\n1E98; 1E98; 0057 030A; 0057 030A; # LATIN SMALL LETTER W WITH RING ABOVE\n1E99; 1E99; 0059 030A; 0059 030A; # LATIN SMALL LETTER Y WITH RING ABOVE\n1E9A; 1E9A; 0041 02BE; 0041 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING\n1F50; 1F50; 03A5 0313; 03A5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI\n1F52; 1F52; 03A5 0313 0300; 03A5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA\n1F54; 1F54; 03A5 0313 0301; 03A5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA\n1F56; 1F56; 03A5 0313 0342; 03A5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI\n1FB6; 1FB6; 0391 0342; 0391 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI\n1FC6; 1FC6; 0397 0342; 0397 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI\n1FD2; 1FD2; 0399 0308 0300; 0399 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA\n1FD3; 1FD3; 0399 0308 0301; 0399 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA\n1FD6; 1FD6; 0399 0342; 0399 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI\n1FD7; 1FD7; 0399 0308 0342; 0399 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI\n1FE2; 1FE2; 03A5 0308 0300; 03A5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA\n1FE3; 1FE3; 03A5 0308 0301; 03A5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA\n1FE4; 1FE4; 03A1 0313; 03A1 0313; # GREEK SMALL LETTER RHO WITH PSILI\n1FE6; 1FE6; 03A5 0342; 03A5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI\n1FE7; 1FE7; 03A5 0308 0342; 03A5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI\n1FF6; 1FF6; 03A9 0342; 03A9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI\n\n# IMPORTANT-when iota-subscript (0345) is uppercased or titlecased,\n#  the result will be incorrect unless the iota-subscript is moved to the end\n#  of any sequence of combining marks. Otherwise, the accents will go on the capital iota.\n#  This process can be achieved by first transforming the text to NFC before casing.\n#  E.g. <alpha><iota_subscript><acute> is uppercased to <ALPHA><acute><IOTA>\n\n# The following cases are already in the UnicodeData.txt file, so are only commented here.\n\n# 0345; 0345; 0399; 0399; # COMBINING GREEK YPOGEGRAMMENI\n\n# All letters with YPOGEGRAMMENI (iota-subscript) or PROSGEGRAMMENI (iota adscript)\n# have special uppercases.\n# Note: characters with PROSGEGRAMMENI are actually titlecase, not uppercase!\n\n1F80; 1F80; 1F88; 1F08 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI\n1F81; 1F81; 1F89; 1F09 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI\n1F82; 1F82; 1F8A; 1F0A 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI\n1F83; 1F83; 1F8B; 1F0B 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI\n1F84; 1F84; 1F8C; 1F0C 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI\n1F85; 1F85; 1F8D; 1F0D 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI\n1F86; 1F86; 1F8E; 1F0E 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI\n1F87; 1F87; 1F8F; 1F0F 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI\n1F88; 1F80; 1F88; 1F08 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI\n1F89; 1F81; 1F89; 1F09 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI\n1F8A; 1F82; 1F8A; 1F0A 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n1F8B; 1F83; 1F8B; 1F0B 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n1F8C; 1F84; 1F8C; 1F0C 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n1F8D; 1F85; 1F8D; 1F0D 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n1F8E; 1F86; 1F8E; 1F0E 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n1F8F; 1F87; 1F8F; 1F0F 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n1F90; 1F90; 1F98; 1F28 0399; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI\n1F91; 1F91; 1F99; 1F29 0399; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI\n1F92; 1F92; 1F9A; 1F2A 0399; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI\n1F93; 1F93; 1F9B; 1F2B 0399; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI\n1F94; 1F94; 1F9C; 1F2C 0399; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI\n1F95; 1F95; 1F9D; 1F2D 0399; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI\n1F96; 1F96; 1F9E; 1F2E 0399; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI\n1F97; 1F97; 1F9F; 1F2F 0399; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI\n1F98; 1F90; 1F98; 1F28 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI\n1F99; 1F91; 1F99; 1F29 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI\n1F9A; 1F92; 1F9A; 1F2A 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n1F9B; 1F93; 1F9B; 1F2B 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n1F9C; 1F94; 1F9C; 1F2C 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n1F9D; 1F95; 1F9D; 1F2D 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n1F9E; 1F96; 1F9E; 1F2E 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n1F9F; 1F97; 1F9F; 1F2F 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n1FA0; 1FA0; 1FA8; 1F68 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI\n1FA1; 1FA1; 1FA9; 1F69 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI\n1FA2; 1FA2; 1FAA; 1F6A 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI\n1FA3; 1FA3; 1FAB; 1F6B 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI\n1FA4; 1FA4; 1FAC; 1F6C 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI\n1FA5; 1FA5; 1FAD; 1F6D 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI\n1FA6; 1FA6; 1FAE; 1F6E 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI\n1FA7; 1FA7; 1FAF; 1F6F 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI\n1FA8; 1FA0; 1FA8; 1F68 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI\n1FA9; 1FA1; 1FA9; 1F69 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI\n1FAA; 1FA2; 1FAA; 1F6A 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n1FAB; 1FA3; 1FAB; 1F6B 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n1FAC; 1FA4; 1FAC; 1F6C 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n1FAD; 1FA5; 1FAD; 1F6D 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n1FAE; 1FA6; 1FAE; 1F6E 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n1FAF; 1FA7; 1FAF; 1F6F 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n1FB3; 1FB3; 1FBC; 0391 0399; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI\n1FBC; 1FB3; 1FBC; 0391 0399; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI\n1FC3; 1FC3; 1FCC; 0397 0399; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI\n1FCC; 1FC3; 1FCC; 0397 0399; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI\n1FF3; 1FF3; 1FFC; 03A9 0399; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI\n1FFC; 1FF3; 1FFC; 03A9 0399; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI\n\n# Some characters with YPOGEGRAMMENI also have no corresponding titlecases\n\n1FB2; 1FB2; 1FBA 0345; 1FBA 0399; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI\n1FB4; 1FB4; 0386 0345; 0386 0399; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI\n1FC2; 1FC2; 1FCA 0345; 1FCA 0399; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI\n1FC4; 1FC4; 0389 0345; 0389 0399; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI\n1FF2; 1FF2; 1FFA 0345; 1FFA 0399; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI\n1FF4; 1FF4; 038F 0345; 038F 0399; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI\n\n1FB7; 1FB7; 0391 0342 0345; 0391 0342 0399; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI\n1FC7; 1FC7; 0397 0342 0345; 0397 0342 0399; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI\n1FF7; 1FF7; 03A9 0342 0345; 03A9 0342 0399; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI\n\n# ================================================================================\n# Conditional Mappings\n# The remainder of this file provides conditional casing data used to produce\n# full case mappings.\n# ================================================================================\n# Language-Insensitive Mappings\n# These are characters whose full case mappings do not depend on language, but do\n# depend on context (which characters come before or after). For more information\n# see the header of this file and the Unicode Standard.\n# ================================================================================\n\n# Special case for final form of sigma\n\n03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA\n\n# Note: the following cases for non-final are already in the UnicodeData.txt file.\n\n# 03A3; 03C3; 03A3; 03A3; # GREEK CAPITAL LETTER SIGMA\n# 03C3; 03C3; 03A3; 03A3; # GREEK SMALL LETTER SIGMA\n# 03C2; 03C2; 03A3; 03A3; # GREEK SMALL LETTER FINAL SIGMA\n\n# Note: the following cases are not included, since they would case-fold in lowercasing\n\n# 03C3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK SMALL LETTER SIGMA\n# 03C2; 03C3; 03A3; 03A3; Not_Final_Sigma; # GREEK SMALL LETTER FINAL SIGMA\n\n# ================================================================================\n# Language-Sensitive Mappings\n# These are characters whose full case mappings depend on language and perhaps also\n# context (which characters come before or after). For more information\n# see the header of this file and the Unicode Standard.\n# ================================================================================\n\n# Lithuanian\n\n# Lithuanian retains the dot in a lowercase i when followed by accents.\n\n# Remove DOT ABOVE after \"i\" with upper or titlecase\n\n0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE\n\n# Introduce an explicit dot above when lowercasing capital I's and J's\n# whenever there are more accents above.\n# (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek)\n\n0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I\n004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J\n012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK\n00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE\n00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE\n0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE\n\n# ================================================================================\n\n# Turkish and Azeri\n\n# I and i-dotless; I-dot and i are case pairs in Turkish and Azeri\n# The following rules handle those cases.\n\n0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE\n0130; 0069; 0130; 0130; az; # LATIN CAPITAL LETTER I WITH DOT ABOVE\n\n# When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i.\n# This matches the behavior of the canonically equivalent I-dot_above\n\n0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE\n0307; ; 0307; 0307; az After_I; # COMBINING DOT ABOVE\n\n# When lowercasing, unless an I is before a dot_above, it turns into a dotless i.\n\n0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I\n0049; 0131; 0049; 0049; az Not_Before_Dot; # LATIN CAPITAL LETTER I\n\n# When uppercasing, i turns into a dotted capital I\n\n0069; 0069; 0130; 0130; tr; # LATIN SMALL LETTER I\n0069; 0069; 0130; 0130; az; # LATIN SMALL LETTER I\n\n# Note: the following case is already in the UnicodeData.txt file.\n\n# 0131; 0131; 0049; 0049; tr; # LATIN SMALL LETTER DOTLESS I\n\n# EOF\n\n"
  },
  {
    "path": "lib/elixir/unicode/UnicodeData.txt",
    "content": "0000;<control>;Cc;0;BN;;;;;N;NULL;;;;\n0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;;\n0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;;\n0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;;\n0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;;\n0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;;\n0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;;\n0007;<control>;Cc;0;BN;;;;;N;BELL;;;;\n0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;;\n0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;\n000A;<control>;Cc;0;B;;;;;N;LINE FEED (LF);;;;\n000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;\n000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;\n000D;<control>;Cc;0;B;;;;;N;CARRIAGE RETURN (CR);;;;\n000E;<control>;Cc;0;BN;;;;;N;SHIFT OUT;;;;\n000F;<control>;Cc;0;BN;;;;;N;SHIFT IN;;;;\n0010;<control>;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;;\n0011;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;;\n0012;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;;\n0013;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;;\n0014;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;;\n0015;<control>;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;;\n0016;<control>;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;;\n0017;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;;\n0018;<control>;Cc;0;BN;;;;;N;CANCEL;;;;\n0019;<control>;Cc;0;BN;;;;;N;END OF MEDIUM;;;;\n001A;<control>;Cc;0;BN;;;;;N;SUBSTITUTE;;;;\n001B;<control>;Cc;0;BN;;;;;N;ESCAPE;;;;\n001C;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR FOUR;;;;\n001D;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR THREE;;;;\n001E;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR TWO;;;;\n001F;<control>;Cc;0;S;;;;;N;INFORMATION SEPARATOR ONE;;;;\n0020;SPACE;Zs;0;WS;;;;;N;;;;;\n0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;\n0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;;\n0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;;\n0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;;\n0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;;\n0026;AMPERSAND;Po;0;ON;;;;;N;;;;;\n0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;;\n0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;;\n0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;;\n002A;ASTERISK;Po;0;ON;;;;;N;;;;;\n002B;PLUS SIGN;Sm;0;ES;;;;;N;;;;;\n002C;COMMA;Po;0;CS;;;;;N;;;;;\n002D;HYPHEN-MINUS;Pd;0;ES;;;;;N;;;;;\n002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;;\n002F;SOLIDUS;Po;0;CS;;;;;N;SLASH;;;;\n0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;;\n0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;;\n0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;;\n0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;;\n0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;;\n0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;;\n0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;;\n0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;\n0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;;\n0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;;\n003A;COLON;Po;0;CS;;;;;N;;;;;\n003B;SEMICOLON;Po;0;ON;;;;;N;;;;;\n003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;;\n003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;;\n003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;;\n003F;QUESTION MARK;Po;0;ON;;;;;N;;;;;\n0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;;\n0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061;\n0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062;\n0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063;\n0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064;\n0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065;\n0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066;\n0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067;\n0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068;\n0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069;\n004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A;\n004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B;\n004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C;\n004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D;\n004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E;\n004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F;\n0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070;\n0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071;\n0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072;\n0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073;\n0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074;\n0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075;\n0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076;\n0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077;\n0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078;\n0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079;\n005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A;\n005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;;\n005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;;\n005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;;\n005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;;\n005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;;\n0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;;\n0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041\n0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042\n0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043\n0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044\n0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045\n0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046\n0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047\n0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048\n0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049\n006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A\n006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B\n006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C\n006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D\n006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E\n006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F\n0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050\n0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051\n0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052\n0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053\n0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054\n0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055\n0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056\n0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057\n0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058\n0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059\n007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A\n007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;;\n007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;;\n007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;;\n007E;TILDE;Sm;0;ON;;;;;N;;;;;\n007F;<control>;Cc;0;BN;;;;;N;DELETE;;;;\n0080;<control>;Cc;0;BN;;;;;N;;;;;\n0081;<control>;Cc;0;BN;;;;;N;;;;;\n0082;<control>;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;;\n0083;<control>;Cc;0;BN;;;;;N;NO BREAK HERE;;;;\n0084;<control>;Cc;0;BN;;;;;N;;;;;\n0085;<control>;Cc;0;B;;;;;N;NEXT LINE (NEL);;;;\n0086;<control>;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;;\n0087;<control>;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;;\n0088;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;;\n0089;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;;\n008A;<control>;Cc;0;BN;;;;;N;LINE TABULATION SET;;;;\n008B;<control>;Cc;0;BN;;;;;N;PARTIAL LINE FORWARD;;;;\n008C;<control>;Cc;0;BN;;;;;N;PARTIAL LINE BACKWARD;;;;\n008D;<control>;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;;\n008E;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;;\n008F;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;;\n0090;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;;\n0091;<control>;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;;\n0092;<control>;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;;\n0093;<control>;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;;\n0094;<control>;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;;\n0095;<control>;Cc;0;BN;;;;;N;MESSAGE WAITING;;;;\n0096;<control>;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;;\n0097;<control>;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;;\n0098;<control>;Cc;0;BN;;;;;N;START OF STRING;;;;\n0099;<control>;Cc;0;BN;;;;;N;;;;;\n009A;<control>;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;;\n009B;<control>;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;;\n009C;<control>;Cc;0;BN;;;;;N;STRING TERMINATOR;;;;\n009D;<control>;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;;\n009E;<control>;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;;\n009F;<control>;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;;\n00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;\n00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;\n00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;;\n00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;;\n00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;\n00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;;\n00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;;\n00A7;SECTION SIGN;Po;0;ON;;;;;N;;;;;\n00A8;DIAERESIS;Sk;0;ON;<compat> 0020 0308;;;;N;SPACING DIAERESIS;;;;\n00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;;\n00AA;FEMININE ORDINAL INDICATOR;Lo;0;L;<super> 0061;;;;N;;;;;\n00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;;;;\n00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;;\n00AD;SOFT HYPHEN;Cf;0;BN;;;;;N;;;;;\n00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;;\n00AF;MACRON;Sk;0;ON;<compat> 0020 0304;;;;N;SPACING MACRON;;;;\n00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;;\n00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;;\n00B2;SUPERSCRIPT TWO;No;0;EN;<super> 0032;;2;2;N;SUPERSCRIPT DIGIT TWO;;;;\n00B3;SUPERSCRIPT THREE;No;0;EN;<super> 0033;;3;3;N;SUPERSCRIPT DIGIT THREE;;;;\n00B4;ACUTE ACCENT;Sk;0;ON;<compat> 0020 0301;;;;N;SPACING ACUTE;;;;\n00B5;MICRO SIGN;Ll;0;L;<compat> 03BC;;;;N;;;039C;;039C\n00B6;PILCROW SIGN;Po;0;ON;;;;;N;PARAGRAPH SIGN;;;;\n00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;;\n00B8;CEDILLA;Sk;0;ON;<compat> 0020 0327;;;;N;SPACING CEDILLA;;;;\n00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;;\n00BA;MASCULINE ORDINAL INDICATOR;Lo;0;L;<super> 006F;;;;N;;;;;\n00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;;;;\n00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;;\n00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;;\n00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON;<fraction> 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;;\n00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;;\n00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0;\n00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1;\n00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2;\n00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3;\n00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4;\n00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5;\n00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;;;00E6;\n00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7;\n00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8;\n00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9;\n00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA;\n00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB;\n00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC;\n00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED;\n00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE;\n00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF;\n00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;00F0;\n00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1;\n00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2;\n00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3;\n00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4;\n00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5;\n00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6;\n00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;;\n00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8;\n00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9;\n00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA;\n00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB;\n00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC;\n00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD;\n00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;;;00FE;\n00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;;;;\n00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0\n00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1\n00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2\n00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3\n00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4\n00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5\n00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;;00C6;;00C6\n00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7\n00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8\n00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9\n00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA\n00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB\n00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC\n00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD\n00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE\n00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF\n00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;;00D0;;00D0\n00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1\n00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2\n00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3\n00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4\n00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5\n00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6\n00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;;\n00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8\n00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9\n00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA\n00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB\n00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC\n00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD\n00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;;00DE;;00DE\n00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178\n0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101;\n0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100\n0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103;\n0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102\n0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105;\n0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104\n0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107;\n0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106\n0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109;\n0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108\n010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B;\n010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A\n010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D;\n010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C\n010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F;\n010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E\n0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111;\n0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110\n0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113;\n0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112\n0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115;\n0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114\n0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117;\n0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116\n0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119;\n0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118\n011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B;\n011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A\n011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D;\n011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C\n011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F;\n011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E\n0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121;\n0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120\n0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123;\n0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122\n0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125;\n0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124\n0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127;\n0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126\n0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129;\n0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128\n012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B;\n012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A\n012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D;\n012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C\n012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F;\n012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E\n0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069;\n0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049\n0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L;<compat> 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133;\n0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132\n0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135;\n0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134\n0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137;\n0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136\n0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;;;;\n0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;\n013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139\n013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C;\n013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B\n013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E;\n013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D\n013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;\n0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L;<compat> 006C 00B7;;;;N;;;013F;;013F\n0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142;\n0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141\n0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144;\n0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143\n0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146;\n0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145\n0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148;\n0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147\n0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L;<compat> 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;;\n014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;014B;\n014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;;014A;;014A\n014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D;\n014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C\n014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F;\n014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E\n0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151;\n0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150\n0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153;\n0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152\n0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155;\n0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154\n0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157;\n0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156\n0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159;\n0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158\n015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B;\n015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A\n015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D;\n015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C\n015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;;;015F;\n015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;;015E;;015E\n0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161;\n0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160\n0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;;;0163;\n0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;;0162;;0162\n0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165;\n0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164\n0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167;\n0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166\n0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169;\n0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168\n016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B;\n016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A\n016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D;\n016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C\n016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F;\n016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E\n0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171;\n0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170\n0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173;\n0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172\n0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175;\n0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174\n0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177;\n0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176\n0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF;\n0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A;\n017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179\n017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C;\n017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B\n017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E;\n017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D\n017F;LATIN SMALL LETTER LONG S;Ll;0;L;<compat> 0073;;;;N;;;0053;;0053\n0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;0243;;0243\n0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253;\n0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183;\n0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182\n0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185;\n0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184\n0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254;\n0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188;\n0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187\n0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;;;0256;\n018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257;\n018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C;\n018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B\n018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;;\n018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD;\n018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259;\n0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B;\n0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192;\n0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191\n0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260;\n0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263;\n0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;;01F6;;01F6\n0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269;\n0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268;\n0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199;\n0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198\n019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;023D;;023D\n019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;A7DC;;A7DC\n019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F;\n019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272;\n019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;0220;;0220\n019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;;;0275;\n01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1;\n01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0\n01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;;;01A3;\n01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;;01A2;;01A2\n01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5;\n01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4\n01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;;;0280;\n01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8;\n01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7\n01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283;\n01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;;\n01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;;\n01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD;\n01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC\n01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288;\n01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0;\n01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF\n01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A;\n01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B;\n01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4;\n01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3\n01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6;\n01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5\n01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292;\n01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9;\n01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8\n01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;;\n01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;;\n01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD;\n01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC\n01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;;\n01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7\n01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;;\n01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;;\n01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;;\n01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;;\n01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L;<compat> 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5\n01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L;<compat> 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6;01C5\n01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L;<compat> 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5\n01C7;LATIN CAPITAL LETTER LJ;Lu;0;L;<compat> 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8\n01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L;<compat> 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9;01C8\n01C9;LATIN SMALL LETTER LJ;Ll;0;L;<compat> 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8\n01CA;LATIN CAPITAL LETTER NJ;Lu;0;L;<compat> 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB\n01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L;<compat> 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC;01CB\n01CC;LATIN SMALL LETTER NJ;Ll;0;L;<compat> 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB\n01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE;\n01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD\n01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0;\n01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF\n01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2;\n01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1\n01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4;\n01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3\n01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6;\n01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5\n01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8;\n01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7\n01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA;\n01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9\n01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC;\n01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB\n01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E\n01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF;\n01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE\n01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1;\n01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0\n01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;;;01E3;\n01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;;01E2;;01E2\n01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5;\n01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4\n01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7;\n01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6\n01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9;\n01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8\n01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB;\n01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA\n01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED;\n01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC\n01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF;\n01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE\n01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;;\n01F1;LATIN CAPITAL LETTER DZ;Lu;0;L;<compat> 0044 005A;;;;N;;;;01F3;01F2\n01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L;<compat> 0044 007A;;;;N;;;01F1;01F3;01F2\n01F3;LATIN SMALL LETTER DZ;Ll;0;L;<compat> 0064 007A;;;;N;;;01F1;;01F2\n01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5;\n01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4\n01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195;\n01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF;\n01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9;\n01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8\n01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB;\n01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA\n01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;;;01FD;\n01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;;01FC;;01FC\n01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF;\n01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE\n0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201;\n0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200\n0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203;\n0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202\n0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205;\n0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204\n0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207;\n0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206\n0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209;\n0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208\n020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B;\n020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A\n020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D;\n020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C\n020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F;\n020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E\n0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211;\n0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210\n0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213;\n0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212\n0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215;\n0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214\n0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217;\n0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216\n0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;;;0219;\n0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;;0218;;0218\n021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;;;021B;\n021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;;021A;;021A\n021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D;\n021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C\n021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F;\n021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E\n0220;LATIN CAPITAL LETTER N WITH LONG RIGHT LEG;Lu;0;L;;;;;N;;;;019E;\n0221;LATIN SMALL LETTER D WITH CURL;Ll;0;L;;;;;N;;;;;\n0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223;\n0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222\n0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225;\n0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224\n0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227;\n0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226\n0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229;\n0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228\n022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B;\n022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A\n022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D;\n022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C\n022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F;\n022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E\n0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231;\n0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230\n0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233;\n0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232\n0234;LATIN SMALL LETTER L WITH CURL;Ll;0;L;;;;;N;;;;;\n0235;LATIN SMALL LETTER N WITH CURL;Ll;0;L;;;;;N;;;;;\n0236;LATIN SMALL LETTER T WITH CURL;Ll;0;L;;;;;N;;;;;\n0237;LATIN SMALL LETTER DOTLESS J;Ll;0;L;;;;;N;;;;;\n0238;LATIN SMALL LETTER DB DIGRAPH;Ll;0;L;;;;;N;;;;;\n0239;LATIN SMALL LETTER QP DIGRAPH;Ll;0;L;;;;;N;;;;;\n023A;LATIN CAPITAL LETTER A WITH STROKE;Lu;0;L;;;;;N;;;;2C65;\n023B;LATIN CAPITAL LETTER C WITH STROKE;Lu;0;L;;;;;N;;;;023C;\n023C;LATIN SMALL LETTER C WITH STROKE;Ll;0;L;;;;;N;;;023B;;023B\n023D;LATIN CAPITAL LETTER L WITH BAR;Lu;0;L;;;;;N;;;;019A;\n023E;LATIN CAPITAL LETTER T WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;2C66;\n023F;LATIN SMALL LETTER S WITH SWASH TAIL;Ll;0;L;;;;;N;;;2C7E;;2C7E\n0240;LATIN SMALL LETTER Z WITH SWASH TAIL;Ll;0;L;;;;;N;;;2C7F;;2C7F\n0241;LATIN CAPITAL LETTER GLOTTAL STOP;Lu;0;L;;;;;N;;;;0242;\n0242;LATIN SMALL LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;0241;;0241\n0243;LATIN CAPITAL LETTER B WITH STROKE;Lu;0;L;;;;;N;;;;0180;\n0244;LATIN CAPITAL LETTER U BAR;Lu;0;L;;;;;N;;;;0289;\n0245;LATIN CAPITAL LETTER TURNED V;Lu;0;L;;;;;N;;;;028C;\n0246;LATIN CAPITAL LETTER E WITH STROKE;Lu;0;L;;;;;N;;;;0247;\n0247;LATIN SMALL LETTER E WITH STROKE;Ll;0;L;;;;;N;;;0246;;0246\n0248;LATIN CAPITAL LETTER J WITH STROKE;Lu;0;L;;;;;N;;;;0249;\n0249;LATIN SMALL LETTER J WITH STROKE;Ll;0;L;;;;;N;;;0248;;0248\n024A;LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL;Lu;0;L;;;;;N;;;;024B;\n024B;LATIN SMALL LETTER Q WITH HOOK TAIL;Ll;0;L;;;;;N;;;024A;;024A\n024C;LATIN CAPITAL LETTER R WITH STROKE;Lu;0;L;;;;;N;;;;024D;\n024D;LATIN SMALL LETTER R WITH STROKE;Ll;0;L;;;;;N;;;024C;;024C\n024E;LATIN CAPITAL LETTER Y WITH STROKE;Lu;0;L;;;;;N;;;;024F;\n024F;LATIN SMALL LETTER Y WITH STROKE;Ll;0;L;;;;;N;;;024E;;024E\n0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;2C6F;;2C6F\n0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;2C6D;;2C6D\n0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;2C70;;2C70\n0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181\n0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186\n0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;;\n0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189\n0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A\n0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;;\n0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F\n025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;;\n025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190\n025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;A7AB;;A7AB\n025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;;\n025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;;\n025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;;\n0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193\n0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;A7AC;;A7AC\n0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;;\n0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194\n0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;A7CB;;A7CB\n0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;A78D;;A78D\n0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;A7AA;;A7AA\n0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;;\n0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197\n0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196\n026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;A7AE;;A7AE\n026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;2C62;;2C62\n026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;A7AD;;A7AD\n026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;;\n026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;;\n026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C\n0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;;\n0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;2C6E;;2C6E\n0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D\n0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;;\n0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;;\n0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F\n0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;;\n0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;;\n0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;;\n0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;;\n027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;;\n027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;;\n027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;;\n027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;2C64;;2C64\n027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;;\n027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;;\n0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;;01A6;;01A6\n0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;;\n0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;A7C5;;A7C5\n0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9\n0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;;\n0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;;\n0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;;\n0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;A7B1;;A7B1\n0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE\n0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;0244;;0244\n028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1\n028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2\n028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;0245;;0245\n028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;;\n028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;;\n028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;;\n0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;;\n0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;;\n0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7\n0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;;\n0294;LATIN LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;;\n0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Lo;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;;\n0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;;\n0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;;\n0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;;\n0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;;\n029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;;\n029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;;\n029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;;\n029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;A7B2;;A7B2\n029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;A7B0;;A7B0\n029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;;\n02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;;\n02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;;\n02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;;\n02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;;\n02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;;\n02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;;\n02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;;\n02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;;\n02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;;\n02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;;\n02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;;\n02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;;\n02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;\n02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;\n02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK;Ll;0;L;;;;;N;;;;;\n02AF;LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL;Ll;0;L;;;;;N;;;;;\n02B0;MODIFIER LETTER SMALL H;Lm;0;L;<super> 0068;;;;N;;;;;\n02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L;<super> 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;;\n02B2;MODIFIER LETTER SMALL J;Lm;0;L;<super> 006A;;;;N;;;;;\n02B3;MODIFIER LETTER SMALL R;Lm;0;L;<super> 0072;;;;N;;;;;\n02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L;<super> 0279;;;;N;;;;;\n02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L;<super> 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;;\n02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L;<super> 0281;;;;N;;;;;\n02B7;MODIFIER LETTER SMALL W;Lm;0;L;<super> 0077;;;;N;;;;;\n02B8;MODIFIER LETTER SMALL Y;Lm;0;L;<super> 0079;;;;N;;;;;\n02B9;MODIFIER LETTER PRIME;Lm;0;ON;;;;;N;;;;;\n02BA;MODIFIER LETTER DOUBLE PRIME;Lm;0;ON;;;;;N;;;;;\n02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;;\n02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;;\n02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;;\n02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;;\n02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;\n02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;;\n02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;;\n02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;\n02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;\n02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;\n02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;\n02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;;\n02C7;CARON;Lm;0;ON;;;;;N;MODIFIER LETTER HACEK;;;;\n02C8;MODIFIER LETTER VERTICAL LINE;Lm;0;ON;;;;;N;;;;;\n02C9;MODIFIER LETTER MACRON;Lm;0;ON;;;;;N;;;;;\n02CA;MODIFIER LETTER ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER ACUTE;;;;\n02CB;MODIFIER LETTER GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER GRAVE;;;;\n02CC;MODIFIER LETTER LOW VERTICAL LINE;Lm;0;ON;;;;;N;;;;;\n02CD;MODIFIER LETTER LOW MACRON;Lm;0;ON;;;;;N;;;;;\n02CE;MODIFIER LETTER LOW GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;;\n02CF;MODIFIER LETTER LOW ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;;\n02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;\n02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;\n02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;;\n02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;;\n02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;;\n02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;;\n02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;;\n02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;;\n02D8;BREVE;Sk;0;ON;<compat> 0020 0306;;;;N;SPACING BREVE;;;;\n02D9;DOT ABOVE;Sk;0;ON;<compat> 0020 0307;;;;N;SPACING DOT ABOVE;;;;\n02DA;RING ABOVE;Sk;0;ON;<compat> 0020 030A;;;;N;SPACING RING ABOVE;;;;\n02DB;OGONEK;Sk;0;ON;<compat> 0020 0328;;;;N;SPACING OGONEK;;;;\n02DC;SMALL TILDE;Sk;0;ON;<compat> 0020 0303;;;;N;SPACING TILDE;;;;\n02DD;DOUBLE ACUTE ACCENT;Sk;0;ON;<compat> 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;;\n02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;;\n02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;;\n02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L;<super> 0263;;;;N;;;;;\n02E1;MODIFIER LETTER SMALL L;Lm;0;L;<super> 006C;;;;N;;;;;\n02E2;MODIFIER LETTER SMALL S;Lm;0;L;<super> 0073;;;;N;;;;;\n02E3;MODIFIER LETTER SMALL X;Lm;0;L;<super> 0078;;;;N;;;;;\n02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L;<super> 0295;;;;N;;;;;\n02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;\n02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;\n02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;;\n02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;;\n02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;;\n02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;\n02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;\n02EC;MODIFIER LETTER VOICING;Lm;0;ON;;;;;N;;;;;\n02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;;\n02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;;\n02EF;MODIFIER LETTER LOW DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;\n02F0;MODIFIER LETTER LOW UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;\n02F1;MODIFIER LETTER LOW LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;\n02F2;MODIFIER LETTER LOW RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;\n02F3;MODIFIER LETTER LOW RING;Sk;0;ON;;;;;N;;;;;\n02F4;MODIFIER LETTER MIDDLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;;\n02F5;MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;;\n02F6;MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT;Sk;0;ON;;;;;N;;;;;\n02F7;MODIFIER LETTER LOW TILDE;Sk;0;ON;;;;;N;;;;;\n02F8;MODIFIER LETTER RAISED COLON;Sk;0;ON;;;;;N;;;;;\n02F9;MODIFIER LETTER BEGIN HIGH TONE;Sk;0;ON;;;;;N;;;;;\n02FA;MODIFIER LETTER END HIGH TONE;Sk;0;ON;;;;;N;;;;;\n02FB;MODIFIER LETTER BEGIN LOW TONE;Sk;0;ON;;;;;N;;;;;\n02FC;MODIFIER LETTER END LOW TONE;Sk;0;ON;;;;;N;;;;;\n02FD;MODIFIER LETTER SHELF;Sk;0;ON;;;;;N;;;;;\n02FE;MODIFIER LETTER OPEN SHELF;Sk;0;ON;;;;;N;;;;;\n02FF;MODIFIER LETTER LOW LEFT ARROW;Sk;0;ON;;;;;N;;;;;\n0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;;;;\n0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;;;;\n0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;;\n0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;;\n0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;;\n0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;;\n0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;;;;\n0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;;\n0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;;;;\n0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;;\n030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;;\n030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;;\n030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;;\n030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;;;;\n030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;;\n030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;;\n0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;;\n0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;;\n0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;;\n0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;;;;\n0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;;;;\n0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;;\n0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;;\n0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;;\n0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;;\n0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;;\n031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;;\n031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;;\n031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;;\n031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;;\n031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;;\n031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;;\n0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;;\n0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;;\n0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;;\n0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;;\n0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;;\n0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;;\n0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;;\n0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;;\n0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;;\n0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;;\n032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;;\n032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;;\n032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;;\n032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;;\n032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;;\n032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;;\n0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;;\n0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;;\n0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;;\n0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;;\n0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;;\n0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;;\n0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;;\n0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;;\n0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;;\n0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;;\n033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;;\n033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;;\n033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;;\n033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;;\n033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;;\n033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;;\n0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;;;;\n0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;;;;\n0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;;\n0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;;\n0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;;\n0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399\n0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;\n0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;;\n0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;;\n0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;;\n034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;;\n034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;;\n034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;;\n034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;\n034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;;\n034F;COMBINING GRAPHEME JOINER;Mn;0;NSM;;;;;N;;;;;\n0350;COMBINING RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;\n0351;COMBINING LEFT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;;\n0352;COMBINING FERMATA;Mn;230;NSM;;;;;N;;;;;\n0353;COMBINING X BELOW;Mn;220;NSM;;;;;N;;;;;\n0354;COMBINING LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;\n0355;COMBINING RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;\n0356;COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;\n0357;COMBINING RIGHT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;;\n0358;COMBINING DOT ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;;\n0359;COMBINING ASTERISK BELOW;Mn;220;NSM;;;;;N;;;;;\n035A;COMBINING DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;;\n035B;COMBINING ZIGZAG ABOVE;Mn;230;NSM;;;;;N;;;;;\n035C;COMBINING DOUBLE BREVE BELOW;Mn;233;NSM;;;;;N;;;;;\n035D;COMBINING DOUBLE BREVE;Mn;234;NSM;;;;;N;;;;;\n035E;COMBINING DOUBLE MACRON;Mn;234;NSM;;;;;N;;;;;\n035F;COMBINING DOUBLE MACRON BELOW;Mn;233;NSM;;;;;N;;;;;\n0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;;\n0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;;\n0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;;\n0363;COMBINING LATIN SMALL LETTER A;Mn;230;NSM;;;;;N;;;;;\n0364;COMBINING LATIN SMALL LETTER E;Mn;230;NSM;;;;;N;;;;;\n0365;COMBINING LATIN SMALL LETTER I;Mn;230;NSM;;;;;N;;;;;\n0366;COMBINING LATIN SMALL LETTER O;Mn;230;NSM;;;;;N;;;;;\n0367;COMBINING LATIN SMALL LETTER U;Mn;230;NSM;;;;;N;;;;;\n0368;COMBINING LATIN SMALL LETTER C;Mn;230;NSM;;;;;N;;;;;\n0369;COMBINING LATIN SMALL LETTER D;Mn;230;NSM;;;;;N;;;;;\n036A;COMBINING LATIN SMALL LETTER H;Mn;230;NSM;;;;;N;;;;;\n036B;COMBINING LATIN SMALL LETTER M;Mn;230;NSM;;;;;N;;;;;\n036C;COMBINING LATIN SMALL LETTER R;Mn;230;NSM;;;;;N;;;;;\n036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;;\n036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;;\n036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;;\n0370;GREEK CAPITAL LETTER HETA;Lu;0;L;;;;;N;;;;0371;\n0371;GREEK SMALL LETTER HETA;Ll;0;L;;;;;N;;;0370;;0370\n0372;GREEK CAPITAL LETTER ARCHAIC SAMPI;Lu;0;L;;;;;N;;;;0373;\n0373;GREEK SMALL LETTER ARCHAIC SAMPI;Ll;0;L;;;;;N;;;0372;;0372\n0374;GREEK NUMERAL SIGN;Lm;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;;;;\n0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;;;;\n0376;GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA;Lu;0;L;;;;;N;;;;0377;\n0377;GREEK SMALL LETTER PAMPHYLIAN DIGAMMA;Ll;0;L;;;;;N;;;0376;;0376\n037A;GREEK YPOGEGRAMMENI;Lm;0;L;<compat> 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;;\n037B;GREEK SMALL REVERSED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FD;;03FD\n037C;GREEK SMALL DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FE;;03FE\n037D;GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FF;;03FF\n037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;;;;\n037F;GREEK CAPITAL LETTER YOT;Lu;0;L;;;;;N;;;;03F3;\n0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;;\n0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;;\n0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC;\n0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;;\n0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD;\n0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE;\n038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF;\n038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC;\n038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD;\n038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE;\n0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;;\n0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1;\n0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2;\n0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3;\n0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4;\n0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5;\n0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6;\n0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7;\n0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;\n0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9;\n039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA;\n039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB;\n039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC;\n039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD;\n039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE;\n039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF;\n03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0;\n03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1;\n03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3;\n03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4;\n03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5;\n03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6;\n03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7;\n03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8;\n03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9;\n03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA;\n03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB;\n03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386\n03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388\n03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389\n03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A\n03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;;\n03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391\n03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392\n03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393\n03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394\n03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395\n03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396\n03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397\n03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398\n03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399\n03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A\n03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B\n03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C\n03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D\n03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E\n03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F\n03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0\n03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1\n03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3\n03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3\n03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4\n03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5\n03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6\n03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7\n03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8\n03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9\n03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA\n03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB\n03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C\n03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E\n03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F\n03CF;GREEK CAPITAL KAI SYMBOL;Lu;0;L;;;;;N;;;;03D7;\n03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392\n03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398\n03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L;<compat> 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;;\n03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;;\n03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;;\n03D5;GREEK PHI SYMBOL;Ll;0;L;<compat> 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6\n03D6;GREEK PI SYMBOL;Ll;0;L;<compat> 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0\n03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;03CF;;03CF\n03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;;;03D9;\n03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;;03D8;;03D8\n03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB;\n03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA\n03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD;\n03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC\n03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF;\n03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE\n03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1;\n03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0\n03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3;\n03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2\n03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5;\n03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4\n03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7;\n03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6\n03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9;\n03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8\n03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB;\n03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA\n03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED;\n03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC\n03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF;\n03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE\n03F0;GREEK KAPPA SYMBOL;Ll;0;L;<compat> 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A\n03F1;GREEK RHO SYMBOL;Ll;0;L;<compat> 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1\n03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L;<compat> 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03F9;;03F9\n03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;037F;;037F\n03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;\n03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L;<compat> 03B5;;;;N;;;0395;;0395\n03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;;\n03F7;GREEK CAPITAL LETTER SHO;Lu;0;L;;;;;N;;;;03F8;\n03F8;GREEK SMALL LETTER SHO;Ll;0;L;;;;;N;;;03F7;;03F7\n03F9;GREEK CAPITAL LUNATE SIGMA SYMBOL;Lu;0;L;<compat> 03A3;;;;N;;;;03F2;\n03FA;GREEK CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;03FB;\n03FB;GREEK SMALL LETTER SAN;Ll;0;L;;;;;N;;;03FA;;03FA\n03FC;GREEK RHO WITH STROKE SYMBOL;Ll;0;L;;;;;N;;;;;\n03FD;GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037B;\n03FE;GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037C;\n03FF;GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037D;\n0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450;\n0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451;\n0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;;;0452;\n0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453;\n0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454;\n0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455;\n0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456;\n0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;;;0457;\n0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458;\n0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459;\n040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A;\n040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;;;045B;\n040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C;\n040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D;\n040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;;;045E;\n040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F;\n0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430;\n0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431;\n0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432;\n0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433;\n0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434;\n0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435;\n0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436;\n0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437;\n0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438;\n0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439;\n041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A;\n041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B;\n041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C;\n041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D;\n041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E;\n041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F;\n0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440;\n0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441;\n0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442;\n0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443;\n0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444;\n0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445;\n0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446;\n0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447;\n0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448;\n0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449;\n042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A;\n042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B;\n042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C;\n042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D;\n042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E;\n042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F;\n0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410\n0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411\n0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412\n0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413\n0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414\n0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415\n0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416\n0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417\n0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418\n0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419\n043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A\n043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B\n043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C\n043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D\n043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E\n043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F\n0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420\n0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421\n0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422\n0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423\n0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424\n0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425\n0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426\n0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427\n0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428\n0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429\n044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A\n044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B\n044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C\n044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D\n044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E\n044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F\n0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400\n0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401\n0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;;0402;;0402\n0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403\n0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404\n0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405\n0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406\n0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;;0407;;0407\n0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408\n0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409\n045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A\n045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;;040B;;040B\n045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C\n045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D\n045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;;040E;;040E\n045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F\n0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461;\n0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460\n0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463;\n0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462\n0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465;\n0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464\n0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467;\n0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466\n0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469;\n0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468\n046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B;\n046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A\n046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D;\n046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C\n046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F;\n046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E\n0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471;\n0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470\n0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473;\n0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472\n0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475;\n0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474\n0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477;\n0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476\n0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479;\n0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478\n047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B;\n047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A\n047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D;\n047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C\n047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F;\n047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E\n0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481;\n0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480\n0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;;\n0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;;\n0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;;\n0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;;\n0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;;\n0487;COMBINING CYRILLIC POKRYTIE;Mn;230;NSM;;;;;N;;;;;\n0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;;\n0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;\n048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B;\n048B;CYRILLIC SMALL LETTER SHORT I WITH TAIL;Ll;0;L;;;;;N;;;048A;;048A\n048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D;\n048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C\n048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F;\n048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E\n0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491;\n0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490\n0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493;\n0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492\n0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495;\n0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494\n0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497;\n0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496\n0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499;\n0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498\n049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B;\n049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A\n049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D;\n049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C\n049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F;\n049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E\n04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1;\n04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0\n04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3;\n04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2\n04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5;\n04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4\n04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;;;04A7;\n04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;;04A6;;04A6\n04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9;\n04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8\n04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB;\n04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA\n04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD;\n04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC\n04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF;\n04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE\n04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1;\n04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0\n04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3;\n04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2\n04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;;;04B5;\n04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;;04B4;;04B4\n04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7;\n04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6\n04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9;\n04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8\n04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB;\n04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA\n04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD;\n04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC\n04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF;\n04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE\n04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;04CF;\n04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2;\n04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1\n04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4;\n04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3\n04C5;CYRILLIC CAPITAL LETTER EL WITH TAIL;Lu;0;L;;;;;N;;;;04C6;\n04C6;CYRILLIC SMALL LETTER EL WITH TAIL;Ll;0;L;;;;;N;;;04C5;;04C5\n04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8;\n04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7\n04C9;CYRILLIC CAPITAL LETTER EN WITH TAIL;Lu;0;L;;;;;N;;;;04CA;\n04CA;CYRILLIC SMALL LETTER EN WITH TAIL;Ll;0;L;;;;;N;;;04C9;;04C9\n04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC;\n04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB\n04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE;\n04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD\n04CF;CYRILLIC SMALL LETTER PALOCHKA;Ll;0;L;;;;;N;;;04C0;;04C0\n04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1;\n04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0\n04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3;\n04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2\n04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5;\n04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4\n04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7;\n04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6\n04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9;\n04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8\n04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB;\n04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA\n04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD;\n04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC\n04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF;\n04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE\n04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1;\n04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0\n04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3;\n04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2\n04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5;\n04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4\n04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7;\n04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6\n04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9;\n04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8\n04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB;\n04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA\n04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED;\n04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC\n04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF;\n04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE\n04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1;\n04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0\n04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3;\n04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2\n04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5;\n04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4\n04F6;CYRILLIC CAPITAL LETTER GHE WITH DESCENDER;Lu;0;L;;;;;N;;;;04F7;\n04F7;CYRILLIC SMALL LETTER GHE WITH DESCENDER;Ll;0;L;;;;;N;;;04F6;;04F6\n04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9;\n04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8\n04FA;CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK;Lu;0;L;;;;;N;;;;04FB;\n04FB;CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK;Ll;0;L;;;;;N;;;04FA;;04FA\n04FC;CYRILLIC CAPITAL LETTER HA WITH HOOK;Lu;0;L;;;;;N;;;;04FD;\n04FD;CYRILLIC SMALL LETTER HA WITH HOOK;Ll;0;L;;;;;N;;;04FC;;04FC\n04FE;CYRILLIC CAPITAL LETTER HA WITH STROKE;Lu;0;L;;;;;N;;;;04FF;\n04FF;CYRILLIC SMALL LETTER HA WITH STROKE;Ll;0;L;;;;;N;;;04FE;;04FE\n0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501;\n0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500\n0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503;\n0503;CYRILLIC SMALL LETTER KOMI DJE;Ll;0;L;;;;;N;;;0502;;0502\n0504;CYRILLIC CAPITAL LETTER KOMI ZJE;Lu;0;L;;;;;N;;;;0505;\n0505;CYRILLIC SMALL LETTER KOMI ZJE;Ll;0;L;;;;;N;;;0504;;0504\n0506;CYRILLIC CAPITAL LETTER KOMI DZJE;Lu;0;L;;;;;N;;;;0507;\n0507;CYRILLIC SMALL LETTER KOMI DZJE;Ll;0;L;;;;;N;;;0506;;0506\n0508;CYRILLIC CAPITAL LETTER KOMI LJE;Lu;0;L;;;;;N;;;;0509;\n0509;CYRILLIC SMALL LETTER KOMI LJE;Ll;0;L;;;;;N;;;0508;;0508\n050A;CYRILLIC CAPITAL LETTER KOMI NJE;Lu;0;L;;;;;N;;;;050B;\n050B;CYRILLIC SMALL LETTER KOMI NJE;Ll;0;L;;;;;N;;;050A;;050A\n050C;CYRILLIC CAPITAL LETTER KOMI SJE;Lu;0;L;;;;;N;;;;050D;\n050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C\n050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F;\n050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E\n0510;CYRILLIC CAPITAL LETTER REVERSED ZE;Lu;0;L;;;;;N;;;;0511;\n0511;CYRILLIC SMALL LETTER REVERSED ZE;Ll;0;L;;;;;N;;;0510;;0510\n0512;CYRILLIC CAPITAL LETTER EL WITH HOOK;Lu;0;L;;;;;N;;;;0513;\n0513;CYRILLIC SMALL LETTER EL WITH HOOK;Ll;0;L;;;;;N;;;0512;;0512\n0514;CYRILLIC CAPITAL LETTER LHA;Lu;0;L;;;;;N;;;;0515;\n0515;CYRILLIC SMALL LETTER LHA;Ll;0;L;;;;;N;;;0514;;0514\n0516;CYRILLIC CAPITAL LETTER RHA;Lu;0;L;;;;;N;;;;0517;\n0517;CYRILLIC SMALL LETTER RHA;Ll;0;L;;;;;N;;;0516;;0516\n0518;CYRILLIC CAPITAL LETTER YAE;Lu;0;L;;;;;N;;;;0519;\n0519;CYRILLIC SMALL LETTER YAE;Ll;0;L;;;;;N;;;0518;;0518\n051A;CYRILLIC CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;051B;\n051B;CYRILLIC SMALL LETTER QA;Ll;0;L;;;;;N;;;051A;;051A\n051C;CYRILLIC CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;051D;\n051D;CYRILLIC SMALL LETTER WE;Ll;0;L;;;;;N;;;051C;;051C\n051E;CYRILLIC CAPITAL LETTER ALEUT KA;Lu;0;L;;;;;N;;;;051F;\n051F;CYRILLIC SMALL LETTER ALEUT KA;Ll;0;L;;;;;N;;;051E;;051E\n0520;CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0521;\n0521;CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0520;;0520\n0522;CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0523;\n0523;CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0522;;0522\n0524;CYRILLIC CAPITAL LETTER PE WITH DESCENDER;Lu;0;L;;;;;N;;;;0525;\n0525;CYRILLIC SMALL LETTER PE WITH DESCENDER;Ll;0;L;;;;;N;;;0524;;0524\n0526;CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER;Lu;0;L;;;;;N;;;;0527;\n0527;CYRILLIC SMALL LETTER SHHA WITH DESCENDER;Ll;0;L;;;;;N;;;0526;;0526\n0528;CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK;Lu;0;L;;;;;N;;;;0529;\n0529;CYRILLIC SMALL LETTER EN WITH LEFT HOOK;Ll;0;L;;;;;N;;;0528;;0528\n052A;CYRILLIC CAPITAL LETTER DZZHE;Lu;0;L;;;;;N;;;;052B;\n052B;CYRILLIC SMALL LETTER DZZHE;Ll;0;L;;;;;N;;;052A;;052A\n052C;CYRILLIC CAPITAL LETTER DCHE;Lu;0;L;;;;;N;;;;052D;\n052D;CYRILLIC SMALL LETTER DCHE;Ll;0;L;;;;;N;;;052C;;052C\n052E;CYRILLIC CAPITAL LETTER EL WITH DESCENDER;Lu;0;L;;;;;N;;;;052F;\n052F;CYRILLIC SMALL LETTER EL WITH DESCENDER;Ll;0;L;;;;;N;;;052E;;052E\n0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561;\n0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562;\n0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563;\n0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564;\n0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565;\n0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566;\n0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567;\n0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568;\n0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569;\n053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A;\n053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B;\n053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C;\n053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D;\n053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E;\n053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F;\n0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570;\n0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571;\n0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572;\n0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573;\n0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574;\n0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575;\n0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576;\n0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577;\n0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578;\n0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579;\n054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A;\n054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B;\n054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C;\n054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D;\n054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E;\n054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F;\n0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580;\n0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581;\n0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582;\n0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583;\n0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584;\n0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585;\n0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586;\n0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;\n055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;;\n055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;;\n055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;;\n055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;;\n055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;;\n055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;;\n0560;ARMENIAN SMALL LETTER TURNED AYB;Ll;0;L;;;;;N;;;;;\n0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531\n0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532\n0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533\n0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534\n0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535\n0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536\n0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537\n0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538\n0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539\n056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A\n056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B\n056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C\n056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D\n056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E\n056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F\n0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540\n0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541\n0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542\n0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543\n0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544\n0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545\n0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546\n0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547\n0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548\n0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549\n057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A\n057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B\n057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C\n057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D\n057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E\n057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F\n0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550\n0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551\n0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552\n0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553\n0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554\n0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555\n0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556\n0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;;\n0588;ARMENIAN SMALL LETTER YI WITH STROKE;Ll;0;L;;;;;N;;;;;\n0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;;\n058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;;\n058D;RIGHT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;;\n058E;LEFT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;;\n058F;ARMENIAN DRAM SIGN;Sc;0;ET;;;;;N;;;;;\n0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;;\n0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;;\n0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;;\n0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;;\n0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;;\n0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;;;;\n0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;;\n0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;;;;\n0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;;\n059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;;\n059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;;\n059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;;\n059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;;\n059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;;\n059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;;\n05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;;\n05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;;\n05A2;HEBREW ACCENT ATNAH HAFUKH;Mn;220;NSM;;;;;N;;;;;\n05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;;\n05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;;\n05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;;;;\n05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;;\n05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;;\n05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;;;;\n05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;;\n05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;;;;\n05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;;\n05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;;\n05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;;\n05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;;\n05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;;\n05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;;\n05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;;\n05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;;\n05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;;\n05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;;\n05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;;\n05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;;\n05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;;\n05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;;\n05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;;\n05BA;HEBREW POINT HOLAM HASER FOR VAV;Mn;19;NSM;;;;;N;;;;;\n05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;;\n05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;;;;\n05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;;;;\n05BE;HEBREW PUNCTUATION MAQAF;Pd;0;R;;;;;N;;;;;\n05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;;\n05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;;;;\n05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;;\n05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;;\n05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;;;;\n05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;;\n05C5;HEBREW MARK LOWER DOT;Mn;220;NSM;;;;;N;;;;;\n05C6;HEBREW PUNCTUATION NUN HAFUKHA;Po;0;R;;;;;N;;;;;\n05C7;HEBREW POINT QAMATS QATAN;Mn;18;NSM;;;;;N;;;;;\n05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;;\n05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;;\n05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;;\n05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;;\n05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;;\n05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;;\n05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;;\n05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;;\n05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;;\n05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;;\n05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;;\n05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;;\n05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;;\n05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;\n05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;;\n05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;;\n05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;;\n05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;;\n05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;;\n05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;;\n05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;;\n05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;;\n05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;;\n05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;;\n05EF;HEBREW YOD TRIANGLE;Lo;0;R;;;;;N;;;;;\n05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;;\n05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;;\n05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;;\n05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;;\n05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;;\n0600;ARABIC NUMBER SIGN;Cf;0;AN;;;;;N;;;;;\n0601;ARABIC SIGN SANAH;Cf;0;AN;;;;;N;;;;;\n0602;ARABIC FOOTNOTE MARKER;Cf;0;AN;;;;;N;;;;;\n0603;ARABIC SIGN SAFHA;Cf;0;AN;;;;;N;;;;;\n0604;ARABIC SIGN SAMVAT;Cf;0;AN;;;;;N;;;;;\n0605;ARABIC NUMBER MARK ABOVE;Cf;0;AN;;;;;N;;;;;\n0606;ARABIC-INDIC CUBE ROOT;Sm;0;ON;;;;;N;;;;;\n0607;ARABIC-INDIC FOURTH ROOT;Sm;0;ON;;;;;N;;;;;\n0608;ARABIC RAY;Sm;0;AL;;;;;N;;;;;\n0609;ARABIC-INDIC PER MILLE SIGN;Po;0;ET;;;;;N;;;;;\n060A;ARABIC-INDIC PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;;\n060B;AFGHANI SIGN;Sc;0;AL;;;;;N;;;;;\n060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;;\n060D;ARABIC DATE SEPARATOR;Po;0;AL;;;;;N;;;;;\n060E;ARABIC POETIC VERSE SIGN;So;0;ON;;;;;N;;;;;\n060F;ARABIC SIGN MISRA;So;0;ON;;;;;N;;;;;\n0610;ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM;Mn;230;NSM;;;;;N;;;;;\n0611;ARABIC SIGN ALAYHE ASSALLAM;Mn;230;NSM;;;;;N;;;;;\n0612;ARABIC SIGN RAHMATULLAH ALAYHE;Mn;230;NSM;;;;;N;;;;;\n0613;ARABIC SIGN RADI ALLAHOU ANHU;Mn;230;NSM;;;;;N;;;;;\n0614;ARABIC SIGN TAKHALLUS;Mn;230;NSM;;;;;N;;;;;\n0615;ARABIC SMALL HIGH TAH;Mn;230;NSM;;;;;N;;;;;\n0616;ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH;Mn;230;NSM;;;;;N;;;;;\n0617;ARABIC SMALL HIGH ZAIN;Mn;230;NSM;;;;;N;;;;;\n0618;ARABIC SMALL FATHA;Mn;30;NSM;;;;;N;;;;;\n0619;ARABIC SMALL DAMMA;Mn;31;NSM;;;;;N;;;;;\n061A;ARABIC SMALL KASRA;Mn;32;NSM;;;;;N;;;;;\n061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;;\n061C;ARABIC LETTER MARK;Cf;0;AL;;;;;N;;;;;\n061D;ARABIC END OF TEXT MARK;Po;0;AL;;;;;N;;;;;\n061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;;\n061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;;\n0620;ARABIC LETTER KASHMIRI YEH;Lo;0;AL;;;;;N;;;;;\n0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;;\n0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;;\n0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;;\n0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;;\n0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;;\n0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;;\n0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;;\n0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;;\n0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;;\n062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;;\n062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;;\n062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;;\n062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;;\n062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;;\n062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;;\n0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;;\n0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;;\n0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;\n0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;;\n0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;;\n0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;;\n0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;;\n0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;;\n0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;;\n0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;;\n063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;;\n063B;ARABIC LETTER KEHEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n063C;ARABIC LETTER KEHEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n063D;ARABIC LETTER FARSI YEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;\n063E;ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n063F;ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;;\n0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;;\n0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;;\n0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;;\n0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;;\n0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;;\n0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;;\n0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;;\n0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;;\n0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;;\n064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;;\n064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;;\n064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;;\n064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;;\n064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;;\n064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;;\n0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;;\n0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;;\n0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;;\n0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;;\n0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;;\n0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;;\n0656;ARABIC SUBSCRIPT ALEF;Mn;220;NSM;;;;;N;;;;;\n0657;ARABIC INVERTED DAMMA;Mn;230;NSM;;;;;N;;;;;\n0658;ARABIC MARK NOON GHUNNA;Mn;230;NSM;;;;;N;;;;;\n0659;ARABIC ZWARAKAY;Mn;230;NSM;;;;;N;;;;;\n065A;ARABIC VOWEL SIGN SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;;\n065B;ARABIC VOWEL SIGN INVERTED SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;;\n065C;ARABIC VOWEL SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;\n065D;ARABIC REVERSED DAMMA;Mn;230;NSM;;;;;N;;;;;\n065E;ARABIC FATHA WITH TWO DOTS;Mn;230;NSM;;;;;N;;;;;\n065F;ARABIC WAVY HAMZA BELOW;Mn;220;NSM;;;;;N;;;;;\n0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;\n0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;\n0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;\n0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;\n0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;\n0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;\n0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;\n0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;\n0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;\n0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;\n066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;;\n066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;;\n066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;;\n066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;;\n066E;ARABIC LETTER DOTLESS BEH;Lo;0;AL;;;;;N;;;;;\n066F;ARABIC LETTER DOTLESS QAF;Lo;0;AL;;;;;N;;;;;\n0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;;\n0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;;\n0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;;\n0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;;\n0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;;\n0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL;<compat> 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;;\n0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL;<compat> 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;;\n0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL;<compat> 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;;\n0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL;<compat> 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;;\n0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;;\n067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;;\n067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;;\n067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;;\n067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;;\n067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;;\n067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;;\n0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;;\n0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;;\n0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;;\n0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;;\n0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;;\n0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;;\n0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;;\n0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;;\n0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;;\n0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;;\n068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;\n068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;;\n068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;;\n068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;;\n068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;;\n0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;;\n0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;;\n0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;;\n0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;;\n0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;;\n0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;;\n0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;;\n0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;;\n0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;;\n069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;;\n06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;;\n06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;;\n06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;;\n06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;;\n06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;;\n06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;;\n06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;;\n06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;;\n06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;;\n06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;;\n06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;;\n06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;;;;\n06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;;\n06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;;\n06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;;\n06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;;\n06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;;\n06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;;\n06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;;\n06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;;\n06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;;\n06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;;\n06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;;\n06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;;\n06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;;\n06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;;\n06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;;\n06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;;\n06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;;\n06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;;\n06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;;\n06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;;\n06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;;\n06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;;\n06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;;;;\n06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;;\n06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;;\n06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;;\n06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;;\n06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;;\n06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;\n06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;\n06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;;\n06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;;\n06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;;\n06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;;\n06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;;\n06DD;ARABIC END OF AYAH;Cf;0;AN;;;;;N;;;;;\n06DE;ARABIC START OF RUB EL HIZB;So;0;ON;;;;;N;;;;;\n06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;;\n06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;;\n06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;;\n06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;;\n06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;;\n06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;;\n06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;;\n06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;;\n06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;;\n06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;;\n06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;;\n06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;;\n06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;;\n06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;;\n06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;;\n06EE;ARABIC LETTER DAL WITH INVERTED V;Lo;0;AL;;;;;N;;;;;\n06EF;ARABIC LETTER REH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;\n06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;;\n06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;;\n06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;;\n06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;;\n06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;;\n06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;;\n06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;;\n06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;;\n06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;;\n06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;;\n06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;;\n06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;;\n06FF;ARABIC LETTER HEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;\n0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;;\n0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;;\n0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;;\n0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;;\n0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;;\n0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;;\n0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;\n0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;\n0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;\n0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;\n070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;;\n070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;;\n070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;;\n070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;;\n070F;SYRIAC ABBREVIATION MARK;Cf;0;AL;;;;;N;;;;;\n0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;;\n0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;;\n0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;;\n0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;;\n0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;;\n0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;;\n0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;;\n0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;;\n0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;;\n0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;\n071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;;\n071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;;\n071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;;\n071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;;\n071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;;\n071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;;\n0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;;\n0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;;\n0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;;\n0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;;\n0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;;\n0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;;\n0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;;\n0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;;\n0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;;\n0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;;\n072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;;\n072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;;\n072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;;\n072D;SYRIAC LETTER PERSIAN BHETH;Lo;0;AL;;;;;N;;;;;\n072E;SYRIAC LETTER PERSIAN GHAMAL;Lo;0;AL;;;;;N;;;;;\n072F;SYRIAC LETTER PERSIAN DHALATH;Lo;0;AL;;;;;N;;;;;\n0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;;\n0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;;\n0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;;\n0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;;\n0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;;\n0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;;\n0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;;\n0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;;\n0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;;\n0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;;\n073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;;\n073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;;\n073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;;\n073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;;\n073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;;\n073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;;\n0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;;\n0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;;\n0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;;\n0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;\n0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;;\n0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;\n0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;;\n0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;;\n0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;;\n0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;;\n074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;;\n074D;SYRIAC LETTER SOGDIAN ZHAIN;Lo;0;AL;;;;;N;;;;;\n074E;SYRIAC LETTER SOGDIAN KHAPH;Lo;0;AL;;;;;N;;;;;\n074F;SYRIAC LETTER SOGDIAN FE;Lo;0;AL;;;;;N;;;;;\n0750;ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW;Lo;0;AL;;;;;N;;;;;\n0751;ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n0752;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;\n0753;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n0754;ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n0755;ARABIC LETTER BEH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;\n0756;ARABIC LETTER BEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;\n0757;ARABIC LETTER HAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n0758;ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;\n0759;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;\n075A;ARABIC LETTER DAL WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;\n075B;ARABIC LETTER REH WITH STROKE;Lo;0;AL;;;;;N;;;;;\n075C;ARABIC LETTER SEEN WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n075D;ARABIC LETTER AIN WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n075E;ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE;Lo;0;AL;;;;;N;;;;;\n075F;ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;\n0760;ARABIC LETTER FEH WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n0761;ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;\n0762;ARABIC LETTER KEHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n0763;ARABIC LETTER KEHEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n0764;ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;\n0765;ARABIC LETTER MEEM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n0766;ARABIC LETTER MEEM WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n0767;ARABIC LETTER NOON WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n0768;ARABIC LETTER NOON WITH SMALL TAH;Lo;0;AL;;;;;N;;;;;\n0769;ARABIC LETTER NOON WITH SMALL V;Lo;0;AL;;;;;N;;;;;\n076A;ARABIC LETTER LAM WITH BAR;Lo;0;AL;;;;;N;;;;;\n076B;ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;\n076C;ARABIC LETTER REH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;\n076D;ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;\n076E;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW;Lo;0;AL;;;;;N;;;;;\n076F;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;;\n0770;ARABIC LETTER SEEN WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;;\n0771;ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;;\n0772;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;;\n0773;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;;\n0774;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;;\n0775;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;;\n0776;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;;\n0777;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;;\n0778;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;;\n0779;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;;\n077A;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;;\n077B;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;;\n077C;ARABIC LETTER HAH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;;\n077D;ARABIC LETTER SEEN WITH EXTENDED ARABIC-INDIC DIGIT FOUR ABOVE;Lo;0;AL;;;;;N;;;;;\n077E;ARABIC LETTER SEEN WITH INVERTED V;Lo;0;AL;;;;;N;;;;;\n077F;ARABIC LETTER KAF WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;;\n0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;;\n0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;;\n0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;;\n0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;;\n0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;;\n0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;;\n0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;;\n0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;;\n0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;;\n078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;;\n078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;;\n078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;;\n078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;;\n078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;;\n078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;;\n0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;;\n0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;;\n0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;;\n0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;;\n0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;;\n0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;;\n0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;;\n0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;;\n0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;;\n0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;;\n079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;;\n079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;;\n079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;;\n079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;;\n079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;;\n079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;;\n07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;;\n07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;;\n07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;;\n07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;;\n07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;;\n07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;;\n07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;;\n07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;;\n07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;;\n07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;;\n07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;;\n07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;;\n07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;;\n07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;;\n07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;;\n07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;;\n07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;;\n07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;;\n07C0;NKO DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;;\n07C1;NKO DIGIT ONE;Nd;0;R;;1;1;1;N;;;;;\n07C2;NKO DIGIT TWO;Nd;0;R;;2;2;2;N;;;;;\n07C3;NKO DIGIT THREE;Nd;0;R;;3;3;3;N;;;;;\n07C4;NKO DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;;\n07C5;NKO DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;;\n07C6;NKO DIGIT SIX;Nd;0;R;;6;6;6;N;;;;;\n07C7;NKO DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;;\n07C8;NKO DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;;\n07C9;NKO DIGIT NINE;Nd;0;R;;9;9;9;N;;;;;\n07CA;NKO LETTER A;Lo;0;R;;;;;N;;;;;\n07CB;NKO LETTER EE;Lo;0;R;;;;;N;;;;;\n07CC;NKO LETTER I;Lo;0;R;;;;;N;;;;;\n07CD;NKO LETTER E;Lo;0;R;;;;;N;;;;;\n07CE;NKO LETTER U;Lo;0;R;;;;;N;;;;;\n07CF;NKO LETTER OO;Lo;0;R;;;;;N;;;;;\n07D0;NKO LETTER O;Lo;0;R;;;;;N;;;;;\n07D1;NKO LETTER DAGBASINNA;Lo;0;R;;;;;N;;;;;\n07D2;NKO LETTER N;Lo;0;R;;;;;N;;;;;\n07D3;NKO LETTER BA;Lo;0;R;;;;;N;;;;;\n07D4;NKO LETTER PA;Lo;0;R;;;;;N;;;;;\n07D5;NKO LETTER TA;Lo;0;R;;;;;N;;;;;\n07D6;NKO LETTER JA;Lo;0;R;;;;;N;;;;;\n07D7;NKO LETTER CHA;Lo;0;R;;;;;N;;;;;\n07D8;NKO LETTER DA;Lo;0;R;;;;;N;;;;;\n07D9;NKO LETTER RA;Lo;0;R;;;;;N;;;;;\n07DA;NKO LETTER RRA;Lo;0;R;;;;;N;;;;;\n07DB;NKO LETTER SA;Lo;0;R;;;;;N;;;;;\n07DC;NKO LETTER GBA;Lo;0;R;;;;;N;;;;;\n07DD;NKO LETTER FA;Lo;0;R;;;;;N;;;;;\n07DE;NKO LETTER KA;Lo;0;R;;;;;N;;;;;\n07DF;NKO LETTER LA;Lo;0;R;;;;;N;;;;;\n07E0;NKO LETTER NA WOLOSO;Lo;0;R;;;;;N;;;;;\n07E1;NKO LETTER MA;Lo;0;R;;;;;N;;;;;\n07E2;NKO LETTER NYA;Lo;0;R;;;;;N;;;;;\n07E3;NKO LETTER NA;Lo;0;R;;;;;N;;;;;\n07E4;NKO LETTER HA;Lo;0;R;;;;;N;;;;;\n07E5;NKO LETTER WA;Lo;0;R;;;;;N;;;;;\n07E6;NKO LETTER YA;Lo;0;R;;;;;N;;;;;\n07E7;NKO LETTER NYA WOLOSO;Lo;0;R;;;;;N;;;;;\n07E8;NKO LETTER JONA JA;Lo;0;R;;;;;N;;;;;\n07E9;NKO LETTER JONA CHA;Lo;0;R;;;;;N;;;;;\n07EA;NKO LETTER JONA RA;Lo;0;R;;;;;N;;;;;\n07EB;NKO COMBINING SHORT HIGH TONE;Mn;230;NSM;;;;;N;;;;;\n07EC;NKO COMBINING SHORT LOW TONE;Mn;230;NSM;;;;;N;;;;;\n07ED;NKO COMBINING SHORT RISING TONE;Mn;230;NSM;;;;;N;;;;;\n07EE;NKO COMBINING LONG DESCENDING TONE;Mn;230;NSM;;;;;N;;;;;\n07EF;NKO COMBINING LONG HIGH TONE;Mn;230;NSM;;;;;N;;;;;\n07F0;NKO COMBINING LONG LOW TONE;Mn;230;NSM;;;;;N;;;;;\n07F1;NKO COMBINING LONG RISING TONE;Mn;230;NSM;;;;;N;;;;;\n07F2;NKO COMBINING NASALIZATION MARK;Mn;220;NSM;;;;;N;;;;;\n07F3;NKO COMBINING DOUBLE DOT ABOVE;Mn;230;NSM;;;;;N;;;;;\n07F4;NKO HIGH TONE APOSTROPHE;Lm;0;R;;;;;N;;;;;\n07F5;NKO LOW TONE APOSTROPHE;Lm;0;R;;;;;N;;;;;\n07F6;NKO SYMBOL OO DENNEN;So;0;ON;;;;;N;;;;;\n07F7;NKO SYMBOL GBAKURUNEN;Po;0;ON;;;;;N;;;;;\n07F8;NKO COMMA;Po;0;ON;;;;;N;;;;;\n07F9;NKO EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;\n07FA;NKO LAJANYALAN;Lm;0;R;;;;;N;;;;;\n07FD;NKO DANTAYALAN;Mn;220;NSM;;;;;N;;;;;\n07FE;NKO DOROME SIGN;Sc;0;R;;;;;N;;;;;\n07FF;NKO TAMAN SIGN;Sc;0;R;;;;;N;;;;;\n0800;SAMARITAN LETTER ALAF;Lo;0;R;;;;;N;;;;;\n0801;SAMARITAN LETTER BIT;Lo;0;R;;;;;N;;;;;\n0802;SAMARITAN LETTER GAMAN;Lo;0;R;;;;;N;;;;;\n0803;SAMARITAN LETTER DALAT;Lo;0;R;;;;;N;;;;;\n0804;SAMARITAN LETTER IY;Lo;0;R;;;;;N;;;;;\n0805;SAMARITAN LETTER BAA;Lo;0;R;;;;;N;;;;;\n0806;SAMARITAN LETTER ZEN;Lo;0;R;;;;;N;;;;;\n0807;SAMARITAN LETTER IT;Lo;0;R;;;;;N;;;;;\n0808;SAMARITAN LETTER TIT;Lo;0;R;;;;;N;;;;;\n0809;SAMARITAN LETTER YUT;Lo;0;R;;;;;N;;;;;\n080A;SAMARITAN LETTER KAAF;Lo;0;R;;;;;N;;;;;\n080B;SAMARITAN LETTER LABAT;Lo;0;R;;;;;N;;;;;\n080C;SAMARITAN LETTER MIM;Lo;0;R;;;;;N;;;;;\n080D;SAMARITAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n080E;SAMARITAN LETTER SINGAAT;Lo;0;R;;;;;N;;;;;\n080F;SAMARITAN LETTER IN;Lo;0;R;;;;;N;;;;;\n0810;SAMARITAN LETTER FI;Lo;0;R;;;;;N;;;;;\n0811;SAMARITAN LETTER TSAADIY;Lo;0;R;;;;;N;;;;;\n0812;SAMARITAN LETTER QUF;Lo;0;R;;;;;N;;;;;\n0813;SAMARITAN LETTER RISH;Lo;0;R;;;;;N;;;;;\n0814;SAMARITAN LETTER SHAN;Lo;0;R;;;;;N;;;;;\n0815;SAMARITAN LETTER TAAF;Lo;0;R;;;;;N;;;;;\n0816;SAMARITAN MARK IN;Mn;230;NSM;;;;;N;;;;;\n0817;SAMARITAN MARK IN-ALAF;Mn;230;NSM;;;;;N;;;;;\n0818;SAMARITAN MARK OCCLUSION;Mn;230;NSM;;;;;N;;;;;\n0819;SAMARITAN MARK DAGESH;Mn;230;NSM;;;;;N;;;;;\n081A;SAMARITAN MODIFIER LETTER EPENTHETIC YUT;Lm;0;R;;;;;N;;;;;\n081B;SAMARITAN MARK EPENTHETIC YUT;Mn;230;NSM;;;;;N;;;;;\n081C;SAMARITAN VOWEL SIGN LONG E;Mn;230;NSM;;;;;N;;;;;\n081D;SAMARITAN VOWEL SIGN E;Mn;230;NSM;;;;;N;;;;;\n081E;SAMARITAN VOWEL SIGN OVERLONG AA;Mn;230;NSM;;;;;N;;;;;\n081F;SAMARITAN VOWEL SIGN LONG AA;Mn;230;NSM;;;;;N;;;;;\n0820;SAMARITAN VOWEL SIGN AA;Mn;230;NSM;;;;;N;;;;;\n0821;SAMARITAN VOWEL SIGN OVERLONG A;Mn;230;NSM;;;;;N;;;;;\n0822;SAMARITAN VOWEL SIGN LONG A;Mn;230;NSM;;;;;N;;;;;\n0823;SAMARITAN VOWEL SIGN A;Mn;230;NSM;;;;;N;;;;;\n0824;SAMARITAN MODIFIER LETTER SHORT A;Lm;0;R;;;;;N;;;;;\n0825;SAMARITAN VOWEL SIGN SHORT A;Mn;230;NSM;;;;;N;;;;;\n0826;SAMARITAN VOWEL SIGN LONG U;Mn;230;NSM;;;;;N;;;;;\n0827;SAMARITAN VOWEL SIGN U;Mn;230;NSM;;;;;N;;;;;\n0828;SAMARITAN MODIFIER LETTER I;Lm;0;R;;;;;N;;;;;\n0829;SAMARITAN VOWEL SIGN LONG I;Mn;230;NSM;;;;;N;;;;;\n082A;SAMARITAN VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;;\n082B;SAMARITAN VOWEL SIGN O;Mn;230;NSM;;;;;N;;;;;\n082C;SAMARITAN VOWEL SIGN SUKUN;Mn;230;NSM;;;;;N;;;;;\n082D;SAMARITAN MARK NEQUDAA;Mn;230;NSM;;;;;N;;;;;\n0830;SAMARITAN PUNCTUATION NEQUDAA;Po;0;R;;;;;N;;;;;\n0831;SAMARITAN PUNCTUATION AFSAAQ;Po;0;R;;;;;N;;;;;\n0832;SAMARITAN PUNCTUATION ANGED;Po;0;R;;;;;N;;;;;\n0833;SAMARITAN PUNCTUATION BAU;Po;0;R;;;;;N;;;;;\n0834;SAMARITAN PUNCTUATION ATMAAU;Po;0;R;;;;;N;;;;;\n0835;SAMARITAN PUNCTUATION SHIYYAALAA;Po;0;R;;;;;N;;;;;\n0836;SAMARITAN ABBREVIATION MARK;Po;0;R;;;;;N;;;;;\n0837;SAMARITAN PUNCTUATION MELODIC QITSA;Po;0;R;;;;;N;;;;;\n0838;SAMARITAN PUNCTUATION ZIQAA;Po;0;R;;;;;N;;;;;\n0839;SAMARITAN PUNCTUATION QITSA;Po;0;R;;;;;N;;;;;\n083A;SAMARITAN PUNCTUATION ZAEF;Po;0;R;;;;;N;;;;;\n083B;SAMARITAN PUNCTUATION TURU;Po;0;R;;;;;N;;;;;\n083C;SAMARITAN PUNCTUATION ARKAANU;Po;0;R;;;;;N;;;;;\n083D;SAMARITAN PUNCTUATION SOF MASHFAAT;Po;0;R;;;;;N;;;;;\n083E;SAMARITAN PUNCTUATION ANNAAU;Po;0;R;;;;;N;;;;;\n0840;MANDAIC LETTER HALQA;Lo;0;R;;;;;N;;;;;\n0841;MANDAIC LETTER AB;Lo;0;R;;;;;N;;;;;\n0842;MANDAIC LETTER AG;Lo;0;R;;;;;N;;;;;\n0843;MANDAIC LETTER AD;Lo;0;R;;;;;N;;;;;\n0844;MANDAIC LETTER AH;Lo;0;R;;;;;N;;;;;\n0845;MANDAIC LETTER USHENNA;Lo;0;R;;;;;N;;;;;\n0846;MANDAIC LETTER AZ;Lo;0;R;;;;;N;;;;;\n0847;MANDAIC LETTER IT;Lo;0;R;;;;;N;;;;;\n0848;MANDAIC LETTER ATT;Lo;0;R;;;;;N;;;;;\n0849;MANDAIC LETTER AKSA;Lo;0;R;;;;;N;;;;;\n084A;MANDAIC LETTER AK;Lo;0;R;;;;;N;;;;;\n084B;MANDAIC LETTER AL;Lo;0;R;;;;;N;;;;;\n084C;MANDAIC LETTER AM;Lo;0;R;;;;;N;;;;;\n084D;MANDAIC LETTER AN;Lo;0;R;;;;;N;;;;;\n084E;MANDAIC LETTER AS;Lo;0;R;;;;;N;;;;;\n084F;MANDAIC LETTER IN;Lo;0;R;;;;;N;;;;;\n0850;MANDAIC LETTER AP;Lo;0;R;;;;;N;;;;;\n0851;MANDAIC LETTER ASZ;Lo;0;R;;;;;N;;;;;\n0852;MANDAIC LETTER AQ;Lo;0;R;;;;;N;;;;;\n0853;MANDAIC LETTER AR;Lo;0;R;;;;;N;;;;;\n0854;MANDAIC LETTER ASH;Lo;0;R;;;;;N;;;;;\n0855;MANDAIC LETTER AT;Lo;0;R;;;;;N;;;;;\n0856;MANDAIC LETTER DUSHENNA;Lo;0;R;;;;;N;;;;;\n0857;MANDAIC LETTER KAD;Lo;0;R;;;;;N;;;;;\n0858;MANDAIC LETTER AIN;Lo;0;R;;;;;N;;;;;\n0859;MANDAIC AFFRICATION MARK;Mn;220;NSM;;;;;N;;;;;\n085A;MANDAIC VOCALIZATION MARK;Mn;220;NSM;;;;;N;;;;;\n085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;;\n085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;;\n0860;SYRIAC LETTER MALAYALAM NGA;Lo;0;AL;;;;;N;;;;;\n0861;SYRIAC LETTER MALAYALAM JA;Lo;0;AL;;;;;N;;;;;\n0862;SYRIAC LETTER MALAYALAM NYA;Lo;0;AL;;;;;N;;;;;\n0863;SYRIAC LETTER MALAYALAM TTA;Lo;0;AL;;;;;N;;;;;\n0864;SYRIAC LETTER MALAYALAM NNA;Lo;0;AL;;;;;N;;;;;\n0865;SYRIAC LETTER MALAYALAM NNNA;Lo;0;AL;;;;;N;;;;;\n0866;SYRIAC LETTER MALAYALAM BHA;Lo;0;AL;;;;;N;;;;;\n0867;SYRIAC LETTER MALAYALAM RA;Lo;0;AL;;;;;N;;;;;\n0868;SYRIAC LETTER MALAYALAM LLA;Lo;0;AL;;;;;N;;;;;\n0869;SYRIAC LETTER MALAYALAM LLLA;Lo;0;AL;;;;;N;;;;;\n086A;SYRIAC LETTER MALAYALAM SSA;Lo;0;AL;;;;;N;;;;;\n0870;ARABIC LETTER ALEF WITH ATTACHED FATHA;Lo;0;AL;;;;;N;;;;;\n0871;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA;Lo;0;AL;;;;;N;;;;;\n0872;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE;Lo;0;AL;;;;;N;;;;;\n0873;ARABIC LETTER ALEF WITH LEFT MIDDLE STROKE;Lo;0;AL;;;;;N;;;;;\n0874;ARABIC LETTER ALEF WITH ATTACHED KASRA;Lo;0;AL;;;;;N;;;;;\n0875;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA;Lo;0;AL;;;;;N;;;;;\n0876;ARABIC LETTER ALEF WITH ATTACHED ROUND DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n0877;ARABIC LETTER ALEF WITH ATTACHED RIGHT ROUND DOT;Lo;0;AL;;;;;N;;;;;\n0878;ARABIC LETTER ALEF WITH ATTACHED LEFT ROUND DOT;Lo;0;AL;;;;;N;;;;;\n0879;ARABIC LETTER ALEF WITH ATTACHED ROUND DOT BELOW;Lo;0;AL;;;;;N;;;;;\n087A;ARABIC LETTER ALEF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n087B;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n087C;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n087D;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n087E;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND LEFT RING;Lo;0;AL;;;;;N;;;;;\n087F;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND LEFT RING;Lo;0;AL;;;;;N;;;;;\n0880;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND LEFT RING;Lo;0;AL;;;;;N;;;;;\n0881;ARABIC LETTER ALEF WITH ATTACHED RIGHT HAMZA;Lo;0;AL;;;;;N;;;;;\n0882;ARABIC LETTER ALEF WITH ATTACHED LEFT HAMZA;Lo;0;AL;;;;;N;;;;;\n0883;ARABIC TATWEEL WITH OVERSTRUCK HAMZA;Lo;0;AL;;;;;N;;;;;\n0884;ARABIC TATWEEL WITH OVERSTRUCK WAW;Lo;0;AL;;;;;N;;;;;\n0885;ARABIC TATWEEL WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n0886;ARABIC LETTER THIN YEH;Lo;0;AL;;;;;N;;;;;\n0887;ARABIC BASELINE ROUND DOT;Lo;0;AL;;;;;N;;;;;\n0888;ARABIC RAISED ROUND DOT;Sk;0;AL;;;;;N;;;;;\n0889;ARABIC LETTER NOON WITH INVERTED SMALL V;Lo;0;AL;;;;;N;;;;;\n088A;ARABIC LETTER HAH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;\n088B;ARABIC LETTER TAH WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n088C;ARABIC LETTER TAH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n088D;ARABIC LETTER KEHEH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;;\n088E;ARABIC VERTICAL TAIL;Lo;0;AL;;;;;N;;;;;\n088F;ARABIC LETTER NOON WITH RING ABOVE;Lo;0;AL;;;;;N;;;;;\n0890;ARABIC POUND MARK ABOVE;Cf;0;AN;;;;;N;;;;;\n0891;ARABIC PIASTRE MARK ABOVE;Cf;0;AN;;;;;N;;;;;\n0897;ARABIC PEPET;Mn;230;NSM;;;;;N;;;;;\n0898;ARABIC SMALL HIGH WORD AL-JUZ;Mn;230;NSM;;;;;N;;;;;\n0899;ARABIC SMALL LOW WORD ISHMAAM;Mn;220;NSM;;;;;N;;;;;\n089A;ARABIC SMALL LOW WORD IMAALA;Mn;220;NSM;;;;;N;;;;;\n089B;ARABIC SMALL LOW WORD TASHEEL;Mn;220;NSM;;;;;N;;;;;\n089C;ARABIC MADDA WAAJIB;Mn;230;NSM;;;;;N;;;;;\n089D;ARABIC SUPERSCRIPT ALEF MOKHASSAS;Mn;230;NSM;;;;;N;;;;;\n089E;ARABIC DOUBLED MADDA;Mn;230;NSM;;;;;N;;;;;\n089F;ARABIC HALF MADDA OVER MADDA;Mn;230;NSM;;;;;N;;;;;\n08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;;\n08A1;ARABIC LETTER BEH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;\n08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n08A3;ARABIC LETTER TAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n08A4;ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n08A5;ARABIC LETTER QAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n08A6;ARABIC LETTER LAM WITH DOUBLE BAR;Lo;0;AL;;;;;N;;;;;\n08A7;ARABIC LETTER MEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n08A8;ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;\n08A9;ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;\n08AA;ARABIC LETTER REH WITH LOOP;Lo;0;AL;;;;;N;;;;;\n08AB;ARABIC LETTER WAW WITH DOT WITHIN;Lo;0;AL;;;;;N;;;;;\n08AC;ARABIC LETTER ROHINGYA YEH;Lo;0;AL;;;;;N;;;;;\n08AD;ARABIC LETTER LOW ALEF;Lo;0;AL;;;;;N;;;;;\n08AE;ARABIC LETTER DAL WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n08AF;ARABIC LETTER SAD WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n08B0;ARABIC LETTER GAF WITH INVERTED STROKE;Lo;0;AL;;;;;N;;;;;\n08B1;ARABIC LETTER STRAIGHT WAW;Lo;0;AL;;;;;N;;;;;\n08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;;\n08B3;ARABIC LETTER AIN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n08B4;ARABIC LETTER KAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;\n08B5;ARABIC LETTER QAF WITH DOT BELOW AND NO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n08B6;ARABIC LETTER BEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;;\n08B7;ARABIC LETTER PEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;;\n08B8;ARABIC LETTER TEH WITH SMALL TEH ABOVE;Lo;0;AL;;;;;N;;;;;\n08B9;ARABIC LETTER REH WITH SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;;\n08BA;ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;;\n08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;;\n08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;;\n08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;;\n08BE;ARABIC LETTER PEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;\n08BF;ARABIC LETTER TEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;\n08C0;ARABIC LETTER TTEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;\n08C1;ARABIC LETTER TCHEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;\n08C2;ARABIC LETTER KEHEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;\n08C3;ARABIC LETTER GHAIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n08C4;ARABIC LETTER AFRICAN QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n08C5;ARABIC LETTER JEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;\n08C6;ARABIC LETTER JEEM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n08C7;ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;;\n08C8;ARABIC LETTER GRAF;Lo;0;AL;;;;;N;;;;;\n08C9;ARABIC SMALL FARSI YEH;Lm;0;AL;;;;;N;;;;;\n08CA;ARABIC SMALL HIGH FARSI YEH;Mn;230;NSM;;;;;N;;;;;\n08CB;ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW;Mn;230;NSM;;;;;N;;;;;\n08CC;ARABIC SMALL HIGH WORD SAH;Mn;230;NSM;;;;;N;;;;;\n08CD;ARABIC SMALL HIGH ZAH;Mn;230;NSM;;;;;N;;;;;\n08CE;ARABIC LARGE ROUND DOT ABOVE;Mn;230;NSM;;;;;N;;;;;\n08CF;ARABIC LARGE ROUND DOT BELOW;Mn;220;NSM;;;;;N;;;;;\n08D0;ARABIC SUKUN BELOW;Mn;220;NSM;;;;;N;;;;;\n08D1;ARABIC LARGE CIRCLE BELOW;Mn;220;NSM;;;;;N;;;;;\n08D2;ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW;Mn;220;NSM;;;;;N;;;;;\n08D3;ARABIC SMALL LOW WAW;Mn;220;NSM;;;;;N;;;;;\n08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;;\n08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;;\n08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;;\n08D7;ARABIC SMALL HIGH QAF;Mn;230;NSM;;;;;N;;;;;\n08D8;ARABIC SMALL HIGH NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;;\n08D9;ARABIC SMALL LOW NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;;\n08DA;ARABIC SMALL HIGH WORD ATH-THALATHA;Mn;230;NSM;;;;;N;;;;;\n08DB;ARABIC SMALL HIGH WORD AS-SAJDA;Mn;230;NSM;;;;;N;;;;;\n08DC;ARABIC SMALL HIGH WORD AN-NISF;Mn;230;NSM;;;;;N;;;;;\n08DD;ARABIC SMALL HIGH WORD SAKTA;Mn;230;NSM;;;;;N;;;;;\n08DE;ARABIC SMALL HIGH WORD QIF;Mn;230;NSM;;;;;N;;;;;\n08DF;ARABIC SMALL HIGH WORD WAQFA;Mn;230;NSM;;;;;N;;;;;\n08E0;ARABIC SMALL HIGH FOOTNOTE MARKER;Mn;230;NSM;;;;;N;;;;;\n08E1;ARABIC SMALL HIGH SIGN SAFHA;Mn;230;NSM;;;;;N;;;;;\n08E2;ARABIC DISPUTED END OF AYAH;Cf;0;AN;;;;;N;;;;;\n08E3;ARABIC TURNED DAMMA BELOW;Mn;220;NSM;;;;;N;;;;;\n08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;;\n08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;;\n08E6;ARABIC CURLY KASRA;Mn;220;NSM;;;;;N;;;;;\n08E7;ARABIC CURLY FATHATAN;Mn;230;NSM;;;;;N;;;;;\n08E8;ARABIC CURLY DAMMATAN;Mn;230;NSM;;;;;N;;;;;\n08E9;ARABIC CURLY KASRATAN;Mn;220;NSM;;;;;N;;;;;\n08EA;ARABIC TONE ONE DOT ABOVE;Mn;230;NSM;;;;;N;;;;;\n08EB;ARABIC TONE TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;\n08EC;ARABIC TONE LOOP ABOVE;Mn;230;NSM;;;;;N;;;;;\n08ED;ARABIC TONE ONE DOT BELOW;Mn;220;NSM;;;;;N;;;;;\n08EE;ARABIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;;\n08EF;ARABIC TONE LOOP BELOW;Mn;220;NSM;;;;;N;;;;;\n08F0;ARABIC OPEN FATHATAN;Mn;27;NSM;;;;;N;;;;;\n08F1;ARABIC OPEN DAMMATAN;Mn;28;NSM;;;;;N;;;;;\n08F2;ARABIC OPEN KASRATAN;Mn;29;NSM;;;;;N;;;;;\n08F3;ARABIC SMALL HIGH WAW;Mn;230;NSM;;;;;N;;;;;\n08F4;ARABIC FATHA WITH RING;Mn;230;NSM;;;;;N;;;;;\n08F5;ARABIC FATHA WITH DOT ABOVE;Mn;230;NSM;;;;;N;;;;;\n08F6;ARABIC KASRA WITH DOT BELOW;Mn;220;NSM;;;;;N;;;;;\n08F7;ARABIC LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;\n08F8;ARABIC RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;\n08F9;ARABIC LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;\n08FA;ARABIC RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;\n08FB;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;\n08FC;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;;\n08FD;ARABIC RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;;\n08FE;ARABIC DAMMA WITH DOT;Mn;230;NSM;;;;;N;;;;;\n08FF;ARABIC MARK SIDEWAYS NOON GHUNNA;Mn;230;NSM;;;;;N;;;;;\n0900;DEVANAGARI SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n0904;DEVANAGARI LETTER SHORT A;Lo;0;L;;;;;N;;;;;\n0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;;\n0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;;\n0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;;\n0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;;\n0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;;\n090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;;\n090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;;\n090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;;\n090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;;\n0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;;\n0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;;\n0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;;\n0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;;\n0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;;\n0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;;\n0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;;\n0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;;\n0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;;\n0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;;\n091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;;\n091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;;\n091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;;\n091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;;\n091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;;\n091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;;\n0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;;\n0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;;\n0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;;\n0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;;\n0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;;\n0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;;\n0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;;\n0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;;\n092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;;\n092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;;\n092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;;\n092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;;\n092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;;\n092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;;\n0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;;\n0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;;\n0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;;\n0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;;\n0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;;\n0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;;\n0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;;\n0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;;\n0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;;\n0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;;\n093A;DEVANAGARI VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;\n093B;DEVANAGARI VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;;\n093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;\n0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;\n0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;\n094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;\n094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n094E;DEVANAGARI VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;;\n094F;DEVANAGARI VOWEL SIGN AW;Mc;0;L;;;;;N;;;;;\n0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;;\n0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;;\n0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;;\n0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;\n0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;\n0955;DEVANAGARI VOWEL SIGN CANDRA LONG E;Mn;0;NSM;;;;;N;;;;;\n0956;DEVANAGARI VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;\n0957;DEVANAGARI VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;;\n0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;;\n0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;;\n095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;;\n095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;;\n095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;;\n095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;;\n095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;;\n095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;;\n0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;;\n0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n0971;DEVANAGARI SIGN HIGH SPACING DOT;Lm;0;L;;;;;N;;;;;\n0972;DEVANAGARI LETTER CANDRA A;Lo;0;L;;;;;N;;;;;\n0973;DEVANAGARI LETTER OE;Lo;0;L;;;;;N;;;;;\n0974;DEVANAGARI LETTER OOE;Lo;0;L;;;;;N;;;;;\n0975;DEVANAGARI LETTER AW;Lo;0;L;;;;;N;;;;;\n0976;DEVANAGARI LETTER UE;Lo;0;L;;;;;N;;;;;\n0977;DEVANAGARI LETTER UUE;Lo;0;L;;;;;N;;;;;\n0978;DEVANAGARI LETTER MARWARI DDA;Lo;0;L;;;;;N;;;;;\n0979;DEVANAGARI LETTER ZHA;Lo;0;L;;;;;N;;;;;\n097A;DEVANAGARI LETTER HEAVY YA;Lo;0;L;;;;;N;;;;;\n097B;DEVANAGARI LETTER GGA;Lo;0;L;;;;;N;;;;;\n097C;DEVANAGARI LETTER JJA;Lo;0;L;;;;;N;;;;;\n097D;DEVANAGARI LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;;\n097E;DEVANAGARI LETTER DDDA;Lo;0;L;;;;;N;;;;;\n097F;DEVANAGARI LETTER BBA;Lo;0;L;;;;;N;;;;;\n0980;BENGALI ANJI;Lo;0;L;;;;;N;;;;;\n0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\n0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;;\n0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;;\n0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;;\n0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;;\n0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;;\n098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;;\n098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;;\n0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;;\n0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;;\n0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;;\n0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;;\n0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;;\n0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;;\n0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;;\n0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;;\n099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;;\n099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;;\n099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;;\n099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;;\n099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;;\n099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;;\n09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;;\n09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;;\n09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;;\n09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;;\n09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;;\n09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;;\n09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;;\n09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;;\n09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;;\n09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;;\n09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;;\n09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;;\n09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;;\n09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;;\n09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;;\n09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;;\n09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;;\n09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;;\n09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;;\n09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n09BD;BENGALI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;;\n09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;;\n09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n09CE;BENGALI LETTER KHANDA TA;Lo;0;L;;;;;N;;;;;\n09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;;\n09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;;\n09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;;\n09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;;\n09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;;;;\n09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;;;;\n09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;;\n09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;\n09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1/16;N;;;;;\n09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;1/8;N;;;;;\n09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3/16;N;;;;;\n09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;1/4;N;;;;;\n09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;3/4;N;;;;;\n09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;;\n09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;;\n09FB;BENGALI GANDA MARK;Sc;0;ET;;;;;N;;;;;\n09FC;BENGALI LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;\n09FD;BENGALI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n09FE;BENGALI SANDHI MARK;Mn;230;NSM;;;;;N;;;;;\n0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;;\n0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;;\n0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;;\n0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;;\n0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;;\n0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;;\n0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;;\n0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;;\n0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;;\n0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;;\n0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;;\n0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;;\n0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;;\n0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;;\n0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;;\n0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;;\n0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;;\n0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;;\n0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;;\n0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;;\n0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;;\n0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;;\n0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;;\n0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;;\n0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;;\n0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;;\n0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;;\n0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;;\n0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;;\n0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;;\n0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;;\n0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;;\n0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;;\n0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;;\n0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;;\n0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;;\n0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;;\n0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;;\n0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;;\n0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;;\n0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;;\n0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;;\n0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;;\n0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;\n0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;\n0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0A51;GURMUKHI SIGN UDAAT;Mn;0;NSM;;;;;N;;;;;\n0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;;\n0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;;\n0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;;\n0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;;\n0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;;\n0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;;\n0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;;\n0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;;\n0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;;\n0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;;\n0A75;GURMUKHI SIGN YAKASH;Mn;0;NSM;;;;;N;;;;;\n0A76;GURMUKHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;;\n0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;;\n0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;;\n0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;;\n0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;;\n0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;;\n0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n0A8C;GUJARATI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;;\n0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;;\n0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;;\n0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;;\n0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;;\n0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;;\n0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;;\n0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;;\n0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;;\n0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;;\n0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;;\n0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;;\n0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;;\n0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;;\n0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;;\n0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;;\n0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;;\n0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;;\n0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;;\n0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;;\n0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;;\n0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;;\n0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;;\n0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;;\n0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;;\n0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;;\n0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;;\n0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;;\n0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;;\n0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;;\n0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;;\n0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;;\n0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;;\n0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;;\n0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;;\n0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;;\n0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;;\n0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;;\n0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;\n0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;\n0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;;\n0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n0AE1;GUJARATI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n0AE2;GUJARATI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n0AE3;GUJARATI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0AF0;GUJARATI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;\n0AF9;GUJARATI LETTER ZHA;Lo;0;L;;;;;N;;;;;\n0AFA;GUJARATI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;;\n0AFB;GUJARATI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;;\n0AFC;GUJARATI SIGN MADDAH;Mn;0;NSM;;;;;N;;;;;\n0AFD;GUJARATI SIGN THREE-DOT NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;;\n0AFE;GUJARATI SIGN CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;;\n0AFF;GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;;\n0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\n0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;;\n0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;;\n0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;;\n0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;;\n0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;;\n0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;;\n0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;;\n0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;;\n0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;;\n0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;;\n0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;;\n0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;;\n0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;;\n0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;;\n0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;;\n0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;;\n0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;;\n0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;;\n0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;;\n0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;;\n0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;;\n0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;;\n0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;;\n0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;;\n0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;;\n0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;;\n0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;;\n0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;;\n0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;;\n0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;;\n0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;;\n0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;;\n0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;;\n0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;;\n0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;;\n0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;;\n0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;;\n0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;;\n0B35;ORIYA LETTER VA;Lo;0;L;;;;;N;;;;;\n0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;;\n0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;;\n0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;;\n0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;;\n0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n0B44;ORIYA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;;\n0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;;\n0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;;\n0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0B55;ORIYA SIGN OVERLINE;Mn;0;NSM;;;;;N;;;;;\n0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;;\n0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;;\n0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;;\n0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;;\n0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;;\n0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n0B62;ORIYA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n0B63;ORIYA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;;\n0B71;ORIYA LETTER WA;Lo;0;L;;;;;N;;;;;\n0B72;ORIYA FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;;\n0B73;ORIYA FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;;\n0B74;ORIYA FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;;\n0B75;ORIYA FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;;\n0B76;ORIYA FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;;\n0B77;ORIYA FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;;\n0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;;\n0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;;\n0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;;\n0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;;\n0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;;\n0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;;\n0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;;\n0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;;\n0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;;\n0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;;\n0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;;\n0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;;\n0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;;\n0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;;\n0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;;\n0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;;\n0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;;\n0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;;\n0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;;\n0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;;\n0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;;\n0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;;\n0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;;\n0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;;\n0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;;\n0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;;\n0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;;\n0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;;\n0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;;\n0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;;\n0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;;\n0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;;\n0BB6;TAMIL LETTER SHA;Lo;0;L;;;;;N;;;;;\n0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;;\n0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;;\n0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;;\n0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\n0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;\n0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;;\n0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;;\n0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;;\n0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0BD0;TAMIL OM;Lo;0;L;;;;;N;;;;;\n0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;;\n0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;;\n0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;\n0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;\n0BF3;TAMIL DAY SIGN;So;0;ON;;;;;N;;;;;\n0BF4;TAMIL MONTH SIGN;So;0;ON;;;;;N;;;;;\n0BF5;TAMIL YEAR SIGN;So;0;ON;;;;;N;;;;;\n0BF6;TAMIL DEBIT SIGN;So;0;ON;;;;;N;;;;;\n0BF7;TAMIL CREDIT SIGN;So;0;ON;;;;;N;;;;;\n0BF8;TAMIL AS ABOVE SIGN;So;0;ON;;;;;N;;;;;\n0BF9;TAMIL RUPEE SIGN;Sc;0;ET;;;;;N;;;;;\n0BFA;TAMIL NUMBER SIGN;So;0;ON;;;;;N;;;;;\n0C00;TELUGU SIGN COMBINING CANDRABINDU ABOVE;Mn;0;NSM;;;;;N;;;;;\n0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;\n0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\n0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n0C04;TELUGU SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;;\n0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;;\n0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;;\n0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;;\n0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;;\n0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;;\n0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;;\n0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;;\n0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;;\n0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;;\n0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;;\n0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;;\n0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;;\n0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;;\n0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;;\n0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;;\n0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;;\n0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;;\n0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;;\n0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;;\n0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;;\n0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;;\n0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;;\n0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;;\n0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;;\n0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;;\n0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;;\n0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;;\n0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;;\n0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;;\n0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;;\n0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;;\n0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;;\n0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;;\n0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;;\n0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;;\n0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;;\n0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;;\n0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;;\n0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;;\n0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;;\n0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;;\n0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;;\n0C34;TELUGU LETTER LLLA;Lo;0;L;;;;;N;;;;;\n0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;;\n0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;;\n0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;;\n0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;;\n0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;;\n0C3C;TELUGU SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n0C3D;TELUGU SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;\n0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\n0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;\n0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;\n0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;\n0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;;\n0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;\n0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;;\n0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;;\n0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;;\n0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;;\n0C5A;TELUGU LETTER RRRA;Lo;0;L;;;;;N;;;;;\n0C5C;TELUGU ARCHAIC SHRII;Lo;0;L;;;;;N;;;;;\n0C5D;TELUGU LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;;\n0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n0C62;TELUGU VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n0C63;TELUGU VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0C77;TELUGU SIGN SIDDHAM;Po;0;L;;;;;N;;;;;\n0C78;TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR;No;0;ON;;;;0;N;;;;;\n0C79;TELUGU FRACTION DIGIT ONE FOR ODD POWERS OF FOUR;No;0;ON;;;;1;N;;;;;\n0C7A;TELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOUR;No;0;ON;;;;2;N;;;;;\n0C7B;TELUGU FRACTION DIGIT THREE FOR ODD POWERS OF FOUR;No;0;ON;;;;3;N;;;;;\n0C7C;TELUGU FRACTION DIGIT ONE FOR EVEN POWERS OF FOUR;No;0;ON;;;;1;N;;;;;\n0C7D;TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR;No;0;ON;;;;2;N;;;;;\n0C7E;TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR;No;0;ON;;;;3;N;;;;;\n0C7F;TELUGU SIGN TUUMU;So;0;L;;;;;N;;;;;\n0C80;KANNADA SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;;\n0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\n0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n0C84;KANNADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;;\n0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;;\n0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;;\n0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;;\n0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;;\n0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;;\n0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;;\n0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;;\n0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;;\n0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;;\n0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;;\n0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;;\n0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;;\n0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;;\n0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;;\n0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;;\n0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;;\n0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;;\n0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;;\n0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;;\n0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;;\n0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;;\n0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;;\n0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;;\n0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;;\n0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;;\n0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;;\n0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;;\n0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;;\n0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;;\n0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;;\n0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;;\n0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;;\n0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;;\n0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;;\n0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;;\n0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;;\n0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;;\n0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;;\n0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;;\n0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;;\n0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;;\n0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;;\n0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;;\n0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;;\n0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;;\n0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;;\n0CBC;KANNADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n0CBD;KANNADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n0CBF;KANNADA VOWEL SIGN I;Mn;0;L;;;;;N;;;;;\n0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;;\n0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\n0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;\n0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;\n0CC6;KANNADA VOWEL SIGN E;Mn;0;L;;;;;N;;;;;\n0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;;\n0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;;\n0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;;\n0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;;\n0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;;\n0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;;\n0CDC;KANNADA ARCHAIC SHRII;Lo;0;L;;;;;N;;;;;\n0CDD;KANNADA LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;;\n0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;;\n0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n0CE2;KANNADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n0CE3;KANNADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;\n0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;\n0CF3;KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT;Mc;0;L;;;;;N;;;;;\n0D00;MALAYALAM SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;;\n0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\n0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n0D04;MALAYALAM LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;\n0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;;\n0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;;\n0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;;\n0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;;\n0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;;\n0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;;\n0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;;\n0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;;\n0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;;\n0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;;\n0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;;\n0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;;\n0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;;\n0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;;\n0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;;\n0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;;\n0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;;\n0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;;\n0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;;\n0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;;\n0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;;\n0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;;\n0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;;\n0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;;\n0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;;\n0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;;\n0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;;\n0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;;\n0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;;\n0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;;\n0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;;\n0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;;\n0D29;MALAYALAM LETTER NNNA;Lo;0;L;;;;;N;;;;;\n0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;;\n0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;;\n0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;;\n0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;;\n0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;;\n0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;;\n0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;;\n0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;;\n0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;;\n0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;;\n0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;;\n0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;;\n0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;;\n0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;;\n0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;;\n0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;;\n0D3A;MALAYALAM LETTER TTTA;Lo;0;L;;;;;N;;;;;\n0D3B;MALAYALAM SIGN VERTICAL BAR VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0D3C;MALAYALAM SIGN CIRCULAR VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0D3D;MALAYALAM SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n0D44;MALAYALAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;\n0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;\n0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;;\n0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;;\n0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0D4E;MALAYALAM LETTER DOT REPH;Lo;0;L;;;;;N;;;;;\n0D4F;MALAYALAM SIGN PARA;So;0;L;;;;;N;;;;;\n0D54;MALAYALAM LETTER CHILLU M;Lo;0;L;;;;;N;;;;;\n0D55;MALAYALAM LETTER CHILLU Y;Lo;0;L;;;;;N;;;;;\n0D56;MALAYALAM LETTER CHILLU LLL;Lo;0;L;;;;;N;;;;;\n0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;;\n0D58;MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;;\n0D59;MALAYALAM FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;;\n0D5A;MALAYALAM FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;;\n0D5B;MALAYALAM FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;;\n0D5C;MALAYALAM FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;;\n0D5D;MALAYALAM FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;;\n0D5E;MALAYALAM FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;;\n0D5F;MALAYALAM LETTER ARCHAIC II;Lo;0;L;;;;;N;;;;;\n0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n0D62;MALAYALAM VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n0D63;MALAYALAM VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0D70;MALAYALAM NUMBER TEN;No;0;L;;;;10;N;;;;;\n0D71;MALAYALAM NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;\n0D72;MALAYALAM NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;\n0D73;MALAYALAM FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;;\n0D74;MALAYALAM FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;;\n0D75;MALAYALAM FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;;\n0D76;MALAYALAM FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;;\n0D77;MALAYALAM FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;;\n0D78;MALAYALAM FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;;\n0D79;MALAYALAM DATE MARK;So;0;L;;;;;N;;;;;\n0D7A;MALAYALAM LETTER CHILLU NN;Lo;0;L;;;;;N;;;;;\n0D7B;MALAYALAM LETTER CHILLU N;Lo;0;L;;;;;N;;;;;\n0D7C;MALAYALAM LETTER CHILLU RR;Lo;0;L;;;;;N;;;;;\n0D7D;MALAYALAM LETTER CHILLU L;Lo;0;L;;;;;N;;;;;\n0D7E;MALAYALAM LETTER CHILLU LL;Lo;0;L;;;;;N;;;;;\n0D7F;MALAYALAM LETTER CHILLU K;Lo;0;L;;;;;N;;;;;\n0D81;SINHALA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;;\n0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;;\n0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;;\n0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;;\n0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;;\n0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;;\n0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;;\n0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;;\n0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;;\n0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;;\n0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;;\n0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;;\n0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;;\n0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;;\n0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;;\n0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;;\n0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;;\n0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;;\n0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;;\n0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;;\n0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;\n0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;\n0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;\n0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;\n0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;\n0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;;\n0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;\n0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;\n0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;\n0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;\n0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;\n0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;;\n0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;;\n0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;\n0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;\n0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;\n0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;\n0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;;\n0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;;\n0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;\n0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;\n0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;\n0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;\n0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;;\n0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;;\n0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;\n0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;\n0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;\n0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;\n0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;;\n0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;;\n0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;;\n0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;;\n0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;;\n0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;;\n0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;;\n0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;;\n0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;;\n0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;;\n0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;;\n0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;;\n0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;;\n0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;;\n0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;;\n0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;;\n0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;;\n0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;;\n0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;;\n0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;;\n0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;;\n0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;;\n0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;;\n0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;;\n0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;;\n0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;;\n0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;;\n0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;;\n0DE6;SINHALA LITH DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0DE7;SINHALA LITH DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0DE8;SINHALA LITH DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0DE9;SINHALA LITH DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0DEA;SINHALA LITH DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0DEB;SINHALA LITH DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0DEC;SINHALA LITH DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0DED;SINHALA LITH DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0DEE;SINHALA LITH DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0DEF;SINHALA LITH DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;;\n0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;;\n0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;;\n0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;;\n0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;;\n0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;;\n0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;;\n0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;;\n0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;;\n0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;;\n0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;;\n0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;;\n0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;;\n0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;;\n0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;;\n0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;;\n0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;;\n0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;;\n0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;;\n0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;;\n0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;;\n0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;;\n0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;;\n0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;;\n0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;;\n0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;;\n0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;;\n0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;;\n0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;;\n0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;;\n0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;;\n0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;;\n0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;;\n0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;;\n0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;;\n0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;;\n0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;;\n0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;;\n0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;;\n0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;;\n0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;;\n0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;;\n0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;;\n0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;;\n0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;;\n0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;;\n0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;;\n0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;;\n0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;;\n0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;;;;\n0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;;\n0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;;\n0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;;\n0E33;THAI CHARACTER SARA AM;Lo;0;L;<compat> 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;;\n0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;;\n0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;;\n0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;;\n0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;;;;\n0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;;\n0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;;\n0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;;\n0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;;\n0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;;\n0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;;\n0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;;\n0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;;;;\n0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;;;;\n0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;;;;\n0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;;;;\n0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;;;;\n0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;;\n0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;;\n0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;;\n0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;;\n0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;;\n0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;;;;\n0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;;\n0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;;\n0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;;\n0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;;\n0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;;\n0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;;\n0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;;\n0E86;LAO LETTER PALI GHA;Lo;0;L;;;;;N;;;;;\n0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;;\n0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;;\n0E89;LAO LETTER PALI CHA;Lo;0;L;;;;;N;;;;;\n0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;;\n0E8C;LAO LETTER PALI JHA;Lo;0;L;;;;;N;;;;;\n0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;;\n0E8E;LAO LETTER PALI NYA;Lo;0;L;;;;;N;;;;;\n0E8F;LAO LETTER PALI TTA;Lo;0;L;;;;;N;;;;;\n0E90;LAO LETTER PALI TTHA;Lo;0;L;;;;;N;;;;;\n0E91;LAO LETTER PALI DDA;Lo;0;L;;;;;N;;;;;\n0E92;LAO LETTER PALI DDHA;Lo;0;L;;;;;N;;;;;\n0E93;LAO LETTER PALI NNA;Lo;0;L;;;;;N;;;;;\n0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;;\n0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;;\n0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;;\n0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;;\n0E98;LAO LETTER PALI DHA;Lo;0;L;;;;;N;;;;;\n0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;;\n0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;;\n0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;;\n0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;;\n0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;;\n0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;;\n0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;;\n0EA0;LAO LETTER PALI BHA;Lo;0;L;;;;;N;;;;;\n0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;;\n0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;;\n0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;;\n0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;;\n0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;;\n0EA8;LAO LETTER SANSKRIT SHA;Lo;0;L;;;;;N;;;;;\n0EA9;LAO LETTER SANSKRIT SSA;Lo;0;L;;;;;N;;;;;\n0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;;\n0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;;\n0EAC;LAO LETTER PALI LLA;Lo;0;L;;;;;N;;;;;\n0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;;\n0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;;\n0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;;\n0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;;\n0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;;\n0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;;\n0EB3;LAO VOWEL SIGN AM;Lo;0;L;<compat> 0ECD 0EB2;;;;N;;;;;\n0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;\n0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;\n0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;;\n0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;;\n0EBA;LAO SIGN PALI VIRAMA;Mn;9;NSM;;;;;N;;;;;\n0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;;\n0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;;\n0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;;\n0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;;\n0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;;\n0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;;\n0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;;\n0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;;\n0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;;\n0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;;\n0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;;\n0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;;\n0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;;\n0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;;\n0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;;\n0ECE;LAO YAMAKKAN;Mn;0;NSM;;;;;N;;;;;\n0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0EDC;LAO HO NO;Lo;0;L;<compat> 0EAB 0E99;;;;N;;;;;\n0EDD;LAO HO MO;Lo;0;L;<compat> 0EAB 0EA1;;;;N;;;;;\n0EDE;LAO LETTER KHMU GO;Lo;0;L;;;;;N;;;;;\n0EDF;LAO LETTER KHMU NYO;Lo;0;L;;;;;N;;;;;\n0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;;\n0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;;;;\n0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;;;;\n0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;;;;\n0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;;;;\n0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;;;;\n0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;;;;\n0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;;;;\n0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;;;;\n0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;;;;\n0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;;;;\n0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;;;;\n0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L;<noBreak> 0F0B;;;;N;;;;;\n0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;;;;\n0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;;;;\n0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;;;;\n0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;;;;\n0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;;;;\n0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;;;;\n0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;;;;\n0F14;TIBETAN MARK GTER TSHEG;Po;0;L;;;;;N;TIBETAN COMMA;;;;\n0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;;;;\n0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;;;;\n0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;;;;\n0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;;;;\n0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;;;;\n0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;;;;\n0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;;;;\n0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;;;;\n0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;;;;\n0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;;;;\n0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;;;;\n0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;;\n0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;;\n0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;;\n0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;;\n0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;;\n0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;;\n0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;;\n0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;;\n0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;;\n0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;;\n0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;;;;\n0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;;;;\n0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;;;;\n0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;;;;\n0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;;;;\n0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;;;;\n0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;Y;;;;;\n0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;Y;;;;;\n0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;Y;TIBETAN LEFT BRACE;;;;\n0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;Y;TIBETAN RIGHT BRACE;;;;\n0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;;;;\n0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;;;;\n0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;;\n0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;;\n0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;;\n0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;;\n0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;;\n0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;;\n0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;;\n0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;;\n0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;;\n0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;;\n0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;;\n0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;;\n0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;;\n0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;;\n0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;;\n0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;;\n0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;;\n0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;;\n0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;;\n0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;;\n0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;;\n0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;;\n0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;;\n0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;;\n0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;;\n0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;;\n0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;;\n0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;;\n0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;;\n0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;;\n0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;;\n0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;;\n0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;;\n0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;;;;\n0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;;\n0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;;\n0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;;\n0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;;\n0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;;\n0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;;\n0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;;\n0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;;;;\n0F6B;TIBETAN LETTER KKA;Lo;0;L;;;;;N;;;;;\n0F6C;TIBETAN LETTER RRA;Lo;0;L;;;;;N;;;;;\n0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;;\n0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;;\n0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;;\n0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;;\n0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;;\n0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;;\n0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM;<compat> 0FB2 0F81;;;;N;;;;;\n0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;;\n0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM;<compat> 0FB3 0F81;;;;N;;;;;\n0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;;\n0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;;\n0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;;\n0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;;\n0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;;;;\n0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;;;;\n0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;;\n0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;;\n0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;;;;\n0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;;;;\n0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;;\n0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;;\n0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;;;;\n0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;;;;\n0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;;;;\n0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;;;;\n0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;;;;\n0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;;;;\n0F8C;TIBETAN SIGN INVERTED MCHU CAN;Lo;0;L;;;;;N;;;;;\n0F8D;TIBETAN SUBJOINED SIGN LCE TSA CAN;Mn;0;NSM;;;;;N;;;;;\n0F8E;TIBETAN SUBJOINED SIGN MCHU CAN;Mn;0;NSM;;;;;N;;;;;\n0F8F;TIBETAN SUBJOINED SIGN INVERTED MCHU CAN;Mn;0;NSM;;;;;N;;;;;\n0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;;\n0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;;\n0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;;\n0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;;\n0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;;\n0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;;\n0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;;\n0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;;\n0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;;\n0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;;\n0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;;\n0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;;\n0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;;\n0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;;\n0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;;\n0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;;\n0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;;\n0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;;\n0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;;\n0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;;\n0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;;\n0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;;\n0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;;\n0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;;\n0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;;\n0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;;\n0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;;\n0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;;\n0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;;\n0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;;\n0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;;\n0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;;\n0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;;;;\n0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;;\n0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;;\n0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;;\n0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;;\n0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;;\n0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;;\n0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;;\n0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;;\n0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;;;;\n0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;;;;\n0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;;;;\n0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;;;;\n0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;;;;\n0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;;\n0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;;\n0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;;;;\n0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;;;;\n0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;;;;\n0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;;;;\n0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;;;;\n0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;;;;\n0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;;;;\n0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;;;;\n0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;;;;\n0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;;;;\n0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;;;;\n0FCE;TIBETAN SIGN RDEL NAG RDEL DKAR;So;0;L;;;;;N;;;;;\n0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;;;;\n0FD0;TIBETAN MARK BSKA- SHOG GI MGO RGYAN;Po;0;L;;;;;N;;;;;\n0FD1;TIBETAN MARK MNYAM YIG GI MGO RGYAN;Po;0;L;;;;;N;;;;;\n0FD2;TIBETAN MARK NYIS TSHEG;Po;0;L;;;;;N;;;;;\n0FD3;TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA;Po;0;L;;;;;N;;;;;\n0FD4;TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA;Po;0;L;;;;;N;;;;;\n0FD5;RIGHT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;;\n0FD6;LEFT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;;\n0FD7;RIGHT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;;\n0FD8;LEFT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;;\n0FD9;TIBETAN MARK LEADING MCHAN RTAGS;Po;0;L;;;;;N;;;;;\n0FDA;TIBETAN MARK TRAILING MCHAN RTAGS;Po;0;L;;;;;N;;;;;\n1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;;\n1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;;\n1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;;\n1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;;\n1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;;\n1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;;\n1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;;\n1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;;\n1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;;\n1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;;\n100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;;\n100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;;\n100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;;\n100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;;\n100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;;\n100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;;\n1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;;\n1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;;\n1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;;\n1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;;\n1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;;\n1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;;\n1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;;\n1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;;\n1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;;\n1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;;\n101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;;\n101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;;\n101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;;\n101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;;\n101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;;\n101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;;\n1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;;\n1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;;\n1022;MYANMAR LETTER SHAN A;Lo;0;L;;;;;N;;;;;\n1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;;\n1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;;\n1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;;\n1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;;\n1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;;\n1028;MYANMAR LETTER MON E;Lo;0;L;;;;;N;;;;;\n1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;;\n102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;;\n102B;MYANMAR VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;;\n102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n1033;MYANMAR VOWEL SIGN MON II;Mn;0;NSM;;;;;N;;;;;\n1034;MYANMAR VOWEL SIGN MON O;Mn;0;NSM;;;;;N;;;;;\n1035;MYANMAR VOWEL SIGN E ABOVE;Mn;0;NSM;;;;;N;;;;;\n1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;;\n1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n103A;MYANMAR SIGN ASAT;Mn;9;NSM;;;;;N;;;;;\n103B;MYANMAR CONSONANT SIGN MEDIAL YA;Mc;0;L;;;;;N;;;;;\n103C;MYANMAR CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;;\n103D;MYANMAR CONSONANT SIGN MEDIAL WA;Mn;0;NSM;;;;;N;;;;;\n103E;MYANMAR CONSONANT SIGN MEDIAL HA;Mn;0;NSM;;;;;N;;;;;\n103F;MYANMAR LETTER GREAT SA;Lo;0;L;;;;;N;;;;;\n1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;;\n104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;;\n104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;;\n104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;;\n104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;;\n104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;;\n1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;;\n1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;;\n1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;\n1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;\n1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n105A;MYANMAR LETTER MON NGA;Lo;0;L;;;;;N;;;;;\n105B;MYANMAR LETTER MON JHA;Lo;0;L;;;;;N;;;;;\n105C;MYANMAR LETTER MON BBA;Lo;0;L;;;;;N;;;;;\n105D;MYANMAR LETTER MON BBE;Lo;0;L;;;;;N;;;;;\n105E;MYANMAR CONSONANT SIGN MON MEDIAL NA;Mn;0;NSM;;;;;N;;;;;\n105F;MYANMAR CONSONANT SIGN MON MEDIAL MA;Mn;0;NSM;;;;;N;;;;;\n1060;MYANMAR CONSONANT SIGN MON MEDIAL LA;Mn;0;NSM;;;;;N;;;;;\n1061;MYANMAR LETTER SGAW KAREN SHA;Lo;0;L;;;;;N;;;;;\n1062;MYANMAR VOWEL SIGN SGAW KAREN EU;Mc;0;L;;;;;N;;;;;\n1063;MYANMAR TONE MARK SGAW KAREN HATHI;Mc;0;L;;;;;N;;;;;\n1064;MYANMAR TONE MARK SGAW KAREN KE PHO;Mc;0;L;;;;;N;;;;;\n1065;MYANMAR LETTER WESTERN PWO KAREN THA;Lo;0;L;;;;;N;;;;;\n1066;MYANMAR LETTER WESTERN PWO KAREN PWA;Lo;0;L;;;;;N;;;;;\n1067;MYANMAR VOWEL SIGN WESTERN PWO KAREN EU;Mc;0;L;;;;;N;;;;;\n1068;MYANMAR VOWEL SIGN WESTERN PWO KAREN UE;Mc;0;L;;;;;N;;;;;\n1069;MYANMAR SIGN WESTERN PWO KAREN TONE-1;Mc;0;L;;;;;N;;;;;\n106A;MYANMAR SIGN WESTERN PWO KAREN TONE-2;Mc;0;L;;;;;N;;;;;\n106B;MYANMAR SIGN WESTERN PWO KAREN TONE-3;Mc;0;L;;;;;N;;;;;\n106C;MYANMAR SIGN WESTERN PWO KAREN TONE-4;Mc;0;L;;;;;N;;;;;\n106D;MYANMAR SIGN WESTERN PWO KAREN TONE-5;Mc;0;L;;;;;N;;;;;\n106E;MYANMAR LETTER EASTERN PWO KAREN NNA;Lo;0;L;;;;;N;;;;;\n106F;MYANMAR LETTER EASTERN PWO KAREN YWA;Lo;0;L;;;;;N;;;;;\n1070;MYANMAR LETTER EASTERN PWO KAREN GHWA;Lo;0;L;;;;;N;;;;;\n1071;MYANMAR VOWEL SIGN GEBA KAREN I;Mn;0;NSM;;;;;N;;;;;\n1072;MYANMAR VOWEL SIGN KAYAH OE;Mn;0;NSM;;;;;N;;;;;\n1073;MYANMAR VOWEL SIGN KAYAH U;Mn;0;NSM;;;;;N;;;;;\n1074;MYANMAR VOWEL SIGN KAYAH EE;Mn;0;NSM;;;;;N;;;;;\n1075;MYANMAR LETTER SHAN KA;Lo;0;L;;;;;N;;;;;\n1076;MYANMAR LETTER SHAN KHA;Lo;0;L;;;;;N;;;;;\n1077;MYANMAR LETTER SHAN GA;Lo;0;L;;;;;N;;;;;\n1078;MYANMAR LETTER SHAN CA;Lo;0;L;;;;;N;;;;;\n1079;MYANMAR LETTER SHAN ZA;Lo;0;L;;;;;N;;;;;\n107A;MYANMAR LETTER SHAN NYA;Lo;0;L;;;;;N;;;;;\n107B;MYANMAR LETTER SHAN DA;Lo;0;L;;;;;N;;;;;\n107C;MYANMAR LETTER SHAN NA;Lo;0;L;;;;;N;;;;;\n107D;MYANMAR LETTER SHAN PHA;Lo;0;L;;;;;N;;;;;\n107E;MYANMAR LETTER SHAN FA;Lo;0;L;;;;;N;;;;;\n107F;MYANMAR LETTER SHAN BA;Lo;0;L;;;;;N;;;;;\n1080;MYANMAR LETTER SHAN THA;Lo;0;L;;;;;N;;;;;\n1081;MYANMAR LETTER SHAN HA;Lo;0;L;;;;;N;;;;;\n1082;MYANMAR CONSONANT SIGN SHAN MEDIAL WA;Mn;0;NSM;;;;;N;;;;;\n1083;MYANMAR VOWEL SIGN SHAN AA;Mc;0;L;;;;;N;;;;;\n1084;MYANMAR VOWEL SIGN SHAN E;Mc;0;L;;;;;N;;;;;\n1085;MYANMAR VOWEL SIGN SHAN E ABOVE;Mn;0;NSM;;;;;N;;;;;\n1086;MYANMAR VOWEL SIGN SHAN FINAL Y;Mn;0;NSM;;;;;N;;;;;\n1087;MYANMAR SIGN SHAN TONE-2;Mc;0;L;;;;;N;;;;;\n1088;MYANMAR SIGN SHAN TONE-3;Mc;0;L;;;;;N;;;;;\n1089;MYANMAR SIGN SHAN TONE-5;Mc;0;L;;;;;N;;;;;\n108A;MYANMAR SIGN SHAN TONE-6;Mc;0;L;;;;;N;;;;;\n108B;MYANMAR SIGN SHAN COUNCIL TONE-2;Mc;0;L;;;;;N;;;;;\n108C;MYANMAR SIGN SHAN COUNCIL TONE-3;Mc;0;L;;;;;N;;;;;\n108D;MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE;Mn;220;NSM;;;;;N;;;;;\n108E;MYANMAR LETTER RUMAI PALAUNG FA;Lo;0;L;;;;;N;;;;;\n108F;MYANMAR SIGN RUMAI PALAUNG TONE-5;Mc;0;L;;;;;N;;;;;\n1090;MYANMAR SHAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1091;MYANMAR SHAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1092;MYANMAR SHAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1093;MYANMAR SHAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1094;MYANMAR SHAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1095;MYANMAR SHAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1096;MYANMAR SHAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1097;MYANMAR SHAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1098;MYANMAR SHAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1099;MYANMAR SHAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n109A;MYANMAR SIGN KHAMTI TONE-1;Mc;0;L;;;;;N;;;;;\n109B;MYANMAR SIGN KHAMTI TONE-3;Mc;0;L;;;;;N;;;;;\n109C;MYANMAR VOWEL SIGN AITON A;Mc;0;L;;;;;N;;;;;\n109D;MYANMAR VOWEL SIGN AITON AI;Mn;0;NSM;;;;;N;;;;;\n109E;MYANMAR SYMBOL SHAN ONE;So;0;L;;;;;N;;;;;\n109F;MYANMAR SYMBOL SHAN EXCLAMATION;So;0;L;;;;;N;;;;;\n10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;2D00;\n10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;2D01;\n10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;2D02;\n10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;2D03;\n10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;2D04;\n10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;2D05;\n10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;2D06;\n10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;2D07;\n10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;2D08;\n10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;2D09;\n10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;2D0A;\n10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;2D0B;\n10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;2D0C;\n10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;2D0D;\n10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;2D0E;\n10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;2D0F;\n10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;2D10;\n10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;2D11;\n10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;2D12;\n10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;2D13;\n10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;2D14;\n10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;2D15;\n10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;2D16;\n10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;2D17;\n10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;2D18;\n10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;2D19;\n10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;2D1A;\n10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;2D1B;\n10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;2D1C;\n10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;2D1D;\n10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;2D1E;\n10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;2D1F;\n10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;2D20;\n10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;2D21;\n10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;2D22;\n10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;2D23;\n10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;2D24;\n10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;2D25;\n10C7;GEORGIAN CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;2D27;\n10CD;GEORGIAN CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;2D2D;\n10D0;GEORGIAN LETTER AN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;1C90;;10D0\n10D1;GEORGIAN LETTER BAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;1C91;;10D1\n10D2;GEORGIAN LETTER GAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;1C92;;10D2\n10D3;GEORGIAN LETTER DON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;1C93;;10D3\n10D4;GEORGIAN LETTER EN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;1C94;;10D4\n10D5;GEORGIAN LETTER VIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;1C95;;10D5\n10D6;GEORGIAN LETTER ZEN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;1C96;;10D6\n10D7;GEORGIAN LETTER TAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;1C97;;10D7\n10D8;GEORGIAN LETTER IN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;1C98;;10D8\n10D9;GEORGIAN LETTER KAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;1C99;;10D9\n10DA;GEORGIAN LETTER LAS;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;1C9A;;10DA\n10DB;GEORGIAN LETTER MAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;1C9B;;10DB\n10DC;GEORGIAN LETTER NAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;1C9C;;10DC\n10DD;GEORGIAN LETTER ON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;1C9D;;10DD\n10DE;GEORGIAN LETTER PAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;1C9E;;10DE\n10DF;GEORGIAN LETTER ZHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;1C9F;;10DF\n10E0;GEORGIAN LETTER RAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;1CA0;;10E0\n10E1;GEORGIAN LETTER SAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;1CA1;;10E1\n10E2;GEORGIAN LETTER TAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;1CA2;;10E2\n10E3;GEORGIAN LETTER UN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;1CA3;;10E3\n10E4;GEORGIAN LETTER PHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;1CA4;;10E4\n10E5;GEORGIAN LETTER KHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;1CA5;;10E5\n10E6;GEORGIAN LETTER GHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;1CA6;;10E6\n10E7;GEORGIAN LETTER QAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;1CA7;;10E7\n10E8;GEORGIAN LETTER SHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;1CA8;;10E8\n10E9;GEORGIAN LETTER CHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;1CA9;;10E9\n10EA;GEORGIAN LETTER CAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;1CAA;;10EA\n10EB;GEORGIAN LETTER JIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;1CAB;;10EB\n10EC;GEORGIAN LETTER CIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;1CAC;;10EC\n10ED;GEORGIAN LETTER CHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;1CAD;;10ED\n10EE;GEORGIAN LETTER XAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;1CAE;;10EE\n10EF;GEORGIAN LETTER JHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;1CAF;;10EF\n10F0;GEORGIAN LETTER HAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;1CB0;;10F0\n10F1;GEORGIAN LETTER HE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;1CB1;;10F1\n10F2;GEORGIAN LETTER HIE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;1CB2;;10F2\n10F3;GEORGIAN LETTER WE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;1CB3;;10F3\n10F4;GEORGIAN LETTER HAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;1CB4;;10F4\n10F5;GEORGIAN LETTER HOE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;1CB5;;10F5\n10F6;GEORGIAN LETTER FI;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;1CB6;;10F6\n10F7;GEORGIAN LETTER YN;Ll;0;L;;;;;N;;;1CB7;;10F7\n10F8;GEORGIAN LETTER ELIFI;Ll;0;L;;;;;N;;;1CB8;;10F8\n10F9;GEORGIAN LETTER TURNED GAN;Ll;0;L;;;;;N;;;1CB9;;10F9\n10FA;GEORGIAN LETTER AIN;Ll;0;L;;;;;N;;;1CBA;;10FA\n10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;\n10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;;\n10FD;GEORGIAN LETTER AEN;Ll;0;L;;;;;N;;;1CBD;;10FD\n10FE;GEORGIAN LETTER HARD SIGN;Ll;0;L;;;;;N;;;1CBE;;10FE\n10FF;GEORGIAN LETTER LABIAL SIGN;Ll;0;L;;;;;N;;;1CBF;;10FF\n1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;;\n1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;;\n1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;;;;\n1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;;;;\n1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;;;;\n1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;;;;\n1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;;;;\n1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;;;;\n1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;;;;\n1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;;;;\n110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;;;;\n110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;;\n110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;;;;\n110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;;;;\n110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;;;;\n110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;;;;\n1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;;;;\n1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;;;;\n1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;;;;\n1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;\n1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;;\n1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;\n1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;;\n1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;\n1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;\n1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;\n111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;;\n111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;;\n111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;\n111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;\n111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;\n111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;;\n1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;\n1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;;\n1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;\n1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;\n1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;;\n1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;;\n1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;;\n1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;;\n1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;;\n1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;;\n112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;\n112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;\n112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;;\n112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;\n112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;;\n112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;\n1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;\n1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;;\n1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;\n1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;\n1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;;\n1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;;\n1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;;\n1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;;\n1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;;\n1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;\n113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;;\n113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;;\n113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;;\n113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;\n113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;;\n113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;\n1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;;\n1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;\n1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;;\n1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;;\n1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;;\n1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;;\n1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;\n1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;\n1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;;\n1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;;\n114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;;\n114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;;\n114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;\n114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;;\n114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;;\n114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;\n1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;;\n1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;\n1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;;\n1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;;\n1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;;\n1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;;\n1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;\n1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;\n1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;;\n1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;\n115A;HANGUL CHOSEONG KIYEOK-TIKEUT;Lo;0;L;;;;;N;;;;;\n115B;HANGUL CHOSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;;\n115C;HANGUL CHOSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;;;;\n115D;HANGUL CHOSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;;;;\n115E;HANGUL CHOSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;;\n115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;;\n1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;;\n1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;;\n1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;;\n1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;;\n1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;;\n1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;;\n1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;;\n1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;;\n1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;;\n1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;;\n116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;;\n116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;;\n116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;;\n116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;;\n116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;;\n116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;;\n1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;;\n1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;;\n1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;;\n1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;;\n1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;;\n1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;;\n1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;;\n1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;;\n1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;;\n1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;;\n117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;;\n117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;;\n117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;;\n117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;;\n117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;;\n117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;;\n1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;;\n1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;;\n1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;;\n1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;;\n1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;;\n1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;;\n1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;;\n1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;;\n1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;;\n1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;;\n118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;;\n118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;;\n118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;;\n118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;;\n118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;;\n118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;;\n1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;;\n1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;;\n1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;;\n1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;;\n1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;;\n1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;;\n1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;;\n1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;;\n1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;;\n1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;;\n119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;;\n119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;;\n119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;;\n119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;;\n119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;;\n119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;;\n11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;;\n11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;;\n11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;;\n11A3;HANGUL JUNGSEONG A-EU;Lo;0;L;;;;;N;;;;;\n11A4;HANGUL JUNGSEONG YA-U;Lo;0;L;;;;;N;;;;;\n11A5;HANGUL JUNGSEONG YEO-YA;Lo;0;L;;;;;N;;;;;\n11A6;HANGUL JUNGSEONG O-YA;Lo;0;L;;;;;N;;;;;\n11A7;HANGUL JUNGSEONG O-YAE;Lo;0;L;;;;;N;;;;;\n11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;;;;\n11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;;\n11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;;;;\n11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;;;;\n11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;;;;\n11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;;;;\n11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;;;;\n11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;;;;\n11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;;;;\n11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;;;;\n11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;;;;\n11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;;;;\n11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;;;;\n11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;;;;\n11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;;\n11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;;;;\n11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;;;;\n11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;;\n11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;;;;\n11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;;;;\n11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;;;;\n11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;;;;\n11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;;;;\n11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;;;;\n11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;;;;\n11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;;;;\n11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;;;;\n11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;;\n11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;\n11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;\n11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;\n11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;;\n11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;;\n11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;;\n11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;\n11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;;\n11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;;\n11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;\n11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;;\n11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;;\n11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;\n11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;\n11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;;\n11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;;\n11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;\n11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;\n11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;;\n11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;;\n11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;\n11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;;\n11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;\n11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;;\n11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;\n11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;;\n11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;;\n11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;;\n11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;;\n11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;;\n11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;\n11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;;\n11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;\n11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;\n11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;\n11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;\n11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;\n11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;\n11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;\n11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;;\n11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;\n11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;\n11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;\n11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;;\n11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;\n11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;;\n11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;\n11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;\n11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;\n11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;;\n11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;;\n11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;;\n11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;;\n11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;\n11FA;HANGUL JONGSEONG KIYEOK-NIEUN;Lo;0;L;;;;;N;;;;;\n11FB;HANGUL JONGSEONG KIYEOK-PIEUP;Lo;0;L;;;;;N;;;;;\n11FC;HANGUL JONGSEONG KIYEOK-CHIEUCH;Lo;0;L;;;;;N;;;;;\n11FD;HANGUL JONGSEONG KIYEOK-KHIEUKH;Lo;0;L;;;;;N;;;;;\n11FE;HANGUL JONGSEONG KIYEOK-HIEUH;Lo;0;L;;;;;N;;;;;\n11FF;HANGUL JONGSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;;\n1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;;\n1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;;\n1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;;\n1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;;\n1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;;\n1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;;\n1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;;\n1207;ETHIOPIC SYLLABLE HOA;Lo;0;L;;;;;N;;;;;\n1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;;\n1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;;\n120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;;\n120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;;\n120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;;\n120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;;\n120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;;\n120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;;\n1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;;\n1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;;\n1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;;\n1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;;\n1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;;\n1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;;\n1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;;\n1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;;\n1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;;\n1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;;\n121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;;\n121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;;\n121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;;\n121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;;\n121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;;\n121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;;\n1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;;\n1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;;\n1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;;\n1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;;\n1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;;\n1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;;\n1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;;\n1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;;\n1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;;\n1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;;\n122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;;\n122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;;\n122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;;\n122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;;\n122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;;\n122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;;\n1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;;\n1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;;\n1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;;\n1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;;\n1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;;\n1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;;\n1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;;\n1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;;\n1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;;\n1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;;\n123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;;\n123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;;\n123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;;\n123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;;\n123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;;\n123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;;\n1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;;\n1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;;\n1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;;\n1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;;\n1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;;\n1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;;\n1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;;\n1247;ETHIOPIC SYLLABLE QOA;Lo;0;L;;;;;N;;;;;\n1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;;\n124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;;\n124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;;\n124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;;\n124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;;\n1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;;\n1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;;\n1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;;\n1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;;\n1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;;\n1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;;\n1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;;\n1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;;\n125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;;\n125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;;\n125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;;\n125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;;\n1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;;\n1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;;\n1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;;\n1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;;\n1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;;\n1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;;\n1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;;\n1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;;\n1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;;\n1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;;\n126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;;\n126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;;\n126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;;\n126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;;\n126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;;\n126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;;\n1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;;\n1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;;\n1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;;\n1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;;\n1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;;\n1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;;\n1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;;\n1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;;\n1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;;\n1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;;\n127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;;\n127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;;\n127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;;\n127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;;\n127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;;\n127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;;\n1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;;\n1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;;\n1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;;\n1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;;\n1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;;\n1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;;\n1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;;\n1287;ETHIOPIC SYLLABLE XOA;Lo;0;L;;;;;N;;;;;\n1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;;\n128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;;\n128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;;\n128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;;\n128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;;\n1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;;\n1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;;\n1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;;\n1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;;\n1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;;\n1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;;\n1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;;\n1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;;\n1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;;\n1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;;\n129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;;\n129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;;\n129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;;\n129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;;\n129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;;\n129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;;\n12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;;\n12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;;\n12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;;\n12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;;\n12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;;\n12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;;\n12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;;\n12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;;\n12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;;\n12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;;\n12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;;\n12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;;\n12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;;\n12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;;\n12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;;\n12AF;ETHIOPIC SYLLABLE KOA;Lo;0;L;;;;;N;;;;;\n12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;;\n12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;;\n12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;;\n12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;;\n12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;;\n12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;;\n12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;;\n12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;;\n12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;;\n12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;;\n12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;;\n12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;;\n12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;;\n12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;;\n12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;;\n12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;;\n12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;;\n12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;;\n12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;;\n12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;;\n12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;;\n12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;;\n12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;;\n12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;;\n12CF;ETHIOPIC SYLLABLE WOA;Lo;0;L;;;;;N;;;;;\n12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;;\n12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;;\n12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;;\n12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;;\n12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;;\n12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;;\n12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;;\n12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;;\n12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;;\n12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;;\n12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;;\n12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;;\n12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;;\n12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;;\n12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;;\n12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;\n12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;\n12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;;\n12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;;\n12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;;\n12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;\n12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;\n12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;;\n12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;;\n12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;;\n12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;;\n12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;;\n12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;;\n12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;;\n12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;;\n12EF;ETHIOPIC SYLLABLE YOA;Lo;0;L;;;;;N;;;;;\n12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;;\n12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;;\n12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;;\n12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;;\n12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;;\n12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;;\n12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;;\n12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;;\n12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;;\n12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;;\n12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;;\n12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;;\n12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;;\n12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;;\n12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;;\n12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;;\n1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;;\n1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;;\n1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;;\n1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;;\n1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;;\n1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;;\n1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;;\n1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;;\n1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;;\n1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;;\n130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;;\n130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;;\n130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;;\n130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;;\n130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;;\n130F;ETHIOPIC SYLLABLE GOA;Lo;0;L;;;;;N;;;;;\n1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;;\n1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;;\n1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;;\n1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;;\n1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;;\n1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;;\n1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;;\n131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;;\n131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;;\n131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;;\n131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;;\n131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;;\n131F;ETHIOPIC SYLLABLE GGWAA;Lo;0;L;;;;;N;;;;;\n1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;;\n1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;;\n1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;;\n1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;;\n1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;;\n1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;;\n1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;;\n1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;;\n1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;;\n1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;;\n132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;;\n132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;;\n132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;;\n132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;;\n132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;;\n132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;;\n1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;;\n1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;;\n1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;;\n1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;;\n1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;;\n1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;;\n1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;;\n1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;;\n1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;;\n1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;;\n133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;;\n133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;;\n133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;;\n133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;;\n133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;;\n133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;;\n1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;;\n1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;;\n1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;;\n1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;;\n1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;;\n1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;;\n1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;;\n1347;ETHIOPIC SYLLABLE TZOA;Lo;0;L;;;;;N;;;;;\n1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;;\n1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;;\n134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;;\n134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;;\n134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;;\n134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;;\n134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;;\n134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;;\n1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;;\n1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;;\n1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;;\n1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;;\n1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;;\n1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;;\n1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;;\n1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;;\n1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;;\n1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;;\n135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;;\n135D;ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;;\n135E;ETHIOPIC COMBINING VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;;\n135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;;\n1360;ETHIOPIC SECTION MARK;Po;0;L;;;;;N;;;;;\n1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;;\n1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;;\n1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;;\n1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;;\n1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;;\n1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;;\n1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;;\n1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;\n1369;ETHIOPIC DIGIT ONE;No;0;L;;;1;1;N;;;;;\n136A;ETHIOPIC DIGIT TWO;No;0;L;;;2;2;N;;;;;\n136B;ETHIOPIC DIGIT THREE;No;0;L;;;3;3;N;;;;;\n136C;ETHIOPIC DIGIT FOUR;No;0;L;;;4;4;N;;;;;\n136D;ETHIOPIC DIGIT FIVE;No;0;L;;;5;5;N;;;;;\n136E;ETHIOPIC DIGIT SIX;No;0;L;;;6;6;N;;;;;\n136F;ETHIOPIC DIGIT SEVEN;No;0;L;;;7;7;N;;;;;\n1370;ETHIOPIC DIGIT EIGHT;No;0;L;;;8;8;N;;;;;\n1371;ETHIOPIC DIGIT NINE;No;0;L;;;9;9;N;;;;;\n1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;;\n1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;;\n1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;;\n1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;;\n1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;;\n1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;;\n1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;;\n1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;;\n137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;;\n137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;;\n137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;\n1380;ETHIOPIC SYLLABLE SEBATBEIT MWA;Lo;0;L;;;;;N;;;;;\n1381;ETHIOPIC SYLLABLE MWI;Lo;0;L;;;;;N;;;;;\n1382;ETHIOPIC SYLLABLE MWEE;Lo;0;L;;;;;N;;;;;\n1383;ETHIOPIC SYLLABLE MWE;Lo;0;L;;;;;N;;;;;\n1384;ETHIOPIC SYLLABLE SEBATBEIT BWA;Lo;0;L;;;;;N;;;;;\n1385;ETHIOPIC SYLLABLE BWI;Lo;0;L;;;;;N;;;;;\n1386;ETHIOPIC SYLLABLE BWEE;Lo;0;L;;;;;N;;;;;\n1387;ETHIOPIC SYLLABLE BWE;Lo;0;L;;;;;N;;;;;\n1388;ETHIOPIC SYLLABLE SEBATBEIT FWA;Lo;0;L;;;;;N;;;;;\n1389;ETHIOPIC SYLLABLE FWI;Lo;0;L;;;;;N;;;;;\n138A;ETHIOPIC SYLLABLE FWEE;Lo;0;L;;;;;N;;;;;\n138B;ETHIOPIC SYLLABLE FWE;Lo;0;L;;;;;N;;;;;\n138C;ETHIOPIC SYLLABLE SEBATBEIT PWA;Lo;0;L;;;;;N;;;;;\n138D;ETHIOPIC SYLLABLE PWI;Lo;0;L;;;;;N;;;;;\n138E;ETHIOPIC SYLLABLE PWEE;Lo;0;L;;;;;N;;;;;\n138F;ETHIOPIC SYLLABLE PWE;Lo;0;L;;;;;N;;;;;\n1390;ETHIOPIC TONAL MARK YIZET;So;0;ON;;;;;N;;;;;\n1391;ETHIOPIC TONAL MARK DERET;So;0;ON;;;;;N;;;;;\n1392;ETHIOPIC TONAL MARK RIKRIK;So;0;ON;;;;;N;;;;;\n1393;ETHIOPIC TONAL MARK SHORT RIKRIK;So;0;ON;;;;;N;;;;;\n1394;ETHIOPIC TONAL MARK DIFAT;So;0;ON;;;;;N;;;;;\n1395;ETHIOPIC TONAL MARK KENAT;So;0;ON;;;;;N;;;;;\n1396;ETHIOPIC TONAL MARK CHIRET;So;0;ON;;;;;N;;;;;\n1397;ETHIOPIC TONAL MARK HIDET;So;0;ON;;;;;N;;;;;\n1398;ETHIOPIC TONAL MARK DERET-HIDET;So;0;ON;;;;;N;;;;;\n1399;ETHIOPIC TONAL MARK KURT;So;0;ON;;;;;N;;;;;\n13A0;CHEROKEE LETTER A;Lu;0;L;;;;;N;;;;AB70;\n13A1;CHEROKEE LETTER E;Lu;0;L;;;;;N;;;;AB71;\n13A2;CHEROKEE LETTER I;Lu;0;L;;;;;N;;;;AB72;\n13A3;CHEROKEE LETTER O;Lu;0;L;;;;;N;;;;AB73;\n13A4;CHEROKEE LETTER U;Lu;0;L;;;;;N;;;;AB74;\n13A5;CHEROKEE LETTER V;Lu;0;L;;;;;N;;;;AB75;\n13A6;CHEROKEE LETTER GA;Lu;0;L;;;;;N;;;;AB76;\n13A7;CHEROKEE LETTER KA;Lu;0;L;;;;;N;;;;AB77;\n13A8;CHEROKEE LETTER GE;Lu;0;L;;;;;N;;;;AB78;\n13A9;CHEROKEE LETTER GI;Lu;0;L;;;;;N;;;;AB79;\n13AA;CHEROKEE LETTER GO;Lu;0;L;;;;;N;;;;AB7A;\n13AB;CHEROKEE LETTER GU;Lu;0;L;;;;;N;;;;AB7B;\n13AC;CHEROKEE LETTER GV;Lu;0;L;;;;;N;;;;AB7C;\n13AD;CHEROKEE LETTER HA;Lu;0;L;;;;;N;;;;AB7D;\n13AE;CHEROKEE LETTER HE;Lu;0;L;;;;;N;;;;AB7E;\n13AF;CHEROKEE LETTER HI;Lu;0;L;;;;;N;;;;AB7F;\n13B0;CHEROKEE LETTER HO;Lu;0;L;;;;;N;;;;AB80;\n13B1;CHEROKEE LETTER HU;Lu;0;L;;;;;N;;;;AB81;\n13B2;CHEROKEE LETTER HV;Lu;0;L;;;;;N;;;;AB82;\n13B3;CHEROKEE LETTER LA;Lu;0;L;;;;;N;;;;AB83;\n13B4;CHEROKEE LETTER LE;Lu;0;L;;;;;N;;;;AB84;\n13B5;CHEROKEE LETTER LI;Lu;0;L;;;;;N;;;;AB85;\n13B6;CHEROKEE LETTER LO;Lu;0;L;;;;;N;;;;AB86;\n13B7;CHEROKEE LETTER LU;Lu;0;L;;;;;N;;;;AB87;\n13B8;CHEROKEE LETTER LV;Lu;0;L;;;;;N;;;;AB88;\n13B9;CHEROKEE LETTER MA;Lu;0;L;;;;;N;;;;AB89;\n13BA;CHEROKEE LETTER ME;Lu;0;L;;;;;N;;;;AB8A;\n13BB;CHEROKEE LETTER MI;Lu;0;L;;;;;N;;;;AB8B;\n13BC;CHEROKEE LETTER MO;Lu;0;L;;;;;N;;;;AB8C;\n13BD;CHEROKEE LETTER MU;Lu;0;L;;;;;N;;;;AB8D;\n13BE;CHEROKEE LETTER NA;Lu;0;L;;;;;N;;;;AB8E;\n13BF;CHEROKEE LETTER HNA;Lu;0;L;;;;;N;;;;AB8F;\n13C0;CHEROKEE LETTER NAH;Lu;0;L;;;;;N;;;;AB90;\n13C1;CHEROKEE LETTER NE;Lu;0;L;;;;;N;;;;AB91;\n13C2;CHEROKEE LETTER NI;Lu;0;L;;;;;N;;;;AB92;\n13C3;CHEROKEE LETTER NO;Lu;0;L;;;;;N;;;;AB93;\n13C4;CHEROKEE LETTER NU;Lu;0;L;;;;;N;;;;AB94;\n13C5;CHEROKEE LETTER NV;Lu;0;L;;;;;N;;;;AB95;\n13C6;CHEROKEE LETTER QUA;Lu;0;L;;;;;N;;;;AB96;\n13C7;CHEROKEE LETTER QUE;Lu;0;L;;;;;N;;;;AB97;\n13C8;CHEROKEE LETTER QUI;Lu;0;L;;;;;N;;;;AB98;\n13C9;CHEROKEE LETTER QUO;Lu;0;L;;;;;N;;;;AB99;\n13CA;CHEROKEE LETTER QUU;Lu;0;L;;;;;N;;;;AB9A;\n13CB;CHEROKEE LETTER QUV;Lu;0;L;;;;;N;;;;AB9B;\n13CC;CHEROKEE LETTER SA;Lu;0;L;;;;;N;;;;AB9C;\n13CD;CHEROKEE LETTER S;Lu;0;L;;;;;N;;;;AB9D;\n13CE;CHEROKEE LETTER SE;Lu;0;L;;;;;N;;;;AB9E;\n13CF;CHEROKEE LETTER SI;Lu;0;L;;;;;N;;;;AB9F;\n13D0;CHEROKEE LETTER SO;Lu;0;L;;;;;N;;;;ABA0;\n13D1;CHEROKEE LETTER SU;Lu;0;L;;;;;N;;;;ABA1;\n13D2;CHEROKEE LETTER SV;Lu;0;L;;;;;N;;;;ABA2;\n13D3;CHEROKEE LETTER DA;Lu;0;L;;;;;N;;;;ABA3;\n13D4;CHEROKEE LETTER TA;Lu;0;L;;;;;N;;;;ABA4;\n13D5;CHEROKEE LETTER DE;Lu;0;L;;;;;N;;;;ABA5;\n13D6;CHEROKEE LETTER TE;Lu;0;L;;;;;N;;;;ABA6;\n13D7;CHEROKEE LETTER DI;Lu;0;L;;;;;N;;;;ABA7;\n13D8;CHEROKEE LETTER TI;Lu;0;L;;;;;N;;;;ABA8;\n13D9;CHEROKEE LETTER DO;Lu;0;L;;;;;N;;;;ABA9;\n13DA;CHEROKEE LETTER DU;Lu;0;L;;;;;N;;;;ABAA;\n13DB;CHEROKEE LETTER DV;Lu;0;L;;;;;N;;;;ABAB;\n13DC;CHEROKEE LETTER DLA;Lu;0;L;;;;;N;;;;ABAC;\n13DD;CHEROKEE LETTER TLA;Lu;0;L;;;;;N;;;;ABAD;\n13DE;CHEROKEE LETTER TLE;Lu;0;L;;;;;N;;;;ABAE;\n13DF;CHEROKEE LETTER TLI;Lu;0;L;;;;;N;;;;ABAF;\n13E0;CHEROKEE LETTER TLO;Lu;0;L;;;;;N;;;;ABB0;\n13E1;CHEROKEE LETTER TLU;Lu;0;L;;;;;N;;;;ABB1;\n13E2;CHEROKEE LETTER TLV;Lu;0;L;;;;;N;;;;ABB2;\n13E3;CHEROKEE LETTER TSA;Lu;0;L;;;;;N;;;;ABB3;\n13E4;CHEROKEE LETTER TSE;Lu;0;L;;;;;N;;;;ABB4;\n13E5;CHEROKEE LETTER TSI;Lu;0;L;;;;;N;;;;ABB5;\n13E6;CHEROKEE LETTER TSO;Lu;0;L;;;;;N;;;;ABB6;\n13E7;CHEROKEE LETTER TSU;Lu;0;L;;;;;N;;;;ABB7;\n13E8;CHEROKEE LETTER TSV;Lu;0;L;;;;;N;;;;ABB8;\n13E9;CHEROKEE LETTER WA;Lu;0;L;;;;;N;;;;ABB9;\n13EA;CHEROKEE LETTER WE;Lu;0;L;;;;;N;;;;ABBA;\n13EB;CHEROKEE LETTER WI;Lu;0;L;;;;;N;;;;ABBB;\n13EC;CHEROKEE LETTER WO;Lu;0;L;;;;;N;;;;ABBC;\n13ED;CHEROKEE LETTER WU;Lu;0;L;;;;;N;;;;ABBD;\n13EE;CHEROKEE LETTER WV;Lu;0;L;;;;;N;;;;ABBE;\n13EF;CHEROKEE LETTER YA;Lu;0;L;;;;;N;;;;ABBF;\n13F0;CHEROKEE LETTER YE;Lu;0;L;;;;;N;;;;13F8;\n13F1;CHEROKEE LETTER YI;Lu;0;L;;;;;N;;;;13F9;\n13F2;CHEROKEE LETTER YO;Lu;0;L;;;;;N;;;;13FA;\n13F3;CHEROKEE LETTER YU;Lu;0;L;;;;;N;;;;13FB;\n13F4;CHEROKEE LETTER YV;Lu;0;L;;;;;N;;;;13FC;\n13F5;CHEROKEE LETTER MV;Lu;0;L;;;;;N;;;;13FD;\n13F8;CHEROKEE SMALL LETTER YE;Ll;0;L;;;;;N;;;13F0;;13F0\n13F9;CHEROKEE SMALL LETTER YI;Ll;0;L;;;;;N;;;13F1;;13F1\n13FA;CHEROKEE SMALL LETTER YO;Ll;0;L;;;;;N;;;13F2;;13F2\n13FB;CHEROKEE SMALL LETTER YU;Ll;0;L;;;;;N;;;13F3;;13F3\n13FC;CHEROKEE SMALL LETTER YV;Ll;0;L;;;;;N;;;13F4;;13F4\n13FD;CHEROKEE SMALL LETTER MV;Ll;0;L;;;;;N;;;13F5;;13F5\n1400;CANADIAN SYLLABICS HYPHEN;Pd;0;ON;;;;;N;;;;;\n1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;;\n1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;;\n1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;;\n1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;;\n1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;;\n1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;;\n1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;;\n1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;;\n1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;;\n140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;;\n140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;;\n140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;;\n140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;;\n140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;;\n140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;;\n1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;;\n1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;;\n1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;;\n1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;;\n1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;;\n1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;;\n1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;;\n1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;;\n1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;;\n1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;;\n141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;;\n141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;;\n141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;;\n141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;;\n141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;;\n141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;;\n1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;;\n1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;;\n1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;;\n1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;;\n1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;;\n1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;;\n1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;;\n1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;;\n1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;;\n1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;;\n142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;;\n142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;;\n142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;;\n142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;;\n142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;;\n142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;;\n1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;;\n1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;;\n1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;;\n1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;;\n1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;;\n1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;;\n1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;;\n1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;;\n1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;;\n1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;;\n143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;;\n143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;;\n143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;;\n143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;;\n143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;;\n143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;;\n1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;;\n1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;;\n1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;;\n1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;;\n1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;;\n1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;;\n1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;;\n1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;;\n1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;;\n1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;;\n144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;;\n144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;;\n144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;;\n144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;;\n144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;;\n144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;;\n1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;;\n1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;;\n1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;;\n1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;;\n1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;;\n1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;;\n1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;;\n1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;;\n1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;;\n1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;;\n145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;;\n145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;;\n145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;;\n145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;;\n145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;;\n145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;;\n1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;;\n1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;;\n1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;;\n1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;;\n1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;;\n1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;;\n1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;;\n1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;;\n1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;;\n1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;;\n146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;;\n146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;;\n146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;;\n146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;;\n146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;;\n146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;;\n1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;;\n1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;;\n1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;;\n1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;;\n1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;;\n1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;;\n1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;;\n1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;;\n1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;;\n1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;;\n147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;;\n147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;;\n147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;;\n147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;;\n147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;;\n147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;;\n1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;;\n1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;;\n1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;;\n1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;;\n1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;;\n1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;;\n1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;;\n1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;;\n1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;;\n1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;;\n148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;;\n148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;;\n148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;;\n148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;;\n148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;;\n148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;;\n1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;;\n1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;;\n1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;;\n1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;;\n1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;;\n1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;;\n1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;;\n1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;;\n1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;;\n1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;;\n149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;;\n149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;;\n149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;;\n149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;;\n149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;;\n149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;;\n14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;;\n14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;;\n14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;;\n14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;;\n14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;;\n14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;;\n14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;;\n14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;;\n14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;;\n14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;;\n14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;;\n14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;;\n14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;;\n14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;;\n14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;;\n14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;;\n14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;;\n14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;;\n14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;;\n14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;;\n14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;;\n14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;;\n14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;;\n14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;;\n14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;;\n14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;;\n14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;;\n14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;;\n14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;;\n14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;;\n14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;;\n14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;;\n14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;;\n14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;;\n14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;;\n14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;;\n14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;;\n14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;;\n14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;;\n14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;;\n14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;;\n14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;;\n14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;;\n14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;;\n14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;;\n14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;;\n14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;;\n14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;;\n14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;;\n14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;;\n14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;;\n14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;;\n14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;;\n14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;;\n14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;;\n14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;;\n14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;;\n14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;;\n14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;;\n14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;;\n14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;;\n14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;;\n14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;;\n14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;;\n14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;;\n14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;;\n14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;;\n14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;;\n14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;;\n14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;;\n14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;;\n14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;;\n14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;;\n14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;;\n14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;;\n14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;;\n14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;;\n14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;;\n14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;;\n14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;;\n14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;;\n14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;;\n14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;;\n14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;;\n14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;;\n14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;;\n14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;;\n14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;;\n14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;;\n14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;;\n14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;;\n14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;;\n14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;;\n14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;;\n14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;;\n14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;;\n1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;;\n1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;;\n1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;;\n1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;;\n1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;;\n1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;;\n1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;;\n1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;;\n1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;;\n1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;;\n150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;;\n150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;;\n150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;;\n150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;;\n150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;;\n150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;;\n1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;;\n1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;;\n1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;;\n1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;;\n1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;;\n1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;;\n1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;;\n1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;;\n1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;;\n1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;;\n151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;;\n151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;;\n151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;;\n151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;;\n151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;;\n151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;;\n1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;;\n1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;;\n1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;;\n1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;;\n1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;;\n1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;;\n1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;;\n1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;;\n1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;;\n1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;;\n152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;;\n152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;;\n152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;;\n152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;;\n152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;;\n152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;;\n1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;;\n1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;;\n1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;;\n1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;;\n1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;;\n1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;;\n1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;;\n1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;;\n1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;;\n1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;;\n153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;;\n153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;;\n153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;;\n153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;;\n153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;;\n153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;;\n1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;;\n1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;;\n1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;;\n1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;;\n1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;;\n1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;;\n1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;;\n1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;;\n1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;;\n1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;;\n154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;;\n154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;;\n154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;;\n154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;;\n154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;;\n154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;;\n1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;;\n1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;;\n1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;;\n1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;;\n1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;;\n1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;;\n1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;;\n1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;;\n1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;;\n1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;;\n155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;;\n155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;;\n155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;;\n155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;;\n155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;;\n155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;;\n1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;;\n1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;;\n1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;;\n1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;;\n1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;;\n1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;;\n1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;;\n1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;;\n1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;;\n1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;;\n156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;;\n156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;;\n156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;;\n156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;;\n156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;;\n156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;;\n1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;;\n1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;;\n1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;;\n1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;;\n1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;;\n1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;;\n1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;;\n1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;;\n1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;;\n1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;;\n157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;;\n157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;;\n157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;;\n157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;;\n157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;;\n157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;;\n1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;;\n1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;;\n1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;;\n1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;;\n1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;;\n1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;;\n1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;;\n1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;;\n1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;;\n1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;;\n158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;;\n158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;;\n158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;;\n158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;;\n158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;;\n158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;;\n1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;;\n1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;;\n1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;;\n1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;;\n1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;;\n1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;;\n1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;;\n1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;;\n1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;;\n1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;;\n159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;;\n159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;;\n159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;;\n159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;;\n159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;;\n159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;;\n15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;;\n15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;;\n15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;;\n15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;;\n15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;;\n15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;;\n15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;;\n15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;;\n15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;;\n15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;;\n15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;;\n15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;;\n15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;;\n15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;;\n15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;;\n15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;;\n15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;;\n15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;;\n15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;;\n15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;;\n15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;;\n15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;;\n15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;;\n15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;;\n15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;;\n15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;;\n15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;;\n15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;;\n15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;;\n15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;;\n15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;;\n15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;;\n15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;;\n15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;;\n15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;;\n15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;;\n15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;;\n15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;;\n15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;;\n15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;;\n15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;;\n15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;;\n15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;;\n15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;;\n15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;;\n15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;;\n15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;;\n15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;;\n15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;;\n15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;;\n15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;;\n15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;;\n15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;;\n15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;;\n15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;;\n15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;;\n15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;;\n15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;;\n15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;;\n15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;;\n15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;;\n15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;;\n15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;;\n15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;;\n15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;;\n15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;;\n15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;;\n15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;;\n15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;;\n15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;;\n15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;;\n15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;;\n15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;;\n15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;;\n15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;;\n15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;;\n15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;;\n15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;;\n15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;;\n15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;;\n15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;;\n15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;;\n15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;;\n15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;;\n15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;;\n15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;;\n15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;;\n15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;;\n15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;;\n15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;;\n15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;;\n15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;;\n15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;;\n15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;;\n15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;;\n15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;;\n1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;;\n1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;;\n1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;;\n1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;;\n1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;;\n1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;;\n1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;;\n1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;;\n1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;;\n1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;;\n160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;;\n160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;;\n160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;;\n160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;;\n160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;;\n160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;;\n1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;;\n1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;;\n1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;;\n1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;;\n1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;;\n1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;;\n1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;;\n1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;;\n1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;;\n1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;;\n161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;;\n161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;;\n161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;;\n161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;;\n161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;;\n161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;;\n1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;;\n1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;;\n1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;;\n1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;;\n1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;;\n1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;;\n1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;;\n1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;;\n1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;;\n1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;;\n162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;;\n162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;;\n162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;;\n162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;;\n162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;;\n162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;;\n1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;;\n1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;;\n1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;;\n1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;;\n1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;;\n1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;;\n1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;;\n1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;;\n1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;;\n1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;;\n163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;;\n163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;;\n163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;;\n163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;;\n163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;;\n163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;;\n1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;;\n1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;;\n1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;;\n1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;;\n1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;;\n1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;;\n1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;;\n1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;;\n1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;;\n1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;;\n164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;;\n164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;;\n164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;;\n164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;;\n164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;;\n164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;;\n1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;;\n1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;;\n1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;;\n1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;;\n1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;;\n1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;;\n1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;;\n1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;;\n1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;;\n1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;;\n165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;;\n165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;;\n165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;;\n165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;;\n165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;;\n165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;;\n1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;;\n1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;;\n1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;;\n1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;;\n1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;;\n1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;;\n1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;;\n1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;;\n1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;;\n1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;;\n166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;;\n166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;;\n166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;;\n166D;CANADIAN SYLLABICS CHI SIGN;So;0;L;;;;;N;;;;;\n166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;;\n166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;;\n1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;;\n1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;;\n1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;;\n1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;;\n1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;;\n1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;;\n1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;;\n1677;CANADIAN SYLLABICS WOODS-CREE THWEE;Lo;0;L;;;;;N;;;;;\n1678;CANADIAN SYLLABICS WOODS-CREE THWI;Lo;0;L;;;;;N;;;;;\n1679;CANADIAN SYLLABICS WOODS-CREE THWII;Lo;0;L;;;;;N;;;;;\n167A;CANADIAN SYLLABICS WOODS-CREE THWO;Lo;0;L;;;;;N;;;;;\n167B;CANADIAN SYLLABICS WOODS-CREE THWOO;Lo;0;L;;;;;N;;;;;\n167C;CANADIAN SYLLABICS WOODS-CREE THWA;Lo;0;L;;;;;N;;;;;\n167D;CANADIAN SYLLABICS WOODS-CREE THWAA;Lo;0;L;;;;;N;;;;;\n167E;CANADIAN SYLLABICS WOODS-CREE FINAL TH;Lo;0;L;;;;;N;;;;;\n167F;CANADIAN SYLLABICS BLACKFOOT W;Lo;0;L;;;;;N;;;;;\n1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;\n1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;;\n1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;;\n1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;;\n1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;;\n1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;;\n1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;;\n1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;;\n1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;;\n1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;;\n168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;;\n168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;;\n168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;;\n168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;;\n168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;;\n168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;;\n1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;;\n1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;;\n1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;;\n1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;;\n1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;;\n1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;;\n1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;;\n1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;;\n1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;;\n1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;;\n169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;;\n169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;Y;;;;;\n169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;Y;;;;;\n16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;;\n16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;;\n16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;;\n16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;;\n16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;;\n16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;;\n16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;;\n16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;;\n16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;;\n16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;;\n16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;;\n16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;;\n16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;;\n16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;;\n16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;;\n16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;;\n16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;;\n16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;;\n16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;;\n16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;;\n16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;;\n16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;;\n16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;;\n16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;;\n16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;;\n16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;;\n16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;;\n16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;;\n16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;;\n16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;;\n16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;;\n16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;;\n16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;;\n16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;;\n16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;;\n16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;;\n16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;;\n16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;;\n16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;;\n16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;;\n16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;;\n16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;;\n16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;;\n16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;;\n16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;;\n16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;;\n16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;;\n16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;;\n16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;;\n16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;;\n16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;;\n16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;;\n16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;;\n16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;;\n16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;;\n16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;;\n16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;;\n16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;;\n16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;;\n16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;;\n16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;;\n16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;;\n16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;;\n16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;;\n16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;;\n16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;;\n16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;;\n16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;;\n16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;;\n16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;;\n16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;;\n16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;;\n16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;;\n16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;;\n16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;;\n16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;\n16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;;\n16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;;\n16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;;;;\n16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;;;;\n16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;;;;\n16F1;RUNIC LETTER K;Lo;0;L;;;;;N;;;;;\n16F2;RUNIC LETTER SH;Lo;0;L;;;;;N;;;;;\n16F3;RUNIC LETTER OO;Lo;0;L;;;;;N;;;;;\n16F4;RUNIC LETTER FRANKS CASKET OS;Lo;0;L;;;;;N;;;;;\n16F5;RUNIC LETTER FRANKS CASKET IS;Lo;0;L;;;;;N;;;;;\n16F6;RUNIC LETTER FRANKS CASKET EH;Lo;0;L;;;;;N;;;;;\n16F7;RUNIC LETTER FRANKS CASKET AC;Lo;0;L;;;;;N;;;;;\n16F8;RUNIC LETTER FRANKS CASKET AESC;Lo;0;L;;;;;N;;;;;\n1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;;\n1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;;\n1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;;\n1703;TAGALOG LETTER KA;Lo;0;L;;;;;N;;;;;\n1704;TAGALOG LETTER GA;Lo;0;L;;;;;N;;;;;\n1705;TAGALOG LETTER NGA;Lo;0;L;;;;;N;;;;;\n1706;TAGALOG LETTER TA;Lo;0;L;;;;;N;;;;;\n1707;TAGALOG LETTER DA;Lo;0;L;;;;;N;;;;;\n1708;TAGALOG LETTER NA;Lo;0;L;;;;;N;;;;;\n1709;TAGALOG LETTER PA;Lo;0;L;;;;;N;;;;;\n170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;;\n170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;;\n170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;;\n170D;TAGALOG LETTER RA;Lo;0;L;;;;;N;;;;;\n170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;;\n170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;;\n1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;;\n1711;TAGALOG LETTER HA;Lo;0;L;;;;;N;;;;;\n1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n1715;TAGALOG SIGN PAMUDPOD;Mc;9;L;;;;;N;;;;;\n171F;TAGALOG LETTER ARCHAIC RA;Lo;0;L;;;;;N;;;;;\n1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;;\n1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;;\n1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;;\n1723;HANUNOO LETTER KA;Lo;0;L;;;;;N;;;;;\n1724;HANUNOO LETTER GA;Lo;0;L;;;;;N;;;;;\n1725;HANUNOO LETTER NGA;Lo;0;L;;;;;N;;;;;\n1726;HANUNOO LETTER TA;Lo;0;L;;;;;N;;;;;\n1727;HANUNOO LETTER DA;Lo;0;L;;;;;N;;;;;\n1728;HANUNOO LETTER NA;Lo;0;L;;;;;N;;;;;\n1729;HANUNOO LETTER PA;Lo;0;L;;;;;N;;;;;\n172A;HANUNOO LETTER BA;Lo;0;L;;;;;N;;;;;\n172B;HANUNOO LETTER MA;Lo;0;L;;;;;N;;;;;\n172C;HANUNOO LETTER YA;Lo;0;L;;;;;N;;;;;\n172D;HANUNOO LETTER RA;Lo;0;L;;;;;N;;;;;\n172E;HANUNOO LETTER LA;Lo;0;L;;;;;N;;;;;\n172F;HANUNOO LETTER WA;Lo;0;L;;;;;N;;;;;\n1730;HANUNOO LETTER SA;Lo;0;L;;;;;N;;;;;\n1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;;\n1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1734;HANUNOO SIGN PAMUDPOD;Mc;9;L;;;;;N;;;;;\n1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;\n1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;;\n1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;;\n1741;BUHID LETTER I;Lo;0;L;;;;;N;;;;;\n1742;BUHID LETTER U;Lo;0;L;;;;;N;;;;;\n1743;BUHID LETTER KA;Lo;0;L;;;;;N;;;;;\n1744;BUHID LETTER GA;Lo;0;L;;;;;N;;;;;\n1745;BUHID LETTER NGA;Lo;0;L;;;;;N;;;;;\n1746;BUHID LETTER TA;Lo;0;L;;;;;N;;;;;\n1747;BUHID LETTER DA;Lo;0;L;;;;;N;;;;;\n1748;BUHID LETTER NA;Lo;0;L;;;;;N;;;;;\n1749;BUHID LETTER PA;Lo;0;L;;;;;N;;;;;\n174A;BUHID LETTER BA;Lo;0;L;;;;;N;;;;;\n174B;BUHID LETTER MA;Lo;0;L;;;;;N;;;;;\n174C;BUHID LETTER YA;Lo;0;L;;;;;N;;;;;\n174D;BUHID LETTER RA;Lo;0;L;;;;;N;;;;;\n174E;BUHID LETTER LA;Lo;0;L;;;;;N;;;;;\n174F;BUHID LETTER WA;Lo;0;L;;;;;N;;;;;\n1750;BUHID LETTER SA;Lo;0;L;;;;;N;;;;;\n1751;BUHID LETTER HA;Lo;0;L;;;;;N;;;;;\n1752;BUHID VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n1753;BUHID VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1760;TAGBANWA LETTER A;Lo;0;L;;;;;N;;;;;\n1761;TAGBANWA LETTER I;Lo;0;L;;;;;N;;;;;\n1762;TAGBANWA LETTER U;Lo;0;L;;;;;N;;;;;\n1763;TAGBANWA LETTER KA;Lo;0;L;;;;;N;;;;;\n1764;TAGBANWA LETTER GA;Lo;0;L;;;;;N;;;;;\n1765;TAGBANWA LETTER NGA;Lo;0;L;;;;;N;;;;;\n1766;TAGBANWA LETTER TA;Lo;0;L;;;;;N;;;;;\n1767;TAGBANWA LETTER DA;Lo;0;L;;;;;N;;;;;\n1768;TAGBANWA LETTER NA;Lo;0;L;;;;;N;;;;;\n1769;TAGBANWA LETTER PA;Lo;0;L;;;;;N;;;;;\n176A;TAGBANWA LETTER BA;Lo;0;L;;;;;N;;;;;\n176B;TAGBANWA LETTER MA;Lo;0;L;;;;;N;;;;;\n176C;TAGBANWA LETTER YA;Lo;0;L;;;;;N;;;;;\n176E;TAGBANWA LETTER LA;Lo;0;L;;;;;N;;;;;\n176F;TAGBANWA LETTER WA;Lo;0;L;;;;;N;;;;;\n1770;TAGBANWA LETTER SA;Lo;0;L;;;;;N;;;;;\n1772;TAGBANWA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n1773;TAGBANWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;;\n1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;;\n1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;;\n1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;;\n1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;;\n1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;;\n1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;;\n1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;;\n1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;;\n1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;;\n178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;;\n178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;;\n178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;;\n178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;;\n178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;;\n178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;;\n1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;;\n1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;;\n1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;;\n1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;;\n1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;;\n1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;;\n1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;;\n1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;;\n1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;;\n1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;;\n179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;;\n179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;;\n179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;;\n179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;;\n179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;;\n179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;;\n17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;;\n17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;;\n17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;;\n17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;;;;\n17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;;;;\n17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;;\n17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;;\n17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;;\n17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;;\n17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;;\n17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;;\n17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;;\n17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;;\n17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;;\n17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;;\n17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;;\n17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;;\n17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;;\n17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;;\n17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;;\n17B4;KHMER VOWEL INHERENT AQ;Mn;0;NSM;;;;;N;;;;;\n17B5;KHMER VOWEL INHERENT AA;Mn;0;NSM;;;;;N;;;;;\n17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;\n17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;\n17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;;\n17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;;\n17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;;\n17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;;\n17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;\n17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;\n17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;;\n17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;;\n17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;;\n17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;;\n17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;;\n17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;;\n17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;;\n17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;;\n17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;;\n17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;;\n17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;;\n17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;;\n17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;;\n17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;;;;\n17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;;\n17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;;\n17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;;\n17D7;KHMER SIGN LEK TOO;Lm;0;L;;;;;N;;;;;\n17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;;;;\n17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;;\n17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;;\n17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;;\n17DC;KHMER SIGN AVAKRAHASANYA;Lo;0;L;;;;;N;;;;;\n17DD;KHMER SIGN ATTHACAN;Mn;230;NSM;;;;;N;;;;;\n17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n17F0;KHMER SYMBOL LEK ATTAK SON;No;0;ON;;;;0;N;;;;;\n17F1;KHMER SYMBOL LEK ATTAK MUOY;No;0;ON;;;;1;N;;;;;\n17F2;KHMER SYMBOL LEK ATTAK PII;No;0;ON;;;;2;N;;;;;\n17F3;KHMER SYMBOL LEK ATTAK BEI;No;0;ON;;;;3;N;;;;;\n17F4;KHMER SYMBOL LEK ATTAK BUON;No;0;ON;;;;4;N;;;;;\n17F5;KHMER SYMBOL LEK ATTAK PRAM;No;0;ON;;;;5;N;;;;;\n17F6;KHMER SYMBOL LEK ATTAK PRAM-MUOY;No;0;ON;;;;6;N;;;;;\n17F7;KHMER SYMBOL LEK ATTAK PRAM-PII;No;0;ON;;;;7;N;;;;;\n17F8;KHMER SYMBOL LEK ATTAK PRAM-BEI;No;0;ON;;;;8;N;;;;;\n17F9;KHMER SYMBOL LEK ATTAK PRAM-BUON;No;0;ON;;;;9;N;;;;;\n1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;;\n1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;;\n1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;;\n1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;;\n1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;;\n1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;;\n1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;;\n1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;;\n1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;;\n1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;;\n180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;;\n180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;;\n180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;;\n180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;;\n180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;;\n180F;MONGOLIAN FREE VARIATION SELECTOR FOUR;Mn;0;NSM;;;;;N;;;;;\n1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;;\n1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;;\n1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;;\n1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;;\n1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;;\n1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;;\n1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;;\n1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;;\n1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;;\n1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;;\n182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;;\n182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;;\n182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;;\n182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;;\n182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;;\n182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;;\n1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;;\n1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;;\n1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;;\n1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;;\n1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;;\n1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;;\n1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;;\n1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;;\n1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;;\n1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;;\n183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;;\n183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;;\n183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;;\n183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;;\n183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;;\n183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;;\n1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;;\n1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;;\n1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;;\n1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;;\n1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;;\n1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;;\n1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;;\n1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;;\n1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;;\n1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;;\n184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;;\n184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;;\n184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;;\n184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;;\n184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;;\n184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;;\n1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;;\n1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;;\n1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;;\n1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;;\n1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;;\n1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;;\n1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;;\n1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;;\n1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;;\n1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;;\n185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;;\n185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;;\n185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;;\n185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;;\n185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;;\n185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;;\n1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;;\n1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;;\n1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;;\n1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;;\n1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;;\n1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;;\n1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;;\n1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;;\n1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;;\n1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;;\n186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;;\n186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;;\n186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;;\n186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;;\n186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;;\n186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;;\n1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;;\n1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;;\n1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;;\n1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;;\n1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;;\n1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;;\n1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;;\n1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;;\n1878;MONGOLIAN LETTER CHA WITH TWO DOTS;Lo;0;L;;;;;N;;;;;\n1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;;\n1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;;\n1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;;\n1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;;\n1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;;\n1885;MONGOLIAN LETTER ALI GALI BALUDA;Mn;0;NSM;;;;;N;;;;;\n1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Mn;0;NSM;;;;;N;;;;;\n1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;;\n1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;;\n1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;;\n188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;;\n188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;;\n188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;;\n188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;;\n188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;;\n188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;;\n1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;;\n1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;;\n1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;;\n1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;;\n1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;;\n1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;;\n1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;;\n1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;;\n1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;;\n1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;;\n189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;;\n189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;;\n189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;;\n189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;;\n189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;;\n189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;;\n18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;;\n18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;;\n18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;;\n18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;;\n18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;;\n18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;;\n18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;;\n18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;;\n18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;;\n18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;;\n18AA;MONGOLIAN LETTER MANCHU ALI GALI LHA;Lo;0;L;;;;;N;;;;;\n18B0;CANADIAN SYLLABICS OY;Lo;0;L;;;;;N;;;;;\n18B1;CANADIAN SYLLABICS AY;Lo;0;L;;;;;N;;;;;\n18B2;CANADIAN SYLLABICS AAY;Lo;0;L;;;;;N;;;;;\n18B3;CANADIAN SYLLABICS WAY;Lo;0;L;;;;;N;;;;;\n18B4;CANADIAN SYLLABICS POY;Lo;0;L;;;;;N;;;;;\n18B5;CANADIAN SYLLABICS PAY;Lo;0;L;;;;;N;;;;;\n18B6;CANADIAN SYLLABICS PWOY;Lo;0;L;;;;;N;;;;;\n18B7;CANADIAN SYLLABICS TAY;Lo;0;L;;;;;N;;;;;\n18B8;CANADIAN SYLLABICS KAY;Lo;0;L;;;;;N;;;;;\n18B9;CANADIAN SYLLABICS KWAY;Lo;0;L;;;;;N;;;;;\n18BA;CANADIAN SYLLABICS MAY;Lo;0;L;;;;;N;;;;;\n18BB;CANADIAN SYLLABICS NOY;Lo;0;L;;;;;N;;;;;\n18BC;CANADIAN SYLLABICS NAY;Lo;0;L;;;;;N;;;;;\n18BD;CANADIAN SYLLABICS LAY;Lo;0;L;;;;;N;;;;;\n18BE;CANADIAN SYLLABICS SOY;Lo;0;L;;;;;N;;;;;\n18BF;CANADIAN SYLLABICS SAY;Lo;0;L;;;;;N;;;;;\n18C0;CANADIAN SYLLABICS SHOY;Lo;0;L;;;;;N;;;;;\n18C1;CANADIAN SYLLABICS SHAY;Lo;0;L;;;;;N;;;;;\n18C2;CANADIAN SYLLABICS SHWOY;Lo;0;L;;;;;N;;;;;\n18C3;CANADIAN SYLLABICS YOY;Lo;0;L;;;;;N;;;;;\n18C4;CANADIAN SYLLABICS YAY;Lo;0;L;;;;;N;;;;;\n18C5;CANADIAN SYLLABICS RAY;Lo;0;L;;;;;N;;;;;\n18C6;CANADIAN SYLLABICS NWI;Lo;0;L;;;;;N;;;;;\n18C7;CANADIAN SYLLABICS OJIBWAY NWI;Lo;0;L;;;;;N;;;;;\n18C8;CANADIAN SYLLABICS NWII;Lo;0;L;;;;;N;;;;;\n18C9;CANADIAN SYLLABICS OJIBWAY NWII;Lo;0;L;;;;;N;;;;;\n18CA;CANADIAN SYLLABICS NWO;Lo;0;L;;;;;N;;;;;\n18CB;CANADIAN SYLLABICS OJIBWAY NWO;Lo;0;L;;;;;N;;;;;\n18CC;CANADIAN SYLLABICS NWOO;Lo;0;L;;;;;N;;;;;\n18CD;CANADIAN SYLLABICS OJIBWAY NWOO;Lo;0;L;;;;;N;;;;;\n18CE;CANADIAN SYLLABICS RWEE;Lo;0;L;;;;;N;;;;;\n18CF;CANADIAN SYLLABICS RWI;Lo;0;L;;;;;N;;;;;\n18D0;CANADIAN SYLLABICS RWII;Lo;0;L;;;;;N;;;;;\n18D1;CANADIAN SYLLABICS RWO;Lo;0;L;;;;;N;;;;;\n18D2;CANADIAN SYLLABICS RWOO;Lo;0;L;;;;;N;;;;;\n18D3;CANADIAN SYLLABICS RWA;Lo;0;L;;;;;N;;;;;\n18D4;CANADIAN SYLLABICS OJIBWAY P;Lo;0;L;;;;;N;;;;;\n18D5;CANADIAN SYLLABICS OJIBWAY T;Lo;0;L;;;;;N;;;;;\n18D6;CANADIAN SYLLABICS OJIBWAY K;Lo;0;L;;;;;N;;;;;\n18D7;CANADIAN SYLLABICS OJIBWAY C;Lo;0;L;;;;;N;;;;;\n18D8;CANADIAN SYLLABICS OJIBWAY M;Lo;0;L;;;;;N;;;;;\n18D9;CANADIAN SYLLABICS OJIBWAY N;Lo;0;L;;;;;N;;;;;\n18DA;CANADIAN SYLLABICS OJIBWAY S;Lo;0;L;;;;;N;;;;;\n18DB;CANADIAN SYLLABICS OJIBWAY SH;Lo;0;L;;;;;N;;;;;\n18DC;CANADIAN SYLLABICS EASTERN W;Lo;0;L;;;;;N;;;;;\n18DD;CANADIAN SYLLABICS WESTERN W;Lo;0;L;;;;;N;;;;;\n18DE;CANADIAN SYLLABICS FINAL SMALL RING;Lo;0;L;;;;;N;;;;;\n18DF;CANADIAN SYLLABICS FINAL RAISED DOT;Lo;0;L;;;;;N;;;;;\n18E0;CANADIAN SYLLABICS R-CREE RWE;Lo;0;L;;;;;N;;;;;\n18E1;CANADIAN SYLLABICS WEST-CREE LOO;Lo;0;L;;;;;N;;;;;\n18E2;CANADIAN SYLLABICS WEST-CREE LAA;Lo;0;L;;;;;N;;;;;\n18E3;CANADIAN SYLLABICS THWE;Lo;0;L;;;;;N;;;;;\n18E4;CANADIAN SYLLABICS THWA;Lo;0;L;;;;;N;;;;;\n18E5;CANADIAN SYLLABICS TTHWE;Lo;0;L;;;;;N;;;;;\n18E6;CANADIAN SYLLABICS TTHOO;Lo;0;L;;;;;N;;;;;\n18E7;CANADIAN SYLLABICS TTHAA;Lo;0;L;;;;;N;;;;;\n18E8;CANADIAN SYLLABICS TLHWE;Lo;0;L;;;;;N;;;;;\n18E9;CANADIAN SYLLABICS TLHOO;Lo;0;L;;;;;N;;;;;\n18EA;CANADIAN SYLLABICS SAYISI SHWE;Lo;0;L;;;;;N;;;;;\n18EB;CANADIAN SYLLABICS SAYISI SHOO;Lo;0;L;;;;;N;;;;;\n18EC;CANADIAN SYLLABICS SAYISI HOO;Lo;0;L;;;;;N;;;;;\n18ED;CANADIAN SYLLABICS CARRIER GWU;Lo;0;L;;;;;N;;;;;\n18EE;CANADIAN SYLLABICS CARRIER DENE GEE;Lo;0;L;;;;;N;;;;;\n18EF;CANADIAN SYLLABICS CARRIER GAA;Lo;0;L;;;;;N;;;;;\n18F0;CANADIAN SYLLABICS CARRIER GWA;Lo;0;L;;;;;N;;;;;\n18F1;CANADIAN SYLLABICS SAYISI JUU;Lo;0;L;;;;;N;;;;;\n18F2;CANADIAN SYLLABICS CARRIER JWA;Lo;0;L;;;;;N;;;;;\n18F3;CANADIAN SYLLABICS BEAVER DENE L;Lo;0;L;;;;;N;;;;;\n18F4;CANADIAN SYLLABICS BEAVER DENE R;Lo;0;L;;;;;N;;;;;\n18F5;CANADIAN SYLLABICS CARRIER DENTAL S;Lo;0;L;;;;;N;;;;;\n1900;LIMBU VOWEL-CARRIER LETTER;Lo;0;L;;;;;N;;;;;\n1901;LIMBU LETTER KA;Lo;0;L;;;;;N;;;;;\n1902;LIMBU LETTER KHA;Lo;0;L;;;;;N;;;;;\n1903;LIMBU LETTER GA;Lo;0;L;;;;;N;;;;;\n1904;LIMBU LETTER GHA;Lo;0;L;;;;;N;;;;;\n1905;LIMBU LETTER NGA;Lo;0;L;;;;;N;;;;;\n1906;LIMBU LETTER CA;Lo;0;L;;;;;N;;;;;\n1907;LIMBU LETTER CHA;Lo;0;L;;;;;N;;;;;\n1908;LIMBU LETTER JA;Lo;0;L;;;;;N;;;;;\n1909;LIMBU LETTER JHA;Lo;0;L;;;;;N;;;;;\n190A;LIMBU LETTER YAN;Lo;0;L;;;;;N;;;;;\n190B;LIMBU LETTER TA;Lo;0;L;;;;;N;;;;;\n190C;LIMBU LETTER THA;Lo;0;L;;;;;N;;;;;\n190D;LIMBU LETTER DA;Lo;0;L;;;;;N;;;;;\n190E;LIMBU LETTER DHA;Lo;0;L;;;;;N;;;;;\n190F;LIMBU LETTER NA;Lo;0;L;;;;;N;;;;;\n1910;LIMBU LETTER PA;Lo;0;L;;;;;N;;;;;\n1911;LIMBU LETTER PHA;Lo;0;L;;;;;N;;;;;\n1912;LIMBU LETTER BA;Lo;0;L;;;;;N;;;;;\n1913;LIMBU LETTER BHA;Lo;0;L;;;;;N;;;;;\n1914;LIMBU LETTER MA;Lo;0;L;;;;;N;;;;;\n1915;LIMBU LETTER YA;Lo;0;L;;;;;N;;;;;\n1916;LIMBU LETTER RA;Lo;0;L;;;;;N;;;;;\n1917;LIMBU LETTER LA;Lo;0;L;;;;;N;;;;;\n1918;LIMBU LETTER WA;Lo;0;L;;;;;N;;;;;\n1919;LIMBU LETTER SHA;Lo;0;L;;;;;N;;;;;\n191A;LIMBU LETTER SSA;Lo;0;L;;;;;N;;;;;\n191B;LIMBU LETTER SA;Lo;0;L;;;;;N;;;;;\n191C;LIMBU LETTER HA;Lo;0;L;;;;;N;;;;;\n191D;LIMBU LETTER GYAN;Lo;0;L;;;;;N;;;;;\n191E;LIMBU LETTER TRA;Lo;0;L;;;;;N;;;;;\n1920;LIMBU VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;;\n1921;LIMBU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n1922;LIMBU VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1923;LIMBU VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;\n1924;LIMBU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n1925;LIMBU VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;\n1926;LIMBU VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n1927;LIMBU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n1928;LIMBU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n1929;LIMBU SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;;\n192A;LIMBU SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;;\n192B;LIMBU SUBJOINED LETTER WA;Mc;0;L;;;;;N;;;;;\n1930;LIMBU SMALL LETTER KA;Mc;0;L;;;;;N;;;;;\n1931;LIMBU SMALL LETTER NGA;Mc;0;L;;;;;N;;;;;\n1932;LIMBU SMALL LETTER ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n1933;LIMBU SMALL LETTER TA;Mc;0;L;;;;;N;;;;;\n1934;LIMBU SMALL LETTER NA;Mc;0;L;;;;;N;;;;;\n1935;LIMBU SMALL LETTER PA;Mc;0;L;;;;;N;;;;;\n1936;LIMBU SMALL LETTER MA;Mc;0;L;;;;;N;;;;;\n1937;LIMBU SMALL LETTER RA;Mc;0;L;;;;;N;;;;;\n1938;LIMBU SMALL LETTER LA;Mc;0;L;;;;;N;;;;;\n1939;LIMBU SIGN MUKPHRENG;Mn;222;NSM;;;;;N;;;;;\n193A;LIMBU SIGN KEMPHRENG;Mn;230;NSM;;;;;N;;;;;\n193B;LIMBU SIGN SA-I;Mn;220;NSM;;;;;N;;;;;\n1940;LIMBU SIGN LOO;So;0;ON;;;;;N;;;;;\n1944;LIMBU EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;\n1945;LIMBU QUESTION MARK;Po;0;ON;;;;;N;;;;;\n1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1950;TAI LE LETTER KA;Lo;0;L;;;;;N;;;;;\n1951;TAI LE LETTER XA;Lo;0;L;;;;;N;;;;;\n1952;TAI LE LETTER NGA;Lo;0;L;;;;;N;;;;;\n1953;TAI LE LETTER TSA;Lo;0;L;;;;;N;;;;;\n1954;TAI LE LETTER SA;Lo;0;L;;;;;N;;;;;\n1955;TAI LE LETTER YA;Lo;0;L;;;;;N;;;;;\n1956;TAI LE LETTER TA;Lo;0;L;;;;;N;;;;;\n1957;TAI LE LETTER THA;Lo;0;L;;;;;N;;;;;\n1958;TAI LE LETTER LA;Lo;0;L;;;;;N;;;;;\n1959;TAI LE LETTER PA;Lo;0;L;;;;;N;;;;;\n195A;TAI LE LETTER PHA;Lo;0;L;;;;;N;;;;;\n195B;TAI LE LETTER MA;Lo;0;L;;;;;N;;;;;\n195C;TAI LE LETTER FA;Lo;0;L;;;;;N;;;;;\n195D;TAI LE LETTER VA;Lo;0;L;;;;;N;;;;;\n195E;TAI LE LETTER HA;Lo;0;L;;;;;N;;;;;\n195F;TAI LE LETTER QA;Lo;0;L;;;;;N;;;;;\n1960;TAI LE LETTER KHA;Lo;0;L;;;;;N;;;;;\n1961;TAI LE LETTER TSHA;Lo;0;L;;;;;N;;;;;\n1962;TAI LE LETTER NA;Lo;0;L;;;;;N;;;;;\n1963;TAI LE LETTER A;Lo;0;L;;;;;N;;;;;\n1964;TAI LE LETTER I;Lo;0;L;;;;;N;;;;;\n1965;TAI LE LETTER EE;Lo;0;L;;;;;N;;;;;\n1966;TAI LE LETTER EH;Lo;0;L;;;;;N;;;;;\n1967;TAI LE LETTER U;Lo;0;L;;;;;N;;;;;\n1968;TAI LE LETTER OO;Lo;0;L;;;;;N;;;;;\n1969;TAI LE LETTER O;Lo;0;L;;;;;N;;;;;\n196A;TAI LE LETTER UE;Lo;0;L;;;;;N;;;;;\n196B;TAI LE LETTER E;Lo;0;L;;;;;N;;;;;\n196C;TAI LE LETTER AUE;Lo;0;L;;;;;N;;;;;\n196D;TAI LE LETTER AI;Lo;0;L;;;;;N;;;;;\n1970;TAI LE LETTER TONE-2;Lo;0;L;;;;;N;;;;;\n1971;TAI LE LETTER TONE-3;Lo;0;L;;;;;N;;;;;\n1972;TAI LE LETTER TONE-4;Lo;0;L;;;;;N;;;;;\n1973;TAI LE LETTER TONE-5;Lo;0;L;;;;;N;;;;;\n1974;TAI LE LETTER TONE-6;Lo;0;L;;;;;N;;;;;\n1980;NEW TAI LUE LETTER HIGH QA;Lo;0;L;;;;;N;;;;;\n1981;NEW TAI LUE LETTER LOW QA;Lo;0;L;;;;;N;;;;;\n1982;NEW TAI LUE LETTER HIGH KA;Lo;0;L;;;;;N;;;;;\n1983;NEW TAI LUE LETTER HIGH XA;Lo;0;L;;;;;N;;;;;\n1984;NEW TAI LUE LETTER HIGH NGA;Lo;0;L;;;;;N;;;;;\n1985;NEW TAI LUE LETTER LOW KA;Lo;0;L;;;;;N;;;;;\n1986;NEW TAI LUE LETTER LOW XA;Lo;0;L;;;;;N;;;;;\n1987;NEW TAI LUE LETTER LOW NGA;Lo;0;L;;;;;N;;;;;\n1988;NEW TAI LUE LETTER HIGH TSA;Lo;0;L;;;;;N;;;;;\n1989;NEW TAI LUE LETTER HIGH SA;Lo;0;L;;;;;N;;;;;\n198A;NEW TAI LUE LETTER HIGH YA;Lo;0;L;;;;;N;;;;;\n198B;NEW TAI LUE LETTER LOW TSA;Lo;0;L;;;;;N;;;;;\n198C;NEW TAI LUE LETTER LOW SA;Lo;0;L;;;;;N;;;;;\n198D;NEW TAI LUE LETTER LOW YA;Lo;0;L;;;;;N;;;;;\n198E;NEW TAI LUE LETTER HIGH TA;Lo;0;L;;;;;N;;;;;\n198F;NEW TAI LUE LETTER HIGH THA;Lo;0;L;;;;;N;;;;;\n1990;NEW TAI LUE LETTER HIGH NA;Lo;0;L;;;;;N;;;;;\n1991;NEW TAI LUE LETTER LOW TA;Lo;0;L;;;;;N;;;;;\n1992;NEW TAI LUE LETTER LOW THA;Lo;0;L;;;;;N;;;;;\n1993;NEW TAI LUE LETTER LOW NA;Lo;0;L;;;;;N;;;;;\n1994;NEW TAI LUE LETTER HIGH PA;Lo;0;L;;;;;N;;;;;\n1995;NEW TAI LUE LETTER HIGH PHA;Lo;0;L;;;;;N;;;;;\n1996;NEW TAI LUE LETTER HIGH MA;Lo;0;L;;;;;N;;;;;\n1997;NEW TAI LUE LETTER LOW PA;Lo;0;L;;;;;N;;;;;\n1998;NEW TAI LUE LETTER LOW PHA;Lo;0;L;;;;;N;;;;;\n1999;NEW TAI LUE LETTER LOW MA;Lo;0;L;;;;;N;;;;;\n199A;NEW TAI LUE LETTER HIGH FA;Lo;0;L;;;;;N;;;;;\n199B;NEW TAI LUE LETTER HIGH VA;Lo;0;L;;;;;N;;;;;\n199C;NEW TAI LUE LETTER HIGH LA;Lo;0;L;;;;;N;;;;;\n199D;NEW TAI LUE LETTER LOW FA;Lo;0;L;;;;;N;;;;;\n199E;NEW TAI LUE LETTER LOW VA;Lo;0;L;;;;;N;;;;;\n199F;NEW TAI LUE LETTER LOW LA;Lo;0;L;;;;;N;;;;;\n19A0;NEW TAI LUE LETTER HIGH HA;Lo;0;L;;;;;N;;;;;\n19A1;NEW TAI LUE LETTER HIGH DA;Lo;0;L;;;;;N;;;;;\n19A2;NEW TAI LUE LETTER HIGH BA;Lo;0;L;;;;;N;;;;;\n19A3;NEW TAI LUE LETTER LOW HA;Lo;0;L;;;;;N;;;;;\n19A4;NEW TAI LUE LETTER LOW DA;Lo;0;L;;;;;N;;;;;\n19A5;NEW TAI LUE LETTER LOW BA;Lo;0;L;;;;;N;;;;;\n19A6;NEW TAI LUE LETTER HIGH KVA;Lo;0;L;;;;;N;;;;;\n19A7;NEW TAI LUE LETTER HIGH XVA;Lo;0;L;;;;;N;;;;;\n19A8;NEW TAI LUE LETTER LOW KVA;Lo;0;L;;;;;N;;;;;\n19A9;NEW TAI LUE LETTER LOW XVA;Lo;0;L;;;;;N;;;;;\n19AA;NEW TAI LUE LETTER HIGH SUA;Lo;0;L;;;;;N;;;;;\n19AB;NEW TAI LUE LETTER LOW SUA;Lo;0;L;;;;;N;;;;;\n19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Lo;0;L;;;;;N;;;;;\n19B1;NEW TAI LUE VOWEL SIGN AA;Lo;0;L;;;;;N;;;;;\n19B2;NEW TAI LUE VOWEL SIGN II;Lo;0;L;;;;;N;;;;;\n19B3;NEW TAI LUE VOWEL SIGN U;Lo;0;L;;;;;N;;;;;\n19B4;NEW TAI LUE VOWEL SIGN UU;Lo;0;L;;;;;N;;;;;\n19B5;NEW TAI LUE VOWEL SIGN E;Lo;0;L;;;;;N;;;;;\n19B6;NEW TAI LUE VOWEL SIGN AE;Lo;0;L;;;;;N;;;;;\n19B7;NEW TAI LUE VOWEL SIGN O;Lo;0;L;;;;;N;;;;;\n19B8;NEW TAI LUE VOWEL SIGN OA;Lo;0;L;;;;;N;;;;;\n19B9;NEW TAI LUE VOWEL SIGN UE;Lo;0;L;;;;;N;;;;;\n19BA;NEW TAI LUE VOWEL SIGN AY;Lo;0;L;;;;;N;;;;;\n19BB;NEW TAI LUE VOWEL SIGN AAY;Lo;0;L;;;;;N;;;;;\n19BC;NEW TAI LUE VOWEL SIGN UY;Lo;0;L;;;;;N;;;;;\n19BD;NEW TAI LUE VOWEL SIGN OY;Lo;0;L;;;;;N;;;;;\n19BE;NEW TAI LUE VOWEL SIGN OAY;Lo;0;L;;;;;N;;;;;\n19BF;NEW TAI LUE VOWEL SIGN UEY;Lo;0;L;;;;;N;;;;;\n19C0;NEW TAI LUE VOWEL SIGN IY;Lo;0;L;;;;;N;;;;;\n19C1;NEW TAI LUE LETTER FINAL V;Lo;0;L;;;;;N;;;;;\n19C2;NEW TAI LUE LETTER FINAL NG;Lo;0;L;;;;;N;;;;;\n19C3;NEW TAI LUE LETTER FINAL N;Lo;0;L;;;;;N;;;;;\n19C4;NEW TAI LUE LETTER FINAL M;Lo;0;L;;;;;N;;;;;\n19C5;NEW TAI LUE LETTER FINAL K;Lo;0;L;;;;;N;;;;;\n19C6;NEW TAI LUE LETTER FINAL D;Lo;0;L;;;;;N;;;;;\n19C7;NEW TAI LUE LETTER FINAL B;Lo;0;L;;;;;N;;;;;\n19C8;NEW TAI LUE TONE MARK-1;Lo;0;L;;;;;N;;;;;\n19C9;NEW TAI LUE TONE MARK-2;Lo;0;L;;;;;N;;;;;\n19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n19DA;NEW TAI LUE THAM DIGIT ONE;No;0;L;;;1;1;N;;;;;\n19DE;NEW TAI LUE SIGN LAE;So;0;ON;;;;;N;;;;;\n19DF;NEW TAI LUE SIGN LAEV;So;0;ON;;;;;N;;;;;\n19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;;\n19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;;\n19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;;\n19E3;KHMER SYMBOL BEI KOET;So;0;ON;;;;;N;;;;;\n19E4;KHMER SYMBOL BUON KOET;So;0;ON;;;;;N;;;;;\n19E5;KHMER SYMBOL PRAM KOET;So;0;ON;;;;;N;;;;;\n19E6;KHMER SYMBOL PRAM-MUOY KOET;So;0;ON;;;;;N;;;;;\n19E7;KHMER SYMBOL PRAM-PII KOET;So;0;ON;;;;;N;;;;;\n19E8;KHMER SYMBOL PRAM-BEI KOET;So;0;ON;;;;;N;;;;;\n19E9;KHMER SYMBOL PRAM-BUON KOET;So;0;ON;;;;;N;;;;;\n19EA;KHMER SYMBOL DAP KOET;So;0;ON;;;;;N;;;;;\n19EB;KHMER SYMBOL DAP-MUOY KOET;So;0;ON;;;;;N;;;;;\n19EC;KHMER SYMBOL DAP-PII KOET;So;0;ON;;;;;N;;;;;\n19ED;KHMER SYMBOL DAP-BEI KOET;So;0;ON;;;;;N;;;;;\n19EE;KHMER SYMBOL DAP-BUON KOET;So;0;ON;;;;;N;;;;;\n19EF;KHMER SYMBOL DAP-PRAM KOET;So;0;ON;;;;;N;;;;;\n19F0;KHMER SYMBOL TUTEYASAT;So;0;ON;;;;;N;;;;;\n19F1;KHMER SYMBOL MUOY ROC;So;0;ON;;;;;N;;;;;\n19F2;KHMER SYMBOL PII ROC;So;0;ON;;;;;N;;;;;\n19F3;KHMER SYMBOL BEI ROC;So;0;ON;;;;;N;;;;;\n19F4;KHMER SYMBOL BUON ROC;So;0;ON;;;;;N;;;;;\n19F5;KHMER SYMBOL PRAM ROC;So;0;ON;;;;;N;;;;;\n19F6;KHMER SYMBOL PRAM-MUOY ROC;So;0;ON;;;;;N;;;;;\n19F7;KHMER SYMBOL PRAM-PII ROC;So;0;ON;;;;;N;;;;;\n19F8;KHMER SYMBOL PRAM-BEI ROC;So;0;ON;;;;;N;;;;;\n19F9;KHMER SYMBOL PRAM-BUON ROC;So;0;ON;;;;;N;;;;;\n19FA;KHMER SYMBOL DAP ROC;So;0;ON;;;;;N;;;;;\n19FB;KHMER SYMBOL DAP-MUOY ROC;So;0;ON;;;;;N;;;;;\n19FC;KHMER SYMBOL DAP-PII ROC;So;0;ON;;;;;N;;;;;\n19FD;KHMER SYMBOL DAP-BEI ROC;So;0;ON;;;;;N;;;;;\n19FE;KHMER SYMBOL DAP-BUON ROC;So;0;ON;;;;;N;;;;;\n19FF;KHMER SYMBOL DAP-PRAM ROC;So;0;ON;;;;;N;;;;;\n1A00;BUGINESE LETTER KA;Lo;0;L;;;;;N;;;;;\n1A01;BUGINESE LETTER GA;Lo;0;L;;;;;N;;;;;\n1A02;BUGINESE LETTER NGA;Lo;0;L;;;;;N;;;;;\n1A03;BUGINESE LETTER NGKA;Lo;0;L;;;;;N;;;;;\n1A04;BUGINESE LETTER PA;Lo;0;L;;;;;N;;;;;\n1A05;BUGINESE LETTER BA;Lo;0;L;;;;;N;;;;;\n1A06;BUGINESE LETTER MA;Lo;0;L;;;;;N;;;;;\n1A07;BUGINESE LETTER MPA;Lo;0;L;;;;;N;;;;;\n1A08;BUGINESE LETTER TA;Lo;0;L;;;;;N;;;;;\n1A09;BUGINESE LETTER DA;Lo;0;L;;;;;N;;;;;\n1A0A;BUGINESE LETTER NA;Lo;0;L;;;;;N;;;;;\n1A0B;BUGINESE LETTER NRA;Lo;0;L;;;;;N;;;;;\n1A0C;BUGINESE LETTER CA;Lo;0;L;;;;;N;;;;;\n1A0D;BUGINESE LETTER JA;Lo;0;L;;;;;N;;;;;\n1A0E;BUGINESE LETTER NYA;Lo;0;L;;;;;N;;;;;\n1A0F;BUGINESE LETTER NYCA;Lo;0;L;;;;;N;;;;;\n1A10;BUGINESE LETTER YA;Lo;0;L;;;;;N;;;;;\n1A11;BUGINESE LETTER RA;Lo;0;L;;;;;N;;;;;\n1A12;BUGINESE LETTER LA;Lo;0;L;;;;;N;;;;;\n1A13;BUGINESE LETTER VA;Lo;0;L;;;;;N;;;;;\n1A14;BUGINESE LETTER SA;Lo;0;L;;;;;N;;;;;\n1A15;BUGINESE LETTER A;Lo;0;L;;;;;N;;;;;\n1A16;BUGINESE LETTER HA;Lo;0;L;;;;;N;;;;;\n1A17;BUGINESE VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;;\n1A18;BUGINESE VOWEL SIGN U;Mn;220;NSM;;;;;N;;;;;\n1A19;BUGINESE VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n1A1A;BUGINESE VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n1A1B;BUGINESE VOWEL SIGN AE;Mn;0;NSM;;;;;N;;;;;\n1A1E;BUGINESE PALLAWA;Po;0;L;;;;;N;;;;;\n1A1F;BUGINESE END OF SECTION;Po;0;L;;;;;N;;;;;\n1A20;TAI THAM LETTER HIGH KA;Lo;0;L;;;;;N;;;;;\n1A21;TAI THAM LETTER HIGH KHA;Lo;0;L;;;;;N;;;;;\n1A22;TAI THAM LETTER HIGH KXA;Lo;0;L;;;;;N;;;;;\n1A23;TAI THAM LETTER LOW KA;Lo;0;L;;;;;N;;;;;\n1A24;TAI THAM LETTER LOW KXA;Lo;0;L;;;;;N;;;;;\n1A25;TAI THAM LETTER LOW KHA;Lo;0;L;;;;;N;;;;;\n1A26;TAI THAM LETTER NGA;Lo;0;L;;;;;N;;;;;\n1A27;TAI THAM LETTER HIGH CA;Lo;0;L;;;;;N;;;;;\n1A28;TAI THAM LETTER HIGH CHA;Lo;0;L;;;;;N;;;;;\n1A29;TAI THAM LETTER LOW CA;Lo;0;L;;;;;N;;;;;\n1A2A;TAI THAM LETTER LOW SA;Lo;0;L;;;;;N;;;;;\n1A2B;TAI THAM LETTER LOW CHA;Lo;0;L;;;;;N;;;;;\n1A2C;TAI THAM LETTER NYA;Lo;0;L;;;;;N;;;;;\n1A2D;TAI THAM LETTER RATA;Lo;0;L;;;;;N;;;;;\n1A2E;TAI THAM LETTER HIGH RATHA;Lo;0;L;;;;;N;;;;;\n1A2F;TAI THAM LETTER DA;Lo;0;L;;;;;N;;;;;\n1A30;TAI THAM LETTER LOW RATHA;Lo;0;L;;;;;N;;;;;\n1A31;TAI THAM LETTER RANA;Lo;0;L;;;;;N;;;;;\n1A32;TAI THAM LETTER HIGH TA;Lo;0;L;;;;;N;;;;;\n1A33;TAI THAM LETTER HIGH THA;Lo;0;L;;;;;N;;;;;\n1A34;TAI THAM LETTER LOW TA;Lo;0;L;;;;;N;;;;;\n1A35;TAI THAM LETTER LOW THA;Lo;0;L;;;;;N;;;;;\n1A36;TAI THAM LETTER NA;Lo;0;L;;;;;N;;;;;\n1A37;TAI THAM LETTER BA;Lo;0;L;;;;;N;;;;;\n1A38;TAI THAM LETTER HIGH PA;Lo;0;L;;;;;N;;;;;\n1A39;TAI THAM LETTER HIGH PHA;Lo;0;L;;;;;N;;;;;\n1A3A;TAI THAM LETTER HIGH FA;Lo;0;L;;;;;N;;;;;\n1A3B;TAI THAM LETTER LOW PA;Lo;0;L;;;;;N;;;;;\n1A3C;TAI THAM LETTER LOW FA;Lo;0;L;;;;;N;;;;;\n1A3D;TAI THAM LETTER LOW PHA;Lo;0;L;;;;;N;;;;;\n1A3E;TAI THAM LETTER MA;Lo;0;L;;;;;N;;;;;\n1A3F;TAI THAM LETTER LOW YA;Lo;0;L;;;;;N;;;;;\n1A40;TAI THAM LETTER HIGH YA;Lo;0;L;;;;;N;;;;;\n1A41;TAI THAM LETTER RA;Lo;0;L;;;;;N;;;;;\n1A42;TAI THAM LETTER RUE;Lo;0;L;;;;;N;;;;;\n1A43;TAI THAM LETTER LA;Lo;0;L;;;;;N;;;;;\n1A44;TAI THAM LETTER LUE;Lo;0;L;;;;;N;;;;;\n1A45;TAI THAM LETTER WA;Lo;0;L;;;;;N;;;;;\n1A46;TAI THAM LETTER HIGH SHA;Lo;0;L;;;;;N;;;;;\n1A47;TAI THAM LETTER HIGH SSA;Lo;0;L;;;;;N;;;;;\n1A48;TAI THAM LETTER HIGH SA;Lo;0;L;;;;;N;;;;;\n1A49;TAI THAM LETTER HIGH HA;Lo;0;L;;;;;N;;;;;\n1A4A;TAI THAM LETTER LLA;Lo;0;L;;;;;N;;;;;\n1A4B;TAI THAM LETTER A;Lo;0;L;;;;;N;;;;;\n1A4C;TAI THAM LETTER LOW HA;Lo;0;L;;;;;N;;;;;\n1A4D;TAI THAM LETTER I;Lo;0;L;;;;;N;;;;;\n1A4E;TAI THAM LETTER II;Lo;0;L;;;;;N;;;;;\n1A4F;TAI THAM LETTER U;Lo;0;L;;;;;N;;;;;\n1A50;TAI THAM LETTER UU;Lo;0;L;;;;;N;;;;;\n1A51;TAI THAM LETTER EE;Lo;0;L;;;;;N;;;;;\n1A52;TAI THAM LETTER OO;Lo;0;L;;;;;N;;;;;\n1A53;TAI THAM LETTER LAE;Lo;0;L;;;;;N;;;;;\n1A54;TAI THAM LETTER GREAT SA;Lo;0;L;;;;;N;;;;;\n1A55;TAI THAM CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;;\n1A56;TAI THAM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;;\n1A57;TAI THAM CONSONANT SIGN LA TANG LAI;Mc;0;L;;;;;N;;;;;\n1A58;TAI THAM SIGN MAI KANG LAI;Mn;0;NSM;;;;;N;;;;;\n1A59;TAI THAM CONSONANT SIGN FINAL NGA;Mn;0;NSM;;;;;N;;;;;\n1A5A;TAI THAM CONSONANT SIGN LOW PA;Mn;0;NSM;;;;;N;;;;;\n1A5B;TAI THAM CONSONANT SIGN HIGH RATHA OR LOW PA;Mn;0;NSM;;;;;N;;;;;\n1A5C;TAI THAM CONSONANT SIGN MA;Mn;0;NSM;;;;;N;;;;;\n1A5D;TAI THAM CONSONANT SIGN BA;Mn;0;NSM;;;;;N;;;;;\n1A5E;TAI THAM CONSONANT SIGN SA;Mn;0;NSM;;;;;N;;;;;\n1A60;TAI THAM SIGN SAKOT;Mn;9;NSM;;;;;N;;;;;\n1A61;TAI THAM VOWEL SIGN A;Mc;0;L;;;;;N;;;;;\n1A62;TAI THAM VOWEL SIGN MAI SAT;Mn;0;NSM;;;;;N;;;;;\n1A63;TAI THAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n1A64;TAI THAM VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;;\n1A65;TAI THAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n1A66;TAI THAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n1A67;TAI THAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;\n1A68;TAI THAM VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;;\n1A69;TAI THAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1A6A;TAI THAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n1A6B;TAI THAM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n1A6C;TAI THAM VOWEL SIGN OA BELOW;Mn;0;NSM;;;;;N;;;;;\n1A6D;TAI THAM VOWEL SIGN OY;Mc;0;L;;;;;N;;;;;\n1A6E;TAI THAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n1A6F;TAI THAM VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;\n1A70;TAI THAM VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;\n1A71;TAI THAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n1A72;TAI THAM VOWEL SIGN THAM AI;Mc;0;L;;;;;N;;;;;\n1A73;TAI THAM VOWEL SIGN OA ABOVE;Mn;0;NSM;;;;;N;;;;;\n1A74;TAI THAM SIGN MAI KANG;Mn;0;NSM;;;;;N;;;;;\n1A75;TAI THAM SIGN TONE-1;Mn;230;NSM;;;;;N;;;;;\n1A76;TAI THAM SIGN TONE-2;Mn;230;NSM;;;;;N;;;;;\n1A77;TAI THAM SIGN KHUEN TONE-3;Mn;230;NSM;;;;;N;;;;;\n1A78;TAI THAM SIGN KHUEN TONE-4;Mn;230;NSM;;;;;N;;;;;\n1A79;TAI THAM SIGN KHUEN TONE-5;Mn;230;NSM;;;;;N;;;;;\n1A7A;TAI THAM SIGN RA HAAM;Mn;230;NSM;;;;;N;;;;;\n1A7B;TAI THAM SIGN MAI SAM;Mn;230;NSM;;;;;N;;;;;\n1A7C;TAI THAM SIGN KHUEN-LUE KARAN;Mn;230;NSM;;;;;N;;;;;\n1A7F;TAI THAM COMBINING CRYPTOGRAMMIC DOT;Mn;220;NSM;;;;;N;;;;;\n1A80;TAI THAM HORA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1A81;TAI THAM HORA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1A82;TAI THAM HORA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1A83;TAI THAM HORA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1A84;TAI THAM HORA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1A85;TAI THAM HORA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1A86;TAI THAM HORA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1A87;TAI THAM HORA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1A88;TAI THAM HORA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1A89;TAI THAM HORA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1A90;TAI THAM THAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1A91;TAI THAM THAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1A92;TAI THAM THAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1A93;TAI THAM THAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1A94;TAI THAM THAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1A95;TAI THAM THAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1A96;TAI THAM THAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1A97;TAI THAM THAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1A98;TAI THAM THAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1A99;TAI THAM THAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1AA0;TAI THAM SIGN WIANG;Po;0;L;;;;;N;;;;;\n1AA1;TAI THAM SIGN WIANGWAAK;Po;0;L;;;;;N;;;;;\n1AA2;TAI THAM SIGN SAWAN;Po;0;L;;;;;N;;;;;\n1AA3;TAI THAM SIGN KEOW;Po;0;L;;;;;N;;;;;\n1AA4;TAI THAM SIGN HOY;Po;0;L;;;;;N;;;;;\n1AA5;TAI THAM SIGN DOKMAI;Po;0;L;;;;;N;;;;;\n1AA6;TAI THAM SIGN REVERSED ROTATED RANA;Po;0;L;;;;;N;;;;;\n1AA7;TAI THAM SIGN MAI YAMOK;Lm;0;L;;;;;N;;;;;\n1AA8;TAI THAM SIGN KAAN;Po;0;L;;;;;N;;;;;\n1AA9;TAI THAM SIGN KAANKUU;Po;0;L;;;;;N;;;;;\n1AAA;TAI THAM SIGN SATKAAN;Po;0;L;;;;;N;;;;;\n1AAB;TAI THAM SIGN SATKAANKUU;Po;0;L;;;;;N;;;;;\n1AAC;TAI THAM SIGN HANG;Po;0;L;;;;;N;;;;;\n1AAD;TAI THAM SIGN CAANG;Po;0;L;;;;;N;;;;;\n1AB0;COMBINING DOUBLED CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;;;;;\n1AB1;COMBINING DIAERESIS-RING;Mn;230;NSM;;;;;N;;;;;\n1AB2;COMBINING INFINITY;Mn;230;NSM;;;;;N;;;;;\n1AB3;COMBINING DOWNWARDS ARROW;Mn;230;NSM;;;;;N;;;;;\n1AB4;COMBINING TRIPLE DOT;Mn;230;NSM;;;;;N;;;;;\n1AB5;COMBINING X-X BELOW;Mn;220;NSM;;;;;N;;;;;\n1AB6;COMBINING WIGGLY LINE BELOW;Mn;220;NSM;;;;;N;;;;;\n1AB7;COMBINING OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;;\n1AB8;COMBINING DOUBLE OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;;\n1AB9;COMBINING LIGHT CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;;\n1ABA;COMBINING STRONG CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;;\n1ABB;COMBINING PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;;\n1ABC;COMBINING DOUBLE PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;;\n1ABD;COMBINING PARENTHESES BELOW;Mn;220;NSM;;;;;N;;;;;\n1ABE;COMBINING PARENTHESES OVERLAY;Me;0;NSM;;;;;N;;;;;\n1ABF;COMBINING LATIN SMALL LETTER W BELOW;Mn;220;NSM;;;;;N;;;;;\n1AC0;COMBINING LATIN SMALL LETTER TURNED W BELOW;Mn;220;NSM;;;;;N;;;;;\n1AC1;COMBINING LEFT PARENTHESIS ABOVE LEFT;Mn;230;NSM;;;;;N;;;;;\n1AC2;COMBINING RIGHT PARENTHESIS ABOVE RIGHT;Mn;230;NSM;;;;;N;;;;;\n1AC3;COMBINING LEFT PARENTHESIS BELOW LEFT;Mn;220;NSM;;;;;N;;;;;\n1AC4;COMBINING RIGHT PARENTHESIS BELOW RIGHT;Mn;220;NSM;;;;;N;;;;;\n1AC5;COMBINING SQUARE BRACKETS ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AC6;COMBINING NUMBER SIGN ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AC7;COMBINING INVERTED DOUBLE ARCH ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AC8;COMBINING PLUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AC9;COMBINING DOUBLE PLUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;;\n1ACA;COMBINING DOUBLE PLUS SIGN BELOW;Mn;220;NSM;;;;;N;;;;;\n1ACB;COMBINING TRIPLE ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;\n1ACC;COMBINING LATIN SMALL LETTER INSULAR G;Mn;230;NSM;;;;;N;;;;;\n1ACD;COMBINING LATIN SMALL LETTER INSULAR R;Mn;230;NSM;;;;;N;;;;;\n1ACE;COMBINING LATIN SMALL LETTER INSULAR T;Mn;230;NSM;;;;;N;;;;;\n1ACF;COMBINING DOUBLE CARON;Mn;230;NSM;;;;;N;;;;;\n1AD0;COMBINING VERTICAL-LINE-ACUTE;Mn;230;NSM;;;;;N;;;;;\n1AD1;COMBINING GRAVE-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;;\n1AD2;COMBINING VERTICAL-LINE-GRAVE;Mn;230;NSM;;;;;N;;;;;\n1AD3;COMBINING ACUTE-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;;\n1AD4;COMBINING VERTICAL-LINE-MACRON;Mn;230;NSM;;;;;N;;;;;\n1AD5;COMBINING MACRON-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;;\n1AD6;COMBINING VERTICAL-LINE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;;\n1AD7;COMBINING VERTICAL-LINE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;;\n1AD8;COMBINING MACRON-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;;\n1AD9;COMBINING SHARP SIGN;Mn;230;NSM;;;;;N;;;;;\n1ADA;COMBINING FLAT SIGN;Mn;230;NSM;;;;;N;;;;;\n1ADB;COMBINING DOWN TACK ABOVE;Mn;230;NSM;;;;;N;;;;;\n1ADC;COMBINING DIAERESIS WITH RAISED LEFT DOT;Mn;230;NSM;;;;;N;;;;;\n1ADD;COMBINING DOT-AND-RING BELOW;Mn;220;NSM;;;;;N;;;;;\n1AE0;COMBINING LEFT TACK ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AE1;COMBINING RIGHT TACK ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AE2;COMBINING MINUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AE3;COMBINING INVERTED BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AE4;COMBINING SQUARE ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AE5;COMBINING SEAGULL ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AE6;COMBINING DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;;;;;\n1AE7;COMBINING DOUBLE ARCH ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AE8;COMBINING EQUALS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AE9;COMBINING LEFT ANGLE CENTRED ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AEA;COMBINING UPWARDS ARROW ABOVE;Mn;230;NSM;;;;;N;;;;;\n1AEB;COMBINING DOUBLE RIGHTWARDS ARROW ABOVE;Mn;234;NSM;;;;;N;;;;;\n1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;;;;\n1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;;;;\n1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;;;;\n1B03;BALINESE SIGN SURANG;Mn;0;NSM;;;;;N;;;;;\n1B04;BALINESE SIGN BISAH;Mc;0;L;;;;;N;;;;;\n1B05;BALINESE LETTER AKARA;Lo;0;L;;;;;N;;;;;\n1B06;BALINESE LETTER AKARA TEDUNG;Lo;0;L;1B05 1B35;;;;N;;;;;\n1B07;BALINESE LETTER IKARA;Lo;0;L;;;;;N;;;;;\n1B08;BALINESE LETTER IKARA TEDUNG;Lo;0;L;1B07 1B35;;;;N;;;;;\n1B09;BALINESE LETTER UKARA;Lo;0;L;;;;;N;;;;;\n1B0A;BALINESE LETTER UKARA TEDUNG;Lo;0;L;1B09 1B35;;;;N;;;;;\n1B0B;BALINESE LETTER RA REPA;Lo;0;L;;;;;N;;;;;\n1B0C;BALINESE LETTER RA REPA TEDUNG;Lo;0;L;1B0B 1B35;;;;N;;;;;\n1B0D;BALINESE LETTER LA LENGA;Lo;0;L;;;;;N;;;;;\n1B0E;BALINESE LETTER LA LENGA TEDUNG;Lo;0;L;1B0D 1B35;;;;N;;;;;\n1B0F;BALINESE LETTER EKARA;Lo;0;L;;;;;N;;;;;\n1B10;BALINESE LETTER AIKARA;Lo;0;L;;;;;N;;;;;\n1B11;BALINESE LETTER OKARA;Lo;0;L;;;;;N;;;;;\n1B12;BALINESE LETTER OKARA TEDUNG;Lo;0;L;1B11 1B35;;;;N;;;;;\n1B13;BALINESE LETTER KA;Lo;0;L;;;;;N;;;;;\n1B14;BALINESE LETTER KA MAHAPRANA;Lo;0;L;;;;;N;;;;;\n1B15;BALINESE LETTER GA;Lo;0;L;;;;;N;;;;;\n1B16;BALINESE LETTER GA GORA;Lo;0;L;;;;;N;;;;;\n1B17;BALINESE LETTER NGA;Lo;0;L;;;;;N;;;;;\n1B18;BALINESE LETTER CA;Lo;0;L;;;;;N;;;;;\n1B19;BALINESE LETTER CA LACA;Lo;0;L;;;;;N;;;;;\n1B1A;BALINESE LETTER JA;Lo;0;L;;;;;N;;;;;\n1B1B;BALINESE LETTER JA JERA;Lo;0;L;;;;;N;;;;;\n1B1C;BALINESE LETTER NYA;Lo;0;L;;;;;N;;;;;\n1B1D;BALINESE LETTER TA LATIK;Lo;0;L;;;;;N;;;;;\n1B1E;BALINESE LETTER TA MURDA MAHAPRANA;Lo;0;L;;;;;N;;;;;\n1B1F;BALINESE LETTER DA MURDA ALPAPRANA;Lo;0;L;;;;;N;;;;;\n1B20;BALINESE LETTER DA MURDA MAHAPRANA;Lo;0;L;;;;;N;;;;;\n1B21;BALINESE LETTER NA RAMBAT;Lo;0;L;;;;;N;;;;;\n1B22;BALINESE LETTER TA;Lo;0;L;;;;;N;;;;;\n1B23;BALINESE LETTER TA TAWA;Lo;0;L;;;;;N;;;;;\n1B24;BALINESE LETTER DA;Lo;0;L;;;;;N;;;;;\n1B25;BALINESE LETTER DA MADU;Lo;0;L;;;;;N;;;;;\n1B26;BALINESE LETTER NA;Lo;0;L;;;;;N;;;;;\n1B27;BALINESE LETTER PA;Lo;0;L;;;;;N;;;;;\n1B28;BALINESE LETTER PA KAPAL;Lo;0;L;;;;;N;;;;;\n1B29;BALINESE LETTER BA;Lo;0;L;;;;;N;;;;;\n1B2A;BALINESE LETTER BA KEMBANG;Lo;0;L;;;;;N;;;;;\n1B2B;BALINESE LETTER MA;Lo;0;L;;;;;N;;;;;\n1B2C;BALINESE LETTER YA;Lo;0;L;;;;;N;;;;;\n1B2D;BALINESE LETTER RA;Lo;0;L;;;;;N;;;;;\n1B2E;BALINESE LETTER LA;Lo;0;L;;;;;N;;;;;\n1B2F;BALINESE LETTER WA;Lo;0;L;;;;;N;;;;;\n1B30;BALINESE LETTER SA SAGA;Lo;0;L;;;;;N;;;;;\n1B31;BALINESE LETTER SA SAPA;Lo;0;L;;;;;N;;;;;\n1B32;BALINESE LETTER SA;Lo;0;L;;;;;N;;;;;\n1B33;BALINESE LETTER HA;Lo;0;L;;;;;N;;;;;\n1B34;BALINESE SIGN REREKAN;Mn;7;NSM;;;;;N;;;;;\n1B35;BALINESE VOWEL SIGN TEDUNG;Mc;0;L;;;;;N;;;;;\n1B36;BALINESE VOWEL SIGN ULU;Mn;0;NSM;;;;;N;;;;;\n1B37;BALINESE VOWEL SIGN ULU SARI;Mn;0;NSM;;;;;N;;;;;\n1B38;BALINESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;;;;\n1B39;BALINESE VOWEL SIGN SUKU ILUT;Mn;0;NSM;;;;;N;;;;;\n1B3A;BALINESE VOWEL SIGN RA REPA;Mn;0;NSM;;;;;N;;;;;\n1B3B;BALINESE VOWEL SIGN RA REPA TEDUNG;Mc;0;L;1B3A 1B35;;;;N;;;;;\n1B3C;BALINESE VOWEL SIGN LA LENGA;Mn;0;NSM;;;;;N;;;;;\n1B3D;BALINESE VOWEL SIGN LA LENGA TEDUNG;Mc;0;L;1B3C 1B35;;;;N;;;;;\n1B3E;BALINESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;;;;\n1B3F;BALINESE VOWEL SIGN TALING REPA;Mc;0;L;;;;;N;;;;;\n1B40;BALINESE VOWEL SIGN TALING TEDUNG;Mc;0;L;1B3E 1B35;;;;N;;;;;\n1B41;BALINESE VOWEL SIGN TALING REPA TEDUNG;Mc;0;L;1B3F 1B35;;;;N;;;;;\n1B42;BALINESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;;;;\n1B43;BALINESE VOWEL SIGN PEPET TEDUNG;Mc;0;L;1B42 1B35;;;;N;;;;;\n1B44;BALINESE ADEG ADEG;Mc;9;L;;;;;N;;;;;\n1B45;BALINESE LETTER KAF SASAK;Lo;0;L;;;;;N;;;;;\n1B46;BALINESE LETTER KHOT SASAK;Lo;0;L;;;;;N;;;;;\n1B47;BALINESE LETTER TZIR SASAK;Lo;0;L;;;;;N;;;;;\n1B48;BALINESE LETTER EF SASAK;Lo;0;L;;;;;N;;;;;\n1B49;BALINESE LETTER VE SASAK;Lo;0;L;;;;;N;;;;;\n1B4A;BALINESE LETTER ZAL SASAK;Lo;0;L;;;;;N;;;;;\n1B4B;BALINESE LETTER ASYURA SASAK;Lo;0;L;;;;;N;;;;;\n1B4C;BALINESE LETTER ARCHAIC JNYA;Lo;0;L;;;;;N;;;;;\n1B4E;BALINESE INVERTED CARIK SIKI;Po;0;L;;;;;N;;;;;\n1B4F;BALINESE INVERTED CARIK PAREREN;Po;0;L;;;;;N;;;;;\n1B50;BALINESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1B51;BALINESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1B52;BALINESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1B53;BALINESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1B54;BALINESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1B55;BALINESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1B56;BALINESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1B57;BALINESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1B58;BALINESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1B59;BALINESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1B5A;BALINESE PANTI;Po;0;L;;;;;N;;;;;\n1B5B;BALINESE PAMADA;Po;0;L;;;;;N;;;;;\n1B5C;BALINESE WINDU;Po;0;L;;;;;N;;;;;\n1B5D;BALINESE CARIK PAMUNGKAH;Po;0;L;;;;;N;;;;;\n1B5E;BALINESE CARIK SIKI;Po;0;L;;;;;N;;;;;\n1B5F;BALINESE CARIK PAREREN;Po;0;L;;;;;N;;;;;\n1B60;BALINESE PAMENENG;Po;0;L;;;;;N;;;;;\n1B61;BALINESE MUSICAL SYMBOL DONG;So;0;L;;;;;N;;;;;\n1B62;BALINESE MUSICAL SYMBOL DENG;So;0;L;;;;;N;;;;;\n1B63;BALINESE MUSICAL SYMBOL DUNG;So;0;L;;;;;N;;;;;\n1B64;BALINESE MUSICAL SYMBOL DANG;So;0;L;;;;;N;;;;;\n1B65;BALINESE MUSICAL SYMBOL DANG SURANG;So;0;L;;;;;N;;;;;\n1B66;BALINESE MUSICAL SYMBOL DING;So;0;L;;;;;N;;;;;\n1B67;BALINESE MUSICAL SYMBOL DAENG;So;0;L;;;;;N;;;;;\n1B68;BALINESE MUSICAL SYMBOL DEUNG;So;0;L;;;;;N;;;;;\n1B69;BALINESE MUSICAL SYMBOL DAING;So;0;L;;;;;N;;;;;\n1B6A;BALINESE MUSICAL SYMBOL DANG GEDE;So;0;L;;;;;N;;;;;\n1B6B;BALINESE MUSICAL SYMBOL COMBINING TEGEH;Mn;230;NSM;;;;;N;;;;;\n1B6C;BALINESE MUSICAL SYMBOL COMBINING ENDEP;Mn;220;NSM;;;;;N;;;;;\n1B6D;BALINESE MUSICAL SYMBOL COMBINING KEMPUL;Mn;230;NSM;;;;;N;;;;;\n1B6E;BALINESE MUSICAL SYMBOL COMBINING KEMPLI;Mn;230;NSM;;;;;N;;;;;\n1B6F;BALINESE MUSICAL SYMBOL COMBINING JEGOGAN;Mn;230;NSM;;;;;N;;;;;\n1B70;BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;;\n1B71;BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;;\n1B72;BALINESE MUSICAL SYMBOL COMBINING BENDE;Mn;230;NSM;;;;;N;;;;;\n1B73;BALINESE MUSICAL SYMBOL COMBINING GONG;Mn;230;NSM;;;;;N;;;;;\n1B74;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG;So;0;L;;;;;N;;;;;\n1B75;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DAG;So;0;L;;;;;N;;;;;\n1B76;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUK;So;0;L;;;;;N;;;;;\n1B77;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAK;So;0;L;;;;;N;;;;;\n1B78;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANG;So;0;L;;;;;N;;;;;\n1B79;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNG;So;0;L;;;;;N;;;;;\n1B7A;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK;So;0;L;;;;;N;;;;;\n1B7B;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK;So;0;L;;;;;N;;;;;\n1B7C;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING;So;0;L;;;;;N;;;;;\n1B7D;BALINESE PANTI LANTANG;Po;0;L;;;;;N;;;;;\n1B7E;BALINESE PAMADA LANTANG;Po;0;L;;;;;N;;;;;\n1B7F;BALINESE PANTI BAWAK;Po;0;L;;;;;N;;;;;\n1B80;SUNDANESE SIGN PANYECEK;Mn;0;NSM;;;;;N;;;;;\n1B81;SUNDANESE SIGN PANGLAYAR;Mn;0;NSM;;;;;N;;;;;\n1B82;SUNDANESE SIGN PANGWISAD;Mc;0;L;;;;;N;;;;;\n1B83;SUNDANESE LETTER A;Lo;0;L;;;;;N;;;;;\n1B84;SUNDANESE LETTER I;Lo;0;L;;;;;N;;;;;\n1B85;SUNDANESE LETTER U;Lo;0;L;;;;;N;;;;;\n1B86;SUNDANESE LETTER AE;Lo;0;L;;;;;N;;;;;\n1B87;SUNDANESE LETTER O;Lo;0;L;;;;;N;;;;;\n1B88;SUNDANESE LETTER E;Lo;0;L;;;;;N;;;;;\n1B89;SUNDANESE LETTER EU;Lo;0;L;;;;;N;;;;;\n1B8A;SUNDANESE LETTER KA;Lo;0;L;;;;;N;;;;;\n1B8B;SUNDANESE LETTER QA;Lo;0;L;;;;;N;;;;;\n1B8C;SUNDANESE LETTER GA;Lo;0;L;;;;;N;;;;;\n1B8D;SUNDANESE LETTER NGA;Lo;0;L;;;;;N;;;;;\n1B8E;SUNDANESE LETTER CA;Lo;0;L;;;;;N;;;;;\n1B8F;SUNDANESE LETTER JA;Lo;0;L;;;;;N;;;;;\n1B90;SUNDANESE LETTER ZA;Lo;0;L;;;;;N;;;;;\n1B91;SUNDANESE LETTER NYA;Lo;0;L;;;;;N;;;;;\n1B92;SUNDANESE LETTER TA;Lo;0;L;;;;;N;;;;;\n1B93;SUNDANESE LETTER DA;Lo;0;L;;;;;N;;;;;\n1B94;SUNDANESE LETTER NA;Lo;0;L;;;;;N;;;;;\n1B95;SUNDANESE LETTER PA;Lo;0;L;;;;;N;;;;;\n1B96;SUNDANESE LETTER FA;Lo;0;L;;;;;N;;;;;\n1B97;SUNDANESE LETTER VA;Lo;0;L;;;;;N;;;;;\n1B98;SUNDANESE LETTER BA;Lo;0;L;;;;;N;;;;;\n1B99;SUNDANESE LETTER MA;Lo;0;L;;;;;N;;;;;\n1B9A;SUNDANESE LETTER YA;Lo;0;L;;;;;N;;;;;\n1B9B;SUNDANESE LETTER RA;Lo;0;L;;;;;N;;;;;\n1B9C;SUNDANESE LETTER LA;Lo;0;L;;;;;N;;;;;\n1B9D;SUNDANESE LETTER WA;Lo;0;L;;;;;N;;;;;\n1B9E;SUNDANESE LETTER SA;Lo;0;L;;;;;N;;;;;\n1B9F;SUNDANESE LETTER XA;Lo;0;L;;;;;N;;;;;\n1BA0;SUNDANESE LETTER HA;Lo;0;L;;;;;N;;;;;\n1BA1;SUNDANESE CONSONANT SIGN PAMINGKAL;Mc;0;L;;;;;N;;;;;\n1BA2;SUNDANESE CONSONANT SIGN PANYAKRA;Mn;0;NSM;;;;;N;;;;;\n1BA3;SUNDANESE CONSONANT SIGN PANYIKU;Mn;0;NSM;;;;;N;;;;;\n1BA4;SUNDANESE VOWEL SIGN PANGHULU;Mn;0;NSM;;;;;N;;;;;\n1BA5;SUNDANESE VOWEL SIGN PANYUKU;Mn;0;NSM;;;;;N;;;;;\n1BA6;SUNDANESE VOWEL SIGN PANAELAENG;Mc;0;L;;;;;N;;;;;\n1BA7;SUNDANESE VOWEL SIGN PANOLONG;Mc;0;L;;;;;N;;;;;\n1BA8;SUNDANESE VOWEL SIGN PAMEPET;Mn;0;NSM;;;;;N;;;;;\n1BA9;SUNDANESE VOWEL SIGN PANEULEUNG;Mn;0;NSM;;;;;N;;;;;\n1BAA;SUNDANESE SIGN PAMAAEH;Mc;9;L;;;;;N;;;;;\n1BAB;SUNDANESE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n1BAC;SUNDANESE CONSONANT SIGN PASANGAN MA;Mn;0;NSM;;;;;N;;;;;\n1BAD;SUNDANESE CONSONANT SIGN PASANGAN WA;Mn;0;NSM;;;;;N;;;;;\n1BAE;SUNDANESE LETTER KHA;Lo;0;L;;;;;N;;;;;\n1BAF;SUNDANESE LETTER SYA;Lo;0;L;;;;;N;;;;;\n1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1BB1;SUNDANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1BB2;SUNDANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1BB3;SUNDANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1BB4;SUNDANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1BB5;SUNDANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1BB6;SUNDANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1BBA;SUNDANESE AVAGRAHA;Lo;0;L;;;;;N;;;;;\n1BBB;SUNDANESE LETTER REU;Lo;0;L;;;;;N;;;;;\n1BBC;SUNDANESE LETTER LEU;Lo;0;L;;;;;N;;;;;\n1BBD;SUNDANESE LETTER BHA;Lo;0;L;;;;;N;;;;;\n1BBE;SUNDANESE LETTER FINAL K;Lo;0;L;;;;;N;;;;;\n1BBF;SUNDANESE LETTER FINAL M;Lo;0;L;;;;;N;;;;;\n1BC0;BATAK LETTER A;Lo;0;L;;;;;N;;;;;\n1BC1;BATAK LETTER SIMALUNGUN A;Lo;0;L;;;;;N;;;;;\n1BC2;BATAK LETTER HA;Lo;0;L;;;;;N;;;;;\n1BC3;BATAK LETTER SIMALUNGUN HA;Lo;0;L;;;;;N;;;;;\n1BC4;BATAK LETTER MANDAILING HA;Lo;0;L;;;;;N;;;;;\n1BC5;BATAK LETTER BA;Lo;0;L;;;;;N;;;;;\n1BC6;BATAK LETTER KARO BA;Lo;0;L;;;;;N;;;;;\n1BC7;BATAK LETTER PA;Lo;0;L;;;;;N;;;;;\n1BC8;BATAK LETTER SIMALUNGUN PA;Lo;0;L;;;;;N;;;;;\n1BC9;BATAK LETTER NA;Lo;0;L;;;;;N;;;;;\n1BCA;BATAK LETTER MANDAILING NA;Lo;0;L;;;;;N;;;;;\n1BCB;BATAK LETTER WA;Lo;0;L;;;;;N;;;;;\n1BCC;BATAK LETTER SIMALUNGUN WA;Lo;0;L;;;;;N;;;;;\n1BCD;BATAK LETTER PAKPAK WA;Lo;0;L;;;;;N;;;;;\n1BCE;BATAK LETTER GA;Lo;0;L;;;;;N;;;;;\n1BCF;BATAK LETTER SIMALUNGUN GA;Lo;0;L;;;;;N;;;;;\n1BD0;BATAK LETTER JA;Lo;0;L;;;;;N;;;;;\n1BD1;BATAK LETTER DA;Lo;0;L;;;;;N;;;;;\n1BD2;BATAK LETTER RA;Lo;0;L;;;;;N;;;;;\n1BD3;BATAK LETTER SIMALUNGUN RA;Lo;0;L;;;;;N;;;;;\n1BD4;BATAK LETTER MA;Lo;0;L;;;;;N;;;;;\n1BD5;BATAK LETTER SIMALUNGUN MA;Lo;0;L;;;;;N;;;;;\n1BD6;BATAK LETTER SOUTHERN TA;Lo;0;L;;;;;N;;;;;\n1BD7;BATAK LETTER NORTHERN TA;Lo;0;L;;;;;N;;;;;\n1BD8;BATAK LETTER SA;Lo;0;L;;;;;N;;;;;\n1BD9;BATAK LETTER SIMALUNGUN SA;Lo;0;L;;;;;N;;;;;\n1BDA;BATAK LETTER MANDAILING SA;Lo;0;L;;;;;N;;;;;\n1BDB;BATAK LETTER YA;Lo;0;L;;;;;N;;;;;\n1BDC;BATAK LETTER SIMALUNGUN YA;Lo;0;L;;;;;N;;;;;\n1BDD;BATAK LETTER NGA;Lo;0;L;;;;;N;;;;;\n1BDE;BATAK LETTER LA;Lo;0;L;;;;;N;;;;;\n1BDF;BATAK LETTER SIMALUNGUN LA;Lo;0;L;;;;;N;;;;;\n1BE0;BATAK LETTER NYA;Lo;0;L;;;;;N;;;;;\n1BE1;BATAK LETTER CA;Lo;0;L;;;;;N;;;;;\n1BE2;BATAK LETTER NDA;Lo;0;L;;;;;N;;;;;\n1BE3;BATAK LETTER MBA;Lo;0;L;;;;;N;;;;;\n1BE4;BATAK LETTER I;Lo;0;L;;;;;N;;;;;\n1BE5;BATAK LETTER U;Lo;0;L;;;;;N;;;;;\n1BE6;BATAK SIGN TOMPI;Mn;7;NSM;;;;;N;;;;;\n1BE7;BATAK VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n1BE8;BATAK VOWEL SIGN PAKPAK E;Mn;0;NSM;;;;;N;;;;;\n1BE9;BATAK VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;\n1BEA;BATAK VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n1BEB;BATAK VOWEL SIGN KARO I;Mc;0;L;;;;;N;;;;;\n1BEC;BATAK VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n1BED;BATAK VOWEL SIGN KARO O;Mn;0;NSM;;;;;N;;;;;\n1BEE;BATAK VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n1BEF;BATAK VOWEL SIGN U FOR SIMALUNGUN SA;Mn;0;NSM;;;;;N;;;;;\n1BF0;BATAK CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;;\n1BF1;BATAK CONSONANT SIGN H;Mn;0;NSM;;;;;N;;;;;\n1BF2;BATAK PANGOLAT;Mc;9;L;;;;;N;;;;;\n1BF3;BATAK PANONGONAN;Mc;9;L;;;;;N;;;;;\n1BFC;BATAK SYMBOL BINDU NA METEK;Po;0;L;;;;;N;;;;;\n1BFD;BATAK SYMBOL BINDU PINARBORAS;Po;0;L;;;;;N;;;;;\n1BFE;BATAK SYMBOL BINDU JUDUL;Po;0;L;;;;;N;;;;;\n1BFF;BATAK SYMBOL BINDU PANGOLAT;Po;0;L;;;;;N;;;;;\n1C00;LEPCHA LETTER KA;Lo;0;L;;;;;N;;;;;\n1C01;LEPCHA LETTER KLA;Lo;0;L;;;;;N;;;;;\n1C02;LEPCHA LETTER KHA;Lo;0;L;;;;;N;;;;;\n1C03;LEPCHA LETTER GA;Lo;0;L;;;;;N;;;;;\n1C04;LEPCHA LETTER GLA;Lo;0;L;;;;;N;;;;;\n1C05;LEPCHA LETTER NGA;Lo;0;L;;;;;N;;;;;\n1C06;LEPCHA LETTER CA;Lo;0;L;;;;;N;;;;;\n1C07;LEPCHA LETTER CHA;Lo;0;L;;;;;N;;;;;\n1C08;LEPCHA LETTER JA;Lo;0;L;;;;;N;;;;;\n1C09;LEPCHA LETTER NYA;Lo;0;L;;;;;N;;;;;\n1C0A;LEPCHA LETTER TA;Lo;0;L;;;;;N;;;;;\n1C0B;LEPCHA LETTER THA;Lo;0;L;;;;;N;;;;;\n1C0C;LEPCHA LETTER DA;Lo;0;L;;;;;N;;;;;\n1C0D;LEPCHA LETTER NA;Lo;0;L;;;;;N;;;;;\n1C0E;LEPCHA LETTER PA;Lo;0;L;;;;;N;;;;;\n1C0F;LEPCHA LETTER PLA;Lo;0;L;;;;;N;;;;;\n1C10;LEPCHA LETTER PHA;Lo;0;L;;;;;N;;;;;\n1C11;LEPCHA LETTER FA;Lo;0;L;;;;;N;;;;;\n1C12;LEPCHA LETTER FLA;Lo;0;L;;;;;N;;;;;\n1C13;LEPCHA LETTER BA;Lo;0;L;;;;;N;;;;;\n1C14;LEPCHA LETTER BLA;Lo;0;L;;;;;N;;;;;\n1C15;LEPCHA LETTER MA;Lo;0;L;;;;;N;;;;;\n1C16;LEPCHA LETTER MLA;Lo;0;L;;;;;N;;;;;\n1C17;LEPCHA LETTER TSA;Lo;0;L;;;;;N;;;;;\n1C18;LEPCHA LETTER TSHA;Lo;0;L;;;;;N;;;;;\n1C19;LEPCHA LETTER DZA;Lo;0;L;;;;;N;;;;;\n1C1A;LEPCHA LETTER YA;Lo;0;L;;;;;N;;;;;\n1C1B;LEPCHA LETTER RA;Lo;0;L;;;;;N;;;;;\n1C1C;LEPCHA LETTER LA;Lo;0;L;;;;;N;;;;;\n1C1D;LEPCHA LETTER HA;Lo;0;L;;;;;N;;;;;\n1C1E;LEPCHA LETTER HLA;Lo;0;L;;;;;N;;;;;\n1C1F;LEPCHA LETTER VA;Lo;0;L;;;;;N;;;;;\n1C20;LEPCHA LETTER SA;Lo;0;L;;;;;N;;;;;\n1C21;LEPCHA LETTER SHA;Lo;0;L;;;;;N;;;;;\n1C22;LEPCHA LETTER WA;Lo;0;L;;;;;N;;;;;\n1C23;LEPCHA LETTER A;Lo;0;L;;;;;N;;;;;\n1C24;LEPCHA SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;;\n1C25;LEPCHA SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;;\n1C26;LEPCHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n1C27;LEPCHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n1C28;LEPCHA VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n1C29;LEPCHA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;\n1C2A;LEPCHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n1C2B;LEPCHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\n1C2C;LEPCHA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n1C2D;LEPCHA CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;;\n1C2E;LEPCHA CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;;\n1C2F;LEPCHA CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;;\n1C30;LEPCHA CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;;\n1C31;LEPCHA CONSONANT SIGN P;Mn;0;NSM;;;;;N;;;;;\n1C32;LEPCHA CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;;\n1C33;LEPCHA CONSONANT SIGN T;Mn;0;NSM;;;;;N;;;;;\n1C34;LEPCHA CONSONANT SIGN NYIN-DO;Mc;0;L;;;;;N;;;;;\n1C35;LEPCHA CONSONANT SIGN KANG;Mc;0;L;;;;;N;;;;;\n1C36;LEPCHA SIGN RAN;Mn;0;NSM;;;;;N;;;;;\n1C37;LEPCHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n1C3B;LEPCHA PUNCTUATION TA-ROL;Po;0;L;;;;;N;;;;;\n1C3C;LEPCHA PUNCTUATION NYET THYOOM TA-ROL;Po;0;L;;;;;N;;;;;\n1C3D;LEPCHA PUNCTUATION CER-WA;Po;0;L;;;;;N;;;;;\n1C3E;LEPCHA PUNCTUATION TSHOOK CER-WA;Po;0;L;;;;;N;;;;;\n1C3F;LEPCHA PUNCTUATION TSHOOK;Po;0;L;;;;;N;;;;;\n1C40;LEPCHA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1C41;LEPCHA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1C42;LEPCHA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1C43;LEPCHA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1C44;LEPCHA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1C45;LEPCHA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1C46;LEPCHA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1C47;LEPCHA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1C48;LEPCHA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1C49;LEPCHA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1C4D;LEPCHA LETTER TTA;Lo;0;L;;;;;N;;;;;\n1C4E;LEPCHA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1C4F;LEPCHA LETTER DDA;Lo;0;L;;;;;N;;;;;\n1C50;OL CHIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1C51;OL CHIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1C52;OL CHIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1C53;OL CHIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1C54;OL CHIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1C55;OL CHIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1C56;OL CHIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1C57;OL CHIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1C58;OL CHIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1C59;OL CHIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1C5A;OL CHIKI LETTER LA;Lo;0;L;;;;;N;;;;;\n1C5B;OL CHIKI LETTER AT;Lo;0;L;;;;;N;;;;;\n1C5C;OL CHIKI LETTER AG;Lo;0;L;;;;;N;;;;;\n1C5D;OL CHIKI LETTER ANG;Lo;0;L;;;;;N;;;;;\n1C5E;OL CHIKI LETTER AL;Lo;0;L;;;;;N;;;;;\n1C5F;OL CHIKI LETTER LAA;Lo;0;L;;;;;N;;;;;\n1C60;OL CHIKI LETTER AAK;Lo;0;L;;;;;N;;;;;\n1C61;OL CHIKI LETTER AAJ;Lo;0;L;;;;;N;;;;;\n1C62;OL CHIKI LETTER AAM;Lo;0;L;;;;;N;;;;;\n1C63;OL CHIKI LETTER AAW;Lo;0;L;;;;;N;;;;;\n1C64;OL CHIKI LETTER LI;Lo;0;L;;;;;N;;;;;\n1C65;OL CHIKI LETTER IS;Lo;0;L;;;;;N;;;;;\n1C66;OL CHIKI LETTER IH;Lo;0;L;;;;;N;;;;;\n1C67;OL CHIKI LETTER INY;Lo;0;L;;;;;N;;;;;\n1C68;OL CHIKI LETTER IR;Lo;0;L;;;;;N;;;;;\n1C69;OL CHIKI LETTER LU;Lo;0;L;;;;;N;;;;;\n1C6A;OL CHIKI LETTER UC;Lo;0;L;;;;;N;;;;;\n1C6B;OL CHIKI LETTER UD;Lo;0;L;;;;;N;;;;;\n1C6C;OL CHIKI LETTER UNN;Lo;0;L;;;;;N;;;;;\n1C6D;OL CHIKI LETTER UY;Lo;0;L;;;;;N;;;;;\n1C6E;OL CHIKI LETTER LE;Lo;0;L;;;;;N;;;;;\n1C6F;OL CHIKI LETTER EP;Lo;0;L;;;;;N;;;;;\n1C70;OL CHIKI LETTER EDD;Lo;0;L;;;;;N;;;;;\n1C71;OL CHIKI LETTER EN;Lo;0;L;;;;;N;;;;;\n1C72;OL CHIKI LETTER ERR;Lo;0;L;;;;;N;;;;;\n1C73;OL CHIKI LETTER LO;Lo;0;L;;;;;N;;;;;\n1C74;OL CHIKI LETTER OTT;Lo;0;L;;;;;N;;;;;\n1C75;OL CHIKI LETTER OB;Lo;0;L;;;;;N;;;;;\n1C76;OL CHIKI LETTER OV;Lo;0;L;;;;;N;;;;;\n1C77;OL CHIKI LETTER OH;Lo;0;L;;;;;N;;;;;\n1C78;OL CHIKI MU TTUDDAG;Lm;0;L;;;;;N;;;;;\n1C79;OL CHIKI GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;;\n1C7A;OL CHIKI MU-GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;;\n1C7B;OL CHIKI RELAA;Lm;0;L;;;;;N;;;;;\n1C7C;OL CHIKI PHAARKAA;Lm;0;L;;;;;N;;;;;\n1C7D;OL CHIKI AHAD;Lm;0;L;;;;;N;;;;;\n1C7E;OL CHIKI PUNCTUATION MUCAAD;Po;0;L;;;;;N;;;;;\n1C7F;OL CHIKI PUNCTUATION DOUBLE MUCAAD;Po;0;L;;;;;N;;;;;\n1C80;CYRILLIC SMALL LETTER ROUNDED VE;Ll;0;L;;;;;N;;;0412;;0412\n1C81;CYRILLIC SMALL LETTER LONG-LEGGED DE;Ll;0;L;;;;;N;;;0414;;0414\n1C82;CYRILLIC SMALL LETTER NARROW O;Ll;0;L;;;;;N;;;041E;;041E\n1C83;CYRILLIC SMALL LETTER WIDE ES;Ll;0;L;;;;;N;;;0421;;0421\n1C84;CYRILLIC SMALL LETTER TALL TE;Ll;0;L;;;;;N;;;0422;;0422\n1C85;CYRILLIC SMALL LETTER THREE-LEGGED TE;Ll;0;L;;;;;N;;;0422;;0422\n1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A\n1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462\n1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A\n1C89;CYRILLIC CAPITAL LETTER TJE;Lu;0;L;;;;;N;;;;1C8A;\n1C8A;CYRILLIC SMALL LETTER TJE;Ll;0;L;;;;;N;;;1C89;;1C89\n1C90;GEORGIAN MTAVRULI CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;10D0;\n1C91;GEORGIAN MTAVRULI CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;10D1;\n1C92;GEORGIAN MTAVRULI CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;10D2;\n1C93;GEORGIAN MTAVRULI CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;10D3;\n1C94;GEORGIAN MTAVRULI CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;10D4;\n1C95;GEORGIAN MTAVRULI CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;10D5;\n1C96;GEORGIAN MTAVRULI CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;10D6;\n1C97;GEORGIAN MTAVRULI CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;10D7;\n1C98;GEORGIAN MTAVRULI CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;10D8;\n1C99;GEORGIAN MTAVRULI CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;10D9;\n1C9A;GEORGIAN MTAVRULI CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;10DA;\n1C9B;GEORGIAN MTAVRULI CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;10DB;\n1C9C;GEORGIAN MTAVRULI CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;10DC;\n1C9D;GEORGIAN MTAVRULI CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;10DD;\n1C9E;GEORGIAN MTAVRULI CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;10DE;\n1C9F;GEORGIAN MTAVRULI CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;10DF;\n1CA0;GEORGIAN MTAVRULI CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;10E0;\n1CA1;GEORGIAN MTAVRULI CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;10E1;\n1CA2;GEORGIAN MTAVRULI CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;10E2;\n1CA3;GEORGIAN MTAVRULI CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;10E3;\n1CA4;GEORGIAN MTAVRULI CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;10E4;\n1CA5;GEORGIAN MTAVRULI CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;10E5;\n1CA6;GEORGIAN MTAVRULI CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;10E6;\n1CA7;GEORGIAN MTAVRULI CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;10E7;\n1CA8;GEORGIAN MTAVRULI CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;10E8;\n1CA9;GEORGIAN MTAVRULI CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;10E9;\n1CAA;GEORGIAN MTAVRULI CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;10EA;\n1CAB;GEORGIAN MTAVRULI CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;10EB;\n1CAC;GEORGIAN MTAVRULI CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;10EC;\n1CAD;GEORGIAN MTAVRULI CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;10ED;\n1CAE;GEORGIAN MTAVRULI CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;10EE;\n1CAF;GEORGIAN MTAVRULI CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;10EF;\n1CB0;GEORGIAN MTAVRULI CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;10F0;\n1CB1;GEORGIAN MTAVRULI CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;10F1;\n1CB2;GEORGIAN MTAVRULI CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;10F2;\n1CB3;GEORGIAN MTAVRULI CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;10F3;\n1CB4;GEORGIAN MTAVRULI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;10F4;\n1CB5;GEORGIAN MTAVRULI CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;10F5;\n1CB6;GEORGIAN MTAVRULI CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;10F6;\n1CB7;GEORGIAN MTAVRULI CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;10F7;\n1CB8;GEORGIAN MTAVRULI CAPITAL LETTER ELIFI;Lu;0;L;;;;;N;;;;10F8;\n1CB9;GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN;Lu;0;L;;;;;N;;;;10F9;\n1CBA;GEORGIAN MTAVRULI CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;10FA;\n1CBD;GEORGIAN MTAVRULI CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;10FD;\n1CBE;GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;10FE;\n1CBF;GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN;Lu;0;L;;;;;N;;;;10FF;\n1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;;\n1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;;\n1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;;\n1CC3;SUNDANESE PUNCTUATION BINDU CAKRA;Po;0;L;;;;;N;;;;;\n1CC4;SUNDANESE PUNCTUATION BINDU LEU SATANGA;Po;0;L;;;;;N;;;;;\n1CC5;SUNDANESE PUNCTUATION BINDU KA SATANGA;Po;0;L;;;;;N;;;;;\n1CC6;SUNDANESE PUNCTUATION BINDU DA SATANGA;Po;0;L;;;;;N;;;;;\n1CC7;SUNDANESE PUNCTUATION BINDU BA SATANGA;Po;0;L;;;;;N;;;;;\n1CD0;VEDIC TONE KARSHANA;Mn;230;NSM;;;;;N;;;;;\n1CD1;VEDIC TONE SHARA;Mn;230;NSM;;;;;N;;;;;\n1CD2;VEDIC TONE PRENKHA;Mn;230;NSM;;;;;N;;;;;\n1CD3;VEDIC SIGN NIHSHVASA;Po;0;L;;;;;N;;;;;\n1CD4;VEDIC SIGN YAJURVEDIC MIDLINE SVARITA;Mn;1;NSM;;;;;N;;;;;\n1CD5;VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;;\n1CD6;VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;;\n1CD7;VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;;\n1CD8;VEDIC TONE CANDRA BELOW;Mn;220;NSM;;;;;N;;;;;\n1CD9;VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER;Mn;220;NSM;;;;;N;;;;;\n1CDA;VEDIC TONE DOUBLE SVARITA;Mn;230;NSM;;;;;N;;;;;\n1CDB;VEDIC TONE TRIPLE SVARITA;Mn;230;NSM;;;;;N;;;;;\n1CDC;VEDIC TONE KATHAKA ANUDATTA;Mn;220;NSM;;;;;N;;;;;\n1CDD;VEDIC TONE DOT BELOW;Mn;220;NSM;;;;;N;;;;;\n1CDE;VEDIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;;\n1CDF;VEDIC TONE THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;;\n1CE0;VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA;Mn;230;NSM;;;;;N;;;;;\n1CE1;VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA;Mc;0;L;;;;;N;;;;;\n1CE2;VEDIC SIGN VISARGA SVARITA;Mn;1;NSM;;;;;N;;;;;\n1CE3;VEDIC SIGN VISARGA UDATTA;Mn;1;NSM;;;;;N;;;;;\n1CE4;VEDIC SIGN REVERSED VISARGA UDATTA;Mn;1;NSM;;;;;N;;;;;\n1CE5;VEDIC SIGN VISARGA ANUDATTA;Mn;1;NSM;;;;;N;;;;;\n1CE6;VEDIC SIGN REVERSED VISARGA ANUDATTA;Mn;1;NSM;;;;;N;;;;;\n1CE7;VEDIC SIGN VISARGA UDATTA WITH TAIL;Mn;1;NSM;;;;;N;;;;;\n1CE8;VEDIC SIGN VISARGA ANUDATTA WITH TAIL;Mn;1;NSM;;;;;N;;;;;\n1CE9;VEDIC SIGN ANUSVARA ANTARGOMUKHA;Lo;0;L;;;;;N;;;;;\n1CEA;VEDIC SIGN ANUSVARA BAHIRGOMUKHA;Lo;0;L;;;;;N;;;;;\n1CEB;VEDIC SIGN ANUSVARA VAMAGOMUKHA;Lo;0;L;;;;;N;;;;;\n1CEC;VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL;Lo;0;L;;;;;N;;;;;\n1CED;VEDIC SIGN TIRYAK;Mn;220;NSM;;;;;N;;;;;\n1CEE;VEDIC SIGN HEXIFORM LONG ANUSVARA;Lo;0;L;;;;;N;;;;;\n1CEF;VEDIC SIGN LONG ANUSVARA;Lo;0;L;;;;;N;;;;;\n1CF0;VEDIC SIGN RTHANG LONG ANUSVARA;Lo;0;L;;;;;N;;;;;\n1CF1;VEDIC SIGN ANUSVARA UBHAYATO MUKHA;Lo;0;L;;;;;N;;;;;\n1CF2;VEDIC SIGN ARDHAVISARGA;Lo;0;L;;;;;N;;;;;\n1CF3;VEDIC SIGN ROTATED ARDHAVISARGA;Lo;0;L;;;;;N;;;;;\n1CF4;VEDIC TONE CANDRA ABOVE;Mn;230;NSM;;;;;N;;;;;\n1CF5;VEDIC SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;\n1CF6;VEDIC SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;\n1CF7;VEDIC SIGN ATIKRAMA;Mc;0;L;;;;;N;;;;;\n1CF8;VEDIC TONE RING ABOVE;Mn;230;NSM;;;;;N;;;;;\n1CF9;VEDIC TONE DOUBLE RING ABOVE;Mn;230;NSM;;;;;N;;;;;\n1CFA;VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA;Lo;0;L;;;;;N;;;;;\n1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;;\n1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;;\n1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;;\n1D03;LATIN LETTER SMALL CAPITAL BARRED B;Ll;0;L;;;;;N;;;;;\n1D04;LATIN LETTER SMALL CAPITAL C;Ll;0;L;;;;;N;;;;;\n1D05;LATIN LETTER SMALL CAPITAL D;Ll;0;L;;;;;N;;;;;\n1D06;LATIN LETTER SMALL CAPITAL ETH;Ll;0;L;;;;;N;;;;;\n1D07;LATIN LETTER SMALL CAPITAL E;Ll;0;L;;;;;N;;;;;\n1D08;LATIN SMALL LETTER TURNED OPEN E;Ll;0;L;;;;;N;;;;;\n1D09;LATIN SMALL LETTER TURNED I;Ll;0;L;;;;;N;;;;;\n1D0A;LATIN LETTER SMALL CAPITAL J;Ll;0;L;;;;;N;;;;;\n1D0B;LATIN LETTER SMALL CAPITAL K;Ll;0;L;;;;;N;;;;;\n1D0C;LATIN LETTER SMALL CAPITAL L WITH STROKE;Ll;0;L;;;;;N;;;;;\n1D0D;LATIN LETTER SMALL CAPITAL M;Ll;0;L;;;;;N;;;;;\n1D0E;LATIN LETTER SMALL CAPITAL REVERSED N;Ll;0;L;;;;;N;;;;;\n1D0F;LATIN LETTER SMALL CAPITAL O;Ll;0;L;;;;;N;;;;;\n1D10;LATIN LETTER SMALL CAPITAL OPEN O;Ll;0;L;;;;;N;;;;;\n1D11;LATIN SMALL LETTER SIDEWAYS O;Ll;0;L;;;;;N;;;;;\n1D12;LATIN SMALL LETTER SIDEWAYS OPEN O;Ll;0;L;;;;;N;;;;;\n1D13;LATIN SMALL LETTER SIDEWAYS O WITH STROKE;Ll;0;L;;;;;N;;;;;\n1D14;LATIN SMALL LETTER TURNED OE;Ll;0;L;;;;;N;;;;;\n1D15;LATIN LETTER SMALL CAPITAL OU;Ll;0;L;;;;;N;;;;;\n1D16;LATIN SMALL LETTER TOP HALF O;Ll;0;L;;;;;N;;;;;\n1D17;LATIN SMALL LETTER BOTTOM HALF O;Ll;0;L;;;;;N;;;;;\n1D18;LATIN LETTER SMALL CAPITAL P;Ll;0;L;;;;;N;;;;;\n1D19;LATIN LETTER SMALL CAPITAL REVERSED R;Ll;0;L;;;;;N;;;;;\n1D1A;LATIN LETTER SMALL CAPITAL TURNED R;Ll;0;L;;;;;N;;;;;\n1D1B;LATIN LETTER SMALL CAPITAL T;Ll;0;L;;;;;N;;;;;\n1D1C;LATIN LETTER SMALL CAPITAL U;Ll;0;L;;;;;N;;;;;\n1D1D;LATIN SMALL LETTER SIDEWAYS U;Ll;0;L;;;;;N;;;;;\n1D1E;LATIN SMALL LETTER SIDEWAYS DIAERESIZED U;Ll;0;L;;;;;N;;;;;\n1D1F;LATIN SMALL LETTER SIDEWAYS TURNED M;Ll;0;L;;;;;N;;;;;\n1D20;LATIN LETTER SMALL CAPITAL V;Ll;0;L;;;;;N;;;;;\n1D21;LATIN LETTER SMALL CAPITAL W;Ll;0;L;;;;;N;;;;;\n1D22;LATIN LETTER SMALL CAPITAL Z;Ll;0;L;;;;;N;;;;;\n1D23;LATIN LETTER SMALL CAPITAL EZH;Ll;0;L;;;;;N;;;;;\n1D24;LATIN LETTER VOICED LARYNGEAL SPIRANT;Ll;0;L;;;;;N;;;;;\n1D25;LATIN LETTER AIN;Ll;0;L;;;;;N;;;;;\n1D26;GREEK LETTER SMALL CAPITAL GAMMA;Ll;0;L;;;;;N;;;;;\n1D27;GREEK LETTER SMALL CAPITAL LAMDA;Ll;0;L;;;;;N;;;;;\n1D28;GREEK LETTER SMALL CAPITAL PI;Ll;0;L;;;;;N;;;;;\n1D29;GREEK LETTER SMALL CAPITAL RHO;Ll;0;L;;;;;N;;;;;\n1D2A;GREEK LETTER SMALL CAPITAL PSI;Ll;0;L;;;;;N;;;;;\n1D2B;CYRILLIC LETTER SMALL CAPITAL EL;Ll;0;L;;;;;N;;;;;\n1D2C;MODIFIER LETTER CAPITAL A;Lm;0;L;<super> 0041;;;;N;;;;;\n1D2D;MODIFIER LETTER CAPITAL AE;Lm;0;L;<super> 00C6;;;;N;;;;;\n1D2E;MODIFIER LETTER CAPITAL B;Lm;0;L;<super> 0042;;;;N;;;;;\n1D2F;MODIFIER LETTER CAPITAL BARRED B;Lm;0;L;;;;;N;;;;;\n1D30;MODIFIER LETTER CAPITAL D;Lm;0;L;<super> 0044;;;;N;;;;;\n1D31;MODIFIER LETTER CAPITAL E;Lm;0;L;<super> 0045;;;;N;;;;;\n1D32;MODIFIER LETTER CAPITAL REVERSED E;Lm;0;L;<super> 018E;;;;N;;;;;\n1D33;MODIFIER LETTER CAPITAL G;Lm;0;L;<super> 0047;;;;N;;;;;\n1D34;MODIFIER LETTER CAPITAL H;Lm;0;L;<super> 0048;;;;N;;;;;\n1D35;MODIFIER LETTER CAPITAL I;Lm;0;L;<super> 0049;;;;N;;;;;\n1D36;MODIFIER LETTER CAPITAL J;Lm;0;L;<super> 004A;;;;N;;;;;\n1D37;MODIFIER LETTER CAPITAL K;Lm;0;L;<super> 004B;;;;N;;;;;\n1D38;MODIFIER LETTER CAPITAL L;Lm;0;L;<super> 004C;;;;N;;;;;\n1D39;MODIFIER LETTER CAPITAL M;Lm;0;L;<super> 004D;;;;N;;;;;\n1D3A;MODIFIER LETTER CAPITAL N;Lm;0;L;<super> 004E;;;;N;;;;;\n1D3B;MODIFIER LETTER CAPITAL REVERSED N;Lm;0;L;;;;;N;;;;;\n1D3C;MODIFIER LETTER CAPITAL O;Lm;0;L;<super> 004F;;;;N;;;;;\n1D3D;MODIFIER LETTER CAPITAL OU;Lm;0;L;<super> 0222;;;;N;;;;;\n1D3E;MODIFIER LETTER CAPITAL P;Lm;0;L;<super> 0050;;;;N;;;;;\n1D3F;MODIFIER LETTER CAPITAL R;Lm;0;L;<super> 0052;;;;N;;;;;\n1D40;MODIFIER LETTER CAPITAL T;Lm;0;L;<super> 0054;;;;N;;;;;\n1D41;MODIFIER LETTER CAPITAL U;Lm;0;L;<super> 0055;;;;N;;;;;\n1D42;MODIFIER LETTER CAPITAL W;Lm;0;L;<super> 0057;;;;N;;;;;\n1D43;MODIFIER LETTER SMALL A;Lm;0;L;<super> 0061;;;;N;;;;;\n1D44;MODIFIER LETTER SMALL TURNED A;Lm;0;L;<super> 0250;;;;N;;;;;\n1D45;MODIFIER LETTER SMALL ALPHA;Lm;0;L;<super> 0251;;;;N;;;;;\n1D46;MODIFIER LETTER SMALL TURNED AE;Lm;0;L;<super> 1D02;;;;N;;;;;\n1D47;MODIFIER LETTER SMALL B;Lm;0;L;<super> 0062;;;;N;;;;;\n1D48;MODIFIER LETTER SMALL D;Lm;0;L;<super> 0064;;;;N;;;;;\n1D49;MODIFIER LETTER SMALL E;Lm;0;L;<super> 0065;;;;N;;;;;\n1D4A;MODIFIER LETTER SMALL SCHWA;Lm;0;L;<super> 0259;;;;N;;;;;\n1D4B;MODIFIER LETTER SMALL OPEN E;Lm;0;L;<super> 025B;;;;N;;;;;\n1D4C;MODIFIER LETTER SMALL TURNED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;;\n1D4D;MODIFIER LETTER SMALL G;Lm;0;L;<super> 0067;;;;N;;;;;\n1D4E;MODIFIER LETTER SMALL TURNED I;Lm;0;L;;;;;N;;;;;\n1D4F;MODIFIER LETTER SMALL K;Lm;0;L;<super> 006B;;;;N;;;;;\n1D50;MODIFIER LETTER SMALL M;Lm;0;L;<super> 006D;;;;N;;;;;\n1D51;MODIFIER LETTER SMALL ENG;Lm;0;L;<super> 014B;;;;N;;;;;\n1D52;MODIFIER LETTER SMALL O;Lm;0;L;<super> 006F;;;;N;;;;;\n1D53;MODIFIER LETTER SMALL OPEN O;Lm;0;L;<super> 0254;;;;N;;;;;\n1D54;MODIFIER LETTER SMALL TOP HALF O;Lm;0;L;<super> 1D16;;;;N;;;;;\n1D55;MODIFIER LETTER SMALL BOTTOM HALF O;Lm;0;L;<super> 1D17;;;;N;;;;;\n1D56;MODIFIER LETTER SMALL P;Lm;0;L;<super> 0070;;;;N;;;;;\n1D57;MODIFIER LETTER SMALL T;Lm;0;L;<super> 0074;;;;N;;;;;\n1D58;MODIFIER LETTER SMALL U;Lm;0;L;<super> 0075;;;;N;;;;;\n1D59;MODIFIER LETTER SMALL SIDEWAYS U;Lm;0;L;<super> 1D1D;;;;N;;;;;\n1D5A;MODIFIER LETTER SMALL TURNED M;Lm;0;L;<super> 026F;;;;N;;;;;\n1D5B;MODIFIER LETTER SMALL V;Lm;0;L;<super> 0076;;;;N;;;;;\n1D5C;MODIFIER LETTER SMALL AIN;Lm;0;L;<super> 1D25;;;;N;;;;;\n1D5D;MODIFIER LETTER SMALL BETA;Lm;0;L;<super> 03B2;;;;N;;;;;\n1D5E;MODIFIER LETTER SMALL GREEK GAMMA;Lm;0;L;<super> 03B3;;;;N;;;;;\n1D5F;MODIFIER LETTER SMALL DELTA;Lm;0;L;<super> 03B4;;;;N;;;;;\n1D60;MODIFIER LETTER SMALL GREEK PHI;Lm;0;L;<super> 03C6;;;;N;;;;;\n1D61;MODIFIER LETTER SMALL CHI;Lm;0;L;<super> 03C7;;;;N;;;;;\n1D62;LATIN SUBSCRIPT SMALL LETTER I;Lm;0;L;<sub> 0069;;;;N;;;;;\n1D63;LATIN SUBSCRIPT SMALL LETTER R;Lm;0;L;<sub> 0072;;;;N;;;;;\n1D64;LATIN SUBSCRIPT SMALL LETTER U;Lm;0;L;<sub> 0075;;;;N;;;;;\n1D65;LATIN SUBSCRIPT SMALL LETTER V;Lm;0;L;<sub> 0076;;;;N;;;;;\n1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Lm;0;L;<sub> 03B2;;;;N;;;;;\n1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Lm;0;L;<sub> 03B3;;;;N;;;;;\n1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Lm;0;L;<sub> 03C1;;;;N;;;;;\n1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Lm;0;L;<sub> 03C6;;;;N;;;;;\n1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Lm;0;L;<sub> 03C7;;;;N;;;;;\n1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;;\n1D6C;LATIN SMALL LETTER B WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D6D;LATIN SMALL LETTER D WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D6E;LATIN SMALL LETTER F WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D6F;LATIN SMALL LETTER M WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D70;LATIN SMALL LETTER N WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D71;LATIN SMALL LETTER P WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D72;LATIN SMALL LETTER R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D73;LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D74;LATIN SMALL LETTER S WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D75;LATIN SMALL LETTER T WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D76;LATIN SMALL LETTER Z WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\n1D77;LATIN SMALL LETTER TURNED G;Ll;0;L;;;;;N;;;;;\n1D78;MODIFIER LETTER CYRILLIC EN;Lm;0;L;<super> 043D;;;;N;;;;;\n1D79;LATIN SMALL LETTER INSULAR G;Ll;0;L;;;;;N;;;A77D;;A77D\n1D7A;LATIN SMALL LETTER TH WITH STRIKETHROUGH;Ll;0;L;;;;;N;;;;;\n1D7B;LATIN SMALL CAPITAL LETTER I WITH STROKE;Ll;0;L;;;;;N;;;;;\n1D7C;LATIN SMALL LETTER IOTA WITH STROKE;Ll;0;L;;;;;N;;;;;\n1D7D;LATIN SMALL LETTER P WITH STROKE;Ll;0;L;;;;;N;;;2C63;;2C63\n1D7E;LATIN SMALL CAPITAL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;;;\n1D7F;LATIN SMALL LETTER UPSILON WITH STROKE;Ll;0;L;;;;;N;;;;;\n1D80;LATIN SMALL LETTER B WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D81;LATIN SMALL LETTER D WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D82;LATIN SMALL LETTER F WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D83;LATIN SMALL LETTER G WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D84;LATIN SMALL LETTER K WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D85;LATIN SMALL LETTER L WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D86;LATIN SMALL LETTER M WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D87;LATIN SMALL LETTER N WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D88;LATIN SMALL LETTER P WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D89;LATIN SMALL LETTER R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D8A;LATIN SMALL LETTER S WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D8B;LATIN SMALL LETTER ESH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D8C;LATIN SMALL LETTER V WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D8D;LATIN SMALL LETTER X WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1D8E;LATIN SMALL LETTER Z WITH PALATAL HOOK;Ll;0;L;;;;;N;;;A7C6;;A7C6\n1D8F;LATIN SMALL LETTER A WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D90;LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D91;LATIN SMALL LETTER D WITH HOOK AND TAIL;Ll;0;L;;;;;N;;;;;\n1D92;LATIN SMALL LETTER E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D93;LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D94;LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D95;LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D96;LATIN SMALL LETTER I WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D97;LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D98;LATIN SMALL LETTER ESH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D99;LATIN SMALL LETTER U WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D9A;LATIN SMALL LETTER EZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1D9B;MODIFIER LETTER SMALL TURNED ALPHA;Lm;0;L;<super> 0252;;;;N;;;;;\n1D9C;MODIFIER LETTER SMALL C;Lm;0;L;<super> 0063;;;;N;;;;;\n1D9D;MODIFIER LETTER SMALL C WITH CURL;Lm;0;L;<super> 0255;;;;N;;;;;\n1D9E;MODIFIER LETTER SMALL ETH;Lm;0;L;<super> 00F0;;;;N;;;;;\n1D9F;MODIFIER LETTER SMALL REVERSED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;;\n1DA0;MODIFIER LETTER SMALL F;Lm;0;L;<super> 0066;;;;N;;;;;\n1DA1;MODIFIER LETTER SMALL DOTLESS J WITH STROKE;Lm;0;L;<super> 025F;;;;N;;;;;\n1DA2;MODIFIER LETTER SMALL SCRIPT G;Lm;0;L;<super> 0261;;;;N;;;;;\n1DA3;MODIFIER LETTER SMALL TURNED H;Lm;0;L;<super> 0265;;;;N;;;;;\n1DA4;MODIFIER LETTER SMALL I WITH STROKE;Lm;0;L;<super> 0268;;;;N;;;;;\n1DA5;MODIFIER LETTER SMALL IOTA;Lm;0;L;<super> 0269;;;;N;;;;;\n1DA6;MODIFIER LETTER SMALL CAPITAL I;Lm;0;L;<super> 026A;;;;N;;;;;\n1DA7;MODIFIER LETTER SMALL CAPITAL I WITH STROKE;Lm;0;L;<super> 1D7B;;;;N;;;;;\n1DA8;MODIFIER LETTER SMALL J WITH CROSSED-TAIL;Lm;0;L;<super> 029D;;;;N;;;;;\n1DA9;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK;Lm;0;L;<super> 026D;;;;N;;;;;\n1DAA;MODIFIER LETTER SMALL L WITH PALATAL HOOK;Lm;0;L;<super> 1D85;;;;N;;;;;\n1DAB;MODIFIER LETTER SMALL CAPITAL L;Lm;0;L;<super> 029F;;;;N;;;;;\n1DAC;MODIFIER LETTER SMALL M WITH HOOK;Lm;0;L;<super> 0271;;;;N;;;;;\n1DAD;MODIFIER LETTER SMALL TURNED M WITH LONG LEG;Lm;0;L;<super> 0270;;;;N;;;;;\n1DAE;MODIFIER LETTER SMALL N WITH LEFT HOOK;Lm;0;L;<super> 0272;;;;N;;;;;\n1DAF;MODIFIER LETTER SMALL N WITH RETROFLEX HOOK;Lm;0;L;<super> 0273;;;;N;;;;;\n1DB0;MODIFIER LETTER SMALL CAPITAL N;Lm;0;L;<super> 0274;;;;N;;;;;\n1DB1;MODIFIER LETTER SMALL BARRED O;Lm;0;L;<super> 0275;;;;N;;;;;\n1DB2;MODIFIER LETTER SMALL PHI;Lm;0;L;<super> 0278;;;;N;;;;;\n1DB3;MODIFIER LETTER SMALL S WITH HOOK;Lm;0;L;<super> 0282;;;;N;;;;;\n1DB4;MODIFIER LETTER SMALL ESH;Lm;0;L;<super> 0283;;;;N;;;;;\n1DB5;MODIFIER LETTER SMALL T WITH PALATAL HOOK;Lm;0;L;<super> 01AB;;;;N;;;;;\n1DB6;MODIFIER LETTER SMALL U BAR;Lm;0;L;<super> 0289;;;;N;;;;;\n1DB7;MODIFIER LETTER SMALL UPSILON;Lm;0;L;<super> 028A;;;;N;;;;;\n1DB8;MODIFIER LETTER SMALL CAPITAL U;Lm;0;L;<super> 1D1C;;;;N;;;;;\n1DB9;MODIFIER LETTER SMALL V WITH HOOK;Lm;0;L;<super> 028B;;;;N;;;;;\n1DBA;MODIFIER LETTER SMALL TURNED V;Lm;0;L;<super> 028C;;;;N;;;;;\n1DBB;MODIFIER LETTER SMALL Z;Lm;0;L;<super> 007A;;;;N;;;;;\n1DBC;MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK;Lm;0;L;<super> 0290;;;;N;;;;;\n1DBD;MODIFIER LETTER SMALL Z WITH CURL;Lm;0;L;<super> 0291;;;;N;;;;;\n1DBE;MODIFIER LETTER SMALL EZH;Lm;0;L;<super> 0292;;;;N;;;;;\n1DBF;MODIFIER LETTER SMALL THETA;Lm;0;L;<super> 03B8;;;;N;;;;;\n1DC0;COMBINING DOTTED GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;\n1DC1;COMBINING DOTTED ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;\n1DC2;COMBINING SNAKE BELOW;Mn;220;NSM;;;;;N;;;;;\n1DC3;COMBINING SUSPENSION MARK;Mn;230;NSM;;;;;N;;;;;\n1DC4;COMBINING MACRON-ACUTE;Mn;230;NSM;;;;;N;;;;;\n1DC5;COMBINING GRAVE-MACRON;Mn;230;NSM;;;;;N;;;;;\n1DC6;COMBINING MACRON-GRAVE;Mn;230;NSM;;;;;N;;;;;\n1DC7;COMBINING ACUTE-MACRON;Mn;230;NSM;;;;;N;;;;;\n1DC8;COMBINING GRAVE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;;\n1DC9;COMBINING ACUTE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;;\n1DCA;COMBINING LATIN SMALL LETTER R BELOW;Mn;220;NSM;;;;;N;;;;;\n1DCB;COMBINING BREVE-MACRON;Mn;230;NSM;;;;;N;;;;;\n1DCC;COMBINING MACRON-BREVE;Mn;230;NSM;;;;;N;;;;;\n1DCD;COMBINING DOUBLE CIRCUMFLEX ABOVE;Mn;234;NSM;;;;;N;;;;;\n1DCE;COMBINING OGONEK ABOVE;Mn;214;NSM;;;;;N;;;;;\n1DCF;COMBINING ZIGZAG BELOW;Mn;220;NSM;;;;;N;;;;;\n1DD0;COMBINING IS BELOW;Mn;202;NSM;;;;;N;;;;;\n1DD1;COMBINING UR ABOVE;Mn;230;NSM;;;;;N;;;;;\n1DD2;COMBINING US ABOVE;Mn;230;NSM;;;;;N;;;;;\n1DD3;COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE;Mn;230;NSM;;;;;N;;;;;\n1DD4;COMBINING LATIN SMALL LETTER AE;Mn;230;NSM;;;;;N;;;;;\n1DD5;COMBINING LATIN SMALL LETTER AO;Mn;230;NSM;;;;;N;;;;;\n1DD6;COMBINING LATIN SMALL LETTER AV;Mn;230;NSM;;;;;N;;;;;\n1DD7;COMBINING LATIN SMALL LETTER C CEDILLA;Mn;230;NSM;;;;;N;;;;;\n1DD8;COMBINING LATIN SMALL LETTER INSULAR D;Mn;230;NSM;;;;;N;;;;;\n1DD9;COMBINING LATIN SMALL LETTER ETH;Mn;230;NSM;;;;;N;;;;;\n1DDA;COMBINING LATIN SMALL LETTER G;Mn;230;NSM;;;;;N;;;;;\n1DDB;COMBINING LATIN LETTER SMALL CAPITAL G;Mn;230;NSM;;;;;N;;;;;\n1DDC;COMBINING LATIN SMALL LETTER K;Mn;230;NSM;;;;;N;;;;;\n1DDD;COMBINING LATIN SMALL LETTER L;Mn;230;NSM;;;;;N;;;;;\n1DDE;COMBINING LATIN LETTER SMALL CAPITAL L;Mn;230;NSM;;;;;N;;;;;\n1DDF;COMBINING LATIN LETTER SMALL CAPITAL M;Mn;230;NSM;;;;;N;;;;;\n1DE0;COMBINING LATIN SMALL LETTER N;Mn;230;NSM;;;;;N;;;;;\n1DE1;COMBINING LATIN LETTER SMALL CAPITAL N;Mn;230;NSM;;;;;N;;;;;\n1DE2;COMBINING LATIN LETTER SMALL CAPITAL R;Mn;230;NSM;;;;;N;;;;;\n1DE3;COMBINING LATIN SMALL LETTER R ROTUNDA;Mn;230;NSM;;;;;N;;;;;\n1DE4;COMBINING LATIN SMALL LETTER S;Mn;230;NSM;;;;;N;;;;;\n1DE5;COMBINING LATIN SMALL LETTER LONG S;Mn;230;NSM;;;;;N;;;;;\n1DE6;COMBINING LATIN SMALL LETTER Z;Mn;230;NSM;;;;;N;;;;;\n1DE7;COMBINING LATIN SMALL LETTER ALPHA;Mn;230;NSM;;;;;N;;;;;\n1DE8;COMBINING LATIN SMALL LETTER B;Mn;230;NSM;;;;;N;;;;;\n1DE9;COMBINING LATIN SMALL LETTER BETA;Mn;230;NSM;;;;;N;;;;;\n1DEA;COMBINING LATIN SMALL LETTER SCHWA;Mn;230;NSM;;;;;N;;;;;\n1DEB;COMBINING LATIN SMALL LETTER F;Mn;230;NSM;;;;;N;;;;;\n1DEC;COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Mn;230;NSM;;;;;N;;;;;\n1DED;COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;;\n1DEE;COMBINING LATIN SMALL LETTER P;Mn;230;NSM;;;;;N;;;;;\n1DEF;COMBINING LATIN SMALL LETTER ESH;Mn;230;NSM;;;;;N;;;;;\n1DF0;COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;;\n1DF1;COMBINING LATIN SMALL LETTER W;Mn;230;NSM;;;;;N;;;;;\n1DF2;COMBINING LATIN SMALL LETTER A WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;;\n1DF3;COMBINING LATIN SMALL LETTER O WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;;\n1DF4;COMBINING LATIN SMALL LETTER U WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;;\n1DF5;COMBINING UP TACK ABOVE;Mn;230;NSM;;;;;N;;;;;\n1DF6;COMBINING KAVYKA ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;;\n1DF7;COMBINING KAVYKA ABOVE LEFT;Mn;228;NSM;;;;;N;;;;;\n1DF8;COMBINING DOT ABOVE LEFT;Mn;228;NSM;;;;;N;;;;;\n1DF9;COMBINING WIDE INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;;;;;\n1DFA;COMBINING DOT BELOW LEFT;Mn;218;NSM;;;;;N;;;;;\n1DFB;COMBINING DELETION MARK;Mn;230;NSM;;;;;N;;;;;\n1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;;\n1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;;\n1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;\n1DFF;COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;\n1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01;\n1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00\n1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03;\n1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02\n1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05;\n1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04\n1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07;\n1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06\n1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09;\n1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08\n1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B;\n1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A\n1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D;\n1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C\n1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F;\n1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E\n1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11;\n1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10\n1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13;\n1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12\n1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15;\n1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14\n1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17;\n1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16\n1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19;\n1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18\n1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B;\n1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A\n1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D;\n1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C\n1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F;\n1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E\n1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21;\n1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20\n1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23;\n1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22\n1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25;\n1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24\n1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27;\n1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26\n1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29;\n1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28\n1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B;\n1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A\n1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D;\n1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C\n1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F;\n1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E\n1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31;\n1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30\n1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33;\n1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32\n1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35;\n1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34\n1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37;\n1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36\n1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39;\n1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38\n1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B;\n1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A\n1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D;\n1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C\n1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F;\n1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E\n1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41;\n1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40\n1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43;\n1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42\n1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45;\n1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44\n1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47;\n1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46\n1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49;\n1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48\n1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B;\n1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A\n1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D;\n1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C\n1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F;\n1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E\n1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51;\n1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50\n1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53;\n1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52\n1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55;\n1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54\n1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57;\n1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56\n1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59;\n1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58\n1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B;\n1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A\n1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D;\n1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C\n1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F;\n1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E\n1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61;\n1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60\n1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63;\n1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62\n1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65;\n1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64\n1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67;\n1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66\n1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69;\n1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68\n1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B;\n1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A\n1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D;\n1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C\n1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F;\n1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E\n1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71;\n1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70\n1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73;\n1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72\n1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75;\n1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74\n1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77;\n1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76\n1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79;\n1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78\n1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B;\n1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A\n1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D;\n1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C\n1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F;\n1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E\n1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81;\n1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80\n1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83;\n1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82\n1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85;\n1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84\n1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87;\n1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86\n1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89;\n1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88\n1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B;\n1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A\n1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D;\n1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C\n1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F;\n1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E\n1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91;\n1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90\n1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93;\n1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92\n1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95;\n1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94\n1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;;\n1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;;\n1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;;\n1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;;\n1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L;<compat> 0061 02BE;;;;N;;;;;\n1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60\n1E9C;LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;;;\n1E9D;LATIN SMALL LETTER LONG S WITH HIGH STROKE;Ll;0;L;;;;;N;;;;;\n1E9E;LATIN CAPITAL LETTER SHARP S;Lu;0;L;;;;;N;;;;00DF;\n1E9F;LATIN SMALL LETTER DELTA;Ll;0;L;;;;;N;;;;;\n1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1;\n1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0\n1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3;\n1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2\n1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5;\n1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4\n1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7;\n1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6\n1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9;\n1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8\n1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB;\n1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA\n1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD;\n1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC\n1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF;\n1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE\n1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1;\n1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0\n1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3;\n1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2\n1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5;\n1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4\n1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7;\n1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6\n1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9;\n1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8\n1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB;\n1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA\n1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD;\n1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC\n1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF;\n1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE\n1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1;\n1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0\n1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3;\n1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2\n1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5;\n1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4\n1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7;\n1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6\n1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9;\n1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8\n1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB;\n1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA\n1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD;\n1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC\n1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF;\n1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE\n1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1;\n1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0\n1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3;\n1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2\n1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5;\n1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4\n1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7;\n1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6\n1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9;\n1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8\n1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB;\n1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA\n1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD;\n1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC\n1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF;\n1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE\n1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1;\n1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0\n1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3;\n1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2\n1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5;\n1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4\n1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7;\n1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6\n1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9;\n1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8\n1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB;\n1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA\n1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED;\n1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC\n1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF;\n1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE\n1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1;\n1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0\n1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3;\n1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2\n1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5;\n1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4\n1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7;\n1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6\n1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9;\n1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8\n1EFA;LATIN CAPITAL LETTER MIDDLE-WELSH LL;Lu;0;L;;;;;N;;;;1EFB;\n1EFB;LATIN SMALL LETTER MIDDLE-WELSH LL;Ll;0;L;;;;;N;;;1EFA;;1EFA\n1EFC;LATIN CAPITAL LETTER MIDDLE-WELSH V;Lu;0;L;;;;;N;;;;1EFD;\n1EFD;LATIN SMALL LETTER MIDDLE-WELSH V;Ll;0;L;;;;;N;;;1EFC;;1EFC\n1EFE;LATIN CAPITAL LETTER Y WITH LOOP;Lu;0;L;;;;;N;;;;1EFF;\n1EFF;LATIN SMALL LETTER Y WITH LOOP;Ll;0;L;;;;;N;;;1EFE;;1EFE\n1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08\n1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09\n1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A\n1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B\n1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C\n1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D\n1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E\n1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F\n1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00;\n1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01;\n1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02;\n1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03;\n1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04;\n1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05;\n1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06;\n1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07;\n1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18\n1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19\n1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A\n1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B\n1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C\n1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D\n1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10;\n1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11;\n1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12;\n1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13;\n1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14;\n1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15;\n1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28\n1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29\n1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A\n1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B\n1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C\n1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D\n1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E\n1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F\n1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20;\n1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21;\n1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22;\n1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23;\n1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24;\n1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25;\n1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26;\n1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27;\n1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38\n1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39\n1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A\n1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B\n1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C\n1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D\n1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E\n1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F\n1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30;\n1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31;\n1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32;\n1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33;\n1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34;\n1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35;\n1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36;\n1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37;\n1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48\n1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49\n1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A\n1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B\n1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C\n1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D\n1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40;\n1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41;\n1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42;\n1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43;\n1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44;\n1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45;\n1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;;\n1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59\n1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;;\n1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B\n1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;;\n1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D\n1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;;\n1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F\n1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51;\n1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53;\n1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55;\n1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57;\n1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68\n1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69\n1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A\n1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B\n1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C\n1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D\n1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E\n1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F\n1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60;\n1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61;\n1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62;\n1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63;\n1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64;\n1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65;\n1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66;\n1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67;\n1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA\n1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB\n1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8\n1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9\n1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA\n1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB\n1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA\n1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB\n1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8\n1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9\n1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA\n1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB\n1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA\n1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB\n1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88\n1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89\n1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A\n1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B\n1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C\n1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D\n1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E\n1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F\n1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80;\n1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81;\n1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82;\n1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83;\n1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84;\n1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85;\n1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86;\n1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87;\n1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98\n1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99\n1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A\n1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B\n1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C\n1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D\n1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E\n1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F\n1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90;\n1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91;\n1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92;\n1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93;\n1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94;\n1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95;\n1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96;\n1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97;\n1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8\n1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9\n1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA\n1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB\n1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC\n1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD\n1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE\n1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF\n1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0;\n1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1;\n1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2;\n1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3;\n1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4;\n1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5;\n1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6;\n1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7;\n1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8\n1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9\n1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;;\n1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC\n1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;;\n1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;;\n1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;;\n1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0;\n1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1;\n1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70;\n1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71;\n1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3;\n1FBD;GREEK KORONIS;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;\n1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399\n1FBF;GREEK PSILI;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;\n1FC0;GREEK PERISPOMENI;Sk;0;ON;<compat> 0020 0342;;;;N;;;;;\n1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;;\n1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;;\n1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC\n1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;;\n1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;;\n1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;;\n1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72;\n1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73;\n1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74;\n1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75;\n1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3;\n1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;;\n1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;;\n1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;;\n1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8\n1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9\n1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;;\n1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;;\n1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;;\n1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;;\n1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0;\n1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1;\n1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76;\n1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77;\n1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;;\n1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;;\n1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;;\n1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8\n1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9\n1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;;\n1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;;\n1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;;\n1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC\n1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;;\n1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;;\n1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0;\n1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1;\n1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A;\n1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B;\n1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5;\n1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;;\n1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;;\n1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;;\n1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;;\n1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC\n1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;;\n1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;;\n1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;;\n1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78;\n1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79;\n1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C;\n1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D;\n1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3;\n1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;;\n1FFE;GREEK DASIA;Sk;0;ON;<compat> 0020 0314;;;;N;;;;;\n2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;\n2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;\n2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;\n2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n200B;ZERO WIDTH SPACE;Cf;0;BN;;;;;N;;;;;\n200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;;\n200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;;\n200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;;\n200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;;\n2010;HYPHEN;Pd;0;ON;;;;;N;;;;;\n2011;NON-BREAKING HYPHEN;Pd;0;ON;<noBreak> 2010;;;;N;;;;;\n2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;;\n2013;EN DASH;Pd;0;ON;;;;;N;;;;;\n2014;EM DASH;Pd;0;ON;;;;;N;;;;;\n2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;;\n2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;;\n2017;DOUBLE LOW LINE;Po;0;ON;<compat> 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;;\n2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;;\n2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;;\n201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;;\n201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;;\n201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;;\n201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;;\n201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;;\n201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;;\n2020;DAGGER;Po;0;ON;;;;;N;;;;;\n2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;;\n2022;BULLET;Po;0;ON;;;;;N;;;;;\n2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;;\n2024;ONE DOT LEADER;Po;0;ON;<compat> 002E;;;;N;;;;;\n2025;TWO DOT LEADER;Po;0;ON;<compat> 002E 002E;;;;N;;;;;\n2026;HORIZONTAL ELLIPSIS;Po;0;ON;<compat> 002E 002E 002E;;;;N;;;;;\n2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;;\n2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;;\n2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;;\n202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;;\n202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;;\n202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;;\n202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;;\n202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;;\n202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;\n2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;;\n2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;;\n2032;PRIME;Po;0;ET;;;;;N;;;;;\n2033;DOUBLE PRIME;Po;0;ET;<compat> 2032 2032;;;;N;;;;;\n2034;TRIPLE PRIME;Po;0;ET;<compat> 2032 2032 2032;;;;N;;;;;\n2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;;\n2036;REVERSED DOUBLE PRIME;Po;0;ON;<compat> 2035 2035;;;;N;;;;;\n2037;REVERSED TRIPLE PRIME;Po;0;ON;<compat> 2035 2035 2035;;;;N;;;;;\n2038;CARET;Po;0;ON;;;;;N;;;;;\n2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;;\n203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;;\n203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;;\n203C;DOUBLE EXCLAMATION MARK;Po;0;ON;<compat> 0021 0021;;;;N;;;;;\n203D;INTERROBANG;Po;0;ON;;;;;N;;;;;\n203E;OVERLINE;Po;0;ON;<compat> 0020 0305;;;;N;SPACING OVERSCORE;;;;\n203F;UNDERTIE;Pc;0;ON;;;;;N;;;;;\n2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;;\n2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;;\n2042;ASTERISM;Po;0;ON;;;;;N;;;;;\n2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;;\n2044;FRACTION SLASH;Sm;0;CS;;;;;N;;;;;\n2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;;\n2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;;\n2047;DOUBLE QUESTION MARK;Po;0;ON;<compat> 003F 003F;;;;N;;;;;\n2048;QUESTION EXCLAMATION MARK;Po;0;ON;<compat> 003F 0021;;;;N;;;;;\n2049;EXCLAMATION QUESTION MARK;Po;0;ON;<compat> 0021 003F;;;;N;;;;;\n204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;;\n204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;;\n204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;;\n204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;;\n204E;LOW ASTERISK;Po;0;ON;;;;;N;;;;;\n204F;REVERSED SEMICOLON;Po;0;ON;;;;;N;;;;;\n2050;CLOSE UP;Po;0;ON;;;;;N;;;;;\n2051;TWO ASTERISKS ALIGNED VERTICALLY;Po;0;ON;;;;;N;;;;;\n2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;;\n2053;SWUNG DASH;Po;0;ON;;;;;N;;;;;\n2054;INVERTED UNDERTIE;Pc;0;ON;;;;;N;;;;;\n2055;FLOWER PUNCTUATION MARK;Po;0;ON;;;;;N;;;;;\n2056;THREE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n2057;QUADRUPLE PRIME;Po;0;ON;<compat> 2032 2032 2032 2032;;;;N;;;;;\n2058;FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n2059;FIVE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n205A;TWO DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n205B;FOUR DOT MARK;Po;0;ON;;;;;N;;;;;\n205C;DOTTED CROSS;Po;0;ON;;;;;N;;;;;\n205D;TRICOLON;Po;0;ON;;;;;N;;;;;\n205E;VERTICAL FOUR DOTS;Po;0;ON;;;;;N;;;;;\n205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;\n2060;WORD JOINER;Cf;0;BN;;;;;N;;;;;\n2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;;\n2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;;\n2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;;\n2064;INVISIBLE PLUS;Cf;0;BN;;;;;N;;;;;\n2066;LEFT-TO-RIGHT ISOLATE;Cf;0;LRI;;;;;N;;;;;\n2067;RIGHT-TO-LEFT ISOLATE;Cf;0;RLI;;;;;N;;;;;\n2068;FIRST STRONG ISOLATE;Cf;0;FSI;;;;;N;;;;;\n2069;POP DIRECTIONAL ISOLATE;Cf;0;PDI;;;;;N;;;;;\n206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;\n206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;\n206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;\n206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;\n206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;\n206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;\n2070;SUPERSCRIPT ZERO;No;0;EN;<super> 0030;;0;0;N;SUPERSCRIPT DIGIT ZERO;;;;\n2071;SUPERSCRIPT LATIN SMALL LETTER I;Lm;0;L;<super> 0069;;;;N;;;;;\n2074;SUPERSCRIPT FOUR;No;0;EN;<super> 0034;;4;4;N;SUPERSCRIPT DIGIT FOUR;;;;\n2075;SUPERSCRIPT FIVE;No;0;EN;<super> 0035;;5;5;N;SUPERSCRIPT DIGIT FIVE;;;;\n2076;SUPERSCRIPT SIX;No;0;EN;<super> 0036;;6;6;N;SUPERSCRIPT DIGIT SIX;;;;\n2077;SUPERSCRIPT SEVEN;No;0;EN;<super> 0037;;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;;\n2078;SUPERSCRIPT EIGHT;No;0;EN;<super> 0038;;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;;\n2079;SUPERSCRIPT NINE;No;0;EN;<super> 0039;;9;9;N;SUPERSCRIPT DIGIT NINE;;;;\n207A;SUPERSCRIPT PLUS SIGN;Sm;0;ES;<super> 002B;;;;N;;;;;\n207B;SUPERSCRIPT MINUS;Sm;0;ES;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;;\n207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON;<super> 003D;;;;N;;;;;\n207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON;<super> 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;;\n207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<super> 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;;\n207F;SUPERSCRIPT LATIN SMALL LETTER N;Lm;0;L;<super> 006E;;;;N;;;;;\n2080;SUBSCRIPT ZERO;No;0;EN;<sub> 0030;;0;0;N;SUBSCRIPT DIGIT ZERO;;;;\n2081;SUBSCRIPT ONE;No;0;EN;<sub> 0031;;1;1;N;SUBSCRIPT DIGIT ONE;;;;\n2082;SUBSCRIPT TWO;No;0;EN;<sub> 0032;;2;2;N;SUBSCRIPT DIGIT TWO;;;;\n2083;SUBSCRIPT THREE;No;0;EN;<sub> 0033;;3;3;N;SUBSCRIPT DIGIT THREE;;;;\n2084;SUBSCRIPT FOUR;No;0;EN;<sub> 0034;;4;4;N;SUBSCRIPT DIGIT FOUR;;;;\n2085;SUBSCRIPT FIVE;No;0;EN;<sub> 0035;;5;5;N;SUBSCRIPT DIGIT FIVE;;;;\n2086;SUBSCRIPT SIX;No;0;EN;<sub> 0036;;6;6;N;SUBSCRIPT DIGIT SIX;;;;\n2087;SUBSCRIPT SEVEN;No;0;EN;<sub> 0037;;7;7;N;SUBSCRIPT DIGIT SEVEN;;;;\n2088;SUBSCRIPT EIGHT;No;0;EN;<sub> 0038;;8;8;N;SUBSCRIPT DIGIT EIGHT;;;;\n2089;SUBSCRIPT NINE;No;0;EN;<sub> 0039;;9;9;N;SUBSCRIPT DIGIT NINE;;;;\n208A;SUBSCRIPT PLUS SIGN;Sm;0;ES;<sub> 002B;;;;N;;;;;\n208B;SUBSCRIPT MINUS;Sm;0;ES;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;;\n208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON;<sub> 003D;;;;N;;;;;\n208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON;<sub> 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;;\n208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<sub> 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;;\n2090;LATIN SUBSCRIPT SMALL LETTER A;Lm;0;L;<sub> 0061;;;;N;;;;;\n2091;LATIN SUBSCRIPT SMALL LETTER E;Lm;0;L;<sub> 0065;;;;N;;;;;\n2092;LATIN SUBSCRIPT SMALL LETTER O;Lm;0;L;<sub> 006F;;;;N;;;;;\n2093;LATIN SUBSCRIPT SMALL LETTER X;Lm;0;L;<sub> 0078;;;;N;;;;;\n2094;LATIN SUBSCRIPT SMALL LETTER SCHWA;Lm;0;L;<sub> 0259;;;;N;;;;;\n2095;LATIN SUBSCRIPT SMALL LETTER H;Lm;0;L;<sub> 0068;;;;N;;;;;\n2096;LATIN SUBSCRIPT SMALL LETTER K;Lm;0;L;<sub> 006B;;;;N;;;;;\n2097;LATIN SUBSCRIPT SMALL LETTER L;Lm;0;L;<sub> 006C;;;;N;;;;;\n2098;LATIN SUBSCRIPT SMALL LETTER M;Lm;0;L;<sub> 006D;;;;N;;;;;\n2099;LATIN SUBSCRIPT SMALL LETTER N;Lm;0;L;<sub> 006E;;;;N;;;;;\n209A;LATIN SUBSCRIPT SMALL LETTER P;Lm;0;L;<sub> 0070;;;;N;;;;;\n209B;LATIN SUBSCRIPT SMALL LETTER S;Lm;0;L;<sub> 0073;;;;N;;;;;\n209C;LATIN SUBSCRIPT SMALL LETTER T;Lm;0;L;<sub> 0074;;;;N;;;;;\n20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;\n20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;;\n20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;;\n20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;;\n20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;;\n20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;;\n20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;;\n20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;;\n20A8;RUPEE SIGN;Sc;0;ET;<compat> 0052 0073;;;;N;;;;;\n20A9;WON SIGN;Sc;0;ET;;;;;N;;;;;\n20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;;\n20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;;\n20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;;\n20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;;\n20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;;\n20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;;\n20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;;\n20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;;\n20B2;GUARANI SIGN;Sc;0;ET;;;;;N;;;;;\n20B3;AUSTRAL SIGN;Sc;0;ET;;;;;N;;;;;\n20B4;HRYVNIA SIGN;Sc;0;ET;;;;;N;;;;;\n20B5;CEDI SIGN;Sc;0;ET;;;;;N;;;;;\n20B6;LIVRE TOURNOIS SIGN;Sc;0;ET;;;;;N;;;;;\n20B7;SPESMILO SIGN;Sc;0;ET;;;;;N;;;;;\n20B8;TENGE SIGN;Sc;0;ET;;;;;N;;;;;\n20B9;INDIAN RUPEE SIGN;Sc;0;ET;;;;;N;;;;;\n20BA;TURKISH LIRA SIGN;Sc;0;ET;;;;;N;;;;;\n20BB;NORDIC MARK SIGN;Sc;0;ET;;;;;N;;;;;\n20BC;MANAT SIGN;Sc;0;ET;;;;;N;;;;;\n20BD;RUBLE SIGN;Sc;0;ET;;;;;N;;;;;\n20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;;\n20BF;BITCOIN SIGN;Sc;0;ET;;;;;N;;;;;\n20C0;SOM SIGN;Sc;0;ET;;;;;N;;;;;\n20C1;SAUDI RIYAL SIGN;Sc;0;ET;;;;;N;;;;;\n20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;;\n20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;;\n20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;;\n20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;;\n20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;;\n20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;;\n20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;;\n20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;;\n20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;;\n20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;;\n20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;;\n20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;;\n20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;;\n20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;;\n20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;;\n20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;;\n20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;;\n20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;;\n20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;;\n20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;;\n20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;;\n20E5;COMBINING REVERSE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;;\n20E6;COMBINING DOUBLE VERTICAL STROKE OVERLAY;Mn;1;NSM;;;;;N;;;;;\n20E7;COMBINING ANNUITY SYMBOL;Mn;230;NSM;;;;;N;;;;;\n20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;;\n20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;\n20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;;\n20EB;COMBINING LONG DOUBLE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;;\n20EC;COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;;\n20ED;COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;;\n20EE;COMBINING LEFT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;\n20EF;COMBINING RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;\n20F0;COMBINING ASTERISK ABOVE;Mn;230;NSM;;;;;N;;;;;\n2100;ACCOUNT OF;So;0;ON;<compat> 0061 002F 0063;;;;N;;;;;\n2101;ADDRESSED TO THE SUBJECT;So;0;ON;<compat> 0061 002F 0073;;;;N;;;;;\n2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L;<font> 0043;;;;N;DOUBLE-STRUCK C;;;;\n2103;DEGREE CELSIUS;So;0;ON;<compat> 00B0 0043;;;;N;DEGREES CENTIGRADE;;;;\n2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;;\n2105;CARE OF;So;0;ON;<compat> 0063 002F 006F;;;;N;;;;;\n2106;CADA UNA;So;0;ON;<compat> 0063 002F 0075;;;;N;;;;;\n2107;EULER CONSTANT;Lu;0;L;<compat> 0190;;;;N;EULERS;;;;\n2108;SCRUPLE;So;0;ON;;;;;N;;;;;\n2109;DEGREE FAHRENHEIT;So;0;ON;<compat> 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;;\n210A;SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n210B;SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;SCRIPT H;;;;\n210C;BLACK-LETTER CAPITAL H;Lu;0;L;<font> 0048;;;;N;BLACK-LETTER H;;;;\n210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L;<font> 0048;;;;N;DOUBLE-STRUCK H;;;;\n210E;PLANCK CONSTANT;Ll;0;L;<font> 0068;;;;N;;;;;\n210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L;<font> 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;;\n2110;SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;SCRIPT I;;;;\n2111;BLACK-LETTER CAPITAL I;Lu;0;L;<font> 0049;;;;N;BLACK-LETTER I;;;;\n2112;SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;SCRIPT L;;;;\n2113;SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;;\n2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L;<font> 004E;;;;N;DOUBLE-STRUCK N;;;;\n2116;NUMERO SIGN;So;0;ON;<compat> 004E 006F;;;;N;NUMERO;;;;\n2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;;\n2118;SCRIPT CAPITAL P;Sm;0;ON;;;;;N;SCRIPT P;;;;\n2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L;<font> 0050;;;;N;DOUBLE-STRUCK P;;;;\n211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L;<font> 0051;;;;N;DOUBLE-STRUCK Q;;;;\n211B;SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;SCRIPT R;;;;\n211C;BLACK-LETTER CAPITAL R;Lu;0;L;<font> 0052;;;;N;BLACK-LETTER R;;;;\n211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L;<font> 0052;;;;N;DOUBLE-STRUCK R;;;;\n211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;;\n211F;RESPONSE;So;0;ON;;;;;N;;;;;\n2120;SERVICE MARK;So;0;ON;<super> 0053 004D;;;;N;;;;;\n2121;TELEPHONE SIGN;So;0;ON;<compat> 0054 0045 004C;;;;N;T E L SYMBOL;;;;\n2122;TRADE MARK SIGN;So;0;ON;<super> 0054 004D;;;;N;TRADEMARK;;;;\n2123;VERSICLE;So;0;ON;;;;;N;;;;;\n2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L;<font> 005A;;;;N;DOUBLE-STRUCK Z;;;;\n2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;;\n2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9;\n2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;;\n2128;BLACK-LETTER CAPITAL Z;Lu;0;L;<font> 005A;;;;N;BLACK-LETTER Z;;;;\n2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;;\n212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;\n212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5;\n212C;SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;SCRIPT B;;;;\n212D;BLACK-LETTER CAPITAL C;Lu;0;L;<font> 0043;;;;N;BLACK-LETTER C;;;;\n212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;;\n212F;SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n2130;SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;SCRIPT E;;;;\n2131;SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;SCRIPT F;;;;\n2132;TURNED CAPITAL F;Lu;0;L;;;;;N;TURNED F;;;214E;\n2133;SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;SCRIPT M;;;;\n2134;SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n2135;ALEF SYMBOL;Lo;0;L;<compat> 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;;\n2136;BET SYMBOL;Lo;0;L;<compat> 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;;\n2137;GIMEL SYMBOL;Lo;0;L;<compat> 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;;\n2138;DALET SYMBOL;Lo;0;L;<compat> 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;;\n2139;INFORMATION SOURCE;Ll;0;L;<font> 0069;;;;N;;;;;\n213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;;\n213B;FACSIMILE SIGN;So;0;ON;<compat> 0046 0041 0058;;;;N;;;;;\n213C;DOUBLE-STRUCK SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;\n213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;\n213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;\n213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;\n2140;DOUBLE-STRUCK N-ARY SUMMATION;Sm;0;ON;<font> 2211;;;;Y;;;;;\n2141;TURNED SANS-SERIF CAPITAL G;Sm;0;ON;;;;;N;;;;;\n2142;TURNED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;;\n2143;REVERSED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;;\n2144;TURNED SANS-SERIF CAPITAL Y;Sm;0;ON;;;;;N;;;;;\n2145;DOUBLE-STRUCK ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n2146;DOUBLE-STRUCK ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n2147;DOUBLE-STRUCK ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n2148;DOUBLE-STRUCK ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n214A;PROPERTY LINE;So;0;ON;;;;;N;;;;;\n214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;;\n214C;PER SIGN;So;0;ON;;;;;N;;;;;\n214D;AKTIESELSKAB;So;0;ON;;;;;N;;;;;\n214E;TURNED SMALL F;Ll;0;L;;;;;N;;;2132;;2132\n214F;SYMBOL FOR SAMARITAN SOURCE;So;0;L;;;;;N;;;;;\n2150;VULGAR FRACTION ONE SEVENTH;No;0;ON;<fraction> 0031 2044 0037;;;1/7;N;;;;;\n2151;VULGAR FRACTION ONE NINTH;No;0;ON;<fraction> 0031 2044 0039;;;1/9;N;;;;;\n2152;VULGAR FRACTION ONE TENTH;No;0;ON;<fraction> 0031 2044 0031 0030;;;1/10;N;;;;;\n2153;VULGAR FRACTION ONE THIRD;No;0;ON;<fraction> 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;;\n2154;VULGAR FRACTION TWO THIRDS;No;0;ON;<fraction> 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;;\n2155;VULGAR FRACTION ONE FIFTH;No;0;ON;<fraction> 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;;\n2156;VULGAR FRACTION TWO FIFTHS;No;0;ON;<fraction> 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;;\n2157;VULGAR FRACTION THREE FIFTHS;No;0;ON;<fraction> 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;;\n2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON;<fraction> 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;;\n2159;VULGAR FRACTION ONE SIXTH;No;0;ON;<fraction> 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;;\n215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON;<fraction> 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;;\n215B;VULGAR FRACTION ONE EIGHTH;No;0;ON;<fraction> 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;;\n215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON;<fraction> 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;;\n215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON;<fraction> 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;;\n215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON;<fraction> 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;;\n215F;FRACTION NUMERATOR ONE;No;0;ON;<fraction> 0031 2044;;;1;N;;;;;\n2160;ROMAN NUMERAL ONE;Nl;0;L;<compat> 0049;;;1;N;;;;2170;\n2161;ROMAN NUMERAL TWO;Nl;0;L;<compat> 0049 0049;;;2;N;;;;2171;\n2162;ROMAN NUMERAL THREE;Nl;0;L;<compat> 0049 0049 0049;;;3;N;;;;2172;\n2163;ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0049 0056;;;4;N;;;;2173;\n2164;ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0056;;;5;N;;;;2174;\n2165;ROMAN NUMERAL SIX;Nl;0;L;<compat> 0056 0049;;;6;N;;;;2175;\n2166;ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0056 0049 0049;;;7;N;;;;2176;\n2167;ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0056 0049 0049 0049;;;8;N;;;;2177;\n2168;ROMAN NUMERAL NINE;Nl;0;L;<compat> 0049 0058;;;9;N;;;;2178;\n2169;ROMAN NUMERAL TEN;Nl;0;L;<compat> 0058;;;10;N;;;;2179;\n216A;ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0058 0049;;;11;N;;;;217A;\n216B;ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0058 0049 0049;;;12;N;;;;217B;\n216C;ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 004C;;;50;N;;;;217C;\n216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0043;;;100;N;;;;217D;\n216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0044;;;500;N;;;;217E;\n216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 004D;;;1000;N;;;;217F;\n2170;SMALL ROMAN NUMERAL ONE;Nl;0;L;<compat> 0069;;;1;N;;;2160;;2160\n2171;SMALL ROMAN NUMERAL TWO;Nl;0;L;<compat> 0069 0069;;;2;N;;;2161;;2161\n2172;SMALL ROMAN NUMERAL THREE;Nl;0;L;<compat> 0069 0069 0069;;;3;N;;;2162;;2162\n2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0069 0076;;;4;N;;;2163;;2163\n2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0076;;;5;N;;;2164;;2164\n2175;SMALL ROMAN NUMERAL SIX;Nl;0;L;<compat> 0076 0069;;;6;N;;;2165;;2165\n2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0076 0069 0069;;;7;N;;;2166;;2166\n2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0076 0069 0069 0069;;;8;N;;;2167;;2167\n2178;SMALL ROMAN NUMERAL NINE;Nl;0;L;<compat> 0069 0078;;;9;N;;;2168;;2168\n2179;SMALL ROMAN NUMERAL TEN;Nl;0;L;<compat> 0078;;;10;N;;;2169;;2169\n217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0078 0069;;;11;N;;;216A;;216A\n217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0078 0069 0069;;;12;N;;;216B;;216B\n217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 006C;;;50;N;;;216C;;216C\n217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0063;;;100;N;;;216D;;216D\n217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0064;;;500;N;;;216E;;216E\n217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 006D;;;1000;N;;;216F;;216F\n2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;;\n2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;;\n2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;;\n2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Lu;0;L;;;;;N;;;;2184;\n2184;LATIN SMALL LETTER REVERSED C;Ll;0;L;;;;;N;;;2183;;2183\n2185;ROMAN NUMERAL SIX LATE FORM;Nl;0;L;;;;6;N;;;;;\n2186;ROMAN NUMERAL FIFTY EARLY FORM;Nl;0;L;;;;50;N;;;;;\n2187;ROMAN NUMERAL FIFTY THOUSAND;Nl;0;L;;;;50000;N;;;;;\n2188;ROMAN NUMERAL ONE HUNDRED THOUSAND;Nl;0;L;;;;100000;N;;;;;\n2189;VULGAR FRACTION ZERO THIRDS;No;0;ON;<fraction> 0030 2044 0033;;;0;N;;;;;\n218A;TURNED DIGIT TWO;So;0;ON;;;;;N;;;;;\n218B;TURNED DIGIT THREE;So;0;ON;;;;;N;;;;;\n2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;;\n2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;;\n2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;;\n2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;;\n2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;\n2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;;\n2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;;\n2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;;\n2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;;\n2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;;\n219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;;\n219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;;\n219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;;\n219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;;\n219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;;\n219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;;\n21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;;\n21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;;\n21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;;\n21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;;\n21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;;\n21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;;\n21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;;\n21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;;\n21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;;\n21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;;\n21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;;\n21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;;\n21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;;\n21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;;\n21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;;\n21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;;\n21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;;\n21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;;\n21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;;\n21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;;\n21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;;\n21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;;\n21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;\n21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;\n21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;;\n21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;;\n21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;\n21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;\n21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;;\n21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;;\n21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;;\n21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;;\n21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;;\n21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;;\n21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;;\n21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;;\n21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;;\n21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;;\n21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;;\n21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;;\n21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;;\n21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;;\n21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;;\n21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;;\n21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;;\n21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;;\n21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;;\n21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;;\n21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;;\n21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;;\n21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;;\n21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;;\n21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;\n21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;;\n21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;;\n21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;;\n21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;;\n21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;;\n21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;;\n21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;;\n21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;;\n21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;;\n21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;;\n21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;;\n21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;;\n21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;;\n21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;;\n21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;;\n21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;;\n21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;;\n21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;;\n21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;;\n21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;;\n21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;;\n21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;;\n21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;\n21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;\n21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;\n21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;;\n21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;\n21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;;\n21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;;\n21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;;\n21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;;\n21F4;RIGHT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;\n21F5;DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n21F6;THREE RIGHTWARDS ARROWS;Sm;0;ON;;;;;N;;;;;\n21F7;LEFTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n21F8;RIGHTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n21F9;LEFT RIGHT ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n21FA;LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n21FB;RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n21FC;LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n21FD;LEFTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;\n21FE;RIGHTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;\n21FF;LEFT RIGHT OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;\n2200;FOR ALL;Sm;0;ON;;;;;N;;;;;\n2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;;\n2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;;\n2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;;\n2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;;\n2205;EMPTY SET;Sm;0;ON;;;;;N;;;;;\n2206;INCREMENT;Sm;0;ON;;;;;N;;;;;\n2207;NABLA;Sm;0;ON;;;;;N;;;;;\n2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;;\n2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;;\n220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;;\n220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;\n220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;;\n220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;\n220E;END OF PROOF;Sm;0;ON;;;;;N;;;;;\n220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;;\n2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;;\n2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;;\n2212;MINUS SIGN;Sm;0;ES;;;;;N;;;;;\n2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;;\n2214;DOT PLUS;Sm;0;ON;;;;;N;;;;;\n2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;\n2216;SET MINUS;Sm;0;ON;;;;;Y;;;;;\n2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;\n2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;;\n2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;;\n221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;;\n221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;;\n221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;;\n221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;;\n221E;INFINITY;Sm;0;ON;;;;;N;;;;;\n221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;;\n2220;ANGLE;Sm;0;ON;;;;;Y;;;;;\n2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;;\n2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;;\n2223;DIVIDES;Sm;0;ON;;;;;N;;;;;\n2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;;\n2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;;\n2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;;\n2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;;\n2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;;\n2229;INTERSECTION;Sm;0;ON;;;;;N;;;;;\n222A;UNION;Sm;0;ON;;;;;N;;;;;\n222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n222C;DOUBLE INTEGRAL;Sm;0;ON;<compat> 222B 222B;;;;Y;;;;;\n222D;TRIPLE INTEGRAL;Sm;0;ON;<compat> 222B 222B 222B;;;;Y;;;;;\n222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n222F;SURFACE INTEGRAL;Sm;0;ON;<compat> 222E 222E;;;;Y;;;;;\n2230;VOLUME INTEGRAL;Sm;0;ON;<compat> 222E 222E 222E;;;;Y;;;;;\n2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n2234;THEREFORE;Sm;0;ON;;;;;N;;;;;\n2235;BECAUSE;Sm;0;ON;;;;;N;;;;;\n2236;RATIO;Sm;0;ON;;;;;N;;;;;\n2237;PROPORTION;Sm;0;ON;;;;;N;;;;;\n2238;DOT MINUS;Sm;0;ON;;;;;N;;;;;\n2239;EXCESS;Sm;0;ON;;;;;Y;;;;;\n223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;;\n223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;;\n223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;\n223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;;;;\n223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;;\n223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;;\n2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;;\n2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;;\n2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;;\n2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;;\n2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;;\n2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;;\n224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;;\n224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;\n224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;\n224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;;\n2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;;\n2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;;\n2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;;\n2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;;\n2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;;\n2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;;\n2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;;\n2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;;\n2259;ESTIMATES;Sm;0;ON;;;;;N;;;;;\n225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;;\n225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;;\n225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;;\n225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;;\n225E;MEASURED BY;Sm;0;ON;;;;;N;;;;;\n225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;;\n2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;;\n2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;;\n2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;\n2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;;\n2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;;\n2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;;\n2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;;\n2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;;\n2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;;\n226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;;\n226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;;\n226C;BETWEEN;Sm;0;ON;;;;;N;;;;;\n226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;Y;;;;;\n226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;;\n226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;;\n2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;;\n2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;;\n2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;;\n2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;;\n2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;;\n2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;;\n2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;;\n2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;;\n2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;;\n2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;;\n227A;PRECEDES;Sm;0;ON;;;;;Y;;;;;\n227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;;\n227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;\n227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;\n2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;;\n2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;;\n2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;;\n2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;;\n2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;;\n2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;;\n2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;;\n2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;;\n228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;;\n228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;;\n228C;MULTISET;Sm;0;ON;;;;;Y;;;;;\n228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;;\n228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;;\n228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;;\n2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;\n2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;;\n2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;;\n2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;\n2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;;\n2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;;\n2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;\n2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;\n229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;;\n229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;\n229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;;\n229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;;\n229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;;\n229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;;\n22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;;\n22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;\n22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;;\n22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;;\n22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;;\n22A5;UP TACK;Sm;0;ON;;;;;N;;;;;\n22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;;\n22A7;MODELS;Sm;0;ON;;;;;Y;;;;;\n22A8;TRUE;Sm;0;ON;;;;;Y;;;;;\n22A9;FORCES;Sm;0;ON;;;;;Y;;;;;\n22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;\n22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;\n22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;;\n22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;;\n22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;;\n22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;;\n22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;;\n22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;;\n22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;;\n22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;;\n22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;\n22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;;\n22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;;\n22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;;\n22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;;\n22BB;XOR;Sm;0;ON;;;;;N;;;;;\n22BC;NAND;Sm;0;ON;;;;;N;;;;;\n22BD;NOR;Sm;0;ON;;;;;N;;;;;\n22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;;\n22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;\n22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;;\n22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;;\n22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;;\n22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;;\n22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;;\n22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;;\n22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;;\n22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;;\n22C8;BOWTIE;Sm;0;ON;;;;;N;;;;;\n22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;\n22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;\n22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;\n22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;\n22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;;\n22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;;\n22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;;\n22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;;\n22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;;\n22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;;\n22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;;\n22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;;\n22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;;\n22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;;\n22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;;\n22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;;\n22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;;\n22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;;\n22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;;\n22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;;\n22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;;\n22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;;\n22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;;\n22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;;\n22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;;\n22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;;\n22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;;\n22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;;\n22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;;\n22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;\n22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;\n22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;;\n22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;;\n22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;;\n22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;;\n22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;\n22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;\n22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;\n22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;\n22F2;ELEMENT OF WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;\n22F3;ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;\n22F4;SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;\n22F5;ELEMENT OF WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;\n22F6;ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;\n22F7;SMALL ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;\n22F8;ELEMENT OF WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;\n22F9;ELEMENT OF WITH TWO HORIZONTAL STROKES;Sm;0;ON;;;;;Y;;;;;\n22FA;CONTAINS WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;\n22FB;CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;\n22FC;SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;\n22FD;CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;\n22FE;SMALL CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;\n22FF;Z NOTATION BAG MEMBERSHIP;Sm;0;ON;;;;;Y;;;;;\n2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;;\n2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;;\n2302;HOUSE;So;0;ON;;;;;N;;;;;\n2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;;\n2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;;\n2305;PROJECTIVE;So;0;ON;;;;;N;;;;;\n2306;PERSPECTIVE;So;0;ON;;;;;N;;;;;\n2307;WAVY LINE;So;0;ON;;;;;N;;;;;\n2308;LEFT CEILING;Ps;0;ON;;;;;Y;;;;;\n2309;RIGHT CEILING;Pe;0;ON;;;;;Y;;;;;\n230A;LEFT FLOOR;Ps;0;ON;;;;;Y;;;;;\n230B;RIGHT FLOOR;Pe;0;ON;;;;;Y;;;;;\n230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;;\n230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;;\n230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;;\n230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;;\n2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;;\n2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;;\n2312;ARC;So;0;ON;;;;;N;;;;;\n2313;SEGMENT;So;0;ON;;;;;N;;;;;\n2314;SECTOR;So;0;ON;;;;;N;;;;;\n2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;;\n2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;;\n2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;;\n2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;;\n2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;;\n231A;WATCH;So;0;ON;;;;;N;;;;;\n231B;HOURGLASS;So;0;ON;;;;;N;;;;;\n231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;;\n231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;;\n231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;;\n231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;;\n2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n2322;FROWN;So;0;ON;;;;;N;;;;;\n2323;SMILE;So;0;ON;;;;;N;;;;;\n2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;;\n2325;OPTION KEY;So;0;ON;;;;;N;;;;;\n2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;;\n2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;;\n2328;KEYBOARD;So;0;ON;;;;;N;;;;;\n2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;;\n232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;;\n232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;;\n232C;BENZENE RING;So;0;ON;;;;;N;;;;;\n232D;CYLINDRICITY;So;0;ON;;;;;N;;;;;\n232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;;\n232F;SYMMETRY;So;0;ON;;;;;N;;;;;\n2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;;\n2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;;\n2332;CONICAL TAPER;So;0;ON;;;;;N;;;;;\n2333;SLOPE;So;0;ON;;;;;N;;;;;\n2334;COUNTERBORE;So;0;ON;;;;;N;;;;;\n2335;COUNTERSINK;So;0;ON;;;;;N;;;;;\n2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;;\n2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;;\n2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;;\n2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;;\n233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;;\n233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;;\n233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;;\n233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;;\n233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;;\n233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;;\n2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;;\n2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;;\n2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;;\n2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;;\n2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;;\n2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;;\n2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;;\n2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;;\n2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;;\n2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;;\n234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;;;;\n234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;;\n234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;;\n234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;;\n234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;;;;\n234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;;\n2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;;\n2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;;;;\n2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;;\n2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;;\n2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;;\n2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;;;;\n2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;;\n2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;;\n2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;;\n2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;;\n235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;;\n235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;;\n235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;;\n235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;;\n235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;;\n235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;;\n2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;;\n2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;;;;\n2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;;\n2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;;\n2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;;\n2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;;\n2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;;\n2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;;\n2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;;\n2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;;\n236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;;\n236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;;\n236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;;\n236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;;\n236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;;\n236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;;\n2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;;\n2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;;\n2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;;\n2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;;\n2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;;\n2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;;\n2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;;\n2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;;\n2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;;\n2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;;\n237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;;\n237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;;\n237C;RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW;Sm;0;ON;;;;;N;;;;;\n237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;;\n237E;BELL SYMBOL;So;0;ON;;;;;N;;;;;\n237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;;\n2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;;\n2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;\n2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;\n2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;;\n2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;;\n2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;;\n2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;;\n2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;;\n2388;HELM SYMBOL;So;0;ON;;;;;N;;;;;\n2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;;;;\n238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;;;;\n238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;;;;\n238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;;\n238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;;\n238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;;\n238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;;\n2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;;\n2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;\n2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;\n2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;;\n2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;;\n2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;;\n2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;;\n2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;;\n2398;NEXT PAGE;So;0;ON;;;;;N;;;;;\n2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;;\n239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;;\n239B;LEFT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;;\n239C;LEFT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;;\n239D;LEFT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;;\n239E;RIGHT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;;\n239F;RIGHT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;;\n23A0;RIGHT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;;\n23A1;LEFT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;;\n23A2;LEFT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;\n23A3;LEFT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;;\n23A4;RIGHT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;;\n23A5;RIGHT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;\n23A6;RIGHT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;;\n23A7;LEFT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;;\n23A8;LEFT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;;\n23A9;LEFT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;;\n23AA;CURLY BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;\n23AB;RIGHT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;;\n23AC;RIGHT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;;\n23AD;RIGHT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;;\n23AE;INTEGRAL EXTENSION;Sm;0;ON;;;;;N;;;;;\n23AF;HORIZONTAL LINE EXTENSION;Sm;0;ON;;;;;N;;;;;\n23B0;UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;;\n23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;;\n23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;;\n23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;;\n23B4;TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;;\n23B5;BOTTOM SQUARE BRACKET;So;0;ON;;;;;N;;;;;\n23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;;\n23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;;\n23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;;\n23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;;\n23BA;HORIZONTAL SCAN LINE-1;So;0;ON;;;;;N;;;;;\n23BB;HORIZONTAL SCAN LINE-3;So;0;ON;;;;;N;;;;;\n23BC;HORIZONTAL SCAN LINE-7;So;0;ON;;;;;N;;;;;\n23BD;HORIZONTAL SCAN LINE-9;So;0;ON;;;;;N;;;;;\n23BE;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;;\n23BF;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;;\n23C0;DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE;So;0;ON;;;;;N;;;;;\n23C1;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;;\n23C2;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;;\n23C3;DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;\n23C4;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;\n23C5;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;\n23C6;DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE;So;0;ON;;;;;N;;;;;\n23C7;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;;\n23C8;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;;\n23C9;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;;;;;\n23CA;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;;;;;\n23CB;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;;\n23CC;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;;\n23CD;SQUARE FOOT;So;0;ON;;;;;N;;;;;\n23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;;\n23CF;EJECT SYMBOL;So;0;ON;;;;;N;;;;;\n23D0;VERTICAL LINE EXTENSION;So;0;ON;;;;;N;;;;;\n23D1;METRICAL BREVE;So;0;ON;;;;;N;;;;;\n23D2;METRICAL LONG OVER SHORT;So;0;ON;;;;;N;;;;;\n23D3;METRICAL SHORT OVER LONG;So;0;ON;;;;;N;;;;;\n23D4;METRICAL LONG OVER TWO SHORTS;So;0;ON;;;;;N;;;;;\n23D5;METRICAL TWO SHORTS OVER LONG;So;0;ON;;;;;N;;;;;\n23D6;METRICAL TWO SHORTS JOINED;So;0;ON;;;;;N;;;;;\n23D7;METRICAL TRISEME;So;0;ON;;;;;N;;;;;\n23D8;METRICAL TETRASEME;So;0;ON;;;;;N;;;;;\n23D9;METRICAL PENTASEME;So;0;ON;;;;;N;;;;;\n23DA;EARTH GROUND;So;0;ON;;;;;N;;;;;\n23DB;FUSE;So;0;ON;;;;;N;;;;;\n23DC;TOP PARENTHESIS;Sm;0;ON;;;;;N;;;;;\n23DD;BOTTOM PARENTHESIS;Sm;0;ON;;;;;N;;;;;\n23DE;TOP CURLY BRACKET;Sm;0;ON;;;;;N;;;;;\n23DF;BOTTOM CURLY BRACKET;Sm;0;ON;;;;;N;;;;;\n23E0;TOP TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;;;;\n23E1;BOTTOM TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;;;;\n23E2;WHITE TRAPEZIUM;So;0;ON;;;;;N;;;;;\n23E3;BENZENE RING WITH CIRCLE;So;0;ON;;;;;N;;;;;\n23E4;STRAIGHTNESS;So;0;ON;;;;;N;;;;;\n23E5;FLATNESS;So;0;ON;;;;;N;;;;;\n23E6;AC CURRENT;So;0;ON;;;;;N;;;;;\n23E7;ELECTRICAL INTERSECTION;So;0;ON;;;;;N;;;;;\n23E8;DECIMAL EXPONENT SYMBOL;So;0;ON;;;;;N;;;;;\n23E9;BLACK RIGHT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;;\n23EA;BLACK LEFT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;;\n23EB;BLACK UP-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;;\n23EC;BLACK DOWN-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;;\n23ED;BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;\n23EE;BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;\n23EF;BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;;\n23F0;ALARM CLOCK;So;0;ON;;;;;N;;;;;\n23F1;STOPWATCH;So;0;ON;;;;;N;;;;;\n23F2;TIMER CLOCK;So;0;ON;;;;;N;;;;;\n23F3;HOURGLASS WITH FLOWING SAND;So;0;ON;;;;;N;;;;;\n23F4;BLACK MEDIUM LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n23F5;BLACK MEDIUM RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n23F6;BLACK MEDIUM UP-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n23F7;BLACK MEDIUM DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n23F8;DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;;\n23F9;BLACK SQUARE FOR STOP;So;0;ON;;;;;N;;;;;\n23FA;BLACK CIRCLE FOR RECORD;So;0;ON;;;;;N;;;;;\n23FB;POWER SYMBOL;So;0;ON;;;;;N;;;;;\n23FC;POWER ON-OFF SYMBOL;So;0;ON;;;;;N;;;;;\n23FD;POWER ON SYMBOL;So;0;ON;;;;;N;;;;;\n23FE;POWER SLEEP SYMBOL;So;0;ON;;;;;N;;;;;\n23FF;OBSERVER EYE SYMBOL;So;0;ON;;;;;N;;;;;\n2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;;\n2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;;\n2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;;\n2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;;\n2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;;\n2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;;\n2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;;\n2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;;\n2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;;\n2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;;\n240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;;\n240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;;\n240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;;\n240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;;\n240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;;\n240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;;\n2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;;\n2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;;\n2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;;\n2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;;\n2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;;\n2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;;\n2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;;\n2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;;\n2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;;\n2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;;\n241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;;\n241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;;\n241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;;\n241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;;\n241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;;\n241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;;\n2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;;\n2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;;\n2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;;\n2423;OPEN BOX;So;0;ON;;;;;N;;;;;\n2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;;\n2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;;\n2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;;\n2427;SYMBOL FOR DELETE SQUARE CHECKER BOARD FORM;So;0;ON;;;;;N;;;;;\n2428;SYMBOL FOR DELETE RECTANGULAR CHECKER BOARD FORM;So;0;ON;;;;;N;;;;;\n2429;SYMBOL FOR DELETE MEDIUM SHADE FORM;So;0;ON;;;;;N;;;;;\n2440;OCR HOOK;So;0;ON;;;;;N;;;;;\n2441;OCR CHAIR;So;0;ON;;;;;N;;;;;\n2442;OCR FORK;So;0;ON;;;;;N;;;;;\n2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;;\n2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;;\n2445;OCR BOW TIE;So;0;ON;;;;;N;;;;;\n2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;;\n2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;;\n2448;OCR DASH;So;0;ON;;;;;N;;;;;\n2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;;\n244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;;\n2460;CIRCLED DIGIT ONE;No;0;ON;<circle> 0031;;1;1;N;;;;;\n2461;CIRCLED DIGIT TWO;No;0;ON;<circle> 0032;;2;2;N;;;;;\n2462;CIRCLED DIGIT THREE;No;0;ON;<circle> 0033;;3;3;N;;;;;\n2463;CIRCLED DIGIT FOUR;No;0;ON;<circle> 0034;;4;4;N;;;;;\n2464;CIRCLED DIGIT FIVE;No;0;ON;<circle> 0035;;5;5;N;;;;;\n2465;CIRCLED DIGIT SIX;No;0;ON;<circle> 0036;;6;6;N;;;;;\n2466;CIRCLED DIGIT SEVEN;No;0;ON;<circle> 0037;;7;7;N;;;;;\n2467;CIRCLED DIGIT EIGHT;No;0;ON;<circle> 0038;;8;8;N;;;;;\n2468;CIRCLED DIGIT NINE;No;0;ON;<circle> 0039;;9;9;N;;;;;\n2469;CIRCLED NUMBER TEN;No;0;ON;<circle> 0031 0030;;;10;N;;;;;\n246A;CIRCLED NUMBER ELEVEN;No;0;ON;<circle> 0031 0031;;;11;N;;;;;\n246B;CIRCLED NUMBER TWELVE;No;0;ON;<circle> 0031 0032;;;12;N;;;;;\n246C;CIRCLED NUMBER THIRTEEN;No;0;ON;<circle> 0031 0033;;;13;N;;;;;\n246D;CIRCLED NUMBER FOURTEEN;No;0;ON;<circle> 0031 0034;;;14;N;;;;;\n246E;CIRCLED NUMBER FIFTEEN;No;0;ON;<circle> 0031 0035;;;15;N;;;;;\n246F;CIRCLED NUMBER SIXTEEN;No;0;ON;<circle> 0031 0036;;;16;N;;;;;\n2470;CIRCLED NUMBER SEVENTEEN;No;0;ON;<circle> 0031 0037;;;17;N;;;;;\n2471;CIRCLED NUMBER EIGHTEEN;No;0;ON;<circle> 0031 0038;;;18;N;;;;;\n2472;CIRCLED NUMBER NINETEEN;No;0;ON;<circle> 0031 0039;;;19;N;;;;;\n2473;CIRCLED NUMBER TWENTY;No;0;ON;<circle> 0032 0030;;;20;N;;;;;\n2474;PARENTHESIZED DIGIT ONE;No;0;ON;<compat> 0028 0031 0029;;1;1;N;;;;;\n2475;PARENTHESIZED DIGIT TWO;No;0;ON;<compat> 0028 0032 0029;;2;2;N;;;;;\n2476;PARENTHESIZED DIGIT THREE;No;0;ON;<compat> 0028 0033 0029;;3;3;N;;;;;\n2477;PARENTHESIZED DIGIT FOUR;No;0;ON;<compat> 0028 0034 0029;;4;4;N;;;;;\n2478;PARENTHESIZED DIGIT FIVE;No;0;ON;<compat> 0028 0035 0029;;5;5;N;;;;;\n2479;PARENTHESIZED DIGIT SIX;No;0;ON;<compat> 0028 0036 0029;;6;6;N;;;;;\n247A;PARENTHESIZED DIGIT SEVEN;No;0;ON;<compat> 0028 0037 0029;;7;7;N;;;;;\n247B;PARENTHESIZED DIGIT EIGHT;No;0;ON;<compat> 0028 0038 0029;;8;8;N;;;;;\n247C;PARENTHESIZED DIGIT NINE;No;0;ON;<compat> 0028 0039 0029;;9;9;N;;;;;\n247D;PARENTHESIZED NUMBER TEN;No;0;ON;<compat> 0028 0031 0030 0029;;;10;N;;;;;\n247E;PARENTHESIZED NUMBER ELEVEN;No;0;ON;<compat> 0028 0031 0031 0029;;;11;N;;;;;\n247F;PARENTHESIZED NUMBER TWELVE;No;0;ON;<compat> 0028 0031 0032 0029;;;12;N;;;;;\n2480;PARENTHESIZED NUMBER THIRTEEN;No;0;ON;<compat> 0028 0031 0033 0029;;;13;N;;;;;\n2481;PARENTHESIZED NUMBER FOURTEEN;No;0;ON;<compat> 0028 0031 0034 0029;;;14;N;;;;;\n2482;PARENTHESIZED NUMBER FIFTEEN;No;0;ON;<compat> 0028 0031 0035 0029;;;15;N;;;;;\n2483;PARENTHESIZED NUMBER SIXTEEN;No;0;ON;<compat> 0028 0031 0036 0029;;;16;N;;;;;\n2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;ON;<compat> 0028 0031 0037 0029;;;17;N;;;;;\n2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;ON;<compat> 0028 0031 0038 0029;;;18;N;;;;;\n2486;PARENTHESIZED NUMBER NINETEEN;No;0;ON;<compat> 0028 0031 0039 0029;;;19;N;;;;;\n2487;PARENTHESIZED NUMBER TWENTY;No;0;ON;<compat> 0028 0032 0030 0029;;;20;N;;;;;\n2488;DIGIT ONE FULL STOP;No;0;EN;<compat> 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;;\n2489;DIGIT TWO FULL STOP;No;0;EN;<compat> 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;;\n248A;DIGIT THREE FULL STOP;No;0;EN;<compat> 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;;\n248B;DIGIT FOUR FULL STOP;No;0;EN;<compat> 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;;\n248C;DIGIT FIVE FULL STOP;No;0;EN;<compat> 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;;\n248D;DIGIT SIX FULL STOP;No;0;EN;<compat> 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;;\n248E;DIGIT SEVEN FULL STOP;No;0;EN;<compat> 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;;\n248F;DIGIT EIGHT FULL STOP;No;0;EN;<compat> 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;;\n2490;DIGIT NINE FULL STOP;No;0;EN;<compat> 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;;\n2491;NUMBER TEN FULL STOP;No;0;EN;<compat> 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;;\n2492;NUMBER ELEVEN FULL STOP;No;0;EN;<compat> 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;;\n2493;NUMBER TWELVE FULL STOP;No;0;EN;<compat> 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;;\n2494;NUMBER THIRTEEN FULL STOP;No;0;EN;<compat> 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;;\n2495;NUMBER FOURTEEN FULL STOP;No;0;EN;<compat> 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;;\n2496;NUMBER FIFTEEN FULL STOP;No;0;EN;<compat> 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;;\n2497;NUMBER SIXTEEN FULL STOP;No;0;EN;<compat> 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;;\n2498;NUMBER SEVENTEEN FULL STOP;No;0;EN;<compat> 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;;\n2499;NUMBER EIGHTEEN FULL STOP;No;0;EN;<compat> 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;;\n249A;NUMBER NINETEEN FULL STOP;No;0;EN;<compat> 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;;\n249B;NUMBER TWENTY FULL STOP;No;0;EN;<compat> 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;;\n249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L;<compat> 0028 0061 0029;;;;N;;;;;\n249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L;<compat> 0028 0062 0029;;;;N;;;;;\n249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L;<compat> 0028 0063 0029;;;;N;;;;;\n249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L;<compat> 0028 0064 0029;;;;N;;;;;\n24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L;<compat> 0028 0065 0029;;;;N;;;;;\n24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L;<compat> 0028 0066 0029;;;;N;;;;;\n24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L;<compat> 0028 0067 0029;;;;N;;;;;\n24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L;<compat> 0028 0068 0029;;;;N;;;;;\n24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L;<compat> 0028 0069 0029;;;;N;;;;;\n24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L;<compat> 0028 006A 0029;;;;N;;;;;\n24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L;<compat> 0028 006B 0029;;;;N;;;;;\n24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L;<compat> 0028 006C 0029;;;;N;;;;;\n24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L;<compat> 0028 006D 0029;;;;N;;;;;\n24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L;<compat> 0028 006E 0029;;;;N;;;;;\n24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L;<compat> 0028 006F 0029;;;;N;;;;;\n24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L;<compat> 0028 0070 0029;;;;N;;;;;\n24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L;<compat> 0028 0071 0029;;;;N;;;;;\n24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L;<compat> 0028 0072 0029;;;;N;;;;;\n24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L;<compat> 0028 0073 0029;;;;N;;;;;\n24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L;<compat> 0028 0074 0029;;;;N;;;;;\n24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L;<compat> 0028 0075 0029;;;;N;;;;;\n24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L;<compat> 0028 0076 0029;;;;N;;;;;\n24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L;<compat> 0028 0077 0029;;;;N;;;;;\n24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L;<compat> 0028 0078 0029;;;;N;;;;;\n24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L;<compat> 0028 0079 0029;;;;N;;;;;\n24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L;<compat> 0028 007A 0029;;;;N;;;;;\n24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L;<circle> 0041;;;;N;;;;24D0;\n24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L;<circle> 0042;;;;N;;;;24D1;\n24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;24D2;\n24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L;<circle> 0044;;;;N;;;;24D3;\n24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L;<circle> 0045;;;;N;;;;24D4;\n24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L;<circle> 0046;;;;N;;;;24D5;\n24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L;<circle> 0047;;;;N;;;;24D6;\n24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L;<circle> 0048;;;;N;;;;24D7;\n24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L;<circle> 0049;;;;N;;;;24D8;\n24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L;<circle> 004A;;;;N;;;;24D9;\n24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L;<circle> 004B;;;;N;;;;24DA;\n24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L;<circle> 004C;;;;N;;;;24DB;\n24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L;<circle> 004D;;;;N;;;;24DC;\n24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L;<circle> 004E;;;;N;;;;24DD;\n24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L;<circle> 004F;;;;N;;;;24DE;\n24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L;<circle> 0050;;;;N;;;;24DF;\n24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L;<circle> 0051;;;;N;;;;24E0;\n24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;24E1;\n24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L;<circle> 0053;;;;N;;;;24E2;\n24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L;<circle> 0054;;;;N;;;;24E3;\n24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L;<circle> 0055;;;;N;;;;24E4;\n24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L;<circle> 0056;;;;N;;;;24E5;\n24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L;<circle> 0057;;;;N;;;;24E6;\n24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L;<circle> 0058;;;;N;;;;24E7;\n24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L;<circle> 0059;;;;N;;;;24E8;\n24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L;<circle> 005A;;;;N;;;;24E9;\n24D0;CIRCLED LATIN SMALL LETTER A;So;0;L;<circle> 0061;;;;N;;;24B6;;24B6\n24D1;CIRCLED LATIN SMALL LETTER B;So;0;L;<circle> 0062;;;;N;;;24B7;;24B7\n24D2;CIRCLED LATIN SMALL LETTER C;So;0;L;<circle> 0063;;;;N;;;24B8;;24B8\n24D3;CIRCLED LATIN SMALL LETTER D;So;0;L;<circle> 0064;;;;N;;;24B9;;24B9\n24D4;CIRCLED LATIN SMALL LETTER E;So;0;L;<circle> 0065;;;;N;;;24BA;;24BA\n24D5;CIRCLED LATIN SMALL LETTER F;So;0;L;<circle> 0066;;;;N;;;24BB;;24BB\n24D6;CIRCLED LATIN SMALL LETTER G;So;0;L;<circle> 0067;;;;N;;;24BC;;24BC\n24D7;CIRCLED LATIN SMALL LETTER H;So;0;L;<circle> 0068;;;;N;;;24BD;;24BD\n24D8;CIRCLED LATIN SMALL LETTER I;So;0;L;<circle> 0069;;;;N;;;24BE;;24BE\n24D9;CIRCLED LATIN SMALL LETTER J;So;0;L;<circle> 006A;;;;N;;;24BF;;24BF\n24DA;CIRCLED LATIN SMALL LETTER K;So;0;L;<circle> 006B;;;;N;;;24C0;;24C0\n24DB;CIRCLED LATIN SMALL LETTER L;So;0;L;<circle> 006C;;;;N;;;24C1;;24C1\n24DC;CIRCLED LATIN SMALL LETTER M;So;0;L;<circle> 006D;;;;N;;;24C2;;24C2\n24DD;CIRCLED LATIN SMALL LETTER N;So;0;L;<circle> 006E;;;;N;;;24C3;;24C3\n24DE;CIRCLED LATIN SMALL LETTER O;So;0;L;<circle> 006F;;;;N;;;24C4;;24C4\n24DF;CIRCLED LATIN SMALL LETTER P;So;0;L;<circle> 0070;;;;N;;;24C5;;24C5\n24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L;<circle> 0071;;;;N;;;24C6;;24C6\n24E1;CIRCLED LATIN SMALL LETTER R;So;0;L;<circle> 0072;;;;N;;;24C7;;24C7\n24E2;CIRCLED LATIN SMALL LETTER S;So;0;L;<circle> 0073;;;;N;;;24C8;;24C8\n24E3;CIRCLED LATIN SMALL LETTER T;So;0;L;<circle> 0074;;;;N;;;24C9;;24C9\n24E4;CIRCLED LATIN SMALL LETTER U;So;0;L;<circle> 0075;;;;N;;;24CA;;24CA\n24E5;CIRCLED LATIN SMALL LETTER V;So;0;L;<circle> 0076;;;;N;;;24CB;;24CB\n24E6;CIRCLED LATIN SMALL LETTER W;So;0;L;<circle> 0077;;;;N;;;24CC;;24CC\n24E7;CIRCLED LATIN SMALL LETTER X;So;0;L;<circle> 0078;;;;N;;;24CD;;24CD\n24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L;<circle> 0079;;;;N;;;24CE;;24CE\n24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L;<circle> 007A;;;;N;;;24CF;;24CF\n24EA;CIRCLED DIGIT ZERO;No;0;ON;<circle> 0030;;0;0;N;;;;;\n24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;;\n24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;;\n24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;;\n24EE;NEGATIVE CIRCLED NUMBER FOURTEEN;No;0;ON;;;;14;N;;;;;\n24EF;NEGATIVE CIRCLED NUMBER FIFTEEN;No;0;ON;;;;15;N;;;;;\n24F0;NEGATIVE CIRCLED NUMBER SIXTEEN;No;0;ON;;;;16;N;;;;;\n24F1;NEGATIVE CIRCLED NUMBER SEVENTEEN;No;0;ON;;;;17;N;;;;;\n24F2;NEGATIVE CIRCLED NUMBER EIGHTEEN;No;0;ON;;;;18;N;;;;;\n24F3;NEGATIVE CIRCLED NUMBER NINETEEN;No;0;ON;;;;19;N;;;;;\n24F4;NEGATIVE CIRCLED NUMBER TWENTY;No;0;ON;;;;20;N;;;;;\n24F5;DOUBLE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;;;;;\n24F6;DOUBLE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;;;;;\n24F7;DOUBLE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;;;;;\n24F8;DOUBLE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;;;;;\n24F9;DOUBLE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;;;;;\n24FA;DOUBLE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;;;;;\n24FB;DOUBLE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;;;;;\n24FC;DOUBLE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;;;;;\n24FD;DOUBLE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;;;;;\n24FE;DOUBLE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;;;;;\n24FF;NEGATIVE CIRCLED DIGIT ZERO;No;0;ON;;;0;0;N;;;;;\n2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;;\n2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;;\n2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;;\n2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;;\n2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;;\n2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;;\n2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;;\n2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;;\n2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;;\n2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;;\n250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;;\n250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;;\n250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;;\n250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;;\n250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;;\n250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;;\n2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;;\n2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;;\n2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;;\n2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;;\n2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;;\n2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;;\n2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;;\n2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;;\n2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;;\n2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;;\n251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;;\n251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;;\n251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;;\n251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;;\n251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;;\n251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;;\n2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;;\n2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;;\n2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;;\n2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;;\n2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;;\n2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;;\n2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;;\n2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;;\n2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;;\n2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;;\n252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;;\n252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;;\n252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;;\n252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;;\n252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;;\n252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;;\n2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;;\n2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;;\n2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;;\n2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;;\n2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;;\n2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;;\n2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;;\n2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;;\n2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;;\n2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;;\n253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;;\n253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;;\n253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;;\n253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;;\n253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;;\n253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;;\n2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;;\n2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;;\n2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;;\n2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;;\n2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;;\n2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;;\n2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;;\n2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;;\n2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;;\n2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;;\n254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;;\n254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;;\n254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;;\n254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;;\n254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;;\n254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;;\n2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;;\n2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;;\n2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;;\n2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;;\n2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;;\n2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;;\n2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;;\n2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;;\n2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;;\n2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;;\n255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;;\n255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;;\n255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;;\n255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;;\n255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;;\n255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;;\n2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;;\n2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;;\n2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;;\n2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;;\n2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;;\n2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;;\n2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;;\n2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;;\n2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;;\n2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;;\n256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;;\n256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;;\n256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;;\n256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;;\n256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;;\n256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;;\n2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;;\n2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;;\n2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;;\n2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;;\n2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;;\n2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;;\n2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;;\n2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;;\n2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;;\n2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;;\n257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;;\n257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;;\n257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;;\n257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;;\n257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;;\n257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;;\n2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;;\n2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;;\n2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;;\n2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n2588;FULL BLOCK;So;0;ON;;;;;N;;;;;\n2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;;\n258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;;\n258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;;\n2591;LIGHT SHADE;So;0;ON;;;;;N;;;;;\n2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n2593;DARK SHADE;So;0;ON;;;;;N;;;;;\n2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n2596;QUADRANT LOWER LEFT;So;0;ON;;;;;N;;;;;\n2597;QUADRANT LOWER RIGHT;So;0;ON;;;;;N;;;;;\n2598;QUADRANT UPPER LEFT;So;0;ON;;;;;N;;;;;\n2599;QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;\n259A;QUADRANT UPPER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;\n259B;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;;\n259C;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;\n259D;QUADRANT UPPER RIGHT;So;0;ON;;;;;N;;;;;\n259E;QUADRANT UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;;\n259F;QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;\n25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;;\n25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;;\n25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;\n25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;\n25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;;\n25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;\n25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;\n25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;;\n25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;;\n25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;\n25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;\n25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;;\n25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;;\n25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;;\n25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;\n25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;\n25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;;\n25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;;\n25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;;\n25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;;\n25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;;\n25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;;\n25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;;\n25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;;\n25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;;\n25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;;\n25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;;\n25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;;\n25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;;\n25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;;\n25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;;\n25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;;\n25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;;\n25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;;\n25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;;\n25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;;\n25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;;\n25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;;\n25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;;\n25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;;\n25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;;\n25C9;FISHEYE;So;0;ON;;;;;N;;;;;\n25CA;LOZENGE;So;0;ON;;;;;N;;;;;\n25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;;\n25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;\n25CE;BULLSEYE;So;0;ON;;;;;N;;;;;\n25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;\n25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;\n25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;;\n25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;;\n25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;;\n25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;;\n25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;;\n25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;\n25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;\n25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;\n25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;\n25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;;\n25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;;\n25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;\n25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;\n25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;\n25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;\n25E6;WHITE BULLET;So;0;ON;;;;;N;;;;;\n25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;\n25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;\n25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;\n25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;\n25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;;\n25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;;\n25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;;\n25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;;\n25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;;\n25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;\n25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;\n25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;\n25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;\n25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;\n25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;\n25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;\n25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;\n25F8;UPPER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;;\n25F9;UPPER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;;\n25FA;LOWER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;;\n25FB;WHITE MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;;\n25FC;BLACK MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;;\n25FD;WHITE MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;;\n25FE;BLACK MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;;\n25FF;LOWER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;;\n2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;;\n2601;CLOUD;So;0;ON;;;;;N;;;;;\n2602;UMBRELLA;So;0;ON;;;;;N;;;;;\n2603;SNOWMAN;So;0;ON;;;;;N;;;;;\n2604;COMET;So;0;ON;;;;;N;;;;;\n2605;BLACK STAR;So;0;ON;;;;;N;;;;;\n2606;WHITE STAR;So;0;ON;;;;;N;;;;;\n2607;LIGHTNING;So;0;ON;;;;;N;;;;;\n2608;THUNDERSTORM;So;0;ON;;;;;N;;;;;\n2609;SUN;So;0;ON;;;;;N;;;;;\n260A;ASCENDING NODE;So;0;ON;;;;;N;;;;;\n260B;DESCENDING NODE;So;0;ON;;;;;N;;;;;\n260C;CONJUNCTION;So;0;ON;;;;;N;;;;;\n260D;OPPOSITION;So;0;ON;;;;;N;;;;;\n260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;;\n260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;;\n2610;BALLOT BOX;So;0;ON;;;;;N;;;;;\n2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;;\n2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;;\n2613;SALTIRE;So;0;ON;;;;;N;;;;;\n2614;UMBRELLA WITH RAIN DROPS;So;0;ON;;;;;N;;;;;\n2615;HOT BEVERAGE;So;0;ON;;;;;N;;;;;\n2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;;\n2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;;\n2618;SHAMROCK;So;0;ON;;;;;N;;;;;\n2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;\n261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;\n261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;\n261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;\n261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;;\n261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;\n261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;\n2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;;\n2621;CAUTION SIGN;So;0;ON;;;;;N;;;;;\n2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;;\n2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;;\n2624;CADUCEUS;So;0;ON;;;;;N;;;;;\n2625;ANKH;So;0;ON;;;;;N;;;;;\n2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;;\n2627;CHI RHO;So;0;ON;;;;;N;;;;;\n2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;;\n2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;;\n262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;;\n262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;;\n262C;ADI SHAKTI;So;0;ON;;;;;N;;;;;\n262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;;\n262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;;\n262F;YIN YANG;So;0;ON;;;;;N;;;;;\n2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;;\n2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;;\n2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;;\n2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;;\n2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;;\n2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;;\n2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;;\n2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;\n2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;;\n2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;;\n263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;;\n263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;;\n263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;;\n263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;;\n263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;;\n263F;MERCURY;So;0;ON;;;;;N;;;;;\n2640;FEMALE SIGN;So;0;ON;;;;;N;;;;;\n2641;EARTH;So;0;ON;;;;;N;;;;;\n2642;MALE SIGN;So;0;ON;;;;;N;;;;;\n2643;JUPITER;So;0;ON;;;;;N;;;;;\n2644;SATURN;So;0;ON;;;;;N;;;;;\n2645;URANUS;So;0;ON;;;;;N;;;;;\n2646;NEPTUNE;So;0;ON;;;;;N;;;;;\n2647;PLUTO;So;0;ON;;;;;N;;;;;\n2648;ARIES;So;0;ON;;;;;N;;;;;\n2649;TAURUS;So;0;ON;;;;;N;;;;;\n264A;GEMINI;So;0;ON;;;;;N;;;;;\n264B;CANCER;So;0;ON;;;;;N;;;;;\n264C;LEO;So;0;ON;;;;;N;;;;;\n264D;VIRGO;So;0;ON;;;;;N;;;;;\n264E;LIBRA;So;0;ON;;;;;N;;;;;\n264F;SCORPIUS;So;0;ON;;;;;N;;;;;\n2650;SAGITTARIUS;So;0;ON;;;;;N;;;;;\n2651;CAPRICORN;So;0;ON;;;;;N;;;;;\n2652;AQUARIUS;So;0;ON;;;;;N;;;;;\n2653;PISCES;So;0;ON;;;;;N;;;;;\n2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;;\n2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;;\n2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;;\n2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;;\n2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;;\n2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;;\n265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;;\n265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;;\n265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;;\n265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;;\n265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;;\n265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;;\n2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;;\n2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;;\n2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;;\n2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;;\n2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;;\n2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;;\n2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;;\n2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;;\n2668;HOT SPRINGS;So;0;ON;;;;;N;;;;;\n2669;QUARTER NOTE;So;0;ON;;;;;N;;;;;\n266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;;\n266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;;\n266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;;\n266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;;\n266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;;\n266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;;\n2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;;\n2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;;\n2672;UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;;\n2673;RECYCLING SYMBOL FOR TYPE-1 PLASTICS;So;0;ON;;;;;N;;;;;\n2674;RECYCLING SYMBOL FOR TYPE-2 PLASTICS;So;0;ON;;;;;N;;;;;\n2675;RECYCLING SYMBOL FOR TYPE-3 PLASTICS;So;0;ON;;;;;N;;;;;\n2676;RECYCLING SYMBOL FOR TYPE-4 PLASTICS;So;0;ON;;;;;N;;;;;\n2677;RECYCLING SYMBOL FOR TYPE-5 PLASTICS;So;0;ON;;;;;N;;;;;\n2678;RECYCLING SYMBOL FOR TYPE-6 PLASTICS;So;0;ON;;;;;N;;;;;\n2679;RECYCLING SYMBOL FOR TYPE-7 PLASTICS;So;0;ON;;;;;N;;;;;\n267A;RECYCLING SYMBOL FOR GENERIC MATERIALS;So;0;ON;;;;;N;;;;;\n267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;;\n267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;;\n267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;;\n267E;PERMANENT PAPER SIGN;So;0;ON;;;;;N;;;;;\n267F;WHEELCHAIR SYMBOL;So;0;ON;;;;;N;;;;;\n2680;DIE FACE-1;So;0;ON;;;;;N;;;;;\n2681;DIE FACE-2;So;0;ON;;;;;N;;;;;\n2682;DIE FACE-3;So;0;ON;;;;;N;;;;;\n2683;DIE FACE-4;So;0;ON;;;;;N;;;;;\n2684;DIE FACE-5;So;0;ON;;;;;N;;;;;\n2685;DIE FACE-6;So;0;ON;;;;;N;;;;;\n2686;WHITE CIRCLE WITH DOT RIGHT;So;0;ON;;;;;N;;;;;\n2687;WHITE CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;;\n2688;BLACK CIRCLE WITH WHITE DOT RIGHT;So;0;ON;;;;;N;;;;;\n2689;BLACK CIRCLE WITH TWO WHITE DOTS;So;0;ON;;;;;N;;;;;\n268A;MONOGRAM FOR YANG;So;0;ON;;;;;N;;;;;\n268B;MONOGRAM FOR YIN;So;0;ON;;;;;N;;;;;\n268C;DIGRAM FOR GREATER YANG;So;0;ON;;;;;N;;;;;\n268D;DIGRAM FOR LESSER YIN;So;0;ON;;;;;N;;;;;\n268E;DIGRAM FOR LESSER YANG;So;0;ON;;;;;N;;;;;\n268F;DIGRAM FOR GREATER YIN;So;0;ON;;;;;N;;;;;\n2690;WHITE FLAG;So;0;ON;;;;;N;;;;;\n2691;BLACK FLAG;So;0;ON;;;;;N;;;;;\n2692;HAMMER AND PICK;So;0;ON;;;;;N;;;;;\n2693;ANCHOR;So;0;ON;;;;;N;;;;;\n2694;CROSSED SWORDS;So;0;ON;;;;;N;;;;;\n2695;STAFF OF AESCULAPIUS;So;0;ON;;;;;N;;;;;\n2696;SCALES;So;0;ON;;;;;N;;;;;\n2697;ALEMBIC;So;0;ON;;;;;N;;;;;\n2698;FLOWER;So;0;ON;;;;;N;;;;;\n2699;GEAR;So;0;ON;;;;;N;;;;;\n269A;STAFF OF HERMES;So;0;ON;;;;;N;;;;;\n269B;ATOM SYMBOL;So;0;ON;;;;;N;;;;;\n269C;FLEUR-DE-LIS;So;0;ON;;;;;N;;;;;\n269D;OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;;\n269E;THREE LINES CONVERGING RIGHT;So;0;ON;;;;;N;;;;;\n269F;THREE LINES CONVERGING LEFT;So;0;ON;;;;;N;;;;;\n26A0;WARNING SIGN;So;0;ON;;;;;N;;;;;\n26A1;HIGH VOLTAGE SIGN;So;0;ON;;;;;N;;;;;\n26A2;DOUBLED FEMALE SIGN;So;0;ON;;;;;N;;;;;\n26A3;DOUBLED MALE SIGN;So;0;ON;;;;;N;;;;;\n26A4;INTERLOCKED FEMALE AND MALE SIGN;So;0;ON;;;;;N;;;;;\n26A5;MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;;\n26A6;MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;\n26A7;MALE WITH STROKE AND MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;;\n26A8;VERTICAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;\n26A9;HORIZONTAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;\n26AA;MEDIUM WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n26AB;MEDIUM BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n26AC;MEDIUM SMALL WHITE CIRCLE;So;0;L;;;;;N;;;;;\n26AD;MARRIAGE SYMBOL;So;0;ON;;;;;N;;;;;\n26AE;DIVORCE SYMBOL;So;0;ON;;;;;N;;;;;\n26AF;UNMARRIED PARTNERSHIP SYMBOL;So;0;ON;;;;;N;;;;;\n26B0;COFFIN;So;0;ON;;;;;N;;;;;\n26B1;FUNERAL URN;So;0;ON;;;;;N;;;;;\n26B2;NEUTER;So;0;ON;;;;;N;;;;;\n26B3;CERES;So;0;ON;;;;;N;;;;;\n26B4;PALLAS;So;0;ON;;;;;N;;;;;\n26B5;JUNO;So;0;ON;;;;;N;;;;;\n26B6;VESTA;So;0;ON;;;;;N;;;;;\n26B7;CHIRON;So;0;ON;;;;;N;;;;;\n26B8;BLACK MOON LILITH;So;0;ON;;;;;N;;;;;\n26B9;SEXTILE;So;0;ON;;;;;N;;;;;\n26BA;SEMISEXTILE;So;0;ON;;;;;N;;;;;\n26BB;QUINCUNX;So;0;ON;;;;;N;;;;;\n26BC;SESQUIQUADRATE;So;0;ON;;;;;N;;;;;\n26BD;SOCCER BALL;So;0;ON;;;;;N;;;;;\n26BE;BASEBALL;So;0;ON;;;;;N;;;;;\n26BF;SQUARED KEY;So;0;ON;;;;;N;;;;;\n26C0;WHITE DRAUGHTS MAN;So;0;ON;;;;;N;;;;;\n26C1;WHITE DRAUGHTS KING;So;0;ON;;;;;N;;;;;\n26C2;BLACK DRAUGHTS MAN;So;0;ON;;;;;N;;;;;\n26C3;BLACK DRAUGHTS KING;So;0;ON;;;;;N;;;;;\n26C4;SNOWMAN WITHOUT SNOW;So;0;ON;;;;;N;;;;;\n26C5;SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;;\n26C6;RAIN;So;0;ON;;;;;N;;;;;\n26C7;BLACK SNOWMAN;So;0;ON;;;;;N;;;;;\n26C8;THUNDER CLOUD AND RAIN;So;0;ON;;;;;N;;;;;\n26C9;TURNED WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;;\n26CA;TURNED BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;;\n26CB;WHITE DIAMOND IN SQUARE;So;0;ON;;;;;N;;;;;\n26CC;CROSSING LANES;So;0;ON;;;;;N;;;;;\n26CD;DISABLED CAR;So;0;ON;;;;;N;;;;;\n26CE;OPHIUCHUS;So;0;ON;;;;;N;;;;;\n26CF;PICK;So;0;ON;;;;;N;;;;;\n26D0;CAR SLIDING;So;0;ON;;;;;N;;;;;\n26D1;HELMET WITH WHITE CROSS;So;0;ON;;;;;N;;;;;\n26D2;CIRCLED CROSSING LANES;So;0;ON;;;;;N;;;;;\n26D3;CHAINS;So;0;ON;;;;;N;;;;;\n26D4;NO ENTRY;So;0;ON;;;;;N;;;;;\n26D5;ALTERNATE ONE-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;;\n26D6;BLACK TWO-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;;\n26D7;WHITE TWO-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;;\n26D8;BLACK LEFT LANE MERGE;So;0;ON;;;;;N;;;;;\n26D9;WHITE LEFT LANE MERGE;So;0;ON;;;;;N;;;;;\n26DA;DRIVE SLOW SIGN;So;0;ON;;;;;N;;;;;\n26DB;HEAVY WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n26DC;LEFT CLOSED ENTRY;So;0;ON;;;;;N;;;;;\n26DD;SQUARED SALTIRE;So;0;ON;;;;;N;;;;;\n26DE;FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARE;So;0;ON;;;;;N;;;;;\n26DF;BLACK TRUCK;So;0;ON;;;;;N;;;;;\n26E0;RESTRICTED LEFT ENTRY-1;So;0;ON;;;;;N;;;;;\n26E1;RESTRICTED LEFT ENTRY-2;So;0;ON;;;;;N;;;;;\n26E2;ASTRONOMICAL SYMBOL FOR URANUS;So;0;ON;;;;;N;;;;;\n26E3;HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE;So;0;ON;;;;;N;;;;;\n26E4;PENTAGRAM;So;0;ON;;;;;N;;;;;\n26E5;RIGHT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;;\n26E6;LEFT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;;\n26E7;INVERTED PENTAGRAM;So;0;ON;;;;;N;;;;;\n26E8;BLACK CROSS ON SHIELD;So;0;ON;;;;;N;;;;;\n26E9;SHINTO SHRINE;So;0;ON;;;;;N;;;;;\n26EA;CHURCH;So;0;ON;;;;;N;;;;;\n26EB;CASTLE;So;0;ON;;;;;N;;;;;\n26EC;HISTORIC SITE;So;0;ON;;;;;N;;;;;\n26ED;GEAR WITHOUT HUB;So;0;ON;;;;;N;;;;;\n26EE;GEAR WITH HANDLES;So;0;ON;;;;;N;;;;;\n26EF;MAP SYMBOL FOR LIGHTHOUSE;So;0;ON;;;;;N;;;;;\n26F0;MOUNTAIN;So;0;ON;;;;;N;;;;;\n26F1;UMBRELLA ON GROUND;So;0;ON;;;;;N;;;;;\n26F2;FOUNTAIN;So;0;ON;;;;;N;;;;;\n26F3;FLAG IN HOLE;So;0;ON;;;;;N;;;;;\n26F4;FERRY;So;0;ON;;;;;N;;;;;\n26F5;SAILBOAT;So;0;ON;;;;;N;;;;;\n26F6;SQUARE FOUR CORNERS;So;0;ON;;;;;N;;;;;\n26F7;SKIER;So;0;ON;;;;;N;;;;;\n26F8;ICE SKATE;So;0;ON;;;;;N;;;;;\n26F9;PERSON WITH BALL;So;0;ON;;;;;N;;;;;\n26FA;TENT;So;0;ON;;;;;N;;;;;\n26FB;JAPANESE BANK SYMBOL;So;0;ON;;;;;N;;;;;\n26FC;HEADSTONE GRAVEYARD SYMBOL;So;0;ON;;;;;N;;;;;\n26FD;FUEL PUMP;So;0;ON;;;;;N;;;;;\n26FE;CUP ON BLACK SQUARE;So;0;ON;;;;;N;;;;;\n26FF;WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE;So;0;ON;;;;;N;;;;;\n2700;BLACK SAFETY SCISSORS;So;0;ON;;;;;N;;;;;\n2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;;\n2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;;\n2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;;\n2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;;\n2705;WHITE HEAVY CHECK MARK;So;0;ON;;;;;N;;;;;\n2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;;\n2707;TAPE DRIVE;So;0;ON;;;;;N;;;;;\n2708;AIRPLANE;So;0;ON;;;;;N;;;;;\n2709;ENVELOPE;So;0;ON;;;;;N;;;;;\n270A;RAISED FIST;So;0;ON;;;;;N;;;;;\n270B;RAISED HAND;So;0;ON;;;;;N;;;;;\n270C;VICTORY HAND;So;0;ON;;;;;N;;;;;\n270D;WRITING HAND;So;0;ON;;;;;N;;;;;\n270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;;\n270F;PENCIL;So;0;ON;;;;;N;;;;;\n2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;;\n2711;WHITE NIB;So;0;ON;;;;;N;;;;;\n2712;BLACK NIB;So;0;ON;;;;;N;;;;;\n2713;CHECK MARK;So;0;ON;;;;;N;;;;;\n2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;;\n2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;;\n2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;;\n2717;BALLOT X;So;0;ON;;;;;N;;;;;\n2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;;\n2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;;\n271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;\n271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;;\n271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;;\n271D;LATIN CROSS;So;0;ON;;;;;N;;;;;\n271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;;\n271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;;\n2720;MALTESE CROSS;So;0;ON;;;;;N;;;;;\n2721;STAR OF DAVID;So;0;ON;;;;;N;;;;;\n2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;;\n2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;;\n2728;SPARKLES;So;0;ON;;;;;N;;;;;\n2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;;\n272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;;\n272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;;\n272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;;\n272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;\n272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;\n272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;;\n2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;;\n2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;;\n2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;;\n2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;\n2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;\n2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;\n2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;;\n273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;;\n273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;;\n273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;;\n2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;;\n2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;;\n2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;;\n2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;;\n2744;SNOWFLAKE;So;0;ON;;;;;N;;;;;\n2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;;\n2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;;\n2747;SPARKLE;So;0;ON;;;;;N;;;;;\n2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;;\n2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;\n274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;\n274C;CROSS MARK;So;0;ON;;;;;N;;;;;\n274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n274E;NEGATIVE SQUARED CROSS MARK;So;0;ON;;;;;N;;;;;\n274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;\n2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;\n2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;\n2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;\n2753;BLACK QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n2754;WHITE QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n2755;WHITE EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;;\n2757;HEAVY EXCLAMATION MARK SYMBOL;So;0;ON;;;;;N;;;;;\n2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;;\n2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;;\n275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;;\n275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n275F;HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n2760;HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;;\n2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;;\n2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;;\n2766;FLORAL HEART;So;0;ON;;;;;N;;;;;\n2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;\n2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;;\n2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;;\n276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;;\n276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;;\n276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;\n276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;\n276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps;0;ON;;;;;Y;;;;;\n276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe;0;ON;;;;;Y;;;;;\n2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;\n2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;\n2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;\n2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;\n2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;\n2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;\n2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;;\n2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;;\n2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;;\n2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;;\n277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;;\n277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;;\n277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;;\n277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;;\n277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;;\n277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;;\n2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;;\n2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;;\n2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;;\n2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;;\n2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;;\n2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;;\n2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;;\n2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;;\n2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;;\n2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;;\n278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;;\n278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;;\n278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;;\n278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;;\n278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;;\n278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;;\n2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;;\n2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;;\n2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;;\n2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;;\n2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;;\n2795;HEAVY PLUS SIGN;So;0;ON;;;;;N;;;;;\n2796;HEAVY MINUS SIGN;So;0;ON;;;;;N;;;;;\n2797;HEAVY DIVISION SIGN;So;0;ON;;;;;N;;;;;\n2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;;\n2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;;\n279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;;\n279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;;\n279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;;\n279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;;\n279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;;\n279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;;\n27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;;\n27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;;\n27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;;\n27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;;\n27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;;\n27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;;\n27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;;\n27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;;\n27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;;\n27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;;\n27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;;\n27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;;\n27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;;\n27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;\n27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;\n27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;\n27B0;CURLY LOOP;So;0;ON;;;;;N;;;;;\n27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;\n27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;;\n27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;;\n27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;;\n27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;;\n27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;;\n27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;;\n27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;;\n27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;;\n27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;;\n27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;;\n27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;;\n27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;;\n27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;;\n27BF;DOUBLE CURLY LOOP;So;0;ON;;;;;N;;;;;\n27C0;THREE DIMENSIONAL ANGLE;Sm;0;ON;;;;;Y;;;;;\n27C1;WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE;Sm;0;ON;;;;;N;;;;;\n27C2;PERPENDICULAR;Sm;0;ON;;;;;N;;;;;\n27C3;OPEN SUBSET;Sm;0;ON;;;;;Y;;;;;\n27C4;OPEN SUPERSET;Sm;0;ON;;;;;Y;;;;;\n27C5;LEFT S-SHAPED BAG DELIMITER;Ps;0;ON;;;;;Y;;;;;\n27C6;RIGHT S-SHAPED BAG DELIMITER;Pe;0;ON;;;;;Y;;;;;\n27C7;OR WITH DOT INSIDE;Sm;0;ON;;;;;N;;;;;\n27C8;REVERSE SOLIDUS PRECEDING SUBSET;Sm;0;ON;;;;;Y;;;;;\n27C9;SUPERSET PRECEDING SOLIDUS;Sm;0;ON;;;;;Y;;;;;\n27CA;VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;\n27CB;MATHEMATICAL RISING DIAGONAL;Sm;0;ON;;;;;Y;;;;;\n27CC;LONG DIVISION;Sm;0;ON;;;;;Y;;;;;\n27CD;MATHEMATICAL FALLING DIAGONAL;Sm;0;ON;;;;;Y;;;;;\n27CE;SQUARED LOGICAL AND;Sm;0;ON;;;;;N;;;;;\n27CF;SQUARED LOGICAL OR;Sm;0;ON;;;;;N;;;;;\n27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;;\n27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;;\n27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;;\n27D3;LOWER RIGHT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;;\n27D4;UPPER LEFT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;;\n27D5;LEFT OUTER JOIN;Sm;0;ON;;;;;Y;;;;;\n27D6;RIGHT OUTER JOIN;Sm;0;ON;;;;;Y;;;;;\n27D7;FULL OUTER JOIN;Sm;0;ON;;;;;N;;;;;\n27D8;LARGE UP TACK;Sm;0;ON;;;;;N;;;;;\n27D9;LARGE DOWN TACK;Sm;0;ON;;;;;N;;;;;\n27DA;LEFT AND RIGHT DOUBLE TURNSTILE;Sm;0;ON;;;;;N;;;;;\n27DB;LEFT AND RIGHT TACK;Sm;0;ON;;;;;N;;;;;\n27DC;LEFT MULTIMAP;Sm;0;ON;;;;;Y;;;;;\n27DD;LONG RIGHT TACK;Sm;0;ON;;;;;Y;;;;;\n27DE;LONG LEFT TACK;Sm;0;ON;;;;;Y;;;;;\n27DF;UP TACK WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;\n27E0;LOZENGE DIVIDED BY HORIZONTAL RULE;Sm;0;ON;;;;;N;;;;;\n27E1;WHITE CONCAVE-SIDED DIAMOND;Sm;0;ON;;;;;N;;;;;\n27E2;WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;;\n27E3;WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;;\n27E4;WHITE SQUARE WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;;\n27E5;WHITE SQUARE WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;;\n27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;;;;;\n27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;;;;;\n27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;\n27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;\n27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;\n27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;\n27EC;MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;;\n27ED;MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;;\n27EE;MATHEMATICAL LEFT FLATTENED PARENTHESIS;Ps;0;ON;;;;;Y;;;;;\n27EF;MATHEMATICAL RIGHT FLATTENED PARENTHESIS;Pe;0;ON;;;;;Y;;;;;\n27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;;\n27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;;\n27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;\n27F3;CLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;\n27F4;RIGHT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;\n27F5;LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n27F6;LONG RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n27F7;LONG LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;\n27F8;LONG LEFTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;\n27F9;LONG RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;\n27FA;LONG LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;\n27FB;LONG LEFTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;\n27FC;LONG RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;\n27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;\n27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;\n27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;;\n2800;BRAILLE PATTERN BLANK;So;0;L;;;;;N;;;;;\n2801;BRAILLE PATTERN DOTS-1;So;0;L;;;;;N;;;;;\n2802;BRAILLE PATTERN DOTS-2;So;0;L;;;;;N;;;;;\n2803;BRAILLE PATTERN DOTS-12;So;0;L;;;;;N;;;;;\n2804;BRAILLE PATTERN DOTS-3;So;0;L;;;;;N;;;;;\n2805;BRAILLE PATTERN DOTS-13;So;0;L;;;;;N;;;;;\n2806;BRAILLE PATTERN DOTS-23;So;0;L;;;;;N;;;;;\n2807;BRAILLE PATTERN DOTS-123;So;0;L;;;;;N;;;;;\n2808;BRAILLE PATTERN DOTS-4;So;0;L;;;;;N;;;;;\n2809;BRAILLE PATTERN DOTS-14;So;0;L;;;;;N;;;;;\n280A;BRAILLE PATTERN DOTS-24;So;0;L;;;;;N;;;;;\n280B;BRAILLE PATTERN DOTS-124;So;0;L;;;;;N;;;;;\n280C;BRAILLE PATTERN DOTS-34;So;0;L;;;;;N;;;;;\n280D;BRAILLE PATTERN DOTS-134;So;0;L;;;;;N;;;;;\n280E;BRAILLE PATTERN DOTS-234;So;0;L;;;;;N;;;;;\n280F;BRAILLE PATTERN DOTS-1234;So;0;L;;;;;N;;;;;\n2810;BRAILLE PATTERN DOTS-5;So;0;L;;;;;N;;;;;\n2811;BRAILLE PATTERN DOTS-15;So;0;L;;;;;N;;;;;\n2812;BRAILLE PATTERN DOTS-25;So;0;L;;;;;N;;;;;\n2813;BRAILLE PATTERN DOTS-125;So;0;L;;;;;N;;;;;\n2814;BRAILLE PATTERN DOTS-35;So;0;L;;;;;N;;;;;\n2815;BRAILLE PATTERN DOTS-135;So;0;L;;;;;N;;;;;\n2816;BRAILLE PATTERN DOTS-235;So;0;L;;;;;N;;;;;\n2817;BRAILLE PATTERN DOTS-1235;So;0;L;;;;;N;;;;;\n2818;BRAILLE PATTERN DOTS-45;So;0;L;;;;;N;;;;;\n2819;BRAILLE PATTERN DOTS-145;So;0;L;;;;;N;;;;;\n281A;BRAILLE PATTERN DOTS-245;So;0;L;;;;;N;;;;;\n281B;BRAILLE PATTERN DOTS-1245;So;0;L;;;;;N;;;;;\n281C;BRAILLE PATTERN DOTS-345;So;0;L;;;;;N;;;;;\n281D;BRAILLE PATTERN DOTS-1345;So;0;L;;;;;N;;;;;\n281E;BRAILLE PATTERN DOTS-2345;So;0;L;;;;;N;;;;;\n281F;BRAILLE PATTERN DOTS-12345;So;0;L;;;;;N;;;;;\n2820;BRAILLE PATTERN DOTS-6;So;0;L;;;;;N;;;;;\n2821;BRAILLE PATTERN DOTS-16;So;0;L;;;;;N;;;;;\n2822;BRAILLE PATTERN DOTS-26;So;0;L;;;;;N;;;;;\n2823;BRAILLE PATTERN DOTS-126;So;0;L;;;;;N;;;;;\n2824;BRAILLE PATTERN DOTS-36;So;0;L;;;;;N;;;;;\n2825;BRAILLE PATTERN DOTS-136;So;0;L;;;;;N;;;;;\n2826;BRAILLE PATTERN DOTS-236;So;0;L;;;;;N;;;;;\n2827;BRAILLE PATTERN DOTS-1236;So;0;L;;;;;N;;;;;\n2828;BRAILLE PATTERN DOTS-46;So;0;L;;;;;N;;;;;\n2829;BRAILLE PATTERN DOTS-146;So;0;L;;;;;N;;;;;\n282A;BRAILLE PATTERN DOTS-246;So;0;L;;;;;N;;;;;\n282B;BRAILLE PATTERN DOTS-1246;So;0;L;;;;;N;;;;;\n282C;BRAILLE PATTERN DOTS-346;So;0;L;;;;;N;;;;;\n282D;BRAILLE PATTERN DOTS-1346;So;0;L;;;;;N;;;;;\n282E;BRAILLE PATTERN DOTS-2346;So;0;L;;;;;N;;;;;\n282F;BRAILLE PATTERN DOTS-12346;So;0;L;;;;;N;;;;;\n2830;BRAILLE PATTERN DOTS-56;So;0;L;;;;;N;;;;;\n2831;BRAILLE PATTERN DOTS-156;So;0;L;;;;;N;;;;;\n2832;BRAILLE PATTERN DOTS-256;So;0;L;;;;;N;;;;;\n2833;BRAILLE PATTERN DOTS-1256;So;0;L;;;;;N;;;;;\n2834;BRAILLE PATTERN DOTS-356;So;0;L;;;;;N;;;;;\n2835;BRAILLE PATTERN DOTS-1356;So;0;L;;;;;N;;;;;\n2836;BRAILLE PATTERN DOTS-2356;So;0;L;;;;;N;;;;;\n2837;BRAILLE PATTERN DOTS-12356;So;0;L;;;;;N;;;;;\n2838;BRAILLE PATTERN DOTS-456;So;0;L;;;;;N;;;;;\n2839;BRAILLE PATTERN DOTS-1456;So;0;L;;;;;N;;;;;\n283A;BRAILLE PATTERN DOTS-2456;So;0;L;;;;;N;;;;;\n283B;BRAILLE PATTERN DOTS-12456;So;0;L;;;;;N;;;;;\n283C;BRAILLE PATTERN DOTS-3456;So;0;L;;;;;N;;;;;\n283D;BRAILLE PATTERN DOTS-13456;So;0;L;;;;;N;;;;;\n283E;BRAILLE PATTERN DOTS-23456;So;0;L;;;;;N;;;;;\n283F;BRAILLE PATTERN DOTS-123456;So;0;L;;;;;N;;;;;\n2840;BRAILLE PATTERN DOTS-7;So;0;L;;;;;N;;;;;\n2841;BRAILLE PATTERN DOTS-17;So;0;L;;;;;N;;;;;\n2842;BRAILLE PATTERN DOTS-27;So;0;L;;;;;N;;;;;\n2843;BRAILLE PATTERN DOTS-127;So;0;L;;;;;N;;;;;\n2844;BRAILLE PATTERN DOTS-37;So;0;L;;;;;N;;;;;\n2845;BRAILLE PATTERN DOTS-137;So;0;L;;;;;N;;;;;\n2846;BRAILLE PATTERN DOTS-237;So;0;L;;;;;N;;;;;\n2847;BRAILLE PATTERN DOTS-1237;So;0;L;;;;;N;;;;;\n2848;BRAILLE PATTERN DOTS-47;So;0;L;;;;;N;;;;;\n2849;BRAILLE PATTERN DOTS-147;So;0;L;;;;;N;;;;;\n284A;BRAILLE PATTERN DOTS-247;So;0;L;;;;;N;;;;;\n284B;BRAILLE PATTERN DOTS-1247;So;0;L;;;;;N;;;;;\n284C;BRAILLE PATTERN DOTS-347;So;0;L;;;;;N;;;;;\n284D;BRAILLE PATTERN DOTS-1347;So;0;L;;;;;N;;;;;\n284E;BRAILLE PATTERN DOTS-2347;So;0;L;;;;;N;;;;;\n284F;BRAILLE PATTERN DOTS-12347;So;0;L;;;;;N;;;;;\n2850;BRAILLE PATTERN DOTS-57;So;0;L;;;;;N;;;;;\n2851;BRAILLE PATTERN DOTS-157;So;0;L;;;;;N;;;;;\n2852;BRAILLE PATTERN DOTS-257;So;0;L;;;;;N;;;;;\n2853;BRAILLE PATTERN DOTS-1257;So;0;L;;;;;N;;;;;\n2854;BRAILLE PATTERN DOTS-357;So;0;L;;;;;N;;;;;\n2855;BRAILLE PATTERN DOTS-1357;So;0;L;;;;;N;;;;;\n2856;BRAILLE PATTERN DOTS-2357;So;0;L;;;;;N;;;;;\n2857;BRAILLE PATTERN DOTS-12357;So;0;L;;;;;N;;;;;\n2858;BRAILLE PATTERN DOTS-457;So;0;L;;;;;N;;;;;\n2859;BRAILLE PATTERN DOTS-1457;So;0;L;;;;;N;;;;;\n285A;BRAILLE PATTERN DOTS-2457;So;0;L;;;;;N;;;;;\n285B;BRAILLE PATTERN DOTS-12457;So;0;L;;;;;N;;;;;\n285C;BRAILLE PATTERN DOTS-3457;So;0;L;;;;;N;;;;;\n285D;BRAILLE PATTERN DOTS-13457;So;0;L;;;;;N;;;;;\n285E;BRAILLE PATTERN DOTS-23457;So;0;L;;;;;N;;;;;\n285F;BRAILLE PATTERN DOTS-123457;So;0;L;;;;;N;;;;;\n2860;BRAILLE PATTERN DOTS-67;So;0;L;;;;;N;;;;;\n2861;BRAILLE PATTERN DOTS-167;So;0;L;;;;;N;;;;;\n2862;BRAILLE PATTERN DOTS-267;So;0;L;;;;;N;;;;;\n2863;BRAILLE PATTERN DOTS-1267;So;0;L;;;;;N;;;;;\n2864;BRAILLE PATTERN DOTS-367;So;0;L;;;;;N;;;;;\n2865;BRAILLE PATTERN DOTS-1367;So;0;L;;;;;N;;;;;\n2866;BRAILLE PATTERN DOTS-2367;So;0;L;;;;;N;;;;;\n2867;BRAILLE PATTERN DOTS-12367;So;0;L;;;;;N;;;;;\n2868;BRAILLE PATTERN DOTS-467;So;0;L;;;;;N;;;;;\n2869;BRAILLE PATTERN DOTS-1467;So;0;L;;;;;N;;;;;\n286A;BRAILLE PATTERN DOTS-2467;So;0;L;;;;;N;;;;;\n286B;BRAILLE PATTERN DOTS-12467;So;0;L;;;;;N;;;;;\n286C;BRAILLE PATTERN DOTS-3467;So;0;L;;;;;N;;;;;\n286D;BRAILLE PATTERN DOTS-13467;So;0;L;;;;;N;;;;;\n286E;BRAILLE PATTERN DOTS-23467;So;0;L;;;;;N;;;;;\n286F;BRAILLE PATTERN DOTS-123467;So;0;L;;;;;N;;;;;\n2870;BRAILLE PATTERN DOTS-567;So;0;L;;;;;N;;;;;\n2871;BRAILLE PATTERN DOTS-1567;So;0;L;;;;;N;;;;;\n2872;BRAILLE PATTERN DOTS-2567;So;0;L;;;;;N;;;;;\n2873;BRAILLE PATTERN DOTS-12567;So;0;L;;;;;N;;;;;\n2874;BRAILLE PATTERN DOTS-3567;So;0;L;;;;;N;;;;;\n2875;BRAILLE PATTERN DOTS-13567;So;0;L;;;;;N;;;;;\n2876;BRAILLE PATTERN DOTS-23567;So;0;L;;;;;N;;;;;\n2877;BRAILLE PATTERN DOTS-123567;So;0;L;;;;;N;;;;;\n2878;BRAILLE PATTERN DOTS-4567;So;0;L;;;;;N;;;;;\n2879;BRAILLE PATTERN DOTS-14567;So;0;L;;;;;N;;;;;\n287A;BRAILLE PATTERN DOTS-24567;So;0;L;;;;;N;;;;;\n287B;BRAILLE PATTERN DOTS-124567;So;0;L;;;;;N;;;;;\n287C;BRAILLE PATTERN DOTS-34567;So;0;L;;;;;N;;;;;\n287D;BRAILLE PATTERN DOTS-134567;So;0;L;;;;;N;;;;;\n287E;BRAILLE PATTERN DOTS-234567;So;0;L;;;;;N;;;;;\n287F;BRAILLE PATTERN DOTS-1234567;So;0;L;;;;;N;;;;;\n2880;BRAILLE PATTERN DOTS-8;So;0;L;;;;;N;;;;;\n2881;BRAILLE PATTERN DOTS-18;So;0;L;;;;;N;;;;;\n2882;BRAILLE PATTERN DOTS-28;So;0;L;;;;;N;;;;;\n2883;BRAILLE PATTERN DOTS-128;So;0;L;;;;;N;;;;;\n2884;BRAILLE PATTERN DOTS-38;So;0;L;;;;;N;;;;;\n2885;BRAILLE PATTERN DOTS-138;So;0;L;;;;;N;;;;;\n2886;BRAILLE PATTERN DOTS-238;So;0;L;;;;;N;;;;;\n2887;BRAILLE PATTERN DOTS-1238;So;0;L;;;;;N;;;;;\n2888;BRAILLE PATTERN DOTS-48;So;0;L;;;;;N;;;;;\n2889;BRAILLE PATTERN DOTS-148;So;0;L;;;;;N;;;;;\n288A;BRAILLE PATTERN DOTS-248;So;0;L;;;;;N;;;;;\n288B;BRAILLE PATTERN DOTS-1248;So;0;L;;;;;N;;;;;\n288C;BRAILLE PATTERN DOTS-348;So;0;L;;;;;N;;;;;\n288D;BRAILLE PATTERN DOTS-1348;So;0;L;;;;;N;;;;;\n288E;BRAILLE PATTERN DOTS-2348;So;0;L;;;;;N;;;;;\n288F;BRAILLE PATTERN DOTS-12348;So;0;L;;;;;N;;;;;\n2890;BRAILLE PATTERN DOTS-58;So;0;L;;;;;N;;;;;\n2891;BRAILLE PATTERN DOTS-158;So;0;L;;;;;N;;;;;\n2892;BRAILLE PATTERN DOTS-258;So;0;L;;;;;N;;;;;\n2893;BRAILLE PATTERN DOTS-1258;So;0;L;;;;;N;;;;;\n2894;BRAILLE PATTERN DOTS-358;So;0;L;;;;;N;;;;;\n2895;BRAILLE PATTERN DOTS-1358;So;0;L;;;;;N;;;;;\n2896;BRAILLE PATTERN DOTS-2358;So;0;L;;;;;N;;;;;\n2897;BRAILLE PATTERN DOTS-12358;So;0;L;;;;;N;;;;;\n2898;BRAILLE PATTERN DOTS-458;So;0;L;;;;;N;;;;;\n2899;BRAILLE PATTERN DOTS-1458;So;0;L;;;;;N;;;;;\n289A;BRAILLE PATTERN DOTS-2458;So;0;L;;;;;N;;;;;\n289B;BRAILLE PATTERN DOTS-12458;So;0;L;;;;;N;;;;;\n289C;BRAILLE PATTERN DOTS-3458;So;0;L;;;;;N;;;;;\n289D;BRAILLE PATTERN DOTS-13458;So;0;L;;;;;N;;;;;\n289E;BRAILLE PATTERN DOTS-23458;So;0;L;;;;;N;;;;;\n289F;BRAILLE PATTERN DOTS-123458;So;0;L;;;;;N;;;;;\n28A0;BRAILLE PATTERN DOTS-68;So;0;L;;;;;N;;;;;\n28A1;BRAILLE PATTERN DOTS-168;So;0;L;;;;;N;;;;;\n28A2;BRAILLE PATTERN DOTS-268;So;0;L;;;;;N;;;;;\n28A3;BRAILLE PATTERN DOTS-1268;So;0;L;;;;;N;;;;;\n28A4;BRAILLE PATTERN DOTS-368;So;0;L;;;;;N;;;;;\n28A5;BRAILLE PATTERN DOTS-1368;So;0;L;;;;;N;;;;;\n28A6;BRAILLE PATTERN DOTS-2368;So;0;L;;;;;N;;;;;\n28A7;BRAILLE PATTERN DOTS-12368;So;0;L;;;;;N;;;;;\n28A8;BRAILLE PATTERN DOTS-468;So;0;L;;;;;N;;;;;\n28A9;BRAILLE PATTERN DOTS-1468;So;0;L;;;;;N;;;;;\n28AA;BRAILLE PATTERN DOTS-2468;So;0;L;;;;;N;;;;;\n28AB;BRAILLE PATTERN DOTS-12468;So;0;L;;;;;N;;;;;\n28AC;BRAILLE PATTERN DOTS-3468;So;0;L;;;;;N;;;;;\n28AD;BRAILLE PATTERN DOTS-13468;So;0;L;;;;;N;;;;;\n28AE;BRAILLE PATTERN DOTS-23468;So;0;L;;;;;N;;;;;\n28AF;BRAILLE PATTERN DOTS-123468;So;0;L;;;;;N;;;;;\n28B0;BRAILLE PATTERN DOTS-568;So;0;L;;;;;N;;;;;\n28B1;BRAILLE PATTERN DOTS-1568;So;0;L;;;;;N;;;;;\n28B2;BRAILLE PATTERN DOTS-2568;So;0;L;;;;;N;;;;;\n28B3;BRAILLE PATTERN DOTS-12568;So;0;L;;;;;N;;;;;\n28B4;BRAILLE PATTERN DOTS-3568;So;0;L;;;;;N;;;;;\n28B5;BRAILLE PATTERN DOTS-13568;So;0;L;;;;;N;;;;;\n28B6;BRAILLE PATTERN DOTS-23568;So;0;L;;;;;N;;;;;\n28B7;BRAILLE PATTERN DOTS-123568;So;0;L;;;;;N;;;;;\n28B8;BRAILLE PATTERN DOTS-4568;So;0;L;;;;;N;;;;;\n28B9;BRAILLE PATTERN DOTS-14568;So;0;L;;;;;N;;;;;\n28BA;BRAILLE PATTERN DOTS-24568;So;0;L;;;;;N;;;;;\n28BB;BRAILLE PATTERN DOTS-124568;So;0;L;;;;;N;;;;;\n28BC;BRAILLE PATTERN DOTS-34568;So;0;L;;;;;N;;;;;\n28BD;BRAILLE PATTERN DOTS-134568;So;0;L;;;;;N;;;;;\n28BE;BRAILLE PATTERN DOTS-234568;So;0;L;;;;;N;;;;;\n28BF;BRAILLE PATTERN DOTS-1234568;So;0;L;;;;;N;;;;;\n28C0;BRAILLE PATTERN DOTS-78;So;0;L;;;;;N;;;;;\n28C1;BRAILLE PATTERN DOTS-178;So;0;L;;;;;N;;;;;\n28C2;BRAILLE PATTERN DOTS-278;So;0;L;;;;;N;;;;;\n28C3;BRAILLE PATTERN DOTS-1278;So;0;L;;;;;N;;;;;\n28C4;BRAILLE PATTERN DOTS-378;So;0;L;;;;;N;;;;;\n28C5;BRAILLE PATTERN DOTS-1378;So;0;L;;;;;N;;;;;\n28C6;BRAILLE PATTERN DOTS-2378;So;0;L;;;;;N;;;;;\n28C7;BRAILLE PATTERN DOTS-12378;So;0;L;;;;;N;;;;;\n28C8;BRAILLE PATTERN DOTS-478;So;0;L;;;;;N;;;;;\n28C9;BRAILLE PATTERN DOTS-1478;So;0;L;;;;;N;;;;;\n28CA;BRAILLE PATTERN DOTS-2478;So;0;L;;;;;N;;;;;\n28CB;BRAILLE PATTERN DOTS-12478;So;0;L;;;;;N;;;;;\n28CC;BRAILLE PATTERN DOTS-3478;So;0;L;;;;;N;;;;;\n28CD;BRAILLE PATTERN DOTS-13478;So;0;L;;;;;N;;;;;\n28CE;BRAILLE PATTERN DOTS-23478;So;0;L;;;;;N;;;;;\n28CF;BRAILLE PATTERN DOTS-123478;So;0;L;;;;;N;;;;;\n28D0;BRAILLE PATTERN DOTS-578;So;0;L;;;;;N;;;;;\n28D1;BRAILLE PATTERN DOTS-1578;So;0;L;;;;;N;;;;;\n28D2;BRAILLE PATTERN DOTS-2578;So;0;L;;;;;N;;;;;\n28D3;BRAILLE PATTERN DOTS-12578;So;0;L;;;;;N;;;;;\n28D4;BRAILLE PATTERN DOTS-3578;So;0;L;;;;;N;;;;;\n28D5;BRAILLE PATTERN DOTS-13578;So;0;L;;;;;N;;;;;\n28D6;BRAILLE PATTERN DOTS-23578;So;0;L;;;;;N;;;;;\n28D7;BRAILLE PATTERN DOTS-123578;So;0;L;;;;;N;;;;;\n28D8;BRAILLE PATTERN DOTS-4578;So;0;L;;;;;N;;;;;\n28D9;BRAILLE PATTERN DOTS-14578;So;0;L;;;;;N;;;;;\n28DA;BRAILLE PATTERN DOTS-24578;So;0;L;;;;;N;;;;;\n28DB;BRAILLE PATTERN DOTS-124578;So;0;L;;;;;N;;;;;\n28DC;BRAILLE PATTERN DOTS-34578;So;0;L;;;;;N;;;;;\n28DD;BRAILLE PATTERN DOTS-134578;So;0;L;;;;;N;;;;;\n28DE;BRAILLE PATTERN DOTS-234578;So;0;L;;;;;N;;;;;\n28DF;BRAILLE PATTERN DOTS-1234578;So;0;L;;;;;N;;;;;\n28E0;BRAILLE PATTERN DOTS-678;So;0;L;;;;;N;;;;;\n28E1;BRAILLE PATTERN DOTS-1678;So;0;L;;;;;N;;;;;\n28E2;BRAILLE PATTERN DOTS-2678;So;0;L;;;;;N;;;;;\n28E3;BRAILLE PATTERN DOTS-12678;So;0;L;;;;;N;;;;;\n28E4;BRAILLE PATTERN DOTS-3678;So;0;L;;;;;N;;;;;\n28E5;BRAILLE PATTERN DOTS-13678;So;0;L;;;;;N;;;;;\n28E6;BRAILLE PATTERN DOTS-23678;So;0;L;;;;;N;;;;;\n28E7;BRAILLE PATTERN DOTS-123678;So;0;L;;;;;N;;;;;\n28E8;BRAILLE PATTERN DOTS-4678;So;0;L;;;;;N;;;;;\n28E9;BRAILLE PATTERN DOTS-14678;So;0;L;;;;;N;;;;;\n28EA;BRAILLE PATTERN DOTS-24678;So;0;L;;;;;N;;;;;\n28EB;BRAILLE PATTERN DOTS-124678;So;0;L;;;;;N;;;;;\n28EC;BRAILLE PATTERN DOTS-34678;So;0;L;;;;;N;;;;;\n28ED;BRAILLE PATTERN DOTS-134678;So;0;L;;;;;N;;;;;\n28EE;BRAILLE PATTERN DOTS-234678;So;0;L;;;;;N;;;;;\n28EF;BRAILLE PATTERN DOTS-1234678;So;0;L;;;;;N;;;;;\n28F0;BRAILLE PATTERN DOTS-5678;So;0;L;;;;;N;;;;;\n28F1;BRAILLE PATTERN DOTS-15678;So;0;L;;;;;N;;;;;\n28F2;BRAILLE PATTERN DOTS-25678;So;0;L;;;;;N;;;;;\n28F3;BRAILLE PATTERN DOTS-125678;So;0;L;;;;;N;;;;;\n28F4;BRAILLE PATTERN DOTS-35678;So;0;L;;;;;N;;;;;\n28F5;BRAILLE PATTERN DOTS-135678;So;0;L;;;;;N;;;;;\n28F6;BRAILLE PATTERN DOTS-235678;So;0;L;;;;;N;;;;;\n28F7;BRAILLE PATTERN DOTS-1235678;So;0;L;;;;;N;;;;;\n28F8;BRAILLE PATTERN DOTS-45678;So;0;L;;;;;N;;;;;\n28F9;BRAILLE PATTERN DOTS-145678;So;0;L;;;;;N;;;;;\n28FA;BRAILLE PATTERN DOTS-245678;So;0;L;;;;;N;;;;;\n28FB;BRAILLE PATTERN DOTS-1245678;So;0;L;;;;;N;;;;;\n28FC;BRAILLE PATTERN DOTS-345678;So;0;L;;;;;N;;;;;\n28FD;BRAILLE PATTERN DOTS-1345678;So;0;L;;;;;N;;;;;\n28FE;BRAILLE PATTERN DOTS-2345678;So;0;L;;;;;N;;;;;\n28FF;BRAILLE PATTERN DOTS-12345678;So;0;L;;;;;N;;;;;\n2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2903;RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2904;LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2905;RIGHTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;\n2906;LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;\n2907;RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;\n2908;DOWNWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;\n2909;UPWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;\n290A;UPWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;;\n290B;DOWNWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;;\n290C;LEFTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;;\n290D;RIGHTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;;\n290E;LEFTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;\n290F;RIGHTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;\n2910;RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;\n2911;RIGHTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;;\n2912;UPWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;;\n2913;DOWNWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;;\n2914;RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2915;RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2916;RIGHTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;;\n2917;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2918;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2919;LEFTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;;\n291A;RIGHTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;;\n291B;LEFTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;;\n291C;RIGHTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;;\n291D;LEFTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;\n291E;RIGHTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;\n291F;LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;\n2920;RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;\n2921;NORTH WEST AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;\n2922;NORTH EAST AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;;\n2923;NORTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;\n2924;NORTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;\n2925;SOUTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;\n2926;SOUTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;\n2927;NORTH WEST ARROW AND NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;\n2928;NORTH EAST ARROW AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;\n2929;SOUTH EAST ARROW AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;;\n292A;SOUTH WEST ARROW AND NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;;\n292B;RISING DIAGONAL CROSSING FALLING DIAGONAL;Sm;0;ON;;;;;N;;;;;\n292C;FALLING DIAGONAL CROSSING RISING DIAGONAL;Sm;0;ON;;;;;N;;;;;\n292D;SOUTH EAST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;\n292E;NORTH EAST ARROW CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;\n292F;FALLING DIAGONAL CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;\n2930;RISING DIAGONAL CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;\n2931;NORTH EAST ARROW CROSSING NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;;\n2932;NORTH WEST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;\n2933;WAVE ARROW POINTING DIRECTLY RIGHT;Sm;0;ON;;;;;N;;;;;\n2934;ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS;Sm;0;ON;;;;;N;;;;;\n2935;ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS;Sm;0;ON;;;;;N;;;;;\n2936;ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS;Sm;0;ON;;;;;N;;;;;\n2937;ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS;Sm;0;ON;;;;;N;;;;;\n2938;RIGHT-SIDE ARC CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;\n2939;LEFT-SIDE ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;\n293A;TOP ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;\n293B;BOTTOM ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;\n293C;TOP ARC CLOCKWISE ARROW WITH MINUS;Sm;0;ON;;;;;N;;;;;\n293D;TOP ARC ANTICLOCKWISE ARROW WITH PLUS;Sm;0;ON;;;;;N;;;;;\n293E;LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;\n293F;LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;\n2940;ANTICLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;\n2941;CLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;\n2942;RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2943;LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2944;SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2945;RIGHTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;;\n2946;LEFTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;;\n2947;RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;;\n2948;LEFT RIGHT ARROW THROUGH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;\n2949;UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;\n294A;LEFT BARB UP RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;;\n294B;LEFT BARB DOWN RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;;\n294C;UP BARB RIGHT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;;\n294D;UP BARB LEFT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;;\n294E;LEFT BARB UP RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;;\n294F;UP BARB RIGHT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;;\n2950;LEFT BARB DOWN RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;;\n2951;UP BARB LEFT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;;\n2952;LEFTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;;\n2953;RIGHTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;;\n2954;UPWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;;\n2955;DOWNWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;;\n2956;LEFTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;;\n2957;RIGHTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;;\n2958;UPWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;;\n2959;DOWNWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;;\n295A;LEFTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;;\n295B;RIGHTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;;\n295C;UPWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;;\n295D;DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;;\n295E;LEFTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;;\n295F;RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;;\n2960;UPWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;;\n2961;DOWNWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;;\n2962;LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;\n2963;UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;\n2964;RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;\n2965;DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;\n2966;LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;;\n2967;LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;\n2968;RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;;\n2969;RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;\n296A;LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;;\n296B;LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;;\n296C;RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;;\n296D;RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;;\n296E;UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;\n296F;DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;\n2970;RIGHT DOUBLE ARROW WITH ROUNDED HEAD;Sm;0;ON;;;;;N;;;;;\n2971;EQUALS SIGN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2972;TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2973;LEFTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;\n2974;RIGHTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;\n2975;RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;\n2976;LESS-THAN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2977;LEFTWARDS ARROW THROUGH LESS-THAN;Sm;0;ON;;;;;N;;;;;\n2978;GREATER-THAN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2979;SUBSET ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n297A;LEFTWARDS ARROW THROUGH SUBSET;Sm;0;ON;;;;;N;;;;;\n297B;SUPERSET ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n297C;LEFT FISH TAIL;Sm;0;ON;;;;;N;;;;;\n297D;RIGHT FISH TAIL;Sm;0;ON;;;;;N;;;;;\n297E;UP FISH TAIL;Sm;0;ON;;;;;N;;;;;\n297F;DOWN FISH TAIL;Sm;0;ON;;;;;N;;;;;\n2980;TRIPLE VERTICAL BAR DELIMITER;Sm;0;ON;;;;;N;;;;;\n2981;Z NOTATION SPOT;Sm;0;ON;;;;;N;;;;;\n2982;Z NOTATION TYPE COLON;Sm;0;ON;;;;;N;;;;;\n2983;LEFT WHITE CURLY BRACKET;Ps;0;ON;;;;;Y;;;;;\n2984;RIGHT WHITE CURLY BRACKET;Pe;0;ON;;;;;Y;;;;;\n2985;LEFT WHITE PARENTHESIS;Ps;0;ON;;;;;Y;;;;;\n2986;RIGHT WHITE PARENTHESIS;Pe;0;ON;;;;;Y;;;;;\n2987;Z NOTATION LEFT IMAGE BRACKET;Ps;0;ON;;;;;Y;;;;;\n2988;Z NOTATION RIGHT IMAGE BRACKET;Pe;0;ON;;;;;Y;;;;;\n2989;Z NOTATION LEFT BINDING BRACKET;Ps;0;ON;;;;;Y;;;;;\n298A;Z NOTATION RIGHT BINDING BRACKET;Pe;0;ON;;;;;Y;;;;;\n298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps;0;ON;;;;;Y;;;;;\n298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe;0;ON;;;;;Y;;;;;\n298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps;0;ON;;;;;Y;;;;;\n298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe;0;ON;;;;;Y;;;;;\n298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps;0;ON;;;;;Y;;;;;\n2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe;0;ON;;;;;Y;;;;;\n2991;LEFT ANGLE BRACKET WITH DOT;Ps;0;ON;;;;;Y;;;;;\n2992;RIGHT ANGLE BRACKET WITH DOT;Pe;0;ON;;;;;Y;;;;;\n2993;LEFT ARC LESS-THAN BRACKET;Ps;0;ON;;;;;Y;;;;;\n2994;RIGHT ARC GREATER-THAN BRACKET;Pe;0;ON;;;;;Y;;;;;\n2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps;0;ON;;;;;Y;;;;;\n2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe;0;ON;;;;;Y;;;;;\n2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;;\n2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;;\n2999;DOTTED FENCE;Sm;0;ON;;;;;N;;;;;\n299A;VERTICAL ZIGZAG LINE;Sm;0;ON;;;;;N;;;;;\n299B;MEASURED ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;\n299C;RIGHT ANGLE VARIANT WITH SQUARE;Sm;0;ON;;;;;Y;;;;;\n299D;MEASURED RIGHT ANGLE WITH DOT;Sm;0;ON;;;;;Y;;;;;\n299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;;\n299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;;\n29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;\n29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;N;;;;;\n29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;;\n29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;;\n29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;\n29A5;REVERSED ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;\n29A6;OBLIQUE ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;\n29A7;OBLIQUE ANGLE OPENING DOWN;Sm;0;ON;;;;;Y;;;;;\n29A8;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT;Sm;0;ON;;;;;Y;;;;;\n29A9;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT;Sm;0;ON;;;;;Y;;;;;\n29AA;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT;Sm;0;ON;;;;;Y;;;;;\n29AB;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT;Sm;0;ON;;;;;Y;;;;;\n29AC;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP;Sm;0;ON;;;;;Y;;;;;\n29AD;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP;Sm;0;ON;;;;;Y;;;;;\n29AE;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN;Sm;0;ON;;;;;Y;;;;;\n29AF;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN;Sm;0;ON;;;;;Y;;;;;\n29B0;REVERSED EMPTY SET;Sm;0;ON;;;;;N;;;;;\n29B1;EMPTY SET WITH OVERBAR;Sm;0;ON;;;;;N;;;;;\n29B2;EMPTY SET WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;\n29B3;EMPTY SET WITH RIGHT ARROW ABOVE;Sm;0;ON;;;;;N;;;;;\n29B4;EMPTY SET WITH LEFT ARROW ABOVE;Sm;0;ON;;;;;N;;;;;\n29B5;CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;;\n29B6;CIRCLED VERTICAL BAR;Sm;0;ON;;;;;N;;;;;\n29B7;CIRCLED PARALLEL;Sm;0;ON;;;;;N;;;;;\n29B8;CIRCLED REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;;\n29B9;CIRCLED PERPENDICULAR;Sm;0;ON;;;;;N;;;;;\n29BA;CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR;Sm;0;ON;;;;;N;;;;;\n29BB;CIRCLE WITH SUPERIMPOSED X;Sm;0;ON;;;;;N;;;;;\n29BC;CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN;Sm;0;ON;;;;;N;;;;;\n29BD;UP ARROW THROUGH CIRCLE;Sm;0;ON;;;;;N;;;;;\n29BE;CIRCLED WHITE BULLET;Sm;0;ON;;;;;N;;;;;\n29BF;CIRCLED BULLET;Sm;0;ON;;;;;N;;;;;\n29C0;CIRCLED LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n29C1;CIRCLED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n29C2;CIRCLE WITH SMALL CIRCLE TO THE RIGHT;Sm;0;ON;;;;;Y;;;;;\n29C3;CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT;Sm;0;ON;;;;;Y;;;;;\n29C4;SQUARED RISING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;;\n29C5;SQUARED FALLING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;;\n29C6;SQUARED ASTERISK;Sm;0;ON;;;;;N;;;;;\n29C7;SQUARED SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;\n29C8;SQUARED SQUARE;Sm;0;ON;;;;;N;;;;;\n29C9;TWO JOINED SQUARES;Sm;0;ON;;;;;Y;;;;;\n29CA;TRIANGLE WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;\n29CB;TRIANGLE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;\n29CC;S IN TRIANGLE;Sm;0;ON;;;;;N;;;;;\n29CD;TRIANGLE WITH SERIFS AT BOTTOM;Sm;0;ON;;;;;N;;;;;\n29CE;RIGHT TRIANGLE ABOVE LEFT TRIANGLE;Sm;0;ON;;;;;Y;;;;;\n29CF;LEFT TRIANGLE BESIDE VERTICAL BAR;Sm;0;ON;;;;;Y;;;;;\n29D0;VERTICAL BAR BESIDE RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;\n29D1;BOWTIE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;\n29D2;BOWTIE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;\n29D3;BLACK BOWTIE;Sm;0;ON;;;;;N;;;;;\n29D4;TIMES WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;\n29D5;TIMES WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;\n29D6;WHITE HOURGLASS;Sm;0;ON;;;;;N;;;;;\n29D7;BLACK HOURGLASS;Sm;0;ON;;;;;N;;;;;\n29D8;LEFT WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;;\n29D9;RIGHT WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;;\n29DA;LEFT DOUBLE WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;;\n29DB;RIGHT DOUBLE WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;;\n29DC;INCOMPLETE INFINITY;Sm;0;ON;;;;;Y;;;;;\n29DD;TIE OVER INFINITY;Sm;0;ON;;;;;N;;;;;\n29DE;INFINITY NEGATED WITH VERTICAL BAR;Sm;0;ON;;;;;N;;;;;\n29DF;DOUBLE-ENDED MULTIMAP;Sm;0;ON;;;;;N;;;;;\n29E0;SQUARE WITH CONTOURED OUTLINE;Sm;0;ON;;;;;N;;;;;\n29E1;INCREASES AS;Sm;0;ON;;;;;Y;;;;;\n29E2;SHUFFLE PRODUCT;Sm;0;ON;;;;;N;;;;;\n29E3;EQUALS SIGN AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;;\n29E4;EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;;\n29E5;IDENTICAL TO AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;;\n29E6;GLEICH STARK;Sm;0;ON;;;;;N;;;;;\n29E7;THERMODYNAMIC;Sm;0;ON;;;;;N;;;;;\n29E8;DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;\n29E9;DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;\n29EA;BLACK DIAMOND WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;\n29EB;BLACK LOZENGE;Sm;0;ON;;;;;N;;;;;\n29EC;WHITE CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;\n29ED;BLACK CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;\n29EE;ERROR-BARRED WHITE SQUARE;Sm;0;ON;;;;;N;;;;;\n29EF;ERROR-BARRED BLACK SQUARE;Sm;0;ON;;;;;N;;;;;\n29F0;ERROR-BARRED WHITE DIAMOND;Sm;0;ON;;;;;N;;;;;\n29F1;ERROR-BARRED BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;\n29F2;ERROR-BARRED WHITE CIRCLE;Sm;0;ON;;;;;N;;;;;\n29F3;ERROR-BARRED BLACK CIRCLE;Sm;0;ON;;;;;N;;;;;\n29F4;RULE-DELAYED;Sm;0;ON;;;;;Y;;;;;\n29F5;REVERSE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;;\n29F6;SOLIDUS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;\n29F7;REVERSE SOLIDUS WITH HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;\n29F8;BIG SOLIDUS;Sm;0;ON;;;;;Y;;;;;\n29F9;BIG REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;;\n29FA;DOUBLE PLUS;Sm;0;ON;;;;;N;;;;;\n29FB;TRIPLE PLUS;Sm;0;ON;;;;;N;;;;;\n29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;\n29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;\n29FE;TINY;Sm;0;ON;;;;;N;;;;;\n29FF;MINY;Sm;0;ON;;;;;N;;;;;\n2A00;N-ARY CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;\n2A01;N-ARY CIRCLED PLUS OPERATOR;Sm;0;ON;;;;;N;;;;;\n2A02;N-ARY CIRCLED TIMES OPERATOR;Sm;0;ON;;;;;N;;;;;\n2A03;N-ARY UNION OPERATOR WITH DOT;Sm;0;ON;;;;;N;;;;;\n2A04;N-ARY UNION OPERATOR WITH PLUS;Sm;0;ON;;;;;N;;;;;\n2A05;N-ARY SQUARE INTERSECTION OPERATOR;Sm;0;ON;;;;;N;;;;;\n2A06;N-ARY SQUARE UNION OPERATOR;Sm;0;ON;;;;;N;;;;;\n2A07;TWO LOGICAL AND OPERATOR;Sm;0;ON;;;;;N;;;;;\n2A08;TWO LOGICAL OR OPERATOR;Sm;0;ON;;;;;N;;;;;\n2A09;N-ARY TIMES OPERATOR;Sm;0;ON;;;;;N;;;;;\n2A0A;MODULO TWO SUM;Sm;0;ON;;;;;Y;;;;;\n2A0B;SUMMATION WITH INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n2A0C;QUADRUPLE INTEGRAL OPERATOR;Sm;0;ON;<compat> 222B 222B 222B 222B;;;;Y;;;;;\n2A0D;FINITE PART INTEGRAL;Sm;0;ON;;;;;Y;;;;;\n2A0E;INTEGRAL WITH DOUBLE STROKE;Sm;0;ON;;;;;Y;;;;;\n2A0F;INTEGRAL AVERAGE WITH SLASH;Sm;0;ON;;;;;Y;;;;;\n2A10;CIRCULATION FUNCTION;Sm;0;ON;;;;;Y;;;;;\n2A11;ANTICLOCKWISE INTEGRATION;Sm;0;ON;;;;;Y;;;;;\n2A12;LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;;\n2A13;LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;;\n2A14;LINE INTEGRATION NOT INCLUDING THE POLE;Sm;0;ON;;;;;Y;;;;;\n2A15;INTEGRAL AROUND A POINT OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2A16;QUATERNION INTEGRAL OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2A17;INTEGRAL WITH LEFTWARDS ARROW WITH HOOK;Sm;0;ON;;;;;Y;;;;;\n2A18;INTEGRAL WITH TIMES SIGN;Sm;0;ON;;;;;Y;;;;;\n2A19;INTEGRAL WITH INTERSECTION;Sm;0;ON;;;;;Y;;;;;\n2A1A;INTEGRAL WITH UNION;Sm;0;ON;;;;;Y;;;;;\n2A1B;INTEGRAL WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;\n2A1C;INTEGRAL WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;\n2A1D;JOIN;Sm;0;ON;;;;;N;;;;;\n2A1E;LARGE LEFT TRIANGLE OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2A1F;Z NOTATION SCHEMA COMPOSITION;Sm;0;ON;;;;;Y;;;;;\n2A20;Z NOTATION SCHEMA PIPING;Sm;0;ON;;;;;Y;;;;;\n2A21;Z NOTATION SCHEMA PROJECTION;Sm;0;ON;;;;;Y;;;;;\n2A22;PLUS SIGN WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;\n2A23;PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE;Sm;0;ON;;;;;N;;;;;\n2A24;PLUS SIGN WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;;\n2A25;PLUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;\n2A26;PLUS SIGN WITH TILDE BELOW;Sm;0;ON;;;;;Y;;;;;\n2A27;PLUS SIGN WITH SUBSCRIPT TWO;Sm;0;ON;;;;;N;;;;;\n2A28;PLUS SIGN WITH BLACK TRIANGLE;Sm;0;ON;;;;;N;;;;;\n2A29;MINUS SIGN WITH COMMA ABOVE;Sm;0;ON;;;;;Y;;;;;\n2A2A;MINUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;\n2A2B;MINUS SIGN WITH FALLING DOTS;Sm;0;ON;;;;;Y;;;;;\n2A2C;MINUS SIGN WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;;\n2A2D;PLUS SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;\n2A2E;PLUS SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;\n2A2F;VECTOR OR CROSS PRODUCT;Sm;0;ON;;;;;N;;;;;\n2A30;MULTIPLICATION SIGN WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;\n2A31;MULTIPLICATION SIGN WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;\n2A32;SEMIDIRECT PRODUCT WITH BOTTOM CLOSED;Sm;0;ON;;;;;N;;;;;\n2A33;SMASH PRODUCT;Sm;0;ON;;;;;N;;;;;\n2A34;MULTIPLICATION SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;\n2A35;MULTIPLICATION SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;\n2A36;CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;N;;;;;\n2A37;MULTIPLICATION SIGN IN DOUBLE CIRCLE;Sm;0;ON;;;;;N;;;;;\n2A38;CIRCLED DIVISION SIGN;Sm;0;ON;;;;;N;;;;;\n2A39;PLUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;\n2A3A;MINUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;\n2A3B;MULTIPLICATION SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;\n2A3C;INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;;\n2A3D;RIGHTHAND INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;;\n2A3E;Z NOTATION RELATIONAL COMPOSITION;Sm;0;ON;;;;;Y;;;;;\n2A3F;AMALGAMATION OR COPRODUCT;Sm;0;ON;;;;;N;;;;;\n2A40;INTERSECTION WITH DOT;Sm;0;ON;;;;;N;;;;;\n2A41;UNION WITH MINUS SIGN;Sm;0;ON;;;;;N;;;;;\n2A42;UNION WITH OVERBAR;Sm;0;ON;;;;;N;;;;;\n2A43;INTERSECTION WITH OVERBAR;Sm;0;ON;;;;;N;;;;;\n2A44;INTERSECTION WITH LOGICAL AND;Sm;0;ON;;;;;N;;;;;\n2A45;UNION WITH LOGICAL OR;Sm;0;ON;;;;;N;;;;;\n2A46;UNION ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;;\n2A47;INTERSECTION ABOVE UNION;Sm;0;ON;;;;;N;;;;;\n2A48;UNION ABOVE BAR ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;;\n2A49;INTERSECTION ABOVE BAR ABOVE UNION;Sm;0;ON;;;;;N;;;;;\n2A4A;UNION BESIDE AND JOINED WITH UNION;Sm;0;ON;;;;;N;;;;;\n2A4B;INTERSECTION BESIDE AND JOINED WITH INTERSECTION;Sm;0;ON;;;;;N;;;;;\n2A4C;CLOSED UNION WITH SERIFS;Sm;0;ON;;;;;N;;;;;\n2A4D;CLOSED INTERSECTION WITH SERIFS;Sm;0;ON;;;;;N;;;;;\n2A4E;DOUBLE SQUARE INTERSECTION;Sm;0;ON;;;;;N;;;;;\n2A4F;DOUBLE SQUARE UNION;Sm;0;ON;;;;;N;;;;;\n2A50;CLOSED UNION WITH SERIFS AND SMASH PRODUCT;Sm;0;ON;;;;;N;;;;;\n2A51;LOGICAL AND WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;\n2A52;LOGICAL OR WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;\n2A53;DOUBLE LOGICAL AND;Sm;0;ON;;;;;N;;;;;\n2A54;DOUBLE LOGICAL OR;Sm;0;ON;;;;;N;;;;;\n2A55;TWO INTERSECTING LOGICAL AND;Sm;0;ON;;;;;N;;;;;\n2A56;TWO INTERSECTING LOGICAL OR;Sm;0;ON;;;;;N;;;;;\n2A57;SLOPING LARGE OR;Sm;0;ON;;;;;Y;;;;;\n2A58;SLOPING LARGE AND;Sm;0;ON;;;;;Y;;;;;\n2A59;LOGICAL OR OVERLAPPING LOGICAL AND;Sm;0;ON;;;;;N;;;;;\n2A5A;LOGICAL AND WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;;\n2A5B;LOGICAL OR WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;;\n2A5C;LOGICAL AND WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;;\n2A5D;LOGICAL OR WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;;\n2A5E;LOGICAL AND WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;;\n2A5F;LOGICAL AND WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;\n2A60;LOGICAL AND WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;;\n2A61;SMALL VEE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;\n2A62;LOGICAL OR WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;;\n2A63;LOGICAL OR WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;;\n2A64;Z NOTATION DOMAIN ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;;\n2A65;Z NOTATION RANGE ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;;\n2A66;EQUALS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;\n2A67;IDENTICAL WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;\n2A68;TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2A69;TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2A6A;TILDE OPERATOR WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;\n2A6B;TILDE OPERATOR WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;;\n2A6C;SIMILAR MINUS SIMILAR;Sm;0;ON;;;;;Y;;;;;\n2A6D;CONGRUENT WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;\n2A6E;EQUALS WITH ASTERISK;Sm;0;ON;;;;;N;;;;;\n2A6F;ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;Y;;;;;\n2A70;APPROXIMATELY EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2A71;EQUALS SIGN ABOVE PLUS SIGN;Sm;0;ON;;;;;N;;;;;\n2A72;PLUS SIGN ABOVE EQUALS SIGN;Sm;0;ON;;;;;N;;;;;\n2A73;EQUALS SIGN ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2A74;DOUBLE COLON EQUAL;Sm;0;ON;<compat> 003A 003A 003D;;;;Y;;;;;\n2A75;TWO CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D;;;;N;;;;;\n2A76;THREE CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D 003D;;;;N;;;;;\n2A77;EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW;Sm;0;ON;;;;;N;;;;;\n2A78;EQUIVALENT WITH FOUR DOTS ABOVE;Sm;0;ON;;;;;N;;;;;\n2A79;LESS-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;;\n2A7A;GREATER-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;;\n2A7B;LESS-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;;\n2A7C;GREATER-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;;\n2A7D;LESS-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2A7E;GREATER-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2A7F;LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;\n2A80;GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;\n2A81;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;\n2A82;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;\n2A83;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT;Sm;0;ON;;;;;Y;;;;;\n2A84;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT;Sm;0;ON;;;;;Y;;;;;\n2A85;LESS-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;;\n2A86;GREATER-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;;\n2A87;LESS-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2A88;GREATER-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2A89;LESS-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;;\n2A8A;GREATER-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;;\n2A8B;LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n2A8C;GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n2A8D;LESS-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;;\n2A8E;GREATER-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;;\n2A8F;LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n2A90;GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n2A91;LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;;\n2A92;GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;;\n2A93;LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;\n2A94;GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;\n2A95;SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n2A96;SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n2A97;SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;\n2A98;SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;\n2A99;DOUBLE-LINE EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n2A9A;DOUBLE-LINE EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n2A9B;DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n2A9C;DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n2A9D;SIMILAR OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n2A9E;SIMILAR OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n2A9F;SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;\n2AA0;SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;\n2AA1;DOUBLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n2AA2;DOUBLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n2AA3;DOUBLE NESTED LESS-THAN WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;\n2AA4;GREATER-THAN OVERLAPPING LESS-THAN;Sm;0;ON;;;;;N;;;;;\n2AA5;GREATER-THAN BESIDE LESS-THAN;Sm;0;ON;;;;;N;;;;;\n2AA6;LESS-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;;\n2AA7;GREATER-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;;\n2AA8;LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;\n2AA9;GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;\n2AAA;SMALLER THAN;Sm;0;ON;;;;;Y;;;;;\n2AAB;LARGER THAN;Sm;0;ON;;;;;Y;;;;;\n2AAC;SMALLER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AAD;LARGER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AAE;EQUALS SIGN WITH BUMPY ABOVE;Sm;0;ON;;;;;N;;;;;\n2AAF;PRECEDES ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;\n2AB0;SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;\n2AB1;PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AB2;SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AB3;PRECEDES ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;\n2AB4;SUCCEEDS ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;\n2AB5;PRECEDES ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AB6;SUCCEEDS ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AB7;PRECEDES ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AB8;SUCCEEDS ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AB9;PRECEDES ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2ABA;SUCCEEDS ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2ABB;DOUBLE PRECEDES;Sm;0;ON;;;;;Y;;;;;\n2ABC;DOUBLE SUCCEEDS;Sm;0;ON;;;;;Y;;;;;\n2ABD;SUBSET WITH DOT;Sm;0;ON;;;;;Y;;;;;\n2ABE;SUPERSET WITH DOT;Sm;0;ON;;;;;Y;;;;;\n2ABF;SUBSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;;\n2AC0;SUPERSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;;\n2AC1;SUBSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;;\n2AC2;SUPERSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;;\n2AC3;SUBSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;\n2AC4;SUPERSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;\n2AC5;SUBSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;\n2AC6;SUPERSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;\n2AC7;SUBSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2AC8;SUPERSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2AC9;SUBSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2ACA;SUPERSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2ACB;SUBSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2ACC;SUPERSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2ACD;SQUARE LEFT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2ACE;SQUARE RIGHT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2ACF;CLOSED SUBSET;Sm;0;ON;;;;;Y;;;;;\n2AD0;CLOSED SUPERSET;Sm;0;ON;;;;;Y;;;;;\n2AD1;CLOSED SUBSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AD2;CLOSED SUPERSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AD3;SUBSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;;\n2AD4;SUPERSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;;\n2AD5;SUBSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;;\n2AD6;SUPERSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;;\n2AD7;SUPERSET BESIDE SUBSET;Sm;0;ON;;;;;N;;;;;\n2AD8;SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET;Sm;0;ON;;;;;N;;;;;\n2AD9;ELEMENT OF OPENING DOWNWARDS;Sm;0;ON;;;;;N;;;;;\n2ADA;PITCHFORK WITH TEE TOP;Sm;0;ON;;;;;N;;;;;\n2ADB;TRANSVERSAL INTERSECTION;Sm;0;ON;;;;;N;;;;;\n2ADC;FORKING;Sm;0;ON;2ADD 0338;;;;Y;;;;;\n2ADD;NONFORKING;Sm;0;ON;;;;;N;;;;;\n2ADE;SHORT LEFT TACK;Sm;0;ON;;;;;Y;;;;;\n2ADF;SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;;\n2AE0;SHORT UP TACK;Sm;0;ON;;;;;N;;;;;\n2AE1;PERPENDICULAR WITH S;Sm;0;ON;;;;;N;;;;;\n2AE2;VERTICAL BAR TRIPLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;\n2AE3;DOUBLE VERTICAL BAR LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;\n2AE4;VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;\n2AE5;DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;\n2AE6;LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL;Sm;0;ON;;;;;Y;;;;;\n2AE7;SHORT DOWN TACK WITH OVERBAR;Sm;0;ON;;;;;N;;;;;\n2AE8;SHORT UP TACK WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;\n2AE9;SHORT UP TACK ABOVE SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;;\n2AEA;DOUBLE DOWN TACK;Sm;0;ON;;;;;N;;;;;\n2AEB;DOUBLE UP TACK;Sm;0;ON;;;;;N;;;;;\n2AEC;DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;;\n2AED;REVERSED DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;;\n2AEE;DOES NOT DIVIDE WITH REVERSED NEGATION SLASH;Sm;0;ON;;;;;Y;;;;;\n2AEF;VERTICAL LINE WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;\n2AF0;VERTICAL LINE WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;;\n2AF1;DOWN TACK WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;;\n2AF2;PARALLEL WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;\n2AF3;PARALLEL WITH TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2AF4;TRIPLE VERTICAL BAR BINARY RELATION;Sm;0;ON;;;;;N;;;;;\n2AF5;TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;\n2AF6;TRIPLE COLON OPERATOR;Sm;0;ON;;;;;N;;;;;\n2AF7;TRIPLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;;\n2AF8;TRIPLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;\n2AF9;DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AFA;DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;\n2AFB;TRIPLE SOLIDUS BINARY RELATION;Sm;0;ON;;;;;Y;;;;;\n2AFC;LARGE TRIPLE VERTICAL BAR OPERATOR;Sm;0;ON;;;;;N;;;;;\n2AFD;DOUBLE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;;\n2AFE;WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;;\n2AFF;N-ARY WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;;\n2B00;NORTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B01;NORTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B02;SOUTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B03;SOUTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B04;LEFT RIGHT WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B05;LEFTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B06;UPWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B07;DOWNWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B08;NORTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B09;NORTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B0A;SOUTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B0B;SOUTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B0C;LEFT RIGHT BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B0D;UP DOWN BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B0E;RIGHTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;;\n2B0F;RIGHTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;;\n2B10;LEFTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;;\n2B11;LEFTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;;\n2B12;SQUARE WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;;\n2B13;SQUARE WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;;\n2B14;SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;\n2B15;SQUARE WITH LOWER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;\n2B16;DIAMOND WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;\n2B17;DIAMOND WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;\n2B18;DIAMOND WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;;\n2B19;DIAMOND WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;;\n2B1A;DOTTED SQUARE;So;0;ON;;;;;N;;;;;\n2B1B;BLACK LARGE SQUARE;So;0;ON;;;;;N;;;;;\n2B1C;WHITE LARGE SQUARE;So;0;ON;;;;;N;;;;;\n2B1D;BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;;\n2B1E;WHITE VERY SMALL SQUARE;So;0;ON;;;;;N;;;;;\n2B1F;BLACK PENTAGON;So;0;ON;;;;;N;;;;;\n2B20;WHITE PENTAGON;So;0;ON;;;;;N;;;;;\n2B21;WHITE HEXAGON;So;0;ON;;;;;N;;;;;\n2B22;BLACK HEXAGON;So;0;ON;;;;;N;;;;;\n2B23;HORIZONTAL BLACK HEXAGON;So;0;ON;;;;;N;;;;;\n2B24;BLACK LARGE CIRCLE;So;0;ON;;;;;N;;;;;\n2B25;BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;;\n2B26;WHITE MEDIUM DIAMOND;So;0;ON;;;;;N;;;;;\n2B27;BLACK MEDIUM LOZENGE;So;0;ON;;;;;N;;;;;\n2B28;WHITE MEDIUM LOZENGE;So;0;ON;;;;;N;;;;;\n2B29;BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;;\n2B2A;BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;;\n2B2B;WHITE SMALL LOZENGE;So;0;ON;;;;;N;;;;;\n2B2C;BLACK HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;;\n2B2D;WHITE HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;;\n2B2E;BLACK VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;;\n2B2F;WHITE VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;;\n2B30;LEFT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;\n2B31;THREE LEFTWARDS ARROWS;Sm;0;ON;;;;;N;;;;;\n2B32;LEFT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;\n2B33;LONG LEFTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;;\n2B34;LEFTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2B35;LEFTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2B36;LEFTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;\n2B37;LEFTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;\n2B38;LEFTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;;\n2B39;LEFTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2B3A;LEFTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2B3B;LEFTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;;\n2B3C;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2B3D;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;\n2B3E;LEFTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;;\n2B3F;WAVE ARROW POINTING DIRECTLY LEFT;Sm;0;ON;;;;;N;;;;;\n2B40;EQUALS SIGN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2B41;REVERSE TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2B42;LEFTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;\n2B43;RIGHTWARDS ARROW THROUGH GREATER-THAN;Sm;0;ON;;;;;N;;;;;\n2B44;RIGHTWARDS ARROW THROUGH SUPERSET;Sm;0;ON;;;;;N;;;;;\n2B45;LEFTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;;\n2B46;RIGHTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;;\n2B47;REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2B48;RIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;\n2B49;TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n2B4A;LEFTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;\n2B4B;LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;\n2B4C;RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;\n2B4D;DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW;So;0;ON;;;;;N;;;;;\n2B4E;SHORT SLANTED NORTH ARROW;So;0;ON;;;;;N;;;;;\n2B4F;SHORT BACKSLANTED SOUTH ARROW;So;0;ON;;;;;N;;;;;\n2B50;WHITE MEDIUM STAR;So;0;ON;;;;;N;;;;;\n2B51;BLACK SMALL STAR;So;0;ON;;;;;N;;;;;\n2B52;WHITE SMALL STAR;So;0;ON;;;;;N;;;;;\n2B53;BLACK RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;;\n2B54;WHITE RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;;\n2B55;HEAVY LARGE CIRCLE;So;0;ON;;;;;N;;;;;\n2B56;HEAVY OVAL WITH OVAL INSIDE;So;0;ON;;;;;N;;;;;\n2B57;HEAVY CIRCLE WITH CIRCLE INSIDE;So;0;ON;;;;;N;;;;;\n2B58;HEAVY CIRCLE;So;0;ON;;;;;N;;;;;\n2B59;HEAVY CIRCLED SALTIRE;So;0;ON;;;;;N;;;;;\n2B5A;SLANTED NORTH ARROW WITH HOOKED HEAD;So;0;ON;;;;;N;;;;;\n2B5B;BACKSLANTED SOUTH ARROW WITH HOOKED TAIL;So;0;ON;;;;;N;;;;;\n2B5C;SLANTED NORTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;;\n2B5D;BACKSLANTED SOUTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;;\n2B5E;BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;;\n2B5F;SHORT BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;;\n2B60;LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B61;UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B62;RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B63;DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B64;LEFT RIGHT TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B65;UP DOWN TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B66;NORTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B67;NORTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B68;SOUTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B69;SOUTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B6A;LEFTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;;\n2B6B;UPWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;;\n2B6C;RIGHTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;;\n2B6D;DOWNWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;;\n2B6E;CLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;\n2B6F;ANTICLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;\n2B70;LEFTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;\n2B71;UPWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;\n2B72;RIGHTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;\n2B73;DOWNWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;\n2B76;NORTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;\n2B77;NORTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;\n2B78;SOUTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;\n2B79;SOUTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;\n2B7A;LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;;\n2B7B;UPWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;;\n2B7C;RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;;\n2B7D;DOWNWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;;\n2B7E;HORIZONTAL TAB KEY;So;0;ON;;;;;N;;;;;\n2B7F;VERTICAL TAB KEY;So;0;ON;;;;;N;;;;;\n2B80;LEFTWARDS TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B81;UPWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B82;RIGHTWARDS TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B83;DOWNWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;\n2B84;LEFTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;;\n2B85;UPWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;;\n2B86;RIGHTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;;\n2B87;DOWNWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;;\n2B88;LEFTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B89;UPWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B8A;RIGHTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B8B;DOWNWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;;\n2B8C;ANTICLOCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROW;So;0;ON;;;;;N;;;;;\n2B8D;ANTICLOCKWISE TRIANGLE-HEADED BOTTOM U-SHAPED ARROW;So;0;ON;;;;;N;;;;;\n2B8E;ANTICLOCKWISE TRIANGLE-HEADED LEFT U-SHAPED ARROW;So;0;ON;;;;;N;;;;;\n2B8F;ANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED ARROW;So;0;ON;;;;;N;;;;;\n2B90;RETURN LEFT;So;0;ON;;;;;N;;;;;\n2B91;RETURN RIGHT;So;0;ON;;;;;N;;;;;\n2B92;NEWLINE LEFT;So;0;ON;;;;;N;;;;;\n2B93;NEWLINE RIGHT;So;0;ON;;;;;N;;;;;\n2B94;FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE;So;0;ON;;;;;N;;;;;\n2B95;RIGHTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;\n2B96;EQUALS SIGN WITH INFINITY ABOVE;So;0;ON;;;;;N;;;;;\n2B97;SYMBOL FOR TYPE A ELECTRONICS;So;0;ON;;;;;N;;;;;\n2B98;THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n2B99;THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n2B9A;THREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n2B9B;THREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n2B9C;BLACK LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n2B9D;BLACK UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n2B9E;BLACK RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n2B9F;BLACK DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n2BA0;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;;\n2BA1;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;;\n2BA2;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;;\n2BA3;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;;\n2BA4;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;;\n2BA5;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;;\n2BA6;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;;\n2BA7;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;;\n2BA8;BLACK CURVED DOWNWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;;\n2BA9;BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;;\n2BAA;BLACK CURVED UPWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;;\n2BAB;BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;;\n2BAC;BLACK CURVED LEFTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;;\n2BAD;BLACK CURVED RIGHTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;;\n2BAE;BLACK CURVED LEFTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;\n2BAF;BLACK CURVED RIGHTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;\n2BB0;RIBBON ARROW DOWN LEFT;So;0;ON;;;;;N;;;;;\n2BB1;RIBBON ARROW DOWN RIGHT;So;0;ON;;;;;N;;;;;\n2BB2;RIBBON ARROW UP LEFT;So;0;ON;;;;;N;;;;;\n2BB3;RIBBON ARROW UP RIGHT;So;0;ON;;;;;N;;;;;\n2BB4;RIBBON ARROW LEFT UP;So;0;ON;;;;;N;;;;;\n2BB5;RIBBON ARROW RIGHT UP;So;0;ON;;;;;N;;;;;\n2BB6;RIBBON ARROW LEFT DOWN;So;0;ON;;;;;N;;;;;\n2BB7;RIBBON ARROW RIGHT DOWN;So;0;ON;;;;;N;;;;;\n2BB8;UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;\n2BB9;UP ARROWHEAD IN A RECTANGLE BOX;So;0;ON;;;;;N;;;;;\n2BBA;OVERLAPPING WHITE SQUARES;So;0;ON;;;;;N;;;;;\n2BBB;OVERLAPPING WHITE AND BLACK SQUARES;So;0;ON;;;;;N;;;;;\n2BBC;OVERLAPPING BLACK SQUARES;So;0;ON;;;;;N;;;;;\n2BBD;BALLOT BOX WITH LIGHT X;So;0;ON;;;;;N;;;;;\n2BBE;CIRCLED X;So;0;ON;;;;;N;;;;;\n2BBF;CIRCLED BOLD X;So;0;ON;;;;;N;;;;;\n2BC0;BLACK SQUARE CENTRED;So;0;ON;;;;;N;;;;;\n2BC1;BLACK DIAMOND CENTRED;So;0;ON;;;;;N;;;;;\n2BC2;TURNED BLACK PENTAGON;So;0;ON;;;;;N;;;;;\n2BC3;HORIZONTAL BLACK OCTAGON;So;0;ON;;;;;N;;;;;\n2BC4;BLACK OCTAGON;So;0;ON;;;;;N;;;;;\n2BC5;BLACK MEDIUM UP-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;;\n2BC6;BLACK MEDIUM DOWN-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;;\n2BC7;BLACK MEDIUM LEFT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;;\n2BC8;BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;;\n2BC9;NEPTUNE FORM TWO;So;0;ON;;;;;N;;;;;\n2BCA;TOP HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n2BCB;BOTTOM HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n2BCC;LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;;\n2BCD;ROTATED LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;;\n2BCE;WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;;\n2BCF;ROTATED WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;;\n2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;;\n2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;;\n2BD2;GROUP MARK;So;0;ON;;;;;N;;;;;\n2BD3;PLUTO FORM TWO;So;0;ON;;;;;N;;;;;\n2BD4;PLUTO FORM THREE;So;0;ON;;;;;N;;;;;\n2BD5;PLUTO FORM FOUR;So;0;ON;;;;;N;;;;;\n2BD6;PLUTO FORM FIVE;So;0;ON;;;;;N;;;;;\n2BD7;TRANSPLUTO;So;0;ON;;;;;N;;;;;\n2BD8;PROSERPINA;So;0;ON;;;;;N;;;;;\n2BD9;ASTRAEA;So;0;ON;;;;;N;;;;;\n2BDA;HYGIEA;So;0;ON;;;;;N;;;;;\n2BDB;PHOLUS;So;0;ON;;;;;N;;;;;\n2BDC;NESSUS;So;0;ON;;;;;N;;;;;\n2BDD;WHITE MOON SELENA;So;0;ON;;;;;N;;;;;\n2BDE;BLACK DIAMOND ON CROSS;So;0;ON;;;;;N;;;;;\n2BDF;TRUE LIGHT MOON ARTA;So;0;ON;;;;;N;;;;;\n2BE0;CUPIDO;So;0;ON;;;;;N;;;;;\n2BE1;HADES;So;0;ON;;;;;N;;;;;\n2BE2;ZEUS;So;0;ON;;;;;N;;;;;\n2BE3;KRONOS;So;0;ON;;;;;N;;;;;\n2BE4;APOLLON;So;0;ON;;;;;N;;;;;\n2BE5;ADMETOS;So;0;ON;;;;;N;;;;;\n2BE6;VULCANUS;So;0;ON;;;;;N;;;;;\n2BE7;POSEIDON;So;0;ON;;;;;N;;;;;\n2BE8;LEFT HALF BLACK STAR;So;0;ON;;;;;N;;;;;\n2BE9;RIGHT HALF BLACK STAR;So;0;ON;;;;;N;;;;;\n2BEA;STAR WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;\n2BEB;STAR WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;\n2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;\n2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;\n2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;\n2BEF;DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;\n2BF0;ERIS FORM ONE;So;0;ON;;;;;N;;;;;\n2BF1;ERIS FORM TWO;So;0;ON;;;;;N;;;;;\n2BF2;SEDNA;So;0;ON;;;;;N;;;;;\n2BF3;RUSSIAN ASTROLOGICAL SYMBOL VIGINTILE;So;0;ON;;;;;N;;;;;\n2BF4;RUSSIAN ASTROLOGICAL SYMBOL NOVILE;So;0;ON;;;;;N;;;;;\n2BF5;RUSSIAN ASTROLOGICAL SYMBOL QUINTILE;So;0;ON;;;;;N;;;;;\n2BF6;RUSSIAN ASTROLOGICAL SYMBOL BINOVILE;So;0;ON;;;;;N;;;;;\n2BF7;RUSSIAN ASTROLOGICAL SYMBOL SENTAGON;So;0;ON;;;;;N;;;;;\n2BF8;RUSSIAN ASTROLOGICAL SYMBOL TREDECILE;So;0;ON;;;;;N;;;;;\n2BF9;EQUALS SIGN WITH INFINITY BELOW;So;0;ON;;;;;N;;;;;\n2BFA;UNITED SYMBOL;So;0;ON;;;;;N;;;;;\n2BFB;SEPARATED SYMBOL;So;0;ON;;;;;N;;;;;\n2BFC;DOUBLED SYMBOL;So;0;ON;;;;;N;;;;;\n2BFD;PASSED SYMBOL;So;0;ON;;;;;N;;;;;\n2BFE;REVERSED RIGHT ANGLE;So;0;ON;;;;;Y;;;;;\n2BFF;HELLSCHREIBER PAUSE SYMBOL;So;0;ON;;;;;N;;;;;\n2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30;\n2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31;\n2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32;\n2C03;GLAGOLITIC CAPITAL LETTER GLAGOLI;Lu;0;L;;;;;N;;;;2C33;\n2C04;GLAGOLITIC CAPITAL LETTER DOBRO;Lu;0;L;;;;;N;;;;2C34;\n2C05;GLAGOLITIC CAPITAL LETTER YESTU;Lu;0;L;;;;;N;;;;2C35;\n2C06;GLAGOLITIC CAPITAL LETTER ZHIVETE;Lu;0;L;;;;;N;;;;2C36;\n2C07;GLAGOLITIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;2C37;\n2C08;GLAGOLITIC CAPITAL LETTER ZEMLJA;Lu;0;L;;;;;N;;;;2C38;\n2C09;GLAGOLITIC CAPITAL LETTER IZHE;Lu;0;L;;;;;N;;;;2C39;\n2C0A;GLAGOLITIC CAPITAL LETTER INITIAL IZHE;Lu;0;L;;;;;N;;;;2C3A;\n2C0B;GLAGOLITIC CAPITAL LETTER I;Lu;0;L;;;;;N;;;;2C3B;\n2C0C;GLAGOLITIC CAPITAL LETTER DJERVI;Lu;0;L;;;;;N;;;;2C3C;\n2C0D;GLAGOLITIC CAPITAL LETTER KAKO;Lu;0;L;;;;;N;;;;2C3D;\n2C0E;GLAGOLITIC CAPITAL LETTER LJUDIJE;Lu;0;L;;;;;N;;;;2C3E;\n2C0F;GLAGOLITIC CAPITAL LETTER MYSLITE;Lu;0;L;;;;;N;;;;2C3F;\n2C10;GLAGOLITIC CAPITAL LETTER NASHI;Lu;0;L;;;;;N;;;;2C40;\n2C11;GLAGOLITIC CAPITAL LETTER ONU;Lu;0;L;;;;;N;;;;2C41;\n2C12;GLAGOLITIC CAPITAL LETTER POKOJI;Lu;0;L;;;;;N;;;;2C42;\n2C13;GLAGOLITIC CAPITAL LETTER RITSI;Lu;0;L;;;;;N;;;;2C43;\n2C14;GLAGOLITIC CAPITAL LETTER SLOVO;Lu;0;L;;;;;N;;;;2C44;\n2C15;GLAGOLITIC CAPITAL LETTER TVRIDO;Lu;0;L;;;;;N;;;;2C45;\n2C16;GLAGOLITIC CAPITAL LETTER UKU;Lu;0;L;;;;;N;;;;2C46;\n2C17;GLAGOLITIC CAPITAL LETTER FRITU;Lu;0;L;;;;;N;;;;2C47;\n2C18;GLAGOLITIC CAPITAL LETTER HERU;Lu;0;L;;;;;N;;;;2C48;\n2C19;GLAGOLITIC CAPITAL LETTER OTU;Lu;0;L;;;;;N;;;;2C49;\n2C1A;GLAGOLITIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;2C4A;\n2C1B;GLAGOLITIC CAPITAL LETTER SHTA;Lu;0;L;;;;;N;;;;2C4B;\n2C1C;GLAGOLITIC CAPITAL LETTER TSI;Lu;0;L;;;;;N;;;;2C4C;\n2C1D;GLAGOLITIC CAPITAL LETTER CHRIVI;Lu;0;L;;;;;N;;;;2C4D;\n2C1E;GLAGOLITIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;2C4E;\n2C1F;GLAGOLITIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;;;;2C4F;\n2C20;GLAGOLITIC CAPITAL LETTER YERI;Lu;0;L;;;;;N;;;;2C50;\n2C21;GLAGOLITIC CAPITAL LETTER YATI;Lu;0;L;;;;;N;;;;2C51;\n2C22;GLAGOLITIC CAPITAL LETTER SPIDERY HA;Lu;0;L;;;;;N;;;;2C52;\n2C23;GLAGOLITIC CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;2C53;\n2C24;GLAGOLITIC CAPITAL LETTER SMALL YUS;Lu;0;L;;;;;N;;;;2C54;\n2C25;GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL;Lu;0;L;;;;;N;;;;2C55;\n2C26;GLAGOLITIC CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;2C56;\n2C27;GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS;Lu;0;L;;;;;N;;;;2C57;\n2C28;GLAGOLITIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;2C58;\n2C29;GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS;Lu;0;L;;;;;N;;;;2C59;\n2C2A;GLAGOLITIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;2C5A;\n2C2B;GLAGOLITIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;2C5B;\n2C2C;GLAGOLITIC CAPITAL LETTER SHTAPIC;Lu;0;L;;;;;N;;;;2C5C;\n2C2D;GLAGOLITIC CAPITAL LETTER TROKUTASTI A;Lu;0;L;;;;;N;;;;2C5D;\n2C2E;GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE;Lu;0;L;;;;;N;;;;2C5E;\n2C2F;GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI;Lu;0;L;;;;;N;;;;2C5F;\n2C30;GLAGOLITIC SMALL LETTER AZU;Ll;0;L;;;;;N;;;2C00;;2C00\n2C31;GLAGOLITIC SMALL LETTER BUKY;Ll;0;L;;;;;N;;;2C01;;2C01\n2C32;GLAGOLITIC SMALL LETTER VEDE;Ll;0;L;;;;;N;;;2C02;;2C02\n2C33;GLAGOLITIC SMALL LETTER GLAGOLI;Ll;0;L;;;;;N;;;2C03;;2C03\n2C34;GLAGOLITIC SMALL LETTER DOBRO;Ll;0;L;;;;;N;;;2C04;;2C04\n2C35;GLAGOLITIC SMALL LETTER YESTU;Ll;0;L;;;;;N;;;2C05;;2C05\n2C36;GLAGOLITIC SMALL LETTER ZHIVETE;Ll;0;L;;;;;N;;;2C06;;2C06\n2C37;GLAGOLITIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;2C07;;2C07\n2C38;GLAGOLITIC SMALL LETTER ZEMLJA;Ll;0;L;;;;;N;;;2C08;;2C08\n2C39;GLAGOLITIC SMALL LETTER IZHE;Ll;0;L;;;;;N;;;2C09;;2C09\n2C3A;GLAGOLITIC SMALL LETTER INITIAL IZHE;Ll;0;L;;;;;N;;;2C0A;;2C0A\n2C3B;GLAGOLITIC SMALL LETTER I;Ll;0;L;;;;;N;;;2C0B;;2C0B\n2C3C;GLAGOLITIC SMALL LETTER DJERVI;Ll;0;L;;;;;N;;;2C0C;;2C0C\n2C3D;GLAGOLITIC SMALL LETTER KAKO;Ll;0;L;;;;;N;;;2C0D;;2C0D\n2C3E;GLAGOLITIC SMALL LETTER LJUDIJE;Ll;0;L;;;;;N;;;2C0E;;2C0E\n2C3F;GLAGOLITIC SMALL LETTER MYSLITE;Ll;0;L;;;;;N;;;2C0F;;2C0F\n2C40;GLAGOLITIC SMALL LETTER NASHI;Ll;0;L;;;;;N;;;2C10;;2C10\n2C41;GLAGOLITIC SMALL LETTER ONU;Ll;0;L;;;;;N;;;2C11;;2C11\n2C42;GLAGOLITIC SMALL LETTER POKOJI;Ll;0;L;;;;;N;;;2C12;;2C12\n2C43;GLAGOLITIC SMALL LETTER RITSI;Ll;0;L;;;;;N;;;2C13;;2C13\n2C44;GLAGOLITIC SMALL LETTER SLOVO;Ll;0;L;;;;;N;;;2C14;;2C14\n2C45;GLAGOLITIC SMALL LETTER TVRIDO;Ll;0;L;;;;;N;;;2C15;;2C15\n2C46;GLAGOLITIC SMALL LETTER UKU;Ll;0;L;;;;;N;;;2C16;;2C16\n2C47;GLAGOLITIC SMALL LETTER FRITU;Ll;0;L;;;;;N;;;2C17;;2C17\n2C48;GLAGOLITIC SMALL LETTER HERU;Ll;0;L;;;;;N;;;2C18;;2C18\n2C49;GLAGOLITIC SMALL LETTER OTU;Ll;0;L;;;;;N;;;2C19;;2C19\n2C4A;GLAGOLITIC SMALL LETTER PE;Ll;0;L;;;;;N;;;2C1A;;2C1A\n2C4B;GLAGOLITIC SMALL LETTER SHTA;Ll;0;L;;;;;N;;;2C1B;;2C1B\n2C4C;GLAGOLITIC SMALL LETTER TSI;Ll;0;L;;;;;N;;;2C1C;;2C1C\n2C4D;GLAGOLITIC SMALL LETTER CHRIVI;Ll;0;L;;;;;N;;;2C1D;;2C1D\n2C4E;GLAGOLITIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;2C1E;;2C1E\n2C4F;GLAGOLITIC SMALL LETTER YERU;Ll;0;L;;;;;N;;;2C1F;;2C1F\n2C50;GLAGOLITIC SMALL LETTER YERI;Ll;0;L;;;;;N;;;2C20;;2C20\n2C51;GLAGOLITIC SMALL LETTER YATI;Ll;0;L;;;;;N;;;2C21;;2C21\n2C52;GLAGOLITIC SMALL LETTER SPIDERY HA;Ll;0;L;;;;;N;;;2C22;;2C22\n2C53;GLAGOLITIC SMALL LETTER YU;Ll;0;L;;;;;N;;;2C23;;2C23\n2C54;GLAGOLITIC SMALL LETTER SMALL YUS;Ll;0;L;;;;;N;;;2C24;;2C24\n2C55;GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL;Ll;0;L;;;;;N;;;2C25;;2C25\n2C56;GLAGOLITIC SMALL LETTER YO;Ll;0;L;;;;;N;;;2C26;;2C26\n2C57;GLAGOLITIC SMALL LETTER IOTATED SMALL YUS;Ll;0;L;;;;;N;;;2C27;;2C27\n2C58;GLAGOLITIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;2C28;;2C28\n2C59;GLAGOLITIC SMALL LETTER IOTATED BIG YUS;Ll;0;L;;;;;N;;;2C29;;2C29\n2C5A;GLAGOLITIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;2C2A;;2C2A\n2C5B;GLAGOLITIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;2C2B;;2C2B\n2C5C;GLAGOLITIC SMALL LETTER SHTAPIC;Ll;0;L;;;;;N;;;2C2C;;2C2C\n2C5D;GLAGOLITIC SMALL LETTER TROKUTASTI A;Ll;0;L;;;;;N;;;2C2D;;2C2D\n2C5E;GLAGOLITIC SMALL LETTER LATINATE MYSLITE;Ll;0;L;;;;;N;;;2C2E;;2C2E\n2C5F;GLAGOLITIC SMALL LETTER CAUDATE CHRIVI;Ll;0;L;;;;;N;;;2C2F;;2C2F\n2C60;LATIN CAPITAL LETTER L WITH DOUBLE BAR;Lu;0;L;;;;;N;;;;2C61;\n2C61;LATIN SMALL LETTER L WITH DOUBLE BAR;Ll;0;L;;;;;N;;;2C60;;2C60\n2C62;LATIN CAPITAL LETTER L WITH MIDDLE TILDE;Lu;0;L;;;;;N;;;;026B;\n2C63;LATIN CAPITAL LETTER P WITH STROKE;Lu;0;L;;;;;N;;;;1D7D;\n2C64;LATIN CAPITAL LETTER R WITH TAIL;Lu;0;L;;;;;N;;;;027D;\n2C65;LATIN SMALL LETTER A WITH STROKE;Ll;0;L;;;;;N;;;023A;;023A\n2C66;LATIN SMALL LETTER T WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;023E;;023E\n2C67;LATIN CAPITAL LETTER H WITH DESCENDER;Lu;0;L;;;;;N;;;;2C68;\n2C68;LATIN SMALL LETTER H WITH DESCENDER;Ll;0;L;;;;;N;;;2C67;;2C67\n2C69;LATIN CAPITAL LETTER K WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6A;\n2C6A;LATIN SMALL LETTER K WITH DESCENDER;Ll;0;L;;;;;N;;;2C69;;2C69\n2C6B;LATIN CAPITAL LETTER Z WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6C;\n2C6C;LATIN SMALL LETTER Z WITH DESCENDER;Ll;0;L;;;;;N;;;2C6B;;2C6B\n2C6D;LATIN CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;0251;\n2C6E;LATIN CAPITAL LETTER M WITH HOOK;Lu;0;L;;;;;N;;;;0271;\n2C6F;LATIN CAPITAL LETTER TURNED A;Lu;0;L;;;;;N;;;;0250;\n2C70;LATIN CAPITAL LETTER TURNED ALPHA;Lu;0;L;;;;;N;;;;0252;\n2C71;LATIN SMALL LETTER V WITH RIGHT HOOK;Ll;0;L;;;;;N;;;;;\n2C72;LATIN CAPITAL LETTER W WITH HOOK;Lu;0;L;;;;;N;;;;2C73;\n2C73;LATIN SMALL LETTER W WITH HOOK;Ll;0;L;;;;;N;;;2C72;;2C72\n2C74;LATIN SMALL LETTER V WITH CURL;Ll;0;L;;;;;N;;;;;\n2C75;LATIN CAPITAL LETTER HALF H;Lu;0;L;;;;;N;;;;2C76;\n2C76;LATIN SMALL LETTER HALF H;Ll;0;L;;;;;N;;;2C75;;2C75\n2C77;LATIN SMALL LETTER TAILLESS PHI;Ll;0;L;;;;;N;;;;;\n2C78;LATIN SMALL LETTER E WITH NOTCH;Ll;0;L;;;;;N;;;;;\n2C79;LATIN SMALL LETTER TURNED R WITH TAIL;Ll;0;L;;;;;N;;;;;\n2C7A;LATIN SMALL LETTER O WITH LOW RING INSIDE;Ll;0;L;;;;;N;;;;;\n2C7B;LATIN LETTER SMALL CAPITAL TURNED E;Ll;0;L;;;;;N;;;;;\n2C7C;LATIN SUBSCRIPT SMALL LETTER J;Lm;0;L;<sub> 006A;;;;N;;;;;\n2C7D;MODIFIER LETTER CAPITAL V;Lm;0;L;<super> 0056;;;;N;;;;;\n2C7E;LATIN CAPITAL LETTER S WITH SWASH TAIL;Lu;0;L;;;;;N;;;;023F;\n2C7F;LATIN CAPITAL LETTER Z WITH SWASH TAIL;Lu;0;L;;;;;N;;;;0240;\n2C80;COPTIC CAPITAL LETTER ALFA;Lu;0;L;;;;;N;;;;2C81;\n2C81;COPTIC SMALL LETTER ALFA;Ll;0;L;;;;;N;;;2C80;;2C80\n2C82;COPTIC CAPITAL LETTER VIDA;Lu;0;L;;;;;N;;;;2C83;\n2C83;COPTIC SMALL LETTER VIDA;Ll;0;L;;;;;N;;;2C82;;2C82\n2C84;COPTIC CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;2C85;\n2C85;COPTIC SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;2C84;;2C84\n2C86;COPTIC CAPITAL LETTER DALDA;Lu;0;L;;;;;N;;;;2C87;\n2C87;COPTIC SMALL LETTER DALDA;Ll;0;L;;;;;N;;;2C86;;2C86\n2C88;COPTIC CAPITAL LETTER EIE;Lu;0;L;;;;;N;;;;2C89;\n2C89;COPTIC SMALL LETTER EIE;Ll;0;L;;;;;N;;;2C88;;2C88\n2C8A;COPTIC CAPITAL LETTER SOU;Lu;0;L;;;;;N;;;;2C8B;\n2C8B;COPTIC SMALL LETTER SOU;Ll;0;L;;;;;N;;;2C8A;;2C8A\n2C8C;COPTIC CAPITAL LETTER ZATA;Lu;0;L;;;;;N;;;;2C8D;\n2C8D;COPTIC SMALL LETTER ZATA;Ll;0;L;;;;;N;;;2C8C;;2C8C\n2C8E;COPTIC CAPITAL LETTER HATE;Lu;0;L;;;;;N;;;;2C8F;\n2C8F;COPTIC SMALL LETTER HATE;Ll;0;L;;;;;N;;;2C8E;;2C8E\n2C90;COPTIC CAPITAL LETTER THETHE;Lu;0;L;;;;;N;;;;2C91;\n2C91;COPTIC SMALL LETTER THETHE;Ll;0;L;;;;;N;;;2C90;;2C90\n2C92;COPTIC CAPITAL LETTER IAUDA;Lu;0;L;;;;;N;;;;2C93;\n2C93;COPTIC SMALL LETTER IAUDA;Ll;0;L;;;;;N;;;2C92;;2C92\n2C94;COPTIC CAPITAL LETTER KAPA;Lu;0;L;;;;;N;;;;2C95;\n2C95;COPTIC SMALL LETTER KAPA;Ll;0;L;;;;;N;;;2C94;;2C94\n2C96;COPTIC CAPITAL LETTER LAULA;Lu;0;L;;;;;N;;;;2C97;\n2C97;COPTIC SMALL LETTER LAULA;Ll;0;L;;;;;N;;;2C96;;2C96\n2C98;COPTIC CAPITAL LETTER MI;Lu;0;L;;;;;N;;;;2C99;\n2C99;COPTIC SMALL LETTER MI;Ll;0;L;;;;;N;;;2C98;;2C98\n2C9A;COPTIC CAPITAL LETTER NI;Lu;0;L;;;;;N;;;;2C9B;\n2C9B;COPTIC SMALL LETTER NI;Ll;0;L;;;;;N;;;2C9A;;2C9A\n2C9C;COPTIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;2C9D;\n2C9D;COPTIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;2C9C;;2C9C\n2C9E;COPTIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;2C9F;\n2C9F;COPTIC SMALL LETTER O;Ll;0;L;;;;;N;;;2C9E;;2C9E\n2CA0;COPTIC CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;2CA1;\n2CA1;COPTIC SMALL LETTER PI;Ll;0;L;;;;;N;;;2CA0;;2CA0\n2CA2;COPTIC CAPITAL LETTER RO;Lu;0;L;;;;;N;;;;2CA3;\n2CA3;COPTIC SMALL LETTER RO;Ll;0;L;;;;;N;;;2CA2;;2CA2\n2CA4;COPTIC CAPITAL LETTER SIMA;Lu;0;L;;;;;N;;;;2CA5;\n2CA5;COPTIC SMALL LETTER SIMA;Ll;0;L;;;;;N;;;2CA4;;2CA4\n2CA6;COPTIC CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;2CA7;\n2CA7;COPTIC SMALL LETTER TAU;Ll;0;L;;;;;N;;;2CA6;;2CA6\n2CA8;COPTIC CAPITAL LETTER UA;Lu;0;L;;;;;N;;;;2CA9;\n2CA9;COPTIC SMALL LETTER UA;Ll;0;L;;;;;N;;;2CA8;;2CA8\n2CAA;COPTIC CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;2CAB;\n2CAB;COPTIC SMALL LETTER FI;Ll;0;L;;;;;N;;;2CAA;;2CAA\n2CAC;COPTIC CAPITAL LETTER KHI;Lu;0;L;;;;;N;;;;2CAD;\n2CAD;COPTIC SMALL LETTER KHI;Ll;0;L;;;;;N;;;2CAC;;2CAC\n2CAE;COPTIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;2CAF;\n2CAF;COPTIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;2CAE;;2CAE\n2CB0;COPTIC CAPITAL LETTER OOU;Lu;0;L;;;;;N;;;;2CB1;\n2CB1;COPTIC SMALL LETTER OOU;Ll;0;L;;;;;N;;;2CB0;;2CB0\n2CB2;COPTIC CAPITAL LETTER DIALECT-P ALEF;Lu;0;L;;;;;N;;;;2CB3;\n2CB3;COPTIC SMALL LETTER DIALECT-P ALEF;Ll;0;L;;;;;N;;;2CB2;;2CB2\n2CB4;COPTIC CAPITAL LETTER OLD COPTIC AIN;Lu;0;L;;;;;N;;;;2CB5;\n2CB5;COPTIC SMALL LETTER OLD COPTIC AIN;Ll;0;L;;;;;N;;;2CB4;;2CB4\n2CB6;COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE;Lu;0;L;;;;;N;;;;2CB7;\n2CB7;COPTIC SMALL LETTER CRYPTOGRAMMIC EIE;Ll;0;L;;;;;N;;;2CB6;;2CB6\n2CB8;COPTIC CAPITAL LETTER DIALECT-P KAPA;Lu;0;L;;;;;N;;;;2CB9;\n2CB9;COPTIC SMALL LETTER DIALECT-P KAPA;Ll;0;L;;;;;N;;;2CB8;;2CB8\n2CBA;COPTIC CAPITAL LETTER DIALECT-P NI;Lu;0;L;;;;;N;;;;2CBB;\n2CBB;COPTIC SMALL LETTER DIALECT-P NI;Ll;0;L;;;;;N;;;2CBA;;2CBA\n2CBC;COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI;Lu;0;L;;;;;N;;;;2CBD;\n2CBD;COPTIC SMALL LETTER CRYPTOGRAMMIC NI;Ll;0;L;;;;;N;;;2CBC;;2CBC\n2CBE;COPTIC CAPITAL LETTER OLD COPTIC OOU;Lu;0;L;;;;;N;;;;2CBF;\n2CBF;COPTIC SMALL LETTER OLD COPTIC OOU;Ll;0;L;;;;;N;;;2CBE;;2CBE\n2CC0;COPTIC CAPITAL LETTER SAMPI;Lu;0;L;;;;;N;;;;2CC1;\n2CC1;COPTIC SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;2CC0;;2CC0\n2CC2;COPTIC CAPITAL LETTER CROSSED SHEI;Lu;0;L;;;;;N;;;;2CC3;\n2CC3;COPTIC SMALL LETTER CROSSED SHEI;Ll;0;L;;;;;N;;;2CC2;;2CC2\n2CC4;COPTIC CAPITAL LETTER OLD COPTIC SHEI;Lu;0;L;;;;;N;;;;2CC5;\n2CC5;COPTIC SMALL LETTER OLD COPTIC SHEI;Ll;0;L;;;;;N;;;2CC4;;2CC4\n2CC6;COPTIC CAPITAL LETTER OLD COPTIC ESH;Lu;0;L;;;;;N;;;;2CC7;\n2CC7;COPTIC SMALL LETTER OLD COPTIC ESH;Ll;0;L;;;;;N;;;2CC6;;2CC6\n2CC8;COPTIC CAPITAL LETTER AKHMIMIC KHEI;Lu;0;L;;;;;N;;;;2CC9;\n2CC9;COPTIC SMALL LETTER AKHMIMIC KHEI;Ll;0;L;;;;;N;;;2CC8;;2CC8\n2CCA;COPTIC CAPITAL LETTER DIALECT-P HORI;Lu;0;L;;;;;N;;;;2CCB;\n2CCB;COPTIC SMALL LETTER DIALECT-P HORI;Ll;0;L;;;;;N;;;2CCA;;2CCA\n2CCC;COPTIC CAPITAL LETTER OLD COPTIC HORI;Lu;0;L;;;;;N;;;;2CCD;\n2CCD;COPTIC SMALL LETTER OLD COPTIC HORI;Ll;0;L;;;;;N;;;2CCC;;2CCC\n2CCE;COPTIC CAPITAL LETTER OLD COPTIC HA;Lu;0;L;;;;;N;;;;2CCF;\n2CCF;COPTIC SMALL LETTER OLD COPTIC HA;Ll;0;L;;;;;N;;;2CCE;;2CCE\n2CD0;COPTIC CAPITAL LETTER L-SHAPED HA;Lu;0;L;;;;;N;;;;2CD1;\n2CD1;COPTIC SMALL LETTER L-SHAPED HA;Ll;0;L;;;;;N;;;2CD0;;2CD0\n2CD2;COPTIC CAPITAL LETTER OLD COPTIC HEI;Lu;0;L;;;;;N;;;;2CD3;\n2CD3;COPTIC SMALL LETTER OLD COPTIC HEI;Ll;0;L;;;;;N;;;2CD2;;2CD2\n2CD4;COPTIC CAPITAL LETTER OLD COPTIC HAT;Lu;0;L;;;;;N;;;;2CD5;\n2CD5;COPTIC SMALL LETTER OLD COPTIC HAT;Ll;0;L;;;;;N;;;2CD4;;2CD4\n2CD6;COPTIC CAPITAL LETTER OLD COPTIC GANGIA;Lu;0;L;;;;;N;;;;2CD7;\n2CD7;COPTIC SMALL LETTER OLD COPTIC GANGIA;Ll;0;L;;;;;N;;;2CD6;;2CD6\n2CD8;COPTIC CAPITAL LETTER OLD COPTIC DJA;Lu;0;L;;;;;N;;;;2CD9;\n2CD9;COPTIC SMALL LETTER OLD COPTIC DJA;Ll;0;L;;;;;N;;;2CD8;;2CD8\n2CDA;COPTIC CAPITAL LETTER OLD COPTIC SHIMA;Lu;0;L;;;;;N;;;;2CDB;\n2CDB;COPTIC SMALL LETTER OLD COPTIC SHIMA;Ll;0;L;;;;;N;;;2CDA;;2CDA\n2CDC;COPTIC CAPITAL LETTER OLD NUBIAN SHIMA;Lu;0;L;;;;;N;;;;2CDD;\n2CDD;COPTIC SMALL LETTER OLD NUBIAN SHIMA;Ll;0;L;;;;;N;;;2CDC;;2CDC\n2CDE;COPTIC CAPITAL LETTER OLD NUBIAN NGI;Lu;0;L;;;;;N;;;;2CDF;\n2CDF;COPTIC SMALL LETTER OLD NUBIAN NGI;Ll;0;L;;;;;N;;;2CDE;;2CDE\n2CE0;COPTIC CAPITAL LETTER OLD NUBIAN NYI;Lu;0;L;;;;;N;;;;2CE1;\n2CE1;COPTIC SMALL LETTER OLD NUBIAN NYI;Ll;0;L;;;;;N;;;2CE0;;2CE0\n2CE2;COPTIC CAPITAL LETTER OLD NUBIAN WAU;Lu;0;L;;;;;N;;;;2CE3;\n2CE3;COPTIC SMALL LETTER OLD NUBIAN WAU;Ll;0;L;;;;;N;;;2CE2;;2CE2\n2CE4;COPTIC SYMBOL KAI;Ll;0;L;;;;;N;;;;;\n2CE5;COPTIC SYMBOL MI RO;So;0;ON;;;;;N;;;;;\n2CE6;COPTIC SYMBOL PI RO;So;0;ON;;;;;N;;;;;\n2CE7;COPTIC SYMBOL STAUROS;So;0;ON;;;;;N;;;;;\n2CE8;COPTIC SYMBOL TAU RO;So;0;ON;;;;;N;;;;;\n2CE9;COPTIC SYMBOL KHI RO;So;0;ON;;;;;N;;;;;\n2CEA;COPTIC SYMBOL SHIMA SIMA;So;0;ON;;;;;N;;;;;\n2CEB;COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI;Lu;0;L;;;;;N;;;;2CEC;\n2CEC;COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI;Ll;0;L;;;;;N;;;2CEB;;2CEB\n2CED;COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA;Lu;0;L;;;;;N;;;;2CEE;\n2CEE;COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA;Ll;0;L;;;;;N;;;2CED;;2CED\n2CEF;COPTIC COMBINING NI ABOVE;Mn;230;NSM;;;;;N;;;;;\n2CF0;COPTIC COMBINING SPIRITUS ASPER;Mn;230;NSM;;;;;N;;;;;\n2CF1;COPTIC COMBINING SPIRITUS LENIS;Mn;230;NSM;;;;;N;;;;;\n2CF2;COPTIC CAPITAL LETTER BOHAIRIC KHEI;Lu;0;L;;;;;N;;;;2CF3;\n2CF3;COPTIC SMALL LETTER BOHAIRIC KHEI;Ll;0;L;;;;;N;;;2CF2;;2CF2\n2CF9;COPTIC OLD NUBIAN FULL STOP;Po;0;ON;;;;;N;;;;;\n2CFA;COPTIC OLD NUBIAN DIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;;\n2CFB;COPTIC OLD NUBIAN INDIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;;\n2CFC;COPTIC OLD NUBIAN VERSE DIVIDER;Po;0;ON;;;;;N;;;;;\n2CFD;COPTIC FRACTION ONE HALF;No;0;ON;;;;1/2;N;;;;;\n2CFE;COPTIC FULL STOP;Po;0;ON;;;;;N;;;;;\n2CFF;COPTIC MORPHOLOGICAL DIVIDER;Po;0;ON;;;;;N;;;;;\n2D00;GEORGIAN SMALL LETTER AN;Ll;0;L;;;;;N;;;10A0;;10A0\n2D01;GEORGIAN SMALL LETTER BAN;Ll;0;L;;;;;N;;;10A1;;10A1\n2D02;GEORGIAN SMALL LETTER GAN;Ll;0;L;;;;;N;;;10A2;;10A2\n2D03;GEORGIAN SMALL LETTER DON;Ll;0;L;;;;;N;;;10A3;;10A3\n2D04;GEORGIAN SMALL LETTER EN;Ll;0;L;;;;;N;;;10A4;;10A4\n2D05;GEORGIAN SMALL LETTER VIN;Ll;0;L;;;;;N;;;10A5;;10A5\n2D06;GEORGIAN SMALL LETTER ZEN;Ll;0;L;;;;;N;;;10A6;;10A6\n2D07;GEORGIAN SMALL LETTER TAN;Ll;0;L;;;;;N;;;10A7;;10A7\n2D08;GEORGIAN SMALL LETTER IN;Ll;0;L;;;;;N;;;10A8;;10A8\n2D09;GEORGIAN SMALL LETTER KAN;Ll;0;L;;;;;N;;;10A9;;10A9\n2D0A;GEORGIAN SMALL LETTER LAS;Ll;0;L;;;;;N;;;10AA;;10AA\n2D0B;GEORGIAN SMALL LETTER MAN;Ll;0;L;;;;;N;;;10AB;;10AB\n2D0C;GEORGIAN SMALL LETTER NAR;Ll;0;L;;;;;N;;;10AC;;10AC\n2D0D;GEORGIAN SMALL LETTER ON;Ll;0;L;;;;;N;;;10AD;;10AD\n2D0E;GEORGIAN SMALL LETTER PAR;Ll;0;L;;;;;N;;;10AE;;10AE\n2D0F;GEORGIAN SMALL LETTER ZHAR;Ll;0;L;;;;;N;;;10AF;;10AF\n2D10;GEORGIAN SMALL LETTER RAE;Ll;0;L;;;;;N;;;10B0;;10B0\n2D11;GEORGIAN SMALL LETTER SAN;Ll;0;L;;;;;N;;;10B1;;10B1\n2D12;GEORGIAN SMALL LETTER TAR;Ll;0;L;;;;;N;;;10B2;;10B2\n2D13;GEORGIAN SMALL LETTER UN;Ll;0;L;;;;;N;;;10B3;;10B3\n2D14;GEORGIAN SMALL LETTER PHAR;Ll;0;L;;;;;N;;;10B4;;10B4\n2D15;GEORGIAN SMALL LETTER KHAR;Ll;0;L;;;;;N;;;10B5;;10B5\n2D16;GEORGIAN SMALL LETTER GHAN;Ll;0;L;;;;;N;;;10B6;;10B6\n2D17;GEORGIAN SMALL LETTER QAR;Ll;0;L;;;;;N;;;10B7;;10B7\n2D18;GEORGIAN SMALL LETTER SHIN;Ll;0;L;;;;;N;;;10B8;;10B8\n2D19;GEORGIAN SMALL LETTER CHIN;Ll;0;L;;;;;N;;;10B9;;10B9\n2D1A;GEORGIAN SMALL LETTER CAN;Ll;0;L;;;;;N;;;10BA;;10BA\n2D1B;GEORGIAN SMALL LETTER JIL;Ll;0;L;;;;;N;;;10BB;;10BB\n2D1C;GEORGIAN SMALL LETTER CIL;Ll;0;L;;;;;N;;;10BC;;10BC\n2D1D;GEORGIAN SMALL LETTER CHAR;Ll;0;L;;;;;N;;;10BD;;10BD\n2D1E;GEORGIAN SMALL LETTER XAN;Ll;0;L;;;;;N;;;10BE;;10BE\n2D1F;GEORGIAN SMALL LETTER JHAN;Ll;0;L;;;;;N;;;10BF;;10BF\n2D20;GEORGIAN SMALL LETTER HAE;Ll;0;L;;;;;N;;;10C0;;10C0\n2D21;GEORGIAN SMALL LETTER HE;Ll;0;L;;;;;N;;;10C1;;10C1\n2D22;GEORGIAN SMALL LETTER HIE;Ll;0;L;;;;;N;;;10C2;;10C2\n2D23;GEORGIAN SMALL LETTER WE;Ll;0;L;;;;;N;;;10C3;;10C3\n2D24;GEORGIAN SMALL LETTER HAR;Ll;0;L;;;;;N;;;10C4;;10C4\n2D25;GEORGIAN SMALL LETTER HOE;Ll;0;L;;;;;N;;;10C5;;10C5\n2D27;GEORGIAN SMALL LETTER YN;Ll;0;L;;;;;N;;;10C7;;10C7\n2D2D;GEORGIAN SMALL LETTER AEN;Ll;0;L;;;;;N;;;10CD;;10CD\n2D30;TIFINAGH LETTER YA;Lo;0;L;;;;;N;;;;;\n2D31;TIFINAGH LETTER YAB;Lo;0;L;;;;;N;;;;;\n2D32;TIFINAGH LETTER YABH;Lo;0;L;;;;;N;;;;;\n2D33;TIFINAGH LETTER YAG;Lo;0;L;;;;;N;;;;;\n2D34;TIFINAGH LETTER YAGHH;Lo;0;L;;;;;N;;;;;\n2D35;TIFINAGH LETTER BERBER ACADEMY YAJ;Lo;0;L;;;;;N;;;;;\n2D36;TIFINAGH LETTER YAJ;Lo;0;L;;;;;N;;;;;\n2D37;TIFINAGH LETTER YAD;Lo;0;L;;;;;N;;;;;\n2D38;TIFINAGH LETTER YADH;Lo;0;L;;;;;N;;;;;\n2D39;TIFINAGH LETTER YADD;Lo;0;L;;;;;N;;;;;\n2D3A;TIFINAGH LETTER YADDH;Lo;0;L;;;;;N;;;;;\n2D3B;TIFINAGH LETTER YEY;Lo;0;L;;;;;N;;;;;\n2D3C;TIFINAGH LETTER YAF;Lo;0;L;;;;;N;;;;;\n2D3D;TIFINAGH LETTER YAK;Lo;0;L;;;;;N;;;;;\n2D3E;TIFINAGH LETTER TUAREG YAK;Lo;0;L;;;;;N;;;;;\n2D3F;TIFINAGH LETTER YAKHH;Lo;0;L;;;;;N;;;;;\n2D40;TIFINAGH LETTER YAH;Lo;0;L;;;;;N;;;;;\n2D41;TIFINAGH LETTER BERBER ACADEMY YAH;Lo;0;L;;;;;N;;;;;\n2D42;TIFINAGH LETTER TUAREG YAH;Lo;0;L;;;;;N;;;;;\n2D43;TIFINAGH LETTER YAHH;Lo;0;L;;;;;N;;;;;\n2D44;TIFINAGH LETTER YAA;Lo;0;L;;;;;N;;;;;\n2D45;TIFINAGH LETTER YAKH;Lo;0;L;;;;;N;;;;;\n2D46;TIFINAGH LETTER TUAREG YAKH;Lo;0;L;;;;;N;;;;;\n2D47;TIFINAGH LETTER YAQ;Lo;0;L;;;;;N;;;;;\n2D48;TIFINAGH LETTER TUAREG YAQ;Lo;0;L;;;;;N;;;;;\n2D49;TIFINAGH LETTER YI;Lo;0;L;;;;;N;;;;;\n2D4A;TIFINAGH LETTER YAZH;Lo;0;L;;;;;N;;;;;\n2D4B;TIFINAGH LETTER AHAGGAR YAZH;Lo;0;L;;;;;N;;;;;\n2D4C;TIFINAGH LETTER TUAREG YAZH;Lo;0;L;;;;;N;;;;;\n2D4D;TIFINAGH LETTER YAL;Lo;0;L;;;;;N;;;;;\n2D4E;TIFINAGH LETTER YAM;Lo;0;L;;;;;N;;;;;\n2D4F;TIFINAGH LETTER YAN;Lo;0;L;;;;;N;;;;;\n2D50;TIFINAGH LETTER TUAREG YAGN;Lo;0;L;;;;;N;;;;;\n2D51;TIFINAGH LETTER TUAREG YANG;Lo;0;L;;;;;N;;;;;\n2D52;TIFINAGH LETTER YAP;Lo;0;L;;;;;N;;;;;\n2D53;TIFINAGH LETTER YU;Lo;0;L;;;;;N;;;;;\n2D54;TIFINAGH LETTER YAR;Lo;0;L;;;;;N;;;;;\n2D55;TIFINAGH LETTER YARR;Lo;0;L;;;;;N;;;;;\n2D56;TIFINAGH LETTER YAGH;Lo;0;L;;;;;N;;;;;\n2D57;TIFINAGH LETTER TUAREG YAGH;Lo;0;L;;;;;N;;;;;\n2D58;TIFINAGH LETTER AYER YAGH;Lo;0;L;;;;;N;;;;;\n2D59;TIFINAGH LETTER YAS;Lo;0;L;;;;;N;;;;;\n2D5A;TIFINAGH LETTER YASS;Lo;0;L;;;;;N;;;;;\n2D5B;TIFINAGH LETTER YASH;Lo;0;L;;;;;N;;;;;\n2D5C;TIFINAGH LETTER YAT;Lo;0;L;;;;;N;;;;;\n2D5D;TIFINAGH LETTER YATH;Lo;0;L;;;;;N;;;;;\n2D5E;TIFINAGH LETTER YACH;Lo;0;L;;;;;N;;;;;\n2D5F;TIFINAGH LETTER YATT;Lo;0;L;;;;;N;;;;;\n2D60;TIFINAGH LETTER YAV;Lo;0;L;;;;;N;;;;;\n2D61;TIFINAGH LETTER YAW;Lo;0;L;;;;;N;;;;;\n2D62;TIFINAGH LETTER YAY;Lo;0;L;;;;;N;;;;;\n2D63;TIFINAGH LETTER YAZ;Lo;0;L;;;;;N;;;;;\n2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;;;;\n2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;;\n2D66;TIFINAGH LETTER YE;Lo;0;L;;;;;N;;;;;\n2D67;TIFINAGH LETTER YO;Lo;0;L;;;;;N;;;;;\n2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L;<super> 2D61;;;;N;;;;;\n2D70;TIFINAGH SEPARATOR MARK;Po;0;L;;;;;N;;;;;\n2D7F;TIFINAGH CONSONANT JOINER;Mn;9;NSM;;;;;N;;;;;\n2D80;ETHIOPIC SYLLABLE LOA;Lo;0;L;;;;;N;;;;;\n2D81;ETHIOPIC SYLLABLE MOA;Lo;0;L;;;;;N;;;;;\n2D82;ETHIOPIC SYLLABLE ROA;Lo;0;L;;;;;N;;;;;\n2D83;ETHIOPIC SYLLABLE SOA;Lo;0;L;;;;;N;;;;;\n2D84;ETHIOPIC SYLLABLE SHOA;Lo;0;L;;;;;N;;;;;\n2D85;ETHIOPIC SYLLABLE BOA;Lo;0;L;;;;;N;;;;;\n2D86;ETHIOPIC SYLLABLE TOA;Lo;0;L;;;;;N;;;;;\n2D87;ETHIOPIC SYLLABLE COA;Lo;0;L;;;;;N;;;;;\n2D88;ETHIOPIC SYLLABLE NOA;Lo;0;L;;;;;N;;;;;\n2D89;ETHIOPIC SYLLABLE NYOA;Lo;0;L;;;;;N;;;;;\n2D8A;ETHIOPIC SYLLABLE GLOTTAL OA;Lo;0;L;;;;;N;;;;;\n2D8B;ETHIOPIC SYLLABLE ZOA;Lo;0;L;;;;;N;;;;;\n2D8C;ETHIOPIC SYLLABLE DOA;Lo;0;L;;;;;N;;;;;\n2D8D;ETHIOPIC SYLLABLE DDOA;Lo;0;L;;;;;N;;;;;\n2D8E;ETHIOPIC SYLLABLE JOA;Lo;0;L;;;;;N;;;;;\n2D8F;ETHIOPIC SYLLABLE THOA;Lo;0;L;;;;;N;;;;;\n2D90;ETHIOPIC SYLLABLE CHOA;Lo;0;L;;;;;N;;;;;\n2D91;ETHIOPIC SYLLABLE PHOA;Lo;0;L;;;;;N;;;;;\n2D92;ETHIOPIC SYLLABLE POA;Lo;0;L;;;;;N;;;;;\n2D93;ETHIOPIC SYLLABLE GGWA;Lo;0;L;;;;;N;;;;;\n2D94;ETHIOPIC SYLLABLE GGWI;Lo;0;L;;;;;N;;;;;\n2D95;ETHIOPIC SYLLABLE GGWEE;Lo;0;L;;;;;N;;;;;\n2D96;ETHIOPIC SYLLABLE GGWE;Lo;0;L;;;;;N;;;;;\n2DA0;ETHIOPIC SYLLABLE SSA;Lo;0;L;;;;;N;;;;;\n2DA1;ETHIOPIC SYLLABLE SSU;Lo;0;L;;;;;N;;;;;\n2DA2;ETHIOPIC SYLLABLE SSI;Lo;0;L;;;;;N;;;;;\n2DA3;ETHIOPIC SYLLABLE SSAA;Lo;0;L;;;;;N;;;;;\n2DA4;ETHIOPIC SYLLABLE SSEE;Lo;0;L;;;;;N;;;;;\n2DA5;ETHIOPIC SYLLABLE SSE;Lo;0;L;;;;;N;;;;;\n2DA6;ETHIOPIC SYLLABLE SSO;Lo;0;L;;;;;N;;;;;\n2DA8;ETHIOPIC SYLLABLE CCA;Lo;0;L;;;;;N;;;;;\n2DA9;ETHIOPIC SYLLABLE CCU;Lo;0;L;;;;;N;;;;;\n2DAA;ETHIOPIC SYLLABLE CCI;Lo;0;L;;;;;N;;;;;\n2DAB;ETHIOPIC SYLLABLE CCAA;Lo;0;L;;;;;N;;;;;\n2DAC;ETHIOPIC SYLLABLE CCEE;Lo;0;L;;;;;N;;;;;\n2DAD;ETHIOPIC SYLLABLE CCE;Lo;0;L;;;;;N;;;;;\n2DAE;ETHIOPIC SYLLABLE CCO;Lo;0;L;;;;;N;;;;;\n2DB0;ETHIOPIC SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;\n2DB1;ETHIOPIC SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;\n2DB2;ETHIOPIC SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;\n2DB3;ETHIOPIC SYLLABLE ZZAA;Lo;0;L;;;;;N;;;;;\n2DB4;ETHIOPIC SYLLABLE ZZEE;Lo;0;L;;;;;N;;;;;\n2DB5;ETHIOPIC SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;\n2DB6;ETHIOPIC SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;\n2DB8;ETHIOPIC SYLLABLE CCHA;Lo;0;L;;;;;N;;;;;\n2DB9;ETHIOPIC SYLLABLE CCHU;Lo;0;L;;;;;N;;;;;\n2DBA;ETHIOPIC SYLLABLE CCHI;Lo;0;L;;;;;N;;;;;\n2DBB;ETHIOPIC SYLLABLE CCHAA;Lo;0;L;;;;;N;;;;;\n2DBC;ETHIOPIC SYLLABLE CCHEE;Lo;0;L;;;;;N;;;;;\n2DBD;ETHIOPIC SYLLABLE CCHE;Lo;0;L;;;;;N;;;;;\n2DBE;ETHIOPIC SYLLABLE CCHO;Lo;0;L;;;;;N;;;;;\n2DC0;ETHIOPIC SYLLABLE QYA;Lo;0;L;;;;;N;;;;;\n2DC1;ETHIOPIC SYLLABLE QYU;Lo;0;L;;;;;N;;;;;\n2DC2;ETHIOPIC SYLLABLE QYI;Lo;0;L;;;;;N;;;;;\n2DC3;ETHIOPIC SYLLABLE QYAA;Lo;0;L;;;;;N;;;;;\n2DC4;ETHIOPIC SYLLABLE QYEE;Lo;0;L;;;;;N;;;;;\n2DC5;ETHIOPIC SYLLABLE QYE;Lo;0;L;;;;;N;;;;;\n2DC6;ETHIOPIC SYLLABLE QYO;Lo;0;L;;;;;N;;;;;\n2DC8;ETHIOPIC SYLLABLE KYA;Lo;0;L;;;;;N;;;;;\n2DC9;ETHIOPIC SYLLABLE KYU;Lo;0;L;;;;;N;;;;;\n2DCA;ETHIOPIC SYLLABLE KYI;Lo;0;L;;;;;N;;;;;\n2DCB;ETHIOPIC SYLLABLE KYAA;Lo;0;L;;;;;N;;;;;\n2DCC;ETHIOPIC SYLLABLE KYEE;Lo;0;L;;;;;N;;;;;\n2DCD;ETHIOPIC SYLLABLE KYE;Lo;0;L;;;;;N;;;;;\n2DCE;ETHIOPIC SYLLABLE KYO;Lo;0;L;;;;;N;;;;;\n2DD0;ETHIOPIC SYLLABLE XYA;Lo;0;L;;;;;N;;;;;\n2DD1;ETHIOPIC SYLLABLE XYU;Lo;0;L;;;;;N;;;;;\n2DD2;ETHIOPIC SYLLABLE XYI;Lo;0;L;;;;;N;;;;;\n2DD3;ETHIOPIC SYLLABLE XYAA;Lo;0;L;;;;;N;;;;;\n2DD4;ETHIOPIC SYLLABLE XYEE;Lo;0;L;;;;;N;;;;;\n2DD5;ETHIOPIC SYLLABLE XYE;Lo;0;L;;;;;N;;;;;\n2DD6;ETHIOPIC SYLLABLE XYO;Lo;0;L;;;;;N;;;;;\n2DD8;ETHIOPIC SYLLABLE GYA;Lo;0;L;;;;;N;;;;;\n2DD9;ETHIOPIC SYLLABLE GYU;Lo;0;L;;;;;N;;;;;\n2DDA;ETHIOPIC SYLLABLE GYI;Lo;0;L;;;;;N;;;;;\n2DDB;ETHIOPIC SYLLABLE GYAA;Lo;0;L;;;;;N;;;;;\n2DDC;ETHIOPIC SYLLABLE GYEE;Lo;0;L;;;;;N;;;;;\n2DDD;ETHIOPIC SYLLABLE GYE;Lo;0;L;;;;;N;;;;;\n2DDE;ETHIOPIC SYLLABLE GYO;Lo;0;L;;;;;N;;;;;\n2DE0;COMBINING CYRILLIC LETTER BE;Mn;230;NSM;;;;;N;;;;;\n2DE1;COMBINING CYRILLIC LETTER VE;Mn;230;NSM;;;;;N;;;;;\n2DE2;COMBINING CYRILLIC LETTER GHE;Mn;230;NSM;;;;;N;;;;;\n2DE3;COMBINING CYRILLIC LETTER DE;Mn;230;NSM;;;;;N;;;;;\n2DE4;COMBINING CYRILLIC LETTER ZHE;Mn;230;NSM;;;;;N;;;;;\n2DE5;COMBINING CYRILLIC LETTER ZE;Mn;230;NSM;;;;;N;;;;;\n2DE6;COMBINING CYRILLIC LETTER KA;Mn;230;NSM;;;;;N;;;;;\n2DE7;COMBINING CYRILLIC LETTER EL;Mn;230;NSM;;;;;N;;;;;\n2DE8;COMBINING CYRILLIC LETTER EM;Mn;230;NSM;;;;;N;;;;;\n2DE9;COMBINING CYRILLIC LETTER EN;Mn;230;NSM;;;;;N;;;;;\n2DEA;COMBINING CYRILLIC LETTER O;Mn;230;NSM;;;;;N;;;;;\n2DEB;COMBINING CYRILLIC LETTER PE;Mn;230;NSM;;;;;N;;;;;\n2DEC;COMBINING CYRILLIC LETTER ER;Mn;230;NSM;;;;;N;;;;;\n2DED;COMBINING CYRILLIC LETTER ES;Mn;230;NSM;;;;;N;;;;;\n2DEE;COMBINING CYRILLIC LETTER TE;Mn;230;NSM;;;;;N;;;;;\n2DEF;COMBINING CYRILLIC LETTER HA;Mn;230;NSM;;;;;N;;;;;\n2DF0;COMBINING CYRILLIC LETTER TSE;Mn;230;NSM;;;;;N;;;;;\n2DF1;COMBINING CYRILLIC LETTER CHE;Mn;230;NSM;;;;;N;;;;;\n2DF2;COMBINING CYRILLIC LETTER SHA;Mn;230;NSM;;;;;N;;;;;\n2DF3;COMBINING CYRILLIC LETTER SHCHA;Mn;230;NSM;;;;;N;;;;;\n2DF4;COMBINING CYRILLIC LETTER FITA;Mn;230;NSM;;;;;N;;;;;\n2DF5;COMBINING CYRILLIC LETTER ES-TE;Mn;230;NSM;;;;;N;;;;;\n2DF6;COMBINING CYRILLIC LETTER A;Mn;230;NSM;;;;;N;;;;;\n2DF7;COMBINING CYRILLIC LETTER IE;Mn;230;NSM;;;;;N;;;;;\n2DF8;COMBINING CYRILLIC LETTER DJERV;Mn;230;NSM;;;;;N;;;;;\n2DF9;COMBINING CYRILLIC LETTER MONOGRAPH UK;Mn;230;NSM;;;;;N;;;;;\n2DFA;COMBINING CYRILLIC LETTER YAT;Mn;230;NSM;;;;;N;;;;;\n2DFB;COMBINING CYRILLIC LETTER YU;Mn;230;NSM;;;;;N;;;;;\n2DFC;COMBINING CYRILLIC LETTER IOTIFIED A;Mn;230;NSM;;;;;N;;;;;\n2DFD;COMBINING CYRILLIC LETTER LITTLE YUS;Mn;230;NSM;;;;;N;;;;;\n2DFE;COMBINING CYRILLIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;;\n2DFF;COMBINING CYRILLIC LETTER IOTIFIED BIG YUS;Mn;230;NSM;;;;;N;;;;;\n2E00;RIGHT ANGLE SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;;\n2E01;RIGHT ANGLE DOTTED SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;;\n2E02;LEFT SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;;\n2E03;RIGHT SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;;\n2E04;LEFT DOTTED SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;;\n2E05;RIGHT DOTTED SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;;\n2E06;RAISED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;;\n2E07;RAISED DOTTED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;;\n2E08;DOTTED TRANSPOSITION MARKER;Po;0;ON;;;;;N;;;;;\n2E09;LEFT TRANSPOSITION BRACKET;Pi;0;ON;;;;;Y;;;;;\n2E0A;RIGHT TRANSPOSITION BRACKET;Pf;0;ON;;;;;Y;;;;;\n2E0B;RAISED SQUARE;Po;0;ON;;;;;N;;;;;\n2E0C;LEFT RAISED OMISSION BRACKET;Pi;0;ON;;;;;Y;;;;;\n2E0D;RIGHT RAISED OMISSION BRACKET;Pf;0;ON;;;;;Y;;;;;\n2E0E;EDITORIAL CORONIS;Po;0;ON;;;;;N;;;;;\n2E0F;PARAGRAPHOS;Po;0;ON;;;;;N;;;;;\n2E10;FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;;\n2E11;REVERSED FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;;\n2E12;HYPODIASTOLE;Po;0;ON;;;;;N;;;;;\n2E13;DOTTED OBELOS;Po;0;ON;;;;;N;;;;;\n2E14;DOWNWARDS ANCORA;Po;0;ON;;;;;N;;;;;\n2E15;UPWARDS ANCORA;Po;0;ON;;;;;N;;;;;\n2E16;DOTTED RIGHT-POINTING ANGLE;Po;0;ON;;;;;N;;;;;\n2E17;DOUBLE OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;;\n2E18;INVERTED INTERROBANG;Po;0;ON;;;;;N;;;;;\n2E19;PALM BRANCH;Po;0;ON;;;;;N;;;;;\n2E1A;HYPHEN WITH DIAERESIS;Pd;0;ON;;;;;N;;;;;\n2E1B;TILDE WITH RING ABOVE;Po;0;ON;;;;;N;;;;;\n2E1C;LEFT LOW PARAPHRASE BRACKET;Pi;0;ON;;;;;Y;;;;;\n2E1D;RIGHT LOW PARAPHRASE BRACKET;Pf;0;ON;;;;;Y;;;;;\n2E1E;TILDE WITH DOT ABOVE;Po;0;ON;;;;;N;;;;;\n2E1F;TILDE WITH DOT BELOW;Po;0;ON;;;;;N;;;;;\n2E20;LEFT VERTICAL BAR WITH QUILL;Pi;0;ON;;;;;Y;;;;;\n2E21;RIGHT VERTICAL BAR WITH QUILL;Pf;0;ON;;;;;Y;;;;;\n2E22;TOP LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;;\n2E23;TOP RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;;\n2E24;BOTTOM LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;;\n2E25;BOTTOM RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;;\n2E26;LEFT SIDEWAYS U BRACKET;Ps;0;ON;;;;;Y;;;;;\n2E27;RIGHT SIDEWAYS U BRACKET;Pe;0;ON;;;;;Y;;;;;\n2E28;LEFT DOUBLE PARENTHESIS;Ps;0;ON;;;;;Y;;;;;\n2E29;RIGHT DOUBLE PARENTHESIS;Pe;0;ON;;;;;Y;;;;;\n2E2A;TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n2E2B;ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;;\n2E2C;SQUARED FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n2E2D;FIVE DOT MARK;Po;0;ON;;;;;N;;;;;\n2E2E;REVERSED QUESTION MARK;Po;0;ON;;;;;N;;;;;\n2E2F;VERTICAL TILDE;Lm;0;ON;;;;;N;;;;;\n2E30;RING POINT;Po;0;ON;;;;;N;;;;;\n2E31;WORD SEPARATOR MIDDLE DOT;Po;0;ON;;;;;N;;;;;\n2E32;TURNED COMMA;Po;0;ON;;;;;N;;;;;\n2E33;RAISED DOT;Po;0;ON;;;;;N;;;;;\n2E34;RAISED COMMA;Po;0;ON;;;;;N;;;;;\n2E35;TURNED SEMICOLON;Po;0;ON;;;;;N;;;;;\n2E36;DAGGER WITH LEFT GUARD;Po;0;ON;;;;;N;;;;;\n2E37;DAGGER WITH RIGHT GUARD;Po;0;ON;;;;;N;;;;;\n2E38;TURNED DAGGER;Po;0;ON;;;;;N;;;;;\n2E39;TOP HALF SECTION SIGN;Po;0;ON;;;;;N;;;;;\n2E3A;TWO-EM DASH;Pd;0;ON;;;;;N;;;;;\n2E3B;THREE-EM DASH;Pd;0;ON;;;;;N;;;;;\n2E3C;STENOGRAPHIC FULL STOP;Po;0;ON;;;;;N;;;;;\n2E3D;VERTICAL SIX DOTS;Po;0;ON;;;;;N;;;;;\n2E3E;WIGGLY VERTICAL LINE;Po;0;ON;;;;;N;;;;;\n2E3F;CAPITULUM;Po;0;ON;;;;;N;;;;;\n2E40;DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;;\n2E41;REVERSED COMMA;Po;0;ON;;;;;N;;;;;\n2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps;0;ON;;;;;N;;;;;\n2E43;DASH WITH LEFT UPTURN;Po;0;ON;;;;;N;;;;;\n2E44;DOUBLE SUSPENSION MARK;Po;0;ON;;;;;N;;;;;\n2E45;INVERTED LOW KAVYKA;Po;0;ON;;;;;N;;;;;\n2E46;INVERTED LOW KAVYKA WITH KAVYKA ABOVE;Po;0;ON;;;;;N;;;;;\n2E47;LOW KAVYKA;Po;0;ON;;;;;N;;;;;\n2E48;LOW KAVYKA WITH DOT;Po;0;ON;;;;;N;;;;;\n2E49;DOUBLE STACKED COMMA;Po;0;ON;;;;;N;;;;;\n2E4A;DOTTED SOLIDUS;Po;0;ON;;;;;N;;;;;\n2E4B;TRIPLE DAGGER;Po;0;ON;;;;;N;;;;;\n2E4C;MEDIEVAL COMMA;Po;0;ON;;;;;N;;;;;\n2E4D;PARAGRAPHUS MARK;Po;0;ON;;;;;N;;;;;\n2E4E;PUNCTUS ELEVATUS MARK;Po;0;ON;;;;;N;;;;;\n2E4F;CORNISH VERSE DIVIDER;Po;0;ON;;;;;N;;;;;\n2E50;CROSS PATTY WITH RIGHT CROSSBAR;So;0;ON;;;;;N;;;;;\n2E51;CROSS PATTY WITH LEFT CROSSBAR;So;0;ON;;;;;N;;;;;\n2E52;TIRONIAN SIGN CAPITAL ET;Po;0;ON;;;;;N;;;;;\n2E53;MEDIEVAL EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;\n2E54;MEDIEVAL QUESTION MARK;Po;0;ON;;;;;N;;;;;\n2E55;LEFT SQUARE BRACKET WITH STROKE;Ps;0;ON;;;;;Y;;;;;\n2E56;RIGHT SQUARE BRACKET WITH STROKE;Pe;0;ON;;;;;Y;;;;;\n2E57;LEFT SQUARE BRACKET WITH DOUBLE STROKE;Ps;0;ON;;;;;Y;;;;;\n2E58;RIGHT SQUARE BRACKET WITH DOUBLE STROKE;Pe;0;ON;;;;;Y;;;;;\n2E59;TOP HALF LEFT PARENTHESIS;Ps;0;ON;;;;;Y;;;;;\n2E5A;TOP HALF RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;;;;;\n2E5B;BOTTOM HALF LEFT PARENTHESIS;Ps;0;ON;;;;;Y;;;;;\n2E5C;BOTTOM HALF RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;;;;;\n2E5D;OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;;\n2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;;\n2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;;\n2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;;\n2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;;\n2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;;\n2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;;\n2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;;\n2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;;\n2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;;\n2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;;\n2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;;\n2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;;\n2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;;\n2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;;\n2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;;\n2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;;\n2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;;\n2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;;\n2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;;\n2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;;\n2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;;\n2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;;\n2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;;\n2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;;\n2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;;\n2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;;\n2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;;\n2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;;\n2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;;\n2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;;\n2E9F;CJK RADICAL MOTHER;So;0;ON;<compat> 6BCD;;;;N;;;;;\n2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;;\n2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;;\n2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;;\n2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;;\n2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;;\n2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;;\n2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;;\n2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;;\n2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;;\n2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;;\n2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;;\n2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;;\n2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;;\n2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;;\n2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;;\n2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;;\n2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;;\n2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;;\n2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;;\n2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;;\n2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;;\n2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;;\n2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;;\n2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;;\n2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;;\n2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;;\n2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;;\n2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;;\n2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;;\n2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;;\n2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;;\n2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;;\n2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;;\n2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;;\n2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;;\n2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;;\n2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;;\n2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;;\n2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;;\n2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;;\n2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;;\n2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;;\n2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;;\n2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;;\n2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;;\n2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;;\n2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;;\n2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;;\n2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;;\n2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;;\n2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;;\n2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;;\n2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;;\n2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;;\n2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;;\n2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;;\n2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;;\n2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;;\n2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;;\n2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;;\n2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;;\n2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;;\n2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;;\n2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;;\n2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;;\n2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;;\n2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;;\n2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;;\n2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;;\n2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;;\n2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;;\n2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;;\n2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;;\n2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;;\n2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;;\n2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;\n2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;\n2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;\n2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;\n2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;\n2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;\n2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;;\n2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;;\n2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON;<compat> 9F9F;;;;N;;;;;\n2F00;KANGXI RADICAL ONE;So;0;ON;<compat> 4E00;;;;N;;;;;\n2F01;KANGXI RADICAL LINE;So;0;ON;<compat> 4E28;;;;N;;;;;\n2F02;KANGXI RADICAL DOT;So;0;ON;<compat> 4E36;;;;N;;;;;\n2F03;KANGXI RADICAL SLASH;So;0;ON;<compat> 4E3F;;;;N;;;;;\n2F04;KANGXI RADICAL SECOND;So;0;ON;<compat> 4E59;;;;N;;;;;\n2F05;KANGXI RADICAL HOOK;So;0;ON;<compat> 4E85;;;;N;;;;;\n2F06;KANGXI RADICAL TWO;So;0;ON;<compat> 4E8C;;;;N;;;;;\n2F07;KANGXI RADICAL LID;So;0;ON;<compat> 4EA0;;;;N;;;;;\n2F08;KANGXI RADICAL MAN;So;0;ON;<compat> 4EBA;;;;N;;;;;\n2F09;KANGXI RADICAL LEGS;So;0;ON;<compat> 513F;;;;N;;;;;\n2F0A;KANGXI RADICAL ENTER;So;0;ON;<compat> 5165;;;;N;;;;;\n2F0B;KANGXI RADICAL EIGHT;So;0;ON;<compat> 516B;;;;N;;;;;\n2F0C;KANGXI RADICAL DOWN BOX;So;0;ON;<compat> 5182;;;;N;;;;;\n2F0D;KANGXI RADICAL COVER;So;0;ON;<compat> 5196;;;;N;;;;;\n2F0E;KANGXI RADICAL ICE;So;0;ON;<compat> 51AB;;;;N;;;;;\n2F0F;KANGXI RADICAL TABLE;So;0;ON;<compat> 51E0;;;;N;;;;;\n2F10;KANGXI RADICAL OPEN BOX;So;0;ON;<compat> 51F5;;;;N;;;;;\n2F11;KANGXI RADICAL KNIFE;So;0;ON;<compat> 5200;;;;N;;;;;\n2F12;KANGXI RADICAL POWER;So;0;ON;<compat> 529B;;;;N;;;;;\n2F13;KANGXI RADICAL WRAP;So;0;ON;<compat> 52F9;;;;N;;;;;\n2F14;KANGXI RADICAL SPOON;So;0;ON;<compat> 5315;;;;N;;;;;\n2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON;<compat> 531A;;;;N;;;;;\n2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON;<compat> 5338;;;;N;;;;;\n2F17;KANGXI RADICAL TEN;So;0;ON;<compat> 5341;;;;N;;;;;\n2F18;KANGXI RADICAL DIVINATION;So;0;ON;<compat> 535C;;;;N;;;;;\n2F19;KANGXI RADICAL SEAL;So;0;ON;<compat> 5369;;;;N;;;;;\n2F1A;KANGXI RADICAL CLIFF;So;0;ON;<compat> 5382;;;;N;;;;;\n2F1B;KANGXI RADICAL PRIVATE;So;0;ON;<compat> 53B6;;;;N;;;;;\n2F1C;KANGXI RADICAL AGAIN;So;0;ON;<compat> 53C8;;;;N;;;;;\n2F1D;KANGXI RADICAL MOUTH;So;0;ON;<compat> 53E3;;;;N;;;;;\n2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON;<compat> 56D7;;;;N;;;;;\n2F1F;KANGXI RADICAL EARTH;So;0;ON;<compat> 571F;;;;N;;;;;\n2F20;KANGXI RADICAL SCHOLAR;So;0;ON;<compat> 58EB;;;;N;;;;;\n2F21;KANGXI RADICAL GO;So;0;ON;<compat> 5902;;;;N;;;;;\n2F22;KANGXI RADICAL GO SLOWLY;So;0;ON;<compat> 590A;;;;N;;;;;\n2F23;KANGXI RADICAL EVENING;So;0;ON;<compat> 5915;;;;N;;;;;\n2F24;KANGXI RADICAL BIG;So;0;ON;<compat> 5927;;;;N;;;;;\n2F25;KANGXI RADICAL WOMAN;So;0;ON;<compat> 5973;;;;N;;;;;\n2F26;KANGXI RADICAL CHILD;So;0;ON;<compat> 5B50;;;;N;;;;;\n2F27;KANGXI RADICAL ROOF;So;0;ON;<compat> 5B80;;;;N;;;;;\n2F28;KANGXI RADICAL INCH;So;0;ON;<compat> 5BF8;;;;N;;;;;\n2F29;KANGXI RADICAL SMALL;So;0;ON;<compat> 5C0F;;;;N;;;;;\n2F2A;KANGXI RADICAL LAME;So;0;ON;<compat> 5C22;;;;N;;;;;\n2F2B;KANGXI RADICAL CORPSE;So;0;ON;<compat> 5C38;;;;N;;;;;\n2F2C;KANGXI RADICAL SPROUT;So;0;ON;<compat> 5C6E;;;;N;;;;;\n2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON;<compat> 5C71;;;;N;;;;;\n2F2E;KANGXI RADICAL RIVER;So;0;ON;<compat> 5DDB;;;;N;;;;;\n2F2F;KANGXI RADICAL WORK;So;0;ON;<compat> 5DE5;;;;N;;;;;\n2F30;KANGXI RADICAL ONESELF;So;0;ON;<compat> 5DF1;;;;N;;;;;\n2F31;KANGXI RADICAL TURBAN;So;0;ON;<compat> 5DFE;;;;N;;;;;\n2F32;KANGXI RADICAL DRY;So;0;ON;<compat> 5E72;;;;N;;;;;\n2F33;KANGXI RADICAL SHORT THREAD;So;0;ON;<compat> 5E7A;;;;N;;;;;\n2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON;<compat> 5E7F;;;;N;;;;;\n2F35;KANGXI RADICAL LONG STRIDE;So;0;ON;<compat> 5EF4;;;;N;;;;;\n2F36;KANGXI RADICAL TWO HANDS;So;0;ON;<compat> 5EFE;;;;N;;;;;\n2F37;KANGXI RADICAL SHOOT;So;0;ON;<compat> 5F0B;;;;N;;;;;\n2F38;KANGXI RADICAL BOW;So;0;ON;<compat> 5F13;;;;N;;;;;\n2F39;KANGXI RADICAL SNOUT;So;0;ON;<compat> 5F50;;;;N;;;;;\n2F3A;KANGXI RADICAL BRISTLE;So;0;ON;<compat> 5F61;;;;N;;;;;\n2F3B;KANGXI RADICAL STEP;So;0;ON;<compat> 5F73;;;;N;;;;;\n2F3C;KANGXI RADICAL HEART;So;0;ON;<compat> 5FC3;;;;N;;;;;\n2F3D;KANGXI RADICAL HALBERD;So;0;ON;<compat> 6208;;;;N;;;;;\n2F3E;KANGXI RADICAL DOOR;So;0;ON;<compat> 6236;;;;N;;;;;\n2F3F;KANGXI RADICAL HAND;So;0;ON;<compat> 624B;;;;N;;;;;\n2F40;KANGXI RADICAL BRANCH;So;0;ON;<compat> 652F;;;;N;;;;;\n2F41;KANGXI RADICAL RAP;So;0;ON;<compat> 6534;;;;N;;;;;\n2F42;KANGXI RADICAL SCRIPT;So;0;ON;<compat> 6587;;;;N;;;;;\n2F43;KANGXI RADICAL DIPPER;So;0;ON;<compat> 6597;;;;N;;;;;\n2F44;KANGXI RADICAL AXE;So;0;ON;<compat> 65A4;;;;N;;;;;\n2F45;KANGXI RADICAL SQUARE;So;0;ON;<compat> 65B9;;;;N;;;;;\n2F46;KANGXI RADICAL NOT;So;0;ON;<compat> 65E0;;;;N;;;;;\n2F47;KANGXI RADICAL SUN;So;0;ON;<compat> 65E5;;;;N;;;;;\n2F48;KANGXI RADICAL SAY;So;0;ON;<compat> 66F0;;;;N;;;;;\n2F49;KANGXI RADICAL MOON;So;0;ON;<compat> 6708;;;;N;;;;;\n2F4A;KANGXI RADICAL TREE;So;0;ON;<compat> 6728;;;;N;;;;;\n2F4B;KANGXI RADICAL LACK;So;0;ON;<compat> 6B20;;;;N;;;;;\n2F4C;KANGXI RADICAL STOP;So;0;ON;<compat> 6B62;;;;N;;;;;\n2F4D;KANGXI RADICAL DEATH;So;0;ON;<compat> 6B79;;;;N;;;;;\n2F4E;KANGXI RADICAL WEAPON;So;0;ON;<compat> 6BB3;;;;N;;;;;\n2F4F;KANGXI RADICAL DO NOT;So;0;ON;<compat> 6BCB;;;;N;;;;;\n2F50;KANGXI RADICAL COMPARE;So;0;ON;<compat> 6BD4;;;;N;;;;;\n2F51;KANGXI RADICAL FUR;So;0;ON;<compat> 6BDB;;;;N;;;;;\n2F52;KANGXI RADICAL CLAN;So;0;ON;<compat> 6C0F;;;;N;;;;;\n2F53;KANGXI RADICAL STEAM;So;0;ON;<compat> 6C14;;;;N;;;;;\n2F54;KANGXI RADICAL WATER;So;0;ON;<compat> 6C34;;;;N;;;;;\n2F55;KANGXI RADICAL FIRE;So;0;ON;<compat> 706B;;;;N;;;;;\n2F56;KANGXI RADICAL CLAW;So;0;ON;<compat> 722A;;;;N;;;;;\n2F57;KANGXI RADICAL FATHER;So;0;ON;<compat> 7236;;;;N;;;;;\n2F58;KANGXI RADICAL DOUBLE X;So;0;ON;<compat> 723B;;;;N;;;;;\n2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON;<compat> 723F;;;;N;;;;;\n2F5A;KANGXI RADICAL SLICE;So;0;ON;<compat> 7247;;;;N;;;;;\n2F5B;KANGXI RADICAL FANG;So;0;ON;<compat> 7259;;;;N;;;;;\n2F5C;KANGXI RADICAL COW;So;0;ON;<compat> 725B;;;;N;;;;;\n2F5D;KANGXI RADICAL DOG;So;0;ON;<compat> 72AC;;;;N;;;;;\n2F5E;KANGXI RADICAL PROFOUND;So;0;ON;<compat> 7384;;;;N;;;;;\n2F5F;KANGXI RADICAL JADE;So;0;ON;<compat> 7389;;;;N;;;;;\n2F60;KANGXI RADICAL MELON;So;0;ON;<compat> 74DC;;;;N;;;;;\n2F61;KANGXI RADICAL TILE;So;0;ON;<compat> 74E6;;;;N;;;;;\n2F62;KANGXI RADICAL SWEET;So;0;ON;<compat> 7518;;;;N;;;;;\n2F63;KANGXI RADICAL LIFE;So;0;ON;<compat> 751F;;;;N;;;;;\n2F64;KANGXI RADICAL USE;So;0;ON;<compat> 7528;;;;N;;;;;\n2F65;KANGXI RADICAL FIELD;So;0;ON;<compat> 7530;;;;N;;;;;\n2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON;<compat> 758B;;;;N;;;;;\n2F67;KANGXI RADICAL SICKNESS;So;0;ON;<compat> 7592;;;;N;;;;;\n2F68;KANGXI RADICAL DOTTED TENT;So;0;ON;<compat> 7676;;;;N;;;;;\n2F69;KANGXI RADICAL WHITE;So;0;ON;<compat> 767D;;;;N;;;;;\n2F6A;KANGXI RADICAL SKIN;So;0;ON;<compat> 76AE;;;;N;;;;;\n2F6B;KANGXI RADICAL DISH;So;0;ON;<compat> 76BF;;;;N;;;;;\n2F6C;KANGXI RADICAL EYE;So;0;ON;<compat> 76EE;;;;N;;;;;\n2F6D;KANGXI RADICAL SPEAR;So;0;ON;<compat> 77DB;;;;N;;;;;\n2F6E;KANGXI RADICAL ARROW;So;0;ON;<compat> 77E2;;;;N;;;;;\n2F6F;KANGXI RADICAL STONE;So;0;ON;<compat> 77F3;;;;N;;;;;\n2F70;KANGXI RADICAL SPIRIT;So;0;ON;<compat> 793A;;;;N;;;;;\n2F71;KANGXI RADICAL TRACK;So;0;ON;<compat> 79B8;;;;N;;;;;\n2F72;KANGXI RADICAL GRAIN;So;0;ON;<compat> 79BE;;;;N;;;;;\n2F73;KANGXI RADICAL CAVE;So;0;ON;<compat> 7A74;;;;N;;;;;\n2F74;KANGXI RADICAL STAND;So;0;ON;<compat> 7ACB;;;;N;;;;;\n2F75;KANGXI RADICAL BAMBOO;So;0;ON;<compat> 7AF9;;;;N;;;;;\n2F76;KANGXI RADICAL RICE;So;0;ON;<compat> 7C73;;;;N;;;;;\n2F77;KANGXI RADICAL SILK;So;0;ON;<compat> 7CF8;;;;N;;;;;\n2F78;KANGXI RADICAL JAR;So;0;ON;<compat> 7F36;;;;N;;;;;\n2F79;KANGXI RADICAL NET;So;0;ON;<compat> 7F51;;;;N;;;;;\n2F7A;KANGXI RADICAL SHEEP;So;0;ON;<compat> 7F8A;;;;N;;;;;\n2F7B;KANGXI RADICAL FEATHER;So;0;ON;<compat> 7FBD;;;;N;;;;;\n2F7C;KANGXI RADICAL OLD;So;0;ON;<compat> 8001;;;;N;;;;;\n2F7D;KANGXI RADICAL AND;So;0;ON;<compat> 800C;;;;N;;;;;\n2F7E;KANGXI RADICAL PLOW;So;0;ON;<compat> 8012;;;;N;;;;;\n2F7F;KANGXI RADICAL EAR;So;0;ON;<compat> 8033;;;;N;;;;;\n2F80;KANGXI RADICAL BRUSH;So;0;ON;<compat> 807F;;;;N;;;;;\n2F81;KANGXI RADICAL MEAT;So;0;ON;<compat> 8089;;;;N;;;;;\n2F82;KANGXI RADICAL MINISTER;So;0;ON;<compat> 81E3;;;;N;;;;;\n2F83;KANGXI RADICAL SELF;So;0;ON;<compat> 81EA;;;;N;;;;;\n2F84;KANGXI RADICAL ARRIVE;So;0;ON;<compat> 81F3;;;;N;;;;;\n2F85;KANGXI RADICAL MORTAR;So;0;ON;<compat> 81FC;;;;N;;;;;\n2F86;KANGXI RADICAL TONGUE;So;0;ON;<compat> 820C;;;;N;;;;;\n2F87;KANGXI RADICAL OPPOSE;So;0;ON;<compat> 821B;;;;N;;;;;\n2F88;KANGXI RADICAL BOAT;So;0;ON;<compat> 821F;;;;N;;;;;\n2F89;KANGXI RADICAL STOPPING;So;0;ON;<compat> 826E;;;;N;;;;;\n2F8A;KANGXI RADICAL COLOR;So;0;ON;<compat> 8272;;;;N;;;;;\n2F8B;KANGXI RADICAL GRASS;So;0;ON;<compat> 8278;;;;N;;;;;\n2F8C;KANGXI RADICAL TIGER;So;0;ON;<compat> 864D;;;;N;;;;;\n2F8D;KANGXI RADICAL INSECT;So;0;ON;<compat> 866B;;;;N;;;;;\n2F8E;KANGXI RADICAL BLOOD;So;0;ON;<compat> 8840;;;;N;;;;;\n2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON;<compat> 884C;;;;N;;;;;\n2F90;KANGXI RADICAL CLOTHES;So;0;ON;<compat> 8863;;;;N;;;;;\n2F91;KANGXI RADICAL WEST;So;0;ON;<compat> 897E;;;;N;;;;;\n2F92;KANGXI RADICAL SEE;So;0;ON;<compat> 898B;;;;N;;;;;\n2F93;KANGXI RADICAL HORN;So;0;ON;<compat> 89D2;;;;N;;;;;\n2F94;KANGXI RADICAL SPEECH;So;0;ON;<compat> 8A00;;;;N;;;;;\n2F95;KANGXI RADICAL VALLEY;So;0;ON;<compat> 8C37;;;;N;;;;;\n2F96;KANGXI RADICAL BEAN;So;0;ON;<compat> 8C46;;;;N;;;;;\n2F97;KANGXI RADICAL PIG;So;0;ON;<compat> 8C55;;;;N;;;;;\n2F98;KANGXI RADICAL BADGER;So;0;ON;<compat> 8C78;;;;N;;;;;\n2F99;KANGXI RADICAL SHELL;So;0;ON;<compat> 8C9D;;;;N;;;;;\n2F9A;KANGXI RADICAL RED;So;0;ON;<compat> 8D64;;;;N;;;;;\n2F9B;KANGXI RADICAL RUN;So;0;ON;<compat> 8D70;;;;N;;;;;\n2F9C;KANGXI RADICAL FOOT;So;0;ON;<compat> 8DB3;;;;N;;;;;\n2F9D;KANGXI RADICAL BODY;So;0;ON;<compat> 8EAB;;;;N;;;;;\n2F9E;KANGXI RADICAL CART;So;0;ON;<compat> 8ECA;;;;N;;;;;\n2F9F;KANGXI RADICAL BITTER;So;0;ON;<compat> 8F9B;;;;N;;;;;\n2FA0;KANGXI RADICAL MORNING;So;0;ON;<compat> 8FB0;;;;N;;;;;\n2FA1;KANGXI RADICAL WALK;So;0;ON;<compat> 8FB5;;;;N;;;;;\n2FA2;KANGXI RADICAL CITY;So;0;ON;<compat> 9091;;;;N;;;;;\n2FA3;KANGXI RADICAL WINE;So;0;ON;<compat> 9149;;;;N;;;;;\n2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON;<compat> 91C6;;;;N;;;;;\n2FA5;KANGXI RADICAL VILLAGE;So;0;ON;<compat> 91CC;;;;N;;;;;\n2FA6;KANGXI RADICAL GOLD;So;0;ON;<compat> 91D1;;;;N;;;;;\n2FA7;KANGXI RADICAL LONG;So;0;ON;<compat> 9577;;;;N;;;;;\n2FA8;KANGXI RADICAL GATE;So;0;ON;<compat> 9580;;;;N;;;;;\n2FA9;KANGXI RADICAL MOUND;So;0;ON;<compat> 961C;;;;N;;;;;\n2FAA;KANGXI RADICAL SLAVE;So;0;ON;<compat> 96B6;;;;N;;;;;\n2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON;<compat> 96B9;;;;N;;;;;\n2FAC;KANGXI RADICAL RAIN;So;0;ON;<compat> 96E8;;;;N;;;;;\n2FAD;KANGXI RADICAL BLUE;So;0;ON;<compat> 9751;;;;N;;;;;\n2FAE;KANGXI RADICAL WRONG;So;0;ON;<compat> 975E;;;;N;;;;;\n2FAF;KANGXI RADICAL FACE;So;0;ON;<compat> 9762;;;;N;;;;;\n2FB0;KANGXI RADICAL LEATHER;So;0;ON;<compat> 9769;;;;N;;;;;\n2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON;<compat> 97CB;;;;N;;;;;\n2FB2;KANGXI RADICAL LEEK;So;0;ON;<compat> 97ED;;;;N;;;;;\n2FB3;KANGXI RADICAL SOUND;So;0;ON;<compat> 97F3;;;;N;;;;;\n2FB4;KANGXI RADICAL LEAF;So;0;ON;<compat> 9801;;;;N;;;;;\n2FB5;KANGXI RADICAL WIND;So;0;ON;<compat> 98A8;;;;N;;;;;\n2FB6;KANGXI RADICAL FLY;So;0;ON;<compat> 98DB;;;;N;;;;;\n2FB7;KANGXI RADICAL EAT;So;0;ON;<compat> 98DF;;;;N;;;;;\n2FB8;KANGXI RADICAL HEAD;So;0;ON;<compat> 9996;;;;N;;;;;\n2FB9;KANGXI RADICAL FRAGRANT;So;0;ON;<compat> 9999;;;;N;;;;;\n2FBA;KANGXI RADICAL HORSE;So;0;ON;<compat> 99AC;;;;N;;;;;\n2FBB;KANGXI RADICAL BONE;So;0;ON;<compat> 9AA8;;;;N;;;;;\n2FBC;KANGXI RADICAL TALL;So;0;ON;<compat> 9AD8;;;;N;;;;;\n2FBD;KANGXI RADICAL HAIR;So;0;ON;<compat> 9ADF;;;;N;;;;;\n2FBE;KANGXI RADICAL FIGHT;So;0;ON;<compat> 9B25;;;;N;;;;;\n2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON;<compat> 9B2F;;;;N;;;;;\n2FC0;KANGXI RADICAL CAULDRON;So;0;ON;<compat> 9B32;;;;N;;;;;\n2FC1;KANGXI RADICAL GHOST;So;0;ON;<compat> 9B3C;;;;N;;;;;\n2FC2;KANGXI RADICAL FISH;So;0;ON;<compat> 9B5A;;;;N;;;;;\n2FC3;KANGXI RADICAL BIRD;So;0;ON;<compat> 9CE5;;;;N;;;;;\n2FC4;KANGXI RADICAL SALT;So;0;ON;<compat> 9E75;;;;N;;;;;\n2FC5;KANGXI RADICAL DEER;So;0;ON;<compat> 9E7F;;;;N;;;;;\n2FC6;KANGXI RADICAL WHEAT;So;0;ON;<compat> 9EA5;;;;N;;;;;\n2FC7;KANGXI RADICAL HEMP;So;0;ON;<compat> 9EBB;;;;N;;;;;\n2FC8;KANGXI RADICAL YELLOW;So;0;ON;<compat> 9EC3;;;;N;;;;;\n2FC9;KANGXI RADICAL MILLET;So;0;ON;<compat> 9ECD;;;;N;;;;;\n2FCA;KANGXI RADICAL BLACK;So;0;ON;<compat> 9ED1;;;;N;;;;;\n2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON;<compat> 9EF9;;;;N;;;;;\n2FCC;KANGXI RADICAL FROG;So;0;ON;<compat> 9EFD;;;;N;;;;;\n2FCD;KANGXI RADICAL TRIPOD;So;0;ON;<compat> 9F0E;;;;N;;;;;\n2FCE;KANGXI RADICAL DRUM;So;0;ON;<compat> 9F13;;;;N;;;;;\n2FCF;KANGXI RADICAL RAT;So;0;ON;<compat> 9F20;;;;N;;;;;\n2FD0;KANGXI RADICAL NOSE;So;0;ON;<compat> 9F3B;;;;N;;;;;\n2FD1;KANGXI RADICAL EVEN;So;0;ON;<compat> 9F4A;;;;N;;;;;\n2FD2;KANGXI RADICAL TOOTH;So;0;ON;<compat> 9F52;;;;N;;;;;\n2FD3;KANGXI RADICAL DRAGON;So;0;ON;<compat> 9F8D;;;;N;;;;;\n2FD4;KANGXI RADICAL TURTLE;So;0;ON;<compat> 9F9C;;;;N;;;;;\n2FD5;KANGXI RADICAL FLUTE;So;0;ON;<compat> 9FA0;;;;N;;;;;\n2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;;\n2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;;\n2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;;\n2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;;\n2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;;\n2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;;\n2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;;\n2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;;\n2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;;\n2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;;\n2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;;\n2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;;\n2FFC;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM RIGHT;So;0;ON;;;;;N;;;;;\n2FFD;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER RIGHT;So;0;ON;;;;;N;;;;;\n2FFE;IDEOGRAPHIC DESCRIPTION CHARACTER HORIZONTAL REFLECTION;So;0;ON;;;;;N;;;;;\n2FFF;IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION;So;0;ON;;;;;N;;;;;\n3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;\n3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;;\n3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;;\n3003;DITTO MARK;Po;0;ON;;;;;N;;;;;\n3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;;\n3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;\n3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;;\n3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;;\n3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;;\n3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;;\n300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;;\n300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;;\n300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;;\n300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;;\n300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;;\n300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;;\n3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;;\n3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;;\n3012;POSTAL MARK;So;0;ON;;;;;N;;;;;\n3013;GETA MARK;So;0;ON;;;;;N;;;;;\n3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;;\n3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;;\n3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;;\n3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;;\n3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;;\n3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;;\n301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;;\n301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;;\n301C;WAVE DASH;Pd;0;ON;;;;;N;;;;;\n301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;;\n301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;\n301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;\n3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;;\n3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;;\n3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;;\n3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;;\n3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;;\n3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;;\n3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;;\n3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;;\n3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;;\n3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;;\n302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;;\n302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;;\n302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;;\n302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;;\n302E;HANGUL SINGLE DOT TONE MARK;Mc;224;L;;;;;N;;;;;\n302F;HANGUL DOUBLE DOT TONE MARK;Mc;224;L;;;;;N;;;;;\n3030;WAVY DASH;Pd;0;ON;;;;;N;;;;;\n3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;;\n3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;;\n3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;;\n3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;;\n3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;;\n3036;CIRCLED POSTAL MARK;So;0;ON;<compat> 3012;;;;N;;;;;\n3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;;\n3038;HANGZHOU NUMERAL TEN;Nl;0;L;<compat> 5341;;;10;N;;;;;\n3039;HANGZHOU NUMERAL TWENTY;Nl;0;L;<compat> 5344;;;20;N;;;;;\n303A;HANGZHOU NUMERAL THIRTY;Nl;0;L;<compat> 5345;;;30;N;;;;;\n303B;VERTICAL IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;\n303C;MASU MARK;Lo;0;L;;;;;N;;;;;\n303D;PART ALTERNATION MARK;Po;0;ON;;;;;N;;;;;\n303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;;\n303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;;\n3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;\n3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;;\n3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;\n3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;;\n3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;\n3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;;\n3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;\n3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;;\n3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;\n304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;;\n304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;;\n304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;;\n304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;;\n304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;;\n304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;;\n3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;;\n3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;;\n3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;;\n3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;;\n3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;;\n3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;;\n3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;;\n3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;;\n3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;;\n3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;;\n305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;;\n305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;;\n305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;;\n305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;;\n305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;;\n305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;;\n3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;;\n3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;;\n3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;;\n3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;\n3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;;\n3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;;\n3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;;\n3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;;\n3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;;\n3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;;\n306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;;\n306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;;\n306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;;\n306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;;\n306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;;\n306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;;\n3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;;\n3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;;\n3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;;\n3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;;\n3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;;\n3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;;\n3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;;\n3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;;\n3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;;\n3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;;\n307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;;\n307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;;\n307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;;\n307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;;\n307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;;\n307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;;\n3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;;\n3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;;\n3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;;\n3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;\n3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;;\n3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;\n3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;;\n3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;\n3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;;\n3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;;\n308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;;\n308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;;\n308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;;\n308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;;\n308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;\n308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;;\n3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;;\n3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;;\n3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;;\n3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;;\n3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;;\n3095;HIRAGANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;\n3096;HIRAGANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;\n3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;;\n309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;;\n309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON;<compat> 0020 3099;;;;N;;;;;\n309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON;<compat> 0020 309A;;;;N;;;;;\n309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;;\n309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;;\n309F;HIRAGANA DIGRAPH YORI;Lo;0;L;<vertical> 3088 308A;;;;N;;;;;\n30A0;KATAKANA-HIRAGANA DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;;\n30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;\n30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;;\n30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;\n30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;;\n30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;\n30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;;\n30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;\n30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;;\n30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;\n30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;;\n30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;;\n30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;;\n30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;;\n30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;;\n30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;;\n30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;;\n30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;;\n30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;;\n30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;;\n30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;;\n30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;;\n30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;;\n30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;;\n30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;;\n30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;;\n30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;;\n30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;;\n30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;;\n30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;;\n30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;;\n30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;;\n30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;;\n30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;;\n30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;;\n30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;\n30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;;\n30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;;\n30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;;\n30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;;\n30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;;\n30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;;\n30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;;\n30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;;\n30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;;\n30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;;\n30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;;\n30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;;\n30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;;\n30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;;\n30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;;\n30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;;\n30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;;\n30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;;\n30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;;\n30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;;\n30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;;\n30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;;\n30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;;\n30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;;\n30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;;\n30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;;\n30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;;\n30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;;\n30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;;\n30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;;\n30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;;\n30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;\n30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;;\n30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;\n30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;;\n30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;\n30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;;\n30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;;\n30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;;\n30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;;\n30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;;\n30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;;\n30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;\n30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;;\n30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;;\n30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;;\n30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;;\n30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;;\n30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;;\n30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;\n30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;\n30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;;\n30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;;\n30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;;\n30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;;\n30FB;KATAKANA MIDDLE DOT;Po;0;ON;;;;;N;;;;;\n30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;;\n30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;;\n30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;;\n30FF;KATAKANA DIGRAPH KOTO;Lo;0;L;<vertical> 30B3 30C8;;;;N;;;;;\n3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;;\n3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;;\n3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;;\n3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;;\n3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;;\n310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;;\n310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;;\n310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;;\n310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;;\n310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;;\n310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;;\n3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;;\n3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;;\n3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;;\n3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;;\n3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;;\n3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;;\n3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;;\n3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;;\n3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;;\n3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;;\n311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;;\n311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;;\n311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;;\n311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;;\n311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;;\n311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;;\n3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;;\n3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;;\n3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;;\n3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;;\n3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;;\n3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;;\n3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;;\n3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;;\n3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;;\n3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;;\n312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;;\n312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;;\n312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;;\n312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;;\n312E;BOPOMOFO LETTER O WITH DOT ABOVE;Lo;0;L;;;;;N;;;;;\n312F;BOPOMOFO LETTER NN;Lo;0;L;;;;;N;;;;;\n3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;;\n3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;;\n3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;\n3134;HANGUL LETTER NIEUN;Lo;0;L;<compat> 1102;;;;N;;;;;\n3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<compat> 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;;\n3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<compat> 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;;\n3137;HANGUL LETTER TIKEUT;Lo;0;L;<compat> 1103;;;;N;HANGUL LETTER DIGEUD;;;;\n3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L;<compat> 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;;\n3139;HANGUL LETTER RIEUL;Lo;0;L;<compat> 1105;;;;N;HANGUL LETTER LIEUL;;;;\n313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<compat> 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;;\n313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<compat> 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;;\n313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<compat> 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;;\n313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L;<compat> 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;;\n313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<compat> 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;;\n313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<compat> 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;;\n3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<compat> 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;;\n3141;HANGUL LETTER MIEUM;Lo;0;L;<compat> 1106;;;;N;;;;;\n3142;HANGUL LETTER PIEUP;Lo;0;L;<compat> 1107;;;;N;HANGUL LETTER BIEUB;;;;\n3143;HANGUL LETTER SSANGPIEUP;Lo;0;L;<compat> 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;;\n3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L;<compat> 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;;\n3145;HANGUL LETTER SIOS;Lo;0;L;<compat> 1109;;;;N;;;;;\n3146;HANGUL LETTER SSANGSIOS;Lo;0;L;<compat> 110A;;;;N;HANGUL LETTER SSANG SIOS;;;;\n3147;HANGUL LETTER IEUNG;Lo;0;L;<compat> 110B;;;;N;;;;;\n3148;HANGUL LETTER CIEUC;Lo;0;L;<compat> 110C;;;;N;HANGUL LETTER JIEUJ;;;;\n3149;HANGUL LETTER SSANGCIEUC;Lo;0;L;<compat> 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;;\n314A;HANGUL LETTER CHIEUCH;Lo;0;L;<compat> 110E;;;;N;HANGUL LETTER CIEUC;;;;\n314B;HANGUL LETTER KHIEUKH;Lo;0;L;<compat> 110F;;;;N;HANGUL LETTER KIYEOK;;;;\n314C;HANGUL LETTER THIEUTH;Lo;0;L;<compat> 1110;;;;N;HANGUL LETTER TIEUT;;;;\n314D;HANGUL LETTER PHIEUPH;Lo;0;L;<compat> 1111;;;;N;HANGUL LETTER PIEUP;;;;\n314E;HANGUL LETTER HIEUH;Lo;0;L;<compat> 1112;;;;N;;;;;\n314F;HANGUL LETTER A;Lo;0;L;<compat> 1161;;;;N;;;;;\n3150;HANGUL LETTER AE;Lo;0;L;<compat> 1162;;;;N;;;;;\n3151;HANGUL LETTER YA;Lo;0;L;<compat> 1163;;;;N;;;;;\n3152;HANGUL LETTER YAE;Lo;0;L;<compat> 1164;;;;N;;;;;\n3153;HANGUL LETTER EO;Lo;0;L;<compat> 1165;;;;N;;;;;\n3154;HANGUL LETTER E;Lo;0;L;<compat> 1166;;;;N;;;;;\n3155;HANGUL LETTER YEO;Lo;0;L;<compat> 1167;;;;N;;;;;\n3156;HANGUL LETTER YE;Lo;0;L;<compat> 1168;;;;N;;;;;\n3157;HANGUL LETTER O;Lo;0;L;<compat> 1169;;;;N;;;;;\n3158;HANGUL LETTER WA;Lo;0;L;<compat> 116A;;;;N;;;;;\n3159;HANGUL LETTER WAE;Lo;0;L;<compat> 116B;;;;N;;;;;\n315A;HANGUL LETTER OE;Lo;0;L;<compat> 116C;;;;N;;;;;\n315B;HANGUL LETTER YO;Lo;0;L;<compat> 116D;;;;N;;;;;\n315C;HANGUL LETTER U;Lo;0;L;<compat> 116E;;;;N;;;;;\n315D;HANGUL LETTER WEO;Lo;0;L;<compat> 116F;;;;N;;;;;\n315E;HANGUL LETTER WE;Lo;0;L;<compat> 1170;;;;N;;;;;\n315F;HANGUL LETTER WI;Lo;0;L;<compat> 1171;;;;N;;;;;\n3160;HANGUL LETTER YU;Lo;0;L;<compat> 1172;;;;N;;;;;\n3161;HANGUL LETTER EU;Lo;0;L;<compat> 1173;;;;N;;;;;\n3162;HANGUL LETTER YI;Lo;0;L;<compat> 1174;;;;N;;;;;\n3163;HANGUL LETTER I;Lo;0;L;<compat> 1175;;;;N;;;;;\n3164;HANGUL FILLER;Lo;0;L;<compat> 1160;;;;N;HANGUL CAE OM;;;;\n3165;HANGUL LETTER SSANGNIEUN;Lo;0;L;<compat> 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;;\n3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L;<compat> 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;;\n3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L;<compat> 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;;\n3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L;<compat> 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;;\n3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L;<compat> 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;;\n316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L;<compat> 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;;\n316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L;<compat> 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;;\n316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L;<compat> 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;;\n316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L;<compat> 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;;\n316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L;<compat> 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;;\n316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L;<compat> 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;;\n3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L;<compat> 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;;\n3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L;<compat> 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;;\n3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L;<compat> 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;;\n3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L;<compat> 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;;\n3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L;<compat> 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;;\n3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L;<compat> 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;;\n3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L;<compat> 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;;\n3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L;<compat> 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;;\n3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L;<compat> 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;;\n3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L;<compat> 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;;\n317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L;<compat> 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;;\n317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L;<compat> 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;;\n317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L;<compat> 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;;\n317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L;<compat> 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;;\n317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L;<compat> 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;;\n317F;HANGUL LETTER PANSIOS;Lo;0;L;<compat> 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;;\n3180;HANGUL LETTER SSANGIEUNG;Lo;0;L;<compat> 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;;\n3181;HANGUL LETTER YESIEUNG;Lo;0;L;<compat> 114C;;;;N;HANGUL LETTER NGIEUNG;;;;\n3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L;<compat> 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;;\n3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L;<compat> 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;;\n3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L;<compat> 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;;\n3185;HANGUL LETTER SSANGHIEUH;Lo;0;L;<compat> 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;;\n3186;HANGUL LETTER YEORINHIEUH;Lo;0;L;<compat> 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;;\n3187;HANGUL LETTER YO-YA;Lo;0;L;<compat> 1184;;;;N;HANGUL LETTER YOYA;;;;\n3188;HANGUL LETTER YO-YAE;Lo;0;L;<compat> 1185;;;;N;HANGUL LETTER YOYAE;;;;\n3189;HANGUL LETTER YO-I;Lo;0;L;<compat> 1188;;;;N;HANGUL LETTER YOI;;;;\n318A;HANGUL LETTER YU-YEO;Lo;0;L;<compat> 1191;;;;N;HANGUL LETTER YUYEO;;;;\n318B;HANGUL LETTER YU-YE;Lo;0;L;<compat> 1192;;;;N;HANGUL LETTER YUYE;;;;\n318C;HANGUL LETTER YU-I;Lo;0;L;<compat> 1194;;;;N;HANGUL LETTER YUI;;;;\n318D;HANGUL LETTER ARAEA;Lo;0;L;<compat> 119E;;;;N;HANGUL LETTER ALAE A;;;;\n318E;HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;;\n3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;;;;\n3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;;;;\n3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L;<super> 4E00;;;1;N;KAERITEN ITI;;;;\n3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L;<super> 4E8C;;;2;N;KAERITEN NI;;;;\n3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L;<super> 4E09;;;3;N;KAERITEN SAN;;;;\n3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L;<super> 56DB;;;4;N;KAERITEN SI;;;;\n3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L;<super> 4E0A;;;;N;KAERITEN ZYOU;;;;\n3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L;<super> 4E2D;;;;N;KAERITEN TYUU;;;;\n3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L;<super> 4E0B;;;;N;KAERITEN GE;;;;\n3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L;<super> 7532;;;;N;KAERITEN KOU;;;;\n319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L;<super> 4E59;;;;N;KAERITEN OTU;;;;\n319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L;<super> 4E19;;;;N;KAERITEN HEI;;;;\n319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L;<super> 4E01;;;;N;KAERITEN TEI;;;;\n319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L;<super> 5929;;;;N;KAERITEN TEN;;;;\n319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L;<super> 5730;;;;N;KAERITEN TI;;;;\n319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L;<super> 4EBA;;;;N;KAERITEN ZIN;;;;\n31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;;\n31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;;\n31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;;\n31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;;\n31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;;\n31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;;\n31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;;\n31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;;\n31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;;\n31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;;\n31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;;\n31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;;\n31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;;\n31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;;\n31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;;\n31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;;\n31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;;\n31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;;\n31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;;\n31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;;\n31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;;\n31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;;\n31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;;\n31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;;\n31B8;BOPOMOFO LETTER GH;Lo;0;L;;;;;N;;;;;\n31B9;BOPOMOFO LETTER LH;Lo;0;L;;;;;N;;;;;\n31BA;BOPOMOFO LETTER ZY;Lo;0;L;;;;;N;;;;;\n31BB;BOPOMOFO FINAL LETTER G;Lo;0;L;;;;;N;;;;;\n31BC;BOPOMOFO LETTER GW;Lo;0;L;;;;;N;;;;;\n31BD;BOPOMOFO LETTER KW;Lo;0;L;;;;;N;;;;;\n31BE;BOPOMOFO LETTER OE;Lo;0;L;;;;;N;;;;;\n31BF;BOPOMOFO LETTER AH;Lo;0;L;;;;;N;;;;;\n31C0;CJK STROKE T;So;0;ON;;;;;N;;;;;\n31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;;\n31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;;\n31C3;CJK STROKE BXG;So;0;ON;;;;;N;;;;;\n31C4;CJK STROKE SW;So;0;ON;;;;;N;;;;;\n31C5;CJK STROKE HZZ;So;0;ON;;;;;N;;;;;\n31C6;CJK STROKE HZG;So;0;ON;;;;;N;;;;;\n31C7;CJK STROKE HP;So;0;ON;;;;;N;;;;;\n31C8;CJK STROKE HZWG;So;0;ON;;;;;N;;;;;\n31C9;CJK STROKE SZWG;So;0;ON;;;;;N;;;;;\n31CA;CJK STROKE HZT;So;0;ON;;;;;N;;;;;\n31CB;CJK STROKE HZZP;So;0;ON;;;;;N;;;;;\n31CC;CJK STROKE HPWG;So;0;ON;;;;;N;;;;;\n31CD;CJK STROKE HZW;So;0;ON;;;;;N;;;;;\n31CE;CJK STROKE HZZZ;So;0;ON;;;;;N;;;;;\n31CF;CJK STROKE N;So;0;ON;;;;;N;;;;;\n31D0;CJK STROKE H;So;0;ON;;;;;N;;;;;\n31D1;CJK STROKE S;So;0;ON;;;;;N;;;;;\n31D2;CJK STROKE P;So;0;ON;;;;;N;;;;;\n31D3;CJK STROKE SP;So;0;ON;;;;;N;;;;;\n31D4;CJK STROKE D;So;0;ON;;;;;N;;;;;\n31D5;CJK STROKE HZ;So;0;ON;;;;;N;;;;;\n31D6;CJK STROKE HG;So;0;ON;;;;;N;;;;;\n31D7;CJK STROKE SZ;So;0;ON;;;;;N;;;;;\n31D8;CJK STROKE SWZ;So;0;ON;;;;;N;;;;;\n31D9;CJK STROKE ST;So;0;ON;;;;;N;;;;;\n31DA;CJK STROKE SG;So;0;ON;;;;;N;;;;;\n31DB;CJK STROKE PD;So;0;ON;;;;;N;;;;;\n31DC;CJK STROKE PZ;So;0;ON;;;;;N;;;;;\n31DD;CJK STROKE TN;So;0;ON;;;;;N;;;;;\n31DE;CJK STROKE SZZ;So;0;ON;;;;;N;;;;;\n31DF;CJK STROKE SWG;So;0;ON;;;;;N;;;;;\n31E0;CJK STROKE HXWG;So;0;ON;;;;;N;;;;;\n31E1;CJK STROKE HZZZG;So;0;ON;;;;;N;;;;;\n31E2;CJK STROKE PG;So;0;ON;;;;;N;;;;;\n31E3;CJK STROKE Q;So;0;ON;;;;;N;;;;;\n31E4;CJK STROKE HXG;So;0;ON;;;;;N;;;;;\n31E5;CJK STROKE SZP;So;0;ON;;;;;N;;;;;\n31EF;IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION;So;0;ON;;;;;N;;;;;\n31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;;\n31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;;\n31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;;\n31F3;KATAKANA LETTER SMALL TO;Lo;0;L;;;;;N;;;;;\n31F4;KATAKANA LETTER SMALL NU;Lo;0;L;;;;;N;;;;;\n31F5;KATAKANA LETTER SMALL HA;Lo;0;L;;;;;N;;;;;\n31F6;KATAKANA LETTER SMALL HI;Lo;0;L;;;;;N;;;;;\n31F7;KATAKANA LETTER SMALL HU;Lo;0;L;;;;;N;;;;;\n31F8;KATAKANA LETTER SMALL HE;Lo;0;L;;;;;N;;;;;\n31F9;KATAKANA LETTER SMALL HO;Lo;0;L;;;;;N;;;;;\n31FA;KATAKANA LETTER SMALL MU;Lo;0;L;;;;;N;;;;;\n31FB;KATAKANA LETTER SMALL RA;Lo;0;L;;;;;N;;;;;\n31FC;KATAKANA LETTER SMALL RI;Lo;0;L;;;;;N;;;;;\n31FD;KATAKANA LETTER SMALL RU;Lo;0;L;;;;;N;;;;;\n31FE;KATAKANA LETTER SMALL RE;Lo;0;L;;;;;N;;;;;\n31FF;KATAKANA LETTER SMALL RO;Lo;0;L;;;;;N;;;;;\n3200;PARENTHESIZED HANGUL KIYEOK;So;0;L;<compat> 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;;\n3201;PARENTHESIZED HANGUL NIEUN;So;0;L;<compat> 0028 1102 0029;;;;N;;;;;\n3202;PARENTHESIZED HANGUL TIKEUT;So;0;L;<compat> 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;;\n3203;PARENTHESIZED HANGUL RIEUL;So;0;L;<compat> 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;;\n3204;PARENTHESIZED HANGUL MIEUM;So;0;L;<compat> 0028 1106 0029;;;;N;;;;;\n3205;PARENTHESIZED HANGUL PIEUP;So;0;L;<compat> 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;;\n3206;PARENTHESIZED HANGUL SIOS;So;0;L;<compat> 0028 1109 0029;;;;N;;;;;\n3207;PARENTHESIZED HANGUL IEUNG;So;0;L;<compat> 0028 110B 0029;;;;N;;;;;\n3208;PARENTHESIZED HANGUL CIEUC;So;0;L;<compat> 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;;\n3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L;<compat> 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;;\n320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L;<compat> 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;;\n320B;PARENTHESIZED HANGUL THIEUTH;So;0;L;<compat> 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;;\n320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L;<compat> 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;;\n320D;PARENTHESIZED HANGUL HIEUH;So;0;L;<compat> 0028 1112 0029;;;;N;;;;;\n320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L;<compat> 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;;\n320F;PARENTHESIZED HANGUL NIEUN A;So;0;L;<compat> 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;;\n3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L;<compat> 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;;\n3211;PARENTHESIZED HANGUL RIEUL A;So;0;L;<compat> 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;;\n3212;PARENTHESIZED HANGUL MIEUM A;So;0;L;<compat> 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;;\n3213;PARENTHESIZED HANGUL PIEUP A;So;0;L;<compat> 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;;\n3214;PARENTHESIZED HANGUL SIOS A;So;0;L;<compat> 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;;\n3215;PARENTHESIZED HANGUL IEUNG A;So;0;L;<compat> 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;;\n3216;PARENTHESIZED HANGUL CIEUC A;So;0;L;<compat> 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;;\n3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L;<compat> 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;;\n3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L;<compat> 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;;\n3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L;<compat> 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;;\n321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L;<compat> 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;;\n321B;PARENTHESIZED HANGUL HIEUH A;So;0;L;<compat> 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;;\n321C;PARENTHESIZED HANGUL CIEUC U;So;0;L;<compat> 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;;\n321D;PARENTHESIZED KOREAN CHARACTER OJEON;So;0;ON;<compat> 0028 110B 1169 110C 1165 11AB 0029;;;;N;;;;;\n321E;PARENTHESIZED KOREAN CHARACTER O HU;So;0;ON;<compat> 0028 110B 1169 1112 116E 0029;;;;N;;;;;\n3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L;<compat> 0028 4E00 0029;;;1;N;;;;;\n3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L;<compat> 0028 4E8C 0029;;;2;N;;;;;\n3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L;<compat> 0028 4E09 0029;;;3;N;;;;;\n3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L;<compat> 0028 56DB 0029;;;4;N;;;;;\n3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L;<compat> 0028 4E94 0029;;;5;N;;;;;\n3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L;<compat> 0028 516D 0029;;;6;N;;;;;\n3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L;<compat> 0028 4E03 0029;;;7;N;;;;;\n3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L;<compat> 0028 516B 0029;;;8;N;;;;;\n3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L;<compat> 0028 4E5D 0029;;;9;N;;;;;\n3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L;<compat> 0028 5341 0029;;;10;N;;;;;\n322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L;<compat> 0028 6708 0029;;;;N;;;;;\n322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L;<compat> 0028 706B 0029;;;;N;;;;;\n322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L;<compat> 0028 6C34 0029;;;;N;;;;;\n322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L;<compat> 0028 6728 0029;;;;N;;;;;\n322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L;<compat> 0028 91D1 0029;;;;N;;;;;\n322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L;<compat> 0028 571F 0029;;;;N;;;;;\n3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L;<compat> 0028 65E5 0029;;;;N;;;;;\n3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L;<compat> 0028 682A 0029;;;;N;;;;;\n3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L;<compat> 0028 6709 0029;;;;N;;;;;\n3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L;<compat> 0028 793E 0029;;;;N;;;;;\n3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L;<compat> 0028 540D 0029;;;;N;;;;;\n3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L;<compat> 0028 7279 0029;;;;N;;;;;\n3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L;<compat> 0028 8CA1 0029;;;;N;;;;;\n3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L;<compat> 0028 795D 0029;;;;N;;;;;\n3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L;<compat> 0028 52B4 0029;;;;N;;;;;\n3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L;<compat> 0028 4EE3 0029;;;;N;;;;;\n323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L;<compat> 0028 547C 0029;;;;N;;;;;\n323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L;<compat> 0028 5B66 0029;;;;N;;;;;\n323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L;<compat> 0028 76E3 0029;;;;N;;;;;\n323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L;<compat> 0028 4F01 0029;;;;N;;;;;\n323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L;<compat> 0028 8CC7 0029;;;;N;;;;;\n323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L;<compat> 0028 5354 0029;;;;N;;;;;\n3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L;<compat> 0028 796D 0029;;;;N;;;;;\n3241;PARENTHESIZED IDEOGRAPH REST;So;0;L;<compat> 0028 4F11 0029;;;;N;;;;;\n3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L;<compat> 0028 81EA 0029;;;;N;;;;;\n3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L;<compat> 0028 81F3 0029;;;;N;;;;;\n3244;CIRCLED IDEOGRAPH QUESTION;So;0;L;<circle> 554F;;;;N;;;;;\n3245;CIRCLED IDEOGRAPH KINDERGARTEN;So;0;L;<circle> 5E7C;;;;N;;;;;\n3246;CIRCLED IDEOGRAPH SCHOOL;So;0;L;<circle> 6587;;;;N;;;;;\n3247;CIRCLED IDEOGRAPH KOTO;So;0;L;<circle> 7B8F;;;;N;;;;;\n3248;CIRCLED NUMBER TEN ON BLACK SQUARE;No;0;L;;;;10;N;;;;;\n3249;CIRCLED NUMBER TWENTY ON BLACK SQUARE;No;0;L;;;;20;N;;;;;\n324A;CIRCLED NUMBER THIRTY ON BLACK SQUARE;No;0;L;;;;30;N;;;;;\n324B;CIRCLED NUMBER FORTY ON BLACK SQUARE;No;0;L;;;;40;N;;;;;\n324C;CIRCLED NUMBER FIFTY ON BLACK SQUARE;No;0;L;;;;50;N;;;;;\n324D;CIRCLED NUMBER SIXTY ON BLACK SQUARE;No;0;L;;;;60;N;;;;;\n324E;CIRCLED NUMBER SEVENTY ON BLACK SQUARE;No;0;L;;;;70;N;;;;;\n324F;CIRCLED NUMBER EIGHTY ON BLACK SQUARE;No;0;L;;;;80;N;;;;;\n3250;PARTNERSHIP SIGN;So;0;ON;<square> 0050 0054 0045;;;;N;;;;;\n3251;CIRCLED NUMBER TWENTY ONE;No;0;ON;<circle> 0032 0031;;;21;N;;;;;\n3252;CIRCLED NUMBER TWENTY TWO;No;0;ON;<circle> 0032 0032;;;22;N;;;;;\n3253;CIRCLED NUMBER TWENTY THREE;No;0;ON;<circle> 0032 0033;;;23;N;;;;;\n3254;CIRCLED NUMBER TWENTY FOUR;No;0;ON;<circle> 0032 0034;;;24;N;;;;;\n3255;CIRCLED NUMBER TWENTY FIVE;No;0;ON;<circle> 0032 0035;;;25;N;;;;;\n3256;CIRCLED NUMBER TWENTY SIX;No;0;ON;<circle> 0032 0036;;;26;N;;;;;\n3257;CIRCLED NUMBER TWENTY SEVEN;No;0;ON;<circle> 0032 0037;;;27;N;;;;;\n3258;CIRCLED NUMBER TWENTY EIGHT;No;0;ON;<circle> 0032 0038;;;28;N;;;;;\n3259;CIRCLED NUMBER TWENTY NINE;No;0;ON;<circle> 0032 0039;;;29;N;;;;;\n325A;CIRCLED NUMBER THIRTY;No;0;ON;<circle> 0033 0030;;;30;N;;;;;\n325B;CIRCLED NUMBER THIRTY ONE;No;0;ON;<circle> 0033 0031;;;31;N;;;;;\n325C;CIRCLED NUMBER THIRTY TWO;No;0;ON;<circle> 0033 0032;;;32;N;;;;;\n325D;CIRCLED NUMBER THIRTY THREE;No;0;ON;<circle> 0033 0033;;;33;N;;;;;\n325E;CIRCLED NUMBER THIRTY FOUR;No;0;ON;<circle> 0033 0034;;;34;N;;;;;\n325F;CIRCLED NUMBER THIRTY FIVE;No;0;ON;<circle> 0033 0035;;;35;N;;;;;\n3260;CIRCLED HANGUL KIYEOK;So;0;L;<circle> 1100;;;;N;CIRCLED HANGUL GIYEOG;;;;\n3261;CIRCLED HANGUL NIEUN;So;0;L;<circle> 1102;;;;N;;;;;\n3262;CIRCLED HANGUL TIKEUT;So;0;L;<circle> 1103;;;;N;CIRCLED HANGUL DIGEUD;;;;\n3263;CIRCLED HANGUL RIEUL;So;0;L;<circle> 1105;;;;N;CIRCLED HANGUL LIEUL;;;;\n3264;CIRCLED HANGUL MIEUM;So;0;L;<circle> 1106;;;;N;;;;;\n3265;CIRCLED HANGUL PIEUP;So;0;L;<circle> 1107;;;;N;CIRCLED HANGUL BIEUB;;;;\n3266;CIRCLED HANGUL SIOS;So;0;L;<circle> 1109;;;;N;;;;;\n3267;CIRCLED HANGUL IEUNG;So;0;L;<circle> 110B;;;;N;;;;;\n3268;CIRCLED HANGUL CIEUC;So;0;L;<circle> 110C;;;;N;CIRCLED HANGUL JIEUJ;;;;\n3269;CIRCLED HANGUL CHIEUCH;So;0;L;<circle> 110E;;;;N;CIRCLED HANGUL CIEUC;;;;\n326A;CIRCLED HANGUL KHIEUKH;So;0;L;<circle> 110F;;;;N;CIRCLED HANGUL KIYEOK;;;;\n326B;CIRCLED HANGUL THIEUTH;So;0;L;<circle> 1110;;;;N;CIRCLED HANGUL TIEUT;;;;\n326C;CIRCLED HANGUL PHIEUPH;So;0;L;<circle> 1111;;;;N;CIRCLED HANGUL PIEUP;;;;\n326D;CIRCLED HANGUL HIEUH;So;0;L;<circle> 1112;;;;N;;;;;\n326E;CIRCLED HANGUL KIYEOK A;So;0;L;<circle> 1100 1161;;;;N;CIRCLED HANGUL GA;;;;\n326F;CIRCLED HANGUL NIEUN A;So;0;L;<circle> 1102 1161;;;;N;CIRCLED HANGUL NA;;;;\n3270;CIRCLED HANGUL TIKEUT A;So;0;L;<circle> 1103 1161;;;;N;CIRCLED HANGUL DA;;;;\n3271;CIRCLED HANGUL RIEUL A;So;0;L;<circle> 1105 1161;;;;N;CIRCLED HANGUL LA;;;;\n3272;CIRCLED HANGUL MIEUM A;So;0;L;<circle> 1106 1161;;;;N;CIRCLED HANGUL MA;;;;\n3273;CIRCLED HANGUL PIEUP A;So;0;L;<circle> 1107 1161;;;;N;CIRCLED HANGUL BA;;;;\n3274;CIRCLED HANGUL SIOS A;So;0;L;<circle> 1109 1161;;;;N;CIRCLED HANGUL SA;;;;\n3275;CIRCLED HANGUL IEUNG A;So;0;L;<circle> 110B 1161;;;;N;CIRCLED HANGUL A;;;;\n3276;CIRCLED HANGUL CIEUC A;So;0;L;<circle> 110C 1161;;;;N;CIRCLED HANGUL JA;;;;\n3277;CIRCLED HANGUL CHIEUCH A;So;0;L;<circle> 110E 1161;;;;N;CIRCLED HANGUL CA;;;;\n3278;CIRCLED HANGUL KHIEUKH A;So;0;L;<circle> 110F 1161;;;;N;CIRCLED HANGUL KA;;;;\n3279;CIRCLED HANGUL THIEUTH A;So;0;L;<circle> 1110 1161;;;;N;CIRCLED HANGUL TA;;;;\n327A;CIRCLED HANGUL PHIEUPH A;So;0;L;<circle> 1111 1161;;;;N;CIRCLED HANGUL PA;;;;\n327B;CIRCLED HANGUL HIEUH A;So;0;L;<circle> 1112 1161;;;;N;CIRCLED HANGUL HA;;;;\n327C;CIRCLED KOREAN CHARACTER CHAMKO;So;0;ON;<circle> 110E 1161 11B7 1100 1169;;;;N;;;;;\n327D;CIRCLED KOREAN CHARACTER JUEUI;So;0;ON;<circle> 110C 116E 110B 1174;;;;N;;;;;\n327E;CIRCLED HANGUL IEUNG U;So;0;ON;<circle> 110B 116E;;;;N;;;;;\n327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;;\n3280;CIRCLED IDEOGRAPH ONE;No;0;L;<circle> 4E00;;;1;N;;;;;\n3281;CIRCLED IDEOGRAPH TWO;No;0;L;<circle> 4E8C;;;2;N;;;;;\n3282;CIRCLED IDEOGRAPH THREE;No;0;L;<circle> 4E09;;;3;N;;;;;\n3283;CIRCLED IDEOGRAPH FOUR;No;0;L;<circle> 56DB;;;4;N;;;;;\n3284;CIRCLED IDEOGRAPH FIVE;No;0;L;<circle> 4E94;;;5;N;;;;;\n3285;CIRCLED IDEOGRAPH SIX;No;0;L;<circle> 516D;;;6;N;;;;;\n3286;CIRCLED IDEOGRAPH SEVEN;No;0;L;<circle> 4E03;;;7;N;;;;;\n3287;CIRCLED IDEOGRAPH EIGHT;No;0;L;<circle> 516B;;;8;N;;;;;\n3288;CIRCLED IDEOGRAPH NINE;No;0;L;<circle> 4E5D;;;9;N;;;;;\n3289;CIRCLED IDEOGRAPH TEN;No;0;L;<circle> 5341;;;10;N;;;;;\n328A;CIRCLED IDEOGRAPH MOON;So;0;L;<circle> 6708;;;;N;;;;;\n328B;CIRCLED IDEOGRAPH FIRE;So;0;L;<circle> 706B;;;;N;;;;;\n328C;CIRCLED IDEOGRAPH WATER;So;0;L;<circle> 6C34;;;;N;;;;;\n328D;CIRCLED IDEOGRAPH WOOD;So;0;L;<circle> 6728;;;;N;;;;;\n328E;CIRCLED IDEOGRAPH METAL;So;0;L;<circle> 91D1;;;;N;;;;;\n328F;CIRCLED IDEOGRAPH EARTH;So;0;L;<circle> 571F;;;;N;;;;;\n3290;CIRCLED IDEOGRAPH SUN;So;0;L;<circle> 65E5;;;;N;;;;;\n3291;CIRCLED IDEOGRAPH STOCK;So;0;L;<circle> 682A;;;;N;;;;;\n3292;CIRCLED IDEOGRAPH HAVE;So;0;L;<circle> 6709;;;;N;;;;;\n3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L;<circle> 793E;;;;N;;;;;\n3294;CIRCLED IDEOGRAPH NAME;So;0;L;<circle> 540D;;;;N;;;;;\n3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L;<circle> 7279;;;;N;;;;;\n3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L;<circle> 8CA1;;;;N;;;;;\n3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L;<circle> 795D;;;;N;;;;;\n3298;CIRCLED IDEOGRAPH LABOR;So;0;L;<circle> 52B4;;;;N;;;;;\n3299;CIRCLED IDEOGRAPH SECRET;So;0;L;<circle> 79D8;;;;N;;;;;\n329A;CIRCLED IDEOGRAPH MALE;So;0;L;<circle> 7537;;;;N;;;;;\n329B;CIRCLED IDEOGRAPH FEMALE;So;0;L;<circle> 5973;;;;N;;;;;\n329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L;<circle> 9069;;;;N;;;;;\n329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L;<circle> 512A;;;;N;;;;;\n329E;CIRCLED IDEOGRAPH PRINT;So;0;L;<circle> 5370;;;;N;;;;;\n329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L;<circle> 6CE8;;;;N;;;;;\n32A0;CIRCLED IDEOGRAPH ITEM;So;0;L;<circle> 9805;;;;N;;;;;\n32A1;CIRCLED IDEOGRAPH REST;So;0;L;<circle> 4F11;;;;N;;;;;\n32A2;CIRCLED IDEOGRAPH COPY;So;0;L;<circle> 5199;;;;N;;;;;\n32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L;<circle> 6B63;;;;N;;;;;\n32A4;CIRCLED IDEOGRAPH HIGH;So;0;L;<circle> 4E0A;;;;N;;;;;\n32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L;<circle> 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;;\n32A6;CIRCLED IDEOGRAPH LOW;So;0;L;<circle> 4E0B;;;;N;;;;;\n32A7;CIRCLED IDEOGRAPH LEFT;So;0;L;<circle> 5DE6;;;;N;;;;;\n32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L;<circle> 53F3;;;;N;;;;;\n32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L;<circle> 533B;;;;N;;;;;\n32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L;<circle> 5B97;;;;N;;;;;\n32AB;CIRCLED IDEOGRAPH STUDY;So;0;L;<circle> 5B66;;;;N;;;;;\n32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L;<circle> 76E3;;;;N;;;;;\n32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L;<circle> 4F01;;;;N;;;;;\n32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L;<circle> 8CC7;;;;N;;;;;\n32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L;<circle> 5354;;;;N;;;;;\n32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L;<circle> 591C;;;;N;;;;;\n32B1;CIRCLED NUMBER THIRTY SIX;No;0;ON;<circle> 0033 0036;;;36;N;;;;;\n32B2;CIRCLED NUMBER THIRTY SEVEN;No;0;ON;<circle> 0033 0037;;;37;N;;;;;\n32B3;CIRCLED NUMBER THIRTY EIGHT;No;0;ON;<circle> 0033 0038;;;38;N;;;;;\n32B4;CIRCLED NUMBER THIRTY NINE;No;0;ON;<circle> 0033 0039;;;39;N;;;;;\n32B5;CIRCLED NUMBER FORTY;No;0;ON;<circle> 0034 0030;;;40;N;;;;;\n32B6;CIRCLED NUMBER FORTY ONE;No;0;ON;<circle> 0034 0031;;;41;N;;;;;\n32B7;CIRCLED NUMBER FORTY TWO;No;0;ON;<circle> 0034 0032;;;42;N;;;;;\n32B8;CIRCLED NUMBER FORTY THREE;No;0;ON;<circle> 0034 0033;;;43;N;;;;;\n32B9;CIRCLED NUMBER FORTY FOUR;No;0;ON;<circle> 0034 0034;;;44;N;;;;;\n32BA;CIRCLED NUMBER FORTY FIVE;No;0;ON;<circle> 0034 0035;;;45;N;;;;;\n32BB;CIRCLED NUMBER FORTY SIX;No;0;ON;<circle> 0034 0036;;;46;N;;;;;\n32BC;CIRCLED NUMBER FORTY SEVEN;No;0;ON;<circle> 0034 0037;;;47;N;;;;;\n32BD;CIRCLED NUMBER FORTY EIGHT;No;0;ON;<circle> 0034 0038;;;48;N;;;;;\n32BE;CIRCLED NUMBER FORTY NINE;No;0;ON;<circle> 0034 0039;;;49;N;;;;;\n32BF;CIRCLED NUMBER FIFTY;No;0;ON;<circle> 0035 0030;;;50;N;;;;;\n32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L;<compat> 0031 6708;;;;N;;;;;\n32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L;<compat> 0032 6708;;;;N;;;;;\n32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L;<compat> 0033 6708;;;;N;;;;;\n32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L;<compat> 0034 6708;;;;N;;;;;\n32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L;<compat> 0035 6708;;;;N;;;;;\n32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L;<compat> 0036 6708;;;;N;;;;;\n32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L;<compat> 0037 6708;;;;N;;;;;\n32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L;<compat> 0038 6708;;;;N;;;;;\n32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L;<compat> 0039 6708;;;;N;;;;;\n32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L;<compat> 0031 0030 6708;;;;N;;;;;\n32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L;<compat> 0031 0031 6708;;;;N;;;;;\n32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L;<compat> 0031 0032 6708;;;;N;;;;;\n32CC;SQUARE HG;So;0;ON;<square> 0048 0067;;;;N;;;;;\n32CD;SQUARE ERG;So;0;ON;<square> 0065 0072 0067;;;;N;;;;;\n32CE;SQUARE EV;So;0;ON;<square> 0065 0056;;;;N;;;;;\n32CF;LIMITED LIABILITY SIGN;So;0;ON;<square> 004C 0054 0044;;;;N;;;;;\n32D0;CIRCLED KATAKANA A;So;0;L;<circle> 30A2;;;;N;;;;;\n32D1;CIRCLED KATAKANA I;So;0;L;<circle> 30A4;;;;N;;;;;\n32D2;CIRCLED KATAKANA U;So;0;L;<circle> 30A6;;;;N;;;;;\n32D3;CIRCLED KATAKANA E;So;0;L;<circle> 30A8;;;;N;;;;;\n32D4;CIRCLED KATAKANA O;So;0;L;<circle> 30AA;;;;N;;;;;\n32D5;CIRCLED KATAKANA KA;So;0;L;<circle> 30AB;;;;N;;;;;\n32D6;CIRCLED KATAKANA KI;So;0;L;<circle> 30AD;;;;N;;;;;\n32D7;CIRCLED KATAKANA KU;So;0;L;<circle> 30AF;;;;N;;;;;\n32D8;CIRCLED KATAKANA KE;So;0;L;<circle> 30B1;;;;N;;;;;\n32D9;CIRCLED KATAKANA KO;So;0;L;<circle> 30B3;;;;N;;;;;\n32DA;CIRCLED KATAKANA SA;So;0;L;<circle> 30B5;;;;N;;;;;\n32DB;CIRCLED KATAKANA SI;So;0;L;<circle> 30B7;;;;N;;;;;\n32DC;CIRCLED KATAKANA SU;So;0;L;<circle> 30B9;;;;N;;;;;\n32DD;CIRCLED KATAKANA SE;So;0;L;<circle> 30BB;;;;N;;;;;\n32DE;CIRCLED KATAKANA SO;So;0;L;<circle> 30BD;;;;N;;;;;\n32DF;CIRCLED KATAKANA TA;So;0;L;<circle> 30BF;;;;N;;;;;\n32E0;CIRCLED KATAKANA TI;So;0;L;<circle> 30C1;;;;N;;;;;\n32E1;CIRCLED KATAKANA TU;So;0;L;<circle> 30C4;;;;N;;;;;\n32E2;CIRCLED KATAKANA TE;So;0;L;<circle> 30C6;;;;N;;;;;\n32E3;CIRCLED KATAKANA TO;So;0;L;<circle> 30C8;;;;N;;;;;\n32E4;CIRCLED KATAKANA NA;So;0;L;<circle> 30CA;;;;N;;;;;\n32E5;CIRCLED KATAKANA NI;So;0;L;<circle> 30CB;;;;N;;;;;\n32E6;CIRCLED KATAKANA NU;So;0;L;<circle> 30CC;;;;N;;;;;\n32E7;CIRCLED KATAKANA NE;So;0;L;<circle> 30CD;;;;N;;;;;\n32E8;CIRCLED KATAKANA NO;So;0;L;<circle> 30CE;;;;N;;;;;\n32E9;CIRCLED KATAKANA HA;So;0;L;<circle> 30CF;;;;N;;;;;\n32EA;CIRCLED KATAKANA HI;So;0;L;<circle> 30D2;;;;N;;;;;\n32EB;CIRCLED KATAKANA HU;So;0;L;<circle> 30D5;;;;N;;;;;\n32EC;CIRCLED KATAKANA HE;So;0;L;<circle> 30D8;;;;N;;;;;\n32ED;CIRCLED KATAKANA HO;So;0;L;<circle> 30DB;;;;N;;;;;\n32EE;CIRCLED KATAKANA MA;So;0;L;<circle> 30DE;;;;N;;;;;\n32EF;CIRCLED KATAKANA MI;So;0;L;<circle> 30DF;;;;N;;;;;\n32F0;CIRCLED KATAKANA MU;So;0;L;<circle> 30E0;;;;N;;;;;\n32F1;CIRCLED KATAKANA ME;So;0;L;<circle> 30E1;;;;N;;;;;\n32F2;CIRCLED KATAKANA MO;So;0;L;<circle> 30E2;;;;N;;;;;\n32F3;CIRCLED KATAKANA YA;So;0;L;<circle> 30E4;;;;N;;;;;\n32F4;CIRCLED KATAKANA YU;So;0;L;<circle> 30E6;;;;N;;;;;\n32F5;CIRCLED KATAKANA YO;So;0;L;<circle> 30E8;;;;N;;;;;\n32F6;CIRCLED KATAKANA RA;So;0;L;<circle> 30E9;;;;N;;;;;\n32F7;CIRCLED KATAKANA RI;So;0;L;<circle> 30EA;;;;N;;;;;\n32F8;CIRCLED KATAKANA RU;So;0;L;<circle> 30EB;;;;N;;;;;\n32F9;CIRCLED KATAKANA RE;So;0;L;<circle> 30EC;;;;N;;;;;\n32FA;CIRCLED KATAKANA RO;So;0;L;<circle> 30ED;;;;N;;;;;\n32FB;CIRCLED KATAKANA WA;So;0;L;<circle> 30EF;;;;N;;;;;\n32FC;CIRCLED KATAKANA WI;So;0;L;<circle> 30F0;;;;N;;;;;\n32FD;CIRCLED KATAKANA WE;So;0;L;<circle> 30F1;;;;N;;;;;\n32FE;CIRCLED KATAKANA WO;So;0;L;<circle> 30F2;;;;N;;;;;\n32FF;SQUARE ERA NAME REIWA;So;0;L;<square> 4EE4 548C;;;;N;;;;;\n3300;SQUARE APAATO;So;0;L;<square> 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;;\n3301;SQUARE ARUHUA;So;0;L;<square> 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;;\n3302;SQUARE ANPEA;So;0;L;<square> 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;;\n3303;SQUARE AARU;So;0;L;<square> 30A2 30FC 30EB;;;;N;SQUARED AARU;;;;\n3304;SQUARE ININGU;So;0;L;<square> 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;;\n3305;SQUARE INTI;So;0;L;<square> 30A4 30F3 30C1;;;;N;SQUARED INTI;;;;\n3306;SQUARE UON;So;0;L;<square> 30A6 30A9 30F3;;;;N;SQUARED UON;;;;\n3307;SQUARE ESUKUUDO;So;0;L;<square> 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;;\n3308;SQUARE EEKAA;So;0;L;<square> 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;;\n3309;SQUARE ONSU;So;0;L;<square> 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;;\n330A;SQUARE OOMU;So;0;L;<square> 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;;\n330B;SQUARE KAIRI;So;0;L;<square> 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;;\n330C;SQUARE KARATTO;So;0;L;<square> 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;;\n330D;SQUARE KARORII;So;0;L;<square> 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;;\n330E;SQUARE GARON;So;0;L;<square> 30AC 30ED 30F3;;;;N;SQUARED GARON;;;;\n330F;SQUARE GANMA;So;0;L;<square> 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;;\n3310;SQUARE GIGA;So;0;L;<square> 30AE 30AC;;;;N;SQUARED GIGA;;;;\n3311;SQUARE GINII;So;0;L;<square> 30AE 30CB 30FC;;;;N;SQUARED GINII;;;;\n3312;SQUARE KYURII;So;0;L;<square> 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;;\n3313;SQUARE GIRUDAA;So;0;L;<square> 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;;\n3314;SQUARE KIRO;So;0;L;<square> 30AD 30ED;;;;N;SQUARED KIRO;;;;\n3315;SQUARE KIROGURAMU;So;0;L;<square> 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;;\n3316;SQUARE KIROMEETORU;So;0;L;<square> 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;;\n3317;SQUARE KIROWATTO;So;0;L;<square> 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;;\n3318;SQUARE GURAMU;So;0;L;<square> 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;;\n3319;SQUARE GURAMUTON;So;0;L;<square> 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;;\n331A;SQUARE KURUZEIRO;So;0;L;<square> 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;;\n331B;SQUARE KUROONE;So;0;L;<square> 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;;\n331C;SQUARE KEESU;So;0;L;<square> 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;;\n331D;SQUARE KORUNA;So;0;L;<square> 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;;\n331E;SQUARE KOOPO;So;0;L;<square> 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;;\n331F;SQUARE SAIKURU;So;0;L;<square> 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;;\n3320;SQUARE SANTIIMU;So;0;L;<square> 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;;\n3321;SQUARE SIRINGU;So;0;L;<square> 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;;\n3322;SQUARE SENTI;So;0;L;<square> 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;;\n3323;SQUARE SENTO;So;0;L;<square> 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;;\n3324;SQUARE DAASU;So;0;L;<square> 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;;\n3325;SQUARE DESI;So;0;L;<square> 30C7 30B7;;;;N;SQUARED DESI;;;;\n3326;SQUARE DORU;So;0;L;<square> 30C9 30EB;;;;N;SQUARED DORU;;;;\n3327;SQUARE TON;So;0;L;<square> 30C8 30F3;;;;N;SQUARED TON;;;;\n3328;SQUARE NANO;So;0;L;<square> 30CA 30CE;;;;N;SQUARED NANO;;;;\n3329;SQUARE NOTTO;So;0;L;<square> 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;;\n332A;SQUARE HAITU;So;0;L;<square> 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;;\n332B;SQUARE PAASENTO;So;0;L;<square> 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;;\n332C;SQUARE PAATU;So;0;L;<square> 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;;\n332D;SQUARE BAARERU;So;0;L;<square> 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;;\n332E;SQUARE PIASUTORU;So;0;L;<square> 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;;\n332F;SQUARE PIKURU;So;0;L;<square> 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;;\n3330;SQUARE PIKO;So;0;L;<square> 30D4 30B3;;;;N;SQUARED PIKO;;;;\n3331;SQUARE BIRU;So;0;L;<square> 30D3 30EB;;;;N;SQUARED BIRU;;;;\n3332;SQUARE HUARADDO;So;0;L;<square> 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;;\n3333;SQUARE HUIITO;So;0;L;<square> 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;;\n3334;SQUARE BUSSYERU;So;0;L;<square> 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;;\n3335;SQUARE HURAN;So;0;L;<square> 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;;\n3336;SQUARE HEKUTAARU;So;0;L;<square> 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;;\n3337;SQUARE PESO;So;0;L;<square> 30DA 30BD;;;;N;SQUARED PESO;;;;\n3338;SQUARE PENIHI;So;0;L;<square> 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;;\n3339;SQUARE HERUTU;So;0;L;<square> 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;;\n333A;SQUARE PENSU;So;0;L;<square> 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;;\n333B;SQUARE PEEZI;So;0;L;<square> 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;;\n333C;SQUARE BEETA;So;0;L;<square> 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;;\n333D;SQUARE POINTO;So;0;L;<square> 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;;\n333E;SQUARE BORUTO;So;0;L;<square> 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;;\n333F;SQUARE HON;So;0;L;<square> 30DB 30F3;;;;N;SQUARED HON;;;;\n3340;SQUARE PONDO;So;0;L;<square> 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;;\n3341;SQUARE HOORU;So;0;L;<square> 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;;\n3342;SQUARE HOON;So;0;L;<square> 30DB 30FC 30F3;;;;N;SQUARED HOON;;;;\n3343;SQUARE MAIKURO;So;0;L;<square> 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;;\n3344;SQUARE MAIRU;So;0;L;<square> 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;;\n3345;SQUARE MAHHA;So;0;L;<square> 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;;\n3346;SQUARE MARUKU;So;0;L;<square> 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;;\n3347;SQUARE MANSYON;So;0;L;<square> 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;;\n3348;SQUARE MIKURON;So;0;L;<square> 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;;\n3349;SQUARE MIRI;So;0;L;<square> 30DF 30EA;;;;N;SQUARED MIRI;;;;\n334A;SQUARE MIRIBAARU;So;0;L;<square> 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;;\n334B;SQUARE MEGA;So;0;L;<square> 30E1 30AC;;;;N;SQUARED MEGA;;;;\n334C;SQUARE MEGATON;So;0;L;<square> 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;;\n334D;SQUARE MEETORU;So;0;L;<square> 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;;\n334E;SQUARE YAADO;So;0;L;<square> 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;;\n334F;SQUARE YAARU;So;0;L;<square> 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;;\n3350;SQUARE YUAN;So;0;L;<square> 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;;\n3351;SQUARE RITTORU;So;0;L;<square> 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;;\n3352;SQUARE RIRA;So;0;L;<square> 30EA 30E9;;;;N;SQUARED RIRA;;;;\n3353;SQUARE RUPII;So;0;L;<square> 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;;\n3354;SQUARE RUUBURU;So;0;L;<square> 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;;\n3355;SQUARE REMU;So;0;L;<square> 30EC 30E0;;;;N;SQUARED REMU;;;;\n3356;SQUARE RENTOGEN;So;0;L;<square> 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;;\n3357;SQUARE WATTO;So;0;L;<square> 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;;\n3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L;<compat> 0030 70B9;;;;N;;;;;\n3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L;<compat> 0031 70B9;;;;N;;;;;\n335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L;<compat> 0032 70B9;;;;N;;;;;\n335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L;<compat> 0033 70B9;;;;N;;;;;\n335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L;<compat> 0034 70B9;;;;N;;;;;\n335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L;<compat> 0035 70B9;;;;N;;;;;\n335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L;<compat> 0036 70B9;;;;N;;;;;\n335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L;<compat> 0037 70B9;;;;N;;;;;\n3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L;<compat> 0038 70B9;;;;N;;;;;\n3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L;<compat> 0039 70B9;;;;N;;;;;\n3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L;<compat> 0031 0030 70B9;;;;N;;;;;\n3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L;<compat> 0031 0031 70B9;;;;N;;;;;\n3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L;<compat> 0031 0032 70B9;;;;N;;;;;\n3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L;<compat> 0031 0033 70B9;;;;N;;;;;\n3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L;<compat> 0031 0034 70B9;;;;N;;;;;\n3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L;<compat> 0031 0035 70B9;;;;N;;;;;\n3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L;<compat> 0031 0036 70B9;;;;N;;;;;\n3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L;<compat> 0031 0037 70B9;;;;N;;;;;\n336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L;<compat> 0031 0038 70B9;;;;N;;;;;\n336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L;<compat> 0031 0039 70B9;;;;N;;;;;\n336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L;<compat> 0032 0030 70B9;;;;N;;;;;\n336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L;<compat> 0032 0031 70B9;;;;N;;;;;\n336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L;<compat> 0032 0032 70B9;;;;N;;;;;\n336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L;<compat> 0032 0033 70B9;;;;N;;;;;\n3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L;<compat> 0032 0034 70B9;;;;N;;;;;\n3371;SQUARE HPA;So;0;L;<square> 0068 0050 0061;;;;N;;;;;\n3372;SQUARE DA;So;0;L;<square> 0064 0061;;;;N;;;;;\n3373;SQUARE AU;So;0;L;<square> 0041 0055;;;;N;;;;;\n3374;SQUARE BAR;So;0;L;<square> 0062 0061 0072;;;;N;;;;;\n3375;SQUARE OV;So;0;L;<square> 006F 0056;;;;N;;;;;\n3376;SQUARE PC;So;0;L;<square> 0070 0063;;;;N;;;;;\n3377;SQUARE DM;So;0;ON;<square> 0064 006D;;;;N;;;;;\n3378;SQUARE DM SQUARED;So;0;ON;<square> 0064 006D 00B2;;;;N;;;;;\n3379;SQUARE DM CUBED;So;0;ON;<square> 0064 006D 00B3;;;;N;;;;;\n337A;SQUARE IU;So;0;ON;<square> 0049 0055;;;;N;;;;;\n337B;SQUARE ERA NAME HEISEI;So;0;L;<square> 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;;\n337C;SQUARE ERA NAME SYOUWA;So;0;L;<square> 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;;\n337D;SQUARE ERA NAME TAISYOU;So;0;L;<square> 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;;\n337E;SQUARE ERA NAME MEIZI;So;0;L;<square> 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;;\n337F;SQUARE CORPORATION;So;0;L;<square> 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;;\n3380;SQUARE PA AMPS;So;0;L;<square> 0070 0041;;;;N;SQUARED PA AMPS;;;;\n3381;SQUARE NA;So;0;L;<square> 006E 0041;;;;N;SQUARED NA;;;;\n3382;SQUARE MU A;So;0;L;<square> 03BC 0041;;;;N;SQUARED MU A;;;;\n3383;SQUARE MA;So;0;L;<square> 006D 0041;;;;N;SQUARED MA;;;;\n3384;SQUARE KA;So;0;L;<square> 006B 0041;;;;N;SQUARED KA;;;;\n3385;SQUARE KB;So;0;L;<square> 004B 0042;;;;N;SQUARED KB;;;;\n3386;SQUARE MB;So;0;L;<square> 004D 0042;;;;N;SQUARED MB;;;;\n3387;SQUARE GB;So;0;L;<square> 0047 0042;;;;N;SQUARED GB;;;;\n3388;SQUARE CAL;So;0;L;<square> 0063 0061 006C;;;;N;SQUARED CAL;;;;\n3389;SQUARE KCAL;So;0;L;<square> 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;;\n338A;SQUARE PF;So;0;L;<square> 0070 0046;;;;N;SQUARED PF;;;;\n338B;SQUARE NF;So;0;L;<square> 006E 0046;;;;N;SQUARED NF;;;;\n338C;SQUARE MU F;So;0;L;<square> 03BC 0046;;;;N;SQUARED MU F;;;;\n338D;SQUARE MU G;So;0;L;<square> 03BC 0067;;;;N;SQUARED MU G;;;;\n338E;SQUARE MG;So;0;L;<square> 006D 0067;;;;N;SQUARED MG;;;;\n338F;SQUARE KG;So;0;L;<square> 006B 0067;;;;N;SQUARED KG;;;;\n3390;SQUARE HZ;So;0;L;<square> 0048 007A;;;;N;SQUARED HZ;;;;\n3391;SQUARE KHZ;So;0;L;<square> 006B 0048 007A;;;;N;SQUARED KHZ;;;;\n3392;SQUARE MHZ;So;0;L;<square> 004D 0048 007A;;;;N;SQUARED MHZ;;;;\n3393;SQUARE GHZ;So;0;L;<square> 0047 0048 007A;;;;N;SQUARED GHZ;;;;\n3394;SQUARE THZ;So;0;L;<square> 0054 0048 007A;;;;N;SQUARED THZ;;;;\n3395;SQUARE MU L;So;0;L;<square> 03BC 2113;;;;N;SQUARED MU L;;;;\n3396;SQUARE ML;So;0;L;<square> 006D 2113;;;;N;SQUARED ML;;;;\n3397;SQUARE DL;So;0;L;<square> 0064 2113;;;;N;SQUARED DL;;;;\n3398;SQUARE KL;So;0;L;<square> 006B 2113;;;;N;SQUARED KL;;;;\n3399;SQUARE FM;So;0;L;<square> 0066 006D;;;;N;SQUARED FM;;;;\n339A;SQUARE NM;So;0;L;<square> 006E 006D;;;;N;SQUARED NM;;;;\n339B;SQUARE MU M;So;0;L;<square> 03BC 006D;;;;N;SQUARED MU M;;;;\n339C;SQUARE MM;So;0;L;<square> 006D 006D;;;;N;SQUARED MM;;;;\n339D;SQUARE CM;So;0;L;<square> 0063 006D;;;;N;SQUARED CM;;;;\n339E;SQUARE KM;So;0;L;<square> 006B 006D;;;;N;SQUARED KM;;;;\n339F;SQUARE MM SQUARED;So;0;L;<square> 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;;\n33A0;SQUARE CM SQUARED;So;0;L;<square> 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;;\n33A1;SQUARE M SQUARED;So;0;L;<square> 006D 00B2;;;;N;SQUARED M SQUARED;;;;\n33A2;SQUARE KM SQUARED;So;0;L;<square> 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;;\n33A3;SQUARE MM CUBED;So;0;L;<square> 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;;\n33A4;SQUARE CM CUBED;So;0;L;<square> 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;;\n33A5;SQUARE M CUBED;So;0;L;<square> 006D 00B3;;;;N;SQUARED M CUBED;;;;\n33A6;SQUARE KM CUBED;So;0;L;<square> 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;;\n33A7;SQUARE M OVER S;So;0;L;<square> 006D 2215 0073;;;;N;SQUARED M OVER S;;;;\n33A8;SQUARE M OVER S SQUARED;So;0;L;<square> 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;;\n33A9;SQUARE PA;So;0;L;<square> 0050 0061;;;;N;SQUARED PA;;;;\n33AA;SQUARE KPA;So;0;L;<square> 006B 0050 0061;;;;N;SQUARED KPA;;;;\n33AB;SQUARE MPA;So;0;L;<square> 004D 0050 0061;;;;N;SQUARED MPA;;;;\n33AC;SQUARE GPA;So;0;L;<square> 0047 0050 0061;;;;N;SQUARED GPA;;;;\n33AD;SQUARE RAD;So;0;L;<square> 0072 0061 0064;;;;N;SQUARED RAD;;;;\n33AE;SQUARE RAD OVER S;So;0;L;<square> 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;;\n33AF;SQUARE RAD OVER S SQUARED;So;0;L;<square> 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;;\n33B0;SQUARE PS;So;0;L;<square> 0070 0073;;;;N;SQUARED PS;;;;\n33B1;SQUARE NS;So;0;L;<square> 006E 0073;;;;N;SQUARED NS;;;;\n33B2;SQUARE MU S;So;0;L;<square> 03BC 0073;;;;N;SQUARED MU S;;;;\n33B3;SQUARE MS;So;0;L;<square> 006D 0073;;;;N;SQUARED MS;;;;\n33B4;SQUARE PV;So;0;L;<square> 0070 0056;;;;N;SQUARED PV;;;;\n33B5;SQUARE NV;So;0;L;<square> 006E 0056;;;;N;SQUARED NV;;;;\n33B6;SQUARE MU V;So;0;L;<square> 03BC 0056;;;;N;SQUARED MU V;;;;\n33B7;SQUARE MV;So;0;L;<square> 006D 0056;;;;N;SQUARED MV;;;;\n33B8;SQUARE KV;So;0;L;<square> 006B 0056;;;;N;SQUARED KV;;;;\n33B9;SQUARE MV MEGA;So;0;L;<square> 004D 0056;;;;N;SQUARED MV MEGA;;;;\n33BA;SQUARE PW;So;0;L;<square> 0070 0057;;;;N;SQUARED PW;;;;\n33BB;SQUARE NW;So;0;L;<square> 006E 0057;;;;N;SQUARED NW;;;;\n33BC;SQUARE MU W;So;0;L;<square> 03BC 0057;;;;N;SQUARED MU W;;;;\n33BD;SQUARE MW;So;0;L;<square> 006D 0057;;;;N;SQUARED MW;;;;\n33BE;SQUARE KW;So;0;L;<square> 006B 0057;;;;N;SQUARED KW;;;;\n33BF;SQUARE MW MEGA;So;0;L;<square> 004D 0057;;;;N;SQUARED MW MEGA;;;;\n33C0;SQUARE K OHM;So;0;L;<square> 006B 03A9;;;;N;SQUARED K OHM;;;;\n33C1;SQUARE M OHM;So;0;L;<square> 004D 03A9;;;;N;SQUARED M OHM;;;;\n33C2;SQUARE AM;So;0;L;<square> 0061 002E 006D 002E;;;;N;SQUARED AM;;;;\n33C3;SQUARE BQ;So;0;L;<square> 0042 0071;;;;N;SQUARED BQ;;;;\n33C4;SQUARE CC;So;0;L;<square> 0063 0063;;;;N;SQUARED CC;;;;\n33C5;SQUARE CD;So;0;L;<square> 0063 0064;;;;N;SQUARED CD;;;;\n33C6;SQUARE C OVER KG;So;0;L;<square> 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;;\n33C7;SQUARE CO;So;0;L;<square> 0043 006F 002E;;;;N;SQUARED CO;;;;\n33C8;SQUARE DB;So;0;L;<square> 0064 0042;;;;N;SQUARED DB;;;;\n33C9;SQUARE GY;So;0;L;<square> 0047 0079;;;;N;SQUARED GY;;;;\n33CA;SQUARE HA;So;0;L;<square> 0068 0061;;;;N;SQUARED HA;;;;\n33CB;SQUARE HP;So;0;L;<square> 0048 0050;;;;N;SQUARED HP;;;;\n33CC;SQUARE IN;So;0;L;<square> 0069 006E;;;;N;SQUARED IN;;;;\n33CD;SQUARE KK;So;0;L;<square> 004B 004B;;;;N;SQUARED KK;;;;\n33CE;SQUARE KM CAPITAL;So;0;L;<square> 004B 004D;;;;N;SQUARED KM CAPITAL;;;;\n33CF;SQUARE KT;So;0;L;<square> 006B 0074;;;;N;SQUARED KT;;;;\n33D0;SQUARE LM;So;0;L;<square> 006C 006D;;;;N;SQUARED LM;;;;\n33D1;SQUARE LN;So;0;L;<square> 006C 006E;;;;N;SQUARED LN;;;;\n33D2;SQUARE LOG;So;0;L;<square> 006C 006F 0067;;;;N;SQUARED LOG;;;;\n33D3;SQUARE LX;So;0;L;<square> 006C 0078;;;;N;SQUARED LX;;;;\n33D4;SQUARE MB SMALL;So;0;L;<square> 006D 0062;;;;N;SQUARED MB SMALL;;;;\n33D5;SQUARE MIL;So;0;L;<square> 006D 0069 006C;;;;N;SQUARED MIL;;;;\n33D6;SQUARE MOL;So;0;L;<square> 006D 006F 006C;;;;N;SQUARED MOL;;;;\n33D7;SQUARE PH;So;0;L;<square> 0050 0048;;;;N;SQUARED PH;;;;\n33D8;SQUARE PM;So;0;L;<square> 0070 002E 006D 002E;;;;N;SQUARED PM;;;;\n33D9;SQUARE PPM;So;0;L;<square> 0050 0050 004D;;;;N;SQUARED PPM;;;;\n33DA;SQUARE PR;So;0;L;<square> 0050 0052;;;;N;SQUARED PR;;;;\n33DB;SQUARE SR;So;0;L;<square> 0073 0072;;;;N;SQUARED SR;;;;\n33DC;SQUARE SV;So;0;L;<square> 0053 0076;;;;N;SQUARED SV;;;;\n33DD;SQUARE WB;So;0;L;<square> 0057 0062;;;;N;SQUARED WB;;;;\n33DE;SQUARE V OVER M;So;0;ON;<square> 0056 2215 006D;;;;N;;;;;\n33DF;SQUARE A OVER M;So;0;ON;<square> 0041 2215 006D;;;;N;;;;;\n33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L;<compat> 0031 65E5;;;;N;;;;;\n33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L;<compat> 0032 65E5;;;;N;;;;;\n33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L;<compat> 0033 65E5;;;;N;;;;;\n33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L;<compat> 0034 65E5;;;;N;;;;;\n33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L;<compat> 0035 65E5;;;;N;;;;;\n33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L;<compat> 0036 65E5;;;;N;;;;;\n33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L;<compat> 0037 65E5;;;;N;;;;;\n33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L;<compat> 0038 65E5;;;;N;;;;;\n33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L;<compat> 0039 65E5;;;;N;;;;;\n33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L;<compat> 0031 0030 65E5;;;;N;;;;;\n33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L;<compat> 0031 0031 65E5;;;;N;;;;;\n33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L;<compat> 0031 0032 65E5;;;;N;;;;;\n33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L;<compat> 0031 0033 65E5;;;;N;;;;;\n33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L;<compat> 0031 0034 65E5;;;;N;;;;;\n33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L;<compat> 0031 0035 65E5;;;;N;;;;;\n33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L;<compat> 0031 0036 65E5;;;;N;;;;;\n33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L;<compat> 0031 0037 65E5;;;;N;;;;;\n33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L;<compat> 0031 0038 65E5;;;;N;;;;;\n33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L;<compat> 0031 0039 65E5;;;;N;;;;;\n33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L;<compat> 0032 0030 65E5;;;;N;;;;;\n33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L;<compat> 0032 0031 65E5;;;;N;;;;;\n33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L;<compat> 0032 0032 65E5;;;;N;;;;;\n33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L;<compat> 0032 0033 65E5;;;;N;;;;;\n33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L;<compat> 0032 0034 65E5;;;;N;;;;;\n33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L;<compat> 0032 0035 65E5;;;;N;;;;;\n33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L;<compat> 0032 0036 65E5;;;;N;;;;;\n33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L;<compat> 0032 0037 65E5;;;;N;;;;;\n33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L;<compat> 0032 0038 65E5;;;;N;;;;;\n33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L;<compat> 0032 0039 65E5;;;;N;;;;;\n33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L;<compat> 0033 0030 65E5;;;;N;;;;;\n33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L;<compat> 0033 0031 65E5;;;;N;;;;;\n33FF;SQUARE GAL;So;0;ON;<square> 0067 0061 006C;;;;N;;;;;\n3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;\n4DBF;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;\n4DC0;HEXAGRAM FOR THE CREATIVE HEAVEN;So;0;ON;;;;;N;;;;;\n4DC1;HEXAGRAM FOR THE RECEPTIVE EARTH;So;0;ON;;;;;N;;;;;\n4DC2;HEXAGRAM FOR DIFFICULTY AT THE BEGINNING;So;0;ON;;;;;N;;;;;\n4DC3;HEXAGRAM FOR YOUTHFUL FOLLY;So;0;ON;;;;;N;;;;;\n4DC4;HEXAGRAM FOR WAITING;So;0;ON;;;;;N;;;;;\n4DC5;HEXAGRAM FOR CONFLICT;So;0;ON;;;;;N;;;;;\n4DC6;HEXAGRAM FOR THE ARMY;So;0;ON;;;;;N;;;;;\n4DC7;HEXAGRAM FOR HOLDING TOGETHER;So;0;ON;;;;;N;;;;;\n4DC8;HEXAGRAM FOR SMALL TAMING;So;0;ON;;;;;N;;;;;\n4DC9;HEXAGRAM FOR TREADING;So;0;ON;;;;;N;;;;;\n4DCA;HEXAGRAM FOR PEACE;So;0;ON;;;;;N;;;;;\n4DCB;HEXAGRAM FOR STANDSTILL;So;0;ON;;;;;N;;;;;\n4DCC;HEXAGRAM FOR FELLOWSHIP;So;0;ON;;;;;N;;;;;\n4DCD;HEXAGRAM FOR GREAT POSSESSION;So;0;ON;;;;;N;;;;;\n4DCE;HEXAGRAM FOR MODESTY;So;0;ON;;;;;N;;;;;\n4DCF;HEXAGRAM FOR ENTHUSIASM;So;0;ON;;;;;N;;;;;\n4DD0;HEXAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;;\n4DD1;HEXAGRAM FOR WORK ON THE DECAYED;So;0;ON;;;;;N;;;;;\n4DD2;HEXAGRAM FOR APPROACH;So;0;ON;;;;;N;;;;;\n4DD3;HEXAGRAM FOR CONTEMPLATION;So;0;ON;;;;;N;;;;;\n4DD4;HEXAGRAM FOR BITING THROUGH;So;0;ON;;;;;N;;;;;\n4DD5;HEXAGRAM FOR GRACE;So;0;ON;;;;;N;;;;;\n4DD6;HEXAGRAM FOR SPLITTING APART;So;0;ON;;;;;N;;;;;\n4DD7;HEXAGRAM FOR RETURN;So;0;ON;;;;;N;;;;;\n4DD8;HEXAGRAM FOR INNOCENCE;So;0;ON;;;;;N;;;;;\n4DD9;HEXAGRAM FOR GREAT TAMING;So;0;ON;;;;;N;;;;;\n4DDA;HEXAGRAM FOR MOUTH CORNERS;So;0;ON;;;;;N;;;;;\n4DDB;HEXAGRAM FOR GREAT PREPONDERANCE;So;0;ON;;;;;N;;;;;\n4DDC;HEXAGRAM FOR THE ABYSMAL WATER;So;0;ON;;;;;N;;;;;\n4DDD;HEXAGRAM FOR THE CLINGING FIRE;So;0;ON;;;;;N;;;;;\n4DDE;HEXAGRAM FOR INFLUENCE;So;0;ON;;;;;N;;;;;\n4DDF;HEXAGRAM FOR DURATION;So;0;ON;;;;;N;;;;;\n4DE0;HEXAGRAM FOR RETREAT;So;0;ON;;;;;N;;;;;\n4DE1;HEXAGRAM FOR GREAT POWER;So;0;ON;;;;;N;;;;;\n4DE2;HEXAGRAM FOR PROGRESS;So;0;ON;;;;;N;;;;;\n4DE3;HEXAGRAM FOR DARKENING OF THE LIGHT;So;0;ON;;;;;N;;;;;\n4DE4;HEXAGRAM FOR THE FAMILY;So;0;ON;;;;;N;;;;;\n4DE5;HEXAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;;\n4DE6;HEXAGRAM FOR OBSTRUCTION;So;0;ON;;;;;N;;;;;\n4DE7;HEXAGRAM FOR DELIVERANCE;So;0;ON;;;;;N;;;;;\n4DE8;HEXAGRAM FOR DECREASE;So;0;ON;;;;;N;;;;;\n4DE9;HEXAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;;\n4DEA;HEXAGRAM FOR BREAKTHROUGH;So;0;ON;;;;;N;;;;;\n4DEB;HEXAGRAM FOR COMING TO MEET;So;0;ON;;;;;N;;;;;\n4DEC;HEXAGRAM FOR GATHERING TOGETHER;So;0;ON;;;;;N;;;;;\n4DED;HEXAGRAM FOR PUSHING UPWARD;So;0;ON;;;;;N;;;;;\n4DEE;HEXAGRAM FOR OPPRESSION;So;0;ON;;;;;N;;;;;\n4DEF;HEXAGRAM FOR THE WELL;So;0;ON;;;;;N;;;;;\n4DF0;HEXAGRAM FOR REVOLUTION;So;0;ON;;;;;N;;;;;\n4DF1;HEXAGRAM FOR THE CAULDRON;So;0;ON;;;;;N;;;;;\n4DF2;HEXAGRAM FOR THE AROUSING THUNDER;So;0;ON;;;;;N;;;;;\n4DF3;HEXAGRAM FOR THE KEEPING STILL MOUNTAIN;So;0;ON;;;;;N;;;;;\n4DF4;HEXAGRAM FOR DEVELOPMENT;So;0;ON;;;;;N;;;;;\n4DF5;HEXAGRAM FOR THE MARRYING MAIDEN;So;0;ON;;;;;N;;;;;\n4DF6;HEXAGRAM FOR ABUNDANCE;So;0;ON;;;;;N;;;;;\n4DF7;HEXAGRAM FOR THE WANDERER;So;0;ON;;;;;N;;;;;\n4DF8;HEXAGRAM FOR THE GENTLE WIND;So;0;ON;;;;;N;;;;;\n4DF9;HEXAGRAM FOR THE JOYOUS LAKE;So;0;ON;;;;;N;;;;;\n4DFA;HEXAGRAM FOR DISPERSION;So;0;ON;;;;;N;;;;;\n4DFB;HEXAGRAM FOR LIMITATION;So;0;ON;;;;;N;;;;;\n4DFC;HEXAGRAM FOR INNER TRUTH;So;0;ON;;;;;N;;;;;\n4DFD;HEXAGRAM FOR SMALL PREPONDERANCE;So;0;ON;;;;;N;;;;;\n4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;;\n4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;;\n4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;\n9FFF;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;\nA000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;;\nA001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;;\nA002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;;\nA003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;;\nA004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;;\nA005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;;\nA006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;;\nA007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;;\nA008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;;\nA009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;;\nA00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;;\nA00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;;\nA00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;;\nA00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;;\nA00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;;\nA00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;;\nA010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;;\nA011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;;\nA012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;;\nA013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;;\nA014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;;\nA015;YI SYLLABLE WU;Lm;0;L;;;;;N;;;;;\nA016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;;\nA017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;;\nA018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;;\nA019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;;\nA01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;;\nA01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;;\nA01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;;\nA01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;;\nA01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;;\nA01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;;\nA020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;;\nA021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;;\nA022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;;\nA023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;;\nA024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;;\nA025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;;\nA026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;;\nA027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;;\nA028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;;\nA029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;;\nA02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;;\nA02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;;\nA02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;;\nA02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;;\nA02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;;\nA02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;;\nA030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;;\nA031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;;\nA032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;;\nA033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;;\nA034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;;\nA035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;;\nA036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;;\nA037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;;\nA038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;;\nA039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;;\nA03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;;\nA03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;;\nA03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;;\nA03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;;\nA03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;;\nA03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;;\nA040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;;\nA041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;;\nA042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;;\nA043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;;\nA044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;;\nA045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;;\nA046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;;\nA047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;;\nA048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;;\nA049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;;\nA04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;;\nA04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;;\nA04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;;\nA04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;;\nA04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;;\nA04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;;\nA050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;;\nA051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;;\nA052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;;\nA053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;;\nA054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;;\nA055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;;\nA056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;;\nA057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;;\nA058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;;\nA059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;;\nA05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;;\nA05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;;\nA05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;;\nA05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;;\nA05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;;\nA05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;;\nA060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;;\nA061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;;\nA062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;;\nA063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;;\nA064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;;\nA065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;;\nA066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;;\nA067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;;\nA068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;;\nA069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;;\nA06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;;\nA06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;;\nA06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;;\nA06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;;\nA06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;;\nA06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;;\nA070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;;\nA071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;;\nA072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;;\nA073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;;\nA074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;;\nA075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;;\nA076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;;\nA077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;;\nA078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;;\nA079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;;\nA07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;;\nA07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;;\nA07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;;\nA07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;;\nA07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;;\nA07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;;\nA080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;;\nA081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;;\nA082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;;\nA083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;;\nA084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;;\nA085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;;\nA086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;;\nA087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;;\nA088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;;\nA089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;;\nA08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;;\nA08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;;\nA08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;;\nA08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;;\nA08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;;\nA08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;;\nA090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;;\nA091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;;\nA092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;;\nA093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;;\nA094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;;\nA095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;;\nA096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;;\nA097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;;\nA098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;;\nA099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;;\nA09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;;\nA09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;;\nA09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;;\nA09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;;\nA09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;;\nA09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;;\nA0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;;\nA0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;;\nA0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;;\nA0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;;\nA0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;;\nA0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;;\nA0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;;\nA0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;;\nA0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;;\nA0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;;\nA0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;;\nA0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;;\nA0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;;\nA0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;;\nA0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;;\nA0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;;\nA0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;;\nA0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;;\nA0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;;\nA0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;;\nA0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;;\nA0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;;\nA0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;;\nA0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;;\nA0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;;\nA0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;;\nA0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;;\nA0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;;\nA0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;;\nA0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;;\nA0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;;\nA0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;;\nA0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;;\nA0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;;\nA0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;;\nA0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;;\nA0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;;\nA0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;;\nA0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;;\nA0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;;\nA0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;;\nA0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;;\nA0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;;\nA0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;;\nA0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;;\nA0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;;\nA0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;;\nA0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;;\nA0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;;\nA0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;;\nA0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;;\nA0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;;\nA0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;;\nA0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;;\nA0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;;\nA0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;;\nA0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;;\nA0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;;\nA0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;;\nA0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;;\nA0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;;\nA0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;;\nA0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;;\nA0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;;\nA0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;;\nA0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;;\nA0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;;\nA0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;;\nA0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;;\nA0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;;\nA0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;;\nA0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;;\nA0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;;\nA0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;;\nA0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;;\nA0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;;\nA0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;;\nA0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;;\nA0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;;\nA0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;;\nA0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;;\nA0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;;\nA0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;;\nA0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;;\nA0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;;\nA0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;;\nA0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;;\nA0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;;\nA0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;;\nA0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;;\nA0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;;\nA0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;;\nA0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;;\nA0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;;\nA0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;;\nA0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;;\nA100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;;\nA101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;;\nA102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;;\nA103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;;\nA104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;;\nA105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;;\nA106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;;\nA107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;;\nA108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;;\nA109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;;\nA10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;;\nA10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;;\nA10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;;\nA10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;;\nA10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;;\nA10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;;\nA110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;;\nA111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;;\nA112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;;\nA113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;;\nA114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;;\nA115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;;\nA116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;;\nA117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;;\nA118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;;\nA119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;;\nA11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;;\nA11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;;\nA11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;;\nA11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;;\nA11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;;\nA11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;;\nA120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;;\nA121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;;\nA122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;;\nA123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;;\nA124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;;\nA125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;;\nA126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;;\nA127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;;\nA128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;;\nA129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;;\nA12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;;\nA12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;;\nA12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;;\nA12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;;\nA12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;;\nA12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;;\nA130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;;\nA131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;;\nA132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;;\nA133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;;\nA134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;;\nA135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;;\nA136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;;\nA137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;;\nA138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;;\nA139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;;\nA13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;;\nA13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;;\nA13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;;\nA13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;;\nA13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;;\nA13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;;\nA140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;;\nA141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;;\nA142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;;\nA143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;;\nA144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;;\nA145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;;\nA146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;;\nA147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;;\nA148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;;\nA149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;;\nA14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;;\nA14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;;\nA14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;;\nA14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;;\nA14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;;\nA14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;;\nA150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;;\nA151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;;\nA152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;;\nA153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;;\nA154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;;\nA155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;;\nA156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;;\nA157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;;\nA158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;;\nA159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;;\nA15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;;\nA15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;;\nA15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;;\nA15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;;\nA15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;;\nA15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;;\nA160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;;\nA161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;;\nA162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;;\nA163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;;\nA164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;;\nA165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;;\nA166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;;\nA167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;;\nA168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;;\nA169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;;\nA16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;;\nA16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;;\nA16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;;\nA16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;;\nA16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;;\nA16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;;\nA170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;;\nA171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;;\nA172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;;\nA173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;;\nA174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;;\nA175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;;\nA176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;;\nA177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;;\nA178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;;\nA179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;;\nA17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;;\nA17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;;\nA17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;;\nA17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;;\nA17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;;\nA17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;;\nA180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;;\nA181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;;\nA182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;;\nA183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;;\nA184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;;\nA185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;;\nA186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;;\nA187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;;\nA188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;;\nA189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;;\nA18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;;\nA18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;;\nA18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;;\nA18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;;\nA18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;;\nA18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;;\nA190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;;\nA191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;;\nA192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;;\nA193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;;\nA194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;;\nA195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;;\nA196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;;\nA197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;;\nA198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;;\nA199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;;\nA19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;;\nA19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;;\nA19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;;\nA19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;;\nA19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;;\nA19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;;\nA1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;;\nA1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;;\nA1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;;\nA1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;;\nA1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;;\nA1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;;\nA1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;;\nA1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;;\nA1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;;\nA1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;;\nA1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;;\nA1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;;\nA1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;;\nA1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;;\nA1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;;\nA1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;;\nA1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;;\nA1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;;\nA1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;;\nA1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;;\nA1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;;\nA1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;;\nA1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;;\nA1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;;\nA1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;;\nA1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;;\nA1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;;\nA1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;;\nA1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;;\nA1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;;\nA1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;;\nA1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;;\nA1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;;\nA1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;;\nA1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;;\nA1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;;\nA1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;;\nA1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;;\nA1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;;\nA1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;;\nA1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;;\nA1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;;\nA1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;;\nA1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;;\nA1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;;\nA1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;;\nA1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;;\nA1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;;\nA1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;;\nA1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;;\nA1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;;\nA1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;;\nA1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;;\nA1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;;\nA1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;;\nA1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;;\nA1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;;\nA1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;;\nA1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;;\nA1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;;\nA1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;;\nA1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;;\nA1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;;\nA1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;;\nA1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;;\nA1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;;\nA1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;;\nA1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;;\nA1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;;\nA1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;;\nA1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;;\nA1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;;\nA1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;;\nA1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;;\nA1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;;\nA1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;;\nA1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;;\nA1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;;\nA1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;;\nA1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;;\nA1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;;\nA1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;;\nA1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;;\nA1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;;\nA1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;;\nA1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;;\nA1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;;\nA1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;;\nA1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;;\nA1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;;\nA1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;;\nA1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;;\nA1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;;\nA1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;;\nA1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;;\nA1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;;\nA200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;;\nA201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;;\nA202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;;\nA203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;;\nA204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;;\nA205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;;\nA206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;;\nA207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;;\nA208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;;\nA209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;;\nA20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;;\nA20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;;\nA20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;;\nA20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;;\nA20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;;\nA20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;;\nA210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;;\nA211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;;\nA212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;;\nA213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;;\nA214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;;\nA215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;;\nA216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;;\nA217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;;\nA218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;;\nA219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;;\nA21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;;\nA21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;;\nA21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;;\nA21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;;\nA21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;;\nA21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;;\nA220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;;\nA221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;;\nA222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;;\nA223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;;\nA224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;;\nA225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;;\nA226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;;\nA227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;;\nA228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;;\nA229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;;\nA22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;;\nA22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;;\nA22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;;\nA22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;;\nA22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;;\nA22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;;\nA230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;;\nA231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;;\nA232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;;\nA233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;;\nA234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;;\nA235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;;\nA236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;;\nA237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;;\nA238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;;\nA239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;;\nA23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;;\nA23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;;\nA23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;;\nA23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;;\nA23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;;\nA23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;;\nA240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;;\nA241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;;\nA242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;;\nA243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;;\nA244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;;\nA245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;;\nA246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;;\nA247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;;\nA248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;;\nA249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;;\nA24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;;\nA24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;;\nA24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;;\nA24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;;\nA24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;;\nA24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;;\nA250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;;\nA251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;;\nA252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;;\nA253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;;\nA254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;;\nA255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;;\nA256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;;\nA257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;;\nA258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;;\nA259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;;\nA25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;;\nA25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;;\nA25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;;\nA25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;;\nA25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;;\nA25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;;\nA260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;;\nA261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;;\nA262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;;\nA263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;;\nA264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;;\nA265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;;\nA266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;;\nA267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;;\nA268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;;\nA269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;;\nA26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;;\nA26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;;\nA26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;;\nA26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;;\nA26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;;\nA26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;;\nA270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;;\nA271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;;\nA272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;;\nA273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;;\nA274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;;\nA275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;;\nA276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;;\nA277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;;\nA278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;;\nA279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;;\nA27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;;\nA27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;;\nA27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;;\nA27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;;\nA27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;;\nA27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;;\nA280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;;\nA281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;;\nA282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;;\nA283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;;\nA284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;;\nA285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;;\nA286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;;\nA287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;;\nA288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;;\nA289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;;\nA28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;;\nA28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;;\nA28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;;\nA28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;;\nA28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;;\nA28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;;\nA290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;;\nA291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;;\nA292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;;\nA293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;;\nA294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;;\nA295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;;\nA296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;;\nA297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;;\nA298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;;\nA299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;;\nA29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;;\nA29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;;\nA29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;;\nA29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;;\nA29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;;\nA29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;;\nA2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;;\nA2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;;\nA2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;;\nA2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;;\nA2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;;\nA2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;;\nA2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;;\nA2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;;\nA2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;;\nA2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;;\nA2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;;\nA2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;;\nA2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;;\nA2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;;\nA2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;;\nA2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;;\nA2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;;\nA2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;;\nA2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;;\nA2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;;\nA2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;;\nA2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;;\nA2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;;\nA2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;;\nA2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;;\nA2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;;\nA2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;;\nA2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;;\nA2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;;\nA2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;;\nA2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;;\nA2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;;\nA2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;;\nA2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;;\nA2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;;\nA2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;;\nA2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;;\nA2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;;\nA2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;;\nA2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;;\nA2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;;\nA2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;;\nA2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;;\nA2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;;\nA2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;;\nA2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;;\nA2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;;\nA2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;;\nA2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;;\nA2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;;\nA2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;\nA2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;;\nA2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;;\nA2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;;\nA2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;;\nA2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;;\nA2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;;\nA2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;;\nA2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;\nA2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;;\nA2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;;\nA2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;\nA2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;;\nA2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;;\nA2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;\nA2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;;\nA2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;;\nA2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;\nA2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;;\nA2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;;\nA2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;;\nA2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;;\nA2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;;\nA2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;;\nA2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;;\nA2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;;\nA2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;;\nA2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;;\nA2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;;\nA2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;;\nA2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;;\nA2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;;\nA2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;;\nA2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;;\nA2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;;\nA2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;;\nA2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;;\nA2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;;\nA2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;;\nA2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;;\nA2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;;\nA2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;;\nA2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;;\nA2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;;\nA2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;;\nA2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;;\nA300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;;\nA301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;;\nA302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;;\nA303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;;\nA304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;;\nA305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;;\nA306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;;\nA307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;;\nA308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;;\nA309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;;\nA30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;;\nA30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;;\nA30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;;\nA30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;;\nA30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;;\nA30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;;\nA310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;;\nA311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;;\nA312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;;\nA313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;;\nA314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;;\nA315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;;\nA316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;;\nA317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;;\nA318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;;\nA319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;;\nA31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;;\nA31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;;\nA31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;;\nA31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;;\nA31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;;\nA31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;;\nA320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;;\nA321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;;\nA322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;;\nA323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;;\nA324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;;\nA325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;;\nA326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;;\nA327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;;\nA328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;;\nA329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;;\nA32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;;\nA32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;;\nA32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;;\nA32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;;\nA32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;;\nA32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;;\nA330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;;\nA331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;;\nA332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;;\nA333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;;\nA334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;;\nA335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;;\nA336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;;\nA337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;;\nA338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;;\nA339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;;\nA33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;;\nA33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;;\nA33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;;\nA33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;;\nA33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;;\nA33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;;\nA340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;;\nA341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;;\nA342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;;\nA343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;;\nA344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;;\nA345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;;\nA346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;;\nA347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;;\nA348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;\nA349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;;\nA34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;;\nA34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;;\nA34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;;\nA34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;;\nA34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;;\nA34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;\nA350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;;\nA351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;;\nA352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;;\nA353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;\nA354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;;\nA355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;;\nA356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;;\nA357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;\nA358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;;\nA359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;;\nA35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;;\nA35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;;\nA35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;;\nA35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;;\nA35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;;\nA35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;;\nA360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;;\nA361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;;\nA362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;;\nA363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;;\nA364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;;\nA365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;;\nA366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;;\nA367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;;\nA368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;;\nA369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;;\nA36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;;\nA36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;;\nA36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;;\nA36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;;\nA36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;;\nA36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;;\nA370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;;\nA371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;;\nA372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;;\nA373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;;\nA374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;;\nA375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;;\nA376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;;\nA377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;;\nA378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;;\nA379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;;\nA37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;;\nA37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;;\nA37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;;\nA37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;;\nA37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;;\nA37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;;\nA380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;;\nA381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;;\nA382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;;\nA383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;;\nA384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;;\nA385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;;\nA386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;;\nA387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;;\nA388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;;\nA389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;;\nA38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;;\nA38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;;\nA38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;;\nA38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;;\nA38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;;\nA38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;;\nA390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;;\nA391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;;\nA392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;;\nA393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;;\nA394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;;\nA395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;;\nA396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;;\nA397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;;\nA398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;;\nA399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;;\nA39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;;\nA39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;;\nA39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;;\nA39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;;\nA39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;;\nA39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;;\nA3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;;\nA3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;;\nA3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;;\nA3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;;\nA3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;;\nA3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;;\nA3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;;\nA3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;;\nA3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;;\nA3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;;\nA3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;;\nA3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;;\nA3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;;\nA3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;;\nA3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;;\nA3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;;\nA3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;;\nA3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;;\nA3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;;\nA3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;;\nA3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;;\nA3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;;\nA3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;;\nA3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;;\nA3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;;\nA3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;;\nA3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;;\nA3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;;\nA3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;;\nA3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;;\nA3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;;\nA3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;;\nA3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;;\nA3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;;\nA3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;;\nA3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;;\nA3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;;\nA3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;;\nA3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;;\nA3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;;\nA3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;;\nA3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;;\nA3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;;\nA3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;;\nA3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;;\nA3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;;\nA3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;;\nA3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;;\nA3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;;\nA3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;;\nA3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;;\nA3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;;\nA3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;;\nA3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;;\nA3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;;\nA3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;;\nA3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;;\nA3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;;\nA3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;;\nA3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;;\nA3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;;\nA3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;;\nA3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;;\nA3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;;\nA3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;;\nA3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;;\nA3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;;\nA3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;;\nA3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;;\nA3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;;\nA3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;;\nA3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;;\nA3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;;\nA3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;;\nA3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;;\nA3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;;\nA3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;;\nA3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;;\nA3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;;\nA3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;;\nA3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;;\nA3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;;\nA3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;;\nA3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;;\nA3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;;\nA3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;;\nA3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;;\nA3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;;\nA3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;;\nA3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;;\nA3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;;\nA3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;;\nA3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;;\nA3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;;\nA3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;;\nA3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;;\nA400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;;\nA401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;;\nA402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;;\nA403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;;\nA404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;;\nA405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;;\nA406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;;\nA407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;;\nA408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;;\nA409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;;\nA40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;;\nA40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;;\nA40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;;\nA40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;;\nA40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;;\nA40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;;\nA410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;;\nA411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;;\nA412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;;\nA413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;;\nA414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;;\nA415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;;\nA416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;;\nA417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;;\nA418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;;\nA419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;;\nA41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;;\nA41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;;\nA41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;;\nA41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;;\nA41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;;\nA41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;;\nA420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;;\nA421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;;\nA422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;;\nA423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;;\nA424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;;\nA425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;;\nA426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;;\nA427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;;\nA428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;;\nA429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;;\nA42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;;\nA42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;;\nA42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;;\nA42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;;\nA42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;;\nA42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;;\nA430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;;\nA431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;;\nA432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;;\nA433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;;\nA434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;;\nA435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;;\nA436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;;\nA437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;;\nA438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;;\nA439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;;\nA43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;;\nA43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;;\nA43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;;\nA43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;;\nA43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;;\nA43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;;\nA440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;;\nA441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;;\nA442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;;\nA443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;;\nA444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;;\nA445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;;\nA446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;;\nA447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;;\nA448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;;\nA449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;;\nA44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;;\nA44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;;\nA44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;;\nA44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;;\nA44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;;\nA44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;;\nA450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;;\nA451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;;\nA452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;;\nA453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;;\nA454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;;\nA455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;;\nA456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;;\nA457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;;\nA458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;;\nA459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;;\nA45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;;\nA45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;;\nA45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;;\nA45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;;\nA45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;;\nA45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;;\nA460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;;\nA461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;;\nA462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;;\nA463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;;\nA464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;;\nA465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;;\nA466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;;\nA467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;;\nA468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;;\nA469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;;\nA46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;;\nA46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;;\nA46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;;\nA46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;;\nA46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;;\nA46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;;\nA470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;;\nA471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;;\nA472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;;\nA473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;;\nA474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;;\nA475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;;\nA476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;;\nA477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;;\nA478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;;\nA479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;;\nA47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;;\nA47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;;\nA47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;;\nA47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;;\nA47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;;\nA47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;;\nA480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;;\nA481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;;\nA482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;;\nA483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;;\nA484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;;\nA485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;;\nA486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;;\nA487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;;\nA488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;;\nA489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;;\nA48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;;\nA48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;;\nA48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;;\nA490;YI RADICAL QOT;So;0;ON;;;;;N;;;;;\nA491;YI RADICAL LI;So;0;ON;;;;;N;;;;;\nA492;YI RADICAL KIT;So;0;ON;;;;;N;;;;;\nA493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;;\nA494;YI RADICAL CYP;So;0;ON;;;;;N;;;;;\nA495;YI RADICAL SSI;So;0;ON;;;;;N;;;;;\nA496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;;\nA497;YI RADICAL GEP;So;0;ON;;;;;N;;;;;\nA498;YI RADICAL MI;So;0;ON;;;;;N;;;;;\nA499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;;\nA49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;;\nA49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;;\nA49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;;\nA49D;YI RADICAL YO;So;0;ON;;;;;N;;;;;\nA49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;;\nA49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;;\nA4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;;\nA4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;;\nA4A2;YI RADICAL ZUP;So;0;ON;;;;;N;;;;;\nA4A3;YI RADICAL CYT;So;0;ON;;;;;N;;;;;\nA4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;;\nA4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;;\nA4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;;\nA4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;;\nA4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;;\nA4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;;\nA4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;;\nA4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;;\nA4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;;\nA4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;;\nA4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;;\nA4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;;\nA4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;;\nA4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;;\nA4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;;\nA4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;;\nA4B4;YI RADICAL NZUP;So;0;ON;;;;;N;;;;;\nA4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;;\nA4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;;\nA4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;;\nA4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;;\nA4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;;\nA4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;;\nA4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;;\nA4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;;\nA4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;;\nA4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;;\nA4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;;\nA4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;;\nA4C1;YI RADICAL ZUR;So;0;ON;;;;;N;;;;;\nA4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;;\nA4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;;\nA4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;;\nA4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;;\nA4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;;\nA4D0;LISU LETTER BA;Lo;0;L;;;;;N;;;;;\nA4D1;LISU LETTER PA;Lo;0;L;;;;;N;;;;;\nA4D2;LISU LETTER PHA;Lo;0;L;;;;;N;;;;;\nA4D3;LISU LETTER DA;Lo;0;L;;;;;N;;;;;\nA4D4;LISU LETTER TA;Lo;0;L;;;;;N;;;;;\nA4D5;LISU LETTER THA;Lo;0;L;;;;;N;;;;;\nA4D6;LISU LETTER GA;Lo;0;L;;;;;N;;;;;\nA4D7;LISU LETTER KA;Lo;0;L;;;;;N;;;;;\nA4D8;LISU LETTER KHA;Lo;0;L;;;;;N;;;;;\nA4D9;LISU LETTER JA;Lo;0;L;;;;;N;;;;;\nA4DA;LISU LETTER CA;Lo;0;L;;;;;N;;;;;\nA4DB;LISU LETTER CHA;Lo;0;L;;;;;N;;;;;\nA4DC;LISU LETTER DZA;Lo;0;L;;;;;N;;;;;\nA4DD;LISU LETTER TSA;Lo;0;L;;;;;N;;;;;\nA4DE;LISU LETTER TSHA;Lo;0;L;;;;;N;;;;;\nA4DF;LISU LETTER MA;Lo;0;L;;;;;N;;;;;\nA4E0;LISU LETTER NA;Lo;0;L;;;;;N;;;;;\nA4E1;LISU LETTER LA;Lo;0;L;;;;;N;;;;;\nA4E2;LISU LETTER SA;Lo;0;L;;;;;N;;;;;\nA4E3;LISU LETTER ZHA;Lo;0;L;;;;;N;;;;;\nA4E4;LISU LETTER ZA;Lo;0;L;;;;;N;;;;;\nA4E5;LISU LETTER NGA;Lo;0;L;;;;;N;;;;;\nA4E6;LISU LETTER HA;Lo;0;L;;;;;N;;;;;\nA4E7;LISU LETTER XA;Lo;0;L;;;;;N;;;;;\nA4E8;LISU LETTER HHA;Lo;0;L;;;;;N;;;;;\nA4E9;LISU LETTER FA;Lo;0;L;;;;;N;;;;;\nA4EA;LISU LETTER WA;Lo;0;L;;;;;N;;;;;\nA4EB;LISU LETTER SHA;Lo;0;L;;;;;N;;;;;\nA4EC;LISU LETTER YA;Lo;0;L;;;;;N;;;;;\nA4ED;LISU LETTER GHA;Lo;0;L;;;;;N;;;;;\nA4EE;LISU LETTER A;Lo;0;L;;;;;N;;;;;\nA4EF;LISU LETTER AE;Lo;0;L;;;;;N;;;;;\nA4F0;LISU LETTER E;Lo;0;L;;;;;N;;;;;\nA4F1;LISU LETTER EU;Lo;0;L;;;;;N;;;;;\nA4F2;LISU LETTER I;Lo;0;L;;;;;N;;;;;\nA4F3;LISU LETTER O;Lo;0;L;;;;;N;;;;;\nA4F4;LISU LETTER U;Lo;0;L;;;;;N;;;;;\nA4F5;LISU LETTER UE;Lo;0;L;;;;;N;;;;;\nA4F6;LISU LETTER UH;Lo;0;L;;;;;N;;;;;\nA4F7;LISU LETTER OE;Lo;0;L;;;;;N;;;;;\nA4F8;LISU LETTER TONE MYA TI;Lm;0;L;;;;;N;;;;;\nA4F9;LISU LETTER TONE NA PO;Lm;0;L;;;;;N;;;;;\nA4FA;LISU LETTER TONE MYA CYA;Lm;0;L;;;;;N;;;;;\nA4FB;LISU LETTER TONE MYA BO;Lm;0;L;;;;;N;;;;;\nA4FC;LISU LETTER TONE MYA NA;Lm;0;L;;;;;N;;;;;\nA4FD;LISU LETTER TONE MYA JEU;Lm;0;L;;;;;N;;;;;\nA4FE;LISU PUNCTUATION COMMA;Po;0;L;;;;;N;;;;;\nA4FF;LISU PUNCTUATION FULL STOP;Po;0;L;;;;;N;;;;;\nA500;VAI SYLLABLE EE;Lo;0;L;;;;;N;;;;;\nA501;VAI SYLLABLE EEN;Lo;0;L;;;;;N;;;;;\nA502;VAI SYLLABLE HEE;Lo;0;L;;;;;N;;;;;\nA503;VAI SYLLABLE WEE;Lo;0;L;;;;;N;;;;;\nA504;VAI SYLLABLE WEEN;Lo;0;L;;;;;N;;;;;\nA505;VAI SYLLABLE PEE;Lo;0;L;;;;;N;;;;;\nA506;VAI SYLLABLE BHEE;Lo;0;L;;;;;N;;;;;\nA507;VAI SYLLABLE BEE;Lo;0;L;;;;;N;;;;;\nA508;VAI SYLLABLE MBEE;Lo;0;L;;;;;N;;;;;\nA509;VAI SYLLABLE KPEE;Lo;0;L;;;;;N;;;;;\nA50A;VAI SYLLABLE MGBEE;Lo;0;L;;;;;N;;;;;\nA50B;VAI SYLLABLE GBEE;Lo;0;L;;;;;N;;;;;\nA50C;VAI SYLLABLE FEE;Lo;0;L;;;;;N;;;;;\nA50D;VAI SYLLABLE VEE;Lo;0;L;;;;;N;;;;;\nA50E;VAI SYLLABLE TEE;Lo;0;L;;;;;N;;;;;\nA50F;VAI SYLLABLE THEE;Lo;0;L;;;;;N;;;;;\nA510;VAI SYLLABLE DHEE;Lo;0;L;;;;;N;;;;;\nA511;VAI SYLLABLE DHHEE;Lo;0;L;;;;;N;;;;;\nA512;VAI SYLLABLE LEE;Lo;0;L;;;;;N;;;;;\nA513;VAI SYLLABLE REE;Lo;0;L;;;;;N;;;;;\nA514;VAI SYLLABLE DEE;Lo;0;L;;;;;N;;;;;\nA515;VAI SYLLABLE NDEE;Lo;0;L;;;;;N;;;;;\nA516;VAI SYLLABLE SEE;Lo;0;L;;;;;N;;;;;\nA517;VAI SYLLABLE SHEE;Lo;0;L;;;;;N;;;;;\nA518;VAI SYLLABLE ZEE;Lo;0;L;;;;;N;;;;;\nA519;VAI SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;;\nA51A;VAI SYLLABLE CEE;Lo;0;L;;;;;N;;;;;\nA51B;VAI SYLLABLE JEE;Lo;0;L;;;;;N;;;;;\nA51C;VAI SYLLABLE NJEE;Lo;0;L;;;;;N;;;;;\nA51D;VAI SYLLABLE YEE;Lo;0;L;;;;;N;;;;;\nA51E;VAI SYLLABLE KEE;Lo;0;L;;;;;N;;;;;\nA51F;VAI SYLLABLE NGGEE;Lo;0;L;;;;;N;;;;;\nA520;VAI SYLLABLE GEE;Lo;0;L;;;;;N;;;;;\nA521;VAI SYLLABLE MEE;Lo;0;L;;;;;N;;;;;\nA522;VAI SYLLABLE NEE;Lo;0;L;;;;;N;;;;;\nA523;VAI SYLLABLE NYEE;Lo;0;L;;;;;N;;;;;\nA524;VAI SYLLABLE I;Lo;0;L;;;;;N;;;;;\nA525;VAI SYLLABLE IN;Lo;0;L;;;;;N;;;;;\nA526;VAI SYLLABLE HI;Lo;0;L;;;;;N;;;;;\nA527;VAI SYLLABLE HIN;Lo;0;L;;;;;N;;;;;\nA528;VAI SYLLABLE WI;Lo;0;L;;;;;N;;;;;\nA529;VAI SYLLABLE WIN;Lo;0;L;;;;;N;;;;;\nA52A;VAI SYLLABLE PI;Lo;0;L;;;;;N;;;;;\nA52B;VAI SYLLABLE BHI;Lo;0;L;;;;;N;;;;;\nA52C;VAI SYLLABLE BI;Lo;0;L;;;;;N;;;;;\nA52D;VAI SYLLABLE MBI;Lo;0;L;;;;;N;;;;;\nA52E;VAI SYLLABLE KPI;Lo;0;L;;;;;N;;;;;\nA52F;VAI SYLLABLE MGBI;Lo;0;L;;;;;N;;;;;\nA530;VAI SYLLABLE GBI;Lo;0;L;;;;;N;;;;;\nA531;VAI SYLLABLE FI;Lo;0;L;;;;;N;;;;;\nA532;VAI SYLLABLE VI;Lo;0;L;;;;;N;;;;;\nA533;VAI SYLLABLE TI;Lo;0;L;;;;;N;;;;;\nA534;VAI SYLLABLE THI;Lo;0;L;;;;;N;;;;;\nA535;VAI SYLLABLE DHI;Lo;0;L;;;;;N;;;;;\nA536;VAI SYLLABLE DHHI;Lo;0;L;;;;;N;;;;;\nA537;VAI SYLLABLE LI;Lo;0;L;;;;;N;;;;;\nA538;VAI SYLLABLE RI;Lo;0;L;;;;;N;;;;;\nA539;VAI SYLLABLE DI;Lo;0;L;;;;;N;;;;;\nA53A;VAI SYLLABLE NDI;Lo;0;L;;;;;N;;;;;\nA53B;VAI SYLLABLE SI;Lo;0;L;;;;;N;;;;;\nA53C;VAI SYLLABLE SHI;Lo;0;L;;;;;N;;;;;\nA53D;VAI SYLLABLE ZI;Lo;0;L;;;;;N;;;;;\nA53E;VAI SYLLABLE ZHI;Lo;0;L;;;;;N;;;;;\nA53F;VAI SYLLABLE CI;Lo;0;L;;;;;N;;;;;\nA540;VAI SYLLABLE JI;Lo;0;L;;;;;N;;;;;\nA541;VAI SYLLABLE NJI;Lo;0;L;;;;;N;;;;;\nA542;VAI SYLLABLE YI;Lo;0;L;;;;;N;;;;;\nA543;VAI SYLLABLE KI;Lo;0;L;;;;;N;;;;;\nA544;VAI SYLLABLE NGGI;Lo;0;L;;;;;N;;;;;\nA545;VAI SYLLABLE GI;Lo;0;L;;;;;N;;;;;\nA546;VAI SYLLABLE MI;Lo;0;L;;;;;N;;;;;\nA547;VAI SYLLABLE NI;Lo;0;L;;;;;N;;;;;\nA548;VAI SYLLABLE NYI;Lo;0;L;;;;;N;;;;;\nA549;VAI SYLLABLE A;Lo;0;L;;;;;N;;;;;\nA54A;VAI SYLLABLE AN;Lo;0;L;;;;;N;;;;;\nA54B;VAI SYLLABLE NGAN;Lo;0;L;;;;;N;;;;;\nA54C;VAI SYLLABLE HA;Lo;0;L;;;;;N;;;;;\nA54D;VAI SYLLABLE HAN;Lo;0;L;;;;;N;;;;;\nA54E;VAI SYLLABLE WA;Lo;0;L;;;;;N;;;;;\nA54F;VAI SYLLABLE WAN;Lo;0;L;;;;;N;;;;;\nA550;VAI SYLLABLE PA;Lo;0;L;;;;;N;;;;;\nA551;VAI SYLLABLE BHA;Lo;0;L;;;;;N;;;;;\nA552;VAI SYLLABLE BA;Lo;0;L;;;;;N;;;;;\nA553;VAI SYLLABLE MBA;Lo;0;L;;;;;N;;;;;\nA554;VAI SYLLABLE KPA;Lo;0;L;;;;;N;;;;;\nA555;VAI SYLLABLE KPAN;Lo;0;L;;;;;N;;;;;\nA556;VAI SYLLABLE MGBA;Lo;0;L;;;;;N;;;;;\nA557;VAI SYLLABLE GBA;Lo;0;L;;;;;N;;;;;\nA558;VAI SYLLABLE FA;Lo;0;L;;;;;N;;;;;\nA559;VAI SYLLABLE VA;Lo;0;L;;;;;N;;;;;\nA55A;VAI SYLLABLE TA;Lo;0;L;;;;;N;;;;;\nA55B;VAI SYLLABLE THA;Lo;0;L;;;;;N;;;;;\nA55C;VAI SYLLABLE DHA;Lo;0;L;;;;;N;;;;;\nA55D;VAI SYLLABLE DHHA;Lo;0;L;;;;;N;;;;;\nA55E;VAI SYLLABLE LA;Lo;0;L;;;;;N;;;;;\nA55F;VAI SYLLABLE RA;Lo;0;L;;;;;N;;;;;\nA560;VAI SYLLABLE DA;Lo;0;L;;;;;N;;;;;\nA561;VAI SYLLABLE NDA;Lo;0;L;;;;;N;;;;;\nA562;VAI SYLLABLE SA;Lo;0;L;;;;;N;;;;;\nA563;VAI SYLLABLE SHA;Lo;0;L;;;;;N;;;;;\nA564;VAI SYLLABLE ZA;Lo;0;L;;;;;N;;;;;\nA565;VAI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;\nA566;VAI SYLLABLE CA;Lo;0;L;;;;;N;;;;;\nA567;VAI SYLLABLE JA;Lo;0;L;;;;;N;;;;;\nA568;VAI SYLLABLE NJA;Lo;0;L;;;;;N;;;;;\nA569;VAI SYLLABLE YA;Lo;0;L;;;;;N;;;;;\nA56A;VAI SYLLABLE KA;Lo;0;L;;;;;N;;;;;\nA56B;VAI SYLLABLE KAN;Lo;0;L;;;;;N;;;;;\nA56C;VAI SYLLABLE NGGA;Lo;0;L;;;;;N;;;;;\nA56D;VAI SYLLABLE GA;Lo;0;L;;;;;N;;;;;\nA56E;VAI SYLLABLE MA;Lo;0;L;;;;;N;;;;;\nA56F;VAI SYLLABLE NA;Lo;0;L;;;;;N;;;;;\nA570;VAI SYLLABLE NYA;Lo;0;L;;;;;N;;;;;\nA571;VAI SYLLABLE OO;Lo;0;L;;;;;N;;;;;\nA572;VAI SYLLABLE OON;Lo;0;L;;;;;N;;;;;\nA573;VAI SYLLABLE HOO;Lo;0;L;;;;;N;;;;;\nA574;VAI SYLLABLE WOO;Lo;0;L;;;;;N;;;;;\nA575;VAI SYLLABLE WOON;Lo;0;L;;;;;N;;;;;\nA576;VAI SYLLABLE POO;Lo;0;L;;;;;N;;;;;\nA577;VAI SYLLABLE BHOO;Lo;0;L;;;;;N;;;;;\nA578;VAI SYLLABLE BOO;Lo;0;L;;;;;N;;;;;\nA579;VAI SYLLABLE MBOO;Lo;0;L;;;;;N;;;;;\nA57A;VAI SYLLABLE KPOO;Lo;0;L;;;;;N;;;;;\nA57B;VAI SYLLABLE MGBOO;Lo;0;L;;;;;N;;;;;\nA57C;VAI SYLLABLE GBOO;Lo;0;L;;;;;N;;;;;\nA57D;VAI SYLLABLE FOO;Lo;0;L;;;;;N;;;;;\nA57E;VAI SYLLABLE VOO;Lo;0;L;;;;;N;;;;;\nA57F;VAI SYLLABLE TOO;Lo;0;L;;;;;N;;;;;\nA580;VAI SYLLABLE THOO;Lo;0;L;;;;;N;;;;;\nA581;VAI SYLLABLE DHOO;Lo;0;L;;;;;N;;;;;\nA582;VAI SYLLABLE DHHOO;Lo;0;L;;;;;N;;;;;\nA583;VAI SYLLABLE LOO;Lo;0;L;;;;;N;;;;;\nA584;VAI SYLLABLE ROO;Lo;0;L;;;;;N;;;;;\nA585;VAI SYLLABLE DOO;Lo;0;L;;;;;N;;;;;\nA586;VAI SYLLABLE NDOO;Lo;0;L;;;;;N;;;;;\nA587;VAI SYLLABLE SOO;Lo;0;L;;;;;N;;;;;\nA588;VAI SYLLABLE SHOO;Lo;0;L;;;;;N;;;;;\nA589;VAI SYLLABLE ZOO;Lo;0;L;;;;;N;;;;;\nA58A;VAI SYLLABLE ZHOO;Lo;0;L;;;;;N;;;;;\nA58B;VAI SYLLABLE COO;Lo;0;L;;;;;N;;;;;\nA58C;VAI SYLLABLE JOO;Lo;0;L;;;;;N;;;;;\nA58D;VAI SYLLABLE NJOO;Lo;0;L;;;;;N;;;;;\nA58E;VAI SYLLABLE YOO;Lo;0;L;;;;;N;;;;;\nA58F;VAI SYLLABLE KOO;Lo;0;L;;;;;N;;;;;\nA590;VAI SYLLABLE NGGOO;Lo;0;L;;;;;N;;;;;\nA591;VAI SYLLABLE GOO;Lo;0;L;;;;;N;;;;;\nA592;VAI SYLLABLE MOO;Lo;0;L;;;;;N;;;;;\nA593;VAI SYLLABLE NOO;Lo;0;L;;;;;N;;;;;\nA594;VAI SYLLABLE NYOO;Lo;0;L;;;;;N;;;;;\nA595;VAI SYLLABLE U;Lo;0;L;;;;;N;;;;;\nA596;VAI SYLLABLE UN;Lo;0;L;;;;;N;;;;;\nA597;VAI SYLLABLE HU;Lo;0;L;;;;;N;;;;;\nA598;VAI SYLLABLE HUN;Lo;0;L;;;;;N;;;;;\nA599;VAI SYLLABLE WU;Lo;0;L;;;;;N;;;;;\nA59A;VAI SYLLABLE WUN;Lo;0;L;;;;;N;;;;;\nA59B;VAI SYLLABLE PU;Lo;0;L;;;;;N;;;;;\nA59C;VAI SYLLABLE BHU;Lo;0;L;;;;;N;;;;;\nA59D;VAI SYLLABLE BU;Lo;0;L;;;;;N;;;;;\nA59E;VAI SYLLABLE MBU;Lo;0;L;;;;;N;;;;;\nA59F;VAI SYLLABLE KPU;Lo;0;L;;;;;N;;;;;\nA5A0;VAI SYLLABLE MGBU;Lo;0;L;;;;;N;;;;;\nA5A1;VAI SYLLABLE GBU;Lo;0;L;;;;;N;;;;;\nA5A2;VAI SYLLABLE FU;Lo;0;L;;;;;N;;;;;\nA5A3;VAI SYLLABLE VU;Lo;0;L;;;;;N;;;;;\nA5A4;VAI SYLLABLE TU;Lo;0;L;;;;;N;;;;;\nA5A5;VAI SYLLABLE THU;Lo;0;L;;;;;N;;;;;\nA5A6;VAI SYLLABLE DHU;Lo;0;L;;;;;N;;;;;\nA5A7;VAI SYLLABLE DHHU;Lo;0;L;;;;;N;;;;;\nA5A8;VAI SYLLABLE LU;Lo;0;L;;;;;N;;;;;\nA5A9;VAI SYLLABLE RU;Lo;0;L;;;;;N;;;;;\nA5AA;VAI SYLLABLE DU;Lo;0;L;;;;;N;;;;;\nA5AB;VAI SYLLABLE NDU;Lo;0;L;;;;;N;;;;;\nA5AC;VAI SYLLABLE SU;Lo;0;L;;;;;N;;;;;\nA5AD;VAI SYLLABLE SHU;Lo;0;L;;;;;N;;;;;\nA5AE;VAI SYLLABLE ZU;Lo;0;L;;;;;N;;;;;\nA5AF;VAI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;\nA5B0;VAI SYLLABLE CU;Lo;0;L;;;;;N;;;;;\nA5B1;VAI SYLLABLE JU;Lo;0;L;;;;;N;;;;;\nA5B2;VAI SYLLABLE NJU;Lo;0;L;;;;;N;;;;;\nA5B3;VAI SYLLABLE YU;Lo;0;L;;;;;N;;;;;\nA5B4;VAI SYLLABLE KU;Lo;0;L;;;;;N;;;;;\nA5B5;VAI SYLLABLE NGGU;Lo;0;L;;;;;N;;;;;\nA5B6;VAI SYLLABLE GU;Lo;0;L;;;;;N;;;;;\nA5B7;VAI SYLLABLE MU;Lo;0;L;;;;;N;;;;;\nA5B8;VAI SYLLABLE NU;Lo;0;L;;;;;N;;;;;\nA5B9;VAI SYLLABLE NYU;Lo;0;L;;;;;N;;;;;\nA5BA;VAI SYLLABLE O;Lo;0;L;;;;;N;;;;;\nA5BB;VAI SYLLABLE ON;Lo;0;L;;;;;N;;;;;\nA5BC;VAI SYLLABLE NGON;Lo;0;L;;;;;N;;;;;\nA5BD;VAI SYLLABLE HO;Lo;0;L;;;;;N;;;;;\nA5BE;VAI SYLLABLE HON;Lo;0;L;;;;;N;;;;;\nA5BF;VAI SYLLABLE WO;Lo;0;L;;;;;N;;;;;\nA5C0;VAI SYLLABLE WON;Lo;0;L;;;;;N;;;;;\nA5C1;VAI SYLLABLE PO;Lo;0;L;;;;;N;;;;;\nA5C2;VAI SYLLABLE BHO;Lo;0;L;;;;;N;;;;;\nA5C3;VAI SYLLABLE BO;Lo;0;L;;;;;N;;;;;\nA5C4;VAI SYLLABLE MBO;Lo;0;L;;;;;N;;;;;\nA5C5;VAI SYLLABLE KPO;Lo;0;L;;;;;N;;;;;\nA5C6;VAI SYLLABLE MGBO;Lo;0;L;;;;;N;;;;;\nA5C7;VAI SYLLABLE GBO;Lo;0;L;;;;;N;;;;;\nA5C8;VAI SYLLABLE GBON;Lo;0;L;;;;;N;;;;;\nA5C9;VAI SYLLABLE FO;Lo;0;L;;;;;N;;;;;\nA5CA;VAI SYLLABLE VO;Lo;0;L;;;;;N;;;;;\nA5CB;VAI SYLLABLE TO;Lo;0;L;;;;;N;;;;;\nA5CC;VAI SYLLABLE THO;Lo;0;L;;;;;N;;;;;\nA5CD;VAI SYLLABLE DHO;Lo;0;L;;;;;N;;;;;\nA5CE;VAI SYLLABLE DHHO;Lo;0;L;;;;;N;;;;;\nA5CF;VAI SYLLABLE LO;Lo;0;L;;;;;N;;;;;\nA5D0;VAI SYLLABLE RO;Lo;0;L;;;;;N;;;;;\nA5D1;VAI SYLLABLE DO;Lo;0;L;;;;;N;;;;;\nA5D2;VAI SYLLABLE NDO;Lo;0;L;;;;;N;;;;;\nA5D3;VAI SYLLABLE SO;Lo;0;L;;;;;N;;;;;\nA5D4;VAI SYLLABLE SHO;Lo;0;L;;;;;N;;;;;\nA5D5;VAI SYLLABLE ZO;Lo;0;L;;;;;N;;;;;\nA5D6;VAI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;\nA5D7;VAI SYLLABLE CO;Lo;0;L;;;;;N;;;;;\nA5D8;VAI SYLLABLE JO;Lo;0;L;;;;;N;;;;;\nA5D9;VAI SYLLABLE NJO;Lo;0;L;;;;;N;;;;;\nA5DA;VAI SYLLABLE YO;Lo;0;L;;;;;N;;;;;\nA5DB;VAI SYLLABLE KO;Lo;0;L;;;;;N;;;;;\nA5DC;VAI SYLLABLE NGGO;Lo;0;L;;;;;N;;;;;\nA5DD;VAI SYLLABLE GO;Lo;0;L;;;;;N;;;;;\nA5DE;VAI SYLLABLE MO;Lo;0;L;;;;;N;;;;;\nA5DF;VAI SYLLABLE NO;Lo;0;L;;;;;N;;;;;\nA5E0;VAI SYLLABLE NYO;Lo;0;L;;;;;N;;;;;\nA5E1;VAI SYLLABLE E;Lo;0;L;;;;;N;;;;;\nA5E2;VAI SYLLABLE EN;Lo;0;L;;;;;N;;;;;\nA5E3;VAI SYLLABLE NGEN;Lo;0;L;;;;;N;;;;;\nA5E4;VAI SYLLABLE HE;Lo;0;L;;;;;N;;;;;\nA5E5;VAI SYLLABLE HEN;Lo;0;L;;;;;N;;;;;\nA5E6;VAI SYLLABLE WE;Lo;0;L;;;;;N;;;;;\nA5E7;VAI SYLLABLE WEN;Lo;0;L;;;;;N;;;;;\nA5E8;VAI SYLLABLE PE;Lo;0;L;;;;;N;;;;;\nA5E9;VAI SYLLABLE BHE;Lo;0;L;;;;;N;;;;;\nA5EA;VAI SYLLABLE BE;Lo;0;L;;;;;N;;;;;\nA5EB;VAI SYLLABLE MBE;Lo;0;L;;;;;N;;;;;\nA5EC;VAI SYLLABLE KPE;Lo;0;L;;;;;N;;;;;\nA5ED;VAI SYLLABLE KPEN;Lo;0;L;;;;;N;;;;;\nA5EE;VAI SYLLABLE MGBE;Lo;0;L;;;;;N;;;;;\nA5EF;VAI SYLLABLE GBE;Lo;0;L;;;;;N;;;;;\nA5F0;VAI SYLLABLE GBEN;Lo;0;L;;;;;N;;;;;\nA5F1;VAI SYLLABLE FE;Lo;0;L;;;;;N;;;;;\nA5F2;VAI SYLLABLE VE;Lo;0;L;;;;;N;;;;;\nA5F3;VAI SYLLABLE TE;Lo;0;L;;;;;N;;;;;\nA5F4;VAI SYLLABLE THE;Lo;0;L;;;;;N;;;;;\nA5F5;VAI SYLLABLE DHE;Lo;0;L;;;;;N;;;;;\nA5F6;VAI SYLLABLE DHHE;Lo;0;L;;;;;N;;;;;\nA5F7;VAI SYLLABLE LE;Lo;0;L;;;;;N;;;;;\nA5F8;VAI SYLLABLE RE;Lo;0;L;;;;;N;;;;;\nA5F9;VAI SYLLABLE DE;Lo;0;L;;;;;N;;;;;\nA5FA;VAI SYLLABLE NDE;Lo;0;L;;;;;N;;;;;\nA5FB;VAI SYLLABLE SE;Lo;0;L;;;;;N;;;;;\nA5FC;VAI SYLLABLE SHE;Lo;0;L;;;;;N;;;;;\nA5FD;VAI SYLLABLE ZE;Lo;0;L;;;;;N;;;;;\nA5FE;VAI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;\nA5FF;VAI SYLLABLE CE;Lo;0;L;;;;;N;;;;;\nA600;VAI SYLLABLE JE;Lo;0;L;;;;;N;;;;;\nA601;VAI SYLLABLE NJE;Lo;0;L;;;;;N;;;;;\nA602;VAI SYLLABLE YE;Lo;0;L;;;;;N;;;;;\nA603;VAI SYLLABLE KE;Lo;0;L;;;;;N;;;;;\nA604;VAI SYLLABLE NGGE;Lo;0;L;;;;;N;;;;;\nA605;VAI SYLLABLE NGGEN;Lo;0;L;;;;;N;;;;;\nA606;VAI SYLLABLE GE;Lo;0;L;;;;;N;;;;;\nA607;VAI SYLLABLE GEN;Lo;0;L;;;;;N;;;;;\nA608;VAI SYLLABLE ME;Lo;0;L;;;;;N;;;;;\nA609;VAI SYLLABLE NE;Lo;0;L;;;;;N;;;;;\nA60A;VAI SYLLABLE NYE;Lo;0;L;;;;;N;;;;;\nA60B;VAI SYLLABLE NG;Lo;0;L;;;;;N;;;;;\nA60C;VAI SYLLABLE LENGTHENER;Lm;0;L;;;;;N;;;;;\nA60D;VAI COMMA;Po;0;ON;;;;;N;;;;;\nA60E;VAI FULL STOP;Po;0;ON;;;;;N;;;;;\nA60F;VAI QUESTION MARK;Po;0;ON;;;;;N;;;;;\nA610;VAI SYLLABLE NDOLE FA;Lo;0;L;;;;;N;;;;;\nA611;VAI SYLLABLE NDOLE KA;Lo;0;L;;;;;N;;;;;\nA612;VAI SYLLABLE NDOLE SOO;Lo;0;L;;;;;N;;;;;\nA613;VAI SYMBOL FEENG;Lo;0;L;;;;;N;;;;;\nA614;VAI SYMBOL KEENG;Lo;0;L;;;;;N;;;;;\nA615;VAI SYMBOL TING;Lo;0;L;;;;;N;;;;;\nA616;VAI SYMBOL NII;Lo;0;L;;;;;N;;;;;\nA617;VAI SYMBOL BANG;Lo;0;L;;;;;N;;;;;\nA618;VAI SYMBOL FAA;Lo;0;L;;;;;N;;;;;\nA619;VAI SYMBOL TAA;Lo;0;L;;;;;N;;;;;\nA61A;VAI SYMBOL DANG;Lo;0;L;;;;;N;;;;;\nA61B;VAI SYMBOL DOONG;Lo;0;L;;;;;N;;;;;\nA61C;VAI SYMBOL KUNG;Lo;0;L;;;;;N;;;;;\nA61D;VAI SYMBOL TONG;Lo;0;L;;;;;N;;;;;\nA61E;VAI SYMBOL DO-O;Lo;0;L;;;;;N;;;;;\nA61F;VAI SYMBOL JONG;Lo;0;L;;;;;N;;;;;\nA620;VAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\nA621;VAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\nA622;VAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\nA623;VAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\nA624;VAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\nA625;VAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\nA626;VAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\nA627;VAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\nA628;VAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\nA629;VAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\nA62A;VAI SYLLABLE NDOLE MA;Lo;0;L;;;;;N;;;;;\nA62B;VAI SYLLABLE NDOLE DO;Lo;0;L;;;;;N;;;;;\nA640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641;\nA641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640\nA642;CYRILLIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;A643;\nA643;CYRILLIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;A642;;A642\nA644;CYRILLIC CAPITAL LETTER REVERSED DZE;Lu;0;L;;;;;N;;;;A645;\nA645;CYRILLIC SMALL LETTER REVERSED DZE;Ll;0;L;;;;;N;;;A644;;A644\nA646;CYRILLIC CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;A647;\nA647;CYRILLIC SMALL LETTER IOTA;Ll;0;L;;;;;N;;;A646;;A646\nA648;CYRILLIC CAPITAL LETTER DJERV;Lu;0;L;;;;;N;;;;A649;\nA649;CYRILLIC SMALL LETTER DJERV;Ll;0;L;;;;;N;;;A648;;A648\nA64A;CYRILLIC CAPITAL LETTER MONOGRAPH UK;Lu;0;L;;;;;N;;;;A64B;\nA64B;CYRILLIC SMALL LETTER MONOGRAPH UK;Ll;0;L;;;;;N;;;A64A;;A64A\nA64C;CYRILLIC CAPITAL LETTER BROAD OMEGA;Lu;0;L;;;;;N;;;;A64D;\nA64D;CYRILLIC SMALL LETTER BROAD OMEGA;Ll;0;L;;;;;N;;;A64C;;A64C\nA64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F;\nA64F;CYRILLIC SMALL LETTER NEUTRAL YER;Ll;0;L;;;;;N;;;A64E;;A64E\nA650;CYRILLIC CAPITAL LETTER YERU WITH BACK YER;Lu;0;L;;;;;N;;;;A651;\nA651;CYRILLIC SMALL LETTER YERU WITH BACK YER;Ll;0;L;;;;;N;;;A650;;A650\nA652;CYRILLIC CAPITAL LETTER IOTIFIED YAT;Lu;0;L;;;;;N;;;;A653;\nA653;CYRILLIC SMALL LETTER IOTIFIED YAT;Ll;0;L;;;;;N;;;A652;;A652\nA654;CYRILLIC CAPITAL LETTER REVERSED YU;Lu;0;L;;;;;N;;;;A655;\nA655;CYRILLIC SMALL LETTER REVERSED YU;Ll;0;L;;;;;N;;;A654;;A654\nA656;CYRILLIC CAPITAL LETTER IOTIFIED A;Lu;0;L;;;;;N;;;;A657;\nA657;CYRILLIC SMALL LETTER IOTIFIED A;Ll;0;L;;;;;N;;;A656;;A656\nA658;CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A659;\nA659;CYRILLIC SMALL LETTER CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A658;;A658\nA65A;CYRILLIC CAPITAL LETTER BLENDED YUS;Lu;0;L;;;;;N;;;;A65B;\nA65B;CYRILLIC SMALL LETTER BLENDED YUS;Ll;0;L;;;;;N;;;A65A;;A65A\nA65C;CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A65D;\nA65D;CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A65C;;A65C\nA65E;CYRILLIC CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;A65F;\nA65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E\nA660;CYRILLIC CAPITAL LETTER REVERSED TSE;Lu;0;L;;;;;N;;;;A661;\nA661;CYRILLIC SMALL LETTER REVERSED TSE;Ll;0;L;;;;;N;;;A660;;A660\nA662;CYRILLIC CAPITAL LETTER SOFT DE;Lu;0;L;;;;;N;;;;A663;\nA663;CYRILLIC SMALL LETTER SOFT DE;Ll;0;L;;;;;N;;;A662;;A662\nA664;CYRILLIC CAPITAL LETTER SOFT EL;Lu;0;L;;;;;N;;;;A665;\nA665;CYRILLIC SMALL LETTER SOFT EL;Ll;0;L;;;;;N;;;A664;;A664\nA666;CYRILLIC CAPITAL LETTER SOFT EM;Lu;0;L;;;;;N;;;;A667;\nA667;CYRILLIC SMALL LETTER SOFT EM;Ll;0;L;;;;;N;;;A666;;A666\nA668;CYRILLIC CAPITAL LETTER MONOCULAR O;Lu;0;L;;;;;N;;;;A669;\nA669;CYRILLIC SMALL LETTER MONOCULAR O;Ll;0;L;;;;;N;;;A668;;A668\nA66A;CYRILLIC CAPITAL LETTER BINOCULAR O;Lu;0;L;;;;;N;;;;A66B;\nA66B;CYRILLIC SMALL LETTER BINOCULAR O;Ll;0;L;;;;;N;;;A66A;;A66A\nA66C;CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O;Lu;0;L;;;;;N;;;;A66D;\nA66D;CYRILLIC SMALL LETTER DOUBLE MONOCULAR O;Ll;0;L;;;;;N;;;A66C;;A66C\nA66E;CYRILLIC LETTER MULTIOCULAR O;Lo;0;L;;;;;N;;;;;\nA66F;COMBINING CYRILLIC VZMET;Mn;230;NSM;;;;;N;;;;;\nA670;COMBINING CYRILLIC TEN MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;\nA671;COMBINING CYRILLIC HUNDRED MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;\nA672;COMBINING CYRILLIC THOUSAND MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;\nA673;SLAVONIC ASTERISK;Po;0;ON;;;;;N;;;;;\nA674;COMBINING CYRILLIC LETTER UKRAINIAN IE;Mn;230;NSM;;;;;N;;;;;\nA675;COMBINING CYRILLIC LETTER I;Mn;230;NSM;;;;;N;;;;;\nA676;COMBINING CYRILLIC LETTER YI;Mn;230;NSM;;;;;N;;;;;\nA677;COMBINING CYRILLIC LETTER U;Mn;230;NSM;;;;;N;;;;;\nA678;COMBINING CYRILLIC LETTER HARD SIGN;Mn;230;NSM;;;;;N;;;;;\nA679;COMBINING CYRILLIC LETTER YERU;Mn;230;NSM;;;;;N;;;;;\nA67A;COMBINING CYRILLIC LETTER SOFT SIGN;Mn;230;NSM;;;;;N;;;;;\nA67B;COMBINING CYRILLIC LETTER OMEGA;Mn;230;NSM;;;;;N;;;;;\nA67C;COMBINING CYRILLIC KAVYKA;Mn;230;NSM;;;;;N;;;;;\nA67D;COMBINING CYRILLIC PAYEROK;Mn;230;NSM;;;;;N;;;;;\nA67E;CYRILLIC KAVYKA;Po;0;ON;;;;;N;;;;;\nA67F;CYRILLIC PAYEROK;Lm;0;ON;;;;;N;;;;;\nA680;CYRILLIC CAPITAL LETTER DWE;Lu;0;L;;;;;N;;;;A681;\nA681;CYRILLIC SMALL LETTER DWE;Ll;0;L;;;;;N;;;A680;;A680\nA682;CYRILLIC CAPITAL LETTER DZWE;Lu;0;L;;;;;N;;;;A683;\nA683;CYRILLIC SMALL LETTER DZWE;Ll;0;L;;;;;N;;;A682;;A682\nA684;CYRILLIC CAPITAL LETTER ZHWE;Lu;0;L;;;;;N;;;;A685;\nA685;CYRILLIC SMALL LETTER ZHWE;Ll;0;L;;;;;N;;;A684;;A684\nA686;CYRILLIC CAPITAL LETTER CCHE;Lu;0;L;;;;;N;;;;A687;\nA687;CYRILLIC SMALL LETTER CCHE;Ll;0;L;;;;;N;;;A686;;A686\nA688;CYRILLIC CAPITAL LETTER DZZE;Lu;0;L;;;;;N;;;;A689;\nA689;CYRILLIC SMALL LETTER DZZE;Ll;0;L;;;;;N;;;A688;;A688\nA68A;CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;A68B;\nA68B;CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;A68A;;A68A\nA68C;CYRILLIC CAPITAL LETTER TWE;Lu;0;L;;;;;N;;;;A68D;\nA68D;CYRILLIC SMALL LETTER TWE;Ll;0;L;;;;;N;;;A68C;;A68C\nA68E;CYRILLIC CAPITAL LETTER TSWE;Lu;0;L;;;;;N;;;;A68F;\nA68F;CYRILLIC SMALL LETTER TSWE;Ll;0;L;;;;;N;;;A68E;;A68E\nA690;CYRILLIC CAPITAL LETTER TSSE;Lu;0;L;;;;;N;;;;A691;\nA691;CYRILLIC SMALL LETTER TSSE;Ll;0;L;;;;;N;;;A690;;A690\nA692;CYRILLIC CAPITAL LETTER TCHE;Lu;0;L;;;;;N;;;;A693;\nA693;CYRILLIC SMALL LETTER TCHE;Ll;0;L;;;;;N;;;A692;;A692\nA694;CYRILLIC CAPITAL LETTER HWE;Lu;0;L;;;;;N;;;;A695;\nA695;CYRILLIC SMALL LETTER HWE;Ll;0;L;;;;;N;;;A694;;A694\nA696;CYRILLIC CAPITAL LETTER SHWE;Lu;0;L;;;;;N;;;;A697;\nA697;CYRILLIC SMALL LETTER SHWE;Ll;0;L;;;;;N;;;A696;;A696\nA698;CYRILLIC CAPITAL LETTER DOUBLE O;Lu;0;L;;;;;N;;;;A699;\nA699;CYRILLIC SMALL LETTER DOUBLE O;Ll;0;L;;;;;N;;;A698;;A698\nA69A;CYRILLIC CAPITAL LETTER CROSSED O;Lu;0;L;;;;;N;;;;A69B;\nA69B;CYRILLIC SMALL LETTER CROSSED O;Ll;0;L;;;;;N;;;A69A;;A69A\nA69C;MODIFIER LETTER CYRILLIC HARD SIGN;Lm;0;L;<super> 044A;;;;N;;;;;\nA69D;MODIFIER LETTER CYRILLIC SOFT SIGN;Lm;0;L;<super> 044C;;;;N;;;;;\nA69E;COMBINING CYRILLIC LETTER EF;Mn;230;NSM;;;;;N;;;;;\nA69F;COMBINING CYRILLIC LETTER IOTIFIED E;Mn;230;NSM;;;;;N;;;;;\nA6A0;BAMUM LETTER A;Lo;0;L;;;;;N;;;;;\nA6A1;BAMUM LETTER KA;Lo;0;L;;;;;N;;;;;\nA6A2;BAMUM LETTER U;Lo;0;L;;;;;N;;;;;\nA6A3;BAMUM LETTER KU;Lo;0;L;;;;;N;;;;;\nA6A4;BAMUM LETTER EE;Lo;0;L;;;;;N;;;;;\nA6A5;BAMUM LETTER REE;Lo;0;L;;;;;N;;;;;\nA6A6;BAMUM LETTER TAE;Lo;0;L;;;;;N;;;;;\nA6A7;BAMUM LETTER O;Lo;0;L;;;;;N;;;;;\nA6A8;BAMUM LETTER NYI;Lo;0;L;;;;;N;;;;;\nA6A9;BAMUM LETTER I;Lo;0;L;;;;;N;;;;;\nA6AA;BAMUM LETTER LA;Lo;0;L;;;;;N;;;;;\nA6AB;BAMUM LETTER PA;Lo;0;L;;;;;N;;;;;\nA6AC;BAMUM LETTER RII;Lo;0;L;;;;;N;;;;;\nA6AD;BAMUM LETTER RIEE;Lo;0;L;;;;;N;;;;;\nA6AE;BAMUM LETTER LEEEE;Lo;0;L;;;;;N;;;;;\nA6AF;BAMUM LETTER MEEEE;Lo;0;L;;;;;N;;;;;\nA6B0;BAMUM LETTER TAA;Lo;0;L;;;;;N;;;;;\nA6B1;BAMUM LETTER NDAA;Lo;0;L;;;;;N;;;;;\nA6B2;BAMUM LETTER NJAEM;Lo;0;L;;;;;N;;;;;\nA6B3;BAMUM LETTER M;Lo;0;L;;;;;N;;;;;\nA6B4;BAMUM LETTER SUU;Lo;0;L;;;;;N;;;;;\nA6B5;BAMUM LETTER MU;Lo;0;L;;;;;N;;;;;\nA6B6;BAMUM LETTER SHII;Lo;0;L;;;;;N;;;;;\nA6B7;BAMUM LETTER SI;Lo;0;L;;;;;N;;;;;\nA6B8;BAMUM LETTER SHEUX;Lo;0;L;;;;;N;;;;;\nA6B9;BAMUM LETTER SEUX;Lo;0;L;;;;;N;;;;;\nA6BA;BAMUM LETTER KYEE;Lo;0;L;;;;;N;;;;;\nA6BB;BAMUM LETTER KET;Lo;0;L;;;;;N;;;;;\nA6BC;BAMUM LETTER NUAE;Lo;0;L;;;;;N;;;;;\nA6BD;BAMUM LETTER NU;Lo;0;L;;;;;N;;;;;\nA6BE;BAMUM LETTER NJUAE;Lo;0;L;;;;;N;;;;;\nA6BF;BAMUM LETTER YOQ;Lo;0;L;;;;;N;;;;;\nA6C0;BAMUM LETTER SHU;Lo;0;L;;;;;N;;;;;\nA6C1;BAMUM LETTER YUQ;Lo;0;L;;;;;N;;;;;\nA6C2;BAMUM LETTER YA;Lo;0;L;;;;;N;;;;;\nA6C3;BAMUM LETTER NSHA;Lo;0;L;;;;;N;;;;;\nA6C4;BAMUM LETTER KEUX;Lo;0;L;;;;;N;;;;;\nA6C5;BAMUM LETTER PEUX;Lo;0;L;;;;;N;;;;;\nA6C6;BAMUM LETTER NJEE;Lo;0;L;;;;;N;;;;;\nA6C7;BAMUM LETTER NTEE;Lo;0;L;;;;;N;;;;;\nA6C8;BAMUM LETTER PUE;Lo;0;L;;;;;N;;;;;\nA6C9;BAMUM LETTER WUE;Lo;0;L;;;;;N;;;;;\nA6CA;BAMUM LETTER PEE;Lo;0;L;;;;;N;;;;;\nA6CB;BAMUM LETTER FEE;Lo;0;L;;;;;N;;;;;\nA6CC;BAMUM LETTER RU;Lo;0;L;;;;;N;;;;;\nA6CD;BAMUM LETTER LU;Lo;0;L;;;;;N;;;;;\nA6CE;BAMUM LETTER MI;Lo;0;L;;;;;N;;;;;\nA6CF;BAMUM LETTER NI;Lo;0;L;;;;;N;;;;;\nA6D0;BAMUM LETTER REUX;Lo;0;L;;;;;N;;;;;\nA6D1;BAMUM LETTER RAE;Lo;0;L;;;;;N;;;;;\nA6D2;BAMUM LETTER KEN;Lo;0;L;;;;;N;;;;;\nA6D3;BAMUM LETTER NGKWAEN;Lo;0;L;;;;;N;;;;;\nA6D4;BAMUM LETTER NGGA;Lo;0;L;;;;;N;;;;;\nA6D5;BAMUM LETTER NGA;Lo;0;L;;;;;N;;;;;\nA6D6;BAMUM LETTER SHO;Lo;0;L;;;;;N;;;;;\nA6D7;BAMUM LETTER PUAE;Lo;0;L;;;;;N;;;;;\nA6D8;BAMUM LETTER FU;Lo;0;L;;;;;N;;;;;\nA6D9;BAMUM LETTER FOM;Lo;0;L;;;;;N;;;;;\nA6DA;BAMUM LETTER WA;Lo;0;L;;;;;N;;;;;\nA6DB;BAMUM LETTER NA;Lo;0;L;;;;;N;;;;;\nA6DC;BAMUM LETTER LI;Lo;0;L;;;;;N;;;;;\nA6DD;BAMUM LETTER PI;Lo;0;L;;;;;N;;;;;\nA6DE;BAMUM LETTER LOQ;Lo;0;L;;;;;N;;;;;\nA6DF;BAMUM LETTER KO;Lo;0;L;;;;;N;;;;;\nA6E0;BAMUM LETTER MBEN;Lo;0;L;;;;;N;;;;;\nA6E1;BAMUM LETTER REN;Lo;0;L;;;;;N;;;;;\nA6E2;BAMUM LETTER MEN;Lo;0;L;;;;;N;;;;;\nA6E3;BAMUM LETTER MA;Lo;0;L;;;;;N;;;;;\nA6E4;BAMUM LETTER TI;Lo;0;L;;;;;N;;;;;\nA6E5;BAMUM LETTER KI;Lo;0;L;;;;;N;;;;;\nA6E6;BAMUM LETTER MO;Nl;0;L;;;;1;N;;;;;\nA6E7;BAMUM LETTER MBAA;Nl;0;L;;;;2;N;;;;;\nA6E8;BAMUM LETTER TET;Nl;0;L;;;;3;N;;;;;\nA6E9;BAMUM LETTER KPA;Nl;0;L;;;;4;N;;;;;\nA6EA;BAMUM LETTER TEN;Nl;0;L;;;;5;N;;;;;\nA6EB;BAMUM LETTER NTUU;Nl;0;L;;;;6;N;;;;;\nA6EC;BAMUM LETTER SAMBA;Nl;0;L;;;;7;N;;;;;\nA6ED;BAMUM LETTER FAAMAE;Nl;0;L;;;;8;N;;;;;\nA6EE;BAMUM LETTER KOVUU;Nl;0;L;;;;9;N;;;;;\nA6EF;BAMUM LETTER KOGHOM;Nl;0;L;;;;0;N;;;;;\nA6F0;BAMUM COMBINING MARK KOQNDON;Mn;230;NSM;;;;;N;;;;;\nA6F1;BAMUM COMBINING MARK TUKWENTIS;Mn;230;NSM;;;;;N;;;;;\nA6F2;BAMUM NJAEMLI;Po;0;L;;;;;N;;;;;\nA6F3;BAMUM FULL STOP;Po;0;L;;;;;N;;;;;\nA6F4;BAMUM COLON;Po;0;L;;;;;N;;;;;\nA6F5;BAMUM COMMA;Po;0;L;;;;;N;;;;;\nA6F6;BAMUM SEMICOLON;Po;0;L;;;;;N;;;;;\nA6F7;BAMUM QUESTION MARK;Po;0;L;;;;;N;;;;;\nA700;MODIFIER LETTER CHINESE TONE YIN PING;Sk;0;ON;;;;;N;;;;;\nA701;MODIFIER LETTER CHINESE TONE YANG PING;Sk;0;ON;;;;;N;;;;;\nA702;MODIFIER LETTER CHINESE TONE YIN SHANG;Sk;0;ON;;;;;N;;;;;\nA703;MODIFIER LETTER CHINESE TONE YANG SHANG;Sk;0;ON;;;;;N;;;;;\nA704;MODIFIER LETTER CHINESE TONE YIN QU;Sk;0;ON;;;;;N;;;;;\nA705;MODIFIER LETTER CHINESE TONE YANG QU;Sk;0;ON;;;;;N;;;;;\nA706;MODIFIER LETTER CHINESE TONE YIN RU;Sk;0;ON;;;;;N;;;;;\nA707;MODIFIER LETTER CHINESE TONE YANG RU;Sk;0;ON;;;;;N;;;;;\nA708;MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;\nA709;MODIFIER LETTER HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;\nA70A;MODIFIER LETTER MID DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;\nA70B;MODIFIER LETTER LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;\nA70C;MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;\nA70D;MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA70E;MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA70F;MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA710;MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA711;MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA712;MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA713;MODIFIER LETTER HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA714;MODIFIER LETTER MID LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA715;MODIFIER LETTER LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA716;MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;\nA717;MODIFIER LETTER DOT VERTICAL BAR;Lm;0;ON;;;;;N;;;;;\nA718;MODIFIER LETTER DOT SLASH;Lm;0;ON;;;;;N;;;;;\nA719;MODIFIER LETTER DOT HORIZONTAL BAR;Lm;0;ON;;;;;N;;;;;\nA71A;MODIFIER LETTER LOWER RIGHT CORNER ANGLE;Lm;0;ON;;;;;N;;;;;\nA71B;MODIFIER LETTER RAISED UP ARROW;Lm;0;ON;;;;;N;;;;;\nA71C;MODIFIER LETTER RAISED DOWN ARROW;Lm;0;ON;;;;;N;;;;;\nA71D;MODIFIER LETTER RAISED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;;\nA71E;MODIFIER LETTER RAISED INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;;\nA71F;MODIFIER LETTER LOW INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;;\nA720;MODIFIER LETTER STRESS AND HIGH TONE;Sk;0;ON;;;;;N;;;;;\nA721;MODIFIER LETTER STRESS AND LOW TONE;Sk;0;ON;;;;;N;;;;;\nA722;LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF;Lu;0;L;;;;;N;;;;A723;\nA723;LATIN SMALL LETTER EGYPTOLOGICAL ALEF;Ll;0;L;;;;;N;;;A722;;A722\nA724;LATIN CAPITAL LETTER EGYPTOLOGICAL AIN;Lu;0;L;;;;;N;;;;A725;\nA725;LATIN SMALL LETTER EGYPTOLOGICAL AIN;Ll;0;L;;;;;N;;;A724;;A724\nA726;LATIN CAPITAL LETTER HENG;Lu;0;L;;;;;N;;;;A727;\nA727;LATIN SMALL LETTER HENG;Ll;0;L;;;;;N;;;A726;;A726\nA728;LATIN CAPITAL LETTER TZ;Lu;0;L;;;;;N;;;;A729;\nA729;LATIN SMALL LETTER TZ;Ll;0;L;;;;;N;;;A728;;A728\nA72A;LATIN CAPITAL LETTER TRESILLO;Lu;0;L;;;;;N;;;;A72B;\nA72B;LATIN SMALL LETTER TRESILLO;Ll;0;L;;;;;N;;;A72A;;A72A\nA72C;LATIN CAPITAL LETTER CUATRILLO;Lu;0;L;;;;;N;;;;A72D;\nA72D;LATIN SMALL LETTER CUATRILLO;Ll;0;L;;;;;N;;;A72C;;A72C\nA72E;LATIN CAPITAL LETTER CUATRILLO WITH COMMA;Lu;0;L;;;;;N;;;;A72F;\nA72F;LATIN SMALL LETTER CUATRILLO WITH COMMA;Ll;0;L;;;;;N;;;A72E;;A72E\nA730;LATIN LETTER SMALL CAPITAL F;Ll;0;L;;;;;N;;;;;\nA731;LATIN LETTER SMALL CAPITAL S;Ll;0;L;;;;;N;;;;;\nA732;LATIN CAPITAL LETTER AA;Lu;0;L;;;;;N;;;;A733;\nA733;LATIN SMALL LETTER AA;Ll;0;L;;;;;N;;;A732;;A732\nA734;LATIN CAPITAL LETTER AO;Lu;0;L;;;;;N;;;;A735;\nA735;LATIN SMALL LETTER AO;Ll;0;L;;;;;N;;;A734;;A734\nA736;LATIN CAPITAL LETTER AU;Lu;0;L;;;;;N;;;;A737;\nA737;LATIN SMALL LETTER AU;Ll;0;L;;;;;N;;;A736;;A736\nA738;LATIN CAPITAL LETTER AV;Lu;0;L;;;;;N;;;;A739;\nA739;LATIN SMALL LETTER AV;Ll;0;L;;;;;N;;;A738;;A738\nA73A;LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR;Lu;0;L;;;;;N;;;;A73B;\nA73B;LATIN SMALL LETTER AV WITH HORIZONTAL BAR;Ll;0;L;;;;;N;;;A73A;;A73A\nA73C;LATIN CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;A73D;\nA73D;LATIN SMALL LETTER AY;Ll;0;L;;;;;N;;;A73C;;A73C\nA73E;LATIN CAPITAL LETTER REVERSED C WITH DOT;Lu;0;L;;;;;N;;;;A73F;\nA73F;LATIN SMALL LETTER REVERSED C WITH DOT;Ll;0;L;;;;;N;;;A73E;;A73E\nA740;LATIN CAPITAL LETTER K WITH STROKE;Lu;0;L;;;;;N;;;;A741;\nA741;LATIN SMALL LETTER K WITH STROKE;Ll;0;L;;;;;N;;;A740;;A740\nA742;LATIN CAPITAL LETTER K WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A743;\nA743;LATIN SMALL LETTER K WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A742;;A742\nA744;LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A745;\nA745;LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE;Ll;0;L;;;;;N;;;A744;;A744\nA746;LATIN CAPITAL LETTER BROKEN L;Lu;0;L;;;;;N;;;;A747;\nA747;LATIN SMALL LETTER BROKEN L;Ll;0;L;;;;;N;;;A746;;A746\nA748;LATIN CAPITAL LETTER L WITH HIGH STROKE;Lu;0;L;;;;;N;;;;A749;\nA749;LATIN SMALL LETTER L WITH HIGH STROKE;Ll;0;L;;;;;N;;;A748;;A748\nA74A;LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY;Lu;0;L;;;;;N;;;;A74B;\nA74B;LATIN SMALL LETTER O WITH LONG STROKE OVERLAY;Ll;0;L;;;;;N;;;A74A;;A74A\nA74C;LATIN CAPITAL LETTER O WITH LOOP;Lu;0;L;;;;;N;;;;A74D;\nA74D;LATIN SMALL LETTER O WITH LOOP;Ll;0;L;;;;;N;;;A74C;;A74C\nA74E;LATIN CAPITAL LETTER OO;Lu;0;L;;;;;N;;;;A74F;\nA74F;LATIN SMALL LETTER OO;Ll;0;L;;;;;N;;;A74E;;A74E\nA750;LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A751;\nA751;LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A750;;A750\nA752;LATIN CAPITAL LETTER P WITH FLOURISH;Lu;0;L;;;;;N;;;;A753;\nA753;LATIN SMALL LETTER P WITH FLOURISH;Ll;0;L;;;;;N;;;A752;;A752\nA754;LATIN CAPITAL LETTER P WITH SQUIRREL TAIL;Lu;0;L;;;;;N;;;;A755;\nA755;LATIN SMALL LETTER P WITH SQUIRREL TAIL;Ll;0;L;;;;;N;;;A754;;A754\nA756;LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A757;\nA757;LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A756;;A756\nA758;LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A759;\nA759;LATIN SMALL LETTER Q WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A758;;A758\nA75A;LATIN CAPITAL LETTER R ROTUNDA;Lu;0;L;;;;;N;;;;A75B;\nA75B;LATIN SMALL LETTER R ROTUNDA;Ll;0;L;;;;;N;;;A75A;;A75A\nA75C;LATIN CAPITAL LETTER RUM ROTUNDA;Lu;0;L;;;;;N;;;;A75D;\nA75D;LATIN SMALL LETTER RUM ROTUNDA;Ll;0;L;;;;;N;;;A75C;;A75C\nA75E;LATIN CAPITAL LETTER V WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A75F;\nA75F;LATIN SMALL LETTER V WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A75E;;A75E\nA760;LATIN CAPITAL LETTER VY;Lu;0;L;;;;;N;;;;A761;\nA761;LATIN SMALL LETTER VY;Ll;0;L;;;;;N;;;A760;;A760\nA762;LATIN CAPITAL LETTER VISIGOTHIC Z;Lu;0;L;;;;;N;;;;A763;\nA763;LATIN SMALL LETTER VISIGOTHIC Z;Ll;0;L;;;;;N;;;A762;;A762\nA764;LATIN CAPITAL LETTER THORN WITH STROKE;Lu;0;L;;;;;N;;;;A765;\nA765;LATIN SMALL LETTER THORN WITH STROKE;Ll;0;L;;;;;N;;;A764;;A764\nA766;LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A767;\nA767;LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A766;;A766\nA768;LATIN CAPITAL LETTER VEND;Lu;0;L;;;;;N;;;;A769;\nA769;LATIN SMALL LETTER VEND;Ll;0;L;;;;;N;;;A768;;A768\nA76A;LATIN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;A76B;\nA76B;LATIN SMALL LETTER ET;Ll;0;L;;;;;N;;;A76A;;A76A\nA76C;LATIN CAPITAL LETTER IS;Lu;0;L;;;;;N;;;;A76D;\nA76D;LATIN SMALL LETTER IS;Ll;0;L;;;;;N;;;A76C;;A76C\nA76E;LATIN CAPITAL LETTER CON;Lu;0;L;;;;;N;;;;A76F;\nA76F;LATIN SMALL LETTER CON;Ll;0;L;;;;;N;;;A76E;;A76E\nA770;MODIFIER LETTER US;Lm;0;L;<super> A76F;;;;N;;;;;\nA771;LATIN SMALL LETTER DUM;Ll;0;L;;;;;N;;;;;\nA772;LATIN SMALL LETTER LUM;Ll;0;L;;;;;N;;;;;\nA773;LATIN SMALL LETTER MUM;Ll;0;L;;;;;N;;;;;\nA774;LATIN SMALL LETTER NUM;Ll;0;L;;;;;N;;;;;\nA775;LATIN SMALL LETTER RUM;Ll;0;L;;;;;N;;;;;\nA776;LATIN LETTER SMALL CAPITAL RUM;Ll;0;L;;;;;N;;;;;\nA777;LATIN SMALL LETTER TUM;Ll;0;L;;;;;N;;;;;\nA778;LATIN SMALL LETTER UM;Ll;0;L;;;;;N;;;;;\nA779;LATIN CAPITAL LETTER INSULAR D;Lu;0;L;;;;;N;;;;A77A;\nA77A;LATIN SMALL LETTER INSULAR D;Ll;0;L;;;;;N;;;A779;;A779\nA77B;LATIN CAPITAL LETTER INSULAR F;Lu;0;L;;;;;N;;;;A77C;\nA77C;LATIN SMALL LETTER INSULAR F;Ll;0;L;;;;;N;;;A77B;;A77B\nA77D;LATIN CAPITAL LETTER INSULAR G;Lu;0;L;;;;;N;;;;1D79;\nA77E;LATIN CAPITAL LETTER TURNED INSULAR G;Lu;0;L;;;;;N;;;;A77F;\nA77F;LATIN SMALL LETTER TURNED INSULAR G;Ll;0;L;;;;;N;;;A77E;;A77E\nA780;LATIN CAPITAL LETTER TURNED L;Lu;0;L;;;;;N;;;;A781;\nA781;LATIN SMALL LETTER TURNED L;Ll;0;L;;;;;N;;;A780;;A780\nA782;LATIN CAPITAL LETTER INSULAR R;Lu;0;L;;;;;N;;;;A783;\nA783;LATIN SMALL LETTER INSULAR R;Ll;0;L;;;;;N;;;A782;;A782\nA784;LATIN CAPITAL LETTER INSULAR S;Lu;0;L;;;;;N;;;;A785;\nA785;LATIN SMALL LETTER INSULAR S;Ll;0;L;;;;;N;;;A784;;A784\nA786;LATIN CAPITAL LETTER INSULAR T;Lu;0;L;;;;;N;;;;A787;\nA787;LATIN SMALL LETTER INSULAR T;Ll;0;L;;;;;N;;;A786;;A786\nA788;MODIFIER LETTER LOW CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;;;;;\nA789;MODIFIER LETTER COLON;Sk;0;L;;;;;N;;;;;\nA78A;MODIFIER LETTER SHORT EQUALS SIGN;Sk;0;L;;;;;N;;;;;\nA78B;LATIN CAPITAL LETTER SALTILLO;Lu;0;L;;;;;N;;;;A78C;\nA78C;LATIN SMALL LETTER SALTILLO;Ll;0;L;;;;;N;;;A78B;;A78B\nA78D;LATIN CAPITAL LETTER TURNED H;Lu;0;L;;;;;N;;;;0265;\nA78E;LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT;Ll;0;L;;;;;N;;;;;\nA78F;LATIN LETTER SINOLOGICAL DOT;Lo;0;L;;;;;N;;;;;\nA790;LATIN CAPITAL LETTER N WITH DESCENDER;Lu;0;L;;;;;N;;;;A791;\nA791;LATIN SMALL LETTER N WITH DESCENDER;Ll;0;L;;;;;N;;;A790;;A790\nA792;LATIN CAPITAL LETTER C WITH BAR;Lu;0;L;;;;;N;;;;A793;\nA793;LATIN SMALL LETTER C WITH BAR;Ll;0;L;;;;;N;;;A792;;A792\nA794;LATIN SMALL LETTER C WITH PALATAL HOOK;Ll;0;L;;;;;N;;;A7C4;;A7C4\nA795;LATIN SMALL LETTER H WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\nA796;LATIN CAPITAL LETTER B WITH FLOURISH;Lu;0;L;;;;;N;;;;A797;\nA797;LATIN SMALL LETTER B WITH FLOURISH;Ll;0;L;;;;;N;;;A796;;A796\nA798;LATIN CAPITAL LETTER F WITH STROKE;Lu;0;L;;;;;N;;;;A799;\nA799;LATIN SMALL LETTER F WITH STROKE;Ll;0;L;;;;;N;;;A798;;A798\nA79A;LATIN CAPITAL LETTER VOLAPUK AE;Lu;0;L;;;;;N;;;;A79B;\nA79B;LATIN SMALL LETTER VOLAPUK AE;Ll;0;L;;;;;N;;;A79A;;A79A\nA79C;LATIN CAPITAL LETTER VOLAPUK OE;Lu;0;L;;;;;N;;;;A79D;\nA79D;LATIN SMALL LETTER VOLAPUK OE;Ll;0;L;;;;;N;;;A79C;;A79C\nA79E;LATIN CAPITAL LETTER VOLAPUK UE;Lu;0;L;;;;;N;;;;A79F;\nA79F;LATIN SMALL LETTER VOLAPUK UE;Ll;0;L;;;;;N;;;A79E;;A79E\nA7A0;LATIN CAPITAL LETTER G WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A1;\nA7A1;LATIN SMALL LETTER G WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A0;;A7A0\nA7A2;LATIN CAPITAL LETTER K WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A3;\nA7A3;LATIN SMALL LETTER K WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A2;;A7A2\nA7A4;LATIN CAPITAL LETTER N WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A5;\nA7A5;LATIN SMALL LETTER N WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A4;;A7A4\nA7A6;LATIN CAPITAL LETTER R WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A7;\nA7A7;LATIN SMALL LETTER R WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A6;;A7A6\nA7A8;LATIN CAPITAL LETTER S WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A9;\nA7A9;LATIN SMALL LETTER S WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A8;;A7A8\nA7AA;LATIN CAPITAL LETTER H WITH HOOK;Lu;0;L;;;;;N;;;;0266;\nA7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C;\nA7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261;\nA7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C;\nA7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A;\nA7AF;LATIN LETTER SMALL CAPITAL Q;Ll;0;L;;;;;N;;;;;\nA7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E;\nA7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287;\nA7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D;\nA7B3;LATIN CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;AB53;\nA7B4;LATIN CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;A7B5;\nA7B5;LATIN SMALL LETTER BETA;Ll;0;L;;;;;N;;;A7B4;;A7B4\nA7B6;LATIN CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;A7B7;\nA7B7;LATIN SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;A7B6;;A7B6\nA7B8;LATIN CAPITAL LETTER U WITH STROKE;Lu;0;L;;;;;N;;;;A7B9;\nA7B9;LATIN SMALL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;A7B8;;A7B8\nA7BA;LATIN CAPITAL LETTER GLOTTAL A;Lu;0;L;;;;;N;;;;A7BB;\nA7BB;LATIN SMALL LETTER GLOTTAL A;Ll;0;L;;;;;N;;;A7BA;;A7BA\nA7BC;LATIN CAPITAL LETTER GLOTTAL I;Lu;0;L;;;;;N;;;;A7BD;\nA7BD;LATIN SMALL LETTER GLOTTAL I;Ll;0;L;;;;;N;;;A7BC;;A7BC\nA7BE;LATIN CAPITAL LETTER GLOTTAL U;Lu;0;L;;;;;N;;;;A7BF;\nA7BF;LATIN SMALL LETTER GLOTTAL U;Ll;0;L;;;;;N;;;A7BE;;A7BE\nA7C0;LATIN CAPITAL LETTER OLD POLISH O;Lu;0;L;;;;;N;;;;A7C1;\nA7C1;LATIN SMALL LETTER OLD POLISH O;Ll;0;L;;;;;N;;;A7C0;;A7C0\nA7C2;LATIN CAPITAL LETTER ANGLICANA W;Lu;0;L;;;;;N;;;;A7C3;\nA7C3;LATIN SMALL LETTER ANGLICANA W;Ll;0;L;;;;;N;;;A7C2;;A7C2\nA7C4;LATIN CAPITAL LETTER C WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;A794;\nA7C5;LATIN CAPITAL LETTER S WITH HOOK;Lu;0;L;;;;;N;;;;0282;\nA7C6;LATIN CAPITAL LETTER Z WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;1D8E;\nA7C7;LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7C8;\nA7C8;LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C7;;A7C7\nA7C9;LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7CA;\nA7CA;LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C9;;A7C9\nA7CB;LATIN CAPITAL LETTER RAMS HORN;Lu;0;L;;;;;N;;;;0264;\nA7CC;LATIN CAPITAL LETTER S WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A7CD;\nA7CD;LATIN SMALL LETTER S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A7CC;;A7CC\nA7CE;LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE;Lu;0;L;;;;;N;;;;A7CF;\nA7CF;LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;;;A7CE;;A7CE\nA7D0;LATIN CAPITAL LETTER CLOSED INSULAR G;Lu;0;L;;;;;N;;;;A7D1;\nA7D1;LATIN SMALL LETTER CLOSED INSULAR G;Ll;0;L;;;;;N;;;A7D0;;A7D0\nA7D2;LATIN CAPITAL LETTER DOUBLE THORN;Lu;0;L;;;;;N;;;;A7D3;\nA7D3;LATIN SMALL LETTER DOUBLE THORN;Ll;0;L;;;;;N;;;A7D2;;A7D2\nA7D4;LATIN CAPITAL LETTER DOUBLE WYNN;Lu;0;L;;;;;N;;;;A7D5;\nA7D5;LATIN SMALL LETTER DOUBLE WYNN;Ll;0;L;;;;;N;;;A7D4;;A7D4\nA7D6;LATIN CAPITAL LETTER MIDDLE SCOTS S;Lu;0;L;;;;;N;;;;A7D7;\nA7D7;LATIN SMALL LETTER MIDDLE SCOTS S;Ll;0;L;;;;;N;;;A7D6;;A7D6\nA7D8;LATIN CAPITAL LETTER SIGMOID S;Lu;0;L;;;;;N;;;;A7D9;\nA7D9;LATIN SMALL LETTER SIGMOID S;Ll;0;L;;;;;N;;;A7D8;;A7D8\nA7DA;LATIN CAPITAL LETTER LAMBDA;Lu;0;L;;;;;N;;;;A7DB;\nA7DB;LATIN SMALL LETTER LAMBDA;Ll;0;L;;;;;N;;;A7DA;;A7DA\nA7DC;LATIN CAPITAL LETTER LAMBDA WITH STROKE;Lu;0;L;;;;;N;;;;019B;\nA7F1;MODIFIER LETTER CAPITAL S;Lm;0;L;<super> 0053;;;;N;;;;;\nA7F2;MODIFIER LETTER CAPITAL C;Lm;0;L;<super> 0043;;;;N;;;;;\nA7F3;MODIFIER LETTER CAPITAL F;Lm;0;L;<super> 0046;;;;N;;;;;\nA7F4;MODIFIER LETTER CAPITAL Q;Lm;0;L;<super> 0051;;;;N;;;;;\nA7F5;LATIN CAPITAL LETTER REVERSED HALF H;Lu;0;L;;;;;N;;;;A7F6;\nA7F6;LATIN SMALL LETTER REVERSED HALF H;Ll;0;L;;;;;N;;;A7F5;;A7F5\nA7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;;\nA7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L;<super> 0126;;;;N;;;;;\nA7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L;<super> 0153;;;;N;;;;;\nA7FA;LATIN LETTER SMALL CAPITAL TURNED M;Ll;0;L;;;;;N;;;;;\nA7FB;LATIN EPIGRAPHIC LETTER REVERSED F;Lo;0;L;;;;;N;;;;;\nA7FC;LATIN EPIGRAPHIC LETTER REVERSED P;Lo;0;L;;;;;N;;;;;\nA7FD;LATIN EPIGRAPHIC LETTER INVERTED M;Lo;0;L;;;;;N;;;;;\nA7FE;LATIN EPIGRAPHIC LETTER I LONGA;Lo;0;L;;;;;N;;;;;\nA7FF;LATIN EPIGRAPHIC LETTER ARCHAIC M;Lo;0;L;;;;;N;;;;;\nA800;SYLOTI NAGRI LETTER A;Lo;0;L;;;;;N;;;;;\nA801;SYLOTI NAGRI LETTER I;Lo;0;L;;;;;N;;;;;\nA802;SYLOTI NAGRI SIGN DVISVARA;Mn;0;NSM;;;;;N;;;;;\nA803;SYLOTI NAGRI LETTER U;Lo;0;L;;;;;N;;;;;\nA804;SYLOTI NAGRI LETTER E;Lo;0;L;;;;;N;;;;;\nA805;SYLOTI NAGRI LETTER O;Lo;0;L;;;;;N;;;;;\nA806;SYLOTI NAGRI SIGN HASANTA;Mn;9;NSM;;;;;N;;;;;\nA807;SYLOTI NAGRI LETTER KO;Lo;0;L;;;;;N;;;;;\nA808;SYLOTI NAGRI LETTER KHO;Lo;0;L;;;;;N;;;;;\nA809;SYLOTI NAGRI LETTER GO;Lo;0;L;;;;;N;;;;;\nA80A;SYLOTI NAGRI LETTER GHO;Lo;0;L;;;;;N;;;;;\nA80B;SYLOTI NAGRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\nA80C;SYLOTI NAGRI LETTER CO;Lo;0;L;;;;;N;;;;;\nA80D;SYLOTI NAGRI LETTER CHO;Lo;0;L;;;;;N;;;;;\nA80E;SYLOTI NAGRI LETTER JO;Lo;0;L;;;;;N;;;;;\nA80F;SYLOTI NAGRI LETTER JHO;Lo;0;L;;;;;N;;;;;\nA810;SYLOTI NAGRI LETTER TTO;Lo;0;L;;;;;N;;;;;\nA811;SYLOTI NAGRI LETTER TTHO;Lo;0;L;;;;;N;;;;;\nA812;SYLOTI NAGRI LETTER DDO;Lo;0;L;;;;;N;;;;;\nA813;SYLOTI NAGRI LETTER DDHO;Lo;0;L;;;;;N;;;;;\nA814;SYLOTI NAGRI LETTER TO;Lo;0;L;;;;;N;;;;;\nA815;SYLOTI NAGRI LETTER THO;Lo;0;L;;;;;N;;;;;\nA816;SYLOTI NAGRI LETTER DO;Lo;0;L;;;;;N;;;;;\nA817;SYLOTI NAGRI LETTER DHO;Lo;0;L;;;;;N;;;;;\nA818;SYLOTI NAGRI LETTER NO;Lo;0;L;;;;;N;;;;;\nA819;SYLOTI NAGRI LETTER PO;Lo;0;L;;;;;N;;;;;\nA81A;SYLOTI NAGRI LETTER PHO;Lo;0;L;;;;;N;;;;;\nA81B;SYLOTI NAGRI LETTER BO;Lo;0;L;;;;;N;;;;;\nA81C;SYLOTI NAGRI LETTER BHO;Lo;0;L;;;;;N;;;;;\nA81D;SYLOTI NAGRI LETTER MO;Lo;0;L;;;;;N;;;;;\nA81E;SYLOTI NAGRI LETTER RO;Lo;0;L;;;;;N;;;;;\nA81F;SYLOTI NAGRI LETTER LO;Lo;0;L;;;;;N;;;;;\nA820;SYLOTI NAGRI LETTER RRO;Lo;0;L;;;;;N;;;;;\nA821;SYLOTI NAGRI LETTER SO;Lo;0;L;;;;;N;;;;;\nA822;SYLOTI NAGRI LETTER HO;Lo;0;L;;;;;N;;;;;\nA823;SYLOTI NAGRI VOWEL SIGN A;Mc;0;L;;;;;N;;;;;\nA824;SYLOTI NAGRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\nA825;SYLOTI NAGRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\nA826;SYLOTI NAGRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\nA827;SYLOTI NAGRI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;\nA828;SYLOTI NAGRI POETRY MARK-1;So;0;ON;;;;;N;;;;;\nA829;SYLOTI NAGRI POETRY MARK-2;So;0;ON;;;;;N;;;;;\nA82A;SYLOTI NAGRI POETRY MARK-3;So;0;ON;;;;;N;;;;;\nA82B;SYLOTI NAGRI POETRY MARK-4;So;0;ON;;;;;N;;;;;\nA82C;SYLOTI NAGRI SIGN ALTERNATE HASANTA;Mn;9;NSM;;;;;N;;;;;\nA830;NORTH INDIC FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;;\nA831;NORTH INDIC FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;;\nA832;NORTH INDIC FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;;\nA833;NORTH INDIC FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;;\nA834;NORTH INDIC FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;;\nA835;NORTH INDIC FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;;\nA836;NORTH INDIC QUARTER MARK;So;0;L;;;;;N;;;;;\nA837;NORTH INDIC PLACEHOLDER MARK;So;0;L;;;;;N;;;;;\nA838;NORTH INDIC RUPEE MARK;Sc;0;ET;;;;;N;;;;;\nA839;NORTH INDIC QUANTITY MARK;So;0;ET;;;;;N;;;;;\nA840;PHAGS-PA LETTER KA;Lo;0;L;;;;;N;;;;;\nA841;PHAGS-PA LETTER KHA;Lo;0;L;;;;;N;;;;;\nA842;PHAGS-PA LETTER GA;Lo;0;L;;;;;N;;;;;\nA843;PHAGS-PA LETTER NGA;Lo;0;L;;;;;N;;;;;\nA844;PHAGS-PA LETTER CA;Lo;0;L;;;;;N;;;;;\nA845;PHAGS-PA LETTER CHA;Lo;0;L;;;;;N;;;;;\nA846;PHAGS-PA LETTER JA;Lo;0;L;;;;;N;;;;;\nA847;PHAGS-PA LETTER NYA;Lo;0;L;;;;;N;;;;;\nA848;PHAGS-PA LETTER TA;Lo;0;L;;;;;N;;;;;\nA849;PHAGS-PA LETTER THA;Lo;0;L;;;;;N;;;;;\nA84A;PHAGS-PA LETTER DA;Lo;0;L;;;;;N;;;;;\nA84B;PHAGS-PA LETTER NA;Lo;0;L;;;;;N;;;;;\nA84C;PHAGS-PA LETTER PA;Lo;0;L;;;;;N;;;;;\nA84D;PHAGS-PA LETTER PHA;Lo;0;L;;;;;N;;;;;\nA84E;PHAGS-PA LETTER BA;Lo;0;L;;;;;N;;;;;\nA84F;PHAGS-PA LETTER MA;Lo;0;L;;;;;N;;;;;\nA850;PHAGS-PA LETTER TSA;Lo;0;L;;;;;N;;;;;\nA851;PHAGS-PA LETTER TSHA;Lo;0;L;;;;;N;;;;;\nA852;PHAGS-PA LETTER DZA;Lo;0;L;;;;;N;;;;;\nA853;PHAGS-PA LETTER WA;Lo;0;L;;;;;N;;;;;\nA854;PHAGS-PA LETTER ZHA;Lo;0;L;;;;;N;;;;;\nA855;PHAGS-PA LETTER ZA;Lo;0;L;;;;;N;;;;;\nA856;PHAGS-PA LETTER SMALL A;Lo;0;L;;;;;N;;;;;\nA857;PHAGS-PA LETTER YA;Lo;0;L;;;;;N;;;;;\nA858;PHAGS-PA LETTER RA;Lo;0;L;;;;;N;;;;;\nA859;PHAGS-PA LETTER LA;Lo;0;L;;;;;N;;;;;\nA85A;PHAGS-PA LETTER SHA;Lo;0;L;;;;;N;;;;;\nA85B;PHAGS-PA LETTER SA;Lo;0;L;;;;;N;;;;;\nA85C;PHAGS-PA LETTER HA;Lo;0;L;;;;;N;;;;;\nA85D;PHAGS-PA LETTER A;Lo;0;L;;;;;N;;;;;\nA85E;PHAGS-PA LETTER I;Lo;0;L;;;;;N;;;;;\nA85F;PHAGS-PA LETTER U;Lo;0;L;;;;;N;;;;;\nA860;PHAGS-PA LETTER E;Lo;0;L;;;;;N;;;;;\nA861;PHAGS-PA LETTER O;Lo;0;L;;;;;N;;;;;\nA862;PHAGS-PA LETTER QA;Lo;0;L;;;;;N;;;;;\nA863;PHAGS-PA LETTER XA;Lo;0;L;;;;;N;;;;;\nA864;PHAGS-PA LETTER FA;Lo;0;L;;;;;N;;;;;\nA865;PHAGS-PA LETTER GGA;Lo;0;L;;;;;N;;;;;\nA866;PHAGS-PA LETTER EE;Lo;0;L;;;;;N;;;;;\nA867;PHAGS-PA SUBJOINED LETTER WA;Lo;0;L;;;;;N;;;;;\nA868;PHAGS-PA SUBJOINED LETTER YA;Lo;0;L;;;;;N;;;;;\nA869;PHAGS-PA LETTER TTA;Lo;0;L;;;;;N;;;;;\nA86A;PHAGS-PA LETTER TTHA;Lo;0;L;;;;;N;;;;;\nA86B;PHAGS-PA LETTER DDA;Lo;0;L;;;;;N;;;;;\nA86C;PHAGS-PA LETTER NNA;Lo;0;L;;;;;N;;;;;\nA86D;PHAGS-PA LETTER ALTERNATE YA;Lo;0;L;;;;;N;;;;;\nA86E;PHAGS-PA LETTER VOICELESS SHA;Lo;0;L;;;;;N;;;;;\nA86F;PHAGS-PA LETTER VOICED HA;Lo;0;L;;;;;N;;;;;\nA870;PHAGS-PA LETTER ASPIRATED FA;Lo;0;L;;;;;N;;;;;\nA871;PHAGS-PA SUBJOINED LETTER RA;Lo;0;L;;;;;N;;;;;\nA872;PHAGS-PA SUPERFIXED LETTER RA;Lo;0;L;;;;;N;;;;;\nA873;PHAGS-PA LETTER CANDRABINDU;Lo;0;L;;;;;N;;;;;\nA874;PHAGS-PA SINGLE HEAD MARK;Po;0;ON;;;;;N;;;;;\nA875;PHAGS-PA DOUBLE HEAD MARK;Po;0;ON;;;;;N;;;;;\nA876;PHAGS-PA MARK SHAD;Po;0;ON;;;;;N;;;;;\nA877;PHAGS-PA MARK DOUBLE SHAD;Po;0;ON;;;;;N;;;;;\nA880;SAURASHTRA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\nA881;SAURASHTRA SIGN VISARGA;Mc;0;L;;;;;N;;;;;\nA882;SAURASHTRA LETTER A;Lo;0;L;;;;;N;;;;;\nA883;SAURASHTRA LETTER AA;Lo;0;L;;;;;N;;;;;\nA884;SAURASHTRA LETTER I;Lo;0;L;;;;;N;;;;;\nA885;SAURASHTRA LETTER II;Lo;0;L;;;;;N;;;;;\nA886;SAURASHTRA LETTER U;Lo;0;L;;;;;N;;;;;\nA887;SAURASHTRA LETTER UU;Lo;0;L;;;;;N;;;;;\nA888;SAURASHTRA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\nA889;SAURASHTRA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\nA88A;SAURASHTRA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\nA88B;SAURASHTRA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\nA88C;SAURASHTRA LETTER E;Lo;0;L;;;;;N;;;;;\nA88D;SAURASHTRA LETTER EE;Lo;0;L;;;;;N;;;;;\nA88E;SAURASHTRA LETTER AI;Lo;0;L;;;;;N;;;;;\nA88F;SAURASHTRA LETTER O;Lo;0;L;;;;;N;;;;;\nA890;SAURASHTRA LETTER OO;Lo;0;L;;;;;N;;;;;\nA891;SAURASHTRA LETTER AU;Lo;0;L;;;;;N;;;;;\nA892;SAURASHTRA LETTER KA;Lo;0;L;;;;;N;;;;;\nA893;SAURASHTRA LETTER KHA;Lo;0;L;;;;;N;;;;;\nA894;SAURASHTRA LETTER GA;Lo;0;L;;;;;N;;;;;\nA895;SAURASHTRA LETTER GHA;Lo;0;L;;;;;N;;;;;\nA896;SAURASHTRA LETTER NGA;Lo;0;L;;;;;N;;;;;\nA897;SAURASHTRA LETTER CA;Lo;0;L;;;;;N;;;;;\nA898;SAURASHTRA LETTER CHA;Lo;0;L;;;;;N;;;;;\nA899;SAURASHTRA LETTER JA;Lo;0;L;;;;;N;;;;;\nA89A;SAURASHTRA LETTER JHA;Lo;0;L;;;;;N;;;;;\nA89B;SAURASHTRA LETTER NYA;Lo;0;L;;;;;N;;;;;\nA89C;SAURASHTRA LETTER TTA;Lo;0;L;;;;;N;;;;;\nA89D;SAURASHTRA LETTER TTHA;Lo;0;L;;;;;N;;;;;\nA89E;SAURASHTRA LETTER DDA;Lo;0;L;;;;;N;;;;;\nA89F;SAURASHTRA LETTER DDHA;Lo;0;L;;;;;N;;;;;\nA8A0;SAURASHTRA LETTER NNA;Lo;0;L;;;;;N;;;;;\nA8A1;SAURASHTRA LETTER TA;Lo;0;L;;;;;N;;;;;\nA8A2;SAURASHTRA LETTER THA;Lo;0;L;;;;;N;;;;;\nA8A3;SAURASHTRA LETTER DA;Lo;0;L;;;;;N;;;;;\nA8A4;SAURASHTRA LETTER DHA;Lo;0;L;;;;;N;;;;;\nA8A5;SAURASHTRA LETTER NA;Lo;0;L;;;;;N;;;;;\nA8A6;SAURASHTRA LETTER PA;Lo;0;L;;;;;N;;;;;\nA8A7;SAURASHTRA LETTER PHA;Lo;0;L;;;;;N;;;;;\nA8A8;SAURASHTRA LETTER BA;Lo;0;L;;;;;N;;;;;\nA8A9;SAURASHTRA LETTER BHA;Lo;0;L;;;;;N;;;;;\nA8AA;SAURASHTRA LETTER MA;Lo;0;L;;;;;N;;;;;\nA8AB;SAURASHTRA LETTER YA;Lo;0;L;;;;;N;;;;;\nA8AC;SAURASHTRA LETTER RA;Lo;0;L;;;;;N;;;;;\nA8AD;SAURASHTRA LETTER LA;Lo;0;L;;;;;N;;;;;\nA8AE;SAURASHTRA LETTER VA;Lo;0;L;;;;;N;;;;;\nA8AF;SAURASHTRA LETTER SHA;Lo;0;L;;;;;N;;;;;\nA8B0;SAURASHTRA LETTER SSA;Lo;0;L;;;;;N;;;;;\nA8B1;SAURASHTRA LETTER SA;Lo;0;L;;;;;N;;;;;\nA8B2;SAURASHTRA LETTER HA;Lo;0;L;;;;;N;;;;;\nA8B3;SAURASHTRA LETTER LLA;Lo;0;L;;;;;N;;;;;\nA8B4;SAURASHTRA CONSONANT SIGN HAARU;Mc;0;L;;;;;N;;;;;\nA8B5;SAURASHTRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\nA8B6;SAURASHTRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\nA8B7;SAURASHTRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\nA8B8;SAURASHTRA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\nA8B9;SAURASHTRA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\nA8BA;SAURASHTRA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;\nA8BB;SAURASHTRA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;\nA8BC;SAURASHTRA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;;\nA8BD;SAURASHTRA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;;\nA8BE;SAURASHTRA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\nA8BF;SAURASHTRA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;\nA8C0;SAURASHTRA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\nA8C1;SAURASHTRA VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\nA8C2;SAURASHTRA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;\nA8C3;SAURASHTRA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\nA8C4;SAURASHTRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\nA8C5;SAURASHTRA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\nA8CE;SAURASHTRA DANDA;Po;0;L;;;;;N;;;;;\nA8CF;SAURASHTRA DOUBLE DANDA;Po;0;L;;;;;N;;;;;\nA8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\nA8D1;SAURASHTRA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\nA8D2;SAURASHTRA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\nA8D3;SAURASHTRA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\nA8D4;SAURASHTRA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\nA8D5;SAURASHTRA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\nA8D6;SAURASHTRA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\nA8D7;SAURASHTRA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\nA8D8;SAURASHTRA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\nA8D9;SAURASHTRA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\nA8E0;COMBINING DEVANAGARI DIGIT ZERO;Mn;230;NSM;;;;;N;;;;;\nA8E1;COMBINING DEVANAGARI DIGIT ONE;Mn;230;NSM;;;;;N;;;;;\nA8E2;COMBINING DEVANAGARI DIGIT TWO;Mn;230;NSM;;;;;N;;;;;\nA8E3;COMBINING DEVANAGARI DIGIT THREE;Mn;230;NSM;;;;;N;;;;;\nA8E4;COMBINING DEVANAGARI DIGIT FOUR;Mn;230;NSM;;;;;N;;;;;\nA8E5;COMBINING DEVANAGARI DIGIT FIVE;Mn;230;NSM;;;;;N;;;;;\nA8E6;COMBINING DEVANAGARI DIGIT SIX;Mn;230;NSM;;;;;N;;;;;\nA8E7;COMBINING DEVANAGARI DIGIT SEVEN;Mn;230;NSM;;;;;N;;;;;\nA8E8;COMBINING DEVANAGARI DIGIT EIGHT;Mn;230;NSM;;;;;N;;;;;\nA8E9;COMBINING DEVANAGARI DIGIT NINE;Mn;230;NSM;;;;;N;;;;;\nA8EA;COMBINING DEVANAGARI LETTER A;Mn;230;NSM;;;;;N;;;;;\nA8EB;COMBINING DEVANAGARI LETTER U;Mn;230;NSM;;;;;N;;;;;\nA8EC;COMBINING DEVANAGARI LETTER KA;Mn;230;NSM;;;;;N;;;;;\nA8ED;COMBINING DEVANAGARI LETTER NA;Mn;230;NSM;;;;;N;;;;;\nA8EE;COMBINING DEVANAGARI LETTER PA;Mn;230;NSM;;;;;N;;;;;\nA8EF;COMBINING DEVANAGARI LETTER RA;Mn;230;NSM;;;;;N;;;;;\nA8F0;COMBINING DEVANAGARI LETTER VI;Mn;230;NSM;;;;;N;;;;;\nA8F1;COMBINING DEVANAGARI SIGN AVAGRAHA;Mn;230;NSM;;;;;N;;;;;\nA8F2;DEVANAGARI SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;;\nA8F3;DEVANAGARI SIGN CANDRABINDU VIRAMA;Lo;0;L;;;;;N;;;;;\nA8F4;DEVANAGARI SIGN DOUBLE CANDRABINDU VIRAMA;Lo;0;L;;;;;N;;;;;\nA8F5;DEVANAGARI SIGN CANDRABINDU TWO;Lo;0;L;;;;;N;;;;;\nA8F6;DEVANAGARI SIGN CANDRABINDU THREE;Lo;0;L;;;;;N;;;;;\nA8F7;DEVANAGARI SIGN CANDRABINDU AVAGRAHA;Lo;0;L;;;;;N;;;;;\nA8F8;DEVANAGARI SIGN PUSHPIKA;Po;0;L;;;;;N;;;;;\nA8F9;DEVANAGARI GAP FILLER;Po;0;L;;;;;N;;;;;\nA8FA;DEVANAGARI CARET;Po;0;L;;;;;N;;;;;\nA8FB;DEVANAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;;\nA8FC;DEVANAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;;\nA8FD;DEVANAGARI JAIN OM;Lo;0;L;;;;;N;;;;;\nA8FE;DEVANAGARI LETTER AY;Lo;0;L;;;;;N;;;;;\nA8FF;DEVANAGARI VOWEL SIGN AY;Mn;0;NSM;;;;;N;;;;;\nA900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\nA901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\nA902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\nA903;KAYAH LI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\nA904;KAYAH LI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\nA905;KAYAH LI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\nA906;KAYAH LI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\nA907;KAYAH LI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\nA908;KAYAH LI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\nA909;KAYAH LI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\nA90A;KAYAH LI LETTER KA;Lo;0;L;;;;;N;;;;;\nA90B;KAYAH LI LETTER KHA;Lo;0;L;;;;;N;;;;;\nA90C;KAYAH LI LETTER GA;Lo;0;L;;;;;N;;;;;\nA90D;KAYAH LI LETTER NGA;Lo;0;L;;;;;N;;;;;\nA90E;KAYAH LI LETTER SA;Lo;0;L;;;;;N;;;;;\nA90F;KAYAH LI LETTER SHA;Lo;0;L;;;;;N;;;;;\nA910;KAYAH LI LETTER ZA;Lo;0;L;;;;;N;;;;;\nA911;KAYAH LI LETTER NYA;Lo;0;L;;;;;N;;;;;\nA912;KAYAH LI LETTER TA;Lo;0;L;;;;;N;;;;;\nA913;KAYAH LI LETTER HTA;Lo;0;L;;;;;N;;;;;\nA914;KAYAH LI LETTER NA;Lo;0;L;;;;;N;;;;;\nA915;KAYAH LI LETTER PA;Lo;0;L;;;;;N;;;;;\nA916;KAYAH LI LETTER PHA;Lo;0;L;;;;;N;;;;;\nA917;KAYAH LI LETTER MA;Lo;0;L;;;;;N;;;;;\nA918;KAYAH LI LETTER DA;Lo;0;L;;;;;N;;;;;\nA919;KAYAH LI LETTER BA;Lo;0;L;;;;;N;;;;;\nA91A;KAYAH LI LETTER RA;Lo;0;L;;;;;N;;;;;\nA91B;KAYAH LI LETTER YA;Lo;0;L;;;;;N;;;;;\nA91C;KAYAH LI LETTER LA;Lo;0;L;;;;;N;;;;;\nA91D;KAYAH LI LETTER WA;Lo;0;L;;;;;N;;;;;\nA91E;KAYAH LI LETTER THA;Lo;0;L;;;;;N;;;;;\nA91F;KAYAH LI LETTER HA;Lo;0;L;;;;;N;;;;;\nA920;KAYAH LI LETTER VA;Lo;0;L;;;;;N;;;;;\nA921;KAYAH LI LETTER CA;Lo;0;L;;;;;N;;;;;\nA922;KAYAH LI LETTER A;Lo;0;L;;;;;N;;;;;\nA923;KAYAH LI LETTER OE;Lo;0;L;;;;;N;;;;;\nA924;KAYAH LI LETTER I;Lo;0;L;;;;;N;;;;;\nA925;KAYAH LI LETTER OO;Lo;0;L;;;;;N;;;;;\nA926;KAYAH LI VOWEL UE;Mn;0;NSM;;;;;N;;;;;\nA927;KAYAH LI VOWEL E;Mn;0;NSM;;;;;N;;;;;\nA928;KAYAH LI VOWEL U;Mn;0;NSM;;;;;N;;;;;\nA929;KAYAH LI VOWEL EE;Mn;0;NSM;;;;;N;;;;;\nA92A;KAYAH LI VOWEL O;Mn;0;NSM;;;;;N;;;;;\nA92B;KAYAH LI TONE PLOPHU;Mn;220;NSM;;;;;N;;;;;\nA92C;KAYAH LI TONE CALYA;Mn;220;NSM;;;;;N;;;;;\nA92D;KAYAH LI TONE CALYA PLOPHU;Mn;220;NSM;;;;;N;;;;;\nA92E;KAYAH LI SIGN CWI;Po;0;L;;;;;N;;;;;\nA92F;KAYAH LI SIGN SHYA;Po;0;L;;;;;N;;;;;\nA930;REJANG LETTER KA;Lo;0;L;;;;;N;;;;;\nA931;REJANG LETTER GA;Lo;0;L;;;;;N;;;;;\nA932;REJANG LETTER NGA;Lo;0;L;;;;;N;;;;;\nA933;REJANG LETTER TA;Lo;0;L;;;;;N;;;;;\nA934;REJANG LETTER DA;Lo;0;L;;;;;N;;;;;\nA935;REJANG LETTER NA;Lo;0;L;;;;;N;;;;;\nA936;REJANG LETTER PA;Lo;0;L;;;;;N;;;;;\nA937;REJANG LETTER BA;Lo;0;L;;;;;N;;;;;\nA938;REJANG LETTER MA;Lo;0;L;;;;;N;;;;;\nA939;REJANG LETTER CA;Lo;0;L;;;;;N;;;;;\nA93A;REJANG LETTER JA;Lo;0;L;;;;;N;;;;;\nA93B;REJANG LETTER NYA;Lo;0;L;;;;;N;;;;;\nA93C;REJANG LETTER SA;Lo;0;L;;;;;N;;;;;\nA93D;REJANG LETTER RA;Lo;0;L;;;;;N;;;;;\nA93E;REJANG LETTER LA;Lo;0;L;;;;;N;;;;;\nA93F;REJANG LETTER YA;Lo;0;L;;;;;N;;;;;\nA940;REJANG LETTER WA;Lo;0;L;;;;;N;;;;;\nA941;REJANG LETTER HA;Lo;0;L;;;;;N;;;;;\nA942;REJANG LETTER MBA;Lo;0;L;;;;;N;;;;;\nA943;REJANG LETTER NGGA;Lo;0;L;;;;;N;;;;;\nA944;REJANG LETTER NDA;Lo;0;L;;;;;N;;;;;\nA945;REJANG LETTER NYJA;Lo;0;L;;;;;N;;;;;\nA946;REJANG LETTER A;Lo;0;L;;;;;N;;;;;\nA947;REJANG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\nA948;REJANG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\nA949;REJANG VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\nA94A;REJANG VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\nA94B;REJANG VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\nA94C;REJANG VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\nA94D;REJANG VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;;\nA94E;REJANG VOWEL SIGN EA;Mn;0;NSM;;;;;N;;;;;\nA94F;REJANG CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;;\nA950;REJANG CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;;\nA951;REJANG CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;;\nA952;REJANG CONSONANT SIGN H;Mc;0;L;;;;;N;;;;;\nA953;REJANG VIRAMA;Mc;9;L;;;;;N;;;;;\nA95F;REJANG SECTION MARK;Po;0;L;;;;;N;;;;;\nA960;HANGUL CHOSEONG TIKEUT-MIEUM;Lo;0;L;;;;;N;;;;;\nA961;HANGUL CHOSEONG TIKEUT-PIEUP;Lo;0;L;;;;;N;;;;;\nA962;HANGUL CHOSEONG TIKEUT-SIOS;Lo;0;L;;;;;N;;;;;\nA963;HANGUL CHOSEONG TIKEUT-CIEUC;Lo;0;L;;;;;N;;;;;\nA964;HANGUL CHOSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;;;;\nA965;HANGUL CHOSEONG RIEUL-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;\nA966;HANGUL CHOSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;;\nA967;HANGUL CHOSEONG RIEUL-SSANGTIKEUT;Lo;0;L;;;;;N;;;;;\nA968;HANGUL CHOSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;;;;\nA969;HANGUL CHOSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;;;;\nA96A;HANGUL CHOSEONG RIEUL-SSANGPIEUP;Lo;0;L;;;;;N;;;;;\nA96B;HANGUL CHOSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;\nA96C;HANGUL CHOSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;;;;\nA96D;HANGUL CHOSEONG RIEUL-CIEUC;Lo;0;L;;;;;N;;;;;\nA96E;HANGUL CHOSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;\nA96F;HANGUL CHOSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;\nA970;HANGUL CHOSEONG MIEUM-TIKEUT;Lo;0;L;;;;;N;;;;;\nA971;HANGUL CHOSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;;\nA972;HANGUL CHOSEONG PIEUP-SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;\nA973;HANGUL CHOSEONG PIEUP-KHIEUKH;Lo;0;L;;;;;N;;;;;\nA974;HANGUL CHOSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;\nA975;HANGUL CHOSEONG SSANGSIOS-PIEUP;Lo;0;L;;;;;N;;;;;\nA976;HANGUL CHOSEONG IEUNG-RIEUL;Lo;0;L;;;;;N;;;;;\nA977;HANGUL CHOSEONG IEUNG-HIEUH;Lo;0;L;;;;;N;;;;;\nA978;HANGUL CHOSEONG SSANGCIEUC-HIEUH;Lo;0;L;;;;;N;;;;;\nA979;HANGUL CHOSEONG SSANGTHIEUTH;Lo;0;L;;;;;N;;;;;\nA97A;HANGUL CHOSEONG PHIEUPH-HIEUH;Lo;0;L;;;;;N;;;;;\nA97B;HANGUL CHOSEONG HIEUH-SIOS;Lo;0;L;;;;;N;;;;;\nA97C;HANGUL CHOSEONG SSANGYEORINHIEUH;Lo;0;L;;;;;N;;;;;\nA980;JAVANESE SIGN PANYANGGA;Mn;0;NSM;;;;;N;;;;;\nA981;JAVANESE SIGN CECAK;Mn;0;NSM;;;;;N;;;;;\nA982;JAVANESE SIGN LAYAR;Mn;0;NSM;;;;;N;;;;;\nA983;JAVANESE SIGN WIGNYAN;Mc;0;L;;;;;N;;;;;\nA984;JAVANESE LETTER A;Lo;0;L;;;;;N;;;;;\nA985;JAVANESE LETTER I KAWI;Lo;0;L;;;;;N;;;;;\nA986;JAVANESE LETTER I;Lo;0;L;;;;;N;;;;;\nA987;JAVANESE LETTER II;Lo;0;L;;;;;N;;;;;\nA988;JAVANESE LETTER U;Lo;0;L;;;;;N;;;;;\nA989;JAVANESE LETTER PA CEREK;Lo;0;L;;;;;N;;;;;\nA98A;JAVANESE LETTER NGA LELET;Lo;0;L;;;;;N;;;;;\nA98B;JAVANESE LETTER NGA LELET RASWADI;Lo;0;L;;;;;N;;;;;\nA98C;JAVANESE LETTER E;Lo;0;L;;;;;N;;;;;\nA98D;JAVANESE LETTER AI;Lo;0;L;;;;;N;;;;;\nA98E;JAVANESE LETTER O;Lo;0;L;;;;;N;;;;;\nA98F;JAVANESE LETTER KA;Lo;0;L;;;;;N;;;;;\nA990;JAVANESE LETTER KA SASAK;Lo;0;L;;;;;N;;;;;\nA991;JAVANESE LETTER KA MURDA;Lo;0;L;;;;;N;;;;;\nA992;JAVANESE LETTER GA;Lo;0;L;;;;;N;;;;;\nA993;JAVANESE LETTER GA MURDA;Lo;0;L;;;;;N;;;;;\nA994;JAVANESE LETTER NGA;Lo;0;L;;;;;N;;;;;\nA995;JAVANESE LETTER CA;Lo;0;L;;;;;N;;;;;\nA996;JAVANESE LETTER CA MURDA;Lo;0;L;;;;;N;;;;;\nA997;JAVANESE LETTER JA;Lo;0;L;;;;;N;;;;;\nA998;JAVANESE LETTER NYA MURDA;Lo;0;L;;;;;N;;;;;\nA999;JAVANESE LETTER JA MAHAPRANA;Lo;0;L;;;;;N;;;;;\nA99A;JAVANESE LETTER NYA;Lo;0;L;;;;;N;;;;;\nA99B;JAVANESE LETTER TTA;Lo;0;L;;;;;N;;;;;\nA99C;JAVANESE LETTER TTA MAHAPRANA;Lo;0;L;;;;;N;;;;;\nA99D;JAVANESE LETTER DDA;Lo;0;L;;;;;N;;;;;\nA99E;JAVANESE LETTER DDA MAHAPRANA;Lo;0;L;;;;;N;;;;;\nA99F;JAVANESE LETTER NA MURDA;Lo;0;L;;;;;N;;;;;\nA9A0;JAVANESE LETTER TA;Lo;0;L;;;;;N;;;;;\nA9A1;JAVANESE LETTER TA MURDA;Lo;0;L;;;;;N;;;;;\nA9A2;JAVANESE LETTER DA;Lo;0;L;;;;;N;;;;;\nA9A3;JAVANESE LETTER DA MAHAPRANA;Lo;0;L;;;;;N;;;;;\nA9A4;JAVANESE LETTER NA;Lo;0;L;;;;;N;;;;;\nA9A5;JAVANESE LETTER PA;Lo;0;L;;;;;N;;;;;\nA9A6;JAVANESE LETTER PA MURDA;Lo;0;L;;;;;N;;;;;\nA9A7;JAVANESE LETTER BA;Lo;0;L;;;;;N;;;;;\nA9A8;JAVANESE LETTER BA MURDA;Lo;0;L;;;;;N;;;;;\nA9A9;JAVANESE LETTER MA;Lo;0;L;;;;;N;;;;;\nA9AA;JAVANESE LETTER YA;Lo;0;L;;;;;N;;;;;\nA9AB;JAVANESE LETTER RA;Lo;0;L;;;;;N;;;;;\nA9AC;JAVANESE LETTER RA AGUNG;Lo;0;L;;;;;N;;;;;\nA9AD;JAVANESE LETTER LA;Lo;0;L;;;;;N;;;;;\nA9AE;JAVANESE LETTER WA;Lo;0;L;;;;;N;;;;;\nA9AF;JAVANESE LETTER SA MURDA;Lo;0;L;;;;;N;;;;;\nA9B0;JAVANESE LETTER SA MAHAPRANA;Lo;0;L;;;;;N;;;;;\nA9B1;JAVANESE LETTER SA;Lo;0;L;;;;;N;;;;;\nA9B2;JAVANESE LETTER HA;Lo;0;L;;;;;N;;;;;\nA9B3;JAVANESE SIGN CECAK TELU;Mn;7;NSM;;;;;N;;;;;\nA9B4;JAVANESE VOWEL SIGN TARUNG;Mc;0;L;;;;;N;;;;;\nA9B5;JAVANESE VOWEL SIGN TOLONG;Mc;0;L;;;;;N;;;;;\nA9B6;JAVANESE VOWEL SIGN WULU;Mn;0;NSM;;;;;N;;;;;\nA9B7;JAVANESE VOWEL SIGN WULU MELIK;Mn;0;NSM;;;;;N;;;;;\nA9B8;JAVANESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;;;;\nA9B9;JAVANESE VOWEL SIGN SUKU MENDUT;Mn;0;NSM;;;;;N;;;;;\nA9BA;JAVANESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;;;;\nA9BB;JAVANESE VOWEL SIGN DIRGA MURE;Mc;0;L;;;;;N;;;;;\nA9BC;JAVANESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;;;;\nA9BD;JAVANESE CONSONANT SIGN KERET;Mn;0;NSM;;;;;N;;;;;\nA9BE;JAVANESE CONSONANT SIGN PENGKAL;Mc;0;L;;;;;N;;;;;\nA9BF;JAVANESE CONSONANT SIGN CAKRA;Mc;0;L;;;;;N;;;;;\nA9C0;JAVANESE PANGKON;Mc;9;L;;;;;N;;;;;\nA9C1;JAVANESE LEFT RERENGGAN;Po;0;L;;;;;N;;;;;\nA9C2;JAVANESE RIGHT RERENGGAN;Po;0;L;;;;;N;;;;;\nA9C3;JAVANESE PADA ANDAP;Po;0;L;;;;;N;;;;;\nA9C4;JAVANESE PADA MADYA;Po;0;L;;;;;N;;;;;\nA9C5;JAVANESE PADA LUHUR;Po;0;L;;;;;N;;;;;\nA9C6;JAVANESE PADA WINDU;Po;0;L;;;;;N;;;;;\nA9C7;JAVANESE PADA PANGKAT;Po;0;L;;;;;N;;;;;\nA9C8;JAVANESE PADA LINGSA;Po;0;L;;;;;N;;;;;\nA9C9;JAVANESE PADA LUNGSI;Po;0;L;;;;;N;;;;;\nA9CA;JAVANESE PADA ADEG;Po;0;L;;;;;N;;;;;\nA9CB;JAVANESE PADA ADEG ADEG;Po;0;L;;;;;N;;;;;\nA9CC;JAVANESE PADA PISELEH;Po;0;L;;;;;N;;;;;\nA9CD;JAVANESE TURNED PADA PISELEH;Po;0;L;;;;;N;;;;;\nA9CF;JAVANESE PANGRANGKEP;Lm;0;L;;;;;N;;;;;\nA9D0;JAVANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\nA9D1;JAVANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\nA9D2;JAVANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\nA9D3;JAVANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\nA9D4;JAVANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\nA9D5;JAVANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\nA9D6;JAVANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\nA9D7;JAVANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\nA9D8;JAVANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\nA9D9;JAVANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\nA9DE;JAVANESE PADA TIRTA TUMETES;Po;0;L;;;;;N;;;;;\nA9DF;JAVANESE PADA ISEN-ISEN;Po;0;L;;;;;N;;;;;\nA9E0;MYANMAR LETTER SHAN GHA;Lo;0;L;;;;;N;;;;;\nA9E1;MYANMAR LETTER SHAN CHA;Lo;0;L;;;;;N;;;;;\nA9E2;MYANMAR LETTER SHAN JHA;Lo;0;L;;;;;N;;;;;\nA9E3;MYANMAR LETTER SHAN NNA;Lo;0;L;;;;;N;;;;;\nA9E4;MYANMAR LETTER SHAN BHA;Lo;0;L;;;;;N;;;;;\nA9E5;MYANMAR SIGN SHAN SAW;Mn;0;NSM;;;;;N;;;;;\nA9E6;MYANMAR MODIFIER LETTER SHAN REDUPLICATION;Lm;0;L;;;;;N;;;;;\nA9E7;MYANMAR LETTER TAI LAING NYA;Lo;0;L;;;;;N;;;;;\nA9E8;MYANMAR LETTER TAI LAING FA;Lo;0;L;;;;;N;;;;;\nA9E9;MYANMAR LETTER TAI LAING GA;Lo;0;L;;;;;N;;;;;\nA9EA;MYANMAR LETTER TAI LAING GHA;Lo;0;L;;;;;N;;;;;\nA9EB;MYANMAR LETTER TAI LAING JA;Lo;0;L;;;;;N;;;;;\nA9EC;MYANMAR LETTER TAI LAING JHA;Lo;0;L;;;;;N;;;;;\nA9ED;MYANMAR LETTER TAI LAING DDA;Lo;0;L;;;;;N;;;;;\nA9EE;MYANMAR LETTER TAI LAING DDHA;Lo;0;L;;;;;N;;;;;\nA9EF;MYANMAR LETTER TAI LAING NNA;Lo;0;L;;;;;N;;;;;\nA9F0;MYANMAR TAI LAING DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\nA9F1;MYANMAR TAI LAING DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\nA9F2;MYANMAR TAI LAING DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\nA9F3;MYANMAR TAI LAING DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\nA9F4;MYANMAR TAI LAING DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\nA9F5;MYANMAR TAI LAING DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\nA9F6;MYANMAR TAI LAING DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\nA9F7;MYANMAR TAI LAING DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\nA9F8;MYANMAR TAI LAING DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\nA9F9;MYANMAR TAI LAING DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\nA9FA;MYANMAR LETTER TAI LAING LLA;Lo;0;L;;;;;N;;;;;\nA9FB;MYANMAR LETTER TAI LAING DA;Lo;0;L;;;;;N;;;;;\nA9FC;MYANMAR LETTER TAI LAING DHA;Lo;0;L;;;;;N;;;;;\nA9FD;MYANMAR LETTER TAI LAING BA;Lo;0;L;;;;;N;;;;;\nA9FE;MYANMAR LETTER TAI LAING BHA;Lo;0;L;;;;;N;;;;;\nAA00;CHAM LETTER A;Lo;0;L;;;;;N;;;;;\nAA01;CHAM LETTER I;Lo;0;L;;;;;N;;;;;\nAA02;CHAM LETTER U;Lo;0;L;;;;;N;;;;;\nAA03;CHAM LETTER E;Lo;0;L;;;;;N;;;;;\nAA04;CHAM LETTER AI;Lo;0;L;;;;;N;;;;;\nAA05;CHAM LETTER O;Lo;0;L;;;;;N;;;;;\nAA06;CHAM LETTER KA;Lo;0;L;;;;;N;;;;;\nAA07;CHAM LETTER KHA;Lo;0;L;;;;;N;;;;;\nAA08;CHAM LETTER GA;Lo;0;L;;;;;N;;;;;\nAA09;CHAM LETTER GHA;Lo;0;L;;;;;N;;;;;\nAA0A;CHAM LETTER NGUE;Lo;0;L;;;;;N;;;;;\nAA0B;CHAM LETTER NGA;Lo;0;L;;;;;N;;;;;\nAA0C;CHAM LETTER CHA;Lo;0;L;;;;;N;;;;;\nAA0D;CHAM LETTER CHHA;Lo;0;L;;;;;N;;;;;\nAA0E;CHAM LETTER JA;Lo;0;L;;;;;N;;;;;\nAA0F;CHAM LETTER JHA;Lo;0;L;;;;;N;;;;;\nAA10;CHAM LETTER NHUE;Lo;0;L;;;;;N;;;;;\nAA11;CHAM LETTER NHA;Lo;0;L;;;;;N;;;;;\nAA12;CHAM LETTER NHJA;Lo;0;L;;;;;N;;;;;\nAA13;CHAM LETTER TA;Lo;0;L;;;;;N;;;;;\nAA14;CHAM LETTER THA;Lo;0;L;;;;;N;;;;;\nAA15;CHAM LETTER DA;Lo;0;L;;;;;N;;;;;\nAA16;CHAM LETTER DHA;Lo;0;L;;;;;N;;;;;\nAA17;CHAM LETTER NUE;Lo;0;L;;;;;N;;;;;\nAA18;CHAM LETTER NA;Lo;0;L;;;;;N;;;;;\nAA19;CHAM LETTER DDA;Lo;0;L;;;;;N;;;;;\nAA1A;CHAM LETTER PA;Lo;0;L;;;;;N;;;;;\nAA1B;CHAM LETTER PPA;Lo;0;L;;;;;N;;;;;\nAA1C;CHAM LETTER PHA;Lo;0;L;;;;;N;;;;;\nAA1D;CHAM LETTER BA;Lo;0;L;;;;;N;;;;;\nAA1E;CHAM LETTER BHA;Lo;0;L;;;;;N;;;;;\nAA1F;CHAM LETTER MUE;Lo;0;L;;;;;N;;;;;\nAA20;CHAM LETTER MA;Lo;0;L;;;;;N;;;;;\nAA21;CHAM LETTER BBA;Lo;0;L;;;;;N;;;;;\nAA22;CHAM LETTER YA;Lo;0;L;;;;;N;;;;;\nAA23;CHAM LETTER RA;Lo;0;L;;;;;N;;;;;\nAA24;CHAM LETTER LA;Lo;0;L;;;;;N;;;;;\nAA25;CHAM LETTER VA;Lo;0;L;;;;;N;;;;;\nAA26;CHAM LETTER SSA;Lo;0;L;;;;;N;;;;;\nAA27;CHAM LETTER SA;Lo;0;L;;;;;N;;;;;\nAA28;CHAM LETTER HA;Lo;0;L;;;;;N;;;;;\nAA29;CHAM VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;\nAA2A;CHAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\nAA2B;CHAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\nAA2C;CHAM VOWEL SIGN EI;Mn;0;NSM;;;;;N;;;;;\nAA2D;CHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\nAA2E;CHAM VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;\nAA2F;CHAM VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\nAA30;CHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\nAA31;CHAM VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\nAA32;CHAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;\nAA33;CHAM CONSONANT SIGN YA;Mc;0;L;;;;;N;;;;;\nAA34;CHAM CONSONANT SIGN RA;Mc;0;L;;;;;N;;;;;\nAA35;CHAM CONSONANT SIGN LA;Mn;0;NSM;;;;;N;;;;;\nAA36;CHAM CONSONANT SIGN WA;Mn;0;NSM;;;;;N;;;;;\nAA40;CHAM LETTER FINAL K;Lo;0;L;;;;;N;;;;;\nAA41;CHAM LETTER FINAL G;Lo;0;L;;;;;N;;;;;\nAA42;CHAM LETTER FINAL NG;Lo;0;L;;;;;N;;;;;\nAA43;CHAM CONSONANT SIGN FINAL NG;Mn;0;NSM;;;;;N;;;;;\nAA44;CHAM LETTER FINAL CH;Lo;0;L;;;;;N;;;;;\nAA45;CHAM LETTER FINAL T;Lo;0;L;;;;;N;;;;;\nAA46;CHAM LETTER FINAL N;Lo;0;L;;;;;N;;;;;\nAA47;CHAM LETTER FINAL P;Lo;0;L;;;;;N;;;;;\nAA48;CHAM LETTER FINAL Y;Lo;0;L;;;;;N;;;;;\nAA49;CHAM LETTER FINAL R;Lo;0;L;;;;;N;;;;;\nAA4A;CHAM LETTER FINAL L;Lo;0;L;;;;;N;;;;;\nAA4B;CHAM LETTER FINAL SS;Lo;0;L;;;;;N;;;;;\nAA4C;CHAM CONSONANT SIGN FINAL M;Mn;0;NSM;;;;;N;;;;;\nAA4D;CHAM CONSONANT SIGN FINAL H;Mc;0;L;;;;;N;;;;;\nAA50;CHAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\nAA51;CHAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\nAA52;CHAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\nAA53;CHAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\nAA54;CHAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\nAA55;CHAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\nAA56;CHAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\nAA57;CHAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\nAA58;CHAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\nAA59;CHAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\nAA5C;CHAM PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;;\nAA5D;CHAM PUNCTUATION DANDA;Po;0;L;;;;;N;;;;;\nAA5E;CHAM PUNCTUATION DOUBLE DANDA;Po;0;L;;;;;N;;;;;\nAA5F;CHAM PUNCTUATION TRIPLE DANDA;Po;0;L;;;;;N;;;;;\nAA60;MYANMAR LETTER KHAMTI GA;Lo;0;L;;;;;N;;;;;\nAA61;MYANMAR LETTER KHAMTI CA;Lo;0;L;;;;;N;;;;;\nAA62;MYANMAR LETTER KHAMTI CHA;Lo;0;L;;;;;N;;;;;\nAA63;MYANMAR LETTER KHAMTI JA;Lo;0;L;;;;;N;;;;;\nAA64;MYANMAR LETTER KHAMTI JHA;Lo;0;L;;;;;N;;;;;\nAA65;MYANMAR LETTER KHAMTI NYA;Lo;0;L;;;;;N;;;;;\nAA66;MYANMAR LETTER KHAMTI TTA;Lo;0;L;;;;;N;;;;;\nAA67;MYANMAR LETTER KHAMTI TTHA;Lo;0;L;;;;;N;;;;;\nAA68;MYANMAR LETTER KHAMTI DDA;Lo;0;L;;;;;N;;;;;\nAA69;MYANMAR LETTER KHAMTI DDHA;Lo;0;L;;;;;N;;;;;\nAA6A;MYANMAR LETTER KHAMTI DHA;Lo;0;L;;;;;N;;;;;\nAA6B;MYANMAR LETTER KHAMTI NA;Lo;0;L;;;;;N;;;;;\nAA6C;MYANMAR LETTER KHAMTI SA;Lo;0;L;;;;;N;;;;;\nAA6D;MYANMAR LETTER KHAMTI HA;Lo;0;L;;;;;N;;;;;\nAA6E;MYANMAR LETTER KHAMTI HHA;Lo;0;L;;;;;N;;;;;\nAA6F;MYANMAR LETTER KHAMTI FA;Lo;0;L;;;;;N;;;;;\nAA70;MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION;Lm;0;L;;;;;N;;;;;\nAA71;MYANMAR LETTER KHAMTI XA;Lo;0;L;;;;;N;;;;;\nAA72;MYANMAR LETTER KHAMTI ZA;Lo;0;L;;;;;N;;;;;\nAA73;MYANMAR LETTER KHAMTI RA;Lo;0;L;;;;;N;;;;;\nAA74;MYANMAR LOGOGRAM KHAMTI OAY;Lo;0;L;;;;;N;;;;;\nAA75;MYANMAR LOGOGRAM KHAMTI QN;Lo;0;L;;;;;N;;;;;\nAA76;MYANMAR LOGOGRAM KHAMTI HM;Lo;0;L;;;;;N;;;;;\nAA77;MYANMAR SYMBOL AITON EXCLAMATION;So;0;L;;;;;N;;;;;\nAA78;MYANMAR SYMBOL AITON ONE;So;0;L;;;;;N;;;;;\nAA79;MYANMAR SYMBOL AITON TWO;So;0;L;;;;;N;;;;;\nAA7A;MYANMAR LETTER AITON RA;Lo;0;L;;;;;N;;;;;\nAA7B;MYANMAR SIGN PAO KAREN TONE;Mc;0;L;;;;;N;;;;;\nAA7C;MYANMAR SIGN TAI LAING TONE-2;Mn;0;NSM;;;;;N;;;;;\nAA7D;MYANMAR SIGN TAI LAING TONE-5;Mc;0;L;;;;;N;;;;;\nAA7E;MYANMAR LETTER SHWE PALAUNG CHA;Lo;0;L;;;;;N;;;;;\nAA7F;MYANMAR LETTER SHWE PALAUNG SHA;Lo;0;L;;;;;N;;;;;\nAA80;TAI VIET LETTER LOW KO;Lo;0;L;;;;;N;;;;;\nAA81;TAI VIET LETTER HIGH KO;Lo;0;L;;;;;N;;;;;\nAA82;TAI VIET LETTER LOW KHO;Lo;0;L;;;;;N;;;;;\nAA83;TAI VIET LETTER HIGH KHO;Lo;0;L;;;;;N;;;;;\nAA84;TAI VIET LETTER LOW KHHO;Lo;0;L;;;;;N;;;;;\nAA85;TAI VIET LETTER HIGH KHHO;Lo;0;L;;;;;N;;;;;\nAA86;TAI VIET LETTER LOW GO;Lo;0;L;;;;;N;;;;;\nAA87;TAI VIET LETTER HIGH GO;Lo;0;L;;;;;N;;;;;\nAA88;TAI VIET LETTER LOW NGO;Lo;0;L;;;;;N;;;;;\nAA89;TAI VIET LETTER HIGH NGO;Lo;0;L;;;;;N;;;;;\nAA8A;TAI VIET LETTER LOW CO;Lo;0;L;;;;;N;;;;;\nAA8B;TAI VIET LETTER HIGH CO;Lo;0;L;;;;;N;;;;;\nAA8C;TAI VIET LETTER LOW CHO;Lo;0;L;;;;;N;;;;;\nAA8D;TAI VIET LETTER HIGH CHO;Lo;0;L;;;;;N;;;;;\nAA8E;TAI VIET LETTER LOW SO;Lo;0;L;;;;;N;;;;;\nAA8F;TAI VIET LETTER HIGH SO;Lo;0;L;;;;;N;;;;;\nAA90;TAI VIET LETTER LOW NYO;Lo;0;L;;;;;N;;;;;\nAA91;TAI VIET LETTER HIGH NYO;Lo;0;L;;;;;N;;;;;\nAA92;TAI VIET LETTER LOW DO;Lo;0;L;;;;;N;;;;;\nAA93;TAI VIET LETTER HIGH DO;Lo;0;L;;;;;N;;;;;\nAA94;TAI VIET LETTER LOW TO;Lo;0;L;;;;;N;;;;;\nAA95;TAI VIET LETTER HIGH TO;Lo;0;L;;;;;N;;;;;\nAA96;TAI VIET LETTER LOW THO;Lo;0;L;;;;;N;;;;;\nAA97;TAI VIET LETTER HIGH THO;Lo;0;L;;;;;N;;;;;\nAA98;TAI VIET LETTER LOW NO;Lo;0;L;;;;;N;;;;;\nAA99;TAI VIET LETTER HIGH NO;Lo;0;L;;;;;N;;;;;\nAA9A;TAI VIET LETTER LOW BO;Lo;0;L;;;;;N;;;;;\nAA9B;TAI VIET LETTER HIGH BO;Lo;0;L;;;;;N;;;;;\nAA9C;TAI VIET LETTER LOW PO;Lo;0;L;;;;;N;;;;;\nAA9D;TAI VIET LETTER HIGH PO;Lo;0;L;;;;;N;;;;;\nAA9E;TAI VIET LETTER LOW PHO;Lo;0;L;;;;;N;;;;;\nAA9F;TAI VIET LETTER HIGH PHO;Lo;0;L;;;;;N;;;;;\nAAA0;TAI VIET LETTER LOW FO;Lo;0;L;;;;;N;;;;;\nAAA1;TAI VIET LETTER HIGH FO;Lo;0;L;;;;;N;;;;;\nAAA2;TAI VIET LETTER LOW MO;Lo;0;L;;;;;N;;;;;\nAAA3;TAI VIET LETTER HIGH MO;Lo;0;L;;;;;N;;;;;\nAAA4;TAI VIET LETTER LOW YO;Lo;0;L;;;;;N;;;;;\nAAA5;TAI VIET LETTER HIGH YO;Lo;0;L;;;;;N;;;;;\nAAA6;TAI VIET LETTER LOW RO;Lo;0;L;;;;;N;;;;;\nAAA7;TAI VIET LETTER HIGH RO;Lo;0;L;;;;;N;;;;;\nAAA8;TAI VIET LETTER LOW LO;Lo;0;L;;;;;N;;;;;\nAAA9;TAI VIET LETTER HIGH LO;Lo;0;L;;;;;N;;;;;\nAAAA;TAI VIET LETTER LOW VO;Lo;0;L;;;;;N;;;;;\nAAAB;TAI VIET LETTER HIGH VO;Lo;0;L;;;;;N;;;;;\nAAAC;TAI VIET LETTER LOW HO;Lo;0;L;;;;;N;;;;;\nAAAD;TAI VIET LETTER HIGH HO;Lo;0;L;;;;;N;;;;;\nAAAE;TAI VIET LETTER LOW O;Lo;0;L;;;;;N;;;;;\nAAAF;TAI VIET LETTER HIGH O;Lo;0;L;;;;;N;;;;;\nAAB0;TAI VIET MAI KANG;Mn;230;NSM;;;;;N;;;;;\nAAB1;TAI VIET VOWEL AA;Lo;0;L;;;;;N;;;;;\nAAB2;TAI VIET VOWEL I;Mn;230;NSM;;;;;N;;;;;\nAAB3;TAI VIET VOWEL UE;Mn;230;NSM;;;;;N;;;;;\nAAB4;TAI VIET VOWEL U;Mn;220;NSM;;;;;N;;;;;\nAAB5;TAI VIET VOWEL E;Lo;0;L;;;;;N;;;;;\nAAB6;TAI VIET VOWEL O;Lo;0;L;;;;;N;;;;;\nAAB7;TAI VIET MAI KHIT;Mn;230;NSM;;;;;N;;;;;\nAAB8;TAI VIET VOWEL IA;Mn;230;NSM;;;;;N;;;;;\nAAB9;TAI VIET VOWEL UEA;Lo;0;L;;;;;N;;;;;\nAABA;TAI VIET VOWEL UA;Lo;0;L;;;;;N;;;;;\nAABB;TAI VIET VOWEL AUE;Lo;0;L;;;;;N;;;;;\nAABC;TAI VIET VOWEL AY;Lo;0;L;;;;;N;;;;;\nAABD;TAI VIET VOWEL AN;Lo;0;L;;;;;N;;;;;\nAABE;TAI VIET VOWEL AM;Mn;230;NSM;;;;;N;;;;;\nAABF;TAI VIET TONE MAI EK;Mn;230;NSM;;;;;N;;;;;\nAAC0;TAI VIET TONE MAI NUENG;Lo;0;L;;;;;N;;;;;\nAAC1;TAI VIET TONE MAI THO;Mn;230;NSM;;;;;N;;;;;\nAAC2;TAI VIET TONE MAI SONG;Lo;0;L;;;;;N;;;;;\nAADB;TAI VIET SYMBOL KON;Lo;0;L;;;;;N;;;;;\nAADC;TAI VIET SYMBOL NUENG;Lo;0;L;;;;;N;;;;;\nAADD;TAI VIET SYMBOL SAM;Lm;0;L;;;;;N;;;;;\nAADE;TAI VIET SYMBOL HO HOI;Po;0;L;;;;;N;;;;;\nAADF;TAI VIET SYMBOL KOI KOI;Po;0;L;;;;;N;;;;;\nAAE0;MEETEI MAYEK LETTER E;Lo;0;L;;;;;N;;;;;\nAAE1;MEETEI MAYEK LETTER O;Lo;0;L;;;;;N;;;;;\nAAE2;MEETEI MAYEK LETTER CHA;Lo;0;L;;;;;N;;;;;\nAAE3;MEETEI MAYEK LETTER NYA;Lo;0;L;;;;;N;;;;;\nAAE4;MEETEI MAYEK LETTER TTA;Lo;0;L;;;;;N;;;;;\nAAE5;MEETEI MAYEK LETTER TTHA;Lo;0;L;;;;;N;;;;;\nAAE6;MEETEI MAYEK LETTER DDA;Lo;0;L;;;;;N;;;;;\nAAE7;MEETEI MAYEK LETTER DDHA;Lo;0;L;;;;;N;;;;;\nAAE8;MEETEI MAYEK LETTER NNA;Lo;0;L;;;;;N;;;;;\nAAE9;MEETEI MAYEK LETTER SHA;Lo;0;L;;;;;N;;;;;\nAAEA;MEETEI MAYEK LETTER SSA;Lo;0;L;;;;;N;;;;;\nAAEB;MEETEI MAYEK VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\nAAEC;MEETEI MAYEK VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\nAAED;MEETEI MAYEK VOWEL SIGN AAI;Mn;0;NSM;;;;;N;;;;;\nAAEE;MEETEI MAYEK VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\nAAEF;MEETEI MAYEK VOWEL SIGN AAU;Mc;0;L;;;;;N;;;;;\nAAF0;MEETEI MAYEK CHEIKHAN;Po;0;L;;;;;N;;;;;\nAAF1;MEETEI MAYEK AHANG KHUDAM;Po;0;L;;;;;N;;;;;\nAAF2;MEETEI MAYEK ANJI;Lo;0;L;;;;;N;;;;;\nAAF3;MEETEI MAYEK SYLLABLE REPETITION MARK;Lm;0;L;;;;;N;;;;;\nAAF4;MEETEI MAYEK WORD REPETITION MARK;Lm;0;L;;;;;N;;;;;\nAAF5;MEETEI MAYEK VOWEL SIGN VISARGA;Mc;0;L;;;;;N;;;;;\nAAF6;MEETEI MAYEK VIRAMA;Mn;9;NSM;;;;;N;;;;;\nAB01;ETHIOPIC SYLLABLE TTHU;Lo;0;L;;;;;N;;;;;\nAB02;ETHIOPIC SYLLABLE TTHI;Lo;0;L;;;;;N;;;;;\nAB03;ETHIOPIC SYLLABLE TTHAA;Lo;0;L;;;;;N;;;;;\nAB04;ETHIOPIC SYLLABLE TTHEE;Lo;0;L;;;;;N;;;;;\nAB05;ETHIOPIC SYLLABLE TTHE;Lo;0;L;;;;;N;;;;;\nAB06;ETHIOPIC SYLLABLE TTHO;Lo;0;L;;;;;N;;;;;\nAB09;ETHIOPIC SYLLABLE DDHU;Lo;0;L;;;;;N;;;;;\nAB0A;ETHIOPIC SYLLABLE DDHI;Lo;0;L;;;;;N;;;;;\nAB0B;ETHIOPIC SYLLABLE DDHAA;Lo;0;L;;;;;N;;;;;\nAB0C;ETHIOPIC SYLLABLE DDHEE;Lo;0;L;;;;;N;;;;;\nAB0D;ETHIOPIC SYLLABLE DDHE;Lo;0;L;;;;;N;;;;;\nAB0E;ETHIOPIC SYLLABLE DDHO;Lo;0;L;;;;;N;;;;;\nAB11;ETHIOPIC SYLLABLE DZU;Lo;0;L;;;;;N;;;;;\nAB12;ETHIOPIC SYLLABLE DZI;Lo;0;L;;;;;N;;;;;\nAB13;ETHIOPIC SYLLABLE DZAA;Lo;0;L;;;;;N;;;;;\nAB14;ETHIOPIC SYLLABLE DZEE;Lo;0;L;;;;;N;;;;;\nAB15;ETHIOPIC SYLLABLE DZE;Lo;0;L;;;;;N;;;;;\nAB16;ETHIOPIC SYLLABLE DZO;Lo;0;L;;;;;N;;;;;\nAB20;ETHIOPIC SYLLABLE CCHHA;Lo;0;L;;;;;N;;;;;\nAB21;ETHIOPIC SYLLABLE CCHHU;Lo;0;L;;;;;N;;;;;\nAB22;ETHIOPIC SYLLABLE CCHHI;Lo;0;L;;;;;N;;;;;\nAB23;ETHIOPIC SYLLABLE CCHHAA;Lo;0;L;;;;;N;;;;;\nAB24;ETHIOPIC SYLLABLE CCHHEE;Lo;0;L;;;;;N;;;;;\nAB25;ETHIOPIC SYLLABLE CCHHE;Lo;0;L;;;;;N;;;;;\nAB26;ETHIOPIC SYLLABLE CCHHO;Lo;0;L;;;;;N;;;;;\nAB28;ETHIOPIC SYLLABLE BBA;Lo;0;L;;;;;N;;;;;\nAB29;ETHIOPIC SYLLABLE BBU;Lo;0;L;;;;;N;;;;;\nAB2A;ETHIOPIC SYLLABLE BBI;Lo;0;L;;;;;N;;;;;\nAB2B;ETHIOPIC SYLLABLE BBAA;Lo;0;L;;;;;N;;;;;\nAB2C;ETHIOPIC SYLLABLE BBEE;Lo;0;L;;;;;N;;;;;\nAB2D;ETHIOPIC SYLLABLE BBE;Lo;0;L;;;;;N;;;;;\nAB2E;ETHIOPIC SYLLABLE BBO;Lo;0;L;;;;;N;;;;;\nAB30;LATIN SMALL LETTER BARRED ALPHA;Ll;0;L;;;;;N;;;;;\nAB31;LATIN SMALL LETTER A REVERSED-SCHWA;Ll;0;L;;;;;N;;;;;\nAB32;LATIN SMALL LETTER BLACKLETTER E;Ll;0;L;;;;;N;;;;;\nAB33;LATIN SMALL LETTER BARRED E;Ll;0;L;;;;;N;;;;;\nAB34;LATIN SMALL LETTER E WITH FLOURISH;Ll;0;L;;;;;N;;;;;\nAB35;LATIN SMALL LETTER LENIS F;Ll;0;L;;;;;N;;;;;\nAB36;LATIN SMALL LETTER SCRIPT G WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;\nAB37;LATIN SMALL LETTER L WITH INVERTED LAZY S;Ll;0;L;;;;;N;;;;;\nAB38;LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\nAB39;LATIN SMALL LETTER L WITH MIDDLE RING;Ll;0;L;;;;;N;;;;;\nAB3A;LATIN SMALL LETTER M WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;\nAB3B;LATIN SMALL LETTER N WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;\nAB3C;LATIN SMALL LETTER ENG WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;\nAB3D;LATIN SMALL LETTER BLACKLETTER O;Ll;0;L;;;;;N;;;;;\nAB3E;LATIN SMALL LETTER BLACKLETTER O WITH STROKE;Ll;0;L;;;;;N;;;;;\nAB3F;LATIN SMALL LETTER OPEN O WITH STROKE;Ll;0;L;;;;;N;;;;;\nAB40;LATIN SMALL LETTER INVERTED OE;Ll;0;L;;;;;N;;;;;\nAB41;LATIN SMALL LETTER TURNED OE WITH STROKE;Ll;0;L;;;;;N;;;;;\nAB42;LATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKE;Ll;0;L;;;;;N;;;;;\nAB43;LATIN SMALL LETTER TURNED O OPEN-O;Ll;0;L;;;;;N;;;;;\nAB44;LATIN SMALL LETTER TURNED O OPEN-O WITH STROKE;Ll;0;L;;;;;N;;;;;\nAB45;LATIN SMALL LETTER STIRRUP R;Ll;0;L;;;;;N;;;;;\nAB46;LATIN LETTER SMALL CAPITAL R WITH RIGHT LEG;Ll;0;L;;;;;N;;;;;\nAB47;LATIN SMALL LETTER R WITHOUT HANDLE;Ll;0;L;;;;;N;;;;;\nAB48;LATIN SMALL LETTER DOUBLE R;Ll;0;L;;;;;N;;;;;\nAB49;LATIN SMALL LETTER R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;\nAB4A;LATIN SMALL LETTER DOUBLE R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;\nAB4B;LATIN SMALL LETTER SCRIPT R;Ll;0;L;;;;;N;;;;;\nAB4C;LATIN SMALL LETTER SCRIPT R WITH RING;Ll;0;L;;;;;N;;;;;\nAB4D;LATIN SMALL LETTER BASELINE ESH;Ll;0;L;;;;;N;;;;;\nAB4E;LATIN SMALL LETTER U WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;;\nAB4F;LATIN SMALL LETTER U BAR WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;;\nAB50;LATIN SMALL LETTER UI;Ll;0;L;;;;;N;;;;;\nAB51;LATIN SMALL LETTER TURNED UI;Ll;0;L;;;;;N;;;;;\nAB52;LATIN SMALL LETTER U WITH LEFT HOOK;Ll;0;L;;;;;N;;;;;\nAB53;LATIN SMALL LETTER CHI;Ll;0;L;;;;;N;;;A7B3;;A7B3\nAB54;LATIN SMALL LETTER CHI WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;;\nAB55;LATIN SMALL LETTER CHI WITH LOW LEFT SERIF;Ll;0;L;;;;;N;;;;;\nAB56;LATIN SMALL LETTER X WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;;\nAB57;LATIN SMALL LETTER X WITH LONG LEFT LEG;Ll;0;L;;;;;N;;;;;\nAB58;LATIN SMALL LETTER X WITH LONG LEFT LEG AND LOW RIGHT RING;Ll;0;L;;;;;N;;;;;\nAB59;LATIN SMALL LETTER X WITH LONG LEFT LEG WITH SERIF;Ll;0;L;;;;;N;;;;;\nAB5A;LATIN SMALL LETTER Y WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;;\nAB5B;MODIFIER BREVE WITH INVERTED BREVE;Sk;0;L;;;;;N;;;;;\nAB5C;MODIFIER LETTER SMALL HENG;Lm;0;L;<super> A727;;;;N;;;;;\nAB5D;MODIFIER LETTER SMALL L WITH INVERTED LAZY S;Lm;0;L;<super> AB37;;;;N;;;;;\nAB5E;MODIFIER LETTER SMALL L WITH MIDDLE TILDE;Lm;0;L;<super> 026B;;;;N;;;;;\nAB5F;MODIFIER LETTER SMALL U WITH LEFT HOOK;Lm;0;L;<super> AB52;;;;N;;;;;\nAB60;LATIN SMALL LETTER SAKHA YAT;Ll;0;L;;;;;N;;;;;\nAB61;LATIN SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;;;\nAB62;LATIN SMALL LETTER OPEN OE;Ll;0;L;;;;;N;;;;;\nAB63;LATIN SMALL LETTER UO;Ll;0;L;;;;;N;;;;;\nAB64;LATIN SMALL LETTER INVERTED ALPHA;Ll;0;L;;;;;N;;;;;\nAB65;GREEK LETTER SMALL CAPITAL OMEGA;Ll;0;L;;;;;N;;;;;\nAB66;LATIN SMALL LETTER DZ DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\nAB67;LATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\nAB68;LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;\nAB69;MODIFIER LETTER SMALL TURNED W;Lm;0;L;<super> 028D;;;;N;;;;;\nAB6A;MODIFIER LETTER LEFT TACK;Sk;0;ON;;;;;N;;;;;\nAB6B;MODIFIER LETTER RIGHT TACK;Sk;0;ON;;;;;N;;;;;\nAB70;CHEROKEE SMALL LETTER A;Ll;0;L;;;;;N;;;13A0;;13A0\nAB71;CHEROKEE SMALL LETTER E;Ll;0;L;;;;;N;;;13A1;;13A1\nAB72;CHEROKEE SMALL LETTER I;Ll;0;L;;;;;N;;;13A2;;13A2\nAB73;CHEROKEE SMALL LETTER O;Ll;0;L;;;;;N;;;13A3;;13A3\nAB74;CHEROKEE SMALL LETTER U;Ll;0;L;;;;;N;;;13A4;;13A4\nAB75;CHEROKEE SMALL LETTER V;Ll;0;L;;;;;N;;;13A5;;13A5\nAB76;CHEROKEE SMALL LETTER GA;Ll;0;L;;;;;N;;;13A6;;13A6\nAB77;CHEROKEE SMALL LETTER KA;Ll;0;L;;;;;N;;;13A7;;13A7\nAB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8\nAB79;CHEROKEE SMALL LETTER GI;Ll;0;L;;;;;N;;;13A9;;13A9\nAB7A;CHEROKEE SMALL LETTER GO;Ll;0;L;;;;;N;;;13AA;;13AA\nAB7B;CHEROKEE SMALL LETTER GU;Ll;0;L;;;;;N;;;13AB;;13AB\nAB7C;CHEROKEE SMALL LETTER GV;Ll;0;L;;;;;N;;;13AC;;13AC\nAB7D;CHEROKEE SMALL LETTER HA;Ll;0;L;;;;;N;;;13AD;;13AD\nAB7E;CHEROKEE SMALL LETTER HE;Ll;0;L;;;;;N;;;13AE;;13AE\nAB7F;CHEROKEE SMALL LETTER HI;Ll;0;L;;;;;N;;;13AF;;13AF\nAB80;CHEROKEE SMALL LETTER HO;Ll;0;L;;;;;N;;;13B0;;13B0\nAB81;CHEROKEE SMALL LETTER HU;Ll;0;L;;;;;N;;;13B1;;13B1\nAB82;CHEROKEE SMALL LETTER HV;Ll;0;L;;;;;N;;;13B2;;13B2\nAB83;CHEROKEE SMALL LETTER LA;Ll;0;L;;;;;N;;;13B3;;13B3\nAB84;CHEROKEE SMALL LETTER LE;Ll;0;L;;;;;N;;;13B4;;13B4\nAB85;CHEROKEE SMALL LETTER LI;Ll;0;L;;;;;N;;;13B5;;13B5\nAB86;CHEROKEE SMALL LETTER LO;Ll;0;L;;;;;N;;;13B6;;13B6\nAB87;CHEROKEE SMALL LETTER LU;Ll;0;L;;;;;N;;;13B7;;13B7\nAB88;CHEROKEE SMALL LETTER LV;Ll;0;L;;;;;N;;;13B8;;13B8\nAB89;CHEROKEE SMALL LETTER MA;Ll;0;L;;;;;N;;;13B9;;13B9\nAB8A;CHEROKEE SMALL LETTER ME;Ll;0;L;;;;;N;;;13BA;;13BA\nAB8B;CHEROKEE SMALL LETTER MI;Ll;0;L;;;;;N;;;13BB;;13BB\nAB8C;CHEROKEE SMALL LETTER MO;Ll;0;L;;;;;N;;;13BC;;13BC\nAB8D;CHEROKEE SMALL LETTER MU;Ll;0;L;;;;;N;;;13BD;;13BD\nAB8E;CHEROKEE SMALL LETTER NA;Ll;0;L;;;;;N;;;13BE;;13BE\nAB8F;CHEROKEE SMALL LETTER HNA;Ll;0;L;;;;;N;;;13BF;;13BF\nAB90;CHEROKEE SMALL LETTER NAH;Ll;0;L;;;;;N;;;13C0;;13C0\nAB91;CHEROKEE SMALL LETTER NE;Ll;0;L;;;;;N;;;13C1;;13C1\nAB92;CHEROKEE SMALL LETTER NI;Ll;0;L;;;;;N;;;13C2;;13C2\nAB93;CHEROKEE SMALL LETTER NO;Ll;0;L;;;;;N;;;13C3;;13C3\nAB94;CHEROKEE SMALL LETTER NU;Ll;0;L;;;;;N;;;13C4;;13C4\nAB95;CHEROKEE SMALL LETTER NV;Ll;0;L;;;;;N;;;13C5;;13C5\nAB96;CHEROKEE SMALL LETTER QUA;Ll;0;L;;;;;N;;;13C6;;13C6\nAB97;CHEROKEE SMALL LETTER QUE;Ll;0;L;;;;;N;;;13C7;;13C7\nAB98;CHEROKEE SMALL LETTER QUI;Ll;0;L;;;;;N;;;13C8;;13C8\nAB99;CHEROKEE SMALL LETTER QUO;Ll;0;L;;;;;N;;;13C9;;13C9\nAB9A;CHEROKEE SMALL LETTER QUU;Ll;0;L;;;;;N;;;13CA;;13CA\nAB9B;CHEROKEE SMALL LETTER QUV;Ll;0;L;;;;;N;;;13CB;;13CB\nAB9C;CHEROKEE SMALL LETTER SA;Ll;0;L;;;;;N;;;13CC;;13CC\nAB9D;CHEROKEE SMALL LETTER S;Ll;0;L;;;;;N;;;13CD;;13CD\nAB9E;CHEROKEE SMALL LETTER SE;Ll;0;L;;;;;N;;;13CE;;13CE\nAB9F;CHEROKEE SMALL LETTER SI;Ll;0;L;;;;;N;;;13CF;;13CF\nABA0;CHEROKEE SMALL LETTER SO;Ll;0;L;;;;;N;;;13D0;;13D0\nABA1;CHEROKEE SMALL LETTER SU;Ll;0;L;;;;;N;;;13D1;;13D1\nABA2;CHEROKEE SMALL LETTER SV;Ll;0;L;;;;;N;;;13D2;;13D2\nABA3;CHEROKEE SMALL LETTER DA;Ll;0;L;;;;;N;;;13D3;;13D3\nABA4;CHEROKEE SMALL LETTER TA;Ll;0;L;;;;;N;;;13D4;;13D4\nABA5;CHEROKEE SMALL LETTER DE;Ll;0;L;;;;;N;;;13D5;;13D5\nABA6;CHEROKEE SMALL LETTER TE;Ll;0;L;;;;;N;;;13D6;;13D6\nABA7;CHEROKEE SMALL LETTER DI;Ll;0;L;;;;;N;;;13D7;;13D7\nABA8;CHEROKEE SMALL LETTER TI;Ll;0;L;;;;;N;;;13D8;;13D8\nABA9;CHEROKEE SMALL LETTER DO;Ll;0;L;;;;;N;;;13D9;;13D9\nABAA;CHEROKEE SMALL LETTER DU;Ll;0;L;;;;;N;;;13DA;;13DA\nABAB;CHEROKEE SMALL LETTER DV;Ll;0;L;;;;;N;;;13DB;;13DB\nABAC;CHEROKEE SMALL LETTER DLA;Ll;0;L;;;;;N;;;13DC;;13DC\nABAD;CHEROKEE SMALL LETTER TLA;Ll;0;L;;;;;N;;;13DD;;13DD\nABAE;CHEROKEE SMALL LETTER TLE;Ll;0;L;;;;;N;;;13DE;;13DE\nABAF;CHEROKEE SMALL LETTER TLI;Ll;0;L;;;;;N;;;13DF;;13DF\nABB0;CHEROKEE SMALL LETTER TLO;Ll;0;L;;;;;N;;;13E0;;13E0\nABB1;CHEROKEE SMALL LETTER TLU;Ll;0;L;;;;;N;;;13E1;;13E1\nABB2;CHEROKEE SMALL LETTER TLV;Ll;0;L;;;;;N;;;13E2;;13E2\nABB3;CHEROKEE SMALL LETTER TSA;Ll;0;L;;;;;N;;;13E3;;13E3\nABB4;CHEROKEE SMALL LETTER TSE;Ll;0;L;;;;;N;;;13E4;;13E4\nABB5;CHEROKEE SMALL LETTER TSI;Ll;0;L;;;;;N;;;13E5;;13E5\nABB6;CHEROKEE SMALL LETTER TSO;Ll;0;L;;;;;N;;;13E6;;13E6\nABB7;CHEROKEE SMALL LETTER TSU;Ll;0;L;;;;;N;;;13E7;;13E7\nABB8;CHEROKEE SMALL LETTER TSV;Ll;0;L;;;;;N;;;13E8;;13E8\nABB9;CHEROKEE SMALL LETTER WA;Ll;0;L;;;;;N;;;13E9;;13E9\nABBA;CHEROKEE SMALL LETTER WE;Ll;0;L;;;;;N;;;13EA;;13EA\nABBB;CHEROKEE SMALL LETTER WI;Ll;0;L;;;;;N;;;13EB;;13EB\nABBC;CHEROKEE SMALL LETTER WO;Ll;0;L;;;;;N;;;13EC;;13EC\nABBD;CHEROKEE SMALL LETTER WU;Ll;0;L;;;;;N;;;13ED;;13ED\nABBE;CHEROKEE SMALL LETTER WV;Ll;0;L;;;;;N;;;13EE;;13EE\nABBF;CHEROKEE SMALL LETTER YA;Ll;0;L;;;;;N;;;13EF;;13EF\nABC0;MEETEI MAYEK LETTER KOK;Lo;0;L;;;;;N;;;;;\nABC1;MEETEI MAYEK LETTER SAM;Lo;0;L;;;;;N;;;;;\nABC2;MEETEI MAYEK LETTER LAI;Lo;0;L;;;;;N;;;;;\nABC3;MEETEI MAYEK LETTER MIT;Lo;0;L;;;;;N;;;;;\nABC4;MEETEI MAYEK LETTER PA;Lo;0;L;;;;;N;;;;;\nABC5;MEETEI MAYEK LETTER NA;Lo;0;L;;;;;N;;;;;\nABC6;MEETEI MAYEK LETTER CHIL;Lo;0;L;;;;;N;;;;;\nABC7;MEETEI MAYEK LETTER TIL;Lo;0;L;;;;;N;;;;;\nABC8;MEETEI MAYEK LETTER KHOU;Lo;0;L;;;;;N;;;;;\nABC9;MEETEI MAYEK LETTER NGOU;Lo;0;L;;;;;N;;;;;\nABCA;MEETEI MAYEK LETTER THOU;Lo;0;L;;;;;N;;;;;\nABCB;MEETEI MAYEK LETTER WAI;Lo;0;L;;;;;N;;;;;\nABCC;MEETEI MAYEK LETTER YANG;Lo;0;L;;;;;N;;;;;\nABCD;MEETEI MAYEK LETTER HUK;Lo;0;L;;;;;N;;;;;\nABCE;MEETEI MAYEK LETTER UN;Lo;0;L;;;;;N;;;;;\nABCF;MEETEI MAYEK LETTER I;Lo;0;L;;;;;N;;;;;\nABD0;MEETEI MAYEK LETTER PHAM;Lo;0;L;;;;;N;;;;;\nABD1;MEETEI MAYEK LETTER ATIYA;Lo;0;L;;;;;N;;;;;\nABD2;MEETEI MAYEK LETTER GOK;Lo;0;L;;;;;N;;;;;\nABD3;MEETEI MAYEK LETTER JHAM;Lo;0;L;;;;;N;;;;;\nABD4;MEETEI MAYEK LETTER RAI;Lo;0;L;;;;;N;;;;;\nABD5;MEETEI MAYEK LETTER BA;Lo;0;L;;;;;N;;;;;\nABD6;MEETEI MAYEK LETTER JIL;Lo;0;L;;;;;N;;;;;\nABD7;MEETEI MAYEK LETTER DIL;Lo;0;L;;;;;N;;;;;\nABD8;MEETEI MAYEK LETTER GHOU;Lo;0;L;;;;;N;;;;;\nABD9;MEETEI MAYEK LETTER DHOU;Lo;0;L;;;;;N;;;;;\nABDA;MEETEI MAYEK LETTER BHAM;Lo;0;L;;;;;N;;;;;\nABDB;MEETEI MAYEK LETTER KOK LONSUM;Lo;0;L;;;;;N;;;;;\nABDC;MEETEI MAYEK LETTER LAI LONSUM;Lo;0;L;;;;;N;;;;;\nABDD;MEETEI MAYEK LETTER MIT LONSUM;Lo;0;L;;;;;N;;;;;\nABDE;MEETEI MAYEK LETTER PA LONSUM;Lo;0;L;;;;;N;;;;;\nABDF;MEETEI MAYEK LETTER NA LONSUM;Lo;0;L;;;;;N;;;;;\nABE0;MEETEI MAYEK LETTER TIL LONSUM;Lo;0;L;;;;;N;;;;;\nABE1;MEETEI MAYEK LETTER NGOU LONSUM;Lo;0;L;;;;;N;;;;;\nABE2;MEETEI MAYEK LETTER I LONSUM;Lo;0;L;;;;;N;;;;;\nABE3;MEETEI MAYEK VOWEL SIGN ONAP;Mc;0;L;;;;;N;;;;;\nABE4;MEETEI MAYEK VOWEL SIGN INAP;Mc;0;L;;;;;N;;;;;\nABE5;MEETEI MAYEK VOWEL SIGN ANAP;Mn;0;NSM;;;;;N;;;;;\nABE6;MEETEI MAYEK VOWEL SIGN YENAP;Mc;0;L;;;;;N;;;;;\nABE7;MEETEI MAYEK VOWEL SIGN SOUNAP;Mc;0;L;;;;;N;;;;;\nABE8;MEETEI MAYEK VOWEL SIGN UNAP;Mn;0;NSM;;;;;N;;;;;\nABE9;MEETEI MAYEK VOWEL SIGN CHEINAP;Mc;0;L;;;;;N;;;;;\nABEA;MEETEI MAYEK VOWEL SIGN NUNG;Mc;0;L;;;;;N;;;;;\nABEB;MEETEI MAYEK CHEIKHEI;Po;0;L;;;;;N;;;;;\nABEC;MEETEI MAYEK LUM IYEK;Mc;0;L;;;;;N;;;;;\nABED;MEETEI MAYEK APUN IYEK;Mn;9;NSM;;;;;N;;;;;\nABF0;MEETEI MAYEK DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\nABF1;MEETEI MAYEK DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\nABF2;MEETEI MAYEK DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\nABF3;MEETEI MAYEK DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\nABF4;MEETEI MAYEK DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\nABF5;MEETEI MAYEK DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\nABF6;MEETEI MAYEK DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\nABF7;MEETEI MAYEK DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\nABF8;MEETEI MAYEK DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\nABF9;MEETEI MAYEK DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\nAC00;<Hangul Syllable, First>;Lo;0;L;;;;;N;;;;;\nD7A3;<Hangul Syllable, Last>;Lo;0;L;;;;;N;;;;;\nD7B0;HANGUL JUNGSEONG O-YEO;Lo;0;L;;;;;N;;;;;\nD7B1;HANGUL JUNGSEONG O-O-I;Lo;0;L;;;;;N;;;;;\nD7B2;HANGUL JUNGSEONG YO-A;Lo;0;L;;;;;N;;;;;\nD7B3;HANGUL JUNGSEONG YO-AE;Lo;0;L;;;;;N;;;;;\nD7B4;HANGUL JUNGSEONG YO-EO;Lo;0;L;;;;;N;;;;;\nD7B5;HANGUL JUNGSEONG U-YEO;Lo;0;L;;;;;N;;;;;\nD7B6;HANGUL JUNGSEONG U-I-I;Lo;0;L;;;;;N;;;;;\nD7B7;HANGUL JUNGSEONG YU-AE;Lo;0;L;;;;;N;;;;;\nD7B8;HANGUL JUNGSEONG YU-O;Lo;0;L;;;;;N;;;;;\nD7B9;HANGUL JUNGSEONG EU-A;Lo;0;L;;;;;N;;;;;\nD7BA;HANGUL JUNGSEONG EU-EO;Lo;0;L;;;;;N;;;;;\nD7BB;HANGUL JUNGSEONG EU-E;Lo;0;L;;;;;N;;;;;\nD7BC;HANGUL JUNGSEONG EU-O;Lo;0;L;;;;;N;;;;;\nD7BD;HANGUL JUNGSEONG I-YA-O;Lo;0;L;;;;;N;;;;;\nD7BE;HANGUL JUNGSEONG I-YAE;Lo;0;L;;;;;N;;;;;\nD7BF;HANGUL JUNGSEONG I-YEO;Lo;0;L;;;;;N;;;;;\nD7C0;HANGUL JUNGSEONG I-YE;Lo;0;L;;;;;N;;;;;\nD7C1;HANGUL JUNGSEONG I-O-I;Lo;0;L;;;;;N;;;;;\nD7C2;HANGUL JUNGSEONG I-YO;Lo;0;L;;;;;N;;;;;\nD7C3;HANGUL JUNGSEONG I-YU;Lo;0;L;;;;;N;;;;;\nD7C4;HANGUL JUNGSEONG I-I;Lo;0;L;;;;;N;;;;;\nD7C5;HANGUL JUNGSEONG ARAEA-A;Lo;0;L;;;;;N;;;;;\nD7C6;HANGUL JUNGSEONG ARAEA-E;Lo;0;L;;;;;N;;;;;\nD7CB;HANGUL JONGSEONG NIEUN-RIEUL;Lo;0;L;;;;;N;;;;;\nD7CC;HANGUL JONGSEONG NIEUN-CHIEUCH;Lo;0;L;;;;;N;;;;;\nD7CD;HANGUL JONGSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;;;;\nD7CE;HANGUL JONGSEONG SSANGTIKEUT-PIEUP;Lo;0;L;;;;;N;;;;;\nD7CF;HANGUL JONGSEONG TIKEUT-PIEUP;Lo;0;L;;;;;N;;;;;\nD7D0;HANGUL JONGSEONG TIKEUT-SIOS;Lo;0;L;;;;;N;;;;;\nD7D1;HANGUL JONGSEONG TIKEUT-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;\nD7D2;HANGUL JONGSEONG TIKEUT-CIEUC;Lo;0;L;;;;;N;;;;;\nD7D3;HANGUL JONGSEONG TIKEUT-CHIEUCH;Lo;0;L;;;;;N;;;;;\nD7D4;HANGUL JONGSEONG TIKEUT-THIEUTH;Lo;0;L;;;;;N;;;;;\nD7D5;HANGUL JONGSEONG RIEUL-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;\nD7D6;HANGUL JONGSEONG RIEUL-KIYEOK-HIEUH;Lo;0;L;;;;;N;;;;;\nD7D7;HANGUL JONGSEONG SSANGRIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;\nD7D8;HANGUL JONGSEONG RIEUL-MIEUM-HIEUH;Lo;0;L;;;;;N;;;;;\nD7D9;HANGUL JONGSEONG RIEUL-PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;\nD7DA;HANGUL JONGSEONG RIEUL-PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;\nD7DB;HANGUL JONGSEONG RIEUL-YESIEUNG;Lo;0;L;;;;;N;;;;;\nD7DC;HANGUL JONGSEONG RIEUL-YEORINHIEUH-HIEUH;Lo;0;L;;;;;N;;;;;\nD7DD;HANGUL JONGSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;;\nD7DE;HANGUL JONGSEONG MIEUM-NIEUN;Lo;0;L;;;;;N;;;;;\nD7DF;HANGUL JONGSEONG MIEUM-SSANGNIEUN;Lo;0;L;;;;;N;;;;;\nD7E0;HANGUL JONGSEONG SSANGMIEUM;Lo;0;L;;;;;N;;;;;\nD7E1;HANGUL JONGSEONG MIEUM-PIEUP-SIOS;Lo;0;L;;;;;N;;;;;\nD7E2;HANGUL JONGSEONG MIEUM-CIEUC;Lo;0;L;;;;;N;;;;;\nD7E3;HANGUL JONGSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;\nD7E4;HANGUL JONGSEONG PIEUP-RIEUL-PHIEUPH;Lo;0;L;;;;;N;;;;;\nD7E5;HANGUL JONGSEONG PIEUP-MIEUM;Lo;0;L;;;;;N;;;;;\nD7E6;HANGUL JONGSEONG SSANGPIEUP;Lo;0;L;;;;;N;;;;;\nD7E7;HANGUL JONGSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;\nD7E8;HANGUL JONGSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;;\nD7E9;HANGUL JONGSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;;\nD7EA;HANGUL JONGSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;;\nD7EB;HANGUL JONGSEONG SIOS-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;\nD7EC;HANGUL JONGSEONG SSANGSIOS-KIYEOK;Lo;0;L;;;;;N;;;;;\nD7ED;HANGUL JONGSEONG SSANGSIOS-TIKEUT;Lo;0;L;;;;;N;;;;;\nD7EE;HANGUL JONGSEONG SIOS-PANSIOS;Lo;0;L;;;;;N;;;;;\nD7EF;HANGUL JONGSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;;\nD7F0;HANGUL JONGSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;;\nD7F1;HANGUL JONGSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;\nD7F2;HANGUL JONGSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;;\nD7F3;HANGUL JONGSEONG PANSIOS-PIEUP;Lo;0;L;;;;;N;;;;;\nD7F4;HANGUL JONGSEONG PANSIOS-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;\nD7F5;HANGUL JONGSEONG YESIEUNG-MIEUM;Lo;0;L;;;;;N;;;;;\nD7F6;HANGUL JONGSEONG YESIEUNG-HIEUH;Lo;0;L;;;;;N;;;;;\nD7F7;HANGUL JONGSEONG CIEUC-PIEUP;Lo;0;L;;;;;N;;;;;\nD7F8;HANGUL JONGSEONG CIEUC-SSANGPIEUP;Lo;0;L;;;;;N;;;;;\nD7F9;HANGUL JONGSEONG SSANGCIEUC;Lo;0;L;;;;;N;;;;;\nD7FA;HANGUL JONGSEONG PHIEUPH-SIOS;Lo;0;L;;;;;N;;;;;\nD7FB;HANGUL JONGSEONG PHIEUPH-THIEUTH;Lo;0;L;;;;;N;;;;;\nD800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;\nDB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;\nDB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;\nDBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;\nDC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;;\nDFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;;\nE000;<Private Use, First>;Co;0;L;;;;;N;;;;;\nF8FF;<Private Use, Last>;Co;0;L;;;;;N;;;;;\nF900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;;\nF901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;;\nF902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;;\nF903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;;\nF904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;;\nF905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;;\nF906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;;\nF907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;;\nF908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;;\nF909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;;\nF90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;;\nF90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;;\nF90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;;\nF90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;;\nF90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;;\nF90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;;\nF910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;;\nF911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;;\nF912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;;\nF913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;;\nF914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;;\nF915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;;\nF916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;;\nF917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;;\nF918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;;\nF919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;;\nF91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;;\nF91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;;\nF91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;;\nF91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;;\nF91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;;\nF91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;;\nF920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;;\nF921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;;\nF922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;;\nF923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;;\nF924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;;\nF925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;;\nF926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;;\nF927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;;\nF928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;;\nF929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;;\nF92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;;\nF92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;;\nF92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;;\nF92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;;\nF92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;;\nF92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;;\nF930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;;\nF931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;;\nF932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;;\nF933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;;\nF934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;;\nF935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;;\nF936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;;\nF937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;;\nF938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;;\nF939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;;\nF93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;;\nF93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;;\nF93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;;\nF93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;;\nF93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;;\nF93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;;\nF940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;;\nF941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;;\nF942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;;\nF943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;;\nF944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;;\nF945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;;\nF946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;;\nF947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;;\nF948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;;\nF949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;;\nF94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;;\nF94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;;\nF94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;;\nF94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;;\nF94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;;\nF94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;;\nF950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;;\nF951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;964B;;;;N;;;;;\nF952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;;\nF953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;;\nF954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;;\nF955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;;\nF956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;;\nF957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;;\nF958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;;\nF959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;;\nF95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;;\nF95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;;\nF95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;;\nF95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;;\nF95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;;\nF95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;;\nF960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;;\nF961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;;\nF962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;;\nF963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;;\nF964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;;\nF965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;;\nF966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;;\nF967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;;\nF968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;;\nF969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;;\nF96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;;\nF96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;3;N;;;;;\nF96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;;\nF96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;;\nF96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;;\nF96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;;\nF970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;;\nF971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;;\nF972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;;\nF973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;10;N;;;;;\nF974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;;\nF975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;;\nF976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;;\nF977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;;\nF978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;2;N;;;;;\nF979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;;\nF97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;;\nF97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;;\nF97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;;\nF97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;;\nF97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;;\nF97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;;\nF980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;;\nF981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;;\nF982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;;\nF983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;;\nF984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;;\nF985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;;\nF986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;;\nF987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;;\nF988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;;\nF989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;;\nF98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;;\nF98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;;\nF98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;;\nF98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;;\nF98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;;\nF98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;;\nF990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;;\nF991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;;\nF992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;;\nF993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;;\nF994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;;\nF995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;;\nF996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;;\nF997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;;\nF998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;;\nF999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;;\nF99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;;\nF99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;;\nF99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;;\nF99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;;\nF99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;;\nF99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;;\nF9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;;\nF9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;;\nF9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;;\nF9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;;\nF9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;;\nF9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;;\nF9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;;\nF9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;;\nF9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;;\nF9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;;\nF9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;;\nF9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;;\nF9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;;\nF9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;;\nF9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;;\nF9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;;\nF9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;;\nF9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;;\nF9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;0;N;;;;;\nF9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;;\nF9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;;\nF9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;;\nF9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;;\nF9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;;\nF9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;;\nF9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;;\nF9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;;\nF9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;;\nF9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;;\nF9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;;\nF9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;;\nF9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;;\nF9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;;\nF9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;;\nF9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;;\nF9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;;\nF9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;;\nF9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;;\nF9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;;\nF9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;;\nF9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;;\nF9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;;\nF9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;;\nF9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;;\nF9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;;\nF9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;;\nF9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;;\nF9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;;\nF9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;;\nF9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;6;N;;;;;\nF9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;;\nF9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;6;N;;;;;\nF9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;;\nF9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;;\nF9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;;\nF9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;;\nF9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;;\nF9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;;\nF9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;;\nF9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;;\nF9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;;\nF9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;;\nF9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;;\nF9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;;\nF9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;;\nF9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;;\nF9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;;\nF9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;;\nF9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;;\nF9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;;\nF9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;;\nF9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;;\nF9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;;\nF9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;;\nF9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;;\nF9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;;\nF9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;;\nF9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;;\nF9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;;\nF9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;;\nF9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;;\nF9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;;\nF9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;;\nF9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;;\nF9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;;\nF9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;;\nF9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;;\nF9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;;\nF9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;;\nF9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;;\nF9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;;\nF9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;;\nF9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;;\nF9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;10;N;;;;;\nF9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;;\nF9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;;\nFA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;;\nFA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;;\nFA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;;\nFA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;;\nFA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;;\nFA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;;\nFA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;;\nFA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;;\nFA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;;\nFA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;;\nFA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;;\nFA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;;\nFA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;;\nFA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;;\nFA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;;\nFA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;;\nFA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;;\nFA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;;\nFA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;;\nFA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;;\nFA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;;\nFA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;;\nFA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;;\nFA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;;\nFA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;;\nFA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;;\nFA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;;\nFA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;;\nFA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;;\nFA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;;\nFA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;;\nFA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;;;;\nFA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;;\nFA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;;\nFA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;;\nFA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;;;;\nFA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;;\nFA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;;\nFA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;;\nFA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;;\nFA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;;\nFA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;;\nFA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;;\nFA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;;\nFA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;;\nFA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;;\nFA2E;CJK COMPATIBILITY IDEOGRAPH-FA2E;Lo;0;L;90DE;;;;N;;;;;\nFA2F;CJK COMPATIBILITY IDEOGRAPH-FA2F;Lo;0;L;96B7;;;;N;;;;;\nFA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;;\nFA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;;\nFA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;;\nFA33;CJK COMPATIBILITY IDEOGRAPH-FA33;Lo;0;L;52C9;;;;N;;;;;\nFA34;CJK COMPATIBILITY IDEOGRAPH-FA34;Lo;0;L;52E4;;;;N;;;;;\nFA35;CJK COMPATIBILITY IDEOGRAPH-FA35;Lo;0;L;5351;;;;N;;;;;\nFA36;CJK COMPATIBILITY IDEOGRAPH-FA36;Lo;0;L;559D;;;;N;;;;;\nFA37;CJK COMPATIBILITY IDEOGRAPH-FA37;Lo;0;L;5606;;;;N;;;;;\nFA38;CJK COMPATIBILITY IDEOGRAPH-FA38;Lo;0;L;5668;;;;N;;;;;\nFA39;CJK COMPATIBILITY IDEOGRAPH-FA39;Lo;0;L;5840;;;;N;;;;;\nFA3A;CJK COMPATIBILITY IDEOGRAPH-FA3A;Lo;0;L;58A8;;;;N;;;;;\nFA3B;CJK COMPATIBILITY IDEOGRAPH-FA3B;Lo;0;L;5C64;;;;N;;;;;\nFA3C;CJK COMPATIBILITY IDEOGRAPH-FA3C;Lo;0;L;5C6E;;;;N;;;;;\nFA3D;CJK COMPATIBILITY IDEOGRAPH-FA3D;Lo;0;L;6094;;;;N;;;;;\nFA3E;CJK COMPATIBILITY IDEOGRAPH-FA3E;Lo;0;L;6168;;;;N;;;;;\nFA3F;CJK COMPATIBILITY IDEOGRAPH-FA3F;Lo;0;L;618E;;;;N;;;;;\nFA40;CJK COMPATIBILITY IDEOGRAPH-FA40;Lo;0;L;61F2;;;;N;;;;;\nFA41;CJK COMPATIBILITY IDEOGRAPH-FA41;Lo;0;L;654F;;;;N;;;;;\nFA42;CJK COMPATIBILITY IDEOGRAPH-FA42;Lo;0;L;65E2;;;;N;;;;;\nFA43;CJK COMPATIBILITY IDEOGRAPH-FA43;Lo;0;L;6691;;;;N;;;;;\nFA44;CJK COMPATIBILITY IDEOGRAPH-FA44;Lo;0;L;6885;;;;N;;;;;\nFA45;CJK COMPATIBILITY IDEOGRAPH-FA45;Lo;0;L;6D77;;;;N;;;;;\nFA46;CJK COMPATIBILITY IDEOGRAPH-FA46;Lo;0;L;6E1A;;;;N;;;;;\nFA47;CJK COMPATIBILITY IDEOGRAPH-FA47;Lo;0;L;6F22;;;;N;;;;;\nFA48;CJK COMPATIBILITY IDEOGRAPH-FA48;Lo;0;L;716E;;;;N;;;;;\nFA49;CJK COMPATIBILITY IDEOGRAPH-FA49;Lo;0;L;722B;;;;N;;;;;\nFA4A;CJK COMPATIBILITY IDEOGRAPH-FA4A;Lo;0;L;7422;;;;N;;;;;\nFA4B;CJK COMPATIBILITY IDEOGRAPH-FA4B;Lo;0;L;7891;;;;N;;;;;\nFA4C;CJK COMPATIBILITY IDEOGRAPH-FA4C;Lo;0;L;793E;;;;N;;;;;\nFA4D;CJK COMPATIBILITY IDEOGRAPH-FA4D;Lo;0;L;7949;;;;N;;;;;\nFA4E;CJK COMPATIBILITY IDEOGRAPH-FA4E;Lo;0;L;7948;;;;N;;;;;\nFA4F;CJK COMPATIBILITY IDEOGRAPH-FA4F;Lo;0;L;7950;;;;N;;;;;\nFA50;CJK COMPATIBILITY IDEOGRAPH-FA50;Lo;0;L;7956;;;;N;;;;;\nFA51;CJK COMPATIBILITY IDEOGRAPH-FA51;Lo;0;L;795D;;;;N;;;;;\nFA52;CJK COMPATIBILITY IDEOGRAPH-FA52;Lo;0;L;798D;;;;N;;;;;\nFA53;CJK COMPATIBILITY IDEOGRAPH-FA53;Lo;0;L;798E;;;;N;;;;;\nFA54;CJK COMPATIBILITY IDEOGRAPH-FA54;Lo;0;L;7A40;;;;N;;;;;\nFA55;CJK COMPATIBILITY IDEOGRAPH-FA55;Lo;0;L;7A81;;;;N;;;;;\nFA56;CJK COMPATIBILITY IDEOGRAPH-FA56;Lo;0;L;7BC0;;;;N;;;;;\nFA57;CJK COMPATIBILITY IDEOGRAPH-FA57;Lo;0;L;7DF4;;;;N;;;;;\nFA58;CJK COMPATIBILITY IDEOGRAPH-FA58;Lo;0;L;7E09;;;;N;;;;;\nFA59;CJK COMPATIBILITY IDEOGRAPH-FA59;Lo;0;L;7E41;;;;N;;;;;\nFA5A;CJK COMPATIBILITY IDEOGRAPH-FA5A;Lo;0;L;7F72;;;;N;;;;;\nFA5B;CJK COMPATIBILITY IDEOGRAPH-FA5B;Lo;0;L;8005;;;;N;;;;;\nFA5C;CJK COMPATIBILITY IDEOGRAPH-FA5C;Lo;0;L;81ED;;;;N;;;;;\nFA5D;CJK COMPATIBILITY IDEOGRAPH-FA5D;Lo;0;L;8279;;;;N;;;;;\nFA5E;CJK COMPATIBILITY IDEOGRAPH-FA5E;Lo;0;L;8279;;;;N;;;;;\nFA5F;CJK COMPATIBILITY IDEOGRAPH-FA5F;Lo;0;L;8457;;;;N;;;;;\nFA60;CJK COMPATIBILITY IDEOGRAPH-FA60;Lo;0;L;8910;;;;N;;;;;\nFA61;CJK COMPATIBILITY IDEOGRAPH-FA61;Lo;0;L;8996;;;;N;;;;;\nFA62;CJK COMPATIBILITY IDEOGRAPH-FA62;Lo;0;L;8B01;;;;N;;;;;\nFA63;CJK COMPATIBILITY IDEOGRAPH-FA63;Lo;0;L;8B39;;;;N;;;;;\nFA64;CJK COMPATIBILITY IDEOGRAPH-FA64;Lo;0;L;8CD3;;;;N;;;;;\nFA65;CJK COMPATIBILITY IDEOGRAPH-FA65;Lo;0;L;8D08;;;;N;;;;;\nFA66;CJK COMPATIBILITY IDEOGRAPH-FA66;Lo;0;L;8FB6;;;;N;;;;;\nFA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;;\nFA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;;\nFA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;;\nFA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;;\nFA6B;CJK COMPATIBILITY IDEOGRAPH-FA6B;Lo;0;L;6075;;;;N;;;;;\nFA6C;CJK COMPATIBILITY IDEOGRAPH-FA6C;Lo;0;L;242EE;;;;N;;;;;\nFA6D;CJK COMPATIBILITY IDEOGRAPH-FA6D;Lo;0;L;8218;;;;N;;;;;\nFA70;CJK COMPATIBILITY IDEOGRAPH-FA70;Lo;0;L;4E26;;;;N;;;;;\nFA71;CJK COMPATIBILITY IDEOGRAPH-FA71;Lo;0;L;51B5;;;;N;;;;;\nFA72;CJK COMPATIBILITY IDEOGRAPH-FA72;Lo;0;L;5168;;;;N;;;;;\nFA73;CJK COMPATIBILITY IDEOGRAPH-FA73;Lo;0;L;4F80;;;;N;;;;;\nFA74;CJK COMPATIBILITY IDEOGRAPH-FA74;Lo;0;L;5145;;;;N;;;;;\nFA75;CJK COMPATIBILITY IDEOGRAPH-FA75;Lo;0;L;5180;;;;N;;;;;\nFA76;CJK COMPATIBILITY IDEOGRAPH-FA76;Lo;0;L;52C7;;;;N;;;;;\nFA77;CJK COMPATIBILITY IDEOGRAPH-FA77;Lo;0;L;52FA;;;;N;;;;;\nFA78;CJK COMPATIBILITY IDEOGRAPH-FA78;Lo;0;L;559D;;;;N;;;;;\nFA79;CJK COMPATIBILITY IDEOGRAPH-FA79;Lo;0;L;5555;;;;N;;;;;\nFA7A;CJK COMPATIBILITY IDEOGRAPH-FA7A;Lo;0;L;5599;;;;N;;;;;\nFA7B;CJK COMPATIBILITY IDEOGRAPH-FA7B;Lo;0;L;55E2;;;;N;;;;;\nFA7C;CJK COMPATIBILITY IDEOGRAPH-FA7C;Lo;0;L;585A;;;;N;;;;;\nFA7D;CJK COMPATIBILITY IDEOGRAPH-FA7D;Lo;0;L;58B3;;;;N;;;;;\nFA7E;CJK COMPATIBILITY IDEOGRAPH-FA7E;Lo;0;L;5944;;;;N;;;;;\nFA7F;CJK COMPATIBILITY IDEOGRAPH-FA7F;Lo;0;L;5954;;;;N;;;;;\nFA80;CJK COMPATIBILITY IDEOGRAPH-FA80;Lo;0;L;5A62;;;;N;;;;;\nFA81;CJK COMPATIBILITY IDEOGRAPH-FA81;Lo;0;L;5B28;;;;N;;;;;\nFA82;CJK COMPATIBILITY IDEOGRAPH-FA82;Lo;0;L;5ED2;;;;N;;;;;\nFA83;CJK COMPATIBILITY IDEOGRAPH-FA83;Lo;0;L;5ED9;;;;N;;;;;\nFA84;CJK COMPATIBILITY IDEOGRAPH-FA84;Lo;0;L;5F69;;;;N;;;;;\nFA85;CJK COMPATIBILITY IDEOGRAPH-FA85;Lo;0;L;5FAD;;;;N;;;;;\nFA86;CJK COMPATIBILITY IDEOGRAPH-FA86;Lo;0;L;60D8;;;;N;;;;;\nFA87;CJK COMPATIBILITY IDEOGRAPH-FA87;Lo;0;L;614E;;;;N;;;;;\nFA88;CJK COMPATIBILITY IDEOGRAPH-FA88;Lo;0;L;6108;;;;N;;;;;\nFA89;CJK COMPATIBILITY IDEOGRAPH-FA89;Lo;0;L;618E;;;;N;;;;;\nFA8A;CJK COMPATIBILITY IDEOGRAPH-FA8A;Lo;0;L;6160;;;;N;;;;;\nFA8B;CJK COMPATIBILITY IDEOGRAPH-FA8B;Lo;0;L;61F2;;;;N;;;;;\nFA8C;CJK COMPATIBILITY IDEOGRAPH-FA8C;Lo;0;L;6234;;;;N;;;;;\nFA8D;CJK COMPATIBILITY IDEOGRAPH-FA8D;Lo;0;L;63C4;;;;N;;;;;\nFA8E;CJK COMPATIBILITY IDEOGRAPH-FA8E;Lo;0;L;641C;;;;N;;;;;\nFA8F;CJK COMPATIBILITY IDEOGRAPH-FA8F;Lo;0;L;6452;;;;N;;;;;\nFA90;CJK COMPATIBILITY IDEOGRAPH-FA90;Lo;0;L;6556;;;;N;;;;;\nFA91;CJK COMPATIBILITY IDEOGRAPH-FA91;Lo;0;L;6674;;;;N;;;;;\nFA92;CJK COMPATIBILITY IDEOGRAPH-FA92;Lo;0;L;6717;;;;N;;;;;\nFA93;CJK COMPATIBILITY IDEOGRAPH-FA93;Lo;0;L;671B;;;;N;;;;;\nFA94;CJK COMPATIBILITY IDEOGRAPH-FA94;Lo;0;L;6756;;;;N;;;;;\nFA95;CJK COMPATIBILITY IDEOGRAPH-FA95;Lo;0;L;6B79;;;;N;;;;;\nFA96;CJK COMPATIBILITY IDEOGRAPH-FA96;Lo;0;L;6BBA;;;;N;;;;;\nFA97;CJK COMPATIBILITY IDEOGRAPH-FA97;Lo;0;L;6D41;;;;N;;;;;\nFA98;CJK COMPATIBILITY IDEOGRAPH-FA98;Lo;0;L;6EDB;;;;N;;;;;\nFA99;CJK COMPATIBILITY IDEOGRAPH-FA99;Lo;0;L;6ECB;;;;N;;;;;\nFA9A;CJK COMPATIBILITY IDEOGRAPH-FA9A;Lo;0;L;6F22;;;;N;;;;;\nFA9B;CJK COMPATIBILITY IDEOGRAPH-FA9B;Lo;0;L;701E;;;;N;;;;;\nFA9C;CJK COMPATIBILITY IDEOGRAPH-FA9C;Lo;0;L;716E;;;;N;;;;;\nFA9D;CJK COMPATIBILITY IDEOGRAPH-FA9D;Lo;0;L;77A7;;;;N;;;;;\nFA9E;CJK COMPATIBILITY IDEOGRAPH-FA9E;Lo;0;L;7235;;;;N;;;;;\nFA9F;CJK COMPATIBILITY IDEOGRAPH-FA9F;Lo;0;L;72AF;;;;N;;;;;\nFAA0;CJK COMPATIBILITY IDEOGRAPH-FAA0;Lo;0;L;732A;;;;N;;;;;\nFAA1;CJK COMPATIBILITY IDEOGRAPH-FAA1;Lo;0;L;7471;;;;N;;;;;\nFAA2;CJK COMPATIBILITY IDEOGRAPH-FAA2;Lo;0;L;7506;;;;N;;;;;\nFAA3;CJK COMPATIBILITY IDEOGRAPH-FAA3;Lo;0;L;753B;;;;N;;;;;\nFAA4;CJK COMPATIBILITY IDEOGRAPH-FAA4;Lo;0;L;761D;;;;N;;;;;\nFAA5;CJK COMPATIBILITY IDEOGRAPH-FAA5;Lo;0;L;761F;;;;N;;;;;\nFAA6;CJK COMPATIBILITY IDEOGRAPH-FAA6;Lo;0;L;76CA;;;;N;;;;;\nFAA7;CJK COMPATIBILITY IDEOGRAPH-FAA7;Lo;0;L;76DB;;;;N;;;;;\nFAA8;CJK COMPATIBILITY IDEOGRAPH-FAA8;Lo;0;L;76F4;;;;N;;;;;\nFAA9;CJK COMPATIBILITY IDEOGRAPH-FAA9;Lo;0;L;774A;;;;N;;;;;\nFAAA;CJK COMPATIBILITY IDEOGRAPH-FAAA;Lo;0;L;7740;;;;N;;;;;\nFAAB;CJK COMPATIBILITY IDEOGRAPH-FAAB;Lo;0;L;78CC;;;;N;;;;;\nFAAC;CJK COMPATIBILITY IDEOGRAPH-FAAC;Lo;0;L;7AB1;;;;N;;;;;\nFAAD;CJK COMPATIBILITY IDEOGRAPH-FAAD;Lo;0;L;7BC0;;;;N;;;;;\nFAAE;CJK COMPATIBILITY IDEOGRAPH-FAAE;Lo;0;L;7C7B;;;;N;;;;;\nFAAF;CJK COMPATIBILITY IDEOGRAPH-FAAF;Lo;0;L;7D5B;;;;N;;;;;\nFAB0;CJK COMPATIBILITY IDEOGRAPH-FAB0;Lo;0;L;7DF4;;;;N;;;;;\nFAB1;CJK COMPATIBILITY IDEOGRAPH-FAB1;Lo;0;L;7F3E;;;;N;;;;;\nFAB2;CJK COMPATIBILITY IDEOGRAPH-FAB2;Lo;0;L;8005;;;;N;;;;;\nFAB3;CJK COMPATIBILITY IDEOGRAPH-FAB3;Lo;0;L;8352;;;;N;;;;;\nFAB4;CJK COMPATIBILITY IDEOGRAPH-FAB4;Lo;0;L;83EF;;;;N;;;;;\nFAB5;CJK COMPATIBILITY IDEOGRAPH-FAB5;Lo;0;L;8779;;;;N;;;;;\nFAB6;CJK COMPATIBILITY IDEOGRAPH-FAB6;Lo;0;L;8941;;;;N;;;;;\nFAB7;CJK COMPATIBILITY IDEOGRAPH-FAB7;Lo;0;L;8986;;;;N;;;;;\nFAB8;CJK COMPATIBILITY IDEOGRAPH-FAB8;Lo;0;L;8996;;;;N;;;;;\nFAB9;CJK COMPATIBILITY IDEOGRAPH-FAB9;Lo;0;L;8ABF;;;;N;;;;;\nFABA;CJK COMPATIBILITY IDEOGRAPH-FABA;Lo;0;L;8AF8;;;;N;;;;;\nFABB;CJK COMPATIBILITY IDEOGRAPH-FABB;Lo;0;L;8ACB;;;;N;;;;;\nFABC;CJK COMPATIBILITY IDEOGRAPH-FABC;Lo;0;L;8B01;;;;N;;;;;\nFABD;CJK COMPATIBILITY IDEOGRAPH-FABD;Lo;0;L;8AFE;;;;N;;;;;\nFABE;CJK COMPATIBILITY IDEOGRAPH-FABE;Lo;0;L;8AED;;;;N;;;;;\nFABF;CJK COMPATIBILITY IDEOGRAPH-FABF;Lo;0;L;8B39;;;;N;;;;;\nFAC0;CJK COMPATIBILITY IDEOGRAPH-FAC0;Lo;0;L;8B8A;;;;N;;;;;\nFAC1;CJK COMPATIBILITY IDEOGRAPH-FAC1;Lo;0;L;8D08;;;;N;;;;;\nFAC2;CJK COMPATIBILITY IDEOGRAPH-FAC2;Lo;0;L;8F38;;;;N;;;;;\nFAC3;CJK COMPATIBILITY IDEOGRAPH-FAC3;Lo;0;L;9072;;;;N;;;;;\nFAC4;CJK COMPATIBILITY IDEOGRAPH-FAC4;Lo;0;L;9199;;;;N;;;;;\nFAC5;CJK COMPATIBILITY IDEOGRAPH-FAC5;Lo;0;L;9276;;;;N;;;;;\nFAC6;CJK COMPATIBILITY IDEOGRAPH-FAC6;Lo;0;L;967C;;;;N;;;;;\nFAC7;CJK COMPATIBILITY IDEOGRAPH-FAC7;Lo;0;L;96E3;;;;N;;;;;\nFAC8;CJK COMPATIBILITY IDEOGRAPH-FAC8;Lo;0;L;9756;;;;N;;;;;\nFAC9;CJK COMPATIBILITY IDEOGRAPH-FAC9;Lo;0;L;97DB;;;;N;;;;;\nFACA;CJK COMPATIBILITY IDEOGRAPH-FACA;Lo;0;L;97FF;;;;N;;;;;\nFACB;CJK COMPATIBILITY IDEOGRAPH-FACB;Lo;0;L;980B;;;;N;;;;;\nFACC;CJK COMPATIBILITY IDEOGRAPH-FACC;Lo;0;L;983B;;;;N;;;;;\nFACD;CJK COMPATIBILITY IDEOGRAPH-FACD;Lo;0;L;9B12;;;;N;;;;;\nFACE;CJK COMPATIBILITY IDEOGRAPH-FACE;Lo;0;L;9F9C;;;;N;;;;;\nFACF;CJK COMPATIBILITY IDEOGRAPH-FACF;Lo;0;L;2284A;;;;N;;;;;\nFAD0;CJK COMPATIBILITY IDEOGRAPH-FAD0;Lo;0;L;22844;;;;N;;;;;\nFAD1;CJK COMPATIBILITY IDEOGRAPH-FAD1;Lo;0;L;233D5;;;;N;;;;;\nFAD2;CJK COMPATIBILITY IDEOGRAPH-FAD2;Lo;0;L;3B9D;;;;N;;;;;\nFAD3;CJK COMPATIBILITY IDEOGRAPH-FAD3;Lo;0;L;4018;;;;N;;;;;\nFAD4;CJK COMPATIBILITY IDEOGRAPH-FAD4;Lo;0;L;4039;;;;N;;;;;\nFAD5;CJK COMPATIBILITY IDEOGRAPH-FAD5;Lo;0;L;25249;;;;N;;;;;\nFAD6;CJK COMPATIBILITY IDEOGRAPH-FAD6;Lo;0;L;25CD0;;;;N;;;;;\nFAD7;CJK COMPATIBILITY IDEOGRAPH-FAD7;Lo;0;L;27ED3;;;;N;;;;;\nFAD8;CJK COMPATIBILITY IDEOGRAPH-FAD8;Lo;0;L;9F43;;;;N;;;;;\nFAD9;CJK COMPATIBILITY IDEOGRAPH-FAD9;Lo;0;L;9F8E;;;;N;;;;;\nFB00;LATIN SMALL LIGATURE FF;Ll;0;L;<compat> 0066 0066;;;;N;;;;;\nFB01;LATIN SMALL LIGATURE FI;Ll;0;L;<compat> 0066 0069;;;;N;;;;;\nFB02;LATIN SMALL LIGATURE FL;Ll;0;L;<compat> 0066 006C;;;;N;;;;;\nFB03;LATIN SMALL LIGATURE FFI;Ll;0;L;<compat> 0066 0066 0069;;;;N;;;;;\nFB04;LATIN SMALL LIGATURE FFL;Ll;0;L;<compat> 0066 0066 006C;;;;N;;;;;\nFB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L;<compat> 017F 0074;;;;N;;;;;\nFB06;LATIN SMALL LIGATURE ST;Ll;0;L;<compat> 0073 0074;;;;N;;;;;\nFB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L;<compat> 0574 0576;;;;N;;;;;\nFB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L;<compat> 0574 0565;;;;N;;;;;\nFB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L;<compat> 0574 056B;;;;N;;;;;\nFB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L;<compat> 057E 0576;;;;N;;;;;\nFB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L;<compat> 0574 056D;;;;N;;;;;\nFB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;;\nFB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;;\nFB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;;\nFB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R;<font> 05E2;;;;N;;;;;\nFB21;HEBREW LETTER WIDE ALEF;Lo;0;R;<font> 05D0;;;;N;;;;;\nFB22;HEBREW LETTER WIDE DALET;Lo;0;R;<font> 05D3;;;;N;;;;;\nFB23;HEBREW LETTER WIDE HE;Lo;0;R;<font> 05D4;;;;N;;;;;\nFB24;HEBREW LETTER WIDE KAF;Lo;0;R;<font> 05DB;;;;N;;;;;\nFB25;HEBREW LETTER WIDE LAMED;Lo;0;R;<font> 05DC;;;;N;;;;;\nFB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R;<font> 05DD;;;;N;;;;;\nFB27;HEBREW LETTER WIDE RESH;Lo;0;R;<font> 05E8;;;;N;;;;;\nFB28;HEBREW LETTER WIDE TAV;Lo;0;R;<font> 05EA;;;;N;;;;;\nFB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ES;<font> 002B;;;;N;;;;;\nFB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;;\nFB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;;\nFB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;;\nFB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;;\nFB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;;\nFB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;;\nFB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;;\nFB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;;\nFB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;;\nFB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;;\nFB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;;\nFB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;;\nFB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;;\nFB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;;\nFB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;;\nFB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;;\nFB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;;\nFB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;;\nFB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;;\nFB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;;\nFB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;;\nFB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;;\nFB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;;\nFB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;;\nFB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;;\nFB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;;\nFB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;;\nFB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;;\nFB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;;\nFB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;;\nFB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;;\nFB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;;\nFB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R;<compat> 05D0 05DC;;;;N;;;;;\nFB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL;<isolated> 0671;;;;N;;;;;\nFB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL;<final> 0671;;;;N;;;;;\nFB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL;<isolated> 067B;;;;N;;;;;\nFB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL;<final> 067B;;;;N;;;;;\nFB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL;<initial> 067B;;;;N;;;;;\nFB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL;<medial> 067B;;;;N;;;;;\nFB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL;<isolated> 067E;;;;N;;;;;\nFB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL;<final> 067E;;;;N;;;;;\nFB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL;<initial> 067E;;;;N;;;;;\nFB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL;<medial> 067E;;;;N;;;;;\nFB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0680;;;;N;;;;;\nFB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL;<final> 0680;;;;N;;;;;\nFB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL;<initial> 0680;;;;N;;;;;\nFB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL;<medial> 0680;;;;N;;;;;\nFB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067A;;;;N;;;;;\nFB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL;<final> 067A;;;;N;;;;;\nFB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL;<initial> 067A;;;;N;;;;;\nFB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL;<medial> 067A;;;;N;;;;;\nFB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067F;;;;N;;;;;\nFB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL;<final> 067F;;;;N;;;;;\nFB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL;<initial> 067F;;;;N;;;;;\nFB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL;<medial> 067F;;;;N;;;;;\nFB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL;<isolated> 0679;;;;N;;;;;\nFB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL;<final> 0679;;;;N;;;;;\nFB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL;<initial> 0679;;;;N;;;;;\nFB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL;<medial> 0679;;;;N;;;;;\nFB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL;<isolated> 06A4;;;;N;;;;;\nFB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL;<final> 06A4;;;;N;;;;;\nFB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL;<initial> 06A4;;;;N;;;;;\nFB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL;<medial> 06A4;;;;N;;;;;\nFB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A6;;;;N;;;;;\nFB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL;<final> 06A6;;;;N;;;;;\nFB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL;<initial> 06A6;;;;N;;;;;\nFB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A6;;;;N;;;;;\nFB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL;<isolated> 0684;;;;N;;;;;\nFB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL;<final> 0684;;;;N;;;;;\nFB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL;<initial> 0684;;;;N;;;;;\nFB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL;<medial> 0684;;;;N;;;;;\nFB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL;<isolated> 0683;;;;N;;;;;\nFB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL;<final> 0683;;;;N;;;;;\nFB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL;<initial> 0683;;;;N;;;;;\nFB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL;<medial> 0683;;;;N;;;;;\nFB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL;<isolated> 0686;;;;N;;;;;\nFB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL;<final> 0686;;;;N;;;;;\nFB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL;<initial> 0686;;;;N;;;;;\nFB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL;<medial> 0686;;;;N;;;;;\nFB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0687;;;;N;;;;;\nFB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL;<final> 0687;;;;N;;;;;\nFB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL;<initial> 0687;;;;N;;;;;\nFB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL;<medial> 0687;;;;N;;;;;\nFB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068D;;;;N;;;;;\nFB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL;<final> 068D;;;;N;;;;;\nFB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068C;;;;N;;;;;\nFB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL;<final> 068C;;;;N;;;;;\nFB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL;<isolated> 068E;;;;N;;;;;\nFB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL;<final> 068E;;;;N;;;;;\nFB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL;<isolated> 0688;;;;N;;;;;\nFB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL;<final> 0688;;;;N;;;;;\nFB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL;<isolated> 0698;;;;N;;;;;\nFB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL;<final> 0698;;;;N;;;;;\nFB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL;<isolated> 0691;;;;N;;;;;\nFB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL;<final> 0691;;;;N;;;;;\nFB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A9;;;;N;;;;;\nFB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL;<final> 06A9;;;;N;;;;;\nFB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL;<initial> 06A9;;;;N;;;;;\nFB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A9;;;;N;;;;;\nFB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL;<isolated> 06AF;;;;N;;;;;\nFB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL;<final> 06AF;;;;N;;;;;\nFB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL;<initial> 06AF;;;;N;;;;;\nFB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL;<medial> 06AF;;;;N;;;;;\nFB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL;<isolated> 06B3;;;;N;;;;;\nFB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL;<final> 06B3;;;;N;;;;;\nFB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL;<initial> 06B3;;;;N;;;;;\nFB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL;<medial> 06B3;;;;N;;;;;\nFB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL;<isolated> 06B1;;;;N;;;;;\nFB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL;<final> 06B1;;;;N;;;;;\nFB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL;<initial> 06B1;;;;N;;;;;\nFB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL;<medial> 06B1;;;;N;;;;;\nFB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL;<isolated> 06BA;;;;N;;;;;\nFB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL;<final> 06BA;;;;N;;;;;\nFBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL;<isolated> 06BB;;;;N;;;;;\nFBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL;<final> 06BB;;;;N;;;;;\nFBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL;<initial> 06BB;;;;N;;;;;\nFBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL;<medial> 06BB;;;;N;;;;;\nFBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06C0;;;;N;;;;;\nFBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL;<final> 06C0;;;;N;;;;;\nFBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL;<isolated> 06C1;;;;N;;;;;\nFBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL;<final> 06C1;;;;N;;;;;\nFBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL;<initial> 06C1;;;;N;;;;;\nFBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL;<medial> 06C1;;;;N;;;;;\nFBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL;<isolated> 06BE;;;;N;;;;;\nFBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL;<final> 06BE;;;;N;;;;;\nFBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL;<initial> 06BE;;;;N;;;;;\nFBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL;<medial> 06BE;;;;N;;;;;\nFBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL;<isolated> 06D2;;;;N;;;;;\nFBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL;<final> 06D2;;;;N;;;;;\nFBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06D3;;;;N;;;;;\nFBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 06D3;;;;N;;;;;\nFBB2;ARABIC SYMBOL DOT ABOVE;Sk;0;AL;;;;;N;;;;;\nFBB3;ARABIC SYMBOL DOT BELOW;Sk;0;AL;;;;;N;;;;;\nFBB4;ARABIC SYMBOL TWO DOTS ABOVE;Sk;0;AL;;;;;N;;;;;\nFBB5;ARABIC SYMBOL TWO DOTS BELOW;Sk;0;AL;;;;;N;;;;;\nFBB6;ARABIC SYMBOL THREE DOTS ABOVE;Sk;0;AL;;;;;N;;;;;\nFBB7;ARABIC SYMBOL THREE DOTS BELOW;Sk;0;AL;;;;;N;;;;;\nFBB8;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS ABOVE;Sk;0;AL;;;;;N;;;;;\nFBB9;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS BELOW;Sk;0;AL;;;;;N;;;;;\nFBBA;ARABIC SYMBOL FOUR DOTS ABOVE;Sk;0;AL;;;;;N;;;;;\nFBBB;ARABIC SYMBOL FOUR DOTS BELOW;Sk;0;AL;;;;;N;;;;;\nFBBC;ARABIC SYMBOL DOUBLE VERTICAL BAR BELOW;Sk;0;AL;;;;;N;;;;;\nFBBD;ARABIC SYMBOL TWO DOTS VERTICALLY ABOVE;Sk;0;AL;;;;;N;;;;;\nFBBE;ARABIC SYMBOL TWO DOTS VERTICALLY BELOW;Sk;0;AL;;;;;N;;;;;\nFBBF;ARABIC SYMBOL RING;Sk;0;AL;;;;;N;;;;;\nFBC0;ARABIC SYMBOL SMALL TAH ABOVE;Sk;0;AL;;;;;N;;;;;\nFBC1;ARABIC SYMBOL SMALL TAH BELOW;Sk;0;AL;;;;;N;;;;;\nFBC2;ARABIC SYMBOL WASLA ABOVE;Sk;0;AL;;;;;N;;;;;\nFBC3;ARABIC LIGATURE JALLA WA-ALAA;So;0;ON;;;;;N;;;;;\nFBC4;ARABIC LIGATURE DAAMAT BARAKAATUHUM;So;0;ON;;;;;N;;;;;\nFBC5;ARABIC LIGATURE RAHMATU ALLAAHI TAAALAA ALAYH;So;0;ON;;;;;N;;;;;\nFBC6;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIM;So;0;ON;;;;;N;;;;;\nFBC7;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIMAA;So;0;ON;;;;;N;;;;;\nFBC8;ARABIC LIGATURE RAHIMAHUM ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;\nFBC9;ARABIC LIGATURE RAHIMAHUMAA ALLAAH;So;0;ON;;;;;N;;;;;\nFBCA;ARABIC LIGATURE RAHIMAHUMAA ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;\nFBCB;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUM;So;0;ON;;;;;N;;;;;\nFBCC;ARABIC LIGATURE HAFIZAHU ALLAAH;So;0;ON;;;;;N;;;;;\nFBCD;ARABIC LIGATURE HAFIZAHU ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;\nFBCE;ARABIC LIGATURE HAFIZAHUM ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;\nFBCF;ARABIC LIGATURE HAFIZAHUMAA ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;\nFBD0;ARABIC LIGATURE SALLALLAAHU TAAALAA ALAYHI WA-SALLAM;So;0;ON;;;;;N;;;;;\nFBD1;ARABIC LIGATURE AJJAL ALLAAHU FARAJAHU ASH-SHAREEF;So;0;ON;;;;;N;;;;;\nFBD2;ARABIC LIGATURE ALAYHI AR-RAHMAH;So;0;ON;;;;;N;;;;;\nFBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL;<isolated> 06AD;;;;N;;;;;\nFBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL;<final> 06AD;;;;N;;;;;\nFBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL;<initial> 06AD;;;;N;;;;;\nFBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL;<medial> 06AD;;;;N;;;;;\nFBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL;<isolated> 06C7;;;;N;;;;;\nFBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL;<final> 06C7;;;;N;;;;;\nFBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL;<isolated> 06C6;;;;N;;;;;\nFBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL;<final> 06C6;;;;N;;;;;\nFBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL;<isolated> 06C8;;;;N;;;;;\nFBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL;<final> 06C8;;;;N;;;;;\nFBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0677;;;;N;;;;;\nFBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL;<isolated> 06CB;;;;N;;;;;\nFBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL;<final> 06CB;;;;N;;;;;\nFBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL;<isolated> 06C5;;;;N;;;;;\nFBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL;<final> 06C5;;;;N;;;;;\nFBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL;<isolated> 06C9;;;;N;;;;;\nFBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL;<final> 06C9;;;;N;;;;;\nFBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL;<isolated> 06D0;;;;N;;;;;\nFBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL;<final> 06D0;;;;N;;;;;\nFBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL;<initial> 06D0;;;;N;;;;;\nFBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL;<medial> 06D0;;;;N;;;;;\nFBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0649;;;;N;;;;;\nFBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL;<medial> 0649;;;;N;;;;;\nFBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0626 0627;;;;N;;;;;\nFBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL;<final> 0626 0627;;;;N;;;;;\nFBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D5;;;;N;;;;;\nFBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL;<final> 0626 06D5;;;;N;;;;;\nFBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL;<isolated> 0626 0648;;;;N;;;;;\nFBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL;<final> 0626 0648;;;;N;;;;;\nFBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C7;;;;N;;;;;\nFBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL;<final> 0626 06C7;;;;N;;;;;\nFBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C6;;;;N;;;;;\nFBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL;<final> 0626 06C6;;;;N;;;;;\nFBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C8;;;;N;;;;;\nFBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL;<final> 0626 06C8;;;;N;;;;;\nFBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D0;;;;N;;;;;\nFBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL;<final> 0626 06D0;;;;N;;;;;\nFBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL;<initial> 0626 06D0;;;;N;;;;;\nFBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;\nFBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;\nFBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0626 0649;;;;N;;;;;\nFBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL;<isolated> 06CC;;;;N;;;;;\nFBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL;<final> 06CC;;;;N;;;;;\nFBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL;<initial> 06CC;;;;N;;;;;\nFBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL;<medial> 06CC;;;;N;;;;;\nFC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 062C;;;;N;;;;;\nFC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0626 062D;;;;N;;;;;\nFC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 0645;;;;N;;;;;\nFC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;\nFC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0626 064A;;;;N;;;;;\nFC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 062C;;;;N;;;;;\nFC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062D;;;;N;;;;;\nFC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062E;;;;N;;;;;\nFC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 0645;;;;N;;;;;\nFC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0628 0649;;;;N;;;;;\nFC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0628 064A;;;;N;;;;;\nFC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 062C;;;;N;;;;;\nFC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062D;;;;N;;;;;\nFC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062E;;;;N;;;;;\nFC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 0645;;;;N;;;;;\nFC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062A 0649;;;;N;;;;;\nFC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062A 064A;;;;N;;;;;\nFC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 062C;;;;N;;;;;\nFC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 0645;;;;N;;;;;\nFC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062B 0649;;;;N;;;;;\nFC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062B 064A;;;;N;;;;;\nFC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062C 062D;;;;N;;;;;\nFC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C 0645;;;;N;;;;;\nFC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 062C;;;;N;;;;;\nFC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 0645;;;;N;;;;;\nFC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 062C;;;;N;;;;;\nFC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062E 062D;;;;N;;;;;\nFC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 0645;;;;N;;;;;\nFC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 062C;;;;N;;;;;\nFC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062D;;;;N;;;;;\nFC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062E;;;;N;;;;;\nFC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 0645;;;;N;;;;;\nFC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0635 062D;;;;N;;;;;\nFC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0645;;;;N;;;;;\nFC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 062C;;;;N;;;;;\nFC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062D;;;;N;;;;;\nFC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062E;;;;N;;;;;\nFC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 0645;;;;N;;;;;\nFC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0637 062D;;;;N;;;;;\nFC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0637 0645;;;;N;;;;;\nFC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0638 0645;;;;N;;;;;\nFC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 062C;;;;N;;;;;\nFC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 0645;;;;N;;;;;\nFC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 062C;;;;N;;;;;\nFC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 0645;;;;N;;;;;\nFC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 062C;;;;N;;;;;\nFC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062D;;;;N;;;;;\nFC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062E;;;;N;;;;;\nFC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 0645;;;;N;;;;;\nFC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0641 0649;;;;N;;;;;\nFC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0641 064A;;;;N;;;;;\nFC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0642 062D;;;;N;;;;;\nFC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0642 0645;;;;N;;;;;\nFC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0642 0649;;;;N;;;;;\nFC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0642 064A;;;;N;;;;;\nFC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0643 0627;;;;N;;;;;\nFC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 062C;;;;N;;;;;\nFC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062D;;;;N;;;;;\nFC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062E;;;;N;;;;;\nFC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0644;;;;N;;;;;\nFC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0645;;;;N;;;;;\nFC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0643 0649;;;;N;;;;;\nFC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0643 064A;;;;N;;;;;\nFC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 062C;;;;N;;;;;\nFC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062D;;;;N;;;;;\nFC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062E;;;;N;;;;;\nFC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 0645;;;;N;;;;;\nFC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0644 0649;;;;N;;;;;\nFC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0644 064A;;;;N;;;;;\nFC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 062C;;;;N;;;;;\nFC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D;;;;N;;;;;\nFC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062E;;;;N;;;;;\nFC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 0645;;;;N;;;;;\nFC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0645 0649;;;;N;;;;;\nFC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0645 064A;;;;N;;;;;\nFC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 062C;;;;N;;;;;\nFC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062D;;;;N;;;;;\nFC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062E;;;;N;;;;;\nFC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 0645;;;;N;;;;;\nFC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0646 0649;;;;N;;;;;\nFC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0646 064A;;;;N;;;;;\nFC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 062C;;;;N;;;;;\nFC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 0645;;;;N;;;;;\nFC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0647 0649;;;;N;;;;;\nFC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0647 064A;;;;N;;;;;\nFC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 062C;;;;N;;;;;\nFC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062D;;;;N;;;;;\nFC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062E;;;;N;;;;;\nFC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 0645;;;;N;;;;;\nFC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 064A 0649;;;;N;;;;;\nFC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A 064A;;;;N;;;;;\nFC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0630 0670;;;;N;;;;;\nFC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0631 0670;;;;N;;;;;\nFC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0649 0670;;;;N;;;;;\nFC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C 0651;;;;N;;;;;\nFC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D 0651;;;;N;;;;;\nFC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E 0651;;;;N;;;;;\nFC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F 0651;;;;N;;;;;\nFC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650 0651;;;;N;;;;;\nFC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651 0670;;;;N;;;;;\nFC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL;<final> 0626 0631;;;;N;;;;;\nFC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0626 0632;;;;N;;;;;\nFC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL;<final> 0626 0645;;;;N;;;;;\nFC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL;<final> 0626 0646;;;;N;;;;;\nFC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;\nFC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL;<final> 0626 064A;;;;N;;;;;\nFC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL;<final> 0628 0631;;;;N;;;;;\nFC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0628 0632;;;;N;;;;;\nFC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0628 0645;;;;N;;;;;\nFC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL;<final> 0628 0646;;;;N;;;;;\nFC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0628 0649;;;;N;;;;;\nFC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 064A;;;;N;;;;;\nFC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL;<final> 062A 0631;;;;N;;;;;\nFC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062A 0632;;;;N;;;;;\nFC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062A 0645;;;;N;;;;;\nFC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062A 0646;;;;N;;;;;\nFC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0649;;;;N;;;;;\nFC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 064A;;;;N;;;;;\nFC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL;<final> 062B 0631;;;;N;;;;;\nFC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062B 0632;;;;N;;;;;\nFC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062B 0645;;;;N;;;;;\nFC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062B 0646;;;;N;;;;;\nFC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062B 0649;;;;N;;;;;\nFC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062B 064A;;;;N;;;;;\nFC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0641 0649;;;;N;;;;;\nFC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 064A;;;;N;;;;;\nFC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0642 0649;;;;N;;;;;\nFC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 064A;;;;N;;;;;\nFC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL;<final> 0643 0627;;;;N;;;;;\nFC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL;<final> 0643 0644;;;;N;;;;;\nFC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645;;;;N;;;;;\nFC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0643 0649;;;;N;;;;;\nFC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 064A;;;;N;;;;;\nFC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 0645;;;;N;;;;;\nFC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 0649;;;;N;;;;;\nFC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 064A;;;;N;;;;;\nFC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0645 0627;;;;N;;;;;\nFC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0645 0645;;;;N;;;;;\nFC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL;<final> 0646 0631;;;;N;;;;;\nFC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0646 0632;;;;N;;;;;\nFC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 0645;;;;N;;;;;\nFC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL;<final> 0646 0646;;;;N;;;;;\nFC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0649;;;;N;;;;;\nFC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 064A;;;;N;;;;;\nFC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL;<final> 0649 0670;;;;N;;;;;\nFC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL;<final> 064A 0631;;;;N;;;;;\nFC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 064A 0632;;;;N;;;;;\nFC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645;;;;N;;;;;\nFC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL;<final> 064A 0646;;;;N;;;;;\nFC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 064A 0649;;;;N;;;;;\nFC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 064A;;;;N;;;;;\nFC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0626 062C;;;;N;;;;;\nFC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0626 062D;;;;N;;;;;\nFC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0626 062E;;;;N;;;;;\nFC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0626 0645;;;;N;;;;;\nFC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0626 0647;;;;N;;;;;\nFC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0628 062C;;;;N;;;;;\nFC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0628 062D;;;;N;;;;;\nFC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0628 062E;;;;N;;;;;\nFC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0628 0645;;;;N;;;;;\nFCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0628 0647;;;;N;;;;;\nFCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C;;;;N;;;;;\nFCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 062D;;;;N;;;;;\nFCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 062E;;;;N;;;;;\nFCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645;;;;N;;;;;\nFCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 062A 0647;;;;N;;;;;\nFCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062B 0645;;;;N;;;;;\nFCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 062D;;;;N;;;;;\nFCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062C 0645;;;;N;;;;;\nFCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062D 062C;;;;N;;;;;\nFCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062D 0645;;;;N;;;;;\nFCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062E 062C;;;;N;;;;;\nFCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062E 0645;;;;N;;;;;\nFCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062C;;;;N;;;;;\nFCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062D;;;;N;;;;;\nFCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0633 062E;;;;N;;;;;\nFCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645;;;;N;;;;;\nFCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D;;;;N;;;;;\nFCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0635 062E;;;;N;;;;;\nFCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645;;;;N;;;;;\nFCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062C;;;;N;;;;;\nFCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0636 062D;;;;N;;;;;\nFCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0636 062E;;;;N;;;;;\nFCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 0645;;;;N;;;;;\nFCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 062D;;;;N;;;;;\nFCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0638 0645;;;;N;;;;;\nFCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C;;;;N;;;;;\nFCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645;;;;N;;;;;\nFCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 063A 062C;;;;N;;;;;\nFCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 063A 0645;;;;N;;;;;\nFCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062C;;;;N;;;;;\nFCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0641 062D;;;;N;;;;;\nFCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0641 062E;;;;N;;;;;\nFCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 0645;;;;N;;;;;\nFCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 062D;;;;N;;;;;\nFCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0642 0645;;;;N;;;;;\nFCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0643 062C;;;;N;;;;;\nFCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0643 062D;;;;N;;;;;\nFCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0643 062E;;;;N;;;;;\nFCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL;<initial> 0643 0644;;;;N;;;;;\nFCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645;;;;N;;;;;\nFCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C;;;;N;;;;;\nFCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 062D;;;;N;;;;;\nFCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0644 062E;;;;N;;;;;\nFCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645;;;;N;;;;;\nFCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0644 0647;;;;N;;;;;\nFCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C;;;;N;;;;;\nFCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062D;;;;N;;;;;\nFCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062E;;;;N;;;;;\nFCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 0645;;;;N;;;;;\nFCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C;;;;N;;;;;\nFCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062D;;;;N;;;;;\nFCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0646 062E;;;;N;;;;;\nFCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 0645;;;;N;;;;;\nFCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0646 0647;;;;N;;;;;\nFCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 062C;;;;N;;;;;\nFCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645;;;;N;;;;;\nFCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL;<initial> 0647 0670;;;;N;;;;;\nFCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 064A 062C;;;;N;;;;;\nFCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 064A 062D;;;;N;;;;;\nFCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 064A 062E;;;;N;;;;;\nFCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645;;;;N;;;;;\nFCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 064A 0647;;;;N;;;;;\nFCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0626 0645;;;;N;;;;;\nFCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0626 0647;;;;N;;;;;\nFCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0628 0645;;;;N;;;;;\nFCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0628 0647;;;;N;;;;;\nFCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062A 0645;;;;N;;;;;\nFCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062A 0647;;;;N;;;;;\nFCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062B 0645;;;;N;;;;;\nFCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062B 0647;;;;N;;;;;\nFCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 0645;;;;N;;;;;\nFCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0633 0647;;;;N;;;;;\nFCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 0645;;;;N;;;;;\nFCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0634 0647;;;;N;;;;;\nFCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL;<medial> 0643 0644;;;;N;;;;;\nFCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0643 0645;;;;N;;;;;\nFCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0644 0645;;;;N;;;;;\nFCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0646 0645;;;;N;;;;;\nFCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0646 0647;;;;N;;;;;\nFCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 064A 0645;;;;N;;;;;\nFCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 064A 0647;;;;N;;;;;\nFCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E 0651;;;;N;;;;;\nFCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F 0651;;;;N;;;;;\nFCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650 0651;;;;N;;;;;\nFCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0637 0649;;;;N;;;;;\nFCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0637 064A;;;;N;;;;;\nFCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0639 0649;;;;N;;;;;\nFCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0639 064A;;;;N;;;;;\nFCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 063A 0649;;;;N;;;;;\nFCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 063A 064A;;;;N;;;;;\nFCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0633 0649;;;;N;;;;;\nFCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0633 064A;;;;N;;;;;\nFCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0634 0649;;;;N;;;;;\nFCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0634 064A;;;;N;;;;;\nFCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062D 0649;;;;N;;;;;\nFD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062D 064A;;;;N;;;;;\nFD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062C 0649;;;;N;;;;;\nFD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062C 064A;;;;N;;;;;\nFD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062E 0649;;;;N;;;;;\nFD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062E 064A;;;;N;;;;;\nFD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0649;;;;N;;;;;\nFD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0635 064A;;;;N;;;;;\nFD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0636 0649;;;;N;;;;;\nFD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0636 064A;;;;N;;;;;\nFD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 062C;;;;N;;;;;\nFD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062D;;;;N;;;;;\nFD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062E;;;;N;;;;;\nFD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 0645;;;;N;;;;;\nFD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0634 0631;;;;N;;;;;\nFD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0633 0631;;;;N;;;;;\nFD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0635 0631;;;;N;;;;;\nFD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0636 0631;;;;N;;;;;\nFD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0637 0649;;;;N;;;;;\nFD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 064A;;;;N;;;;;\nFD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0649;;;;N;;;;;\nFD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 064A;;;;N;;;;;\nFD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0649;;;;N;;;;;\nFD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 064A;;;;N;;;;;\nFD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 0649;;;;N;;;;;\nFD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 064A;;;;N;;;;;\nFD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0634 0649;;;;N;;;;;\nFD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 064A;;;;N;;;;;\nFD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0649;;;;N;;;;;\nFD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 064A;;;;N;;;;;\nFD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0649;;;;N;;;;;\nFD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 064A;;;;N;;;;;\nFD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062E 0649;;;;N;;;;;\nFD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062E 064A;;;;N;;;;;\nFD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0635 0649;;;;N;;;;;\nFD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 064A;;;;N;;;;;\nFD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 0649;;;;N;;;;;\nFD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 064A;;;;N;;;;;\nFD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL;<final> 0634 062C;;;;N;;;;;\nFD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL;<final> 0634 062D;;;;N;;;;;\nFD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 062E;;;;N;;;;;\nFD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645;;;;N;;;;;\nFD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0634 0631;;;;N;;;;;\nFD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0633 0631;;;;N;;;;;\nFD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL;<final> 0635 0631;;;;N;;;;;\nFD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL;<final> 0636 0631;;;;N;;;;;\nFD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062C;;;;N;;;;;\nFD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0634 062D;;;;N;;;;;\nFD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 062E;;;;N;;;;;\nFD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645;;;;N;;;;;\nFD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0633 0647;;;;N;;;;;\nFD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0634 0647;;;;N;;;;;\nFD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645;;;;N;;;;;\nFD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 062C;;;;N;;;;;\nFD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062D;;;;N;;;;;\nFD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062E;;;;N;;;;;\nFD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 062C;;;;N;;;;;\nFD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062D;;;;N;;;;;\nFD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062E;;;;N;;;;;\nFD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0637 0645;;;;N;;;;;\nFD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0638 0645;;;;N;;;;;\nFD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL;<final> 0627 064B;;;;N;;;;;\nFD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0627 064B;;;;N;;;;;\nFD3E;ORNATE LEFT PARENTHESIS;Pe;0;ON;;;;;N;;;;;\nFD3F;ORNATE RIGHT PARENTHESIS;Ps;0;ON;;;;;N;;;;;\nFD40;ARABIC LIGATURE RAHIMAHU ALLAAH;So;0;ON;;;;;N;;;;;\nFD41;ARABIC LIGATURE RADI ALLAAHU ANH;So;0;ON;;;;;N;;;;;\nFD42;ARABIC LIGATURE RADI ALLAAHU ANHAA;So;0;ON;;;;;N;;;;;\nFD43;ARABIC LIGATURE RADI ALLAAHU ANHUM;So;0;ON;;;;;N;;;;;\nFD44;ARABIC LIGATURE RADI ALLAAHU ANHUMAA;So;0;ON;;;;;N;;;;;\nFD45;ARABIC LIGATURE RADI ALLAAHU ANHUNNA;So;0;ON;;;;;N;;;;;\nFD46;ARABIC LIGATURE SALLALLAAHU ALAYHI WA-AALIH;So;0;ON;;;;;N;;;;;\nFD47;ARABIC LIGATURE ALAYHI AS-SALAAM;So;0;ON;;;;;N;;;;;\nFD48;ARABIC LIGATURE ALAYHIM AS-SALAAM;So;0;ON;;;;;N;;;;;\nFD49;ARABIC LIGATURE ALAYHIMAA AS-SALAAM;So;0;ON;;;;;N;;;;;\nFD4A;ARABIC LIGATURE ALAYHI AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;;\nFD4B;ARABIC LIGATURE QUDDISA SIRRAH;So;0;ON;;;;;N;;;;;\nFD4C;ARABIC LIGATURE SALLALLAHU ALAYHI WAAALIHEE WA-SALLAM;So;0;ON;;;;;N;;;;;\nFD4D;ARABIC LIGATURE ALAYHAA AS-SALAAM;So;0;ON;;;;;N;;;;;\nFD4E;ARABIC LIGATURE TABAARAKA WA-TAAALAA;So;0;ON;;;;;N;;;;;\nFD4F;ARABIC LIGATURE RAHIMAHUM ALLAAH;So;0;ON;;;;;N;;;;;\nFD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C 0645;;;;N;;;;;\nFD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL;<final> 062A 062D 062C;;;;N;;;;;\nFD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 062C;;;;N;;;;;\nFD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 0645;;;;N;;;;;\nFD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062E 0645;;;;N;;;;;\nFD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062C;;;;N;;;;;\nFD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062D;;;;N;;;;;\nFD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062E;;;;N;;;;;\nFD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 062C 0645 062D;;;;N;;;;;\nFD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 0645 062D;;;;N;;;;;\nFD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 0645 064A;;;;N;;;;;\nFD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0645 0649;;;;N;;;;;\nFD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062D 062C;;;;N;;;;;\nFD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062C 062D;;;;N;;;;;\nFD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062C 0649;;;;N;;;;;\nFD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0633 0645 062D;;;;N;;;;;\nFD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062D;;;;N;;;;;\nFD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062C;;;;N;;;;;\nFD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0633 0645 0645;;;;N;;;;;\nFD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 0645;;;;N;;;;;\nFD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL;<final> 0635 062D 062D;;;;N;;;;;\nFD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D 062D;;;;N;;;;;\nFD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0635 0645 0645;;;;N;;;;;\nFD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 062D 0645;;;;N;;;;;\nFD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062D 0645;;;;N;;;;;\nFD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062C 064A;;;;N;;;;;\nFD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 0645 062E;;;;N;;;;;\nFD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 0645 062E;;;;N;;;;;\nFD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645 0645;;;;N;;;;;\nFD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645 0645;;;;N;;;;;\nFD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 062D 0649;;;;N;;;;;\nFD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0636 062E 0645;;;;N;;;;;\nFD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062E 0645;;;;N;;;;;\nFD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0637 0645 062D;;;;N;;;;;\nFD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 0645 062D;;;;N;;;;;\nFD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645 0645;;;;N;;;;;\nFD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 0645 064A;;;;N;;;;;\nFD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 062C 0645;;;;N;;;;;\nFD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 0645 0645;;;;N;;;;;\nFD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645 0645;;;;N;;;;;\nFD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0645 0649;;;;N;;;;;\nFD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 063A 0645 0645;;;;N;;;;;\nFD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 0645 064A;;;;N;;;;;\nFD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0645 0649;;;;N;;;;;\nFD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0641 062E 0645;;;;N;;;;;\nFD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062E 0645;;;;N;;;;;\nFD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0642 0645 062D;;;;N;;;;;\nFD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0642 0645 0645;;;;N;;;;;\nFD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062D 0645;;;;N;;;;;\nFD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062D 064A;;;;N;;;;;\nFD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 062D 0649;;;;N;;;;;\nFD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 062C;;;;N;;;;;\nFD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 062C;;;;N;;;;;\nFD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062E 0645;;;;N;;;;;\nFD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062E 0645;;;;N;;;;;\nFD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0644 0645 062D;;;;N;;;;;\nFD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062D;;;;N;;;;;\nFD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 062C;;;;N;;;;;\nFD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 0645;;;;N;;;;;\nFD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062D 064A;;;;N;;;;;\nFD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062D;;;;N;;;;;\nFD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C 0645;;;;N;;;;;\nFD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 062C;;;;N;;;;;\nFD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 0645;;;;N;;;;;\nFD90;ARABIC LIGATURE RAHMATU ALLAAHI ALAYH;So;0;ON;;;;;N;;;;;\nFD91;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHAA;So;0;ON;;;;;N;;;;;\nFD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062E;;;;N;;;;;\nFD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 062C;;;;N;;;;;\nFD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 0645;;;;N;;;;;\nFD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062D 0645;;;;N;;;;;\nFD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062D 0649;;;;N;;;;;\nFD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 062C 0645;;;;N;;;;;\nFD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C 0645;;;;N;;;;;\nFD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062C 0649;;;;N;;;;;\nFD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 0645 064A;;;;N;;;;;\nFD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0645 0649;;;;N;;;;;\nFD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645 0645;;;;N;;;;;\nFD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645 0645;;;;N;;;;;\nFD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062E 064A;;;;N;;;;;\nFD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062C 064A;;;;N;;;;;\nFDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062C 0649;;;;N;;;;;\nFDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062E 064A;;;;N;;;;;\nFDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062E 0649;;;;N;;;;;\nFDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 0645 064A;;;;N;;;;;\nFDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0645 0649;;;;N;;;;;\nFDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 0645 064A;;;;N;;;;;\nFDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 062D 0649;;;;N;;;;;\nFDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0645 0649;;;;N;;;;;\nFDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062E 0649;;;;N;;;;;\nFDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 062D 064A;;;;N;;;;;\nFDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062D 064A;;;;N;;;;;\nFDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 062D 064A;;;;N;;;;;\nFDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062C 064A;;;;N;;;;;\nFDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 0645 064A;;;;N;;;;;\nFDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062D 064A;;;;N;;;;;\nFDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062C 064A;;;;N;;;;;\nFDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 0645 064A;;;;N;;;;;\nFDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 0645 064A;;;;N;;;;;\nFDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 0645 064A;;;;N;;;;;\nFDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062D 064A;;;;N;;;;;\nFDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 0645 062D;;;;N;;;;;\nFDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062D 0645;;;;N;;;;;\nFDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 0645 064A;;;;N;;;;;\nFDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 0645 064A;;;;N;;;;;\nFDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062C 062D;;;;N;;;;;\nFDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062E 064A;;;;N;;;;;\nFDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 0645;;;;N;;;;;\nFDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645 0645;;;;N;;;;;\nFDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 0645;;;;N;;;;;\nFDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0646 062C 062D;;;;N;;;;;\nFDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 062D 064A;;;;N;;;;;\nFDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 062C 064A;;;;N;;;;;\nFDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062C 064A;;;;N;;;;;\nFDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 0645 064A;;;;N;;;;;\nFDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062D 064A;;;;N;;;;;\nFDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645 0645;;;;N;;;;;\nFDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C 0645;;;;N;;;;;\nFDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645 0645;;;;N;;;;;\nFDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 062E 064A;;;;N;;;;;\nFDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062C 064A;;;;N;;;;;\nFDC8;ARABIC LIGATURE RAHIMAHU ALLAAH TAAALAA;So;0;ON;;;;;N;;;;;\nFDC9;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANH;So;0;ON;;;;;N;;;;;\nFDCA;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHAA;So;0;ON;;;;;N;;;;;\nFDCB;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUMAA;So;0;ON;;;;;N;;;;;\nFDCC;ARABIC LIGATURE SALLALLAHU ALAYHI WA-ALAA AALIHEE WA-SALLAM;So;0;ON;;;;;N;;;;;\nFDCD;ARABIC LIGATURE AJJAL ALLAAHU TAAALAA FARAJAHU ASH-SHAREEF;So;0;ON;;;;;N;;;;;\nFDCE;ARABIC LIGATURE KARRAMA ALLAAHU WAJHAH;So;0;ON;;;;;N;;;;;\nFDCF;ARABIC LIGATURE SALAAMUHU ALAYNAA;So;0;ON;;;;;N;;;;;\nFDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 06D2;;;;N;;;;;\nFDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0642 0644 06D2;;;;N;;;;;\nFDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL;<isolated> 0627 0644 0644 0647;;;;N;;;;;\nFDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL;<isolated> 0627 0643 0628 0631;;;;N;;;;;\nFDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D 0645 062F;;;;N;;;;;\nFDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0639 0645;;;;N;;;;;\nFDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL;<isolated> 0631 0633 0648 0644;;;;N;;;;;\nFDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL;<isolated> 0639 0644 064A 0647;;;;N;;;;;\nFDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL;<isolated> 0648 0633 0644 0645;;;;N;;;;;\nFDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0649;;;;N;;;;;\nFDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL;<isolated> 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;;\nFDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL;<isolated> 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;;\nFDFC;RIAL SIGN;Sc;0;AL;<isolated> 0631 06CC 0627 0644;;;;N;;;;;\nFDFD;ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM;So;0;ON;;;;;N;;;;;\nFDFE;ARABIC LIGATURE SUBHAANAHU WA TAAALAA;So;0;ON;;;;;N;;;;;\nFDFF;ARABIC LIGATURE AZZA WA JALL;So;0;ON;;;;;N;;;;;\nFE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;;\nFE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;;\nFE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;;\nFE03;VARIATION SELECTOR-4;Mn;0;NSM;;;;;N;;;;;\nFE04;VARIATION SELECTOR-5;Mn;0;NSM;;;;;N;;;;;\nFE05;VARIATION SELECTOR-6;Mn;0;NSM;;;;;N;;;;;\nFE06;VARIATION SELECTOR-7;Mn;0;NSM;;;;;N;;;;;\nFE07;VARIATION SELECTOR-8;Mn;0;NSM;;;;;N;;;;;\nFE08;VARIATION SELECTOR-9;Mn;0;NSM;;;;;N;;;;;\nFE09;VARIATION SELECTOR-10;Mn;0;NSM;;;;;N;;;;;\nFE0A;VARIATION SELECTOR-11;Mn;0;NSM;;;;;N;;;;;\nFE0B;VARIATION SELECTOR-12;Mn;0;NSM;;;;;N;;;;;\nFE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;;\nFE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;;\nFE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;;\nFE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;;\nFE10;PRESENTATION FORM FOR VERTICAL COMMA;Po;0;ON;<vertical> 002C;;;;N;;;;;\nFE11;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA;Po;0;ON;<vertical> 3001;;;;N;;;;;\nFE12;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP;Po;0;ON;<vertical> 3002;;;;N;;;;;\nFE13;PRESENTATION FORM FOR VERTICAL COLON;Po;0;ON;<vertical> 003A;;;;N;;;;;\nFE14;PRESENTATION FORM FOR VERTICAL SEMICOLON;Po;0;ON;<vertical> 003B;;;;N;;;;;\nFE15;PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK;Po;0;ON;<vertical> 0021;;;;N;;;;;\nFE16;PRESENTATION FORM FOR VERTICAL QUESTION MARK;Po;0;ON;<vertical> 003F;;;;N;;;;;\nFE17;PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;<vertical> 3016;;;;N;;;;;\nFE18;PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET;Pe;0;ON;<vertical> 3017;;;;N;;;;;\nFE19;PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS;Po;0;ON;<vertical> 2026;;;;N;;;;;\nFE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;;\nFE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;\nFE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;;\nFE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;\nFE24;COMBINING MACRON LEFT HALF;Mn;230;NSM;;;;;N;;;;;\nFE25;COMBINING MACRON RIGHT HALF;Mn;230;NSM;;;;;N;;;;;\nFE26;COMBINING CONJOINING MACRON;Mn;230;NSM;;;;;N;;;;;\nFE27;COMBINING LIGATURE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;;\nFE28;COMBINING LIGATURE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;;\nFE29;COMBINING TILDE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;;\nFE2A;COMBINING TILDE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;;\nFE2B;COMBINING MACRON LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;;\nFE2C;COMBINING MACRON RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;;\nFE2D;COMBINING CONJOINING MACRON BELOW;Mn;220;NSM;;;;;N;;;;;\nFE2E;COMBINING CYRILLIC TITLO LEFT HALF;Mn;230;NSM;;;;;N;;;;;\nFE2F;COMBINING CYRILLIC TITLO RIGHT HALF;Mn;230;NSM;;;;;N;;;;;\nFE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;;\nFE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;;\nFE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;;\nFE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;;\nFE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;;\nFE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON;<vertical> 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;;\nFE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON;<vertical> 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;;\nFE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON;<vertical> 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;;\nFE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON;<vertical> 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;;\nFE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<vertical> 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;;\nFE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<vertical> 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;;\nFE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;<vertical> 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;;\nFE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;<vertical> 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;;\nFE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;<vertical> 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;;\nFE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;<vertical> 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;;\nFE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON;<vertical> 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;;\nFE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON;<vertical> 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;;\nFE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON;<vertical> 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;;\nFE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON;<vertical> 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;;\nFE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON;<vertical> 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;;\nFE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON;<vertical> 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;;\nFE45;SESAME DOT;Po;0;ON;;;;;N;;;;;\nFE46;WHITE SESAME DOT;Po;0;ON;;;;;N;;;;;\nFE47;PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET;Ps;0;ON;<vertical> 005B;;;;N;;;;;\nFE48;PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET;Pe;0;ON;<vertical> 005D;;;;N;;;;;\nFE49;DASHED OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DASHED OVERSCORE;;;;\nFE4A;CENTRELINE OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;;\nFE4B;WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING WAVY OVERSCORE;;;;\nFE4C;DOUBLE WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;;\nFE4D;DASHED LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING DASHED UNDERSCORE;;;;\nFE4E;CENTRELINE LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;;\nFE4F;WAVY LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING WAVY UNDERSCORE;;;;\nFE50;SMALL COMMA;Po;0;CS;<small> 002C;;;;N;;;;;\nFE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON;<small> 3001;;;;N;;;;;\nFE52;SMALL FULL STOP;Po;0;CS;<small> 002E;;;;N;SMALL PERIOD;;;;\nFE54;SMALL SEMICOLON;Po;0;ON;<small> 003B;;;;N;;;;;\nFE55;SMALL COLON;Po;0;CS;<small> 003A;;;;N;;;;;\nFE56;SMALL QUESTION MARK;Po;0;ON;<small> 003F;;;;N;;;;;\nFE57;SMALL EXCLAMATION MARK;Po;0;ON;<small> 0021;;;;N;;;;;\nFE58;SMALL EM DASH;Pd;0;ON;<small> 2014;;;;N;;;;;\nFE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;Y;SMALL OPENING PARENTHESIS;;;;\nFE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;Y;SMALL CLOSING PARENTHESIS;;;;\nFE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;Y;SMALL OPENING CURLY BRACKET;;;;\nFE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;Y;SMALL CLOSING CURLY BRACKET;;;;\nFE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;Y;SMALL OPENING TORTOISE SHELL BRACKET;;;;\nFE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;Y;SMALL CLOSING TORTOISE SHELL BRACKET;;;;\nFE5F;SMALL NUMBER SIGN;Po;0;ET;<small> 0023;;;;N;;;;;\nFE60;SMALL AMPERSAND;Po;0;ON;<small> 0026;;;;N;;;;;\nFE61;SMALL ASTERISK;Po;0;ON;<small> 002A;;;;N;;;;;\nFE62;SMALL PLUS SIGN;Sm;0;ES;<small> 002B;;;;N;;;;;\nFE63;SMALL HYPHEN-MINUS;Pd;0;ES;<small> 002D;;;;N;;;;;\nFE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;Y;;;;;\nFE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;Y;;;;;\nFE66;SMALL EQUALS SIGN;Sm;0;ON;<small> 003D;;;;N;;;;;\nFE68;SMALL REVERSE SOLIDUS;Po;0;ON;<small> 005C;;;;N;SMALL BACKSLASH;;;;\nFE69;SMALL DOLLAR SIGN;Sc;0;ET;<small> 0024;;;;N;;;;;\nFE6A;SMALL PERCENT SIGN;Po;0;ET;<small> 0025;;;;N;;;;;\nFE6B;SMALL COMMERCIAL AT;Po;0;ON;<small> 0040;;;;N;;;;;\nFE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;;\nFE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL;<medial> 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;;\nFE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;;\nFE73;ARABIC TAIL FRAGMENT;Lo;0;AL;;;;;N;;;;;\nFE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;;\nFE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E;;;;N;ARABIC SPACING FATHAH;;;;\nFE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;;\nFE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;;\nFE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;;\nFE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650;;;;N;ARABIC SPACING KASRAH;;;;\nFE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;;\nFE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;;\nFE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL;<medial> 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;;\nFE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL;<isolated> 0020 0652;;;;N;ARABIC SPACING SUKUN;;;;\nFE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL;<medial> 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;;\nFE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL;<isolated> 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;;\nFE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;;\nFE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;;\nFE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;;\nFE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;;\nFE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;;\nFE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;;\nFE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;;\nFE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;;\nFE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;;\nFE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;;\nFE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL;<initial> 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;;\nFE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL;<medial> 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;;\nFE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;;\nFE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL;<final> 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;;\nFE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL;<isolated> 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;;\nFE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL;<final> 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;;\nFE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL;<initial> 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;;\nFE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL;<medial> 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;;\nFE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL;<isolated> 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;;\nFE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL;<final> 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;;\nFE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL;<isolated> 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;;\nFE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL;<final> 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;;\nFE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL;<initial> 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;;\nFE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL;<medial> 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;;\nFE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL;<isolated> 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;;\nFE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL;<final> 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;;\nFE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL;<initial> 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;;\nFE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL;<medial> 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;;\nFE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;;\nFE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL;<final> 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;;\nFE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL;<initial> 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;;\nFEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL;<medial> 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;;\nFEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL;<isolated> 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;;\nFEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL;<final> 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;;\nFEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL;<initial> 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;;\nFEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL;<medial> 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;;\nFEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;;\nFEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL;<final> 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;;\nFEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL;<initial> 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;;\nFEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL;<medial> 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;;\nFEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL;<isolated> 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;;\nFEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL;<final> 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;;\nFEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL;<isolated> 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;;\nFEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL;<final> 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;;\nFEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL;<isolated> 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;;\nFEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL;<final> 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;;\nFEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL;<isolated> 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;;\nFEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL;<final> 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;;\nFEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL;<isolated> 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;;\nFEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL;<final> 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;;\nFEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL;<initial> 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;;\nFEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL;<medial> 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;;\nFEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL;<isolated> 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;;\nFEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL;<final> 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;;\nFEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL;<initial> 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;;\nFEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL;<medial> 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;;\nFEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL;<isolated> 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;;\nFEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL;<final> 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;;\nFEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL;<initial> 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;;\nFEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL;<medial> 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;;\nFEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL;<isolated> 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;;\nFEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL;<final> 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;;\nFEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL;<initial> 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;;\nFEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL;<medial> 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;;\nFEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL;<isolated> 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;;\nFEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL;<final> 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;;\nFEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL;<initial> 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;;\nFEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL;<medial> 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;;\nFEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL;<isolated> 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;;\nFEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL;<final> 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;;\nFEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL;<initial> 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;;\nFEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL;<medial> 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;;\nFEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL;<isolated> 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;;\nFECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL;<final> 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;;\nFECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL;<initial> 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;;\nFECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL;<medial> 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;;\nFECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL;<isolated> 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;;\nFECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL;<final> 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;;\nFECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL;<initial> 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;;\nFED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL;<medial> 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;;\nFED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL;<isolated> 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;;\nFED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL;<final> 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;;\nFED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL;<initial> 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;;\nFED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL;<medial> 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;;\nFED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL;<isolated> 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;;\nFED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL;<final> 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;;\nFED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL;<initial> 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;;\nFED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL;<medial> 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;;\nFED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL;<isolated> 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;;\nFEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL;<final> 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;;\nFEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL;<initial> 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;;\nFEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL;<medial> 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;;\nFEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL;<isolated> 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;;\nFEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL;<final> 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;;\nFEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL;<initial> 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;;\nFEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL;<medial> 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;;\nFEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;;\nFEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL;<final> 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;;\nFEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL;<initial> 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;;\nFEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL;<medial> 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;;\nFEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL;<isolated> 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;;\nFEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL;<final> 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;;\nFEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL;<initial> 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;;\nFEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL;<medial> 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;;\nFEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL;<isolated> 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;;\nFEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL;<final> 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;;\nFEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL;<initial> 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;;\nFEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL;<medial> 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;;\nFEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL;<isolated> 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;;\nFEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL;<final> 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;;\nFEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;;\nFEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;;\nFEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;;\nFEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL;<final> 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;;\nFEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL;<initial> 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;;\nFEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL;<medial> 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;;\nFEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;;\nFEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;;\nFEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;\nFEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;\nFEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;\nFEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;\nFEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;;\nFEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;;\nFEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;\nFF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON;<wide> 0021;;;;N;;;;;\nFF02;FULLWIDTH QUOTATION MARK;Po;0;ON;<wide> 0022;;;;N;;;;;\nFF03;FULLWIDTH NUMBER SIGN;Po;0;ET;<wide> 0023;;;;N;;;;;\nFF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET;<wide> 0024;;;;N;;;;;\nFF05;FULLWIDTH PERCENT SIGN;Po;0;ET;<wide> 0025;;;;N;;;;;\nFF06;FULLWIDTH AMPERSAND;Po;0;ON;<wide> 0026;;;;N;;;;;\nFF07;FULLWIDTH APOSTROPHE;Po;0;ON;<wide> 0027;;;;N;;;;;\nFF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON;<wide> 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;;\nFF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON;<wide> 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;;\nFF0A;FULLWIDTH ASTERISK;Po;0;ON;<wide> 002A;;;;N;;;;;\nFF0B;FULLWIDTH PLUS SIGN;Sm;0;ES;<wide> 002B;;;;N;;;;;\nFF0C;FULLWIDTH COMMA;Po;0;CS;<wide> 002C;;;;N;;;;;\nFF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ES;<wide> 002D;;;;N;;;;;\nFF0E;FULLWIDTH FULL STOP;Po;0;CS;<wide> 002E;;;;N;FULLWIDTH PERIOD;;;;\nFF0F;FULLWIDTH SOLIDUS;Po;0;CS;<wide> 002F;;;;N;FULLWIDTH SLASH;;;;\nFF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;;\nFF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;;\nFF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;;\nFF13;FULLWIDTH DIGIT THREE;Nd;0;EN;<wide> 0033;3;3;3;N;;;;;\nFF14;FULLWIDTH DIGIT FOUR;Nd;0;EN;<wide> 0034;4;4;4;N;;;;;\nFF15;FULLWIDTH DIGIT FIVE;Nd;0;EN;<wide> 0035;5;5;5;N;;;;;\nFF16;FULLWIDTH DIGIT SIX;Nd;0;EN;<wide> 0036;6;6;6;N;;;;;\nFF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN;<wide> 0037;7;7;7;N;;;;;\nFF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN;<wide> 0038;8;8;8;N;;;;;\nFF19;FULLWIDTH DIGIT NINE;Nd;0;EN;<wide> 0039;9;9;9;N;;;;;\nFF1A;FULLWIDTH COLON;Po;0;CS;<wide> 003A;;;;N;;;;;\nFF1B;FULLWIDTH SEMICOLON;Po;0;ON;<wide> 003B;;;;N;;;;;\nFF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON;<wide> 003C;;;;Y;;;;;\nFF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON;<wide> 003D;;;;N;;;;;\nFF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON;<wide> 003E;;;;Y;;;;;\nFF1F;FULLWIDTH QUESTION MARK;Po;0;ON;<wide> 003F;;;;N;;;;;\nFF20;FULLWIDTH COMMERCIAL AT;Po;0;ON;<wide> 0040;;;;N;;;;;\nFF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L;<wide> 0041;;;;N;;;;FF41;\nFF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L;<wide> 0042;;;;N;;;;FF42;\nFF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L;<wide> 0043;;;;N;;;;FF43;\nFF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L;<wide> 0044;;;;N;;;;FF44;\nFF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L;<wide> 0045;;;;N;;;;FF45;\nFF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L;<wide> 0046;;;;N;;;;FF46;\nFF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L;<wide> 0047;;;;N;;;;FF47;\nFF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L;<wide> 0048;;;;N;;;;FF48;\nFF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L;<wide> 0049;;;;N;;;;FF49;\nFF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L;<wide> 004A;;;;N;;;;FF4A;\nFF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L;<wide> 004B;;;;N;;;;FF4B;\nFF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L;<wide> 004C;;;;N;;;;FF4C;\nFF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L;<wide> 004D;;;;N;;;;FF4D;\nFF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L;<wide> 004E;;;;N;;;;FF4E;\nFF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L;<wide> 004F;;;;N;;;;FF4F;\nFF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L;<wide> 0050;;;;N;;;;FF50;\nFF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L;<wide> 0051;;;;N;;;;FF51;\nFF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L;<wide> 0052;;;;N;;;;FF52;\nFF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L;<wide> 0053;;;;N;;;;FF53;\nFF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L;<wide> 0054;;;;N;;;;FF54;\nFF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L;<wide> 0055;;;;N;;;;FF55;\nFF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L;<wide> 0056;;;;N;;;;FF56;\nFF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L;<wide> 0057;;;;N;;;;FF57;\nFF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L;<wide> 0058;;;;N;;;;FF58;\nFF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L;<wide> 0059;;;;N;;;;FF59;\nFF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L;<wide> 005A;;;;N;;;;FF5A;\nFF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON;<wide> 005B;;;;Y;FULLWIDTH OPENING SQUARE BRACKET;;;;\nFF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON;<wide> 005C;;;;N;FULLWIDTH BACKSLASH;;;;\nFF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON;<wide> 005D;;;;Y;FULLWIDTH CLOSING SQUARE BRACKET;;;;\nFF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON;<wide> 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;;\nFF3F;FULLWIDTH LOW LINE;Pc;0;ON;<wide> 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;;\nFF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON;<wide> 0060;;;;N;FULLWIDTH SPACING GRAVE;;;;\nFF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L;<wide> 0061;;;;N;;;FF21;;FF21\nFF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L;<wide> 0062;;;;N;;;FF22;;FF22\nFF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L;<wide> 0063;;;;N;;;FF23;;FF23\nFF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L;<wide> 0064;;;;N;;;FF24;;FF24\nFF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L;<wide> 0065;;;;N;;;FF25;;FF25\nFF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L;<wide> 0066;;;;N;;;FF26;;FF26\nFF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L;<wide> 0067;;;;N;;;FF27;;FF27\nFF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L;<wide> 0068;;;;N;;;FF28;;FF28\nFF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L;<wide> 0069;;;;N;;;FF29;;FF29\nFF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L;<wide> 006A;;;;N;;;FF2A;;FF2A\nFF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L;<wide> 006B;;;;N;;;FF2B;;FF2B\nFF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L;<wide> 006C;;;;N;;;FF2C;;FF2C\nFF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L;<wide> 006D;;;;N;;;FF2D;;FF2D\nFF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L;<wide> 006E;;;;N;;;FF2E;;FF2E\nFF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L;<wide> 006F;;;;N;;;FF2F;;FF2F\nFF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L;<wide> 0070;;;;N;;;FF30;;FF30\nFF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L;<wide> 0071;;;;N;;;FF31;;FF31\nFF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L;<wide> 0072;;;;N;;;FF32;;FF32\nFF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L;<wide> 0073;;;;N;;;FF33;;FF33\nFF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L;<wide> 0074;;;;N;;;FF34;;FF34\nFF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L;<wide> 0075;;;;N;;;FF35;;FF35\nFF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L;<wide> 0076;;;;N;;;FF36;;FF36\nFF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L;<wide> 0077;;;;N;;;FF37;;FF37\nFF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L;<wide> 0078;;;;N;;;FF38;;FF38\nFF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L;<wide> 0079;;;;N;;;FF39;;FF39\nFF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L;<wide> 007A;;;;N;;;FF3A;;FF3A\nFF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON;<wide> 007B;;;;Y;FULLWIDTH OPENING CURLY BRACKET;;;;\nFF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON;<wide> 007C;;;;N;FULLWIDTH VERTICAL BAR;;;;\nFF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON;<wide> 007D;;;;Y;FULLWIDTH CLOSING CURLY BRACKET;;;;\nFF5E;FULLWIDTH TILDE;Sm;0;ON;<wide> 007E;;;;N;FULLWIDTH SPACING TILDE;;;;\nFF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps;0;ON;<wide> 2985;;;;Y;;;;;\nFF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe;0;ON;<wide> 2986;;;;Y;;;;;\nFF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON;<narrow> 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;;\nFF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON;<narrow> 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;;\nFF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON;<narrow> 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;;\nFF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON;<narrow> 3001;;;;N;;;;;\nFF65;HALFWIDTH KATAKANA MIDDLE DOT;Po;0;ON;<narrow> 30FB;;;;N;;;;;\nFF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L;<narrow> 30F2;;;;N;;;;;\nFF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L;<narrow> 30A1;;;;N;;;;;\nFF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L;<narrow> 30A3;;;;N;;;;;\nFF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L;<narrow> 30A5;;;;N;;;;;\nFF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L;<narrow> 30A7;;;;N;;;;;\nFF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L;<narrow> 30A9;;;;N;;;;;\nFF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L;<narrow> 30E3;;;;N;;;;;\nFF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L;<narrow> 30E5;;;;N;;;;;\nFF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L;<narrow> 30E7;;;;N;;;;;\nFF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L;<narrow> 30C3;;;;N;;;;;\nFF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;<narrow> 30FC;;;;N;;;;;\nFF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L;<narrow> 30A2;;;;N;;;;;\nFF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L;<narrow> 30A4;;;;N;;;;;\nFF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L;<narrow> 30A6;;;;N;;;;;\nFF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L;<narrow> 30A8;;;;N;;;;;\nFF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L;<narrow> 30AA;;;;N;;;;;\nFF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L;<narrow> 30AB;;;;N;;;;;\nFF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L;<narrow> 30AD;;;;N;;;;;\nFF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L;<narrow> 30AF;;;;N;;;;;\nFF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L;<narrow> 30B1;;;;N;;;;;\nFF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L;<narrow> 30B3;;;;N;;;;;\nFF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L;<narrow> 30B5;;;;N;;;;;\nFF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L;<narrow> 30B7;;;;N;;;;;\nFF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L;<narrow> 30B9;;;;N;;;;;\nFF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L;<narrow> 30BB;;;;N;;;;;\nFF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L;<narrow> 30BD;;;;N;;;;;\nFF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L;<narrow> 30BF;;;;N;;;;;\nFF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L;<narrow> 30C1;;;;N;;;;;\nFF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L;<narrow> 30C4;;;;N;;;;;\nFF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L;<narrow> 30C6;;;;N;;;;;\nFF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L;<narrow> 30C8;;;;N;;;;;\nFF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L;<narrow> 30CA;;;;N;;;;;\nFF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L;<narrow> 30CB;;;;N;;;;;\nFF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L;<narrow> 30CC;;;;N;;;;;\nFF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L;<narrow> 30CD;;;;N;;;;;\nFF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L;<narrow> 30CE;;;;N;;;;;\nFF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L;<narrow> 30CF;;;;N;;;;;\nFF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L;<narrow> 30D2;;;;N;;;;;\nFF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L;<narrow> 30D5;;;;N;;;;;\nFF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L;<narrow> 30D8;;;;N;;;;;\nFF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L;<narrow> 30DB;;;;N;;;;;\nFF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L;<narrow> 30DE;;;;N;;;;;\nFF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L;<narrow> 30DF;;;;N;;;;;\nFF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L;<narrow> 30E0;;;;N;;;;;\nFF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L;<narrow> 30E1;;;;N;;;;;\nFF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L;<narrow> 30E2;;;;N;;;;;\nFF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L;<narrow> 30E4;;;;N;;;;;\nFF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L;<narrow> 30E6;;;;N;;;;;\nFF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L;<narrow> 30E8;;;;N;;;;;\nFF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L;<narrow> 30E9;;;;N;;;;;\nFF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L;<narrow> 30EA;;;;N;;;;;\nFF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L;<narrow> 30EB;;;;N;;;;;\nFF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L;<narrow> 30EC;;;;N;;;;;\nFF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L;<narrow> 30ED;;;;N;;;;;\nFF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L;<narrow> 30EF;;;;N;;;;;\nFF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L;<narrow> 30F3;;;;N;;;;;\nFF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;;;;\nFF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;;;;\nFFA0;HALFWIDTH HANGUL FILLER;Lo;0;L;<narrow> 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;;\nFFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L;<narrow> 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;;\nFFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L;<narrow> 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;;\nFFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;;\nFFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L;<narrow> 3134;;;;N;;;;;\nFFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<narrow> 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;;\nFFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<narrow> 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;;\nFFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L;<narrow> 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;;\nFFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L;<narrow> 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;;\nFFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L;<narrow> 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;;\nFFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<narrow> 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;;\nFFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<narrow> 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;;\nFFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<narrow> 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;;\nFFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L;<narrow> 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;;\nFFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<narrow> 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;;\nFFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<narrow> 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;;\nFFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<narrow> 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;;\nFFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L;<narrow> 3141;;;;N;;;;;\nFFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L;<narrow> 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;;\nFFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L;<narrow> 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;;\nFFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L;<narrow> 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;;\nFFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L;<narrow> 3145;;;;N;;;;;\nFFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L;<narrow> 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;;\nFFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L;<narrow> 3147;;;;N;;;;;\nFFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L;<narrow> 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;;\nFFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L;<narrow> 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;;\nFFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L;<narrow> 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;;\nFFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L;<narrow> 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;;\nFFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L;<narrow> 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;;\nFFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L;<narrow> 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;;\nFFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L;<narrow> 314E;;;;N;;;;;\nFFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L;<narrow> 314F;;;;N;;;;;\nFFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L;<narrow> 3150;;;;N;;;;;\nFFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L;<narrow> 3151;;;;N;;;;;\nFFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L;<narrow> 3152;;;;N;;;;;\nFFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L;<narrow> 3153;;;;N;;;;;\nFFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L;<narrow> 3154;;;;N;;;;;\nFFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L;<narrow> 3155;;;;N;;;;;\nFFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L;<narrow> 3156;;;;N;;;;;\nFFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L;<narrow> 3157;;;;N;;;;;\nFFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L;<narrow> 3158;;;;N;;;;;\nFFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L;<narrow> 3159;;;;N;;;;;\nFFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L;<narrow> 315A;;;;N;;;;;\nFFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L;<narrow> 315B;;;;N;;;;;\nFFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L;<narrow> 315C;;;;N;;;;;\nFFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L;<narrow> 315D;;;;N;;;;;\nFFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L;<narrow> 315E;;;;N;;;;;\nFFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L;<narrow> 315F;;;;N;;;;;\nFFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L;<narrow> 3160;;;;N;;;;;\nFFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L;<narrow> 3161;;;;N;;;;;\nFFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L;<narrow> 3162;;;;N;;;;;\nFFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;;\nFFE0;FULLWIDTH CENT SIGN;Sc;0;ET;<wide> 00A2;;;;N;;;;;\nFFE1;FULLWIDTH POUND SIGN;Sc;0;ET;<wide> 00A3;;;;N;;;;;\nFFE2;FULLWIDTH NOT SIGN;Sm;0;ON;<wide> 00AC;;;;N;;;;;\nFFE3;FULLWIDTH MACRON;Sk;0;ON;<wide> 00AF;;;;N;FULLWIDTH SPACING MACRON;;;;\nFFE4;FULLWIDTH BROKEN BAR;So;0;ON;<wide> 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;;\nFFE5;FULLWIDTH YEN SIGN;Sc;0;ET;<wide> 00A5;;;;N;;;;;\nFFE6;FULLWIDTH WON SIGN;Sc;0;ET;<wide> 20A9;;;;N;;;;;\nFFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON;<narrow> 2502;;;;N;;;;;\nFFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON;<narrow> 2190;;;;N;;;;;\nFFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON;<narrow> 2191;;;;N;;;;;\nFFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON;<narrow> 2192;;;;N;;;;;\nFFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON;<narrow> 2193;;;;N;;;;;\nFFED;HALFWIDTH BLACK SQUARE;So;0;ON;<narrow> 25A0;;;;N;;;;;\nFFEE;HALFWIDTH WHITE CIRCLE;So;0;ON;<narrow> 25CB;;;;N;;;;;\nFFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;ON;;;;;N;;;;;\nFFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;ON;;;;;N;;;;;\nFFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;ON;;;;;N;;;;;\nFFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;\nFFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;\n10000;LINEAR B SYLLABLE B008 A;Lo;0;L;;;;;N;;;;;\n10001;LINEAR B SYLLABLE B038 E;Lo;0;L;;;;;N;;;;;\n10002;LINEAR B SYLLABLE B028 I;Lo;0;L;;;;;N;;;;;\n10003;LINEAR B SYLLABLE B061 O;Lo;0;L;;;;;N;;;;;\n10004;LINEAR B SYLLABLE B010 U;Lo;0;L;;;;;N;;;;;\n10005;LINEAR B SYLLABLE B001 DA;Lo;0;L;;;;;N;;;;;\n10006;LINEAR B SYLLABLE B045 DE;Lo;0;L;;;;;N;;;;;\n10007;LINEAR B SYLLABLE B007 DI;Lo;0;L;;;;;N;;;;;\n10008;LINEAR B SYLLABLE B014 DO;Lo;0;L;;;;;N;;;;;\n10009;LINEAR B SYLLABLE B051 DU;Lo;0;L;;;;;N;;;;;\n1000A;LINEAR B SYLLABLE B057 JA;Lo;0;L;;;;;N;;;;;\n1000B;LINEAR B SYLLABLE B046 JE;Lo;0;L;;;;;N;;;;;\n1000D;LINEAR B SYLLABLE B036 JO;Lo;0;L;;;;;N;;;;;\n1000E;LINEAR B SYLLABLE B065 JU;Lo;0;L;;;;;N;;;;;\n1000F;LINEAR B SYLLABLE B077 KA;Lo;0;L;;;;;N;;;;;\n10010;LINEAR B SYLLABLE B044 KE;Lo;0;L;;;;;N;;;;;\n10011;LINEAR B SYLLABLE B067 KI;Lo;0;L;;;;;N;;;;;\n10012;LINEAR B SYLLABLE B070 KO;Lo;0;L;;;;;N;;;;;\n10013;LINEAR B SYLLABLE B081 KU;Lo;0;L;;;;;N;;;;;\n10014;LINEAR B SYLLABLE B080 MA;Lo;0;L;;;;;N;;;;;\n10015;LINEAR B SYLLABLE B013 ME;Lo;0;L;;;;;N;;;;;\n10016;LINEAR B SYLLABLE B073 MI;Lo;0;L;;;;;N;;;;;\n10017;LINEAR B SYLLABLE B015 MO;Lo;0;L;;;;;N;;;;;\n10018;LINEAR B SYLLABLE B023 MU;Lo;0;L;;;;;N;;;;;\n10019;LINEAR B SYLLABLE B006 NA;Lo;0;L;;;;;N;;;;;\n1001A;LINEAR B SYLLABLE B024 NE;Lo;0;L;;;;;N;;;;;\n1001B;LINEAR B SYLLABLE B030 NI;Lo;0;L;;;;;N;;;;;\n1001C;LINEAR B SYLLABLE B052 NO;Lo;0;L;;;;;N;;;;;\n1001D;LINEAR B SYLLABLE B055 NU;Lo;0;L;;;;;N;;;;;\n1001E;LINEAR B SYLLABLE B003 PA;Lo;0;L;;;;;N;;;;;\n1001F;LINEAR B SYLLABLE B072 PE;Lo;0;L;;;;;N;;;;;\n10020;LINEAR B SYLLABLE B039 PI;Lo;0;L;;;;;N;;;;;\n10021;LINEAR B SYLLABLE B011 PO;Lo;0;L;;;;;N;;;;;\n10022;LINEAR B SYLLABLE B050 PU;Lo;0;L;;;;;N;;;;;\n10023;LINEAR B SYLLABLE B016 QA;Lo;0;L;;;;;N;;;;;\n10024;LINEAR B SYLLABLE B078 QE;Lo;0;L;;;;;N;;;;;\n10025;LINEAR B SYLLABLE B021 QI;Lo;0;L;;;;;N;;;;;\n10026;LINEAR B SYLLABLE B032 QO;Lo;0;L;;;;;N;;;;;\n10028;LINEAR B SYLLABLE B060 RA;Lo;0;L;;;;;N;;;;;\n10029;LINEAR B SYLLABLE B027 RE;Lo;0;L;;;;;N;;;;;\n1002A;LINEAR B SYLLABLE B053 RI;Lo;0;L;;;;;N;;;;;\n1002B;LINEAR B SYLLABLE B002 RO;Lo;0;L;;;;;N;;;;;\n1002C;LINEAR B SYLLABLE B026 RU;Lo;0;L;;;;;N;;;;;\n1002D;LINEAR B SYLLABLE B031 SA;Lo;0;L;;;;;N;;;;;\n1002E;LINEAR B SYLLABLE B009 SE;Lo;0;L;;;;;N;;;;;\n1002F;LINEAR B SYLLABLE B041 SI;Lo;0;L;;;;;N;;;;;\n10030;LINEAR B SYLLABLE B012 SO;Lo;0;L;;;;;N;;;;;\n10031;LINEAR B SYLLABLE B058 SU;Lo;0;L;;;;;N;;;;;\n10032;LINEAR B SYLLABLE B059 TA;Lo;0;L;;;;;N;;;;;\n10033;LINEAR B SYLLABLE B004 TE;Lo;0;L;;;;;N;;;;;\n10034;LINEAR B SYLLABLE B037 TI;Lo;0;L;;;;;N;;;;;\n10035;LINEAR B SYLLABLE B005 TO;Lo;0;L;;;;;N;;;;;\n10036;LINEAR B SYLLABLE B069 TU;Lo;0;L;;;;;N;;;;;\n10037;LINEAR B SYLLABLE B054 WA;Lo;0;L;;;;;N;;;;;\n10038;LINEAR B SYLLABLE B075 WE;Lo;0;L;;;;;N;;;;;\n10039;LINEAR B SYLLABLE B040 WI;Lo;0;L;;;;;N;;;;;\n1003A;LINEAR B SYLLABLE B042 WO;Lo;0;L;;;;;N;;;;;\n1003C;LINEAR B SYLLABLE B017 ZA;Lo;0;L;;;;;N;;;;;\n1003D;LINEAR B SYLLABLE B074 ZE;Lo;0;L;;;;;N;;;;;\n1003F;LINEAR B SYLLABLE B020 ZO;Lo;0;L;;;;;N;;;;;\n10040;LINEAR B SYLLABLE B025 A2;Lo;0;L;;;;;N;;;;;\n10041;LINEAR B SYLLABLE B043 A3;Lo;0;L;;;;;N;;;;;\n10042;LINEAR B SYLLABLE B085 AU;Lo;0;L;;;;;N;;;;;\n10043;LINEAR B SYLLABLE B071 DWE;Lo;0;L;;;;;N;;;;;\n10044;LINEAR B SYLLABLE B090 DWO;Lo;0;L;;;;;N;;;;;\n10045;LINEAR B SYLLABLE B048 NWA;Lo;0;L;;;;;N;;;;;\n10046;LINEAR B SYLLABLE B029 PU2;Lo;0;L;;;;;N;;;;;\n10047;LINEAR B SYLLABLE B062 PTE;Lo;0;L;;;;;N;;;;;\n10048;LINEAR B SYLLABLE B076 RA2;Lo;0;L;;;;;N;;;;;\n10049;LINEAR B SYLLABLE B033 RA3;Lo;0;L;;;;;N;;;;;\n1004A;LINEAR B SYLLABLE B068 RO2;Lo;0;L;;;;;N;;;;;\n1004B;LINEAR B SYLLABLE B066 TA2;Lo;0;L;;;;;N;;;;;\n1004C;LINEAR B SYLLABLE B087 TWE;Lo;0;L;;;;;N;;;;;\n1004D;LINEAR B SYLLABLE B091 TWO;Lo;0;L;;;;;N;;;;;\n10050;LINEAR B SYMBOL B018;Lo;0;L;;;;;N;;;;;\n10051;LINEAR B SYMBOL B019;Lo;0;L;;;;;N;;;;;\n10052;LINEAR B SYMBOL B022;Lo;0;L;;;;;N;;;;;\n10053;LINEAR B SYMBOL B034;Lo;0;L;;;;;N;;;;;\n10054;LINEAR B SYMBOL B047;Lo;0;L;;;;;N;;;;;\n10055;LINEAR B SYMBOL B049;Lo;0;L;;;;;N;;;;;\n10056;LINEAR B SYMBOL B056;Lo;0;L;;;;;N;;;;;\n10057;LINEAR B SYMBOL B063;Lo;0;L;;;;;N;;;;;\n10058;LINEAR B SYMBOL B064;Lo;0;L;;;;;N;;;;;\n10059;LINEAR B SYMBOL B079;Lo;0;L;;;;;N;;;;;\n1005A;LINEAR B SYMBOL B082;Lo;0;L;;;;;N;;;;;\n1005B;LINEAR B SYMBOL B083;Lo;0;L;;;;;N;;;;;\n1005C;LINEAR B SYMBOL B086;Lo;0;L;;;;;N;;;;;\n1005D;LINEAR B SYMBOL B089;Lo;0;L;;;;;N;;;;;\n10080;LINEAR B IDEOGRAM B100 MAN;Lo;0;L;;;;;N;;;;;\n10081;LINEAR B IDEOGRAM B102 WOMAN;Lo;0;L;;;;;N;;;;;\n10082;LINEAR B IDEOGRAM B104 DEER;Lo;0;L;;;;;N;;;;;\n10083;LINEAR B IDEOGRAM B105 EQUID;Lo;0;L;;;;;N;;;;;\n10084;LINEAR B IDEOGRAM B105F MARE;Lo;0;L;;;;;N;;;;;\n10085;LINEAR B IDEOGRAM B105M STALLION;Lo;0;L;;;;;N;;;;;\n10086;LINEAR B IDEOGRAM B106F EWE;Lo;0;L;;;;;N;;;;;\n10087;LINEAR B IDEOGRAM B106M RAM;Lo;0;L;;;;;N;;;;;\n10088;LINEAR B IDEOGRAM B107F SHE-GOAT;Lo;0;L;;;;;N;;;;;\n10089;LINEAR B IDEOGRAM B107M HE-GOAT;Lo;0;L;;;;;N;;;;;\n1008A;LINEAR B IDEOGRAM B108F SOW;Lo;0;L;;;;;N;;;;;\n1008B;LINEAR B IDEOGRAM B108M BOAR;Lo;0;L;;;;;N;;;;;\n1008C;LINEAR B IDEOGRAM B109F COW;Lo;0;L;;;;;N;;;;;\n1008D;LINEAR B IDEOGRAM B109M BULL;Lo;0;L;;;;;N;;;;;\n1008E;LINEAR B IDEOGRAM B120 WHEAT;Lo;0;L;;;;;N;;;;;\n1008F;LINEAR B IDEOGRAM B121 BARLEY;Lo;0;L;;;;;N;;;;;\n10090;LINEAR B IDEOGRAM B122 OLIVE;Lo;0;L;;;;;N;;;;;\n10091;LINEAR B IDEOGRAM B123 SPICE;Lo;0;L;;;;;N;;;;;\n10092;LINEAR B IDEOGRAM B125 CYPERUS;Lo;0;L;;;;;N;;;;;\n10093;LINEAR B MONOGRAM B127 KAPO;Lo;0;L;;;;;N;;;;;\n10094;LINEAR B MONOGRAM B128 KANAKO;Lo;0;L;;;;;N;;;;;\n10095;LINEAR B IDEOGRAM B130 OIL;Lo;0;L;;;;;N;;;;;\n10096;LINEAR B IDEOGRAM B131 WINE;Lo;0;L;;;;;N;;;;;\n10097;LINEAR B IDEOGRAM B132;Lo;0;L;;;;;N;;;;;\n10098;LINEAR B MONOGRAM B133 AREPA;Lo;0;L;;;;;N;;;;;\n10099;LINEAR B MONOGRAM B135 MERI;Lo;0;L;;;;;N;;;;;\n1009A;LINEAR B IDEOGRAM B140 BRONZE;Lo;0;L;;;;;N;;;;;\n1009B;LINEAR B IDEOGRAM B141 GOLD;Lo;0;L;;;;;N;;;;;\n1009C;LINEAR B IDEOGRAM B142;Lo;0;L;;;;;N;;;;;\n1009D;LINEAR B IDEOGRAM B145 WOOL;Lo;0;L;;;;;N;;;;;\n1009E;LINEAR B IDEOGRAM B146;Lo;0;L;;;;;N;;;;;\n1009F;LINEAR B IDEOGRAM B150;Lo;0;L;;;;;N;;;;;\n100A0;LINEAR B IDEOGRAM B151 HORN;Lo;0;L;;;;;N;;;;;\n100A1;LINEAR B IDEOGRAM B152;Lo;0;L;;;;;N;;;;;\n100A2;LINEAR B IDEOGRAM B153;Lo;0;L;;;;;N;;;;;\n100A3;LINEAR B IDEOGRAM B154;Lo;0;L;;;;;N;;;;;\n100A4;LINEAR B MONOGRAM B156 TURO2;Lo;0;L;;;;;N;;;;;\n100A5;LINEAR B IDEOGRAM B157;Lo;0;L;;;;;N;;;;;\n100A6;LINEAR B IDEOGRAM B158;Lo;0;L;;;;;N;;;;;\n100A7;LINEAR B IDEOGRAM B159 CLOTH;Lo;0;L;;;;;N;;;;;\n100A8;LINEAR B IDEOGRAM B160;Lo;0;L;;;;;N;;;;;\n100A9;LINEAR B IDEOGRAM B161;Lo;0;L;;;;;N;;;;;\n100AA;LINEAR B IDEOGRAM B162 GARMENT;Lo;0;L;;;;;N;;;;;\n100AB;LINEAR B IDEOGRAM B163 ARMOUR;Lo;0;L;;;;;N;;;;;\n100AC;LINEAR B IDEOGRAM B164;Lo;0;L;;;;;N;;;;;\n100AD;LINEAR B IDEOGRAM B165;Lo;0;L;;;;;N;;;;;\n100AE;LINEAR B IDEOGRAM B166;Lo;0;L;;;;;N;;;;;\n100AF;LINEAR B IDEOGRAM B167;Lo;0;L;;;;;N;;;;;\n100B0;LINEAR B IDEOGRAM B168;Lo;0;L;;;;;N;;;;;\n100B1;LINEAR B IDEOGRAM B169;Lo;0;L;;;;;N;;;;;\n100B2;LINEAR B IDEOGRAM B170;Lo;0;L;;;;;N;;;;;\n100B3;LINEAR B IDEOGRAM B171;Lo;0;L;;;;;N;;;;;\n100B4;LINEAR B IDEOGRAM B172;Lo;0;L;;;;;N;;;;;\n100B5;LINEAR B IDEOGRAM B173 MONTH;Lo;0;L;;;;;N;;;;;\n100B6;LINEAR B IDEOGRAM B174;Lo;0;L;;;;;N;;;;;\n100B7;LINEAR B IDEOGRAM B176 TREE;Lo;0;L;;;;;N;;;;;\n100B8;LINEAR B IDEOGRAM B177;Lo;0;L;;;;;N;;;;;\n100B9;LINEAR B IDEOGRAM B178;Lo;0;L;;;;;N;;;;;\n100BA;LINEAR B IDEOGRAM B179;Lo;0;L;;;;;N;;;;;\n100BB;LINEAR B IDEOGRAM B180;Lo;0;L;;;;;N;;;;;\n100BC;LINEAR B IDEOGRAM B181;Lo;0;L;;;;;N;;;;;\n100BD;LINEAR B IDEOGRAM B182;Lo;0;L;;;;;N;;;;;\n100BE;LINEAR B IDEOGRAM B183;Lo;0;L;;;;;N;;;;;\n100BF;LINEAR B IDEOGRAM B184;Lo;0;L;;;;;N;;;;;\n100C0;LINEAR B IDEOGRAM B185;Lo;0;L;;;;;N;;;;;\n100C1;LINEAR B IDEOGRAM B189;Lo;0;L;;;;;N;;;;;\n100C2;LINEAR B IDEOGRAM B190;Lo;0;L;;;;;N;;;;;\n100C3;LINEAR B IDEOGRAM B191 HELMET;Lo;0;L;;;;;N;;;;;\n100C4;LINEAR B IDEOGRAM B220 FOOTSTOOL;Lo;0;L;;;;;N;;;;;\n100C5;LINEAR B IDEOGRAM B225 BATHTUB;Lo;0;L;;;;;N;;;;;\n100C6;LINEAR B IDEOGRAM B230 SPEAR;Lo;0;L;;;;;N;;;;;\n100C7;LINEAR B IDEOGRAM B231 ARROW;Lo;0;L;;;;;N;;;;;\n100C8;LINEAR B IDEOGRAM B232;Lo;0;L;;;;;N;;;;;\n100C9;LINEAR B IDEOGRAM B233 SWORD;Lo;0;L;;;;;N;;;;;\n100CA;LINEAR B IDEOGRAM B234;Lo;0;L;;;;;N;;;;;\n100CB;LINEAR B IDEOGRAM B236;Lo;0;L;;;;;N;;;;;\n100CC;LINEAR B IDEOGRAM B240 WHEELED CHARIOT;Lo;0;L;;;;;N;;;;;\n100CD;LINEAR B IDEOGRAM B241 CHARIOT;Lo;0;L;;;;;N;;;;;\n100CE;LINEAR B IDEOGRAM B242 CHARIOT FRAME;Lo;0;L;;;;;N;;;;;\n100CF;LINEAR B IDEOGRAM B243 WHEEL;Lo;0;L;;;;;N;;;;;\n100D0;LINEAR B IDEOGRAM B245;Lo;0;L;;;;;N;;;;;\n100D1;LINEAR B IDEOGRAM B246;Lo;0;L;;;;;N;;;;;\n100D2;LINEAR B MONOGRAM B247 DIPTE;Lo;0;L;;;;;N;;;;;\n100D3;LINEAR B IDEOGRAM B248;Lo;0;L;;;;;N;;;;;\n100D4;LINEAR B IDEOGRAM B249;Lo;0;L;;;;;N;;;;;\n100D5;LINEAR B IDEOGRAM B251;Lo;0;L;;;;;N;;;;;\n100D6;LINEAR B IDEOGRAM B252;Lo;0;L;;;;;N;;;;;\n100D7;LINEAR B IDEOGRAM B253;Lo;0;L;;;;;N;;;;;\n100D8;LINEAR B IDEOGRAM B254 DART;Lo;0;L;;;;;N;;;;;\n100D9;LINEAR B IDEOGRAM B255;Lo;0;L;;;;;N;;;;;\n100DA;LINEAR B IDEOGRAM B256;Lo;0;L;;;;;N;;;;;\n100DB;LINEAR B IDEOGRAM B257;Lo;0;L;;;;;N;;;;;\n100DC;LINEAR B IDEOGRAM B258;Lo;0;L;;;;;N;;;;;\n100DD;LINEAR B IDEOGRAM B259;Lo;0;L;;;;;N;;;;;\n100DE;LINEAR B IDEOGRAM VESSEL B155;Lo;0;L;;;;;N;;;;;\n100DF;LINEAR B IDEOGRAM VESSEL B200;Lo;0;L;;;;;N;;;;;\n100E0;LINEAR B IDEOGRAM VESSEL B201;Lo;0;L;;;;;N;;;;;\n100E1;LINEAR B IDEOGRAM VESSEL B202;Lo;0;L;;;;;N;;;;;\n100E2;LINEAR B IDEOGRAM VESSEL B203;Lo;0;L;;;;;N;;;;;\n100E3;LINEAR B IDEOGRAM VESSEL B204;Lo;0;L;;;;;N;;;;;\n100E4;LINEAR B IDEOGRAM VESSEL B205;Lo;0;L;;;;;N;;;;;\n100E5;LINEAR B IDEOGRAM VESSEL B206;Lo;0;L;;;;;N;;;;;\n100E6;LINEAR B IDEOGRAM VESSEL B207;Lo;0;L;;;;;N;;;;;\n100E7;LINEAR B IDEOGRAM VESSEL B208;Lo;0;L;;;;;N;;;;;\n100E8;LINEAR B IDEOGRAM VESSEL B209;Lo;0;L;;;;;N;;;;;\n100E9;LINEAR B IDEOGRAM VESSEL B210;Lo;0;L;;;;;N;;;;;\n100EA;LINEAR B IDEOGRAM VESSEL B211;Lo;0;L;;;;;N;;;;;\n100EB;LINEAR B IDEOGRAM VESSEL B212;Lo;0;L;;;;;N;;;;;\n100EC;LINEAR B IDEOGRAM VESSEL B213;Lo;0;L;;;;;N;;;;;\n100ED;LINEAR B IDEOGRAM VESSEL B214;Lo;0;L;;;;;N;;;;;\n100EE;LINEAR B IDEOGRAM VESSEL B215;Lo;0;L;;;;;N;;;;;\n100EF;LINEAR B IDEOGRAM VESSEL B216;Lo;0;L;;;;;N;;;;;\n100F0;LINEAR B IDEOGRAM VESSEL B217;Lo;0;L;;;;;N;;;;;\n100F1;LINEAR B IDEOGRAM VESSEL B218;Lo;0;L;;;;;N;;;;;\n100F2;LINEAR B IDEOGRAM VESSEL B219;Lo;0;L;;;;;N;;;;;\n100F3;LINEAR B IDEOGRAM VESSEL B221;Lo;0;L;;;;;N;;;;;\n100F4;LINEAR B IDEOGRAM VESSEL B222;Lo;0;L;;;;;N;;;;;\n100F5;LINEAR B IDEOGRAM VESSEL B226;Lo;0;L;;;;;N;;;;;\n100F6;LINEAR B IDEOGRAM VESSEL B227;Lo;0;L;;;;;N;;;;;\n100F7;LINEAR B IDEOGRAM VESSEL B228;Lo;0;L;;;;;N;;;;;\n100F8;LINEAR B IDEOGRAM VESSEL B229;Lo;0;L;;;;;N;;;;;\n100F9;LINEAR B IDEOGRAM VESSEL B250;Lo;0;L;;;;;N;;;;;\n100FA;LINEAR B IDEOGRAM VESSEL B305;Lo;0;L;;;;;N;;;;;\n10100;AEGEAN WORD SEPARATOR LINE;Po;0;L;;;;;N;;;;;\n10101;AEGEAN WORD SEPARATOR DOT;Po;0;ON;;;;;N;;;;;\n10102;AEGEAN CHECK MARK;Po;0;L;;;;;N;;;;;\n10107;AEGEAN NUMBER ONE;No;0;L;;;;1;N;;;;;\n10108;AEGEAN NUMBER TWO;No;0;L;;;;2;N;;;;;\n10109;AEGEAN NUMBER THREE;No;0;L;;;;3;N;;;;;\n1010A;AEGEAN NUMBER FOUR;No;0;L;;;;4;N;;;;;\n1010B;AEGEAN NUMBER FIVE;No;0;L;;;;5;N;;;;;\n1010C;AEGEAN NUMBER SIX;No;0;L;;;;6;N;;;;;\n1010D;AEGEAN NUMBER SEVEN;No;0;L;;;;7;N;;;;;\n1010E;AEGEAN NUMBER EIGHT;No;0;L;;;;8;N;;;;;\n1010F;AEGEAN NUMBER NINE;No;0;L;;;;9;N;;;;;\n10110;AEGEAN NUMBER TEN;No;0;L;;;;10;N;;;;;\n10111;AEGEAN NUMBER TWENTY;No;0;L;;;;20;N;;;;;\n10112;AEGEAN NUMBER THIRTY;No;0;L;;;;30;N;;;;;\n10113;AEGEAN NUMBER FORTY;No;0;L;;;;40;N;;;;;\n10114;AEGEAN NUMBER FIFTY;No;0;L;;;;50;N;;;;;\n10115;AEGEAN NUMBER SIXTY;No;0;L;;;;60;N;;;;;\n10116;AEGEAN NUMBER SEVENTY;No;0;L;;;;70;N;;;;;\n10117;AEGEAN NUMBER EIGHTY;No;0;L;;;;80;N;;;;;\n10118;AEGEAN NUMBER NINETY;No;0;L;;;;90;N;;;;;\n10119;AEGEAN NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;\n1011A;AEGEAN NUMBER TWO HUNDRED;No;0;L;;;;200;N;;;;;\n1011B;AEGEAN NUMBER THREE HUNDRED;No;0;L;;;;300;N;;;;;\n1011C;AEGEAN NUMBER FOUR HUNDRED;No;0;L;;;;400;N;;;;;\n1011D;AEGEAN NUMBER FIVE HUNDRED;No;0;L;;;;500;N;;;;;\n1011E;AEGEAN NUMBER SIX HUNDRED;No;0;L;;;;600;N;;;;;\n1011F;AEGEAN NUMBER SEVEN HUNDRED;No;0;L;;;;700;N;;;;;\n10120;AEGEAN NUMBER EIGHT HUNDRED;No;0;L;;;;800;N;;;;;\n10121;AEGEAN NUMBER NINE HUNDRED;No;0;L;;;;900;N;;;;;\n10122;AEGEAN NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;\n10123;AEGEAN NUMBER TWO THOUSAND;No;0;L;;;;2000;N;;;;;\n10124;AEGEAN NUMBER THREE THOUSAND;No;0;L;;;;3000;N;;;;;\n10125;AEGEAN NUMBER FOUR THOUSAND;No;0;L;;;;4000;N;;;;;\n10126;AEGEAN NUMBER FIVE THOUSAND;No;0;L;;;;5000;N;;;;;\n10127;AEGEAN NUMBER SIX THOUSAND;No;0;L;;;;6000;N;;;;;\n10128;AEGEAN NUMBER SEVEN THOUSAND;No;0;L;;;;7000;N;;;;;\n10129;AEGEAN NUMBER EIGHT THOUSAND;No;0;L;;;;8000;N;;;;;\n1012A;AEGEAN NUMBER NINE THOUSAND;No;0;L;;;;9000;N;;;;;\n1012B;AEGEAN NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;\n1012C;AEGEAN NUMBER TWENTY THOUSAND;No;0;L;;;;20000;N;;;;;\n1012D;AEGEAN NUMBER THIRTY THOUSAND;No;0;L;;;;30000;N;;;;;\n1012E;AEGEAN NUMBER FORTY THOUSAND;No;0;L;;;;40000;N;;;;;\n1012F;AEGEAN NUMBER FIFTY THOUSAND;No;0;L;;;;50000;N;;;;;\n10130;AEGEAN NUMBER SIXTY THOUSAND;No;0;L;;;;60000;N;;;;;\n10131;AEGEAN NUMBER SEVENTY THOUSAND;No;0;L;;;;70000;N;;;;;\n10132;AEGEAN NUMBER EIGHTY THOUSAND;No;0;L;;;;80000;N;;;;;\n10133;AEGEAN NUMBER NINETY THOUSAND;No;0;L;;;;90000;N;;;;;\n10137;AEGEAN WEIGHT BASE UNIT;So;0;L;;;;;N;;;;;\n10138;AEGEAN WEIGHT FIRST SUBUNIT;So;0;L;;;;;N;;;;;\n10139;AEGEAN WEIGHT SECOND SUBUNIT;So;0;L;;;;;N;;;;;\n1013A;AEGEAN WEIGHT THIRD SUBUNIT;So;0;L;;;;;N;;;;;\n1013B;AEGEAN WEIGHT FOURTH SUBUNIT;So;0;L;;;;;N;;;;;\n1013C;AEGEAN DRY MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;;\n1013D;AEGEAN LIQUID MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;;\n1013E;AEGEAN MEASURE SECOND SUBUNIT;So;0;L;;;;;N;;;;;\n1013F;AEGEAN MEASURE THIRD SUBUNIT;So;0;L;;;;;N;;;;;\n10140;GREEK ACROPHONIC ATTIC ONE QUARTER;Nl;0;ON;;;;1/4;N;;;;;\n10141;GREEK ACROPHONIC ATTIC ONE HALF;Nl;0;ON;;;;1/2;N;;;;;\n10142;GREEK ACROPHONIC ATTIC ONE DRACHMA;Nl;0;ON;;;;1;N;;;;;\n10143;GREEK ACROPHONIC ATTIC FIVE;Nl;0;ON;;;;5;N;;;;;\n10144;GREEK ACROPHONIC ATTIC FIFTY;Nl;0;ON;;;;50;N;;;;;\n10145;GREEK ACROPHONIC ATTIC FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;\n10146;GREEK ACROPHONIC ATTIC FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;;\n10147;GREEK ACROPHONIC ATTIC FIFTY THOUSAND;Nl;0;ON;;;;50000;N;;;;;\n10148;GREEK ACROPHONIC ATTIC FIVE TALENTS;Nl;0;ON;;;;5;N;;;;;\n10149;GREEK ACROPHONIC ATTIC TEN TALENTS;Nl;0;ON;;;;10;N;;;;;\n1014A;GREEK ACROPHONIC ATTIC FIFTY TALENTS;Nl;0;ON;;;;50;N;;;;;\n1014B;GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS;Nl;0;ON;;;;100;N;;;;;\n1014C;GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS;Nl;0;ON;;;;500;N;;;;;\n1014D;GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS;Nl;0;ON;;;;1000;N;;;;;\n1014E;GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS;Nl;0;ON;;;;5000;N;;;;;\n1014F;GREEK ACROPHONIC ATTIC FIVE STATERS;Nl;0;ON;;;;5;N;;;;;\n10150;GREEK ACROPHONIC ATTIC TEN STATERS;Nl;0;ON;;;;10;N;;;;;\n10151;GREEK ACROPHONIC ATTIC FIFTY STATERS;Nl;0;ON;;;;50;N;;;;;\n10152;GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS;Nl;0;ON;;;;100;N;;;;;\n10153;GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS;Nl;0;ON;;;;500;N;;;;;\n10154;GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS;Nl;0;ON;;;;1000;N;;;;;\n10155;GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS;Nl;0;ON;;;;10000;N;;;;;\n10156;GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS;Nl;0;ON;;;;50000;N;;;;;\n10157;GREEK ACROPHONIC ATTIC TEN MNAS;Nl;0;ON;;;;10;N;;;;;\n10158;GREEK ACROPHONIC HERAEUM ONE PLETHRON;Nl;0;ON;;;;1;N;;;;;\n10159;GREEK ACROPHONIC THESPIAN ONE;Nl;0;ON;;;;1;N;;;;;\n1015A;GREEK ACROPHONIC HERMIONIAN ONE;Nl;0;ON;;;;1;N;;;;;\n1015B;GREEK ACROPHONIC EPIDAUREAN TWO;Nl;0;ON;;;;2;N;;;;;\n1015C;GREEK ACROPHONIC THESPIAN TWO;Nl;0;ON;;;;2;N;;;;;\n1015D;GREEK ACROPHONIC CYRENAIC TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;;\n1015E;GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;;\n1015F;GREEK ACROPHONIC TROEZENIAN FIVE;Nl;0;ON;;;;5;N;;;;;\n10160;GREEK ACROPHONIC TROEZENIAN TEN;Nl;0;ON;;;;10;N;;;;;\n10161;GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM;Nl;0;ON;;;;10;N;;;;;\n10162;GREEK ACROPHONIC HERMIONIAN TEN;Nl;0;ON;;;;10;N;;;;;\n10163;GREEK ACROPHONIC MESSENIAN TEN;Nl;0;ON;;;;10;N;;;;;\n10164;GREEK ACROPHONIC THESPIAN TEN;Nl;0;ON;;;;10;N;;;;;\n10165;GREEK ACROPHONIC THESPIAN THIRTY;Nl;0;ON;;;;30;N;;;;;\n10166;GREEK ACROPHONIC TROEZENIAN FIFTY;Nl;0;ON;;;;50;N;;;;;\n10167;GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM;Nl;0;ON;;;;50;N;;;;;\n10168;GREEK ACROPHONIC HERMIONIAN FIFTY;Nl;0;ON;;;;50;N;;;;;\n10169;GREEK ACROPHONIC THESPIAN FIFTY;Nl;0;ON;;;;50;N;;;;;\n1016A;GREEK ACROPHONIC THESPIAN ONE HUNDRED;Nl;0;ON;;;;100;N;;;;;\n1016B;GREEK ACROPHONIC THESPIAN THREE HUNDRED;Nl;0;ON;;;;300;N;;;;;\n1016C;GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;\n1016D;GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;\n1016E;GREEK ACROPHONIC THESPIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;\n1016F;GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;\n10170;GREEK ACROPHONIC NAXIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;\n10171;GREEK ACROPHONIC THESPIAN ONE THOUSAND;Nl;0;ON;;;;1000;N;;;;;\n10172;GREEK ACROPHONIC THESPIAN FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;;\n10173;GREEK ACROPHONIC DELPHIC FIVE MNAS;Nl;0;ON;;;;5;N;;;;;\n10174;GREEK ACROPHONIC STRATIAN FIFTY MNAS;Nl;0;ON;;;;50;N;;;;;\n10175;GREEK ONE HALF SIGN;No;0;ON;;;;1/2;N;;;;;\n10176;GREEK ONE HALF SIGN ALTERNATE FORM;No;0;ON;;;;1/2;N;;;;;\n10177;GREEK TWO THIRDS SIGN;No;0;ON;;;;2/3;N;;;;;\n10178;GREEK THREE QUARTERS SIGN;No;0;ON;;;;3/4;N;;;;;\n10179;GREEK YEAR SIGN;So;0;ON;;;;;N;;;;;\n1017A;GREEK TALENT SIGN;So;0;ON;;;;;N;;;;;\n1017B;GREEK DRACHMA SIGN;So;0;ON;;;;;N;;;;;\n1017C;GREEK OBOL SIGN;So;0;ON;;;;;N;;;;;\n1017D;GREEK TWO OBOLS SIGN;So;0;ON;;;;;N;;;;;\n1017E;GREEK THREE OBOLS SIGN;So;0;ON;;;;;N;;;;;\n1017F;GREEK FOUR OBOLS SIGN;So;0;ON;;;;;N;;;;;\n10180;GREEK FIVE OBOLS SIGN;So;0;ON;;;;;N;;;;;\n10181;GREEK METRETES SIGN;So;0;ON;;;;;N;;;;;\n10182;GREEK KYATHOS BASE SIGN;So;0;ON;;;;;N;;;;;\n10183;GREEK LITRA SIGN;So;0;ON;;;;;N;;;;;\n10184;GREEK OUNKIA SIGN;So;0;ON;;;;;N;;;;;\n10185;GREEK XESTES SIGN;So;0;ON;;;;;N;;;;;\n10186;GREEK ARTABE SIGN;So;0;ON;;;;;N;;;;;\n10187;GREEK AROURA SIGN;So;0;ON;;;;;N;;;;;\n10188;GREEK GRAMMA SIGN;So;0;ON;;;;;N;;;;;\n10189;GREEK TRYBLION BASE SIGN;So;0;ON;;;;;N;;;;;\n1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;;\n1018B;GREEK ONE QUARTER SIGN;No;0;ON;;;;1/4;N;;;;;\n1018C;GREEK SINUSOID SIGN;So;0;ON;;;;;N;;;;;\n1018D;GREEK INDICTION SIGN;So;0;L;;;;;N;;;;;\n1018E;NOMISMA SIGN;So;0;L;;;;;N;;;;;\n10190;ROMAN SEXTANS SIGN;So;0;ON;;;;;N;;;;;\n10191;ROMAN UNCIA SIGN;So;0;ON;;;;;N;;;;;\n10192;ROMAN SEMUNCIA SIGN;So;0;ON;;;;;N;;;;;\n10193;ROMAN SEXTULA SIGN;So;0;ON;;;;;N;;;;;\n10194;ROMAN DIMIDIA SEXTULA SIGN;So;0;ON;;;;;N;;;;;\n10195;ROMAN SILIQUA SIGN;So;0;ON;;;;;N;;;;;\n10196;ROMAN DENARIUS SIGN;So;0;ON;;;;;N;;;;;\n10197;ROMAN QUINARIUS SIGN;So;0;ON;;;;;N;;;;;\n10198;ROMAN SESTERTIUS SIGN;So;0;ON;;;;;N;;;;;\n10199;ROMAN DUPONDIUS SIGN;So;0;ON;;;;;N;;;;;\n1019A;ROMAN AS SIGN;So;0;ON;;;;;N;;;;;\n1019B;ROMAN CENTURIAL SIGN;So;0;ON;;;;;N;;;;;\n1019C;ASCIA SYMBOL;So;0;ON;;;;;N;;;;;\n101A0;GREEK SYMBOL TAU RHO;So;0;ON;;;;;N;;;;;\n101D0;PHAISTOS DISC SIGN PEDESTRIAN;So;0;L;;;;;N;;;;;\n101D1;PHAISTOS DISC SIGN PLUMED HEAD;So;0;L;;;;;N;;;;;\n101D2;PHAISTOS DISC SIGN TATTOOED HEAD;So;0;L;;;;;N;;;;;\n101D3;PHAISTOS DISC SIGN CAPTIVE;So;0;L;;;;;N;;;;;\n101D4;PHAISTOS DISC SIGN CHILD;So;0;L;;;;;N;;;;;\n101D5;PHAISTOS DISC SIGN WOMAN;So;0;L;;;;;N;;;;;\n101D6;PHAISTOS DISC SIGN HELMET;So;0;L;;;;;N;;;;;\n101D7;PHAISTOS DISC SIGN GAUNTLET;So;0;L;;;;;N;;;;;\n101D8;PHAISTOS DISC SIGN TIARA;So;0;L;;;;;N;;;;;\n101D9;PHAISTOS DISC SIGN ARROW;So;0;L;;;;;N;;;;;\n101DA;PHAISTOS DISC SIGN BOW;So;0;L;;;;;N;;;;;\n101DB;PHAISTOS DISC SIGN SHIELD;So;0;L;;;;;N;;;;;\n101DC;PHAISTOS DISC SIGN CLUB;So;0;L;;;;;N;;;;;\n101DD;PHAISTOS DISC SIGN MANACLES;So;0;L;;;;;N;;;;;\n101DE;PHAISTOS DISC SIGN MATTOCK;So;0;L;;;;;N;;;;;\n101DF;PHAISTOS DISC SIGN SAW;So;0;L;;;;;N;;;;;\n101E0;PHAISTOS DISC SIGN LID;So;0;L;;;;;N;;;;;\n101E1;PHAISTOS DISC SIGN BOOMERANG;So;0;L;;;;;N;;;;;\n101E2;PHAISTOS DISC SIGN CARPENTRY PLANE;So;0;L;;;;;N;;;;;\n101E3;PHAISTOS DISC SIGN DOLIUM;So;0;L;;;;;N;;;;;\n101E4;PHAISTOS DISC SIGN COMB;So;0;L;;;;;N;;;;;\n101E5;PHAISTOS DISC SIGN SLING;So;0;L;;;;;N;;;;;\n101E6;PHAISTOS DISC SIGN COLUMN;So;0;L;;;;;N;;;;;\n101E7;PHAISTOS DISC SIGN BEEHIVE;So;0;L;;;;;N;;;;;\n101E8;PHAISTOS DISC SIGN SHIP;So;0;L;;;;;N;;;;;\n101E9;PHAISTOS DISC SIGN HORN;So;0;L;;;;;N;;;;;\n101EA;PHAISTOS DISC SIGN HIDE;So;0;L;;;;;N;;;;;\n101EB;PHAISTOS DISC SIGN BULLS LEG;So;0;L;;;;;N;;;;;\n101EC;PHAISTOS DISC SIGN CAT;So;0;L;;;;;N;;;;;\n101ED;PHAISTOS DISC SIGN RAM;So;0;L;;;;;N;;;;;\n101EE;PHAISTOS DISC SIGN EAGLE;So;0;L;;;;;N;;;;;\n101EF;PHAISTOS DISC SIGN DOVE;So;0;L;;;;;N;;;;;\n101F0;PHAISTOS DISC SIGN TUNNY;So;0;L;;;;;N;;;;;\n101F1;PHAISTOS DISC SIGN BEE;So;0;L;;;;;N;;;;;\n101F2;PHAISTOS DISC SIGN PLANE TREE;So;0;L;;;;;N;;;;;\n101F3;PHAISTOS DISC SIGN VINE;So;0;L;;;;;N;;;;;\n101F4;PHAISTOS DISC SIGN PAPYRUS;So;0;L;;;;;N;;;;;\n101F5;PHAISTOS DISC SIGN ROSETTE;So;0;L;;;;;N;;;;;\n101F6;PHAISTOS DISC SIGN LILY;So;0;L;;;;;N;;;;;\n101F7;PHAISTOS DISC SIGN OX BACK;So;0;L;;;;;N;;;;;\n101F8;PHAISTOS DISC SIGN FLUTE;So;0;L;;;;;N;;;;;\n101F9;PHAISTOS DISC SIGN GRATER;So;0;L;;;;;N;;;;;\n101FA;PHAISTOS DISC SIGN STRAINER;So;0;L;;;;;N;;;;;\n101FB;PHAISTOS DISC SIGN SMALL AXE;So;0;L;;;;;N;;;;;\n101FC;PHAISTOS DISC SIGN WAVY BAND;So;0;L;;;;;N;;;;;\n101FD;PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE;Mn;220;NSM;;;;;N;;;;;\n10280;LYCIAN LETTER A;Lo;0;L;;;;;N;;;;;\n10281;LYCIAN LETTER E;Lo;0;L;;;;;N;;;;;\n10282;LYCIAN LETTER B;Lo;0;L;;;;;N;;;;;\n10283;LYCIAN LETTER BH;Lo;0;L;;;;;N;;;;;\n10284;LYCIAN LETTER G;Lo;0;L;;;;;N;;;;;\n10285;LYCIAN LETTER D;Lo;0;L;;;;;N;;;;;\n10286;LYCIAN LETTER I;Lo;0;L;;;;;N;;;;;\n10287;LYCIAN LETTER W;Lo;0;L;;;;;N;;;;;\n10288;LYCIAN LETTER Z;Lo;0;L;;;;;N;;;;;\n10289;LYCIAN LETTER TH;Lo;0;L;;;;;N;;;;;\n1028A;LYCIAN LETTER J;Lo;0;L;;;;;N;;;;;\n1028B;LYCIAN LETTER K;Lo;0;L;;;;;N;;;;;\n1028C;LYCIAN LETTER Q;Lo;0;L;;;;;N;;;;;\n1028D;LYCIAN LETTER L;Lo;0;L;;;;;N;;;;;\n1028E;LYCIAN LETTER M;Lo;0;L;;;;;N;;;;;\n1028F;LYCIAN LETTER N;Lo;0;L;;;;;N;;;;;\n10290;LYCIAN LETTER MM;Lo;0;L;;;;;N;;;;;\n10291;LYCIAN LETTER NN;Lo;0;L;;;;;N;;;;;\n10292;LYCIAN LETTER U;Lo;0;L;;;;;N;;;;;\n10293;LYCIAN LETTER P;Lo;0;L;;;;;N;;;;;\n10294;LYCIAN LETTER KK;Lo;0;L;;;;;N;;;;;\n10295;LYCIAN LETTER R;Lo;0;L;;;;;N;;;;;\n10296;LYCIAN LETTER S;Lo;0;L;;;;;N;;;;;\n10297;LYCIAN LETTER T;Lo;0;L;;;;;N;;;;;\n10298;LYCIAN LETTER TT;Lo;0;L;;;;;N;;;;;\n10299;LYCIAN LETTER AN;Lo;0;L;;;;;N;;;;;\n1029A;LYCIAN LETTER EN;Lo;0;L;;;;;N;;;;;\n1029B;LYCIAN LETTER H;Lo;0;L;;;;;N;;;;;\n1029C;LYCIAN LETTER X;Lo;0;L;;;;;N;;;;;\n102A0;CARIAN LETTER A;Lo;0;L;;;;;N;;;;;\n102A1;CARIAN LETTER P2;Lo;0;L;;;;;N;;;;;\n102A2;CARIAN LETTER D;Lo;0;L;;;;;N;;;;;\n102A3;CARIAN LETTER L;Lo;0;L;;;;;N;;;;;\n102A4;CARIAN LETTER UUU;Lo;0;L;;;;;N;;;;;\n102A5;CARIAN LETTER R;Lo;0;L;;;;;N;;;;;\n102A6;CARIAN LETTER LD;Lo;0;L;;;;;N;;;;;\n102A7;CARIAN LETTER A2;Lo;0;L;;;;;N;;;;;\n102A8;CARIAN LETTER Q;Lo;0;L;;;;;N;;;;;\n102A9;CARIAN LETTER B;Lo;0;L;;;;;N;;;;;\n102AA;CARIAN LETTER M;Lo;0;L;;;;;N;;;;;\n102AB;CARIAN LETTER O;Lo;0;L;;;;;N;;;;;\n102AC;CARIAN LETTER D2;Lo;0;L;;;;;N;;;;;\n102AD;CARIAN LETTER T;Lo;0;L;;;;;N;;;;;\n102AE;CARIAN LETTER SH;Lo;0;L;;;;;N;;;;;\n102AF;CARIAN LETTER SH2;Lo;0;L;;;;;N;;;;;\n102B0;CARIAN LETTER S;Lo;0;L;;;;;N;;;;;\n102B1;CARIAN LETTER C-18;Lo;0;L;;;;;N;;;;;\n102B2;CARIAN LETTER U;Lo;0;L;;;;;N;;;;;\n102B3;CARIAN LETTER NN;Lo;0;L;;;;;N;;;;;\n102B4;CARIAN LETTER X;Lo;0;L;;;;;N;;;;;\n102B5;CARIAN LETTER N;Lo;0;L;;;;;N;;;;;\n102B6;CARIAN LETTER TT2;Lo;0;L;;;;;N;;;;;\n102B7;CARIAN LETTER P;Lo;0;L;;;;;N;;;;;\n102B8;CARIAN LETTER SS;Lo;0;L;;;;;N;;;;;\n102B9;CARIAN LETTER I;Lo;0;L;;;;;N;;;;;\n102BA;CARIAN LETTER E;Lo;0;L;;;;;N;;;;;\n102BB;CARIAN LETTER UUUU;Lo;0;L;;;;;N;;;;;\n102BC;CARIAN LETTER K;Lo;0;L;;;;;N;;;;;\n102BD;CARIAN LETTER K2;Lo;0;L;;;;;N;;;;;\n102BE;CARIAN LETTER ND;Lo;0;L;;;;;N;;;;;\n102BF;CARIAN LETTER UU;Lo;0;L;;;;;N;;;;;\n102C0;CARIAN LETTER G;Lo;0;L;;;;;N;;;;;\n102C1;CARIAN LETTER G2;Lo;0;L;;;;;N;;;;;\n102C2;CARIAN LETTER ST;Lo;0;L;;;;;N;;;;;\n102C3;CARIAN LETTER ST2;Lo;0;L;;;;;N;;;;;\n102C4;CARIAN LETTER NG;Lo;0;L;;;;;N;;;;;\n102C5;CARIAN LETTER II;Lo;0;L;;;;;N;;;;;\n102C6;CARIAN LETTER C-39;Lo;0;L;;;;;N;;;;;\n102C7;CARIAN LETTER TT;Lo;0;L;;;;;N;;;;;\n102C8;CARIAN LETTER UUU2;Lo;0;L;;;;;N;;;;;\n102C9;CARIAN LETTER RR;Lo;0;L;;;;;N;;;;;\n102CA;CARIAN LETTER MB;Lo;0;L;;;;;N;;;;;\n102CB;CARIAN LETTER MB2;Lo;0;L;;;;;N;;;;;\n102CC;CARIAN LETTER MB3;Lo;0;L;;;;;N;;;;;\n102CD;CARIAN LETTER MB4;Lo;0;L;;;;;N;;;;;\n102CE;CARIAN LETTER LD2;Lo;0;L;;;;;N;;;;;\n102CF;CARIAN LETTER E2;Lo;0;L;;;;;N;;;;;\n102D0;CARIAN LETTER UUU3;Lo;0;L;;;;;N;;;;;\n102E0;COPTIC EPACT THOUSANDS MARK;Mn;220;NSM;;;;;N;;;;;\n102E1;COPTIC EPACT DIGIT ONE;No;0;EN;;;;1;N;;;;;\n102E2;COPTIC EPACT DIGIT TWO;No;0;EN;;;;2;N;;;;;\n102E3;COPTIC EPACT DIGIT THREE;No;0;EN;;;;3;N;;;;;\n102E4;COPTIC EPACT DIGIT FOUR;No;0;EN;;;;4;N;;;;;\n102E5;COPTIC EPACT DIGIT FIVE;No;0;EN;;;;5;N;;;;;\n102E6;COPTIC EPACT DIGIT SIX;No;0;EN;;;;6;N;;;;;\n102E7;COPTIC EPACT DIGIT SEVEN;No;0;EN;;;;7;N;;;;;\n102E8;COPTIC EPACT DIGIT EIGHT;No;0;EN;;;;8;N;;;;;\n102E9;COPTIC EPACT DIGIT NINE;No;0;EN;;;;9;N;;;;;\n102EA;COPTIC EPACT NUMBER TEN;No;0;EN;;;;10;N;;;;;\n102EB;COPTIC EPACT NUMBER TWENTY;No;0;EN;;;;20;N;;;;;\n102EC;COPTIC EPACT NUMBER THIRTY;No;0;EN;;;;30;N;;;;;\n102ED;COPTIC EPACT NUMBER FORTY;No;0;EN;;;;40;N;;;;;\n102EE;COPTIC EPACT NUMBER FIFTY;No;0;EN;;;;50;N;;;;;\n102EF;COPTIC EPACT NUMBER SIXTY;No;0;EN;;;;60;N;;;;;\n102F0;COPTIC EPACT NUMBER SEVENTY;No;0;EN;;;;70;N;;;;;\n102F1;COPTIC EPACT NUMBER EIGHTY;No;0;EN;;;;80;N;;;;;\n102F2;COPTIC EPACT NUMBER NINETY;No;0;EN;;;;90;N;;;;;\n102F3;COPTIC EPACT NUMBER ONE HUNDRED;No;0;EN;;;;100;N;;;;;\n102F4;COPTIC EPACT NUMBER TWO HUNDRED;No;0;EN;;;;200;N;;;;;\n102F5;COPTIC EPACT NUMBER THREE HUNDRED;No;0;EN;;;;300;N;;;;;\n102F6;COPTIC EPACT NUMBER FOUR HUNDRED;No;0;EN;;;;400;N;;;;;\n102F7;COPTIC EPACT NUMBER FIVE HUNDRED;No;0;EN;;;;500;N;;;;;\n102F8;COPTIC EPACT NUMBER SIX HUNDRED;No;0;EN;;;;600;N;;;;;\n102F9;COPTIC EPACT NUMBER SEVEN HUNDRED;No;0;EN;;;;700;N;;;;;\n102FA;COPTIC EPACT NUMBER EIGHT HUNDRED;No;0;EN;;;;800;N;;;;;\n102FB;COPTIC EPACT NUMBER NINE HUNDRED;No;0;EN;;;;900;N;;;;;\n10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;;\n10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;;\n10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;;\n10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;;\n10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;;\n10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;;\n10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;;\n10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;;\n10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;;\n10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;;\n1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;;\n1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;;\n1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;;\n1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;;\n1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;;\n1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;;;;\n10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;;\n10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;;\n10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;;\n10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;;\n10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;;\n10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;;\n10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;;\n10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;;;;\n10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;;\n10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;;\n1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;;\n1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;;;;\n1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;;;;\n1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;;;;\n1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;;;;\n1031F;OLD ITALIC LETTER ESS;Lo;0;L;;;;;N;;;;;\n10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;;\n10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;;\n10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;;\n10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;;\n1032D;OLD ITALIC LETTER YE;Lo;0;L;;;;;N;;;;;\n1032E;OLD ITALIC LETTER NORTHERN TSE;Lo;0;L;;;;;N;;;;;\n1032F;OLD ITALIC LETTER SOUTHERN TSE;Lo;0;L;;;;;N;;;;;\n10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;;\n10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;;\n10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;;\n10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;;\n10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;;\n10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;;\n10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;;\n10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;;\n10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;;\n10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;;\n1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;;\n1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;;\n1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;;\n1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;;\n1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;;\n1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;;\n10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;;\n10341;GOTHIC LETTER NINETY;Nl;0;L;;;;90;N;;;;;\n10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;;\n10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;;\n10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;;\n10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;;\n10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;;\n10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;;\n10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;;\n10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;;\n1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;900;N;;;;;\n10350;OLD PERMIC LETTER AN;Lo;0;L;;;;;N;;;;;\n10351;OLD PERMIC LETTER BUR;Lo;0;L;;;;;N;;;;;\n10352;OLD PERMIC LETTER GAI;Lo;0;L;;;;;N;;;;;\n10353;OLD PERMIC LETTER DOI;Lo;0;L;;;;;N;;;;;\n10354;OLD PERMIC LETTER E;Lo;0;L;;;;;N;;;;;\n10355;OLD PERMIC LETTER ZHOI;Lo;0;L;;;;;N;;;;;\n10356;OLD PERMIC LETTER DZHOI;Lo;0;L;;;;;N;;;;;\n10357;OLD PERMIC LETTER ZATA;Lo;0;L;;;;;N;;;;;\n10358;OLD PERMIC LETTER DZITA;Lo;0;L;;;;;N;;;;;\n10359;OLD PERMIC LETTER I;Lo;0;L;;;;;N;;;;;\n1035A;OLD PERMIC LETTER KOKE;Lo;0;L;;;;;N;;;;;\n1035B;OLD PERMIC LETTER LEI;Lo;0;L;;;;;N;;;;;\n1035C;OLD PERMIC LETTER MENOE;Lo;0;L;;;;;N;;;;;\n1035D;OLD PERMIC LETTER NENOE;Lo;0;L;;;;;N;;;;;\n1035E;OLD PERMIC LETTER VOOI;Lo;0;L;;;;;N;;;;;\n1035F;OLD PERMIC LETTER PEEI;Lo;0;L;;;;;N;;;;;\n10360;OLD PERMIC LETTER REI;Lo;0;L;;;;;N;;;;;\n10361;OLD PERMIC LETTER SII;Lo;0;L;;;;;N;;;;;\n10362;OLD PERMIC LETTER TAI;Lo;0;L;;;;;N;;;;;\n10363;OLD PERMIC LETTER U;Lo;0;L;;;;;N;;;;;\n10364;OLD PERMIC LETTER CHERY;Lo;0;L;;;;;N;;;;;\n10365;OLD PERMIC LETTER SHOOI;Lo;0;L;;;;;N;;;;;\n10366;OLD PERMIC LETTER SHCHOOI;Lo;0;L;;;;;N;;;;;\n10367;OLD PERMIC LETTER YRY;Lo;0;L;;;;;N;;;;;\n10368;OLD PERMIC LETTER YERU;Lo;0;L;;;;;N;;;;;\n10369;OLD PERMIC LETTER O;Lo;0;L;;;;;N;;;;;\n1036A;OLD PERMIC LETTER OO;Lo;0;L;;;;;N;;;;;\n1036B;OLD PERMIC LETTER EF;Lo;0;L;;;;;N;;;;;\n1036C;OLD PERMIC LETTER HA;Lo;0;L;;;;;N;;;;;\n1036D;OLD PERMIC LETTER TSIU;Lo;0;L;;;;;N;;;;;\n1036E;OLD PERMIC LETTER VER;Lo;0;L;;;;;N;;;;;\n1036F;OLD PERMIC LETTER YER;Lo;0;L;;;;;N;;;;;\n10370;OLD PERMIC LETTER YERI;Lo;0;L;;;;;N;;;;;\n10371;OLD PERMIC LETTER YAT;Lo;0;L;;;;;N;;;;;\n10372;OLD PERMIC LETTER IE;Lo;0;L;;;;;N;;;;;\n10373;OLD PERMIC LETTER YU;Lo;0;L;;;;;N;;;;;\n10374;OLD PERMIC LETTER YA;Lo;0;L;;;;;N;;;;;\n10375;OLD PERMIC LETTER IA;Lo;0;L;;;;;N;;;;;\n10376;COMBINING OLD PERMIC LETTER AN;Mn;230;NSM;;;;;N;;;;;\n10377;COMBINING OLD PERMIC LETTER DOI;Mn;230;NSM;;;;;N;;;;;\n10378;COMBINING OLD PERMIC LETTER ZATA;Mn;230;NSM;;;;;N;;;;;\n10379;COMBINING OLD PERMIC LETTER NENOE;Mn;230;NSM;;;;;N;;;;;\n1037A;COMBINING OLD PERMIC LETTER SII;Mn;230;NSM;;;;;N;;;;;\n10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;;\n10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;;\n10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;;\n10383;UGARITIC LETTER KHA;Lo;0;L;;;;;N;;;;;\n10384;UGARITIC LETTER DELTA;Lo;0;L;;;;;N;;;;;\n10385;UGARITIC LETTER HO;Lo;0;L;;;;;N;;;;;\n10386;UGARITIC LETTER WO;Lo;0;L;;;;;N;;;;;\n10387;UGARITIC LETTER ZETA;Lo;0;L;;;;;N;;;;;\n10388;UGARITIC LETTER HOTA;Lo;0;L;;;;;N;;;;;\n10389;UGARITIC LETTER TET;Lo;0;L;;;;;N;;;;;\n1038A;UGARITIC LETTER YOD;Lo;0;L;;;;;N;;;;;\n1038B;UGARITIC LETTER KAF;Lo;0;L;;;;;N;;;;;\n1038C;UGARITIC LETTER SHIN;Lo;0;L;;;;;N;;;;;\n1038D;UGARITIC LETTER LAMDA;Lo;0;L;;;;;N;;;;;\n1038E;UGARITIC LETTER MEM;Lo;0;L;;;;;N;;;;;\n1038F;UGARITIC LETTER DHAL;Lo;0;L;;;;;N;;;;;\n10390;UGARITIC LETTER NUN;Lo;0;L;;;;;N;;;;;\n10391;UGARITIC LETTER ZU;Lo;0;L;;;;;N;;;;;\n10392;UGARITIC LETTER SAMKA;Lo;0;L;;;;;N;;;;;\n10393;UGARITIC LETTER AIN;Lo;0;L;;;;;N;;;;;\n10394;UGARITIC LETTER PU;Lo;0;L;;;;;N;;;;;\n10395;UGARITIC LETTER SADE;Lo;0;L;;;;;N;;;;;\n10396;UGARITIC LETTER QOPA;Lo;0;L;;;;;N;;;;;\n10397;UGARITIC LETTER RASHA;Lo;0;L;;;;;N;;;;;\n10398;UGARITIC LETTER THANNA;Lo;0;L;;;;;N;;;;;\n10399;UGARITIC LETTER GHAIN;Lo;0;L;;;;;N;;;;;\n1039A;UGARITIC LETTER TO;Lo;0;L;;;;;N;;;;;\n1039B;UGARITIC LETTER I;Lo;0;L;;;;;N;;;;;\n1039C;UGARITIC LETTER U;Lo;0;L;;;;;N;;;;;\n1039D;UGARITIC LETTER SSU;Lo;0;L;;;;;N;;;;;\n1039F;UGARITIC WORD DIVIDER;Po;0;L;;;;;N;;;;;\n103A0;OLD PERSIAN SIGN A;Lo;0;L;;;;;N;;;;;\n103A1;OLD PERSIAN SIGN I;Lo;0;L;;;;;N;;;;;\n103A2;OLD PERSIAN SIGN U;Lo;0;L;;;;;N;;;;;\n103A3;OLD PERSIAN SIGN KA;Lo;0;L;;;;;N;;;;;\n103A4;OLD PERSIAN SIGN KU;Lo;0;L;;;;;N;;;;;\n103A5;OLD PERSIAN SIGN GA;Lo;0;L;;;;;N;;;;;\n103A6;OLD PERSIAN SIGN GU;Lo;0;L;;;;;N;;;;;\n103A7;OLD PERSIAN SIGN XA;Lo;0;L;;;;;N;;;;;\n103A8;OLD PERSIAN SIGN CA;Lo;0;L;;;;;N;;;;;\n103A9;OLD PERSIAN SIGN JA;Lo;0;L;;;;;N;;;;;\n103AA;OLD PERSIAN SIGN JI;Lo;0;L;;;;;N;;;;;\n103AB;OLD PERSIAN SIGN TA;Lo;0;L;;;;;N;;;;;\n103AC;OLD PERSIAN SIGN TU;Lo;0;L;;;;;N;;;;;\n103AD;OLD PERSIAN SIGN DA;Lo;0;L;;;;;N;;;;;\n103AE;OLD PERSIAN SIGN DI;Lo;0;L;;;;;N;;;;;\n103AF;OLD PERSIAN SIGN DU;Lo;0;L;;;;;N;;;;;\n103B0;OLD PERSIAN SIGN THA;Lo;0;L;;;;;N;;;;;\n103B1;OLD PERSIAN SIGN PA;Lo;0;L;;;;;N;;;;;\n103B2;OLD PERSIAN SIGN BA;Lo;0;L;;;;;N;;;;;\n103B3;OLD PERSIAN SIGN FA;Lo;0;L;;;;;N;;;;;\n103B4;OLD PERSIAN SIGN NA;Lo;0;L;;;;;N;;;;;\n103B5;OLD PERSIAN SIGN NU;Lo;0;L;;;;;N;;;;;\n103B6;OLD PERSIAN SIGN MA;Lo;0;L;;;;;N;;;;;\n103B7;OLD PERSIAN SIGN MI;Lo;0;L;;;;;N;;;;;\n103B8;OLD PERSIAN SIGN MU;Lo;0;L;;;;;N;;;;;\n103B9;OLD PERSIAN SIGN YA;Lo;0;L;;;;;N;;;;;\n103BA;OLD PERSIAN SIGN VA;Lo;0;L;;;;;N;;;;;\n103BB;OLD PERSIAN SIGN VI;Lo;0;L;;;;;N;;;;;\n103BC;OLD PERSIAN SIGN RA;Lo;0;L;;;;;N;;;;;\n103BD;OLD PERSIAN SIGN RU;Lo;0;L;;;;;N;;;;;\n103BE;OLD PERSIAN SIGN LA;Lo;0;L;;;;;N;;;;;\n103BF;OLD PERSIAN SIGN SA;Lo;0;L;;;;;N;;;;;\n103C0;OLD PERSIAN SIGN ZA;Lo;0;L;;;;;N;;;;;\n103C1;OLD PERSIAN SIGN SHA;Lo;0;L;;;;;N;;;;;\n103C2;OLD PERSIAN SIGN SSA;Lo;0;L;;;;;N;;;;;\n103C3;OLD PERSIAN SIGN HA;Lo;0;L;;;;;N;;;;;\n103C8;OLD PERSIAN SIGN AURAMAZDAA;Lo;0;L;;;;;N;;;;;\n103C9;OLD PERSIAN SIGN AURAMAZDAA-2;Lo;0;L;;;;;N;;;;;\n103CA;OLD PERSIAN SIGN AURAMAZDAAHA;Lo;0;L;;;;;N;;;;;\n103CB;OLD PERSIAN SIGN XSHAAYATHIYA;Lo;0;L;;;;;N;;;;;\n103CC;OLD PERSIAN SIGN DAHYAAUSH;Lo;0;L;;;;;N;;;;;\n103CD;OLD PERSIAN SIGN DAHYAAUSH-2;Lo;0;L;;;;;N;;;;;\n103CE;OLD PERSIAN SIGN BAGA;Lo;0;L;;;;;N;;;;;\n103CF;OLD PERSIAN SIGN BUUMISH;Lo;0;L;;;;;N;;;;;\n103D0;OLD PERSIAN WORD DIVIDER;Po;0;L;;;;;N;;;;;\n103D1;OLD PERSIAN NUMBER ONE;Nl;0;L;;;;1;N;;;;;\n103D2;OLD PERSIAN NUMBER TWO;Nl;0;L;;;;2;N;;;;;\n103D3;OLD PERSIAN NUMBER TEN;Nl;0;L;;;;10;N;;;;;\n103D4;OLD PERSIAN NUMBER TWENTY;Nl;0;L;;;;20;N;;;;;\n103D5;OLD PERSIAN NUMBER HUNDRED;Nl;0;L;;;;100;N;;;;;\n10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;\n10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429;\n10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A;\n10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B;\n10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C;\n10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D;\n10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E;\n10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F;\n10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430;\n10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431;\n1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432;\n1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433;\n1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434;\n1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435;\n1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436;\n1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437;\n10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438;\n10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439;\n10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A;\n10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B;\n10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C;\n10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D;\n10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E;\n10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F;\n10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440;\n10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441;\n1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442;\n1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443;\n1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444;\n1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445;\n1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446;\n1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447;\n10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448;\n10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449;\n10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A;\n10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B;\n10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C;\n10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D;\n10426;DESERET CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;1044E;\n10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;\n10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400\n10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401\n1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402\n1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403\n1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404\n1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405\n1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406\n1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407\n10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408\n10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409\n10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A\n10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B\n10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C\n10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D\n10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E\n10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F\n10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410\n10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411\n1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412\n1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413\n1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414\n1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415\n1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416\n1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417\n10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418\n10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419\n10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A\n10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B\n10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C\n10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D\n10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E\n10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F\n10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420\n10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421\n1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422\n1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423\n1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424\n1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425\n1044E;DESERET SMALL LETTER OI;Ll;0;L;;;;;N;;;10426;;10426\n1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427\n10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;\n10451;SHAVIAN LETTER TOT;Lo;0;L;;;;;N;;;;;\n10452;SHAVIAN LETTER KICK;Lo;0;L;;;;;N;;;;;\n10453;SHAVIAN LETTER FEE;Lo;0;L;;;;;N;;;;;\n10454;SHAVIAN LETTER THIGH;Lo;0;L;;;;;N;;;;;\n10455;SHAVIAN LETTER SO;Lo;0;L;;;;;N;;;;;\n10456;SHAVIAN LETTER SURE;Lo;0;L;;;;;N;;;;;\n10457;SHAVIAN LETTER CHURCH;Lo;0;L;;;;;N;;;;;\n10458;SHAVIAN LETTER YEA;Lo;0;L;;;;;N;;;;;\n10459;SHAVIAN LETTER HUNG;Lo;0;L;;;;;N;;;;;\n1045A;SHAVIAN LETTER BIB;Lo;0;L;;;;;N;;;;;\n1045B;SHAVIAN LETTER DEAD;Lo;0;L;;;;;N;;;;;\n1045C;SHAVIAN LETTER GAG;Lo;0;L;;;;;N;;;;;\n1045D;SHAVIAN LETTER VOW;Lo;0;L;;;;;N;;;;;\n1045E;SHAVIAN LETTER THEY;Lo;0;L;;;;;N;;;;;\n1045F;SHAVIAN LETTER ZOO;Lo;0;L;;;;;N;;;;;\n10460;SHAVIAN LETTER MEASURE;Lo;0;L;;;;;N;;;;;\n10461;SHAVIAN LETTER JUDGE;Lo;0;L;;;;;N;;;;;\n10462;SHAVIAN LETTER WOE;Lo;0;L;;;;;N;;;;;\n10463;SHAVIAN LETTER HA-HA;Lo;0;L;;;;;N;;;;;\n10464;SHAVIAN LETTER LOLL;Lo;0;L;;;;;N;;;;;\n10465;SHAVIAN LETTER MIME;Lo;0;L;;;;;N;;;;;\n10466;SHAVIAN LETTER IF;Lo;0;L;;;;;N;;;;;\n10467;SHAVIAN LETTER EGG;Lo;0;L;;;;;N;;;;;\n10468;SHAVIAN LETTER ASH;Lo;0;L;;;;;N;;;;;\n10469;SHAVIAN LETTER ADO;Lo;0;L;;;;;N;;;;;\n1046A;SHAVIAN LETTER ON;Lo;0;L;;;;;N;;;;;\n1046B;SHAVIAN LETTER WOOL;Lo;0;L;;;;;N;;;;;\n1046C;SHAVIAN LETTER OUT;Lo;0;L;;;;;N;;;;;\n1046D;SHAVIAN LETTER AH;Lo;0;L;;;;;N;;;;;\n1046E;SHAVIAN LETTER ROAR;Lo;0;L;;;;;N;;;;;\n1046F;SHAVIAN LETTER NUN;Lo;0;L;;;;;N;;;;;\n10470;SHAVIAN LETTER EAT;Lo;0;L;;;;;N;;;;;\n10471;SHAVIAN LETTER AGE;Lo;0;L;;;;;N;;;;;\n10472;SHAVIAN LETTER ICE;Lo;0;L;;;;;N;;;;;\n10473;SHAVIAN LETTER UP;Lo;0;L;;;;;N;;;;;\n10474;SHAVIAN LETTER OAK;Lo;0;L;;;;;N;;;;;\n10475;SHAVIAN LETTER OOZE;Lo;0;L;;;;;N;;;;;\n10476;SHAVIAN LETTER OIL;Lo;0;L;;;;;N;;;;;\n10477;SHAVIAN LETTER AWE;Lo;0;L;;;;;N;;;;;\n10478;SHAVIAN LETTER ARE;Lo;0;L;;;;;N;;;;;\n10479;SHAVIAN LETTER OR;Lo;0;L;;;;;N;;;;;\n1047A;SHAVIAN LETTER AIR;Lo;0;L;;;;;N;;;;;\n1047B;SHAVIAN LETTER ERR;Lo;0;L;;;;;N;;;;;\n1047C;SHAVIAN LETTER ARRAY;Lo;0;L;;;;;N;;;;;\n1047D;SHAVIAN LETTER EAR;Lo;0;L;;;;;N;;;;;\n1047E;SHAVIAN LETTER IAN;Lo;0;L;;;;;N;;;;;\n1047F;SHAVIAN LETTER YEW;Lo;0;L;;;;;N;;;;;\n10480;OSMANYA LETTER ALEF;Lo;0;L;;;;;N;;;;;\n10481;OSMANYA LETTER BA;Lo;0;L;;;;;N;;;;;\n10482;OSMANYA LETTER TA;Lo;0;L;;;;;N;;;;;\n10483;OSMANYA LETTER JA;Lo;0;L;;;;;N;;;;;\n10484;OSMANYA LETTER XA;Lo;0;L;;;;;N;;;;;\n10485;OSMANYA LETTER KHA;Lo;0;L;;;;;N;;;;;\n10486;OSMANYA LETTER DEEL;Lo;0;L;;;;;N;;;;;\n10487;OSMANYA LETTER RA;Lo;0;L;;;;;N;;;;;\n10488;OSMANYA LETTER SA;Lo;0;L;;;;;N;;;;;\n10489;OSMANYA LETTER SHIIN;Lo;0;L;;;;;N;;;;;\n1048A;OSMANYA LETTER DHA;Lo;0;L;;;;;N;;;;;\n1048B;OSMANYA LETTER CAYN;Lo;0;L;;;;;N;;;;;\n1048C;OSMANYA LETTER GA;Lo;0;L;;;;;N;;;;;\n1048D;OSMANYA LETTER FA;Lo;0;L;;;;;N;;;;;\n1048E;OSMANYA LETTER QAAF;Lo;0;L;;;;;N;;;;;\n1048F;OSMANYA LETTER KAAF;Lo;0;L;;;;;N;;;;;\n10490;OSMANYA LETTER LAAN;Lo;0;L;;;;;N;;;;;\n10491;OSMANYA LETTER MIIN;Lo;0;L;;;;;N;;;;;\n10492;OSMANYA LETTER NUUN;Lo;0;L;;;;;N;;;;;\n10493;OSMANYA LETTER WAW;Lo;0;L;;;;;N;;;;;\n10494;OSMANYA LETTER HA;Lo;0;L;;;;;N;;;;;\n10495;OSMANYA LETTER YA;Lo;0;L;;;;;N;;;;;\n10496;OSMANYA LETTER A;Lo;0;L;;;;;N;;;;;\n10497;OSMANYA LETTER E;Lo;0;L;;;;;N;;;;;\n10498;OSMANYA LETTER I;Lo;0;L;;;;;N;;;;;\n10499;OSMANYA LETTER O;Lo;0;L;;;;;N;;;;;\n1049A;OSMANYA LETTER U;Lo;0;L;;;;;N;;;;;\n1049B;OSMANYA LETTER AA;Lo;0;L;;;;;N;;;;;\n1049C;OSMANYA LETTER EE;Lo;0;L;;;;;N;;;;;\n1049D;OSMANYA LETTER OO;Lo;0;L;;;;;N;;;;;\n104A0;OSMANYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n104A1;OSMANYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n104A2;OSMANYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n104A3;OSMANYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n104A4;OSMANYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n104A5;OSMANYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n104A6;OSMANYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n104B0;OSAGE CAPITAL LETTER A;Lu;0;L;;;;;N;;;;104D8;\n104B1;OSAGE CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;104D9;\n104B2;OSAGE CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;104DA;\n104B3;OSAGE CAPITAL LETTER AH;Lu;0;L;;;;;N;;;;104DB;\n104B4;OSAGE CAPITAL LETTER BRA;Lu;0;L;;;;;N;;;;104DC;\n104B5;OSAGE CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;104DD;\n104B6;OSAGE CAPITAL LETTER EHCHA;Lu;0;L;;;;;N;;;;104DE;\n104B7;OSAGE CAPITAL LETTER E;Lu;0;L;;;;;N;;;;104DF;\n104B8;OSAGE CAPITAL LETTER EIN;Lu;0;L;;;;;N;;;;104E0;\n104B9;OSAGE CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;104E1;\n104BA;OSAGE CAPITAL LETTER HYA;Lu;0;L;;;;;N;;;;104E2;\n104BB;OSAGE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;104E3;\n104BC;OSAGE CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;104E4;\n104BD;OSAGE CAPITAL LETTER EHKA;Lu;0;L;;;;;N;;;;104E5;\n104BE;OSAGE CAPITAL LETTER KYA;Lu;0;L;;;;;N;;;;104E6;\n104BF;OSAGE CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;104E7;\n104C0;OSAGE CAPITAL LETTER MA;Lu;0;L;;;;;N;;;;104E8;\n104C1;OSAGE CAPITAL LETTER NA;Lu;0;L;;;;;N;;;;104E9;\n104C2;OSAGE CAPITAL LETTER O;Lu;0;L;;;;;N;;;;104EA;\n104C3;OSAGE CAPITAL LETTER OIN;Lu;0;L;;;;;N;;;;104EB;\n104C4;OSAGE CAPITAL LETTER PA;Lu;0;L;;;;;N;;;;104EC;\n104C5;OSAGE CAPITAL LETTER EHPA;Lu;0;L;;;;;N;;;;104ED;\n104C6;OSAGE CAPITAL LETTER SA;Lu;0;L;;;;;N;;;;104EE;\n104C7;OSAGE CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;104EF;\n104C8;OSAGE CAPITAL LETTER TA;Lu;0;L;;;;;N;;;;104F0;\n104C9;OSAGE CAPITAL LETTER EHTA;Lu;0;L;;;;;N;;;;104F1;\n104CA;OSAGE CAPITAL LETTER TSA;Lu;0;L;;;;;N;;;;104F2;\n104CB;OSAGE CAPITAL LETTER EHTSA;Lu;0;L;;;;;N;;;;104F3;\n104CC;OSAGE CAPITAL LETTER TSHA;Lu;0;L;;;;;N;;;;104F4;\n104CD;OSAGE CAPITAL LETTER DHA;Lu;0;L;;;;;N;;;;104F5;\n104CE;OSAGE CAPITAL LETTER U;Lu;0;L;;;;;N;;;;104F6;\n104CF;OSAGE CAPITAL LETTER WA;Lu;0;L;;;;;N;;;;104F7;\n104D0;OSAGE CAPITAL LETTER KHA;Lu;0;L;;;;;N;;;;104F8;\n104D1;OSAGE CAPITAL LETTER GHA;Lu;0;L;;;;;N;;;;104F9;\n104D2;OSAGE CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;104FA;\n104D3;OSAGE CAPITAL LETTER ZHA;Lu;0;L;;;;;N;;;;104FB;\n104D8;OSAGE SMALL LETTER A;Ll;0;L;;;;;N;;;104B0;;104B0\n104D9;OSAGE SMALL LETTER AI;Ll;0;L;;;;;N;;;104B1;;104B1\n104DA;OSAGE SMALL LETTER AIN;Ll;0;L;;;;;N;;;104B2;;104B2\n104DB;OSAGE SMALL LETTER AH;Ll;0;L;;;;;N;;;104B3;;104B3\n104DC;OSAGE SMALL LETTER BRA;Ll;0;L;;;;;N;;;104B4;;104B4\n104DD;OSAGE SMALL LETTER CHA;Ll;0;L;;;;;N;;;104B5;;104B5\n104DE;OSAGE SMALL LETTER EHCHA;Ll;0;L;;;;;N;;;104B6;;104B6\n104DF;OSAGE SMALL LETTER E;Ll;0;L;;;;;N;;;104B7;;104B7\n104E0;OSAGE SMALL LETTER EIN;Ll;0;L;;;;;N;;;104B8;;104B8\n104E1;OSAGE SMALL LETTER HA;Ll;0;L;;;;;N;;;104B9;;104B9\n104E2;OSAGE SMALL LETTER HYA;Ll;0;L;;;;;N;;;104BA;;104BA\n104E3;OSAGE SMALL LETTER I;Ll;0;L;;;;;N;;;104BB;;104BB\n104E4;OSAGE SMALL LETTER KA;Ll;0;L;;;;;N;;;104BC;;104BC\n104E5;OSAGE SMALL LETTER EHKA;Ll;0;L;;;;;N;;;104BD;;104BD\n104E6;OSAGE SMALL LETTER KYA;Ll;0;L;;;;;N;;;104BE;;104BE\n104E7;OSAGE SMALL LETTER LA;Ll;0;L;;;;;N;;;104BF;;104BF\n104E8;OSAGE SMALL LETTER MA;Ll;0;L;;;;;N;;;104C0;;104C0\n104E9;OSAGE SMALL LETTER NA;Ll;0;L;;;;;N;;;104C1;;104C1\n104EA;OSAGE SMALL LETTER O;Ll;0;L;;;;;N;;;104C2;;104C2\n104EB;OSAGE SMALL LETTER OIN;Ll;0;L;;;;;N;;;104C3;;104C3\n104EC;OSAGE SMALL LETTER PA;Ll;0;L;;;;;N;;;104C4;;104C4\n104ED;OSAGE SMALL LETTER EHPA;Ll;0;L;;;;;N;;;104C5;;104C5\n104EE;OSAGE SMALL LETTER SA;Ll;0;L;;;;;N;;;104C6;;104C6\n104EF;OSAGE SMALL LETTER SHA;Ll;0;L;;;;;N;;;104C7;;104C7\n104F0;OSAGE SMALL LETTER TA;Ll;0;L;;;;;N;;;104C8;;104C8\n104F1;OSAGE SMALL LETTER EHTA;Ll;0;L;;;;;N;;;104C9;;104C9\n104F2;OSAGE SMALL LETTER TSA;Ll;0;L;;;;;N;;;104CA;;104CA\n104F3;OSAGE SMALL LETTER EHTSA;Ll;0;L;;;;;N;;;104CB;;104CB\n104F4;OSAGE SMALL LETTER TSHA;Ll;0;L;;;;;N;;;104CC;;104CC\n104F5;OSAGE SMALL LETTER DHA;Ll;0;L;;;;;N;;;104CD;;104CD\n104F6;OSAGE SMALL LETTER U;Ll;0;L;;;;;N;;;104CE;;104CE\n104F7;OSAGE SMALL LETTER WA;Ll;0;L;;;;;N;;;104CF;;104CF\n104F8;OSAGE SMALL LETTER KHA;Ll;0;L;;;;;N;;;104D0;;104D0\n104F9;OSAGE SMALL LETTER GHA;Ll;0;L;;;;;N;;;104D1;;104D1\n104FA;OSAGE SMALL LETTER ZA;Ll;0;L;;;;;N;;;104D2;;104D2\n104FB;OSAGE SMALL LETTER ZHA;Ll;0;L;;;;;N;;;104D3;;104D3\n10500;ELBASAN LETTER A;Lo;0;L;;;;;N;;;;;\n10501;ELBASAN LETTER BE;Lo;0;L;;;;;N;;;;;\n10502;ELBASAN LETTER CE;Lo;0;L;;;;;N;;;;;\n10503;ELBASAN LETTER CHE;Lo;0;L;;;;;N;;;;;\n10504;ELBASAN LETTER DE;Lo;0;L;;;;;N;;;;;\n10505;ELBASAN LETTER NDE;Lo;0;L;;;;;N;;;;;\n10506;ELBASAN LETTER DHE;Lo;0;L;;;;;N;;;;;\n10507;ELBASAN LETTER EI;Lo;0;L;;;;;N;;;;;\n10508;ELBASAN LETTER E;Lo;0;L;;;;;N;;;;;\n10509;ELBASAN LETTER FE;Lo;0;L;;;;;N;;;;;\n1050A;ELBASAN LETTER GE;Lo;0;L;;;;;N;;;;;\n1050B;ELBASAN LETTER GJE;Lo;0;L;;;;;N;;;;;\n1050C;ELBASAN LETTER HE;Lo;0;L;;;;;N;;;;;\n1050D;ELBASAN LETTER I;Lo;0;L;;;;;N;;;;;\n1050E;ELBASAN LETTER JE;Lo;0;L;;;;;N;;;;;\n1050F;ELBASAN LETTER KE;Lo;0;L;;;;;N;;;;;\n10510;ELBASAN LETTER LE;Lo;0;L;;;;;N;;;;;\n10511;ELBASAN LETTER LLE;Lo;0;L;;;;;N;;;;;\n10512;ELBASAN LETTER ME;Lo;0;L;;;;;N;;;;;\n10513;ELBASAN LETTER NE;Lo;0;L;;;;;N;;;;;\n10514;ELBASAN LETTER NA;Lo;0;L;;;;;N;;;;;\n10515;ELBASAN LETTER NJE;Lo;0;L;;;;;N;;;;;\n10516;ELBASAN LETTER O;Lo;0;L;;;;;N;;;;;\n10517;ELBASAN LETTER PE;Lo;0;L;;;;;N;;;;;\n10518;ELBASAN LETTER QE;Lo;0;L;;;;;N;;;;;\n10519;ELBASAN LETTER RE;Lo;0;L;;;;;N;;;;;\n1051A;ELBASAN LETTER RRE;Lo;0;L;;;;;N;;;;;\n1051B;ELBASAN LETTER SE;Lo;0;L;;;;;N;;;;;\n1051C;ELBASAN LETTER SHE;Lo;0;L;;;;;N;;;;;\n1051D;ELBASAN LETTER TE;Lo;0;L;;;;;N;;;;;\n1051E;ELBASAN LETTER THE;Lo;0;L;;;;;N;;;;;\n1051F;ELBASAN LETTER U;Lo;0;L;;;;;N;;;;;\n10520;ELBASAN LETTER VE;Lo;0;L;;;;;N;;;;;\n10521;ELBASAN LETTER XE;Lo;0;L;;;;;N;;;;;\n10522;ELBASAN LETTER Y;Lo;0;L;;;;;N;;;;;\n10523;ELBASAN LETTER ZE;Lo;0;L;;;;;N;;;;;\n10524;ELBASAN LETTER ZHE;Lo;0;L;;;;;N;;;;;\n10525;ELBASAN LETTER GHE;Lo;0;L;;;;;N;;;;;\n10526;ELBASAN LETTER GHAMMA;Lo;0;L;;;;;N;;;;;\n10527;ELBASAN LETTER KHE;Lo;0;L;;;;;N;;;;;\n10530;CAUCASIAN ALBANIAN LETTER ALT;Lo;0;L;;;;;N;;;;;\n10531;CAUCASIAN ALBANIAN LETTER BET;Lo;0;L;;;;;N;;;;;\n10532;CAUCASIAN ALBANIAN LETTER GIM;Lo;0;L;;;;;N;;;;;\n10533;CAUCASIAN ALBANIAN LETTER DAT;Lo;0;L;;;;;N;;;;;\n10534;CAUCASIAN ALBANIAN LETTER EB;Lo;0;L;;;;;N;;;;;\n10535;CAUCASIAN ALBANIAN LETTER ZARL;Lo;0;L;;;;;N;;;;;\n10536;CAUCASIAN ALBANIAN LETTER EYN;Lo;0;L;;;;;N;;;;;\n10537;CAUCASIAN ALBANIAN LETTER ZHIL;Lo;0;L;;;;;N;;;;;\n10538;CAUCASIAN ALBANIAN LETTER TAS;Lo;0;L;;;;;N;;;;;\n10539;CAUCASIAN ALBANIAN LETTER CHA;Lo;0;L;;;;;N;;;;;\n1053A;CAUCASIAN ALBANIAN LETTER YOWD;Lo;0;L;;;;;N;;;;;\n1053B;CAUCASIAN ALBANIAN LETTER ZHA;Lo;0;L;;;;;N;;;;;\n1053C;CAUCASIAN ALBANIAN LETTER IRB;Lo;0;L;;;;;N;;;;;\n1053D;CAUCASIAN ALBANIAN LETTER SHA;Lo;0;L;;;;;N;;;;;\n1053E;CAUCASIAN ALBANIAN LETTER LAN;Lo;0;L;;;;;N;;;;;\n1053F;CAUCASIAN ALBANIAN LETTER INYA;Lo;0;L;;;;;N;;;;;\n10540;CAUCASIAN ALBANIAN LETTER XEYN;Lo;0;L;;;;;N;;;;;\n10541;CAUCASIAN ALBANIAN LETTER DYAN;Lo;0;L;;;;;N;;;;;\n10542;CAUCASIAN ALBANIAN LETTER CAR;Lo;0;L;;;;;N;;;;;\n10543;CAUCASIAN ALBANIAN LETTER JHOX;Lo;0;L;;;;;N;;;;;\n10544;CAUCASIAN ALBANIAN LETTER KAR;Lo;0;L;;;;;N;;;;;\n10545;CAUCASIAN ALBANIAN LETTER LYIT;Lo;0;L;;;;;N;;;;;\n10546;CAUCASIAN ALBANIAN LETTER HEYT;Lo;0;L;;;;;N;;;;;\n10547;CAUCASIAN ALBANIAN LETTER QAY;Lo;0;L;;;;;N;;;;;\n10548;CAUCASIAN ALBANIAN LETTER AOR;Lo;0;L;;;;;N;;;;;\n10549;CAUCASIAN ALBANIAN LETTER CHOY;Lo;0;L;;;;;N;;;;;\n1054A;CAUCASIAN ALBANIAN LETTER CHI;Lo;0;L;;;;;N;;;;;\n1054B;CAUCASIAN ALBANIAN LETTER CYAY;Lo;0;L;;;;;N;;;;;\n1054C;CAUCASIAN ALBANIAN LETTER MAQ;Lo;0;L;;;;;N;;;;;\n1054D;CAUCASIAN ALBANIAN LETTER QAR;Lo;0;L;;;;;N;;;;;\n1054E;CAUCASIAN ALBANIAN LETTER NOWC;Lo;0;L;;;;;N;;;;;\n1054F;CAUCASIAN ALBANIAN LETTER DZYAY;Lo;0;L;;;;;N;;;;;\n10550;CAUCASIAN ALBANIAN LETTER SHAK;Lo;0;L;;;;;N;;;;;\n10551;CAUCASIAN ALBANIAN LETTER JAYN;Lo;0;L;;;;;N;;;;;\n10552;CAUCASIAN ALBANIAN LETTER ON;Lo;0;L;;;;;N;;;;;\n10553;CAUCASIAN ALBANIAN LETTER TYAY;Lo;0;L;;;;;N;;;;;\n10554;CAUCASIAN ALBANIAN LETTER FAM;Lo;0;L;;;;;N;;;;;\n10555;CAUCASIAN ALBANIAN LETTER DZAY;Lo;0;L;;;;;N;;;;;\n10556;CAUCASIAN ALBANIAN LETTER CHAT;Lo;0;L;;;;;N;;;;;\n10557;CAUCASIAN ALBANIAN LETTER PEN;Lo;0;L;;;;;N;;;;;\n10558;CAUCASIAN ALBANIAN LETTER GHEYS;Lo;0;L;;;;;N;;;;;\n10559;CAUCASIAN ALBANIAN LETTER RAT;Lo;0;L;;;;;N;;;;;\n1055A;CAUCASIAN ALBANIAN LETTER SEYK;Lo;0;L;;;;;N;;;;;\n1055B;CAUCASIAN ALBANIAN LETTER VEYZ;Lo;0;L;;;;;N;;;;;\n1055C;CAUCASIAN ALBANIAN LETTER TIWR;Lo;0;L;;;;;N;;;;;\n1055D;CAUCASIAN ALBANIAN LETTER SHOY;Lo;0;L;;;;;N;;;;;\n1055E;CAUCASIAN ALBANIAN LETTER IWN;Lo;0;L;;;;;N;;;;;\n1055F;CAUCASIAN ALBANIAN LETTER CYAW;Lo;0;L;;;;;N;;;;;\n10560;CAUCASIAN ALBANIAN LETTER CAYN;Lo;0;L;;;;;N;;;;;\n10561;CAUCASIAN ALBANIAN LETTER YAYD;Lo;0;L;;;;;N;;;;;\n10562;CAUCASIAN ALBANIAN LETTER PIWR;Lo;0;L;;;;;N;;;;;\n10563;CAUCASIAN ALBANIAN LETTER KIW;Lo;0;L;;;;;N;;;;;\n1056F;CAUCASIAN ALBANIAN CITATION MARK;Po;0;L;;;;;N;;;;;\n10570;VITHKUQI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;10597;\n10571;VITHKUQI CAPITAL LETTER BBE;Lu;0;L;;;;;N;;;;10598;\n10572;VITHKUQI CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;10599;\n10573;VITHKUQI CAPITAL LETTER CE;Lu;0;L;;;;;N;;;;1059A;\n10574;VITHKUQI CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;1059B;\n10575;VITHKUQI CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;1059C;\n10576;VITHKUQI CAPITAL LETTER DHE;Lu;0;L;;;;;N;;;;1059D;\n10577;VITHKUQI CAPITAL LETTER EI;Lu;0;L;;;;;N;;;;1059E;\n10578;VITHKUQI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;1059F;\n10579;VITHKUQI CAPITAL LETTER FE;Lu;0;L;;;;;N;;;;105A0;\n1057A;VITHKUQI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;105A1;\n1057C;VITHKUQI CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;105A3;\n1057D;VITHKUQI CAPITAL LETTER HHA;Lu;0;L;;;;;N;;;;105A4;\n1057E;VITHKUQI CAPITAL LETTER I;Lu;0;L;;;;;N;;;;105A5;\n1057F;VITHKUQI CAPITAL LETTER IJE;Lu;0;L;;;;;N;;;;105A6;\n10580;VITHKUQI CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;105A7;\n10581;VITHKUQI CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;105A8;\n10582;VITHKUQI CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;105A9;\n10583;VITHKUQI CAPITAL LETTER LLA;Lu;0;L;;;;;N;;;;105AA;\n10584;VITHKUQI CAPITAL LETTER ME;Lu;0;L;;;;;N;;;;105AB;\n10585;VITHKUQI CAPITAL LETTER NE;Lu;0;L;;;;;N;;;;105AC;\n10586;VITHKUQI CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;105AD;\n10587;VITHKUQI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;105AE;\n10588;VITHKUQI CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;105AF;\n10589;VITHKUQI CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;105B0;\n1058A;VITHKUQI CAPITAL LETTER RE;Lu;0;L;;;;;N;;;;105B1;\n1058C;VITHKUQI CAPITAL LETTER SE;Lu;0;L;;;;;N;;;;105B3;\n1058D;VITHKUQI CAPITAL LETTER SHE;Lu;0;L;;;;;N;;;;105B4;\n1058E;VITHKUQI CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;105B5;\n1058F;VITHKUQI CAPITAL LETTER THE;Lu;0;L;;;;;N;;;;105B6;\n10590;VITHKUQI CAPITAL LETTER U;Lu;0;L;;;;;N;;;;105B7;\n10591;VITHKUQI CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;105B8;\n10592;VITHKUQI CAPITAL LETTER XE;Lu;0;L;;;;;N;;;;105B9;\n10594;VITHKUQI CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;105BB;\n10595;VITHKUQI CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;105BC;\n10597;VITHKUQI SMALL LETTER A;Ll;0;L;;;;;N;;;10570;;10570\n10598;VITHKUQI SMALL LETTER BBE;Ll;0;L;;;;;N;;;10571;;10571\n10599;VITHKUQI SMALL LETTER BE;Ll;0;L;;;;;N;;;10572;;10572\n1059A;VITHKUQI SMALL LETTER CE;Ll;0;L;;;;;N;;;10573;;10573\n1059B;VITHKUQI SMALL LETTER CHE;Ll;0;L;;;;;N;;;10574;;10574\n1059C;VITHKUQI SMALL LETTER DE;Ll;0;L;;;;;N;;;10575;;10575\n1059D;VITHKUQI SMALL LETTER DHE;Ll;0;L;;;;;N;;;10576;;10576\n1059E;VITHKUQI SMALL LETTER EI;Ll;0;L;;;;;N;;;10577;;10577\n1059F;VITHKUQI SMALL LETTER E;Ll;0;L;;;;;N;;;10578;;10578\n105A0;VITHKUQI SMALL LETTER FE;Ll;0;L;;;;;N;;;10579;;10579\n105A1;VITHKUQI SMALL LETTER GA;Ll;0;L;;;;;N;;;1057A;;1057A\n105A3;VITHKUQI SMALL LETTER HA;Ll;0;L;;;;;N;;;1057C;;1057C\n105A4;VITHKUQI SMALL LETTER HHA;Ll;0;L;;;;;N;;;1057D;;1057D\n105A5;VITHKUQI SMALL LETTER I;Ll;0;L;;;;;N;;;1057E;;1057E\n105A6;VITHKUQI SMALL LETTER IJE;Ll;0;L;;;;;N;;;1057F;;1057F\n105A7;VITHKUQI SMALL LETTER JE;Ll;0;L;;;;;N;;;10580;;10580\n105A8;VITHKUQI SMALL LETTER KA;Ll;0;L;;;;;N;;;10581;;10581\n105A9;VITHKUQI SMALL LETTER LA;Ll;0;L;;;;;N;;;10582;;10582\n105AA;VITHKUQI SMALL LETTER LLA;Ll;0;L;;;;;N;;;10583;;10583\n105AB;VITHKUQI SMALL LETTER ME;Ll;0;L;;;;;N;;;10584;;10584\n105AC;VITHKUQI SMALL LETTER NE;Ll;0;L;;;;;N;;;10585;;10585\n105AD;VITHKUQI SMALL LETTER NJE;Ll;0;L;;;;;N;;;10586;;10586\n105AE;VITHKUQI SMALL LETTER O;Ll;0;L;;;;;N;;;10587;;10587\n105AF;VITHKUQI SMALL LETTER PE;Ll;0;L;;;;;N;;;10588;;10588\n105B0;VITHKUQI SMALL LETTER QA;Ll;0;L;;;;;N;;;10589;;10589\n105B1;VITHKUQI SMALL LETTER RE;Ll;0;L;;;;;N;;;1058A;;1058A\n105B3;VITHKUQI SMALL LETTER SE;Ll;0;L;;;;;N;;;1058C;;1058C\n105B4;VITHKUQI SMALL LETTER SHE;Ll;0;L;;;;;N;;;1058D;;1058D\n105B5;VITHKUQI SMALL LETTER TE;Ll;0;L;;;;;N;;;1058E;;1058E\n105B6;VITHKUQI SMALL LETTER THE;Ll;0;L;;;;;N;;;1058F;;1058F\n105B7;VITHKUQI SMALL LETTER U;Ll;0;L;;;;;N;;;10590;;10590\n105B8;VITHKUQI SMALL LETTER VE;Ll;0;L;;;;;N;;;10591;;10591\n105B9;VITHKUQI SMALL LETTER XE;Ll;0;L;;;;;N;;;10592;;10592\n105BB;VITHKUQI SMALL LETTER Y;Ll;0;L;;;;;N;;;10594;;10594\n105BC;VITHKUQI SMALL LETTER ZE;Ll;0;L;;;;;N;;;10595;;10595\n105C0;TODHRI LETTER A;Lo;0;L;;;;;N;;;;;\n105C1;TODHRI LETTER AS;Lo;0;L;;;;;N;;;;;\n105C2;TODHRI LETTER BA;Lo;0;L;;;;;N;;;;;\n105C3;TODHRI LETTER MBA;Lo;0;L;;;;;N;;;;;\n105C4;TODHRI LETTER CA;Lo;0;L;;;;;N;;;;;\n105C5;TODHRI LETTER CHA;Lo;0;L;;;;;N;;;;;\n105C6;TODHRI LETTER DA;Lo;0;L;;;;;N;;;;;\n105C7;TODHRI LETTER NDA;Lo;0;L;;;;;N;;;;;\n105C8;TODHRI LETTER DHA;Lo;0;L;;;;;N;;;;;\n105C9;TODHRI LETTER EI;Lo;0;L;105D2 0307;;;;N;;;;;\n105CA;TODHRI LETTER E;Lo;0;L;;;;;N;;;;;\n105CB;TODHRI LETTER FA;Lo;0;L;;;;;N;;;;;\n105CC;TODHRI LETTER GA;Lo;0;L;;;;;N;;;;;\n105CD;TODHRI LETTER NGA;Lo;0;L;;;;;N;;;;;\n105CE;TODHRI LETTER GJA;Lo;0;L;;;;;N;;;;;\n105CF;TODHRI LETTER NGJA;Lo;0;L;;;;;N;;;;;\n105D0;TODHRI LETTER HA;Lo;0;L;;;;;N;;;;;\n105D1;TODHRI LETTER HJA;Lo;0;L;;;;;N;;;;;\n105D2;TODHRI LETTER I;Lo;0;L;;;;;N;;;;;\n105D3;TODHRI LETTER JA;Lo;0;L;;;;;N;;;;;\n105D4;TODHRI LETTER KA;Lo;0;L;;;;;N;;;;;\n105D5;TODHRI LETTER LA;Lo;0;L;;;;;N;;;;;\n105D6;TODHRI LETTER LLA;Lo;0;L;;;;;N;;;;;\n105D7;TODHRI LETTER MA;Lo;0;L;;;;;N;;;;;\n105D8;TODHRI LETTER NA;Lo;0;L;;;;;N;;;;;\n105D9;TODHRI LETTER NJAN;Lo;0;L;;;;;N;;;;;\n105DA;TODHRI LETTER O;Lo;0;L;;;;;N;;;;;\n105DB;TODHRI LETTER PA;Lo;0;L;;;;;N;;;;;\n105DC;TODHRI LETTER QA;Lo;0;L;;;;;N;;;;;\n105DD;TODHRI LETTER RA;Lo;0;L;;;;;N;;;;;\n105DE;TODHRI LETTER RRA;Lo;0;L;;;;;N;;;;;\n105DF;TODHRI LETTER SA;Lo;0;L;;;;;N;;;;;\n105E0;TODHRI LETTER SHA;Lo;0;L;;;;;N;;;;;\n105E1;TODHRI LETTER SHTA;Lo;0;L;;;;;N;;;;;\n105E2;TODHRI LETTER TA;Lo;0;L;;;;;N;;;;;\n105E3;TODHRI LETTER THA;Lo;0;L;;;;;N;;;;;\n105E4;TODHRI LETTER U;Lo;0;L;105DA 0307;;;;N;;;;;\n105E5;TODHRI LETTER VA;Lo;0;L;;;;;N;;;;;\n105E6;TODHRI LETTER XA;Lo;0;L;;;;;N;;;;;\n105E7;TODHRI LETTER NXA;Lo;0;L;;;;;N;;;;;\n105E8;TODHRI LETTER XHA;Lo;0;L;;;;;N;;;;;\n105E9;TODHRI LETTER NXHA;Lo;0;L;;;;;N;;;;;\n105EA;TODHRI LETTER Y;Lo;0;L;;;;;N;;;;;\n105EB;TODHRI LETTER JY;Lo;0;L;;;;;N;;;;;\n105EC;TODHRI LETTER ZA;Lo;0;L;;;;;N;;;;;\n105ED;TODHRI LETTER ZHA;Lo;0;L;;;;;N;;;;;\n105EE;TODHRI LETTER GHA;Lo;0;L;;;;;N;;;;;\n105EF;TODHRI LETTER STA;Lo;0;L;;;;;N;;;;;\n105F0;TODHRI LETTER SKAN;Lo;0;L;;;;;N;;;;;\n105F1;TODHRI LETTER KHA;Lo;0;L;;;;;N;;;;;\n105F2;TODHRI LETTER PSA;Lo;0;L;;;;;N;;;;;\n105F3;TODHRI LETTER OO;Lo;0;L;;;;;N;;;;;\n10600;LINEAR A SIGN AB001;Lo;0;L;;;;;N;;;;;\n10601;LINEAR A SIGN AB002;Lo;0;L;;;;;N;;;;;\n10602;LINEAR A SIGN AB003;Lo;0;L;;;;;N;;;;;\n10603;LINEAR A SIGN AB004;Lo;0;L;;;;;N;;;;;\n10604;LINEAR A SIGN AB005;Lo;0;L;;;;;N;;;;;\n10605;LINEAR A SIGN AB006;Lo;0;L;;;;;N;;;;;\n10606;LINEAR A SIGN AB007;Lo;0;L;;;;;N;;;;;\n10607;LINEAR A SIGN AB008;Lo;0;L;;;;;N;;;;;\n10608;LINEAR A SIGN AB009;Lo;0;L;;;;;N;;;;;\n10609;LINEAR A SIGN AB010;Lo;0;L;;;;;N;;;;;\n1060A;LINEAR A SIGN AB011;Lo;0;L;;;;;N;;;;;\n1060B;LINEAR A SIGN AB013;Lo;0;L;;;;;N;;;;;\n1060C;LINEAR A SIGN AB016;Lo;0;L;;;;;N;;;;;\n1060D;LINEAR A SIGN AB017;Lo;0;L;;;;;N;;;;;\n1060E;LINEAR A SIGN AB020;Lo;0;L;;;;;N;;;;;\n1060F;LINEAR A SIGN AB021;Lo;0;L;;;;;N;;;;;\n10610;LINEAR A SIGN AB021F;Lo;0;L;;;;;N;;;;;\n10611;LINEAR A SIGN AB021M;Lo;0;L;;;;;N;;;;;\n10612;LINEAR A SIGN AB022;Lo;0;L;;;;;N;;;;;\n10613;LINEAR A SIGN AB022F;Lo;0;L;;;;;N;;;;;\n10614;LINEAR A SIGN AB022M;Lo;0;L;;;;;N;;;;;\n10615;LINEAR A SIGN AB023;Lo;0;L;;;;;N;;;;;\n10616;LINEAR A SIGN AB023M;Lo;0;L;;;;;N;;;;;\n10617;LINEAR A SIGN AB024;Lo;0;L;;;;;N;;;;;\n10618;LINEAR A SIGN AB026;Lo;0;L;;;;;N;;;;;\n10619;LINEAR A SIGN AB027;Lo;0;L;;;;;N;;;;;\n1061A;LINEAR A SIGN AB028;Lo;0;L;;;;;N;;;;;\n1061B;LINEAR A SIGN A028B;Lo;0;L;;;;;N;;;;;\n1061C;LINEAR A SIGN AB029;Lo;0;L;;;;;N;;;;;\n1061D;LINEAR A SIGN AB030;Lo;0;L;;;;;N;;;;;\n1061E;LINEAR A SIGN AB031;Lo;0;L;;;;;N;;;;;\n1061F;LINEAR A SIGN AB034;Lo;0;L;;;;;N;;;;;\n10620;LINEAR A SIGN AB037;Lo;0;L;;;;;N;;;;;\n10621;LINEAR A SIGN AB038;Lo;0;L;;;;;N;;;;;\n10622;LINEAR A SIGN AB039;Lo;0;L;;;;;N;;;;;\n10623;LINEAR A SIGN AB040;Lo;0;L;;;;;N;;;;;\n10624;LINEAR A SIGN AB041;Lo;0;L;;;;;N;;;;;\n10625;LINEAR A SIGN AB044;Lo;0;L;;;;;N;;;;;\n10626;LINEAR A SIGN AB045;Lo;0;L;;;;;N;;;;;\n10627;LINEAR A SIGN AB046;Lo;0;L;;;;;N;;;;;\n10628;LINEAR A SIGN AB047;Lo;0;L;;;;;N;;;;;\n10629;LINEAR A SIGN AB048;Lo;0;L;;;;;N;;;;;\n1062A;LINEAR A SIGN AB049;Lo;0;L;;;;;N;;;;;\n1062B;LINEAR A SIGN AB050;Lo;0;L;;;;;N;;;;;\n1062C;LINEAR A SIGN AB051;Lo;0;L;;;;;N;;;;;\n1062D;LINEAR A SIGN AB053;Lo;0;L;;;;;N;;;;;\n1062E;LINEAR A SIGN AB054;Lo;0;L;;;;;N;;;;;\n1062F;LINEAR A SIGN AB055;Lo;0;L;;;;;N;;;;;\n10630;LINEAR A SIGN AB056;Lo;0;L;;;;;N;;;;;\n10631;LINEAR A SIGN AB057;Lo;0;L;;;;;N;;;;;\n10632;LINEAR A SIGN AB058;Lo;0;L;;;;;N;;;;;\n10633;LINEAR A SIGN AB059;Lo;0;L;;;;;N;;;;;\n10634;LINEAR A SIGN AB060;Lo;0;L;;;;;N;;;;;\n10635;LINEAR A SIGN AB061;Lo;0;L;;;;;N;;;;;\n10636;LINEAR A SIGN AB065;Lo;0;L;;;;;N;;;;;\n10637;LINEAR A SIGN AB066;Lo;0;L;;;;;N;;;;;\n10638;LINEAR A SIGN AB067;Lo;0;L;;;;;N;;;;;\n10639;LINEAR A SIGN AB069;Lo;0;L;;;;;N;;;;;\n1063A;LINEAR A SIGN AB070;Lo;0;L;;;;;N;;;;;\n1063B;LINEAR A SIGN AB073;Lo;0;L;;;;;N;;;;;\n1063C;LINEAR A SIGN AB074;Lo;0;L;;;;;N;;;;;\n1063D;LINEAR A SIGN AB076;Lo;0;L;;;;;N;;;;;\n1063E;LINEAR A SIGN AB077;Lo;0;L;;;;;N;;;;;\n1063F;LINEAR A SIGN AB078;Lo;0;L;;;;;N;;;;;\n10640;LINEAR A SIGN AB079;Lo;0;L;;;;;N;;;;;\n10641;LINEAR A SIGN AB080;Lo;0;L;;;;;N;;;;;\n10642;LINEAR A SIGN AB081;Lo;0;L;;;;;N;;;;;\n10643;LINEAR A SIGN AB082;Lo;0;L;;;;;N;;;;;\n10644;LINEAR A SIGN AB085;Lo;0;L;;;;;N;;;;;\n10645;LINEAR A SIGN AB086;Lo;0;L;;;;;N;;;;;\n10646;LINEAR A SIGN AB087;Lo;0;L;;;;;N;;;;;\n10647;LINEAR A SIGN A100-102;Lo;0;L;;;;;N;;;;;\n10648;LINEAR A SIGN AB118;Lo;0;L;;;;;N;;;;;\n10649;LINEAR A SIGN AB120;Lo;0;L;;;;;N;;;;;\n1064A;LINEAR A SIGN A120B;Lo;0;L;;;;;N;;;;;\n1064B;LINEAR A SIGN AB122;Lo;0;L;;;;;N;;;;;\n1064C;LINEAR A SIGN AB123;Lo;0;L;;;;;N;;;;;\n1064D;LINEAR A SIGN AB131A;Lo;0;L;;;;;N;;;;;\n1064E;LINEAR A SIGN AB131B;Lo;0;L;;;;;N;;;;;\n1064F;LINEAR A SIGN A131C;Lo;0;L;;;;;N;;;;;\n10650;LINEAR A SIGN AB164;Lo;0;L;;;;;N;;;;;\n10651;LINEAR A SIGN AB171;Lo;0;L;;;;;N;;;;;\n10652;LINEAR A SIGN AB180;Lo;0;L;;;;;N;;;;;\n10653;LINEAR A SIGN AB188;Lo;0;L;;;;;N;;;;;\n10654;LINEAR A SIGN AB191;Lo;0;L;;;;;N;;;;;\n10655;LINEAR A SIGN A301;Lo;0;L;;;;;N;;;;;\n10656;LINEAR A SIGN A302;Lo;0;L;;;;;N;;;;;\n10657;LINEAR A SIGN A303;Lo;0;L;;;;;N;;;;;\n10658;LINEAR A SIGN A304;Lo;0;L;;;;;N;;;;;\n10659;LINEAR A SIGN A305;Lo;0;L;;;;;N;;;;;\n1065A;LINEAR A SIGN A306;Lo;0;L;;;;;N;;;;;\n1065B;LINEAR A SIGN A307;Lo;0;L;;;;;N;;;;;\n1065C;LINEAR A SIGN A308;Lo;0;L;;;;;N;;;;;\n1065D;LINEAR A SIGN A309A;Lo;0;L;;;;;N;;;;;\n1065E;LINEAR A SIGN A309B;Lo;0;L;;;;;N;;;;;\n1065F;LINEAR A SIGN A309C;Lo;0;L;;;;;N;;;;;\n10660;LINEAR A SIGN A310;Lo;0;L;;;;;N;;;;;\n10661;LINEAR A SIGN A311;Lo;0;L;;;;;N;;;;;\n10662;LINEAR A SIGN A312;Lo;0;L;;;;;N;;;;;\n10663;LINEAR A SIGN A313A;Lo;0;L;;;;;N;;;;;\n10664;LINEAR A SIGN A313B;Lo;0;L;;;;;N;;;;;\n10665;LINEAR A SIGN A313C;Lo;0;L;;;;;N;;;;;\n10666;LINEAR A SIGN A314;Lo;0;L;;;;;N;;;;;\n10667;LINEAR A SIGN A315;Lo;0;L;;;;;N;;;;;\n10668;LINEAR A SIGN A316;Lo;0;L;;;;;N;;;;;\n10669;LINEAR A SIGN A317;Lo;0;L;;;;;N;;;;;\n1066A;LINEAR A SIGN A318;Lo;0;L;;;;;N;;;;;\n1066B;LINEAR A SIGN A319;Lo;0;L;;;;;N;;;;;\n1066C;LINEAR A SIGN A320;Lo;0;L;;;;;N;;;;;\n1066D;LINEAR A SIGN A321;Lo;0;L;;;;;N;;;;;\n1066E;LINEAR A SIGN A322;Lo;0;L;;;;;N;;;;;\n1066F;LINEAR A SIGN A323;Lo;0;L;;;;;N;;;;;\n10670;LINEAR A SIGN A324;Lo;0;L;;;;;N;;;;;\n10671;LINEAR A SIGN A325;Lo;0;L;;;;;N;;;;;\n10672;LINEAR A SIGN A326;Lo;0;L;;;;;N;;;;;\n10673;LINEAR A SIGN A327;Lo;0;L;;;;;N;;;;;\n10674;LINEAR A SIGN A328;Lo;0;L;;;;;N;;;;;\n10675;LINEAR A SIGN A329;Lo;0;L;;;;;N;;;;;\n10676;LINEAR A SIGN A330;Lo;0;L;;;;;N;;;;;\n10677;LINEAR A SIGN A331;Lo;0;L;;;;;N;;;;;\n10678;LINEAR A SIGN A332;Lo;0;L;;;;;N;;;;;\n10679;LINEAR A SIGN A333;Lo;0;L;;;;;N;;;;;\n1067A;LINEAR A SIGN A334;Lo;0;L;;;;;N;;;;;\n1067B;LINEAR A SIGN A335;Lo;0;L;;;;;N;;;;;\n1067C;LINEAR A SIGN A336;Lo;0;L;;;;;N;;;;;\n1067D;LINEAR A SIGN A337;Lo;0;L;;;;;N;;;;;\n1067E;LINEAR A SIGN A338;Lo;0;L;;;;;N;;;;;\n1067F;LINEAR A SIGN A339;Lo;0;L;;;;;N;;;;;\n10680;LINEAR A SIGN A340;Lo;0;L;;;;;N;;;;;\n10681;LINEAR A SIGN A341;Lo;0;L;;;;;N;;;;;\n10682;LINEAR A SIGN A342;Lo;0;L;;;;;N;;;;;\n10683;LINEAR A SIGN A343;Lo;0;L;;;;;N;;;;;\n10684;LINEAR A SIGN A344;Lo;0;L;;;;;N;;;;;\n10685;LINEAR A SIGN A345;Lo;0;L;;;;;N;;;;;\n10686;LINEAR A SIGN A346;Lo;0;L;;;;;N;;;;;\n10687;LINEAR A SIGN A347;Lo;0;L;;;;;N;;;;;\n10688;LINEAR A SIGN A348;Lo;0;L;;;;;N;;;;;\n10689;LINEAR A SIGN A349;Lo;0;L;;;;;N;;;;;\n1068A;LINEAR A SIGN A350;Lo;0;L;;;;;N;;;;;\n1068B;LINEAR A SIGN A351;Lo;0;L;;;;;N;;;;;\n1068C;LINEAR A SIGN A352;Lo;0;L;;;;;N;;;;;\n1068D;LINEAR A SIGN A353;Lo;0;L;;;;;N;;;;;\n1068E;LINEAR A SIGN A354;Lo;0;L;;;;;N;;;;;\n1068F;LINEAR A SIGN A355;Lo;0;L;;;;;N;;;;;\n10690;LINEAR A SIGN A356;Lo;0;L;;;;;N;;;;;\n10691;LINEAR A SIGN A357;Lo;0;L;;;;;N;;;;;\n10692;LINEAR A SIGN A358;Lo;0;L;;;;;N;;;;;\n10693;LINEAR A SIGN A359;Lo;0;L;;;;;N;;;;;\n10694;LINEAR A SIGN A360;Lo;0;L;;;;;N;;;;;\n10695;LINEAR A SIGN A361;Lo;0;L;;;;;N;;;;;\n10696;LINEAR A SIGN A362;Lo;0;L;;;;;N;;;;;\n10697;LINEAR A SIGN A363;Lo;0;L;;;;;N;;;;;\n10698;LINEAR A SIGN A364;Lo;0;L;;;;;N;;;;;\n10699;LINEAR A SIGN A365;Lo;0;L;;;;;N;;;;;\n1069A;LINEAR A SIGN A366;Lo;0;L;;;;;N;;;;;\n1069B;LINEAR A SIGN A367;Lo;0;L;;;;;N;;;;;\n1069C;LINEAR A SIGN A368;Lo;0;L;;;;;N;;;;;\n1069D;LINEAR A SIGN A369;Lo;0;L;;;;;N;;;;;\n1069E;LINEAR A SIGN A370;Lo;0;L;;;;;N;;;;;\n1069F;LINEAR A SIGN A371;Lo;0;L;;;;;N;;;;;\n106A0;LINEAR A SIGN A400-VAS;Lo;0;L;;;;;N;;;;;\n106A1;LINEAR A SIGN A401-VAS;Lo;0;L;;;;;N;;;;;\n106A2;LINEAR A SIGN A402-VAS;Lo;0;L;;;;;N;;;;;\n106A3;LINEAR A SIGN A403-VAS;Lo;0;L;;;;;N;;;;;\n106A4;LINEAR A SIGN A404-VAS;Lo;0;L;;;;;N;;;;;\n106A5;LINEAR A SIGN A405-VAS;Lo;0;L;;;;;N;;;;;\n106A6;LINEAR A SIGN A406-VAS;Lo;0;L;;;;;N;;;;;\n106A7;LINEAR A SIGN A407-VAS;Lo;0;L;;;;;N;;;;;\n106A8;LINEAR A SIGN A408-VAS;Lo;0;L;;;;;N;;;;;\n106A9;LINEAR A SIGN A409-VAS;Lo;0;L;;;;;N;;;;;\n106AA;LINEAR A SIGN A410-VAS;Lo;0;L;;;;;N;;;;;\n106AB;LINEAR A SIGN A411-VAS;Lo;0;L;;;;;N;;;;;\n106AC;LINEAR A SIGN A412-VAS;Lo;0;L;;;;;N;;;;;\n106AD;LINEAR A SIGN A413-VAS;Lo;0;L;;;;;N;;;;;\n106AE;LINEAR A SIGN A414-VAS;Lo;0;L;;;;;N;;;;;\n106AF;LINEAR A SIGN A415-VAS;Lo;0;L;;;;;N;;;;;\n106B0;LINEAR A SIGN A416-VAS;Lo;0;L;;;;;N;;;;;\n106B1;LINEAR A SIGN A417-VAS;Lo;0;L;;;;;N;;;;;\n106B2;LINEAR A SIGN A418-VAS;Lo;0;L;;;;;N;;;;;\n106B3;LINEAR A SIGN A501;Lo;0;L;;;;;N;;;;;\n106B4;LINEAR A SIGN A502;Lo;0;L;;;;;N;;;;;\n106B5;LINEAR A SIGN A503;Lo;0;L;;;;;N;;;;;\n106B6;LINEAR A SIGN A504;Lo;0;L;;;;;N;;;;;\n106B7;LINEAR A SIGN A505;Lo;0;L;;;;;N;;;;;\n106B8;LINEAR A SIGN A506;Lo;0;L;;;;;N;;;;;\n106B9;LINEAR A SIGN A508;Lo;0;L;;;;;N;;;;;\n106BA;LINEAR A SIGN A509;Lo;0;L;;;;;N;;;;;\n106BB;LINEAR A SIGN A510;Lo;0;L;;;;;N;;;;;\n106BC;LINEAR A SIGN A511;Lo;0;L;;;;;N;;;;;\n106BD;LINEAR A SIGN A512;Lo;0;L;;;;;N;;;;;\n106BE;LINEAR A SIGN A513;Lo;0;L;;;;;N;;;;;\n106BF;LINEAR A SIGN A515;Lo;0;L;;;;;N;;;;;\n106C0;LINEAR A SIGN A516;Lo;0;L;;;;;N;;;;;\n106C1;LINEAR A SIGN A520;Lo;0;L;;;;;N;;;;;\n106C2;LINEAR A SIGN A521;Lo;0;L;;;;;N;;;;;\n106C3;LINEAR A SIGN A523;Lo;0;L;;;;;N;;;;;\n106C4;LINEAR A SIGN A524;Lo;0;L;;;;;N;;;;;\n106C5;LINEAR A SIGN A525;Lo;0;L;;;;;N;;;;;\n106C6;LINEAR A SIGN A526;Lo;0;L;;;;;N;;;;;\n106C7;LINEAR A SIGN A527;Lo;0;L;;;;;N;;;;;\n106C8;LINEAR A SIGN A528;Lo;0;L;;;;;N;;;;;\n106C9;LINEAR A SIGN A529;Lo;0;L;;;;;N;;;;;\n106CA;LINEAR A SIGN A530;Lo;0;L;;;;;N;;;;;\n106CB;LINEAR A SIGN A531;Lo;0;L;;;;;N;;;;;\n106CC;LINEAR A SIGN A532;Lo;0;L;;;;;N;;;;;\n106CD;LINEAR A SIGN A534;Lo;0;L;;;;;N;;;;;\n106CE;LINEAR A SIGN A535;Lo;0;L;;;;;N;;;;;\n106CF;LINEAR A SIGN A536;Lo;0;L;;;;;N;;;;;\n106D0;LINEAR A SIGN A537;Lo;0;L;;;;;N;;;;;\n106D1;LINEAR A SIGN A538;Lo;0;L;;;;;N;;;;;\n106D2;LINEAR A SIGN A539;Lo;0;L;;;;;N;;;;;\n106D3;LINEAR A SIGN A540;Lo;0;L;;;;;N;;;;;\n106D4;LINEAR A SIGN A541;Lo;0;L;;;;;N;;;;;\n106D5;LINEAR A SIGN A542;Lo;0;L;;;;;N;;;;;\n106D6;LINEAR A SIGN A545;Lo;0;L;;;;;N;;;;;\n106D7;LINEAR A SIGN A547;Lo;0;L;;;;;N;;;;;\n106D8;LINEAR A SIGN A548;Lo;0;L;;;;;N;;;;;\n106D9;LINEAR A SIGN A549;Lo;0;L;;;;;N;;;;;\n106DA;LINEAR A SIGN A550;Lo;0;L;;;;;N;;;;;\n106DB;LINEAR A SIGN A551;Lo;0;L;;;;;N;;;;;\n106DC;LINEAR A SIGN A552;Lo;0;L;;;;;N;;;;;\n106DD;LINEAR A SIGN A553;Lo;0;L;;;;;N;;;;;\n106DE;LINEAR A SIGN A554;Lo;0;L;;;;;N;;;;;\n106DF;LINEAR A SIGN A555;Lo;0;L;;;;;N;;;;;\n106E0;LINEAR A SIGN A556;Lo;0;L;;;;;N;;;;;\n106E1;LINEAR A SIGN A557;Lo;0;L;;;;;N;;;;;\n106E2;LINEAR A SIGN A559;Lo;0;L;;;;;N;;;;;\n106E3;LINEAR A SIGN A563;Lo;0;L;;;;;N;;;;;\n106E4;LINEAR A SIGN A564;Lo;0;L;;;;;N;;;;;\n106E5;LINEAR A SIGN A565;Lo;0;L;;;;;N;;;;;\n106E6;LINEAR A SIGN A566;Lo;0;L;;;;;N;;;;;\n106E7;LINEAR A SIGN A568;Lo;0;L;;;;;N;;;;;\n106E8;LINEAR A SIGN A569;Lo;0;L;;;;;N;;;;;\n106E9;LINEAR A SIGN A570;Lo;0;L;;;;;N;;;;;\n106EA;LINEAR A SIGN A571;Lo;0;L;;;;;N;;;;;\n106EB;LINEAR A SIGN A572;Lo;0;L;;;;;N;;;;;\n106EC;LINEAR A SIGN A573;Lo;0;L;;;;;N;;;;;\n106ED;LINEAR A SIGN A574;Lo;0;L;;;;;N;;;;;\n106EE;LINEAR A SIGN A575;Lo;0;L;;;;;N;;;;;\n106EF;LINEAR A SIGN A576;Lo;0;L;;;;;N;;;;;\n106F0;LINEAR A SIGN A577;Lo;0;L;;;;;N;;;;;\n106F1;LINEAR A SIGN A578;Lo;0;L;;;;;N;;;;;\n106F2;LINEAR A SIGN A579;Lo;0;L;;;;;N;;;;;\n106F3;LINEAR A SIGN A580;Lo;0;L;;;;;N;;;;;\n106F4;LINEAR A SIGN A581;Lo;0;L;;;;;N;;;;;\n106F5;LINEAR A SIGN A582;Lo;0;L;;;;;N;;;;;\n106F6;LINEAR A SIGN A583;Lo;0;L;;;;;N;;;;;\n106F7;LINEAR A SIGN A584;Lo;0;L;;;;;N;;;;;\n106F8;LINEAR A SIGN A585;Lo;0;L;;;;;N;;;;;\n106F9;LINEAR A SIGN A586;Lo;0;L;;;;;N;;;;;\n106FA;LINEAR A SIGN A587;Lo;0;L;;;;;N;;;;;\n106FB;LINEAR A SIGN A588;Lo;0;L;;;;;N;;;;;\n106FC;LINEAR A SIGN A589;Lo;0;L;;;;;N;;;;;\n106FD;LINEAR A SIGN A591;Lo;0;L;;;;;N;;;;;\n106FE;LINEAR A SIGN A592;Lo;0;L;;;;;N;;;;;\n106FF;LINEAR A SIGN A594;Lo;0;L;;;;;N;;;;;\n10700;LINEAR A SIGN A595;Lo;0;L;;;;;N;;;;;\n10701;LINEAR A SIGN A596;Lo;0;L;;;;;N;;;;;\n10702;LINEAR A SIGN A598;Lo;0;L;;;;;N;;;;;\n10703;LINEAR A SIGN A600;Lo;0;L;;;;;N;;;;;\n10704;LINEAR A SIGN A601;Lo;0;L;;;;;N;;;;;\n10705;LINEAR A SIGN A602;Lo;0;L;;;;;N;;;;;\n10706;LINEAR A SIGN A603;Lo;0;L;;;;;N;;;;;\n10707;LINEAR A SIGN A604;Lo;0;L;;;;;N;;;;;\n10708;LINEAR A SIGN A606;Lo;0;L;;;;;N;;;;;\n10709;LINEAR A SIGN A608;Lo;0;L;;;;;N;;;;;\n1070A;LINEAR A SIGN A609;Lo;0;L;;;;;N;;;;;\n1070B;LINEAR A SIGN A610;Lo;0;L;;;;;N;;;;;\n1070C;LINEAR A SIGN A611;Lo;0;L;;;;;N;;;;;\n1070D;LINEAR A SIGN A612;Lo;0;L;;;;;N;;;;;\n1070E;LINEAR A SIGN A613;Lo;0;L;;;;;N;;;;;\n1070F;LINEAR A SIGN A614;Lo;0;L;;;;;N;;;;;\n10710;LINEAR A SIGN A615;Lo;0;L;;;;;N;;;;;\n10711;LINEAR A SIGN A616;Lo;0;L;;;;;N;;;;;\n10712;LINEAR A SIGN A617;Lo;0;L;;;;;N;;;;;\n10713;LINEAR A SIGN A618;Lo;0;L;;;;;N;;;;;\n10714;LINEAR A SIGN A619;Lo;0;L;;;;;N;;;;;\n10715;LINEAR A SIGN A620;Lo;0;L;;;;;N;;;;;\n10716;LINEAR A SIGN A621;Lo;0;L;;;;;N;;;;;\n10717;LINEAR A SIGN A622;Lo;0;L;;;;;N;;;;;\n10718;LINEAR A SIGN A623;Lo;0;L;;;;;N;;;;;\n10719;LINEAR A SIGN A624;Lo;0;L;;;;;N;;;;;\n1071A;LINEAR A SIGN A626;Lo;0;L;;;;;N;;;;;\n1071B;LINEAR A SIGN A627;Lo;0;L;;;;;N;;;;;\n1071C;LINEAR A SIGN A628;Lo;0;L;;;;;N;;;;;\n1071D;LINEAR A SIGN A629;Lo;0;L;;;;;N;;;;;\n1071E;LINEAR A SIGN A634;Lo;0;L;;;;;N;;;;;\n1071F;LINEAR A SIGN A637;Lo;0;L;;;;;N;;;;;\n10720;LINEAR A SIGN A638;Lo;0;L;;;;;N;;;;;\n10721;LINEAR A SIGN A640;Lo;0;L;;;;;N;;;;;\n10722;LINEAR A SIGN A642;Lo;0;L;;;;;N;;;;;\n10723;LINEAR A SIGN A643;Lo;0;L;;;;;N;;;;;\n10724;LINEAR A SIGN A644;Lo;0;L;;;;;N;;;;;\n10725;LINEAR A SIGN A645;Lo;0;L;;;;;N;;;;;\n10726;LINEAR A SIGN A646;Lo;0;L;;;;;N;;;;;\n10727;LINEAR A SIGN A648;Lo;0;L;;;;;N;;;;;\n10728;LINEAR A SIGN A649;Lo;0;L;;;;;N;;;;;\n10729;LINEAR A SIGN A651;Lo;0;L;;;;;N;;;;;\n1072A;LINEAR A SIGN A652;Lo;0;L;;;;;N;;;;;\n1072B;LINEAR A SIGN A653;Lo;0;L;;;;;N;;;;;\n1072C;LINEAR A SIGN A654;Lo;0;L;;;;;N;;;;;\n1072D;LINEAR A SIGN A655;Lo;0;L;;;;;N;;;;;\n1072E;LINEAR A SIGN A656;Lo;0;L;;;;;N;;;;;\n1072F;LINEAR A SIGN A657;Lo;0;L;;;;;N;;;;;\n10730;LINEAR A SIGN A658;Lo;0;L;;;;;N;;;;;\n10731;LINEAR A SIGN A659;Lo;0;L;;;;;N;;;;;\n10732;LINEAR A SIGN A660;Lo;0;L;;;;;N;;;;;\n10733;LINEAR A SIGN A661;Lo;0;L;;;;;N;;;;;\n10734;LINEAR A SIGN A662;Lo;0;L;;;;;N;;;;;\n10735;LINEAR A SIGN A663;Lo;0;L;;;;;N;;;;;\n10736;LINEAR A SIGN A664;Lo;0;L;;;;;N;;;;;\n10740;LINEAR A SIGN A701 A;Lo;0;L;;;;;N;;;;;\n10741;LINEAR A SIGN A702 B;Lo;0;L;;;;;N;;;;;\n10742;LINEAR A SIGN A703 D;Lo;0;L;;;;;N;;;;;\n10743;LINEAR A SIGN A704 E;Lo;0;L;;;;;N;;;;;\n10744;LINEAR A SIGN A705 F;Lo;0;L;;;;;N;;;;;\n10745;LINEAR A SIGN A706 H;Lo;0;L;;;;;N;;;;;\n10746;LINEAR A SIGN A707 J;Lo;0;L;;;;;N;;;;;\n10747;LINEAR A SIGN A708 K;Lo;0;L;;;;;N;;;;;\n10748;LINEAR A SIGN A709 L;Lo;0;L;;;;;N;;;;;\n10749;LINEAR A SIGN A709-2 L2;Lo;0;L;;;;;N;;;;;\n1074A;LINEAR A SIGN A709-3 L3;Lo;0;L;;;;;N;;;;;\n1074B;LINEAR A SIGN A709-4 L4;Lo;0;L;;;;;N;;;;;\n1074C;LINEAR A SIGN A709-6 L6;Lo;0;L;;;;;N;;;;;\n1074D;LINEAR A SIGN A710 W;Lo;0;L;;;;;N;;;;;\n1074E;LINEAR A SIGN A711 X;Lo;0;L;;;;;N;;;;;\n1074F;LINEAR A SIGN A712 Y;Lo;0;L;;;;;N;;;;;\n10750;LINEAR A SIGN A713 OMEGA;Lo;0;L;;;;;N;;;;;\n10751;LINEAR A SIGN A714 ABB;Lo;0;L;;;;;N;;;;;\n10752;LINEAR A SIGN A715 BB;Lo;0;L;;;;;N;;;;;\n10753;LINEAR A SIGN A717 DD;Lo;0;L;;;;;N;;;;;\n10754;LINEAR A SIGN A726 EYYY;Lo;0;L;;;;;N;;;;;\n10755;LINEAR A SIGN A732 JE;Lo;0;L;;;;;N;;;;;\n10760;LINEAR A SIGN A800;Lo;0;L;;;;;N;;;;;\n10761;LINEAR A SIGN A801;Lo;0;L;;;;;N;;;;;\n10762;LINEAR A SIGN A802;Lo;0;L;;;;;N;;;;;\n10763;LINEAR A SIGN A803;Lo;0;L;;;;;N;;;;;\n10764;LINEAR A SIGN A804;Lo;0;L;;;;;N;;;;;\n10765;LINEAR A SIGN A805;Lo;0;L;;;;;N;;;;;\n10766;LINEAR A SIGN A806;Lo;0;L;;;;;N;;;;;\n10767;LINEAR A SIGN A807;Lo;0;L;;;;;N;;;;;\n10780;MODIFIER LETTER SMALL CAPITAL AA;Lm;0;L;;;;;N;;;;;\n10781;MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON;Lm;0;L;<super> 02D0;;;;N;;;;;\n10782;MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON;Lm;0;L;<super> 02D1;;;;N;;;;;\n10783;MODIFIER LETTER SMALL AE;Lm;0;L;<super> 00E6;;;;N;;;;;\n10784;MODIFIER LETTER SMALL CAPITAL B;Lm;0;L;<super> 0299;;;;N;;;;;\n10785;MODIFIER LETTER SMALL B WITH HOOK;Lm;0;L;<super> 0253;;;;N;;;;;\n10787;MODIFIER LETTER SMALL DZ DIGRAPH;Lm;0;L;<super> 02A3;;;;N;;;;;\n10788;MODIFIER LETTER SMALL DZ DIGRAPH WITH RETROFLEX HOOK;Lm;0;L;<super> AB66;;;;N;;;;;\n10789;MODIFIER LETTER SMALL DZ DIGRAPH WITH CURL;Lm;0;L;<super> 02A5;;;;N;;;;;\n1078A;MODIFIER LETTER SMALL DEZH DIGRAPH;Lm;0;L;<super> 02A4;;;;N;;;;;\n1078B;MODIFIER LETTER SMALL D WITH TAIL;Lm;0;L;<super> 0256;;;;N;;;;;\n1078C;MODIFIER LETTER SMALL D WITH HOOK;Lm;0;L;<super> 0257;;;;N;;;;;\n1078D;MODIFIER LETTER SMALL D WITH HOOK AND TAIL;Lm;0;L;<super> 1D91;;;;N;;;;;\n1078E;MODIFIER LETTER SMALL REVERSED E;Lm;0;L;<super> 0258;;;;N;;;;;\n1078F;MODIFIER LETTER SMALL CLOSED REVERSED OPEN E;Lm;0;L;<super> 025E;;;;N;;;;;\n10790;MODIFIER LETTER SMALL FENG DIGRAPH;Lm;0;L;<super> 02A9;;;;N;;;;;\n10791;MODIFIER LETTER SMALL RAMS HORN;Lm;0;L;<super> 0264;;;;N;;;;;\n10792;MODIFIER LETTER SMALL CAPITAL G;Lm;0;L;<super> 0262;;;;N;;;;;\n10793;MODIFIER LETTER SMALL G WITH HOOK;Lm;0;L;<super> 0260;;;;N;;;;;\n10794;MODIFIER LETTER SMALL CAPITAL G WITH HOOK;Lm;0;L;<super> 029B;;;;N;;;;;\n10795;MODIFIER LETTER SMALL H WITH STROKE;Lm;0;L;<super> 0127;;;;N;;;;;\n10796;MODIFIER LETTER SMALL CAPITAL H;Lm;0;L;<super> 029C;;;;N;;;;;\n10797;MODIFIER LETTER SMALL HENG WITH HOOK;Lm;0;L;<super> 0267;;;;N;;;;;\n10798;MODIFIER LETTER SMALL DOTLESS J WITH STROKE AND HOOK;Lm;0;L;<super> 0284;;;;N;;;;;\n10799;MODIFIER LETTER SMALL LS DIGRAPH;Lm;0;L;<super> 02AA;;;;N;;;;;\n1079A;MODIFIER LETTER SMALL LZ DIGRAPH;Lm;0;L;<super> 02AB;;;;N;;;;;\n1079B;MODIFIER LETTER SMALL L WITH BELT;Lm;0;L;<super> 026C;;;;N;;;;;\n1079C;MODIFIER LETTER SMALL CAPITAL L WITH BELT;Lm;0;L;<super> 1DF04;;;;N;;;;;\n1079D;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK AND BELT;Lm;0;L;<super> A78E;;;;N;;;;;\n1079E;MODIFIER LETTER SMALL LEZH;Lm;0;L;<super> 026E;;;;N;;;;;\n1079F;MODIFIER LETTER SMALL LEZH WITH RETROFLEX HOOK;Lm;0;L;<super> 1DF05;;;;N;;;;;\n107A0;MODIFIER LETTER SMALL TURNED Y;Lm;0;L;<super> 028E;;;;N;;;;;\n107A1;MODIFIER LETTER SMALL TURNED Y WITH BELT;Lm;0;L;<super> 1DF06;;;;N;;;;;\n107A2;MODIFIER LETTER SMALL O WITH STROKE;Lm;0;L;<super> 00F8;;;;N;;;;;\n107A3;MODIFIER LETTER SMALL CAPITAL OE;Lm;0;L;<super> 0276;;;;N;;;;;\n107A4;MODIFIER LETTER SMALL CLOSED OMEGA;Lm;0;L;<super> 0277;;;;N;;;;;\n107A5;MODIFIER LETTER SMALL Q;Lm;0;L;<super> 0071;;;;N;;;;;\n107A6;MODIFIER LETTER SMALL TURNED R WITH LONG LEG;Lm;0;L;<super> 027A;;;;N;;;;;\n107A7;MODIFIER LETTER SMALL TURNED R WITH LONG LEG AND RETROFLEX HOOK;Lm;0;L;<super> 1DF08;;;;N;;;;;\n107A8;MODIFIER LETTER SMALL R WITH TAIL;Lm;0;L;<super> 027D;;;;N;;;;;\n107A9;MODIFIER LETTER SMALL R WITH FISHHOOK;Lm;0;L;<super> 027E;;;;N;;;;;\n107AA;MODIFIER LETTER SMALL CAPITAL R;Lm;0;L;<super> 0280;;;;N;;;;;\n107AB;MODIFIER LETTER SMALL TC DIGRAPH WITH CURL;Lm;0;L;<super> 02A8;;;;N;;;;;\n107AC;MODIFIER LETTER SMALL TS DIGRAPH;Lm;0;L;<super> 02A6;;;;N;;;;;\n107AD;MODIFIER LETTER SMALL TS DIGRAPH WITH RETROFLEX HOOK;Lm;0;L;<super> AB67;;;;N;;;;;\n107AE;MODIFIER LETTER SMALL TESH DIGRAPH;Lm;0;L;<super> 02A7;;;;N;;;;;\n107AF;MODIFIER LETTER SMALL T WITH RETROFLEX HOOK;Lm;0;L;<super> 0288;;;;N;;;;;\n107B0;MODIFIER LETTER SMALL V WITH RIGHT HOOK;Lm;0;L;<super> 2C71;;;;N;;;;;\n107B2;MODIFIER LETTER SMALL CAPITAL Y;Lm;0;L;<super> 028F;;;;N;;;;;\n107B3;MODIFIER LETTER GLOTTAL STOP WITH STROKE;Lm;0;L;<super> 02A1;;;;N;;;;;\n107B4;MODIFIER LETTER REVERSED GLOTTAL STOP WITH STROKE;Lm;0;L;<super> 02A2;;;;N;;;;;\n107B5;MODIFIER LETTER BILABIAL CLICK;Lm;0;L;<super> 0298;;;;N;;;;;\n107B6;MODIFIER LETTER DENTAL CLICK;Lm;0;L;<super> 01C0;;;;N;;;;;\n107B7;MODIFIER LETTER LATERAL CLICK;Lm;0;L;<super> 01C1;;;;N;;;;;\n107B8;MODIFIER LETTER ALVEOLAR CLICK;Lm;0;L;<super> 01C2;;;;N;;;;;\n107B9;MODIFIER LETTER RETROFLEX CLICK WITH RETROFLEX HOOK;Lm;0;L;<super> 1DF0A;;;;N;;;;;\n107BA;MODIFIER LETTER SMALL S WITH CURL;Lm;0;L;<super> 1DF1E;;;;N;;;;;\n10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;;\n10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;;\n10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;;\n10803;CYPRIOT SYLLABLE O;Lo;0;R;;;;;N;;;;;\n10804;CYPRIOT SYLLABLE U;Lo;0;R;;;;;N;;;;;\n10805;CYPRIOT SYLLABLE JA;Lo;0;R;;;;;N;;;;;\n10808;CYPRIOT SYLLABLE JO;Lo;0;R;;;;;N;;;;;\n1080A;CYPRIOT SYLLABLE KA;Lo;0;R;;;;;N;;;;;\n1080B;CYPRIOT SYLLABLE KE;Lo;0;R;;;;;N;;;;;\n1080C;CYPRIOT SYLLABLE KI;Lo;0;R;;;;;N;;;;;\n1080D;CYPRIOT SYLLABLE KO;Lo;0;R;;;;;N;;;;;\n1080E;CYPRIOT SYLLABLE KU;Lo;0;R;;;;;N;;;;;\n1080F;CYPRIOT SYLLABLE LA;Lo;0;R;;;;;N;;;;;\n10810;CYPRIOT SYLLABLE LE;Lo;0;R;;;;;N;;;;;\n10811;CYPRIOT SYLLABLE LI;Lo;0;R;;;;;N;;;;;\n10812;CYPRIOT SYLLABLE LO;Lo;0;R;;;;;N;;;;;\n10813;CYPRIOT SYLLABLE LU;Lo;0;R;;;;;N;;;;;\n10814;CYPRIOT SYLLABLE MA;Lo;0;R;;;;;N;;;;;\n10815;CYPRIOT SYLLABLE ME;Lo;0;R;;;;;N;;;;;\n10816;CYPRIOT SYLLABLE MI;Lo;0;R;;;;;N;;;;;\n10817;CYPRIOT SYLLABLE MO;Lo;0;R;;;;;N;;;;;\n10818;CYPRIOT SYLLABLE MU;Lo;0;R;;;;;N;;;;;\n10819;CYPRIOT SYLLABLE NA;Lo;0;R;;;;;N;;;;;\n1081A;CYPRIOT SYLLABLE NE;Lo;0;R;;;;;N;;;;;\n1081B;CYPRIOT SYLLABLE NI;Lo;0;R;;;;;N;;;;;\n1081C;CYPRIOT SYLLABLE NO;Lo;0;R;;;;;N;;;;;\n1081D;CYPRIOT SYLLABLE NU;Lo;0;R;;;;;N;;;;;\n1081E;CYPRIOT SYLLABLE PA;Lo;0;R;;;;;N;;;;;\n1081F;CYPRIOT SYLLABLE PE;Lo;0;R;;;;;N;;;;;\n10820;CYPRIOT SYLLABLE PI;Lo;0;R;;;;;N;;;;;\n10821;CYPRIOT SYLLABLE PO;Lo;0;R;;;;;N;;;;;\n10822;CYPRIOT SYLLABLE PU;Lo;0;R;;;;;N;;;;;\n10823;CYPRIOT SYLLABLE RA;Lo;0;R;;;;;N;;;;;\n10824;CYPRIOT SYLLABLE RE;Lo;0;R;;;;;N;;;;;\n10825;CYPRIOT SYLLABLE RI;Lo;0;R;;;;;N;;;;;\n10826;CYPRIOT SYLLABLE RO;Lo;0;R;;;;;N;;;;;\n10827;CYPRIOT SYLLABLE RU;Lo;0;R;;;;;N;;;;;\n10828;CYPRIOT SYLLABLE SA;Lo;0;R;;;;;N;;;;;\n10829;CYPRIOT SYLLABLE SE;Lo;0;R;;;;;N;;;;;\n1082A;CYPRIOT SYLLABLE SI;Lo;0;R;;;;;N;;;;;\n1082B;CYPRIOT SYLLABLE SO;Lo;0;R;;;;;N;;;;;\n1082C;CYPRIOT SYLLABLE SU;Lo;0;R;;;;;N;;;;;\n1082D;CYPRIOT SYLLABLE TA;Lo;0;R;;;;;N;;;;;\n1082E;CYPRIOT SYLLABLE TE;Lo;0;R;;;;;N;;;;;\n1082F;CYPRIOT SYLLABLE TI;Lo;0;R;;;;;N;;;;;\n10830;CYPRIOT SYLLABLE TO;Lo;0;R;;;;;N;;;;;\n10831;CYPRIOT SYLLABLE TU;Lo;0;R;;;;;N;;;;;\n10832;CYPRIOT SYLLABLE WA;Lo;0;R;;;;;N;;;;;\n10833;CYPRIOT SYLLABLE WE;Lo;0;R;;;;;N;;;;;\n10834;CYPRIOT SYLLABLE WI;Lo;0;R;;;;;N;;;;;\n10835;CYPRIOT SYLLABLE WO;Lo;0;R;;;;;N;;;;;\n10837;CYPRIOT SYLLABLE XA;Lo;0;R;;;;;N;;;;;\n10838;CYPRIOT SYLLABLE XE;Lo;0;R;;;;;N;;;;;\n1083C;CYPRIOT SYLLABLE ZA;Lo;0;R;;;;;N;;;;;\n1083F;CYPRIOT SYLLABLE ZO;Lo;0;R;;;;;N;;;;;\n10840;IMPERIAL ARAMAIC LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10841;IMPERIAL ARAMAIC LETTER BETH;Lo;0;R;;;;;N;;;;;\n10842;IMPERIAL ARAMAIC LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10843;IMPERIAL ARAMAIC LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10844;IMPERIAL ARAMAIC LETTER HE;Lo;0;R;;;;;N;;;;;\n10845;IMPERIAL ARAMAIC LETTER WAW;Lo;0;R;;;;;N;;;;;\n10846;IMPERIAL ARAMAIC LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10847;IMPERIAL ARAMAIC LETTER HETH;Lo;0;R;;;;;N;;;;;\n10848;IMPERIAL ARAMAIC LETTER TETH;Lo;0;R;;;;;N;;;;;\n10849;IMPERIAL ARAMAIC LETTER YODH;Lo;0;R;;;;;N;;;;;\n1084A;IMPERIAL ARAMAIC LETTER KAPH;Lo;0;R;;;;;N;;;;;\n1084B;IMPERIAL ARAMAIC LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n1084C;IMPERIAL ARAMAIC LETTER MEM;Lo;0;R;;;;;N;;;;;\n1084D;IMPERIAL ARAMAIC LETTER NUN;Lo;0;R;;;;;N;;;;;\n1084E;IMPERIAL ARAMAIC LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n1084F;IMPERIAL ARAMAIC LETTER AYIN;Lo;0;R;;;;;N;;;;;\n10850;IMPERIAL ARAMAIC LETTER PE;Lo;0;R;;;;;N;;;;;\n10851;IMPERIAL ARAMAIC LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10852;IMPERIAL ARAMAIC LETTER QOPH;Lo;0;R;;;;;N;;;;;\n10853;IMPERIAL ARAMAIC LETTER RESH;Lo;0;R;;;;;N;;;;;\n10854;IMPERIAL ARAMAIC LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10855;IMPERIAL ARAMAIC LETTER TAW;Lo;0;R;;;;;N;;;;;\n10857;IMPERIAL ARAMAIC SECTION SIGN;Po;0;R;;;;;N;;;;;\n10858;IMPERIAL ARAMAIC NUMBER ONE;No;0;R;;;;1;N;;;;;\n10859;IMPERIAL ARAMAIC NUMBER TWO;No;0;R;;;;2;N;;;;;\n1085A;IMPERIAL ARAMAIC NUMBER THREE;No;0;R;;;;3;N;;;;;\n1085B;IMPERIAL ARAMAIC NUMBER TEN;No;0;R;;;;10;N;;;;;\n1085C;IMPERIAL ARAMAIC NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n1085D;IMPERIAL ARAMAIC NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n1085E;IMPERIAL ARAMAIC NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;\n1085F;IMPERIAL ARAMAIC NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;;\n10860;PALMYRENE LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10861;PALMYRENE LETTER BETH;Lo;0;R;;;;;N;;;;;\n10862;PALMYRENE LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10863;PALMYRENE LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10864;PALMYRENE LETTER HE;Lo;0;R;;;;;N;;;;;\n10865;PALMYRENE LETTER WAW;Lo;0;R;;;;;N;;;;;\n10866;PALMYRENE LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10867;PALMYRENE LETTER HETH;Lo;0;R;;;;;N;;;;;\n10868;PALMYRENE LETTER TETH;Lo;0;R;;;;;N;;;;;\n10869;PALMYRENE LETTER YODH;Lo;0;R;;;;;N;;;;;\n1086A;PALMYRENE LETTER KAPH;Lo;0;R;;;;;N;;;;;\n1086B;PALMYRENE LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n1086C;PALMYRENE LETTER MEM;Lo;0;R;;;;;N;;;;;\n1086D;PALMYRENE LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;\n1086E;PALMYRENE LETTER NUN;Lo;0;R;;;;;N;;;;;\n1086F;PALMYRENE LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10870;PALMYRENE LETTER AYIN;Lo;0;R;;;;;N;;;;;\n10871;PALMYRENE LETTER PE;Lo;0;R;;;;;N;;;;;\n10872;PALMYRENE LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10873;PALMYRENE LETTER QOPH;Lo;0;R;;;;;N;;;;;\n10874;PALMYRENE LETTER RESH;Lo;0;R;;;;;N;;;;;\n10875;PALMYRENE LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10876;PALMYRENE LETTER TAW;Lo;0;R;;;;;N;;;;;\n10877;PALMYRENE LEFT-POINTING FLEURON;So;0;R;;;;;N;;;;;\n10878;PALMYRENE RIGHT-POINTING FLEURON;So;0;R;;;;;N;;;;;\n10879;PALMYRENE NUMBER ONE;No;0;R;;;;1;N;;;;;\n1087A;PALMYRENE NUMBER TWO;No;0;R;;;;2;N;;;;;\n1087B;PALMYRENE NUMBER THREE;No;0;R;;;;3;N;;;;;\n1087C;PALMYRENE NUMBER FOUR;No;0;R;;;;4;N;;;;;\n1087D;PALMYRENE NUMBER FIVE;No;0;R;;;;5;N;;;;;\n1087E;PALMYRENE NUMBER TEN;No;0;R;;;;10;N;;;;;\n1087F;PALMYRENE NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10880;NABATAEAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;;\n10881;NABATAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10882;NABATAEAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;;\n10883;NABATAEAN LETTER BETH;Lo;0;R;;;;;N;;;;;\n10884;NABATAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10885;NABATAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10886;NABATAEAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;;\n10887;NABATAEAN LETTER HE;Lo;0;R;;;;;N;;;;;\n10888;NABATAEAN LETTER WAW;Lo;0;R;;;;;N;;;;;\n10889;NABATAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n1088A;NABATAEAN LETTER HETH;Lo;0;R;;;;;N;;;;;\n1088B;NABATAEAN LETTER TETH;Lo;0;R;;;;;N;;;;;\n1088C;NABATAEAN LETTER FINAL YODH;Lo;0;R;;;;;N;;;;;\n1088D;NABATAEAN LETTER YODH;Lo;0;R;;;;;N;;;;;\n1088E;NABATAEAN LETTER FINAL KAPH;Lo;0;R;;;;;N;;;;;\n1088F;NABATAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10890;NABATAEAN LETTER FINAL LAMEDH;Lo;0;R;;;;;N;;;;;\n10891;NABATAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10892;NABATAEAN LETTER FINAL MEM;Lo;0;R;;;;;N;;;;;\n10893;NABATAEAN LETTER MEM;Lo;0;R;;;;;N;;;;;\n10894;NABATAEAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;\n10895;NABATAEAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n10896;NABATAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10897;NABATAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;;\n10898;NABATAEAN LETTER PE;Lo;0;R;;;;;N;;;;;\n10899;NABATAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;;\n1089A;NABATAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;;\n1089B;NABATAEAN LETTER RESH;Lo;0;R;;;;;N;;;;;\n1089C;NABATAEAN LETTER FINAL SHIN;Lo;0;R;;;;;N;;;;;\n1089D;NABATAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;;\n1089E;NABATAEAN LETTER TAW;Lo;0;R;;;;;N;;;;;\n108A7;NABATAEAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n108A8;NABATAEAN NUMBER TWO;No;0;R;;;;2;N;;;;;\n108A9;NABATAEAN NUMBER THREE;No;0;R;;;;3;N;;;;;\n108AA;NABATAEAN NUMBER FOUR;No;0;R;;;;4;N;;;;;\n108AB;NABATAEAN CRUCIFORM NUMBER FOUR;No;0;R;;;;4;N;;;;;\n108AC;NABATAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;;\n108AD;NABATAEAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n108AE;NABATAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n108AF;NABATAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n108E0;HATRAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n108E1;HATRAN LETTER BETH;Lo;0;R;;;;;N;;;;;\n108E2;HATRAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n108E3;HATRAN LETTER DALETH-RESH;Lo;0;R;;;;;N;;;;;\n108E4;HATRAN LETTER HE;Lo;0;R;;;;;N;;;;;\n108E5;HATRAN LETTER WAW;Lo;0;R;;;;;N;;;;;\n108E6;HATRAN LETTER ZAYN;Lo;0;R;;;;;N;;;;;\n108E7;HATRAN LETTER HETH;Lo;0;R;;;;;N;;;;;\n108E8;HATRAN LETTER TETH;Lo;0;R;;;;;N;;;;;\n108E9;HATRAN LETTER YODH;Lo;0;R;;;;;N;;;;;\n108EA;HATRAN LETTER KAPH;Lo;0;R;;;;;N;;;;;\n108EB;HATRAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n108EC;HATRAN LETTER MEM;Lo;0;R;;;;;N;;;;;\n108ED;HATRAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n108EE;HATRAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n108EF;HATRAN LETTER AYN;Lo;0;R;;;;;N;;;;;\n108F0;HATRAN LETTER PE;Lo;0;R;;;;;N;;;;;\n108F1;HATRAN LETTER SADHE;Lo;0;R;;;;;N;;;;;\n108F2;HATRAN LETTER QOPH;Lo;0;R;;;;;N;;;;;\n108F4;HATRAN LETTER SHIN;Lo;0;R;;;;;N;;;;;\n108F5;HATRAN LETTER TAW;Lo;0;R;;;;;N;;;;;\n108FB;HATRAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n108FC;HATRAN NUMBER FIVE;No;0;R;;;;5;N;;;;;\n108FD;HATRAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n108FE;HATRAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n108FF;HATRAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10900;PHOENICIAN LETTER ALF;Lo;0;R;;;;;N;;;;;\n10901;PHOENICIAN LETTER BET;Lo;0;R;;;;;N;;;;;\n10902;PHOENICIAN LETTER GAML;Lo;0;R;;;;;N;;;;;\n10903;PHOENICIAN LETTER DELT;Lo;0;R;;;;;N;;;;;\n10904;PHOENICIAN LETTER HE;Lo;0;R;;;;;N;;;;;\n10905;PHOENICIAN LETTER WAU;Lo;0;R;;;;;N;;;;;\n10906;PHOENICIAN LETTER ZAI;Lo;0;R;;;;;N;;;;;\n10907;PHOENICIAN LETTER HET;Lo;0;R;;;;;N;;;;;\n10908;PHOENICIAN LETTER TET;Lo;0;R;;;;;N;;;;;\n10909;PHOENICIAN LETTER YOD;Lo;0;R;;;;;N;;;;;\n1090A;PHOENICIAN LETTER KAF;Lo;0;R;;;;;N;;;;;\n1090B;PHOENICIAN LETTER LAMD;Lo;0;R;;;;;N;;;;;\n1090C;PHOENICIAN LETTER MEM;Lo;0;R;;;;;N;;;;;\n1090D;PHOENICIAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n1090E;PHOENICIAN LETTER SEMK;Lo;0;R;;;;;N;;;;;\n1090F;PHOENICIAN LETTER AIN;Lo;0;R;;;;;N;;;;;\n10910;PHOENICIAN LETTER PE;Lo;0;R;;;;;N;;;;;\n10911;PHOENICIAN LETTER SADE;Lo;0;R;;;;;N;;;;;\n10912;PHOENICIAN LETTER QOF;Lo;0;R;;;;;N;;;;;\n10913;PHOENICIAN LETTER ROSH;Lo;0;R;;;;;N;;;;;\n10914;PHOENICIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10915;PHOENICIAN LETTER TAU;Lo;0;R;;;;;N;;;;;\n10916;PHOENICIAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n10917;PHOENICIAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n10918;PHOENICIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10919;PHOENICIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n1091A;PHOENICIAN NUMBER TWO;No;0;R;;;;2;N;;;;;\n1091B;PHOENICIAN NUMBER THREE;No;0;R;;;;3;N;;;;;\n1091F;PHOENICIAN WORD SEPARATOR;Po;0;ON;;;;;N;;;;;\n10920;LYDIAN LETTER A;Lo;0;R;;;;;N;;;;;\n10921;LYDIAN LETTER B;Lo;0;R;;;;;N;;;;;\n10922;LYDIAN LETTER G;Lo;0;R;;;;;N;;;;;\n10923;LYDIAN LETTER D;Lo;0;R;;;;;N;;;;;\n10924;LYDIAN LETTER E;Lo;0;R;;;;;N;;;;;\n10925;LYDIAN LETTER V;Lo;0;R;;;;;N;;;;;\n10926;LYDIAN LETTER I;Lo;0;R;;;;;N;;;;;\n10927;LYDIAN LETTER Y;Lo;0;R;;;;;N;;;;;\n10928;LYDIAN LETTER K;Lo;0;R;;;;;N;;;;;\n10929;LYDIAN LETTER L;Lo;0;R;;;;;N;;;;;\n1092A;LYDIAN LETTER M;Lo;0;R;;;;;N;;;;;\n1092B;LYDIAN LETTER N;Lo;0;R;;;;;N;;;;;\n1092C;LYDIAN LETTER O;Lo;0;R;;;;;N;;;;;\n1092D;LYDIAN LETTER R;Lo;0;R;;;;;N;;;;;\n1092E;LYDIAN LETTER SS;Lo;0;R;;;;;N;;;;;\n1092F;LYDIAN LETTER T;Lo;0;R;;;;;N;;;;;\n10930;LYDIAN LETTER U;Lo;0;R;;;;;N;;;;;\n10931;LYDIAN LETTER F;Lo;0;R;;;;;N;;;;;\n10932;LYDIAN LETTER Q;Lo;0;R;;;;;N;;;;;\n10933;LYDIAN LETTER S;Lo;0;R;;;;;N;;;;;\n10934;LYDIAN LETTER TT;Lo;0;R;;;;;N;;;;;\n10935;LYDIAN LETTER AN;Lo;0;R;;;;;N;;;;;\n10936;LYDIAN LETTER EN;Lo;0;R;;;;;N;;;;;\n10937;LYDIAN LETTER LY;Lo;0;R;;;;;N;;;;;\n10938;LYDIAN LETTER NN;Lo;0;R;;;;;N;;;;;\n10939;LYDIAN LETTER C;Lo;0;R;;;;;N;;;;;\n1093F;LYDIAN TRIANGULAR MARK;Po;0;R;;;;;N;;;;;\n10940;SIDETIC LETTER N01;Lo;0;R;;;;;N;;;;;\n10941;SIDETIC LETTER N02;Lo;0;R;;;;;N;;;;;\n10942;SIDETIC LETTER N03;Lo;0;R;;;;;N;;;;;\n10943;SIDETIC LETTER N04;Lo;0;R;;;;;N;;;;;\n10944;SIDETIC LETTER N05;Lo;0;R;;;;;N;;;;;\n10945;SIDETIC LETTER N06;Lo;0;R;;;;;N;;;;;\n10946;SIDETIC LETTER N07;Lo;0;R;;;;;N;;;;;\n10947;SIDETIC LETTER N08;Lo;0;R;;;;;N;;;;;\n10948;SIDETIC LETTER N09;Lo;0;R;;;;;N;;;;;\n10949;SIDETIC LETTER N10;Lo;0;R;;;;;N;;;;;\n1094A;SIDETIC LETTER N11;Lo;0;R;;;;;N;;;;;\n1094B;SIDETIC LETTER N12;Lo;0;R;;;;;N;;;;;\n1094C;SIDETIC LETTER N13;Lo;0;R;;;;;N;;;;;\n1094D;SIDETIC LETTER N14;Lo;0;R;;;;;N;;;;;\n1094E;SIDETIC LETTER N15;Lo;0;R;;;;;N;;;;;\n1094F;SIDETIC LETTER N16;Lo;0;R;;;;;N;;;;;\n10950;SIDETIC LETTER N17;Lo;0;R;;;;;N;;;;;\n10951;SIDETIC LETTER N18;Lo;0;R;;;;;N;;;;;\n10952;SIDETIC LETTER N19;Lo;0;R;;;;;N;;;;;\n10953;SIDETIC LETTER N20;Lo;0;R;;;;;N;;;;;\n10954;SIDETIC LETTER N21;Lo;0;R;;;;;N;;;;;\n10955;SIDETIC LETTER N22;Lo;0;R;;;;;N;;;;;\n10956;SIDETIC LETTER N23;Lo;0;R;;;;;N;;;;;\n10957;SIDETIC LETTER N24;Lo;0;R;;;;;N;;;;;\n10958;SIDETIC LETTER N25;Lo;0;R;;;;;N;;;;;\n10959;SIDETIC LETTER N26;Lo;0;R;;;;;N;;;;;\n10980;MEROITIC HIEROGLYPHIC LETTER A;Lo;0;R;;;;;N;;;;;\n10981;MEROITIC HIEROGLYPHIC LETTER E;Lo;0;R;;;;;N;;;;;\n10982;MEROITIC HIEROGLYPHIC LETTER I;Lo;0;R;;;;;N;;;;;\n10983;MEROITIC HIEROGLYPHIC LETTER O;Lo;0;R;;;;;N;;;;;\n10984;MEROITIC HIEROGLYPHIC LETTER YA;Lo;0;R;;;;;N;;;;;\n10985;MEROITIC HIEROGLYPHIC LETTER WA;Lo;0;R;;;;;N;;;;;\n10986;MEROITIC HIEROGLYPHIC LETTER BA;Lo;0;R;;;;;N;;;;;\n10987;MEROITIC HIEROGLYPHIC LETTER BA-2;Lo;0;R;;;;;N;;;;;\n10988;MEROITIC HIEROGLYPHIC LETTER PA;Lo;0;R;;;;;N;;;;;\n10989;MEROITIC HIEROGLYPHIC LETTER MA;Lo;0;R;;;;;N;;;;;\n1098A;MEROITIC HIEROGLYPHIC LETTER NA;Lo;0;R;;;;;N;;;;;\n1098B;MEROITIC HIEROGLYPHIC LETTER NA-2;Lo;0;R;;;;;N;;;;;\n1098C;MEROITIC HIEROGLYPHIC LETTER NE;Lo;0;R;;;;;N;;;;;\n1098D;MEROITIC HIEROGLYPHIC LETTER NE-2;Lo;0;R;;;;;N;;;;;\n1098E;MEROITIC HIEROGLYPHIC LETTER RA;Lo;0;R;;;;;N;;;;;\n1098F;MEROITIC HIEROGLYPHIC LETTER RA-2;Lo;0;R;;;;;N;;;;;\n10990;MEROITIC HIEROGLYPHIC LETTER LA;Lo;0;R;;;;;N;;;;;\n10991;MEROITIC HIEROGLYPHIC LETTER KHA;Lo;0;R;;;;;N;;;;;\n10992;MEROITIC HIEROGLYPHIC LETTER HHA;Lo;0;R;;;;;N;;;;;\n10993;MEROITIC HIEROGLYPHIC LETTER SA;Lo;0;R;;;;;N;;;;;\n10994;MEROITIC HIEROGLYPHIC LETTER SA-2;Lo;0;R;;;;;N;;;;;\n10995;MEROITIC HIEROGLYPHIC LETTER SE;Lo;0;R;;;;;N;;;;;\n10996;MEROITIC HIEROGLYPHIC LETTER KA;Lo;0;R;;;;;N;;;;;\n10997;MEROITIC HIEROGLYPHIC LETTER QA;Lo;0;R;;;;;N;;;;;\n10998;MEROITIC HIEROGLYPHIC LETTER TA;Lo;0;R;;;;;N;;;;;\n10999;MEROITIC HIEROGLYPHIC LETTER TA-2;Lo;0;R;;;;;N;;;;;\n1099A;MEROITIC HIEROGLYPHIC LETTER TE;Lo;0;R;;;;;N;;;;;\n1099B;MEROITIC HIEROGLYPHIC LETTER TE-2;Lo;0;R;;;;;N;;;;;\n1099C;MEROITIC HIEROGLYPHIC LETTER TO;Lo;0;R;;;;;N;;;;;\n1099D;MEROITIC HIEROGLYPHIC LETTER DA;Lo;0;R;;;;;N;;;;;\n1099E;MEROITIC HIEROGLYPHIC SYMBOL VIDJ;Lo;0;R;;;;;N;;;;;\n1099F;MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2;Lo;0;R;;;;;N;;;;;\n109A0;MEROITIC CURSIVE LETTER A;Lo;0;R;;;;;N;;;;;\n109A1;MEROITIC CURSIVE LETTER E;Lo;0;R;;;;;N;;;;;\n109A2;MEROITIC CURSIVE LETTER I;Lo;0;R;;;;;N;;;;;\n109A3;MEROITIC CURSIVE LETTER O;Lo;0;R;;;;;N;;;;;\n109A4;MEROITIC CURSIVE LETTER YA;Lo;0;R;;;;;N;;;;;\n109A5;MEROITIC CURSIVE LETTER WA;Lo;0;R;;;;;N;;;;;\n109A6;MEROITIC CURSIVE LETTER BA;Lo;0;R;;;;;N;;;;;\n109A7;MEROITIC CURSIVE LETTER PA;Lo;0;R;;;;;N;;;;;\n109A8;MEROITIC CURSIVE LETTER MA;Lo;0;R;;;;;N;;;;;\n109A9;MEROITIC CURSIVE LETTER NA;Lo;0;R;;;;;N;;;;;\n109AA;MEROITIC CURSIVE LETTER NE;Lo;0;R;;;;;N;;;;;\n109AB;MEROITIC CURSIVE LETTER RA;Lo;0;R;;;;;N;;;;;\n109AC;MEROITIC CURSIVE LETTER LA;Lo;0;R;;;;;N;;;;;\n109AD;MEROITIC CURSIVE LETTER KHA;Lo;0;R;;;;;N;;;;;\n109AE;MEROITIC CURSIVE LETTER HHA;Lo;0;R;;;;;N;;;;;\n109AF;MEROITIC CURSIVE LETTER SA;Lo;0;R;;;;;N;;;;;\n109B0;MEROITIC CURSIVE LETTER ARCHAIC SA;Lo;0;R;;;;;N;;;;;\n109B1;MEROITIC CURSIVE LETTER SE;Lo;0;R;;;;;N;;;;;\n109B2;MEROITIC CURSIVE LETTER KA;Lo;0;R;;;;;N;;;;;\n109B3;MEROITIC CURSIVE LETTER QA;Lo;0;R;;;;;N;;;;;\n109B4;MEROITIC CURSIVE LETTER TA;Lo;0;R;;;;;N;;;;;\n109B5;MEROITIC CURSIVE LETTER TE;Lo;0;R;;;;;N;;;;;\n109B6;MEROITIC CURSIVE LETTER TO;Lo;0;R;;;;;N;;;;;\n109B7;MEROITIC CURSIVE LETTER DA;Lo;0;R;;;;;N;;;;;\n109BC;MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS;No;0;R;;;;11/12;N;;;;;\n109BD;MEROITIC CURSIVE FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;;\n109BE;MEROITIC CURSIVE LOGOGRAM RMT;Lo;0;R;;;;;N;;;;;\n109BF;MEROITIC CURSIVE LOGOGRAM IMN;Lo;0;R;;;;;N;;;;;\n109C0;MEROITIC CURSIVE NUMBER ONE;No;0;R;;;;1;N;;;;;\n109C1;MEROITIC CURSIVE NUMBER TWO;No;0;R;;;;2;N;;;;;\n109C2;MEROITIC CURSIVE NUMBER THREE;No;0;R;;;;3;N;;;;;\n109C3;MEROITIC CURSIVE NUMBER FOUR;No;0;R;;;;4;N;;;;;\n109C4;MEROITIC CURSIVE NUMBER FIVE;No;0;R;;;;5;N;;;;;\n109C5;MEROITIC CURSIVE NUMBER SIX;No;0;R;;;;6;N;;;;;\n109C6;MEROITIC CURSIVE NUMBER SEVEN;No;0;R;;;;7;N;;;;;\n109C7;MEROITIC CURSIVE NUMBER EIGHT;No;0;R;;;;8;N;;;;;\n109C8;MEROITIC CURSIVE NUMBER NINE;No;0;R;;;;9;N;;;;;\n109C9;MEROITIC CURSIVE NUMBER TEN;No;0;R;;;;10;N;;;;;\n109CA;MEROITIC CURSIVE NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n109CB;MEROITIC CURSIVE NUMBER THIRTY;No;0;R;;;;30;N;;;;;\n109CC;MEROITIC CURSIVE NUMBER FORTY;No;0;R;;;;40;N;;;;;\n109CD;MEROITIC CURSIVE NUMBER FIFTY;No;0;R;;;;50;N;;;;;\n109CE;MEROITIC CURSIVE NUMBER SIXTY;No;0;R;;;;60;N;;;;;\n109CF;MEROITIC CURSIVE NUMBER SEVENTY;No;0;R;;;;70;N;;;;;\n109D2;MEROITIC CURSIVE NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n109D3;MEROITIC CURSIVE NUMBER TWO HUNDRED;No;0;R;;;;200;N;;;;;\n109D4;MEROITIC CURSIVE NUMBER THREE HUNDRED;No;0;R;;;;300;N;;;;;\n109D5;MEROITIC CURSIVE NUMBER FOUR HUNDRED;No;0;R;;;;400;N;;;;;\n109D6;MEROITIC CURSIVE NUMBER FIVE HUNDRED;No;0;R;;;;500;N;;;;;\n109D7;MEROITIC CURSIVE NUMBER SIX HUNDRED;No;0;R;;;;600;N;;;;;\n109D8;MEROITIC CURSIVE NUMBER SEVEN HUNDRED;No;0;R;;;;700;N;;;;;\n109D9;MEROITIC CURSIVE NUMBER EIGHT HUNDRED;No;0;R;;;;800;N;;;;;\n109DA;MEROITIC CURSIVE NUMBER NINE HUNDRED;No;0;R;;;;900;N;;;;;\n109DB;MEROITIC CURSIVE NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;\n109DC;MEROITIC CURSIVE NUMBER TWO THOUSAND;No;0;R;;;;2000;N;;;;;\n109DD;MEROITIC CURSIVE NUMBER THREE THOUSAND;No;0;R;;;;3000;N;;;;;\n109DE;MEROITIC CURSIVE NUMBER FOUR THOUSAND;No;0;R;;;;4000;N;;;;;\n109DF;MEROITIC CURSIVE NUMBER FIVE THOUSAND;No;0;R;;;;5000;N;;;;;\n109E0;MEROITIC CURSIVE NUMBER SIX THOUSAND;No;0;R;;;;6000;N;;;;;\n109E1;MEROITIC CURSIVE NUMBER SEVEN THOUSAND;No;0;R;;;;7000;N;;;;;\n109E2;MEROITIC CURSIVE NUMBER EIGHT THOUSAND;No;0;R;;;;8000;N;;;;;\n109E3;MEROITIC CURSIVE NUMBER NINE THOUSAND;No;0;R;;;;9000;N;;;;;\n109E4;MEROITIC CURSIVE NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;;\n109E5;MEROITIC CURSIVE NUMBER TWENTY THOUSAND;No;0;R;;;;20000;N;;;;;\n109E6;MEROITIC CURSIVE NUMBER THIRTY THOUSAND;No;0;R;;;;30000;N;;;;;\n109E7;MEROITIC CURSIVE NUMBER FORTY THOUSAND;No;0;R;;;;40000;N;;;;;\n109E8;MEROITIC CURSIVE NUMBER FIFTY THOUSAND;No;0;R;;;;50000;N;;;;;\n109E9;MEROITIC CURSIVE NUMBER SIXTY THOUSAND;No;0;R;;;;60000;N;;;;;\n109EA;MEROITIC CURSIVE NUMBER SEVENTY THOUSAND;No;0;R;;;;70000;N;;;;;\n109EB;MEROITIC CURSIVE NUMBER EIGHTY THOUSAND;No;0;R;;;;80000;N;;;;;\n109EC;MEROITIC CURSIVE NUMBER NINETY THOUSAND;No;0;R;;;;90000;N;;;;;\n109ED;MEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAND;No;0;R;;;;100000;N;;;;;\n109EE;MEROITIC CURSIVE NUMBER TWO HUNDRED THOUSAND;No;0;R;;;;200000;N;;;;;\n109EF;MEROITIC CURSIVE NUMBER THREE HUNDRED THOUSAND;No;0;R;;;;300000;N;;;;;\n109F0;MEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSAND;No;0;R;;;;400000;N;;;;;\n109F1;MEROITIC CURSIVE NUMBER FIVE HUNDRED THOUSAND;No;0;R;;;;500000;N;;;;;\n109F2;MEROITIC CURSIVE NUMBER SIX HUNDRED THOUSAND;No;0;R;;;;600000;N;;;;;\n109F3;MEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSAND;No;0;R;;;;700000;N;;;;;\n109F4;MEROITIC CURSIVE NUMBER EIGHT HUNDRED THOUSAND;No;0;R;;;;800000;N;;;;;\n109F5;MEROITIC CURSIVE NUMBER NINE HUNDRED THOUSAND;No;0;R;;;;900000;N;;;;;\n109F6;MEROITIC CURSIVE FRACTION ONE TWELFTH;No;0;R;;;;1/12;N;;;;;\n109F7;MEROITIC CURSIVE FRACTION TWO TWELFTHS;No;0;R;;;;2/12;N;;;;;\n109F8;MEROITIC CURSIVE FRACTION THREE TWELFTHS;No;0;R;;;;3/12;N;;;;;\n109F9;MEROITIC CURSIVE FRACTION FOUR TWELFTHS;No;0;R;;;;4/12;N;;;;;\n109FA;MEROITIC CURSIVE FRACTION FIVE TWELFTHS;No;0;R;;;;5/12;N;;;;;\n109FB;MEROITIC CURSIVE FRACTION SIX TWELFTHS;No;0;R;;;;6/12;N;;;;;\n109FC;MEROITIC CURSIVE FRACTION SEVEN TWELFTHS;No;0;R;;;;7/12;N;;;;;\n109FD;MEROITIC CURSIVE FRACTION EIGHT TWELFTHS;No;0;R;;;;8/12;N;;;;;\n109FE;MEROITIC CURSIVE FRACTION NINE TWELFTHS;No;0;R;;;;9/12;N;;;;;\n109FF;MEROITIC CURSIVE FRACTION TEN TWELFTHS;No;0;R;;;;10/12;N;;;;;\n10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;;\n10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n10A03;KHAROSHTHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n10A05;KHAROSHTHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n10A06;KHAROSHTHI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n10A0C;KHAROSHTHI VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;\n10A0D;KHAROSHTHI SIGN DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;;\n10A0E;KHAROSHTHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n10A0F;KHAROSHTHI SIGN VISARGA;Mn;230;NSM;;;;;N;;;;;\n10A10;KHAROSHTHI LETTER KA;Lo;0;R;;;;;N;;;;;\n10A11;KHAROSHTHI LETTER KHA;Lo;0;R;;;;;N;;;;;\n10A12;KHAROSHTHI LETTER GA;Lo;0;R;;;;;N;;;;;\n10A13;KHAROSHTHI LETTER GHA;Lo;0;R;;;;;N;;;;;\n10A15;KHAROSHTHI LETTER CA;Lo;0;R;;;;;N;;;;;\n10A16;KHAROSHTHI LETTER CHA;Lo;0;R;;;;;N;;;;;\n10A17;KHAROSHTHI LETTER JA;Lo;0;R;;;;;N;;;;;\n10A19;KHAROSHTHI LETTER NYA;Lo;0;R;;;;;N;;;;;\n10A1A;KHAROSHTHI LETTER TTA;Lo;0;R;;;;;N;;;;;\n10A1B;KHAROSHTHI LETTER TTHA;Lo;0;R;;;;;N;;;;;\n10A1C;KHAROSHTHI LETTER DDA;Lo;0;R;;;;;N;;;;;\n10A1D;KHAROSHTHI LETTER DDHA;Lo;0;R;;;;;N;;;;;\n10A1E;KHAROSHTHI LETTER NNA;Lo;0;R;;;;;N;;;;;\n10A1F;KHAROSHTHI LETTER TA;Lo;0;R;;;;;N;;;;;\n10A20;KHAROSHTHI LETTER THA;Lo;0;R;;;;;N;;;;;\n10A21;KHAROSHTHI LETTER DA;Lo;0;R;;;;;N;;;;;\n10A22;KHAROSHTHI LETTER DHA;Lo;0;R;;;;;N;;;;;\n10A23;KHAROSHTHI LETTER NA;Lo;0;R;;;;;N;;;;;\n10A24;KHAROSHTHI LETTER PA;Lo;0;R;;;;;N;;;;;\n10A25;KHAROSHTHI LETTER PHA;Lo;0;R;;;;;N;;;;;\n10A26;KHAROSHTHI LETTER BA;Lo;0;R;;;;;N;;;;;\n10A27;KHAROSHTHI LETTER BHA;Lo;0;R;;;;;N;;;;;\n10A28;KHAROSHTHI LETTER MA;Lo;0;R;;;;;N;;;;;\n10A29;KHAROSHTHI LETTER YA;Lo;0;R;;;;;N;;;;;\n10A2A;KHAROSHTHI LETTER RA;Lo;0;R;;;;;N;;;;;\n10A2B;KHAROSHTHI LETTER LA;Lo;0;R;;;;;N;;;;;\n10A2C;KHAROSHTHI LETTER VA;Lo;0;R;;;;;N;;;;;\n10A2D;KHAROSHTHI LETTER SHA;Lo;0;R;;;;;N;;;;;\n10A2E;KHAROSHTHI LETTER SSA;Lo;0;R;;;;;N;;;;;\n10A2F;KHAROSHTHI LETTER SA;Lo;0;R;;;;;N;;;;;\n10A30;KHAROSHTHI LETTER ZA;Lo;0;R;;;;;N;;;;;\n10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;;\n10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;;\n10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;;\n10A34;KHAROSHTHI LETTER TTTA;Lo;0;R;;;;;N;;;;;\n10A35;KHAROSHTHI LETTER VHA;Lo;0;R;;;;;N;;;;;\n10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;;\n10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;;\n10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;\n10A3F;KHAROSHTHI VIRAMA;Mn;9;NSM;;;;;N;;;;;\n10A40;KHAROSHTHI DIGIT ONE;No;0;R;;;1;1;N;;;;;\n10A41;KHAROSHTHI DIGIT TWO;No;0;R;;;2;2;N;;;;;\n10A42;KHAROSHTHI DIGIT THREE;No;0;R;;;3;3;N;;;;;\n10A43;KHAROSHTHI DIGIT FOUR;No;0;R;;;4;4;N;;;;;\n10A44;KHAROSHTHI NUMBER TEN;No;0;R;;;;10;N;;;;;\n10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;\n10A48;KHAROSHTHI FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;;\n10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;;\n10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;;\n10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;;\n10A53;KHAROSHTHI PUNCTUATION CRESCENT BAR;Po;0;R;;;;;N;;;;;\n10A54;KHAROSHTHI PUNCTUATION MANGALAM;Po;0;R;;;;;N;;;;;\n10A55;KHAROSHTHI PUNCTUATION LOTUS;Po;0;R;;;;;N;;;;;\n10A56;KHAROSHTHI PUNCTUATION DANDA;Po;0;R;;;;;N;;;;;\n10A57;KHAROSHTHI PUNCTUATION DOUBLE DANDA;Po;0;R;;;;;N;;;;;\n10A58;KHAROSHTHI PUNCTUATION LINES;Po;0;R;;;;;N;;;;;\n10A60;OLD SOUTH ARABIAN LETTER HE;Lo;0;R;;;;;N;;;;;\n10A61;OLD SOUTH ARABIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10A62;OLD SOUTH ARABIAN LETTER HETH;Lo;0;R;;;;;N;;;;;\n10A63;OLD SOUTH ARABIAN LETTER MEM;Lo;0;R;;;;;N;;;;;\n10A64;OLD SOUTH ARABIAN LETTER QOPH;Lo;0;R;;;;;N;;;;;\n10A65;OLD SOUTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;;\n10A66;OLD SOUTH ARABIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10A67;OLD SOUTH ARABIAN LETTER RESH;Lo;0;R;;;;;N;;;;;\n10A68;OLD SOUTH ARABIAN LETTER BETH;Lo;0;R;;;;;N;;;;;\n10A69;OLD SOUTH ARABIAN LETTER TAW;Lo;0;R;;;;;N;;;;;\n10A6A;OLD SOUTH ARABIAN LETTER SAT;Lo;0;R;;;;;N;;;;;\n10A6B;OLD SOUTH ARABIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10A6C;OLD SOUTH ARABIAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n10A6D;OLD SOUTH ARABIAN LETTER KHETH;Lo;0;R;;;;;N;;;;;\n10A6E;OLD SOUTH ARABIAN LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10A6F;OLD SOUTH ARABIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10A70;OLD SOUTH ARABIAN LETTER FE;Lo;0;R;;;;;N;;;;;\n10A71;OLD SOUTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;;\n10A72;OLD SOUTH ARABIAN LETTER AYN;Lo;0;R;;;;;N;;;;;\n10A73;OLD SOUTH ARABIAN LETTER DHADHE;Lo;0;R;;;;;N;;;;;\n10A74;OLD SOUTH ARABIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10A75;OLD SOUTH ARABIAN LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10A76;OLD SOUTH ARABIAN LETTER GHAYN;Lo;0;R;;;;;N;;;;;\n10A77;OLD SOUTH ARABIAN LETTER TETH;Lo;0;R;;;;;N;;;;;\n10A78;OLD SOUTH ARABIAN LETTER ZAYN;Lo;0;R;;;;;N;;;;;\n10A79;OLD SOUTH ARABIAN LETTER DHALETH;Lo;0;R;;;;;N;;;;;\n10A7A;OLD SOUTH ARABIAN LETTER YODH;Lo;0;R;;;;;N;;;;;\n10A7B;OLD SOUTH ARABIAN LETTER THAW;Lo;0;R;;;;;N;;;;;\n10A7C;OLD SOUTH ARABIAN LETTER THETH;Lo;0;R;;;;;N;;;;;\n10A7D;OLD SOUTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n10A7E;OLD SOUTH ARABIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;;\n10A7F;OLD SOUTH ARABIAN NUMERIC INDICATOR;Po;0;R;;;;;N;;;;;\n10A80;OLD NORTH ARABIAN LETTER HEH;Lo;0;R;;;;;N;;;;;\n10A81;OLD NORTH ARABIAN LETTER LAM;Lo;0;R;;;;;N;;;;;\n10A82;OLD NORTH ARABIAN LETTER HAH;Lo;0;R;;;;;N;;;;;\n10A83;OLD NORTH ARABIAN LETTER MEEM;Lo;0;R;;;;;N;;;;;\n10A84;OLD NORTH ARABIAN LETTER QAF;Lo;0;R;;;;;N;;;;;\n10A85;OLD NORTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;;\n10A86;OLD NORTH ARABIAN LETTER ES-2;Lo;0;R;;;;;N;;;;;\n10A87;OLD NORTH ARABIAN LETTER REH;Lo;0;R;;;;;N;;;;;\n10A88;OLD NORTH ARABIAN LETTER BEH;Lo;0;R;;;;;N;;;;;\n10A89;OLD NORTH ARABIAN LETTER TEH;Lo;0;R;;;;;N;;;;;\n10A8A;OLD NORTH ARABIAN LETTER ES-1;Lo;0;R;;;;;N;;;;;\n10A8B;OLD NORTH ARABIAN LETTER KAF;Lo;0;R;;;;;N;;;;;\n10A8C;OLD NORTH ARABIAN LETTER NOON;Lo;0;R;;;;;N;;;;;\n10A8D;OLD NORTH ARABIAN LETTER KHAH;Lo;0;R;;;;;N;;;;;\n10A8E;OLD NORTH ARABIAN LETTER SAD;Lo;0;R;;;;;N;;;;;\n10A8F;OLD NORTH ARABIAN LETTER ES-3;Lo;0;R;;;;;N;;;;;\n10A90;OLD NORTH ARABIAN LETTER FEH;Lo;0;R;;;;;N;;;;;\n10A91;OLD NORTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;;\n10A92;OLD NORTH ARABIAN LETTER AIN;Lo;0;R;;;;;N;;;;;\n10A93;OLD NORTH ARABIAN LETTER DAD;Lo;0;R;;;;;N;;;;;\n10A94;OLD NORTH ARABIAN LETTER GEEM;Lo;0;R;;;;;N;;;;;\n10A95;OLD NORTH ARABIAN LETTER DAL;Lo;0;R;;;;;N;;;;;\n10A96;OLD NORTH ARABIAN LETTER GHAIN;Lo;0;R;;;;;N;;;;;\n10A97;OLD NORTH ARABIAN LETTER TAH;Lo;0;R;;;;;N;;;;;\n10A98;OLD NORTH ARABIAN LETTER ZAIN;Lo;0;R;;;;;N;;;;;\n10A99;OLD NORTH ARABIAN LETTER THAL;Lo;0;R;;;;;N;;;;;\n10A9A;OLD NORTH ARABIAN LETTER YEH;Lo;0;R;;;;;N;;;;;\n10A9B;OLD NORTH ARABIAN LETTER THEH;Lo;0;R;;;;;N;;;;;\n10A9C;OLD NORTH ARABIAN LETTER ZAH;Lo;0;R;;;;;N;;;;;\n10A9D;OLD NORTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n10A9E;OLD NORTH ARABIAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n10A9F;OLD NORTH ARABIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10AC0;MANICHAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10AC1;MANICHAEAN LETTER BETH;Lo;0;R;;;;;N;;;;;\n10AC2;MANICHAEAN LETTER BHETH;Lo;0;R;;;;;N;;;;;\n10AC3;MANICHAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10AC4;MANICHAEAN LETTER GHIMEL;Lo;0;R;;;;;N;;;;;\n10AC5;MANICHAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10AC6;MANICHAEAN LETTER HE;Lo;0;R;;;;;N;;;;;\n10AC7;MANICHAEAN LETTER WAW;Lo;0;R;;;;;N;;;;;\n10AC8;MANICHAEAN SIGN UD;So;0;R;;;;;N;;;;;\n10AC9;MANICHAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10ACA;MANICHAEAN LETTER ZHAYIN;Lo;0;R;;;;;N;;;;;\n10ACB;MANICHAEAN LETTER JAYIN;Lo;0;R;;;;;N;;;;;\n10ACC;MANICHAEAN LETTER JHAYIN;Lo;0;R;;;;;N;;;;;\n10ACD;MANICHAEAN LETTER HETH;Lo;0;R;;;;;N;;;;;\n10ACE;MANICHAEAN LETTER TETH;Lo;0;R;;;;;N;;;;;\n10ACF;MANICHAEAN LETTER YODH;Lo;0;R;;;;;N;;;;;\n10AD0;MANICHAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10AD1;MANICHAEAN LETTER XAPH;Lo;0;R;;;;;N;;;;;\n10AD2;MANICHAEAN LETTER KHAPH;Lo;0;R;;;;;N;;;;;\n10AD3;MANICHAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10AD4;MANICHAEAN LETTER DHAMEDH;Lo;0;R;;;;;N;;;;;\n10AD5;MANICHAEAN LETTER THAMEDH;Lo;0;R;;;;;N;;;;;\n10AD6;MANICHAEAN LETTER MEM;Lo;0;R;;;;;N;;;;;\n10AD7;MANICHAEAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n10AD8;MANICHAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10AD9;MANICHAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;;\n10ADA;MANICHAEAN LETTER AAYIN;Lo;0;R;;;;;N;;;;;\n10ADB;MANICHAEAN LETTER PE;Lo;0;R;;;;;N;;;;;\n10ADC;MANICHAEAN LETTER FE;Lo;0;R;;;;;N;;;;;\n10ADD;MANICHAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10ADE;MANICHAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;;\n10ADF;MANICHAEAN LETTER XOPH;Lo;0;R;;;;;N;;;;;\n10AE0;MANICHAEAN LETTER QHOPH;Lo;0;R;;;;;N;;;;;\n10AE1;MANICHAEAN LETTER RESH;Lo;0;R;;;;;N;;;;;\n10AE2;MANICHAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10AE3;MANICHAEAN LETTER SSHIN;Lo;0;R;;;;;N;;;;;\n10AE4;MANICHAEAN LETTER TAW;Lo;0;R;;;;;N;;;;;\n10AE5;MANICHAEAN ABBREVIATION MARK ABOVE;Mn;230;NSM;;;;;N;;;;;\n10AE6;MANICHAEAN ABBREVIATION MARK BELOW;Mn;220;NSM;;;;;N;;;;;\n10AEB;MANICHAEAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n10AEC;MANICHAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;;\n10AED;MANICHAEAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n10AEE;MANICHAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10AEF;MANICHAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10AF0;MANICHAEAN PUNCTUATION STAR;Po;0;R;;;;;N;;;;;\n10AF1;MANICHAEAN PUNCTUATION FLEURON;Po;0;R;;;;;N;;;;;\n10AF2;MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT;Po;0;R;;;;;N;;;;;\n10AF3;MANICHAEAN PUNCTUATION DOT WITHIN DOT;Po;0;R;;;;;N;;;;;\n10AF4;MANICHAEAN PUNCTUATION DOT;Po;0;R;;;;;N;;;;;\n10AF5;MANICHAEAN PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;;\n10AF6;MANICHAEAN PUNCTUATION LINE FILLER;Po;0;R;;;;;N;;;;;\n10B00;AVESTAN LETTER A;Lo;0;R;;;;;N;;;;;\n10B01;AVESTAN LETTER AA;Lo;0;R;;;;;N;;;;;\n10B02;AVESTAN LETTER AO;Lo;0;R;;;;;N;;;;;\n10B03;AVESTAN LETTER AAO;Lo;0;R;;;;;N;;;;;\n10B04;AVESTAN LETTER AN;Lo;0;R;;;;;N;;;;;\n10B05;AVESTAN LETTER AAN;Lo;0;R;;;;;N;;;;;\n10B06;AVESTAN LETTER AE;Lo;0;R;;;;;N;;;;;\n10B07;AVESTAN LETTER AEE;Lo;0;R;;;;;N;;;;;\n10B08;AVESTAN LETTER E;Lo;0;R;;;;;N;;;;;\n10B09;AVESTAN LETTER EE;Lo;0;R;;;;;N;;;;;\n10B0A;AVESTAN LETTER O;Lo;0;R;;;;;N;;;;;\n10B0B;AVESTAN LETTER OO;Lo;0;R;;;;;N;;;;;\n10B0C;AVESTAN LETTER I;Lo;0;R;;;;;N;;;;;\n10B0D;AVESTAN LETTER II;Lo;0;R;;;;;N;;;;;\n10B0E;AVESTAN LETTER U;Lo;0;R;;;;;N;;;;;\n10B0F;AVESTAN LETTER UU;Lo;0;R;;;;;N;;;;;\n10B10;AVESTAN LETTER KE;Lo;0;R;;;;;N;;;;;\n10B11;AVESTAN LETTER XE;Lo;0;R;;;;;N;;;;;\n10B12;AVESTAN LETTER XYE;Lo;0;R;;;;;N;;;;;\n10B13;AVESTAN LETTER XVE;Lo;0;R;;;;;N;;;;;\n10B14;AVESTAN LETTER GE;Lo;0;R;;;;;N;;;;;\n10B15;AVESTAN LETTER GGE;Lo;0;R;;;;;N;;;;;\n10B16;AVESTAN LETTER GHE;Lo;0;R;;;;;N;;;;;\n10B17;AVESTAN LETTER CE;Lo;0;R;;;;;N;;;;;\n10B18;AVESTAN LETTER JE;Lo;0;R;;;;;N;;;;;\n10B19;AVESTAN LETTER TE;Lo;0;R;;;;;N;;;;;\n10B1A;AVESTAN LETTER THE;Lo;0;R;;;;;N;;;;;\n10B1B;AVESTAN LETTER DE;Lo;0;R;;;;;N;;;;;\n10B1C;AVESTAN LETTER DHE;Lo;0;R;;;;;N;;;;;\n10B1D;AVESTAN LETTER TTE;Lo;0;R;;;;;N;;;;;\n10B1E;AVESTAN LETTER PE;Lo;0;R;;;;;N;;;;;\n10B1F;AVESTAN LETTER FE;Lo;0;R;;;;;N;;;;;\n10B20;AVESTAN LETTER BE;Lo;0;R;;;;;N;;;;;\n10B21;AVESTAN LETTER BHE;Lo;0;R;;;;;N;;;;;\n10B22;AVESTAN LETTER NGE;Lo;0;R;;;;;N;;;;;\n10B23;AVESTAN LETTER NGYE;Lo;0;R;;;;;N;;;;;\n10B24;AVESTAN LETTER NGVE;Lo;0;R;;;;;N;;;;;\n10B25;AVESTAN LETTER NE;Lo;0;R;;;;;N;;;;;\n10B26;AVESTAN LETTER NYE;Lo;0;R;;;;;N;;;;;\n10B27;AVESTAN LETTER NNE;Lo;0;R;;;;;N;;;;;\n10B28;AVESTAN LETTER ME;Lo;0;R;;;;;N;;;;;\n10B29;AVESTAN LETTER HME;Lo;0;R;;;;;N;;;;;\n10B2A;AVESTAN LETTER YYE;Lo;0;R;;;;;N;;;;;\n10B2B;AVESTAN LETTER YE;Lo;0;R;;;;;N;;;;;\n10B2C;AVESTAN LETTER VE;Lo;0;R;;;;;N;;;;;\n10B2D;AVESTAN LETTER RE;Lo;0;R;;;;;N;;;;;\n10B2E;AVESTAN LETTER LE;Lo;0;R;;;;;N;;;;;\n10B2F;AVESTAN LETTER SE;Lo;0;R;;;;;N;;;;;\n10B30;AVESTAN LETTER ZE;Lo;0;R;;;;;N;;;;;\n10B31;AVESTAN LETTER SHE;Lo;0;R;;;;;N;;;;;\n10B32;AVESTAN LETTER ZHE;Lo;0;R;;;;;N;;;;;\n10B33;AVESTAN LETTER SHYE;Lo;0;R;;;;;N;;;;;\n10B34;AVESTAN LETTER SSHE;Lo;0;R;;;;;N;;;;;\n10B35;AVESTAN LETTER HE;Lo;0;R;;;;;N;;;;;\n10B39;AVESTAN ABBREVIATION MARK;Po;0;ON;;;;;N;;;;;\n10B3A;TINY TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n10B3B;SMALL TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n10B3C;LARGE TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;\n10B3D;LARGE ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;;\n10B3E;LARGE TWO RINGS OVER ONE RING PUNCTUATION;Po;0;ON;;;;;N;;;;;\n10B3F;LARGE ONE RING OVER TWO RINGS PUNCTUATION;Po;0;ON;;;;;N;;;;;\n10B40;INSCRIPTIONAL PARTHIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10B41;INSCRIPTIONAL PARTHIAN LETTER BETH;Lo;0;R;;;;;N;;;;;\n10B42;INSCRIPTIONAL PARTHIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10B43;INSCRIPTIONAL PARTHIAN LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10B44;INSCRIPTIONAL PARTHIAN LETTER HE;Lo;0;R;;;;;N;;;;;\n10B45;INSCRIPTIONAL PARTHIAN LETTER WAW;Lo;0;R;;;;;N;;;;;\n10B46;INSCRIPTIONAL PARTHIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10B47;INSCRIPTIONAL PARTHIAN LETTER HETH;Lo;0;R;;;;;N;;;;;\n10B48;INSCRIPTIONAL PARTHIAN LETTER TETH;Lo;0;R;;;;;N;;;;;\n10B49;INSCRIPTIONAL PARTHIAN LETTER YODH;Lo;0;R;;;;;N;;;;;\n10B4A;INSCRIPTIONAL PARTHIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10B4B;INSCRIPTIONAL PARTHIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10B4C;INSCRIPTIONAL PARTHIAN LETTER MEM;Lo;0;R;;;;;N;;;;;\n10B4D;INSCRIPTIONAL PARTHIAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n10B4E;INSCRIPTIONAL PARTHIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10B4F;INSCRIPTIONAL PARTHIAN LETTER AYIN;Lo;0;R;;;;;N;;;;;\n10B50;INSCRIPTIONAL PARTHIAN LETTER PE;Lo;0;R;;;;;N;;;;;\n10B51;INSCRIPTIONAL PARTHIAN LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10B52;INSCRIPTIONAL PARTHIAN LETTER QOPH;Lo;0;R;;;;;N;;;;;\n10B53;INSCRIPTIONAL PARTHIAN LETTER RESH;Lo;0;R;;;;;N;;;;;\n10B54;INSCRIPTIONAL PARTHIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10B55;INSCRIPTIONAL PARTHIAN LETTER TAW;Lo;0;R;;;;;N;;;;;\n10B58;INSCRIPTIONAL PARTHIAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n10B59;INSCRIPTIONAL PARTHIAN NUMBER TWO;No;0;R;;;;2;N;;;;;\n10B5A;INSCRIPTIONAL PARTHIAN NUMBER THREE;No;0;R;;;;3;N;;;;;\n10B5B;INSCRIPTIONAL PARTHIAN NUMBER FOUR;No;0;R;;;;4;N;;;;;\n10B5C;INSCRIPTIONAL PARTHIAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n10B5D;INSCRIPTIONAL PARTHIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10B5E;INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10B5F;INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;\n10B60;INSCRIPTIONAL PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10B61;INSCRIPTIONAL PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;;\n10B62;INSCRIPTIONAL PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10B63;INSCRIPTIONAL PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10B64;INSCRIPTIONAL PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;;\n10B65;INSCRIPTIONAL PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;;\n10B66;INSCRIPTIONAL PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10B67;INSCRIPTIONAL PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;;\n10B68;INSCRIPTIONAL PAHLAVI LETTER TETH;Lo;0;R;;;;;N;;;;;\n10B69;INSCRIPTIONAL PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;;\n10B6A;INSCRIPTIONAL PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10B6B;INSCRIPTIONAL PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10B6C;INSCRIPTIONAL PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;;\n10B6D;INSCRIPTIONAL PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;;\n10B6E;INSCRIPTIONAL PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10B6F;INSCRIPTIONAL PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;;\n10B70;INSCRIPTIONAL PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10B71;INSCRIPTIONAL PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10B72;INSCRIPTIONAL PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;;\n10B78;INSCRIPTIONAL PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;;\n10B79;INSCRIPTIONAL PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;;\n10B7A;INSCRIPTIONAL PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;;\n10B7B;INSCRIPTIONAL PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;;\n10B7C;INSCRIPTIONAL PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;;\n10B7D;INSCRIPTIONAL PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10B7E;INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10B7F;INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;\n10B80;PSALTER PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10B81;PSALTER PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;;\n10B82;PSALTER PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10B83;PSALTER PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10B84;PSALTER PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;;\n10B85;PSALTER PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;;\n10B86;PSALTER PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10B87;PSALTER PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;;\n10B88;PSALTER PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;;\n10B89;PSALTER PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10B8A;PSALTER PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10B8B;PSALTER PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;;\n10B8C;PSALTER PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;;\n10B8D;PSALTER PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10B8E;PSALTER PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;;\n10B8F;PSALTER PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10B90;PSALTER PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10B91;PSALTER PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;;\n10B99;PSALTER PAHLAVI SECTION MARK;Po;0;R;;;;;N;;;;;\n10B9A;PSALTER PAHLAVI TURNED SECTION MARK;Po;0;R;;;;;N;;;;;\n10B9B;PSALTER PAHLAVI FOUR DOTS WITH CROSS;Po;0;R;;;;;N;;;;;\n10B9C;PSALTER PAHLAVI FOUR DOTS WITH DOT;Po;0;R;;;;;N;;;;;\n10BA9;PSALTER PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;;\n10BAA;PSALTER PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;;\n10BAB;PSALTER PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;;\n10BAC;PSALTER PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;;\n10BAD;PSALTER PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;;\n10BAE;PSALTER PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10BAF;PSALTER PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10C00;OLD TURKIC LETTER ORKHON A;Lo;0;R;;;;;N;;;;;\n10C01;OLD TURKIC LETTER YENISEI A;Lo;0;R;;;;;N;;;;;\n10C02;OLD TURKIC LETTER YENISEI AE;Lo;0;R;;;;;N;;;;;\n10C03;OLD TURKIC LETTER ORKHON I;Lo;0;R;;;;;N;;;;;\n10C04;OLD TURKIC LETTER YENISEI I;Lo;0;R;;;;;N;;;;;\n10C05;OLD TURKIC LETTER YENISEI E;Lo;0;R;;;;;N;;;;;\n10C06;OLD TURKIC LETTER ORKHON O;Lo;0;R;;;;;N;;;;;\n10C07;OLD TURKIC LETTER ORKHON OE;Lo;0;R;;;;;N;;;;;\n10C08;OLD TURKIC LETTER YENISEI OE;Lo;0;R;;;;;N;;;;;\n10C09;OLD TURKIC LETTER ORKHON AB;Lo;0;R;;;;;N;;;;;\n10C0A;OLD TURKIC LETTER YENISEI AB;Lo;0;R;;;;;N;;;;;\n10C0B;OLD TURKIC LETTER ORKHON AEB;Lo;0;R;;;;;N;;;;;\n10C0C;OLD TURKIC LETTER YENISEI AEB;Lo;0;R;;;;;N;;;;;\n10C0D;OLD TURKIC LETTER ORKHON AG;Lo;0;R;;;;;N;;;;;\n10C0E;OLD TURKIC LETTER YENISEI AG;Lo;0;R;;;;;N;;;;;\n10C0F;OLD TURKIC LETTER ORKHON AEG;Lo;0;R;;;;;N;;;;;\n10C10;OLD TURKIC LETTER YENISEI AEG;Lo;0;R;;;;;N;;;;;\n10C11;OLD TURKIC LETTER ORKHON AD;Lo;0;R;;;;;N;;;;;\n10C12;OLD TURKIC LETTER YENISEI AD;Lo;0;R;;;;;N;;;;;\n10C13;OLD TURKIC LETTER ORKHON AED;Lo;0;R;;;;;N;;;;;\n10C14;OLD TURKIC LETTER ORKHON EZ;Lo;0;R;;;;;N;;;;;\n10C15;OLD TURKIC LETTER YENISEI EZ;Lo;0;R;;;;;N;;;;;\n10C16;OLD TURKIC LETTER ORKHON AY;Lo;0;R;;;;;N;;;;;\n10C17;OLD TURKIC LETTER YENISEI AY;Lo;0;R;;;;;N;;;;;\n10C18;OLD TURKIC LETTER ORKHON AEY;Lo;0;R;;;;;N;;;;;\n10C19;OLD TURKIC LETTER YENISEI AEY;Lo;0;R;;;;;N;;;;;\n10C1A;OLD TURKIC LETTER ORKHON AEK;Lo;0;R;;;;;N;;;;;\n10C1B;OLD TURKIC LETTER YENISEI AEK;Lo;0;R;;;;;N;;;;;\n10C1C;OLD TURKIC LETTER ORKHON OEK;Lo;0;R;;;;;N;;;;;\n10C1D;OLD TURKIC LETTER YENISEI OEK;Lo;0;R;;;;;N;;;;;\n10C1E;OLD TURKIC LETTER ORKHON AL;Lo;0;R;;;;;N;;;;;\n10C1F;OLD TURKIC LETTER YENISEI AL;Lo;0;R;;;;;N;;;;;\n10C20;OLD TURKIC LETTER ORKHON AEL;Lo;0;R;;;;;N;;;;;\n10C21;OLD TURKIC LETTER ORKHON ELT;Lo;0;R;;;;;N;;;;;\n10C22;OLD TURKIC LETTER ORKHON EM;Lo;0;R;;;;;N;;;;;\n10C23;OLD TURKIC LETTER ORKHON AN;Lo;0;R;;;;;N;;;;;\n10C24;OLD TURKIC LETTER ORKHON AEN;Lo;0;R;;;;;N;;;;;\n10C25;OLD TURKIC LETTER YENISEI AEN;Lo;0;R;;;;;N;;;;;\n10C26;OLD TURKIC LETTER ORKHON ENT;Lo;0;R;;;;;N;;;;;\n10C27;OLD TURKIC LETTER YENISEI ENT;Lo;0;R;;;;;N;;;;;\n10C28;OLD TURKIC LETTER ORKHON ENC;Lo;0;R;;;;;N;;;;;\n10C29;OLD TURKIC LETTER YENISEI ENC;Lo;0;R;;;;;N;;;;;\n10C2A;OLD TURKIC LETTER ORKHON ENY;Lo;0;R;;;;;N;;;;;\n10C2B;OLD TURKIC LETTER YENISEI ENY;Lo;0;R;;;;;N;;;;;\n10C2C;OLD TURKIC LETTER YENISEI ANG;Lo;0;R;;;;;N;;;;;\n10C2D;OLD TURKIC LETTER ORKHON ENG;Lo;0;R;;;;;N;;;;;\n10C2E;OLD TURKIC LETTER YENISEI AENG;Lo;0;R;;;;;N;;;;;\n10C2F;OLD TURKIC LETTER ORKHON EP;Lo;0;R;;;;;N;;;;;\n10C30;OLD TURKIC LETTER ORKHON OP;Lo;0;R;;;;;N;;;;;\n10C31;OLD TURKIC LETTER ORKHON IC;Lo;0;R;;;;;N;;;;;\n10C32;OLD TURKIC LETTER ORKHON EC;Lo;0;R;;;;;N;;;;;\n10C33;OLD TURKIC LETTER YENISEI EC;Lo;0;R;;;;;N;;;;;\n10C34;OLD TURKIC LETTER ORKHON AQ;Lo;0;R;;;;;N;;;;;\n10C35;OLD TURKIC LETTER YENISEI AQ;Lo;0;R;;;;;N;;;;;\n10C36;OLD TURKIC LETTER ORKHON IQ;Lo;0;R;;;;;N;;;;;\n10C37;OLD TURKIC LETTER YENISEI IQ;Lo;0;R;;;;;N;;;;;\n10C38;OLD TURKIC LETTER ORKHON OQ;Lo;0;R;;;;;N;;;;;\n10C39;OLD TURKIC LETTER YENISEI OQ;Lo;0;R;;;;;N;;;;;\n10C3A;OLD TURKIC LETTER ORKHON AR;Lo;0;R;;;;;N;;;;;\n10C3B;OLD TURKIC LETTER YENISEI AR;Lo;0;R;;;;;N;;;;;\n10C3C;OLD TURKIC LETTER ORKHON AER;Lo;0;R;;;;;N;;;;;\n10C3D;OLD TURKIC LETTER ORKHON AS;Lo;0;R;;;;;N;;;;;\n10C3E;OLD TURKIC LETTER ORKHON AES;Lo;0;R;;;;;N;;;;;\n10C3F;OLD TURKIC LETTER ORKHON ASH;Lo;0;R;;;;;N;;;;;\n10C40;OLD TURKIC LETTER YENISEI ASH;Lo;0;R;;;;;N;;;;;\n10C41;OLD TURKIC LETTER ORKHON ESH;Lo;0;R;;;;;N;;;;;\n10C42;OLD TURKIC LETTER YENISEI ESH;Lo;0;R;;;;;N;;;;;\n10C43;OLD TURKIC LETTER ORKHON AT;Lo;0;R;;;;;N;;;;;\n10C44;OLD TURKIC LETTER YENISEI AT;Lo;0;R;;;;;N;;;;;\n10C45;OLD TURKIC LETTER ORKHON AET;Lo;0;R;;;;;N;;;;;\n10C46;OLD TURKIC LETTER YENISEI AET;Lo;0;R;;;;;N;;;;;\n10C47;OLD TURKIC LETTER ORKHON OT;Lo;0;R;;;;;N;;;;;\n10C48;OLD TURKIC LETTER ORKHON BASH;Lo;0;R;;;;;N;;;;;\n10C80;OLD HUNGARIAN CAPITAL LETTER A;Lu;0;R;;;;;N;;;;10CC0;\n10C81;OLD HUNGARIAN CAPITAL LETTER AA;Lu;0;R;;;;;N;;;;10CC1;\n10C82;OLD HUNGARIAN CAPITAL LETTER EB;Lu;0;R;;;;;N;;;;10CC2;\n10C83;OLD HUNGARIAN CAPITAL LETTER AMB;Lu;0;R;;;;;N;;;;10CC3;\n10C84;OLD HUNGARIAN CAPITAL LETTER EC;Lu;0;R;;;;;N;;;;10CC4;\n10C85;OLD HUNGARIAN CAPITAL LETTER ENC;Lu;0;R;;;;;N;;;;10CC5;\n10C86;OLD HUNGARIAN CAPITAL LETTER ECS;Lu;0;R;;;;;N;;;;10CC6;\n10C87;OLD HUNGARIAN CAPITAL LETTER ED;Lu;0;R;;;;;N;;;;10CC7;\n10C88;OLD HUNGARIAN CAPITAL LETTER AND;Lu;0;R;;;;;N;;;;10CC8;\n10C89;OLD HUNGARIAN CAPITAL LETTER E;Lu;0;R;;;;;N;;;;10CC9;\n10C8A;OLD HUNGARIAN CAPITAL LETTER CLOSE E;Lu;0;R;;;;;N;;;;10CCA;\n10C8B;OLD HUNGARIAN CAPITAL LETTER EE;Lu;0;R;;;;;N;;;;10CCB;\n10C8C;OLD HUNGARIAN CAPITAL LETTER EF;Lu;0;R;;;;;N;;;;10CCC;\n10C8D;OLD HUNGARIAN CAPITAL LETTER EG;Lu;0;R;;;;;N;;;;10CCD;\n10C8E;OLD HUNGARIAN CAPITAL LETTER EGY;Lu;0;R;;;;;N;;;;10CCE;\n10C8F;OLD HUNGARIAN CAPITAL LETTER EH;Lu;0;R;;;;;N;;;;10CCF;\n10C90;OLD HUNGARIAN CAPITAL LETTER I;Lu;0;R;;;;;N;;;;10CD0;\n10C91;OLD HUNGARIAN CAPITAL LETTER II;Lu;0;R;;;;;N;;;;10CD1;\n10C92;OLD HUNGARIAN CAPITAL LETTER EJ;Lu;0;R;;;;;N;;;;10CD2;\n10C93;OLD HUNGARIAN CAPITAL LETTER EK;Lu;0;R;;;;;N;;;;10CD3;\n10C94;OLD HUNGARIAN CAPITAL LETTER AK;Lu;0;R;;;;;N;;;;10CD4;\n10C95;OLD HUNGARIAN CAPITAL LETTER UNK;Lu;0;R;;;;;N;;;;10CD5;\n10C96;OLD HUNGARIAN CAPITAL LETTER EL;Lu;0;R;;;;;N;;;;10CD6;\n10C97;OLD HUNGARIAN CAPITAL LETTER ELY;Lu;0;R;;;;;N;;;;10CD7;\n10C98;OLD HUNGARIAN CAPITAL LETTER EM;Lu;0;R;;;;;N;;;;10CD8;\n10C99;OLD HUNGARIAN CAPITAL LETTER EN;Lu;0;R;;;;;N;;;;10CD9;\n10C9A;OLD HUNGARIAN CAPITAL LETTER ENY;Lu;0;R;;;;;N;;;;10CDA;\n10C9B;OLD HUNGARIAN CAPITAL LETTER O;Lu;0;R;;;;;N;;;;10CDB;\n10C9C;OLD HUNGARIAN CAPITAL LETTER OO;Lu;0;R;;;;;N;;;;10CDC;\n10C9D;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE;Lu;0;R;;;;;N;;;;10CDD;\n10C9E;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE;Lu;0;R;;;;;N;;;;10CDE;\n10C9F;OLD HUNGARIAN CAPITAL LETTER OEE;Lu;0;R;;;;;N;;;;10CDF;\n10CA0;OLD HUNGARIAN CAPITAL LETTER EP;Lu;0;R;;;;;N;;;;10CE0;\n10CA1;OLD HUNGARIAN CAPITAL LETTER EMP;Lu;0;R;;;;;N;;;;10CE1;\n10CA2;OLD HUNGARIAN CAPITAL LETTER ER;Lu;0;R;;;;;N;;;;10CE2;\n10CA3;OLD HUNGARIAN CAPITAL LETTER SHORT ER;Lu;0;R;;;;;N;;;;10CE3;\n10CA4;OLD HUNGARIAN CAPITAL LETTER ES;Lu;0;R;;;;;N;;;;10CE4;\n10CA5;OLD HUNGARIAN CAPITAL LETTER ESZ;Lu;0;R;;;;;N;;;;10CE5;\n10CA6;OLD HUNGARIAN CAPITAL LETTER ET;Lu;0;R;;;;;N;;;;10CE6;\n10CA7;OLD HUNGARIAN CAPITAL LETTER ENT;Lu;0;R;;;;;N;;;;10CE7;\n10CA8;OLD HUNGARIAN CAPITAL LETTER ETY;Lu;0;R;;;;;N;;;;10CE8;\n10CA9;OLD HUNGARIAN CAPITAL LETTER ECH;Lu;0;R;;;;;N;;;;10CE9;\n10CAA;OLD HUNGARIAN CAPITAL LETTER U;Lu;0;R;;;;;N;;;;10CEA;\n10CAB;OLD HUNGARIAN CAPITAL LETTER UU;Lu;0;R;;;;;N;;;;10CEB;\n10CAC;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE;Lu;0;R;;;;;N;;;;10CEC;\n10CAD;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE;Lu;0;R;;;;;N;;;;10CED;\n10CAE;OLD HUNGARIAN CAPITAL LETTER EV;Lu;0;R;;;;;N;;;;10CEE;\n10CAF;OLD HUNGARIAN CAPITAL LETTER EZ;Lu;0;R;;;;;N;;;;10CEF;\n10CB0;OLD HUNGARIAN CAPITAL LETTER EZS;Lu;0;R;;;;;N;;;;10CF0;\n10CB1;OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN;Lu;0;R;;;;;N;;;;10CF1;\n10CB2;OLD HUNGARIAN CAPITAL LETTER US;Lu;0;R;;;;;N;;;;10CF2;\n10CC0;OLD HUNGARIAN SMALL LETTER A;Ll;0;R;;;;;N;;;10C80;;10C80\n10CC1;OLD HUNGARIAN SMALL LETTER AA;Ll;0;R;;;;;N;;;10C81;;10C81\n10CC2;OLD HUNGARIAN SMALL LETTER EB;Ll;0;R;;;;;N;;;10C82;;10C82\n10CC3;OLD HUNGARIAN SMALL LETTER AMB;Ll;0;R;;;;;N;;;10C83;;10C83\n10CC4;OLD HUNGARIAN SMALL LETTER EC;Ll;0;R;;;;;N;;;10C84;;10C84\n10CC5;OLD HUNGARIAN SMALL LETTER ENC;Ll;0;R;;;;;N;;;10C85;;10C85\n10CC6;OLD HUNGARIAN SMALL LETTER ECS;Ll;0;R;;;;;N;;;10C86;;10C86\n10CC7;OLD HUNGARIAN SMALL LETTER ED;Ll;0;R;;;;;N;;;10C87;;10C87\n10CC8;OLD HUNGARIAN SMALL LETTER AND;Ll;0;R;;;;;N;;;10C88;;10C88\n10CC9;OLD HUNGARIAN SMALL LETTER E;Ll;0;R;;;;;N;;;10C89;;10C89\n10CCA;OLD HUNGARIAN SMALL LETTER CLOSE E;Ll;0;R;;;;;N;;;10C8A;;10C8A\n10CCB;OLD HUNGARIAN SMALL LETTER EE;Ll;0;R;;;;;N;;;10C8B;;10C8B\n10CCC;OLD HUNGARIAN SMALL LETTER EF;Ll;0;R;;;;;N;;;10C8C;;10C8C\n10CCD;OLD HUNGARIAN SMALL LETTER EG;Ll;0;R;;;;;N;;;10C8D;;10C8D\n10CCE;OLD HUNGARIAN SMALL LETTER EGY;Ll;0;R;;;;;N;;;10C8E;;10C8E\n10CCF;OLD HUNGARIAN SMALL LETTER EH;Ll;0;R;;;;;N;;;10C8F;;10C8F\n10CD0;OLD HUNGARIAN SMALL LETTER I;Ll;0;R;;;;;N;;;10C90;;10C90\n10CD1;OLD HUNGARIAN SMALL LETTER II;Ll;0;R;;;;;N;;;10C91;;10C91\n10CD2;OLD HUNGARIAN SMALL LETTER EJ;Ll;0;R;;;;;N;;;10C92;;10C92\n10CD3;OLD HUNGARIAN SMALL LETTER EK;Ll;0;R;;;;;N;;;10C93;;10C93\n10CD4;OLD HUNGARIAN SMALL LETTER AK;Ll;0;R;;;;;N;;;10C94;;10C94\n10CD5;OLD HUNGARIAN SMALL LETTER UNK;Ll;0;R;;;;;N;;;10C95;;10C95\n10CD6;OLD HUNGARIAN SMALL LETTER EL;Ll;0;R;;;;;N;;;10C96;;10C96\n10CD7;OLD HUNGARIAN SMALL LETTER ELY;Ll;0;R;;;;;N;;;10C97;;10C97\n10CD8;OLD HUNGARIAN SMALL LETTER EM;Ll;0;R;;;;;N;;;10C98;;10C98\n10CD9;OLD HUNGARIAN SMALL LETTER EN;Ll;0;R;;;;;N;;;10C99;;10C99\n10CDA;OLD HUNGARIAN SMALL LETTER ENY;Ll;0;R;;;;;N;;;10C9A;;10C9A\n10CDB;OLD HUNGARIAN SMALL LETTER O;Ll;0;R;;;;;N;;;10C9B;;10C9B\n10CDC;OLD HUNGARIAN SMALL LETTER OO;Ll;0;R;;;;;N;;;10C9C;;10C9C\n10CDD;OLD HUNGARIAN SMALL LETTER NIKOLSBURG OE;Ll;0;R;;;;;N;;;10C9D;;10C9D\n10CDE;OLD HUNGARIAN SMALL LETTER RUDIMENTA OE;Ll;0;R;;;;;N;;;10C9E;;10C9E\n10CDF;OLD HUNGARIAN SMALL LETTER OEE;Ll;0;R;;;;;N;;;10C9F;;10C9F\n10CE0;OLD HUNGARIAN SMALL LETTER EP;Ll;0;R;;;;;N;;;10CA0;;10CA0\n10CE1;OLD HUNGARIAN SMALL LETTER EMP;Ll;0;R;;;;;N;;;10CA1;;10CA1\n10CE2;OLD HUNGARIAN SMALL LETTER ER;Ll;0;R;;;;;N;;;10CA2;;10CA2\n10CE3;OLD HUNGARIAN SMALL LETTER SHORT ER;Ll;0;R;;;;;N;;;10CA3;;10CA3\n10CE4;OLD HUNGARIAN SMALL LETTER ES;Ll;0;R;;;;;N;;;10CA4;;10CA4\n10CE5;OLD HUNGARIAN SMALL LETTER ESZ;Ll;0;R;;;;;N;;;10CA5;;10CA5\n10CE6;OLD HUNGARIAN SMALL LETTER ET;Ll;0;R;;;;;N;;;10CA6;;10CA6\n10CE7;OLD HUNGARIAN SMALL LETTER ENT;Ll;0;R;;;;;N;;;10CA7;;10CA7\n10CE8;OLD HUNGARIAN SMALL LETTER ETY;Ll;0;R;;;;;N;;;10CA8;;10CA8\n10CE9;OLD HUNGARIAN SMALL LETTER ECH;Ll;0;R;;;;;N;;;10CA9;;10CA9\n10CEA;OLD HUNGARIAN SMALL LETTER U;Ll;0;R;;;;;N;;;10CAA;;10CAA\n10CEB;OLD HUNGARIAN SMALL LETTER UU;Ll;0;R;;;;;N;;;10CAB;;10CAB\n10CEC;OLD HUNGARIAN SMALL LETTER NIKOLSBURG UE;Ll;0;R;;;;;N;;;10CAC;;10CAC\n10CED;OLD HUNGARIAN SMALL LETTER RUDIMENTA UE;Ll;0;R;;;;;N;;;10CAD;;10CAD\n10CEE;OLD HUNGARIAN SMALL LETTER EV;Ll;0;R;;;;;N;;;10CAE;;10CAE\n10CEF;OLD HUNGARIAN SMALL LETTER EZ;Ll;0;R;;;;;N;;;10CAF;;10CAF\n10CF0;OLD HUNGARIAN SMALL LETTER EZS;Ll;0;R;;;;;N;;;10CB0;;10CB0\n10CF1;OLD HUNGARIAN SMALL LETTER ENT-SHAPED SIGN;Ll;0;R;;;;;N;;;10CB1;;10CB1\n10CF2;OLD HUNGARIAN SMALL LETTER US;Ll;0;R;;;;;N;;;10CB2;;10CB2\n10CFA;OLD HUNGARIAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n10CFB;OLD HUNGARIAN NUMBER FIVE;No;0;R;;;;5;N;;;;;\n10CFC;OLD HUNGARIAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n10CFD;OLD HUNGARIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;;\n10CFE;OLD HUNGARIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10CFF;OLD HUNGARIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;\n10D00;HANIFI ROHINGYA LETTER A;Lo;0;AL;;;;;N;;;;;\n10D01;HANIFI ROHINGYA LETTER BA;Lo;0;AL;;;;;N;;;;;\n10D02;HANIFI ROHINGYA LETTER PA;Lo;0;AL;;;;;N;;;;;\n10D03;HANIFI ROHINGYA LETTER TA;Lo;0;AL;;;;;N;;;;;\n10D04;HANIFI ROHINGYA LETTER TTA;Lo;0;AL;;;;;N;;;;;\n10D05;HANIFI ROHINGYA LETTER JA;Lo;0;AL;;;;;N;;;;;\n10D06;HANIFI ROHINGYA LETTER CA;Lo;0;AL;;;;;N;;;;;\n10D07;HANIFI ROHINGYA LETTER HA;Lo;0;AL;;;;;N;;;;;\n10D08;HANIFI ROHINGYA LETTER KHA;Lo;0;AL;;;;;N;;;;;\n10D09;HANIFI ROHINGYA LETTER FA;Lo;0;AL;;;;;N;;;;;\n10D0A;HANIFI ROHINGYA LETTER DA;Lo;0;AL;;;;;N;;;;;\n10D0B;HANIFI ROHINGYA LETTER DDA;Lo;0;AL;;;;;N;;;;;\n10D0C;HANIFI ROHINGYA LETTER RA;Lo;0;AL;;;;;N;;;;;\n10D0D;HANIFI ROHINGYA LETTER RRA;Lo;0;AL;;;;;N;;;;;\n10D0E;HANIFI ROHINGYA LETTER ZA;Lo;0;AL;;;;;N;;;;;\n10D0F;HANIFI ROHINGYA LETTER SA;Lo;0;AL;;;;;N;;;;;\n10D10;HANIFI ROHINGYA LETTER SHA;Lo;0;AL;;;;;N;;;;;\n10D11;HANIFI ROHINGYA LETTER KA;Lo;0;AL;;;;;N;;;;;\n10D12;HANIFI ROHINGYA LETTER GA;Lo;0;AL;;;;;N;;;;;\n10D13;HANIFI ROHINGYA LETTER LA;Lo;0;AL;;;;;N;;;;;\n10D14;HANIFI ROHINGYA LETTER MA;Lo;0;AL;;;;;N;;;;;\n10D15;HANIFI ROHINGYA LETTER NA;Lo;0;AL;;;;;N;;;;;\n10D16;HANIFI ROHINGYA LETTER WA;Lo;0;AL;;;;;N;;;;;\n10D17;HANIFI ROHINGYA LETTER KINNA WA;Lo;0;AL;;;;;N;;;;;\n10D18;HANIFI ROHINGYA LETTER YA;Lo;0;AL;;;;;N;;;;;\n10D19;HANIFI ROHINGYA LETTER KINNA YA;Lo;0;AL;;;;;N;;;;;\n10D1A;HANIFI ROHINGYA LETTER NGA;Lo;0;AL;;;;;N;;;;;\n10D1B;HANIFI ROHINGYA LETTER NYA;Lo;0;AL;;;;;N;;;;;\n10D1C;HANIFI ROHINGYA LETTER VA;Lo;0;AL;;;;;N;;;;;\n10D1D;HANIFI ROHINGYA VOWEL A;Lo;0;AL;;;;;N;;;;;\n10D1E;HANIFI ROHINGYA VOWEL I;Lo;0;AL;;;;;N;;;;;\n10D1F;HANIFI ROHINGYA VOWEL U;Lo;0;AL;;;;;N;;;;;\n10D20;HANIFI ROHINGYA VOWEL E;Lo;0;AL;;;;;N;;;;;\n10D21;HANIFI ROHINGYA VOWEL O;Lo;0;AL;;;;;N;;;;;\n10D22;HANIFI ROHINGYA MARK SAKIN;Lo;0;AL;;;;;N;;;;;\n10D23;HANIFI ROHINGYA MARK NA KHONNA;Lo;0;AL;;;;;N;;;;;\n10D24;HANIFI ROHINGYA SIGN HARBAHAY;Mn;230;NSM;;;;;N;;;;;\n10D25;HANIFI ROHINGYA SIGN TAHALA;Mn;230;NSM;;;;;N;;;;;\n10D26;HANIFI ROHINGYA SIGN TANA;Mn;230;NSM;;;;;N;;;;;\n10D27;HANIFI ROHINGYA SIGN TASSI;Mn;230;NSM;;;;;N;;;;;\n10D30;HANIFI ROHINGYA DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;\n10D31;HANIFI ROHINGYA DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;\n10D32;HANIFI ROHINGYA DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;\n10D33;HANIFI ROHINGYA DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;\n10D34;HANIFI ROHINGYA DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;\n10D35;HANIFI ROHINGYA DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;\n10D36;HANIFI ROHINGYA DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;\n10D37;HANIFI ROHINGYA DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;\n10D38;HANIFI ROHINGYA DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;\n10D39;HANIFI ROHINGYA DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;\n10D40;GARAY DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;\n10D41;GARAY DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;\n10D42;GARAY DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;\n10D43;GARAY DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;\n10D44;GARAY DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;\n10D45;GARAY DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;\n10D46;GARAY DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;\n10D47;GARAY DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;\n10D48;GARAY DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;\n10D49;GARAY DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;\n10D4A;GARAY VOWEL SIGN A;Lo;0;R;;;;;N;;;;;\n10D4B;GARAY VOWEL SIGN I;Lo;0;R;;;;;N;;;;;\n10D4C;GARAY VOWEL SIGN O;Lo;0;R;;;;;N;;;;;\n10D4D;GARAY VOWEL SIGN EE;Lo;0;R;;;;;N;;;;;\n10D4E;GARAY VOWEL LENGTH MARK;Lm;0;R;;;;;N;;;;;\n10D4F;GARAY SUKUN;Lo;0;R;;;;;N;;;;;\n10D50;GARAY CAPITAL LETTER A;Lu;0;R;;;;;N;;;;10D70;\n10D51;GARAY CAPITAL LETTER CA;Lu;0;R;;;;;N;;;;10D71;\n10D52;GARAY CAPITAL LETTER MA;Lu;0;R;;;;;N;;;;10D72;\n10D53;GARAY CAPITAL LETTER KA;Lu;0;R;;;;;N;;;;10D73;\n10D54;GARAY CAPITAL LETTER BA;Lu;0;R;;;;;N;;;;10D74;\n10D55;GARAY CAPITAL LETTER JA;Lu;0;R;;;;;N;;;;10D75;\n10D56;GARAY CAPITAL LETTER SA;Lu;0;R;;;;;N;;;;10D76;\n10D57;GARAY CAPITAL LETTER WA;Lu;0;R;;;;;N;;;;10D77;\n10D58;GARAY CAPITAL LETTER LA;Lu;0;R;;;;;N;;;;10D78;\n10D59;GARAY CAPITAL LETTER GA;Lu;0;R;;;;;N;;;;10D79;\n10D5A;GARAY CAPITAL LETTER DA;Lu;0;R;;;;;N;;;;10D7A;\n10D5B;GARAY CAPITAL LETTER XA;Lu;0;R;;;;;N;;;;10D7B;\n10D5C;GARAY CAPITAL LETTER YA;Lu;0;R;;;;;N;;;;10D7C;\n10D5D;GARAY CAPITAL LETTER TA;Lu;0;R;;;;;N;;;;10D7D;\n10D5E;GARAY CAPITAL LETTER RA;Lu;0;R;;;;;N;;;;10D7E;\n10D5F;GARAY CAPITAL LETTER NYA;Lu;0;R;;;;;N;;;;10D7F;\n10D60;GARAY CAPITAL LETTER FA;Lu;0;R;;;;;N;;;;10D80;\n10D61;GARAY CAPITAL LETTER NA;Lu;0;R;;;;;N;;;;10D81;\n10D62;GARAY CAPITAL LETTER PA;Lu;0;R;;;;;N;;;;10D82;\n10D63;GARAY CAPITAL LETTER HA;Lu;0;R;;;;;N;;;;10D83;\n10D64;GARAY CAPITAL LETTER OLD KA;Lu;0;R;;;;;N;;;;10D84;\n10D65;GARAY CAPITAL LETTER OLD NA;Lu;0;R;;;;;N;;;;10D85;\n10D69;GARAY VOWEL SIGN E;Mn;230;NSM;;;;;N;;;;;\n10D6A;GARAY CONSONANT GEMINATION MARK;Mn;230;NSM;;;;;N;;;;;\n10D6B;GARAY COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;;\n10D6C;GARAY COMBINING DOUBLE DOT ABOVE;Mn;230;NSM;;;;;N;;;;;\n10D6D;GARAY CONSONANT NASALIZATION MARK;Mn;230;NSM;;;;;N;;;;;\n10D6E;GARAY HYPHEN;Pd;0;ON;;;;;N;;;;;\n10D6F;GARAY REDUPLICATION MARK;Lm;0;R;;;;;N;;;;;\n10D70;GARAY SMALL LETTER A;Ll;0;R;;;;;N;;;10D50;;10D50\n10D71;GARAY SMALL LETTER CA;Ll;0;R;;;;;N;;;10D51;;10D51\n10D72;GARAY SMALL LETTER MA;Ll;0;R;;;;;N;;;10D52;;10D52\n10D73;GARAY SMALL LETTER KA;Ll;0;R;;;;;N;;;10D53;;10D53\n10D74;GARAY SMALL LETTER BA;Ll;0;R;;;;;N;;;10D54;;10D54\n10D75;GARAY SMALL LETTER JA;Ll;0;R;;;;;N;;;10D55;;10D55\n10D76;GARAY SMALL LETTER SA;Ll;0;R;;;;;N;;;10D56;;10D56\n10D77;GARAY SMALL LETTER WA;Ll;0;R;;;;;N;;;10D57;;10D57\n10D78;GARAY SMALL LETTER LA;Ll;0;R;;;;;N;;;10D58;;10D58\n10D79;GARAY SMALL LETTER GA;Ll;0;R;;;;;N;;;10D59;;10D59\n10D7A;GARAY SMALL LETTER DA;Ll;0;R;;;;;N;;;10D5A;;10D5A\n10D7B;GARAY SMALL LETTER XA;Ll;0;R;;;;;N;;;10D5B;;10D5B\n10D7C;GARAY SMALL LETTER YA;Ll;0;R;;;;;N;;;10D5C;;10D5C\n10D7D;GARAY SMALL LETTER TA;Ll;0;R;;;;;N;;;10D5D;;10D5D\n10D7E;GARAY SMALL LETTER RA;Ll;0;R;;;;;N;;;10D5E;;10D5E\n10D7F;GARAY SMALL LETTER NYA;Ll;0;R;;;;;N;;;10D5F;;10D5F\n10D80;GARAY SMALL LETTER FA;Ll;0;R;;;;;N;;;10D60;;10D60\n10D81;GARAY SMALL LETTER NA;Ll;0;R;;;;;N;;;10D61;;10D61\n10D82;GARAY SMALL LETTER PA;Ll;0;R;;;;;N;;;10D62;;10D62\n10D83;GARAY SMALL LETTER HA;Ll;0;R;;;;;N;;;10D63;;10D63\n10D84;GARAY SMALL LETTER OLD KA;Ll;0;R;;;;;N;;;10D64;;10D64\n10D85;GARAY SMALL LETTER OLD NA;Ll;0;R;;;;;N;;;10D65;;10D65\n10D8E;GARAY PLUS SIGN;Sm;0;R;;;;;N;;;;;\n10D8F;GARAY MINUS SIGN;Sm;0;R;;;;;N;;;;;\n10E60;RUMI DIGIT ONE;No;0;AN;;;1;1;N;;;;;\n10E61;RUMI DIGIT TWO;No;0;AN;;;2;2;N;;;;;\n10E62;RUMI DIGIT THREE;No;0;AN;;;3;3;N;;;;;\n10E63;RUMI DIGIT FOUR;No;0;AN;;;4;4;N;;;;;\n10E64;RUMI DIGIT FIVE;No;0;AN;;;5;5;N;;;;;\n10E65;RUMI DIGIT SIX;No;0;AN;;;6;6;N;;;;;\n10E66;RUMI DIGIT SEVEN;No;0;AN;;;7;7;N;;;;;\n10E67;RUMI DIGIT EIGHT;No;0;AN;;;8;8;N;;;;;\n10E68;RUMI DIGIT NINE;No;0;AN;;;9;9;N;;;;;\n10E69;RUMI NUMBER TEN;No;0;AN;;;;10;N;;;;;\n10E6A;RUMI NUMBER TWENTY;No;0;AN;;;;20;N;;;;;\n10E6B;RUMI NUMBER THIRTY;No;0;AN;;;;30;N;;;;;\n10E6C;RUMI NUMBER FORTY;No;0;AN;;;;40;N;;;;;\n10E6D;RUMI NUMBER FIFTY;No;0;AN;;;;50;N;;;;;\n10E6E;RUMI NUMBER SIXTY;No;0;AN;;;;60;N;;;;;\n10E6F;RUMI NUMBER SEVENTY;No;0;AN;;;;70;N;;;;;\n10E70;RUMI NUMBER EIGHTY;No;0;AN;;;;80;N;;;;;\n10E71;RUMI NUMBER NINETY;No;0;AN;;;;90;N;;;;;\n10E72;RUMI NUMBER ONE HUNDRED;No;0;AN;;;;100;N;;;;;\n10E73;RUMI NUMBER TWO HUNDRED;No;0;AN;;;;200;N;;;;;\n10E74;RUMI NUMBER THREE HUNDRED;No;0;AN;;;;300;N;;;;;\n10E75;RUMI NUMBER FOUR HUNDRED;No;0;AN;;;;400;N;;;;;\n10E76;RUMI NUMBER FIVE HUNDRED;No;0;AN;;;;500;N;;;;;\n10E77;RUMI NUMBER SIX HUNDRED;No;0;AN;;;;600;N;;;;;\n10E78;RUMI NUMBER SEVEN HUNDRED;No;0;AN;;;;700;N;;;;;\n10E79;RUMI NUMBER EIGHT HUNDRED;No;0;AN;;;;800;N;;;;;\n10E7A;RUMI NUMBER NINE HUNDRED;No;0;AN;;;;900;N;;;;;\n10E7B;RUMI FRACTION ONE HALF;No;0;AN;;;;1/2;N;;;;;\n10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;;\n10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;;\n10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;;\n10E80;YEZIDI LETTER ELIF;Lo;0;R;;;;;N;;;;;\n10E81;YEZIDI LETTER BE;Lo;0;R;;;;;N;;;;;\n10E82;YEZIDI LETTER PE;Lo;0;R;;;;;N;;;;;\n10E83;YEZIDI LETTER PHE;Lo;0;R;;;;;N;;;;;\n10E84;YEZIDI LETTER THE;Lo;0;R;;;;;N;;;;;\n10E85;YEZIDI LETTER SE;Lo;0;R;;;;;N;;;;;\n10E86;YEZIDI LETTER CIM;Lo;0;R;;;;;N;;;;;\n10E87;YEZIDI LETTER CHIM;Lo;0;R;;;;;N;;;;;\n10E88;YEZIDI LETTER CHHIM;Lo;0;R;;;;;N;;;;;\n10E89;YEZIDI LETTER HHA;Lo;0;R;;;;;N;;;;;\n10E8A;YEZIDI LETTER XA;Lo;0;R;;;;;N;;;;;\n10E8B;YEZIDI LETTER DAL;Lo;0;R;;;;;N;;;;;\n10E8C;YEZIDI LETTER ZAL;Lo;0;R;;;;;N;;;;;\n10E8D;YEZIDI LETTER RA;Lo;0;R;;;;;N;;;;;\n10E8E;YEZIDI LETTER RHA;Lo;0;R;;;;;N;;;;;\n10E8F;YEZIDI LETTER ZA;Lo;0;R;;;;;N;;;;;\n10E90;YEZIDI LETTER JA;Lo;0;R;;;;;N;;;;;\n10E91;YEZIDI LETTER SIN;Lo;0;R;;;;;N;;;;;\n10E92;YEZIDI LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10E93;YEZIDI LETTER SAD;Lo;0;R;;;;;N;;;;;\n10E94;YEZIDI LETTER DAD;Lo;0;R;;;;;N;;;;;\n10E95;YEZIDI LETTER TA;Lo;0;R;;;;;N;;;;;\n10E96;YEZIDI LETTER ZE;Lo;0;R;;;;;N;;;;;\n10E97;YEZIDI LETTER EYN;Lo;0;R;;;;;N;;;;;\n10E98;YEZIDI LETTER XHEYN;Lo;0;R;;;;;N;;;;;\n10E99;YEZIDI LETTER FA;Lo;0;R;;;;;N;;;;;\n10E9A;YEZIDI LETTER VA;Lo;0;R;;;;;N;;;;;\n10E9B;YEZIDI LETTER VA ALTERNATE FORM;Lo;0;R;;;;;N;;;;;\n10E9C;YEZIDI LETTER QAF;Lo;0;R;;;;;N;;;;;\n10E9D;YEZIDI LETTER KAF;Lo;0;R;;;;;N;;;;;\n10E9E;YEZIDI LETTER KHAF;Lo;0;R;;;;;N;;;;;\n10E9F;YEZIDI LETTER GAF;Lo;0;R;;;;;N;;;;;\n10EA0;YEZIDI LETTER LAM;Lo;0;R;;;;;N;;;;;\n10EA1;YEZIDI LETTER MIM;Lo;0;R;;;;;N;;;;;\n10EA2;YEZIDI LETTER NUN;Lo;0;R;;;;;N;;;;;\n10EA3;YEZIDI LETTER UM;Lo;0;R;;;;;N;;;;;\n10EA4;YEZIDI LETTER WAW;Lo;0;R;;;;;N;;;;;\n10EA5;YEZIDI LETTER OW;Lo;0;R;;;;;N;;;;;\n10EA6;YEZIDI LETTER EW;Lo;0;R;;;;;N;;;;;\n10EA7;YEZIDI LETTER HAY;Lo;0;R;;;;;N;;;;;\n10EA8;YEZIDI LETTER YOT;Lo;0;R;;;;;N;;;;;\n10EA9;YEZIDI LETTER ET;Lo;0;R;;;;;N;;;;;\n10EAB;YEZIDI COMBINING HAMZA MARK;Mn;230;NSM;;;;;N;;;;;\n10EAC;YEZIDI COMBINING MADDA MARK;Mn;230;NSM;;;;;N;;;;;\n10EAD;YEZIDI HYPHENATION MARK;Pd;0;R;;;;;N;;;;;\n10EB0;YEZIDI LETTER LAM WITH DOT ABOVE;Lo;0;R;;;;;N;;;;;\n10EB1;YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE;Lo;0;R;;;;;N;;;;;\n10EC2;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;;\n10EC3;ARABIC LETTER TAH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;;\n10EC4;ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;;\n10EC5;ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW;Lm;0;AL;;;;;N;;;;;\n10EC6;ARABIC LETTER THIN NOON;Lo;0;AL;;;;;N;;;;;\n10EC7;ARABIC LETTER YEH WITH FOUR DOTS BELOW;Lo;0;AL;;;;;N;;;;;\n10ED0;ARABIC BIBLICAL END OF VERSE;Po;0;ON;;;;;N;;;;;\n10ED1;ARABIC LIGATURE ALAYHAA AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;;\n10ED2;ARABIC LIGATURE ALAYHIM AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;;\n10ED3;ARABIC LIGATURE ALAYHIMAA AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;;\n10ED4;ARABIC LIGATURE QADDASA ALLAAHU SIRRAH;So;0;ON;;;;;N;;;;;\n10ED5;ARABIC LIGATURE QUDDISA SIRRUHUM;So;0;ON;;;;;N;;;;;\n10ED6;ARABIC LIGATURE QUDDISA SIRRUHUMAA;So;0;ON;;;;;N;;;;;\n10ED7;ARABIC LIGATURE QUDDISAT ASRAARUHUM;So;0;ON;;;;;N;;;;;\n10ED8;ARABIC LIGATURE NAWWARA ALLAAHU MARQADAH;So;0;ON;;;;;N;;;;;\n10EFA;ARABIC DOUBLE VERTICAL BAR BELOW;Mn;220;NSM;;;;;N;;;;;\n10EFB;ARABIC SMALL LOW NOON;Mn;220;NSM;;;;;N;;;;;\n10EFC;ARABIC COMBINING ALEF OVERLAY;Mn;0;NSM;;;;;N;;;;;\n10EFD;ARABIC SMALL LOW WORD SAKTA;Mn;220;NSM;;;;;N;;;;;\n10EFE;ARABIC SMALL LOW WORD QASR;Mn;220;NSM;;;;;N;;;;;\n10EFF;ARABIC SMALL LOW WORD MADDA;Mn;220;NSM;;;;;N;;;;;\n10F00;OLD SOGDIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10F01;OLD SOGDIAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;;\n10F02;OLD SOGDIAN LETTER BETH;Lo;0;R;;;;;N;;;;;\n10F03;OLD SOGDIAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;;\n10F04;OLD SOGDIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10F05;OLD SOGDIAN LETTER HE;Lo;0;R;;;;;N;;;;;\n10F06;OLD SOGDIAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;;\n10F07;OLD SOGDIAN LETTER WAW;Lo;0;R;;;;;N;;;;;\n10F08;OLD SOGDIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10F09;OLD SOGDIAN LETTER HETH;Lo;0;R;;;;;N;;;;;\n10F0A;OLD SOGDIAN LETTER YODH;Lo;0;R;;;;;N;;;;;\n10F0B;OLD SOGDIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10F0C;OLD SOGDIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10F0D;OLD SOGDIAN LETTER MEM;Lo;0;R;;;;;N;;;;;\n10F0E;OLD SOGDIAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n10F0F;OLD SOGDIAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;\n10F10;OLD SOGDIAN LETTER FINAL NUN WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;\n10F11;OLD SOGDIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10F12;OLD SOGDIAN LETTER AYIN;Lo;0;R;;;;;N;;;;;\n10F13;OLD SOGDIAN LETTER ALTERNATE AYIN;Lo;0;R;;;;;N;;;;;\n10F14;OLD SOGDIAN LETTER PE;Lo;0;R;;;;;N;;;;;\n10F15;OLD SOGDIAN LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10F16;OLD SOGDIAN LETTER FINAL SADHE;Lo;0;R;;;;;N;;;;;\n10F17;OLD SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;\n10F18;OLD SOGDIAN LETTER RESH-AYIN-DALETH;Lo;0;R;;;;;N;;;;;\n10F19;OLD SOGDIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10F1A;OLD SOGDIAN LETTER TAW;Lo;0;R;;;;;N;;;;;\n10F1B;OLD SOGDIAN LETTER FINAL TAW;Lo;0;R;;;;;N;;;;;\n10F1C;OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;\n10F1D;OLD SOGDIAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n10F1E;OLD SOGDIAN NUMBER TWO;No;0;R;;;;2;N;;;;;\n10F1F;OLD SOGDIAN NUMBER THREE;No;0;R;;;;3;N;;;;;\n10F20;OLD SOGDIAN NUMBER FOUR;No;0;R;;;;4;N;;;;;\n10F21;OLD SOGDIAN NUMBER FIVE;No;0;R;;;;5;N;;;;;\n10F22;OLD SOGDIAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n10F23;OLD SOGDIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10F24;OLD SOGDIAN NUMBER THIRTY;No;0;R;;;;30;N;;;;;\n10F25;OLD SOGDIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10F26;OLD SOGDIAN FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;;\n10F27;OLD SOGDIAN LIGATURE AYIN-DALETH;Lo;0;R;;;;;N;;;;;\n10F30;SOGDIAN LETTER ALEPH;Lo;0;AL;;;;;N;;;;;\n10F31;SOGDIAN LETTER BETH;Lo;0;AL;;;;;N;;;;;\n10F32;SOGDIAN LETTER GIMEL;Lo;0;AL;;;;;N;;;;;\n10F33;SOGDIAN LETTER HE;Lo;0;AL;;;;;N;;;;;\n10F34;SOGDIAN LETTER WAW;Lo;0;AL;;;;;N;;;;;\n10F35;SOGDIAN LETTER ZAYIN;Lo;0;AL;;;;;N;;;;;\n10F36;SOGDIAN LETTER HETH;Lo;0;AL;;;;;N;;;;;\n10F37;SOGDIAN LETTER YODH;Lo;0;AL;;;;;N;;;;;\n10F38;SOGDIAN LETTER KAPH;Lo;0;AL;;;;;N;;;;;\n10F39;SOGDIAN LETTER LAMEDH;Lo;0;AL;;;;;N;;;;;\n10F3A;SOGDIAN LETTER MEM;Lo;0;AL;;;;;N;;;;;\n10F3B;SOGDIAN LETTER NUN;Lo;0;AL;;;;;N;;;;;\n10F3C;SOGDIAN LETTER SAMEKH;Lo;0;AL;;;;;N;;;;;\n10F3D;SOGDIAN LETTER AYIN;Lo;0;AL;;;;;N;;;;;\n10F3E;SOGDIAN LETTER PE;Lo;0;AL;;;;;N;;;;;\n10F3F;SOGDIAN LETTER SADHE;Lo;0;AL;;;;;N;;;;;\n10F40;SOGDIAN LETTER RESH-AYIN;Lo;0;AL;;;;;N;;;;;\n10F41;SOGDIAN LETTER SHIN;Lo;0;AL;;;;;N;;;;;\n10F42;SOGDIAN LETTER TAW;Lo;0;AL;;;;;N;;;;;\n10F43;SOGDIAN LETTER FETH;Lo;0;AL;;;;;N;;;;;\n10F44;SOGDIAN LETTER LESH;Lo;0;AL;;;;;N;;;;;\n10F45;SOGDIAN INDEPENDENT SHIN;Lo;0;AL;;;;;N;;;;;\n10F46;SOGDIAN COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;;\n10F47;SOGDIAN COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;;\n10F48;SOGDIAN COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;;\n10F49;SOGDIAN COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;\n10F4A;SOGDIAN COMBINING CURVE ABOVE;Mn;230;NSM;;;;;N;;;;;\n10F4B;SOGDIAN COMBINING CURVE BELOW;Mn;220;NSM;;;;;N;;;;;\n10F4C;SOGDIAN COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;;;;;\n10F4D;SOGDIAN COMBINING HOOK BELOW;Mn;220;NSM;;;;;N;;;;;\n10F4E;SOGDIAN COMBINING LONG HOOK BELOW;Mn;220;NSM;;;;;N;;;;;\n10F4F;SOGDIAN COMBINING RESH BELOW;Mn;220;NSM;;;;;N;;;;;\n10F50;SOGDIAN COMBINING STROKE BELOW;Mn;220;NSM;;;;;N;;;;;\n10F51;SOGDIAN NUMBER ONE;No;0;AL;;;;1;N;;;;;\n10F52;SOGDIAN NUMBER TEN;No;0;AL;;;;10;N;;;;;\n10F53;SOGDIAN NUMBER TWENTY;No;0;AL;;;;20;N;;;;;\n10F54;SOGDIAN NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;;\n10F55;SOGDIAN PUNCTUATION TWO VERTICAL BARS;Po;0;AL;;;;;N;;;;;\n10F56;SOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTS;Po;0;AL;;;;;N;;;;;\n10F57;SOGDIAN PUNCTUATION CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;;\n10F58;SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS;Po;0;AL;;;;;N;;;;;\n10F59;SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;;\n10F70;OLD UYGHUR LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10F71;OLD UYGHUR LETTER BETH;Lo;0;R;;;;;N;;;;;\n10F72;OLD UYGHUR LETTER GIMEL-HETH;Lo;0;R;;;;;N;;;;;\n10F73;OLD UYGHUR LETTER WAW;Lo;0;R;;;;;N;;;;;\n10F74;OLD UYGHUR LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10F75;OLD UYGHUR LETTER FINAL HETH;Lo;0;R;;;;;N;;;;;\n10F76;OLD UYGHUR LETTER YODH;Lo;0;R;;;;;N;;;;;\n10F77;OLD UYGHUR LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10F78;OLD UYGHUR LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10F79;OLD UYGHUR LETTER MEM;Lo;0;R;;;;;N;;;;;\n10F7A;OLD UYGHUR LETTER NUN;Lo;0;R;;;;;N;;;;;\n10F7B;OLD UYGHUR LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10F7C;OLD UYGHUR LETTER PE;Lo;0;R;;;;;N;;;;;\n10F7D;OLD UYGHUR LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10F7E;OLD UYGHUR LETTER RESH;Lo;0;R;;;;;N;;;;;\n10F7F;OLD UYGHUR LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10F80;OLD UYGHUR LETTER TAW;Lo;0;R;;;;;N;;;;;\n10F81;OLD UYGHUR LETTER LESH;Lo;0;R;;;;;N;;;;;\n10F82;OLD UYGHUR COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;;\n10F83;OLD UYGHUR COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;;\n10F84;OLD UYGHUR COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;\n10F85;OLD UYGHUR COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;;\n10F86;OLD UYGHUR PUNCTUATION BAR;Po;0;R;;;;;N;;;;;\n10F87;OLD UYGHUR PUNCTUATION TWO BARS;Po;0;R;;;;;N;;;;;\n10F88;OLD UYGHUR PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;;\n10F89;OLD UYGHUR PUNCTUATION FOUR DOTS;Po;0;R;;;;;N;;;;;\n10FB0;CHORASMIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10FB1;CHORASMIAN LETTER SMALL ALEPH;Lo;0;R;;;;;N;;;;;\n10FB2;CHORASMIAN LETTER BETH;Lo;0;R;;;;;N;;;;;\n10FB3;CHORASMIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10FB4;CHORASMIAN LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10FB5;CHORASMIAN LETTER HE;Lo;0;R;;;;;N;;;;;\n10FB6;CHORASMIAN LETTER WAW;Lo;0;R;;;;;N;;;;;\n10FB7;CHORASMIAN LETTER CURLED WAW;Lo;0;R;;;;;N;;;;;\n10FB8;CHORASMIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10FB9;CHORASMIAN LETTER HETH;Lo;0;R;;;;;N;;;;;\n10FBA;CHORASMIAN LETTER YODH;Lo;0;R;;;;;N;;;;;\n10FBB;CHORASMIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10FBC;CHORASMIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10FBD;CHORASMIAN LETTER MEM;Lo;0;R;;;;;N;;;;;\n10FBE;CHORASMIAN LETTER NUN;Lo;0;R;;;;;N;;;;;\n10FBF;CHORASMIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10FC0;CHORASMIAN LETTER AYIN;Lo;0;R;;;;;N;;;;;\n10FC1;CHORASMIAN LETTER PE;Lo;0;R;;;;;N;;;;;\n10FC2;CHORASMIAN LETTER RESH;Lo;0;R;;;;;N;;;;;\n10FC3;CHORASMIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10FC4;CHORASMIAN LETTER TAW;Lo;0;R;;;;;N;;;;;\n10FC5;CHORASMIAN NUMBER ONE;No;0;R;;;;1;N;;;;;\n10FC6;CHORASMIAN NUMBER TWO;No;0;R;;;;2;N;;;;;\n10FC7;CHORASMIAN NUMBER THREE;No;0;R;;;;3;N;;;;;\n10FC8;CHORASMIAN NUMBER FOUR;No;0;R;;;;4;N;;;;;\n10FC9;CHORASMIAN NUMBER TEN;No;0;R;;;;10;N;;;;;\n10FCA;CHORASMIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;\n10FCB;CHORASMIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;\n10FE0;ELYMAIC LETTER ALEPH;Lo;0;R;;;;;N;;;;;\n10FE1;ELYMAIC LETTER BETH;Lo;0;R;;;;;N;;;;;\n10FE2;ELYMAIC LETTER GIMEL;Lo;0;R;;;;;N;;;;;\n10FE3;ELYMAIC LETTER DALETH;Lo;0;R;;;;;N;;;;;\n10FE4;ELYMAIC LETTER HE;Lo;0;R;;;;;N;;;;;\n10FE5;ELYMAIC LETTER WAW;Lo;0;R;;;;;N;;;;;\n10FE6;ELYMAIC LETTER ZAYIN;Lo;0;R;;;;;N;;;;;\n10FE7;ELYMAIC LETTER HETH;Lo;0;R;;;;;N;;;;;\n10FE8;ELYMAIC LETTER TETH;Lo;0;R;;;;;N;;;;;\n10FE9;ELYMAIC LETTER YODH;Lo;0;R;;;;;N;;;;;\n10FEA;ELYMAIC LETTER KAPH;Lo;0;R;;;;;N;;;;;\n10FEB;ELYMAIC LETTER LAMEDH;Lo;0;R;;;;;N;;;;;\n10FEC;ELYMAIC LETTER MEM;Lo;0;R;;;;;N;;;;;\n10FED;ELYMAIC LETTER NUN;Lo;0;R;;;;;N;;;;;\n10FEE;ELYMAIC LETTER SAMEKH;Lo;0;R;;;;;N;;;;;\n10FEF;ELYMAIC LETTER AYIN;Lo;0;R;;;;;N;;;;;\n10FF0;ELYMAIC LETTER PE;Lo;0;R;;;;;N;;;;;\n10FF1;ELYMAIC LETTER SADHE;Lo;0;R;;;;;N;;;;;\n10FF2;ELYMAIC LETTER QOPH;Lo;0;R;;;;;N;;;;;\n10FF3;ELYMAIC LETTER RESH;Lo;0;R;;;;;N;;;;;\n10FF4;ELYMAIC LETTER SHIN;Lo;0;R;;;;;N;;;;;\n10FF5;ELYMAIC LETTER TAW;Lo;0;R;;;;;N;;;;;\n10FF6;ELYMAIC LIGATURE ZAYIN-YODH;Lo;0;R;;;;;N;;;;;\n11000;BRAHMI SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;\n11001;BRAHMI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11002;BRAHMI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11003;BRAHMI SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;\n11004;BRAHMI SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;\n11005;BRAHMI LETTER A;Lo;0;L;;;;;N;;;;;\n11006;BRAHMI LETTER AA;Lo;0;L;;;;;N;;;;;\n11007;BRAHMI LETTER I;Lo;0;L;;;;;N;;;;;\n11008;BRAHMI LETTER II;Lo;0;L;;;;;N;;;;;\n11009;BRAHMI LETTER U;Lo;0;L;;;;;N;;;;;\n1100A;BRAHMI LETTER UU;Lo;0;L;;;;;N;;;;;\n1100B;BRAHMI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n1100C;BRAHMI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n1100D;BRAHMI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n1100E;BRAHMI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n1100F;BRAHMI LETTER E;Lo;0;L;;;;;N;;;;;\n11010;BRAHMI LETTER AI;Lo;0;L;;;;;N;;;;;\n11011;BRAHMI LETTER O;Lo;0;L;;;;;N;;;;;\n11012;BRAHMI LETTER AU;Lo;0;L;;;;;N;;;;;\n11013;BRAHMI LETTER KA;Lo;0;L;;;;;N;;;;;\n11014;BRAHMI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11015;BRAHMI LETTER GA;Lo;0;L;;;;;N;;;;;\n11016;BRAHMI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11017;BRAHMI LETTER NGA;Lo;0;L;;;;;N;;;;;\n11018;BRAHMI LETTER CA;Lo;0;L;;;;;N;;;;;\n11019;BRAHMI LETTER CHA;Lo;0;L;;;;;N;;;;;\n1101A;BRAHMI LETTER JA;Lo;0;L;;;;;N;;;;;\n1101B;BRAHMI LETTER JHA;Lo;0;L;;;;;N;;;;;\n1101C;BRAHMI LETTER NYA;Lo;0;L;;;;;N;;;;;\n1101D;BRAHMI LETTER TTA;Lo;0;L;;;;;N;;;;;\n1101E;BRAHMI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1101F;BRAHMI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11020;BRAHMI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11021;BRAHMI LETTER NNA;Lo;0;L;;;;;N;;;;;\n11022;BRAHMI LETTER TA;Lo;0;L;;;;;N;;;;;\n11023;BRAHMI LETTER THA;Lo;0;L;;;;;N;;;;;\n11024;BRAHMI LETTER DA;Lo;0;L;;;;;N;;;;;\n11025;BRAHMI LETTER DHA;Lo;0;L;;;;;N;;;;;\n11026;BRAHMI LETTER NA;Lo;0;L;;;;;N;;;;;\n11027;BRAHMI LETTER PA;Lo;0;L;;;;;N;;;;;\n11028;BRAHMI LETTER PHA;Lo;0;L;;;;;N;;;;;\n11029;BRAHMI LETTER BA;Lo;0;L;;;;;N;;;;;\n1102A;BRAHMI LETTER BHA;Lo;0;L;;;;;N;;;;;\n1102B;BRAHMI LETTER MA;Lo;0;L;;;;;N;;;;;\n1102C;BRAHMI LETTER YA;Lo;0;L;;;;;N;;;;;\n1102D;BRAHMI LETTER RA;Lo;0;L;;;;;N;;;;;\n1102E;BRAHMI LETTER LA;Lo;0;L;;;;;N;;;;;\n1102F;BRAHMI LETTER VA;Lo;0;L;;;;;N;;;;;\n11030;BRAHMI LETTER SHA;Lo;0;L;;;;;N;;;;;\n11031;BRAHMI LETTER SSA;Lo;0;L;;;;;N;;;;;\n11032;BRAHMI LETTER SA;Lo;0;L;;;;;N;;;;;\n11033;BRAHMI LETTER HA;Lo;0;L;;;;;N;;;;;\n11034;BRAHMI LETTER LLA;Lo;0;L;;;;;N;;;;;\n11035;BRAHMI LETTER OLD TAMIL LLLA;Lo;0;L;;;;;N;;;;;\n11036;BRAHMI LETTER OLD TAMIL RRA;Lo;0;L;;;;;N;;;;;\n11037;BRAHMI LETTER OLD TAMIL NNNA;Lo;0;L;;;;;N;;;;;\n11038;BRAHMI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;\n11039;BRAHMI VOWEL SIGN BHATTIPROLU AA;Mn;0;NSM;;;;;N;;;;;\n1103A;BRAHMI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n1103B;BRAHMI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n1103C;BRAHMI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1103D;BRAHMI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n1103E;BRAHMI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n1103F;BRAHMI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n11040;BRAHMI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n11041;BRAHMI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n11042;BRAHMI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n11043;BRAHMI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n11044;BRAHMI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n11045;BRAHMI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n11046;BRAHMI VIRAMA;Mn;9;NSM;;;;;N;;;;;\n11047;BRAHMI DANDA;Po;0;L;;;;;N;;;;;\n11048;BRAHMI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n11049;BRAHMI PUNCTUATION DOT;Po;0;L;;;;;N;;;;;\n1104A;BRAHMI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;;\n1104B;BRAHMI PUNCTUATION LINE;Po;0;L;;;;;N;;;;;\n1104C;BRAHMI PUNCTUATION CRESCENT BAR;Po;0;L;;;;;N;;;;;\n1104D;BRAHMI PUNCTUATION LOTUS;Po;0;L;;;;;N;;;;;\n11052;BRAHMI NUMBER ONE;No;0;ON;;;1;1;N;;;;;\n11053;BRAHMI NUMBER TWO;No;0;ON;;;2;2;N;;;;;\n11054;BRAHMI NUMBER THREE;No;0;ON;;;3;3;N;;;;;\n11055;BRAHMI NUMBER FOUR;No;0;ON;;;4;4;N;;;;;\n11056;BRAHMI NUMBER FIVE;No;0;ON;;;5;5;N;;;;;\n11057;BRAHMI NUMBER SIX;No;0;ON;;;6;6;N;;;;;\n11058;BRAHMI NUMBER SEVEN;No;0;ON;;;7;7;N;;;;;\n11059;BRAHMI NUMBER EIGHT;No;0;ON;;;8;8;N;;;;;\n1105A;BRAHMI NUMBER NINE;No;0;ON;;;9;9;N;;;;;\n1105B;BRAHMI NUMBER TEN;No;0;ON;;;;10;N;;;;;\n1105C;BRAHMI NUMBER TWENTY;No;0;ON;;;;20;N;;;;;\n1105D;BRAHMI NUMBER THIRTY;No;0;ON;;;;30;N;;;;;\n1105E;BRAHMI NUMBER FORTY;No;0;ON;;;;40;N;;;;;\n1105F;BRAHMI NUMBER FIFTY;No;0;ON;;;;50;N;;;;;\n11060;BRAHMI NUMBER SIXTY;No;0;ON;;;;60;N;;;;;\n11061;BRAHMI NUMBER SEVENTY;No;0;ON;;;;70;N;;;;;\n11062;BRAHMI NUMBER EIGHTY;No;0;ON;;;;80;N;;;;;\n11063;BRAHMI NUMBER NINETY;No;0;ON;;;;90;N;;;;;\n11064;BRAHMI NUMBER ONE HUNDRED;No;0;ON;;;;100;N;;;;;\n11065;BRAHMI NUMBER ONE THOUSAND;No;0;ON;;;;1000;N;;;;;\n11066;BRAHMI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11067;BRAHMI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11068;BRAHMI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11069;BRAHMI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1106A;BRAHMI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1106B;BRAHMI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1106C;BRAHMI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1106D;BRAHMI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1106E;BRAHMI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1106F;BRAHMI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11070;BRAHMI SIGN OLD TAMIL VIRAMA;Mn;9;NSM;;;;;N;;;;;\n11071;BRAHMI LETTER OLD TAMIL SHORT E;Lo;0;L;;;;;N;;;;;\n11072;BRAHMI LETTER OLD TAMIL SHORT O;Lo;0;L;;;;;N;;;;;\n11073;BRAHMI VOWEL SIGN OLD TAMIL SHORT E;Mn;0;NSM;;;;;N;;;;;\n11074;BRAHMI VOWEL SIGN OLD TAMIL SHORT O;Mn;0;NSM;;;;;N;;;;;\n11075;BRAHMI LETTER OLD TAMIL LLA;Lo;0;L;;;;;N;;;;;\n1107F;BRAHMI NUMBER JOINER;Mn;9;NSM;;;;;N;;;;;\n11080;KAITHI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n11081;KAITHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11082;KAITHI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11083;KAITHI LETTER A;Lo;0;L;;;;;N;;;;;\n11084;KAITHI LETTER AA;Lo;0;L;;;;;N;;;;;\n11085;KAITHI LETTER I;Lo;0;L;;;;;N;;;;;\n11086;KAITHI LETTER II;Lo;0;L;;;;;N;;;;;\n11087;KAITHI LETTER U;Lo;0;L;;;;;N;;;;;\n11088;KAITHI LETTER UU;Lo;0;L;;;;;N;;;;;\n11089;KAITHI LETTER E;Lo;0;L;;;;;N;;;;;\n1108A;KAITHI LETTER AI;Lo;0;L;;;;;N;;;;;\n1108B;KAITHI LETTER O;Lo;0;L;;;;;N;;;;;\n1108C;KAITHI LETTER AU;Lo;0;L;;;;;N;;;;;\n1108D;KAITHI LETTER KA;Lo;0;L;;;;;N;;;;;\n1108E;KAITHI LETTER KHA;Lo;0;L;;;;;N;;;;;\n1108F;KAITHI LETTER GA;Lo;0;L;;;;;N;;;;;\n11090;KAITHI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11091;KAITHI LETTER NGA;Lo;0;L;;;;;N;;;;;\n11092;KAITHI LETTER CA;Lo;0;L;;;;;N;;;;;\n11093;KAITHI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11094;KAITHI LETTER JA;Lo;0;L;;;;;N;;;;;\n11095;KAITHI LETTER JHA;Lo;0;L;;;;;N;;;;;\n11096;KAITHI LETTER NYA;Lo;0;L;;;;;N;;;;;\n11097;KAITHI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11098;KAITHI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11099;KAITHI LETTER DDA;Lo;0;L;;;;;N;;;;;\n1109A;KAITHI LETTER DDDHA;Lo;0;L;11099 110BA;;;;N;;;;;\n1109B;KAITHI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n1109C;KAITHI LETTER RHA;Lo;0;L;1109B 110BA;;;;N;;;;;\n1109D;KAITHI LETTER NNA;Lo;0;L;;;;;N;;;;;\n1109E;KAITHI LETTER TA;Lo;0;L;;;;;N;;;;;\n1109F;KAITHI LETTER THA;Lo;0;L;;;;;N;;;;;\n110A0;KAITHI LETTER DA;Lo;0;L;;;;;N;;;;;\n110A1;KAITHI LETTER DHA;Lo;0;L;;;;;N;;;;;\n110A2;KAITHI LETTER NA;Lo;0;L;;;;;N;;;;;\n110A3;KAITHI LETTER PA;Lo;0;L;;;;;N;;;;;\n110A4;KAITHI LETTER PHA;Lo;0;L;;;;;N;;;;;\n110A5;KAITHI LETTER BA;Lo;0;L;;;;;N;;;;;\n110A6;KAITHI LETTER BHA;Lo;0;L;;;;;N;;;;;\n110A7;KAITHI LETTER MA;Lo;0;L;;;;;N;;;;;\n110A8;KAITHI LETTER YA;Lo;0;L;;;;;N;;;;;\n110A9;KAITHI LETTER RA;Lo;0;L;;;;;N;;;;;\n110AA;KAITHI LETTER LA;Lo;0;L;;;;;N;;;;;\n110AB;KAITHI LETTER VA;Lo;0;L;110A5 110BA;;;;N;;;;;\n110AC;KAITHI LETTER SHA;Lo;0;L;;;;;N;;;;;\n110AD;KAITHI LETTER SSA;Lo;0;L;;;;;N;;;;;\n110AE;KAITHI LETTER SA;Lo;0;L;;;;;N;;;;;\n110AF;KAITHI LETTER HA;Lo;0;L;;;;;N;;;;;\n110B0;KAITHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n110B1;KAITHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n110B2;KAITHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n110B3;KAITHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n110B4;KAITHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n110B5;KAITHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n110B6;KAITHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n110B7;KAITHI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n110B8;KAITHI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n110B9;KAITHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n110BA;KAITHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n110BB;KAITHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n110BC;KAITHI ENUMERATION SIGN;Po;0;L;;;;;N;;;;;\n110BD;KAITHI NUMBER SIGN;Cf;0;L;;;;;N;;;;;\n110BE;KAITHI SECTION MARK;Po;0;L;;;;;N;;;;;\n110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;;\n110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;;\n110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n110C2;KAITHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n110CD;KAITHI NUMBER SIGN ABOVE;Cf;0;L;;;;;N;;;;;\n110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;;\n110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;;\n110D2;SORA SOMPENG LETTER BAH;Lo;0;L;;;;;N;;;;;\n110D3;SORA SOMPENG LETTER CAH;Lo;0;L;;;;;N;;;;;\n110D4;SORA SOMPENG LETTER DAH;Lo;0;L;;;;;N;;;;;\n110D5;SORA SOMPENG LETTER GAH;Lo;0;L;;;;;N;;;;;\n110D6;SORA SOMPENG LETTER MAH;Lo;0;L;;;;;N;;;;;\n110D7;SORA SOMPENG LETTER NGAH;Lo;0;L;;;;;N;;;;;\n110D8;SORA SOMPENG LETTER LAH;Lo;0;L;;;;;N;;;;;\n110D9;SORA SOMPENG LETTER NAH;Lo;0;L;;;;;N;;;;;\n110DA;SORA SOMPENG LETTER VAH;Lo;0;L;;;;;N;;;;;\n110DB;SORA SOMPENG LETTER PAH;Lo;0;L;;;;;N;;;;;\n110DC;SORA SOMPENG LETTER YAH;Lo;0;L;;;;;N;;;;;\n110DD;SORA SOMPENG LETTER RAH;Lo;0;L;;;;;N;;;;;\n110DE;SORA SOMPENG LETTER HAH;Lo;0;L;;;;;N;;;;;\n110DF;SORA SOMPENG LETTER KAH;Lo;0;L;;;;;N;;;;;\n110E0;SORA SOMPENG LETTER JAH;Lo;0;L;;;;;N;;;;;\n110E1;SORA SOMPENG LETTER NYAH;Lo;0;L;;;;;N;;;;;\n110E2;SORA SOMPENG LETTER AH;Lo;0;L;;;;;N;;;;;\n110E3;SORA SOMPENG LETTER EEH;Lo;0;L;;;;;N;;;;;\n110E4;SORA SOMPENG LETTER IH;Lo;0;L;;;;;N;;;;;\n110E5;SORA SOMPENG LETTER UH;Lo;0;L;;;;;N;;;;;\n110E6;SORA SOMPENG LETTER OH;Lo;0;L;;;;;N;;;;;\n110E7;SORA SOMPENG LETTER EH;Lo;0;L;;;;;N;;;;;\n110E8;SORA SOMPENG LETTER MAE;Lo;0;L;;;;;N;;;;;\n110F0;SORA SOMPENG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n110F1;SORA SOMPENG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n110F2;SORA SOMPENG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n110F3;SORA SOMPENG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n110F4;SORA SOMPENG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n110F5;SORA SOMPENG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n110F6;SORA SOMPENG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n110F7;SORA SOMPENG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n110F8;SORA SOMPENG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n110F9;SORA SOMPENG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11100;CHAKMA SIGN CANDRABINDU;Mn;230;NSM;;;;;N;;;;;\n11101;CHAKMA SIGN ANUSVARA;Mn;230;NSM;;;;;N;;;;;\n11102;CHAKMA SIGN VISARGA;Mn;230;NSM;;;;;N;;;;;\n11103;CHAKMA LETTER AA;Lo;0;L;;;;;N;;;;;\n11104;CHAKMA LETTER I;Lo;0;L;;;;;N;;;;;\n11105;CHAKMA LETTER U;Lo;0;L;;;;;N;;;;;\n11106;CHAKMA LETTER E;Lo;0;L;;;;;N;;;;;\n11107;CHAKMA LETTER KAA;Lo;0;L;;;;;N;;;;;\n11108;CHAKMA LETTER KHAA;Lo;0;L;;;;;N;;;;;\n11109;CHAKMA LETTER GAA;Lo;0;L;;;;;N;;;;;\n1110A;CHAKMA LETTER GHAA;Lo;0;L;;;;;N;;;;;\n1110B;CHAKMA LETTER NGAA;Lo;0;L;;;;;N;;;;;\n1110C;CHAKMA LETTER CAA;Lo;0;L;;;;;N;;;;;\n1110D;CHAKMA LETTER CHAA;Lo;0;L;;;;;N;;;;;\n1110E;CHAKMA LETTER JAA;Lo;0;L;;;;;N;;;;;\n1110F;CHAKMA LETTER JHAA;Lo;0;L;;;;;N;;;;;\n11110;CHAKMA LETTER NYAA;Lo;0;L;;;;;N;;;;;\n11111;CHAKMA LETTER TTAA;Lo;0;L;;;;;N;;;;;\n11112;CHAKMA LETTER TTHAA;Lo;0;L;;;;;N;;;;;\n11113;CHAKMA LETTER DDAA;Lo;0;L;;;;;N;;;;;\n11114;CHAKMA LETTER DDHAA;Lo;0;L;;;;;N;;;;;\n11115;CHAKMA LETTER NNAA;Lo;0;L;;;;;N;;;;;\n11116;CHAKMA LETTER TAA;Lo;0;L;;;;;N;;;;;\n11117;CHAKMA LETTER THAA;Lo;0;L;;;;;N;;;;;\n11118;CHAKMA LETTER DAA;Lo;0;L;;;;;N;;;;;\n11119;CHAKMA LETTER DHAA;Lo;0;L;;;;;N;;;;;\n1111A;CHAKMA LETTER NAA;Lo;0;L;;;;;N;;;;;\n1111B;CHAKMA LETTER PAA;Lo;0;L;;;;;N;;;;;\n1111C;CHAKMA LETTER PHAA;Lo;0;L;;;;;N;;;;;\n1111D;CHAKMA LETTER BAA;Lo;0;L;;;;;N;;;;;\n1111E;CHAKMA LETTER BHAA;Lo;0;L;;;;;N;;;;;\n1111F;CHAKMA LETTER MAA;Lo;0;L;;;;;N;;;;;\n11120;CHAKMA LETTER YYAA;Lo;0;L;;;;;N;;;;;\n11121;CHAKMA LETTER YAA;Lo;0;L;;;;;N;;;;;\n11122;CHAKMA LETTER RAA;Lo;0;L;;;;;N;;;;;\n11123;CHAKMA LETTER LAA;Lo;0;L;;;;;N;;;;;\n11124;CHAKMA LETTER WAA;Lo;0;L;;;;;N;;;;;\n11125;CHAKMA LETTER SAA;Lo;0;L;;;;;N;;;;;\n11126;CHAKMA LETTER HAA;Lo;0;L;;;;;N;;;;;\n11127;CHAKMA VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;;\n11128;CHAKMA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n11129;CHAKMA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n1112A;CHAKMA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n1112B;CHAKMA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n1112C;CHAKMA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n1112D;CHAKMA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n1112E;CHAKMA VOWEL SIGN O;Mn;0;NSM;11131 11127;;;;N;;;;;\n1112F;CHAKMA VOWEL SIGN AU;Mn;0;NSM;11132 11127;;;;N;;;;;\n11130;CHAKMA VOWEL SIGN OI;Mn;0;NSM;;;;;N;;;;;\n11131;CHAKMA O MARK;Mn;0;NSM;;;;;N;;;;;\n11132;CHAKMA AU MARK;Mn;0;NSM;;;;;N;;;;;\n11133;CHAKMA VIRAMA;Mn;9;NSM;;;;;N;;;;;\n11134;CHAKMA MAAYYAA;Mn;9;NSM;;;;;N;;;;;\n11136;CHAKMA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11137;CHAKMA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11138;CHAKMA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11139;CHAKMA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1113A;CHAKMA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1113B;CHAKMA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1113C;CHAKMA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1113D;CHAKMA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1113E;CHAKMA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1113F;CHAKMA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11140;CHAKMA SECTION MARK;Po;0;L;;;;;N;;;;;\n11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;;\n11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;;\n11144;CHAKMA LETTER LHAA;Lo;0;L;;;;;N;;;;;\n11145;CHAKMA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n11146;CHAKMA VOWEL SIGN EI;Mc;0;L;;;;;N;;;;;\n11147;CHAKMA LETTER VAA;Lo;0;L;;;;;N;;;;;\n11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;;\n11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;;\n11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;;\n11153;MAHAJANI LETTER E;Lo;0;L;;;;;N;;;;;\n11154;MAHAJANI LETTER O;Lo;0;L;;;;;N;;;;;\n11155;MAHAJANI LETTER KA;Lo;0;L;;;;;N;;;;;\n11156;MAHAJANI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11157;MAHAJANI LETTER GA;Lo;0;L;;;;;N;;;;;\n11158;MAHAJANI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11159;MAHAJANI LETTER CA;Lo;0;L;;;;;N;;;;;\n1115A;MAHAJANI LETTER CHA;Lo;0;L;;;;;N;;;;;\n1115B;MAHAJANI LETTER JA;Lo;0;L;;;;;N;;;;;\n1115C;MAHAJANI LETTER JHA;Lo;0;L;;;;;N;;;;;\n1115D;MAHAJANI LETTER NYA;Lo;0;L;;;;;N;;;;;\n1115E;MAHAJANI LETTER TTA;Lo;0;L;;;;;N;;;;;\n1115F;MAHAJANI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11160;MAHAJANI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11161;MAHAJANI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11162;MAHAJANI LETTER NNA;Lo;0;L;;;;;N;;;;;\n11163;MAHAJANI LETTER TA;Lo;0;L;;;;;N;;;;;\n11164;MAHAJANI LETTER THA;Lo;0;L;;;;;N;;;;;\n11165;MAHAJANI LETTER DA;Lo;0;L;;;;;N;;;;;\n11166;MAHAJANI LETTER DHA;Lo;0;L;;;;;N;;;;;\n11167;MAHAJANI LETTER NA;Lo;0;L;;;;;N;;;;;\n11168;MAHAJANI LETTER PA;Lo;0;L;;;;;N;;;;;\n11169;MAHAJANI LETTER PHA;Lo;0;L;;;;;N;;;;;\n1116A;MAHAJANI LETTER BA;Lo;0;L;;;;;N;;;;;\n1116B;MAHAJANI LETTER BHA;Lo;0;L;;;;;N;;;;;\n1116C;MAHAJANI LETTER MA;Lo;0;L;;;;;N;;;;;\n1116D;MAHAJANI LETTER RA;Lo;0;L;;;;;N;;;;;\n1116E;MAHAJANI LETTER LA;Lo;0;L;;;;;N;;;;;\n1116F;MAHAJANI LETTER VA;Lo;0;L;;;;;N;;;;;\n11170;MAHAJANI LETTER SA;Lo;0;L;;;;;N;;;;;\n11171;MAHAJANI LETTER HA;Lo;0;L;;;;;N;;;;;\n11172;MAHAJANI LETTER RRA;Lo;0;L;;;;;N;;;;;\n11173;MAHAJANI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n11174;MAHAJANI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n11175;MAHAJANI SECTION MARK;Po;0;L;;;;;N;;;;;\n11176;MAHAJANI LIGATURE SHRI;Lo;0;L;;;;;N;;;;;\n11180;SHARADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n11181;SHARADA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11182;SHARADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11183;SHARADA LETTER A;Lo;0;L;;;;;N;;;;;\n11184;SHARADA LETTER AA;Lo;0;L;;;;;N;;;;;\n11185;SHARADA LETTER I;Lo;0;L;;;;;N;;;;;\n11186;SHARADA LETTER II;Lo;0;L;;;;;N;;;;;\n11187;SHARADA LETTER U;Lo;0;L;;;;;N;;;;;\n11188;SHARADA LETTER UU;Lo;0;L;;;;;N;;;;;\n11189;SHARADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n1118A;SHARADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n1118B;SHARADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n1118C;SHARADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n1118D;SHARADA LETTER E;Lo;0;L;;;;;N;;;;;\n1118E;SHARADA LETTER AI;Lo;0;L;;;;;N;;;;;\n1118F;SHARADA LETTER O;Lo;0;L;;;;;N;;;;;\n11190;SHARADA LETTER AU;Lo;0;L;;;;;N;;;;;\n11191;SHARADA LETTER KA;Lo;0;L;;;;;N;;;;;\n11192;SHARADA LETTER KHA;Lo;0;L;;;;;N;;;;;\n11193;SHARADA LETTER GA;Lo;0;L;;;;;N;;;;;\n11194;SHARADA LETTER GHA;Lo;0;L;;;;;N;;;;;\n11195;SHARADA LETTER NGA;Lo;0;L;;;;;N;;;;;\n11196;SHARADA LETTER CA;Lo;0;L;;;;;N;;;;;\n11197;SHARADA LETTER CHA;Lo;0;L;;;;;N;;;;;\n11198;SHARADA LETTER JA;Lo;0;L;;;;;N;;;;;\n11199;SHARADA LETTER JHA;Lo;0;L;;;;;N;;;;;\n1119A;SHARADA LETTER NYA;Lo;0;L;;;;;N;;;;;\n1119B;SHARADA LETTER TTA;Lo;0;L;;;;;N;;;;;\n1119C;SHARADA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1119D;SHARADA LETTER DDA;Lo;0;L;;;;;N;;;;;\n1119E;SHARADA LETTER DDHA;Lo;0;L;;;;;N;;;;;\n1119F;SHARADA LETTER NNA;Lo;0;L;;;;;N;;;;;\n111A0;SHARADA LETTER TA;Lo;0;L;;;;;N;;;;;\n111A1;SHARADA LETTER THA;Lo;0;L;;;;;N;;;;;\n111A2;SHARADA LETTER DA;Lo;0;L;;;;;N;;;;;\n111A3;SHARADA LETTER DHA;Lo;0;L;;;;;N;;;;;\n111A4;SHARADA LETTER NA;Lo;0;L;;;;;N;;;;;\n111A5;SHARADA LETTER PA;Lo;0;L;;;;;N;;;;;\n111A6;SHARADA LETTER PHA;Lo;0;L;;;;;N;;;;;\n111A7;SHARADA LETTER BA;Lo;0;L;;;;;N;;;;;\n111A8;SHARADA LETTER BHA;Lo;0;L;;;;;N;;;;;\n111A9;SHARADA LETTER MA;Lo;0;L;;;;;N;;;;;\n111AA;SHARADA LETTER YA;Lo;0;L;;;;;N;;;;;\n111AB;SHARADA LETTER RA;Lo;0;L;;;;;N;;;;;\n111AC;SHARADA LETTER LA;Lo;0;L;;;;;N;;;;;\n111AD;SHARADA LETTER LLA;Lo;0;L;;;;;N;;;;;\n111AE;SHARADA LETTER VA;Lo;0;L;;;;;N;;;;;\n111AF;SHARADA LETTER SHA;Lo;0;L;;;;;N;;;;;\n111B0;SHARADA LETTER SSA;Lo;0;L;;;;;N;;;;;\n111B1;SHARADA LETTER SA;Lo;0;L;;;;;N;;;;;\n111B2;SHARADA LETTER HA;Lo;0;L;;;;;N;;;;;\n111B3;SHARADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n111B4;SHARADA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n111B5;SHARADA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n111B6;SHARADA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n111B7;SHARADA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n111B8;SHARADA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n111B9;SHARADA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n111BA;SHARADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n111BB;SHARADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n111BC;SHARADA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n111BD;SHARADA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n111BE;SHARADA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n111BF;SHARADA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n111C0;SHARADA SIGN VIRAMA;Mc;9;L;;;;;N;;;;;\n111C1;SHARADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n111C2;SHARADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;\n111C3;SHARADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;\n111C4;SHARADA OM;Lo;0;L;;;;;N;;;;;\n111C5;SHARADA DANDA;Po;0;L;;;;;N;;;;;\n111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;;\n111C9;SHARADA SANDHI MARK;Mn;0;NSM;;;;;N;;;;;\n111CA;SHARADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;;\n111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;;\n111CD;SHARADA SUTRA MARK;Po;0;L;;;;;N;;;;;\n111CE;SHARADA VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;;\n111CF;SHARADA SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n111D0;SHARADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n111D1;SHARADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n111D2;SHARADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n111D3;SHARADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n111D4;SHARADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n111D5;SHARADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n111D6;SHARADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n111D7;SHARADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n111D8;SHARADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n111D9;SHARADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n111DA;SHARADA EKAM;Lo;0;L;;;;;N;;;;;\n111DB;SHARADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;;\n111DC;SHARADA HEADSTROKE;Lo;0;L;;;;;N;;;;;\n111DD;SHARADA CONTINUATION SIGN;Po;0;L;;;;;N;;;;;\n111DE;SHARADA SECTION MARK-1;Po;0;L;;;;;N;;;;;\n111DF;SHARADA SECTION MARK-2;Po;0;L;;;;;N;;;;;\n111E1;SINHALA ARCHAIC DIGIT ONE;No;0;L;;;;1;N;;;;;\n111E2;SINHALA ARCHAIC DIGIT TWO;No;0;L;;;;2;N;;;;;\n111E3;SINHALA ARCHAIC DIGIT THREE;No;0;L;;;;3;N;;;;;\n111E4;SINHALA ARCHAIC DIGIT FOUR;No;0;L;;;;4;N;;;;;\n111E5;SINHALA ARCHAIC DIGIT FIVE;No;0;L;;;;5;N;;;;;\n111E6;SINHALA ARCHAIC DIGIT SIX;No;0;L;;;;6;N;;;;;\n111E7;SINHALA ARCHAIC DIGIT SEVEN;No;0;L;;;;7;N;;;;;\n111E8;SINHALA ARCHAIC DIGIT EIGHT;No;0;L;;;;8;N;;;;;\n111E9;SINHALA ARCHAIC DIGIT NINE;No;0;L;;;;9;N;;;;;\n111EA;SINHALA ARCHAIC NUMBER TEN;No;0;L;;;;10;N;;;;;\n111EB;SINHALA ARCHAIC NUMBER TWENTY;No;0;L;;;;20;N;;;;;\n111EC;SINHALA ARCHAIC NUMBER THIRTY;No;0;L;;;;30;N;;;;;\n111ED;SINHALA ARCHAIC NUMBER FORTY;No;0;L;;;;40;N;;;;;\n111EE;SINHALA ARCHAIC NUMBER FIFTY;No;0;L;;;;50;N;;;;;\n111EF;SINHALA ARCHAIC NUMBER SIXTY;No;0;L;;;;60;N;;;;;\n111F0;SINHALA ARCHAIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;;\n111F1;SINHALA ARCHAIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;;\n111F2;SINHALA ARCHAIC NUMBER NINETY;No;0;L;;;;90;N;;;;;\n111F3;SINHALA ARCHAIC NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;\n111F4;SINHALA ARCHAIC NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;\n11200;KHOJKI LETTER A;Lo;0;L;;;;;N;;;;;\n11201;KHOJKI LETTER AA;Lo;0;L;;;;;N;;;;;\n11202;KHOJKI LETTER I;Lo;0;L;;;;;N;;;;;\n11203;KHOJKI LETTER U;Lo;0;L;;;;;N;;;;;\n11204;KHOJKI LETTER E;Lo;0;L;;;;;N;;;;;\n11205;KHOJKI LETTER AI;Lo;0;L;;;;;N;;;;;\n11206;KHOJKI LETTER O;Lo;0;L;;;;;N;;;;;\n11207;KHOJKI LETTER AU;Lo;0;L;;;;;N;;;;;\n11208;KHOJKI LETTER KA;Lo;0;L;;;;;N;;;;;\n11209;KHOJKI LETTER KHA;Lo;0;L;;;;;N;;;;;\n1120A;KHOJKI LETTER GA;Lo;0;L;;;;;N;;;;;\n1120B;KHOJKI LETTER GGA;Lo;0;L;;;;;N;;;;;\n1120C;KHOJKI LETTER GHA;Lo;0;L;;;;;N;;;;;\n1120D;KHOJKI LETTER NGA;Lo;0;L;;;;;N;;;;;\n1120E;KHOJKI LETTER CA;Lo;0;L;;;;;N;;;;;\n1120F;KHOJKI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11210;KHOJKI LETTER JA;Lo;0;L;;;;;N;;;;;\n11211;KHOJKI LETTER JJA;Lo;0;L;;;;;N;;;;;\n11213;KHOJKI LETTER NYA;Lo;0;L;;;;;N;;;;;\n11214;KHOJKI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11215;KHOJKI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11216;KHOJKI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11217;KHOJKI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11218;KHOJKI LETTER NNA;Lo;0;L;;;;;N;;;;;\n11219;KHOJKI LETTER TA;Lo;0;L;;;;;N;;;;;\n1121A;KHOJKI LETTER THA;Lo;0;L;;;;;N;;;;;\n1121B;KHOJKI LETTER DA;Lo;0;L;;;;;N;;;;;\n1121C;KHOJKI LETTER DDDA;Lo;0;L;;;;;N;;;;;\n1121D;KHOJKI LETTER DHA;Lo;0;L;;;;;N;;;;;\n1121E;KHOJKI LETTER NA;Lo;0;L;;;;;N;;;;;\n1121F;KHOJKI LETTER PA;Lo;0;L;;;;;N;;;;;\n11220;KHOJKI LETTER PHA;Lo;0;L;;;;;N;;;;;\n11221;KHOJKI LETTER BA;Lo;0;L;;;;;N;;;;;\n11222;KHOJKI LETTER BBA;Lo;0;L;;;;;N;;;;;\n11223;KHOJKI LETTER BHA;Lo;0;L;;;;;N;;;;;\n11224;KHOJKI LETTER MA;Lo;0;L;;;;;N;;;;;\n11225;KHOJKI LETTER YA;Lo;0;L;;;;;N;;;;;\n11226;KHOJKI LETTER RA;Lo;0;L;;;;;N;;;;;\n11227;KHOJKI LETTER LA;Lo;0;L;;;;;N;;;;;\n11228;KHOJKI LETTER VA;Lo;0;L;;;;;N;;;;;\n11229;KHOJKI LETTER SA;Lo;0;L;;;;;N;;;;;\n1122A;KHOJKI LETTER HA;Lo;0;L;;;;;N;;;;;\n1122B;KHOJKI LETTER LLA;Lo;0;L;;;;;N;;;;;\n1122C;KHOJKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n1122D;KHOJKI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n1122E;KHOJKI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n1122F;KHOJKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11230;KHOJKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n11231;KHOJKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n11232;KHOJKI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n11233;KHOJKI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n11234;KHOJKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11235;KHOJKI SIGN VIRAMA;Mc;9;L;;;;;N;;;;;\n11236;KHOJKI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n11237;KHOJKI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;;\n11238;KHOJKI DANDA;Po;0;L;;;;;N;;;;;\n11239;KHOJKI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n1123A;KHOJKI WORD SEPARATOR;Po;0;L;;;;;N;;;;;\n1123B;KHOJKI SECTION MARK;Po;0;L;;;;;N;;;;;\n1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;;\n1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n1123E;KHOJKI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;;\n1123F;KHOJKI LETTER QA;Lo;0;L;;;;;N;;;;;\n11240;KHOJKI LETTER SHORT I;Lo;0;L;;;;;N;;;;;\n11241;KHOJKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n11280;MULTANI LETTER A;Lo;0;L;;;;;N;;;;;\n11281;MULTANI LETTER I;Lo;0;L;;;;;N;;;;;\n11282;MULTANI LETTER U;Lo;0;L;;;;;N;;;;;\n11283;MULTANI LETTER E;Lo;0;L;;;;;N;;;;;\n11284;MULTANI LETTER KA;Lo;0;L;;;;;N;;;;;\n11285;MULTANI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11286;MULTANI LETTER GA;Lo;0;L;;;;;N;;;;;\n11288;MULTANI LETTER GHA;Lo;0;L;;;;;N;;;;;\n1128A;MULTANI LETTER CA;Lo;0;L;;;;;N;;;;;\n1128B;MULTANI LETTER CHA;Lo;0;L;;;;;N;;;;;\n1128C;MULTANI LETTER JA;Lo;0;L;;;;;N;;;;;\n1128D;MULTANI LETTER JJA;Lo;0;L;;;;;N;;;;;\n1128F;MULTANI LETTER NYA;Lo;0;L;;;;;N;;;;;\n11290;MULTANI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11291;MULTANI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11292;MULTANI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11293;MULTANI LETTER DDDA;Lo;0;L;;;;;N;;;;;\n11294;MULTANI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11295;MULTANI LETTER NNA;Lo;0;L;;;;;N;;;;;\n11296;MULTANI LETTER TA;Lo;0;L;;;;;N;;;;;\n11297;MULTANI LETTER THA;Lo;0;L;;;;;N;;;;;\n11298;MULTANI LETTER DA;Lo;0;L;;;;;N;;;;;\n11299;MULTANI LETTER DHA;Lo;0;L;;;;;N;;;;;\n1129A;MULTANI LETTER NA;Lo;0;L;;;;;N;;;;;\n1129B;MULTANI LETTER PA;Lo;0;L;;;;;N;;;;;\n1129C;MULTANI LETTER PHA;Lo;0;L;;;;;N;;;;;\n1129D;MULTANI LETTER BA;Lo;0;L;;;;;N;;;;;\n1129F;MULTANI LETTER BHA;Lo;0;L;;;;;N;;;;;\n112A0;MULTANI LETTER MA;Lo;0;L;;;;;N;;;;;\n112A1;MULTANI LETTER YA;Lo;0;L;;;;;N;;;;;\n112A2;MULTANI LETTER RA;Lo;0;L;;;;;N;;;;;\n112A3;MULTANI LETTER LA;Lo;0;L;;;;;N;;;;;\n112A4;MULTANI LETTER VA;Lo;0;L;;;;;N;;;;;\n112A5;MULTANI LETTER SA;Lo;0;L;;;;;N;;;;;\n112A6;MULTANI LETTER HA;Lo;0;L;;;;;N;;;;;\n112A7;MULTANI LETTER RRA;Lo;0;L;;;;;N;;;;;\n112A8;MULTANI LETTER RHA;Lo;0;L;;;;;N;;;;;\n112A9;MULTANI SECTION MARK;Po;0;L;;;;;N;;;;;\n112B0;KHUDAWADI LETTER A;Lo;0;L;;;;;N;;;;;\n112B1;KHUDAWADI LETTER AA;Lo;0;L;;;;;N;;;;;\n112B2;KHUDAWADI LETTER I;Lo;0;L;;;;;N;;;;;\n112B3;KHUDAWADI LETTER II;Lo;0;L;;;;;N;;;;;\n112B4;KHUDAWADI LETTER U;Lo;0;L;;;;;N;;;;;\n112B5;KHUDAWADI LETTER UU;Lo;0;L;;;;;N;;;;;\n112B6;KHUDAWADI LETTER E;Lo;0;L;;;;;N;;;;;\n112B7;KHUDAWADI LETTER AI;Lo;0;L;;;;;N;;;;;\n112B8;KHUDAWADI LETTER O;Lo;0;L;;;;;N;;;;;\n112B9;KHUDAWADI LETTER AU;Lo;0;L;;;;;N;;;;;\n112BA;KHUDAWADI LETTER KA;Lo;0;L;;;;;N;;;;;\n112BB;KHUDAWADI LETTER KHA;Lo;0;L;;;;;N;;;;;\n112BC;KHUDAWADI LETTER GA;Lo;0;L;;;;;N;;;;;\n112BD;KHUDAWADI LETTER GGA;Lo;0;L;;;;;N;;;;;\n112BE;KHUDAWADI LETTER GHA;Lo;0;L;;;;;N;;;;;\n112BF;KHUDAWADI LETTER NGA;Lo;0;L;;;;;N;;;;;\n112C0;KHUDAWADI LETTER CA;Lo;0;L;;;;;N;;;;;\n112C1;KHUDAWADI LETTER CHA;Lo;0;L;;;;;N;;;;;\n112C2;KHUDAWADI LETTER JA;Lo;0;L;;;;;N;;;;;\n112C3;KHUDAWADI LETTER JJA;Lo;0;L;;;;;N;;;;;\n112C4;KHUDAWADI LETTER JHA;Lo;0;L;;;;;N;;;;;\n112C5;KHUDAWADI LETTER NYA;Lo;0;L;;;;;N;;;;;\n112C6;KHUDAWADI LETTER TTA;Lo;0;L;;;;;N;;;;;\n112C7;KHUDAWADI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n112C8;KHUDAWADI LETTER DDA;Lo;0;L;;;;;N;;;;;\n112C9;KHUDAWADI LETTER DDDA;Lo;0;L;;;;;N;;;;;\n112CA;KHUDAWADI LETTER RRA;Lo;0;L;;;;;N;;;;;\n112CB;KHUDAWADI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n112CC;KHUDAWADI LETTER NNA;Lo;0;L;;;;;N;;;;;\n112CD;KHUDAWADI LETTER TA;Lo;0;L;;;;;N;;;;;\n112CE;KHUDAWADI LETTER THA;Lo;0;L;;;;;N;;;;;\n112CF;KHUDAWADI LETTER DA;Lo;0;L;;;;;N;;;;;\n112D0;KHUDAWADI LETTER DHA;Lo;0;L;;;;;N;;;;;\n112D1;KHUDAWADI LETTER NA;Lo;0;L;;;;;N;;;;;\n112D2;KHUDAWADI LETTER PA;Lo;0;L;;;;;N;;;;;\n112D3;KHUDAWADI LETTER PHA;Lo;0;L;;;;;N;;;;;\n112D4;KHUDAWADI LETTER BA;Lo;0;L;;;;;N;;;;;\n112D5;KHUDAWADI LETTER BBA;Lo;0;L;;;;;N;;;;;\n112D6;KHUDAWADI LETTER BHA;Lo;0;L;;;;;N;;;;;\n112D7;KHUDAWADI LETTER MA;Lo;0;L;;;;;N;;;;;\n112D8;KHUDAWADI LETTER YA;Lo;0;L;;;;;N;;;;;\n112D9;KHUDAWADI LETTER RA;Lo;0;L;;;;;N;;;;;\n112DA;KHUDAWADI LETTER LA;Lo;0;L;;;;;N;;;;;\n112DB;KHUDAWADI LETTER VA;Lo;0;L;;;;;N;;;;;\n112DC;KHUDAWADI LETTER SHA;Lo;0;L;;;;;N;;;;;\n112DD;KHUDAWADI LETTER SA;Lo;0;L;;;;;N;;;;;\n112DE;KHUDAWADI LETTER HA;Lo;0;L;;;;;N;;;;;\n112DF;KHUDAWADI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n112E0;KHUDAWADI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n112E1;KHUDAWADI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n112E2;KHUDAWADI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n112E3;KHUDAWADI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n112E4;KHUDAWADI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n112E5;KHUDAWADI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n112E6;KHUDAWADI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n112E7;KHUDAWADI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n112E8;KHUDAWADI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n112E9;KHUDAWADI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n112EA;KHUDAWADI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n112F0;KHUDAWADI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n112F1;KHUDAWADI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n112F2;KHUDAWADI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n112F3;KHUDAWADI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n112F4;KHUDAWADI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n112F5;KHUDAWADI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n112F6;KHUDAWADI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n112F7;KHUDAWADI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n112F8;KHUDAWADI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n112F9;KHUDAWADI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11300;GRANTHA SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;;\n11301;GRANTHA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n11302;GRANTHA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\n11303;GRANTHA SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11305;GRANTHA LETTER A;Lo;0;L;;;;;N;;;;;\n11306;GRANTHA LETTER AA;Lo;0;L;;;;;N;;;;;\n11307;GRANTHA LETTER I;Lo;0;L;;;;;N;;;;;\n11308;GRANTHA LETTER II;Lo;0;L;;;;;N;;;;;\n11309;GRANTHA LETTER U;Lo;0;L;;;;;N;;;;;\n1130A;GRANTHA LETTER UU;Lo;0;L;;;;;N;;;;;\n1130B;GRANTHA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n1130C;GRANTHA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n1130F;GRANTHA LETTER EE;Lo;0;L;;;;;N;;;;;\n11310;GRANTHA LETTER AI;Lo;0;L;;;;;N;;;;;\n11313;GRANTHA LETTER OO;Lo;0;L;;;;;N;;;;;\n11314;GRANTHA LETTER AU;Lo;0;L;;;;;N;;;;;\n11315;GRANTHA LETTER KA;Lo;0;L;;;;;N;;;;;\n11316;GRANTHA LETTER KHA;Lo;0;L;;;;;N;;;;;\n11317;GRANTHA LETTER GA;Lo;0;L;;;;;N;;;;;\n11318;GRANTHA LETTER GHA;Lo;0;L;;;;;N;;;;;\n11319;GRANTHA LETTER NGA;Lo;0;L;;;;;N;;;;;\n1131A;GRANTHA LETTER CA;Lo;0;L;;;;;N;;;;;\n1131B;GRANTHA LETTER CHA;Lo;0;L;;;;;N;;;;;\n1131C;GRANTHA LETTER JA;Lo;0;L;;;;;N;;;;;\n1131D;GRANTHA LETTER JHA;Lo;0;L;;;;;N;;;;;\n1131E;GRANTHA LETTER NYA;Lo;0;L;;;;;N;;;;;\n1131F;GRANTHA LETTER TTA;Lo;0;L;;;;;N;;;;;\n11320;GRANTHA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11321;GRANTHA LETTER DDA;Lo;0;L;;;;;N;;;;;\n11322;GRANTHA LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11323;GRANTHA LETTER NNA;Lo;0;L;;;;;N;;;;;\n11324;GRANTHA LETTER TA;Lo;0;L;;;;;N;;;;;\n11325;GRANTHA LETTER THA;Lo;0;L;;;;;N;;;;;\n11326;GRANTHA LETTER DA;Lo;0;L;;;;;N;;;;;\n11327;GRANTHA LETTER DHA;Lo;0;L;;;;;N;;;;;\n11328;GRANTHA LETTER NA;Lo;0;L;;;;;N;;;;;\n1132A;GRANTHA LETTER PA;Lo;0;L;;;;;N;;;;;\n1132B;GRANTHA LETTER PHA;Lo;0;L;;;;;N;;;;;\n1132C;GRANTHA LETTER BA;Lo;0;L;;;;;N;;;;;\n1132D;GRANTHA LETTER BHA;Lo;0;L;;;;;N;;;;;\n1132E;GRANTHA LETTER MA;Lo;0;L;;;;;N;;;;;\n1132F;GRANTHA LETTER YA;Lo;0;L;;;;;N;;;;;\n11330;GRANTHA LETTER RA;Lo;0;L;;;;;N;;;;;\n11332;GRANTHA LETTER LA;Lo;0;L;;;;;N;;;;;\n11333;GRANTHA LETTER LLA;Lo;0;L;;;;;N;;;;;\n11335;GRANTHA LETTER VA;Lo;0;L;;;;;N;;;;;\n11336;GRANTHA LETTER SHA;Lo;0;L;;;;;N;;;;;\n11337;GRANTHA LETTER SSA;Lo;0;L;;;;;N;;;;;\n11338;GRANTHA LETTER SA;Lo;0;L;;;;;N;;;;;\n11339;GRANTHA LETTER HA;Lo;0;L;;;;;N;;;;;\n1133B;COMBINING BINDU BELOW;Mn;7;NSM;;;;;N;;;;;\n1133C;GRANTHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n1133D;GRANTHA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n1133E;GRANTHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n1133F;GRANTHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n11340;GRANTHA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n11341;GRANTHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n11342;GRANTHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\n11343;GRANTHA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;\n11344;GRANTHA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;\n11347;GRANTHA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;\n11348;GRANTHA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n1134B;GRANTHA VOWEL SIGN OO;Mc;0;L;11347 1133E;;;;N;;;;;\n1134C;GRANTHA VOWEL SIGN AU;Mc;0;L;11347 11357;;;;N;;;;;\n1134D;GRANTHA SIGN VIRAMA;Mc;9;L;;;;;N;;;;;\n11350;GRANTHA OM;Lo;0;L;;;;;N;;;;;\n11357;GRANTHA AU LENGTH MARK;Mc;0;L;;;;;N;;;;;\n1135D;GRANTHA SIGN PLUTA;Lo;0;L;;;;;N;;;;;\n1135E;GRANTHA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;\n1135F;GRANTHA LETTER VEDIC DOUBLE ANUSVARA;Lo;0;L;;;;;N;;;;;\n11360;GRANTHA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n11361;GRANTHA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n11362;GRANTHA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;;\n11363;GRANTHA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;;\n11366;COMBINING GRANTHA DIGIT ZERO;Mn;230;NSM;;;;;N;;;;;\n11367;COMBINING GRANTHA DIGIT ONE;Mn;230;NSM;;;;;N;;;;;\n11368;COMBINING GRANTHA DIGIT TWO;Mn;230;NSM;;;;;N;;;;;\n11369;COMBINING GRANTHA DIGIT THREE;Mn;230;NSM;;;;;N;;;;;\n1136A;COMBINING GRANTHA DIGIT FOUR;Mn;230;NSM;;;;;N;;;;;\n1136B;COMBINING GRANTHA DIGIT FIVE;Mn;230;NSM;;;;;N;;;;;\n1136C;COMBINING GRANTHA DIGIT SIX;Mn;230;NSM;;;;;N;;;;;\n11370;COMBINING GRANTHA LETTER A;Mn;230;NSM;;;;;N;;;;;\n11371;COMBINING GRANTHA LETTER KA;Mn;230;NSM;;;;;N;;;;;\n11372;COMBINING GRANTHA LETTER NA;Mn;230;NSM;;;;;N;;;;;\n11373;COMBINING GRANTHA LETTER VI;Mn;230;NSM;;;;;N;;;;;\n11374;COMBINING GRANTHA LETTER PA;Mn;230;NSM;;;;;N;;;;;\n11380;TULU-TIGALARI LETTER A;Lo;0;L;;;;;N;;;;;\n11381;TULU-TIGALARI LETTER AA;Lo;0;L;;;;;N;;;;;\n11382;TULU-TIGALARI LETTER I;Lo;0;L;;;;;N;;;;;\n11383;TULU-TIGALARI LETTER II;Lo;0;L;11382 113C9;;;;N;;;;;\n11384;TULU-TIGALARI LETTER U;Lo;0;L;;;;;N;;;;;\n11385;TULU-TIGALARI LETTER UU;Lo;0;L;11384 113BB;;;;N;;;;;\n11386;TULU-TIGALARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n11387;TULU-TIGALARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n11388;TULU-TIGALARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n11389;TULU-TIGALARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n1138B;TULU-TIGALARI LETTER EE;Lo;0;L;;;;;N;;;;;\n1138E;TULU-TIGALARI LETTER AI;Lo;0;L;1138B 113C2;;;;N;;;;;\n11390;TULU-TIGALARI LETTER OO;Lo;0;L;;;;;N;;;;;\n11391;TULU-TIGALARI LETTER AU;Lo;0;L;11390 113C9;;;;N;;;;;\n11392;TULU-TIGALARI LETTER KA;Lo;0;L;;;;;N;;;;;\n11393;TULU-TIGALARI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11394;TULU-TIGALARI LETTER GA;Lo;0;L;;;;;N;;;;;\n11395;TULU-TIGALARI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11396;TULU-TIGALARI LETTER NGA;Lo;0;L;;;;;N;;;;;\n11397;TULU-TIGALARI LETTER CA;Lo;0;L;;;;;N;;;;;\n11398;TULU-TIGALARI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11399;TULU-TIGALARI LETTER JA;Lo;0;L;;;;;N;;;;;\n1139A;TULU-TIGALARI LETTER JHA;Lo;0;L;;;;;N;;;;;\n1139B;TULU-TIGALARI LETTER NYA;Lo;0;L;;;;;N;;;;;\n1139C;TULU-TIGALARI LETTER TTA;Lo;0;L;;;;;N;;;;;\n1139D;TULU-TIGALARI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1139E;TULU-TIGALARI LETTER DDA;Lo;0;L;;;;;N;;;;;\n1139F;TULU-TIGALARI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n113A0;TULU-TIGALARI LETTER NNA;Lo;0;L;;;;;N;;;;;\n113A1;TULU-TIGALARI LETTER TA;Lo;0;L;;;;;N;;;;;\n113A2;TULU-TIGALARI LETTER THA;Lo;0;L;;;;;N;;;;;\n113A3;TULU-TIGALARI LETTER DA;Lo;0;L;;;;;N;;;;;\n113A4;TULU-TIGALARI LETTER DHA;Lo;0;L;;;;;N;;;;;\n113A5;TULU-TIGALARI LETTER NA;Lo;0;L;;;;;N;;;;;\n113A6;TULU-TIGALARI LETTER PA;Lo;0;L;;;;;N;;;;;\n113A7;TULU-TIGALARI LETTER PHA;Lo;0;L;;;;;N;;;;;\n113A8;TULU-TIGALARI LETTER BA;Lo;0;L;;;;;N;;;;;\n113A9;TULU-TIGALARI LETTER BHA;Lo;0;L;;;;;N;;;;;\n113AA;TULU-TIGALARI LETTER MA;Lo;0;L;;;;;N;;;;;\n113AB;TULU-TIGALARI LETTER YA;Lo;0;L;;;;;N;;;;;\n113AC;TULU-TIGALARI LETTER RA;Lo;0;L;;;;;N;;;;;\n113AD;TULU-TIGALARI LETTER LA;Lo;0;L;;;;;N;;;;;\n113AE;TULU-TIGALARI LETTER VA;Lo;0;L;;;;;N;;;;;\n113AF;TULU-TIGALARI LETTER SHA;Lo;0;L;;;;;N;;;;;\n113B0;TULU-TIGALARI LETTER SSA;Lo;0;L;;;;;N;;;;;\n113B1;TULU-TIGALARI LETTER SA;Lo;0;L;;;;;N;;;;;\n113B2;TULU-TIGALARI LETTER HA;Lo;0;L;;;;;N;;;;;\n113B3;TULU-TIGALARI LETTER LLA;Lo;0;L;;;;;N;;;;;\n113B4;TULU-TIGALARI LETTER RRA;Lo;0;L;;;;;N;;;;;\n113B5;TULU-TIGALARI LETTER LLLA;Lo;0;L;;;;;N;;;;;\n113B7;TULU-TIGALARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n113B8;TULU-TIGALARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n113B9;TULU-TIGALARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n113BA;TULU-TIGALARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n113BB;TULU-TIGALARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n113BC;TULU-TIGALARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n113BD;TULU-TIGALARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n113BE;TULU-TIGALARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n113BF;TULU-TIGALARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n113C0;TULU-TIGALARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n113C2;TULU-TIGALARI VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;\n113C5;TULU-TIGALARI VOWEL SIGN AI;Mc;0;L;113C2 113C2;;;;N;;;;;\n113C7;TULU-TIGALARI VOWEL SIGN OO;Mc;0;L;113C2 113B8;;;;N;;;;;\n113C8;TULU-TIGALARI VOWEL SIGN AU;Mc;0;L;113C2 113C9;;;;N;;;;;\n113C9;TULU-TIGALARI AU LENGTH MARK;Mc;0;L;;;;;N;;;;;\n113CA;TULU-TIGALARI SIGN CANDRA ANUNASIKA;Mc;0;L;;;;;N;;;;;\n113CC;TULU-TIGALARI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\n113CD;TULU-TIGALARI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n113CE;TULU-TIGALARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n113CF;TULU-TIGALARI SIGN LOOPED VIRAMA;Mc;9;L;;;;;N;;;;;\n113D0;TULU-TIGALARI CONJOINER;Mn;9;NSM;;;;;N;;;;;\n113D1;TULU-TIGALARI REPHA;Lo;0;L;;;;;N;;;;;\n113D2;TULU-TIGALARI GEMINATION MARK;Mn;0;NSM;;;;;N;;;;;\n113D3;TULU-TIGALARI SIGN PLUTA;Lo;0;L;;;;;N;;;;;\n113D4;TULU-TIGALARI DANDA;Po;0;L;;;;;N;;;;;\n113D5;TULU-TIGALARI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n113D7;TULU-TIGALARI SIGN OM PUSHPIKA;Po;0;L;;;;;N;;;;;\n113D8;TULU-TIGALARI SIGN SHRII PUSHPIKA;Po;0;L;;;;;N;;;;;\n113E1;TULU-TIGALARI VEDIC TONE SVARITA;Mn;0;NSM;;;;;N;;;;;\n113E2;TULU-TIGALARI VEDIC TONE ANUDATTA;Mn;0;NSM;;;;;N;;;;;\n11400;NEWA LETTER A;Lo;0;L;;;;;N;;;;;\n11401;NEWA LETTER AA;Lo;0;L;;;;;N;;;;;\n11402;NEWA LETTER I;Lo;0;L;;;;;N;;;;;\n11403;NEWA LETTER II;Lo;0;L;;;;;N;;;;;\n11404;NEWA LETTER U;Lo;0;L;;;;;N;;;;;\n11405;NEWA LETTER UU;Lo;0;L;;;;;N;;;;;\n11406;NEWA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n11407;NEWA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n11408;NEWA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n11409;NEWA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n1140A;NEWA LETTER E;Lo;0;L;;;;;N;;;;;\n1140B;NEWA LETTER AI;Lo;0;L;;;;;N;;;;;\n1140C;NEWA LETTER O;Lo;0;L;;;;;N;;;;;\n1140D;NEWA LETTER AU;Lo;0;L;;;;;N;;;;;\n1140E;NEWA LETTER KA;Lo;0;L;;;;;N;;;;;\n1140F;NEWA LETTER KHA;Lo;0;L;;;;;N;;;;;\n11410;NEWA LETTER GA;Lo;0;L;;;;;N;;;;;\n11411;NEWA LETTER GHA;Lo;0;L;;;;;N;;;;;\n11412;NEWA LETTER NGA;Lo;0;L;;;;;N;;;;;\n11413;NEWA LETTER NGHA;Lo;0;L;;;;;N;;;;;\n11414;NEWA LETTER CA;Lo;0;L;;;;;N;;;;;\n11415;NEWA LETTER CHA;Lo;0;L;;;;;N;;;;;\n11416;NEWA LETTER JA;Lo;0;L;;;;;N;;;;;\n11417;NEWA LETTER JHA;Lo;0;L;;;;;N;;;;;\n11418;NEWA LETTER NYA;Lo;0;L;;;;;N;;;;;\n11419;NEWA LETTER NYHA;Lo;0;L;;;;;N;;;;;\n1141A;NEWA LETTER TTA;Lo;0;L;;;;;N;;;;;\n1141B;NEWA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1141C;NEWA LETTER DDA;Lo;0;L;;;;;N;;;;;\n1141D;NEWA LETTER DDHA;Lo;0;L;;;;;N;;;;;\n1141E;NEWA LETTER NNA;Lo;0;L;;;;;N;;;;;\n1141F;NEWA LETTER TA;Lo;0;L;;;;;N;;;;;\n11420;NEWA LETTER THA;Lo;0;L;;;;;N;;;;;\n11421;NEWA LETTER DA;Lo;0;L;;;;;N;;;;;\n11422;NEWA LETTER DHA;Lo;0;L;;;;;N;;;;;\n11423;NEWA LETTER NA;Lo;0;L;;;;;N;;;;;\n11424;NEWA LETTER NHA;Lo;0;L;;;;;N;;;;;\n11425;NEWA LETTER PA;Lo;0;L;;;;;N;;;;;\n11426;NEWA LETTER PHA;Lo;0;L;;;;;N;;;;;\n11427;NEWA LETTER BA;Lo;0;L;;;;;N;;;;;\n11428;NEWA LETTER BHA;Lo;0;L;;;;;N;;;;;\n11429;NEWA LETTER MA;Lo;0;L;;;;;N;;;;;\n1142A;NEWA LETTER MHA;Lo;0;L;;;;;N;;;;;\n1142B;NEWA LETTER YA;Lo;0;L;;;;;N;;;;;\n1142C;NEWA LETTER RA;Lo;0;L;;;;;N;;;;;\n1142D;NEWA LETTER RHA;Lo;0;L;;;;;N;;;;;\n1142E;NEWA LETTER LA;Lo;0;L;;;;;N;;;;;\n1142F;NEWA LETTER LHA;Lo;0;L;;;;;N;;;;;\n11430;NEWA LETTER WA;Lo;0;L;;;;;N;;;;;\n11431;NEWA LETTER SHA;Lo;0;L;;;;;N;;;;;\n11432;NEWA LETTER SSA;Lo;0;L;;;;;N;;;;;\n11433;NEWA LETTER SA;Lo;0;L;;;;;N;;;;;\n11434;NEWA LETTER HA;Lo;0;L;;;;;N;;;;;\n11435;NEWA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n11436;NEWA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n11437;NEWA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n11438;NEWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11439;NEWA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n1143A;NEWA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n1143B;NEWA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n1143C;NEWA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n1143D;NEWA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n1143E;NEWA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n1143F;NEWA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n11440;NEWA VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n11441;NEWA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n11442;NEWA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n11443;NEWA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n11444;NEWA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11445;NEWA SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11446;NEWA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n11447;NEWA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n11448;NEWA SIGN FINAL ANUSVARA;Lo;0;L;;;;;N;;;;;\n11449;NEWA OM;Lo;0;L;;;;;N;;;;;\n1144A;NEWA SIDDHI;Lo;0;L;;;;;N;;;;;\n1144B;NEWA DANDA;Po;0;L;;;;;N;;;;;\n1144C;NEWA DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n1144D;NEWA COMMA;Po;0;L;;;;;N;;;;;\n1144E;NEWA GAP FILLER;Po;0;L;;;;;N;;;;;\n1144F;NEWA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n11450;NEWA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11451;NEWA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11452;NEWA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11453;NEWA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11454;NEWA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11455;NEWA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11456;NEWA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11457;NEWA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11458;NEWA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1145A;NEWA DOUBLE COMMA;Po;0;L;;;;;N;;;;;\n1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;;\n1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;;\n1145E;NEWA SANDHI MARK;Mn;230;NSM;;;;;N;;;;;\n1145F;NEWA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;\n11460;NEWA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;\n11461;NEWA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;\n11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;;\n11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;;\n11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;;\n11483;TIRHUTA LETTER I;Lo;0;L;;;;;N;;;;;\n11484;TIRHUTA LETTER II;Lo;0;L;;;;;N;;;;;\n11485;TIRHUTA LETTER U;Lo;0;L;;;;;N;;;;;\n11486;TIRHUTA LETTER UU;Lo;0;L;;;;;N;;;;;\n11487;TIRHUTA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n11488;TIRHUTA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n11489;TIRHUTA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n1148A;TIRHUTA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n1148B;TIRHUTA LETTER E;Lo;0;L;;;;;N;;;;;\n1148C;TIRHUTA LETTER AI;Lo;0;L;;;;;N;;;;;\n1148D;TIRHUTA LETTER O;Lo;0;L;;;;;N;;;;;\n1148E;TIRHUTA LETTER AU;Lo;0;L;;;;;N;;;;;\n1148F;TIRHUTA LETTER KA;Lo;0;L;;;;;N;;;;;\n11490;TIRHUTA LETTER KHA;Lo;0;L;;;;;N;;;;;\n11491;TIRHUTA LETTER GA;Lo;0;L;;;;;N;;;;;\n11492;TIRHUTA LETTER GHA;Lo;0;L;;;;;N;;;;;\n11493;TIRHUTA LETTER NGA;Lo;0;L;;;;;N;;;;;\n11494;TIRHUTA LETTER CA;Lo;0;L;;;;;N;;;;;\n11495;TIRHUTA LETTER CHA;Lo;0;L;;;;;N;;;;;\n11496;TIRHUTA LETTER JA;Lo;0;L;;;;;N;;;;;\n11497;TIRHUTA LETTER JHA;Lo;0;L;;;;;N;;;;;\n11498;TIRHUTA LETTER NYA;Lo;0;L;;;;;N;;;;;\n11499;TIRHUTA LETTER TTA;Lo;0;L;;;;;N;;;;;\n1149A;TIRHUTA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1149B;TIRHUTA LETTER DDA;Lo;0;L;;;;;N;;;;;\n1149C;TIRHUTA LETTER DDHA;Lo;0;L;;;;;N;;;;;\n1149D;TIRHUTA LETTER NNA;Lo;0;L;;;;;N;;;;;\n1149E;TIRHUTA LETTER TA;Lo;0;L;;;;;N;;;;;\n1149F;TIRHUTA LETTER THA;Lo;0;L;;;;;N;;;;;\n114A0;TIRHUTA LETTER DA;Lo;0;L;;;;;N;;;;;\n114A1;TIRHUTA LETTER DHA;Lo;0;L;;;;;N;;;;;\n114A2;TIRHUTA LETTER NA;Lo;0;L;;;;;N;;;;;\n114A3;TIRHUTA LETTER PA;Lo;0;L;;;;;N;;;;;\n114A4;TIRHUTA LETTER PHA;Lo;0;L;;;;;N;;;;;\n114A5;TIRHUTA LETTER BA;Lo;0;L;;;;;N;;;;;\n114A6;TIRHUTA LETTER BHA;Lo;0;L;;;;;N;;;;;\n114A7;TIRHUTA LETTER MA;Lo;0;L;;;;;N;;;;;\n114A8;TIRHUTA LETTER YA;Lo;0;L;;;;;N;;;;;\n114A9;TIRHUTA LETTER RA;Lo;0;L;;;;;N;;;;;\n114AA;TIRHUTA LETTER LA;Lo;0;L;;;;;N;;;;;\n114AB;TIRHUTA LETTER VA;Lo;0;L;;;;;N;;;;;\n114AC;TIRHUTA LETTER SHA;Lo;0;L;;;;;N;;;;;\n114AD;TIRHUTA LETTER SSA;Lo;0;L;;;;;N;;;;;\n114AE;TIRHUTA LETTER SA;Lo;0;L;;;;;N;;;;;\n114AF;TIRHUTA LETTER HA;Lo;0;L;;;;;N;;;;;\n114B0;TIRHUTA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n114B1;TIRHUTA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n114B2;TIRHUTA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n114B3;TIRHUTA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n114B4;TIRHUTA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n114B5;TIRHUTA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n114B6;TIRHUTA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n114B7;TIRHUTA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n114B8;TIRHUTA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n114B9;TIRHUTA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n114BA;TIRHUTA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;\n114BB;TIRHUTA VOWEL SIGN AI;Mc;0;L;114B9 114BA;;;;N;;;;;\n114BC;TIRHUTA VOWEL SIGN O;Mc;0;L;114B9 114B0;;;;N;;;;;\n114BD;TIRHUTA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;\n114BE;TIRHUTA VOWEL SIGN AU;Mc;0;L;114B9 114BD;;;;N;;;;;\n114BF;TIRHUTA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n114C0;TIRHUTA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n114C1;TIRHUTA SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n114C2;TIRHUTA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n114C3;TIRHUTA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n114C4;TIRHUTA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n114C5;TIRHUTA GVANG;Lo;0;L;;;;;N;;;;;\n114C6;TIRHUTA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n114C7;TIRHUTA OM;Lo;0;L;;;;;N;;;;;\n114D0;TIRHUTA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n114D1;TIRHUTA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n114D2;TIRHUTA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n114D3;TIRHUTA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n114D4;TIRHUTA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n114D5;TIRHUTA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n114D6;TIRHUTA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n114D7;TIRHUTA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n114D8;TIRHUTA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n114D9;TIRHUTA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11580;SIDDHAM LETTER A;Lo;0;L;;;;;N;;;;;\n11581;SIDDHAM LETTER AA;Lo;0;L;;;;;N;;;;;\n11582;SIDDHAM LETTER I;Lo;0;L;;;;;N;;;;;\n11583;SIDDHAM LETTER II;Lo;0;L;;;;;N;;;;;\n11584;SIDDHAM LETTER U;Lo;0;L;;;;;N;;;;;\n11585;SIDDHAM LETTER UU;Lo;0;L;;;;;N;;;;;\n11586;SIDDHAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n11587;SIDDHAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n11588;SIDDHAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n11589;SIDDHAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n1158A;SIDDHAM LETTER E;Lo;0;L;;;;;N;;;;;\n1158B;SIDDHAM LETTER AI;Lo;0;L;;;;;N;;;;;\n1158C;SIDDHAM LETTER O;Lo;0;L;;;;;N;;;;;\n1158D;SIDDHAM LETTER AU;Lo;0;L;;;;;N;;;;;\n1158E;SIDDHAM LETTER KA;Lo;0;L;;;;;N;;;;;\n1158F;SIDDHAM LETTER KHA;Lo;0;L;;;;;N;;;;;\n11590;SIDDHAM LETTER GA;Lo;0;L;;;;;N;;;;;\n11591;SIDDHAM LETTER GHA;Lo;0;L;;;;;N;;;;;\n11592;SIDDHAM LETTER NGA;Lo;0;L;;;;;N;;;;;\n11593;SIDDHAM LETTER CA;Lo;0;L;;;;;N;;;;;\n11594;SIDDHAM LETTER CHA;Lo;0;L;;;;;N;;;;;\n11595;SIDDHAM LETTER JA;Lo;0;L;;;;;N;;;;;\n11596;SIDDHAM LETTER JHA;Lo;0;L;;;;;N;;;;;\n11597;SIDDHAM LETTER NYA;Lo;0;L;;;;;N;;;;;\n11598;SIDDHAM LETTER TTA;Lo;0;L;;;;;N;;;;;\n11599;SIDDHAM LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1159A;SIDDHAM LETTER DDA;Lo;0;L;;;;;N;;;;;\n1159B;SIDDHAM LETTER DDHA;Lo;0;L;;;;;N;;;;;\n1159C;SIDDHAM LETTER NNA;Lo;0;L;;;;;N;;;;;\n1159D;SIDDHAM LETTER TA;Lo;0;L;;;;;N;;;;;\n1159E;SIDDHAM LETTER THA;Lo;0;L;;;;;N;;;;;\n1159F;SIDDHAM LETTER DA;Lo;0;L;;;;;N;;;;;\n115A0;SIDDHAM LETTER DHA;Lo;0;L;;;;;N;;;;;\n115A1;SIDDHAM LETTER NA;Lo;0;L;;;;;N;;;;;\n115A2;SIDDHAM LETTER PA;Lo;0;L;;;;;N;;;;;\n115A3;SIDDHAM LETTER PHA;Lo;0;L;;;;;N;;;;;\n115A4;SIDDHAM LETTER BA;Lo;0;L;;;;;N;;;;;\n115A5;SIDDHAM LETTER BHA;Lo;0;L;;;;;N;;;;;\n115A6;SIDDHAM LETTER MA;Lo;0;L;;;;;N;;;;;\n115A7;SIDDHAM LETTER YA;Lo;0;L;;;;;N;;;;;\n115A8;SIDDHAM LETTER RA;Lo;0;L;;;;;N;;;;;\n115A9;SIDDHAM LETTER LA;Lo;0;L;;;;;N;;;;;\n115AA;SIDDHAM LETTER VA;Lo;0;L;;;;;N;;;;;\n115AB;SIDDHAM LETTER SHA;Lo;0;L;;;;;N;;;;;\n115AC;SIDDHAM LETTER SSA;Lo;0;L;;;;;N;;;;;\n115AD;SIDDHAM LETTER SA;Lo;0;L;;;;;N;;;;;\n115AE;SIDDHAM LETTER HA;Lo;0;L;;;;;N;;;;;\n115AF;SIDDHAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n115B0;SIDDHAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n115B1;SIDDHAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n115B2;SIDDHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n115B3;SIDDHAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n115B4;SIDDHAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n115B5;SIDDHAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n115B8;SIDDHAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n115B9;SIDDHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n115BA;SIDDHAM VOWEL SIGN O;Mc;0;L;115B8 115AF;;;;N;;;;;\n115BB;SIDDHAM VOWEL SIGN AU;Mc;0;L;115B9 115AF;;;;N;;;;;\n115BC;SIDDHAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n115BD;SIDDHAM SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n115BE;SIDDHAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n115BF;SIDDHAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n115C0;SIDDHAM SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n115C1;SIDDHAM SIGN SIDDHAM;Po;0;L;;;;;N;;;;;\n115C2;SIDDHAM DANDA;Po;0;L;;;;;N;;;;;\n115C3;SIDDHAM DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n115C4;SIDDHAM SEPARATOR DOT;Po;0;L;;;;;N;;;;;\n115C5;SIDDHAM SEPARATOR BAR;Po;0;L;;;;;N;;;;;\n115C6;SIDDHAM REPETITION MARK-1;Po;0;L;;;;;N;;;;;\n115C7;SIDDHAM REPETITION MARK-2;Po;0;L;;;;;N;;;;;\n115C8;SIDDHAM REPETITION MARK-3;Po;0;L;;;;;N;;;;;\n115C9;SIDDHAM END OF TEXT MARK;Po;0;L;;;;;N;;;;;\n115CA;SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS;Po;0;L;;;;;N;;;;;\n115CB;SIDDHAM SECTION MARK WITH TRIDENT AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;;\n115CC;SIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;;\n115CD;SIDDHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;;\n115CE;SIDDHAM SECTION MARK WITH RAYS AND DOTTED TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;;\n115CF;SIDDHAM SECTION MARK DOUBLE RING;Po;0;L;;;;;N;;;;;\n115D0;SIDDHAM SECTION MARK DOUBLE RING WITH RAYS;Po;0;L;;;;;N;;;;;\n115D1;SIDDHAM SECTION MARK WITH DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;;\n115D2;SIDDHAM SECTION MARK WITH TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;;\n115D3;SIDDHAM SECTION MARK WITH QUADRUPLE CRESCENTS;Po;0;L;;;;;N;;;;;\n115D4;SIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS;Po;0;L;;;;;N;;;;;\n115D5;SIDDHAM SECTION MARK WITH CIRCLES AND RAYS;Po;0;L;;;;;N;;;;;\n115D6;SIDDHAM SECTION MARK WITH CIRCLES AND TWO ENCLOSURES;Po;0;L;;;;;N;;;;;\n115D7;SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES;Po;0;L;;;;;N;;;;;\n115D8;SIDDHAM LETTER THREE-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;;\n115D9;SIDDHAM LETTER TWO-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;;\n115DA;SIDDHAM LETTER TWO-CIRCLE ALTERNATE II;Lo;0;L;;;;;N;;;;;\n115DB;SIDDHAM LETTER ALTERNATE U;Lo;0;L;;;;;N;;;;;\n115DC;SIDDHAM VOWEL SIGN ALTERNATE U;Mn;0;NSM;;;;;N;;;;;\n115DD;SIDDHAM VOWEL SIGN ALTERNATE UU;Mn;0;NSM;;;;;N;;;;;\n11600;MODI LETTER A;Lo;0;L;;;;;N;;;;;\n11601;MODI LETTER AA;Lo;0;L;;;;;N;;;;;\n11602;MODI LETTER I;Lo;0;L;;;;;N;;;;;\n11603;MODI LETTER II;Lo;0;L;;;;;N;;;;;\n11604;MODI LETTER U;Lo;0;L;;;;;N;;;;;\n11605;MODI LETTER UU;Lo;0;L;;;;;N;;;;;\n11606;MODI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n11607;MODI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n11608;MODI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n11609;MODI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n1160A;MODI LETTER E;Lo;0;L;;;;;N;;;;;\n1160B;MODI LETTER AI;Lo;0;L;;;;;N;;;;;\n1160C;MODI LETTER O;Lo;0;L;;;;;N;;;;;\n1160D;MODI LETTER AU;Lo;0;L;;;;;N;;;;;\n1160E;MODI LETTER KA;Lo;0;L;;;;;N;;;;;\n1160F;MODI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11610;MODI LETTER GA;Lo;0;L;;;;;N;;;;;\n11611;MODI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11612;MODI LETTER NGA;Lo;0;L;;;;;N;;;;;\n11613;MODI LETTER CA;Lo;0;L;;;;;N;;;;;\n11614;MODI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11615;MODI LETTER JA;Lo;0;L;;;;;N;;;;;\n11616;MODI LETTER JHA;Lo;0;L;;;;;N;;;;;\n11617;MODI LETTER NYA;Lo;0;L;;;;;N;;;;;\n11618;MODI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11619;MODI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1161A;MODI LETTER DDA;Lo;0;L;;;;;N;;;;;\n1161B;MODI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n1161C;MODI LETTER NNA;Lo;0;L;;;;;N;;;;;\n1161D;MODI LETTER TA;Lo;0;L;;;;;N;;;;;\n1161E;MODI LETTER THA;Lo;0;L;;;;;N;;;;;\n1161F;MODI LETTER DA;Lo;0;L;;;;;N;;;;;\n11620;MODI LETTER DHA;Lo;0;L;;;;;N;;;;;\n11621;MODI LETTER NA;Lo;0;L;;;;;N;;;;;\n11622;MODI LETTER PA;Lo;0;L;;;;;N;;;;;\n11623;MODI LETTER PHA;Lo;0;L;;;;;N;;;;;\n11624;MODI LETTER BA;Lo;0;L;;;;;N;;;;;\n11625;MODI LETTER BHA;Lo;0;L;;;;;N;;;;;\n11626;MODI LETTER MA;Lo;0;L;;;;;N;;;;;\n11627;MODI LETTER YA;Lo;0;L;;;;;N;;;;;\n11628;MODI LETTER RA;Lo;0;L;;;;;N;;;;;\n11629;MODI LETTER LA;Lo;0;L;;;;;N;;;;;\n1162A;MODI LETTER VA;Lo;0;L;;;;;N;;;;;\n1162B;MODI LETTER SHA;Lo;0;L;;;;;N;;;;;\n1162C;MODI LETTER SSA;Lo;0;L;;;;;N;;;;;\n1162D;MODI LETTER SA;Lo;0;L;;;;;N;;;;;\n1162E;MODI LETTER HA;Lo;0;L;;;;;N;;;;;\n1162F;MODI LETTER LLA;Lo;0;L;;;;;N;;;;;\n11630;MODI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n11631;MODI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n11632;MODI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n11633;MODI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11634;MODI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n11635;MODI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n11636;MODI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n11637;MODI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n11638;MODI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;\n11639;MODI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n1163A;MODI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n1163B;MODI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n1163C;MODI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n1163D;MODI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n1163E;MODI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n1163F;MODI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n11640;MODI SIGN ARDHACANDRA;Mn;0;NSM;;;;;N;;;;;\n11641;MODI DANDA;Po;0;L;;;;;N;;;;;\n11642;MODI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n11643;MODI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n11644;MODI SIGN HUVA;Lo;0;L;;;;;N;;;;;\n11650;MODI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11651;MODI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11652;MODI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11653;MODI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11654;MODI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11655;MODI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11656;MODI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11657;MODI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11658;MODI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11659;MODI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11660;MONGOLIAN BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;\n11661;MONGOLIAN ROTATED BIRGA;Po;0;ON;;;;;N;;;;;\n11662;MONGOLIAN DOUBLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;\n11663;MONGOLIAN TRIPLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;\n11664;MONGOLIAN BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;\n11665;MONGOLIAN ROTATED BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;\n11666;MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;\n11667;MONGOLIAN INVERTED BIRGA;Po;0;ON;;;;;N;;;;;\n11668;MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;\n11669;MONGOLIAN SWIRL BIRGA;Po;0;ON;;;;;N;;;;;\n1166A;MONGOLIAN SWIRL BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;\n1166B;MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;\n1166C;MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;\n11680;TAKRI LETTER A;Lo;0;L;;;;;N;;;;;\n11681;TAKRI LETTER AA;Lo;0;L;;;;;N;;;;;\n11682;TAKRI LETTER I;Lo;0;L;;;;;N;;;;;\n11683;TAKRI LETTER II;Lo;0;L;;;;;N;;;;;\n11684;TAKRI LETTER U;Lo;0;L;;;;;N;;;;;\n11685;TAKRI LETTER UU;Lo;0;L;;;;;N;;;;;\n11686;TAKRI LETTER E;Lo;0;L;;;;;N;;;;;\n11687;TAKRI LETTER AI;Lo;0;L;;;;;N;;;;;\n11688;TAKRI LETTER O;Lo;0;L;;;;;N;;;;;\n11689;TAKRI LETTER AU;Lo;0;L;;;;;N;;;;;\n1168A;TAKRI LETTER KA;Lo;0;L;;;;;N;;;;;\n1168B;TAKRI LETTER KHA;Lo;0;L;;;;;N;;;;;\n1168C;TAKRI LETTER GA;Lo;0;L;;;;;N;;;;;\n1168D;TAKRI LETTER GHA;Lo;0;L;;;;;N;;;;;\n1168E;TAKRI LETTER NGA;Lo;0;L;;;;;N;;;;;\n1168F;TAKRI LETTER CA;Lo;0;L;;;;;N;;;;;\n11690;TAKRI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11691;TAKRI LETTER JA;Lo;0;L;;;;;N;;;;;\n11692;TAKRI LETTER JHA;Lo;0;L;;;;;N;;;;;\n11693;TAKRI LETTER NYA;Lo;0;L;;;;;N;;;;;\n11694;TAKRI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11695;TAKRI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11696;TAKRI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11697;TAKRI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11698;TAKRI LETTER NNA;Lo;0;L;;;;;N;;;;;\n11699;TAKRI LETTER TA;Lo;0;L;;;;;N;;;;;\n1169A;TAKRI LETTER THA;Lo;0;L;;;;;N;;;;;\n1169B;TAKRI LETTER DA;Lo;0;L;;;;;N;;;;;\n1169C;TAKRI LETTER DHA;Lo;0;L;;;;;N;;;;;\n1169D;TAKRI LETTER NA;Lo;0;L;;;;;N;;;;;\n1169E;TAKRI LETTER PA;Lo;0;L;;;;;N;;;;;\n1169F;TAKRI LETTER PHA;Lo;0;L;;;;;N;;;;;\n116A0;TAKRI LETTER BA;Lo;0;L;;;;;N;;;;;\n116A1;TAKRI LETTER BHA;Lo;0;L;;;;;N;;;;;\n116A2;TAKRI LETTER MA;Lo;0;L;;;;;N;;;;;\n116A3;TAKRI LETTER YA;Lo;0;L;;;;;N;;;;;\n116A4;TAKRI LETTER RA;Lo;0;L;;;;;N;;;;;\n116A5;TAKRI LETTER LA;Lo;0;L;;;;;N;;;;;\n116A6;TAKRI LETTER VA;Lo;0;L;;;;;N;;;;;\n116A7;TAKRI LETTER SHA;Lo;0;L;;;;;N;;;;;\n116A8;TAKRI LETTER SA;Lo;0;L;;;;;N;;;;;\n116A9;TAKRI LETTER HA;Lo;0;L;;;;;N;;;;;\n116AA;TAKRI LETTER RRA;Lo;0;L;;;;;N;;;;;\n116AB;TAKRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n116AC;TAKRI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n116AD;TAKRI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;\n116AE;TAKRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n116AF;TAKRI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n116B0;TAKRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n116B1;TAKRI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n116B2;TAKRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n116B3;TAKRI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n116B4;TAKRI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n116B5;TAKRI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n116B6;TAKRI SIGN VIRAMA;Mc;9;L;;;;;N;;;;;\n116B7;TAKRI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n116B8;TAKRI LETTER ARCHAIC KHA;Lo;0;L;;;;;N;;;;;\n116B9;TAKRI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n116C0;TAKRI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n116C1;TAKRI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n116C2;TAKRI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n116C3;TAKRI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n116C4;TAKRI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n116C5;TAKRI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n116C6;TAKRI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n116C7;TAKRI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n116C8;TAKRI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n116C9;TAKRI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n116D0;MYANMAR PAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n116D1;MYANMAR PAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n116D2;MYANMAR PAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n116D3;MYANMAR PAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n116D4;MYANMAR PAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n116D5;MYANMAR PAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n116D6;MYANMAR PAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n116D7;MYANMAR PAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n116D8;MYANMAR PAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n116D9;MYANMAR PAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n116DA;MYANMAR EASTERN PWO KAREN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n116DB;MYANMAR EASTERN PWO KAREN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n116DC;MYANMAR EASTERN PWO KAREN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n116DD;MYANMAR EASTERN PWO KAREN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n116DE;MYANMAR EASTERN PWO KAREN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n116DF;MYANMAR EASTERN PWO KAREN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n116E0;MYANMAR EASTERN PWO KAREN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n116E1;MYANMAR EASTERN PWO KAREN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n116E2;MYANMAR EASTERN PWO KAREN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n116E3;MYANMAR EASTERN PWO KAREN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11700;AHOM LETTER KA;Lo;0;L;;;;;N;;;;;\n11701;AHOM LETTER KHA;Lo;0;L;;;;;N;;;;;\n11702;AHOM LETTER NGA;Lo;0;L;;;;;N;;;;;\n11703;AHOM LETTER NA;Lo;0;L;;;;;N;;;;;\n11704;AHOM LETTER TA;Lo;0;L;;;;;N;;;;;\n11705;AHOM LETTER ALTERNATE TA;Lo;0;L;;;;;N;;;;;\n11706;AHOM LETTER PA;Lo;0;L;;;;;N;;;;;\n11707;AHOM LETTER PHA;Lo;0;L;;;;;N;;;;;\n11708;AHOM LETTER BA;Lo;0;L;;;;;N;;;;;\n11709;AHOM LETTER MA;Lo;0;L;;;;;N;;;;;\n1170A;AHOM LETTER JA;Lo;0;L;;;;;N;;;;;\n1170B;AHOM LETTER CHA;Lo;0;L;;;;;N;;;;;\n1170C;AHOM LETTER THA;Lo;0;L;;;;;N;;;;;\n1170D;AHOM LETTER RA;Lo;0;L;;;;;N;;;;;\n1170E;AHOM LETTER LA;Lo;0;L;;;;;N;;;;;\n1170F;AHOM LETTER SA;Lo;0;L;;;;;N;;;;;\n11710;AHOM LETTER NYA;Lo;0;L;;;;;N;;;;;\n11711;AHOM LETTER HA;Lo;0;L;;;;;N;;;;;\n11712;AHOM LETTER A;Lo;0;L;;;;;N;;;;;\n11713;AHOM LETTER DA;Lo;0;L;;;;;N;;;;;\n11714;AHOM LETTER DHA;Lo;0;L;;;;;N;;;;;\n11715;AHOM LETTER GA;Lo;0;L;;;;;N;;;;;\n11716;AHOM LETTER ALTERNATE GA;Lo;0;L;;;;;N;;;;;\n11717;AHOM LETTER GHA;Lo;0;L;;;;;N;;;;;\n11718;AHOM LETTER BHA;Lo;0;L;;;;;N;;;;;\n11719;AHOM LETTER JHA;Lo;0;L;;;;;N;;;;;\n1171A;AHOM LETTER ALTERNATE BA;Lo;0;L;;;;;N;;;;;\n1171D;AHOM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;;\n1171E;AHOM CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;;\n1171F;AHOM CONSONANT SIGN MEDIAL LIGATING RA;Mn;0;NSM;;;;;N;;;;;\n11720;AHOM VOWEL SIGN A;Mc;0;L;;;;;N;;;;;\n11721;AHOM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n11722;AHOM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n11723;AHOM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n11724;AHOM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11725;AHOM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n11726;AHOM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n11727;AHOM VOWEL SIGN AW;Mn;0;NSM;;;;;N;;;;;\n11728;AHOM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n11729;AHOM VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n1172A;AHOM VOWEL SIGN AM;Mn;0;NSM;;;;;N;;;;;\n1172B;AHOM SIGN KILLER;Mn;9;NSM;;;;;N;;;;;\n11730;AHOM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11731;AHOM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11732;AHOM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11733;AHOM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11734;AHOM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11735;AHOM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11736;AHOM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11737;AHOM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11738;AHOM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11739;AHOM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1173A;AHOM NUMBER TEN;No;0;L;;;;10;N;;;;;\n1173B;AHOM NUMBER TWENTY;No;0;L;;;;20;N;;;;;\n1173C;AHOM SIGN SMALL SECTION;Po;0;L;;;;;N;;;;;\n1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;;\n1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;;\n1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;;\n11740;AHOM LETTER CA;Lo;0;L;;;;;N;;;;;\n11741;AHOM LETTER TTA;Lo;0;L;;;;;N;;;;;\n11742;AHOM LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11743;AHOM LETTER DDA;Lo;0;L;;;;;N;;;;;\n11744;AHOM LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11745;AHOM LETTER NNA;Lo;0;L;;;;;N;;;;;\n11746;AHOM LETTER LLA;Lo;0;L;;;;;N;;;;;\n11800;DOGRA LETTER A;Lo;0;L;;;;;N;;;;;\n11801;DOGRA LETTER AA;Lo;0;L;;;;;N;;;;;\n11802;DOGRA LETTER I;Lo;0;L;;;;;N;;;;;\n11803;DOGRA LETTER II;Lo;0;L;;;;;N;;;;;\n11804;DOGRA LETTER U;Lo;0;L;;;;;N;;;;;\n11805;DOGRA LETTER UU;Lo;0;L;;;;;N;;;;;\n11806;DOGRA LETTER E;Lo;0;L;;;;;N;;;;;\n11807;DOGRA LETTER AI;Lo;0;L;;;;;N;;;;;\n11808;DOGRA LETTER O;Lo;0;L;;;;;N;;;;;\n11809;DOGRA LETTER AU;Lo;0;L;;;;;N;;;;;\n1180A;DOGRA LETTER KA;Lo;0;L;;;;;N;;;;;\n1180B;DOGRA LETTER KHA;Lo;0;L;;;;;N;;;;;\n1180C;DOGRA LETTER GA;Lo;0;L;;;;;N;;;;;\n1180D;DOGRA LETTER GHA;Lo;0;L;;;;;N;;;;;\n1180E;DOGRA LETTER NGA;Lo;0;L;;;;;N;;;;;\n1180F;DOGRA LETTER CA;Lo;0;L;;;;;N;;;;;\n11810;DOGRA LETTER CHA;Lo;0;L;;;;;N;;;;;\n11811;DOGRA LETTER JA;Lo;0;L;;;;;N;;;;;\n11812;DOGRA LETTER JHA;Lo;0;L;;;;;N;;;;;\n11813;DOGRA LETTER NYA;Lo;0;L;;;;;N;;;;;\n11814;DOGRA LETTER TTA;Lo;0;L;;;;;N;;;;;\n11815;DOGRA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11816;DOGRA LETTER DDA;Lo;0;L;;;;;N;;;;;\n11817;DOGRA LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11818;DOGRA LETTER NNA;Lo;0;L;;;;;N;;;;;\n11819;DOGRA LETTER TA;Lo;0;L;;;;;N;;;;;\n1181A;DOGRA LETTER THA;Lo;0;L;;;;;N;;;;;\n1181B;DOGRA LETTER DA;Lo;0;L;;;;;N;;;;;\n1181C;DOGRA LETTER DHA;Lo;0;L;;;;;N;;;;;\n1181D;DOGRA LETTER NA;Lo;0;L;;;;;N;;;;;\n1181E;DOGRA LETTER PA;Lo;0;L;;;;;N;;;;;\n1181F;DOGRA LETTER PHA;Lo;0;L;;;;;N;;;;;\n11820;DOGRA LETTER BA;Lo;0;L;;;;;N;;;;;\n11821;DOGRA LETTER BHA;Lo;0;L;;;;;N;;;;;\n11822;DOGRA LETTER MA;Lo;0;L;;;;;N;;;;;\n11823;DOGRA LETTER YA;Lo;0;L;;;;;N;;;;;\n11824;DOGRA LETTER RA;Lo;0;L;;;;;N;;;;;\n11825;DOGRA LETTER LA;Lo;0;L;;;;;N;;;;;\n11826;DOGRA LETTER VA;Lo;0;L;;;;;N;;;;;\n11827;DOGRA LETTER SHA;Lo;0;L;;;;;N;;;;;\n11828;DOGRA LETTER SSA;Lo;0;L;;;;;N;;;;;\n11829;DOGRA LETTER SA;Lo;0;L;;;;;N;;;;;\n1182A;DOGRA LETTER HA;Lo;0;L;;;;;N;;;;;\n1182B;DOGRA LETTER RRA;Lo;0;L;;;;;N;;;;;\n1182C;DOGRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n1182D;DOGRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n1182E;DOGRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n1182F;DOGRA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11830;DOGRA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n11831;DOGRA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n11832;DOGRA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n11833;DOGRA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n11834;DOGRA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n11835;DOGRA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n11836;DOGRA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n11837;DOGRA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11838;DOGRA SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11839;DOGRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n1183A;DOGRA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n1183B;DOGRA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0;\n118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1;\n118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2;\n118A3;WARANG CITI CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;118C3;\n118A4;WARANG CITI CAPITAL LETTER YA;Lu;0;L;;;;;N;;;;118C4;\n118A5;WARANG CITI CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;118C5;\n118A6;WARANG CITI CAPITAL LETTER II;Lu;0;L;;;;;N;;;;118C6;\n118A7;WARANG CITI CAPITAL LETTER UU;Lu;0;L;;;;;N;;;;118C7;\n118A8;WARANG CITI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;118C8;\n118A9;WARANG CITI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;118C9;\n118AA;WARANG CITI CAPITAL LETTER ANG;Lu;0;L;;;;;N;;;;118CA;\n118AB;WARANG CITI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;118CB;\n118AC;WARANG CITI CAPITAL LETTER KO;Lu;0;L;;;;;N;;;;118CC;\n118AD;WARANG CITI CAPITAL LETTER ENY;Lu;0;L;;;;;N;;;;118CD;\n118AE;WARANG CITI CAPITAL LETTER YUJ;Lu;0;L;;;;;N;;;;118CE;\n118AF;WARANG CITI CAPITAL LETTER UC;Lu;0;L;;;;;N;;;;118CF;\n118B0;WARANG CITI CAPITAL LETTER ENN;Lu;0;L;;;;;N;;;;118D0;\n118B1;WARANG CITI CAPITAL LETTER ODD;Lu;0;L;;;;;N;;;;118D1;\n118B2;WARANG CITI CAPITAL LETTER TTE;Lu;0;L;;;;;N;;;;118D2;\n118B3;WARANG CITI CAPITAL LETTER NUNG;Lu;0;L;;;;;N;;;;118D3;\n118B4;WARANG CITI CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;118D4;\n118B5;WARANG CITI CAPITAL LETTER AT;Lu;0;L;;;;;N;;;;118D5;\n118B6;WARANG CITI CAPITAL LETTER AM;Lu;0;L;;;;;N;;;;118D6;\n118B7;WARANG CITI CAPITAL LETTER BU;Lu;0;L;;;;;N;;;;118D7;\n118B8;WARANG CITI CAPITAL LETTER PU;Lu;0;L;;;;;N;;;;118D8;\n118B9;WARANG CITI CAPITAL LETTER HIYO;Lu;0;L;;;;;N;;;;118D9;\n118BA;WARANG CITI CAPITAL LETTER HOLO;Lu;0;L;;;;;N;;;;118DA;\n118BB;WARANG CITI CAPITAL LETTER HORR;Lu;0;L;;;;;N;;;;118DB;\n118BC;WARANG CITI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;118DC;\n118BD;WARANG CITI CAPITAL LETTER SSUU;Lu;0;L;;;;;N;;;;118DD;\n118BE;WARANG CITI CAPITAL LETTER SII;Lu;0;L;;;;;N;;;;118DE;\n118BF;WARANG CITI CAPITAL LETTER VIYO;Lu;0;L;;;;;N;;;;118DF;\n118C0;WARANG CITI SMALL LETTER NGAA;Ll;0;L;;;;;N;;;118A0;;118A0\n118C1;WARANG CITI SMALL LETTER A;Ll;0;L;;;;;N;;;118A1;;118A1\n118C2;WARANG CITI SMALL LETTER WI;Ll;0;L;;;;;N;;;118A2;;118A2\n118C3;WARANG CITI SMALL LETTER YU;Ll;0;L;;;;;N;;;118A3;;118A3\n118C4;WARANG CITI SMALL LETTER YA;Ll;0;L;;;;;N;;;118A4;;118A4\n118C5;WARANG CITI SMALL LETTER YO;Ll;0;L;;;;;N;;;118A5;;118A5\n118C6;WARANG CITI SMALL LETTER II;Ll;0;L;;;;;N;;;118A6;;118A6\n118C7;WARANG CITI SMALL LETTER UU;Ll;0;L;;;;;N;;;118A7;;118A7\n118C8;WARANG CITI SMALL LETTER E;Ll;0;L;;;;;N;;;118A8;;118A8\n118C9;WARANG CITI SMALL LETTER O;Ll;0;L;;;;;N;;;118A9;;118A9\n118CA;WARANG CITI SMALL LETTER ANG;Ll;0;L;;;;;N;;;118AA;;118AA\n118CB;WARANG CITI SMALL LETTER GA;Ll;0;L;;;;;N;;;118AB;;118AB\n118CC;WARANG CITI SMALL LETTER KO;Ll;0;L;;;;;N;;;118AC;;118AC\n118CD;WARANG CITI SMALL LETTER ENY;Ll;0;L;;;;;N;;;118AD;;118AD\n118CE;WARANG CITI SMALL LETTER YUJ;Ll;0;L;;;;;N;;;118AE;;118AE\n118CF;WARANG CITI SMALL LETTER UC;Ll;0;L;;;;;N;;;118AF;;118AF\n118D0;WARANG CITI SMALL LETTER ENN;Ll;0;L;;;;;N;;;118B0;;118B0\n118D1;WARANG CITI SMALL LETTER ODD;Ll;0;L;;;;;N;;;118B1;;118B1\n118D2;WARANG CITI SMALL LETTER TTE;Ll;0;L;;;;;N;;;118B2;;118B2\n118D3;WARANG CITI SMALL LETTER NUNG;Ll;0;L;;;;;N;;;118B3;;118B3\n118D4;WARANG CITI SMALL LETTER DA;Ll;0;L;;;;;N;;;118B4;;118B4\n118D5;WARANG CITI SMALL LETTER AT;Ll;0;L;;;;;N;;;118B5;;118B5\n118D6;WARANG CITI SMALL LETTER AM;Ll;0;L;;;;;N;;;118B6;;118B6\n118D7;WARANG CITI SMALL LETTER BU;Ll;0;L;;;;;N;;;118B7;;118B7\n118D8;WARANG CITI SMALL LETTER PU;Ll;0;L;;;;;N;;;118B8;;118B8\n118D9;WARANG CITI SMALL LETTER HIYO;Ll;0;L;;;;;N;;;118B9;;118B9\n118DA;WARANG CITI SMALL LETTER HOLO;Ll;0;L;;;;;N;;;118BA;;118BA\n118DB;WARANG CITI SMALL LETTER HORR;Ll;0;L;;;;;N;;;118BB;;118BB\n118DC;WARANG CITI SMALL LETTER HAR;Ll;0;L;;;;;N;;;118BC;;118BC\n118DD;WARANG CITI SMALL LETTER SSUU;Ll;0;L;;;;;N;;;118BD;;118BD\n118DE;WARANG CITI SMALL LETTER SII;Ll;0;L;;;;;N;;;118BE;;118BE\n118DF;WARANG CITI SMALL LETTER VIYO;Ll;0;L;;;;;N;;;118BF;;118BF\n118E0;WARANG CITI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n118E1;WARANG CITI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n118E2;WARANG CITI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n118E3;WARANG CITI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n118E4;WARANG CITI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n118E5;WARANG CITI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n118E6;WARANG CITI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n118E7;WARANG CITI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n118E8;WARANG CITI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n118E9;WARANG CITI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n118EA;WARANG CITI NUMBER TEN;No;0;L;;;;10;N;;;;;\n118EB;WARANG CITI NUMBER TWENTY;No;0;L;;;;20;N;;;;;\n118EC;WARANG CITI NUMBER THIRTY;No;0;L;;;;30;N;;;;;\n118ED;WARANG CITI NUMBER FORTY;No;0;L;;;;40;N;;;;;\n118EE;WARANG CITI NUMBER FIFTY;No;0;L;;;;50;N;;;;;\n118EF;WARANG CITI NUMBER SIXTY;No;0;L;;;;60;N;;;;;\n118F0;WARANG CITI NUMBER SEVENTY;No;0;L;;;;70;N;;;;;\n118F1;WARANG CITI NUMBER EIGHTY;No;0;L;;;;80;N;;;;;\n118F2;WARANG CITI NUMBER NINETY;No;0;L;;;;90;N;;;;;\n118FF;WARANG CITI OM;Lo;0;L;;;;;N;;;;;\n11900;DIVES AKURU LETTER A;Lo;0;L;;;;;N;;;;;\n11901;DIVES AKURU LETTER AA;Lo;0;L;;;;;N;;;;;\n11902;DIVES AKURU LETTER I;Lo;0;L;;;;;N;;;;;\n11903;DIVES AKURU LETTER II;Lo;0;L;;;;;N;;;;;\n11904;DIVES AKURU LETTER U;Lo;0;L;;;;;N;;;;;\n11905;DIVES AKURU LETTER UU;Lo;0;L;;;;;N;;;;;\n11906;DIVES AKURU LETTER E;Lo;0;L;;;;;N;;;;;\n11909;DIVES AKURU LETTER O;Lo;0;L;;;;;N;;;;;\n1190C;DIVES AKURU LETTER KA;Lo;0;L;;;;;N;;;;;\n1190D;DIVES AKURU LETTER KHA;Lo;0;L;;;;;N;;;;;\n1190E;DIVES AKURU LETTER GA;Lo;0;L;;;;;N;;;;;\n1190F;DIVES AKURU LETTER GHA;Lo;0;L;;;;;N;;;;;\n11910;DIVES AKURU LETTER NGA;Lo;0;L;;;;;N;;;;;\n11911;DIVES AKURU LETTER CA;Lo;0;L;;;;;N;;;;;\n11912;DIVES AKURU LETTER CHA;Lo;0;L;;;;;N;;;;;\n11913;DIVES AKURU LETTER JA;Lo;0;L;;;;;N;;;;;\n11915;DIVES AKURU LETTER NYA;Lo;0;L;;;;;N;;;;;\n11916;DIVES AKURU LETTER TTA;Lo;0;L;;;;;N;;;;;\n11918;DIVES AKURU LETTER DDA;Lo;0;L;;;;;N;;;;;\n11919;DIVES AKURU LETTER DDHA;Lo;0;L;;;;;N;;;;;\n1191A;DIVES AKURU LETTER NNA;Lo;0;L;;;;;N;;;;;\n1191B;DIVES AKURU LETTER TA;Lo;0;L;;;;;N;;;;;\n1191C;DIVES AKURU LETTER THA;Lo;0;L;;;;;N;;;;;\n1191D;DIVES AKURU LETTER DA;Lo;0;L;;;;;N;;;;;\n1191E;DIVES AKURU LETTER DHA;Lo;0;L;;;;;N;;;;;\n1191F;DIVES AKURU LETTER NA;Lo;0;L;;;;;N;;;;;\n11920;DIVES AKURU LETTER PA;Lo;0;L;;;;;N;;;;;\n11921;DIVES AKURU LETTER PHA;Lo;0;L;;;;;N;;;;;\n11922;DIVES AKURU LETTER BA;Lo;0;L;;;;;N;;;;;\n11923;DIVES AKURU LETTER BHA;Lo;0;L;;;;;N;;;;;\n11924;DIVES AKURU LETTER MA;Lo;0;L;;;;;N;;;;;\n11925;DIVES AKURU LETTER YA;Lo;0;L;;;;;N;;;;;\n11926;DIVES AKURU LETTER YYA;Lo;0;L;;;;;N;;;;;\n11927;DIVES AKURU LETTER RA;Lo;0;L;;;;;N;;;;;\n11928;DIVES AKURU LETTER LA;Lo;0;L;;;;;N;;;;;\n11929;DIVES AKURU LETTER VA;Lo;0;L;;;;;N;;;;;\n1192A;DIVES AKURU LETTER SHA;Lo;0;L;;;;;N;;;;;\n1192B;DIVES AKURU LETTER SSA;Lo;0;L;;;;;N;;;;;\n1192C;DIVES AKURU LETTER SA;Lo;0;L;;;;;N;;;;;\n1192D;DIVES AKURU LETTER HA;Lo;0;L;;;;;N;;;;;\n1192E;DIVES AKURU LETTER LLA;Lo;0;L;;;;;N;;;;;\n1192F;DIVES AKURU LETTER ZA;Lo;0;L;;;;;N;;;;;\n11930;DIVES AKURU VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n11931;DIVES AKURU VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n11932;DIVES AKURU VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n11933;DIVES AKURU VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n11934;DIVES AKURU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\n11935;DIVES AKURU VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n11937;DIVES AKURU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n11938;DIVES AKURU VOWEL SIGN O;Mc;0;L;11935 11930;;;;N;;;;;\n1193B;DIVES AKURU SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n1193C;DIVES AKURU SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n1193D;DIVES AKURU SIGN HALANTA;Mc;9;L;;;;;N;;;;;\n1193E;DIVES AKURU VIRAMA;Mn;9;NSM;;;;;N;;;;;\n1193F;DIVES AKURU PREFIXED NASAL SIGN;Lo;0;L;;;;;N;;;;;\n11940;DIVES AKURU MEDIAL YA;Mc;0;L;;;;;N;;;;;\n11941;DIVES AKURU INITIAL RA;Lo;0;L;;;;;N;;;;;\n11942;DIVES AKURU MEDIAL RA;Mc;0;L;;;;;N;;;;;\n11943;DIVES AKURU SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n11944;DIVES AKURU DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n11945;DIVES AKURU GAP FILLER;Po;0;L;;;;;N;;;;;\n11946;DIVES AKURU END OF TEXT MARK;Po;0;L;;;;;N;;;;;\n11950;DIVES AKURU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11951;DIVES AKURU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11952;DIVES AKURU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11953;DIVES AKURU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11954;DIVES AKURU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11955;DIVES AKURU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11956;DIVES AKURU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11957;DIVES AKURU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11958;DIVES AKURU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11959;DIVES AKURU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n119A0;NANDINAGARI LETTER A;Lo;0;L;;;;;N;;;;;\n119A1;NANDINAGARI LETTER AA;Lo;0;L;;;;;N;;;;;\n119A2;NANDINAGARI LETTER I;Lo;0;L;;;;;N;;;;;\n119A3;NANDINAGARI LETTER II;Lo;0;L;;;;;N;;;;;\n119A4;NANDINAGARI LETTER U;Lo;0;L;;;;;N;;;;;\n119A5;NANDINAGARI LETTER UU;Lo;0;L;;;;;N;;;;;\n119A6;NANDINAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n119A7;NANDINAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n119AA;NANDINAGARI LETTER E;Lo;0;L;;;;;N;;;;;\n119AB;NANDINAGARI LETTER AI;Lo;0;L;;;;;N;;;;;\n119AC;NANDINAGARI LETTER O;Lo;0;L;;;;;N;;;;;\n119AD;NANDINAGARI LETTER AU;Lo;0;L;;;;;N;;;;;\n119AE;NANDINAGARI LETTER KA;Lo;0;L;;;;;N;;;;;\n119AF;NANDINAGARI LETTER KHA;Lo;0;L;;;;;N;;;;;\n119B0;NANDINAGARI LETTER GA;Lo;0;L;;;;;N;;;;;\n119B1;NANDINAGARI LETTER GHA;Lo;0;L;;;;;N;;;;;\n119B2;NANDINAGARI LETTER NGA;Lo;0;L;;;;;N;;;;;\n119B3;NANDINAGARI LETTER CA;Lo;0;L;;;;;N;;;;;\n119B4;NANDINAGARI LETTER CHA;Lo;0;L;;;;;N;;;;;\n119B5;NANDINAGARI LETTER JA;Lo;0;L;;;;;N;;;;;\n119B6;NANDINAGARI LETTER JHA;Lo;0;L;;;;;N;;;;;\n119B7;NANDINAGARI LETTER NYA;Lo;0;L;;;;;N;;;;;\n119B8;NANDINAGARI LETTER TTA;Lo;0;L;;;;;N;;;;;\n119B9;NANDINAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n119BA;NANDINAGARI LETTER DDA;Lo;0;L;;;;;N;;;;;\n119BB;NANDINAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n119BC;NANDINAGARI LETTER NNA;Lo;0;L;;;;;N;;;;;\n119BD;NANDINAGARI LETTER TA;Lo;0;L;;;;;N;;;;;\n119BE;NANDINAGARI LETTER THA;Lo;0;L;;;;;N;;;;;\n119BF;NANDINAGARI LETTER DA;Lo;0;L;;;;;N;;;;;\n119C0;NANDINAGARI LETTER DHA;Lo;0;L;;;;;N;;;;;\n119C1;NANDINAGARI LETTER NA;Lo;0;L;;;;;N;;;;;\n119C2;NANDINAGARI LETTER PA;Lo;0;L;;;;;N;;;;;\n119C3;NANDINAGARI LETTER PHA;Lo;0;L;;;;;N;;;;;\n119C4;NANDINAGARI LETTER BA;Lo;0;L;;;;;N;;;;;\n119C5;NANDINAGARI LETTER BHA;Lo;0;L;;;;;N;;;;;\n119C6;NANDINAGARI LETTER MA;Lo;0;L;;;;;N;;;;;\n119C7;NANDINAGARI LETTER YA;Lo;0;L;;;;;N;;;;;\n119C8;NANDINAGARI LETTER RA;Lo;0;L;;;;;N;;;;;\n119C9;NANDINAGARI LETTER LA;Lo;0;L;;;;;N;;;;;\n119CA;NANDINAGARI LETTER VA;Lo;0;L;;;;;N;;;;;\n119CB;NANDINAGARI LETTER SHA;Lo;0;L;;;;;N;;;;;\n119CC;NANDINAGARI LETTER SSA;Lo;0;L;;;;;N;;;;;\n119CD;NANDINAGARI LETTER SA;Lo;0;L;;;;;N;;;;;\n119CE;NANDINAGARI LETTER HA;Lo;0;L;;;;;N;;;;;\n119CF;NANDINAGARI LETTER LLA;Lo;0;L;;;;;N;;;;;\n119D0;NANDINAGARI LETTER RRA;Lo;0;L;;;;;N;;;;;\n119D1;NANDINAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n119D2;NANDINAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n119D3;NANDINAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n119D4;NANDINAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n119D5;NANDINAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n119D6;NANDINAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n119D7;NANDINAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n119DA;NANDINAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n119DB;NANDINAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n119DC;NANDINAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n119DD;NANDINAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n119DE;NANDINAGARI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;\n119DF;NANDINAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n119E0;NANDINAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n119E1;NANDINAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n119E2;NANDINAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;;\n119E3;NANDINAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;;\n119E4;NANDINAGARI VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;;\n11A00;ZANABAZAR SQUARE LETTER A;Lo;0;L;;;;;N;;;;;\n11A01;ZANABAZAR SQUARE VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n11A02;ZANABAZAR SQUARE VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;\n11A03;ZANABAZAR SQUARE VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11A04;ZANABAZAR SQUARE VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n11A05;ZANABAZAR SQUARE VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;\n11A06;ZANABAZAR SQUARE VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mn;0;L;;;;;N;;;;;\n11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mn;0;L;;;;;N;;;;;\n11A09;ZANABAZAR SQUARE VOWEL SIGN REVERSED I;Mn;0;NSM;;;;;N;;;;;\n11A0A;ZANABAZAR SQUARE VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;\n11A0B;ZANABAZAR SQUARE LETTER KA;Lo;0;L;;;;;N;;;;;\n11A0C;ZANABAZAR SQUARE LETTER KHA;Lo;0;L;;;;;N;;;;;\n11A0D;ZANABAZAR SQUARE LETTER GA;Lo;0;L;;;;;N;;;;;\n11A0E;ZANABAZAR SQUARE LETTER GHA;Lo;0;L;;;;;N;;;;;\n11A0F;ZANABAZAR SQUARE LETTER NGA;Lo;0;L;;;;;N;;;;;\n11A10;ZANABAZAR SQUARE LETTER CA;Lo;0;L;;;;;N;;;;;\n11A11;ZANABAZAR SQUARE LETTER CHA;Lo;0;L;;;;;N;;;;;\n11A12;ZANABAZAR SQUARE LETTER JA;Lo;0;L;;;;;N;;;;;\n11A13;ZANABAZAR SQUARE LETTER NYA;Lo;0;L;;;;;N;;;;;\n11A14;ZANABAZAR SQUARE LETTER TTA;Lo;0;L;;;;;N;;;;;\n11A15;ZANABAZAR SQUARE LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11A16;ZANABAZAR SQUARE LETTER DDA;Lo;0;L;;;;;N;;;;;\n11A17;ZANABAZAR SQUARE LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11A18;ZANABAZAR SQUARE LETTER NNA;Lo;0;L;;;;;N;;;;;\n11A19;ZANABAZAR SQUARE LETTER TA;Lo;0;L;;;;;N;;;;;\n11A1A;ZANABAZAR SQUARE LETTER THA;Lo;0;L;;;;;N;;;;;\n11A1B;ZANABAZAR SQUARE LETTER DA;Lo;0;L;;;;;N;;;;;\n11A1C;ZANABAZAR SQUARE LETTER DHA;Lo;0;L;;;;;N;;;;;\n11A1D;ZANABAZAR SQUARE LETTER NA;Lo;0;L;;;;;N;;;;;\n11A1E;ZANABAZAR SQUARE LETTER PA;Lo;0;L;;;;;N;;;;;\n11A1F;ZANABAZAR SQUARE LETTER PHA;Lo;0;L;;;;;N;;;;;\n11A20;ZANABAZAR SQUARE LETTER BA;Lo;0;L;;;;;N;;;;;\n11A21;ZANABAZAR SQUARE LETTER BHA;Lo;0;L;;;;;N;;;;;\n11A22;ZANABAZAR SQUARE LETTER MA;Lo;0;L;;;;;N;;;;;\n11A23;ZANABAZAR SQUARE LETTER TSA;Lo;0;L;;;;;N;;;;;\n11A24;ZANABAZAR SQUARE LETTER TSHA;Lo;0;L;;;;;N;;;;;\n11A25;ZANABAZAR SQUARE LETTER DZA;Lo;0;L;;;;;N;;;;;\n11A26;ZANABAZAR SQUARE LETTER DZHA;Lo;0;L;;;;;N;;;;;\n11A27;ZANABAZAR SQUARE LETTER ZHA;Lo;0;L;;;;;N;;;;;\n11A28;ZANABAZAR SQUARE LETTER ZA;Lo;0;L;;;;;N;;;;;\n11A29;ZANABAZAR SQUARE LETTER -A;Lo;0;L;;;;;N;;;;;\n11A2A;ZANABAZAR SQUARE LETTER YA;Lo;0;L;;;;;N;;;;;\n11A2B;ZANABAZAR SQUARE LETTER RA;Lo;0;L;;;;;N;;;;;\n11A2C;ZANABAZAR SQUARE LETTER LA;Lo;0;L;;;;;N;;;;;\n11A2D;ZANABAZAR SQUARE LETTER VA;Lo;0;L;;;;;N;;;;;\n11A2E;ZANABAZAR SQUARE LETTER SHA;Lo;0;L;;;;;N;;;;;\n11A2F;ZANABAZAR SQUARE LETTER SSA;Lo;0;L;;;;;N;;;;;\n11A30;ZANABAZAR SQUARE LETTER SA;Lo;0;L;;;;;N;;;;;\n11A31;ZANABAZAR SQUARE LETTER HA;Lo;0;L;;;;;N;;;;;\n11A32;ZANABAZAR SQUARE LETTER KSSA;Lo;0;L;;;;;N;;;;;\n11A33;ZANABAZAR SQUARE FINAL CONSONANT MARK;Mn;0;NSM;;;;;N;;;;;\n11A34;ZANABAZAR SQUARE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;\n11A35;ZANABAZAR SQUARE SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n11A36;ZANABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;;\n11A37;ZANABAZAR SQUARE SIGN CANDRA WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;;\n11A38;ZANABAZAR SQUARE SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11A39;ZANABAZAR SQUARE SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11A3A;ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;;\n11A3B;ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA;Mn;0;NSM;;;;;N;;;;;\n11A3C;ZANABAZAR SQUARE CLUSTER-FINAL LETTER RA;Mn;0;NSM;;;;;N;;;;;\n11A3D;ZANABAZAR SQUARE CLUSTER-FINAL LETTER LA;Mn;0;NSM;;;;;N;;;;;\n11A3E;ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA;Mn;0;NSM;;;;;N;;;;;\n11A3F;ZANABAZAR SQUARE INITIAL HEAD MARK;Po;0;L;;;;;N;;;;;\n11A40;ZANABAZAR SQUARE CLOSING HEAD MARK;Po;0;L;;;;;N;;;;;\n11A41;ZANABAZAR SQUARE MARK TSHEG;Po;0;L;;;;;N;;;;;\n11A42;ZANABAZAR SQUARE MARK SHAD;Po;0;L;;;;;N;;;;;\n11A43;ZANABAZAR SQUARE MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;;\n11A44;ZANABAZAR SQUARE MARK LONG TSHEG;Po;0;L;;;;;N;;;;;\n11A45;ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;;\n11A46;ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;;\n11A47;ZANABAZAR SQUARE SUBJOINER;Mn;9;NSM;;;;;N;;;;;\n11A50;SOYOMBO LETTER A;Lo;0;L;;;;;N;;;;;\n11A51;SOYOMBO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n11A52;SOYOMBO VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;\n11A53;SOYOMBO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11A54;SOYOMBO VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n11A55;SOYOMBO VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n11A56;SOYOMBO VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;\n11A57;SOYOMBO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n11A58;SOYOMBO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n11A59;SOYOMBO VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n11A5A;SOYOMBO VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n11A5B;SOYOMBO VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;\n11A5C;SOYOMBO LETTER KA;Lo;0;L;;;;;N;;;;;\n11A5D;SOYOMBO LETTER KHA;Lo;0;L;;;;;N;;;;;\n11A5E;SOYOMBO LETTER GA;Lo;0;L;;;;;N;;;;;\n11A5F;SOYOMBO LETTER GHA;Lo;0;L;;;;;N;;;;;\n11A60;SOYOMBO LETTER NGA;Lo;0;L;;;;;N;;;;;\n11A61;SOYOMBO LETTER CA;Lo;0;L;;;;;N;;;;;\n11A62;SOYOMBO LETTER CHA;Lo;0;L;;;;;N;;;;;\n11A63;SOYOMBO LETTER JA;Lo;0;L;;;;;N;;;;;\n11A64;SOYOMBO LETTER JHA;Lo;0;L;;;;;N;;;;;\n11A65;SOYOMBO LETTER NYA;Lo;0;L;;;;;N;;;;;\n11A66;SOYOMBO LETTER TTA;Lo;0;L;;;;;N;;;;;\n11A67;SOYOMBO LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11A68;SOYOMBO LETTER DDA;Lo;0;L;;;;;N;;;;;\n11A69;SOYOMBO LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11A6A;SOYOMBO LETTER NNA;Lo;0;L;;;;;N;;;;;\n11A6B;SOYOMBO LETTER TA;Lo;0;L;;;;;N;;;;;\n11A6C;SOYOMBO LETTER THA;Lo;0;L;;;;;N;;;;;\n11A6D;SOYOMBO LETTER DA;Lo;0;L;;;;;N;;;;;\n11A6E;SOYOMBO LETTER DHA;Lo;0;L;;;;;N;;;;;\n11A6F;SOYOMBO LETTER NA;Lo;0;L;;;;;N;;;;;\n11A70;SOYOMBO LETTER PA;Lo;0;L;;;;;N;;;;;\n11A71;SOYOMBO LETTER PHA;Lo;0;L;;;;;N;;;;;\n11A72;SOYOMBO LETTER BA;Lo;0;L;;;;;N;;;;;\n11A73;SOYOMBO LETTER BHA;Lo;0;L;;;;;N;;;;;\n11A74;SOYOMBO LETTER MA;Lo;0;L;;;;;N;;;;;\n11A75;SOYOMBO LETTER TSA;Lo;0;L;;;;;N;;;;;\n11A76;SOYOMBO LETTER TSHA;Lo;0;L;;;;;N;;;;;\n11A77;SOYOMBO LETTER DZA;Lo;0;L;;;;;N;;;;;\n11A78;SOYOMBO LETTER ZHA;Lo;0;L;;;;;N;;;;;\n11A79;SOYOMBO LETTER ZA;Lo;0;L;;;;;N;;;;;\n11A7A;SOYOMBO LETTER -A;Lo;0;L;;;;;N;;;;;\n11A7B;SOYOMBO LETTER YA;Lo;0;L;;;;;N;;;;;\n11A7C;SOYOMBO LETTER RA;Lo;0;L;;;;;N;;;;;\n11A7D;SOYOMBO LETTER LA;Lo;0;L;;;;;N;;;;;\n11A7E;SOYOMBO LETTER VA;Lo;0;L;;;;;N;;;;;\n11A7F;SOYOMBO LETTER SHA;Lo;0;L;;;;;N;;;;;\n11A80;SOYOMBO LETTER SSA;Lo;0;L;;;;;N;;;;;\n11A81;SOYOMBO LETTER SA;Lo;0;L;;;;;N;;;;;\n11A82;SOYOMBO LETTER HA;Lo;0;L;;;;;N;;;;;\n11A83;SOYOMBO LETTER KSSA;Lo;0;L;;;;;N;;;;;\n11A84;SOYOMBO SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;\n11A85;SOYOMBO SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;\n11A86;SOYOMBO CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;;\n11A87;SOYOMBO CLUSTER-INITIAL LETTER LA;Lo;0;L;;;;;N;;;;;\n11A88;SOYOMBO CLUSTER-INITIAL LETTER SHA;Lo;0;L;;;;;N;;;;;\n11A89;SOYOMBO CLUSTER-INITIAL LETTER SA;Lo;0;L;;;;;N;;;;;\n11A8A;SOYOMBO FINAL CONSONANT SIGN G;Mn;0;NSM;;;;;N;;;;;\n11A8B;SOYOMBO FINAL CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;;\n11A8C;SOYOMBO FINAL CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;;\n11A8D;SOYOMBO FINAL CONSONANT SIGN D;Mn;0;NSM;;;;;N;;;;;\n11A8E;SOYOMBO FINAL CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;;\n11A8F;SOYOMBO FINAL CONSONANT SIGN B;Mn;0;NSM;;;;;N;;;;;\n11A90;SOYOMBO FINAL CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;;\n11A91;SOYOMBO FINAL CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;;\n11A92;SOYOMBO FINAL CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;;\n11A93;SOYOMBO FINAL CONSONANT SIGN SH;Mn;0;NSM;;;;;N;;;;;\n11A94;SOYOMBO FINAL CONSONANT SIGN S;Mn;0;NSM;;;;;N;;;;;\n11A95;SOYOMBO FINAL CONSONANT SIGN -A;Mn;0;NSM;;;;;N;;;;;\n11A96;SOYOMBO SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11A97;SOYOMBO SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11A98;SOYOMBO GEMINATION MARK;Mn;0;NSM;;;;;N;;;;;\n11A99;SOYOMBO SUBJOINER;Mn;9;NSM;;;;;N;;;;;\n11A9A;SOYOMBO MARK TSHEG;Po;0;L;;;;;N;;;;;\n11A9B;SOYOMBO MARK SHAD;Po;0;L;;;;;N;;;;;\n11A9C;SOYOMBO MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;;\n11A9D;SOYOMBO MARK PLUTA;Lo;0;L;;;;;N;;;;;\n11A9E;SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME;Po;0;L;;;;;N;;;;;\n11A9F;SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME;Po;0;L;;;;;N;;;;;\n11AA0;SOYOMBO HEAD MARK WITH MOON AND SUN;Po;0;L;;;;;N;;;;;\n11AA1;SOYOMBO TERMINAL MARK-1;Po;0;L;;;;;N;;;;;\n11AA2;SOYOMBO TERMINAL MARK-2;Po;0;L;;;;;N;;;;;\n11AB0;CANADIAN SYLLABICS NATTILIK HI;Lo;0;L;;;;;N;;;;;\n11AB1;CANADIAN SYLLABICS NATTILIK HII;Lo;0;L;;;;;N;;;;;\n11AB2;CANADIAN SYLLABICS NATTILIK HO;Lo;0;L;;;;;N;;;;;\n11AB3;CANADIAN SYLLABICS NATTILIK HOO;Lo;0;L;;;;;N;;;;;\n11AB4;CANADIAN SYLLABICS NATTILIK HA;Lo;0;L;;;;;N;;;;;\n11AB5;CANADIAN SYLLABICS NATTILIK HAA;Lo;0;L;;;;;N;;;;;\n11AB6;CANADIAN SYLLABICS NATTILIK SHRI;Lo;0;L;;;;;N;;;;;\n11AB7;CANADIAN SYLLABICS NATTILIK SHRII;Lo;0;L;;;;;N;;;;;\n11AB8;CANADIAN SYLLABICS NATTILIK SHRO;Lo;0;L;;;;;N;;;;;\n11AB9;CANADIAN SYLLABICS NATTILIK SHROO;Lo;0;L;;;;;N;;;;;\n11ABA;CANADIAN SYLLABICS NATTILIK SHRA;Lo;0;L;;;;;N;;;;;\n11ABB;CANADIAN SYLLABICS NATTILIK SHRAA;Lo;0;L;;;;;N;;;;;\n11ABC;CANADIAN SYLLABICS SPE;Lo;0;L;;;;;N;;;;;\n11ABD;CANADIAN SYLLABICS SPI;Lo;0;L;;;;;N;;;;;\n11ABE;CANADIAN SYLLABICS SPO;Lo;0;L;;;;;N;;;;;\n11ABF;CANADIAN SYLLABICS SPA;Lo;0;L;;;;;N;;;;;\n11AC0;PAU CIN HAU LETTER PA;Lo;0;L;;;;;N;;;;;\n11AC1;PAU CIN HAU LETTER KA;Lo;0;L;;;;;N;;;;;\n11AC2;PAU CIN HAU LETTER LA;Lo;0;L;;;;;N;;;;;\n11AC3;PAU CIN HAU LETTER MA;Lo;0;L;;;;;N;;;;;\n11AC4;PAU CIN HAU LETTER DA;Lo;0;L;;;;;N;;;;;\n11AC5;PAU CIN HAU LETTER ZA;Lo;0;L;;;;;N;;;;;\n11AC6;PAU CIN HAU LETTER VA;Lo;0;L;;;;;N;;;;;\n11AC7;PAU CIN HAU LETTER NGA;Lo;0;L;;;;;N;;;;;\n11AC8;PAU CIN HAU LETTER HA;Lo;0;L;;;;;N;;;;;\n11AC9;PAU CIN HAU LETTER GA;Lo;0;L;;;;;N;;;;;\n11ACA;PAU CIN HAU LETTER KHA;Lo;0;L;;;;;N;;;;;\n11ACB;PAU CIN HAU LETTER SA;Lo;0;L;;;;;N;;;;;\n11ACC;PAU CIN HAU LETTER BA;Lo;0;L;;;;;N;;;;;\n11ACD;PAU CIN HAU LETTER CA;Lo;0;L;;;;;N;;;;;\n11ACE;PAU CIN HAU LETTER TA;Lo;0;L;;;;;N;;;;;\n11ACF;PAU CIN HAU LETTER THA;Lo;0;L;;;;;N;;;;;\n11AD0;PAU CIN HAU LETTER NA;Lo;0;L;;;;;N;;;;;\n11AD1;PAU CIN HAU LETTER PHA;Lo;0;L;;;;;N;;;;;\n11AD2;PAU CIN HAU LETTER RA;Lo;0;L;;;;;N;;;;;\n11AD3;PAU CIN HAU LETTER FA;Lo;0;L;;;;;N;;;;;\n11AD4;PAU CIN HAU LETTER CHA;Lo;0;L;;;;;N;;;;;\n11AD5;PAU CIN HAU LETTER A;Lo;0;L;;;;;N;;;;;\n11AD6;PAU CIN HAU LETTER E;Lo;0;L;;;;;N;;;;;\n11AD7;PAU CIN HAU LETTER I;Lo;0;L;;;;;N;;;;;\n11AD8;PAU CIN HAU LETTER O;Lo;0;L;;;;;N;;;;;\n11AD9;PAU CIN HAU LETTER U;Lo;0;L;;;;;N;;;;;\n11ADA;PAU CIN HAU LETTER UA;Lo;0;L;;;;;N;;;;;\n11ADB;PAU CIN HAU LETTER IA;Lo;0;L;;;;;N;;;;;\n11ADC;PAU CIN HAU LETTER FINAL P;Lo;0;L;;;;;N;;;;;\n11ADD;PAU CIN HAU LETTER FINAL K;Lo;0;L;;;;;N;;;;;\n11ADE;PAU CIN HAU LETTER FINAL T;Lo;0;L;;;;;N;;;;;\n11ADF;PAU CIN HAU LETTER FINAL M;Lo;0;L;;;;;N;;;;;\n11AE0;PAU CIN HAU LETTER FINAL N;Lo;0;L;;;;;N;;;;;\n11AE1;PAU CIN HAU LETTER FINAL L;Lo;0;L;;;;;N;;;;;\n11AE2;PAU CIN HAU LETTER FINAL W;Lo;0;L;;;;;N;;;;;\n11AE3;PAU CIN HAU LETTER FINAL NG;Lo;0;L;;;;;N;;;;;\n11AE4;PAU CIN HAU LETTER FINAL Y;Lo;0;L;;;;;N;;;;;\n11AE5;PAU CIN HAU RISING TONE LONG;Lo;0;L;;;;;N;;;;;\n11AE6;PAU CIN HAU RISING TONE;Lo;0;L;;;;;N;;;;;\n11AE7;PAU CIN HAU SANDHI GLOTTAL STOP;Lo;0;L;;;;;N;;;;;\n11AE8;PAU CIN HAU RISING TONE LONG FINAL;Lo;0;L;;;;;N;;;;;\n11AE9;PAU CIN HAU RISING TONE FINAL;Lo;0;L;;;;;N;;;;;\n11AEA;PAU CIN HAU SANDHI GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;;\n11AEB;PAU CIN HAU SANDHI TONE LONG;Lo;0;L;;;;;N;;;;;\n11AEC;PAU CIN HAU SANDHI TONE;Lo;0;L;;;;;N;;;;;\n11AED;PAU CIN HAU SANDHI TONE LONG FINAL;Lo;0;L;;;;;N;;;;;\n11AEE;PAU CIN HAU SANDHI TONE FINAL;Lo;0;L;;;;;N;;;;;\n11AEF;PAU CIN HAU MID-LEVEL TONE;Lo;0;L;;;;;N;;;;;\n11AF0;PAU CIN HAU GLOTTAL STOP VARIANT;Lo;0;L;;;;;N;;;;;\n11AF1;PAU CIN HAU MID-LEVEL TONE LONG FINAL;Lo;0;L;;;;;N;;;;;\n11AF2;PAU CIN HAU MID-LEVEL TONE FINAL;Lo;0;L;;;;;N;;;;;\n11AF3;PAU CIN HAU LOW-FALLING TONE LONG;Lo;0;L;;;;;N;;;;;\n11AF4;PAU CIN HAU LOW-FALLING TONE;Lo;0;L;;;;;N;;;;;\n11AF5;PAU CIN HAU GLOTTAL STOP;Lo;0;L;;;;;N;;;;;\n11AF6;PAU CIN HAU LOW-FALLING TONE LONG FINAL;Lo;0;L;;;;;N;;;;;\n11AF7;PAU CIN HAU LOW-FALLING TONE FINAL;Lo;0;L;;;;;N;;;;;\n11AF8;PAU CIN HAU GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;;\n11B00;DEVANAGARI HEAD MARK;Po;0;L;;;;;N;;;;;\n11B01;DEVANAGARI HEAD MARK WITH HEADSTROKE;Po;0;L;;;;;N;;;;;\n11B02;DEVANAGARI SIGN BHALE;Po;0;L;;;;;N;;;;;\n11B03;DEVANAGARI SIGN BHALE WITH HOOK;Po;0;L;;;;;N;;;;;\n11B04;DEVANAGARI SIGN EXTENDED BHALE;Po;0;L;;;;;N;;;;;\n11B05;DEVANAGARI SIGN EXTENDED BHALE WITH HOOK;Po;0;L;;;;;N;;;;;\n11B06;DEVANAGARI SIGN WESTERN FIVE-LIKE BHALE;Po;0;L;;;;;N;;;;;\n11B07;DEVANAGARI SIGN WESTERN NINE-LIKE BHALE;Po;0;L;;;;;N;;;;;\n11B08;DEVANAGARI SIGN REVERSED NINE-LIKE BHALE;Po;0;L;;;;;N;;;;;\n11B09;DEVANAGARI SIGN MINDU;Po;0;L;;;;;N;;;;;\n11B60;SHARADA VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;\n11B61;SHARADA VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;;\n11B62;SHARADA VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;\n11B63;SHARADA VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;;\n11B64;SHARADA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;\n11B65;SHARADA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;\n11B66;SHARADA VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;\n11B67;SHARADA VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;\n11BC0;SUNUWAR LETTER DEVI;Lo;0;L;;;;;N;;;;;\n11BC1;SUNUWAR LETTER TASLA;Lo;0;L;;;;;N;;;;;\n11BC2;SUNUWAR LETTER EKO;Lo;0;L;;;;;N;;;;;\n11BC3;SUNUWAR LETTER IMAR;Lo;0;L;;;;;N;;;;;\n11BC4;SUNUWAR LETTER REU;Lo;0;L;;;;;N;;;;;\n11BC5;SUNUWAR LETTER UTTHI;Lo;0;L;;;;;N;;;;;\n11BC6;SUNUWAR LETTER KIK;Lo;0;L;;;;;N;;;;;\n11BC7;SUNUWAR LETTER MA;Lo;0;L;;;;;N;;;;;\n11BC8;SUNUWAR LETTER APPHO;Lo;0;L;;;;;N;;;;;\n11BC9;SUNUWAR LETTER PIP;Lo;0;L;;;;;N;;;;;\n11BCA;SUNUWAR LETTER GIL;Lo;0;L;;;;;N;;;;;\n11BCB;SUNUWAR LETTER HAMSO;Lo;0;L;;;;;N;;;;;\n11BCC;SUNUWAR LETTER CARMI;Lo;0;L;;;;;N;;;;;\n11BCD;SUNUWAR LETTER NAH;Lo;0;L;;;;;N;;;;;\n11BCE;SUNUWAR LETTER BUR;Lo;0;L;;;;;N;;;;;\n11BCF;SUNUWAR LETTER JYAH;Lo;0;L;;;;;N;;;;;\n11BD0;SUNUWAR LETTER LOACHA;Lo;0;L;;;;;N;;;;;\n11BD1;SUNUWAR LETTER OTTHI;Lo;0;L;;;;;N;;;;;\n11BD2;SUNUWAR LETTER SHYELE;Lo;0;L;;;;;N;;;;;\n11BD3;SUNUWAR LETTER VARCA;Lo;0;L;;;;;N;;;;;\n11BD4;SUNUWAR LETTER YAT;Lo;0;L;;;;;N;;;;;\n11BD5;SUNUWAR LETTER AVA;Lo;0;L;;;;;N;;;;;\n11BD6;SUNUWAR LETTER AAL;Lo;0;L;;;;;N;;;;;\n11BD7;SUNUWAR LETTER DONGA;Lo;0;L;;;;;N;;;;;\n11BD8;SUNUWAR LETTER THARI;Lo;0;L;;;;;N;;;;;\n11BD9;SUNUWAR LETTER PHAR;Lo;0;L;;;;;N;;;;;\n11BDA;SUNUWAR LETTER NGAR;Lo;0;L;;;;;N;;;;;\n11BDB;SUNUWAR LETTER KHA;Lo;0;L;;;;;N;;;;;\n11BDC;SUNUWAR LETTER SHYER;Lo;0;L;;;;;N;;;;;\n11BDD;SUNUWAR LETTER CHELAP;Lo;0;L;;;;;N;;;;;\n11BDE;SUNUWAR LETTER TENTU;Lo;0;L;;;;;N;;;;;\n11BDF;SUNUWAR LETTER THELE;Lo;0;L;;;;;N;;;;;\n11BE0;SUNUWAR LETTER KLOKO;Lo;0;L;;;;;N;;;;;\n11BE1;SUNUWAR SIGN PVO;Po;0;L;;;;;N;;;;;\n11BF0;SUNUWAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11BF1;SUNUWAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11BF2;SUNUWAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11BF3;SUNUWAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11BF4;SUNUWAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11BF5;SUNUWAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11BF6;SUNUWAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11BF7;SUNUWAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11BF8;SUNUWAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11BF9;SUNUWAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11C00;BHAIKSUKI LETTER A;Lo;0;L;;;;;N;;;;;\n11C01;BHAIKSUKI LETTER AA;Lo;0;L;;;;;N;;;;;\n11C02;BHAIKSUKI LETTER I;Lo;0;L;;;;;N;;;;;\n11C03;BHAIKSUKI LETTER II;Lo;0;L;;;;;N;;;;;\n11C04;BHAIKSUKI LETTER U;Lo;0;L;;;;;N;;;;;\n11C05;BHAIKSUKI LETTER UU;Lo;0;L;;;;;N;;;;;\n11C06;BHAIKSUKI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n11C07;BHAIKSUKI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n11C08;BHAIKSUKI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n11C0A;BHAIKSUKI LETTER E;Lo;0;L;;;;;N;;;;;\n11C0B;BHAIKSUKI LETTER AI;Lo;0;L;;;;;N;;;;;\n11C0C;BHAIKSUKI LETTER O;Lo;0;L;;;;;N;;;;;\n11C0D;BHAIKSUKI LETTER AU;Lo;0;L;;;;;N;;;;;\n11C0E;BHAIKSUKI LETTER KA;Lo;0;L;;;;;N;;;;;\n11C0F;BHAIKSUKI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11C10;BHAIKSUKI LETTER GA;Lo;0;L;;;;;N;;;;;\n11C11;BHAIKSUKI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11C12;BHAIKSUKI LETTER NGA;Lo;0;L;;;;;N;;;;;\n11C13;BHAIKSUKI LETTER CA;Lo;0;L;;;;;N;;;;;\n11C14;BHAIKSUKI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11C15;BHAIKSUKI LETTER JA;Lo;0;L;;;;;N;;;;;\n11C16;BHAIKSUKI LETTER JHA;Lo;0;L;;;;;N;;;;;\n11C17;BHAIKSUKI LETTER NYA;Lo;0;L;;;;;N;;;;;\n11C18;BHAIKSUKI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11C19;BHAIKSUKI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11C1A;BHAIKSUKI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11C1B;BHAIKSUKI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11C1C;BHAIKSUKI LETTER NNA;Lo;0;L;;;;;N;;;;;\n11C1D;BHAIKSUKI LETTER TA;Lo;0;L;;;;;N;;;;;\n11C1E;BHAIKSUKI LETTER THA;Lo;0;L;;;;;N;;;;;\n11C1F;BHAIKSUKI LETTER DA;Lo;0;L;;;;;N;;;;;\n11C20;BHAIKSUKI LETTER DHA;Lo;0;L;;;;;N;;;;;\n11C21;BHAIKSUKI LETTER NA;Lo;0;L;;;;;N;;;;;\n11C22;BHAIKSUKI LETTER PA;Lo;0;L;;;;;N;;;;;\n11C23;BHAIKSUKI LETTER PHA;Lo;0;L;;;;;N;;;;;\n11C24;BHAIKSUKI LETTER BA;Lo;0;L;;;;;N;;;;;\n11C25;BHAIKSUKI LETTER BHA;Lo;0;L;;;;;N;;;;;\n11C26;BHAIKSUKI LETTER MA;Lo;0;L;;;;;N;;;;;\n11C27;BHAIKSUKI LETTER YA;Lo;0;L;;;;;N;;;;;\n11C28;BHAIKSUKI LETTER RA;Lo;0;L;;;;;N;;;;;\n11C29;BHAIKSUKI LETTER LA;Lo;0;L;;;;;N;;;;;\n11C2A;BHAIKSUKI LETTER VA;Lo;0;L;;;;;N;;;;;\n11C2B;BHAIKSUKI LETTER SHA;Lo;0;L;;;;;N;;;;;\n11C2C;BHAIKSUKI LETTER SSA;Lo;0;L;;;;;N;;;;;\n11C2D;BHAIKSUKI LETTER SA;Lo;0;L;;;;;N;;;;;\n11C2E;BHAIKSUKI LETTER HA;Lo;0;L;;;;;N;;;;;\n11C2F;BHAIKSUKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n11C30;BHAIKSUKI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n11C31;BHAIKSUKI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n11C32;BHAIKSUKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11C33;BHAIKSUKI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n11C34;BHAIKSUKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n11C35;BHAIKSUKI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;\n11C36;BHAIKSUKI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;\n11C38;BHAIKSUKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n11C39;BHAIKSUKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n11C3A;BHAIKSUKI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n11C3B;BHAIKSUKI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n11C3C;BHAIKSUKI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n11C3D;BHAIKSUKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11C3E;BHAIKSUKI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11C3F;BHAIKSUKI SIGN VIRAMA;Mn;9;L;;;;;N;;;;;\n11C40;BHAIKSUKI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;\n11C41;BHAIKSUKI DANDA;Po;0;L;;;;;N;;;;;\n11C42;BHAIKSUKI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n11C43;BHAIKSUKI WORD SEPARATOR;Po;0;L;;;;;N;;;;;\n11C44;BHAIKSUKI GAP FILLER-1;Po;0;L;;;;;N;;;;;\n11C45;BHAIKSUKI GAP FILLER-2;Po;0;L;;;;;N;;;;;\n11C50;BHAIKSUKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11C51;BHAIKSUKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11C52;BHAIKSUKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11C53;BHAIKSUKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11C54;BHAIKSUKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11C55;BHAIKSUKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11C56;BHAIKSUKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11C57;BHAIKSUKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11C58;BHAIKSUKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11C59;BHAIKSUKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11C5A;BHAIKSUKI NUMBER ONE;No;0;L;;;;1;N;;;;;\n11C5B;BHAIKSUKI NUMBER TWO;No;0;L;;;;2;N;;;;;\n11C5C;BHAIKSUKI NUMBER THREE;No;0;L;;;;3;N;;;;;\n11C5D;BHAIKSUKI NUMBER FOUR;No;0;L;;;;4;N;;;;;\n11C5E;BHAIKSUKI NUMBER FIVE;No;0;L;;;;5;N;;;;;\n11C5F;BHAIKSUKI NUMBER SIX;No;0;L;;;;6;N;;;;;\n11C60;BHAIKSUKI NUMBER SEVEN;No;0;L;;;;7;N;;;;;\n11C61;BHAIKSUKI NUMBER EIGHT;No;0;L;;;;8;N;;;;;\n11C62;BHAIKSUKI NUMBER NINE;No;0;L;;;;9;N;;;;;\n11C63;BHAIKSUKI NUMBER TEN;No;0;L;;;;10;N;;;;;\n11C64;BHAIKSUKI NUMBER TWENTY;No;0;L;;;;20;N;;;;;\n11C65;BHAIKSUKI NUMBER THIRTY;No;0;L;;;;30;N;;;;;\n11C66;BHAIKSUKI NUMBER FORTY;No;0;L;;;;40;N;;;;;\n11C67;BHAIKSUKI NUMBER FIFTY;No;0;L;;;;50;N;;;;;\n11C68;BHAIKSUKI NUMBER SIXTY;No;0;L;;;;60;N;;;;;\n11C69;BHAIKSUKI NUMBER SEVENTY;No;0;L;;;;70;N;;;;;\n11C6A;BHAIKSUKI NUMBER EIGHTY;No;0;L;;;;80;N;;;;;\n11C6B;BHAIKSUKI NUMBER NINETY;No;0;L;;;;90;N;;;;;\n11C6C;BHAIKSUKI HUNDREDS UNIT MARK;No;0;L;;;;100;N;;;;;\n11C70;MARCHEN HEAD MARK;Po;0;L;;;;;N;;;;;\n11C71;MARCHEN MARK SHAD;Po;0;L;;;;;N;;;;;\n11C72;MARCHEN LETTER KA;Lo;0;L;;;;;N;;;;;\n11C73;MARCHEN LETTER KHA;Lo;0;L;;;;;N;;;;;\n11C74;MARCHEN LETTER GA;Lo;0;L;;;;;N;;;;;\n11C75;MARCHEN LETTER NGA;Lo;0;L;;;;;N;;;;;\n11C76;MARCHEN LETTER CA;Lo;0;L;;;;;N;;;;;\n11C77;MARCHEN LETTER CHA;Lo;0;L;;;;;N;;;;;\n11C78;MARCHEN LETTER JA;Lo;0;L;;;;;N;;;;;\n11C79;MARCHEN LETTER NYA;Lo;0;L;;;;;N;;;;;\n11C7A;MARCHEN LETTER TA;Lo;0;L;;;;;N;;;;;\n11C7B;MARCHEN LETTER THA;Lo;0;L;;;;;N;;;;;\n11C7C;MARCHEN LETTER DA;Lo;0;L;;;;;N;;;;;\n11C7D;MARCHEN LETTER NA;Lo;0;L;;;;;N;;;;;\n11C7E;MARCHEN LETTER PA;Lo;0;L;;;;;N;;;;;\n11C7F;MARCHEN LETTER PHA;Lo;0;L;;;;;N;;;;;\n11C80;MARCHEN LETTER BA;Lo;0;L;;;;;N;;;;;\n11C81;MARCHEN LETTER MA;Lo;0;L;;;;;N;;;;;\n11C82;MARCHEN LETTER TSA;Lo;0;L;;;;;N;;;;;\n11C83;MARCHEN LETTER TSHA;Lo;0;L;;;;;N;;;;;\n11C84;MARCHEN LETTER DZA;Lo;0;L;;;;;N;;;;;\n11C85;MARCHEN LETTER WA;Lo;0;L;;;;;N;;;;;\n11C86;MARCHEN LETTER ZHA;Lo;0;L;;;;;N;;;;;\n11C87;MARCHEN LETTER ZA;Lo;0;L;;;;;N;;;;;\n11C88;MARCHEN LETTER -A;Lo;0;L;;;;;N;;;;;\n11C89;MARCHEN LETTER YA;Lo;0;L;;;;;N;;;;;\n11C8A;MARCHEN LETTER RA;Lo;0;L;;;;;N;;;;;\n11C8B;MARCHEN LETTER LA;Lo;0;L;;;;;N;;;;;\n11C8C;MARCHEN LETTER SHA;Lo;0;L;;;;;N;;;;;\n11C8D;MARCHEN LETTER SA;Lo;0;L;;;;;N;;;;;\n11C8E;MARCHEN LETTER HA;Lo;0;L;;;;;N;;;;;\n11C8F;MARCHEN LETTER A;Lo;0;L;;;;;N;;;;;\n11C92;MARCHEN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;;\n11C93;MARCHEN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;;\n11C94;MARCHEN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;;\n11C95;MARCHEN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;;\n11C96;MARCHEN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;;\n11C97;MARCHEN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;;\n11C98;MARCHEN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;;\n11C99;MARCHEN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;;\n11C9A;MARCHEN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;;\n11C9B;MARCHEN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;;\n11C9C;MARCHEN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;;\n11C9D;MARCHEN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;;\n11C9E;MARCHEN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;;\n11C9F;MARCHEN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;;\n11CA0;MARCHEN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;;\n11CA1;MARCHEN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;;\n11CA2;MARCHEN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;;\n11CA3;MARCHEN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;;\n11CA4;MARCHEN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;;\n11CA5;MARCHEN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;;\n11CA6;MARCHEN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;;\n11CA7;MARCHEN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;;\n11CA9;MARCHEN SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;;\n11CAA;MARCHEN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;;\n11CAB;MARCHEN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;;\n11CAC;MARCHEN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;;\n11CAD;MARCHEN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;;\n11CAE;MARCHEN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;;\n11CAF;MARCHEN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;;\n11CB0;MARCHEN VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;\n11CB1;MARCHEN VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n11CB2;MARCHEN VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11CB3;MARCHEN VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n11CB4;MARCHEN VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n11CB5;MARCHEN SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11CB6;MARCHEN SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n11D00;MASARAM GONDI LETTER A;Lo;0;L;;;;;N;;;;;\n11D01;MASARAM GONDI LETTER AA;Lo;0;L;;;;;N;;;;;\n11D02;MASARAM GONDI LETTER I;Lo;0;L;;;;;N;;;;;\n11D03;MASARAM GONDI LETTER II;Lo;0;L;;;;;N;;;;;\n11D04;MASARAM GONDI LETTER U;Lo;0;L;;;;;N;;;;;\n11D05;MASARAM GONDI LETTER UU;Lo;0;L;;;;;N;;;;;\n11D06;MASARAM GONDI LETTER E;Lo;0;L;;;;;N;;;;;\n11D08;MASARAM GONDI LETTER AI;Lo;0;L;;;;;N;;;;;\n11D09;MASARAM GONDI LETTER O;Lo;0;L;;;;;N;;;;;\n11D0B;MASARAM GONDI LETTER AU;Lo;0;L;;;;;N;;;;;\n11D0C;MASARAM GONDI LETTER KA;Lo;0;L;;;;;N;;;;;\n11D0D;MASARAM GONDI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11D0E;MASARAM GONDI LETTER GA;Lo;0;L;;;;;N;;;;;\n11D0F;MASARAM GONDI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11D10;MASARAM GONDI LETTER NGA;Lo;0;L;;;;;N;;;;;\n11D11;MASARAM GONDI LETTER CA;Lo;0;L;;;;;N;;;;;\n11D12;MASARAM GONDI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11D13;MASARAM GONDI LETTER JA;Lo;0;L;;;;;N;;;;;\n11D14;MASARAM GONDI LETTER JHA;Lo;0;L;;;;;N;;;;;\n11D15;MASARAM GONDI LETTER NYA;Lo;0;L;;;;;N;;;;;\n11D16;MASARAM GONDI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11D17;MASARAM GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11D18;MASARAM GONDI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11D19;MASARAM GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11D1A;MASARAM GONDI LETTER NNA;Lo;0;L;;;;;N;;;;;\n11D1B;MASARAM GONDI LETTER TA;Lo;0;L;;;;;N;;;;;\n11D1C;MASARAM GONDI LETTER THA;Lo;0;L;;;;;N;;;;;\n11D1D;MASARAM GONDI LETTER DA;Lo;0;L;;;;;N;;;;;\n11D1E;MASARAM GONDI LETTER DHA;Lo;0;L;;;;;N;;;;;\n11D1F;MASARAM GONDI LETTER NA;Lo;0;L;;;;;N;;;;;\n11D20;MASARAM GONDI LETTER PA;Lo;0;L;;;;;N;;;;;\n11D21;MASARAM GONDI LETTER PHA;Lo;0;L;;;;;N;;;;;\n11D22;MASARAM GONDI LETTER BA;Lo;0;L;;;;;N;;;;;\n11D23;MASARAM GONDI LETTER BHA;Lo;0;L;;;;;N;;;;;\n11D24;MASARAM GONDI LETTER MA;Lo;0;L;;;;;N;;;;;\n11D25;MASARAM GONDI LETTER YA;Lo;0;L;;;;;N;;;;;\n11D26;MASARAM GONDI LETTER RA;Lo;0;L;;;;;N;;;;;\n11D27;MASARAM GONDI LETTER LA;Lo;0;L;;;;;N;;;;;\n11D28;MASARAM GONDI LETTER VA;Lo;0;L;;;;;N;;;;;\n11D29;MASARAM GONDI LETTER SHA;Lo;0;L;;;;;N;;;;;\n11D2A;MASARAM GONDI LETTER SSA;Lo;0;L;;;;;N;;;;;\n11D2B;MASARAM GONDI LETTER SA;Lo;0;L;;;;;N;;;;;\n11D2C;MASARAM GONDI LETTER HA;Lo;0;L;;;;;N;;;;;\n11D2D;MASARAM GONDI LETTER LLA;Lo;0;L;;;;;N;;;;;\n11D2E;MASARAM GONDI LETTER KSSA;Lo;0;L;;;;;N;;;;;\n11D2F;MASARAM GONDI LETTER JNYA;Lo;0;L;;;;;N;;;;;\n11D30;MASARAM GONDI LETTER TRA;Lo;0;L;;;;;N;;;;;\n11D31;MASARAM GONDI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;\n11D32;MASARAM GONDI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n11D33;MASARAM GONDI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n11D34;MASARAM GONDI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11D35;MASARAM GONDI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n11D36;MASARAM GONDI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n11D3A;MASARAM GONDI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;\n11D3C;MASARAM GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n11D3D;MASARAM GONDI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;\n11D3F;MASARAM GONDI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;\n11D40;MASARAM GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11D41;MASARAM GONDI SIGN VISARGA;Mn;0;NSM;;;;;N;;;;;\n11D42;MASARAM GONDI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;\n11D43;MASARAM GONDI SIGN CANDRA;Mn;0;NSM;;;;;N;;;;;\n11D44;MASARAM GONDI SIGN HALANTA;Mn;9;NSM;;;;;N;;;;;\n11D45;MASARAM GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;;\n11D46;MASARAM GONDI REPHA;Lo;0;L;;;;;N;;;;;\n11D47;MASARAM GONDI RA-KARA;Mn;0;NSM;;;;;N;;;;;\n11D50;MASARAM GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11D51;MASARAM GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11D52;MASARAM GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11D53;MASARAM GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11D54;MASARAM GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11D55;MASARAM GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11D56;MASARAM GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11D57;MASARAM GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11D58;MASARAM GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11D59;MASARAM GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11D60;GUNJALA GONDI LETTER A;Lo;0;L;;;;;N;;;;;\n11D61;GUNJALA GONDI LETTER AA;Lo;0;L;;;;;N;;;;;\n11D62;GUNJALA GONDI LETTER I;Lo;0;L;;;;;N;;;;;\n11D63;GUNJALA GONDI LETTER II;Lo;0;L;;;;;N;;;;;\n11D64;GUNJALA GONDI LETTER U;Lo;0;L;;;;;N;;;;;\n11D65;GUNJALA GONDI LETTER UU;Lo;0;L;;;;;N;;;;;\n11D67;GUNJALA GONDI LETTER EE;Lo;0;L;;;;;N;;;;;\n11D68;GUNJALA GONDI LETTER AI;Lo;0;L;;;;;N;;;;;\n11D6A;GUNJALA GONDI LETTER OO;Lo;0;L;;;;;N;;;;;\n11D6B;GUNJALA GONDI LETTER AU;Lo;0;L;;;;;N;;;;;\n11D6C;GUNJALA GONDI LETTER YA;Lo;0;L;;;;;N;;;;;\n11D6D;GUNJALA GONDI LETTER VA;Lo;0;L;;;;;N;;;;;\n11D6E;GUNJALA GONDI LETTER BA;Lo;0;L;;;;;N;;;;;\n11D6F;GUNJALA GONDI LETTER BHA;Lo;0;L;;;;;N;;;;;\n11D70;GUNJALA GONDI LETTER MA;Lo;0;L;;;;;N;;;;;\n11D71;GUNJALA GONDI LETTER KA;Lo;0;L;;;;;N;;;;;\n11D72;GUNJALA GONDI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11D73;GUNJALA GONDI LETTER TA;Lo;0;L;;;;;N;;;;;\n11D74;GUNJALA GONDI LETTER THA;Lo;0;L;;;;;N;;;;;\n11D75;GUNJALA GONDI LETTER LA;Lo;0;L;;;;;N;;;;;\n11D76;GUNJALA GONDI LETTER GA;Lo;0;L;;;;;N;;;;;\n11D77;GUNJALA GONDI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11D78;GUNJALA GONDI LETTER DA;Lo;0;L;;;;;N;;;;;\n11D79;GUNJALA GONDI LETTER DHA;Lo;0;L;;;;;N;;;;;\n11D7A;GUNJALA GONDI LETTER NA;Lo;0;L;;;;;N;;;;;\n11D7B;GUNJALA GONDI LETTER CA;Lo;0;L;;;;;N;;;;;\n11D7C;GUNJALA GONDI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11D7D;GUNJALA GONDI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11D7E;GUNJALA GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11D7F;GUNJALA GONDI LETTER LLA;Lo;0;L;;;;;N;;;;;\n11D80;GUNJALA GONDI LETTER JA;Lo;0;L;;;;;N;;;;;\n11D81;GUNJALA GONDI LETTER JHA;Lo;0;L;;;;;N;;;;;\n11D82;GUNJALA GONDI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11D83;GUNJALA GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11D84;GUNJALA GONDI LETTER NGA;Lo;0;L;;;;;N;;;;;\n11D85;GUNJALA GONDI LETTER PA;Lo;0;L;;;;;N;;;;;\n11D86;GUNJALA GONDI LETTER PHA;Lo;0;L;;;;;N;;;;;\n11D87;GUNJALA GONDI LETTER HA;Lo;0;L;;;;;N;;;;;\n11D88;GUNJALA GONDI LETTER RA;Lo;0;L;;;;;N;;;;;\n11D89;GUNJALA GONDI LETTER SA;Lo;0;L;;;;;N;;;;;\n11D8A;GUNJALA GONDI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n11D8B;GUNJALA GONDI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n11D8C;GUNJALA GONDI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n11D8D;GUNJALA GONDI VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n11D8E;GUNJALA GONDI VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\n11D90;GUNJALA GONDI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;\n11D91;GUNJALA GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;\n11D93;GUNJALA GONDI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;\n11D94;GUNJALA GONDI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n11D95;GUNJALA GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11D96;GUNJALA GONDI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11D97;GUNJALA GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;;\n11D98;GUNJALA GONDI OM;Lo;0;L;;;;;N;;;;;\n11DA0;GUNJALA GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11DA1;GUNJALA GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11DA2;GUNJALA GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11DA3;GUNJALA GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11DA4;GUNJALA GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11DA5;GUNJALA GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11DA6;GUNJALA GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11DA7;GUNJALA GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11DA8;GUNJALA GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11DA9;GUNJALA GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11DB0;TOLONG SIKI LETTER I;Lo;0;L;;;;;N;;;;;\n11DB1;TOLONG SIKI LETTER E;Lo;0;L;;;;;N;;;;;\n11DB2;TOLONG SIKI LETTER U;Lo;0;L;;;;;N;;;;;\n11DB3;TOLONG SIKI LETTER O;Lo;0;L;;;;;N;;;;;\n11DB4;TOLONG SIKI LETTER A;Lo;0;L;;;;;N;;;;;\n11DB5;TOLONG SIKI LETTER AA;Lo;0;L;;;;;N;;;;;\n11DB6;TOLONG SIKI LETTER P;Lo;0;L;;;;;N;;;;;\n11DB7;TOLONG SIKI LETTER PH;Lo;0;L;;;;;N;;;;;\n11DB8;TOLONG SIKI LETTER B;Lo;0;L;;;;;N;;;;;\n11DB9;TOLONG SIKI LETTER BH;Lo;0;L;;;;;N;;;;;\n11DBA;TOLONG SIKI LETTER M;Lo;0;L;;;;;N;;;;;\n11DBB;TOLONG SIKI LETTER T;Lo;0;L;;;;;N;;;;;\n11DBC;TOLONG SIKI LETTER TH;Lo;0;L;;;;;N;;;;;\n11DBD;TOLONG SIKI LETTER D;Lo;0;L;;;;;N;;;;;\n11DBE;TOLONG SIKI LETTER DH;Lo;0;L;;;;;N;;;;;\n11DBF;TOLONG SIKI LETTER N;Lo;0;L;;;;;N;;;;;\n11DC0;TOLONG SIKI LETTER TT;Lo;0;L;;;;;N;;;;;\n11DC1;TOLONG SIKI LETTER TTH;Lo;0;L;;;;;N;;;;;\n11DC2;TOLONG SIKI LETTER DD;Lo;0;L;;;;;N;;;;;\n11DC3;TOLONG SIKI LETTER DDH;Lo;0;L;;;;;N;;;;;\n11DC4;TOLONG SIKI LETTER NN;Lo;0;L;;;;;N;;;;;\n11DC5;TOLONG SIKI LETTER C;Lo;0;L;;;;;N;;;;;\n11DC6;TOLONG SIKI LETTER CH;Lo;0;L;;;;;N;;;;;\n11DC7;TOLONG SIKI LETTER J;Lo;0;L;;;;;N;;;;;\n11DC8;TOLONG SIKI LETTER JH;Lo;0;L;;;;;N;;;;;\n11DC9;TOLONG SIKI LETTER NY;Lo;0;L;;;;;N;;;;;\n11DCA;TOLONG SIKI LETTER K;Lo;0;L;;;;;N;;;;;\n11DCB;TOLONG SIKI LETTER KH;Lo;0;L;;;;;N;;;;;\n11DCC;TOLONG SIKI LETTER G;Lo;0;L;;;;;N;;;;;\n11DCD;TOLONG SIKI LETTER GH;Lo;0;L;;;;;N;;;;;\n11DCE;TOLONG SIKI LETTER NG;Lo;0;L;;;;;N;;;;;\n11DCF;TOLONG SIKI LETTER Y;Lo;0;L;;;;;N;;;;;\n11DD0;TOLONG SIKI LETTER R;Lo;0;L;;;;;N;;;;;\n11DD1;TOLONG SIKI LETTER L;Lo;0;L;;;;;N;;;;;\n11DD2;TOLONG SIKI LETTER V;Lo;0;L;;;;;N;;;;;\n11DD3;TOLONG SIKI LETTER NNY;Lo;0;L;;;;;N;;;;;\n11DD4;TOLONG SIKI LETTER S;Lo;0;L;;;;;N;;;;;\n11DD5;TOLONG SIKI LETTER H;Lo;0;L;;;;;N;;;;;\n11DD6;TOLONG SIKI LETTER X;Lo;0;L;;;;;N;;;;;\n11DD7;TOLONG SIKI LETTER RR;Lo;0;L;;;;;N;;;;;\n11DD8;TOLONG SIKI LETTER RRH;Lo;0;L;;;;;N;;;;;\n11DD9;TOLONG SIKI SIGN SELA;Lm;0;L;;;;;N;;;;;\n11DDA;TOLONG SIKI SIGN HECAKA;Lo;0;L;;;;;N;;;;;\n11DDB;TOLONG SIKI UNGGA;Lo;0;L;;;;;N;;;;;\n11DE0;TOLONG SIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11DE1;TOLONG SIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11DE2;TOLONG SIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11DE3;TOLONG SIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11DE4;TOLONG SIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11DE5;TOLONG SIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11DE6;TOLONG SIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11DE7;TOLONG SIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11DE8;TOLONG SIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11DE9;TOLONG SIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11EE0;MAKASAR LETTER KA;Lo;0;L;;;;;N;;;;;\n11EE1;MAKASAR LETTER GA;Lo;0;L;;;;;N;;;;;\n11EE2;MAKASAR LETTER NGA;Lo;0;L;;;;;N;;;;;\n11EE3;MAKASAR LETTER PA;Lo;0;L;;;;;N;;;;;\n11EE4;MAKASAR LETTER BA;Lo;0;L;;;;;N;;;;;\n11EE5;MAKASAR LETTER MA;Lo;0;L;;;;;N;;;;;\n11EE6;MAKASAR LETTER TA;Lo;0;L;;;;;N;;;;;\n11EE7;MAKASAR LETTER DA;Lo;0;L;;;;;N;;;;;\n11EE8;MAKASAR LETTER NA;Lo;0;L;;;;;N;;;;;\n11EE9;MAKASAR LETTER CA;Lo;0;L;;;;;N;;;;;\n11EEA;MAKASAR LETTER JA;Lo;0;L;;;;;N;;;;;\n11EEB;MAKASAR LETTER NYA;Lo;0;L;;;;;N;;;;;\n11EEC;MAKASAR LETTER YA;Lo;0;L;;;;;N;;;;;\n11EED;MAKASAR LETTER RA;Lo;0;L;;;;;N;;;;;\n11EEE;MAKASAR LETTER LA;Lo;0;L;;;;;N;;;;;\n11EEF;MAKASAR LETTER VA;Lo;0;L;;;;;N;;;;;\n11EF0;MAKASAR LETTER SA;Lo;0;L;;;;;N;;;;;\n11EF1;MAKASAR LETTER A;Lo;0;L;;;;;N;;;;;\n11EF2;MAKASAR ANGKA;Lo;0;L;;;;;N;;;;;\n11EF3;MAKASAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n11EF4;MAKASAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11EF5;MAKASAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n11EF6;MAKASAR VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n11EF7;MAKASAR PASSIMBANG;Po;0;L;;;;;N;;;;;\n11EF8;MAKASAR END OF SECTION;Po;0;L;;;;;N;;;;;\n11F00;KAWI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;\n11F01;KAWI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n11F02;KAWI SIGN REPHA;Lo;0;L;;;;;N;;;;;\n11F03;KAWI SIGN VISARGA;Mc;0;L;;;;;N;;;;;\n11F04;KAWI LETTER A;Lo;0;L;;;;;N;;;;;\n11F05;KAWI LETTER AA;Lo;0;L;;;;;N;;;;;\n11F06;KAWI LETTER I;Lo;0;L;;;;;N;;;;;\n11F07;KAWI LETTER II;Lo;0;L;;;;;N;;;;;\n11F08;KAWI LETTER U;Lo;0;L;;;;;N;;;;;\n11F09;KAWI LETTER UU;Lo;0;L;;;;;N;;;;;\n11F0A;KAWI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;\n11F0B;KAWI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;\n11F0C;KAWI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;\n11F0D;KAWI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;\n11F0E;KAWI LETTER E;Lo;0;L;;;;;N;;;;;\n11F0F;KAWI LETTER AI;Lo;0;L;;;;;N;;;;;\n11F10;KAWI LETTER O;Lo;0;L;;;;;N;;;;;\n11F12;KAWI LETTER KA;Lo;0;L;;;;;N;;;;;\n11F13;KAWI LETTER KHA;Lo;0;L;;;;;N;;;;;\n11F14;KAWI LETTER GA;Lo;0;L;;;;;N;;;;;\n11F15;KAWI LETTER GHA;Lo;0;L;;;;;N;;;;;\n11F16;KAWI LETTER NGA;Lo;0;L;;;;;N;;;;;\n11F17;KAWI LETTER CA;Lo;0;L;;;;;N;;;;;\n11F18;KAWI LETTER CHA;Lo;0;L;;;;;N;;;;;\n11F19;KAWI LETTER JA;Lo;0;L;;;;;N;;;;;\n11F1A;KAWI LETTER JHA;Lo;0;L;;;;;N;;;;;\n11F1B;KAWI LETTER NYA;Lo;0;L;;;;;N;;;;;\n11F1C;KAWI LETTER TTA;Lo;0;L;;;;;N;;;;;\n11F1D;KAWI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n11F1E;KAWI LETTER DDA;Lo;0;L;;;;;N;;;;;\n11F1F;KAWI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n11F20;KAWI LETTER NNA;Lo;0;L;;;;;N;;;;;\n11F21;KAWI LETTER TA;Lo;0;L;;;;;N;;;;;\n11F22;KAWI LETTER THA;Lo;0;L;;;;;N;;;;;\n11F23;KAWI LETTER DA;Lo;0;L;;;;;N;;;;;\n11F24;KAWI LETTER DHA;Lo;0;L;;;;;N;;;;;\n11F25;KAWI LETTER NA;Lo;0;L;;;;;N;;;;;\n11F26;KAWI LETTER PA;Lo;0;L;;;;;N;;;;;\n11F27;KAWI LETTER PHA;Lo;0;L;;;;;N;;;;;\n11F28;KAWI LETTER BA;Lo;0;L;;;;;N;;;;;\n11F29;KAWI LETTER BHA;Lo;0;L;;;;;N;;;;;\n11F2A;KAWI LETTER MA;Lo;0;L;;;;;N;;;;;\n11F2B;KAWI LETTER YA;Lo;0;L;;;;;N;;;;;\n11F2C;KAWI LETTER RA;Lo;0;L;;;;;N;;;;;\n11F2D;KAWI LETTER LA;Lo;0;L;;;;;N;;;;;\n11F2E;KAWI LETTER WA;Lo;0;L;;;;;N;;;;;\n11F2F;KAWI LETTER SHA;Lo;0;L;;;;;N;;;;;\n11F30;KAWI LETTER SSA;Lo;0;L;;;;;N;;;;;\n11F31;KAWI LETTER SA;Lo;0;L;;;;;N;;;;;\n11F32;KAWI LETTER HA;Lo;0;L;;;;;N;;;;;\n11F33;KAWI LETTER JNYA;Lo;0;L;;;;;N;;;;;\n11F34;KAWI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n11F35;KAWI VOWEL SIGN ALTERNATE AA;Mc;0;L;;;;;N;;;;;\n11F36;KAWI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n11F37;KAWI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n11F38;KAWI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;\n11F39;KAWI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;\n11F3A;KAWI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;\n11F3E;KAWI VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n11F3F;KAWI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n11F40;KAWI VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;;\n11F41;KAWI SIGN KILLER;Mc;9;L;;;;;N;;;;;\n11F42;KAWI CONJOINER;Mn;9;NSM;;;;;N;;;;;\n11F43;KAWI DANDA;Po;0;L;;;;;N;;;;;\n11F44;KAWI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n11F45;KAWI PUNCTUATION SECTION MARKER;Po;0;L;;;;;N;;;;;\n11F46;KAWI PUNCTUATION ALTERNATE SECTION MARKER;Po;0;L;;;;;N;;;;;\n11F47;KAWI PUNCTUATION FLOWER;Po;0;L;;;;;N;;;;;\n11F48;KAWI PUNCTUATION SPACE FILLER;Po;0;L;;;;;N;;;;;\n11F49;KAWI PUNCTUATION DOT;Po;0;L;;;;;N;;;;;\n11F4A;KAWI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;;\n11F4B;KAWI PUNCTUATION TRIPLE DOT;Po;0;L;;;;;N;;;;;\n11F4C;KAWI PUNCTUATION CIRCLE;Po;0;L;;;;;N;;;;;\n11F4D;KAWI PUNCTUATION FILLED CIRCLE;Po;0;L;;;;;N;;;;;\n11F4E;KAWI PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;;\n11F4F;KAWI PUNCTUATION CLOSING SPIRAL;Po;0;L;;;;;N;;;;;\n11F50;KAWI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n11F51;KAWI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n11F52;KAWI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n11F53;KAWI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n11F54;KAWI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n11F55;KAWI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n11F56;KAWI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n11F57;KAWI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n11F58;KAWI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n11F59;KAWI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n11F5A;KAWI SIGN NUKTA;Mn;0;NSM;;;;;N;;;;;\n11FB0;LISU LETTER YHA;Lo;0;L;;;;;N;;;;;\n11FC0;TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH;No;0;L;;;;1/320;N;;;;;\n11FC1;TAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;;\n11FC2;TAMIL FRACTION ONE EIGHTIETH;No;0;L;;;;1/80;N;;;;;\n11FC3;TAMIL FRACTION ONE SIXTY-FOURTH;No;0;L;;;;1/64;N;;;;;\n11FC4;TAMIL FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;;\n11FC5;TAMIL FRACTION ONE THIRTY-SECOND;No;0;L;;;;1/32;N;;;;;\n11FC6;TAMIL FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;;\n11FC7;TAMIL FRACTION THREE SIXTY-FOURTHS;No;0;L;;;;3/64;N;;;;;\n11FC8;TAMIL FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;;\n11FC9;TAMIL FRACTION ONE SIXTEENTH-1;No;0;L;;;;1/16;N;;;;;\n11FCA;TAMIL FRACTION ONE SIXTEENTH-2;No;0;L;;;;1/16;N;;;;;\n11FCB;TAMIL FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;;\n11FCC;TAMIL FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;;\n11FCD;TAMIL FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;;\n11FCE;TAMIL FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;;\n11FCF;TAMIL FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;;\n11FD0;TAMIL FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;;\n11FD1;TAMIL FRACTION ONE HALF-1;No;0;L;;;;1/2;N;;;;;\n11FD2;TAMIL FRACTION ONE HALF-2;No;0;L;;;;1/2;N;;;;;\n11FD3;TAMIL FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;;\n11FD4;TAMIL FRACTION DOWNSCALING FACTOR KIIZH;No;0;L;;;;1/320;N;;;;;\n11FD5;TAMIL SIGN NEL;So;0;ON;;;;;N;;;;;\n11FD6;TAMIL SIGN CEVITU;So;0;ON;;;;;N;;;;;\n11FD7;TAMIL SIGN AAZHAAKKU;So;0;ON;;;;;N;;;;;\n11FD8;TAMIL SIGN UZHAKKU;So;0;ON;;;;;N;;;;;\n11FD9;TAMIL SIGN MUUVUZHAKKU;So;0;ON;;;;;N;;;;;\n11FDA;TAMIL SIGN KURUNI;So;0;ON;;;;;N;;;;;\n11FDB;TAMIL SIGN PATHAKKU;So;0;ON;;;;;N;;;;;\n11FDC;TAMIL SIGN MUKKURUNI;So;0;ON;;;;;N;;;;;\n11FDD;TAMIL SIGN KAACU;Sc;0;ET;;;;;N;;;;;\n11FDE;TAMIL SIGN PANAM;Sc;0;ET;;;;;N;;;;;\n11FDF;TAMIL SIGN PON;Sc;0;ET;;;;;N;;;;;\n11FE0;TAMIL SIGN VARAAKAN;Sc;0;ET;;;;;N;;;;;\n11FE1;TAMIL SIGN PAARAM;So;0;ON;;;;;N;;;;;\n11FE2;TAMIL SIGN KUZHI;So;0;ON;;;;;N;;;;;\n11FE3;TAMIL SIGN VELI;So;0;ON;;;;;N;;;;;\n11FE4;TAMIL WET CULTIVATION SIGN;So;0;ON;;;;;N;;;;;\n11FE5;TAMIL DRY CULTIVATION SIGN;So;0;ON;;;;;N;;;;;\n11FE6;TAMIL LAND SIGN;So;0;ON;;;;;N;;;;;\n11FE7;TAMIL SALT PAN SIGN;So;0;ON;;;;;N;;;;;\n11FE8;TAMIL TRADITIONAL CREDIT SIGN;So;0;ON;;;;;N;;;;;\n11FE9;TAMIL TRADITIONAL NUMBER SIGN;So;0;ON;;;;;N;;;;;\n11FEA;TAMIL CURRENT SIGN;So;0;ON;;;;;N;;;;;\n11FEB;TAMIL AND ODD SIGN;So;0;ON;;;;;N;;;;;\n11FEC;TAMIL SPENT SIGN;So;0;ON;;;;;N;;;;;\n11FED;TAMIL TOTAL SIGN;So;0;ON;;;;;N;;;;;\n11FEE;TAMIL IN POSSESSION SIGN;So;0;ON;;;;;N;;;;;\n11FEF;TAMIL STARTING FROM SIGN;So;0;ON;;;;;N;;;;;\n11FF0;TAMIL SIGN MUTHALIYA;So;0;ON;;;;;N;;;;;\n11FF1;TAMIL SIGN VAKAIYARAA;So;0;ON;;;;;N;;;;;\n11FFF;TAMIL PUNCTUATION END OF TEXT;Po;0;L;;;;;N;;;;;\n12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;;\n12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;;\n12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;;\n12003;CUNEIFORM SIGN A TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n12004;CUNEIFORM SIGN A TIMES HA;Lo;0;L;;;;;N;;;;;\n12005;CUNEIFORM SIGN A TIMES IGI;Lo;0;L;;;;;N;;;;;\n12006;CUNEIFORM SIGN A TIMES LAGAR GUNU;Lo;0;L;;;;;N;;;;;\n12007;CUNEIFORM SIGN A TIMES MUSH;Lo;0;L;;;;;N;;;;;\n12008;CUNEIFORM SIGN A TIMES SAG;Lo;0;L;;;;;N;;;;;\n12009;CUNEIFORM SIGN A2;Lo;0;L;;;;;N;;;;;\n1200A;CUNEIFORM SIGN AB;Lo;0;L;;;;;N;;;;;\n1200B;CUNEIFORM SIGN AB TIMES ASH2;Lo;0;L;;;;;N;;;;;\n1200C;CUNEIFORM SIGN AB TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;;\n1200D;CUNEIFORM SIGN AB TIMES GAL;Lo;0;L;;;;;N;;;;;\n1200E;CUNEIFORM SIGN AB TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n1200F;CUNEIFORM SIGN AB TIMES HA;Lo;0;L;;;;;N;;;;;\n12010;CUNEIFORM SIGN AB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n12011;CUNEIFORM SIGN AB TIMES IMIN;Lo;0;L;;;;;N;;;;;\n12012;CUNEIFORM SIGN AB TIMES LAGAB;Lo;0;L;;;;;N;;;;;\n12013;CUNEIFORM SIGN AB TIMES SHESH;Lo;0;L;;;;;N;;;;;\n12014;CUNEIFORM SIGN AB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;;\n12015;CUNEIFORM SIGN AB GUNU;Lo;0;L;;;;;N;;;;;\n12016;CUNEIFORM SIGN AB2;Lo;0;L;;;;;N;;;;;\n12017;CUNEIFORM SIGN AB2 TIMES BALAG;Lo;0;L;;;;;N;;;;;\n12018;CUNEIFORM SIGN AB2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n12019;CUNEIFORM SIGN AB2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;;\n1201A;CUNEIFORM SIGN AB2 TIMES SHA3;Lo;0;L;;;;;N;;;;;\n1201B;CUNEIFORM SIGN AB2 TIMES TAK4;Lo;0;L;;;;;N;;;;;\n1201C;CUNEIFORM SIGN AD;Lo;0;L;;;;;N;;;;;\n1201D;CUNEIFORM SIGN AK;Lo;0;L;;;;;N;;;;;\n1201E;CUNEIFORM SIGN AK TIMES ERIN2;Lo;0;L;;;;;N;;;;;\n1201F;CUNEIFORM SIGN AK TIMES SHITA PLUS GISH;Lo;0;L;;;;;N;;;;;\n12020;CUNEIFORM SIGN AL;Lo;0;L;;;;;N;;;;;\n12021;CUNEIFORM SIGN AL TIMES AL;Lo;0;L;;;;;N;;;;;\n12022;CUNEIFORM SIGN AL TIMES DIM2;Lo;0;L;;;;;N;;;;;\n12023;CUNEIFORM SIGN AL TIMES GISH;Lo;0;L;;;;;N;;;;;\n12024;CUNEIFORM SIGN AL TIMES HA;Lo;0;L;;;;;N;;;;;\n12025;CUNEIFORM SIGN AL TIMES KAD3;Lo;0;L;;;;;N;;;;;\n12026;CUNEIFORM SIGN AL TIMES KI;Lo;0;L;;;;;N;;;;;\n12027;CUNEIFORM SIGN AL TIMES SHE;Lo;0;L;;;;;N;;;;;\n12028;CUNEIFORM SIGN AL TIMES USH;Lo;0;L;;;;;N;;;;;\n12029;CUNEIFORM SIGN ALAN;Lo;0;L;;;;;N;;;;;\n1202A;CUNEIFORM SIGN ALEPH;Lo;0;L;;;;;N;;;;;\n1202B;CUNEIFORM SIGN AMAR;Lo;0;L;;;;;N;;;;;\n1202C;CUNEIFORM SIGN AMAR TIMES SHE;Lo;0;L;;;;;N;;;;;\n1202D;CUNEIFORM SIGN AN;Lo;0;L;;;;;N;;;;;\n1202E;CUNEIFORM SIGN AN OVER AN;Lo;0;L;;;;;N;;;;;\n1202F;CUNEIFORM SIGN AN THREE TIMES;Lo;0;L;;;;;N;;;;;\n12030;CUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGA;Lo;0;L;;;;;N;;;;;\n12031;CUNEIFORM SIGN AN PLUS NAGA SQUARED;Lo;0;L;;;;;N;;;;;\n12032;CUNEIFORM SIGN ANSHE;Lo;0;L;;;;;N;;;;;\n12033;CUNEIFORM SIGN APIN;Lo;0;L;;;;;N;;;;;\n12034;CUNEIFORM SIGN ARAD;Lo;0;L;;;;;N;;;;;\n12035;CUNEIFORM SIGN ARAD TIMES KUR;Lo;0;L;;;;;N;;;;;\n12036;CUNEIFORM SIGN ARKAB;Lo;0;L;;;;;N;;;;;\n12037;CUNEIFORM SIGN ASAL2;Lo;0;L;;;;;N;;;;;\n12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;1;N;;;;;\n12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;1;N;;;;;\n1203A;CUNEIFORM SIGN ASH KABA TENU;Lo;0;L;;;;;N;;;;;\n1203B;CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP;Lo;0;L;;;;;N;;;;;\n1203C;CUNEIFORM SIGN ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;;\n1203D;CUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;;\n1203E;CUNEIFORM SIGN ASH2;Lo;0;L;;;;;N;;;;;\n1203F;CUNEIFORM SIGN ASHGAB;Lo;0;L;;;;;N;;;;;\n12040;CUNEIFORM SIGN BA;Lo;0;L;;;;;N;;;;;\n12041;CUNEIFORM SIGN BAD;Lo;0;L;;;;;N;;;;;\n12042;CUNEIFORM SIGN BAG3;Lo;0;L;;;;;N;;;;;\n12043;CUNEIFORM SIGN BAHAR2;Lo;0;L;;;;;N;;;;;\n12044;CUNEIFORM SIGN BAL;Lo;0;L;;;;;N;;;;;\n12045;CUNEIFORM SIGN BAL OVER BAL;Lo;0;L;;;;;N;;;;;\n12046;CUNEIFORM SIGN BALAG;Lo;0;L;;;;;N;;;;;\n12047;CUNEIFORM SIGN BAR;Lo;0;L;;;;;N;;;;;\n12048;CUNEIFORM SIGN BARA2;Lo;0;L;;;;;N;;;;;\n12049;CUNEIFORM SIGN BI;Lo;0;L;;;;;N;;;;;\n1204A;CUNEIFORM SIGN BI TIMES A;Lo;0;L;;;;;N;;;;;\n1204B;CUNEIFORM SIGN BI TIMES GAR;Lo;0;L;;;;;N;;;;;\n1204C;CUNEIFORM SIGN BI TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n1204D;CUNEIFORM SIGN BU;Lo;0;L;;;;;N;;;;;\n1204E;CUNEIFORM SIGN BU OVER BU AB;Lo;0;L;;;;;N;;;;;\n1204F;CUNEIFORM SIGN BU OVER BU UN;Lo;0;L;;;;;N;;;;;\n12050;CUNEIFORM SIGN BU CROSSING BU;Lo;0;L;;;;;N;;;;;\n12051;CUNEIFORM SIGN BULUG;Lo;0;L;;;;;N;;;;;\n12052;CUNEIFORM SIGN BULUG OVER BULUG;Lo;0;L;;;;;N;;;;;\n12053;CUNEIFORM SIGN BUR;Lo;0;L;;;;;N;;;;;\n12054;CUNEIFORM SIGN BUR2;Lo;0;L;;;;;N;;;;;\n12055;CUNEIFORM SIGN DA;Lo;0;L;;;;;N;;;;;\n12056;CUNEIFORM SIGN DAG;Lo;0;L;;;;;N;;;;;\n12057;CUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASH;Lo;0;L;;;;;N;;;;;\n12058;CUNEIFORM SIGN DAG KISIM5 TIMES AMAR;Lo;0;L;;;;;N;;;;;\n12059;CUNEIFORM SIGN DAG KISIM5 TIMES BALAG;Lo;0;L;;;;;N;;;;;\n1205A;CUNEIFORM SIGN DAG KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;;\n1205B;CUNEIFORM SIGN DAG KISIM5 TIMES GA;Lo;0;L;;;;;N;;;;;\n1205C;CUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MASH;Lo;0;L;;;;;N;;;;;\n1205D;CUNEIFORM SIGN DAG KISIM5 TIMES GI;Lo;0;L;;;;;N;;;;;\n1205E;CUNEIFORM SIGN DAG KISIM5 TIMES GIR2;Lo;0;L;;;;;N;;;;;\n1205F;CUNEIFORM SIGN DAG KISIM5 TIMES GUD;Lo;0;L;;;;;N;;;;;\n12060;CUNEIFORM SIGN DAG KISIM5 TIMES HA;Lo;0;L;;;;;N;;;;;\n12061;CUNEIFORM SIGN DAG KISIM5 TIMES IR;Lo;0;L;;;;;N;;;;;\n12062;CUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS LU;Lo;0;L;;;;;N;;;;;\n12063;CUNEIFORM SIGN DAG KISIM5 TIMES KAK;Lo;0;L;;;;;N;;;;;\n12064;CUNEIFORM SIGN DAG KISIM5 TIMES LA;Lo;0;L;;;;;N;;;;;\n12065;CUNEIFORM SIGN DAG KISIM5 TIMES LU;Lo;0;L;;;;;N;;;;;\n12066;CUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS MASH2;Lo;0;L;;;;;N;;;;;\n12067;CUNEIFORM SIGN DAG KISIM5 TIMES LUM;Lo;0;L;;;;;N;;;;;\n12068;CUNEIFORM SIGN DAG KISIM5 TIMES NE;Lo;0;L;;;;;N;;;;;\n12069;CUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;;\n1206A;CUNEIFORM SIGN DAG KISIM5 TIMES SI;Lo;0;L;;;;;N;;;;;\n1206B;CUNEIFORM SIGN DAG KISIM5 TIMES TAK4;Lo;0;L;;;;;N;;;;;\n1206C;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS GIR2;Lo;0;L;;;;;N;;;;;\n1206D;CUNEIFORM SIGN DAG KISIM5 TIMES USH;Lo;0;L;;;;;N;;;;;\n1206E;CUNEIFORM SIGN DAM;Lo;0;L;;;;;N;;;;;\n1206F;CUNEIFORM SIGN DAR;Lo;0;L;;;;;N;;;;;\n12070;CUNEIFORM SIGN DARA3;Lo;0;L;;;;;N;;;;;\n12071;CUNEIFORM SIGN DARA4;Lo;0;L;;;;;N;;;;;\n12072;CUNEIFORM SIGN DI;Lo;0;L;;;;;N;;;;;\n12073;CUNEIFORM SIGN DIB;Lo;0;L;;;;;N;;;;;\n12074;CUNEIFORM SIGN DIM;Lo;0;L;;;;;N;;;;;\n12075;CUNEIFORM SIGN DIM TIMES SHE;Lo;0;L;;;;;N;;;;;\n12076;CUNEIFORM SIGN DIM2;Lo;0;L;;;;;N;;;;;\n12077;CUNEIFORM SIGN DIN;Lo;0;L;;;;;N;;;;;\n12078;CUNEIFORM SIGN DIN KASKAL U GUNU DISH;Lo;0;L;;;;;N;;;;;\n12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;1;N;;;;;\n1207A;CUNEIFORM SIGN DU;Lo;0;L;;;;;N;;;;;\n1207B;CUNEIFORM SIGN DU OVER DU;Lo;0;L;;;;;N;;;;;\n1207C;CUNEIFORM SIGN DU GUNU;Lo;0;L;;;;;N;;;;;\n1207D;CUNEIFORM SIGN DU SHESHIG;Lo;0;L;;;;;N;;;;;\n1207E;CUNEIFORM SIGN DUB;Lo;0;L;;;;;N;;;;;\n1207F;CUNEIFORM SIGN DUB TIMES ESH2;Lo;0;L;;;;;N;;;;;\n12080;CUNEIFORM SIGN DUB2;Lo;0;L;;;;;N;;;;;\n12081;CUNEIFORM SIGN DUG;Lo;0;L;;;;;N;;;;;\n12082;CUNEIFORM SIGN DUGUD;Lo;0;L;;;;;N;;;;;\n12083;CUNEIFORM SIGN DUH;Lo;0;L;;;;;N;;;;;\n12084;CUNEIFORM SIGN DUN;Lo;0;L;;;;;N;;;;;\n12085;CUNEIFORM SIGN DUN3;Lo;0;L;;;;;N;;;;;\n12086;CUNEIFORM SIGN DUN3 GUNU;Lo;0;L;;;;;N;;;;;\n12087;CUNEIFORM SIGN DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;;\n12088;CUNEIFORM SIGN DUN4;Lo;0;L;;;;;N;;;;;\n12089;CUNEIFORM SIGN DUR2;Lo;0;L;;;;;N;;;;;\n1208A;CUNEIFORM SIGN E;Lo;0;L;;;;;N;;;;;\n1208B;CUNEIFORM SIGN E TIMES PAP;Lo;0;L;;;;;N;;;;;\n1208C;CUNEIFORM SIGN E OVER E NUN OVER NUN;Lo;0;L;;;;;N;;;;;\n1208D;CUNEIFORM SIGN E2;Lo;0;L;;;;;N;;;;;\n1208E;CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DA;Lo;0;L;;;;;N;;;;;\n1208F;CUNEIFORM SIGN E2 TIMES GAR;Lo;0;L;;;;;N;;;;;\n12090;CUNEIFORM SIGN E2 TIMES MI;Lo;0;L;;;;;N;;;;;\n12091;CUNEIFORM SIGN E2 TIMES SAL;Lo;0;L;;;;;N;;;;;\n12092;CUNEIFORM SIGN E2 TIMES SHE;Lo;0;L;;;;;N;;;;;\n12093;CUNEIFORM SIGN E2 TIMES U;Lo;0;L;;;;;N;;;;;\n12094;CUNEIFORM SIGN EDIN;Lo;0;L;;;;;N;;;;;\n12095;CUNEIFORM SIGN EGIR;Lo;0;L;;;;;N;;;;;\n12096;CUNEIFORM SIGN EL;Lo;0;L;;;;;N;;;;;\n12097;CUNEIFORM SIGN EN;Lo;0;L;;;;;N;;;;;\n12098;CUNEIFORM SIGN EN TIMES GAN2;Lo;0;L;;;;;N;;;;;\n12099;CUNEIFORM SIGN EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n1209A;CUNEIFORM SIGN EN TIMES ME;Lo;0;L;;;;;N;;;;;\n1209B;CUNEIFORM SIGN EN CROSSING EN;Lo;0;L;;;;;N;;;;;\n1209C;CUNEIFORM SIGN EN OPPOSING EN;Lo;0;L;;;;;N;;;;;\n1209D;CUNEIFORM SIGN EN SQUARED;Lo;0;L;;;;;N;;;;;\n1209E;CUNEIFORM SIGN EREN;Lo;0;L;;;;;N;;;;;\n1209F;CUNEIFORM SIGN ERIN2;Lo;0;L;;;;;N;;;;;\n120A0;CUNEIFORM SIGN ESH2;Lo;0;L;;;;;N;;;;;\n120A1;CUNEIFORM SIGN EZEN;Lo;0;L;;;;;N;;;;;\n120A2;CUNEIFORM SIGN EZEN TIMES A;Lo;0;L;;;;;N;;;;;\n120A3;CUNEIFORM SIGN EZEN TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;;\n120A4;CUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LAL;Lo;0;L;;;;;N;;;;;\n120A5;CUNEIFORM SIGN EZEN TIMES AN;Lo;0;L;;;;;N;;;;;\n120A6;CUNEIFORM SIGN EZEN TIMES BAD;Lo;0;L;;;;;N;;;;;\n120A7;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;;\n120A8;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;;\n120A9;CUNEIFORM SIGN EZEN TIMES HA;Lo;0;L;;;;;N;;;;;\n120AA;CUNEIFORM SIGN EZEN TIMES HA GUNU;Lo;0;L;;;;;N;;;;;\n120AB;CUNEIFORM SIGN EZEN TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n120AC;CUNEIFORM SIGN EZEN TIMES KASKAL;Lo;0;L;;;;;N;;;;;\n120AD;CUNEIFORM SIGN EZEN TIMES KASKAL SQUARED;Lo;0;L;;;;;N;;;;;\n120AE;CUNEIFORM SIGN EZEN TIMES KU3;Lo;0;L;;;;;N;;;;;\n120AF;CUNEIFORM SIGN EZEN TIMES LA;Lo;0;L;;;;;N;;;;;\n120B0;CUNEIFORM SIGN EZEN TIMES LAL TIMES LAL;Lo;0;L;;;;;N;;;;;\n120B1;CUNEIFORM SIGN EZEN TIMES LI;Lo;0;L;;;;;N;;;;;\n120B2;CUNEIFORM SIGN EZEN TIMES LU;Lo;0;L;;;;;N;;;;;\n120B3;CUNEIFORM SIGN EZEN TIMES U2;Lo;0;L;;;;;N;;;;;\n120B4;CUNEIFORM SIGN EZEN TIMES UD;Lo;0;L;;;;;N;;;;;\n120B5;CUNEIFORM SIGN GA;Lo;0;L;;;;;N;;;;;\n120B6;CUNEIFORM SIGN GA GUNU;Lo;0;L;;;;;N;;;;;\n120B7;CUNEIFORM SIGN GA2;Lo;0;L;;;;;N;;;;;\n120B8;CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;;\n120B9;CUNEIFORM SIGN GA2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;;\n120BA;CUNEIFORM SIGN GA2 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;;\n120BB;CUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TAB;Lo;0;L;;;;;N;;;;;\n120BC;CUNEIFORM SIGN GA2 TIMES AN;Lo;0;L;;;;;N;;;;;\n120BD;CUNEIFORM SIGN GA2 TIMES ASH;Lo;0;L;;;;;N;;;;;\n120BE;CUNEIFORM SIGN GA2 TIMES ASH2 PLUS GAL;Lo;0;L;;;;;N;;;;;\n120BF;CUNEIFORM SIGN GA2 TIMES BAD;Lo;0;L;;;;;N;;;;;\n120C0;CUNEIFORM SIGN GA2 TIMES BAR PLUS RA;Lo;0;L;;;;;N;;;;;\n120C1;CUNEIFORM SIGN GA2 TIMES BUR;Lo;0;L;;;;;N;;;;;\n120C2;CUNEIFORM SIGN GA2 TIMES BUR PLUS RA;Lo;0;L;;;;;N;;;;;\n120C3;CUNEIFORM SIGN GA2 TIMES DA;Lo;0;L;;;;;N;;;;;\n120C4;CUNEIFORM SIGN GA2 TIMES DI;Lo;0;L;;;;;N;;;;;\n120C5;CUNEIFORM SIGN GA2 TIMES DIM TIMES SHE;Lo;0;L;;;;;N;;;;;\n120C6;CUNEIFORM SIGN GA2 TIMES DUB;Lo;0;L;;;;;N;;;;;\n120C7;CUNEIFORM SIGN GA2 TIMES EL;Lo;0;L;;;;;N;;;;;\n120C8;CUNEIFORM SIGN GA2 TIMES EL PLUS LA;Lo;0;L;;;;;N;;;;;\n120C9;CUNEIFORM SIGN GA2 TIMES EN;Lo;0;L;;;;;N;;;;;\n120CA;CUNEIFORM SIGN GA2 TIMES EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n120CB;CUNEIFORM SIGN GA2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n120CC;CUNEIFORM SIGN GA2 TIMES GAR;Lo;0;L;;;;;N;;;;;\n120CD;CUNEIFORM SIGN GA2 TIMES GI;Lo;0;L;;;;;N;;;;;\n120CE;CUNEIFORM SIGN GA2 TIMES GI4;Lo;0;L;;;;;N;;;;;\n120CF;CUNEIFORM SIGN GA2 TIMES GI4 PLUS A;Lo;0;L;;;;;N;;;;;\n120D0;CUNEIFORM SIGN GA2 TIMES GIR2 PLUS SU;Lo;0;L;;;;;N;;;;;\n120D1;CUNEIFORM SIGN GA2 TIMES HA PLUS LU PLUS ESH2;Lo;0;L;;;;;N;;;;;\n120D2;CUNEIFORM SIGN GA2 TIMES HAL;Lo;0;L;;;;;N;;;;;\n120D3;CUNEIFORM SIGN GA2 TIMES HAL PLUS LA;Lo;0;L;;;;;N;;;;;\n120D4;CUNEIFORM SIGN GA2 TIMES HI PLUS LI;Lo;0;L;;;;;N;;;;;\n120D5;CUNEIFORM SIGN GA2 TIMES HUB2;Lo;0;L;;;;;N;;;;;\n120D6;CUNEIFORM SIGN GA2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n120D7;CUNEIFORM SIGN GA2 TIMES ISH PLUS HU PLUS ASH;Lo;0;L;;;;;N;;;;;\n120D8;CUNEIFORM SIGN GA2 TIMES KAK;Lo;0;L;;;;;N;;;;;\n120D9;CUNEIFORM SIGN GA2 TIMES KASKAL;Lo;0;L;;;;;N;;;;;\n120DA;CUNEIFORM SIGN GA2 TIMES KID;Lo;0;L;;;;;N;;;;;\n120DB;CUNEIFORM SIGN GA2 TIMES KID PLUS LAL;Lo;0;L;;;;;N;;;;;\n120DC;CUNEIFORM SIGN GA2 TIMES KU3 PLUS AN;Lo;0;L;;;;;N;;;;;\n120DD;CUNEIFORM SIGN GA2 TIMES LA;Lo;0;L;;;;;N;;;;;\n120DE;CUNEIFORM SIGN GA2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;;\n120DF;CUNEIFORM SIGN GA2 TIMES MI;Lo;0;L;;;;;N;;;;;\n120E0;CUNEIFORM SIGN GA2 TIMES NUN;Lo;0;L;;;;;N;;;;;\n120E1;CUNEIFORM SIGN GA2 TIMES NUN OVER NUN;Lo;0;L;;;;;N;;;;;\n120E2;CUNEIFORM SIGN GA2 TIMES PA;Lo;0;L;;;;;N;;;;;\n120E3;CUNEIFORM SIGN GA2 TIMES SAL;Lo;0;L;;;;;N;;;;;\n120E4;CUNEIFORM SIGN GA2 TIMES SAR;Lo;0;L;;;;;N;;;;;\n120E5;CUNEIFORM SIGN GA2 TIMES SHE;Lo;0;L;;;;;N;;;;;\n120E6;CUNEIFORM SIGN GA2 TIMES SHE PLUS TUR;Lo;0;L;;;;;N;;;;;\n120E7;CUNEIFORM SIGN GA2 TIMES SHID;Lo;0;L;;;;;N;;;;;\n120E8;CUNEIFORM SIGN GA2 TIMES SUM;Lo;0;L;;;;;N;;;;;\n120E9;CUNEIFORM SIGN GA2 TIMES TAK4;Lo;0;L;;;;;N;;;;;\n120EA;CUNEIFORM SIGN GA2 TIMES U;Lo;0;L;;;;;N;;;;;\n120EB;CUNEIFORM SIGN GA2 TIMES UD;Lo;0;L;;;;;N;;;;;\n120EC;CUNEIFORM SIGN GA2 TIMES UD PLUS DU;Lo;0;L;;;;;N;;;;;\n120ED;CUNEIFORM SIGN GA2 OVER GA2;Lo;0;L;;;;;N;;;;;\n120EE;CUNEIFORM SIGN GABA;Lo;0;L;;;;;N;;;;;\n120EF;CUNEIFORM SIGN GABA CROSSING GABA;Lo;0;L;;;;;N;;;;;\n120F0;CUNEIFORM SIGN GAD;Lo;0;L;;;;;N;;;;;\n120F1;CUNEIFORM SIGN GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;;\n120F2;CUNEIFORM SIGN GAL;Lo;0;L;;;;;N;;;;;\n120F3;CUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;;\n120F4;CUNEIFORM SIGN GALAM;Lo;0;L;;;;;N;;;;;\n120F5;CUNEIFORM SIGN GAM;Lo;0;L;;;;;N;;;;;\n120F6;CUNEIFORM SIGN GAN;Lo;0;L;;;;;N;;;;;\n120F7;CUNEIFORM SIGN GAN2;Lo;0;L;;;;;N;;;;;\n120F8;CUNEIFORM SIGN GAN2 TENU;Lo;0;L;;;;;N;;;;;\n120F9;CUNEIFORM SIGN GAN2 OVER GAN2;Lo;0;L;;;;;N;;;;;\n120FA;CUNEIFORM SIGN GAN2 CROSSING GAN2;Lo;0;L;;;;;N;;;;;\n120FB;CUNEIFORM SIGN GAR;Lo;0;L;;;;;N;;;;;\n120FC;CUNEIFORM SIGN GAR3;Lo;0;L;;;;;N;;;;;\n120FD;CUNEIFORM SIGN GASHAN;Lo;0;L;;;;;N;;;;;\n120FE;CUNEIFORM SIGN GESHTIN;Lo;0;L;;;;;N;;;;;\n120FF;CUNEIFORM SIGN GESHTIN TIMES KUR;Lo;0;L;;;;;N;;;;;\n12100;CUNEIFORM SIGN GI;Lo;0;L;;;;;N;;;;;\n12101;CUNEIFORM SIGN GI TIMES E;Lo;0;L;;;;;N;;;;;\n12102;CUNEIFORM SIGN GI TIMES U;Lo;0;L;;;;;N;;;;;\n12103;CUNEIFORM SIGN GI CROSSING GI;Lo;0;L;;;;;N;;;;;\n12104;CUNEIFORM SIGN GI4;Lo;0;L;;;;;N;;;;;\n12105;CUNEIFORM SIGN GI4 OVER GI4;Lo;0;L;;;;;N;;;;;\n12106;CUNEIFORM SIGN GI4 CROSSING GI4;Lo;0;L;;;;;N;;;;;\n12107;CUNEIFORM SIGN GIDIM;Lo;0;L;;;;;N;;;;;\n12108;CUNEIFORM SIGN GIR2;Lo;0;L;;;;;N;;;;;\n12109;CUNEIFORM SIGN GIR2 GUNU;Lo;0;L;;;;;N;;;;;\n1210A;CUNEIFORM SIGN GIR3;Lo;0;L;;;;;N;;;;;\n1210B;CUNEIFORM SIGN GIR3 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;;\n1210C;CUNEIFORM SIGN GIR3 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n1210D;CUNEIFORM SIGN GIR3 TIMES IGI;Lo;0;L;;;;;N;;;;;\n1210E;CUNEIFORM SIGN GIR3 TIMES LU PLUS IGI;Lo;0;L;;;;;N;;;;;\n1210F;CUNEIFORM SIGN GIR3 TIMES PA;Lo;0;L;;;;;N;;;;;\n12110;CUNEIFORM SIGN GISAL;Lo;0;L;;;;;N;;;;;\n12111;CUNEIFORM SIGN GISH;Lo;0;L;;;;;N;;;;;\n12112;CUNEIFORM SIGN GISH CROSSING GISH;Lo;0;L;;;;;N;;;;;\n12113;CUNEIFORM SIGN GISH TIMES BAD;Lo;0;L;;;;;N;;;;;\n12114;CUNEIFORM SIGN GISH TIMES TAK4;Lo;0;L;;;;;N;;;;;\n12115;CUNEIFORM SIGN GISH TENU;Lo;0;L;;;;;N;;;;;\n12116;CUNEIFORM SIGN GU;Lo;0;L;;;;;N;;;;;\n12117;CUNEIFORM SIGN GU CROSSING GU;Lo;0;L;;;;;N;;;;;\n12118;CUNEIFORM SIGN GU2;Lo;0;L;;;;;N;;;;;\n12119;CUNEIFORM SIGN GU2 TIMES KAK;Lo;0;L;;;;;N;;;;;\n1211A;CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n1211B;CUNEIFORM SIGN GU2 TIMES NUN;Lo;0;L;;;;;N;;;;;\n1211C;CUNEIFORM SIGN GU2 TIMES SAL PLUS TUG2;Lo;0;L;;;;;N;;;;;\n1211D;CUNEIFORM SIGN GU2 GUNU;Lo;0;L;;;;;N;;;;;\n1211E;CUNEIFORM SIGN GUD;Lo;0;L;;;;;N;;;;;\n1211F;CUNEIFORM SIGN GUD TIMES A PLUS KUR;Lo;0;L;;;;;N;;;;;\n12120;CUNEIFORM SIGN GUD TIMES KUR;Lo;0;L;;;;;N;;;;;\n12121;CUNEIFORM SIGN GUD OVER GUD LUGAL;Lo;0;L;;;;;N;;;;;\n12122;CUNEIFORM SIGN GUL;Lo;0;L;;;;;N;;;;;\n12123;CUNEIFORM SIGN GUM;Lo;0;L;;;;;N;;;;;\n12124;CUNEIFORM SIGN GUM TIMES SHE;Lo;0;L;;;;;N;;;;;\n12125;CUNEIFORM SIGN GUR;Lo;0;L;;;;;N;;;;;\n12126;CUNEIFORM SIGN GUR7;Lo;0;L;;;;;N;;;;;\n12127;CUNEIFORM SIGN GURUN;Lo;0;L;;;;;N;;;;;\n12128;CUNEIFORM SIGN GURUSH;Lo;0;L;;;;;N;;;;;\n12129;CUNEIFORM SIGN HA;Lo;0;L;;;;;N;;;;;\n1212A;CUNEIFORM SIGN HA TENU;Lo;0;L;;;;;N;;;;;\n1212B;CUNEIFORM SIGN HA GUNU;Lo;0;L;;;;;N;;;;;\n1212C;CUNEIFORM SIGN HAL;Lo;0;L;;;;;N;;;;;\n1212D;CUNEIFORM SIGN HI;Lo;0;L;;;;;N;;;;;\n1212E;CUNEIFORM SIGN HI TIMES ASH;Lo;0;L;;;;;N;;;;;\n1212F;CUNEIFORM SIGN HI TIMES ASH2;Lo;0;L;;;;;N;;;;;\n12130;CUNEIFORM SIGN HI TIMES BAD;Lo;0;L;;;;;N;;;;;\n12131;CUNEIFORM SIGN HI TIMES DISH;Lo;0;L;;;;;N;;;;;\n12132;CUNEIFORM SIGN HI TIMES GAD;Lo;0;L;;;;;N;;;;;\n12133;CUNEIFORM SIGN HI TIMES KIN;Lo;0;L;;;;;N;;;;;\n12134;CUNEIFORM SIGN HI TIMES NUN;Lo;0;L;;;;;N;;;;;\n12135;CUNEIFORM SIGN HI TIMES SHE;Lo;0;L;;;;;N;;;;;\n12136;CUNEIFORM SIGN HI TIMES U;Lo;0;L;;;;;N;;;;;\n12137;CUNEIFORM SIGN HU;Lo;0;L;;;;;N;;;;;\n12138;CUNEIFORM SIGN HUB2;Lo;0;L;;;;;N;;;;;\n12139;CUNEIFORM SIGN HUB2 TIMES AN;Lo;0;L;;;;;N;;;;;\n1213A;CUNEIFORM SIGN HUB2 TIMES HAL;Lo;0;L;;;;;N;;;;;\n1213B;CUNEIFORM SIGN HUB2 TIMES KASKAL;Lo;0;L;;;;;N;;;;;\n1213C;CUNEIFORM SIGN HUB2 TIMES LISH;Lo;0;L;;;;;N;;;;;\n1213D;CUNEIFORM SIGN HUB2 TIMES UD;Lo;0;L;;;;;N;;;;;\n1213E;CUNEIFORM SIGN HUL2;Lo;0;L;;;;;N;;;;;\n1213F;CUNEIFORM SIGN I;Lo;0;L;;;;;N;;;;;\n12140;CUNEIFORM SIGN I A;Lo;0;L;;;;;N;;;;;\n12141;CUNEIFORM SIGN IB;Lo;0;L;;;;;N;;;;;\n12142;CUNEIFORM SIGN IDIM;Lo;0;L;;;;;N;;;;;\n12143;CUNEIFORM SIGN IDIM OVER IDIM BUR;Lo;0;L;;;;;N;;;;;\n12144;CUNEIFORM SIGN IDIM OVER IDIM SQUARED;Lo;0;L;;;;;N;;;;;\n12145;CUNEIFORM SIGN IG;Lo;0;L;;;;;N;;;;;\n12146;CUNEIFORM SIGN IGI;Lo;0;L;;;;;N;;;;;\n12147;CUNEIFORM SIGN IGI DIB;Lo;0;L;;;;;N;;;;;\n12148;CUNEIFORM SIGN IGI RI;Lo;0;L;;;;;N;;;;;\n12149;CUNEIFORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UD;Lo;0;L;;;;;N;;;;;\n1214A;CUNEIFORM SIGN IGI GUNU;Lo;0;L;;;;;N;;;;;\n1214B;CUNEIFORM SIGN IL;Lo;0;L;;;;;N;;;;;\n1214C;CUNEIFORM SIGN IL TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n1214D;CUNEIFORM SIGN IL2;Lo;0;L;;;;;N;;;;;\n1214E;CUNEIFORM SIGN IM;Lo;0;L;;;;;N;;;;;\n1214F;CUNEIFORM SIGN IM TIMES TAK4;Lo;0;L;;;;;N;;;;;\n12150;CUNEIFORM SIGN IM CROSSING IM;Lo;0;L;;;;;N;;;;;\n12151;CUNEIFORM SIGN IM OPPOSING IM;Lo;0;L;;;;;N;;;;;\n12152;CUNEIFORM SIGN IM SQUARED;Lo;0;L;;;;;N;;;;;\n12153;CUNEIFORM SIGN IMIN;Lo;0;L;;;;;N;;;;;\n12154;CUNEIFORM SIGN IN;Lo;0;L;;;;;N;;;;;\n12155;CUNEIFORM SIGN IR;Lo;0;L;;;;;N;;;;;\n12156;CUNEIFORM SIGN ISH;Lo;0;L;;;;;N;;;;;\n12157;CUNEIFORM SIGN KA;Lo;0;L;;;;;N;;;;;\n12158;CUNEIFORM SIGN KA TIMES A;Lo;0;L;;;;;N;;;;;\n12159;CUNEIFORM SIGN KA TIMES AD;Lo;0;L;;;;;N;;;;;\n1215A;CUNEIFORM SIGN KA TIMES AD PLUS KU3;Lo;0;L;;;;;N;;;;;\n1215B;CUNEIFORM SIGN KA TIMES ASH2;Lo;0;L;;;;;N;;;;;\n1215C;CUNEIFORM SIGN KA TIMES BAD;Lo;0;L;;;;;N;;;;;\n1215D;CUNEIFORM SIGN KA TIMES BALAG;Lo;0;L;;;;;N;;;;;\n1215E;CUNEIFORM SIGN KA TIMES BAR;Lo;0;L;;;;;N;;;;;\n1215F;CUNEIFORM SIGN KA TIMES BI;Lo;0;L;;;;;N;;;;;\n12160;CUNEIFORM SIGN KA TIMES ERIN2;Lo;0;L;;;;;N;;;;;\n12161;CUNEIFORM SIGN KA TIMES ESH2;Lo;0;L;;;;;N;;;;;\n12162;CUNEIFORM SIGN KA TIMES GA;Lo;0;L;;;;;N;;;;;\n12163;CUNEIFORM SIGN KA TIMES GAL;Lo;0;L;;;;;N;;;;;\n12164;CUNEIFORM SIGN KA TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n12165;CUNEIFORM SIGN KA TIMES GAR;Lo;0;L;;;;;N;;;;;\n12166;CUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A;Lo;0;L;;;;;N;;;;;\n12167;CUNEIFORM SIGN KA TIMES GI;Lo;0;L;;;;;N;;;;;\n12168;CUNEIFORM SIGN KA TIMES GIR2;Lo;0;L;;;;;N;;;;;\n12169;CUNEIFORM SIGN KA TIMES GISH PLUS SAR;Lo;0;L;;;;;N;;;;;\n1216A;CUNEIFORM SIGN KA TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;;\n1216B;CUNEIFORM SIGN KA TIMES GU;Lo;0;L;;;;;N;;;;;\n1216C;CUNEIFORM SIGN KA TIMES GUR7;Lo;0;L;;;;;N;;;;;\n1216D;CUNEIFORM SIGN KA TIMES IGI;Lo;0;L;;;;;N;;;;;\n1216E;CUNEIFORM SIGN KA TIMES IM;Lo;0;L;;;;;N;;;;;\n1216F;CUNEIFORM SIGN KA TIMES KAK;Lo;0;L;;;;;N;;;;;\n12170;CUNEIFORM SIGN KA TIMES KI;Lo;0;L;;;;;N;;;;;\n12171;CUNEIFORM SIGN KA TIMES KID;Lo;0;L;;;;;N;;;;;\n12172;CUNEIFORM SIGN KA TIMES LI;Lo;0;L;;;;;N;;;;;\n12173;CUNEIFORM SIGN KA TIMES LU;Lo;0;L;;;;;N;;;;;\n12174;CUNEIFORM SIGN KA TIMES ME;Lo;0;L;;;;;N;;;;;\n12175;CUNEIFORM SIGN KA TIMES ME PLUS DU;Lo;0;L;;;;;N;;;;;\n12176;CUNEIFORM SIGN KA TIMES ME PLUS GI;Lo;0;L;;;;;N;;;;;\n12177;CUNEIFORM SIGN KA TIMES ME PLUS TE;Lo;0;L;;;;;N;;;;;\n12178;CUNEIFORM SIGN KA TIMES MI;Lo;0;L;;;;;N;;;;;\n12179;CUNEIFORM SIGN KA TIMES MI PLUS NUNUZ;Lo;0;L;;;;;N;;;;;\n1217A;CUNEIFORM SIGN KA TIMES NE;Lo;0;L;;;;;N;;;;;\n1217B;CUNEIFORM SIGN KA TIMES NUN;Lo;0;L;;;;;N;;;;;\n1217C;CUNEIFORM SIGN KA TIMES PI;Lo;0;L;;;;;N;;;;;\n1217D;CUNEIFORM SIGN KA TIMES RU;Lo;0;L;;;;;N;;;;;\n1217E;CUNEIFORM SIGN KA TIMES SA;Lo;0;L;;;;;N;;;;;\n1217F;CUNEIFORM SIGN KA TIMES SAR;Lo;0;L;;;;;N;;;;;\n12180;CUNEIFORM SIGN KA TIMES SHA;Lo;0;L;;;;;N;;;;;\n12181;CUNEIFORM SIGN KA TIMES SHE;Lo;0;L;;;;;N;;;;;\n12182;CUNEIFORM SIGN KA TIMES SHID;Lo;0;L;;;;;N;;;;;\n12183;CUNEIFORM SIGN KA TIMES SHU;Lo;0;L;;;;;N;;;;;\n12184;CUNEIFORM SIGN KA TIMES SIG;Lo;0;L;;;;;N;;;;;\n12185;CUNEIFORM SIGN KA TIMES SUHUR;Lo;0;L;;;;;N;;;;;\n12186;CUNEIFORM SIGN KA TIMES TAR;Lo;0;L;;;;;N;;;;;\n12187;CUNEIFORM SIGN KA TIMES U;Lo;0;L;;;;;N;;;;;\n12188;CUNEIFORM SIGN KA TIMES U2;Lo;0;L;;;;;N;;;;;\n12189;CUNEIFORM SIGN KA TIMES UD;Lo;0;L;;;;;N;;;;;\n1218A;CUNEIFORM SIGN KA TIMES UMUM TIMES PA;Lo;0;L;;;;;N;;;;;\n1218B;CUNEIFORM SIGN KA TIMES USH;Lo;0;L;;;;;N;;;;;\n1218C;CUNEIFORM SIGN KA TIMES ZI;Lo;0;L;;;;;N;;;;;\n1218D;CUNEIFORM SIGN KA2;Lo;0;L;;;;;N;;;;;\n1218E;CUNEIFORM SIGN KA2 CROSSING KA2;Lo;0;L;;;;;N;;;;;\n1218F;CUNEIFORM SIGN KAB;Lo;0;L;;;;;N;;;;;\n12190;CUNEIFORM SIGN KAD2;Lo;0;L;;;;;N;;;;;\n12191;CUNEIFORM SIGN KAD3;Lo;0;L;;;;;N;;;;;\n12192;CUNEIFORM SIGN KAD4;Lo;0;L;;;;;N;;;;;\n12193;CUNEIFORM SIGN KAD5;Lo;0;L;;;;;N;;;;;\n12194;CUNEIFORM SIGN KAD5 OVER KAD5;Lo;0;L;;;;;N;;;;;\n12195;CUNEIFORM SIGN KAK;Lo;0;L;;;;;N;;;;;\n12196;CUNEIFORM SIGN KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n12197;CUNEIFORM SIGN KAL;Lo;0;L;;;;;N;;;;;\n12198;CUNEIFORM SIGN KAL TIMES BAD;Lo;0;L;;;;;N;;;;;\n12199;CUNEIFORM SIGN KAL CROSSING KAL;Lo;0;L;;;;;N;;;;;\n1219A;CUNEIFORM SIGN KAM2;Lo;0;L;;;;;N;;;;;\n1219B;CUNEIFORM SIGN KAM4;Lo;0;L;;;;;N;;;;;\n1219C;CUNEIFORM SIGN KASKAL;Lo;0;L;;;;;N;;;;;\n1219D;CUNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;;\n1219E;CUNEIFORM SIGN KASKAL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;;\n1219F;CUNEIFORM SIGN KESH2;Lo;0;L;;;;;N;;;;;\n121A0;CUNEIFORM SIGN KI;Lo;0;L;;;;;N;;;;;\n121A1;CUNEIFORM SIGN KI TIMES BAD;Lo;0;L;;;;;N;;;;;\n121A2;CUNEIFORM SIGN KI TIMES U;Lo;0;L;;;;;N;;;;;\n121A3;CUNEIFORM SIGN KI TIMES UD;Lo;0;L;;;;;N;;;;;\n121A4;CUNEIFORM SIGN KID;Lo;0;L;;;;;N;;;;;\n121A5;CUNEIFORM SIGN KIN;Lo;0;L;;;;;N;;;;;\n121A6;CUNEIFORM SIGN KISAL;Lo;0;L;;;;;N;;;;;\n121A7;CUNEIFORM SIGN KISH;Lo;0;L;;;;;N;;;;;\n121A8;CUNEIFORM SIGN KISIM5;Lo;0;L;;;;;N;;;;;\n121A9;CUNEIFORM SIGN KISIM5 OVER KISIM5;Lo;0;L;;;;;N;;;;;\n121AA;CUNEIFORM SIGN KU;Lo;0;L;;;;;N;;;;;\n121AB;CUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2;Lo;0;L;;;;;N;;;;;\n121AC;CUNEIFORM SIGN KU3;Lo;0;L;;;;;N;;;;;\n121AD;CUNEIFORM SIGN KU4;Lo;0;L;;;;;N;;;;;\n121AE;CUNEIFORM SIGN KU4 VARIANT FORM;Lo;0;L;;;;;N;;;;;\n121AF;CUNEIFORM SIGN KU7;Lo;0;L;;;;;N;;;;;\n121B0;CUNEIFORM SIGN KUL;Lo;0;L;;;;;N;;;;;\n121B1;CUNEIFORM SIGN KUL GUNU;Lo;0;L;;;;;N;;;;;\n121B2;CUNEIFORM SIGN KUN;Lo;0;L;;;;;N;;;;;\n121B3;CUNEIFORM SIGN KUR;Lo;0;L;;;;;N;;;;;\n121B4;CUNEIFORM SIGN KUR OPPOSING KUR;Lo;0;L;;;;;N;;;;;\n121B5;CUNEIFORM SIGN KUSHU2;Lo;0;L;;;;;N;;;;;\n121B6;CUNEIFORM SIGN KWU318;Lo;0;L;;;;;N;;;;;\n121B7;CUNEIFORM SIGN LA;Lo;0;L;;;;;N;;;;;\n121B8;CUNEIFORM SIGN LAGAB;Lo;0;L;;;;;N;;;;;\n121B9;CUNEIFORM SIGN LAGAB TIMES A;Lo;0;L;;;;;N;;;;;\n121BA;CUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;;\n121BB;CUNEIFORM SIGN LAGAB TIMES A PLUS GAR;Lo;0;L;;;;;N;;;;;\n121BC;CUNEIFORM SIGN LAGAB TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;;\n121BD;CUNEIFORM SIGN LAGAB TIMES AL;Lo;0;L;;;;;N;;;;;\n121BE;CUNEIFORM SIGN LAGAB TIMES AN;Lo;0;L;;;;;N;;;;;\n121BF;CUNEIFORM SIGN LAGAB TIMES ASH ZIDA TENU;Lo;0;L;;;;;N;;;;;\n121C0;CUNEIFORM SIGN LAGAB TIMES BAD;Lo;0;L;;;;;N;;;;;\n121C1;CUNEIFORM SIGN LAGAB TIMES BI;Lo;0;L;;;;;N;;;;;\n121C2;CUNEIFORM SIGN LAGAB TIMES DAR;Lo;0;L;;;;;N;;;;;\n121C3;CUNEIFORM SIGN LAGAB TIMES EN;Lo;0;L;;;;;N;;;;;\n121C4;CUNEIFORM SIGN LAGAB TIMES GA;Lo;0;L;;;;;N;;;;;\n121C5;CUNEIFORM SIGN LAGAB TIMES GAR;Lo;0;L;;;;;N;;;;;\n121C6;CUNEIFORM SIGN LAGAB TIMES GUD;Lo;0;L;;;;;N;;;;;\n121C7;CUNEIFORM SIGN LAGAB TIMES GUD PLUS GUD;Lo;0;L;;;;;N;;;;;\n121C8;CUNEIFORM SIGN LAGAB TIMES HA;Lo;0;L;;;;;N;;;;;\n121C9;CUNEIFORM SIGN LAGAB TIMES HAL;Lo;0;L;;;;;N;;;;;\n121CA;CUNEIFORM SIGN LAGAB TIMES HI TIMES NUN;Lo;0;L;;;;;N;;;;;\n121CB;CUNEIFORM SIGN LAGAB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n121CC;CUNEIFORM SIGN LAGAB TIMES IM;Lo;0;L;;;;;N;;;;;\n121CD;CUNEIFORM SIGN LAGAB TIMES IM PLUS HA;Lo;0;L;;;;;N;;;;;\n121CE;CUNEIFORM SIGN LAGAB TIMES IM PLUS LU;Lo;0;L;;;;;N;;;;;\n121CF;CUNEIFORM SIGN LAGAB TIMES KI;Lo;0;L;;;;;N;;;;;\n121D0;CUNEIFORM SIGN LAGAB TIMES KIN;Lo;0;L;;;;;N;;;;;\n121D1;CUNEIFORM SIGN LAGAB TIMES KU3;Lo;0;L;;;;;N;;;;;\n121D2;CUNEIFORM SIGN LAGAB TIMES KUL;Lo;0;L;;;;;N;;;;;\n121D3;CUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PLUS A;Lo;0;L;;;;;N;;;;;\n121D4;CUNEIFORM SIGN LAGAB TIMES LAGAB;Lo;0;L;;;;;N;;;;;\n121D5;CUNEIFORM SIGN LAGAB TIMES LISH;Lo;0;L;;;;;N;;;;;\n121D6;CUNEIFORM SIGN LAGAB TIMES LU;Lo;0;L;;;;;N;;;;;\n121D7;CUNEIFORM SIGN LAGAB TIMES LUL;Lo;0;L;;;;;N;;;;;\n121D8;CUNEIFORM SIGN LAGAB TIMES ME;Lo;0;L;;;;;N;;;;;\n121D9;CUNEIFORM SIGN LAGAB TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;;\n121DA;CUNEIFORM SIGN LAGAB TIMES MUSH;Lo;0;L;;;;;N;;;;;\n121DB;CUNEIFORM SIGN LAGAB TIMES NE;Lo;0;L;;;;;N;;;;;\n121DC;CUNEIFORM SIGN LAGAB TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;;\n121DD;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2;Lo;0;L;;;;;N;;;;;\n121DE;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH TENU;Lo;0;L;;;;;N;;;;;\n121DF;CUNEIFORM SIGN LAGAB TIMES SHU2;Lo;0;L;;;;;N;;;;;\n121E0;CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2;Lo;0;L;;;;;N;;;;;\n121E1;CUNEIFORM SIGN LAGAB TIMES SUM;Lo;0;L;;;;;N;;;;;\n121E2;CUNEIFORM SIGN LAGAB TIMES TAG;Lo;0;L;;;;;N;;;;;\n121E3;CUNEIFORM SIGN LAGAB TIMES TAK4;Lo;0;L;;;;;N;;;;;\n121E4;CUNEIFORM SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NA;Lo;0;L;;;;;N;;;;;\n121E5;CUNEIFORM SIGN LAGAB TIMES U;Lo;0;L;;;;;N;;;;;\n121E6;CUNEIFORM SIGN LAGAB TIMES U PLUS A;Lo;0;L;;;;;N;;;;;\n121E7;CUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;;\n121E8;CUNEIFORM SIGN LAGAB TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;;\n121E9;CUNEIFORM SIGN LAGAB TIMES UD;Lo;0;L;;;;;N;;;;;\n121EA;CUNEIFORM SIGN LAGAB TIMES USH;Lo;0;L;;;;;N;;;;;\n121EB;CUNEIFORM SIGN LAGAB SQUARED;Lo;0;L;;;;;N;;;;;\n121EC;CUNEIFORM SIGN LAGAR;Lo;0;L;;;;;N;;;;;\n121ED;CUNEIFORM SIGN LAGAR TIMES SHE;Lo;0;L;;;;;N;;;;;\n121EE;CUNEIFORM SIGN LAGAR TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;;\n121EF;CUNEIFORM SIGN LAGAR GUNU;Lo;0;L;;;;;N;;;;;\n121F0;CUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHE;Lo;0;L;;;;;N;;;;;\n121F1;CUNEIFORM SIGN LAHSHU;Lo;0;L;;;;;N;;;;;\n121F2;CUNEIFORM SIGN LAL;Lo;0;L;;;;;N;;;;;\n121F3;CUNEIFORM SIGN LAL TIMES LAL;Lo;0;L;;;;;N;;;;;\n121F4;CUNEIFORM SIGN LAM;Lo;0;L;;;;;N;;;;;\n121F5;CUNEIFORM SIGN LAM TIMES KUR;Lo;0;L;;;;;N;;;;;\n121F6;CUNEIFORM SIGN LAM TIMES KUR PLUS RU;Lo;0;L;;;;;N;;;;;\n121F7;CUNEIFORM SIGN LI;Lo;0;L;;;;;N;;;;;\n121F8;CUNEIFORM SIGN LIL;Lo;0;L;;;;;N;;;;;\n121F9;CUNEIFORM SIGN LIMMU2;Lo;0;L;;;;;N;;;;;\n121FA;CUNEIFORM SIGN LISH;Lo;0;L;;;;;N;;;;;\n121FB;CUNEIFORM SIGN LU;Lo;0;L;;;;;N;;;;;\n121FC;CUNEIFORM SIGN LU TIMES BAD;Lo;0;L;;;;;N;;;;;\n121FD;CUNEIFORM SIGN LU2;Lo;0;L;;;;;N;;;;;\n121FE;CUNEIFORM SIGN LU2 TIMES AL;Lo;0;L;;;;;N;;;;;\n121FF;CUNEIFORM SIGN LU2 TIMES BAD;Lo;0;L;;;;;N;;;;;\n12200;CUNEIFORM SIGN LU2 TIMES ESH2;Lo;0;L;;;;;N;;;;;\n12201;CUNEIFORM SIGN LU2 TIMES ESH2 TENU;Lo;0;L;;;;;N;;;;;\n12202;CUNEIFORM SIGN LU2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n12203;CUNEIFORM SIGN LU2 TIMES HI TIMES BAD;Lo;0;L;;;;;N;;;;;\n12204;CUNEIFORM SIGN LU2 TIMES IM;Lo;0;L;;;;;N;;;;;\n12205;CUNEIFORM SIGN LU2 TIMES KAD2;Lo;0;L;;;;;N;;;;;\n12206;CUNEIFORM SIGN LU2 TIMES KAD3;Lo;0;L;;;;;N;;;;;\n12207;CUNEIFORM SIGN LU2 TIMES KAD3 PLUS ASH;Lo;0;L;;;;;N;;;;;\n12208;CUNEIFORM SIGN LU2 TIMES KI;Lo;0;L;;;;;N;;;;;\n12209;CUNEIFORM SIGN LU2 TIMES LA PLUS ASH;Lo;0;L;;;;;N;;;;;\n1220A;CUNEIFORM SIGN LU2 TIMES LAGAB;Lo;0;L;;;;;N;;;;;\n1220B;CUNEIFORM SIGN LU2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;;\n1220C;CUNEIFORM SIGN LU2 TIMES NE;Lo;0;L;;;;;N;;;;;\n1220D;CUNEIFORM SIGN LU2 TIMES NU;Lo;0;L;;;;;N;;;;;\n1220E;CUNEIFORM SIGN LU2 TIMES SI PLUS ASH;Lo;0;L;;;;;N;;;;;\n1220F;CUNEIFORM SIGN LU2 TIMES SIK2 PLUS BU;Lo;0;L;;;;;N;;;;;\n12210;CUNEIFORM SIGN LU2 TIMES TUG2;Lo;0;L;;;;;N;;;;;\n12211;CUNEIFORM SIGN LU2 TENU;Lo;0;L;;;;;N;;;;;\n12212;CUNEIFORM SIGN LU2 CROSSING LU2;Lo;0;L;;;;;N;;;;;\n12213;CUNEIFORM SIGN LU2 OPPOSING LU2;Lo;0;L;;;;;N;;;;;\n12214;CUNEIFORM SIGN LU2 SQUARED;Lo;0;L;;;;;N;;;;;\n12215;CUNEIFORM SIGN LU2 SHESHIG;Lo;0;L;;;;;N;;;;;\n12216;CUNEIFORM SIGN LU3;Lo;0;L;;;;;N;;;;;\n12217;CUNEIFORM SIGN LUGAL;Lo;0;L;;;;;N;;;;;\n12218;CUNEIFORM SIGN LUGAL OVER LUGAL;Lo;0;L;;;;;N;;;;;\n12219;CUNEIFORM SIGN LUGAL OPPOSING LUGAL;Lo;0;L;;;;;N;;;;;\n1221A;CUNEIFORM SIGN LUGAL SHESHIG;Lo;0;L;;;;;N;;;;;\n1221B;CUNEIFORM SIGN LUH;Lo;0;L;;;;;N;;;;;\n1221C;CUNEIFORM SIGN LUL;Lo;0;L;;;;;N;;;;;\n1221D;CUNEIFORM SIGN LUM;Lo;0;L;;;;;N;;;;;\n1221E;CUNEIFORM SIGN LUM OVER LUM;Lo;0;L;;;;;N;;;;;\n1221F;CUNEIFORM SIGN LUM OVER LUM GAR OVER GAR;Lo;0;L;;;;;N;;;;;\n12220;CUNEIFORM SIGN MA;Lo;0;L;;;;;N;;;;;\n12221;CUNEIFORM SIGN MA TIMES TAK4;Lo;0;L;;;;;N;;;;;\n12222;CUNEIFORM SIGN MA GUNU;Lo;0;L;;;;;N;;;;;\n12223;CUNEIFORM SIGN MA2;Lo;0;L;;;;;N;;;;;\n12224;CUNEIFORM SIGN MAH;Lo;0;L;;;;;N;;;;;\n12225;CUNEIFORM SIGN MAR;Lo;0;L;;;;;N;;;;;\n12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;1/2;N;;;;;\n12227;CUNEIFORM SIGN MASH2;Lo;0;L;;;;;N;;;;;\n12228;CUNEIFORM SIGN ME;Lo;0;L;;;;;N;;;;;\n12229;CUNEIFORM SIGN MES;Lo;0;L;;;;;N;;;;;\n1222A;CUNEIFORM SIGN MI;Lo;0;L;;;;;N;;;;;\n1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;2;N;;;;;\n1222C;CUNEIFORM SIGN MU;Lo;0;L;;;;;N;;;;;\n1222D;CUNEIFORM SIGN MU OVER MU;Lo;0;L;;;;;N;;;;;\n1222E;CUNEIFORM SIGN MUG;Lo;0;L;;;;;N;;;;;\n1222F;CUNEIFORM SIGN MUG GUNU;Lo;0;L;;;;;N;;;;;\n12230;CUNEIFORM SIGN MUNSUB;Lo;0;L;;;;;N;;;;;\n12231;CUNEIFORM SIGN MURGU2;Lo;0;L;;;;;N;;;;;\n12232;CUNEIFORM SIGN MUSH;Lo;0;L;;;;;N;;;;;\n12233;CUNEIFORM SIGN MUSH TIMES A;Lo;0;L;;;;;N;;;;;\n12234;CUNEIFORM SIGN MUSH TIMES KUR;Lo;0;L;;;;;N;;;;;\n12235;CUNEIFORM SIGN MUSH TIMES ZA;Lo;0;L;;;;;N;;;;;\n12236;CUNEIFORM SIGN MUSH OVER MUSH;Lo;0;L;;;;;N;;;;;\n12237;CUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NA;Lo;0;L;;;;;N;;;;;\n12238;CUNEIFORM SIGN MUSH CROSSING MUSH;Lo;0;L;;;;;N;;;;;\n12239;CUNEIFORM SIGN MUSH3;Lo;0;L;;;;;N;;;;;\n1223A;CUNEIFORM SIGN MUSH3 TIMES A;Lo;0;L;;;;;N;;;;;\n1223B;CUNEIFORM SIGN MUSH3 TIMES A PLUS DI;Lo;0;L;;;;;N;;;;;\n1223C;CUNEIFORM SIGN MUSH3 TIMES DI;Lo;0;L;;;;;N;;;;;\n1223D;CUNEIFORM SIGN MUSH3 GUNU;Lo;0;L;;;;;N;;;;;\n1223E;CUNEIFORM SIGN NA;Lo;0;L;;;;;N;;;;;\n1223F;CUNEIFORM SIGN NA2;Lo;0;L;;;;;N;;;;;\n12240;CUNEIFORM SIGN NAGA;Lo;0;L;;;;;N;;;;;\n12241;CUNEIFORM SIGN NAGA INVERTED;Lo;0;L;;;;;N;;;;;\n12242;CUNEIFORM SIGN NAGA TIMES SHU TENU;Lo;0;L;;;;;N;;;;;\n12243;CUNEIFORM SIGN NAGA OPPOSING NAGA;Lo;0;L;;;;;N;;;;;\n12244;CUNEIFORM SIGN NAGAR;Lo;0;L;;;;;N;;;;;\n12245;CUNEIFORM SIGN NAM NUTILLU;Lo;0;L;;;;;N;;;;;\n12246;CUNEIFORM SIGN NAM;Lo;0;L;;;;;N;;;;;\n12247;CUNEIFORM SIGN NAM2;Lo;0;L;;;;;N;;;;;\n12248;CUNEIFORM SIGN NE;Lo;0;L;;;;;N;;;;;\n12249;CUNEIFORM SIGN NE TIMES A;Lo;0;L;;;;;N;;;;;\n1224A;CUNEIFORM SIGN NE TIMES UD;Lo;0;L;;;;;N;;;;;\n1224B;CUNEIFORM SIGN NE SHESHIG;Lo;0;L;;;;;N;;;;;\n1224C;CUNEIFORM SIGN NI;Lo;0;L;;;;;N;;;;;\n1224D;CUNEIFORM SIGN NI TIMES E;Lo;0;L;;;;;N;;;;;\n1224E;CUNEIFORM SIGN NI2;Lo;0;L;;;;;N;;;;;\n1224F;CUNEIFORM SIGN NIM;Lo;0;L;;;;;N;;;;;\n12250;CUNEIFORM SIGN NIM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n12251;CUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;;\n12252;CUNEIFORM SIGN NINDA2;Lo;0;L;;;;;N;;;;;\n12253;CUNEIFORM SIGN NINDA2 TIMES AN;Lo;0;L;;;;;N;;;;;\n12254;CUNEIFORM SIGN NINDA2 TIMES ASH;Lo;0;L;;;;;N;;;;;\n12255;CUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASH;Lo;0;L;;;;;N;;;;;\n12256;CUNEIFORM SIGN NINDA2 TIMES GUD;Lo;0;L;;;;;N;;;;;\n12257;CUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;;\n12258;CUNEIFORM SIGN NINDA2 TIMES NE;Lo;0;L;;;;;N;;;;;\n12259;CUNEIFORM SIGN NINDA2 TIMES NUN;Lo;0;L;;;;;N;;;;;\n1225A;CUNEIFORM SIGN NINDA2 TIMES SHE;Lo;0;L;;;;;N;;;;;\n1225B;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS A AN;Lo;0;L;;;;;N;;;;;\n1225C;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH;Lo;0;L;;;;;N;;;;;\n1225D;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASH;Lo;0;L;;;;;N;;;;;\n1225E;CUNEIFORM SIGN NINDA2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;;\n1225F;CUNEIFORM SIGN NINDA2 TIMES USH;Lo;0;L;;;;;N;;;;;\n12260;CUNEIFORM SIGN NISAG;Lo;0;L;;;;;N;;;;;\n12261;CUNEIFORM SIGN NU;Lo;0;L;;;;;N;;;;;\n12262;CUNEIFORM SIGN NU11;Lo;0;L;;;;;N;;;;;\n12263;CUNEIFORM SIGN NUN;Lo;0;L;;;;;N;;;;;\n12264;CUNEIFORM SIGN NUN LAGAR TIMES GAR;Lo;0;L;;;;;N;;;;;\n12265;CUNEIFORM SIGN NUN LAGAR TIMES MASH;Lo;0;L;;;;;N;;;;;\n12266;CUNEIFORM SIGN NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;;\n12267;CUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;;\n12268;CUNEIFORM SIGN NUN LAGAR TIMES USH;Lo;0;L;;;;;N;;;;;\n12269;CUNEIFORM SIGN NUN TENU;Lo;0;L;;;;;N;;;;;\n1226A;CUNEIFORM SIGN NUN OVER NUN;Lo;0;L;;;;;N;;;;;\n1226B;CUNEIFORM SIGN NUN CROSSING NUN;Lo;0;L;;;;;N;;;;;\n1226C;CUNEIFORM SIGN NUN CROSSING NUN LAGAR OVER LAGAR;Lo;0;L;;;;;N;;;;;\n1226D;CUNEIFORM SIGN NUNUZ;Lo;0;L;;;;;N;;;;;\n1226E;CUNEIFORM SIGN NUNUZ AB2 TIMES ASHGAB;Lo;0;L;;;;;N;;;;;\n1226F;CUNEIFORM SIGN NUNUZ AB2 TIMES BI;Lo;0;L;;;;;N;;;;;\n12270;CUNEIFORM SIGN NUNUZ AB2 TIMES DUG;Lo;0;L;;;;;N;;;;;\n12271;CUNEIFORM SIGN NUNUZ AB2 TIMES GUD;Lo;0;L;;;;;N;;;;;\n12272;CUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n12273;CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3;Lo;0;L;;;;;N;;;;;\n12274;CUNEIFORM SIGN NUNUZ AB2 TIMES LA;Lo;0;L;;;;;N;;;;;\n12275;CUNEIFORM SIGN NUNUZ AB2 TIMES NE;Lo;0;L;;;;;N;;;;;\n12276;CUNEIFORM SIGN NUNUZ AB2 TIMES SILA3;Lo;0;L;;;;;N;;;;;\n12277;CUNEIFORM SIGN NUNUZ AB2 TIMES U2;Lo;0;L;;;;;N;;;;;\n12278;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;;\n12279;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI U;Lo;0;L;;;;;N;;;;;\n1227A;CUNEIFORM SIGN PA;Lo;0;L;;;;;N;;;;;\n1227B;CUNEIFORM SIGN PAD;Lo;0;L;;;;;N;;;;;\n1227C;CUNEIFORM SIGN PAN;Lo;0;L;;;;;N;;;;;\n1227D;CUNEIFORM SIGN PAP;Lo;0;L;;;;;N;;;;;\n1227E;CUNEIFORM SIGN PESH2;Lo;0;L;;;;;N;;;;;\n1227F;CUNEIFORM SIGN PI;Lo;0;L;;;;;N;;;;;\n12280;CUNEIFORM SIGN PI TIMES A;Lo;0;L;;;;;N;;;;;\n12281;CUNEIFORM SIGN PI TIMES AB;Lo;0;L;;;;;N;;;;;\n12282;CUNEIFORM SIGN PI TIMES BI;Lo;0;L;;;;;N;;;;;\n12283;CUNEIFORM SIGN PI TIMES BU;Lo;0;L;;;;;N;;;;;\n12284;CUNEIFORM SIGN PI TIMES E;Lo;0;L;;;;;N;;;;;\n12285;CUNEIFORM SIGN PI TIMES I;Lo;0;L;;;;;N;;;;;\n12286;CUNEIFORM SIGN PI TIMES IB;Lo;0;L;;;;;N;;;;;\n12287;CUNEIFORM SIGN PI TIMES U;Lo;0;L;;;;;N;;;;;\n12288;CUNEIFORM SIGN PI TIMES U2;Lo;0;L;;;;;N;;;;;\n12289;CUNEIFORM SIGN PI CROSSING PI;Lo;0;L;;;;;N;;;;;\n1228A;CUNEIFORM SIGN PIRIG;Lo;0;L;;;;;N;;;;;\n1228B;CUNEIFORM SIGN PIRIG TIMES KAL;Lo;0;L;;;;;N;;;;;\n1228C;CUNEIFORM SIGN PIRIG TIMES UD;Lo;0;L;;;;;N;;;;;\n1228D;CUNEIFORM SIGN PIRIG TIMES ZA;Lo;0;L;;;;;N;;;;;\n1228E;CUNEIFORM SIGN PIRIG OPPOSING PIRIG;Lo;0;L;;;;;N;;;;;\n1228F;CUNEIFORM SIGN RA;Lo;0;L;;;;;N;;;;;\n12290;CUNEIFORM SIGN RAB;Lo;0;L;;;;;N;;;;;\n12291;CUNEIFORM SIGN RI;Lo;0;L;;;;;N;;;;;\n12292;CUNEIFORM SIGN RU;Lo;0;L;;;;;N;;;;;\n12293;CUNEIFORM SIGN SA;Lo;0;L;;;;;N;;;;;\n12294;CUNEIFORM SIGN SAG NUTILLU;Lo;0;L;;;;;N;;;;;\n12295;CUNEIFORM SIGN SAG;Lo;0;L;;;;;N;;;;;\n12296;CUNEIFORM SIGN SAG TIMES A;Lo;0;L;;;;;N;;;;;\n12297;CUNEIFORM SIGN SAG TIMES DU;Lo;0;L;;;;;N;;;;;\n12298;CUNEIFORM SIGN SAG TIMES DUB;Lo;0;L;;;;;N;;;;;\n12299;CUNEIFORM SIGN SAG TIMES HA;Lo;0;L;;;;;N;;;;;\n1229A;CUNEIFORM SIGN SAG TIMES KAK;Lo;0;L;;;;;N;;;;;\n1229B;CUNEIFORM SIGN SAG TIMES KUR;Lo;0;L;;;;;N;;;;;\n1229C;CUNEIFORM SIGN SAG TIMES LUM;Lo;0;L;;;;;N;;;;;\n1229D;CUNEIFORM SIGN SAG TIMES MI;Lo;0;L;;;;;N;;;;;\n1229E;CUNEIFORM SIGN SAG TIMES NUN;Lo;0;L;;;;;N;;;;;\n1229F;CUNEIFORM SIGN SAG TIMES SAL;Lo;0;L;;;;;N;;;;;\n122A0;CUNEIFORM SIGN SAG TIMES SHID;Lo;0;L;;;;;N;;;;;\n122A1;CUNEIFORM SIGN SAG TIMES TAB;Lo;0;L;;;;;N;;;;;\n122A2;CUNEIFORM SIGN SAG TIMES U2;Lo;0;L;;;;;N;;;;;\n122A3;CUNEIFORM SIGN SAG TIMES UB;Lo;0;L;;;;;N;;;;;\n122A4;CUNEIFORM SIGN SAG TIMES UM;Lo;0;L;;;;;N;;;;;\n122A5;CUNEIFORM SIGN SAG TIMES UR;Lo;0;L;;;;;N;;;;;\n122A6;CUNEIFORM SIGN SAG TIMES USH;Lo;0;L;;;;;N;;;;;\n122A7;CUNEIFORM SIGN SAG OVER SAG;Lo;0;L;;;;;N;;;;;\n122A8;CUNEIFORM SIGN SAG GUNU;Lo;0;L;;;;;N;;;;;\n122A9;CUNEIFORM SIGN SAL;Lo;0;L;;;;;N;;;;;\n122AA;CUNEIFORM SIGN SAL LAGAB TIMES ASH2;Lo;0;L;;;;;N;;;;;\n122AB;CUNEIFORM SIGN SANGA2;Lo;0;L;;;;;N;;;;;\n122AC;CUNEIFORM SIGN SAR;Lo;0;L;;;;;N;;;;;\n122AD;CUNEIFORM SIGN SHA;Lo;0;L;;;;;N;;;;;\n122AE;CUNEIFORM SIGN SHA3;Lo;0;L;;;;;N;;;;;\n122AF;CUNEIFORM SIGN SHA3 TIMES A;Lo;0;L;;;;;N;;;;;\n122B0;CUNEIFORM SIGN SHA3 TIMES BAD;Lo;0;L;;;;;N;;;;;\n122B1;CUNEIFORM SIGN SHA3 TIMES GISH;Lo;0;L;;;;;N;;;;;\n122B2;CUNEIFORM SIGN SHA3 TIMES NE;Lo;0;L;;;;;N;;;;;\n122B3;CUNEIFORM SIGN SHA3 TIMES SHU2;Lo;0;L;;;;;N;;;;;\n122B4;CUNEIFORM SIGN SHA3 TIMES TUR;Lo;0;L;;;;;N;;;;;\n122B5;CUNEIFORM SIGN SHA3 TIMES U;Lo;0;L;;;;;N;;;;;\n122B6;CUNEIFORM SIGN SHA3 TIMES U PLUS A;Lo;0;L;;;;;N;;;;;\n122B7;CUNEIFORM SIGN SHA6;Lo;0;L;;;;;N;;;;;\n122B8;CUNEIFORM SIGN SHAB6;Lo;0;L;;;;;N;;;;;\n122B9;CUNEIFORM SIGN SHAR2;Lo;0;L;;;;;N;;;;;\n122BA;CUNEIFORM SIGN SHE;Lo;0;L;;;;;N;;;;;\n122BB;CUNEIFORM SIGN SHE HU;Lo;0;L;;;;;N;;;;;\n122BC;CUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;;\n122BD;CUNEIFORM SIGN SHE OVER SHE TAB OVER TAB GAR OVER GAR;Lo;0;L;;;;;N;;;;;\n122BE;CUNEIFORM SIGN SHEG9;Lo;0;L;;;;;N;;;;;\n122BF;CUNEIFORM SIGN SHEN;Lo;0;L;;;;;N;;;;;\n122C0;CUNEIFORM SIGN SHESH;Lo;0;L;;;;;N;;;;;\n122C1;CUNEIFORM SIGN SHESH2;Lo;0;L;;;;;N;;;;;\n122C2;CUNEIFORM SIGN SHESHLAM;Lo;0;L;;;;;N;;;;;\n122C3;CUNEIFORM SIGN SHID;Lo;0;L;;;;;N;;;;;\n122C4;CUNEIFORM SIGN SHID TIMES A;Lo;0;L;;;;;N;;;;;\n122C5;CUNEIFORM SIGN SHID TIMES IM;Lo;0;L;;;;;N;;;;;\n122C6;CUNEIFORM SIGN SHIM;Lo;0;L;;;;;N;;;;;\n122C7;CUNEIFORM SIGN SHIM TIMES A;Lo;0;L;;;;;N;;;;;\n122C8;CUNEIFORM SIGN SHIM TIMES BAL;Lo;0;L;;;;;N;;;;;\n122C9;CUNEIFORM SIGN SHIM TIMES BULUG;Lo;0;L;;;;;N;;;;;\n122CA;CUNEIFORM SIGN SHIM TIMES DIN;Lo;0;L;;;;;N;;;;;\n122CB;CUNEIFORM SIGN SHIM TIMES GAR;Lo;0;L;;;;;N;;;;;\n122CC;CUNEIFORM SIGN SHIM TIMES IGI;Lo;0;L;;;;;N;;;;;\n122CD;CUNEIFORM SIGN SHIM TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n122CE;CUNEIFORM SIGN SHIM TIMES KUSHU2;Lo;0;L;;;;;N;;;;;\n122CF;CUNEIFORM SIGN SHIM TIMES LUL;Lo;0;L;;;;;N;;;;;\n122D0;CUNEIFORM SIGN SHIM TIMES MUG;Lo;0;L;;;;;N;;;;;\n122D1;CUNEIFORM SIGN SHIM TIMES SAL;Lo;0;L;;;;;N;;;;;\n122D2;CUNEIFORM SIGN SHINIG;Lo;0;L;;;;;N;;;;;\n122D3;CUNEIFORM SIGN SHIR;Lo;0;L;;;;;N;;;;;\n122D4;CUNEIFORM SIGN SHIR TENU;Lo;0;L;;;;;N;;;;;\n122D5;CUNEIFORM SIGN SHIR OVER SHIR BUR OVER BUR;Lo;0;L;;;;;N;;;;;\n122D6;CUNEIFORM SIGN SHITA;Lo;0;L;;;;;N;;;;;\n122D7;CUNEIFORM SIGN SHU;Lo;0;L;;;;;N;;;;;\n122D8;CUNEIFORM SIGN SHU OVER INVERTED SHU;Lo;0;L;;;;;N;;;;;\n122D9;CUNEIFORM SIGN SHU2;Lo;0;L;;;;;N;;;;;\n122DA;CUNEIFORM SIGN SHUBUR;Lo;0;L;;;;;N;;;;;\n122DB;CUNEIFORM SIGN SI;Lo;0;L;;;;;N;;;;;\n122DC;CUNEIFORM SIGN SI GUNU;Lo;0;L;;;;;N;;;;;\n122DD;CUNEIFORM SIGN SIG;Lo;0;L;;;;;N;;;;;\n122DE;CUNEIFORM SIGN SIG4;Lo;0;L;;;;;N;;;;;\n122DF;CUNEIFORM SIGN SIG4 OVER SIG4 SHU2;Lo;0;L;;;;;N;;;;;\n122E0;CUNEIFORM SIGN SIK2;Lo;0;L;;;;;N;;;;;\n122E1;CUNEIFORM SIGN SILA3;Lo;0;L;;;;;N;;;;;\n122E2;CUNEIFORM SIGN SU;Lo;0;L;;;;;N;;;;;\n122E3;CUNEIFORM SIGN SU OVER SU;Lo;0;L;;;;;N;;;;;\n122E4;CUNEIFORM SIGN SUD;Lo;0;L;;;;;N;;;;;\n122E5;CUNEIFORM SIGN SUD2;Lo;0;L;;;;;N;;;;;\n122E6;CUNEIFORM SIGN SUHUR;Lo;0;L;;;;;N;;;;;\n122E7;CUNEIFORM SIGN SUM;Lo;0;L;;;;;N;;;;;\n122E8;CUNEIFORM SIGN SUMASH;Lo;0;L;;;;;N;;;;;\n122E9;CUNEIFORM SIGN SUR;Lo;0;L;;;;;N;;;;;\n122EA;CUNEIFORM SIGN SUR9;Lo;0;L;;;;;N;;;;;\n122EB;CUNEIFORM SIGN TA;Lo;0;L;;;;;N;;;;;\n122EC;CUNEIFORM SIGN TA ASTERISK;Lo;0;L;;;;;N;;;;;\n122ED;CUNEIFORM SIGN TA TIMES HI;Lo;0;L;;;;;N;;;;;\n122EE;CUNEIFORM SIGN TA TIMES MI;Lo;0;L;;;;;N;;;;;\n122EF;CUNEIFORM SIGN TA GUNU;Lo;0;L;;;;;N;;;;;\n122F0;CUNEIFORM SIGN TAB;Lo;0;L;;;;;N;;;;;\n122F1;CUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISH;Lo;0;L;;;;;N;;;;;\n122F2;CUNEIFORM SIGN TAB SQUARED;Lo;0;L;;;;;N;;;;;\n122F3;CUNEIFORM SIGN TAG;Lo;0;L;;;;;N;;;;;\n122F4;CUNEIFORM SIGN TAG TIMES BI;Lo;0;L;;;;;N;;;;;\n122F5;CUNEIFORM SIGN TAG TIMES GUD;Lo;0;L;;;;;N;;;;;\n122F6;CUNEIFORM SIGN TAG TIMES SHE;Lo;0;L;;;;;N;;;;;\n122F7;CUNEIFORM SIGN TAG TIMES SHU;Lo;0;L;;;;;N;;;;;\n122F8;CUNEIFORM SIGN TAG TIMES TUG2;Lo;0;L;;;;;N;;;;;\n122F9;CUNEIFORM SIGN TAG TIMES UD;Lo;0;L;;;;;N;;;;;\n122FA;CUNEIFORM SIGN TAK4;Lo;0;L;;;;;N;;;;;\n122FB;CUNEIFORM SIGN TAR;Lo;0;L;;;;;N;;;;;\n122FC;CUNEIFORM SIGN TE;Lo;0;L;;;;;N;;;;;\n122FD;CUNEIFORM SIGN TE GUNU;Lo;0;L;;;;;N;;;;;\n122FE;CUNEIFORM SIGN TI;Lo;0;L;;;;;N;;;;;\n122FF;CUNEIFORM SIGN TI TENU;Lo;0;L;;;;;N;;;;;\n12300;CUNEIFORM SIGN TIL;Lo;0;L;;;;;N;;;;;\n12301;CUNEIFORM SIGN TIR;Lo;0;L;;;;;N;;;;;\n12302;CUNEIFORM SIGN TIR TIMES TAK4;Lo;0;L;;;;;N;;;;;\n12303;CUNEIFORM SIGN TIR OVER TIR;Lo;0;L;;;;;N;;;;;\n12304;CUNEIFORM SIGN TIR OVER TIR GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;;\n12305;CUNEIFORM SIGN TU;Lo;0;L;;;;;N;;;;;\n12306;CUNEIFORM SIGN TUG2;Lo;0;L;;;;;N;;;;;\n12307;CUNEIFORM SIGN TUK;Lo;0;L;;;;;N;;;;;\n12308;CUNEIFORM SIGN TUM;Lo;0;L;;;;;N;;;;;\n12309;CUNEIFORM SIGN TUR;Lo;0;L;;;;;N;;;;;\n1230A;CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA;Lo;0;L;;;;;N;;;;;\n1230B;CUNEIFORM SIGN U;Lo;0;L;;;;1;N;;;;;\n1230C;CUNEIFORM SIGN U GUD;Lo;0;L;;;;;N;;;;;\n1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;3;N;;;;;\n1230E;CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR;Lo;0;L;;;;;N;;;;;\n1230F;CUNEIFORM SIGN U OVER U SUR OVER SUR;Lo;0;L;;;;;N;;;;;\n12310;CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED;Lo;0;L;;;;;N;;;;;\n12311;CUNEIFORM SIGN U2;Lo;0;L;;;;;N;;;;;\n12312;CUNEIFORM SIGN UB;Lo;0;L;;;;;N;;;;;\n12313;CUNEIFORM SIGN UD;Lo;0;L;;;;;N;;;;;\n12314;CUNEIFORM SIGN UD KUSHU2;Lo;0;L;;;;;N;;;;;\n12315;CUNEIFORM SIGN UD TIMES BAD;Lo;0;L;;;;;N;;;;;\n12316;CUNEIFORM SIGN UD TIMES MI;Lo;0;L;;;;;N;;;;;\n12317;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;;\n12318;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNU;Lo;0;L;;;;;N;;;;;\n12319;CUNEIFORM SIGN UD GUNU;Lo;0;L;;;;;N;;;;;\n1231A;CUNEIFORM SIGN UD SHESHIG;Lo;0;L;;;;;N;;;;;\n1231B;CUNEIFORM SIGN UD SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;;\n1231C;CUNEIFORM SIGN UDUG;Lo;0;L;;;;;N;;;;;\n1231D;CUNEIFORM SIGN UM;Lo;0;L;;;;;N;;;;;\n1231E;CUNEIFORM SIGN UM TIMES LAGAB;Lo;0;L;;;;;N;;;;;\n1231F;CUNEIFORM SIGN UM TIMES ME PLUS DA;Lo;0;L;;;;;N;;;;;\n12320;CUNEIFORM SIGN UM TIMES SHA3;Lo;0;L;;;;;N;;;;;\n12321;CUNEIFORM SIGN UM TIMES U;Lo;0;L;;;;;N;;;;;\n12322;CUNEIFORM SIGN UMBIN;Lo;0;L;;;;;N;;;;;\n12323;CUNEIFORM SIGN UMUM;Lo;0;L;;;;;N;;;;;\n12324;CUNEIFORM SIGN UMUM TIMES KASKAL;Lo;0;L;;;;;N;;;;;\n12325;CUNEIFORM SIGN UMUM TIMES PA;Lo;0;L;;;;;N;;;;;\n12326;CUNEIFORM SIGN UN;Lo;0;L;;;;;N;;;;;\n12327;CUNEIFORM SIGN UN GUNU;Lo;0;L;;;;;N;;;;;\n12328;CUNEIFORM SIGN UR;Lo;0;L;;;;;N;;;;;\n12329;CUNEIFORM SIGN UR CROSSING UR;Lo;0;L;;;;;N;;;;;\n1232A;CUNEIFORM SIGN UR SHESHIG;Lo;0;L;;;;;N;;;;;\n1232B;CUNEIFORM SIGN UR2;Lo;0;L;;;;;N;;;;;\n1232C;CUNEIFORM SIGN UR2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;;\n1232D;CUNEIFORM SIGN UR2 TIMES A PLUS NA;Lo;0;L;;;;;N;;;;;\n1232E;CUNEIFORM SIGN UR2 TIMES AL;Lo;0;L;;;;;N;;;;;\n1232F;CUNEIFORM SIGN UR2 TIMES HA;Lo;0;L;;;;;N;;;;;\n12330;CUNEIFORM SIGN UR2 TIMES NUN;Lo;0;L;;;;;N;;;;;\n12331;CUNEIFORM SIGN UR2 TIMES U2;Lo;0;L;;;;;N;;;;;\n12332;CUNEIFORM SIGN UR2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;;\n12333;CUNEIFORM SIGN UR2 TIMES U2 PLUS BI;Lo;0;L;;;;;N;;;;;\n12334;CUNEIFORM SIGN UR4;Lo;0;L;;;;;N;;;;;\n12335;CUNEIFORM SIGN URI;Lo;0;L;;;;;N;;;;;\n12336;CUNEIFORM SIGN URI3;Lo;0;L;;;;;N;;;;;\n12337;CUNEIFORM SIGN URU;Lo;0;L;;;;;N;;;;;\n12338;CUNEIFORM SIGN URU TIMES A;Lo;0;L;;;;;N;;;;;\n12339;CUNEIFORM SIGN URU TIMES ASHGAB;Lo;0;L;;;;;N;;;;;\n1233A;CUNEIFORM SIGN URU TIMES BAR;Lo;0;L;;;;;N;;;;;\n1233B;CUNEIFORM SIGN URU TIMES DUN;Lo;0;L;;;;;N;;;;;\n1233C;CUNEIFORM SIGN URU TIMES GA;Lo;0;L;;;;;N;;;;;\n1233D;CUNEIFORM SIGN URU TIMES GAL;Lo;0;L;;;;;N;;;;;\n1233E;CUNEIFORM SIGN URU TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n1233F;CUNEIFORM SIGN URU TIMES GAR;Lo;0;L;;;;;N;;;;;\n12340;CUNEIFORM SIGN URU TIMES GU;Lo;0;L;;;;;N;;;;;\n12341;CUNEIFORM SIGN URU TIMES HA;Lo;0;L;;;;;N;;;;;\n12342;CUNEIFORM SIGN URU TIMES IGI;Lo;0;L;;;;;N;;;;;\n12343;CUNEIFORM SIGN URU TIMES IM;Lo;0;L;;;;;N;;;;;\n12344;CUNEIFORM SIGN URU TIMES ISH;Lo;0;L;;;;;N;;;;;\n12345;CUNEIFORM SIGN URU TIMES KI;Lo;0;L;;;;;N;;;;;\n12346;CUNEIFORM SIGN URU TIMES LUM;Lo;0;L;;;;;N;;;;;\n12347;CUNEIFORM SIGN URU TIMES MIN;Lo;0;L;;;;;N;;;;;\n12348;CUNEIFORM SIGN URU TIMES PA;Lo;0;L;;;;;N;;;;;\n12349;CUNEIFORM SIGN URU TIMES SHE;Lo;0;L;;;;;N;;;;;\n1234A;CUNEIFORM SIGN URU TIMES SIG4;Lo;0;L;;;;;N;;;;;\n1234B;CUNEIFORM SIGN URU TIMES TU;Lo;0;L;;;;;N;;;;;\n1234C;CUNEIFORM SIGN URU TIMES U PLUS GUD;Lo;0;L;;;;;N;;;;;\n1234D;CUNEIFORM SIGN URU TIMES UD;Lo;0;L;;;;;N;;;;;\n1234E;CUNEIFORM SIGN URU TIMES URUDA;Lo;0;L;;;;;N;;;;;\n1234F;CUNEIFORM SIGN URUDA;Lo;0;L;;;;;N;;;;;\n12350;CUNEIFORM SIGN URUDA TIMES U;Lo;0;L;;;;;N;;;;;\n12351;CUNEIFORM SIGN USH;Lo;0;L;;;;;N;;;;;\n12352;CUNEIFORM SIGN USH TIMES A;Lo;0;L;;;;;N;;;;;\n12353;CUNEIFORM SIGN USH TIMES KU;Lo;0;L;;;;;N;;;;;\n12354;CUNEIFORM SIGN USH TIMES KUR;Lo;0;L;;;;;N;;;;;\n12355;CUNEIFORM SIGN USH TIMES TAK4;Lo;0;L;;;;;N;;;;;\n12356;CUNEIFORM SIGN USHX;Lo;0;L;;;;;N;;;;;\n12357;CUNEIFORM SIGN USH2;Lo;0;L;;;;;N;;;;;\n12358;CUNEIFORM SIGN USHUMX;Lo;0;L;;;;;N;;;;;\n12359;CUNEIFORM SIGN UTUKI;Lo;0;L;;;;;N;;;;;\n1235A;CUNEIFORM SIGN UZ3;Lo;0;L;;;;;N;;;;;\n1235B;CUNEIFORM SIGN UZ3 TIMES KASKAL;Lo;0;L;;;;;N;;;;;\n1235C;CUNEIFORM SIGN UZU;Lo;0;L;;;;;N;;;;;\n1235D;CUNEIFORM SIGN ZA;Lo;0;L;;;;;N;;;;;\n1235E;CUNEIFORM SIGN ZA TENU;Lo;0;L;;;;;N;;;;;\n1235F;CUNEIFORM SIGN ZA SQUARED TIMES KUR;Lo;0;L;;;;;N;;;;;\n12360;CUNEIFORM SIGN ZAG;Lo;0;L;;;;;N;;;;;\n12361;CUNEIFORM SIGN ZAMX;Lo;0;L;;;;;N;;;;;\n12362;CUNEIFORM SIGN ZE2;Lo;0;L;;;;;N;;;;;\n12363;CUNEIFORM SIGN ZI;Lo;0;L;;;;;N;;;;;\n12364;CUNEIFORM SIGN ZI OVER ZI;Lo;0;L;;;;;N;;;;;\n12365;CUNEIFORM SIGN ZI3;Lo;0;L;;;;;N;;;;;\n12366;CUNEIFORM SIGN ZIB;Lo;0;L;;;;;N;;;;;\n12367;CUNEIFORM SIGN ZIB KABA TENU;Lo;0;L;;;;;N;;;;;\n12368;CUNEIFORM SIGN ZIG;Lo;0;L;;;;;N;;;;;\n12369;CUNEIFORM SIGN ZIZ2;Lo;0;L;;;;;N;;;;;\n1236A;CUNEIFORM SIGN ZU;Lo;0;L;;;;;N;;;;;\n1236B;CUNEIFORM SIGN ZU5;Lo;0;L;;;;;N;;;;;\n1236C;CUNEIFORM SIGN ZU5 TIMES A;Lo;0;L;;;;;N;;;;;\n1236D;CUNEIFORM SIGN ZUBUR;Lo;0;L;;;;;N;;;;;\n1236E;CUNEIFORM SIGN ZUM;Lo;0;L;;;;;N;;;;;\n1236F;CUNEIFORM SIGN KAP ELAMITE;Lo;0;L;;;;;N;;;;;\n12370;CUNEIFORM SIGN AB TIMES NUN;Lo;0;L;;;;;N;;;;;\n12371;CUNEIFORM SIGN AB2 TIMES A;Lo;0;L;;;;;N;;;;;\n12372;CUNEIFORM SIGN AMAR TIMES KUG;Lo;0;L;;;;;N;;;;;\n12373;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS MASH;Lo;0;L;;;;;N;;;;;\n12374;CUNEIFORM SIGN DAG3;Lo;0;L;;;;;N;;;;;\n12375;CUNEIFORM SIGN DISH PLUS SHU;Lo;0;L;;;;;N;;;;;\n12376;CUNEIFORM SIGN DUB TIMES SHE;Lo;0;L;;;;;N;;;;;\n12377;CUNEIFORM SIGN EZEN TIMES GUD;Lo;0;L;;;;;N;;;;;\n12378;CUNEIFORM SIGN EZEN TIMES SHE;Lo;0;L;;;;;N;;;;;\n12379;CUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS A;Lo;0;L;;;;;N;;;;;\n1237A;CUNEIFORM SIGN GA2 TIMES ASH2;Lo;0;L;;;;;N;;;;;\n1237B;CUNEIFORM SIGN GE22;Lo;0;L;;;;;N;;;;;\n1237C;CUNEIFORM SIGN GIG;Lo;0;L;;;;;N;;;;;\n1237D;CUNEIFORM SIGN HUSH;Lo;0;L;;;;;N;;;;;\n1237E;CUNEIFORM SIGN KA TIMES ANSHE;Lo;0;L;;;;;N;;;;;\n1237F;CUNEIFORM SIGN KA TIMES ASH3;Lo;0;L;;;;;N;;;;;\n12380;CUNEIFORM SIGN KA TIMES GISH;Lo;0;L;;;;;N;;;;;\n12381;CUNEIFORM SIGN KA TIMES GUD;Lo;0;L;;;;;N;;;;;\n12382;CUNEIFORM SIGN KA TIMES HI TIMES ASH2;Lo;0;L;;;;;N;;;;;\n12383;CUNEIFORM SIGN KA TIMES LUM;Lo;0;L;;;;;N;;;;;\n12384;CUNEIFORM SIGN KA TIMES PA;Lo;0;L;;;;;N;;;;;\n12385;CUNEIFORM SIGN KA TIMES SHUL;Lo;0;L;;;;;N;;;;;\n12386;CUNEIFORM SIGN KA TIMES TU;Lo;0;L;;;;;N;;;;;\n12387;CUNEIFORM SIGN KA TIMES UR2;Lo;0;L;;;;;N;;;;;\n12388;CUNEIFORM SIGN LAGAB TIMES GI;Lo;0;L;;;;;N;;;;;\n12389;CUNEIFORM SIGN LU2 SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;;\n1238A;CUNEIFORM SIGN LU2 TIMES ESH2 PLUS LAL;Lo;0;L;;;;;N;;;;;\n1238B;CUNEIFORM SIGN LU2 TIMES SHU;Lo;0;L;;;;;N;;;;;\n1238C;CUNEIFORM SIGN MESH;Lo;0;L;;;;;N;;;;;\n1238D;CUNEIFORM SIGN MUSH3 TIMES ZA;Lo;0;L;;;;;N;;;;;\n1238E;CUNEIFORM SIGN NA4;Lo;0;L;;;;;N;;;;;\n1238F;CUNEIFORM SIGN NIN;Lo;0;L;;;;;N;;;;;\n12390;CUNEIFORM SIGN NIN9;Lo;0;L;;;;;N;;;;;\n12391;CUNEIFORM SIGN NINDA2 TIMES BAL;Lo;0;L;;;;;N;;;;;\n12392;CUNEIFORM SIGN NINDA2 TIMES GI;Lo;0;L;;;;;N;;;;;\n12393;CUNEIFORM SIGN NU11 ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;;\n12394;CUNEIFORM SIGN PESH2 ASTERISK;Lo;0;L;;;;;N;;;;;\n12395;CUNEIFORM SIGN PIR2;Lo;0;L;;;;;N;;;;;\n12396;CUNEIFORM SIGN SAG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n12397;CUNEIFORM SIGN TI2;Lo;0;L;;;;;N;;;;;\n12398;CUNEIFORM SIGN UM TIMES ME;Lo;0;L;;;;;N;;;;;\n12399;CUNEIFORM SIGN U U;Lo;0;L;;;;2;N;;;;;\n12400;CUNEIFORM NUMERIC SIGN TWO ASH;Nl;0;L;;;;2;N;;;;;\n12401;CUNEIFORM NUMERIC SIGN THREE ASH;Nl;0;L;;;;3;N;;;;;\n12402;CUNEIFORM NUMERIC SIGN FOUR ASH;Nl;0;L;;;;4;N;;;;;\n12403;CUNEIFORM NUMERIC SIGN FIVE ASH;Nl;0;L;;;;5;N;;;;;\n12404;CUNEIFORM NUMERIC SIGN SIX ASH;Nl;0;L;;;;6;N;;;;;\n12405;CUNEIFORM NUMERIC SIGN SEVEN ASH;Nl;0;L;;;;7;N;;;;;\n12406;CUNEIFORM NUMERIC SIGN EIGHT ASH;Nl;0;L;;;;8;N;;;;;\n12407;CUNEIFORM NUMERIC SIGN NINE ASH;Nl;0;L;;;;9;N;;;;;\n12408;CUNEIFORM NUMERIC SIGN THREE DISH;Nl;0;L;;;;3;N;;;;;\n12409;CUNEIFORM NUMERIC SIGN FOUR DISH;Nl;0;L;;;;4;N;;;;;\n1240A;CUNEIFORM NUMERIC SIGN FIVE DISH;Nl;0;L;;;;5;N;;;;;\n1240B;CUNEIFORM NUMERIC SIGN SIX DISH;Nl;0;L;;;;6;N;;;;;\n1240C;CUNEIFORM NUMERIC SIGN SEVEN DISH;Nl;0;L;;;;7;N;;;;;\n1240D;CUNEIFORM NUMERIC SIGN EIGHT DISH;Nl;0;L;;;;8;N;;;;;\n1240E;CUNEIFORM NUMERIC SIGN NINE DISH;Nl;0;L;;;;9;N;;;;;\n1240F;CUNEIFORM NUMERIC SIGN FOUR U;Nl;0;L;;;;4;N;;;;;\n12410;CUNEIFORM NUMERIC SIGN FIVE U;Nl;0;L;;;;5;N;;;;;\n12411;CUNEIFORM NUMERIC SIGN SIX U;Nl;0;L;;;;6;N;;;;;\n12412;CUNEIFORM NUMERIC SIGN SEVEN U;Nl;0;L;;;;7;N;;;;;\n12413;CUNEIFORM NUMERIC SIGN EIGHT U;Nl;0;L;;;;8;N;;;;;\n12414;CUNEIFORM NUMERIC SIGN NINE U;Nl;0;L;;;;9;N;;;;;\n12415;CUNEIFORM NUMERIC SIGN ONE GESH2;Nl;0;L;;;;1;N;;;;;\n12416;CUNEIFORM NUMERIC SIGN TWO GESH2;Nl;0;L;;;;2;N;;;;;\n12417;CUNEIFORM NUMERIC SIGN THREE GESH2;Nl;0;L;;;;3;N;;;;;\n12418;CUNEIFORM NUMERIC SIGN FOUR GESH2;Nl;0;L;;;;4;N;;;;;\n12419;CUNEIFORM NUMERIC SIGN FIVE GESH2;Nl;0;L;;;;5;N;;;;;\n1241A;CUNEIFORM NUMERIC SIGN SIX GESH2;Nl;0;L;;;;6;N;;;;;\n1241B;CUNEIFORM NUMERIC SIGN SEVEN GESH2;Nl;0;L;;;;7;N;;;;;\n1241C;CUNEIFORM NUMERIC SIGN EIGHT GESH2;Nl;0;L;;;;8;N;;;;;\n1241D;CUNEIFORM NUMERIC SIGN NINE GESH2;Nl;0;L;;;;9;N;;;;;\n1241E;CUNEIFORM NUMERIC SIGN ONE GESHU;Nl;0;L;;;;1;N;;;;;\n1241F;CUNEIFORM NUMERIC SIGN TWO GESHU;Nl;0;L;;;;2;N;;;;;\n12420;CUNEIFORM NUMERIC SIGN THREE GESHU;Nl;0;L;;;;3;N;;;;;\n12421;CUNEIFORM NUMERIC SIGN FOUR GESHU;Nl;0;L;;;;4;N;;;;;\n12422;CUNEIFORM NUMERIC SIGN FIVE GESHU;Nl;0;L;;;;5;N;;;;;\n12423;CUNEIFORM NUMERIC SIGN TWO SHAR2;Nl;0;L;;;;2;N;;;;;\n12424;CUNEIFORM NUMERIC SIGN THREE SHAR2;Nl;0;L;;;;3;N;;;;;\n12425;CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORM;Nl;0;L;;;;3;N;;;;;\n12426;CUNEIFORM NUMERIC SIGN FOUR SHAR2;Nl;0;L;;;;4;N;;;;;\n12427;CUNEIFORM NUMERIC SIGN FIVE SHAR2;Nl;0;L;;;;5;N;;;;;\n12428;CUNEIFORM NUMERIC SIGN SIX SHAR2;Nl;0;L;;;;6;N;;;;;\n12429;CUNEIFORM NUMERIC SIGN SEVEN SHAR2;Nl;0;L;;;;7;N;;;;;\n1242A;CUNEIFORM NUMERIC SIGN EIGHT SHAR2;Nl;0;L;;;;8;N;;;;;\n1242B;CUNEIFORM NUMERIC SIGN NINE SHAR2;Nl;0;L;;;;9;N;;;;;\n1242C;CUNEIFORM NUMERIC SIGN ONE SHARU;Nl;0;L;;;;1;N;;;;;\n1242D;CUNEIFORM NUMERIC SIGN TWO SHARU;Nl;0;L;;;;2;N;;;;;\n1242E;CUNEIFORM NUMERIC SIGN THREE SHARU;Nl;0;L;;;;3;N;;;;;\n1242F;CUNEIFORM NUMERIC SIGN THREE SHARU VARIANT FORM;Nl;0;L;;;;3;N;;;;;\n12430;CUNEIFORM NUMERIC SIGN FOUR SHARU;Nl;0;L;;;;4;N;;;;;\n12431;CUNEIFORM NUMERIC SIGN FIVE SHARU;Nl;0;L;;;;5;N;;;;;\n12432;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH;Nl;0;L;;;;216000;N;;;;;\n12433;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN;Nl;0;L;;;;432000;N;;;;;\n12434;CUNEIFORM NUMERIC SIGN ONE BURU;Nl;0;L;;;;1;N;;;;;\n12435;CUNEIFORM NUMERIC SIGN TWO BURU;Nl;0;L;;;;2;N;;;;;\n12436;CUNEIFORM NUMERIC SIGN THREE BURU;Nl;0;L;;;;3;N;;;;;\n12437;CUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORM;Nl;0;L;;;;3;N;;;;;\n12438;CUNEIFORM NUMERIC SIGN FOUR BURU;Nl;0;L;;;;4;N;;;;;\n12439;CUNEIFORM NUMERIC SIGN FIVE BURU;Nl;0;L;;;;5;N;;;;;\n1243A;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH16;Nl;0;L;;;;3;N;;;;;\n1243B;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21;Nl;0;L;;;;3;N;;;;;\n1243C;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU;Nl;0;L;;;;4;N;;;;;\n1243D;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4;Nl;0;L;;;;4;N;;;;;\n1243E;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU A;Nl;0;L;;;;4;N;;;;;\n1243F;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU B;Nl;0;L;;;;4;N;;;;;\n12440;CUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9;Nl;0;L;;;;6;N;;;;;\n12441;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3;Nl;0;L;;;;7;N;;;;;\n12442;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN A;Nl;0;L;;;;7;N;;;;;\n12443;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN B;Nl;0;L;;;;7;N;;;;;\n12444;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU;Nl;0;L;;;;8;N;;;;;\n12445;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU3;Nl;0;L;;;;8;N;;;;;\n12446;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU;Nl;0;L;;;;9;N;;;;;\n12447;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3;Nl;0;L;;;;9;N;;;;;\n12448;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU4;Nl;0;L;;;;9;N;;;;;\n12449;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU A;Nl;0;L;;;;9;N;;;;;\n1244A;CUNEIFORM NUMERIC SIGN TWO ASH TENU;Nl;0;L;;;;2;N;;;;;\n1244B;CUNEIFORM NUMERIC SIGN THREE ASH TENU;Nl;0;L;;;;3;N;;;;;\n1244C;CUNEIFORM NUMERIC SIGN FOUR ASH TENU;Nl;0;L;;;;4;N;;;;;\n1244D;CUNEIFORM NUMERIC SIGN FIVE ASH TENU;Nl;0;L;;;;5;N;;;;;\n1244E;CUNEIFORM NUMERIC SIGN SIX ASH TENU;Nl;0;L;;;;6;N;;;;;\n1244F;CUNEIFORM NUMERIC SIGN ONE BAN2;Nl;0;L;;;;1;N;;;;;\n12450;CUNEIFORM NUMERIC SIGN TWO BAN2;Nl;0;L;;;;2;N;;;;;\n12451;CUNEIFORM NUMERIC SIGN THREE BAN2;Nl;0;L;;;;3;N;;;;;\n12452;CUNEIFORM NUMERIC SIGN FOUR BAN2;Nl;0;L;;;;4;N;;;;;\n12453;CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM;Nl;0;L;;;;4;N;;;;;\n12454;CUNEIFORM NUMERIC SIGN FIVE BAN2;Nl;0;L;;;;5;N;;;;;\n12455;CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM;Nl;0;L;;;;5;N;;;;;\n12456;CUNEIFORM NUMERIC SIGN NIGIDAMIN;Nl;0;L;;;;2;N;;;;;\n12457;CUNEIFORM NUMERIC SIGN NIGIDAESH;Nl;0;L;;;;3;N;;;;;\n12458;CUNEIFORM NUMERIC SIGN ONE ESHE3;Nl;0;L;;;;1;N;;;;;\n12459;CUNEIFORM NUMERIC SIGN TWO ESHE3;Nl;0;L;;;;2;N;;;;;\n1245A;CUNEIFORM NUMERIC SIGN ONE THIRD DISH;Nl;0;L;;;;1/3;N;;;;;\n1245B;CUNEIFORM NUMERIC SIGN TWO THIRDS DISH;Nl;0;L;;;;2/3;N;;;;;\n1245C;CUNEIFORM NUMERIC SIGN FIVE SIXTHS DISH;Nl;0;L;;;;5/6;N;;;;;\n1245D;CUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM A;Nl;0;L;;;;1/3;N;;;;;\n1245E;CUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM A;Nl;0;L;;;;2/3;N;;;;;\n1245F;CUNEIFORM NUMERIC SIGN ONE EIGHTH ASH;Nl;0;L;;;;1/8;N;;;;;\n12460;CUNEIFORM NUMERIC SIGN ONE QUARTER ASH;Nl;0;L;;;;1/4;N;;;;;\n12461;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH;Nl;0;L;;;;1/6;N;;;;;\n12462;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER;Nl;0;L;;;;1/4;N;;;;;\n12463;CUNEIFORM NUMERIC SIGN ONE QUARTER GUR;Nl;0;L;;;;1/4;N;;;;;\n12464;CUNEIFORM NUMERIC SIGN ONE HALF GUR;Nl;0;L;;;;1/2;N;;;;;\n12465;CUNEIFORM NUMERIC SIGN ELAMITE ONE THIRD;Nl;0;L;;;;1/3;N;;;;;\n12466;CUNEIFORM NUMERIC SIGN ELAMITE TWO THIRDS;Nl;0;L;;;;2/3;N;;;;;\n12467;CUNEIFORM NUMERIC SIGN ELAMITE FORTY;Nl;0;L;;;;40;N;;;;;\n12468;CUNEIFORM NUMERIC SIGN ELAMITE FIFTY;Nl;0;L;;;;50;N;;;;;\n12469;CUNEIFORM NUMERIC SIGN FOUR U VARIANT FORM;Nl;0;L;;;;4;N;;;;;\n1246A;CUNEIFORM NUMERIC SIGN FIVE U VARIANT FORM;Nl;0;L;;;;5;N;;;;;\n1246B;CUNEIFORM NUMERIC SIGN SIX U VARIANT FORM;Nl;0;L;;;;6;N;;;;;\n1246C;CUNEIFORM NUMERIC SIGN SEVEN U VARIANT FORM;Nl;0;L;;;;7;N;;;;;\n1246D;CUNEIFORM NUMERIC SIGN EIGHT U VARIANT FORM;Nl;0;L;;;;8;N;;;;;\n1246E;CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM;Nl;0;L;;;;9;N;;;;;\n12470;CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER;Po;0;L;;;;;N;;;;;\n12471;CUNEIFORM PUNCTUATION SIGN VERTICAL COLON;Po;0;L;;;;;N;;;;;\n12472;CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON;Po;0;L;;;;;N;;;;;\n12473;CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON;Po;0;L;;;;;N;;;;;\n12474;CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON;Po;0;L;;;;;N;;;;;\n12480;CUNEIFORM SIGN AB TIMES NUN TENU;Lo;0;L;;;;;N;;;;;\n12481;CUNEIFORM SIGN AB TIMES SHU2;Lo;0;L;;;;;N;;;;;\n12482;CUNEIFORM SIGN AD TIMES ESH2;Lo;0;L;;;;;N;;;;;\n12483;CUNEIFORM SIGN BAD TIMES DISH TENU;Lo;0;L;;;;;N;;;;;\n12484;CUNEIFORM SIGN BAHAR2 TIMES AB2;Lo;0;L;;;;;N;;;;;\n12485;CUNEIFORM SIGN BAHAR2 TIMES NI;Lo;0;L;;;;;N;;;;;\n12486;CUNEIFORM SIGN BAHAR2 TIMES ZA;Lo;0;L;;;;;N;;;;;\n12487;CUNEIFORM SIGN BU OVER BU TIMES NA2;Lo;0;L;;;;;N;;;;;\n12488;CUNEIFORM SIGN DA TIMES TAK4;Lo;0;L;;;;;N;;;;;\n12489;CUNEIFORM SIGN DAG TIMES KUR;Lo;0;L;;;;;N;;;;;\n1248A;CUNEIFORM SIGN DIM TIMES IGI;Lo;0;L;;;;;N;;;;;\n1248B;CUNEIFORM SIGN DIM TIMES U U U;Lo;0;L;;;;;N;;;;;\n1248C;CUNEIFORM SIGN DIM2 TIMES UD;Lo;0;L;;;;;N;;;;;\n1248D;CUNEIFORM SIGN DUG TIMES ANSHE;Lo;0;L;;;;;N;;;;;\n1248E;CUNEIFORM SIGN DUG TIMES ASH;Lo;0;L;;;;;N;;;;;\n1248F;CUNEIFORM SIGN DUG TIMES ASH AT LEFT;Lo;0;L;;;;;N;;;;;\n12490;CUNEIFORM SIGN DUG TIMES DIN;Lo;0;L;;;;;N;;;;;\n12491;CUNEIFORM SIGN DUG TIMES DUN;Lo;0;L;;;;;N;;;;;\n12492;CUNEIFORM SIGN DUG TIMES ERIN2;Lo;0;L;;;;;N;;;;;\n12493;CUNEIFORM SIGN DUG TIMES GA;Lo;0;L;;;;;N;;;;;\n12494;CUNEIFORM SIGN DUG TIMES GI;Lo;0;L;;;;;N;;;;;\n12495;CUNEIFORM SIGN DUG TIMES GIR2 GUNU;Lo;0;L;;;;;N;;;;;\n12496;CUNEIFORM SIGN DUG TIMES GISH;Lo;0;L;;;;;N;;;;;\n12497;CUNEIFORM SIGN DUG TIMES HA;Lo;0;L;;;;;N;;;;;\n12498;CUNEIFORM SIGN DUG TIMES HI;Lo;0;L;;;;;N;;;;;\n12499;CUNEIFORM SIGN DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n1249A;CUNEIFORM SIGN DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;;\n1249B;CUNEIFORM SIGN DUG TIMES KUR;Lo;0;L;;;;;N;;;;;\n1249C;CUNEIFORM SIGN DUG TIMES KUSHU2;Lo;0;L;;;;;N;;;;;\n1249D;CUNEIFORM SIGN DUG TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;;\n1249E;CUNEIFORM SIGN DUG TIMES LAK-020;Lo;0;L;;;;;N;;;;;\n1249F;CUNEIFORM SIGN DUG TIMES LAM;Lo;0;L;;;;;N;;;;;\n124A0;CUNEIFORM SIGN DUG TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;;\n124A1;CUNEIFORM SIGN DUG TIMES LUH PLUS GISH;Lo;0;L;;;;;N;;;;;\n124A2;CUNEIFORM SIGN DUG TIMES MASH;Lo;0;L;;;;;N;;;;;\n124A3;CUNEIFORM SIGN DUG TIMES MES;Lo;0;L;;;;;N;;;;;\n124A4;CUNEIFORM SIGN DUG TIMES MI;Lo;0;L;;;;;N;;;;;\n124A5;CUNEIFORM SIGN DUG TIMES NI;Lo;0;L;;;;;N;;;;;\n124A6;CUNEIFORM SIGN DUG TIMES PI;Lo;0;L;;;;;N;;;;;\n124A7;CUNEIFORM SIGN DUG TIMES SHE;Lo;0;L;;;;;N;;;;;\n124A8;CUNEIFORM SIGN DUG TIMES SI GUNU;Lo;0;L;;;;;N;;;;;\n124A9;CUNEIFORM SIGN E2 TIMES KUR;Lo;0;L;;;;;N;;;;;\n124AA;CUNEIFORM SIGN E2 TIMES PAP;Lo;0;L;;;;;N;;;;;\n124AB;CUNEIFORM SIGN ERIN2 X;Lo;0;L;;;;;N;;;;;\n124AC;CUNEIFORM SIGN ESH2 CROSSING ESH2;Lo;0;L;;;;;N;;;;;\n124AD;CUNEIFORM SIGN EZEN SHESHIG TIMES ASH;Lo;0;L;;;;;N;;;;;\n124AE;CUNEIFORM SIGN EZEN SHESHIG TIMES HI;Lo;0;L;;;;;N;;;;;\n124AF;CUNEIFORM SIGN EZEN SHESHIG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n124B0;CUNEIFORM SIGN EZEN SHESHIG TIMES LA;Lo;0;L;;;;;N;;;;;\n124B1;CUNEIFORM SIGN EZEN SHESHIG TIMES LAL;Lo;0;L;;;;;N;;;;;\n124B2;CUNEIFORM SIGN EZEN SHESHIG TIMES ME;Lo;0;L;;;;;N;;;;;\n124B3;CUNEIFORM SIGN EZEN SHESHIG TIMES MES;Lo;0;L;;;;;N;;;;;\n124B4;CUNEIFORM SIGN EZEN SHESHIG TIMES SU;Lo;0;L;;;;;N;;;;;\n124B5;CUNEIFORM SIGN EZEN TIMES SU;Lo;0;L;;;;;N;;;;;\n124B6;CUNEIFORM SIGN GA2 TIMES BAHAR2;Lo;0;L;;;;;N;;;;;\n124B7;CUNEIFORM SIGN GA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;;\n124B8;CUNEIFORM SIGN GA2 TIMES DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n124B9;CUNEIFORM SIGN GA2 TIMES DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;;\n124BA;CUNEIFORM SIGN GA2 TIMES EREN;Lo;0;L;;;;;N;;;;;\n124BB;CUNEIFORM SIGN GA2 TIMES GA;Lo;0;L;;;;;N;;;;;\n124BC;CUNEIFORM SIGN GA2 TIMES GAR PLUS DI;Lo;0;L;;;;;N;;;;;\n124BD;CUNEIFORM SIGN GA2 TIMES GAR PLUS NE;Lo;0;L;;;;;N;;;;;\n124BE;CUNEIFORM SIGN GA2 TIMES HA PLUS A;Lo;0;L;;;;;N;;;;;\n124BF;CUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;;\n124C0;CUNEIFORM SIGN GA2 TIMES LAM;Lo;0;L;;;;;N;;;;;\n124C1;CUNEIFORM SIGN GA2 TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;;\n124C2;CUNEIFORM SIGN GA2 TIMES LUH;Lo;0;L;;;;;N;;;;;\n124C3;CUNEIFORM SIGN GA2 TIMES MUSH;Lo;0;L;;;;;N;;;;;\n124C4;CUNEIFORM SIGN GA2 TIMES NE;Lo;0;L;;;;;N;;;;;\n124C5;CUNEIFORM SIGN GA2 TIMES NE PLUS E2;Lo;0;L;;;;;N;;;;;\n124C6;CUNEIFORM SIGN GA2 TIMES NE PLUS GI;Lo;0;L;;;;;N;;;;;\n124C7;CUNEIFORM SIGN GA2 TIMES SHIM;Lo;0;L;;;;;N;;;;;\n124C8;CUNEIFORM SIGN GA2 TIMES ZIZ2;Lo;0;L;;;;;N;;;;;\n124C9;CUNEIFORM SIGN GABA ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;;\n124CA;CUNEIFORM SIGN GESHTIN TIMES U;Lo;0;L;;;;;N;;;;;\n124CB;CUNEIFORM SIGN GISH TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;;\n124CC;CUNEIFORM SIGN GU2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n124CD;CUNEIFORM SIGN GUD PLUS GISH TIMES TAK4;Lo;0;L;;;;;N;;;;;\n124CE;CUNEIFORM SIGN HA TENU GUNU;Lo;0;L;;;;;N;;;;;\n124CF;CUNEIFORM SIGN HI TIMES ASH OVER HI TIMES ASH;Lo;0;L;;;;;N;;;;;\n124D0;CUNEIFORM SIGN KA TIMES BU;Lo;0;L;;;;;N;;;;;\n124D1;CUNEIFORM SIGN KA TIMES KA;Lo;0;L;;;;;N;;;;;\n124D2;CUNEIFORM SIGN KA TIMES U U U;Lo;0;L;;;;;N;;;;;\n124D3;CUNEIFORM SIGN KA TIMES UR;Lo;0;L;;;;;N;;;;;\n124D4;CUNEIFORM SIGN LAGAB TIMES ZU OVER ZU;Lo;0;L;;;;;N;;;;;\n124D5;CUNEIFORM SIGN LAK-003;Lo;0;L;;;;;N;;;;;\n124D6;CUNEIFORM SIGN LAK-021;Lo;0;L;;;;;N;;;;;\n124D7;CUNEIFORM SIGN LAK-025;Lo;0;L;;;;;N;;;;;\n124D8;CUNEIFORM SIGN LAK-030;Lo;0;L;;;;;N;;;;;\n124D9;CUNEIFORM SIGN LAK-050;Lo;0;L;;;;;N;;;;;\n124DA;CUNEIFORM SIGN LAK-051;Lo;0;L;;;;;N;;;;;\n124DB;CUNEIFORM SIGN LAK-062;Lo;0;L;;;;;N;;;;;\n124DC;CUNEIFORM SIGN LAK-079 OVER LAK-079 GUNU;Lo;0;L;;;;;N;;;;;\n124DD;CUNEIFORM SIGN LAK-080;Lo;0;L;;;;;N;;;;;\n124DE;CUNEIFORM SIGN LAK-081 OVER LAK-081;Lo;0;L;;;;;N;;;;;\n124DF;CUNEIFORM SIGN LAK-092;Lo;0;L;;;;;N;;;;;\n124E0;CUNEIFORM SIGN LAK-130;Lo;0;L;;;;;N;;;;;\n124E1;CUNEIFORM SIGN LAK-142;Lo;0;L;;;;;N;;;;;\n124E2;CUNEIFORM SIGN LAK-210;Lo;0;L;;;;;N;;;;;\n124E3;CUNEIFORM SIGN LAK-219;Lo;0;L;;;;;N;;;;;\n124E4;CUNEIFORM SIGN LAK-220;Lo;0;L;;;;;N;;;;;\n124E5;CUNEIFORM SIGN LAK-225;Lo;0;L;;;;;N;;;;;\n124E6;CUNEIFORM SIGN LAK-228;Lo;0;L;;;;;N;;;;;\n124E7;CUNEIFORM SIGN LAK-238;Lo;0;L;;;;;N;;;;;\n124E8;CUNEIFORM SIGN LAK-265;Lo;0;L;;;;;N;;;;;\n124E9;CUNEIFORM SIGN LAK-266;Lo;0;L;;;;;N;;;;;\n124EA;CUNEIFORM SIGN LAK-343;Lo;0;L;;;;;N;;;;;\n124EB;CUNEIFORM SIGN LAK-347;Lo;0;L;;;;;N;;;;;\n124EC;CUNEIFORM SIGN LAK-348;Lo;0;L;;;;;N;;;;;\n124ED;CUNEIFORM SIGN LAK-383;Lo;0;L;;;;;N;;;;;\n124EE;CUNEIFORM SIGN LAK-384;Lo;0;L;;;;;N;;;;;\n124EF;CUNEIFORM SIGN LAK-390;Lo;0;L;;;;;N;;;;;\n124F0;CUNEIFORM SIGN LAK-441;Lo;0;L;;;;;N;;;;;\n124F1;CUNEIFORM SIGN LAK-449;Lo;0;L;;;;;N;;;;;\n124F2;CUNEIFORM SIGN LAK-449 TIMES GU;Lo;0;L;;;;;N;;;;;\n124F3;CUNEIFORM SIGN LAK-449 TIMES IGI;Lo;0;L;;;;;N;;;;;\n124F4;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS LU3;Lo;0;L;;;;;N;;;;;\n124F5;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;;\n124F6;CUNEIFORM SIGN LAK-449 TIMES U2 PLUS BA;Lo;0;L;;;;;N;;;;;\n124F7;CUNEIFORM SIGN LAK-450;Lo;0;L;;;;;N;;;;;\n124F8;CUNEIFORM SIGN LAK-457;Lo;0;L;;;;;N;;;;;\n124F9;CUNEIFORM SIGN LAK-470;Lo;0;L;;;;;N;;;;;\n124FA;CUNEIFORM SIGN LAK-483;Lo;0;L;;;;;N;;;;;\n124FB;CUNEIFORM SIGN LAK-490;Lo;0;L;;;;;N;;;;;\n124FC;CUNEIFORM SIGN LAK-492;Lo;0;L;;;;;N;;;;;\n124FD;CUNEIFORM SIGN LAK-493;Lo;0;L;;;;;N;;;;;\n124FE;CUNEIFORM SIGN LAK-495;Lo;0;L;;;;;N;;;;;\n124FF;CUNEIFORM SIGN LAK-550;Lo;0;L;;;;;N;;;;;\n12500;CUNEIFORM SIGN LAK-608;Lo;0;L;;;;;N;;;;;\n12501;CUNEIFORM SIGN LAK-617;Lo;0;L;;;;;N;;;;;\n12502;CUNEIFORM SIGN LAK-617 TIMES ASH;Lo;0;L;;;;;N;;;;;\n12503;CUNEIFORM SIGN LAK-617 TIMES BAD;Lo;0;L;;;;;N;;;;;\n12504;CUNEIFORM SIGN LAK-617 TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;;\n12505;CUNEIFORM SIGN LAK-617 TIMES KU3;Lo;0;L;;;;;N;;;;;\n12506;CUNEIFORM SIGN LAK-617 TIMES LA;Lo;0;L;;;;;N;;;;;\n12507;CUNEIFORM SIGN LAK-617 TIMES TAR;Lo;0;L;;;;;N;;;;;\n12508;CUNEIFORM SIGN LAK-617 TIMES TE;Lo;0;L;;;;;N;;;;;\n12509;CUNEIFORM SIGN LAK-617 TIMES U2;Lo;0;L;;;;;N;;;;;\n1250A;CUNEIFORM SIGN LAK-617 TIMES UD;Lo;0;L;;;;;N;;;;;\n1250B;CUNEIFORM SIGN LAK-617 TIMES URUDA;Lo;0;L;;;;;N;;;;;\n1250C;CUNEIFORM SIGN LAK-636;Lo;0;L;;;;;N;;;;;\n1250D;CUNEIFORM SIGN LAK-648;Lo;0;L;;;;;N;;;;;\n1250E;CUNEIFORM SIGN LAK-648 TIMES DUB;Lo;0;L;;;;;N;;;;;\n1250F;CUNEIFORM SIGN LAK-648 TIMES GA;Lo;0;L;;;;;N;;;;;\n12510;CUNEIFORM SIGN LAK-648 TIMES IGI;Lo;0;L;;;;;N;;;;;\n12511;CUNEIFORM SIGN LAK-648 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;\n12512;CUNEIFORM SIGN LAK-648 TIMES NI;Lo;0;L;;;;;N;;;;;\n12513;CUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;;\n12514;CUNEIFORM SIGN LAK-648 TIMES SHESH PLUS KI;Lo;0;L;;;;;N;;;;;\n12515;CUNEIFORM SIGN LAK-648 TIMES UD;Lo;0;L;;;;;N;;;;;\n12516;CUNEIFORM SIGN LAK-648 TIMES URUDA;Lo;0;L;;;;;N;;;;;\n12517;CUNEIFORM SIGN LAK-724;Lo;0;L;;;;;N;;;;;\n12518;CUNEIFORM SIGN LAK-749;Lo;0;L;;;;;N;;;;;\n12519;CUNEIFORM SIGN LU2 GUNU TIMES ASH;Lo;0;L;;;;;N;;;;;\n1251A;CUNEIFORM SIGN LU2 TIMES DISH;Lo;0;L;;;;;N;;;;;\n1251B;CUNEIFORM SIGN LU2 TIMES HAL;Lo;0;L;;;;;N;;;;;\n1251C;CUNEIFORM SIGN LU2 TIMES PAP;Lo;0;L;;;;;N;;;;;\n1251D;CUNEIFORM SIGN LU2 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;;\n1251E;CUNEIFORM SIGN LU2 TIMES TAK4;Lo;0;L;;;;;N;;;;;\n1251F;CUNEIFORM SIGN MI PLUS ZA7;Lo;0;L;;;;;N;;;;;\n12520;CUNEIFORM SIGN MUSH OVER MUSH TIMES GA;Lo;0;L;;;;;N;;;;;\n12521;CUNEIFORM SIGN MUSH OVER MUSH TIMES KAK;Lo;0;L;;;;;N;;;;;\n12522;CUNEIFORM SIGN NINDA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;;\n12523;CUNEIFORM SIGN NINDA2 TIMES GISH;Lo;0;L;;;;;N;;;;;\n12524;CUNEIFORM SIGN NINDA2 TIMES GUL;Lo;0;L;;;;;N;;;;;\n12525;CUNEIFORM SIGN NINDA2 TIMES HI;Lo;0;L;;;;;N;;;;;\n12526;CUNEIFORM SIGN NINDA2 TIMES KESH2;Lo;0;L;;;;;N;;;;;\n12527;CUNEIFORM SIGN NINDA2 TIMES LAK-050;Lo;0;L;;;;;N;;;;;\n12528;CUNEIFORM SIGN NINDA2 TIMES MASH;Lo;0;L;;;;;N;;;;;\n12529;CUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;;\n1252A;CUNEIFORM SIGN NINDA2 TIMES U;Lo;0;L;;;;;N;;;;;\n1252B;CUNEIFORM SIGN NINDA2 TIMES U PLUS U;Lo;0;L;;;;;N;;;;;\n1252C;CUNEIFORM SIGN NINDA2 TIMES URUDA;Lo;0;L;;;;;N;;;;;\n1252D;CUNEIFORM SIGN SAG GUNU TIMES HA;Lo;0;L;;;;;N;;;;;\n1252E;CUNEIFORM SIGN SAG TIMES EN;Lo;0;L;;;;;N;;;;;\n1252F;CUNEIFORM SIGN SAG TIMES SHE AT LEFT;Lo;0;L;;;;;N;;;;;\n12530;CUNEIFORM SIGN SAG TIMES TAK4;Lo;0;L;;;;;N;;;;;\n12531;CUNEIFORM SIGN SHA6 TENU;Lo;0;L;;;;;N;;;;;\n12532;CUNEIFORM SIGN SHE OVER SHE;Lo;0;L;;;;;N;;;;;\n12533;CUNEIFORM SIGN SHE PLUS HUB2;Lo;0;L;;;;;N;;;;;\n12534;CUNEIFORM SIGN SHE PLUS NAM2;Lo;0;L;;;;;N;;;;;\n12535;CUNEIFORM SIGN SHE PLUS SAR;Lo;0;L;;;;;N;;;;;\n12536;CUNEIFORM SIGN SHU2 PLUS DUG TIMES NI;Lo;0;L;;;;;N;;;;;\n12537;CUNEIFORM SIGN SHU2 PLUS E2 TIMES AN;Lo;0;L;;;;;N;;;;;\n12538;CUNEIFORM SIGN SI TIMES TAK4;Lo;0;L;;;;;N;;;;;\n12539;CUNEIFORM SIGN TAK4 PLUS SAG;Lo;0;L;;;;;N;;;;;\n1253A;CUNEIFORM SIGN TUM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;\n1253B;CUNEIFORM SIGN TUM TIMES THREE DISH;Lo;0;L;;;;;N;;;;;\n1253C;CUNEIFORM SIGN UR2 INVERTED;Lo;0;L;;;;;N;;;;;\n1253D;CUNEIFORM SIGN UR2 TIMES UD;Lo;0;L;;;;;N;;;;;\n1253E;CUNEIFORM SIGN URU TIMES DARA3;Lo;0;L;;;;;N;;;;;\n1253F;CUNEIFORM SIGN URU TIMES LAK-668;Lo;0;L;;;;;N;;;;;\n12540;CUNEIFORM SIGN URU TIMES LU3;Lo;0;L;;;;;N;;;;;\n12541;CUNEIFORM SIGN ZA7;Lo;0;L;;;;;N;;;;;\n12542;CUNEIFORM SIGN ZU OVER ZU PLUS SAR;Lo;0;L;;;;;N;;;;;\n12543;CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU;Lo;0;L;;;;;N;;;;;\n12F90;CYPRO-MINOAN SIGN CM001;Lo;0;L;;;;;N;;;;;\n12F91;CYPRO-MINOAN SIGN CM002;Lo;0;L;;;;;N;;;;;\n12F92;CYPRO-MINOAN SIGN CM004;Lo;0;L;;;;;N;;;;;\n12F93;CYPRO-MINOAN SIGN CM005;Lo;0;L;;;;;N;;;;;\n12F94;CYPRO-MINOAN SIGN CM006;Lo;0;L;;;;;N;;;;;\n12F95;CYPRO-MINOAN SIGN CM007;Lo;0;L;;;;;N;;;;;\n12F96;CYPRO-MINOAN SIGN CM008;Lo;0;L;;;;;N;;;;;\n12F97;CYPRO-MINOAN SIGN CM009;Lo;0;L;;;;;N;;;;;\n12F98;CYPRO-MINOAN SIGN CM010;Lo;0;L;;;;;N;;;;;\n12F99;CYPRO-MINOAN SIGN CM011;Lo;0;L;;;;;N;;;;;\n12F9A;CYPRO-MINOAN SIGN CM012;Lo;0;L;;;;;N;;;;;\n12F9B;CYPRO-MINOAN SIGN CM012B;Lo;0;L;;;;;N;;;;;\n12F9C;CYPRO-MINOAN SIGN CM013;Lo;0;L;;;;;N;;;;;\n12F9D;CYPRO-MINOAN SIGN CM015;Lo;0;L;;;;;N;;;;;\n12F9E;CYPRO-MINOAN SIGN CM017;Lo;0;L;;;;;N;;;;;\n12F9F;CYPRO-MINOAN SIGN CM019;Lo;0;L;;;;;N;;;;;\n12FA0;CYPRO-MINOAN SIGN CM021;Lo;0;L;;;;;N;;;;;\n12FA1;CYPRO-MINOAN SIGN CM023;Lo;0;L;;;;;N;;;;;\n12FA2;CYPRO-MINOAN SIGN CM024;Lo;0;L;;;;;N;;;;;\n12FA3;CYPRO-MINOAN SIGN CM025;Lo;0;L;;;;;N;;;;;\n12FA4;CYPRO-MINOAN SIGN CM026;Lo;0;L;;;;;N;;;;;\n12FA5;CYPRO-MINOAN SIGN CM027;Lo;0;L;;;;;N;;;;;\n12FA6;CYPRO-MINOAN SIGN CM028;Lo;0;L;;;;;N;;;;;\n12FA7;CYPRO-MINOAN SIGN CM029;Lo;0;L;;;;;N;;;;;\n12FA8;CYPRO-MINOAN SIGN CM030;Lo;0;L;;;;;N;;;;;\n12FA9;CYPRO-MINOAN SIGN CM033;Lo;0;L;;;;;N;;;;;\n12FAA;CYPRO-MINOAN SIGN CM034;Lo;0;L;;;;;N;;;;;\n12FAB;CYPRO-MINOAN SIGN CM035;Lo;0;L;;;;;N;;;;;\n12FAC;CYPRO-MINOAN SIGN CM036;Lo;0;L;;;;;N;;;;;\n12FAD;CYPRO-MINOAN SIGN CM037;Lo;0;L;;;;;N;;;;;\n12FAE;CYPRO-MINOAN SIGN CM038;Lo;0;L;;;;;N;;;;;\n12FAF;CYPRO-MINOAN SIGN CM039;Lo;0;L;;;;;N;;;;;\n12FB0;CYPRO-MINOAN SIGN CM040;Lo;0;L;;;;;N;;;;;\n12FB1;CYPRO-MINOAN SIGN CM041;Lo;0;L;;;;;N;;;;;\n12FB2;CYPRO-MINOAN SIGN CM044;Lo;0;L;;;;;N;;;;;\n12FB3;CYPRO-MINOAN SIGN CM046;Lo;0;L;;;;;N;;;;;\n12FB4;CYPRO-MINOAN SIGN CM047;Lo;0;L;;;;;N;;;;;\n12FB5;CYPRO-MINOAN SIGN CM049;Lo;0;L;;;;;N;;;;;\n12FB6;CYPRO-MINOAN SIGN CM050;Lo;0;L;;;;;N;;;;;\n12FB7;CYPRO-MINOAN SIGN CM051;Lo;0;L;;;;;N;;;;;\n12FB8;CYPRO-MINOAN SIGN CM052;Lo;0;L;;;;;N;;;;;\n12FB9;CYPRO-MINOAN SIGN CM053;Lo;0;L;;;;;N;;;;;\n12FBA;CYPRO-MINOAN SIGN CM054;Lo;0;L;;;;;N;;;;;\n12FBB;CYPRO-MINOAN SIGN CM055;Lo;0;L;;;;;N;;;;;\n12FBC;CYPRO-MINOAN SIGN CM056;Lo;0;L;;;;;N;;;;;\n12FBD;CYPRO-MINOAN SIGN CM058;Lo;0;L;;;;;N;;;;;\n12FBE;CYPRO-MINOAN SIGN CM059;Lo;0;L;;;;;N;;;;;\n12FBF;CYPRO-MINOAN SIGN CM060;Lo;0;L;;;;;N;;;;;\n12FC0;CYPRO-MINOAN SIGN CM061;Lo;0;L;;;;;N;;;;;\n12FC1;CYPRO-MINOAN SIGN CM062;Lo;0;L;;;;;N;;;;;\n12FC2;CYPRO-MINOAN SIGN CM063;Lo;0;L;;;;;N;;;;;\n12FC3;CYPRO-MINOAN SIGN CM064;Lo;0;L;;;;;N;;;;;\n12FC4;CYPRO-MINOAN SIGN CM066;Lo;0;L;;;;;N;;;;;\n12FC5;CYPRO-MINOAN SIGN CM067;Lo;0;L;;;;;N;;;;;\n12FC6;CYPRO-MINOAN SIGN CM068;Lo;0;L;;;;;N;;;;;\n12FC7;CYPRO-MINOAN SIGN CM069;Lo;0;L;;;;;N;;;;;\n12FC8;CYPRO-MINOAN SIGN CM070;Lo;0;L;;;;;N;;;;;\n12FC9;CYPRO-MINOAN SIGN CM071;Lo;0;L;;;;;N;;;;;\n12FCA;CYPRO-MINOAN SIGN CM072;Lo;0;L;;;;;N;;;;;\n12FCB;CYPRO-MINOAN SIGN CM073;Lo;0;L;;;;;N;;;;;\n12FCC;CYPRO-MINOAN SIGN CM074;Lo;0;L;;;;;N;;;;;\n12FCD;CYPRO-MINOAN SIGN CM075;Lo;0;L;;;;;N;;;;;\n12FCE;CYPRO-MINOAN SIGN CM075B;Lo;0;L;;;;;N;;;;;\n12FCF;CYPRO-MINOAN SIGN CM076;Lo;0;L;;;;;N;;;;;\n12FD0;CYPRO-MINOAN SIGN CM078;Lo;0;L;;;;;N;;;;;\n12FD1;CYPRO-MINOAN SIGN CM079;Lo;0;L;;;;;N;;;;;\n12FD2;CYPRO-MINOAN SIGN CM080;Lo;0;L;;;;;N;;;;;\n12FD3;CYPRO-MINOAN SIGN CM081;Lo;0;L;;;;;N;;;;;\n12FD4;CYPRO-MINOAN SIGN CM082;Lo;0;L;;;;;N;;;;;\n12FD5;CYPRO-MINOAN SIGN CM083;Lo;0;L;;;;;N;;;;;\n12FD6;CYPRO-MINOAN SIGN CM084;Lo;0;L;;;;;N;;;;;\n12FD7;CYPRO-MINOAN SIGN CM085;Lo;0;L;;;;;N;;;;;\n12FD8;CYPRO-MINOAN SIGN CM086;Lo;0;L;;;;;N;;;;;\n12FD9;CYPRO-MINOAN SIGN CM087;Lo;0;L;;;;;N;;;;;\n12FDA;CYPRO-MINOAN SIGN CM088;Lo;0;L;;;;;N;;;;;\n12FDB;CYPRO-MINOAN SIGN CM089;Lo;0;L;;;;;N;;;;;\n12FDC;CYPRO-MINOAN SIGN CM090;Lo;0;L;;;;;N;;;;;\n12FDD;CYPRO-MINOAN SIGN CM091;Lo;0;L;;;;;N;;;;;\n12FDE;CYPRO-MINOAN SIGN CM092;Lo;0;L;;;;;N;;;;;\n12FDF;CYPRO-MINOAN SIGN CM094;Lo;0;L;;;;;N;;;;;\n12FE0;CYPRO-MINOAN SIGN CM095;Lo;0;L;;;;;N;;;;;\n12FE1;CYPRO-MINOAN SIGN CM096;Lo;0;L;;;;;N;;;;;\n12FE2;CYPRO-MINOAN SIGN CM097;Lo;0;L;;;;;N;;;;;\n12FE3;CYPRO-MINOAN SIGN CM098;Lo;0;L;;;;;N;;;;;\n12FE4;CYPRO-MINOAN SIGN CM099;Lo;0;L;;;;;N;;;;;\n12FE5;CYPRO-MINOAN SIGN CM100;Lo;0;L;;;;;N;;;;;\n12FE6;CYPRO-MINOAN SIGN CM101;Lo;0;L;;;;;N;;;;;\n12FE7;CYPRO-MINOAN SIGN CM102;Lo;0;L;;;;;N;;;;;\n12FE8;CYPRO-MINOAN SIGN CM103;Lo;0;L;;;;;N;;;;;\n12FE9;CYPRO-MINOAN SIGN CM104;Lo;0;L;;;;;N;;;;;\n12FEA;CYPRO-MINOAN SIGN CM105;Lo;0;L;;;;;N;;;;;\n12FEB;CYPRO-MINOAN SIGN CM107;Lo;0;L;;;;;N;;;;;\n12FEC;CYPRO-MINOAN SIGN CM108;Lo;0;L;;;;;N;;;;;\n12FED;CYPRO-MINOAN SIGN CM109;Lo;0;L;;;;;N;;;;;\n12FEE;CYPRO-MINOAN SIGN CM110;Lo;0;L;;;;;N;;;;;\n12FEF;CYPRO-MINOAN SIGN CM112;Lo;0;L;;;;;N;;;;;\n12FF0;CYPRO-MINOAN SIGN CM114;Lo;0;L;;;;;N;;;;;\n12FF1;CYPRO-MINOAN SIGN CM301;Po;0;L;;;;;N;;;;;\n12FF2;CYPRO-MINOAN SIGN CM302;Po;0;L;;;;;N;;;;;\n13000;EGYPTIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;;\n13001;EGYPTIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;;\n13002;EGYPTIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;;\n13003;EGYPTIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;;\n13004;EGYPTIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;;\n13005;EGYPTIAN HIEROGLYPH A005A;Lo;0;L;;;;;N;;;;;\n13006;EGYPTIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;;\n13007;EGYPTIAN HIEROGLYPH A006A;Lo;0;L;;;;;N;;;;;\n13008;EGYPTIAN HIEROGLYPH A006B;Lo;0;L;;;;;N;;;;;\n13009;EGYPTIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;;\n1300A;EGYPTIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;;\n1300B;EGYPTIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;;\n1300C;EGYPTIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;;\n1300D;EGYPTIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;;\n1300E;EGYPTIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;;\n1300F;EGYPTIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;;\n13010;EGYPTIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;;\n13011;EGYPTIAN HIEROGLYPH A014A;Lo;0;L;;;;;N;;;;;\n13012;EGYPTIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;;\n13013;EGYPTIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;;\n13014;EGYPTIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;;\n13015;EGYPTIAN HIEROGLYPH A017A;Lo;0;L;;;;;N;;;;;\n13016;EGYPTIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;;\n13017;EGYPTIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;;\n13018;EGYPTIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;;\n13019;EGYPTIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;;\n1301A;EGYPTIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;;\n1301B;EGYPTIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;;\n1301C;EGYPTIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;;\n1301D;EGYPTIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;;\n1301E;EGYPTIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;;\n1301F;EGYPTIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;;\n13020;EGYPTIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;;\n13021;EGYPTIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;;\n13022;EGYPTIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;;\n13023;EGYPTIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;;\n13024;EGYPTIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;;\n13025;EGYPTIAN HIEROGLYPH A032A;Lo;0;L;;;;;N;;;;;\n13026;EGYPTIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;;\n13027;EGYPTIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;;\n13028;EGYPTIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;;\n13029;EGYPTIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;;\n1302A;EGYPTIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;;\n1302B;EGYPTIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;;\n1302C;EGYPTIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;;\n1302D;EGYPTIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;;\n1302E;EGYPTIAN HIEROGLYPH A040A;Lo;0;L;;;;;N;;;;;\n1302F;EGYPTIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;;\n13030;EGYPTIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;;\n13031;EGYPTIAN HIEROGLYPH A042A;Lo;0;L;;;;;N;;;;;\n13032;EGYPTIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;;\n13033;EGYPTIAN HIEROGLYPH A043A;Lo;0;L;;;;;N;;;;;\n13034;EGYPTIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;;\n13035;EGYPTIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;;\n13036;EGYPTIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;;\n13037;EGYPTIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;;\n13038;EGYPTIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;;\n13039;EGYPTIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;;\n1303A;EGYPTIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;;\n1303B;EGYPTIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;;\n1303C;EGYPTIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;;\n1303D;EGYPTIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;;\n1303E;EGYPTIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;;\n1303F;EGYPTIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;;\n13040;EGYPTIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;;\n13041;EGYPTIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;;\n13042;EGYPTIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;;\n13043;EGYPTIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;;\n13044;EGYPTIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;;\n13045;EGYPTIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;;\n13046;EGYPTIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;;\n13047;EGYPTIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;;\n13048;EGYPTIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;;\n13049;EGYPTIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;;\n1304A;EGYPTIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;;\n1304B;EGYPTIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;;\n1304C;EGYPTIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;;\n1304D;EGYPTIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;;\n1304E;EGYPTIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;;\n1304F;EGYPTIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;;\n13050;EGYPTIAN HIEROGLYPH B001;Lo;0;L;;;;;N;;;;;\n13051;EGYPTIAN HIEROGLYPH B002;Lo;0;L;;;;;N;;;;;\n13052;EGYPTIAN HIEROGLYPH B003;Lo;0;L;;;;;N;;;;;\n13053;EGYPTIAN HIEROGLYPH B004;Lo;0;L;;;;;N;;;;;\n13054;EGYPTIAN HIEROGLYPH B005;Lo;0;L;;;;;N;;;;;\n13055;EGYPTIAN HIEROGLYPH B005A;Lo;0;L;;;;;N;;;;;\n13056;EGYPTIAN HIEROGLYPH B006;Lo;0;L;;;;;N;;;;;\n13057;EGYPTIAN HIEROGLYPH B007;Lo;0;L;;;;;N;;;;;\n13058;EGYPTIAN HIEROGLYPH B008;Lo;0;L;;;;;N;;;;;\n13059;EGYPTIAN HIEROGLYPH B009;Lo;0;L;;;;;N;;;;;\n1305A;EGYPTIAN HIEROGLYPH C001;Lo;0;L;;;;;N;;;;;\n1305B;EGYPTIAN HIEROGLYPH C002;Lo;0;L;;;;;N;;;;;\n1305C;EGYPTIAN HIEROGLYPH C002A;Lo;0;L;;;;;N;;;;;\n1305D;EGYPTIAN HIEROGLYPH C002B;Lo;0;L;;;;;N;;;;;\n1305E;EGYPTIAN HIEROGLYPH C002C;Lo;0;L;;;;;N;;;;;\n1305F;EGYPTIAN HIEROGLYPH C003;Lo;0;L;;;;;N;;;;;\n13060;EGYPTIAN HIEROGLYPH C004;Lo;0;L;;;;;N;;;;;\n13061;EGYPTIAN HIEROGLYPH C005;Lo;0;L;;;;;N;;;;;\n13062;EGYPTIAN HIEROGLYPH C006;Lo;0;L;;;;;N;;;;;\n13063;EGYPTIAN HIEROGLYPH C007;Lo;0;L;;;;;N;;;;;\n13064;EGYPTIAN HIEROGLYPH C008;Lo;0;L;;;;;N;;;;;\n13065;EGYPTIAN HIEROGLYPH C009;Lo;0;L;;;;;N;;;;;\n13066;EGYPTIAN HIEROGLYPH C010;Lo;0;L;;;;;N;;;;;\n13067;EGYPTIAN HIEROGLYPH C010A;Lo;0;L;;;;;N;;;;;\n13068;EGYPTIAN HIEROGLYPH C011;Lo;0;L;;;;;N;;;;;\n13069;EGYPTIAN HIEROGLYPH C012;Lo;0;L;;;;;N;;;;;\n1306A;EGYPTIAN HIEROGLYPH C013;Lo;0;L;;;;;N;;;;;\n1306B;EGYPTIAN HIEROGLYPH C014;Lo;0;L;;;;;N;;;;;\n1306C;EGYPTIAN HIEROGLYPH C015;Lo;0;L;;;;;N;;;;;\n1306D;EGYPTIAN HIEROGLYPH C016;Lo;0;L;;;;;N;;;;;\n1306E;EGYPTIAN HIEROGLYPH C017;Lo;0;L;;;;;N;;;;;\n1306F;EGYPTIAN HIEROGLYPH C018;Lo;0;L;;;;;N;;;;;\n13070;EGYPTIAN HIEROGLYPH C019;Lo;0;L;;;;;N;;;;;\n13071;EGYPTIAN HIEROGLYPH C020;Lo;0;L;;;;;N;;;;;\n13072;EGYPTIAN HIEROGLYPH C021;Lo;0;L;;;;;N;;;;;\n13073;EGYPTIAN HIEROGLYPH C022;Lo;0;L;;;;;N;;;;;\n13074;EGYPTIAN HIEROGLYPH C023;Lo;0;L;;;;;N;;;;;\n13075;EGYPTIAN HIEROGLYPH C024;Lo;0;L;;;;;N;;;;;\n13076;EGYPTIAN HIEROGLYPH D001;Lo;0;L;;;;;N;;;;;\n13077;EGYPTIAN HIEROGLYPH D002;Lo;0;L;;;;;N;;;;;\n13078;EGYPTIAN HIEROGLYPH D003;Lo;0;L;;;;;N;;;;;\n13079;EGYPTIAN HIEROGLYPH D004;Lo;0;L;;;;;N;;;;;\n1307A;EGYPTIAN HIEROGLYPH D005;Lo;0;L;;;;;N;;;;;\n1307B;EGYPTIAN HIEROGLYPH D006;Lo;0;L;;;;;N;;;;;\n1307C;EGYPTIAN HIEROGLYPH D007;Lo;0;L;;;;;N;;;;;\n1307D;EGYPTIAN HIEROGLYPH D008;Lo;0;L;;;;;N;;;;;\n1307E;EGYPTIAN HIEROGLYPH D008A;Lo;0;L;;;;;N;;;;;\n1307F;EGYPTIAN HIEROGLYPH D009;Lo;0;L;;;;;N;;;;;\n13080;EGYPTIAN HIEROGLYPH D010;Lo;0;L;;;;;N;;;;;\n13081;EGYPTIAN HIEROGLYPH D011;Lo;0;L;;;;;N;;;;;\n13082;EGYPTIAN HIEROGLYPH D012;Lo;0;L;;;;;N;;;;;\n13083;EGYPTIAN HIEROGLYPH D013;Lo;0;L;;;;;N;;;;;\n13084;EGYPTIAN HIEROGLYPH D014;Lo;0;L;;;;;N;;;;;\n13085;EGYPTIAN HIEROGLYPH D015;Lo;0;L;;;;;N;;;;;\n13086;EGYPTIAN HIEROGLYPH D016;Lo;0;L;;;;;N;;;;;\n13087;EGYPTIAN HIEROGLYPH D017;Lo;0;L;;;;;N;;;;;\n13088;EGYPTIAN HIEROGLYPH D018;Lo;0;L;;;;;N;;;;;\n13089;EGYPTIAN HIEROGLYPH D019;Lo;0;L;;;;;N;;;;;\n1308A;EGYPTIAN HIEROGLYPH D020;Lo;0;L;;;;;N;;;;;\n1308B;EGYPTIAN HIEROGLYPH D021;Lo;0;L;;;;;N;;;;;\n1308C;EGYPTIAN HIEROGLYPH D022;Lo;0;L;;;;;N;;;;;\n1308D;EGYPTIAN HIEROGLYPH D023;Lo;0;L;;;;;N;;;;;\n1308E;EGYPTIAN HIEROGLYPH D024;Lo;0;L;;;;;N;;;;;\n1308F;EGYPTIAN HIEROGLYPH D025;Lo;0;L;;;;;N;;;;;\n13090;EGYPTIAN HIEROGLYPH D026;Lo;0;L;;;;;N;;;;;\n13091;EGYPTIAN HIEROGLYPH D027;Lo;0;L;;;;;N;;;;;\n13092;EGYPTIAN HIEROGLYPH D027A;Lo;0;L;;;;;N;;;;;\n13093;EGYPTIAN HIEROGLYPH D028;Lo;0;L;;;;;N;;;;;\n13094;EGYPTIAN HIEROGLYPH D029;Lo;0;L;;;;;N;;;;;\n13095;EGYPTIAN HIEROGLYPH D030;Lo;0;L;;;;;N;;;;;\n13096;EGYPTIAN HIEROGLYPH D031;Lo;0;L;;;;;N;;;;;\n13097;EGYPTIAN HIEROGLYPH D031A;Lo;0;L;;;;;N;;;;;\n13098;EGYPTIAN HIEROGLYPH D032;Lo;0;L;;;;;N;;;;;\n13099;EGYPTIAN HIEROGLYPH D033;Lo;0;L;;;;;N;;;;;\n1309A;EGYPTIAN HIEROGLYPH D034;Lo;0;L;;;;;N;;;;;\n1309B;EGYPTIAN HIEROGLYPH D034A;Lo;0;L;;;;;N;;;;;\n1309C;EGYPTIAN HIEROGLYPH D035;Lo;0;L;;;;;N;;;;;\n1309D;EGYPTIAN HIEROGLYPH D036;Lo;0;L;;;;;N;;;;;\n1309E;EGYPTIAN HIEROGLYPH D037;Lo;0;L;;;;;N;;;;;\n1309F;EGYPTIAN HIEROGLYPH D038;Lo;0;L;;;;;N;;;;;\n130A0;EGYPTIAN HIEROGLYPH D039;Lo;0;L;;;;;N;;;;;\n130A1;EGYPTIAN HIEROGLYPH D040;Lo;0;L;;;;;N;;;;;\n130A2;EGYPTIAN HIEROGLYPH D041;Lo;0;L;;;;;N;;;;;\n130A3;EGYPTIAN HIEROGLYPH D042;Lo;0;L;;;;;N;;;;;\n130A4;EGYPTIAN HIEROGLYPH D043;Lo;0;L;;;;;N;;;;;\n130A5;EGYPTIAN HIEROGLYPH D044;Lo;0;L;;;;;N;;;;;\n130A6;EGYPTIAN HIEROGLYPH D045;Lo;0;L;;;;;N;;;;;\n130A7;EGYPTIAN HIEROGLYPH D046;Lo;0;L;;;;;N;;;;;\n130A8;EGYPTIAN HIEROGLYPH D046A;Lo;0;L;;;;;N;;;;;\n130A9;EGYPTIAN HIEROGLYPH D047;Lo;0;L;;;;;N;;;;;\n130AA;EGYPTIAN HIEROGLYPH D048;Lo;0;L;;;;;N;;;;;\n130AB;EGYPTIAN HIEROGLYPH D048A;Lo;0;L;;;;;N;;;;;\n130AC;EGYPTIAN HIEROGLYPH D049;Lo;0;L;;;;;N;;;;;\n130AD;EGYPTIAN HIEROGLYPH D050;Lo;0;L;;;;;N;;;;;\n130AE;EGYPTIAN HIEROGLYPH D050A;Lo;0;L;;;;;N;;;;;\n130AF;EGYPTIAN HIEROGLYPH D050B;Lo;0;L;;;;;N;;;;;\n130B0;EGYPTIAN HIEROGLYPH D050C;Lo;0;L;;;;;N;;;;;\n130B1;EGYPTIAN HIEROGLYPH D050D;Lo;0;L;;;;;N;;;;;\n130B2;EGYPTIAN HIEROGLYPH D050E;Lo;0;L;;;;;N;;;;;\n130B3;EGYPTIAN HIEROGLYPH D050F;Lo;0;L;;;;;N;;;;;\n130B4;EGYPTIAN HIEROGLYPH D050G;Lo;0;L;;;;;N;;;;;\n130B5;EGYPTIAN HIEROGLYPH D050H;Lo;0;L;;;;;N;;;;;\n130B6;EGYPTIAN HIEROGLYPH D050I;Lo;0;L;;;;;N;;;;;\n130B7;EGYPTIAN HIEROGLYPH D051;Lo;0;L;;;;;N;;;;;\n130B8;EGYPTIAN HIEROGLYPH D052;Lo;0;L;;;;;N;;;;;\n130B9;EGYPTIAN HIEROGLYPH D052A;Lo;0;L;;;;;N;;;;;\n130BA;EGYPTIAN HIEROGLYPH D053;Lo;0;L;;;;;N;;;;;\n130BB;EGYPTIAN HIEROGLYPH D054;Lo;0;L;;;;;N;;;;;\n130BC;EGYPTIAN HIEROGLYPH D054A;Lo;0;L;;;;;N;;;;;\n130BD;EGYPTIAN HIEROGLYPH D055;Lo;0;L;;;;;N;;;;;\n130BE;EGYPTIAN HIEROGLYPH D056;Lo;0;L;;;;;N;;;;;\n130BF;EGYPTIAN HIEROGLYPH D057;Lo;0;L;;;;;N;;;;;\n130C0;EGYPTIAN HIEROGLYPH D058;Lo;0;L;;;;;N;;;;;\n130C1;EGYPTIAN HIEROGLYPH D059;Lo;0;L;;;;;N;;;;;\n130C2;EGYPTIAN HIEROGLYPH D060;Lo;0;L;;;;;N;;;;;\n130C3;EGYPTIAN HIEROGLYPH D061;Lo;0;L;;;;;N;;;;;\n130C4;EGYPTIAN HIEROGLYPH D062;Lo;0;L;;;;;N;;;;;\n130C5;EGYPTIAN HIEROGLYPH D063;Lo;0;L;;;;;N;;;;;\n130C6;EGYPTIAN HIEROGLYPH D064;Lo;0;L;;;;;N;;;;;\n130C7;EGYPTIAN HIEROGLYPH D065;Lo;0;L;;;;;N;;;;;\n130C8;EGYPTIAN HIEROGLYPH D066;Lo;0;L;;;;;N;;;;;\n130C9;EGYPTIAN HIEROGLYPH D067;Lo;0;L;;;;;N;;;;;\n130CA;EGYPTIAN HIEROGLYPH D067A;Lo;0;L;;;;;N;;;;;\n130CB;EGYPTIAN HIEROGLYPH D067B;Lo;0;L;;;;;N;;;;;\n130CC;EGYPTIAN HIEROGLYPH D067C;Lo;0;L;;;;;N;;;;;\n130CD;EGYPTIAN HIEROGLYPH D067D;Lo;0;L;;;;;N;;;;;\n130CE;EGYPTIAN HIEROGLYPH D067E;Lo;0;L;;;;;N;;;;;\n130CF;EGYPTIAN HIEROGLYPH D067F;Lo;0;L;;;;;N;;;;;\n130D0;EGYPTIAN HIEROGLYPH D067G;Lo;0;L;;;;;N;;;;;\n130D1;EGYPTIAN HIEROGLYPH D067H;Lo;0;L;;;;;N;;;;;\n130D2;EGYPTIAN HIEROGLYPH E001;Lo;0;L;;;;;N;;;;;\n130D3;EGYPTIAN HIEROGLYPH E002;Lo;0;L;;;;;N;;;;;\n130D4;EGYPTIAN HIEROGLYPH E003;Lo;0;L;;;;;N;;;;;\n130D5;EGYPTIAN HIEROGLYPH E004;Lo;0;L;;;;;N;;;;;\n130D6;EGYPTIAN HIEROGLYPH E005;Lo;0;L;;;;;N;;;;;\n130D7;EGYPTIAN HIEROGLYPH E006;Lo;0;L;;;;;N;;;;;\n130D8;EGYPTIAN HIEROGLYPH E007;Lo;0;L;;;;;N;;;;;\n130D9;EGYPTIAN HIEROGLYPH E008;Lo;0;L;;;;;N;;;;;\n130DA;EGYPTIAN HIEROGLYPH E008A;Lo;0;L;;;;;N;;;;;\n130DB;EGYPTIAN HIEROGLYPH E009;Lo;0;L;;;;;N;;;;;\n130DC;EGYPTIAN HIEROGLYPH E009A;Lo;0;L;;;;;N;;;;;\n130DD;EGYPTIAN HIEROGLYPH E010;Lo;0;L;;;;;N;;;;;\n130DE;EGYPTIAN HIEROGLYPH E011;Lo;0;L;;;;;N;;;;;\n130DF;EGYPTIAN HIEROGLYPH E012;Lo;0;L;;;;;N;;;;;\n130E0;EGYPTIAN HIEROGLYPH E013;Lo;0;L;;;;;N;;;;;\n130E1;EGYPTIAN HIEROGLYPH E014;Lo;0;L;;;;;N;;;;;\n130E2;EGYPTIAN HIEROGLYPH E015;Lo;0;L;;;;;N;;;;;\n130E3;EGYPTIAN HIEROGLYPH E016;Lo;0;L;;;;;N;;;;;\n130E4;EGYPTIAN HIEROGLYPH E016A;Lo;0;L;;;;;N;;;;;\n130E5;EGYPTIAN HIEROGLYPH E017;Lo;0;L;;;;;N;;;;;\n130E6;EGYPTIAN HIEROGLYPH E017A;Lo;0;L;;;;;N;;;;;\n130E7;EGYPTIAN HIEROGLYPH E018;Lo;0;L;;;;;N;;;;;\n130E8;EGYPTIAN HIEROGLYPH E019;Lo;0;L;;;;;N;;;;;\n130E9;EGYPTIAN HIEROGLYPH E020;Lo;0;L;;;;;N;;;;;\n130EA;EGYPTIAN HIEROGLYPH E020A;Lo;0;L;;;;;N;;;;;\n130EB;EGYPTIAN HIEROGLYPH E021;Lo;0;L;;;;;N;;;;;\n130EC;EGYPTIAN HIEROGLYPH E022;Lo;0;L;;;;;N;;;;;\n130ED;EGYPTIAN HIEROGLYPH E023;Lo;0;L;;;;;N;;;;;\n130EE;EGYPTIAN HIEROGLYPH E024;Lo;0;L;;;;;N;;;;;\n130EF;EGYPTIAN HIEROGLYPH E025;Lo;0;L;;;;;N;;;;;\n130F0;EGYPTIAN HIEROGLYPH E026;Lo;0;L;;;;;N;;;;;\n130F1;EGYPTIAN HIEROGLYPH E027;Lo;0;L;;;;;N;;;;;\n130F2;EGYPTIAN HIEROGLYPH E028;Lo;0;L;;;;;N;;;;;\n130F3;EGYPTIAN HIEROGLYPH E028A;Lo;0;L;;;;;N;;;;;\n130F4;EGYPTIAN HIEROGLYPH E029;Lo;0;L;;;;;N;;;;;\n130F5;EGYPTIAN HIEROGLYPH E030;Lo;0;L;;;;;N;;;;;\n130F6;EGYPTIAN HIEROGLYPH E031;Lo;0;L;;;;;N;;;;;\n130F7;EGYPTIAN HIEROGLYPH E032;Lo;0;L;;;;;N;;;;;\n130F8;EGYPTIAN HIEROGLYPH E033;Lo;0;L;;;;;N;;;;;\n130F9;EGYPTIAN HIEROGLYPH E034;Lo;0;L;;;;;N;;;;;\n130FA;EGYPTIAN HIEROGLYPH E034A;Lo;0;L;;;;;N;;;;;\n130FB;EGYPTIAN HIEROGLYPH E036;Lo;0;L;;;;;N;;;;;\n130FC;EGYPTIAN HIEROGLYPH E037;Lo;0;L;;;;;N;;;;;\n130FD;EGYPTIAN HIEROGLYPH E038;Lo;0;L;;;;;N;;;;;\n130FE;EGYPTIAN HIEROGLYPH F001;Lo;0;L;;;;;N;;;;;\n130FF;EGYPTIAN HIEROGLYPH F001A;Lo;0;L;;;;;N;;;;;\n13100;EGYPTIAN HIEROGLYPH F002;Lo;0;L;;;;;N;;;;;\n13101;EGYPTIAN HIEROGLYPH F003;Lo;0;L;;;;;N;;;;;\n13102;EGYPTIAN HIEROGLYPH F004;Lo;0;L;;;;;N;;;;;\n13103;EGYPTIAN HIEROGLYPH F005;Lo;0;L;;;;;N;;;;;\n13104;EGYPTIAN HIEROGLYPH F006;Lo;0;L;;;;;N;;;;;\n13105;EGYPTIAN HIEROGLYPH F007;Lo;0;L;;;;;N;;;;;\n13106;EGYPTIAN HIEROGLYPH F008;Lo;0;L;;;;;N;;;;;\n13107;EGYPTIAN HIEROGLYPH F009;Lo;0;L;;;;;N;;;;;\n13108;EGYPTIAN HIEROGLYPH F010;Lo;0;L;;;;;N;;;;;\n13109;EGYPTIAN HIEROGLYPH F011;Lo;0;L;;;;;N;;;;;\n1310A;EGYPTIAN HIEROGLYPH F012;Lo;0;L;;;;;N;;;;;\n1310B;EGYPTIAN HIEROGLYPH F013;Lo;0;L;;;;;N;;;;;\n1310C;EGYPTIAN HIEROGLYPH F013A;Lo;0;L;;;;;N;;;;;\n1310D;EGYPTIAN HIEROGLYPH F014;Lo;0;L;;;;;N;;;;;\n1310E;EGYPTIAN HIEROGLYPH F015;Lo;0;L;;;;;N;;;;;\n1310F;EGYPTIAN HIEROGLYPH F016;Lo;0;L;;;;;N;;;;;\n13110;EGYPTIAN HIEROGLYPH F017;Lo;0;L;;;;;N;;;;;\n13111;EGYPTIAN HIEROGLYPH F018;Lo;0;L;;;;;N;;;;;\n13112;EGYPTIAN HIEROGLYPH F019;Lo;0;L;;;;;N;;;;;\n13113;EGYPTIAN HIEROGLYPH F020;Lo;0;L;;;;;N;;;;;\n13114;EGYPTIAN HIEROGLYPH F021;Lo;0;L;;;;;N;;;;;\n13115;EGYPTIAN HIEROGLYPH F021A;Lo;0;L;;;;;N;;;;;\n13116;EGYPTIAN HIEROGLYPH F022;Lo;0;L;;;;;N;;;;;\n13117;EGYPTIAN HIEROGLYPH F023;Lo;0;L;;;;;N;;;;;\n13118;EGYPTIAN HIEROGLYPH F024;Lo;0;L;;;;;N;;;;;\n13119;EGYPTIAN HIEROGLYPH F025;Lo;0;L;;;;;N;;;;;\n1311A;EGYPTIAN HIEROGLYPH F026;Lo;0;L;;;;;N;;;;;\n1311B;EGYPTIAN HIEROGLYPH F027;Lo;0;L;;;;;N;;;;;\n1311C;EGYPTIAN HIEROGLYPH F028;Lo;0;L;;;;;N;;;;;\n1311D;EGYPTIAN HIEROGLYPH F029;Lo;0;L;;;;;N;;;;;\n1311E;EGYPTIAN HIEROGLYPH F030;Lo;0;L;;;;;N;;;;;\n1311F;EGYPTIAN HIEROGLYPH F031;Lo;0;L;;;;;N;;;;;\n13120;EGYPTIAN HIEROGLYPH F031A;Lo;0;L;;;;;N;;;;;\n13121;EGYPTIAN HIEROGLYPH F032;Lo;0;L;;;;;N;;;;;\n13122;EGYPTIAN HIEROGLYPH F033;Lo;0;L;;;;;N;;;;;\n13123;EGYPTIAN HIEROGLYPH F034;Lo;0;L;;;;;N;;;;;\n13124;EGYPTIAN HIEROGLYPH F035;Lo;0;L;;;;;N;;;;;\n13125;EGYPTIAN HIEROGLYPH F036;Lo;0;L;;;;;N;;;;;\n13126;EGYPTIAN HIEROGLYPH F037;Lo;0;L;;;;;N;;;;;\n13127;EGYPTIAN HIEROGLYPH F037A;Lo;0;L;;;;;N;;;;;\n13128;EGYPTIAN HIEROGLYPH F038;Lo;0;L;;;;;N;;;;;\n13129;EGYPTIAN HIEROGLYPH F038A;Lo;0;L;;;;;N;;;;;\n1312A;EGYPTIAN HIEROGLYPH F039;Lo;0;L;;;;;N;;;;;\n1312B;EGYPTIAN HIEROGLYPH F040;Lo;0;L;;;;;N;;;;;\n1312C;EGYPTIAN HIEROGLYPH F041;Lo;0;L;;;;;N;;;;;\n1312D;EGYPTIAN HIEROGLYPH F042;Lo;0;L;;;;;N;;;;;\n1312E;EGYPTIAN HIEROGLYPH F043;Lo;0;L;;;;;N;;;;;\n1312F;EGYPTIAN HIEROGLYPH F044;Lo;0;L;;;;;N;;;;;\n13130;EGYPTIAN HIEROGLYPH F045;Lo;0;L;;;;;N;;;;;\n13131;EGYPTIAN HIEROGLYPH F045A;Lo;0;L;;;;;N;;;;;\n13132;EGYPTIAN HIEROGLYPH F046;Lo;0;L;;;;;N;;;;;\n13133;EGYPTIAN HIEROGLYPH F046A;Lo;0;L;;;;;N;;;;;\n13134;EGYPTIAN HIEROGLYPH F047;Lo;0;L;;;;;N;;;;;\n13135;EGYPTIAN HIEROGLYPH F047A;Lo;0;L;;;;;N;;;;;\n13136;EGYPTIAN HIEROGLYPH F048;Lo;0;L;;;;;N;;;;;\n13137;EGYPTIAN HIEROGLYPH F049;Lo;0;L;;;;;N;;;;;\n13138;EGYPTIAN HIEROGLYPH F050;Lo;0;L;;;;;N;;;;;\n13139;EGYPTIAN HIEROGLYPH F051;Lo;0;L;;;;;N;;;;;\n1313A;EGYPTIAN HIEROGLYPH F051A;Lo;0;L;;;;;N;;;;;\n1313B;EGYPTIAN HIEROGLYPH F051B;Lo;0;L;;;;;N;;;;;\n1313C;EGYPTIAN HIEROGLYPH F051C;Lo;0;L;;;;;N;;;;;\n1313D;EGYPTIAN HIEROGLYPH F052;Lo;0;L;;;;;N;;;;;\n1313E;EGYPTIAN HIEROGLYPH F053;Lo;0;L;;;;;N;;;;;\n1313F;EGYPTIAN HIEROGLYPH G001;Lo;0;L;;;;;N;;;;;\n13140;EGYPTIAN HIEROGLYPH G002;Lo;0;L;;;;;N;;;;;\n13141;EGYPTIAN HIEROGLYPH G003;Lo;0;L;;;;;N;;;;;\n13142;EGYPTIAN HIEROGLYPH G004;Lo;0;L;;;;;N;;;;;\n13143;EGYPTIAN HIEROGLYPH G005;Lo;0;L;;;;;N;;;;;\n13144;EGYPTIAN HIEROGLYPH G006;Lo;0;L;;;;;N;;;;;\n13145;EGYPTIAN HIEROGLYPH G006A;Lo;0;L;;;;;N;;;;;\n13146;EGYPTIAN HIEROGLYPH G007;Lo;0;L;;;;;N;;;;;\n13147;EGYPTIAN HIEROGLYPH G007A;Lo;0;L;;;;;N;;;;;\n13148;EGYPTIAN HIEROGLYPH G007B;Lo;0;L;;;;;N;;;;;\n13149;EGYPTIAN HIEROGLYPH G008;Lo;0;L;;;;;N;;;;;\n1314A;EGYPTIAN HIEROGLYPH G009;Lo;0;L;;;;;N;;;;;\n1314B;EGYPTIAN HIEROGLYPH G010;Lo;0;L;;;;;N;;;;;\n1314C;EGYPTIAN HIEROGLYPH G011;Lo;0;L;;;;;N;;;;;\n1314D;EGYPTIAN HIEROGLYPH G011A;Lo;0;L;;;;;N;;;;;\n1314E;EGYPTIAN HIEROGLYPH G012;Lo;0;L;;;;;N;;;;;\n1314F;EGYPTIAN HIEROGLYPH G013;Lo;0;L;;;;;N;;;;;\n13150;EGYPTIAN HIEROGLYPH G014;Lo;0;L;;;;;N;;;;;\n13151;EGYPTIAN HIEROGLYPH G015;Lo;0;L;;;;;N;;;;;\n13152;EGYPTIAN HIEROGLYPH G016;Lo;0;L;;;;;N;;;;;\n13153;EGYPTIAN HIEROGLYPH G017;Lo;0;L;;;;;N;;;;;\n13154;EGYPTIAN HIEROGLYPH G018;Lo;0;L;;;;;N;;;;;\n13155;EGYPTIAN HIEROGLYPH G019;Lo;0;L;;;;;N;;;;;\n13156;EGYPTIAN HIEROGLYPH G020;Lo;0;L;;;;;N;;;;;\n13157;EGYPTIAN HIEROGLYPH G020A;Lo;0;L;;;;;N;;;;;\n13158;EGYPTIAN HIEROGLYPH G021;Lo;0;L;;;;;N;;;;;\n13159;EGYPTIAN HIEROGLYPH G022;Lo;0;L;;;;;N;;;;;\n1315A;EGYPTIAN HIEROGLYPH G023;Lo;0;L;;;;;N;;;;;\n1315B;EGYPTIAN HIEROGLYPH G024;Lo;0;L;;;;;N;;;;;\n1315C;EGYPTIAN HIEROGLYPH G025;Lo;0;L;;;;;N;;;;;\n1315D;EGYPTIAN HIEROGLYPH G026;Lo;0;L;;;;;N;;;;;\n1315E;EGYPTIAN HIEROGLYPH G026A;Lo;0;L;;;;;N;;;;;\n1315F;EGYPTIAN HIEROGLYPH G027;Lo;0;L;;;;;N;;;;;\n13160;EGYPTIAN HIEROGLYPH G028;Lo;0;L;;;;;N;;;;;\n13161;EGYPTIAN HIEROGLYPH G029;Lo;0;L;;;;;N;;;;;\n13162;EGYPTIAN HIEROGLYPH G030;Lo;0;L;;;;;N;;;;;\n13163;EGYPTIAN HIEROGLYPH G031;Lo;0;L;;;;;N;;;;;\n13164;EGYPTIAN HIEROGLYPH G032;Lo;0;L;;;;;N;;;;;\n13165;EGYPTIAN HIEROGLYPH G033;Lo;0;L;;;;;N;;;;;\n13166;EGYPTIAN HIEROGLYPH G034;Lo;0;L;;;;;N;;;;;\n13167;EGYPTIAN HIEROGLYPH G035;Lo;0;L;;;;;N;;;;;\n13168;EGYPTIAN HIEROGLYPH G036;Lo;0;L;;;;;N;;;;;\n13169;EGYPTIAN HIEROGLYPH G036A;Lo;0;L;;;;;N;;;;;\n1316A;EGYPTIAN HIEROGLYPH G037;Lo;0;L;;;;;N;;;;;\n1316B;EGYPTIAN HIEROGLYPH G037A;Lo;0;L;;;;;N;;;;;\n1316C;EGYPTIAN HIEROGLYPH G038;Lo;0;L;;;;;N;;;;;\n1316D;EGYPTIAN HIEROGLYPH G039;Lo;0;L;;;;;N;;;;;\n1316E;EGYPTIAN HIEROGLYPH G040;Lo;0;L;;;;;N;;;;;\n1316F;EGYPTIAN HIEROGLYPH G041;Lo;0;L;;;;;N;;;;;\n13170;EGYPTIAN HIEROGLYPH G042;Lo;0;L;;;;;N;;;;;\n13171;EGYPTIAN HIEROGLYPH G043;Lo;0;L;;;;;N;;;;;\n13172;EGYPTIAN HIEROGLYPH G043A;Lo;0;L;;;;;N;;;;;\n13173;EGYPTIAN HIEROGLYPH G044;Lo;0;L;;;;;N;;;;;\n13174;EGYPTIAN HIEROGLYPH G045;Lo;0;L;;;;;N;;;;;\n13175;EGYPTIAN HIEROGLYPH G045A;Lo;0;L;;;;;N;;;;;\n13176;EGYPTIAN HIEROGLYPH G046;Lo;0;L;;;;;N;;;;;\n13177;EGYPTIAN HIEROGLYPH G047;Lo;0;L;;;;;N;;;;;\n13178;EGYPTIAN HIEROGLYPH G048;Lo;0;L;;;;;N;;;;;\n13179;EGYPTIAN HIEROGLYPH G049;Lo;0;L;;;;;N;;;;;\n1317A;EGYPTIAN HIEROGLYPH G050;Lo;0;L;;;;;N;;;;;\n1317B;EGYPTIAN HIEROGLYPH G051;Lo;0;L;;;;;N;;;;;\n1317C;EGYPTIAN HIEROGLYPH G052;Lo;0;L;;;;;N;;;;;\n1317D;EGYPTIAN HIEROGLYPH G053;Lo;0;L;;;;;N;;;;;\n1317E;EGYPTIAN HIEROGLYPH G054;Lo;0;L;;;;;N;;;;;\n1317F;EGYPTIAN HIEROGLYPH H001;Lo;0;L;;;;;N;;;;;\n13180;EGYPTIAN HIEROGLYPH H002;Lo;0;L;;;;;N;;;;;\n13181;EGYPTIAN HIEROGLYPH H003;Lo;0;L;;;;;N;;;;;\n13182;EGYPTIAN HIEROGLYPH H004;Lo;0;L;;;;;N;;;;;\n13183;EGYPTIAN HIEROGLYPH H005;Lo;0;L;;;;;N;;;;;\n13184;EGYPTIAN HIEROGLYPH H006;Lo;0;L;;;;;N;;;;;\n13185;EGYPTIAN HIEROGLYPH H006A;Lo;0;L;;;;;N;;;;;\n13186;EGYPTIAN HIEROGLYPH H007;Lo;0;L;;;;;N;;;;;\n13187;EGYPTIAN HIEROGLYPH H008;Lo;0;L;;;;;N;;;;;\n13188;EGYPTIAN HIEROGLYPH I001;Lo;0;L;;;;;N;;;;;\n13189;EGYPTIAN HIEROGLYPH I002;Lo;0;L;;;;;N;;;;;\n1318A;EGYPTIAN HIEROGLYPH I003;Lo;0;L;;;;;N;;;;;\n1318B;EGYPTIAN HIEROGLYPH I004;Lo;0;L;;;;;N;;;;;\n1318C;EGYPTIAN HIEROGLYPH I005;Lo;0;L;;;;;N;;;;;\n1318D;EGYPTIAN HIEROGLYPH I005A;Lo;0;L;;;;;N;;;;;\n1318E;EGYPTIAN HIEROGLYPH I006;Lo;0;L;;;;;N;;;;;\n1318F;EGYPTIAN HIEROGLYPH I007;Lo;0;L;;;;;N;;;;;\n13190;EGYPTIAN HIEROGLYPH I008;Lo;0;L;;;;;N;;;;;\n13191;EGYPTIAN HIEROGLYPH I009;Lo;0;L;;;;;N;;;;;\n13192;EGYPTIAN HIEROGLYPH I009A;Lo;0;L;;;;;N;;;;;\n13193;EGYPTIAN HIEROGLYPH I010;Lo;0;L;;;;;N;;;;;\n13194;EGYPTIAN HIEROGLYPH I010A;Lo;0;L;;;;;N;;;;;\n13195;EGYPTIAN HIEROGLYPH I011;Lo;0;L;;;;;N;;;;;\n13196;EGYPTIAN HIEROGLYPH I011A;Lo;0;L;;;;;N;;;;;\n13197;EGYPTIAN HIEROGLYPH I012;Lo;0;L;;;;;N;;;;;\n13198;EGYPTIAN HIEROGLYPH I013;Lo;0;L;;;;;N;;;;;\n13199;EGYPTIAN HIEROGLYPH I014;Lo;0;L;;;;;N;;;;;\n1319A;EGYPTIAN HIEROGLYPH I015;Lo;0;L;;;;;N;;;;;\n1319B;EGYPTIAN HIEROGLYPH K001;Lo;0;L;;;;;N;;;;;\n1319C;EGYPTIAN HIEROGLYPH K002;Lo;0;L;;;;;N;;;;;\n1319D;EGYPTIAN HIEROGLYPH K003;Lo;0;L;;;;;N;;;;;\n1319E;EGYPTIAN HIEROGLYPH K004;Lo;0;L;;;;;N;;;;;\n1319F;EGYPTIAN HIEROGLYPH K005;Lo;0;L;;;;;N;;;;;\n131A0;EGYPTIAN HIEROGLYPH K006;Lo;0;L;;;;;N;;;;;\n131A1;EGYPTIAN HIEROGLYPH K007;Lo;0;L;;;;;N;;;;;\n131A2;EGYPTIAN HIEROGLYPH K008;Lo;0;L;;;;;N;;;;;\n131A3;EGYPTIAN HIEROGLYPH L001;Lo;0;L;;;;;N;;;;;\n131A4;EGYPTIAN HIEROGLYPH L002;Lo;0;L;;;;;N;;;;;\n131A5;EGYPTIAN HIEROGLYPH L002A;Lo;0;L;;;;;N;;;;;\n131A6;EGYPTIAN HIEROGLYPH L003;Lo;0;L;;;;;N;;;;;\n131A7;EGYPTIAN HIEROGLYPH L004;Lo;0;L;;;;;N;;;;;\n131A8;EGYPTIAN HIEROGLYPH L005;Lo;0;L;;;;;N;;;;;\n131A9;EGYPTIAN HIEROGLYPH L006;Lo;0;L;;;;;N;;;;;\n131AA;EGYPTIAN HIEROGLYPH L006A;Lo;0;L;;;;;N;;;;;\n131AB;EGYPTIAN HIEROGLYPH L007;Lo;0;L;;;;;N;;;;;\n131AC;EGYPTIAN HIEROGLYPH L008;Lo;0;L;;;;;N;;;;;\n131AD;EGYPTIAN HIEROGLYPH M001;Lo;0;L;;;;;N;;;;;\n131AE;EGYPTIAN HIEROGLYPH M001A;Lo;0;L;;;;;N;;;;;\n131AF;EGYPTIAN HIEROGLYPH M001B;Lo;0;L;;;;;N;;;;;\n131B0;EGYPTIAN HIEROGLYPH M002;Lo;0;L;;;;;N;;;;;\n131B1;EGYPTIAN HIEROGLYPH M003;Lo;0;L;;;;;N;;;;;\n131B2;EGYPTIAN HIEROGLYPH M003A;Lo;0;L;;;;;N;;;;;\n131B3;EGYPTIAN HIEROGLYPH M004;Lo;0;L;;;;;N;;;;;\n131B4;EGYPTIAN HIEROGLYPH M005;Lo;0;L;;;;;N;;;;;\n131B5;EGYPTIAN HIEROGLYPH M006;Lo;0;L;;;;;N;;;;;\n131B6;EGYPTIAN HIEROGLYPH M007;Lo;0;L;;;;;N;;;;;\n131B7;EGYPTIAN HIEROGLYPH M008;Lo;0;L;;;;;N;;;;;\n131B8;EGYPTIAN HIEROGLYPH M009;Lo;0;L;;;;;N;;;;;\n131B9;EGYPTIAN HIEROGLYPH M010;Lo;0;L;;;;;N;;;;;\n131BA;EGYPTIAN HIEROGLYPH M010A;Lo;0;L;;;;;N;;;;;\n131BB;EGYPTIAN HIEROGLYPH M011;Lo;0;L;;;;;N;;;;;\n131BC;EGYPTIAN HIEROGLYPH M012;Lo;0;L;;;;;N;;;;;\n131BD;EGYPTIAN HIEROGLYPH M012A;Lo;0;L;;;;;N;;;;;\n131BE;EGYPTIAN HIEROGLYPH M012B;Lo;0;L;;;;;N;;;;;\n131BF;EGYPTIAN HIEROGLYPH M012C;Lo;0;L;;;;;N;;;;;\n131C0;EGYPTIAN HIEROGLYPH M012D;Lo;0;L;;;;;N;;;;;\n131C1;EGYPTIAN HIEROGLYPH M012E;Lo;0;L;;;;;N;;;;;\n131C2;EGYPTIAN HIEROGLYPH M012F;Lo;0;L;;;;;N;;;;;\n131C3;EGYPTIAN HIEROGLYPH M012G;Lo;0;L;;;;;N;;;;;\n131C4;EGYPTIAN HIEROGLYPH M012H;Lo;0;L;;;;;N;;;;;\n131C5;EGYPTIAN HIEROGLYPH M013;Lo;0;L;;;;;N;;;;;\n131C6;EGYPTIAN HIEROGLYPH M014;Lo;0;L;;;;;N;;;;;\n131C7;EGYPTIAN HIEROGLYPH M015;Lo;0;L;;;;;N;;;;;\n131C8;EGYPTIAN HIEROGLYPH M015A;Lo;0;L;;;;;N;;;;;\n131C9;EGYPTIAN HIEROGLYPH M016;Lo;0;L;;;;;N;;;;;\n131CA;EGYPTIAN HIEROGLYPH M016A;Lo;0;L;;;;;N;;;;;\n131CB;EGYPTIAN HIEROGLYPH M017;Lo;0;L;;;;;N;;;;;\n131CC;EGYPTIAN HIEROGLYPH M017A;Lo;0;L;;;;;N;;;;;\n131CD;EGYPTIAN HIEROGLYPH M018;Lo;0;L;;;;;N;;;;;\n131CE;EGYPTIAN HIEROGLYPH M019;Lo;0;L;;;;;N;;;;;\n131CF;EGYPTIAN HIEROGLYPH M020;Lo;0;L;;;;;N;;;;;\n131D0;EGYPTIAN HIEROGLYPH M021;Lo;0;L;;;;;N;;;;;\n131D1;EGYPTIAN HIEROGLYPH M022;Lo;0;L;;;;;N;;;;;\n131D2;EGYPTIAN HIEROGLYPH M022A;Lo;0;L;;;;;N;;;;;\n131D3;EGYPTIAN HIEROGLYPH M023;Lo;0;L;;;;;N;;;;;\n131D4;EGYPTIAN HIEROGLYPH M024;Lo;0;L;;;;;N;;;;;\n131D5;EGYPTIAN HIEROGLYPH M024A;Lo;0;L;;;;;N;;;;;\n131D6;EGYPTIAN HIEROGLYPH M025;Lo;0;L;;;;;N;;;;;\n131D7;EGYPTIAN HIEROGLYPH M026;Lo;0;L;;;;;N;;;;;\n131D8;EGYPTIAN HIEROGLYPH M027;Lo;0;L;;;;;N;;;;;\n131D9;EGYPTIAN HIEROGLYPH M028;Lo;0;L;;;;;N;;;;;\n131DA;EGYPTIAN HIEROGLYPH M028A;Lo;0;L;;;;;N;;;;;\n131DB;EGYPTIAN HIEROGLYPH M029;Lo;0;L;;;;;N;;;;;\n131DC;EGYPTIAN HIEROGLYPH M030;Lo;0;L;;;;;N;;;;;\n131DD;EGYPTIAN HIEROGLYPH M031;Lo;0;L;;;;;N;;;;;\n131DE;EGYPTIAN HIEROGLYPH M031A;Lo;0;L;;;;;N;;;;;\n131DF;EGYPTIAN HIEROGLYPH M032;Lo;0;L;;;;;N;;;;;\n131E0;EGYPTIAN HIEROGLYPH M033;Lo;0;L;;;;;N;;;;;\n131E1;EGYPTIAN HIEROGLYPH M033A;Lo;0;L;;;;;N;;;;;\n131E2;EGYPTIAN HIEROGLYPH M033B;Lo;0;L;;;;;N;;;;;\n131E3;EGYPTIAN HIEROGLYPH M034;Lo;0;L;;;;;N;;;;;\n131E4;EGYPTIAN HIEROGLYPH M035;Lo;0;L;;;;;N;;;;;\n131E5;EGYPTIAN HIEROGLYPH M036;Lo;0;L;;;;;N;;;;;\n131E6;EGYPTIAN HIEROGLYPH M037;Lo;0;L;;;;;N;;;;;\n131E7;EGYPTIAN HIEROGLYPH M038;Lo;0;L;;;;;N;;;;;\n131E8;EGYPTIAN HIEROGLYPH M039;Lo;0;L;;;;;N;;;;;\n131E9;EGYPTIAN HIEROGLYPH M040;Lo;0;L;;;;;N;;;;;\n131EA;EGYPTIAN HIEROGLYPH M040A;Lo;0;L;;;;;N;;;;;\n131EB;EGYPTIAN HIEROGLYPH M041;Lo;0;L;;;;;N;;;;;\n131EC;EGYPTIAN HIEROGLYPH M042;Lo;0;L;;;;;N;;;;;\n131ED;EGYPTIAN HIEROGLYPH M043;Lo;0;L;;;;;N;;;;;\n131EE;EGYPTIAN HIEROGLYPH M044;Lo;0;L;;;;;N;;;;;\n131EF;EGYPTIAN HIEROGLYPH N001;Lo;0;L;;;;;N;;;;;\n131F0;EGYPTIAN HIEROGLYPH N002;Lo;0;L;;;;;N;;;;;\n131F1;EGYPTIAN HIEROGLYPH N003;Lo;0;L;;;;;N;;;;;\n131F2;EGYPTIAN HIEROGLYPH N004;Lo;0;L;;;;;N;;;;;\n131F3;EGYPTIAN HIEROGLYPH N005;Lo;0;L;;;;;N;;;;;\n131F4;EGYPTIAN HIEROGLYPH N006;Lo;0;L;;;;;N;;;;;\n131F5;EGYPTIAN HIEROGLYPH N007;Lo;0;L;;;;;N;;;;;\n131F6;EGYPTIAN HIEROGLYPH N008;Lo;0;L;;;;;N;;;;;\n131F7;EGYPTIAN HIEROGLYPH N009;Lo;0;L;;;;;N;;;;;\n131F8;EGYPTIAN HIEROGLYPH N010;Lo;0;L;;;;;N;;;;;\n131F9;EGYPTIAN HIEROGLYPH N011;Lo;0;L;;;;;N;;;;;\n131FA;EGYPTIAN HIEROGLYPH N012;Lo;0;L;;;;;N;;;;;\n131FB;EGYPTIAN HIEROGLYPH N013;Lo;0;L;;;;;N;;;;;\n131FC;EGYPTIAN HIEROGLYPH N014;Lo;0;L;;;;;N;;;;;\n131FD;EGYPTIAN HIEROGLYPH N015;Lo;0;L;;;;;N;;;;;\n131FE;EGYPTIAN HIEROGLYPH N016;Lo;0;L;;;;;N;;;;;\n131FF;EGYPTIAN HIEROGLYPH N017;Lo;0;L;;;;;N;;;;;\n13200;EGYPTIAN HIEROGLYPH N018;Lo;0;L;;;;;N;;;;;\n13201;EGYPTIAN HIEROGLYPH N018A;Lo;0;L;;;;;N;;;;;\n13202;EGYPTIAN HIEROGLYPH N018B;Lo;0;L;;;;;N;;;;;\n13203;EGYPTIAN HIEROGLYPH N019;Lo;0;L;;;;;N;;;;;\n13204;EGYPTIAN HIEROGLYPH N020;Lo;0;L;;;;;N;;;;;\n13205;EGYPTIAN HIEROGLYPH N021;Lo;0;L;;;;;N;;;;;\n13206;EGYPTIAN HIEROGLYPH N022;Lo;0;L;;;;;N;;;;;\n13207;EGYPTIAN HIEROGLYPH N023;Lo;0;L;;;;;N;;;;;\n13208;EGYPTIAN HIEROGLYPH N024;Lo;0;L;;;;;N;;;;;\n13209;EGYPTIAN HIEROGLYPH N025;Lo;0;L;;;;;N;;;;;\n1320A;EGYPTIAN HIEROGLYPH N025A;Lo;0;L;;;;;N;;;;;\n1320B;EGYPTIAN HIEROGLYPH N026;Lo;0;L;;;;;N;;;;;\n1320C;EGYPTIAN HIEROGLYPH N027;Lo;0;L;;;;;N;;;;;\n1320D;EGYPTIAN HIEROGLYPH N028;Lo;0;L;;;;;N;;;;;\n1320E;EGYPTIAN HIEROGLYPH N029;Lo;0;L;;;;;N;;;;;\n1320F;EGYPTIAN HIEROGLYPH N030;Lo;0;L;;;;;N;;;;;\n13210;EGYPTIAN HIEROGLYPH N031;Lo;0;L;;;;;N;;;;;\n13211;EGYPTIAN HIEROGLYPH N032;Lo;0;L;;;;;N;;;;;\n13212;EGYPTIAN HIEROGLYPH N033;Lo;0;L;;;;;N;;;;;\n13213;EGYPTIAN HIEROGLYPH N033A;Lo;0;L;;;;;N;;;;;\n13214;EGYPTIAN HIEROGLYPH N034;Lo;0;L;;;;;N;;;;;\n13215;EGYPTIAN HIEROGLYPH N034A;Lo;0;L;;;;;N;;;;;\n13216;EGYPTIAN HIEROGLYPH N035;Lo;0;L;;;;;N;;;;;\n13217;EGYPTIAN HIEROGLYPH N035A;Lo;0;L;;;;;N;;;;;\n13218;EGYPTIAN HIEROGLYPH N036;Lo;0;L;;;;;N;;;;;\n13219;EGYPTIAN HIEROGLYPH N037;Lo;0;L;;;;;N;;;;;\n1321A;EGYPTIAN HIEROGLYPH N037A;Lo;0;L;;;;;N;;;;;\n1321B;EGYPTIAN HIEROGLYPH N038;Lo;0;L;;;;;N;;;;;\n1321C;EGYPTIAN HIEROGLYPH N039;Lo;0;L;;;;;N;;;;;\n1321D;EGYPTIAN HIEROGLYPH N040;Lo;0;L;;;;;N;;;;;\n1321E;EGYPTIAN HIEROGLYPH N041;Lo;0;L;;;;;N;;;;;\n1321F;EGYPTIAN HIEROGLYPH N042;Lo;0;L;;;;;N;;;;;\n13220;EGYPTIAN HIEROGLYPH NL001;Lo;0;L;;;;;N;;;;;\n13221;EGYPTIAN HIEROGLYPH NL002;Lo;0;L;;;;;N;;;;;\n13222;EGYPTIAN HIEROGLYPH NL003;Lo;0;L;;;;;N;;;;;\n13223;EGYPTIAN HIEROGLYPH NL004;Lo;0;L;;;;;N;;;;;\n13224;EGYPTIAN HIEROGLYPH NL005;Lo;0;L;;;;;N;;;;;\n13225;EGYPTIAN HIEROGLYPH NL005A;Lo;0;L;;;;;N;;;;;\n13226;EGYPTIAN HIEROGLYPH NL006;Lo;0;L;;;;;N;;;;;\n13227;EGYPTIAN HIEROGLYPH NL007;Lo;0;L;;;;;N;;;;;\n13228;EGYPTIAN HIEROGLYPH NL008;Lo;0;L;;;;;N;;;;;\n13229;EGYPTIAN HIEROGLYPH NL009;Lo;0;L;;;;;N;;;;;\n1322A;EGYPTIAN HIEROGLYPH NL010;Lo;0;L;;;;;N;;;;;\n1322B;EGYPTIAN HIEROGLYPH NL011;Lo;0;L;;;;;N;;;;;\n1322C;EGYPTIAN HIEROGLYPH NL012;Lo;0;L;;;;;N;;;;;\n1322D;EGYPTIAN HIEROGLYPH NL013;Lo;0;L;;;;;N;;;;;\n1322E;EGYPTIAN HIEROGLYPH NL014;Lo;0;L;;;;;N;;;;;\n1322F;EGYPTIAN HIEROGLYPH NL015;Lo;0;L;;;;;N;;;;;\n13230;EGYPTIAN HIEROGLYPH NL016;Lo;0;L;;;;;N;;;;;\n13231;EGYPTIAN HIEROGLYPH NL017;Lo;0;L;;;;;N;;;;;\n13232;EGYPTIAN HIEROGLYPH NL017A;Lo;0;L;;;;;N;;;;;\n13233;EGYPTIAN HIEROGLYPH NL018;Lo;0;L;;;;;N;;;;;\n13234;EGYPTIAN HIEROGLYPH NL019;Lo;0;L;;;;;N;;;;;\n13235;EGYPTIAN HIEROGLYPH NL020;Lo;0;L;;;;;N;;;;;\n13236;EGYPTIAN HIEROGLYPH NU001;Lo;0;L;;;;;N;;;;;\n13237;EGYPTIAN HIEROGLYPH NU002;Lo;0;L;;;;;N;;;;;\n13238;EGYPTIAN HIEROGLYPH NU003;Lo;0;L;;;;;N;;;;;\n13239;EGYPTIAN HIEROGLYPH NU004;Lo;0;L;;;;;N;;;;;\n1323A;EGYPTIAN HIEROGLYPH NU005;Lo;0;L;;;;;N;;;;;\n1323B;EGYPTIAN HIEROGLYPH NU006;Lo;0;L;;;;;N;;;;;\n1323C;EGYPTIAN HIEROGLYPH NU007;Lo;0;L;;;;;N;;;;;\n1323D;EGYPTIAN HIEROGLYPH NU008;Lo;0;L;;;;;N;;;;;\n1323E;EGYPTIAN HIEROGLYPH NU009;Lo;0;L;;;;;N;;;;;\n1323F;EGYPTIAN HIEROGLYPH NU010;Lo;0;L;;;;;N;;;;;\n13240;EGYPTIAN HIEROGLYPH NU010A;Lo;0;L;;;;;N;;;;;\n13241;EGYPTIAN HIEROGLYPH NU011;Lo;0;L;;;;;N;;;;;\n13242;EGYPTIAN HIEROGLYPH NU011A;Lo;0;L;;;;;N;;;;;\n13243;EGYPTIAN HIEROGLYPH NU012;Lo;0;L;;;;;N;;;;;\n13244;EGYPTIAN HIEROGLYPH NU013;Lo;0;L;;;;;N;;;;;\n13245;EGYPTIAN HIEROGLYPH NU014;Lo;0;L;;;;;N;;;;;\n13246;EGYPTIAN HIEROGLYPH NU015;Lo;0;L;;;;;N;;;;;\n13247;EGYPTIAN HIEROGLYPH NU016;Lo;0;L;;;;;N;;;;;\n13248;EGYPTIAN HIEROGLYPH NU017;Lo;0;L;;;;;N;;;;;\n13249;EGYPTIAN HIEROGLYPH NU018;Lo;0;L;;;;;N;;;;;\n1324A;EGYPTIAN HIEROGLYPH NU018A;Lo;0;L;;;;;N;;;;;\n1324B;EGYPTIAN HIEROGLYPH NU019;Lo;0;L;;;;;N;;;;;\n1324C;EGYPTIAN HIEROGLYPH NU020;Lo;0;L;;;;;N;;;;;\n1324D;EGYPTIAN HIEROGLYPH NU021;Lo;0;L;;;;;N;;;;;\n1324E;EGYPTIAN HIEROGLYPH NU022;Lo;0;L;;;;;N;;;;;\n1324F;EGYPTIAN HIEROGLYPH NU022A;Lo;0;L;;;;;N;;;;;\n13250;EGYPTIAN HIEROGLYPH O001;Lo;0;L;;;;;N;;;;;\n13251;EGYPTIAN HIEROGLYPH O001A;Lo;0;L;;;;;N;;;;;\n13252;EGYPTIAN HIEROGLYPH O002;Lo;0;L;;;;;N;;;;;\n13253;EGYPTIAN HIEROGLYPH O003;Lo;0;L;;;;;N;;;;;\n13254;EGYPTIAN HIEROGLYPH O004;Lo;0;L;;;;;N;;;;;\n13255;EGYPTIAN HIEROGLYPH O005;Lo;0;L;;;;;N;;;;;\n13256;EGYPTIAN HIEROGLYPH O005A;Lo;0;L;;;;;N;;;;;\n13257;EGYPTIAN HIEROGLYPH O006;Lo;0;L;;;;;N;;;;;\n13258;EGYPTIAN HIEROGLYPH O006A;Lo;0;L;;;;;N;;;;;\n13259;EGYPTIAN HIEROGLYPH O006B;Lo;0;L;;;;;N;;;;;\n1325A;EGYPTIAN HIEROGLYPH O006C;Lo;0;L;;;;;N;;;;;\n1325B;EGYPTIAN HIEROGLYPH O006D;Lo;0;L;;;;;N;;;;;\n1325C;EGYPTIAN HIEROGLYPH O006E;Lo;0;L;;;;;N;;;;;\n1325D;EGYPTIAN HIEROGLYPH O006F;Lo;0;L;;;;;N;;;;;\n1325E;EGYPTIAN HIEROGLYPH O007;Lo;0;L;;;;;N;;;;;\n1325F;EGYPTIAN HIEROGLYPH O008;Lo;0;L;;;;;N;;;;;\n13260;EGYPTIAN HIEROGLYPH O009;Lo;0;L;;;;;N;;;;;\n13261;EGYPTIAN HIEROGLYPH O010;Lo;0;L;;;;;N;;;;;\n13262;EGYPTIAN HIEROGLYPH O010A;Lo;0;L;;;;;N;;;;;\n13263;EGYPTIAN HIEROGLYPH O010B;Lo;0;L;;;;;N;;;;;\n13264;EGYPTIAN HIEROGLYPH O010C;Lo;0;L;;;;;N;;;;;\n13265;EGYPTIAN HIEROGLYPH O011;Lo;0;L;;;;;N;;;;;\n13266;EGYPTIAN HIEROGLYPH O012;Lo;0;L;;;;;N;;;;;\n13267;EGYPTIAN HIEROGLYPH O013;Lo;0;L;;;;;N;;;;;\n13268;EGYPTIAN HIEROGLYPH O014;Lo;0;L;;;;;N;;;;;\n13269;EGYPTIAN HIEROGLYPH O015;Lo;0;L;;;;;N;;;;;\n1326A;EGYPTIAN HIEROGLYPH O016;Lo;0;L;;;;;N;;;;;\n1326B;EGYPTIAN HIEROGLYPH O017;Lo;0;L;;;;;N;;;;;\n1326C;EGYPTIAN HIEROGLYPH O018;Lo;0;L;;;;;N;;;;;\n1326D;EGYPTIAN HIEROGLYPH O019;Lo;0;L;;;;;N;;;;;\n1326E;EGYPTIAN HIEROGLYPH O019A;Lo;0;L;;;;;N;;;;;\n1326F;EGYPTIAN HIEROGLYPH O020;Lo;0;L;;;;;N;;;;;\n13270;EGYPTIAN HIEROGLYPH O020A;Lo;0;L;;;;;N;;;;;\n13271;EGYPTIAN HIEROGLYPH O021;Lo;0;L;;;;;N;;;;;\n13272;EGYPTIAN HIEROGLYPH O022;Lo;0;L;;;;;N;;;;;\n13273;EGYPTIAN HIEROGLYPH O023;Lo;0;L;;;;;N;;;;;\n13274;EGYPTIAN HIEROGLYPH O024;Lo;0;L;;;;;N;;;;;\n13275;EGYPTIAN HIEROGLYPH O024A;Lo;0;L;;;;;N;;;;;\n13276;EGYPTIAN HIEROGLYPH O025;Lo;0;L;;;;;N;;;;;\n13277;EGYPTIAN HIEROGLYPH O025A;Lo;0;L;;;;;N;;;;;\n13278;EGYPTIAN HIEROGLYPH O026;Lo;0;L;;;;;N;;;;;\n13279;EGYPTIAN HIEROGLYPH O027;Lo;0;L;;;;;N;;;;;\n1327A;EGYPTIAN HIEROGLYPH O028;Lo;0;L;;;;;N;;;;;\n1327B;EGYPTIAN HIEROGLYPH O029;Lo;0;L;;;;;N;;;;;\n1327C;EGYPTIAN HIEROGLYPH O029A;Lo;0;L;;;;;N;;;;;\n1327D;EGYPTIAN HIEROGLYPH O030;Lo;0;L;;;;;N;;;;;\n1327E;EGYPTIAN HIEROGLYPH O030A;Lo;0;L;;;;;N;;;;;\n1327F;EGYPTIAN HIEROGLYPH O031;Lo;0;L;;;;;N;;;;;\n13280;EGYPTIAN HIEROGLYPH O032;Lo;0;L;;;;;N;;;;;\n13281;EGYPTIAN HIEROGLYPH O033;Lo;0;L;;;;;N;;;;;\n13282;EGYPTIAN HIEROGLYPH O033A;Lo;0;L;;;;;N;;;;;\n13283;EGYPTIAN HIEROGLYPH O034;Lo;0;L;;;;;N;;;;;\n13284;EGYPTIAN HIEROGLYPH O035;Lo;0;L;;;;;N;;;;;\n13285;EGYPTIAN HIEROGLYPH O036;Lo;0;L;;;;;N;;;;;\n13286;EGYPTIAN HIEROGLYPH O036A;Lo;0;L;;;;;N;;;;;\n13287;EGYPTIAN HIEROGLYPH O036B;Lo;0;L;;;;;N;;;;;\n13288;EGYPTIAN HIEROGLYPH O036C;Lo;0;L;;;;;N;;;;;\n13289;EGYPTIAN HIEROGLYPH O036D;Lo;0;L;;;;;N;;;;;\n1328A;EGYPTIAN HIEROGLYPH O037;Lo;0;L;;;;;N;;;;;\n1328B;EGYPTIAN HIEROGLYPH O038;Lo;0;L;;;;;N;;;;;\n1328C;EGYPTIAN HIEROGLYPH O039;Lo;0;L;;;;;N;;;;;\n1328D;EGYPTIAN HIEROGLYPH O040;Lo;0;L;;;;;N;;;;;\n1328E;EGYPTIAN HIEROGLYPH O041;Lo;0;L;;;;;N;;;;;\n1328F;EGYPTIAN HIEROGLYPH O042;Lo;0;L;;;;;N;;;;;\n13290;EGYPTIAN HIEROGLYPH O043;Lo;0;L;;;;;N;;;;;\n13291;EGYPTIAN HIEROGLYPH O044;Lo;0;L;;;;;N;;;;;\n13292;EGYPTIAN HIEROGLYPH O045;Lo;0;L;;;;;N;;;;;\n13293;EGYPTIAN HIEROGLYPH O046;Lo;0;L;;;;;N;;;;;\n13294;EGYPTIAN HIEROGLYPH O047;Lo;0;L;;;;;N;;;;;\n13295;EGYPTIAN HIEROGLYPH O048;Lo;0;L;;;;;N;;;;;\n13296;EGYPTIAN HIEROGLYPH O049;Lo;0;L;;;;;N;;;;;\n13297;EGYPTIAN HIEROGLYPH O050;Lo;0;L;;;;;N;;;;;\n13298;EGYPTIAN HIEROGLYPH O050A;Lo;0;L;;;;;N;;;;;\n13299;EGYPTIAN HIEROGLYPH O050B;Lo;0;L;;;;;N;;;;;\n1329A;EGYPTIAN HIEROGLYPH O051;Lo;0;L;;;;;N;;;;;\n1329B;EGYPTIAN HIEROGLYPH P001;Lo;0;L;;;;;N;;;;;\n1329C;EGYPTIAN HIEROGLYPH P001A;Lo;0;L;;;;;N;;;;;\n1329D;EGYPTIAN HIEROGLYPH P002;Lo;0;L;;;;;N;;;;;\n1329E;EGYPTIAN HIEROGLYPH P003;Lo;0;L;;;;;N;;;;;\n1329F;EGYPTIAN HIEROGLYPH P003A;Lo;0;L;;;;;N;;;;;\n132A0;EGYPTIAN HIEROGLYPH P004;Lo;0;L;;;;;N;;;;;\n132A1;EGYPTIAN HIEROGLYPH P005;Lo;0;L;;;;;N;;;;;\n132A2;EGYPTIAN HIEROGLYPH P006;Lo;0;L;;;;;N;;;;;\n132A3;EGYPTIAN HIEROGLYPH P007;Lo;0;L;;;;;N;;;;;\n132A4;EGYPTIAN HIEROGLYPH P008;Lo;0;L;;;;;N;;;;;\n132A5;EGYPTIAN HIEROGLYPH P009;Lo;0;L;;;;;N;;;;;\n132A6;EGYPTIAN HIEROGLYPH P010;Lo;0;L;;;;;N;;;;;\n132A7;EGYPTIAN HIEROGLYPH P011;Lo;0;L;;;;;N;;;;;\n132A8;EGYPTIAN HIEROGLYPH Q001;Lo;0;L;;;;;N;;;;;\n132A9;EGYPTIAN HIEROGLYPH Q002;Lo;0;L;;;;;N;;;;;\n132AA;EGYPTIAN HIEROGLYPH Q003;Lo;0;L;;;;;N;;;;;\n132AB;EGYPTIAN HIEROGLYPH Q004;Lo;0;L;;;;;N;;;;;\n132AC;EGYPTIAN HIEROGLYPH Q005;Lo;0;L;;;;;N;;;;;\n132AD;EGYPTIAN HIEROGLYPH Q006;Lo;0;L;;;;;N;;;;;\n132AE;EGYPTIAN HIEROGLYPH Q007;Lo;0;L;;;;;N;;;;;\n132AF;EGYPTIAN HIEROGLYPH R001;Lo;0;L;;;;;N;;;;;\n132B0;EGYPTIAN HIEROGLYPH R002;Lo;0;L;;;;;N;;;;;\n132B1;EGYPTIAN HIEROGLYPH R002A;Lo;0;L;;;;;N;;;;;\n132B2;EGYPTIAN HIEROGLYPH R003;Lo;0;L;;;;;N;;;;;\n132B3;EGYPTIAN HIEROGLYPH R003A;Lo;0;L;;;;;N;;;;;\n132B4;EGYPTIAN HIEROGLYPH R003B;Lo;0;L;;;;;N;;;;;\n132B5;EGYPTIAN HIEROGLYPH R004;Lo;0;L;;;;;N;;;;;\n132B6;EGYPTIAN HIEROGLYPH R005;Lo;0;L;;;;;N;;;;;\n132B7;EGYPTIAN HIEROGLYPH R006;Lo;0;L;;;;;N;;;;;\n132B8;EGYPTIAN HIEROGLYPH R007;Lo;0;L;;;;;N;;;;;\n132B9;EGYPTIAN HIEROGLYPH R008;Lo;0;L;;;;;N;;;;;\n132BA;EGYPTIAN HIEROGLYPH R009;Lo;0;L;;;;;N;;;;;\n132BB;EGYPTIAN HIEROGLYPH R010;Lo;0;L;;;;;N;;;;;\n132BC;EGYPTIAN HIEROGLYPH R010A;Lo;0;L;;;;;N;;;;;\n132BD;EGYPTIAN HIEROGLYPH R011;Lo;0;L;;;;;N;;;;;\n132BE;EGYPTIAN HIEROGLYPH R012;Lo;0;L;;;;;N;;;;;\n132BF;EGYPTIAN HIEROGLYPH R013;Lo;0;L;;;;;N;;;;;\n132C0;EGYPTIAN HIEROGLYPH R014;Lo;0;L;;;;;N;;;;;\n132C1;EGYPTIAN HIEROGLYPH R015;Lo;0;L;;;;;N;;;;;\n132C2;EGYPTIAN HIEROGLYPH R016;Lo;0;L;;;;;N;;;;;\n132C3;EGYPTIAN HIEROGLYPH R016A;Lo;0;L;;;;;N;;;;;\n132C4;EGYPTIAN HIEROGLYPH R017;Lo;0;L;;;;;N;;;;;\n132C5;EGYPTIAN HIEROGLYPH R018;Lo;0;L;;;;;N;;;;;\n132C6;EGYPTIAN HIEROGLYPH R019;Lo;0;L;;;;;N;;;;;\n132C7;EGYPTIAN HIEROGLYPH R020;Lo;0;L;;;;;N;;;;;\n132C8;EGYPTIAN HIEROGLYPH R021;Lo;0;L;;;;;N;;;;;\n132C9;EGYPTIAN HIEROGLYPH R022;Lo;0;L;;;;;N;;;;;\n132CA;EGYPTIAN HIEROGLYPH R023;Lo;0;L;;;;;N;;;;;\n132CB;EGYPTIAN HIEROGLYPH R024;Lo;0;L;;;;;N;;;;;\n132CC;EGYPTIAN HIEROGLYPH R025;Lo;0;L;;;;;N;;;;;\n132CD;EGYPTIAN HIEROGLYPH R026;Lo;0;L;;;;;N;;;;;\n132CE;EGYPTIAN HIEROGLYPH R027;Lo;0;L;;;;;N;;;;;\n132CF;EGYPTIAN HIEROGLYPH R028;Lo;0;L;;;;;N;;;;;\n132D0;EGYPTIAN HIEROGLYPH R029;Lo;0;L;;;;;N;;;;;\n132D1;EGYPTIAN HIEROGLYPH S001;Lo;0;L;;;;;N;;;;;\n132D2;EGYPTIAN HIEROGLYPH S002;Lo;0;L;;;;;N;;;;;\n132D3;EGYPTIAN HIEROGLYPH S002A;Lo;0;L;;;;;N;;;;;\n132D4;EGYPTIAN HIEROGLYPH S003;Lo;0;L;;;;;N;;;;;\n132D5;EGYPTIAN HIEROGLYPH S004;Lo;0;L;;;;;N;;;;;\n132D6;EGYPTIAN HIEROGLYPH S005;Lo;0;L;;;;;N;;;;;\n132D7;EGYPTIAN HIEROGLYPH S006;Lo;0;L;;;;;N;;;;;\n132D8;EGYPTIAN HIEROGLYPH S006A;Lo;0;L;;;;;N;;;;;\n132D9;EGYPTIAN HIEROGLYPH S007;Lo;0;L;;;;;N;;;;;\n132DA;EGYPTIAN HIEROGLYPH S008;Lo;0;L;;;;;N;;;;;\n132DB;EGYPTIAN HIEROGLYPH S009;Lo;0;L;;;;;N;;;;;\n132DC;EGYPTIAN HIEROGLYPH S010;Lo;0;L;;;;;N;;;;;\n132DD;EGYPTIAN HIEROGLYPH S011;Lo;0;L;;;;;N;;;;;\n132DE;EGYPTIAN HIEROGLYPH S012;Lo;0;L;;;;;N;;;;;\n132DF;EGYPTIAN HIEROGLYPH S013;Lo;0;L;;;;;N;;;;;\n132E0;EGYPTIAN HIEROGLYPH S014;Lo;0;L;;;;;N;;;;;\n132E1;EGYPTIAN HIEROGLYPH S014A;Lo;0;L;;;;;N;;;;;\n132E2;EGYPTIAN HIEROGLYPH S014B;Lo;0;L;;;;;N;;;;;\n132E3;EGYPTIAN HIEROGLYPH S015;Lo;0;L;;;;;N;;;;;\n132E4;EGYPTIAN HIEROGLYPH S016;Lo;0;L;;;;;N;;;;;\n132E5;EGYPTIAN HIEROGLYPH S017;Lo;0;L;;;;;N;;;;;\n132E6;EGYPTIAN HIEROGLYPH S017A;Lo;0;L;;;;;N;;;;;\n132E7;EGYPTIAN HIEROGLYPH S018;Lo;0;L;;;;;N;;;;;\n132E8;EGYPTIAN HIEROGLYPH S019;Lo;0;L;;;;;N;;;;;\n132E9;EGYPTIAN HIEROGLYPH S020;Lo;0;L;;;;;N;;;;;\n132EA;EGYPTIAN HIEROGLYPH S021;Lo;0;L;;;;;N;;;;;\n132EB;EGYPTIAN HIEROGLYPH S022;Lo;0;L;;;;;N;;;;;\n132EC;EGYPTIAN HIEROGLYPH S023;Lo;0;L;;;;;N;;;;;\n132ED;EGYPTIAN HIEROGLYPH S024;Lo;0;L;;;;;N;;;;;\n132EE;EGYPTIAN HIEROGLYPH S025;Lo;0;L;;;;;N;;;;;\n132EF;EGYPTIAN HIEROGLYPH S026;Lo;0;L;;;;;N;;;;;\n132F0;EGYPTIAN HIEROGLYPH S026A;Lo;0;L;;;;;N;;;;;\n132F1;EGYPTIAN HIEROGLYPH S026B;Lo;0;L;;;;;N;;;;;\n132F2;EGYPTIAN HIEROGLYPH S027;Lo;0;L;;;;;N;;;;;\n132F3;EGYPTIAN HIEROGLYPH S028;Lo;0;L;;;;;N;;;;;\n132F4;EGYPTIAN HIEROGLYPH S029;Lo;0;L;;;;;N;;;;;\n132F5;EGYPTIAN HIEROGLYPH S030;Lo;0;L;;;;;N;;;;;\n132F6;EGYPTIAN HIEROGLYPH S031;Lo;0;L;;;;;N;;;;;\n132F7;EGYPTIAN HIEROGLYPH S032;Lo;0;L;;;;;N;;;;;\n132F8;EGYPTIAN HIEROGLYPH S033;Lo;0;L;;;;;N;;;;;\n132F9;EGYPTIAN HIEROGLYPH S034;Lo;0;L;;;;;N;;;;;\n132FA;EGYPTIAN HIEROGLYPH S035;Lo;0;L;;;;;N;;;;;\n132FB;EGYPTIAN HIEROGLYPH S035A;Lo;0;L;;;;;N;;;;;\n132FC;EGYPTIAN HIEROGLYPH S036;Lo;0;L;;;;;N;;;;;\n132FD;EGYPTIAN HIEROGLYPH S037;Lo;0;L;;;;;N;;;;;\n132FE;EGYPTIAN HIEROGLYPH S038;Lo;0;L;;;;;N;;;;;\n132FF;EGYPTIAN HIEROGLYPH S039;Lo;0;L;;;;;N;;;;;\n13300;EGYPTIAN HIEROGLYPH S040;Lo;0;L;;;;;N;;;;;\n13301;EGYPTIAN HIEROGLYPH S041;Lo;0;L;;;;;N;;;;;\n13302;EGYPTIAN HIEROGLYPH S042;Lo;0;L;;;;;N;;;;;\n13303;EGYPTIAN HIEROGLYPH S043;Lo;0;L;;;;;N;;;;;\n13304;EGYPTIAN HIEROGLYPH S044;Lo;0;L;;;;;N;;;;;\n13305;EGYPTIAN HIEROGLYPH S045;Lo;0;L;;;;;N;;;;;\n13306;EGYPTIAN HIEROGLYPH S046;Lo;0;L;;;;;N;;;;;\n13307;EGYPTIAN HIEROGLYPH T001;Lo;0;L;;;;;N;;;;;\n13308;EGYPTIAN HIEROGLYPH T002;Lo;0;L;;;;;N;;;;;\n13309;EGYPTIAN HIEROGLYPH T003;Lo;0;L;;;;;N;;;;;\n1330A;EGYPTIAN HIEROGLYPH T003A;Lo;0;L;;;;;N;;;;;\n1330B;EGYPTIAN HIEROGLYPH T004;Lo;0;L;;;;;N;;;;;\n1330C;EGYPTIAN HIEROGLYPH T005;Lo;0;L;;;;;N;;;;;\n1330D;EGYPTIAN HIEROGLYPH T006;Lo;0;L;;;;;N;;;;;\n1330E;EGYPTIAN HIEROGLYPH T007;Lo;0;L;;;;;N;;;;;\n1330F;EGYPTIAN HIEROGLYPH T007A;Lo;0;L;;;;;N;;;;;\n13310;EGYPTIAN HIEROGLYPH T008;Lo;0;L;;;;;N;;;;;\n13311;EGYPTIAN HIEROGLYPH T008A;Lo;0;L;;;;;N;;;;;\n13312;EGYPTIAN HIEROGLYPH T009;Lo;0;L;;;;;N;;;;;\n13313;EGYPTIAN HIEROGLYPH T009A;Lo;0;L;;;;;N;;;;;\n13314;EGYPTIAN HIEROGLYPH T010;Lo;0;L;;;;;N;;;;;\n13315;EGYPTIAN HIEROGLYPH T011;Lo;0;L;;;;;N;;;;;\n13316;EGYPTIAN HIEROGLYPH T011A;Lo;0;L;;;;;N;;;;;\n13317;EGYPTIAN HIEROGLYPH T012;Lo;0;L;;;;;N;;;;;\n13318;EGYPTIAN HIEROGLYPH T013;Lo;0;L;;;;;N;;;;;\n13319;EGYPTIAN HIEROGLYPH T014;Lo;0;L;;;;;N;;;;;\n1331A;EGYPTIAN HIEROGLYPH T015;Lo;0;L;;;;;N;;;;;\n1331B;EGYPTIAN HIEROGLYPH T016;Lo;0;L;;;;;N;;;;;\n1331C;EGYPTIAN HIEROGLYPH T016A;Lo;0;L;;;;;N;;;;;\n1331D;EGYPTIAN HIEROGLYPH T017;Lo;0;L;;;;;N;;;;;\n1331E;EGYPTIAN HIEROGLYPH T018;Lo;0;L;;;;;N;;;;;\n1331F;EGYPTIAN HIEROGLYPH T019;Lo;0;L;;;;;N;;;;;\n13320;EGYPTIAN HIEROGLYPH T020;Lo;0;L;;;;;N;;;;;\n13321;EGYPTIAN HIEROGLYPH T021;Lo;0;L;;;;;N;;;;;\n13322;EGYPTIAN HIEROGLYPH T022;Lo;0;L;;;;;N;;;;;\n13323;EGYPTIAN HIEROGLYPH T023;Lo;0;L;;;;;N;;;;;\n13324;EGYPTIAN HIEROGLYPH T024;Lo;0;L;;;;;N;;;;;\n13325;EGYPTIAN HIEROGLYPH T025;Lo;0;L;;;;;N;;;;;\n13326;EGYPTIAN HIEROGLYPH T026;Lo;0;L;;;;;N;;;;;\n13327;EGYPTIAN HIEROGLYPH T027;Lo;0;L;;;;;N;;;;;\n13328;EGYPTIAN HIEROGLYPH T028;Lo;0;L;;;;;N;;;;;\n13329;EGYPTIAN HIEROGLYPH T029;Lo;0;L;;;;;N;;;;;\n1332A;EGYPTIAN HIEROGLYPH T030;Lo;0;L;;;;;N;;;;;\n1332B;EGYPTIAN HIEROGLYPH T031;Lo;0;L;;;;;N;;;;;\n1332C;EGYPTIAN HIEROGLYPH T032;Lo;0;L;;;;;N;;;;;\n1332D;EGYPTIAN HIEROGLYPH T032A;Lo;0;L;;;;;N;;;;;\n1332E;EGYPTIAN HIEROGLYPH T033;Lo;0;L;;;;;N;;;;;\n1332F;EGYPTIAN HIEROGLYPH T033A;Lo;0;L;;;;;N;;;;;\n13330;EGYPTIAN HIEROGLYPH T034;Lo;0;L;;;;;N;;;;;\n13331;EGYPTIAN HIEROGLYPH T035;Lo;0;L;;;;;N;;;;;\n13332;EGYPTIAN HIEROGLYPH T036;Lo;0;L;;;;;N;;;;;\n13333;EGYPTIAN HIEROGLYPH U001;Lo;0;L;;;;;N;;;;;\n13334;EGYPTIAN HIEROGLYPH U002;Lo;0;L;;;;;N;;;;;\n13335;EGYPTIAN HIEROGLYPH U003;Lo;0;L;;;;;N;;;;;\n13336;EGYPTIAN HIEROGLYPH U004;Lo;0;L;;;;;N;;;;;\n13337;EGYPTIAN HIEROGLYPH U005;Lo;0;L;;;;;N;;;;;\n13338;EGYPTIAN HIEROGLYPH U006;Lo;0;L;;;;;N;;;;;\n13339;EGYPTIAN HIEROGLYPH U006A;Lo;0;L;;;;;N;;;;;\n1333A;EGYPTIAN HIEROGLYPH U006B;Lo;0;L;;;;;N;;;;;\n1333B;EGYPTIAN HIEROGLYPH U007;Lo;0;L;;;;;N;;;;;\n1333C;EGYPTIAN HIEROGLYPH U008;Lo;0;L;;;;;N;;;;;\n1333D;EGYPTIAN HIEROGLYPH U009;Lo;0;L;;;;;N;;;;;\n1333E;EGYPTIAN HIEROGLYPH U010;Lo;0;L;;;;;N;;;;;\n1333F;EGYPTIAN HIEROGLYPH U011;Lo;0;L;;;;;N;;;;;\n13340;EGYPTIAN HIEROGLYPH U012;Lo;0;L;;;;;N;;;;;\n13341;EGYPTIAN HIEROGLYPH U013;Lo;0;L;;;;;N;;;;;\n13342;EGYPTIAN HIEROGLYPH U014;Lo;0;L;;;;;N;;;;;\n13343;EGYPTIAN HIEROGLYPH U015;Lo;0;L;;;;;N;;;;;\n13344;EGYPTIAN HIEROGLYPH U016;Lo;0;L;;;;;N;;;;;\n13345;EGYPTIAN HIEROGLYPH U017;Lo;0;L;;;;;N;;;;;\n13346;EGYPTIAN HIEROGLYPH U018;Lo;0;L;;;;;N;;;;;\n13347;EGYPTIAN HIEROGLYPH U019;Lo;0;L;;;;;N;;;;;\n13348;EGYPTIAN HIEROGLYPH U020;Lo;0;L;;;;;N;;;;;\n13349;EGYPTIAN HIEROGLYPH U021;Lo;0;L;;;;;N;;;;;\n1334A;EGYPTIAN HIEROGLYPH U022;Lo;0;L;;;;;N;;;;;\n1334B;EGYPTIAN HIEROGLYPH U023;Lo;0;L;;;;;N;;;;;\n1334C;EGYPTIAN HIEROGLYPH U023A;Lo;0;L;;;;;N;;;;;\n1334D;EGYPTIAN HIEROGLYPH U024;Lo;0;L;;;;;N;;;;;\n1334E;EGYPTIAN HIEROGLYPH U025;Lo;0;L;;;;;N;;;;;\n1334F;EGYPTIAN HIEROGLYPH U026;Lo;0;L;;;;;N;;;;;\n13350;EGYPTIAN HIEROGLYPH U027;Lo;0;L;;;;;N;;;;;\n13351;EGYPTIAN HIEROGLYPH U028;Lo;0;L;;;;;N;;;;;\n13352;EGYPTIAN HIEROGLYPH U029;Lo;0;L;;;;;N;;;;;\n13353;EGYPTIAN HIEROGLYPH U029A;Lo;0;L;;;;;N;;;;;\n13354;EGYPTIAN HIEROGLYPH U030;Lo;0;L;;;;;N;;;;;\n13355;EGYPTIAN HIEROGLYPH U031;Lo;0;L;;;;;N;;;;;\n13356;EGYPTIAN HIEROGLYPH U032;Lo;0;L;;;;;N;;;;;\n13357;EGYPTIAN HIEROGLYPH U032A;Lo;0;L;;;;;N;;;;;\n13358;EGYPTIAN HIEROGLYPH U033;Lo;0;L;;;;;N;;;;;\n13359;EGYPTIAN HIEROGLYPH U034;Lo;0;L;;;;;N;;;;;\n1335A;EGYPTIAN HIEROGLYPH U035;Lo;0;L;;;;;N;;;;;\n1335B;EGYPTIAN HIEROGLYPH U036;Lo;0;L;;;;;N;;;;;\n1335C;EGYPTIAN HIEROGLYPH U037;Lo;0;L;;;;;N;;;;;\n1335D;EGYPTIAN HIEROGLYPH U038;Lo;0;L;;;;;N;;;;;\n1335E;EGYPTIAN HIEROGLYPH U039;Lo;0;L;;;;;N;;;;;\n1335F;EGYPTIAN HIEROGLYPH U040;Lo;0;L;;;;;N;;;;;\n13360;EGYPTIAN HIEROGLYPH U041;Lo;0;L;;;;;N;;;;;\n13361;EGYPTIAN HIEROGLYPH U042;Lo;0;L;;;;;N;;;;;\n13362;EGYPTIAN HIEROGLYPH V001;Lo;0;L;;;;;N;;;;;\n13363;EGYPTIAN HIEROGLYPH V001A;Lo;0;L;;;;;N;;;;;\n13364;EGYPTIAN HIEROGLYPH V001B;Lo;0;L;;;;;N;;;;;\n13365;EGYPTIAN HIEROGLYPH V001C;Lo;0;L;;;;;N;;;;;\n13366;EGYPTIAN HIEROGLYPH V001D;Lo;0;L;;;;;N;;;;;\n13367;EGYPTIAN HIEROGLYPH V001E;Lo;0;L;;;;;N;;;;;\n13368;EGYPTIAN HIEROGLYPH V001F;Lo;0;L;;;;;N;;;;;\n13369;EGYPTIAN HIEROGLYPH V001G;Lo;0;L;;;;;N;;;;;\n1336A;EGYPTIAN HIEROGLYPH V001H;Lo;0;L;;;;;N;;;;;\n1336B;EGYPTIAN HIEROGLYPH V001I;Lo;0;L;;;;;N;;;;;\n1336C;EGYPTIAN HIEROGLYPH V002;Lo;0;L;;;;;N;;;;;\n1336D;EGYPTIAN HIEROGLYPH V002A;Lo;0;L;;;;;N;;;;;\n1336E;EGYPTIAN HIEROGLYPH V003;Lo;0;L;;;;;N;;;;;\n1336F;EGYPTIAN HIEROGLYPH V004;Lo;0;L;;;;;N;;;;;\n13370;EGYPTIAN HIEROGLYPH V005;Lo;0;L;;;;;N;;;;;\n13371;EGYPTIAN HIEROGLYPH V006;Lo;0;L;;;;;N;;;;;\n13372;EGYPTIAN HIEROGLYPH V007;Lo;0;L;;;;;N;;;;;\n13373;EGYPTIAN HIEROGLYPH V007A;Lo;0;L;;;;;N;;;;;\n13374;EGYPTIAN HIEROGLYPH V007B;Lo;0;L;;;;;N;;;;;\n13375;EGYPTIAN HIEROGLYPH V008;Lo;0;L;;;;;N;;;;;\n13376;EGYPTIAN HIEROGLYPH V009;Lo;0;L;;;;;N;;;;;\n13377;EGYPTIAN HIEROGLYPH V010;Lo;0;L;;;;;N;;;;;\n13378;EGYPTIAN HIEROGLYPH V011;Lo;0;L;;;;;N;;;;;\n13379;EGYPTIAN HIEROGLYPH V011A;Lo;0;L;;;;;N;;;;;\n1337A;EGYPTIAN HIEROGLYPH V011B;Lo;0;L;;;;;N;;;;;\n1337B;EGYPTIAN HIEROGLYPH V011C;Lo;0;L;;;;;N;;;;;\n1337C;EGYPTIAN HIEROGLYPH V012;Lo;0;L;;;;;N;;;;;\n1337D;EGYPTIAN HIEROGLYPH V012A;Lo;0;L;;;;;N;;;;;\n1337E;EGYPTIAN HIEROGLYPH V012B;Lo;0;L;;;;;N;;;;;\n1337F;EGYPTIAN HIEROGLYPH V013;Lo;0;L;;;;;N;;;;;\n13380;EGYPTIAN HIEROGLYPH V014;Lo;0;L;;;;;N;;;;;\n13381;EGYPTIAN HIEROGLYPH V015;Lo;0;L;;;;;N;;;;;\n13382;EGYPTIAN HIEROGLYPH V016;Lo;0;L;;;;;N;;;;;\n13383;EGYPTIAN HIEROGLYPH V017;Lo;0;L;;;;;N;;;;;\n13384;EGYPTIAN HIEROGLYPH V018;Lo;0;L;;;;;N;;;;;\n13385;EGYPTIAN HIEROGLYPH V019;Lo;0;L;;;;;N;;;;;\n13386;EGYPTIAN HIEROGLYPH V020;Lo;0;L;;;;;N;;;;;\n13387;EGYPTIAN HIEROGLYPH V020A;Lo;0;L;;;;;N;;;;;\n13388;EGYPTIAN HIEROGLYPH V020B;Lo;0;L;;;;;N;;;;;\n13389;EGYPTIAN HIEROGLYPH V020C;Lo;0;L;;;;;N;;;;;\n1338A;EGYPTIAN HIEROGLYPH V020D;Lo;0;L;;;;;N;;;;;\n1338B;EGYPTIAN HIEROGLYPH V020E;Lo;0;L;;;;;N;;;;;\n1338C;EGYPTIAN HIEROGLYPH V020F;Lo;0;L;;;;;N;;;;;\n1338D;EGYPTIAN HIEROGLYPH V020G;Lo;0;L;;;;;N;;;;;\n1338E;EGYPTIAN HIEROGLYPH V020H;Lo;0;L;;;;;N;;;;;\n1338F;EGYPTIAN HIEROGLYPH V020I;Lo;0;L;;;;;N;;;;;\n13390;EGYPTIAN HIEROGLYPH V020J;Lo;0;L;;;;;N;;;;;\n13391;EGYPTIAN HIEROGLYPH V020K;Lo;0;L;;;;;N;;;;;\n13392;EGYPTIAN HIEROGLYPH V020L;Lo;0;L;;;;;N;;;;;\n13393;EGYPTIAN HIEROGLYPH V021;Lo;0;L;;;;;N;;;;;\n13394;EGYPTIAN HIEROGLYPH V022;Lo;0;L;;;;;N;;;;;\n13395;EGYPTIAN HIEROGLYPH V023;Lo;0;L;;;;;N;;;;;\n13396;EGYPTIAN HIEROGLYPH V023A;Lo;0;L;;;;;N;;;;;\n13397;EGYPTIAN HIEROGLYPH V024;Lo;0;L;;;;;N;;;;;\n13398;EGYPTIAN HIEROGLYPH V025;Lo;0;L;;;;;N;;;;;\n13399;EGYPTIAN HIEROGLYPH V026;Lo;0;L;;;;;N;;;;;\n1339A;EGYPTIAN HIEROGLYPH V027;Lo;0;L;;;;;N;;;;;\n1339B;EGYPTIAN HIEROGLYPH V028;Lo;0;L;;;;;N;;;;;\n1339C;EGYPTIAN HIEROGLYPH V028A;Lo;0;L;;;;;N;;;;;\n1339D;EGYPTIAN HIEROGLYPH V029;Lo;0;L;;;;;N;;;;;\n1339E;EGYPTIAN HIEROGLYPH V029A;Lo;0;L;;;;;N;;;;;\n1339F;EGYPTIAN HIEROGLYPH V030;Lo;0;L;;;;;N;;;;;\n133A0;EGYPTIAN HIEROGLYPH V030A;Lo;0;L;;;;;N;;;;;\n133A1;EGYPTIAN HIEROGLYPH V031;Lo;0;L;;;;;N;;;;;\n133A2;EGYPTIAN HIEROGLYPH V031A;Lo;0;L;;;;;N;;;;;\n133A3;EGYPTIAN HIEROGLYPH V032;Lo;0;L;;;;;N;;;;;\n133A4;EGYPTIAN HIEROGLYPH V033;Lo;0;L;;;;;N;;;;;\n133A5;EGYPTIAN HIEROGLYPH V033A;Lo;0;L;;;;;N;;;;;\n133A6;EGYPTIAN HIEROGLYPH V034;Lo;0;L;;;;;N;;;;;\n133A7;EGYPTIAN HIEROGLYPH V035;Lo;0;L;;;;;N;;;;;\n133A8;EGYPTIAN HIEROGLYPH V036;Lo;0;L;;;;;N;;;;;\n133A9;EGYPTIAN HIEROGLYPH V037;Lo;0;L;;;;;N;;;;;\n133AA;EGYPTIAN HIEROGLYPH V037A;Lo;0;L;;;;;N;;;;;\n133AB;EGYPTIAN HIEROGLYPH V038;Lo;0;L;;;;;N;;;;;\n133AC;EGYPTIAN HIEROGLYPH V039;Lo;0;L;;;;;N;;;;;\n133AD;EGYPTIAN HIEROGLYPH V040;Lo;0;L;;;;;N;;;;;\n133AE;EGYPTIAN HIEROGLYPH V040A;Lo;0;L;;;;;N;;;;;\n133AF;EGYPTIAN HIEROGLYPH W001;Lo;0;L;;;;;N;;;;;\n133B0;EGYPTIAN HIEROGLYPH W002;Lo;0;L;;;;;N;;;;;\n133B1;EGYPTIAN HIEROGLYPH W003;Lo;0;L;;;;;N;;;;;\n133B2;EGYPTIAN HIEROGLYPH W003A;Lo;0;L;;;;;N;;;;;\n133B3;EGYPTIAN HIEROGLYPH W004;Lo;0;L;;;;;N;;;;;\n133B4;EGYPTIAN HIEROGLYPH W005;Lo;0;L;;;;;N;;;;;\n133B5;EGYPTIAN HIEROGLYPH W006;Lo;0;L;;;;;N;;;;;\n133B6;EGYPTIAN HIEROGLYPH W007;Lo;0;L;;;;;N;;;;;\n133B7;EGYPTIAN HIEROGLYPH W008;Lo;0;L;;;;;N;;;;;\n133B8;EGYPTIAN HIEROGLYPH W009;Lo;0;L;;;;;N;;;;;\n133B9;EGYPTIAN HIEROGLYPH W009A;Lo;0;L;;;;;N;;;;;\n133BA;EGYPTIAN HIEROGLYPH W010;Lo;0;L;;;;;N;;;;;\n133BB;EGYPTIAN HIEROGLYPH W010A;Lo;0;L;;;;;N;;;;;\n133BC;EGYPTIAN HIEROGLYPH W011;Lo;0;L;;;;;N;;;;;\n133BD;EGYPTIAN HIEROGLYPH W012;Lo;0;L;;;;;N;;;;;\n133BE;EGYPTIAN HIEROGLYPH W013;Lo;0;L;;;;;N;;;;;\n133BF;EGYPTIAN HIEROGLYPH W014;Lo;0;L;;;;;N;;;;;\n133C0;EGYPTIAN HIEROGLYPH W014A;Lo;0;L;;;;;N;;;;;\n133C1;EGYPTIAN HIEROGLYPH W015;Lo;0;L;;;;;N;;;;;\n133C2;EGYPTIAN HIEROGLYPH W016;Lo;0;L;;;;;N;;;;;\n133C3;EGYPTIAN HIEROGLYPH W017;Lo;0;L;;;;;N;;;;;\n133C4;EGYPTIAN HIEROGLYPH W017A;Lo;0;L;;;;;N;;;;;\n133C5;EGYPTIAN HIEROGLYPH W018;Lo;0;L;;;;;N;;;;;\n133C6;EGYPTIAN HIEROGLYPH W018A;Lo;0;L;;;;;N;;;;;\n133C7;EGYPTIAN HIEROGLYPH W019;Lo;0;L;;;;;N;;;;;\n133C8;EGYPTIAN HIEROGLYPH W020;Lo;0;L;;;;;N;;;;;\n133C9;EGYPTIAN HIEROGLYPH W021;Lo;0;L;;;;;N;;;;;\n133CA;EGYPTIAN HIEROGLYPH W022;Lo;0;L;;;;;N;;;;;\n133CB;EGYPTIAN HIEROGLYPH W023;Lo;0;L;;;;;N;;;;;\n133CC;EGYPTIAN HIEROGLYPH W024;Lo;0;L;;;;;N;;;;;\n133CD;EGYPTIAN HIEROGLYPH W024A;Lo;0;L;;;;;N;;;;;\n133CE;EGYPTIAN HIEROGLYPH W025;Lo;0;L;;;;;N;;;;;\n133CF;EGYPTIAN HIEROGLYPH X001;Lo;0;L;;;;;N;;;;;\n133D0;EGYPTIAN HIEROGLYPH X002;Lo;0;L;;;;;N;;;;;\n133D1;EGYPTIAN HIEROGLYPH X003;Lo;0;L;;;;;N;;;;;\n133D2;EGYPTIAN HIEROGLYPH X004;Lo;0;L;;;;;N;;;;;\n133D3;EGYPTIAN HIEROGLYPH X004A;Lo;0;L;;;;;N;;;;;\n133D4;EGYPTIAN HIEROGLYPH X004B;Lo;0;L;;;;;N;;;;;\n133D5;EGYPTIAN HIEROGLYPH X005;Lo;0;L;;;;;N;;;;;\n133D6;EGYPTIAN HIEROGLYPH X006;Lo;0;L;;;;;N;;;;;\n133D7;EGYPTIAN HIEROGLYPH X006A;Lo;0;L;;;;;N;;;;;\n133D8;EGYPTIAN HIEROGLYPH X007;Lo;0;L;;;;;N;;;;;\n133D9;EGYPTIAN HIEROGLYPH X008;Lo;0;L;;;;;N;;;;;\n133DA;EGYPTIAN HIEROGLYPH X008A;Lo;0;L;;;;;N;;;;;\n133DB;EGYPTIAN HIEROGLYPH Y001;Lo;0;L;;;;;N;;;;;\n133DC;EGYPTIAN HIEROGLYPH Y001A;Lo;0;L;;;;;N;;;;;\n133DD;EGYPTIAN HIEROGLYPH Y002;Lo;0;L;;;;;N;;;;;\n133DE;EGYPTIAN HIEROGLYPH Y003;Lo;0;L;;;;;N;;;;;\n133DF;EGYPTIAN HIEROGLYPH Y004;Lo;0;L;;;;;N;;;;;\n133E0;EGYPTIAN HIEROGLYPH Y005;Lo;0;L;;;;;N;;;;;\n133E1;EGYPTIAN HIEROGLYPH Y006;Lo;0;L;;;;;N;;;;;\n133E2;EGYPTIAN HIEROGLYPH Y007;Lo;0;L;;;;;N;;;;;\n133E3;EGYPTIAN HIEROGLYPH Y008;Lo;0;L;;;;;N;;;;;\n133E4;EGYPTIAN HIEROGLYPH Z001;Lo;0;L;;;;;N;;;;;\n133E5;EGYPTIAN HIEROGLYPH Z002;Lo;0;L;;;;;N;;;;;\n133E6;EGYPTIAN HIEROGLYPH Z002A;Lo;0;L;;;;;N;;;;;\n133E7;EGYPTIAN HIEROGLYPH Z002B;Lo;0;L;;;;;N;;;;;\n133E8;EGYPTIAN HIEROGLYPH Z002C;Lo;0;L;;;;;N;;;;;\n133E9;EGYPTIAN HIEROGLYPH Z002D;Lo;0;L;;;;;N;;;;;\n133EA;EGYPTIAN HIEROGLYPH Z003;Lo;0;L;;;;;N;;;;;\n133EB;EGYPTIAN HIEROGLYPH Z003A;Lo;0;L;;;;;N;;;;;\n133EC;EGYPTIAN HIEROGLYPH Z003B;Lo;0;L;;;;;N;;;;;\n133ED;EGYPTIAN HIEROGLYPH Z004;Lo;0;L;;;;;N;;;;;\n133EE;EGYPTIAN HIEROGLYPH Z004A;Lo;0;L;;;;;N;;;;;\n133EF;EGYPTIAN HIEROGLYPH Z005;Lo;0;L;;;;;N;;;;;\n133F0;EGYPTIAN HIEROGLYPH Z005A;Lo;0;L;;;;;N;;;;;\n133F1;EGYPTIAN HIEROGLYPH Z006;Lo;0;L;;;;;N;;;;;\n133F2;EGYPTIAN HIEROGLYPH Z007;Lo;0;L;;;;;N;;;;;\n133F3;EGYPTIAN HIEROGLYPH Z008;Lo;0;L;;;;;N;;;;;\n133F4;EGYPTIAN HIEROGLYPH Z009;Lo;0;L;;;;;N;;;;;\n133F5;EGYPTIAN HIEROGLYPH Z010;Lo;0;L;;;;;N;;;;;\n133F6;EGYPTIAN HIEROGLYPH Z011;Lo;0;L;;;;;N;;;;;\n133F7;EGYPTIAN HIEROGLYPH Z012;Lo;0;L;;;;;N;;;;;\n133F8;EGYPTIAN HIEROGLYPH Z013;Lo;0;L;;;;;N;;;;;\n133F9;EGYPTIAN HIEROGLYPH Z014;Lo;0;L;;;;;N;;;;;\n133FA;EGYPTIAN HIEROGLYPH Z015;Lo;0;L;;;;;N;;;;;\n133FB;EGYPTIAN HIEROGLYPH Z015A;Lo;0;L;;;;;N;;;;;\n133FC;EGYPTIAN HIEROGLYPH Z015B;Lo;0;L;;;;;N;;;;;\n133FD;EGYPTIAN HIEROGLYPH Z015C;Lo;0;L;;;;;N;;;;;\n133FE;EGYPTIAN HIEROGLYPH Z015D;Lo;0;L;;;;;N;;;;;\n133FF;EGYPTIAN HIEROGLYPH Z015E;Lo;0;L;;;;;N;;;;;\n13400;EGYPTIAN HIEROGLYPH Z015F;Lo;0;L;;;;;N;;;;;\n13401;EGYPTIAN HIEROGLYPH Z015G;Lo;0;L;;;;;N;;;;;\n13402;EGYPTIAN HIEROGLYPH Z015H;Lo;0;L;;;;;N;;;;;\n13403;EGYPTIAN HIEROGLYPH Z015I;Lo;0;L;;;;;N;;;;;\n13404;EGYPTIAN HIEROGLYPH Z016;Lo;0;L;;;;;N;;;;;\n13405;EGYPTIAN HIEROGLYPH Z016A;Lo;0;L;;;;;N;;;;;\n13406;EGYPTIAN HIEROGLYPH Z016B;Lo;0;L;;;;;N;;;;;\n13407;EGYPTIAN HIEROGLYPH Z016C;Lo;0;L;;;;;N;;;;;\n13408;EGYPTIAN HIEROGLYPH Z016D;Lo;0;L;;;;;N;;;;;\n13409;EGYPTIAN HIEROGLYPH Z016E;Lo;0;L;;;;;N;;;;;\n1340A;EGYPTIAN HIEROGLYPH Z016F;Lo;0;L;;;;;N;;;;;\n1340B;EGYPTIAN HIEROGLYPH Z016G;Lo;0;L;;;;;N;;;;;\n1340C;EGYPTIAN HIEROGLYPH Z016H;Lo;0;L;;;;;N;;;;;\n1340D;EGYPTIAN HIEROGLYPH AA001;Lo;0;L;;;;;N;;;;;\n1340E;EGYPTIAN HIEROGLYPH AA002;Lo;0;L;;;;;N;;;;;\n1340F;EGYPTIAN HIEROGLYPH AA003;Lo;0;L;;;;;N;;;;;\n13410;EGYPTIAN HIEROGLYPH AA004;Lo;0;L;;;;;N;;;;;\n13411;EGYPTIAN HIEROGLYPH AA005;Lo;0;L;;;;;N;;;;;\n13412;EGYPTIAN HIEROGLYPH AA006;Lo;0;L;;;;;N;;;;;\n13413;EGYPTIAN HIEROGLYPH AA007;Lo;0;L;;;;;N;;;;;\n13414;EGYPTIAN HIEROGLYPH AA007A;Lo;0;L;;;;;N;;;;;\n13415;EGYPTIAN HIEROGLYPH AA007B;Lo;0;L;;;;;N;;;;;\n13416;EGYPTIAN HIEROGLYPH AA008;Lo;0;L;;;;;N;;;;;\n13417;EGYPTIAN HIEROGLYPH AA009;Lo;0;L;;;;;N;;;;;\n13418;EGYPTIAN HIEROGLYPH AA010;Lo;0;L;;;;;N;;;;;\n13419;EGYPTIAN HIEROGLYPH AA011;Lo;0;L;;;;;N;;;;;\n1341A;EGYPTIAN HIEROGLYPH AA012;Lo;0;L;;;;;N;;;;;\n1341B;EGYPTIAN HIEROGLYPH AA013;Lo;0;L;;;;;N;;;;;\n1341C;EGYPTIAN HIEROGLYPH AA014;Lo;0;L;;;;;N;;;;;\n1341D;EGYPTIAN HIEROGLYPH AA015;Lo;0;L;;;;;N;;;;;\n1341E;EGYPTIAN HIEROGLYPH AA016;Lo;0;L;;;;;N;;;;;\n1341F;EGYPTIAN HIEROGLYPH AA017;Lo;0;L;;;;;N;;;;;\n13420;EGYPTIAN HIEROGLYPH AA018;Lo;0;L;;;;;N;;;;;\n13421;EGYPTIAN HIEROGLYPH AA019;Lo;0;L;;;;;N;;;;;\n13422;EGYPTIAN HIEROGLYPH AA020;Lo;0;L;;;;;N;;;;;\n13423;EGYPTIAN HIEROGLYPH AA021;Lo;0;L;;;;;N;;;;;\n13424;EGYPTIAN HIEROGLYPH AA022;Lo;0;L;;;;;N;;;;;\n13425;EGYPTIAN HIEROGLYPH AA023;Lo;0;L;;;;;N;;;;;\n13426;EGYPTIAN HIEROGLYPH AA024;Lo;0;L;;;;;N;;;;;\n13427;EGYPTIAN HIEROGLYPH AA025;Lo;0;L;;;;;N;;;;;\n13428;EGYPTIAN HIEROGLYPH AA026;Lo;0;L;;;;;N;;;;;\n13429;EGYPTIAN HIEROGLYPH AA027;Lo;0;L;;;;;N;;;;;\n1342A;EGYPTIAN HIEROGLYPH AA028;Lo;0;L;;;;;N;;;;;\n1342B;EGYPTIAN HIEROGLYPH AA029;Lo;0;L;;;;;N;;;;;\n1342C;EGYPTIAN HIEROGLYPH AA030;Lo;0;L;;;;;N;;;;;\n1342D;EGYPTIAN HIEROGLYPH AA031;Lo;0;L;;;;;N;;;;;\n1342E;EGYPTIAN HIEROGLYPH AA032;Lo;0;L;;;;;N;;;;;\n1342F;EGYPTIAN HIEROGLYPH V011D;Lo;0;L;;;;;N;;;;;\n13430;EGYPTIAN HIEROGLYPH VERTICAL JOINER;Cf;0;L;;;;;N;;;;;\n13431;EGYPTIAN HIEROGLYPH HORIZONTAL JOINER;Cf;0;L;;;;;N;;;;;\n13432;EGYPTIAN HIEROGLYPH INSERT AT TOP START;Cf;0;L;;;;;N;;;;;\n13433;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM START;Cf;0;L;;;;;N;;;;;\n13434;EGYPTIAN HIEROGLYPH INSERT AT TOP END;Cf;0;L;;;;;N;;;;;\n13435;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM END;Cf;0;L;;;;;N;;;;;\n13436;EGYPTIAN HIEROGLYPH OVERLAY MIDDLE;Cf;0;L;;;;;N;;;;;\n13437;EGYPTIAN HIEROGLYPH BEGIN SEGMENT;Cf;0;L;;;;;N;;;;;\n13438;EGYPTIAN HIEROGLYPH END SEGMENT;Cf;0;L;;;;;N;;;;;\n13439;EGYPTIAN HIEROGLYPH INSERT AT MIDDLE;Cf;0;L;;;;;N;;;;;\n1343A;EGYPTIAN HIEROGLYPH INSERT AT TOP;Cf;0;L;;;;;N;;;;;\n1343B;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM;Cf;0;L;;;;;N;;;;;\n1343C;EGYPTIAN HIEROGLYPH BEGIN ENCLOSURE;Cf;0;L;;;;;N;;;;;\n1343D;EGYPTIAN HIEROGLYPH END ENCLOSURE;Cf;0;L;;;;;N;;;;;\n1343E;EGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSURE;Cf;0;L;;;;;N;;;;;\n1343F;EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE;Cf;0;L;;;;;N;;;;;\n13440;EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY;Mn;0;NSM;;;;;N;;;;;\n13441;EGYPTIAN HIEROGLYPH FULL BLANK;Lo;0;L;;;;;N;;;;;\n13442;EGYPTIAN HIEROGLYPH HALF BLANK;Lo;0;L;;;;;N;;;;;\n13443;EGYPTIAN HIEROGLYPH LOST SIGN;Lo;0;L;;;;;N;;;;;\n13444;EGYPTIAN HIEROGLYPH HALF LOST SIGN;Lo;0;L;;;;;N;;;;;\n13445;EGYPTIAN HIEROGLYPH TALL LOST SIGN;Lo;0;L;;;;;N;;;;;\n13446;EGYPTIAN HIEROGLYPH WIDE LOST SIGN;Lo;0;L;;;;;N;;;;;\n13447;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START;Mn;0;NSM;;;;;N;;;;;\n13448;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START;Mn;0;NSM;;;;;N;;;;;\n13449;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START;Mn;0;NSM;;;;;N;;;;;\n1344A;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP END;Mn;0;NSM;;;;;N;;;;;\n1344B;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP;Mn;0;NSM;;;;;N;;;;;\n1344C;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START AND TOP END;Mn;0;NSM;;;;;N;;;;;\n1344D;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND TOP;Mn;0;NSM;;;;;N;;;;;\n1344E;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM END;Mn;0;NSM;;;;;N;;;;;\n1344F;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START AND BOTTOM END;Mn;0;NSM;;;;;N;;;;;\n13450;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM;Mn;0;NSM;;;;;N;;;;;\n13451;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND BOTTOM;Mn;0;NSM;;;;;N;;;;;\n13452;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT END;Mn;0;NSM;;;;;N;;;;;\n13453;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP AND END;Mn;0;NSM;;;;;N;;;;;\n13454;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM AND END;Mn;0;NSM;;;;;N;;;;;\n13455;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED;Mn;0;NSM;;;;;N;;;;;\n13460;EGYPTIAN HIEROGLYPH-13460;Lo;0;L;;;;;N;;;;;\n13461;EGYPTIAN HIEROGLYPH-13461;Lo;0;L;;;;;N;;;;;\n13462;EGYPTIAN HIEROGLYPH-13462;Lo;0;L;;;;;N;;;;;\n13463;EGYPTIAN HIEROGLYPH-13463;Lo;0;L;;;;;N;;;;;\n13464;EGYPTIAN HIEROGLYPH-13464;Lo;0;L;;;;;N;;;;;\n13465;EGYPTIAN HIEROGLYPH-13465;Lo;0;L;;;;;N;;;;;\n13466;EGYPTIAN HIEROGLYPH-13466;Lo;0;L;;;;;N;;;;;\n13467;EGYPTIAN HIEROGLYPH-13467;Lo;0;L;;;;;N;;;;;\n13468;EGYPTIAN HIEROGLYPH-13468;Lo;0;L;;;;;N;;;;;\n13469;EGYPTIAN HIEROGLYPH-13469;Lo;0;L;;;;;N;;;;;\n1346A;EGYPTIAN HIEROGLYPH-1346A;Lo;0;L;;;;;N;;;;;\n1346B;EGYPTIAN HIEROGLYPH-1346B;Lo;0;L;;;;;N;;;;;\n1346C;EGYPTIAN HIEROGLYPH-1346C;Lo;0;L;;;;;N;;;;;\n1346D;EGYPTIAN HIEROGLYPH-1346D;Lo;0;L;;;;;N;;;;;\n1346E;EGYPTIAN HIEROGLYPH-1346E;Lo;0;L;;;;;N;;;;;\n1346F;EGYPTIAN HIEROGLYPH-1346F;Lo;0;L;;;;;N;;;;;\n13470;EGYPTIAN HIEROGLYPH-13470;Lo;0;L;;;;;N;;;;;\n13471;EGYPTIAN HIEROGLYPH-13471;Lo;0;L;;;;;N;;;;;\n13472;EGYPTIAN HIEROGLYPH-13472;Lo;0;L;;;;;N;;;;;\n13473;EGYPTIAN HIEROGLYPH-13473;Lo;0;L;;;;;N;;;;;\n13474;EGYPTIAN HIEROGLYPH-13474;Lo;0;L;;;;;N;;;;;\n13475;EGYPTIAN HIEROGLYPH-13475;Lo;0;L;;;;;N;;;;;\n13476;EGYPTIAN HIEROGLYPH-13476;Lo;0;L;;;;;N;;;;;\n13477;EGYPTIAN HIEROGLYPH-13477;Lo;0;L;;;;;N;;;;;\n13478;EGYPTIAN HIEROGLYPH-13478;Lo;0;L;;;;;N;;;;;\n13479;EGYPTIAN HIEROGLYPH-13479;Lo;0;L;;;;;N;;;;;\n1347A;EGYPTIAN HIEROGLYPH-1347A;Lo;0;L;;;;;N;;;;;\n1347B;EGYPTIAN HIEROGLYPH-1347B;Lo;0;L;;;;;N;;;;;\n1347C;EGYPTIAN HIEROGLYPH-1347C;Lo;0;L;;;;;N;;;;;\n1347D;EGYPTIAN HIEROGLYPH-1347D;Lo;0;L;;;;;N;;;;;\n1347E;EGYPTIAN HIEROGLYPH-1347E;Lo;0;L;;;;;N;;;;;\n1347F;EGYPTIAN HIEROGLYPH-1347F;Lo;0;L;;;;;N;;;;;\n13480;EGYPTIAN HIEROGLYPH-13480;Lo;0;L;;;;;N;;;;;\n13481;EGYPTIAN HIEROGLYPH-13481;Lo;0;L;;;;;N;;;;;\n13482;EGYPTIAN HIEROGLYPH-13482;Lo;0;L;;;;;N;;;;;\n13483;EGYPTIAN HIEROGLYPH-13483;Lo;0;L;;;;;N;;;;;\n13484;EGYPTIAN HIEROGLYPH-13484;Lo;0;L;;;;;N;;;;;\n13485;EGYPTIAN HIEROGLYPH-13485;Lo;0;L;;;;;N;;;;;\n13486;EGYPTIAN HIEROGLYPH-13486;Lo;0;L;;;;;N;;;;;\n13487;EGYPTIAN HIEROGLYPH-13487;Lo;0;L;;;;;N;;;;;\n13488;EGYPTIAN HIEROGLYPH-13488;Lo;0;L;;;;;N;;;;;\n13489;EGYPTIAN HIEROGLYPH-13489;Lo;0;L;;;;;N;;;;;\n1348A;EGYPTIAN HIEROGLYPH-1348A;Lo;0;L;;;;;N;;;;;\n1348B;EGYPTIAN HIEROGLYPH-1348B;Lo;0;L;;;;;N;;;;;\n1348C;EGYPTIAN HIEROGLYPH-1348C;Lo;0;L;;;;;N;;;;;\n1348D;EGYPTIAN HIEROGLYPH-1348D;Lo;0;L;;;;;N;;;;;\n1348E;EGYPTIAN HIEROGLYPH-1348E;Lo;0;L;;;;;N;;;;;\n1348F;EGYPTIAN HIEROGLYPH-1348F;Lo;0;L;;;;;N;;;;;\n13490;EGYPTIAN HIEROGLYPH-13490;Lo;0;L;;;;;N;;;;;\n13491;EGYPTIAN HIEROGLYPH-13491;Lo;0;L;;;;;N;;;;;\n13492;EGYPTIAN HIEROGLYPH-13492;Lo;0;L;;;;;N;;;;;\n13493;EGYPTIAN HIEROGLYPH-13493;Lo;0;L;;;;;N;;;;;\n13494;EGYPTIAN HIEROGLYPH-13494;Lo;0;L;;;;;N;;;;;\n13495;EGYPTIAN HIEROGLYPH-13495;Lo;0;L;;;;;N;;;;;\n13496;EGYPTIAN HIEROGLYPH-13496;Lo;0;L;;;;;N;;;;;\n13497;EGYPTIAN HIEROGLYPH-13497;Lo;0;L;;;;;N;;;;;\n13498;EGYPTIAN HIEROGLYPH-13498;Lo;0;L;;;;;N;;;;;\n13499;EGYPTIAN HIEROGLYPH-13499;Lo;0;L;;;;;N;;;;;\n1349A;EGYPTIAN HIEROGLYPH-1349A;Lo;0;L;;;;;N;;;;;\n1349B;EGYPTIAN HIEROGLYPH-1349B;Lo;0;L;;;;;N;;;;;\n1349C;EGYPTIAN HIEROGLYPH-1349C;Lo;0;L;;;;;N;;;;;\n1349D;EGYPTIAN HIEROGLYPH-1349D;Lo;0;L;;;;;N;;;;;\n1349E;EGYPTIAN HIEROGLYPH-1349E;Lo;0;L;;;;;N;;;;;\n1349F;EGYPTIAN HIEROGLYPH-1349F;Lo;0;L;;;;;N;;;;;\n134A0;EGYPTIAN HIEROGLYPH-134A0;Lo;0;L;;;;;N;;;;;\n134A1;EGYPTIAN HIEROGLYPH-134A1;Lo;0;L;;;;;N;;;;;\n134A2;EGYPTIAN HIEROGLYPH-134A2;Lo;0;L;;;;;N;;;;;\n134A3;EGYPTIAN HIEROGLYPH-134A3;Lo;0;L;;;;;N;;;;;\n134A4;EGYPTIAN HIEROGLYPH-134A4;Lo;0;L;;;;;N;;;;;\n134A5;EGYPTIAN HIEROGLYPH-134A5;Lo;0;L;;;;;N;;;;;\n134A6;EGYPTIAN HIEROGLYPH-134A6;Lo;0;L;;;;;N;;;;;\n134A7;EGYPTIAN HIEROGLYPH-134A7;Lo;0;L;;;;;N;;;;;\n134A8;EGYPTIAN HIEROGLYPH-134A8;Lo;0;L;;;;;N;;;;;\n134A9;EGYPTIAN HIEROGLYPH-134A9;Lo;0;L;;;;;N;;;;;\n134AA;EGYPTIAN HIEROGLYPH-134AA;Lo;0;L;;;;;N;;;;;\n134AB;EGYPTIAN HIEROGLYPH-134AB;Lo;0;L;;;;;N;;;;;\n134AC;EGYPTIAN HIEROGLYPH-134AC;Lo;0;L;;;;;N;;;;;\n134AD;EGYPTIAN HIEROGLYPH-134AD;Lo;0;L;;;;;N;;;;;\n134AE;EGYPTIAN HIEROGLYPH-134AE;Lo;0;L;;;;;N;;;;;\n134AF;EGYPTIAN HIEROGLYPH-134AF;Lo;0;L;;;;;N;;;;;\n134B0;EGYPTIAN HIEROGLYPH-134B0;Lo;0;L;;;;;N;;;;;\n134B1;EGYPTIAN HIEROGLYPH-134B1;Lo;0;L;;;;;N;;;;;\n134B2;EGYPTIAN HIEROGLYPH-134B2;Lo;0;L;;;;;N;;;;;\n134B3;EGYPTIAN HIEROGLYPH-134B3;Lo;0;L;;;;;N;;;;;\n134B4;EGYPTIAN HIEROGLYPH-134B4;Lo;0;L;;;;;N;;;;;\n134B5;EGYPTIAN HIEROGLYPH-134B5;Lo;0;L;;;;;N;;;;;\n134B6;EGYPTIAN HIEROGLYPH-134B6;Lo;0;L;;;;;N;;;;;\n134B7;EGYPTIAN HIEROGLYPH-134B7;Lo;0;L;;;;;N;;;;;\n134B8;EGYPTIAN HIEROGLYPH-134B8;Lo;0;L;;;;;N;;;;;\n134B9;EGYPTIAN HIEROGLYPH-134B9;Lo;0;L;;;;;N;;;;;\n134BA;EGYPTIAN HIEROGLYPH-134BA;Lo;0;L;;;;;N;;;;;\n134BB;EGYPTIAN HIEROGLYPH-134BB;Lo;0;L;;;;;N;;;;;\n134BC;EGYPTIAN HIEROGLYPH-134BC;Lo;0;L;;;;;N;;;;;\n134BD;EGYPTIAN HIEROGLYPH-134BD;Lo;0;L;;;;;N;;;;;\n134BE;EGYPTIAN HIEROGLYPH-134BE;Lo;0;L;;;;;N;;;;;\n134BF;EGYPTIAN HIEROGLYPH-134BF;Lo;0;L;;;;;N;;;;;\n134C0;EGYPTIAN HIEROGLYPH-134C0;Lo;0;L;;;;;N;;;;;\n134C1;EGYPTIAN HIEROGLYPH-134C1;Lo;0;L;;;;;N;;;;;\n134C2;EGYPTIAN HIEROGLYPH-134C2;Lo;0;L;;;;;N;;;;;\n134C3;EGYPTIAN HIEROGLYPH-134C3;Lo;0;L;;;;;N;;;;;\n134C4;EGYPTIAN HIEROGLYPH-134C4;Lo;0;L;;;;;N;;;;;\n134C5;EGYPTIAN HIEROGLYPH-134C5;Lo;0;L;;;;;N;;;;;\n134C6;EGYPTIAN HIEROGLYPH-134C6;Lo;0;L;;;;;N;;;;;\n134C7;EGYPTIAN HIEROGLYPH-134C7;Lo;0;L;;;;;N;;;;;\n134C8;EGYPTIAN HIEROGLYPH-134C8;Lo;0;L;;;;;N;;;;;\n134C9;EGYPTIAN HIEROGLYPH-134C9;Lo;0;L;;;;;N;;;;;\n134CA;EGYPTIAN HIEROGLYPH-134CA;Lo;0;L;;;;;N;;;;;\n134CB;EGYPTIAN HIEROGLYPH-134CB;Lo;0;L;;;;;N;;;;;\n134CC;EGYPTIAN HIEROGLYPH-134CC;Lo;0;L;;;;;N;;;;;\n134CD;EGYPTIAN HIEROGLYPH-134CD;Lo;0;L;;;;;N;;;;;\n134CE;EGYPTIAN HIEROGLYPH-134CE;Lo;0;L;;;;;N;;;;;\n134CF;EGYPTIAN HIEROGLYPH-134CF;Lo;0;L;;;;;N;;;;;\n134D0;EGYPTIAN HIEROGLYPH-134D0;Lo;0;L;;;;;N;;;;;\n134D1;EGYPTIAN HIEROGLYPH-134D1;Lo;0;L;;;;;N;;;;;\n134D2;EGYPTIAN HIEROGLYPH-134D2;Lo;0;L;;;;;N;;;;;\n134D3;EGYPTIAN HIEROGLYPH-134D3;Lo;0;L;;;;;N;;;;;\n134D4;EGYPTIAN HIEROGLYPH-134D4;Lo;0;L;;;;;N;;;;;\n134D5;EGYPTIAN HIEROGLYPH-134D5;Lo;0;L;;;;;N;;;;;\n134D6;EGYPTIAN HIEROGLYPH-134D6;Lo;0;L;;;;;N;;;;;\n134D7;EGYPTIAN HIEROGLYPH-134D7;Lo;0;L;;;;;N;;;;;\n134D8;EGYPTIAN HIEROGLYPH-134D8;Lo;0;L;;;;;N;;;;;\n134D9;EGYPTIAN HIEROGLYPH-134D9;Lo;0;L;;;;;N;;;;;\n134DA;EGYPTIAN HIEROGLYPH-134DA;Lo;0;L;;;;;N;;;;;\n134DB;EGYPTIAN HIEROGLYPH-134DB;Lo;0;L;;;;;N;;;;;\n134DC;EGYPTIAN HIEROGLYPH-134DC;Lo;0;L;;;;;N;;;;;\n134DD;EGYPTIAN HIEROGLYPH-134DD;Lo;0;L;;;;;N;;;;;\n134DE;EGYPTIAN HIEROGLYPH-134DE;Lo;0;L;;;;;N;;;;;\n134DF;EGYPTIAN HIEROGLYPH-134DF;Lo;0;L;;;;;N;;;;;\n134E0;EGYPTIAN HIEROGLYPH-134E0;Lo;0;L;;;;;N;;;;;\n134E1;EGYPTIAN HIEROGLYPH-134E1;Lo;0;L;;;;;N;;;;;\n134E2;EGYPTIAN HIEROGLYPH-134E2;Lo;0;L;;;;;N;;;;;\n134E3;EGYPTIAN HIEROGLYPH-134E3;Lo;0;L;;;;;N;;;;;\n134E4;EGYPTIAN HIEROGLYPH-134E4;Lo;0;L;;;;;N;;;;;\n134E5;EGYPTIAN HIEROGLYPH-134E5;Lo;0;L;;;;;N;;;;;\n134E6;EGYPTIAN HIEROGLYPH-134E6;Lo;0;L;;;;;N;;;;;\n134E7;EGYPTIAN HIEROGLYPH-134E7;Lo;0;L;;;;;N;;;;;\n134E8;EGYPTIAN HIEROGLYPH-134E8;Lo;0;L;;;;;N;;;;;\n134E9;EGYPTIAN HIEROGLYPH-134E9;Lo;0;L;;;;;N;;;;;\n134EA;EGYPTIAN HIEROGLYPH-134EA;Lo;0;L;;;;;N;;;;;\n134EB;EGYPTIAN HIEROGLYPH-134EB;Lo;0;L;;;;;N;;;;;\n134EC;EGYPTIAN HIEROGLYPH-134EC;Lo;0;L;;;;;N;;;;;\n134ED;EGYPTIAN HIEROGLYPH-134ED;Lo;0;L;;;;;N;;;;;\n134EE;EGYPTIAN HIEROGLYPH-134EE;Lo;0;L;;;;;N;;;;;\n134EF;EGYPTIAN HIEROGLYPH-134EF;Lo;0;L;;;;;N;;;;;\n134F0;EGYPTIAN HIEROGLYPH-134F0;Lo;0;L;;;;;N;;;;;\n134F1;EGYPTIAN HIEROGLYPH-134F1;Lo;0;L;;;;;N;;;;;\n134F2;EGYPTIAN HIEROGLYPH-134F2;Lo;0;L;;;;;N;;;;;\n134F3;EGYPTIAN HIEROGLYPH-134F3;Lo;0;L;;;;;N;;;;;\n134F4;EGYPTIAN HIEROGLYPH-134F4;Lo;0;L;;;;;N;;;;;\n134F5;EGYPTIAN HIEROGLYPH-134F5;Lo;0;L;;;;;N;;;;;\n134F6;EGYPTIAN HIEROGLYPH-134F6;Lo;0;L;;;;;N;;;;;\n134F7;EGYPTIAN HIEROGLYPH-134F7;Lo;0;L;;;;;N;;;;;\n134F8;EGYPTIAN HIEROGLYPH-134F8;Lo;0;L;;;;;N;;;;;\n134F9;EGYPTIAN HIEROGLYPH-134F9;Lo;0;L;;;;;N;;;;;\n134FA;EGYPTIAN HIEROGLYPH-134FA;Lo;0;L;;;;;N;;;;;\n134FB;EGYPTIAN HIEROGLYPH-134FB;Lo;0;L;;;;;N;;;;;\n134FC;EGYPTIAN HIEROGLYPH-134FC;Lo;0;L;;;;;N;;;;;\n134FD;EGYPTIAN HIEROGLYPH-134FD;Lo;0;L;;;;;N;;;;;\n134FE;EGYPTIAN HIEROGLYPH-134FE;Lo;0;L;;;;;N;;;;;\n134FF;EGYPTIAN HIEROGLYPH-134FF;Lo;0;L;;;;;N;;;;;\n13500;EGYPTIAN HIEROGLYPH-13500;Lo;0;L;;;;;N;;;;;\n13501;EGYPTIAN HIEROGLYPH-13501;Lo;0;L;;;;;N;;;;;\n13502;EGYPTIAN HIEROGLYPH-13502;Lo;0;L;;;;;N;;;;;\n13503;EGYPTIAN HIEROGLYPH-13503;Lo;0;L;;;;;N;;;;;\n13504;EGYPTIAN HIEROGLYPH-13504;Lo;0;L;;;;;N;;;;;\n13505;EGYPTIAN HIEROGLYPH-13505;Lo;0;L;;;;;N;;;;;\n13506;EGYPTIAN HIEROGLYPH-13506;Lo;0;L;;;;;N;;;;;\n13507;EGYPTIAN HIEROGLYPH-13507;Lo;0;L;;;;;N;;;;;\n13508;EGYPTIAN HIEROGLYPH-13508;Lo;0;L;;;;;N;;;;;\n13509;EGYPTIAN HIEROGLYPH-13509;Lo;0;L;;;;;N;;;;;\n1350A;EGYPTIAN HIEROGLYPH-1350A;Lo;0;L;;;;;N;;;;;\n1350B;EGYPTIAN HIEROGLYPH-1350B;Lo;0;L;;;;;N;;;;;\n1350C;EGYPTIAN HIEROGLYPH-1350C;Lo;0;L;;;;;N;;;;;\n1350D;EGYPTIAN HIEROGLYPH-1350D;Lo;0;L;;;;;N;;;;;\n1350E;EGYPTIAN HIEROGLYPH-1350E;Lo;0;L;;;;;N;;;;;\n1350F;EGYPTIAN HIEROGLYPH-1350F;Lo;0;L;;;;;N;;;;;\n13510;EGYPTIAN HIEROGLYPH-13510;Lo;0;L;;;;;N;;;;;\n13511;EGYPTIAN HIEROGLYPH-13511;Lo;0;L;;;;;N;;;;;\n13512;EGYPTIAN HIEROGLYPH-13512;Lo;0;L;;;;;N;;;;;\n13513;EGYPTIAN HIEROGLYPH-13513;Lo;0;L;;;;;N;;;;;\n13514;EGYPTIAN HIEROGLYPH-13514;Lo;0;L;;;;;N;;;;;\n13515;EGYPTIAN HIEROGLYPH-13515;Lo;0;L;;;;;N;;;;;\n13516;EGYPTIAN HIEROGLYPH-13516;Lo;0;L;;;;;N;;;;;\n13517;EGYPTIAN HIEROGLYPH-13517;Lo;0;L;;;;;N;;;;;\n13518;EGYPTIAN HIEROGLYPH-13518;Lo;0;L;;;;;N;;;;;\n13519;EGYPTIAN HIEROGLYPH-13519;Lo;0;L;;;;;N;;;;;\n1351A;EGYPTIAN HIEROGLYPH-1351A;Lo;0;L;;;;;N;;;;;\n1351B;EGYPTIAN HIEROGLYPH-1351B;Lo;0;L;;;;;N;;;;;\n1351C;EGYPTIAN HIEROGLYPH-1351C;Lo;0;L;;;;;N;;;;;\n1351D;EGYPTIAN HIEROGLYPH-1351D;Lo;0;L;;;;;N;;;;;\n1351E;EGYPTIAN HIEROGLYPH-1351E;Lo;0;L;;;;;N;;;;;\n1351F;EGYPTIAN HIEROGLYPH-1351F;Lo;0;L;;;;;N;;;;;\n13520;EGYPTIAN HIEROGLYPH-13520;Lo;0;L;;;;;N;;;;;\n13521;EGYPTIAN HIEROGLYPH-13521;Lo;0;L;;;;;N;;;;;\n13522;EGYPTIAN HIEROGLYPH-13522;Lo;0;L;;;;;N;;;;;\n13523;EGYPTIAN HIEROGLYPH-13523;Lo;0;L;;;;;N;;;;;\n13524;EGYPTIAN HIEROGLYPH-13524;Lo;0;L;;;;;N;;;;;\n13525;EGYPTIAN HIEROGLYPH-13525;Lo;0;L;;;;;N;;;;;\n13526;EGYPTIAN HIEROGLYPH-13526;Lo;0;L;;;;;N;;;;;\n13527;EGYPTIAN HIEROGLYPH-13527;Lo;0;L;;;;;N;;;;;\n13528;EGYPTIAN HIEROGLYPH-13528;Lo;0;L;;;;;N;;;;;\n13529;EGYPTIAN HIEROGLYPH-13529;Lo;0;L;;;;;N;;;;;\n1352A;EGYPTIAN HIEROGLYPH-1352A;Lo;0;L;;;;;N;;;;;\n1352B;EGYPTIAN HIEROGLYPH-1352B;Lo;0;L;;;;;N;;;;;\n1352C;EGYPTIAN HIEROGLYPH-1352C;Lo;0;L;;;;;N;;;;;\n1352D;EGYPTIAN HIEROGLYPH-1352D;Lo;0;L;;;;;N;;;;;\n1352E;EGYPTIAN HIEROGLYPH-1352E;Lo;0;L;;;;;N;;;;;\n1352F;EGYPTIAN HIEROGLYPH-1352F;Lo;0;L;;;;;N;;;;;\n13530;EGYPTIAN HIEROGLYPH-13530;Lo;0;L;;;;;N;;;;;\n13531;EGYPTIAN HIEROGLYPH-13531;Lo;0;L;;;;;N;;;;;\n13532;EGYPTIAN HIEROGLYPH-13532;Lo;0;L;;;;;N;;;;;\n13533;EGYPTIAN HIEROGLYPH-13533;Lo;0;L;;;;;N;;;;;\n13534;EGYPTIAN HIEROGLYPH-13534;Lo;0;L;;;;;N;;;;;\n13535;EGYPTIAN HIEROGLYPH-13535;Lo;0;L;;;;;N;;;;;\n13536;EGYPTIAN HIEROGLYPH-13536;Lo;0;L;;;;;N;;;;;\n13537;EGYPTIAN HIEROGLYPH-13537;Lo;0;L;;;;;N;;;;;\n13538;EGYPTIAN HIEROGLYPH-13538;Lo;0;L;;;;;N;;;;;\n13539;EGYPTIAN HIEROGLYPH-13539;Lo;0;L;;;;;N;;;;;\n1353A;EGYPTIAN HIEROGLYPH-1353A;Lo;0;L;;;;;N;;;;;\n1353B;EGYPTIAN HIEROGLYPH-1353B;Lo;0;L;;;;;N;;;;;\n1353C;EGYPTIAN HIEROGLYPH-1353C;Lo;0;L;;;;;N;;;;;\n1353D;EGYPTIAN HIEROGLYPH-1353D;Lo;0;L;;;;;N;;;;;\n1353E;EGYPTIAN HIEROGLYPH-1353E;Lo;0;L;;;;;N;;;;;\n1353F;EGYPTIAN HIEROGLYPH-1353F;Lo;0;L;;;;;N;;;;;\n13540;EGYPTIAN HIEROGLYPH-13540;Lo;0;L;;;;;N;;;;;\n13541;EGYPTIAN HIEROGLYPH-13541;Lo;0;L;;;;;N;;;;;\n13542;EGYPTIAN HIEROGLYPH-13542;Lo;0;L;;;;;N;;;;;\n13543;EGYPTIAN HIEROGLYPH-13543;Lo;0;L;;;;;N;;;;;\n13544;EGYPTIAN HIEROGLYPH-13544;Lo;0;L;;;;;N;;;;;\n13545;EGYPTIAN HIEROGLYPH-13545;Lo;0;L;;;;;N;;;;;\n13546;EGYPTIAN HIEROGLYPH-13546;Lo;0;L;;;;;N;;;;;\n13547;EGYPTIAN HIEROGLYPH-13547;Lo;0;L;;;;;N;;;;;\n13548;EGYPTIAN HIEROGLYPH-13548;Lo;0;L;;;;;N;;;;;\n13549;EGYPTIAN HIEROGLYPH-13549;Lo;0;L;;;;;N;;;;;\n1354A;EGYPTIAN HIEROGLYPH-1354A;Lo;0;L;;;;;N;;;;;\n1354B;EGYPTIAN HIEROGLYPH-1354B;Lo;0;L;;;;;N;;;;;\n1354C;EGYPTIAN HIEROGLYPH-1354C;Lo;0;L;;;;;N;;;;;\n1354D;EGYPTIAN HIEROGLYPH-1354D;Lo;0;L;;;;;N;;;;;\n1354E;EGYPTIAN HIEROGLYPH-1354E;Lo;0;L;;;;;N;;;;;\n1354F;EGYPTIAN HIEROGLYPH-1354F;Lo;0;L;;;;;N;;;;;\n13550;EGYPTIAN HIEROGLYPH-13550;Lo;0;L;;;;;N;;;;;\n13551;EGYPTIAN HIEROGLYPH-13551;Lo;0;L;;;;;N;;;;;\n13552;EGYPTIAN HIEROGLYPH-13552;Lo;0;L;;;;;N;;;;;\n13553;EGYPTIAN HIEROGLYPH-13553;Lo;0;L;;;;;N;;;;;\n13554;EGYPTIAN HIEROGLYPH-13554;Lo;0;L;;;;;N;;;;;\n13555;EGYPTIAN HIEROGLYPH-13555;Lo;0;L;;;;;N;;;;;\n13556;EGYPTIAN HIEROGLYPH-13556;Lo;0;L;;;;;N;;;;;\n13557;EGYPTIAN HIEROGLYPH-13557;Lo;0;L;;;;;N;;;;;\n13558;EGYPTIAN HIEROGLYPH-13558;Lo;0;L;;;;;N;;;;;\n13559;EGYPTIAN HIEROGLYPH-13559;Lo;0;L;;;;;N;;;;;\n1355A;EGYPTIAN HIEROGLYPH-1355A;Lo;0;L;;;;;N;;;;;\n1355B;EGYPTIAN HIEROGLYPH-1355B;Lo;0;L;;;;;N;;;;;\n1355C;EGYPTIAN HIEROGLYPH-1355C;Lo;0;L;;;;;N;;;;;\n1355D;EGYPTIAN HIEROGLYPH-1355D;Lo;0;L;;;;;N;;;;;\n1355E;EGYPTIAN HIEROGLYPH-1355E;Lo;0;L;;;;;N;;;;;\n1355F;EGYPTIAN HIEROGLYPH-1355F;Lo;0;L;;;;;N;;;;;\n13560;EGYPTIAN HIEROGLYPH-13560;Lo;0;L;;;;;N;;;;;\n13561;EGYPTIAN HIEROGLYPH-13561;Lo;0;L;;;;;N;;;;;\n13562;EGYPTIAN HIEROGLYPH-13562;Lo;0;L;;;;;N;;;;;\n13563;EGYPTIAN HIEROGLYPH-13563;Lo;0;L;;;;;N;;;;;\n13564;EGYPTIAN HIEROGLYPH-13564;Lo;0;L;;;;;N;;;;;\n13565;EGYPTIAN HIEROGLYPH-13565;Lo;0;L;;;;;N;;;;;\n13566;EGYPTIAN HIEROGLYPH-13566;Lo;0;L;;;;;N;;;;;\n13567;EGYPTIAN HIEROGLYPH-13567;Lo;0;L;;;;;N;;;;;\n13568;EGYPTIAN HIEROGLYPH-13568;Lo;0;L;;;;;N;;;;;\n13569;EGYPTIAN HIEROGLYPH-13569;Lo;0;L;;;;;N;;;;;\n1356A;EGYPTIAN HIEROGLYPH-1356A;Lo;0;L;;;;;N;;;;;\n1356B;EGYPTIAN HIEROGLYPH-1356B;Lo;0;L;;;;;N;;;;;\n1356C;EGYPTIAN HIEROGLYPH-1356C;Lo;0;L;;;;;N;;;;;\n1356D;EGYPTIAN HIEROGLYPH-1356D;Lo;0;L;;;;;N;;;;;\n1356E;EGYPTIAN HIEROGLYPH-1356E;Lo;0;L;;;;;N;;;;;\n1356F;EGYPTIAN HIEROGLYPH-1356F;Lo;0;L;;;;;N;;;;;\n13570;EGYPTIAN HIEROGLYPH-13570;Lo;0;L;;;;;N;;;;;\n13571;EGYPTIAN HIEROGLYPH-13571;Lo;0;L;;;;;N;;;;;\n13572;EGYPTIAN HIEROGLYPH-13572;Lo;0;L;;;;;N;;;;;\n13573;EGYPTIAN HIEROGLYPH-13573;Lo;0;L;;;;;N;;;;;\n13574;EGYPTIAN HIEROGLYPH-13574;Lo;0;L;;;;;N;;;;;\n13575;EGYPTIAN HIEROGLYPH-13575;Lo;0;L;;;;;N;;;;;\n13576;EGYPTIAN HIEROGLYPH-13576;Lo;0;L;;;;;N;;;;;\n13577;EGYPTIAN HIEROGLYPH-13577;Lo;0;L;;;;;N;;;;;\n13578;EGYPTIAN HIEROGLYPH-13578;Lo;0;L;;;;;N;;;;;\n13579;EGYPTIAN HIEROGLYPH-13579;Lo;0;L;;;;;N;;;;;\n1357A;EGYPTIAN HIEROGLYPH-1357A;Lo;0;L;;;;;N;;;;;\n1357B;EGYPTIAN HIEROGLYPH-1357B;Lo;0;L;;;;;N;;;;;\n1357C;EGYPTIAN HIEROGLYPH-1357C;Lo;0;L;;;;;N;;;;;\n1357D;EGYPTIAN HIEROGLYPH-1357D;Lo;0;L;;;;;N;;;;;\n1357E;EGYPTIAN HIEROGLYPH-1357E;Lo;0;L;;;;;N;;;;;\n1357F;EGYPTIAN HIEROGLYPH-1357F;Lo;0;L;;;;;N;;;;;\n13580;EGYPTIAN HIEROGLYPH-13580;Lo;0;L;;;;;N;;;;;\n13581;EGYPTIAN HIEROGLYPH-13581;Lo;0;L;;;;;N;;;;;\n13582;EGYPTIAN HIEROGLYPH-13582;Lo;0;L;;;;;N;;;;;\n13583;EGYPTIAN HIEROGLYPH-13583;Lo;0;L;;;;;N;;;;;\n13584;EGYPTIAN HIEROGLYPH-13584;Lo;0;L;;;;;N;;;;;\n13585;EGYPTIAN HIEROGLYPH-13585;Lo;0;L;;;;;N;;;;;\n13586;EGYPTIAN HIEROGLYPH-13586;Lo;0;L;;;;;N;;;;;\n13587;EGYPTIAN HIEROGLYPH-13587;Lo;0;L;;;;;N;;;;;\n13588;EGYPTIAN HIEROGLYPH-13588;Lo;0;L;;;;;N;;;;;\n13589;EGYPTIAN HIEROGLYPH-13589;Lo;0;L;;;;;N;;;;;\n1358A;EGYPTIAN HIEROGLYPH-1358A;Lo;0;L;;;;;N;;;;;\n1358B;EGYPTIAN HIEROGLYPH-1358B;Lo;0;L;;;;;N;;;;;\n1358C;EGYPTIAN HIEROGLYPH-1358C;Lo;0;L;;;;;N;;;;;\n1358D;EGYPTIAN HIEROGLYPH-1358D;Lo;0;L;;;;;N;;;;;\n1358E;EGYPTIAN HIEROGLYPH-1358E;Lo;0;L;;;;;N;;;;;\n1358F;EGYPTIAN HIEROGLYPH-1358F;Lo;0;L;;;;;N;;;;;\n13590;EGYPTIAN HIEROGLYPH-13590;Lo;0;L;;;;;N;;;;;\n13591;EGYPTIAN HIEROGLYPH-13591;Lo;0;L;;;;;N;;;;;\n13592;EGYPTIAN HIEROGLYPH-13592;Lo;0;L;;;;;N;;;;;\n13593;EGYPTIAN HIEROGLYPH-13593;Lo;0;L;;;;;N;;;;;\n13594;EGYPTIAN HIEROGLYPH-13594;Lo;0;L;;;;;N;;;;;\n13595;EGYPTIAN HIEROGLYPH-13595;Lo;0;L;;;;;N;;;;;\n13596;EGYPTIAN HIEROGLYPH-13596;Lo;0;L;;;;;N;;;;;\n13597;EGYPTIAN HIEROGLYPH-13597;Lo;0;L;;;;;N;;;;;\n13598;EGYPTIAN HIEROGLYPH-13598;Lo;0;L;;;;;N;;;;;\n13599;EGYPTIAN HIEROGLYPH-13599;Lo;0;L;;;;;N;;;;;\n1359A;EGYPTIAN HIEROGLYPH-1359A;Lo;0;L;;;;;N;;;;;\n1359B;EGYPTIAN HIEROGLYPH-1359B;Lo;0;L;;;;;N;;;;;\n1359C;EGYPTIAN HIEROGLYPH-1359C;Lo;0;L;;;;;N;;;;;\n1359D;EGYPTIAN HIEROGLYPH-1359D;Lo;0;L;;;;;N;;;;;\n1359E;EGYPTIAN HIEROGLYPH-1359E;Lo;0;L;;;;;N;;;;;\n1359F;EGYPTIAN HIEROGLYPH-1359F;Lo;0;L;;;;;N;;;;;\n135A0;EGYPTIAN HIEROGLYPH-135A0;Lo;0;L;;;;;N;;;;;\n135A1;EGYPTIAN HIEROGLYPH-135A1;Lo;0;L;;;;;N;;;;;\n135A2;EGYPTIAN HIEROGLYPH-135A2;Lo;0;L;;;;;N;;;;;\n135A3;EGYPTIAN HIEROGLYPH-135A3;Lo;0;L;;;;;N;;;;;\n135A4;EGYPTIAN HIEROGLYPH-135A4;Lo;0;L;;;;;N;;;;;\n135A5;EGYPTIAN HIEROGLYPH-135A5;Lo;0;L;;;;;N;;;;;\n135A6;EGYPTIAN HIEROGLYPH-135A6;Lo;0;L;;;;;N;;;;;\n135A7;EGYPTIAN HIEROGLYPH-135A7;Lo;0;L;;;;;N;;;;;\n135A8;EGYPTIAN HIEROGLYPH-135A8;Lo;0;L;;;;;N;;;;;\n135A9;EGYPTIAN HIEROGLYPH-135A9;Lo;0;L;;;;;N;;;;;\n135AA;EGYPTIAN HIEROGLYPH-135AA;Lo;0;L;;;;;N;;;;;\n135AB;EGYPTIAN HIEROGLYPH-135AB;Lo;0;L;;;;;N;;;;;\n135AC;EGYPTIAN HIEROGLYPH-135AC;Lo;0;L;;;;;N;;;;;\n135AD;EGYPTIAN HIEROGLYPH-135AD;Lo;0;L;;;;;N;;;;;\n135AE;EGYPTIAN HIEROGLYPH-135AE;Lo;0;L;;;;;N;;;;;\n135AF;EGYPTIAN HIEROGLYPH-135AF;Lo;0;L;;;;;N;;;;;\n135B0;EGYPTIAN HIEROGLYPH-135B0;Lo;0;L;;;;;N;;;;;\n135B1;EGYPTIAN HIEROGLYPH-135B1;Lo;0;L;;;;;N;;;;;\n135B2;EGYPTIAN HIEROGLYPH-135B2;Lo;0;L;;;;;N;;;;;\n135B3;EGYPTIAN HIEROGLYPH-135B3;Lo;0;L;;;;;N;;;;;\n135B4;EGYPTIAN HIEROGLYPH-135B4;Lo;0;L;;;;;N;;;;;\n135B5;EGYPTIAN HIEROGLYPH-135B5;Lo;0;L;;;;;N;;;;;\n135B6;EGYPTIAN HIEROGLYPH-135B6;Lo;0;L;;;;;N;;;;;\n135B7;EGYPTIAN HIEROGLYPH-135B7;Lo;0;L;;;;;N;;;;;\n135B8;EGYPTIAN HIEROGLYPH-135B8;Lo;0;L;;;;;N;;;;;\n135B9;EGYPTIAN HIEROGLYPH-135B9;Lo;0;L;;;;;N;;;;;\n135BA;EGYPTIAN HIEROGLYPH-135BA;Lo;0;L;;;;;N;;;;;\n135BB;EGYPTIAN HIEROGLYPH-135BB;Lo;0;L;;;;;N;;;;;\n135BC;EGYPTIAN HIEROGLYPH-135BC;Lo;0;L;;;;;N;;;;;\n135BD;EGYPTIAN HIEROGLYPH-135BD;Lo;0;L;;;;;N;;;;;\n135BE;EGYPTIAN HIEROGLYPH-135BE;Lo;0;L;;;;;N;;;;;\n135BF;EGYPTIAN HIEROGLYPH-135BF;Lo;0;L;;;;;N;;;;;\n135C0;EGYPTIAN HIEROGLYPH-135C0;Lo;0;L;;;;;N;;;;;\n135C1;EGYPTIAN HIEROGLYPH-135C1;Lo;0;L;;;;;N;;;;;\n135C2;EGYPTIAN HIEROGLYPH-135C2;Lo;0;L;;;;;N;;;;;\n135C3;EGYPTIAN HIEROGLYPH-135C3;Lo;0;L;;;;;N;;;;;\n135C4;EGYPTIAN HIEROGLYPH-135C4;Lo;0;L;;;;;N;;;;;\n135C5;EGYPTIAN HIEROGLYPH-135C5;Lo;0;L;;;;;N;;;;;\n135C6;EGYPTIAN HIEROGLYPH-135C6;Lo;0;L;;;;;N;;;;;\n135C7;EGYPTIAN HIEROGLYPH-135C7;Lo;0;L;;;;;N;;;;;\n135C8;EGYPTIAN HIEROGLYPH-135C8;Lo;0;L;;;;;N;;;;;\n135C9;EGYPTIAN HIEROGLYPH-135C9;Lo;0;L;;;;;N;;;;;\n135CA;EGYPTIAN HIEROGLYPH-135CA;Lo;0;L;;;;;N;;;;;\n135CB;EGYPTIAN HIEROGLYPH-135CB;Lo;0;L;;;;;N;;;;;\n135CC;EGYPTIAN HIEROGLYPH-135CC;Lo;0;L;;;;;N;;;;;\n135CD;EGYPTIAN HIEROGLYPH-135CD;Lo;0;L;;;;;N;;;;;\n135CE;EGYPTIAN HIEROGLYPH-135CE;Lo;0;L;;;;;N;;;;;\n135CF;EGYPTIAN HIEROGLYPH-135CF;Lo;0;L;;;;;N;;;;;\n135D0;EGYPTIAN HIEROGLYPH-135D0;Lo;0;L;;;;;N;;;;;\n135D1;EGYPTIAN HIEROGLYPH-135D1;Lo;0;L;;;;;N;;;;;\n135D2;EGYPTIAN HIEROGLYPH-135D2;Lo;0;L;;;;;N;;;;;\n135D3;EGYPTIAN HIEROGLYPH-135D3;Lo;0;L;;;;;N;;;;;\n135D4;EGYPTIAN HIEROGLYPH-135D4;Lo;0;L;;;;;N;;;;;\n135D5;EGYPTIAN HIEROGLYPH-135D5;Lo;0;L;;;;;N;;;;;\n135D6;EGYPTIAN HIEROGLYPH-135D6;Lo;0;L;;;;;N;;;;;\n135D7;EGYPTIAN HIEROGLYPH-135D7;Lo;0;L;;;;;N;;;;;\n135D8;EGYPTIAN HIEROGLYPH-135D8;Lo;0;L;;;;;N;;;;;\n135D9;EGYPTIAN HIEROGLYPH-135D9;Lo;0;L;;;;;N;;;;;\n135DA;EGYPTIAN HIEROGLYPH-135DA;Lo;0;L;;;;;N;;;;;\n135DB;EGYPTIAN HIEROGLYPH-135DB;Lo;0;L;;;;;N;;;;;\n135DC;EGYPTIAN HIEROGLYPH-135DC;Lo;0;L;;;;;N;;;;;\n135DD;EGYPTIAN HIEROGLYPH-135DD;Lo;0;L;;;;;N;;;;;\n135DE;EGYPTIAN HIEROGLYPH-135DE;Lo;0;L;;;;;N;;;;;\n135DF;EGYPTIAN HIEROGLYPH-135DF;Lo;0;L;;;;;N;;;;;\n135E0;EGYPTIAN HIEROGLYPH-135E0;Lo;0;L;;;;;N;;;;;\n135E1;EGYPTIAN HIEROGLYPH-135E1;Lo;0;L;;;;;N;;;;;\n135E2;EGYPTIAN HIEROGLYPH-135E2;Lo;0;L;;;;;N;;;;;\n135E3;EGYPTIAN HIEROGLYPH-135E3;Lo;0;L;;;;;N;;;;;\n135E4;EGYPTIAN HIEROGLYPH-135E4;Lo;0;L;;;;;N;;;;;\n135E5;EGYPTIAN HIEROGLYPH-135E5;Lo;0;L;;;;;N;;;;;\n135E6;EGYPTIAN HIEROGLYPH-135E6;Lo;0;L;;;;;N;;;;;\n135E7;EGYPTIAN HIEROGLYPH-135E7;Lo;0;L;;;;;N;;;;;\n135E8;EGYPTIAN HIEROGLYPH-135E8;Lo;0;L;;;;;N;;;;;\n135E9;EGYPTIAN HIEROGLYPH-135E9;Lo;0;L;;;;;N;;;;;\n135EA;EGYPTIAN HIEROGLYPH-135EA;Lo;0;L;;;;;N;;;;;\n135EB;EGYPTIAN HIEROGLYPH-135EB;Lo;0;L;;;;;N;;;;;\n135EC;EGYPTIAN HIEROGLYPH-135EC;Lo;0;L;;;;;N;;;;;\n135ED;EGYPTIAN HIEROGLYPH-135ED;Lo;0;L;;;;;N;;;;;\n135EE;EGYPTIAN HIEROGLYPH-135EE;Lo;0;L;;;;;N;;;;;\n135EF;EGYPTIAN HIEROGLYPH-135EF;Lo;0;L;;;;;N;;;;;\n135F0;EGYPTIAN HIEROGLYPH-135F0;Lo;0;L;;;;;N;;;;;\n135F1;EGYPTIAN HIEROGLYPH-135F1;Lo;0;L;;;;;N;;;;;\n135F2;EGYPTIAN HIEROGLYPH-135F2;Lo;0;L;;;;;N;;;;;\n135F3;EGYPTIAN HIEROGLYPH-135F3;Lo;0;L;;;;;N;;;;;\n135F4;EGYPTIAN HIEROGLYPH-135F4;Lo;0;L;;;;;N;;;;;\n135F5;EGYPTIAN HIEROGLYPH-135F5;Lo;0;L;;;;;N;;;;;\n135F6;EGYPTIAN HIEROGLYPH-135F6;Lo;0;L;;;;;N;;;;;\n135F7;EGYPTIAN HIEROGLYPH-135F7;Lo;0;L;;;;;N;;;;;\n135F8;EGYPTIAN HIEROGLYPH-135F8;Lo;0;L;;;;;N;;;;;\n135F9;EGYPTIAN HIEROGLYPH-135F9;Lo;0;L;;;;;N;;;;;\n135FA;EGYPTIAN HIEROGLYPH-135FA;Lo;0;L;;;;;N;;;;;\n135FB;EGYPTIAN HIEROGLYPH-135FB;Lo;0;L;;;;;N;;;;;\n135FC;EGYPTIAN HIEROGLYPH-135FC;Lo;0;L;;;;;N;;;;;\n135FD;EGYPTIAN HIEROGLYPH-135FD;Lo;0;L;;;;;N;;;;;\n135FE;EGYPTIAN HIEROGLYPH-135FE;Lo;0;L;;;;;N;;;;;\n135FF;EGYPTIAN HIEROGLYPH-135FF;Lo;0;L;;;;;N;;;;;\n13600;EGYPTIAN HIEROGLYPH-13600;Lo;0;L;;;;;N;;;;;\n13601;EGYPTIAN HIEROGLYPH-13601;Lo;0;L;;;;;N;;;;;\n13602;EGYPTIAN HIEROGLYPH-13602;Lo;0;L;;;;;N;;;;;\n13603;EGYPTIAN HIEROGLYPH-13603;Lo;0;L;;;;;N;;;;;\n13604;EGYPTIAN HIEROGLYPH-13604;Lo;0;L;;;;;N;;;;;\n13605;EGYPTIAN HIEROGLYPH-13605;Lo;0;L;;;;;N;;;;;\n13606;EGYPTIAN HIEROGLYPH-13606;Lo;0;L;;;;;N;;;;;\n13607;EGYPTIAN HIEROGLYPH-13607;Lo;0;L;;;;;N;;;;;\n13608;EGYPTIAN HIEROGLYPH-13608;Lo;0;L;;;;;N;;;;;\n13609;EGYPTIAN HIEROGLYPH-13609;Lo;0;L;;;;;N;;;;;\n1360A;EGYPTIAN HIEROGLYPH-1360A;Lo;0;L;;;;;N;;;;;\n1360B;EGYPTIAN HIEROGLYPH-1360B;Lo;0;L;;;;;N;;;;;\n1360C;EGYPTIAN HIEROGLYPH-1360C;Lo;0;L;;;;;N;;;;;\n1360D;EGYPTIAN HIEROGLYPH-1360D;Lo;0;L;;;;;N;;;;;\n1360E;EGYPTIAN HIEROGLYPH-1360E;Lo;0;L;;;;;N;;;;;\n1360F;EGYPTIAN HIEROGLYPH-1360F;Lo;0;L;;;;;N;;;;;\n13610;EGYPTIAN HIEROGLYPH-13610;Lo;0;L;;;;;N;;;;;\n13611;EGYPTIAN HIEROGLYPH-13611;Lo;0;L;;;;;N;;;;;\n13612;EGYPTIAN HIEROGLYPH-13612;Lo;0;L;;;;;N;;;;;\n13613;EGYPTIAN HIEROGLYPH-13613;Lo;0;L;;;;;N;;;;;\n13614;EGYPTIAN HIEROGLYPH-13614;Lo;0;L;;;;;N;;;;;\n13615;EGYPTIAN HIEROGLYPH-13615;Lo;0;L;;;;;N;;;;;\n13616;EGYPTIAN HIEROGLYPH-13616;Lo;0;L;;;;;N;;;;;\n13617;EGYPTIAN HIEROGLYPH-13617;Lo;0;L;;;;;N;;;;;\n13618;EGYPTIAN HIEROGLYPH-13618;Lo;0;L;;;;;N;;;;;\n13619;EGYPTIAN HIEROGLYPH-13619;Lo;0;L;;;;;N;;;;;\n1361A;EGYPTIAN HIEROGLYPH-1361A;Lo;0;L;;;;;N;;;;;\n1361B;EGYPTIAN HIEROGLYPH-1361B;Lo;0;L;;;;;N;;;;;\n1361C;EGYPTIAN HIEROGLYPH-1361C;Lo;0;L;;;;;N;;;;;\n1361D;EGYPTIAN HIEROGLYPH-1361D;Lo;0;L;;;;;N;;;;;\n1361E;EGYPTIAN HIEROGLYPH-1361E;Lo;0;L;;;;;N;;;;;\n1361F;EGYPTIAN HIEROGLYPH-1361F;Lo;0;L;;;;;N;;;;;\n13620;EGYPTIAN HIEROGLYPH-13620;Lo;0;L;;;;;N;;;;;\n13621;EGYPTIAN HIEROGLYPH-13621;Lo;0;L;;;;;N;;;;;\n13622;EGYPTIAN HIEROGLYPH-13622;Lo;0;L;;;;;N;;;;;\n13623;EGYPTIAN HIEROGLYPH-13623;Lo;0;L;;;;;N;;;;;\n13624;EGYPTIAN HIEROGLYPH-13624;Lo;0;L;;;;;N;;;;;\n13625;EGYPTIAN HIEROGLYPH-13625;Lo;0;L;;;;;N;;;;;\n13626;EGYPTIAN HIEROGLYPH-13626;Lo;0;L;;;;;N;;;;;\n13627;EGYPTIAN HIEROGLYPH-13627;Lo;0;L;;;;;N;;;;;\n13628;EGYPTIAN HIEROGLYPH-13628;Lo;0;L;;;;;N;;;;;\n13629;EGYPTIAN HIEROGLYPH-13629;Lo;0;L;;;;;N;;;;;\n1362A;EGYPTIAN HIEROGLYPH-1362A;Lo;0;L;;;;;N;;;;;\n1362B;EGYPTIAN HIEROGLYPH-1362B;Lo;0;L;;;;;N;;;;;\n1362C;EGYPTIAN HIEROGLYPH-1362C;Lo;0;L;;;;;N;;;;;\n1362D;EGYPTIAN HIEROGLYPH-1362D;Lo;0;L;;;;;N;;;;;\n1362E;EGYPTIAN HIEROGLYPH-1362E;Lo;0;L;;;;;N;;;;;\n1362F;EGYPTIAN HIEROGLYPH-1362F;Lo;0;L;;;;;N;;;;;\n13630;EGYPTIAN HIEROGLYPH-13630;Lo;0;L;;;;;N;;;;;\n13631;EGYPTIAN HIEROGLYPH-13631;Lo;0;L;;;;;N;;;;;\n13632;EGYPTIAN HIEROGLYPH-13632;Lo;0;L;;;;;N;;;;;\n13633;EGYPTIAN HIEROGLYPH-13633;Lo;0;L;;;;;N;;;;;\n13634;EGYPTIAN HIEROGLYPH-13634;Lo;0;L;;;;;N;;;;;\n13635;EGYPTIAN HIEROGLYPH-13635;Lo;0;L;;;;;N;;;;;\n13636;EGYPTIAN HIEROGLYPH-13636;Lo;0;L;;;;;N;;;;;\n13637;EGYPTIAN HIEROGLYPH-13637;Lo;0;L;;;;;N;;;;;\n13638;EGYPTIAN HIEROGLYPH-13638;Lo;0;L;;;;;N;;;;;\n13639;EGYPTIAN HIEROGLYPH-13639;Lo;0;L;;;;;N;;;;;\n1363A;EGYPTIAN HIEROGLYPH-1363A;Lo;0;L;;;;;N;;;;;\n1363B;EGYPTIAN HIEROGLYPH-1363B;Lo;0;L;;;;;N;;;;;\n1363C;EGYPTIAN HIEROGLYPH-1363C;Lo;0;L;;;;;N;;;;;\n1363D;EGYPTIAN HIEROGLYPH-1363D;Lo;0;L;;;;;N;;;;;\n1363E;EGYPTIAN HIEROGLYPH-1363E;Lo;0;L;;;;;N;;;;;\n1363F;EGYPTIAN HIEROGLYPH-1363F;Lo;0;L;;;;;N;;;;;\n13640;EGYPTIAN HIEROGLYPH-13640;Lo;0;L;;;;;N;;;;;\n13641;EGYPTIAN HIEROGLYPH-13641;Lo;0;L;;;;;N;;;;;\n13642;EGYPTIAN HIEROGLYPH-13642;Lo;0;L;;;;;N;;;;;\n13643;EGYPTIAN HIEROGLYPH-13643;Lo;0;L;;;;;N;;;;;\n13644;EGYPTIAN HIEROGLYPH-13644;Lo;0;L;;;;;N;;;;;\n13645;EGYPTIAN HIEROGLYPH-13645;Lo;0;L;;;;;N;;;;;\n13646;EGYPTIAN HIEROGLYPH-13646;Lo;0;L;;;;;N;;;;;\n13647;EGYPTIAN HIEROGLYPH-13647;Lo;0;L;;;;;N;;;;;\n13648;EGYPTIAN HIEROGLYPH-13648;Lo;0;L;;;;;N;;;;;\n13649;EGYPTIAN HIEROGLYPH-13649;Lo;0;L;;;;;N;;;;;\n1364A;EGYPTIAN HIEROGLYPH-1364A;Lo;0;L;;;;;N;;;;;\n1364B;EGYPTIAN HIEROGLYPH-1364B;Lo;0;L;;;;;N;;;;;\n1364C;EGYPTIAN HIEROGLYPH-1364C;Lo;0;L;;;;;N;;;;;\n1364D;EGYPTIAN HIEROGLYPH-1364D;Lo;0;L;;;;;N;;;;;\n1364E;EGYPTIAN HIEROGLYPH-1364E;Lo;0;L;;;;;N;;;;;\n1364F;EGYPTIAN HIEROGLYPH-1364F;Lo;0;L;;;;;N;;;;;\n13650;EGYPTIAN HIEROGLYPH-13650;Lo;0;L;;;;;N;;;;;\n13651;EGYPTIAN HIEROGLYPH-13651;Lo;0;L;;;;;N;;;;;\n13652;EGYPTIAN HIEROGLYPH-13652;Lo;0;L;;;;;N;;;;;\n13653;EGYPTIAN HIEROGLYPH-13653;Lo;0;L;;;;;N;;;;;\n13654;EGYPTIAN HIEROGLYPH-13654;Lo;0;L;;;;;N;;;;;\n13655;EGYPTIAN HIEROGLYPH-13655;Lo;0;L;;;;;N;;;;;\n13656;EGYPTIAN HIEROGLYPH-13656;Lo;0;L;;;;;N;;;;;\n13657;EGYPTIAN HIEROGLYPH-13657;Lo;0;L;;;;;N;;;;;\n13658;EGYPTIAN HIEROGLYPH-13658;Lo;0;L;;;;;N;;;;;\n13659;EGYPTIAN HIEROGLYPH-13659;Lo;0;L;;;;;N;;;;;\n1365A;EGYPTIAN HIEROGLYPH-1365A;Lo;0;L;;;;;N;;;;;\n1365B;EGYPTIAN HIEROGLYPH-1365B;Lo;0;L;;;;;N;;;;;\n1365C;EGYPTIAN HIEROGLYPH-1365C;Lo;0;L;;;;;N;;;;;\n1365D;EGYPTIAN HIEROGLYPH-1365D;Lo;0;L;;;;;N;;;;;\n1365E;EGYPTIAN HIEROGLYPH-1365E;Lo;0;L;;;;;N;;;;;\n1365F;EGYPTIAN HIEROGLYPH-1365F;Lo;0;L;;;;;N;;;;;\n13660;EGYPTIAN HIEROGLYPH-13660;Lo;0;L;;;;;N;;;;;\n13661;EGYPTIAN HIEROGLYPH-13661;Lo;0;L;;;;;N;;;;;\n13662;EGYPTIAN HIEROGLYPH-13662;Lo;0;L;;;;;N;;;;;\n13663;EGYPTIAN HIEROGLYPH-13663;Lo;0;L;;;;;N;;;;;\n13664;EGYPTIAN HIEROGLYPH-13664;Lo;0;L;;;;;N;;;;;\n13665;EGYPTIAN HIEROGLYPH-13665;Lo;0;L;;;;;N;;;;;\n13666;EGYPTIAN HIEROGLYPH-13666;Lo;0;L;;;;;N;;;;;\n13667;EGYPTIAN HIEROGLYPH-13667;Lo;0;L;;;;;N;;;;;\n13668;EGYPTIAN HIEROGLYPH-13668;Lo;0;L;;;;;N;;;;;\n13669;EGYPTIAN HIEROGLYPH-13669;Lo;0;L;;;;;N;;;;;\n1366A;EGYPTIAN HIEROGLYPH-1366A;Lo;0;L;;;;;N;;;;;\n1366B;EGYPTIAN HIEROGLYPH-1366B;Lo;0;L;;;;;N;;;;;\n1366C;EGYPTIAN HIEROGLYPH-1366C;Lo;0;L;;;;;N;;;;;\n1366D;EGYPTIAN HIEROGLYPH-1366D;Lo;0;L;;;;;N;;;;;\n1366E;EGYPTIAN HIEROGLYPH-1366E;Lo;0;L;;;;;N;;;;;\n1366F;EGYPTIAN HIEROGLYPH-1366F;Lo;0;L;;;;;N;;;;;\n13670;EGYPTIAN HIEROGLYPH-13670;Lo;0;L;;;;;N;;;;;\n13671;EGYPTIAN HIEROGLYPH-13671;Lo;0;L;;;;;N;;;;;\n13672;EGYPTIAN HIEROGLYPH-13672;Lo;0;L;;;;;N;;;;;\n13673;EGYPTIAN HIEROGLYPH-13673;Lo;0;L;;;;;N;;;;;\n13674;EGYPTIAN HIEROGLYPH-13674;Lo;0;L;;;;;N;;;;;\n13675;EGYPTIAN HIEROGLYPH-13675;Lo;0;L;;;;;N;;;;;\n13676;EGYPTIAN HIEROGLYPH-13676;Lo;0;L;;;;;N;;;;;\n13677;EGYPTIAN HIEROGLYPH-13677;Lo;0;L;;;;;N;;;;;\n13678;EGYPTIAN HIEROGLYPH-13678;Lo;0;L;;;;;N;;;;;\n13679;EGYPTIAN HIEROGLYPH-13679;Lo;0;L;;;;;N;;;;;\n1367A;EGYPTIAN HIEROGLYPH-1367A;Lo;0;L;;;;;N;;;;;\n1367B;EGYPTIAN HIEROGLYPH-1367B;Lo;0;L;;;;;N;;;;;\n1367C;EGYPTIAN HIEROGLYPH-1367C;Lo;0;L;;;;;N;;;;;\n1367D;EGYPTIAN HIEROGLYPH-1367D;Lo;0;L;;;;;N;;;;;\n1367E;EGYPTIAN HIEROGLYPH-1367E;Lo;0;L;;;;;N;;;;;\n1367F;EGYPTIAN HIEROGLYPH-1367F;Lo;0;L;;;;;N;;;;;\n13680;EGYPTIAN HIEROGLYPH-13680;Lo;0;L;;;;;N;;;;;\n13681;EGYPTIAN HIEROGLYPH-13681;Lo;0;L;;;;;N;;;;;\n13682;EGYPTIAN HIEROGLYPH-13682;Lo;0;L;;;;;N;;;;;\n13683;EGYPTIAN HIEROGLYPH-13683;Lo;0;L;;;;;N;;;;;\n13684;EGYPTIAN HIEROGLYPH-13684;Lo;0;L;;;;;N;;;;;\n13685;EGYPTIAN HIEROGLYPH-13685;Lo;0;L;;;;;N;;;;;\n13686;EGYPTIAN HIEROGLYPH-13686;Lo;0;L;;;;;N;;;;;\n13687;EGYPTIAN HIEROGLYPH-13687;Lo;0;L;;;;;N;;;;;\n13688;EGYPTIAN HIEROGLYPH-13688;Lo;0;L;;;;;N;;;;;\n13689;EGYPTIAN HIEROGLYPH-13689;Lo;0;L;;;;;N;;;;;\n1368A;EGYPTIAN HIEROGLYPH-1368A;Lo;0;L;;;;;N;;;;;\n1368B;EGYPTIAN HIEROGLYPH-1368B;Lo;0;L;;;;;N;;;;;\n1368C;EGYPTIAN HIEROGLYPH-1368C;Lo;0;L;;;;;N;;;;;\n1368D;EGYPTIAN HIEROGLYPH-1368D;Lo;0;L;;;;;N;;;;;\n1368E;EGYPTIAN HIEROGLYPH-1368E;Lo;0;L;;;;;N;;;;;\n1368F;EGYPTIAN HIEROGLYPH-1368F;Lo;0;L;;;;;N;;;;;\n13690;EGYPTIAN HIEROGLYPH-13690;Lo;0;L;;;;;N;;;;;\n13691;EGYPTIAN HIEROGLYPH-13691;Lo;0;L;;;;;N;;;;;\n13692;EGYPTIAN HIEROGLYPH-13692;Lo;0;L;;;;;N;;;;;\n13693;EGYPTIAN HIEROGLYPH-13693;Lo;0;L;;;;;N;;;;;\n13694;EGYPTIAN HIEROGLYPH-13694;Lo;0;L;;;;;N;;;;;\n13695;EGYPTIAN HIEROGLYPH-13695;Lo;0;L;;;;;N;;;;;\n13696;EGYPTIAN HIEROGLYPH-13696;Lo;0;L;;;;;N;;;;;\n13697;EGYPTIAN HIEROGLYPH-13697;Lo;0;L;;;;;N;;;;;\n13698;EGYPTIAN HIEROGLYPH-13698;Lo;0;L;;;;;N;;;;;\n13699;EGYPTIAN HIEROGLYPH-13699;Lo;0;L;;;;;N;;;;;\n1369A;EGYPTIAN HIEROGLYPH-1369A;Lo;0;L;;;;;N;;;;;\n1369B;EGYPTIAN HIEROGLYPH-1369B;Lo;0;L;;;;;N;;;;;\n1369C;EGYPTIAN HIEROGLYPH-1369C;Lo;0;L;;;;;N;;;;;\n1369D;EGYPTIAN HIEROGLYPH-1369D;Lo;0;L;;;;;N;;;;;\n1369E;EGYPTIAN HIEROGLYPH-1369E;Lo;0;L;;;;;N;;;;;\n1369F;EGYPTIAN HIEROGLYPH-1369F;Lo;0;L;;;;;N;;;;;\n136A0;EGYPTIAN HIEROGLYPH-136A0;Lo;0;L;;;;;N;;;;;\n136A1;EGYPTIAN HIEROGLYPH-136A1;Lo;0;L;;;;;N;;;;;\n136A2;EGYPTIAN HIEROGLYPH-136A2;Lo;0;L;;;;;N;;;;;\n136A3;EGYPTIAN HIEROGLYPH-136A3;Lo;0;L;;;;;N;;;;;\n136A4;EGYPTIAN HIEROGLYPH-136A4;Lo;0;L;;;;;N;;;;;\n136A5;EGYPTIAN HIEROGLYPH-136A5;Lo;0;L;;;;;N;;;;;\n136A6;EGYPTIAN HIEROGLYPH-136A6;Lo;0;L;;;;;N;;;;;\n136A7;EGYPTIAN HIEROGLYPH-136A7;Lo;0;L;;;;;N;;;;;\n136A8;EGYPTIAN HIEROGLYPH-136A8;Lo;0;L;;;;;N;;;;;\n136A9;EGYPTIAN HIEROGLYPH-136A9;Lo;0;L;;;;;N;;;;;\n136AA;EGYPTIAN HIEROGLYPH-136AA;Lo;0;L;;;;;N;;;;;\n136AB;EGYPTIAN HIEROGLYPH-136AB;Lo;0;L;;;;;N;;;;;\n136AC;EGYPTIAN HIEROGLYPH-136AC;Lo;0;L;;;;;N;;;;;\n136AD;EGYPTIAN HIEROGLYPH-136AD;Lo;0;L;;;;;N;;;;;\n136AE;EGYPTIAN HIEROGLYPH-136AE;Lo;0;L;;;;;N;;;;;\n136AF;EGYPTIAN HIEROGLYPH-136AF;Lo;0;L;;;;;N;;;;;\n136B0;EGYPTIAN HIEROGLYPH-136B0;Lo;0;L;;;;;N;;;;;\n136B1;EGYPTIAN HIEROGLYPH-136B1;Lo;0;L;;;;;N;;;;;\n136B2;EGYPTIAN HIEROGLYPH-136B2;Lo;0;L;;;;;N;;;;;\n136B3;EGYPTIAN HIEROGLYPH-136B3;Lo;0;L;;;;;N;;;;;\n136B4;EGYPTIAN HIEROGLYPH-136B4;Lo;0;L;;;;;N;;;;;\n136B5;EGYPTIAN HIEROGLYPH-136B5;Lo;0;L;;;;;N;;;;;\n136B6;EGYPTIAN HIEROGLYPH-136B6;Lo;0;L;;;;;N;;;;;\n136B7;EGYPTIAN HIEROGLYPH-136B7;Lo;0;L;;;;;N;;;;;\n136B8;EGYPTIAN HIEROGLYPH-136B8;Lo;0;L;;;;;N;;;;;\n136B9;EGYPTIAN HIEROGLYPH-136B9;Lo;0;L;;;;;N;;;;;\n136BA;EGYPTIAN HIEROGLYPH-136BA;Lo;0;L;;;;;N;;;;;\n136BB;EGYPTIAN HIEROGLYPH-136BB;Lo;0;L;;;;;N;;;;;\n136BC;EGYPTIAN HIEROGLYPH-136BC;Lo;0;L;;;;;N;;;;;\n136BD;EGYPTIAN HIEROGLYPH-136BD;Lo;0;L;;;;;N;;;;;\n136BE;EGYPTIAN HIEROGLYPH-136BE;Lo;0;L;;;;;N;;;;;\n136BF;EGYPTIAN HIEROGLYPH-136BF;Lo;0;L;;;;;N;;;;;\n136C0;EGYPTIAN HIEROGLYPH-136C0;Lo;0;L;;;;;N;;;;;\n136C1;EGYPTIAN HIEROGLYPH-136C1;Lo;0;L;;;;;N;;;;;\n136C2;EGYPTIAN HIEROGLYPH-136C2;Lo;0;L;;;;;N;;;;;\n136C3;EGYPTIAN HIEROGLYPH-136C3;Lo;0;L;;;;;N;;;;;\n136C4;EGYPTIAN HIEROGLYPH-136C4;Lo;0;L;;;;;N;;;;;\n136C5;EGYPTIAN HIEROGLYPH-136C5;Lo;0;L;;;;;N;;;;;\n136C6;EGYPTIAN HIEROGLYPH-136C6;Lo;0;L;;;;;N;;;;;\n136C7;EGYPTIAN HIEROGLYPH-136C7;Lo;0;L;;;;;N;;;;;\n136C8;EGYPTIAN HIEROGLYPH-136C8;Lo;0;L;;;;;N;;;;;\n136C9;EGYPTIAN HIEROGLYPH-136C9;Lo;0;L;;;;;N;;;;;\n136CA;EGYPTIAN HIEROGLYPH-136CA;Lo;0;L;;;;;N;;;;;\n136CB;EGYPTIAN HIEROGLYPH-136CB;Lo;0;L;;;;;N;;;;;\n136CC;EGYPTIAN HIEROGLYPH-136CC;Lo;0;L;;;;;N;;;;;\n136CD;EGYPTIAN HIEROGLYPH-136CD;Lo;0;L;;;;;N;;;;;\n136CE;EGYPTIAN HIEROGLYPH-136CE;Lo;0;L;;;;;N;;;;;\n136CF;EGYPTIAN HIEROGLYPH-136CF;Lo;0;L;;;;;N;;;;;\n136D0;EGYPTIAN HIEROGLYPH-136D0;Lo;0;L;;;;;N;;;;;\n136D1;EGYPTIAN HIEROGLYPH-136D1;Lo;0;L;;;;;N;;;;;\n136D2;EGYPTIAN HIEROGLYPH-136D2;Lo;0;L;;;;;N;;;;;\n136D3;EGYPTIAN HIEROGLYPH-136D3;Lo;0;L;;;;;N;;;;;\n136D4;EGYPTIAN HIEROGLYPH-136D4;Lo;0;L;;;;;N;;;;;\n136D5;EGYPTIAN HIEROGLYPH-136D5;Lo;0;L;;;;;N;;;;;\n136D6;EGYPTIAN HIEROGLYPH-136D6;Lo;0;L;;;;;N;;;;;\n136D7;EGYPTIAN HIEROGLYPH-136D7;Lo;0;L;;;;;N;;;;;\n136D8;EGYPTIAN HIEROGLYPH-136D8;Lo;0;L;;;;;N;;;;;\n136D9;EGYPTIAN HIEROGLYPH-136D9;Lo;0;L;;;;;N;;;;;\n136DA;EGYPTIAN HIEROGLYPH-136DA;Lo;0;L;;;;;N;;;;;\n136DB;EGYPTIAN HIEROGLYPH-136DB;Lo;0;L;;;;;N;;;;;\n136DC;EGYPTIAN HIEROGLYPH-136DC;Lo;0;L;;;;;N;;;;;\n136DD;EGYPTIAN HIEROGLYPH-136DD;Lo;0;L;;;;;N;;;;;\n136DE;EGYPTIAN HIEROGLYPH-136DE;Lo;0;L;;;;;N;;;;;\n136DF;EGYPTIAN HIEROGLYPH-136DF;Lo;0;L;;;;;N;;;;;\n136E0;EGYPTIAN HIEROGLYPH-136E0;Lo;0;L;;;;;N;;;;;\n136E1;EGYPTIAN HIEROGLYPH-136E1;Lo;0;L;;;;;N;;;;;\n136E2;EGYPTIAN HIEROGLYPH-136E2;Lo;0;L;;;;;N;;;;;\n136E3;EGYPTIAN HIEROGLYPH-136E3;Lo;0;L;;;;;N;;;;;\n136E4;EGYPTIAN HIEROGLYPH-136E4;Lo;0;L;;;;;N;;;;;\n136E5;EGYPTIAN HIEROGLYPH-136E5;Lo;0;L;;;;;N;;;;;\n136E6;EGYPTIAN HIEROGLYPH-136E6;Lo;0;L;;;;;N;;;;;\n136E7;EGYPTIAN HIEROGLYPH-136E7;Lo;0;L;;;;;N;;;;;\n136E8;EGYPTIAN HIEROGLYPH-136E8;Lo;0;L;;;;;N;;;;;\n136E9;EGYPTIAN HIEROGLYPH-136E9;Lo;0;L;;;;;N;;;;;\n136EA;EGYPTIAN HIEROGLYPH-136EA;Lo;0;L;;;;;N;;;;;\n136EB;EGYPTIAN HIEROGLYPH-136EB;Lo;0;L;;;;;N;;;;;\n136EC;EGYPTIAN HIEROGLYPH-136EC;Lo;0;L;;;;;N;;;;;\n136ED;EGYPTIAN HIEROGLYPH-136ED;Lo;0;L;;;;;N;;;;;\n136EE;EGYPTIAN HIEROGLYPH-136EE;Lo;0;L;;;;;N;;;;;\n136EF;EGYPTIAN HIEROGLYPH-136EF;Lo;0;L;;;;;N;;;;;\n136F0;EGYPTIAN HIEROGLYPH-136F0;Lo;0;L;;;;;N;;;;;\n136F1;EGYPTIAN HIEROGLYPH-136F1;Lo;0;L;;;;;N;;;;;\n136F2;EGYPTIAN HIEROGLYPH-136F2;Lo;0;L;;;;;N;;;;;\n136F3;EGYPTIAN HIEROGLYPH-136F3;Lo;0;L;;;;;N;;;;;\n136F4;EGYPTIAN HIEROGLYPH-136F4;Lo;0;L;;;;;N;;;;;\n136F5;EGYPTIAN HIEROGLYPH-136F5;Lo;0;L;;;;;N;;;;;\n136F6;EGYPTIAN HIEROGLYPH-136F6;Lo;0;L;;;;;N;;;;;\n136F7;EGYPTIAN HIEROGLYPH-136F7;Lo;0;L;;;;;N;;;;;\n136F8;EGYPTIAN HIEROGLYPH-136F8;Lo;0;L;;;;;N;;;;;\n136F9;EGYPTIAN HIEROGLYPH-136F9;Lo;0;L;;;;;N;;;;;\n136FA;EGYPTIAN HIEROGLYPH-136FA;Lo;0;L;;;;;N;;;;;\n136FB;EGYPTIAN HIEROGLYPH-136FB;Lo;0;L;;;;;N;;;;;\n136FC;EGYPTIAN HIEROGLYPH-136FC;Lo;0;L;;;;;N;;;;;\n136FD;EGYPTIAN HIEROGLYPH-136FD;Lo;0;L;;;;;N;;;;;\n136FE;EGYPTIAN HIEROGLYPH-136FE;Lo;0;L;;;;;N;;;;;\n136FF;EGYPTIAN HIEROGLYPH-136FF;Lo;0;L;;;;;N;;;;;\n13700;EGYPTIAN HIEROGLYPH-13700;Lo;0;L;;;;;N;;;;;\n13701;EGYPTIAN HIEROGLYPH-13701;Lo;0;L;;;;;N;;;;;\n13702;EGYPTIAN HIEROGLYPH-13702;Lo;0;L;;;;;N;;;;;\n13703;EGYPTIAN HIEROGLYPH-13703;Lo;0;L;;;;;N;;;;;\n13704;EGYPTIAN HIEROGLYPH-13704;Lo;0;L;;;;;N;;;;;\n13705;EGYPTIAN HIEROGLYPH-13705;Lo;0;L;;;;;N;;;;;\n13706;EGYPTIAN HIEROGLYPH-13706;Lo;0;L;;;;;N;;;;;\n13707;EGYPTIAN HIEROGLYPH-13707;Lo;0;L;;;;;N;;;;;\n13708;EGYPTIAN HIEROGLYPH-13708;Lo;0;L;;;;;N;;;;;\n13709;EGYPTIAN HIEROGLYPH-13709;Lo;0;L;;;;;N;;;;;\n1370A;EGYPTIAN HIEROGLYPH-1370A;Lo;0;L;;;;;N;;;;;\n1370B;EGYPTIAN HIEROGLYPH-1370B;Lo;0;L;;;;;N;;;;;\n1370C;EGYPTIAN HIEROGLYPH-1370C;Lo;0;L;;;;;N;;;;;\n1370D;EGYPTIAN HIEROGLYPH-1370D;Lo;0;L;;;;;N;;;;;\n1370E;EGYPTIAN HIEROGLYPH-1370E;Lo;0;L;;;;;N;;;;;\n1370F;EGYPTIAN HIEROGLYPH-1370F;Lo;0;L;;;;;N;;;;;\n13710;EGYPTIAN HIEROGLYPH-13710;Lo;0;L;;;;;N;;;;;\n13711;EGYPTIAN HIEROGLYPH-13711;Lo;0;L;;;;;N;;;;;\n13712;EGYPTIAN HIEROGLYPH-13712;Lo;0;L;;;;;N;;;;;\n13713;EGYPTIAN HIEROGLYPH-13713;Lo;0;L;;;;;N;;;;;\n13714;EGYPTIAN HIEROGLYPH-13714;Lo;0;L;;;;;N;;;;;\n13715;EGYPTIAN HIEROGLYPH-13715;Lo;0;L;;;;;N;;;;;\n13716;EGYPTIAN HIEROGLYPH-13716;Lo;0;L;;;;;N;;;;;\n13717;EGYPTIAN HIEROGLYPH-13717;Lo;0;L;;;;;N;;;;;\n13718;EGYPTIAN HIEROGLYPH-13718;Lo;0;L;;;;;N;;;;;\n13719;EGYPTIAN HIEROGLYPH-13719;Lo;0;L;;;;;N;;;;;\n1371A;EGYPTIAN HIEROGLYPH-1371A;Lo;0;L;;;;;N;;;;;\n1371B;EGYPTIAN HIEROGLYPH-1371B;Lo;0;L;;;;;N;;;;;\n1371C;EGYPTIAN HIEROGLYPH-1371C;Lo;0;L;;;;;N;;;;;\n1371D;EGYPTIAN HIEROGLYPH-1371D;Lo;0;L;;;;;N;;;;;\n1371E;EGYPTIAN HIEROGLYPH-1371E;Lo;0;L;;;;;N;;;;;\n1371F;EGYPTIAN HIEROGLYPH-1371F;Lo;0;L;;;;;N;;;;;\n13720;EGYPTIAN HIEROGLYPH-13720;Lo;0;L;;;;;N;;;;;\n13721;EGYPTIAN HIEROGLYPH-13721;Lo;0;L;;;;;N;;;;;\n13722;EGYPTIAN HIEROGLYPH-13722;Lo;0;L;;;;;N;;;;;\n13723;EGYPTIAN HIEROGLYPH-13723;Lo;0;L;;;;;N;;;;;\n13724;EGYPTIAN HIEROGLYPH-13724;Lo;0;L;;;;;N;;;;;\n13725;EGYPTIAN HIEROGLYPH-13725;Lo;0;L;;;;;N;;;;;\n13726;EGYPTIAN HIEROGLYPH-13726;Lo;0;L;;;;;N;;;;;\n13727;EGYPTIAN HIEROGLYPH-13727;Lo;0;L;;;;;N;;;;;\n13728;EGYPTIAN HIEROGLYPH-13728;Lo;0;L;;;;;N;;;;;\n13729;EGYPTIAN HIEROGLYPH-13729;Lo;0;L;;;;;N;;;;;\n1372A;EGYPTIAN HIEROGLYPH-1372A;Lo;0;L;;;;;N;;;;;\n1372B;EGYPTIAN HIEROGLYPH-1372B;Lo;0;L;;;;;N;;;;;\n1372C;EGYPTIAN HIEROGLYPH-1372C;Lo;0;L;;;;;N;;;;;\n1372D;EGYPTIAN HIEROGLYPH-1372D;Lo;0;L;;;;;N;;;;;\n1372E;EGYPTIAN HIEROGLYPH-1372E;Lo;0;L;;;;;N;;;;;\n1372F;EGYPTIAN HIEROGLYPH-1372F;Lo;0;L;;;;;N;;;;;\n13730;EGYPTIAN HIEROGLYPH-13730;Lo;0;L;;;;;N;;;;;\n13731;EGYPTIAN HIEROGLYPH-13731;Lo;0;L;;;;;N;;;;;\n13732;EGYPTIAN HIEROGLYPH-13732;Lo;0;L;;;;;N;;;;;\n13733;EGYPTIAN HIEROGLYPH-13733;Lo;0;L;;;;;N;;;;;\n13734;EGYPTIAN HIEROGLYPH-13734;Lo;0;L;;;;;N;;;;;\n13735;EGYPTIAN HIEROGLYPH-13735;Lo;0;L;;;;;N;;;;;\n13736;EGYPTIAN HIEROGLYPH-13736;Lo;0;L;;;;;N;;;;;\n13737;EGYPTIAN HIEROGLYPH-13737;Lo;0;L;;;;;N;;;;;\n13738;EGYPTIAN HIEROGLYPH-13738;Lo;0;L;;;;;N;;;;;\n13739;EGYPTIAN HIEROGLYPH-13739;Lo;0;L;;;;;N;;;;;\n1373A;EGYPTIAN HIEROGLYPH-1373A;Lo;0;L;;;;;N;;;;;\n1373B;EGYPTIAN HIEROGLYPH-1373B;Lo;0;L;;;;;N;;;;;\n1373C;EGYPTIAN HIEROGLYPH-1373C;Lo;0;L;;;;;N;;;;;\n1373D;EGYPTIAN HIEROGLYPH-1373D;Lo;0;L;;;;;N;;;;;\n1373E;EGYPTIAN HIEROGLYPH-1373E;Lo;0;L;;;;;N;;;;;\n1373F;EGYPTIAN HIEROGLYPH-1373F;Lo;0;L;;;;;N;;;;;\n13740;EGYPTIAN HIEROGLYPH-13740;Lo;0;L;;;;;N;;;;;\n13741;EGYPTIAN HIEROGLYPH-13741;Lo;0;L;;;;;N;;;;;\n13742;EGYPTIAN HIEROGLYPH-13742;Lo;0;L;;;;;N;;;;;\n13743;EGYPTIAN HIEROGLYPH-13743;Lo;0;L;;;;;N;;;;;\n13744;EGYPTIAN HIEROGLYPH-13744;Lo;0;L;;;;;N;;;;;\n13745;EGYPTIAN HIEROGLYPH-13745;Lo;0;L;;;;;N;;;;;\n13746;EGYPTIAN HIEROGLYPH-13746;Lo;0;L;;;;;N;;;;;\n13747;EGYPTIAN HIEROGLYPH-13747;Lo;0;L;;;;;N;;;;;\n13748;EGYPTIAN HIEROGLYPH-13748;Lo;0;L;;;;;N;;;;;\n13749;EGYPTIAN HIEROGLYPH-13749;Lo;0;L;;;;;N;;;;;\n1374A;EGYPTIAN HIEROGLYPH-1374A;Lo;0;L;;;;;N;;;;;\n1374B;EGYPTIAN HIEROGLYPH-1374B;Lo;0;L;;;;;N;;;;;\n1374C;EGYPTIAN HIEROGLYPH-1374C;Lo;0;L;;;;;N;;;;;\n1374D;EGYPTIAN HIEROGLYPH-1374D;Lo;0;L;;;;;N;;;;;\n1374E;EGYPTIAN HIEROGLYPH-1374E;Lo;0;L;;;;;N;;;;;\n1374F;EGYPTIAN HIEROGLYPH-1374F;Lo;0;L;;;;;N;;;;;\n13750;EGYPTIAN HIEROGLYPH-13750;Lo;0;L;;;;;N;;;;;\n13751;EGYPTIAN HIEROGLYPH-13751;Lo;0;L;;;;;N;;;;;\n13752;EGYPTIAN HIEROGLYPH-13752;Lo;0;L;;;;;N;;;;;\n13753;EGYPTIAN HIEROGLYPH-13753;Lo;0;L;;;;;N;;;;;\n13754;EGYPTIAN HIEROGLYPH-13754;Lo;0;L;;;;;N;;;;;\n13755;EGYPTIAN HIEROGLYPH-13755;Lo;0;L;;;;;N;;;;;\n13756;EGYPTIAN HIEROGLYPH-13756;Lo;0;L;;;;;N;;;;;\n13757;EGYPTIAN HIEROGLYPH-13757;Lo;0;L;;;;;N;;;;;\n13758;EGYPTIAN HIEROGLYPH-13758;Lo;0;L;;;;;N;;;;;\n13759;EGYPTIAN HIEROGLYPH-13759;Lo;0;L;;;;;N;;;;;\n1375A;EGYPTIAN HIEROGLYPH-1375A;Lo;0;L;;;;;N;;;;;\n1375B;EGYPTIAN HIEROGLYPH-1375B;Lo;0;L;;;;;N;;;;;\n1375C;EGYPTIAN HIEROGLYPH-1375C;Lo;0;L;;;;;N;;;;;\n1375D;EGYPTIAN HIEROGLYPH-1375D;Lo;0;L;;;;;N;;;;;\n1375E;EGYPTIAN HIEROGLYPH-1375E;Lo;0;L;;;;;N;;;;;\n1375F;EGYPTIAN HIEROGLYPH-1375F;Lo;0;L;;;;;N;;;;;\n13760;EGYPTIAN HIEROGLYPH-13760;Lo;0;L;;;;;N;;;;;\n13761;EGYPTIAN HIEROGLYPH-13761;Lo;0;L;;;;;N;;;;;\n13762;EGYPTIAN HIEROGLYPH-13762;Lo;0;L;;;;;N;;;;;\n13763;EGYPTIAN HIEROGLYPH-13763;Lo;0;L;;;;;N;;;;;\n13764;EGYPTIAN HIEROGLYPH-13764;Lo;0;L;;;;;N;;;;;\n13765;EGYPTIAN HIEROGLYPH-13765;Lo;0;L;;;;;N;;;;;\n13766;EGYPTIAN HIEROGLYPH-13766;Lo;0;L;;;;;N;;;;;\n13767;EGYPTIAN HIEROGLYPH-13767;Lo;0;L;;;;;N;;;;;\n13768;EGYPTIAN HIEROGLYPH-13768;Lo;0;L;;;;;N;;;;;\n13769;EGYPTIAN HIEROGLYPH-13769;Lo;0;L;;;;;N;;;;;\n1376A;EGYPTIAN HIEROGLYPH-1376A;Lo;0;L;;;;;N;;;;;\n1376B;EGYPTIAN HIEROGLYPH-1376B;Lo;0;L;;;;;N;;;;;\n1376C;EGYPTIAN HIEROGLYPH-1376C;Lo;0;L;;;;;N;;;;;\n1376D;EGYPTIAN HIEROGLYPH-1376D;Lo;0;L;;;;;N;;;;;\n1376E;EGYPTIAN HIEROGLYPH-1376E;Lo;0;L;;;;;N;;;;;\n1376F;EGYPTIAN HIEROGLYPH-1376F;Lo;0;L;;;;;N;;;;;\n13770;EGYPTIAN HIEROGLYPH-13770;Lo;0;L;;;;;N;;;;;\n13771;EGYPTIAN HIEROGLYPH-13771;Lo;0;L;;;;;N;;;;;\n13772;EGYPTIAN HIEROGLYPH-13772;Lo;0;L;;;;;N;;;;;\n13773;EGYPTIAN HIEROGLYPH-13773;Lo;0;L;;;;;N;;;;;\n13774;EGYPTIAN HIEROGLYPH-13774;Lo;0;L;;;;;N;;;;;\n13775;EGYPTIAN HIEROGLYPH-13775;Lo;0;L;;;;;N;;;;;\n13776;EGYPTIAN HIEROGLYPH-13776;Lo;0;L;;;;;N;;;;;\n13777;EGYPTIAN HIEROGLYPH-13777;Lo;0;L;;;;;N;;;;;\n13778;EGYPTIAN HIEROGLYPH-13778;Lo;0;L;;;;;N;;;;;\n13779;EGYPTIAN HIEROGLYPH-13779;Lo;0;L;;;;;N;;;;;\n1377A;EGYPTIAN HIEROGLYPH-1377A;Lo;0;L;;;;;N;;;;;\n1377B;EGYPTIAN HIEROGLYPH-1377B;Lo;0;L;;;;;N;;;;;\n1377C;EGYPTIAN HIEROGLYPH-1377C;Lo;0;L;;;;;N;;;;;\n1377D;EGYPTIAN HIEROGLYPH-1377D;Lo;0;L;;;;;N;;;;;\n1377E;EGYPTIAN HIEROGLYPH-1377E;Lo;0;L;;;;;N;;;;;\n1377F;EGYPTIAN HIEROGLYPH-1377F;Lo;0;L;;;;;N;;;;;\n13780;EGYPTIAN HIEROGLYPH-13780;Lo;0;L;;;;;N;;;;;\n13781;EGYPTIAN HIEROGLYPH-13781;Lo;0;L;;;;;N;;;;;\n13782;EGYPTIAN HIEROGLYPH-13782;Lo;0;L;;;;;N;;;;;\n13783;EGYPTIAN HIEROGLYPH-13783;Lo;0;L;;;;;N;;;;;\n13784;EGYPTIAN HIEROGLYPH-13784;Lo;0;L;;;;;N;;;;;\n13785;EGYPTIAN HIEROGLYPH-13785;Lo;0;L;;;;;N;;;;;\n13786;EGYPTIAN HIEROGLYPH-13786;Lo;0;L;;;;;N;;;;;\n13787;EGYPTIAN HIEROGLYPH-13787;Lo;0;L;;;;;N;;;;;\n13788;EGYPTIAN HIEROGLYPH-13788;Lo;0;L;;;;;N;;;;;\n13789;EGYPTIAN HIEROGLYPH-13789;Lo;0;L;;;;;N;;;;;\n1378A;EGYPTIAN HIEROGLYPH-1378A;Lo;0;L;;;;;N;;;;;\n1378B;EGYPTIAN HIEROGLYPH-1378B;Lo;0;L;;;;;N;;;;;\n1378C;EGYPTIAN HIEROGLYPH-1378C;Lo;0;L;;;;;N;;;;;\n1378D;EGYPTIAN HIEROGLYPH-1378D;Lo;0;L;;;;;N;;;;;\n1378E;EGYPTIAN HIEROGLYPH-1378E;Lo;0;L;;;;;N;;;;;\n1378F;EGYPTIAN HIEROGLYPH-1378F;Lo;0;L;;;;;N;;;;;\n13790;EGYPTIAN HIEROGLYPH-13790;Lo;0;L;;;;;N;;;;;\n13791;EGYPTIAN HIEROGLYPH-13791;Lo;0;L;;;;;N;;;;;\n13792;EGYPTIAN HIEROGLYPH-13792;Lo;0;L;;;;;N;;;;;\n13793;EGYPTIAN HIEROGLYPH-13793;Lo;0;L;;;;;N;;;;;\n13794;EGYPTIAN HIEROGLYPH-13794;Lo;0;L;;;;;N;;;;;\n13795;EGYPTIAN HIEROGLYPH-13795;Lo;0;L;;;;;N;;;;;\n13796;EGYPTIAN HIEROGLYPH-13796;Lo;0;L;;;;;N;;;;;\n13797;EGYPTIAN HIEROGLYPH-13797;Lo;0;L;;;;;N;;;;;\n13798;EGYPTIAN HIEROGLYPH-13798;Lo;0;L;;;;;N;;;;;\n13799;EGYPTIAN HIEROGLYPH-13799;Lo;0;L;;;;;N;;;;;\n1379A;EGYPTIAN HIEROGLYPH-1379A;Lo;0;L;;;;;N;;;;;\n1379B;EGYPTIAN HIEROGLYPH-1379B;Lo;0;L;;;;;N;;;;;\n1379C;EGYPTIAN HIEROGLYPH-1379C;Lo;0;L;;;;;N;;;;;\n1379D;EGYPTIAN HIEROGLYPH-1379D;Lo;0;L;;;;;N;;;;;\n1379E;EGYPTIAN HIEROGLYPH-1379E;Lo;0;L;;;;;N;;;;;\n1379F;EGYPTIAN HIEROGLYPH-1379F;Lo;0;L;;;;;N;;;;;\n137A0;EGYPTIAN HIEROGLYPH-137A0;Lo;0;L;;;;;N;;;;;\n137A1;EGYPTIAN HIEROGLYPH-137A1;Lo;0;L;;;;;N;;;;;\n137A2;EGYPTIAN HIEROGLYPH-137A2;Lo;0;L;;;;;N;;;;;\n137A3;EGYPTIAN HIEROGLYPH-137A3;Lo;0;L;;;;;N;;;;;\n137A4;EGYPTIAN HIEROGLYPH-137A4;Lo;0;L;;;;;N;;;;;\n137A5;EGYPTIAN HIEROGLYPH-137A5;Lo;0;L;;;;;N;;;;;\n137A6;EGYPTIAN HIEROGLYPH-137A6;Lo;0;L;;;;;N;;;;;\n137A7;EGYPTIAN HIEROGLYPH-137A7;Lo;0;L;;;;;N;;;;;\n137A8;EGYPTIAN HIEROGLYPH-137A8;Lo;0;L;;;;;N;;;;;\n137A9;EGYPTIAN HIEROGLYPH-137A9;Lo;0;L;;;;;N;;;;;\n137AA;EGYPTIAN HIEROGLYPH-137AA;Lo;0;L;;;;;N;;;;;\n137AB;EGYPTIAN HIEROGLYPH-137AB;Lo;0;L;;;;;N;;;;;\n137AC;EGYPTIAN HIEROGLYPH-137AC;Lo;0;L;;;;;N;;;;;\n137AD;EGYPTIAN HIEROGLYPH-137AD;Lo;0;L;;;;;N;;;;;\n137AE;EGYPTIAN HIEROGLYPH-137AE;Lo;0;L;;;;;N;;;;;\n137AF;EGYPTIAN HIEROGLYPH-137AF;Lo;0;L;;;;;N;;;;;\n137B0;EGYPTIAN HIEROGLYPH-137B0;Lo;0;L;;;;;N;;;;;\n137B1;EGYPTIAN HIEROGLYPH-137B1;Lo;0;L;;;;;N;;;;;\n137B2;EGYPTIAN HIEROGLYPH-137B2;Lo;0;L;;;;;N;;;;;\n137B3;EGYPTIAN HIEROGLYPH-137B3;Lo;0;L;;;;;N;;;;;\n137B4;EGYPTIAN HIEROGLYPH-137B4;Lo;0;L;;;;;N;;;;;\n137B5;EGYPTIAN HIEROGLYPH-137B5;Lo;0;L;;;;;N;;;;;\n137B6;EGYPTIAN HIEROGLYPH-137B6;Lo;0;L;;;;;N;;;;;\n137B7;EGYPTIAN HIEROGLYPH-137B7;Lo;0;L;;;;;N;;;;;\n137B8;EGYPTIAN HIEROGLYPH-137B8;Lo;0;L;;;;;N;;;;;\n137B9;EGYPTIAN HIEROGLYPH-137B9;Lo;0;L;;;;;N;;;;;\n137BA;EGYPTIAN HIEROGLYPH-137BA;Lo;0;L;;;;;N;;;;;\n137BB;EGYPTIAN HIEROGLYPH-137BB;Lo;0;L;;;;;N;;;;;\n137BC;EGYPTIAN HIEROGLYPH-137BC;Lo;0;L;;;;;N;;;;;\n137BD;EGYPTIAN HIEROGLYPH-137BD;Lo;0;L;;;;;N;;;;;\n137BE;EGYPTIAN HIEROGLYPH-137BE;Lo;0;L;;;;;N;;;;;\n137BF;EGYPTIAN HIEROGLYPH-137BF;Lo;0;L;;;;;N;;;;;\n137C0;EGYPTIAN HIEROGLYPH-137C0;Lo;0;L;;;;;N;;;;;\n137C1;EGYPTIAN HIEROGLYPH-137C1;Lo;0;L;;;;;N;;;;;\n137C2;EGYPTIAN HIEROGLYPH-137C2;Lo;0;L;;;;;N;;;;;\n137C3;EGYPTIAN HIEROGLYPH-137C3;Lo;0;L;;;;;N;;;;;\n137C4;EGYPTIAN HIEROGLYPH-137C4;Lo;0;L;;;;;N;;;;;\n137C5;EGYPTIAN HIEROGLYPH-137C5;Lo;0;L;;;;;N;;;;;\n137C6;EGYPTIAN HIEROGLYPH-137C6;Lo;0;L;;;;;N;;;;;\n137C7;EGYPTIAN HIEROGLYPH-137C7;Lo;0;L;;;;;N;;;;;\n137C8;EGYPTIAN HIEROGLYPH-137C8;Lo;0;L;;;;;N;;;;;\n137C9;EGYPTIAN HIEROGLYPH-137C9;Lo;0;L;;;;;N;;;;;\n137CA;EGYPTIAN HIEROGLYPH-137CA;Lo;0;L;;;;;N;;;;;\n137CB;EGYPTIAN HIEROGLYPH-137CB;Lo;0;L;;;;;N;;;;;\n137CC;EGYPTIAN HIEROGLYPH-137CC;Lo;0;L;;;;;N;;;;;\n137CD;EGYPTIAN HIEROGLYPH-137CD;Lo;0;L;;;;;N;;;;;\n137CE;EGYPTIAN HIEROGLYPH-137CE;Lo;0;L;;;;;N;;;;;\n137CF;EGYPTIAN HIEROGLYPH-137CF;Lo;0;L;;;;;N;;;;;\n137D0;EGYPTIAN HIEROGLYPH-137D0;Lo;0;L;;;;;N;;;;;\n137D1;EGYPTIAN HIEROGLYPH-137D1;Lo;0;L;;;;;N;;;;;\n137D2;EGYPTIAN HIEROGLYPH-137D2;Lo;0;L;;;;;N;;;;;\n137D3;EGYPTIAN HIEROGLYPH-137D3;Lo;0;L;;;;;N;;;;;\n137D4;EGYPTIAN HIEROGLYPH-137D4;Lo;0;L;;;;;N;;;;;\n137D5;EGYPTIAN HIEROGLYPH-137D5;Lo;0;L;;;;;N;;;;;\n137D6;EGYPTIAN HIEROGLYPH-137D6;Lo;0;L;;;;;N;;;;;\n137D7;EGYPTIAN HIEROGLYPH-137D7;Lo;0;L;;;;;N;;;;;\n137D8;EGYPTIAN HIEROGLYPH-137D8;Lo;0;L;;;;;N;;;;;\n137D9;EGYPTIAN HIEROGLYPH-137D9;Lo;0;L;;;;;N;;;;;\n137DA;EGYPTIAN HIEROGLYPH-137DA;Lo;0;L;;;;;N;;;;;\n137DB;EGYPTIAN HIEROGLYPH-137DB;Lo;0;L;;;;;N;;;;;\n137DC;EGYPTIAN HIEROGLYPH-137DC;Lo;0;L;;;;;N;;;;;\n137DD;EGYPTIAN HIEROGLYPH-137DD;Lo;0;L;;;;;N;;;;;\n137DE;EGYPTIAN HIEROGLYPH-137DE;Lo;0;L;;;;;N;;;;;\n137DF;EGYPTIAN HIEROGLYPH-137DF;Lo;0;L;;;;;N;;;;;\n137E0;EGYPTIAN HIEROGLYPH-137E0;Lo;0;L;;;;;N;;;;;\n137E1;EGYPTIAN HIEROGLYPH-137E1;Lo;0;L;;;;;N;;;;;\n137E2;EGYPTIAN HIEROGLYPH-137E2;Lo;0;L;;;;;N;;;;;\n137E3;EGYPTIAN HIEROGLYPH-137E3;Lo;0;L;;;;;N;;;;;\n137E4;EGYPTIAN HIEROGLYPH-137E4;Lo;0;L;;;;;N;;;;;\n137E5;EGYPTIAN HIEROGLYPH-137E5;Lo;0;L;;;;;N;;;;;\n137E6;EGYPTIAN HIEROGLYPH-137E6;Lo;0;L;;;;;N;;;;;\n137E7;EGYPTIAN HIEROGLYPH-137E7;Lo;0;L;;;;;N;;;;;\n137E8;EGYPTIAN HIEROGLYPH-137E8;Lo;0;L;;;;;N;;;;;\n137E9;EGYPTIAN HIEROGLYPH-137E9;Lo;0;L;;;;;N;;;;;\n137EA;EGYPTIAN HIEROGLYPH-137EA;Lo;0;L;;;;;N;;;;;\n137EB;EGYPTIAN HIEROGLYPH-137EB;Lo;0;L;;;;;N;;;;;\n137EC;EGYPTIAN HIEROGLYPH-137EC;Lo;0;L;;;;;N;;;;;\n137ED;EGYPTIAN HIEROGLYPH-137ED;Lo;0;L;;;;;N;;;;;\n137EE;EGYPTIAN HIEROGLYPH-137EE;Lo;0;L;;;;;N;;;;;\n137EF;EGYPTIAN HIEROGLYPH-137EF;Lo;0;L;;;;;N;;;;;\n137F0;EGYPTIAN HIEROGLYPH-137F0;Lo;0;L;;;;;N;;;;;\n137F1;EGYPTIAN HIEROGLYPH-137F1;Lo;0;L;;;;;N;;;;;\n137F2;EGYPTIAN HIEROGLYPH-137F2;Lo;0;L;;;;;N;;;;;\n137F3;EGYPTIAN HIEROGLYPH-137F3;Lo;0;L;;;;;N;;;;;\n137F4;EGYPTIAN HIEROGLYPH-137F4;Lo;0;L;;;;;N;;;;;\n137F5;EGYPTIAN HIEROGLYPH-137F5;Lo;0;L;;;;;N;;;;;\n137F6;EGYPTIAN HIEROGLYPH-137F6;Lo;0;L;;;;;N;;;;;\n137F7;EGYPTIAN HIEROGLYPH-137F7;Lo;0;L;;;;;N;;;;;\n137F8;EGYPTIAN HIEROGLYPH-137F8;Lo;0;L;;;;;N;;;;;\n137F9;EGYPTIAN HIEROGLYPH-137F9;Lo;0;L;;;;;N;;;;;\n137FA;EGYPTIAN HIEROGLYPH-137FA;Lo;0;L;;;;;N;;;;;\n137FB;EGYPTIAN HIEROGLYPH-137FB;Lo;0;L;;;;;N;;;;;\n137FC;EGYPTIAN HIEROGLYPH-137FC;Lo;0;L;;;;;N;;;;;\n137FD;EGYPTIAN HIEROGLYPH-137FD;Lo;0;L;;;;;N;;;;;\n137FE;EGYPTIAN HIEROGLYPH-137FE;Lo;0;L;;;;;N;;;;;\n137FF;EGYPTIAN HIEROGLYPH-137FF;Lo;0;L;;;;;N;;;;;\n13800;EGYPTIAN HIEROGLYPH-13800;Lo;0;L;;;;;N;;;;;\n13801;EGYPTIAN HIEROGLYPH-13801;Lo;0;L;;;;;N;;;;;\n13802;EGYPTIAN HIEROGLYPH-13802;Lo;0;L;;;;;N;;;;;\n13803;EGYPTIAN HIEROGLYPH-13803;Lo;0;L;;;;;N;;;;;\n13804;EGYPTIAN HIEROGLYPH-13804;Lo;0;L;;;;;N;;;;;\n13805;EGYPTIAN HIEROGLYPH-13805;Lo;0;L;;;;;N;;;;;\n13806;EGYPTIAN HIEROGLYPH-13806;Lo;0;L;;;;;N;;;;;\n13807;EGYPTIAN HIEROGLYPH-13807;Lo;0;L;;;;;N;;;;;\n13808;EGYPTIAN HIEROGLYPH-13808;Lo;0;L;;;;;N;;;;;\n13809;EGYPTIAN HIEROGLYPH-13809;Lo;0;L;;;;;N;;;;;\n1380A;EGYPTIAN HIEROGLYPH-1380A;Lo;0;L;;;;;N;;;;;\n1380B;EGYPTIAN HIEROGLYPH-1380B;Lo;0;L;;;;;N;;;;;\n1380C;EGYPTIAN HIEROGLYPH-1380C;Lo;0;L;;;;;N;;;;;\n1380D;EGYPTIAN HIEROGLYPH-1380D;Lo;0;L;;;;;N;;;;;\n1380E;EGYPTIAN HIEROGLYPH-1380E;Lo;0;L;;;;;N;;;;;\n1380F;EGYPTIAN HIEROGLYPH-1380F;Lo;0;L;;;;;N;;;;;\n13810;EGYPTIAN HIEROGLYPH-13810;Lo;0;L;;;;;N;;;;;\n13811;EGYPTIAN HIEROGLYPH-13811;Lo;0;L;;;;;N;;;;;\n13812;EGYPTIAN HIEROGLYPH-13812;Lo;0;L;;;;;N;;;;;\n13813;EGYPTIAN HIEROGLYPH-13813;Lo;0;L;;;;;N;;;;;\n13814;EGYPTIAN HIEROGLYPH-13814;Lo;0;L;;;;;N;;;;;\n13815;EGYPTIAN HIEROGLYPH-13815;Lo;0;L;;;;;N;;;;;\n13816;EGYPTIAN HIEROGLYPH-13816;Lo;0;L;;;;;N;;;;;\n13817;EGYPTIAN HIEROGLYPH-13817;Lo;0;L;;;;;N;;;;;\n13818;EGYPTIAN HIEROGLYPH-13818;Lo;0;L;;;;;N;;;;;\n13819;EGYPTIAN HIEROGLYPH-13819;Lo;0;L;;;;;N;;;;;\n1381A;EGYPTIAN HIEROGLYPH-1381A;Lo;0;L;;;;;N;;;;;\n1381B;EGYPTIAN HIEROGLYPH-1381B;Lo;0;L;;;;;N;;;;;\n1381C;EGYPTIAN HIEROGLYPH-1381C;Lo;0;L;;;;;N;;;;;\n1381D;EGYPTIAN HIEROGLYPH-1381D;Lo;0;L;;;;;N;;;;;\n1381E;EGYPTIAN HIEROGLYPH-1381E;Lo;0;L;;;;;N;;;;;\n1381F;EGYPTIAN HIEROGLYPH-1381F;Lo;0;L;;;;;N;;;;;\n13820;EGYPTIAN HIEROGLYPH-13820;Lo;0;L;;;;;N;;;;;\n13821;EGYPTIAN HIEROGLYPH-13821;Lo;0;L;;;;;N;;;;;\n13822;EGYPTIAN HIEROGLYPH-13822;Lo;0;L;;;;;N;;;;;\n13823;EGYPTIAN HIEROGLYPH-13823;Lo;0;L;;;;;N;;;;;\n13824;EGYPTIAN HIEROGLYPH-13824;Lo;0;L;;;;;N;;;;;\n13825;EGYPTIAN HIEROGLYPH-13825;Lo;0;L;;;;;N;;;;;\n13826;EGYPTIAN HIEROGLYPH-13826;Lo;0;L;;;;;N;;;;;\n13827;EGYPTIAN HIEROGLYPH-13827;Lo;0;L;;;;;N;;;;;\n13828;EGYPTIAN HIEROGLYPH-13828;Lo;0;L;;;;;N;;;;;\n13829;EGYPTIAN HIEROGLYPH-13829;Lo;0;L;;;;;N;;;;;\n1382A;EGYPTIAN HIEROGLYPH-1382A;Lo;0;L;;;;;N;;;;;\n1382B;EGYPTIAN HIEROGLYPH-1382B;Lo;0;L;;;;;N;;;;;\n1382C;EGYPTIAN HIEROGLYPH-1382C;Lo;0;L;;;;;N;;;;;\n1382D;EGYPTIAN HIEROGLYPH-1382D;Lo;0;L;;;;;N;;;;;\n1382E;EGYPTIAN HIEROGLYPH-1382E;Lo;0;L;;;;;N;;;;;\n1382F;EGYPTIAN HIEROGLYPH-1382F;Lo;0;L;;;;;N;;;;;\n13830;EGYPTIAN HIEROGLYPH-13830;Lo;0;L;;;;;N;;;;;\n13831;EGYPTIAN HIEROGLYPH-13831;Lo;0;L;;;;;N;;;;;\n13832;EGYPTIAN HIEROGLYPH-13832;Lo;0;L;;;;;N;;;;;\n13833;EGYPTIAN HIEROGLYPH-13833;Lo;0;L;;;;;N;;;;;\n13834;EGYPTIAN HIEROGLYPH-13834;Lo;0;L;;;;;N;;;;;\n13835;EGYPTIAN HIEROGLYPH-13835;Lo;0;L;;;;;N;;;;;\n13836;EGYPTIAN HIEROGLYPH-13836;Lo;0;L;;;;;N;;;;;\n13837;EGYPTIAN HIEROGLYPH-13837;Lo;0;L;;;;;N;;;;;\n13838;EGYPTIAN HIEROGLYPH-13838;Lo;0;L;;;;;N;;;;;\n13839;EGYPTIAN HIEROGLYPH-13839;Lo;0;L;;;;;N;;;;;\n1383A;EGYPTIAN HIEROGLYPH-1383A;Lo;0;L;;;;;N;;;;;\n1383B;EGYPTIAN HIEROGLYPH-1383B;Lo;0;L;;;;;N;;;;;\n1383C;EGYPTIAN HIEROGLYPH-1383C;Lo;0;L;;;;;N;;;;;\n1383D;EGYPTIAN HIEROGLYPH-1383D;Lo;0;L;;;;;N;;;;;\n1383E;EGYPTIAN HIEROGLYPH-1383E;Lo;0;L;;;;;N;;;;;\n1383F;EGYPTIAN HIEROGLYPH-1383F;Lo;0;L;;;;;N;;;;;\n13840;EGYPTIAN HIEROGLYPH-13840;Lo;0;L;;;;;N;;;;;\n13841;EGYPTIAN HIEROGLYPH-13841;Lo;0;L;;;;;N;;;;;\n13842;EGYPTIAN HIEROGLYPH-13842;Lo;0;L;;;;;N;;;;;\n13843;EGYPTIAN HIEROGLYPH-13843;Lo;0;L;;;;;N;;;;;\n13844;EGYPTIAN HIEROGLYPH-13844;Lo;0;L;;;;;N;;;;;\n13845;EGYPTIAN HIEROGLYPH-13845;Lo;0;L;;;;;N;;;;;\n13846;EGYPTIAN HIEROGLYPH-13846;Lo;0;L;;;;;N;;;;;\n13847;EGYPTIAN HIEROGLYPH-13847;Lo;0;L;;;;;N;;;;;\n13848;EGYPTIAN HIEROGLYPH-13848;Lo;0;L;;;;;N;;;;;\n13849;EGYPTIAN HIEROGLYPH-13849;Lo;0;L;;;;;N;;;;;\n1384A;EGYPTIAN HIEROGLYPH-1384A;Lo;0;L;;;;;N;;;;;\n1384B;EGYPTIAN HIEROGLYPH-1384B;Lo;0;L;;;;;N;;;;;\n1384C;EGYPTIAN HIEROGLYPH-1384C;Lo;0;L;;;;;N;;;;;\n1384D;EGYPTIAN HIEROGLYPH-1384D;Lo;0;L;;;;;N;;;;;\n1384E;EGYPTIAN HIEROGLYPH-1384E;Lo;0;L;;;;;N;;;;;\n1384F;EGYPTIAN HIEROGLYPH-1384F;Lo;0;L;;;;;N;;;;;\n13850;EGYPTIAN HIEROGLYPH-13850;Lo;0;L;;;;;N;;;;;\n13851;EGYPTIAN HIEROGLYPH-13851;Lo;0;L;;;;;N;;;;;\n13852;EGYPTIAN HIEROGLYPH-13852;Lo;0;L;;;;;N;;;;;\n13853;EGYPTIAN HIEROGLYPH-13853;Lo;0;L;;;;;N;;;;;\n13854;EGYPTIAN HIEROGLYPH-13854;Lo;0;L;;;;;N;;;;;\n13855;EGYPTIAN HIEROGLYPH-13855;Lo;0;L;;;;;N;;;;;\n13856;EGYPTIAN HIEROGLYPH-13856;Lo;0;L;;;;;N;;;;;\n13857;EGYPTIAN HIEROGLYPH-13857;Lo;0;L;;;;;N;;;;;\n13858;EGYPTIAN HIEROGLYPH-13858;Lo;0;L;;;;;N;;;;;\n13859;EGYPTIAN HIEROGLYPH-13859;Lo;0;L;;;;;N;;;;;\n1385A;EGYPTIAN HIEROGLYPH-1385A;Lo;0;L;;;;;N;;;;;\n1385B;EGYPTIAN HIEROGLYPH-1385B;Lo;0;L;;;;;N;;;;;\n1385C;EGYPTIAN HIEROGLYPH-1385C;Lo;0;L;;;;;N;;;;;\n1385D;EGYPTIAN HIEROGLYPH-1385D;Lo;0;L;;;;;N;;;;;\n1385E;EGYPTIAN HIEROGLYPH-1385E;Lo;0;L;;;;;N;;;;;\n1385F;EGYPTIAN HIEROGLYPH-1385F;Lo;0;L;;;;;N;;;;;\n13860;EGYPTIAN HIEROGLYPH-13860;Lo;0;L;;;;;N;;;;;\n13861;EGYPTIAN HIEROGLYPH-13861;Lo;0;L;;;;;N;;;;;\n13862;EGYPTIAN HIEROGLYPH-13862;Lo;0;L;;;;;N;;;;;\n13863;EGYPTIAN HIEROGLYPH-13863;Lo;0;L;;;;;N;;;;;\n13864;EGYPTIAN HIEROGLYPH-13864;Lo;0;L;;;;;N;;;;;\n13865;EGYPTIAN HIEROGLYPH-13865;Lo;0;L;;;;;N;;;;;\n13866;EGYPTIAN HIEROGLYPH-13866;Lo;0;L;;;;;N;;;;;\n13867;EGYPTIAN HIEROGLYPH-13867;Lo;0;L;;;;;N;;;;;\n13868;EGYPTIAN HIEROGLYPH-13868;Lo;0;L;;;;;N;;;;;\n13869;EGYPTIAN HIEROGLYPH-13869;Lo;0;L;;;;;N;;;;;\n1386A;EGYPTIAN HIEROGLYPH-1386A;Lo;0;L;;;;;N;;;;;\n1386B;EGYPTIAN HIEROGLYPH-1386B;Lo;0;L;;;;;N;;;;;\n1386C;EGYPTIAN HIEROGLYPH-1386C;Lo;0;L;;;;;N;;;;;\n1386D;EGYPTIAN HIEROGLYPH-1386D;Lo;0;L;;;;;N;;;;;\n1386E;EGYPTIAN HIEROGLYPH-1386E;Lo;0;L;;;;;N;;;;;\n1386F;EGYPTIAN HIEROGLYPH-1386F;Lo;0;L;;;;;N;;;;;\n13870;EGYPTIAN HIEROGLYPH-13870;Lo;0;L;;;;;N;;;;;\n13871;EGYPTIAN HIEROGLYPH-13871;Lo;0;L;;;;;N;;;;;\n13872;EGYPTIAN HIEROGLYPH-13872;Lo;0;L;;;;;N;;;;;\n13873;EGYPTIAN HIEROGLYPH-13873;Lo;0;L;;;;;N;;;;;\n13874;EGYPTIAN HIEROGLYPH-13874;Lo;0;L;;;;;N;;;;;\n13875;EGYPTIAN HIEROGLYPH-13875;Lo;0;L;;;;;N;;;;;\n13876;EGYPTIAN HIEROGLYPH-13876;Lo;0;L;;;;;N;;;;;\n13877;EGYPTIAN HIEROGLYPH-13877;Lo;0;L;;;;;N;;;;;\n13878;EGYPTIAN HIEROGLYPH-13878;Lo;0;L;;;;;N;;;;;\n13879;EGYPTIAN HIEROGLYPH-13879;Lo;0;L;;;;;N;;;;;\n1387A;EGYPTIAN HIEROGLYPH-1387A;Lo;0;L;;;;;N;;;;;\n1387B;EGYPTIAN HIEROGLYPH-1387B;Lo;0;L;;;;;N;;;;;\n1387C;EGYPTIAN HIEROGLYPH-1387C;Lo;0;L;;;;;N;;;;;\n1387D;EGYPTIAN HIEROGLYPH-1387D;Lo;0;L;;;;;N;;;;;\n1387E;EGYPTIAN HIEROGLYPH-1387E;Lo;0;L;;;;;N;;;;;\n1387F;EGYPTIAN HIEROGLYPH-1387F;Lo;0;L;;;;;N;;;;;\n13880;EGYPTIAN HIEROGLYPH-13880;Lo;0;L;;;;;N;;;;;\n13881;EGYPTIAN HIEROGLYPH-13881;Lo;0;L;;;;;N;;;;;\n13882;EGYPTIAN HIEROGLYPH-13882;Lo;0;L;;;;;N;;;;;\n13883;EGYPTIAN HIEROGLYPH-13883;Lo;0;L;;;;;N;;;;;\n13884;EGYPTIAN HIEROGLYPH-13884;Lo;0;L;;;;;N;;;;;\n13885;EGYPTIAN HIEROGLYPH-13885;Lo;0;L;;;;;N;;;;;\n13886;EGYPTIAN HIEROGLYPH-13886;Lo;0;L;;;;;N;;;;;\n13887;EGYPTIAN HIEROGLYPH-13887;Lo;0;L;;;;;N;;;;;\n13888;EGYPTIAN HIEROGLYPH-13888;Lo;0;L;;;;;N;;;;;\n13889;EGYPTIAN HIEROGLYPH-13889;Lo;0;L;;;;;N;;;;;\n1388A;EGYPTIAN HIEROGLYPH-1388A;Lo;0;L;;;;;N;;;;;\n1388B;EGYPTIAN HIEROGLYPH-1388B;Lo;0;L;;;;;N;;;;;\n1388C;EGYPTIAN HIEROGLYPH-1388C;Lo;0;L;;;;;N;;;;;\n1388D;EGYPTIAN HIEROGLYPH-1388D;Lo;0;L;;;;;N;;;;;\n1388E;EGYPTIAN HIEROGLYPH-1388E;Lo;0;L;;;;;N;;;;;\n1388F;EGYPTIAN HIEROGLYPH-1388F;Lo;0;L;;;;;N;;;;;\n13890;EGYPTIAN HIEROGLYPH-13890;Lo;0;L;;;;;N;;;;;\n13891;EGYPTIAN HIEROGLYPH-13891;Lo;0;L;;;;;N;;;;;\n13892;EGYPTIAN HIEROGLYPH-13892;Lo;0;L;;;;;N;;;;;\n13893;EGYPTIAN HIEROGLYPH-13893;Lo;0;L;;;;;N;;;;;\n13894;EGYPTIAN HIEROGLYPH-13894;Lo;0;L;;;;;N;;;;;\n13895;EGYPTIAN HIEROGLYPH-13895;Lo;0;L;;;;;N;;;;;\n13896;EGYPTIAN HIEROGLYPH-13896;Lo;0;L;;;;;N;;;;;\n13897;EGYPTIAN HIEROGLYPH-13897;Lo;0;L;;;;;N;;;;;\n13898;EGYPTIAN HIEROGLYPH-13898;Lo;0;L;;;;;N;;;;;\n13899;EGYPTIAN HIEROGLYPH-13899;Lo;0;L;;;;;N;;;;;\n1389A;EGYPTIAN HIEROGLYPH-1389A;Lo;0;L;;;;;N;;;;;\n1389B;EGYPTIAN HIEROGLYPH-1389B;Lo;0;L;;;;;N;;;;;\n1389C;EGYPTIAN HIEROGLYPH-1389C;Lo;0;L;;;;;N;;;;;\n1389D;EGYPTIAN HIEROGLYPH-1389D;Lo;0;L;;;;;N;;;;;\n1389E;EGYPTIAN HIEROGLYPH-1389E;Lo;0;L;;;;;N;;;;;\n1389F;EGYPTIAN HIEROGLYPH-1389F;Lo;0;L;;;;;N;;;;;\n138A0;EGYPTIAN HIEROGLYPH-138A0;Lo;0;L;;;;;N;;;;;\n138A1;EGYPTIAN HIEROGLYPH-138A1;Lo;0;L;;;;;N;;;;;\n138A2;EGYPTIAN HIEROGLYPH-138A2;Lo;0;L;;;;;N;;;;;\n138A3;EGYPTIAN HIEROGLYPH-138A3;Lo;0;L;;;;;N;;;;;\n138A4;EGYPTIAN HIEROGLYPH-138A4;Lo;0;L;;;;;N;;;;;\n138A5;EGYPTIAN HIEROGLYPH-138A5;Lo;0;L;;;;;N;;;;;\n138A6;EGYPTIAN HIEROGLYPH-138A6;Lo;0;L;;;;;N;;;;;\n138A7;EGYPTIAN HIEROGLYPH-138A7;Lo;0;L;;;;;N;;;;;\n138A8;EGYPTIAN HIEROGLYPH-138A8;Lo;0;L;;;;;N;;;;;\n138A9;EGYPTIAN HIEROGLYPH-138A9;Lo;0;L;;;;;N;;;;;\n138AA;EGYPTIAN HIEROGLYPH-138AA;Lo;0;L;;;;;N;;;;;\n138AB;EGYPTIAN HIEROGLYPH-138AB;Lo;0;L;;;;;N;;;;;\n138AC;EGYPTIAN HIEROGLYPH-138AC;Lo;0;L;;;;;N;;;;;\n138AD;EGYPTIAN HIEROGLYPH-138AD;Lo;0;L;;;;;N;;;;;\n138AE;EGYPTIAN HIEROGLYPH-138AE;Lo;0;L;;;;;N;;;;;\n138AF;EGYPTIAN HIEROGLYPH-138AF;Lo;0;L;;;;;N;;;;;\n138B0;EGYPTIAN HIEROGLYPH-138B0;Lo;0;L;;;;;N;;;;;\n138B1;EGYPTIAN HIEROGLYPH-138B1;Lo;0;L;;;;;N;;;;;\n138B2;EGYPTIAN HIEROGLYPH-138B2;Lo;0;L;;;;;N;;;;;\n138B3;EGYPTIAN HIEROGLYPH-138B3;Lo;0;L;;;;;N;;;;;\n138B4;EGYPTIAN HIEROGLYPH-138B4;Lo;0;L;;;;;N;;;;;\n138B5;EGYPTIAN HIEROGLYPH-138B5;Lo;0;L;;;;;N;;;;;\n138B6;EGYPTIAN HIEROGLYPH-138B6;Lo;0;L;;;;;N;;;;;\n138B7;EGYPTIAN HIEROGLYPH-138B7;Lo;0;L;;;;;N;;;;;\n138B8;EGYPTIAN HIEROGLYPH-138B8;Lo;0;L;;;;;N;;;;;\n138B9;EGYPTIAN HIEROGLYPH-138B9;Lo;0;L;;;;;N;;;;;\n138BA;EGYPTIAN HIEROGLYPH-138BA;Lo;0;L;;;;;N;;;;;\n138BB;EGYPTIAN HIEROGLYPH-138BB;Lo;0;L;;;;;N;;;;;\n138BC;EGYPTIAN HIEROGLYPH-138BC;Lo;0;L;;;;;N;;;;;\n138BD;EGYPTIAN HIEROGLYPH-138BD;Lo;0;L;;;;;N;;;;;\n138BE;EGYPTIAN HIEROGLYPH-138BE;Lo;0;L;;;;;N;;;;;\n138BF;EGYPTIAN HIEROGLYPH-138BF;Lo;0;L;;;;;N;;;;;\n138C0;EGYPTIAN HIEROGLYPH-138C0;Lo;0;L;;;;;N;;;;;\n138C1;EGYPTIAN HIEROGLYPH-138C1;Lo;0;L;;;;;N;;;;;\n138C2;EGYPTIAN HIEROGLYPH-138C2;Lo;0;L;;;;;N;;;;;\n138C3;EGYPTIAN HIEROGLYPH-138C3;Lo;0;L;;;;;N;;;;;\n138C4;EGYPTIAN HIEROGLYPH-138C4;Lo;0;L;;;;;N;;;;;\n138C5;EGYPTIAN HIEROGLYPH-138C5;Lo;0;L;;;;;N;;;;;\n138C6;EGYPTIAN HIEROGLYPH-138C6;Lo;0;L;;;;;N;;;;;\n138C7;EGYPTIAN HIEROGLYPH-138C7;Lo;0;L;;;;;N;;;;;\n138C8;EGYPTIAN HIEROGLYPH-138C8;Lo;0;L;;;;;N;;;;;\n138C9;EGYPTIAN HIEROGLYPH-138C9;Lo;0;L;;;;;N;;;;;\n138CA;EGYPTIAN HIEROGLYPH-138CA;Lo;0;L;;;;;N;;;;;\n138CB;EGYPTIAN HIEROGLYPH-138CB;Lo;0;L;;;;;N;;;;;\n138CC;EGYPTIAN HIEROGLYPH-138CC;Lo;0;L;;;;;N;;;;;\n138CD;EGYPTIAN HIEROGLYPH-138CD;Lo;0;L;;;;;N;;;;;\n138CE;EGYPTIAN HIEROGLYPH-138CE;Lo;0;L;;;;;N;;;;;\n138CF;EGYPTIAN HIEROGLYPH-138CF;Lo;0;L;;;;;N;;;;;\n138D0;EGYPTIAN HIEROGLYPH-138D0;Lo;0;L;;;;;N;;;;;\n138D1;EGYPTIAN HIEROGLYPH-138D1;Lo;0;L;;;;;N;;;;;\n138D2;EGYPTIAN HIEROGLYPH-138D2;Lo;0;L;;;;;N;;;;;\n138D3;EGYPTIAN HIEROGLYPH-138D3;Lo;0;L;;;;;N;;;;;\n138D4;EGYPTIAN HIEROGLYPH-138D4;Lo;0;L;;;;;N;;;;;\n138D5;EGYPTIAN HIEROGLYPH-138D5;Lo;0;L;;;;;N;;;;;\n138D6;EGYPTIAN HIEROGLYPH-138D6;Lo;0;L;;;;;N;;;;;\n138D7;EGYPTIAN HIEROGLYPH-138D7;Lo;0;L;;;;;N;;;;;\n138D8;EGYPTIAN HIEROGLYPH-138D8;Lo;0;L;;;;;N;;;;;\n138D9;EGYPTIAN HIEROGLYPH-138D9;Lo;0;L;;;;;N;;;;;\n138DA;EGYPTIAN HIEROGLYPH-138DA;Lo;0;L;;;;;N;;;;;\n138DB;EGYPTIAN HIEROGLYPH-138DB;Lo;0;L;;;;;N;;;;;\n138DC;EGYPTIAN HIEROGLYPH-138DC;Lo;0;L;;;;;N;;;;;\n138DD;EGYPTIAN HIEROGLYPH-138DD;Lo;0;L;;;;;N;;;;;\n138DE;EGYPTIAN HIEROGLYPH-138DE;Lo;0;L;;;;;N;;;;;\n138DF;EGYPTIAN HIEROGLYPH-138DF;Lo;0;L;;;;;N;;;;;\n138E0;EGYPTIAN HIEROGLYPH-138E0;Lo;0;L;;;;;N;;;;;\n138E1;EGYPTIAN HIEROGLYPH-138E1;Lo;0;L;;;;;N;;;;;\n138E2;EGYPTIAN HIEROGLYPH-138E2;Lo;0;L;;;;;N;;;;;\n138E3;EGYPTIAN HIEROGLYPH-138E3;Lo;0;L;;;;;N;;;;;\n138E4;EGYPTIAN HIEROGLYPH-138E4;Lo;0;L;;;;;N;;;;;\n138E5;EGYPTIAN HIEROGLYPH-138E5;Lo;0;L;;;;;N;;;;;\n138E6;EGYPTIAN HIEROGLYPH-138E6;Lo;0;L;;;;;N;;;;;\n138E7;EGYPTIAN HIEROGLYPH-138E7;Lo;0;L;;;;;N;;;;;\n138E8;EGYPTIAN HIEROGLYPH-138E8;Lo;0;L;;;;;N;;;;;\n138E9;EGYPTIAN HIEROGLYPH-138E9;Lo;0;L;;;;;N;;;;;\n138EA;EGYPTIAN HIEROGLYPH-138EA;Lo;0;L;;;;;N;;;;;\n138EB;EGYPTIAN HIEROGLYPH-138EB;Lo;0;L;;;;;N;;;;;\n138EC;EGYPTIAN HIEROGLYPH-138EC;Lo;0;L;;;;;N;;;;;\n138ED;EGYPTIAN HIEROGLYPH-138ED;Lo;0;L;;;;;N;;;;;\n138EE;EGYPTIAN HIEROGLYPH-138EE;Lo;0;L;;;;;N;;;;;\n138EF;EGYPTIAN HIEROGLYPH-138EF;Lo;0;L;;;;;N;;;;;\n138F0;EGYPTIAN HIEROGLYPH-138F0;Lo;0;L;;;;;N;;;;;\n138F1;EGYPTIAN HIEROGLYPH-138F1;Lo;0;L;;;;;N;;;;;\n138F2;EGYPTIAN HIEROGLYPH-138F2;Lo;0;L;;;;;N;;;;;\n138F3;EGYPTIAN HIEROGLYPH-138F3;Lo;0;L;;;;;N;;;;;\n138F4;EGYPTIAN HIEROGLYPH-138F4;Lo;0;L;;;;;N;;;;;\n138F5;EGYPTIAN HIEROGLYPH-138F5;Lo;0;L;;;;;N;;;;;\n138F6;EGYPTIAN HIEROGLYPH-138F6;Lo;0;L;;;;;N;;;;;\n138F7;EGYPTIAN HIEROGLYPH-138F7;Lo;0;L;;;;;N;;;;;\n138F8;EGYPTIAN HIEROGLYPH-138F8;Lo;0;L;;;;;N;;;;;\n138F9;EGYPTIAN HIEROGLYPH-138F9;Lo;0;L;;;;;N;;;;;\n138FA;EGYPTIAN HIEROGLYPH-138FA;Lo;0;L;;;;;N;;;;;\n138FB;EGYPTIAN HIEROGLYPH-138FB;Lo;0;L;;;;;N;;;;;\n138FC;EGYPTIAN HIEROGLYPH-138FC;Lo;0;L;;;;;N;;;;;\n138FD;EGYPTIAN HIEROGLYPH-138FD;Lo;0;L;;;;;N;;;;;\n138FE;EGYPTIAN HIEROGLYPH-138FE;Lo;0;L;;;;;N;;;;;\n138FF;EGYPTIAN HIEROGLYPH-138FF;Lo;0;L;;;;;N;;;;;\n13900;EGYPTIAN HIEROGLYPH-13900;Lo;0;L;;;;;N;;;;;\n13901;EGYPTIAN HIEROGLYPH-13901;Lo;0;L;;;;;N;;;;;\n13902;EGYPTIAN HIEROGLYPH-13902;Lo;0;L;;;;;N;;;;;\n13903;EGYPTIAN HIEROGLYPH-13903;Lo;0;L;;;;;N;;;;;\n13904;EGYPTIAN HIEROGLYPH-13904;Lo;0;L;;;;;N;;;;;\n13905;EGYPTIAN HIEROGLYPH-13905;Lo;0;L;;;;;N;;;;;\n13906;EGYPTIAN HIEROGLYPH-13906;Lo;0;L;;;;;N;;;;;\n13907;EGYPTIAN HIEROGLYPH-13907;Lo;0;L;;;;;N;;;;;\n13908;EGYPTIAN HIEROGLYPH-13908;Lo;0;L;;;;;N;;;;;\n13909;EGYPTIAN HIEROGLYPH-13909;Lo;0;L;;;;;N;;;;;\n1390A;EGYPTIAN HIEROGLYPH-1390A;Lo;0;L;;;;;N;;;;;\n1390B;EGYPTIAN HIEROGLYPH-1390B;Lo;0;L;;;;;N;;;;;\n1390C;EGYPTIAN HIEROGLYPH-1390C;Lo;0;L;;;;;N;;;;;\n1390D;EGYPTIAN HIEROGLYPH-1390D;Lo;0;L;;;;;N;;;;;\n1390E;EGYPTIAN HIEROGLYPH-1390E;Lo;0;L;;;;;N;;;;;\n1390F;EGYPTIAN HIEROGLYPH-1390F;Lo;0;L;;;;;N;;;;;\n13910;EGYPTIAN HIEROGLYPH-13910;Lo;0;L;;;;;N;;;;;\n13911;EGYPTIAN HIEROGLYPH-13911;Lo;0;L;;;;;N;;;;;\n13912;EGYPTIAN HIEROGLYPH-13912;Lo;0;L;;;;;N;;;;;\n13913;EGYPTIAN HIEROGLYPH-13913;Lo;0;L;;;;;N;;;;;\n13914;EGYPTIAN HIEROGLYPH-13914;Lo;0;L;;;;;N;;;;;\n13915;EGYPTIAN HIEROGLYPH-13915;Lo;0;L;;;;;N;;;;;\n13916;EGYPTIAN HIEROGLYPH-13916;Lo;0;L;;;;;N;;;;;\n13917;EGYPTIAN HIEROGLYPH-13917;Lo;0;L;;;;;N;;;;;\n13918;EGYPTIAN HIEROGLYPH-13918;Lo;0;L;;;;;N;;;;;\n13919;EGYPTIAN HIEROGLYPH-13919;Lo;0;L;;;;;N;;;;;\n1391A;EGYPTIAN HIEROGLYPH-1391A;Lo;0;L;;;;;N;;;;;\n1391B;EGYPTIAN HIEROGLYPH-1391B;Lo;0;L;;;;;N;;;;;\n1391C;EGYPTIAN HIEROGLYPH-1391C;Lo;0;L;;;;;N;;;;;\n1391D;EGYPTIAN HIEROGLYPH-1391D;Lo;0;L;;;;;N;;;;;\n1391E;EGYPTIAN HIEROGLYPH-1391E;Lo;0;L;;;;;N;;;;;\n1391F;EGYPTIAN HIEROGLYPH-1391F;Lo;0;L;;;;;N;;;;;\n13920;EGYPTIAN HIEROGLYPH-13920;Lo;0;L;;;;;N;;;;;\n13921;EGYPTIAN HIEROGLYPH-13921;Lo;0;L;;;;;N;;;;;\n13922;EGYPTIAN HIEROGLYPH-13922;Lo;0;L;;;;;N;;;;;\n13923;EGYPTIAN HIEROGLYPH-13923;Lo;0;L;;;;;N;;;;;\n13924;EGYPTIAN HIEROGLYPH-13924;Lo;0;L;;;;;N;;;;;\n13925;EGYPTIAN HIEROGLYPH-13925;Lo;0;L;;;;;N;;;;;\n13926;EGYPTIAN HIEROGLYPH-13926;Lo;0;L;;;;;N;;;;;\n13927;EGYPTIAN HIEROGLYPH-13927;Lo;0;L;;;;;N;;;;;\n13928;EGYPTIAN HIEROGLYPH-13928;Lo;0;L;;;;;N;;;;;\n13929;EGYPTIAN HIEROGLYPH-13929;Lo;0;L;;;;;N;;;;;\n1392A;EGYPTIAN HIEROGLYPH-1392A;Lo;0;L;;;;;N;;;;;\n1392B;EGYPTIAN HIEROGLYPH-1392B;Lo;0;L;;;;;N;;;;;\n1392C;EGYPTIAN HIEROGLYPH-1392C;Lo;0;L;;;;;N;;;;;\n1392D;EGYPTIAN HIEROGLYPH-1392D;Lo;0;L;;;;;N;;;;;\n1392E;EGYPTIAN HIEROGLYPH-1392E;Lo;0;L;;;;;N;;;;;\n1392F;EGYPTIAN HIEROGLYPH-1392F;Lo;0;L;;;;;N;;;;;\n13930;EGYPTIAN HIEROGLYPH-13930;Lo;0;L;;;;;N;;;;;\n13931;EGYPTIAN HIEROGLYPH-13931;Lo;0;L;;;;;N;;;;;\n13932;EGYPTIAN HIEROGLYPH-13932;Lo;0;L;;;;;N;;;;;\n13933;EGYPTIAN HIEROGLYPH-13933;Lo;0;L;;;;;N;;;;;\n13934;EGYPTIAN HIEROGLYPH-13934;Lo;0;L;;;;;N;;;;;\n13935;EGYPTIAN HIEROGLYPH-13935;Lo;0;L;;;;;N;;;;;\n13936;EGYPTIAN HIEROGLYPH-13936;Lo;0;L;;;;;N;;;;;\n13937;EGYPTIAN HIEROGLYPH-13937;Lo;0;L;;;;;N;;;;;\n13938;EGYPTIAN HIEROGLYPH-13938;Lo;0;L;;;;;N;;;;;\n13939;EGYPTIAN HIEROGLYPH-13939;Lo;0;L;;;;;N;;;;;\n1393A;EGYPTIAN HIEROGLYPH-1393A;Lo;0;L;;;;;N;;;;;\n1393B;EGYPTIAN HIEROGLYPH-1393B;Lo;0;L;;;;;N;;;;;\n1393C;EGYPTIAN HIEROGLYPH-1393C;Lo;0;L;;;;;N;;;;;\n1393D;EGYPTIAN HIEROGLYPH-1393D;Lo;0;L;;;;;N;;;;;\n1393E;EGYPTIAN HIEROGLYPH-1393E;Lo;0;L;;;;;N;;;;;\n1393F;EGYPTIAN HIEROGLYPH-1393F;Lo;0;L;;;;;N;;;;;\n13940;EGYPTIAN HIEROGLYPH-13940;Lo;0;L;;;;;N;;;;;\n13941;EGYPTIAN HIEROGLYPH-13941;Lo;0;L;;;;;N;;;;;\n13942;EGYPTIAN HIEROGLYPH-13942;Lo;0;L;;;;;N;;;;;\n13943;EGYPTIAN HIEROGLYPH-13943;Lo;0;L;;;;;N;;;;;\n13944;EGYPTIAN HIEROGLYPH-13944;Lo;0;L;;;;;N;;;;;\n13945;EGYPTIAN HIEROGLYPH-13945;Lo;0;L;;;;;N;;;;;\n13946;EGYPTIAN HIEROGLYPH-13946;Lo;0;L;;;;;N;;;;;\n13947;EGYPTIAN HIEROGLYPH-13947;Lo;0;L;;;;;N;;;;;\n13948;EGYPTIAN HIEROGLYPH-13948;Lo;0;L;;;;;N;;;;;\n13949;EGYPTIAN HIEROGLYPH-13949;Lo;0;L;;;;;N;;;;;\n1394A;EGYPTIAN HIEROGLYPH-1394A;Lo;0;L;;;;;N;;;;;\n1394B;EGYPTIAN HIEROGLYPH-1394B;Lo;0;L;;;;;N;;;;;\n1394C;EGYPTIAN HIEROGLYPH-1394C;Lo;0;L;;;;;N;;;;;\n1394D;EGYPTIAN HIEROGLYPH-1394D;Lo;0;L;;;;;N;;;;;\n1394E;EGYPTIAN HIEROGLYPH-1394E;Lo;0;L;;;;;N;;;;;\n1394F;EGYPTIAN HIEROGLYPH-1394F;Lo;0;L;;;;;N;;;;;\n13950;EGYPTIAN HIEROGLYPH-13950;Lo;0;L;;;;;N;;;;;\n13951;EGYPTIAN HIEROGLYPH-13951;Lo;0;L;;;;;N;;;;;\n13952;EGYPTIAN HIEROGLYPH-13952;Lo;0;L;;;;;N;;;;;\n13953;EGYPTIAN HIEROGLYPH-13953;Lo;0;L;;;;;N;;;;;\n13954;EGYPTIAN HIEROGLYPH-13954;Lo;0;L;;;;;N;;;;;\n13955;EGYPTIAN HIEROGLYPH-13955;Lo;0;L;;;;;N;;;;;\n13956;EGYPTIAN HIEROGLYPH-13956;Lo;0;L;;;;;N;;;;;\n13957;EGYPTIAN HIEROGLYPH-13957;Lo;0;L;;;;;N;;;;;\n13958;EGYPTIAN HIEROGLYPH-13958;Lo;0;L;;;;;N;;;;;\n13959;EGYPTIAN HIEROGLYPH-13959;Lo;0;L;;;;;N;;;;;\n1395A;EGYPTIAN HIEROGLYPH-1395A;Lo;0;L;;;;;N;;;;;\n1395B;EGYPTIAN HIEROGLYPH-1395B;Lo;0;L;;;;;N;;;;;\n1395C;EGYPTIAN HIEROGLYPH-1395C;Lo;0;L;;;;;N;;;;;\n1395D;EGYPTIAN HIEROGLYPH-1395D;Lo;0;L;;;;;N;;;;;\n1395E;EGYPTIAN HIEROGLYPH-1395E;Lo;0;L;;;;;N;;;;;\n1395F;EGYPTIAN HIEROGLYPH-1395F;Lo;0;L;;;;;N;;;;;\n13960;EGYPTIAN HIEROGLYPH-13960;Lo;0;L;;;;;N;;;;;\n13961;EGYPTIAN HIEROGLYPH-13961;Lo;0;L;;;;;N;;;;;\n13962;EGYPTIAN HIEROGLYPH-13962;Lo;0;L;;;;;N;;;;;\n13963;EGYPTIAN HIEROGLYPH-13963;Lo;0;L;;;;;N;;;;;\n13964;EGYPTIAN HIEROGLYPH-13964;Lo;0;L;;;;;N;;;;;\n13965;EGYPTIAN HIEROGLYPH-13965;Lo;0;L;;;;;N;;;;;\n13966;EGYPTIAN HIEROGLYPH-13966;Lo;0;L;;;;;N;;;;;\n13967;EGYPTIAN HIEROGLYPH-13967;Lo;0;L;;;;;N;;;;;\n13968;EGYPTIAN HIEROGLYPH-13968;Lo;0;L;;;;;N;;;;;\n13969;EGYPTIAN HIEROGLYPH-13969;Lo;0;L;;;;;N;;;;;\n1396A;EGYPTIAN HIEROGLYPH-1396A;Lo;0;L;;;;;N;;;;;\n1396B;EGYPTIAN HIEROGLYPH-1396B;Lo;0;L;;;;;N;;;;;\n1396C;EGYPTIAN HIEROGLYPH-1396C;Lo;0;L;;;;;N;;;;;\n1396D;EGYPTIAN HIEROGLYPH-1396D;Lo;0;L;;;;;N;;;;;\n1396E;EGYPTIAN HIEROGLYPH-1396E;Lo;0;L;;;;;N;;;;;\n1396F;EGYPTIAN HIEROGLYPH-1396F;Lo;0;L;;;;;N;;;;;\n13970;EGYPTIAN HIEROGLYPH-13970;Lo;0;L;;;;;N;;;;;\n13971;EGYPTIAN HIEROGLYPH-13971;Lo;0;L;;;;;N;;;;;\n13972;EGYPTIAN HIEROGLYPH-13972;Lo;0;L;;;;;N;;;;;\n13973;EGYPTIAN HIEROGLYPH-13973;Lo;0;L;;;;;N;;;;;\n13974;EGYPTIAN HIEROGLYPH-13974;Lo;0;L;;;;;N;;;;;\n13975;EGYPTIAN HIEROGLYPH-13975;Lo;0;L;;;;;N;;;;;\n13976;EGYPTIAN HIEROGLYPH-13976;Lo;0;L;;;;;N;;;;;\n13977;EGYPTIAN HIEROGLYPH-13977;Lo;0;L;;;;;N;;;;;\n13978;EGYPTIAN HIEROGLYPH-13978;Lo;0;L;;;;;N;;;;;\n13979;EGYPTIAN HIEROGLYPH-13979;Lo;0;L;;;;;N;;;;;\n1397A;EGYPTIAN HIEROGLYPH-1397A;Lo;0;L;;;;;N;;;;;\n1397B;EGYPTIAN HIEROGLYPH-1397B;Lo;0;L;;;;;N;;;;;\n1397C;EGYPTIAN HIEROGLYPH-1397C;Lo;0;L;;;;;N;;;;;\n1397D;EGYPTIAN HIEROGLYPH-1397D;Lo;0;L;;;;;N;;;;;\n1397E;EGYPTIAN HIEROGLYPH-1397E;Lo;0;L;;;;;N;;;;;\n1397F;EGYPTIAN HIEROGLYPH-1397F;Lo;0;L;;;;;N;;;;;\n13980;EGYPTIAN HIEROGLYPH-13980;Lo;0;L;;;;;N;;;;;\n13981;EGYPTIAN HIEROGLYPH-13981;Lo;0;L;;;;;N;;;;;\n13982;EGYPTIAN HIEROGLYPH-13982;Lo;0;L;;;;;N;;;;;\n13983;EGYPTIAN HIEROGLYPH-13983;Lo;0;L;;;;;N;;;;;\n13984;EGYPTIAN HIEROGLYPH-13984;Lo;0;L;;;;;N;;;;;\n13985;EGYPTIAN HIEROGLYPH-13985;Lo;0;L;;;;;N;;;;;\n13986;EGYPTIAN HIEROGLYPH-13986;Lo;0;L;;;;;N;;;;;\n13987;EGYPTIAN HIEROGLYPH-13987;Lo;0;L;;;;;N;;;;;\n13988;EGYPTIAN HIEROGLYPH-13988;Lo;0;L;;;;;N;;;;;\n13989;EGYPTIAN HIEROGLYPH-13989;Lo;0;L;;;;;N;;;;;\n1398A;EGYPTIAN HIEROGLYPH-1398A;Lo;0;L;;;;;N;;;;;\n1398B;EGYPTIAN HIEROGLYPH-1398B;Lo;0;L;;;;;N;;;;;\n1398C;EGYPTIAN HIEROGLYPH-1398C;Lo;0;L;;;;;N;;;;;\n1398D;EGYPTIAN HIEROGLYPH-1398D;Lo;0;L;;;;;N;;;;;\n1398E;EGYPTIAN HIEROGLYPH-1398E;Lo;0;L;;;;;N;;;;;\n1398F;EGYPTIAN HIEROGLYPH-1398F;Lo;0;L;;;;;N;;;;;\n13990;EGYPTIAN HIEROGLYPH-13990;Lo;0;L;;;;;N;;;;;\n13991;EGYPTIAN HIEROGLYPH-13991;Lo;0;L;;;;;N;;;;;\n13992;EGYPTIAN HIEROGLYPH-13992;Lo;0;L;;;;;N;;;;;\n13993;EGYPTIAN HIEROGLYPH-13993;Lo;0;L;;;;;N;;;;;\n13994;EGYPTIAN HIEROGLYPH-13994;Lo;0;L;;;;;N;;;;;\n13995;EGYPTIAN HIEROGLYPH-13995;Lo;0;L;;;;;N;;;;;\n13996;EGYPTIAN HIEROGLYPH-13996;Lo;0;L;;;;;N;;;;;\n13997;EGYPTIAN HIEROGLYPH-13997;Lo;0;L;;;;;N;;;;;\n13998;EGYPTIAN HIEROGLYPH-13998;Lo;0;L;;;;;N;;;;;\n13999;EGYPTIAN HIEROGLYPH-13999;Lo;0;L;;;;;N;;;;;\n1399A;EGYPTIAN HIEROGLYPH-1399A;Lo;0;L;;;;;N;;;;;\n1399B;EGYPTIAN HIEROGLYPH-1399B;Lo;0;L;;;;;N;;;;;\n1399C;EGYPTIAN HIEROGLYPH-1399C;Lo;0;L;;;;;N;;;;;\n1399D;EGYPTIAN HIEROGLYPH-1399D;Lo;0;L;;;;;N;;;;;\n1399E;EGYPTIAN HIEROGLYPH-1399E;Lo;0;L;;;;;N;;;;;\n1399F;EGYPTIAN HIEROGLYPH-1399F;Lo;0;L;;;;;N;;;;;\n139A0;EGYPTIAN HIEROGLYPH-139A0;Lo;0;L;;;;;N;;;;;\n139A1;EGYPTIAN HIEROGLYPH-139A1;Lo;0;L;;;;;N;;;;;\n139A2;EGYPTIAN HIEROGLYPH-139A2;Lo;0;L;;;;;N;;;;;\n139A3;EGYPTIAN HIEROGLYPH-139A3;Lo;0;L;;;;;N;;;;;\n139A4;EGYPTIAN HIEROGLYPH-139A4;Lo;0;L;;;;;N;;;;;\n139A5;EGYPTIAN HIEROGLYPH-139A5;Lo;0;L;;;;;N;;;;;\n139A6;EGYPTIAN HIEROGLYPH-139A6;Lo;0;L;;;;;N;;;;;\n139A7;EGYPTIAN HIEROGLYPH-139A7;Lo;0;L;;;;;N;;;;;\n139A8;EGYPTIAN HIEROGLYPH-139A8;Lo;0;L;;;;;N;;;;;\n139A9;EGYPTIAN HIEROGLYPH-139A9;Lo;0;L;;;;;N;;;;;\n139AA;EGYPTIAN HIEROGLYPH-139AA;Lo;0;L;;;;;N;;;;;\n139AB;EGYPTIAN HIEROGLYPH-139AB;Lo;0;L;;;;;N;;;;;\n139AC;EGYPTIAN HIEROGLYPH-139AC;Lo;0;L;;;;;N;;;;;\n139AD;EGYPTIAN HIEROGLYPH-139AD;Lo;0;L;;;;;N;;;;;\n139AE;EGYPTIAN HIEROGLYPH-139AE;Lo;0;L;;;;;N;;;;;\n139AF;EGYPTIAN HIEROGLYPH-139AF;Lo;0;L;;;;;N;;;;;\n139B0;EGYPTIAN HIEROGLYPH-139B0;Lo;0;L;;;;;N;;;;;\n139B1;EGYPTIAN HIEROGLYPH-139B1;Lo;0;L;;;;;N;;;;;\n139B2;EGYPTIAN HIEROGLYPH-139B2;Lo;0;L;;;;;N;;;;;\n139B3;EGYPTIAN HIEROGLYPH-139B3;Lo;0;L;;;;;N;;;;;\n139B4;EGYPTIAN HIEROGLYPH-139B4;Lo;0;L;;;;;N;;;;;\n139B5;EGYPTIAN HIEROGLYPH-139B5;Lo;0;L;;;;;N;;;;;\n139B6;EGYPTIAN HIEROGLYPH-139B6;Lo;0;L;;;;;N;;;;;\n139B7;EGYPTIAN HIEROGLYPH-139B7;Lo;0;L;;;;;N;;;;;\n139B8;EGYPTIAN HIEROGLYPH-139B8;Lo;0;L;;;;;N;;;;;\n139B9;EGYPTIAN HIEROGLYPH-139B9;Lo;0;L;;;;;N;;;;;\n139BA;EGYPTIAN HIEROGLYPH-139BA;Lo;0;L;;;;;N;;;;;\n139BB;EGYPTIAN HIEROGLYPH-139BB;Lo;0;L;;;;;N;;;;;\n139BC;EGYPTIAN HIEROGLYPH-139BC;Lo;0;L;;;;;N;;;;;\n139BD;EGYPTIAN HIEROGLYPH-139BD;Lo;0;L;;;;;N;;;;;\n139BE;EGYPTIAN HIEROGLYPH-139BE;Lo;0;L;;;;;N;;;;;\n139BF;EGYPTIAN HIEROGLYPH-139BF;Lo;0;L;;;;;N;;;;;\n139C0;EGYPTIAN HIEROGLYPH-139C0;Lo;0;L;;;;;N;;;;;\n139C1;EGYPTIAN HIEROGLYPH-139C1;Lo;0;L;;;;;N;;;;;\n139C2;EGYPTIAN HIEROGLYPH-139C2;Lo;0;L;;;;;N;;;;;\n139C3;EGYPTIAN HIEROGLYPH-139C3;Lo;0;L;;;;;N;;;;;\n139C4;EGYPTIAN HIEROGLYPH-139C4;Lo;0;L;;;;;N;;;;;\n139C5;EGYPTIAN HIEROGLYPH-139C5;Lo;0;L;;;;;N;;;;;\n139C6;EGYPTIAN HIEROGLYPH-139C6;Lo;0;L;;;;;N;;;;;\n139C7;EGYPTIAN HIEROGLYPH-139C7;Lo;0;L;;;;;N;;;;;\n139C8;EGYPTIAN HIEROGLYPH-139C8;Lo;0;L;;;;;N;;;;;\n139C9;EGYPTIAN HIEROGLYPH-139C9;Lo;0;L;;;;;N;;;;;\n139CA;EGYPTIAN HIEROGLYPH-139CA;Lo;0;L;;;;;N;;;;;\n139CB;EGYPTIAN HIEROGLYPH-139CB;Lo;0;L;;;;;N;;;;;\n139CC;EGYPTIAN HIEROGLYPH-139CC;Lo;0;L;;;;;N;;;;;\n139CD;EGYPTIAN HIEROGLYPH-139CD;Lo;0;L;;;;;N;;;;;\n139CE;EGYPTIAN HIEROGLYPH-139CE;Lo;0;L;;;;;N;;;;;\n139CF;EGYPTIAN HIEROGLYPH-139CF;Lo;0;L;;;;;N;;;;;\n139D0;EGYPTIAN HIEROGLYPH-139D0;Lo;0;L;;;;;N;;;;;\n139D1;EGYPTIAN HIEROGLYPH-139D1;Lo;0;L;;;;;N;;;;;\n139D2;EGYPTIAN HIEROGLYPH-139D2;Lo;0;L;;;;;N;;;;;\n139D3;EGYPTIAN HIEROGLYPH-139D3;Lo;0;L;;;;;N;;;;;\n139D4;EGYPTIAN HIEROGLYPH-139D4;Lo;0;L;;;;;N;;;;;\n139D5;EGYPTIAN HIEROGLYPH-139D5;Lo;0;L;;;;;N;;;;;\n139D6;EGYPTIAN HIEROGLYPH-139D6;Lo;0;L;;;;;N;;;;;\n139D7;EGYPTIAN HIEROGLYPH-139D7;Lo;0;L;;;;;N;;;;;\n139D8;EGYPTIAN HIEROGLYPH-139D8;Lo;0;L;;;;;N;;;;;\n139D9;EGYPTIAN HIEROGLYPH-139D9;Lo;0;L;;;;;N;;;;;\n139DA;EGYPTIAN HIEROGLYPH-139DA;Lo;0;L;;;;;N;;;;;\n139DB;EGYPTIAN HIEROGLYPH-139DB;Lo;0;L;;;;;N;;;;;\n139DC;EGYPTIAN HIEROGLYPH-139DC;Lo;0;L;;;;;N;;;;;\n139DD;EGYPTIAN HIEROGLYPH-139DD;Lo;0;L;;;;;N;;;;;\n139DE;EGYPTIAN HIEROGLYPH-139DE;Lo;0;L;;;;;N;;;;;\n139DF;EGYPTIAN HIEROGLYPH-139DF;Lo;0;L;;;;;N;;;;;\n139E0;EGYPTIAN HIEROGLYPH-139E0;Lo;0;L;;;;;N;;;;;\n139E1;EGYPTIAN HIEROGLYPH-139E1;Lo;0;L;;;;;N;;;;;\n139E2;EGYPTIAN HIEROGLYPH-139E2;Lo;0;L;;;;;N;;;;;\n139E3;EGYPTIAN HIEROGLYPH-139E3;Lo;0;L;;;;;N;;;;;\n139E4;EGYPTIAN HIEROGLYPH-139E4;Lo;0;L;;;;;N;;;;;\n139E5;EGYPTIAN HIEROGLYPH-139E5;Lo;0;L;;;;;N;;;;;\n139E6;EGYPTIAN HIEROGLYPH-139E6;Lo;0;L;;;;;N;;;;;\n139E7;EGYPTIAN HIEROGLYPH-139E7;Lo;0;L;;;;;N;;;;;\n139E8;EGYPTIAN HIEROGLYPH-139E8;Lo;0;L;;;;;N;;;;;\n139E9;EGYPTIAN HIEROGLYPH-139E9;Lo;0;L;;;;;N;;;;;\n139EA;EGYPTIAN HIEROGLYPH-139EA;Lo;0;L;;;;;N;;;;;\n139EB;EGYPTIAN HIEROGLYPH-139EB;Lo;0;L;;;;;N;;;;;\n139EC;EGYPTIAN HIEROGLYPH-139EC;Lo;0;L;;;;;N;;;;;\n139ED;EGYPTIAN HIEROGLYPH-139ED;Lo;0;L;;;;;N;;;;;\n139EE;EGYPTIAN HIEROGLYPH-139EE;Lo;0;L;;;;;N;;;;;\n139EF;EGYPTIAN HIEROGLYPH-139EF;Lo;0;L;;;;;N;;;;;\n139F0;EGYPTIAN HIEROGLYPH-139F0;Lo;0;L;;;;;N;;;;;\n139F1;EGYPTIAN HIEROGLYPH-139F1;Lo;0;L;;;;;N;;;;;\n139F2;EGYPTIAN HIEROGLYPH-139F2;Lo;0;L;;;;;N;;;;;\n139F3;EGYPTIAN HIEROGLYPH-139F3;Lo;0;L;;;;;N;;;;;\n139F4;EGYPTIAN HIEROGLYPH-139F4;Lo;0;L;;;;;N;;;;;\n139F5;EGYPTIAN HIEROGLYPH-139F5;Lo;0;L;;;;;N;;;;;\n139F6;EGYPTIAN HIEROGLYPH-139F6;Lo;0;L;;;;;N;;;;;\n139F7;EGYPTIAN HIEROGLYPH-139F7;Lo;0;L;;;;;N;;;;;\n139F8;EGYPTIAN HIEROGLYPH-139F8;Lo;0;L;;;;;N;;;;;\n139F9;EGYPTIAN HIEROGLYPH-139F9;Lo;0;L;;;;;N;;;;;\n139FA;EGYPTIAN HIEROGLYPH-139FA;Lo;0;L;;;;;N;;;;;\n139FB;EGYPTIAN HIEROGLYPH-139FB;Lo;0;L;;;;;N;;;;;\n139FC;EGYPTIAN HIEROGLYPH-139FC;Lo;0;L;;;;;N;;;;;\n139FD;EGYPTIAN HIEROGLYPH-139FD;Lo;0;L;;;;;N;;;;;\n139FE;EGYPTIAN HIEROGLYPH-139FE;Lo;0;L;;;;;N;;;;;\n139FF;EGYPTIAN HIEROGLYPH-139FF;Lo;0;L;;;;;N;;;;;\n13A00;EGYPTIAN HIEROGLYPH-13A00;Lo;0;L;;;;;N;;;;;\n13A01;EGYPTIAN HIEROGLYPH-13A01;Lo;0;L;;;;;N;;;;;\n13A02;EGYPTIAN HIEROGLYPH-13A02;Lo;0;L;;;;;N;;;;;\n13A03;EGYPTIAN HIEROGLYPH-13A03;Lo;0;L;;;;;N;;;;;\n13A04;EGYPTIAN HIEROGLYPH-13A04;Lo;0;L;;;;;N;;;;;\n13A05;EGYPTIAN HIEROGLYPH-13A05;Lo;0;L;;;;;N;;;;;\n13A06;EGYPTIAN HIEROGLYPH-13A06;Lo;0;L;;;;;N;;;;;\n13A07;EGYPTIAN HIEROGLYPH-13A07;Lo;0;L;;;;;N;;;;;\n13A08;EGYPTIAN HIEROGLYPH-13A08;Lo;0;L;;;;;N;;;;;\n13A09;EGYPTIAN HIEROGLYPH-13A09;Lo;0;L;;;;;N;;;;;\n13A0A;EGYPTIAN HIEROGLYPH-13A0A;Lo;0;L;;;;;N;;;;;\n13A0B;EGYPTIAN HIEROGLYPH-13A0B;Lo;0;L;;;;;N;;;;;\n13A0C;EGYPTIAN HIEROGLYPH-13A0C;Lo;0;L;;;;;N;;;;;\n13A0D;EGYPTIAN HIEROGLYPH-13A0D;Lo;0;L;;;;;N;;;;;\n13A0E;EGYPTIAN HIEROGLYPH-13A0E;Lo;0;L;;;;;N;;;;;\n13A0F;EGYPTIAN HIEROGLYPH-13A0F;Lo;0;L;;;;;N;;;;;\n13A10;EGYPTIAN HIEROGLYPH-13A10;Lo;0;L;;;;;N;;;;;\n13A11;EGYPTIAN HIEROGLYPH-13A11;Lo;0;L;;;;;N;;;;;\n13A12;EGYPTIAN HIEROGLYPH-13A12;Lo;0;L;;;;;N;;;;;\n13A13;EGYPTIAN HIEROGLYPH-13A13;Lo;0;L;;;;;N;;;;;\n13A14;EGYPTIAN HIEROGLYPH-13A14;Lo;0;L;;;;;N;;;;;\n13A15;EGYPTIAN HIEROGLYPH-13A15;Lo;0;L;;;;;N;;;;;\n13A16;EGYPTIAN HIEROGLYPH-13A16;Lo;0;L;;;;;N;;;;;\n13A17;EGYPTIAN HIEROGLYPH-13A17;Lo;0;L;;;;;N;;;;;\n13A18;EGYPTIAN HIEROGLYPH-13A18;Lo;0;L;;;;;N;;;;;\n13A19;EGYPTIAN HIEROGLYPH-13A19;Lo;0;L;;;;;N;;;;;\n13A1A;EGYPTIAN HIEROGLYPH-13A1A;Lo;0;L;;;;;N;;;;;\n13A1B;EGYPTIAN HIEROGLYPH-13A1B;Lo;0;L;;;;;N;;;;;\n13A1C;EGYPTIAN HIEROGLYPH-13A1C;Lo;0;L;;;;;N;;;;;\n13A1D;EGYPTIAN HIEROGLYPH-13A1D;Lo;0;L;;;;;N;;;;;\n13A1E;EGYPTIAN HIEROGLYPH-13A1E;Lo;0;L;;;;;N;;;;;\n13A1F;EGYPTIAN HIEROGLYPH-13A1F;Lo;0;L;;;;;N;;;;;\n13A20;EGYPTIAN HIEROGLYPH-13A20;Lo;0;L;;;;;N;;;;;\n13A21;EGYPTIAN HIEROGLYPH-13A21;Lo;0;L;;;;;N;;;;;\n13A22;EGYPTIAN HIEROGLYPH-13A22;Lo;0;L;;;;;N;;;;;\n13A23;EGYPTIAN HIEROGLYPH-13A23;Lo;0;L;;;;;N;;;;;\n13A24;EGYPTIAN HIEROGLYPH-13A24;Lo;0;L;;;;;N;;;;;\n13A25;EGYPTIAN HIEROGLYPH-13A25;Lo;0;L;;;;;N;;;;;\n13A26;EGYPTIAN HIEROGLYPH-13A26;Lo;0;L;;;;;N;;;;;\n13A27;EGYPTIAN HIEROGLYPH-13A27;Lo;0;L;;;;;N;;;;;\n13A28;EGYPTIAN HIEROGLYPH-13A28;Lo;0;L;;;;;N;;;;;\n13A29;EGYPTIAN HIEROGLYPH-13A29;Lo;0;L;;;;;N;;;;;\n13A2A;EGYPTIAN HIEROGLYPH-13A2A;Lo;0;L;;;;;N;;;;;\n13A2B;EGYPTIAN HIEROGLYPH-13A2B;Lo;0;L;;;;;N;;;;;\n13A2C;EGYPTIAN HIEROGLYPH-13A2C;Lo;0;L;;;;;N;;;;;\n13A2D;EGYPTIAN HIEROGLYPH-13A2D;Lo;0;L;;;;;N;;;;;\n13A2E;EGYPTIAN HIEROGLYPH-13A2E;Lo;0;L;;;;;N;;;;;\n13A2F;EGYPTIAN HIEROGLYPH-13A2F;Lo;0;L;;;;;N;;;;;\n13A30;EGYPTIAN HIEROGLYPH-13A30;Lo;0;L;;;;;N;;;;;\n13A31;EGYPTIAN HIEROGLYPH-13A31;Lo;0;L;;;;;N;;;;;\n13A32;EGYPTIAN HIEROGLYPH-13A32;Lo;0;L;;;;;N;;;;;\n13A33;EGYPTIAN HIEROGLYPH-13A33;Lo;0;L;;;;;N;;;;;\n13A34;EGYPTIAN HIEROGLYPH-13A34;Lo;0;L;;;;;N;;;;;\n13A35;EGYPTIAN HIEROGLYPH-13A35;Lo;0;L;;;;;N;;;;;\n13A36;EGYPTIAN HIEROGLYPH-13A36;Lo;0;L;;;;;N;;;;;\n13A37;EGYPTIAN HIEROGLYPH-13A37;Lo;0;L;;;;;N;;;;;\n13A38;EGYPTIAN HIEROGLYPH-13A38;Lo;0;L;;;;;N;;;;;\n13A39;EGYPTIAN HIEROGLYPH-13A39;Lo;0;L;;;;;N;;;;;\n13A3A;EGYPTIAN HIEROGLYPH-13A3A;Lo;0;L;;;;;N;;;;;\n13A3B;EGYPTIAN HIEROGLYPH-13A3B;Lo;0;L;;;;;N;;;;;\n13A3C;EGYPTIAN HIEROGLYPH-13A3C;Lo;0;L;;;;;N;;;;;\n13A3D;EGYPTIAN HIEROGLYPH-13A3D;Lo;0;L;;;;;N;;;;;\n13A3E;EGYPTIAN HIEROGLYPH-13A3E;Lo;0;L;;;;;N;;;;;\n13A3F;EGYPTIAN HIEROGLYPH-13A3F;Lo;0;L;;;;;N;;;;;\n13A40;EGYPTIAN HIEROGLYPH-13A40;Lo;0;L;;;;;N;;;;;\n13A41;EGYPTIAN HIEROGLYPH-13A41;Lo;0;L;;;;;N;;;;;\n13A42;EGYPTIAN HIEROGLYPH-13A42;Lo;0;L;;;;;N;;;;;\n13A43;EGYPTIAN HIEROGLYPH-13A43;Lo;0;L;;;;;N;;;;;\n13A44;EGYPTIAN HIEROGLYPH-13A44;Lo;0;L;;;;;N;;;;;\n13A45;EGYPTIAN HIEROGLYPH-13A45;Lo;0;L;;;;;N;;;;;\n13A46;EGYPTIAN HIEROGLYPH-13A46;Lo;0;L;;;;;N;;;;;\n13A47;EGYPTIAN HIEROGLYPH-13A47;Lo;0;L;;;;;N;;;;;\n13A48;EGYPTIAN HIEROGLYPH-13A48;Lo;0;L;;;;;N;;;;;\n13A49;EGYPTIAN HIEROGLYPH-13A49;Lo;0;L;;;;;N;;;;;\n13A4A;EGYPTIAN HIEROGLYPH-13A4A;Lo;0;L;;;;;N;;;;;\n13A4B;EGYPTIAN HIEROGLYPH-13A4B;Lo;0;L;;;;;N;;;;;\n13A4C;EGYPTIAN HIEROGLYPH-13A4C;Lo;0;L;;;;;N;;;;;\n13A4D;EGYPTIAN HIEROGLYPH-13A4D;Lo;0;L;;;;;N;;;;;\n13A4E;EGYPTIAN HIEROGLYPH-13A4E;Lo;0;L;;;;;N;;;;;\n13A4F;EGYPTIAN HIEROGLYPH-13A4F;Lo;0;L;;;;;N;;;;;\n13A50;EGYPTIAN HIEROGLYPH-13A50;Lo;0;L;;;;;N;;;;;\n13A51;EGYPTIAN HIEROGLYPH-13A51;Lo;0;L;;;;;N;;;;;\n13A52;EGYPTIAN HIEROGLYPH-13A52;Lo;0;L;;;;;N;;;;;\n13A53;EGYPTIAN HIEROGLYPH-13A53;Lo;0;L;;;;;N;;;;;\n13A54;EGYPTIAN HIEROGLYPH-13A54;Lo;0;L;;;;;N;;;;;\n13A55;EGYPTIAN HIEROGLYPH-13A55;Lo;0;L;;;;;N;;;;;\n13A56;EGYPTIAN HIEROGLYPH-13A56;Lo;0;L;;;;;N;;;;;\n13A57;EGYPTIAN HIEROGLYPH-13A57;Lo;0;L;;;;;N;;;;;\n13A58;EGYPTIAN HIEROGLYPH-13A58;Lo;0;L;;;;;N;;;;;\n13A59;EGYPTIAN HIEROGLYPH-13A59;Lo;0;L;;;;;N;;;;;\n13A5A;EGYPTIAN HIEROGLYPH-13A5A;Lo;0;L;;;;;N;;;;;\n13A5B;EGYPTIAN HIEROGLYPH-13A5B;Lo;0;L;;;;;N;;;;;\n13A5C;EGYPTIAN HIEROGLYPH-13A5C;Lo;0;L;;;;;N;;;;;\n13A5D;EGYPTIAN HIEROGLYPH-13A5D;Lo;0;L;;;;;N;;;;;\n13A5E;EGYPTIAN HIEROGLYPH-13A5E;Lo;0;L;;;;;N;;;;;\n13A5F;EGYPTIAN HIEROGLYPH-13A5F;Lo;0;L;;;;;N;;;;;\n13A60;EGYPTIAN HIEROGLYPH-13A60;Lo;0;L;;;;;N;;;;;\n13A61;EGYPTIAN HIEROGLYPH-13A61;Lo;0;L;;;;;N;;;;;\n13A62;EGYPTIAN HIEROGLYPH-13A62;Lo;0;L;;;;;N;;;;;\n13A63;EGYPTIAN HIEROGLYPH-13A63;Lo;0;L;;;;;N;;;;;\n13A64;EGYPTIAN HIEROGLYPH-13A64;Lo;0;L;;;;;N;;;;;\n13A65;EGYPTIAN HIEROGLYPH-13A65;Lo;0;L;;;;;N;;;;;\n13A66;EGYPTIAN HIEROGLYPH-13A66;Lo;0;L;;;;;N;;;;;\n13A67;EGYPTIAN HIEROGLYPH-13A67;Lo;0;L;;;;;N;;;;;\n13A68;EGYPTIAN HIEROGLYPH-13A68;Lo;0;L;;;;;N;;;;;\n13A69;EGYPTIAN HIEROGLYPH-13A69;Lo;0;L;;;;;N;;;;;\n13A6A;EGYPTIAN HIEROGLYPH-13A6A;Lo;0;L;;;;;N;;;;;\n13A6B;EGYPTIAN HIEROGLYPH-13A6B;Lo;0;L;;;;;N;;;;;\n13A6C;EGYPTIAN HIEROGLYPH-13A6C;Lo;0;L;;;;;N;;;;;\n13A6D;EGYPTIAN HIEROGLYPH-13A6D;Lo;0;L;;;;;N;;;;;\n13A6E;EGYPTIAN HIEROGLYPH-13A6E;Lo;0;L;;;;;N;;;;;\n13A6F;EGYPTIAN HIEROGLYPH-13A6F;Lo;0;L;;;;;N;;;;;\n13A70;EGYPTIAN HIEROGLYPH-13A70;Lo;0;L;;;;;N;;;;;\n13A71;EGYPTIAN HIEROGLYPH-13A71;Lo;0;L;;;;;N;;;;;\n13A72;EGYPTIAN HIEROGLYPH-13A72;Lo;0;L;;;;;N;;;;;\n13A73;EGYPTIAN HIEROGLYPH-13A73;Lo;0;L;;;;;N;;;;;\n13A74;EGYPTIAN HIEROGLYPH-13A74;Lo;0;L;;;;;N;;;;;\n13A75;EGYPTIAN HIEROGLYPH-13A75;Lo;0;L;;;;;N;;;;;\n13A76;EGYPTIAN HIEROGLYPH-13A76;Lo;0;L;;;;;N;;;;;\n13A77;EGYPTIAN HIEROGLYPH-13A77;Lo;0;L;;;;;N;;;;;\n13A78;EGYPTIAN HIEROGLYPH-13A78;Lo;0;L;;;;;N;;;;;\n13A79;EGYPTIAN HIEROGLYPH-13A79;Lo;0;L;;;;;N;;;;;\n13A7A;EGYPTIAN HIEROGLYPH-13A7A;Lo;0;L;;;;;N;;;;;\n13A7B;EGYPTIAN HIEROGLYPH-13A7B;Lo;0;L;;;;;N;;;;;\n13A7C;EGYPTIAN HIEROGLYPH-13A7C;Lo;0;L;;;;;N;;;;;\n13A7D;EGYPTIAN HIEROGLYPH-13A7D;Lo;0;L;;;;;N;;;;;\n13A7E;EGYPTIAN HIEROGLYPH-13A7E;Lo;0;L;;;;;N;;;;;\n13A7F;EGYPTIAN HIEROGLYPH-13A7F;Lo;0;L;;;;;N;;;;;\n13A80;EGYPTIAN HIEROGLYPH-13A80;Lo;0;L;;;;;N;;;;;\n13A81;EGYPTIAN HIEROGLYPH-13A81;Lo;0;L;;;;;N;;;;;\n13A82;EGYPTIAN HIEROGLYPH-13A82;Lo;0;L;;;;;N;;;;;\n13A83;EGYPTIAN HIEROGLYPH-13A83;Lo;0;L;;;;;N;;;;;\n13A84;EGYPTIAN HIEROGLYPH-13A84;Lo;0;L;;;;;N;;;;;\n13A85;EGYPTIAN HIEROGLYPH-13A85;Lo;0;L;;;;;N;;;;;\n13A86;EGYPTIAN HIEROGLYPH-13A86;Lo;0;L;;;;;N;;;;;\n13A87;EGYPTIAN HIEROGLYPH-13A87;Lo;0;L;;;;;N;;;;;\n13A88;EGYPTIAN HIEROGLYPH-13A88;Lo;0;L;;;;;N;;;;;\n13A89;EGYPTIAN HIEROGLYPH-13A89;Lo;0;L;;;;;N;;;;;\n13A8A;EGYPTIAN HIEROGLYPH-13A8A;Lo;0;L;;;;;N;;;;;\n13A8B;EGYPTIAN HIEROGLYPH-13A8B;Lo;0;L;;;;;N;;;;;\n13A8C;EGYPTIAN HIEROGLYPH-13A8C;Lo;0;L;;;;;N;;;;;\n13A8D;EGYPTIAN HIEROGLYPH-13A8D;Lo;0;L;;;;;N;;;;;\n13A8E;EGYPTIAN HIEROGLYPH-13A8E;Lo;0;L;;;;;N;;;;;\n13A8F;EGYPTIAN HIEROGLYPH-13A8F;Lo;0;L;;;;;N;;;;;\n13A90;EGYPTIAN HIEROGLYPH-13A90;Lo;0;L;;;;;N;;;;;\n13A91;EGYPTIAN HIEROGLYPH-13A91;Lo;0;L;;;;;N;;;;;\n13A92;EGYPTIAN HIEROGLYPH-13A92;Lo;0;L;;;;;N;;;;;\n13A93;EGYPTIAN HIEROGLYPH-13A93;Lo;0;L;;;;;N;;;;;\n13A94;EGYPTIAN HIEROGLYPH-13A94;Lo;0;L;;;;;N;;;;;\n13A95;EGYPTIAN HIEROGLYPH-13A95;Lo;0;L;;;;;N;;;;;\n13A96;EGYPTIAN HIEROGLYPH-13A96;Lo;0;L;;;;;N;;;;;\n13A97;EGYPTIAN HIEROGLYPH-13A97;Lo;0;L;;;;;N;;;;;\n13A98;EGYPTIAN HIEROGLYPH-13A98;Lo;0;L;;;;;N;;;;;\n13A99;EGYPTIAN HIEROGLYPH-13A99;Lo;0;L;;;;;N;;;;;\n13A9A;EGYPTIAN HIEROGLYPH-13A9A;Lo;0;L;;;;;N;;;;;\n13A9B;EGYPTIAN HIEROGLYPH-13A9B;Lo;0;L;;;;;N;;;;;\n13A9C;EGYPTIAN HIEROGLYPH-13A9C;Lo;0;L;;;;;N;;;;;\n13A9D;EGYPTIAN HIEROGLYPH-13A9D;Lo;0;L;;;;;N;;;;;\n13A9E;EGYPTIAN HIEROGLYPH-13A9E;Lo;0;L;;;;;N;;;;;\n13A9F;EGYPTIAN HIEROGLYPH-13A9F;Lo;0;L;;;;;N;;;;;\n13AA0;EGYPTIAN HIEROGLYPH-13AA0;Lo;0;L;;;;;N;;;;;\n13AA1;EGYPTIAN HIEROGLYPH-13AA1;Lo;0;L;;;;;N;;;;;\n13AA2;EGYPTIAN HIEROGLYPH-13AA2;Lo;0;L;;;;;N;;;;;\n13AA3;EGYPTIAN HIEROGLYPH-13AA3;Lo;0;L;;;;;N;;;;;\n13AA4;EGYPTIAN HIEROGLYPH-13AA4;Lo;0;L;;;;;N;;;;;\n13AA5;EGYPTIAN HIEROGLYPH-13AA5;Lo;0;L;;;;;N;;;;;\n13AA6;EGYPTIAN HIEROGLYPH-13AA6;Lo;0;L;;;;;N;;;;;\n13AA7;EGYPTIAN HIEROGLYPH-13AA7;Lo;0;L;;;;;N;;;;;\n13AA8;EGYPTIAN HIEROGLYPH-13AA8;Lo;0;L;;;;;N;;;;;\n13AA9;EGYPTIAN HIEROGLYPH-13AA9;Lo;0;L;;;;;N;;;;;\n13AAA;EGYPTIAN HIEROGLYPH-13AAA;Lo;0;L;;;;;N;;;;;\n13AAB;EGYPTIAN HIEROGLYPH-13AAB;Lo;0;L;;;;;N;;;;;\n13AAC;EGYPTIAN HIEROGLYPH-13AAC;Lo;0;L;;;;;N;;;;;\n13AAD;EGYPTIAN HIEROGLYPH-13AAD;Lo;0;L;;;;;N;;;;;\n13AAE;EGYPTIAN HIEROGLYPH-13AAE;Lo;0;L;;;;;N;;;;;\n13AAF;EGYPTIAN HIEROGLYPH-13AAF;Lo;0;L;;;;;N;;;;;\n13AB0;EGYPTIAN HIEROGLYPH-13AB0;Lo;0;L;;;;;N;;;;;\n13AB1;EGYPTIAN HIEROGLYPH-13AB1;Lo;0;L;;;;;N;;;;;\n13AB2;EGYPTIAN HIEROGLYPH-13AB2;Lo;0;L;;;;;N;;;;;\n13AB3;EGYPTIAN HIEROGLYPH-13AB3;Lo;0;L;;;;;N;;;;;\n13AB4;EGYPTIAN HIEROGLYPH-13AB4;Lo;0;L;;;;;N;;;;;\n13AB5;EGYPTIAN HIEROGLYPH-13AB5;Lo;0;L;;;;;N;;;;;\n13AB6;EGYPTIAN HIEROGLYPH-13AB6;Lo;0;L;;;;;N;;;;;\n13AB7;EGYPTIAN HIEROGLYPH-13AB7;Lo;0;L;;;;;N;;;;;\n13AB8;EGYPTIAN HIEROGLYPH-13AB8;Lo;0;L;;;;;N;;;;;\n13AB9;EGYPTIAN HIEROGLYPH-13AB9;Lo;0;L;;;;;N;;;;;\n13ABA;EGYPTIAN HIEROGLYPH-13ABA;Lo;0;L;;;;;N;;;;;\n13ABB;EGYPTIAN HIEROGLYPH-13ABB;Lo;0;L;;;;;N;;;;;\n13ABC;EGYPTIAN HIEROGLYPH-13ABC;Lo;0;L;;;;;N;;;;;\n13ABD;EGYPTIAN HIEROGLYPH-13ABD;Lo;0;L;;;;;N;;;;;\n13ABE;EGYPTIAN HIEROGLYPH-13ABE;Lo;0;L;;;;;N;;;;;\n13ABF;EGYPTIAN HIEROGLYPH-13ABF;Lo;0;L;;;;;N;;;;;\n13AC0;EGYPTIAN HIEROGLYPH-13AC0;Lo;0;L;;;;;N;;;;;\n13AC1;EGYPTIAN HIEROGLYPH-13AC1;Lo;0;L;;;;;N;;;;;\n13AC2;EGYPTIAN HIEROGLYPH-13AC2;Lo;0;L;;;;;N;;;;;\n13AC3;EGYPTIAN HIEROGLYPH-13AC3;Lo;0;L;;;;;N;;;;;\n13AC4;EGYPTIAN HIEROGLYPH-13AC4;Lo;0;L;;;;;N;;;;;\n13AC5;EGYPTIAN HIEROGLYPH-13AC5;Lo;0;L;;;;;N;;;;;\n13AC6;EGYPTIAN HIEROGLYPH-13AC6;Lo;0;L;;;;;N;;;;;\n13AC7;EGYPTIAN HIEROGLYPH-13AC7;Lo;0;L;;;;;N;;;;;\n13AC8;EGYPTIAN HIEROGLYPH-13AC8;Lo;0;L;;;;;N;;;;;\n13AC9;EGYPTIAN HIEROGLYPH-13AC9;Lo;0;L;;;;;N;;;;;\n13ACA;EGYPTIAN HIEROGLYPH-13ACA;Lo;0;L;;;;;N;;;;;\n13ACB;EGYPTIAN HIEROGLYPH-13ACB;Lo;0;L;;;;;N;;;;;\n13ACC;EGYPTIAN HIEROGLYPH-13ACC;Lo;0;L;;;;;N;;;;;\n13ACD;EGYPTIAN HIEROGLYPH-13ACD;Lo;0;L;;;;;N;;;;;\n13ACE;EGYPTIAN HIEROGLYPH-13ACE;Lo;0;L;;;;;N;;;;;\n13ACF;EGYPTIAN HIEROGLYPH-13ACF;Lo;0;L;;;;;N;;;;;\n13AD0;EGYPTIAN HIEROGLYPH-13AD0;Lo;0;L;;;;;N;;;;;\n13AD1;EGYPTIAN HIEROGLYPH-13AD1;Lo;0;L;;;;;N;;;;;\n13AD2;EGYPTIAN HIEROGLYPH-13AD2;Lo;0;L;;;;;N;;;;;\n13AD3;EGYPTIAN HIEROGLYPH-13AD3;Lo;0;L;;;;;N;;;;;\n13AD4;EGYPTIAN HIEROGLYPH-13AD4;Lo;0;L;;;;;N;;;;;\n13AD5;EGYPTIAN HIEROGLYPH-13AD5;Lo;0;L;;;;;N;;;;;\n13AD6;EGYPTIAN HIEROGLYPH-13AD6;Lo;0;L;;;;;N;;;;;\n13AD7;EGYPTIAN HIEROGLYPH-13AD7;Lo;0;L;;;;;N;;;;;\n13AD8;EGYPTIAN HIEROGLYPH-13AD8;Lo;0;L;;;;;N;;;;;\n13AD9;EGYPTIAN HIEROGLYPH-13AD9;Lo;0;L;;;;;N;;;;;\n13ADA;EGYPTIAN HIEROGLYPH-13ADA;Lo;0;L;;;;;N;;;;;\n13ADB;EGYPTIAN HIEROGLYPH-13ADB;Lo;0;L;;;;;N;;;;;\n13ADC;EGYPTIAN HIEROGLYPH-13ADC;Lo;0;L;;;;;N;;;;;\n13ADD;EGYPTIAN HIEROGLYPH-13ADD;Lo;0;L;;;;;N;;;;;\n13ADE;EGYPTIAN HIEROGLYPH-13ADE;Lo;0;L;;;;;N;;;;;\n13ADF;EGYPTIAN HIEROGLYPH-13ADF;Lo;0;L;;;;;N;;;;;\n13AE0;EGYPTIAN HIEROGLYPH-13AE0;Lo;0;L;;;;;N;;;;;\n13AE1;EGYPTIAN HIEROGLYPH-13AE1;Lo;0;L;;;;;N;;;;;\n13AE2;EGYPTIAN HIEROGLYPH-13AE2;Lo;0;L;;;;;N;;;;;\n13AE3;EGYPTIAN HIEROGLYPH-13AE3;Lo;0;L;;;;;N;;;;;\n13AE4;EGYPTIAN HIEROGLYPH-13AE4;Lo;0;L;;;;;N;;;;;\n13AE5;EGYPTIAN HIEROGLYPH-13AE5;Lo;0;L;;;;;N;;;;;\n13AE6;EGYPTIAN HIEROGLYPH-13AE6;Lo;0;L;;;;;N;;;;;\n13AE7;EGYPTIAN HIEROGLYPH-13AE7;Lo;0;L;;;;;N;;;;;\n13AE8;EGYPTIAN HIEROGLYPH-13AE8;Lo;0;L;;;;;N;;;;;\n13AE9;EGYPTIAN HIEROGLYPH-13AE9;Lo;0;L;;;;;N;;;;;\n13AEA;EGYPTIAN HIEROGLYPH-13AEA;Lo;0;L;;;;;N;;;;;\n13AEB;EGYPTIAN HIEROGLYPH-13AEB;Lo;0;L;;;;;N;;;;;\n13AEC;EGYPTIAN HIEROGLYPH-13AEC;Lo;0;L;;;;;N;;;;;\n13AED;EGYPTIAN HIEROGLYPH-13AED;Lo;0;L;;;;;N;;;;;\n13AEE;EGYPTIAN HIEROGLYPH-13AEE;Lo;0;L;;;;;N;;;;;\n13AEF;EGYPTIAN HIEROGLYPH-13AEF;Lo;0;L;;;;;N;;;;;\n13AF0;EGYPTIAN HIEROGLYPH-13AF0;Lo;0;L;;;;;N;;;;;\n13AF1;EGYPTIAN HIEROGLYPH-13AF1;Lo;0;L;;;;;N;;;;;\n13AF2;EGYPTIAN HIEROGLYPH-13AF2;Lo;0;L;;;;;N;;;;;\n13AF3;EGYPTIAN HIEROGLYPH-13AF3;Lo;0;L;;;;;N;;;;;\n13AF4;EGYPTIAN HIEROGLYPH-13AF4;Lo;0;L;;;;;N;;;;;\n13AF5;EGYPTIAN HIEROGLYPH-13AF5;Lo;0;L;;;;;N;;;;;\n13AF6;EGYPTIAN HIEROGLYPH-13AF6;Lo;0;L;;;;;N;;;;;\n13AF7;EGYPTIAN HIEROGLYPH-13AF7;Lo;0;L;;;;;N;;;;;\n13AF8;EGYPTIAN HIEROGLYPH-13AF8;Lo;0;L;;;;;N;;;;;\n13AF9;EGYPTIAN HIEROGLYPH-13AF9;Lo;0;L;;;;;N;;;;;\n13AFA;EGYPTIAN HIEROGLYPH-13AFA;Lo;0;L;;;;;N;;;;;\n13AFB;EGYPTIAN HIEROGLYPH-13AFB;Lo;0;L;;;;;N;;;;;\n13AFC;EGYPTIAN HIEROGLYPH-13AFC;Lo;0;L;;;;;N;;;;;\n13AFD;EGYPTIAN HIEROGLYPH-13AFD;Lo;0;L;;;;;N;;;;;\n13AFE;EGYPTIAN HIEROGLYPH-13AFE;Lo;0;L;;;;;N;;;;;\n13AFF;EGYPTIAN HIEROGLYPH-13AFF;Lo;0;L;;;;;N;;;;;\n13B00;EGYPTIAN HIEROGLYPH-13B00;Lo;0;L;;;;;N;;;;;\n13B01;EGYPTIAN HIEROGLYPH-13B01;Lo;0;L;;;;;N;;;;;\n13B02;EGYPTIAN HIEROGLYPH-13B02;Lo;0;L;;;;;N;;;;;\n13B03;EGYPTIAN HIEROGLYPH-13B03;Lo;0;L;;;;;N;;;;;\n13B04;EGYPTIAN HIEROGLYPH-13B04;Lo;0;L;;;;;N;;;;;\n13B05;EGYPTIAN HIEROGLYPH-13B05;Lo;0;L;;;;;N;;;;;\n13B06;EGYPTIAN HIEROGLYPH-13B06;Lo;0;L;;;;;N;;;;;\n13B07;EGYPTIAN HIEROGLYPH-13B07;Lo;0;L;;;;;N;;;;;\n13B08;EGYPTIAN HIEROGLYPH-13B08;Lo;0;L;;;;;N;;;;;\n13B09;EGYPTIAN HIEROGLYPH-13B09;Lo;0;L;;;;;N;;;;;\n13B0A;EGYPTIAN HIEROGLYPH-13B0A;Lo;0;L;;;;;N;;;;;\n13B0B;EGYPTIAN HIEROGLYPH-13B0B;Lo;0;L;;;;;N;;;;;\n13B0C;EGYPTIAN HIEROGLYPH-13B0C;Lo;0;L;;;;;N;;;;;\n13B0D;EGYPTIAN HIEROGLYPH-13B0D;Lo;0;L;;;;;N;;;;;\n13B0E;EGYPTIAN HIEROGLYPH-13B0E;Lo;0;L;;;;;N;;;;;\n13B0F;EGYPTIAN HIEROGLYPH-13B0F;Lo;0;L;;;;;N;;;;;\n13B10;EGYPTIAN HIEROGLYPH-13B10;Lo;0;L;;;;;N;;;;;\n13B11;EGYPTIAN HIEROGLYPH-13B11;Lo;0;L;;;;;N;;;;;\n13B12;EGYPTIAN HIEROGLYPH-13B12;Lo;0;L;;;;;N;;;;;\n13B13;EGYPTIAN HIEROGLYPH-13B13;Lo;0;L;;;;;N;;;;;\n13B14;EGYPTIAN HIEROGLYPH-13B14;Lo;0;L;;;;;N;;;;;\n13B15;EGYPTIAN HIEROGLYPH-13B15;Lo;0;L;;;;;N;;;;;\n13B16;EGYPTIAN HIEROGLYPH-13B16;Lo;0;L;;;;;N;;;;;\n13B17;EGYPTIAN HIEROGLYPH-13B17;Lo;0;L;;;;;N;;;;;\n13B18;EGYPTIAN HIEROGLYPH-13B18;Lo;0;L;;;;;N;;;;;\n13B19;EGYPTIAN HIEROGLYPH-13B19;Lo;0;L;;;;;N;;;;;\n13B1A;EGYPTIAN HIEROGLYPH-13B1A;Lo;0;L;;;;;N;;;;;\n13B1B;EGYPTIAN HIEROGLYPH-13B1B;Lo;0;L;;;;;N;;;;;\n13B1C;EGYPTIAN HIEROGLYPH-13B1C;Lo;0;L;;;;;N;;;;;\n13B1D;EGYPTIAN HIEROGLYPH-13B1D;Lo;0;L;;;;;N;;;;;\n13B1E;EGYPTIAN HIEROGLYPH-13B1E;Lo;0;L;;;;;N;;;;;\n13B1F;EGYPTIAN HIEROGLYPH-13B1F;Lo;0;L;;;;;N;;;;;\n13B20;EGYPTIAN HIEROGLYPH-13B20;Lo;0;L;;;;;N;;;;;\n13B21;EGYPTIAN HIEROGLYPH-13B21;Lo;0;L;;;;;N;;;;;\n13B22;EGYPTIAN HIEROGLYPH-13B22;Lo;0;L;;;;;N;;;;;\n13B23;EGYPTIAN HIEROGLYPH-13B23;Lo;0;L;;;;;N;;;;;\n13B24;EGYPTIAN HIEROGLYPH-13B24;Lo;0;L;;;;;N;;;;;\n13B25;EGYPTIAN HIEROGLYPH-13B25;Lo;0;L;;;;;N;;;;;\n13B26;EGYPTIAN HIEROGLYPH-13B26;Lo;0;L;;;;;N;;;;;\n13B27;EGYPTIAN HIEROGLYPH-13B27;Lo;0;L;;;;;N;;;;;\n13B28;EGYPTIAN HIEROGLYPH-13B28;Lo;0;L;;;;;N;;;;;\n13B29;EGYPTIAN HIEROGLYPH-13B29;Lo;0;L;;;;;N;;;;;\n13B2A;EGYPTIAN HIEROGLYPH-13B2A;Lo;0;L;;;;;N;;;;;\n13B2B;EGYPTIAN HIEROGLYPH-13B2B;Lo;0;L;;;;;N;;;;;\n13B2C;EGYPTIAN HIEROGLYPH-13B2C;Lo;0;L;;;;;N;;;;;\n13B2D;EGYPTIAN HIEROGLYPH-13B2D;Lo;0;L;;;;;N;;;;;\n13B2E;EGYPTIAN HIEROGLYPH-13B2E;Lo;0;L;;;;;N;;;;;\n13B2F;EGYPTIAN HIEROGLYPH-13B2F;Lo;0;L;;;;;N;;;;;\n13B30;EGYPTIAN HIEROGLYPH-13B30;Lo;0;L;;;;;N;;;;;\n13B31;EGYPTIAN HIEROGLYPH-13B31;Lo;0;L;;;;;N;;;;;\n13B32;EGYPTIAN HIEROGLYPH-13B32;Lo;0;L;;;;;N;;;;;\n13B33;EGYPTIAN HIEROGLYPH-13B33;Lo;0;L;;;;;N;;;;;\n13B34;EGYPTIAN HIEROGLYPH-13B34;Lo;0;L;;;;;N;;;;;\n13B35;EGYPTIAN HIEROGLYPH-13B35;Lo;0;L;;;;;N;;;;;\n13B36;EGYPTIAN HIEROGLYPH-13B36;Lo;0;L;;;;;N;;;;;\n13B37;EGYPTIAN HIEROGLYPH-13B37;Lo;0;L;;;;;N;;;;;\n13B38;EGYPTIAN HIEROGLYPH-13B38;Lo;0;L;;;;;N;;;;;\n13B39;EGYPTIAN HIEROGLYPH-13B39;Lo;0;L;;;;;N;;;;;\n13B3A;EGYPTIAN HIEROGLYPH-13B3A;Lo;0;L;;;;;N;;;;;\n13B3B;EGYPTIAN HIEROGLYPH-13B3B;Lo;0;L;;;;;N;;;;;\n13B3C;EGYPTIAN HIEROGLYPH-13B3C;Lo;0;L;;;;;N;;;;;\n13B3D;EGYPTIAN HIEROGLYPH-13B3D;Lo;0;L;;;;;N;;;;;\n13B3E;EGYPTIAN HIEROGLYPH-13B3E;Lo;0;L;;;;;N;;;;;\n13B3F;EGYPTIAN HIEROGLYPH-13B3F;Lo;0;L;;;;;N;;;;;\n13B40;EGYPTIAN HIEROGLYPH-13B40;Lo;0;L;;;;;N;;;;;\n13B41;EGYPTIAN HIEROGLYPH-13B41;Lo;0;L;;;;;N;;;;;\n13B42;EGYPTIAN HIEROGLYPH-13B42;Lo;0;L;;;;;N;;;;;\n13B43;EGYPTIAN HIEROGLYPH-13B43;Lo;0;L;;;;;N;;;;;\n13B44;EGYPTIAN HIEROGLYPH-13B44;Lo;0;L;;;;;N;;;;;\n13B45;EGYPTIAN HIEROGLYPH-13B45;Lo;0;L;;;;;N;;;;;\n13B46;EGYPTIAN HIEROGLYPH-13B46;Lo;0;L;;;;;N;;;;;\n13B47;EGYPTIAN HIEROGLYPH-13B47;Lo;0;L;;;;;N;;;;;\n13B48;EGYPTIAN HIEROGLYPH-13B48;Lo;0;L;;;;;N;;;;;\n13B49;EGYPTIAN HIEROGLYPH-13B49;Lo;0;L;;;;;N;;;;;\n13B4A;EGYPTIAN HIEROGLYPH-13B4A;Lo;0;L;;;;;N;;;;;\n13B4B;EGYPTIAN HIEROGLYPH-13B4B;Lo;0;L;;;;;N;;;;;\n13B4C;EGYPTIAN HIEROGLYPH-13B4C;Lo;0;L;;;;;N;;;;;\n13B4D;EGYPTIAN HIEROGLYPH-13B4D;Lo;0;L;;;;;N;;;;;\n13B4E;EGYPTIAN HIEROGLYPH-13B4E;Lo;0;L;;;;;N;;;;;\n13B4F;EGYPTIAN HIEROGLYPH-13B4F;Lo;0;L;;;;;N;;;;;\n13B50;EGYPTIAN HIEROGLYPH-13B50;Lo;0;L;;;;;N;;;;;\n13B51;EGYPTIAN HIEROGLYPH-13B51;Lo;0;L;;;;;N;;;;;\n13B52;EGYPTIAN HIEROGLYPH-13B52;Lo;0;L;;;;;N;;;;;\n13B53;EGYPTIAN HIEROGLYPH-13B53;Lo;0;L;;;;;N;;;;;\n13B54;EGYPTIAN HIEROGLYPH-13B54;Lo;0;L;;;;;N;;;;;\n13B55;EGYPTIAN HIEROGLYPH-13B55;Lo;0;L;;;;;N;;;;;\n13B56;EGYPTIAN HIEROGLYPH-13B56;Lo;0;L;;;;;N;;;;;\n13B57;EGYPTIAN HIEROGLYPH-13B57;Lo;0;L;;;;;N;;;;;\n13B58;EGYPTIAN HIEROGLYPH-13B58;Lo;0;L;;;;;N;;;;;\n13B59;EGYPTIAN HIEROGLYPH-13B59;Lo;0;L;;;;;N;;;;;\n13B5A;EGYPTIAN HIEROGLYPH-13B5A;Lo;0;L;;;;;N;;;;;\n13B5B;EGYPTIAN HIEROGLYPH-13B5B;Lo;0;L;;;;;N;;;;;\n13B5C;EGYPTIAN HIEROGLYPH-13B5C;Lo;0;L;;;;;N;;;;;\n13B5D;EGYPTIAN HIEROGLYPH-13B5D;Lo;0;L;;;;;N;;;;;\n13B5E;EGYPTIAN HIEROGLYPH-13B5E;Lo;0;L;;;;;N;;;;;\n13B5F;EGYPTIAN HIEROGLYPH-13B5F;Lo;0;L;;;;;N;;;;;\n13B60;EGYPTIAN HIEROGLYPH-13B60;Lo;0;L;;;;;N;;;;;\n13B61;EGYPTIAN HIEROGLYPH-13B61;Lo;0;L;;;;;N;;;;;\n13B62;EGYPTIAN HIEROGLYPH-13B62;Lo;0;L;;;;;N;;;;;\n13B63;EGYPTIAN HIEROGLYPH-13B63;Lo;0;L;;;;;N;;;;;\n13B64;EGYPTIAN HIEROGLYPH-13B64;Lo;0;L;;;;;N;;;;;\n13B65;EGYPTIAN HIEROGLYPH-13B65;Lo;0;L;;;;;N;;;;;\n13B66;EGYPTIAN HIEROGLYPH-13B66;Lo;0;L;;;;;N;;;;;\n13B67;EGYPTIAN HIEROGLYPH-13B67;Lo;0;L;;;;;N;;;;;\n13B68;EGYPTIAN HIEROGLYPH-13B68;Lo;0;L;;;;;N;;;;;\n13B69;EGYPTIAN HIEROGLYPH-13B69;Lo;0;L;;;;;N;;;;;\n13B6A;EGYPTIAN HIEROGLYPH-13B6A;Lo;0;L;;;;;N;;;;;\n13B6B;EGYPTIAN HIEROGLYPH-13B6B;Lo;0;L;;;;;N;;;;;\n13B6C;EGYPTIAN HIEROGLYPH-13B6C;Lo;0;L;;;;;N;;;;;\n13B6D;EGYPTIAN HIEROGLYPH-13B6D;Lo;0;L;;;;;N;;;;;\n13B6E;EGYPTIAN HIEROGLYPH-13B6E;Lo;0;L;;;;;N;;;;;\n13B6F;EGYPTIAN HIEROGLYPH-13B6F;Lo;0;L;;;;;N;;;;;\n13B70;EGYPTIAN HIEROGLYPH-13B70;Lo;0;L;;;;;N;;;;;\n13B71;EGYPTIAN HIEROGLYPH-13B71;Lo;0;L;;;;;N;;;;;\n13B72;EGYPTIAN HIEROGLYPH-13B72;Lo;0;L;;;;;N;;;;;\n13B73;EGYPTIAN HIEROGLYPH-13B73;Lo;0;L;;;;;N;;;;;\n13B74;EGYPTIAN HIEROGLYPH-13B74;Lo;0;L;;;;;N;;;;;\n13B75;EGYPTIAN HIEROGLYPH-13B75;Lo;0;L;;;;;N;;;;;\n13B76;EGYPTIAN HIEROGLYPH-13B76;Lo;0;L;;;;;N;;;;;\n13B77;EGYPTIAN HIEROGLYPH-13B77;Lo;0;L;;;;;N;;;;;\n13B78;EGYPTIAN HIEROGLYPH-13B78;Lo;0;L;;;;;N;;;;;\n13B79;EGYPTIAN HIEROGLYPH-13B79;Lo;0;L;;;;;N;;;;;\n13B7A;EGYPTIAN HIEROGLYPH-13B7A;Lo;0;L;;;;;N;;;;;\n13B7B;EGYPTIAN HIEROGLYPH-13B7B;Lo;0;L;;;;;N;;;;;\n13B7C;EGYPTIAN HIEROGLYPH-13B7C;Lo;0;L;;;;;N;;;;;\n13B7D;EGYPTIAN HIEROGLYPH-13B7D;Lo;0;L;;;;;N;;;;;\n13B7E;EGYPTIAN HIEROGLYPH-13B7E;Lo;0;L;;;;;N;;;;;\n13B7F;EGYPTIAN HIEROGLYPH-13B7F;Lo;0;L;;;;;N;;;;;\n13B80;EGYPTIAN HIEROGLYPH-13B80;Lo;0;L;;;;;N;;;;;\n13B81;EGYPTIAN HIEROGLYPH-13B81;Lo;0;L;;;;;N;;;;;\n13B82;EGYPTIAN HIEROGLYPH-13B82;Lo;0;L;;;;;N;;;;;\n13B83;EGYPTIAN HIEROGLYPH-13B83;Lo;0;L;;;;;N;;;;;\n13B84;EGYPTIAN HIEROGLYPH-13B84;Lo;0;L;;;;;N;;;;;\n13B85;EGYPTIAN HIEROGLYPH-13B85;Lo;0;L;;;;;N;;;;;\n13B86;EGYPTIAN HIEROGLYPH-13B86;Lo;0;L;;;;;N;;;;;\n13B87;EGYPTIAN HIEROGLYPH-13B87;Lo;0;L;;;;;N;;;;;\n13B88;EGYPTIAN HIEROGLYPH-13B88;Lo;0;L;;;;;N;;;;;\n13B89;EGYPTIAN HIEROGLYPH-13B89;Lo;0;L;;;;;N;;;;;\n13B8A;EGYPTIAN HIEROGLYPH-13B8A;Lo;0;L;;;;;N;;;;;\n13B8B;EGYPTIAN HIEROGLYPH-13B8B;Lo;0;L;;;;;N;;;;;\n13B8C;EGYPTIAN HIEROGLYPH-13B8C;Lo;0;L;;;;;N;;;;;\n13B8D;EGYPTIAN HIEROGLYPH-13B8D;Lo;0;L;;;;;N;;;;;\n13B8E;EGYPTIAN HIEROGLYPH-13B8E;Lo;0;L;;;;;N;;;;;\n13B8F;EGYPTIAN HIEROGLYPH-13B8F;Lo;0;L;;;;;N;;;;;\n13B90;EGYPTIAN HIEROGLYPH-13B90;Lo;0;L;;;;;N;;;;;\n13B91;EGYPTIAN HIEROGLYPH-13B91;Lo;0;L;;;;;N;;;;;\n13B92;EGYPTIAN HIEROGLYPH-13B92;Lo;0;L;;;;;N;;;;;\n13B93;EGYPTIAN HIEROGLYPH-13B93;Lo;0;L;;;;;N;;;;;\n13B94;EGYPTIAN HIEROGLYPH-13B94;Lo;0;L;;;;;N;;;;;\n13B95;EGYPTIAN HIEROGLYPH-13B95;Lo;0;L;;;;;N;;;;;\n13B96;EGYPTIAN HIEROGLYPH-13B96;Lo;0;L;;;;;N;;;;;\n13B97;EGYPTIAN HIEROGLYPH-13B97;Lo;0;L;;;;;N;;;;;\n13B98;EGYPTIAN HIEROGLYPH-13B98;Lo;0;L;;;;;N;;;;;\n13B99;EGYPTIAN HIEROGLYPH-13B99;Lo;0;L;;;;;N;;;;;\n13B9A;EGYPTIAN HIEROGLYPH-13B9A;Lo;0;L;;;;;N;;;;;\n13B9B;EGYPTIAN HIEROGLYPH-13B9B;Lo;0;L;;;;;N;;;;;\n13B9C;EGYPTIAN HIEROGLYPH-13B9C;Lo;0;L;;;;;N;;;;;\n13B9D;EGYPTIAN HIEROGLYPH-13B9D;Lo;0;L;;;;;N;;;;;\n13B9E;EGYPTIAN HIEROGLYPH-13B9E;Lo;0;L;;;;;N;;;;;\n13B9F;EGYPTIAN HIEROGLYPH-13B9F;Lo;0;L;;;;;N;;;;;\n13BA0;EGYPTIAN HIEROGLYPH-13BA0;Lo;0;L;;;;;N;;;;;\n13BA1;EGYPTIAN HIEROGLYPH-13BA1;Lo;0;L;;;;;N;;;;;\n13BA2;EGYPTIAN HIEROGLYPH-13BA2;Lo;0;L;;;;;N;;;;;\n13BA3;EGYPTIAN HIEROGLYPH-13BA3;Lo;0;L;;;;;N;;;;;\n13BA4;EGYPTIAN HIEROGLYPH-13BA4;Lo;0;L;;;;;N;;;;;\n13BA5;EGYPTIAN HIEROGLYPH-13BA5;Lo;0;L;;;;;N;;;;;\n13BA6;EGYPTIAN HIEROGLYPH-13BA6;Lo;0;L;;;;;N;;;;;\n13BA7;EGYPTIAN HIEROGLYPH-13BA7;Lo;0;L;;;;;N;;;;;\n13BA8;EGYPTIAN HIEROGLYPH-13BA8;Lo;0;L;;;;;N;;;;;\n13BA9;EGYPTIAN HIEROGLYPH-13BA9;Lo;0;L;;;;;N;;;;;\n13BAA;EGYPTIAN HIEROGLYPH-13BAA;Lo;0;L;;;;;N;;;;;\n13BAB;EGYPTIAN HIEROGLYPH-13BAB;Lo;0;L;;;;;N;;;;;\n13BAC;EGYPTIAN HIEROGLYPH-13BAC;Lo;0;L;;;;;N;;;;;\n13BAD;EGYPTIAN HIEROGLYPH-13BAD;Lo;0;L;;;;;N;;;;;\n13BAE;EGYPTIAN HIEROGLYPH-13BAE;Lo;0;L;;;;;N;;;;;\n13BAF;EGYPTIAN HIEROGLYPH-13BAF;Lo;0;L;;;;;N;;;;;\n13BB0;EGYPTIAN HIEROGLYPH-13BB0;Lo;0;L;;;;;N;;;;;\n13BB1;EGYPTIAN HIEROGLYPH-13BB1;Lo;0;L;;;;;N;;;;;\n13BB2;EGYPTIAN HIEROGLYPH-13BB2;Lo;0;L;;;;;N;;;;;\n13BB3;EGYPTIAN HIEROGLYPH-13BB3;Lo;0;L;;;;;N;;;;;\n13BB4;EGYPTIAN HIEROGLYPH-13BB4;Lo;0;L;;;;;N;;;;;\n13BB5;EGYPTIAN HIEROGLYPH-13BB5;Lo;0;L;;;;;N;;;;;\n13BB6;EGYPTIAN HIEROGLYPH-13BB6;Lo;0;L;;;;;N;;;;;\n13BB7;EGYPTIAN HIEROGLYPH-13BB7;Lo;0;L;;;;;N;;;;;\n13BB8;EGYPTIAN HIEROGLYPH-13BB8;Lo;0;L;;;;;N;;;;;\n13BB9;EGYPTIAN HIEROGLYPH-13BB9;Lo;0;L;;;;;N;;;;;\n13BBA;EGYPTIAN HIEROGLYPH-13BBA;Lo;0;L;;;;;N;;;;;\n13BBB;EGYPTIAN HIEROGLYPH-13BBB;Lo;0;L;;;;;N;;;;;\n13BBC;EGYPTIAN HIEROGLYPH-13BBC;Lo;0;L;;;;;N;;;;;\n13BBD;EGYPTIAN HIEROGLYPH-13BBD;Lo;0;L;;;;;N;;;;;\n13BBE;EGYPTIAN HIEROGLYPH-13BBE;Lo;0;L;;;;;N;;;;;\n13BBF;EGYPTIAN HIEROGLYPH-13BBF;Lo;0;L;;;;;N;;;;;\n13BC0;EGYPTIAN HIEROGLYPH-13BC0;Lo;0;L;;;;;N;;;;;\n13BC1;EGYPTIAN HIEROGLYPH-13BC1;Lo;0;L;;;;;N;;;;;\n13BC2;EGYPTIAN HIEROGLYPH-13BC2;Lo;0;L;;;;;N;;;;;\n13BC3;EGYPTIAN HIEROGLYPH-13BC3;Lo;0;L;;;;;N;;;;;\n13BC4;EGYPTIAN HIEROGLYPH-13BC4;Lo;0;L;;;;;N;;;;;\n13BC5;EGYPTIAN HIEROGLYPH-13BC5;Lo;0;L;;;;;N;;;;;\n13BC6;EGYPTIAN HIEROGLYPH-13BC6;Lo;0;L;;;;;N;;;;;\n13BC7;EGYPTIAN HIEROGLYPH-13BC7;Lo;0;L;;;;;N;;;;;\n13BC8;EGYPTIAN HIEROGLYPH-13BC8;Lo;0;L;;;;;N;;;;;\n13BC9;EGYPTIAN HIEROGLYPH-13BC9;Lo;0;L;;;;;N;;;;;\n13BCA;EGYPTIAN HIEROGLYPH-13BCA;Lo;0;L;;;;;N;;;;;\n13BCB;EGYPTIAN HIEROGLYPH-13BCB;Lo;0;L;;;;;N;;;;;\n13BCC;EGYPTIAN HIEROGLYPH-13BCC;Lo;0;L;;;;;N;;;;;\n13BCD;EGYPTIAN HIEROGLYPH-13BCD;Lo;0;L;;;;;N;;;;;\n13BCE;EGYPTIAN HIEROGLYPH-13BCE;Lo;0;L;;;;;N;;;;;\n13BCF;EGYPTIAN HIEROGLYPH-13BCF;Lo;0;L;;;;;N;;;;;\n13BD0;EGYPTIAN HIEROGLYPH-13BD0;Lo;0;L;;;;;N;;;;;\n13BD1;EGYPTIAN HIEROGLYPH-13BD1;Lo;0;L;;;;;N;;;;;\n13BD2;EGYPTIAN HIEROGLYPH-13BD2;Lo;0;L;;;;;N;;;;;\n13BD3;EGYPTIAN HIEROGLYPH-13BD3;Lo;0;L;;;;;N;;;;;\n13BD4;EGYPTIAN HIEROGLYPH-13BD4;Lo;0;L;;;;;N;;;;;\n13BD5;EGYPTIAN HIEROGLYPH-13BD5;Lo;0;L;;;;;N;;;;;\n13BD6;EGYPTIAN HIEROGLYPH-13BD6;Lo;0;L;;;;;N;;;;;\n13BD7;EGYPTIAN HIEROGLYPH-13BD7;Lo;0;L;;;;;N;;;;;\n13BD8;EGYPTIAN HIEROGLYPH-13BD8;Lo;0;L;;;;;N;;;;;\n13BD9;EGYPTIAN HIEROGLYPH-13BD9;Lo;0;L;;;;;N;;;;;\n13BDA;EGYPTIAN HIEROGLYPH-13BDA;Lo;0;L;;;;;N;;;;;\n13BDB;EGYPTIAN HIEROGLYPH-13BDB;Lo;0;L;;;;;N;;;;;\n13BDC;EGYPTIAN HIEROGLYPH-13BDC;Lo;0;L;;;;;N;;;;;\n13BDD;EGYPTIAN HIEROGLYPH-13BDD;Lo;0;L;;;;;N;;;;;\n13BDE;EGYPTIAN HIEROGLYPH-13BDE;Lo;0;L;;;;;N;;;;;\n13BDF;EGYPTIAN HIEROGLYPH-13BDF;Lo;0;L;;;;;N;;;;;\n13BE0;EGYPTIAN HIEROGLYPH-13BE0;Lo;0;L;;;;;N;;;;;\n13BE1;EGYPTIAN HIEROGLYPH-13BE1;Lo;0;L;;;;;N;;;;;\n13BE2;EGYPTIAN HIEROGLYPH-13BE2;Lo;0;L;;;;;N;;;;;\n13BE3;EGYPTIAN HIEROGLYPH-13BE3;Lo;0;L;;;;;N;;;;;\n13BE4;EGYPTIAN HIEROGLYPH-13BE4;Lo;0;L;;;;;N;;;;;\n13BE5;EGYPTIAN HIEROGLYPH-13BE5;Lo;0;L;;;;;N;;;;;\n13BE6;EGYPTIAN HIEROGLYPH-13BE6;Lo;0;L;;;;;N;;;;;\n13BE7;EGYPTIAN HIEROGLYPH-13BE7;Lo;0;L;;;;;N;;;;;\n13BE8;EGYPTIAN HIEROGLYPH-13BE8;Lo;0;L;;;;;N;;;;;\n13BE9;EGYPTIAN HIEROGLYPH-13BE9;Lo;0;L;;;;;N;;;;;\n13BEA;EGYPTIAN HIEROGLYPH-13BEA;Lo;0;L;;;;;N;;;;;\n13BEB;EGYPTIAN HIEROGLYPH-13BEB;Lo;0;L;;;;;N;;;;;\n13BEC;EGYPTIAN HIEROGLYPH-13BEC;Lo;0;L;;;;;N;;;;;\n13BED;EGYPTIAN HIEROGLYPH-13BED;Lo;0;L;;;;;N;;;;;\n13BEE;EGYPTIAN HIEROGLYPH-13BEE;Lo;0;L;;;;;N;;;;;\n13BEF;EGYPTIAN HIEROGLYPH-13BEF;Lo;0;L;;;;;N;;;;;\n13BF0;EGYPTIAN HIEROGLYPH-13BF0;Lo;0;L;;;;;N;;;;;\n13BF1;EGYPTIAN HIEROGLYPH-13BF1;Lo;0;L;;;;;N;;;;;\n13BF2;EGYPTIAN HIEROGLYPH-13BF2;Lo;0;L;;;;;N;;;;;\n13BF3;EGYPTIAN HIEROGLYPH-13BF3;Lo;0;L;;;;;N;;;;;\n13BF4;EGYPTIAN HIEROGLYPH-13BF4;Lo;0;L;;;;;N;;;;;\n13BF5;EGYPTIAN HIEROGLYPH-13BF5;Lo;0;L;;;;;N;;;;;\n13BF6;EGYPTIAN HIEROGLYPH-13BF6;Lo;0;L;;;;;N;;;;;\n13BF7;EGYPTIAN HIEROGLYPH-13BF7;Lo;0;L;;;;;N;;;;;\n13BF8;EGYPTIAN HIEROGLYPH-13BF8;Lo;0;L;;;;;N;;;;;\n13BF9;EGYPTIAN HIEROGLYPH-13BF9;Lo;0;L;;;;;N;;;;;\n13BFA;EGYPTIAN HIEROGLYPH-13BFA;Lo;0;L;;;;;N;;;;;\n13BFB;EGYPTIAN HIEROGLYPH-13BFB;Lo;0;L;;;;;N;;;;;\n13BFC;EGYPTIAN HIEROGLYPH-13BFC;Lo;0;L;;;;;N;;;;;\n13BFD;EGYPTIAN HIEROGLYPH-13BFD;Lo;0;L;;;;;N;;;;;\n13BFE;EGYPTIAN HIEROGLYPH-13BFE;Lo;0;L;;;;;N;;;;;\n13BFF;EGYPTIAN HIEROGLYPH-13BFF;Lo;0;L;;;;;N;;;;;\n13C00;EGYPTIAN HIEROGLYPH-13C00;Lo;0;L;;;;;N;;;;;\n13C01;EGYPTIAN HIEROGLYPH-13C01;Lo;0;L;;;;;N;;;;;\n13C02;EGYPTIAN HIEROGLYPH-13C02;Lo;0;L;;;;;N;;;;;\n13C03;EGYPTIAN HIEROGLYPH-13C03;Lo;0;L;;;;;N;;;;;\n13C04;EGYPTIAN HIEROGLYPH-13C04;Lo;0;L;;;;;N;;;;;\n13C05;EGYPTIAN HIEROGLYPH-13C05;Lo;0;L;;;;;N;;;;;\n13C06;EGYPTIAN HIEROGLYPH-13C06;Lo;0;L;;;;;N;;;;;\n13C07;EGYPTIAN HIEROGLYPH-13C07;Lo;0;L;;;;;N;;;;;\n13C08;EGYPTIAN HIEROGLYPH-13C08;Lo;0;L;;;;;N;;;;;\n13C09;EGYPTIAN HIEROGLYPH-13C09;Lo;0;L;;;;;N;;;;;\n13C0A;EGYPTIAN HIEROGLYPH-13C0A;Lo;0;L;;;;;N;;;;;\n13C0B;EGYPTIAN HIEROGLYPH-13C0B;Lo;0;L;;;;;N;;;;;\n13C0C;EGYPTIAN HIEROGLYPH-13C0C;Lo;0;L;;;;;N;;;;;\n13C0D;EGYPTIAN HIEROGLYPH-13C0D;Lo;0;L;;;;;N;;;;;\n13C0E;EGYPTIAN HIEROGLYPH-13C0E;Lo;0;L;;;;;N;;;;;\n13C0F;EGYPTIAN HIEROGLYPH-13C0F;Lo;0;L;;;;;N;;;;;\n13C10;EGYPTIAN HIEROGLYPH-13C10;Lo;0;L;;;;;N;;;;;\n13C11;EGYPTIAN HIEROGLYPH-13C11;Lo;0;L;;;;;N;;;;;\n13C12;EGYPTIAN HIEROGLYPH-13C12;Lo;0;L;;;;;N;;;;;\n13C13;EGYPTIAN HIEROGLYPH-13C13;Lo;0;L;;;;;N;;;;;\n13C14;EGYPTIAN HIEROGLYPH-13C14;Lo;0;L;;;;;N;;;;;\n13C15;EGYPTIAN HIEROGLYPH-13C15;Lo;0;L;;;;;N;;;;;\n13C16;EGYPTIAN HIEROGLYPH-13C16;Lo;0;L;;;;;N;;;;;\n13C17;EGYPTIAN HIEROGLYPH-13C17;Lo;0;L;;;;;N;;;;;\n13C18;EGYPTIAN HIEROGLYPH-13C18;Lo;0;L;;;;;N;;;;;\n13C19;EGYPTIAN HIEROGLYPH-13C19;Lo;0;L;;;;;N;;;;;\n13C1A;EGYPTIAN HIEROGLYPH-13C1A;Lo;0;L;;;;;N;;;;;\n13C1B;EGYPTIAN HIEROGLYPH-13C1B;Lo;0;L;;;;;N;;;;;\n13C1C;EGYPTIAN HIEROGLYPH-13C1C;Lo;0;L;;;;;N;;;;;\n13C1D;EGYPTIAN HIEROGLYPH-13C1D;Lo;0;L;;;;;N;;;;;\n13C1E;EGYPTIAN HIEROGLYPH-13C1E;Lo;0;L;;;;;N;;;;;\n13C1F;EGYPTIAN HIEROGLYPH-13C1F;Lo;0;L;;;;;N;;;;;\n13C20;EGYPTIAN HIEROGLYPH-13C20;Lo;0;L;;;;;N;;;;;\n13C21;EGYPTIAN HIEROGLYPH-13C21;Lo;0;L;;;;;N;;;;;\n13C22;EGYPTIAN HIEROGLYPH-13C22;Lo;0;L;;;;;N;;;;;\n13C23;EGYPTIAN HIEROGLYPH-13C23;Lo;0;L;;;;;N;;;;;\n13C24;EGYPTIAN HIEROGLYPH-13C24;Lo;0;L;;;;;N;;;;;\n13C25;EGYPTIAN HIEROGLYPH-13C25;Lo;0;L;;;;;N;;;;;\n13C26;EGYPTIAN HIEROGLYPH-13C26;Lo;0;L;;;;;N;;;;;\n13C27;EGYPTIAN HIEROGLYPH-13C27;Lo;0;L;;;;;N;;;;;\n13C28;EGYPTIAN HIEROGLYPH-13C28;Lo;0;L;;;;;N;;;;;\n13C29;EGYPTIAN HIEROGLYPH-13C29;Lo;0;L;;;;;N;;;;;\n13C2A;EGYPTIAN HIEROGLYPH-13C2A;Lo;0;L;;;;;N;;;;;\n13C2B;EGYPTIAN HIEROGLYPH-13C2B;Lo;0;L;;;;;N;;;;;\n13C2C;EGYPTIAN HIEROGLYPH-13C2C;Lo;0;L;;;;;N;;;;;\n13C2D;EGYPTIAN HIEROGLYPH-13C2D;Lo;0;L;;;;;N;;;;;\n13C2E;EGYPTIAN HIEROGLYPH-13C2E;Lo;0;L;;;;;N;;;;;\n13C2F;EGYPTIAN HIEROGLYPH-13C2F;Lo;0;L;;;;;N;;;;;\n13C30;EGYPTIAN HIEROGLYPH-13C30;Lo;0;L;;;;;N;;;;;\n13C31;EGYPTIAN HIEROGLYPH-13C31;Lo;0;L;;;;;N;;;;;\n13C32;EGYPTIAN HIEROGLYPH-13C32;Lo;0;L;;;;;N;;;;;\n13C33;EGYPTIAN HIEROGLYPH-13C33;Lo;0;L;;;;;N;;;;;\n13C34;EGYPTIAN HIEROGLYPH-13C34;Lo;0;L;;;;;N;;;;;\n13C35;EGYPTIAN HIEROGLYPH-13C35;Lo;0;L;;;;;N;;;;;\n13C36;EGYPTIAN HIEROGLYPH-13C36;Lo;0;L;;;;;N;;;;;\n13C37;EGYPTIAN HIEROGLYPH-13C37;Lo;0;L;;;;;N;;;;;\n13C38;EGYPTIAN HIEROGLYPH-13C38;Lo;0;L;;;;;N;;;;;\n13C39;EGYPTIAN HIEROGLYPH-13C39;Lo;0;L;;;;;N;;;;;\n13C3A;EGYPTIAN HIEROGLYPH-13C3A;Lo;0;L;;;;;N;;;;;\n13C3B;EGYPTIAN HIEROGLYPH-13C3B;Lo;0;L;;;;;N;;;;;\n13C3C;EGYPTIAN HIEROGLYPH-13C3C;Lo;0;L;;;;;N;;;;;\n13C3D;EGYPTIAN HIEROGLYPH-13C3D;Lo;0;L;;;;;N;;;;;\n13C3E;EGYPTIAN HIEROGLYPH-13C3E;Lo;0;L;;;;;N;;;;;\n13C3F;EGYPTIAN HIEROGLYPH-13C3F;Lo;0;L;;;;;N;;;;;\n13C40;EGYPTIAN HIEROGLYPH-13C40;Lo;0;L;;;;;N;;;;;\n13C41;EGYPTIAN HIEROGLYPH-13C41;Lo;0;L;;;;;N;;;;;\n13C42;EGYPTIAN HIEROGLYPH-13C42;Lo;0;L;;;;;N;;;;;\n13C43;EGYPTIAN HIEROGLYPH-13C43;Lo;0;L;;;;;N;;;;;\n13C44;EGYPTIAN HIEROGLYPH-13C44;Lo;0;L;;;;;N;;;;;\n13C45;EGYPTIAN HIEROGLYPH-13C45;Lo;0;L;;;;;N;;;;;\n13C46;EGYPTIAN HIEROGLYPH-13C46;Lo;0;L;;;;;N;;;;;\n13C47;EGYPTIAN HIEROGLYPH-13C47;Lo;0;L;;;;;N;;;;;\n13C48;EGYPTIAN HIEROGLYPH-13C48;Lo;0;L;;;;;N;;;;;\n13C49;EGYPTIAN HIEROGLYPH-13C49;Lo;0;L;;;;;N;;;;;\n13C4A;EGYPTIAN HIEROGLYPH-13C4A;Lo;0;L;;;;;N;;;;;\n13C4B;EGYPTIAN HIEROGLYPH-13C4B;Lo;0;L;;;;;N;;;;;\n13C4C;EGYPTIAN HIEROGLYPH-13C4C;Lo;0;L;;;;;N;;;;;\n13C4D;EGYPTIAN HIEROGLYPH-13C4D;Lo;0;L;;;;;N;;;;;\n13C4E;EGYPTIAN HIEROGLYPH-13C4E;Lo;0;L;;;;;N;;;;;\n13C4F;EGYPTIAN HIEROGLYPH-13C4F;Lo;0;L;;;;;N;;;;;\n13C50;EGYPTIAN HIEROGLYPH-13C50;Lo;0;L;;;;;N;;;;;\n13C51;EGYPTIAN HIEROGLYPH-13C51;Lo;0;L;;;;;N;;;;;\n13C52;EGYPTIAN HIEROGLYPH-13C52;Lo;0;L;;;;;N;;;;;\n13C53;EGYPTIAN HIEROGLYPH-13C53;Lo;0;L;;;;;N;;;;;\n13C54;EGYPTIAN HIEROGLYPH-13C54;Lo;0;L;;;;;N;;;;;\n13C55;EGYPTIAN HIEROGLYPH-13C55;Lo;0;L;;;;;N;;;;;\n13C56;EGYPTIAN HIEROGLYPH-13C56;Lo;0;L;;;;;N;;;;;\n13C57;EGYPTIAN HIEROGLYPH-13C57;Lo;0;L;;;;;N;;;;;\n13C58;EGYPTIAN HIEROGLYPH-13C58;Lo;0;L;;;;;N;;;;;\n13C59;EGYPTIAN HIEROGLYPH-13C59;Lo;0;L;;;;;N;;;;;\n13C5A;EGYPTIAN HIEROGLYPH-13C5A;Lo;0;L;;;;;N;;;;;\n13C5B;EGYPTIAN HIEROGLYPH-13C5B;Lo;0;L;;;;;N;;;;;\n13C5C;EGYPTIAN HIEROGLYPH-13C5C;Lo;0;L;;;;;N;;;;;\n13C5D;EGYPTIAN HIEROGLYPH-13C5D;Lo;0;L;;;;;N;;;;;\n13C5E;EGYPTIAN HIEROGLYPH-13C5E;Lo;0;L;;;;;N;;;;;\n13C5F;EGYPTIAN HIEROGLYPH-13C5F;Lo;0;L;;;;;N;;;;;\n13C60;EGYPTIAN HIEROGLYPH-13C60;Lo;0;L;;;;;N;;;;;\n13C61;EGYPTIAN HIEROGLYPH-13C61;Lo;0;L;;;;;N;;;;;\n13C62;EGYPTIAN HIEROGLYPH-13C62;Lo;0;L;;;;;N;;;;;\n13C63;EGYPTIAN HIEROGLYPH-13C63;Lo;0;L;;;;;N;;;;;\n13C64;EGYPTIAN HIEROGLYPH-13C64;Lo;0;L;;;;;N;;;;;\n13C65;EGYPTIAN HIEROGLYPH-13C65;Lo;0;L;;;;;N;;;;;\n13C66;EGYPTIAN HIEROGLYPH-13C66;Lo;0;L;;;;;N;;;;;\n13C67;EGYPTIAN HIEROGLYPH-13C67;Lo;0;L;;;;;N;;;;;\n13C68;EGYPTIAN HIEROGLYPH-13C68;Lo;0;L;;;;;N;;;;;\n13C69;EGYPTIAN HIEROGLYPH-13C69;Lo;0;L;;;;;N;;;;;\n13C6A;EGYPTIAN HIEROGLYPH-13C6A;Lo;0;L;;;;;N;;;;;\n13C6B;EGYPTIAN HIEROGLYPH-13C6B;Lo;0;L;;;;;N;;;;;\n13C6C;EGYPTIAN HIEROGLYPH-13C6C;Lo;0;L;;;;;N;;;;;\n13C6D;EGYPTIAN HIEROGLYPH-13C6D;Lo;0;L;;;;;N;;;;;\n13C6E;EGYPTIAN HIEROGLYPH-13C6E;Lo;0;L;;;;;N;;;;;\n13C6F;EGYPTIAN HIEROGLYPH-13C6F;Lo;0;L;;;;;N;;;;;\n13C70;EGYPTIAN HIEROGLYPH-13C70;Lo;0;L;;;;;N;;;;;\n13C71;EGYPTIAN HIEROGLYPH-13C71;Lo;0;L;;;;;N;;;;;\n13C72;EGYPTIAN HIEROGLYPH-13C72;Lo;0;L;;;;;N;;;;;\n13C73;EGYPTIAN HIEROGLYPH-13C73;Lo;0;L;;;;;N;;;;;\n13C74;EGYPTIAN HIEROGLYPH-13C74;Lo;0;L;;;;;N;;;;;\n13C75;EGYPTIAN HIEROGLYPH-13C75;Lo;0;L;;;;;N;;;;;\n13C76;EGYPTIAN HIEROGLYPH-13C76;Lo;0;L;;;;;N;;;;;\n13C77;EGYPTIAN HIEROGLYPH-13C77;Lo;0;L;;;;;N;;;;;\n13C78;EGYPTIAN HIEROGLYPH-13C78;Lo;0;L;;;;;N;;;;;\n13C79;EGYPTIAN HIEROGLYPH-13C79;Lo;0;L;;;;;N;;;;;\n13C7A;EGYPTIAN HIEROGLYPH-13C7A;Lo;0;L;;;;;N;;;;;\n13C7B;EGYPTIAN HIEROGLYPH-13C7B;Lo;0;L;;;;;N;;;;;\n13C7C;EGYPTIAN HIEROGLYPH-13C7C;Lo;0;L;;;;;N;;;;;\n13C7D;EGYPTIAN HIEROGLYPH-13C7D;Lo;0;L;;;;;N;;;;;\n13C7E;EGYPTIAN HIEROGLYPH-13C7E;Lo;0;L;;;;;N;;;;;\n13C7F;EGYPTIAN HIEROGLYPH-13C7F;Lo;0;L;;;;;N;;;;;\n13C80;EGYPTIAN HIEROGLYPH-13C80;Lo;0;L;;;;;N;;;;;\n13C81;EGYPTIAN HIEROGLYPH-13C81;Lo;0;L;;;;;N;;;;;\n13C82;EGYPTIAN HIEROGLYPH-13C82;Lo;0;L;;;;;N;;;;;\n13C83;EGYPTIAN HIEROGLYPH-13C83;Lo;0;L;;;;;N;;;;;\n13C84;EGYPTIAN HIEROGLYPH-13C84;Lo;0;L;;;;;N;;;;;\n13C85;EGYPTIAN HIEROGLYPH-13C85;Lo;0;L;;;;;N;;;;;\n13C86;EGYPTIAN HIEROGLYPH-13C86;Lo;0;L;;;;;N;;;;;\n13C87;EGYPTIAN HIEROGLYPH-13C87;Lo;0;L;;;;;N;;;;;\n13C88;EGYPTIAN HIEROGLYPH-13C88;Lo;0;L;;;;;N;;;;;\n13C89;EGYPTIAN HIEROGLYPH-13C89;Lo;0;L;;;;;N;;;;;\n13C8A;EGYPTIAN HIEROGLYPH-13C8A;Lo;0;L;;;;;N;;;;;\n13C8B;EGYPTIAN HIEROGLYPH-13C8B;Lo;0;L;;;;;N;;;;;\n13C8C;EGYPTIAN HIEROGLYPH-13C8C;Lo;0;L;;;;;N;;;;;\n13C8D;EGYPTIAN HIEROGLYPH-13C8D;Lo;0;L;;;;;N;;;;;\n13C8E;EGYPTIAN HIEROGLYPH-13C8E;Lo;0;L;;;;;N;;;;;\n13C8F;EGYPTIAN HIEROGLYPH-13C8F;Lo;0;L;;;;;N;;;;;\n13C90;EGYPTIAN HIEROGLYPH-13C90;Lo;0;L;;;;;N;;;;;\n13C91;EGYPTIAN HIEROGLYPH-13C91;Lo;0;L;;;;;N;;;;;\n13C92;EGYPTIAN HIEROGLYPH-13C92;Lo;0;L;;;;;N;;;;;\n13C93;EGYPTIAN HIEROGLYPH-13C93;Lo;0;L;;;;;N;;;;;\n13C94;EGYPTIAN HIEROGLYPH-13C94;Lo;0;L;;;;;N;;;;;\n13C95;EGYPTIAN HIEROGLYPH-13C95;Lo;0;L;;;;;N;;;;;\n13C96;EGYPTIAN HIEROGLYPH-13C96;Lo;0;L;;;;;N;;;;;\n13C97;EGYPTIAN HIEROGLYPH-13C97;Lo;0;L;;;;;N;;;;;\n13C98;EGYPTIAN HIEROGLYPH-13C98;Lo;0;L;;;;;N;;;;;\n13C99;EGYPTIAN HIEROGLYPH-13C99;Lo;0;L;;;;;N;;;;;\n13C9A;EGYPTIAN HIEROGLYPH-13C9A;Lo;0;L;;;;;N;;;;;\n13C9B;EGYPTIAN HIEROGLYPH-13C9B;Lo;0;L;;;;;N;;;;;\n13C9C;EGYPTIAN HIEROGLYPH-13C9C;Lo;0;L;;;;;N;;;;;\n13C9D;EGYPTIAN HIEROGLYPH-13C9D;Lo;0;L;;;;;N;;;;;\n13C9E;EGYPTIAN HIEROGLYPH-13C9E;Lo;0;L;;;;;N;;;;;\n13C9F;EGYPTIAN HIEROGLYPH-13C9F;Lo;0;L;;;;;N;;;;;\n13CA0;EGYPTIAN HIEROGLYPH-13CA0;Lo;0;L;;;;;N;;;;;\n13CA1;EGYPTIAN HIEROGLYPH-13CA1;Lo;0;L;;;;;N;;;;;\n13CA2;EGYPTIAN HIEROGLYPH-13CA2;Lo;0;L;;;;;N;;;;;\n13CA3;EGYPTIAN HIEROGLYPH-13CA3;Lo;0;L;;;;;N;;;;;\n13CA4;EGYPTIAN HIEROGLYPH-13CA4;Lo;0;L;;;;;N;;;;;\n13CA5;EGYPTIAN HIEROGLYPH-13CA5;Lo;0;L;;;;;N;;;;;\n13CA6;EGYPTIAN HIEROGLYPH-13CA6;Lo;0;L;;;;;N;;;;;\n13CA7;EGYPTIAN HIEROGLYPH-13CA7;Lo;0;L;;;;;N;;;;;\n13CA8;EGYPTIAN HIEROGLYPH-13CA8;Lo;0;L;;;;;N;;;;;\n13CA9;EGYPTIAN HIEROGLYPH-13CA9;Lo;0;L;;;;;N;;;;;\n13CAA;EGYPTIAN HIEROGLYPH-13CAA;Lo;0;L;;;;;N;;;;;\n13CAB;EGYPTIAN HIEROGLYPH-13CAB;Lo;0;L;;;;;N;;;;;\n13CAC;EGYPTIAN HIEROGLYPH-13CAC;Lo;0;L;;;;;N;;;;;\n13CAD;EGYPTIAN HIEROGLYPH-13CAD;Lo;0;L;;;;;N;;;;;\n13CAE;EGYPTIAN HIEROGLYPH-13CAE;Lo;0;L;;;;;N;;;;;\n13CAF;EGYPTIAN HIEROGLYPH-13CAF;Lo;0;L;;;;;N;;;;;\n13CB0;EGYPTIAN HIEROGLYPH-13CB0;Lo;0;L;;;;;N;;;;;\n13CB1;EGYPTIAN HIEROGLYPH-13CB1;Lo;0;L;;;;;N;;;;;\n13CB2;EGYPTIAN HIEROGLYPH-13CB2;Lo;0;L;;;;;N;;;;;\n13CB3;EGYPTIAN HIEROGLYPH-13CB3;Lo;0;L;;;;;N;;;;;\n13CB4;EGYPTIAN HIEROGLYPH-13CB4;Lo;0;L;;;;;N;;;;;\n13CB5;EGYPTIAN HIEROGLYPH-13CB5;Lo;0;L;;;;;N;;;;;\n13CB6;EGYPTIAN HIEROGLYPH-13CB6;Lo;0;L;;;;;N;;;;;\n13CB7;EGYPTIAN HIEROGLYPH-13CB7;Lo;0;L;;;;;N;;;;;\n13CB8;EGYPTIAN HIEROGLYPH-13CB8;Lo;0;L;;;;;N;;;;;\n13CB9;EGYPTIAN HIEROGLYPH-13CB9;Lo;0;L;;;;;N;;;;;\n13CBA;EGYPTIAN HIEROGLYPH-13CBA;Lo;0;L;;;;;N;;;;;\n13CBB;EGYPTIAN HIEROGLYPH-13CBB;Lo;0;L;;;;;N;;;;;\n13CBC;EGYPTIAN HIEROGLYPH-13CBC;Lo;0;L;;;;;N;;;;;\n13CBD;EGYPTIAN HIEROGLYPH-13CBD;Lo;0;L;;;;;N;;;;;\n13CBE;EGYPTIAN HIEROGLYPH-13CBE;Lo;0;L;;;;;N;;;;;\n13CBF;EGYPTIAN HIEROGLYPH-13CBF;Lo;0;L;;;;;N;;;;;\n13CC0;EGYPTIAN HIEROGLYPH-13CC0;Lo;0;L;;;;;N;;;;;\n13CC1;EGYPTIAN HIEROGLYPH-13CC1;Lo;0;L;;;;;N;;;;;\n13CC2;EGYPTIAN HIEROGLYPH-13CC2;Lo;0;L;;;;;N;;;;;\n13CC3;EGYPTIAN HIEROGLYPH-13CC3;Lo;0;L;;;;;N;;;;;\n13CC4;EGYPTIAN HIEROGLYPH-13CC4;Lo;0;L;;;;;N;;;;;\n13CC5;EGYPTIAN HIEROGLYPH-13CC5;Lo;0;L;;;;;N;;;;;\n13CC6;EGYPTIAN HIEROGLYPH-13CC6;Lo;0;L;;;;;N;;;;;\n13CC7;EGYPTIAN HIEROGLYPH-13CC7;Lo;0;L;;;;;N;;;;;\n13CC8;EGYPTIAN HIEROGLYPH-13CC8;Lo;0;L;;;;;N;;;;;\n13CC9;EGYPTIAN HIEROGLYPH-13CC9;Lo;0;L;;;;;N;;;;;\n13CCA;EGYPTIAN HIEROGLYPH-13CCA;Lo;0;L;;;;;N;;;;;\n13CCB;EGYPTIAN HIEROGLYPH-13CCB;Lo;0;L;;;;;N;;;;;\n13CCC;EGYPTIAN HIEROGLYPH-13CCC;Lo;0;L;;;;;N;;;;;\n13CCD;EGYPTIAN HIEROGLYPH-13CCD;Lo;0;L;;;;;N;;;;;\n13CCE;EGYPTIAN HIEROGLYPH-13CCE;Lo;0;L;;;;;N;;;;;\n13CCF;EGYPTIAN HIEROGLYPH-13CCF;Lo;0;L;;;;;N;;;;;\n13CD0;EGYPTIAN HIEROGLYPH-13CD0;Lo;0;L;;;;;N;;;;;\n13CD1;EGYPTIAN HIEROGLYPH-13CD1;Lo;0;L;;;;;N;;;;;\n13CD2;EGYPTIAN HIEROGLYPH-13CD2;Lo;0;L;;;;;N;;;;;\n13CD3;EGYPTIAN HIEROGLYPH-13CD3;Lo;0;L;;;;;N;;;;;\n13CD4;EGYPTIAN HIEROGLYPH-13CD4;Lo;0;L;;;;;N;;;;;\n13CD5;EGYPTIAN HIEROGLYPH-13CD5;Lo;0;L;;;;;N;;;;;\n13CD6;EGYPTIAN HIEROGLYPH-13CD6;Lo;0;L;;;;;N;;;;;\n13CD7;EGYPTIAN HIEROGLYPH-13CD7;Lo;0;L;;;;;N;;;;;\n13CD8;EGYPTIAN HIEROGLYPH-13CD8;Lo;0;L;;;;;N;;;;;\n13CD9;EGYPTIAN HIEROGLYPH-13CD9;Lo;0;L;;;;;N;;;;;\n13CDA;EGYPTIAN HIEROGLYPH-13CDA;Lo;0;L;;;;;N;;;;;\n13CDB;EGYPTIAN HIEROGLYPH-13CDB;Lo;0;L;;;;;N;;;;;\n13CDC;EGYPTIAN HIEROGLYPH-13CDC;Lo;0;L;;;;;N;;;;;\n13CDD;EGYPTIAN HIEROGLYPH-13CDD;Lo;0;L;;;;;N;;;;;\n13CDE;EGYPTIAN HIEROGLYPH-13CDE;Lo;0;L;;;;;N;;;;;\n13CDF;EGYPTIAN HIEROGLYPH-13CDF;Lo;0;L;;;;;N;;;;;\n13CE0;EGYPTIAN HIEROGLYPH-13CE0;Lo;0;L;;;;;N;;;;;\n13CE1;EGYPTIAN HIEROGLYPH-13CE1;Lo;0;L;;;;;N;;;;;\n13CE2;EGYPTIAN HIEROGLYPH-13CE2;Lo;0;L;;;;;N;;;;;\n13CE3;EGYPTIAN HIEROGLYPH-13CE3;Lo;0;L;;;;;N;;;;;\n13CE4;EGYPTIAN HIEROGLYPH-13CE4;Lo;0;L;;;;;N;;;;;\n13CE5;EGYPTIAN HIEROGLYPH-13CE5;Lo;0;L;;;;;N;;;;;\n13CE6;EGYPTIAN HIEROGLYPH-13CE6;Lo;0;L;;;;;N;;;;;\n13CE7;EGYPTIAN HIEROGLYPH-13CE7;Lo;0;L;;;;;N;;;;;\n13CE8;EGYPTIAN HIEROGLYPH-13CE8;Lo;0;L;;;;;N;;;;;\n13CE9;EGYPTIAN HIEROGLYPH-13CE9;Lo;0;L;;;;;N;;;;;\n13CEA;EGYPTIAN HIEROGLYPH-13CEA;Lo;0;L;;;;;N;;;;;\n13CEB;EGYPTIAN HIEROGLYPH-13CEB;Lo;0;L;;;;;N;;;;;\n13CEC;EGYPTIAN HIEROGLYPH-13CEC;Lo;0;L;;;;;N;;;;;\n13CED;EGYPTIAN HIEROGLYPH-13CED;Lo;0;L;;;;;N;;;;;\n13CEE;EGYPTIAN HIEROGLYPH-13CEE;Lo;0;L;;;;;N;;;;;\n13CEF;EGYPTIAN HIEROGLYPH-13CEF;Lo;0;L;;;;;N;;;;;\n13CF0;EGYPTIAN HIEROGLYPH-13CF0;Lo;0;L;;;;;N;;;;;\n13CF1;EGYPTIAN HIEROGLYPH-13CF1;Lo;0;L;;;;;N;;;;;\n13CF2;EGYPTIAN HIEROGLYPH-13CF2;Lo;0;L;;;;;N;;;;;\n13CF3;EGYPTIAN HIEROGLYPH-13CF3;Lo;0;L;;;;;N;;;;;\n13CF4;EGYPTIAN HIEROGLYPH-13CF4;Lo;0;L;;;;;N;;;;;\n13CF5;EGYPTIAN HIEROGLYPH-13CF5;Lo;0;L;;;;;N;;;;;\n13CF6;EGYPTIAN HIEROGLYPH-13CF6;Lo;0;L;;;;;N;;;;;\n13CF7;EGYPTIAN HIEROGLYPH-13CF7;Lo;0;L;;;;;N;;;;;\n13CF8;EGYPTIAN HIEROGLYPH-13CF8;Lo;0;L;;;;;N;;;;;\n13CF9;EGYPTIAN HIEROGLYPH-13CF9;Lo;0;L;;;;;N;;;;;\n13CFA;EGYPTIAN HIEROGLYPH-13CFA;Lo;0;L;;;;;N;;;;;\n13CFB;EGYPTIAN HIEROGLYPH-13CFB;Lo;0;L;;;;;N;;;;;\n13CFC;EGYPTIAN HIEROGLYPH-13CFC;Lo;0;L;;;;;N;;;;;\n13CFD;EGYPTIAN HIEROGLYPH-13CFD;Lo;0;L;;;;;N;;;;;\n13CFE;EGYPTIAN HIEROGLYPH-13CFE;Lo;0;L;;;;;N;;;;;\n13CFF;EGYPTIAN HIEROGLYPH-13CFF;Lo;0;L;;;;;N;;;;;\n13D00;EGYPTIAN HIEROGLYPH-13D00;Lo;0;L;;;;;N;;;;;\n13D01;EGYPTIAN HIEROGLYPH-13D01;Lo;0;L;;;;;N;;;;;\n13D02;EGYPTIAN HIEROGLYPH-13D02;Lo;0;L;;;;;N;;;;;\n13D03;EGYPTIAN HIEROGLYPH-13D03;Lo;0;L;;;;;N;;;;;\n13D04;EGYPTIAN HIEROGLYPH-13D04;Lo;0;L;;;;;N;;;;;\n13D05;EGYPTIAN HIEROGLYPH-13D05;Lo;0;L;;;;;N;;;;;\n13D06;EGYPTIAN HIEROGLYPH-13D06;Lo;0;L;;;;;N;;;;;\n13D07;EGYPTIAN HIEROGLYPH-13D07;Lo;0;L;;;;;N;;;;;\n13D08;EGYPTIAN HIEROGLYPH-13D08;Lo;0;L;;;;;N;;;;;\n13D09;EGYPTIAN HIEROGLYPH-13D09;Lo;0;L;;;;;N;;;;;\n13D0A;EGYPTIAN HIEROGLYPH-13D0A;Lo;0;L;;;;;N;;;;;\n13D0B;EGYPTIAN HIEROGLYPH-13D0B;Lo;0;L;;;;;N;;;;;\n13D0C;EGYPTIAN HIEROGLYPH-13D0C;Lo;0;L;;;;;N;;;;;\n13D0D;EGYPTIAN HIEROGLYPH-13D0D;Lo;0;L;;;;;N;;;;;\n13D0E;EGYPTIAN HIEROGLYPH-13D0E;Lo;0;L;;;;;N;;;;;\n13D0F;EGYPTIAN HIEROGLYPH-13D0F;Lo;0;L;;;;;N;;;;;\n13D10;EGYPTIAN HIEROGLYPH-13D10;Lo;0;L;;;;;N;;;;;\n13D11;EGYPTIAN HIEROGLYPH-13D11;Lo;0;L;;;;;N;;;;;\n13D12;EGYPTIAN HIEROGLYPH-13D12;Lo;0;L;;;;;N;;;;;\n13D13;EGYPTIAN HIEROGLYPH-13D13;Lo;0;L;;;;;N;;;;;\n13D14;EGYPTIAN HIEROGLYPH-13D14;Lo;0;L;;;;;N;;;;;\n13D15;EGYPTIAN HIEROGLYPH-13D15;Lo;0;L;;;;;N;;;;;\n13D16;EGYPTIAN HIEROGLYPH-13D16;Lo;0;L;;;;;N;;;;;\n13D17;EGYPTIAN HIEROGLYPH-13D17;Lo;0;L;;;;;N;;;;;\n13D18;EGYPTIAN HIEROGLYPH-13D18;Lo;0;L;;;;;N;;;;;\n13D19;EGYPTIAN HIEROGLYPH-13D19;Lo;0;L;;;;;N;;;;;\n13D1A;EGYPTIAN HIEROGLYPH-13D1A;Lo;0;L;;;;;N;;;;;\n13D1B;EGYPTIAN HIEROGLYPH-13D1B;Lo;0;L;;;;;N;;;;;\n13D1C;EGYPTIAN HIEROGLYPH-13D1C;Lo;0;L;;;;;N;;;;;\n13D1D;EGYPTIAN HIEROGLYPH-13D1D;Lo;0;L;;;;;N;;;;;\n13D1E;EGYPTIAN HIEROGLYPH-13D1E;Lo;0;L;;;;;N;;;;;\n13D1F;EGYPTIAN HIEROGLYPH-13D1F;Lo;0;L;;;;;N;;;;;\n13D20;EGYPTIAN HIEROGLYPH-13D20;Lo;0;L;;;;;N;;;;;\n13D21;EGYPTIAN HIEROGLYPH-13D21;Lo;0;L;;;;;N;;;;;\n13D22;EGYPTIAN HIEROGLYPH-13D22;Lo;0;L;;;;;N;;;;;\n13D23;EGYPTIAN HIEROGLYPH-13D23;Lo;0;L;;;;;N;;;;;\n13D24;EGYPTIAN HIEROGLYPH-13D24;Lo;0;L;;;;;N;;;;;\n13D25;EGYPTIAN HIEROGLYPH-13D25;Lo;0;L;;;;;N;;;;;\n13D26;EGYPTIAN HIEROGLYPH-13D26;Lo;0;L;;;;;N;;;;;\n13D27;EGYPTIAN HIEROGLYPH-13D27;Lo;0;L;;;;;N;;;;;\n13D28;EGYPTIAN HIEROGLYPH-13D28;Lo;0;L;;;;;N;;;;;\n13D29;EGYPTIAN HIEROGLYPH-13D29;Lo;0;L;;;;;N;;;;;\n13D2A;EGYPTIAN HIEROGLYPH-13D2A;Lo;0;L;;;;;N;;;;;\n13D2B;EGYPTIAN HIEROGLYPH-13D2B;Lo;0;L;;;;;N;;;;;\n13D2C;EGYPTIAN HIEROGLYPH-13D2C;Lo;0;L;;;;;N;;;;;\n13D2D;EGYPTIAN HIEROGLYPH-13D2D;Lo;0;L;;;;;N;;;;;\n13D2E;EGYPTIAN HIEROGLYPH-13D2E;Lo;0;L;;;;;N;;;;;\n13D2F;EGYPTIAN HIEROGLYPH-13D2F;Lo;0;L;;;;;N;;;;;\n13D30;EGYPTIAN HIEROGLYPH-13D30;Lo;0;L;;;;;N;;;;;\n13D31;EGYPTIAN HIEROGLYPH-13D31;Lo;0;L;;;;;N;;;;;\n13D32;EGYPTIAN HIEROGLYPH-13D32;Lo;0;L;;;;;N;;;;;\n13D33;EGYPTIAN HIEROGLYPH-13D33;Lo;0;L;;;;;N;;;;;\n13D34;EGYPTIAN HIEROGLYPH-13D34;Lo;0;L;;;;;N;;;;;\n13D35;EGYPTIAN HIEROGLYPH-13D35;Lo;0;L;;;;;N;;;;;\n13D36;EGYPTIAN HIEROGLYPH-13D36;Lo;0;L;;;;;N;;;;;\n13D37;EGYPTIAN HIEROGLYPH-13D37;Lo;0;L;;;;;N;;;;;\n13D38;EGYPTIAN HIEROGLYPH-13D38;Lo;0;L;;;;;N;;;;;\n13D39;EGYPTIAN HIEROGLYPH-13D39;Lo;0;L;;;;;N;;;;;\n13D3A;EGYPTIAN HIEROGLYPH-13D3A;Lo;0;L;;;;;N;;;;;\n13D3B;EGYPTIAN HIEROGLYPH-13D3B;Lo;0;L;;;;;N;;;;;\n13D3C;EGYPTIAN HIEROGLYPH-13D3C;Lo;0;L;;;;;N;;;;;\n13D3D;EGYPTIAN HIEROGLYPH-13D3D;Lo;0;L;;;;;N;;;;;\n13D3E;EGYPTIAN HIEROGLYPH-13D3E;Lo;0;L;;;;;N;;;;;\n13D3F;EGYPTIAN HIEROGLYPH-13D3F;Lo;0;L;;;;;N;;;;;\n13D40;EGYPTIAN HIEROGLYPH-13D40;Lo;0;L;;;;;N;;;;;\n13D41;EGYPTIAN HIEROGLYPH-13D41;Lo;0;L;;;;;N;;;;;\n13D42;EGYPTIAN HIEROGLYPH-13D42;Lo;0;L;;;;;N;;;;;\n13D43;EGYPTIAN HIEROGLYPH-13D43;Lo;0;L;;;;;N;;;;;\n13D44;EGYPTIAN HIEROGLYPH-13D44;Lo;0;L;;;;;N;;;;;\n13D45;EGYPTIAN HIEROGLYPH-13D45;Lo;0;L;;;;;N;;;;;\n13D46;EGYPTIAN HIEROGLYPH-13D46;Lo;0;L;;;;;N;;;;;\n13D47;EGYPTIAN HIEROGLYPH-13D47;Lo;0;L;;;;;N;;;;;\n13D48;EGYPTIAN HIEROGLYPH-13D48;Lo;0;L;;;;;N;;;;;\n13D49;EGYPTIAN HIEROGLYPH-13D49;Lo;0;L;;;;;N;;;;;\n13D4A;EGYPTIAN HIEROGLYPH-13D4A;Lo;0;L;;;;;N;;;;;\n13D4B;EGYPTIAN HIEROGLYPH-13D4B;Lo;0;L;;;;;N;;;;;\n13D4C;EGYPTIAN HIEROGLYPH-13D4C;Lo;0;L;;;;;N;;;;;\n13D4D;EGYPTIAN HIEROGLYPH-13D4D;Lo;0;L;;;;;N;;;;;\n13D4E;EGYPTIAN HIEROGLYPH-13D4E;Lo;0;L;;;;;N;;;;;\n13D4F;EGYPTIAN HIEROGLYPH-13D4F;Lo;0;L;;;;;N;;;;;\n13D50;EGYPTIAN HIEROGLYPH-13D50;Lo;0;L;;;;;N;;;;;\n13D51;EGYPTIAN HIEROGLYPH-13D51;Lo;0;L;;;;;N;;;;;\n13D52;EGYPTIAN HIEROGLYPH-13D52;Lo;0;L;;;;;N;;;;;\n13D53;EGYPTIAN HIEROGLYPH-13D53;Lo;0;L;;;;;N;;;;;\n13D54;EGYPTIAN HIEROGLYPH-13D54;Lo;0;L;;;;;N;;;;;\n13D55;EGYPTIAN HIEROGLYPH-13D55;Lo;0;L;;;;;N;;;;;\n13D56;EGYPTIAN HIEROGLYPH-13D56;Lo;0;L;;;;;N;;;;;\n13D57;EGYPTIAN HIEROGLYPH-13D57;Lo;0;L;;;;;N;;;;;\n13D58;EGYPTIAN HIEROGLYPH-13D58;Lo;0;L;;;;;N;;;;;\n13D59;EGYPTIAN HIEROGLYPH-13D59;Lo;0;L;;;;;N;;;;;\n13D5A;EGYPTIAN HIEROGLYPH-13D5A;Lo;0;L;;;;;N;;;;;\n13D5B;EGYPTIAN HIEROGLYPH-13D5B;Lo;0;L;;;;;N;;;;;\n13D5C;EGYPTIAN HIEROGLYPH-13D5C;Lo;0;L;;;;;N;;;;;\n13D5D;EGYPTIAN HIEROGLYPH-13D5D;Lo;0;L;;;;;N;;;;;\n13D5E;EGYPTIAN HIEROGLYPH-13D5E;Lo;0;L;;;;;N;;;;;\n13D5F;EGYPTIAN HIEROGLYPH-13D5F;Lo;0;L;;;;;N;;;;;\n13D60;EGYPTIAN HIEROGLYPH-13D60;Lo;0;L;;;;;N;;;;;\n13D61;EGYPTIAN HIEROGLYPH-13D61;Lo;0;L;;;;;N;;;;;\n13D62;EGYPTIAN HIEROGLYPH-13D62;Lo;0;L;;;;;N;;;;;\n13D63;EGYPTIAN HIEROGLYPH-13D63;Lo;0;L;;;;;N;;;;;\n13D64;EGYPTIAN HIEROGLYPH-13D64;Lo;0;L;;;;;N;;;;;\n13D65;EGYPTIAN HIEROGLYPH-13D65;Lo;0;L;;;;;N;;;;;\n13D66;EGYPTIAN HIEROGLYPH-13D66;Lo;0;L;;;;;N;;;;;\n13D67;EGYPTIAN HIEROGLYPH-13D67;Lo;0;L;;;;;N;;;;;\n13D68;EGYPTIAN HIEROGLYPH-13D68;Lo;0;L;;;;;N;;;;;\n13D69;EGYPTIAN HIEROGLYPH-13D69;Lo;0;L;;;;;N;;;;;\n13D6A;EGYPTIAN HIEROGLYPH-13D6A;Lo;0;L;;;;;N;;;;;\n13D6B;EGYPTIAN HIEROGLYPH-13D6B;Lo;0;L;;;;;N;;;;;\n13D6C;EGYPTIAN HIEROGLYPH-13D6C;Lo;0;L;;;;;N;;;;;\n13D6D;EGYPTIAN HIEROGLYPH-13D6D;Lo;0;L;;;;;N;;;;;\n13D6E;EGYPTIAN HIEROGLYPH-13D6E;Lo;0;L;;;;;N;;;;;\n13D6F;EGYPTIAN HIEROGLYPH-13D6F;Lo;0;L;;;;;N;;;;;\n13D70;EGYPTIAN HIEROGLYPH-13D70;Lo;0;L;;;;;N;;;;;\n13D71;EGYPTIAN HIEROGLYPH-13D71;Lo;0;L;;;;;N;;;;;\n13D72;EGYPTIAN HIEROGLYPH-13D72;Lo;0;L;;;;;N;;;;;\n13D73;EGYPTIAN HIEROGLYPH-13D73;Lo;0;L;;;;;N;;;;;\n13D74;EGYPTIAN HIEROGLYPH-13D74;Lo;0;L;;;;;N;;;;;\n13D75;EGYPTIAN HIEROGLYPH-13D75;Lo;0;L;;;;;N;;;;;\n13D76;EGYPTIAN HIEROGLYPH-13D76;Lo;0;L;;;;;N;;;;;\n13D77;EGYPTIAN HIEROGLYPH-13D77;Lo;0;L;;;;;N;;;;;\n13D78;EGYPTIAN HIEROGLYPH-13D78;Lo;0;L;;;;;N;;;;;\n13D79;EGYPTIAN HIEROGLYPH-13D79;Lo;0;L;;;;;N;;;;;\n13D7A;EGYPTIAN HIEROGLYPH-13D7A;Lo;0;L;;;;;N;;;;;\n13D7B;EGYPTIAN HIEROGLYPH-13D7B;Lo;0;L;;;;;N;;;;;\n13D7C;EGYPTIAN HIEROGLYPH-13D7C;Lo;0;L;;;;;N;;;;;\n13D7D;EGYPTIAN HIEROGLYPH-13D7D;Lo;0;L;;;;;N;;;;;\n13D7E;EGYPTIAN HIEROGLYPH-13D7E;Lo;0;L;;;;;N;;;;;\n13D7F;EGYPTIAN HIEROGLYPH-13D7F;Lo;0;L;;;;;N;;;;;\n13D80;EGYPTIAN HIEROGLYPH-13D80;Lo;0;L;;;;;N;;;;;\n13D81;EGYPTIAN HIEROGLYPH-13D81;Lo;0;L;;;;;N;;;;;\n13D82;EGYPTIAN HIEROGLYPH-13D82;Lo;0;L;;;;;N;;;;;\n13D83;EGYPTIAN HIEROGLYPH-13D83;Lo;0;L;;;;;N;;;;;\n13D84;EGYPTIAN HIEROGLYPH-13D84;Lo;0;L;;;;;N;;;;;\n13D85;EGYPTIAN HIEROGLYPH-13D85;Lo;0;L;;;;;N;;;;;\n13D86;EGYPTIAN HIEROGLYPH-13D86;Lo;0;L;;;;;N;;;;;\n13D87;EGYPTIAN HIEROGLYPH-13D87;Lo;0;L;;;;;N;;;;;\n13D88;EGYPTIAN HIEROGLYPH-13D88;Lo;0;L;;;;;N;;;;;\n13D89;EGYPTIAN HIEROGLYPH-13D89;Lo;0;L;;;;;N;;;;;\n13D8A;EGYPTIAN HIEROGLYPH-13D8A;Lo;0;L;;;;;N;;;;;\n13D8B;EGYPTIAN HIEROGLYPH-13D8B;Lo;0;L;;;;;N;;;;;\n13D8C;EGYPTIAN HIEROGLYPH-13D8C;Lo;0;L;;;;;N;;;;;\n13D8D;EGYPTIAN HIEROGLYPH-13D8D;Lo;0;L;;;;;N;;;;;\n13D8E;EGYPTIAN HIEROGLYPH-13D8E;Lo;0;L;;;;;N;;;;;\n13D8F;EGYPTIAN HIEROGLYPH-13D8F;Lo;0;L;;;;;N;;;;;\n13D90;EGYPTIAN HIEROGLYPH-13D90;Lo;0;L;;;;;N;;;;;\n13D91;EGYPTIAN HIEROGLYPH-13D91;Lo;0;L;;;;;N;;;;;\n13D92;EGYPTIAN HIEROGLYPH-13D92;Lo;0;L;;;;;N;;;;;\n13D93;EGYPTIAN HIEROGLYPH-13D93;Lo;0;L;;;;;N;;;;;\n13D94;EGYPTIAN HIEROGLYPH-13D94;Lo;0;L;;;;;N;;;;;\n13D95;EGYPTIAN HIEROGLYPH-13D95;Lo;0;L;;;;;N;;;;;\n13D96;EGYPTIAN HIEROGLYPH-13D96;Lo;0;L;;;;;N;;;;;\n13D97;EGYPTIAN HIEROGLYPH-13D97;Lo;0;L;;;;;N;;;;;\n13D98;EGYPTIAN HIEROGLYPH-13D98;Lo;0;L;;;;;N;;;;;\n13D99;EGYPTIAN HIEROGLYPH-13D99;Lo;0;L;;;;;N;;;;;\n13D9A;EGYPTIAN HIEROGLYPH-13D9A;Lo;0;L;;;;;N;;;;;\n13D9B;EGYPTIAN HIEROGLYPH-13D9B;Lo;0;L;;;;;N;;;;;\n13D9C;EGYPTIAN HIEROGLYPH-13D9C;Lo;0;L;;;;;N;;;;;\n13D9D;EGYPTIAN HIEROGLYPH-13D9D;Lo;0;L;;;;;N;;;;;\n13D9E;EGYPTIAN HIEROGLYPH-13D9E;Lo;0;L;;;;;N;;;;;\n13D9F;EGYPTIAN HIEROGLYPH-13D9F;Lo;0;L;;;;;N;;;;;\n13DA0;EGYPTIAN HIEROGLYPH-13DA0;Lo;0;L;;;;;N;;;;;\n13DA1;EGYPTIAN HIEROGLYPH-13DA1;Lo;0;L;;;;;N;;;;;\n13DA2;EGYPTIAN HIEROGLYPH-13DA2;Lo;0;L;;;;;N;;;;;\n13DA3;EGYPTIAN HIEROGLYPH-13DA3;Lo;0;L;;;;;N;;;;;\n13DA4;EGYPTIAN HIEROGLYPH-13DA4;Lo;0;L;;;;;N;;;;;\n13DA5;EGYPTIAN HIEROGLYPH-13DA5;Lo;0;L;;;;;N;;;;;\n13DA6;EGYPTIAN HIEROGLYPH-13DA6;Lo;0;L;;;;;N;;;;;\n13DA7;EGYPTIAN HIEROGLYPH-13DA7;Lo;0;L;;;;;N;;;;;\n13DA8;EGYPTIAN HIEROGLYPH-13DA8;Lo;0;L;;;;;N;;;;;\n13DA9;EGYPTIAN HIEROGLYPH-13DA9;Lo;0;L;;;;;N;;;;;\n13DAA;EGYPTIAN HIEROGLYPH-13DAA;Lo;0;L;;;;;N;;;;;\n13DAB;EGYPTIAN HIEROGLYPH-13DAB;Lo;0;L;;;;;N;;;;;\n13DAC;EGYPTIAN HIEROGLYPH-13DAC;Lo;0;L;;;;;N;;;;;\n13DAD;EGYPTIAN HIEROGLYPH-13DAD;Lo;0;L;;;;;N;;;;;\n13DAE;EGYPTIAN HIEROGLYPH-13DAE;Lo;0;L;;;;;N;;;;;\n13DAF;EGYPTIAN HIEROGLYPH-13DAF;Lo;0;L;;;;;N;;;;;\n13DB0;EGYPTIAN HIEROGLYPH-13DB0;Lo;0;L;;;;;N;;;;;\n13DB1;EGYPTIAN HIEROGLYPH-13DB1;Lo;0;L;;;;;N;;;;;\n13DB2;EGYPTIAN HIEROGLYPH-13DB2;Lo;0;L;;;;;N;;;;;\n13DB3;EGYPTIAN HIEROGLYPH-13DB3;Lo;0;L;;;;;N;;;;;\n13DB4;EGYPTIAN HIEROGLYPH-13DB4;Lo;0;L;;;;;N;;;;;\n13DB5;EGYPTIAN HIEROGLYPH-13DB5;Lo;0;L;;;;;N;;;;;\n13DB6;EGYPTIAN HIEROGLYPH-13DB6;Lo;0;L;;;;;N;;;;;\n13DB7;EGYPTIAN HIEROGLYPH-13DB7;Lo;0;L;;;;;N;;;;;\n13DB8;EGYPTIAN HIEROGLYPH-13DB8;Lo;0;L;;;;;N;;;;;\n13DB9;EGYPTIAN HIEROGLYPH-13DB9;Lo;0;L;;;;;N;;;;;\n13DBA;EGYPTIAN HIEROGLYPH-13DBA;Lo;0;L;;;;;N;;;;;\n13DBB;EGYPTIAN HIEROGLYPH-13DBB;Lo;0;L;;;;;N;;;;;\n13DBC;EGYPTIAN HIEROGLYPH-13DBC;Lo;0;L;;;;;N;;;;;\n13DBD;EGYPTIAN HIEROGLYPH-13DBD;Lo;0;L;;;;;N;;;;;\n13DBE;EGYPTIAN HIEROGLYPH-13DBE;Lo;0;L;;;;;N;;;;;\n13DBF;EGYPTIAN HIEROGLYPH-13DBF;Lo;0;L;;;;;N;;;;;\n13DC0;EGYPTIAN HIEROGLYPH-13DC0;Lo;0;L;;;;;N;;;;;\n13DC1;EGYPTIAN HIEROGLYPH-13DC1;Lo;0;L;;;;;N;;;;;\n13DC2;EGYPTIAN HIEROGLYPH-13DC2;Lo;0;L;;;;;N;;;;;\n13DC3;EGYPTIAN HIEROGLYPH-13DC3;Lo;0;L;;;;;N;;;;;\n13DC4;EGYPTIAN HIEROGLYPH-13DC4;Lo;0;L;;;;;N;;;;;\n13DC5;EGYPTIAN HIEROGLYPH-13DC5;Lo;0;L;;;;;N;;;;;\n13DC6;EGYPTIAN HIEROGLYPH-13DC6;Lo;0;L;;;;;N;;;;;\n13DC7;EGYPTIAN HIEROGLYPH-13DC7;Lo;0;L;;;;;N;;;;;\n13DC8;EGYPTIAN HIEROGLYPH-13DC8;Lo;0;L;;;;;N;;;;;\n13DC9;EGYPTIAN HIEROGLYPH-13DC9;Lo;0;L;;;;;N;;;;;\n13DCA;EGYPTIAN HIEROGLYPH-13DCA;Lo;0;L;;;;;N;;;;;\n13DCB;EGYPTIAN HIEROGLYPH-13DCB;Lo;0;L;;;;;N;;;;;\n13DCC;EGYPTIAN HIEROGLYPH-13DCC;Lo;0;L;;;;;N;;;;;\n13DCD;EGYPTIAN HIEROGLYPH-13DCD;Lo;0;L;;;;;N;;;;;\n13DCE;EGYPTIAN HIEROGLYPH-13DCE;Lo;0;L;;;;;N;;;;;\n13DCF;EGYPTIAN HIEROGLYPH-13DCF;Lo;0;L;;;;;N;;;;;\n13DD0;EGYPTIAN HIEROGLYPH-13DD0;Lo;0;L;;;;;N;;;;;\n13DD1;EGYPTIAN HIEROGLYPH-13DD1;Lo;0;L;;;;;N;;;;;\n13DD2;EGYPTIAN HIEROGLYPH-13DD2;Lo;0;L;;;;;N;;;;;\n13DD3;EGYPTIAN HIEROGLYPH-13DD3;Lo;0;L;;;;;N;;;;;\n13DD4;EGYPTIAN HIEROGLYPH-13DD4;Lo;0;L;;;;;N;;;;;\n13DD5;EGYPTIAN HIEROGLYPH-13DD5;Lo;0;L;;;;;N;;;;;\n13DD6;EGYPTIAN HIEROGLYPH-13DD6;Lo;0;L;;;;;N;;;;;\n13DD7;EGYPTIAN HIEROGLYPH-13DD7;Lo;0;L;;;;;N;;;;;\n13DD8;EGYPTIAN HIEROGLYPH-13DD8;Lo;0;L;;;;;N;;;;;\n13DD9;EGYPTIAN HIEROGLYPH-13DD9;Lo;0;L;;;;;N;;;;;\n13DDA;EGYPTIAN HIEROGLYPH-13DDA;Lo;0;L;;;;;N;;;;;\n13DDB;EGYPTIAN HIEROGLYPH-13DDB;Lo;0;L;;;;;N;;;;;\n13DDC;EGYPTIAN HIEROGLYPH-13DDC;Lo;0;L;;;;;N;;;;;\n13DDD;EGYPTIAN HIEROGLYPH-13DDD;Lo;0;L;;;;;N;;;;;\n13DDE;EGYPTIAN HIEROGLYPH-13DDE;Lo;0;L;;;;;N;;;;;\n13DDF;EGYPTIAN HIEROGLYPH-13DDF;Lo;0;L;;;;;N;;;;;\n13DE0;EGYPTIAN HIEROGLYPH-13DE0;Lo;0;L;;;;;N;;;;;\n13DE1;EGYPTIAN HIEROGLYPH-13DE1;Lo;0;L;;;;;N;;;;;\n13DE2;EGYPTIAN HIEROGLYPH-13DE2;Lo;0;L;;;;;N;;;;;\n13DE3;EGYPTIAN HIEROGLYPH-13DE3;Lo;0;L;;;;;N;;;;;\n13DE4;EGYPTIAN HIEROGLYPH-13DE4;Lo;0;L;;;;;N;;;;;\n13DE5;EGYPTIAN HIEROGLYPH-13DE5;Lo;0;L;;;;;N;;;;;\n13DE6;EGYPTIAN HIEROGLYPH-13DE6;Lo;0;L;;;;;N;;;;;\n13DE7;EGYPTIAN HIEROGLYPH-13DE7;Lo;0;L;;;;;N;;;;;\n13DE8;EGYPTIAN HIEROGLYPH-13DE8;Lo;0;L;;;;;N;;;;;\n13DE9;EGYPTIAN HIEROGLYPH-13DE9;Lo;0;L;;;;;N;;;;;\n13DEA;EGYPTIAN HIEROGLYPH-13DEA;Lo;0;L;;;;;N;;;;;\n13DEB;EGYPTIAN HIEROGLYPH-13DEB;Lo;0;L;;;;;N;;;;;\n13DEC;EGYPTIAN HIEROGLYPH-13DEC;Lo;0;L;;;;;N;;;;;\n13DED;EGYPTIAN HIEROGLYPH-13DED;Lo;0;L;;;;;N;;;;;\n13DEE;EGYPTIAN HIEROGLYPH-13DEE;Lo;0;L;;;;;N;;;;;\n13DEF;EGYPTIAN HIEROGLYPH-13DEF;Lo;0;L;;;;;N;;;;;\n13DF0;EGYPTIAN HIEROGLYPH-13DF0;Lo;0;L;;;;;N;;;;;\n13DF1;EGYPTIAN HIEROGLYPH-13DF1;Lo;0;L;;;;;N;;;;;\n13DF2;EGYPTIAN HIEROGLYPH-13DF2;Lo;0;L;;;;;N;;;;;\n13DF3;EGYPTIAN HIEROGLYPH-13DF3;Lo;0;L;;;;;N;;;;;\n13DF4;EGYPTIAN HIEROGLYPH-13DF4;Lo;0;L;;;;;N;;;;;\n13DF5;EGYPTIAN HIEROGLYPH-13DF5;Lo;0;L;;;;;N;;;;;\n13DF6;EGYPTIAN HIEROGLYPH-13DF6;Lo;0;L;;;;;N;;;;;\n13DF7;EGYPTIAN HIEROGLYPH-13DF7;Lo;0;L;;;;;N;;;;;\n13DF8;EGYPTIAN HIEROGLYPH-13DF8;Lo;0;L;;;;;N;;;;;\n13DF9;EGYPTIAN HIEROGLYPH-13DF9;Lo;0;L;;;;;N;;;;;\n13DFA;EGYPTIAN HIEROGLYPH-13DFA;Lo;0;L;;;;;N;;;;;\n13DFB;EGYPTIAN HIEROGLYPH-13DFB;Lo;0;L;;;;;N;;;;;\n13DFC;EGYPTIAN HIEROGLYPH-13DFC;Lo;0;L;;;;;N;;;;;\n13DFD;EGYPTIAN HIEROGLYPH-13DFD;Lo;0;L;;;;;N;;;;;\n13DFE;EGYPTIAN HIEROGLYPH-13DFE;Lo;0;L;;;;;N;;;;;\n13DFF;EGYPTIAN HIEROGLYPH-13DFF;Lo;0;L;;;;;N;;;;;\n13E00;EGYPTIAN HIEROGLYPH-13E00;Lo;0;L;;;;;N;;;;;\n13E01;EGYPTIAN HIEROGLYPH-13E01;Lo;0;L;;;;;N;;;;;\n13E02;EGYPTIAN HIEROGLYPH-13E02;Lo;0;L;;;;;N;;;;;\n13E03;EGYPTIAN HIEROGLYPH-13E03;Lo;0;L;;;;;N;;;;;\n13E04;EGYPTIAN HIEROGLYPH-13E04;Lo;0;L;;;;;N;;;;;\n13E05;EGYPTIAN HIEROGLYPH-13E05;Lo;0;L;;;;;N;;;;;\n13E06;EGYPTIAN HIEROGLYPH-13E06;Lo;0;L;;;;;N;;;;;\n13E07;EGYPTIAN HIEROGLYPH-13E07;Lo;0;L;;;;;N;;;;;\n13E08;EGYPTIAN HIEROGLYPH-13E08;Lo;0;L;;;;;N;;;;;\n13E09;EGYPTIAN HIEROGLYPH-13E09;Lo;0;L;;;;;N;;;;;\n13E0A;EGYPTIAN HIEROGLYPH-13E0A;Lo;0;L;;;;;N;;;;;\n13E0B;EGYPTIAN HIEROGLYPH-13E0B;Lo;0;L;;;;;N;;;;;\n13E0C;EGYPTIAN HIEROGLYPH-13E0C;Lo;0;L;;;;;N;;;;;\n13E0D;EGYPTIAN HIEROGLYPH-13E0D;Lo;0;L;;;;;N;;;;;\n13E0E;EGYPTIAN HIEROGLYPH-13E0E;Lo;0;L;;;;;N;;;;;\n13E0F;EGYPTIAN HIEROGLYPH-13E0F;Lo;0;L;;;;;N;;;;;\n13E10;EGYPTIAN HIEROGLYPH-13E10;Lo;0;L;;;;;N;;;;;\n13E11;EGYPTIAN HIEROGLYPH-13E11;Lo;0;L;;;;;N;;;;;\n13E12;EGYPTIAN HIEROGLYPH-13E12;Lo;0;L;;;;;N;;;;;\n13E13;EGYPTIAN HIEROGLYPH-13E13;Lo;0;L;;;;;N;;;;;\n13E14;EGYPTIAN HIEROGLYPH-13E14;Lo;0;L;;;;;N;;;;;\n13E15;EGYPTIAN HIEROGLYPH-13E15;Lo;0;L;;;;;N;;;;;\n13E16;EGYPTIAN HIEROGLYPH-13E16;Lo;0;L;;;;;N;;;;;\n13E17;EGYPTIAN HIEROGLYPH-13E17;Lo;0;L;;;;;N;;;;;\n13E18;EGYPTIAN HIEROGLYPH-13E18;Lo;0;L;;;;;N;;;;;\n13E19;EGYPTIAN HIEROGLYPH-13E19;Lo;0;L;;;;;N;;;;;\n13E1A;EGYPTIAN HIEROGLYPH-13E1A;Lo;0;L;;;;;N;;;;;\n13E1B;EGYPTIAN HIEROGLYPH-13E1B;Lo;0;L;;;;;N;;;;;\n13E1C;EGYPTIAN HIEROGLYPH-13E1C;Lo;0;L;;;;;N;;;;;\n13E1D;EGYPTIAN HIEROGLYPH-13E1D;Lo;0;L;;;;;N;;;;;\n13E1E;EGYPTIAN HIEROGLYPH-13E1E;Lo;0;L;;;;;N;;;;;\n13E1F;EGYPTIAN HIEROGLYPH-13E1F;Lo;0;L;;;;;N;;;;;\n13E20;EGYPTIAN HIEROGLYPH-13E20;Lo;0;L;;;;;N;;;;;\n13E21;EGYPTIAN HIEROGLYPH-13E21;Lo;0;L;;;;;N;;;;;\n13E22;EGYPTIAN HIEROGLYPH-13E22;Lo;0;L;;;;;N;;;;;\n13E23;EGYPTIAN HIEROGLYPH-13E23;Lo;0;L;;;;;N;;;;;\n13E24;EGYPTIAN HIEROGLYPH-13E24;Lo;0;L;;;;;N;;;;;\n13E25;EGYPTIAN HIEROGLYPH-13E25;Lo;0;L;;;;;N;;;;;\n13E26;EGYPTIAN HIEROGLYPH-13E26;Lo;0;L;;;;;N;;;;;\n13E27;EGYPTIAN HIEROGLYPH-13E27;Lo;0;L;;;;;N;;;;;\n13E28;EGYPTIAN HIEROGLYPH-13E28;Lo;0;L;;;;;N;;;;;\n13E29;EGYPTIAN HIEROGLYPH-13E29;Lo;0;L;;;;;N;;;;;\n13E2A;EGYPTIAN HIEROGLYPH-13E2A;Lo;0;L;;;;;N;;;;;\n13E2B;EGYPTIAN HIEROGLYPH-13E2B;Lo;0;L;;;;;N;;;;;\n13E2C;EGYPTIAN HIEROGLYPH-13E2C;Lo;0;L;;;;;N;;;;;\n13E2D;EGYPTIAN HIEROGLYPH-13E2D;Lo;0;L;;;;;N;;;;;\n13E2E;EGYPTIAN HIEROGLYPH-13E2E;Lo;0;L;;;;;N;;;;;\n13E2F;EGYPTIAN HIEROGLYPH-13E2F;Lo;0;L;;;;;N;;;;;\n13E30;EGYPTIAN HIEROGLYPH-13E30;Lo;0;L;;;;;N;;;;;\n13E31;EGYPTIAN HIEROGLYPH-13E31;Lo;0;L;;;;;N;;;;;\n13E32;EGYPTIAN HIEROGLYPH-13E32;Lo;0;L;;;;;N;;;;;\n13E33;EGYPTIAN HIEROGLYPH-13E33;Lo;0;L;;;;;N;;;;;\n13E34;EGYPTIAN HIEROGLYPH-13E34;Lo;0;L;;;;;N;;;;;\n13E35;EGYPTIAN HIEROGLYPH-13E35;Lo;0;L;;;;;N;;;;;\n13E36;EGYPTIAN HIEROGLYPH-13E36;Lo;0;L;;;;;N;;;;;\n13E37;EGYPTIAN HIEROGLYPH-13E37;Lo;0;L;;;;;N;;;;;\n13E38;EGYPTIAN HIEROGLYPH-13E38;Lo;0;L;;;;;N;;;;;\n13E39;EGYPTIAN HIEROGLYPH-13E39;Lo;0;L;;;;;N;;;;;\n13E3A;EGYPTIAN HIEROGLYPH-13E3A;Lo;0;L;;;;;N;;;;;\n13E3B;EGYPTIAN HIEROGLYPH-13E3B;Lo;0;L;;;;;N;;;;;\n13E3C;EGYPTIAN HIEROGLYPH-13E3C;Lo;0;L;;;;;N;;;;;\n13E3D;EGYPTIAN HIEROGLYPH-13E3D;Lo;0;L;;;;;N;;;;;\n13E3E;EGYPTIAN HIEROGLYPH-13E3E;Lo;0;L;;;;;N;;;;;\n13E3F;EGYPTIAN HIEROGLYPH-13E3F;Lo;0;L;;;;;N;;;;;\n13E40;EGYPTIAN HIEROGLYPH-13E40;Lo;0;L;;;;;N;;;;;\n13E41;EGYPTIAN HIEROGLYPH-13E41;Lo;0;L;;;;;N;;;;;\n13E42;EGYPTIAN HIEROGLYPH-13E42;Lo;0;L;;;;;N;;;;;\n13E43;EGYPTIAN HIEROGLYPH-13E43;Lo;0;L;;;;;N;;;;;\n13E44;EGYPTIAN HIEROGLYPH-13E44;Lo;0;L;;;;;N;;;;;\n13E45;EGYPTIAN HIEROGLYPH-13E45;Lo;0;L;;;;;N;;;;;\n13E46;EGYPTIAN HIEROGLYPH-13E46;Lo;0;L;;;;;N;;;;;\n13E47;EGYPTIAN HIEROGLYPH-13E47;Lo;0;L;;;;;N;;;;;\n13E48;EGYPTIAN HIEROGLYPH-13E48;Lo;0;L;;;;;N;;;;;\n13E49;EGYPTIAN HIEROGLYPH-13E49;Lo;0;L;;;;;N;;;;;\n13E4A;EGYPTIAN HIEROGLYPH-13E4A;Lo;0;L;;;;;N;;;;;\n13E4B;EGYPTIAN HIEROGLYPH-13E4B;Lo;0;L;;;;;N;;;;;\n13E4C;EGYPTIAN HIEROGLYPH-13E4C;Lo;0;L;;;;;N;;;;;\n13E4D;EGYPTIAN HIEROGLYPH-13E4D;Lo;0;L;;;;;N;;;;;\n13E4E;EGYPTIAN HIEROGLYPH-13E4E;Lo;0;L;;;;;N;;;;;\n13E4F;EGYPTIAN HIEROGLYPH-13E4F;Lo;0;L;;;;;N;;;;;\n13E50;EGYPTIAN HIEROGLYPH-13E50;Lo;0;L;;;;;N;;;;;\n13E51;EGYPTIAN HIEROGLYPH-13E51;Lo;0;L;;;;;N;;;;;\n13E52;EGYPTIAN HIEROGLYPH-13E52;Lo;0;L;;;;;N;;;;;\n13E53;EGYPTIAN HIEROGLYPH-13E53;Lo;0;L;;;;;N;;;;;\n13E54;EGYPTIAN HIEROGLYPH-13E54;Lo;0;L;;;;;N;;;;;\n13E55;EGYPTIAN HIEROGLYPH-13E55;Lo;0;L;;;;;N;;;;;\n13E56;EGYPTIAN HIEROGLYPH-13E56;Lo;0;L;;;;;N;;;;;\n13E57;EGYPTIAN HIEROGLYPH-13E57;Lo;0;L;;;;;N;;;;;\n13E58;EGYPTIAN HIEROGLYPH-13E58;Lo;0;L;;;;;N;;;;;\n13E59;EGYPTIAN HIEROGLYPH-13E59;Lo;0;L;;;;;N;;;;;\n13E5A;EGYPTIAN HIEROGLYPH-13E5A;Lo;0;L;;;;;N;;;;;\n13E5B;EGYPTIAN HIEROGLYPH-13E5B;Lo;0;L;;;;;N;;;;;\n13E5C;EGYPTIAN HIEROGLYPH-13E5C;Lo;0;L;;;;;N;;;;;\n13E5D;EGYPTIAN HIEROGLYPH-13E5D;Lo;0;L;;;;;N;;;;;\n13E5E;EGYPTIAN HIEROGLYPH-13E5E;Lo;0;L;;;;;N;;;;;\n13E5F;EGYPTIAN HIEROGLYPH-13E5F;Lo;0;L;;;;;N;;;;;\n13E60;EGYPTIAN HIEROGLYPH-13E60;Lo;0;L;;;;;N;;;;;\n13E61;EGYPTIAN HIEROGLYPH-13E61;Lo;0;L;;;;;N;;;;;\n13E62;EGYPTIAN HIEROGLYPH-13E62;Lo;0;L;;;;;N;;;;;\n13E63;EGYPTIAN HIEROGLYPH-13E63;Lo;0;L;;;;;N;;;;;\n13E64;EGYPTIAN HIEROGLYPH-13E64;Lo;0;L;;;;;N;;;;;\n13E65;EGYPTIAN HIEROGLYPH-13E65;Lo;0;L;;;;;N;;;;;\n13E66;EGYPTIAN HIEROGLYPH-13E66;Lo;0;L;;;;;N;;;;;\n13E67;EGYPTIAN HIEROGLYPH-13E67;Lo;0;L;;;;;N;;;;;\n13E68;EGYPTIAN HIEROGLYPH-13E68;Lo;0;L;;;;;N;;;;;\n13E69;EGYPTIAN HIEROGLYPH-13E69;Lo;0;L;;;;;N;;;;;\n13E6A;EGYPTIAN HIEROGLYPH-13E6A;Lo;0;L;;;;;N;;;;;\n13E6B;EGYPTIAN HIEROGLYPH-13E6B;Lo;0;L;;;;;N;;;;;\n13E6C;EGYPTIAN HIEROGLYPH-13E6C;Lo;0;L;;;;;N;;;;;\n13E6D;EGYPTIAN HIEROGLYPH-13E6D;Lo;0;L;;;;;N;;;;;\n13E6E;EGYPTIAN HIEROGLYPH-13E6E;Lo;0;L;;;;;N;;;;;\n13E6F;EGYPTIAN HIEROGLYPH-13E6F;Lo;0;L;;;;;N;;;;;\n13E70;EGYPTIAN HIEROGLYPH-13E70;Lo;0;L;;;;;N;;;;;\n13E71;EGYPTIAN HIEROGLYPH-13E71;Lo;0;L;;;;;N;;;;;\n13E72;EGYPTIAN HIEROGLYPH-13E72;Lo;0;L;;;;;N;;;;;\n13E73;EGYPTIAN HIEROGLYPH-13E73;Lo;0;L;;;;;N;;;;;\n13E74;EGYPTIAN HIEROGLYPH-13E74;Lo;0;L;;;;;N;;;;;\n13E75;EGYPTIAN HIEROGLYPH-13E75;Lo;0;L;;;;;N;;;;;\n13E76;EGYPTIAN HIEROGLYPH-13E76;Lo;0;L;;;;;N;;;;;\n13E77;EGYPTIAN HIEROGLYPH-13E77;Lo;0;L;;;;;N;;;;;\n13E78;EGYPTIAN HIEROGLYPH-13E78;Lo;0;L;;;;;N;;;;;\n13E79;EGYPTIAN HIEROGLYPH-13E79;Lo;0;L;;;;;N;;;;;\n13E7A;EGYPTIAN HIEROGLYPH-13E7A;Lo;0;L;;;;;N;;;;;\n13E7B;EGYPTIAN HIEROGLYPH-13E7B;Lo;0;L;;;;;N;;;;;\n13E7C;EGYPTIAN HIEROGLYPH-13E7C;Lo;0;L;;;;;N;;;;;\n13E7D;EGYPTIAN HIEROGLYPH-13E7D;Lo;0;L;;;;;N;;;;;\n13E7E;EGYPTIAN HIEROGLYPH-13E7E;Lo;0;L;;;;;N;;;;;\n13E7F;EGYPTIAN HIEROGLYPH-13E7F;Lo;0;L;;;;;N;;;;;\n13E80;EGYPTIAN HIEROGLYPH-13E80;Lo;0;L;;;;;N;;;;;\n13E81;EGYPTIAN HIEROGLYPH-13E81;Lo;0;L;;;;;N;;;;;\n13E82;EGYPTIAN HIEROGLYPH-13E82;Lo;0;L;;;;;N;;;;;\n13E83;EGYPTIAN HIEROGLYPH-13E83;Lo;0;L;;;;;N;;;;;\n13E84;EGYPTIAN HIEROGLYPH-13E84;Lo;0;L;;;;;N;;;;;\n13E85;EGYPTIAN HIEROGLYPH-13E85;Lo;0;L;;;;;N;;;;;\n13E86;EGYPTIAN HIEROGLYPH-13E86;Lo;0;L;;;;;N;;;;;\n13E87;EGYPTIAN HIEROGLYPH-13E87;Lo;0;L;;;;;N;;;;;\n13E88;EGYPTIAN HIEROGLYPH-13E88;Lo;0;L;;;;;N;;;;;\n13E89;EGYPTIAN HIEROGLYPH-13E89;Lo;0;L;;;;;N;;;;;\n13E8A;EGYPTIAN HIEROGLYPH-13E8A;Lo;0;L;;;;;N;;;;;\n13E8B;EGYPTIAN HIEROGLYPH-13E8B;Lo;0;L;;;;;N;;;;;\n13E8C;EGYPTIAN HIEROGLYPH-13E8C;Lo;0;L;;;;;N;;;;;\n13E8D;EGYPTIAN HIEROGLYPH-13E8D;Lo;0;L;;;;;N;;;;;\n13E8E;EGYPTIAN HIEROGLYPH-13E8E;Lo;0;L;;;;;N;;;;;\n13E8F;EGYPTIAN HIEROGLYPH-13E8F;Lo;0;L;;;;;N;;;;;\n13E90;EGYPTIAN HIEROGLYPH-13E90;Lo;0;L;;;;;N;;;;;\n13E91;EGYPTIAN HIEROGLYPH-13E91;Lo;0;L;;;;;N;;;;;\n13E92;EGYPTIAN HIEROGLYPH-13E92;Lo;0;L;;;;;N;;;;;\n13E93;EGYPTIAN HIEROGLYPH-13E93;Lo;0;L;;;;;N;;;;;\n13E94;EGYPTIAN HIEROGLYPH-13E94;Lo;0;L;;;;;N;;;;;\n13E95;EGYPTIAN HIEROGLYPH-13E95;Lo;0;L;;;;;N;;;;;\n13E96;EGYPTIAN HIEROGLYPH-13E96;Lo;0;L;;;;;N;;;;;\n13E97;EGYPTIAN HIEROGLYPH-13E97;Lo;0;L;;;;;N;;;;;\n13E98;EGYPTIAN HIEROGLYPH-13E98;Lo;0;L;;;;;N;;;;;\n13E99;EGYPTIAN HIEROGLYPH-13E99;Lo;0;L;;;;;N;;;;;\n13E9A;EGYPTIAN HIEROGLYPH-13E9A;Lo;0;L;;;;;N;;;;;\n13E9B;EGYPTIAN HIEROGLYPH-13E9B;Lo;0;L;;;;;N;;;;;\n13E9C;EGYPTIAN HIEROGLYPH-13E9C;Lo;0;L;;;;;N;;;;;\n13E9D;EGYPTIAN HIEROGLYPH-13E9D;Lo;0;L;;;;;N;;;;;\n13E9E;EGYPTIAN HIEROGLYPH-13E9E;Lo;0;L;;;;;N;;;;;\n13E9F;EGYPTIAN HIEROGLYPH-13E9F;Lo;0;L;;;;;N;;;;;\n13EA0;EGYPTIAN HIEROGLYPH-13EA0;Lo;0;L;;;;;N;;;;;\n13EA1;EGYPTIAN HIEROGLYPH-13EA1;Lo;0;L;;;;;N;;;;;\n13EA2;EGYPTIAN HIEROGLYPH-13EA2;Lo;0;L;;;;;N;;;;;\n13EA3;EGYPTIAN HIEROGLYPH-13EA3;Lo;0;L;;;;;N;;;;;\n13EA4;EGYPTIAN HIEROGLYPH-13EA4;Lo;0;L;;;;;N;;;;;\n13EA5;EGYPTIAN HIEROGLYPH-13EA5;Lo;0;L;;;;;N;;;;;\n13EA6;EGYPTIAN HIEROGLYPH-13EA6;Lo;0;L;;;;;N;;;;;\n13EA7;EGYPTIAN HIEROGLYPH-13EA7;Lo;0;L;;;;;N;;;;;\n13EA8;EGYPTIAN HIEROGLYPH-13EA8;Lo;0;L;;;;;N;;;;;\n13EA9;EGYPTIAN HIEROGLYPH-13EA9;Lo;0;L;;;;;N;;;;;\n13EAA;EGYPTIAN HIEROGLYPH-13EAA;Lo;0;L;;;;;N;;;;;\n13EAB;EGYPTIAN HIEROGLYPH-13EAB;Lo;0;L;;;;;N;;;;;\n13EAC;EGYPTIAN HIEROGLYPH-13EAC;Lo;0;L;;;;;N;;;;;\n13EAD;EGYPTIAN HIEROGLYPH-13EAD;Lo;0;L;;;;;N;;;;;\n13EAE;EGYPTIAN HIEROGLYPH-13EAE;Lo;0;L;;;;;N;;;;;\n13EAF;EGYPTIAN HIEROGLYPH-13EAF;Lo;0;L;;;;;N;;;;;\n13EB0;EGYPTIAN HIEROGLYPH-13EB0;Lo;0;L;;;;;N;;;;;\n13EB1;EGYPTIAN HIEROGLYPH-13EB1;Lo;0;L;;;;;N;;;;;\n13EB2;EGYPTIAN HIEROGLYPH-13EB2;Lo;0;L;;;;;N;;;;;\n13EB3;EGYPTIAN HIEROGLYPH-13EB3;Lo;0;L;;;;;N;;;;;\n13EB4;EGYPTIAN HIEROGLYPH-13EB4;Lo;0;L;;;;;N;;;;;\n13EB5;EGYPTIAN HIEROGLYPH-13EB5;Lo;0;L;;;;;N;;;;;\n13EB6;EGYPTIAN HIEROGLYPH-13EB6;Lo;0;L;;;;;N;;;;;\n13EB7;EGYPTIAN HIEROGLYPH-13EB7;Lo;0;L;;;;;N;;;;;\n13EB8;EGYPTIAN HIEROGLYPH-13EB8;Lo;0;L;;;;;N;;;;;\n13EB9;EGYPTIAN HIEROGLYPH-13EB9;Lo;0;L;;;;;N;;;;;\n13EBA;EGYPTIAN HIEROGLYPH-13EBA;Lo;0;L;;;;;N;;;;;\n13EBB;EGYPTIAN HIEROGLYPH-13EBB;Lo;0;L;;;;;N;;;;;\n13EBC;EGYPTIAN HIEROGLYPH-13EBC;Lo;0;L;;;;;N;;;;;\n13EBD;EGYPTIAN HIEROGLYPH-13EBD;Lo;0;L;;;;;N;;;;;\n13EBE;EGYPTIAN HIEROGLYPH-13EBE;Lo;0;L;;;;;N;;;;;\n13EBF;EGYPTIAN HIEROGLYPH-13EBF;Lo;0;L;;;;;N;;;;;\n13EC0;EGYPTIAN HIEROGLYPH-13EC0;Lo;0;L;;;;;N;;;;;\n13EC1;EGYPTIAN HIEROGLYPH-13EC1;Lo;0;L;;;;;N;;;;;\n13EC2;EGYPTIAN HIEROGLYPH-13EC2;Lo;0;L;;;;;N;;;;;\n13EC3;EGYPTIAN HIEROGLYPH-13EC3;Lo;0;L;;;;;N;;;;;\n13EC4;EGYPTIAN HIEROGLYPH-13EC4;Lo;0;L;;;;;N;;;;;\n13EC5;EGYPTIAN HIEROGLYPH-13EC5;Lo;0;L;;;;;N;;;;;\n13EC6;EGYPTIAN HIEROGLYPH-13EC6;Lo;0;L;;;;;N;;;;;\n13EC7;EGYPTIAN HIEROGLYPH-13EC7;Lo;0;L;;;;;N;;;;;\n13EC8;EGYPTIAN HIEROGLYPH-13EC8;Lo;0;L;;;;;N;;;;;\n13EC9;EGYPTIAN HIEROGLYPH-13EC9;Lo;0;L;;;;;N;;;;;\n13ECA;EGYPTIAN HIEROGLYPH-13ECA;Lo;0;L;;;;;N;;;;;\n13ECB;EGYPTIAN HIEROGLYPH-13ECB;Lo;0;L;;;;;N;;;;;\n13ECC;EGYPTIAN HIEROGLYPH-13ECC;Lo;0;L;;;;;N;;;;;\n13ECD;EGYPTIAN HIEROGLYPH-13ECD;Lo;0;L;;;;;N;;;;;\n13ECE;EGYPTIAN HIEROGLYPH-13ECE;Lo;0;L;;;;;N;;;;;\n13ECF;EGYPTIAN HIEROGLYPH-13ECF;Lo;0;L;;;;;N;;;;;\n13ED0;EGYPTIAN HIEROGLYPH-13ED0;Lo;0;L;;;;;N;;;;;\n13ED1;EGYPTIAN HIEROGLYPH-13ED1;Lo;0;L;;;;;N;;;;;\n13ED2;EGYPTIAN HIEROGLYPH-13ED2;Lo;0;L;;;;;N;;;;;\n13ED3;EGYPTIAN HIEROGLYPH-13ED3;Lo;0;L;;;;;N;;;;;\n13ED4;EGYPTIAN HIEROGLYPH-13ED4;Lo;0;L;;;;;N;;;;;\n13ED5;EGYPTIAN HIEROGLYPH-13ED5;Lo;0;L;;;;;N;;;;;\n13ED6;EGYPTIAN HIEROGLYPH-13ED6;Lo;0;L;;;;;N;;;;;\n13ED7;EGYPTIAN HIEROGLYPH-13ED7;Lo;0;L;;;;;N;;;;;\n13ED8;EGYPTIAN HIEROGLYPH-13ED8;Lo;0;L;;;;;N;;;;;\n13ED9;EGYPTIAN HIEROGLYPH-13ED9;Lo;0;L;;;;;N;;;;;\n13EDA;EGYPTIAN HIEROGLYPH-13EDA;Lo;0;L;;;;;N;;;;;\n13EDB;EGYPTIAN HIEROGLYPH-13EDB;Lo;0;L;;;;;N;;;;;\n13EDC;EGYPTIAN HIEROGLYPH-13EDC;Lo;0;L;;;;;N;;;;;\n13EDD;EGYPTIAN HIEROGLYPH-13EDD;Lo;0;L;;;;;N;;;;;\n13EDE;EGYPTIAN HIEROGLYPH-13EDE;Lo;0;L;;;;;N;;;;;\n13EDF;EGYPTIAN HIEROGLYPH-13EDF;Lo;0;L;;;;;N;;;;;\n13EE0;EGYPTIAN HIEROGLYPH-13EE0;Lo;0;L;;;;;N;;;;;\n13EE1;EGYPTIAN HIEROGLYPH-13EE1;Lo;0;L;;;;;N;;;;;\n13EE2;EGYPTIAN HIEROGLYPH-13EE2;Lo;0;L;;;;;N;;;;;\n13EE3;EGYPTIAN HIEROGLYPH-13EE3;Lo;0;L;;;;;N;;;;;\n13EE4;EGYPTIAN HIEROGLYPH-13EE4;Lo;0;L;;;;;N;;;;;\n13EE5;EGYPTIAN HIEROGLYPH-13EE5;Lo;0;L;;;;;N;;;;;\n13EE6;EGYPTIAN HIEROGLYPH-13EE6;Lo;0;L;;;;;N;;;;;\n13EE7;EGYPTIAN HIEROGLYPH-13EE7;Lo;0;L;;;;;N;;;;;\n13EE8;EGYPTIAN HIEROGLYPH-13EE8;Lo;0;L;;;;;N;;;;;\n13EE9;EGYPTIAN HIEROGLYPH-13EE9;Lo;0;L;;;;;N;;;;;\n13EEA;EGYPTIAN HIEROGLYPH-13EEA;Lo;0;L;;;;;N;;;;;\n13EEB;EGYPTIAN HIEROGLYPH-13EEB;Lo;0;L;;;;;N;;;;;\n13EEC;EGYPTIAN HIEROGLYPH-13EEC;Lo;0;L;;;;;N;;;;;\n13EED;EGYPTIAN HIEROGLYPH-13EED;Lo;0;L;;;;;N;;;;;\n13EEE;EGYPTIAN HIEROGLYPH-13EEE;Lo;0;L;;;;;N;;;;;\n13EEF;EGYPTIAN HIEROGLYPH-13EEF;Lo;0;L;;;;;N;;;;;\n13EF0;EGYPTIAN HIEROGLYPH-13EF0;Lo;0;L;;;;;N;;;;;\n13EF1;EGYPTIAN HIEROGLYPH-13EF1;Lo;0;L;;;;;N;;;;;\n13EF2;EGYPTIAN HIEROGLYPH-13EF2;Lo;0;L;;;;;N;;;;;\n13EF3;EGYPTIAN HIEROGLYPH-13EF3;Lo;0;L;;;;;N;;;;;\n13EF4;EGYPTIAN HIEROGLYPH-13EF4;Lo;0;L;;;;;N;;;;;\n13EF5;EGYPTIAN HIEROGLYPH-13EF5;Lo;0;L;;;;;N;;;;;\n13EF6;EGYPTIAN HIEROGLYPH-13EF6;Lo;0;L;;;;;N;;;;;\n13EF7;EGYPTIAN HIEROGLYPH-13EF7;Lo;0;L;;;;;N;;;;;\n13EF8;EGYPTIAN HIEROGLYPH-13EF8;Lo;0;L;;;;;N;;;;;\n13EF9;EGYPTIAN HIEROGLYPH-13EF9;Lo;0;L;;;;;N;;;;;\n13EFA;EGYPTIAN HIEROGLYPH-13EFA;Lo;0;L;;;;;N;;;;;\n13EFB;EGYPTIAN HIEROGLYPH-13EFB;Lo;0;L;;;;;N;;;;;\n13EFC;EGYPTIAN HIEROGLYPH-13EFC;Lo;0;L;;;;;N;;;;;\n13EFD;EGYPTIAN HIEROGLYPH-13EFD;Lo;0;L;;;;;N;;;;;\n13EFE;EGYPTIAN HIEROGLYPH-13EFE;Lo;0;L;;;;;N;;;;;\n13EFF;EGYPTIAN HIEROGLYPH-13EFF;Lo;0;L;;;;;N;;;;;\n13F00;EGYPTIAN HIEROGLYPH-13F00;Lo;0;L;;;;;N;;;;;\n13F01;EGYPTIAN HIEROGLYPH-13F01;Lo;0;L;;;;;N;;;;;\n13F02;EGYPTIAN HIEROGLYPH-13F02;Lo;0;L;;;;;N;;;;;\n13F03;EGYPTIAN HIEROGLYPH-13F03;Lo;0;L;;;;;N;;;;;\n13F04;EGYPTIAN HIEROGLYPH-13F04;Lo;0;L;;;;;N;;;;;\n13F05;EGYPTIAN HIEROGLYPH-13F05;Lo;0;L;;;;;N;;;;;\n13F06;EGYPTIAN HIEROGLYPH-13F06;Lo;0;L;;;;;N;;;;;\n13F07;EGYPTIAN HIEROGLYPH-13F07;Lo;0;L;;;;;N;;;;;\n13F08;EGYPTIAN HIEROGLYPH-13F08;Lo;0;L;;;;;N;;;;;\n13F09;EGYPTIAN HIEROGLYPH-13F09;Lo;0;L;;;;;N;;;;;\n13F0A;EGYPTIAN HIEROGLYPH-13F0A;Lo;0;L;;;;;N;;;;;\n13F0B;EGYPTIAN HIEROGLYPH-13F0B;Lo;0;L;;;;;N;;;;;\n13F0C;EGYPTIAN HIEROGLYPH-13F0C;Lo;0;L;;;;;N;;;;;\n13F0D;EGYPTIAN HIEROGLYPH-13F0D;Lo;0;L;;;;;N;;;;;\n13F0E;EGYPTIAN HIEROGLYPH-13F0E;Lo;0;L;;;;;N;;;;;\n13F0F;EGYPTIAN HIEROGLYPH-13F0F;Lo;0;L;;;;;N;;;;;\n13F10;EGYPTIAN HIEROGLYPH-13F10;Lo;0;L;;;;;N;;;;;\n13F11;EGYPTIAN HIEROGLYPH-13F11;Lo;0;L;;;;;N;;;;;\n13F12;EGYPTIAN HIEROGLYPH-13F12;Lo;0;L;;;;;N;;;;;\n13F13;EGYPTIAN HIEROGLYPH-13F13;Lo;0;L;;;;;N;;;;;\n13F14;EGYPTIAN HIEROGLYPH-13F14;Lo;0;L;;;;;N;;;;;\n13F15;EGYPTIAN HIEROGLYPH-13F15;Lo;0;L;;;;;N;;;;;\n13F16;EGYPTIAN HIEROGLYPH-13F16;Lo;0;L;;;;;N;;;;;\n13F17;EGYPTIAN HIEROGLYPH-13F17;Lo;0;L;;;;;N;;;;;\n13F18;EGYPTIAN HIEROGLYPH-13F18;Lo;0;L;;;;;N;;;;;\n13F19;EGYPTIAN HIEROGLYPH-13F19;Lo;0;L;;;;;N;;;;;\n13F1A;EGYPTIAN HIEROGLYPH-13F1A;Lo;0;L;;;;;N;;;;;\n13F1B;EGYPTIAN HIEROGLYPH-13F1B;Lo;0;L;;;;;N;;;;;\n13F1C;EGYPTIAN HIEROGLYPH-13F1C;Lo;0;L;;;;;N;;;;;\n13F1D;EGYPTIAN HIEROGLYPH-13F1D;Lo;0;L;;;;;N;;;;;\n13F1E;EGYPTIAN HIEROGLYPH-13F1E;Lo;0;L;;;;;N;;;;;\n13F1F;EGYPTIAN HIEROGLYPH-13F1F;Lo;0;L;;;;;N;;;;;\n13F20;EGYPTIAN HIEROGLYPH-13F20;Lo;0;L;;;;;N;;;;;\n13F21;EGYPTIAN HIEROGLYPH-13F21;Lo;0;L;;;;;N;;;;;\n13F22;EGYPTIAN HIEROGLYPH-13F22;Lo;0;L;;;;;N;;;;;\n13F23;EGYPTIAN HIEROGLYPH-13F23;Lo;0;L;;;;;N;;;;;\n13F24;EGYPTIAN HIEROGLYPH-13F24;Lo;0;L;;;;;N;;;;;\n13F25;EGYPTIAN HIEROGLYPH-13F25;Lo;0;L;;;;;N;;;;;\n13F26;EGYPTIAN HIEROGLYPH-13F26;Lo;0;L;;;;;N;;;;;\n13F27;EGYPTIAN HIEROGLYPH-13F27;Lo;0;L;;;;;N;;;;;\n13F28;EGYPTIAN HIEROGLYPH-13F28;Lo;0;L;;;;;N;;;;;\n13F29;EGYPTIAN HIEROGLYPH-13F29;Lo;0;L;;;;;N;;;;;\n13F2A;EGYPTIAN HIEROGLYPH-13F2A;Lo;0;L;;;;;N;;;;;\n13F2B;EGYPTIAN HIEROGLYPH-13F2B;Lo;0;L;;;;;N;;;;;\n13F2C;EGYPTIAN HIEROGLYPH-13F2C;Lo;0;L;;;;;N;;;;;\n13F2D;EGYPTIAN HIEROGLYPH-13F2D;Lo;0;L;;;;;N;;;;;\n13F2E;EGYPTIAN HIEROGLYPH-13F2E;Lo;0;L;;;;;N;;;;;\n13F2F;EGYPTIAN HIEROGLYPH-13F2F;Lo;0;L;;;;;N;;;;;\n13F30;EGYPTIAN HIEROGLYPH-13F30;Lo;0;L;;;;;N;;;;;\n13F31;EGYPTIAN HIEROGLYPH-13F31;Lo;0;L;;;;;N;;;;;\n13F32;EGYPTIAN HIEROGLYPH-13F32;Lo;0;L;;;;;N;;;;;\n13F33;EGYPTIAN HIEROGLYPH-13F33;Lo;0;L;;;;;N;;;;;\n13F34;EGYPTIAN HIEROGLYPH-13F34;Lo;0;L;;;;;N;;;;;\n13F35;EGYPTIAN HIEROGLYPH-13F35;Lo;0;L;;;;;N;;;;;\n13F36;EGYPTIAN HIEROGLYPH-13F36;Lo;0;L;;;;;N;;;;;\n13F37;EGYPTIAN HIEROGLYPH-13F37;Lo;0;L;;;;;N;;;;;\n13F38;EGYPTIAN HIEROGLYPH-13F38;Lo;0;L;;;;;N;;;;;\n13F39;EGYPTIAN HIEROGLYPH-13F39;Lo;0;L;;;;;N;;;;;\n13F3A;EGYPTIAN HIEROGLYPH-13F3A;Lo;0;L;;;;;N;;;;;\n13F3B;EGYPTIAN HIEROGLYPH-13F3B;Lo;0;L;;;;;N;;;;;\n13F3C;EGYPTIAN HIEROGLYPH-13F3C;Lo;0;L;;;;;N;;;;;\n13F3D;EGYPTIAN HIEROGLYPH-13F3D;Lo;0;L;;;;;N;;;;;\n13F3E;EGYPTIAN HIEROGLYPH-13F3E;Lo;0;L;;;;;N;;;;;\n13F3F;EGYPTIAN HIEROGLYPH-13F3F;Lo;0;L;;;;;N;;;;;\n13F40;EGYPTIAN HIEROGLYPH-13F40;Lo;0;L;;;;;N;;;;;\n13F41;EGYPTIAN HIEROGLYPH-13F41;Lo;0;L;;;;;N;;;;;\n13F42;EGYPTIAN HIEROGLYPH-13F42;Lo;0;L;;;;;N;;;;;\n13F43;EGYPTIAN HIEROGLYPH-13F43;Lo;0;L;;;;;N;;;;;\n13F44;EGYPTIAN HIEROGLYPH-13F44;Lo;0;L;;;;;N;;;;;\n13F45;EGYPTIAN HIEROGLYPH-13F45;Lo;0;L;;;;;N;;;;;\n13F46;EGYPTIAN HIEROGLYPH-13F46;Lo;0;L;;;;;N;;;;;\n13F47;EGYPTIAN HIEROGLYPH-13F47;Lo;0;L;;;;;N;;;;;\n13F48;EGYPTIAN HIEROGLYPH-13F48;Lo;0;L;;;;;N;;;;;\n13F49;EGYPTIAN HIEROGLYPH-13F49;Lo;0;L;;;;;N;;;;;\n13F4A;EGYPTIAN HIEROGLYPH-13F4A;Lo;0;L;;;;;N;;;;;\n13F4B;EGYPTIAN HIEROGLYPH-13F4B;Lo;0;L;;;;;N;;;;;\n13F4C;EGYPTIAN HIEROGLYPH-13F4C;Lo;0;L;;;;;N;;;;;\n13F4D;EGYPTIAN HIEROGLYPH-13F4D;Lo;0;L;;;;;N;;;;;\n13F4E;EGYPTIAN HIEROGLYPH-13F4E;Lo;0;L;;;;;N;;;;;\n13F4F;EGYPTIAN HIEROGLYPH-13F4F;Lo;0;L;;;;;N;;;;;\n13F50;EGYPTIAN HIEROGLYPH-13F50;Lo;0;L;;;;;N;;;;;\n13F51;EGYPTIAN HIEROGLYPH-13F51;Lo;0;L;;;;;N;;;;;\n13F52;EGYPTIAN HIEROGLYPH-13F52;Lo;0;L;;;;;N;;;;;\n13F53;EGYPTIAN HIEROGLYPH-13F53;Lo;0;L;;;;;N;;;;;\n13F54;EGYPTIAN HIEROGLYPH-13F54;Lo;0;L;;;;;N;;;;;\n13F55;EGYPTIAN HIEROGLYPH-13F55;Lo;0;L;;;;;N;;;;;\n13F56;EGYPTIAN HIEROGLYPH-13F56;Lo;0;L;;;;;N;;;;;\n13F57;EGYPTIAN HIEROGLYPH-13F57;Lo;0;L;;;;;N;;;;;\n13F58;EGYPTIAN HIEROGLYPH-13F58;Lo;0;L;;;;;N;;;;;\n13F59;EGYPTIAN HIEROGLYPH-13F59;Lo;0;L;;;;;N;;;;;\n13F5A;EGYPTIAN HIEROGLYPH-13F5A;Lo;0;L;;;;;N;;;;;\n13F5B;EGYPTIAN HIEROGLYPH-13F5B;Lo;0;L;;;;;N;;;;;\n13F5C;EGYPTIAN HIEROGLYPH-13F5C;Lo;0;L;;;;;N;;;;;\n13F5D;EGYPTIAN HIEROGLYPH-13F5D;Lo;0;L;;;;;N;;;;;\n13F5E;EGYPTIAN HIEROGLYPH-13F5E;Lo;0;L;;;;;N;;;;;\n13F5F;EGYPTIAN HIEROGLYPH-13F5F;Lo;0;L;;;;;N;;;;;\n13F60;EGYPTIAN HIEROGLYPH-13F60;Lo;0;L;;;;;N;;;;;\n13F61;EGYPTIAN HIEROGLYPH-13F61;Lo;0;L;;;;;N;;;;;\n13F62;EGYPTIAN HIEROGLYPH-13F62;Lo;0;L;;;;;N;;;;;\n13F63;EGYPTIAN HIEROGLYPH-13F63;Lo;0;L;;;;;N;;;;;\n13F64;EGYPTIAN HIEROGLYPH-13F64;Lo;0;L;;;;;N;;;;;\n13F65;EGYPTIAN HIEROGLYPH-13F65;Lo;0;L;;;;;N;;;;;\n13F66;EGYPTIAN HIEROGLYPH-13F66;Lo;0;L;;;;;N;;;;;\n13F67;EGYPTIAN HIEROGLYPH-13F67;Lo;0;L;;;;;N;;;;;\n13F68;EGYPTIAN HIEROGLYPH-13F68;Lo;0;L;;;;;N;;;;;\n13F69;EGYPTIAN HIEROGLYPH-13F69;Lo;0;L;;;;;N;;;;;\n13F6A;EGYPTIAN HIEROGLYPH-13F6A;Lo;0;L;;;;;N;;;;;\n13F6B;EGYPTIAN HIEROGLYPH-13F6B;Lo;0;L;;;;;N;;;;;\n13F6C;EGYPTIAN HIEROGLYPH-13F6C;Lo;0;L;;;;;N;;;;;\n13F6D;EGYPTIAN HIEROGLYPH-13F6D;Lo;0;L;;;;;N;;;;;\n13F6E;EGYPTIAN HIEROGLYPH-13F6E;Lo;0;L;;;;;N;;;;;\n13F6F;EGYPTIAN HIEROGLYPH-13F6F;Lo;0;L;;;;;N;;;;;\n13F70;EGYPTIAN HIEROGLYPH-13F70;Lo;0;L;;;;;N;;;;;\n13F71;EGYPTIAN HIEROGLYPH-13F71;Lo;0;L;;;;;N;;;;;\n13F72;EGYPTIAN HIEROGLYPH-13F72;Lo;0;L;;;;;N;;;;;\n13F73;EGYPTIAN HIEROGLYPH-13F73;Lo;0;L;;;;;N;;;;;\n13F74;EGYPTIAN HIEROGLYPH-13F74;Lo;0;L;;;;;N;;;;;\n13F75;EGYPTIAN HIEROGLYPH-13F75;Lo;0;L;;;;;N;;;;;\n13F76;EGYPTIAN HIEROGLYPH-13F76;Lo;0;L;;;;;N;;;;;\n13F77;EGYPTIAN HIEROGLYPH-13F77;Lo;0;L;;;;;N;;;;;\n13F78;EGYPTIAN HIEROGLYPH-13F78;Lo;0;L;;;;;N;;;;;\n13F79;EGYPTIAN HIEROGLYPH-13F79;Lo;0;L;;;;;N;;;;;\n13F7A;EGYPTIAN HIEROGLYPH-13F7A;Lo;0;L;;;;;N;;;;;\n13F7B;EGYPTIAN HIEROGLYPH-13F7B;Lo;0;L;;;;;N;;;;;\n13F7C;EGYPTIAN HIEROGLYPH-13F7C;Lo;0;L;;;;;N;;;;;\n13F7D;EGYPTIAN HIEROGLYPH-13F7D;Lo;0;L;;;;;N;;;;;\n13F7E;EGYPTIAN HIEROGLYPH-13F7E;Lo;0;L;;;;;N;;;;;\n13F7F;EGYPTIAN HIEROGLYPH-13F7F;Lo;0;L;;;;;N;;;;;\n13F80;EGYPTIAN HIEROGLYPH-13F80;Lo;0;L;;;;;N;;;;;\n13F81;EGYPTIAN HIEROGLYPH-13F81;Lo;0;L;;;;;N;;;;;\n13F82;EGYPTIAN HIEROGLYPH-13F82;Lo;0;L;;;;;N;;;;;\n13F83;EGYPTIAN HIEROGLYPH-13F83;Lo;0;L;;;;;N;;;;;\n13F84;EGYPTIAN HIEROGLYPH-13F84;Lo;0;L;;;;;N;;;;;\n13F85;EGYPTIAN HIEROGLYPH-13F85;Lo;0;L;;;;;N;;;;;\n13F86;EGYPTIAN HIEROGLYPH-13F86;Lo;0;L;;;;;N;;;;;\n13F87;EGYPTIAN HIEROGLYPH-13F87;Lo;0;L;;;;;N;;;;;\n13F88;EGYPTIAN HIEROGLYPH-13F88;Lo;0;L;;;;;N;;;;;\n13F89;EGYPTIAN HIEROGLYPH-13F89;Lo;0;L;;;;;N;;;;;\n13F8A;EGYPTIAN HIEROGLYPH-13F8A;Lo;0;L;;;;;N;;;;;\n13F8B;EGYPTIAN HIEROGLYPH-13F8B;Lo;0;L;;;;;N;;;;;\n13F8C;EGYPTIAN HIEROGLYPH-13F8C;Lo;0;L;;;;;N;;;;;\n13F8D;EGYPTIAN HIEROGLYPH-13F8D;Lo;0;L;;;;;N;;;;;\n13F8E;EGYPTIAN HIEROGLYPH-13F8E;Lo;0;L;;;;;N;;;;;\n13F8F;EGYPTIAN HIEROGLYPH-13F8F;Lo;0;L;;;;;N;;;;;\n13F90;EGYPTIAN HIEROGLYPH-13F90;Lo;0;L;;;;;N;;;;;\n13F91;EGYPTIAN HIEROGLYPH-13F91;Lo;0;L;;;;;N;;;;;\n13F92;EGYPTIAN HIEROGLYPH-13F92;Lo;0;L;;;;;N;;;;;\n13F93;EGYPTIAN HIEROGLYPH-13F93;Lo;0;L;;;;;N;;;;;\n13F94;EGYPTIAN HIEROGLYPH-13F94;Lo;0;L;;;;;N;;;;;\n13F95;EGYPTIAN HIEROGLYPH-13F95;Lo;0;L;;;;;N;;;;;\n13F96;EGYPTIAN HIEROGLYPH-13F96;Lo;0;L;;;;;N;;;;;\n13F97;EGYPTIAN HIEROGLYPH-13F97;Lo;0;L;;;;;N;;;;;\n13F98;EGYPTIAN HIEROGLYPH-13F98;Lo;0;L;;;;;N;;;;;\n13F99;EGYPTIAN HIEROGLYPH-13F99;Lo;0;L;;;;;N;;;;;\n13F9A;EGYPTIAN HIEROGLYPH-13F9A;Lo;0;L;;;;;N;;;;;\n13F9B;EGYPTIAN HIEROGLYPH-13F9B;Lo;0;L;;;;;N;;;;;\n13F9C;EGYPTIAN HIEROGLYPH-13F9C;Lo;0;L;;;;;N;;;;;\n13F9D;EGYPTIAN HIEROGLYPH-13F9D;Lo;0;L;;;;;N;;;;;\n13F9E;EGYPTIAN HIEROGLYPH-13F9E;Lo;0;L;;;;;N;;;;;\n13F9F;EGYPTIAN HIEROGLYPH-13F9F;Lo;0;L;;;;;N;;;;;\n13FA0;EGYPTIAN HIEROGLYPH-13FA0;Lo;0;L;;;;;N;;;;;\n13FA1;EGYPTIAN HIEROGLYPH-13FA1;Lo;0;L;;;;;N;;;;;\n13FA2;EGYPTIAN HIEROGLYPH-13FA2;Lo;0;L;;;;;N;;;;;\n13FA3;EGYPTIAN HIEROGLYPH-13FA3;Lo;0;L;;;;;N;;;;;\n13FA4;EGYPTIAN HIEROGLYPH-13FA4;Lo;0;L;;;;;N;;;;;\n13FA5;EGYPTIAN HIEROGLYPH-13FA5;Lo;0;L;;;;;N;;;;;\n13FA6;EGYPTIAN HIEROGLYPH-13FA6;Lo;0;L;;;;;N;;;;;\n13FA7;EGYPTIAN HIEROGLYPH-13FA7;Lo;0;L;;;;;N;;;;;\n13FA8;EGYPTIAN HIEROGLYPH-13FA8;Lo;0;L;;;;;N;;;;;\n13FA9;EGYPTIAN HIEROGLYPH-13FA9;Lo;0;L;;;;;N;;;;;\n13FAA;EGYPTIAN HIEROGLYPH-13FAA;Lo;0;L;;;;;N;;;;;\n13FAB;EGYPTIAN HIEROGLYPH-13FAB;Lo;0;L;;;;;N;;;;;\n13FAC;EGYPTIAN HIEROGLYPH-13FAC;Lo;0;L;;;;;N;;;;;\n13FAD;EGYPTIAN HIEROGLYPH-13FAD;Lo;0;L;;;;;N;;;;;\n13FAE;EGYPTIAN HIEROGLYPH-13FAE;Lo;0;L;;;;;N;;;;;\n13FAF;EGYPTIAN HIEROGLYPH-13FAF;Lo;0;L;;;;;N;;;;;\n13FB0;EGYPTIAN HIEROGLYPH-13FB0;Lo;0;L;;;;;N;;;;;\n13FB1;EGYPTIAN HIEROGLYPH-13FB1;Lo;0;L;;;;;N;;;;;\n13FB2;EGYPTIAN HIEROGLYPH-13FB2;Lo;0;L;;;;;N;;;;;\n13FB3;EGYPTIAN HIEROGLYPH-13FB3;Lo;0;L;;;;;N;;;;;\n13FB4;EGYPTIAN HIEROGLYPH-13FB4;Lo;0;L;;;;;N;;;;;\n13FB5;EGYPTIAN HIEROGLYPH-13FB5;Lo;0;L;;;;;N;;;;;\n13FB6;EGYPTIAN HIEROGLYPH-13FB6;Lo;0;L;;;;;N;;;;;\n13FB7;EGYPTIAN HIEROGLYPH-13FB7;Lo;0;L;;;;;N;;;;;\n13FB8;EGYPTIAN HIEROGLYPH-13FB8;Lo;0;L;;;;;N;;;;;\n13FB9;EGYPTIAN HIEROGLYPH-13FB9;Lo;0;L;;;;;N;;;;;\n13FBA;EGYPTIAN HIEROGLYPH-13FBA;Lo;0;L;;;;;N;;;;;\n13FBB;EGYPTIAN HIEROGLYPH-13FBB;Lo;0;L;;;;;N;;;;;\n13FBC;EGYPTIAN HIEROGLYPH-13FBC;Lo;0;L;;;;;N;;;;;\n13FBD;EGYPTIAN HIEROGLYPH-13FBD;Lo;0;L;;;;;N;;;;;\n13FBE;EGYPTIAN HIEROGLYPH-13FBE;Lo;0;L;;;;;N;;;;;\n13FBF;EGYPTIAN HIEROGLYPH-13FBF;Lo;0;L;;;;;N;;;;;\n13FC0;EGYPTIAN HIEROGLYPH-13FC0;Lo;0;L;;;;;N;;;;;\n13FC1;EGYPTIAN HIEROGLYPH-13FC1;Lo;0;L;;;;;N;;;;;\n13FC2;EGYPTIAN HIEROGLYPH-13FC2;Lo;0;L;;;;;N;;;;;\n13FC3;EGYPTIAN HIEROGLYPH-13FC3;Lo;0;L;;;;;N;;;;;\n13FC4;EGYPTIAN HIEROGLYPH-13FC4;Lo;0;L;;;;;N;;;;;\n13FC5;EGYPTIAN HIEROGLYPH-13FC5;Lo;0;L;;;;;N;;;;;\n13FC6;EGYPTIAN HIEROGLYPH-13FC6;Lo;0;L;;;;;N;;;;;\n13FC7;EGYPTIAN HIEROGLYPH-13FC7;Lo;0;L;;;;;N;;;;;\n13FC8;EGYPTIAN HIEROGLYPH-13FC8;Lo;0;L;;;;;N;;;;;\n13FC9;EGYPTIAN HIEROGLYPH-13FC9;Lo;0;L;;;;;N;;;;;\n13FCA;EGYPTIAN HIEROGLYPH-13FCA;Lo;0;L;;;;;N;;;;;\n13FCB;EGYPTIAN HIEROGLYPH-13FCB;Lo;0;L;;;;;N;;;;;\n13FCC;EGYPTIAN HIEROGLYPH-13FCC;Lo;0;L;;;;;N;;;;;\n13FCD;EGYPTIAN HIEROGLYPH-13FCD;Lo;0;L;;;;;N;;;;;\n13FCE;EGYPTIAN HIEROGLYPH-13FCE;Lo;0;L;;;;;N;;;;;\n13FCF;EGYPTIAN HIEROGLYPH-13FCF;Lo;0;L;;;;;N;;;;;\n13FD0;EGYPTIAN HIEROGLYPH-13FD0;Lo;0;L;;;;;N;;;;;\n13FD1;EGYPTIAN HIEROGLYPH-13FD1;Lo;0;L;;;;;N;;;;;\n13FD2;EGYPTIAN HIEROGLYPH-13FD2;Lo;0;L;;;;;N;;;;;\n13FD3;EGYPTIAN HIEROGLYPH-13FD3;Lo;0;L;;;;;N;;;;;\n13FD4;EGYPTIAN HIEROGLYPH-13FD4;Lo;0;L;;;;;N;;;;;\n13FD5;EGYPTIAN HIEROGLYPH-13FD5;Lo;0;L;;;;;N;;;;;\n13FD6;EGYPTIAN HIEROGLYPH-13FD6;Lo;0;L;;;;;N;;;;;\n13FD7;EGYPTIAN HIEROGLYPH-13FD7;Lo;0;L;;;;;N;;;;;\n13FD8;EGYPTIAN HIEROGLYPH-13FD8;Lo;0;L;;;;;N;;;;;\n13FD9;EGYPTIAN HIEROGLYPH-13FD9;Lo;0;L;;;;;N;;;;;\n13FDA;EGYPTIAN HIEROGLYPH-13FDA;Lo;0;L;;;;;N;;;;;\n13FDB;EGYPTIAN HIEROGLYPH-13FDB;Lo;0;L;;;;;N;;;;;\n13FDC;EGYPTIAN HIEROGLYPH-13FDC;Lo;0;L;;;;;N;;;;;\n13FDD;EGYPTIAN HIEROGLYPH-13FDD;Lo;0;L;;;;;N;;;;;\n13FDE;EGYPTIAN HIEROGLYPH-13FDE;Lo;0;L;;;;;N;;;;;\n13FDF;EGYPTIAN HIEROGLYPH-13FDF;Lo;0;L;;;;;N;;;;;\n13FE0;EGYPTIAN HIEROGLYPH-13FE0;Lo;0;L;;;;;N;;;;;\n13FE1;EGYPTIAN HIEROGLYPH-13FE1;Lo;0;L;;;;;N;;;;;\n13FE2;EGYPTIAN HIEROGLYPH-13FE2;Lo;0;L;;;;;N;;;;;\n13FE3;EGYPTIAN HIEROGLYPH-13FE3;Lo;0;L;;;;;N;;;;;\n13FE4;EGYPTIAN HIEROGLYPH-13FE4;Lo;0;L;;;;;N;;;;;\n13FE5;EGYPTIAN HIEROGLYPH-13FE5;Lo;0;L;;;;;N;;;;;\n13FE6;EGYPTIAN HIEROGLYPH-13FE6;Lo;0;L;;;;;N;;;;;\n13FE7;EGYPTIAN HIEROGLYPH-13FE7;Lo;0;L;;;;;N;;;;;\n13FE8;EGYPTIAN HIEROGLYPH-13FE8;Lo;0;L;;;;;N;;;;;\n13FE9;EGYPTIAN HIEROGLYPH-13FE9;Lo;0;L;;;;;N;;;;;\n13FEA;EGYPTIAN HIEROGLYPH-13FEA;Lo;0;L;;;;;N;;;;;\n13FEB;EGYPTIAN HIEROGLYPH-13FEB;Lo;0;L;;;;;N;;;;;\n13FEC;EGYPTIAN HIEROGLYPH-13FEC;Lo;0;L;;;;;N;;;;;\n13FED;EGYPTIAN HIEROGLYPH-13FED;Lo;0;L;;;;;N;;;;;\n13FEE;EGYPTIAN HIEROGLYPH-13FEE;Lo;0;L;;;;;N;;;;;\n13FEF;EGYPTIAN HIEROGLYPH-13FEF;Lo;0;L;;;;;N;;;;;\n13FF0;EGYPTIAN HIEROGLYPH-13FF0;Lo;0;L;;;;;N;;;;;\n13FF1;EGYPTIAN HIEROGLYPH-13FF1;Lo;0;L;;;;;N;;;;;\n13FF2;EGYPTIAN HIEROGLYPH-13FF2;Lo;0;L;;;;;N;;;;;\n13FF3;EGYPTIAN HIEROGLYPH-13FF3;Lo;0;L;;;;;N;;;;;\n13FF4;EGYPTIAN HIEROGLYPH-13FF4;Lo;0;L;;;;;N;;;;;\n13FF5;EGYPTIAN HIEROGLYPH-13FF5;Lo;0;L;;;;;N;;;;;\n13FF6;EGYPTIAN HIEROGLYPH-13FF6;Lo;0;L;;;;;N;;;;;\n13FF7;EGYPTIAN HIEROGLYPH-13FF7;Lo;0;L;;;;;N;;;;;\n13FF8;EGYPTIAN HIEROGLYPH-13FF8;Lo;0;L;;;;;N;;;;;\n13FF9;EGYPTIAN HIEROGLYPH-13FF9;Lo;0;L;;;;;N;;;;;\n13FFA;EGYPTIAN HIEROGLYPH-13FFA;Lo;0;L;;;;;N;;;;;\n13FFB;EGYPTIAN HIEROGLYPH-13FFB;Lo;0;L;;;;;N;;;;;\n13FFC;EGYPTIAN HIEROGLYPH-13FFC;Lo;0;L;;;;;N;;;;;\n13FFD;EGYPTIAN HIEROGLYPH-13FFD;Lo;0;L;;;;;N;;;;;\n13FFE;EGYPTIAN HIEROGLYPH-13FFE;Lo;0;L;;;;;N;;;;;\n13FFF;EGYPTIAN HIEROGLYPH-13FFF;Lo;0;L;;;;;N;;;;;\n14000;EGYPTIAN HIEROGLYPH-14000;Lo;0;L;;;;;N;;;;;\n14001;EGYPTIAN HIEROGLYPH-14001;Lo;0;L;;;;;N;;;;;\n14002;EGYPTIAN HIEROGLYPH-14002;Lo;0;L;;;;;N;;;;;\n14003;EGYPTIAN HIEROGLYPH-14003;Lo;0;L;;;;;N;;;;;\n14004;EGYPTIAN HIEROGLYPH-14004;Lo;0;L;;;;;N;;;;;\n14005;EGYPTIAN HIEROGLYPH-14005;Lo;0;L;;;;;N;;;;;\n14006;EGYPTIAN HIEROGLYPH-14006;Lo;0;L;;;;;N;;;;;\n14007;EGYPTIAN HIEROGLYPH-14007;Lo;0;L;;;;;N;;;;;\n14008;EGYPTIAN HIEROGLYPH-14008;Lo;0;L;;;;;N;;;;;\n14009;EGYPTIAN HIEROGLYPH-14009;Lo;0;L;;;;;N;;;;;\n1400A;EGYPTIAN HIEROGLYPH-1400A;Lo;0;L;;;;;N;;;;;\n1400B;EGYPTIAN HIEROGLYPH-1400B;Lo;0;L;;;;;N;;;;;\n1400C;EGYPTIAN HIEROGLYPH-1400C;Lo;0;L;;;;;N;;;;;\n1400D;EGYPTIAN HIEROGLYPH-1400D;Lo;0;L;;;;;N;;;;;\n1400E;EGYPTIAN HIEROGLYPH-1400E;Lo;0;L;;;;;N;;;;;\n1400F;EGYPTIAN HIEROGLYPH-1400F;Lo;0;L;;;;;N;;;;;\n14010;EGYPTIAN HIEROGLYPH-14010;Lo;0;L;;;;;N;;;;;\n14011;EGYPTIAN HIEROGLYPH-14011;Lo;0;L;;;;;N;;;;;\n14012;EGYPTIAN HIEROGLYPH-14012;Lo;0;L;;;;;N;;;;;\n14013;EGYPTIAN HIEROGLYPH-14013;Lo;0;L;;;;;N;;;;;\n14014;EGYPTIAN HIEROGLYPH-14014;Lo;0;L;;;;;N;;;;;\n14015;EGYPTIAN HIEROGLYPH-14015;Lo;0;L;;;;;N;;;;;\n14016;EGYPTIAN HIEROGLYPH-14016;Lo;0;L;;;;;N;;;;;\n14017;EGYPTIAN HIEROGLYPH-14017;Lo;0;L;;;;;N;;;;;\n14018;EGYPTIAN HIEROGLYPH-14018;Lo;0;L;;;;;N;;;;;\n14019;EGYPTIAN HIEROGLYPH-14019;Lo;0;L;;;;;N;;;;;\n1401A;EGYPTIAN HIEROGLYPH-1401A;Lo;0;L;;;;;N;;;;;\n1401B;EGYPTIAN HIEROGLYPH-1401B;Lo;0;L;;;;;N;;;;;\n1401C;EGYPTIAN HIEROGLYPH-1401C;Lo;0;L;;;;;N;;;;;\n1401D;EGYPTIAN HIEROGLYPH-1401D;Lo;0;L;;;;;N;;;;;\n1401E;EGYPTIAN HIEROGLYPH-1401E;Lo;0;L;;;;;N;;;;;\n1401F;EGYPTIAN HIEROGLYPH-1401F;Lo;0;L;;;;;N;;;;;\n14020;EGYPTIAN HIEROGLYPH-14020;Lo;0;L;;;;;N;;;;;\n14021;EGYPTIAN HIEROGLYPH-14021;Lo;0;L;;;;;N;;;;;\n14022;EGYPTIAN HIEROGLYPH-14022;Lo;0;L;;;;;N;;;;;\n14023;EGYPTIAN HIEROGLYPH-14023;Lo;0;L;;;;;N;;;;;\n14024;EGYPTIAN HIEROGLYPH-14024;Lo;0;L;;;;;N;;;;;\n14025;EGYPTIAN HIEROGLYPH-14025;Lo;0;L;;;;;N;;;;;\n14026;EGYPTIAN HIEROGLYPH-14026;Lo;0;L;;;;;N;;;;;\n14027;EGYPTIAN HIEROGLYPH-14027;Lo;0;L;;;;;N;;;;;\n14028;EGYPTIAN HIEROGLYPH-14028;Lo;0;L;;;;;N;;;;;\n14029;EGYPTIAN HIEROGLYPH-14029;Lo;0;L;;;;;N;;;;;\n1402A;EGYPTIAN HIEROGLYPH-1402A;Lo;0;L;;;;;N;;;;;\n1402B;EGYPTIAN HIEROGLYPH-1402B;Lo;0;L;;;;;N;;;;;\n1402C;EGYPTIAN HIEROGLYPH-1402C;Lo;0;L;;;;;N;;;;;\n1402D;EGYPTIAN HIEROGLYPH-1402D;Lo;0;L;;;;;N;;;;;\n1402E;EGYPTIAN HIEROGLYPH-1402E;Lo;0;L;;;;;N;;;;;\n1402F;EGYPTIAN HIEROGLYPH-1402F;Lo;0;L;;;;;N;;;;;\n14030;EGYPTIAN HIEROGLYPH-14030;Lo;0;L;;;;;N;;;;;\n14031;EGYPTIAN HIEROGLYPH-14031;Lo;0;L;;;;;N;;;;;\n14032;EGYPTIAN HIEROGLYPH-14032;Lo;0;L;;;;;N;;;;;\n14033;EGYPTIAN HIEROGLYPH-14033;Lo;0;L;;;;;N;;;;;\n14034;EGYPTIAN HIEROGLYPH-14034;Lo;0;L;;;;;N;;;;;\n14035;EGYPTIAN HIEROGLYPH-14035;Lo;0;L;;;;;N;;;;;\n14036;EGYPTIAN HIEROGLYPH-14036;Lo;0;L;;;;;N;;;;;\n14037;EGYPTIAN HIEROGLYPH-14037;Lo;0;L;;;;;N;;;;;\n14038;EGYPTIAN HIEROGLYPH-14038;Lo;0;L;;;;;N;;;;;\n14039;EGYPTIAN HIEROGLYPH-14039;Lo;0;L;;;;;N;;;;;\n1403A;EGYPTIAN HIEROGLYPH-1403A;Lo;0;L;;;;;N;;;;;\n1403B;EGYPTIAN HIEROGLYPH-1403B;Lo;0;L;;;;;N;;;;;\n1403C;EGYPTIAN HIEROGLYPH-1403C;Lo;0;L;;;;;N;;;;;\n1403D;EGYPTIAN HIEROGLYPH-1403D;Lo;0;L;;;;;N;;;;;\n1403E;EGYPTIAN HIEROGLYPH-1403E;Lo;0;L;;;;;N;;;;;\n1403F;EGYPTIAN HIEROGLYPH-1403F;Lo;0;L;;;;;N;;;;;\n14040;EGYPTIAN HIEROGLYPH-14040;Lo;0;L;;;;;N;;;;;\n14041;EGYPTIAN HIEROGLYPH-14041;Lo;0;L;;;;;N;;;;;\n14042;EGYPTIAN HIEROGLYPH-14042;Lo;0;L;;;;;N;;;;;\n14043;EGYPTIAN HIEROGLYPH-14043;Lo;0;L;;;;;N;;;;;\n14044;EGYPTIAN HIEROGLYPH-14044;Lo;0;L;;;;;N;;;;;\n14045;EGYPTIAN HIEROGLYPH-14045;Lo;0;L;;;;;N;;;;;\n14046;EGYPTIAN HIEROGLYPH-14046;Lo;0;L;;;;;N;;;;;\n14047;EGYPTIAN HIEROGLYPH-14047;Lo;0;L;;;;;N;;;;;\n14048;EGYPTIAN HIEROGLYPH-14048;Lo;0;L;;;;;N;;;;;\n14049;EGYPTIAN HIEROGLYPH-14049;Lo;0;L;;;;;N;;;;;\n1404A;EGYPTIAN HIEROGLYPH-1404A;Lo;0;L;;;;;N;;;;;\n1404B;EGYPTIAN HIEROGLYPH-1404B;Lo;0;L;;;;;N;;;;;\n1404C;EGYPTIAN HIEROGLYPH-1404C;Lo;0;L;;;;;N;;;;;\n1404D;EGYPTIAN HIEROGLYPH-1404D;Lo;0;L;;;;;N;;;;;\n1404E;EGYPTIAN HIEROGLYPH-1404E;Lo;0;L;;;;;N;;;;;\n1404F;EGYPTIAN HIEROGLYPH-1404F;Lo;0;L;;;;;N;;;;;\n14050;EGYPTIAN HIEROGLYPH-14050;Lo;0;L;;;;;N;;;;;\n14051;EGYPTIAN HIEROGLYPH-14051;Lo;0;L;;;;;N;;;;;\n14052;EGYPTIAN HIEROGLYPH-14052;Lo;0;L;;;;;N;;;;;\n14053;EGYPTIAN HIEROGLYPH-14053;Lo;0;L;;;;;N;;;;;\n14054;EGYPTIAN HIEROGLYPH-14054;Lo;0;L;;;;;N;;;;;\n14055;EGYPTIAN HIEROGLYPH-14055;Lo;0;L;;;;;N;;;;;\n14056;EGYPTIAN HIEROGLYPH-14056;Lo;0;L;;;;;N;;;;;\n14057;EGYPTIAN HIEROGLYPH-14057;Lo;0;L;;;;;N;;;;;\n14058;EGYPTIAN HIEROGLYPH-14058;Lo;0;L;;;;;N;;;;;\n14059;EGYPTIAN HIEROGLYPH-14059;Lo;0;L;;;;;N;;;;;\n1405A;EGYPTIAN HIEROGLYPH-1405A;Lo;0;L;;;;;N;;;;;\n1405B;EGYPTIAN HIEROGLYPH-1405B;Lo;0;L;;;;;N;;;;;\n1405C;EGYPTIAN HIEROGLYPH-1405C;Lo;0;L;;;;;N;;;;;\n1405D;EGYPTIAN HIEROGLYPH-1405D;Lo;0;L;;;;;N;;;;;\n1405E;EGYPTIAN HIEROGLYPH-1405E;Lo;0;L;;;;;N;;;;;\n1405F;EGYPTIAN HIEROGLYPH-1405F;Lo;0;L;;;;;N;;;;;\n14060;EGYPTIAN HIEROGLYPH-14060;Lo;0;L;;;;;N;;;;;\n14061;EGYPTIAN HIEROGLYPH-14061;Lo;0;L;;;;;N;;;;;\n14062;EGYPTIAN HIEROGLYPH-14062;Lo;0;L;;;;;N;;;;;\n14063;EGYPTIAN HIEROGLYPH-14063;Lo;0;L;;;;;N;;;;;\n14064;EGYPTIAN HIEROGLYPH-14064;Lo;0;L;;;;;N;;;;;\n14065;EGYPTIAN HIEROGLYPH-14065;Lo;0;L;;;;;N;;;;;\n14066;EGYPTIAN HIEROGLYPH-14066;Lo;0;L;;;;;N;;;;;\n14067;EGYPTIAN HIEROGLYPH-14067;Lo;0;L;;;;;N;;;;;\n14068;EGYPTIAN HIEROGLYPH-14068;Lo;0;L;;;;;N;;;;;\n14069;EGYPTIAN HIEROGLYPH-14069;Lo;0;L;;;;;N;;;;;\n1406A;EGYPTIAN HIEROGLYPH-1406A;Lo;0;L;;;;;N;;;;;\n1406B;EGYPTIAN HIEROGLYPH-1406B;Lo;0;L;;;;;N;;;;;\n1406C;EGYPTIAN HIEROGLYPH-1406C;Lo;0;L;;;;;N;;;;;\n1406D;EGYPTIAN HIEROGLYPH-1406D;Lo;0;L;;;;;N;;;;;\n1406E;EGYPTIAN HIEROGLYPH-1406E;Lo;0;L;;;;;N;;;;;\n1406F;EGYPTIAN HIEROGLYPH-1406F;Lo;0;L;;;;;N;;;;;\n14070;EGYPTIAN HIEROGLYPH-14070;Lo;0;L;;;;;N;;;;;\n14071;EGYPTIAN HIEROGLYPH-14071;Lo;0;L;;;;;N;;;;;\n14072;EGYPTIAN HIEROGLYPH-14072;Lo;0;L;;;;;N;;;;;\n14073;EGYPTIAN HIEROGLYPH-14073;Lo;0;L;;;;;N;;;;;\n14074;EGYPTIAN HIEROGLYPH-14074;Lo;0;L;;;;;N;;;;;\n14075;EGYPTIAN HIEROGLYPH-14075;Lo;0;L;;;;;N;;;;;\n14076;EGYPTIAN HIEROGLYPH-14076;Lo;0;L;;;;;N;;;;;\n14077;EGYPTIAN HIEROGLYPH-14077;Lo;0;L;;;;;N;;;;;\n14078;EGYPTIAN HIEROGLYPH-14078;Lo;0;L;;;;;N;;;;;\n14079;EGYPTIAN HIEROGLYPH-14079;Lo;0;L;;;;;N;;;;;\n1407A;EGYPTIAN HIEROGLYPH-1407A;Lo;0;L;;;;;N;;;;;\n1407B;EGYPTIAN HIEROGLYPH-1407B;Lo;0;L;;;;;N;;;;;\n1407C;EGYPTIAN HIEROGLYPH-1407C;Lo;0;L;;;;;N;;;;;\n1407D;EGYPTIAN HIEROGLYPH-1407D;Lo;0;L;;;;;N;;;;;\n1407E;EGYPTIAN HIEROGLYPH-1407E;Lo;0;L;;;;;N;;;;;\n1407F;EGYPTIAN HIEROGLYPH-1407F;Lo;0;L;;;;;N;;;;;\n14080;EGYPTIAN HIEROGLYPH-14080;Lo;0;L;;;;;N;;;;;\n14081;EGYPTIAN HIEROGLYPH-14081;Lo;0;L;;;;;N;;;;;\n14082;EGYPTIAN HIEROGLYPH-14082;Lo;0;L;;;;;N;;;;;\n14083;EGYPTIAN HIEROGLYPH-14083;Lo;0;L;;;;;N;;;;;\n14084;EGYPTIAN HIEROGLYPH-14084;Lo;0;L;;;;;N;;;;;\n14085;EGYPTIAN HIEROGLYPH-14085;Lo;0;L;;;;;N;;;;;\n14086;EGYPTIAN HIEROGLYPH-14086;Lo;0;L;;;;;N;;;;;\n14087;EGYPTIAN HIEROGLYPH-14087;Lo;0;L;;;;;N;;;;;\n14088;EGYPTIAN HIEROGLYPH-14088;Lo;0;L;;;;;N;;;;;\n14089;EGYPTIAN HIEROGLYPH-14089;Lo;0;L;;;;;N;;;;;\n1408A;EGYPTIAN HIEROGLYPH-1408A;Lo;0;L;;;;;N;;;;;\n1408B;EGYPTIAN HIEROGLYPH-1408B;Lo;0;L;;;;;N;;;;;\n1408C;EGYPTIAN HIEROGLYPH-1408C;Lo;0;L;;;;;N;;;;;\n1408D;EGYPTIAN HIEROGLYPH-1408D;Lo;0;L;;;;;N;;;;;\n1408E;EGYPTIAN HIEROGLYPH-1408E;Lo;0;L;;;;;N;;;;;\n1408F;EGYPTIAN HIEROGLYPH-1408F;Lo;0;L;;;;;N;;;;;\n14090;EGYPTIAN HIEROGLYPH-14090;Lo;0;L;;;;;N;;;;;\n14091;EGYPTIAN HIEROGLYPH-14091;Lo;0;L;;;;;N;;;;;\n14092;EGYPTIAN HIEROGLYPH-14092;Lo;0;L;;;;;N;;;;;\n14093;EGYPTIAN HIEROGLYPH-14093;Lo;0;L;;;;;N;;;;;\n14094;EGYPTIAN HIEROGLYPH-14094;Lo;0;L;;;;;N;;;;;\n14095;EGYPTIAN HIEROGLYPH-14095;Lo;0;L;;;;;N;;;;;\n14096;EGYPTIAN HIEROGLYPH-14096;Lo;0;L;;;;;N;;;;;\n14097;EGYPTIAN HIEROGLYPH-14097;Lo;0;L;;;;;N;;;;;\n14098;EGYPTIAN HIEROGLYPH-14098;Lo;0;L;;;;;N;;;;;\n14099;EGYPTIAN HIEROGLYPH-14099;Lo;0;L;;;;;N;;;;;\n1409A;EGYPTIAN HIEROGLYPH-1409A;Lo;0;L;;;;;N;;;;;\n1409B;EGYPTIAN HIEROGLYPH-1409B;Lo;0;L;;;;;N;;;;;\n1409C;EGYPTIAN HIEROGLYPH-1409C;Lo;0;L;;;;;N;;;;;\n1409D;EGYPTIAN HIEROGLYPH-1409D;Lo;0;L;;;;;N;;;;;\n1409E;EGYPTIAN HIEROGLYPH-1409E;Lo;0;L;;;;;N;;;;;\n1409F;EGYPTIAN HIEROGLYPH-1409F;Lo;0;L;;;;;N;;;;;\n140A0;EGYPTIAN HIEROGLYPH-140A0;Lo;0;L;;;;;N;;;;;\n140A1;EGYPTIAN HIEROGLYPH-140A1;Lo;0;L;;;;;N;;;;;\n140A2;EGYPTIAN HIEROGLYPH-140A2;Lo;0;L;;;;;N;;;;;\n140A3;EGYPTIAN HIEROGLYPH-140A3;Lo;0;L;;;;;N;;;;;\n140A4;EGYPTIAN HIEROGLYPH-140A4;Lo;0;L;;;;;N;;;;;\n140A5;EGYPTIAN HIEROGLYPH-140A5;Lo;0;L;;;;;N;;;;;\n140A6;EGYPTIAN HIEROGLYPH-140A6;Lo;0;L;;;;;N;;;;;\n140A7;EGYPTIAN HIEROGLYPH-140A7;Lo;0;L;;;;;N;;;;;\n140A8;EGYPTIAN HIEROGLYPH-140A8;Lo;0;L;;;;;N;;;;;\n140A9;EGYPTIAN HIEROGLYPH-140A9;Lo;0;L;;;;;N;;;;;\n140AA;EGYPTIAN HIEROGLYPH-140AA;Lo;0;L;;;;;N;;;;;\n140AB;EGYPTIAN HIEROGLYPH-140AB;Lo;0;L;;;;;N;;;;;\n140AC;EGYPTIAN HIEROGLYPH-140AC;Lo;0;L;;;;;N;;;;;\n140AD;EGYPTIAN HIEROGLYPH-140AD;Lo;0;L;;;;;N;;;;;\n140AE;EGYPTIAN HIEROGLYPH-140AE;Lo;0;L;;;;;N;;;;;\n140AF;EGYPTIAN HIEROGLYPH-140AF;Lo;0;L;;;;;N;;;;;\n140B0;EGYPTIAN HIEROGLYPH-140B0;Lo;0;L;;;;;N;;;;;\n140B1;EGYPTIAN HIEROGLYPH-140B1;Lo;0;L;;;;;N;;;;;\n140B2;EGYPTIAN HIEROGLYPH-140B2;Lo;0;L;;;;;N;;;;;\n140B3;EGYPTIAN HIEROGLYPH-140B3;Lo;0;L;;;;;N;;;;;\n140B4;EGYPTIAN HIEROGLYPH-140B4;Lo;0;L;;;;;N;;;;;\n140B5;EGYPTIAN HIEROGLYPH-140B5;Lo;0;L;;;;;N;;;;;\n140B6;EGYPTIAN HIEROGLYPH-140B6;Lo;0;L;;;;;N;;;;;\n140B7;EGYPTIAN HIEROGLYPH-140B7;Lo;0;L;;;;;N;;;;;\n140B8;EGYPTIAN HIEROGLYPH-140B8;Lo;0;L;;;;;N;;;;;\n140B9;EGYPTIAN HIEROGLYPH-140B9;Lo;0;L;;;;;N;;;;;\n140BA;EGYPTIAN HIEROGLYPH-140BA;Lo;0;L;;;;;N;;;;;\n140BB;EGYPTIAN HIEROGLYPH-140BB;Lo;0;L;;;;;N;;;;;\n140BC;EGYPTIAN HIEROGLYPH-140BC;Lo;0;L;;;;;N;;;;;\n140BD;EGYPTIAN HIEROGLYPH-140BD;Lo;0;L;;;;;N;;;;;\n140BE;EGYPTIAN HIEROGLYPH-140BE;Lo;0;L;;;;;N;;;;;\n140BF;EGYPTIAN HIEROGLYPH-140BF;Lo;0;L;;;;;N;;;;;\n140C0;EGYPTIAN HIEROGLYPH-140C0;Lo;0;L;;;;;N;;;;;\n140C1;EGYPTIAN HIEROGLYPH-140C1;Lo;0;L;;;;;N;;;;;\n140C2;EGYPTIAN HIEROGLYPH-140C2;Lo;0;L;;;;;N;;;;;\n140C3;EGYPTIAN HIEROGLYPH-140C3;Lo;0;L;;;;;N;;;;;\n140C4;EGYPTIAN HIEROGLYPH-140C4;Lo;0;L;;;;;N;;;;;\n140C5;EGYPTIAN HIEROGLYPH-140C5;Lo;0;L;;;;;N;;;;;\n140C6;EGYPTIAN HIEROGLYPH-140C6;Lo;0;L;;;;;N;;;;;\n140C7;EGYPTIAN HIEROGLYPH-140C7;Lo;0;L;;;;;N;;;;;\n140C8;EGYPTIAN HIEROGLYPH-140C8;Lo;0;L;;;;;N;;;;;\n140C9;EGYPTIAN HIEROGLYPH-140C9;Lo;0;L;;;;;N;;;;;\n140CA;EGYPTIAN HIEROGLYPH-140CA;Lo;0;L;;;;;N;;;;;\n140CB;EGYPTIAN HIEROGLYPH-140CB;Lo;0;L;;;;;N;;;;;\n140CC;EGYPTIAN HIEROGLYPH-140CC;Lo;0;L;;;;;N;;;;;\n140CD;EGYPTIAN HIEROGLYPH-140CD;Lo;0;L;;;;;N;;;;;\n140CE;EGYPTIAN HIEROGLYPH-140CE;Lo;0;L;;;;;N;;;;;\n140CF;EGYPTIAN HIEROGLYPH-140CF;Lo;0;L;;;;;N;;;;;\n140D0;EGYPTIAN HIEROGLYPH-140D0;Lo;0;L;;;;;N;;;;;\n140D1;EGYPTIAN HIEROGLYPH-140D1;Lo;0;L;;;;;N;;;;;\n140D2;EGYPTIAN HIEROGLYPH-140D2;Lo;0;L;;;;;N;;;;;\n140D3;EGYPTIAN HIEROGLYPH-140D3;Lo;0;L;;;;;N;;;;;\n140D4;EGYPTIAN HIEROGLYPH-140D4;Lo;0;L;;;;;N;;;;;\n140D5;EGYPTIAN HIEROGLYPH-140D5;Lo;0;L;;;;;N;;;;;\n140D6;EGYPTIAN HIEROGLYPH-140D6;Lo;0;L;;;;;N;;;;;\n140D7;EGYPTIAN HIEROGLYPH-140D7;Lo;0;L;;;;;N;;;;;\n140D8;EGYPTIAN HIEROGLYPH-140D8;Lo;0;L;;;;;N;;;;;\n140D9;EGYPTIAN HIEROGLYPH-140D9;Lo;0;L;;;;;N;;;;;\n140DA;EGYPTIAN HIEROGLYPH-140DA;Lo;0;L;;;;;N;;;;;\n140DB;EGYPTIAN HIEROGLYPH-140DB;Lo;0;L;;;;;N;;;;;\n140DC;EGYPTIAN HIEROGLYPH-140DC;Lo;0;L;;;;;N;;;;;\n140DD;EGYPTIAN HIEROGLYPH-140DD;Lo;0;L;;;;;N;;;;;\n140DE;EGYPTIAN HIEROGLYPH-140DE;Lo;0;L;;;;;N;;;;;\n140DF;EGYPTIAN HIEROGLYPH-140DF;Lo;0;L;;;;;N;;;;;\n140E0;EGYPTIAN HIEROGLYPH-140E0;Lo;0;L;;;;;N;;;;;\n140E1;EGYPTIAN HIEROGLYPH-140E1;Lo;0;L;;;;;N;;;;;\n140E2;EGYPTIAN HIEROGLYPH-140E2;Lo;0;L;;;;;N;;;;;\n140E3;EGYPTIAN HIEROGLYPH-140E3;Lo;0;L;;;;;N;;;;;\n140E4;EGYPTIAN HIEROGLYPH-140E4;Lo;0;L;;;;;N;;;;;\n140E5;EGYPTIAN HIEROGLYPH-140E5;Lo;0;L;;;;;N;;;;;\n140E6;EGYPTIAN HIEROGLYPH-140E6;Lo;0;L;;;;;N;;;;;\n140E7;EGYPTIAN HIEROGLYPH-140E7;Lo;0;L;;;;;N;;;;;\n140E8;EGYPTIAN HIEROGLYPH-140E8;Lo;0;L;;;;;N;;;;;\n140E9;EGYPTIAN HIEROGLYPH-140E9;Lo;0;L;;;;;N;;;;;\n140EA;EGYPTIAN HIEROGLYPH-140EA;Lo;0;L;;;;;N;;;;;\n140EB;EGYPTIAN HIEROGLYPH-140EB;Lo;0;L;;;;;N;;;;;\n140EC;EGYPTIAN HIEROGLYPH-140EC;Lo;0;L;;;;;N;;;;;\n140ED;EGYPTIAN HIEROGLYPH-140ED;Lo;0;L;;;;;N;;;;;\n140EE;EGYPTIAN HIEROGLYPH-140EE;Lo;0;L;;;;;N;;;;;\n140EF;EGYPTIAN HIEROGLYPH-140EF;Lo;0;L;;;;;N;;;;;\n140F0;EGYPTIAN HIEROGLYPH-140F0;Lo;0;L;;;;;N;;;;;\n140F1;EGYPTIAN HIEROGLYPH-140F1;Lo;0;L;;;;;N;;;;;\n140F2;EGYPTIAN HIEROGLYPH-140F2;Lo;0;L;;;;;N;;;;;\n140F3;EGYPTIAN HIEROGLYPH-140F3;Lo;0;L;;;;;N;;;;;\n140F4;EGYPTIAN HIEROGLYPH-140F4;Lo;0;L;;;;;N;;;;;\n140F5;EGYPTIAN HIEROGLYPH-140F5;Lo;0;L;;;;;N;;;;;\n140F6;EGYPTIAN HIEROGLYPH-140F6;Lo;0;L;;;;;N;;;;;\n140F7;EGYPTIAN HIEROGLYPH-140F7;Lo;0;L;;;;;N;;;;;\n140F8;EGYPTIAN HIEROGLYPH-140F8;Lo;0;L;;;;;N;;;;;\n140F9;EGYPTIAN HIEROGLYPH-140F9;Lo;0;L;;;;;N;;;;;\n140FA;EGYPTIAN HIEROGLYPH-140FA;Lo;0;L;;;;;N;;;;;\n140FB;EGYPTIAN HIEROGLYPH-140FB;Lo;0;L;;;;;N;;;;;\n140FC;EGYPTIAN HIEROGLYPH-140FC;Lo;0;L;;;;;N;;;;;\n140FD;EGYPTIAN HIEROGLYPH-140FD;Lo;0;L;;;;;N;;;;;\n140FE;EGYPTIAN HIEROGLYPH-140FE;Lo;0;L;;;;;N;;;;;\n140FF;EGYPTIAN HIEROGLYPH-140FF;Lo;0;L;;;;;N;;;;;\n14100;EGYPTIAN HIEROGLYPH-14100;Lo;0;L;;;;;N;;;;;\n14101;EGYPTIAN HIEROGLYPH-14101;Lo;0;L;;;;;N;;;;;\n14102;EGYPTIAN HIEROGLYPH-14102;Lo;0;L;;;;;N;;;;;\n14103;EGYPTIAN HIEROGLYPH-14103;Lo;0;L;;;;;N;;;;;\n14104;EGYPTIAN HIEROGLYPH-14104;Lo;0;L;;;;;N;;;;;\n14105;EGYPTIAN HIEROGLYPH-14105;Lo;0;L;;;;;N;;;;;\n14106;EGYPTIAN HIEROGLYPH-14106;Lo;0;L;;;;;N;;;;;\n14107;EGYPTIAN HIEROGLYPH-14107;Lo;0;L;;;;;N;;;;;\n14108;EGYPTIAN HIEROGLYPH-14108;Lo;0;L;;;;;N;;;;;\n14109;EGYPTIAN HIEROGLYPH-14109;Lo;0;L;;;;;N;;;;;\n1410A;EGYPTIAN HIEROGLYPH-1410A;Lo;0;L;;;;;N;;;;;\n1410B;EGYPTIAN HIEROGLYPH-1410B;Lo;0;L;;;;;N;;;;;\n1410C;EGYPTIAN HIEROGLYPH-1410C;Lo;0;L;;;;;N;;;;;\n1410D;EGYPTIAN HIEROGLYPH-1410D;Lo;0;L;;;;;N;;;;;\n1410E;EGYPTIAN HIEROGLYPH-1410E;Lo;0;L;;;;;N;;;;;\n1410F;EGYPTIAN HIEROGLYPH-1410F;Lo;0;L;;;;;N;;;;;\n14110;EGYPTIAN HIEROGLYPH-14110;Lo;0;L;;;;;N;;;;;\n14111;EGYPTIAN HIEROGLYPH-14111;Lo;0;L;;;;;N;;;;;\n14112;EGYPTIAN HIEROGLYPH-14112;Lo;0;L;;;;;N;;;;;\n14113;EGYPTIAN HIEROGLYPH-14113;Lo;0;L;;;;;N;;;;;\n14114;EGYPTIAN HIEROGLYPH-14114;Lo;0;L;;;;;N;;;;;\n14115;EGYPTIAN HIEROGLYPH-14115;Lo;0;L;;;;;N;;;;;\n14116;EGYPTIAN HIEROGLYPH-14116;Lo;0;L;;;;;N;;;;;\n14117;EGYPTIAN HIEROGLYPH-14117;Lo;0;L;;;;;N;;;;;\n14118;EGYPTIAN HIEROGLYPH-14118;Lo;0;L;;;;;N;;;;;\n14119;EGYPTIAN HIEROGLYPH-14119;Lo;0;L;;;;;N;;;;;\n1411A;EGYPTIAN HIEROGLYPH-1411A;Lo;0;L;;;;;N;;;;;\n1411B;EGYPTIAN HIEROGLYPH-1411B;Lo;0;L;;;;;N;;;;;\n1411C;EGYPTIAN HIEROGLYPH-1411C;Lo;0;L;;;;;N;;;;;\n1411D;EGYPTIAN HIEROGLYPH-1411D;Lo;0;L;;;;;N;;;;;\n1411E;EGYPTIAN HIEROGLYPH-1411E;Lo;0;L;;;;;N;;;;;\n1411F;EGYPTIAN HIEROGLYPH-1411F;Lo;0;L;;;;;N;;;;;\n14120;EGYPTIAN HIEROGLYPH-14120;Lo;0;L;;;;;N;;;;;\n14121;EGYPTIAN HIEROGLYPH-14121;Lo;0;L;;;;;N;;;;;\n14122;EGYPTIAN HIEROGLYPH-14122;Lo;0;L;;;;;N;;;;;\n14123;EGYPTIAN HIEROGLYPH-14123;Lo;0;L;;;;;N;;;;;\n14124;EGYPTIAN HIEROGLYPH-14124;Lo;0;L;;;;;N;;;;;\n14125;EGYPTIAN HIEROGLYPH-14125;Lo;0;L;;;;;N;;;;;\n14126;EGYPTIAN HIEROGLYPH-14126;Lo;0;L;;;;;N;;;;;\n14127;EGYPTIAN HIEROGLYPH-14127;Lo;0;L;;;;;N;;;;;\n14128;EGYPTIAN HIEROGLYPH-14128;Lo;0;L;;;;;N;;;;;\n14129;EGYPTIAN HIEROGLYPH-14129;Lo;0;L;;;;;N;;;;;\n1412A;EGYPTIAN HIEROGLYPH-1412A;Lo;0;L;;;;;N;;;;;\n1412B;EGYPTIAN HIEROGLYPH-1412B;Lo;0;L;;;;;N;;;;;\n1412C;EGYPTIAN HIEROGLYPH-1412C;Lo;0;L;;;;;N;;;;;\n1412D;EGYPTIAN HIEROGLYPH-1412D;Lo;0;L;;;;;N;;;;;\n1412E;EGYPTIAN HIEROGLYPH-1412E;Lo;0;L;;;;;N;;;;;\n1412F;EGYPTIAN HIEROGLYPH-1412F;Lo;0;L;;;;;N;;;;;\n14130;EGYPTIAN HIEROGLYPH-14130;Lo;0;L;;;;;N;;;;;\n14131;EGYPTIAN HIEROGLYPH-14131;Lo;0;L;;;;;N;;;;;\n14132;EGYPTIAN HIEROGLYPH-14132;Lo;0;L;;;;;N;;;;;\n14133;EGYPTIAN HIEROGLYPH-14133;Lo;0;L;;;;;N;;;;;\n14134;EGYPTIAN HIEROGLYPH-14134;Lo;0;L;;;;;N;;;;;\n14135;EGYPTIAN HIEROGLYPH-14135;Lo;0;L;;;;;N;;;;;\n14136;EGYPTIAN HIEROGLYPH-14136;Lo;0;L;;;;;N;;;;;\n14137;EGYPTIAN HIEROGLYPH-14137;Lo;0;L;;;;;N;;;;;\n14138;EGYPTIAN HIEROGLYPH-14138;Lo;0;L;;;;;N;;;;;\n14139;EGYPTIAN HIEROGLYPH-14139;Lo;0;L;;;;;N;;;;;\n1413A;EGYPTIAN HIEROGLYPH-1413A;Lo;0;L;;;;;N;;;;;\n1413B;EGYPTIAN HIEROGLYPH-1413B;Lo;0;L;;;;;N;;;;;\n1413C;EGYPTIAN HIEROGLYPH-1413C;Lo;0;L;;;;;N;;;;;\n1413D;EGYPTIAN HIEROGLYPH-1413D;Lo;0;L;;;;;N;;;;;\n1413E;EGYPTIAN HIEROGLYPH-1413E;Lo;0;L;;;;;N;;;;;\n1413F;EGYPTIAN HIEROGLYPH-1413F;Lo;0;L;;;;;N;;;;;\n14140;EGYPTIAN HIEROGLYPH-14140;Lo;0;L;;;;;N;;;;;\n14141;EGYPTIAN HIEROGLYPH-14141;Lo;0;L;;;;;N;;;;;\n14142;EGYPTIAN HIEROGLYPH-14142;Lo;0;L;;;;;N;;;;;\n14143;EGYPTIAN HIEROGLYPH-14143;Lo;0;L;;;;;N;;;;;\n14144;EGYPTIAN HIEROGLYPH-14144;Lo;0;L;;;;;N;;;;;\n14145;EGYPTIAN HIEROGLYPH-14145;Lo;0;L;;;;;N;;;;;\n14146;EGYPTIAN HIEROGLYPH-14146;Lo;0;L;;;;;N;;;;;\n14147;EGYPTIAN HIEROGLYPH-14147;Lo;0;L;;;;;N;;;;;\n14148;EGYPTIAN HIEROGLYPH-14148;Lo;0;L;;;;;N;;;;;\n14149;EGYPTIAN HIEROGLYPH-14149;Lo;0;L;;;;;N;;;;;\n1414A;EGYPTIAN HIEROGLYPH-1414A;Lo;0;L;;;;;N;;;;;\n1414B;EGYPTIAN HIEROGLYPH-1414B;Lo;0;L;;;;;N;;;;;\n1414C;EGYPTIAN HIEROGLYPH-1414C;Lo;0;L;;;;;N;;;;;\n1414D;EGYPTIAN HIEROGLYPH-1414D;Lo;0;L;;;;;N;;;;;\n1414E;EGYPTIAN HIEROGLYPH-1414E;Lo;0;L;;;;;N;;;;;\n1414F;EGYPTIAN HIEROGLYPH-1414F;Lo;0;L;;;;;N;;;;;\n14150;EGYPTIAN HIEROGLYPH-14150;Lo;0;L;;;;;N;;;;;\n14151;EGYPTIAN HIEROGLYPH-14151;Lo;0;L;;;;;N;;;;;\n14152;EGYPTIAN HIEROGLYPH-14152;Lo;0;L;;;;;N;;;;;\n14153;EGYPTIAN HIEROGLYPH-14153;Lo;0;L;;;;;N;;;;;\n14154;EGYPTIAN HIEROGLYPH-14154;Lo;0;L;;;;;N;;;;;\n14155;EGYPTIAN HIEROGLYPH-14155;Lo;0;L;;;;;N;;;;;\n14156;EGYPTIAN HIEROGLYPH-14156;Lo;0;L;;;;;N;;;;;\n14157;EGYPTIAN HIEROGLYPH-14157;Lo;0;L;;;;;N;;;;;\n14158;EGYPTIAN HIEROGLYPH-14158;Lo;0;L;;;;;N;;;;;\n14159;EGYPTIAN HIEROGLYPH-14159;Lo;0;L;;;;;N;;;;;\n1415A;EGYPTIAN HIEROGLYPH-1415A;Lo;0;L;;;;;N;;;;;\n1415B;EGYPTIAN HIEROGLYPH-1415B;Lo;0;L;;;;;N;;;;;\n1415C;EGYPTIAN HIEROGLYPH-1415C;Lo;0;L;;;;;N;;;;;\n1415D;EGYPTIAN HIEROGLYPH-1415D;Lo;0;L;;;;;N;;;;;\n1415E;EGYPTIAN HIEROGLYPH-1415E;Lo;0;L;;;;;N;;;;;\n1415F;EGYPTIAN HIEROGLYPH-1415F;Lo;0;L;;;;;N;;;;;\n14160;EGYPTIAN HIEROGLYPH-14160;Lo;0;L;;;;;N;;;;;\n14161;EGYPTIAN HIEROGLYPH-14161;Lo;0;L;;;;;N;;;;;\n14162;EGYPTIAN HIEROGLYPH-14162;Lo;0;L;;;;;N;;;;;\n14163;EGYPTIAN HIEROGLYPH-14163;Lo;0;L;;;;;N;;;;;\n14164;EGYPTIAN HIEROGLYPH-14164;Lo;0;L;;;;;N;;;;;\n14165;EGYPTIAN HIEROGLYPH-14165;Lo;0;L;;;;;N;;;;;\n14166;EGYPTIAN HIEROGLYPH-14166;Lo;0;L;;;;;N;;;;;\n14167;EGYPTIAN HIEROGLYPH-14167;Lo;0;L;;;;;N;;;;;\n14168;EGYPTIAN HIEROGLYPH-14168;Lo;0;L;;;;;N;;;;;\n14169;EGYPTIAN HIEROGLYPH-14169;Lo;0;L;;;;;N;;;;;\n1416A;EGYPTIAN HIEROGLYPH-1416A;Lo;0;L;;;;;N;;;;;\n1416B;EGYPTIAN HIEROGLYPH-1416B;Lo;0;L;;;;;N;;;;;\n1416C;EGYPTIAN HIEROGLYPH-1416C;Lo;0;L;;;;;N;;;;;\n1416D;EGYPTIAN HIEROGLYPH-1416D;Lo;0;L;;;;;N;;;;;\n1416E;EGYPTIAN HIEROGLYPH-1416E;Lo;0;L;;;;;N;;;;;\n1416F;EGYPTIAN HIEROGLYPH-1416F;Lo;0;L;;;;;N;;;;;\n14170;EGYPTIAN HIEROGLYPH-14170;Lo;0;L;;;;;N;;;;;\n14171;EGYPTIAN HIEROGLYPH-14171;Lo;0;L;;;;;N;;;;;\n14172;EGYPTIAN HIEROGLYPH-14172;Lo;0;L;;;;;N;;;;;\n14173;EGYPTIAN HIEROGLYPH-14173;Lo;0;L;;;;;N;;;;;\n14174;EGYPTIAN HIEROGLYPH-14174;Lo;0;L;;;;;N;;;;;\n14175;EGYPTIAN HIEROGLYPH-14175;Lo;0;L;;;;;N;;;;;\n14176;EGYPTIAN HIEROGLYPH-14176;Lo;0;L;;;;;N;;;;;\n14177;EGYPTIAN HIEROGLYPH-14177;Lo;0;L;;;;;N;;;;;\n14178;EGYPTIAN HIEROGLYPH-14178;Lo;0;L;;;;;N;;;;;\n14179;EGYPTIAN HIEROGLYPH-14179;Lo;0;L;;;;;N;;;;;\n1417A;EGYPTIAN HIEROGLYPH-1417A;Lo;0;L;;;;;N;;;;;\n1417B;EGYPTIAN HIEROGLYPH-1417B;Lo;0;L;;;;;N;;;;;\n1417C;EGYPTIAN HIEROGLYPH-1417C;Lo;0;L;;;;;N;;;;;\n1417D;EGYPTIAN HIEROGLYPH-1417D;Lo;0;L;;;;;N;;;;;\n1417E;EGYPTIAN HIEROGLYPH-1417E;Lo;0;L;;;;;N;;;;;\n1417F;EGYPTIAN HIEROGLYPH-1417F;Lo;0;L;;;;;N;;;;;\n14180;EGYPTIAN HIEROGLYPH-14180;Lo;0;L;;;;;N;;;;;\n14181;EGYPTIAN HIEROGLYPH-14181;Lo;0;L;;;;;N;;;;;\n14182;EGYPTIAN HIEROGLYPH-14182;Lo;0;L;;;;;N;;;;;\n14183;EGYPTIAN HIEROGLYPH-14183;Lo;0;L;;;;;N;;;;;\n14184;EGYPTIAN HIEROGLYPH-14184;Lo;0;L;;;;;N;;;;;\n14185;EGYPTIAN HIEROGLYPH-14185;Lo;0;L;;;;;N;;;;;\n14186;EGYPTIAN HIEROGLYPH-14186;Lo;0;L;;;;;N;;;;;\n14187;EGYPTIAN HIEROGLYPH-14187;Lo;0;L;;;;;N;;;;;\n14188;EGYPTIAN HIEROGLYPH-14188;Lo;0;L;;;;;N;;;;;\n14189;EGYPTIAN HIEROGLYPH-14189;Lo;0;L;;;;;N;;;;;\n1418A;EGYPTIAN HIEROGLYPH-1418A;Lo;0;L;;;;;N;;;;;\n1418B;EGYPTIAN HIEROGLYPH-1418B;Lo;0;L;;;;;N;;;;;\n1418C;EGYPTIAN HIEROGLYPH-1418C;Lo;0;L;;;;;N;;;;;\n1418D;EGYPTIAN HIEROGLYPH-1418D;Lo;0;L;;;;;N;;;;;\n1418E;EGYPTIAN HIEROGLYPH-1418E;Lo;0;L;;;;;N;;;;;\n1418F;EGYPTIAN HIEROGLYPH-1418F;Lo;0;L;;;;;N;;;;;\n14190;EGYPTIAN HIEROGLYPH-14190;Lo;0;L;;;;;N;;;;;\n14191;EGYPTIAN HIEROGLYPH-14191;Lo;0;L;;;;;N;;;;;\n14192;EGYPTIAN HIEROGLYPH-14192;Lo;0;L;;;;;N;;;;;\n14193;EGYPTIAN HIEROGLYPH-14193;Lo;0;L;;;;;N;;;;;\n14194;EGYPTIAN HIEROGLYPH-14194;Lo;0;L;;;;;N;;;;;\n14195;EGYPTIAN HIEROGLYPH-14195;Lo;0;L;;;;;N;;;;;\n14196;EGYPTIAN HIEROGLYPH-14196;Lo;0;L;;;;;N;;;;;\n14197;EGYPTIAN HIEROGLYPH-14197;Lo;0;L;;;;;N;;;;;\n14198;EGYPTIAN HIEROGLYPH-14198;Lo;0;L;;;;;N;;;;;\n14199;EGYPTIAN HIEROGLYPH-14199;Lo;0;L;;;;;N;;;;;\n1419A;EGYPTIAN HIEROGLYPH-1419A;Lo;0;L;;;;;N;;;;;\n1419B;EGYPTIAN HIEROGLYPH-1419B;Lo;0;L;;;;;N;;;;;\n1419C;EGYPTIAN HIEROGLYPH-1419C;Lo;0;L;;;;;N;;;;;\n1419D;EGYPTIAN HIEROGLYPH-1419D;Lo;0;L;;;;;N;;;;;\n1419E;EGYPTIAN HIEROGLYPH-1419E;Lo;0;L;;;;;N;;;;;\n1419F;EGYPTIAN HIEROGLYPH-1419F;Lo;0;L;;;;;N;;;;;\n141A0;EGYPTIAN HIEROGLYPH-141A0;Lo;0;L;;;;;N;;;;;\n141A1;EGYPTIAN HIEROGLYPH-141A1;Lo;0;L;;;;;N;;;;;\n141A2;EGYPTIAN HIEROGLYPH-141A2;Lo;0;L;;;;;N;;;;;\n141A3;EGYPTIAN HIEROGLYPH-141A3;Lo;0;L;;;;;N;;;;;\n141A4;EGYPTIAN HIEROGLYPH-141A4;Lo;0;L;;;;;N;;;;;\n141A5;EGYPTIAN HIEROGLYPH-141A5;Lo;0;L;;;;;N;;;;;\n141A6;EGYPTIAN HIEROGLYPH-141A6;Lo;0;L;;;;;N;;;;;\n141A7;EGYPTIAN HIEROGLYPH-141A7;Lo;0;L;;;;;N;;;;;\n141A8;EGYPTIAN HIEROGLYPH-141A8;Lo;0;L;;;;;N;;;;;\n141A9;EGYPTIAN HIEROGLYPH-141A9;Lo;0;L;;;;;N;;;;;\n141AA;EGYPTIAN HIEROGLYPH-141AA;Lo;0;L;;;;;N;;;;;\n141AB;EGYPTIAN HIEROGLYPH-141AB;Lo;0;L;;;;;N;;;;;\n141AC;EGYPTIAN HIEROGLYPH-141AC;Lo;0;L;;;;;N;;;;;\n141AD;EGYPTIAN HIEROGLYPH-141AD;Lo;0;L;;;;;N;;;;;\n141AE;EGYPTIAN HIEROGLYPH-141AE;Lo;0;L;;;;;N;;;;;\n141AF;EGYPTIAN HIEROGLYPH-141AF;Lo;0;L;;;;;N;;;;;\n141B0;EGYPTIAN HIEROGLYPH-141B0;Lo;0;L;;;;;N;;;;;\n141B1;EGYPTIAN HIEROGLYPH-141B1;Lo;0;L;;;;;N;;;;;\n141B2;EGYPTIAN HIEROGLYPH-141B2;Lo;0;L;;;;;N;;;;;\n141B3;EGYPTIAN HIEROGLYPH-141B3;Lo;0;L;;;;;N;;;;;\n141B4;EGYPTIAN HIEROGLYPH-141B4;Lo;0;L;;;;;N;;;;;\n141B5;EGYPTIAN HIEROGLYPH-141B5;Lo;0;L;;;;;N;;;;;\n141B6;EGYPTIAN HIEROGLYPH-141B6;Lo;0;L;;;;;N;;;;;\n141B7;EGYPTIAN HIEROGLYPH-141B7;Lo;0;L;;;;;N;;;;;\n141B8;EGYPTIAN HIEROGLYPH-141B8;Lo;0;L;;;;;N;;;;;\n141B9;EGYPTIAN HIEROGLYPH-141B9;Lo;0;L;;;;;N;;;;;\n141BA;EGYPTIAN HIEROGLYPH-141BA;Lo;0;L;;;;;N;;;;;\n141BB;EGYPTIAN HIEROGLYPH-141BB;Lo;0;L;;;;;N;;;;;\n141BC;EGYPTIAN HIEROGLYPH-141BC;Lo;0;L;;;;;N;;;;;\n141BD;EGYPTIAN HIEROGLYPH-141BD;Lo;0;L;;;;;N;;;;;\n141BE;EGYPTIAN HIEROGLYPH-141BE;Lo;0;L;;;;;N;;;;;\n141BF;EGYPTIAN HIEROGLYPH-141BF;Lo;0;L;;;;;N;;;;;\n141C0;EGYPTIAN HIEROGLYPH-141C0;Lo;0;L;;;;;N;;;;;\n141C1;EGYPTIAN HIEROGLYPH-141C1;Lo;0;L;;;;;N;;;;;\n141C2;EGYPTIAN HIEROGLYPH-141C2;Lo;0;L;;;;;N;;;;;\n141C3;EGYPTIAN HIEROGLYPH-141C3;Lo;0;L;;;;;N;;;;;\n141C4;EGYPTIAN HIEROGLYPH-141C4;Lo;0;L;;;;;N;;;;;\n141C5;EGYPTIAN HIEROGLYPH-141C5;Lo;0;L;;;;;N;;;;;\n141C6;EGYPTIAN HIEROGLYPH-141C6;Lo;0;L;;;;;N;;;;;\n141C7;EGYPTIAN HIEROGLYPH-141C7;Lo;0;L;;;;;N;;;;;\n141C8;EGYPTIAN HIEROGLYPH-141C8;Lo;0;L;;;;;N;;;;;\n141C9;EGYPTIAN HIEROGLYPH-141C9;Lo;0;L;;;;;N;;;;;\n141CA;EGYPTIAN HIEROGLYPH-141CA;Lo;0;L;;;;;N;;;;;\n141CB;EGYPTIAN HIEROGLYPH-141CB;Lo;0;L;;;;;N;;;;;\n141CC;EGYPTIAN HIEROGLYPH-141CC;Lo;0;L;;;;;N;;;;;\n141CD;EGYPTIAN HIEROGLYPH-141CD;Lo;0;L;;;;;N;;;;;\n141CE;EGYPTIAN HIEROGLYPH-141CE;Lo;0;L;;;;;N;;;;;\n141CF;EGYPTIAN HIEROGLYPH-141CF;Lo;0;L;;;;;N;;;;;\n141D0;EGYPTIAN HIEROGLYPH-141D0;Lo;0;L;;;;;N;;;;;\n141D1;EGYPTIAN HIEROGLYPH-141D1;Lo;0;L;;;;;N;;;;;\n141D2;EGYPTIAN HIEROGLYPH-141D2;Lo;0;L;;;;;N;;;;;\n141D3;EGYPTIAN HIEROGLYPH-141D3;Lo;0;L;;;;;N;;;;;\n141D4;EGYPTIAN HIEROGLYPH-141D4;Lo;0;L;;;;;N;;;;;\n141D5;EGYPTIAN HIEROGLYPH-141D5;Lo;0;L;;;;;N;;;;;\n141D6;EGYPTIAN HIEROGLYPH-141D6;Lo;0;L;;;;;N;;;;;\n141D7;EGYPTIAN HIEROGLYPH-141D7;Lo;0;L;;;;;N;;;;;\n141D8;EGYPTIAN HIEROGLYPH-141D8;Lo;0;L;;;;;N;;;;;\n141D9;EGYPTIAN HIEROGLYPH-141D9;Lo;0;L;;;;;N;;;;;\n141DA;EGYPTIAN HIEROGLYPH-141DA;Lo;0;L;;;;;N;;;;;\n141DB;EGYPTIAN HIEROGLYPH-141DB;Lo;0;L;;;;;N;;;;;\n141DC;EGYPTIAN HIEROGLYPH-141DC;Lo;0;L;;;;;N;;;;;\n141DD;EGYPTIAN HIEROGLYPH-141DD;Lo;0;L;;;;;N;;;;;\n141DE;EGYPTIAN HIEROGLYPH-141DE;Lo;0;L;;;;;N;;;;;\n141DF;EGYPTIAN HIEROGLYPH-141DF;Lo;0;L;;;;;N;;;;;\n141E0;EGYPTIAN HIEROGLYPH-141E0;Lo;0;L;;;;;N;;;;;\n141E1;EGYPTIAN HIEROGLYPH-141E1;Lo;0;L;;;;;N;;;;;\n141E2;EGYPTIAN HIEROGLYPH-141E2;Lo;0;L;;;;;N;;;;;\n141E3;EGYPTIAN HIEROGLYPH-141E3;Lo;0;L;;;;;N;;;;;\n141E4;EGYPTIAN HIEROGLYPH-141E4;Lo;0;L;;;;;N;;;;;\n141E5;EGYPTIAN HIEROGLYPH-141E5;Lo;0;L;;;;;N;;;;;\n141E6;EGYPTIAN HIEROGLYPH-141E6;Lo;0;L;;;;;N;;;;;\n141E7;EGYPTIAN HIEROGLYPH-141E7;Lo;0;L;;;;;N;;;;;\n141E8;EGYPTIAN HIEROGLYPH-141E8;Lo;0;L;;;;;N;;;;;\n141E9;EGYPTIAN HIEROGLYPH-141E9;Lo;0;L;;;;;N;;;;;\n141EA;EGYPTIAN HIEROGLYPH-141EA;Lo;0;L;;;;;N;;;;;\n141EB;EGYPTIAN HIEROGLYPH-141EB;Lo;0;L;;;;;N;;;;;\n141EC;EGYPTIAN HIEROGLYPH-141EC;Lo;0;L;;;;;N;;;;;\n141ED;EGYPTIAN HIEROGLYPH-141ED;Lo;0;L;;;;;N;;;;;\n141EE;EGYPTIAN HIEROGLYPH-141EE;Lo;0;L;;;;;N;;;;;\n141EF;EGYPTIAN HIEROGLYPH-141EF;Lo;0;L;;;;;N;;;;;\n141F0;EGYPTIAN HIEROGLYPH-141F0;Lo;0;L;;;;;N;;;;;\n141F1;EGYPTIAN HIEROGLYPH-141F1;Lo;0;L;;;;;N;;;;;\n141F2;EGYPTIAN HIEROGLYPH-141F2;Lo;0;L;;;;;N;;;;;\n141F3;EGYPTIAN HIEROGLYPH-141F3;Lo;0;L;;;;;N;;;;;\n141F4;EGYPTIAN HIEROGLYPH-141F4;Lo;0;L;;;;;N;;;;;\n141F5;EGYPTIAN HIEROGLYPH-141F5;Lo;0;L;;;;;N;;;;;\n141F6;EGYPTIAN HIEROGLYPH-141F6;Lo;0;L;;;;;N;;;;;\n141F7;EGYPTIAN HIEROGLYPH-141F7;Lo;0;L;;;;;N;;;;;\n141F8;EGYPTIAN HIEROGLYPH-141F8;Lo;0;L;;;;;N;;;;;\n141F9;EGYPTIAN HIEROGLYPH-141F9;Lo;0;L;;;;;N;;;;;\n141FA;EGYPTIAN HIEROGLYPH-141FA;Lo;0;L;;;;;N;;;;;\n141FB;EGYPTIAN HIEROGLYPH-141FB;Lo;0;L;;;;;N;;;;;\n141FC;EGYPTIAN HIEROGLYPH-141FC;Lo;0;L;;;;;N;;;;;\n141FD;EGYPTIAN HIEROGLYPH-141FD;Lo;0;L;;;;;N;;;;;\n141FE;EGYPTIAN HIEROGLYPH-141FE;Lo;0;L;;;;;N;;;;;\n141FF;EGYPTIAN HIEROGLYPH-141FF;Lo;0;L;;;;;N;;;;;\n14200;EGYPTIAN HIEROGLYPH-14200;Lo;0;L;;;;;N;;;;;\n14201;EGYPTIAN HIEROGLYPH-14201;Lo;0;L;;;;;N;;;;;\n14202;EGYPTIAN HIEROGLYPH-14202;Lo;0;L;;;;;N;;;;;\n14203;EGYPTIAN HIEROGLYPH-14203;Lo;0;L;;;;;N;;;;;\n14204;EGYPTIAN HIEROGLYPH-14204;Lo;0;L;;;;;N;;;;;\n14205;EGYPTIAN HIEROGLYPH-14205;Lo;0;L;;;;;N;;;;;\n14206;EGYPTIAN HIEROGLYPH-14206;Lo;0;L;;;;;N;;;;;\n14207;EGYPTIAN HIEROGLYPH-14207;Lo;0;L;;;;;N;;;;;\n14208;EGYPTIAN HIEROGLYPH-14208;Lo;0;L;;;;;N;;;;;\n14209;EGYPTIAN HIEROGLYPH-14209;Lo;0;L;;;;;N;;;;;\n1420A;EGYPTIAN HIEROGLYPH-1420A;Lo;0;L;;;;;N;;;;;\n1420B;EGYPTIAN HIEROGLYPH-1420B;Lo;0;L;;;;;N;;;;;\n1420C;EGYPTIAN HIEROGLYPH-1420C;Lo;0;L;;;;;N;;;;;\n1420D;EGYPTIAN HIEROGLYPH-1420D;Lo;0;L;;;;;N;;;;;\n1420E;EGYPTIAN HIEROGLYPH-1420E;Lo;0;L;;;;;N;;;;;\n1420F;EGYPTIAN HIEROGLYPH-1420F;Lo;0;L;;;;;N;;;;;\n14210;EGYPTIAN HIEROGLYPH-14210;Lo;0;L;;;;;N;;;;;\n14211;EGYPTIAN HIEROGLYPH-14211;Lo;0;L;;;;;N;;;;;\n14212;EGYPTIAN HIEROGLYPH-14212;Lo;0;L;;;;;N;;;;;\n14213;EGYPTIAN HIEROGLYPH-14213;Lo;0;L;;;;;N;;;;;\n14214;EGYPTIAN HIEROGLYPH-14214;Lo;0;L;;;;;N;;;;;\n14215;EGYPTIAN HIEROGLYPH-14215;Lo;0;L;;;;;N;;;;;\n14216;EGYPTIAN HIEROGLYPH-14216;Lo;0;L;;;;;N;;;;;\n14217;EGYPTIAN HIEROGLYPH-14217;Lo;0;L;;;;;N;;;;;\n14218;EGYPTIAN HIEROGLYPH-14218;Lo;0;L;;;;;N;;;;;\n14219;EGYPTIAN HIEROGLYPH-14219;Lo;0;L;;;;;N;;;;;\n1421A;EGYPTIAN HIEROGLYPH-1421A;Lo;0;L;;;;;N;;;;;\n1421B;EGYPTIAN HIEROGLYPH-1421B;Lo;0;L;;;;;N;;;;;\n1421C;EGYPTIAN HIEROGLYPH-1421C;Lo;0;L;;;;;N;;;;;\n1421D;EGYPTIAN HIEROGLYPH-1421D;Lo;0;L;;;;;N;;;;;\n1421E;EGYPTIAN HIEROGLYPH-1421E;Lo;0;L;;;;;N;;;;;\n1421F;EGYPTIAN HIEROGLYPH-1421F;Lo;0;L;;;;;N;;;;;\n14220;EGYPTIAN HIEROGLYPH-14220;Lo;0;L;;;;;N;;;;;\n14221;EGYPTIAN HIEROGLYPH-14221;Lo;0;L;;;;;N;;;;;\n14222;EGYPTIAN HIEROGLYPH-14222;Lo;0;L;;;;;N;;;;;\n14223;EGYPTIAN HIEROGLYPH-14223;Lo;0;L;;;;;N;;;;;\n14224;EGYPTIAN HIEROGLYPH-14224;Lo;0;L;;;;;N;;;;;\n14225;EGYPTIAN HIEROGLYPH-14225;Lo;0;L;;;;;N;;;;;\n14226;EGYPTIAN HIEROGLYPH-14226;Lo;0;L;;;;;N;;;;;\n14227;EGYPTIAN HIEROGLYPH-14227;Lo;0;L;;;;;N;;;;;\n14228;EGYPTIAN HIEROGLYPH-14228;Lo;0;L;;;;;N;;;;;\n14229;EGYPTIAN HIEROGLYPH-14229;Lo;0;L;;;;;N;;;;;\n1422A;EGYPTIAN HIEROGLYPH-1422A;Lo;0;L;;;;;N;;;;;\n1422B;EGYPTIAN HIEROGLYPH-1422B;Lo;0;L;;;;;N;;;;;\n1422C;EGYPTIAN HIEROGLYPH-1422C;Lo;0;L;;;;;N;;;;;\n1422D;EGYPTIAN HIEROGLYPH-1422D;Lo;0;L;;;;;N;;;;;\n1422E;EGYPTIAN HIEROGLYPH-1422E;Lo;0;L;;;;;N;;;;;\n1422F;EGYPTIAN HIEROGLYPH-1422F;Lo;0;L;;;;;N;;;;;\n14230;EGYPTIAN HIEROGLYPH-14230;Lo;0;L;;;;;N;;;;;\n14231;EGYPTIAN HIEROGLYPH-14231;Lo;0;L;;;;;N;;;;;\n14232;EGYPTIAN HIEROGLYPH-14232;Lo;0;L;;;;;N;;;;;\n14233;EGYPTIAN HIEROGLYPH-14233;Lo;0;L;;;;;N;;;;;\n14234;EGYPTIAN HIEROGLYPH-14234;Lo;0;L;;;;;N;;;;;\n14235;EGYPTIAN HIEROGLYPH-14235;Lo;0;L;;;;;N;;;;;\n14236;EGYPTIAN HIEROGLYPH-14236;Lo;0;L;;;;;N;;;;;\n14237;EGYPTIAN HIEROGLYPH-14237;Lo;0;L;;;;;N;;;;;\n14238;EGYPTIAN HIEROGLYPH-14238;Lo;0;L;;;;;N;;;;;\n14239;EGYPTIAN HIEROGLYPH-14239;Lo;0;L;;;;;N;;;;;\n1423A;EGYPTIAN HIEROGLYPH-1423A;Lo;0;L;;;;;N;;;;;\n1423B;EGYPTIAN HIEROGLYPH-1423B;Lo;0;L;;;;;N;;;;;\n1423C;EGYPTIAN HIEROGLYPH-1423C;Lo;0;L;;;;;N;;;;;\n1423D;EGYPTIAN HIEROGLYPH-1423D;Lo;0;L;;;;;N;;;;;\n1423E;EGYPTIAN HIEROGLYPH-1423E;Lo;0;L;;;;;N;;;;;\n1423F;EGYPTIAN HIEROGLYPH-1423F;Lo;0;L;;;;;N;;;;;\n14240;EGYPTIAN HIEROGLYPH-14240;Lo;0;L;;;;;N;;;;;\n14241;EGYPTIAN HIEROGLYPH-14241;Lo;0;L;;;;;N;;;;;\n14242;EGYPTIAN HIEROGLYPH-14242;Lo;0;L;;;;;N;;;;;\n14243;EGYPTIAN HIEROGLYPH-14243;Lo;0;L;;;;;N;;;;;\n14244;EGYPTIAN HIEROGLYPH-14244;Lo;0;L;;;;;N;;;;;\n14245;EGYPTIAN HIEROGLYPH-14245;Lo;0;L;;;;;N;;;;;\n14246;EGYPTIAN HIEROGLYPH-14246;Lo;0;L;;;;;N;;;;;\n14247;EGYPTIAN HIEROGLYPH-14247;Lo;0;L;;;;;N;;;;;\n14248;EGYPTIAN HIEROGLYPH-14248;Lo;0;L;;;;;N;;;;;\n14249;EGYPTIAN HIEROGLYPH-14249;Lo;0;L;;;;;N;;;;;\n1424A;EGYPTIAN HIEROGLYPH-1424A;Lo;0;L;;;;;N;;;;;\n1424B;EGYPTIAN HIEROGLYPH-1424B;Lo;0;L;;;;;N;;;;;\n1424C;EGYPTIAN HIEROGLYPH-1424C;Lo;0;L;;;;;N;;;;;\n1424D;EGYPTIAN HIEROGLYPH-1424D;Lo;0;L;;;;;N;;;;;\n1424E;EGYPTIAN HIEROGLYPH-1424E;Lo;0;L;;;;;N;;;;;\n1424F;EGYPTIAN HIEROGLYPH-1424F;Lo;0;L;;;;;N;;;;;\n14250;EGYPTIAN HIEROGLYPH-14250;Lo;0;L;;;;;N;;;;;\n14251;EGYPTIAN HIEROGLYPH-14251;Lo;0;L;;;;;N;;;;;\n14252;EGYPTIAN HIEROGLYPH-14252;Lo;0;L;;;;;N;;;;;\n14253;EGYPTIAN HIEROGLYPH-14253;Lo;0;L;;;;;N;;;;;\n14254;EGYPTIAN HIEROGLYPH-14254;Lo;0;L;;;;;N;;;;;\n14255;EGYPTIAN HIEROGLYPH-14255;Lo;0;L;;;;;N;;;;;\n14256;EGYPTIAN HIEROGLYPH-14256;Lo;0;L;;;;;N;;;;;\n14257;EGYPTIAN HIEROGLYPH-14257;Lo;0;L;;;;;N;;;;;\n14258;EGYPTIAN HIEROGLYPH-14258;Lo;0;L;;;;;N;;;;;\n14259;EGYPTIAN HIEROGLYPH-14259;Lo;0;L;;;;;N;;;;;\n1425A;EGYPTIAN HIEROGLYPH-1425A;Lo;0;L;;;;;N;;;;;\n1425B;EGYPTIAN HIEROGLYPH-1425B;Lo;0;L;;;;;N;;;;;\n1425C;EGYPTIAN HIEROGLYPH-1425C;Lo;0;L;;;;;N;;;;;\n1425D;EGYPTIAN HIEROGLYPH-1425D;Lo;0;L;;;;;N;;;;;\n1425E;EGYPTIAN HIEROGLYPH-1425E;Lo;0;L;;;;;N;;;;;\n1425F;EGYPTIAN HIEROGLYPH-1425F;Lo;0;L;;;;;N;;;;;\n14260;EGYPTIAN HIEROGLYPH-14260;Lo;0;L;;;;;N;;;;;\n14261;EGYPTIAN HIEROGLYPH-14261;Lo;0;L;;;;;N;;;;;\n14262;EGYPTIAN HIEROGLYPH-14262;Lo;0;L;;;;;N;;;;;\n14263;EGYPTIAN HIEROGLYPH-14263;Lo;0;L;;;;;N;;;;;\n14264;EGYPTIAN HIEROGLYPH-14264;Lo;0;L;;;;;N;;;;;\n14265;EGYPTIAN HIEROGLYPH-14265;Lo;0;L;;;;;N;;;;;\n14266;EGYPTIAN HIEROGLYPH-14266;Lo;0;L;;;;;N;;;;;\n14267;EGYPTIAN HIEROGLYPH-14267;Lo;0;L;;;;;N;;;;;\n14268;EGYPTIAN HIEROGLYPH-14268;Lo;0;L;;;;;N;;;;;\n14269;EGYPTIAN HIEROGLYPH-14269;Lo;0;L;;;;;N;;;;;\n1426A;EGYPTIAN HIEROGLYPH-1426A;Lo;0;L;;;;;N;;;;;\n1426B;EGYPTIAN HIEROGLYPH-1426B;Lo;0;L;;;;;N;;;;;\n1426C;EGYPTIAN HIEROGLYPH-1426C;Lo;0;L;;;;;N;;;;;\n1426D;EGYPTIAN HIEROGLYPH-1426D;Lo;0;L;;;;;N;;;;;\n1426E;EGYPTIAN HIEROGLYPH-1426E;Lo;0;L;;;;;N;;;;;\n1426F;EGYPTIAN HIEROGLYPH-1426F;Lo;0;L;;;;;N;;;;;\n14270;EGYPTIAN HIEROGLYPH-14270;Lo;0;L;;;;;N;;;;;\n14271;EGYPTIAN HIEROGLYPH-14271;Lo;0;L;;;;;N;;;;;\n14272;EGYPTIAN HIEROGLYPH-14272;Lo;0;L;;;;;N;;;;;\n14273;EGYPTIAN HIEROGLYPH-14273;Lo;0;L;;;;;N;;;;;\n14274;EGYPTIAN HIEROGLYPH-14274;Lo;0;L;;;;;N;;;;;\n14275;EGYPTIAN HIEROGLYPH-14275;Lo;0;L;;;;;N;;;;;\n14276;EGYPTIAN HIEROGLYPH-14276;Lo;0;L;;;;;N;;;;;\n14277;EGYPTIAN HIEROGLYPH-14277;Lo;0;L;;;;;N;;;;;\n14278;EGYPTIAN HIEROGLYPH-14278;Lo;0;L;;;;;N;;;;;\n14279;EGYPTIAN HIEROGLYPH-14279;Lo;0;L;;;;;N;;;;;\n1427A;EGYPTIAN HIEROGLYPH-1427A;Lo;0;L;;;;;N;;;;;\n1427B;EGYPTIAN HIEROGLYPH-1427B;Lo;0;L;;;;;N;;;;;\n1427C;EGYPTIAN HIEROGLYPH-1427C;Lo;0;L;;;;;N;;;;;\n1427D;EGYPTIAN HIEROGLYPH-1427D;Lo;0;L;;;;;N;;;;;\n1427E;EGYPTIAN HIEROGLYPH-1427E;Lo;0;L;;;;;N;;;;;\n1427F;EGYPTIAN HIEROGLYPH-1427F;Lo;0;L;;;;;N;;;;;\n14280;EGYPTIAN HIEROGLYPH-14280;Lo;0;L;;;;;N;;;;;\n14281;EGYPTIAN HIEROGLYPH-14281;Lo;0;L;;;;;N;;;;;\n14282;EGYPTIAN HIEROGLYPH-14282;Lo;0;L;;;;;N;;;;;\n14283;EGYPTIAN HIEROGLYPH-14283;Lo;0;L;;;;;N;;;;;\n14284;EGYPTIAN HIEROGLYPH-14284;Lo;0;L;;;;;N;;;;;\n14285;EGYPTIAN HIEROGLYPH-14285;Lo;0;L;;;;;N;;;;;\n14286;EGYPTIAN HIEROGLYPH-14286;Lo;0;L;;;;;N;;;;;\n14287;EGYPTIAN HIEROGLYPH-14287;Lo;0;L;;;;;N;;;;;\n14288;EGYPTIAN HIEROGLYPH-14288;Lo;0;L;;;;;N;;;;;\n14289;EGYPTIAN HIEROGLYPH-14289;Lo;0;L;;;;;N;;;;;\n1428A;EGYPTIAN HIEROGLYPH-1428A;Lo;0;L;;;;;N;;;;;\n1428B;EGYPTIAN HIEROGLYPH-1428B;Lo;0;L;;;;;N;;;;;\n1428C;EGYPTIAN HIEROGLYPH-1428C;Lo;0;L;;;;;N;;;;;\n1428D;EGYPTIAN HIEROGLYPH-1428D;Lo;0;L;;;;;N;;;;;\n1428E;EGYPTIAN HIEROGLYPH-1428E;Lo;0;L;;;;;N;;;;;\n1428F;EGYPTIAN HIEROGLYPH-1428F;Lo;0;L;;;;;N;;;;;\n14290;EGYPTIAN HIEROGLYPH-14290;Lo;0;L;;;;;N;;;;;\n14291;EGYPTIAN HIEROGLYPH-14291;Lo;0;L;;;;;N;;;;;\n14292;EGYPTIAN HIEROGLYPH-14292;Lo;0;L;;;;;N;;;;;\n14293;EGYPTIAN HIEROGLYPH-14293;Lo;0;L;;;;;N;;;;;\n14294;EGYPTIAN HIEROGLYPH-14294;Lo;0;L;;;;;N;;;;;\n14295;EGYPTIAN HIEROGLYPH-14295;Lo;0;L;;;;;N;;;;;\n14296;EGYPTIAN HIEROGLYPH-14296;Lo;0;L;;;;;N;;;;;\n14297;EGYPTIAN HIEROGLYPH-14297;Lo;0;L;;;;;N;;;;;\n14298;EGYPTIAN HIEROGLYPH-14298;Lo;0;L;;;;;N;;;;;\n14299;EGYPTIAN HIEROGLYPH-14299;Lo;0;L;;;;;N;;;;;\n1429A;EGYPTIAN HIEROGLYPH-1429A;Lo;0;L;;;;;N;;;;;\n1429B;EGYPTIAN HIEROGLYPH-1429B;Lo;0;L;;;;;N;;;;;\n1429C;EGYPTIAN HIEROGLYPH-1429C;Lo;0;L;;;;;N;;;;;\n1429D;EGYPTIAN HIEROGLYPH-1429D;Lo;0;L;;;;;N;;;;;\n1429E;EGYPTIAN HIEROGLYPH-1429E;Lo;0;L;;;;;N;;;;;\n1429F;EGYPTIAN HIEROGLYPH-1429F;Lo;0;L;;;;;N;;;;;\n142A0;EGYPTIAN HIEROGLYPH-142A0;Lo;0;L;;;;;N;;;;;\n142A1;EGYPTIAN HIEROGLYPH-142A1;Lo;0;L;;;;;N;;;;;\n142A2;EGYPTIAN HIEROGLYPH-142A2;Lo;0;L;;;;;N;;;;;\n142A3;EGYPTIAN HIEROGLYPH-142A3;Lo;0;L;;;;;N;;;;;\n142A4;EGYPTIAN HIEROGLYPH-142A4;Lo;0;L;;;;;N;;;;;\n142A5;EGYPTIAN HIEROGLYPH-142A5;Lo;0;L;;;;;N;;;;;\n142A6;EGYPTIAN HIEROGLYPH-142A6;Lo;0;L;;;;;N;;;;;\n142A7;EGYPTIAN HIEROGLYPH-142A7;Lo;0;L;;;;;N;;;;;\n142A8;EGYPTIAN HIEROGLYPH-142A8;Lo;0;L;;;;;N;;;;;\n142A9;EGYPTIAN HIEROGLYPH-142A9;Lo;0;L;;;;;N;;;;;\n142AA;EGYPTIAN HIEROGLYPH-142AA;Lo;0;L;;;;;N;;;;;\n142AB;EGYPTIAN HIEROGLYPH-142AB;Lo;0;L;;;;;N;;;;;\n142AC;EGYPTIAN HIEROGLYPH-142AC;Lo;0;L;;;;;N;;;;;\n142AD;EGYPTIAN HIEROGLYPH-142AD;Lo;0;L;;;;;N;;;;;\n142AE;EGYPTIAN HIEROGLYPH-142AE;Lo;0;L;;;;;N;;;;;\n142AF;EGYPTIAN HIEROGLYPH-142AF;Lo;0;L;;;;;N;;;;;\n142B0;EGYPTIAN HIEROGLYPH-142B0;Lo;0;L;;;;;N;;;;;\n142B1;EGYPTIAN HIEROGLYPH-142B1;Lo;0;L;;;;;N;;;;;\n142B2;EGYPTIAN HIEROGLYPH-142B2;Lo;0;L;;;;;N;;;;;\n142B3;EGYPTIAN HIEROGLYPH-142B3;Lo;0;L;;;;;N;;;;;\n142B4;EGYPTIAN HIEROGLYPH-142B4;Lo;0;L;;;;;N;;;;;\n142B5;EGYPTIAN HIEROGLYPH-142B5;Lo;0;L;;;;;N;;;;;\n142B6;EGYPTIAN HIEROGLYPH-142B6;Lo;0;L;;;;;N;;;;;\n142B7;EGYPTIAN HIEROGLYPH-142B7;Lo;0;L;;;;;N;;;;;\n142B8;EGYPTIAN HIEROGLYPH-142B8;Lo;0;L;;;;;N;;;;;\n142B9;EGYPTIAN HIEROGLYPH-142B9;Lo;0;L;;;;;N;;;;;\n142BA;EGYPTIAN HIEROGLYPH-142BA;Lo;0;L;;;;;N;;;;;\n142BB;EGYPTIAN HIEROGLYPH-142BB;Lo;0;L;;;;;N;;;;;\n142BC;EGYPTIAN HIEROGLYPH-142BC;Lo;0;L;;;;;N;;;;;\n142BD;EGYPTIAN HIEROGLYPH-142BD;Lo;0;L;;;;;N;;;;;\n142BE;EGYPTIAN HIEROGLYPH-142BE;Lo;0;L;;;;;N;;;;;\n142BF;EGYPTIAN HIEROGLYPH-142BF;Lo;0;L;;;;;N;;;;;\n142C0;EGYPTIAN HIEROGLYPH-142C0;Lo;0;L;;;;;N;;;;;\n142C1;EGYPTIAN HIEROGLYPH-142C1;Lo;0;L;;;;;N;;;;;\n142C2;EGYPTIAN HIEROGLYPH-142C2;Lo;0;L;;;;;N;;;;;\n142C3;EGYPTIAN HIEROGLYPH-142C3;Lo;0;L;;;;;N;;;;;\n142C4;EGYPTIAN HIEROGLYPH-142C4;Lo;0;L;;;;;N;;;;;\n142C5;EGYPTIAN HIEROGLYPH-142C5;Lo;0;L;;;;;N;;;;;\n142C6;EGYPTIAN HIEROGLYPH-142C6;Lo;0;L;;;;;N;;;;;\n142C7;EGYPTIAN HIEROGLYPH-142C7;Lo;0;L;;;;;N;;;;;\n142C8;EGYPTIAN HIEROGLYPH-142C8;Lo;0;L;;;;;N;;;;;\n142C9;EGYPTIAN HIEROGLYPH-142C9;Lo;0;L;;;;;N;;;;;\n142CA;EGYPTIAN HIEROGLYPH-142CA;Lo;0;L;;;;;N;;;;;\n142CB;EGYPTIAN HIEROGLYPH-142CB;Lo;0;L;;;;;N;;;;;\n142CC;EGYPTIAN HIEROGLYPH-142CC;Lo;0;L;;;;;N;;;;;\n142CD;EGYPTIAN HIEROGLYPH-142CD;Lo;0;L;;;;;N;;;;;\n142CE;EGYPTIAN HIEROGLYPH-142CE;Lo;0;L;;;;;N;;;;;\n142CF;EGYPTIAN HIEROGLYPH-142CF;Lo;0;L;;;;;N;;;;;\n142D0;EGYPTIAN HIEROGLYPH-142D0;Lo;0;L;;;;;N;;;;;\n142D1;EGYPTIAN HIEROGLYPH-142D1;Lo;0;L;;;;;N;;;;;\n142D2;EGYPTIAN HIEROGLYPH-142D2;Lo;0;L;;;;;N;;;;;\n142D3;EGYPTIAN HIEROGLYPH-142D3;Lo;0;L;;;;;N;;;;;\n142D4;EGYPTIAN HIEROGLYPH-142D4;Lo;0;L;;;;;N;;;;;\n142D5;EGYPTIAN HIEROGLYPH-142D5;Lo;0;L;;;;;N;;;;;\n142D6;EGYPTIAN HIEROGLYPH-142D6;Lo;0;L;;;;;N;;;;;\n142D7;EGYPTIAN HIEROGLYPH-142D7;Lo;0;L;;;;;N;;;;;\n142D8;EGYPTIAN HIEROGLYPH-142D8;Lo;0;L;;;;;N;;;;;\n142D9;EGYPTIAN HIEROGLYPH-142D9;Lo;0;L;;;;;N;;;;;\n142DA;EGYPTIAN HIEROGLYPH-142DA;Lo;0;L;;;;;N;;;;;\n142DB;EGYPTIAN HIEROGLYPH-142DB;Lo;0;L;;;;;N;;;;;\n142DC;EGYPTIAN HIEROGLYPH-142DC;Lo;0;L;;;;;N;;;;;\n142DD;EGYPTIAN HIEROGLYPH-142DD;Lo;0;L;;;;;N;;;;;\n142DE;EGYPTIAN HIEROGLYPH-142DE;Lo;0;L;;;;;N;;;;;\n142DF;EGYPTIAN HIEROGLYPH-142DF;Lo;0;L;;;;;N;;;;;\n142E0;EGYPTIAN HIEROGLYPH-142E0;Lo;0;L;;;;;N;;;;;\n142E1;EGYPTIAN HIEROGLYPH-142E1;Lo;0;L;;;;;N;;;;;\n142E2;EGYPTIAN HIEROGLYPH-142E2;Lo;0;L;;;;;N;;;;;\n142E3;EGYPTIAN HIEROGLYPH-142E3;Lo;0;L;;;;;N;;;;;\n142E4;EGYPTIAN HIEROGLYPH-142E4;Lo;0;L;;;;;N;;;;;\n142E5;EGYPTIAN HIEROGLYPH-142E5;Lo;0;L;;;;;N;;;;;\n142E6;EGYPTIAN HIEROGLYPH-142E6;Lo;0;L;;;;;N;;;;;\n142E7;EGYPTIAN HIEROGLYPH-142E7;Lo;0;L;;;;;N;;;;;\n142E8;EGYPTIAN HIEROGLYPH-142E8;Lo;0;L;;;;;N;;;;;\n142E9;EGYPTIAN HIEROGLYPH-142E9;Lo;0;L;;;;;N;;;;;\n142EA;EGYPTIAN HIEROGLYPH-142EA;Lo;0;L;;;;;N;;;;;\n142EB;EGYPTIAN HIEROGLYPH-142EB;Lo;0;L;;;;;N;;;;;\n142EC;EGYPTIAN HIEROGLYPH-142EC;Lo;0;L;;;;;N;;;;;\n142ED;EGYPTIAN HIEROGLYPH-142ED;Lo;0;L;;;;;N;;;;;\n142EE;EGYPTIAN HIEROGLYPH-142EE;Lo;0;L;;;;;N;;;;;\n142EF;EGYPTIAN HIEROGLYPH-142EF;Lo;0;L;;;;;N;;;;;\n142F0;EGYPTIAN HIEROGLYPH-142F0;Lo;0;L;;;;;N;;;;;\n142F1;EGYPTIAN HIEROGLYPH-142F1;Lo;0;L;;;;;N;;;;;\n142F2;EGYPTIAN HIEROGLYPH-142F2;Lo;0;L;;;;;N;;;;;\n142F3;EGYPTIAN HIEROGLYPH-142F3;Lo;0;L;;;;;N;;;;;\n142F4;EGYPTIAN HIEROGLYPH-142F4;Lo;0;L;;;;;N;;;;;\n142F5;EGYPTIAN HIEROGLYPH-142F5;Lo;0;L;;;;;N;;;;;\n142F6;EGYPTIAN HIEROGLYPH-142F6;Lo;0;L;;;;;N;;;;;\n142F7;EGYPTIAN HIEROGLYPH-142F7;Lo;0;L;;;;;N;;;;;\n142F8;EGYPTIAN HIEROGLYPH-142F8;Lo;0;L;;;;;N;;;;;\n142F9;EGYPTIAN HIEROGLYPH-142F9;Lo;0;L;;;;;N;;;;;\n142FA;EGYPTIAN HIEROGLYPH-142FA;Lo;0;L;;;;;N;;;;;\n142FB;EGYPTIAN HIEROGLYPH-142FB;Lo;0;L;;;;;N;;;;;\n142FC;EGYPTIAN HIEROGLYPH-142FC;Lo;0;L;;;;;N;;;;;\n142FD;EGYPTIAN HIEROGLYPH-142FD;Lo;0;L;;;;;N;;;;;\n142FE;EGYPTIAN HIEROGLYPH-142FE;Lo;0;L;;;;;N;;;;;\n142FF;EGYPTIAN HIEROGLYPH-142FF;Lo;0;L;;;;;N;;;;;\n14300;EGYPTIAN HIEROGLYPH-14300;Lo;0;L;;;;;N;;;;;\n14301;EGYPTIAN HIEROGLYPH-14301;Lo;0;L;;;;;N;;;;;\n14302;EGYPTIAN HIEROGLYPH-14302;Lo;0;L;;;;;N;;;;;\n14303;EGYPTIAN HIEROGLYPH-14303;Lo;0;L;;;;;N;;;;;\n14304;EGYPTIAN HIEROGLYPH-14304;Lo;0;L;;;;;N;;;;;\n14305;EGYPTIAN HIEROGLYPH-14305;Lo;0;L;;;;;N;;;;;\n14306;EGYPTIAN HIEROGLYPH-14306;Lo;0;L;;;;;N;;;;;\n14307;EGYPTIAN HIEROGLYPH-14307;Lo;0;L;;;;;N;;;;;\n14308;EGYPTIAN HIEROGLYPH-14308;Lo;0;L;;;;;N;;;;;\n14309;EGYPTIAN HIEROGLYPH-14309;Lo;0;L;;;;;N;;;;;\n1430A;EGYPTIAN HIEROGLYPH-1430A;Lo;0;L;;;;;N;;;;;\n1430B;EGYPTIAN HIEROGLYPH-1430B;Lo;0;L;;;;;N;;;;;\n1430C;EGYPTIAN HIEROGLYPH-1430C;Lo;0;L;;;;;N;;;;;\n1430D;EGYPTIAN HIEROGLYPH-1430D;Lo;0;L;;;;;N;;;;;\n1430E;EGYPTIAN HIEROGLYPH-1430E;Lo;0;L;;;;;N;;;;;\n1430F;EGYPTIAN HIEROGLYPH-1430F;Lo;0;L;;;;;N;;;;;\n14310;EGYPTIAN HIEROGLYPH-14310;Lo;0;L;;;;;N;;;;;\n14311;EGYPTIAN HIEROGLYPH-14311;Lo;0;L;;;;;N;;;;;\n14312;EGYPTIAN HIEROGLYPH-14312;Lo;0;L;;;;;N;;;;;\n14313;EGYPTIAN HIEROGLYPH-14313;Lo;0;L;;;;;N;;;;;\n14314;EGYPTIAN HIEROGLYPH-14314;Lo;0;L;;;;;N;;;;;\n14315;EGYPTIAN HIEROGLYPH-14315;Lo;0;L;;;;;N;;;;;\n14316;EGYPTIAN HIEROGLYPH-14316;Lo;0;L;;;;;N;;;;;\n14317;EGYPTIAN HIEROGLYPH-14317;Lo;0;L;;;;;N;;;;;\n14318;EGYPTIAN HIEROGLYPH-14318;Lo;0;L;;;;;N;;;;;\n14319;EGYPTIAN HIEROGLYPH-14319;Lo;0;L;;;;;N;;;;;\n1431A;EGYPTIAN HIEROGLYPH-1431A;Lo;0;L;;;;;N;;;;;\n1431B;EGYPTIAN HIEROGLYPH-1431B;Lo;0;L;;;;;N;;;;;\n1431C;EGYPTIAN HIEROGLYPH-1431C;Lo;0;L;;;;;N;;;;;\n1431D;EGYPTIAN HIEROGLYPH-1431D;Lo;0;L;;;;;N;;;;;\n1431E;EGYPTIAN HIEROGLYPH-1431E;Lo;0;L;;;;;N;;;;;\n1431F;EGYPTIAN HIEROGLYPH-1431F;Lo;0;L;;;;;N;;;;;\n14320;EGYPTIAN HIEROGLYPH-14320;Lo;0;L;;;;;N;;;;;\n14321;EGYPTIAN HIEROGLYPH-14321;Lo;0;L;;;;;N;;;;;\n14322;EGYPTIAN HIEROGLYPH-14322;Lo;0;L;;;;;N;;;;;\n14323;EGYPTIAN HIEROGLYPH-14323;Lo;0;L;;;;;N;;;;;\n14324;EGYPTIAN HIEROGLYPH-14324;Lo;0;L;;;;;N;;;;;\n14325;EGYPTIAN HIEROGLYPH-14325;Lo;0;L;;;;;N;;;;;\n14326;EGYPTIAN HIEROGLYPH-14326;Lo;0;L;;;;;N;;;;;\n14327;EGYPTIAN HIEROGLYPH-14327;Lo;0;L;;;;;N;;;;;\n14328;EGYPTIAN HIEROGLYPH-14328;Lo;0;L;;;;;N;;;;;\n14329;EGYPTIAN HIEROGLYPH-14329;Lo;0;L;;;;;N;;;;;\n1432A;EGYPTIAN HIEROGLYPH-1432A;Lo;0;L;;;;;N;;;;;\n1432B;EGYPTIAN HIEROGLYPH-1432B;Lo;0;L;;;;;N;;;;;\n1432C;EGYPTIAN HIEROGLYPH-1432C;Lo;0;L;;;;;N;;;;;\n1432D;EGYPTIAN HIEROGLYPH-1432D;Lo;0;L;;;;;N;;;;;\n1432E;EGYPTIAN HIEROGLYPH-1432E;Lo;0;L;;;;;N;;;;;\n1432F;EGYPTIAN HIEROGLYPH-1432F;Lo;0;L;;;;;N;;;;;\n14330;EGYPTIAN HIEROGLYPH-14330;Lo;0;L;;;;;N;;;;;\n14331;EGYPTIAN HIEROGLYPH-14331;Lo;0;L;;;;;N;;;;;\n14332;EGYPTIAN HIEROGLYPH-14332;Lo;0;L;;;;;N;;;;;\n14333;EGYPTIAN HIEROGLYPH-14333;Lo;0;L;;;;;N;;;;;\n14334;EGYPTIAN HIEROGLYPH-14334;Lo;0;L;;;;;N;;;;;\n14335;EGYPTIAN HIEROGLYPH-14335;Lo;0;L;;;;;N;;;;;\n14336;EGYPTIAN HIEROGLYPH-14336;Lo;0;L;;;;;N;;;;;\n14337;EGYPTIAN HIEROGLYPH-14337;Lo;0;L;;;;;N;;;;;\n14338;EGYPTIAN HIEROGLYPH-14338;Lo;0;L;;;;;N;;;;;\n14339;EGYPTIAN HIEROGLYPH-14339;Lo;0;L;;;;;N;;;;;\n1433A;EGYPTIAN HIEROGLYPH-1433A;Lo;0;L;;;;;N;;;;;\n1433B;EGYPTIAN HIEROGLYPH-1433B;Lo;0;L;;;;;N;;;;;\n1433C;EGYPTIAN HIEROGLYPH-1433C;Lo;0;L;;;;;N;;;;;\n1433D;EGYPTIAN HIEROGLYPH-1433D;Lo;0;L;;;;;N;;;;;\n1433E;EGYPTIAN HIEROGLYPH-1433E;Lo;0;L;;;;;N;;;;;\n1433F;EGYPTIAN HIEROGLYPH-1433F;Lo;0;L;;;;;N;;;;;\n14340;EGYPTIAN HIEROGLYPH-14340;Lo;0;L;;;;;N;;;;;\n14341;EGYPTIAN HIEROGLYPH-14341;Lo;0;L;;;;;N;;;;;\n14342;EGYPTIAN HIEROGLYPH-14342;Lo;0;L;;;;;N;;;;;\n14343;EGYPTIAN HIEROGLYPH-14343;Lo;0;L;;;;;N;;;;;\n14344;EGYPTIAN HIEROGLYPH-14344;Lo;0;L;;;;;N;;;;;\n14345;EGYPTIAN HIEROGLYPH-14345;Lo;0;L;;;;;N;;;;;\n14346;EGYPTIAN HIEROGLYPH-14346;Lo;0;L;;;;;N;;;;;\n14347;EGYPTIAN HIEROGLYPH-14347;Lo;0;L;;;;;N;;;;;\n14348;EGYPTIAN HIEROGLYPH-14348;Lo;0;L;;;;;N;;;;;\n14349;EGYPTIAN HIEROGLYPH-14349;Lo;0;L;;;;;N;;;;;\n1434A;EGYPTIAN HIEROGLYPH-1434A;Lo;0;L;;;;;N;;;;;\n1434B;EGYPTIAN HIEROGLYPH-1434B;Lo;0;L;;;;;N;;;;;\n1434C;EGYPTIAN HIEROGLYPH-1434C;Lo;0;L;;;;;N;;;;;\n1434D;EGYPTIAN HIEROGLYPH-1434D;Lo;0;L;;;;;N;;;;;\n1434E;EGYPTIAN HIEROGLYPH-1434E;Lo;0;L;;;;;N;;;;;\n1434F;EGYPTIAN HIEROGLYPH-1434F;Lo;0;L;;;;;N;;;;;\n14350;EGYPTIAN HIEROGLYPH-14350;Lo;0;L;;;;;N;;;;;\n14351;EGYPTIAN HIEROGLYPH-14351;Lo;0;L;;;;;N;;;;;\n14352;EGYPTIAN HIEROGLYPH-14352;Lo;0;L;;;;;N;;;;;\n14353;EGYPTIAN HIEROGLYPH-14353;Lo;0;L;;;;;N;;;;;\n14354;EGYPTIAN HIEROGLYPH-14354;Lo;0;L;;;;;N;;;;;\n14355;EGYPTIAN HIEROGLYPH-14355;Lo;0;L;;;;;N;;;;;\n14356;EGYPTIAN HIEROGLYPH-14356;Lo;0;L;;;;;N;;;;;\n14357;EGYPTIAN HIEROGLYPH-14357;Lo;0;L;;;;;N;;;;;\n14358;EGYPTIAN HIEROGLYPH-14358;Lo;0;L;;;;;N;;;;;\n14359;EGYPTIAN HIEROGLYPH-14359;Lo;0;L;;;;;N;;;;;\n1435A;EGYPTIAN HIEROGLYPH-1435A;Lo;0;L;;;;;N;;;;;\n1435B;EGYPTIAN HIEROGLYPH-1435B;Lo;0;L;;;;;N;;;;;\n1435C;EGYPTIAN HIEROGLYPH-1435C;Lo;0;L;;;;;N;;;;;\n1435D;EGYPTIAN HIEROGLYPH-1435D;Lo;0;L;;;;;N;;;;;\n1435E;EGYPTIAN HIEROGLYPH-1435E;Lo;0;L;;;;;N;;;;;\n1435F;EGYPTIAN HIEROGLYPH-1435F;Lo;0;L;;;;;N;;;;;\n14360;EGYPTIAN HIEROGLYPH-14360;Lo;0;L;;;;;N;;;;;\n14361;EGYPTIAN HIEROGLYPH-14361;Lo;0;L;;;;;N;;;;;\n14362;EGYPTIAN HIEROGLYPH-14362;Lo;0;L;;;;;N;;;;;\n14363;EGYPTIAN HIEROGLYPH-14363;Lo;0;L;;;;;N;;;;;\n14364;EGYPTIAN HIEROGLYPH-14364;Lo;0;L;;;;;N;;;;;\n14365;EGYPTIAN HIEROGLYPH-14365;Lo;0;L;;;;;N;;;;;\n14366;EGYPTIAN HIEROGLYPH-14366;Lo;0;L;;;;;N;;;;;\n14367;EGYPTIAN HIEROGLYPH-14367;Lo;0;L;;;;;N;;;;;\n14368;EGYPTIAN HIEROGLYPH-14368;Lo;0;L;;;;;N;;;;;\n14369;EGYPTIAN HIEROGLYPH-14369;Lo;0;L;;;;;N;;;;;\n1436A;EGYPTIAN HIEROGLYPH-1436A;Lo;0;L;;;;;N;;;;;\n1436B;EGYPTIAN HIEROGLYPH-1436B;Lo;0;L;;;;;N;;;;;\n1436C;EGYPTIAN HIEROGLYPH-1436C;Lo;0;L;;;;;N;;;;;\n1436D;EGYPTIAN HIEROGLYPH-1436D;Lo;0;L;;;;;N;;;;;\n1436E;EGYPTIAN HIEROGLYPH-1436E;Lo;0;L;;;;;N;;;;;\n1436F;EGYPTIAN HIEROGLYPH-1436F;Lo;0;L;;;;;N;;;;;\n14370;EGYPTIAN HIEROGLYPH-14370;Lo;0;L;;;;;N;;;;;\n14371;EGYPTIAN HIEROGLYPH-14371;Lo;0;L;;;;;N;;;;;\n14372;EGYPTIAN HIEROGLYPH-14372;Lo;0;L;;;;;N;;;;;\n14373;EGYPTIAN HIEROGLYPH-14373;Lo;0;L;;;;;N;;;;;\n14374;EGYPTIAN HIEROGLYPH-14374;Lo;0;L;;;;;N;;;;;\n14375;EGYPTIAN HIEROGLYPH-14375;Lo;0;L;;;;;N;;;;;\n14376;EGYPTIAN HIEROGLYPH-14376;Lo;0;L;;;;;N;;;;;\n14377;EGYPTIAN HIEROGLYPH-14377;Lo;0;L;;;;;N;;;;;\n14378;EGYPTIAN HIEROGLYPH-14378;Lo;0;L;;;;;N;;;;;\n14379;EGYPTIAN HIEROGLYPH-14379;Lo;0;L;;;;;N;;;;;\n1437A;EGYPTIAN HIEROGLYPH-1437A;Lo;0;L;;;;;N;;;;;\n1437B;EGYPTIAN HIEROGLYPH-1437B;Lo;0;L;;;;;N;;;;;\n1437C;EGYPTIAN HIEROGLYPH-1437C;Lo;0;L;;;;;N;;;;;\n1437D;EGYPTIAN HIEROGLYPH-1437D;Lo;0;L;;;;;N;;;;;\n1437E;EGYPTIAN HIEROGLYPH-1437E;Lo;0;L;;;;;N;;;;;\n1437F;EGYPTIAN HIEROGLYPH-1437F;Lo;0;L;;;;;N;;;;;\n14380;EGYPTIAN HIEROGLYPH-14380;Lo;0;L;;;;;N;;;;;\n14381;EGYPTIAN HIEROGLYPH-14381;Lo;0;L;;;;;N;;;;;\n14382;EGYPTIAN HIEROGLYPH-14382;Lo;0;L;;;;;N;;;;;\n14383;EGYPTIAN HIEROGLYPH-14383;Lo;0;L;;;;;N;;;;;\n14384;EGYPTIAN HIEROGLYPH-14384;Lo;0;L;;;;;N;;;;;\n14385;EGYPTIAN HIEROGLYPH-14385;Lo;0;L;;;;;N;;;;;\n14386;EGYPTIAN HIEROGLYPH-14386;Lo;0;L;;;;;N;;;;;\n14387;EGYPTIAN HIEROGLYPH-14387;Lo;0;L;;;;;N;;;;;\n14388;EGYPTIAN HIEROGLYPH-14388;Lo;0;L;;;;;N;;;;;\n14389;EGYPTIAN HIEROGLYPH-14389;Lo;0;L;;;;;N;;;;;\n1438A;EGYPTIAN HIEROGLYPH-1438A;Lo;0;L;;;;;N;;;;;\n1438B;EGYPTIAN HIEROGLYPH-1438B;Lo;0;L;;;;;N;;;;;\n1438C;EGYPTIAN HIEROGLYPH-1438C;Lo;0;L;;;;;N;;;;;\n1438D;EGYPTIAN HIEROGLYPH-1438D;Lo;0;L;;;;;N;;;;;\n1438E;EGYPTIAN HIEROGLYPH-1438E;Lo;0;L;;;;;N;;;;;\n1438F;EGYPTIAN HIEROGLYPH-1438F;Lo;0;L;;;;;N;;;;;\n14390;EGYPTIAN HIEROGLYPH-14390;Lo;0;L;;;;;N;;;;;\n14391;EGYPTIAN HIEROGLYPH-14391;Lo;0;L;;;;;N;;;;;\n14392;EGYPTIAN HIEROGLYPH-14392;Lo;0;L;;;;;N;;;;;\n14393;EGYPTIAN HIEROGLYPH-14393;Lo;0;L;;;;;N;;;;;\n14394;EGYPTIAN HIEROGLYPH-14394;Lo;0;L;;;;;N;;;;;\n14395;EGYPTIAN HIEROGLYPH-14395;Lo;0;L;;;;;N;;;;;\n14396;EGYPTIAN HIEROGLYPH-14396;Lo;0;L;;;;;N;;;;;\n14397;EGYPTIAN HIEROGLYPH-14397;Lo;0;L;;;;;N;;;;;\n14398;EGYPTIAN HIEROGLYPH-14398;Lo;0;L;;;;;N;;;;;\n14399;EGYPTIAN HIEROGLYPH-14399;Lo;0;L;;;;;N;;;;;\n1439A;EGYPTIAN HIEROGLYPH-1439A;Lo;0;L;;;;;N;;;;;\n1439B;EGYPTIAN HIEROGLYPH-1439B;Lo;0;L;;;;;N;;;;;\n1439C;EGYPTIAN HIEROGLYPH-1439C;Lo;0;L;;;;;N;;;;;\n1439D;EGYPTIAN HIEROGLYPH-1439D;Lo;0;L;;;;;N;;;;;\n1439E;EGYPTIAN HIEROGLYPH-1439E;Lo;0;L;;;;;N;;;;;\n1439F;EGYPTIAN HIEROGLYPH-1439F;Lo;0;L;;;;;N;;;;;\n143A0;EGYPTIAN HIEROGLYPH-143A0;Lo;0;L;;;;;N;;;;;\n143A1;EGYPTIAN HIEROGLYPH-143A1;Lo;0;L;;;;;N;;;;;\n143A2;EGYPTIAN HIEROGLYPH-143A2;Lo;0;L;;;;;N;;;;;\n143A3;EGYPTIAN HIEROGLYPH-143A3;Lo;0;L;;;;;N;;;;;\n143A4;EGYPTIAN HIEROGLYPH-143A4;Lo;0;L;;;;;N;;;;;\n143A5;EGYPTIAN HIEROGLYPH-143A5;Lo;0;L;;;;;N;;;;;\n143A6;EGYPTIAN HIEROGLYPH-143A6;Lo;0;L;;;;;N;;;;;\n143A7;EGYPTIAN HIEROGLYPH-143A7;Lo;0;L;;;;;N;;;;;\n143A8;EGYPTIAN HIEROGLYPH-143A8;Lo;0;L;;;;;N;;;;;\n143A9;EGYPTIAN HIEROGLYPH-143A9;Lo;0;L;;;;;N;;;;;\n143AA;EGYPTIAN HIEROGLYPH-143AA;Lo;0;L;;;;;N;;;;;\n143AB;EGYPTIAN HIEROGLYPH-143AB;Lo;0;L;;;;;N;;;;;\n143AC;EGYPTIAN HIEROGLYPH-143AC;Lo;0;L;;;;;N;;;;;\n143AD;EGYPTIAN HIEROGLYPH-143AD;Lo;0;L;;;;;N;;;;;\n143AE;EGYPTIAN HIEROGLYPH-143AE;Lo;0;L;;;;;N;;;;;\n143AF;EGYPTIAN HIEROGLYPH-143AF;Lo;0;L;;;;;N;;;;;\n143B0;EGYPTIAN HIEROGLYPH-143B0;Lo;0;L;;;;;N;;;;;\n143B1;EGYPTIAN HIEROGLYPH-143B1;Lo;0;L;;;;;N;;;;;\n143B2;EGYPTIAN HIEROGLYPH-143B2;Lo;0;L;;;;;N;;;;;\n143B3;EGYPTIAN HIEROGLYPH-143B3;Lo;0;L;;;;;N;;;;;\n143B4;EGYPTIAN HIEROGLYPH-143B4;Lo;0;L;;;;;N;;;;;\n143B5;EGYPTIAN HIEROGLYPH-143B5;Lo;0;L;;;;;N;;;;;\n143B6;EGYPTIAN HIEROGLYPH-143B6;Lo;0;L;;;;;N;;;;;\n143B7;EGYPTIAN HIEROGLYPH-143B7;Lo;0;L;;;;;N;;;;;\n143B8;EGYPTIAN HIEROGLYPH-143B8;Lo;0;L;;;;;N;;;;;\n143B9;EGYPTIAN HIEROGLYPH-143B9;Lo;0;L;;;;;N;;;;;\n143BA;EGYPTIAN HIEROGLYPH-143BA;Lo;0;L;;;;;N;;;;;\n143BB;EGYPTIAN HIEROGLYPH-143BB;Lo;0;L;;;;;N;;;;;\n143BC;EGYPTIAN HIEROGLYPH-143BC;Lo;0;L;;;;;N;;;;;\n143BD;EGYPTIAN HIEROGLYPH-143BD;Lo;0;L;;;;;N;;;;;\n143BE;EGYPTIAN HIEROGLYPH-143BE;Lo;0;L;;;;;N;;;;;\n143BF;EGYPTIAN HIEROGLYPH-143BF;Lo;0;L;;;;;N;;;;;\n143C0;EGYPTIAN HIEROGLYPH-143C0;Lo;0;L;;;;;N;;;;;\n143C1;EGYPTIAN HIEROGLYPH-143C1;Lo;0;L;;;;;N;;;;;\n143C2;EGYPTIAN HIEROGLYPH-143C2;Lo;0;L;;;;;N;;;;;\n143C3;EGYPTIAN HIEROGLYPH-143C3;Lo;0;L;;;;;N;;;;;\n143C4;EGYPTIAN HIEROGLYPH-143C4;Lo;0;L;;;;;N;;;;;\n143C5;EGYPTIAN HIEROGLYPH-143C5;Lo;0;L;;;;;N;;;;;\n143C6;EGYPTIAN HIEROGLYPH-143C6;Lo;0;L;;;;;N;;;;;\n143C7;EGYPTIAN HIEROGLYPH-143C7;Lo;0;L;;;;;N;;;;;\n143C8;EGYPTIAN HIEROGLYPH-143C8;Lo;0;L;;;;;N;;;;;\n143C9;EGYPTIAN HIEROGLYPH-143C9;Lo;0;L;;;;;N;;;;;\n143CA;EGYPTIAN HIEROGLYPH-143CA;Lo;0;L;;;;;N;;;;;\n143CB;EGYPTIAN HIEROGLYPH-143CB;Lo;0;L;;;;;N;;;;;\n143CC;EGYPTIAN HIEROGLYPH-143CC;Lo;0;L;;;;;N;;;;;\n143CD;EGYPTIAN HIEROGLYPH-143CD;Lo;0;L;;;;;N;;;;;\n143CE;EGYPTIAN HIEROGLYPH-143CE;Lo;0;L;;;;;N;;;;;\n143CF;EGYPTIAN HIEROGLYPH-143CF;Lo;0;L;;;;;N;;;;;\n143D0;EGYPTIAN HIEROGLYPH-143D0;Lo;0;L;;;;;N;;;;;\n143D1;EGYPTIAN HIEROGLYPH-143D1;Lo;0;L;;;;;N;;;;;\n143D2;EGYPTIAN HIEROGLYPH-143D2;Lo;0;L;;;;;N;;;;;\n143D3;EGYPTIAN HIEROGLYPH-143D3;Lo;0;L;;;;;N;;;;;\n143D4;EGYPTIAN HIEROGLYPH-143D4;Lo;0;L;;;;;N;;;;;\n143D5;EGYPTIAN HIEROGLYPH-143D5;Lo;0;L;;;;;N;;;;;\n143D6;EGYPTIAN HIEROGLYPH-143D6;Lo;0;L;;;;;N;;;;;\n143D7;EGYPTIAN HIEROGLYPH-143D7;Lo;0;L;;;;;N;;;;;\n143D8;EGYPTIAN HIEROGLYPH-143D8;Lo;0;L;;;;;N;;;;;\n143D9;EGYPTIAN HIEROGLYPH-143D9;Lo;0;L;;;;;N;;;;;\n143DA;EGYPTIAN HIEROGLYPH-143DA;Lo;0;L;;;;;N;;;;;\n143DB;EGYPTIAN HIEROGLYPH-143DB;Lo;0;L;;;;;N;;;;;\n143DC;EGYPTIAN HIEROGLYPH-143DC;Lo;0;L;;;;;N;;;;;\n143DD;EGYPTIAN HIEROGLYPH-143DD;Lo;0;L;;;;;N;;;;;\n143DE;EGYPTIAN HIEROGLYPH-143DE;Lo;0;L;;;;;N;;;;;\n143DF;EGYPTIAN HIEROGLYPH-143DF;Lo;0;L;;;;;N;;;;;\n143E0;EGYPTIAN HIEROGLYPH-143E0;Lo;0;L;;;;;N;;;;;\n143E1;EGYPTIAN HIEROGLYPH-143E1;Lo;0;L;;;;;N;;;;;\n143E2;EGYPTIAN HIEROGLYPH-143E2;Lo;0;L;;;;;N;;;;;\n143E3;EGYPTIAN HIEROGLYPH-143E3;Lo;0;L;;;;;N;;;;;\n143E4;EGYPTIAN HIEROGLYPH-143E4;Lo;0;L;;;;;N;;;;;\n143E5;EGYPTIAN HIEROGLYPH-143E5;Lo;0;L;;;;;N;;;;;\n143E6;EGYPTIAN HIEROGLYPH-143E6;Lo;0;L;;;;;N;;;;;\n143E7;EGYPTIAN HIEROGLYPH-143E7;Lo;0;L;;;;;N;;;;;\n143E8;EGYPTIAN HIEROGLYPH-143E8;Lo;0;L;;;;;N;;;;;\n143E9;EGYPTIAN HIEROGLYPH-143E9;Lo;0;L;;;;;N;;;;;\n143EA;EGYPTIAN HIEROGLYPH-143EA;Lo;0;L;;;;;N;;;;;\n143EB;EGYPTIAN HIEROGLYPH-143EB;Lo;0;L;;;;;N;;;;;\n143EC;EGYPTIAN HIEROGLYPH-143EC;Lo;0;L;;;;;N;;;;;\n143ED;EGYPTIAN HIEROGLYPH-143ED;Lo;0;L;;;;;N;;;;;\n143EE;EGYPTIAN HIEROGLYPH-143EE;Lo;0;L;;;;;N;;;;;\n143EF;EGYPTIAN HIEROGLYPH-143EF;Lo;0;L;;;;;N;;;;;\n143F0;EGYPTIAN HIEROGLYPH-143F0;Lo;0;L;;;;;N;;;;;\n143F1;EGYPTIAN HIEROGLYPH-143F1;Lo;0;L;;;;;N;;;;;\n143F2;EGYPTIAN HIEROGLYPH-143F2;Lo;0;L;;;;;N;;;;;\n143F3;EGYPTIAN HIEROGLYPH-143F3;Lo;0;L;;;;;N;;;;;\n143F4;EGYPTIAN HIEROGLYPH-143F4;Lo;0;L;;;;;N;;;;;\n143F5;EGYPTIAN HIEROGLYPH-143F5;Lo;0;L;;;;;N;;;;;\n143F6;EGYPTIAN HIEROGLYPH-143F6;Lo;0;L;;;;;N;;;;;\n143F7;EGYPTIAN HIEROGLYPH-143F7;Lo;0;L;;;;;N;;;;;\n143F8;EGYPTIAN HIEROGLYPH-143F8;Lo;0;L;;;;;N;;;;;\n143F9;EGYPTIAN HIEROGLYPH-143F9;Lo;0;L;;;;;N;;;;;\n143FA;EGYPTIAN HIEROGLYPH-143FA;Lo;0;L;;;;;N;;;;;\n14400;ANATOLIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;;\n14401;ANATOLIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;;\n14402;ANATOLIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;;\n14403;ANATOLIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;;\n14404;ANATOLIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;;\n14405;ANATOLIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;;\n14406;ANATOLIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;;\n14407;ANATOLIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;;\n14408;ANATOLIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;;\n14409;ANATOLIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;;\n1440A;ANATOLIAN HIEROGLYPH A010A;Lo;0;L;;;;;N;;;;;\n1440B;ANATOLIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;;\n1440C;ANATOLIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;;\n1440D;ANATOLIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;;\n1440E;ANATOLIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;;\n1440F;ANATOLIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;;\n14410;ANATOLIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;;\n14411;ANATOLIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;;\n14412;ANATOLIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;;\n14413;ANATOLIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;;\n14414;ANATOLIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;;\n14415;ANATOLIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;;\n14416;ANATOLIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;;\n14417;ANATOLIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;;\n14418;ANATOLIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;;\n14419;ANATOLIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;;\n1441A;ANATOLIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;;\n1441B;ANATOLIAN HIEROGLYPH A026A;Lo;0;L;;;;;N;;;;;\n1441C;ANATOLIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;;\n1441D;ANATOLIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;;\n1441E;ANATOLIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;;\n1441F;ANATOLIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;;\n14420;ANATOLIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;;\n14421;ANATOLIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;;\n14422;ANATOLIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;;\n14423;ANATOLIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;;\n14424;ANATOLIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;;\n14425;ANATOLIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;;\n14426;ANATOLIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;;\n14427;ANATOLIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;;\n14428;ANATOLIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;;\n14429;ANATOLIAN HIEROGLYPH A039A;Lo;0;L;;;;;N;;;;;\n1442A;ANATOLIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;;\n1442B;ANATOLIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;;\n1442C;ANATOLIAN HIEROGLYPH A041A;Lo;0;L;;;;;N;;;;;\n1442D;ANATOLIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;;\n1442E;ANATOLIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;;\n1442F;ANATOLIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;;\n14430;ANATOLIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;;\n14431;ANATOLIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;;\n14432;ANATOLIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;;\n14433;ANATOLIAN HIEROGLYPH A046A;Lo;0;L;;;;;N;;;;;\n14434;ANATOLIAN HIEROGLYPH A046B;Lo;0;L;;;;;N;;;;;\n14435;ANATOLIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;;\n14436;ANATOLIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;;\n14437;ANATOLIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;;\n14438;ANATOLIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;;\n14439;ANATOLIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;;\n1443A;ANATOLIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;;\n1443B;ANATOLIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;;\n1443C;ANATOLIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;;\n1443D;ANATOLIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;;\n1443E;ANATOLIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;;\n1443F;ANATOLIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;;\n14440;ANATOLIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;;\n14441;ANATOLIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;;\n14442;ANATOLIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;;\n14443;ANATOLIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;;\n14444;ANATOLIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;;\n14445;ANATOLIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;;\n14446;ANATOLIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;;\n14447;ANATOLIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;;\n14448;ANATOLIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;;\n14449;ANATOLIAN HIEROGLYPH A066A;Lo;0;L;;;;;N;;;;;\n1444A;ANATOLIAN HIEROGLYPH A066B;Lo;0;L;;;;;N;;;;;\n1444B;ANATOLIAN HIEROGLYPH A066C;Lo;0;L;;;;;N;;;;;\n1444C;ANATOLIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;;\n1444D;ANATOLIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;;\n1444E;ANATOLIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;;\n1444F;ANATOLIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;;\n14450;ANATOLIAN HIEROGLYPH A071;Lo;0;L;;;;;N;;;;;\n14451;ANATOLIAN HIEROGLYPH A072;Lo;0;L;;;;;N;;;;;\n14452;ANATOLIAN HIEROGLYPH A073;Lo;0;L;;;;;N;;;;;\n14453;ANATOLIAN HIEROGLYPH A074;Lo;0;L;;;;;N;;;;;\n14454;ANATOLIAN HIEROGLYPH A075;Lo;0;L;;;;;N;;;;;\n14455;ANATOLIAN HIEROGLYPH A076;Lo;0;L;;;;;N;;;;;\n14456;ANATOLIAN HIEROGLYPH A077;Lo;0;L;;;;;N;;;;;\n14457;ANATOLIAN HIEROGLYPH A078;Lo;0;L;;;;;N;;;;;\n14458;ANATOLIAN HIEROGLYPH A079;Lo;0;L;;;;;N;;;;;\n14459;ANATOLIAN HIEROGLYPH A080;Lo;0;L;;;;;N;;;;;\n1445A;ANATOLIAN HIEROGLYPH A081;Lo;0;L;;;;;N;;;;;\n1445B;ANATOLIAN HIEROGLYPH A082;Lo;0;L;;;;;N;;;;;\n1445C;ANATOLIAN HIEROGLYPH A083;Lo;0;L;;;;;N;;;;;\n1445D;ANATOLIAN HIEROGLYPH A084;Lo;0;L;;;;;N;;;;;\n1445E;ANATOLIAN HIEROGLYPH A085;Lo;0;L;;;;;N;;;;;\n1445F;ANATOLIAN HIEROGLYPH A086;Lo;0;L;;;;;N;;;;;\n14460;ANATOLIAN HIEROGLYPH A087;Lo;0;L;;;;;N;;;;;\n14461;ANATOLIAN HIEROGLYPH A088;Lo;0;L;;;;;N;;;;;\n14462;ANATOLIAN HIEROGLYPH A089;Lo;0;L;;;;;N;;;;;\n14463;ANATOLIAN HIEROGLYPH A090;Lo;0;L;;;;;N;;;;;\n14464;ANATOLIAN HIEROGLYPH A091;Lo;0;L;;;;;N;;;;;\n14465;ANATOLIAN HIEROGLYPH A092;Lo;0;L;;;;;N;;;;;\n14466;ANATOLIAN HIEROGLYPH A093;Lo;0;L;;;;;N;;;;;\n14467;ANATOLIAN HIEROGLYPH A094;Lo;0;L;;;;;N;;;;;\n14468;ANATOLIAN HIEROGLYPH A095;Lo;0;L;;;;;N;;;;;\n14469;ANATOLIAN HIEROGLYPH A096;Lo;0;L;;;;;N;;;;;\n1446A;ANATOLIAN HIEROGLYPH A097;Lo;0;L;;;;;N;;;;;\n1446B;ANATOLIAN HIEROGLYPH A097A;Lo;0;L;;;;;N;;;;;\n1446C;ANATOLIAN HIEROGLYPH A098;Lo;0;L;;;;;N;;;;;\n1446D;ANATOLIAN HIEROGLYPH A098A;Lo;0;L;;;;;N;;;;;\n1446E;ANATOLIAN HIEROGLYPH A099;Lo;0;L;;;;;N;;;;;\n1446F;ANATOLIAN HIEROGLYPH A100;Lo;0;L;;;;;N;;;;;\n14470;ANATOLIAN HIEROGLYPH A100A;Lo;0;L;;;;;N;;;;;\n14471;ANATOLIAN HIEROGLYPH A101;Lo;0;L;;;;;N;;;;;\n14472;ANATOLIAN HIEROGLYPH A101A;Lo;0;L;;;;;N;;;;;\n14473;ANATOLIAN HIEROGLYPH A102;Lo;0;L;;;;;N;;;;;\n14474;ANATOLIAN HIEROGLYPH A102A;Lo;0;L;;;;;N;;;;;\n14475;ANATOLIAN HIEROGLYPH A103;Lo;0;L;;;;;N;;;;;\n14476;ANATOLIAN HIEROGLYPH A104;Lo;0;L;;;;;N;;;;;\n14477;ANATOLIAN HIEROGLYPH A104A;Lo;0;L;;;;;N;;;;;\n14478;ANATOLIAN HIEROGLYPH A104B;Lo;0;L;;;;;N;;;;;\n14479;ANATOLIAN HIEROGLYPH A104C;Lo;0;L;;;;;N;;;;;\n1447A;ANATOLIAN HIEROGLYPH A105;Lo;0;L;;;;;N;;;;;\n1447B;ANATOLIAN HIEROGLYPH A105A;Lo;0;L;;;;;N;;;;;\n1447C;ANATOLIAN HIEROGLYPH A105B;Lo;0;L;;;;;N;;;;;\n1447D;ANATOLIAN HIEROGLYPH A106;Lo;0;L;;;;;N;;;;;\n1447E;ANATOLIAN HIEROGLYPH A107;Lo;0;L;;;;;N;;;;;\n1447F;ANATOLIAN HIEROGLYPH A107A;Lo;0;L;;;;;N;;;;;\n14480;ANATOLIAN HIEROGLYPH A107B;Lo;0;L;;;;;N;;;;;\n14481;ANATOLIAN HIEROGLYPH A107C;Lo;0;L;;;;;N;;;;;\n14482;ANATOLIAN HIEROGLYPH A108;Lo;0;L;;;;;N;;;;;\n14483;ANATOLIAN HIEROGLYPH A109;Lo;0;L;;;;;N;;;;;\n14484;ANATOLIAN HIEROGLYPH A110;Lo;0;L;;;;;N;;;;;\n14485;ANATOLIAN HIEROGLYPH A110A;Lo;0;L;;;;;N;;;;;\n14486;ANATOLIAN HIEROGLYPH A110B;Lo;0;L;;;;;N;;;;;\n14487;ANATOLIAN HIEROGLYPH A111;Lo;0;L;;;;;N;;;;;\n14488;ANATOLIAN HIEROGLYPH A112;Lo;0;L;;;;;N;;;;;\n14489;ANATOLIAN HIEROGLYPH A113;Lo;0;L;;;;;N;;;;;\n1448A;ANATOLIAN HIEROGLYPH A114;Lo;0;L;;;;;N;;;;;\n1448B;ANATOLIAN HIEROGLYPH A115;Lo;0;L;;;;;N;;;;;\n1448C;ANATOLIAN HIEROGLYPH A115A;Lo;0;L;;;;;N;;;;;\n1448D;ANATOLIAN HIEROGLYPH A116;Lo;0;L;;;;;N;;;;;\n1448E;ANATOLIAN HIEROGLYPH A117;Lo;0;L;;;;;N;;;;;\n1448F;ANATOLIAN HIEROGLYPH A118;Lo;0;L;;;;;N;;;;;\n14490;ANATOLIAN HIEROGLYPH A119;Lo;0;L;;;;;N;;;;;\n14491;ANATOLIAN HIEROGLYPH A120;Lo;0;L;;;;;N;;;;;\n14492;ANATOLIAN HIEROGLYPH A121;Lo;0;L;;;;;N;;;;;\n14493;ANATOLIAN HIEROGLYPH A122;Lo;0;L;;;;;N;;;;;\n14494;ANATOLIAN HIEROGLYPH A123;Lo;0;L;;;;;N;;;;;\n14495;ANATOLIAN HIEROGLYPH A124;Lo;0;L;;;;;N;;;;;\n14496;ANATOLIAN HIEROGLYPH A125;Lo;0;L;;;;;N;;;;;\n14497;ANATOLIAN HIEROGLYPH A125A;Lo;0;L;;;;;N;;;;;\n14498;ANATOLIAN HIEROGLYPH A126;Lo;0;L;;;;;N;;;;;\n14499;ANATOLIAN HIEROGLYPH A127;Lo;0;L;;;;;N;;;;;\n1449A;ANATOLIAN HIEROGLYPH A128;Lo;0;L;;;;;N;;;;;\n1449B;ANATOLIAN HIEROGLYPH A129;Lo;0;L;;;;;N;;;;;\n1449C;ANATOLIAN HIEROGLYPH A130;Lo;0;L;;;;;N;;;;;\n1449D;ANATOLIAN HIEROGLYPH A131;Lo;0;L;;;;;N;;;;;\n1449E;ANATOLIAN HIEROGLYPH A132;Lo;0;L;;;;;N;;;;;\n1449F;ANATOLIAN HIEROGLYPH A133;Lo;0;L;;;;;N;;;;;\n144A0;ANATOLIAN HIEROGLYPH A134;Lo;0;L;;;;;N;;;;;\n144A1;ANATOLIAN HIEROGLYPH A135;Lo;0;L;;;;;N;;;;;\n144A2;ANATOLIAN HIEROGLYPH A135A;Lo;0;L;;;;;N;;;;;\n144A3;ANATOLIAN HIEROGLYPH A136;Lo;0;L;;;;;N;;;;;\n144A4;ANATOLIAN HIEROGLYPH A137;Lo;0;L;;;;;N;;;;;\n144A5;ANATOLIAN HIEROGLYPH A138;Lo;0;L;;;;;N;;;;;\n144A6;ANATOLIAN HIEROGLYPH A139;Lo;0;L;;;;;N;;;;;\n144A7;ANATOLIAN HIEROGLYPH A140;Lo;0;L;;;;;N;;;;;\n144A8;ANATOLIAN HIEROGLYPH A141;Lo;0;L;;;;;N;;;;;\n144A9;ANATOLIAN HIEROGLYPH A142;Lo;0;L;;;;;N;;;;;\n144AA;ANATOLIAN HIEROGLYPH A143;Lo;0;L;;;;;N;;;;;\n144AB;ANATOLIAN HIEROGLYPH A144;Lo;0;L;;;;;N;;;;;\n144AC;ANATOLIAN HIEROGLYPH A145;Lo;0;L;;;;;N;;;;;\n144AD;ANATOLIAN HIEROGLYPH A146;Lo;0;L;;;;;N;;;;;\n144AE;ANATOLIAN HIEROGLYPH A147;Lo;0;L;;;;;N;;;;;\n144AF;ANATOLIAN HIEROGLYPH A148;Lo;0;L;;;;;N;;;;;\n144B0;ANATOLIAN HIEROGLYPH A149;Lo;0;L;;;;;N;;;;;\n144B1;ANATOLIAN HIEROGLYPH A150;Lo;0;L;;;;;N;;;;;\n144B2;ANATOLIAN HIEROGLYPH A151;Lo;0;L;;;;;N;;;;;\n144B3;ANATOLIAN HIEROGLYPH A152;Lo;0;L;;;;;N;;;;;\n144B4;ANATOLIAN HIEROGLYPH A153;Lo;0;L;;;;;N;;;;;\n144B5;ANATOLIAN HIEROGLYPH A154;Lo;0;L;;;;;N;;;;;\n144B6;ANATOLIAN HIEROGLYPH A155;Lo;0;L;;;;;N;;;;;\n144B7;ANATOLIAN HIEROGLYPH A156;Lo;0;L;;;;;N;;;;;\n144B8;ANATOLIAN HIEROGLYPH A157;Lo;0;L;;;;;N;;;;;\n144B9;ANATOLIAN HIEROGLYPH A158;Lo;0;L;;;;;N;;;;;\n144BA;ANATOLIAN HIEROGLYPH A159;Lo;0;L;;;;;N;;;;;\n144BB;ANATOLIAN HIEROGLYPH A160;Lo;0;L;;;;;N;;;;;\n144BC;ANATOLIAN HIEROGLYPH A161;Lo;0;L;;;;;N;;;;;\n144BD;ANATOLIAN HIEROGLYPH A162;Lo;0;L;;;;;N;;;;;\n144BE;ANATOLIAN HIEROGLYPH A163;Lo;0;L;;;;;N;;;;;\n144BF;ANATOLIAN HIEROGLYPH A164;Lo;0;L;;;;;N;;;;;\n144C0;ANATOLIAN HIEROGLYPH A165;Lo;0;L;;;;;N;;;;;\n144C1;ANATOLIAN HIEROGLYPH A166;Lo;0;L;;;;;N;;;;;\n144C2;ANATOLIAN HIEROGLYPH A167;Lo;0;L;;;;;N;;;;;\n144C3;ANATOLIAN HIEROGLYPH A168;Lo;0;L;;;;;N;;;;;\n144C4;ANATOLIAN HIEROGLYPH A169;Lo;0;L;;;;;N;;;;;\n144C5;ANATOLIAN HIEROGLYPH A170;Lo;0;L;;;;;N;;;;;\n144C6;ANATOLIAN HIEROGLYPH A171;Lo;0;L;;;;;N;;;;;\n144C7;ANATOLIAN HIEROGLYPH A172;Lo;0;L;;;;;N;;;;;\n144C8;ANATOLIAN HIEROGLYPH A173;Lo;0;L;;;;;N;;;;;\n144C9;ANATOLIAN HIEROGLYPH A174;Lo;0;L;;;;;N;;;;;\n144CA;ANATOLIAN HIEROGLYPH A175;Lo;0;L;;;;;N;;;;;\n144CB;ANATOLIAN HIEROGLYPH A176;Lo;0;L;;;;;N;;;;;\n144CC;ANATOLIAN HIEROGLYPH A177;Lo;0;L;;;;;N;;;;;\n144CD;ANATOLIAN HIEROGLYPH A178;Lo;0;L;;;;;N;;;;;\n144CE;ANATOLIAN HIEROGLYPH A179;Lo;0;L;;;;;N;;;;;\n144CF;ANATOLIAN HIEROGLYPH A180;Lo;0;L;;;;;N;;;;;\n144D0;ANATOLIAN HIEROGLYPH A181;Lo;0;L;;;;;N;;;;;\n144D1;ANATOLIAN HIEROGLYPH A182;Lo;0;L;;;;;N;;;;;\n144D2;ANATOLIAN HIEROGLYPH A183;Lo;0;L;;;;;N;;;;;\n144D3;ANATOLIAN HIEROGLYPH A184;Lo;0;L;;;;;N;;;;;\n144D4;ANATOLIAN HIEROGLYPH A185;Lo;0;L;;;;;N;;;;;\n144D5;ANATOLIAN HIEROGLYPH A186;Lo;0;L;;;;;N;;;;;\n144D6;ANATOLIAN HIEROGLYPH A187;Lo;0;L;;;;;N;;;;;\n144D7;ANATOLIAN HIEROGLYPH A188;Lo;0;L;;;;;N;;;;;\n144D8;ANATOLIAN HIEROGLYPH A189;Lo;0;L;;;;;N;;;;;\n144D9;ANATOLIAN HIEROGLYPH A190;Lo;0;L;;;;;N;;;;;\n144DA;ANATOLIAN HIEROGLYPH A191;Lo;0;L;;;;;N;;;;;\n144DB;ANATOLIAN HIEROGLYPH A192;Lo;0;L;;;;;N;;;;;\n144DC;ANATOLIAN HIEROGLYPH A193;Lo;0;L;;;;;N;;;;;\n144DD;ANATOLIAN HIEROGLYPH A194;Lo;0;L;;;;;N;;;;;\n144DE;ANATOLIAN HIEROGLYPH A195;Lo;0;L;;;;;N;;;;;\n144DF;ANATOLIAN HIEROGLYPH A196;Lo;0;L;;;;;N;;;;;\n144E0;ANATOLIAN HIEROGLYPH A197;Lo;0;L;;;;;N;;;;;\n144E1;ANATOLIAN HIEROGLYPH A198;Lo;0;L;;;;;N;;;;;\n144E2;ANATOLIAN HIEROGLYPH A199;Lo;0;L;;;;;N;;;;;\n144E3;ANATOLIAN HIEROGLYPH A200;Lo;0;L;;;;;N;;;;;\n144E4;ANATOLIAN HIEROGLYPH A201;Lo;0;L;;;;;N;;;;;\n144E5;ANATOLIAN HIEROGLYPH A202;Lo;0;L;;;;;N;;;;;\n144E6;ANATOLIAN HIEROGLYPH A202A;Lo;0;L;;;;;N;;;;;\n144E7;ANATOLIAN HIEROGLYPH A202B;Lo;0;L;;;;;N;;;;;\n144E8;ANATOLIAN HIEROGLYPH A203;Lo;0;L;;;;;N;;;;;\n144E9;ANATOLIAN HIEROGLYPH A204;Lo;0;L;;;;;N;;;;;\n144EA;ANATOLIAN HIEROGLYPH A205;Lo;0;L;;;;;N;;;;;\n144EB;ANATOLIAN HIEROGLYPH A206;Lo;0;L;;;;;N;;;;;\n144EC;ANATOLIAN HIEROGLYPH A207;Lo;0;L;;;;;N;;;;;\n144ED;ANATOLIAN HIEROGLYPH A207A;Lo;0;L;;;;;N;;;;;\n144EE;ANATOLIAN HIEROGLYPH A208;Lo;0;L;;;;;N;;;;;\n144EF;ANATOLIAN HIEROGLYPH A209;Lo;0;L;;;;;N;;;;;\n144F0;ANATOLIAN HIEROGLYPH A209A;Lo;0;L;;;;;N;;;;;\n144F1;ANATOLIAN HIEROGLYPH A210;Lo;0;L;;;;;N;;;;;\n144F2;ANATOLIAN HIEROGLYPH A211;Lo;0;L;;;;;N;;;;;\n144F3;ANATOLIAN HIEROGLYPH A212;Lo;0;L;;;;;N;;;;;\n144F4;ANATOLIAN HIEROGLYPH A213;Lo;0;L;;;;;N;;;;;\n144F5;ANATOLIAN HIEROGLYPH A214;Lo;0;L;;;;;N;;;;;\n144F6;ANATOLIAN HIEROGLYPH A215;Lo;0;L;;;;;N;;;;;\n144F7;ANATOLIAN HIEROGLYPH A215A;Lo;0;L;;;;;N;;;;;\n144F8;ANATOLIAN HIEROGLYPH A216;Lo;0;L;;;;;N;;;;;\n144F9;ANATOLIAN HIEROGLYPH A216A;Lo;0;L;;;;;N;;;;;\n144FA;ANATOLIAN HIEROGLYPH A217;Lo;0;L;;;;;N;;;;;\n144FB;ANATOLIAN HIEROGLYPH A218;Lo;0;L;;;;;N;;;;;\n144FC;ANATOLIAN HIEROGLYPH A219;Lo;0;L;;;;;N;;;;;\n144FD;ANATOLIAN HIEROGLYPH A220;Lo;0;L;;;;;N;;;;;\n144FE;ANATOLIAN HIEROGLYPH A221;Lo;0;L;;;;;N;;;;;\n144FF;ANATOLIAN HIEROGLYPH A222;Lo;0;L;;;;;N;;;;;\n14500;ANATOLIAN HIEROGLYPH A223;Lo;0;L;;;;;N;;;;;\n14501;ANATOLIAN HIEROGLYPH A224;Lo;0;L;;;;;N;;;;;\n14502;ANATOLIAN HIEROGLYPH A225;Lo;0;L;;;;;N;;;;;\n14503;ANATOLIAN HIEROGLYPH A226;Lo;0;L;;;;;N;;;;;\n14504;ANATOLIAN HIEROGLYPH A227;Lo;0;L;;;;;N;;;;;\n14505;ANATOLIAN HIEROGLYPH A227A;Lo;0;L;;;;;N;;;;;\n14506;ANATOLIAN HIEROGLYPH A228;Lo;0;L;;;;;N;;;;;\n14507;ANATOLIAN HIEROGLYPH A229;Lo;0;L;;;;;N;;;;;\n14508;ANATOLIAN HIEROGLYPH A230;Lo;0;L;;;;;N;;;;;\n14509;ANATOLIAN HIEROGLYPH A231;Lo;0;L;;;;;N;;;;;\n1450A;ANATOLIAN HIEROGLYPH A232;Lo;0;L;;;;;N;;;;;\n1450B;ANATOLIAN HIEROGLYPH A233;Lo;0;L;;;;;N;;;;;\n1450C;ANATOLIAN HIEROGLYPH A234;Lo;0;L;;;;;N;;;;;\n1450D;ANATOLIAN HIEROGLYPH A235;Lo;0;L;;;;;N;;;;;\n1450E;ANATOLIAN HIEROGLYPH A236;Lo;0;L;;;;;N;;;;;\n1450F;ANATOLIAN HIEROGLYPH A237;Lo;0;L;;;;;N;;;;;\n14510;ANATOLIAN HIEROGLYPH A238;Lo;0;L;;;;;N;;;;;\n14511;ANATOLIAN HIEROGLYPH A239;Lo;0;L;;;;;N;;;;;\n14512;ANATOLIAN HIEROGLYPH A240;Lo;0;L;;;;;N;;;;;\n14513;ANATOLIAN HIEROGLYPH A241;Lo;0;L;;;;;N;;;;;\n14514;ANATOLIAN HIEROGLYPH A242;Lo;0;L;;;;;N;;;;;\n14515;ANATOLIAN HIEROGLYPH A243;Lo;0;L;;;;;N;;;;;\n14516;ANATOLIAN HIEROGLYPH A244;Lo;0;L;;;;;N;;;;;\n14517;ANATOLIAN HIEROGLYPH A245;Lo;0;L;;;;;N;;;;;\n14518;ANATOLIAN HIEROGLYPH A246;Lo;0;L;;;;;N;;;;;\n14519;ANATOLIAN HIEROGLYPH A247;Lo;0;L;;;;;N;;;;;\n1451A;ANATOLIAN HIEROGLYPH A248;Lo;0;L;;;;;N;;;;;\n1451B;ANATOLIAN HIEROGLYPH A249;Lo;0;L;;;;;N;;;;;\n1451C;ANATOLIAN HIEROGLYPH A250;Lo;0;L;;;;;N;;;;;\n1451D;ANATOLIAN HIEROGLYPH A251;Lo;0;L;;;;;N;;;;;\n1451E;ANATOLIAN HIEROGLYPH A252;Lo;0;L;;;;;N;;;;;\n1451F;ANATOLIAN HIEROGLYPH A253;Lo;0;L;;;;;N;;;;;\n14520;ANATOLIAN HIEROGLYPH A254;Lo;0;L;;;;;N;;;;;\n14521;ANATOLIAN HIEROGLYPH A255;Lo;0;L;;;;;N;;;;;\n14522;ANATOLIAN HIEROGLYPH A256;Lo;0;L;;;;;N;;;;;\n14523;ANATOLIAN HIEROGLYPH A257;Lo;0;L;;;;;N;;;;;\n14524;ANATOLIAN HIEROGLYPH A258;Lo;0;L;;;;;N;;;;;\n14525;ANATOLIAN HIEROGLYPH A259;Lo;0;L;;;;;N;;;;;\n14526;ANATOLIAN HIEROGLYPH A260;Lo;0;L;;;;;N;;;;;\n14527;ANATOLIAN HIEROGLYPH A261;Lo;0;L;;;;;N;;;;;\n14528;ANATOLIAN HIEROGLYPH A262;Lo;0;L;;;;;N;;;;;\n14529;ANATOLIAN HIEROGLYPH A263;Lo;0;L;;;;;N;;;;;\n1452A;ANATOLIAN HIEROGLYPH A264;Lo;0;L;;;;;N;;;;;\n1452B;ANATOLIAN HIEROGLYPH A265;Lo;0;L;;;;;N;;;;;\n1452C;ANATOLIAN HIEROGLYPH A266;Lo;0;L;;;;;N;;;;;\n1452D;ANATOLIAN HIEROGLYPH A267;Lo;0;L;;;;;N;;;;;\n1452E;ANATOLIAN HIEROGLYPH A267A;Lo;0;L;;;;;N;;;;;\n1452F;ANATOLIAN HIEROGLYPH A268;Lo;0;L;;;;;N;;;;;\n14530;ANATOLIAN HIEROGLYPH A269;Lo;0;L;;;;;N;;;;;\n14531;ANATOLIAN HIEROGLYPH A270;Lo;0;L;;;;;N;;;;;\n14532;ANATOLIAN HIEROGLYPH A271;Lo;0;L;;;;;N;;;;;\n14533;ANATOLIAN HIEROGLYPH A272;Lo;0;L;;;;;N;;;;;\n14534;ANATOLIAN HIEROGLYPH A273;Lo;0;L;;;;;N;;;;;\n14535;ANATOLIAN HIEROGLYPH A274;Lo;0;L;;;;;N;;;;;\n14536;ANATOLIAN HIEROGLYPH A275;Lo;0;L;;;;;N;;;;;\n14537;ANATOLIAN HIEROGLYPH A276;Lo;0;L;;;;;N;;;;;\n14538;ANATOLIAN HIEROGLYPH A277;Lo;0;L;;;;;N;;;;;\n14539;ANATOLIAN HIEROGLYPH A278;Lo;0;L;;;;;N;;;;;\n1453A;ANATOLIAN HIEROGLYPH A279;Lo;0;L;;;;;N;;;;;\n1453B;ANATOLIAN HIEROGLYPH A280;Lo;0;L;;;;;N;;;;;\n1453C;ANATOLIAN HIEROGLYPH A281;Lo;0;L;;;;;N;;;;;\n1453D;ANATOLIAN HIEROGLYPH A282;Lo;0;L;;;;;N;;;;;\n1453E;ANATOLIAN HIEROGLYPH A283;Lo;0;L;;;;;N;;;;;\n1453F;ANATOLIAN HIEROGLYPH A284;Lo;0;L;;;;;N;;;;;\n14540;ANATOLIAN HIEROGLYPH A285;Lo;0;L;;;;;N;;;;;\n14541;ANATOLIAN HIEROGLYPH A286;Lo;0;L;;;;;N;;;;;\n14542;ANATOLIAN HIEROGLYPH A287;Lo;0;L;;;;;N;;;;;\n14543;ANATOLIAN HIEROGLYPH A288;Lo;0;L;;;;;N;;;;;\n14544;ANATOLIAN HIEROGLYPH A289;Lo;0;L;;;;;N;;;;;\n14545;ANATOLIAN HIEROGLYPH A289A;Lo;0;L;;;;;N;;;;;\n14546;ANATOLIAN HIEROGLYPH A290;Lo;0;L;;;;;N;;;;;\n14547;ANATOLIAN HIEROGLYPH A291;Lo;0;L;;;;;N;;;;;\n14548;ANATOLIAN HIEROGLYPH A292;Lo;0;L;;;;;N;;;;;\n14549;ANATOLIAN HIEROGLYPH A293;Lo;0;L;;;;;N;;;;;\n1454A;ANATOLIAN HIEROGLYPH A294;Lo;0;L;;;;;N;;;;;\n1454B;ANATOLIAN HIEROGLYPH A294A;Lo;0;L;;;;;N;;;;;\n1454C;ANATOLIAN HIEROGLYPH A295;Lo;0;L;;;;;N;;;;;\n1454D;ANATOLIAN HIEROGLYPH A296;Lo;0;L;;;;;N;;;;;\n1454E;ANATOLIAN HIEROGLYPH A297;Lo;0;L;;;;;N;;;;;\n1454F;ANATOLIAN HIEROGLYPH A298;Lo;0;L;;;;;N;;;;;\n14550;ANATOLIAN HIEROGLYPH A299;Lo;0;L;;;;;N;;;;;\n14551;ANATOLIAN HIEROGLYPH A299A;Lo;0;L;;;;;N;;;;;\n14552;ANATOLIAN HIEROGLYPH A300;Lo;0;L;;;;;N;;;;;\n14553;ANATOLIAN HIEROGLYPH A301;Lo;0;L;;;;;N;;;;;\n14554;ANATOLIAN HIEROGLYPH A302;Lo;0;L;;;;;N;;;;;\n14555;ANATOLIAN HIEROGLYPH A303;Lo;0;L;;;;;N;;;;;\n14556;ANATOLIAN HIEROGLYPH A304;Lo;0;L;;;;;N;;;;;\n14557;ANATOLIAN HIEROGLYPH A305;Lo;0;L;;;;;N;;;;;\n14558;ANATOLIAN HIEROGLYPH A306;Lo;0;L;;;;;N;;;;;\n14559;ANATOLIAN HIEROGLYPH A307;Lo;0;L;;;;;N;;;;;\n1455A;ANATOLIAN HIEROGLYPH A308;Lo;0;L;;;;;N;;;;;\n1455B;ANATOLIAN HIEROGLYPH A309;Lo;0;L;;;;;N;;;;;\n1455C;ANATOLIAN HIEROGLYPH A309A;Lo;0;L;;;;;N;;;;;\n1455D;ANATOLIAN HIEROGLYPH A310;Lo;0;L;;;;;N;;;;;\n1455E;ANATOLIAN HIEROGLYPH A311;Lo;0;L;;;;;N;;;;;\n1455F;ANATOLIAN HIEROGLYPH A312;Lo;0;L;;;;;N;;;;;\n14560;ANATOLIAN HIEROGLYPH A313;Lo;0;L;;;;;N;;;;;\n14561;ANATOLIAN HIEROGLYPH A314;Lo;0;L;;;;;N;;;;;\n14562;ANATOLIAN HIEROGLYPH A315;Lo;0;L;;;;;N;;;;;\n14563;ANATOLIAN HIEROGLYPH A316;Lo;0;L;;;;;N;;;;;\n14564;ANATOLIAN HIEROGLYPH A317;Lo;0;L;;;;;N;;;;;\n14565;ANATOLIAN HIEROGLYPH A318;Lo;0;L;;;;;N;;;;;\n14566;ANATOLIAN HIEROGLYPH A319;Lo;0;L;;;;;N;;;;;\n14567;ANATOLIAN HIEROGLYPH A320;Lo;0;L;;;;;N;;;;;\n14568;ANATOLIAN HIEROGLYPH A321;Lo;0;L;;;;;N;;;;;\n14569;ANATOLIAN HIEROGLYPH A322;Lo;0;L;;;;;N;;;;;\n1456A;ANATOLIAN HIEROGLYPH A323;Lo;0;L;;;;;N;;;;;\n1456B;ANATOLIAN HIEROGLYPH A324;Lo;0;L;;;;;N;;;;;\n1456C;ANATOLIAN HIEROGLYPH A325;Lo;0;L;;;;;N;;;;;\n1456D;ANATOLIAN HIEROGLYPH A326;Lo;0;L;;;;;N;;;;;\n1456E;ANATOLIAN HIEROGLYPH A327;Lo;0;L;;;;;N;;;;;\n1456F;ANATOLIAN HIEROGLYPH A328;Lo;0;L;;;;;N;;;;;\n14570;ANATOLIAN HIEROGLYPH A329;Lo;0;L;;;;;N;;;;;\n14571;ANATOLIAN HIEROGLYPH A329A;Lo;0;L;;;;;N;;;;;\n14572;ANATOLIAN HIEROGLYPH A330;Lo;0;L;;;;;N;;;;;\n14573;ANATOLIAN HIEROGLYPH A331;Lo;0;L;;;;;N;;;;;\n14574;ANATOLIAN HIEROGLYPH A332A;Lo;0;L;;;;;N;;;;;\n14575;ANATOLIAN HIEROGLYPH A332B;Lo;0;L;;;;;N;;;;;\n14576;ANATOLIAN HIEROGLYPH A332C;Lo;0;L;;;;;N;;;;;\n14577;ANATOLIAN HIEROGLYPH A333;Lo;0;L;;;;;N;;;;;\n14578;ANATOLIAN HIEROGLYPH A334;Lo;0;L;;;;;N;;;;;\n14579;ANATOLIAN HIEROGLYPH A335;Lo;0;L;;;;;N;;;;;\n1457A;ANATOLIAN HIEROGLYPH A336;Lo;0;L;;;;;N;;;;;\n1457B;ANATOLIAN HIEROGLYPH A336A;Lo;0;L;;;;;N;;;;;\n1457C;ANATOLIAN HIEROGLYPH A336B;Lo;0;L;;;;;N;;;;;\n1457D;ANATOLIAN HIEROGLYPH A336C;Lo;0;L;;;;;N;;;;;\n1457E;ANATOLIAN HIEROGLYPH A337;Lo;0;L;;;;;N;;;;;\n1457F;ANATOLIAN HIEROGLYPH A338;Lo;0;L;;;;;N;;;;;\n14580;ANATOLIAN HIEROGLYPH A339;Lo;0;L;;;;;N;;;;;\n14581;ANATOLIAN HIEROGLYPH A340;Lo;0;L;;;;;N;;;;;\n14582;ANATOLIAN HIEROGLYPH A341;Lo;0;L;;;;;N;;;;;\n14583;ANATOLIAN HIEROGLYPH A342;Lo;0;L;;;;;N;;;;;\n14584;ANATOLIAN HIEROGLYPH A343;Lo;0;L;;;;;N;;;;;\n14585;ANATOLIAN HIEROGLYPH A344;Lo;0;L;;;;;N;;;;;\n14586;ANATOLIAN HIEROGLYPH A345;Lo;0;L;;;;;N;;;;;\n14587;ANATOLIAN HIEROGLYPH A346;Lo;0;L;;;;;N;;;;;\n14588;ANATOLIAN HIEROGLYPH A347;Lo;0;L;;;;;N;;;;;\n14589;ANATOLIAN HIEROGLYPH A348;Lo;0;L;;;;;N;;;;;\n1458A;ANATOLIAN HIEROGLYPH A349;Lo;0;L;;;;;N;;;;;\n1458B;ANATOLIAN HIEROGLYPH A350;Lo;0;L;;;;;N;;;;;\n1458C;ANATOLIAN HIEROGLYPH A351;Lo;0;L;;;;;N;;;;;\n1458D;ANATOLIAN HIEROGLYPH A352;Lo;0;L;;;;;N;;;;;\n1458E;ANATOLIAN HIEROGLYPH A353;Lo;0;L;;;;;N;;;;;\n1458F;ANATOLIAN HIEROGLYPH A354;Lo;0;L;;;;;N;;;;;\n14590;ANATOLIAN HIEROGLYPH A355;Lo;0;L;;;;;N;;;;;\n14591;ANATOLIAN HIEROGLYPH A356;Lo;0;L;;;;;N;;;;;\n14592;ANATOLIAN HIEROGLYPH A357;Lo;0;L;;;;;N;;;;;\n14593;ANATOLIAN HIEROGLYPH A358;Lo;0;L;;;;;N;;;;;\n14594;ANATOLIAN HIEROGLYPH A359;Lo;0;L;;;;;N;;;;;\n14595;ANATOLIAN HIEROGLYPH A359A;Lo;0;L;;;;;N;;;;;\n14596;ANATOLIAN HIEROGLYPH A360;Lo;0;L;;;;;N;;;;;\n14597;ANATOLIAN HIEROGLYPH A361;Lo;0;L;;;;;N;;;;;\n14598;ANATOLIAN HIEROGLYPH A362;Lo;0;L;;;;;N;;;;;\n14599;ANATOLIAN HIEROGLYPH A363;Lo;0;L;;;;;N;;;;;\n1459A;ANATOLIAN HIEROGLYPH A364;Lo;0;L;;;;;N;;;;;\n1459B;ANATOLIAN HIEROGLYPH A364A;Lo;0;L;;;;;N;;;;;\n1459C;ANATOLIAN HIEROGLYPH A365;Lo;0;L;;;;;N;;;;;\n1459D;ANATOLIAN HIEROGLYPH A366;Lo;0;L;;;;;N;;;;;\n1459E;ANATOLIAN HIEROGLYPH A367;Lo;0;L;;;;;N;;;;;\n1459F;ANATOLIAN HIEROGLYPH A368;Lo;0;L;;;;;N;;;;;\n145A0;ANATOLIAN HIEROGLYPH A368A;Lo;0;L;;;;;N;;;;;\n145A1;ANATOLIAN HIEROGLYPH A369;Lo;0;L;;;;;N;;;;;\n145A2;ANATOLIAN HIEROGLYPH A370;Lo;0;L;;;;;N;;;;;\n145A3;ANATOLIAN HIEROGLYPH A371;Lo;0;L;;;;;N;;;;;\n145A4;ANATOLIAN HIEROGLYPH A371A;Lo;0;L;;;;;N;;;;;\n145A5;ANATOLIAN HIEROGLYPH A372;Lo;0;L;;;;;N;;;;;\n145A6;ANATOLIAN HIEROGLYPH A373;Lo;0;L;;;;;N;;;;;\n145A7;ANATOLIAN HIEROGLYPH A374;Lo;0;L;;;;;N;;;;;\n145A8;ANATOLIAN HIEROGLYPH A375;Lo;0;L;;;;;N;;;;;\n145A9;ANATOLIAN HIEROGLYPH A376;Lo;0;L;;;;;N;;;;;\n145AA;ANATOLIAN HIEROGLYPH A377;Lo;0;L;;;;;N;;;;;\n145AB;ANATOLIAN HIEROGLYPH A378;Lo;0;L;;;;;N;;;;;\n145AC;ANATOLIAN HIEROGLYPH A379;Lo;0;L;;;;;N;;;;;\n145AD;ANATOLIAN HIEROGLYPH A380;Lo;0;L;;;;;N;;;;;\n145AE;ANATOLIAN HIEROGLYPH A381;Lo;0;L;;;;;N;;;;;\n145AF;ANATOLIAN HIEROGLYPH A381A;Lo;0;L;;;;;N;;;;;\n145B0;ANATOLIAN HIEROGLYPH A382;Lo;0;L;;;;;N;;;;;\n145B1;ANATOLIAN HIEROGLYPH A383 RA OR RI;Lo;0;L;;;;;N;;;;;\n145B2;ANATOLIAN HIEROGLYPH A383A;Lo;0;L;;;;;N;;;;;\n145B3;ANATOLIAN HIEROGLYPH A384;Lo;0;L;;;;;N;;;;;\n145B4;ANATOLIAN HIEROGLYPH A385;Lo;0;L;;;;;N;;;;;\n145B5;ANATOLIAN HIEROGLYPH A386;Lo;0;L;;;;;N;;;;;\n145B6;ANATOLIAN HIEROGLYPH A386A;Lo;0;L;;;;;N;;;;;\n145B7;ANATOLIAN HIEROGLYPH A387;Lo;0;L;;;;;N;;;;;\n145B8;ANATOLIAN HIEROGLYPH A388;Lo;0;L;;;;;N;;;;;\n145B9;ANATOLIAN HIEROGLYPH A389;Lo;0;L;;;;;N;;;;;\n145BA;ANATOLIAN HIEROGLYPH A390;Lo;0;L;;;;;N;;;;;\n145BB;ANATOLIAN HIEROGLYPH A391;Lo;0;L;;;;;N;;;;;\n145BC;ANATOLIAN HIEROGLYPH A392;Lo;0;L;;;;;N;;;;;\n145BD;ANATOLIAN HIEROGLYPH A393 EIGHT;Lo;0;L;;;;;N;;;;;\n145BE;ANATOLIAN HIEROGLYPH A394;Lo;0;L;;;;;N;;;;;\n145BF;ANATOLIAN HIEROGLYPH A395;Lo;0;L;;;;;N;;;;;\n145C0;ANATOLIAN HIEROGLYPH A396;Lo;0;L;;;;;N;;;;;\n145C1;ANATOLIAN HIEROGLYPH A397;Lo;0;L;;;;;N;;;;;\n145C2;ANATOLIAN HIEROGLYPH A398;Lo;0;L;;;;;N;;;;;\n145C3;ANATOLIAN HIEROGLYPH A399;Lo;0;L;;;;;N;;;;;\n145C4;ANATOLIAN HIEROGLYPH A400;Lo;0;L;;;;;N;;;;;\n145C5;ANATOLIAN HIEROGLYPH A401;Lo;0;L;;;;;N;;;;;\n145C6;ANATOLIAN HIEROGLYPH A402;Lo;0;L;;;;;N;;;;;\n145C7;ANATOLIAN HIEROGLYPH A403;Lo;0;L;;;;;N;;;;;\n145C8;ANATOLIAN HIEROGLYPH A404;Lo;0;L;;;;;N;;;;;\n145C9;ANATOLIAN HIEROGLYPH A405;Lo;0;L;;;;;N;;;;;\n145CA;ANATOLIAN HIEROGLYPH A406;Lo;0;L;;;;;N;;;;;\n145CB;ANATOLIAN HIEROGLYPH A407;Lo;0;L;;;;;N;;;;;\n145CC;ANATOLIAN HIEROGLYPH A408;Lo;0;L;;;;;N;;;;;\n145CD;ANATOLIAN HIEROGLYPH A409;Lo;0;L;;;;;N;;;;;\n145CE;ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK;Lo;0;L;;;;;N;;;;;\n145CF;ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK;Lo;0;L;;;;;N;;;;;\n145D0;ANATOLIAN HIEROGLYPH A411;Lo;0;L;;;;;N;;;;;\n145D1;ANATOLIAN HIEROGLYPH A412;Lo;0;L;;;;;N;;;;;\n145D2;ANATOLIAN HIEROGLYPH A413;Lo;0;L;;;;;N;;;;;\n145D3;ANATOLIAN HIEROGLYPH A414;Lo;0;L;;;;;N;;;;;\n145D4;ANATOLIAN HIEROGLYPH A415;Lo;0;L;;;;;N;;;;;\n145D5;ANATOLIAN HIEROGLYPH A416;Lo;0;L;;;;;N;;;;;\n145D6;ANATOLIAN HIEROGLYPH A417;Lo;0;L;;;;;N;;;;;\n145D7;ANATOLIAN HIEROGLYPH A418;Lo;0;L;;;;;N;;;;;\n145D8;ANATOLIAN HIEROGLYPH A419;Lo;0;L;;;;;N;;;;;\n145D9;ANATOLIAN HIEROGLYPH A420;Lo;0;L;;;;;N;;;;;\n145DA;ANATOLIAN HIEROGLYPH A421;Lo;0;L;;;;;N;;;;;\n145DB;ANATOLIAN HIEROGLYPH A422;Lo;0;L;;;;;N;;;;;\n145DC;ANATOLIAN HIEROGLYPH A423;Lo;0;L;;;;;N;;;;;\n145DD;ANATOLIAN HIEROGLYPH A424;Lo;0;L;;;;;N;;;;;\n145DE;ANATOLIAN HIEROGLYPH A425;Lo;0;L;;;;;N;;;;;\n145DF;ANATOLIAN HIEROGLYPH A426;Lo;0;L;;;;;N;;;;;\n145E0;ANATOLIAN HIEROGLYPH A427;Lo;0;L;;;;;N;;;;;\n145E1;ANATOLIAN HIEROGLYPH A428;Lo;0;L;;;;;N;;;;;\n145E2;ANATOLIAN HIEROGLYPH A429;Lo;0;L;;;;;N;;;;;\n145E3;ANATOLIAN HIEROGLYPH A430;Lo;0;L;;;;;N;;;;;\n145E4;ANATOLIAN HIEROGLYPH A431;Lo;0;L;;;;;N;;;;;\n145E5;ANATOLIAN HIEROGLYPH A432;Lo;0;L;;;;;N;;;;;\n145E6;ANATOLIAN HIEROGLYPH A433;Lo;0;L;;;;;N;;;;;\n145E7;ANATOLIAN HIEROGLYPH A434;Lo;0;L;;;;;N;;;;;\n145E8;ANATOLIAN HIEROGLYPH A435;Lo;0;L;;;;;N;;;;;\n145E9;ANATOLIAN HIEROGLYPH A436;Lo;0;L;;;;;N;;;;;\n145EA;ANATOLIAN HIEROGLYPH A437;Lo;0;L;;;;;N;;;;;\n145EB;ANATOLIAN HIEROGLYPH A438;Lo;0;L;;;;;N;;;;;\n145EC;ANATOLIAN HIEROGLYPH A439;Lo;0;L;;;;;N;;;;;\n145ED;ANATOLIAN HIEROGLYPH A440;Lo;0;L;;;;;N;;;;;\n145EE;ANATOLIAN HIEROGLYPH A441;Lo;0;L;;;;;N;;;;;\n145EF;ANATOLIAN HIEROGLYPH A442;Lo;0;L;;;;;N;;;;;\n145F0;ANATOLIAN HIEROGLYPH A443;Lo;0;L;;;;;N;;;;;\n145F1;ANATOLIAN HIEROGLYPH A444;Lo;0;L;;;;;N;;;;;\n145F2;ANATOLIAN HIEROGLYPH A445;Lo;0;L;;;;;N;;;;;\n145F3;ANATOLIAN HIEROGLYPH A446;Lo;0;L;;;;;N;;;;;\n145F4;ANATOLIAN HIEROGLYPH A447;Lo;0;L;;;;;N;;;;;\n145F5;ANATOLIAN HIEROGLYPH A448;Lo;0;L;;;;;N;;;;;\n145F6;ANATOLIAN HIEROGLYPH A449;Lo;0;L;;;;;N;;;;;\n145F7;ANATOLIAN HIEROGLYPH A450;Lo;0;L;;;;;N;;;;;\n145F8;ANATOLIAN HIEROGLYPH A450A;Lo;0;L;;;;;N;;;;;\n145F9;ANATOLIAN HIEROGLYPH A451;Lo;0;L;;;;;N;;;;;\n145FA;ANATOLIAN HIEROGLYPH A452;Lo;0;L;;;;;N;;;;;\n145FB;ANATOLIAN HIEROGLYPH A453;Lo;0;L;;;;;N;;;;;\n145FC;ANATOLIAN HIEROGLYPH A454;Lo;0;L;;;;;N;;;;;\n145FD;ANATOLIAN HIEROGLYPH A455;Lo;0;L;;;;;N;;;;;\n145FE;ANATOLIAN HIEROGLYPH A456;Lo;0;L;;;;;N;;;;;\n145FF;ANATOLIAN HIEROGLYPH A457;Lo;0;L;;;;;N;;;;;\n14600;ANATOLIAN HIEROGLYPH A457A;Lo;0;L;;;;;N;;;;;\n14601;ANATOLIAN HIEROGLYPH A458;Lo;0;L;;;;;N;;;;;\n14602;ANATOLIAN HIEROGLYPH A459;Lo;0;L;;;;;N;;;;;\n14603;ANATOLIAN HIEROGLYPH A460;Lo;0;L;;;;;N;;;;;\n14604;ANATOLIAN HIEROGLYPH A461;Lo;0;L;;;;;N;;;;;\n14605;ANATOLIAN HIEROGLYPH A462;Lo;0;L;;;;;N;;;;;\n14606;ANATOLIAN HIEROGLYPH A463;Lo;0;L;;;;;N;;;;;\n14607;ANATOLIAN HIEROGLYPH A464;Lo;0;L;;;;;N;;;;;\n14608;ANATOLIAN HIEROGLYPH A465;Lo;0;L;;;;;N;;;;;\n14609;ANATOLIAN HIEROGLYPH A466;Lo;0;L;;;;;N;;;;;\n1460A;ANATOLIAN HIEROGLYPH A467;Lo;0;L;;;;;N;;;;;\n1460B;ANATOLIAN HIEROGLYPH A468;Lo;0;L;;;;;N;;;;;\n1460C;ANATOLIAN HIEROGLYPH A469;Lo;0;L;;;;;N;;;;;\n1460D;ANATOLIAN HIEROGLYPH A470;Lo;0;L;;;;;N;;;;;\n1460E;ANATOLIAN HIEROGLYPH A471;Lo;0;L;;;;;N;;;;;\n1460F;ANATOLIAN HIEROGLYPH A472;Lo;0;L;;;;;N;;;;;\n14610;ANATOLIAN HIEROGLYPH A473;Lo;0;L;;;;;N;;;;;\n14611;ANATOLIAN HIEROGLYPH A474;Lo;0;L;;;;;N;;;;;\n14612;ANATOLIAN HIEROGLYPH A475;Lo;0;L;;;;;N;;;;;\n14613;ANATOLIAN HIEROGLYPH A476;Lo;0;L;;;;;N;;;;;\n14614;ANATOLIAN HIEROGLYPH A477;Lo;0;L;;;;;N;;;;;\n14615;ANATOLIAN HIEROGLYPH A478;Lo;0;L;;;;;N;;;;;\n14616;ANATOLIAN HIEROGLYPH A479;Lo;0;L;;;;;N;;;;;\n14617;ANATOLIAN HIEROGLYPH A480;Lo;0;L;;;;;N;;;;;\n14618;ANATOLIAN HIEROGLYPH A481;Lo;0;L;;;;;N;;;;;\n14619;ANATOLIAN HIEROGLYPH A482;Lo;0;L;;;;;N;;;;;\n1461A;ANATOLIAN HIEROGLYPH A483;Lo;0;L;;;;;N;;;;;\n1461B;ANATOLIAN HIEROGLYPH A484;Lo;0;L;;;;;N;;;;;\n1461C;ANATOLIAN HIEROGLYPH A485;Lo;0;L;;;;;N;;;;;\n1461D;ANATOLIAN HIEROGLYPH A486;Lo;0;L;;;;;N;;;;;\n1461E;ANATOLIAN HIEROGLYPH A487;Lo;0;L;;;;;N;;;;;\n1461F;ANATOLIAN HIEROGLYPH A488;Lo;0;L;;;;;N;;;;;\n14620;ANATOLIAN HIEROGLYPH A489;Lo;0;L;;;;;N;;;;;\n14621;ANATOLIAN HIEROGLYPH A490;Lo;0;L;;;;;N;;;;;\n14622;ANATOLIAN HIEROGLYPH A491;Lo;0;L;;;;;N;;;;;\n14623;ANATOLIAN HIEROGLYPH A492;Lo;0;L;;;;;N;;;;;\n14624;ANATOLIAN HIEROGLYPH A493;Lo;0;L;;;;;N;;;;;\n14625;ANATOLIAN HIEROGLYPH A494;Lo;0;L;;;;;N;;;;;\n14626;ANATOLIAN HIEROGLYPH A495;Lo;0;L;;;;;N;;;;;\n14627;ANATOLIAN HIEROGLYPH A496;Lo;0;L;;;;;N;;;;;\n14628;ANATOLIAN HIEROGLYPH A497;Lo;0;L;;;;;N;;;;;\n14629;ANATOLIAN HIEROGLYPH A501;Lo;0;L;;;;;N;;;;;\n1462A;ANATOLIAN HIEROGLYPH A502;Lo;0;L;;;;;N;;;;;\n1462B;ANATOLIAN HIEROGLYPH A503;Lo;0;L;;;;;N;;;;;\n1462C;ANATOLIAN HIEROGLYPH A504;Lo;0;L;;;;;N;;;;;\n1462D;ANATOLIAN HIEROGLYPH A505;Lo;0;L;;;;;N;;;;;\n1462E;ANATOLIAN HIEROGLYPH A506;Lo;0;L;;;;;N;;;;;\n1462F;ANATOLIAN HIEROGLYPH A507;Lo;0;L;;;;;N;;;;;\n14630;ANATOLIAN HIEROGLYPH A508;Lo;0;L;;;;;N;;;;;\n14631;ANATOLIAN HIEROGLYPH A509;Lo;0;L;;;;;N;;;;;\n14632;ANATOLIAN HIEROGLYPH A510;Lo;0;L;;;;;N;;;;;\n14633;ANATOLIAN HIEROGLYPH A511;Lo;0;L;;;;;N;;;;;\n14634;ANATOLIAN HIEROGLYPH A512;Lo;0;L;;;;;N;;;;;\n14635;ANATOLIAN HIEROGLYPH A513;Lo;0;L;;;;;N;;;;;\n14636;ANATOLIAN HIEROGLYPH A514;Lo;0;L;;;;;N;;;;;\n14637;ANATOLIAN HIEROGLYPH A515;Lo;0;L;;;;;N;;;;;\n14638;ANATOLIAN HIEROGLYPH A516;Lo;0;L;;;;;N;;;;;\n14639;ANATOLIAN HIEROGLYPH A517;Lo;0;L;;;;;N;;;;;\n1463A;ANATOLIAN HIEROGLYPH A518;Lo;0;L;;;;;N;;;;;\n1463B;ANATOLIAN HIEROGLYPH A519;Lo;0;L;;;;;N;;;;;\n1463C;ANATOLIAN HIEROGLYPH A520;Lo;0;L;;;;;N;;;;;\n1463D;ANATOLIAN HIEROGLYPH A521;Lo;0;L;;;;;N;;;;;\n1463E;ANATOLIAN HIEROGLYPH A522;Lo;0;L;;;;;N;;;;;\n1463F;ANATOLIAN HIEROGLYPH A523;Lo;0;L;;;;;N;;;;;\n14640;ANATOLIAN HIEROGLYPH A524;Lo;0;L;;;;;N;;;;;\n14641;ANATOLIAN HIEROGLYPH A525;Lo;0;L;;;;;N;;;;;\n14642;ANATOLIAN HIEROGLYPH A526;Lo;0;L;;;;;N;;;;;\n14643;ANATOLIAN HIEROGLYPH A527;Lo;0;L;;;;;N;;;;;\n14644;ANATOLIAN HIEROGLYPH A528;Lo;0;L;;;;;N;;;;;\n14645;ANATOLIAN HIEROGLYPH A529;Lo;0;L;;;;;N;;;;;\n14646;ANATOLIAN HIEROGLYPH A530;Lo;0;L;;;;;N;;;;;\n16100;GURUNG KHEMA LETTER A;Lo;0;L;;;;;N;;;;;\n16101;GURUNG KHEMA LETTER KA;Lo;0;L;;;;;N;;;;;\n16102;GURUNG KHEMA LETTER KHA;Lo;0;L;;;;;N;;;;;\n16103;GURUNG KHEMA LETTER GA;Lo;0;L;;;;;N;;;;;\n16104;GURUNG KHEMA LETTER GHA;Lo;0;L;;;;;N;;;;;\n16105;GURUNG KHEMA LETTER NGA;Lo;0;L;;;;;N;;;;;\n16106;GURUNG KHEMA LETTER CA;Lo;0;L;;;;;N;;;;;\n16107;GURUNG KHEMA LETTER CHA;Lo;0;L;;;;;N;;;;;\n16108;GURUNG KHEMA LETTER JA;Lo;0;L;;;;;N;;;;;\n16109;GURUNG KHEMA LETTER JHA;Lo;0;L;;;;;N;;;;;\n1610A;GURUNG KHEMA LETTER HA;Lo;0;L;;;;;N;;;;;\n1610B;GURUNG KHEMA LETTER TTA;Lo;0;L;;;;;N;;;;;\n1610C;GURUNG KHEMA LETTER TTHA;Lo;0;L;;;;;N;;;;;\n1610D;GURUNG KHEMA LETTER DDA;Lo;0;L;;;;;N;;;;;\n1610E;GURUNG KHEMA LETTER DDHA;Lo;0;L;;;;;N;;;;;\n1610F;GURUNG KHEMA LETTER VA;Lo;0;L;;;;;N;;;;;\n16110;GURUNG KHEMA LETTER TA;Lo;0;L;;;;;N;;;;;\n16111;GURUNG KHEMA LETTER THA;Lo;0;L;;;;;N;;;;;\n16112;GURUNG KHEMA LETTER DA;Lo;0;L;;;;;N;;;;;\n16113;GURUNG KHEMA LETTER DHA;Lo;0;L;;;;;N;;;;;\n16114;GURUNG KHEMA LETTER NA;Lo;0;L;;;;;N;;;;;\n16115;GURUNG KHEMA LETTER PA;Lo;0;L;;;;;N;;;;;\n16116;GURUNG KHEMA LETTER PHA;Lo;0;L;;;;;N;;;;;\n16117;GURUNG KHEMA LETTER BA;Lo;0;L;;;;;N;;;;;\n16118;GURUNG KHEMA LETTER BHA;Lo;0;L;;;;;N;;;;;\n16119;GURUNG KHEMA LETTER MA;Lo;0;L;;;;;N;;;;;\n1611A;GURUNG KHEMA LETTER YA;Lo;0;L;;;;;N;;;;;\n1611B;GURUNG KHEMA LETTER RA;Lo;0;L;;;;;N;;;;;\n1611C;GURUNG KHEMA LETTER LA;Lo;0;L;;;;;N;;;;;\n1611D;GURUNG KHEMA LETTER SA;Lo;0;L;;;;;N;;;;;\n1611E;GURUNG KHEMA VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;\n1611F;GURUNG KHEMA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;\n16120;GURUNG KHEMA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;\n16121;GURUNG KHEMA VOWEL SIGN U;Mn;0;NSM;1611E 1611E;;;;N;;;;;\n16122;GURUNG KHEMA VOWEL SIGN UU;Mn;0;NSM;1611E 16129;;;;N;;;;;\n16123;GURUNG KHEMA VOWEL SIGN E;Mn;0;NSM;1611E 1611F;;;;N;;;;;\n16124;GURUNG KHEMA VOWEL SIGN EE;Mn;0;NSM;16129 1611F;;;;N;;;;;\n16125;GURUNG KHEMA VOWEL SIGN AI;Mn;0;NSM;1611E 16120;;;;N;;;;;\n16126;GURUNG KHEMA VOWEL SIGN O;Mn;0;NSM;16121 1611F;;;;N;;;;;\n16127;GURUNG KHEMA VOWEL SIGN OO;Mn;0;NSM;16122 1611F;;;;N;;;;;\n16128;GURUNG KHEMA VOWEL SIGN AU;Mn;0;NSM;16121 16120;;;;N;;;;;\n16129;GURUNG KHEMA VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;\n1612A;GURUNG KHEMA CONSONANT SIGN MEDIAL YA;Mc;0;L;;;;;N;;;;;\n1612B;GURUNG KHEMA CONSONANT SIGN MEDIAL VA;Mc;0;L;;;;;N;;;;;\n1612C;GURUNG KHEMA CONSONANT SIGN MEDIAL HA;Mc;0;L;;;;;N;;;;;\n1612D;GURUNG KHEMA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;\n1612E;GURUNG KHEMA CONSONANT SIGN MEDIAL RA;Mn;0;NSM;;;;;N;;;;;\n1612F;GURUNG KHEMA SIGN THOLHOMA;Mn;9;NSM;;;;;N;;;;;\n16130;GURUNG KHEMA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n16131;GURUNG KHEMA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n16132;GURUNG KHEMA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n16133;GURUNG KHEMA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n16134;GURUNG KHEMA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n16135;GURUNG KHEMA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n16136;GURUNG KHEMA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n16137;GURUNG KHEMA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n16138;GURUNG KHEMA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n16139;GURUNG KHEMA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n16800;BAMUM LETTER PHASE-A NGKUE MFON;Lo;0;L;;;;;N;;;;;\n16801;BAMUM LETTER PHASE-A GBIEE FON;Lo;0;L;;;;;N;;;;;\n16802;BAMUM LETTER PHASE-A PON MFON PIPAEMGBIEE;Lo;0;L;;;;;N;;;;;\n16803;BAMUM LETTER PHASE-A PON MFON PIPAEMBA;Lo;0;L;;;;;N;;;;;\n16804;BAMUM LETTER PHASE-A NAA MFON;Lo;0;L;;;;;N;;;;;\n16805;BAMUM LETTER PHASE-A SHUENSHUET;Lo;0;L;;;;;N;;;;;\n16806;BAMUM LETTER PHASE-A TITA MFON;Lo;0;L;;;;;N;;;;;\n16807;BAMUM LETTER PHASE-A NZA MFON;Lo;0;L;;;;;N;;;;;\n16808;BAMUM LETTER PHASE-A SHINDA PA NJI;Lo;0;L;;;;;N;;;;;\n16809;BAMUM LETTER PHASE-A PON PA NJI PIPAEMGBIEE;Lo;0;L;;;;;N;;;;;\n1680A;BAMUM LETTER PHASE-A PON PA NJI PIPAEMBA;Lo;0;L;;;;;N;;;;;\n1680B;BAMUM LETTER PHASE-A MAEMBGBIEE;Lo;0;L;;;;;N;;;;;\n1680C;BAMUM LETTER PHASE-A TU MAEMBA;Lo;0;L;;;;;N;;;;;\n1680D;BAMUM LETTER PHASE-A NGANGU;Lo;0;L;;;;;N;;;;;\n1680E;BAMUM LETTER PHASE-A MAEMVEUX;Lo;0;L;;;;;N;;;;;\n1680F;BAMUM LETTER PHASE-A MANSUAE;Lo;0;L;;;;;N;;;;;\n16810;BAMUM LETTER PHASE-A MVEUAENGAM;Lo;0;L;;;;;N;;;;;\n16811;BAMUM LETTER PHASE-A SEUNYAM;Lo;0;L;;;;;N;;;;;\n16812;BAMUM LETTER PHASE-A NTOQPEN;Lo;0;L;;;;;N;;;;;\n16813;BAMUM LETTER PHASE-A KEUKEUTNDA;Lo;0;L;;;;;N;;;;;\n16814;BAMUM LETTER PHASE-A NKINDI;Lo;0;L;;;;;N;;;;;\n16815;BAMUM LETTER PHASE-A SUU;Lo;0;L;;;;;N;;;;;\n16816;BAMUM LETTER PHASE-A NGKUENZEUM;Lo;0;L;;;;;N;;;;;\n16817;BAMUM LETTER PHASE-A LAPAQ;Lo;0;L;;;;;N;;;;;\n16818;BAMUM LETTER PHASE-A LET KUT;Lo;0;L;;;;;N;;;;;\n16819;BAMUM LETTER PHASE-A NTAP MFAA;Lo;0;L;;;;;N;;;;;\n1681A;BAMUM LETTER PHASE-A MAEKEUP;Lo;0;L;;;;;N;;;;;\n1681B;BAMUM LETTER PHASE-A PASHAE;Lo;0;L;;;;;N;;;;;\n1681C;BAMUM LETTER PHASE-A GHEUAERAE;Lo;0;L;;;;;N;;;;;\n1681D;BAMUM LETTER PHASE-A PAMSHAE;Lo;0;L;;;;;N;;;;;\n1681E;BAMUM LETTER PHASE-A MON NGGEUAET;Lo;0;L;;;;;N;;;;;\n1681F;BAMUM LETTER PHASE-A NZUN MEUT;Lo;0;L;;;;;N;;;;;\n16820;BAMUM LETTER PHASE-A U YUQ NAE;Lo;0;L;;;;;N;;;;;\n16821;BAMUM LETTER PHASE-A GHEUAEGHEUAE;Lo;0;L;;;;;N;;;;;\n16822;BAMUM LETTER PHASE-A NTAP NTAA;Lo;0;L;;;;;N;;;;;\n16823;BAMUM LETTER PHASE-A SISA;Lo;0;L;;;;;N;;;;;\n16824;BAMUM LETTER PHASE-A MGBASA;Lo;0;L;;;;;N;;;;;\n16825;BAMUM LETTER PHASE-A MEUNJOMNDEUQ;Lo;0;L;;;;;N;;;;;\n16826;BAMUM LETTER PHASE-A MOOMPUQ;Lo;0;L;;;;;N;;;;;\n16827;BAMUM LETTER PHASE-A KAFA;Lo;0;L;;;;;N;;;;;\n16828;BAMUM LETTER PHASE-A PA LEERAEWA;Lo;0;L;;;;;N;;;;;\n16829;BAMUM LETTER PHASE-A NDA LEERAEWA;Lo;0;L;;;;;N;;;;;\n1682A;BAMUM LETTER PHASE-A PET;Lo;0;L;;;;;N;;;;;\n1682B;BAMUM LETTER PHASE-A MAEMKPEN;Lo;0;L;;;;;N;;;;;\n1682C;BAMUM LETTER PHASE-A NIKA;Lo;0;L;;;;;N;;;;;\n1682D;BAMUM LETTER PHASE-A PUP;Lo;0;L;;;;;N;;;;;\n1682E;BAMUM LETTER PHASE-A TUAEP;Lo;0;L;;;;;N;;;;;\n1682F;BAMUM LETTER PHASE-A LUAEP;Lo;0;L;;;;;N;;;;;\n16830;BAMUM LETTER PHASE-A SONJAM;Lo;0;L;;;;;N;;;;;\n16831;BAMUM LETTER PHASE-A TEUTEUWEN;Lo;0;L;;;;;N;;;;;\n16832;BAMUM LETTER PHASE-A MAENYI;Lo;0;L;;;;;N;;;;;\n16833;BAMUM LETTER PHASE-A KET;Lo;0;L;;;;;N;;;;;\n16834;BAMUM LETTER PHASE-A NDAANGGEUAET;Lo;0;L;;;;;N;;;;;\n16835;BAMUM LETTER PHASE-A KUOQ;Lo;0;L;;;;;N;;;;;\n16836;BAMUM LETTER PHASE-A MOOMEUT;Lo;0;L;;;;;N;;;;;\n16837;BAMUM LETTER PHASE-A SHUM;Lo;0;L;;;;;N;;;;;\n16838;BAMUM LETTER PHASE-A LOMMAE;Lo;0;L;;;;;N;;;;;\n16839;BAMUM LETTER PHASE-A FIRI;Lo;0;L;;;;;N;;;;;\n1683A;BAMUM LETTER PHASE-A ROM;Lo;0;L;;;;;N;;;;;\n1683B;BAMUM LETTER PHASE-A KPOQ;Lo;0;L;;;;;N;;;;;\n1683C;BAMUM LETTER PHASE-A SOQ;Lo;0;L;;;;;N;;;;;\n1683D;BAMUM LETTER PHASE-A MAP PIEET;Lo;0;L;;;;;N;;;;;\n1683E;BAMUM LETTER PHASE-A SHIRAE;Lo;0;L;;;;;N;;;;;\n1683F;BAMUM LETTER PHASE-A NTAP;Lo;0;L;;;;;N;;;;;\n16840;BAMUM LETTER PHASE-A SHOQ NSHUT YUM;Lo;0;L;;;;;N;;;;;\n16841;BAMUM LETTER PHASE-A NYIT MONGKEUAEQ;Lo;0;L;;;;;N;;;;;\n16842;BAMUM LETTER PHASE-A PAARAE;Lo;0;L;;;;;N;;;;;\n16843;BAMUM LETTER PHASE-A NKAARAE;Lo;0;L;;;;;N;;;;;\n16844;BAMUM LETTER PHASE-A UNKNOWN;Lo;0;L;;;;;N;;;;;\n16845;BAMUM LETTER PHASE-A NGGEN;Lo;0;L;;;;;N;;;;;\n16846;BAMUM LETTER PHASE-A MAESI;Lo;0;L;;;;;N;;;;;\n16847;BAMUM LETTER PHASE-A NJAM;Lo;0;L;;;;;N;;;;;\n16848;BAMUM LETTER PHASE-A MBANYI;Lo;0;L;;;;;N;;;;;\n16849;BAMUM LETTER PHASE-A NYET;Lo;0;L;;;;;N;;;;;\n1684A;BAMUM LETTER PHASE-A TEUAEN;Lo;0;L;;;;;N;;;;;\n1684B;BAMUM LETTER PHASE-A SOT;Lo;0;L;;;;;N;;;;;\n1684C;BAMUM LETTER PHASE-A PAAM;Lo;0;L;;;;;N;;;;;\n1684D;BAMUM LETTER PHASE-A NSHIEE;Lo;0;L;;;;;N;;;;;\n1684E;BAMUM LETTER PHASE-A MAEM;Lo;0;L;;;;;N;;;;;\n1684F;BAMUM LETTER PHASE-A NYI;Lo;0;L;;;;;N;;;;;\n16850;BAMUM LETTER PHASE-A KAQ;Lo;0;L;;;;;N;;;;;\n16851;BAMUM LETTER PHASE-A NSHA;Lo;0;L;;;;;N;;;;;\n16852;BAMUM LETTER PHASE-A VEE;Lo;0;L;;;;;N;;;;;\n16853;BAMUM LETTER PHASE-A LU;Lo;0;L;;;;;N;;;;;\n16854;BAMUM LETTER PHASE-A NEN;Lo;0;L;;;;;N;;;;;\n16855;BAMUM LETTER PHASE-A NAQ;Lo;0;L;;;;;N;;;;;\n16856;BAMUM LETTER PHASE-A MBAQ;Lo;0;L;;;;;N;;;;;\n16857;BAMUM LETTER PHASE-B NSHUET;Lo;0;L;;;;;N;;;;;\n16858;BAMUM LETTER PHASE-B TU MAEMGBIEE;Lo;0;L;;;;;N;;;;;\n16859;BAMUM LETTER PHASE-B SIEE;Lo;0;L;;;;;N;;;;;\n1685A;BAMUM LETTER PHASE-B SET TU;Lo;0;L;;;;;N;;;;;\n1685B;BAMUM LETTER PHASE-B LOM NTEUM;Lo;0;L;;;;;N;;;;;\n1685C;BAMUM LETTER PHASE-B MBA MAELEE;Lo;0;L;;;;;N;;;;;\n1685D;BAMUM LETTER PHASE-B KIEEM;Lo;0;L;;;;;N;;;;;\n1685E;BAMUM LETTER PHASE-B YEURAE;Lo;0;L;;;;;N;;;;;\n1685F;BAMUM LETTER PHASE-B MBAARAE;Lo;0;L;;;;;N;;;;;\n16860;BAMUM LETTER PHASE-B KAM;Lo;0;L;;;;;N;;;;;\n16861;BAMUM LETTER PHASE-B PEESHI;Lo;0;L;;;;;N;;;;;\n16862;BAMUM LETTER PHASE-B YAFU LEERAEWA;Lo;0;L;;;;;N;;;;;\n16863;BAMUM LETTER PHASE-B LAM NSHUT NYAM;Lo;0;L;;;;;N;;;;;\n16864;BAMUM LETTER PHASE-B NTIEE SHEUOQ;Lo;0;L;;;;;N;;;;;\n16865;BAMUM LETTER PHASE-B NDU NJAA;Lo;0;L;;;;;N;;;;;\n16866;BAMUM LETTER PHASE-B GHEUGHEUAEM;Lo;0;L;;;;;N;;;;;\n16867;BAMUM LETTER PHASE-B PIT;Lo;0;L;;;;;N;;;;;\n16868;BAMUM LETTER PHASE-B TU NSIEE;Lo;0;L;;;;;N;;;;;\n16869;BAMUM LETTER PHASE-B SHET NJAQ;Lo;0;L;;;;;N;;;;;\n1686A;BAMUM LETTER PHASE-B SHEUAEQTU;Lo;0;L;;;;;N;;;;;\n1686B;BAMUM LETTER PHASE-B MFON TEUAEQ;Lo;0;L;;;;;N;;;;;\n1686C;BAMUM LETTER PHASE-B MBIT MBAAKET;Lo;0;L;;;;;N;;;;;\n1686D;BAMUM LETTER PHASE-B NYI NTEUM;Lo;0;L;;;;;N;;;;;\n1686E;BAMUM LETTER PHASE-B KEUPUQ;Lo;0;L;;;;;N;;;;;\n1686F;BAMUM LETTER PHASE-B GHEUGHEN;Lo;0;L;;;;;N;;;;;\n16870;BAMUM LETTER PHASE-B KEUYEUX;Lo;0;L;;;;;N;;;;;\n16871;BAMUM LETTER PHASE-B LAANAE;Lo;0;L;;;;;N;;;;;\n16872;BAMUM LETTER PHASE-B PARUM;Lo;0;L;;;;;N;;;;;\n16873;BAMUM LETTER PHASE-B VEUM;Lo;0;L;;;;;N;;;;;\n16874;BAMUM LETTER PHASE-B NGKINDI MVOP;Lo;0;L;;;;;N;;;;;\n16875;BAMUM LETTER PHASE-B NGGEU MBU;Lo;0;L;;;;;N;;;;;\n16876;BAMUM LETTER PHASE-B WUAET;Lo;0;L;;;;;N;;;;;\n16877;BAMUM LETTER PHASE-B SAKEUAE;Lo;0;L;;;;;N;;;;;\n16878;BAMUM LETTER PHASE-B TAAM;Lo;0;L;;;;;N;;;;;\n16879;BAMUM LETTER PHASE-B MEUQ;Lo;0;L;;;;;N;;;;;\n1687A;BAMUM LETTER PHASE-B NGGUOQ;Lo;0;L;;;;;N;;;;;\n1687B;BAMUM LETTER PHASE-B NGGUOQ LARGE;Lo;0;L;;;;;N;;;;;\n1687C;BAMUM LETTER PHASE-B MFIYAQ;Lo;0;L;;;;;N;;;;;\n1687D;BAMUM LETTER PHASE-B SUE;Lo;0;L;;;;;N;;;;;\n1687E;BAMUM LETTER PHASE-B MBEURI;Lo;0;L;;;;;N;;;;;\n1687F;BAMUM LETTER PHASE-B MONTIEEN;Lo;0;L;;;;;N;;;;;\n16880;BAMUM LETTER PHASE-B NYAEMAE;Lo;0;L;;;;;N;;;;;\n16881;BAMUM LETTER PHASE-B PUNGAAM;Lo;0;L;;;;;N;;;;;\n16882;BAMUM LETTER PHASE-B MEUT NGGEET;Lo;0;L;;;;;N;;;;;\n16883;BAMUM LETTER PHASE-B FEUX;Lo;0;L;;;;;N;;;;;\n16884;BAMUM LETTER PHASE-B MBUOQ;Lo;0;L;;;;;N;;;;;\n16885;BAMUM LETTER PHASE-B FEE;Lo;0;L;;;;;N;;;;;\n16886;BAMUM LETTER PHASE-B KEUAEM;Lo;0;L;;;;;N;;;;;\n16887;BAMUM LETTER PHASE-B MA NJEUAENA;Lo;0;L;;;;;N;;;;;\n16888;BAMUM LETTER PHASE-B MA NJUQA;Lo;0;L;;;;;N;;;;;\n16889;BAMUM LETTER PHASE-B LET;Lo;0;L;;;;;N;;;;;\n1688A;BAMUM LETTER PHASE-B NGGAAM;Lo;0;L;;;;;N;;;;;\n1688B;BAMUM LETTER PHASE-B NSEN;Lo;0;L;;;;;N;;;;;\n1688C;BAMUM LETTER PHASE-B MA;Lo;0;L;;;;;N;;;;;\n1688D;BAMUM LETTER PHASE-B KIQ;Lo;0;L;;;;;N;;;;;\n1688E;BAMUM LETTER PHASE-B NGOM;Lo;0;L;;;;;N;;;;;\n1688F;BAMUM LETTER PHASE-C NGKUE MAEMBA;Lo;0;L;;;;;N;;;;;\n16890;BAMUM LETTER PHASE-C NZA;Lo;0;L;;;;;N;;;;;\n16891;BAMUM LETTER PHASE-C YUM;Lo;0;L;;;;;N;;;;;\n16892;BAMUM LETTER PHASE-C WANGKUOQ;Lo;0;L;;;;;N;;;;;\n16893;BAMUM LETTER PHASE-C NGGEN;Lo;0;L;;;;;N;;;;;\n16894;BAMUM LETTER PHASE-C NDEUAEREE;Lo;0;L;;;;;N;;;;;\n16895;BAMUM LETTER PHASE-C NGKAQ;Lo;0;L;;;;;N;;;;;\n16896;BAMUM LETTER PHASE-C GHARAE;Lo;0;L;;;;;N;;;;;\n16897;BAMUM LETTER PHASE-C MBEEKEET;Lo;0;L;;;;;N;;;;;\n16898;BAMUM LETTER PHASE-C GBAYI;Lo;0;L;;;;;N;;;;;\n16899;BAMUM LETTER PHASE-C NYIR MKPARAQ MEUN;Lo;0;L;;;;;N;;;;;\n1689A;BAMUM LETTER PHASE-C NTU MBIT;Lo;0;L;;;;;N;;;;;\n1689B;BAMUM LETTER PHASE-C MBEUM;Lo;0;L;;;;;N;;;;;\n1689C;BAMUM LETTER PHASE-C PIRIEEN;Lo;0;L;;;;;N;;;;;\n1689D;BAMUM LETTER PHASE-C NDOMBU;Lo;0;L;;;;;N;;;;;\n1689E;BAMUM LETTER PHASE-C MBAA CABBAGE-TREE;Lo;0;L;;;;;N;;;;;\n1689F;BAMUM LETTER PHASE-C KEUSHEUAEP;Lo;0;L;;;;;N;;;;;\n168A0;BAMUM LETTER PHASE-C GHAP;Lo;0;L;;;;;N;;;;;\n168A1;BAMUM LETTER PHASE-C KEUKAQ;Lo;0;L;;;;;N;;;;;\n168A2;BAMUM LETTER PHASE-C YU MUOMAE;Lo;0;L;;;;;N;;;;;\n168A3;BAMUM LETTER PHASE-C NZEUM;Lo;0;L;;;;;N;;;;;\n168A4;BAMUM LETTER PHASE-C MBUE;Lo;0;L;;;;;N;;;;;\n168A5;BAMUM LETTER PHASE-C NSEUAEN;Lo;0;L;;;;;N;;;;;\n168A6;BAMUM LETTER PHASE-C MBIT;Lo;0;L;;;;;N;;;;;\n168A7;BAMUM LETTER PHASE-C YEUQ;Lo;0;L;;;;;N;;;;;\n168A8;BAMUM LETTER PHASE-C KPARAQ;Lo;0;L;;;;;N;;;;;\n168A9;BAMUM LETTER PHASE-C KAA;Lo;0;L;;;;;N;;;;;\n168AA;BAMUM LETTER PHASE-C SEUX;Lo;0;L;;;;;N;;;;;\n168AB;BAMUM LETTER PHASE-C NDIDA;Lo;0;L;;;;;N;;;;;\n168AC;BAMUM LETTER PHASE-C TAASHAE;Lo;0;L;;;;;N;;;;;\n168AD;BAMUM LETTER PHASE-C NJUEQ;Lo;0;L;;;;;N;;;;;\n168AE;BAMUM LETTER PHASE-C TITA YUE;Lo;0;L;;;;;N;;;;;\n168AF;BAMUM LETTER PHASE-C SUAET;Lo;0;L;;;;;N;;;;;\n168B0;BAMUM LETTER PHASE-C NGGUAEN NYAM;Lo;0;L;;;;;N;;;;;\n168B1;BAMUM LETTER PHASE-C VEUX;Lo;0;L;;;;;N;;;;;\n168B2;BAMUM LETTER PHASE-C NANSANAQ;Lo;0;L;;;;;N;;;;;\n168B3;BAMUM LETTER PHASE-C MA KEUAERI;Lo;0;L;;;;;N;;;;;\n168B4;BAMUM LETTER PHASE-C NTAA;Lo;0;L;;;;;N;;;;;\n168B5;BAMUM LETTER PHASE-C NGGUON;Lo;0;L;;;;;N;;;;;\n168B6;BAMUM LETTER PHASE-C LAP;Lo;0;L;;;;;N;;;;;\n168B7;BAMUM LETTER PHASE-C MBIRIEEN;Lo;0;L;;;;;N;;;;;\n168B8;BAMUM LETTER PHASE-C MGBASAQ;Lo;0;L;;;;;N;;;;;\n168B9;BAMUM LETTER PHASE-C NTEUNGBA;Lo;0;L;;;;;N;;;;;\n168BA;BAMUM LETTER PHASE-C TEUTEUX;Lo;0;L;;;;;N;;;;;\n168BB;BAMUM LETTER PHASE-C NGGUM;Lo;0;L;;;;;N;;;;;\n168BC;BAMUM LETTER PHASE-C FUE;Lo;0;L;;;;;N;;;;;\n168BD;BAMUM LETTER PHASE-C NDEUT;Lo;0;L;;;;;N;;;;;\n168BE;BAMUM LETTER PHASE-C NSA;Lo;0;L;;;;;N;;;;;\n168BF;BAMUM LETTER PHASE-C NSHAQ;Lo;0;L;;;;;N;;;;;\n168C0;BAMUM LETTER PHASE-C BUNG;Lo;0;L;;;;;N;;;;;\n168C1;BAMUM LETTER PHASE-C VEUAEPEN;Lo;0;L;;;;;N;;;;;\n168C2;BAMUM LETTER PHASE-C MBERAE;Lo;0;L;;;;;N;;;;;\n168C3;BAMUM LETTER PHASE-C RU;Lo;0;L;;;;;N;;;;;\n168C4;BAMUM LETTER PHASE-C NJAEM;Lo;0;L;;;;;N;;;;;\n168C5;BAMUM LETTER PHASE-C LAM;Lo;0;L;;;;;N;;;;;\n168C6;BAMUM LETTER PHASE-C TITUAEP;Lo;0;L;;;;;N;;;;;\n168C7;BAMUM LETTER PHASE-C NSUOT NGOM;Lo;0;L;;;;;N;;;;;\n168C8;BAMUM LETTER PHASE-C NJEEEE;Lo;0;L;;;;;N;;;;;\n168C9;BAMUM LETTER PHASE-C KET;Lo;0;L;;;;;N;;;;;\n168CA;BAMUM LETTER PHASE-C NGGU;Lo;0;L;;;;;N;;;;;\n168CB;BAMUM LETTER PHASE-C MAESI;Lo;0;L;;;;;N;;;;;\n168CC;BAMUM LETTER PHASE-C MBUAEM;Lo;0;L;;;;;N;;;;;\n168CD;BAMUM LETTER PHASE-C LU;Lo;0;L;;;;;N;;;;;\n168CE;BAMUM LETTER PHASE-C KUT;Lo;0;L;;;;;N;;;;;\n168CF;BAMUM LETTER PHASE-C NJAM;Lo;0;L;;;;;N;;;;;\n168D0;BAMUM LETTER PHASE-C NGOM;Lo;0;L;;;;;N;;;;;\n168D1;BAMUM LETTER PHASE-C WUP;Lo;0;L;;;;;N;;;;;\n168D2;BAMUM LETTER PHASE-C NGGUEET;Lo;0;L;;;;;N;;;;;\n168D3;BAMUM LETTER PHASE-C NSOM;Lo;0;L;;;;;N;;;;;\n168D4;BAMUM LETTER PHASE-C NTEN;Lo;0;L;;;;;N;;;;;\n168D5;BAMUM LETTER PHASE-C KUOP NKAARAE;Lo;0;L;;;;;N;;;;;\n168D6;BAMUM LETTER PHASE-C NSUN;Lo;0;L;;;;;N;;;;;\n168D7;BAMUM LETTER PHASE-C NDAM;Lo;0;L;;;;;N;;;;;\n168D8;BAMUM LETTER PHASE-C MA NSIEE;Lo;0;L;;;;;N;;;;;\n168D9;BAMUM LETTER PHASE-C YAA;Lo;0;L;;;;;N;;;;;\n168DA;BAMUM LETTER PHASE-C NDAP;Lo;0;L;;;;;N;;;;;\n168DB;BAMUM LETTER PHASE-C SHUEQ;Lo;0;L;;;;;N;;;;;\n168DC;BAMUM LETTER PHASE-C SETFON;Lo;0;L;;;;;N;;;;;\n168DD;BAMUM LETTER PHASE-C MBI;Lo;0;L;;;;;N;;;;;\n168DE;BAMUM LETTER PHASE-C MAEMBA;Lo;0;L;;;;;N;;;;;\n168DF;BAMUM LETTER PHASE-C MBANYI;Lo;0;L;;;;;N;;;;;\n168E0;BAMUM LETTER PHASE-C KEUSEUX;Lo;0;L;;;;;N;;;;;\n168E1;BAMUM LETTER PHASE-C MBEUX;Lo;0;L;;;;;N;;;;;\n168E2;BAMUM LETTER PHASE-C KEUM;Lo;0;L;;;;;N;;;;;\n168E3;BAMUM LETTER PHASE-C MBAA PICKET;Lo;0;L;;;;;N;;;;;\n168E4;BAMUM LETTER PHASE-C YUWOQ;Lo;0;L;;;;;N;;;;;\n168E5;BAMUM LETTER PHASE-C NJEUX;Lo;0;L;;;;;N;;;;;\n168E6;BAMUM LETTER PHASE-C MIEE;Lo;0;L;;;;;N;;;;;\n168E7;BAMUM LETTER PHASE-C MUAE;Lo;0;L;;;;;N;;;;;\n168E8;BAMUM LETTER PHASE-C SHIQ;Lo;0;L;;;;;N;;;;;\n168E9;BAMUM LETTER PHASE-C KEN LAW;Lo;0;L;;;;;N;;;;;\n168EA;BAMUM LETTER PHASE-C KEN FATIGUE;Lo;0;L;;;;;N;;;;;\n168EB;BAMUM LETTER PHASE-C NGAQ;Lo;0;L;;;;;N;;;;;\n168EC;BAMUM LETTER PHASE-C NAQ;Lo;0;L;;;;;N;;;;;\n168ED;BAMUM LETTER PHASE-C LIQ;Lo;0;L;;;;;N;;;;;\n168EE;BAMUM LETTER PHASE-C PIN;Lo;0;L;;;;;N;;;;;\n168EF;BAMUM LETTER PHASE-C PEN;Lo;0;L;;;;;N;;;;;\n168F0;BAMUM LETTER PHASE-C TET;Lo;0;L;;;;;N;;;;;\n168F1;BAMUM LETTER PHASE-D MBUO;Lo;0;L;;;;;N;;;;;\n168F2;BAMUM LETTER PHASE-D WAP;Lo;0;L;;;;;N;;;;;\n168F3;BAMUM LETTER PHASE-D NJI;Lo;0;L;;;;;N;;;;;\n168F4;BAMUM LETTER PHASE-D MFON;Lo;0;L;;;;;N;;;;;\n168F5;BAMUM LETTER PHASE-D NJIEE;Lo;0;L;;;;;N;;;;;\n168F6;BAMUM LETTER PHASE-D LIEE;Lo;0;L;;;;;N;;;;;\n168F7;BAMUM LETTER PHASE-D NJEUT;Lo;0;L;;;;;N;;;;;\n168F8;BAMUM LETTER PHASE-D NSHEE;Lo;0;L;;;;;N;;;;;\n168F9;BAMUM LETTER PHASE-D NGGAAMAE;Lo;0;L;;;;;N;;;;;\n168FA;BAMUM LETTER PHASE-D NYAM;Lo;0;L;;;;;N;;;;;\n168FB;BAMUM LETTER PHASE-D WUAEN;Lo;0;L;;;;;N;;;;;\n168FC;BAMUM LETTER PHASE-D NGKUN;Lo;0;L;;;;;N;;;;;\n168FD;BAMUM LETTER PHASE-D SHEE;Lo;0;L;;;;;N;;;;;\n168FE;BAMUM LETTER PHASE-D NGKAP;Lo;0;L;;;;;N;;;;;\n168FF;BAMUM LETTER PHASE-D KEUAETMEUN;Lo;0;L;;;;;N;;;;;\n16900;BAMUM LETTER PHASE-D TEUT;Lo;0;L;;;;;N;;;;;\n16901;BAMUM LETTER PHASE-D SHEUAE;Lo;0;L;;;;;N;;;;;\n16902;BAMUM LETTER PHASE-D NJAP;Lo;0;L;;;;;N;;;;;\n16903;BAMUM LETTER PHASE-D SUE;Lo;0;L;;;;;N;;;;;\n16904;BAMUM LETTER PHASE-D KET;Lo;0;L;;;;;N;;;;;\n16905;BAMUM LETTER PHASE-D YAEMMAE;Lo;0;L;;;;;N;;;;;\n16906;BAMUM LETTER PHASE-D KUOM;Lo;0;L;;;;;N;;;;;\n16907;BAMUM LETTER PHASE-D SAP;Lo;0;L;;;;;N;;;;;\n16908;BAMUM LETTER PHASE-D MFEUT;Lo;0;L;;;;;N;;;;;\n16909;BAMUM LETTER PHASE-D NDEUX;Lo;0;L;;;;;N;;;;;\n1690A;BAMUM LETTER PHASE-D MALEERI;Lo;0;L;;;;;N;;;;;\n1690B;BAMUM LETTER PHASE-D MEUT;Lo;0;L;;;;;N;;;;;\n1690C;BAMUM LETTER PHASE-D SEUAEQ;Lo;0;L;;;;;N;;;;;\n1690D;BAMUM LETTER PHASE-D YEN;Lo;0;L;;;;;N;;;;;\n1690E;BAMUM LETTER PHASE-D NJEUAEM;Lo;0;L;;;;;N;;;;;\n1690F;BAMUM LETTER PHASE-D KEUOT MBUAE;Lo;0;L;;;;;N;;;;;\n16910;BAMUM LETTER PHASE-D NGKEURI;Lo;0;L;;;;;N;;;;;\n16911;BAMUM LETTER PHASE-D TU;Lo;0;L;;;;;N;;;;;\n16912;BAMUM LETTER PHASE-D GHAA;Lo;0;L;;;;;N;;;;;\n16913;BAMUM LETTER PHASE-D NGKYEE;Lo;0;L;;;;;N;;;;;\n16914;BAMUM LETTER PHASE-D FEUFEUAET;Lo;0;L;;;;;N;;;;;\n16915;BAMUM LETTER PHASE-D NDEE;Lo;0;L;;;;;N;;;;;\n16916;BAMUM LETTER PHASE-D MGBOFUM;Lo;0;L;;;;;N;;;;;\n16917;BAMUM LETTER PHASE-D LEUAEP;Lo;0;L;;;;;N;;;;;\n16918;BAMUM LETTER PHASE-D NDON;Lo;0;L;;;;;N;;;;;\n16919;BAMUM LETTER PHASE-D MONI;Lo;0;L;;;;;N;;;;;\n1691A;BAMUM LETTER PHASE-D MGBEUN;Lo;0;L;;;;;N;;;;;\n1691B;BAMUM LETTER PHASE-D PUUT;Lo;0;L;;;;;N;;;;;\n1691C;BAMUM LETTER PHASE-D MGBIEE;Lo;0;L;;;;;N;;;;;\n1691D;BAMUM LETTER PHASE-D MFO;Lo;0;L;;;;;N;;;;;\n1691E;BAMUM LETTER PHASE-D LUM;Lo;0;L;;;;;N;;;;;\n1691F;BAMUM LETTER PHASE-D NSIEEP;Lo;0;L;;;;;N;;;;;\n16920;BAMUM LETTER PHASE-D MBAA;Lo;0;L;;;;;N;;;;;\n16921;BAMUM LETTER PHASE-D KWAET;Lo;0;L;;;;;N;;;;;\n16922;BAMUM LETTER PHASE-D NYET;Lo;0;L;;;;;N;;;;;\n16923;BAMUM LETTER PHASE-D TEUAEN;Lo;0;L;;;;;N;;;;;\n16924;BAMUM LETTER PHASE-D SOT;Lo;0;L;;;;;N;;;;;\n16925;BAMUM LETTER PHASE-D YUWOQ;Lo;0;L;;;;;N;;;;;\n16926;BAMUM LETTER PHASE-D KEUM;Lo;0;L;;;;;N;;;;;\n16927;BAMUM LETTER PHASE-D RAEM;Lo;0;L;;;;;N;;;;;\n16928;BAMUM LETTER PHASE-D TEEEE;Lo;0;L;;;;;N;;;;;\n16929;BAMUM LETTER PHASE-D NGKEUAEQ;Lo;0;L;;;;;N;;;;;\n1692A;BAMUM LETTER PHASE-D MFEUAE;Lo;0;L;;;;;N;;;;;\n1692B;BAMUM LETTER PHASE-D NSIEET;Lo;0;L;;;;;N;;;;;\n1692C;BAMUM LETTER PHASE-D KEUP;Lo;0;L;;;;;N;;;;;\n1692D;BAMUM LETTER PHASE-D PIP;Lo;0;L;;;;;N;;;;;\n1692E;BAMUM LETTER PHASE-D PEUTAE;Lo;0;L;;;;;N;;;;;\n1692F;BAMUM LETTER PHASE-D NYUE;Lo;0;L;;;;;N;;;;;\n16930;BAMUM LETTER PHASE-D LET;Lo;0;L;;;;;N;;;;;\n16931;BAMUM LETTER PHASE-D NGGAAM;Lo;0;L;;;;;N;;;;;\n16932;BAMUM LETTER PHASE-D MFIEE;Lo;0;L;;;;;N;;;;;\n16933;BAMUM LETTER PHASE-D NGGWAEN;Lo;0;L;;;;;N;;;;;\n16934;BAMUM LETTER PHASE-D YUOM;Lo;0;L;;;;;N;;;;;\n16935;BAMUM LETTER PHASE-D PAP;Lo;0;L;;;;;N;;;;;\n16936;BAMUM LETTER PHASE-D YUOP;Lo;0;L;;;;;N;;;;;\n16937;BAMUM LETTER PHASE-D NDAM;Lo;0;L;;;;;N;;;;;\n16938;BAMUM LETTER PHASE-D NTEUM;Lo;0;L;;;;;N;;;;;\n16939;BAMUM LETTER PHASE-D SUAE;Lo;0;L;;;;;N;;;;;\n1693A;BAMUM LETTER PHASE-D KUN;Lo;0;L;;;;;N;;;;;\n1693B;BAMUM LETTER PHASE-D NGGEUX;Lo;0;L;;;;;N;;;;;\n1693C;BAMUM LETTER PHASE-D NGKIEE;Lo;0;L;;;;;N;;;;;\n1693D;BAMUM LETTER PHASE-D TUOT;Lo;0;L;;;;;N;;;;;\n1693E;BAMUM LETTER PHASE-D MEUN;Lo;0;L;;;;;N;;;;;\n1693F;BAMUM LETTER PHASE-D KUQ;Lo;0;L;;;;;N;;;;;\n16940;BAMUM LETTER PHASE-D NSUM;Lo;0;L;;;;;N;;;;;\n16941;BAMUM LETTER PHASE-D TEUN;Lo;0;L;;;;;N;;;;;\n16942;BAMUM LETTER PHASE-D MAENJET;Lo;0;L;;;;;N;;;;;\n16943;BAMUM LETTER PHASE-D NGGAP;Lo;0;L;;;;;N;;;;;\n16944;BAMUM LETTER PHASE-D LEUM;Lo;0;L;;;;;N;;;;;\n16945;BAMUM LETTER PHASE-D NGGUOM;Lo;0;L;;;;;N;;;;;\n16946;BAMUM LETTER PHASE-D NSHUT;Lo;0;L;;;;;N;;;;;\n16947;BAMUM LETTER PHASE-D NJUEQ;Lo;0;L;;;;;N;;;;;\n16948;BAMUM LETTER PHASE-D GHEUAE;Lo;0;L;;;;;N;;;;;\n16949;BAMUM LETTER PHASE-D KU;Lo;0;L;;;;;N;;;;;\n1694A;BAMUM LETTER PHASE-D REN OLD;Lo;0;L;;;;;N;;;;;\n1694B;BAMUM LETTER PHASE-D TAE;Lo;0;L;;;;;N;;;;;\n1694C;BAMUM LETTER PHASE-D TOQ;Lo;0;L;;;;;N;;;;;\n1694D;BAMUM LETTER PHASE-D NYI;Lo;0;L;;;;;N;;;;;\n1694E;BAMUM LETTER PHASE-D RII;Lo;0;L;;;;;N;;;;;\n1694F;BAMUM LETTER PHASE-D LEEEE;Lo;0;L;;;;;N;;;;;\n16950;BAMUM LETTER PHASE-D MEEEE;Lo;0;L;;;;;N;;;;;\n16951;BAMUM LETTER PHASE-D M;Lo;0;L;;;;;N;;;;;\n16952;BAMUM LETTER PHASE-D SUU;Lo;0;L;;;;;N;;;;;\n16953;BAMUM LETTER PHASE-D MU;Lo;0;L;;;;;N;;;;;\n16954;BAMUM LETTER PHASE-D SHII;Lo;0;L;;;;;N;;;;;\n16955;BAMUM LETTER PHASE-D SHEUX;Lo;0;L;;;;;N;;;;;\n16956;BAMUM LETTER PHASE-D KYEE;Lo;0;L;;;;;N;;;;;\n16957;BAMUM LETTER PHASE-D NU;Lo;0;L;;;;;N;;;;;\n16958;BAMUM LETTER PHASE-D SHU;Lo;0;L;;;;;N;;;;;\n16959;BAMUM LETTER PHASE-D NTEE;Lo;0;L;;;;;N;;;;;\n1695A;BAMUM LETTER PHASE-D PEE;Lo;0;L;;;;;N;;;;;\n1695B;BAMUM LETTER PHASE-D NI;Lo;0;L;;;;;N;;;;;\n1695C;BAMUM LETTER PHASE-D SHOQ;Lo;0;L;;;;;N;;;;;\n1695D;BAMUM LETTER PHASE-D PUQ;Lo;0;L;;;;;N;;;;;\n1695E;BAMUM LETTER PHASE-D MVOP;Lo;0;L;;;;;N;;;;;\n1695F;BAMUM LETTER PHASE-D LOQ;Lo;0;L;;;;;N;;;;;\n16960;BAMUM LETTER PHASE-D REN MUCH;Lo;0;L;;;;;N;;;;;\n16961;BAMUM LETTER PHASE-D TI;Lo;0;L;;;;;N;;;;;\n16962;BAMUM LETTER PHASE-D NTUU;Lo;0;L;;;;;N;;;;;\n16963;BAMUM LETTER PHASE-D MBAA SEVEN;Lo;0;L;;;;;N;;;;;\n16964;BAMUM LETTER PHASE-D SAQ;Lo;0;L;;;;;N;;;;;\n16965;BAMUM LETTER PHASE-D FAA;Lo;0;L;;;;;N;;;;;\n16966;BAMUM LETTER PHASE-E NDAP;Lo;0;L;;;;;N;;;;;\n16967;BAMUM LETTER PHASE-E TOON;Lo;0;L;;;;;N;;;;;\n16968;BAMUM LETTER PHASE-E MBEUM;Lo;0;L;;;;;N;;;;;\n16969;BAMUM LETTER PHASE-E LAP;Lo;0;L;;;;;N;;;;;\n1696A;BAMUM LETTER PHASE-E VOM;Lo;0;L;;;;;N;;;;;\n1696B;BAMUM LETTER PHASE-E LOON;Lo;0;L;;;;;N;;;;;\n1696C;BAMUM LETTER PHASE-E PAA;Lo;0;L;;;;;N;;;;;\n1696D;BAMUM LETTER PHASE-E SOM;Lo;0;L;;;;;N;;;;;\n1696E;BAMUM LETTER PHASE-E RAQ;Lo;0;L;;;;;N;;;;;\n1696F;BAMUM LETTER PHASE-E NSHUOP;Lo;0;L;;;;;N;;;;;\n16970;BAMUM LETTER PHASE-E NDUN;Lo;0;L;;;;;N;;;;;\n16971;BAMUM LETTER PHASE-E PUAE;Lo;0;L;;;;;N;;;;;\n16972;BAMUM LETTER PHASE-E TAM;Lo;0;L;;;;;N;;;;;\n16973;BAMUM LETTER PHASE-E NGKA;Lo;0;L;;;;;N;;;;;\n16974;BAMUM LETTER PHASE-E KPEUX;Lo;0;L;;;;;N;;;;;\n16975;BAMUM LETTER PHASE-E WUO;Lo;0;L;;;;;N;;;;;\n16976;BAMUM LETTER PHASE-E SEE;Lo;0;L;;;;;N;;;;;\n16977;BAMUM LETTER PHASE-E NGGEUAET;Lo;0;L;;;;;N;;;;;\n16978;BAMUM LETTER PHASE-E PAAM;Lo;0;L;;;;;N;;;;;\n16979;BAMUM LETTER PHASE-E TOO;Lo;0;L;;;;;N;;;;;\n1697A;BAMUM LETTER PHASE-E KUOP;Lo;0;L;;;;;N;;;;;\n1697B;BAMUM LETTER PHASE-E LOM;Lo;0;L;;;;;N;;;;;\n1697C;BAMUM LETTER PHASE-E NSHIEE;Lo;0;L;;;;;N;;;;;\n1697D;BAMUM LETTER PHASE-E NGOP;Lo;0;L;;;;;N;;;;;\n1697E;BAMUM LETTER PHASE-E MAEM;Lo;0;L;;;;;N;;;;;\n1697F;BAMUM LETTER PHASE-E NGKEUX;Lo;0;L;;;;;N;;;;;\n16980;BAMUM LETTER PHASE-E NGOQ;Lo;0;L;;;;;N;;;;;\n16981;BAMUM LETTER PHASE-E NSHUE;Lo;0;L;;;;;N;;;;;\n16982;BAMUM LETTER PHASE-E RIMGBA;Lo;0;L;;;;;N;;;;;\n16983;BAMUM LETTER PHASE-E NJEUX;Lo;0;L;;;;;N;;;;;\n16984;BAMUM LETTER PHASE-E PEEM;Lo;0;L;;;;;N;;;;;\n16985;BAMUM LETTER PHASE-E SAA;Lo;0;L;;;;;N;;;;;\n16986;BAMUM LETTER PHASE-E NGGURAE;Lo;0;L;;;;;N;;;;;\n16987;BAMUM LETTER PHASE-E MGBA;Lo;0;L;;;;;N;;;;;\n16988;BAMUM LETTER PHASE-E GHEUX;Lo;0;L;;;;;N;;;;;\n16989;BAMUM LETTER PHASE-E NGKEUAEM;Lo;0;L;;;;;N;;;;;\n1698A;BAMUM LETTER PHASE-E NJAEMLI;Lo;0;L;;;;;N;;;;;\n1698B;BAMUM LETTER PHASE-E MAP;Lo;0;L;;;;;N;;;;;\n1698C;BAMUM LETTER PHASE-E LOOT;Lo;0;L;;;;;N;;;;;\n1698D;BAMUM LETTER PHASE-E NGGEEEE;Lo;0;L;;;;;N;;;;;\n1698E;BAMUM LETTER PHASE-E NDIQ;Lo;0;L;;;;;N;;;;;\n1698F;BAMUM LETTER PHASE-E TAEN NTEUM;Lo;0;L;;;;;N;;;;;\n16990;BAMUM LETTER PHASE-E SET;Lo;0;L;;;;;N;;;;;\n16991;BAMUM LETTER PHASE-E PUM;Lo;0;L;;;;;N;;;;;\n16992;BAMUM LETTER PHASE-E NDAA SOFTNESS;Lo;0;L;;;;;N;;;;;\n16993;BAMUM LETTER PHASE-E NGGUAESHAE NYAM;Lo;0;L;;;;;N;;;;;\n16994;BAMUM LETTER PHASE-E YIEE;Lo;0;L;;;;;N;;;;;\n16995;BAMUM LETTER PHASE-E GHEUN;Lo;0;L;;;;;N;;;;;\n16996;BAMUM LETTER PHASE-E TUAE;Lo;0;L;;;;;N;;;;;\n16997;BAMUM LETTER PHASE-E YEUAE;Lo;0;L;;;;;N;;;;;\n16998;BAMUM LETTER PHASE-E PO;Lo;0;L;;;;;N;;;;;\n16999;BAMUM LETTER PHASE-E TUMAE;Lo;0;L;;;;;N;;;;;\n1699A;BAMUM LETTER PHASE-E KEUAE;Lo;0;L;;;;;N;;;;;\n1699B;BAMUM LETTER PHASE-E SUAEN;Lo;0;L;;;;;N;;;;;\n1699C;BAMUM LETTER PHASE-E TEUAEQ;Lo;0;L;;;;;N;;;;;\n1699D;BAMUM LETTER PHASE-E VEUAE;Lo;0;L;;;;;N;;;;;\n1699E;BAMUM LETTER PHASE-E WEUX;Lo;0;L;;;;;N;;;;;\n1699F;BAMUM LETTER PHASE-E LAAM;Lo;0;L;;;;;N;;;;;\n169A0;BAMUM LETTER PHASE-E PU;Lo;0;L;;;;;N;;;;;\n169A1;BAMUM LETTER PHASE-E TAAQ;Lo;0;L;;;;;N;;;;;\n169A2;BAMUM LETTER PHASE-E GHAAMAE;Lo;0;L;;;;;N;;;;;\n169A3;BAMUM LETTER PHASE-E NGEUREUT;Lo;0;L;;;;;N;;;;;\n169A4;BAMUM LETTER PHASE-E SHEUAEQ;Lo;0;L;;;;;N;;;;;\n169A5;BAMUM LETTER PHASE-E MGBEN;Lo;0;L;;;;;N;;;;;\n169A6;BAMUM LETTER PHASE-E MBEE;Lo;0;L;;;;;N;;;;;\n169A7;BAMUM LETTER PHASE-E NZAQ;Lo;0;L;;;;;N;;;;;\n169A8;BAMUM LETTER PHASE-E NKOM;Lo;0;L;;;;;N;;;;;\n169A9;BAMUM LETTER PHASE-E GBET;Lo;0;L;;;;;N;;;;;\n169AA;BAMUM LETTER PHASE-E TUM;Lo;0;L;;;;;N;;;;;\n169AB;BAMUM LETTER PHASE-E KUET;Lo;0;L;;;;;N;;;;;\n169AC;BAMUM LETTER PHASE-E YAP;Lo;0;L;;;;;N;;;;;\n169AD;BAMUM LETTER PHASE-E NYI CLEAVER;Lo;0;L;;;;;N;;;;;\n169AE;BAMUM LETTER PHASE-E YIT;Lo;0;L;;;;;N;;;;;\n169AF;BAMUM LETTER PHASE-E MFEUQ;Lo;0;L;;;;;N;;;;;\n169B0;BAMUM LETTER PHASE-E NDIAQ;Lo;0;L;;;;;N;;;;;\n169B1;BAMUM LETTER PHASE-E PIEEQ;Lo;0;L;;;;;N;;;;;\n169B2;BAMUM LETTER PHASE-E YUEQ;Lo;0;L;;;;;N;;;;;\n169B3;BAMUM LETTER PHASE-E LEUAEM;Lo;0;L;;;;;N;;;;;\n169B4;BAMUM LETTER PHASE-E FUE;Lo;0;L;;;;;N;;;;;\n169B5;BAMUM LETTER PHASE-E GBEUX;Lo;0;L;;;;;N;;;;;\n169B6;BAMUM LETTER PHASE-E NGKUP;Lo;0;L;;;;;N;;;;;\n169B7;BAMUM LETTER PHASE-E KET;Lo;0;L;;;;;N;;;;;\n169B8;BAMUM LETTER PHASE-E MAE;Lo;0;L;;;;;N;;;;;\n169B9;BAMUM LETTER PHASE-E NGKAAMI;Lo;0;L;;;;;N;;;;;\n169BA;BAMUM LETTER PHASE-E GHET;Lo;0;L;;;;;N;;;;;\n169BB;BAMUM LETTER PHASE-E FA;Lo;0;L;;;;;N;;;;;\n169BC;BAMUM LETTER PHASE-E NTUM;Lo;0;L;;;;;N;;;;;\n169BD;BAMUM LETTER PHASE-E PEUT;Lo;0;L;;;;;N;;;;;\n169BE;BAMUM LETTER PHASE-E YEUM;Lo;0;L;;;;;N;;;;;\n169BF;BAMUM LETTER PHASE-E NGGEUAE;Lo;0;L;;;;;N;;;;;\n169C0;BAMUM LETTER PHASE-E NYI BETWEEN;Lo;0;L;;;;;N;;;;;\n169C1;BAMUM LETTER PHASE-E NZUQ;Lo;0;L;;;;;N;;;;;\n169C2;BAMUM LETTER PHASE-E POON;Lo;0;L;;;;;N;;;;;\n169C3;BAMUM LETTER PHASE-E MIEE;Lo;0;L;;;;;N;;;;;\n169C4;BAMUM LETTER PHASE-E FUET;Lo;0;L;;;;;N;;;;;\n169C5;BAMUM LETTER PHASE-E NAE;Lo;0;L;;;;;N;;;;;\n169C6;BAMUM LETTER PHASE-E MUAE;Lo;0;L;;;;;N;;;;;\n169C7;BAMUM LETTER PHASE-E GHEUAE;Lo;0;L;;;;;N;;;;;\n169C8;BAMUM LETTER PHASE-E FU I;Lo;0;L;;;;;N;;;;;\n169C9;BAMUM LETTER PHASE-E MVI;Lo;0;L;;;;;N;;;;;\n169CA;BAMUM LETTER PHASE-E PUAQ;Lo;0;L;;;;;N;;;;;\n169CB;BAMUM LETTER PHASE-E NGKUM;Lo;0;L;;;;;N;;;;;\n169CC;BAMUM LETTER PHASE-E KUT;Lo;0;L;;;;;N;;;;;\n169CD;BAMUM LETTER PHASE-E PIET;Lo;0;L;;;;;N;;;;;\n169CE;BAMUM LETTER PHASE-E NTAP;Lo;0;L;;;;;N;;;;;\n169CF;BAMUM LETTER PHASE-E YEUAET;Lo;0;L;;;;;N;;;;;\n169D0;BAMUM LETTER PHASE-E NGGUP;Lo;0;L;;;;;N;;;;;\n169D1;BAMUM LETTER PHASE-E PA PEOPLE;Lo;0;L;;;;;N;;;;;\n169D2;BAMUM LETTER PHASE-E FU CALL;Lo;0;L;;;;;N;;;;;\n169D3;BAMUM LETTER PHASE-E FOM;Lo;0;L;;;;;N;;;;;\n169D4;BAMUM LETTER PHASE-E NJEE;Lo;0;L;;;;;N;;;;;\n169D5;BAMUM LETTER PHASE-E A;Lo;0;L;;;;;N;;;;;\n169D6;BAMUM LETTER PHASE-E TOQ;Lo;0;L;;;;;N;;;;;\n169D7;BAMUM LETTER PHASE-E O;Lo;0;L;;;;;N;;;;;\n169D8;BAMUM LETTER PHASE-E I;Lo;0;L;;;;;N;;;;;\n169D9;BAMUM LETTER PHASE-E LAQ;Lo;0;L;;;;;N;;;;;\n169DA;BAMUM LETTER PHASE-E PA PLURAL;Lo;0;L;;;;;N;;;;;\n169DB;BAMUM LETTER PHASE-E TAA;Lo;0;L;;;;;N;;;;;\n169DC;BAMUM LETTER PHASE-E TAQ;Lo;0;L;;;;;N;;;;;\n169DD;BAMUM LETTER PHASE-E NDAA MY HOUSE;Lo;0;L;;;;;N;;;;;\n169DE;BAMUM LETTER PHASE-E SHIQ;Lo;0;L;;;;;N;;;;;\n169DF;BAMUM LETTER PHASE-E YEUX;Lo;0;L;;;;;N;;;;;\n169E0;BAMUM LETTER PHASE-E NGUAE;Lo;0;L;;;;;N;;;;;\n169E1;BAMUM LETTER PHASE-E YUAEN;Lo;0;L;;;;;N;;;;;\n169E2;BAMUM LETTER PHASE-E YOQ SWIMMING;Lo;0;L;;;;;N;;;;;\n169E3;BAMUM LETTER PHASE-E YOQ COVER;Lo;0;L;;;;;N;;;;;\n169E4;BAMUM LETTER PHASE-E YUQ;Lo;0;L;;;;;N;;;;;\n169E5;BAMUM LETTER PHASE-E YUN;Lo;0;L;;;;;N;;;;;\n169E6;BAMUM LETTER PHASE-E KEUX;Lo;0;L;;;;;N;;;;;\n169E7;BAMUM LETTER PHASE-E PEUX;Lo;0;L;;;;;N;;;;;\n169E8;BAMUM LETTER PHASE-E NJEE EPOCH;Lo;0;L;;;;;N;;;;;\n169E9;BAMUM LETTER PHASE-E PUE;Lo;0;L;;;;;N;;;;;\n169EA;BAMUM LETTER PHASE-E WUE;Lo;0;L;;;;;N;;;;;\n169EB;BAMUM LETTER PHASE-E FEE;Lo;0;L;;;;;N;;;;;\n169EC;BAMUM LETTER PHASE-E VEE;Lo;0;L;;;;;N;;;;;\n169ED;BAMUM LETTER PHASE-E LU;Lo;0;L;;;;;N;;;;;\n169EE;BAMUM LETTER PHASE-E MI;Lo;0;L;;;;;N;;;;;\n169EF;BAMUM LETTER PHASE-E REUX;Lo;0;L;;;;;N;;;;;\n169F0;BAMUM LETTER PHASE-E RAE;Lo;0;L;;;;;N;;;;;\n169F1;BAMUM LETTER PHASE-E NGUAET;Lo;0;L;;;;;N;;;;;\n169F2;BAMUM LETTER PHASE-E NGA;Lo;0;L;;;;;N;;;;;\n169F3;BAMUM LETTER PHASE-E SHO;Lo;0;L;;;;;N;;;;;\n169F4;BAMUM LETTER PHASE-E SHOQ;Lo;0;L;;;;;N;;;;;\n169F5;BAMUM LETTER PHASE-E FU REMEDY;Lo;0;L;;;;;N;;;;;\n169F6;BAMUM LETTER PHASE-E NA;Lo;0;L;;;;;N;;;;;\n169F7;BAMUM LETTER PHASE-E PI;Lo;0;L;;;;;N;;;;;\n169F8;BAMUM LETTER PHASE-E LOQ;Lo;0;L;;;;;N;;;;;\n169F9;BAMUM LETTER PHASE-E KO;Lo;0;L;;;;;N;;;;;\n169FA;BAMUM LETTER PHASE-E MEN;Lo;0;L;;;;;N;;;;;\n169FB;BAMUM LETTER PHASE-E MA;Lo;0;L;;;;;N;;;;;\n169FC;BAMUM LETTER PHASE-E MAQ;Lo;0;L;;;;;N;;;;;\n169FD;BAMUM LETTER PHASE-E TEU;Lo;0;L;;;;;N;;;;;\n169FE;BAMUM LETTER PHASE-E KI;Lo;0;L;;;;;N;;;;;\n169FF;BAMUM LETTER PHASE-E MON;Lo;0;L;;;;;N;;;;;\n16A00;BAMUM LETTER PHASE-E TEN;Lo;0;L;;;;;N;;;;;\n16A01;BAMUM LETTER PHASE-E FAQ;Lo;0;L;;;;;N;;;;;\n16A02;BAMUM LETTER PHASE-E GHOM;Lo;0;L;;;;;N;;;;;\n16A03;BAMUM LETTER PHASE-F KA;Lo;0;L;;;;;N;;;;;\n16A04;BAMUM LETTER PHASE-F U;Lo;0;L;;;;;N;;;;;\n16A05;BAMUM LETTER PHASE-F KU;Lo;0;L;;;;;N;;;;;\n16A06;BAMUM LETTER PHASE-F EE;Lo;0;L;;;;;N;;;;;\n16A07;BAMUM LETTER PHASE-F REE;Lo;0;L;;;;;N;;;;;\n16A08;BAMUM LETTER PHASE-F TAE;Lo;0;L;;;;;N;;;;;\n16A09;BAMUM LETTER PHASE-F NYI;Lo;0;L;;;;;N;;;;;\n16A0A;BAMUM LETTER PHASE-F LA;Lo;0;L;;;;;N;;;;;\n16A0B;BAMUM LETTER PHASE-F RII;Lo;0;L;;;;;N;;;;;\n16A0C;BAMUM LETTER PHASE-F RIEE;Lo;0;L;;;;;N;;;;;\n16A0D;BAMUM LETTER PHASE-F MEEEE;Lo;0;L;;;;;N;;;;;\n16A0E;BAMUM LETTER PHASE-F TAA;Lo;0;L;;;;;N;;;;;\n16A0F;BAMUM LETTER PHASE-F NDAA;Lo;0;L;;;;;N;;;;;\n16A10;BAMUM LETTER PHASE-F NJAEM;Lo;0;L;;;;;N;;;;;\n16A11;BAMUM LETTER PHASE-F M;Lo;0;L;;;;;N;;;;;\n16A12;BAMUM LETTER PHASE-F SUU;Lo;0;L;;;;;N;;;;;\n16A13;BAMUM LETTER PHASE-F SHII;Lo;0;L;;;;;N;;;;;\n16A14;BAMUM LETTER PHASE-F SI;Lo;0;L;;;;;N;;;;;\n16A15;BAMUM LETTER PHASE-F SEUX;Lo;0;L;;;;;N;;;;;\n16A16;BAMUM LETTER PHASE-F KYEE;Lo;0;L;;;;;N;;;;;\n16A17;BAMUM LETTER PHASE-F KET;Lo;0;L;;;;;N;;;;;\n16A18;BAMUM LETTER PHASE-F NUAE;Lo;0;L;;;;;N;;;;;\n16A19;BAMUM LETTER PHASE-F NU;Lo;0;L;;;;;N;;;;;\n16A1A;BAMUM LETTER PHASE-F NJUAE;Lo;0;L;;;;;N;;;;;\n16A1B;BAMUM LETTER PHASE-F YOQ;Lo;0;L;;;;;N;;;;;\n16A1C;BAMUM LETTER PHASE-F SHU;Lo;0;L;;;;;N;;;;;\n16A1D;BAMUM LETTER PHASE-F YA;Lo;0;L;;;;;N;;;;;\n16A1E;BAMUM LETTER PHASE-F NSHA;Lo;0;L;;;;;N;;;;;\n16A1F;BAMUM LETTER PHASE-F PEUX;Lo;0;L;;;;;N;;;;;\n16A20;BAMUM LETTER PHASE-F NTEE;Lo;0;L;;;;;N;;;;;\n16A21;BAMUM LETTER PHASE-F WUE;Lo;0;L;;;;;N;;;;;\n16A22;BAMUM LETTER PHASE-F PEE;Lo;0;L;;;;;N;;;;;\n16A23;BAMUM LETTER PHASE-F RU;Lo;0;L;;;;;N;;;;;\n16A24;BAMUM LETTER PHASE-F NI;Lo;0;L;;;;;N;;;;;\n16A25;BAMUM LETTER PHASE-F REUX;Lo;0;L;;;;;N;;;;;\n16A26;BAMUM LETTER PHASE-F KEN;Lo;0;L;;;;;N;;;;;\n16A27;BAMUM LETTER PHASE-F NGKWAEN;Lo;0;L;;;;;N;;;;;\n16A28;BAMUM LETTER PHASE-F NGGA;Lo;0;L;;;;;N;;;;;\n16A29;BAMUM LETTER PHASE-F SHO;Lo;0;L;;;;;N;;;;;\n16A2A;BAMUM LETTER PHASE-F PUAE;Lo;0;L;;;;;N;;;;;\n16A2B;BAMUM LETTER PHASE-F FOM;Lo;0;L;;;;;N;;;;;\n16A2C;BAMUM LETTER PHASE-F WA;Lo;0;L;;;;;N;;;;;\n16A2D;BAMUM LETTER PHASE-F LI;Lo;0;L;;;;;N;;;;;\n16A2E;BAMUM LETTER PHASE-F LOQ;Lo;0;L;;;;;N;;;;;\n16A2F;BAMUM LETTER PHASE-F KO;Lo;0;L;;;;;N;;;;;\n16A30;BAMUM LETTER PHASE-F MBEN;Lo;0;L;;;;;N;;;;;\n16A31;BAMUM LETTER PHASE-F REN;Lo;0;L;;;;;N;;;;;\n16A32;BAMUM LETTER PHASE-F MA;Lo;0;L;;;;;N;;;;;\n16A33;BAMUM LETTER PHASE-F MO;Lo;0;L;;;;;N;;;;;\n16A34;BAMUM LETTER PHASE-F MBAA;Lo;0;L;;;;;N;;;;;\n16A35;BAMUM LETTER PHASE-F TET;Lo;0;L;;;;;N;;;;;\n16A36;BAMUM LETTER PHASE-F KPA;Lo;0;L;;;;;N;;;;;\n16A37;BAMUM LETTER PHASE-F SAMBA;Lo;0;L;;;;;N;;;;;\n16A38;BAMUM LETTER PHASE-F VUEQ;Lo;0;L;;;;;N;;;;;\n16A40;MRO LETTER TA;Lo;0;L;;;;;N;;;;;\n16A41;MRO LETTER NGI;Lo;0;L;;;;;N;;;;;\n16A42;MRO LETTER YO;Lo;0;L;;;;;N;;;;;\n16A43;MRO LETTER MIM;Lo;0;L;;;;;N;;;;;\n16A44;MRO LETTER BA;Lo;0;L;;;;;N;;;;;\n16A45;MRO LETTER DA;Lo;0;L;;;;;N;;;;;\n16A46;MRO LETTER A;Lo;0;L;;;;;N;;;;;\n16A47;MRO LETTER PHI;Lo;0;L;;;;;N;;;;;\n16A48;MRO LETTER KHAI;Lo;0;L;;;;;N;;;;;\n16A49;MRO LETTER HAO;Lo;0;L;;;;;N;;;;;\n16A4A;MRO LETTER DAI;Lo;0;L;;;;;N;;;;;\n16A4B;MRO LETTER CHU;Lo;0;L;;;;;N;;;;;\n16A4C;MRO LETTER KEAAE;Lo;0;L;;;;;N;;;;;\n16A4D;MRO LETTER OL;Lo;0;L;;;;;N;;;;;\n16A4E;MRO LETTER MAEM;Lo;0;L;;;;;N;;;;;\n16A4F;MRO LETTER NIN;Lo;0;L;;;;;N;;;;;\n16A50;MRO LETTER PA;Lo;0;L;;;;;N;;;;;\n16A51;MRO LETTER OO;Lo;0;L;;;;;N;;;;;\n16A52;MRO LETTER O;Lo;0;L;;;;;N;;;;;\n16A53;MRO LETTER RO;Lo;0;L;;;;;N;;;;;\n16A54;MRO LETTER SHI;Lo;0;L;;;;;N;;;;;\n16A55;MRO LETTER THEA;Lo;0;L;;;;;N;;;;;\n16A56;MRO LETTER EA;Lo;0;L;;;;;N;;;;;\n16A57;MRO LETTER WA;Lo;0;L;;;;;N;;;;;\n16A58;MRO LETTER E;Lo;0;L;;;;;N;;;;;\n16A59;MRO LETTER KO;Lo;0;L;;;;;N;;;;;\n16A5A;MRO LETTER LAN;Lo;0;L;;;;;N;;;;;\n16A5B;MRO LETTER LA;Lo;0;L;;;;;N;;;;;\n16A5C;MRO LETTER HAI;Lo;0;L;;;;;N;;;;;\n16A5D;MRO LETTER RI;Lo;0;L;;;;;N;;;;;\n16A5E;MRO LETTER TEK;Lo;0;L;;;;;N;;;;;\n16A60;MRO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n16A61;MRO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n16A62;MRO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n16A63;MRO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n16A64;MRO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n16A65;MRO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n16A66;MRO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n16A67;MRO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n16A68;MRO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n16A69;MRO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n16A6E;MRO DANDA;Po;0;L;;;;;N;;;;;\n16A6F;MRO DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n16A70;TANGSA LETTER OZ;Lo;0;L;;;;;N;;;;;\n16A71;TANGSA LETTER OC;Lo;0;L;;;;;N;;;;;\n16A72;TANGSA LETTER OQ;Lo;0;L;;;;;N;;;;;\n16A73;TANGSA LETTER OX;Lo;0;L;;;;;N;;;;;\n16A74;TANGSA LETTER AZ;Lo;0;L;;;;;N;;;;;\n16A75;TANGSA LETTER AC;Lo;0;L;;;;;N;;;;;\n16A76;TANGSA LETTER AQ;Lo;0;L;;;;;N;;;;;\n16A77;TANGSA LETTER AX;Lo;0;L;;;;;N;;;;;\n16A78;TANGSA LETTER VZ;Lo;0;L;;;;;N;;;;;\n16A79;TANGSA LETTER VC;Lo;0;L;;;;;N;;;;;\n16A7A;TANGSA LETTER VQ;Lo;0;L;;;;;N;;;;;\n16A7B;TANGSA LETTER VX;Lo;0;L;;;;;N;;;;;\n16A7C;TANGSA LETTER EZ;Lo;0;L;;;;;N;;;;;\n16A7D;TANGSA LETTER EC;Lo;0;L;;;;;N;;;;;\n16A7E;TANGSA LETTER EQ;Lo;0;L;;;;;N;;;;;\n16A7F;TANGSA LETTER EX;Lo;0;L;;;;;N;;;;;\n16A80;TANGSA LETTER IZ;Lo;0;L;;;;;N;;;;;\n16A81;TANGSA LETTER IC;Lo;0;L;;;;;N;;;;;\n16A82;TANGSA LETTER IQ;Lo;0;L;;;;;N;;;;;\n16A83;TANGSA LETTER IX;Lo;0;L;;;;;N;;;;;\n16A84;TANGSA LETTER UZ;Lo;0;L;;;;;N;;;;;\n16A85;TANGSA LETTER UC;Lo;0;L;;;;;N;;;;;\n16A86;TANGSA LETTER UQ;Lo;0;L;;;;;N;;;;;\n16A87;TANGSA LETTER UX;Lo;0;L;;;;;N;;;;;\n16A88;TANGSA LETTER AWZ;Lo;0;L;;;;;N;;;;;\n16A89;TANGSA LETTER AWC;Lo;0;L;;;;;N;;;;;\n16A8A;TANGSA LETTER AWQ;Lo;0;L;;;;;N;;;;;\n16A8B;TANGSA LETTER AWX;Lo;0;L;;;;;N;;;;;\n16A8C;TANGSA LETTER UIZ;Lo;0;L;;;;;N;;;;;\n16A8D;TANGSA LETTER UIC;Lo;0;L;;;;;N;;;;;\n16A8E;TANGSA LETTER UIQ;Lo;0;L;;;;;N;;;;;\n16A8F;TANGSA LETTER UIX;Lo;0;L;;;;;N;;;;;\n16A90;TANGSA LETTER FINAL NG;Lo;0;L;;;;;N;;;;;\n16A91;TANGSA LETTER LONG UEX;Lo;0;L;;;;;N;;;;;\n16A92;TANGSA LETTER SHORT UEZ;Lo;0;L;;;;;N;;;;;\n16A93;TANGSA LETTER SHORT AWX;Lo;0;L;;;;;N;;;;;\n16A94;TANGSA LETTER UEC;Lo;0;L;;;;;N;;;;;\n16A95;TANGSA LETTER UEZ;Lo;0;L;;;;;N;;;;;\n16A96;TANGSA LETTER UEQ;Lo;0;L;;;;;N;;;;;\n16A97;TANGSA LETTER UEX;Lo;0;L;;;;;N;;;;;\n16A98;TANGSA LETTER UIUZ;Lo;0;L;;;;;N;;;;;\n16A99;TANGSA LETTER UIUC;Lo;0;L;;;;;N;;;;;\n16A9A;TANGSA LETTER UIUQ;Lo;0;L;;;;;N;;;;;\n16A9B;TANGSA LETTER UIUX;Lo;0;L;;;;;N;;;;;\n16A9C;TANGSA LETTER MZ;Lo;0;L;;;;;N;;;;;\n16A9D;TANGSA LETTER MC;Lo;0;L;;;;;N;;;;;\n16A9E;TANGSA LETTER MQ;Lo;0;L;;;;;N;;;;;\n16A9F;TANGSA LETTER MX;Lo;0;L;;;;;N;;;;;\n16AA0;TANGSA LETTER KA;Lo;0;L;;;;;N;;;;;\n16AA1;TANGSA LETTER KHA;Lo;0;L;;;;;N;;;;;\n16AA2;TANGSA LETTER GA;Lo;0;L;;;;;N;;;;;\n16AA3;TANGSA LETTER NGA;Lo;0;L;;;;;N;;;;;\n16AA4;TANGSA LETTER SA;Lo;0;L;;;;;N;;;;;\n16AA5;TANGSA LETTER YA;Lo;0;L;;;;;N;;;;;\n16AA6;TANGSA LETTER WA;Lo;0;L;;;;;N;;;;;\n16AA7;TANGSA LETTER PA;Lo;0;L;;;;;N;;;;;\n16AA8;TANGSA LETTER NYA;Lo;0;L;;;;;N;;;;;\n16AA9;TANGSA LETTER PHA;Lo;0;L;;;;;N;;;;;\n16AAA;TANGSA LETTER BA;Lo;0;L;;;;;N;;;;;\n16AAB;TANGSA LETTER MA;Lo;0;L;;;;;N;;;;;\n16AAC;TANGSA LETTER NA;Lo;0;L;;;;;N;;;;;\n16AAD;TANGSA LETTER HA;Lo;0;L;;;;;N;;;;;\n16AAE;TANGSA LETTER LA;Lo;0;L;;;;;N;;;;;\n16AAF;TANGSA LETTER HTA;Lo;0;L;;;;;N;;;;;\n16AB0;TANGSA LETTER TA;Lo;0;L;;;;;N;;;;;\n16AB1;TANGSA LETTER DA;Lo;0;L;;;;;N;;;;;\n16AB2;TANGSA LETTER RA;Lo;0;L;;;;;N;;;;;\n16AB3;TANGSA LETTER NHA;Lo;0;L;;;;;N;;;;;\n16AB4;TANGSA LETTER SHA;Lo;0;L;;;;;N;;;;;\n16AB5;TANGSA LETTER CA;Lo;0;L;;;;;N;;;;;\n16AB6;TANGSA LETTER TSA;Lo;0;L;;;;;N;;;;;\n16AB7;TANGSA LETTER GHA;Lo;0;L;;;;;N;;;;;\n16AB8;TANGSA LETTER HTTA;Lo;0;L;;;;;N;;;;;\n16AB9;TANGSA LETTER THA;Lo;0;L;;;;;N;;;;;\n16ABA;TANGSA LETTER XA;Lo;0;L;;;;;N;;;;;\n16ABB;TANGSA LETTER FA;Lo;0;L;;;;;N;;;;;\n16ABC;TANGSA LETTER DHA;Lo;0;L;;;;;N;;;;;\n16ABD;TANGSA LETTER CHA;Lo;0;L;;;;;N;;;;;\n16ABE;TANGSA LETTER ZA;Lo;0;L;;;;;N;;;;;\n16AC0;TANGSA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n16AC1;TANGSA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n16AC2;TANGSA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n16AC3;TANGSA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n16AC4;TANGSA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n16AC5;TANGSA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n16AC6;TANGSA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n16AC7;TANGSA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n16AC8;TANGSA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n16AC9;TANGSA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n16AD0;BASSA VAH LETTER ENNI;Lo;0;L;;;;;N;;;;;\n16AD1;BASSA VAH LETTER KA;Lo;0;L;;;;;N;;;;;\n16AD2;BASSA VAH LETTER SE;Lo;0;L;;;;;N;;;;;\n16AD3;BASSA VAH LETTER FA;Lo;0;L;;;;;N;;;;;\n16AD4;BASSA VAH LETTER MBE;Lo;0;L;;;;;N;;;;;\n16AD5;BASSA VAH LETTER YIE;Lo;0;L;;;;;N;;;;;\n16AD6;BASSA VAH LETTER GAH;Lo;0;L;;;;;N;;;;;\n16AD7;BASSA VAH LETTER DHII;Lo;0;L;;;;;N;;;;;\n16AD8;BASSA VAH LETTER KPAH;Lo;0;L;;;;;N;;;;;\n16AD9;BASSA VAH LETTER JO;Lo;0;L;;;;;N;;;;;\n16ADA;BASSA VAH LETTER HWAH;Lo;0;L;;;;;N;;;;;\n16ADB;BASSA VAH LETTER WA;Lo;0;L;;;;;N;;;;;\n16ADC;BASSA VAH LETTER ZO;Lo;0;L;;;;;N;;;;;\n16ADD;BASSA VAH LETTER GBU;Lo;0;L;;;;;N;;;;;\n16ADE;BASSA VAH LETTER DO;Lo;0;L;;;;;N;;;;;\n16ADF;BASSA VAH LETTER CE;Lo;0;L;;;;;N;;;;;\n16AE0;BASSA VAH LETTER UWU;Lo;0;L;;;;;N;;;;;\n16AE1;BASSA VAH LETTER TO;Lo;0;L;;;;;N;;;;;\n16AE2;BASSA VAH LETTER BA;Lo;0;L;;;;;N;;;;;\n16AE3;BASSA VAH LETTER VU;Lo;0;L;;;;;N;;;;;\n16AE4;BASSA VAH LETTER YEIN;Lo;0;L;;;;;N;;;;;\n16AE5;BASSA VAH LETTER PA;Lo;0;L;;;;;N;;;;;\n16AE6;BASSA VAH LETTER WADDA;Lo;0;L;;;;;N;;;;;\n16AE7;BASSA VAH LETTER A;Lo;0;L;;;;;N;;;;;\n16AE8;BASSA VAH LETTER O;Lo;0;L;;;;;N;;;;;\n16AE9;BASSA VAH LETTER OO;Lo;0;L;;;;;N;;;;;\n16AEA;BASSA VAH LETTER U;Lo;0;L;;;;;N;;;;;\n16AEB;BASSA VAH LETTER EE;Lo;0;L;;;;;N;;;;;\n16AEC;BASSA VAH LETTER E;Lo;0;L;;;;;N;;;;;\n16AED;BASSA VAH LETTER I;Lo;0;L;;;;;N;;;;;\n16AF0;BASSA VAH COMBINING HIGH TONE;Mn;1;NSM;;;;;N;;;;;\n16AF1;BASSA VAH COMBINING LOW TONE;Mn;1;NSM;;;;;N;;;;;\n16AF2;BASSA VAH COMBINING MID TONE;Mn;1;NSM;;;;;N;;;;;\n16AF3;BASSA VAH COMBINING LOW-MID TONE;Mn;1;NSM;;;;;N;;;;;\n16AF4;BASSA VAH COMBINING HIGH-LOW TONE;Mn;1;NSM;;;;;N;;;;;\n16AF5;BASSA VAH FULL STOP;Po;0;L;;;;;N;;;;;\n16B00;PAHAWH HMONG VOWEL KEEB;Lo;0;L;;;;;N;;;;;\n16B01;PAHAWH HMONG VOWEL KEEV;Lo;0;L;;;;;N;;;;;\n16B02;PAHAWH HMONG VOWEL KIB;Lo;0;L;;;;;N;;;;;\n16B03;PAHAWH HMONG VOWEL KIV;Lo;0;L;;;;;N;;;;;\n16B04;PAHAWH HMONG VOWEL KAUB;Lo;0;L;;;;;N;;;;;\n16B05;PAHAWH HMONG VOWEL KAUV;Lo;0;L;;;;;N;;;;;\n16B06;PAHAWH HMONG VOWEL KUB;Lo;0;L;;;;;N;;;;;\n16B07;PAHAWH HMONG VOWEL KUV;Lo;0;L;;;;;N;;;;;\n16B08;PAHAWH HMONG VOWEL KEB;Lo;0;L;;;;;N;;;;;\n16B09;PAHAWH HMONG VOWEL KEV;Lo;0;L;;;;;N;;;;;\n16B0A;PAHAWH HMONG VOWEL KAIB;Lo;0;L;;;;;N;;;;;\n16B0B;PAHAWH HMONG VOWEL KAIV;Lo;0;L;;;;;N;;;;;\n16B0C;PAHAWH HMONG VOWEL KOOB;Lo;0;L;;;;;N;;;;;\n16B0D;PAHAWH HMONG VOWEL KOOV;Lo;0;L;;;;;N;;;;;\n16B0E;PAHAWH HMONG VOWEL KAWB;Lo;0;L;;;;;N;;;;;\n16B0F;PAHAWH HMONG VOWEL KAWV;Lo;0;L;;;;;N;;;;;\n16B10;PAHAWH HMONG VOWEL KUAB;Lo;0;L;;;;;N;;;;;\n16B11;PAHAWH HMONG VOWEL KUAV;Lo;0;L;;;;;N;;;;;\n16B12;PAHAWH HMONG VOWEL KOB;Lo;0;L;;;;;N;;;;;\n16B13;PAHAWH HMONG VOWEL KOV;Lo;0;L;;;;;N;;;;;\n16B14;PAHAWH HMONG VOWEL KIAB;Lo;0;L;;;;;N;;;;;\n16B15;PAHAWH HMONG VOWEL KIAV;Lo;0;L;;;;;N;;;;;\n16B16;PAHAWH HMONG VOWEL KAB;Lo;0;L;;;;;N;;;;;\n16B17;PAHAWH HMONG VOWEL KAV;Lo;0;L;;;;;N;;;;;\n16B18;PAHAWH HMONG VOWEL KWB;Lo;0;L;;;;;N;;;;;\n16B19;PAHAWH HMONG VOWEL KWV;Lo;0;L;;;;;N;;;;;\n16B1A;PAHAWH HMONG VOWEL KAAB;Lo;0;L;;;;;N;;;;;\n16B1B;PAHAWH HMONG VOWEL KAAV;Lo;0;L;;;;;N;;;;;\n16B1C;PAHAWH HMONG CONSONANT VAU;Lo;0;L;;;;;N;;;;;\n16B1D;PAHAWH HMONG CONSONANT NTSAU;Lo;0;L;;;;;N;;;;;\n16B1E;PAHAWH HMONG CONSONANT LAU;Lo;0;L;;;;;N;;;;;\n16B1F;PAHAWH HMONG CONSONANT HAU;Lo;0;L;;;;;N;;;;;\n16B20;PAHAWH HMONG CONSONANT NLAU;Lo;0;L;;;;;N;;;;;\n16B21;PAHAWH HMONG CONSONANT RAU;Lo;0;L;;;;;N;;;;;\n16B22;PAHAWH HMONG CONSONANT NKAU;Lo;0;L;;;;;N;;;;;\n16B23;PAHAWH HMONG CONSONANT QHAU;Lo;0;L;;;;;N;;;;;\n16B24;PAHAWH HMONG CONSONANT YAU;Lo;0;L;;;;;N;;;;;\n16B25;PAHAWH HMONG CONSONANT HLAU;Lo;0;L;;;;;N;;;;;\n16B26;PAHAWH HMONG CONSONANT MAU;Lo;0;L;;;;;N;;;;;\n16B27;PAHAWH HMONG CONSONANT CHAU;Lo;0;L;;;;;N;;;;;\n16B28;PAHAWH HMONG CONSONANT NCHAU;Lo;0;L;;;;;N;;;;;\n16B29;PAHAWH HMONG CONSONANT HNAU;Lo;0;L;;;;;N;;;;;\n16B2A;PAHAWH HMONG CONSONANT PLHAU;Lo;0;L;;;;;N;;;;;\n16B2B;PAHAWH HMONG CONSONANT NTHAU;Lo;0;L;;;;;N;;;;;\n16B2C;PAHAWH HMONG CONSONANT NAU;Lo;0;L;;;;;N;;;;;\n16B2D;PAHAWH HMONG CONSONANT AU;Lo;0;L;;;;;N;;;;;\n16B2E;PAHAWH HMONG CONSONANT XAU;Lo;0;L;;;;;N;;;;;\n16B2F;PAHAWH HMONG CONSONANT CAU;Lo;0;L;;;;;N;;;;;\n16B30;PAHAWH HMONG MARK CIM TUB;Mn;230;NSM;;;;;N;;;;;\n16B31;PAHAWH HMONG MARK CIM SO;Mn;230;NSM;;;;;N;;;;;\n16B32;PAHAWH HMONG MARK CIM KES;Mn;230;NSM;;;;;N;;;;;\n16B33;PAHAWH HMONG MARK CIM KHAV;Mn;230;NSM;;;;;N;;;;;\n16B34;PAHAWH HMONG MARK CIM SUAM;Mn;230;NSM;;;;;N;;;;;\n16B35;PAHAWH HMONG MARK CIM HOM;Mn;230;NSM;;;;;N;;;;;\n16B36;PAHAWH HMONG MARK CIM TAUM;Mn;230;NSM;;;;;N;;;;;\n16B37;PAHAWH HMONG SIGN VOS THOM;Po;0;L;;;;;N;;;;;\n16B38;PAHAWH HMONG SIGN VOS TSHAB CEEB;Po;0;L;;;;;N;;;;;\n16B39;PAHAWH HMONG SIGN CIM CHEEM;Po;0;L;;;;;N;;;;;\n16B3A;PAHAWH HMONG SIGN VOS THIAB;Po;0;L;;;;;N;;;;;\n16B3B;PAHAWH HMONG SIGN VOS FEEM;Po;0;L;;;;;N;;;;;\n16B3C;PAHAWH HMONG SIGN XYEEM NTXIV;So;0;L;;;;;N;;;;;\n16B3D;PAHAWH HMONG SIGN XYEEM RHO;So;0;L;;;;;N;;;;;\n16B3E;PAHAWH HMONG SIGN XYEEM TOV;So;0;L;;;;;N;;;;;\n16B3F;PAHAWH HMONG SIGN XYEEM FAIB;So;0;L;;;;;N;;;;;\n16B40;PAHAWH HMONG SIGN VOS SEEV;Lm;0;L;;;;;N;;;;;\n16B41;PAHAWH HMONG SIGN MEEJ SUAB;Lm;0;L;;;;;N;;;;;\n16B42;PAHAWH HMONG SIGN VOS NRUA;Lm;0;L;;;;;N;;;;;\n16B43;PAHAWH HMONG SIGN IB YAM;Lm;0;L;;;;;N;;;;;\n16B44;PAHAWH HMONG SIGN XAUS;Po;0;L;;;;;N;;;;;\n16B45;PAHAWH HMONG SIGN CIM TSOV ROG;So;0;L;;;;;N;;;;;\n16B50;PAHAWH HMONG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n16B51;PAHAWH HMONG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n16B52;PAHAWH HMONG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n16B53;PAHAWH HMONG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n16B54;PAHAWH HMONG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n16B55;PAHAWH HMONG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n16B56;PAHAWH HMONG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n16B57;PAHAWH HMONG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n16B58;PAHAWH HMONG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n16B59;PAHAWH HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n16B5B;PAHAWH HMONG NUMBER TENS;No;0;L;;;;10;N;;;;;\n16B5C;PAHAWH HMONG NUMBER HUNDREDS;No;0;L;;;;100;N;;;;;\n16B5D;PAHAWH HMONG NUMBER TEN THOUSANDS;No;0;L;;;;10000;N;;;;;\n16B5E;PAHAWH HMONG NUMBER MILLIONS;No;0;L;;;;1000000;N;;;;;\n16B5F;PAHAWH HMONG NUMBER HUNDRED MILLIONS;No;0;L;;;;100000000;N;;;;;\n16B60;PAHAWH HMONG NUMBER TEN BILLIONS;No;0;L;;;;10000000000;N;;;;;\n16B61;PAHAWH HMONG NUMBER TRILLIONS;No;0;L;;;;1000000000000;N;;;;;\n16B63;PAHAWH HMONG SIGN VOS LUB;Lo;0;L;;;;;N;;;;;\n16B64;PAHAWH HMONG SIGN XYOO;Lo;0;L;;;;;N;;;;;\n16B65;PAHAWH HMONG SIGN HLI;Lo;0;L;;;;;N;;;;;\n16B66;PAHAWH HMONG SIGN THIRD-STAGE HLI;Lo;0;L;;;;;N;;;;;\n16B67;PAHAWH HMONG SIGN ZWJ THAJ;Lo;0;L;;;;;N;;;;;\n16B68;PAHAWH HMONG SIGN HNUB;Lo;0;L;;;;;N;;;;;\n16B69;PAHAWH HMONG SIGN NQIG;Lo;0;L;;;;;N;;;;;\n16B6A;PAHAWH HMONG SIGN XIAB;Lo;0;L;;;;;N;;;;;\n16B6B;PAHAWH HMONG SIGN NTUJ;Lo;0;L;;;;;N;;;;;\n16B6C;PAHAWH HMONG SIGN AV;Lo;0;L;;;;;N;;;;;\n16B6D;PAHAWH HMONG SIGN TXHEEJ CEEV;Lo;0;L;;;;;N;;;;;\n16B6E;PAHAWH HMONG SIGN MEEJ TSEEB;Lo;0;L;;;;;N;;;;;\n16B6F;PAHAWH HMONG SIGN TAU;Lo;0;L;;;;;N;;;;;\n16B70;PAHAWH HMONG SIGN LOS;Lo;0;L;;;;;N;;;;;\n16B71;PAHAWH HMONG SIGN MUS;Lo;0;L;;;;;N;;;;;\n16B72;PAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOG;Lo;0;L;;;;;N;;;;;\n16B73;PAHAWH HMONG SIGN CIM CUAM TSHOOJ;Lo;0;L;;;;;N;;;;;\n16B74;PAHAWH HMONG SIGN CIM TXWV;Lo;0;L;;;;;N;;;;;\n16B75;PAHAWH HMONG SIGN CIM TXWV CHWV;Lo;0;L;;;;;N;;;;;\n16B76;PAHAWH HMONG SIGN CIM PUB DAWB;Lo;0;L;;;;;N;;;;;\n16B77;PAHAWH HMONG SIGN CIM NRES TOS;Lo;0;L;;;;;N;;;;;\n16B7D;PAHAWH HMONG CLAN SIGN TSHEEJ;Lo;0;L;;;;;N;;;;;\n16B7E;PAHAWH HMONG CLAN SIGN YEEG;Lo;0;L;;;;;N;;;;;\n16B7F;PAHAWH HMONG CLAN SIGN LIS;Lo;0;L;;;;;N;;;;;\n16B80;PAHAWH HMONG CLAN SIGN LAUJ;Lo;0;L;;;;;N;;;;;\n16B81;PAHAWH HMONG CLAN SIGN XYOOJ;Lo;0;L;;;;;N;;;;;\n16B82;PAHAWH HMONG CLAN SIGN KOO;Lo;0;L;;;;;N;;;;;\n16B83;PAHAWH HMONG CLAN SIGN HAWJ;Lo;0;L;;;;;N;;;;;\n16B84;PAHAWH HMONG CLAN SIGN MUAS;Lo;0;L;;;;;N;;;;;\n16B85;PAHAWH HMONG CLAN SIGN THOJ;Lo;0;L;;;;;N;;;;;\n16B86;PAHAWH HMONG CLAN SIGN TSAB;Lo;0;L;;;;;N;;;;;\n16B87;PAHAWH HMONG CLAN SIGN PHAB;Lo;0;L;;;;;N;;;;;\n16B88;PAHAWH HMONG CLAN SIGN KHAB;Lo;0;L;;;;;N;;;;;\n16B89;PAHAWH HMONG CLAN SIGN HAM;Lo;0;L;;;;;N;;;;;\n16B8A;PAHAWH HMONG CLAN SIGN VAJ;Lo;0;L;;;;;N;;;;;\n16B8B;PAHAWH HMONG CLAN SIGN FAJ;Lo;0;L;;;;;N;;;;;\n16B8C;PAHAWH HMONG CLAN SIGN YAJ;Lo;0;L;;;;;N;;;;;\n16B8D;PAHAWH HMONG CLAN SIGN TSWB;Lo;0;L;;;;;N;;;;;\n16B8E;PAHAWH HMONG CLAN SIGN KWM;Lo;0;L;;;;;N;;;;;\n16B8F;PAHAWH HMONG CLAN SIGN VWJ;Lo;0;L;;;;;N;;;;;\n16D40;KIRAT RAI SIGN ANUSVARA;Lm;0;L;;;;;N;;;;;\n16D41;KIRAT RAI SIGN TONPI;Lm;0;L;;;;;N;;;;;\n16D42;KIRAT RAI SIGN VISARGA;Lm;0;L;;;;;N;;;;;\n16D43;KIRAT RAI LETTER A;Lo;0;L;;;;;N;;;;;\n16D44;KIRAT RAI LETTER KA;Lo;0;L;;;;;N;;;;;\n16D45;KIRAT RAI LETTER KHA;Lo;0;L;;;;;N;;;;;\n16D46;KIRAT RAI LETTER GA;Lo;0;L;;;;;N;;;;;\n16D47;KIRAT RAI LETTER GHA;Lo;0;L;;;;;N;;;;;\n16D48;KIRAT RAI LETTER NGA;Lo;0;L;;;;;N;;;;;\n16D49;KIRAT RAI LETTER CA;Lo;0;L;;;;;N;;;;;\n16D4A;KIRAT RAI LETTER CHA;Lo;0;L;;;;;N;;;;;\n16D4B;KIRAT RAI LETTER JA;Lo;0;L;;;;;N;;;;;\n16D4C;KIRAT RAI LETTER JHA;Lo;0;L;;;;;N;;;;;\n16D4D;KIRAT RAI LETTER NYA;Lo;0;L;;;;;N;;;;;\n16D4E;KIRAT RAI LETTER TTA;Lo;0;L;;;;;N;;;;;\n16D4F;KIRAT RAI LETTER TTHA;Lo;0;L;;;;;N;;;;;\n16D50;KIRAT RAI LETTER DDA;Lo;0;L;;;;;N;;;;;\n16D51;KIRAT RAI LETTER DDHA;Lo;0;L;;;;;N;;;;;\n16D52;KIRAT RAI LETTER TA;Lo;0;L;;;;;N;;;;;\n16D53;KIRAT RAI LETTER THA;Lo;0;L;;;;;N;;;;;\n16D54;KIRAT RAI LETTER DA;Lo;0;L;;;;;N;;;;;\n16D55;KIRAT RAI LETTER DHA;Lo;0;L;;;;;N;;;;;\n16D56;KIRAT RAI LETTER NA;Lo;0;L;;;;;N;;;;;\n16D57;KIRAT RAI LETTER PA;Lo;0;L;;;;;N;;;;;\n16D58;KIRAT RAI LETTER PHA;Lo;0;L;;;;;N;;;;;\n16D59;KIRAT RAI LETTER BA;Lo;0;L;;;;;N;;;;;\n16D5A;KIRAT RAI LETTER BHA;Lo;0;L;;;;;N;;;;;\n16D5B;KIRAT RAI LETTER MA;Lo;0;L;;;;;N;;;;;\n16D5C;KIRAT RAI LETTER YA;Lo;0;L;;;;;N;;;;;\n16D5D;KIRAT RAI LETTER RA;Lo;0;L;;;;;N;;;;;\n16D5E;KIRAT RAI LETTER LA;Lo;0;L;;;;;N;;;;;\n16D5F;KIRAT RAI LETTER VA;Lo;0;L;;;;;N;;;;;\n16D60;KIRAT RAI LETTER SA;Lo;0;L;;;;;N;;;;;\n16D61;KIRAT RAI LETTER SHA;Lo;0;L;;;;;N;;;;;\n16D62;KIRAT RAI LETTER HA;Lo;0;L;;;;;N;;;;;\n16D63;KIRAT RAI VOWEL SIGN AA;Lo;0;L;;;;;N;;;;;\n16D64;KIRAT RAI VOWEL SIGN I;Lo;0;L;;;;;N;;;;;\n16D65;KIRAT RAI VOWEL SIGN U;Lo;0;L;;;;;N;;;;;\n16D66;KIRAT RAI VOWEL SIGN UE;Lo;0;L;;;;;N;;;;;\n16D67;KIRAT RAI VOWEL SIGN E;Lo;0;L;;;;;N;;;;;\n16D68;KIRAT RAI VOWEL SIGN AI;Lo;0;L;16D67 16D67;;;;N;;;;;\n16D69;KIRAT RAI VOWEL SIGN O;Lo;0;L;16D63 16D67;;;;N;;;;;\n16D6A;KIRAT RAI VOWEL SIGN AU;Lo;0;L;16D69 16D67;;;;N;;;;;\n16D6B;KIRAT RAI SIGN VIRAMA;Lm;0;L;;;;;N;;;;;\n16D6C;KIRAT RAI SIGN SAAT;Lm;0;L;;;;;N;;;;;\n16D6D;KIRAT RAI SIGN YUPI;Po;0;L;;;;;N;;;;;\n16D6E;KIRAT RAI DANDA;Po;0;L;;;;;N;;;;;\n16D6F;KIRAT RAI DOUBLE DANDA;Po;0;L;;;;;N;;;;;\n16D70;KIRAT RAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n16D71;KIRAT RAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n16D72;KIRAT RAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n16D73;KIRAT RAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n16D74;KIRAT RAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n16D75;KIRAT RAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n16D76;KIRAT RAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n16D77;KIRAT RAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n16D78;KIRAT RAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n16D79;KIRAT RAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n16E40;MEDEFAIDRIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;16E60;\n16E41;MEDEFAIDRIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;16E61;\n16E42;MEDEFAIDRIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;16E62;\n16E43;MEDEFAIDRIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;16E63;\n16E44;MEDEFAIDRIN CAPITAL LETTER ATIU;Lu;0;L;;;;;N;;;;16E64;\n16E45;MEDEFAIDRIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;16E65;\n16E46;MEDEFAIDRIN CAPITAL LETTER KP;Lu;0;L;;;;;N;;;;16E66;\n16E47;MEDEFAIDRIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;16E67;\n16E48;MEDEFAIDRIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;16E68;\n16E49;MEDEFAIDRIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;16E69;\n16E4A;MEDEFAIDRIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;16E6A;\n16E4B;MEDEFAIDRIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16E6B;\n16E4C;MEDEFAIDRIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;16E6C;\n16E4D;MEDEFAIDRIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;16E6D;\n16E4E;MEDEFAIDRIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;16E6E;\n16E4F;MEDEFAIDRIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;16E6F;\n16E50;MEDEFAIDRIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;16E70;\n16E51;MEDEFAIDRIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;16E71;\n16E52;MEDEFAIDRIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;16E72;\n16E53;MEDEFAIDRIN CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;16E73;\n16E54;MEDEFAIDRIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;16E74;\n16E55;MEDEFAIDRIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;16E75;\n16E56;MEDEFAIDRIN CAPITAL LETTER HP;Lu;0;L;;;;;N;;;;16E76;\n16E57;MEDEFAIDRIN CAPITAL LETTER NY;Lu;0;L;;;;;N;;;;16E77;\n16E58;MEDEFAIDRIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;16E78;\n16E59;MEDEFAIDRIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;16E79;\n16E5A;MEDEFAIDRIN CAPITAL LETTER OE;Lu;0;L;;;;;N;;;;16E7A;\n16E5B;MEDEFAIDRIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;16E7B;\n16E5C;MEDEFAIDRIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;16E7C;\n16E5D;MEDEFAIDRIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;16E7D;\n16E5E;MEDEFAIDRIN CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;16E7E;\n16E5F;MEDEFAIDRIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;16E7F;\n16E60;MEDEFAIDRIN SMALL LETTER M;Ll;0;L;;;;;N;;;16E40;;16E40\n16E61;MEDEFAIDRIN SMALL LETTER S;Ll;0;L;;;;;N;;;16E41;;16E41\n16E62;MEDEFAIDRIN SMALL LETTER V;Ll;0;L;;;;;N;;;16E42;;16E42\n16E63;MEDEFAIDRIN SMALL LETTER W;Ll;0;L;;;;;N;;;16E43;;16E43\n16E64;MEDEFAIDRIN SMALL LETTER ATIU;Ll;0;L;;;;;N;;;16E44;;16E44\n16E65;MEDEFAIDRIN SMALL LETTER Z;Ll;0;L;;;;;N;;;16E45;;16E45\n16E66;MEDEFAIDRIN SMALL LETTER KP;Ll;0;L;;;;;N;;;16E46;;16E46\n16E67;MEDEFAIDRIN SMALL LETTER P;Ll;0;L;;;;;N;;;16E47;;16E47\n16E68;MEDEFAIDRIN SMALL LETTER T;Ll;0;L;;;;;N;;;16E48;;16E48\n16E69;MEDEFAIDRIN SMALL LETTER G;Ll;0;L;;;;;N;;;16E49;;16E49\n16E6A;MEDEFAIDRIN SMALL LETTER F;Ll;0;L;;;;;N;;;16E4A;;16E4A\n16E6B;MEDEFAIDRIN SMALL LETTER I;Ll;0;L;;;;;N;;;16E4B;;16E4B\n16E6C;MEDEFAIDRIN SMALL LETTER K;Ll;0;L;;;;;N;;;16E4C;;16E4C\n16E6D;MEDEFAIDRIN SMALL LETTER A;Ll;0;L;;;;;N;;;16E4D;;16E4D\n16E6E;MEDEFAIDRIN SMALL LETTER J;Ll;0;L;;;;;N;;;16E4E;;16E4E\n16E6F;MEDEFAIDRIN SMALL LETTER E;Ll;0;L;;;;;N;;;16E4F;;16E4F\n16E70;MEDEFAIDRIN SMALL LETTER B;Ll;0;L;;;;;N;;;16E50;;16E50\n16E71;MEDEFAIDRIN SMALL LETTER C;Ll;0;L;;;;;N;;;16E51;;16E51\n16E72;MEDEFAIDRIN SMALL LETTER U;Ll;0;L;;;;;N;;;16E52;;16E52\n16E73;MEDEFAIDRIN SMALL LETTER YU;Ll;0;L;;;;;N;;;16E53;;16E53\n16E74;MEDEFAIDRIN SMALL LETTER L;Ll;0;L;;;;;N;;;16E54;;16E54\n16E75;MEDEFAIDRIN SMALL LETTER Q;Ll;0;L;;;;;N;;;16E55;;16E55\n16E76;MEDEFAIDRIN SMALL LETTER HP;Ll;0;L;;;;;N;;;16E56;;16E56\n16E77;MEDEFAIDRIN SMALL LETTER NY;Ll;0;L;;;;;N;;;16E57;;16E57\n16E78;MEDEFAIDRIN SMALL LETTER X;Ll;0;L;;;;;N;;;16E58;;16E58\n16E79;MEDEFAIDRIN SMALL LETTER D;Ll;0;L;;;;;N;;;16E59;;16E59\n16E7A;MEDEFAIDRIN SMALL LETTER OE;Ll;0;L;;;;;N;;;16E5A;;16E5A\n16E7B;MEDEFAIDRIN SMALL LETTER N;Ll;0;L;;;;;N;;;16E5B;;16E5B\n16E7C;MEDEFAIDRIN SMALL LETTER R;Ll;0;L;;;;;N;;;16E5C;;16E5C\n16E7D;MEDEFAIDRIN SMALL LETTER O;Ll;0;L;;;;;N;;;16E5D;;16E5D\n16E7E;MEDEFAIDRIN SMALL LETTER AI;Ll;0;L;;;;;N;;;16E5E;;16E5E\n16E7F;MEDEFAIDRIN SMALL LETTER Y;Ll;0;L;;;;;N;;;16E5F;;16E5F\n16E80;MEDEFAIDRIN DIGIT ZERO;No;0;L;;;;0;N;;;;;\n16E81;MEDEFAIDRIN DIGIT ONE;No;0;L;;;;1;N;;;;;\n16E82;MEDEFAIDRIN DIGIT TWO;No;0;L;;;;2;N;;;;;\n16E83;MEDEFAIDRIN DIGIT THREE;No;0;L;;;;3;N;;;;;\n16E84;MEDEFAIDRIN DIGIT FOUR;No;0;L;;;;4;N;;;;;\n16E85;MEDEFAIDRIN DIGIT FIVE;No;0;L;;;;5;N;;;;;\n16E86;MEDEFAIDRIN DIGIT SIX;No;0;L;;;;6;N;;;;;\n16E87;MEDEFAIDRIN DIGIT SEVEN;No;0;L;;;;7;N;;;;;\n16E88;MEDEFAIDRIN DIGIT EIGHT;No;0;L;;;;8;N;;;;;\n16E89;MEDEFAIDRIN DIGIT NINE;No;0;L;;;;9;N;;;;;\n16E8A;MEDEFAIDRIN NUMBER TEN;No;0;L;;;;10;N;;;;;\n16E8B;MEDEFAIDRIN NUMBER ELEVEN;No;0;L;;;;11;N;;;;;\n16E8C;MEDEFAIDRIN NUMBER TWELVE;No;0;L;;;;12;N;;;;;\n16E8D;MEDEFAIDRIN NUMBER THIRTEEN;No;0;L;;;;13;N;;;;;\n16E8E;MEDEFAIDRIN NUMBER FOURTEEN;No;0;L;;;;14;N;;;;;\n16E8F;MEDEFAIDRIN NUMBER FIFTEEN;No;0;L;;;;15;N;;;;;\n16E90;MEDEFAIDRIN NUMBER SIXTEEN;No;0;L;;;;16;N;;;;;\n16E91;MEDEFAIDRIN NUMBER SEVENTEEN;No;0;L;;;;17;N;;;;;\n16E92;MEDEFAIDRIN NUMBER EIGHTEEN;No;0;L;;;;18;N;;;;;\n16E93;MEDEFAIDRIN NUMBER NINETEEN;No;0;L;;;;19;N;;;;;\n16E94;MEDEFAIDRIN DIGIT ONE ALTERNATE FORM;No;0;L;;;;1;N;;;;;\n16E95;MEDEFAIDRIN DIGIT TWO ALTERNATE FORM;No;0;L;;;;2;N;;;;;\n16E96;MEDEFAIDRIN DIGIT THREE ALTERNATE FORM;No;0;L;;;;3;N;;;;;\n16E97;MEDEFAIDRIN COMMA;Po;0;L;;;;;N;;;;;\n16E98;MEDEFAIDRIN FULL STOP;Po;0;L;;;;;N;;;;;\n16E99;MEDEFAIDRIN SYMBOL AIVA;Po;0;L;;;;;N;;;;;\n16E9A;MEDEFAIDRIN EXCLAMATION OH;Po;0;L;;;;;N;;;;;\n16EA0;BERIA ERFE CAPITAL LETTER ARKAB;Lu;0;L;;;;;N;;;;16EBB;\n16EA1;BERIA ERFE CAPITAL LETTER BASIGNA;Lu;0;L;;;;;N;;;;16EBC;\n16EA2;BERIA ERFE CAPITAL LETTER DARBAI;Lu;0;L;;;;;N;;;;16EBD;\n16EA3;BERIA ERFE CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;16EBE;\n16EA4;BERIA ERFE CAPITAL LETTER FITKO;Lu;0;L;;;;;N;;;;16EBF;\n16EA5;BERIA ERFE CAPITAL LETTER GOWAY;Lu;0;L;;;;;N;;;;16EC0;\n16EA6;BERIA ERFE CAPITAL LETTER HIRDEABO;Lu;0;L;;;;;N;;;;16EC1;\n16EA7;BERIA ERFE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16EC2;\n16EA8;BERIA ERFE CAPITAL LETTER DJAI;Lu;0;L;;;;;N;;;;16EC3;\n16EA9;BERIA ERFE CAPITAL LETTER KOBO;Lu;0;L;;;;;N;;;;16EC4;\n16EAA;BERIA ERFE CAPITAL LETTER LAKKO;Lu;0;L;;;;;N;;;;16EC5;\n16EAB;BERIA ERFE CAPITAL LETTER MERI;Lu;0;L;;;;;N;;;;16EC6;\n16EAC;BERIA ERFE CAPITAL LETTER NINI;Lu;0;L;;;;;N;;;;16EC7;\n16EAD;BERIA ERFE CAPITAL LETTER GNA;Lu;0;L;;;;;N;;;;16EC8;\n16EAE;BERIA ERFE CAPITAL LETTER NGAY;Lu;0;L;;;;;N;;;;16EC9;\n16EAF;BERIA ERFE CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;16ECA;\n16EB0;BERIA ERFE CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;16ECB;\n16EB1;BERIA ERFE CAPITAL LETTER ERIGO;Lu;0;L;;;;;N;;;;16ECC;\n16EB2;BERIA ERFE CAPITAL LETTER ERIGO TAMURA;Lu;0;L;;;;;N;;;;16ECD;\n16EB3;BERIA ERFE CAPITAL LETTER SERI;Lu;0;L;;;;;N;;;;16ECE;\n16EB4;BERIA ERFE CAPITAL LETTER SHEP;Lu;0;L;;;;;N;;;;16ECF;\n16EB5;BERIA ERFE CAPITAL LETTER TATASOUE;Lu;0;L;;;;;N;;;;16ED0;\n16EB6;BERIA ERFE CAPITAL LETTER UI;Lu;0;L;;;;;N;;;;16ED1;\n16EB7;BERIA ERFE CAPITAL LETTER WASSE;Lu;0;L;;;;;N;;;;16ED2;\n16EB8;BERIA ERFE CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;16ED3;\n16EBB;BERIA ERFE SMALL LETTER ARKAB;Ll;0;L;;;;;N;;;16EA0;;16EA0\n16EBC;BERIA ERFE SMALL LETTER BASIGNA;Ll;0;L;;;;;N;;;16EA1;;16EA1\n16EBD;BERIA ERFE SMALL LETTER DARBAI;Ll;0;L;;;;;N;;;16EA2;;16EA2\n16EBE;BERIA ERFE SMALL LETTER EH;Ll;0;L;;;;;N;;;16EA3;;16EA3\n16EBF;BERIA ERFE SMALL LETTER FITKO;Ll;0;L;;;;;N;;;16EA4;;16EA4\n16EC0;BERIA ERFE SMALL LETTER GOWAY;Ll;0;L;;;;;N;;;16EA5;;16EA5\n16EC1;BERIA ERFE SMALL LETTER HIRDEABO;Ll;0;L;;;;;N;;;16EA6;;16EA6\n16EC2;BERIA ERFE SMALL LETTER I;Ll;0;L;;;;;N;;;16EA7;;16EA7\n16EC3;BERIA ERFE SMALL LETTER DJAI;Ll;0;L;;;;;N;;;16EA8;;16EA8\n16EC4;BERIA ERFE SMALL LETTER KOBO;Ll;0;L;;;;;N;;;16EA9;;16EA9\n16EC5;BERIA ERFE SMALL LETTER LAKKO;Ll;0;L;;;;;N;;;16EAA;;16EAA\n16EC6;BERIA ERFE SMALL LETTER MERI;Ll;0;L;;;;;N;;;16EAB;;16EAB\n16EC7;BERIA ERFE SMALL LETTER NINI;Ll;0;L;;;;;N;;;16EAC;;16EAC\n16EC8;BERIA ERFE SMALL LETTER GNA;Ll;0;L;;;;;N;;;16EAD;;16EAD\n16EC9;BERIA ERFE SMALL LETTER NGAY;Ll;0;L;;;;;N;;;16EAE;;16EAE\n16ECA;BERIA ERFE SMALL LETTER OI;Ll;0;L;;;;;N;;;16EAF;;16EAF\n16ECB;BERIA ERFE SMALL LETTER PI;Ll;0;L;;;;;N;;;16EB0;;16EB0\n16ECC;BERIA ERFE SMALL LETTER ERIGO;Ll;0;L;;;;;N;;;16EB1;;16EB1\n16ECD;BERIA ERFE SMALL LETTER ERIGO TAMURA;Ll;0;L;;;;;N;;;16EB2;;16EB2\n16ECE;BERIA ERFE SMALL LETTER SERI;Ll;0;L;;;;;N;;;16EB3;;16EB3\n16ECF;BERIA ERFE SMALL LETTER SHEP;Ll;0;L;;;;;N;;;16EB4;;16EB4\n16ED0;BERIA ERFE SMALL LETTER TATASOUE;Ll;0;L;;;;;N;;;16EB5;;16EB5\n16ED1;BERIA ERFE SMALL LETTER UI;Ll;0;L;;;;;N;;;16EB6;;16EB6\n16ED2;BERIA ERFE SMALL LETTER WASSE;Ll;0;L;;;;;N;;;16EB7;;16EB7\n16ED3;BERIA ERFE SMALL LETTER AY;Ll;0;L;;;;;N;;;16EB8;;16EB8\n16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;;\n16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;;\n16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;;\n16F03;MIAO LETTER PLA;Lo;0;L;;;;;N;;;;;\n16F04;MIAO LETTER MA;Lo;0;L;;;;;N;;;;;\n16F05;MIAO LETTER MHA;Lo;0;L;;;;;N;;;;;\n16F06;MIAO LETTER ARCHAIC MA;Lo;0;L;;;;;N;;;;;\n16F07;MIAO LETTER FA;Lo;0;L;;;;;N;;;;;\n16F08;MIAO LETTER VA;Lo;0;L;;;;;N;;;;;\n16F09;MIAO LETTER VFA;Lo;0;L;;;;;N;;;;;\n16F0A;MIAO LETTER TA;Lo;0;L;;;;;N;;;;;\n16F0B;MIAO LETTER DA;Lo;0;L;;;;;N;;;;;\n16F0C;MIAO LETTER YI TTA;Lo;0;L;;;;;N;;;;;\n16F0D;MIAO LETTER YI TA;Lo;0;L;;;;;N;;;;;\n16F0E;MIAO LETTER TTA;Lo;0;L;;;;;N;;;;;\n16F0F;MIAO LETTER DDA;Lo;0;L;;;;;N;;;;;\n16F10;MIAO LETTER NA;Lo;0;L;;;;;N;;;;;\n16F11;MIAO LETTER NHA;Lo;0;L;;;;;N;;;;;\n16F12;MIAO LETTER YI NNA;Lo;0;L;;;;;N;;;;;\n16F13;MIAO LETTER ARCHAIC NA;Lo;0;L;;;;;N;;;;;\n16F14;MIAO LETTER NNA;Lo;0;L;;;;;N;;;;;\n16F15;MIAO LETTER NNHA;Lo;0;L;;;;;N;;;;;\n16F16;MIAO LETTER LA;Lo;0;L;;;;;N;;;;;\n16F17;MIAO LETTER LYA;Lo;0;L;;;;;N;;;;;\n16F18;MIAO LETTER LHA;Lo;0;L;;;;;N;;;;;\n16F19;MIAO LETTER LHYA;Lo;0;L;;;;;N;;;;;\n16F1A;MIAO LETTER TLHA;Lo;0;L;;;;;N;;;;;\n16F1B;MIAO LETTER DLHA;Lo;0;L;;;;;N;;;;;\n16F1C;MIAO LETTER TLHYA;Lo;0;L;;;;;N;;;;;\n16F1D;MIAO LETTER DLHYA;Lo;0;L;;;;;N;;;;;\n16F1E;MIAO LETTER KA;Lo;0;L;;;;;N;;;;;\n16F1F;MIAO LETTER GA;Lo;0;L;;;;;N;;;;;\n16F20;MIAO LETTER YI KA;Lo;0;L;;;;;N;;;;;\n16F21;MIAO LETTER QA;Lo;0;L;;;;;N;;;;;\n16F22;MIAO LETTER QGA;Lo;0;L;;;;;N;;;;;\n16F23;MIAO LETTER NGA;Lo;0;L;;;;;N;;;;;\n16F24;MIAO LETTER NGHA;Lo;0;L;;;;;N;;;;;\n16F25;MIAO LETTER ARCHAIC NGA;Lo;0;L;;;;;N;;;;;\n16F26;MIAO LETTER HA;Lo;0;L;;;;;N;;;;;\n16F27;MIAO LETTER XA;Lo;0;L;;;;;N;;;;;\n16F28;MIAO LETTER GHA;Lo;0;L;;;;;N;;;;;\n16F29;MIAO LETTER GHHA;Lo;0;L;;;;;N;;;;;\n16F2A;MIAO LETTER TSSA;Lo;0;L;;;;;N;;;;;\n16F2B;MIAO LETTER DZZA;Lo;0;L;;;;;N;;;;;\n16F2C;MIAO LETTER NYA;Lo;0;L;;;;;N;;;;;\n16F2D;MIAO LETTER NYHA;Lo;0;L;;;;;N;;;;;\n16F2E;MIAO LETTER TSHA;Lo;0;L;;;;;N;;;;;\n16F2F;MIAO LETTER DZHA;Lo;0;L;;;;;N;;;;;\n16F30;MIAO LETTER YI TSHA;Lo;0;L;;;;;N;;;;;\n16F31;MIAO LETTER YI DZHA;Lo;0;L;;;;;N;;;;;\n16F32;MIAO LETTER REFORMED TSHA;Lo;0;L;;;;;N;;;;;\n16F33;MIAO LETTER SHA;Lo;0;L;;;;;N;;;;;\n16F34;MIAO LETTER SSA;Lo;0;L;;;;;N;;;;;\n16F35;MIAO LETTER ZHA;Lo;0;L;;;;;N;;;;;\n16F36;MIAO LETTER ZSHA;Lo;0;L;;;;;N;;;;;\n16F37;MIAO LETTER TSA;Lo;0;L;;;;;N;;;;;\n16F38;MIAO LETTER DZA;Lo;0;L;;;;;N;;;;;\n16F39;MIAO LETTER YI TSA;Lo;0;L;;;;;N;;;;;\n16F3A;MIAO LETTER SA;Lo;0;L;;;;;N;;;;;\n16F3B;MIAO LETTER ZA;Lo;0;L;;;;;N;;;;;\n16F3C;MIAO LETTER ZSA;Lo;0;L;;;;;N;;;;;\n16F3D;MIAO LETTER ZZA;Lo;0;L;;;;;N;;;;;\n16F3E;MIAO LETTER ZZSA;Lo;0;L;;;;;N;;;;;\n16F3F;MIAO LETTER ARCHAIC ZZA;Lo;0;L;;;;;N;;;;;\n16F40;MIAO LETTER ZZYA;Lo;0;L;;;;;N;;;;;\n16F41;MIAO LETTER ZZSYA;Lo;0;L;;;;;N;;;;;\n16F42;MIAO LETTER WA;Lo;0;L;;;;;N;;;;;\n16F43;MIAO LETTER AH;Lo;0;L;;;;;N;;;;;\n16F44;MIAO LETTER HHA;Lo;0;L;;;;;N;;;;;\n16F45;MIAO LETTER BRI;Lo;0;L;;;;;N;;;;;\n16F46;MIAO LETTER SYI;Lo;0;L;;;;;N;;;;;\n16F47;MIAO LETTER DZYI;Lo;0;L;;;;;N;;;;;\n16F48;MIAO LETTER TE;Lo;0;L;;;;;N;;;;;\n16F49;MIAO LETTER TSE;Lo;0;L;;;;;N;;;;;\n16F4A;MIAO LETTER RTE;Lo;0;L;;;;;N;;;;;\n16F4F;MIAO SIGN CONSONANT MODIFIER BAR;Mn;0;NSM;;;;;N;;;;;\n16F50;MIAO LETTER NASALIZATION;Lo;0;L;;;;;N;;;;;\n16F51;MIAO SIGN ASPIRATION;Mc;0;L;;;;;N;;;;;\n16F52;MIAO SIGN REFORMED VOICING;Mc;0;L;;;;;N;;;;;\n16F53;MIAO SIGN REFORMED ASPIRATION;Mc;0;L;;;;;N;;;;;\n16F54;MIAO VOWEL SIGN A;Mc;0;L;;;;;N;;;;;\n16F55;MIAO VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;\n16F56;MIAO VOWEL SIGN AHH;Mc;0;L;;;;;N;;;;;\n16F57;MIAO VOWEL SIGN AN;Mc;0;L;;;;;N;;;;;\n16F58;MIAO VOWEL SIGN ANG;Mc;0;L;;;;;N;;;;;\n16F59;MIAO VOWEL SIGN O;Mc;0;L;;;;;N;;;;;\n16F5A;MIAO VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;\n16F5B;MIAO VOWEL SIGN WO;Mc;0;L;;;;;N;;;;;\n16F5C;MIAO VOWEL SIGN W;Mc;0;L;;;;;N;;;;;\n16F5D;MIAO VOWEL SIGN E;Mc;0;L;;;;;N;;;;;\n16F5E;MIAO VOWEL SIGN EN;Mc;0;L;;;;;N;;;;;\n16F5F;MIAO VOWEL SIGN ENG;Mc;0;L;;;;;N;;;;;\n16F60;MIAO VOWEL SIGN OEY;Mc;0;L;;;;;N;;;;;\n16F61;MIAO VOWEL SIGN I;Mc;0;L;;;;;N;;;;;\n16F62;MIAO VOWEL SIGN IA;Mc;0;L;;;;;N;;;;;\n16F63;MIAO VOWEL SIGN IAN;Mc;0;L;;;;;N;;;;;\n16F64;MIAO VOWEL SIGN IANG;Mc;0;L;;;;;N;;;;;\n16F65;MIAO VOWEL SIGN IO;Mc;0;L;;;;;N;;;;;\n16F66;MIAO VOWEL SIGN IE;Mc;0;L;;;;;N;;;;;\n16F67;MIAO VOWEL SIGN II;Mc;0;L;;;;;N;;;;;\n16F68;MIAO VOWEL SIGN IU;Mc;0;L;;;;;N;;;;;\n16F69;MIAO VOWEL SIGN ING;Mc;0;L;;;;;N;;;;;\n16F6A;MIAO VOWEL SIGN U;Mc;0;L;;;;;N;;;;;\n16F6B;MIAO VOWEL SIGN UA;Mc;0;L;;;;;N;;;;;\n16F6C;MIAO VOWEL SIGN UAN;Mc;0;L;;;;;N;;;;;\n16F6D;MIAO VOWEL SIGN UANG;Mc;0;L;;;;;N;;;;;\n16F6E;MIAO VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;\n16F6F;MIAO VOWEL SIGN UEI;Mc;0;L;;;;;N;;;;;\n16F70;MIAO VOWEL SIGN UNG;Mc;0;L;;;;;N;;;;;\n16F71;MIAO VOWEL SIGN Y;Mc;0;L;;;;;N;;;;;\n16F72;MIAO VOWEL SIGN YI;Mc;0;L;;;;;N;;;;;\n16F73;MIAO VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;\n16F74;MIAO VOWEL SIGN AEE;Mc;0;L;;;;;N;;;;;\n16F75;MIAO VOWEL SIGN ERR;Mc;0;L;;;;;N;;;;;\n16F76;MIAO VOWEL SIGN ROUNDED ERR;Mc;0;L;;;;;N;;;;;\n16F77;MIAO VOWEL SIGN ER;Mc;0;L;;;;;N;;;;;\n16F78;MIAO VOWEL SIGN ROUNDED ER;Mc;0;L;;;;;N;;;;;\n16F79;MIAO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;\n16F7A;MIAO VOWEL SIGN EI;Mc;0;L;;;;;N;;;;;\n16F7B;MIAO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;\n16F7C;MIAO VOWEL SIGN OU;Mc;0;L;;;;;N;;;;;\n16F7D;MIAO VOWEL SIGN N;Mc;0;L;;;;;N;;;;;\n16F7E;MIAO VOWEL SIGN NG;Mc;0;L;;;;;N;;;;;\n16F7F;MIAO VOWEL SIGN UOG;Mc;0;L;;;;;N;;;;;\n16F80;MIAO VOWEL SIGN YUI;Mc;0;L;;;;;N;;;;;\n16F81;MIAO VOWEL SIGN OG;Mc;0;L;;;;;N;;;;;\n16F82;MIAO VOWEL SIGN OER;Mc;0;L;;;;;N;;;;;\n16F83;MIAO VOWEL SIGN VW;Mc;0;L;;;;;N;;;;;\n16F84;MIAO VOWEL SIGN IG;Mc;0;L;;;;;N;;;;;\n16F85;MIAO VOWEL SIGN EA;Mc;0;L;;;;;N;;;;;\n16F86;MIAO VOWEL SIGN IONG;Mc;0;L;;;;;N;;;;;\n16F87;MIAO VOWEL SIGN UI;Mc;0;L;;;;;N;;;;;\n16F8F;MIAO TONE RIGHT;Mn;0;NSM;;;;;N;;;;;\n16F90;MIAO TONE TOP RIGHT;Mn;0;NSM;;;;;N;;;;;\n16F91;MIAO TONE ABOVE;Mn;0;NSM;;;;;N;;;;;\n16F92;MIAO TONE BELOW;Mn;0;NSM;;;;;N;;;;;\n16F93;MIAO LETTER TONE-2;Lm;0;L;;;;;N;;;;;\n16F94;MIAO LETTER TONE-3;Lm;0;L;;;;;N;;;;;\n16F95;MIAO LETTER TONE-4;Lm;0;L;;;;;N;;;;;\n16F96;MIAO LETTER TONE-5;Lm;0;L;;;;;N;;;;;\n16F97;MIAO LETTER TONE-6;Lm;0;L;;;;;N;;;;;\n16F98;MIAO LETTER TONE-7;Lm;0;L;;;;;N;;;;;\n16F99;MIAO LETTER TONE-8;Lm;0;L;;;;;N;;;;;\n16F9A;MIAO LETTER REFORMED TONE-1;Lm;0;L;;;;;N;;;;;\n16F9B;MIAO LETTER REFORMED TONE-2;Lm;0;L;;;;;N;;;;;\n16F9C;MIAO LETTER REFORMED TONE-4;Lm;0;L;;;;;N;;;;;\n16F9D;MIAO LETTER REFORMED TONE-5;Lm;0;L;;;;;N;;;;;\n16F9E;MIAO LETTER REFORMED TONE-6;Lm;0;L;;;;;N;;;;;\n16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;;\n16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;;\n16FE1;NUSHU ITERATION MARK;Lm;0;L;;;;;N;;;;;\n16FE2;OLD CHINESE HOOK MARK;Po;0;ON;;;;;N;;;;;\n16FE3;OLD CHINESE ITERATION MARK;Lm;0;L;;;;;N;;;;;\n16FE4;KHITAN SMALL SCRIPT FILLER;Mn;0;NSM;;;;;N;;;;;\n16FF0;VIETNAMESE ALTERNATE READING MARK CA;Mc;6;L;;;;;N;;;;;\n16FF1;VIETNAMESE ALTERNATE READING MARK NHAY;Mc;6;L;;;;;N;;;;;\n16FF2;CHINESE SMALL SIMPLIFIED ER;Lm;0;L;;;;;N;;;;;\n16FF3;CHINESE SMALL TRADITIONAL ER;Lm;0;L;;;;;N;;;;;\n16FF4;YANGQIN SIGN SLOW ONE BEAT;Nl;0;L;;;;1;N;;;;;\n16FF5;YANGQIN SIGN SLOW THREE HALF BEATS;Nl;0;L;;;;3/2;N;;;;;\n16FF6;YANGQIN SIGN SLOW TWO BEATS;Nl;0;L;;;;2;N;;;;;\n17000;<Tangut Ideograph, First>;Lo;0;L;;;;;N;;;;;\n187FF;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;;\n18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;;\n18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;;\n18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;;\n18803;TANGUT COMPONENT-004;Lo;0;L;;;;;N;;;;;\n18804;TANGUT COMPONENT-005;Lo;0;L;;;;;N;;;;;\n18805;TANGUT COMPONENT-006;Lo;0;L;;;;;N;;;;;\n18806;TANGUT COMPONENT-007;Lo;0;L;;;;;N;;;;;\n18807;TANGUT COMPONENT-008;Lo;0;L;;;;;N;;;;;\n18808;TANGUT COMPONENT-009;Lo;0;L;;;;;N;;;;;\n18809;TANGUT COMPONENT-010;Lo;0;L;;;;;N;;;;;\n1880A;TANGUT COMPONENT-011;Lo;0;L;;;;;N;;;;;\n1880B;TANGUT COMPONENT-012;Lo;0;L;;;;;N;;;;;\n1880C;TANGUT COMPONENT-013;Lo;0;L;;;;;N;;;;;\n1880D;TANGUT COMPONENT-014;Lo;0;L;;;;;N;;;;;\n1880E;TANGUT COMPONENT-015;Lo;0;L;;;;;N;;;;;\n1880F;TANGUT COMPONENT-016;Lo;0;L;;;;;N;;;;;\n18810;TANGUT COMPONENT-017;Lo;0;L;;;;;N;;;;;\n18811;TANGUT COMPONENT-018;Lo;0;L;;;;;N;;;;;\n18812;TANGUT COMPONENT-019;Lo;0;L;;;;;N;;;;;\n18813;TANGUT COMPONENT-020;Lo;0;L;;;;;N;;;;;\n18814;TANGUT COMPONENT-021;Lo;0;L;;;;;N;;;;;\n18815;TANGUT COMPONENT-022;Lo;0;L;;;;;N;;;;;\n18816;TANGUT COMPONENT-023;Lo;0;L;;;;;N;;;;;\n18817;TANGUT COMPONENT-024;Lo;0;L;;;;;N;;;;;\n18818;TANGUT COMPONENT-025;Lo;0;L;;;;;N;;;;;\n18819;TANGUT COMPONENT-026;Lo;0;L;;;;;N;;;;;\n1881A;TANGUT COMPONENT-027;Lo;0;L;;;;;N;;;;;\n1881B;TANGUT COMPONENT-028;Lo;0;L;;;;;N;;;;;\n1881C;TANGUT COMPONENT-029;Lo;0;L;;;;;N;;;;;\n1881D;TANGUT COMPONENT-030;Lo;0;L;;;;;N;;;;;\n1881E;TANGUT COMPONENT-031;Lo;0;L;;;;;N;;;;;\n1881F;TANGUT COMPONENT-032;Lo;0;L;;;;;N;;;;;\n18820;TANGUT COMPONENT-033;Lo;0;L;;;;;N;;;;;\n18821;TANGUT COMPONENT-034;Lo;0;L;;;;;N;;;;;\n18822;TANGUT COMPONENT-035;Lo;0;L;;;;;N;;;;;\n18823;TANGUT COMPONENT-036;Lo;0;L;;;;;N;;;;;\n18824;TANGUT COMPONENT-037;Lo;0;L;;;;;N;;;;;\n18825;TANGUT COMPONENT-038;Lo;0;L;;;;;N;;;;;\n18826;TANGUT COMPONENT-039;Lo;0;L;;;;;N;;;;;\n18827;TANGUT COMPONENT-040;Lo;0;L;;;;;N;;;;;\n18828;TANGUT COMPONENT-041;Lo;0;L;;;;;N;;;;;\n18829;TANGUT COMPONENT-042;Lo;0;L;;;;;N;;;;;\n1882A;TANGUT COMPONENT-043;Lo;0;L;;;;;N;;;;;\n1882B;TANGUT COMPONENT-044;Lo;0;L;;;;;N;;;;;\n1882C;TANGUT COMPONENT-045;Lo;0;L;;;;;N;;;;;\n1882D;TANGUT COMPONENT-046;Lo;0;L;;;;;N;;;;;\n1882E;TANGUT COMPONENT-047;Lo;0;L;;;;;N;;;;;\n1882F;TANGUT COMPONENT-048;Lo;0;L;;;;;N;;;;;\n18830;TANGUT COMPONENT-049;Lo;0;L;;;;;N;;;;;\n18831;TANGUT COMPONENT-050;Lo;0;L;;;;;N;;;;;\n18832;TANGUT COMPONENT-051;Lo;0;L;;;;;N;;;;;\n18833;TANGUT COMPONENT-052;Lo;0;L;;;;;N;;;;;\n18834;TANGUT COMPONENT-053;Lo;0;L;;;;;N;;;;;\n18835;TANGUT COMPONENT-054;Lo;0;L;;;;;N;;;;;\n18836;TANGUT COMPONENT-055;Lo;0;L;;;;;N;;;;;\n18837;TANGUT COMPONENT-056;Lo;0;L;;;;;N;;;;;\n18838;TANGUT COMPONENT-057;Lo;0;L;;;;;N;;;;;\n18839;TANGUT COMPONENT-058;Lo;0;L;;;;;N;;;;;\n1883A;TANGUT COMPONENT-059;Lo;0;L;;;;;N;;;;;\n1883B;TANGUT COMPONENT-060;Lo;0;L;;;;;N;;;;;\n1883C;TANGUT COMPONENT-061;Lo;0;L;;;;;N;;;;;\n1883D;TANGUT COMPONENT-062;Lo;0;L;;;;;N;;;;;\n1883E;TANGUT COMPONENT-063;Lo;0;L;;;;;N;;;;;\n1883F;TANGUT COMPONENT-064;Lo;0;L;;;;;N;;;;;\n18840;TANGUT COMPONENT-065;Lo;0;L;;;;;N;;;;;\n18841;TANGUT COMPONENT-066;Lo;0;L;;;;;N;;;;;\n18842;TANGUT COMPONENT-067;Lo;0;L;;;;;N;;;;;\n18843;TANGUT COMPONENT-068;Lo;0;L;;;;;N;;;;;\n18844;TANGUT COMPONENT-069;Lo;0;L;;;;;N;;;;;\n18845;TANGUT COMPONENT-070;Lo;0;L;;;;;N;;;;;\n18846;TANGUT COMPONENT-071;Lo;0;L;;;;;N;;;;;\n18847;TANGUT COMPONENT-072;Lo;0;L;;;;;N;;;;;\n18848;TANGUT COMPONENT-073;Lo;0;L;;;;;N;;;;;\n18849;TANGUT COMPONENT-074;Lo;0;L;;;;;N;;;;;\n1884A;TANGUT COMPONENT-075;Lo;0;L;;;;;N;;;;;\n1884B;TANGUT COMPONENT-076;Lo;0;L;;;;;N;;;;;\n1884C;TANGUT COMPONENT-077;Lo;0;L;;;;;N;;;;;\n1884D;TANGUT COMPONENT-078;Lo;0;L;;;;;N;;;;;\n1884E;TANGUT COMPONENT-079;Lo;0;L;;;;;N;;;;;\n1884F;TANGUT COMPONENT-080;Lo;0;L;;;;;N;;;;;\n18850;TANGUT COMPONENT-081;Lo;0;L;;;;;N;;;;;\n18851;TANGUT COMPONENT-082;Lo;0;L;;;;;N;;;;;\n18852;TANGUT COMPONENT-083;Lo;0;L;;;;;N;;;;;\n18853;TANGUT COMPONENT-084;Lo;0;L;;;;;N;;;;;\n18854;TANGUT COMPONENT-085;Lo;0;L;;;;;N;;;;;\n18855;TANGUT COMPONENT-086;Lo;0;L;;;;;N;;;;;\n18856;TANGUT COMPONENT-087;Lo;0;L;;;;;N;;;;;\n18857;TANGUT COMPONENT-088;Lo;0;L;;;;;N;;;;;\n18858;TANGUT COMPONENT-089;Lo;0;L;;;;;N;;;;;\n18859;TANGUT COMPONENT-090;Lo;0;L;;;;;N;;;;;\n1885A;TANGUT COMPONENT-091;Lo;0;L;;;;;N;;;;;\n1885B;TANGUT COMPONENT-092;Lo;0;L;;;;;N;;;;;\n1885C;TANGUT COMPONENT-093;Lo;0;L;;;;;N;;;;;\n1885D;TANGUT COMPONENT-094;Lo;0;L;;;;;N;;;;;\n1885E;TANGUT COMPONENT-095;Lo;0;L;;;;;N;;;;;\n1885F;TANGUT COMPONENT-096;Lo;0;L;;;;;N;;;;;\n18860;TANGUT COMPONENT-097;Lo;0;L;;;;;N;;;;;\n18861;TANGUT COMPONENT-098;Lo;0;L;;;;;N;;;;;\n18862;TANGUT COMPONENT-099;Lo;0;L;;;;;N;;;;;\n18863;TANGUT COMPONENT-100;Lo;0;L;;;;;N;;;;;\n18864;TANGUT COMPONENT-101;Lo;0;L;;;;;N;;;;;\n18865;TANGUT COMPONENT-102;Lo;0;L;;;;;N;;;;;\n18866;TANGUT COMPONENT-103;Lo;0;L;;;;;N;;;;;\n18867;TANGUT COMPONENT-104;Lo;0;L;;;;;N;;;;;\n18868;TANGUT COMPONENT-105;Lo;0;L;;;;;N;;;;;\n18869;TANGUT COMPONENT-106;Lo;0;L;;;;;N;;;;;\n1886A;TANGUT COMPONENT-107;Lo;0;L;;;;;N;;;;;\n1886B;TANGUT COMPONENT-108;Lo;0;L;;;;;N;;;;;\n1886C;TANGUT COMPONENT-109;Lo;0;L;;;;;N;;;;;\n1886D;TANGUT COMPONENT-110;Lo;0;L;;;;;N;;;;;\n1886E;TANGUT COMPONENT-111;Lo;0;L;;;;;N;;;;;\n1886F;TANGUT COMPONENT-112;Lo;0;L;;;;;N;;;;;\n18870;TANGUT COMPONENT-113;Lo;0;L;;;;;N;;;;;\n18871;TANGUT COMPONENT-114;Lo;0;L;;;;;N;;;;;\n18872;TANGUT COMPONENT-115;Lo;0;L;;;;;N;;;;;\n18873;TANGUT COMPONENT-116;Lo;0;L;;;;;N;;;;;\n18874;TANGUT COMPONENT-117;Lo;0;L;;;;;N;;;;;\n18875;TANGUT COMPONENT-118;Lo;0;L;;;;;N;;;;;\n18876;TANGUT COMPONENT-119;Lo;0;L;;;;;N;;;;;\n18877;TANGUT COMPONENT-120;Lo;0;L;;;;;N;;;;;\n18878;TANGUT COMPONENT-121;Lo;0;L;;;;;N;;;;;\n18879;TANGUT COMPONENT-122;Lo;0;L;;;;;N;;;;;\n1887A;TANGUT COMPONENT-123;Lo;0;L;;;;;N;;;;;\n1887B;TANGUT COMPONENT-124;Lo;0;L;;;;;N;;;;;\n1887C;TANGUT COMPONENT-125;Lo;0;L;;;;;N;;;;;\n1887D;TANGUT COMPONENT-126;Lo;0;L;;;;;N;;;;;\n1887E;TANGUT COMPONENT-127;Lo;0;L;;;;;N;;;;;\n1887F;TANGUT COMPONENT-128;Lo;0;L;;;;;N;;;;;\n18880;TANGUT COMPONENT-129;Lo;0;L;;;;;N;;;;;\n18881;TANGUT COMPONENT-130;Lo;0;L;;;;;N;;;;;\n18882;TANGUT COMPONENT-131;Lo;0;L;;;;;N;;;;;\n18883;TANGUT COMPONENT-132;Lo;0;L;;;;;N;;;;;\n18884;TANGUT COMPONENT-133;Lo;0;L;;;;;N;;;;;\n18885;TANGUT COMPONENT-134;Lo;0;L;;;;;N;;;;;\n18886;TANGUT COMPONENT-135;Lo;0;L;;;;;N;;;;;\n18887;TANGUT COMPONENT-136;Lo;0;L;;;;;N;;;;;\n18888;TANGUT COMPONENT-137;Lo;0;L;;;;;N;;;;;\n18889;TANGUT COMPONENT-138;Lo;0;L;;;;;N;;;;;\n1888A;TANGUT COMPONENT-139;Lo;0;L;;;;;N;;;;;\n1888B;TANGUT COMPONENT-140;Lo;0;L;;;;;N;;;;;\n1888C;TANGUT COMPONENT-141;Lo;0;L;;;;;N;;;;;\n1888D;TANGUT COMPONENT-142;Lo;0;L;;;;;N;;;;;\n1888E;TANGUT COMPONENT-143;Lo;0;L;;;;;N;;;;;\n1888F;TANGUT COMPONENT-144;Lo;0;L;;;;;N;;;;;\n18890;TANGUT COMPONENT-145;Lo;0;L;;;;;N;;;;;\n18891;TANGUT COMPONENT-146;Lo;0;L;;;;;N;;;;;\n18892;TANGUT COMPONENT-147;Lo;0;L;;;;;N;;;;;\n18893;TANGUT COMPONENT-148;Lo;0;L;;;;;N;;;;;\n18894;TANGUT COMPONENT-149;Lo;0;L;;;;;N;;;;;\n18895;TANGUT COMPONENT-150;Lo;0;L;;;;;N;;;;;\n18896;TANGUT COMPONENT-151;Lo;0;L;;;;;N;;;;;\n18897;TANGUT COMPONENT-152;Lo;0;L;;;;;N;;;;;\n18898;TANGUT COMPONENT-153;Lo;0;L;;;;;N;;;;;\n18899;TANGUT COMPONENT-154;Lo;0;L;;;;;N;;;;;\n1889A;TANGUT COMPONENT-155;Lo;0;L;;;;;N;;;;;\n1889B;TANGUT COMPONENT-156;Lo;0;L;;;;;N;;;;;\n1889C;TANGUT COMPONENT-157;Lo;0;L;;;;;N;;;;;\n1889D;TANGUT COMPONENT-158;Lo;0;L;;;;;N;;;;;\n1889E;TANGUT COMPONENT-159;Lo;0;L;;;;;N;;;;;\n1889F;TANGUT COMPONENT-160;Lo;0;L;;;;;N;;;;;\n188A0;TANGUT COMPONENT-161;Lo;0;L;;;;;N;;;;;\n188A1;TANGUT COMPONENT-162;Lo;0;L;;;;;N;;;;;\n188A2;TANGUT COMPONENT-163;Lo;0;L;;;;;N;;;;;\n188A3;TANGUT COMPONENT-164;Lo;0;L;;;;;N;;;;;\n188A4;TANGUT COMPONENT-165;Lo;0;L;;;;;N;;;;;\n188A5;TANGUT COMPONENT-166;Lo;0;L;;;;;N;;;;;\n188A6;TANGUT COMPONENT-167;Lo;0;L;;;;;N;;;;;\n188A7;TANGUT COMPONENT-168;Lo;0;L;;;;;N;;;;;\n188A8;TANGUT COMPONENT-169;Lo;0;L;;;;;N;;;;;\n188A9;TANGUT COMPONENT-170;Lo;0;L;;;;;N;;;;;\n188AA;TANGUT COMPONENT-171;Lo;0;L;;;;;N;;;;;\n188AB;TANGUT COMPONENT-172;Lo;0;L;;;;;N;;;;;\n188AC;TANGUT COMPONENT-173;Lo;0;L;;;;;N;;;;;\n188AD;TANGUT COMPONENT-174;Lo;0;L;;;;;N;;;;;\n188AE;TANGUT COMPONENT-175;Lo;0;L;;;;;N;;;;;\n188AF;TANGUT COMPONENT-176;Lo;0;L;;;;;N;;;;;\n188B0;TANGUT COMPONENT-177;Lo;0;L;;;;;N;;;;;\n188B1;TANGUT COMPONENT-178;Lo;0;L;;;;;N;;;;;\n188B2;TANGUT COMPONENT-179;Lo;0;L;;;;;N;;;;;\n188B3;TANGUT COMPONENT-180;Lo;0;L;;;;;N;;;;;\n188B4;TANGUT COMPONENT-181;Lo;0;L;;;;;N;;;;;\n188B5;TANGUT COMPONENT-182;Lo;0;L;;;;;N;;;;;\n188B6;TANGUT COMPONENT-183;Lo;0;L;;;;;N;;;;;\n188B7;TANGUT COMPONENT-184;Lo;0;L;;;;;N;;;;;\n188B8;TANGUT COMPONENT-185;Lo;0;L;;;;;N;;;;;\n188B9;TANGUT COMPONENT-186;Lo;0;L;;;;;N;;;;;\n188BA;TANGUT COMPONENT-187;Lo;0;L;;;;;N;;;;;\n188BB;TANGUT COMPONENT-188;Lo;0;L;;;;;N;;;;;\n188BC;TANGUT COMPONENT-189;Lo;0;L;;;;;N;;;;;\n188BD;TANGUT COMPONENT-190;Lo;0;L;;;;;N;;;;;\n188BE;TANGUT COMPONENT-191;Lo;0;L;;;;;N;;;;;\n188BF;TANGUT COMPONENT-192;Lo;0;L;;;;;N;;;;;\n188C0;TANGUT COMPONENT-193;Lo;0;L;;;;;N;;;;;\n188C1;TANGUT COMPONENT-194;Lo;0;L;;;;;N;;;;;\n188C2;TANGUT COMPONENT-195;Lo;0;L;;;;;N;;;;;\n188C3;TANGUT COMPONENT-196;Lo;0;L;;;;;N;;;;;\n188C4;TANGUT COMPONENT-197;Lo;0;L;;;;;N;;;;;\n188C5;TANGUT COMPONENT-198;Lo;0;L;;;;;N;;;;;\n188C6;TANGUT COMPONENT-199;Lo;0;L;;;;;N;;;;;\n188C7;TANGUT COMPONENT-200;Lo;0;L;;;;;N;;;;;\n188C8;TANGUT COMPONENT-201;Lo;0;L;;;;;N;;;;;\n188C9;TANGUT COMPONENT-202;Lo;0;L;;;;;N;;;;;\n188CA;TANGUT COMPONENT-203;Lo;0;L;;;;;N;;;;;\n188CB;TANGUT COMPONENT-204;Lo;0;L;;;;;N;;;;;\n188CC;TANGUT COMPONENT-205;Lo;0;L;;;;;N;;;;;\n188CD;TANGUT COMPONENT-206;Lo;0;L;;;;;N;;;;;\n188CE;TANGUT COMPONENT-207;Lo;0;L;;;;;N;;;;;\n188CF;TANGUT COMPONENT-208;Lo;0;L;;;;;N;;;;;\n188D0;TANGUT COMPONENT-209;Lo;0;L;;;;;N;;;;;\n188D1;TANGUT COMPONENT-210;Lo;0;L;;;;;N;;;;;\n188D2;TANGUT COMPONENT-211;Lo;0;L;;;;;N;;;;;\n188D3;TANGUT COMPONENT-212;Lo;0;L;;;;;N;;;;;\n188D4;TANGUT COMPONENT-213;Lo;0;L;;;;;N;;;;;\n188D5;TANGUT COMPONENT-214;Lo;0;L;;;;;N;;;;;\n188D6;TANGUT COMPONENT-215;Lo;0;L;;;;;N;;;;;\n188D7;TANGUT COMPONENT-216;Lo;0;L;;;;;N;;;;;\n188D8;TANGUT COMPONENT-217;Lo;0;L;;;;;N;;;;;\n188D9;TANGUT COMPONENT-218;Lo;0;L;;;;;N;;;;;\n188DA;TANGUT COMPONENT-219;Lo;0;L;;;;;N;;;;;\n188DB;TANGUT COMPONENT-220;Lo;0;L;;;;;N;;;;;\n188DC;TANGUT COMPONENT-221;Lo;0;L;;;;;N;;;;;\n188DD;TANGUT COMPONENT-222;Lo;0;L;;;;;N;;;;;\n188DE;TANGUT COMPONENT-223;Lo;0;L;;;;;N;;;;;\n188DF;TANGUT COMPONENT-224;Lo;0;L;;;;;N;;;;;\n188E0;TANGUT COMPONENT-225;Lo;0;L;;;;;N;;;;;\n188E1;TANGUT COMPONENT-226;Lo;0;L;;;;;N;;;;;\n188E2;TANGUT COMPONENT-227;Lo;0;L;;;;;N;;;;;\n188E3;TANGUT COMPONENT-228;Lo;0;L;;;;;N;;;;;\n188E4;TANGUT COMPONENT-229;Lo;0;L;;;;;N;;;;;\n188E5;TANGUT COMPONENT-230;Lo;0;L;;;;;N;;;;;\n188E6;TANGUT COMPONENT-231;Lo;0;L;;;;;N;;;;;\n188E7;TANGUT COMPONENT-232;Lo;0;L;;;;;N;;;;;\n188E8;TANGUT COMPONENT-233;Lo;0;L;;;;;N;;;;;\n188E9;TANGUT COMPONENT-234;Lo;0;L;;;;;N;;;;;\n188EA;TANGUT COMPONENT-235;Lo;0;L;;;;;N;;;;;\n188EB;TANGUT COMPONENT-236;Lo;0;L;;;;;N;;;;;\n188EC;TANGUT COMPONENT-237;Lo;0;L;;;;;N;;;;;\n188ED;TANGUT COMPONENT-238;Lo;0;L;;;;;N;;;;;\n188EE;TANGUT COMPONENT-239;Lo;0;L;;;;;N;;;;;\n188EF;TANGUT COMPONENT-240;Lo;0;L;;;;;N;;;;;\n188F0;TANGUT COMPONENT-241;Lo;0;L;;;;;N;;;;;\n188F1;TANGUT COMPONENT-242;Lo;0;L;;;;;N;;;;;\n188F2;TANGUT COMPONENT-243;Lo;0;L;;;;;N;;;;;\n188F3;TANGUT COMPONENT-244;Lo;0;L;;;;;N;;;;;\n188F4;TANGUT COMPONENT-245;Lo;0;L;;;;;N;;;;;\n188F5;TANGUT COMPONENT-246;Lo;0;L;;;;;N;;;;;\n188F6;TANGUT COMPONENT-247;Lo;0;L;;;;;N;;;;;\n188F7;TANGUT COMPONENT-248;Lo;0;L;;;;;N;;;;;\n188F8;TANGUT COMPONENT-249;Lo;0;L;;;;;N;;;;;\n188F9;TANGUT COMPONENT-250;Lo;0;L;;;;;N;;;;;\n188FA;TANGUT COMPONENT-251;Lo;0;L;;;;;N;;;;;\n188FB;TANGUT COMPONENT-252;Lo;0;L;;;;;N;;;;;\n188FC;TANGUT COMPONENT-253;Lo;0;L;;;;;N;;;;;\n188FD;TANGUT COMPONENT-254;Lo;0;L;;;;;N;;;;;\n188FE;TANGUT COMPONENT-255;Lo;0;L;;;;;N;;;;;\n188FF;TANGUT COMPONENT-256;Lo;0;L;;;;;N;;;;;\n18900;TANGUT COMPONENT-257;Lo;0;L;;;;;N;;;;;\n18901;TANGUT COMPONENT-258;Lo;0;L;;;;;N;;;;;\n18902;TANGUT COMPONENT-259;Lo;0;L;;;;;N;;;;;\n18903;TANGUT COMPONENT-260;Lo;0;L;;;;;N;;;;;\n18904;TANGUT COMPONENT-261;Lo;0;L;;;;;N;;;;;\n18905;TANGUT COMPONENT-262;Lo;0;L;;;;;N;;;;;\n18906;TANGUT COMPONENT-263;Lo;0;L;;;;;N;;;;;\n18907;TANGUT COMPONENT-264;Lo;0;L;;;;;N;;;;;\n18908;TANGUT COMPONENT-265;Lo;0;L;;;;;N;;;;;\n18909;TANGUT COMPONENT-266;Lo;0;L;;;;;N;;;;;\n1890A;TANGUT COMPONENT-267;Lo;0;L;;;;;N;;;;;\n1890B;TANGUT COMPONENT-268;Lo;0;L;;;;;N;;;;;\n1890C;TANGUT COMPONENT-269;Lo;0;L;;;;;N;;;;;\n1890D;TANGUT COMPONENT-270;Lo;0;L;;;;;N;;;;;\n1890E;TANGUT COMPONENT-271;Lo;0;L;;;;;N;;;;;\n1890F;TANGUT COMPONENT-272;Lo;0;L;;;;;N;;;;;\n18910;TANGUT COMPONENT-273;Lo;0;L;;;;;N;;;;;\n18911;TANGUT COMPONENT-274;Lo;0;L;;;;;N;;;;;\n18912;TANGUT COMPONENT-275;Lo;0;L;;;;;N;;;;;\n18913;TANGUT COMPONENT-276;Lo;0;L;;;;;N;;;;;\n18914;TANGUT COMPONENT-277;Lo;0;L;;;;;N;;;;;\n18915;TANGUT COMPONENT-278;Lo;0;L;;;;;N;;;;;\n18916;TANGUT COMPONENT-279;Lo;0;L;;;;;N;;;;;\n18917;TANGUT COMPONENT-280;Lo;0;L;;;;;N;;;;;\n18918;TANGUT COMPONENT-281;Lo;0;L;;;;;N;;;;;\n18919;TANGUT COMPONENT-282;Lo;0;L;;;;;N;;;;;\n1891A;TANGUT COMPONENT-283;Lo;0;L;;;;;N;;;;;\n1891B;TANGUT COMPONENT-284;Lo;0;L;;;;;N;;;;;\n1891C;TANGUT COMPONENT-285;Lo;0;L;;;;;N;;;;;\n1891D;TANGUT COMPONENT-286;Lo;0;L;;;;;N;;;;;\n1891E;TANGUT COMPONENT-287;Lo;0;L;;;;;N;;;;;\n1891F;TANGUT COMPONENT-288;Lo;0;L;;;;;N;;;;;\n18920;TANGUT COMPONENT-289;Lo;0;L;;;;;N;;;;;\n18921;TANGUT COMPONENT-290;Lo;0;L;;;;;N;;;;;\n18922;TANGUT COMPONENT-291;Lo;0;L;;;;;N;;;;;\n18923;TANGUT COMPONENT-292;Lo;0;L;;;;;N;;;;;\n18924;TANGUT COMPONENT-293;Lo;0;L;;;;;N;;;;;\n18925;TANGUT COMPONENT-294;Lo;0;L;;;;;N;;;;;\n18926;TANGUT COMPONENT-295;Lo;0;L;;;;;N;;;;;\n18927;TANGUT COMPONENT-296;Lo;0;L;;;;;N;;;;;\n18928;TANGUT COMPONENT-297;Lo;0;L;;;;;N;;;;;\n18929;TANGUT COMPONENT-298;Lo;0;L;;;;;N;;;;;\n1892A;TANGUT COMPONENT-299;Lo;0;L;;;;;N;;;;;\n1892B;TANGUT COMPONENT-300;Lo;0;L;;;;;N;;;;;\n1892C;TANGUT COMPONENT-301;Lo;0;L;;;;;N;;;;;\n1892D;TANGUT COMPONENT-302;Lo;0;L;;;;;N;;;;;\n1892E;TANGUT COMPONENT-303;Lo;0;L;;;;;N;;;;;\n1892F;TANGUT COMPONENT-304;Lo;0;L;;;;;N;;;;;\n18930;TANGUT COMPONENT-305;Lo;0;L;;;;;N;;;;;\n18931;TANGUT COMPONENT-306;Lo;0;L;;;;;N;;;;;\n18932;TANGUT COMPONENT-307;Lo;0;L;;;;;N;;;;;\n18933;TANGUT COMPONENT-308;Lo;0;L;;;;;N;;;;;\n18934;TANGUT COMPONENT-309;Lo;0;L;;;;;N;;;;;\n18935;TANGUT COMPONENT-310;Lo;0;L;;;;;N;;;;;\n18936;TANGUT COMPONENT-311;Lo;0;L;;;;;N;;;;;\n18937;TANGUT COMPONENT-312;Lo;0;L;;;;;N;;;;;\n18938;TANGUT COMPONENT-313;Lo;0;L;;;;;N;;;;;\n18939;TANGUT COMPONENT-314;Lo;0;L;;;;;N;;;;;\n1893A;TANGUT COMPONENT-315;Lo;0;L;;;;;N;;;;;\n1893B;TANGUT COMPONENT-316;Lo;0;L;;;;;N;;;;;\n1893C;TANGUT COMPONENT-317;Lo;0;L;;;;;N;;;;;\n1893D;TANGUT COMPONENT-318;Lo;0;L;;;;;N;;;;;\n1893E;TANGUT COMPONENT-319;Lo;0;L;;;;;N;;;;;\n1893F;TANGUT COMPONENT-320;Lo;0;L;;;;;N;;;;;\n18940;TANGUT COMPONENT-321;Lo;0;L;;;;;N;;;;;\n18941;TANGUT COMPONENT-322;Lo;0;L;;;;;N;;;;;\n18942;TANGUT COMPONENT-323;Lo;0;L;;;;;N;;;;;\n18943;TANGUT COMPONENT-324;Lo;0;L;;;;;N;;;;;\n18944;TANGUT COMPONENT-325;Lo;0;L;;;;;N;;;;;\n18945;TANGUT COMPONENT-326;Lo;0;L;;;;;N;;;;;\n18946;TANGUT COMPONENT-327;Lo;0;L;;;;;N;;;;;\n18947;TANGUT COMPONENT-328;Lo;0;L;;;;;N;;;;;\n18948;TANGUT COMPONENT-329;Lo;0;L;;;;;N;;;;;\n18949;TANGUT COMPONENT-330;Lo;0;L;;;;;N;;;;;\n1894A;TANGUT COMPONENT-331;Lo;0;L;;;;;N;;;;;\n1894B;TANGUT COMPONENT-332;Lo;0;L;;;;;N;;;;;\n1894C;TANGUT COMPONENT-333;Lo;0;L;;;;;N;;;;;\n1894D;TANGUT COMPONENT-334;Lo;0;L;;;;;N;;;;;\n1894E;TANGUT COMPONENT-335;Lo;0;L;;;;;N;;;;;\n1894F;TANGUT COMPONENT-336;Lo;0;L;;;;;N;;;;;\n18950;TANGUT COMPONENT-337;Lo;0;L;;;;;N;;;;;\n18951;TANGUT COMPONENT-338;Lo;0;L;;;;;N;;;;;\n18952;TANGUT COMPONENT-339;Lo;0;L;;;;;N;;;;;\n18953;TANGUT COMPONENT-340;Lo;0;L;;;;;N;;;;;\n18954;TANGUT COMPONENT-341;Lo;0;L;;;;;N;;;;;\n18955;TANGUT COMPONENT-342;Lo;0;L;;;;;N;;;;;\n18956;TANGUT COMPONENT-343;Lo;0;L;;;;;N;;;;;\n18957;TANGUT COMPONENT-344;Lo;0;L;;;;;N;;;;;\n18958;TANGUT COMPONENT-345;Lo;0;L;;;;;N;;;;;\n18959;TANGUT COMPONENT-346;Lo;0;L;;;;;N;;;;;\n1895A;TANGUT COMPONENT-347;Lo;0;L;;;;;N;;;;;\n1895B;TANGUT COMPONENT-348;Lo;0;L;;;;;N;;;;;\n1895C;TANGUT COMPONENT-349;Lo;0;L;;;;;N;;;;;\n1895D;TANGUT COMPONENT-350;Lo;0;L;;;;;N;;;;;\n1895E;TANGUT COMPONENT-351;Lo;0;L;;;;;N;;;;;\n1895F;TANGUT COMPONENT-352;Lo;0;L;;;;;N;;;;;\n18960;TANGUT COMPONENT-353;Lo;0;L;;;;;N;;;;;\n18961;TANGUT COMPONENT-354;Lo;0;L;;;;;N;;;;;\n18962;TANGUT COMPONENT-355;Lo;0;L;;;;;N;;;;;\n18963;TANGUT COMPONENT-356;Lo;0;L;;;;;N;;;;;\n18964;TANGUT COMPONENT-357;Lo;0;L;;;;;N;;;;;\n18965;TANGUT COMPONENT-358;Lo;0;L;;;;;N;;;;;\n18966;TANGUT COMPONENT-359;Lo;0;L;;;;;N;;;;;\n18967;TANGUT COMPONENT-360;Lo;0;L;;;;;N;;;;;\n18968;TANGUT COMPONENT-361;Lo;0;L;;;;;N;;;;;\n18969;TANGUT COMPONENT-362;Lo;0;L;;;;;N;;;;;\n1896A;TANGUT COMPONENT-363;Lo;0;L;;;;;N;;;;;\n1896B;TANGUT COMPONENT-364;Lo;0;L;;;;;N;;;;;\n1896C;TANGUT COMPONENT-365;Lo;0;L;;;;;N;;;;;\n1896D;TANGUT COMPONENT-366;Lo;0;L;;;;;N;;;;;\n1896E;TANGUT COMPONENT-367;Lo;0;L;;;;;N;;;;;\n1896F;TANGUT COMPONENT-368;Lo;0;L;;;;;N;;;;;\n18970;TANGUT COMPONENT-369;Lo;0;L;;;;;N;;;;;\n18971;TANGUT COMPONENT-370;Lo;0;L;;;;;N;;;;;\n18972;TANGUT COMPONENT-371;Lo;0;L;;;;;N;;;;;\n18973;TANGUT COMPONENT-372;Lo;0;L;;;;;N;;;;;\n18974;TANGUT COMPONENT-373;Lo;0;L;;;;;N;;;;;\n18975;TANGUT COMPONENT-374;Lo;0;L;;;;;N;;;;;\n18976;TANGUT COMPONENT-375;Lo;0;L;;;;;N;;;;;\n18977;TANGUT COMPONENT-376;Lo;0;L;;;;;N;;;;;\n18978;TANGUT COMPONENT-377;Lo;0;L;;;;;N;;;;;\n18979;TANGUT COMPONENT-378;Lo;0;L;;;;;N;;;;;\n1897A;TANGUT COMPONENT-379;Lo;0;L;;;;;N;;;;;\n1897B;TANGUT COMPONENT-380;Lo;0;L;;;;;N;;;;;\n1897C;TANGUT COMPONENT-381;Lo;0;L;;;;;N;;;;;\n1897D;TANGUT COMPONENT-382;Lo;0;L;;;;;N;;;;;\n1897E;TANGUT COMPONENT-383;Lo;0;L;;;;;N;;;;;\n1897F;TANGUT COMPONENT-384;Lo;0;L;;;;;N;;;;;\n18980;TANGUT COMPONENT-385;Lo;0;L;;;;;N;;;;;\n18981;TANGUT COMPONENT-386;Lo;0;L;;;;;N;;;;;\n18982;TANGUT COMPONENT-387;Lo;0;L;;;;;N;;;;;\n18983;TANGUT COMPONENT-388;Lo;0;L;;;;;N;;;;;\n18984;TANGUT COMPONENT-389;Lo;0;L;;;;;N;;;;;\n18985;TANGUT COMPONENT-390;Lo;0;L;;;;;N;;;;;\n18986;TANGUT COMPONENT-391;Lo;0;L;;;;;N;;;;;\n18987;TANGUT COMPONENT-392;Lo;0;L;;;;;N;;;;;\n18988;TANGUT COMPONENT-393;Lo;0;L;;;;;N;;;;;\n18989;TANGUT COMPONENT-394;Lo;0;L;;;;;N;;;;;\n1898A;TANGUT COMPONENT-395;Lo;0;L;;;;;N;;;;;\n1898B;TANGUT COMPONENT-396;Lo;0;L;;;;;N;;;;;\n1898C;TANGUT COMPONENT-397;Lo;0;L;;;;;N;;;;;\n1898D;TANGUT COMPONENT-398;Lo;0;L;;;;;N;;;;;\n1898E;TANGUT COMPONENT-399;Lo;0;L;;;;;N;;;;;\n1898F;TANGUT COMPONENT-400;Lo;0;L;;;;;N;;;;;\n18990;TANGUT COMPONENT-401;Lo;0;L;;;;;N;;;;;\n18991;TANGUT COMPONENT-402;Lo;0;L;;;;;N;;;;;\n18992;TANGUT COMPONENT-403;Lo;0;L;;;;;N;;;;;\n18993;TANGUT COMPONENT-404;Lo;0;L;;;;;N;;;;;\n18994;TANGUT COMPONENT-405;Lo;0;L;;;;;N;;;;;\n18995;TANGUT COMPONENT-406;Lo;0;L;;;;;N;;;;;\n18996;TANGUT COMPONENT-407;Lo;0;L;;;;;N;;;;;\n18997;TANGUT COMPONENT-408;Lo;0;L;;;;;N;;;;;\n18998;TANGUT COMPONENT-409;Lo;0;L;;;;;N;;;;;\n18999;TANGUT COMPONENT-410;Lo;0;L;;;;;N;;;;;\n1899A;TANGUT COMPONENT-411;Lo;0;L;;;;;N;;;;;\n1899B;TANGUT COMPONENT-412;Lo;0;L;;;;;N;;;;;\n1899C;TANGUT COMPONENT-413;Lo;0;L;;;;;N;;;;;\n1899D;TANGUT COMPONENT-414;Lo;0;L;;;;;N;;;;;\n1899E;TANGUT COMPONENT-415;Lo;0;L;;;;;N;;;;;\n1899F;TANGUT COMPONENT-416;Lo;0;L;;;;;N;;;;;\n189A0;TANGUT COMPONENT-417;Lo;0;L;;;;;N;;;;;\n189A1;TANGUT COMPONENT-418;Lo;0;L;;;;;N;;;;;\n189A2;TANGUT COMPONENT-419;Lo;0;L;;;;;N;;;;;\n189A3;TANGUT COMPONENT-420;Lo;0;L;;;;;N;;;;;\n189A4;TANGUT COMPONENT-421;Lo;0;L;;;;;N;;;;;\n189A5;TANGUT COMPONENT-422;Lo;0;L;;;;;N;;;;;\n189A6;TANGUT COMPONENT-423;Lo;0;L;;;;;N;;;;;\n189A7;TANGUT COMPONENT-424;Lo;0;L;;;;;N;;;;;\n189A8;TANGUT COMPONENT-425;Lo;0;L;;;;;N;;;;;\n189A9;TANGUT COMPONENT-426;Lo;0;L;;;;;N;;;;;\n189AA;TANGUT COMPONENT-427;Lo;0;L;;;;;N;;;;;\n189AB;TANGUT COMPONENT-428;Lo;0;L;;;;;N;;;;;\n189AC;TANGUT COMPONENT-429;Lo;0;L;;;;;N;;;;;\n189AD;TANGUT COMPONENT-430;Lo;0;L;;;;;N;;;;;\n189AE;TANGUT COMPONENT-431;Lo;0;L;;;;;N;;;;;\n189AF;TANGUT COMPONENT-432;Lo;0;L;;;;;N;;;;;\n189B0;TANGUT COMPONENT-433;Lo;0;L;;;;;N;;;;;\n189B1;TANGUT COMPONENT-434;Lo;0;L;;;;;N;;;;;\n189B2;TANGUT COMPONENT-435;Lo;0;L;;;;;N;;;;;\n189B3;TANGUT COMPONENT-436;Lo;0;L;;;;;N;;;;;\n189B4;TANGUT COMPONENT-437;Lo;0;L;;;;;N;;;;;\n189B5;TANGUT COMPONENT-438;Lo;0;L;;;;;N;;;;;\n189B6;TANGUT COMPONENT-439;Lo;0;L;;;;;N;;;;;\n189B7;TANGUT COMPONENT-440;Lo;0;L;;;;;N;;;;;\n189B8;TANGUT COMPONENT-441;Lo;0;L;;;;;N;;;;;\n189B9;TANGUT COMPONENT-442;Lo;0;L;;;;;N;;;;;\n189BA;TANGUT COMPONENT-443;Lo;0;L;;;;;N;;;;;\n189BB;TANGUT COMPONENT-444;Lo;0;L;;;;;N;;;;;\n189BC;TANGUT COMPONENT-445;Lo;0;L;;;;;N;;;;;\n189BD;TANGUT COMPONENT-446;Lo;0;L;;;;;N;;;;;\n189BE;TANGUT COMPONENT-447;Lo;0;L;;;;;N;;;;;\n189BF;TANGUT COMPONENT-448;Lo;0;L;;;;;N;;;;;\n189C0;TANGUT COMPONENT-449;Lo;0;L;;;;;N;;;;;\n189C1;TANGUT COMPONENT-450;Lo;0;L;;;;;N;;;;;\n189C2;TANGUT COMPONENT-451;Lo;0;L;;;;;N;;;;;\n189C3;TANGUT COMPONENT-452;Lo;0;L;;;;;N;;;;;\n189C4;TANGUT COMPONENT-453;Lo;0;L;;;;;N;;;;;\n189C5;TANGUT COMPONENT-454;Lo;0;L;;;;;N;;;;;\n189C6;TANGUT COMPONENT-455;Lo;0;L;;;;;N;;;;;\n189C7;TANGUT COMPONENT-456;Lo;0;L;;;;;N;;;;;\n189C8;TANGUT COMPONENT-457;Lo;0;L;;;;;N;;;;;\n189C9;TANGUT COMPONENT-458;Lo;0;L;;;;;N;;;;;\n189CA;TANGUT COMPONENT-459;Lo;0;L;;;;;N;;;;;\n189CB;TANGUT COMPONENT-460;Lo;0;L;;;;;N;;;;;\n189CC;TANGUT COMPONENT-461;Lo;0;L;;;;;N;;;;;\n189CD;TANGUT COMPONENT-462;Lo;0;L;;;;;N;;;;;\n189CE;TANGUT COMPONENT-463;Lo;0;L;;;;;N;;;;;\n189CF;TANGUT COMPONENT-464;Lo;0;L;;;;;N;;;;;\n189D0;TANGUT COMPONENT-465;Lo;0;L;;;;;N;;;;;\n189D1;TANGUT COMPONENT-466;Lo;0;L;;;;;N;;;;;\n189D2;TANGUT COMPONENT-467;Lo;0;L;;;;;N;;;;;\n189D3;TANGUT COMPONENT-468;Lo;0;L;;;;;N;;;;;\n189D4;TANGUT COMPONENT-469;Lo;0;L;;;;;N;;;;;\n189D5;TANGUT COMPONENT-470;Lo;0;L;;;;;N;;;;;\n189D6;TANGUT COMPONENT-471;Lo;0;L;;;;;N;;;;;\n189D7;TANGUT COMPONENT-472;Lo;0;L;;;;;N;;;;;\n189D8;TANGUT COMPONENT-473;Lo;0;L;;;;;N;;;;;\n189D9;TANGUT COMPONENT-474;Lo;0;L;;;;;N;;;;;\n189DA;TANGUT COMPONENT-475;Lo;0;L;;;;;N;;;;;\n189DB;TANGUT COMPONENT-476;Lo;0;L;;;;;N;;;;;\n189DC;TANGUT COMPONENT-477;Lo;0;L;;;;;N;;;;;\n189DD;TANGUT COMPONENT-478;Lo;0;L;;;;;N;;;;;\n189DE;TANGUT COMPONENT-479;Lo;0;L;;;;;N;;;;;\n189DF;TANGUT COMPONENT-480;Lo;0;L;;;;;N;;;;;\n189E0;TANGUT COMPONENT-481;Lo;0;L;;;;;N;;;;;\n189E1;TANGUT COMPONENT-482;Lo;0;L;;;;;N;;;;;\n189E2;TANGUT COMPONENT-483;Lo;0;L;;;;;N;;;;;\n189E3;TANGUT COMPONENT-484;Lo;0;L;;;;;N;;;;;\n189E4;TANGUT COMPONENT-485;Lo;0;L;;;;;N;;;;;\n189E5;TANGUT COMPONENT-486;Lo;0;L;;;;;N;;;;;\n189E6;TANGUT COMPONENT-487;Lo;0;L;;;;;N;;;;;\n189E7;TANGUT COMPONENT-488;Lo;0;L;;;;;N;;;;;\n189E8;TANGUT COMPONENT-489;Lo;0;L;;;;;N;;;;;\n189E9;TANGUT COMPONENT-490;Lo;0;L;;;;;N;;;;;\n189EA;TANGUT COMPONENT-491;Lo;0;L;;;;;N;;;;;\n189EB;TANGUT COMPONENT-492;Lo;0;L;;;;;N;;;;;\n189EC;TANGUT COMPONENT-493;Lo;0;L;;;;;N;;;;;\n189ED;TANGUT COMPONENT-494;Lo;0;L;;;;;N;;;;;\n189EE;TANGUT COMPONENT-495;Lo;0;L;;;;;N;;;;;\n189EF;TANGUT COMPONENT-496;Lo;0;L;;;;;N;;;;;\n189F0;TANGUT COMPONENT-497;Lo;0;L;;;;;N;;;;;\n189F1;TANGUT COMPONENT-498;Lo;0;L;;;;;N;;;;;\n189F2;TANGUT COMPONENT-499;Lo;0;L;;;;;N;;;;;\n189F3;TANGUT COMPONENT-500;Lo;0;L;;;;;N;;;;;\n189F4;TANGUT COMPONENT-501;Lo;0;L;;;;;N;;;;;\n189F5;TANGUT COMPONENT-502;Lo;0;L;;;;;N;;;;;\n189F6;TANGUT COMPONENT-503;Lo;0;L;;;;;N;;;;;\n189F7;TANGUT COMPONENT-504;Lo;0;L;;;;;N;;;;;\n189F8;TANGUT COMPONENT-505;Lo;0;L;;;;;N;;;;;\n189F9;TANGUT COMPONENT-506;Lo;0;L;;;;;N;;;;;\n189FA;TANGUT COMPONENT-507;Lo;0;L;;;;;N;;;;;\n189FB;TANGUT COMPONENT-508;Lo;0;L;;;;;N;;;;;\n189FC;TANGUT COMPONENT-509;Lo;0;L;;;;;N;;;;;\n189FD;TANGUT COMPONENT-510;Lo;0;L;;;;;N;;;;;\n189FE;TANGUT COMPONENT-511;Lo;0;L;;;;;N;;;;;\n189FF;TANGUT COMPONENT-512;Lo;0;L;;;;;N;;;;;\n18A00;TANGUT COMPONENT-513;Lo;0;L;;;;;N;;;;;\n18A01;TANGUT COMPONENT-514;Lo;0;L;;;;;N;;;;;\n18A02;TANGUT COMPONENT-515;Lo;0;L;;;;;N;;;;;\n18A03;TANGUT COMPONENT-516;Lo;0;L;;;;;N;;;;;\n18A04;TANGUT COMPONENT-517;Lo;0;L;;;;;N;;;;;\n18A05;TANGUT COMPONENT-518;Lo;0;L;;;;;N;;;;;\n18A06;TANGUT COMPONENT-519;Lo;0;L;;;;;N;;;;;\n18A07;TANGUT COMPONENT-520;Lo;0;L;;;;;N;;;;;\n18A08;TANGUT COMPONENT-521;Lo;0;L;;;;;N;;;;;\n18A09;TANGUT COMPONENT-522;Lo;0;L;;;;;N;;;;;\n18A0A;TANGUT COMPONENT-523;Lo;0;L;;;;;N;;;;;\n18A0B;TANGUT COMPONENT-524;Lo;0;L;;;;;N;;;;;\n18A0C;TANGUT COMPONENT-525;Lo;0;L;;;;;N;;;;;\n18A0D;TANGUT COMPONENT-526;Lo;0;L;;;;;N;;;;;\n18A0E;TANGUT COMPONENT-527;Lo;0;L;;;;;N;;;;;\n18A0F;TANGUT COMPONENT-528;Lo;0;L;;;;;N;;;;;\n18A10;TANGUT COMPONENT-529;Lo;0;L;;;;;N;;;;;\n18A11;TANGUT COMPONENT-530;Lo;0;L;;;;;N;;;;;\n18A12;TANGUT COMPONENT-531;Lo;0;L;;;;;N;;;;;\n18A13;TANGUT COMPONENT-532;Lo;0;L;;;;;N;;;;;\n18A14;TANGUT COMPONENT-533;Lo;0;L;;;;;N;;;;;\n18A15;TANGUT COMPONENT-534;Lo;0;L;;;;;N;;;;;\n18A16;TANGUT COMPONENT-535;Lo;0;L;;;;;N;;;;;\n18A17;TANGUT COMPONENT-536;Lo;0;L;;;;;N;;;;;\n18A18;TANGUT COMPONENT-537;Lo;0;L;;;;;N;;;;;\n18A19;TANGUT COMPONENT-538;Lo;0;L;;;;;N;;;;;\n18A1A;TANGUT COMPONENT-539;Lo;0;L;;;;;N;;;;;\n18A1B;TANGUT COMPONENT-540;Lo;0;L;;;;;N;;;;;\n18A1C;TANGUT COMPONENT-541;Lo;0;L;;;;;N;;;;;\n18A1D;TANGUT COMPONENT-542;Lo;0;L;;;;;N;;;;;\n18A1E;TANGUT COMPONENT-543;Lo;0;L;;;;;N;;;;;\n18A1F;TANGUT COMPONENT-544;Lo;0;L;;;;;N;;;;;\n18A20;TANGUT COMPONENT-545;Lo;0;L;;;;;N;;;;;\n18A21;TANGUT COMPONENT-546;Lo;0;L;;;;;N;;;;;\n18A22;TANGUT COMPONENT-547;Lo;0;L;;;;;N;;;;;\n18A23;TANGUT COMPONENT-548;Lo;0;L;;;;;N;;;;;\n18A24;TANGUT COMPONENT-549;Lo;0;L;;;;;N;;;;;\n18A25;TANGUT COMPONENT-550;Lo;0;L;;;;;N;;;;;\n18A26;TANGUT COMPONENT-551;Lo;0;L;;;;;N;;;;;\n18A27;TANGUT COMPONENT-552;Lo;0;L;;;;;N;;;;;\n18A28;TANGUT COMPONENT-553;Lo;0;L;;;;;N;;;;;\n18A29;TANGUT COMPONENT-554;Lo;0;L;;;;;N;;;;;\n18A2A;TANGUT COMPONENT-555;Lo;0;L;;;;;N;;;;;\n18A2B;TANGUT COMPONENT-556;Lo;0;L;;;;;N;;;;;\n18A2C;TANGUT COMPONENT-557;Lo;0;L;;;;;N;;;;;\n18A2D;TANGUT COMPONENT-558;Lo;0;L;;;;;N;;;;;\n18A2E;TANGUT COMPONENT-559;Lo;0;L;;;;;N;;;;;\n18A2F;TANGUT COMPONENT-560;Lo;0;L;;;;;N;;;;;\n18A30;TANGUT COMPONENT-561;Lo;0;L;;;;;N;;;;;\n18A31;TANGUT COMPONENT-562;Lo;0;L;;;;;N;;;;;\n18A32;TANGUT COMPONENT-563;Lo;0;L;;;;;N;;;;;\n18A33;TANGUT COMPONENT-564;Lo;0;L;;;;;N;;;;;\n18A34;TANGUT COMPONENT-565;Lo;0;L;;;;;N;;;;;\n18A35;TANGUT COMPONENT-566;Lo;0;L;;;;;N;;;;;\n18A36;TANGUT COMPONENT-567;Lo;0;L;;;;;N;;;;;\n18A37;TANGUT COMPONENT-568;Lo;0;L;;;;;N;;;;;\n18A38;TANGUT COMPONENT-569;Lo;0;L;;;;;N;;;;;\n18A39;TANGUT COMPONENT-570;Lo;0;L;;;;;N;;;;;\n18A3A;TANGUT COMPONENT-571;Lo;0;L;;;;;N;;;;;\n18A3B;TANGUT COMPONENT-572;Lo;0;L;;;;;N;;;;;\n18A3C;TANGUT COMPONENT-573;Lo;0;L;;;;;N;;;;;\n18A3D;TANGUT COMPONENT-574;Lo;0;L;;;;;N;;;;;\n18A3E;TANGUT COMPONENT-575;Lo;0;L;;;;;N;;;;;\n18A3F;TANGUT COMPONENT-576;Lo;0;L;;;;;N;;;;;\n18A40;TANGUT COMPONENT-577;Lo;0;L;;;;;N;;;;;\n18A41;TANGUT COMPONENT-578;Lo;0;L;;;;;N;;;;;\n18A42;TANGUT COMPONENT-579;Lo;0;L;;;;;N;;;;;\n18A43;TANGUT COMPONENT-580;Lo;0;L;;;;;N;;;;;\n18A44;TANGUT COMPONENT-581;Lo;0;L;;;;;N;;;;;\n18A45;TANGUT COMPONENT-582;Lo;0;L;;;;;N;;;;;\n18A46;TANGUT COMPONENT-583;Lo;0;L;;;;;N;;;;;\n18A47;TANGUT COMPONENT-584;Lo;0;L;;;;;N;;;;;\n18A48;TANGUT COMPONENT-585;Lo;0;L;;;;;N;;;;;\n18A49;TANGUT COMPONENT-586;Lo;0;L;;;;;N;;;;;\n18A4A;TANGUT COMPONENT-587;Lo;0;L;;;;;N;;;;;\n18A4B;TANGUT COMPONENT-588;Lo;0;L;;;;;N;;;;;\n18A4C;TANGUT COMPONENT-589;Lo;0;L;;;;;N;;;;;\n18A4D;TANGUT COMPONENT-590;Lo;0;L;;;;;N;;;;;\n18A4E;TANGUT COMPONENT-591;Lo;0;L;;;;;N;;;;;\n18A4F;TANGUT COMPONENT-592;Lo;0;L;;;;;N;;;;;\n18A50;TANGUT COMPONENT-593;Lo;0;L;;;;;N;;;;;\n18A51;TANGUT COMPONENT-594;Lo;0;L;;;;;N;;;;;\n18A52;TANGUT COMPONENT-595;Lo;0;L;;;;;N;;;;;\n18A53;TANGUT COMPONENT-596;Lo;0;L;;;;;N;;;;;\n18A54;TANGUT COMPONENT-597;Lo;0;L;;;;;N;;;;;\n18A55;TANGUT COMPONENT-598;Lo;0;L;;;;;N;;;;;\n18A56;TANGUT COMPONENT-599;Lo;0;L;;;;;N;;;;;\n18A57;TANGUT COMPONENT-600;Lo;0;L;;;;;N;;;;;\n18A58;TANGUT COMPONENT-601;Lo;0;L;;;;;N;;;;;\n18A59;TANGUT COMPONENT-602;Lo;0;L;;;;;N;;;;;\n18A5A;TANGUT COMPONENT-603;Lo;0;L;;;;;N;;;;;\n18A5B;TANGUT COMPONENT-604;Lo;0;L;;;;;N;;;;;\n18A5C;TANGUT COMPONENT-605;Lo;0;L;;;;;N;;;;;\n18A5D;TANGUT COMPONENT-606;Lo;0;L;;;;;N;;;;;\n18A5E;TANGUT COMPONENT-607;Lo;0;L;;;;;N;;;;;\n18A5F;TANGUT COMPONENT-608;Lo;0;L;;;;;N;;;;;\n18A60;TANGUT COMPONENT-609;Lo;0;L;;;;;N;;;;;\n18A61;TANGUT COMPONENT-610;Lo;0;L;;;;;N;;;;;\n18A62;TANGUT COMPONENT-611;Lo;0;L;;;;;N;;;;;\n18A63;TANGUT COMPONENT-612;Lo;0;L;;;;;N;;;;;\n18A64;TANGUT COMPONENT-613;Lo;0;L;;;;;N;;;;;\n18A65;TANGUT COMPONENT-614;Lo;0;L;;;;;N;;;;;\n18A66;TANGUT COMPONENT-615;Lo;0;L;;;;;N;;;;;\n18A67;TANGUT COMPONENT-616;Lo;0;L;;;;;N;;;;;\n18A68;TANGUT COMPONENT-617;Lo;0;L;;;;;N;;;;;\n18A69;TANGUT COMPONENT-618;Lo;0;L;;;;;N;;;;;\n18A6A;TANGUT COMPONENT-619;Lo;0;L;;;;;N;;;;;\n18A6B;TANGUT COMPONENT-620;Lo;0;L;;;;;N;;;;;\n18A6C;TANGUT COMPONENT-621;Lo;0;L;;;;;N;;;;;\n18A6D;TANGUT COMPONENT-622;Lo;0;L;;;;;N;;;;;\n18A6E;TANGUT COMPONENT-623;Lo;0;L;;;;;N;;;;;\n18A6F;TANGUT COMPONENT-624;Lo;0;L;;;;;N;;;;;\n18A70;TANGUT COMPONENT-625;Lo;0;L;;;;;N;;;;;\n18A71;TANGUT COMPONENT-626;Lo;0;L;;;;;N;;;;;\n18A72;TANGUT COMPONENT-627;Lo;0;L;;;;;N;;;;;\n18A73;TANGUT COMPONENT-628;Lo;0;L;;;;;N;;;;;\n18A74;TANGUT COMPONENT-629;Lo;0;L;;;;;N;;;;;\n18A75;TANGUT COMPONENT-630;Lo;0;L;;;;;N;;;;;\n18A76;TANGUT COMPONENT-631;Lo;0;L;;;;;N;;;;;\n18A77;TANGUT COMPONENT-632;Lo;0;L;;;;;N;;;;;\n18A78;TANGUT COMPONENT-633;Lo;0;L;;;;;N;;;;;\n18A79;TANGUT COMPONENT-634;Lo;0;L;;;;;N;;;;;\n18A7A;TANGUT COMPONENT-635;Lo;0;L;;;;;N;;;;;\n18A7B;TANGUT COMPONENT-636;Lo;0;L;;;;;N;;;;;\n18A7C;TANGUT COMPONENT-637;Lo;0;L;;;;;N;;;;;\n18A7D;TANGUT COMPONENT-638;Lo;0;L;;;;;N;;;;;\n18A7E;TANGUT COMPONENT-639;Lo;0;L;;;;;N;;;;;\n18A7F;TANGUT COMPONENT-640;Lo;0;L;;;;;N;;;;;\n18A80;TANGUT COMPONENT-641;Lo;0;L;;;;;N;;;;;\n18A81;TANGUT COMPONENT-642;Lo;0;L;;;;;N;;;;;\n18A82;TANGUT COMPONENT-643;Lo;0;L;;;;;N;;;;;\n18A83;TANGUT COMPONENT-644;Lo;0;L;;;;;N;;;;;\n18A84;TANGUT COMPONENT-645;Lo;0;L;;;;;N;;;;;\n18A85;TANGUT COMPONENT-646;Lo;0;L;;;;;N;;;;;\n18A86;TANGUT COMPONENT-647;Lo;0;L;;;;;N;;;;;\n18A87;TANGUT COMPONENT-648;Lo;0;L;;;;;N;;;;;\n18A88;TANGUT COMPONENT-649;Lo;0;L;;;;;N;;;;;\n18A89;TANGUT COMPONENT-650;Lo;0;L;;;;;N;;;;;\n18A8A;TANGUT COMPONENT-651;Lo;0;L;;;;;N;;;;;\n18A8B;TANGUT COMPONENT-652;Lo;0;L;;;;;N;;;;;\n18A8C;TANGUT COMPONENT-653;Lo;0;L;;;;;N;;;;;\n18A8D;TANGUT COMPONENT-654;Lo;0;L;;;;;N;;;;;\n18A8E;TANGUT COMPONENT-655;Lo;0;L;;;;;N;;;;;\n18A8F;TANGUT COMPONENT-656;Lo;0;L;;;;;N;;;;;\n18A90;TANGUT COMPONENT-657;Lo;0;L;;;;;N;;;;;\n18A91;TANGUT COMPONENT-658;Lo;0;L;;;;;N;;;;;\n18A92;TANGUT COMPONENT-659;Lo;0;L;;;;;N;;;;;\n18A93;TANGUT COMPONENT-660;Lo;0;L;;;;;N;;;;;\n18A94;TANGUT COMPONENT-661;Lo;0;L;;;;;N;;;;;\n18A95;TANGUT COMPONENT-662;Lo;0;L;;;;;N;;;;;\n18A96;TANGUT COMPONENT-663;Lo;0;L;;;;;N;;;;;\n18A97;TANGUT COMPONENT-664;Lo;0;L;;;;;N;;;;;\n18A98;TANGUT COMPONENT-665;Lo;0;L;;;;;N;;;;;\n18A99;TANGUT COMPONENT-666;Lo;0;L;;;;;N;;;;;\n18A9A;TANGUT COMPONENT-667;Lo;0;L;;;;;N;;;;;\n18A9B;TANGUT COMPONENT-668;Lo;0;L;;;;;N;;;;;\n18A9C;TANGUT COMPONENT-669;Lo;0;L;;;;;N;;;;;\n18A9D;TANGUT COMPONENT-670;Lo;0;L;;;;;N;;;;;\n18A9E;TANGUT COMPONENT-671;Lo;0;L;;;;;N;;;;;\n18A9F;TANGUT COMPONENT-672;Lo;0;L;;;;;N;;;;;\n18AA0;TANGUT COMPONENT-673;Lo;0;L;;;;;N;;;;;\n18AA1;TANGUT COMPONENT-674;Lo;0;L;;;;;N;;;;;\n18AA2;TANGUT COMPONENT-675;Lo;0;L;;;;;N;;;;;\n18AA3;TANGUT COMPONENT-676;Lo;0;L;;;;;N;;;;;\n18AA4;TANGUT COMPONENT-677;Lo;0;L;;;;;N;;;;;\n18AA5;TANGUT COMPONENT-678;Lo;0;L;;;;;N;;;;;\n18AA6;TANGUT COMPONENT-679;Lo;0;L;;;;;N;;;;;\n18AA7;TANGUT COMPONENT-680;Lo;0;L;;;;;N;;;;;\n18AA8;TANGUT COMPONENT-681;Lo;0;L;;;;;N;;;;;\n18AA9;TANGUT COMPONENT-682;Lo;0;L;;;;;N;;;;;\n18AAA;TANGUT COMPONENT-683;Lo;0;L;;;;;N;;;;;\n18AAB;TANGUT COMPONENT-684;Lo;0;L;;;;;N;;;;;\n18AAC;TANGUT COMPONENT-685;Lo;0;L;;;;;N;;;;;\n18AAD;TANGUT COMPONENT-686;Lo;0;L;;;;;N;;;;;\n18AAE;TANGUT COMPONENT-687;Lo;0;L;;;;;N;;;;;\n18AAF;TANGUT COMPONENT-688;Lo;0;L;;;;;N;;;;;\n18AB0;TANGUT COMPONENT-689;Lo;0;L;;;;;N;;;;;\n18AB1;TANGUT COMPONENT-690;Lo;0;L;;;;;N;;;;;\n18AB2;TANGUT COMPONENT-691;Lo;0;L;;;;;N;;;;;\n18AB3;TANGUT COMPONENT-692;Lo;0;L;;;;;N;;;;;\n18AB4;TANGUT COMPONENT-693;Lo;0;L;;;;;N;;;;;\n18AB5;TANGUT COMPONENT-694;Lo;0;L;;;;;N;;;;;\n18AB6;TANGUT COMPONENT-695;Lo;0;L;;;;;N;;;;;\n18AB7;TANGUT COMPONENT-696;Lo;0;L;;;;;N;;;;;\n18AB8;TANGUT COMPONENT-697;Lo;0;L;;;;;N;;;;;\n18AB9;TANGUT COMPONENT-698;Lo;0;L;;;;;N;;;;;\n18ABA;TANGUT COMPONENT-699;Lo;0;L;;;;;N;;;;;\n18ABB;TANGUT COMPONENT-700;Lo;0;L;;;;;N;;;;;\n18ABC;TANGUT COMPONENT-701;Lo;0;L;;;;;N;;;;;\n18ABD;TANGUT COMPONENT-702;Lo;0;L;;;;;N;;;;;\n18ABE;TANGUT COMPONENT-703;Lo;0;L;;;;;N;;;;;\n18ABF;TANGUT COMPONENT-704;Lo;0;L;;;;;N;;;;;\n18AC0;TANGUT COMPONENT-705;Lo;0;L;;;;;N;;;;;\n18AC1;TANGUT COMPONENT-706;Lo;0;L;;;;;N;;;;;\n18AC2;TANGUT COMPONENT-707;Lo;0;L;;;;;N;;;;;\n18AC3;TANGUT COMPONENT-708;Lo;0;L;;;;;N;;;;;\n18AC4;TANGUT COMPONENT-709;Lo;0;L;;;;;N;;;;;\n18AC5;TANGUT COMPONENT-710;Lo;0;L;;;;;N;;;;;\n18AC6;TANGUT COMPONENT-711;Lo;0;L;;;;;N;;;;;\n18AC7;TANGUT COMPONENT-712;Lo;0;L;;;;;N;;;;;\n18AC8;TANGUT COMPONENT-713;Lo;0;L;;;;;N;;;;;\n18AC9;TANGUT COMPONENT-714;Lo;0;L;;;;;N;;;;;\n18ACA;TANGUT COMPONENT-715;Lo;0;L;;;;;N;;;;;\n18ACB;TANGUT COMPONENT-716;Lo;0;L;;;;;N;;;;;\n18ACC;TANGUT COMPONENT-717;Lo;0;L;;;;;N;;;;;\n18ACD;TANGUT COMPONENT-718;Lo;0;L;;;;;N;;;;;\n18ACE;TANGUT COMPONENT-719;Lo;0;L;;;;;N;;;;;\n18ACF;TANGUT COMPONENT-720;Lo;0;L;;;;;N;;;;;\n18AD0;TANGUT COMPONENT-721;Lo;0;L;;;;;N;;;;;\n18AD1;TANGUT COMPONENT-722;Lo;0;L;;;;;N;;;;;\n18AD2;TANGUT COMPONENT-723;Lo;0;L;;;;;N;;;;;\n18AD3;TANGUT COMPONENT-724;Lo;0;L;;;;;N;;;;;\n18AD4;TANGUT COMPONENT-725;Lo;0;L;;;;;N;;;;;\n18AD5;TANGUT COMPONENT-726;Lo;0;L;;;;;N;;;;;\n18AD6;TANGUT COMPONENT-727;Lo;0;L;;;;;N;;;;;\n18AD7;TANGUT COMPONENT-728;Lo;0;L;;;;;N;;;;;\n18AD8;TANGUT COMPONENT-729;Lo;0;L;;;;;N;;;;;\n18AD9;TANGUT COMPONENT-730;Lo;0;L;;;;;N;;;;;\n18ADA;TANGUT COMPONENT-731;Lo;0;L;;;;;N;;;;;\n18ADB;TANGUT COMPONENT-732;Lo;0;L;;;;;N;;;;;\n18ADC;TANGUT COMPONENT-733;Lo;0;L;;;;;N;;;;;\n18ADD;TANGUT COMPONENT-734;Lo;0;L;;;;;N;;;;;\n18ADE;TANGUT COMPONENT-735;Lo;0;L;;;;;N;;;;;\n18ADF;TANGUT COMPONENT-736;Lo;0;L;;;;;N;;;;;\n18AE0;TANGUT COMPONENT-737;Lo;0;L;;;;;N;;;;;\n18AE1;TANGUT COMPONENT-738;Lo;0;L;;;;;N;;;;;\n18AE2;TANGUT COMPONENT-739;Lo;0;L;;;;;N;;;;;\n18AE3;TANGUT COMPONENT-740;Lo;0;L;;;;;N;;;;;\n18AE4;TANGUT COMPONENT-741;Lo;0;L;;;;;N;;;;;\n18AE5;TANGUT COMPONENT-742;Lo;0;L;;;;;N;;;;;\n18AE6;TANGUT COMPONENT-743;Lo;0;L;;;;;N;;;;;\n18AE7;TANGUT COMPONENT-744;Lo;0;L;;;;;N;;;;;\n18AE8;TANGUT COMPONENT-745;Lo;0;L;;;;;N;;;;;\n18AE9;TANGUT COMPONENT-746;Lo;0;L;;;;;N;;;;;\n18AEA;TANGUT COMPONENT-747;Lo;0;L;;;;;N;;;;;\n18AEB;TANGUT COMPONENT-748;Lo;0;L;;;;;N;;;;;\n18AEC;TANGUT COMPONENT-749;Lo;0;L;;;;;N;;;;;\n18AED;TANGUT COMPONENT-750;Lo;0;L;;;;;N;;;;;\n18AEE;TANGUT COMPONENT-751;Lo;0;L;;;;;N;;;;;\n18AEF;TANGUT COMPONENT-752;Lo;0;L;;;;;N;;;;;\n18AF0;TANGUT COMPONENT-753;Lo;0;L;;;;;N;;;;;\n18AF1;TANGUT COMPONENT-754;Lo;0;L;;;;;N;;;;;\n18AF2;TANGUT COMPONENT-755;Lo;0;L;;;;;N;;;;;\n18AF3;TANGUT COMPONENT-756;Lo;0;L;;;;;N;;;;;\n18AF4;TANGUT COMPONENT-757;Lo;0;L;;;;;N;;;;;\n18AF5;TANGUT COMPONENT-758;Lo;0;L;;;;;N;;;;;\n18AF6;TANGUT COMPONENT-759;Lo;0;L;;;;;N;;;;;\n18AF7;TANGUT COMPONENT-760;Lo;0;L;;;;;N;;;;;\n18AF8;TANGUT COMPONENT-761;Lo;0;L;;;;;N;;;;;\n18AF9;TANGUT COMPONENT-762;Lo;0;L;;;;;N;;;;;\n18AFA;TANGUT COMPONENT-763;Lo;0;L;;;;;N;;;;;\n18AFB;TANGUT COMPONENT-764;Lo;0;L;;;;;N;;;;;\n18AFC;TANGUT COMPONENT-765;Lo;0;L;;;;;N;;;;;\n18AFD;TANGUT COMPONENT-766;Lo;0;L;;;;;N;;;;;\n18AFE;TANGUT COMPONENT-767;Lo;0;L;;;;;N;;;;;\n18AFF;TANGUT COMPONENT-768;Lo;0;L;;;;;N;;;;;\n18B00;KHITAN SMALL SCRIPT CHARACTER-18B00;Lo;0;L;;;;;N;;;;;\n18B01;KHITAN SMALL SCRIPT CHARACTER-18B01;Lo;0;L;;;;;N;;;;;\n18B02;KHITAN SMALL SCRIPT CHARACTER-18B02;Lo;0;L;;;;;N;;;;;\n18B03;KHITAN SMALL SCRIPT CHARACTER-18B03;Lo;0;L;;;;;N;;;;;\n18B04;KHITAN SMALL SCRIPT CHARACTER-18B04;Lo;0;L;;;;;N;;;;;\n18B05;KHITAN SMALL SCRIPT CHARACTER-18B05;Lo;0;L;;;;;N;;;;;\n18B06;KHITAN SMALL SCRIPT CHARACTER-18B06;Lo;0;L;;;;;N;;;;;\n18B07;KHITAN SMALL SCRIPT CHARACTER-18B07;Lo;0;L;;;;;N;;;;;\n18B08;KHITAN SMALL SCRIPT CHARACTER-18B08;Lo;0;L;;;;;N;;;;;\n18B09;KHITAN SMALL SCRIPT CHARACTER-18B09;Lo;0;L;;;;;N;;;;;\n18B0A;KHITAN SMALL SCRIPT CHARACTER-18B0A;Lo;0;L;;;;;N;;;;;\n18B0B;KHITAN SMALL SCRIPT CHARACTER-18B0B;Lo;0;L;;;;;N;;;;;\n18B0C;KHITAN SMALL SCRIPT CHARACTER-18B0C;Lo;0;L;;;;;N;;;;;\n18B0D;KHITAN SMALL SCRIPT CHARACTER-18B0D;Lo;0;L;;;;;N;;;;;\n18B0E;KHITAN SMALL SCRIPT CHARACTER-18B0E;Lo;0;L;;;;;N;;;;;\n18B0F;KHITAN SMALL SCRIPT CHARACTER-18B0F;Lo;0;L;;;;;N;;;;;\n18B10;KHITAN SMALL SCRIPT CHARACTER-18B10;Lo;0;L;;;;;N;;;;;\n18B11;KHITAN SMALL SCRIPT CHARACTER-18B11;Lo;0;L;;;;;N;;;;;\n18B12;KHITAN SMALL SCRIPT CHARACTER-18B12;Lo;0;L;;;;;N;;;;;\n18B13;KHITAN SMALL SCRIPT CHARACTER-18B13;Lo;0;L;;;;;N;;;;;\n18B14;KHITAN SMALL SCRIPT CHARACTER-18B14;Lo;0;L;;;;;N;;;;;\n18B15;KHITAN SMALL SCRIPT CHARACTER-18B15;Lo;0;L;;;;;N;;;;;\n18B16;KHITAN SMALL SCRIPT CHARACTER-18B16;Lo;0;L;;;;;N;;;;;\n18B17;KHITAN SMALL SCRIPT CHARACTER-18B17;Lo;0;L;;;;;N;;;;;\n18B18;KHITAN SMALL SCRIPT CHARACTER-18B18;Lo;0;L;;;;;N;;;;;\n18B19;KHITAN SMALL SCRIPT CHARACTER-18B19;Lo;0;L;;;;;N;;;;;\n18B1A;KHITAN SMALL SCRIPT CHARACTER-18B1A;Lo;0;L;;;;;N;;;;;\n18B1B;KHITAN SMALL SCRIPT CHARACTER-18B1B;Lo;0;L;;;;;N;;;;;\n18B1C;KHITAN SMALL SCRIPT CHARACTER-18B1C;Lo;0;L;;;;;N;;;;;\n18B1D;KHITAN SMALL SCRIPT CHARACTER-18B1D;Lo;0;L;;;;;N;;;;;\n18B1E;KHITAN SMALL SCRIPT CHARACTER-18B1E;Lo;0;L;;;;;N;;;;;\n18B1F;KHITAN SMALL SCRIPT CHARACTER-18B1F;Lo;0;L;;;;;N;;;;;\n18B20;KHITAN SMALL SCRIPT CHARACTER-18B20;Lo;0;L;;;;;N;;;;;\n18B21;KHITAN SMALL SCRIPT CHARACTER-18B21;Lo;0;L;;;;;N;;;;;\n18B22;KHITAN SMALL SCRIPT CHARACTER-18B22;Lo;0;L;;;;;N;;;;;\n18B23;KHITAN SMALL SCRIPT CHARACTER-18B23;Lo;0;L;;;;;N;;;;;\n18B24;KHITAN SMALL SCRIPT CHARACTER-18B24;Lo;0;L;;;;;N;;;;;\n18B25;KHITAN SMALL SCRIPT CHARACTER-18B25;Lo;0;L;;;;;N;;;;;\n18B26;KHITAN SMALL SCRIPT CHARACTER-18B26;Lo;0;L;;;;;N;;;;;\n18B27;KHITAN SMALL SCRIPT CHARACTER-18B27;Lo;0;L;;;;;N;;;;;\n18B28;KHITAN SMALL SCRIPT CHARACTER-18B28;Lo;0;L;;;;;N;;;;;\n18B29;KHITAN SMALL SCRIPT CHARACTER-18B29;Lo;0;L;;;;;N;;;;;\n18B2A;KHITAN SMALL SCRIPT CHARACTER-18B2A;Lo;0;L;;;;;N;;;;;\n18B2B;KHITAN SMALL SCRIPT CHARACTER-18B2B;Lo;0;L;;;;;N;;;;;\n18B2C;KHITAN SMALL SCRIPT CHARACTER-18B2C;Lo;0;L;;;;;N;;;;;\n18B2D;KHITAN SMALL SCRIPT CHARACTER-18B2D;Lo;0;L;;;;;N;;;;;\n18B2E;KHITAN SMALL SCRIPT CHARACTER-18B2E;Lo;0;L;;;;;N;;;;;\n18B2F;KHITAN SMALL SCRIPT CHARACTER-18B2F;Lo;0;L;;;;;N;;;;;\n18B30;KHITAN SMALL SCRIPT CHARACTER-18B30;Lo;0;L;;;;;N;;;;;\n18B31;KHITAN SMALL SCRIPT CHARACTER-18B31;Lo;0;L;;;;;N;;;;;\n18B32;KHITAN SMALL SCRIPT CHARACTER-18B32;Lo;0;L;;;;;N;;;;;\n18B33;KHITAN SMALL SCRIPT CHARACTER-18B33;Lo;0;L;;;;;N;;;;;\n18B34;KHITAN SMALL SCRIPT CHARACTER-18B34;Lo;0;L;;;;;N;;;;;\n18B35;KHITAN SMALL SCRIPT CHARACTER-18B35;Lo;0;L;;;;;N;;;;;\n18B36;KHITAN SMALL SCRIPT CHARACTER-18B36;Lo;0;L;;;;;N;;;;;\n18B37;KHITAN SMALL SCRIPT CHARACTER-18B37;Lo;0;L;;;;;N;;;;;\n18B38;KHITAN SMALL SCRIPT CHARACTER-18B38;Lo;0;L;;;;;N;;;;;\n18B39;KHITAN SMALL SCRIPT CHARACTER-18B39;Lo;0;L;;;;;N;;;;;\n18B3A;KHITAN SMALL SCRIPT CHARACTER-18B3A;Lo;0;L;;;;;N;;;;;\n18B3B;KHITAN SMALL SCRIPT CHARACTER-18B3B;Lo;0;L;;;;;N;;;;;\n18B3C;KHITAN SMALL SCRIPT CHARACTER-18B3C;Lo;0;L;;;;;N;;;;;\n18B3D;KHITAN SMALL SCRIPT CHARACTER-18B3D;Lo;0;L;;;;;N;;;;;\n18B3E;KHITAN SMALL SCRIPT CHARACTER-18B3E;Lo;0;L;;;;;N;;;;;\n18B3F;KHITAN SMALL SCRIPT CHARACTER-18B3F;Lo;0;L;;;;;N;;;;;\n18B40;KHITAN SMALL SCRIPT CHARACTER-18B40;Lo;0;L;;;;;N;;;;;\n18B41;KHITAN SMALL SCRIPT CHARACTER-18B41;Lo;0;L;;;;;N;;;;;\n18B42;KHITAN SMALL SCRIPT CHARACTER-18B42;Lo;0;L;;;;;N;;;;;\n18B43;KHITAN SMALL SCRIPT CHARACTER-18B43;Lo;0;L;;;;;N;;;;;\n18B44;KHITAN SMALL SCRIPT CHARACTER-18B44;Lo;0;L;;;;;N;;;;;\n18B45;KHITAN SMALL SCRIPT CHARACTER-18B45;Lo;0;L;;;;;N;;;;;\n18B46;KHITAN SMALL SCRIPT CHARACTER-18B46;Lo;0;L;;;;;N;;;;;\n18B47;KHITAN SMALL SCRIPT CHARACTER-18B47;Lo;0;L;;;;;N;;;;;\n18B48;KHITAN SMALL SCRIPT CHARACTER-18B48;Lo;0;L;;;;;N;;;;;\n18B49;KHITAN SMALL SCRIPT CHARACTER-18B49;Lo;0;L;;;;;N;;;;;\n18B4A;KHITAN SMALL SCRIPT CHARACTER-18B4A;Lo;0;L;;;;;N;;;;;\n18B4B;KHITAN SMALL SCRIPT CHARACTER-18B4B;Lo;0;L;;;;;N;;;;;\n18B4C;KHITAN SMALL SCRIPT CHARACTER-18B4C;Lo;0;L;;;;;N;;;;;\n18B4D;KHITAN SMALL SCRIPT CHARACTER-18B4D;Lo;0;L;;;;;N;;;;;\n18B4E;KHITAN SMALL SCRIPT CHARACTER-18B4E;Lo;0;L;;;;;N;;;;;\n18B4F;KHITAN SMALL SCRIPT CHARACTER-18B4F;Lo;0;L;;;;;N;;;;;\n18B50;KHITAN SMALL SCRIPT CHARACTER-18B50;Lo;0;L;;;;;N;;;;;\n18B51;KHITAN SMALL SCRIPT CHARACTER-18B51;Lo;0;L;;;;;N;;;;;\n18B52;KHITAN SMALL SCRIPT CHARACTER-18B52;Lo;0;L;;;;;N;;;;;\n18B53;KHITAN SMALL SCRIPT CHARACTER-18B53;Lo;0;L;;;;;N;;;;;\n18B54;KHITAN SMALL SCRIPT CHARACTER-18B54;Lo;0;L;;;;;N;;;;;\n18B55;KHITAN SMALL SCRIPT CHARACTER-18B55;Lo;0;L;;;;;N;;;;;\n18B56;KHITAN SMALL SCRIPT CHARACTER-18B56;Lo;0;L;;;;;N;;;;;\n18B57;KHITAN SMALL SCRIPT CHARACTER-18B57;Lo;0;L;;;;;N;;;;;\n18B58;KHITAN SMALL SCRIPT CHARACTER-18B58;Lo;0;L;;;;;N;;;;;\n18B59;KHITAN SMALL SCRIPT CHARACTER-18B59;Lo;0;L;;;;;N;;;;;\n18B5A;KHITAN SMALL SCRIPT CHARACTER-18B5A;Lo;0;L;;;;;N;;;;;\n18B5B;KHITAN SMALL SCRIPT CHARACTER-18B5B;Lo;0;L;;;;;N;;;;;\n18B5C;KHITAN SMALL SCRIPT CHARACTER-18B5C;Lo;0;L;;;;;N;;;;;\n18B5D;KHITAN SMALL SCRIPT CHARACTER-18B5D;Lo;0;L;;;;;N;;;;;\n18B5E;KHITAN SMALL SCRIPT CHARACTER-18B5E;Lo;0;L;;;;;N;;;;;\n18B5F;KHITAN SMALL SCRIPT CHARACTER-18B5F;Lo;0;L;;;;;N;;;;;\n18B60;KHITAN SMALL SCRIPT CHARACTER-18B60;Lo;0;L;;;;;N;;;;;\n18B61;KHITAN SMALL SCRIPT CHARACTER-18B61;Lo;0;L;;;;;N;;;;;\n18B62;KHITAN SMALL SCRIPT CHARACTER-18B62;Lo;0;L;;;;;N;;;;;\n18B63;KHITAN SMALL SCRIPT CHARACTER-18B63;Lo;0;L;;;;;N;;;;;\n18B64;KHITAN SMALL SCRIPT CHARACTER-18B64;Lo;0;L;;;;;N;;;;;\n18B65;KHITAN SMALL SCRIPT CHARACTER-18B65;Lo;0;L;;;;;N;;;;;\n18B66;KHITAN SMALL SCRIPT CHARACTER-18B66;Lo;0;L;;;;;N;;;;;\n18B67;KHITAN SMALL SCRIPT CHARACTER-18B67;Lo;0;L;;;;;N;;;;;\n18B68;KHITAN SMALL SCRIPT CHARACTER-18B68;Lo;0;L;;;;;N;;;;;\n18B69;KHITAN SMALL SCRIPT CHARACTER-18B69;Lo;0;L;;;;;N;;;;;\n18B6A;KHITAN SMALL SCRIPT CHARACTER-18B6A;Lo;0;L;;;;;N;;;;;\n18B6B;KHITAN SMALL SCRIPT CHARACTER-18B6B;Lo;0;L;;;;;N;;;;;\n18B6C;KHITAN SMALL SCRIPT CHARACTER-18B6C;Lo;0;L;;;;;N;;;;;\n18B6D;KHITAN SMALL SCRIPT CHARACTER-18B6D;Lo;0;L;;;;;N;;;;;\n18B6E;KHITAN SMALL SCRIPT CHARACTER-18B6E;Lo;0;L;;;;;N;;;;;\n18B6F;KHITAN SMALL SCRIPT CHARACTER-18B6F;Lo;0;L;;;;;N;;;;;\n18B70;KHITAN SMALL SCRIPT CHARACTER-18B70;Lo;0;L;;;;;N;;;;;\n18B71;KHITAN SMALL SCRIPT CHARACTER-18B71;Lo;0;L;;;;;N;;;;;\n18B72;KHITAN SMALL SCRIPT CHARACTER-18B72;Lo;0;L;;;;;N;;;;;\n18B73;KHITAN SMALL SCRIPT CHARACTER-18B73;Lo;0;L;;;;;N;;;;;\n18B74;KHITAN SMALL SCRIPT CHARACTER-18B74;Lo;0;L;;;;;N;;;;;\n18B75;KHITAN SMALL SCRIPT CHARACTER-18B75;Lo;0;L;;;;;N;;;;;\n18B76;KHITAN SMALL SCRIPT CHARACTER-18B76;Lo;0;L;;;;;N;;;;;\n18B77;KHITAN SMALL SCRIPT CHARACTER-18B77;Lo;0;L;;;;;N;;;;;\n18B78;KHITAN SMALL SCRIPT CHARACTER-18B78;Lo;0;L;;;;;N;;;;;\n18B79;KHITAN SMALL SCRIPT CHARACTER-18B79;Lo;0;L;;;;;N;;;;;\n18B7A;KHITAN SMALL SCRIPT CHARACTER-18B7A;Lo;0;L;;;;;N;;;;;\n18B7B;KHITAN SMALL SCRIPT CHARACTER-18B7B;Lo;0;L;;;;;N;;;;;\n18B7C;KHITAN SMALL SCRIPT CHARACTER-18B7C;Lo;0;L;;;;;N;;;;;\n18B7D;KHITAN SMALL SCRIPT CHARACTER-18B7D;Lo;0;L;;;;;N;;;;;\n18B7E;KHITAN SMALL SCRIPT CHARACTER-18B7E;Lo;0;L;;;;;N;;;;;\n18B7F;KHITAN SMALL SCRIPT CHARACTER-18B7F;Lo;0;L;;;;;N;;;;;\n18B80;KHITAN SMALL SCRIPT CHARACTER-18B80;Lo;0;L;;;;;N;;;;;\n18B81;KHITAN SMALL SCRIPT CHARACTER-18B81;Lo;0;L;;;;;N;;;;;\n18B82;KHITAN SMALL SCRIPT CHARACTER-18B82;Lo;0;L;;;;;N;;;;;\n18B83;KHITAN SMALL SCRIPT CHARACTER-18B83;Lo;0;L;;;;;N;;;;;\n18B84;KHITAN SMALL SCRIPT CHARACTER-18B84;Lo;0;L;;;;;N;;;;;\n18B85;KHITAN SMALL SCRIPT CHARACTER-18B85;Lo;0;L;;;;;N;;;;;\n18B86;KHITAN SMALL SCRIPT CHARACTER-18B86;Lo;0;L;;;;;N;;;;;\n18B87;KHITAN SMALL SCRIPT CHARACTER-18B87;Lo;0;L;;;;;N;;;;;\n18B88;KHITAN SMALL SCRIPT CHARACTER-18B88;Lo;0;L;;;;;N;;;;;\n18B89;KHITAN SMALL SCRIPT CHARACTER-18B89;Lo;0;L;;;;;N;;;;;\n18B8A;KHITAN SMALL SCRIPT CHARACTER-18B8A;Lo;0;L;;;;;N;;;;;\n18B8B;KHITAN SMALL SCRIPT CHARACTER-18B8B;Lo;0;L;;;;;N;;;;;\n18B8C;KHITAN SMALL SCRIPT CHARACTER-18B8C;Lo;0;L;;;;;N;;;;;\n18B8D;KHITAN SMALL SCRIPT CHARACTER-18B8D;Lo;0;L;;;;;N;;;;;\n18B8E;KHITAN SMALL SCRIPT CHARACTER-18B8E;Lo;0;L;;;;;N;;;;;\n18B8F;KHITAN SMALL SCRIPT CHARACTER-18B8F;Lo;0;L;;;;;N;;;;;\n18B90;KHITAN SMALL SCRIPT CHARACTER-18B90;Lo;0;L;;;;;N;;;;;\n18B91;KHITAN SMALL SCRIPT CHARACTER-18B91;Lo;0;L;;;;;N;;;;;\n18B92;KHITAN SMALL SCRIPT CHARACTER-18B92;Lo;0;L;;;;;N;;;;;\n18B93;KHITAN SMALL SCRIPT CHARACTER-18B93;Lo;0;L;;;;;N;;;;;\n18B94;KHITAN SMALL SCRIPT CHARACTER-18B94;Lo;0;L;;;;;N;;;;;\n18B95;KHITAN SMALL SCRIPT CHARACTER-18B95;Lo;0;L;;;;;N;;;;;\n18B96;KHITAN SMALL SCRIPT CHARACTER-18B96;Lo;0;L;;;;;N;;;;;\n18B97;KHITAN SMALL SCRIPT CHARACTER-18B97;Lo;0;L;;;;;N;;;;;\n18B98;KHITAN SMALL SCRIPT CHARACTER-18B98;Lo;0;L;;;;;N;;;;;\n18B99;KHITAN SMALL SCRIPT CHARACTER-18B99;Lo;0;L;;;;;N;;;;;\n18B9A;KHITAN SMALL SCRIPT CHARACTER-18B9A;Lo;0;L;;;;;N;;;;;\n18B9B;KHITAN SMALL SCRIPT CHARACTER-18B9B;Lo;0;L;;;;;N;;;;;\n18B9C;KHITAN SMALL SCRIPT CHARACTER-18B9C;Lo;0;L;;;;;N;;;;;\n18B9D;KHITAN SMALL SCRIPT CHARACTER-18B9D;Lo;0;L;;;;;N;;;;;\n18B9E;KHITAN SMALL SCRIPT CHARACTER-18B9E;Lo;0;L;;;;;N;;;;;\n18B9F;KHITAN SMALL SCRIPT CHARACTER-18B9F;Lo;0;L;;;;;N;;;;;\n18BA0;KHITAN SMALL SCRIPT CHARACTER-18BA0;Lo;0;L;;;;;N;;;;;\n18BA1;KHITAN SMALL SCRIPT CHARACTER-18BA1;Lo;0;L;;;;;N;;;;;\n18BA2;KHITAN SMALL SCRIPT CHARACTER-18BA2;Lo;0;L;;;;;N;;;;;\n18BA3;KHITAN SMALL SCRIPT CHARACTER-18BA3;Lo;0;L;;;;;N;;;;;\n18BA4;KHITAN SMALL SCRIPT CHARACTER-18BA4;Lo;0;L;;;;;N;;;;;\n18BA5;KHITAN SMALL SCRIPT CHARACTER-18BA5;Lo;0;L;;;;;N;;;;;\n18BA6;KHITAN SMALL SCRIPT CHARACTER-18BA6;Lo;0;L;;;;;N;;;;;\n18BA7;KHITAN SMALL SCRIPT CHARACTER-18BA7;Lo;0;L;;;;;N;;;;;\n18BA8;KHITAN SMALL SCRIPT CHARACTER-18BA8;Lo;0;L;;;;;N;;;;;\n18BA9;KHITAN SMALL SCRIPT CHARACTER-18BA9;Lo;0;L;;;;;N;;;;;\n18BAA;KHITAN SMALL SCRIPT CHARACTER-18BAA;Lo;0;L;;;;;N;;;;;\n18BAB;KHITAN SMALL SCRIPT CHARACTER-18BAB;Lo;0;L;;;;;N;;;;;\n18BAC;KHITAN SMALL SCRIPT CHARACTER-18BAC;Lo;0;L;;;;;N;;;;;\n18BAD;KHITAN SMALL SCRIPT CHARACTER-18BAD;Lo;0;L;;;;;N;;;;;\n18BAE;KHITAN SMALL SCRIPT CHARACTER-18BAE;Lo;0;L;;;;;N;;;;;\n18BAF;KHITAN SMALL SCRIPT CHARACTER-18BAF;Lo;0;L;;;;;N;;;;;\n18BB0;KHITAN SMALL SCRIPT CHARACTER-18BB0;Lo;0;L;;;;;N;;;;;\n18BB1;KHITAN SMALL SCRIPT CHARACTER-18BB1;Lo;0;L;;;;;N;;;;;\n18BB2;KHITAN SMALL SCRIPT CHARACTER-18BB2;Lo;0;L;;;;;N;;;;;\n18BB3;KHITAN SMALL SCRIPT CHARACTER-18BB3;Lo;0;L;;;;;N;;;;;\n18BB4;KHITAN SMALL SCRIPT CHARACTER-18BB4;Lo;0;L;;;;;N;;;;;\n18BB5;KHITAN SMALL SCRIPT CHARACTER-18BB5;Lo;0;L;;;;;N;;;;;\n18BB6;KHITAN SMALL SCRIPT CHARACTER-18BB6;Lo;0;L;;;;;N;;;;;\n18BB7;KHITAN SMALL SCRIPT CHARACTER-18BB7;Lo;0;L;;;;;N;;;;;\n18BB8;KHITAN SMALL SCRIPT CHARACTER-18BB8;Lo;0;L;;;;;N;;;;;\n18BB9;KHITAN SMALL SCRIPT CHARACTER-18BB9;Lo;0;L;;;;;N;;;;;\n18BBA;KHITAN SMALL SCRIPT CHARACTER-18BBA;Lo;0;L;;;;;N;;;;;\n18BBB;KHITAN SMALL SCRIPT CHARACTER-18BBB;Lo;0;L;;;;;N;;;;;\n18BBC;KHITAN SMALL SCRIPT CHARACTER-18BBC;Lo;0;L;;;;;N;;;;;\n18BBD;KHITAN SMALL SCRIPT CHARACTER-18BBD;Lo;0;L;;;;;N;;;;;\n18BBE;KHITAN SMALL SCRIPT CHARACTER-18BBE;Lo;0;L;;;;;N;;;;;\n18BBF;KHITAN SMALL SCRIPT CHARACTER-18BBF;Lo;0;L;;;;;N;;;;;\n18BC0;KHITAN SMALL SCRIPT CHARACTER-18BC0;Lo;0;L;;;;;N;;;;;\n18BC1;KHITAN SMALL SCRIPT CHARACTER-18BC1;Lo;0;L;;;;;N;;;;;\n18BC2;KHITAN SMALL SCRIPT CHARACTER-18BC2;Lo;0;L;;;;;N;;;;;\n18BC3;KHITAN SMALL SCRIPT CHARACTER-18BC3;Lo;0;L;;;;;N;;;;;\n18BC4;KHITAN SMALL SCRIPT CHARACTER-18BC4;Lo;0;L;;;;;N;;;;;\n18BC5;KHITAN SMALL SCRIPT CHARACTER-18BC5;Lo;0;L;;;;;N;;;;;\n18BC6;KHITAN SMALL SCRIPT CHARACTER-18BC6;Lo;0;L;;;;;N;;;;;\n18BC7;KHITAN SMALL SCRIPT CHARACTER-18BC7;Lo;0;L;;;;;N;;;;;\n18BC8;KHITAN SMALL SCRIPT CHARACTER-18BC8;Lo;0;L;;;;;N;;;;;\n18BC9;KHITAN SMALL SCRIPT CHARACTER-18BC9;Lo;0;L;;;;;N;;;;;\n18BCA;KHITAN SMALL SCRIPT CHARACTER-18BCA;Lo;0;L;;;;;N;;;;;\n18BCB;KHITAN SMALL SCRIPT CHARACTER-18BCB;Lo;0;L;;;;;N;;;;;\n18BCC;KHITAN SMALL SCRIPT CHARACTER-18BCC;Lo;0;L;;;;;N;;;;;\n18BCD;KHITAN SMALL SCRIPT CHARACTER-18BCD;Lo;0;L;;;;;N;;;;;\n18BCE;KHITAN SMALL SCRIPT CHARACTER-18BCE;Lo;0;L;;;;;N;;;;;\n18BCF;KHITAN SMALL SCRIPT CHARACTER-18BCF;Lo;0;L;;;;;N;;;;;\n18BD0;KHITAN SMALL SCRIPT CHARACTER-18BD0;Lo;0;L;;;;;N;;;;;\n18BD1;KHITAN SMALL SCRIPT CHARACTER-18BD1;Lo;0;L;;;;;N;;;;;\n18BD2;KHITAN SMALL SCRIPT CHARACTER-18BD2;Lo;0;L;;;;;N;;;;;\n18BD3;KHITAN SMALL SCRIPT CHARACTER-18BD3;Lo;0;L;;;;;N;;;;;\n18BD4;KHITAN SMALL SCRIPT CHARACTER-18BD4;Lo;0;L;;;;;N;;;;;\n18BD5;KHITAN SMALL SCRIPT CHARACTER-18BD5;Lo;0;L;;;;;N;;;;;\n18BD6;KHITAN SMALL SCRIPT CHARACTER-18BD6;Lo;0;L;;;;;N;;;;;\n18BD7;KHITAN SMALL SCRIPT CHARACTER-18BD7;Lo;0;L;;;;;N;;;;;\n18BD8;KHITAN SMALL SCRIPT CHARACTER-18BD8;Lo;0;L;;;;;N;;;;;\n18BD9;KHITAN SMALL SCRIPT CHARACTER-18BD9;Lo;0;L;;;;;N;;;;;\n18BDA;KHITAN SMALL SCRIPT CHARACTER-18BDA;Lo;0;L;;;;;N;;;;;\n18BDB;KHITAN SMALL SCRIPT CHARACTER-18BDB;Lo;0;L;;;;;N;;;;;\n18BDC;KHITAN SMALL SCRIPT CHARACTER-18BDC;Lo;0;L;;;;;N;;;;;\n18BDD;KHITAN SMALL SCRIPT CHARACTER-18BDD;Lo;0;L;;;;;N;;;;;\n18BDE;KHITAN SMALL SCRIPT CHARACTER-18BDE;Lo;0;L;;;;;N;;;;;\n18BDF;KHITAN SMALL SCRIPT CHARACTER-18BDF;Lo;0;L;;;;;N;;;;;\n18BE0;KHITAN SMALL SCRIPT CHARACTER-18BE0;Lo;0;L;;;;;N;;;;;\n18BE1;KHITAN SMALL SCRIPT CHARACTER-18BE1;Lo;0;L;;;;;N;;;;;\n18BE2;KHITAN SMALL SCRIPT CHARACTER-18BE2;Lo;0;L;;;;;N;;;;;\n18BE3;KHITAN SMALL SCRIPT CHARACTER-18BE3;Lo;0;L;;;;;N;;;;;\n18BE4;KHITAN SMALL SCRIPT CHARACTER-18BE4;Lo;0;L;;;;;N;;;;;\n18BE5;KHITAN SMALL SCRIPT CHARACTER-18BE5;Lo;0;L;;;;;N;;;;;\n18BE6;KHITAN SMALL SCRIPT CHARACTER-18BE6;Lo;0;L;;;;;N;;;;;\n18BE7;KHITAN SMALL SCRIPT CHARACTER-18BE7;Lo;0;L;;;;;N;;;;;\n18BE8;KHITAN SMALL SCRIPT CHARACTER-18BE8;Lo;0;L;;;;;N;;;;;\n18BE9;KHITAN SMALL SCRIPT CHARACTER-18BE9;Lo;0;L;;;;;N;;;;;\n18BEA;KHITAN SMALL SCRIPT CHARACTER-18BEA;Lo;0;L;;;;;N;;;;;\n18BEB;KHITAN SMALL SCRIPT CHARACTER-18BEB;Lo;0;L;;;;;N;;;;;\n18BEC;KHITAN SMALL SCRIPT CHARACTER-18BEC;Lo;0;L;;;;;N;;;;;\n18BED;KHITAN SMALL SCRIPT CHARACTER-18BED;Lo;0;L;;;;;N;;;;;\n18BEE;KHITAN SMALL SCRIPT CHARACTER-18BEE;Lo;0;L;;;;;N;;;;;\n18BEF;KHITAN SMALL SCRIPT CHARACTER-18BEF;Lo;0;L;;;;;N;;;;;\n18BF0;KHITAN SMALL SCRIPT CHARACTER-18BF0;Lo;0;L;;;;;N;;;;;\n18BF1;KHITAN SMALL SCRIPT CHARACTER-18BF1;Lo;0;L;;;;;N;;;;;\n18BF2;KHITAN SMALL SCRIPT CHARACTER-18BF2;Lo;0;L;;;;;N;;;;;\n18BF3;KHITAN SMALL SCRIPT CHARACTER-18BF3;Lo;0;L;;;;;N;;;;;\n18BF4;KHITAN SMALL SCRIPT CHARACTER-18BF4;Lo;0;L;;;;;N;;;;;\n18BF5;KHITAN SMALL SCRIPT CHARACTER-18BF5;Lo;0;L;;;;;N;;;;;\n18BF6;KHITAN SMALL SCRIPT CHARACTER-18BF6;Lo;0;L;;;;;N;;;;;\n18BF7;KHITAN SMALL SCRIPT CHARACTER-18BF7;Lo;0;L;;;;;N;;;;;\n18BF8;KHITAN SMALL SCRIPT CHARACTER-18BF8;Lo;0;L;;;;;N;;;;;\n18BF9;KHITAN SMALL SCRIPT CHARACTER-18BF9;Lo;0;L;;;;;N;;;;;\n18BFA;KHITAN SMALL SCRIPT CHARACTER-18BFA;Lo;0;L;;;;;N;;;;;\n18BFB;KHITAN SMALL SCRIPT CHARACTER-18BFB;Lo;0;L;;;;;N;;;;;\n18BFC;KHITAN SMALL SCRIPT CHARACTER-18BFC;Lo;0;L;;;;;N;;;;;\n18BFD;KHITAN SMALL SCRIPT CHARACTER-18BFD;Lo;0;L;;;;;N;;;;;\n18BFE;KHITAN SMALL SCRIPT CHARACTER-18BFE;Lo;0;L;;;;;N;;;;;\n18BFF;KHITAN SMALL SCRIPT CHARACTER-18BFF;Lo;0;L;;;;;N;;;;;\n18C00;KHITAN SMALL SCRIPT CHARACTER-18C00;Lo;0;L;;;;;N;;;;;\n18C01;KHITAN SMALL SCRIPT CHARACTER-18C01;Lo;0;L;;;;;N;;;;;\n18C02;KHITAN SMALL SCRIPT CHARACTER-18C02;Lo;0;L;;;;;N;;;;;\n18C03;KHITAN SMALL SCRIPT CHARACTER-18C03;Lo;0;L;;;;;N;;;;;\n18C04;KHITAN SMALL SCRIPT CHARACTER-18C04;Lo;0;L;;;;;N;;;;;\n18C05;KHITAN SMALL SCRIPT CHARACTER-18C05;Lo;0;L;;;;;N;;;;;\n18C06;KHITAN SMALL SCRIPT CHARACTER-18C06;Lo;0;L;;;;;N;;;;;\n18C07;KHITAN SMALL SCRIPT CHARACTER-18C07;Lo;0;L;;;;;N;;;;;\n18C08;KHITAN SMALL SCRIPT CHARACTER-18C08;Lo;0;L;;;;;N;;;;;\n18C09;KHITAN SMALL SCRIPT CHARACTER-18C09;Lo;0;L;;;;;N;;;;;\n18C0A;KHITAN SMALL SCRIPT CHARACTER-18C0A;Lo;0;L;;;;;N;;;;;\n18C0B;KHITAN SMALL SCRIPT CHARACTER-18C0B;Lo;0;L;;;;;N;;;;;\n18C0C;KHITAN SMALL SCRIPT CHARACTER-18C0C;Lo;0;L;;;;;N;;;;;\n18C0D;KHITAN SMALL SCRIPT CHARACTER-18C0D;Lo;0;L;;;;;N;;;;;\n18C0E;KHITAN SMALL SCRIPT CHARACTER-18C0E;Lo;0;L;;;;;N;;;;;\n18C0F;KHITAN SMALL SCRIPT CHARACTER-18C0F;Lo;0;L;;;;;N;;;;;\n18C10;KHITAN SMALL SCRIPT CHARACTER-18C10;Lo;0;L;;;;;N;;;;;\n18C11;KHITAN SMALL SCRIPT CHARACTER-18C11;Lo;0;L;;;;;N;;;;;\n18C12;KHITAN SMALL SCRIPT CHARACTER-18C12;Lo;0;L;;;;;N;;;;;\n18C13;KHITAN SMALL SCRIPT CHARACTER-18C13;Lo;0;L;;;;;N;;;;;\n18C14;KHITAN SMALL SCRIPT CHARACTER-18C14;Lo;0;L;;;;;N;;;;;\n18C15;KHITAN SMALL SCRIPT CHARACTER-18C15;Lo;0;L;;;;;N;;;;;\n18C16;KHITAN SMALL SCRIPT CHARACTER-18C16;Lo;0;L;;;;;N;;;;;\n18C17;KHITAN SMALL SCRIPT CHARACTER-18C17;Lo;0;L;;;;;N;;;;;\n18C18;KHITAN SMALL SCRIPT CHARACTER-18C18;Lo;0;L;;;;;N;;;;;\n18C19;KHITAN SMALL SCRIPT CHARACTER-18C19;Lo;0;L;;;;;N;;;;;\n18C1A;KHITAN SMALL SCRIPT CHARACTER-18C1A;Lo;0;L;;;;;N;;;;;\n18C1B;KHITAN SMALL SCRIPT CHARACTER-18C1B;Lo;0;L;;;;;N;;;;;\n18C1C;KHITAN SMALL SCRIPT CHARACTER-18C1C;Lo;0;L;;;;;N;;;;;\n18C1D;KHITAN SMALL SCRIPT CHARACTER-18C1D;Lo;0;L;;;;;N;;;;;\n18C1E;KHITAN SMALL SCRIPT CHARACTER-18C1E;Lo;0;L;;;;;N;;;;;\n18C1F;KHITAN SMALL SCRIPT CHARACTER-18C1F;Lo;0;L;;;;;N;;;;;\n18C20;KHITAN SMALL SCRIPT CHARACTER-18C20;Lo;0;L;;;;;N;;;;;\n18C21;KHITAN SMALL SCRIPT CHARACTER-18C21;Lo;0;L;;;;;N;;;;;\n18C22;KHITAN SMALL SCRIPT CHARACTER-18C22;Lo;0;L;;;;;N;;;;;\n18C23;KHITAN SMALL SCRIPT CHARACTER-18C23;Lo;0;L;;;;;N;;;;;\n18C24;KHITAN SMALL SCRIPT CHARACTER-18C24;Lo;0;L;;;;;N;;;;;\n18C25;KHITAN SMALL SCRIPT CHARACTER-18C25;Lo;0;L;;;;;N;;;;;\n18C26;KHITAN SMALL SCRIPT CHARACTER-18C26;Lo;0;L;;;;;N;;;;;\n18C27;KHITAN SMALL SCRIPT CHARACTER-18C27;Lo;0;L;;;;;N;;;;;\n18C28;KHITAN SMALL SCRIPT CHARACTER-18C28;Lo;0;L;;;;;N;;;;;\n18C29;KHITAN SMALL SCRIPT CHARACTER-18C29;Lo;0;L;;;;;N;;;;;\n18C2A;KHITAN SMALL SCRIPT CHARACTER-18C2A;Lo;0;L;;;;;N;;;;;\n18C2B;KHITAN SMALL SCRIPT CHARACTER-18C2B;Lo;0;L;;;;;N;;;;;\n18C2C;KHITAN SMALL SCRIPT CHARACTER-18C2C;Lo;0;L;;;;;N;;;;;\n18C2D;KHITAN SMALL SCRIPT CHARACTER-18C2D;Lo;0;L;;;;;N;;;;;\n18C2E;KHITAN SMALL SCRIPT CHARACTER-18C2E;Lo;0;L;;;;;N;;;;;\n18C2F;KHITAN SMALL SCRIPT CHARACTER-18C2F;Lo;0;L;;;;;N;;;;;\n18C30;KHITAN SMALL SCRIPT CHARACTER-18C30;Lo;0;L;;;;;N;;;;;\n18C31;KHITAN SMALL SCRIPT CHARACTER-18C31;Lo;0;L;;;;;N;;;;;\n18C32;KHITAN SMALL SCRIPT CHARACTER-18C32;Lo;0;L;;;;;N;;;;;\n18C33;KHITAN SMALL SCRIPT CHARACTER-18C33;Lo;0;L;;;;;N;;;;;\n18C34;KHITAN SMALL SCRIPT CHARACTER-18C34;Lo;0;L;;;;;N;;;;;\n18C35;KHITAN SMALL SCRIPT CHARACTER-18C35;Lo;0;L;;;;;N;;;;;\n18C36;KHITAN SMALL SCRIPT CHARACTER-18C36;Lo;0;L;;;;;N;;;;;\n18C37;KHITAN SMALL SCRIPT CHARACTER-18C37;Lo;0;L;;;;;N;;;;;\n18C38;KHITAN SMALL SCRIPT CHARACTER-18C38;Lo;0;L;;;;;N;;;;;\n18C39;KHITAN SMALL SCRIPT CHARACTER-18C39;Lo;0;L;;;;;N;;;;;\n18C3A;KHITAN SMALL SCRIPT CHARACTER-18C3A;Lo;0;L;;;;;N;;;;;\n18C3B;KHITAN SMALL SCRIPT CHARACTER-18C3B;Lo;0;L;;;;;N;;;;;\n18C3C;KHITAN SMALL SCRIPT CHARACTER-18C3C;Lo;0;L;;;;;N;;;;;\n18C3D;KHITAN SMALL SCRIPT CHARACTER-18C3D;Lo;0;L;;;;;N;;;;;\n18C3E;KHITAN SMALL SCRIPT CHARACTER-18C3E;Lo;0;L;;;;;N;;;;;\n18C3F;KHITAN SMALL SCRIPT CHARACTER-18C3F;Lo;0;L;;;;;N;;;;;\n18C40;KHITAN SMALL SCRIPT CHARACTER-18C40;Lo;0;L;;;;;N;;;;;\n18C41;KHITAN SMALL SCRIPT CHARACTER-18C41;Lo;0;L;;;;;N;;;;;\n18C42;KHITAN SMALL SCRIPT CHARACTER-18C42;Lo;0;L;;;;;N;;;;;\n18C43;KHITAN SMALL SCRIPT CHARACTER-18C43;Lo;0;L;;;;;N;;;;;\n18C44;KHITAN SMALL SCRIPT CHARACTER-18C44;Lo;0;L;;;;;N;;;;;\n18C45;KHITAN SMALL SCRIPT CHARACTER-18C45;Lo;0;L;;;;;N;;;;;\n18C46;KHITAN SMALL SCRIPT CHARACTER-18C46;Lo;0;L;;;;;N;;;;;\n18C47;KHITAN SMALL SCRIPT CHARACTER-18C47;Lo;0;L;;;;;N;;;;;\n18C48;KHITAN SMALL SCRIPT CHARACTER-18C48;Lo;0;L;;;;;N;;;;;\n18C49;KHITAN SMALL SCRIPT CHARACTER-18C49;Lo;0;L;;;;;N;;;;;\n18C4A;KHITAN SMALL SCRIPT CHARACTER-18C4A;Lo;0;L;;;;;N;;;;;\n18C4B;KHITAN SMALL SCRIPT CHARACTER-18C4B;Lo;0;L;;;;;N;;;;;\n18C4C;KHITAN SMALL SCRIPT CHARACTER-18C4C;Lo;0;L;;;;;N;;;;;\n18C4D;KHITAN SMALL SCRIPT CHARACTER-18C4D;Lo;0;L;;;;;N;;;;;\n18C4E;KHITAN SMALL SCRIPT CHARACTER-18C4E;Lo;0;L;;;;;N;;;;;\n18C4F;KHITAN SMALL SCRIPT CHARACTER-18C4F;Lo;0;L;;;;;N;;;;;\n18C50;KHITAN SMALL SCRIPT CHARACTER-18C50;Lo;0;L;;;;;N;;;;;\n18C51;KHITAN SMALL SCRIPT CHARACTER-18C51;Lo;0;L;;;;;N;;;;;\n18C52;KHITAN SMALL SCRIPT CHARACTER-18C52;Lo;0;L;;;;;N;;;;;\n18C53;KHITAN SMALL SCRIPT CHARACTER-18C53;Lo;0;L;;;;;N;;;;;\n18C54;KHITAN SMALL SCRIPT CHARACTER-18C54;Lo;0;L;;;;;N;;;;;\n18C55;KHITAN SMALL SCRIPT CHARACTER-18C55;Lo;0;L;;;;;N;;;;;\n18C56;KHITAN SMALL SCRIPT CHARACTER-18C56;Lo;0;L;;;;;N;;;;;\n18C57;KHITAN SMALL SCRIPT CHARACTER-18C57;Lo;0;L;;;;;N;;;;;\n18C58;KHITAN SMALL SCRIPT CHARACTER-18C58;Lo;0;L;;;;;N;;;;;\n18C59;KHITAN SMALL SCRIPT CHARACTER-18C59;Lo;0;L;;;;;N;;;;;\n18C5A;KHITAN SMALL SCRIPT CHARACTER-18C5A;Lo;0;L;;;;;N;;;;;\n18C5B;KHITAN SMALL SCRIPT CHARACTER-18C5B;Lo;0;L;;;;;N;;;;;\n18C5C;KHITAN SMALL SCRIPT CHARACTER-18C5C;Lo;0;L;;;;;N;;;;;\n18C5D;KHITAN SMALL SCRIPT CHARACTER-18C5D;Lo;0;L;;;;;N;;;;;\n18C5E;KHITAN SMALL SCRIPT CHARACTER-18C5E;Lo;0;L;;;;;N;;;;;\n18C5F;KHITAN SMALL SCRIPT CHARACTER-18C5F;Lo;0;L;;;;;N;;;;;\n18C60;KHITAN SMALL SCRIPT CHARACTER-18C60;Lo;0;L;;;;;N;;;;;\n18C61;KHITAN SMALL SCRIPT CHARACTER-18C61;Lo;0;L;;;;;N;;;;;\n18C62;KHITAN SMALL SCRIPT CHARACTER-18C62;Lo;0;L;;;;;N;;;;;\n18C63;KHITAN SMALL SCRIPT CHARACTER-18C63;Lo;0;L;;;;;N;;;;;\n18C64;KHITAN SMALL SCRIPT CHARACTER-18C64;Lo;0;L;;;;;N;;;;;\n18C65;KHITAN SMALL SCRIPT CHARACTER-18C65;Lo;0;L;;;;;N;;;;;\n18C66;KHITAN SMALL SCRIPT CHARACTER-18C66;Lo;0;L;;;;;N;;;;;\n18C67;KHITAN SMALL SCRIPT CHARACTER-18C67;Lo;0;L;;;;;N;;;;;\n18C68;KHITAN SMALL SCRIPT CHARACTER-18C68;Lo;0;L;;;;;N;;;;;\n18C69;KHITAN SMALL SCRIPT CHARACTER-18C69;Lo;0;L;;;;;N;;;;;\n18C6A;KHITAN SMALL SCRIPT CHARACTER-18C6A;Lo;0;L;;;;;N;;;;;\n18C6B;KHITAN SMALL SCRIPT CHARACTER-18C6B;Lo;0;L;;;;;N;;;;;\n18C6C;KHITAN SMALL SCRIPT CHARACTER-18C6C;Lo;0;L;;;;;N;;;;;\n18C6D;KHITAN SMALL SCRIPT CHARACTER-18C6D;Lo;0;L;;;;;N;;;;;\n18C6E;KHITAN SMALL SCRIPT CHARACTER-18C6E;Lo;0;L;;;;;N;;;;;\n18C6F;KHITAN SMALL SCRIPT CHARACTER-18C6F;Lo;0;L;;;;;N;;;;;\n18C70;KHITAN SMALL SCRIPT CHARACTER-18C70;Lo;0;L;;;;;N;;;;;\n18C71;KHITAN SMALL SCRIPT CHARACTER-18C71;Lo;0;L;;;;;N;;;;;\n18C72;KHITAN SMALL SCRIPT CHARACTER-18C72;Lo;0;L;;;;;N;;;;;\n18C73;KHITAN SMALL SCRIPT CHARACTER-18C73;Lo;0;L;;;;;N;;;;;\n18C74;KHITAN SMALL SCRIPT CHARACTER-18C74;Lo;0;L;;;;;N;;;;;\n18C75;KHITAN SMALL SCRIPT CHARACTER-18C75;Lo;0;L;;;;;N;;;;;\n18C76;KHITAN SMALL SCRIPT CHARACTER-18C76;Lo;0;L;;;;;N;;;;;\n18C77;KHITAN SMALL SCRIPT CHARACTER-18C77;Lo;0;L;;;;;N;;;;;\n18C78;KHITAN SMALL SCRIPT CHARACTER-18C78;Lo;0;L;;;;;N;;;;;\n18C79;KHITAN SMALL SCRIPT CHARACTER-18C79;Lo;0;L;;;;;N;;;;;\n18C7A;KHITAN SMALL SCRIPT CHARACTER-18C7A;Lo;0;L;;;;;N;;;;;\n18C7B;KHITAN SMALL SCRIPT CHARACTER-18C7B;Lo;0;L;;;;;N;;;;;\n18C7C;KHITAN SMALL SCRIPT CHARACTER-18C7C;Lo;0;L;;;;;N;;;;;\n18C7D;KHITAN SMALL SCRIPT CHARACTER-18C7D;Lo;0;L;;;;;N;;;;;\n18C7E;KHITAN SMALL SCRIPT CHARACTER-18C7E;Lo;0;L;;;;;N;;;;;\n18C7F;KHITAN SMALL SCRIPT CHARACTER-18C7F;Lo;0;L;;;;;N;;;;;\n18C80;KHITAN SMALL SCRIPT CHARACTER-18C80;Lo;0;L;;;;;N;;;;;\n18C81;KHITAN SMALL SCRIPT CHARACTER-18C81;Lo;0;L;;;;;N;;;;;\n18C82;KHITAN SMALL SCRIPT CHARACTER-18C82;Lo;0;L;;;;;N;;;;;\n18C83;KHITAN SMALL SCRIPT CHARACTER-18C83;Lo;0;L;;;;;N;;;;;\n18C84;KHITAN SMALL SCRIPT CHARACTER-18C84;Lo;0;L;;;;;N;;;;;\n18C85;KHITAN SMALL SCRIPT CHARACTER-18C85;Lo;0;L;;;;;N;;;;;\n18C86;KHITAN SMALL SCRIPT CHARACTER-18C86;Lo;0;L;;;;;N;;;;;\n18C87;KHITAN SMALL SCRIPT CHARACTER-18C87;Lo;0;L;;;;;N;;;;;\n18C88;KHITAN SMALL SCRIPT CHARACTER-18C88;Lo;0;L;;;;;N;;;;;\n18C89;KHITAN SMALL SCRIPT CHARACTER-18C89;Lo;0;L;;;;;N;;;;;\n18C8A;KHITAN SMALL SCRIPT CHARACTER-18C8A;Lo;0;L;;;;;N;;;;;\n18C8B;KHITAN SMALL SCRIPT CHARACTER-18C8B;Lo;0;L;;;;;N;;;;;\n18C8C;KHITAN SMALL SCRIPT CHARACTER-18C8C;Lo;0;L;;;;;N;;;;;\n18C8D;KHITAN SMALL SCRIPT CHARACTER-18C8D;Lo;0;L;;;;;N;;;;;\n18C8E;KHITAN SMALL SCRIPT CHARACTER-18C8E;Lo;0;L;;;;;N;;;;;\n18C8F;KHITAN SMALL SCRIPT CHARACTER-18C8F;Lo;0;L;;;;;N;;;;;\n18C90;KHITAN SMALL SCRIPT CHARACTER-18C90;Lo;0;L;;;;;N;;;;;\n18C91;KHITAN SMALL SCRIPT CHARACTER-18C91;Lo;0;L;;;;;N;;;;;\n18C92;KHITAN SMALL SCRIPT CHARACTER-18C92;Lo;0;L;;;;;N;;;;;\n18C93;KHITAN SMALL SCRIPT CHARACTER-18C93;Lo;0;L;;;;;N;;;;;\n18C94;KHITAN SMALL SCRIPT CHARACTER-18C94;Lo;0;L;;;;;N;;;;;\n18C95;KHITAN SMALL SCRIPT CHARACTER-18C95;Lo;0;L;;;;;N;;;;;\n18C96;KHITAN SMALL SCRIPT CHARACTER-18C96;Lo;0;L;;;;;N;;;;;\n18C97;KHITAN SMALL SCRIPT CHARACTER-18C97;Lo;0;L;;;;;N;;;;;\n18C98;KHITAN SMALL SCRIPT CHARACTER-18C98;Lo;0;L;;;;;N;;;;;\n18C99;KHITAN SMALL SCRIPT CHARACTER-18C99;Lo;0;L;;;;;N;;;;;\n18C9A;KHITAN SMALL SCRIPT CHARACTER-18C9A;Lo;0;L;;;;;N;;;;;\n18C9B;KHITAN SMALL SCRIPT CHARACTER-18C9B;Lo;0;L;;;;;N;;;;;\n18C9C;KHITAN SMALL SCRIPT CHARACTER-18C9C;Lo;0;L;;;;;N;;;;;\n18C9D;KHITAN SMALL SCRIPT CHARACTER-18C9D;Lo;0;L;;;;;N;;;;;\n18C9E;KHITAN SMALL SCRIPT CHARACTER-18C9E;Lo;0;L;;;;;N;;;;;\n18C9F;KHITAN SMALL SCRIPT CHARACTER-18C9F;Lo;0;L;;;;;N;;;;;\n18CA0;KHITAN SMALL SCRIPT CHARACTER-18CA0;Lo;0;L;;;;;N;;;;;\n18CA1;KHITAN SMALL SCRIPT CHARACTER-18CA1;Lo;0;L;;;;;N;;;;;\n18CA2;KHITAN SMALL SCRIPT CHARACTER-18CA2;Lo;0;L;;;;;N;;;;;\n18CA3;KHITAN SMALL SCRIPT CHARACTER-18CA3;Lo;0;L;;;;;N;;;;;\n18CA4;KHITAN SMALL SCRIPT CHARACTER-18CA4;Lo;0;L;;;;;N;;;;;\n18CA5;KHITAN SMALL SCRIPT CHARACTER-18CA5;Lo;0;L;;;;;N;;;;;\n18CA6;KHITAN SMALL SCRIPT CHARACTER-18CA6;Lo;0;L;;;;;N;;;;;\n18CA7;KHITAN SMALL SCRIPT CHARACTER-18CA7;Lo;0;L;;;;;N;;;;;\n18CA8;KHITAN SMALL SCRIPT CHARACTER-18CA8;Lo;0;L;;;;;N;;;;;\n18CA9;KHITAN SMALL SCRIPT CHARACTER-18CA9;Lo;0;L;;;;;N;;;;;\n18CAA;KHITAN SMALL SCRIPT CHARACTER-18CAA;Lo;0;L;;;;;N;;;;;\n18CAB;KHITAN SMALL SCRIPT CHARACTER-18CAB;Lo;0;L;;;;;N;;;;;\n18CAC;KHITAN SMALL SCRIPT CHARACTER-18CAC;Lo;0;L;;;;;N;;;;;\n18CAD;KHITAN SMALL SCRIPT CHARACTER-18CAD;Lo;0;L;;;;;N;;;;;\n18CAE;KHITAN SMALL SCRIPT CHARACTER-18CAE;Lo;0;L;;;;;N;;;;;\n18CAF;KHITAN SMALL SCRIPT CHARACTER-18CAF;Lo;0;L;;;;;N;;;;;\n18CB0;KHITAN SMALL SCRIPT CHARACTER-18CB0;Lo;0;L;;;;;N;;;;;\n18CB1;KHITAN SMALL SCRIPT CHARACTER-18CB1;Lo;0;L;;;;;N;;;;;\n18CB2;KHITAN SMALL SCRIPT CHARACTER-18CB2;Lo;0;L;;;;;N;;;;;\n18CB3;KHITAN SMALL SCRIPT CHARACTER-18CB3;Lo;0;L;;;;;N;;;;;\n18CB4;KHITAN SMALL SCRIPT CHARACTER-18CB4;Lo;0;L;;;;;N;;;;;\n18CB5;KHITAN SMALL SCRIPT CHARACTER-18CB5;Lo;0;L;;;;;N;;;;;\n18CB6;KHITAN SMALL SCRIPT CHARACTER-18CB6;Lo;0;L;;;;;N;;;;;\n18CB7;KHITAN SMALL SCRIPT CHARACTER-18CB7;Lo;0;L;;;;;N;;;;;\n18CB8;KHITAN SMALL SCRIPT CHARACTER-18CB8;Lo;0;L;;;;;N;;;;;\n18CB9;KHITAN SMALL SCRIPT CHARACTER-18CB9;Lo;0;L;;;;;N;;;;;\n18CBA;KHITAN SMALL SCRIPT CHARACTER-18CBA;Lo;0;L;;;;;N;;;;;\n18CBB;KHITAN SMALL SCRIPT CHARACTER-18CBB;Lo;0;L;;;;;N;;;;;\n18CBC;KHITAN SMALL SCRIPT CHARACTER-18CBC;Lo;0;L;;;;;N;;;;;\n18CBD;KHITAN SMALL SCRIPT CHARACTER-18CBD;Lo;0;L;;;;;N;;;;;\n18CBE;KHITAN SMALL SCRIPT CHARACTER-18CBE;Lo;0;L;;;;;N;;;;;\n18CBF;KHITAN SMALL SCRIPT CHARACTER-18CBF;Lo;0;L;;;;;N;;;;;\n18CC0;KHITAN SMALL SCRIPT CHARACTER-18CC0;Lo;0;L;;;;;N;;;;;\n18CC1;KHITAN SMALL SCRIPT CHARACTER-18CC1;Lo;0;L;;;;;N;;;;;\n18CC2;KHITAN SMALL SCRIPT CHARACTER-18CC2;Lo;0;L;;;;;N;;;;;\n18CC3;KHITAN SMALL SCRIPT CHARACTER-18CC3;Lo;0;L;;;;;N;;;;;\n18CC4;KHITAN SMALL SCRIPT CHARACTER-18CC4;Lo;0;L;;;;;N;;;;;\n18CC5;KHITAN SMALL SCRIPT CHARACTER-18CC5;Lo;0;L;;;;;N;;;;;\n18CC6;KHITAN SMALL SCRIPT CHARACTER-18CC6;Lo;0;L;;;;;N;;;;;\n18CC7;KHITAN SMALL SCRIPT CHARACTER-18CC7;Lo;0;L;;;;;N;;;;;\n18CC8;KHITAN SMALL SCRIPT CHARACTER-18CC8;Lo;0;L;;;;;N;;;;;\n18CC9;KHITAN SMALL SCRIPT CHARACTER-18CC9;Lo;0;L;;;;;N;;;;;\n18CCA;KHITAN SMALL SCRIPT CHARACTER-18CCA;Lo;0;L;;;;;N;;;;;\n18CCB;KHITAN SMALL SCRIPT CHARACTER-18CCB;Lo;0;L;;;;;N;;;;;\n18CCC;KHITAN SMALL SCRIPT CHARACTER-18CCC;Lo;0;L;;;;;N;;;;;\n18CCD;KHITAN SMALL SCRIPT CHARACTER-18CCD;Lo;0;L;;;;;N;;;;;\n18CCE;KHITAN SMALL SCRIPT CHARACTER-18CCE;Lo;0;L;;;;;N;;;;;\n18CCF;KHITAN SMALL SCRIPT CHARACTER-18CCF;Lo;0;L;;;;;N;;;;;\n18CD0;KHITAN SMALL SCRIPT CHARACTER-18CD0;Lo;0;L;;;;;N;;;;;\n18CD1;KHITAN SMALL SCRIPT CHARACTER-18CD1;Lo;0;L;;;;;N;;;;;\n18CD2;KHITAN SMALL SCRIPT CHARACTER-18CD2;Lo;0;L;;;;;N;;;;;\n18CD3;KHITAN SMALL SCRIPT CHARACTER-18CD3;Lo;0;L;;;;;N;;;;;\n18CD4;KHITAN SMALL SCRIPT CHARACTER-18CD4;Lo;0;L;;;;;N;;;;;\n18CD5;KHITAN SMALL SCRIPT CHARACTER-18CD5;Lo;0;L;;;;;N;;;;;\n18CFF;KHITAN SMALL SCRIPT CHARACTER-18CFF;Lo;0;L;;;;;N;;;;;\n18D00;<Tangut Ideograph Supplement, First>;Lo;0;L;;;;;N;;;;;\n18D1E;<Tangut Ideograph Supplement, Last>;Lo;0;L;;;;;N;;;;;\n18D80;TANGUT COMPONENT-769;Lo;0;L;;;;;N;;;;;\n18D81;TANGUT COMPONENT-770;Lo;0;L;;;;;N;;;;;\n18D82;TANGUT COMPONENT-771;Lo;0;L;;;;;N;;;;;\n18D83;TANGUT COMPONENT-772;Lo;0;L;;;;;N;;;;;\n18D84;TANGUT COMPONENT-773;Lo;0;L;;;;;N;;;;;\n18D85;TANGUT COMPONENT-774;Lo;0;L;;;;;N;;;;;\n18D86;TANGUT COMPONENT-775;Lo;0;L;;;;;N;;;;;\n18D87;TANGUT COMPONENT-776;Lo;0;L;;;;;N;;;;;\n18D88;TANGUT COMPONENT-777;Lo;0;L;;;;;N;;;;;\n18D89;TANGUT COMPONENT-778;Lo;0;L;;;;;N;;;;;\n18D8A;TANGUT COMPONENT-779;Lo;0;L;;;;;N;;;;;\n18D8B;TANGUT COMPONENT-780;Lo;0;L;;;;;N;;;;;\n18D8C;TANGUT COMPONENT-781;Lo;0;L;;;;;N;;;;;\n18D8D;TANGUT COMPONENT-782;Lo;0;L;;;;;N;;;;;\n18D8E;TANGUT COMPONENT-783;Lo;0;L;;;;;N;;;;;\n18D8F;TANGUT COMPONENT-784;Lo;0;L;;;;;N;;;;;\n18D90;TANGUT COMPONENT-785;Lo;0;L;;;;;N;;;;;\n18D91;TANGUT COMPONENT-786;Lo;0;L;;;;;N;;;;;\n18D92;TANGUT COMPONENT-787;Lo;0;L;;;;;N;;;;;\n18D93;TANGUT COMPONENT-788;Lo;0;L;;;;;N;;;;;\n18D94;TANGUT COMPONENT-789;Lo;0;L;;;;;N;;;;;\n18D95;TANGUT COMPONENT-790;Lo;0;L;;;;;N;;;;;\n18D96;TANGUT COMPONENT-791;Lo;0;L;;;;;N;;;;;\n18D97;TANGUT COMPONENT-792;Lo;0;L;;;;;N;;;;;\n18D98;TANGUT COMPONENT-793;Lo;0;L;;;;;N;;;;;\n18D99;TANGUT COMPONENT-794;Lo;0;L;;;;;N;;;;;\n18D9A;TANGUT COMPONENT-795;Lo;0;L;;;;;N;;;;;\n18D9B;TANGUT COMPONENT-796;Lo;0;L;;;;;N;;;;;\n18D9C;TANGUT COMPONENT-797;Lo;0;L;;;;;N;;;;;\n18D9D;TANGUT COMPONENT-798;Lo;0;L;;;;;N;;;;;\n18D9E;TANGUT COMPONENT-799;Lo;0;L;;;;;N;;;;;\n18D9F;TANGUT COMPONENT-800;Lo;0;L;;;;;N;;;;;\n18DA0;TANGUT COMPONENT-801;Lo;0;L;;;;;N;;;;;\n18DA1;TANGUT COMPONENT-802;Lo;0;L;;;;;N;;;;;\n18DA2;TANGUT COMPONENT-803;Lo;0;L;;;;;N;;;;;\n18DA3;TANGUT COMPONENT-804;Lo;0;L;;;;;N;;;;;\n18DA4;TANGUT COMPONENT-805;Lo;0;L;;;;;N;;;;;\n18DA5;TANGUT COMPONENT-806;Lo;0;L;;;;;N;;;;;\n18DA6;TANGUT COMPONENT-807;Lo;0;L;;;;;N;;;;;\n18DA7;TANGUT COMPONENT-808;Lo;0;L;;;;;N;;;;;\n18DA8;TANGUT COMPONENT-809;Lo;0;L;;;;;N;;;;;\n18DA9;TANGUT COMPONENT-810;Lo;0;L;;;;;N;;;;;\n18DAA;TANGUT COMPONENT-811;Lo;0;L;;;;;N;;;;;\n18DAB;TANGUT COMPONENT-812;Lo;0;L;;;;;N;;;;;\n18DAC;TANGUT COMPONENT-813;Lo;0;L;;;;;N;;;;;\n18DAD;TANGUT COMPONENT-814;Lo;0;L;;;;;N;;;;;\n18DAE;TANGUT COMPONENT-815;Lo;0;L;;;;;N;;;;;\n18DAF;TANGUT COMPONENT-816;Lo;0;L;;;;;N;;;;;\n18DB0;TANGUT COMPONENT-817;Lo;0;L;;;;;N;;;;;\n18DB1;TANGUT COMPONENT-818;Lo;0;L;;;;;N;;;;;\n18DB2;TANGUT COMPONENT-819;Lo;0;L;;;;;N;;;;;\n18DB3;TANGUT COMPONENT-820;Lo;0;L;;;;;N;;;;;\n18DB4;TANGUT COMPONENT-821;Lo;0;L;;;;;N;;;;;\n18DB5;TANGUT COMPONENT-822;Lo;0;L;;;;;N;;;;;\n18DB6;TANGUT COMPONENT-823;Lo;0;L;;;;;N;;;;;\n18DB7;TANGUT COMPONENT-824;Lo;0;L;;;;;N;;;;;\n18DB8;TANGUT COMPONENT-825;Lo;0;L;;;;;N;;;;;\n18DB9;TANGUT COMPONENT-826;Lo;0;L;;;;;N;;;;;\n18DBA;TANGUT COMPONENT-827;Lo;0;L;;;;;N;;;;;\n18DBB;TANGUT COMPONENT-828;Lo;0;L;;;;;N;;;;;\n18DBC;TANGUT COMPONENT-829;Lo;0;L;;;;;N;;;;;\n18DBD;TANGUT COMPONENT-830;Lo;0;L;;;;;N;;;;;\n18DBE;TANGUT COMPONENT-831;Lo;0;L;;;;;N;;;;;\n18DBF;TANGUT COMPONENT-832;Lo;0;L;;;;;N;;;;;\n18DC0;TANGUT COMPONENT-833;Lo;0;L;;;;;N;;;;;\n18DC1;TANGUT COMPONENT-834;Lo;0;L;;;;;N;;;;;\n18DC2;TANGUT COMPONENT-835;Lo;0;L;;;;;N;;;;;\n18DC3;TANGUT COMPONENT-836;Lo;0;L;;;;;N;;;;;\n18DC4;TANGUT COMPONENT-837;Lo;0;L;;;;;N;;;;;\n18DC5;TANGUT COMPONENT-838;Lo;0;L;;;;;N;;;;;\n18DC6;TANGUT COMPONENT-839;Lo;0;L;;;;;N;;;;;\n18DC7;TANGUT COMPONENT-840;Lo;0;L;;;;;N;;;;;\n18DC8;TANGUT COMPONENT-841;Lo;0;L;;;;;N;;;;;\n18DC9;TANGUT COMPONENT-842;Lo;0;L;;;;;N;;;;;\n18DCA;TANGUT COMPONENT-843;Lo;0;L;;;;;N;;;;;\n18DCB;TANGUT COMPONENT-844;Lo;0;L;;;;;N;;;;;\n18DCC;TANGUT COMPONENT-845;Lo;0;L;;;;;N;;;;;\n18DCD;TANGUT COMPONENT-846;Lo;0;L;;;;;N;;;;;\n18DCE;TANGUT COMPONENT-847;Lo;0;L;;;;;N;;;;;\n18DCF;TANGUT COMPONENT-848;Lo;0;L;;;;;N;;;;;\n18DD0;TANGUT COMPONENT-849;Lo;0;L;;;;;N;;;;;\n18DD1;TANGUT COMPONENT-850;Lo;0;L;;;;;N;;;;;\n18DD2;TANGUT COMPONENT-851;Lo;0;L;;;;;N;;;;;\n18DD3;TANGUT COMPONENT-852;Lo;0;L;;;;;N;;;;;\n18DD4;TANGUT COMPONENT-853;Lo;0;L;;;;;N;;;;;\n18DD5;TANGUT COMPONENT-854;Lo;0;L;;;;;N;;;;;\n18DD6;TANGUT COMPONENT-855;Lo;0;L;;;;;N;;;;;\n18DD7;TANGUT COMPONENT-856;Lo;0;L;;;;;N;;;;;\n18DD8;TANGUT COMPONENT-857;Lo;0;L;;;;;N;;;;;\n18DD9;TANGUT COMPONENT-858;Lo;0;L;;;;;N;;;;;\n18DDA;TANGUT COMPONENT-859;Lo;0;L;;;;;N;;;;;\n18DDB;TANGUT COMPONENT-860;Lo;0;L;;;;;N;;;;;\n18DDC;TANGUT COMPONENT-861;Lo;0;L;;;;;N;;;;;\n18DDD;TANGUT COMPONENT-862;Lo;0;L;;;;;N;;;;;\n18DDE;TANGUT COMPONENT-863;Lo;0;L;;;;;N;;;;;\n18DDF;TANGUT COMPONENT-864;Lo;0;L;;;;;N;;;;;\n18DE0;TANGUT COMPONENT-865;Lo;0;L;;;;;N;;;;;\n18DE1;TANGUT COMPONENT-866;Lo;0;L;;;;;N;;;;;\n18DE2;TANGUT COMPONENT-867;Lo;0;L;;;;;N;;;;;\n18DE3;TANGUT COMPONENT-868;Lo;0;L;;;;;N;;;;;\n18DE4;TANGUT COMPONENT-869;Lo;0;L;;;;;N;;;;;\n18DE5;TANGUT COMPONENT-870;Lo;0;L;;;;;N;;;;;\n18DE6;TANGUT COMPONENT-871;Lo;0;L;;;;;N;;;;;\n18DE7;TANGUT COMPONENT-872;Lo;0;L;;;;;N;;;;;\n18DE8;TANGUT COMPONENT-873;Lo;0;L;;;;;N;;;;;\n18DE9;TANGUT COMPONENT-874;Lo;0;L;;;;;N;;;;;\n18DEA;TANGUT COMPONENT-875;Lo;0;L;;;;;N;;;;;\n18DEB;TANGUT COMPONENT-876;Lo;0;L;;;;;N;;;;;\n18DEC;TANGUT COMPONENT-877;Lo;0;L;;;;;N;;;;;\n18DED;TANGUT COMPONENT-878;Lo;0;L;;;;;N;;;;;\n18DEE;TANGUT COMPONENT-879;Lo;0;L;;;;;N;;;;;\n18DEF;TANGUT COMPONENT-880;Lo;0;L;;;;;N;;;;;\n18DF0;TANGUT COMPONENT-881;Lo;0;L;;;;;N;;;;;\n18DF1;TANGUT COMPONENT-882;Lo;0;L;;;;;N;;;;;\n18DF2;TANGUT COMPONENT-883;Lo;0;L;;;;;N;;;;;\n1AFF0;KATAKANA LETTER MINNAN TONE-2;Lm;0;L;;;;;N;;;;;\n1AFF1;KATAKANA LETTER MINNAN TONE-3;Lm;0;L;;;;;N;;;;;\n1AFF2;KATAKANA LETTER MINNAN TONE-4;Lm;0;L;;;;;N;;;;;\n1AFF3;KATAKANA LETTER MINNAN TONE-5;Lm;0;L;;;;;N;;;;;\n1AFF5;KATAKANA LETTER MINNAN TONE-7;Lm;0;L;;;;;N;;;;;\n1AFF6;KATAKANA LETTER MINNAN TONE-8;Lm;0;L;;;;;N;;;;;\n1AFF7;KATAKANA LETTER MINNAN NASALIZED TONE-1;Lm;0;L;;;;;N;;;;;\n1AFF8;KATAKANA LETTER MINNAN NASALIZED TONE-2;Lm;0;L;;;;;N;;;;;\n1AFF9;KATAKANA LETTER MINNAN NASALIZED TONE-3;Lm;0;L;;;;;N;;;;;\n1AFFA;KATAKANA LETTER MINNAN NASALIZED TONE-4;Lm;0;L;;;;;N;;;;;\n1AFFB;KATAKANA LETTER MINNAN NASALIZED TONE-5;Lm;0;L;;;;;N;;;;;\n1AFFD;KATAKANA LETTER MINNAN NASALIZED TONE-7;Lm;0;L;;;;;N;;;;;\n1AFFE;KATAKANA LETTER MINNAN NASALIZED TONE-8;Lm;0;L;;;;;N;;;;;\n1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;;\n1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;;\n1B002;HENTAIGANA LETTER A-1;Lo;0;L;;;;;N;;;;;\n1B003;HENTAIGANA LETTER A-2;Lo;0;L;;;;;N;;;;;\n1B004;HENTAIGANA LETTER A-3;Lo;0;L;;;;;N;;;;;\n1B005;HENTAIGANA LETTER A-WO;Lo;0;L;;;;;N;;;;;\n1B006;HENTAIGANA LETTER I-1;Lo;0;L;;;;;N;;;;;\n1B007;HENTAIGANA LETTER I-2;Lo;0;L;;;;;N;;;;;\n1B008;HENTAIGANA LETTER I-3;Lo;0;L;;;;;N;;;;;\n1B009;HENTAIGANA LETTER I-4;Lo;0;L;;;;;N;;;;;\n1B00A;HENTAIGANA LETTER U-1;Lo;0;L;;;;;N;;;;;\n1B00B;HENTAIGANA LETTER U-2;Lo;0;L;;;;;N;;;;;\n1B00C;HENTAIGANA LETTER U-3;Lo;0;L;;;;;N;;;;;\n1B00D;HENTAIGANA LETTER U-4;Lo;0;L;;;;;N;;;;;\n1B00E;HENTAIGANA LETTER U-5;Lo;0;L;;;;;N;;;;;\n1B00F;HENTAIGANA LETTER E-2;Lo;0;L;;;;;N;;;;;\n1B010;HENTAIGANA LETTER E-3;Lo;0;L;;;;;N;;;;;\n1B011;HENTAIGANA LETTER E-4;Lo;0;L;;;;;N;;;;;\n1B012;HENTAIGANA LETTER E-5;Lo;0;L;;;;;N;;;;;\n1B013;HENTAIGANA LETTER E-6;Lo;0;L;;;;;N;;;;;\n1B014;HENTAIGANA LETTER O-1;Lo;0;L;;;;;N;;;;;\n1B015;HENTAIGANA LETTER O-2;Lo;0;L;;;;;N;;;;;\n1B016;HENTAIGANA LETTER O-3;Lo;0;L;;;;;N;;;;;\n1B017;HENTAIGANA LETTER KA-1;Lo;0;L;;;;;N;;;;;\n1B018;HENTAIGANA LETTER KA-2;Lo;0;L;;;;;N;;;;;\n1B019;HENTAIGANA LETTER KA-3;Lo;0;L;;;;;N;;;;;\n1B01A;HENTAIGANA LETTER KA-4;Lo;0;L;;;;;N;;;;;\n1B01B;HENTAIGANA LETTER KA-5;Lo;0;L;;;;;N;;;;;\n1B01C;HENTAIGANA LETTER KA-6;Lo;0;L;;;;;N;;;;;\n1B01D;HENTAIGANA LETTER KA-7;Lo;0;L;;;;;N;;;;;\n1B01E;HENTAIGANA LETTER KA-8;Lo;0;L;;;;;N;;;;;\n1B01F;HENTAIGANA LETTER KA-9;Lo;0;L;;;;;N;;;;;\n1B020;HENTAIGANA LETTER KA-10;Lo;0;L;;;;;N;;;;;\n1B021;HENTAIGANA LETTER KA-11;Lo;0;L;;;;;N;;;;;\n1B022;HENTAIGANA LETTER KA-KE;Lo;0;L;;;;;N;;;;;\n1B023;HENTAIGANA LETTER KI-1;Lo;0;L;;;;;N;;;;;\n1B024;HENTAIGANA LETTER KI-2;Lo;0;L;;;;;N;;;;;\n1B025;HENTAIGANA LETTER KI-3;Lo;0;L;;;;;N;;;;;\n1B026;HENTAIGANA LETTER KI-4;Lo;0;L;;;;;N;;;;;\n1B027;HENTAIGANA LETTER KI-5;Lo;0;L;;;;;N;;;;;\n1B028;HENTAIGANA LETTER KI-6;Lo;0;L;;;;;N;;;;;\n1B029;HENTAIGANA LETTER KI-7;Lo;0;L;;;;;N;;;;;\n1B02A;HENTAIGANA LETTER KI-8;Lo;0;L;;;;;N;;;;;\n1B02B;HENTAIGANA LETTER KU-1;Lo;0;L;;;;;N;;;;;\n1B02C;HENTAIGANA LETTER KU-2;Lo;0;L;;;;;N;;;;;\n1B02D;HENTAIGANA LETTER KU-3;Lo;0;L;;;;;N;;;;;\n1B02E;HENTAIGANA LETTER KU-4;Lo;0;L;;;;;N;;;;;\n1B02F;HENTAIGANA LETTER KU-5;Lo;0;L;;;;;N;;;;;\n1B030;HENTAIGANA LETTER KU-6;Lo;0;L;;;;;N;;;;;\n1B031;HENTAIGANA LETTER KU-7;Lo;0;L;;;;;N;;;;;\n1B032;HENTAIGANA LETTER KE-1;Lo;0;L;;;;;N;;;;;\n1B033;HENTAIGANA LETTER KE-2;Lo;0;L;;;;;N;;;;;\n1B034;HENTAIGANA LETTER KE-3;Lo;0;L;;;;;N;;;;;\n1B035;HENTAIGANA LETTER KE-4;Lo;0;L;;;;;N;;;;;\n1B036;HENTAIGANA LETTER KE-5;Lo;0;L;;;;;N;;;;;\n1B037;HENTAIGANA LETTER KE-6;Lo;0;L;;;;;N;;;;;\n1B038;HENTAIGANA LETTER KO-1;Lo;0;L;;;;;N;;;;;\n1B039;HENTAIGANA LETTER KO-2;Lo;0;L;;;;;N;;;;;\n1B03A;HENTAIGANA LETTER KO-3;Lo;0;L;;;;;N;;;;;\n1B03B;HENTAIGANA LETTER KO-KI;Lo;0;L;;;;;N;;;;;\n1B03C;HENTAIGANA LETTER SA-1;Lo;0;L;;;;;N;;;;;\n1B03D;HENTAIGANA LETTER SA-2;Lo;0;L;;;;;N;;;;;\n1B03E;HENTAIGANA LETTER SA-3;Lo;0;L;;;;;N;;;;;\n1B03F;HENTAIGANA LETTER SA-4;Lo;0;L;;;;;N;;;;;\n1B040;HENTAIGANA LETTER SA-5;Lo;0;L;;;;;N;;;;;\n1B041;HENTAIGANA LETTER SA-6;Lo;0;L;;;;;N;;;;;\n1B042;HENTAIGANA LETTER SA-7;Lo;0;L;;;;;N;;;;;\n1B043;HENTAIGANA LETTER SA-8;Lo;0;L;;;;;N;;;;;\n1B044;HENTAIGANA LETTER SI-1;Lo;0;L;;;;;N;;;;;\n1B045;HENTAIGANA LETTER SI-2;Lo;0;L;;;;;N;;;;;\n1B046;HENTAIGANA LETTER SI-3;Lo;0;L;;;;;N;;;;;\n1B047;HENTAIGANA LETTER SI-4;Lo;0;L;;;;;N;;;;;\n1B048;HENTAIGANA LETTER SI-5;Lo;0;L;;;;;N;;;;;\n1B049;HENTAIGANA LETTER SI-6;Lo;0;L;;;;;N;;;;;\n1B04A;HENTAIGANA LETTER SU-1;Lo;0;L;;;;;N;;;;;\n1B04B;HENTAIGANA LETTER SU-2;Lo;0;L;;;;;N;;;;;\n1B04C;HENTAIGANA LETTER SU-3;Lo;0;L;;;;;N;;;;;\n1B04D;HENTAIGANA LETTER SU-4;Lo;0;L;;;;;N;;;;;\n1B04E;HENTAIGANA LETTER SU-5;Lo;0;L;;;;;N;;;;;\n1B04F;HENTAIGANA LETTER SU-6;Lo;0;L;;;;;N;;;;;\n1B050;HENTAIGANA LETTER SU-7;Lo;0;L;;;;;N;;;;;\n1B051;HENTAIGANA LETTER SU-8;Lo;0;L;;;;;N;;;;;\n1B052;HENTAIGANA LETTER SE-1;Lo;0;L;;;;;N;;;;;\n1B053;HENTAIGANA LETTER SE-2;Lo;0;L;;;;;N;;;;;\n1B054;HENTAIGANA LETTER SE-3;Lo;0;L;;;;;N;;;;;\n1B055;HENTAIGANA LETTER SE-4;Lo;0;L;;;;;N;;;;;\n1B056;HENTAIGANA LETTER SE-5;Lo;0;L;;;;;N;;;;;\n1B057;HENTAIGANA LETTER SO-1;Lo;0;L;;;;;N;;;;;\n1B058;HENTAIGANA LETTER SO-2;Lo;0;L;;;;;N;;;;;\n1B059;HENTAIGANA LETTER SO-3;Lo;0;L;;;;;N;;;;;\n1B05A;HENTAIGANA LETTER SO-4;Lo;0;L;;;;;N;;;;;\n1B05B;HENTAIGANA LETTER SO-5;Lo;0;L;;;;;N;;;;;\n1B05C;HENTAIGANA LETTER SO-6;Lo;0;L;;;;;N;;;;;\n1B05D;HENTAIGANA LETTER SO-7;Lo;0;L;;;;;N;;;;;\n1B05E;HENTAIGANA LETTER TA-1;Lo;0;L;;;;;N;;;;;\n1B05F;HENTAIGANA LETTER TA-2;Lo;0;L;;;;;N;;;;;\n1B060;HENTAIGANA LETTER TA-3;Lo;0;L;;;;;N;;;;;\n1B061;HENTAIGANA LETTER TA-4;Lo;0;L;;;;;N;;;;;\n1B062;HENTAIGANA LETTER TI-1;Lo;0;L;;;;;N;;;;;\n1B063;HENTAIGANA LETTER TI-2;Lo;0;L;;;;;N;;;;;\n1B064;HENTAIGANA LETTER TI-3;Lo;0;L;;;;;N;;;;;\n1B065;HENTAIGANA LETTER TI-4;Lo;0;L;;;;;N;;;;;\n1B066;HENTAIGANA LETTER TI-5;Lo;0;L;;;;;N;;;;;\n1B067;HENTAIGANA LETTER TI-6;Lo;0;L;;;;;N;;;;;\n1B068;HENTAIGANA LETTER TI-7;Lo;0;L;;;;;N;;;;;\n1B069;HENTAIGANA LETTER TU-1;Lo;0;L;;;;;N;;;;;\n1B06A;HENTAIGANA LETTER TU-2;Lo;0;L;;;;;N;;;;;\n1B06B;HENTAIGANA LETTER TU-3;Lo;0;L;;;;;N;;;;;\n1B06C;HENTAIGANA LETTER TU-4;Lo;0;L;;;;;N;;;;;\n1B06D;HENTAIGANA LETTER TU-TO;Lo;0;L;;;;;N;;;;;\n1B06E;HENTAIGANA LETTER TE-1;Lo;0;L;;;;;N;;;;;\n1B06F;HENTAIGANA LETTER TE-2;Lo;0;L;;;;;N;;;;;\n1B070;HENTAIGANA LETTER TE-3;Lo;0;L;;;;;N;;;;;\n1B071;HENTAIGANA LETTER TE-4;Lo;0;L;;;;;N;;;;;\n1B072;HENTAIGANA LETTER TE-5;Lo;0;L;;;;;N;;;;;\n1B073;HENTAIGANA LETTER TE-6;Lo;0;L;;;;;N;;;;;\n1B074;HENTAIGANA LETTER TE-7;Lo;0;L;;;;;N;;;;;\n1B075;HENTAIGANA LETTER TE-8;Lo;0;L;;;;;N;;;;;\n1B076;HENTAIGANA LETTER TE-9;Lo;0;L;;;;;N;;;;;\n1B077;HENTAIGANA LETTER TO-1;Lo;0;L;;;;;N;;;;;\n1B078;HENTAIGANA LETTER TO-2;Lo;0;L;;;;;N;;;;;\n1B079;HENTAIGANA LETTER TO-3;Lo;0;L;;;;;N;;;;;\n1B07A;HENTAIGANA LETTER TO-4;Lo;0;L;;;;;N;;;;;\n1B07B;HENTAIGANA LETTER TO-5;Lo;0;L;;;;;N;;;;;\n1B07C;HENTAIGANA LETTER TO-6;Lo;0;L;;;;;N;;;;;\n1B07D;HENTAIGANA LETTER TO-RA;Lo;0;L;;;;;N;;;;;\n1B07E;HENTAIGANA LETTER NA-1;Lo;0;L;;;;;N;;;;;\n1B07F;HENTAIGANA LETTER NA-2;Lo;0;L;;;;;N;;;;;\n1B080;HENTAIGANA LETTER NA-3;Lo;0;L;;;;;N;;;;;\n1B081;HENTAIGANA LETTER NA-4;Lo;0;L;;;;;N;;;;;\n1B082;HENTAIGANA LETTER NA-5;Lo;0;L;;;;;N;;;;;\n1B083;HENTAIGANA LETTER NA-6;Lo;0;L;;;;;N;;;;;\n1B084;HENTAIGANA LETTER NA-7;Lo;0;L;;;;;N;;;;;\n1B085;HENTAIGANA LETTER NA-8;Lo;0;L;;;;;N;;;;;\n1B086;HENTAIGANA LETTER NA-9;Lo;0;L;;;;;N;;;;;\n1B087;HENTAIGANA LETTER NI-1;Lo;0;L;;;;;N;;;;;\n1B088;HENTAIGANA LETTER NI-2;Lo;0;L;;;;;N;;;;;\n1B089;HENTAIGANA LETTER NI-3;Lo;0;L;;;;;N;;;;;\n1B08A;HENTAIGANA LETTER NI-4;Lo;0;L;;;;;N;;;;;\n1B08B;HENTAIGANA LETTER NI-5;Lo;0;L;;;;;N;;;;;\n1B08C;HENTAIGANA LETTER NI-6;Lo;0;L;;;;;N;;;;;\n1B08D;HENTAIGANA LETTER NI-7;Lo;0;L;;;;;N;;;;;\n1B08E;HENTAIGANA LETTER NI-TE;Lo;0;L;;;;;N;;;;;\n1B08F;HENTAIGANA LETTER NU-1;Lo;0;L;;;;;N;;;;;\n1B090;HENTAIGANA LETTER NU-2;Lo;0;L;;;;;N;;;;;\n1B091;HENTAIGANA LETTER NU-3;Lo;0;L;;;;;N;;;;;\n1B092;HENTAIGANA LETTER NE-1;Lo;0;L;;;;;N;;;;;\n1B093;HENTAIGANA LETTER NE-2;Lo;0;L;;;;;N;;;;;\n1B094;HENTAIGANA LETTER NE-3;Lo;0;L;;;;;N;;;;;\n1B095;HENTAIGANA LETTER NE-4;Lo;0;L;;;;;N;;;;;\n1B096;HENTAIGANA LETTER NE-5;Lo;0;L;;;;;N;;;;;\n1B097;HENTAIGANA LETTER NE-6;Lo;0;L;;;;;N;;;;;\n1B098;HENTAIGANA LETTER NE-KO;Lo;0;L;;;;;N;;;;;\n1B099;HENTAIGANA LETTER NO-1;Lo;0;L;;;;;N;;;;;\n1B09A;HENTAIGANA LETTER NO-2;Lo;0;L;;;;;N;;;;;\n1B09B;HENTAIGANA LETTER NO-3;Lo;0;L;;;;;N;;;;;\n1B09C;HENTAIGANA LETTER NO-4;Lo;0;L;;;;;N;;;;;\n1B09D;HENTAIGANA LETTER NO-5;Lo;0;L;;;;;N;;;;;\n1B09E;HENTAIGANA LETTER HA-1;Lo;0;L;;;;;N;;;;;\n1B09F;HENTAIGANA LETTER HA-2;Lo;0;L;;;;;N;;;;;\n1B0A0;HENTAIGANA LETTER HA-3;Lo;0;L;;;;;N;;;;;\n1B0A1;HENTAIGANA LETTER HA-4;Lo;0;L;;;;;N;;;;;\n1B0A2;HENTAIGANA LETTER HA-5;Lo;0;L;;;;;N;;;;;\n1B0A3;HENTAIGANA LETTER HA-6;Lo;0;L;;;;;N;;;;;\n1B0A4;HENTAIGANA LETTER HA-7;Lo;0;L;;;;;N;;;;;\n1B0A5;HENTAIGANA LETTER HA-8;Lo;0;L;;;;;N;;;;;\n1B0A6;HENTAIGANA LETTER HA-9;Lo;0;L;;;;;N;;;;;\n1B0A7;HENTAIGANA LETTER HA-10;Lo;0;L;;;;;N;;;;;\n1B0A8;HENTAIGANA LETTER HA-11;Lo;0;L;;;;;N;;;;;\n1B0A9;HENTAIGANA LETTER HI-1;Lo;0;L;;;;;N;;;;;\n1B0AA;HENTAIGANA LETTER HI-2;Lo;0;L;;;;;N;;;;;\n1B0AB;HENTAIGANA LETTER HI-3;Lo;0;L;;;;;N;;;;;\n1B0AC;HENTAIGANA LETTER HI-4;Lo;0;L;;;;;N;;;;;\n1B0AD;HENTAIGANA LETTER HI-5;Lo;0;L;;;;;N;;;;;\n1B0AE;HENTAIGANA LETTER HI-6;Lo;0;L;;;;;N;;;;;\n1B0AF;HENTAIGANA LETTER HI-7;Lo;0;L;;;;;N;;;;;\n1B0B0;HENTAIGANA LETTER HU-1;Lo;0;L;;;;;N;;;;;\n1B0B1;HENTAIGANA LETTER HU-2;Lo;0;L;;;;;N;;;;;\n1B0B2;HENTAIGANA LETTER HU-3;Lo;0;L;;;;;N;;;;;\n1B0B3;HENTAIGANA LETTER HE-1;Lo;0;L;;;;;N;;;;;\n1B0B4;HENTAIGANA LETTER HE-2;Lo;0;L;;;;;N;;;;;\n1B0B5;HENTAIGANA LETTER HE-3;Lo;0;L;;;;;N;;;;;\n1B0B6;HENTAIGANA LETTER HE-4;Lo;0;L;;;;;N;;;;;\n1B0B7;HENTAIGANA LETTER HE-5;Lo;0;L;;;;;N;;;;;\n1B0B8;HENTAIGANA LETTER HE-6;Lo;0;L;;;;;N;;;;;\n1B0B9;HENTAIGANA LETTER HE-7;Lo;0;L;;;;;N;;;;;\n1B0BA;HENTAIGANA LETTER HO-1;Lo;0;L;;;;;N;;;;;\n1B0BB;HENTAIGANA LETTER HO-2;Lo;0;L;;;;;N;;;;;\n1B0BC;HENTAIGANA LETTER HO-3;Lo;0;L;;;;;N;;;;;\n1B0BD;HENTAIGANA LETTER HO-4;Lo;0;L;;;;;N;;;;;\n1B0BE;HENTAIGANA LETTER HO-5;Lo;0;L;;;;;N;;;;;\n1B0BF;HENTAIGANA LETTER HO-6;Lo;0;L;;;;;N;;;;;\n1B0C0;HENTAIGANA LETTER HO-7;Lo;0;L;;;;;N;;;;;\n1B0C1;HENTAIGANA LETTER HO-8;Lo;0;L;;;;;N;;;;;\n1B0C2;HENTAIGANA LETTER MA-1;Lo;0;L;;;;;N;;;;;\n1B0C3;HENTAIGANA LETTER MA-2;Lo;0;L;;;;;N;;;;;\n1B0C4;HENTAIGANA LETTER MA-3;Lo;0;L;;;;;N;;;;;\n1B0C5;HENTAIGANA LETTER MA-4;Lo;0;L;;;;;N;;;;;\n1B0C6;HENTAIGANA LETTER MA-5;Lo;0;L;;;;;N;;;;;\n1B0C7;HENTAIGANA LETTER MA-6;Lo;0;L;;;;;N;;;;;\n1B0C8;HENTAIGANA LETTER MA-7;Lo;0;L;;;;;N;;;;;\n1B0C9;HENTAIGANA LETTER MI-1;Lo;0;L;;;;;N;;;;;\n1B0CA;HENTAIGANA LETTER MI-2;Lo;0;L;;;;;N;;;;;\n1B0CB;HENTAIGANA LETTER MI-3;Lo;0;L;;;;;N;;;;;\n1B0CC;HENTAIGANA LETTER MI-4;Lo;0;L;;;;;N;;;;;\n1B0CD;HENTAIGANA LETTER MI-5;Lo;0;L;;;;;N;;;;;\n1B0CE;HENTAIGANA LETTER MI-6;Lo;0;L;;;;;N;;;;;\n1B0CF;HENTAIGANA LETTER MI-7;Lo;0;L;;;;;N;;;;;\n1B0D0;HENTAIGANA LETTER MU-1;Lo;0;L;;;;;N;;;;;\n1B0D1;HENTAIGANA LETTER MU-2;Lo;0;L;;;;;N;;;;;\n1B0D2;HENTAIGANA LETTER MU-3;Lo;0;L;;;;;N;;;;;\n1B0D3;HENTAIGANA LETTER MU-4;Lo;0;L;;;;;N;;;;;\n1B0D4;HENTAIGANA LETTER ME-1;Lo;0;L;;;;;N;;;;;\n1B0D5;HENTAIGANA LETTER ME-2;Lo;0;L;;;;;N;;;;;\n1B0D6;HENTAIGANA LETTER ME-MA;Lo;0;L;;;;;N;;;;;\n1B0D7;HENTAIGANA LETTER MO-1;Lo;0;L;;;;;N;;;;;\n1B0D8;HENTAIGANA LETTER MO-2;Lo;0;L;;;;;N;;;;;\n1B0D9;HENTAIGANA LETTER MO-3;Lo;0;L;;;;;N;;;;;\n1B0DA;HENTAIGANA LETTER MO-4;Lo;0;L;;;;;N;;;;;\n1B0DB;HENTAIGANA LETTER MO-5;Lo;0;L;;;;;N;;;;;\n1B0DC;HENTAIGANA LETTER MO-6;Lo;0;L;;;;;N;;;;;\n1B0DD;HENTAIGANA LETTER YA-1;Lo;0;L;;;;;N;;;;;\n1B0DE;HENTAIGANA LETTER YA-2;Lo;0;L;;;;;N;;;;;\n1B0DF;HENTAIGANA LETTER YA-3;Lo;0;L;;;;;N;;;;;\n1B0E0;HENTAIGANA LETTER YA-4;Lo;0;L;;;;;N;;;;;\n1B0E1;HENTAIGANA LETTER YA-5;Lo;0;L;;;;;N;;;;;\n1B0E2;HENTAIGANA LETTER YA-YO;Lo;0;L;;;;;N;;;;;\n1B0E3;HENTAIGANA LETTER YU-1;Lo;0;L;;;;;N;;;;;\n1B0E4;HENTAIGANA LETTER YU-2;Lo;0;L;;;;;N;;;;;\n1B0E5;HENTAIGANA LETTER YU-3;Lo;0;L;;;;;N;;;;;\n1B0E6;HENTAIGANA LETTER YU-4;Lo;0;L;;;;;N;;;;;\n1B0E7;HENTAIGANA LETTER YO-1;Lo;0;L;;;;;N;;;;;\n1B0E8;HENTAIGANA LETTER YO-2;Lo;0;L;;;;;N;;;;;\n1B0E9;HENTAIGANA LETTER YO-3;Lo;0;L;;;;;N;;;;;\n1B0EA;HENTAIGANA LETTER YO-4;Lo;0;L;;;;;N;;;;;\n1B0EB;HENTAIGANA LETTER YO-5;Lo;0;L;;;;;N;;;;;\n1B0EC;HENTAIGANA LETTER YO-6;Lo;0;L;;;;;N;;;;;\n1B0ED;HENTAIGANA LETTER RA-1;Lo;0;L;;;;;N;;;;;\n1B0EE;HENTAIGANA LETTER RA-2;Lo;0;L;;;;;N;;;;;\n1B0EF;HENTAIGANA LETTER RA-3;Lo;0;L;;;;;N;;;;;\n1B0F0;HENTAIGANA LETTER RA-4;Lo;0;L;;;;;N;;;;;\n1B0F1;HENTAIGANA LETTER RI-1;Lo;0;L;;;;;N;;;;;\n1B0F2;HENTAIGANA LETTER RI-2;Lo;0;L;;;;;N;;;;;\n1B0F3;HENTAIGANA LETTER RI-3;Lo;0;L;;;;;N;;;;;\n1B0F4;HENTAIGANA LETTER RI-4;Lo;0;L;;;;;N;;;;;\n1B0F5;HENTAIGANA LETTER RI-5;Lo;0;L;;;;;N;;;;;\n1B0F6;HENTAIGANA LETTER RI-6;Lo;0;L;;;;;N;;;;;\n1B0F7;HENTAIGANA LETTER RI-7;Lo;0;L;;;;;N;;;;;\n1B0F8;HENTAIGANA LETTER RU-1;Lo;0;L;;;;;N;;;;;\n1B0F9;HENTAIGANA LETTER RU-2;Lo;0;L;;;;;N;;;;;\n1B0FA;HENTAIGANA LETTER RU-3;Lo;0;L;;;;;N;;;;;\n1B0FB;HENTAIGANA LETTER RU-4;Lo;0;L;;;;;N;;;;;\n1B0FC;HENTAIGANA LETTER RU-5;Lo;0;L;;;;;N;;;;;\n1B0FD;HENTAIGANA LETTER RU-6;Lo;0;L;;;;;N;;;;;\n1B0FE;HENTAIGANA LETTER RE-1;Lo;0;L;;;;;N;;;;;\n1B0FF;HENTAIGANA LETTER RE-2;Lo;0;L;;;;;N;;;;;\n1B100;HENTAIGANA LETTER RE-3;Lo;0;L;;;;;N;;;;;\n1B101;HENTAIGANA LETTER RE-4;Lo;0;L;;;;;N;;;;;\n1B102;HENTAIGANA LETTER RO-1;Lo;0;L;;;;;N;;;;;\n1B103;HENTAIGANA LETTER RO-2;Lo;0;L;;;;;N;;;;;\n1B104;HENTAIGANA LETTER RO-3;Lo;0;L;;;;;N;;;;;\n1B105;HENTAIGANA LETTER RO-4;Lo;0;L;;;;;N;;;;;\n1B106;HENTAIGANA LETTER RO-5;Lo;0;L;;;;;N;;;;;\n1B107;HENTAIGANA LETTER RO-6;Lo;0;L;;;;;N;;;;;\n1B108;HENTAIGANA LETTER WA-1;Lo;0;L;;;;;N;;;;;\n1B109;HENTAIGANA LETTER WA-2;Lo;0;L;;;;;N;;;;;\n1B10A;HENTAIGANA LETTER WA-3;Lo;0;L;;;;;N;;;;;\n1B10B;HENTAIGANA LETTER WA-4;Lo;0;L;;;;;N;;;;;\n1B10C;HENTAIGANA LETTER WA-5;Lo;0;L;;;;;N;;;;;\n1B10D;HENTAIGANA LETTER WI-1;Lo;0;L;;;;;N;;;;;\n1B10E;HENTAIGANA LETTER WI-2;Lo;0;L;;;;;N;;;;;\n1B10F;HENTAIGANA LETTER WI-3;Lo;0;L;;;;;N;;;;;\n1B110;HENTAIGANA LETTER WI-4;Lo;0;L;;;;;N;;;;;\n1B111;HENTAIGANA LETTER WI-5;Lo;0;L;;;;;N;;;;;\n1B112;HENTAIGANA LETTER WE-1;Lo;0;L;;;;;N;;;;;\n1B113;HENTAIGANA LETTER WE-2;Lo;0;L;;;;;N;;;;;\n1B114;HENTAIGANA LETTER WE-3;Lo;0;L;;;;;N;;;;;\n1B115;HENTAIGANA LETTER WE-4;Lo;0;L;;;;;N;;;;;\n1B116;HENTAIGANA LETTER WO-1;Lo;0;L;;;;;N;;;;;\n1B117;HENTAIGANA LETTER WO-2;Lo;0;L;;;;;N;;;;;\n1B118;HENTAIGANA LETTER WO-3;Lo;0;L;;;;;N;;;;;\n1B119;HENTAIGANA LETTER WO-4;Lo;0;L;;;;;N;;;;;\n1B11A;HENTAIGANA LETTER WO-5;Lo;0;L;;;;;N;;;;;\n1B11B;HENTAIGANA LETTER WO-6;Lo;0;L;;;;;N;;;;;\n1B11C;HENTAIGANA LETTER WO-7;Lo;0;L;;;;;N;;;;;\n1B11D;HENTAIGANA LETTER N-MU-MO-1;Lo;0;L;;;;;N;;;;;\n1B11E;HENTAIGANA LETTER N-MU-MO-2;Lo;0;L;;;;;N;;;;;\n1B11F;HIRAGANA LETTER ARCHAIC WU;Lo;0;L;;;;;N;;;;;\n1B120;KATAKANA LETTER ARCHAIC YI;Lo;0;L;;;;;N;;;;;\n1B121;KATAKANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;;\n1B122;KATAKANA LETTER ARCHAIC WU;Lo;0;L;;;;;N;;;;;\n1B132;HIRAGANA LETTER SMALL KO;Lo;0;L;;;;;N;;;;;\n1B150;HIRAGANA LETTER SMALL WI;Lo;0;L;;;;;N;;;;;\n1B151;HIRAGANA LETTER SMALL WE;Lo;0;L;;;;;N;;;;;\n1B152;HIRAGANA LETTER SMALL WO;Lo;0;L;;;;;N;;;;;\n1B155;KATAKANA LETTER SMALL KO;Lo;0;L;;;;;N;;;;;\n1B164;KATAKANA LETTER SMALL WI;Lo;0;L;;;;;N;;;;;\n1B165;KATAKANA LETTER SMALL WE;Lo;0;L;;;;;N;;;;;\n1B166;KATAKANA LETTER SMALL WO;Lo;0;L;;;;;N;;;;;\n1B167;KATAKANA LETTER SMALL N;Lo;0;L;;;;;N;;;;;\n1B170;NUSHU CHARACTER-1B170;Lo;0;L;;;;;N;;;;;\n1B171;NUSHU CHARACTER-1B171;Lo;0;L;;;;;N;;;;;\n1B172;NUSHU CHARACTER-1B172;Lo;0;L;;;;;N;;;;;\n1B173;NUSHU CHARACTER-1B173;Lo;0;L;;;;;N;;;;;\n1B174;NUSHU CHARACTER-1B174;Lo;0;L;;;;;N;;;;;\n1B175;NUSHU CHARACTER-1B175;Lo;0;L;;;;;N;;;;;\n1B176;NUSHU CHARACTER-1B176;Lo;0;L;;;;;N;;;;;\n1B177;NUSHU CHARACTER-1B177;Lo;0;L;;;;;N;;;;;\n1B178;NUSHU CHARACTER-1B178;Lo;0;L;;;;;N;;;;;\n1B179;NUSHU CHARACTER-1B179;Lo;0;L;;;;;N;;;;;\n1B17A;NUSHU CHARACTER-1B17A;Lo;0;L;;;;;N;;;;;\n1B17B;NUSHU CHARACTER-1B17B;Lo;0;L;;;;;N;;;;;\n1B17C;NUSHU CHARACTER-1B17C;Lo;0;L;;;;;N;;;;;\n1B17D;NUSHU CHARACTER-1B17D;Lo;0;L;;;;;N;;;;;\n1B17E;NUSHU CHARACTER-1B17E;Lo;0;L;;;;;N;;;;;\n1B17F;NUSHU CHARACTER-1B17F;Lo;0;L;;;;;N;;;;;\n1B180;NUSHU CHARACTER-1B180;Lo;0;L;;;;;N;;;;;\n1B181;NUSHU CHARACTER-1B181;Lo;0;L;;;;;N;;;;;\n1B182;NUSHU CHARACTER-1B182;Lo;0;L;;;;;N;;;;;\n1B183;NUSHU CHARACTER-1B183;Lo;0;L;;;;;N;;;;;\n1B184;NUSHU CHARACTER-1B184;Lo;0;L;;;;;N;;;;;\n1B185;NUSHU CHARACTER-1B185;Lo;0;L;;;;;N;;;;;\n1B186;NUSHU CHARACTER-1B186;Lo;0;L;;;;;N;;;;;\n1B187;NUSHU CHARACTER-1B187;Lo;0;L;;;;;N;;;;;\n1B188;NUSHU CHARACTER-1B188;Lo;0;L;;;;;N;;;;;\n1B189;NUSHU CHARACTER-1B189;Lo;0;L;;;;;N;;;;;\n1B18A;NUSHU CHARACTER-1B18A;Lo;0;L;;;;;N;;;;;\n1B18B;NUSHU CHARACTER-1B18B;Lo;0;L;;;;;N;;;;;\n1B18C;NUSHU CHARACTER-1B18C;Lo;0;L;;;;;N;;;;;\n1B18D;NUSHU CHARACTER-1B18D;Lo;0;L;;;;;N;;;;;\n1B18E;NUSHU CHARACTER-1B18E;Lo;0;L;;;;;N;;;;;\n1B18F;NUSHU CHARACTER-1B18F;Lo;0;L;;;;;N;;;;;\n1B190;NUSHU CHARACTER-1B190;Lo;0;L;;;;;N;;;;;\n1B191;NUSHU CHARACTER-1B191;Lo;0;L;;;;;N;;;;;\n1B192;NUSHU CHARACTER-1B192;Lo;0;L;;;;;N;;;;;\n1B193;NUSHU CHARACTER-1B193;Lo;0;L;;;;;N;;;;;\n1B194;NUSHU CHARACTER-1B194;Lo;0;L;;;;;N;;;;;\n1B195;NUSHU CHARACTER-1B195;Lo;0;L;;;;;N;;;;;\n1B196;NUSHU CHARACTER-1B196;Lo;0;L;;;;;N;;;;;\n1B197;NUSHU CHARACTER-1B197;Lo;0;L;;;;;N;;;;;\n1B198;NUSHU CHARACTER-1B198;Lo;0;L;;;;;N;;;;;\n1B199;NUSHU CHARACTER-1B199;Lo;0;L;;;;;N;;;;;\n1B19A;NUSHU CHARACTER-1B19A;Lo;0;L;;;;;N;;;;;\n1B19B;NUSHU CHARACTER-1B19B;Lo;0;L;;;;;N;;;;;\n1B19C;NUSHU CHARACTER-1B19C;Lo;0;L;;;;;N;;;;;\n1B19D;NUSHU CHARACTER-1B19D;Lo;0;L;;;;;N;;;;;\n1B19E;NUSHU CHARACTER-1B19E;Lo;0;L;;;;;N;;;;;\n1B19F;NUSHU CHARACTER-1B19F;Lo;0;L;;;;;N;;;;;\n1B1A0;NUSHU CHARACTER-1B1A0;Lo;0;L;;;;;N;;;;;\n1B1A1;NUSHU CHARACTER-1B1A1;Lo;0;L;;;;;N;;;;;\n1B1A2;NUSHU CHARACTER-1B1A2;Lo;0;L;;;;;N;;;;;\n1B1A3;NUSHU CHARACTER-1B1A3;Lo;0;L;;;;;N;;;;;\n1B1A4;NUSHU CHARACTER-1B1A4;Lo;0;L;;;;;N;;;;;\n1B1A5;NUSHU CHARACTER-1B1A5;Lo;0;L;;;;;N;;;;;\n1B1A6;NUSHU CHARACTER-1B1A6;Lo;0;L;;;;;N;;;;;\n1B1A7;NUSHU CHARACTER-1B1A7;Lo;0;L;;;;;N;;;;;\n1B1A8;NUSHU CHARACTER-1B1A8;Lo;0;L;;;;;N;;;;;\n1B1A9;NUSHU CHARACTER-1B1A9;Lo;0;L;;;;;N;;;;;\n1B1AA;NUSHU CHARACTER-1B1AA;Lo;0;L;;;;;N;;;;;\n1B1AB;NUSHU CHARACTER-1B1AB;Lo;0;L;;;;;N;;;;;\n1B1AC;NUSHU CHARACTER-1B1AC;Lo;0;L;;;;;N;;;;;\n1B1AD;NUSHU CHARACTER-1B1AD;Lo;0;L;;;;;N;;;;;\n1B1AE;NUSHU CHARACTER-1B1AE;Lo;0;L;;;;;N;;;;;\n1B1AF;NUSHU CHARACTER-1B1AF;Lo;0;L;;;;;N;;;;;\n1B1B0;NUSHU CHARACTER-1B1B0;Lo;0;L;;;;;N;;;;;\n1B1B1;NUSHU CHARACTER-1B1B1;Lo;0;L;;;;;N;;;;;\n1B1B2;NUSHU CHARACTER-1B1B2;Lo;0;L;;;;;N;;;;;\n1B1B3;NUSHU CHARACTER-1B1B3;Lo;0;L;;;;;N;;;;;\n1B1B4;NUSHU CHARACTER-1B1B4;Lo;0;L;;;;;N;;;;;\n1B1B5;NUSHU CHARACTER-1B1B5;Lo;0;L;;;;;N;;;;;\n1B1B6;NUSHU CHARACTER-1B1B6;Lo;0;L;;;;;N;;;;;\n1B1B7;NUSHU CHARACTER-1B1B7;Lo;0;L;;;;;N;;;;;\n1B1B8;NUSHU CHARACTER-1B1B8;Lo;0;L;;;;;N;;;;;\n1B1B9;NUSHU CHARACTER-1B1B9;Lo;0;L;;;;;N;;;;;\n1B1BA;NUSHU CHARACTER-1B1BA;Lo;0;L;;;;;N;;;;;\n1B1BB;NUSHU CHARACTER-1B1BB;Lo;0;L;;;;;N;;;;;\n1B1BC;NUSHU CHARACTER-1B1BC;Lo;0;L;;;;;N;;;;;\n1B1BD;NUSHU CHARACTER-1B1BD;Lo;0;L;;;;;N;;;;;\n1B1BE;NUSHU CHARACTER-1B1BE;Lo;0;L;;;;;N;;;;;\n1B1BF;NUSHU CHARACTER-1B1BF;Lo;0;L;;;;;N;;;;;\n1B1C0;NUSHU CHARACTER-1B1C0;Lo;0;L;;;;;N;;;;;\n1B1C1;NUSHU CHARACTER-1B1C1;Lo;0;L;;;;;N;;;;;\n1B1C2;NUSHU CHARACTER-1B1C2;Lo;0;L;;;;;N;;;;;\n1B1C3;NUSHU CHARACTER-1B1C3;Lo;0;L;;;;;N;;;;;\n1B1C4;NUSHU CHARACTER-1B1C4;Lo;0;L;;;;;N;;;;;\n1B1C5;NUSHU CHARACTER-1B1C5;Lo;0;L;;;;;N;;;;;\n1B1C6;NUSHU CHARACTER-1B1C6;Lo;0;L;;;;;N;;;;;\n1B1C7;NUSHU CHARACTER-1B1C7;Lo;0;L;;;;;N;;;;;\n1B1C8;NUSHU CHARACTER-1B1C8;Lo;0;L;;;;;N;;;;;\n1B1C9;NUSHU CHARACTER-1B1C9;Lo;0;L;;;;;N;;;;;\n1B1CA;NUSHU CHARACTER-1B1CA;Lo;0;L;;;;;N;;;;;\n1B1CB;NUSHU CHARACTER-1B1CB;Lo;0;L;;;;;N;;;;;\n1B1CC;NUSHU CHARACTER-1B1CC;Lo;0;L;;;;;N;;;;;\n1B1CD;NUSHU CHARACTER-1B1CD;Lo;0;L;;;;;N;;;;;\n1B1CE;NUSHU CHARACTER-1B1CE;Lo;0;L;;;;;N;;;;;\n1B1CF;NUSHU CHARACTER-1B1CF;Lo;0;L;;;;;N;;;;;\n1B1D0;NUSHU CHARACTER-1B1D0;Lo;0;L;;;;;N;;;;;\n1B1D1;NUSHU CHARACTER-1B1D1;Lo;0;L;;;;;N;;;;;\n1B1D2;NUSHU CHARACTER-1B1D2;Lo;0;L;;;;;N;;;;;\n1B1D3;NUSHU CHARACTER-1B1D3;Lo;0;L;;;;;N;;;;;\n1B1D4;NUSHU CHARACTER-1B1D4;Lo;0;L;;;;;N;;;;;\n1B1D5;NUSHU CHARACTER-1B1D5;Lo;0;L;;;;;N;;;;;\n1B1D6;NUSHU CHARACTER-1B1D6;Lo;0;L;;;;;N;;;;;\n1B1D7;NUSHU CHARACTER-1B1D7;Lo;0;L;;;;;N;;;;;\n1B1D8;NUSHU CHARACTER-1B1D8;Lo;0;L;;;;;N;;;;;\n1B1D9;NUSHU CHARACTER-1B1D9;Lo;0;L;;;;;N;;;;;\n1B1DA;NUSHU CHARACTER-1B1DA;Lo;0;L;;;;;N;;;;;\n1B1DB;NUSHU CHARACTER-1B1DB;Lo;0;L;;;;;N;;;;;\n1B1DC;NUSHU CHARACTER-1B1DC;Lo;0;L;;;;;N;;;;;\n1B1DD;NUSHU CHARACTER-1B1DD;Lo;0;L;;;;;N;;;;;\n1B1DE;NUSHU CHARACTER-1B1DE;Lo;0;L;;;;;N;;;;;\n1B1DF;NUSHU CHARACTER-1B1DF;Lo;0;L;;;;;N;;;;;\n1B1E0;NUSHU CHARACTER-1B1E0;Lo;0;L;;;;;N;;;;;\n1B1E1;NUSHU CHARACTER-1B1E1;Lo;0;L;;;;;N;;;;;\n1B1E2;NUSHU CHARACTER-1B1E2;Lo;0;L;;;;;N;;;;;\n1B1E3;NUSHU CHARACTER-1B1E3;Lo;0;L;;;;;N;;;;;\n1B1E4;NUSHU CHARACTER-1B1E4;Lo;0;L;;;;;N;;;;;\n1B1E5;NUSHU CHARACTER-1B1E5;Lo;0;L;;;;;N;;;;;\n1B1E6;NUSHU CHARACTER-1B1E6;Lo;0;L;;;;;N;;;;;\n1B1E7;NUSHU CHARACTER-1B1E7;Lo;0;L;;;;;N;;;;;\n1B1E8;NUSHU CHARACTER-1B1E8;Lo;0;L;;;;;N;;;;;\n1B1E9;NUSHU CHARACTER-1B1E9;Lo;0;L;;;;;N;;;;;\n1B1EA;NUSHU CHARACTER-1B1EA;Lo;0;L;;;;;N;;;;;\n1B1EB;NUSHU CHARACTER-1B1EB;Lo;0;L;;;;;N;;;;;\n1B1EC;NUSHU CHARACTER-1B1EC;Lo;0;L;;;;;N;;;;;\n1B1ED;NUSHU CHARACTER-1B1ED;Lo;0;L;;;;;N;;;;;\n1B1EE;NUSHU CHARACTER-1B1EE;Lo;0;L;;;;;N;;;;;\n1B1EF;NUSHU CHARACTER-1B1EF;Lo;0;L;;;;;N;;;;;\n1B1F0;NUSHU CHARACTER-1B1F0;Lo;0;L;;;;;N;;;;;\n1B1F1;NUSHU CHARACTER-1B1F1;Lo;0;L;;;;;N;;;;;\n1B1F2;NUSHU CHARACTER-1B1F2;Lo;0;L;;;;;N;;;;;\n1B1F3;NUSHU CHARACTER-1B1F3;Lo;0;L;;;;;N;;;;;\n1B1F4;NUSHU CHARACTER-1B1F4;Lo;0;L;;;;;N;;;;;\n1B1F5;NUSHU CHARACTER-1B1F5;Lo;0;L;;;;;N;;;;;\n1B1F6;NUSHU CHARACTER-1B1F6;Lo;0;L;;;;;N;;;;;\n1B1F7;NUSHU CHARACTER-1B1F7;Lo;0;L;;;;;N;;;;;\n1B1F8;NUSHU CHARACTER-1B1F8;Lo;0;L;;;;;N;;;;;\n1B1F9;NUSHU CHARACTER-1B1F9;Lo;0;L;;;;;N;;;;;\n1B1FA;NUSHU CHARACTER-1B1FA;Lo;0;L;;;;;N;;;;;\n1B1FB;NUSHU CHARACTER-1B1FB;Lo;0;L;;;;;N;;;;;\n1B1FC;NUSHU CHARACTER-1B1FC;Lo;0;L;;;;;N;;;;;\n1B1FD;NUSHU CHARACTER-1B1FD;Lo;0;L;;;;;N;;;;;\n1B1FE;NUSHU CHARACTER-1B1FE;Lo;0;L;;;;;N;;;;;\n1B1FF;NUSHU CHARACTER-1B1FF;Lo;0;L;;;;;N;;;;;\n1B200;NUSHU CHARACTER-1B200;Lo;0;L;;;;;N;;;;;\n1B201;NUSHU CHARACTER-1B201;Lo;0;L;;;;;N;;;;;\n1B202;NUSHU CHARACTER-1B202;Lo;0;L;;;;;N;;;;;\n1B203;NUSHU CHARACTER-1B203;Lo;0;L;;;;;N;;;;;\n1B204;NUSHU CHARACTER-1B204;Lo;0;L;;;;;N;;;;;\n1B205;NUSHU CHARACTER-1B205;Lo;0;L;;;;;N;;;;;\n1B206;NUSHU CHARACTER-1B206;Lo;0;L;;;;;N;;;;;\n1B207;NUSHU CHARACTER-1B207;Lo;0;L;;;;;N;;;;;\n1B208;NUSHU CHARACTER-1B208;Lo;0;L;;;;;N;;;;;\n1B209;NUSHU CHARACTER-1B209;Lo;0;L;;;;;N;;;;;\n1B20A;NUSHU CHARACTER-1B20A;Lo;0;L;;;;;N;;;;;\n1B20B;NUSHU CHARACTER-1B20B;Lo;0;L;;;;;N;;;;;\n1B20C;NUSHU CHARACTER-1B20C;Lo;0;L;;;;;N;;;;;\n1B20D;NUSHU CHARACTER-1B20D;Lo;0;L;;;;;N;;;;;\n1B20E;NUSHU CHARACTER-1B20E;Lo;0;L;;;;;N;;;;;\n1B20F;NUSHU CHARACTER-1B20F;Lo;0;L;;;;;N;;;;;\n1B210;NUSHU CHARACTER-1B210;Lo;0;L;;;;;N;;;;;\n1B211;NUSHU CHARACTER-1B211;Lo;0;L;;;;;N;;;;;\n1B212;NUSHU CHARACTER-1B212;Lo;0;L;;;;;N;;;;;\n1B213;NUSHU CHARACTER-1B213;Lo;0;L;;;;;N;;;;;\n1B214;NUSHU CHARACTER-1B214;Lo;0;L;;;;;N;;;;;\n1B215;NUSHU CHARACTER-1B215;Lo;0;L;;;;;N;;;;;\n1B216;NUSHU CHARACTER-1B216;Lo;0;L;;;;;N;;;;;\n1B217;NUSHU CHARACTER-1B217;Lo;0;L;;;;;N;;;;;\n1B218;NUSHU CHARACTER-1B218;Lo;0;L;;;;;N;;;;;\n1B219;NUSHU CHARACTER-1B219;Lo;0;L;;;;;N;;;;;\n1B21A;NUSHU CHARACTER-1B21A;Lo;0;L;;;;;N;;;;;\n1B21B;NUSHU CHARACTER-1B21B;Lo;0;L;;;;;N;;;;;\n1B21C;NUSHU CHARACTER-1B21C;Lo;0;L;;;;;N;;;;;\n1B21D;NUSHU CHARACTER-1B21D;Lo;0;L;;;;;N;;;;;\n1B21E;NUSHU CHARACTER-1B21E;Lo;0;L;;;;;N;;;;;\n1B21F;NUSHU CHARACTER-1B21F;Lo;0;L;;;;;N;;;;;\n1B220;NUSHU CHARACTER-1B220;Lo;0;L;;;;;N;;;;;\n1B221;NUSHU CHARACTER-1B221;Lo;0;L;;;;;N;;;;;\n1B222;NUSHU CHARACTER-1B222;Lo;0;L;;;;;N;;;;;\n1B223;NUSHU CHARACTER-1B223;Lo;0;L;;;;;N;;;;;\n1B224;NUSHU CHARACTER-1B224;Lo;0;L;;;;;N;;;;;\n1B225;NUSHU CHARACTER-1B225;Lo;0;L;;;;;N;;;;;\n1B226;NUSHU CHARACTER-1B226;Lo;0;L;;;;;N;;;;;\n1B227;NUSHU CHARACTER-1B227;Lo;0;L;;;;;N;;;;;\n1B228;NUSHU CHARACTER-1B228;Lo;0;L;;;;;N;;;;;\n1B229;NUSHU CHARACTER-1B229;Lo;0;L;;;;;N;;;;;\n1B22A;NUSHU CHARACTER-1B22A;Lo;0;L;;;;;N;;;;;\n1B22B;NUSHU CHARACTER-1B22B;Lo;0;L;;;;;N;;;;;\n1B22C;NUSHU CHARACTER-1B22C;Lo;0;L;;;;;N;;;;;\n1B22D;NUSHU CHARACTER-1B22D;Lo;0;L;;;;;N;;;;;\n1B22E;NUSHU CHARACTER-1B22E;Lo;0;L;;;;;N;;;;;\n1B22F;NUSHU CHARACTER-1B22F;Lo;0;L;;;;;N;;;;;\n1B230;NUSHU CHARACTER-1B230;Lo;0;L;;;;;N;;;;;\n1B231;NUSHU CHARACTER-1B231;Lo;0;L;;;;;N;;;;;\n1B232;NUSHU CHARACTER-1B232;Lo;0;L;;;;;N;;;;;\n1B233;NUSHU CHARACTER-1B233;Lo;0;L;;;;;N;;;;;\n1B234;NUSHU CHARACTER-1B234;Lo;0;L;;;;;N;;;;;\n1B235;NUSHU CHARACTER-1B235;Lo;0;L;;;;;N;;;;;\n1B236;NUSHU CHARACTER-1B236;Lo;0;L;;;;;N;;;;;\n1B237;NUSHU CHARACTER-1B237;Lo;0;L;;;;;N;;;;;\n1B238;NUSHU CHARACTER-1B238;Lo;0;L;;;;;N;;;;;\n1B239;NUSHU CHARACTER-1B239;Lo;0;L;;;;;N;;;;;\n1B23A;NUSHU CHARACTER-1B23A;Lo;0;L;;;;;N;;;;;\n1B23B;NUSHU CHARACTER-1B23B;Lo;0;L;;;;;N;;;;;\n1B23C;NUSHU CHARACTER-1B23C;Lo;0;L;;;;;N;;;;;\n1B23D;NUSHU CHARACTER-1B23D;Lo;0;L;;;;;N;;;;;\n1B23E;NUSHU CHARACTER-1B23E;Lo;0;L;;;;;N;;;;;\n1B23F;NUSHU CHARACTER-1B23F;Lo;0;L;;;;;N;;;;;\n1B240;NUSHU CHARACTER-1B240;Lo;0;L;;;;;N;;;;;\n1B241;NUSHU CHARACTER-1B241;Lo;0;L;;;;;N;;;;;\n1B242;NUSHU CHARACTER-1B242;Lo;0;L;;;;;N;;;;;\n1B243;NUSHU CHARACTER-1B243;Lo;0;L;;;;;N;;;;;\n1B244;NUSHU CHARACTER-1B244;Lo;0;L;;;;;N;;;;;\n1B245;NUSHU CHARACTER-1B245;Lo;0;L;;;;;N;;;;;\n1B246;NUSHU CHARACTER-1B246;Lo;0;L;;;;;N;;;;;\n1B247;NUSHU CHARACTER-1B247;Lo;0;L;;;;;N;;;;;\n1B248;NUSHU CHARACTER-1B248;Lo;0;L;;;;;N;;;;;\n1B249;NUSHU CHARACTER-1B249;Lo;0;L;;;;;N;;;;;\n1B24A;NUSHU CHARACTER-1B24A;Lo;0;L;;;;;N;;;;;\n1B24B;NUSHU CHARACTER-1B24B;Lo;0;L;;;;;N;;;;;\n1B24C;NUSHU CHARACTER-1B24C;Lo;0;L;;;;;N;;;;;\n1B24D;NUSHU CHARACTER-1B24D;Lo;0;L;;;;;N;;;;;\n1B24E;NUSHU CHARACTER-1B24E;Lo;0;L;;;;;N;;;;;\n1B24F;NUSHU CHARACTER-1B24F;Lo;0;L;;;;;N;;;;;\n1B250;NUSHU CHARACTER-1B250;Lo;0;L;;;;;N;;;;;\n1B251;NUSHU CHARACTER-1B251;Lo;0;L;;;;;N;;;;;\n1B252;NUSHU CHARACTER-1B252;Lo;0;L;;;;;N;;;;;\n1B253;NUSHU CHARACTER-1B253;Lo;0;L;;;;;N;;;;;\n1B254;NUSHU CHARACTER-1B254;Lo;0;L;;;;;N;;;;;\n1B255;NUSHU CHARACTER-1B255;Lo;0;L;;;;;N;;;;;\n1B256;NUSHU CHARACTER-1B256;Lo;0;L;;;;;N;;;;;\n1B257;NUSHU CHARACTER-1B257;Lo;0;L;;;;;N;;;;;\n1B258;NUSHU CHARACTER-1B258;Lo;0;L;;;;;N;;;;;\n1B259;NUSHU CHARACTER-1B259;Lo;0;L;;;;;N;;;;;\n1B25A;NUSHU CHARACTER-1B25A;Lo;0;L;;;;;N;;;;;\n1B25B;NUSHU CHARACTER-1B25B;Lo;0;L;;;;;N;;;;;\n1B25C;NUSHU CHARACTER-1B25C;Lo;0;L;;;;;N;;;;;\n1B25D;NUSHU CHARACTER-1B25D;Lo;0;L;;;;;N;;;;;\n1B25E;NUSHU CHARACTER-1B25E;Lo;0;L;;;;;N;;;;;\n1B25F;NUSHU CHARACTER-1B25F;Lo;0;L;;;;;N;;;;;\n1B260;NUSHU CHARACTER-1B260;Lo;0;L;;;;;N;;;;;\n1B261;NUSHU CHARACTER-1B261;Lo;0;L;;;;;N;;;;;\n1B262;NUSHU CHARACTER-1B262;Lo;0;L;;;;;N;;;;;\n1B263;NUSHU CHARACTER-1B263;Lo;0;L;;;;;N;;;;;\n1B264;NUSHU CHARACTER-1B264;Lo;0;L;;;;;N;;;;;\n1B265;NUSHU CHARACTER-1B265;Lo;0;L;;;;;N;;;;;\n1B266;NUSHU CHARACTER-1B266;Lo;0;L;;;;;N;;;;;\n1B267;NUSHU CHARACTER-1B267;Lo;0;L;;;;;N;;;;;\n1B268;NUSHU CHARACTER-1B268;Lo;0;L;;;;;N;;;;;\n1B269;NUSHU CHARACTER-1B269;Lo;0;L;;;;;N;;;;;\n1B26A;NUSHU CHARACTER-1B26A;Lo;0;L;;;;;N;;;;;\n1B26B;NUSHU CHARACTER-1B26B;Lo;0;L;;;;;N;;;;;\n1B26C;NUSHU CHARACTER-1B26C;Lo;0;L;;;;;N;;;;;\n1B26D;NUSHU CHARACTER-1B26D;Lo;0;L;;;;;N;;;;;\n1B26E;NUSHU CHARACTER-1B26E;Lo;0;L;;;;;N;;;;;\n1B26F;NUSHU CHARACTER-1B26F;Lo;0;L;;;;;N;;;;;\n1B270;NUSHU CHARACTER-1B270;Lo;0;L;;;;;N;;;;;\n1B271;NUSHU CHARACTER-1B271;Lo;0;L;;;;;N;;;;;\n1B272;NUSHU CHARACTER-1B272;Lo;0;L;;;;;N;;;;;\n1B273;NUSHU CHARACTER-1B273;Lo;0;L;;;;;N;;;;;\n1B274;NUSHU CHARACTER-1B274;Lo;0;L;;;;;N;;;;;\n1B275;NUSHU CHARACTER-1B275;Lo;0;L;;;;;N;;;;;\n1B276;NUSHU CHARACTER-1B276;Lo;0;L;;;;;N;;;;;\n1B277;NUSHU CHARACTER-1B277;Lo;0;L;;;;;N;;;;;\n1B278;NUSHU CHARACTER-1B278;Lo;0;L;;;;;N;;;;;\n1B279;NUSHU CHARACTER-1B279;Lo;0;L;;;;;N;;;;;\n1B27A;NUSHU CHARACTER-1B27A;Lo;0;L;;;;;N;;;;;\n1B27B;NUSHU CHARACTER-1B27B;Lo;0;L;;;;;N;;;;;\n1B27C;NUSHU CHARACTER-1B27C;Lo;0;L;;;;;N;;;;;\n1B27D;NUSHU CHARACTER-1B27D;Lo;0;L;;;;;N;;;;;\n1B27E;NUSHU CHARACTER-1B27E;Lo;0;L;;;;;N;;;;;\n1B27F;NUSHU CHARACTER-1B27F;Lo;0;L;;;;;N;;;;;\n1B280;NUSHU CHARACTER-1B280;Lo;0;L;;;;;N;;;;;\n1B281;NUSHU CHARACTER-1B281;Lo;0;L;;;;;N;;;;;\n1B282;NUSHU CHARACTER-1B282;Lo;0;L;;;;;N;;;;;\n1B283;NUSHU CHARACTER-1B283;Lo;0;L;;;;;N;;;;;\n1B284;NUSHU CHARACTER-1B284;Lo;0;L;;;;;N;;;;;\n1B285;NUSHU CHARACTER-1B285;Lo;0;L;;;;;N;;;;;\n1B286;NUSHU CHARACTER-1B286;Lo;0;L;;;;;N;;;;;\n1B287;NUSHU CHARACTER-1B287;Lo;0;L;;;;;N;;;;;\n1B288;NUSHU CHARACTER-1B288;Lo;0;L;;;;;N;;;;;\n1B289;NUSHU CHARACTER-1B289;Lo;0;L;;;;;N;;;;;\n1B28A;NUSHU CHARACTER-1B28A;Lo;0;L;;;;;N;;;;;\n1B28B;NUSHU CHARACTER-1B28B;Lo;0;L;;;;;N;;;;;\n1B28C;NUSHU CHARACTER-1B28C;Lo;0;L;;;;;N;;;;;\n1B28D;NUSHU CHARACTER-1B28D;Lo;0;L;;;;;N;;;;;\n1B28E;NUSHU CHARACTER-1B28E;Lo;0;L;;;;;N;;;;;\n1B28F;NUSHU CHARACTER-1B28F;Lo;0;L;;;;;N;;;;;\n1B290;NUSHU CHARACTER-1B290;Lo;0;L;;;;;N;;;;;\n1B291;NUSHU CHARACTER-1B291;Lo;0;L;;;;;N;;;;;\n1B292;NUSHU CHARACTER-1B292;Lo;0;L;;;;;N;;;;;\n1B293;NUSHU CHARACTER-1B293;Lo;0;L;;;;;N;;;;;\n1B294;NUSHU CHARACTER-1B294;Lo;0;L;;;;;N;;;;;\n1B295;NUSHU CHARACTER-1B295;Lo;0;L;;;;;N;;;;;\n1B296;NUSHU CHARACTER-1B296;Lo;0;L;;;;;N;;;;;\n1B297;NUSHU CHARACTER-1B297;Lo;0;L;;;;;N;;;;;\n1B298;NUSHU CHARACTER-1B298;Lo;0;L;;;;;N;;;;;\n1B299;NUSHU CHARACTER-1B299;Lo;0;L;;;;;N;;;;;\n1B29A;NUSHU CHARACTER-1B29A;Lo;0;L;;;;;N;;;;;\n1B29B;NUSHU CHARACTER-1B29B;Lo;0;L;;;;;N;;;;;\n1B29C;NUSHU CHARACTER-1B29C;Lo;0;L;;;;;N;;;;;\n1B29D;NUSHU CHARACTER-1B29D;Lo;0;L;;;;;N;;;;;\n1B29E;NUSHU CHARACTER-1B29E;Lo;0;L;;;;;N;;;;;\n1B29F;NUSHU CHARACTER-1B29F;Lo;0;L;;;;;N;;;;;\n1B2A0;NUSHU CHARACTER-1B2A0;Lo;0;L;;;;;N;;;;;\n1B2A1;NUSHU CHARACTER-1B2A1;Lo;0;L;;;;;N;;;;;\n1B2A2;NUSHU CHARACTER-1B2A2;Lo;0;L;;;;;N;;;;;\n1B2A3;NUSHU CHARACTER-1B2A3;Lo;0;L;;;;;N;;;;;\n1B2A4;NUSHU CHARACTER-1B2A4;Lo;0;L;;;;;N;;;;;\n1B2A5;NUSHU CHARACTER-1B2A5;Lo;0;L;;;;;N;;;;;\n1B2A6;NUSHU CHARACTER-1B2A6;Lo;0;L;;;;;N;;;;;\n1B2A7;NUSHU CHARACTER-1B2A7;Lo;0;L;;;;;N;;;;;\n1B2A8;NUSHU CHARACTER-1B2A8;Lo;0;L;;;;;N;;;;;\n1B2A9;NUSHU CHARACTER-1B2A9;Lo;0;L;;;;;N;;;;;\n1B2AA;NUSHU CHARACTER-1B2AA;Lo;0;L;;;;;N;;;;;\n1B2AB;NUSHU CHARACTER-1B2AB;Lo;0;L;;;;;N;;;;;\n1B2AC;NUSHU CHARACTER-1B2AC;Lo;0;L;;;;;N;;;;;\n1B2AD;NUSHU CHARACTER-1B2AD;Lo;0;L;;;;;N;;;;;\n1B2AE;NUSHU CHARACTER-1B2AE;Lo;0;L;;;;;N;;;;;\n1B2AF;NUSHU CHARACTER-1B2AF;Lo;0;L;;;;;N;;;;;\n1B2B0;NUSHU CHARACTER-1B2B0;Lo;0;L;;;;;N;;;;;\n1B2B1;NUSHU CHARACTER-1B2B1;Lo;0;L;;;;;N;;;;;\n1B2B2;NUSHU CHARACTER-1B2B2;Lo;0;L;;;;;N;;;;;\n1B2B3;NUSHU CHARACTER-1B2B3;Lo;0;L;;;;;N;;;;;\n1B2B4;NUSHU CHARACTER-1B2B4;Lo;0;L;;;;;N;;;;;\n1B2B5;NUSHU CHARACTER-1B2B5;Lo;0;L;;;;;N;;;;;\n1B2B6;NUSHU CHARACTER-1B2B6;Lo;0;L;;;;;N;;;;;\n1B2B7;NUSHU CHARACTER-1B2B7;Lo;0;L;;;;;N;;;;;\n1B2B8;NUSHU CHARACTER-1B2B8;Lo;0;L;;;;;N;;;;;\n1B2B9;NUSHU CHARACTER-1B2B9;Lo;0;L;;;;;N;;;;;\n1B2BA;NUSHU CHARACTER-1B2BA;Lo;0;L;;;;;N;;;;;\n1B2BB;NUSHU CHARACTER-1B2BB;Lo;0;L;;;;;N;;;;;\n1B2BC;NUSHU CHARACTER-1B2BC;Lo;0;L;;;;;N;;;;;\n1B2BD;NUSHU CHARACTER-1B2BD;Lo;0;L;;;;;N;;;;;\n1B2BE;NUSHU CHARACTER-1B2BE;Lo;0;L;;;;;N;;;;;\n1B2BF;NUSHU CHARACTER-1B2BF;Lo;0;L;;;;;N;;;;;\n1B2C0;NUSHU CHARACTER-1B2C0;Lo;0;L;;;;;N;;;;;\n1B2C1;NUSHU CHARACTER-1B2C1;Lo;0;L;;;;;N;;;;;\n1B2C2;NUSHU CHARACTER-1B2C2;Lo;0;L;;;;;N;;;;;\n1B2C3;NUSHU CHARACTER-1B2C3;Lo;0;L;;;;;N;;;;;\n1B2C4;NUSHU CHARACTER-1B2C4;Lo;0;L;;;;;N;;;;;\n1B2C5;NUSHU CHARACTER-1B2C5;Lo;0;L;;;;;N;;;;;\n1B2C6;NUSHU CHARACTER-1B2C6;Lo;0;L;;;;;N;;;;;\n1B2C7;NUSHU CHARACTER-1B2C7;Lo;0;L;;;;;N;;;;;\n1B2C8;NUSHU CHARACTER-1B2C8;Lo;0;L;;;;;N;;;;;\n1B2C9;NUSHU CHARACTER-1B2C9;Lo;0;L;;;;;N;;;;;\n1B2CA;NUSHU CHARACTER-1B2CA;Lo;0;L;;;;;N;;;;;\n1B2CB;NUSHU CHARACTER-1B2CB;Lo;0;L;;;;;N;;;;;\n1B2CC;NUSHU CHARACTER-1B2CC;Lo;0;L;;;;;N;;;;;\n1B2CD;NUSHU CHARACTER-1B2CD;Lo;0;L;;;;;N;;;;;\n1B2CE;NUSHU CHARACTER-1B2CE;Lo;0;L;;;;;N;;;;;\n1B2CF;NUSHU CHARACTER-1B2CF;Lo;0;L;;;;;N;;;;;\n1B2D0;NUSHU CHARACTER-1B2D0;Lo;0;L;;;;;N;;;;;\n1B2D1;NUSHU CHARACTER-1B2D1;Lo;0;L;;;;;N;;;;;\n1B2D2;NUSHU CHARACTER-1B2D2;Lo;0;L;;;;;N;;;;;\n1B2D3;NUSHU CHARACTER-1B2D3;Lo;0;L;;;;;N;;;;;\n1B2D4;NUSHU CHARACTER-1B2D4;Lo;0;L;;;;;N;;;;;\n1B2D5;NUSHU CHARACTER-1B2D5;Lo;0;L;;;;;N;;;;;\n1B2D6;NUSHU CHARACTER-1B2D6;Lo;0;L;;;;;N;;;;;\n1B2D7;NUSHU CHARACTER-1B2D7;Lo;0;L;;;;;N;;;;;\n1B2D8;NUSHU CHARACTER-1B2D8;Lo;0;L;;;;;N;;;;;\n1B2D9;NUSHU CHARACTER-1B2D9;Lo;0;L;;;;;N;;;;;\n1B2DA;NUSHU CHARACTER-1B2DA;Lo;0;L;;;;;N;;;;;\n1B2DB;NUSHU CHARACTER-1B2DB;Lo;0;L;;;;;N;;;;;\n1B2DC;NUSHU CHARACTER-1B2DC;Lo;0;L;;;;;N;;;;;\n1B2DD;NUSHU CHARACTER-1B2DD;Lo;0;L;;;;;N;;;;;\n1B2DE;NUSHU CHARACTER-1B2DE;Lo;0;L;;;;;N;;;;;\n1B2DF;NUSHU CHARACTER-1B2DF;Lo;0;L;;;;;N;;;;;\n1B2E0;NUSHU CHARACTER-1B2E0;Lo;0;L;;;;;N;;;;;\n1B2E1;NUSHU CHARACTER-1B2E1;Lo;0;L;;;;;N;;;;;\n1B2E2;NUSHU CHARACTER-1B2E2;Lo;0;L;;;;;N;;;;;\n1B2E3;NUSHU CHARACTER-1B2E3;Lo;0;L;;;;;N;;;;;\n1B2E4;NUSHU CHARACTER-1B2E4;Lo;0;L;;;;;N;;;;;\n1B2E5;NUSHU CHARACTER-1B2E5;Lo;0;L;;;;;N;;;;;\n1B2E6;NUSHU CHARACTER-1B2E6;Lo;0;L;;;;;N;;;;;\n1B2E7;NUSHU CHARACTER-1B2E7;Lo;0;L;;;;;N;;;;;\n1B2E8;NUSHU CHARACTER-1B2E8;Lo;0;L;;;;;N;;;;;\n1B2E9;NUSHU CHARACTER-1B2E9;Lo;0;L;;;;;N;;;;;\n1B2EA;NUSHU CHARACTER-1B2EA;Lo;0;L;;;;;N;;;;;\n1B2EB;NUSHU CHARACTER-1B2EB;Lo;0;L;;;;;N;;;;;\n1B2EC;NUSHU CHARACTER-1B2EC;Lo;0;L;;;;;N;;;;;\n1B2ED;NUSHU CHARACTER-1B2ED;Lo;0;L;;;;;N;;;;;\n1B2EE;NUSHU CHARACTER-1B2EE;Lo;0;L;;;;;N;;;;;\n1B2EF;NUSHU CHARACTER-1B2EF;Lo;0;L;;;;;N;;;;;\n1B2F0;NUSHU CHARACTER-1B2F0;Lo;0;L;;;;;N;;;;;\n1B2F1;NUSHU CHARACTER-1B2F1;Lo;0;L;;;;;N;;;;;\n1B2F2;NUSHU CHARACTER-1B2F2;Lo;0;L;;;;;N;;;;;\n1B2F3;NUSHU CHARACTER-1B2F3;Lo;0;L;;;;;N;;;;;\n1B2F4;NUSHU CHARACTER-1B2F4;Lo;0;L;;;;;N;;;;;\n1B2F5;NUSHU CHARACTER-1B2F5;Lo;0;L;;;;;N;;;;;\n1B2F6;NUSHU CHARACTER-1B2F6;Lo;0;L;;;;;N;;;;;\n1B2F7;NUSHU CHARACTER-1B2F7;Lo;0;L;;;;;N;;;;;\n1B2F8;NUSHU CHARACTER-1B2F8;Lo;0;L;;;;;N;;;;;\n1B2F9;NUSHU CHARACTER-1B2F9;Lo;0;L;;;;;N;;;;;\n1B2FA;NUSHU CHARACTER-1B2FA;Lo;0;L;;;;;N;;;;;\n1B2FB;NUSHU CHARACTER-1B2FB;Lo;0;L;;;;;N;;;;;\n1BC00;DUPLOYAN LETTER H;Lo;0;L;;;;;N;;;;;\n1BC01;DUPLOYAN LETTER X;Lo;0;L;;;;;N;;;;;\n1BC02;DUPLOYAN LETTER P;Lo;0;L;;;;;N;;;;;\n1BC03;DUPLOYAN LETTER T;Lo;0;L;;;;;N;;;;;\n1BC04;DUPLOYAN LETTER F;Lo;0;L;;;;;N;;;;;\n1BC05;DUPLOYAN LETTER K;Lo;0;L;;;;;N;;;;;\n1BC06;DUPLOYAN LETTER L;Lo;0;L;;;;;N;;;;;\n1BC07;DUPLOYAN LETTER B;Lo;0;L;;;;;N;;;;;\n1BC08;DUPLOYAN LETTER D;Lo;0;L;;;;;N;;;;;\n1BC09;DUPLOYAN LETTER V;Lo;0;L;;;;;N;;;;;\n1BC0A;DUPLOYAN LETTER G;Lo;0;L;;;;;N;;;;;\n1BC0B;DUPLOYAN LETTER R;Lo;0;L;;;;;N;;;;;\n1BC0C;DUPLOYAN LETTER P N;Lo;0;L;;;;;N;;;;;\n1BC0D;DUPLOYAN LETTER D S;Lo;0;L;;;;;N;;;;;\n1BC0E;DUPLOYAN LETTER F N;Lo;0;L;;;;;N;;;;;\n1BC0F;DUPLOYAN LETTER K M;Lo;0;L;;;;;N;;;;;\n1BC10;DUPLOYAN LETTER R S;Lo;0;L;;;;;N;;;;;\n1BC11;DUPLOYAN LETTER TH;Lo;0;L;;;;;N;;;;;\n1BC12;DUPLOYAN LETTER SLOAN DH;Lo;0;L;;;;;N;;;;;\n1BC13;DUPLOYAN LETTER DH;Lo;0;L;;;;;N;;;;;\n1BC14;DUPLOYAN LETTER KK;Lo;0;L;;;;;N;;;;;\n1BC15;DUPLOYAN LETTER SLOAN J;Lo;0;L;;;;;N;;;;;\n1BC16;DUPLOYAN LETTER HL;Lo;0;L;;;;;N;;;;;\n1BC17;DUPLOYAN LETTER LH;Lo;0;L;;;;;N;;;;;\n1BC18;DUPLOYAN LETTER RH;Lo;0;L;;;;;N;;;;;\n1BC19;DUPLOYAN LETTER M;Lo;0;L;;;;;N;;;;;\n1BC1A;DUPLOYAN LETTER N;Lo;0;L;;;;;N;;;;;\n1BC1B;DUPLOYAN LETTER J;Lo;0;L;;;;;N;;;;;\n1BC1C;DUPLOYAN LETTER S;Lo;0;L;;;;;N;;;;;\n1BC1D;DUPLOYAN LETTER M N;Lo;0;L;;;;;N;;;;;\n1BC1E;DUPLOYAN LETTER N M;Lo;0;L;;;;;N;;;;;\n1BC1F;DUPLOYAN LETTER J M;Lo;0;L;;;;;N;;;;;\n1BC20;DUPLOYAN LETTER S J;Lo;0;L;;;;;N;;;;;\n1BC21;DUPLOYAN LETTER M WITH DOT;Lo;0;L;;;;;N;;;;;\n1BC22;DUPLOYAN LETTER N WITH DOT;Lo;0;L;;;;;N;;;;;\n1BC23;DUPLOYAN LETTER J WITH DOT;Lo;0;L;;;;;N;;;;;\n1BC24;DUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVE;Lo;0;L;;;;;N;;;;;\n1BC25;DUPLOYAN LETTER S WITH DOT;Lo;0;L;;;;;N;;;;;\n1BC26;DUPLOYAN LETTER S WITH DOT BELOW;Lo;0;L;;;;;N;;;;;\n1BC27;DUPLOYAN LETTER M S;Lo;0;L;;;;;N;;;;;\n1BC28;DUPLOYAN LETTER N S;Lo;0;L;;;;;N;;;;;\n1BC29;DUPLOYAN LETTER J S;Lo;0;L;;;;;N;;;;;\n1BC2A;DUPLOYAN LETTER S S;Lo;0;L;;;;;N;;;;;\n1BC2B;DUPLOYAN LETTER M N S;Lo;0;L;;;;;N;;;;;\n1BC2C;DUPLOYAN LETTER N M S;Lo;0;L;;;;;N;;;;;\n1BC2D;DUPLOYAN LETTER J M S;Lo;0;L;;;;;N;;;;;\n1BC2E;DUPLOYAN LETTER S J S;Lo;0;L;;;;;N;;;;;\n1BC2F;DUPLOYAN LETTER J S WITH DOT;Lo;0;L;;;;;N;;;;;\n1BC30;DUPLOYAN LETTER J N;Lo;0;L;;;;;N;;;;;\n1BC31;DUPLOYAN LETTER J N S;Lo;0;L;;;;;N;;;;;\n1BC32;DUPLOYAN LETTER S T;Lo;0;L;;;;;N;;;;;\n1BC33;DUPLOYAN LETTER S T R;Lo;0;L;;;;;N;;;;;\n1BC34;DUPLOYAN LETTER S P;Lo;0;L;;;;;N;;;;;\n1BC35;DUPLOYAN LETTER S P R;Lo;0;L;;;;;N;;;;;\n1BC36;DUPLOYAN LETTER T S;Lo;0;L;;;;;N;;;;;\n1BC37;DUPLOYAN LETTER T R S;Lo;0;L;;;;;N;;;;;\n1BC38;DUPLOYAN LETTER W;Lo;0;L;;;;;N;;;;;\n1BC39;DUPLOYAN LETTER WH;Lo;0;L;;;;;N;;;;;\n1BC3A;DUPLOYAN LETTER W R;Lo;0;L;;;;;N;;;;;\n1BC3B;DUPLOYAN LETTER S N;Lo;0;L;;;;;N;;;;;\n1BC3C;DUPLOYAN LETTER S M;Lo;0;L;;;;;N;;;;;\n1BC3D;DUPLOYAN LETTER K R S;Lo;0;L;;;;;N;;;;;\n1BC3E;DUPLOYAN LETTER G R S;Lo;0;L;;;;;N;;;;;\n1BC3F;DUPLOYAN LETTER S K;Lo;0;L;;;;;N;;;;;\n1BC40;DUPLOYAN LETTER S K R;Lo;0;L;;;;;N;;;;;\n1BC41;DUPLOYAN LETTER A;Lo;0;L;;;;;N;;;;;\n1BC42;DUPLOYAN LETTER SLOAN OW;Lo;0;L;;;;;N;;;;;\n1BC43;DUPLOYAN LETTER OA;Lo;0;L;;;;;N;;;;;\n1BC44;DUPLOYAN LETTER O;Lo;0;L;;;;;N;;;;;\n1BC45;DUPLOYAN LETTER AOU;Lo;0;L;;;;;N;;;;;\n1BC46;DUPLOYAN LETTER I;Lo;0;L;;;;;N;;;;;\n1BC47;DUPLOYAN LETTER E;Lo;0;L;;;;;N;;;;;\n1BC48;DUPLOYAN LETTER IE;Lo;0;L;;;;;N;;;;;\n1BC49;DUPLOYAN LETTER SHORT I;Lo;0;L;;;;;N;;;;;\n1BC4A;DUPLOYAN LETTER UI;Lo;0;L;;;;;N;;;;;\n1BC4B;DUPLOYAN LETTER EE;Lo;0;L;;;;;N;;;;;\n1BC4C;DUPLOYAN LETTER SLOAN EH;Lo;0;L;;;;;N;;;;;\n1BC4D;DUPLOYAN LETTER ROMANIAN I;Lo;0;L;;;;;N;;;;;\n1BC4E;DUPLOYAN LETTER SLOAN EE;Lo;0;L;;;;;N;;;;;\n1BC4F;DUPLOYAN LETTER LONG I;Lo;0;L;;;;;N;;;;;\n1BC50;DUPLOYAN LETTER YE;Lo;0;L;;;;;N;;;;;\n1BC51;DUPLOYAN LETTER U;Lo;0;L;;;;;N;;;;;\n1BC52;DUPLOYAN LETTER EU;Lo;0;L;;;;;N;;;;;\n1BC53;DUPLOYAN LETTER XW;Lo;0;L;;;;;N;;;;;\n1BC54;DUPLOYAN LETTER U N;Lo;0;L;;;;;N;;;;;\n1BC55;DUPLOYAN LETTER LONG U;Lo;0;L;;;;;N;;;;;\n1BC56;DUPLOYAN LETTER ROMANIAN U;Lo;0;L;;;;;N;;;;;\n1BC57;DUPLOYAN LETTER UH;Lo;0;L;;;;;N;;;;;\n1BC58;DUPLOYAN LETTER SLOAN U;Lo;0;L;;;;;N;;;;;\n1BC59;DUPLOYAN LETTER OOH;Lo;0;L;;;;;N;;;;;\n1BC5A;DUPLOYAN LETTER OW;Lo;0;L;;;;;N;;;;;\n1BC5B;DUPLOYAN LETTER OU;Lo;0;L;;;;;N;;;;;\n1BC5C;DUPLOYAN LETTER WA;Lo;0;L;;;;;N;;;;;\n1BC5D;DUPLOYAN LETTER WO;Lo;0;L;;;;;N;;;;;\n1BC5E;DUPLOYAN LETTER WI;Lo;0;L;;;;;N;;;;;\n1BC5F;DUPLOYAN LETTER WEI;Lo;0;L;;;;;N;;;;;\n1BC60;DUPLOYAN LETTER WOW;Lo;0;L;;;;;N;;;;;\n1BC61;DUPLOYAN LETTER NASAL U;Lo;0;L;;;;;N;;;;;\n1BC62;DUPLOYAN LETTER NASAL O;Lo;0;L;;;;;N;;;;;\n1BC63;DUPLOYAN LETTER NASAL I;Lo;0;L;;;;;N;;;;;\n1BC64;DUPLOYAN LETTER NASAL A;Lo;0;L;;;;;N;;;;;\n1BC65;DUPLOYAN LETTER PERNIN AN;Lo;0;L;;;;;N;;;;;\n1BC66;DUPLOYAN LETTER PERNIN AM;Lo;0;L;;;;;N;;;;;\n1BC67;DUPLOYAN LETTER SLOAN EN;Lo;0;L;;;;;N;;;;;\n1BC68;DUPLOYAN LETTER SLOAN AN;Lo;0;L;;;;;N;;;;;\n1BC69;DUPLOYAN LETTER SLOAN ON;Lo;0;L;;;;;N;;;;;\n1BC6A;DUPLOYAN LETTER VOCALIC M;Lo;0;L;;;;;N;;;;;\n1BC70;DUPLOYAN AFFIX LEFT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;;\n1BC71;DUPLOYAN AFFIX MID HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;;\n1BC72;DUPLOYAN AFFIX RIGHT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;;\n1BC73;DUPLOYAN AFFIX LOW VERTICAL SECANT;Lo;0;L;;;;;N;;;;;\n1BC74;DUPLOYAN AFFIX MID VERTICAL SECANT;Lo;0;L;;;;;N;;;;;\n1BC75;DUPLOYAN AFFIX HIGH VERTICAL SECANT;Lo;0;L;;;;;N;;;;;\n1BC76;DUPLOYAN AFFIX ATTACHED SECANT;Lo;0;L;;;;;N;;;;;\n1BC77;DUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANT;Lo;0;L;;;;;N;;;;;\n1BC78;DUPLOYAN AFFIX ATTACHED TANGENT;Lo;0;L;;;;;N;;;;;\n1BC79;DUPLOYAN AFFIX ATTACHED TAIL;Lo;0;L;;;;;N;;;;;\n1BC7A;DUPLOYAN AFFIX ATTACHED E HOOK;Lo;0;L;;;;;N;;;;;\n1BC7B;DUPLOYAN AFFIX ATTACHED I HOOK;Lo;0;L;;;;;N;;;;;\n1BC7C;DUPLOYAN AFFIX ATTACHED TANGENT HOOK;Lo;0;L;;;;;N;;;;;\n1BC80;DUPLOYAN AFFIX HIGH ACUTE;Lo;0;L;;;;;N;;;;;\n1BC81;DUPLOYAN AFFIX HIGH TIGHT ACUTE;Lo;0;L;;;;;N;;;;;\n1BC82;DUPLOYAN AFFIX HIGH GRAVE;Lo;0;L;;;;;N;;;;;\n1BC83;DUPLOYAN AFFIX HIGH LONG GRAVE;Lo;0;L;;;;;N;;;;;\n1BC84;DUPLOYAN AFFIX HIGH DOT;Lo;0;L;;;;;N;;;;;\n1BC85;DUPLOYAN AFFIX HIGH CIRCLE;Lo;0;L;;;;;N;;;;;\n1BC86;DUPLOYAN AFFIX HIGH LINE;Lo;0;L;;;;;N;;;;;\n1BC87;DUPLOYAN AFFIX HIGH WAVE;Lo;0;L;;;;;N;;;;;\n1BC88;DUPLOYAN AFFIX HIGH VERTICAL;Lo;0;L;;;;;N;;;;;\n1BC90;DUPLOYAN AFFIX LOW ACUTE;Lo;0;L;;;;;N;;;;;\n1BC91;DUPLOYAN AFFIX LOW TIGHT ACUTE;Lo;0;L;;;;;N;;;;;\n1BC92;DUPLOYAN AFFIX LOW GRAVE;Lo;0;L;;;;;N;;;;;\n1BC93;DUPLOYAN AFFIX LOW LONG GRAVE;Lo;0;L;;;;;N;;;;;\n1BC94;DUPLOYAN AFFIX LOW DOT;Lo;0;L;;;;;N;;;;;\n1BC95;DUPLOYAN AFFIX LOW CIRCLE;Lo;0;L;;;;;N;;;;;\n1BC96;DUPLOYAN AFFIX LOW LINE;Lo;0;L;;;;;N;;;;;\n1BC97;DUPLOYAN AFFIX LOW WAVE;Lo;0;L;;;;;N;;;;;\n1BC98;DUPLOYAN AFFIX LOW VERTICAL;Lo;0;L;;;;;N;;;;;\n1BC99;DUPLOYAN AFFIX LOW ARROW;Lo;0;L;;;;;N;;;;;\n1BC9C;DUPLOYAN SIGN O WITH CROSS;So;0;L;;;;;N;;;;;\n1BC9D;DUPLOYAN THICK LETTER SELECTOR;Mn;0;NSM;;;;;N;;;;;\n1BC9E;DUPLOYAN DOUBLE MARK;Mn;1;NSM;;;;;N;;;;;\n1BC9F;DUPLOYAN PUNCTUATION CHINOOK FULL STOP;Po;0;L;;;;;N;;;;;\n1BCA0;SHORTHAND FORMAT LETTER OVERLAP;Cf;0;BN;;;;;N;;;;;\n1BCA1;SHORTHAND FORMAT CONTINUING OVERLAP;Cf;0;BN;;;;;N;;;;;\n1BCA2;SHORTHAND FORMAT DOWN STEP;Cf;0;BN;;;;;N;;;;;\n1BCA3;SHORTHAND FORMAT UP STEP;Cf;0;BN;;;;;N;;;;;\n1CC00;UP-POINTING GO-KART;So;0;ON;;;;;N;;;;;\n1CC01;RIGHT-POINTING GO-KART;So;0;ON;;;;;N;;;;;\n1CC02;LEFT-POINTING STICK FIGURE;So;0;ON;;;;;N;;;;;\n1CC03;RIGHT-POINTING STICK FIGURE;So;0;ON;;;;;N;;;;;\n1CC04;DOWN-POINTING STICK FIGURE;So;0;ON;;;;;N;;;;;\n1CC05;LOWER HORIZONTAL RULER SEGMENT;So;0;ON;;;;;N;;;;;\n1CC06;RIGHT VERTICAL RULER SEGMENT;So;0;ON;;;;;N;;;;;\n1CC07;LOWER RIGHT RULER SEGMENT;So;0;ON;;;;;N;;;;;\n1CC08;ANTENNA;So;0;ON;;;;;N;;;;;\n1CC09;HORIZONTAL RESISTOR SEGMENT;So;0;ON;;;;;N;;;;;\n1CC0A;VERTICAL RESISTOR SEGMENT;So;0;ON;;;;;N;;;;;\n1CC0B;LEFT THIRD INDUCTOR;So;0;ON;;;;;N;;;;;\n1CC0C;MIDDLE THIRD INDUCTOR;So;0;ON;;;;;N;;;;;\n1CC0D;RIGHT THIRD INDUCTOR;So;0;ON;;;;;N;;;;;\n1CC0E;LEFT-POINTING DIODE;So;0;ON;;;;;N;;;;;\n1CC0F;RIGHT-POINTING DIODE;So;0;ON;;;;;N;;;;;\n1CC10;NPN TRANSISTOR;So;0;ON;;;;;N;;;;;\n1CC11;PNP TRANSISTOR;So;0;ON;;;;;N;;;;;\n1CC12;RECEPTACLE;So;0;ON;;;;;N;;;;;\n1CC13;HORIZONTAL CAPACITOR;So;0;ON;;;;;N;;;;;\n1CC14;VERTICAL CAPACITOR;So;0;ON;;;;;N;;;;;\n1CC15;LOGIC GATE OR;So;0;ON;;;;;N;;;;;\n1CC16;LOGIC GATE AND;So;0;ON;;;;;N;;;;;\n1CC17;LOGIC GATE INVERTED INPUTS;So;0;ON;;;;;N;;;;;\n1CC18;LOGIC GATE INVERTED OUTPUT;So;0;ON;;;;;N;;;;;\n1CC19;LOGIC GATE BUFFER;So;0;ON;;;;;N;;;;;\n1CC1A;LOGIC GATE BUFFER WITH INVERTED INPUT;So;0;ON;;;;;N;;;;;\n1CC1B;BOX DRAWINGS LIGHT HORIZONTAL AND UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1CC1C;BOX DRAWINGS LIGHT HORIZONTAL AND LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1CC1D;BOX DRAWINGS LIGHT TOP AND UPPER LEFT;So;0;ON;;;;;N;;;;;\n1CC1E;BOX DRAWINGS LIGHT BOTTOM AND LOWER LEFT;So;0;ON;;;;;N;;;;;\n1CC1F;BOX DRAWINGS DOUBLE DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;;;;;\n1CC20;BOX DRAWINGS DOUBLE DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1CC21;SEPARATED BLOCK QUADRANT-1;So;0;ON;;;;;N;;;;;\n1CC22;SEPARATED BLOCK QUADRANT-2;So;0;ON;;;;;N;;;;;\n1CC23;SEPARATED BLOCK QUADRANT-12;So;0;ON;;;;;N;;;;;\n1CC24;SEPARATED BLOCK QUADRANT-3;So;0;ON;;;;;N;;;;;\n1CC25;SEPARATED BLOCK QUADRANT-13;So;0;ON;;;;;N;;;;;\n1CC26;SEPARATED BLOCK QUADRANT-23;So;0;ON;;;;;N;;;;;\n1CC27;SEPARATED BLOCK QUADRANT-123;So;0;ON;;;;;N;;;;;\n1CC28;SEPARATED BLOCK QUADRANT-4;So;0;ON;;;;;N;;;;;\n1CC29;SEPARATED BLOCK QUADRANT-14;So;0;ON;;;;;N;;;;;\n1CC2A;SEPARATED BLOCK QUADRANT-24;So;0;ON;;;;;N;;;;;\n1CC2B;SEPARATED BLOCK QUADRANT-124;So;0;ON;;;;;N;;;;;\n1CC2C;SEPARATED BLOCK QUADRANT-34;So;0;ON;;;;;N;;;;;\n1CC2D;SEPARATED BLOCK QUADRANT-134;So;0;ON;;;;;N;;;;;\n1CC2E;SEPARATED BLOCK QUADRANT-234;So;0;ON;;;;;N;;;;;\n1CC2F;SEPARATED BLOCK QUADRANT-1234;So;0;ON;;;;;N;;;;;\n1CC30;UPPER LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC31;UPPER CENTRE LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC32;UPPER CENTRE RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC33;UPPER RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC34;UPPER MIDDLE LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC35;UPPER LEFT QUARTER CIRCLE;So;0;ON;;;;;N;;;;;\n1CC36;UPPER RIGHT QUARTER CIRCLE;So;0;ON;;;;;N;;;;;\n1CC37;UPPER MIDDLE RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC38;LOWER MIDDLE LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC39;LOWER LEFT QUARTER CIRCLE;So;0;ON;;;;;N;;;;;\n1CC3A;LOWER RIGHT QUARTER CIRCLE;So;0;ON;;;;;N;;;;;\n1CC3B;LOWER MIDDLE RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC3C;LOWER LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC3D;LOWER CENTRE LEFT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC3E;LOWER CENTRE RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC3F;LOWER RIGHT TWELFTH CIRCLE;So;0;ON;;;;;N;;;;;\n1CC40;SPARSE HORIZONTAL FILL;So;0;ON;;;;;N;;;;;\n1CC41;SPARSE VERTICAL FILL;So;0;ON;;;;;N;;;;;\n1CC42;ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;\n1CC43;DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;\n1CC44;DENSE VERTICAL FILL;So;0;ON;;;;;N;;;;;\n1CC45;DENSE HORIZONTAL FILL;So;0;ON;;;;;N;;;;;\n1CC46;SPECKLE FILL FRAME-1;So;0;ON;;;;;N;;;;;\n1CC47;SPECKLE FILL FRAME-2;So;0;ON;;;;;N;;;;;\n1CC48;LEFT-FACING BASSINET;So;0;ON;;;;;N;;;;;\n1CC49;RIGHT-FACING BASSINET;So;0;ON;;;;;N;;;;;\n1CC4A;FLYING SAUCER WITH BEAMS;So;0;ON;;;;;N;;;;;\n1CC4B;FLYING SAUCER WITHOUT BEAMS;So;0;ON;;;;;N;;;;;\n1CC4C;ALIEN MONSTER OPEN JAWS;So;0;ON;;;;;N;;;;;\n1CC4D;ALIEN MONSTER CLOSED JAWS;So;0;ON;;;;;N;;;;;\n1CC4E;ALIEN SQUID OPEN TENTACLES;So;0;ON;;;;;N;;;;;\n1CC4F;ALIEN SQUID CLOSED TENTACLES;So;0;ON;;;;;N;;;;;\n1CC50;ALIEN CRAB STEPPING RIGHT;So;0;ON;;;;;N;;;;;\n1CC51;ALIEN CRAB STEPPING LEFT;So;0;ON;;;;;N;;;;;\n1CC52;ALIEN SPIDER CROUCHING;So;0;ON;;;;;N;;;;;\n1CC53;ALIEN SPIDER SPREAD;So;0;ON;;;;;N;;;;;\n1CC54;ALIEN MONSTER STEP-1;So;0;ON;;;;;N;;;;;\n1CC55;ALIEN MONSTER STEP-2;So;0;ON;;;;;N;;;;;\n1CC56;LEFT-POINTING ROCKET SHIP;So;0;ON;;;;;N;;;;;\n1CC57;UP-POINTING ROCKET SHIP;So;0;ON;;;;;N;;;;;\n1CC58;RIGHT-POINTING ROCKET SHIP;So;0;ON;;;;;N;;;;;\n1CC59;DOWN-POINTING ROCKET SHIP;So;0;ON;;;;;N;;;;;\n1CC5A;TOP HALF LEFT-FACING ROBOT;So;0;ON;;;;;N;;;;;\n1CC5B;TOP HALF FORWARD-FACING ROBOT;So;0;ON;;;;;N;;;;;\n1CC5C;TOP HALF RIGHT-FACING ROBOT;So;0;ON;;;;;N;;;;;\n1CC5D;BOTTOM HALF LEFT-FACING ROBOT;So;0;ON;;;;;N;;;;;\n1CC5E;BOTTOM HALF FORWARD-FACING ROBOT;So;0;ON;;;;;N;;;;;\n1CC5F;BOTTOM HALF RIGHT-FACING ROBOT;So;0;ON;;;;;N;;;;;\n1CC60;LEFT-POINTING ATOMIC BOMB;So;0;ON;;;;;N;;;;;\n1CC61;UP-POINTING ATOMIC BOMB;So;0;ON;;;;;N;;;;;\n1CC62;RIGHT-POINTING ATOMIC BOMB;So;0;ON;;;;;N;;;;;\n1CC63;DOWN-POINTING ATOMIC BOMB;So;0;ON;;;;;N;;;;;\n1CC64;MUSHROOM CLOUD;So;0;ON;;;;;N;;;;;\n1CC65;LEFT-POINTING RIFLE;So;0;ON;;;;;N;;;;;\n1CC66;UP-POINTING RIFLE;So;0;ON;;;;;N;;;;;\n1CC67;RIGHT-POINTING RIFLE;So;0;ON;;;;;N;;;;;\n1CC68;DOWN-POINTING RIFLE;So;0;ON;;;;;N;;;;;\n1CC69;EIGHT RAYS INWARD;So;0;ON;;;;;N;;;;;\n1CC6A;EIGHT RAYS OUTWARD;So;0;ON;;;;;N;;;;;\n1CC6B;BLACK LARGE CIRCLE MINUS LEFT QUARTER SECTION;So;0;ON;;;;;N;;;;;\n1CC6C;BLACK LARGE CIRCLE MINUS UPPER QUARTER SECTION;So;0;ON;;;;;N;;;;;\n1CC6D;BLACK LARGE CIRCLE MINUS RIGHT QUARTER SECTION;So;0;ON;;;;;N;;;;;\n1CC6E;BLACK LARGE CIRCLE MINUS LOWER QUARTER SECTION;So;0;ON;;;;;N;;;;;\n1CC6F;BLACK NEUTRAL FACE;So;0;ON;;;;;N;;;;;\n1CC70;LEFT-FACING SNAKE HEAD WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1CC71;UP-FACING SNAKE HEAD WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1CC72;RIGHT-FACING SNAKE HEAD WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1CC73;DOWN-FACING SNAKE HEAD WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1CC74;LEFT-FACING SNAKE HEAD WITH CLOSED MOUTH;So;0;ON;;;;;N;;;;;\n1CC75;UP-FACING SNAKE HEAD WITH CLOSED MOUTH;So;0;ON;;;;;N;;;;;\n1CC76;RIGHT-FACING SNAKE HEAD WITH CLOSED MOUTH;So;0;ON;;;;;N;;;;;\n1CC77;DOWN-FACING SNAKE HEAD WITH CLOSED MOUTH;So;0;ON;;;;;N;;;;;\n1CC78;LEFT-POINTING ENERGY WAVE;So;0;ON;;;;;N;;;;;\n1CC79;UP-POINTING ENERGY WAVE;So;0;ON;;;;;N;;;;;\n1CC7A;RIGHT-POINTING ENERGY WAVE;So;0;ON;;;;;N;;;;;\n1CC7B;DOWN-POINTING ENERGY WAVE;So;0;ON;;;;;N;;;;;\n1CC7C;SQUARE SPIRAL FROM TOP LEFT;So;0;ON;;;;;N;;;;;\n1CC7D;SQUARE SPIRAL FROM TOP RIGHT;So;0;ON;;;;;N;;;;;\n1CC7E;SQUARE SPIRAL FROM BOTTOM RIGHT;So;0;ON;;;;;N;;;;;\n1CC7F;SQUARE SPIRAL FROM BOTTOM LEFT;So;0;ON;;;;;N;;;;;\n1CC80;STRIPED LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n1CC81;STRIPED UP-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n1CC82;STRIPED RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n1CC83;STRIPED DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;\n1CC84;VERTICAL LADDER;So;0;ON;;;;;N;;;;;\n1CC85;HORIZONTAL LADDER;So;0;ON;;;;;N;;;;;\n1CC86;WHITE LOWER LEFT POINTER;So;0;ON;;;;;N;;;;;\n1CC87;WHITE LOWER RIGHT POINTER;So;0;ON;;;;;N;;;;;\n1CC88;TWO RINGS ALIGNED HORIZONTALLY;So;0;ON;;;;;N;;;;;\n1CC89;SQUARE FOUR CORNER SALTIRES;So;0;ON;;;;;N;;;;;\n1CC8A;SQUARE FOUR CORNER DIAGONALS;So;0;ON;;;;;N;;;;;\n1CC8B;SQUARE FOUR CORNER BLACK TRIANGLES;So;0;ON;;;;;N;;;;;\n1CC8C;SQUARE APERTURE;So;0;ON;;;;;N;;;;;\n1CC8D;INVERSE BLACK DIAMOND;So;0;ON;;;;;N;;;;;\n1CC8E;LEFT AND UPPER ONE EIGHTH BLOCK CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;\n1CC8F;INVERSE BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;\n1CC90;VERTICAL LINE WITH FOUR TICK MARKS;So;0;ON;;;;;N;;;;;\n1CC91;HORIZONTAL LINE WITH FOUR TICK MARKS;So;0;ON;;;;;N;;;;;\n1CC92;LEFT-FACING FISH;So;0;ON;;;;;N;;;;;\n1CC93;RIGHT-FACING FISH;So;0;ON;;;;;N;;;;;\n1CC94;LEFT-FACING FISH WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1CC95;RIGHT-FACING FISH WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1CC96;FLAPPING BIRD;So;0;ON;;;;;N;;;;;\n1CC97;LEFT-POINTING RACING CAR;So;0;ON;;;;;N;;;;;\n1CC98;UP-POINTING RACING CAR;So;0;ON;;;;;N;;;;;\n1CC99;RIGHT-POINTING RACING CAR;So;0;ON;;;;;N;;;;;\n1CC9A;DOWN-POINTING RACING CAR;So;0;ON;;;;;N;;;;;\n1CC9B;HORIZONTAL RACING CAR;So;0;ON;;;;;N;;;;;\n1CC9C;VERTICAL RACING CAR;So;0;ON;;;;;N;;;;;\n1CC9D;VERTICAL GO-KART;So;0;ON;;;;;N;;;;;\n1CC9E;LEFT-POINTING TANK;So;0;ON;;;;;N;;;;;\n1CC9F;RIGHT-POINTING TANK;So;0;ON;;;;;N;;;;;\n1CCA0;LEFT-POINTING ROCKET BOOSTER;So;0;ON;;;;;N;;;;;\n1CCA1;RIGHT-POINTING ROCKET BOOSTER;So;0;ON;;;;;N;;;;;\n1CCA2;LEFT-POINTING ROLLER COASTER CAR;So;0;ON;;;;;N;;;;;\n1CCA3;RIGHT-POINTING ROLLER COASTER CAR;So;0;ON;;;;;N;;;;;\n1CCA4;LEFT HALF FLYING SAUCER;So;0;ON;;;;;N;;;;;\n1CCA5;RIGHT HALF FLYING SAUCER;So;0;ON;;;;;N;;;;;\n1CCA6;UPPER LEFT QUADRANT FACE WITH OPEN EYES;So;0;ON;;;;;N;;;;;\n1CCA7;UPPER RIGHT QUADRANT FACE WITH OPEN EYES;So;0;ON;;;;;N;;;;;\n1CCA8;UPPER LEFT QUADRANT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;;\n1CCA9;UPPER RIGHT QUADRANT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;;\n1CCAA;LOWER LEFT QUADRANT SMILING FACE;So;0;ON;;;;;N;;;;;\n1CCAB;LOWER RIGHT QUADRANT SMILING FACE;So;0;ON;;;;;N;;;;;\n1CCAC;LOWER LEFT QUADRANT NEUTRAL FACE;So;0;ON;;;;;N;;;;;\n1CCAD;LOWER RIGHT QUADRANT NEUTRAL FACE;So;0;ON;;;;;N;;;;;\n1CCAE;LOWER LEFT QUADRANT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1CCAF;LOWER RIGHT QUADRANT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1CCB0;LOWER LEFT QUADRANT FROWNING FACE;So;0;ON;;;;;N;;;;;\n1CCB1;LOWER RIGHT QUADRANT FROWNING FACE;So;0;ON;;;;;N;;;;;\n1CCB2;UPPER LEFT QUADRANT TELEVISION;So;0;ON;;;;;N;;;;;\n1CCB3;UPPER RIGHT QUADRANT TELEVISION;So;0;ON;;;;;N;;;;;\n1CCB4;LOWER LEFT QUADRANT TELEVISION;So;0;ON;;;;;N;;;;;\n1CCB5;LOWER RIGHT QUADRANT TELEVISION;So;0;ON;;;;;N;;;;;\n1CCB6;UPPER LEFT QUADRANT MICROCOMPUTER;So;0;ON;;;;;N;;;;;\n1CCB7;UPPER RIGHT QUADRANT MICROCOMPUTER;So;0;ON;;;;;N;;;;;\n1CCB8;LOWER LEFT QUADRANT MICROCOMPUTER;So;0;ON;;;;;N;;;;;\n1CCB9;LOWER RIGHT QUADRANT MICROCOMPUTER;So;0;ON;;;;;N;;;;;\n1CCBA;UPPER LEFT QUADRANT CHESS KING;So;0;ON;;;;;N;;;;;\n1CCBB;UPPER RIGHT QUADRANT CHESS KING;So;0;ON;;;;;N;;;;;\n1CCBC;LOWER LEFT QUADRANT CHESS KING;So;0;ON;;;;;N;;;;;\n1CCBD;LOWER RIGHT QUADRANT CHESS KING;So;0;ON;;;;;N;;;;;\n1CCBE;UPPER LEFT QUADRANT CHESS QUEEN;So;0;ON;;;;;N;;;;;\n1CCBF;UPPER RIGHT QUADRANT CHESS QUEEN;So;0;ON;;;;;N;;;;;\n1CCC0;LOWER LEFT QUADRANT CHESS QUEEN;So;0;ON;;;;;N;;;;;\n1CCC1;LOWER RIGHT QUADRANT CHESS QUEEN;So;0;ON;;;;;N;;;;;\n1CCC2;UPPER LEFT QUADRANT CHESS ROOK;So;0;ON;;;;;N;;;;;\n1CCC3;UPPER RIGHT QUADRANT CHESS ROOK;So;0;ON;;;;;N;;;;;\n1CCC4;LOWER LEFT QUADRANT CHESS ROOK;So;0;ON;;;;;N;;;;;\n1CCC5;LOWER RIGHT QUADRANT CHESS ROOK;So;0;ON;;;;;N;;;;;\n1CCC6;UPPER LEFT QUADRANT CHESS BISHOP;So;0;ON;;;;;N;;;;;\n1CCC7;UPPER RIGHT QUADRANT CHESS BISHOP;So;0;ON;;;;;N;;;;;\n1CCC8;LOWER LEFT QUADRANT CHESS BISHOP;So;0;ON;;;;;N;;;;;\n1CCC9;LOWER RIGHT QUADRANT CHESS BISHOP;So;0;ON;;;;;N;;;;;\n1CCCA;UPPER LEFT QUADRANT CHESS KNIGHT;So;0;ON;;;;;N;;;;;\n1CCCB;UPPER RIGHT QUADRANT CHESS KNIGHT;So;0;ON;;;;;N;;;;;\n1CCCC;LOWER LEFT QUADRANT CHESS KNIGHT;So;0;ON;;;;;N;;;;;\n1CCCD;LOWER RIGHT QUADRANT CHESS KNIGHT;So;0;ON;;;;;N;;;;;\n1CCCE;UPPER LEFT QUADRANT CHESS PAWN;So;0;ON;;;;;N;;;;;\n1CCCF;UPPER RIGHT QUADRANT CHESS PAWN;So;0;ON;;;;;N;;;;;\n1CCD0;LOWER LEFT QUADRANT CHESS PAWN;So;0;ON;;;;;N;;;;;\n1CCD1;LOWER RIGHT QUADRANT CHESS PAWN;So;0;ON;;;;;N;;;;;\n1CCD2;UPPER LEFT QUADRANT STANDING KNIGHT;So;0;ON;;;;;N;;;;;\n1CCD3;UPPER RIGHT QUADRANT STANDING KNIGHT;So;0;ON;;;;;N;;;;;\n1CCD4;LOWER LEFT QUADRANT STANDING KNIGHT;So;0;ON;;;;;N;;;;;\n1CCD5;LOWER RIGHT QUADRANT STANDING KNIGHT;So;0;ON;;;;;N;;;;;\n1CCD6;OUTLINED LATIN CAPITAL LETTER A;So;0;L;<font> 0041;;;;N;;;;;\n1CCD7;OUTLINED LATIN CAPITAL LETTER B;So;0;L;<font> 0042;;;;N;;;;;\n1CCD8;OUTLINED LATIN CAPITAL LETTER C;So;0;L;<font> 0043;;;;N;;;;;\n1CCD9;OUTLINED LATIN CAPITAL LETTER D;So;0;L;<font> 0044;;;;N;;;;;\n1CCDA;OUTLINED LATIN CAPITAL LETTER E;So;0;L;<font> 0045;;;;N;;;;;\n1CCDB;OUTLINED LATIN CAPITAL LETTER F;So;0;L;<font> 0046;;;;N;;;;;\n1CCDC;OUTLINED LATIN CAPITAL LETTER G;So;0;L;<font> 0047;;;;N;;;;;\n1CCDD;OUTLINED LATIN CAPITAL LETTER H;So;0;L;<font> 0048;;;;N;;;;;\n1CCDE;OUTLINED LATIN CAPITAL LETTER I;So;0;L;<font> 0049;;;;N;;;;;\n1CCDF;OUTLINED LATIN CAPITAL LETTER J;So;0;L;<font> 004A;;;;N;;;;;\n1CCE0;OUTLINED LATIN CAPITAL LETTER K;So;0;L;<font> 004B;;;;N;;;;;\n1CCE1;OUTLINED LATIN CAPITAL LETTER L;So;0;L;<font> 004C;;;;N;;;;;\n1CCE2;OUTLINED LATIN CAPITAL LETTER M;So;0;L;<font> 004D;;;;N;;;;;\n1CCE3;OUTLINED LATIN CAPITAL LETTER N;So;0;L;<font> 004E;;;;N;;;;;\n1CCE4;OUTLINED LATIN CAPITAL LETTER O;So;0;L;<font> 004F;;;;N;;;;;\n1CCE5;OUTLINED LATIN CAPITAL LETTER P;So;0;L;<font> 0050;;;;N;;;;;\n1CCE6;OUTLINED LATIN CAPITAL LETTER Q;So;0;L;<font> 0051;;;;N;;;;;\n1CCE7;OUTLINED LATIN CAPITAL LETTER R;So;0;L;<font> 0052;;;;N;;;;;\n1CCE8;OUTLINED LATIN CAPITAL LETTER S;So;0;L;<font> 0053;;;;N;;;;;\n1CCE9;OUTLINED LATIN CAPITAL LETTER T;So;0;L;<font> 0054;;;;N;;;;;\n1CCEA;OUTLINED LATIN CAPITAL LETTER U;So;0;L;<font> 0055;;;;N;;;;;\n1CCEB;OUTLINED LATIN CAPITAL LETTER V;So;0;L;<font> 0056;;;;N;;;;;\n1CCEC;OUTLINED LATIN CAPITAL LETTER W;So;0;L;<font> 0057;;;;N;;;;;\n1CCED;OUTLINED LATIN CAPITAL LETTER X;So;0;L;<font> 0058;;;;N;;;;;\n1CCEE;OUTLINED LATIN CAPITAL LETTER Y;So;0;L;<font> 0059;;;;N;;;;;\n1CCEF;OUTLINED LATIN CAPITAL LETTER Z;So;0;L;<font> 005A;;;;N;;;;;\n1CCF0;OUTLINED DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;\n1CCF1;OUTLINED DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;\n1CCF2;OUTLINED DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;\n1CCF3;OUTLINED DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;\n1CCF4;OUTLINED DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;\n1CCF5;OUTLINED DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;\n1CCF6;OUTLINED DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;\n1CCF7;OUTLINED DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;\n1CCF8;OUTLINED DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;\n1CCF9;OUTLINED DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;\n1CCFA;SNAKE SYMBOL;So;0;ON;;;;;N;;;;;\n1CCFB;FLYING SAUCER SYMBOL;So;0;ON;;;;;N;;;;;\n1CCFC;NOSE SYMBOL;So;0;ON;;;;;N;;;;;\n1CD00;BLOCK OCTANT-3;So;0;ON;;;;;N;;;;;\n1CD01;BLOCK OCTANT-23;So;0;ON;;;;;N;;;;;\n1CD02;BLOCK OCTANT-123;So;0;ON;;;;;N;;;;;\n1CD03;BLOCK OCTANT-4;So;0;ON;;;;;N;;;;;\n1CD04;BLOCK OCTANT-14;So;0;ON;;;;;N;;;;;\n1CD05;BLOCK OCTANT-124;So;0;ON;;;;;N;;;;;\n1CD06;BLOCK OCTANT-34;So;0;ON;;;;;N;;;;;\n1CD07;BLOCK OCTANT-134;So;0;ON;;;;;N;;;;;\n1CD08;BLOCK OCTANT-234;So;0;ON;;;;;N;;;;;\n1CD09;BLOCK OCTANT-5;So;0;ON;;;;;N;;;;;\n1CD0A;BLOCK OCTANT-15;So;0;ON;;;;;N;;;;;\n1CD0B;BLOCK OCTANT-25;So;0;ON;;;;;N;;;;;\n1CD0C;BLOCK OCTANT-125;So;0;ON;;;;;N;;;;;\n1CD0D;BLOCK OCTANT-135;So;0;ON;;;;;N;;;;;\n1CD0E;BLOCK OCTANT-235;So;0;ON;;;;;N;;;;;\n1CD0F;BLOCK OCTANT-1235;So;0;ON;;;;;N;;;;;\n1CD10;BLOCK OCTANT-45;So;0;ON;;;;;N;;;;;\n1CD11;BLOCK OCTANT-145;So;0;ON;;;;;N;;;;;\n1CD12;BLOCK OCTANT-245;So;0;ON;;;;;N;;;;;\n1CD13;BLOCK OCTANT-1245;So;0;ON;;;;;N;;;;;\n1CD14;BLOCK OCTANT-345;So;0;ON;;;;;N;;;;;\n1CD15;BLOCK OCTANT-1345;So;0;ON;;;;;N;;;;;\n1CD16;BLOCK OCTANT-2345;So;0;ON;;;;;N;;;;;\n1CD17;BLOCK OCTANT-12345;So;0;ON;;;;;N;;;;;\n1CD18;BLOCK OCTANT-6;So;0;ON;;;;;N;;;;;\n1CD19;BLOCK OCTANT-16;So;0;ON;;;;;N;;;;;\n1CD1A;BLOCK OCTANT-26;So;0;ON;;;;;N;;;;;\n1CD1B;BLOCK OCTANT-126;So;0;ON;;;;;N;;;;;\n1CD1C;BLOCK OCTANT-36;So;0;ON;;;;;N;;;;;\n1CD1D;BLOCK OCTANT-136;So;0;ON;;;;;N;;;;;\n1CD1E;BLOCK OCTANT-236;So;0;ON;;;;;N;;;;;\n1CD1F;BLOCK OCTANT-1236;So;0;ON;;;;;N;;;;;\n1CD20;BLOCK OCTANT-146;So;0;ON;;;;;N;;;;;\n1CD21;BLOCK OCTANT-246;So;0;ON;;;;;N;;;;;\n1CD22;BLOCK OCTANT-1246;So;0;ON;;;;;N;;;;;\n1CD23;BLOCK OCTANT-346;So;0;ON;;;;;N;;;;;\n1CD24;BLOCK OCTANT-1346;So;0;ON;;;;;N;;;;;\n1CD25;BLOCK OCTANT-2346;So;0;ON;;;;;N;;;;;\n1CD26;BLOCK OCTANT-12346;So;0;ON;;;;;N;;;;;\n1CD27;BLOCK OCTANT-56;So;0;ON;;;;;N;;;;;\n1CD28;BLOCK OCTANT-156;So;0;ON;;;;;N;;;;;\n1CD29;BLOCK OCTANT-256;So;0;ON;;;;;N;;;;;\n1CD2A;BLOCK OCTANT-1256;So;0;ON;;;;;N;;;;;\n1CD2B;BLOCK OCTANT-356;So;0;ON;;;;;N;;;;;\n1CD2C;BLOCK OCTANT-1356;So;0;ON;;;;;N;;;;;\n1CD2D;BLOCK OCTANT-2356;So;0;ON;;;;;N;;;;;\n1CD2E;BLOCK OCTANT-12356;So;0;ON;;;;;N;;;;;\n1CD2F;BLOCK OCTANT-456;So;0;ON;;;;;N;;;;;\n1CD30;BLOCK OCTANT-1456;So;0;ON;;;;;N;;;;;\n1CD31;BLOCK OCTANT-2456;So;0;ON;;;;;N;;;;;\n1CD32;BLOCK OCTANT-12456;So;0;ON;;;;;N;;;;;\n1CD33;BLOCK OCTANT-3456;So;0;ON;;;;;N;;;;;\n1CD34;BLOCK OCTANT-13456;So;0;ON;;;;;N;;;;;\n1CD35;BLOCK OCTANT-23456;So;0;ON;;;;;N;;;;;\n1CD36;BLOCK OCTANT-17;So;0;ON;;;;;N;;;;;\n1CD37;BLOCK OCTANT-27;So;0;ON;;;;;N;;;;;\n1CD38;BLOCK OCTANT-127;So;0;ON;;;;;N;;;;;\n1CD39;BLOCK OCTANT-37;So;0;ON;;;;;N;;;;;\n1CD3A;BLOCK OCTANT-137;So;0;ON;;;;;N;;;;;\n1CD3B;BLOCK OCTANT-237;So;0;ON;;;;;N;;;;;\n1CD3C;BLOCK OCTANT-1237;So;0;ON;;;;;N;;;;;\n1CD3D;BLOCK OCTANT-47;So;0;ON;;;;;N;;;;;\n1CD3E;BLOCK OCTANT-147;So;0;ON;;;;;N;;;;;\n1CD3F;BLOCK OCTANT-247;So;0;ON;;;;;N;;;;;\n1CD40;BLOCK OCTANT-1247;So;0;ON;;;;;N;;;;;\n1CD41;BLOCK OCTANT-347;So;0;ON;;;;;N;;;;;\n1CD42;BLOCK OCTANT-1347;So;0;ON;;;;;N;;;;;\n1CD43;BLOCK OCTANT-2347;So;0;ON;;;;;N;;;;;\n1CD44;BLOCK OCTANT-12347;So;0;ON;;;;;N;;;;;\n1CD45;BLOCK OCTANT-157;So;0;ON;;;;;N;;;;;\n1CD46;BLOCK OCTANT-257;So;0;ON;;;;;N;;;;;\n1CD47;BLOCK OCTANT-1257;So;0;ON;;;;;N;;;;;\n1CD48;BLOCK OCTANT-357;So;0;ON;;;;;N;;;;;\n1CD49;BLOCK OCTANT-2357;So;0;ON;;;;;N;;;;;\n1CD4A;BLOCK OCTANT-12357;So;0;ON;;;;;N;;;;;\n1CD4B;BLOCK OCTANT-457;So;0;ON;;;;;N;;;;;\n1CD4C;BLOCK OCTANT-1457;So;0;ON;;;;;N;;;;;\n1CD4D;BLOCK OCTANT-12457;So;0;ON;;;;;N;;;;;\n1CD4E;BLOCK OCTANT-3457;So;0;ON;;;;;N;;;;;\n1CD4F;BLOCK OCTANT-13457;So;0;ON;;;;;N;;;;;\n1CD50;BLOCK OCTANT-23457;So;0;ON;;;;;N;;;;;\n1CD51;BLOCK OCTANT-67;So;0;ON;;;;;N;;;;;\n1CD52;BLOCK OCTANT-167;So;0;ON;;;;;N;;;;;\n1CD53;BLOCK OCTANT-267;So;0;ON;;;;;N;;;;;\n1CD54;BLOCK OCTANT-1267;So;0;ON;;;;;N;;;;;\n1CD55;BLOCK OCTANT-367;So;0;ON;;;;;N;;;;;\n1CD56;BLOCK OCTANT-1367;So;0;ON;;;;;N;;;;;\n1CD57;BLOCK OCTANT-2367;So;0;ON;;;;;N;;;;;\n1CD58;BLOCK OCTANT-12367;So;0;ON;;;;;N;;;;;\n1CD59;BLOCK OCTANT-467;So;0;ON;;;;;N;;;;;\n1CD5A;BLOCK OCTANT-1467;So;0;ON;;;;;N;;;;;\n1CD5B;BLOCK OCTANT-2467;So;0;ON;;;;;N;;;;;\n1CD5C;BLOCK OCTANT-12467;So;0;ON;;;;;N;;;;;\n1CD5D;BLOCK OCTANT-3467;So;0;ON;;;;;N;;;;;\n1CD5E;BLOCK OCTANT-13467;So;0;ON;;;;;N;;;;;\n1CD5F;BLOCK OCTANT-23467;So;0;ON;;;;;N;;;;;\n1CD60;BLOCK OCTANT-123467;So;0;ON;;;;;N;;;;;\n1CD61;BLOCK OCTANT-567;So;0;ON;;;;;N;;;;;\n1CD62;BLOCK OCTANT-1567;So;0;ON;;;;;N;;;;;\n1CD63;BLOCK OCTANT-2567;So;0;ON;;;;;N;;;;;\n1CD64;BLOCK OCTANT-12567;So;0;ON;;;;;N;;;;;\n1CD65;BLOCK OCTANT-3567;So;0;ON;;;;;N;;;;;\n1CD66;BLOCK OCTANT-13567;So;0;ON;;;;;N;;;;;\n1CD67;BLOCK OCTANT-23567;So;0;ON;;;;;N;;;;;\n1CD68;BLOCK OCTANT-123567;So;0;ON;;;;;N;;;;;\n1CD69;BLOCK OCTANT-4567;So;0;ON;;;;;N;;;;;\n1CD6A;BLOCK OCTANT-14567;So;0;ON;;;;;N;;;;;\n1CD6B;BLOCK OCTANT-24567;So;0;ON;;;;;N;;;;;\n1CD6C;BLOCK OCTANT-124567;So;0;ON;;;;;N;;;;;\n1CD6D;BLOCK OCTANT-34567;So;0;ON;;;;;N;;;;;\n1CD6E;BLOCK OCTANT-134567;So;0;ON;;;;;N;;;;;\n1CD6F;BLOCK OCTANT-234567;So;0;ON;;;;;N;;;;;\n1CD70;BLOCK OCTANT-1234567;So;0;ON;;;;;N;;;;;\n1CD71;BLOCK OCTANT-18;So;0;ON;;;;;N;;;;;\n1CD72;BLOCK OCTANT-28;So;0;ON;;;;;N;;;;;\n1CD73;BLOCK OCTANT-128;So;0;ON;;;;;N;;;;;\n1CD74;BLOCK OCTANT-38;So;0;ON;;;;;N;;;;;\n1CD75;BLOCK OCTANT-138;So;0;ON;;;;;N;;;;;\n1CD76;BLOCK OCTANT-238;So;0;ON;;;;;N;;;;;\n1CD77;BLOCK OCTANT-1238;So;0;ON;;;;;N;;;;;\n1CD78;BLOCK OCTANT-48;So;0;ON;;;;;N;;;;;\n1CD79;BLOCK OCTANT-148;So;0;ON;;;;;N;;;;;\n1CD7A;BLOCK OCTANT-248;So;0;ON;;;;;N;;;;;\n1CD7B;BLOCK OCTANT-1248;So;0;ON;;;;;N;;;;;\n1CD7C;BLOCK OCTANT-348;So;0;ON;;;;;N;;;;;\n1CD7D;BLOCK OCTANT-1348;So;0;ON;;;;;N;;;;;\n1CD7E;BLOCK OCTANT-2348;So;0;ON;;;;;N;;;;;\n1CD7F;BLOCK OCTANT-12348;So;0;ON;;;;;N;;;;;\n1CD80;BLOCK OCTANT-58;So;0;ON;;;;;N;;;;;\n1CD81;BLOCK OCTANT-158;So;0;ON;;;;;N;;;;;\n1CD82;BLOCK OCTANT-258;So;0;ON;;;;;N;;;;;\n1CD83;BLOCK OCTANT-1258;So;0;ON;;;;;N;;;;;\n1CD84;BLOCK OCTANT-358;So;0;ON;;;;;N;;;;;\n1CD85;BLOCK OCTANT-1358;So;0;ON;;;;;N;;;;;\n1CD86;BLOCK OCTANT-2358;So;0;ON;;;;;N;;;;;\n1CD87;BLOCK OCTANT-12358;So;0;ON;;;;;N;;;;;\n1CD88;BLOCK OCTANT-458;So;0;ON;;;;;N;;;;;\n1CD89;BLOCK OCTANT-1458;So;0;ON;;;;;N;;;;;\n1CD8A;BLOCK OCTANT-2458;So;0;ON;;;;;N;;;;;\n1CD8B;BLOCK OCTANT-12458;So;0;ON;;;;;N;;;;;\n1CD8C;BLOCK OCTANT-3458;So;0;ON;;;;;N;;;;;\n1CD8D;BLOCK OCTANT-13458;So;0;ON;;;;;N;;;;;\n1CD8E;BLOCK OCTANT-23458;So;0;ON;;;;;N;;;;;\n1CD8F;BLOCK OCTANT-123458;So;0;ON;;;;;N;;;;;\n1CD90;BLOCK OCTANT-168;So;0;ON;;;;;N;;;;;\n1CD91;BLOCK OCTANT-268;So;0;ON;;;;;N;;;;;\n1CD92;BLOCK OCTANT-1268;So;0;ON;;;;;N;;;;;\n1CD93;BLOCK OCTANT-368;So;0;ON;;;;;N;;;;;\n1CD94;BLOCK OCTANT-2368;So;0;ON;;;;;N;;;;;\n1CD95;BLOCK OCTANT-12368;So;0;ON;;;;;N;;;;;\n1CD96;BLOCK OCTANT-468;So;0;ON;;;;;N;;;;;\n1CD97;BLOCK OCTANT-1468;So;0;ON;;;;;N;;;;;\n1CD98;BLOCK OCTANT-12468;So;0;ON;;;;;N;;;;;\n1CD99;BLOCK OCTANT-3468;So;0;ON;;;;;N;;;;;\n1CD9A;BLOCK OCTANT-13468;So;0;ON;;;;;N;;;;;\n1CD9B;BLOCK OCTANT-23468;So;0;ON;;;;;N;;;;;\n1CD9C;BLOCK OCTANT-568;So;0;ON;;;;;N;;;;;\n1CD9D;BLOCK OCTANT-1568;So;0;ON;;;;;N;;;;;\n1CD9E;BLOCK OCTANT-2568;So;0;ON;;;;;N;;;;;\n1CD9F;BLOCK OCTANT-12568;So;0;ON;;;;;N;;;;;\n1CDA0;BLOCK OCTANT-3568;So;0;ON;;;;;N;;;;;\n1CDA1;BLOCK OCTANT-13568;So;0;ON;;;;;N;;;;;\n1CDA2;BLOCK OCTANT-23568;So;0;ON;;;;;N;;;;;\n1CDA3;BLOCK OCTANT-123568;So;0;ON;;;;;N;;;;;\n1CDA4;BLOCK OCTANT-4568;So;0;ON;;;;;N;;;;;\n1CDA5;BLOCK OCTANT-14568;So;0;ON;;;;;N;;;;;\n1CDA6;BLOCK OCTANT-24568;So;0;ON;;;;;N;;;;;\n1CDA7;BLOCK OCTANT-124568;So;0;ON;;;;;N;;;;;\n1CDA8;BLOCK OCTANT-34568;So;0;ON;;;;;N;;;;;\n1CDA9;BLOCK OCTANT-134568;So;0;ON;;;;;N;;;;;\n1CDAA;BLOCK OCTANT-234568;So;0;ON;;;;;N;;;;;\n1CDAB;BLOCK OCTANT-1234568;So;0;ON;;;;;N;;;;;\n1CDAC;BLOCK OCTANT-178;So;0;ON;;;;;N;;;;;\n1CDAD;BLOCK OCTANT-278;So;0;ON;;;;;N;;;;;\n1CDAE;BLOCK OCTANT-1278;So;0;ON;;;;;N;;;;;\n1CDAF;BLOCK OCTANT-378;So;0;ON;;;;;N;;;;;\n1CDB0;BLOCK OCTANT-1378;So;0;ON;;;;;N;;;;;\n1CDB1;BLOCK OCTANT-2378;So;0;ON;;;;;N;;;;;\n1CDB2;BLOCK OCTANT-12378;So;0;ON;;;;;N;;;;;\n1CDB3;BLOCK OCTANT-478;So;0;ON;;;;;N;;;;;\n1CDB4;BLOCK OCTANT-1478;So;0;ON;;;;;N;;;;;\n1CDB5;BLOCK OCTANT-2478;So;0;ON;;;;;N;;;;;\n1CDB6;BLOCK OCTANT-12478;So;0;ON;;;;;N;;;;;\n1CDB7;BLOCK OCTANT-3478;So;0;ON;;;;;N;;;;;\n1CDB8;BLOCK OCTANT-13478;So;0;ON;;;;;N;;;;;\n1CDB9;BLOCK OCTANT-23478;So;0;ON;;;;;N;;;;;\n1CDBA;BLOCK OCTANT-123478;So;0;ON;;;;;N;;;;;\n1CDBB;BLOCK OCTANT-578;So;0;ON;;;;;N;;;;;\n1CDBC;BLOCK OCTANT-1578;So;0;ON;;;;;N;;;;;\n1CDBD;BLOCK OCTANT-2578;So;0;ON;;;;;N;;;;;\n1CDBE;BLOCK OCTANT-12578;So;0;ON;;;;;N;;;;;\n1CDBF;BLOCK OCTANT-3578;So;0;ON;;;;;N;;;;;\n1CDC0;BLOCK OCTANT-13578;So;0;ON;;;;;N;;;;;\n1CDC1;BLOCK OCTANT-23578;So;0;ON;;;;;N;;;;;\n1CDC2;BLOCK OCTANT-123578;So;0;ON;;;;;N;;;;;\n1CDC3;BLOCK OCTANT-4578;So;0;ON;;;;;N;;;;;\n1CDC4;BLOCK OCTANT-14578;So;0;ON;;;;;N;;;;;\n1CDC5;BLOCK OCTANT-24578;So;0;ON;;;;;N;;;;;\n1CDC6;BLOCK OCTANT-124578;So;0;ON;;;;;N;;;;;\n1CDC7;BLOCK OCTANT-34578;So;0;ON;;;;;N;;;;;\n1CDC8;BLOCK OCTANT-134578;So;0;ON;;;;;N;;;;;\n1CDC9;BLOCK OCTANT-234578;So;0;ON;;;;;N;;;;;\n1CDCA;BLOCK OCTANT-1234578;So;0;ON;;;;;N;;;;;\n1CDCB;BLOCK OCTANT-678;So;0;ON;;;;;N;;;;;\n1CDCC;BLOCK OCTANT-1678;So;0;ON;;;;;N;;;;;\n1CDCD;BLOCK OCTANT-2678;So;0;ON;;;;;N;;;;;\n1CDCE;BLOCK OCTANT-12678;So;0;ON;;;;;N;;;;;\n1CDCF;BLOCK OCTANT-3678;So;0;ON;;;;;N;;;;;\n1CDD0;BLOCK OCTANT-13678;So;0;ON;;;;;N;;;;;\n1CDD1;BLOCK OCTANT-23678;So;0;ON;;;;;N;;;;;\n1CDD2;BLOCK OCTANT-123678;So;0;ON;;;;;N;;;;;\n1CDD3;BLOCK OCTANT-4678;So;0;ON;;;;;N;;;;;\n1CDD4;BLOCK OCTANT-14678;So;0;ON;;;;;N;;;;;\n1CDD5;BLOCK OCTANT-24678;So;0;ON;;;;;N;;;;;\n1CDD6;BLOCK OCTANT-124678;So;0;ON;;;;;N;;;;;\n1CDD7;BLOCK OCTANT-34678;So;0;ON;;;;;N;;;;;\n1CDD8;BLOCK OCTANT-134678;So;0;ON;;;;;N;;;;;\n1CDD9;BLOCK OCTANT-234678;So;0;ON;;;;;N;;;;;\n1CDDA;BLOCK OCTANT-1234678;So;0;ON;;;;;N;;;;;\n1CDDB;BLOCK OCTANT-15678;So;0;ON;;;;;N;;;;;\n1CDDC;BLOCK OCTANT-25678;So;0;ON;;;;;N;;;;;\n1CDDD;BLOCK OCTANT-125678;So;0;ON;;;;;N;;;;;\n1CDDE;BLOCK OCTANT-35678;So;0;ON;;;;;N;;;;;\n1CDDF;BLOCK OCTANT-235678;So;0;ON;;;;;N;;;;;\n1CDE0;BLOCK OCTANT-1235678;So;0;ON;;;;;N;;;;;\n1CDE1;BLOCK OCTANT-45678;So;0;ON;;;;;N;;;;;\n1CDE2;BLOCK OCTANT-145678;So;0;ON;;;;;N;;;;;\n1CDE3;BLOCK OCTANT-1245678;So;0;ON;;;;;N;;;;;\n1CDE4;BLOCK OCTANT-1345678;So;0;ON;;;;;N;;;;;\n1CDE5;BLOCK OCTANT-2345678;So;0;ON;;;;;N;;;;;\n1CDE6;TOP HALF STANDING PERSON;So;0;ON;;;;;N;;;;;\n1CDE7;BOTTOM HALF STANDING PERSON;So;0;ON;;;;;N;;;;;\n1CDE8;TOP HALF RIGHT-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;;\n1CDE9;BOTTOM HALF RIGHT-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;;\n1CDEA;TOP HALF RIGHT-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;;\n1CDEB;BOTTOM HALF RIGHT-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;;\n1CDEC;TOP HALF LEFT-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;;\n1CDED;BOTTOM HALF LEFT-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;;\n1CDEE;TOP HALF LEFT-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;;\n1CDEF;BOTTOM HALF LEFT-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;;\n1CDF0;TOP HALF FORWARD-FACING RUNNER;So;0;ON;;;;;N;;;;;\n1CDF1;BOTTOM HALF FORWARD-FACING RUNNER FRAME-1;So;0;ON;;;;;N;;;;;\n1CDF2;BOTTOM HALF FORWARD-FACING RUNNER FRAME-2;So;0;ON;;;;;N;;;;;\n1CDF3;BOTTOM HALF FORWARD-FACING RUNNER FRAME-3;So;0;ON;;;;;N;;;;;\n1CDF4;BOTTOM HALF FORWARD-FACING RUNNER FRAME-4;So;0;ON;;;;;N;;;;;\n1CDF5;MOON LANDER;So;0;ON;;;;;N;;;;;\n1CDF6;TOP HALF FLAILING ROBOT FRAME-1;So;0;ON;;;;;N;;;;;\n1CDF7;TOP HALF FLAILING ROBOT FRAME-2;So;0;ON;;;;;N;;;;;\n1CDF8;DOWN-POINTING AIRPLANE;So;0;ON;;;;;N;;;;;\n1CDF9;LEFT-POINTING AIRPLANE;So;0;ON;;;;;N;;;;;\n1CDFA;SMALL UP-POINTING AIRPLANE;So;0;ON;;;;;N;;;;;\n1CDFB;UP-POINTING FROG;So;0;ON;;;;;N;;;;;\n1CDFC;DOWN-POINTING FROG;So;0;ON;;;;;N;;;;;\n1CDFD;EXPLOSION FRAME-1;So;0;ON;;;;;N;;;;;\n1CDFE;EXPLOSION FRAME-2;So;0;ON;;;;;N;;;;;\n1CDFF;EXPLOSION FRAME-3;So;0;ON;;;;;N;;;;;\n1CE00;RIGHT HALF AND LEFT HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1CE01;LOWER HALF AND UPPER HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1CE02;EXPLOSION AT HORIZON;So;0;ON;;;;;N;;;;;\n1CE03;UPPER HALF HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;;\n1CE04;LOWER HALF HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;;\n1CE05;HEAVY WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;;\n1CE06;WHITE VERTICAL RECTANGLE WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;\n1CE07;TOP LEFT BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;;;;;\n1CE08;FUNNEL;So;0;ON;;;;;N;;;;;\n1CE09;BOX DRAWINGS DOUBLE DIAGONAL LOWER LEFT TO MIDDLE CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1CE0A;BOX DRAWINGS DOUBLE DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1CE0B;LEFT HALF WHITE ELLIPSE;So;0;ON;;;;;N;;;;;\n1CE0C;RIGHT HALF WHITE ELLIPSE;So;0;ON;;;;;N;;;;;\n1CE0D;LEFT HALF TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;;;;;\n1CE0E;RIGHT HALF TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;;;;;\n1CE0F;HORIZONTAL LINE WITH TICK MARK;So;0;ON;;;;;N;;;;;\n1CE10;LEFT HALF HORIZONTAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;;\n1CE11;RIGHT HALF HORIZONTAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;;\n1CE12;HORIZONTAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;;\n1CE13;LOWER HALF VERTICAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;;\n1CE14;UPPER HALF VERTICAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;;\n1CE15;VERTICAL LINE WITH THREE TICK MARKS;So;0;ON;;;;;N;;;;;\n1CE16;BOX DRAWINGS LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;;\n1CE17;BOX DRAWINGS LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;;\n1CE18;BOX DRAWINGS LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;;\n1CE19;BOX DRAWINGS LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;;\n1CE1A;LARGE TYPE PIECE UPPER LEFT ARC;So;0;ON;;;;;N;;;;;\n1CE1B;LARGE TYPE PIECE UPPER LEFT CORNER;So;0;ON;;;;;N;;;;;\n1CE1C;LARGE TYPE PIECE UPPER TERMINAL;So;0;ON;;;;;N;;;;;\n1CE1D;LARGE TYPE PIECE UPPER LEFT CROTCH;So;0;ON;;;;;N;;;;;\n1CE1E;LARGE TYPE PIECE LEFT ARM;So;0;ON;;;;;N;;;;;\n1CE1F;LARGE TYPE PIECE CROSSBAR;So;0;ON;;;;;N;;;;;\n1CE20;LARGE TYPE PIECE CROSSBAR WITH LOWER STEM;So;0;ON;;;;;N;;;;;\n1CE21;LARGE TYPE PIECE UPPER HALF VERTEX OF M;So;0;ON;;;;;N;;;;;\n1CE22;LARGE TYPE PIECE DIAGONAL LOWER LEFT;So;0;ON;;;;;N;;;;;\n1CE23;LARGE TYPE PIECE SHORT UPPER TERMINAL;So;0;ON;;;;;N;;;;;\n1CE24;LARGE TYPE PIECE UPPER RIGHT ARC;So;0;ON;;;;;N;;;;;\n1CE25;LARGE TYPE PIECE RIGHT ARM;So;0;ON;;;;;N;;;;;\n1CE26;LARGE TYPE PIECE UPPER RIGHT CROTCH;So;0;ON;;;;;N;;;;;\n1CE27;LARGE TYPE PIECE UPPER RIGHT CORNER;So;0;ON;;;;;N;;;;;\n1CE28;LARGE TYPE PIECE STEM WITH RIGHT CROSSBAR;So;0;ON;;;;;N;;;;;\n1CE29;LARGE TYPE PIECE STEM;So;0;ON;;;;;N;;;;;\n1CE2A;LARGE TYPE PIECE DIAGONAL UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1CE2B;LARGE TYPE PIECE DIAGONAL UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1CE2C;LARGE TYPE PIECE DIAGONAL LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1CE2D;LARGE TYPE PIECE SHORT LOWER TERMINAL;So;0;ON;;;;;N;;;;;\n1CE2E;LARGE TYPE PIECE LOWER LEFT AND UPPER LEFT ARC;So;0;ON;;;;;N;;;;;\n1CE2F;LARGE TYPE PIECE CENTRE OF K;So;0;ON;;;;;N;;;;;\n1CE30;LARGE TYPE PIECE LOWER HALF VERTEX OF M;So;0;ON;;;;;N;;;;;\n1CE31;LARGE TYPE PIECE UPPER HALF VERTEX OF W;So;0;ON;;;;;N;;;;;\n1CE32;LARGE TYPE PIECE CENTRE OF X;So;0;ON;;;;;N;;;;;\n1CE33;LARGE TYPE PIECE CENTRE OF Y;So;0;ON;;;;;N;;;;;\n1CE34;LARGE TYPE PIECE CENTRE OF Z WITH CROSSBAR;So;0;ON;;;;;N;;;;;\n1CE35;LARGE TYPE PIECE RAISED UPPER LEFT ARC;So;0;ON;;;;;N;;;;;\n1CE36;LARGE TYPE PIECE STEM WITH LEFT CROSSBAR;So;0;ON;;;;;N;;;;;\n1CE37;LARGE TYPE PIECE LOWER RIGHT AND UPPER RIGHT ARC;So;0;ON;;;;;N;;;;;\n1CE38;LARGE TYPE PIECE DIAGONAL UPPER LEFT AND LOWER LEFT;So;0;ON;;;;;N;;;;;\n1CE39;LARGE TYPE PIECE STEM WITH LEFT JOINT;So;0;ON;;;;;N;;;;;\n1CE3A;LARGE TYPE PIECE STEM WITH CROSSBAR;So;0;ON;;;;;N;;;;;\n1CE3B;LARGE TYPE PIECE DIAGONAL UPPER LEFT;So;0;ON;;;;;N;;;;;\n1CE3C;LARGE TYPE PIECE LOWER TERMINAL;So;0;ON;;;;;N;;;;;\n1CE3D;LARGE TYPE PIECE LOWER LEFT CORNER;So;0;ON;;;;;N;;;;;\n1CE3E;LARGE TYPE PIECE LOWER LEFT ARC;So;0;ON;;;;;N;;;;;\n1CE3F;LARGE TYPE PIECE LOWER LEFT CROTCH;So;0;ON;;;;;N;;;;;\n1CE40;LARGE TYPE PIECE CROSSBAR WITH UPPER STEM;So;0;ON;;;;;N;;;;;\n1CE41;LARGE TYPE PIECE VERTEX OF V;So;0;ON;;;;;N;;;;;\n1CE42;LARGE TYPE PIECE LOWER HALF VERTEX OF W;So;0;ON;;;;;N;;;;;\n1CE43;LARGE TYPE PIECE LOWER RIGHT ARC;So;0;ON;;;;;N;;;;;\n1CE44;LARGE TYPE PIECE LOWER RIGHT CORNER;So;0;ON;;;;;N;;;;;\n1CE45;LARGE TYPE PIECE LOWER RIGHT ARC WITH TAIL;So;0;ON;;;;;N;;;;;\n1CE46;LARGE TYPE PIECE LOWER RIGHT CROTCH;So;0;ON;;;;;N;;;;;\n1CE47;LARGE TYPE PIECE STEM-45;So;0;ON;;;;;N;;;;;\n1CE48;LARGE TYPE PIECE STEM-2345;So;0;ON;;;;;N;;;;;\n1CE49;LARGE TYPE PIECE STEM-4;So;0;ON;;;;;N;;;;;\n1CE4A;LARGE TYPE PIECE STEM-34;So;0;ON;;;;;N;;;;;\n1CE4B;LARGE TYPE PIECE STEM-234;So;0;ON;;;;;N;;;;;\n1CE4C;LARGE TYPE PIECE STEM-1234;So;0;ON;;;;;N;;;;;\n1CE4D;LARGE TYPE PIECE STEM-3;So;0;ON;;;;;N;;;;;\n1CE4E;LARGE TYPE PIECE STEM-23;So;0;ON;;;;;N;;;;;\n1CE4F;LARGE TYPE PIECE STEM-2;So;0;ON;;;;;N;;;;;\n1CE50;LARGE TYPE PIECE STEM-12;So;0;ON;;;;;N;;;;;\n1CE51;SEPARATED BLOCK SEXTANT-1;So;0;ON;;;;;N;;;;;\n1CE52;SEPARATED BLOCK SEXTANT-2;So;0;ON;;;;;N;;;;;\n1CE53;SEPARATED BLOCK SEXTANT-12;So;0;ON;;;;;N;;;;;\n1CE54;SEPARATED BLOCK SEXTANT-3;So;0;ON;;;;;N;;;;;\n1CE55;SEPARATED BLOCK SEXTANT-13;So;0;ON;;;;;N;;;;;\n1CE56;SEPARATED BLOCK SEXTANT-23;So;0;ON;;;;;N;;;;;\n1CE57;SEPARATED BLOCK SEXTANT-123;So;0;ON;;;;;N;;;;;\n1CE58;SEPARATED BLOCK SEXTANT-4;So;0;ON;;;;;N;;;;;\n1CE59;SEPARATED BLOCK SEXTANT-14;So;0;ON;;;;;N;;;;;\n1CE5A;SEPARATED BLOCK SEXTANT-24;So;0;ON;;;;;N;;;;;\n1CE5B;SEPARATED BLOCK SEXTANT-124;So;0;ON;;;;;N;;;;;\n1CE5C;SEPARATED BLOCK SEXTANT-34;So;0;ON;;;;;N;;;;;\n1CE5D;SEPARATED BLOCK SEXTANT-134;So;0;ON;;;;;N;;;;;\n1CE5E;SEPARATED BLOCK SEXTANT-234;So;0;ON;;;;;N;;;;;\n1CE5F;SEPARATED BLOCK SEXTANT-1234;So;0;ON;;;;;N;;;;;\n1CE60;SEPARATED BLOCK SEXTANT-5;So;0;ON;;;;;N;;;;;\n1CE61;SEPARATED BLOCK SEXTANT-15;So;0;ON;;;;;N;;;;;\n1CE62;SEPARATED BLOCK SEXTANT-25;So;0;ON;;;;;N;;;;;\n1CE63;SEPARATED BLOCK SEXTANT-125;So;0;ON;;;;;N;;;;;\n1CE64;SEPARATED BLOCK SEXTANT-35;So;0;ON;;;;;N;;;;;\n1CE65;SEPARATED BLOCK SEXTANT-135;So;0;ON;;;;;N;;;;;\n1CE66;SEPARATED BLOCK SEXTANT-235;So;0;ON;;;;;N;;;;;\n1CE67;SEPARATED BLOCK SEXTANT-1235;So;0;ON;;;;;N;;;;;\n1CE68;SEPARATED BLOCK SEXTANT-45;So;0;ON;;;;;N;;;;;\n1CE69;SEPARATED BLOCK SEXTANT-145;So;0;ON;;;;;N;;;;;\n1CE6A;SEPARATED BLOCK SEXTANT-245;So;0;ON;;;;;N;;;;;\n1CE6B;SEPARATED BLOCK SEXTANT-1245;So;0;ON;;;;;N;;;;;\n1CE6C;SEPARATED BLOCK SEXTANT-345;So;0;ON;;;;;N;;;;;\n1CE6D;SEPARATED BLOCK SEXTANT-1345;So;0;ON;;;;;N;;;;;\n1CE6E;SEPARATED BLOCK SEXTANT-2345;So;0;ON;;;;;N;;;;;\n1CE6F;SEPARATED BLOCK SEXTANT-12345;So;0;ON;;;;;N;;;;;\n1CE70;SEPARATED BLOCK SEXTANT-6;So;0;ON;;;;;N;;;;;\n1CE71;SEPARATED BLOCK SEXTANT-16;So;0;ON;;;;;N;;;;;\n1CE72;SEPARATED BLOCK SEXTANT-26;So;0;ON;;;;;N;;;;;\n1CE73;SEPARATED BLOCK SEXTANT-126;So;0;ON;;;;;N;;;;;\n1CE74;SEPARATED BLOCK SEXTANT-36;So;0;ON;;;;;N;;;;;\n1CE75;SEPARATED BLOCK SEXTANT-136;So;0;ON;;;;;N;;;;;\n1CE76;SEPARATED BLOCK SEXTANT-236;So;0;ON;;;;;N;;;;;\n1CE77;SEPARATED BLOCK SEXTANT-1236;So;0;ON;;;;;N;;;;;\n1CE78;SEPARATED BLOCK SEXTANT-46;So;0;ON;;;;;N;;;;;\n1CE79;SEPARATED BLOCK SEXTANT-146;So;0;ON;;;;;N;;;;;\n1CE7A;SEPARATED BLOCK SEXTANT-246;So;0;ON;;;;;N;;;;;\n1CE7B;SEPARATED BLOCK SEXTANT-1246;So;0;ON;;;;;N;;;;;\n1CE7C;SEPARATED BLOCK SEXTANT-346;So;0;ON;;;;;N;;;;;\n1CE7D;SEPARATED BLOCK SEXTANT-1346;So;0;ON;;;;;N;;;;;\n1CE7E;SEPARATED BLOCK SEXTANT-2346;So;0;ON;;;;;N;;;;;\n1CE7F;SEPARATED BLOCK SEXTANT-12346;So;0;ON;;;;;N;;;;;\n1CE80;SEPARATED BLOCK SEXTANT-56;So;0;ON;;;;;N;;;;;\n1CE81;SEPARATED BLOCK SEXTANT-156;So;0;ON;;;;;N;;;;;\n1CE82;SEPARATED BLOCK SEXTANT-256;So;0;ON;;;;;N;;;;;\n1CE83;SEPARATED BLOCK SEXTANT-1256;So;0;ON;;;;;N;;;;;\n1CE84;SEPARATED BLOCK SEXTANT-356;So;0;ON;;;;;N;;;;;\n1CE85;SEPARATED BLOCK SEXTANT-1356;So;0;ON;;;;;N;;;;;\n1CE86;SEPARATED BLOCK SEXTANT-2356;So;0;ON;;;;;N;;;;;\n1CE87;SEPARATED BLOCK SEXTANT-12356;So;0;ON;;;;;N;;;;;\n1CE88;SEPARATED BLOCK SEXTANT-456;So;0;ON;;;;;N;;;;;\n1CE89;SEPARATED BLOCK SEXTANT-1456;So;0;ON;;;;;N;;;;;\n1CE8A;SEPARATED BLOCK SEXTANT-2456;So;0;ON;;;;;N;;;;;\n1CE8B;SEPARATED BLOCK SEXTANT-12456;So;0;ON;;;;;N;;;;;\n1CE8C;SEPARATED BLOCK SEXTANT-3456;So;0;ON;;;;;N;;;;;\n1CE8D;SEPARATED BLOCK SEXTANT-13456;So;0;ON;;;;;N;;;;;\n1CE8E;SEPARATED BLOCK SEXTANT-23456;So;0;ON;;;;;N;;;;;\n1CE8F;SEPARATED BLOCK SEXTANT-123456;So;0;ON;;;;;N;;;;;\n1CE90;UPPER LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE91;UPPER CENTRE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE92;UPPER CENTRE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE93;UPPER RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE94;UPPER MIDDLE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE95;UPPER MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE96;UPPER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE97;UPPER MIDDLE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE98;LOWER MIDDLE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE99;LOWER MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE9A;LOWER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE9B;LOWER MIDDLE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE9C;LOWER LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE9D;LOWER CENTRE LEFT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE9E;LOWER CENTRE RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CE9F;LOWER RIGHT ONE SIXTEENTH BLOCK;So;0;ON;;;;;N;;;;;\n1CEA0;RIGHT HALF LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA1;RIGHT THREE QUARTERS LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA2;LEFT THREE QUARTERS LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA3;LEFT HALF LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA4;LOWER HALF LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA5;LOWER THREE QUARTERS LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA6;UPPER THREE QUARTERS LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA7;UPPER HALF LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA8;LEFT HALF UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEA9;LEFT THREE QUARTERS UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEAA;RIGHT THREE QUARTERS UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEAB;RIGHT HALF UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEAC;UPPER HALF RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEAD;UPPER THREE QUARTERS RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEAE;LOWER THREE QUARTERS RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEAF;LOWER HALF RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1CEB0;HORIZONTAL ZIGZAG LINE;So;0;ON;;;;;N;;;;;\n1CEB1;KEYHOLE;So;0;ON;;;;;N;;;;;\n1CEB2;OLD PERSONAL COMPUTER WITH MONITOR IN PORTRAIT ORIENTATION;So;0;ON;;;;;N;;;;;\n1CEB3;BLACK RIGHT TRIANGLE CARET;So;0;ON;;;;;N;;;;;\n1CEBA;FRAGILE SYMBOL;So;0;ON;;;;;N;;;;;\n1CEBB;OFFICE BUILDING SYMBOL;So;0;ON;;;;;N;;;;;\n1CEBC;TREE SYMBOL;So;0;ON;;;;;N;;;;;\n1CEBD;APPLE SYMBOL;So;0;ON;;;;;N;;;;;\n1CEBE;CHERRY SYMBOL;So;0;ON;;;;;N;;;;;\n1CEBF;STRAWBERRY SYMBOL;So;0;ON;;;;;N;;;;;\n1CEC0;HEBE;So;0;ON;;;;;N;;;;;\n1CEC1;IRIS;So;0;ON;;;;;N;;;;;\n1CEC2;FLORA;So;0;ON;;;;;N;;;;;\n1CEC3;METIS;So;0;ON;;;;;N;;;;;\n1CEC4;PARTHENOPE;So;0;ON;;;;;N;;;;;\n1CEC5;VICTORIA;So;0;ON;;;;;N;;;;;\n1CEC6;EGERIA;So;0;ON;;;;;N;;;;;\n1CEC7;IRENE;So;0;ON;;;;;N;;;;;\n1CEC8;EUNOMIA;So;0;ON;;;;;N;;;;;\n1CEC9;PSYCHE;So;0;ON;;;;;N;;;;;\n1CECA;THETIS;So;0;ON;;;;;N;;;;;\n1CECB;MELPOMENE;So;0;ON;;;;;N;;;;;\n1CECC;FORTUNA;So;0;ON;;;;;N;;;;;\n1CECD;ASTRONOMICAL SYMBOL FOR ASTEROID PROSERPINA;So;0;ON;;;;;N;;;;;\n1CECE;BELLONA;So;0;ON;;;;;N;;;;;\n1CECF;AMPHITRITE;So;0;ON;;;;;N;;;;;\n1CED0;LEUKOTHEA;So;0;ON;;;;;N;;;;;\n1CEE0;GEOMANTIC FIGURE POPULUS;So;0;ON;;;;;N;;;;;\n1CEE1;GEOMANTIC FIGURE TRISTITIA;So;0;ON;;;;;N;;;;;\n1CEE2;GEOMANTIC FIGURE ALBUS;So;0;ON;;;;;N;;;;;\n1CEE3;GEOMANTIC FIGURE FORTUNA MAJOR;So;0;ON;;;;;N;;;;;\n1CEE4;GEOMANTIC FIGURE RUBEUS;So;0;ON;;;;;N;;;;;\n1CEE5;GEOMANTIC FIGURE ACQUISITIO;So;0;ON;;;;;N;;;;;\n1CEE6;GEOMANTIC FIGURE CONJUNCTIO;So;0;ON;;;;;N;;;;;\n1CEE7;GEOMANTIC FIGURE CAPUT DRACONIS;So;0;ON;;;;;N;;;;;\n1CEE8;GEOMANTIC FIGURE LAETITIA;So;0;ON;;;;;N;;;;;\n1CEE9;GEOMANTIC FIGURE CARCER;So;0;ON;;;;;N;;;;;\n1CEEA;GEOMANTIC FIGURE AMISSIO;So;0;ON;;;;;N;;;;;\n1CEEB;GEOMANTIC FIGURE PUELLA;So;0;ON;;;;;N;;;;;\n1CEEC;GEOMANTIC FIGURE FORTUNA MINOR;So;0;ON;;;;;N;;;;;\n1CEED;GEOMANTIC FIGURE PUER;So;0;ON;;;;;N;;;;;\n1CEEE;GEOMANTIC FIGURE CAUDA DRACONIS;So;0;ON;;;;;N;;;;;\n1CEEF;GEOMANTIC FIGURE VIA;So;0;ON;;;;;N;;;;;\n1CEF0;MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;;\n1CF00;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF01;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF02;ZNAMENNY COMBINING MARK TSATA ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF03;ZNAMENNY COMBINING MARK GORAZDO NIZKO ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF04;ZNAMENNY COMBINING MARK NIZKO ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF05;ZNAMENNY COMBINING MARK SREDNE ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF06;ZNAMENNY COMBINING MARK MALO POVYSHE ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF07;ZNAMENNY COMBINING MARK POVYSHE ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF08;ZNAMENNY COMBINING MARK VYSOKO ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF09;ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF0A;ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF0B;ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF0C;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF0D;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF0E;ZNAMENNY COMBINING MARK TSATA ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF0F;ZNAMENNY COMBINING MARK GORAZDO NIZKO ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF10;ZNAMENNY COMBINING MARK NIZKO ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF11;ZNAMENNY COMBINING MARK SREDNE ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF12;ZNAMENNY COMBINING MARK MALO POVYSHE ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF13;ZNAMENNY COMBINING MARK POVYSHE ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF14;ZNAMENNY COMBINING MARK VYSOKO ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF15;ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF16;ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF17;ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;;\n1CF18;ZNAMENNY COMBINING MARK TSATA S KRYZHEM;Mn;0;NSM;;;;;N;;;;;\n1CF19;ZNAMENNY COMBINING MARK MALO POVYSHE S KRYZHEM;Mn;0;NSM;;;;;N;;;;;\n1CF1A;ZNAMENNY COMBINING MARK STRANNO MALO POVYSHE;Mn;0;NSM;;;;;N;;;;;\n1CF1B;ZNAMENNY COMBINING MARK POVYSHE S KRYZHEM;Mn;0;NSM;;;;;N;;;;;\n1CF1C;ZNAMENNY COMBINING MARK POVYSHE STRANNO;Mn;0;NSM;;;;;N;;;;;\n1CF1D;ZNAMENNY COMBINING MARK VYSOKO S KRYZHEM;Mn;0;NSM;;;;;N;;;;;\n1CF1E;ZNAMENNY COMBINING MARK MALO POVYSHE STRANNO;Mn;0;NSM;;;;;N;;;;;\n1CF1F;ZNAMENNY COMBINING MARK GORAZDO VYSOKO;Mn;0;NSM;;;;;N;;;;;\n1CF20;ZNAMENNY COMBINING MARK ZELO;Mn;0;NSM;;;;;N;;;;;\n1CF21;ZNAMENNY COMBINING MARK ON;Mn;0;NSM;;;;;N;;;;;\n1CF22;ZNAMENNY COMBINING MARK RAVNO;Mn;0;NSM;;;;;N;;;;;\n1CF23;ZNAMENNY COMBINING MARK TIKHAYA;Mn;0;NSM;;;;;N;;;;;\n1CF24;ZNAMENNY COMBINING MARK BORZAYA;Mn;0;NSM;;;;;N;;;;;\n1CF25;ZNAMENNY COMBINING MARK UDARKA;Mn;0;NSM;;;;;N;;;;;\n1CF26;ZNAMENNY COMBINING MARK PODVERTKA;Mn;0;NSM;;;;;N;;;;;\n1CF27;ZNAMENNY COMBINING MARK LOMKA;Mn;0;NSM;;;;;N;;;;;\n1CF28;ZNAMENNY COMBINING MARK KUPNAYA;Mn;0;NSM;;;;;N;;;;;\n1CF29;ZNAMENNY COMBINING MARK KACHKA;Mn;0;NSM;;;;;N;;;;;\n1CF2A;ZNAMENNY COMBINING MARK ZEVOK;Mn;0;NSM;;;;;N;;;;;\n1CF2B;ZNAMENNY COMBINING MARK SKOBA;Mn;0;NSM;;;;;N;;;;;\n1CF2C;ZNAMENNY COMBINING MARK RAZSEKA;Mn;0;NSM;;;;;N;;;;;\n1CF2D;ZNAMENNY COMBINING MARK KRYZH ON LEFT;Mn;0;NSM;;;;;N;;;;;\n1CF30;ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO;Mn;0;NSM;;;;;N;;;;;\n1CF31;ZNAMENNY COMBINING TONAL RANGE MARK SVETLO;Mn;0;NSM;;;;;N;;;;;\n1CF32;ZNAMENNY COMBINING TONAL RANGE MARK TRESVETLO;Mn;0;NSM;;;;;N;;;;;\n1CF33;ZNAMENNY COMBINING MARK ZADERZHKA;Mn;0;NSM;;;;;N;;;;;\n1CF34;ZNAMENNY COMBINING MARK DEMESTVENNY ZADERZHKA;Mn;0;NSM;;;;;N;;;;;\n1CF35;ZNAMENNY COMBINING MARK OTSECHKA;Mn;0;NSM;;;;;N;;;;;\n1CF36;ZNAMENNY COMBINING MARK PODCHASHIE;Mn;0;NSM;;;;;N;;;;;\n1CF37;ZNAMENNY COMBINING MARK PODCHASHIE WITH VERTICAL STROKE;Mn;0;NSM;;;;;N;;;;;\n1CF38;ZNAMENNY COMBINING MARK CHASHKA;Mn;0;NSM;;;;;N;;;;;\n1CF39;ZNAMENNY COMBINING MARK CHASHKA POLNAYA;Mn;0;NSM;;;;;N;;;;;\n1CF3A;ZNAMENNY COMBINING MARK OBLACHKO;Mn;0;NSM;;;;;N;;;;;\n1CF3B;ZNAMENNY COMBINING MARK SOROCHYA NOZHKA;Mn;0;NSM;;;;;N;;;;;\n1CF3C;ZNAMENNY COMBINING MARK TOCHKA;Mn;0;NSM;;;;;N;;;;;\n1CF3D;ZNAMENNY COMBINING MARK DVOETOCHIE;Mn;0;NSM;;;;;N;;;;;\n1CF3E;ZNAMENNY COMBINING ATTACHING VERTICAL OMET;Mn;0;NSM;;;;;N;;;;;\n1CF3F;ZNAMENNY COMBINING MARK CURVED OMET;Mn;0;NSM;;;;;N;;;;;\n1CF40;ZNAMENNY COMBINING MARK KRYZH;Mn;0;NSM;;;;;N;;;;;\n1CF41;ZNAMENNY COMBINING LOWER TONAL RANGE INDICATOR;Mn;0;NSM;;;;;N;;;;;\n1CF42;ZNAMENNY PRIZNAK MODIFIER LEVEL-2;Mn;0;NSM;;;;;N;;;;;\n1CF43;ZNAMENNY PRIZNAK MODIFIER LEVEL-3;Mn;0;NSM;;;;;N;;;;;\n1CF44;ZNAMENNY PRIZNAK MODIFIER DIRECTION FLIP;Mn;0;NSM;;;;;N;;;;;\n1CF45;ZNAMENNY PRIZNAK MODIFIER KRYZH;Mn;0;NSM;;;;;N;;;;;\n1CF46;ZNAMENNY PRIZNAK MODIFIER ROG;Mn;0;NSM;;;;;N;;;;;\n1CF50;ZNAMENNY NEUME KRYUK;So;0;L;;;;;N;;;;;\n1CF51;ZNAMENNY NEUME KRYUK TIKHY;So;0;L;;;;;N;;;;;\n1CF52;ZNAMENNY NEUME PARAKLIT;So;0;L;;;;;N;;;;;\n1CF53;ZNAMENNY NEUME DVA V CHELNU;So;0;L;;;;;N;;;;;\n1CF54;ZNAMENNY NEUME KLYUCH;So;0;L;;;;;N;;;;;\n1CF55;ZNAMENNY NEUME ZANOZHEK;So;0;L;;;;;N;;;;;\n1CF56;ZNAMENNY NEUME STOPITSA;So;0;L;;;;;N;;;;;\n1CF57;ZNAMENNY NEUME STOPITSA S OCHKOM;So;0;L;;;;;N;;;;;\n1CF58;ZNAMENNY NEUME PEREVODKA;So;0;L;;;;;N;;;;;\n1CF59;ZNAMENNY NEUME PEREVODKA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;;\n1CF5A;ZNAMENNY NEUME STOPITSA WITH SOROCHYA NOZHKA;So;0;L;;;;;N;;;;;\n1CF5B;ZNAMENNY NEUME CHELYUSTKA;So;0;L;;;;;N;;;;;\n1CF5C;ZNAMENNY NEUME PALKA;So;0;L;;;;;N;;;;;\n1CF5D;ZNAMENNY NEUME ZAPYATAYA;So;0;L;;;;;N;;;;;\n1CF5E;ZNAMENNY NEUME GOLUBCHIK BORZY;So;0;L;;;;;N;;;;;\n1CF5F;ZNAMENNY NEUME GOLUBCHIK TIKHY;So;0;L;;;;;N;;;;;\n1CF60;ZNAMENNY NEUME GOLUBCHIK MRACHNY;So;0;L;;;;;N;;;;;\n1CF61;ZNAMENNY NEUME GOLUBCHIK SVETLY;So;0;L;;;;;N;;;;;\n1CF62;ZNAMENNY NEUME GOLUBCHIK TRESVETLY;So;0;L;;;;;N;;;;;\n1CF63;ZNAMENNY NEUME VRAKHIYA PROSTAYA;So;0;L;;;;;N;;;;;\n1CF64;ZNAMENNY NEUME VRAKHIYA MRACHNAYA;So;0;L;;;;;N;;;;;\n1CF65;ZNAMENNY NEUME VRAKHIYA SVETLAYA;So;0;L;;;;;N;;;;;\n1CF66;ZNAMENNY NEUME VRAKHIYA TRESVETLAYA;So;0;L;;;;;N;;;;;\n1CF67;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA PROSTAYA;So;0;L;;;;;N;;;;;\n1CF68;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA MRACHNAYA;So;0;L;;;;;N;;;;;\n1CF69;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;;\n1CF6A;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA TRESVETLAYA;So;0;L;;;;;N;;;;;\n1CF6B;ZNAMENNY NEUME DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;;\n1CF6C;ZNAMENNY NEUME REVERSED CHELYUSTKA;So;0;L;;;;;N;;;;;\n1CF6D;ZNAMENNY NEUME DERBITSA;So;0;L;;;;;N;;;;;\n1CF6E;ZNAMENNY NEUME KHAMILO;So;0;L;;;;;N;;;;;\n1CF6F;ZNAMENNY NEUME CHASHKA;So;0;L;;;;;N;;;;;\n1CF70;ZNAMENNY NEUME PODCHASHIE;So;0;L;;;;;N;;;;;\n1CF71;ZNAMENNY NEUME SKAMEYTSA MRACHNAYA;So;0;L;;;;;N;;;;;\n1CF72;ZNAMENNY NEUME SKAMEYTSA SVETLAYA;So;0;L;;;;;N;;;;;\n1CF73;ZNAMENNY NEUME SKAMEYTSA TRESVETLAYA;So;0;L;;;;;N;;;;;\n1CF74;ZNAMENNY NEUME SKAMEYTSA TIKHAYA;So;0;L;;;;;N;;;;;\n1CF75;ZNAMENNY NEUME DEMESTVENNY KLYUCH;So;0;L;;;;;N;;;;;\n1CF76;ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;;\n1CF77;ZNAMENNY NEUME SKAMEYTSA KLYUCHENEPOSTOYANNAYA;So;0;L;;;;;N;;;;;\n1CF78;ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA TIKHAYA;So;0;L;;;;;N;;;;;\n1CF79;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA PROSTAYA;So;0;L;;;;;N;;;;;\n1CF7A;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA SVETLAYA;So;0;L;;;;;N;;;;;\n1CF7B;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;;\n1CF7C;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;;\n1CF7D;ZNAMENNY NEUME SLOZHITIE;So;0;L;;;;;N;;;;;\n1CF7E;ZNAMENNY NEUME SLOZHITIE S ZAPYATOY;So;0;L;;;;;N;;;;;\n1CF7F;ZNAMENNY NEUME SLOZHITIE ZAKRYTOE;So;0;L;;;;;N;;;;;\n1CF80;ZNAMENNY NEUME SLOZHITIE S KRYZHEM;So;0;L;;;;;N;;;;;\n1CF81;ZNAMENNY NEUME KRYZH;So;0;L;;;;;N;;;;;\n1CF82;ZNAMENNY NEUME ROG;So;0;L;;;;;N;;;;;\n1CF83;ZNAMENNY NEUME FITA;So;0;L;;;;;N;;;;;\n1CF84;ZNAMENNY NEUME KOBYLA;So;0;L;;;;;N;;;;;\n1CF85;ZNAMENNY NEUME ZMEYTSA;So;0;L;;;;;N;;;;;\n1CF86;ZNAMENNY NEUME STATYA;So;0;L;;;;;N;;;;;\n1CF87;ZNAMENNY NEUME STATYA S ZAPYATOY;So;0;L;;;;;N;;;;;\n1CF88;ZNAMENNY NEUME STATYA S KRYZHEM;So;0;L;;;;;N;;;;;\n1CF89;ZNAMENNY NEUME STATYA S ZAPYATOY I KRYZHEM;So;0;L;;;;;N;;;;;\n1CF8A;ZNAMENNY NEUME STATYA S KRYZHEM I ZAPYATOY;So;0;L;;;;;N;;;;;\n1CF8B;ZNAMENNY NEUME STATYA ZAKRYTAYA;So;0;L;;;;;N;;;;;\n1CF8C;ZNAMENNY NEUME STATYA ZAKRYTAYA S ZAPYATOY;So;0;L;;;;;N;;;;;\n1CF8D;ZNAMENNY NEUME STATYA S ROGOM;So;0;L;;;;;N;;;;;\n1CF8E;ZNAMENNY NEUME STATYA S DVUMYA ZAPYATYMI;So;0;L;;;;;N;;;;;\n1CF8F;ZNAMENNY NEUME STATYA S ZAPYATOY I PODCHASHIEM;So;0;L;;;;;N;;;;;\n1CF90;ZNAMENNY NEUME POLKULIZMY;So;0;L;;;;;N;;;;;\n1CF91;ZNAMENNY NEUME STATYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;;\n1CF92;ZNAMENNY NEUME STRELA PROSTAYA;So;0;L;;;;;N;;;;;\n1CF93;ZNAMENNY NEUME STRELA MRACHNOTIKHAYA;So;0;L;;;;;N;;;;;\n1CF94;ZNAMENNY NEUME STRELA KRYZHEVAYA;So;0;L;;;;;N;;;;;\n1CF95;ZNAMENNY NEUME STRELA POLUPOVODNAYA;So;0;L;;;;;N;;;;;\n1CF96;ZNAMENNY NEUME STRELA POVODNAYA;So;0;L;;;;;N;;;;;\n1CF97;ZNAMENNY NEUME STRELA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;;\n1CF98;ZNAMENNY NEUME STRELA KLYUCHEPOVODNAYA;So;0;L;;;;;N;;;;;\n1CF99;ZNAMENNY NEUME STRELA KLYUCHENEPOSTOYANNAYA;So;0;L;;;;;N;;;;;\n1CF9A;ZNAMENNY NEUME STRELA TIKHAYA PUTNAYA;So;0;L;;;;;N;;;;;\n1CF9B;ZNAMENNY NEUME STRELA DVOECHELNAYA;So;0;L;;;;;N;;;;;\n1CF9C;ZNAMENNY NEUME STRELA DVOECHELNOKRYZHEVAYA;So;0;L;;;;;N;;;;;\n1CF9D;ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA;So;0;L;;;;;N;;;;;\n1CF9E;ZNAMENNY NEUME STRELA DVOECHELNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;;\n1CF9F;ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;;\n1CFA0;ZNAMENNY NEUME STRELA GROMNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;;\n1CFA1;ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;;\n1CFA2;ZNAMENNY NEUME STRELA GROMNAYA;So;0;L;;;;;N;;;;;\n1CFA3;ZNAMENNY NEUME STRELA GROMOPOVODNAYA;So;0;L;;;;;N;;;;;\n1CFA4;ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;;\n1CFA5;ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA;So;0;L;;;;;N;;;;;\n1CFA6;ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA POVODNAYA;So;0;L;;;;;N;;;;;\n1CFA7;ZNAMENNY NEUME MECHIK;So;0;L;;;;;N;;;;;\n1CFA8;ZNAMENNY NEUME MECHIK POVODNY;So;0;L;;;;;N;;;;;\n1CFA9;ZNAMENNY NEUME MECHIK KLYUCHEVOY;So;0;L;;;;;N;;;;;\n1CFAA;ZNAMENNY NEUME MECHIK KLYUCHEPOVODNY;So;0;L;;;;;N;;;;;\n1CFAB;ZNAMENNY NEUME MECHIK KLYUCHENEPOSTOYANNY;So;0;L;;;;;N;;;;;\n1CFAC;ZNAMENNY NEUME STRELA TRYASOGLASNAYA;So;0;L;;;;;N;;;;;\n1CFAD;ZNAMENNY NEUME STRELA TRYASOPOVODNAYA;So;0;L;;;;;N;;;;;\n1CFAE;ZNAMENNY NEUME STRELA TRYASOSTRELNAYA;So;0;L;;;;;N;;;;;\n1CFAF;ZNAMENNY NEUME OSOKA;So;0;L;;;;;N;;;;;\n1CFB0;ZNAMENNY NEUME OSOKA SVETLAYA;So;0;L;;;;;N;;;;;\n1CFB1;ZNAMENNY NEUME OSOKA TRESVETLAYA;So;0;L;;;;;N;;;;;\n1CFB2;ZNAMENNY NEUME OSOKA KRYUKOVAYA SVETLAYA;So;0;L;;;;;N;;;;;\n1CFB3;ZNAMENNY NEUME OSOKA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;;\n1CFB4;ZNAMENNY NEUME OSOKA KLYUCHEVAYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;;\n1CFB5;ZNAMENNY NEUME STRELA KRYUKOVAYA;So;0;L;;;;;N;;;;;\n1CFB6;ZNAMENNY NEUME STRELA KRYUKOVAYA POVODNAYA;So;0;L;;;;;N;;;;;\n1CFB7;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;;\n1CFB8;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;;\n1CFB9;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA;So;0;L;;;;;N;;;;;\n1CFBA;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA;So;0;L;;;;;N;;;;;\n1CFBB;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;;\n1CFBC;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA;So;0;L;;;;;N;;;;;\n1CFBD;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA POVODNAYA;So;0;L;;;;;N;;;;;\n1CFBE;ZNAMENNY NEUME STRELA KRYUKOVAYA TRYASKA;So;0;L;;;;;N;;;;;\n1CFBF;ZNAMENNY NEUME KUFISMA;So;0;L;;;;;N;;;;;\n1CFC0;ZNAMENNY NEUME OBLAKO;So;0;L;;;;;N;;;;;\n1CFC1;ZNAMENNY NEUME DUDA;So;0;L;;;;;N;;;;;\n1CFC2;ZNAMENNY NEUME NEMKA;So;0;L;;;;;N;;;;;\n1CFC3;ZNAMENNY NEUME PAUK;So;0;L;;;;;N;;;;;\n1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;;\n1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;;\n1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;;\n1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;;\n1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;;\n1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;;\n1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;;\n1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;;\n1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;;\n1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;;\n1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;;\n1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;;\n1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;;\n1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;;\n1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;;\n1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;;\n1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;;\n1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;;\n1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;;\n1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;;\n1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;;\n1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;;\n1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;;\n1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;;\n1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;;\n1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;;\n1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;;\n1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;;\n1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;;\n1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;;\n1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;;\n1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;;\n1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;;\n1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;;\n1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;;\n1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;;\n1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;;\n1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;;\n1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;;\n1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;;\n1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;;\n1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;;\n1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;;\n1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;;\n1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;;\n1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;;\n1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;;\n1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;;\n1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;;\n1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;;\n1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;;\n1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;;\n1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;;\n1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;;\n1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;;\n1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;;\n1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;;\n1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;;\n1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;;\n1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;;\n1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;;\n1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;;\n1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;;\n1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;;\n1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;;\n1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;;\n1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;;\n1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;;\n1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;;\n1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;;\n1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;;\n1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;;\n1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;;\n1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;;\n1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;;\n1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;;\n1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;;\n1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;;\n1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;;\n1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;;\n1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;;\n1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;;\n1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;;\n1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;;\n1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;;\n1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;;\n1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;;\n1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;;\n1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;;\n1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;;\n1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;;\n1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;;\n1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;;\n1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;;\n1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;;\n1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;;\n1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;;\n1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;;\n1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;;\n1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;;\n1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;;\n1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;;\n1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;;\n1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;;\n1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;;\n1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;;\n1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;;\n1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;;\n1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;;\n1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;;\n1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;;\n1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;;\n1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;;\n1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;;\n1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;;\n1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;;\n1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;;\n1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;;\n1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;;\n1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;;\n1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;;\n1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;;\n1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;;\n1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;;\n1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;;\n1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;;\n1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;;\n1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;;\n1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;;\n1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;;\n1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;;\n1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;;\n1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;;\n1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;;\n1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;;\n1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;;\n1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;;\n1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;;\n1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;;\n1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;;\n1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;;\n1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;;\n1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;;\n1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;;\n1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;;\n1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;\n1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;;\n1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;;\n1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;;\n1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;\n1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;;\n1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;;\n1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;;\n1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;;\n1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;;\n1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;;\n1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;;\n1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;;\n1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;;\n1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;;\n1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;;\n1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;;\n1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;;\n1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;;\n1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;;\n1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;;\n1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;;\n1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;;\n1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;;\n1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;;\n1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;;\n1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;;\n1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;\n1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;\n1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;;\n1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;;\n1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;;\n1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;;\n1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;;\n1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;;\n1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;;\n1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;;\n1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;;\n1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;;\n1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;;\n1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;;\n1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;;\n1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;;\n1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;;\n1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;;\n1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;;\n1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;;\n1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;;\n1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;;\n1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;;\n1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;;\n1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;;\n1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;;\n1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;;\n1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;;\n1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;;\n1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;;\n1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;;\n1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;;\n1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;;\n1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;;\n1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;;\n1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;;\n1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;\n1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;\n1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;\n1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;\n1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;\n1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;\n1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;\n1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;\n1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;;\n1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;;\n1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;;\n1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;;\n1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;;\n1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;;\n1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;;\n1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;;\n1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;;\n1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;;\n1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;;\n1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;;\n1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;;\n1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;;\n1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;;\n1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;;\n1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;;\n1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;;\n1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;;\n1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;;\n1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;;\n1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;;\n1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;;\n1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;;\n1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;;\n1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;;\n1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;;\n1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;;\n1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;;\n1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;;\n1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;;\n1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;;\n1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;;\n1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;;\n1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;;\n1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;;\n1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;;\n1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;;\n1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;;\n1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;;\n1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;;\n1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;;\n1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;;\n1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;;\n1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;;\n1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;;\n1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;;\n1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;;\n1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;;\n1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;;\n1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;;\n1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;;\n1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;;\n1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;;\n1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;;\n1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;;\n1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;;\n1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;;\n1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;;\n1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;;\n1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;;\n1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;\n1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;\n1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;;\n1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;;\n1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;\n1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;\n1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;;\n1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;;\n1D129;MUSICAL SYMBOL MULTIPLE MEASURE REST;So;0;L;;;;;N;;;;;\n1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;;\n1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;;\n1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;;\n1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;;\n1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;;\n1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;;\n1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;;\n1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;;\n1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;;\n1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;;\n1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;;\n1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;;\n1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;;\n1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;;\n1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;;\n1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;;\n1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;;\n1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;;\n1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;;\n1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;;\n1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;;\n1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;;\n1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;;\n1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;;\n1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;;\n1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;;\n1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;;\n1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;;\n1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;;\n1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;;\n1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;;\n1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;;\n1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;;\n1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;;\n1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;;\n1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;;\n1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;\n1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;\n1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;;\n1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;;\n1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;;\n1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;;\n1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;\n1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;\n1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;;\n1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;;\n1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;;\n1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;;\n1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;;\n1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;;\n1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;;\n1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;;\n1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;;\n1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;;\n1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;;\n1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;;\n1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;;\n1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;;\n1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;;\n1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;;\n1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;;\n1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;;\n1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;;\n1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;;\n1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;;\n1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;;\n1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;;\n1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;;\n1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;;\n1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;;\n1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;;\n1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;;\n1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;;\n1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;;\n1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;;\n1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;;\n1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;;\n1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;;\n1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;;\n1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;;\n1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;;\n1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;;\n1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;;\n1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;;\n1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;;\n1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;;\n1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;;\n1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;;\n1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;;\n1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;;\n1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;;\n1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;;\n1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;;\n1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;;\n1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;;\n1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;;\n1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;;\n1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;;\n1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;;\n1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;;\n1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;;\n1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;;\n1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;;\n1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;;\n1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;;\n1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;;\n1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;;\n1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;;\n1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;;\n1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;;\n1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;;\n1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;;\n1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;;\n1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;;\n1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;;\n1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;;\n1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;;\n1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;;\n1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;;\n1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;;\n1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;;\n1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;;\n1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;;\n1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;;\n1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;;\n1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;;\n1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;;\n1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;;\n1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;;\n1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;;\n1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;;\n1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;;\n1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;;\n1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;;\n1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;;\n1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;;\n1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;;\n1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;;\n1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;;\n1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;;\n1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;;\n1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;;\n1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;;\n1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;;\n1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;;\n1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;;\n1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;;\n1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;;\n1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;;\n1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;;\n1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;;\n1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;;\n1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;;\n1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;;\n1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;;\n1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;;\n1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;;\n1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;\n1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;\n1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;\n1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;\n1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;\n1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;\n1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;;\n1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;;\n1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;;\n1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;;\n1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;;\n1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;;\n1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;;\n1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;;\n1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;;\n1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;;\n1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;;\n1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;;\n1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;;\n1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;;\n1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;;\n1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;;\n1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;;\n1D1DE;MUSICAL SYMBOL KIEVAN C CLEF;So;0;L;;;;;N;;;;;\n1D1DF;MUSICAL SYMBOL KIEVAN END OF PIECE;So;0;L;;;;;N;;;;;\n1D1E0;MUSICAL SYMBOL KIEVAN FINAL NOTE;So;0;L;;;;;N;;;;;\n1D1E1;MUSICAL SYMBOL KIEVAN RECITATIVE MARK;So;0;L;;;;;N;;;;;\n1D1E2;MUSICAL SYMBOL KIEVAN WHOLE NOTE;So;0;L;;;;;N;;;;;\n1D1E3;MUSICAL SYMBOL KIEVAN HALF NOTE;So;0;L;;;;;N;;;;;\n1D1E4;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM DOWN;So;0;L;;;;;N;;;;;\n1D1E5;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM UP;So;0;L;;;;;N;;;;;\n1D1E6;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWN;So;0;L;;;;;N;;;;;\n1D1E7;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UP;So;0;L;;;;;N;;;;;\n1D1E8;MUSICAL SYMBOL KIEVAN FLAT SIGN;So;0;L;;;;;N;;;;;\n1D1E9;MUSICAL SYMBOL SORI;So;0;ON;;;;;N;;;;;\n1D1EA;MUSICAL SYMBOL KORON;So;0;ON;;;;;N;;;;;\n1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;;\n1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;;\n1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;;\n1D203;GREEK VOCAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;;\n1D204;GREEK VOCAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;;\n1D205;GREEK VOCAL NOTATION SYMBOL-6;So;0;ON;;;;;N;;;;;\n1D206;GREEK VOCAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;;\n1D207;GREEK VOCAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;;\n1D208;GREEK VOCAL NOTATION SYMBOL-9;So;0;ON;;;;;N;;;;;\n1D209;GREEK VOCAL NOTATION SYMBOL-10;So;0;ON;;;;;N;;;;;\n1D20A;GREEK VOCAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;;\n1D20B;GREEK VOCAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;;\n1D20C;GREEK VOCAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;;\n1D20D;GREEK VOCAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;;\n1D20E;GREEK VOCAL NOTATION SYMBOL-15;So;0;ON;;;;;N;;;;;\n1D20F;GREEK VOCAL NOTATION SYMBOL-16;So;0;ON;;;;;N;;;;;\n1D210;GREEK VOCAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;;\n1D211;GREEK VOCAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;;\n1D212;GREEK VOCAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;;\n1D213;GREEK VOCAL NOTATION SYMBOL-20;So;0;ON;;;;;N;;;;;\n1D214;GREEK VOCAL NOTATION SYMBOL-21;So;0;ON;;;;;N;;;;;\n1D215;GREEK VOCAL NOTATION SYMBOL-22;So;0;ON;;;;;N;;;;;\n1D216;GREEK VOCAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;;\n1D217;GREEK VOCAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;;\n1D218;GREEK VOCAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;;\n1D219;GREEK VOCAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;;\n1D21A;GREEK VOCAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;;\n1D21B;GREEK VOCAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;;\n1D21C;GREEK VOCAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;;\n1D21D;GREEK INSTRUMENTAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;;\n1D21E;GREEK INSTRUMENTAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;;\n1D21F;GREEK INSTRUMENTAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;;\n1D220;GREEK INSTRUMENTAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;;\n1D221;GREEK INSTRUMENTAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;;\n1D222;GREEK INSTRUMENTAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;;\n1D223;GREEK INSTRUMENTAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;;\n1D224;GREEK INSTRUMENTAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;;\n1D225;GREEK INSTRUMENTAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;;\n1D226;GREEK INSTRUMENTAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;;\n1D227;GREEK INSTRUMENTAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;;\n1D228;GREEK INSTRUMENTAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;;\n1D229;GREEK INSTRUMENTAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;;\n1D22A;GREEK INSTRUMENTAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;;\n1D22B;GREEK INSTRUMENTAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;;\n1D22C;GREEK INSTRUMENTAL NOTATION SYMBOL-25;So;0;ON;;;;;N;;;;;\n1D22D;GREEK INSTRUMENTAL NOTATION SYMBOL-26;So;0;ON;;;;;N;;;;;\n1D22E;GREEK INSTRUMENTAL NOTATION SYMBOL-27;So;0;ON;;;;;N;;;;;\n1D22F;GREEK INSTRUMENTAL NOTATION SYMBOL-29;So;0;ON;;;;;N;;;;;\n1D230;GREEK INSTRUMENTAL NOTATION SYMBOL-30;So;0;ON;;;;;N;;;;;\n1D231;GREEK INSTRUMENTAL NOTATION SYMBOL-32;So;0;ON;;;;;N;;;;;\n1D232;GREEK INSTRUMENTAL NOTATION SYMBOL-36;So;0;ON;;;;;N;;;;;\n1D233;GREEK INSTRUMENTAL NOTATION SYMBOL-37;So;0;ON;;;;;N;;;;;\n1D234;GREEK INSTRUMENTAL NOTATION SYMBOL-38;So;0;ON;;;;;N;;;;;\n1D235;GREEK INSTRUMENTAL NOTATION SYMBOL-39;So;0;ON;;;;;N;;;;;\n1D236;GREEK INSTRUMENTAL NOTATION SYMBOL-40;So;0;ON;;;;;N;;;;;\n1D237;GREEK INSTRUMENTAL NOTATION SYMBOL-42;So;0;ON;;;;;N;;;;;\n1D238;GREEK INSTRUMENTAL NOTATION SYMBOL-43;So;0;ON;;;;;N;;;;;\n1D239;GREEK INSTRUMENTAL NOTATION SYMBOL-45;So;0;ON;;;;;N;;;;;\n1D23A;GREEK INSTRUMENTAL NOTATION SYMBOL-47;So;0;ON;;;;;N;;;;;\n1D23B;GREEK INSTRUMENTAL NOTATION SYMBOL-48;So;0;ON;;;;;N;;;;;\n1D23C;GREEK INSTRUMENTAL NOTATION SYMBOL-49;So;0;ON;;;;;N;;;;;\n1D23D;GREEK INSTRUMENTAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;;\n1D23E;GREEK INSTRUMENTAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;;\n1D23F;GREEK INSTRUMENTAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;;\n1D240;GREEK INSTRUMENTAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;;\n1D241;GREEK INSTRUMENTAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;;\n1D242;COMBINING GREEK MUSICAL TRISEME;Mn;230;NSM;;;;;N;;;;;\n1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;;\n1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;;\n1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;;\n1D2C0;KAKTOVIK NUMERAL ZERO;No;0;L;;;;0;N;;;;;\n1D2C1;KAKTOVIK NUMERAL ONE;No;0;L;;;;1;N;;;;;\n1D2C2;KAKTOVIK NUMERAL TWO;No;0;L;;;;2;N;;;;;\n1D2C3;KAKTOVIK NUMERAL THREE;No;0;L;;;;3;N;;;;;\n1D2C4;KAKTOVIK NUMERAL FOUR;No;0;L;;;;4;N;;;;;\n1D2C5;KAKTOVIK NUMERAL FIVE;No;0;L;;;;5;N;;;;;\n1D2C6;KAKTOVIK NUMERAL SIX;No;0;L;;;;6;N;;;;;\n1D2C7;KAKTOVIK NUMERAL SEVEN;No;0;L;;;;7;N;;;;;\n1D2C8;KAKTOVIK NUMERAL EIGHT;No;0;L;;;;8;N;;;;;\n1D2C9;KAKTOVIK NUMERAL NINE;No;0;L;;;;9;N;;;;;\n1D2CA;KAKTOVIK NUMERAL TEN;No;0;L;;;;10;N;;;;;\n1D2CB;KAKTOVIK NUMERAL ELEVEN;No;0;L;;;;11;N;;;;;\n1D2CC;KAKTOVIK NUMERAL TWELVE;No;0;L;;;;12;N;;;;;\n1D2CD;KAKTOVIK NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;;\n1D2CE;KAKTOVIK NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;;\n1D2CF;KAKTOVIK NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;;\n1D2D0;KAKTOVIK NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;;\n1D2D1;KAKTOVIK NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;;\n1D2D2;KAKTOVIK NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;;\n1D2D3;KAKTOVIK NUMERAL NINETEEN;No;0;L;;;;19;N;;;;;\n1D2E0;MAYAN NUMERAL ZERO;No;0;L;;;;0;N;;;;;\n1D2E1;MAYAN NUMERAL ONE;No;0;L;;;;1;N;;;;;\n1D2E2;MAYAN NUMERAL TWO;No;0;L;;;;2;N;;;;;\n1D2E3;MAYAN NUMERAL THREE;No;0;L;;;;3;N;;;;;\n1D2E4;MAYAN NUMERAL FOUR;No;0;L;;;;4;N;;;;;\n1D2E5;MAYAN NUMERAL FIVE;No;0;L;;;;5;N;;;;;\n1D2E6;MAYAN NUMERAL SIX;No;0;L;;;;6;N;;;;;\n1D2E7;MAYAN NUMERAL SEVEN;No;0;L;;;;7;N;;;;;\n1D2E8;MAYAN NUMERAL EIGHT;No;0;L;;;;8;N;;;;;\n1D2E9;MAYAN NUMERAL NINE;No;0;L;;;;9;N;;;;;\n1D2EA;MAYAN NUMERAL TEN;No;0;L;;;;10;N;;;;;\n1D2EB;MAYAN NUMERAL ELEVEN;No;0;L;;;;11;N;;;;;\n1D2EC;MAYAN NUMERAL TWELVE;No;0;L;;;;12;N;;;;;\n1D2ED;MAYAN NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;;\n1D2EE;MAYAN NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;;\n1D2EF;MAYAN NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;;\n1D2F0;MAYAN NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;;\n1D2F1;MAYAN NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;;\n1D2F2;MAYAN NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;;\n1D2F3;MAYAN NUMERAL NINETEEN;No;0;L;;;;19;N;;;;;\n1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;;\n1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;;\n1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;;\n1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;;;;\n1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;;;;\n1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;\n1D306;TETRAGRAM FOR CENTRE;So;0;ON;;;;;N;;;;;\n1D307;TETRAGRAM FOR FULL CIRCLE;So;0;ON;;;;;N;;;;;\n1D308;TETRAGRAM FOR MIRED;So;0;ON;;;;;N;;;;;\n1D309;TETRAGRAM FOR BARRIER;So;0;ON;;;;;N;;;;;\n1D30A;TETRAGRAM FOR KEEPING SMALL;So;0;ON;;;;;N;;;;;\n1D30B;TETRAGRAM FOR CONTRARIETY;So;0;ON;;;;;N;;;;;\n1D30C;TETRAGRAM FOR ASCENT;So;0;ON;;;;;N;;;;;\n1D30D;TETRAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;;\n1D30E;TETRAGRAM FOR BRANCHING OUT;So;0;ON;;;;;N;;;;;\n1D30F;TETRAGRAM FOR DEFECTIVENESS OR DISTORTION;So;0;ON;;;;;N;;;;;\n1D310;TETRAGRAM FOR DIVERGENCE;So;0;ON;;;;;N;;;;;\n1D311;TETRAGRAM FOR YOUTHFULNESS;So;0;ON;;;;;N;;;;;\n1D312;TETRAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;;\n1D313;TETRAGRAM FOR PENETRATION;So;0;ON;;;;;N;;;;;\n1D314;TETRAGRAM FOR REACH;So;0;ON;;;;;N;;;;;\n1D315;TETRAGRAM FOR CONTACT;So;0;ON;;;;;N;;;;;\n1D316;TETRAGRAM FOR HOLDING BACK;So;0;ON;;;;;N;;;;;\n1D317;TETRAGRAM FOR WAITING;So;0;ON;;;;;N;;;;;\n1D318;TETRAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;;\n1D319;TETRAGRAM FOR ADVANCE;So;0;ON;;;;;N;;;;;\n1D31A;TETRAGRAM FOR RELEASE;So;0;ON;;;;;N;;;;;\n1D31B;TETRAGRAM FOR RESISTANCE;So;0;ON;;;;;N;;;;;\n1D31C;TETRAGRAM FOR EASE;So;0;ON;;;;;N;;;;;\n1D31D;TETRAGRAM FOR JOY;So;0;ON;;;;;N;;;;;\n1D31E;TETRAGRAM FOR CONTENTION;So;0;ON;;;;;N;;;;;\n1D31F;TETRAGRAM FOR ENDEAVOUR;So;0;ON;;;;;N;;;;;\n1D320;TETRAGRAM FOR DUTIES;So;0;ON;;;;;N;;;;;\n1D321;TETRAGRAM FOR CHANGE;So;0;ON;;;;;N;;;;;\n1D322;TETRAGRAM FOR DECISIVENESS;So;0;ON;;;;;N;;;;;\n1D323;TETRAGRAM FOR BOLD RESOLUTION;So;0;ON;;;;;N;;;;;\n1D324;TETRAGRAM FOR PACKING;So;0;ON;;;;;N;;;;;\n1D325;TETRAGRAM FOR LEGION;So;0;ON;;;;;N;;;;;\n1D326;TETRAGRAM FOR CLOSENESS;So;0;ON;;;;;N;;;;;\n1D327;TETRAGRAM FOR KINSHIP;So;0;ON;;;;;N;;;;;\n1D328;TETRAGRAM FOR GATHERING;So;0;ON;;;;;N;;;;;\n1D329;TETRAGRAM FOR STRENGTH;So;0;ON;;;;;N;;;;;\n1D32A;TETRAGRAM FOR PURITY;So;0;ON;;;;;N;;;;;\n1D32B;TETRAGRAM FOR FULLNESS;So;0;ON;;;;;N;;;;;\n1D32C;TETRAGRAM FOR RESIDENCE;So;0;ON;;;;;N;;;;;\n1D32D;TETRAGRAM FOR LAW OR MODEL;So;0;ON;;;;;N;;;;;\n1D32E;TETRAGRAM FOR RESPONSE;So;0;ON;;;;;N;;;;;\n1D32F;TETRAGRAM FOR GOING TO MEET;So;0;ON;;;;;N;;;;;\n1D330;TETRAGRAM FOR ENCOUNTERS;So;0;ON;;;;;N;;;;;\n1D331;TETRAGRAM FOR STOVE;So;0;ON;;;;;N;;;;;\n1D332;TETRAGRAM FOR GREATNESS;So;0;ON;;;;;N;;;;;\n1D333;TETRAGRAM FOR ENLARGEMENT;So;0;ON;;;;;N;;;;;\n1D334;TETRAGRAM FOR PATTERN;So;0;ON;;;;;N;;;;;\n1D335;TETRAGRAM FOR RITUAL;So;0;ON;;;;;N;;;;;\n1D336;TETRAGRAM FOR FLIGHT;So;0;ON;;;;;N;;;;;\n1D337;TETRAGRAM FOR VASTNESS OR WASTING;So;0;ON;;;;;N;;;;;\n1D338;TETRAGRAM FOR CONSTANCY;So;0;ON;;;;;N;;;;;\n1D339;TETRAGRAM FOR MEASURE;So;0;ON;;;;;N;;;;;\n1D33A;TETRAGRAM FOR ETERNITY;So;0;ON;;;;;N;;;;;\n1D33B;TETRAGRAM FOR UNITY;So;0;ON;;;;;N;;;;;\n1D33C;TETRAGRAM FOR DIMINISHMENT;So;0;ON;;;;;N;;;;;\n1D33D;TETRAGRAM FOR CLOSED MOUTH;So;0;ON;;;;;N;;;;;\n1D33E;TETRAGRAM FOR GUARDEDNESS;So;0;ON;;;;;N;;;;;\n1D33F;TETRAGRAM FOR GATHERING IN;So;0;ON;;;;;N;;;;;\n1D340;TETRAGRAM FOR MASSING;So;0;ON;;;;;N;;;;;\n1D341;TETRAGRAM FOR ACCUMULATION;So;0;ON;;;;;N;;;;;\n1D342;TETRAGRAM FOR EMBELLISHMENT;So;0;ON;;;;;N;;;;;\n1D343;TETRAGRAM FOR DOUBT;So;0;ON;;;;;N;;;;;\n1D344;TETRAGRAM FOR WATCH;So;0;ON;;;;;N;;;;;\n1D345;TETRAGRAM FOR SINKING;So;0;ON;;;;;N;;;;;\n1D346;TETRAGRAM FOR INNER;So;0;ON;;;;;N;;;;;\n1D347;TETRAGRAM FOR DEPARTURE;So;0;ON;;;;;N;;;;;\n1D348;TETRAGRAM FOR DARKENING;So;0;ON;;;;;N;;;;;\n1D349;TETRAGRAM FOR DIMMING;So;0;ON;;;;;N;;;;;\n1D34A;TETRAGRAM FOR EXHAUSTION;So;0;ON;;;;;N;;;;;\n1D34B;TETRAGRAM FOR SEVERANCE;So;0;ON;;;;;N;;;;;\n1D34C;TETRAGRAM FOR STOPPAGE;So;0;ON;;;;;N;;;;;\n1D34D;TETRAGRAM FOR HARDNESS;So;0;ON;;;;;N;;;;;\n1D34E;TETRAGRAM FOR COMPLETION;So;0;ON;;;;;N;;;;;\n1D34F;TETRAGRAM FOR CLOSURE;So;0;ON;;;;;N;;;;;\n1D350;TETRAGRAM FOR FAILURE;So;0;ON;;;;;N;;;;;\n1D351;TETRAGRAM FOR AGGRAVATION;So;0;ON;;;;;N;;;;;\n1D352;TETRAGRAM FOR COMPLIANCE;So;0;ON;;;;;N;;;;;\n1D353;TETRAGRAM FOR ON THE VERGE;So;0;ON;;;;;N;;;;;\n1D354;TETRAGRAM FOR DIFFICULTIES;So;0;ON;;;;;N;;;;;\n1D355;TETRAGRAM FOR LABOURING;So;0;ON;;;;;N;;;;;\n1D356;TETRAGRAM FOR FOSTERING;So;0;ON;;;;;N;;;;;\n1D360;COUNTING ROD UNIT DIGIT ONE;No;0;L;;;;1;N;;;;;\n1D361;COUNTING ROD UNIT DIGIT TWO;No;0;L;;;;2;N;;;;;\n1D362;COUNTING ROD UNIT DIGIT THREE;No;0;L;;;;3;N;;;;;\n1D363;COUNTING ROD UNIT DIGIT FOUR;No;0;L;;;;4;N;;;;;\n1D364;COUNTING ROD UNIT DIGIT FIVE;No;0;L;;;;5;N;;;;;\n1D365;COUNTING ROD UNIT DIGIT SIX;No;0;L;;;;6;N;;;;;\n1D366;COUNTING ROD UNIT DIGIT SEVEN;No;0;L;;;;7;N;;;;;\n1D367;COUNTING ROD UNIT DIGIT EIGHT;No;0;L;;;;8;N;;;;;\n1D368;COUNTING ROD UNIT DIGIT NINE;No;0;L;;;;9;N;;;;;\n1D369;COUNTING ROD TENS DIGIT ONE;No;0;L;;;;10;N;;;;;\n1D36A;COUNTING ROD TENS DIGIT TWO;No;0;L;;;;20;N;;;;;\n1D36B;COUNTING ROD TENS DIGIT THREE;No;0;L;;;;30;N;;;;;\n1D36C;COUNTING ROD TENS DIGIT FOUR;No;0;L;;;;40;N;;;;;\n1D36D;COUNTING ROD TENS DIGIT FIVE;No;0;L;;;;50;N;;;;;\n1D36E;COUNTING ROD TENS DIGIT SIX;No;0;L;;;;60;N;;;;;\n1D36F;COUNTING ROD TENS DIGIT SEVEN;No;0;L;;;;70;N;;;;;\n1D370;COUNTING ROD TENS DIGIT EIGHT;No;0;L;;;;80;N;;;;;\n1D371;COUNTING ROD TENS DIGIT NINE;No;0;L;;;;90;N;;;;;\n1D372;IDEOGRAPHIC TALLY MARK ONE;No;0;L;;;;1;N;;;;;\n1D373;IDEOGRAPHIC TALLY MARK TWO;No;0;L;;;;2;N;;;;;\n1D374;IDEOGRAPHIC TALLY MARK THREE;No;0;L;;;;3;N;;;;;\n1D375;IDEOGRAPHIC TALLY MARK FOUR;No;0;L;;;;4;N;;;;;\n1D376;IDEOGRAPHIC TALLY MARK FIVE;No;0;L;;;;5;N;;;;;\n1D377;TALLY MARK ONE;No;0;L;;;;1;N;;;;;\n1D378;TALLY MARK FIVE;No;0;L;;;;5;N;;;;;\n1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D4C1;MATHEMATICAL SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;\n1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;\n1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;\n1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;\n1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;\n1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;\n1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;\n1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;\n1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;\n1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;\n1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;\n1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;\n1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;\n1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;\n1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;\n1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;\n1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;\n1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;\n1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;\n1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;\n1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;\n1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;\n1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;\n1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;\n1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;\n1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;\n1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;\n1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;\n1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;\n1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;\n1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;\n1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;\n1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;\n1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;\n1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;\n1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;\n1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;\n1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;\n1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;\n1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;\n1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;\n1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;\n1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;\n1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;\n1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;\n1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;\n1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;\n1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;\n1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;\n1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;\n1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;\n1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;\n1D6A4;MATHEMATICAL ITALIC SMALL DOTLESS I;Ll;0;L;<font> 0131;;;;N;;;;;\n1D6A5;MATHEMATICAL ITALIC SMALL DOTLESS J;Ll;0;L;<font> 0237;;;;N;;;;;\n1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;\n1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;\n1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;\n1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;\n1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;\n1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;\n1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;\n1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;\n1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;\n1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;\n1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;\n1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;\n1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;\n1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;\n1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;\n1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;\n1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;\n1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;\n1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;\n1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;\n1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;\n1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;\n1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;\n1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;\n1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;\n1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;ON;<font> 2207;;;;N;;;;;\n1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;\n1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;\n1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;\n1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;\n1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;\n1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;\n1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;\n1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;\n1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;\n1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;\n1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;\n1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;\n1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;\n1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;\n1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;\n1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;\n1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;\n1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;\n1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;\n1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;\n1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;\n1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;\n1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;\n1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;\n1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;\n1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;\n1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;\n1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;\n1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;\n1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;\n1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;\n1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;\n1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;\n1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;\n1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;\n1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;\n1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;\n1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;\n1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;\n1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;\n1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;\n1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;\n1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;\n1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;\n1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;\n1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;\n1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;\n1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;\n1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;\n1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;\n1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;\n1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;\n1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;\n1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;\n1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;\n1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;\n1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;\n1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;ON;<font> 2207;;;;N;;;;;\n1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;\n1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;\n1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;\n1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;\n1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;\n1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;\n1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;\n1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;\n1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;\n1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;\n1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;\n1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;\n1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;\n1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;\n1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;\n1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;\n1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;\n1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;\n1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;\n1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;\n1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;\n1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;\n1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;\n1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;\n1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;\n1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;\n1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;\n1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;\n1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;\n1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;\n1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;\n1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;\n1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;\n1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;\n1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;\n1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;\n1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;\n1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;\n1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;\n1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;\n1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;\n1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;\n1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;\n1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;\n1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;\n1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;\n1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;\n1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;\n1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;\n1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;\n1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;\n1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;\n1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;\n1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;\n1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;\n1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;\n1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;\n1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;ON;<font> 2207;;;;N;;;;;\n1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;\n1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;\n1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;\n1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;\n1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;\n1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;\n1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;\n1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;\n1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;\n1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;\n1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;\n1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;\n1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;\n1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;\n1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;\n1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;\n1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;\n1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;\n1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;\n1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;\n1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;\n1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;\n1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;\n1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;\n1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;\n1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;\n1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;\n1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;\n1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;\n1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;\n1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;\n1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;\n1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;\n1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;\n1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;\n1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;\n1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;\n1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;\n1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;\n1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;\n1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;\n1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;\n1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;\n1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;\n1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;\n1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;\n1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;\n1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;\n1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;\n1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;\n1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;\n1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;\n1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;\n1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;\n1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;\n1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;\n1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;\n1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;ON;<font> 2207;;;;N;;;;;\n1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;\n1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;\n1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;\n1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;\n1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;\n1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;\n1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;\n1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;\n1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;\n1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;\n1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;\n1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;\n1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;\n1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;\n1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;\n1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;\n1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;\n1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;\n1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;\n1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;\n1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;\n1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;\n1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;\n1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;\n1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;\n1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;\n1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;\n1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;\n1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;\n1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;\n1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;\n1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;\n1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;\n1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;\n1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;\n1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;\n1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;\n1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;\n1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;\n1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;\n1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;\n1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;\n1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;\n1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;\n1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;\n1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;\n1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;\n1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;\n1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;\n1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;\n1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;\n1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;\n1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;\n1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;\n1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;\n1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;\n1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;\n1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;ON;<font> 2207;;;;N;;;;;\n1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;\n1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;\n1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;\n1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;\n1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;\n1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;\n1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;\n1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;\n1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;\n1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;\n1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;\n1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;\n1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;\n1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;\n1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;\n1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;\n1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;\n1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;\n1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;\n1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;\n1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;\n1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;\n1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;\n1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;\n1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;\n1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;\n1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;\n1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;\n1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;\n1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;\n1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;\n1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;\n1D7CA;MATHEMATICAL BOLD CAPITAL DIGAMMA;Lu;0;L;<font> 03DC;;;;N;;;;;\n1D7CB;MATHEMATICAL BOLD SMALL DIGAMMA;Ll;0;L;<font> 03DD;;;;N;;;;;\n1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;\n1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;\n1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;\n1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;\n1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;\n1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;\n1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;\n1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;\n1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;\n1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;\n1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;\n1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;\n1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;\n1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;\n1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;\n1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;\n1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;\n1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;\n1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;\n1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;\n1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;\n1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;\n1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;\n1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;\n1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;\n1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;\n1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;\n1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;\n1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;\n1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;\n1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;\n1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;\n1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;\n1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;\n1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;\n1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;\n1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;\n1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;\n1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;\n1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;\n1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;\n1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;\n1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;\n1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;\n1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;\n1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;\n1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;\n1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;\n1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;\n1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;\n1D800;SIGNWRITING HAND-FIST INDEX;So;0;L;;;;;N;;;;;\n1D801;SIGNWRITING HAND-CIRCLE INDEX;So;0;L;;;;;N;;;;;\n1D802;SIGNWRITING HAND-CUP INDEX;So;0;L;;;;;N;;;;;\n1D803;SIGNWRITING HAND-OVAL INDEX;So;0;L;;;;;N;;;;;\n1D804;SIGNWRITING HAND-HINGE INDEX;So;0;L;;;;;N;;;;;\n1D805;SIGNWRITING HAND-ANGLE INDEX;So;0;L;;;;;N;;;;;\n1D806;SIGNWRITING HAND-FIST INDEX BENT;So;0;L;;;;;N;;;;;\n1D807;SIGNWRITING HAND-CIRCLE INDEX BENT;So;0;L;;;;;N;;;;;\n1D808;SIGNWRITING HAND-FIST THUMB UNDER INDEX BENT;So;0;L;;;;;N;;;;;\n1D809;SIGNWRITING HAND-FIST INDEX RAISED KNUCKLE;So;0;L;;;;;N;;;;;\n1D80A;SIGNWRITING HAND-FIST INDEX CUPPED;So;0;L;;;;;N;;;;;\n1D80B;SIGNWRITING HAND-FIST INDEX HINGED;So;0;L;;;;;N;;;;;\n1D80C;SIGNWRITING HAND-FIST INDEX HINGED LOW;So;0;L;;;;;N;;;;;\n1D80D;SIGNWRITING HAND-CIRCLE INDEX HINGE;So;0;L;;;;;N;;;;;\n1D80E;SIGNWRITING HAND-FIST INDEX MIDDLE;So;0;L;;;;;N;;;;;\n1D80F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE;So;0;L;;;;;N;;;;;\n1D810;SIGNWRITING HAND-FIST INDEX MIDDLE BENT;So;0;L;;;;;N;;;;;\n1D811;SIGNWRITING HAND-FIST INDEX MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;;\n1D812;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED;So;0;L;;;;;N;;;;;\n1D813;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED;So;0;L;;;;;N;;;;;\n1D814;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP;So;0;L;;;;;N;;;;;\n1D815;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED;So;0;L;;;;;N;;;;;\n1D816;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED INDEX BENT;So;0;L;;;;;N;;;;;\n1D817;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED MIDDLE BENT;So;0;L;;;;;N;;;;;\n1D818;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED;So;0;L;;;;;N;;;;;\n1D819;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED;So;0;L;;;;;N;;;;;\n1D81A;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;;\n1D81B;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;;\n1D81C;SIGNWRITING HAND-FIST MIDDLE BENT OVER INDEX;So;0;L;;;;;N;;;;;\n1D81D;SIGNWRITING HAND-FIST INDEX BENT OVER MIDDLE;So;0;L;;;;;N;;;;;\n1D81E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;;\n1D81F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;;\n1D820;SIGNWRITING HAND-FIST INDEX MIDDLE STRAIGHT THUMB BENT;So;0;L;;;;;N;;;;;\n1D821;SIGNWRITING HAND-FIST INDEX MIDDLE BENT THUMB STRAIGHT;So;0;L;;;;;N;;;;;\n1D822;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB BENT;So;0;L;;;;;N;;;;;\n1D823;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED SPREAD THUMB SIDE;So;0;L;;;;;N;;;;;\n1D824;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB SIDE;So;0;L;;;;;N;;;;;\n1D825;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB CONJOINED;So;0;L;;;;;N;;;;;\n1D826;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;;\n1D827;SIGNWRITING HAND-FIST INDEX MIDDLE UP SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D828;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CUPPED;So;0;L;;;;;N;;;;;\n1D829;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CIRCLED;So;0;L;;;;;N;;;;;\n1D82A;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HOOKED;So;0;L;;;;;N;;;;;\n1D82B;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HINGED;So;0;L;;;;;N;;;;;\n1D82C;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE STRAIGHT;So;0;L;;;;;N;;;;;\n1D82D;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE;So;0;L;;;;;N;;;;;\n1D82E;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;;\n1D82F;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE BENT;So;0;L;;;;;N;;;;;\n1D830;SIGNWRITING HAND-FIST MIDDLE THUMB HOOKED INDEX UP;So;0;L;;;;;N;;;;;\n1D831;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE UP;So;0;L;;;;;N;;;;;\n1D832;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED THUMB SIDE;So;0;L;;;;;N;;;;;\n1D833;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED THUMB SIDE;So;0;L;;;;;N;;;;;\n1D834;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D835;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D836;SIGNWRITING HAND-FIST MIDDLE THUMB CUPPED INDEX UP;So;0;L;;;;;N;;;;;\n1D837;SIGNWRITING HAND-FIST INDEX THUMB CUPPED MIDDLE UP;So;0;L;;;;;N;;;;;\n1D838;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX UP;So;0;L;;;;;N;;;;;\n1D839;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX HINGED;So;0;L;;;;;N;;;;;\n1D83A;SIGNWRITING HAND-FIST INDEX THUMB ANGLED OUT MIDDLE UP;So;0;L;;;;;N;;;;;\n1D83B;SIGNWRITING HAND-FIST INDEX THUMB ANGLED IN MIDDLE UP;So;0;L;;;;;N;;;;;\n1D83C;SIGNWRITING HAND-FIST INDEX THUMB CIRCLED MIDDLE UP;So;0;L;;;;;N;;;;;\n1D83D;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CONJOINED HINGED;So;0;L;;;;;N;;;;;\n1D83E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED OUT;So;0;L;;;;;N;;;;;\n1D83F;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED;So;0;L;;;;;N;;;;;\n1D840;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX UP;So;0;L;;;;;N;;;;;\n1D841;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX CROSSED;So;0;L;;;;;N;;;;;\n1D842;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED INDEX UP;So;0;L;;;;;N;;;;;\n1D843;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE HINGED;So;0;L;;;;;N;;;;;\n1D844;SIGNWRITING HAND-FLAT FOUR FINGERS;So;0;L;;;;;N;;;;;\n1D845;SIGNWRITING HAND-FLAT FOUR FINGERS BENT;So;0;L;;;;;N;;;;;\n1D846;SIGNWRITING HAND-FLAT FOUR FINGERS HINGED;So;0;L;;;;;N;;;;;\n1D847;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;;\n1D848;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED SPLIT;So;0;L;;;;;N;;;;;\n1D849;SIGNWRITING HAND-CLAW FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;;\n1D84A;SIGNWRITING HAND-FIST FOUR FINGERS CONJOINED BENT;So;0;L;;;;;N;;;;;\n1D84B;SIGNWRITING HAND-HINGE FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;;\n1D84C;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;;\n1D84D;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;;\n1D84E;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;;\n1D84F;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;;\n1D850;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;;\n1D851;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;;\n1D852;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D853;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;;\n1D854;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;;\n1D855;SIGNWRITING HAND-HINGE FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;;\n1D856;SIGNWRITING HAND-OVAL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;;\n1D857;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED;So;0;L;;;;;N;;;;;\n1D858;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED THUMB SIDE;So;0;L;;;;;N;;;;;\n1D859;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED NO THUMB;So;0;L;;;;;N;;;;;\n1D85A;SIGNWRITING HAND-FLAT;So;0;L;;;;;N;;;;;\n1D85B;SIGNWRITING HAND-FLAT BETWEEN PALM FACINGS;So;0;L;;;;;N;;;;;\n1D85C;SIGNWRITING HAND-FLAT HEEL;So;0;L;;;;;N;;;;;\n1D85D;SIGNWRITING HAND-FLAT THUMB SIDE;So;0;L;;;;;N;;;;;\n1D85E;SIGNWRITING HAND-FLAT HEEL THUMB SIDE;So;0;L;;;;;N;;;;;\n1D85F;SIGNWRITING HAND-FLAT THUMB BENT;So;0;L;;;;;N;;;;;\n1D860;SIGNWRITING HAND-FLAT THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D861;SIGNWRITING HAND-FLAT SPLIT INDEX THUMB SIDE;So;0;L;;;;;N;;;;;\n1D862;SIGNWRITING HAND-FLAT SPLIT CENTRE;So;0;L;;;;;N;;;;;\n1D863;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE;So;0;L;;;;;N;;;;;\n1D864;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE BENT;So;0;L;;;;;N;;;;;\n1D865;SIGNWRITING HAND-FLAT SPLIT LITTLE;So;0;L;;;;;N;;;;;\n1D866;SIGNWRITING HAND-CLAW;So;0;L;;;;;N;;;;;\n1D867;SIGNWRITING HAND-CLAW THUMB SIDE;So;0;L;;;;;N;;;;;\n1D868;SIGNWRITING HAND-CLAW NO THUMB;So;0;L;;;;;N;;;;;\n1D869;SIGNWRITING HAND-CLAW THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D86A;SIGNWRITING HAND-HOOK CURLICUE;So;0;L;;;;;N;;;;;\n1D86B;SIGNWRITING HAND-HOOK;So;0;L;;;;;N;;;;;\n1D86C;SIGNWRITING HAND-CUP OPEN;So;0;L;;;;;N;;;;;\n1D86D;SIGNWRITING HAND-CUP;So;0;L;;;;;N;;;;;\n1D86E;SIGNWRITING HAND-CUP OPEN THUMB SIDE;So;0;L;;;;;N;;;;;\n1D86F;SIGNWRITING HAND-CUP THUMB SIDE;So;0;L;;;;;N;;;;;\n1D870;SIGNWRITING HAND-CUP OPEN NO THUMB;So;0;L;;;;;N;;;;;\n1D871;SIGNWRITING HAND-CUP NO THUMB;So;0;L;;;;;N;;;;;\n1D872;SIGNWRITING HAND-CUP OPEN THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D873;SIGNWRITING HAND-CUP THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D874;SIGNWRITING HAND-CURLICUE OPEN;So;0;L;;;;;N;;;;;\n1D875;SIGNWRITING HAND-CURLICUE;So;0;L;;;;;N;;;;;\n1D876;SIGNWRITING HAND-CIRCLE;So;0;L;;;;;N;;;;;\n1D877;SIGNWRITING HAND-OVAL;So;0;L;;;;;N;;;;;\n1D878;SIGNWRITING HAND-OVAL THUMB SIDE;So;0;L;;;;;N;;;;;\n1D879;SIGNWRITING HAND-OVAL NO THUMB;So;0;L;;;;;N;;;;;\n1D87A;SIGNWRITING HAND-OVAL THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D87B;SIGNWRITING HAND-HINGE OPEN;So;0;L;;;;;N;;;;;\n1D87C;SIGNWRITING HAND-HINGE OPEN THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D87D;SIGNWRITING HAND-HINGE;So;0;L;;;;;N;;;;;\n1D87E;SIGNWRITING HAND-HINGE SMALL;So;0;L;;;;;N;;;;;\n1D87F;SIGNWRITING HAND-HINGE OPEN THUMB SIDE;So;0;L;;;;;N;;;;;\n1D880;SIGNWRITING HAND-HINGE THUMB SIDE;So;0;L;;;;;N;;;;;\n1D881;SIGNWRITING HAND-HINGE OPEN NO THUMB;So;0;L;;;;;N;;;;;\n1D882;SIGNWRITING HAND-HINGE NO THUMB;So;0;L;;;;;N;;;;;\n1D883;SIGNWRITING HAND-HINGE THUMB SIDE TOUCHING INDEX;So;0;L;;;;;N;;;;;\n1D884;SIGNWRITING HAND-HINGE THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;;\n1D885;SIGNWRITING HAND-ANGLE;So;0;L;;;;;N;;;;;\n1D886;SIGNWRITING HAND-FIST INDEX MIDDLE RING;So;0;L;;;;;N;;;;;\n1D887;SIGNWRITING HAND-CIRCLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;;\n1D888;SIGNWRITING HAND-HINGE INDEX MIDDLE RING;So;0;L;;;;;N;;;;;\n1D889;SIGNWRITING HAND-ANGLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;;\n1D88A;SIGNWRITING HAND-HINGE LITTLE;So;0;L;;;;;N;;;;;\n1D88B;SIGNWRITING HAND-FIST INDEX MIDDLE RING BENT;So;0;L;;;;;N;;;;;\n1D88C;SIGNWRITING HAND-FIST INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;;\n1D88D;SIGNWRITING HAND-HINGE INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;;\n1D88E;SIGNWRITING HAND-FIST LITTLE DOWN;So;0;L;;;;;N;;;;;\n1D88F;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE STRAIGHT;So;0;L;;;;;N;;;;;\n1D890;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE CURVED;So;0;L;;;;;N;;;;;\n1D891;SIGNWRITING HAND-FIST LITTLE DOWN OTHERS CIRCLED;So;0;L;;;;;N;;;;;\n1D892;SIGNWRITING HAND-FIST LITTLE UP;So;0;L;;;;;N;;;;;\n1D893;SIGNWRITING HAND-FIST THUMB UNDER LITTLE UP;So;0;L;;;;;N;;;;;\n1D894;SIGNWRITING HAND-CIRCLE LITTLE UP;So;0;L;;;;;N;;;;;\n1D895;SIGNWRITING HAND-OVAL LITTLE UP;So;0;L;;;;;N;;;;;\n1D896;SIGNWRITING HAND-ANGLE LITTLE UP;So;0;L;;;;;N;;;;;\n1D897;SIGNWRITING HAND-FIST LITTLE RAISED KNUCKLE;So;0;L;;;;;N;;;;;\n1D898;SIGNWRITING HAND-FIST LITTLE BENT;So;0;L;;;;;N;;;;;\n1D899;SIGNWRITING HAND-FIST LITTLE TOUCHES THUMB;So;0;L;;;;;N;;;;;\n1D89A;SIGNWRITING HAND-FIST LITTLE THUMB;So;0;L;;;;;N;;;;;\n1D89B;SIGNWRITING HAND-HINGE LITTLE THUMB;So;0;L;;;;;N;;;;;\n1D89C;SIGNWRITING HAND-FIST LITTLE INDEX THUMB;So;0;L;;;;;N;;;;;\n1D89D;SIGNWRITING HAND-HINGE LITTLE INDEX THUMB;So;0;L;;;;;N;;;;;\n1D89E;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB OUT;So;0;L;;;;;N;;;;;\n1D89F;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB;So;0;L;;;;;N;;;;;\n1D8A0;SIGNWRITING HAND-FIST LITTLE INDEX;So;0;L;;;;;N;;;;;\n1D8A1;SIGNWRITING HAND-CIRCLE LITTLE INDEX;So;0;L;;;;;N;;;;;\n1D8A2;SIGNWRITING HAND-HINGE LITTLE INDEX;So;0;L;;;;;N;;;;;\n1D8A3;SIGNWRITING HAND-ANGLE LITTLE INDEX;So;0;L;;;;;N;;;;;\n1D8A4;SIGNWRITING HAND-FIST INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;;\n1D8A5;SIGNWRITING HAND-CIRCLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;;\n1D8A6;SIGNWRITING HAND-HINGE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;;\n1D8A7;SIGNWRITING HAND-HINGE RING;So;0;L;;;;;N;;;;;\n1D8A8;SIGNWRITING HAND-ANGLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;;\n1D8A9;SIGNWRITING HAND-FIST INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;;\n1D8AA;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;;\n1D8AB;SIGNWRITING HAND-FIST RING DOWN;So;0;L;;;;;N;;;;;\n1D8AC;SIGNWRITING HAND-HINGE RING DOWN INDEX THUMB HOOK MIDDLE;So;0;L;;;;;N;;;;;\n1D8AD;SIGNWRITING HAND-ANGLE RING DOWN MIDDLE THUMB INDEX CROSS;So;0;L;;;;;N;;;;;\n1D8AE;SIGNWRITING HAND-FIST RING UP;So;0;L;;;;;N;;;;;\n1D8AF;SIGNWRITING HAND-FIST RING RAISED KNUCKLE;So;0;L;;;;;N;;;;;\n1D8B0;SIGNWRITING HAND-FIST RING LITTLE;So;0;L;;;;;N;;;;;\n1D8B1;SIGNWRITING HAND-CIRCLE RING LITTLE;So;0;L;;;;;N;;;;;\n1D8B2;SIGNWRITING HAND-OVAL RING LITTLE;So;0;L;;;;;N;;;;;\n1D8B3;SIGNWRITING HAND-ANGLE RING LITTLE;So;0;L;;;;;N;;;;;\n1D8B4;SIGNWRITING HAND-FIST RING MIDDLE;So;0;L;;;;;N;;;;;\n1D8B5;SIGNWRITING HAND-FIST RING MIDDLE CONJOINED;So;0;L;;;;;N;;;;;\n1D8B6;SIGNWRITING HAND-FIST RING MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;;\n1D8B7;SIGNWRITING HAND-FIST RING INDEX;So;0;L;;;;;N;;;;;\n1D8B8;SIGNWRITING HAND-FIST RING THUMB;So;0;L;;;;;N;;;;;\n1D8B9;SIGNWRITING HAND-HOOK RING THUMB;So;0;L;;;;;N;;;;;\n1D8BA;SIGNWRITING HAND-FIST INDEX RING LITTLE;So;0;L;;;;;N;;;;;\n1D8BB;SIGNWRITING HAND-CIRCLE INDEX RING LITTLE;So;0;L;;;;;N;;;;;\n1D8BC;SIGNWRITING HAND-CURLICUE INDEX RING LITTLE ON;So;0;L;;;;;N;;;;;\n1D8BD;SIGNWRITING HAND-HOOK INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;;\n1D8BE;SIGNWRITING HAND-HOOK INDEX RING LITTLE IN;So;0;L;;;;;N;;;;;\n1D8BF;SIGNWRITING HAND-HOOK INDEX RING LITTLE UNDER;So;0;L;;;;;N;;;;;\n1D8C0;SIGNWRITING HAND-CUP INDEX RING LITTLE;So;0;L;;;;;N;;;;;\n1D8C1;SIGNWRITING HAND-HINGE INDEX RING LITTLE;So;0;L;;;;;N;;;;;\n1D8C2;SIGNWRITING HAND-ANGLE INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;;\n1D8C3;SIGNWRITING HAND-ANGLE INDEX RING LITTLE;So;0;L;;;;;N;;;;;\n1D8C4;SIGNWRITING HAND-FIST MIDDLE DOWN;So;0;L;;;;;N;;;;;\n1D8C5;SIGNWRITING HAND-HINGE MIDDLE;So;0;L;;;;;N;;;;;\n1D8C6;SIGNWRITING HAND-FIST MIDDLE UP;So;0;L;;;;;N;;;;;\n1D8C7;SIGNWRITING HAND-CIRCLE MIDDLE UP;So;0;L;;;;;N;;;;;\n1D8C8;SIGNWRITING HAND-FIST MIDDLE RAISED KNUCKLE;So;0;L;;;;;N;;;;;\n1D8C9;SIGNWRITING HAND-FIST MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;;\n1D8CA;SIGNWRITING HAND-HOOK MIDDLE THUMB;So;0;L;;;;;N;;;;;\n1D8CB;SIGNWRITING HAND-FIST MIDDLE THUMB LITTLE;So;0;L;;;;;N;;;;;\n1D8CC;SIGNWRITING HAND-FIST MIDDLE LITTLE;So;0;L;;;;;N;;;;;\n1D8CD;SIGNWRITING HAND-FIST MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;\n1D8CE;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;\n1D8CF;SIGNWRITING HAND-CURLICUE MIDDLE RING LITTLE ON;So;0;L;;;;;N;;;;;\n1D8D0;SIGNWRITING HAND-CUP MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;\n1D8D1;SIGNWRITING HAND-HINGE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;\n1D8D2;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE OUT;So;0;L;;;;;N;;;;;\n1D8D3;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE IN;So;0;L;;;;;N;;;;;\n1D8D4;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;\n1D8D5;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE BENT;So;0;L;;;;;N;;;;;\n1D8D6;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;;\n1D8D7;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED SIDE;So;0;L;;;;;N;;;;;\n1D8D8;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED OUT;So;0;L;;;;;N;;;;;\n1D8D9;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED IN;So;0;L;;;;;N;;;;;\n1D8DA;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;;\n1D8DB;SIGNWRITING HAND-HINGE INDEX HINGED;So;0;L;;;;;N;;;;;\n1D8DC;SIGNWRITING HAND-FIST INDEX THUMB SIDE;So;0;L;;;;;N;;;;;\n1D8DD;SIGNWRITING HAND-HINGE INDEX THUMB SIDE;So;0;L;;;;;N;;;;;\n1D8DE;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB DIAGONAL;So;0;L;;;;;N;;;;;\n1D8DF;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB CONJOINED;So;0;L;;;;;N;;;;;\n1D8E0;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB BENT;So;0;L;;;;;N;;;;;\n1D8E1;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX BENT;So;0;L;;;;;N;;;;;\n1D8E2;SIGNWRITING HAND-FIST INDEX THUMB SIDE BOTH BENT;So;0;L;;;;;N;;;;;\n1D8E3;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX HINGE;So;0;L;;;;;N;;;;;\n1D8E4;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX STRAIGHT;So;0;L;;;;;N;;;;;\n1D8E5;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX BENT;So;0;L;;;;;N;;;;;\n1D8E6;SIGNWRITING HAND-FIST INDEX THUMB HOOK;So;0;L;;;;;N;;;;;\n1D8E7;SIGNWRITING HAND-FIST INDEX THUMB CURLICUE;So;0;L;;;;;N;;;;;\n1D8E8;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;;\n1D8E9;SIGNWRITING HAND-CLAW INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;;\n1D8EA;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB UNDER;So;0;L;;;;;N;;;;;\n1D8EB;SIGNWRITING HAND-FIST INDEX THUMB CIRCLE;So;0;L;;;;;N;;;;;\n1D8EC;SIGNWRITING HAND-CUP INDEX THUMB;So;0;L;;;;;N;;;;;\n1D8ED;SIGNWRITING HAND-CUP INDEX THUMB OPEN;So;0;L;;;;;N;;;;;\n1D8EE;SIGNWRITING HAND-HINGE INDEX THUMB OPEN;So;0;L;;;;;N;;;;;\n1D8EF;SIGNWRITING HAND-HINGE INDEX THUMB LARGE;So;0;L;;;;;N;;;;;\n1D8F0;SIGNWRITING HAND-HINGE INDEX THUMB;So;0;L;;;;;N;;;;;\n1D8F1;SIGNWRITING HAND-HINGE INDEX THUMB SMALL;So;0;L;;;;;N;;;;;\n1D8F2;SIGNWRITING HAND-ANGLE INDEX THUMB OUT;So;0;L;;;;;N;;;;;\n1D8F3;SIGNWRITING HAND-ANGLE INDEX THUMB IN;So;0;L;;;;;N;;;;;\n1D8F4;SIGNWRITING HAND-ANGLE INDEX THUMB;So;0;L;;;;;N;;;;;\n1D8F5;SIGNWRITING HAND-FIST THUMB;So;0;L;;;;;N;;;;;\n1D8F6;SIGNWRITING HAND-FIST THUMB HEEL;So;0;L;;;;;N;;;;;\n1D8F7;SIGNWRITING HAND-FIST THUMB SIDE DIAGONAL;So;0;L;;;;;N;;;;;\n1D8F8;SIGNWRITING HAND-FIST THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;;\n1D8F9;SIGNWRITING HAND-FIST THUMB SIDE BENT;So;0;L;;;;;N;;;;;\n1D8FA;SIGNWRITING HAND-FIST THUMB FORWARD;So;0;L;;;;;N;;;;;\n1D8FB;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE;So;0;L;;;;;N;;;;;\n1D8FC;SIGNWRITING HAND-FIST THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;;\n1D8FD;SIGNWRITING HAND-FIST THUMB BETWEEN RING LITTLE;So;0;L;;;;;N;;;;;\n1D8FE;SIGNWRITING HAND-FIST THUMB UNDER TWO FINGERS;So;0;L;;;;;N;;;;;\n1D8FF;SIGNWRITING HAND-FIST THUMB OVER TWO FINGERS;So;0;L;;;;;N;;;;;\n1D900;SIGNWRITING HAND-FIST THUMB UNDER THREE FINGERS;So;0;L;;;;;N;;;;;\n1D901;SIGNWRITING HAND-FIST THUMB UNDER FOUR FINGERS;So;0;L;;;;;N;;;;;\n1D902;SIGNWRITING HAND-FIST THUMB OVER FOUR RAISED KNUCKLES;So;0;L;;;;;N;;;;;\n1D903;SIGNWRITING HAND-FIST;So;0;L;;;;;N;;;;;\n1D904;SIGNWRITING HAND-FIST HEEL;So;0;L;;;;;N;;;;;\n1D905;SIGNWRITING TOUCH SINGLE;So;0;L;;;;;N;;;;;\n1D906;SIGNWRITING TOUCH MULTIPLE;So;0;L;;;;;N;;;;;\n1D907;SIGNWRITING TOUCH BETWEEN;So;0;L;;;;;N;;;;;\n1D908;SIGNWRITING GRASP SINGLE;So;0;L;;;;;N;;;;;\n1D909;SIGNWRITING GRASP MULTIPLE;So;0;L;;;;;N;;;;;\n1D90A;SIGNWRITING GRASP BETWEEN;So;0;L;;;;;N;;;;;\n1D90B;SIGNWRITING STRIKE SINGLE;So;0;L;;;;;N;;;;;\n1D90C;SIGNWRITING STRIKE MULTIPLE;So;0;L;;;;;N;;;;;\n1D90D;SIGNWRITING STRIKE BETWEEN;So;0;L;;;;;N;;;;;\n1D90E;SIGNWRITING BRUSH SINGLE;So;0;L;;;;;N;;;;;\n1D90F;SIGNWRITING BRUSH MULTIPLE;So;0;L;;;;;N;;;;;\n1D910;SIGNWRITING BRUSH BETWEEN;So;0;L;;;;;N;;;;;\n1D911;SIGNWRITING RUB SINGLE;So;0;L;;;;;N;;;;;\n1D912;SIGNWRITING RUB MULTIPLE;So;0;L;;;;;N;;;;;\n1D913;SIGNWRITING RUB BETWEEN;So;0;L;;;;;N;;;;;\n1D914;SIGNWRITING SURFACE SYMBOLS;So;0;L;;;;;N;;;;;\n1D915;SIGNWRITING SURFACE BETWEEN;So;0;L;;;;;N;;;;;\n1D916;SIGNWRITING SQUEEZE LARGE SINGLE;So;0;L;;;;;N;;;;;\n1D917;SIGNWRITING SQUEEZE SMALL SINGLE;So;0;L;;;;;N;;;;;\n1D918;SIGNWRITING SQUEEZE LARGE MULTIPLE;So;0;L;;;;;N;;;;;\n1D919;SIGNWRITING SQUEEZE SMALL MULTIPLE;So;0;L;;;;;N;;;;;\n1D91A;SIGNWRITING SQUEEZE SEQUENTIAL;So;0;L;;;;;N;;;;;\n1D91B;SIGNWRITING FLICK LARGE SINGLE;So;0;L;;;;;N;;;;;\n1D91C;SIGNWRITING FLICK SMALL SINGLE;So;0;L;;;;;N;;;;;\n1D91D;SIGNWRITING FLICK LARGE MULTIPLE;So;0;L;;;;;N;;;;;\n1D91E;SIGNWRITING FLICK SMALL MULTIPLE;So;0;L;;;;;N;;;;;\n1D91F;SIGNWRITING FLICK SEQUENTIAL;So;0;L;;;;;N;;;;;\n1D920;SIGNWRITING SQUEEZE FLICK ALTERNATING;So;0;L;;;;;N;;;;;\n1D921;SIGNWRITING MOVEMENT-HINGE UP DOWN LARGE;So;0;L;;;;;N;;;;;\n1D922;SIGNWRITING MOVEMENT-HINGE UP DOWN SMALL;So;0;L;;;;;N;;;;;\n1D923;SIGNWRITING MOVEMENT-HINGE UP SEQUENTIAL;So;0;L;;;;;N;;;;;\n1D924;SIGNWRITING MOVEMENT-HINGE DOWN SEQUENTIAL;So;0;L;;;;;N;;;;;\n1D925;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING LARGE;So;0;L;;;;;N;;;;;\n1D926;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING SMALL;So;0;L;;;;;N;;;;;\n1D927;SIGNWRITING MOVEMENT-HINGE SIDE TO SIDE SCISSORS;So;0;L;;;;;N;;;;;\n1D928;SIGNWRITING MOVEMENT-WALLPLANE FINGER CONTACT;So;0;L;;;;;N;;;;;\n1D929;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CONTACT;So;0;L;;;;;N;;;;;\n1D92A;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;;\n1D92B;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;;\n1D92C;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;;\n1D92D;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;;\n1D92E;SIGNWRITING MOVEMENT-WALLPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;;\n1D92F;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;;\n1D930;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;;\n1D931;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;;\n1D932;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;;\n1D933;SIGNWRITING MOVEMENT-WALLPLANE CROSS;So;0;L;;;;;N;;;;;\n1D934;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;;\n1D935;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;;\n1D936;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING;So;0;L;;;;;N;;;;;\n1D937;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;;\n1D938;SIGNWRITING MOVEMENT-WALLPLANE BEND SMALL;So;0;L;;;;;N;;;;;\n1D939;SIGNWRITING MOVEMENT-WALLPLANE BEND MEDIUM;So;0;L;;;;;N;;;;;\n1D93A;SIGNWRITING MOVEMENT-WALLPLANE BEND LARGE;So;0;L;;;;;N;;;;;\n1D93B;SIGNWRITING MOVEMENT-WALLPLANE CORNER SMALL;So;0;L;;;;;N;;;;;\n1D93C;SIGNWRITING MOVEMENT-WALLPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;;\n1D93D;SIGNWRITING MOVEMENT-WALLPLANE CORNER LARGE;So;0;L;;;;;N;;;;;\n1D93E;SIGNWRITING MOVEMENT-WALLPLANE CORNER ROTATION;So;0;L;;;;;N;;;;;\n1D93F;SIGNWRITING MOVEMENT-WALLPLANE CHECK SMALL;So;0;L;;;;;N;;;;;\n1D940;SIGNWRITING MOVEMENT-WALLPLANE CHECK MEDIUM;So;0;L;;;;;N;;;;;\n1D941;SIGNWRITING MOVEMENT-WALLPLANE CHECK LARGE;So;0;L;;;;;N;;;;;\n1D942;SIGNWRITING MOVEMENT-WALLPLANE BOX SMALL;So;0;L;;;;;N;;;;;\n1D943;SIGNWRITING MOVEMENT-WALLPLANE BOX MEDIUM;So;0;L;;;;;N;;;;;\n1D944;SIGNWRITING MOVEMENT-WALLPLANE BOX LARGE;So;0;L;;;;;N;;;;;\n1D945;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;;\n1D946;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;;\n1D947;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;;\n1D948;SIGNWRITING MOVEMENT-WALLPLANE PEAKS SMALL;So;0;L;;;;;N;;;;;\n1D949;SIGNWRITING MOVEMENT-WALLPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;;\n1D94A;SIGNWRITING MOVEMENT-WALLPLANE PEAKS LARGE;So;0;L;;;;;N;;;;;\n1D94B;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;;\n1D94C;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;;\n1D94D;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;;\n1D94E;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;;\n1D94F;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;;\n1D950;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;;\n1D951;SIGNWRITING TRAVEL-WALLPLANE SHAKING;So;0;L;;;;;N;;;;;\n1D952;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL SINGLE;So;0;L;;;;;N;;;;;\n1D953;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL DOUBLE;So;0;L;;;;;N;;;;;\n1D954;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL TRIPLE;So;0;L;;;;;N;;;;;\n1D955;SIGNWRITING MOVEMENT-DIAGONAL AWAY SMALL;So;0;L;;;;;N;;;;;\n1D956;SIGNWRITING MOVEMENT-DIAGONAL AWAY MEDIUM;So;0;L;;;;;N;;;;;\n1D957;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGE;So;0;L;;;;;N;;;;;\n1D958;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGEST;So;0;L;;;;;N;;;;;\n1D959;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS SMALL;So;0;L;;;;;N;;;;;\n1D95A;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS MEDIUM;So;0;L;;;;;N;;;;;\n1D95B;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGE;So;0;L;;;;;N;;;;;\n1D95C;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGEST;So;0;L;;;;;N;;;;;\n1D95D;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY SMALL;So;0;L;;;;;N;;;;;\n1D95E;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY MEDIUM;So;0;L;;;;;N;;;;;\n1D95F;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGE;So;0;L;;;;;N;;;;;\n1D960;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGEST;So;0;L;;;;;N;;;;;\n1D961;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS SMALL;So;0;L;;;;;N;;;;;\n1D962;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS MEDIUM;So;0;L;;;;;N;;;;;\n1D963;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGE;So;0;L;;;;;N;;;;;\n1D964;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGEST;So;0;L;;;;;N;;;;;\n1D965;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;;\n1D966;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;;\n1D967;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;;\n1D968;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;;\n1D969;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;;\n1D96A;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;;\n1D96B;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;;\n1D96C;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;;\n1D96D;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;;\n1D96E;SIGNWRITING MOVEMENT-FLOORPLANE CROSS;So;0;L;;;;;N;;;;;\n1D96F;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;;\n1D970;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;;\n1D971;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING MOVEMENT;So;0;L;;;;;N;;;;;\n1D972;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;;\n1D973;SIGNWRITING MOVEMENT-FLOORPLANE BEND;So;0;L;;;;;N;;;;;\n1D974;SIGNWRITING MOVEMENT-FLOORPLANE CORNER SMALL;So;0;L;;;;;N;;;;;\n1D975;SIGNWRITING MOVEMENT-FLOORPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;;\n1D976;SIGNWRITING MOVEMENT-FLOORPLANE CORNER LARGE;So;0;L;;;;;N;;;;;\n1D977;SIGNWRITING MOVEMENT-FLOORPLANE CHECK;So;0;L;;;;;N;;;;;\n1D978;SIGNWRITING MOVEMENT-FLOORPLANE BOX SMALL;So;0;L;;;;;N;;;;;\n1D979;SIGNWRITING MOVEMENT-FLOORPLANE BOX MEDIUM;So;0;L;;;;;N;;;;;\n1D97A;SIGNWRITING MOVEMENT-FLOORPLANE BOX LARGE;So;0;L;;;;;N;;;;;\n1D97B;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;;\n1D97C;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;;\n1D97D;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;;\n1D97E;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS SMALL;So;0;L;;;;;N;;;;;\n1D97F;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;;\n1D980;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS LARGE;So;0;L;;;;;N;;;;;\n1D981;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;;\n1D982;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;;\n1D983;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;;\n1D984;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;;\n1D985;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;;\n1D986;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;;\n1D987;SIGNWRITING TRAVEL-FLOORPLANE SHAKING;So;0;L;;;;;N;;;;;\n1D988;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER SMALL;So;0;L;;;;;N;;;;;\n1D989;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER MEDIUM;So;0;L;;;;;N;;;;;\n1D98A;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGE;So;0;L;;;;;N;;;;;\n1D98B;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGEST;So;0;L;;;;;N;;;;;\n1D98C;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE SMALL;So;0;L;;;;;N;;;;;\n1D98D;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE MEDIUM;So;0;L;;;;;N;;;;;\n1D98E;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGE;So;0;L;;;;;N;;;;;\n1D98F;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGEST;So;0;L;;;;;N;;;;;\n1D990;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE SMALL;So;0;L;;;;;N;;;;;\n1D991;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE MEDIUM;So;0;L;;;;;N;;;;;\n1D992;SIGNWRITING MOVEMENT-WALLPLANE HUMP SMALL;So;0;L;;;;;N;;;;;\n1D993;SIGNWRITING MOVEMENT-WALLPLANE HUMP MEDIUM;So;0;L;;;;;N;;;;;\n1D994;SIGNWRITING MOVEMENT-WALLPLANE HUMP LARGE;So;0;L;;;;;N;;;;;\n1D995;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL;So;0;L;;;;;N;;;;;\n1D996;SIGNWRITING MOVEMENT-WALLPLANE LOOP MEDIUM;So;0;L;;;;;N;;;;;\n1D997;SIGNWRITING MOVEMENT-WALLPLANE LOOP LARGE;So;0;L;;;;;N;;;;;\n1D998;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL DOUBLE;So;0;L;;;;;N;;;;;\n1D999;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE SMALL;So;0;L;;;;;N;;;;;\n1D99A;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE MEDIUM;So;0;L;;;;;N;;;;;\n1D99B;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE LARGE;So;0;L;;;;;N;;;;;\n1D99C;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE SMALL;So;0;L;;;;;N;;;;;\n1D99D;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE MEDIUM;So;0;L;;;;;N;;;;;\n1D99E;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE LARGE;So;0;L;;;;;N;;;;;\n1D99F;SIGNWRITING MOVEMENT-WALLPLANE CURVE THEN STRAIGHT;So;0;L;;;;;N;;;;;\n1D9A0;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS SMALL;So;0;L;;;;;N;;;;;\n1D9A1;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS MEDIUM;So;0;L;;;;;N;;;;;\n1D9A2;SIGNWRITING ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;;\n1D9A3;SIGNWRITING ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;;\n1D9A4;SIGNWRITING ROTATION-WALLPLANE ALTERNATE;So;0;L;;;;;N;;;;;\n1D9A5;SIGNWRITING MOVEMENT-WALLPLANE SHAKING;So;0;L;;;;;N;;;;;\n1D9A6;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING FRONT WALL;So;0;L;;;;;N;;;;;\n1D9A7;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING FRONT WALL;So;0;L;;;;;N;;;;;\n1D9A8;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING FRONT WALL;So;0;L;;;;;N;;;;;\n1D9A9;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING FRONT WALL;So;0;L;;;;;N;;;;;\n1D9AA;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING FRONT WALL;So;0;L;;;;;N;;;;;\n1D9AB;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING FRONT WALL;So;0;L;;;;;N;;;;;\n1D9AC;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING FRONT WALL;So;0;L;;;;;N;;;;;\n1D9AD;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING CHEST;So;0;L;;;;;N;;;;;\n1D9AE;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING CHEST;So;0;L;;;;;N;;;;;\n1D9AF;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING CHEST;So;0;L;;;;;N;;;;;\n1D9B0;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING CHEST;So;0;L;;;;;N;;;;;\n1D9B1;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING CHEST;So;0;L;;;;;N;;;;;\n1D9B2;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING CHEST;So;0;L;;;;;N;;;;;\n1D9B3;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING CHEST;So;0;L;;;;;N;;;;;\n1D9B4;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH SMALL;So;0;L;;;;;N;;;;;\n1D9B5;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH MEDIUM;So;0;L;;;;;N;;;;;\n1D9B6;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH LARGE;So;0;L;;;;;N;;;;;\n1D9B7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;;\n1D9B8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;;\n1D9B9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;;\n1D9BA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;;\n1D9BB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL TRIPLE;So;0;L;;;;;N;;;;;\n1D9BC;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE TRIPLE;So;0;L;;;;;N;;;;;\n1D9BD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL SINGLE;So;0;L;;;;;N;;;;;\n1D9BE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE SINGLE;So;0;L;;;;;N;;;;;\n1D9BF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;;\n1D9C0;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;;\n1D9C1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;;\n1D9C2;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;;\n1D9C3;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING CEILING;So;0;L;;;;;N;;;;;\n1D9C4;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING CEILING;So;0;L;;;;;N;;;;;\n1D9C5;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING CEILING;So;0;L;;;;;N;;;;;\n1D9C6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;;\n1D9C7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;;\n1D9C8;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;;\n1D9C9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;;\n1D9CA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE SMALL TRIPLE;So;0;L;;;;;N;;;;;\n1D9CB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE LARGE TRIPLE;So;0;L;;;;;N;;;;;\n1D9CC;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL SINGLE;So;0;L;;;;;N;;;;;\n1D9CD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE SINGLE;So;0;L;;;;;N;;;;;\n1D9CE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;;\n1D9CF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;;\n1D9D0;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;;\n1D9D1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;;\n1D9D2;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING FLOOR;So;0;L;;;;;N;;;;;\n1D9D3;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING FLOOR;So;0;L;;;;;N;;;;;\n1D9D4;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING FLOOR;So;0;L;;;;;N;;;;;\n1D9D5;SIGNWRITING MOVEMENT-FLOORPLANE CURVE SMALL;So;0;L;;;;;N;;;;;\n1D9D6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE MEDIUM;So;0;L;;;;;N;;;;;\n1D9D7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGE;So;0;L;;;;;N;;;;;\n1D9D8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGEST;So;0;L;;;;;N;;;;;\n1D9D9;SIGNWRITING MOVEMENT-FLOORPLANE CURVE COMBINED;So;0;L;;;;;N;;;;;\n1D9DA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP SMALL;So;0;L;;;;;N;;;;;\n1D9DB;SIGNWRITING MOVEMENT-FLOORPLANE LOOP SMALL;So;0;L;;;;;N;;;;;\n1D9DC;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SNAKE;So;0;L;;;;;N;;;;;\n1D9DD;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SMALL;So;0;L;;;;;N;;;;;\n1D9DE;SIGNWRITING MOVEMENT-FLOORPLANE WAVE LARGE;So;0;L;;;;;N;;;;;\n1D9DF;SIGNWRITING ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;;\n1D9E0;SIGNWRITING ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;;\n1D9E1;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;;\n1D9E2;SIGNWRITING MOVEMENT-FLOORPLANE SHAKING PARALLEL;So;0;L;;;;;N;;;;;\n1D9E3;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL SINGLE;So;0;L;;;;;N;;;;;\n1D9E4;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM SINGLE;So;0;L;;;;;N;;;;;\n1D9E5;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL DOUBLE;So;0;L;;;;;N;;;;;\n1D9E6;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM DOUBLE;So;0;L;;;;;N;;;;;\n1D9E7;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL SINGLE;So;0;L;;;;;N;;;;;\n1D9E8;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM SINGLE;So;0;L;;;;;N;;;;;\n1D9E9;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE SINGLE;So;0;L;;;;;N;;;;;\n1D9EA;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL DOUBLE;So;0;L;;;;;N;;;;;\n1D9EB;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM DOUBLE;So;0;L;;;;;N;;;;;\n1D9EC;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE DOUBLE;So;0;L;;;;;N;;;;;\n1D9ED;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT SINGLE;So;0;L;;;;;N;;;;;\n1D9EE;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT DOUBLE;So;0;L;;;;;N;;;;;\n1D9EF;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL SINGLE;So;0;L;;;;;N;;;;;\n1D9F0;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL DOUBLE;So;0;L;;;;;N;;;;;\n1D9F1;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES SINGLE;So;0;L;;;;;N;;;;;\n1D9F2;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES DOUBLE;So;0;L;;;;;N;;;;;\n1D9F3;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL SINGLE;So;0;L;;;;;N;;;;;\n1D9F4;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL DOUBLE;So;0;L;;;;;N;;;;;\n1D9F5;SIGNWRITING DYNAMIC ARROWHEAD SMALL;So;0;L;;;;;N;;;;;\n1D9F6;SIGNWRITING DYNAMIC ARROWHEAD LARGE;So;0;L;;;;;N;;;;;\n1D9F7;SIGNWRITING DYNAMIC FAST;So;0;L;;;;;N;;;;;\n1D9F8;SIGNWRITING DYNAMIC SLOW;So;0;L;;;;;N;;;;;\n1D9F9;SIGNWRITING DYNAMIC TENSE;So;0;L;;;;;N;;;;;\n1D9FA;SIGNWRITING DYNAMIC RELAXED;So;0;L;;;;;N;;;;;\n1D9FB;SIGNWRITING DYNAMIC SIMULTANEOUS;So;0;L;;;;;N;;;;;\n1D9FC;SIGNWRITING DYNAMIC SIMULTANEOUS ALTERNATING;So;0;L;;;;;N;;;;;\n1D9FD;SIGNWRITING DYNAMIC EVERY OTHER TIME;So;0;L;;;;;N;;;;;\n1D9FE;SIGNWRITING DYNAMIC GRADUAL;So;0;L;;;;;N;;;;;\n1D9FF;SIGNWRITING HEAD;So;0;L;;;;;N;;;;;\n1DA00;SIGNWRITING HEAD RIM;Mn;0;NSM;;;;;N;;;;;\n1DA01;SIGNWRITING HEAD MOVEMENT-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;;\n1DA02;SIGNWRITING HEAD MOVEMENT-WALLPLANE TILT;Mn;0;NSM;;;;;N;;;;;\n1DA03;SIGNWRITING HEAD MOVEMENT-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;;\n1DA04;SIGNWRITING HEAD MOVEMENT-WALLPLANE CURVE;Mn;0;NSM;;;;;N;;;;;\n1DA05;SIGNWRITING HEAD MOVEMENT-FLOORPLANE CURVE;Mn;0;NSM;;;;;N;;;;;\n1DA06;SIGNWRITING HEAD MOVEMENT CIRCLE;Mn;0;NSM;;;;;N;;;;;\n1DA07;SIGNWRITING FACE DIRECTION POSITION NOSE FORWARD TILTING;Mn;0;NSM;;;;;N;;;;;\n1DA08;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN;Mn;0;NSM;;;;;N;;;;;\n1DA09;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN TILTING;Mn;0;NSM;;;;;N;;;;;\n1DA0A;SIGNWRITING EYEBROWS STRAIGHT UP;Mn;0;NSM;;;;;N;;;;;\n1DA0B;SIGNWRITING EYEBROWS STRAIGHT NEUTRAL;Mn;0;NSM;;;;;N;;;;;\n1DA0C;SIGNWRITING EYEBROWS STRAIGHT DOWN;Mn;0;NSM;;;;;N;;;;;\n1DA0D;SIGNWRITING DREAMY EYEBROWS NEUTRAL DOWN;Mn;0;NSM;;;;;N;;;;;\n1DA0E;SIGNWRITING DREAMY EYEBROWS DOWN NEUTRAL;Mn;0;NSM;;;;;N;;;;;\n1DA0F;SIGNWRITING DREAMY EYEBROWS UP NEUTRAL;Mn;0;NSM;;;;;N;;;;;\n1DA10;SIGNWRITING DREAMY EYEBROWS NEUTRAL UP;Mn;0;NSM;;;;;N;;;;;\n1DA11;SIGNWRITING FOREHEAD NEUTRAL;Mn;0;NSM;;;;;N;;;;;\n1DA12;SIGNWRITING FOREHEAD CONTACT;Mn;0;NSM;;;;;N;;;;;\n1DA13;SIGNWRITING FOREHEAD WRINKLED;Mn;0;NSM;;;;;N;;;;;\n1DA14;SIGNWRITING EYES OPEN;Mn;0;NSM;;;;;N;;;;;\n1DA15;SIGNWRITING EYES SQUEEZED;Mn;0;NSM;;;;;N;;;;;\n1DA16;SIGNWRITING EYES CLOSED;Mn;0;NSM;;;;;N;;;;;\n1DA17;SIGNWRITING EYE BLINK SINGLE;Mn;0;NSM;;;;;N;;;;;\n1DA18;SIGNWRITING EYE BLINK MULTIPLE;Mn;0;NSM;;;;;N;;;;;\n1DA19;SIGNWRITING EYES HALF OPEN;Mn;0;NSM;;;;;N;;;;;\n1DA1A;SIGNWRITING EYES WIDE OPEN;Mn;0;NSM;;;;;N;;;;;\n1DA1B;SIGNWRITING EYES HALF CLOSED;Mn;0;NSM;;;;;N;;;;;\n1DA1C;SIGNWRITING EYES WIDENING MOVEMENT;Mn;0;NSM;;;;;N;;;;;\n1DA1D;SIGNWRITING EYE WINK;Mn;0;NSM;;;;;N;;;;;\n1DA1E;SIGNWRITING EYELASHES UP;Mn;0;NSM;;;;;N;;;;;\n1DA1F;SIGNWRITING EYELASHES DOWN;Mn;0;NSM;;;;;N;;;;;\n1DA20;SIGNWRITING EYELASHES FLUTTERING;Mn;0;NSM;;;;;N;;;;;\n1DA21;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;;\n1DA22;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;;\n1DA23;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;;\n1DA24;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;;\n1DA25;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;;\n1DA26;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;;\n1DA27;SIGNWRITING EYEGAZE-WALLPLANE CURVED;Mn;0;NSM;;;;;N;;;;;\n1DA28;SIGNWRITING EYEGAZE-FLOORPLANE CURVED;Mn;0;NSM;;;;;N;;;;;\n1DA29;SIGNWRITING EYEGAZE-WALLPLANE CIRCLING;Mn;0;NSM;;;;;N;;;;;\n1DA2A;SIGNWRITING CHEEKS PUFFED;Mn;0;NSM;;;;;N;;;;;\n1DA2B;SIGNWRITING CHEEKS NEUTRAL;Mn;0;NSM;;;;;N;;;;;\n1DA2C;SIGNWRITING CHEEKS SUCKED;Mn;0;NSM;;;;;N;;;;;\n1DA2D;SIGNWRITING TENSE CHEEKS HIGH;Mn;0;NSM;;;;;N;;;;;\n1DA2E;SIGNWRITING TENSE CHEEKS MIDDLE;Mn;0;NSM;;;;;N;;;;;\n1DA2F;SIGNWRITING TENSE CHEEKS LOW;Mn;0;NSM;;;;;N;;;;;\n1DA30;SIGNWRITING EARS;Mn;0;NSM;;;;;N;;;;;\n1DA31;SIGNWRITING NOSE NEUTRAL;Mn;0;NSM;;;;;N;;;;;\n1DA32;SIGNWRITING NOSE CONTACT;Mn;0;NSM;;;;;N;;;;;\n1DA33;SIGNWRITING NOSE WRINKLES;Mn;0;NSM;;;;;N;;;;;\n1DA34;SIGNWRITING NOSE WIGGLES;Mn;0;NSM;;;;;N;;;;;\n1DA35;SIGNWRITING AIR BLOWING OUT;Mn;0;NSM;;;;;N;;;;;\n1DA36;SIGNWRITING AIR SUCKING IN;Mn;0;NSM;;;;;N;;;;;\n1DA37;SIGNWRITING AIR BLOW SMALL ROTATIONS;So;0;L;;;;;N;;;;;\n1DA38;SIGNWRITING AIR SUCK SMALL ROTATIONS;So;0;L;;;;;N;;;;;\n1DA39;SIGNWRITING BREATH INHALE;So;0;L;;;;;N;;;;;\n1DA3A;SIGNWRITING BREATH EXHALE;So;0;L;;;;;N;;;;;\n1DA3B;SIGNWRITING MOUTH CLOSED NEUTRAL;Mn;0;NSM;;;;;N;;;;;\n1DA3C;SIGNWRITING MOUTH CLOSED FORWARD;Mn;0;NSM;;;;;N;;;;;\n1DA3D;SIGNWRITING MOUTH CLOSED CONTACT;Mn;0;NSM;;;;;N;;;;;\n1DA3E;SIGNWRITING MOUTH SMILE;Mn;0;NSM;;;;;N;;;;;\n1DA3F;SIGNWRITING MOUTH SMILE WRINKLED;Mn;0;NSM;;;;;N;;;;;\n1DA40;SIGNWRITING MOUTH SMILE OPEN;Mn;0;NSM;;;;;N;;;;;\n1DA41;SIGNWRITING MOUTH FROWN;Mn;0;NSM;;;;;N;;;;;\n1DA42;SIGNWRITING MOUTH FROWN WRINKLED;Mn;0;NSM;;;;;N;;;;;\n1DA43;SIGNWRITING MOUTH FROWN OPEN;Mn;0;NSM;;;;;N;;;;;\n1DA44;SIGNWRITING MOUTH OPEN CIRCLE;Mn;0;NSM;;;;;N;;;;;\n1DA45;SIGNWRITING MOUTH OPEN FORWARD;Mn;0;NSM;;;;;N;;;;;\n1DA46;SIGNWRITING MOUTH OPEN WRINKLED;Mn;0;NSM;;;;;N;;;;;\n1DA47;SIGNWRITING MOUTH OPEN OVAL;Mn;0;NSM;;;;;N;;;;;\n1DA48;SIGNWRITING MOUTH OPEN OVAL WRINKLED;Mn;0;NSM;;;;;N;;;;;\n1DA49;SIGNWRITING MOUTH OPEN OVAL YAWN;Mn;0;NSM;;;;;N;;;;;\n1DA4A;SIGNWRITING MOUTH OPEN RECTANGLE;Mn;0;NSM;;;;;N;;;;;\n1DA4B;SIGNWRITING MOUTH OPEN RECTANGLE WRINKLED;Mn;0;NSM;;;;;N;;;;;\n1DA4C;SIGNWRITING MOUTH OPEN RECTANGLE YAWN;Mn;0;NSM;;;;;N;;;;;\n1DA4D;SIGNWRITING MOUTH KISS;Mn;0;NSM;;;;;N;;;;;\n1DA4E;SIGNWRITING MOUTH KISS FORWARD;Mn;0;NSM;;;;;N;;;;;\n1DA4F;SIGNWRITING MOUTH KISS WRINKLED;Mn;0;NSM;;;;;N;;;;;\n1DA50;SIGNWRITING MOUTH TENSE;Mn;0;NSM;;;;;N;;;;;\n1DA51;SIGNWRITING MOUTH TENSE FORWARD;Mn;0;NSM;;;;;N;;;;;\n1DA52;SIGNWRITING MOUTH TENSE SUCKED;Mn;0;NSM;;;;;N;;;;;\n1DA53;SIGNWRITING LIPS PRESSED TOGETHER;Mn;0;NSM;;;;;N;;;;;\n1DA54;SIGNWRITING LIP LOWER OVER UPPER;Mn;0;NSM;;;;;N;;;;;\n1DA55;SIGNWRITING LIP UPPER OVER LOWER;Mn;0;NSM;;;;;N;;;;;\n1DA56;SIGNWRITING MOUTH CORNERS;Mn;0;NSM;;;;;N;;;;;\n1DA57;SIGNWRITING MOUTH WRINKLES SINGLE;Mn;0;NSM;;;;;N;;;;;\n1DA58;SIGNWRITING MOUTH WRINKLES DOUBLE;Mn;0;NSM;;;;;N;;;;;\n1DA59;SIGNWRITING TONGUE STICKING OUT FAR;Mn;0;NSM;;;;;N;;;;;\n1DA5A;SIGNWRITING TONGUE LICKING LIPS;Mn;0;NSM;;;;;N;;;;;\n1DA5B;SIGNWRITING TONGUE TIP BETWEEN LIPS;Mn;0;NSM;;;;;N;;;;;\n1DA5C;SIGNWRITING TONGUE TIP TOUCHING INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;;\n1DA5D;SIGNWRITING TONGUE INSIDE MOUTH RELAXED;Mn;0;NSM;;;;;N;;;;;\n1DA5E;SIGNWRITING TONGUE MOVES AGAINST CHEEK;Mn;0;NSM;;;;;N;;;;;\n1DA5F;SIGNWRITING TONGUE CENTRE STICKING OUT;Mn;0;NSM;;;;;N;;;;;\n1DA60;SIGNWRITING TONGUE CENTRE INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;;\n1DA61;SIGNWRITING TEETH;Mn;0;NSM;;;;;N;;;;;\n1DA62;SIGNWRITING TEETH MOVEMENT;Mn;0;NSM;;;;;N;;;;;\n1DA63;SIGNWRITING TEETH ON TONGUE;Mn;0;NSM;;;;;N;;;;;\n1DA64;SIGNWRITING TEETH ON TONGUE MOVEMENT;Mn;0;NSM;;;;;N;;;;;\n1DA65;SIGNWRITING TEETH ON LIPS;Mn;0;NSM;;;;;N;;;;;\n1DA66;SIGNWRITING TEETH ON LIPS MOVEMENT;Mn;0;NSM;;;;;N;;;;;\n1DA67;SIGNWRITING TEETH BITE LIPS;Mn;0;NSM;;;;;N;;;;;\n1DA68;SIGNWRITING MOVEMENT-WALLPLANE JAW;Mn;0;NSM;;;;;N;;;;;\n1DA69;SIGNWRITING MOVEMENT-FLOORPLANE JAW;Mn;0;NSM;;;;;N;;;;;\n1DA6A;SIGNWRITING NECK;Mn;0;NSM;;;;;N;;;;;\n1DA6B;SIGNWRITING HAIR;Mn;0;NSM;;;;;N;;;;;\n1DA6C;SIGNWRITING EXCITEMENT;Mn;0;NSM;;;;;N;;;;;\n1DA6D;SIGNWRITING SHOULDER HIP SPINE;So;0;L;;;;;N;;;;;\n1DA6E;SIGNWRITING SHOULDER HIP POSITIONS;So;0;L;;;;;N;;;;;\n1DA6F;SIGNWRITING WALLPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;;\n1DA70;SIGNWRITING FLOORPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;;\n1DA71;SIGNWRITING SHOULDER TILTING FROM WAIST;So;0;L;;;;;N;;;;;\n1DA72;SIGNWRITING TORSO-WALLPLANE STRAIGHT STRETCH;So;0;L;;;;;N;;;;;\n1DA73;SIGNWRITING TORSO-WALLPLANE CURVED BEND;So;0;L;;;;;N;;;;;\n1DA74;SIGNWRITING TORSO-FLOORPLANE TWISTING;So;0;L;;;;;N;;;;;\n1DA75;SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS;Mn;0;NSM;;;;;N;;;;;\n1DA76;SIGNWRITING LIMB COMBINATION;So;0;L;;;;;N;;;;;\n1DA77;SIGNWRITING LIMB LENGTH-1;So;0;L;;;;;N;;;;;\n1DA78;SIGNWRITING LIMB LENGTH-2;So;0;L;;;;;N;;;;;\n1DA79;SIGNWRITING LIMB LENGTH-3;So;0;L;;;;;N;;;;;\n1DA7A;SIGNWRITING LIMB LENGTH-4;So;0;L;;;;;N;;;;;\n1DA7B;SIGNWRITING LIMB LENGTH-5;So;0;L;;;;;N;;;;;\n1DA7C;SIGNWRITING LIMB LENGTH-6;So;0;L;;;;;N;;;;;\n1DA7D;SIGNWRITING LIMB LENGTH-7;So;0;L;;;;;N;;;;;\n1DA7E;SIGNWRITING FINGER;So;0;L;;;;;N;;;;;\n1DA7F;SIGNWRITING LOCATION-WALLPLANE SPACE;So;0;L;;;;;N;;;;;\n1DA80;SIGNWRITING LOCATION-FLOORPLANE SPACE;So;0;L;;;;;N;;;;;\n1DA81;SIGNWRITING LOCATION HEIGHT;So;0;L;;;;;N;;;;;\n1DA82;SIGNWRITING LOCATION WIDTH;So;0;L;;;;;N;;;;;\n1DA83;SIGNWRITING LOCATION DEPTH;So;0;L;;;;;N;;;;;\n1DA84;SIGNWRITING LOCATION HEAD NECK;Mn;0;NSM;;;;;N;;;;;\n1DA85;SIGNWRITING LOCATION TORSO;So;0;L;;;;;N;;;;;\n1DA86;SIGNWRITING LOCATION LIMBS DIGITS;So;0;L;;;;;N;;;;;\n1DA87;SIGNWRITING COMMA;Po;0;L;;;;;N;;;;;\n1DA88;SIGNWRITING FULL STOP;Po;0;L;;;;;N;;;;;\n1DA89;SIGNWRITING SEMICOLON;Po;0;L;;;;;N;;;;;\n1DA8A;SIGNWRITING COLON;Po;0;L;;;;;N;;;;;\n1DA8B;SIGNWRITING PARENTHESIS;Po;0;L;;;;;N;;;;;\n1DA9B;SIGNWRITING FILL MODIFIER-2;Mn;0;NSM;;;;;N;;;;;\n1DA9C;SIGNWRITING FILL MODIFIER-3;Mn;0;NSM;;;;;N;;;;;\n1DA9D;SIGNWRITING FILL MODIFIER-4;Mn;0;NSM;;;;;N;;;;;\n1DA9E;SIGNWRITING FILL MODIFIER-5;Mn;0;NSM;;;;;N;;;;;\n1DA9F;SIGNWRITING FILL MODIFIER-6;Mn;0;NSM;;;;;N;;;;;\n1DAA1;SIGNWRITING ROTATION MODIFIER-2;Mn;0;NSM;;;;;N;;;;;\n1DAA2;SIGNWRITING ROTATION MODIFIER-3;Mn;0;NSM;;;;;N;;;;;\n1DAA3;SIGNWRITING ROTATION MODIFIER-4;Mn;0;NSM;;;;;N;;;;;\n1DAA4;SIGNWRITING ROTATION MODIFIER-5;Mn;0;NSM;;;;;N;;;;;\n1DAA5;SIGNWRITING ROTATION MODIFIER-6;Mn;0;NSM;;;;;N;;;;;\n1DAA6;SIGNWRITING ROTATION MODIFIER-7;Mn;0;NSM;;;;;N;;;;;\n1DAA7;SIGNWRITING ROTATION MODIFIER-8;Mn;0;NSM;;;;;N;;;;;\n1DAA8;SIGNWRITING ROTATION MODIFIER-9;Mn;0;NSM;;;;;N;;;;;\n1DAA9;SIGNWRITING ROTATION MODIFIER-10;Mn;0;NSM;;;;;N;;;;;\n1DAAA;SIGNWRITING ROTATION MODIFIER-11;Mn;0;NSM;;;;;N;;;;;\n1DAAB;SIGNWRITING ROTATION MODIFIER-12;Mn;0;NSM;;;;;N;;;;;\n1DAAC;SIGNWRITING ROTATION MODIFIER-13;Mn;0;NSM;;;;;N;;;;;\n1DAAD;SIGNWRITING ROTATION MODIFIER-14;Mn;0;NSM;;;;;N;;;;;\n1DAAE;SIGNWRITING ROTATION MODIFIER-15;Mn;0;NSM;;;;;N;;;;;\n1DAAF;SIGNWRITING ROTATION MODIFIER-16;Mn;0;NSM;;;;;N;;;;;\n1DF00;LATIN SMALL LETTER FENG DIGRAPH WITH TRILL;Ll;0;L;;;;;N;;;;;\n1DF01;LATIN SMALL LETTER REVERSED SCRIPT G;Ll;0;L;;;;;N;;;;;\n1DF02;LATIN LETTER SMALL CAPITAL TURNED G;Ll;0;L;;;;;N;;;;;\n1DF03;LATIN SMALL LETTER REVERSED K;Ll;0;L;;;;;N;;;;;\n1DF04;LATIN LETTER SMALL CAPITAL L WITH BELT;Ll;0;L;;;;;N;;;;;\n1DF05;LATIN SMALL LETTER LEZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1DF06;LATIN SMALL LETTER TURNED Y WITH BELT;Ll;0;L;;;;;N;;;;;\n1DF07;LATIN SMALL LETTER REVERSED ENG;Ll;0;L;;;;;N;;;;;\n1DF08;LATIN SMALL LETTER TURNED R WITH LONG LEG AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1DF09;LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1DF0A;LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK;Lo;0;L;;;;;N;;;;;\n1DF0B;LATIN SMALL LETTER ESH WITH DOUBLE BAR;Ll;0;L;;;;;N;;;;;\n1DF0C;LATIN SMALL LETTER ESH WITH DOUBLE BAR AND CURL;Ll;0;L;;;;;N;;;;;\n1DF0D;LATIN SMALL LETTER TURNED T WITH CURL;Ll;0;L;;;;;N;;;;;\n1DF0E;LATIN LETTER INVERTED GLOTTAL STOP WITH CURL;Ll;0;L;;;;;N;;;;;\n1DF0F;LATIN LETTER STRETCHED C WITH CURL;Ll;0;L;;;;;N;;;;;\n1DF10;LATIN LETTER SMALL CAPITAL TURNED K;Ll;0;L;;;;;N;;;;;\n1DF11;LATIN SMALL LETTER L WITH FISHHOOK;Ll;0;L;;;;;N;;;;;\n1DF12;LATIN SMALL LETTER DEZH DIGRAPH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1DF13;LATIN SMALL LETTER L WITH BELT AND PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1DF14;LATIN SMALL LETTER ENG WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1DF15;LATIN SMALL LETTER TURNED R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1DF16;LATIN SMALL LETTER R WITH FISHHOOK AND PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1DF17;LATIN SMALL LETTER TESH DIGRAPH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1DF18;LATIN SMALL LETTER EZH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;\n1DF19;LATIN SMALL LETTER DEZH DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1DF1A;LATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1DF1B;LATIN SMALL LETTER O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1DF1C;LATIN SMALL LETTER TESH DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1DF1D;LATIN SMALL LETTER C WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;\n1DF1E;LATIN SMALL LETTER S WITH CURL;Ll;0;L;;;;;N;;;;;\n1DF25;LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;;\n1DF26;LATIN SMALL LETTER L WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;;\n1DF27;LATIN SMALL LETTER N WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;;\n1DF28;LATIN SMALL LETTER R WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;;\n1DF29;LATIN SMALL LETTER S WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;;\n1DF2A;LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;;\n1E000;COMBINING GLAGOLITIC LETTER AZU;Mn;230;NSM;;;;;N;;;;;\n1E001;COMBINING GLAGOLITIC LETTER BUKY;Mn;230;NSM;;;;;N;;;;;\n1E002;COMBINING GLAGOLITIC LETTER VEDE;Mn;230;NSM;;;;;N;;;;;\n1E003;COMBINING GLAGOLITIC LETTER GLAGOLI;Mn;230;NSM;;;;;N;;;;;\n1E004;COMBINING GLAGOLITIC LETTER DOBRO;Mn;230;NSM;;;;;N;;;;;\n1E005;COMBINING GLAGOLITIC LETTER YESTU;Mn;230;NSM;;;;;N;;;;;\n1E006;COMBINING GLAGOLITIC LETTER ZHIVETE;Mn;230;NSM;;;;;N;;;;;\n1E008;COMBINING GLAGOLITIC LETTER ZEMLJA;Mn;230;NSM;;;;;N;;;;;\n1E009;COMBINING GLAGOLITIC LETTER IZHE;Mn;230;NSM;;;;;N;;;;;\n1E00A;COMBINING GLAGOLITIC LETTER INITIAL IZHE;Mn;230;NSM;;;;;N;;;;;\n1E00B;COMBINING GLAGOLITIC LETTER I;Mn;230;NSM;;;;;N;;;;;\n1E00C;COMBINING GLAGOLITIC LETTER DJERVI;Mn;230;NSM;;;;;N;;;;;\n1E00D;COMBINING GLAGOLITIC LETTER KAKO;Mn;230;NSM;;;;;N;;;;;\n1E00E;COMBINING GLAGOLITIC LETTER LJUDIJE;Mn;230;NSM;;;;;N;;;;;\n1E00F;COMBINING GLAGOLITIC LETTER MYSLITE;Mn;230;NSM;;;;;N;;;;;\n1E010;COMBINING GLAGOLITIC LETTER NASHI;Mn;230;NSM;;;;;N;;;;;\n1E011;COMBINING GLAGOLITIC LETTER ONU;Mn;230;NSM;;;;;N;;;;;\n1E012;COMBINING GLAGOLITIC LETTER POKOJI;Mn;230;NSM;;;;;N;;;;;\n1E013;COMBINING GLAGOLITIC LETTER RITSI;Mn;230;NSM;;;;;N;;;;;\n1E014;COMBINING GLAGOLITIC LETTER SLOVO;Mn;230;NSM;;;;;N;;;;;\n1E015;COMBINING GLAGOLITIC LETTER TVRIDO;Mn;230;NSM;;;;;N;;;;;\n1E016;COMBINING GLAGOLITIC LETTER UKU;Mn;230;NSM;;;;;N;;;;;\n1E017;COMBINING GLAGOLITIC LETTER FRITU;Mn;230;NSM;;;;;N;;;;;\n1E018;COMBINING GLAGOLITIC LETTER HERU;Mn;230;NSM;;;;;N;;;;;\n1E01B;COMBINING GLAGOLITIC LETTER SHTA;Mn;230;NSM;;;;;N;;;;;\n1E01C;COMBINING GLAGOLITIC LETTER TSI;Mn;230;NSM;;;;;N;;;;;\n1E01D;COMBINING GLAGOLITIC LETTER CHRIVI;Mn;230;NSM;;;;;N;;;;;\n1E01E;COMBINING GLAGOLITIC LETTER SHA;Mn;230;NSM;;;;;N;;;;;\n1E01F;COMBINING GLAGOLITIC LETTER YERU;Mn;230;NSM;;;;;N;;;;;\n1E020;COMBINING GLAGOLITIC LETTER YERI;Mn;230;NSM;;;;;N;;;;;\n1E021;COMBINING GLAGOLITIC LETTER YATI;Mn;230;NSM;;;;;N;;;;;\n1E023;COMBINING GLAGOLITIC LETTER YU;Mn;230;NSM;;;;;N;;;;;\n1E024;COMBINING GLAGOLITIC LETTER SMALL YUS;Mn;230;NSM;;;;;N;;;;;\n1E026;COMBINING GLAGOLITIC LETTER YO;Mn;230;NSM;;;;;N;;;;;\n1E027;COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS;Mn;230;NSM;;;;;N;;;;;\n1E028;COMBINING GLAGOLITIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;;\n1E029;COMBINING GLAGOLITIC LETTER IOTATED BIG YUS;Mn;230;NSM;;;;;N;;;;;\n1E02A;COMBINING GLAGOLITIC LETTER FITA;Mn;230;NSM;;;;;N;;;;;\n1E030;MODIFIER LETTER CYRILLIC SMALL A;Lm;0;L;<super> 0430;;;;N;;;;;\n1E031;MODIFIER LETTER CYRILLIC SMALL BE;Lm;0;L;<super> 0431;;;;N;;;;;\n1E032;MODIFIER LETTER CYRILLIC SMALL VE;Lm;0;L;<super> 0432;;;;N;;;;;\n1E033;MODIFIER LETTER CYRILLIC SMALL GHE;Lm;0;L;<super> 0433;;;;N;;;;;\n1E034;MODIFIER LETTER CYRILLIC SMALL DE;Lm;0;L;<super> 0434;;;;N;;;;;\n1E035;MODIFIER LETTER CYRILLIC SMALL IE;Lm;0;L;<super> 0435;;;;N;;;;;\n1E036;MODIFIER LETTER CYRILLIC SMALL ZHE;Lm;0;L;<super> 0436;;;;N;;;;;\n1E037;MODIFIER LETTER CYRILLIC SMALL ZE;Lm;0;L;<super> 0437;;;;N;;;;;\n1E038;MODIFIER LETTER CYRILLIC SMALL I;Lm;0;L;<super> 0438;;;;N;;;;;\n1E039;MODIFIER LETTER CYRILLIC SMALL KA;Lm;0;L;<super> 043A;;;;N;;;;;\n1E03A;MODIFIER LETTER CYRILLIC SMALL EL;Lm;0;L;<super> 043B;;;;N;;;;;\n1E03B;MODIFIER LETTER CYRILLIC SMALL EM;Lm;0;L;<super> 043C;;;;N;;;;;\n1E03C;MODIFIER LETTER CYRILLIC SMALL O;Lm;0;L;<super> 043E;;;;N;;;;;\n1E03D;MODIFIER LETTER CYRILLIC SMALL PE;Lm;0;L;<super> 043F;;;;N;;;;;\n1E03E;MODIFIER LETTER CYRILLIC SMALL ER;Lm;0;L;<super> 0440;;;;N;;;;;\n1E03F;MODIFIER LETTER CYRILLIC SMALL ES;Lm;0;L;<super> 0441;;;;N;;;;;\n1E040;MODIFIER LETTER CYRILLIC SMALL TE;Lm;0;L;<super> 0442;;;;N;;;;;\n1E041;MODIFIER LETTER CYRILLIC SMALL U;Lm;0;L;<super> 0443;;;;N;;;;;\n1E042;MODIFIER LETTER CYRILLIC SMALL EF;Lm;0;L;<super> 0444;;;;N;;;;;\n1E043;MODIFIER LETTER CYRILLIC SMALL HA;Lm;0;L;<super> 0445;;;;N;;;;;\n1E044;MODIFIER LETTER CYRILLIC SMALL TSE;Lm;0;L;<super> 0446;;;;N;;;;;\n1E045;MODIFIER LETTER CYRILLIC SMALL CHE;Lm;0;L;<super> 0447;;;;N;;;;;\n1E046;MODIFIER LETTER CYRILLIC SMALL SHA;Lm;0;L;<super> 0448;;;;N;;;;;\n1E047;MODIFIER LETTER CYRILLIC SMALL YERU;Lm;0;L;<super> 044B;;;;N;;;;;\n1E048;MODIFIER LETTER CYRILLIC SMALL E;Lm;0;L;<super> 044D;;;;N;;;;;\n1E049;MODIFIER LETTER CYRILLIC SMALL YU;Lm;0;L;<super> 044E;;;;N;;;;;\n1E04A;MODIFIER LETTER CYRILLIC SMALL DZZE;Lm;0;L;<super> A689;;;;N;;;;;\n1E04B;MODIFIER LETTER CYRILLIC SMALL SCHWA;Lm;0;L;<super> 04D9;;;;N;;;;;\n1E04C;MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I;Lm;0;L;<super> 0456;;;;N;;;;;\n1E04D;MODIFIER LETTER CYRILLIC SMALL JE;Lm;0;L;<super> 0458;;;;N;;;;;\n1E04E;MODIFIER LETTER CYRILLIC SMALL BARRED O;Lm;0;L;<super> 04E9;;;;N;;;;;\n1E04F;MODIFIER LETTER CYRILLIC SMALL STRAIGHT U;Lm;0;L;<super> 04AF;;;;N;;;;;\n1E050;MODIFIER LETTER CYRILLIC SMALL PALOCHKA;Lm;0;L;<super> 04CF;;;;N;;;;;\n1E051;CYRILLIC SUBSCRIPT SMALL LETTER A;Lm;0;L;<sub> 0430;;;;N;;;;;\n1E052;CYRILLIC SUBSCRIPT SMALL LETTER BE;Lm;0;L;<sub> 0431;;;;N;;;;;\n1E053;CYRILLIC SUBSCRIPT SMALL LETTER VE;Lm;0;L;<sub> 0432;;;;N;;;;;\n1E054;CYRILLIC SUBSCRIPT SMALL LETTER GHE;Lm;0;L;<sub> 0433;;;;N;;;;;\n1E055;CYRILLIC SUBSCRIPT SMALL LETTER DE;Lm;0;L;<sub> 0434;;;;N;;;;;\n1E056;CYRILLIC SUBSCRIPT SMALL LETTER IE;Lm;0;L;<sub> 0435;;;;N;;;;;\n1E057;CYRILLIC SUBSCRIPT SMALL LETTER ZHE;Lm;0;L;<sub> 0436;;;;N;;;;;\n1E058;CYRILLIC SUBSCRIPT SMALL LETTER ZE;Lm;0;L;<sub> 0437;;;;N;;;;;\n1E059;CYRILLIC SUBSCRIPT SMALL LETTER I;Lm;0;L;<sub> 0438;;;;N;;;;;\n1E05A;CYRILLIC SUBSCRIPT SMALL LETTER KA;Lm;0;L;<sub> 043A;;;;N;;;;;\n1E05B;CYRILLIC SUBSCRIPT SMALL LETTER EL;Lm;0;L;<sub> 043B;;;;N;;;;;\n1E05C;CYRILLIC SUBSCRIPT SMALL LETTER O;Lm;0;L;<sub> 043E;;;;N;;;;;\n1E05D;CYRILLIC SUBSCRIPT SMALL LETTER PE;Lm;0;L;<sub> 043F;;;;N;;;;;\n1E05E;CYRILLIC SUBSCRIPT SMALL LETTER ES;Lm;0;L;<sub> 0441;;;;N;;;;;\n1E05F;CYRILLIC SUBSCRIPT SMALL LETTER U;Lm;0;L;<sub> 0443;;;;N;;;;;\n1E060;CYRILLIC SUBSCRIPT SMALL LETTER EF;Lm;0;L;<sub> 0444;;;;N;;;;;\n1E061;CYRILLIC SUBSCRIPT SMALL LETTER HA;Lm;0;L;<sub> 0445;;;;N;;;;;\n1E062;CYRILLIC SUBSCRIPT SMALL LETTER TSE;Lm;0;L;<sub> 0446;;;;N;;;;;\n1E063;CYRILLIC SUBSCRIPT SMALL LETTER CHE;Lm;0;L;<sub> 0447;;;;N;;;;;\n1E064;CYRILLIC SUBSCRIPT SMALL LETTER SHA;Lm;0;L;<sub> 0448;;;;N;;;;;\n1E065;CYRILLIC SUBSCRIPT SMALL LETTER HARD SIGN;Lm;0;L;<sub> 044A;;;;N;;;;;\n1E066;CYRILLIC SUBSCRIPT SMALL LETTER YERU;Lm;0;L;<sub> 044B;;;;N;;;;;\n1E067;CYRILLIC SUBSCRIPT SMALL LETTER GHE WITH UPTURN;Lm;0;L;<sub> 0491;;;;N;;;;;\n1E068;CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Lm;0;L;<sub> 0456;;;;N;;;;;\n1E069;CYRILLIC SUBSCRIPT SMALL LETTER DZE;Lm;0;L;<sub> 0455;;;;N;;;;;\n1E06A;CYRILLIC SUBSCRIPT SMALL LETTER DZHE;Lm;0;L;<sub> 045F;;;;N;;;;;\n1E06B;MODIFIER LETTER CYRILLIC SMALL ES WITH DESCENDER;Lm;0;L;<super> 04AB;;;;N;;;;;\n1E06C;MODIFIER LETTER CYRILLIC SMALL YERU WITH BACK YER;Lm;0;L;<super> A651;;;;N;;;;;\n1E06D;MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE;Lm;0;L;<super> 04B1;;;;N;;;;;\n1E08F;COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Mn;230;NSM;;;;;N;;;;;\n1E100;NYIAKENG PUACHUE HMONG LETTER MA;Lo;0;L;;;;;N;;;;;\n1E101;NYIAKENG PUACHUE HMONG LETTER TSA;Lo;0;L;;;;;N;;;;;\n1E102;NYIAKENG PUACHUE HMONG LETTER NTA;Lo;0;L;;;;;N;;;;;\n1E103;NYIAKENG PUACHUE HMONG LETTER TA;Lo;0;L;;;;;N;;;;;\n1E104;NYIAKENG PUACHUE HMONG LETTER HA;Lo;0;L;;;;;N;;;;;\n1E105;NYIAKENG PUACHUE HMONG LETTER NA;Lo;0;L;;;;;N;;;;;\n1E106;NYIAKENG PUACHUE HMONG LETTER XA;Lo;0;L;;;;;N;;;;;\n1E107;NYIAKENG PUACHUE HMONG LETTER NKA;Lo;0;L;;;;;N;;;;;\n1E108;NYIAKENG PUACHUE HMONG LETTER CA;Lo;0;L;;;;;N;;;;;\n1E109;NYIAKENG PUACHUE HMONG LETTER LA;Lo;0;L;;;;;N;;;;;\n1E10A;NYIAKENG PUACHUE HMONG LETTER SA;Lo;0;L;;;;;N;;;;;\n1E10B;NYIAKENG PUACHUE HMONG LETTER ZA;Lo;0;L;;;;;N;;;;;\n1E10C;NYIAKENG PUACHUE HMONG LETTER NCA;Lo;0;L;;;;;N;;;;;\n1E10D;NYIAKENG PUACHUE HMONG LETTER NTSA;Lo;0;L;;;;;N;;;;;\n1E10E;NYIAKENG PUACHUE HMONG LETTER KA;Lo;0;L;;;;;N;;;;;\n1E10F;NYIAKENG PUACHUE HMONG LETTER DA;Lo;0;L;;;;;N;;;;;\n1E110;NYIAKENG PUACHUE HMONG LETTER NYA;Lo;0;L;;;;;N;;;;;\n1E111;NYIAKENG PUACHUE HMONG LETTER NRA;Lo;0;L;;;;;N;;;;;\n1E112;NYIAKENG PUACHUE HMONG LETTER VA;Lo;0;L;;;;;N;;;;;\n1E113;NYIAKENG PUACHUE HMONG LETTER NTXA;Lo;0;L;;;;;N;;;;;\n1E114;NYIAKENG PUACHUE HMONG LETTER TXA;Lo;0;L;;;;;N;;;;;\n1E115;NYIAKENG PUACHUE HMONG LETTER FA;Lo;0;L;;;;;N;;;;;\n1E116;NYIAKENG PUACHUE HMONG LETTER RA;Lo;0;L;;;;;N;;;;;\n1E117;NYIAKENG PUACHUE HMONG LETTER QA;Lo;0;L;;;;;N;;;;;\n1E118;NYIAKENG PUACHUE HMONG LETTER YA;Lo;0;L;;;;;N;;;;;\n1E119;NYIAKENG PUACHUE HMONG LETTER NQA;Lo;0;L;;;;;N;;;;;\n1E11A;NYIAKENG PUACHUE HMONG LETTER PA;Lo;0;L;;;;;N;;;;;\n1E11B;NYIAKENG PUACHUE HMONG LETTER XYA;Lo;0;L;;;;;N;;;;;\n1E11C;NYIAKENG PUACHUE HMONG LETTER NPA;Lo;0;L;;;;;N;;;;;\n1E11D;NYIAKENG PUACHUE HMONG LETTER DLA;Lo;0;L;;;;;N;;;;;\n1E11E;NYIAKENG PUACHUE HMONG LETTER NPLA;Lo;0;L;;;;;N;;;;;\n1E11F;NYIAKENG PUACHUE HMONG LETTER HAH;Lo;0;L;;;;;N;;;;;\n1E120;NYIAKENG PUACHUE HMONG LETTER MLA;Lo;0;L;;;;;N;;;;;\n1E121;NYIAKENG PUACHUE HMONG LETTER PLA;Lo;0;L;;;;;N;;;;;\n1E122;NYIAKENG PUACHUE HMONG LETTER GA;Lo;0;L;;;;;N;;;;;\n1E123;NYIAKENG PUACHUE HMONG LETTER RRA;Lo;0;L;;;;;N;;;;;\n1E124;NYIAKENG PUACHUE HMONG LETTER A;Lo;0;L;;;;;N;;;;;\n1E125;NYIAKENG PUACHUE HMONG LETTER AA;Lo;0;L;;;;;N;;;;;\n1E126;NYIAKENG PUACHUE HMONG LETTER I;Lo;0;L;;;;;N;;;;;\n1E127;NYIAKENG PUACHUE HMONG LETTER U;Lo;0;L;;;;;N;;;;;\n1E128;NYIAKENG PUACHUE HMONG LETTER O;Lo;0;L;;;;;N;;;;;\n1E129;NYIAKENG PUACHUE HMONG LETTER OO;Lo;0;L;;;;;N;;;;;\n1E12A;NYIAKENG PUACHUE HMONG LETTER E;Lo;0;L;;;;;N;;;;;\n1E12B;NYIAKENG PUACHUE HMONG LETTER EE;Lo;0;L;;;;;N;;;;;\n1E12C;NYIAKENG PUACHUE HMONG LETTER W;Lo;0;L;;;;;N;;;;;\n1E130;NYIAKENG PUACHUE HMONG TONE-B;Mn;230;NSM;;;;;N;;;;;\n1E131;NYIAKENG PUACHUE HMONG TONE-M;Mn;230;NSM;;;;;N;;;;;\n1E132;NYIAKENG PUACHUE HMONG TONE-J;Mn;230;NSM;;;;;N;;;;;\n1E133;NYIAKENG PUACHUE HMONG TONE-V;Mn;230;NSM;;;;;N;;;;;\n1E134;NYIAKENG PUACHUE HMONG TONE-S;Mn;230;NSM;;;;;N;;;;;\n1E135;NYIAKENG PUACHUE HMONG TONE-G;Mn;230;NSM;;;;;N;;;;;\n1E136;NYIAKENG PUACHUE HMONG TONE-D;Mn;230;NSM;;;;;N;;;;;\n1E137;NYIAKENG PUACHUE HMONG SIGN FOR PERSON;Lm;0;L;;;;;N;;;;;\n1E138;NYIAKENG PUACHUE HMONG SIGN FOR THING;Lm;0;L;;;;;N;;;;;\n1E139;NYIAKENG PUACHUE HMONG SIGN FOR LOCATION;Lm;0;L;;;;;N;;;;;\n1E13A;NYIAKENG PUACHUE HMONG SIGN FOR ANIMAL;Lm;0;L;;;;;N;;;;;\n1E13B;NYIAKENG PUACHUE HMONG SIGN FOR INVERTEBRATE;Lm;0;L;;;;;N;;;;;\n1E13C;NYIAKENG PUACHUE HMONG SIGN XW XW;Lm;0;L;;;;;N;;;;;\n1E13D;NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER;Lm;0;L;;;;;N;;;;;\n1E140;NYIAKENG PUACHUE HMONG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1E141;NYIAKENG PUACHUE HMONG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1E142;NYIAKENG PUACHUE HMONG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1E143;NYIAKENG PUACHUE HMONG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1E144;NYIAKENG PUACHUE HMONG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1E145;NYIAKENG PUACHUE HMONG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1E146;NYIAKENG PUACHUE HMONG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1E147;NYIAKENG PUACHUE HMONG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1E148;NYIAKENG PUACHUE HMONG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1E149;NYIAKENG PUACHUE HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1E14E;NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ;Lo;0;L;;;;;N;;;;;\n1E14F;NYIAKENG PUACHUE HMONG CIRCLED CA;So;0;L;;;;;N;;;;;\n1E290;TOTO LETTER PA;Lo;0;L;;;;;N;;;;;\n1E291;TOTO LETTER BA;Lo;0;L;;;;;N;;;;;\n1E292;TOTO LETTER TA;Lo;0;L;;;;;N;;;;;\n1E293;TOTO LETTER DA;Lo;0;L;;;;;N;;;;;\n1E294;TOTO LETTER KA;Lo;0;L;;;;;N;;;;;\n1E295;TOTO LETTER GA;Lo;0;L;;;;;N;;;;;\n1E296;TOTO LETTER MA;Lo;0;L;;;;;N;;;;;\n1E297;TOTO LETTER NA;Lo;0;L;;;;;N;;;;;\n1E298;TOTO LETTER NGA;Lo;0;L;;;;;N;;;;;\n1E299;TOTO LETTER SA;Lo;0;L;;;;;N;;;;;\n1E29A;TOTO LETTER CHA;Lo;0;L;;;;;N;;;;;\n1E29B;TOTO LETTER YA;Lo;0;L;;;;;N;;;;;\n1E29C;TOTO LETTER WA;Lo;0;L;;;;;N;;;;;\n1E29D;TOTO LETTER JA;Lo;0;L;;;;;N;;;;;\n1E29E;TOTO LETTER HA;Lo;0;L;;;;;N;;;;;\n1E29F;TOTO LETTER RA;Lo;0;L;;;;;N;;;;;\n1E2A0;TOTO LETTER LA;Lo;0;L;;;;;N;;;;;\n1E2A1;TOTO LETTER I;Lo;0;L;;;;;N;;;;;\n1E2A2;TOTO LETTER BREATHY I;Lo;0;L;;;;;N;;;;;\n1E2A3;TOTO LETTER IU;Lo;0;L;;;;;N;;;;;\n1E2A4;TOTO LETTER BREATHY IU;Lo;0;L;;;;;N;;;;;\n1E2A5;TOTO LETTER U;Lo;0;L;;;;;N;;;;;\n1E2A6;TOTO LETTER E;Lo;0;L;;;;;N;;;;;\n1E2A7;TOTO LETTER BREATHY E;Lo;0;L;;;;;N;;;;;\n1E2A8;TOTO LETTER EO;Lo;0;L;;;;;N;;;;;\n1E2A9;TOTO LETTER BREATHY EO;Lo;0;L;;;;;N;;;;;\n1E2AA;TOTO LETTER O;Lo;0;L;;;;;N;;;;;\n1E2AB;TOTO LETTER AE;Lo;0;L;;;;;N;;;;;\n1E2AC;TOTO LETTER BREATHY AE;Lo;0;L;;;;;N;;;;;\n1E2AD;TOTO LETTER A;Lo;0;L;;;;;N;;;;;\n1E2AE;TOTO SIGN RISING TONE;Mn;230;NSM;;;;;N;;;;;\n1E2C0;WANCHO LETTER AA;Lo;0;L;;;;;N;;;;;\n1E2C1;WANCHO LETTER A;Lo;0;L;;;;;N;;;;;\n1E2C2;WANCHO LETTER BA;Lo;0;L;;;;;N;;;;;\n1E2C3;WANCHO LETTER CA;Lo;0;L;;;;;N;;;;;\n1E2C4;WANCHO LETTER DA;Lo;0;L;;;;;N;;;;;\n1E2C5;WANCHO LETTER GA;Lo;0;L;;;;;N;;;;;\n1E2C6;WANCHO LETTER YA;Lo;0;L;;;;;N;;;;;\n1E2C7;WANCHO LETTER PHA;Lo;0;L;;;;;N;;;;;\n1E2C8;WANCHO LETTER LA;Lo;0;L;;;;;N;;;;;\n1E2C9;WANCHO LETTER NA;Lo;0;L;;;;;N;;;;;\n1E2CA;WANCHO LETTER PA;Lo;0;L;;;;;N;;;;;\n1E2CB;WANCHO LETTER TA;Lo;0;L;;;;;N;;;;;\n1E2CC;WANCHO LETTER THA;Lo;0;L;;;;;N;;;;;\n1E2CD;WANCHO LETTER FA;Lo;0;L;;;;;N;;;;;\n1E2CE;WANCHO LETTER SA;Lo;0;L;;;;;N;;;;;\n1E2CF;WANCHO LETTER SHA;Lo;0;L;;;;;N;;;;;\n1E2D0;WANCHO LETTER JA;Lo;0;L;;;;;N;;;;;\n1E2D1;WANCHO LETTER ZA;Lo;0;L;;;;;N;;;;;\n1E2D2;WANCHO LETTER WA;Lo;0;L;;;;;N;;;;;\n1E2D3;WANCHO LETTER VA;Lo;0;L;;;;;N;;;;;\n1E2D4;WANCHO LETTER KA;Lo;0;L;;;;;N;;;;;\n1E2D5;WANCHO LETTER O;Lo;0;L;;;;;N;;;;;\n1E2D6;WANCHO LETTER AU;Lo;0;L;;;;;N;;;;;\n1E2D7;WANCHO LETTER RA;Lo;0;L;;;;;N;;;;;\n1E2D8;WANCHO LETTER MA;Lo;0;L;;;;;N;;;;;\n1E2D9;WANCHO LETTER KHA;Lo;0;L;;;;;N;;;;;\n1E2DA;WANCHO LETTER HA;Lo;0;L;;;;;N;;;;;\n1E2DB;WANCHO LETTER E;Lo;0;L;;;;;N;;;;;\n1E2DC;WANCHO LETTER I;Lo;0;L;;;;;N;;;;;\n1E2DD;WANCHO LETTER NGA;Lo;0;L;;;;;N;;;;;\n1E2DE;WANCHO LETTER U;Lo;0;L;;;;;N;;;;;\n1E2DF;WANCHO LETTER LLHA;Lo;0;L;;;;;N;;;;;\n1E2E0;WANCHO LETTER TSA;Lo;0;L;;;;;N;;;;;\n1E2E1;WANCHO LETTER TRA;Lo;0;L;;;;;N;;;;;\n1E2E2;WANCHO LETTER ONG;Lo;0;L;;;;;N;;;;;\n1E2E3;WANCHO LETTER AANG;Lo;0;L;;;;;N;;;;;\n1E2E4;WANCHO LETTER ANG;Lo;0;L;;;;;N;;;;;\n1E2E5;WANCHO LETTER ING;Lo;0;L;;;;;N;;;;;\n1E2E6;WANCHO LETTER ON;Lo;0;L;;;;;N;;;;;\n1E2E7;WANCHO LETTER EN;Lo;0;L;;;;;N;;;;;\n1E2E8;WANCHO LETTER AAN;Lo;0;L;;;;;N;;;;;\n1E2E9;WANCHO LETTER NYA;Lo;0;L;;;;;N;;;;;\n1E2EA;WANCHO LETTER UEN;Lo;0;L;;;;;N;;;;;\n1E2EB;WANCHO LETTER YIH;Lo;0;L;;;;;N;;;;;\n1E2EC;WANCHO TONE TUP;Mn;230;NSM;;;;;N;;;;;\n1E2ED;WANCHO TONE TUPNI;Mn;230;NSM;;;;;N;;;;;\n1E2EE;WANCHO TONE KOI;Mn;230;NSM;;;;;N;;;;;\n1E2EF;WANCHO TONE KOINI;Mn;230;NSM;;;;;N;;;;;\n1E2F0;WANCHO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1E2F1;WANCHO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1E2F2;WANCHO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1E2F3;WANCHO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1E2F4;WANCHO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1E2F5;WANCHO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1E2F6;WANCHO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1E2F7;WANCHO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1E2F8;WANCHO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1E2F9;WANCHO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1E2FF;WANCHO NGUN SIGN;Sc;0;ET;;;;;N;;;;;\n1E4D0;NAG MUNDARI LETTER O;Lo;0;L;;;;;N;;;;;\n1E4D1;NAG MUNDARI LETTER OP;Lo;0;L;;;;;N;;;;;\n1E4D2;NAG MUNDARI LETTER OL;Lo;0;L;;;;;N;;;;;\n1E4D3;NAG MUNDARI LETTER OY;Lo;0;L;;;;;N;;;;;\n1E4D4;NAG MUNDARI LETTER ONG;Lo;0;L;;;;;N;;;;;\n1E4D5;NAG MUNDARI LETTER A;Lo;0;L;;;;;N;;;;;\n1E4D6;NAG MUNDARI LETTER AJ;Lo;0;L;;;;;N;;;;;\n1E4D7;NAG MUNDARI LETTER AB;Lo;0;L;;;;;N;;;;;\n1E4D8;NAG MUNDARI LETTER ANY;Lo;0;L;;;;;N;;;;;\n1E4D9;NAG MUNDARI LETTER AH;Lo;0;L;;;;;N;;;;;\n1E4DA;NAG MUNDARI LETTER I;Lo;0;L;;;;;N;;;;;\n1E4DB;NAG MUNDARI LETTER IS;Lo;0;L;;;;;N;;;;;\n1E4DC;NAG MUNDARI LETTER IDD;Lo;0;L;;;;;N;;;;;\n1E4DD;NAG MUNDARI LETTER IT;Lo;0;L;;;;;N;;;;;\n1E4DE;NAG MUNDARI LETTER IH;Lo;0;L;;;;;N;;;;;\n1E4DF;NAG MUNDARI LETTER U;Lo;0;L;;;;;N;;;;;\n1E4E0;NAG MUNDARI LETTER UC;Lo;0;L;;;;;N;;;;;\n1E4E1;NAG MUNDARI LETTER UD;Lo;0;L;;;;;N;;;;;\n1E4E2;NAG MUNDARI LETTER UK;Lo;0;L;;;;;N;;;;;\n1E4E3;NAG MUNDARI LETTER UR;Lo;0;L;;;;;N;;;;;\n1E4E4;NAG MUNDARI LETTER E;Lo;0;L;;;;;N;;;;;\n1E4E5;NAG MUNDARI LETTER ENN;Lo;0;L;;;;;N;;;;;\n1E4E6;NAG MUNDARI LETTER EG;Lo;0;L;;;;;N;;;;;\n1E4E7;NAG MUNDARI LETTER EM;Lo;0;L;;;;;N;;;;;\n1E4E8;NAG MUNDARI LETTER EN;Lo;0;L;;;;;N;;;;;\n1E4E9;NAG MUNDARI LETTER ETT;Lo;0;L;;;;;N;;;;;\n1E4EA;NAG MUNDARI LETTER ELL;Lo;0;L;;;;;N;;;;;\n1E4EB;NAG MUNDARI SIGN OJOD;Lm;0;L;;;;;N;;;;;\n1E4EC;NAG MUNDARI SIGN MUHOR;Mn;232;NSM;;;;;N;;;;;\n1E4ED;NAG MUNDARI SIGN TOYOR;Mn;232;NSM;;;;;N;;;;;\n1E4EE;NAG MUNDARI SIGN IKIR;Mn;220;NSM;;;;;N;;;;;\n1E4EF;NAG MUNDARI SIGN SUTUH;Mn;230;NSM;;;;;N;;;;;\n1E4F0;NAG MUNDARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1E4F1;NAG MUNDARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1E4F2;NAG MUNDARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1E4F3;NAG MUNDARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1E4F4;NAG MUNDARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1E4F5;NAG MUNDARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1E4F6;NAG MUNDARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1E4F7;NAG MUNDARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1E4F8;NAG MUNDARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1E4F9;NAG MUNDARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1E5D0;OL ONAL LETTER O;Lo;0;L;;;;;N;;;;;\n1E5D1;OL ONAL LETTER OM;Lo;0;L;;;;;N;;;;;\n1E5D2;OL ONAL LETTER ONG;Lo;0;L;;;;;N;;;;;\n1E5D3;OL ONAL LETTER ORR;Lo;0;L;;;;;N;;;;;\n1E5D4;OL ONAL LETTER OO;Lo;0;L;;;;;N;;;;;\n1E5D5;OL ONAL LETTER OY;Lo;0;L;;;;;N;;;;;\n1E5D6;OL ONAL LETTER A;Lo;0;L;;;;;N;;;;;\n1E5D7;OL ONAL LETTER AD;Lo;0;L;;;;;N;;;;;\n1E5D8;OL ONAL LETTER AB;Lo;0;L;;;;;N;;;;;\n1E5D9;OL ONAL LETTER AH;Lo;0;L;;;;;N;;;;;\n1E5DA;OL ONAL LETTER AL;Lo;0;L;;;;;N;;;;;\n1E5DB;OL ONAL LETTER AW;Lo;0;L;;;;;N;;;;;\n1E5DC;OL ONAL LETTER I;Lo;0;L;;;;;N;;;;;\n1E5DD;OL ONAL LETTER IT;Lo;0;L;;;;;N;;;;;\n1E5DE;OL ONAL LETTER IP;Lo;0;L;;;;;N;;;;;\n1E5DF;OL ONAL LETTER ITT;Lo;0;L;;;;;N;;;;;\n1E5E0;OL ONAL LETTER ID;Lo;0;L;;;;;N;;;;;\n1E5E1;OL ONAL LETTER IN;Lo;0;L;;;;;N;;;;;\n1E5E2;OL ONAL LETTER U;Lo;0;L;;;;;N;;;;;\n1E5E3;OL ONAL LETTER UK;Lo;0;L;;;;;N;;;;;\n1E5E4;OL ONAL LETTER UDD;Lo;0;L;;;;;N;;;;;\n1E5E5;OL ONAL LETTER UJ;Lo;0;L;;;;;N;;;;;\n1E5E6;OL ONAL LETTER UNY;Lo;0;L;;;;;N;;;;;\n1E5E7;OL ONAL LETTER UR;Lo;0;L;;;;;N;;;;;\n1E5E8;OL ONAL LETTER E;Lo;0;L;;;;;N;;;;;\n1E5E9;OL ONAL LETTER ES;Lo;0;L;;;;;N;;;;;\n1E5EA;OL ONAL LETTER EH;Lo;0;L;;;;;N;;;;;\n1E5EB;OL ONAL LETTER EC;Lo;0;L;;;;;N;;;;;\n1E5EC;OL ONAL LETTER ENN;Lo;0;L;;;;;N;;;;;\n1E5ED;OL ONAL LETTER EG;Lo;0;L;;;;;N;;;;;\n1E5EE;OL ONAL SIGN MU;Mn;230;NSM;;;;;N;;;;;\n1E5EF;OL ONAL SIGN IKIR;Mn;220;NSM;;;;;N;;;;;\n1E5F0;OL ONAL SIGN HODDOND;Lo;0;L;;;;;N;;;;;\n1E5F1;OL ONAL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;\n1E5F2;OL ONAL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;\n1E5F3;OL ONAL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;\n1E5F4;OL ONAL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;\n1E5F5;OL ONAL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;\n1E5F6;OL ONAL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;\n1E5F7;OL ONAL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;\n1E5F8;OL ONAL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;\n1E5F9;OL ONAL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;\n1E5FA;OL ONAL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;\n1E5FF;OL ONAL ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;\n1E6C0;TAI YO LETTER LOW KO;Lo;0;L;;;;;N;;;;;\n1E6C1;TAI YO LETTER HIGH KO;Lo;0;L;;;;;N;;;;;\n1E6C2;TAI YO LETTER LOW KHO;Lo;0;L;;;;;N;;;;;\n1E6C3;TAI YO LETTER HIGH KHO;Lo;0;L;;;;;N;;;;;\n1E6C4;TAI YO LETTER GO;Lo;0;L;;;;;N;;;;;\n1E6C5;TAI YO LETTER NGO;Lo;0;L;;;;;N;;;;;\n1E6C6;TAI YO LETTER CO;Lo;0;L;;;;;N;;;;;\n1E6C7;TAI YO LETTER LOW XO;Lo;0;L;;;;;N;;;;;\n1E6C8;TAI YO LETTER HIGH XO;Lo;0;L;;;;;N;;;;;\n1E6C9;TAI YO LETTER LOW NYO;Lo;0;L;;;;;N;;;;;\n1E6CA;TAI YO LETTER HIGH NYO;Lo;0;L;;;;;N;;;;;\n1E6CB;TAI YO LETTER DO;Lo;0;L;;;;;N;;;;;\n1E6CC;TAI YO LETTER LOW TO;Lo;0;L;;;;;N;;;;;\n1E6CD;TAI YO LETTER HIGH TO;Lo;0;L;;;;;N;;;;;\n1E6CE;TAI YO LETTER THO;Lo;0;L;;;;;N;;;;;\n1E6CF;TAI YO LETTER NO;Lo;0;L;;;;;N;;;;;\n1E6D0;TAI YO LETTER BO;Lo;0;L;;;;;N;;;;;\n1E6D1;TAI YO LETTER LOW PO;Lo;0;L;;;;;N;;;;;\n1E6D2;TAI YO LETTER HIGH PO;Lo;0;L;;;;;N;;;;;\n1E6D3;TAI YO LETTER PHO;Lo;0;L;;;;;N;;;;;\n1E6D4;TAI YO LETTER LOW FO;Lo;0;L;;;;;N;;;;;\n1E6D5;TAI YO LETTER HIGH FO;Lo;0;L;;;;;N;;;;;\n1E6D6;TAI YO LETTER MO;Lo;0;L;;;;;N;;;;;\n1E6D7;TAI YO LETTER YO;Lo;0;L;;;;;N;;;;;\n1E6D8;TAI YO LETTER LO;Lo;0;L;;;;;N;;;;;\n1E6D9;TAI YO LETTER VO;Lo;0;L;;;;;N;;;;;\n1E6DA;TAI YO LETTER LOW HO;Lo;0;L;;;;;N;;;;;\n1E6DB;TAI YO LETTER HIGH HO;Lo;0;L;;;;;N;;;;;\n1E6DC;TAI YO LETTER QO;Lo;0;L;;;;;N;;;;;\n1E6DD;TAI YO LETTER LOW KVO;Lo;0;L;;;;;N;;;;;\n1E6DE;TAI YO LETTER HIGH KVO;Lo;0;L;;;;;N;;;;;\n1E6E0;TAI YO LETTER AA;Lo;0;L;;;;;N;;;;;\n1E6E1;TAI YO LETTER I;Lo;0;L;;;;;N;;;;;\n1E6E2;TAI YO LETTER UE;Lo;0;L;;;;;N;;;;;\n1E6E3;TAI YO SIGN UE;Mn;230;NSM;;;;;N;;;;;\n1E6E4;TAI YO LETTER U;Lo;0;L;;;;;N;;;;;\n1E6E5;TAI YO LETTER AE;Lo;0;L;;;;;N;;;;;\n1E6E6;TAI YO SIGN AU;Mn;230;NSM;;;;;N;;;;;\n1E6E7;TAI YO LETTER O;Lo;0;L;;;;;N;;;;;\n1E6E8;TAI YO LETTER E;Lo;0;L;;;;;N;;;;;\n1E6E9;TAI YO LETTER IA;Lo;0;L;;;;;N;;;;;\n1E6EA;TAI YO LETTER UEA;Lo;0;L;;;;;N;;;;;\n1E6EB;TAI YO LETTER UA;Lo;0;L;;;;;N;;;;;\n1E6EC;TAI YO LETTER OO;Lo;0;L;;;;;N;;;;;\n1E6ED;TAI YO LETTER AUE;Lo;0;L;;;;;N;;;;;\n1E6EE;TAI YO SIGN AY;Mn;230;NSM;;;;;N;;;;;\n1E6EF;TAI YO SIGN ANG;Mn;230;NSM;;;;;N;;;;;\n1E6F0;TAI YO LETTER AN;Lo;0;L;;;;;N;;;;;\n1E6F1;TAI YO LETTER AM;Lo;0;L;;;;;N;;;;;\n1E6F2;TAI YO LETTER AK;Lo;0;L;;;;;N;;;;;\n1E6F3;TAI YO LETTER AT;Lo;0;L;;;;;N;;;;;\n1E6F4;TAI YO LETTER AP;Lo;0;L;;;;;N;;;;;\n1E6F5;TAI YO SIGN OM;Mn;230;NSM;;;;;N;;;;;\n1E6FE;TAI YO SYMBOL MUEANG;Lo;0;L;;;;;N;;;;;\n1E6FF;TAI YO XAM LAI;Lm;0;L;;;;;N;;;;;\n1E7E0;ETHIOPIC SYLLABLE HHYA;Lo;0;L;;;;;N;;;;;\n1E7E1;ETHIOPIC SYLLABLE HHYU;Lo;0;L;;;;;N;;;;;\n1E7E2;ETHIOPIC SYLLABLE HHYI;Lo;0;L;;;;;N;;;;;\n1E7E3;ETHIOPIC SYLLABLE HHYAA;Lo;0;L;;;;;N;;;;;\n1E7E4;ETHIOPIC SYLLABLE HHYEE;Lo;0;L;;;;;N;;;;;\n1E7E5;ETHIOPIC SYLLABLE HHYE;Lo;0;L;;;;;N;;;;;\n1E7E6;ETHIOPIC SYLLABLE HHYO;Lo;0;L;;;;;N;;;;;\n1E7E8;ETHIOPIC SYLLABLE GURAGE HHWA;Lo;0;L;;;;;N;;;;;\n1E7E9;ETHIOPIC SYLLABLE HHWI;Lo;0;L;;;;;N;;;;;\n1E7EA;ETHIOPIC SYLLABLE HHWEE;Lo;0;L;;;;;N;;;;;\n1E7EB;ETHIOPIC SYLLABLE HHWE;Lo;0;L;;;;;N;;;;;\n1E7ED;ETHIOPIC SYLLABLE GURAGE MWI;Lo;0;L;;;;;N;;;;;\n1E7EE;ETHIOPIC SYLLABLE GURAGE MWEE;Lo;0;L;;;;;N;;;;;\n1E7F0;ETHIOPIC SYLLABLE GURAGE QWI;Lo;0;L;;;;;N;;;;;\n1E7F1;ETHIOPIC SYLLABLE GURAGE QWEE;Lo;0;L;;;;;N;;;;;\n1E7F2;ETHIOPIC SYLLABLE GURAGE QWE;Lo;0;L;;;;;N;;;;;\n1E7F3;ETHIOPIC SYLLABLE GURAGE BWI;Lo;0;L;;;;;N;;;;;\n1E7F4;ETHIOPIC SYLLABLE GURAGE BWEE;Lo;0;L;;;;;N;;;;;\n1E7F5;ETHIOPIC SYLLABLE GURAGE KWI;Lo;0;L;;;;;N;;;;;\n1E7F6;ETHIOPIC SYLLABLE GURAGE KWEE;Lo;0;L;;;;;N;;;;;\n1E7F7;ETHIOPIC SYLLABLE GURAGE KWE;Lo;0;L;;;;;N;;;;;\n1E7F8;ETHIOPIC SYLLABLE GURAGE GWI;Lo;0;L;;;;;N;;;;;\n1E7F9;ETHIOPIC SYLLABLE GURAGE GWEE;Lo;0;L;;;;;N;;;;;\n1E7FA;ETHIOPIC SYLLABLE GURAGE GWE;Lo;0;L;;;;;N;;;;;\n1E7FB;ETHIOPIC SYLLABLE GURAGE FWI;Lo;0;L;;;;;N;;;;;\n1E7FC;ETHIOPIC SYLLABLE GURAGE FWEE;Lo;0;L;;;;;N;;;;;\n1E7FD;ETHIOPIC SYLLABLE GURAGE PWI;Lo;0;L;;;;;N;;;;;\n1E7FE;ETHIOPIC SYLLABLE GURAGE PWEE;Lo;0;L;;;;;N;;;;;\n1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;;\n1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;;\n1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;;\n1E803;MENDE KIKAKUI SYLLABLE M065 KEE;Lo;0;R;;;;;N;;;;;\n1E804;MENDE KIKAKUI SYLLABLE M095 KE;Lo;0;R;;;;;N;;;;;\n1E805;MENDE KIKAKUI SYLLABLE M076 KOO;Lo;0;R;;;;;N;;;;;\n1E806;MENDE KIKAKUI SYLLABLE M048 KO;Lo;0;R;;;;;N;;;;;\n1E807;MENDE KIKAKUI SYLLABLE M179 KUA;Lo;0;R;;;;;N;;;;;\n1E808;MENDE KIKAKUI SYLLABLE M004 WI;Lo;0;R;;;;;N;;;;;\n1E809;MENDE KIKAKUI SYLLABLE M005 WA;Lo;0;R;;;;;N;;;;;\n1E80A;MENDE KIKAKUI SYLLABLE M006 WU;Lo;0;R;;;;;N;;;;;\n1E80B;MENDE KIKAKUI SYLLABLE M126 WEE;Lo;0;R;;;;;N;;;;;\n1E80C;MENDE KIKAKUI SYLLABLE M118 WE;Lo;0;R;;;;;N;;;;;\n1E80D;MENDE KIKAKUI SYLLABLE M114 WOO;Lo;0;R;;;;;N;;;;;\n1E80E;MENDE KIKAKUI SYLLABLE M045 WO;Lo;0;R;;;;;N;;;;;\n1E80F;MENDE KIKAKUI SYLLABLE M194 WUI;Lo;0;R;;;;;N;;;;;\n1E810;MENDE KIKAKUI SYLLABLE M143 WEI;Lo;0;R;;;;;N;;;;;\n1E811;MENDE KIKAKUI SYLLABLE M061 WVI;Lo;0;R;;;;;N;;;;;\n1E812;MENDE KIKAKUI SYLLABLE M049 WVA;Lo;0;R;;;;;N;;;;;\n1E813;MENDE KIKAKUI SYLLABLE M139 WVE;Lo;0;R;;;;;N;;;;;\n1E814;MENDE KIKAKUI SYLLABLE M007 MIN;Lo;0;R;;;;;N;;;;;\n1E815;MENDE KIKAKUI SYLLABLE M008 MAN;Lo;0;R;;;;;N;;;;;\n1E816;MENDE KIKAKUI SYLLABLE M009 MUN;Lo;0;R;;;;;N;;;;;\n1E817;MENDE KIKAKUI SYLLABLE M059 MEN;Lo;0;R;;;;;N;;;;;\n1E818;MENDE KIKAKUI SYLLABLE M094 MON;Lo;0;R;;;;;N;;;;;\n1E819;MENDE KIKAKUI SYLLABLE M154 MUAN;Lo;0;R;;;;;N;;;;;\n1E81A;MENDE KIKAKUI SYLLABLE M189 MUEN;Lo;0;R;;;;;N;;;;;\n1E81B;MENDE KIKAKUI SYLLABLE M010 BI;Lo;0;R;;;;;N;;;;;\n1E81C;MENDE KIKAKUI SYLLABLE M011 BA;Lo;0;R;;;;;N;;;;;\n1E81D;MENDE KIKAKUI SYLLABLE M012 BU;Lo;0;R;;;;;N;;;;;\n1E81E;MENDE KIKAKUI SYLLABLE M150 BEE;Lo;0;R;;;;;N;;;;;\n1E81F;MENDE KIKAKUI SYLLABLE M097 BE;Lo;0;R;;;;;N;;;;;\n1E820;MENDE KIKAKUI SYLLABLE M103 BOO;Lo;0;R;;;;;N;;;;;\n1E821;MENDE KIKAKUI SYLLABLE M138 BO;Lo;0;R;;;;;N;;;;;\n1E822;MENDE KIKAKUI SYLLABLE M013 I;Lo;0;R;;;;;N;;;;;\n1E823;MENDE KIKAKUI SYLLABLE M014 A;Lo;0;R;;;;;N;;;;;\n1E824;MENDE KIKAKUI SYLLABLE M015 U;Lo;0;R;;;;;N;;;;;\n1E825;MENDE KIKAKUI SYLLABLE M163 EE;Lo;0;R;;;;;N;;;;;\n1E826;MENDE KIKAKUI SYLLABLE M100 E;Lo;0;R;;;;;N;;;;;\n1E827;MENDE KIKAKUI SYLLABLE M165 OO;Lo;0;R;;;;;N;;;;;\n1E828;MENDE KIKAKUI SYLLABLE M147 O;Lo;0;R;;;;;N;;;;;\n1E829;MENDE KIKAKUI SYLLABLE M137 EI;Lo;0;R;;;;;N;;;;;\n1E82A;MENDE KIKAKUI SYLLABLE M131 IN;Lo;0;R;;;;;N;;;;;\n1E82B;MENDE KIKAKUI SYLLABLE M135 IN;Lo;0;R;;;;;N;;;;;\n1E82C;MENDE KIKAKUI SYLLABLE M195 AN;Lo;0;R;;;;;N;;;;;\n1E82D;MENDE KIKAKUI SYLLABLE M178 EN;Lo;0;R;;;;;N;;;;;\n1E82E;MENDE KIKAKUI SYLLABLE M019 SI;Lo;0;R;;;;;N;;;;;\n1E82F;MENDE KIKAKUI SYLLABLE M020 SA;Lo;0;R;;;;;N;;;;;\n1E830;MENDE KIKAKUI SYLLABLE M021 SU;Lo;0;R;;;;;N;;;;;\n1E831;MENDE KIKAKUI SYLLABLE M162 SEE;Lo;0;R;;;;;N;;;;;\n1E832;MENDE KIKAKUI SYLLABLE M116 SE;Lo;0;R;;;;;N;;;;;\n1E833;MENDE KIKAKUI SYLLABLE M136 SOO;Lo;0;R;;;;;N;;;;;\n1E834;MENDE KIKAKUI SYLLABLE M079 SO;Lo;0;R;;;;;N;;;;;\n1E835;MENDE KIKAKUI SYLLABLE M196 SIA;Lo;0;R;;;;;N;;;;;\n1E836;MENDE KIKAKUI SYLLABLE M025 LI;Lo;0;R;;;;;N;;;;;\n1E837;MENDE KIKAKUI SYLLABLE M026 LA;Lo;0;R;;;;;N;;;;;\n1E838;MENDE KIKAKUI SYLLABLE M027 LU;Lo;0;R;;;;;N;;;;;\n1E839;MENDE KIKAKUI SYLLABLE M084 LEE;Lo;0;R;;;;;N;;;;;\n1E83A;MENDE KIKAKUI SYLLABLE M073 LE;Lo;0;R;;;;;N;;;;;\n1E83B;MENDE KIKAKUI SYLLABLE M054 LOO;Lo;0;R;;;;;N;;;;;\n1E83C;MENDE KIKAKUI SYLLABLE M153 LO;Lo;0;R;;;;;N;;;;;\n1E83D;MENDE KIKAKUI SYLLABLE M110 LONG LE;Lo;0;R;;;;;N;;;;;\n1E83E;MENDE KIKAKUI SYLLABLE M016 DI;Lo;0;R;;;;;N;;;;;\n1E83F;MENDE KIKAKUI SYLLABLE M017 DA;Lo;0;R;;;;;N;;;;;\n1E840;MENDE KIKAKUI SYLLABLE M018 DU;Lo;0;R;;;;;N;;;;;\n1E841;MENDE KIKAKUI SYLLABLE M089 DEE;Lo;0;R;;;;;N;;;;;\n1E842;MENDE KIKAKUI SYLLABLE M180 DOO;Lo;0;R;;;;;N;;;;;\n1E843;MENDE KIKAKUI SYLLABLE M181 DO;Lo;0;R;;;;;N;;;;;\n1E844;MENDE KIKAKUI SYLLABLE M022 TI;Lo;0;R;;;;;N;;;;;\n1E845;MENDE KIKAKUI SYLLABLE M023 TA;Lo;0;R;;;;;N;;;;;\n1E846;MENDE KIKAKUI SYLLABLE M024 TU;Lo;0;R;;;;;N;;;;;\n1E847;MENDE KIKAKUI SYLLABLE M091 TEE;Lo;0;R;;;;;N;;;;;\n1E848;MENDE KIKAKUI SYLLABLE M055 TE;Lo;0;R;;;;;N;;;;;\n1E849;MENDE KIKAKUI SYLLABLE M104 TOO;Lo;0;R;;;;;N;;;;;\n1E84A;MENDE KIKAKUI SYLLABLE M069 TO;Lo;0;R;;;;;N;;;;;\n1E84B;MENDE KIKAKUI SYLLABLE M028 JI;Lo;0;R;;;;;N;;;;;\n1E84C;MENDE KIKAKUI SYLLABLE M029 JA;Lo;0;R;;;;;N;;;;;\n1E84D;MENDE KIKAKUI SYLLABLE M030 JU;Lo;0;R;;;;;N;;;;;\n1E84E;MENDE KIKAKUI SYLLABLE M157 JEE;Lo;0;R;;;;;N;;;;;\n1E84F;MENDE KIKAKUI SYLLABLE M113 JE;Lo;0;R;;;;;N;;;;;\n1E850;MENDE KIKAKUI SYLLABLE M160 JOO;Lo;0;R;;;;;N;;;;;\n1E851;MENDE KIKAKUI SYLLABLE M063 JO;Lo;0;R;;;;;N;;;;;\n1E852;MENDE KIKAKUI SYLLABLE M175 LONG JO;Lo;0;R;;;;;N;;;;;\n1E853;MENDE KIKAKUI SYLLABLE M031 YI;Lo;0;R;;;;;N;;;;;\n1E854;MENDE KIKAKUI SYLLABLE M032 YA;Lo;0;R;;;;;N;;;;;\n1E855;MENDE KIKAKUI SYLLABLE M033 YU;Lo;0;R;;;;;N;;;;;\n1E856;MENDE KIKAKUI SYLLABLE M109 YEE;Lo;0;R;;;;;N;;;;;\n1E857;MENDE KIKAKUI SYLLABLE M080 YE;Lo;0;R;;;;;N;;;;;\n1E858;MENDE KIKAKUI SYLLABLE M141 YOO;Lo;0;R;;;;;N;;;;;\n1E859;MENDE KIKAKUI SYLLABLE M121 YO;Lo;0;R;;;;;N;;;;;\n1E85A;MENDE KIKAKUI SYLLABLE M034 FI;Lo;0;R;;;;;N;;;;;\n1E85B;MENDE KIKAKUI SYLLABLE M035 FA;Lo;0;R;;;;;N;;;;;\n1E85C;MENDE KIKAKUI SYLLABLE M036 FU;Lo;0;R;;;;;N;;;;;\n1E85D;MENDE KIKAKUI SYLLABLE M078 FEE;Lo;0;R;;;;;N;;;;;\n1E85E;MENDE KIKAKUI SYLLABLE M075 FE;Lo;0;R;;;;;N;;;;;\n1E85F;MENDE KIKAKUI SYLLABLE M133 FOO;Lo;0;R;;;;;N;;;;;\n1E860;MENDE KIKAKUI SYLLABLE M088 FO;Lo;0;R;;;;;N;;;;;\n1E861;MENDE KIKAKUI SYLLABLE M197 FUA;Lo;0;R;;;;;N;;;;;\n1E862;MENDE KIKAKUI SYLLABLE M101 FAN;Lo;0;R;;;;;N;;;;;\n1E863;MENDE KIKAKUI SYLLABLE M037 NIN;Lo;0;R;;;;;N;;;;;\n1E864;MENDE KIKAKUI SYLLABLE M038 NAN;Lo;0;R;;;;;N;;;;;\n1E865;MENDE KIKAKUI SYLLABLE M039 NUN;Lo;0;R;;;;;N;;;;;\n1E866;MENDE KIKAKUI SYLLABLE M117 NEN;Lo;0;R;;;;;N;;;;;\n1E867;MENDE KIKAKUI SYLLABLE M169 NON;Lo;0;R;;;;;N;;;;;\n1E868;MENDE KIKAKUI SYLLABLE M176 HI;Lo;0;R;;;;;N;;;;;\n1E869;MENDE KIKAKUI SYLLABLE M041 HA;Lo;0;R;;;;;N;;;;;\n1E86A;MENDE KIKAKUI SYLLABLE M186 HU;Lo;0;R;;;;;N;;;;;\n1E86B;MENDE KIKAKUI SYLLABLE M040 HEE;Lo;0;R;;;;;N;;;;;\n1E86C;MENDE KIKAKUI SYLLABLE M096 HE;Lo;0;R;;;;;N;;;;;\n1E86D;MENDE KIKAKUI SYLLABLE M042 HOO;Lo;0;R;;;;;N;;;;;\n1E86E;MENDE KIKAKUI SYLLABLE M140 HO;Lo;0;R;;;;;N;;;;;\n1E86F;MENDE KIKAKUI SYLLABLE M083 HEEI;Lo;0;R;;;;;N;;;;;\n1E870;MENDE KIKAKUI SYLLABLE M128 HOOU;Lo;0;R;;;;;N;;;;;\n1E871;MENDE KIKAKUI SYLLABLE M053 HIN;Lo;0;R;;;;;N;;;;;\n1E872;MENDE KIKAKUI SYLLABLE M130 HAN;Lo;0;R;;;;;N;;;;;\n1E873;MENDE KIKAKUI SYLLABLE M087 HUN;Lo;0;R;;;;;N;;;;;\n1E874;MENDE KIKAKUI SYLLABLE M052 HEN;Lo;0;R;;;;;N;;;;;\n1E875;MENDE KIKAKUI SYLLABLE M193 HON;Lo;0;R;;;;;N;;;;;\n1E876;MENDE KIKAKUI SYLLABLE M046 HUAN;Lo;0;R;;;;;N;;;;;\n1E877;MENDE KIKAKUI SYLLABLE M090 NGGI;Lo;0;R;;;;;N;;;;;\n1E878;MENDE KIKAKUI SYLLABLE M043 NGGA;Lo;0;R;;;;;N;;;;;\n1E879;MENDE KIKAKUI SYLLABLE M082 NGGU;Lo;0;R;;;;;N;;;;;\n1E87A;MENDE KIKAKUI SYLLABLE M115 NGGEE;Lo;0;R;;;;;N;;;;;\n1E87B;MENDE KIKAKUI SYLLABLE M146 NGGE;Lo;0;R;;;;;N;;;;;\n1E87C;MENDE KIKAKUI SYLLABLE M156 NGGOO;Lo;0;R;;;;;N;;;;;\n1E87D;MENDE KIKAKUI SYLLABLE M120 NGGO;Lo;0;R;;;;;N;;;;;\n1E87E;MENDE KIKAKUI SYLLABLE M159 NGGAA;Lo;0;R;;;;;N;;;;;\n1E87F;MENDE KIKAKUI SYLLABLE M127 NGGUA;Lo;0;R;;;;;N;;;;;\n1E880;MENDE KIKAKUI SYLLABLE M086 LONG NGGE;Lo;0;R;;;;;N;;;;;\n1E881;MENDE KIKAKUI SYLLABLE M106 LONG NGGOO;Lo;0;R;;;;;N;;;;;\n1E882;MENDE KIKAKUI SYLLABLE M183 LONG NGGO;Lo;0;R;;;;;N;;;;;\n1E883;MENDE KIKAKUI SYLLABLE M155 GI;Lo;0;R;;;;;N;;;;;\n1E884;MENDE KIKAKUI SYLLABLE M111 GA;Lo;0;R;;;;;N;;;;;\n1E885;MENDE KIKAKUI SYLLABLE M168 GU;Lo;0;R;;;;;N;;;;;\n1E886;MENDE KIKAKUI SYLLABLE M190 GEE;Lo;0;R;;;;;N;;;;;\n1E887;MENDE KIKAKUI SYLLABLE M166 GUEI;Lo;0;R;;;;;N;;;;;\n1E888;MENDE KIKAKUI SYLLABLE M167 GUAN;Lo;0;R;;;;;N;;;;;\n1E889;MENDE KIKAKUI SYLLABLE M184 NGEN;Lo;0;R;;;;;N;;;;;\n1E88A;MENDE KIKAKUI SYLLABLE M057 NGON;Lo;0;R;;;;;N;;;;;\n1E88B;MENDE KIKAKUI SYLLABLE M177 NGUAN;Lo;0;R;;;;;N;;;;;\n1E88C;MENDE KIKAKUI SYLLABLE M068 PI;Lo;0;R;;;;;N;;;;;\n1E88D;MENDE KIKAKUI SYLLABLE M099 PA;Lo;0;R;;;;;N;;;;;\n1E88E;MENDE KIKAKUI SYLLABLE M050 PU;Lo;0;R;;;;;N;;;;;\n1E88F;MENDE KIKAKUI SYLLABLE M081 PEE;Lo;0;R;;;;;N;;;;;\n1E890;MENDE KIKAKUI SYLLABLE M051 PE;Lo;0;R;;;;;N;;;;;\n1E891;MENDE KIKAKUI SYLLABLE M102 POO;Lo;0;R;;;;;N;;;;;\n1E892;MENDE KIKAKUI SYLLABLE M066 PO;Lo;0;R;;;;;N;;;;;\n1E893;MENDE KIKAKUI SYLLABLE M145 MBI;Lo;0;R;;;;;N;;;;;\n1E894;MENDE KIKAKUI SYLLABLE M062 MBA;Lo;0;R;;;;;N;;;;;\n1E895;MENDE KIKAKUI SYLLABLE M122 MBU;Lo;0;R;;;;;N;;;;;\n1E896;MENDE KIKAKUI SYLLABLE M047 MBEE;Lo;0;R;;;;;N;;;;;\n1E897;MENDE KIKAKUI SYLLABLE M188 MBEE;Lo;0;R;;;;;N;;;;;\n1E898;MENDE KIKAKUI SYLLABLE M072 MBE;Lo;0;R;;;;;N;;;;;\n1E899;MENDE KIKAKUI SYLLABLE M172 MBOO;Lo;0;R;;;;;N;;;;;\n1E89A;MENDE KIKAKUI SYLLABLE M174 MBO;Lo;0;R;;;;;N;;;;;\n1E89B;MENDE KIKAKUI SYLLABLE M187 MBUU;Lo;0;R;;;;;N;;;;;\n1E89C;MENDE KIKAKUI SYLLABLE M161 LONG MBE;Lo;0;R;;;;;N;;;;;\n1E89D;MENDE KIKAKUI SYLLABLE M105 LONG MBOO;Lo;0;R;;;;;N;;;;;\n1E89E;MENDE KIKAKUI SYLLABLE M142 LONG MBO;Lo;0;R;;;;;N;;;;;\n1E89F;MENDE KIKAKUI SYLLABLE M132 KPI;Lo;0;R;;;;;N;;;;;\n1E8A0;MENDE KIKAKUI SYLLABLE M092 KPA;Lo;0;R;;;;;N;;;;;\n1E8A1;MENDE KIKAKUI SYLLABLE M074 KPU;Lo;0;R;;;;;N;;;;;\n1E8A2;MENDE KIKAKUI SYLLABLE M044 KPEE;Lo;0;R;;;;;N;;;;;\n1E8A3;MENDE KIKAKUI SYLLABLE M108 KPE;Lo;0;R;;;;;N;;;;;\n1E8A4;MENDE KIKAKUI SYLLABLE M112 KPOO;Lo;0;R;;;;;N;;;;;\n1E8A5;MENDE KIKAKUI SYLLABLE M158 KPO;Lo;0;R;;;;;N;;;;;\n1E8A6;MENDE KIKAKUI SYLLABLE M124 GBI;Lo;0;R;;;;;N;;;;;\n1E8A7;MENDE KIKAKUI SYLLABLE M056 GBA;Lo;0;R;;;;;N;;;;;\n1E8A8;MENDE KIKAKUI SYLLABLE M148 GBU;Lo;0;R;;;;;N;;;;;\n1E8A9;MENDE KIKAKUI SYLLABLE M093 GBEE;Lo;0;R;;;;;N;;;;;\n1E8AA;MENDE KIKAKUI SYLLABLE M107 GBE;Lo;0;R;;;;;N;;;;;\n1E8AB;MENDE KIKAKUI SYLLABLE M071 GBOO;Lo;0;R;;;;;N;;;;;\n1E8AC;MENDE KIKAKUI SYLLABLE M070 GBO;Lo;0;R;;;;;N;;;;;\n1E8AD;MENDE KIKAKUI SYLLABLE M171 RA;Lo;0;R;;;;;N;;;;;\n1E8AE;MENDE KIKAKUI SYLLABLE M123 NDI;Lo;0;R;;;;;N;;;;;\n1E8AF;MENDE KIKAKUI SYLLABLE M129 NDA;Lo;0;R;;;;;N;;;;;\n1E8B0;MENDE KIKAKUI SYLLABLE M125 NDU;Lo;0;R;;;;;N;;;;;\n1E8B1;MENDE KIKAKUI SYLLABLE M191 NDEE;Lo;0;R;;;;;N;;;;;\n1E8B2;MENDE KIKAKUI SYLLABLE M119 NDE;Lo;0;R;;;;;N;;;;;\n1E8B3;MENDE KIKAKUI SYLLABLE M067 NDOO;Lo;0;R;;;;;N;;;;;\n1E8B4;MENDE KIKAKUI SYLLABLE M064 NDO;Lo;0;R;;;;;N;;;;;\n1E8B5;MENDE KIKAKUI SYLLABLE M152 NJA;Lo;0;R;;;;;N;;;;;\n1E8B6;MENDE KIKAKUI SYLLABLE M192 NJU;Lo;0;R;;;;;N;;;;;\n1E8B7;MENDE KIKAKUI SYLLABLE M149 NJEE;Lo;0;R;;;;;N;;;;;\n1E8B8;MENDE KIKAKUI SYLLABLE M134 NJOO;Lo;0;R;;;;;N;;;;;\n1E8B9;MENDE KIKAKUI SYLLABLE M182 VI;Lo;0;R;;;;;N;;;;;\n1E8BA;MENDE KIKAKUI SYLLABLE M185 VA;Lo;0;R;;;;;N;;;;;\n1E8BB;MENDE KIKAKUI SYLLABLE M151 VU;Lo;0;R;;;;;N;;;;;\n1E8BC;MENDE KIKAKUI SYLLABLE M173 VEE;Lo;0;R;;;;;N;;;;;\n1E8BD;MENDE KIKAKUI SYLLABLE M085 VE;Lo;0;R;;;;;N;;;;;\n1E8BE;MENDE KIKAKUI SYLLABLE M144 VOO;Lo;0;R;;;;;N;;;;;\n1E8BF;MENDE KIKAKUI SYLLABLE M077 VO;Lo;0;R;;;;;N;;;;;\n1E8C0;MENDE KIKAKUI SYLLABLE M164 NYIN;Lo;0;R;;;;;N;;;;;\n1E8C1;MENDE KIKAKUI SYLLABLE M058 NYAN;Lo;0;R;;;;;N;;;;;\n1E8C2;MENDE KIKAKUI SYLLABLE M170 NYUN;Lo;0;R;;;;;N;;;;;\n1E8C3;MENDE KIKAKUI SYLLABLE M098 NYEN;Lo;0;R;;;;;N;;;;;\n1E8C4;MENDE KIKAKUI SYLLABLE M060 NYON;Lo;0;R;;;;;N;;;;;\n1E8C7;MENDE KIKAKUI DIGIT ONE;No;0;R;;;;1;N;;;;;\n1E8C8;MENDE KIKAKUI DIGIT TWO;No;0;R;;;;2;N;;;;;\n1E8C9;MENDE KIKAKUI DIGIT THREE;No;0;R;;;;3;N;;;;;\n1E8CA;MENDE KIKAKUI DIGIT FOUR;No;0;R;;;;4;N;;;;;\n1E8CB;MENDE KIKAKUI DIGIT FIVE;No;0;R;;;;5;N;;;;;\n1E8CC;MENDE KIKAKUI DIGIT SIX;No;0;R;;;;6;N;;;;;\n1E8CD;MENDE KIKAKUI DIGIT SEVEN;No;0;R;;;;7;N;;;;;\n1E8CE;MENDE KIKAKUI DIGIT EIGHT;No;0;R;;;;8;N;;;;;\n1E8CF;MENDE KIKAKUI DIGIT NINE;No;0;R;;;;9;N;;;;;\n1E8D0;MENDE KIKAKUI COMBINING NUMBER TEENS;Mn;220;NSM;;;;;N;;;;;\n1E8D1;MENDE KIKAKUI COMBINING NUMBER TENS;Mn;220;NSM;;;;;N;;;;;\n1E8D2;MENDE KIKAKUI COMBINING NUMBER HUNDREDS;Mn;220;NSM;;;;;N;;;;;\n1E8D3;MENDE KIKAKUI COMBINING NUMBER THOUSANDS;Mn;220;NSM;;;;;N;;;;;\n1E8D4;MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS;Mn;220;NSM;;;;;N;;;;;\n1E8D5;MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS;Mn;220;NSM;;;;;N;;;;;\n1E8D6;MENDE KIKAKUI COMBINING NUMBER MILLIONS;Mn;220;NSM;;;;;N;;;;;\n1E900;ADLAM CAPITAL LETTER ALIF;Lu;0;R;;;;;N;;;;1E922;\n1E901;ADLAM CAPITAL LETTER DAALI;Lu;0;R;;;;;N;;;;1E923;\n1E902;ADLAM CAPITAL LETTER LAAM;Lu;0;R;;;;;N;;;;1E924;\n1E903;ADLAM CAPITAL LETTER MIIM;Lu;0;R;;;;;N;;;;1E925;\n1E904;ADLAM CAPITAL LETTER BA;Lu;0;R;;;;;N;;;;1E926;\n1E905;ADLAM CAPITAL LETTER SINNYIIYHE;Lu;0;R;;;;;N;;;;1E927;\n1E906;ADLAM CAPITAL LETTER PE;Lu;0;R;;;;;N;;;;1E928;\n1E907;ADLAM CAPITAL LETTER BHE;Lu;0;R;;;;;N;;;;1E929;\n1E908;ADLAM CAPITAL LETTER RA;Lu;0;R;;;;;N;;;;1E92A;\n1E909;ADLAM CAPITAL LETTER E;Lu;0;R;;;;;N;;;;1E92B;\n1E90A;ADLAM CAPITAL LETTER FA;Lu;0;R;;;;;N;;;;1E92C;\n1E90B;ADLAM CAPITAL LETTER I;Lu;0;R;;;;;N;;;;1E92D;\n1E90C;ADLAM CAPITAL LETTER O;Lu;0;R;;;;;N;;;;1E92E;\n1E90D;ADLAM CAPITAL LETTER DHA;Lu;0;R;;;;;N;;;;1E92F;\n1E90E;ADLAM CAPITAL LETTER YHE;Lu;0;R;;;;;N;;;;1E930;\n1E90F;ADLAM CAPITAL LETTER WAW;Lu;0;R;;;;;N;;;;1E931;\n1E910;ADLAM CAPITAL LETTER NUN;Lu;0;R;;;;;N;;;;1E932;\n1E911;ADLAM CAPITAL LETTER KAF;Lu;0;R;;;;;N;;;;1E933;\n1E912;ADLAM CAPITAL LETTER YA;Lu;0;R;;;;;N;;;;1E934;\n1E913;ADLAM CAPITAL LETTER U;Lu;0;R;;;;;N;;;;1E935;\n1E914;ADLAM CAPITAL LETTER JIIM;Lu;0;R;;;;;N;;;;1E936;\n1E915;ADLAM CAPITAL LETTER CHI;Lu;0;R;;;;;N;;;;1E937;\n1E916;ADLAM CAPITAL LETTER HA;Lu;0;R;;;;;N;;;;1E938;\n1E917;ADLAM CAPITAL LETTER QAAF;Lu;0;R;;;;;N;;;;1E939;\n1E918;ADLAM CAPITAL LETTER GA;Lu;0;R;;;;;N;;;;1E93A;\n1E919;ADLAM CAPITAL LETTER NYA;Lu;0;R;;;;;N;;;;1E93B;\n1E91A;ADLAM CAPITAL LETTER TU;Lu;0;R;;;;;N;;;;1E93C;\n1E91B;ADLAM CAPITAL LETTER NHA;Lu;0;R;;;;;N;;;;1E93D;\n1E91C;ADLAM CAPITAL LETTER VA;Lu;0;R;;;;;N;;;;1E93E;\n1E91D;ADLAM CAPITAL LETTER KHA;Lu;0;R;;;;;N;;;;1E93F;\n1E91E;ADLAM CAPITAL LETTER GBE;Lu;0;R;;;;;N;;;;1E940;\n1E91F;ADLAM CAPITAL LETTER ZAL;Lu;0;R;;;;;N;;;;1E941;\n1E920;ADLAM CAPITAL LETTER KPO;Lu;0;R;;;;;N;;;;1E942;\n1E921;ADLAM CAPITAL LETTER SHA;Lu;0;R;;;;;N;;;;1E943;\n1E922;ADLAM SMALL LETTER ALIF;Ll;0;R;;;;;N;;;1E900;;1E900\n1E923;ADLAM SMALL LETTER DAALI;Ll;0;R;;;;;N;;;1E901;;1E901\n1E924;ADLAM SMALL LETTER LAAM;Ll;0;R;;;;;N;;;1E902;;1E902\n1E925;ADLAM SMALL LETTER MIIM;Ll;0;R;;;;;N;;;1E903;;1E903\n1E926;ADLAM SMALL LETTER BA;Ll;0;R;;;;;N;;;1E904;;1E904\n1E927;ADLAM SMALL LETTER SINNYIIYHE;Ll;0;R;;;;;N;;;1E905;;1E905\n1E928;ADLAM SMALL LETTER PE;Ll;0;R;;;;;N;;;1E906;;1E906\n1E929;ADLAM SMALL LETTER BHE;Ll;0;R;;;;;N;;;1E907;;1E907\n1E92A;ADLAM SMALL LETTER RA;Ll;0;R;;;;;N;;;1E908;;1E908\n1E92B;ADLAM SMALL LETTER E;Ll;0;R;;;;;N;;;1E909;;1E909\n1E92C;ADLAM SMALL LETTER FA;Ll;0;R;;;;;N;;;1E90A;;1E90A\n1E92D;ADLAM SMALL LETTER I;Ll;0;R;;;;;N;;;1E90B;;1E90B\n1E92E;ADLAM SMALL LETTER O;Ll;0;R;;;;;N;;;1E90C;;1E90C\n1E92F;ADLAM SMALL LETTER DHA;Ll;0;R;;;;;N;;;1E90D;;1E90D\n1E930;ADLAM SMALL LETTER YHE;Ll;0;R;;;;;N;;;1E90E;;1E90E\n1E931;ADLAM SMALL LETTER WAW;Ll;0;R;;;;;N;;;1E90F;;1E90F\n1E932;ADLAM SMALL LETTER NUN;Ll;0;R;;;;;N;;;1E910;;1E910\n1E933;ADLAM SMALL LETTER KAF;Ll;0;R;;;;;N;;;1E911;;1E911\n1E934;ADLAM SMALL LETTER YA;Ll;0;R;;;;;N;;;1E912;;1E912\n1E935;ADLAM SMALL LETTER U;Ll;0;R;;;;;N;;;1E913;;1E913\n1E936;ADLAM SMALL LETTER JIIM;Ll;0;R;;;;;N;;;1E914;;1E914\n1E937;ADLAM SMALL LETTER CHI;Ll;0;R;;;;;N;;;1E915;;1E915\n1E938;ADLAM SMALL LETTER HA;Ll;0;R;;;;;N;;;1E916;;1E916\n1E939;ADLAM SMALL LETTER QAAF;Ll;0;R;;;;;N;;;1E917;;1E917\n1E93A;ADLAM SMALL LETTER GA;Ll;0;R;;;;;N;;;1E918;;1E918\n1E93B;ADLAM SMALL LETTER NYA;Ll;0;R;;;;;N;;;1E919;;1E919\n1E93C;ADLAM SMALL LETTER TU;Ll;0;R;;;;;N;;;1E91A;;1E91A\n1E93D;ADLAM SMALL LETTER NHA;Ll;0;R;;;;;N;;;1E91B;;1E91B\n1E93E;ADLAM SMALL LETTER VA;Ll;0;R;;;;;N;;;1E91C;;1E91C\n1E93F;ADLAM SMALL LETTER KHA;Ll;0;R;;;;;N;;;1E91D;;1E91D\n1E940;ADLAM SMALL LETTER GBE;Ll;0;R;;;;;N;;;1E91E;;1E91E\n1E941;ADLAM SMALL LETTER ZAL;Ll;0;R;;;;;N;;;1E91F;;1E91F\n1E942;ADLAM SMALL LETTER KPO;Ll;0;R;;;;;N;;;1E920;;1E920\n1E943;ADLAM SMALL LETTER SHA;Ll;0;R;;;;;N;;;1E921;;1E921\n1E944;ADLAM ALIF LENGTHENER;Mn;230;NSM;;;;;N;;;;;\n1E945;ADLAM VOWEL LENGTHENER;Mn;230;NSM;;;;;N;;;;;\n1E946;ADLAM GEMINATION MARK;Mn;230;NSM;;;;;N;;;;;\n1E947;ADLAM HAMZA;Mn;230;NSM;;;;;N;;;;;\n1E948;ADLAM CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;;\n1E949;ADLAM GEMINATE CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;;\n1E94A;ADLAM NUKTA;Mn;7;NSM;;;;;N;;;;;\n1E94B;ADLAM NASALIZATION MARK;Lm;0;R;;;;;N;;;;;\n1E950;ADLAM DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;;\n1E951;ADLAM DIGIT ONE;Nd;0;R;;1;1;1;N;;;;;\n1E952;ADLAM DIGIT TWO;Nd;0;R;;2;2;2;N;;;;;\n1E953;ADLAM DIGIT THREE;Nd;0;R;;3;3;3;N;;;;;\n1E954;ADLAM DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;;\n1E955;ADLAM DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;;\n1E956;ADLAM DIGIT SIX;Nd;0;R;;6;6;6;N;;;;;\n1E957;ADLAM DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;;\n1E958;ADLAM DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;;\n1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;;\n1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;;\n1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;;\n1EC71;INDIC SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;;\n1EC72;INDIC SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;;\n1EC73;INDIC SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;;\n1EC74;INDIC SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;;\n1EC75;INDIC SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;;\n1EC76;INDIC SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;;\n1EC77;INDIC SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;;\n1EC78;INDIC SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;;\n1EC79;INDIC SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;;\n1EC7A;INDIC SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;;\n1EC7B;INDIC SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;;\n1EC7C;INDIC SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;;\n1EC7D;INDIC SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;;\n1EC7E;INDIC SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;;\n1EC7F;INDIC SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;;\n1EC80;INDIC SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;;\n1EC81;INDIC SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;;\n1EC82;INDIC SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;;\n1EC83;INDIC SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;;\n1EC84;INDIC SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;;\n1EC85;INDIC SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;;\n1EC86;INDIC SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;;\n1EC87;INDIC SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;;\n1EC88;INDIC SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;;\n1EC89;INDIC SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;;\n1EC8A;INDIC SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;;\n1EC8B;INDIC SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;;\n1EC8C;INDIC SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;;\n1EC8D;INDIC SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;;\n1EC8E;INDIC SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;;\n1EC8F;INDIC SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;;\n1EC90;INDIC SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;;\n1EC91;INDIC SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;;\n1EC92;INDIC SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;;\n1EC93;INDIC SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;;\n1EC94;INDIC SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;;\n1EC95;INDIC SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;;\n1EC96;INDIC SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;;\n1EC97;INDIC SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;;\n1EC98;INDIC SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;;\n1EC99;INDIC SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;;\n1EC9A;INDIC SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;;\n1EC9B;INDIC SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;;\n1EC9C;INDIC SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;;\n1EC9D;INDIC SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;;\n1EC9E;INDIC SIYAQ NUMBER LAKH;No;0;AL;;;;100000;N;;;;;\n1EC9F;INDIC SIYAQ NUMBER LAKHAN;No;0;AL;;;;200000;N;;;;;\n1ECA0;INDIC SIYAQ LAKH MARK;No;0;AL;;;;100000;N;;;;;\n1ECA1;INDIC SIYAQ NUMBER KAROR;No;0;AL;;;;10000000;N;;;;;\n1ECA2;INDIC SIYAQ NUMBER KARORAN;No;0;AL;;;;20000000;N;;;;;\n1ECA3;INDIC SIYAQ NUMBER PREFIXED ONE;No;0;AL;;;;1;N;;;;;\n1ECA4;INDIC SIYAQ NUMBER PREFIXED TWO;No;0;AL;;;;2;N;;;;;\n1ECA5;INDIC SIYAQ NUMBER PREFIXED THREE;No;0;AL;;;;3;N;;;;;\n1ECA6;INDIC SIYAQ NUMBER PREFIXED FOUR;No;0;AL;;;;4;N;;;;;\n1ECA7;INDIC SIYAQ NUMBER PREFIXED FIVE;No;0;AL;;;;5;N;;;;;\n1ECA8;INDIC SIYAQ NUMBER PREFIXED SIX;No;0;AL;;;;6;N;;;;;\n1ECA9;INDIC SIYAQ NUMBER PREFIXED SEVEN;No;0;AL;;;;7;N;;;;;\n1ECAA;INDIC SIYAQ NUMBER PREFIXED EIGHT;No;0;AL;;;;8;N;;;;;\n1ECAB;INDIC SIYAQ NUMBER PREFIXED NINE;No;0;AL;;;;9;N;;;;;\n1ECAC;INDIC SIYAQ PLACEHOLDER;So;0;AL;;;;;N;;;;;\n1ECAD;INDIC SIYAQ FRACTION ONE QUARTER;No;0;AL;;;;1/4;N;;;;;\n1ECAE;INDIC SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;;\n1ECAF;INDIC SIYAQ FRACTION THREE QUARTERS;No;0;AL;;;;3/4;N;;;;;\n1ECB0;INDIC SIYAQ RUPEE MARK;Sc;0;AL;;;;;N;;;;;\n1ECB1;INDIC SIYAQ NUMBER ALTERNATE ONE;No;0;AL;;;;1;N;;;;;\n1ECB2;INDIC SIYAQ NUMBER ALTERNATE TWO;No;0;AL;;;;2;N;;;;;\n1ECB3;INDIC SIYAQ NUMBER ALTERNATE TEN THOUSAND;No;0;AL;;;;10000;N;;;;;\n1ECB4;INDIC SIYAQ ALTERNATE LAKH MARK;No;0;AL;;;;100000;N;;;;;\n1ED01;OTTOMAN SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;;\n1ED02;OTTOMAN SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;;\n1ED03;OTTOMAN SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;;\n1ED04;OTTOMAN SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;;\n1ED05;OTTOMAN SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;;\n1ED06;OTTOMAN SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;;\n1ED07;OTTOMAN SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;;\n1ED08;OTTOMAN SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;;\n1ED09;OTTOMAN SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;;\n1ED0A;OTTOMAN SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;;\n1ED0B;OTTOMAN SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;;\n1ED0C;OTTOMAN SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;;\n1ED0D;OTTOMAN SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;;\n1ED0E;OTTOMAN SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;;\n1ED0F;OTTOMAN SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;;\n1ED10;OTTOMAN SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;;\n1ED11;OTTOMAN SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;;\n1ED12;OTTOMAN SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;;\n1ED13;OTTOMAN SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;;\n1ED14;OTTOMAN SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;;\n1ED15;OTTOMAN SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;;\n1ED16;OTTOMAN SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;;\n1ED17;OTTOMAN SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;;\n1ED18;OTTOMAN SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;;\n1ED19;OTTOMAN SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;;\n1ED1A;OTTOMAN SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;;\n1ED1B;OTTOMAN SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;;\n1ED1C;OTTOMAN SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;;\n1ED1D;OTTOMAN SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;;\n1ED1E;OTTOMAN SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;;\n1ED1F;OTTOMAN SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;;\n1ED20;OTTOMAN SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;;\n1ED21;OTTOMAN SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;;\n1ED22;OTTOMAN SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;;\n1ED23;OTTOMAN SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;;\n1ED24;OTTOMAN SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;;\n1ED25;OTTOMAN SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;;\n1ED26;OTTOMAN SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;;\n1ED27;OTTOMAN SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;;\n1ED28;OTTOMAN SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;;\n1ED29;OTTOMAN SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;;\n1ED2A;OTTOMAN SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;;\n1ED2B;OTTOMAN SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;;\n1ED2C;OTTOMAN SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;;\n1ED2D;OTTOMAN SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;;\n1ED2E;OTTOMAN SIYAQ MARRATAN;So;0;AL;;;;;N;;;;;\n1ED2F;OTTOMAN SIYAQ ALTERNATE NUMBER TWO;No;0;AL;;;;2;N;;;;;\n1ED30;OTTOMAN SIYAQ ALTERNATE NUMBER THREE;No;0;AL;;;;3;N;;;;;\n1ED31;OTTOMAN SIYAQ ALTERNATE NUMBER FOUR;No;0;AL;;;;4;N;;;;;\n1ED32;OTTOMAN SIYAQ ALTERNATE NUMBER FIVE;No;0;AL;;;;5;N;;;;;\n1ED33;OTTOMAN SIYAQ ALTERNATE NUMBER SIX;No;0;AL;;;;6;N;;;;;\n1ED34;OTTOMAN SIYAQ ALTERNATE NUMBER SEVEN;No;0;AL;;;;7;N;;;;;\n1ED35;OTTOMAN SIYAQ ALTERNATE NUMBER EIGHT;No;0;AL;;;;8;N;;;;;\n1ED36;OTTOMAN SIYAQ ALTERNATE NUMBER NINE;No;0;AL;;;;9;N;;;;;\n1ED37;OTTOMAN SIYAQ ALTERNATE NUMBER TEN;No;0;AL;;;;10;N;;;;;\n1ED38;OTTOMAN SIYAQ ALTERNATE NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;;\n1ED39;OTTOMAN SIYAQ ALTERNATE NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;;\n1ED3A;OTTOMAN SIYAQ ALTERNATE NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;;\n1ED3B;OTTOMAN SIYAQ ALTERNATE NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;;\n1ED3C;OTTOMAN SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;;\n1ED3D;OTTOMAN SIYAQ FRACTION ONE SIXTH;No;0;AL;;;;1/6;N;;;;;\n1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;;\n1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;;\n1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;\n1EE03;ARABIC MATHEMATICAL DAL;Lo;0;AL;<font> 062F;;;;N;;;;;\n1EE05;ARABIC MATHEMATICAL WAW;Lo;0;AL;<font> 0648;;;;N;;;;;\n1EE06;ARABIC MATHEMATICAL ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;;\n1EE07;ARABIC MATHEMATICAL HAH;Lo;0;AL;<font> 062D;;;;N;;;;;\n1EE08;ARABIC MATHEMATICAL TAH;Lo;0;AL;<font> 0637;;;;N;;;;;\n1EE09;ARABIC MATHEMATICAL YEH;Lo;0;AL;<font> 064A;;;;N;;;;;\n1EE0A;ARABIC MATHEMATICAL KAF;Lo;0;AL;<font> 0643;;;;N;;;;;\n1EE0B;ARABIC MATHEMATICAL LAM;Lo;0;AL;<font> 0644;;;;N;;;;;\n1EE0C;ARABIC MATHEMATICAL MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;\n1EE0D;ARABIC MATHEMATICAL NOON;Lo;0;AL;<font> 0646;;;;N;;;;;\n1EE0E;ARABIC MATHEMATICAL SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;\n1EE0F;ARABIC MATHEMATICAL AIN;Lo;0;AL;<font> 0639;;;;N;;;;;\n1EE10;ARABIC MATHEMATICAL FEH;Lo;0;AL;<font> 0641;;;;N;;;;;\n1EE11;ARABIC MATHEMATICAL SAD;Lo;0;AL;<font> 0635;;;;N;;;;;\n1EE12;ARABIC MATHEMATICAL QAF;Lo;0;AL;<font> 0642;;;;N;;;;;\n1EE13;ARABIC MATHEMATICAL REH;Lo;0;AL;<font> 0631;;;;N;;;;;\n1EE14;ARABIC MATHEMATICAL SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;\n1EE15;ARABIC MATHEMATICAL TEH;Lo;0;AL;<font> 062A;;;;N;;;;;\n1EE16;ARABIC MATHEMATICAL THEH;Lo;0;AL;<font> 062B;;;;N;;;;;\n1EE17;ARABIC MATHEMATICAL KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;\n1EE18;ARABIC MATHEMATICAL THAL;Lo;0;AL;<font> 0630;;;;N;;;;;\n1EE19;ARABIC MATHEMATICAL DAD;Lo;0;AL;<font> 0636;;;;N;;;;;\n1EE1A;ARABIC MATHEMATICAL ZAH;Lo;0;AL;<font> 0638;;;;N;;;;;\n1EE1B;ARABIC MATHEMATICAL GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;\n1EE1C;ARABIC MATHEMATICAL DOTLESS BEH;Lo;0;AL;<font> 066E;;;;N;;;;;\n1EE1D;ARABIC MATHEMATICAL DOTLESS NOON;Lo;0;AL;<font> 06BA;;;;N;;;;;\n1EE1E;ARABIC MATHEMATICAL DOTLESS FEH;Lo;0;AL;<font> 06A1;;;;N;;;;;\n1EE1F;ARABIC MATHEMATICAL DOTLESS QAF;Lo;0;AL;<font> 066F;;;;N;;;;;\n1EE21;ARABIC MATHEMATICAL INITIAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;;\n1EE22;ARABIC MATHEMATICAL INITIAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;\n1EE24;ARABIC MATHEMATICAL INITIAL HEH;Lo;0;AL;<font> 0647;;;;N;;;;;\n1EE27;ARABIC MATHEMATICAL INITIAL HAH;Lo;0;AL;<font> 062D;;;;N;;;;;\n1EE29;ARABIC MATHEMATICAL INITIAL YEH;Lo;0;AL;<font> 064A;;;;N;;;;;\n1EE2A;ARABIC MATHEMATICAL INITIAL KAF;Lo;0;AL;<font> 0643;;;;N;;;;;\n1EE2B;ARABIC MATHEMATICAL INITIAL LAM;Lo;0;AL;<font> 0644;;;;N;;;;;\n1EE2C;ARABIC MATHEMATICAL INITIAL MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;\n1EE2D;ARABIC MATHEMATICAL INITIAL NOON;Lo;0;AL;<font> 0646;;;;N;;;;;\n1EE2E;ARABIC MATHEMATICAL INITIAL SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;\n1EE2F;ARABIC MATHEMATICAL INITIAL AIN;Lo;0;AL;<font> 0639;;;;N;;;;;\n1EE30;ARABIC MATHEMATICAL INITIAL FEH;Lo;0;AL;<font> 0641;;;;N;;;;;\n1EE31;ARABIC MATHEMATICAL INITIAL SAD;Lo;0;AL;<font> 0635;;;;N;;;;;\n1EE32;ARABIC MATHEMATICAL INITIAL QAF;Lo;0;AL;<font> 0642;;;;N;;;;;\n1EE34;ARABIC MATHEMATICAL INITIAL SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;\n1EE35;ARABIC MATHEMATICAL INITIAL TEH;Lo;0;AL;<font> 062A;;;;N;;;;;\n1EE36;ARABIC MATHEMATICAL INITIAL THEH;Lo;0;AL;<font> 062B;;;;N;;;;;\n1EE37;ARABIC MATHEMATICAL INITIAL KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;\n1EE39;ARABIC MATHEMATICAL INITIAL DAD;Lo;0;AL;<font> 0636;;;;N;;;;;\n1EE3B;ARABIC MATHEMATICAL INITIAL GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;\n1EE42;ARABIC MATHEMATICAL TAILED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;\n1EE47;ARABIC MATHEMATICAL TAILED HAH;Lo;0;AL;<font> 062D;;;;N;;;;;\n1EE49;ARABIC MATHEMATICAL TAILED YEH;Lo;0;AL;<font> 064A;;;;N;;;;;\n1EE4B;ARABIC MATHEMATICAL TAILED LAM;Lo;0;AL;<font> 0644;;;;N;;;;;\n1EE4D;ARABIC MATHEMATICAL TAILED NOON;Lo;0;AL;<font> 0646;;;;N;;;;;\n1EE4E;ARABIC MATHEMATICAL TAILED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;\n1EE4F;ARABIC MATHEMATICAL TAILED AIN;Lo;0;AL;<font> 0639;;;;N;;;;;\n1EE51;ARABIC MATHEMATICAL TAILED SAD;Lo;0;AL;<font> 0635;;;;N;;;;;\n1EE52;ARABIC MATHEMATICAL TAILED QAF;Lo;0;AL;<font> 0642;;;;N;;;;;\n1EE54;ARABIC MATHEMATICAL TAILED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;\n1EE57;ARABIC MATHEMATICAL TAILED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;\n1EE59;ARABIC MATHEMATICAL TAILED DAD;Lo;0;AL;<font> 0636;;;;N;;;;;\n1EE5B;ARABIC MATHEMATICAL TAILED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;\n1EE5D;ARABIC MATHEMATICAL TAILED DOTLESS NOON;Lo;0;AL;<font> 06BA;;;;N;;;;;\n1EE5F;ARABIC MATHEMATICAL TAILED DOTLESS QAF;Lo;0;AL;<font> 066F;;;;N;;;;;\n1EE61;ARABIC MATHEMATICAL STRETCHED BEH;Lo;0;AL;<font> 0628;;;;N;;;;;\n1EE62;ARABIC MATHEMATICAL STRETCHED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;\n1EE64;ARABIC MATHEMATICAL STRETCHED HEH;Lo;0;AL;<font> 0647;;;;N;;;;;\n1EE67;ARABIC MATHEMATICAL STRETCHED HAH;Lo;0;AL;<font> 062D;;;;N;;;;;\n1EE68;ARABIC MATHEMATICAL STRETCHED TAH;Lo;0;AL;<font> 0637;;;;N;;;;;\n1EE69;ARABIC MATHEMATICAL STRETCHED YEH;Lo;0;AL;<font> 064A;;;;N;;;;;\n1EE6A;ARABIC MATHEMATICAL STRETCHED KAF;Lo;0;AL;<font> 0643;;;;N;;;;;\n1EE6C;ARABIC MATHEMATICAL STRETCHED MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;\n1EE6D;ARABIC MATHEMATICAL STRETCHED NOON;Lo;0;AL;<font> 0646;;;;N;;;;;\n1EE6E;ARABIC MATHEMATICAL STRETCHED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;\n1EE6F;ARABIC MATHEMATICAL STRETCHED AIN;Lo;0;AL;<font> 0639;;;;N;;;;;\n1EE70;ARABIC MATHEMATICAL STRETCHED FEH;Lo;0;AL;<font> 0641;;;;N;;;;;\n1EE71;ARABIC MATHEMATICAL STRETCHED SAD;Lo;0;AL;<font> 0635;;;;N;;;;;\n1EE72;ARABIC MATHEMATICAL STRETCHED QAF;Lo;0;AL;<font> 0642;;;;N;;;;;\n1EE74;ARABIC MATHEMATICAL STRETCHED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;\n1EE75;ARABIC MATHEMATICAL STRETCHED TEH;Lo;0;AL;<font> 062A;;;;N;;;;;\n1EE76;ARABIC MATHEMATICAL STRETCHED THEH;Lo;0;AL;<font> 062B;;;;N;;;;;\n1EE77;ARABIC MATHEMATICAL STRETCHED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;\n1EE79;ARABIC MATHEMATICAL STRETCHED DAD;Lo;0;AL;<font> 0636;;;;N;;;;;\n1EE7A;ARABIC MATHEMATICAL STRETCHED ZAH;Lo;0;AL;<font> 0638;;;;N;;;;;\n1EE7B;ARABIC MATHEMATICAL STRETCHED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;\n1EE7C;ARABIC MATHEMATICAL STRETCHED DOTLESS BEH;Lo;0;AL;<font> 066E;;;;N;;;;;\n1EE7E;ARABIC MATHEMATICAL STRETCHED DOTLESS FEH;Lo;0;AL;<font> 06A1;;;;N;;;;;\n1EE80;ARABIC MATHEMATICAL LOOPED ALEF;Lo;0;AL;<font> 0627;;;;N;;;;;\n1EE81;ARABIC MATHEMATICAL LOOPED BEH;Lo;0;AL;<font> 0628;;;;N;;;;;\n1EE82;ARABIC MATHEMATICAL LOOPED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;\n1EE83;ARABIC MATHEMATICAL LOOPED DAL;Lo;0;AL;<font> 062F;;;;N;;;;;\n1EE84;ARABIC MATHEMATICAL LOOPED HEH;Lo;0;AL;<font> 0647;;;;N;;;;;\n1EE85;ARABIC MATHEMATICAL LOOPED WAW;Lo;0;AL;<font> 0648;;;;N;;;;;\n1EE86;ARABIC MATHEMATICAL LOOPED ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;;\n1EE87;ARABIC MATHEMATICAL LOOPED HAH;Lo;0;AL;<font> 062D;;;;N;;;;;\n1EE88;ARABIC MATHEMATICAL LOOPED TAH;Lo;0;AL;<font> 0637;;;;N;;;;;\n1EE89;ARABIC MATHEMATICAL LOOPED YEH;Lo;0;AL;<font> 064A;;;;N;;;;;\n1EE8B;ARABIC MATHEMATICAL LOOPED LAM;Lo;0;AL;<font> 0644;;;;N;;;;;\n1EE8C;ARABIC MATHEMATICAL LOOPED MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;\n1EE8D;ARABIC MATHEMATICAL LOOPED NOON;Lo;0;AL;<font> 0646;;;;N;;;;;\n1EE8E;ARABIC MATHEMATICAL LOOPED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;\n1EE8F;ARABIC MATHEMATICAL LOOPED AIN;Lo;0;AL;<font> 0639;;;;N;;;;;\n1EE90;ARABIC MATHEMATICAL LOOPED FEH;Lo;0;AL;<font> 0641;;;;N;;;;;\n1EE91;ARABIC MATHEMATICAL LOOPED SAD;Lo;0;AL;<font> 0635;;;;N;;;;;\n1EE92;ARABIC MATHEMATICAL LOOPED QAF;Lo;0;AL;<font> 0642;;;;N;;;;;\n1EE93;ARABIC MATHEMATICAL LOOPED REH;Lo;0;AL;<font> 0631;;;;N;;;;;\n1EE94;ARABIC MATHEMATICAL LOOPED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;\n1EE95;ARABIC MATHEMATICAL LOOPED TEH;Lo;0;AL;<font> 062A;;;;N;;;;;\n1EE96;ARABIC MATHEMATICAL LOOPED THEH;Lo;0;AL;<font> 062B;;;;N;;;;;\n1EE97;ARABIC MATHEMATICAL LOOPED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;\n1EE98;ARABIC MATHEMATICAL LOOPED THAL;Lo;0;AL;<font> 0630;;;;N;;;;;\n1EE99;ARABIC MATHEMATICAL LOOPED DAD;Lo;0;AL;<font> 0636;;;;N;;;;;\n1EE9A;ARABIC MATHEMATICAL LOOPED ZAH;Lo;0;AL;<font> 0638;;;;N;;;;;\n1EE9B;ARABIC MATHEMATICAL LOOPED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;\n1EEA1;ARABIC MATHEMATICAL DOUBLE-STRUCK BEH;Lo;0;AL;<font> 0628;;;;N;;;;;\n1EEA2;ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;\n1EEA3;ARABIC MATHEMATICAL DOUBLE-STRUCK DAL;Lo;0;AL;<font> 062F;;;;N;;;;;\n1EEA5;ARABIC MATHEMATICAL DOUBLE-STRUCK WAW;Lo;0;AL;<font> 0648;;;;N;;;;;\n1EEA6;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;;\n1EEA7;ARABIC MATHEMATICAL DOUBLE-STRUCK HAH;Lo;0;AL;<font> 062D;;;;N;;;;;\n1EEA8;ARABIC MATHEMATICAL DOUBLE-STRUCK TAH;Lo;0;AL;<font> 0637;;;;N;;;;;\n1EEA9;ARABIC MATHEMATICAL DOUBLE-STRUCK YEH;Lo;0;AL;<font> 064A;;;;N;;;;;\n1EEAB;ARABIC MATHEMATICAL DOUBLE-STRUCK LAM;Lo;0;AL;<font> 0644;;;;N;;;;;\n1EEAC;ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;\n1EEAD;ARABIC MATHEMATICAL DOUBLE-STRUCK NOON;Lo;0;AL;<font> 0646;;;;N;;;;;\n1EEAE;ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;\n1EEAF;ARABIC MATHEMATICAL DOUBLE-STRUCK AIN;Lo;0;AL;<font> 0639;;;;N;;;;;\n1EEB0;ARABIC MATHEMATICAL DOUBLE-STRUCK FEH;Lo;0;AL;<font> 0641;;;;N;;;;;\n1EEB1;ARABIC MATHEMATICAL DOUBLE-STRUCK SAD;Lo;0;AL;<font> 0635;;;;N;;;;;\n1EEB2;ARABIC MATHEMATICAL DOUBLE-STRUCK QAF;Lo;0;AL;<font> 0642;;;;N;;;;;\n1EEB3;ARABIC MATHEMATICAL DOUBLE-STRUCK REH;Lo;0;AL;<font> 0631;;;;N;;;;;\n1EEB4;ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;\n1EEB5;ARABIC MATHEMATICAL DOUBLE-STRUCK TEH;Lo;0;AL;<font> 062A;;;;N;;;;;\n1EEB6;ARABIC MATHEMATICAL DOUBLE-STRUCK THEH;Lo;0;AL;<font> 062B;;;;N;;;;;\n1EEB7;ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;\n1EEB8;ARABIC MATHEMATICAL DOUBLE-STRUCK THAL;Lo;0;AL;<font> 0630;;;;N;;;;;\n1EEB9;ARABIC MATHEMATICAL DOUBLE-STRUCK DAD;Lo;0;AL;<font> 0636;;;;N;;;;;\n1EEBA;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH;Lo;0;AL;<font> 0638;;;;N;;;;;\n1EEBB;ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;\n1EEF0;ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL;Sm;0;ON;;;;;N;;;;;\n1EEF1;ARABIC MATHEMATICAL OPERATOR HAH WITH DAL;Sm;0;ON;;;;;N;;;;;\n1F000;MAHJONG TILE EAST WIND;So;0;ON;;;;;N;;;;;\n1F001;MAHJONG TILE SOUTH WIND;So;0;ON;;;;;N;;;;;\n1F002;MAHJONG TILE WEST WIND;So;0;ON;;;;;N;;;;;\n1F003;MAHJONG TILE NORTH WIND;So;0;ON;;;;;N;;;;;\n1F004;MAHJONG TILE RED DRAGON;So;0;ON;;;;;N;;;;;\n1F005;MAHJONG TILE GREEN DRAGON;So;0;ON;;;;;N;;;;;\n1F006;MAHJONG TILE WHITE DRAGON;So;0;ON;;;;;N;;;;;\n1F007;MAHJONG TILE ONE OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F008;MAHJONG TILE TWO OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F009;MAHJONG TILE THREE OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F00A;MAHJONG TILE FOUR OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F00B;MAHJONG TILE FIVE OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F00C;MAHJONG TILE SIX OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F00D;MAHJONG TILE SEVEN OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F00E;MAHJONG TILE EIGHT OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F00F;MAHJONG TILE NINE OF CHARACTERS;So;0;ON;;;;;N;;;;;\n1F010;MAHJONG TILE ONE OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F011;MAHJONG TILE TWO OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F012;MAHJONG TILE THREE OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F013;MAHJONG TILE FOUR OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F014;MAHJONG TILE FIVE OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F015;MAHJONG TILE SIX OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F016;MAHJONG TILE SEVEN OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F017;MAHJONG TILE EIGHT OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F018;MAHJONG TILE NINE OF BAMBOOS;So;0;ON;;;;;N;;;;;\n1F019;MAHJONG TILE ONE OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F01A;MAHJONG TILE TWO OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F01B;MAHJONG TILE THREE OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F01C;MAHJONG TILE FOUR OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F01D;MAHJONG TILE FIVE OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F01E;MAHJONG TILE SIX OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F01F;MAHJONG TILE SEVEN OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F020;MAHJONG TILE EIGHT OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F021;MAHJONG TILE NINE OF CIRCLES;So;0;ON;;;;;N;;;;;\n1F022;MAHJONG TILE PLUM;So;0;ON;;;;;N;;;;;\n1F023;MAHJONG TILE ORCHID;So;0;ON;;;;;N;;;;;\n1F024;MAHJONG TILE BAMBOO;So;0;ON;;;;;N;;;;;\n1F025;MAHJONG TILE CHRYSANTHEMUM;So;0;ON;;;;;N;;;;;\n1F026;MAHJONG TILE SPRING;So;0;ON;;;;;N;;;;;\n1F027;MAHJONG TILE SUMMER;So;0;ON;;;;;N;;;;;\n1F028;MAHJONG TILE AUTUMN;So;0;ON;;;;;N;;;;;\n1F029;MAHJONG TILE WINTER;So;0;ON;;;;;N;;;;;\n1F02A;MAHJONG TILE JOKER;So;0;ON;;;;;N;;;;;\n1F02B;MAHJONG TILE BACK;So;0;ON;;;;;N;;;;;\n1F030;DOMINO TILE HORIZONTAL BACK;So;0;ON;;;;;N;;;;;\n1F031;DOMINO TILE HORIZONTAL-00-00;So;0;ON;;;;;N;;;;;\n1F032;DOMINO TILE HORIZONTAL-00-01;So;0;ON;;;;;N;;;;;\n1F033;DOMINO TILE HORIZONTAL-00-02;So;0;ON;;;;;N;;;;;\n1F034;DOMINO TILE HORIZONTAL-00-03;So;0;ON;;;;;N;;;;;\n1F035;DOMINO TILE HORIZONTAL-00-04;So;0;ON;;;;;N;;;;;\n1F036;DOMINO TILE HORIZONTAL-00-05;So;0;ON;;;;;N;;;;;\n1F037;DOMINO TILE HORIZONTAL-00-06;So;0;ON;;;;;N;;;;;\n1F038;DOMINO TILE HORIZONTAL-01-00;So;0;ON;;;;;N;;;;;\n1F039;DOMINO TILE HORIZONTAL-01-01;So;0;ON;;;;;N;;;;;\n1F03A;DOMINO TILE HORIZONTAL-01-02;So;0;ON;;;;;N;;;;;\n1F03B;DOMINO TILE HORIZONTAL-01-03;So;0;ON;;;;;N;;;;;\n1F03C;DOMINO TILE HORIZONTAL-01-04;So;0;ON;;;;;N;;;;;\n1F03D;DOMINO TILE HORIZONTAL-01-05;So;0;ON;;;;;N;;;;;\n1F03E;DOMINO TILE HORIZONTAL-01-06;So;0;ON;;;;;N;;;;;\n1F03F;DOMINO TILE HORIZONTAL-02-00;So;0;ON;;;;;N;;;;;\n1F040;DOMINO TILE HORIZONTAL-02-01;So;0;ON;;;;;N;;;;;\n1F041;DOMINO TILE HORIZONTAL-02-02;So;0;ON;;;;;N;;;;;\n1F042;DOMINO TILE HORIZONTAL-02-03;So;0;ON;;;;;N;;;;;\n1F043;DOMINO TILE HORIZONTAL-02-04;So;0;ON;;;;;N;;;;;\n1F044;DOMINO TILE HORIZONTAL-02-05;So;0;ON;;;;;N;;;;;\n1F045;DOMINO TILE HORIZONTAL-02-06;So;0;ON;;;;;N;;;;;\n1F046;DOMINO TILE HORIZONTAL-03-00;So;0;ON;;;;;N;;;;;\n1F047;DOMINO TILE HORIZONTAL-03-01;So;0;ON;;;;;N;;;;;\n1F048;DOMINO TILE HORIZONTAL-03-02;So;0;ON;;;;;N;;;;;\n1F049;DOMINO TILE HORIZONTAL-03-03;So;0;ON;;;;;N;;;;;\n1F04A;DOMINO TILE HORIZONTAL-03-04;So;0;ON;;;;;N;;;;;\n1F04B;DOMINO TILE HORIZONTAL-03-05;So;0;ON;;;;;N;;;;;\n1F04C;DOMINO TILE HORIZONTAL-03-06;So;0;ON;;;;;N;;;;;\n1F04D;DOMINO TILE HORIZONTAL-04-00;So;0;ON;;;;;N;;;;;\n1F04E;DOMINO TILE HORIZONTAL-04-01;So;0;ON;;;;;N;;;;;\n1F04F;DOMINO TILE HORIZONTAL-04-02;So;0;ON;;;;;N;;;;;\n1F050;DOMINO TILE HORIZONTAL-04-03;So;0;ON;;;;;N;;;;;\n1F051;DOMINO TILE HORIZONTAL-04-04;So;0;ON;;;;;N;;;;;\n1F052;DOMINO TILE HORIZONTAL-04-05;So;0;ON;;;;;N;;;;;\n1F053;DOMINO TILE HORIZONTAL-04-06;So;0;ON;;;;;N;;;;;\n1F054;DOMINO TILE HORIZONTAL-05-00;So;0;ON;;;;;N;;;;;\n1F055;DOMINO TILE HORIZONTAL-05-01;So;0;ON;;;;;N;;;;;\n1F056;DOMINO TILE HORIZONTAL-05-02;So;0;ON;;;;;N;;;;;\n1F057;DOMINO TILE HORIZONTAL-05-03;So;0;ON;;;;;N;;;;;\n1F058;DOMINO TILE HORIZONTAL-05-04;So;0;ON;;;;;N;;;;;\n1F059;DOMINO TILE HORIZONTAL-05-05;So;0;ON;;;;;N;;;;;\n1F05A;DOMINO TILE HORIZONTAL-05-06;So;0;ON;;;;;N;;;;;\n1F05B;DOMINO TILE HORIZONTAL-06-00;So;0;ON;;;;;N;;;;;\n1F05C;DOMINO TILE HORIZONTAL-06-01;So;0;ON;;;;;N;;;;;\n1F05D;DOMINO TILE HORIZONTAL-06-02;So;0;ON;;;;;N;;;;;\n1F05E;DOMINO TILE HORIZONTAL-06-03;So;0;ON;;;;;N;;;;;\n1F05F;DOMINO TILE HORIZONTAL-06-04;So;0;ON;;;;;N;;;;;\n1F060;DOMINO TILE HORIZONTAL-06-05;So;0;ON;;;;;N;;;;;\n1F061;DOMINO TILE HORIZONTAL-06-06;So;0;ON;;;;;N;;;;;\n1F062;DOMINO TILE VERTICAL BACK;So;0;ON;;;;;N;;;;;\n1F063;DOMINO TILE VERTICAL-00-00;So;0;ON;;;;;N;;;;;\n1F064;DOMINO TILE VERTICAL-00-01;So;0;ON;;;;;N;;;;;\n1F065;DOMINO TILE VERTICAL-00-02;So;0;ON;;;;;N;;;;;\n1F066;DOMINO TILE VERTICAL-00-03;So;0;ON;;;;;N;;;;;\n1F067;DOMINO TILE VERTICAL-00-04;So;0;ON;;;;;N;;;;;\n1F068;DOMINO TILE VERTICAL-00-05;So;0;ON;;;;;N;;;;;\n1F069;DOMINO TILE VERTICAL-00-06;So;0;ON;;;;;N;;;;;\n1F06A;DOMINO TILE VERTICAL-01-00;So;0;ON;;;;;N;;;;;\n1F06B;DOMINO TILE VERTICAL-01-01;So;0;ON;;;;;N;;;;;\n1F06C;DOMINO TILE VERTICAL-01-02;So;0;ON;;;;;N;;;;;\n1F06D;DOMINO TILE VERTICAL-01-03;So;0;ON;;;;;N;;;;;\n1F06E;DOMINO TILE VERTICAL-01-04;So;0;ON;;;;;N;;;;;\n1F06F;DOMINO TILE VERTICAL-01-05;So;0;ON;;;;;N;;;;;\n1F070;DOMINO TILE VERTICAL-01-06;So;0;ON;;;;;N;;;;;\n1F071;DOMINO TILE VERTICAL-02-00;So;0;ON;;;;;N;;;;;\n1F072;DOMINO TILE VERTICAL-02-01;So;0;ON;;;;;N;;;;;\n1F073;DOMINO TILE VERTICAL-02-02;So;0;ON;;;;;N;;;;;\n1F074;DOMINO TILE VERTICAL-02-03;So;0;ON;;;;;N;;;;;\n1F075;DOMINO TILE VERTICAL-02-04;So;0;ON;;;;;N;;;;;\n1F076;DOMINO TILE VERTICAL-02-05;So;0;ON;;;;;N;;;;;\n1F077;DOMINO TILE VERTICAL-02-06;So;0;ON;;;;;N;;;;;\n1F078;DOMINO TILE VERTICAL-03-00;So;0;ON;;;;;N;;;;;\n1F079;DOMINO TILE VERTICAL-03-01;So;0;ON;;;;;N;;;;;\n1F07A;DOMINO TILE VERTICAL-03-02;So;0;ON;;;;;N;;;;;\n1F07B;DOMINO TILE VERTICAL-03-03;So;0;ON;;;;;N;;;;;\n1F07C;DOMINO TILE VERTICAL-03-04;So;0;ON;;;;;N;;;;;\n1F07D;DOMINO TILE VERTICAL-03-05;So;0;ON;;;;;N;;;;;\n1F07E;DOMINO TILE VERTICAL-03-06;So;0;ON;;;;;N;;;;;\n1F07F;DOMINO TILE VERTICAL-04-00;So;0;ON;;;;;N;;;;;\n1F080;DOMINO TILE VERTICAL-04-01;So;0;ON;;;;;N;;;;;\n1F081;DOMINO TILE VERTICAL-04-02;So;0;ON;;;;;N;;;;;\n1F082;DOMINO TILE VERTICAL-04-03;So;0;ON;;;;;N;;;;;\n1F083;DOMINO TILE VERTICAL-04-04;So;0;ON;;;;;N;;;;;\n1F084;DOMINO TILE VERTICAL-04-05;So;0;ON;;;;;N;;;;;\n1F085;DOMINO TILE VERTICAL-04-06;So;0;ON;;;;;N;;;;;\n1F086;DOMINO TILE VERTICAL-05-00;So;0;ON;;;;;N;;;;;\n1F087;DOMINO TILE VERTICAL-05-01;So;0;ON;;;;;N;;;;;\n1F088;DOMINO TILE VERTICAL-05-02;So;0;ON;;;;;N;;;;;\n1F089;DOMINO TILE VERTICAL-05-03;So;0;ON;;;;;N;;;;;\n1F08A;DOMINO TILE VERTICAL-05-04;So;0;ON;;;;;N;;;;;\n1F08B;DOMINO TILE VERTICAL-05-05;So;0;ON;;;;;N;;;;;\n1F08C;DOMINO TILE VERTICAL-05-06;So;0;ON;;;;;N;;;;;\n1F08D;DOMINO TILE VERTICAL-06-00;So;0;ON;;;;;N;;;;;\n1F08E;DOMINO TILE VERTICAL-06-01;So;0;ON;;;;;N;;;;;\n1F08F;DOMINO TILE VERTICAL-06-02;So;0;ON;;;;;N;;;;;\n1F090;DOMINO TILE VERTICAL-06-03;So;0;ON;;;;;N;;;;;\n1F091;DOMINO TILE VERTICAL-06-04;So;0;ON;;;;;N;;;;;\n1F092;DOMINO TILE VERTICAL-06-05;So;0;ON;;;;;N;;;;;\n1F093;DOMINO TILE VERTICAL-06-06;So;0;ON;;;;;N;;;;;\n1F0A0;PLAYING CARD BACK;So;0;ON;;;;;N;;;;;\n1F0A1;PLAYING CARD ACE OF SPADES;So;0;ON;;;;;N;;;;;\n1F0A2;PLAYING CARD TWO OF SPADES;So;0;ON;;;;;N;;;;;\n1F0A3;PLAYING CARD THREE OF SPADES;So;0;ON;;;;;N;;;;;\n1F0A4;PLAYING CARD FOUR OF SPADES;So;0;ON;;;;;N;;;;;\n1F0A5;PLAYING CARD FIVE OF SPADES;So;0;ON;;;;;N;;;;;\n1F0A6;PLAYING CARD SIX OF SPADES;So;0;ON;;;;;N;;;;;\n1F0A7;PLAYING CARD SEVEN OF SPADES;So;0;ON;;;;;N;;;;;\n1F0A8;PLAYING CARD EIGHT OF SPADES;So;0;ON;;;;;N;;;;;\n1F0A9;PLAYING CARD NINE OF SPADES;So;0;ON;;;;;N;;;;;\n1F0AA;PLAYING CARD TEN OF SPADES;So;0;ON;;;;;N;;;;;\n1F0AB;PLAYING CARD JACK OF SPADES;So;0;ON;;;;;N;;;;;\n1F0AC;PLAYING CARD KNIGHT OF SPADES;So;0;ON;;;;;N;;;;;\n1F0AD;PLAYING CARD QUEEN OF SPADES;So;0;ON;;;;;N;;;;;\n1F0AE;PLAYING CARD KING OF SPADES;So;0;ON;;;;;N;;;;;\n1F0B1;PLAYING CARD ACE OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0B2;PLAYING CARD TWO OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0B3;PLAYING CARD THREE OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0B4;PLAYING CARD FOUR OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0B5;PLAYING CARD FIVE OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0B6;PLAYING CARD SIX OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0B7;PLAYING CARD SEVEN OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0B8;PLAYING CARD EIGHT OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0B9;PLAYING CARD NINE OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0BA;PLAYING CARD TEN OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0BB;PLAYING CARD JACK OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0BC;PLAYING CARD KNIGHT OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0BD;PLAYING CARD QUEEN OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0BE;PLAYING CARD KING OF HEARTS;So;0;ON;;;;;N;;;;;\n1F0BF;PLAYING CARD RED JOKER;So;0;ON;;;;;N;;;;;\n1F0C1;PLAYING CARD ACE OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0C2;PLAYING CARD TWO OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0C3;PLAYING CARD THREE OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0C4;PLAYING CARD FOUR OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0C5;PLAYING CARD FIVE OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0C6;PLAYING CARD SIX OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0C7;PLAYING CARD SEVEN OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0C8;PLAYING CARD EIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0C9;PLAYING CARD NINE OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0CA;PLAYING CARD TEN OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0CB;PLAYING CARD JACK OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0CC;PLAYING CARD KNIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0CD;PLAYING CARD QUEEN OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0CE;PLAYING CARD KING OF DIAMONDS;So;0;ON;;;;;N;;;;;\n1F0CF;PLAYING CARD BLACK JOKER;So;0;ON;;;;;N;;;;;\n1F0D1;PLAYING CARD ACE OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0D2;PLAYING CARD TWO OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0D3;PLAYING CARD THREE OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0D4;PLAYING CARD FOUR OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0D5;PLAYING CARD FIVE OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0D6;PLAYING CARD SIX OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0D7;PLAYING CARD SEVEN OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0D8;PLAYING CARD EIGHT OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0D9;PLAYING CARD NINE OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0DA;PLAYING CARD TEN OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0DB;PLAYING CARD JACK OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0DC;PLAYING CARD KNIGHT OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0DD;PLAYING CARD QUEEN OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0DE;PLAYING CARD KING OF CLUBS;So;0;ON;;;;;N;;;;;\n1F0DF;PLAYING CARD WHITE JOKER;So;0;ON;;;;;N;;;;;\n1F0E0;PLAYING CARD FOOL;So;0;ON;;;;;N;;;;;\n1F0E1;PLAYING CARD TRUMP-1;So;0;ON;;;;;N;;;;;\n1F0E2;PLAYING CARD TRUMP-2;So;0;ON;;;;;N;;;;;\n1F0E3;PLAYING CARD TRUMP-3;So;0;ON;;;;;N;;;;;\n1F0E4;PLAYING CARD TRUMP-4;So;0;ON;;;;;N;;;;;\n1F0E5;PLAYING CARD TRUMP-5;So;0;ON;;;;;N;;;;;\n1F0E6;PLAYING CARD TRUMP-6;So;0;ON;;;;;N;;;;;\n1F0E7;PLAYING CARD TRUMP-7;So;0;ON;;;;;N;;;;;\n1F0E8;PLAYING CARD TRUMP-8;So;0;ON;;;;;N;;;;;\n1F0E9;PLAYING CARD TRUMP-9;So;0;ON;;;;;N;;;;;\n1F0EA;PLAYING CARD TRUMP-10;So;0;ON;;;;;N;;;;;\n1F0EB;PLAYING CARD TRUMP-11;So;0;ON;;;;;N;;;;;\n1F0EC;PLAYING CARD TRUMP-12;So;0;ON;;;;;N;;;;;\n1F0ED;PLAYING CARD TRUMP-13;So;0;ON;;;;;N;;;;;\n1F0EE;PLAYING CARD TRUMP-14;So;0;ON;;;;;N;;;;;\n1F0EF;PLAYING CARD TRUMP-15;So;0;ON;;;;;N;;;;;\n1F0F0;PLAYING CARD TRUMP-16;So;0;ON;;;;;N;;;;;\n1F0F1;PLAYING CARD TRUMP-17;So;0;ON;;;;;N;;;;;\n1F0F2;PLAYING CARD TRUMP-18;So;0;ON;;;;;N;;;;;\n1F0F3;PLAYING CARD TRUMP-19;So;0;ON;;;;;N;;;;;\n1F0F4;PLAYING CARD TRUMP-20;So;0;ON;;;;;N;;;;;\n1F0F5;PLAYING CARD TRUMP-21;So;0;ON;;;;;N;;;;;\n1F100;DIGIT ZERO FULL STOP;No;0;EN;<compat> 0030 002E;;0;0;N;;;;;\n1F101;DIGIT ZERO COMMA;No;0;EN;<compat> 0030 002C;;0;0;N;;;;;\n1F102;DIGIT ONE COMMA;No;0;EN;<compat> 0031 002C;;1;1;N;;;;;\n1F103;DIGIT TWO COMMA;No;0;EN;<compat> 0032 002C;;2;2;N;;;;;\n1F104;DIGIT THREE COMMA;No;0;EN;<compat> 0033 002C;;3;3;N;;;;;\n1F105;DIGIT FOUR COMMA;No;0;EN;<compat> 0034 002C;;4;4;N;;;;;\n1F106;DIGIT FIVE COMMA;No;0;EN;<compat> 0035 002C;;5;5;N;;;;;\n1F107;DIGIT SIX COMMA;No;0;EN;<compat> 0036 002C;;6;6;N;;;;;\n1F108;DIGIT SEVEN COMMA;No;0;EN;<compat> 0037 002C;;7;7;N;;;;;\n1F109;DIGIT EIGHT COMMA;No;0;EN;<compat> 0038 002C;;8;8;N;;;;;\n1F10A;DIGIT NINE COMMA;No;0;EN;<compat> 0039 002C;;9;9;N;;;;;\n1F10B;DINGBAT CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;;\n1F10C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;;\n1F10D;CIRCLED ZERO WITH SLASH;So;0;ON;;;;;N;;;;;\n1F10E;CIRCLED ANTICLOCKWISE ARROW;So;0;ON;;;;;N;;;;;\n1F10F;CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH;So;0;ON;;;;;N;;;;;\n1F110;PARENTHESIZED LATIN CAPITAL LETTER A;So;0;L;<compat> 0028 0041 0029;;;;N;;;;;\n1F111;PARENTHESIZED LATIN CAPITAL LETTER B;So;0;L;<compat> 0028 0042 0029;;;;N;;;;;\n1F112;PARENTHESIZED LATIN CAPITAL LETTER C;So;0;L;<compat> 0028 0043 0029;;;;N;;;;;\n1F113;PARENTHESIZED LATIN CAPITAL LETTER D;So;0;L;<compat> 0028 0044 0029;;;;N;;;;;\n1F114;PARENTHESIZED LATIN CAPITAL LETTER E;So;0;L;<compat> 0028 0045 0029;;;;N;;;;;\n1F115;PARENTHESIZED LATIN CAPITAL LETTER F;So;0;L;<compat> 0028 0046 0029;;;;N;;;;;\n1F116;PARENTHESIZED LATIN CAPITAL LETTER G;So;0;L;<compat> 0028 0047 0029;;;;N;;;;;\n1F117;PARENTHESIZED LATIN CAPITAL LETTER H;So;0;L;<compat> 0028 0048 0029;;;;N;;;;;\n1F118;PARENTHESIZED LATIN CAPITAL LETTER I;So;0;L;<compat> 0028 0049 0029;;;;N;;;;;\n1F119;PARENTHESIZED LATIN CAPITAL LETTER J;So;0;L;<compat> 0028 004A 0029;;;;N;;;;;\n1F11A;PARENTHESIZED LATIN CAPITAL LETTER K;So;0;L;<compat> 0028 004B 0029;;;;N;;;;;\n1F11B;PARENTHESIZED LATIN CAPITAL LETTER L;So;0;L;<compat> 0028 004C 0029;;;;N;;;;;\n1F11C;PARENTHESIZED LATIN CAPITAL LETTER M;So;0;L;<compat> 0028 004D 0029;;;;N;;;;;\n1F11D;PARENTHESIZED LATIN CAPITAL LETTER N;So;0;L;<compat> 0028 004E 0029;;;;N;;;;;\n1F11E;PARENTHESIZED LATIN CAPITAL LETTER O;So;0;L;<compat> 0028 004F 0029;;;;N;;;;;\n1F11F;PARENTHESIZED LATIN CAPITAL LETTER P;So;0;L;<compat> 0028 0050 0029;;;;N;;;;;\n1F120;PARENTHESIZED LATIN CAPITAL LETTER Q;So;0;L;<compat> 0028 0051 0029;;;;N;;;;;\n1F121;PARENTHESIZED LATIN CAPITAL LETTER R;So;0;L;<compat> 0028 0052 0029;;;;N;;;;;\n1F122;PARENTHESIZED LATIN CAPITAL LETTER S;So;0;L;<compat> 0028 0053 0029;;;;N;;;;;\n1F123;PARENTHESIZED LATIN CAPITAL LETTER T;So;0;L;<compat> 0028 0054 0029;;;;N;;;;;\n1F124;PARENTHESIZED LATIN CAPITAL LETTER U;So;0;L;<compat> 0028 0055 0029;;;;N;;;;;\n1F125;PARENTHESIZED LATIN CAPITAL LETTER V;So;0;L;<compat> 0028 0056 0029;;;;N;;;;;\n1F126;PARENTHESIZED LATIN CAPITAL LETTER W;So;0;L;<compat> 0028 0057 0029;;;;N;;;;;\n1F127;PARENTHESIZED LATIN CAPITAL LETTER X;So;0;L;<compat> 0028 0058 0029;;;;N;;;;;\n1F128;PARENTHESIZED LATIN CAPITAL LETTER Y;So;0;L;<compat> 0028 0059 0029;;;;N;;;;;\n1F129;PARENTHESIZED LATIN CAPITAL LETTER Z;So;0;L;<compat> 0028 005A 0029;;;;N;;;;;\n1F12A;TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S;So;0;L;<compat> 3014 0053 3015;;;;N;;;;;\n1F12B;CIRCLED ITALIC LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;;\n1F12C;CIRCLED ITALIC LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;;\n1F12D;CIRCLED CD;So;0;L;<circle> 0043 0044;;;;N;;;;;\n1F12E;CIRCLED WZ;So;0;L;<circle> 0057 005A;;;;N;;;;;\n1F12F;COPYLEFT SYMBOL;So;0;ON;;;;;N;;;;;\n1F130;SQUARED LATIN CAPITAL LETTER A;So;0;L;<square> 0041;;;;N;;;;;\n1F131;SQUARED LATIN CAPITAL LETTER B;So;0;L;<square> 0042;;;;N;;;;;\n1F132;SQUARED LATIN CAPITAL LETTER C;So;0;L;<square> 0043;;;;N;;;;;\n1F133;SQUARED LATIN CAPITAL LETTER D;So;0;L;<square> 0044;;;;N;;;;;\n1F134;SQUARED LATIN CAPITAL LETTER E;So;0;L;<square> 0045;;;;N;;;;;\n1F135;SQUARED LATIN CAPITAL LETTER F;So;0;L;<square> 0046;;;;N;;;;;\n1F136;SQUARED LATIN CAPITAL LETTER G;So;0;L;<square> 0047;;;;N;;;;;\n1F137;SQUARED LATIN CAPITAL LETTER H;So;0;L;<square> 0048;;;;N;;;;;\n1F138;SQUARED LATIN CAPITAL LETTER I;So;0;L;<square> 0049;;;;N;;;;;\n1F139;SQUARED LATIN CAPITAL LETTER J;So;0;L;<square> 004A;;;;N;;;;;\n1F13A;SQUARED LATIN CAPITAL LETTER K;So;0;L;<square> 004B;;;;N;;;;;\n1F13B;SQUARED LATIN CAPITAL LETTER L;So;0;L;<square> 004C;;;;N;;;;;\n1F13C;SQUARED LATIN CAPITAL LETTER M;So;0;L;<square> 004D;;;;N;;;;;\n1F13D;SQUARED LATIN CAPITAL LETTER N;So;0;L;<square> 004E;;;;N;;;;;\n1F13E;SQUARED LATIN CAPITAL LETTER O;So;0;L;<square> 004F;;;;N;;;;;\n1F13F;SQUARED LATIN CAPITAL LETTER P;So;0;L;<square> 0050;;;;N;;;;;\n1F140;SQUARED LATIN CAPITAL LETTER Q;So;0;L;<square> 0051;;;;N;;;;;\n1F141;SQUARED LATIN CAPITAL LETTER R;So;0;L;<square> 0052;;;;N;;;;;\n1F142;SQUARED LATIN CAPITAL LETTER S;So;0;L;<square> 0053;;;;N;;;;;\n1F143;SQUARED LATIN CAPITAL LETTER T;So;0;L;<square> 0054;;;;N;;;;;\n1F144;SQUARED LATIN CAPITAL LETTER U;So;0;L;<square> 0055;;;;N;;;;;\n1F145;SQUARED LATIN CAPITAL LETTER V;So;0;L;<square> 0056;;;;N;;;;;\n1F146;SQUARED LATIN CAPITAL LETTER W;So;0;L;<square> 0057;;;;N;;;;;\n1F147;SQUARED LATIN CAPITAL LETTER X;So;0;L;<square> 0058;;;;N;;;;;\n1F148;SQUARED LATIN CAPITAL LETTER Y;So;0;L;<square> 0059;;;;N;;;;;\n1F149;SQUARED LATIN CAPITAL LETTER Z;So;0;L;<square> 005A;;;;N;;;;;\n1F14A;SQUARED HV;So;0;L;<square> 0048 0056;;;;N;;;;;\n1F14B;SQUARED MV;So;0;L;<square> 004D 0056;;;;N;;;;;\n1F14C;SQUARED SD;So;0;L;<square> 0053 0044;;;;N;;;;;\n1F14D;SQUARED SS;So;0;L;<square> 0053 0053;;;;N;;;;;\n1F14E;SQUARED PPV;So;0;L;<square> 0050 0050 0056;;;;N;;;;;\n1F14F;SQUARED WC;So;0;L;<square> 0057 0043;;;;N;;;;;\n1F150;NEGATIVE CIRCLED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;;\n1F151;NEGATIVE CIRCLED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;;\n1F152;NEGATIVE CIRCLED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;;\n1F153;NEGATIVE CIRCLED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;;\n1F154;NEGATIVE CIRCLED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;;\n1F155;NEGATIVE CIRCLED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;;\n1F156;NEGATIVE CIRCLED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;;\n1F157;NEGATIVE CIRCLED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;;\n1F158;NEGATIVE CIRCLED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;;\n1F159;NEGATIVE CIRCLED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;;\n1F15A;NEGATIVE CIRCLED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;;\n1F15B;NEGATIVE CIRCLED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;;\n1F15C;NEGATIVE CIRCLED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;;\n1F15D;NEGATIVE CIRCLED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;;\n1F15E;NEGATIVE CIRCLED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;;\n1F15F;NEGATIVE CIRCLED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;;\n1F160;NEGATIVE CIRCLED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;;\n1F161;NEGATIVE CIRCLED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;;\n1F162;NEGATIVE CIRCLED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;;\n1F163;NEGATIVE CIRCLED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;;\n1F164;NEGATIVE CIRCLED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;;\n1F165;NEGATIVE CIRCLED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;;\n1F166;NEGATIVE CIRCLED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;;\n1F167;NEGATIVE CIRCLED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;;\n1F168;NEGATIVE CIRCLED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;;\n1F169;NEGATIVE CIRCLED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;;\n1F16A;RAISED MC SIGN;So;0;ON;<super> 004D 0043;;;;N;;;;;\n1F16B;RAISED MD SIGN;So;0;ON;<super> 004D 0044;;;;N;;;;;\n1F16C;RAISED MR SIGN;So;0;ON;<super> 004D 0052;;;;N;;;;;\n1F16D;CIRCLED CC;So;0;ON;;;;;N;;;;;\n1F16E;CIRCLED C WITH OVERLAID BACKSLASH;So;0;ON;;;;;N;;;;;\n1F16F;CIRCLED HUMAN FIGURE;So;0;ON;;;;;N;;;;;\n1F170;NEGATIVE SQUARED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;;\n1F171;NEGATIVE SQUARED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;;\n1F172;NEGATIVE SQUARED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;;\n1F173;NEGATIVE SQUARED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;;\n1F174;NEGATIVE SQUARED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;;\n1F175;NEGATIVE SQUARED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;;\n1F176;NEGATIVE SQUARED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;;\n1F177;NEGATIVE SQUARED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;;\n1F178;NEGATIVE SQUARED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;;\n1F179;NEGATIVE SQUARED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;;\n1F17A;NEGATIVE SQUARED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;;\n1F17B;NEGATIVE SQUARED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;;\n1F17C;NEGATIVE SQUARED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;;\n1F17D;NEGATIVE SQUARED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;;\n1F17E;NEGATIVE SQUARED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;;\n1F17F;NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;;\n1F180;NEGATIVE SQUARED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;;\n1F181;NEGATIVE SQUARED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;;\n1F182;NEGATIVE SQUARED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;;\n1F183;NEGATIVE SQUARED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;;\n1F184;NEGATIVE SQUARED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;;\n1F185;NEGATIVE SQUARED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;;\n1F186;NEGATIVE SQUARED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;;\n1F187;NEGATIVE SQUARED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;;\n1F188;NEGATIVE SQUARED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;;\n1F189;NEGATIVE SQUARED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;;\n1F18A;CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;;\n1F18B;NEGATIVE SQUARED IC;So;0;L;;;;;N;;;;;\n1F18C;NEGATIVE SQUARED PA;So;0;L;;;;;N;;;;;\n1F18D;NEGATIVE SQUARED SA;So;0;L;;;;;N;;;;;\n1F18E;NEGATIVE SQUARED AB;So;0;L;;;;;N;;;;;\n1F18F;NEGATIVE SQUARED WC;So;0;L;;;;;N;;;;;\n1F190;SQUARE DJ;So;0;L;<square> 0044 004A;;;;N;;;;;\n1F191;SQUARED CL;So;0;L;;;;;N;;;;;\n1F192;SQUARED COOL;So;0;L;;;;;N;;;;;\n1F193;SQUARED FREE;So;0;L;;;;;N;;;;;\n1F194;SQUARED ID;So;0;L;;;;;N;;;;;\n1F195;SQUARED NEW;So;0;L;;;;;N;;;;;\n1F196;SQUARED NG;So;0;L;;;;;N;;;;;\n1F197;SQUARED OK;So;0;L;;;;;N;;;;;\n1F198;SQUARED SOS;So;0;L;;;;;N;;;;;\n1F199;SQUARED UP WITH EXCLAMATION MARK;So;0;L;;;;;N;;;;;\n1F19A;SQUARED VS;So;0;L;;;;;N;;;;;\n1F19B;SQUARED THREE D;So;0;L;;;;;N;;;;;\n1F19C;SQUARED SECOND SCREEN;So;0;L;;;;;N;;;;;\n1F19D;SQUARED TWO K;So;0;L;;;;;N;;;;;\n1F19E;SQUARED FOUR K;So;0;L;;;;;N;;;;;\n1F19F;SQUARED EIGHT K;So;0;L;;;;;N;;;;;\n1F1A0;SQUARED FIVE POINT ONE;So;0;L;;;;;N;;;;;\n1F1A1;SQUARED SEVEN POINT ONE;So;0;L;;;;;N;;;;;\n1F1A2;SQUARED TWENTY-TWO POINT TWO;So;0;L;;;;;N;;;;;\n1F1A3;SQUARED SIXTY P;So;0;L;;;;;N;;;;;\n1F1A4;SQUARED ONE HUNDRED TWENTY P;So;0;L;;;;;N;;;;;\n1F1A5;SQUARED LATIN SMALL LETTER D;So;0;L;;;;;N;;;;;\n1F1A6;SQUARED HC;So;0;L;;;;;N;;;;;\n1F1A7;SQUARED HDR;So;0;L;;;;;N;;;;;\n1F1A8;SQUARED HI-RES;So;0;L;;;;;N;;;;;\n1F1A9;SQUARED LOSSLESS;So;0;L;;;;;N;;;;;\n1F1AA;SQUARED SHV;So;0;L;;;;;N;;;;;\n1F1AB;SQUARED UHD;So;0;L;;;;;N;;;;;\n1F1AC;SQUARED VOD;So;0;L;;;;;N;;;;;\n1F1AD;MASK WORK SYMBOL;So;0;ON;;;;;N;;;;;\n1F1E6;REGIONAL INDICATOR SYMBOL LETTER A;So;0;L;;;;;N;;;;;\n1F1E7;REGIONAL INDICATOR SYMBOL LETTER B;So;0;L;;;;;N;;;;;\n1F1E8;REGIONAL INDICATOR SYMBOL LETTER C;So;0;L;;;;;N;;;;;\n1F1E9;REGIONAL INDICATOR SYMBOL LETTER D;So;0;L;;;;;N;;;;;\n1F1EA;REGIONAL INDICATOR SYMBOL LETTER E;So;0;L;;;;;N;;;;;\n1F1EB;REGIONAL INDICATOR SYMBOL LETTER F;So;0;L;;;;;N;;;;;\n1F1EC;REGIONAL INDICATOR SYMBOL LETTER G;So;0;L;;;;;N;;;;;\n1F1ED;REGIONAL INDICATOR SYMBOL LETTER H;So;0;L;;;;;N;;;;;\n1F1EE;REGIONAL INDICATOR SYMBOL LETTER I;So;0;L;;;;;N;;;;;\n1F1EF;REGIONAL INDICATOR SYMBOL LETTER J;So;0;L;;;;;N;;;;;\n1F1F0;REGIONAL INDICATOR SYMBOL LETTER K;So;0;L;;;;;N;;;;;\n1F1F1;REGIONAL INDICATOR SYMBOL LETTER L;So;0;L;;;;;N;;;;;\n1F1F2;REGIONAL INDICATOR SYMBOL LETTER M;So;0;L;;;;;N;;;;;\n1F1F3;REGIONAL INDICATOR SYMBOL LETTER N;So;0;L;;;;;N;;;;;\n1F1F4;REGIONAL INDICATOR SYMBOL LETTER O;So;0;L;;;;;N;;;;;\n1F1F5;REGIONAL INDICATOR SYMBOL LETTER P;So;0;L;;;;;N;;;;;\n1F1F6;REGIONAL INDICATOR SYMBOL LETTER Q;So;0;L;;;;;N;;;;;\n1F1F7;REGIONAL INDICATOR SYMBOL LETTER R;So;0;L;;;;;N;;;;;\n1F1F8;REGIONAL INDICATOR SYMBOL LETTER S;So;0;L;;;;;N;;;;;\n1F1F9;REGIONAL INDICATOR SYMBOL LETTER T;So;0;L;;;;;N;;;;;\n1F1FA;REGIONAL INDICATOR SYMBOL LETTER U;So;0;L;;;;;N;;;;;\n1F1FB;REGIONAL INDICATOR SYMBOL LETTER V;So;0;L;;;;;N;;;;;\n1F1FC;REGIONAL INDICATOR SYMBOL LETTER W;So;0;L;;;;;N;;;;;\n1F1FD;REGIONAL INDICATOR SYMBOL LETTER X;So;0;L;;;;;N;;;;;\n1F1FE;REGIONAL INDICATOR SYMBOL LETTER Y;So;0;L;;;;;N;;;;;\n1F1FF;REGIONAL INDICATOR SYMBOL LETTER Z;So;0;L;;;;;N;;;;;\n1F200;SQUARE HIRAGANA HOKA;So;0;L;<square> 307B 304B;;;;N;;;;;\n1F201;SQUARED KATAKANA KOKO;So;0;L;<square> 30B3 30B3;;;;N;;;;;\n1F202;SQUARED KATAKANA SA;So;0;L;<square> 30B5;;;;N;;;;;\n1F210;SQUARED CJK UNIFIED IDEOGRAPH-624B;So;0;L;<square> 624B;;;;N;;;;;\n1F211;SQUARED CJK UNIFIED IDEOGRAPH-5B57;So;0;L;<square> 5B57;;;;N;;;;;\n1F212;SQUARED CJK UNIFIED IDEOGRAPH-53CC;So;0;L;<square> 53CC;;;;N;;;;;\n1F213;SQUARED KATAKANA DE;So;0;L;<square> 30C7;;;;N;;;;;\n1F214;SQUARED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L;<square> 4E8C;;;;N;;;;;\n1F215;SQUARED CJK UNIFIED IDEOGRAPH-591A;So;0;L;<square> 591A;;;;N;;;;;\n1F216;SQUARED CJK UNIFIED IDEOGRAPH-89E3;So;0;L;<square> 89E3;;;;N;;;;;\n1F217;SQUARED CJK UNIFIED IDEOGRAPH-5929;So;0;L;<square> 5929;;;;N;;;;;\n1F218;SQUARED CJK UNIFIED IDEOGRAPH-4EA4;So;0;L;<square> 4EA4;;;;N;;;;;\n1F219;SQUARED CJK UNIFIED IDEOGRAPH-6620;So;0;L;<square> 6620;;;;N;;;;;\n1F21A;SQUARED CJK UNIFIED IDEOGRAPH-7121;So;0;L;<square> 7121;;;;N;;;;;\n1F21B;SQUARED CJK UNIFIED IDEOGRAPH-6599;So;0;L;<square> 6599;;;;N;;;;;\n1F21C;SQUARED CJK UNIFIED IDEOGRAPH-524D;So;0;L;<square> 524D;;;;N;;;;;\n1F21D;SQUARED CJK UNIFIED IDEOGRAPH-5F8C;So;0;L;<square> 5F8C;;;;N;;;;;\n1F21E;SQUARED CJK UNIFIED IDEOGRAPH-518D;So;0;L;<square> 518D;;;;N;;;;;\n1F21F;SQUARED CJK UNIFIED IDEOGRAPH-65B0;So;0;L;<square> 65B0;;;;N;;;;;\n1F220;SQUARED CJK UNIFIED IDEOGRAPH-521D;So;0;L;<square> 521D;;;;N;;;;;\n1F221;SQUARED CJK UNIFIED IDEOGRAPH-7D42;So;0;L;<square> 7D42;;;;N;;;;;\n1F222;SQUARED CJK UNIFIED IDEOGRAPH-751F;So;0;L;<square> 751F;;;;N;;;;;\n1F223;SQUARED CJK UNIFIED IDEOGRAPH-8CA9;So;0;L;<square> 8CA9;;;;N;;;;;\n1F224;SQUARED CJK UNIFIED IDEOGRAPH-58F0;So;0;L;<square> 58F0;;;;N;;;;;\n1F225;SQUARED CJK UNIFIED IDEOGRAPH-5439;So;0;L;<square> 5439;;;;N;;;;;\n1F226;SQUARED CJK UNIFIED IDEOGRAPH-6F14;So;0;L;<square> 6F14;;;;N;;;;;\n1F227;SQUARED CJK UNIFIED IDEOGRAPH-6295;So;0;L;<square> 6295;;;;N;;;;;\n1F228;SQUARED CJK UNIFIED IDEOGRAPH-6355;So;0;L;<square> 6355;;;;N;;;;;\n1F229;SQUARED CJK UNIFIED IDEOGRAPH-4E00;So;0;L;<square> 4E00;;;;N;;;;;\n1F22A;SQUARED CJK UNIFIED IDEOGRAPH-4E09;So;0;L;<square> 4E09;;;;N;;;;;\n1F22B;SQUARED CJK UNIFIED IDEOGRAPH-904A;So;0;L;<square> 904A;;;;N;;;;;\n1F22C;SQUARED CJK UNIFIED IDEOGRAPH-5DE6;So;0;L;<square> 5DE6;;;;N;;;;;\n1F22D;SQUARED CJK UNIFIED IDEOGRAPH-4E2D;So;0;L;<square> 4E2D;;;;N;;;;;\n1F22E;SQUARED CJK UNIFIED IDEOGRAPH-53F3;So;0;L;<square> 53F3;;;;N;;;;;\n1F22F;SQUARED CJK UNIFIED IDEOGRAPH-6307;So;0;L;<square> 6307;;;;N;;;;;\n1F230;SQUARED CJK UNIFIED IDEOGRAPH-8D70;So;0;L;<square> 8D70;;;;N;;;;;\n1F231;SQUARED CJK UNIFIED IDEOGRAPH-6253;So;0;L;<square> 6253;;;;N;;;;;\n1F232;SQUARED CJK UNIFIED IDEOGRAPH-7981;So;0;L;<square> 7981;;;;N;;;;;\n1F233;SQUARED CJK UNIFIED IDEOGRAPH-7A7A;So;0;L;<square> 7A7A;;;;N;;;;;\n1F234;SQUARED CJK UNIFIED IDEOGRAPH-5408;So;0;L;<square> 5408;;;;N;;;;;\n1F235;SQUARED CJK UNIFIED IDEOGRAPH-6E80;So;0;L;<square> 6E80;;;;N;;;;;\n1F236;SQUARED CJK UNIFIED IDEOGRAPH-6709;So;0;L;<square> 6709;;;;N;;;;;\n1F237;SQUARED CJK UNIFIED IDEOGRAPH-6708;So;0;L;<square> 6708;;;;N;;;;;\n1F238;SQUARED CJK UNIFIED IDEOGRAPH-7533;So;0;L;<square> 7533;;;;N;;;;;\n1F239;SQUARED CJK UNIFIED IDEOGRAPH-5272;So;0;L;<square> 5272;;;;N;;;;;\n1F23A;SQUARED CJK UNIFIED IDEOGRAPH-55B6;So;0;L;<square> 55B6;;;;N;;;;;\n1F23B;SQUARED CJK UNIFIED IDEOGRAPH-914D;So;0;L;<square> 914D;;;;N;;;;;\n1F240;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C;So;0;L;<compat> 3014 672C 3015;;;;N;;;;;\n1F241;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09;So;0;L;<compat> 3014 4E09 3015;;;;N;;;;;\n1F242;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L;<compat> 3014 4E8C 3015;;;;N;;;;;\n1F243;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89;So;0;L;<compat> 3014 5B89 3015;;;;N;;;;;\n1F244;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9;So;0;L;<compat> 3014 70B9 3015;;;;N;;;;;\n1F245;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253;So;0;L;<compat> 3014 6253 3015;;;;N;;;;;\n1F246;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7;So;0;L;<compat> 3014 76D7 3015;;;;N;;;;;\n1F247;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD;So;0;L;<compat> 3014 52DD 3015;;;;N;;;;;\n1F248;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557;So;0;L;<compat> 3014 6557 3015;;;;N;;;;;\n1F250;CIRCLED IDEOGRAPH ADVANTAGE;So;0;L;<circle> 5F97;;;;N;;;;;\n1F251;CIRCLED IDEOGRAPH ACCEPT;So;0;L;<circle> 53EF;;;;N;;;;;\n1F260;ROUNDED SYMBOL FOR FU;So;0;ON;;;;;N;;;;;\n1F261;ROUNDED SYMBOL FOR LU;So;0;ON;;;;;N;;;;;\n1F262;ROUNDED SYMBOL FOR SHOU;So;0;ON;;;;;N;;;;;\n1F263;ROUNDED SYMBOL FOR XI;So;0;ON;;;;;N;;;;;\n1F264;ROUNDED SYMBOL FOR SHUANGXI;So;0;ON;;;;;N;;;;;\n1F265;ROUNDED SYMBOL FOR CAI;So;0;ON;;;;;N;;;;;\n1F300;CYCLONE;So;0;ON;;;;;N;;;;;\n1F301;FOGGY;So;0;ON;;;;;N;;;;;\n1F302;CLOSED UMBRELLA;So;0;ON;;;;;N;;;;;\n1F303;NIGHT WITH STARS;So;0;ON;;;;;N;;;;;\n1F304;SUNRISE OVER MOUNTAINS;So;0;ON;;;;;N;;;;;\n1F305;SUNRISE;So;0;ON;;;;;N;;;;;\n1F306;CITYSCAPE AT DUSK;So;0;ON;;;;;N;;;;;\n1F307;SUNSET OVER BUILDINGS;So;0;ON;;;;;N;;;;;\n1F308;RAINBOW;So;0;ON;;;;;N;;;;;\n1F309;BRIDGE AT NIGHT;So;0;ON;;;;;N;;;;;\n1F30A;WATER WAVE;So;0;ON;;;;;N;;;;;\n1F30B;VOLCANO;So;0;ON;;;;;N;;;;;\n1F30C;MILKY WAY;So;0;ON;;;;;N;;;;;\n1F30D;EARTH GLOBE EUROPE-AFRICA;So;0;ON;;;;;N;;;;;\n1F30E;EARTH GLOBE AMERICAS;So;0;ON;;;;;N;;;;;\n1F30F;EARTH GLOBE ASIA-AUSTRALIA;So;0;ON;;;;;N;;;;;\n1F310;GLOBE WITH MERIDIANS;So;0;ON;;;;;N;;;;;\n1F311;NEW MOON SYMBOL;So;0;ON;;;;;N;;;;;\n1F312;WAXING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;;\n1F313;FIRST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;;\n1F314;WAXING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;;\n1F315;FULL MOON SYMBOL;So;0;ON;;;;;N;;;;;\n1F316;WANING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;;\n1F317;LAST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;;\n1F318;WANING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;;\n1F319;CRESCENT MOON;So;0;ON;;;;;N;;;;;\n1F31A;NEW MOON WITH FACE;So;0;ON;;;;;N;;;;;\n1F31B;FIRST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;;\n1F31C;LAST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;;\n1F31D;FULL MOON WITH FACE;So;0;ON;;;;;N;;;;;\n1F31E;SUN WITH FACE;So;0;ON;;;;;N;;;;;\n1F31F;GLOWING STAR;So;0;ON;;;;;N;;;;;\n1F320;SHOOTING STAR;So;0;ON;;;;;N;;;;;\n1F321;THERMOMETER;So;0;ON;;;;;N;;;;;\n1F322;BLACK DROPLET;So;0;ON;;;;;N;;;;;\n1F323;WHITE SUN;So;0;ON;;;;;N;;;;;\n1F324;WHITE SUN WITH SMALL CLOUD;So;0;ON;;;;;N;;;;;\n1F325;WHITE SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;;\n1F326;WHITE SUN BEHIND CLOUD WITH RAIN;So;0;ON;;;;;N;;;;;\n1F327;CLOUD WITH RAIN;So;0;ON;;;;;N;;;;;\n1F328;CLOUD WITH SNOW;So;0;ON;;;;;N;;;;;\n1F329;CLOUD WITH LIGHTNING;So;0;ON;;;;;N;;;;;\n1F32A;CLOUD WITH TORNADO;So;0;ON;;;;;N;;;;;\n1F32B;FOG;So;0;ON;;;;;N;;;;;\n1F32C;WIND BLOWING FACE;So;0;ON;;;;;N;;;;;\n1F32D;HOT DOG;So;0;ON;;;;;N;;;;;\n1F32E;TACO;So;0;ON;;;;;N;;;;;\n1F32F;BURRITO;So;0;ON;;;;;N;;;;;\n1F330;CHESTNUT;So;0;ON;;;;;N;;;;;\n1F331;SEEDLING;So;0;ON;;;;;N;;;;;\n1F332;EVERGREEN TREE;So;0;ON;;;;;N;;;;;\n1F333;DECIDUOUS TREE;So;0;ON;;;;;N;;;;;\n1F334;PALM TREE;So;0;ON;;;;;N;;;;;\n1F335;CACTUS;So;0;ON;;;;;N;;;;;\n1F336;HOT PEPPER;So;0;ON;;;;;N;;;;;\n1F337;TULIP;So;0;ON;;;;;N;;;;;\n1F338;CHERRY BLOSSOM;So;0;ON;;;;;N;;;;;\n1F339;ROSE;So;0;ON;;;;;N;;;;;\n1F33A;HIBISCUS;So;0;ON;;;;;N;;;;;\n1F33B;SUNFLOWER;So;0;ON;;;;;N;;;;;\n1F33C;BLOSSOM;So;0;ON;;;;;N;;;;;\n1F33D;EAR OF MAIZE;So;0;ON;;;;;N;;;;;\n1F33E;EAR OF RICE;So;0;ON;;;;;N;;;;;\n1F33F;HERB;So;0;ON;;;;;N;;;;;\n1F340;FOUR LEAF CLOVER;So;0;ON;;;;;N;;;;;\n1F341;MAPLE LEAF;So;0;ON;;;;;N;;;;;\n1F342;FALLEN LEAF;So;0;ON;;;;;N;;;;;\n1F343;LEAF FLUTTERING IN WIND;So;0;ON;;;;;N;;;;;\n1F344;MUSHROOM;So;0;ON;;;;;N;;;;;\n1F345;TOMATO;So;0;ON;;;;;N;;;;;\n1F346;AUBERGINE;So;0;ON;;;;;N;;;;;\n1F347;GRAPES;So;0;ON;;;;;N;;;;;\n1F348;MELON;So;0;ON;;;;;N;;;;;\n1F349;WATERMELON;So;0;ON;;;;;N;;;;;\n1F34A;TANGERINE;So;0;ON;;;;;N;;;;;\n1F34B;LEMON;So;0;ON;;;;;N;;;;;\n1F34C;BANANA;So;0;ON;;;;;N;;;;;\n1F34D;PINEAPPLE;So;0;ON;;;;;N;;;;;\n1F34E;RED APPLE;So;0;ON;;;;;N;;;;;\n1F34F;GREEN APPLE;So;0;ON;;;;;N;;;;;\n1F350;PEAR;So;0;ON;;;;;N;;;;;\n1F351;PEACH;So;0;ON;;;;;N;;;;;\n1F352;CHERRIES;So;0;ON;;;;;N;;;;;\n1F353;STRAWBERRY;So;0;ON;;;;;N;;;;;\n1F354;HAMBURGER;So;0;ON;;;;;N;;;;;\n1F355;SLICE OF PIZZA;So;0;ON;;;;;N;;;;;\n1F356;MEAT ON BONE;So;0;ON;;;;;N;;;;;\n1F357;POULTRY LEG;So;0;ON;;;;;N;;;;;\n1F358;RICE CRACKER;So;0;ON;;;;;N;;;;;\n1F359;RICE BALL;So;0;ON;;;;;N;;;;;\n1F35A;COOKED RICE;So;0;ON;;;;;N;;;;;\n1F35B;CURRY AND RICE;So;0;ON;;;;;N;;;;;\n1F35C;STEAMING BOWL;So;0;ON;;;;;N;;;;;\n1F35D;SPAGHETTI;So;0;ON;;;;;N;;;;;\n1F35E;BREAD;So;0;ON;;;;;N;;;;;\n1F35F;FRENCH FRIES;So;0;ON;;;;;N;;;;;\n1F360;ROASTED SWEET POTATO;So;0;ON;;;;;N;;;;;\n1F361;DANGO;So;0;ON;;;;;N;;;;;\n1F362;ODEN;So;0;ON;;;;;N;;;;;\n1F363;SUSHI;So;0;ON;;;;;N;;;;;\n1F364;FRIED SHRIMP;So;0;ON;;;;;N;;;;;\n1F365;FISH CAKE WITH SWIRL DESIGN;So;0;ON;;;;;N;;;;;\n1F366;SOFT ICE CREAM;So;0;ON;;;;;N;;;;;\n1F367;SHAVED ICE;So;0;ON;;;;;N;;;;;\n1F368;ICE CREAM;So;0;ON;;;;;N;;;;;\n1F369;DOUGHNUT;So;0;ON;;;;;N;;;;;\n1F36A;COOKIE;So;0;ON;;;;;N;;;;;\n1F36B;CHOCOLATE BAR;So;0;ON;;;;;N;;;;;\n1F36C;CANDY;So;0;ON;;;;;N;;;;;\n1F36D;LOLLIPOP;So;0;ON;;;;;N;;;;;\n1F36E;CUSTARD;So;0;ON;;;;;N;;;;;\n1F36F;HONEY POT;So;0;ON;;;;;N;;;;;\n1F370;SHORTCAKE;So;0;ON;;;;;N;;;;;\n1F371;BENTO BOX;So;0;ON;;;;;N;;;;;\n1F372;POT OF FOOD;So;0;ON;;;;;N;;;;;\n1F373;COOKING;So;0;ON;;;;;N;;;;;\n1F374;FORK AND KNIFE;So;0;ON;;;;;N;;;;;\n1F375;TEACUP WITHOUT HANDLE;So;0;ON;;;;;N;;;;;\n1F376;SAKE BOTTLE AND CUP;So;0;ON;;;;;N;;;;;\n1F377;WINE GLASS;So;0;ON;;;;;N;;;;;\n1F378;COCKTAIL GLASS;So;0;ON;;;;;N;;;;;\n1F379;TROPICAL DRINK;So;0;ON;;;;;N;;;;;\n1F37A;BEER MUG;So;0;ON;;;;;N;;;;;\n1F37B;CLINKING BEER MUGS;So;0;ON;;;;;N;;;;;\n1F37C;BABY BOTTLE;So;0;ON;;;;;N;;;;;\n1F37D;FORK AND KNIFE WITH PLATE;So;0;ON;;;;;N;;;;;\n1F37E;BOTTLE WITH POPPING CORK;So;0;ON;;;;;N;;;;;\n1F37F;POPCORN;So;0;ON;;;;;N;;;;;\n1F380;RIBBON;So;0;ON;;;;;N;;;;;\n1F381;WRAPPED PRESENT;So;0;ON;;;;;N;;;;;\n1F382;BIRTHDAY CAKE;So;0;ON;;;;;N;;;;;\n1F383;JACK-O-LANTERN;So;0;ON;;;;;N;;;;;\n1F384;CHRISTMAS TREE;So;0;ON;;;;;N;;;;;\n1F385;FATHER CHRISTMAS;So;0;ON;;;;;N;;;;;\n1F386;FIREWORKS;So;0;ON;;;;;N;;;;;\n1F387;FIREWORK SPARKLER;So;0;ON;;;;;N;;;;;\n1F388;BALLOON;So;0;ON;;;;;N;;;;;\n1F389;PARTY POPPER;So;0;ON;;;;;N;;;;;\n1F38A;CONFETTI BALL;So;0;ON;;;;;N;;;;;\n1F38B;TANABATA TREE;So;0;ON;;;;;N;;;;;\n1F38C;CROSSED FLAGS;So;0;ON;;;;;N;;;;;\n1F38D;PINE DECORATION;So;0;ON;;;;;N;;;;;\n1F38E;JAPANESE DOLLS;So;0;ON;;;;;N;;;;;\n1F38F;CARP STREAMER;So;0;ON;;;;;N;;;;;\n1F390;WIND CHIME;So;0;ON;;;;;N;;;;;\n1F391;MOON VIEWING CEREMONY;So;0;ON;;;;;N;;;;;\n1F392;SCHOOL SATCHEL;So;0;ON;;;;;N;;;;;\n1F393;GRADUATION CAP;So;0;ON;;;;;N;;;;;\n1F394;HEART WITH TIP ON THE LEFT;So;0;ON;;;;;N;;;;;\n1F395;BOUQUET OF FLOWERS;So;0;ON;;;;;N;;;;;\n1F396;MILITARY MEDAL;So;0;ON;;;;;N;;;;;\n1F397;REMINDER RIBBON;So;0;ON;;;;;N;;;;;\n1F398;MUSICAL KEYBOARD WITH JACKS;So;0;ON;;;;;N;;;;;\n1F399;STUDIO MICROPHONE;So;0;ON;;;;;N;;;;;\n1F39A;LEVEL SLIDER;So;0;ON;;;;;N;;;;;\n1F39B;CONTROL KNOBS;So;0;ON;;;;;N;;;;;\n1F39C;BEAMED ASCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;;\n1F39D;BEAMED DESCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;;\n1F39E;FILM FRAMES;So;0;ON;;;;;N;;;;;\n1F39F;ADMISSION TICKETS;So;0;ON;;;;;N;;;;;\n1F3A0;CAROUSEL HORSE;So;0;ON;;;;;N;;;;;\n1F3A1;FERRIS WHEEL;So;0;ON;;;;;N;;;;;\n1F3A2;ROLLER COASTER;So;0;ON;;;;;N;;;;;\n1F3A3;FISHING POLE AND FISH;So;0;ON;;;;;N;;;;;\n1F3A4;MICROPHONE;So;0;ON;;;;;N;;;;;\n1F3A5;MOVIE CAMERA;So;0;ON;;;;;N;;;;;\n1F3A6;CINEMA;So;0;ON;;;;;N;;;;;\n1F3A7;HEADPHONE;So;0;ON;;;;;N;;;;;\n1F3A8;ARTIST PALETTE;So;0;ON;;;;;N;;;;;\n1F3A9;TOP HAT;So;0;ON;;;;;N;;;;;\n1F3AA;CIRCUS TENT;So;0;ON;;;;;N;;;;;\n1F3AB;TICKET;So;0;ON;;;;;N;;;;;\n1F3AC;CLAPPER BOARD;So;0;ON;;;;;N;;;;;\n1F3AD;PERFORMING ARTS;So;0;ON;;;;;N;;;;;\n1F3AE;VIDEO GAME;So;0;ON;;;;;N;;;;;\n1F3AF;DIRECT HIT;So;0;ON;;;;;N;;;;;\n1F3B0;SLOT MACHINE;So;0;ON;;;;;N;;;;;\n1F3B1;BILLIARDS;So;0;ON;;;;;N;;;;;\n1F3B2;GAME DIE;So;0;ON;;;;;N;;;;;\n1F3B3;BOWLING;So;0;ON;;;;;N;;;;;\n1F3B4;FLOWER PLAYING CARDS;So;0;ON;;;;;N;;;;;\n1F3B5;MUSICAL NOTE;So;0;ON;;;;;N;;;;;\n1F3B6;MULTIPLE MUSICAL NOTES;So;0;ON;;;;;N;;;;;\n1F3B7;SAXOPHONE;So;0;ON;;;;;N;;;;;\n1F3B8;GUITAR;So;0;ON;;;;;N;;;;;\n1F3B9;MUSICAL KEYBOARD;So;0;ON;;;;;N;;;;;\n1F3BA;TRUMPET;So;0;ON;;;;;N;;;;;\n1F3BB;VIOLIN;So;0;ON;;;;;N;;;;;\n1F3BC;MUSICAL SCORE;So;0;ON;;;;;N;;;;;\n1F3BD;RUNNING SHIRT WITH SASH;So;0;ON;;;;;N;;;;;\n1F3BE;TENNIS RACQUET AND BALL;So;0;ON;;;;;N;;;;;\n1F3BF;SKI AND SKI BOOT;So;0;ON;;;;;N;;;;;\n1F3C0;BASKETBALL AND HOOP;So;0;ON;;;;;N;;;;;\n1F3C1;CHEQUERED FLAG;So;0;ON;;;;;N;;;;;\n1F3C2;SNOWBOARDER;So;0;ON;;;;;N;;;;;\n1F3C3;RUNNER;So;0;ON;;;;;N;;;;;\n1F3C4;SURFER;So;0;ON;;;;;N;;;;;\n1F3C5;SPORTS MEDAL;So;0;ON;;;;;N;;;;;\n1F3C6;TROPHY;So;0;ON;;;;;N;;;;;\n1F3C7;HORSE RACING;So;0;ON;;;;;N;;;;;\n1F3C8;AMERICAN FOOTBALL;So;0;ON;;;;;N;;;;;\n1F3C9;RUGBY FOOTBALL;So;0;ON;;;;;N;;;;;\n1F3CA;SWIMMER;So;0;ON;;;;;N;;;;;\n1F3CB;WEIGHT LIFTER;So;0;ON;;;;;N;;;;;\n1F3CC;GOLFER;So;0;ON;;;;;N;;;;;\n1F3CD;RACING MOTORCYCLE;So;0;ON;;;;;N;;;;;\n1F3CE;RACING CAR;So;0;ON;;;;;N;;;;;\n1F3CF;CRICKET BAT AND BALL;So;0;ON;;;;;N;;;;;\n1F3D0;VOLLEYBALL;So;0;ON;;;;;N;;;;;\n1F3D1;FIELD HOCKEY STICK AND BALL;So;0;ON;;;;;N;;;;;\n1F3D2;ICE HOCKEY STICK AND PUCK;So;0;ON;;;;;N;;;;;\n1F3D3;TABLE TENNIS PADDLE AND BALL;So;0;ON;;;;;N;;;;;\n1F3D4;SNOW CAPPED MOUNTAIN;So;0;ON;;;;;N;;;;;\n1F3D5;CAMPING;So;0;ON;;;;;N;;;;;\n1F3D6;BEACH WITH UMBRELLA;So;0;ON;;;;;N;;;;;\n1F3D7;BUILDING CONSTRUCTION;So;0;ON;;;;;N;;;;;\n1F3D8;HOUSE BUILDINGS;So;0;ON;;;;;N;;;;;\n1F3D9;CITYSCAPE;So;0;ON;;;;;N;;;;;\n1F3DA;DERELICT HOUSE BUILDING;So;0;ON;;;;;N;;;;;\n1F3DB;CLASSICAL BUILDING;So;0;ON;;;;;N;;;;;\n1F3DC;DESERT;So;0;ON;;;;;N;;;;;\n1F3DD;DESERT ISLAND;So;0;ON;;;;;N;;;;;\n1F3DE;NATIONAL PARK;So;0;ON;;;;;N;;;;;\n1F3DF;STADIUM;So;0;ON;;;;;N;;;;;\n1F3E0;HOUSE BUILDING;So;0;ON;;;;;N;;;;;\n1F3E1;HOUSE WITH GARDEN;So;0;ON;;;;;N;;;;;\n1F3E2;OFFICE BUILDING;So;0;ON;;;;;N;;;;;\n1F3E3;JAPANESE POST OFFICE;So;0;ON;;;;;N;;;;;\n1F3E4;EUROPEAN POST OFFICE;So;0;ON;;;;;N;;;;;\n1F3E5;HOSPITAL;So;0;ON;;;;;N;;;;;\n1F3E6;BANK;So;0;ON;;;;;N;;;;;\n1F3E7;AUTOMATED TELLER MACHINE;So;0;ON;;;;;N;;;;;\n1F3E8;HOTEL;So;0;ON;;;;;N;;;;;\n1F3E9;LOVE HOTEL;So;0;ON;;;;;N;;;;;\n1F3EA;CONVENIENCE STORE;So;0;ON;;;;;N;;;;;\n1F3EB;SCHOOL;So;0;ON;;;;;N;;;;;\n1F3EC;DEPARTMENT STORE;So;0;ON;;;;;N;;;;;\n1F3ED;FACTORY;So;0;ON;;;;;N;;;;;\n1F3EE;IZAKAYA LANTERN;So;0;ON;;;;;N;;;;;\n1F3EF;JAPANESE CASTLE;So;0;ON;;;;;N;;;;;\n1F3F0;EUROPEAN CASTLE;So;0;ON;;;;;N;;;;;\n1F3F1;WHITE PENNANT;So;0;ON;;;;;N;;;;;\n1F3F2;BLACK PENNANT;So;0;ON;;;;;N;;;;;\n1F3F3;WAVING WHITE FLAG;So;0;ON;;;;;N;;;;;\n1F3F4;WAVING BLACK FLAG;So;0;ON;;;;;N;;;;;\n1F3F5;ROSETTE;So;0;ON;;;;;N;;;;;\n1F3F6;BLACK ROSETTE;So;0;ON;;;;;N;;;;;\n1F3F7;LABEL;So;0;ON;;;;;N;;;;;\n1F3F8;BADMINTON RACQUET AND SHUTTLECOCK;So;0;ON;;;;;N;;;;;\n1F3F9;BOW AND ARROW;So;0;ON;;;;;N;;;;;\n1F3FA;AMPHORA;So;0;ON;;;;;N;;;;;\n1F3FB;EMOJI MODIFIER FITZPATRICK TYPE-1-2;Sk;0;ON;;;;;N;;;;;\n1F3FC;EMOJI MODIFIER FITZPATRICK TYPE-3;Sk;0;ON;;;;;N;;;;;\n1F3FD;EMOJI MODIFIER FITZPATRICK TYPE-4;Sk;0;ON;;;;;N;;;;;\n1F3FE;EMOJI MODIFIER FITZPATRICK TYPE-5;Sk;0;ON;;;;;N;;;;;\n1F3FF;EMOJI MODIFIER FITZPATRICK TYPE-6;Sk;0;ON;;;;;N;;;;;\n1F400;RAT;So;0;ON;;;;;N;;;;;\n1F401;MOUSE;So;0;ON;;;;;N;;;;;\n1F402;OX;So;0;ON;;;;;N;;;;;\n1F403;WATER BUFFALO;So;0;ON;;;;;N;;;;;\n1F404;COW;So;0;ON;;;;;N;;;;;\n1F405;TIGER;So;0;ON;;;;;N;;;;;\n1F406;LEOPARD;So;0;ON;;;;;N;;;;;\n1F407;RABBIT;So;0;ON;;;;;N;;;;;\n1F408;CAT;So;0;ON;;;;;N;;;;;\n1F409;DRAGON;So;0;ON;;;;;N;;;;;\n1F40A;CROCODILE;So;0;ON;;;;;N;;;;;\n1F40B;WHALE;So;0;ON;;;;;N;;;;;\n1F40C;SNAIL;So;0;ON;;;;;N;;;;;\n1F40D;SNAKE;So;0;ON;;;;;N;;;;;\n1F40E;HORSE;So;0;ON;;;;;N;;;;;\n1F40F;RAM;So;0;ON;;;;;N;;;;;\n1F410;GOAT;So;0;ON;;;;;N;;;;;\n1F411;SHEEP;So;0;ON;;;;;N;;;;;\n1F412;MONKEY;So;0;ON;;;;;N;;;;;\n1F413;ROOSTER;So;0;ON;;;;;N;;;;;\n1F414;CHICKEN;So;0;ON;;;;;N;;;;;\n1F415;DOG;So;0;ON;;;;;N;;;;;\n1F416;PIG;So;0;ON;;;;;N;;;;;\n1F417;BOAR;So;0;ON;;;;;N;;;;;\n1F418;ELEPHANT;So;0;ON;;;;;N;;;;;\n1F419;OCTOPUS;So;0;ON;;;;;N;;;;;\n1F41A;SPIRAL SHELL;So;0;ON;;;;;N;;;;;\n1F41B;BUG;So;0;ON;;;;;N;;;;;\n1F41C;ANT;So;0;ON;;;;;N;;;;;\n1F41D;HONEYBEE;So;0;ON;;;;;N;;;;;\n1F41E;LADY BEETLE;So;0;ON;;;;;N;;;;;\n1F41F;FISH;So;0;ON;;;;;N;;;;;\n1F420;TROPICAL FISH;So;0;ON;;;;;N;;;;;\n1F421;BLOWFISH;So;0;ON;;;;;N;;;;;\n1F422;TURTLE;So;0;ON;;;;;N;;;;;\n1F423;HATCHING CHICK;So;0;ON;;;;;N;;;;;\n1F424;BABY CHICK;So;0;ON;;;;;N;;;;;\n1F425;FRONT-FACING BABY CHICK;So;0;ON;;;;;N;;;;;\n1F426;BIRD;So;0;ON;;;;;N;;;;;\n1F427;PENGUIN;So;0;ON;;;;;N;;;;;\n1F428;KOALA;So;0;ON;;;;;N;;;;;\n1F429;POODLE;So;0;ON;;;;;N;;;;;\n1F42A;DROMEDARY CAMEL;So;0;ON;;;;;N;;;;;\n1F42B;BACTRIAN CAMEL;So;0;ON;;;;;N;;;;;\n1F42C;DOLPHIN;So;0;ON;;;;;N;;;;;\n1F42D;MOUSE FACE;So;0;ON;;;;;N;;;;;\n1F42E;COW FACE;So;0;ON;;;;;N;;;;;\n1F42F;TIGER FACE;So;0;ON;;;;;N;;;;;\n1F430;RABBIT FACE;So;0;ON;;;;;N;;;;;\n1F431;CAT FACE;So;0;ON;;;;;N;;;;;\n1F432;DRAGON FACE;So;0;ON;;;;;N;;;;;\n1F433;SPOUTING WHALE;So;0;ON;;;;;N;;;;;\n1F434;HORSE FACE;So;0;ON;;;;;N;;;;;\n1F435;MONKEY FACE;So;0;ON;;;;;N;;;;;\n1F436;DOG FACE;So;0;ON;;;;;N;;;;;\n1F437;PIG FACE;So;0;ON;;;;;N;;;;;\n1F438;FROG FACE;So;0;ON;;;;;N;;;;;\n1F439;HAMSTER FACE;So;0;ON;;;;;N;;;;;\n1F43A;WOLF FACE;So;0;ON;;;;;N;;;;;\n1F43B;BEAR FACE;So;0;ON;;;;;N;;;;;\n1F43C;PANDA FACE;So;0;ON;;;;;N;;;;;\n1F43D;PIG NOSE;So;0;ON;;;;;N;;;;;\n1F43E;PAW PRINTS;So;0;ON;;;;;N;;;;;\n1F43F;CHIPMUNK;So;0;ON;;;;;N;;;;;\n1F440;EYES;So;0;ON;;;;;N;;;;;\n1F441;EYE;So;0;ON;;;;;N;;;;;\n1F442;EAR;So;0;ON;;;;;N;;;;;\n1F443;NOSE;So;0;ON;;;;;N;;;;;\n1F444;MOUTH;So;0;ON;;;;;N;;;;;\n1F445;TONGUE;So;0;ON;;;;;N;;;;;\n1F446;WHITE UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;\n1F447;WHITE DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;\n1F448;WHITE LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;\n1F449;WHITE RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;\n1F44A;FISTED HAND SIGN;So;0;ON;;;;;N;;;;;\n1F44B;WAVING HAND SIGN;So;0;ON;;;;;N;;;;;\n1F44C;OK HAND SIGN;So;0;ON;;;;;N;;;;;\n1F44D;THUMBS UP SIGN;So;0;ON;;;;;N;;;;;\n1F44E;THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;;\n1F44F;CLAPPING HANDS SIGN;So;0;ON;;;;;N;;;;;\n1F450;OPEN HANDS SIGN;So;0;ON;;;;;N;;;;;\n1F451;CROWN;So;0;ON;;;;;N;;;;;\n1F452;WOMANS HAT;So;0;ON;;;;;N;;;;;\n1F453;EYEGLASSES;So;0;ON;;;;;N;;;;;\n1F454;NECKTIE;So;0;ON;;;;;N;;;;;\n1F455;T-SHIRT;So;0;ON;;;;;N;;;;;\n1F456;JEANS;So;0;ON;;;;;N;;;;;\n1F457;DRESS;So;0;ON;;;;;N;;;;;\n1F458;KIMONO;So;0;ON;;;;;N;;;;;\n1F459;BIKINI;So;0;ON;;;;;N;;;;;\n1F45A;WOMANS CLOTHES;So;0;ON;;;;;N;;;;;\n1F45B;PURSE;So;0;ON;;;;;N;;;;;\n1F45C;HANDBAG;So;0;ON;;;;;N;;;;;\n1F45D;POUCH;So;0;ON;;;;;N;;;;;\n1F45E;MANS SHOE;So;0;ON;;;;;N;;;;;\n1F45F;ATHLETIC SHOE;So;0;ON;;;;;N;;;;;\n1F460;HIGH-HEELED SHOE;So;0;ON;;;;;N;;;;;\n1F461;WOMANS SANDAL;So;0;ON;;;;;N;;;;;\n1F462;WOMANS BOOTS;So;0;ON;;;;;N;;;;;\n1F463;FOOTPRINTS;So;0;ON;;;;;N;;;;;\n1F464;BUST IN SILHOUETTE;So;0;ON;;;;;N;;;;;\n1F465;BUSTS IN SILHOUETTE;So;0;ON;;;;;N;;;;;\n1F466;BOY;So;0;ON;;;;;N;;;;;\n1F467;GIRL;So;0;ON;;;;;N;;;;;\n1F468;MAN;So;0;ON;;;;;N;;;;;\n1F469;WOMAN;So;0;ON;;;;;N;;;;;\n1F46A;FAMILY;So;0;ON;;;;;N;;;;;\n1F46B;MAN AND WOMAN HOLDING HANDS;So;0;ON;;;;;N;;;;;\n1F46C;TWO MEN HOLDING HANDS;So;0;ON;;;;;N;;;;;\n1F46D;TWO WOMEN HOLDING HANDS;So;0;ON;;;;;N;;;;;\n1F46E;POLICE OFFICER;So;0;ON;;;;;N;;;;;\n1F46F;WOMAN WITH BUNNY EARS;So;0;ON;;;;;N;;;;;\n1F470;BRIDE WITH VEIL;So;0;ON;;;;;N;;;;;\n1F471;PERSON WITH BLOND HAIR;So;0;ON;;;;;N;;;;;\n1F472;MAN WITH GUA PI MAO;So;0;ON;;;;;N;;;;;\n1F473;MAN WITH TURBAN;So;0;ON;;;;;N;;;;;\n1F474;OLDER MAN;So;0;ON;;;;;N;;;;;\n1F475;OLDER WOMAN;So;0;ON;;;;;N;;;;;\n1F476;BABY;So;0;ON;;;;;N;;;;;\n1F477;CONSTRUCTION WORKER;So;0;ON;;;;;N;;;;;\n1F478;PRINCESS;So;0;ON;;;;;N;;;;;\n1F479;JAPANESE OGRE;So;0;ON;;;;;N;;;;;\n1F47A;JAPANESE GOBLIN;So;0;ON;;;;;N;;;;;\n1F47B;GHOST;So;0;ON;;;;;N;;;;;\n1F47C;BABY ANGEL;So;0;ON;;;;;N;;;;;\n1F47D;EXTRATERRESTRIAL ALIEN;So;0;ON;;;;;N;;;;;\n1F47E;ALIEN MONSTER;So;0;ON;;;;;N;;;;;\n1F47F;IMP;So;0;ON;;;;;N;;;;;\n1F480;SKULL;So;0;ON;;;;;N;;;;;\n1F481;INFORMATION DESK PERSON;So;0;ON;;;;;N;;;;;\n1F482;GUARDSMAN;So;0;ON;;;;;N;;;;;\n1F483;DANCER;So;0;ON;;;;;N;;;;;\n1F484;LIPSTICK;So;0;ON;;;;;N;;;;;\n1F485;NAIL POLISH;So;0;ON;;;;;N;;;;;\n1F486;FACE MASSAGE;So;0;ON;;;;;N;;;;;\n1F487;HAIRCUT;So;0;ON;;;;;N;;;;;\n1F488;BARBER POLE;So;0;ON;;;;;N;;;;;\n1F489;SYRINGE;So;0;ON;;;;;N;;;;;\n1F48A;PILL;So;0;ON;;;;;N;;;;;\n1F48B;KISS MARK;So;0;ON;;;;;N;;;;;\n1F48C;LOVE LETTER;So;0;ON;;;;;N;;;;;\n1F48D;RING;So;0;ON;;;;;N;;;;;\n1F48E;GEM STONE;So;0;ON;;;;;N;;;;;\n1F48F;KISS;So;0;ON;;;;;N;;;;;\n1F490;BOUQUET;So;0;ON;;;;;N;;;;;\n1F491;COUPLE WITH HEART;So;0;ON;;;;;N;;;;;\n1F492;WEDDING;So;0;ON;;;;;N;;;;;\n1F493;BEATING HEART;So;0;ON;;;;;N;;;;;\n1F494;BROKEN HEART;So;0;ON;;;;;N;;;;;\n1F495;TWO HEARTS;So;0;ON;;;;;N;;;;;\n1F496;SPARKLING HEART;So;0;ON;;;;;N;;;;;\n1F497;GROWING HEART;So;0;ON;;;;;N;;;;;\n1F498;HEART WITH ARROW;So;0;ON;;;;;N;;;;;\n1F499;BLUE HEART;So;0;ON;;;;;N;;;;;\n1F49A;GREEN HEART;So;0;ON;;;;;N;;;;;\n1F49B;YELLOW HEART;So;0;ON;;;;;N;;;;;\n1F49C;PURPLE HEART;So;0;ON;;;;;N;;;;;\n1F49D;HEART WITH RIBBON;So;0;ON;;;;;N;;;;;\n1F49E;REVOLVING HEARTS;So;0;ON;;;;;N;;;;;\n1F49F;HEART DECORATION;So;0;ON;;;;;N;;;;;\n1F4A0;DIAMOND SHAPE WITH A DOT INSIDE;So;0;ON;;;;;N;;;;;\n1F4A1;ELECTRIC LIGHT BULB;So;0;ON;;;;;N;;;;;\n1F4A2;ANGER SYMBOL;So;0;ON;;;;;N;;;;;\n1F4A3;BOMB;So;0;ON;;;;;N;;;;;\n1F4A4;SLEEPING SYMBOL;So;0;ON;;;;;N;;;;;\n1F4A5;COLLISION SYMBOL;So;0;ON;;;;;N;;;;;\n1F4A6;SPLASHING SWEAT SYMBOL;So;0;ON;;;;;N;;;;;\n1F4A7;DROPLET;So;0;ON;;;;;N;;;;;\n1F4A8;DASH SYMBOL;So;0;ON;;;;;N;;;;;\n1F4A9;PILE OF POO;So;0;ON;;;;;N;;;;;\n1F4AA;FLEXED BICEPS;So;0;ON;;;;;N;;;;;\n1F4AB;DIZZY SYMBOL;So;0;ON;;;;;N;;;;;\n1F4AC;SPEECH BALLOON;So;0;ON;;;;;N;;;;;\n1F4AD;THOUGHT BALLOON;So;0;ON;;;;;N;;;;;\n1F4AE;WHITE FLOWER;So;0;ON;;;;;N;;;;;\n1F4AF;HUNDRED POINTS SYMBOL;So;0;ON;;;;;N;;;;;\n1F4B0;MONEY BAG;So;0;ON;;;;;N;;;;;\n1F4B1;CURRENCY EXCHANGE;So;0;ON;;;;;N;;;;;\n1F4B2;HEAVY DOLLAR SIGN;So;0;ON;;;;;N;;;;;\n1F4B3;CREDIT CARD;So;0;ON;;;;;N;;;;;\n1F4B4;BANKNOTE WITH YEN SIGN;So;0;ON;;;;;N;;;;;\n1F4B5;BANKNOTE WITH DOLLAR SIGN;So;0;ON;;;;;N;;;;;\n1F4B6;BANKNOTE WITH EURO SIGN;So;0;ON;;;;;N;;;;;\n1F4B7;BANKNOTE WITH POUND SIGN;So;0;ON;;;;;N;;;;;\n1F4B8;MONEY WITH WINGS;So;0;ON;;;;;N;;;;;\n1F4B9;CHART WITH UPWARDS TREND AND YEN SIGN;So;0;ON;;;;;N;;;;;\n1F4BA;SEAT;So;0;ON;;;;;N;;;;;\n1F4BB;PERSONAL COMPUTER;So;0;ON;;;;;N;;;;;\n1F4BC;BRIEFCASE;So;0;ON;;;;;N;;;;;\n1F4BD;MINIDISC;So;0;ON;;;;;N;;;;;\n1F4BE;FLOPPY DISK;So;0;ON;;;;;N;;;;;\n1F4BF;OPTICAL DISC;So;0;ON;;;;;N;;;;;\n1F4C0;DVD;So;0;ON;;;;;N;;;;;\n1F4C1;FILE FOLDER;So;0;ON;;;;;N;;;;;\n1F4C2;OPEN FILE FOLDER;So;0;ON;;;;;N;;;;;\n1F4C3;PAGE WITH CURL;So;0;ON;;;;;N;;;;;\n1F4C4;PAGE FACING UP;So;0;ON;;;;;N;;;;;\n1F4C5;CALENDAR;So;0;ON;;;;;N;;;;;\n1F4C6;TEAR-OFF CALENDAR;So;0;ON;;;;;N;;;;;\n1F4C7;CARD INDEX;So;0;ON;;;;;N;;;;;\n1F4C8;CHART WITH UPWARDS TREND;So;0;ON;;;;;N;;;;;\n1F4C9;CHART WITH DOWNWARDS TREND;So;0;ON;;;;;N;;;;;\n1F4CA;BAR CHART;So;0;ON;;;;;N;;;;;\n1F4CB;CLIPBOARD;So;0;ON;;;;;N;;;;;\n1F4CC;PUSHPIN;So;0;ON;;;;;N;;;;;\n1F4CD;ROUND PUSHPIN;So;0;ON;;;;;N;;;;;\n1F4CE;PAPERCLIP;So;0;ON;;;;;N;;;;;\n1F4CF;STRAIGHT RULER;So;0;ON;;;;;N;;;;;\n1F4D0;TRIANGULAR RULER;So;0;ON;;;;;N;;;;;\n1F4D1;BOOKMARK TABS;So;0;ON;;;;;N;;;;;\n1F4D2;LEDGER;So;0;ON;;;;;N;;;;;\n1F4D3;NOTEBOOK;So;0;ON;;;;;N;;;;;\n1F4D4;NOTEBOOK WITH DECORATIVE COVER;So;0;ON;;;;;N;;;;;\n1F4D5;CLOSED BOOK;So;0;ON;;;;;N;;;;;\n1F4D6;OPEN BOOK;So;0;ON;;;;;N;;;;;\n1F4D7;GREEN BOOK;So;0;ON;;;;;N;;;;;\n1F4D8;BLUE BOOK;So;0;ON;;;;;N;;;;;\n1F4D9;ORANGE BOOK;So;0;ON;;;;;N;;;;;\n1F4DA;BOOKS;So;0;ON;;;;;N;;;;;\n1F4DB;NAME BADGE;So;0;ON;;;;;N;;;;;\n1F4DC;SCROLL;So;0;ON;;;;;N;;;;;\n1F4DD;MEMO;So;0;ON;;;;;N;;;;;\n1F4DE;TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;;\n1F4DF;PAGER;So;0;ON;;;;;N;;;;;\n1F4E0;FAX MACHINE;So;0;ON;;;;;N;;;;;\n1F4E1;SATELLITE ANTENNA;So;0;ON;;;;;N;;;;;\n1F4E2;PUBLIC ADDRESS LOUDSPEAKER;So;0;ON;;;;;N;;;;;\n1F4E3;CHEERING MEGAPHONE;So;0;ON;;;;;N;;;;;\n1F4E4;OUTBOX TRAY;So;0;ON;;;;;N;;;;;\n1F4E5;INBOX TRAY;So;0;ON;;;;;N;;;;;\n1F4E6;PACKAGE;So;0;ON;;;;;N;;;;;\n1F4E7;E-MAIL SYMBOL;So;0;ON;;;;;N;;;;;\n1F4E8;INCOMING ENVELOPE;So;0;ON;;;;;N;;;;;\n1F4E9;ENVELOPE WITH DOWNWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;\n1F4EA;CLOSED MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;;\n1F4EB;CLOSED MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;;\n1F4EC;OPEN MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;;\n1F4ED;OPEN MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;;\n1F4EE;POSTBOX;So;0;ON;;;;;N;;;;;\n1F4EF;POSTAL HORN;So;0;ON;;;;;N;;;;;\n1F4F0;NEWSPAPER;So;0;ON;;;;;N;;;;;\n1F4F1;MOBILE PHONE;So;0;ON;;;;;N;;;;;\n1F4F2;MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT;So;0;ON;;;;;N;;;;;\n1F4F3;VIBRATION MODE;So;0;ON;;;;;N;;;;;\n1F4F4;MOBILE PHONE OFF;So;0;ON;;;;;N;;;;;\n1F4F5;NO MOBILE PHONES;So;0;ON;;;;;N;;;;;\n1F4F6;ANTENNA WITH BARS;So;0;ON;;;;;N;;;;;\n1F4F7;CAMERA;So;0;ON;;;;;N;;;;;\n1F4F8;CAMERA WITH FLASH;So;0;ON;;;;;N;;;;;\n1F4F9;VIDEO CAMERA;So;0;ON;;;;;N;;;;;\n1F4FA;TELEVISION;So;0;ON;;;;;N;;;;;\n1F4FB;RADIO;So;0;ON;;;;;N;;;;;\n1F4FC;VIDEOCASSETTE;So;0;ON;;;;;N;;;;;\n1F4FD;FILM PROJECTOR;So;0;ON;;;;;N;;;;;\n1F4FE;PORTABLE STEREO;So;0;ON;;;;;N;;;;;\n1F4FF;PRAYER BEADS;So;0;ON;;;;;N;;;;;\n1F500;TWISTED RIGHTWARDS ARROWS;So;0;ON;;;;;N;;;;;\n1F501;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;;\n1F502;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY;So;0;ON;;;;;N;;;;;\n1F503;CLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;;\n1F504;ANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;;\n1F505;LOW BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;;\n1F506;HIGH BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;;\n1F507;SPEAKER WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;;\n1F508;SPEAKER;So;0;ON;;;;;N;;;;;\n1F509;SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;;\n1F50A;SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;;\n1F50B;BATTERY;So;0;ON;;;;;N;;;;;\n1F50C;ELECTRIC PLUG;So;0;ON;;;;;N;;;;;\n1F50D;LEFT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;;\n1F50E;RIGHT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;;\n1F50F;LOCK WITH INK PEN;So;0;ON;;;;;N;;;;;\n1F510;CLOSED LOCK WITH KEY;So;0;ON;;;;;N;;;;;\n1F511;KEY;So;0;ON;;;;;N;;;;;\n1F512;LOCK;So;0;ON;;;;;N;;;;;\n1F513;OPEN LOCK;So;0;ON;;;;;N;;;;;\n1F514;BELL;So;0;ON;;;;;N;;;;;\n1F515;BELL WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;;\n1F516;BOOKMARK;So;0;ON;;;;;N;;;;;\n1F517;LINK SYMBOL;So;0;ON;;;;;N;;;;;\n1F518;RADIO BUTTON;So;0;ON;;;;;N;;;;;\n1F519;BACK WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;\n1F51A;END WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;\n1F51B;ON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVE;So;0;ON;;;;;N;;;;;\n1F51C;SOON WITH RIGHTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;\n1F51D;TOP WITH UPWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;\n1F51E;NO ONE UNDER EIGHTEEN SYMBOL;So;0;ON;;;;;N;;;;;\n1F51F;KEYCAP TEN;So;0;ON;;;;;N;;;;;\n1F520;INPUT SYMBOL FOR LATIN CAPITAL LETTERS;So;0;ON;;;;;N;;;;;\n1F521;INPUT SYMBOL FOR LATIN SMALL LETTERS;So;0;ON;;;;;N;;;;;\n1F522;INPUT SYMBOL FOR NUMBERS;So;0;ON;;;;;N;;;;;\n1F523;INPUT SYMBOL FOR SYMBOLS;So;0;ON;;;;;N;;;;;\n1F524;INPUT SYMBOL FOR LATIN LETTERS;So;0;ON;;;;;N;;;;;\n1F525;FIRE;So;0;ON;;;;;N;;;;;\n1F526;ELECTRIC TORCH;So;0;ON;;;;;N;;;;;\n1F527;WRENCH;So;0;ON;;;;;N;;;;;\n1F528;HAMMER;So;0;ON;;;;;N;;;;;\n1F529;NUT AND BOLT;So;0;ON;;;;;N;;;;;\n1F52A;HOCHO;So;0;ON;;;;;N;;;;;\n1F52B;PISTOL;So;0;ON;;;;;N;;;;;\n1F52C;MICROSCOPE;So;0;ON;;;;;N;;;;;\n1F52D;TELESCOPE;So;0;ON;;;;;N;;;;;\n1F52E;CRYSTAL BALL;So;0;ON;;;;;N;;;;;\n1F52F;SIX POINTED STAR WITH MIDDLE DOT;So;0;ON;;;;;N;;;;;\n1F530;JAPANESE SYMBOL FOR BEGINNER;So;0;ON;;;;;N;;;;;\n1F531;TRIDENT EMBLEM;So;0;ON;;;;;N;;;;;\n1F532;BLACK SQUARE BUTTON;So;0;ON;;;;;N;;;;;\n1F533;WHITE SQUARE BUTTON;So;0;ON;;;;;N;;;;;\n1F534;LARGE RED CIRCLE;So;0;ON;;;;;N;;;;;\n1F535;LARGE BLUE CIRCLE;So;0;ON;;;;;N;;;;;\n1F536;LARGE ORANGE DIAMOND;So;0;ON;;;;;N;;;;;\n1F537;LARGE BLUE DIAMOND;So;0;ON;;;;;N;;;;;\n1F538;SMALL ORANGE DIAMOND;So;0;ON;;;;;N;;;;;\n1F539;SMALL BLUE DIAMOND;So;0;ON;;;;;N;;;;;\n1F53A;UP-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;;\n1F53B;DOWN-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;;\n1F53C;UP-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;;\n1F53D;DOWN-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;;\n1F53E;LOWER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1F53F;UPPER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1F540;CIRCLED CROSS POMMEE;So;0;ON;;;;;N;;;;;\n1F541;CROSS POMMEE WITH HALF-CIRCLE BELOW;So;0;ON;;;;;N;;;;;\n1F542;CROSS POMMEE;So;0;ON;;;;;N;;;;;\n1F543;NOTCHED LEFT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;;\n1F544;NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;;\n1F545;SYMBOL FOR MARKS CHAPTER;So;0;ON;;;;;N;;;;;\n1F546;WHITE LATIN CROSS;So;0;ON;;;;;N;;;;;\n1F547;HEAVY LATIN CROSS;So;0;ON;;;;;N;;;;;\n1F548;CELTIC CROSS;So;0;ON;;;;;N;;;;;\n1F549;OM SYMBOL;So;0;ON;;;;;N;;;;;\n1F54A;DOVE OF PEACE;So;0;ON;;;;;N;;;;;\n1F54B;KAABA;So;0;ON;;;;;N;;;;;\n1F54C;MOSQUE;So;0;ON;;;;;N;;;;;\n1F54D;SYNAGOGUE;So;0;ON;;;;;N;;;;;\n1F54E;MENORAH WITH NINE BRANCHES;So;0;ON;;;;;N;;;;;\n1F54F;BOWL OF HYGIEIA;So;0;ON;;;;;N;;;;;\n1F550;CLOCK FACE ONE OCLOCK;So;0;ON;;;;;N;;;;;\n1F551;CLOCK FACE TWO OCLOCK;So;0;ON;;;;;N;;;;;\n1F552;CLOCK FACE THREE OCLOCK;So;0;ON;;;;;N;;;;;\n1F553;CLOCK FACE FOUR OCLOCK;So;0;ON;;;;;N;;;;;\n1F554;CLOCK FACE FIVE OCLOCK;So;0;ON;;;;;N;;;;;\n1F555;CLOCK FACE SIX OCLOCK;So;0;ON;;;;;N;;;;;\n1F556;CLOCK FACE SEVEN OCLOCK;So;0;ON;;;;;N;;;;;\n1F557;CLOCK FACE EIGHT OCLOCK;So;0;ON;;;;;N;;;;;\n1F558;CLOCK FACE NINE OCLOCK;So;0;ON;;;;;N;;;;;\n1F559;CLOCK FACE TEN OCLOCK;So;0;ON;;;;;N;;;;;\n1F55A;CLOCK FACE ELEVEN OCLOCK;So;0;ON;;;;;N;;;;;\n1F55B;CLOCK FACE TWELVE OCLOCK;So;0;ON;;;;;N;;;;;\n1F55C;CLOCK FACE ONE-THIRTY;So;0;ON;;;;;N;;;;;\n1F55D;CLOCK FACE TWO-THIRTY;So;0;ON;;;;;N;;;;;\n1F55E;CLOCK FACE THREE-THIRTY;So;0;ON;;;;;N;;;;;\n1F55F;CLOCK FACE FOUR-THIRTY;So;0;ON;;;;;N;;;;;\n1F560;CLOCK FACE FIVE-THIRTY;So;0;ON;;;;;N;;;;;\n1F561;CLOCK FACE SIX-THIRTY;So;0;ON;;;;;N;;;;;\n1F562;CLOCK FACE SEVEN-THIRTY;So;0;ON;;;;;N;;;;;\n1F563;CLOCK FACE EIGHT-THIRTY;So;0;ON;;;;;N;;;;;\n1F564;CLOCK FACE NINE-THIRTY;So;0;ON;;;;;N;;;;;\n1F565;CLOCK FACE TEN-THIRTY;So;0;ON;;;;;N;;;;;\n1F566;CLOCK FACE ELEVEN-THIRTY;So;0;ON;;;;;N;;;;;\n1F567;CLOCK FACE TWELVE-THIRTY;So;0;ON;;;;;N;;;;;\n1F568;RIGHT SPEAKER;So;0;ON;;;;;N;;;;;\n1F569;RIGHT SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;;\n1F56A;RIGHT SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;;\n1F56B;BULLHORN;So;0;ON;;;;;N;;;;;\n1F56C;BULLHORN WITH SOUND WAVES;So;0;ON;;;;;N;;;;;\n1F56D;RINGING BELL;So;0;ON;;;;;N;;;;;\n1F56E;BOOK;So;0;ON;;;;;N;;;;;\n1F56F;CANDLE;So;0;ON;;;;;N;;;;;\n1F570;MANTELPIECE CLOCK;So;0;ON;;;;;N;;;;;\n1F571;BLACK SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;;\n1F572;NO PIRACY;So;0;ON;;;;;N;;;;;\n1F573;HOLE;So;0;ON;;;;;N;;;;;\n1F574;MAN IN BUSINESS SUIT LEVITATING;So;0;ON;;;;;N;;;;;\n1F575;SLEUTH OR SPY;So;0;ON;;;;;N;;;;;\n1F576;DARK SUNGLASSES;So;0;ON;;;;;N;;;;;\n1F577;SPIDER;So;0;ON;;;;;N;;;;;\n1F578;SPIDER WEB;So;0;ON;;;;;N;;;;;\n1F579;JOYSTICK;So;0;ON;;;;;N;;;;;\n1F57A;MAN DANCING;So;0;ON;;;;;N;;;;;\n1F57B;LEFT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;;\n1F57C;TELEPHONE RECEIVER WITH PAGE;So;0;ON;;;;;N;;;;;\n1F57D;RIGHT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;;\n1F57E;WHITE TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;;\n1F57F;BLACK TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;;\n1F580;TELEPHONE ON TOP OF MODEM;So;0;ON;;;;;N;;;;;\n1F581;CLAMSHELL MOBILE PHONE;So;0;ON;;;;;N;;;;;\n1F582;BACK OF ENVELOPE;So;0;ON;;;;;N;;;;;\n1F583;STAMPED ENVELOPE;So;0;ON;;;;;N;;;;;\n1F584;ENVELOPE WITH LIGHTNING;So;0;ON;;;;;N;;;;;\n1F585;FLYING ENVELOPE;So;0;ON;;;;;N;;;;;\n1F586;PEN OVER STAMPED ENVELOPE;So;0;ON;;;;;N;;;;;\n1F587;LINKED PAPERCLIPS;So;0;ON;;;;;N;;;;;\n1F588;BLACK PUSHPIN;So;0;ON;;;;;N;;;;;\n1F589;LOWER LEFT PENCIL;So;0;ON;;;;;N;;;;;\n1F58A;LOWER LEFT BALLPOINT PEN;So;0;ON;;;;;N;;;;;\n1F58B;LOWER LEFT FOUNTAIN PEN;So;0;ON;;;;;N;;;;;\n1F58C;LOWER LEFT PAINTBRUSH;So;0;ON;;;;;N;;;;;\n1F58D;LOWER LEFT CRAYON;So;0;ON;;;;;N;;;;;\n1F58E;LEFT WRITING HAND;So;0;ON;;;;;N;;;;;\n1F58F;TURNED OK HAND SIGN;So;0;ON;;;;;N;;;;;\n1F590;RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;;\n1F591;REVERSED RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;;\n1F592;REVERSED THUMBS UP SIGN;So;0;ON;;;;;N;;;;;\n1F593;REVERSED THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;;\n1F594;REVERSED VICTORY HAND;So;0;ON;;;;;N;;;;;\n1F595;REVERSED HAND WITH MIDDLE FINGER EXTENDED;So;0;ON;;;;;N;;;;;\n1F596;RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS;So;0;ON;;;;;N;;;;;\n1F597;WHITE DOWN POINTING LEFT HAND INDEX;So;0;ON;;;;;N;;;;;\n1F598;SIDEWAYS WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;\n1F599;SIDEWAYS WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;\n1F59A;SIDEWAYS BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;\n1F59B;SIDEWAYS BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;\n1F59C;BLACK LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;\n1F59D;BLACK RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;\n1F59E;SIDEWAYS WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;;\n1F59F;SIDEWAYS WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;\n1F5A0;SIDEWAYS BLACK UP POINTING INDEX;So;0;ON;;;;;N;;;;;\n1F5A1;SIDEWAYS BLACK DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;\n1F5A2;BLACK UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;\n1F5A3;BLACK DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;\n1F5A4;BLACK HEART;So;0;ON;;;;;N;;;;;\n1F5A5;DESKTOP COMPUTER;So;0;ON;;;;;N;;;;;\n1F5A6;KEYBOARD AND MOUSE;So;0;ON;;;;;N;;;;;\n1F5A7;THREE NETWORKED COMPUTERS;So;0;ON;;;;;N;;;;;\n1F5A8;PRINTER;So;0;ON;;;;;N;;;;;\n1F5A9;POCKET CALCULATOR;So;0;ON;;;;;N;;;;;\n1F5AA;BLACK HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;;\n1F5AB;WHITE HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;;\n1F5AC;SOFT SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;;\n1F5AD;TAPE CARTRIDGE;So;0;ON;;;;;N;;;;;\n1F5AE;WIRED KEYBOARD;So;0;ON;;;;;N;;;;;\n1F5AF;ONE BUTTON MOUSE;So;0;ON;;;;;N;;;;;\n1F5B0;TWO BUTTON MOUSE;So;0;ON;;;;;N;;;;;\n1F5B1;THREE BUTTON MOUSE;So;0;ON;;;;;N;;;;;\n1F5B2;TRACKBALL;So;0;ON;;;;;N;;;;;\n1F5B3;OLD PERSONAL COMPUTER;So;0;ON;;;;;N;;;;;\n1F5B4;HARD DISK;So;0;ON;;;;;N;;;;;\n1F5B5;SCREEN;So;0;ON;;;;;N;;;;;\n1F5B6;PRINTER ICON;So;0;ON;;;;;N;;;;;\n1F5B7;FAX ICON;So;0;ON;;;;;N;;;;;\n1F5B8;OPTICAL DISC ICON;So;0;ON;;;;;N;;;;;\n1F5B9;DOCUMENT WITH TEXT;So;0;ON;;;;;N;;;;;\n1F5BA;DOCUMENT WITH TEXT AND PICTURE;So;0;ON;;;;;N;;;;;\n1F5BB;DOCUMENT WITH PICTURE;So;0;ON;;;;;N;;;;;\n1F5BC;FRAME WITH PICTURE;So;0;ON;;;;;N;;;;;\n1F5BD;FRAME WITH TILES;So;0;ON;;;;;N;;;;;\n1F5BE;FRAME WITH AN X;So;0;ON;;;;;N;;;;;\n1F5BF;BLACK FOLDER;So;0;ON;;;;;N;;;;;\n1F5C0;FOLDER;So;0;ON;;;;;N;;;;;\n1F5C1;OPEN FOLDER;So;0;ON;;;;;N;;;;;\n1F5C2;CARD INDEX DIVIDERS;So;0;ON;;;;;N;;;;;\n1F5C3;CARD FILE BOX;So;0;ON;;;;;N;;;;;\n1F5C4;FILE CABINET;So;0;ON;;;;;N;;;;;\n1F5C5;EMPTY NOTE;So;0;ON;;;;;N;;;;;\n1F5C6;EMPTY NOTE PAGE;So;0;ON;;;;;N;;;;;\n1F5C7;EMPTY NOTE PAD;So;0;ON;;;;;N;;;;;\n1F5C8;NOTE;So;0;ON;;;;;N;;;;;\n1F5C9;NOTE PAGE;So;0;ON;;;;;N;;;;;\n1F5CA;NOTE PAD;So;0;ON;;;;;N;;;;;\n1F5CB;EMPTY DOCUMENT;So;0;ON;;;;;N;;;;;\n1F5CC;EMPTY PAGE;So;0;ON;;;;;N;;;;;\n1F5CD;EMPTY PAGES;So;0;ON;;;;;N;;;;;\n1F5CE;DOCUMENT;So;0;ON;;;;;N;;;;;\n1F5CF;PAGE;So;0;ON;;;;;N;;;;;\n1F5D0;PAGES;So;0;ON;;;;;N;;;;;\n1F5D1;WASTEBASKET;So;0;ON;;;;;N;;;;;\n1F5D2;SPIRAL NOTE PAD;So;0;ON;;;;;N;;;;;\n1F5D3;SPIRAL CALENDAR PAD;So;0;ON;;;;;N;;;;;\n1F5D4;DESKTOP WINDOW;So;0;ON;;;;;N;;;;;\n1F5D5;MINIMIZE;So;0;ON;;;;;N;;;;;\n1F5D6;MAXIMIZE;So;0;ON;;;;;N;;;;;\n1F5D7;OVERLAP;So;0;ON;;;;;N;;;;;\n1F5D8;CLOCKWISE RIGHT AND LEFT SEMICIRCLE ARROWS;So;0;ON;;;;;N;;;;;\n1F5D9;CANCELLATION X;So;0;ON;;;;;N;;;;;\n1F5DA;INCREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;;\n1F5DB;DECREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;;\n1F5DC;COMPRESSION;So;0;ON;;;;;N;;;;;\n1F5DD;OLD KEY;So;0;ON;;;;;N;;;;;\n1F5DE;ROLLED-UP NEWSPAPER;So;0;ON;;;;;N;;;;;\n1F5DF;PAGE WITH CIRCLED TEXT;So;0;ON;;;;;N;;;;;\n1F5E0;STOCK CHART;So;0;ON;;;;;N;;;;;\n1F5E1;DAGGER KNIFE;So;0;ON;;;;;N;;;;;\n1F5E2;LIPS;So;0;ON;;;;;N;;;;;\n1F5E3;SPEAKING HEAD IN SILHOUETTE;So;0;ON;;;;;N;;;;;\n1F5E4;THREE RAYS ABOVE;So;0;ON;;;;;N;;;;;\n1F5E5;THREE RAYS BELOW;So;0;ON;;;;;N;;;;;\n1F5E6;THREE RAYS LEFT;So;0;ON;;;;;N;;;;;\n1F5E7;THREE RAYS RIGHT;So;0;ON;;;;;N;;;;;\n1F5E8;LEFT SPEECH BUBBLE;So;0;ON;;;;;N;;;;;\n1F5E9;RIGHT SPEECH BUBBLE;So;0;ON;;;;;N;;;;;\n1F5EA;TWO SPEECH BUBBLES;So;0;ON;;;;;N;;;;;\n1F5EB;THREE SPEECH BUBBLES;So;0;ON;;;;;N;;;;;\n1F5EC;LEFT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;;\n1F5ED;RIGHT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;;\n1F5EE;LEFT ANGER BUBBLE;So;0;ON;;;;;N;;;;;\n1F5EF;RIGHT ANGER BUBBLE;So;0;ON;;;;;N;;;;;\n1F5F0;MOOD BUBBLE;So;0;ON;;;;;N;;;;;\n1F5F1;LIGHTNING MOOD BUBBLE;So;0;ON;;;;;N;;;;;\n1F5F2;LIGHTNING MOOD;So;0;ON;;;;;N;;;;;\n1F5F3;BALLOT BOX WITH BALLOT;So;0;ON;;;;;N;;;;;\n1F5F4;BALLOT SCRIPT X;So;0;ON;;;;;N;;;;;\n1F5F5;BALLOT BOX WITH SCRIPT X;So;0;ON;;;;;N;;;;;\n1F5F6;BALLOT BOLD SCRIPT X;So;0;ON;;;;;N;;;;;\n1F5F7;BALLOT BOX WITH BOLD SCRIPT X;So;0;ON;;;;;N;;;;;\n1F5F8;LIGHT CHECK MARK;So;0;ON;;;;;N;;;;;\n1F5F9;BALLOT BOX WITH BOLD CHECK;So;0;ON;;;;;N;;;;;\n1F5FA;WORLD MAP;So;0;ON;;;;;N;;;;;\n1F5FB;MOUNT FUJI;So;0;ON;;;;;N;;;;;\n1F5FC;TOKYO TOWER;So;0;ON;;;;;N;;;;;\n1F5FD;STATUE OF LIBERTY;So;0;ON;;;;;N;;;;;\n1F5FE;SILHOUETTE OF JAPAN;So;0;ON;;;;;N;;;;;\n1F5FF;MOYAI;So;0;ON;;;;;N;;;;;\n1F600;GRINNING FACE;So;0;ON;;;;;N;;;;;\n1F601;GRINNING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;;\n1F602;FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;;\n1F603;SMILING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1F604;SMILING FACE WITH OPEN MOUTH AND SMILING EYES;So;0;ON;;;;;N;;;;;\n1F605;SMILING FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;;\n1F606;SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;;\n1F607;SMILING FACE WITH HALO;So;0;ON;;;;;N;;;;;\n1F608;SMILING FACE WITH HORNS;So;0;ON;;;;;N;;;;;\n1F609;WINKING FACE;So;0;ON;;;;;N;;;;;\n1F60A;SMILING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;;\n1F60B;FACE SAVOURING DELICIOUS FOOD;So;0;ON;;;;;N;;;;;\n1F60C;RELIEVED FACE;So;0;ON;;;;;N;;;;;\n1F60D;SMILING FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;;\n1F60E;SMILING FACE WITH SUNGLASSES;So;0;ON;;;;;N;;;;;\n1F60F;SMIRKING FACE;So;0;ON;;;;;N;;;;;\n1F610;NEUTRAL FACE;So;0;ON;;;;;N;;;;;\n1F611;EXPRESSIONLESS FACE;So;0;ON;;;;;N;;;;;\n1F612;UNAMUSED FACE;So;0;ON;;;;;N;;;;;\n1F613;FACE WITH COLD SWEAT;So;0;ON;;;;;N;;;;;\n1F614;PENSIVE FACE;So;0;ON;;;;;N;;;;;\n1F615;CONFUSED FACE;So;0;ON;;;;;N;;;;;\n1F616;CONFOUNDED FACE;So;0;ON;;;;;N;;;;;\n1F617;KISSING FACE;So;0;ON;;;;;N;;;;;\n1F618;FACE THROWING A KISS;So;0;ON;;;;;N;;;;;\n1F619;KISSING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;;\n1F61A;KISSING FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;;\n1F61B;FACE WITH STUCK-OUT TONGUE;So;0;ON;;;;;N;;;;;\n1F61C;FACE WITH STUCK-OUT TONGUE AND WINKING EYE;So;0;ON;;;;;N;;;;;\n1F61D;FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;;\n1F61E;DISAPPOINTED FACE;So;0;ON;;;;;N;;;;;\n1F61F;WORRIED FACE;So;0;ON;;;;;N;;;;;\n1F620;ANGRY FACE;So;0;ON;;;;;N;;;;;\n1F621;POUTING FACE;So;0;ON;;;;;N;;;;;\n1F622;CRYING FACE;So;0;ON;;;;;N;;;;;\n1F623;PERSEVERING FACE;So;0;ON;;;;;N;;;;;\n1F624;FACE WITH LOOK OF TRIUMPH;So;0;ON;;;;;N;;;;;\n1F625;DISAPPOINTED BUT RELIEVED FACE;So;0;ON;;;;;N;;;;;\n1F626;FROWNING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1F627;ANGUISHED FACE;So;0;ON;;;;;N;;;;;\n1F628;FEARFUL FACE;So;0;ON;;;;;N;;;;;\n1F629;WEARY FACE;So;0;ON;;;;;N;;;;;\n1F62A;SLEEPY FACE;So;0;ON;;;;;N;;;;;\n1F62B;TIRED FACE;So;0;ON;;;;;N;;;;;\n1F62C;GRIMACING FACE;So;0;ON;;;;;N;;;;;\n1F62D;LOUDLY CRYING FACE;So;0;ON;;;;;N;;;;;\n1F62E;FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1F62F;HUSHED FACE;So;0;ON;;;;;N;;;;;\n1F630;FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;;\n1F631;FACE SCREAMING IN FEAR;So;0;ON;;;;;N;;;;;\n1F632;ASTONISHED FACE;So;0;ON;;;;;N;;;;;\n1F633;FLUSHED FACE;So;0;ON;;;;;N;;;;;\n1F634;SLEEPING FACE;So;0;ON;;;;;N;;;;;\n1F635;DIZZY FACE;So;0;ON;;;;;N;;;;;\n1F636;FACE WITHOUT MOUTH;So;0;ON;;;;;N;;;;;\n1F637;FACE WITH MEDICAL MASK;So;0;ON;;;;;N;;;;;\n1F638;GRINNING CAT FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;;\n1F639;CAT FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;;\n1F63A;SMILING CAT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;\n1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;;\n1F63C;CAT FACE WITH WRY SMILE;So;0;ON;;;;;N;;;;;\n1F63D;KISSING CAT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;;\n1F63E;POUTING CAT FACE;So;0;ON;;;;;N;;;;;\n1F63F;CRYING CAT FACE;So;0;ON;;;;;N;;;;;\n1F640;WEARY CAT FACE;So;0;ON;;;;;N;;;;;\n1F641;SLIGHTLY FROWNING FACE;So;0;ON;;;;;N;;;;;\n1F642;SLIGHTLY SMILING FACE;So;0;ON;;;;;N;;;;;\n1F643;UPSIDE-DOWN FACE;So;0;ON;;;;;N;;;;;\n1F644;FACE WITH ROLLING EYES;So;0;ON;;;;;N;;;;;\n1F645;FACE WITH NO GOOD GESTURE;So;0;ON;;;;;N;;;;;\n1F646;FACE WITH OK GESTURE;So;0;ON;;;;;N;;;;;\n1F647;PERSON BOWING DEEPLY;So;0;ON;;;;;N;;;;;\n1F648;SEE-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;;\n1F649;HEAR-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;;\n1F64A;SPEAK-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;;\n1F64B;HAPPY PERSON RAISING ONE HAND;So;0;ON;;;;;N;;;;;\n1F64C;PERSON RAISING BOTH HANDS IN CELEBRATION;So;0;ON;;;;;N;;;;;\n1F64D;PERSON FROWNING;So;0;ON;;;;;N;;;;;\n1F64E;PERSON WITH POUTING FACE;So;0;ON;;;;;N;;;;;\n1F64F;PERSON WITH FOLDED HANDS;So;0;ON;;;;;N;;;;;\n1F650;NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;;\n1F651;SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;;\n1F652;NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;;\n1F653;SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;;\n1F654;TURNED NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;;\n1F655;TURNED SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;;\n1F656;TURNED NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;;\n1F657;TURNED SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;;\n1F658;NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;\n1F659;SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;\n1F65A;NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;\n1F65B;SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;\n1F65C;HEAVY NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;\n1F65D;HEAVY SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;\n1F65E;HEAVY NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;\n1F65F;HEAVY SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;\n1F660;NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;;\n1F661;SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;;\n1F662;NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;;\n1F663;SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;;\n1F664;HEAVY NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;;\n1F665;HEAVY SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;;\n1F666;HEAVY NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;;\n1F667;HEAVY SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;;\n1F668;HOLLOW QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;;\n1F669;HOLLOW QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;;\n1F66A;SOLID QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;;\n1F66B;SOLID QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;;\n1F66C;LEFTWARDS ROCKET;So;0;ON;;;;;N;;;;;\n1F66D;UPWARDS ROCKET;So;0;ON;;;;;N;;;;;\n1F66E;RIGHTWARDS ROCKET;So;0;ON;;;;;N;;;;;\n1F66F;DOWNWARDS ROCKET;So;0;ON;;;;;N;;;;;\n1F670;SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;;\n1F671;HEAVY SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;;\n1F672;LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;;\n1F673;HEAVY LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;;\n1F674;HEAVY AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;;\n1F675;SWASH AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;;\n1F676;SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n1F677;SANS-SERIF HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n1F678;SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;\n1F679;HEAVY INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;;\n1F67A;SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;;\n1F67B;HEAVY SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;;\n1F67C;VERY HEAVY SOLIDUS;So;0;ON;;;;;N;;;;;\n1F67D;VERY HEAVY REVERSE SOLIDUS;So;0;ON;;;;;N;;;;;\n1F67E;CHECKER BOARD;So;0;ON;;;;;N;;;;;\n1F67F;REVERSE CHECKER BOARD;So;0;ON;;;;;N;;;;;\n1F680;ROCKET;So;0;ON;;;;;N;;;;;\n1F681;HELICOPTER;So;0;ON;;;;;N;;;;;\n1F682;STEAM LOCOMOTIVE;So;0;ON;;;;;N;;;;;\n1F683;RAILWAY CAR;So;0;ON;;;;;N;;;;;\n1F684;HIGH-SPEED TRAIN;So;0;ON;;;;;N;;;;;\n1F685;HIGH-SPEED TRAIN WITH BULLET NOSE;So;0;ON;;;;;N;;;;;\n1F686;TRAIN;So;0;ON;;;;;N;;;;;\n1F687;METRO;So;0;ON;;;;;N;;;;;\n1F688;LIGHT RAIL;So;0;ON;;;;;N;;;;;\n1F689;STATION;So;0;ON;;;;;N;;;;;\n1F68A;TRAM;So;0;ON;;;;;N;;;;;\n1F68B;TRAM CAR;So;0;ON;;;;;N;;;;;\n1F68C;BUS;So;0;ON;;;;;N;;;;;\n1F68D;ONCOMING BUS;So;0;ON;;;;;N;;;;;\n1F68E;TROLLEYBUS;So;0;ON;;;;;N;;;;;\n1F68F;BUS STOP;So;0;ON;;;;;N;;;;;\n1F690;MINIBUS;So;0;ON;;;;;N;;;;;\n1F691;AMBULANCE;So;0;ON;;;;;N;;;;;\n1F692;FIRE ENGINE;So;0;ON;;;;;N;;;;;\n1F693;POLICE CAR;So;0;ON;;;;;N;;;;;\n1F694;ONCOMING POLICE CAR;So;0;ON;;;;;N;;;;;\n1F695;TAXI;So;0;ON;;;;;N;;;;;\n1F696;ONCOMING TAXI;So;0;ON;;;;;N;;;;;\n1F697;AUTOMOBILE;So;0;ON;;;;;N;;;;;\n1F698;ONCOMING AUTOMOBILE;So;0;ON;;;;;N;;;;;\n1F699;RECREATIONAL VEHICLE;So;0;ON;;;;;N;;;;;\n1F69A;DELIVERY TRUCK;So;0;ON;;;;;N;;;;;\n1F69B;ARTICULATED LORRY;So;0;ON;;;;;N;;;;;\n1F69C;TRACTOR;So;0;ON;;;;;N;;;;;\n1F69D;MONORAIL;So;0;ON;;;;;N;;;;;\n1F69E;MOUNTAIN RAILWAY;So;0;ON;;;;;N;;;;;\n1F69F;SUSPENSION RAILWAY;So;0;ON;;;;;N;;;;;\n1F6A0;MOUNTAIN CABLEWAY;So;0;ON;;;;;N;;;;;\n1F6A1;AERIAL TRAMWAY;So;0;ON;;;;;N;;;;;\n1F6A2;SHIP;So;0;ON;;;;;N;;;;;\n1F6A3;ROWBOAT;So;0;ON;;;;;N;;;;;\n1F6A4;SPEEDBOAT;So;0;ON;;;;;N;;;;;\n1F6A5;HORIZONTAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;;\n1F6A6;VERTICAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;;\n1F6A7;CONSTRUCTION SIGN;So;0;ON;;;;;N;;;;;\n1F6A8;POLICE CARS REVOLVING LIGHT;So;0;ON;;;;;N;;;;;\n1F6A9;TRIANGULAR FLAG ON POST;So;0;ON;;;;;N;;;;;\n1F6AA;DOOR;So;0;ON;;;;;N;;;;;\n1F6AB;NO ENTRY SIGN;So;0;ON;;;;;N;;;;;\n1F6AC;SMOKING SYMBOL;So;0;ON;;;;;N;;;;;\n1F6AD;NO SMOKING SYMBOL;So;0;ON;;;;;N;;;;;\n1F6AE;PUT LITTER IN ITS PLACE SYMBOL;So;0;ON;;;;;N;;;;;\n1F6AF;DO NOT LITTER SYMBOL;So;0;ON;;;;;N;;;;;\n1F6B0;POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;;\n1F6B1;NON-POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;;\n1F6B2;BICYCLE;So;0;ON;;;;;N;;;;;\n1F6B3;NO BICYCLES;So;0;ON;;;;;N;;;;;\n1F6B4;BICYCLIST;So;0;ON;;;;;N;;;;;\n1F6B5;MOUNTAIN BICYCLIST;So;0;ON;;;;;N;;;;;\n1F6B6;PEDESTRIAN;So;0;ON;;;;;N;;;;;\n1F6B7;NO PEDESTRIANS;So;0;ON;;;;;N;;;;;\n1F6B8;CHILDREN CROSSING;So;0;ON;;;;;N;;;;;\n1F6B9;MENS SYMBOL;So;0;ON;;;;;N;;;;;\n1F6BA;WOMENS SYMBOL;So;0;ON;;;;;N;;;;;\n1F6BB;RESTROOM;So;0;ON;;;;;N;;;;;\n1F6BC;BABY SYMBOL;So;0;ON;;;;;N;;;;;\n1F6BD;TOILET;So;0;ON;;;;;N;;;;;\n1F6BE;WATER CLOSET;So;0;ON;;;;;N;;;;;\n1F6BF;SHOWER;So;0;ON;;;;;N;;;;;\n1F6C0;BATH;So;0;ON;;;;;N;;;;;\n1F6C1;BATHTUB;So;0;ON;;;;;N;;;;;\n1F6C2;PASSPORT CONTROL;So;0;ON;;;;;N;;;;;\n1F6C3;CUSTOMS;So;0;ON;;;;;N;;;;;\n1F6C4;BAGGAGE CLAIM;So;0;ON;;;;;N;;;;;\n1F6C5;LEFT LUGGAGE;So;0;ON;;;;;N;;;;;\n1F6C6;TRIANGLE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;\n1F6C7;PROHIBITED SIGN;So;0;ON;;;;;N;;;;;\n1F6C8;CIRCLED INFORMATION SOURCE;So;0;ON;;;;;N;;;;;\n1F6C9;BOYS SYMBOL;So;0;ON;;;;;N;;;;;\n1F6CA;GIRLS SYMBOL;So;0;ON;;;;;N;;;;;\n1F6CB;COUCH AND LAMP;So;0;ON;;;;;N;;;;;\n1F6CC;SLEEPING ACCOMMODATION;So;0;ON;;;;;N;;;;;\n1F6CD;SHOPPING BAGS;So;0;ON;;;;;N;;;;;\n1F6CE;BELLHOP BELL;So;0;ON;;;;;N;;;;;\n1F6CF;BED;So;0;ON;;;;;N;;;;;\n1F6D0;PLACE OF WORSHIP;So;0;ON;;;;;N;;;;;\n1F6D1;OCTAGONAL SIGN;So;0;ON;;;;;N;;;;;\n1F6D2;SHOPPING TROLLEY;So;0;ON;;;;;N;;;;;\n1F6D3;STUPA;So;0;ON;;;;;N;;;;;\n1F6D4;PAGODA;So;0;ON;;;;;N;;;;;\n1F6D5;HINDU TEMPLE;So;0;ON;;;;;N;;;;;\n1F6D6;HUT;So;0;ON;;;;;N;;;;;\n1F6D7;ELEVATOR;So;0;ON;;;;;N;;;;;\n1F6D8;LANDSLIDE;So;0;ON;;;;;N;;;;;\n1F6DC;WIRELESS;So;0;ON;;;;;N;;;;;\n1F6DD;PLAYGROUND SLIDE;So;0;ON;;;;;N;;;;;\n1F6DE;WHEEL;So;0;ON;;;;;N;;;;;\n1F6DF;RING BUOY;So;0;ON;;;;;N;;;;;\n1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;;\n1F6E1;SHIELD;So;0;ON;;;;;N;;;;;\n1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;;\n1F6E3;MOTORWAY;So;0;ON;;;;;N;;;;;\n1F6E4;RAILWAY TRACK;So;0;ON;;;;;N;;;;;\n1F6E5;MOTOR BOAT;So;0;ON;;;;;N;;;;;\n1F6E6;UP-POINTING MILITARY AIRPLANE;So;0;ON;;;;;N;;;;;\n1F6E7;UP-POINTING AIRPLANE;So;0;ON;;;;;N;;;;;\n1F6E8;UP-POINTING SMALL AIRPLANE;So;0;ON;;;;;N;;;;;\n1F6E9;SMALL AIRPLANE;So;0;ON;;;;;N;;;;;\n1F6EA;NORTHEAST-POINTING AIRPLANE;So;0;ON;;;;;N;;;;;\n1F6EB;AIRPLANE DEPARTURE;So;0;ON;;;;;N;;;;;\n1F6EC;AIRPLANE ARRIVING;So;0;ON;;;;;N;;;;;\n1F6F0;SATELLITE;So;0;ON;;;;;N;;;;;\n1F6F1;ONCOMING FIRE ENGINE;So;0;ON;;;;;N;;;;;\n1F6F2;DIESEL LOCOMOTIVE;So;0;ON;;;;;N;;;;;\n1F6F3;PASSENGER SHIP;So;0;ON;;;;;N;;;;;\n1F6F4;SCOOTER;So;0;ON;;;;;N;;;;;\n1F6F5;MOTOR SCOOTER;So;0;ON;;;;;N;;;;;\n1F6F6;CANOE;So;0;ON;;;;;N;;;;;\n1F6F7;SLED;So;0;ON;;;;;N;;;;;\n1F6F8;FLYING SAUCER;So;0;ON;;;;;N;;;;;\n1F6F9;SKATEBOARD;So;0;ON;;;;;N;;;;;\n1F6FA;AUTO RICKSHAW;So;0;ON;;;;;N;;;;;\n1F6FB;PICKUP TRUCK;So;0;ON;;;;;N;;;;;\n1F6FC;ROLLER SKATE;So;0;ON;;;;;N;;;;;\n1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;;\n1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;;\n1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;;\n1F703;ALCHEMICAL SYMBOL FOR EARTH;So;0;ON;;;;;N;;;;;\n1F704;ALCHEMICAL SYMBOL FOR WATER;So;0;ON;;;;;N;;;;;\n1F705;ALCHEMICAL SYMBOL FOR AQUAFORTIS;So;0;ON;;;;;N;;;;;\n1F706;ALCHEMICAL SYMBOL FOR AQUA REGIA;So;0;ON;;;;;N;;;;;\n1F707;ALCHEMICAL SYMBOL FOR AQUA REGIA-2;So;0;ON;;;;;N;;;;;\n1F708;ALCHEMICAL SYMBOL FOR AQUA VITAE;So;0;ON;;;;;N;;;;;\n1F709;ALCHEMICAL SYMBOL FOR AQUA VITAE-2;So;0;ON;;;;;N;;;;;\n1F70A;ALCHEMICAL SYMBOL FOR VINEGAR;So;0;ON;;;;;N;;;;;\n1F70B;ALCHEMICAL SYMBOL FOR VINEGAR-2;So;0;ON;;;;;N;;;;;\n1F70C;ALCHEMICAL SYMBOL FOR VINEGAR-3;So;0;ON;;;;;N;;;;;\n1F70D;ALCHEMICAL SYMBOL FOR SULFUR;So;0;ON;;;;;N;;;;;\n1F70E;ALCHEMICAL SYMBOL FOR PHILOSOPHERS SULFUR;So;0;ON;;;;;N;;;;;\n1F70F;ALCHEMICAL SYMBOL FOR BLACK SULFUR;So;0;ON;;;;;N;;;;;\n1F710;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE;So;0;ON;;;;;N;;;;;\n1F711;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-2;So;0;ON;;;;;N;;;;;\n1F712;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-3;So;0;ON;;;;;N;;;;;\n1F713;ALCHEMICAL SYMBOL FOR CINNABAR;So;0;ON;;;;;N;;;;;\n1F714;ALCHEMICAL SYMBOL FOR SALT;So;0;ON;;;;;N;;;;;\n1F715;ALCHEMICAL SYMBOL FOR NITRE;So;0;ON;;;;;N;;;;;\n1F716;ALCHEMICAL SYMBOL FOR VITRIOL;So;0;ON;;;;;N;;;;;\n1F717;ALCHEMICAL SYMBOL FOR VITRIOL-2;So;0;ON;;;;;N;;;;;\n1F718;ALCHEMICAL SYMBOL FOR ROCK SALT;So;0;ON;;;;;N;;;;;\n1F719;ALCHEMICAL SYMBOL FOR ROCK SALT-2;So;0;ON;;;;;N;;;;;\n1F71A;ALCHEMICAL SYMBOL FOR GOLD;So;0;ON;;;;;N;;;;;\n1F71B;ALCHEMICAL SYMBOL FOR SILVER;So;0;ON;;;;;N;;;;;\n1F71C;ALCHEMICAL SYMBOL FOR IRON ORE;So;0;ON;;;;;N;;;;;\n1F71D;ALCHEMICAL SYMBOL FOR IRON ORE-2;So;0;ON;;;;;N;;;;;\n1F71E;ALCHEMICAL SYMBOL FOR CROCUS OF IRON;So;0;ON;;;;;N;;;;;\n1F71F;ALCHEMICAL SYMBOL FOR REGULUS OF IRON;So;0;ON;;;;;N;;;;;\n1F720;ALCHEMICAL SYMBOL FOR COPPER ORE;So;0;ON;;;;;N;;;;;\n1F721;ALCHEMICAL SYMBOL FOR IRON-COPPER ORE;So;0;ON;;;;;N;;;;;\n1F722;ALCHEMICAL SYMBOL FOR SUBLIMATE OF COPPER;So;0;ON;;;;;N;;;;;\n1F723;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER;So;0;ON;;;;;N;;;;;\n1F724;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER-2;So;0;ON;;;;;N;;;;;\n1F725;ALCHEMICAL SYMBOL FOR COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;;\n1F726;ALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;;\n1F727;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF COPPER;So;0;ON;;;;;N;;;;;\n1F728;ALCHEMICAL SYMBOL FOR VERDIGRIS;So;0;ON;;;;;N;;;;;\n1F729;ALCHEMICAL SYMBOL FOR TIN ORE;So;0;ON;;;;;N;;;;;\n1F72A;ALCHEMICAL SYMBOL FOR LEAD ORE;So;0;ON;;;;;N;;;;;\n1F72B;ALCHEMICAL SYMBOL FOR ANTIMONY ORE;So;0;ON;;;;;N;;;;;\n1F72C;ALCHEMICAL SYMBOL FOR SUBLIMATE OF ANTIMONY;So;0;ON;;;;;N;;;;;\n1F72D;ALCHEMICAL SYMBOL FOR SALT OF ANTIMONY;So;0;ON;;;;;N;;;;;\n1F72E;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF ANTIMONY;So;0;ON;;;;;N;;;;;\n1F72F;ALCHEMICAL SYMBOL FOR VINEGAR OF ANTIMONY;So;0;ON;;;;;N;;;;;\n1F730;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY;So;0;ON;;;;;N;;;;;\n1F731;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY-2;So;0;ON;;;;;N;;;;;\n1F732;ALCHEMICAL SYMBOL FOR REGULUS;So;0;ON;;;;;N;;;;;\n1F733;ALCHEMICAL SYMBOL FOR REGULUS-2;So;0;ON;;;;;N;;;;;\n1F734;ALCHEMICAL SYMBOL FOR REGULUS-3;So;0;ON;;;;;N;;;;;\n1F735;ALCHEMICAL SYMBOL FOR REGULUS-4;So;0;ON;;;;;N;;;;;\n1F736;ALCHEMICAL SYMBOL FOR ALKALI;So;0;ON;;;;;N;;;;;\n1F737;ALCHEMICAL SYMBOL FOR ALKALI-2;So;0;ON;;;;;N;;;;;\n1F738;ALCHEMICAL SYMBOL FOR MARCASITE;So;0;ON;;;;;N;;;;;\n1F739;ALCHEMICAL SYMBOL FOR SAL-AMMONIAC;So;0;ON;;;;;N;;;;;\n1F73A;ALCHEMICAL SYMBOL FOR ARSENIC;So;0;ON;;;;;N;;;;;\n1F73B;ALCHEMICAL SYMBOL FOR REALGAR;So;0;ON;;;;;N;;;;;\n1F73C;ALCHEMICAL SYMBOL FOR REALGAR-2;So;0;ON;;;;;N;;;;;\n1F73D;ALCHEMICAL SYMBOL FOR AURIPIGMENT;So;0;ON;;;;;N;;;;;\n1F73E;ALCHEMICAL SYMBOL FOR BISMUTH ORE;So;0;ON;;;;;N;;;;;\n1F73F;ALCHEMICAL SYMBOL FOR TARTAR;So;0;ON;;;;;N;;;;;\n1F740;ALCHEMICAL SYMBOL FOR TARTAR-2;So;0;ON;;;;;N;;;;;\n1F741;ALCHEMICAL SYMBOL FOR QUICK LIME;So;0;ON;;;;;N;;;;;\n1F742;ALCHEMICAL SYMBOL FOR BORAX;So;0;ON;;;;;N;;;;;\n1F743;ALCHEMICAL SYMBOL FOR BORAX-2;So;0;ON;;;;;N;;;;;\n1F744;ALCHEMICAL SYMBOL FOR BORAX-3;So;0;ON;;;;;N;;;;;\n1F745;ALCHEMICAL SYMBOL FOR ALUM;So;0;ON;;;;;N;;;;;\n1F746;ALCHEMICAL SYMBOL FOR OIL;So;0;ON;;;;;N;;;;;\n1F747;ALCHEMICAL SYMBOL FOR SPIRIT;So;0;ON;;;;;N;;;;;\n1F748;ALCHEMICAL SYMBOL FOR TINCTURE;So;0;ON;;;;;N;;;;;\n1F749;ALCHEMICAL SYMBOL FOR GUM;So;0;ON;;;;;N;;;;;\n1F74A;ALCHEMICAL SYMBOL FOR WAX;So;0;ON;;;;;N;;;;;\n1F74B;ALCHEMICAL SYMBOL FOR POWDER;So;0;ON;;;;;N;;;;;\n1F74C;ALCHEMICAL SYMBOL FOR CALX;So;0;ON;;;;;N;;;;;\n1F74D;ALCHEMICAL SYMBOL FOR TUTTY;So;0;ON;;;;;N;;;;;\n1F74E;ALCHEMICAL SYMBOL FOR CAPUT MORTUUM;So;0;ON;;;;;N;;;;;\n1F74F;ALCHEMICAL SYMBOL FOR SCEPTER OF JOVE;So;0;ON;;;;;N;;;;;\n1F750;ALCHEMICAL SYMBOL FOR CADUCEUS;So;0;ON;;;;;N;;;;;\n1F751;ALCHEMICAL SYMBOL FOR TRIDENT;So;0;ON;;;;;N;;;;;\n1F752;ALCHEMICAL SYMBOL FOR STARRED TRIDENT;So;0;ON;;;;;N;;;;;\n1F753;ALCHEMICAL SYMBOL FOR LODESTONE;So;0;ON;;;;;N;;;;;\n1F754;ALCHEMICAL SYMBOL FOR SOAP;So;0;ON;;;;;N;;;;;\n1F755;ALCHEMICAL SYMBOL FOR URINE;So;0;ON;;;;;N;;;;;\n1F756;ALCHEMICAL SYMBOL FOR HORSE DUNG;So;0;ON;;;;;N;;;;;\n1F757;ALCHEMICAL SYMBOL FOR ASHES;So;0;ON;;;;;N;;;;;\n1F758;ALCHEMICAL SYMBOL FOR POT ASHES;So;0;ON;;;;;N;;;;;\n1F759;ALCHEMICAL SYMBOL FOR BRICK;So;0;ON;;;;;N;;;;;\n1F75A;ALCHEMICAL SYMBOL FOR POWDERED BRICK;So;0;ON;;;;;N;;;;;\n1F75B;ALCHEMICAL SYMBOL FOR AMALGAM;So;0;ON;;;;;N;;;;;\n1F75C;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM;So;0;ON;;;;;N;;;;;\n1F75D;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM-2;So;0;ON;;;;;N;;;;;\n1F75E;ALCHEMICAL SYMBOL FOR SUBLIMATION;So;0;ON;;;;;N;;;;;\n1F75F;ALCHEMICAL SYMBOL FOR PRECIPITATE;So;0;ON;;;;;N;;;;;\n1F760;ALCHEMICAL SYMBOL FOR DISTILL;So;0;ON;;;;;N;;;;;\n1F761;ALCHEMICAL SYMBOL FOR DISSOLVE;So;0;ON;;;;;N;;;;;\n1F762;ALCHEMICAL SYMBOL FOR DISSOLVE-2;So;0;ON;;;;;N;;;;;\n1F763;ALCHEMICAL SYMBOL FOR PURIFY;So;0;ON;;;;;N;;;;;\n1F764;ALCHEMICAL SYMBOL FOR PUTREFACTION;So;0;ON;;;;;N;;;;;\n1F765;ALCHEMICAL SYMBOL FOR CRUCIBLE;So;0;ON;;;;;N;;;;;\n1F766;ALCHEMICAL SYMBOL FOR CRUCIBLE-2;So;0;ON;;;;;N;;;;;\n1F767;ALCHEMICAL SYMBOL FOR CRUCIBLE-3;So;0;ON;;;;;N;;;;;\n1F768;ALCHEMICAL SYMBOL FOR CRUCIBLE-4;So;0;ON;;;;;N;;;;;\n1F769;ALCHEMICAL SYMBOL FOR CRUCIBLE-5;So;0;ON;;;;;N;;;;;\n1F76A;ALCHEMICAL SYMBOL FOR ALEMBIC;So;0;ON;;;;;N;;;;;\n1F76B;ALCHEMICAL SYMBOL FOR BATH OF MARY;So;0;ON;;;;;N;;;;;\n1F76C;ALCHEMICAL SYMBOL FOR BATH OF VAPOURS;So;0;ON;;;;;N;;;;;\n1F76D;ALCHEMICAL SYMBOL FOR RETORT;So;0;ON;;;;;N;;;;;\n1F76E;ALCHEMICAL SYMBOL FOR HOUR;So;0;ON;;;;;N;;;;;\n1F76F;ALCHEMICAL SYMBOL FOR NIGHT;So;0;ON;;;;;N;;;;;\n1F770;ALCHEMICAL SYMBOL FOR DAY-NIGHT;So;0;ON;;;;;N;;;;;\n1F771;ALCHEMICAL SYMBOL FOR MONTH;So;0;ON;;;;;N;;;;;\n1F772;ALCHEMICAL SYMBOL FOR HALF DRAM;So;0;ON;;;;;N;;;;;\n1F773;ALCHEMICAL SYMBOL FOR HALF OUNCE;So;0;ON;;;;;N;;;;;\n1F774;LOT OF FORTUNE;So;0;ON;;;;;N;;;;;\n1F775;OCCULTATION;So;0;ON;;;;;N;;;;;\n1F776;LUNAR ECLIPSE;So;0;ON;;;;;N;;;;;\n1F777;VESTA FORM TWO;So;0;ON;;;;;N;;;;;\n1F778;ASTRAEA FORM TWO;So;0;ON;;;;;N;;;;;\n1F779;HYGIEA FORM TWO;So;0;ON;;;;;N;;;;;\n1F77A;PARTHENOPE FORM TWO;So;0;ON;;;;;N;;;;;\n1F77B;HAUMEA;So;0;ON;;;;;N;;;;;\n1F77C;MAKEMAKE;So;0;ON;;;;;N;;;;;\n1F77D;GONGGONG;So;0;ON;;;;;N;;;;;\n1F77E;QUAOAR;So;0;ON;;;;;N;;;;;\n1F77F;ORCUS;So;0;ON;;;;;N;;;;;\n1F780;BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;\n1F781;BLACK UP-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;\n1F782;BLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;\n1F783;BLACK DOWN-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;\n1F784;BLACK SLIGHTLY SMALL CIRCLE;So;0;ON;;;;;N;;;;;\n1F785;MEDIUM BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1F786;BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1F787;HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1F788;VERY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1F789;EXTREMELY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1F78A;WHITE CIRCLE CONTAINING BLACK SMALL CIRCLE;So;0;ON;;;;;N;;;;;\n1F78B;ROUND TARGET;So;0;ON;;;;;N;;;;;\n1F78C;BLACK TINY SQUARE;So;0;ON;;;;;N;;;;;\n1F78D;BLACK SLIGHTLY SMALL SQUARE;So;0;ON;;;;;N;;;;;\n1F78E;LIGHT WHITE SQUARE;So;0;ON;;;;;N;;;;;\n1F78F;MEDIUM WHITE SQUARE;So;0;ON;;;;;N;;;;;\n1F790;BOLD WHITE SQUARE;So;0;ON;;;;;N;;;;;\n1F791;HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;;\n1F792;VERY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;;\n1F793;EXTREMELY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;;\n1F794;WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;;\n1F795;WHITE SQUARE CONTAINING BLACK MEDIUM SQUARE;So;0;ON;;;;;N;;;;;\n1F796;SQUARE TARGET;So;0;ON;;;;;N;;;;;\n1F797;BLACK TINY DIAMOND;So;0;ON;;;;;N;;;;;\n1F798;BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;;\n1F799;BLACK MEDIUM SMALL DIAMOND;So;0;ON;;;;;N;;;;;\n1F79A;WHITE DIAMOND CONTAINING BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;;\n1F79B;WHITE DIAMOND CONTAINING BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;;\n1F79C;DIAMOND TARGET;So;0;ON;;;;;N;;;;;\n1F79D;BLACK TINY LOZENGE;So;0;ON;;;;;N;;;;;\n1F79E;BLACK VERY SMALL LOZENGE;So;0;ON;;;;;N;;;;;\n1F79F;BLACK MEDIUM SMALL LOZENGE;So;0;ON;;;;;N;;;;;\n1F7A0;WHITE LOZENGE CONTAINING BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;;\n1F7A1;THIN GREEK CROSS;So;0;ON;;;;;N;;;;;\n1F7A2;LIGHT GREEK CROSS;So;0;ON;;;;;N;;;;;\n1F7A3;MEDIUM GREEK CROSS;So;0;ON;;;;;N;;;;;\n1F7A4;BOLD GREEK CROSS;So;0;ON;;;;;N;;;;;\n1F7A5;VERY BOLD GREEK CROSS;So;0;ON;;;;;N;;;;;\n1F7A6;VERY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;\n1F7A7;EXTREMELY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;\n1F7A8;THIN SALTIRE;So;0;ON;;;;;N;;;;;\n1F7A9;LIGHT SALTIRE;So;0;ON;;;;;N;;;;;\n1F7AA;MEDIUM SALTIRE;So;0;ON;;;;;N;;;;;\n1F7AB;BOLD SALTIRE;So;0;ON;;;;;N;;;;;\n1F7AC;HEAVY SALTIRE;So;0;ON;;;;;N;;;;;\n1F7AD;VERY HEAVY SALTIRE;So;0;ON;;;;;N;;;;;\n1F7AE;EXTREMELY HEAVY SALTIRE;So;0;ON;;;;;N;;;;;\n1F7AF;LIGHT FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B0;MEDIUM FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B1;BOLD FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B2;HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B3;VERY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B4;EXTREMELY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B5;LIGHT SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B6;MEDIUM SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B7;BOLD SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B8;HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7B9;VERY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7BA;EXTREMELY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7BB;LIGHT EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7BC;MEDIUM EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7BD;BOLD EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7BE;HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7BF;VERY HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;\n1F7C0;LIGHT THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7C1;MEDIUM THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7C2;THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7C3;MEDIUM THREE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;\n1F7C4;LIGHT FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7C5;MEDIUM FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7C6;FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7C7;MEDIUM FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;\n1F7C8;REVERSE LIGHT FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;\n1F7C9;LIGHT FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7CA;HEAVY FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7CB;MEDIUM SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7CC;HEAVY SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7CD;SIX POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;\n1F7CE;MEDIUM EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7CF;HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7D0;VERY HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7D1;HEAVY EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;\n1F7D2;LIGHT TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7D3;HEAVY TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;\n1F7D4;HEAVY TWELVE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;\n1F7D5;CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;;\n1F7D6;NEGATIVE CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;;\n1F7D7;CIRCLED SQUARE;So;0;ON;;;;;N;;;;;\n1F7D8;NEGATIVE CIRCLED SQUARE;So;0;ON;;;;;N;;;;;\n1F7D9;NINE POINTED WHITE STAR;So;0;ON;;;;;N;;;;;\n1F7E0;LARGE ORANGE CIRCLE;So;0;ON;;;;;N;;;;;\n1F7E1;LARGE YELLOW CIRCLE;So;0;ON;;;;;N;;;;;\n1F7E2;LARGE GREEN CIRCLE;So;0;ON;;;;;N;;;;;\n1F7E3;LARGE PURPLE CIRCLE;So;0;ON;;;;;N;;;;;\n1F7E4;LARGE BROWN CIRCLE;So;0;ON;;;;;N;;;;;\n1F7E5;LARGE RED SQUARE;So;0;ON;;;;;N;;;;;\n1F7E6;LARGE BLUE SQUARE;So;0;ON;;;;;N;;;;;\n1F7E7;LARGE ORANGE SQUARE;So;0;ON;;;;;N;;;;;\n1F7E8;LARGE YELLOW SQUARE;So;0;ON;;;;;N;;;;;\n1F7E9;LARGE GREEN SQUARE;So;0;ON;;;;;N;;;;;\n1F7EA;LARGE PURPLE SQUARE;So;0;ON;;;;;N;;;;;\n1F7EB;LARGE BROWN SQUARE;So;0;ON;;;;;N;;;;;\n1F7F0;HEAVY EQUALS SIGN;So;0;ON;;;;;N;;;;;\n1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F803;DOWNWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F804;LEFTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F805;UPWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F806;RIGHTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F807;DOWNWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F808;LEFTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F809;UPWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F80A;RIGHTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F80B;DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F810;LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F811;UPWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F812;RIGHTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F813;DOWNWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F814;LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F815;UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F816;RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F817;DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F818;HEAVY LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F819;HEAVY UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F81A;HEAVY RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F81B;HEAVY DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F81C;HEAVY LEFTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F81D;HEAVY UPWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F81E;HEAVY RIGHTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F81F;HEAVY DOWNWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F820;LEFTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;;\n1F821;UPWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;;\n1F822;RIGHTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;;\n1F823;DOWNWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;;\n1F824;LEFTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;;\n1F825;UPWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;;\n1F826;RIGHTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;;\n1F827;DOWNWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;;\n1F828;LEFTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;;\n1F829;UPWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;;\n1F82A;RIGHTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;;\n1F82B;DOWNWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;;\n1F82C;LEFTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;;\n1F82D;UPWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;;\n1F82E;RIGHTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;;\n1F82F;DOWNWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;;\n1F830;LEFTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;;\n1F831;UPWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;;\n1F832;RIGHTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;;\n1F833;DOWNWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;;\n1F834;LEFTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;;\n1F835;UPWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;;\n1F836;RIGHTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;;\n1F837;DOWNWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;;\n1F838;LEFTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;;\n1F839;UPWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;;\n1F83A;RIGHTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;;\n1F83B;DOWNWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;;\n1F83C;LEFTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;;\n1F83D;UPWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;;\n1F83E;RIGHTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;;\n1F83F;DOWNWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;;\n1F840;LEFTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;;\n1F841;UPWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;;\n1F842;RIGHTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;;\n1F843;DOWNWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;;\n1F844;LEFTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;;\n1F845;UPWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;;\n1F846;RIGHTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;;\n1F847;DOWNWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;;\n1F850;LEFTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F851;UPWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F852;RIGHTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F853;DOWNWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F854;NORTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F855;NORTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F856;SOUTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F857;SOUTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F858;LEFT RIGHT SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F859;UP DOWN SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;\n1F860;WIDE-HEADED LEFTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;\n1F861;WIDE-HEADED UPWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;\n1F862;WIDE-HEADED RIGHTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;\n1F863;WIDE-HEADED DOWNWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;\n1F864;WIDE-HEADED NORTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;\n1F865;WIDE-HEADED NORTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;\n1F866;WIDE-HEADED SOUTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;\n1F867;WIDE-HEADED SOUTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;\n1F868;WIDE-HEADED LEFTWARDS BARB ARROW;So;0;ON;;;;;N;;;;;\n1F869;WIDE-HEADED UPWARDS BARB ARROW;So;0;ON;;;;;N;;;;;\n1F86A;WIDE-HEADED RIGHTWARDS BARB ARROW;So;0;ON;;;;;N;;;;;\n1F86B;WIDE-HEADED DOWNWARDS BARB ARROW;So;0;ON;;;;;N;;;;;\n1F86C;WIDE-HEADED NORTH WEST BARB ARROW;So;0;ON;;;;;N;;;;;\n1F86D;WIDE-HEADED NORTH EAST BARB ARROW;So;0;ON;;;;;N;;;;;\n1F86E;WIDE-HEADED SOUTH EAST BARB ARROW;So;0;ON;;;;;N;;;;;\n1F86F;WIDE-HEADED SOUTH WEST BARB ARROW;So;0;ON;;;;;N;;;;;\n1F870;WIDE-HEADED LEFTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;\n1F871;WIDE-HEADED UPWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;\n1F872;WIDE-HEADED RIGHTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;\n1F873;WIDE-HEADED DOWNWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;\n1F874;WIDE-HEADED NORTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;\n1F875;WIDE-HEADED NORTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;\n1F876;WIDE-HEADED SOUTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;\n1F877;WIDE-HEADED SOUTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;\n1F878;WIDE-HEADED LEFTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F879;WIDE-HEADED UPWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F87A;WIDE-HEADED RIGHTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F87B;WIDE-HEADED DOWNWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F87C;WIDE-HEADED NORTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F87D;WIDE-HEADED NORTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F87E;WIDE-HEADED SOUTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F87F;WIDE-HEADED SOUTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F880;WIDE-HEADED LEFTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F881;WIDE-HEADED UPWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F882;WIDE-HEADED RIGHTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F883;WIDE-HEADED DOWNWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F884;WIDE-HEADED NORTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F885;WIDE-HEADED NORTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F886;WIDE-HEADED SOUTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F887;WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;\n1F890;LEFTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F891;UPWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F892;RIGHTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F893;DOWNWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F894;LEFTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F895;UPWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F896;RIGHTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F897;DOWNWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;\n1F898;LEFTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;;\n1F899;UPWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;;\n1F89A;RIGHTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;;\n1F89B;DOWNWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;;\n1F89C;HEAVY ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;;\n1F89D;HEAVY ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;;\n1F89E;HEAVY ARROW SHAFT WIDTH ONE HALF;So;0;ON;;;;;N;;;;;\n1F89F;HEAVY ARROW SHAFT WIDTH ONE THIRD;So;0;ON;;;;;N;;;;;\n1F8A0;LEFTWARDS BOTTOM-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A1;RIGHTWARDS BOTTOM SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A2;LEFTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A3;RIGHTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A4;LEFTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A5;RIGHTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A6;LEFTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A7;RIGHTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A8;LEFTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8A9;RIGHTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8AA;LEFTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;\n1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;;\n1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;;\n1F8B0;ARROW POINTING UPWARDS THEN NORTH WEST;So;0;ON;;;;;N;;;;;\n1F8B1;ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST;So;0;ON;;;;;N;;;;;\n1F8B2;RIGHTWARDS ARROW WITH LOWER HOOK;So;0;ON;;;;;N;;;;;\n1F8B3;DOWNWARDS BLACK ARROW TO BAR;So;0;ON;;;;;N;;;;;\n1F8B4;NEGATIVE SQUARED LEFTWARDS ARROW;So;0;ON;;;;;N;;;;;\n1F8B5;NEGATIVE SQUARED UPWARDS ARROW;So;0;ON;;;;;N;;;;;\n1F8B6;NEGATIVE SQUARED RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;;\n1F8B7;NEGATIVE SQUARED DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;\n1F8B8;NORTH WEST ARROW FROM BAR;So;0;ON;;;;;N;;;;;\n1F8B9;NORTH EAST ARROW FROM BAR;So;0;ON;;;;;N;;;;;\n1F8BA;SOUTH EAST ARROW FROM BAR;So;0;ON;;;;;N;;;;;\n1F8BB;SOUTH WEST ARROW FROM BAR;So;0;ON;;;;;N;;;;;\n1F8C0;LEFTWARDS ARROW FROM DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;\n1F8C1;RIGHTWARDS ARROW FROM DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;\n1F8D0;LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;\n1F8D1;LONG RIGHTWARDS HARPOON OVER LONG LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;\n1F8D2;LONG RIGHTWARDS HARPOON ABOVE SHORT LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;\n1F8D3;SHORT RIGHTWARDS HARPOON ABOVE LONG LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;\n1F8D4;LONG LEFTWARDS HARPOON ABOVE SHORT RIGHTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;\n1F8D5;SHORT LEFTWARDS HARPOON ABOVE LONG RIGHTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;\n1F8D6;LONG RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;;\n1F8D7;LONG RIGHTWARDS ARROW WITH DOUBLE SLASH;Sm;0;ON;;;;;N;;;;;\n1F8D8;LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE;Sm;0;ON;;;;;N;;;;;\n1F900;CIRCLED CROSS FORMEE WITH FOUR DOTS;So;0;ON;;;;;N;;;;;\n1F901;CIRCLED CROSS FORMEE WITH TWO DOTS;So;0;ON;;;;;N;;;;;\n1F902;CIRCLED CROSS FORMEE;So;0;ON;;;;;N;;;;;\n1F903;LEFT HALF CIRCLE WITH FOUR DOTS;So;0;ON;;;;;N;;;;;\n1F904;LEFT HALF CIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;;\n1F905;LEFT HALF CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;;\n1F906;LEFT HALF CIRCLE WITH DOT;So;0;ON;;;;;N;;;;;\n1F907;LEFT HALF CIRCLE;So;0;ON;;;;;N;;;;;\n1F908;DOWNWARD FACING HOOK;So;0;ON;;;;;N;;;;;\n1F909;DOWNWARD FACING NOTCHED HOOK;So;0;ON;;;;;N;;;;;\n1F90A;DOWNWARD FACING HOOK WITH DOT;So;0;ON;;;;;N;;;;;\n1F90B;DOWNWARD FACING NOTCHED HOOK WITH DOT;So;0;ON;;;;;N;;;;;\n1F90C;PINCHED FINGERS;So;0;ON;;;;;N;;;;;\n1F90D;WHITE HEART;So;0;ON;;;;;N;;;;;\n1F90E;BROWN HEART;So;0;ON;;;;;N;;;;;\n1F90F;PINCHING HAND;So;0;ON;;;;;N;;;;;\n1F910;ZIPPER-MOUTH FACE;So;0;ON;;;;;N;;;;;\n1F911;MONEY-MOUTH FACE;So;0;ON;;;;;N;;;;;\n1F912;FACE WITH THERMOMETER;So;0;ON;;;;;N;;;;;\n1F913;NERD FACE;So;0;ON;;;;;N;;;;;\n1F914;THINKING FACE;So;0;ON;;;;;N;;;;;\n1F915;FACE WITH HEAD-BANDAGE;So;0;ON;;;;;N;;;;;\n1F916;ROBOT FACE;So;0;ON;;;;;N;;;;;\n1F917;HUGGING FACE;So;0;ON;;;;;N;;;;;\n1F918;SIGN OF THE HORNS;So;0;ON;;;;;N;;;;;\n1F919;CALL ME HAND;So;0;ON;;;;;N;;;;;\n1F91A;RAISED BACK OF HAND;So;0;ON;;;;;N;;;;;\n1F91B;LEFT-FACING FIST;So;0;ON;;;;;N;;;;;\n1F91C;RIGHT-FACING FIST;So;0;ON;;;;;N;;;;;\n1F91D;HANDSHAKE;So;0;ON;;;;;N;;;;;\n1F91E;HAND WITH INDEX AND MIDDLE FINGERS CROSSED;So;0;ON;;;;;N;;;;;\n1F91F;I LOVE YOU HAND SIGN;So;0;ON;;;;;N;;;;;\n1F920;FACE WITH COWBOY HAT;So;0;ON;;;;;N;;;;;\n1F921;CLOWN FACE;So;0;ON;;;;;N;;;;;\n1F922;NAUSEATED FACE;So;0;ON;;;;;N;;;;;\n1F923;ROLLING ON THE FLOOR LAUGHING;So;0;ON;;;;;N;;;;;\n1F924;DROOLING FACE;So;0;ON;;;;;N;;;;;\n1F925;LYING FACE;So;0;ON;;;;;N;;;;;\n1F926;FACE PALM;So;0;ON;;;;;N;;;;;\n1F927;SNEEZING FACE;So;0;ON;;;;;N;;;;;\n1F928;FACE WITH ONE EYEBROW RAISED;So;0;ON;;;;;N;;;;;\n1F929;GRINNING FACE WITH STAR EYES;So;0;ON;;;;;N;;;;;\n1F92A;GRINNING FACE WITH ONE LARGE AND ONE SMALL EYE;So;0;ON;;;;;N;;;;;\n1F92B;FACE WITH FINGER COVERING CLOSED LIPS;So;0;ON;;;;;N;;;;;\n1F92C;SERIOUS FACE WITH SYMBOLS COVERING MOUTH;So;0;ON;;;;;N;;;;;\n1F92D;SMILING FACE WITH SMILING EYES AND HAND COVERING MOUTH;So;0;ON;;;;;N;;;;;\n1F92E;FACE WITH OPEN MOUTH VOMITING;So;0;ON;;;;;N;;;;;\n1F92F;SHOCKED FACE WITH EXPLODING HEAD;So;0;ON;;;;;N;;;;;\n1F930;PREGNANT WOMAN;So;0;ON;;;;;N;;;;;\n1F931;BREAST-FEEDING;So;0;ON;;;;;N;;;;;\n1F932;PALMS UP TOGETHER;So;0;ON;;;;;N;;;;;\n1F933;SELFIE;So;0;ON;;;;;N;;;;;\n1F934;PRINCE;So;0;ON;;;;;N;;;;;\n1F935;MAN IN TUXEDO;So;0;ON;;;;;N;;;;;\n1F936;MOTHER CHRISTMAS;So;0;ON;;;;;N;;;;;\n1F937;SHRUG;So;0;ON;;;;;N;;;;;\n1F938;PERSON DOING CARTWHEEL;So;0;ON;;;;;N;;;;;\n1F939;JUGGLING;So;0;ON;;;;;N;;;;;\n1F93A;FENCER;So;0;ON;;;;;N;;;;;\n1F93B;MODERN PENTATHLON;So;0;ON;;;;;N;;;;;\n1F93C;WRESTLERS;So;0;ON;;;;;N;;;;;\n1F93D;WATER POLO;So;0;ON;;;;;N;;;;;\n1F93E;HANDBALL;So;0;ON;;;;;N;;;;;\n1F93F;DIVING MASK;So;0;ON;;;;;N;;;;;\n1F940;WILTED FLOWER;So;0;ON;;;;;N;;;;;\n1F941;DRUM WITH DRUMSTICKS;So;0;ON;;;;;N;;;;;\n1F942;CLINKING GLASSES;So;0;ON;;;;;N;;;;;\n1F943;TUMBLER GLASS;So;0;ON;;;;;N;;;;;\n1F944;SPOON;So;0;ON;;;;;N;;;;;\n1F945;GOAL NET;So;0;ON;;;;;N;;;;;\n1F946;RIFLE;So;0;ON;;;;;N;;;;;\n1F947;FIRST PLACE MEDAL;So;0;ON;;;;;N;;;;;\n1F948;SECOND PLACE MEDAL;So;0;ON;;;;;N;;;;;\n1F949;THIRD PLACE MEDAL;So;0;ON;;;;;N;;;;;\n1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;;\n1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;;\n1F94C;CURLING STONE;So;0;ON;;;;;N;;;;;\n1F94D;LACROSSE STICK AND BALL;So;0;ON;;;;;N;;;;;\n1F94E;SOFTBALL;So;0;ON;;;;;N;;;;;\n1F94F;FLYING DISC;So;0;ON;;;;;N;;;;;\n1F950;CROISSANT;So;0;ON;;;;;N;;;;;\n1F951;AVOCADO;So;0;ON;;;;;N;;;;;\n1F952;CUCUMBER;So;0;ON;;;;;N;;;;;\n1F953;BACON;So;0;ON;;;;;N;;;;;\n1F954;POTATO;So;0;ON;;;;;N;;;;;\n1F955;CARROT;So;0;ON;;;;;N;;;;;\n1F956;BAGUETTE BREAD;So;0;ON;;;;;N;;;;;\n1F957;GREEN SALAD;So;0;ON;;;;;N;;;;;\n1F958;SHALLOW PAN OF FOOD;So;0;ON;;;;;N;;;;;\n1F959;STUFFED FLATBREAD;So;0;ON;;;;;N;;;;;\n1F95A;EGG;So;0;ON;;;;;N;;;;;\n1F95B;GLASS OF MILK;So;0;ON;;;;;N;;;;;\n1F95C;PEANUTS;So;0;ON;;;;;N;;;;;\n1F95D;KIWIFRUIT;So;0;ON;;;;;N;;;;;\n1F95E;PANCAKES;So;0;ON;;;;;N;;;;;\n1F95F;DUMPLING;So;0;ON;;;;;N;;;;;\n1F960;FORTUNE COOKIE;So;0;ON;;;;;N;;;;;\n1F961;TAKEOUT BOX;So;0;ON;;;;;N;;;;;\n1F962;CHOPSTICKS;So;0;ON;;;;;N;;;;;\n1F963;BOWL WITH SPOON;So;0;ON;;;;;N;;;;;\n1F964;CUP WITH STRAW;So;0;ON;;;;;N;;;;;\n1F965;COCONUT;So;0;ON;;;;;N;;;;;\n1F966;BROCCOLI;So;0;ON;;;;;N;;;;;\n1F967;PIE;So;0;ON;;;;;N;;;;;\n1F968;PRETZEL;So;0;ON;;;;;N;;;;;\n1F969;CUT OF MEAT;So;0;ON;;;;;N;;;;;\n1F96A;SANDWICH;So;0;ON;;;;;N;;;;;\n1F96B;CANNED FOOD;So;0;ON;;;;;N;;;;;\n1F96C;LEAFY GREEN;So;0;ON;;;;;N;;;;;\n1F96D;MANGO;So;0;ON;;;;;N;;;;;\n1F96E;MOON CAKE;So;0;ON;;;;;N;;;;;\n1F96F;BAGEL;So;0;ON;;;;;N;;;;;\n1F970;SMILING FACE WITH SMILING EYES AND THREE HEARTS;So;0;ON;;;;;N;;;;;\n1F971;YAWNING FACE;So;0;ON;;;;;N;;;;;\n1F972;SMILING FACE WITH TEAR;So;0;ON;;;;;N;;;;;\n1F973;FACE WITH PARTY HORN AND PARTY HAT;So;0;ON;;;;;N;;;;;\n1F974;FACE WITH UNEVEN EYES AND WAVY MOUTH;So;0;ON;;;;;N;;;;;\n1F975;OVERHEATED FACE;So;0;ON;;;;;N;;;;;\n1F976;FREEZING FACE;So;0;ON;;;;;N;;;;;\n1F977;NINJA;So;0;ON;;;;;N;;;;;\n1F978;DISGUISED FACE;So;0;ON;;;;;N;;;;;\n1F979;FACE HOLDING BACK TEARS;So;0;ON;;;;;N;;;;;\n1F97A;FACE WITH PLEADING EYES;So;0;ON;;;;;N;;;;;\n1F97B;SARI;So;0;ON;;;;;N;;;;;\n1F97C;LAB COAT;So;0;ON;;;;;N;;;;;\n1F97D;GOGGLES;So;0;ON;;;;;N;;;;;\n1F97E;HIKING BOOT;So;0;ON;;;;;N;;;;;\n1F97F;FLAT SHOE;So;0;ON;;;;;N;;;;;\n1F980;CRAB;So;0;ON;;;;;N;;;;;\n1F981;LION FACE;So;0;ON;;;;;N;;;;;\n1F982;SCORPION;So;0;ON;;;;;N;;;;;\n1F983;TURKEY;So;0;ON;;;;;N;;;;;\n1F984;UNICORN FACE;So;0;ON;;;;;N;;;;;\n1F985;EAGLE;So;0;ON;;;;;N;;;;;\n1F986;DUCK;So;0;ON;;;;;N;;;;;\n1F987;BAT;So;0;ON;;;;;N;;;;;\n1F988;SHARK;So;0;ON;;;;;N;;;;;\n1F989;OWL;So;0;ON;;;;;N;;;;;\n1F98A;FOX FACE;So;0;ON;;;;;N;;;;;\n1F98B;BUTTERFLY;So;0;ON;;;;;N;;;;;\n1F98C;DEER;So;0;ON;;;;;N;;;;;\n1F98D;GORILLA;So;0;ON;;;;;N;;;;;\n1F98E;LIZARD;So;0;ON;;;;;N;;;;;\n1F98F;RHINOCEROS;So;0;ON;;;;;N;;;;;\n1F990;SHRIMP;So;0;ON;;;;;N;;;;;\n1F991;SQUID;So;0;ON;;;;;N;;;;;\n1F992;GIRAFFE FACE;So;0;ON;;;;;N;;;;;\n1F993;ZEBRA FACE;So;0;ON;;;;;N;;;;;\n1F994;HEDGEHOG;So;0;ON;;;;;N;;;;;\n1F995;SAUROPOD;So;0;ON;;;;;N;;;;;\n1F996;T-REX;So;0;ON;;;;;N;;;;;\n1F997;CRICKET;So;0;ON;;;;;N;;;;;\n1F998;KANGAROO;So;0;ON;;;;;N;;;;;\n1F999;LLAMA;So;0;ON;;;;;N;;;;;\n1F99A;PEACOCK;So;0;ON;;;;;N;;;;;\n1F99B;HIPPOPOTAMUS;So;0;ON;;;;;N;;;;;\n1F99C;PARROT;So;0;ON;;;;;N;;;;;\n1F99D;RACCOON;So;0;ON;;;;;N;;;;;\n1F99E;LOBSTER;So;0;ON;;;;;N;;;;;\n1F99F;MOSQUITO;So;0;ON;;;;;N;;;;;\n1F9A0;MICROBE;So;0;ON;;;;;N;;;;;\n1F9A1;BADGER;So;0;ON;;;;;N;;;;;\n1F9A2;SWAN;So;0;ON;;;;;N;;;;;\n1F9A3;MAMMOTH;So;0;ON;;;;;N;;;;;\n1F9A4;DODO;So;0;ON;;;;;N;;;;;\n1F9A5;SLOTH;So;0;ON;;;;;N;;;;;\n1F9A6;OTTER;So;0;ON;;;;;N;;;;;\n1F9A7;ORANGUTAN;So;0;ON;;;;;N;;;;;\n1F9A8;SKUNK;So;0;ON;;;;;N;;;;;\n1F9A9;FLAMINGO;So;0;ON;;;;;N;;;;;\n1F9AA;OYSTER;So;0;ON;;;;;N;;;;;\n1F9AB;BEAVER;So;0;ON;;;;;N;;;;;\n1F9AC;BISON;So;0;ON;;;;;N;;;;;\n1F9AD;SEAL;So;0;ON;;;;;N;;;;;\n1F9AE;GUIDE DOG;So;0;ON;;;;;N;;;;;\n1F9AF;PROBING CANE;So;0;ON;;;;;N;;;;;\n1F9B0;EMOJI COMPONENT RED HAIR;So;0;ON;;;;;N;;;;;\n1F9B1;EMOJI COMPONENT CURLY HAIR;So;0;ON;;;;;N;;;;;\n1F9B2;EMOJI COMPONENT BALD;So;0;ON;;;;;N;;;;;\n1F9B3;EMOJI COMPONENT WHITE HAIR;So;0;ON;;;;;N;;;;;\n1F9B4;BONE;So;0;ON;;;;;N;;;;;\n1F9B5;LEG;So;0;ON;;;;;N;;;;;\n1F9B6;FOOT;So;0;ON;;;;;N;;;;;\n1F9B7;TOOTH;So;0;ON;;;;;N;;;;;\n1F9B8;SUPERHERO;So;0;ON;;;;;N;;;;;\n1F9B9;SUPERVILLAIN;So;0;ON;;;;;N;;;;;\n1F9BA;SAFETY VEST;So;0;ON;;;;;N;;;;;\n1F9BB;EAR WITH HEARING AID;So;0;ON;;;;;N;;;;;\n1F9BC;MOTORIZED WHEELCHAIR;So;0;ON;;;;;N;;;;;\n1F9BD;MANUAL WHEELCHAIR;So;0;ON;;;;;N;;;;;\n1F9BE;MECHANICAL ARM;So;0;ON;;;;;N;;;;;\n1F9BF;MECHANICAL LEG;So;0;ON;;;;;N;;;;;\n1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;;\n1F9C1;CUPCAKE;So;0;ON;;;;;N;;;;;\n1F9C2;SALT SHAKER;So;0;ON;;;;;N;;;;;\n1F9C3;BEVERAGE BOX;So;0;ON;;;;;N;;;;;\n1F9C4;GARLIC;So;0;ON;;;;;N;;;;;\n1F9C5;ONION;So;0;ON;;;;;N;;;;;\n1F9C6;FALAFEL;So;0;ON;;;;;N;;;;;\n1F9C7;WAFFLE;So;0;ON;;;;;N;;;;;\n1F9C8;BUTTER;So;0;ON;;;;;N;;;;;\n1F9C9;MATE DRINK;So;0;ON;;;;;N;;;;;\n1F9CA;ICE CUBE;So;0;ON;;;;;N;;;;;\n1F9CB;BUBBLE TEA;So;0;ON;;;;;N;;;;;\n1F9CC;TROLL;So;0;ON;;;;;N;;;;;\n1F9CD;STANDING PERSON;So;0;ON;;;;;N;;;;;\n1F9CE;KNEELING PERSON;So;0;ON;;;;;N;;;;;\n1F9CF;DEAF PERSON;So;0;ON;;;;;N;;;;;\n1F9D0;FACE WITH MONOCLE;So;0;ON;;;;;N;;;;;\n1F9D1;ADULT;So;0;ON;;;;;N;;;;;\n1F9D2;CHILD;So;0;ON;;;;;N;;;;;\n1F9D3;OLDER ADULT;So;0;ON;;;;;N;;;;;\n1F9D4;BEARDED PERSON;So;0;ON;;;;;N;;;;;\n1F9D5;PERSON WITH HEADSCARF;So;0;ON;;;;;N;;;;;\n1F9D6;PERSON IN STEAMY ROOM;So;0;ON;;;;;N;;;;;\n1F9D7;PERSON CLIMBING;So;0;ON;;;;;N;;;;;\n1F9D8;PERSON IN LOTUS POSITION;So;0;ON;;;;;N;;;;;\n1F9D9;MAGE;So;0;ON;;;;;N;;;;;\n1F9DA;FAIRY;So;0;ON;;;;;N;;;;;\n1F9DB;VAMPIRE;So;0;ON;;;;;N;;;;;\n1F9DC;MERPERSON;So;0;ON;;;;;N;;;;;\n1F9DD;ELF;So;0;ON;;;;;N;;;;;\n1F9DE;GENIE;So;0;ON;;;;;N;;;;;\n1F9DF;ZOMBIE;So;0;ON;;;;;N;;;;;\n1F9E0;BRAIN;So;0;ON;;;;;N;;;;;\n1F9E1;ORANGE HEART;So;0;ON;;;;;N;;;;;\n1F9E2;BILLED CAP;So;0;ON;;;;;N;;;;;\n1F9E3;SCARF;So;0;ON;;;;;N;;;;;\n1F9E4;GLOVES;So;0;ON;;;;;N;;;;;\n1F9E5;COAT;So;0;ON;;;;;N;;;;;\n1F9E6;SOCKS;So;0;ON;;;;;N;;;;;\n1F9E7;RED GIFT ENVELOPE;So;0;ON;;;;;N;;;;;\n1F9E8;FIRECRACKER;So;0;ON;;;;;N;;;;;\n1F9E9;JIGSAW PUZZLE PIECE;So;0;ON;;;;;N;;;;;\n1F9EA;TEST TUBE;So;0;ON;;;;;N;;;;;\n1F9EB;PETRI DISH;So;0;ON;;;;;N;;;;;\n1F9EC;DNA DOUBLE HELIX;So;0;ON;;;;;N;;;;;\n1F9ED;COMPASS;So;0;ON;;;;;N;;;;;\n1F9EE;ABACUS;So;0;ON;;;;;N;;;;;\n1F9EF;FIRE EXTINGUISHER;So;0;ON;;;;;N;;;;;\n1F9F0;TOOLBOX;So;0;ON;;;;;N;;;;;\n1F9F1;BRICK;So;0;ON;;;;;N;;;;;\n1F9F2;MAGNET;So;0;ON;;;;;N;;;;;\n1F9F3;LUGGAGE;So;0;ON;;;;;N;;;;;\n1F9F4;LOTION BOTTLE;So;0;ON;;;;;N;;;;;\n1F9F5;SPOOL OF THREAD;So;0;ON;;;;;N;;;;;\n1F9F6;BALL OF YARN;So;0;ON;;;;;N;;;;;\n1F9F7;SAFETY PIN;So;0;ON;;;;;N;;;;;\n1F9F8;TEDDY BEAR;So;0;ON;;;;;N;;;;;\n1F9F9;BROOM;So;0;ON;;;;;N;;;;;\n1F9FA;BASKET;So;0;ON;;;;;N;;;;;\n1F9FB;ROLL OF PAPER;So;0;ON;;;;;N;;;;;\n1F9FC;BAR OF SOAP;So;0;ON;;;;;N;;;;;\n1F9FD;SPONGE;So;0;ON;;;;;N;;;;;\n1F9FE;RECEIPT;So;0;ON;;;;;N;;;;;\n1F9FF;NAZAR AMULET;So;0;ON;;;;;N;;;;;\n1FA00;NEUTRAL CHESS KING;So;0;ON;;;;;N;;;;;\n1FA01;NEUTRAL CHESS QUEEN;So;0;ON;;;;;N;;;;;\n1FA02;NEUTRAL CHESS ROOK;So;0;ON;;;;;N;;;;;\n1FA03;NEUTRAL CHESS BISHOP;So;0;ON;;;;;N;;;;;\n1FA04;NEUTRAL CHESS KNIGHT;So;0;ON;;;;;N;;;;;\n1FA05;NEUTRAL CHESS PAWN;So;0;ON;;;;;N;;;;;\n1FA06;WHITE CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA07;BLACK CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA08;NEUTRAL CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA09;WHITE CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA0A;WHITE CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA0B;WHITE CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA0C;WHITE CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA0D;WHITE CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA0E;WHITE CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA0F;BLACK CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA10;BLACK CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA11;BLACK CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA12;BLACK CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA13;BLACK CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA14;BLACK CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA15;NEUTRAL CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA16;NEUTRAL CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA17;NEUTRAL CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA18;NEUTRAL CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA19;NEUTRAL CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA1A;NEUTRAL CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA1B;WHITE CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA1C;BLACK CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA1D;NEUTRAL CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA1E;WHITE CHESS TURNED KING;So;0;ON;;;;;N;;;;;\n1FA1F;WHITE CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;;\n1FA20;WHITE CHESS TURNED ROOK;So;0;ON;;;;;N;;;;;\n1FA21;WHITE CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;;\n1FA22;WHITE CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;;\n1FA23;WHITE CHESS TURNED PAWN;So;0;ON;;;;;N;;;;;\n1FA24;BLACK CHESS TURNED KING;So;0;ON;;;;;N;;;;;\n1FA25;BLACK CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;;\n1FA26;BLACK CHESS TURNED ROOK;So;0;ON;;;;;N;;;;;\n1FA27;BLACK CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;;\n1FA28;BLACK CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;;\n1FA29;BLACK CHESS TURNED PAWN;So;0;ON;;;;;N;;;;;\n1FA2A;NEUTRAL CHESS TURNED KING;So;0;ON;;;;;N;;;;;\n1FA2B;NEUTRAL CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;;\n1FA2C;NEUTRAL CHESS TURNED ROOK;So;0;ON;;;;;N;;;;;\n1FA2D;NEUTRAL CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;;\n1FA2E;NEUTRAL CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;;\n1FA2F;NEUTRAL CHESS TURNED PAWN;So;0;ON;;;;;N;;;;;\n1FA30;WHITE CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA31;BLACK CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA32;NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;;\n1FA33;WHITE CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA34;WHITE CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA35;WHITE CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA36;WHITE CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA37;WHITE CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA38;WHITE CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA39;BLACK CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA3A;BLACK CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA3B;BLACK CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA3C;BLACK CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA3D;BLACK CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA3E;BLACK CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA3F;NEUTRAL CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA40;NEUTRAL CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA41;NEUTRAL CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA42;NEUTRAL CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA43;NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA44;NEUTRAL CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;;\n1FA45;WHITE CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;;\n1FA46;BLACK CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;;\n1FA47;NEUTRAL CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;;\n1FA48;WHITE CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;;\n1FA49;BLACK CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;;\n1FA4A;NEUTRAL CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;;\n1FA4B;WHITE CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA4C;BLACK CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA4D;NEUTRAL CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;;\n1FA4E;WHITE CHESS KNIGHT-QUEEN;So;0;ON;;;;;N;;;;;\n1FA4F;WHITE CHESS KNIGHT-ROOK;So;0;ON;;;;;N;;;;;\n1FA50;WHITE CHESS KNIGHT-BISHOP;So;0;ON;;;;;N;;;;;\n1FA51;BLACK CHESS KNIGHT-QUEEN;So;0;ON;;;;;N;;;;;\n1FA52;BLACK CHESS KNIGHT-ROOK;So;0;ON;;;;;N;;;;;\n1FA53;BLACK CHESS KNIGHT-BISHOP;So;0;ON;;;;;N;;;;;\n1FA54;WHITE CHESS FERZ;So;0;ON;;;;;N;;;;;\n1FA55;WHITE CHESS ALFIL;So;0;ON;;;;;N;;;;;\n1FA56;BLACK CHESS FERZ;So;0;ON;;;;;N;;;;;\n1FA57;BLACK CHESS ALFIL;So;0;ON;;;;;N;;;;;\n1FA60;XIANGQI RED GENERAL;So;0;ON;;;;;N;;;;;\n1FA61;XIANGQI RED MANDARIN;So;0;ON;;;;;N;;;;;\n1FA62;XIANGQI RED ELEPHANT;So;0;ON;;;;;N;;;;;\n1FA63;XIANGQI RED HORSE;So;0;ON;;;;;N;;;;;\n1FA64;XIANGQI RED CHARIOT;So;0;ON;;;;;N;;;;;\n1FA65;XIANGQI RED CANNON;So;0;ON;;;;;N;;;;;\n1FA66;XIANGQI RED SOLDIER;So;0;ON;;;;;N;;;;;\n1FA67;XIANGQI BLACK GENERAL;So;0;ON;;;;;N;;;;;\n1FA68;XIANGQI BLACK MANDARIN;So;0;ON;;;;;N;;;;;\n1FA69;XIANGQI BLACK ELEPHANT;So;0;ON;;;;;N;;;;;\n1FA6A;XIANGQI BLACK HORSE;So;0;ON;;;;;N;;;;;\n1FA6B;XIANGQI BLACK CHARIOT;So;0;ON;;;;;N;;;;;\n1FA6C;XIANGQI BLACK CANNON;So;0;ON;;;;;N;;;;;\n1FA6D;XIANGQI BLACK SOLDIER;So;0;ON;;;;;N;;;;;\n1FA70;BALLET SHOES;So;0;ON;;;;;N;;;;;\n1FA71;ONE-PIECE SWIMSUIT;So;0;ON;;;;;N;;;;;\n1FA72;BRIEFS;So;0;ON;;;;;N;;;;;\n1FA73;SHORTS;So;0;ON;;;;;N;;;;;\n1FA74;THONG SANDAL;So;0;ON;;;;;N;;;;;\n1FA75;LIGHT BLUE HEART;So;0;ON;;;;;N;;;;;\n1FA76;GREY HEART;So;0;ON;;;;;N;;;;;\n1FA77;PINK HEART;So;0;ON;;;;;N;;;;;\n1FA78;DROP OF BLOOD;So;0;ON;;;;;N;;;;;\n1FA79;ADHESIVE BANDAGE;So;0;ON;;;;;N;;;;;\n1FA7A;STETHOSCOPE;So;0;ON;;;;;N;;;;;\n1FA7B;X-RAY;So;0;ON;;;;;N;;;;;\n1FA7C;CRUTCH;So;0;ON;;;;;N;;;;;\n1FA80;YO-YO;So;0;ON;;;;;N;;;;;\n1FA81;KITE;So;0;ON;;;;;N;;;;;\n1FA82;PARACHUTE;So;0;ON;;;;;N;;;;;\n1FA83;BOOMERANG;So;0;ON;;;;;N;;;;;\n1FA84;MAGIC WAND;So;0;ON;;;;;N;;;;;\n1FA85;PINATA;So;0;ON;;;;;N;;;;;\n1FA86;NESTING DOLLS;So;0;ON;;;;;N;;;;;\n1FA87;MARACAS;So;0;ON;;;;;N;;;;;\n1FA88;FLUTE;So;0;ON;;;;;N;;;;;\n1FA89;HARP;So;0;ON;;;;;N;;;;;\n1FA8A;TROMBONE;So;0;ON;;;;;N;;;;;\n1FA8E;TREASURE CHEST;So;0;ON;;;;;N;;;;;\n1FA8F;SHOVEL;So;0;ON;;;;;N;;;;;\n1FA90;RINGED PLANET;So;0;ON;;;;;N;;;;;\n1FA91;CHAIR;So;0;ON;;;;;N;;;;;\n1FA92;RAZOR;So;0;ON;;;;;N;;;;;\n1FA93;AXE;So;0;ON;;;;;N;;;;;\n1FA94;DIYA LAMP;So;0;ON;;;;;N;;;;;\n1FA95;BANJO;So;0;ON;;;;;N;;;;;\n1FA96;MILITARY HELMET;So;0;ON;;;;;N;;;;;\n1FA97;ACCORDION;So;0;ON;;;;;N;;;;;\n1FA98;LONG DRUM;So;0;ON;;;;;N;;;;;\n1FA99;COIN;So;0;ON;;;;;N;;;;;\n1FA9A;CARPENTRY SAW;So;0;ON;;;;;N;;;;;\n1FA9B;SCREWDRIVER;So;0;ON;;;;;N;;;;;\n1FA9C;LADDER;So;0;ON;;;;;N;;;;;\n1FA9D;HOOK;So;0;ON;;;;;N;;;;;\n1FA9E;MIRROR;So;0;ON;;;;;N;;;;;\n1FA9F;WINDOW;So;0;ON;;;;;N;;;;;\n1FAA0;PLUNGER;So;0;ON;;;;;N;;;;;\n1FAA1;SEWING NEEDLE;So;0;ON;;;;;N;;;;;\n1FAA2;KNOT;So;0;ON;;;;;N;;;;;\n1FAA3;BUCKET;So;0;ON;;;;;N;;;;;\n1FAA4;MOUSE TRAP;So;0;ON;;;;;N;;;;;\n1FAA5;TOOTHBRUSH;So;0;ON;;;;;N;;;;;\n1FAA6;HEADSTONE;So;0;ON;;;;;N;;;;;\n1FAA7;PLACARD;So;0;ON;;;;;N;;;;;\n1FAA8;ROCK;So;0;ON;;;;;N;;;;;\n1FAA9;MIRROR BALL;So;0;ON;;;;;N;;;;;\n1FAAA;IDENTIFICATION CARD;So;0;ON;;;;;N;;;;;\n1FAAB;LOW BATTERY;So;0;ON;;;;;N;;;;;\n1FAAC;HAMSA;So;0;ON;;;;;N;;;;;\n1FAAD;FOLDING HAND FAN;So;0;ON;;;;;N;;;;;\n1FAAE;HAIR PICK;So;0;ON;;;;;N;;;;;\n1FAAF;KHANDA;So;0;ON;;;;;N;;;;;\n1FAB0;FLY;So;0;ON;;;;;N;;;;;\n1FAB1;WORM;So;0;ON;;;;;N;;;;;\n1FAB2;BEETLE;So;0;ON;;;;;N;;;;;\n1FAB3;COCKROACH;So;0;ON;;;;;N;;;;;\n1FAB4;POTTED PLANT;So;0;ON;;;;;N;;;;;\n1FAB5;WOOD;So;0;ON;;;;;N;;;;;\n1FAB6;FEATHER;So;0;ON;;;;;N;;;;;\n1FAB7;LOTUS;So;0;ON;;;;;N;;;;;\n1FAB8;CORAL;So;0;ON;;;;;N;;;;;\n1FAB9;EMPTY NEST;So;0;ON;;;;;N;;;;;\n1FABA;NEST WITH EGGS;So;0;ON;;;;;N;;;;;\n1FABB;HYACINTH;So;0;ON;;;;;N;;;;;\n1FABC;JELLYFISH;So;0;ON;;;;;N;;;;;\n1FABD;WING;So;0;ON;;;;;N;;;;;\n1FABE;LEAFLESS TREE;So;0;ON;;;;;N;;;;;\n1FABF;GOOSE;So;0;ON;;;;;N;;;;;\n1FAC0;ANATOMICAL HEART;So;0;ON;;;;;N;;;;;\n1FAC1;LUNGS;So;0;ON;;;;;N;;;;;\n1FAC2;PEOPLE HUGGING;So;0;ON;;;;;N;;;;;\n1FAC3;PREGNANT MAN;So;0;ON;;;;;N;;;;;\n1FAC4;PREGNANT PERSON;So;0;ON;;;;;N;;;;;\n1FAC5;PERSON WITH CROWN;So;0;ON;;;;;N;;;;;\n1FAC6;FINGERPRINT;So;0;ON;;;;;N;;;;;\n1FAC8;HAIRY CREATURE;So;0;ON;;;;;N;;;;;\n1FACD;ORCA;So;0;ON;;;;;N;;;;;\n1FACE;MOOSE;So;0;ON;;;;;N;;;;;\n1FACF;DONKEY;So;0;ON;;;;;N;;;;;\n1FAD0;BLUEBERRIES;So;0;ON;;;;;N;;;;;\n1FAD1;BELL PEPPER;So;0;ON;;;;;N;;;;;\n1FAD2;OLIVE;So;0;ON;;;;;N;;;;;\n1FAD3;FLATBREAD;So;0;ON;;;;;N;;;;;\n1FAD4;TAMALE;So;0;ON;;;;;N;;;;;\n1FAD5;FONDUE;So;0;ON;;;;;N;;;;;\n1FAD6;TEAPOT;So;0;ON;;;;;N;;;;;\n1FAD7;POURING LIQUID;So;0;ON;;;;;N;;;;;\n1FAD8;BEANS;So;0;ON;;;;;N;;;;;\n1FAD9;JAR;So;0;ON;;;;;N;;;;;\n1FADA;GINGER ROOT;So;0;ON;;;;;N;;;;;\n1FADB;PEA POD;So;0;ON;;;;;N;;;;;\n1FADC;ROOT VEGETABLE;So;0;ON;;;;;N;;;;;\n1FADF;SPLATTER;So;0;ON;;;;;N;;;;;\n1FAE0;MELTING FACE;So;0;ON;;;;;N;;;;;\n1FAE1;SALUTING FACE;So;0;ON;;;;;N;;;;;\n1FAE2;FACE WITH OPEN EYES AND HAND OVER MOUTH;So;0;ON;;;;;N;;;;;\n1FAE3;FACE WITH PEEKING EYE;So;0;ON;;;;;N;;;;;\n1FAE4;FACE WITH DIAGONAL MOUTH;So;0;ON;;;;;N;;;;;\n1FAE5;DOTTED LINE FACE;So;0;ON;;;;;N;;;;;\n1FAE6;BITING LIP;So;0;ON;;;;;N;;;;;\n1FAE7;BUBBLES;So;0;ON;;;;;N;;;;;\n1FAE8;SHAKING FACE;So;0;ON;;;;;N;;;;;\n1FAE9;FACE WITH BAGS UNDER EYES;So;0;ON;;;;;N;;;;;\n1FAEA;DISTORTED FACE;So;0;ON;;;;;N;;;;;\n1FAEF;FIGHT CLOUD;So;0;ON;;;;;N;;;;;\n1FAF0;HAND WITH INDEX FINGER AND THUMB CROSSED;So;0;ON;;;;;N;;;;;\n1FAF1;RIGHTWARDS HAND;So;0;ON;;;;;N;;;;;\n1FAF2;LEFTWARDS HAND;So;0;ON;;;;;N;;;;;\n1FAF3;PALM DOWN HAND;So;0;ON;;;;;N;;;;;\n1FAF4;PALM UP HAND;So;0;ON;;;;;N;;;;;\n1FAF5;INDEX POINTING AT THE VIEWER;So;0;ON;;;;;N;;;;;\n1FAF6;HEART HANDS;So;0;ON;;;;;N;;;;;\n1FAF7;LEFTWARDS PUSHING HAND;So;0;ON;;;;;N;;;;;\n1FAF8;RIGHTWARDS PUSHING HAND;So;0;ON;;;;;N;;;;;\n1FB00;BLOCK SEXTANT-1;So;0;ON;;;;;N;;;;;\n1FB01;BLOCK SEXTANT-2;So;0;ON;;;;;N;;;;;\n1FB02;BLOCK SEXTANT-12;So;0;ON;;;;;N;;;;;\n1FB03;BLOCK SEXTANT-3;So;0;ON;;;;;N;;;;;\n1FB04;BLOCK SEXTANT-13;So;0;ON;;;;;N;;;;;\n1FB05;BLOCK SEXTANT-23;So;0;ON;;;;;N;;;;;\n1FB06;BLOCK SEXTANT-123;So;0;ON;;;;;N;;;;;\n1FB07;BLOCK SEXTANT-4;So;0;ON;;;;;N;;;;;\n1FB08;BLOCK SEXTANT-14;So;0;ON;;;;;N;;;;;\n1FB09;BLOCK SEXTANT-24;So;0;ON;;;;;N;;;;;\n1FB0A;BLOCK SEXTANT-124;So;0;ON;;;;;N;;;;;\n1FB0B;BLOCK SEXTANT-34;So;0;ON;;;;;N;;;;;\n1FB0C;BLOCK SEXTANT-134;So;0;ON;;;;;N;;;;;\n1FB0D;BLOCK SEXTANT-234;So;0;ON;;;;;N;;;;;\n1FB0E;BLOCK SEXTANT-1234;So;0;ON;;;;;N;;;;;\n1FB0F;BLOCK SEXTANT-5;So;0;ON;;;;;N;;;;;\n1FB10;BLOCK SEXTANT-15;So;0;ON;;;;;N;;;;;\n1FB11;BLOCK SEXTANT-25;So;0;ON;;;;;N;;;;;\n1FB12;BLOCK SEXTANT-125;So;0;ON;;;;;N;;;;;\n1FB13;BLOCK SEXTANT-35;So;0;ON;;;;;N;;;;;\n1FB14;BLOCK SEXTANT-235;So;0;ON;;;;;N;;;;;\n1FB15;BLOCK SEXTANT-1235;So;0;ON;;;;;N;;;;;\n1FB16;BLOCK SEXTANT-45;So;0;ON;;;;;N;;;;;\n1FB17;BLOCK SEXTANT-145;So;0;ON;;;;;N;;;;;\n1FB18;BLOCK SEXTANT-245;So;0;ON;;;;;N;;;;;\n1FB19;BLOCK SEXTANT-1245;So;0;ON;;;;;N;;;;;\n1FB1A;BLOCK SEXTANT-345;So;0;ON;;;;;N;;;;;\n1FB1B;BLOCK SEXTANT-1345;So;0;ON;;;;;N;;;;;\n1FB1C;BLOCK SEXTANT-2345;So;0;ON;;;;;N;;;;;\n1FB1D;BLOCK SEXTANT-12345;So;0;ON;;;;;N;;;;;\n1FB1E;BLOCK SEXTANT-6;So;0;ON;;;;;N;;;;;\n1FB1F;BLOCK SEXTANT-16;So;0;ON;;;;;N;;;;;\n1FB20;BLOCK SEXTANT-26;So;0;ON;;;;;N;;;;;\n1FB21;BLOCK SEXTANT-126;So;0;ON;;;;;N;;;;;\n1FB22;BLOCK SEXTANT-36;So;0;ON;;;;;N;;;;;\n1FB23;BLOCK SEXTANT-136;So;0;ON;;;;;N;;;;;\n1FB24;BLOCK SEXTANT-236;So;0;ON;;;;;N;;;;;\n1FB25;BLOCK SEXTANT-1236;So;0;ON;;;;;N;;;;;\n1FB26;BLOCK SEXTANT-46;So;0;ON;;;;;N;;;;;\n1FB27;BLOCK SEXTANT-146;So;0;ON;;;;;N;;;;;\n1FB28;BLOCK SEXTANT-1246;So;0;ON;;;;;N;;;;;\n1FB29;BLOCK SEXTANT-346;So;0;ON;;;;;N;;;;;\n1FB2A;BLOCK SEXTANT-1346;So;0;ON;;;;;N;;;;;\n1FB2B;BLOCK SEXTANT-2346;So;0;ON;;;;;N;;;;;\n1FB2C;BLOCK SEXTANT-12346;So;0;ON;;;;;N;;;;;\n1FB2D;BLOCK SEXTANT-56;So;0;ON;;;;;N;;;;;\n1FB2E;BLOCK SEXTANT-156;So;0;ON;;;;;N;;;;;\n1FB2F;BLOCK SEXTANT-256;So;0;ON;;;;;N;;;;;\n1FB30;BLOCK SEXTANT-1256;So;0;ON;;;;;N;;;;;\n1FB31;BLOCK SEXTANT-356;So;0;ON;;;;;N;;;;;\n1FB32;BLOCK SEXTANT-1356;So;0;ON;;;;;N;;;;;\n1FB33;BLOCK SEXTANT-2356;So;0;ON;;;;;N;;;;;\n1FB34;BLOCK SEXTANT-12356;So;0;ON;;;;;N;;;;;\n1FB35;BLOCK SEXTANT-456;So;0;ON;;;;;N;;;;;\n1FB36;BLOCK SEXTANT-1456;So;0;ON;;;;;N;;;;;\n1FB37;BLOCK SEXTANT-2456;So;0;ON;;;;;N;;;;;\n1FB38;BLOCK SEXTANT-12456;So;0;ON;;;;;N;;;;;\n1FB39;BLOCK SEXTANT-3456;So;0;ON;;;;;N;;;;;\n1FB3A;BLOCK SEXTANT-13456;So;0;ON;;;;;N;;;;;\n1FB3B;BLOCK SEXTANT-23456;So;0;ON;;;;;N;;;;;\n1FB3C;LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FB3D;LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FB3E;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FB3F;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FB40;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FB41;LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;\n1FB42;LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1FB43;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;\n1FB44;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1FB45;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;\n1FB46;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB47;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB48;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB49;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB4A;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB4B;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1FB4C;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB4D;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB4E;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB4F;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB50;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FB51;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB52;UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FB53;UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FB54;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FB55;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FB56;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FB57;UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;\n1FB58;UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1FB59;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;\n1FB5A;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1FB5B;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;;\n1FB5C;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB5D;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB5E;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB5F;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB60;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB61;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1FB62;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB63;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB64;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB65;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB66;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FB67;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FB68;UPPER AND RIGHT AND LOWER TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;\n1FB69;LEFT AND LOWER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;\n1FB6A;UPPER AND LEFT AND LOWER TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;\n1FB6B;LEFT AND UPPER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;\n1FB6C;LEFT TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FB6D;UPPER TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FB6E;RIGHT TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FB6F;LOWER TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FB70;VERTICAL ONE EIGHTH BLOCK-2;So;0;ON;;;;;N;;;;;\n1FB71;VERTICAL ONE EIGHTH BLOCK-3;So;0;ON;;;;;N;;;;;\n1FB72;VERTICAL ONE EIGHTH BLOCK-4;So;0;ON;;;;;N;;;;;\n1FB73;VERTICAL ONE EIGHTH BLOCK-5;So;0;ON;;;;;N;;;;;\n1FB74;VERTICAL ONE EIGHTH BLOCK-6;So;0;ON;;;;;N;;;;;\n1FB75;VERTICAL ONE EIGHTH BLOCK-7;So;0;ON;;;;;N;;;;;\n1FB76;HORIZONTAL ONE EIGHTH BLOCK-2;So;0;ON;;;;;N;;;;;\n1FB77;HORIZONTAL ONE EIGHTH BLOCK-3;So;0;ON;;;;;N;;;;;\n1FB78;HORIZONTAL ONE EIGHTH BLOCK-4;So;0;ON;;;;;N;;;;;\n1FB79;HORIZONTAL ONE EIGHTH BLOCK-5;So;0;ON;;;;;N;;;;;\n1FB7A;HORIZONTAL ONE EIGHTH BLOCK-6;So;0;ON;;;;;N;;;;;\n1FB7B;HORIZONTAL ONE EIGHTH BLOCK-7;So;0;ON;;;;;N;;;;;\n1FB7C;LEFT AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FB7D;LEFT AND UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FB7E;RIGHT AND UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FB7F;RIGHT AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FB80;UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FB81;HORIZONTAL ONE EIGHTH BLOCK-1358;So;0;ON;;;;;N;;;;;\n1FB82;UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FB83;UPPER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n1FB84;UPPER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n1FB85;UPPER THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;\n1FB86;UPPER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n1FB87;RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FB88;RIGHT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n1FB89;RIGHT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n1FB8A;RIGHT THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;;\n1FB8B;RIGHT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;\n1FB8C;LEFT HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB8D;RIGHT HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB8E;UPPER HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB8F;LOWER HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB90;INVERSE MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB91;UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB92;UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK;So;0;ON;;;;;N;;;;;\n1FB94;LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;;\n1FB95;CHECKER BOARD FILL;So;0;ON;;;;;N;;;;;\n1FB96;INVERSE CHECKER BOARD FILL;So;0;ON;;;;;N;;;;;\n1FB97;HEAVY HORIZONTAL FILL;So;0;ON;;;;;N;;;;;\n1FB98;UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;;\n1FB99;UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;;\n1FB9A;UPPER AND LOWER TRIANGULAR HALF BLOCK;So;0;ON;;;;;N;;;;;\n1FB9B;LEFT AND RIGHT TRIANGULAR HALF BLOCK;So;0;ON;;;;;N;;;;;\n1FB9C;UPPER LEFT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB9D;UPPER RIGHT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB9E;LOWER RIGHT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FB9F;LOWER LEFT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;;\n1FBA0;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT;So;0;ON;;;;;N;;;;;\n1FBA1;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FBA2;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBA3;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBA4;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBA5;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBA6;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FBA7;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FBA8;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT AND MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBA9;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT AND MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBAA;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE TO MIDDLE LEFT;So;0;ON;;;;;N;;;;;\n1FBAB;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FBAC;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBAD;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBAE;BOX DRAWINGS LIGHT DIAGONAL DIAMOND;So;0;ON;;;;;N;;;;;\n1FBAF;BOX DRAWINGS LIGHT HORIZONTAL WITH VERTICAL STROKE;So;0;ON;;;;;N;;;;;\n1FBB0;ARROWHEAD-SHAPED POINTER;So;0;ON;;;;;N;;;;;\n1FBB1;INVERSE CHECK MARK;So;0;ON;;;;;N;;;;;\n1FBB2;LEFT HALF RUNNING MAN;So;0;ON;;;;;N;;;;;\n1FBB3;RIGHT HALF RUNNING MAN;So;0;ON;;;;;N;;;;;\n1FBB4;INVERSE DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;;;;;\n1FBB5;LEFTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FBB6;RIGHTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FBB7;DOWNWARDS ARROW AND RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FBB8;UPWARDS ARROW AND RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;\n1FBB9;LEFT HALF FOLDER;So;0;ON;;;;;N;;;;;\n1FBBA;RIGHT HALF FOLDER;So;0;ON;;;;;N;;;;;\n1FBBB;VOIDED GREEK CROSS;So;0;ON;;;;;N;;;;;\n1FBBC;RIGHT OPEN SQUARED DOT;So;0;ON;;;;;N;;;;;\n1FBBD;NEGATIVE DIAGONAL CROSS;So;0;ON;;;;;N;;;;;\n1FBBE;NEGATIVE DIAGONAL MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBBF;NEGATIVE DIAGONAL DIAMOND;So;0;ON;;;;;N;;;;;\n1FBC0;WHITE HEAVY SALTIRE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;\n1FBC1;LEFT THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;\n1FBC2;MIDDLE THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;\n1FBC3;RIGHT THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;\n1FBC4;NEGATIVE SQUARED QUESTION MARK;So;0;ON;;;;;N;;;;;\n1FBC5;STICK FIGURE;So;0;ON;;;;;N;;;;;\n1FBC6;STICK FIGURE WITH ARMS RAISED;So;0;ON;;;;;N;;;;;\n1FBC7;STICK FIGURE LEANING LEFT;So;0;ON;;;;;N;;;;;\n1FBC8;STICK FIGURE LEANING RIGHT;So;0;ON;;;;;N;;;;;\n1FBC9;STICK FIGURE WITH DRESS;So;0;ON;;;;;N;;;;;\n1FBCA;WHITE UP-POINTING CHEVRON;So;0;ON;;;;;N;;;;;\n1FBCB;WHITE CROSS MARK;So;0;ON;;;;;N;;;;;\n1FBCC;RAISED SMALL LEFT SQUARE BRACKET;So;0;ON;;;;;N;;;;;\n1FBCD;BLACK SMALL UP-POINTING CHEVRON;So;0;ON;;;;;N;;;;;\n1FBCE;LEFT TWO THIRDS BLOCK;So;0;ON;;;;;N;;;;;\n1FBCF;LEFT ONE THIRD BLOCK;So;0;ON;;;;;N;;;;;\n1FBD0;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER LEFT;So;0;ON;;;;;N;;;;;\n1FBD1;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE LEFT;So;0;ON;;;;;N;;;;;\n1FBD2;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;;\n1FBD3;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FBD4;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBD5;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FBD6;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;;\n1FBD7;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO LOWER LEFT;So;0;ON;;;;;N;;;;;\n1FBD8;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1FBD9;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FBDA;BOX DRAWINGS LIGHT DIAGONAL LOWER LEFT TO MIDDLE CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FBDB;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO LOWER LEFT;So;0;ON;;;;;N;;;;;\n1FBDC;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;;\n1FBDD;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FBDE;BOX DRAWINGS LIGHT DIAGONAL LOWER LEFT TO UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;;\n1FBDF;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE RIGHT TO LOWER LEFT;So;0;ON;;;;;N;;;;;\n1FBE0;TOP JUSTIFIED LOWER HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1FBE1;RIGHT JUSTIFIED LEFT HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1FBE2;BOTTOM JUSTIFIED UPPER HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1FBE3;LEFT JUSTIFIED RIGHT HALF WHITE CIRCLE;So;0;ON;;;;;N;;;;;\n1FBE4;UPPER CENTRE ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FBE5;LOWER CENTRE ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FBE6;MIDDLE LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FBE7;MIDDLE RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;\n1FBE8;TOP JUSTIFIED LOWER HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n1FBE9;RIGHT JUSTIFIED LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n1FBEA;BOTTOM JUSTIFIED UPPER HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n1FBEB;LEFT JUSTIFIED RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n1FBEC;TOP RIGHT JUSTIFIED LOWER LEFT QUARTER BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n1FBED;BOTTOM LEFT JUSTIFIED UPPER RIGHT QUARTER BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n1FBEE;BOTTOM RIGHT JUSTIFIED UPPER LEFT QUARTER BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n1FBEF;TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE;So;0;ON;;;;;N;;;;;\n1FBF0;SEGMENTED DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;\n1FBF1;SEGMENTED DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;\n1FBF2;SEGMENTED DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;\n1FBF3;SEGMENTED DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;\n1FBF4;SEGMENTED DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;\n1FBF5;SEGMENTED DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;\n1FBF6;SEGMENTED DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;\n1FBF7;SEGMENTED DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;\n1FBF8;SEGMENTED DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;\n1FBF9;SEGMENTED DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;\n1FBFA;ALARM BELL SYMBOL;So;0;ON;;;;;N;;;;;\n20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;\n2A6DF;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;\n2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;;\n2B73F;<CJK Ideograph Extension C, Last>;Lo;0;L;;;;;N;;;;;\n2B740;<CJK Ideograph Extension D, First>;Lo;0;L;;;;;N;;;;;\n2B81D;<CJK Ideograph Extension D, Last>;Lo;0;L;;;;;N;;;;;\n2B820;<CJK Ideograph Extension E, First>;Lo;0;L;;;;;N;;;;;\n2CEAD;<CJK Ideograph Extension E, Last>;Lo;0;L;;;;;N;;;;;\n2CEB0;<CJK Ideograph Extension F, First>;Lo;0;L;;;;;N;;;;;\n2EBE0;<CJK Ideograph Extension F, Last>;Lo;0;L;;;;;N;;;;;\n2EBF0;<CJK Ideograph Extension I, First>;Lo;0;L;;;;;N;;;;;\n2EE5D;<CJK Ideograph Extension I, Last>;Lo;0;L;;;;;N;;;;;\n2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;;\n2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;;\n2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;;\n2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;;\n2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;;\n2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;;\n2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;;\n2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;;\n2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;;\n2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;;\n2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;;\n2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;;\n2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;;\n2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;;\n2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;;\n2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;;\n2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;;\n2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;;\n2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;;\n2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;;\n2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;;\n2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;;\n2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;;\n2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;;\n2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;;\n2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;;\n2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;;\n2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;;\n2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;;\n2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;;\n2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;;\n2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;;\n2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;;\n2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;;\n2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;;\n2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;;\n2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;;\n2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;;\n2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;;\n2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;;\n2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;;\n2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;;\n2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;;\n2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;;\n2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;;\n2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;;\n2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;;\n2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;;\n2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;;\n2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;;\n2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;;\n2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;;\n2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;;\n2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;;\n2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;;\n2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;;\n2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;;\n2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;;\n2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;;\n2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;;\n2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;;\n2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;;\n2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;;\n2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;;\n2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;;\n2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;;\n2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;;\n2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;;\n2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;;\n2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;;\n2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;;\n2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;;\n2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;;\n2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;;\n2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;;\n2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;;\n2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;;\n2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;;\n2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;;\n2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;;\n2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;;\n2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;;\n2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;;\n2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;;\n2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;;\n2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;;\n2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;;\n2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;;\n2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;;\n2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;;\n2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;;\n2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;;\n2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;;\n2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;;\n2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;;\n2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;;\n2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;;\n2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;;\n2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;;\n2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;;\n2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;;\n2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;;\n2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;;\n2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;;\n2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;36FC;;;;N;;;;;\n2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;;\n2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;;\n2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;;\n2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;;\n2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;;\n2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;;\n2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;;\n2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;;\n2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;;\n2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;;\n2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;;\n2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F53;;;;N;;;;;\n2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;;\n2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;;\n2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;;\n2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;;\n2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;;\n2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;;\n2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;;\n2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;;\n2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;;\n2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;;\n2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;;\n2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;;\n2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;;\n2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;;\n2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;;\n2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;;\n2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;;\n2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;;\n2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;;\n2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;;\n2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;;\n2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;;\n2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;;\n2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;;\n2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;;\n2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;;\n2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;;\n2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;9;N;;;;;\n2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;;\n2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;;\n2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;;\n2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;;\n2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;;\n2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;;\n2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;;\n2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;;\n2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;;\n2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;;\n2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;;\n2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;;\n2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;;\n2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;;\n2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;;\n2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;;\n2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;;\n2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;;\n2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;;\n2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;;\n2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;;\n2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;;\n2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;;\n2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;;\n2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;;\n2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;;\n2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;;\n2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;;\n2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;;\n2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;;\n2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;;\n2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;;\n2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;;\n2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;;\n2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;;\n2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;;\n2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;;\n2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;;\n2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;;\n2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;;\n2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;;\n2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;;\n2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;;\n2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;;\n2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;;\n2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;;\n2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;;\n2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;;\n2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;;\n2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;;\n2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;;\n2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;;\n2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;;\n2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;;\n2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;;\n2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;;\n2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;;\n2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;;\n2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;;\n2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;;\n2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;;\n2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;;\n2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;;\n2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;;\n2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;;\n2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;;\n2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;;\n2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;;\n2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;;\n2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;;\n2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;;\n2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;;\n2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;;\n2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;;\n2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;;\n2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;;\n2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;;\n2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;;\n2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;;\n2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;;\n2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;;\n2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;;\n2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;;\n2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;;\n2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;;\n2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;;\n2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;;\n2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;;\n2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;;\n2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;;\n2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;;\n2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;;\n2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;;\n2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;;\n2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;;\n2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;;\n2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;;\n2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;;\n2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;;\n2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;;\n2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;;\n2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;;\n2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;;\n2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;;\n2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;;\n2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;;\n2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;;\n2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;;\n2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;;\n2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;;\n2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;;\n2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;;\n2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;;\n2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;;\n2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;;\n2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;;\n2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;;\n2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;;\n2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;;\n2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;;\n2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;;\n2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;;\n2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;;\n2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;;\n2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;;\n2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;;\n2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;;\n2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;;\n2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;;\n2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;;\n2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;;\n2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;;\n2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;;\n2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;;\n2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;;\n2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;;\n2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;;\n2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;;\n2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;;\n2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;;\n2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;;\n2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;;\n2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;243AB;;;;N;;;;;\n2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;;\n2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;;\n2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;;\n2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;;\n2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;;\n2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;;\n2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;;\n2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;;\n2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;;\n2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;;\n2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;;\n2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;;\n2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;;\n2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;;\n2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;;\n2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;;\n2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;;\n2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;;\n2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;;\n2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;;\n2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;;\n2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;;\n2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;;\n2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;;\n2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;;\n2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;;\n2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;;\n2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;;\n2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;;\n2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;;\n2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;;\n2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;;\n2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;;\n2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;;\n2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;;\n2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;;\n2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;;\n2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;;\n2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;;\n2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;;\n2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;;\n2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;;\n2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;;\n2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;;\n2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;;\n2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;;\n2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;;\n2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;;\n2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;;\n2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;;\n2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;;\n2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;;\n2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;;\n2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;;\n2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;;\n2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;;\n2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;;\n2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;;\n2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;;\n2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;;\n2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;;\n2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;;\n2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;;\n2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AEE;;;;N;;;;;\n2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;;\n2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;;\n2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;;\n2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;;\n2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;;\n2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;;\n2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;;\n2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;;\n2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;;\n2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;;\n2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;;\n2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;;\n2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;;\n2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;;\n2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;;\n2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;;\n2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;;\n2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;;\n2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;;\n2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;;\n2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;;\n2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;;\n2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;;\n2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;;\n2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;;\n2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;;\n2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;;\n2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;;\n2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;;\n2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;;\n2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;;\n2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;;\n2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;;\n2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;;\n2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;;\n2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;;\n2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;;\n2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;;\n2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;;\n2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;;\n2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;;\n2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;;\n2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;;\n2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;;\n2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;;\n2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;;\n2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;;\n2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;;\n2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;;\n2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;;\n2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;;\n2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;;\n2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;;\n2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;;\n2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;;\n2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;;\n2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;;\n2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;;\n2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;;\n2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;;\n2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;;\n2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;;\n2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;;\n2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;;\n2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;;\n2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;;\n2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;;\n2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;;\n2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;;\n2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;;\n2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;;\n2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;;\n2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;;\n2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;;\n2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;;\n2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;;\n2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;;\n2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;;\n2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;;\n2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;;\n2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;;\n2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;;\n2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;;\n2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;;\n2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;;\n2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;;\n2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;;\n2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;;\n2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;;\n2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;;\n2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;;\n2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;;\n2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;;\n2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;;\n2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;;\n2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;45D7;;;;N;;;;;\n2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;;\n2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;;\n2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;;\n2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;;\n2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;;\n2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;;\n2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;;\n2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;;\n2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;;\n2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;;\n2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;;\n2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;;\n2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;;\n2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;;\n2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;;\n2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;;\n2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;;\n2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;;\n2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;;\n2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;;\n2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;;\n2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;;\n2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;;\n2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;;\n2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;;\n2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;;\n2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;;\n2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;;\n2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;;\n2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;;\n2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;;\n2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;;\n2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;;\n2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;;\n2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;;\n2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;;\n2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;;\n2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;;\n2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;;\n2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;;\n2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;;\n2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;;\n2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;;\n2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;;\n2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;;\n2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;;\n2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;;\n2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;;\n2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;;\n2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;;\n2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;;\n2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;;\n2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;;\n2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;;\n2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;;\n2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;;\n2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;;\n2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;;\n2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;;\n2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;;\n2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;;\n2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;;\n2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;;\n2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;;\n2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;;\n2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;;\n2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;;\n2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;;\n2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;;\n2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;;\n2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;;\n2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;;\n2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;;\n2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;;\n2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;;\n2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;;\n2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;;\n2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;;\n2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;;\n2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;;\n2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;;\n2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;;\n2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;;\n2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;;\n2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;;\n2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;;\n2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;;\n2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;;\n2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;;\n2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;;\n2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;;\n2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;;\n2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;;\n2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;;\n30000;<CJK Ideograph Extension G, First>;Lo;0;L;;;;;N;;;;;\n3134A;<CJK Ideograph Extension G, Last>;Lo;0;L;;;;;N;;;;;\n31350;<CJK Ideograph Extension H, First>;Lo;0;L;;;;;N;;;;;\n323AF;<CJK Ideograph Extension H, Last>;Lo;0;L;;;;;N;;;;;\n323B0;<CJK Ideograph Extension J, First>;Lo;0;L;;;;;N;;;;;\n33479;<CJK Ideograph Extension J, Last>;Lo;0;L;;;;;N;;;;;\nE0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;;\nE0020;TAG SPACE;Cf;0;BN;;;;;N;;;;;\nE0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;;\nE0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;;\nE0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;;\nE0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;;\nE0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;;\nE0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;;\nE0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;;\nE0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;;\nE0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;;\nE002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;;\nE002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;;\nE002C;TAG COMMA;Cf;0;BN;;;;;N;;;;;\nE002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;;\nE002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;;\nE002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;;\nE0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;;\nE0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;;\nE0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;;\nE0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;;\nE0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;;\nE0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;;\nE0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;;\nE0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;;\nE0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;;\nE0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;;\nE003A;TAG COLON;Cf;0;BN;;;;;N;;;;;\nE003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;;\nE003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;;\nE003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;;\nE003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;;\nE003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;;\nE0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;;\nE0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;;\nE0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;;\nE0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;;\nE0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;;\nE0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;;\nE0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;;\nE0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;;\nE0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;;\nE0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;;\nE004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;;\nE004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;;\nE004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;;\nE004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;;\nE004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;;\nE004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;;\nE0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;;\nE0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;;\nE0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;;\nE0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;;\nE0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;;\nE0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;;\nE0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;;\nE0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;;\nE0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;;\nE0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;;\nE005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;;\nE005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;\nE005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;;\nE005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;\nE005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;;\nE005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;;\nE0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;;\nE0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;;\nE0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;;\nE0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;;\nE0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;;\nE0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;;\nE0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;;\nE0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;;\nE0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;;\nE0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;;\nE006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;;\nE006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;;\nE006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;;\nE006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;;\nE006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;;\nE006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;;\nE0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;;\nE0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;;\nE0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;;\nE0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;;\nE0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;;\nE0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;;\nE0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;;\nE0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;;\nE0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;;\nE0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;;\nE007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;;\nE007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;\nE007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;;\nE007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;\nE007E;TAG TILDE;Cf;0;BN;;;;;N;;;;;\nE007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;;\nE0100;VARIATION SELECTOR-17;Mn;0;NSM;;;;;N;;;;;\nE0101;VARIATION SELECTOR-18;Mn;0;NSM;;;;;N;;;;;\nE0102;VARIATION SELECTOR-19;Mn;0;NSM;;;;;N;;;;;\nE0103;VARIATION SELECTOR-20;Mn;0;NSM;;;;;N;;;;;\nE0104;VARIATION SELECTOR-21;Mn;0;NSM;;;;;N;;;;;\nE0105;VARIATION SELECTOR-22;Mn;0;NSM;;;;;N;;;;;\nE0106;VARIATION SELECTOR-23;Mn;0;NSM;;;;;N;;;;;\nE0107;VARIATION SELECTOR-24;Mn;0;NSM;;;;;N;;;;;\nE0108;VARIATION SELECTOR-25;Mn;0;NSM;;;;;N;;;;;\nE0109;VARIATION SELECTOR-26;Mn;0;NSM;;;;;N;;;;;\nE010A;VARIATION SELECTOR-27;Mn;0;NSM;;;;;N;;;;;\nE010B;VARIATION SELECTOR-28;Mn;0;NSM;;;;;N;;;;;\nE010C;VARIATION SELECTOR-29;Mn;0;NSM;;;;;N;;;;;\nE010D;VARIATION SELECTOR-30;Mn;0;NSM;;;;;N;;;;;\nE010E;VARIATION SELECTOR-31;Mn;0;NSM;;;;;N;;;;;\nE010F;VARIATION SELECTOR-32;Mn;0;NSM;;;;;N;;;;;\nE0110;VARIATION SELECTOR-33;Mn;0;NSM;;;;;N;;;;;\nE0111;VARIATION SELECTOR-34;Mn;0;NSM;;;;;N;;;;;\nE0112;VARIATION SELECTOR-35;Mn;0;NSM;;;;;N;;;;;\nE0113;VARIATION SELECTOR-36;Mn;0;NSM;;;;;N;;;;;\nE0114;VARIATION SELECTOR-37;Mn;0;NSM;;;;;N;;;;;\nE0115;VARIATION SELECTOR-38;Mn;0;NSM;;;;;N;;;;;\nE0116;VARIATION SELECTOR-39;Mn;0;NSM;;;;;N;;;;;\nE0117;VARIATION SELECTOR-40;Mn;0;NSM;;;;;N;;;;;\nE0118;VARIATION SELECTOR-41;Mn;0;NSM;;;;;N;;;;;\nE0119;VARIATION SELECTOR-42;Mn;0;NSM;;;;;N;;;;;\nE011A;VARIATION SELECTOR-43;Mn;0;NSM;;;;;N;;;;;\nE011B;VARIATION SELECTOR-44;Mn;0;NSM;;;;;N;;;;;\nE011C;VARIATION SELECTOR-45;Mn;0;NSM;;;;;N;;;;;\nE011D;VARIATION SELECTOR-46;Mn;0;NSM;;;;;N;;;;;\nE011E;VARIATION SELECTOR-47;Mn;0;NSM;;;;;N;;;;;\nE011F;VARIATION SELECTOR-48;Mn;0;NSM;;;;;N;;;;;\nE0120;VARIATION SELECTOR-49;Mn;0;NSM;;;;;N;;;;;\nE0121;VARIATION SELECTOR-50;Mn;0;NSM;;;;;N;;;;;\nE0122;VARIATION SELECTOR-51;Mn;0;NSM;;;;;N;;;;;\nE0123;VARIATION SELECTOR-52;Mn;0;NSM;;;;;N;;;;;\nE0124;VARIATION SELECTOR-53;Mn;0;NSM;;;;;N;;;;;\nE0125;VARIATION SELECTOR-54;Mn;0;NSM;;;;;N;;;;;\nE0126;VARIATION SELECTOR-55;Mn;0;NSM;;;;;N;;;;;\nE0127;VARIATION SELECTOR-56;Mn;0;NSM;;;;;N;;;;;\nE0128;VARIATION SELECTOR-57;Mn;0;NSM;;;;;N;;;;;\nE0129;VARIATION SELECTOR-58;Mn;0;NSM;;;;;N;;;;;\nE012A;VARIATION SELECTOR-59;Mn;0;NSM;;;;;N;;;;;\nE012B;VARIATION SELECTOR-60;Mn;0;NSM;;;;;N;;;;;\nE012C;VARIATION SELECTOR-61;Mn;0;NSM;;;;;N;;;;;\nE012D;VARIATION SELECTOR-62;Mn;0;NSM;;;;;N;;;;;\nE012E;VARIATION SELECTOR-63;Mn;0;NSM;;;;;N;;;;;\nE012F;VARIATION SELECTOR-64;Mn;0;NSM;;;;;N;;;;;\nE0130;VARIATION SELECTOR-65;Mn;0;NSM;;;;;N;;;;;\nE0131;VARIATION SELECTOR-66;Mn;0;NSM;;;;;N;;;;;\nE0132;VARIATION SELECTOR-67;Mn;0;NSM;;;;;N;;;;;\nE0133;VARIATION SELECTOR-68;Mn;0;NSM;;;;;N;;;;;\nE0134;VARIATION SELECTOR-69;Mn;0;NSM;;;;;N;;;;;\nE0135;VARIATION SELECTOR-70;Mn;0;NSM;;;;;N;;;;;\nE0136;VARIATION SELECTOR-71;Mn;0;NSM;;;;;N;;;;;\nE0137;VARIATION SELECTOR-72;Mn;0;NSM;;;;;N;;;;;\nE0138;VARIATION SELECTOR-73;Mn;0;NSM;;;;;N;;;;;\nE0139;VARIATION SELECTOR-74;Mn;0;NSM;;;;;N;;;;;\nE013A;VARIATION SELECTOR-75;Mn;0;NSM;;;;;N;;;;;\nE013B;VARIATION SELECTOR-76;Mn;0;NSM;;;;;N;;;;;\nE013C;VARIATION SELECTOR-77;Mn;0;NSM;;;;;N;;;;;\nE013D;VARIATION SELECTOR-78;Mn;0;NSM;;;;;N;;;;;\nE013E;VARIATION SELECTOR-79;Mn;0;NSM;;;;;N;;;;;\nE013F;VARIATION SELECTOR-80;Mn;0;NSM;;;;;N;;;;;\nE0140;VARIATION SELECTOR-81;Mn;0;NSM;;;;;N;;;;;\nE0141;VARIATION SELECTOR-82;Mn;0;NSM;;;;;N;;;;;\nE0142;VARIATION SELECTOR-83;Mn;0;NSM;;;;;N;;;;;\nE0143;VARIATION SELECTOR-84;Mn;0;NSM;;;;;N;;;;;\nE0144;VARIATION SELECTOR-85;Mn;0;NSM;;;;;N;;;;;\nE0145;VARIATION SELECTOR-86;Mn;0;NSM;;;;;N;;;;;\nE0146;VARIATION SELECTOR-87;Mn;0;NSM;;;;;N;;;;;\nE0147;VARIATION SELECTOR-88;Mn;0;NSM;;;;;N;;;;;\nE0148;VARIATION SELECTOR-89;Mn;0;NSM;;;;;N;;;;;\nE0149;VARIATION SELECTOR-90;Mn;0;NSM;;;;;N;;;;;\nE014A;VARIATION SELECTOR-91;Mn;0;NSM;;;;;N;;;;;\nE014B;VARIATION SELECTOR-92;Mn;0;NSM;;;;;N;;;;;\nE014C;VARIATION SELECTOR-93;Mn;0;NSM;;;;;N;;;;;\nE014D;VARIATION SELECTOR-94;Mn;0;NSM;;;;;N;;;;;\nE014E;VARIATION SELECTOR-95;Mn;0;NSM;;;;;N;;;;;\nE014F;VARIATION SELECTOR-96;Mn;0;NSM;;;;;N;;;;;\nE0150;VARIATION SELECTOR-97;Mn;0;NSM;;;;;N;;;;;\nE0151;VARIATION SELECTOR-98;Mn;0;NSM;;;;;N;;;;;\nE0152;VARIATION SELECTOR-99;Mn;0;NSM;;;;;N;;;;;\nE0153;VARIATION SELECTOR-100;Mn;0;NSM;;;;;N;;;;;\nE0154;VARIATION SELECTOR-101;Mn;0;NSM;;;;;N;;;;;\nE0155;VARIATION SELECTOR-102;Mn;0;NSM;;;;;N;;;;;\nE0156;VARIATION SELECTOR-103;Mn;0;NSM;;;;;N;;;;;\nE0157;VARIATION SELECTOR-104;Mn;0;NSM;;;;;N;;;;;\nE0158;VARIATION SELECTOR-105;Mn;0;NSM;;;;;N;;;;;\nE0159;VARIATION SELECTOR-106;Mn;0;NSM;;;;;N;;;;;\nE015A;VARIATION SELECTOR-107;Mn;0;NSM;;;;;N;;;;;\nE015B;VARIATION SELECTOR-108;Mn;0;NSM;;;;;N;;;;;\nE015C;VARIATION SELECTOR-109;Mn;0;NSM;;;;;N;;;;;\nE015D;VARIATION SELECTOR-110;Mn;0;NSM;;;;;N;;;;;\nE015E;VARIATION SELECTOR-111;Mn;0;NSM;;;;;N;;;;;\nE015F;VARIATION SELECTOR-112;Mn;0;NSM;;;;;N;;;;;\nE0160;VARIATION SELECTOR-113;Mn;0;NSM;;;;;N;;;;;\nE0161;VARIATION SELECTOR-114;Mn;0;NSM;;;;;N;;;;;\nE0162;VARIATION SELECTOR-115;Mn;0;NSM;;;;;N;;;;;\nE0163;VARIATION SELECTOR-116;Mn;0;NSM;;;;;N;;;;;\nE0164;VARIATION SELECTOR-117;Mn;0;NSM;;;;;N;;;;;\nE0165;VARIATION SELECTOR-118;Mn;0;NSM;;;;;N;;;;;\nE0166;VARIATION SELECTOR-119;Mn;0;NSM;;;;;N;;;;;\nE0167;VARIATION SELECTOR-120;Mn;0;NSM;;;;;N;;;;;\nE0168;VARIATION SELECTOR-121;Mn;0;NSM;;;;;N;;;;;\nE0169;VARIATION SELECTOR-122;Mn;0;NSM;;;;;N;;;;;\nE016A;VARIATION SELECTOR-123;Mn;0;NSM;;;;;N;;;;;\nE016B;VARIATION SELECTOR-124;Mn;0;NSM;;;;;N;;;;;\nE016C;VARIATION SELECTOR-125;Mn;0;NSM;;;;;N;;;;;\nE016D;VARIATION SELECTOR-126;Mn;0;NSM;;;;;N;;;;;\nE016E;VARIATION SELECTOR-127;Mn;0;NSM;;;;;N;;;;;\nE016F;VARIATION SELECTOR-128;Mn;0;NSM;;;;;N;;;;;\nE0170;VARIATION SELECTOR-129;Mn;0;NSM;;;;;N;;;;;\nE0171;VARIATION SELECTOR-130;Mn;0;NSM;;;;;N;;;;;\nE0172;VARIATION SELECTOR-131;Mn;0;NSM;;;;;N;;;;;\nE0173;VARIATION SELECTOR-132;Mn;0;NSM;;;;;N;;;;;\nE0174;VARIATION SELECTOR-133;Mn;0;NSM;;;;;N;;;;;\nE0175;VARIATION SELECTOR-134;Mn;0;NSM;;;;;N;;;;;\nE0176;VARIATION SELECTOR-135;Mn;0;NSM;;;;;N;;;;;\nE0177;VARIATION SELECTOR-136;Mn;0;NSM;;;;;N;;;;;\nE0178;VARIATION SELECTOR-137;Mn;0;NSM;;;;;N;;;;;\nE0179;VARIATION SELECTOR-138;Mn;0;NSM;;;;;N;;;;;\nE017A;VARIATION SELECTOR-139;Mn;0;NSM;;;;;N;;;;;\nE017B;VARIATION SELECTOR-140;Mn;0;NSM;;;;;N;;;;;\nE017C;VARIATION SELECTOR-141;Mn;0;NSM;;;;;N;;;;;\nE017D;VARIATION SELECTOR-142;Mn;0;NSM;;;;;N;;;;;\nE017E;VARIATION SELECTOR-143;Mn;0;NSM;;;;;N;;;;;\nE017F;VARIATION SELECTOR-144;Mn;0;NSM;;;;;N;;;;;\nE0180;VARIATION SELECTOR-145;Mn;0;NSM;;;;;N;;;;;\nE0181;VARIATION SELECTOR-146;Mn;0;NSM;;;;;N;;;;;\nE0182;VARIATION SELECTOR-147;Mn;0;NSM;;;;;N;;;;;\nE0183;VARIATION SELECTOR-148;Mn;0;NSM;;;;;N;;;;;\nE0184;VARIATION SELECTOR-149;Mn;0;NSM;;;;;N;;;;;\nE0185;VARIATION SELECTOR-150;Mn;0;NSM;;;;;N;;;;;\nE0186;VARIATION SELECTOR-151;Mn;0;NSM;;;;;N;;;;;\nE0187;VARIATION SELECTOR-152;Mn;0;NSM;;;;;N;;;;;\nE0188;VARIATION SELECTOR-153;Mn;0;NSM;;;;;N;;;;;\nE0189;VARIATION SELECTOR-154;Mn;0;NSM;;;;;N;;;;;\nE018A;VARIATION SELECTOR-155;Mn;0;NSM;;;;;N;;;;;\nE018B;VARIATION SELECTOR-156;Mn;0;NSM;;;;;N;;;;;\nE018C;VARIATION SELECTOR-157;Mn;0;NSM;;;;;N;;;;;\nE018D;VARIATION SELECTOR-158;Mn;0;NSM;;;;;N;;;;;\nE018E;VARIATION SELECTOR-159;Mn;0;NSM;;;;;N;;;;;\nE018F;VARIATION SELECTOR-160;Mn;0;NSM;;;;;N;;;;;\nE0190;VARIATION SELECTOR-161;Mn;0;NSM;;;;;N;;;;;\nE0191;VARIATION SELECTOR-162;Mn;0;NSM;;;;;N;;;;;\nE0192;VARIATION SELECTOR-163;Mn;0;NSM;;;;;N;;;;;\nE0193;VARIATION SELECTOR-164;Mn;0;NSM;;;;;N;;;;;\nE0194;VARIATION SELECTOR-165;Mn;0;NSM;;;;;N;;;;;\nE0195;VARIATION SELECTOR-166;Mn;0;NSM;;;;;N;;;;;\nE0196;VARIATION SELECTOR-167;Mn;0;NSM;;;;;N;;;;;\nE0197;VARIATION SELECTOR-168;Mn;0;NSM;;;;;N;;;;;\nE0198;VARIATION SELECTOR-169;Mn;0;NSM;;;;;N;;;;;\nE0199;VARIATION SELECTOR-170;Mn;0;NSM;;;;;N;;;;;\nE019A;VARIATION SELECTOR-171;Mn;0;NSM;;;;;N;;;;;\nE019B;VARIATION SELECTOR-172;Mn;0;NSM;;;;;N;;;;;\nE019C;VARIATION SELECTOR-173;Mn;0;NSM;;;;;N;;;;;\nE019D;VARIATION SELECTOR-174;Mn;0;NSM;;;;;N;;;;;\nE019E;VARIATION SELECTOR-175;Mn;0;NSM;;;;;N;;;;;\nE019F;VARIATION SELECTOR-176;Mn;0;NSM;;;;;N;;;;;\nE01A0;VARIATION SELECTOR-177;Mn;0;NSM;;;;;N;;;;;\nE01A1;VARIATION SELECTOR-178;Mn;0;NSM;;;;;N;;;;;\nE01A2;VARIATION SELECTOR-179;Mn;0;NSM;;;;;N;;;;;\nE01A3;VARIATION SELECTOR-180;Mn;0;NSM;;;;;N;;;;;\nE01A4;VARIATION SELECTOR-181;Mn;0;NSM;;;;;N;;;;;\nE01A5;VARIATION SELECTOR-182;Mn;0;NSM;;;;;N;;;;;\nE01A6;VARIATION SELECTOR-183;Mn;0;NSM;;;;;N;;;;;\nE01A7;VARIATION SELECTOR-184;Mn;0;NSM;;;;;N;;;;;\nE01A8;VARIATION SELECTOR-185;Mn;0;NSM;;;;;N;;;;;\nE01A9;VARIATION SELECTOR-186;Mn;0;NSM;;;;;N;;;;;\nE01AA;VARIATION SELECTOR-187;Mn;0;NSM;;;;;N;;;;;\nE01AB;VARIATION SELECTOR-188;Mn;0;NSM;;;;;N;;;;;\nE01AC;VARIATION SELECTOR-189;Mn;0;NSM;;;;;N;;;;;\nE01AD;VARIATION SELECTOR-190;Mn;0;NSM;;;;;N;;;;;\nE01AE;VARIATION SELECTOR-191;Mn;0;NSM;;;;;N;;;;;\nE01AF;VARIATION SELECTOR-192;Mn;0;NSM;;;;;N;;;;;\nE01B0;VARIATION SELECTOR-193;Mn;0;NSM;;;;;N;;;;;\nE01B1;VARIATION SELECTOR-194;Mn;0;NSM;;;;;N;;;;;\nE01B2;VARIATION SELECTOR-195;Mn;0;NSM;;;;;N;;;;;\nE01B3;VARIATION SELECTOR-196;Mn;0;NSM;;;;;N;;;;;\nE01B4;VARIATION SELECTOR-197;Mn;0;NSM;;;;;N;;;;;\nE01B5;VARIATION SELECTOR-198;Mn;0;NSM;;;;;N;;;;;\nE01B6;VARIATION SELECTOR-199;Mn;0;NSM;;;;;N;;;;;\nE01B7;VARIATION SELECTOR-200;Mn;0;NSM;;;;;N;;;;;\nE01B8;VARIATION SELECTOR-201;Mn;0;NSM;;;;;N;;;;;\nE01B9;VARIATION SELECTOR-202;Mn;0;NSM;;;;;N;;;;;\nE01BA;VARIATION SELECTOR-203;Mn;0;NSM;;;;;N;;;;;\nE01BB;VARIATION SELECTOR-204;Mn;0;NSM;;;;;N;;;;;\nE01BC;VARIATION SELECTOR-205;Mn;0;NSM;;;;;N;;;;;\nE01BD;VARIATION SELECTOR-206;Mn;0;NSM;;;;;N;;;;;\nE01BE;VARIATION SELECTOR-207;Mn;0;NSM;;;;;N;;;;;\nE01BF;VARIATION SELECTOR-208;Mn;0;NSM;;;;;N;;;;;\nE01C0;VARIATION SELECTOR-209;Mn;0;NSM;;;;;N;;;;;\nE01C1;VARIATION SELECTOR-210;Mn;0;NSM;;;;;N;;;;;\nE01C2;VARIATION SELECTOR-211;Mn;0;NSM;;;;;N;;;;;\nE01C3;VARIATION SELECTOR-212;Mn;0;NSM;;;;;N;;;;;\nE01C4;VARIATION SELECTOR-213;Mn;0;NSM;;;;;N;;;;;\nE01C5;VARIATION SELECTOR-214;Mn;0;NSM;;;;;N;;;;;\nE01C6;VARIATION SELECTOR-215;Mn;0;NSM;;;;;N;;;;;\nE01C7;VARIATION SELECTOR-216;Mn;0;NSM;;;;;N;;;;;\nE01C8;VARIATION SELECTOR-217;Mn;0;NSM;;;;;N;;;;;\nE01C9;VARIATION SELECTOR-218;Mn;0;NSM;;;;;N;;;;;\nE01CA;VARIATION SELECTOR-219;Mn;0;NSM;;;;;N;;;;;\nE01CB;VARIATION SELECTOR-220;Mn;0;NSM;;;;;N;;;;;\nE01CC;VARIATION SELECTOR-221;Mn;0;NSM;;;;;N;;;;;\nE01CD;VARIATION SELECTOR-222;Mn;0;NSM;;;;;N;;;;;\nE01CE;VARIATION SELECTOR-223;Mn;0;NSM;;;;;N;;;;;\nE01CF;VARIATION SELECTOR-224;Mn;0;NSM;;;;;N;;;;;\nE01D0;VARIATION SELECTOR-225;Mn;0;NSM;;;;;N;;;;;\nE01D1;VARIATION SELECTOR-226;Mn;0;NSM;;;;;N;;;;;\nE01D2;VARIATION SELECTOR-227;Mn;0;NSM;;;;;N;;;;;\nE01D3;VARIATION SELECTOR-228;Mn;0;NSM;;;;;N;;;;;\nE01D4;VARIATION SELECTOR-229;Mn;0;NSM;;;;;N;;;;;\nE01D5;VARIATION SELECTOR-230;Mn;0;NSM;;;;;N;;;;;\nE01D6;VARIATION SELECTOR-231;Mn;0;NSM;;;;;N;;;;;\nE01D7;VARIATION SELECTOR-232;Mn;0;NSM;;;;;N;;;;;\nE01D8;VARIATION SELECTOR-233;Mn;0;NSM;;;;;N;;;;;\nE01D9;VARIATION SELECTOR-234;Mn;0;NSM;;;;;N;;;;;\nE01DA;VARIATION SELECTOR-235;Mn;0;NSM;;;;;N;;;;;\nE01DB;VARIATION SELECTOR-236;Mn;0;NSM;;;;;N;;;;;\nE01DC;VARIATION SELECTOR-237;Mn;0;NSM;;;;;N;;;;;\nE01DD;VARIATION SELECTOR-238;Mn;0;NSM;;;;;N;;;;;\nE01DE;VARIATION SELECTOR-239;Mn;0;NSM;;;;;N;;;;;\nE01DF;VARIATION SELECTOR-240;Mn;0;NSM;;;;;N;;;;;\nE01E0;VARIATION SELECTOR-241;Mn;0;NSM;;;;;N;;;;;\nE01E1;VARIATION SELECTOR-242;Mn;0;NSM;;;;;N;;;;;\nE01E2;VARIATION SELECTOR-243;Mn;0;NSM;;;;;N;;;;;\nE01E3;VARIATION SELECTOR-244;Mn;0;NSM;;;;;N;;;;;\nE01E4;VARIATION SELECTOR-245;Mn;0;NSM;;;;;N;;;;;\nE01E5;VARIATION SELECTOR-246;Mn;0;NSM;;;;;N;;;;;\nE01E6;VARIATION SELECTOR-247;Mn;0;NSM;;;;;N;;;;;\nE01E7;VARIATION SELECTOR-248;Mn;0;NSM;;;;;N;;;;;\nE01E8;VARIATION SELECTOR-249;Mn;0;NSM;;;;;N;;;;;\nE01E9;VARIATION SELECTOR-250;Mn;0;NSM;;;;;N;;;;;\nE01EA;VARIATION SELECTOR-251;Mn;0;NSM;;;;;N;;;;;\nE01EB;VARIATION SELECTOR-252;Mn;0;NSM;;;;;N;;;;;\nE01EC;VARIATION SELECTOR-253;Mn;0;NSM;;;;;N;;;;;\nE01ED;VARIATION SELECTOR-254;Mn;0;NSM;;;;;N;;;;;\nE01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;;\nE01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;;\nF0000;<Plane 15 Private Use, First>;Co;0;L;;;;;N;;;;;\nFFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N;;;;;\n100000;<Plane 16 Private Use, First>;Co;0;L;;;;;N;;;;;\n10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;N;;;;;\n"
  },
  {
    "path": "lib/elixir/unicode/confusables.txt",
    "content": "# confusables.txt\n# Date: 2025-07-22, 05:49:37 GMT\n# © 2025 Unicode®, Inc.\n# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.\n# For terms of use and license, see https://www.unicode.org/terms_of_use.html\n#\n# Unicode Security Mechanisms for UTS #39\n# Version: 17.0.0\n#\n# For documentation and usage, see https://www.unicode.org/reports/tr39\n#\n05AD ;\t0596 ;\tMA\t# ( ֭ → ֖ ) HEBREW ACCENT DEHI → HEBREW ACCENT TIPEHA\t# \n\n05AE ;\t0598 ;\tMA\t# ( ֮ → ֘ ) HEBREW ACCENT ZINOR → HEBREW ACCENT ZARQA\t# \n\n05A8 ;\t0599 ;\tMA\t# ( ֨ → ֙ ) HEBREW ACCENT QADMA → HEBREW ACCENT PASHTA\t# \n\n05A4 ;\t059A ;\tMA\t# ( ֤ → ֚ ) HEBREW ACCENT MAHAPAKH → HEBREW ACCENT YETIV\t# \n\n1AB4 ;\t06DB ;\tMA\t# ( ᪴ → ۛ ) COMBINING TRIPLE DOT → ARABIC SMALL HIGH THREE DOTS\t# \n20DB ;\t06DB ;\tMA\t# ( ⃛ → ۛ ) COMBINING THREE DOTS ABOVE → ARABIC SMALL HIGH THREE DOTS\t# →᪴→\n\n0619 ;\t0313 ;\tMA\t# ( ؙ → ̓ ) ARABIC SMALL DAMMA → COMBINING COMMA ABOVE\t# →ُ→\n08F3 ;\t0313 ;\tMA\t# ( ࣳ → ̓ ) ARABIC SMALL HIGH WAW → COMBINING COMMA ABOVE\t# →ُ→\n0343 ;\t0313 ;\tMA\t# ( ̓ → ̓ ) COMBINING GREEK KORONIS → COMBINING COMMA ABOVE\t# \n0315 ;\t0313 ;\tMA\t# ( ̕ → ̓ ) COMBINING COMMA ABOVE RIGHT → COMBINING COMMA ABOVE\t# \n064F ;\t0313 ;\tMA\t# ( ُ → ̓ ) ARABIC DAMMA → COMBINING COMMA ABOVE\t# \n\n065D ;\t0314 ;\tMA\t# ( ٝ → ̔ ) ARABIC REVERSED DAMMA → COMBINING REVERSED COMMA ABOVE\t# \n\n059C ;\t0301 ;\tMA\t# ( ֜ → ́ ) HEBREW ACCENT GERESH → COMBINING ACUTE ACCENT\t# \n059D ;\t0301 ;\tMA\t# ( ֝ → ́ ) HEBREW ACCENT GERESH MUQDAM → COMBINING ACUTE ACCENT\t# →֜→\n0618 ;\t0301 ;\tMA\t# ( ؘ → ́ ) ARABIC SMALL FATHA → COMBINING ACUTE ACCENT\t# →َ→\n0747 ;\t0301 ;\tMA\t# ( ݇ → ́ ) SYRIAC OBLIQUE LINE ABOVE → COMBINING ACUTE ACCENT\t# \n0341 ;\t0301 ;\tMA\t# ( ́ → ́ ) COMBINING ACUTE TONE MARK → COMBINING ACUTE ACCENT\t# \n0954 ;\t0301 ;\tMA\t# ( ॔ → ́ ) DEVANAGARI ACUTE ACCENT → COMBINING ACUTE ACCENT\t# \n064E ;\t0301 ;\tMA\t# ( َ → ́ ) ARABIC FATHA → COMBINING ACUTE ACCENT\t# \n\n0340 ;\t0300 ;\tMA\t# ( ̀ → ̀ ) COMBINING GRAVE TONE MARK → COMBINING GRAVE ACCENT\t# \n0953 ;\t0300 ;\tMA\t# ( ॓ → ̀ ) DEVANAGARI GRAVE ACCENT → COMBINING GRAVE ACCENT\t# \n\n030C ;\t0306 ;\tMA\t# ( ̌ → ̆ ) COMBINING CARON → COMBINING BREVE\t# \nA67C ;\t0306 ;\tMA\t# ( ꙼ → ̆ ) COMBINING CYRILLIC KAVYKA → COMBINING BREVE\t# \n0658 ;\t0306 ;\tMA\t# ( ٘ → ̆ ) ARABIC MARK NOON GHUNNA → COMBINING BREVE\t# \n065A ;\t0306 ;\tMA\t# ( ٚ → ̆ ) ARABIC VOWEL SIGN SMALL V ABOVE → COMBINING BREVE\t# →̌→\n036E ;\t0306 ;\tMA\t# ( ͮ → ̆ ) COMBINING LATIN SMALL LETTER V → COMBINING BREVE\t# →̌→\n0945 ;\t0306 ;\tMA\t# ( ॅ → ̆ ) DEVANAGARI VOWEL SIGN CANDRA E → COMBINING BREVE\t# \n11B66 ;\t0306 ;\tMA\t# ( 𑭦 → ̆ ) SHARADA VOWEL SIGN CANDRA E → COMBINING BREVE\t# →ॅ→\n\n06E8 ;\t0306 0307 ;\tMA\t# ( ۨ → ̆̇ ) ARABIC SMALL HIGH NOON → COMBINING BREVE, COMBINING DOT ABOVE\t# →̐→\n0310 ;\t0306 0307 ;\tMA\t# ( ̐ → ̆̇ ) COMBINING CANDRABINDU → COMBINING BREVE, COMBINING DOT ABOVE\t# \n0901 ;\t0306 0307 ;\tMA\t# ( ँ → ̆̇ ) DEVANAGARI SIGN CANDRABINDU → COMBINING BREVE, COMBINING DOT ABOVE\t# →̐→\n0981 ;\t0306 0307 ;\tMA\t# ( ঁ → ̆̇ ) BENGALI SIGN CANDRABINDU → COMBINING BREVE, COMBINING DOT ABOVE\t# →̐→\n0A81 ;\t0306 0307 ;\tMA\t# ( ઁ → ̆̇ ) GUJARATI SIGN CANDRABINDU → COMBINING BREVE, COMBINING DOT ABOVE\t# →̐→\n0B01 ;\t0306 0307 ;\tMA\t# ( ଁ → ̆̇ ) ORIYA SIGN CANDRABINDU → COMBINING BREVE, COMBINING DOT ABOVE\t# →̐→\n0C00 ;\t0306 0307 ;\tMA\t# ( ఀ → ̆̇ ) TELUGU SIGN COMBINING CANDRABINDU ABOVE → COMBINING BREVE, COMBINING DOT ABOVE\t# →ँ→→̐→\n0C81 ;\t0306 0307 ;\tMA\t# ( ಁ → ̆̇ ) KANNADA SIGN CANDRABINDU → COMBINING BREVE, COMBINING DOT ABOVE\t# →ँ→→̐→\n0D01 ;\t0306 0307 ;\tMA\t# ( ഁ → ̆̇ ) MALAYALAM SIGN CANDRABINDU → COMBINING BREVE, COMBINING DOT ABOVE\t# →ँ→→̐→\n114BF ;\t0306 0307 ;\tMA\t# ( 𑒿 → ̆̇ ) TIRHUTA SIGN CANDRABINDU → COMBINING BREVE, COMBINING DOT ABOVE\t# →ঁ→→̐→\n\n1CD0 ;\t0302 ;\tMA\t# ( ᳐ → ̂ ) VEDIC TONE KARSHANA → COMBINING CIRCUMFLEX ACCENT\t# \n0311 ;\t0302 ;\tMA\t# ( ̑ → ̂ ) COMBINING INVERTED BREVE → COMBINING CIRCUMFLEX ACCENT\t# \n065B ;\t0302 ;\tMA\t# ( ٛ → ̂ ) ARABIC VOWEL SIGN INVERTED SMALL V ABOVE → COMBINING CIRCUMFLEX ACCENT\t# \n07EE ;\t0302 ;\tMA\t# ( ߮ → ̂ ) NKO COMBINING LONG DESCENDING TONE → COMBINING CIRCUMFLEX ACCENT\t# \nA6F0 ;\t0302 ;\tMA\t# ( ꛰ → ̂ ) BAMUM COMBINING MARK KOQNDON → COMBINING CIRCUMFLEX ACCENT\t# \n\n05AF ;\t030A ;\tMA\t# ( ֯ → ̊ ) HEBREW MARK MASORA CIRCLE → COMBINING RING ABOVE\t# \n06DF ;\t030A ;\tMA\t# ( ۟ → ̊ ) ARABIC SMALL HIGH ROUNDED ZERO → COMBINING RING ABOVE\t# →ْ→\n17D3 ;\t030A ;\tMA\t# ( ៓ → ̊ ) KHMER SIGN BATHAMASAT → COMBINING RING ABOVE\t# \n309A ;\t030A ;\tMA\t# ( ゚ → ̊ ) COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK → COMBINING RING ABOVE\t# \n0652 ;\t030A ;\tMA\t# ( ْ → ̊ ) ARABIC SUKUN → COMBINING RING ABOVE\t# \n0B82 ;\t030A ;\tMA\t# ( ஂ → ̊ ) TAMIL SIGN ANUSVARA → COMBINING RING ABOVE\t# \n1036 ;\t030A ;\tMA\t# ( ံ → ̊ ) MYANMAR SIGN ANUSVARA → COMBINING RING ABOVE\t# \n17C6 ;\t030A ;\tMA\t# ( ំ → ̊ ) KHMER SIGN NIKAHIT → COMBINING RING ABOVE\t# \n11300 ;\t030A ;\tMA\t# ( 𑌀 → ̊ ) GRANTHA SIGN COMBINING ANUSVARA ABOVE → COMBINING RING ABOVE\t# →ஂ→\n0E4D ;\t030A ;\tMA\t# ( ํ → ̊ ) THAI CHARACTER NIKHAHIT → COMBINING RING ABOVE\t# \n0ECD ;\t030A ;\tMA\t# ( ໍ → ̊ ) LAO NIGGAHITA → COMBINING RING ABOVE\t# \n0366 ;\t030A ;\tMA\t# ( ͦ → ̊ ) COMBINING LATIN SMALL LETTER O → COMBINING RING ABOVE\t# \n2DEA ;\t030A ;\tMA\t# ( ⷪ → ̊ ) COMBINING CYRILLIC LETTER O → COMBINING RING ABOVE\t# →ͦ→\n\n08EB ;\t0308 ;\tMA\t# ( ࣫ → ̈ ) ARABIC TONE TWO DOTS ABOVE → COMBINING DIAERESIS\t# \n07F3 ;\t0308 ;\tMA\t# ( ߳ → ̈ ) NKO COMBINING DOUBLE DOT ABOVE → COMBINING DIAERESIS\t# \n\n064B ;\t030B ;\tMA\t# ( ً → ̋ ) ARABIC FATHATAN → COMBINING DOUBLE ACUTE ACCENT\t# \n08F0 ;\t030B ;\tMA\t# ( ࣰ → ̋ ) ARABIC OPEN FATHATAN → COMBINING DOUBLE ACUTE ACCENT\t# →ً→\n\n0342 ;\t0303 ;\tMA\t# ( ͂ → ̃ ) COMBINING GREEK PERISPOMENI → COMBINING TILDE\t# \n0653 ;\t0303 ;\tMA\t# ( ٓ → ̃ ) ARABIC MADDAH ABOVE → COMBINING TILDE\t# \n\n05C4 ;\t0307 ;\tMA\t# ( ׄ → ̇ ) HEBREW MARK UPPER DOT → COMBINING DOT ABOVE\t# \n06EC ;\t0307 ;\tMA\t# ( ۬ → ̇ ) ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE → COMBINING DOT ABOVE\t# \n0740 ;\t0307 ;\tMA\t# ( ݀ → ̇ ) SYRIAC FEMININE DOT → COMBINING DOT ABOVE\t# →݁→\n08EA ;\t0307 ;\tMA\t# ( ࣪ → ̇ ) ARABIC TONE ONE DOT ABOVE → COMBINING DOT ABOVE\t# \n0741 ;\t0307 ;\tMA\t# ( ݁ → ̇ ) SYRIAC QUSHSHAYA → COMBINING DOT ABOVE\t# \n0358 ;\t0307 ;\tMA\t# ( ͘ → ̇ ) COMBINING DOT ABOVE RIGHT → COMBINING DOT ABOVE\t# \n05B9 ;\t0307 ;\tMA\t# ( ֹ → ̇ ) HEBREW POINT HOLAM → COMBINING DOT ABOVE\t# \n05BA ;\t0307 ;\tMA\t# ( ֺ → ̇ ) HEBREW POINT HOLAM HASER FOR VAV → COMBINING DOT ABOVE\t# →ׁ→\n05C2 ;\t0307 ;\tMA\t# ( ׂ → ̇ ) HEBREW POINT SIN DOT → COMBINING DOT ABOVE\t# \n05C1 ;\t0307 ;\tMA\t# ( ׁ → ̇ ) HEBREW POINT SHIN DOT → COMBINING DOT ABOVE\t# \n07ED ;\t0307 ;\tMA\t# ( ߭ → ̇ ) NKO COMBINING SHORT RISING TONE → COMBINING DOT ABOVE\t# \n0902 ;\t0307 ;\tMA\t# ( ं → ̇ ) DEVANAGARI SIGN ANUSVARA → COMBINING DOT ABOVE\t# \n0A02 ;\t0307 ;\tMA\t# ( ਂ → ̇ ) GURMUKHI SIGN BINDI → COMBINING DOT ABOVE\t# \n0A82 ;\t0307 ;\tMA\t# ( ં → ̇ ) GUJARATI SIGN ANUSVARA → COMBINING DOT ABOVE\t# \n0BCD ;\t0307 ;\tMA\t# ( ் → ̇ ) TAMIL SIGN VIRAMA → COMBINING DOT ABOVE\t# \n\n0337 ;\t0338 ;\tMA\t# ( ̷ → ̸ ) COMBINING SHORT SOLIDUS OVERLAY → COMBINING LONG SOLIDUS OVERLAY\t# \n\n1AB7 ;\t0328 ;\tMA\t# ( ᪷ → ̨ ) COMBINING OPEN MARK BELOW → COMBINING OGONEK\t# \n0322 ;\t0328 ;\tMA\t# ( ̢ → ̨ ) COMBINING RETROFLEX HOOK BELOW → COMBINING OGONEK\t# \n0345 ;\t0328 ;\tMA\t# ( ͅ → ̨ ) COMBINING GREEK YPOGEGRAMMENI → COMBINING OGONEK\t# \n\n1CD2 ;\t0304 ;\tMA\t# ( ᳒ → ̄ ) VEDIC TONE PRENKHA → COMBINING MACRON\t# \n0305 ;\t0304 ;\tMA\t# ( ̅ → ̄ ) COMBINING OVERLINE → COMBINING MACRON\t# \n0659 ;\t0304 ;\tMA\t# ( ٙ → ̄ ) ARABIC ZWARAKAY → COMBINING MACRON\t# \n07EB ;\t0304 ;\tMA\t# ( ߫ → ̄ ) NKO COMBINING SHORT HIGH TONE → COMBINING MACRON\t# \nA6F1 ;\t0304 ;\tMA\t# ( ꛱ → ̄ ) BAMUM COMBINING MARK TUKWENTIS → COMBINING MACRON\t# \n1AE2 ;\t0304 ;\tMA\t# ( ᫢ → ̄ ) COMBINING MINUS SIGN ABOVE → COMBINING MACRON\t# \n\n1AE8 ;\t0304 0304 ;\tMA\t# ( ᫨ → ̄̄ ) COMBINING EQUALS SIGN ABOVE → COMBINING MACRON, COMBINING MACRON\t# \n\n1CDA ;\t030E ;\tMA\t# ( ᳚ → ̎ ) VEDIC TONE DOUBLE SVARITA → COMBINING DOUBLE VERTICAL LINE ABOVE\t# \n\n0657 ;\t0312 ;\tMA\t# ( ٗ → ̒ ) ARABIC INVERTED DAMMA → COMBINING TURNED COMMA ABOVE\t# \n\n0357 ;\t0350 ;\tMA\t# ( ͗ → ͐ ) COMBINING RIGHT HALF RING ABOVE → COMBINING RIGHT ARROWHEAD ABOVE\t# →ࣿ→→ࣸ→\n08FF ;\t0350 ;\tMA\t# ( ࣿ → ͐ ) ARABIC MARK SIDEWAYS NOON GHUNNA → COMBINING RIGHT ARROWHEAD ABOVE\t# →ࣸ→\n08F8 ;\t0350 ;\tMA\t# ( ࣸ → ͐ ) ARABIC RIGHT ARROWHEAD ABOVE → COMBINING RIGHT ARROWHEAD ABOVE\t# \n\n0900 ;\t0352 ;\tMA\t# ( ऀ → ͒ ) DEVANAGARI SIGN INVERTED CANDRABINDU → COMBINING FERMATA\t# \n\n1AD9 ;\t1AC6 ;\tMA\t# ( ᫙ → ᫆ ) COMBINING SHARP SIGN → COMBINING NUMBER SIGN ABOVE\t# \n\n1E6EE ;\t1AC8 ;\tMA\t# ( 𞛮 → ᫈ ) TAI YO SIGN AY → COMBINING PLUS SIGN ABOVE\t# \n\n1CED ;\t0316 ;\tMA\t# ( ᳭ → ̖ ) VEDIC SIGN TIRYAK → COMBINING GRAVE ACCENT BELOW\t# \n\n1CDC ;\t0329 ;\tMA\t# ( ᳜ → ̩ ) VEDIC TONE KATHAKA ANUDATTA → COMBINING VERTICAL LINE BELOW\t# \n0656 ;\t0329 ;\tMA\t# ( ٖ → ̩ ) ARABIC SUBSCRIPT ALEF → COMBINING VERTICAL LINE BELOW\t# \n\n1CD5 ;\t032B ;\tMA\t# ( ᳕ → ̫ ) VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA → COMBINING INVERTED DOUBLE ARCH BELOW\t# \n\n0347 ;\t0333 ;\tMA\t# ( ͇ → ̳ ) COMBINING EQUALS SIGN BELOW → COMBINING DOUBLE LOW LINE\t# \n\n08F9 ;\t0354 ;\tMA\t# ( ࣹ → ͔ ) ARABIC LEFT ARROWHEAD BELOW → COMBINING LEFT ARROWHEAD BELOW\t# \n\n08FA ;\t0355 ;\tMA\t# ( ࣺ → ͕ ) ARABIC RIGHT ARROWHEAD BELOW → COMBINING RIGHT ARROWHEAD BELOW\t# \n\n309B ;\tFF9E ;\tMA\t#* ( ゛ → ﾞ ) KATAKANA-HIRAGANA VOICED SOUND MARK → HALFWIDTH KATAKANA VOICED SOUND MARK\t# \n\n309C ;\tFF9F ;\tMA\t#* ( ゜ → ﾟ ) KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK → HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK\t# \n\n0336 ;\t0335 ;\tMA\t# ( ̶ → ̵ ) COMBINING LONG STROKE OVERLAY → COMBINING SHORT STROKE OVERLAY\t# \n\n302C ;\t0309 ;\tMA\t# ( 〬 → ̉ ) IDEOGRAPHIC DEPARTING TONE MARK → COMBINING HOOK ABOVE\t# \n\n05C5 ;\t0323 ;\tMA\t# ( ׅ → ̣ ) HEBREW MARK LOWER DOT → COMBINING DOT BELOW\t# \n08ED ;\t0323 ;\tMA\t# ( ࣭ → ̣ ) ARABIC TONE ONE DOT BELOW → COMBINING DOT BELOW\t# \n1CDD ;\t0323 ;\tMA\t# ( ᳝ → ̣ ) VEDIC TONE DOT BELOW → COMBINING DOT BELOW\t# \n05B4 ;\t0323 ;\tMA\t# ( ִ → ̣ ) HEBREW POINT HIRIQ → COMBINING DOT BELOW\t# \n065C ;\t0323 ;\tMA\t# ( ٜ → ̣ ) ARABIC VOWEL SIGN DOT BELOW → COMBINING DOT BELOW\t# \n093C ;\t0323 ;\tMA\t# ( ़ → ̣ ) DEVANAGARI SIGN NUKTA → COMBINING DOT BELOW\t# \n09BC ;\t0323 ;\tMA\t# ( ় → ̣ ) BENGALI SIGN NUKTA → COMBINING DOT BELOW\t# \n0A3C ;\t0323 ;\tMA\t# ( ਼ → ̣ ) GURMUKHI SIGN NUKTA → COMBINING DOT BELOW\t# \n0ABC ;\t0323 ;\tMA\t# ( ઼ → ̣ ) GUJARATI SIGN NUKTA → COMBINING DOT BELOW\t# \n0B3C ;\t0323 ;\tMA\t# ( ଼ → ̣ ) ORIYA SIGN NUKTA → COMBINING DOT BELOW\t# \n111CA ;\t0323 ;\tMA\t# ( 𑇊 → ̣ ) SHARADA SIGN NUKTA → COMBINING DOT BELOW\t# →़→\n114C3 ;\t0323 ;\tMA\t# ( 𑓃 → ̣ ) TIRHUTA SIGN NUKTA → COMBINING DOT BELOW\t# →়→\n10A3A ;\t0323 ;\tMA\t# ( 𐨺 → ̣ ) KHAROSHTHI SIGN DOT BELOW → COMBINING DOT BELOW\t# \n\n08EE ;\t0324 ;\tMA\t# ( ࣮ → ̤ ) ARABIC TONE TWO DOTS BELOW → COMBINING DIAERESIS BELOW\t# \n1CDE ;\t0324 ;\tMA\t# ( ᳞ → ̤ ) VEDIC TONE TWO DOTS BELOW → COMBINING DIAERESIS BELOW\t# \n\n0F37 ;\t0325 ;\tMA\t# ( ༷ → ̥ ) TIBETAN MARK NGAS BZUNG SGOR RTAGS → COMBINING RING BELOW\t# \n302D ;\t0325 ;\tMA\t# ( 〭 → ̥ ) IDEOGRAPHIC ENTERING TONE MARK → COMBINING RING BELOW\t# \n\n0327 ;\t0326 ;\tMA\t# ( ̧ → ̦ ) COMBINING CEDILLA → COMBINING COMMA BELOW\t# →̡→\n0321 ;\t0326 ;\tMA\t# ( ̡ → ̦ ) COMBINING PALATALIZED HOOK BELOW → COMBINING COMMA BELOW\t# \n0339 ;\t0326 ;\tMA\t# ( ̹ → ̦ ) COMBINING RIGHT HALF RING BELOW → COMBINING COMMA BELOW\t# →̧→→̡→\n\n1CD9 ;\t032D ;\tMA\t# ( ᳙ → ̭ ) VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER → COMBINING CIRCUMFLEX ACCENT BELOW\t# \n\n1CD8 ;\t032E ;\tMA\t# ( ᳘ → ̮ ) VEDIC TONE CANDRA BELOW → COMBINING BREVE BELOW\t# \n\n0952 ;\t0331 ;\tMA\t# ( ॒ → ̱ ) DEVANAGARI STRESS SIGN ANUDATTA → COMBINING MACRON BELOW\t# \n0320 ;\t0331 ;\tMA\t# ( ̠ → ̱ ) COMBINING MINUS SIGN BELOW → COMBINING MACRON BELOW\t# \n\n08F1 ;\t064C ;\tMA\t# ( ࣱ → ٌ ) ARABIC OPEN DAMMATAN → ARABIC DAMMATAN\t# \n08E8 ;\t064C ;\tMA\t# ( ࣨ → ٌ ) ARABIC CURLY DAMMATAN → ARABIC DAMMATAN\t# \n08E5 ;\t064C ;\tMA\t# ( ࣥ → ٌ ) ARABIC CURLY DAMMA → ARABIC DAMMATAN\t# \n\nFC5E ;\tFE72 0651 ;\tMA\t#* ( ‎ﱞ‎ → ‎ﹲّ‎ ) ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM → ARABIC DAMMATAN ISOLATED FORM, ARABIC SHADDA\t# \n\n08F2 ;\t064D ;\tMA\t# ( ࣲ → ٍ ) ARABIC OPEN KASRATAN → ARABIC KASRATAN\t# \n\nFC5F ;\tFE74 0651 ;\tMA\t#* ( ‎ﱟ‎ → ‎ﹴّ‎ ) ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM → ARABIC KASRATAN ISOLATED FORM, ARABIC SHADDA\t# \n\nFCF2 ;\tFE77 0651 ;\tMA\t# ( ‎ﳲ‎ → ‎ﹷّ‎ ) ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM → ARABIC FATHA MEDIAL FORM, ARABIC SHADDA\t# \n\nFC60 ;\tFE76 0651 ;\tMA\t#* ( ‎ﱠ‎ → ‎ﹶّ‎ ) ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM → ARABIC FATHA ISOLATED FORM, ARABIC SHADDA\t# \n\nFCF3 ;\tFE79 0651 ;\tMA\t# ( ‎ﳳ‎ → ‎ﹹّ‎ ) ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM → ARABIC DAMMA MEDIAL FORM, ARABIC SHADDA\t# \n\nFC61 ;\tFE78 0651 ;\tMA\t#* ( ‎ﱡ‎ → ‎ﹸّ‎ ) ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM → ARABIC DAMMA ISOLATED FORM, ARABIC SHADDA\t# \n\n061A ;\t0650 ;\tMA\t# ( ؚ → ِ ) ARABIC SMALL KASRA → ARABIC KASRA\t# \n0317 ;\t0650 ;\tMA\t# ( ̗ → ِ ) COMBINING ACUTE ACCENT BELOW → ARABIC KASRA\t# \n\nFCF4 ;\tFE7B 0651 ;\tMA\t# ( ‎ﳴ‎ → ‎ﹻّ‎ ) ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM → ARABIC KASRA MEDIAL FORM, ARABIC SHADDA\t# \n\nFC62 ;\tFE7A 0651 ;\tMA\t#* ( ‎ﱢ‎ → ‎ﹺّ‎ ) ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM → ARABIC KASRA ISOLATED FORM, ARABIC SHADDA\t# \n\nFC63 ;\tFE7C 0670 ;\tMA\t#* ( ‎ﱣ‎ → ‎ﹼٰ‎ ) ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM → ARABIC SHADDA ISOLATED FORM, ARABIC LETTER SUPERSCRIPT ALEF\t# \n\n065F ;\t0655 ;\tMA\t# ( ٟ → ٕ ) ARABIC WAVY HAMZA BELOW → ARABIC HAMZA BELOW\t# \n\n030D ;\t0670 ;\tMA\t# ( ̍ → ٰ ) COMBINING VERTICAL LINE ABOVE → ARABIC LETTER SUPERSCRIPT ALEF\t# \n\n0742 ;\t073C ;\tMA\t# ( ݂ → ܼ ) SYRIAC RUKKAKHA → SYRIAC HBASA-ESASA DOTTED\t# \n\n0A03 ;\t0983 ;\tMA\t# ( ਃ → ঃ ) GURMUKHI SIGN VISARGA → BENGALI SIGN VISARGA\t# \n0C03 ;\t0983 ;\tMA\t# ( ః → ঃ ) TELUGU SIGN VISARGA → BENGALI SIGN VISARGA\t# →ਃ→\n0C83 ;\t0983 ;\tMA\t# ( ಃ → ঃ ) KANNADA SIGN VISARGA → BENGALI SIGN VISARGA\t# →ః→→ਃ→\n0D03 ;\t0983 ;\tMA\t# ( ഃ → ঃ ) MALAYALAM SIGN VISARGA → BENGALI SIGN VISARGA\t# →ಃ→→ః→→ਃ→\n0D83 ;\t0983 ;\tMA\t# ( ඃ → ঃ ) SINHALA SIGN VISARGAYA → BENGALI SIGN VISARGA\t# →ഃ→→ಃ→→ః→→ਃ→\n1038 ;\t0983 ;\tMA\t# ( း → ঃ ) MYANMAR SIGN VISARGA → BENGALI SIGN VISARGA\t# →ඃ→→ഃ→→ಃ→→ః→→ਃ→\n114C1 ;\t0983 ;\tMA\t# ( 𑓁 → ঃ ) TIRHUTA SIGN VISARGA → BENGALI SIGN VISARGA\t# \n\n17CB ;\t0E48 ;\tMA\t# ( ់ → ่ ) KHMER SIGN BANTOC → THAI CHARACTER MAI EK\t# \n0EC8 ;\t0E48 ;\tMA\t# ( ່ → ่ ) LAO TONE MAI EK → THAI CHARACTER MAI EK\t# \n\n0EC9 ;\t0E49 ;\tMA\t# ( ້ → ้ ) LAO TONE MAI THO → THAI CHARACTER MAI THO\t# \n\n0ECA ;\t0E4A ;\tMA\t# ( ໊ → ๊ ) LAO TONE MAI TI → THAI CHARACTER MAI TRI\t# \n\n0ECB ;\t0E4B ;\tMA\t# ( ໋ → ๋ ) LAO TONE MAI CATAWA → THAI CHARACTER MAI CHATTAWA\t# \n\nA66F ;\t20E9 ;\tMA\t# ( ꙯ → ⃩ ) COMBINING CYRILLIC VZMET → COMBINING WIDE BRIDGE ABOVE\t# \n\n2028 ;\t0020 ;\tMA\t#* (  →   ) LINE SEPARATOR → SPACE\t# \n2029 ;\t0020 ;\tMA\t#* (  →   ) PARAGRAPH SEPARATOR → SPACE\t# \n1680 ;\t0020 ;\tMA\t#* (   →   ) OGHAM SPACE MARK → SPACE\t# \n2000 ;\t0020 ;\tMA\t#* (   →   ) EN QUAD → SPACE\t# \n2001 ;\t0020 ;\tMA\t#* (   →   ) EM QUAD → SPACE\t# \n2002 ;\t0020 ;\tMA\t#* (   →   ) EN SPACE → SPACE\t# \n2003 ;\t0020 ;\tMA\t#* (   →   ) EM SPACE → SPACE\t# \n2004 ;\t0020 ;\tMA\t#* (   →   ) THREE-PER-EM SPACE → SPACE\t# \n2005 ;\t0020 ;\tMA\t#* (   →   ) FOUR-PER-EM SPACE → SPACE\t# \n2006 ;\t0020 ;\tMA\t#* (   →   ) SIX-PER-EM SPACE → SPACE\t# \n2008 ;\t0020 ;\tMA\t#* (   →   ) PUNCTUATION SPACE → SPACE\t# \n2009 ;\t0020 ;\tMA\t#* (   →   ) THIN SPACE → SPACE\t# \n200A ;\t0020 ;\tMA\t#* (   →   ) HAIR SPACE → SPACE\t# \n205F ;\t0020 ;\tMA\t#* (   →   ) MEDIUM MATHEMATICAL SPACE → SPACE\t# \n00A0 ;\t0020 ;\tMA\t#* (   →   ) NO-BREAK SPACE → SPACE\t# \n2007 ;\t0020 ;\tMA\t#* (   →   ) FIGURE SPACE → SPACE\t# \n202F ;\t0020 ;\tMA\t#* (   →   ) NARROW NO-BREAK SPACE → SPACE\t# \n\n07FA ;\t005F ;\tMA\t# ( ‎ߺ‎ → _ ) NKO LAJANYALAN → LOW LINE\t# \nFE4D ;\t005F ;\tMA\t# ( ﹍ → _ ) DASHED LOW LINE → LOW LINE\t# \nFE4E ;\t005F ;\tMA\t# ( ﹎ → _ ) CENTRELINE LOW LINE → LOW LINE\t# \nFE4F ;\t005F ;\tMA\t# ( ﹏ → _ ) WAVY LOW LINE → LOW LINE\t# \n\n2010 ;\t002D ;\tMA\t#* ( ‐ → - ) HYPHEN → HYPHEN-MINUS\t# \n2011 ;\t002D ;\tMA\t#* ( ‑ → - ) NON-BREAKING HYPHEN → HYPHEN-MINUS\t# \n2012 ;\t002D ;\tMA\t#* ( ‒ → - ) FIGURE DASH → HYPHEN-MINUS\t# \n2013 ;\t002D ;\tMA\t#* ( – → - ) EN DASH → HYPHEN-MINUS\t# \nFE58 ;\t002D ;\tMA\t#* ( ﹘ → - ) SMALL EM DASH → HYPHEN-MINUS\t# \n06D4 ;\t002D ;\tMA\t#* ( ‎۔‎ → - ) ARABIC FULL STOP → HYPHEN-MINUS\t# →‐→\n2043 ;\t002D ;\tMA\t#* ( ⁃ → - ) HYPHEN BULLET → HYPHEN-MINUS\t# →‐→\n02D7 ;\t002D ;\tMA\t#* ( ˗ → - ) MODIFIER LETTER MINUS SIGN → HYPHEN-MINUS\t# \n2212 ;\t002D ;\tMA\t#* ( − → - ) MINUS SIGN → HYPHEN-MINUS\t# \n2796 ;\t002D ;\tMA\t#* ( ➖ → - ) HEAVY MINUS SIGN → HYPHEN-MINUS\t# →−→\n2CBB ;\t002D ;\tMA\t# ( ⲻ → - ) COPTIC SMALL LETTER DIALECT-P NI → HYPHEN-MINUS\t# →−→\n2CBA ;\t002D ;\tMA\t# ( Ⲻ → - ) COPTIC CAPITAL LETTER DIALECT-P NI → HYPHEN-MINUS\t# →‒→\n\n2A29 ;\t002D 0313 ;\tMA\t#* ( ⨩ → -̓ ) MINUS SIGN WITH COMMA ABOVE → HYPHEN-MINUS, COMBINING COMMA ABOVE\t# →−̓→\n\n2E1A ;\t002D 0308 ;\tMA\t#* ( ⸚ → -̈ ) HYPHEN WITH DIAERESIS → HYPHEN-MINUS, COMBINING DIAERESIS\t# \n\nFB29 ;\t002D 0307 ;\tMA\t#* ( ﬩ → -̇ ) HEBREW LETTER ALTERNATIVE PLUS SIGN → HYPHEN-MINUS, COMBINING DOT ABOVE\t# →∸→→−̇→\n2238 ;\t002D 0307 ;\tMA\t#* ( ∸ → -̇ ) DOT MINUS → HYPHEN-MINUS, COMBINING DOT ABOVE\t# →−̇→\n2CB3 ;\t002D 0307 ;\tMA\t# ( ⲳ → -̇ ) COPTIC SMALL LETTER DIALECT-P ALEF → HYPHEN-MINUS, COMBINING DOT ABOVE\t# →﬩→→∸→→−̇→\n2CB2 ;\t002D 0307 ;\tMA\t# ( Ⲳ → -̇ ) COPTIC CAPITAL LETTER DIALECT-P ALEF → HYPHEN-MINUS, COMBINING DOT ABOVE\t# →﬩→→∸→→−̇→\n\n2A2A ;\t002D 0323 ;\tMA\t#* ( ⨪ → -̣ ) MINUS SIGN WITH DOT BELOW → HYPHEN-MINUS, COMBINING DOT BELOW\t# →−̣→\n\nA4FE ;\t002D 002E ;\tMA\t#* ( ꓾ → -. ) LISU PUNCTUATION COMMA → HYPHEN-MINUS, FULL STOP\t# \n\nFF5E ;\t301C ;\tMA\t#* ( ～ → 〜 ) FULLWIDTH TILDE → WAVE DASH\t# \n\n060D ;\t002C ;\tMA\t#* ( ‎؍‎ → , ) ARABIC DATE SEPARATOR → COMMA\t# →‎٫‎→\n066B ;\t002C ;\tMA\t#* ( ‎٫‎ → , ) ARABIC DECIMAL SEPARATOR → COMMA\t# \n201A ;\t002C ;\tMA\t#* ( ‚ → , ) SINGLE LOW-9 QUOTATION MARK → COMMA\t# \n00B8 ;\t002C ;\tMA\t#* ( ¸ → , ) CEDILLA → COMMA\t# \nA4F9 ;\t002C ;\tMA\t# ( ꓹ → , ) LISU LETTER TONE NA PO → COMMA\t# \n\n2E32 ;\t060C ;\tMA\t#* ( ⸲ → ، ) TURNED COMMA → ARABIC COMMA\t# \n066C ;\t060C ;\tMA\t#* ( ‎٬‎ → ، ) ARABIC THOUSANDS SEPARATOR → ARABIC COMMA\t# \n\n037E ;\t003B ;\tMA\t#* ( ; → ; ) GREEK QUESTION MARK → SEMICOLON\t# \n\n2E35 ;\t061B ;\tMA\t#* ( ⸵ → ‎؛‎ ) TURNED SEMICOLON → ARABIC SEMICOLON\t# \n\n0903 ;\t003A ;\tMA\t# ( ः → : ) DEVANAGARI SIGN VISARGA → COLON\t# \n0A83 ;\t003A ;\tMA\t# ( ઃ → : ) GUJARATI SIGN VISARGA → COLON\t# \nFF1A ;\t003A ;\tMA\t#* ( ： → : ) FULLWIDTH COLON → COLON\t# →︰→\n0589 ;\t003A ;\tMA\t#* ( ։ → : ) ARMENIAN FULL STOP → COLON\t# \n0703 ;\t003A ;\tMA\t#* ( ‎܃‎ → : ) SYRIAC SUPRALINEAR COLON → COLON\t# \n0704 ;\t003A ;\tMA\t#* ( ‎܄‎ → : ) SYRIAC SUBLINEAR COLON → COLON\t# \n16EC ;\t003A ;\tMA\t#* ( ᛬ → : ) RUNIC MULTIPLE PUNCTUATION → COLON\t# \nFE30 ;\t003A ;\tMA\t#* ( ︰ → : ) PRESENTATION FORM FOR VERTICAL TWO DOT LEADER → COLON\t# \n1803 ;\t003A ;\tMA\t#* ( ᠃ → : ) MONGOLIAN FULL STOP → COLON\t# \n1809 ;\t003A ;\tMA\t#* ( ᠉ → : ) MONGOLIAN MANCHU FULL STOP → COLON\t# \n205A ;\t003A ;\tMA\t#* ( ⁚ → : ) TWO DOT PUNCTUATION → COLON\t# \n05C3 ;\t003A ;\tMA\t#* ( ‎׃‎ → : ) HEBREW PUNCTUATION SOF PASUQ → COLON\t# \n02F8 ;\t003A ;\tMA\t#* ( ˸ → : ) MODIFIER LETTER RAISED COLON → COLON\t# \nA789 ;\t003A ;\tMA\t#* ( ꞉ → : ) MODIFIER LETTER COLON → COLON\t# \n2236 ;\t003A ;\tMA\t#* ( ∶ → : ) RATIO → COLON\t# \n02D0 ;\t003A ;\tMA\t# ( ː → : ) MODIFIER LETTER TRIANGULAR COLON → COLON\t# \nA4FD ;\t003A ;\tMA\t# ( ꓽ → : ) LISU LETTER TONE MYA JEU → COLON\t# \n11DD9 ;\t003A ;\tMA\t# ( 𑷙 → : ) TOLONG SIKI SIGN SELA → COLON\t# \n\n2A74 ;\t003A 003A 003D ;\tMA\t#* ( ⩴ → ::= ) DOUBLE COLON EQUAL → COLON, COLON, EQUALS SIGN\t# \n\n29F4 ;\t003A 2192 ;\tMA\t#* ( ⧴ → :→ ) RULE-DELAYED → COLON, RIGHTWARDS ARROW\t# \n\nFF01 ;\t0021 ;\tMA\t#* ( ！ → ! ) FULLWIDTH EXCLAMATION MARK → EXCLAMATION MARK\t# →ǃ→\n01C3 ;\t0021 ;\tMA\t# ( ǃ → ! ) LATIN LETTER RETROFLEX CLICK → EXCLAMATION MARK\t# \n2D51 ;\t0021 ;\tMA\t# ( ⵑ → ! ) TIFINAGH LETTER TUAREG YANG → EXCLAMATION MARK\t# \n\n203C ;\t0021 0021 ;\tMA\t#* ( ‼ → !! ) DOUBLE EXCLAMATION MARK → EXCLAMATION MARK, EXCLAMATION MARK\t# \n\n2049 ;\t0021 003F ;\tMA\t#* ( ⁉ → !? ) EXCLAMATION QUESTION MARK → EXCLAMATION MARK, QUESTION MARK\t# \n\n0294 ;\t003F ;\tMA\t# ( ʔ → ? ) LATIN LETTER GLOTTAL STOP → QUESTION MARK\t# \n0241 ;\t003F ;\tMA\t# ( Ɂ → ? ) LATIN CAPITAL LETTER GLOTTAL STOP → QUESTION MARK\t# →ʔ→\n097D ;\t003F ;\tMA\t# ( ॽ → ? ) DEVANAGARI LETTER GLOTTAL STOP → QUESTION MARK\t# \n13AE ;\t003F ;\tMA\t# ( Ꭾ → ? ) CHEROKEE LETTER HE → QUESTION MARK\t# →Ɂ→→ʔ→\nA6EB ;\t003F ;\tMA\t# ( ꛫ → ? ) BAMUM LETTER NTUU → QUESTION MARK\t# →ʔ→\n\n2048 ;\t003F 0021 ;\tMA\t#* ( ⁈ → ?! ) QUESTION EXCLAMATION MARK → QUESTION MARK, EXCLAMATION MARK\t# \n\n2047 ;\t003F 003F ;\tMA\t#* ( ⁇ → ?? ) DOUBLE QUESTION MARK → QUESTION MARK, QUESTION MARK\t# \n\n2E2E ;\t061F ;\tMA\t#* ( ⸮ → ‎؟‎ ) REVERSED QUESTION MARK → ARABIC QUESTION MARK\t# \n\n1D16D ;\t002E ;\tMA\t# ( 𝅭 → . ) MUSICAL SYMBOL COMBINING AUGMENTATION DOT → FULL STOP\t# \n2024 ;\t002E ;\tMA\t#* ( ․ → . ) ONE DOT LEADER → FULL STOP\t# \n0701 ;\t002E ;\tMA\t#* ( ‎܁‎ → . ) SYRIAC SUPRALINEAR FULL STOP → FULL STOP\t# \n0702 ;\t002E ;\tMA\t#* ( ‎܂‎ → . ) SYRIAC SUBLINEAR FULL STOP → FULL STOP\t# \nA60E ;\t002E ;\tMA\t#* ( ꘎ → . ) VAI FULL STOP → FULL STOP\t# \n10A50 ;\t002E ;\tMA\t#* ( ‎𐩐‎ → . ) KHAROSHTHI PUNCTUATION DOT → FULL STOP\t# \n0660 ;\t002E ;\tMA\t# ( ‎٠‎ → . ) ARABIC-INDIC DIGIT ZERO → FULL STOP\t# \n06F0 ;\t002E ;\tMA\t# ( ۰ → . ) EXTENDED ARABIC-INDIC DIGIT ZERO → FULL STOP\t# →‎٠‎→\nA4F8 ;\t002E ;\tMA\t# ( ꓸ → . ) LISU LETTER TONE MYA TI → FULL STOP\t# \n\nA4FB ;\t002E 002C ;\tMA\t# ( ꓻ → ., ) LISU LETTER TONE MYA BO → FULL STOP, COMMA\t# \n\n2025 ;\t002E 002E ;\tMA\t#* ( ‥ → .. ) TWO DOT LEADER → FULL STOP, FULL STOP\t# \nA4FA ;\t002E 002E ;\tMA\t# ( ꓺ → .. ) LISU LETTER TONE MYA CYA → FULL STOP, FULL STOP\t# \n\n2026 ;\t002E 002E 002E ;\tMA\t#* ( … → ... ) HORIZONTAL ELLIPSIS → FULL STOP, FULL STOP, FULL STOP\t# \n\nA6F4 ;\tA6F3 A6F3 ;\tMA\t#* ( ꛴ → ꛳꛳ ) BAMUM COLON → BAMUM FULL STOP, BAMUM FULL STOP\t# \n\n30FB ;\t00B7 ;\tMA\t# ( ・ → · ) KATAKANA MIDDLE DOT → MIDDLE DOT\t# →•→\nFF65 ;\t00B7 ;\tMA\t# ( ･ → · ) HALFWIDTH KATAKANA MIDDLE DOT → MIDDLE DOT\t# →•→\n16EB ;\t00B7 ;\tMA\t#* ( ᛫ → · ) RUNIC SINGLE PUNCTUATION → MIDDLE DOT\t# \n0387 ;\t00B7 ;\tMA\t# ( · → · ) GREEK ANO TELEIA → MIDDLE DOT\t# \n2E31 ;\t00B7 ;\tMA\t#* ( ⸱ → · ) WORD SEPARATOR MIDDLE DOT → MIDDLE DOT\t# \n10101 ;\t00B7 ;\tMA\t#* ( 𐄁 → · ) AEGEAN WORD SEPARATOR DOT → MIDDLE DOT\t# \n2022 ;\t00B7 ;\tMA\t#* ( • → · ) BULLET → MIDDLE DOT\t# \n2027 ;\t00B7 ;\tMA\t#* ( ‧ → · ) HYPHENATION POINT → MIDDLE DOT\t# \n2219 ;\t00B7 ;\tMA\t#* ( ∙ → · ) BULLET OPERATOR → MIDDLE DOT\t# \n22C5 ;\t00B7 ;\tMA\t#* ( ⋅ → · ) DOT OPERATOR → MIDDLE DOT\t# \nA78F ;\t00B7 ;\tMA\t# ( ꞏ → · ) LATIN LETTER SINOLOGICAL DOT → MIDDLE DOT\t# \n1427 ;\t00B7 ;\tMA\t# ( ᐧ → · ) CANADIAN SYLLABICS FINAL MIDDLE DOT → MIDDLE DOT\t# \n\n22EF ;\t00B7 00B7 00B7 ;\tMA\t#* ( ⋯ → ··· ) MIDLINE HORIZONTAL ELLIPSIS → MIDDLE DOT, MIDDLE DOT, MIDDLE DOT\t# \n2D48 ;\t00B7 00B7 00B7 ;\tMA\t# ( ⵈ → ··· ) TIFINAGH LETTER TUAREG YAQ → MIDDLE DOT, MIDDLE DOT, MIDDLE DOT\t# →⋯→\n\n1444 ;\t00B7 003C ;\tMA\t# ( ᑄ → ·< ) CANADIAN SYLLABICS PWA → MIDDLE DOT, LESS-THAN SIGN\t# →ᐧᐸ→\n\n22D7 ;\t00B7 003E ;\tMA\t#* ( ⋗ → ·> ) GREATER-THAN WITH DOT → MIDDLE DOT, GREATER-THAN SIGN\t# →ᑀ→→ᐧᐳ→\n1437 ;\t00B7 003E ;\tMA\t# ( ᐷ → ·> ) CANADIAN SYLLABICS CARRIER HI → MIDDLE DOT, GREATER-THAN SIGN\t# →ᑀ→→ᐧᐳ→\n1440 ;\t00B7 003E ;\tMA\t# ( ᑀ → ·> ) CANADIAN SYLLABICS PWO → MIDDLE DOT, GREATER-THAN SIGN\t# →ᐧᐳ→\n\n152F ;\t00B7 0034 ;\tMA\t# ( ᔯ → ·4 ) CANADIAN SYLLABICS YWE → MIDDLE DOT, DIGIT FOUR\t# →ᐧ4→\n\n147E ;\t00B7 0062 ;\tMA\t# ( ᑾ → ·b ) CANADIAN SYLLABICS KWA → MIDDLE DOT, LATIN SMALL LETTER B\t# →ᐧᑲ→\n\n1480 ;\t00B7 0062 0307 ;\tMA\t# ( ᒀ → ·ḃ ) CANADIAN SYLLABICS KWAA → MIDDLE DOT, LATIN SMALL LETTER B, COMBINING DOT ABOVE\t# →ᐧᑳ→\n\n147A ;\t00B7 0064 ;\tMA\t# ( ᑺ → ·d ) CANADIAN SYLLABICS KWO → MIDDLE DOT, LATIN SMALL LETTER D\t# →ᐧᑯ→\n\n1498 ;\t00B7 004A ;\tMA\t# ( ᒘ → ·J ) CANADIAN SYLLABICS CWO → MIDDLE DOT, LATIN CAPITAL LETTER J\t# →ᐧᒍ→\n\n14B6 ;\t00B7 004C ;\tMA\t# ( ᒶ → ·L ) CANADIAN SYLLABICS MWA → MIDDLE DOT, LATIN CAPITAL LETTER L\t# →ᐧL→\n\n1476 ;\t00B7 0050 ;\tMA\t# ( ᑶ → ·P ) CANADIAN SYLLABICS KWI → MIDDLE DOT, LATIN CAPITAL LETTER P\t# →ᐧᑭ→\n\n1457 ;\t00B7 0055 ;\tMA\t# ( ᑗ → ·U ) CANADIAN SYLLABICS TWE → MIDDLE DOT, LATIN CAPITAL LETTER U\t# →ᐧᑌ→→·ᑌ→\n\n143A ;\t00B7 0056 ;\tMA\t# ( ᐺ → ·V ) CANADIAN SYLLABICS PWE → MIDDLE DOT, LATIN CAPITAL LETTER V\t# →ᐧᐯ→\n\n143C ;\t00B7 0245 ;\tMA\t# ( ᐼ → ·Ʌ ) CANADIAN SYLLABICS PWI → MIDDLE DOT, LATIN CAPITAL LETTER TURNED V\t# →ᐧᐱ→→·ᐱ→\n\n14AE ;\t00B7 0393 ;\tMA\t# ( ᒮ → ·Γ ) CANADIAN SYLLABICS MWI → MIDDLE DOT, GREEK CAPITAL LETTER GAMMA\t# →ᐧᒥ→→·ᒥ→\n\n140E ;\t00B7 0394 ;\tMA\t# ( ᐎ → ·Δ ) CANADIAN SYLLABICS WI → MIDDLE DOT, GREEK CAPITAL LETTER DELTA\t# →ᐧᐃ→\n\n1459 ;\t00B7 0548 ;\tMA\t# ( ᑙ → ·Ո ) CANADIAN SYLLABICS TWI → MIDDLE DOT, ARMENIAN CAPITAL LETTER VO\t# →ᐧᑎ→→·ᑎ→\n\n140C ;\t00B7 1401 ;\tMA\t# ( ᐌ → ·ᐁ ) CANADIAN SYLLABICS WE → MIDDLE DOT, CANADIAN SYLLABICS E\t# →ᐧᐁ→\n\n1410 ;\t00B7 1404 ;\tMA\t# ( ᐐ → ·ᐄ ) CANADIAN SYLLABICS WII → MIDDLE DOT, CANADIAN SYLLABICS II\t# →ᐧᐄ→\n\n1412 ;\t00B7 1405 ;\tMA\t# ( ᐒ → ·ᐅ ) CANADIAN SYLLABICS WO → MIDDLE DOT, CANADIAN SYLLABICS O\t# →ᐧᐅ→\n\n1414 ;\t00B7 1406 ;\tMA\t# ( ᐔ → ·ᐆ ) CANADIAN SYLLABICS WOO → MIDDLE DOT, CANADIAN SYLLABICS OO\t# →ᐧᐆ→\n\n1417 ;\t00B7 140A ;\tMA\t# ( ᐗ → ·ᐊ ) CANADIAN SYLLABICS WA → MIDDLE DOT, CANADIAN SYLLABICS A\t# →ᐧᐊ→\n\n1419 ;\t00B7 140B ;\tMA\t# ( ᐙ → ·ᐋ ) CANADIAN SYLLABICS WAA → MIDDLE DOT, CANADIAN SYLLABICS AA\t# →ᐧᐋ→\n\n143E ;\t00B7 1432 ;\tMA\t# ( ᐾ → ·ᐲ ) CANADIAN SYLLABICS PWII → MIDDLE DOT, CANADIAN SYLLABICS PII\t# →ᐧᐲ→\n\n1442 ;\t00B7 1434 ;\tMA\t# ( ᑂ → ·ᐴ ) CANADIAN SYLLABICS PWOO → MIDDLE DOT, CANADIAN SYLLABICS POO\t# →ᐧᐴ→\n\n1446 ;\t00B7 1439 ;\tMA\t# ( ᑆ → ·ᐹ ) CANADIAN SYLLABICS PWAA → MIDDLE DOT, CANADIAN SYLLABICS PAA\t# →ᐧᐹ→\n\n145B ;\t00B7 144F ;\tMA\t# ( ᑛ → ·ᑏ ) CANADIAN SYLLABICS TWII → MIDDLE DOT, CANADIAN SYLLABICS TII\t# →ᐧᑏ→\n\n1454 ;\t00B7 1450 ;\tMA\t# ( ᑔ → ·ᑐ ) CANADIAN SYLLABICS CARRIER DI → MIDDLE DOT, CANADIAN SYLLABICS TO\t# →ᑝ→→ᐧᑐ→\n145D ;\t00B7 1450 ;\tMA\t# ( ᑝ → ·ᑐ ) CANADIAN SYLLABICS TWO → MIDDLE DOT, CANADIAN SYLLABICS TO\t# →ᐧᑐ→\n\n145F ;\t00B7 1451 ;\tMA\t# ( ᑟ → ·ᑑ ) CANADIAN SYLLABICS TWOO → MIDDLE DOT, CANADIAN SYLLABICS TOO\t# →ᐧᑑ→\n\n1461 ;\t00B7 1455 ;\tMA\t# ( ᑡ → ·ᑕ ) CANADIAN SYLLABICS TWA → MIDDLE DOT, CANADIAN SYLLABICS TA\t# →ᐧᑕ→\n\n1463 ;\t00B7 1456 ;\tMA\t# ( ᑣ → ·ᑖ ) CANADIAN SYLLABICS TWAA → MIDDLE DOT, CANADIAN SYLLABICS TAA\t# →ᐧᑖ→\n\n1474 ;\t00B7 146B ;\tMA\t# ( ᑴ → ·ᑫ ) CANADIAN SYLLABICS KWE → MIDDLE DOT, CANADIAN SYLLABICS KE\t# →ᐧᑫ→\n\n1478 ;\t00B7 146E ;\tMA\t# ( ᑸ → ·ᑮ ) CANADIAN SYLLABICS KWII → MIDDLE DOT, CANADIAN SYLLABICS KII\t# →ᐧᑮ→\n\n147C ;\t00B7 1470 ;\tMA\t# ( ᑼ → ·ᑰ ) CANADIAN SYLLABICS KWOO → MIDDLE DOT, CANADIAN SYLLABICS KOO\t# →ᐧᑰ→\n\n1492 ;\t00B7 1489 ;\tMA\t# ( ᒒ → ·ᒉ ) CANADIAN SYLLABICS CWE → MIDDLE DOT, CANADIAN SYLLABICS CE\t# →ᐧᒉ→\n\n1494 ;\t00B7 148B ;\tMA\t# ( ᒔ → ·ᒋ ) CANADIAN SYLLABICS CWI → MIDDLE DOT, CANADIAN SYLLABICS CI\t# →ᐧᒋ→\n\n1496 ;\t00B7 148C ;\tMA\t# ( ᒖ → ·ᒌ ) CANADIAN SYLLABICS CWII → MIDDLE DOT, CANADIAN SYLLABICS CII\t# →ᐧᒌ→\n\n149A ;\t00B7 148E ;\tMA\t# ( ᒚ → ·ᒎ ) CANADIAN SYLLABICS CWOO → MIDDLE DOT, CANADIAN SYLLABICS COO\t# →ᐧᒎ→\n\n149C ;\t00B7 1490 ;\tMA\t# ( ᒜ → ·ᒐ ) CANADIAN SYLLABICS CWA → MIDDLE DOT, CANADIAN SYLLABICS CA\t# →ᐧᒐ→\n\n149E ;\t00B7 1491 ;\tMA\t# ( ᒞ → ·ᒑ ) CANADIAN SYLLABICS CWAA → MIDDLE DOT, CANADIAN SYLLABICS CAA\t# →ᐧᒑ→\n\n14AC ;\t00B7 14A3 ;\tMA\t# ( ᒬ → ·ᒣ ) CANADIAN SYLLABICS MWE → MIDDLE DOT, CANADIAN SYLLABICS ME\t# →ᐧᒣ→\n\n14B0 ;\t00B7 14A6 ;\tMA\t# ( ᒰ → ·ᒦ ) CANADIAN SYLLABICS MWII → MIDDLE DOT, CANADIAN SYLLABICS MII\t# →ᐧᒦ→\n\n14B2 ;\t00B7 14A7 ;\tMA\t# ( ᒲ → ·ᒧ ) CANADIAN SYLLABICS MWO → MIDDLE DOT, CANADIAN SYLLABICS MO\t# →ᐧᒧ→\n\n14B4 ;\t00B7 14A8 ;\tMA\t# ( ᒴ → ·ᒨ ) CANADIAN SYLLABICS MWOO → MIDDLE DOT, CANADIAN SYLLABICS MOO\t# →ᐧᒨ→\n\n14B8 ;\t00B7 14AB ;\tMA\t# ( ᒸ → ·ᒫ ) CANADIAN SYLLABICS MWAA → MIDDLE DOT, CANADIAN SYLLABICS MAA\t# →ᐧᒫ→\n\n14C9 ;\t00B7 14C0 ;\tMA\t# ( ᓉ → ·ᓀ ) CANADIAN SYLLABICS NWE → MIDDLE DOT, CANADIAN SYLLABICS NE\t# →ᐧᓀ→\n\n18C6 ;\t00B7 14C2 ;\tMA\t# ( ᣆ → ·ᓂ ) CANADIAN SYLLABICS NWI → MIDDLE DOT, CANADIAN SYLLABICS NI\t# →ᐧᓂ→\n\n18C8 ;\t00B7 14C3 ;\tMA\t# ( ᣈ → ·ᓃ ) CANADIAN SYLLABICS NWII → MIDDLE DOT, CANADIAN SYLLABICS NII\t# →ᐧᓃ→\n\n18CA ;\t00B7 14C4 ;\tMA\t# ( ᣊ → ·ᓄ ) CANADIAN SYLLABICS NWO → MIDDLE DOT, CANADIAN SYLLABICS NO\t# →ᐧᓄ→\n\n18CC ;\t00B7 14C5 ;\tMA\t# ( ᣌ → ·ᓅ ) CANADIAN SYLLABICS NWOO → MIDDLE DOT, CANADIAN SYLLABICS NOO\t# →ᐧᓅ→\n\n14CB ;\t00B7 14C7 ;\tMA\t# ( ᓋ → ·ᓇ ) CANADIAN SYLLABICS NWA → MIDDLE DOT, CANADIAN SYLLABICS NA\t# →ᐧᓇ→\n\n14CD ;\t00B7 14C8 ;\tMA\t# ( ᓍ → ·ᓈ ) CANADIAN SYLLABICS NWAA → MIDDLE DOT, CANADIAN SYLLABICS NAA\t# →ᐧᓈ→\n\n14DC ;\t00B7 14D3 ;\tMA\t# ( ᓜ → ·ᓓ ) CANADIAN SYLLABICS LWE → MIDDLE DOT, CANADIAN SYLLABICS LE\t# →ᐧᓓ→\n\n14DE ;\t00B7 14D5 ;\tMA\t# ( ᓞ → ·ᓕ ) CANADIAN SYLLABICS LWI → MIDDLE DOT, CANADIAN SYLLABICS LI\t# →ᐧᓕ→\n\n14E0 ;\t00B7 14D6 ;\tMA\t# ( ᓠ → ·ᓖ ) CANADIAN SYLLABICS LWII → MIDDLE DOT, CANADIAN SYLLABICS LII\t# →ᐧᓖ→\n\n14E2 ;\t00B7 14D7 ;\tMA\t# ( ᓢ → ·ᓗ ) CANADIAN SYLLABICS LWO → MIDDLE DOT, CANADIAN SYLLABICS LO\t# →ᐧᓗ→\n\n14E4 ;\t00B7 14D8 ;\tMA\t# ( ᓤ → ·ᓘ ) CANADIAN SYLLABICS LWOO → MIDDLE DOT, CANADIAN SYLLABICS LOO\t# →ᐧᓘ→\n\n14E6 ;\t00B7 14DA ;\tMA\t# ( ᓦ → ·ᓚ ) CANADIAN SYLLABICS LWA → MIDDLE DOT, CANADIAN SYLLABICS LA\t# →ᐧᓚ→\n\n14E8 ;\t00B7 14DB ;\tMA\t# ( ᓨ → ·ᓛ ) CANADIAN SYLLABICS LWAA → MIDDLE DOT, CANADIAN SYLLABICS LAA\t# →ᐧᓛ→\n\n14F6 ;\t00B7 14ED ;\tMA\t# ( ᓶ → ·ᓭ ) CANADIAN SYLLABICS SWE → MIDDLE DOT, CANADIAN SYLLABICS SE\t# →ᐧᓭ→\n\n14F8 ;\t00B7 14EF ;\tMA\t# ( ᓸ → ·ᓯ ) CANADIAN SYLLABICS SWI → MIDDLE DOT, CANADIAN SYLLABICS SI\t# →ᐧᓯ→\n\n14FA ;\t00B7 14F0 ;\tMA\t# ( ᓺ → ·ᓰ ) CANADIAN SYLLABICS SWII → MIDDLE DOT, CANADIAN SYLLABICS SII\t# →ᐧᓰ→\n\n14FC ;\t00B7 14F1 ;\tMA\t# ( ᓼ → ·ᓱ ) CANADIAN SYLLABICS SWO → MIDDLE DOT, CANADIAN SYLLABICS SO\t# →ᐧᓱ→\n\n14FE ;\t00B7 14F2 ;\tMA\t# ( ᓾ → ·ᓲ ) CANADIAN SYLLABICS SWOO → MIDDLE DOT, CANADIAN SYLLABICS SOO\t# →ᐧᓲ→\n\n1500 ;\t00B7 14F4 ;\tMA\t# ( ᔀ → ·ᓴ ) CANADIAN SYLLABICS SWA → MIDDLE DOT, CANADIAN SYLLABICS SA\t# →ᐧᓴ→\n\n1502 ;\t00B7 14F5 ;\tMA\t# ( ᔂ → ·ᓵ ) CANADIAN SYLLABICS SWAA → MIDDLE DOT, CANADIAN SYLLABICS SAA\t# →ᐧᓵ→\n\n1517 ;\t00B7 1510 ;\tMA\t# ( ᔗ → ·ᔐ ) CANADIAN SYLLABICS SHWE → MIDDLE DOT, CANADIAN SYLLABICS SHE\t# →ᐧᔐ→\n\n1519 ;\t00B7 1511 ;\tMA\t# ( ᔙ → ·ᔑ ) CANADIAN SYLLABICS SHWI → MIDDLE DOT, CANADIAN SYLLABICS SHI\t# →ᐧᔑ→\n\n151B ;\t00B7 1512 ;\tMA\t# ( ᔛ → ·ᔒ ) CANADIAN SYLLABICS SHWII → MIDDLE DOT, CANADIAN SYLLABICS SHII\t# →ᐧᔒ→\n\n151D ;\t00B7 1513 ;\tMA\t# ( ᔝ → ·ᔓ ) CANADIAN SYLLABICS SHWO → MIDDLE DOT, CANADIAN SYLLABICS SHO\t# →ᐧᔓ→\n\n151F ;\t00B7 1514 ;\tMA\t# ( ᔟ → ·ᔔ ) CANADIAN SYLLABICS SHWOO → MIDDLE DOT, CANADIAN SYLLABICS SHOO\t# →ᐧᔔ→\n\n1521 ;\t00B7 1515 ;\tMA\t# ( ᔡ → ·ᔕ ) CANADIAN SYLLABICS SHWA → MIDDLE DOT, CANADIAN SYLLABICS SHA\t# →ᐧᔕ→\n\n1523 ;\t00B7 1516 ;\tMA\t# ( ᔣ → ·ᔖ ) CANADIAN SYLLABICS SHWAA → MIDDLE DOT, CANADIAN SYLLABICS SHAA\t# →ᐧᔖ→\n\n1531 ;\t00B7 1528 ;\tMA\t# ( ᔱ → ·ᔨ ) CANADIAN SYLLABICS YWI → MIDDLE DOT, CANADIAN SYLLABICS YI\t# →ᐧᔨ→\n\n1533 ;\t00B7 1529 ;\tMA\t# ( ᔳ → ·ᔩ ) CANADIAN SYLLABICS YWII → MIDDLE DOT, CANADIAN SYLLABICS YII\t# →ᐧᔩ→\n\n1535 ;\t00B7 152A ;\tMA\t# ( ᔵ → ·ᔪ ) CANADIAN SYLLABICS YWO → MIDDLE DOT, CANADIAN SYLLABICS YO\t# →ᐧᔪ→\n\n1537 ;\t00B7 152B ;\tMA\t# ( ᔷ → ·ᔫ ) CANADIAN SYLLABICS YWOO → MIDDLE DOT, CANADIAN SYLLABICS YOO\t# →ᐧᔫ→\n\n1539 ;\t00B7 152D ;\tMA\t# ( ᔹ → ·ᔭ ) CANADIAN SYLLABICS YWA → MIDDLE DOT, CANADIAN SYLLABICS YA\t# →ᐧᔭ→\n\n153B ;\t00B7 152E ;\tMA\t# ( ᔻ → ·ᔮ ) CANADIAN SYLLABICS YWAA → MIDDLE DOT, CANADIAN SYLLABICS YAA\t# →ᐧᔮ→\n\n18CE ;\t00B7 1543 ;\tMA\t# ( ᣎ → ·ᕃ ) CANADIAN SYLLABICS RWEE → MIDDLE DOT, CANADIAN SYLLABICS R-CREE RE\t# →ᐧᕃ→\n\n18CF ;\t00B7 1546 ;\tMA\t# ( ᣏ → ·ᕆ ) CANADIAN SYLLABICS RWI → MIDDLE DOT, CANADIAN SYLLABICS RI\t# →ᐧᕆ→\n\n18D0 ;\t00B7 1547 ;\tMA\t# ( ᣐ → ·ᕇ ) CANADIAN SYLLABICS RWII → MIDDLE DOT, CANADIAN SYLLABICS RII\t# →ᐧᕇ→\n\n18D1 ;\t00B7 1548 ;\tMA\t# ( ᣑ → ·ᕈ ) CANADIAN SYLLABICS RWO → MIDDLE DOT, CANADIAN SYLLABICS RO\t# →ᐧᕈ→\n\n18D2 ;\t00B7 1549 ;\tMA\t# ( ᣒ → ·ᕉ ) CANADIAN SYLLABICS RWOO → MIDDLE DOT, CANADIAN SYLLABICS ROO\t# →ᐧᕉ→\n\n18D3 ;\t00B7 154B ;\tMA\t# ( ᣓ → ·ᕋ ) CANADIAN SYLLABICS RWA → MIDDLE DOT, CANADIAN SYLLABICS RA\t# →ᐧᕋ→\n\n154E ;\t00B7 154C ;\tMA\t# ( ᕎ → ·ᕌ ) CANADIAN SYLLABICS RWAA → MIDDLE DOT, CANADIAN SYLLABICS RAA\t# →ᐧᕌ→\n\n155B ;\t00B7 155A ;\tMA\t# ( ᕛ → ·ᕚ ) CANADIAN SYLLABICS FWAA → MIDDLE DOT, CANADIAN SYLLABICS FAA\t# →ᐧᕚ→\n\n1568 ;\t00B7 1567 ;\tMA\t# ( ᕨ → ·ᕧ ) CANADIAN SYLLABICS THWAA → MIDDLE DOT, CANADIAN SYLLABICS THAA\t# →ᐧᕧ→\n\n18B3 ;\t00B7 18B1 ;\tMA\t# ( ᢳ → ·ᢱ ) CANADIAN SYLLABICS WAY → MIDDLE DOT, CANADIAN SYLLABICS AY\t# →ᐧᢱ→\n\n18B6 ;\t00B7 18B4 ;\tMA\t# ( ᢶ → ·ᢴ ) CANADIAN SYLLABICS PWOY → MIDDLE DOT, CANADIAN SYLLABICS POY\t# →ᐧᢴ→\n\n18B9 ;\t00B7 18B8 ;\tMA\t# ( ᢹ → ·ᢸ ) CANADIAN SYLLABICS KWAY → MIDDLE DOT, CANADIAN SYLLABICS KAY\t# →ᐧᢸ→\n\n18C2 ;\t00B7 18C0 ;\tMA\t# ( ᣂ → ·ᣀ ) CANADIAN SYLLABICS SHWOY → MIDDLE DOT, CANADIAN SYLLABICS SHOY\t# →ᐧᣀ→\n\nA830 ;\t0964 ;\tMA\t#* ( ꠰ → । ) NORTH INDIC FRACTION ONE QUARTER → DEVANAGARI DANDA\t# \n\n0965 ;\t0964 0964 ;\tMA\t#* ( ॥ → ।। ) DEVANAGARI DOUBLE DANDA → DEVANAGARI DANDA, DEVANAGARI DANDA\t# \n\n1C3C ;\t1C3B 1C3B ;\tMA\t#* ( ᰼ → ᰻᰻ ) LEPCHA PUNCTUATION NYET THYOOM TA-ROL → LEPCHA PUNCTUATION TA-ROL, LEPCHA PUNCTUATION TA-ROL\t# \n\n104B ;\t104A 104A ;\tMA\t#* ( ။ → ၊၊ ) MYANMAR SIGN SECTION → MYANMAR SIGN LITTLE SECTION, MYANMAR SIGN LITTLE SECTION\t# \n\n1AA9 ;\t1AA8 1AA8 ;\tMA\t#* ( ᪩ → ᪨᪨ ) TAI THAM SIGN KAANKUU → TAI THAM SIGN KAAN, TAI THAM SIGN KAAN\t# \n\n1AAB ;\t1AAA 1AA8 ;\tMA\t#* ( ᪫ → ᪪᪨ ) TAI THAM SIGN SATKAANKUU → TAI THAM SIGN SATKAAN, TAI THAM SIGN KAAN\t# \n\n1B5F ;\t1B5E 1B5E ;\tMA\t#* ( ᭟ → ᭞᭞ ) BALINESE CARIK PAREREN → BALINESE CARIK SIKI, BALINESE CARIK SIKI\t# \n\n10A57 ;\t10A56 10A56 ;\tMA\t#* ( ‎𐩗‎ → ‎𐩖𐩖‎ ) KHAROSHTHI PUNCTUATION DOUBLE DANDA → KHAROSHTHI PUNCTUATION DANDA, KHAROSHTHI PUNCTUATION DANDA\t# \n\n1144C ;\t1144B 1144B ;\tMA\t#* ( 𑑌 → 𑑋𑑋 ) NEWA DOUBLE DANDA → NEWA DANDA, NEWA DANDA\t# \n\n11642 ;\t11641 11641 ;\tMA\t#* ( 𑙂 → 𑙁𑙁 ) MODI DOUBLE DANDA → MODI DANDA, MODI DANDA\t# \n\n11C42 ;\t11C41 11C41 ;\tMA\t#* ( 𑱂 → 𑱁𑱁 ) BHAIKSUKI DOUBLE DANDA → BHAIKSUKI DANDA, BHAIKSUKI DANDA\t# \n\n1C7F ;\t1C7E 1C7E ;\tMA\t#* ( ᱿ → ᱾᱾ ) OL CHIKI PUNCTUATION DOUBLE MUCAAD → OL CHIKI PUNCTUATION MUCAAD, OL CHIKI PUNCTUATION MUCAAD\t# \n\n055D ;\t0027 ;\tMA\t#* ( ՝ → ' ) ARMENIAN COMMA → APOSTROPHE\t# →ˋ→→｀→→‘→\nFF07 ;\t0027 ;\tMA\t#* ( ＇ → ' ) FULLWIDTH APOSTROPHE → APOSTROPHE\t# →’→\n2018 ;\t0027 ;\tMA\t#* ( ‘ → ' ) LEFT SINGLE QUOTATION MARK → APOSTROPHE\t# \n2019 ;\t0027 ;\tMA\t#* ( ’ → ' ) RIGHT SINGLE QUOTATION MARK → APOSTROPHE\t# \n201B ;\t0027 ;\tMA\t#* ( ‛ → ' ) SINGLE HIGH-REVERSED-9 QUOTATION MARK → APOSTROPHE\t# →′→\n05F3 ;\t0027 ;\tMA\t#* ( ‎׳‎ → ' ) HEBREW PUNCTUATION GERESH → APOSTROPHE\t# \n2032 ;\t0027 ;\tMA\t#* ( ′ → ' ) PRIME → APOSTROPHE\t# \n2035 ;\t0027 ;\tMA\t#* ( ‵ → ' ) REVERSED PRIME → APOSTROPHE\t# →ʽ→→‘→\n055A ;\t0027 ;\tMA\t#* ( ՚ → ' ) ARMENIAN APOSTROPHE → APOSTROPHE\t# →’→\n0060 ;\t0027 ;\tMA\t#* ( ` → ' ) GRAVE ACCENT → APOSTROPHE\t# →ˋ→→｀→→‘→\n1FEF ;\t0027 ;\tMA\t#* ( ` → ' ) GREEK VARIA → APOSTROPHE\t# →ˋ→→｀→→‘→\nFF40 ;\t0027 ;\tMA\t#* ( ｀ → ' ) FULLWIDTH GRAVE ACCENT → APOSTROPHE\t# →‘→\n00B4 ;\t0027 ;\tMA\t#* ( ´ → ' ) ACUTE ACCENT → APOSTROPHE\t# →΄→→ʹ→\n0384 ;\t0027 ;\tMA\t#* ( ΄ → ' ) GREEK TONOS → APOSTROPHE\t# →ʹ→\n1FFD ;\t0027 ;\tMA\t#* ( ´ → ' ) GREEK OXIA → APOSTROPHE\t# →´→→΄→→ʹ→\n1FBD ;\t0027 ;\tMA\t#* ( ᾽ → ' ) GREEK KORONIS → APOSTROPHE\t# →’→\n1FBF ;\t0027 ;\tMA\t#* ( ᾿ → ' ) GREEK PSILI → APOSTROPHE\t# →’→\n1FFE ;\t0027 ;\tMA\t#* ( ῾ → ' ) GREEK DASIA → APOSTROPHE\t# →‛→→′→\n02B9 ;\t0027 ;\tMA\t# ( ʹ → ' ) MODIFIER LETTER PRIME → APOSTROPHE\t# \n0374 ;\t0027 ;\tMA\t# ( ʹ → ' ) GREEK NUMERAL SIGN → APOSTROPHE\t# →′→\n02C8 ;\t0027 ;\tMA\t# ( ˈ → ' ) MODIFIER LETTER VERTICAL LINE → APOSTROPHE\t# \n02CA ;\t0027 ;\tMA\t# ( ˊ → ' ) MODIFIER LETTER ACUTE ACCENT → APOSTROPHE\t# →΄→→ʹ→\n02CB ;\t0027 ;\tMA\t# ( ˋ → ' ) MODIFIER LETTER GRAVE ACCENT → APOSTROPHE\t# →｀→→‘→\n02F4 ;\t0027 ;\tMA\t#* ( ˴ → ' ) MODIFIER LETTER MIDDLE GRAVE ACCENT → APOSTROPHE\t# →ˋ→→｀→→‘→\n02BB ;\t0027 ;\tMA\t# ( ʻ → ' ) MODIFIER LETTER TURNED COMMA → APOSTROPHE\t# →‘→\n02BD ;\t0027 ;\tMA\t# ( ʽ → ' ) MODIFIER LETTER REVERSED COMMA → APOSTROPHE\t# →‘→\n02BC ;\t0027 ;\tMA\t# ( ʼ → ' ) MODIFIER LETTER APOSTROPHE → APOSTROPHE\t# →′→\n02BE ;\t0027 ;\tMA\t# ( ʾ → ' ) MODIFIER LETTER RIGHT HALF RING → APOSTROPHE\t# →ʼ→→′→\nA78C ;\t0027 ;\tMA\t# ( ꞌ → ' ) LATIN SMALL LETTER SALTILLO → APOSTROPHE\t# \n05D9 ;\t0027 ;\tMA\t# ( ‎י‎ → ' ) HEBREW LETTER YOD → APOSTROPHE\t# \n07F4 ;\t0027 ;\tMA\t# ( ‎ߴ‎ → ' ) NKO HIGH TONE APOSTROPHE → APOSTROPHE\t# →’→\n07F5 ;\t0027 ;\tMA\t# ( ‎ߵ‎ → ' ) NKO LOW TONE APOSTROPHE → APOSTROPHE\t# →‘→\n144A ;\t0027 ;\tMA\t# ( ᑊ → ' ) CANADIAN SYLLABICS WEST-CREE P → APOSTROPHE\t# →ˈ→\n16CC ;\t0027 ;\tMA\t# ( ᛌ → ' ) RUNIC LETTER SHORT-TWIG-SOL S → APOSTROPHE\t# \n16F51 ;\t0027 ;\tMA\t# ( 𖽑 → ' ) MIAO SIGN ASPIRATION → APOSTROPHE\t# →ʼ→→′→\n16F52 ;\t0027 ;\tMA\t# ( 𖽒 → ' ) MIAO SIGN REFORMED VOICING → APOSTROPHE\t# →ʻ→→‘→\n\n1CD3 ;\t0027 0027 ;\tMA\t#* ( ᳓ → '' ) VEDIC SIGN NIHSHVASA → APOSTROPHE, APOSTROPHE\t# →″→→\"→\n0022 ;\t0027 0027 ;\tMA\t#* ( \" → '' ) QUOTATION MARK → APOSTROPHE, APOSTROPHE\t# \nFF02 ;\t0027 0027 ;\tMA\t#* ( ＂ → '' ) FULLWIDTH QUOTATION MARK → APOSTROPHE, APOSTROPHE\t# →”→→\"→\n201C ;\t0027 0027 ;\tMA\t#* ( “ → '' ) LEFT DOUBLE QUOTATION MARK → APOSTROPHE, APOSTROPHE\t# →\"→\n201D ;\t0027 0027 ;\tMA\t#* ( ” → '' ) RIGHT DOUBLE QUOTATION MARK → APOSTROPHE, APOSTROPHE\t# →\"→\n201F ;\t0027 0027 ;\tMA\t#* ( ‟ → '' ) DOUBLE HIGH-REVERSED-9 QUOTATION MARK → APOSTROPHE, APOSTROPHE\t# →“→→\"→\n05F4 ;\t0027 0027 ;\tMA\t#* ( ‎״‎ → '' ) HEBREW PUNCTUATION GERSHAYIM → APOSTROPHE, APOSTROPHE\t# →\"→\n2033 ;\t0027 0027 ;\tMA\t#* ( ″ → '' ) DOUBLE PRIME → APOSTROPHE, APOSTROPHE\t# →\"→\n2036 ;\t0027 0027 ;\tMA\t#* ( ‶ → '' ) REVERSED DOUBLE PRIME → APOSTROPHE, APOSTROPHE\t# →‵‵→\n3003 ;\t0027 0027 ;\tMA\t#* ( 〃 → '' ) DITTO MARK → APOSTROPHE, APOSTROPHE\t# →″→→\"→\n02DD ;\t0027 0027 ;\tMA\t#* ( ˝ → '' ) DOUBLE ACUTE ACCENT → APOSTROPHE, APOSTROPHE\t# →\"→\n02BA ;\t0027 0027 ;\tMA\t# ( ʺ → '' ) MODIFIER LETTER DOUBLE PRIME → APOSTROPHE, APOSTROPHE\t# →\"→\n02F6 ;\t0027 0027 ;\tMA\t#* ( ˶ → '' ) MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT → APOSTROPHE, APOSTROPHE\t# →˝→→\"→\n02EE ;\t0027 0027 ;\tMA\t# ( ˮ → '' ) MODIFIER LETTER DOUBLE APOSTROPHE → APOSTROPHE, APOSTROPHE\t# →″→→\"→\n05F2 ;\t0027 0027 ;\tMA\t# ( ‎ײ‎ → '' ) HEBREW LIGATURE YIDDISH DOUBLE YOD → APOSTROPHE, APOSTROPHE\t# →‎יי‎→\n\n2034 ;\t0027 0027 0027 ;\tMA\t#* ( ‴ → ''' ) TRIPLE PRIME → APOSTROPHE, APOSTROPHE, APOSTROPHE\t# →′′′→\n2037 ;\t0027 0027 0027 ;\tMA\t#* ( ‷ → ''' ) REVERSED TRIPLE PRIME → APOSTROPHE, APOSTROPHE, APOSTROPHE\t# →‵‵‵→\n\n2057 ;\t0027 0027 0027 0027 ;\tMA\t#* ( ⁗ → '''' ) QUADRUPLE PRIME → APOSTROPHE, APOSTROPHE, APOSTROPHE, APOSTROPHE\t# →′′′′→\n\n0181 ;\t0027 0042 ;\tMA\t# ( Ɓ → 'B ) LATIN CAPITAL LETTER B WITH HOOK → APOSTROPHE, LATIN CAPITAL LETTER B\t# →ʽB→\n\n018A ;\t0027 0044 ;\tMA\t# ( Ɗ → 'D ) LATIN CAPITAL LETTER D WITH HOOK → APOSTROPHE, LATIN CAPITAL LETTER D\t# →ʽD→\n\n0149 ;\t0027 006E ;\tMA\t# ( ŉ → 'n ) LATIN SMALL LETTER N PRECEDED BY APOSTROPHE → APOSTROPHE, LATIN SMALL LETTER N\t# →ʼn→\n\n01A4 ;\t0027 0050 ;\tMA\t# ( Ƥ → 'P ) LATIN CAPITAL LETTER P WITH HOOK → APOSTROPHE, LATIN CAPITAL LETTER P\t# →ʽP→\n\n01AC ;\t0027 0054 ;\tMA\t# ( Ƭ → 'T ) LATIN CAPITAL LETTER T WITH HOOK → APOSTROPHE, LATIN CAPITAL LETTER T\t# →ʽT→\n\n01B3 ;\t0027 0059 ;\tMA\t# ( Ƴ → 'Y ) LATIN CAPITAL LETTER Y WITH HOOK → APOSTROPHE, LATIN CAPITAL LETTER Y\t# →ʽY→\n\nFF3B ;\t0028 ;\tMA\t#* ( ［ → ( ) FULLWIDTH LEFT SQUARE BRACKET → LEFT PARENTHESIS\t# →〔→\n2768 ;\t0028 ;\tMA\t#* ( ❨ → ( ) MEDIUM LEFT PARENTHESIS ORNAMENT → LEFT PARENTHESIS\t# \n2772 ;\t0028 ;\tMA\t#* ( ❲ → ( ) LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT → LEFT PARENTHESIS\t# →〔→\n3014 ;\t0028 ;\tMA\t#* ( 〔 → ( ) LEFT TORTOISE SHELL BRACKET → LEFT PARENTHESIS\t# \nFD3E ;\t0028 ;\tMA\t#* ( ﴾ → ( ) ORNATE LEFT PARENTHESIS → LEFT PARENTHESIS\t# \n\n2E28 ;\t0028 0028 ;\tMA\t#* ( ⸨ → (( ) LEFT DOUBLE PARENTHESIS → LEFT PARENTHESIS, LEFT PARENTHESIS\t# \n\n3220 ;\t0028 30FC 0029 ;\tMA\t#* ( ㈠ → (ー) ) PARENTHESIZED IDEOGRAPH ONE → LEFT PARENTHESIS, KATAKANA-HIRAGANA PROLONGED SOUND MARK, RIGHT PARENTHESIS\t# →(一)→\n\n2475 ;\t0028 0032 0029 ;\tMA\t#* ( ⑵ → (2) ) PARENTHESIZED DIGIT TWO → LEFT PARENTHESIS, DIGIT TWO, RIGHT PARENTHESIS\t# \n\n2487 ;\t0028 0032 004F 0029 ;\tMA\t#* ( ⒇ → (2O) ) PARENTHESIZED NUMBER TWENTY → LEFT PARENTHESIS, DIGIT TWO, LATIN CAPITAL LETTER O, RIGHT PARENTHESIS\t# →(20)→\n\n2476 ;\t0028 0033 0029 ;\tMA\t#* ( ⑶ → (3) ) PARENTHESIZED DIGIT THREE → LEFT PARENTHESIS, DIGIT THREE, RIGHT PARENTHESIS\t# \n\n2477 ;\t0028 0034 0029 ;\tMA\t#* ( ⑷ → (4) ) PARENTHESIZED DIGIT FOUR → LEFT PARENTHESIS, DIGIT FOUR, RIGHT PARENTHESIS\t# \n\n2478 ;\t0028 0035 0029 ;\tMA\t#* ( ⑸ → (5) ) PARENTHESIZED DIGIT FIVE → LEFT PARENTHESIS, DIGIT FIVE, RIGHT PARENTHESIS\t# \n\n2479 ;\t0028 0036 0029 ;\tMA\t#* ( ⑹ → (6) ) PARENTHESIZED DIGIT SIX → LEFT PARENTHESIS, DIGIT SIX, RIGHT PARENTHESIS\t# \n\n247A ;\t0028 0037 0029 ;\tMA\t#* ( ⑺ → (7) ) PARENTHESIZED DIGIT SEVEN → LEFT PARENTHESIS, DIGIT SEVEN, RIGHT PARENTHESIS\t# \n\n247B ;\t0028 0038 0029 ;\tMA\t#* ( ⑻ → (8) ) PARENTHESIZED DIGIT EIGHT → LEFT PARENTHESIS, DIGIT EIGHT, RIGHT PARENTHESIS\t# \n\n247C ;\t0028 0039 0029 ;\tMA\t#* ( ⑼ → (9) ) PARENTHESIZED DIGIT NINE → LEFT PARENTHESIS, DIGIT NINE, RIGHT PARENTHESIS\t# \n\n249C ;\t0028 0061 0029 ;\tMA\t#* ( ⒜ → (a) ) PARENTHESIZED LATIN SMALL LETTER A → LEFT PARENTHESIS, LATIN SMALL LETTER A, RIGHT PARENTHESIS\t# \n\n1F110 ;\t0028 0041 0029 ;\tMA\t#* ( 🄐 → (A) ) PARENTHESIZED LATIN CAPITAL LETTER A → LEFT PARENTHESIS, LATIN CAPITAL LETTER A, RIGHT PARENTHESIS\t# \n\n249D ;\t0028 0062 0029 ;\tMA\t#* ( ⒝ → (b) ) PARENTHESIZED LATIN SMALL LETTER B → LEFT PARENTHESIS, LATIN SMALL LETTER B, RIGHT PARENTHESIS\t# \n\n1F111 ;\t0028 0042 0029 ;\tMA\t#* ( 🄑 → (B) ) PARENTHESIZED LATIN CAPITAL LETTER B → LEFT PARENTHESIS, LATIN CAPITAL LETTER B, RIGHT PARENTHESIS\t# \n\n249E ;\t0028 0063 0029 ;\tMA\t#* ( ⒞ → (c) ) PARENTHESIZED LATIN SMALL LETTER C → LEFT PARENTHESIS, LATIN SMALL LETTER C, RIGHT PARENTHESIS\t# \n\n1F112 ;\t0028 0043 0029 ;\tMA\t#* ( 🄒 → (C) ) PARENTHESIZED LATIN CAPITAL LETTER C → LEFT PARENTHESIS, LATIN CAPITAL LETTER C, RIGHT PARENTHESIS\t# \n\n249F ;\t0028 0064 0029 ;\tMA\t#* ( ⒟ → (d) ) PARENTHESIZED LATIN SMALL LETTER D → LEFT PARENTHESIS, LATIN SMALL LETTER D, RIGHT PARENTHESIS\t# \n\n1F113 ;\t0028 0044 0029 ;\tMA\t#* ( 🄓 → (D) ) PARENTHESIZED LATIN CAPITAL LETTER D → LEFT PARENTHESIS, LATIN CAPITAL LETTER D, RIGHT PARENTHESIS\t# \n\n24A0 ;\t0028 0065 0029 ;\tMA\t#* ( ⒠ → (e) ) PARENTHESIZED LATIN SMALL LETTER E → LEFT PARENTHESIS, LATIN SMALL LETTER E, RIGHT PARENTHESIS\t# \n\n1F114 ;\t0028 0045 0029 ;\tMA\t#* ( 🄔 → (E) ) PARENTHESIZED LATIN CAPITAL LETTER E → LEFT PARENTHESIS, LATIN CAPITAL LETTER E, RIGHT PARENTHESIS\t# \n\n24A1 ;\t0028 0066 0029 ;\tMA\t#* ( ⒡ → (f) ) PARENTHESIZED LATIN SMALL LETTER F → LEFT PARENTHESIS, LATIN SMALL LETTER F, RIGHT PARENTHESIS\t# \n\n1F115 ;\t0028 0046 0029 ;\tMA\t#* ( 🄕 → (F) ) PARENTHESIZED LATIN CAPITAL LETTER F → LEFT PARENTHESIS, LATIN CAPITAL LETTER F, RIGHT PARENTHESIS\t# \n\n24A2 ;\t0028 0067 0029 ;\tMA\t#* ( ⒢ → (g) ) PARENTHESIZED LATIN SMALL LETTER G → LEFT PARENTHESIS, LATIN SMALL LETTER G, RIGHT PARENTHESIS\t# \n\n1F116 ;\t0028 0047 0029 ;\tMA\t#* ( 🄖 → (G) ) PARENTHESIZED LATIN CAPITAL LETTER G → LEFT PARENTHESIS, LATIN CAPITAL LETTER G, RIGHT PARENTHESIS\t# \n\n24A3 ;\t0028 0068 0029 ;\tMA\t#* ( ⒣ → (h) ) PARENTHESIZED LATIN SMALL LETTER H → LEFT PARENTHESIS, LATIN SMALL LETTER H, RIGHT PARENTHESIS\t# \n\n1F117 ;\t0028 0048 0029 ;\tMA\t#* ( 🄗 → (H) ) PARENTHESIZED LATIN CAPITAL LETTER H → LEFT PARENTHESIS, LATIN CAPITAL LETTER H, RIGHT PARENTHESIS\t# \n\n24A4 ;\t0028 0069 0029 ;\tMA\t#* ( ⒤ → (i) ) PARENTHESIZED LATIN SMALL LETTER I → LEFT PARENTHESIS, LATIN SMALL LETTER I, RIGHT PARENTHESIS\t# \n\n24A5 ;\t0028 006A 0029 ;\tMA\t#* ( ⒥ → (j) ) PARENTHESIZED LATIN SMALL LETTER J → LEFT PARENTHESIS, LATIN SMALL LETTER J, RIGHT PARENTHESIS\t# \n\n1F119 ;\t0028 004A 0029 ;\tMA\t#* ( 🄙 → (J) ) PARENTHESIZED LATIN CAPITAL LETTER J → LEFT PARENTHESIS, LATIN CAPITAL LETTER J, RIGHT PARENTHESIS\t# \n\n24A6 ;\t0028 006B 0029 ;\tMA\t#* ( ⒦ → (k) ) PARENTHESIZED LATIN SMALL LETTER K → LEFT PARENTHESIS, LATIN SMALL LETTER K, RIGHT PARENTHESIS\t# \n\n1F11A ;\t0028 004B 0029 ;\tMA\t#* ( 🄚 → (K) ) PARENTHESIZED LATIN CAPITAL LETTER K → LEFT PARENTHESIS, LATIN CAPITAL LETTER K, RIGHT PARENTHESIS\t# \n\n2474 ;\t0028 006C 0029 ;\tMA\t#* ( ⑴ → (l) ) PARENTHESIZED DIGIT ONE → LEFT PARENTHESIS, LATIN SMALL LETTER L, RIGHT PARENTHESIS\t# →(1)→\n1F118 ;\t0028 006C 0029 ;\tMA\t#* ( 🄘 → (l) ) PARENTHESIZED LATIN CAPITAL LETTER I → LEFT PARENTHESIS, LATIN SMALL LETTER L, RIGHT PARENTHESIS\t# →(I)→\n24A7 ;\t0028 006C 0029 ;\tMA\t#* ( ⒧ → (l) ) PARENTHESIZED LATIN SMALL LETTER L → LEFT PARENTHESIS, LATIN SMALL LETTER L, RIGHT PARENTHESIS\t# \n\n1F11B ;\t0028 004C 0029 ;\tMA\t#* ( 🄛 → (L) ) PARENTHESIZED LATIN CAPITAL LETTER L → LEFT PARENTHESIS, LATIN CAPITAL LETTER L, RIGHT PARENTHESIS\t# \n\n247F ;\t0028 006C 0032 0029 ;\tMA\t#* ( ⑿ → (l2) ) PARENTHESIZED NUMBER TWELVE → LEFT PARENTHESIS, LATIN SMALL LETTER L, DIGIT TWO, RIGHT PARENTHESIS\t# →(12)→\n\n2480 ;\t0028 006C 0033 0029 ;\tMA\t#* ( ⒀ → (l3) ) PARENTHESIZED NUMBER THIRTEEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, DIGIT THREE, RIGHT PARENTHESIS\t# →(13)→\n\n2481 ;\t0028 006C 0034 0029 ;\tMA\t#* ( ⒁ → (l4) ) PARENTHESIZED NUMBER FOURTEEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, DIGIT FOUR, RIGHT PARENTHESIS\t# →(14)→\n\n2482 ;\t0028 006C 0035 0029 ;\tMA\t#* ( ⒂ → (l5) ) PARENTHESIZED NUMBER FIFTEEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, DIGIT FIVE, RIGHT PARENTHESIS\t# →(15)→\n\n2483 ;\t0028 006C 0036 0029 ;\tMA\t#* ( ⒃ → (l6) ) PARENTHESIZED NUMBER SIXTEEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, DIGIT SIX, RIGHT PARENTHESIS\t# →(16)→\n\n2484 ;\t0028 006C 0037 0029 ;\tMA\t#* ( ⒄ → (l7) ) PARENTHESIZED NUMBER SEVENTEEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, DIGIT SEVEN, RIGHT PARENTHESIS\t# →(17)→\n\n2485 ;\t0028 006C 0038 0029 ;\tMA\t#* ( ⒅ → (l8) ) PARENTHESIZED NUMBER EIGHTEEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, DIGIT EIGHT, RIGHT PARENTHESIS\t# →(18)→\n\n2486 ;\t0028 006C 0039 0029 ;\tMA\t#* ( ⒆ → (l9) ) PARENTHESIZED NUMBER NINETEEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, DIGIT NINE, RIGHT PARENTHESIS\t# →(19)→\n\n247E ;\t0028 006C 006C 0029 ;\tMA\t#* ( ⑾ → (ll) ) PARENTHESIZED NUMBER ELEVEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, LATIN SMALL LETTER L, RIGHT PARENTHESIS\t# →(11)→\n\n247D ;\t0028 006C 004F 0029 ;\tMA\t#* ( ⑽ → (lO) ) PARENTHESIZED NUMBER TEN → LEFT PARENTHESIS, LATIN SMALL LETTER L, LATIN CAPITAL LETTER O, RIGHT PARENTHESIS\t# →(10)→\n\n1F11C ;\t0028 004D 0029 ;\tMA\t#* ( 🄜 → (M) ) PARENTHESIZED LATIN CAPITAL LETTER M → LEFT PARENTHESIS, LATIN CAPITAL LETTER M, RIGHT PARENTHESIS\t# \n\n24A9 ;\t0028 006E 0029 ;\tMA\t#* ( ⒩ → (n) ) PARENTHESIZED LATIN SMALL LETTER N → LEFT PARENTHESIS, LATIN SMALL LETTER N, RIGHT PARENTHESIS\t# \n\n1F11D ;\t0028 004E 0029 ;\tMA\t#* ( 🄝 → (N) ) PARENTHESIZED LATIN CAPITAL LETTER N → LEFT PARENTHESIS, LATIN CAPITAL LETTER N, RIGHT PARENTHESIS\t# \n\n24AA ;\t0028 006F 0029 ;\tMA\t#* ( ⒪ → (o) ) PARENTHESIZED LATIN SMALL LETTER O → LEFT PARENTHESIS, LATIN SMALL LETTER O, RIGHT PARENTHESIS\t# \n\n1F11E ;\t0028 004F 0029 ;\tMA\t#* ( 🄞 → (O) ) PARENTHESIZED LATIN CAPITAL LETTER O → LEFT PARENTHESIS, LATIN CAPITAL LETTER O, RIGHT PARENTHESIS\t# \n\n24AB ;\t0028 0070 0029 ;\tMA\t#* ( ⒫ → (p) ) PARENTHESIZED LATIN SMALL LETTER P → LEFT PARENTHESIS, LATIN SMALL LETTER P, RIGHT PARENTHESIS\t# \n\n1F11F ;\t0028 0050 0029 ;\tMA\t#* ( 🄟 → (P) ) PARENTHESIZED LATIN CAPITAL LETTER P → LEFT PARENTHESIS, LATIN CAPITAL LETTER P, RIGHT PARENTHESIS\t# \n\n24AC ;\t0028 0071 0029 ;\tMA\t#* ( ⒬ → (q) ) PARENTHESIZED LATIN SMALL LETTER Q → LEFT PARENTHESIS, LATIN SMALL LETTER Q, RIGHT PARENTHESIS\t# \n\n1F120 ;\t0028 0051 0029 ;\tMA\t#* ( 🄠 → (Q) ) PARENTHESIZED LATIN CAPITAL LETTER Q → LEFT PARENTHESIS, LATIN CAPITAL LETTER Q, RIGHT PARENTHESIS\t# \n\n24AD ;\t0028 0072 0029 ;\tMA\t#* ( ⒭ → (r) ) PARENTHESIZED LATIN SMALL LETTER R → LEFT PARENTHESIS, LATIN SMALL LETTER R, RIGHT PARENTHESIS\t# \n\n1F121 ;\t0028 0052 0029 ;\tMA\t#* ( 🄡 → (R) ) PARENTHESIZED LATIN CAPITAL LETTER R → LEFT PARENTHESIS, LATIN CAPITAL LETTER R, RIGHT PARENTHESIS\t# \n\n24A8 ;\t0028 0072 006E 0029 ;\tMA\t#* ( ⒨ → (rn) ) PARENTHESIZED LATIN SMALL LETTER M → LEFT PARENTHESIS, LATIN SMALL LETTER R, LATIN SMALL LETTER N, RIGHT PARENTHESIS\t# →(m)→\n\n24AE ;\t0028 0073 0029 ;\tMA\t#* ( ⒮ → (s) ) PARENTHESIZED LATIN SMALL LETTER S → LEFT PARENTHESIS, LATIN SMALL LETTER S, RIGHT PARENTHESIS\t# \n\n1F122 ;\t0028 0053 0029 ;\tMA\t#* ( 🄢 → (S) ) PARENTHESIZED LATIN CAPITAL LETTER S → LEFT PARENTHESIS, LATIN CAPITAL LETTER S, RIGHT PARENTHESIS\t# \n1F12A ;\t0028 0053 0029 ;\tMA\t#* ( 🄪 → (S) ) TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S → LEFT PARENTHESIS, LATIN CAPITAL LETTER S, RIGHT PARENTHESIS\t# →〔S〕→\n\n24AF ;\t0028 0074 0029 ;\tMA\t#* ( ⒯ → (t) ) PARENTHESIZED LATIN SMALL LETTER T → LEFT PARENTHESIS, LATIN SMALL LETTER T, RIGHT PARENTHESIS\t# \n\n1F123 ;\t0028 0054 0029 ;\tMA\t#* ( 🄣 → (T) ) PARENTHESIZED LATIN CAPITAL LETTER T → LEFT PARENTHESIS, LATIN CAPITAL LETTER T, RIGHT PARENTHESIS\t# \n\n24B0 ;\t0028 0075 0029 ;\tMA\t#* ( ⒰ → (u) ) PARENTHESIZED LATIN SMALL LETTER U → LEFT PARENTHESIS, LATIN SMALL LETTER U, RIGHT PARENTHESIS\t# \n\n1F124 ;\t0028 0055 0029 ;\tMA\t#* ( 🄤 → (U) ) PARENTHESIZED LATIN CAPITAL LETTER U → LEFT PARENTHESIS, LATIN CAPITAL LETTER U, RIGHT PARENTHESIS\t# \n\n24B1 ;\t0028 0076 0029 ;\tMA\t#* ( ⒱ → (v) ) PARENTHESIZED LATIN SMALL LETTER V → LEFT PARENTHESIS, LATIN SMALL LETTER V, RIGHT PARENTHESIS\t# \n\n1F125 ;\t0028 0056 0029 ;\tMA\t#* ( 🄥 → (V) ) PARENTHESIZED LATIN CAPITAL LETTER V → LEFT PARENTHESIS, LATIN CAPITAL LETTER V, RIGHT PARENTHESIS\t# \n\n24B2 ;\t0028 0077 0029 ;\tMA\t#* ( ⒲ → (w) ) PARENTHESIZED LATIN SMALL LETTER W → LEFT PARENTHESIS, LATIN SMALL LETTER W, RIGHT PARENTHESIS\t# \n\n1F126 ;\t0028 0057 0029 ;\tMA\t#* ( 🄦 → (W) ) PARENTHESIZED LATIN CAPITAL LETTER W → LEFT PARENTHESIS, LATIN CAPITAL LETTER W, RIGHT PARENTHESIS\t# \n\n24B3 ;\t0028 0078 0029 ;\tMA\t#* ( ⒳ → (x) ) PARENTHESIZED LATIN SMALL LETTER X → LEFT PARENTHESIS, LATIN SMALL LETTER X, RIGHT PARENTHESIS\t# \n\n1F127 ;\t0028 0058 0029 ;\tMA\t#* ( 🄧 → (X) ) PARENTHESIZED LATIN CAPITAL LETTER X → LEFT PARENTHESIS, LATIN CAPITAL LETTER X, RIGHT PARENTHESIS\t# \n\n24B4 ;\t0028 0079 0029 ;\tMA\t#* ( ⒴ → (y) ) PARENTHESIZED LATIN SMALL LETTER Y → LEFT PARENTHESIS, LATIN SMALL LETTER Y, RIGHT PARENTHESIS\t# \n\n1F128 ;\t0028 0059 0029 ;\tMA\t#* ( 🄨 → (Y) ) PARENTHESIZED LATIN CAPITAL LETTER Y → LEFT PARENTHESIS, LATIN CAPITAL LETTER Y, RIGHT PARENTHESIS\t# \n\n24B5 ;\t0028 007A 0029 ;\tMA\t#* ( ⒵ → (z) ) PARENTHESIZED LATIN SMALL LETTER Z → LEFT PARENTHESIS, LATIN SMALL LETTER Z, RIGHT PARENTHESIS\t# \n\n1F129 ;\t0028 005A 0029 ;\tMA\t#* ( 🄩 → (Z) ) PARENTHESIZED LATIN CAPITAL LETTER Z → LEFT PARENTHESIS, LATIN CAPITAL LETTER Z, RIGHT PARENTHESIS\t# \n\n3200 ;\t0028 1100 0029 ;\tMA\t#* ( ㈀ → (ᄀ) ) PARENTHESIZED HANGUL KIYEOK → LEFT PARENTHESIS, HANGUL CHOSEONG KIYEOK, RIGHT PARENTHESIS\t# \n\n320E ;\t0028 AC00 0029 ;\tMA\t#* ( ㈎ → (가) ) PARENTHESIZED HANGUL KIYEOK A → LEFT PARENTHESIS, HANGUL SYLLABLE GA, RIGHT PARENTHESIS\t# \n\n3201 ;\t0028 1102 0029 ;\tMA\t#* ( ㈁ → (ᄂ) ) PARENTHESIZED HANGUL NIEUN → LEFT PARENTHESIS, HANGUL CHOSEONG NIEUN, RIGHT PARENTHESIS\t# \n\n320F ;\t0028 B098 0029 ;\tMA\t#* ( ㈏ → (나) ) PARENTHESIZED HANGUL NIEUN A → LEFT PARENTHESIS, HANGUL SYLLABLE NA, RIGHT PARENTHESIS\t# \n\n3202 ;\t0028 1103 0029 ;\tMA\t#* ( ㈂ → (ᄃ) ) PARENTHESIZED HANGUL TIKEUT → LEFT PARENTHESIS, HANGUL CHOSEONG TIKEUT, RIGHT PARENTHESIS\t# \n\n3210 ;\t0028 B2E4 0029 ;\tMA\t#* ( ㈐ → (다) ) PARENTHESIZED HANGUL TIKEUT A → LEFT PARENTHESIS, HANGUL SYLLABLE DA, RIGHT PARENTHESIS\t# \n\n3203 ;\t0028 1105 0029 ;\tMA\t#* ( ㈃ → (ᄅ) ) PARENTHESIZED HANGUL RIEUL → LEFT PARENTHESIS, HANGUL CHOSEONG RIEUL, RIGHT PARENTHESIS\t# \n\n3211 ;\t0028 B77C 0029 ;\tMA\t#* ( ㈑ → (라) ) PARENTHESIZED HANGUL RIEUL A → LEFT PARENTHESIS, HANGUL SYLLABLE RA, RIGHT PARENTHESIS\t# \n\n3204 ;\t0028 1106 0029 ;\tMA\t#* ( ㈄ → (ᄆ) ) PARENTHESIZED HANGUL MIEUM → LEFT PARENTHESIS, HANGUL CHOSEONG MIEUM, RIGHT PARENTHESIS\t# \n\n3212 ;\t0028 B9C8 0029 ;\tMA\t#* ( ㈒ → (마) ) PARENTHESIZED HANGUL MIEUM A → LEFT PARENTHESIS, HANGUL SYLLABLE MA, RIGHT PARENTHESIS\t# \n\n3205 ;\t0028 1107 0029 ;\tMA\t#* ( ㈅ → (ᄇ) ) PARENTHESIZED HANGUL PIEUP → LEFT PARENTHESIS, HANGUL CHOSEONG PIEUP, RIGHT PARENTHESIS\t# \n\n3213 ;\t0028 BC14 0029 ;\tMA\t#* ( ㈓ → (바) ) PARENTHESIZED HANGUL PIEUP A → LEFT PARENTHESIS, HANGUL SYLLABLE BA, RIGHT PARENTHESIS\t# \n\n3206 ;\t0028 1109 0029 ;\tMA\t#* ( ㈆ → (ᄉ) ) PARENTHESIZED HANGUL SIOS → LEFT PARENTHESIS, HANGUL CHOSEONG SIOS, RIGHT PARENTHESIS\t# \n\n3214 ;\t0028 C0AC 0029 ;\tMA\t#* ( ㈔ → (사) ) PARENTHESIZED HANGUL SIOS A → LEFT PARENTHESIS, HANGUL SYLLABLE SA, RIGHT PARENTHESIS\t# \n\n3207 ;\t0028 110B 0029 ;\tMA\t#* ( ㈇ → (ᄋ) ) PARENTHESIZED HANGUL IEUNG → LEFT PARENTHESIS, HANGUL CHOSEONG IEUNG, RIGHT PARENTHESIS\t# \n\n3215 ;\t0028 C544 0029 ;\tMA\t#* ( ㈕ → (아) ) PARENTHESIZED HANGUL IEUNG A → LEFT PARENTHESIS, HANGUL SYLLABLE A, RIGHT PARENTHESIS\t# \n\n321D ;\t0028 C624 C804 0029 ;\tMA\t#* ( ㈝ → (오전) ) PARENTHESIZED KOREAN CHARACTER OJEON → LEFT PARENTHESIS, HANGUL SYLLABLE O, HANGUL SYLLABLE JEON, RIGHT PARENTHESIS\t# \n\n321E ;\t0028 C624 D6C4 0029 ;\tMA\t#* ( ㈞ → (오후) ) PARENTHESIZED KOREAN CHARACTER O HU → LEFT PARENTHESIS, HANGUL SYLLABLE O, HANGUL SYLLABLE HU, RIGHT PARENTHESIS\t# \n\n3208 ;\t0028 110C 0029 ;\tMA\t#* ( ㈈ → (ᄌ) ) PARENTHESIZED HANGUL CIEUC → LEFT PARENTHESIS, HANGUL CHOSEONG CIEUC, RIGHT PARENTHESIS\t# \n\n3216 ;\t0028 C790 0029 ;\tMA\t#* ( ㈖ → (자) ) PARENTHESIZED HANGUL CIEUC A → LEFT PARENTHESIS, HANGUL SYLLABLE JA, RIGHT PARENTHESIS\t# \n\n321C ;\t0028 C8FC 0029 ;\tMA\t#* ( ㈜ → (주) ) PARENTHESIZED HANGUL CIEUC U → LEFT PARENTHESIS, HANGUL SYLLABLE JU, RIGHT PARENTHESIS\t# \n\n3209 ;\t0028 110E 0029 ;\tMA\t#* ( ㈉ → (ᄎ) ) PARENTHESIZED HANGUL CHIEUCH → LEFT PARENTHESIS, HANGUL CHOSEONG CHIEUCH, RIGHT PARENTHESIS\t# \n\n3217 ;\t0028 CC28 0029 ;\tMA\t#* ( ㈗ → (차) ) PARENTHESIZED HANGUL CHIEUCH A → LEFT PARENTHESIS, HANGUL SYLLABLE CA, RIGHT PARENTHESIS\t# \n\n320A ;\t0028 110F 0029 ;\tMA\t#* ( ㈊ → (ᄏ) ) PARENTHESIZED HANGUL KHIEUKH → LEFT PARENTHESIS, HANGUL CHOSEONG KHIEUKH, RIGHT PARENTHESIS\t# \n\n3218 ;\t0028 CE74 0029 ;\tMA\t#* ( ㈘ → (카) ) PARENTHESIZED HANGUL KHIEUKH A → LEFT PARENTHESIS, HANGUL SYLLABLE KA, RIGHT PARENTHESIS\t# \n\n320B ;\t0028 1110 0029 ;\tMA\t#* ( ㈋ → (ᄐ) ) PARENTHESIZED HANGUL THIEUTH → LEFT PARENTHESIS, HANGUL CHOSEONG THIEUTH, RIGHT PARENTHESIS\t# \n\n3219 ;\t0028 D0C0 0029 ;\tMA\t#* ( ㈙ → (타) ) PARENTHESIZED HANGUL THIEUTH A → LEFT PARENTHESIS, HANGUL SYLLABLE TA, RIGHT PARENTHESIS\t# \n\n320C ;\t0028 1111 0029 ;\tMA\t#* ( ㈌ → (ᄑ) ) PARENTHESIZED HANGUL PHIEUPH → LEFT PARENTHESIS, HANGUL CHOSEONG PHIEUPH, RIGHT PARENTHESIS\t# \n\n321A ;\t0028 D30C 0029 ;\tMA\t#* ( ㈚ → (파) ) PARENTHESIZED HANGUL PHIEUPH A → LEFT PARENTHESIS, HANGUL SYLLABLE PA, RIGHT PARENTHESIS\t# \n\n320D ;\t0028 1112 0029 ;\tMA\t#* ( ㈍ → (ᄒ) ) PARENTHESIZED HANGUL HIEUH → LEFT PARENTHESIS, HANGUL CHOSEONG HIEUH, RIGHT PARENTHESIS\t# \n\n321B ;\t0028 D558 0029 ;\tMA\t#* ( ㈛ → (하) ) PARENTHESIZED HANGUL HIEUH A → LEFT PARENTHESIS, HANGUL SYLLABLE HA, RIGHT PARENTHESIS\t# \n\n3226 ;\t0028 4E03 0029 ;\tMA\t#* ( ㈦ → (七) ) PARENTHESIZED IDEOGRAPH SEVEN → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4E03, RIGHT PARENTHESIS\t# \n\n3222 ;\t0028 4E09 0029 ;\tMA\t#* ( ㈢ → (三) ) PARENTHESIZED IDEOGRAPH THREE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4E09, RIGHT PARENTHESIS\t# \n1F241 ;\t0028 4E09 0029 ;\tMA\t#* ( 🉁 → (三) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09 → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4E09, RIGHT PARENTHESIS\t# →〔三〕→\n\n3228 ;\t0028 4E5D 0029 ;\tMA\t#* ( ㈨ → (九) ) PARENTHESIZED IDEOGRAPH NINE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4E5D, RIGHT PARENTHESIS\t# \n\n3221 ;\t0028 4E8C 0029 ;\tMA\t#* ( ㈡ → (二) ) PARENTHESIZED IDEOGRAPH TWO → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4E8C, RIGHT PARENTHESIS\t# \n1F242 ;\t0028 4E8C 0029 ;\tMA\t#* ( 🉂 → (二) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4E8C, RIGHT PARENTHESIS\t# →〔二〕→\n\n3224 ;\t0028 4E94 0029 ;\tMA\t#* ( ㈤ → (五) ) PARENTHESIZED IDEOGRAPH FIVE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4E94, RIGHT PARENTHESIS\t# \n\n3239 ;\t0028 4EE3 0029 ;\tMA\t#* ( ㈹ → (代) ) PARENTHESIZED IDEOGRAPH REPRESENT → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4EE3, RIGHT PARENTHESIS\t# \n\n323D ;\t0028 4F01 0029 ;\tMA\t#* ( ㈽ → (企) ) PARENTHESIZED IDEOGRAPH ENTERPRISE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4F01, RIGHT PARENTHESIS\t# \n\n3241 ;\t0028 4F11 0029 ;\tMA\t#* ( ㉁ → (休) ) PARENTHESIZED IDEOGRAPH REST → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-4F11, RIGHT PARENTHESIS\t# \n\n3227 ;\t0028 516B 0029 ;\tMA\t#* ( ㈧ → (八) ) PARENTHESIZED IDEOGRAPH EIGHT → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-516B, RIGHT PARENTHESIS\t# \n\n3225 ;\t0028 516D 0029 ;\tMA\t#* ( ㈥ → (六) ) PARENTHESIZED IDEOGRAPH SIX → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-516D, RIGHT PARENTHESIS\t# \n\n3238 ;\t0028 52B4 0029 ;\tMA\t#* ( ㈸ → (労) ) PARENTHESIZED IDEOGRAPH LABOR → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-52B4, RIGHT PARENTHESIS\t# \n\n1F247 ;\t0028 52DD 0029 ;\tMA\t#* ( 🉇 → (勝) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-52DD, RIGHT PARENTHESIS\t# →〔勝〕→\n\n3229 ;\t0028 5341 0029 ;\tMA\t#* ( ㈩ → (十) ) PARENTHESIZED IDEOGRAPH TEN → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-5341, RIGHT PARENTHESIS\t# \n\n323F ;\t0028 5354 0029 ;\tMA\t#* ( ㈿ → (協) ) PARENTHESIZED IDEOGRAPH ALLIANCE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-5354, RIGHT PARENTHESIS\t# \n\n3234 ;\t0028 540D 0029 ;\tMA\t#* ( ㈴ → (名) ) PARENTHESIZED IDEOGRAPH NAME → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-540D, RIGHT PARENTHESIS\t# \n\n323A ;\t0028 547C 0029 ;\tMA\t#* ( ㈺ → (呼) ) PARENTHESIZED IDEOGRAPH CALL → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-547C, RIGHT PARENTHESIS\t# \n\n3223 ;\t0028 56DB 0029 ;\tMA\t#* ( ㈣ → (四) ) PARENTHESIZED IDEOGRAPH FOUR → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-56DB, RIGHT PARENTHESIS\t# \n\n322F ;\t0028 571F 0029 ;\tMA\t#* ( ㈯ → (土) ) PARENTHESIZED IDEOGRAPH EARTH → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-571F, RIGHT PARENTHESIS\t# \n\n323B ;\t0028 5B66 0029 ;\tMA\t#* ( ㈻ → (学) ) PARENTHESIZED IDEOGRAPH STUDY → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-5B66, RIGHT PARENTHESIS\t# \n\n1F243 ;\t0028 5B89 0029 ;\tMA\t#* ( 🉃 → (安) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89 → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-5B89, RIGHT PARENTHESIS\t# →〔安〕→\n\n1F245 ;\t0028 6253 0029 ;\tMA\t#* ( 🉅 → (打) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253 → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-6253, RIGHT PARENTHESIS\t# →〔打〕→\n\n1F248 ;\t0028 6557 0029 ;\tMA\t#* ( 🉈 → (敗) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-6557, RIGHT PARENTHESIS\t# →〔敗〕→\n\n3230 ;\t0028 65E5 0029 ;\tMA\t#* ( ㈰ → (日) ) PARENTHESIZED IDEOGRAPH SUN → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-65E5, RIGHT PARENTHESIS\t# \n\n322A ;\t0028 6708 0029 ;\tMA\t#* ( ㈪ → (月) ) PARENTHESIZED IDEOGRAPH MOON → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-6708, RIGHT PARENTHESIS\t# \n\n3232 ;\t0028 6709 0029 ;\tMA\t#* ( ㈲ → (有) ) PARENTHESIZED IDEOGRAPH HAVE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-6709, RIGHT PARENTHESIS\t# \n\n322D ;\t0028 6728 0029 ;\tMA\t#* ( ㈭ → (木) ) PARENTHESIZED IDEOGRAPH WOOD → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-6728, RIGHT PARENTHESIS\t# \n\n1F240 ;\t0028 672C 0029 ;\tMA\t#* ( 🉀 → (本) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-672C, RIGHT PARENTHESIS\t# →〔本〕→\n\n3231 ;\t0028 682A 0029 ;\tMA\t#* ( ㈱ → (株) ) PARENTHESIZED IDEOGRAPH STOCK → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-682A, RIGHT PARENTHESIS\t# \n\n322C ;\t0028 6C34 0029 ;\tMA\t#* ( ㈬ → (水) ) PARENTHESIZED IDEOGRAPH WATER → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-6C34, RIGHT PARENTHESIS\t# \n\n322B ;\t0028 706B 0029 ;\tMA\t#* ( ㈫ → (火) ) PARENTHESIZED IDEOGRAPH FIRE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-706B, RIGHT PARENTHESIS\t# \n\n1F244 ;\t0028 70B9 0029 ;\tMA\t#* ( 🉄 → (点) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9 → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-70B9, RIGHT PARENTHESIS\t# →〔点〕→\n\n3235 ;\t0028 7279 0029 ;\tMA\t#* ( ㈵ → (特) ) PARENTHESIZED IDEOGRAPH SPECIAL → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-7279, RIGHT PARENTHESIS\t# \n\n1F246 ;\t0028 76D7 0029 ;\tMA\t#* ( 🉆 → (盗) ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7 → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-76D7, RIGHT PARENTHESIS\t# →〔盗〕→\n\n323C ;\t0028 76E3 0029 ;\tMA\t#* ( ㈼ → (監) ) PARENTHESIZED IDEOGRAPH SUPERVISE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-76E3, RIGHT PARENTHESIS\t# \n\n3233 ;\t0028 793E 0029 ;\tMA\t#* ( ㈳ → (社) ) PARENTHESIZED IDEOGRAPH SOCIETY → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-793E, RIGHT PARENTHESIS\t# \n\n3237 ;\t0028 795D 0029 ;\tMA\t#* ( ㈷ → (祝) ) PARENTHESIZED IDEOGRAPH CONGRATULATION → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-795D, RIGHT PARENTHESIS\t# \n\n3240 ;\t0028 796D 0029 ;\tMA\t#* ( ㉀ → (祭) ) PARENTHESIZED IDEOGRAPH FESTIVAL → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-796D, RIGHT PARENTHESIS\t# \n\n3242 ;\t0028 81EA 0029 ;\tMA\t#* ( ㉂ → (自) ) PARENTHESIZED IDEOGRAPH SELF → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-81EA, RIGHT PARENTHESIS\t# \n\n3243 ;\t0028 81F3 0029 ;\tMA\t#* ( ㉃ → (至) ) PARENTHESIZED IDEOGRAPH REACH → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-81F3, RIGHT PARENTHESIS\t# \n\n3236 ;\t0028 8CA1 0029 ;\tMA\t#* ( ㈶ → (財) ) PARENTHESIZED IDEOGRAPH FINANCIAL → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-8CA1, RIGHT PARENTHESIS\t# \n\n323E ;\t0028 8CC7 0029 ;\tMA\t#* ( ㈾ → (資) ) PARENTHESIZED IDEOGRAPH RESOURCE → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-8CC7, RIGHT PARENTHESIS\t# \n\n322E ;\t0028 91D1 0029 ;\tMA\t#* ( ㈮ → (金) ) PARENTHESIZED IDEOGRAPH METAL → LEFT PARENTHESIS, CJK UNIFIED IDEOGRAPH-91D1, RIGHT PARENTHESIS\t# \n\nFF3D ;\t0029 ;\tMA\t#* ( ］ → ) ) FULLWIDTH RIGHT SQUARE BRACKET → RIGHT PARENTHESIS\t# →〕→\n2769 ;\t0029 ;\tMA\t#* ( ❩ → ) ) MEDIUM RIGHT PARENTHESIS ORNAMENT → RIGHT PARENTHESIS\t# \n2773 ;\t0029 ;\tMA\t#* ( ❳ → ) ) LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT → RIGHT PARENTHESIS\t# →〕→\n3015 ;\t0029 ;\tMA\t#* ( 〕 → ) ) RIGHT TORTOISE SHELL BRACKET → RIGHT PARENTHESIS\t# \nFD3F ;\t0029 ;\tMA\t#* ( ﴿ → ) ) ORNATE RIGHT PARENTHESIS → RIGHT PARENTHESIS\t# \n\n2E29 ;\t0029 0029 ;\tMA\t#* ( ⸩ → )) ) RIGHT DOUBLE PARENTHESIS → RIGHT PARENTHESIS, RIGHT PARENTHESIS\t# \n\n2774 ;\t007B ;\tMA\t#* ( ❴ → { ) MEDIUM LEFT CURLY BRACKET ORNAMENT → LEFT CURLY BRACKET\t# \n1D114 ;\t007B ;\tMA\t#* ( 𝄔 → { ) MUSICAL SYMBOL BRACE → LEFT CURLY BRACKET\t# \n\n2775 ;\t007D ;\tMA\t#* ( ❵ → } ) MEDIUM RIGHT CURLY BRACKET ORNAMENT → RIGHT CURLY BRACKET\t# \n\n301A ;\t27E6 ;\tMA\t#* ( 〚 → ⟦ ) LEFT WHITE SQUARE BRACKET → MATHEMATICAL LEFT WHITE SQUARE BRACKET\t# \n\n301B ;\t27E7 ;\tMA\t#* ( 〛 → ⟧ ) RIGHT WHITE SQUARE BRACKET → MATHEMATICAL RIGHT WHITE SQUARE BRACKET\t# \n\n27E8 ;\t276C ;\tMA\t#* ( ⟨ → ❬ ) MATHEMATICAL LEFT ANGLE BRACKET → MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT\t# →〈→\n2329 ;\t276C ;\tMA\t#* ( 〈 → ❬ ) LEFT-POINTING ANGLE BRACKET → MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT\t# →〈→\n3008 ;\t276C ;\tMA\t#* ( 〈 → ❬ ) LEFT ANGLE BRACKET → MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT\t# \n31DB ;\t276C ;\tMA\t#* ( ㇛ → ❬ ) CJK STROKE PD → MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT\t# →⟨→→〈→\n304F ;\t276C ;\tMA\t# ( く → ❬ ) HIRAGANA LETTER KU → MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT\t# →㇛→→⟨→→〈→\n21FE8 ;\t276C ;\tMA\t# ( 𡿨 → ❬ ) CJK UNIFIED IDEOGRAPH-21FE8 → MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT\t# →㇛→→⟨→→〈→\n\n27E9 ;\t276D ;\tMA\t#* ( ⟩ → ❭ ) MATHEMATICAL RIGHT ANGLE BRACKET → MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT\t# →〉→\n232A ;\t276D ;\tMA\t#* ( 〉 → ❭ ) RIGHT-POINTING ANGLE BRACKET → MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT\t# →〉→\n3009 ;\t276D ;\tMA\t#* ( 〉 → ❭ ) RIGHT ANGLE BRACKET → MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT\t# \n\nFF3E ;\tFE3F ;\tMA\t#* ( ＾ → ︿ ) FULLWIDTH CIRCUMFLEX ACCENT → PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET\t# \n\n2E3F ;\t00B6 ;\tMA\t#* ( ⸿ → ¶ ) CAPITULUM → PILCROW SIGN\t# \n\n204E ;\t002A ;\tMA\t#* ( ⁎ → * ) LOW ASTERISK → ASTERISK\t# \n066D ;\t002A ;\tMA\t#* ( ‎٭‎ → * ) ARABIC FIVE POINTED STAR → ASTERISK\t# \n2217 ;\t002A ;\tMA\t#* ( ∗ → * ) ASTERISK OPERATOR → ASTERISK\t# \n1031F ;\t002A ;\tMA\t# ( 𐌟 → * ) OLD ITALIC LETTER ESS → ASTERISK\t# \n\n1735 ;\t002F ;\tMA\t#* ( ᜵ → / ) PHILIPPINE SINGLE PUNCTUATION → SOLIDUS\t# \n2041 ;\t002F ;\tMA\t#* ( ⁁ → / ) CARET INSERTION POINT → SOLIDUS\t# \n2215 ;\t002F ;\tMA\t#* ( ∕ → / ) DIVISION SLASH → SOLIDUS\t# \n2044 ;\t002F ;\tMA\t#* ( ⁄ → / ) FRACTION SLASH → SOLIDUS\t# \n2571 ;\t002F ;\tMA\t#* ( ╱ → / ) BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT → SOLIDUS\t# \n27CB ;\t002F ;\tMA\t#* ( ⟋ → / ) MATHEMATICAL RISING DIAGONAL → SOLIDUS\t# \n29F8 ;\t002F ;\tMA\t#* ( ⧸ → / ) BIG SOLIDUS → SOLIDUS\t# \n1D23A ;\t002F ;\tMA\t#* ( 𝈺 → / ) GREEK INSTRUMENTAL NOTATION SYMBOL-47 → SOLIDUS\t# \n31D3 ;\t002F ;\tMA\t#* ( ㇓ → / ) CJK STROKE SP → SOLIDUS\t# →⼃→\n3033 ;\t002F ;\tMA\t# ( 〳 → / ) VERTICAL KANA REPEAT MARK UPPER HALF → SOLIDUS\t# \n2CC7 ;\t002F ;\tMA\t# ( ⳇ → / ) COPTIC SMALL LETTER OLD COPTIC ESH → SOLIDUS\t# \n2CC6 ;\t002F ;\tMA\t# ( Ⳇ → / ) COPTIC CAPITAL LETTER OLD COPTIC ESH → SOLIDUS\t# \n30CE ;\t002F ;\tMA\t# ( ノ → / ) KATAKANA LETTER NO → SOLIDUS\t# →⼃→\n4E3F ;\t002F ;\tMA\t# ( 丿 → / ) CJK UNIFIED IDEOGRAPH-4E3F → SOLIDUS\t# →⼃→\n2F03 ;\t002F ;\tMA\t#* ( ⼃ → / ) KANGXI RADICAL SLASH → SOLIDUS\t# \n\n29F6 ;\t002F 0304 ;\tMA\t#* ( ⧶ → /̄ ) SOLIDUS WITH OVERBAR → SOLIDUS, COMBINING MACRON\t# \n\n2AFD ;\t002F 002F ;\tMA\t#* ( ⫽ → // ) DOUBLE SOLIDUS OPERATOR → SOLIDUS, SOLIDUS\t# \n\n2AFB ;\t002F 002F 002F ;\tMA\t#* ( ⫻ → /// ) TRIPLE SOLIDUS BINARY RELATION → SOLIDUS, SOLIDUS, SOLIDUS\t# \n\nFF3C ;\t005C ;\tMA\t#* ( ＼ → \\ ) FULLWIDTH REVERSE SOLIDUS → REVERSE SOLIDUS\t# →∖→\nFE68 ;\t005C ;\tMA\t#* ( ﹨ → \\ ) SMALL REVERSE SOLIDUS → REVERSE SOLIDUS\t# →∖→\n2216 ;\t005C ;\tMA\t#* ( ∖ → \\ ) SET MINUS → REVERSE SOLIDUS\t# \n27CD ;\t005C ;\tMA\t#* ( ⟍ → \\ ) MATHEMATICAL FALLING DIAGONAL → REVERSE SOLIDUS\t# \n29F5 ;\t005C ;\tMA\t#* ( ⧵ → \\ ) REVERSE SOLIDUS OPERATOR → REVERSE SOLIDUS\t# \n29F9 ;\t005C ;\tMA\t#* ( ⧹ → \\ ) BIG REVERSE SOLIDUS → REVERSE SOLIDUS\t# \n1D20F ;\t005C ;\tMA\t#* ( 𝈏 → \\ ) GREEK VOCAL NOTATION SYMBOL-16 → REVERSE SOLIDUS\t# \n1D23B ;\t005C ;\tMA\t#* ( 𝈻 → \\ ) GREEK INSTRUMENTAL NOTATION SYMBOL-48 → REVERSE SOLIDUS\t# →𝈏→\n31D4 ;\t005C ;\tMA\t#* ( ㇔ → \\ ) CJK STROKE D → REVERSE SOLIDUS\t# →⼂→\n4E36 ;\t005C ;\tMA\t# ( 丶 → \\ ) CJK UNIFIED IDEOGRAPH-4E36 → REVERSE SOLIDUS\t# →⼂→\n2F02 ;\t005C ;\tMA\t#* ( ⼂ → \\ ) KANGXI RADICAL DOT → REVERSE SOLIDUS\t# \n\n2CF9 ;\t005C 005C ;\tMA\t#* ( ⳹ → \\\\ ) COPTIC OLD NUBIAN FULL STOP → REVERSE SOLIDUS, REVERSE SOLIDUS\t# \n244A ;\t005C 005C ;\tMA\t#* ( ⑊ → \\\\ ) OCR DOUBLE BACKSLASH → REVERSE SOLIDUS, REVERSE SOLIDUS\t# \n\n27C8 ;\t005C 1455 ;\tMA\t#* ( ⟈ → \\ᑕ ) REVERSE SOLIDUS PRECEDING SUBSET → REVERSE SOLIDUS, CANADIAN SYLLABICS TA\t# →\\⊂→\n\nA778 ;\t0026 ;\tMA\t# ( ꝸ → & ) LATIN SMALL LETTER UM → AMPERSAND\t# \n\n0AF0 ;\t0970 ;\tMA\t#* ( ૰ → ॰ ) GUJARATI ABBREVIATION SIGN → DEVANAGARI ABBREVIATION SIGN\t# \n110BB ;\t0970 ;\tMA\t#* ( 𑂻 → ॰ ) KAITHI ABBREVIATION SIGN → DEVANAGARI ABBREVIATION SIGN\t# \n111C7 ;\t0970 ;\tMA\t#* ( 𑇇 → ॰ ) SHARADA ABBREVIATION SIGN → DEVANAGARI ABBREVIATION SIGN\t# \n26AC ;\t0970 ;\tMA\t#* ( ⚬ → ॰ ) MEDIUM SMALL WHITE CIRCLE → DEVANAGARI ABBREVIATION SIGN\t# \n\n111DB ;\tA8FC ;\tMA\t#* ( 𑇛 → ꣼ ) SHARADA SIGN SIDDHAM → DEVANAGARI SIGN SIDDHAM\t# \n\n17D9 ;\t0E4F ;\tMA\t#* ( ៙ → ๏ ) KHMER SIGN PHNAEK MUAN → THAI CHARACTER FONGMAN\t# \n\n17D5 ;\t0E5A ;\tMA\t#* ( ៕ → ๚ ) KHMER SIGN BARIYOOSAN → THAI CHARACTER ANGKHANKHU\t# \n\n17DA ;\t0E5B ;\tMA\t#* ( ៚ → ๛ ) KHMER SIGN KOOMUUT → THAI CHARACTER KHOMUT\t# \n\n0F0C ;\t0F0B ;\tMA\t#* ( ༌ → ་ ) TIBETAN MARK DELIMITER TSHEG BSTAR → TIBETAN MARK INTERSYLLABIC TSHEG\t# \n\n0F0E ;\t0F0D 0F0D ;\tMA\t#* ( ༎ → །། ) TIBETAN MARK NYIS SHAD → TIBETAN MARK SHAD, TIBETAN MARK SHAD\t# \n\n02C4 ;\t005E ;\tMA\t#* ( ˄ → ^ ) MODIFIER LETTER UP ARROWHEAD → CIRCUMFLEX ACCENT\t# \n02C6 ;\t005E ;\tMA\t# ( ˆ → ^ ) MODIFIER LETTER CIRCUMFLEX ACCENT → CIRCUMFLEX ACCENT\t# \n\nA67E ;\t02C7 ;\tMA\t#* ( ꙾ → ˇ ) CYRILLIC KAVYKA → CARON\t# →˘→\n02D8 ;\t02C7 ;\tMA\t#* ( ˘ → ˇ ) BREVE → CARON\t# \n\n203E ;\t02C9 ;\tMA\t#* ( ‾ → ˉ ) OVERLINE → MODIFIER LETTER MACRON\t# \nFE49 ;\t02C9 ;\tMA\t#* ( ﹉ → ˉ ) DASHED OVERLINE → MODIFIER LETTER MACRON\t# →‾→\nFE4A ;\t02C9 ;\tMA\t#* ( ﹊ → ˉ ) CENTRELINE OVERLINE → MODIFIER LETTER MACRON\t# →‾→\nFE4B ;\t02C9 ;\tMA\t#* ( ﹋ → ˉ ) WAVY OVERLINE → MODIFIER LETTER MACRON\t# →‾→\nFE4C ;\t02C9 ;\tMA\t#* ( ﹌ → ˉ ) DOUBLE WAVY OVERLINE → MODIFIER LETTER MACRON\t# →‾→\n00AF ;\t02C9 ;\tMA\t#* ( ¯ → ˉ ) MACRON → MODIFIER LETTER MACRON\t# \nFFE3 ;\t02C9 ;\tMA\t#* ( ￣ → ˉ ) FULLWIDTH MACRON → MODIFIER LETTER MACRON\t# →‾→\n2594 ;\t02C9 ;\tMA\t#* ( ▔ → ˉ ) UPPER ONE EIGHTH BLOCK → MODIFIER LETTER MACRON\t# →¯→\n\n044A ;\t02C9 0062 ;\tMA\t# ( ъ → ˉb ) CYRILLIC SMALL LETTER HARD SIGN → MODIFIER LETTER MACRON, LATIN SMALL LETTER B\t# →¯b→\n\nA651 ;\t02C9 0062 0069 ;\tMA\t# ( ꙑ → ˉbi ) CYRILLIC SMALL LETTER YERU WITH BACK YER → MODIFIER LETTER MACRON, LATIN SMALL LETTER B, LATIN SMALL LETTER I\t# →ъı→\n\n0375 ;\t02CF ;\tMA\t#* ( ͵ → ˏ ) GREEK LOWER NUMERAL SIGN → MODIFIER LETTER LOW ACUTE ACCENT\t# \n\n02FB ;\t02EA ;\tMA\t#* ( ˻ → ˪ ) MODIFIER LETTER BEGIN LOW TONE → MODIFIER LETTER YIN DEPARTING TONE MARK\t# \nA716 ;\t02EA ;\tMA\t#* ( ꜖ → ˪ ) MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR → MODIFIER LETTER YIN DEPARTING TONE MARK\t# \n\nA714 ;\t02EB ;\tMA\t#* ( ꜔ → ˫ ) MODIFIER LETTER MID LEFT-STEM TONE BAR → MODIFIER LETTER YANG DEPARTING TONE MARK\t# \n\n3002 ;\t02F3 ;\tMA\t#* ( 。 → ˳ ) IDEOGRAPHIC FULL STOP → MODIFIER LETTER LOW RING\t# \n\n2E30 ;\t00B0 ;\tMA\t#* ( ⸰ → ° ) RING POINT → DEGREE SIGN\t# →∘→\n02DA ;\t00B0 ;\tMA\t#* ( ˚ → ° ) RING ABOVE → DEGREE SIGN\t# \n2218 ;\t00B0 ;\tMA\t#* ( ∘ → ° ) RING OPERATOR → DEGREE SIGN\t# \n25CB ;\t00B0 ;\tMA\t#* ( ○ → ° ) WHITE CIRCLE → DEGREE SIGN\t# →◦→→∘→\n25E6 ;\t00B0 ;\tMA\t#* ( ◦ → ° ) WHITE BULLET → DEGREE SIGN\t# →∘→\n\n235C ;\t00B0 0332 ;\tMA\t#* ( ⍜ → °̲ ) APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR → DEGREE SIGN, COMBINING LOW LINE\t# →○̲→\n10ED0 ;\t00B0 0332 ;\tMA\t#* ( 𐻐 → °̲ ) ARABIC BIBLICAL END OF VERSE → DEGREE SIGN, COMBINING LOW LINE\t# →⍜→→○̲→\n\n2364 ;\t00B0 0308 ;\tMA\t#* ( ⍤ → °̈ ) APL FUNCTIONAL SYMBOL JOT DIAERESIS → DEGREE SIGN, COMBINING DIAERESIS\t# →◦̈→→∘̈→\n\n2103 ;\t00B0 0043 ;\tMA\t#* ( ℃ → °C ) DEGREE CELSIUS → DEGREE SIGN, LATIN CAPITAL LETTER C\t# \n\n2109 ;\t00B0 0046 ;\tMA\t#* ( ℉ → °F ) DEGREE FAHRENHEIT → DEGREE SIGN, LATIN CAPITAL LETTER F\t# \n\n0BF5 ;\t0BF3 ;\tMA\t#* ( ௵ → ௳ ) TAMIL YEAR SIGN → TAMIL DAY SIGN\t# \n\n0F1B ;\t0F1A 0F1A ;\tMA\t#* ( ༛ → ༚༚ ) TIBETAN SIGN RDEL DKAR GNYIS → TIBETAN SIGN RDEL DKAR GCIG, TIBETAN SIGN RDEL DKAR GCIG\t# \n\n0F1F ;\t0F1A 0F1D ;\tMA\t#* ( ༟ → ༚༝ ) TIBETAN SIGN RDEL DKAR RDEL NAG → TIBETAN SIGN RDEL DKAR GCIG, TIBETAN SIGN RDEL NAG GCIG\t# \n\n0FCE ;\t0F1D 0F1A ;\tMA\t#* ( ࿎ → ༝༚ ) TIBETAN SIGN RDEL NAG RDEL DKAR → TIBETAN SIGN RDEL NAG GCIG, TIBETAN SIGN RDEL DKAR GCIG\t# \n\n0F1E ;\t0F1D 0F1D ;\tMA\t#* ( ༞ → ༝༝ ) TIBETAN SIGN RDEL NAG GNYIS → TIBETAN SIGN RDEL NAG GCIG, TIBETAN SIGN RDEL NAG GCIG\t# \n\n24B8 ;\t00A9 ;\tMA\t#* ( Ⓒ → © ) CIRCLED LATIN CAPITAL LETTER C → COPYRIGHT SIGN\t# \n\n24C7 ;\t00AE ;\tMA\t#* ( Ⓡ → ® ) CIRCLED LATIN CAPITAL LETTER R → REGISTERED SIGN\t# \n\n24C5 ;\t2117 ;\tMA\t#* ( Ⓟ → ℗ ) CIRCLED LATIN CAPITAL LETTER P → SOUND RECORDING COPYRIGHT\t# \n\n1D21B ;\t2144 ;\tMA\t#* ( 𝈛 → ⅄ ) GREEK VOCAL NOTATION SYMBOL-53 → TURNED SANS-SERIF CAPITAL Y\t# \n\n2BEC ;\t219E ;\tMA\t#* ( ⯬ → ↞ ) LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS → LEFTWARDS TWO HEADED ARROW\t# \n\n2BED ;\t219F ;\tMA\t#* ( ⯭ → ↟ ) UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS → UPWARDS TWO HEADED ARROW\t# \n\n2BEE ;\t21A0 ;\tMA\t#* ( ⯮ → ↠ ) RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS → RIGHTWARDS TWO HEADED ARROW\t# \n\n2BEF ;\t21A1 ;\tMA\t#* ( ⯯ → ↡ ) DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS → DOWNWARDS TWO HEADED ARROW\t# \n\n21B5 ;\t21B2 ;\tMA\t#* ( ↵ → ↲ ) DOWNWARDS ARROW WITH CORNER LEFTWARDS → DOWNWARDS ARROW WITH TIP LEFTWARDS\t# \n\n2965 ;\t21C3 21C2 ;\tMA\t#* ( ⥥ → ⇃⇂ ) DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT → DOWNWARDS HARPOON WITH BARB LEFTWARDS, DOWNWARDS HARPOON WITH BARB RIGHTWARDS\t# \n\n296F ;\t21C3 16DA ;\tMA\t#* ( ⥯ → ⇃ᛚ ) DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT → DOWNWARDS HARPOON WITH BARB LEFTWARDS, RUNIC LETTER LAUKAZ LAGU LOGR L\t# →⇃↾→\n\n1D6DB ;\t2202 ;\tMA\t#* ( 𝛛 → ∂ ) MATHEMATICAL BOLD PARTIAL DIFFERENTIAL → PARTIAL DIFFERENTIAL\t# \n1D715 ;\t2202 ;\tMA\t#* ( 𝜕 → ∂ ) MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL → PARTIAL DIFFERENTIAL\t# \n1D74F ;\t2202 ;\tMA\t#* ( 𝝏 → ∂ ) MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL → PARTIAL DIFFERENTIAL\t# \n1D789 ;\t2202 ;\tMA\t#* ( 𝞉 → ∂ ) MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL → PARTIAL DIFFERENTIAL\t# \n1D7C3 ;\t2202 ;\tMA\t#* ( 𝟃 → ∂ ) MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL → PARTIAL DIFFERENTIAL\t# \n1E8CC ;\t2202 ;\tMA\t#* ( ‎𞣌‎ → ∂ ) MENDE KIKAKUI DIGIT SIX → PARTIAL DIFFERENTIAL\t# \n\n1E8CD ;\t2202 0335 ;\tMA\t#* ( ‎𞣍‎ → ∂̵ ) MENDE KIKAKUI DIGIT SEVEN → PARTIAL DIFFERENTIAL, COMBINING SHORT STROKE OVERLAY\t# →ð→\n00F0 ;\t2202 0335 ;\tMA\t# ( ð → ∂̵ ) LATIN SMALL LETTER ETH → PARTIAL DIFFERENTIAL, COMBINING SHORT STROKE OVERLAY\t# \n\n2300 ;\t2205 ;\tMA\t#* ( ⌀ → ∅ ) DIAMETER SIGN → EMPTY SET\t# \n\n1D6C1 ;\t2207 ;\tMA\t#* ( 𝛁 → ∇ ) MATHEMATICAL BOLD NABLA → NABLA\t# \n1D6FB ;\t2207 ;\tMA\t#* ( 𝛻 → ∇ ) MATHEMATICAL ITALIC NABLA → NABLA\t# \n1D735 ;\t2207 ;\tMA\t#* ( 𝜵 → ∇ ) MATHEMATICAL BOLD ITALIC NABLA → NABLA\t# \n1D76F ;\t2207 ;\tMA\t#* ( 𝝯 → ∇ ) MATHEMATICAL SANS-SERIF BOLD NABLA → NABLA\t# \n1D7A9 ;\t2207 ;\tMA\t#* ( 𝞩 → ∇ ) MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA → NABLA\t# \n118A8 ;\t2207 ;\tMA\t# ( 𑢨 → ∇ ) WARANG CITI CAPITAL LETTER E → NABLA\t# \n\n2362 ;\t2207 0308 ;\tMA\t#* ( ⍢ → ∇̈ ) APL FUNCTIONAL SYMBOL DEL DIAERESIS → NABLA, COMBINING DIAERESIS\t# \n\n236B ;\t2207 0334 ;\tMA\t#* ( ⍫ → ∇̴ ) APL FUNCTIONAL SYMBOL DEL TILDE → NABLA, COMBINING TILDE OVERLAY\t# \n\n2588 ;\t220E ;\tMA\t#* ( █ → ∎ ) FULL BLOCK → END OF PROOF\t# →■→\n25A0 ;\t220E ;\tMA\t#* ( ■ → ∎ ) BLACK SQUARE → END OF PROOF\t# \n\n2A3F ;\t2210 ;\tMA\t#* ( ⨿ → ∐ ) AMALGAMATION OR COPRODUCT → N-ARY COPRODUCT\t# \n\n16ED ;\t002B ;\tMA\t#* ( ᛭ → + ) RUNIC CROSS PUNCTUATION → PLUS SIGN\t# \n2795 ;\t002B ;\tMA\t#* ( ➕ → + ) HEAVY PLUS SIGN → PLUS SIGN\t# \n1029B ;\t002B ;\tMA\t# ( 𐊛 → + ) LYCIAN LETTER H → PLUS SIGN\t# \n1E6E9 ;\t002B ;\tMA\t# ( 𞛩 → + ) TAI YO LETTER IA → PLUS SIGN\t# \n\n2A23 ;\t002B 0302 ;\tMA\t#* ( ⨣ → +̂ ) PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE → PLUS SIGN, COMBINING CIRCUMFLEX ACCENT\t# \n\n2A22 ;\t002B 030A ;\tMA\t#* ( ⨢ → +̊ ) PLUS SIGN WITH SMALL CIRCLE ABOVE → PLUS SIGN, COMBINING RING ABOVE\t# \n\n2A24 ;\t002B 0303 ;\tMA\t#* ( ⨤ → +̃ ) PLUS SIGN WITH TILDE ABOVE → PLUS SIGN, COMBINING TILDE\t# \n\n2214 ;\t002B 0307 ;\tMA\t#* ( ∔ → +̇ ) DOT PLUS → PLUS SIGN, COMBINING DOT ABOVE\t# \n\n2A25 ;\t002B 0323 ;\tMA\t#* ( ⨥ → +̣ ) PLUS SIGN WITH DOT BELOW → PLUS SIGN, COMBINING DOT BELOW\t# \n\n2A26 ;\t002B 0330 ;\tMA\t#* ( ⨦ → +̰ ) PLUS SIGN WITH TILDE BELOW → PLUS SIGN, COMBINING TILDE BELOW\t# \n\n2A27 ;\t002B 2082 ;\tMA\t#* ( ⨧ → +₂ ) PLUS SIGN WITH SUBSCRIPT TWO → PLUS SIGN, SUBSCRIPT TWO\t# \n\n2797 ;\t00F7 ;\tMA\t#* ( ➗ → ÷ ) HEAVY DIVISION SIGN → DIVISION SIGN\t# \n\n2039 ;\t003C ;\tMA\t#* ( ‹ → < ) SINGLE LEFT-POINTING ANGLE QUOTATION MARK → LESS-THAN SIGN\t# \n276E ;\t003C ;\tMA\t#* ( ❮ → < ) HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT → LESS-THAN SIGN\t# →‹→\n02C2 ;\t003C ;\tMA\t#* ( ˂ → < ) MODIFIER LETTER LEFT ARROWHEAD → LESS-THAN SIGN\t# \n1D236 ;\t003C ;\tMA\t#* ( 𝈶 → < ) GREEK INSTRUMENTAL NOTATION SYMBOL-40 → LESS-THAN SIGN\t# \n1438 ;\t003C ;\tMA\t# ( ᐸ → < ) CANADIAN SYLLABICS PA → LESS-THAN SIGN\t# \n16B2 ;\t003C ;\tMA\t# ( ᚲ → < ) RUNIC LETTER KAUNA → LESS-THAN SIGN\t# \n\n22D6 ;\t003C 00B7 ;\tMA\t#* ( ⋖ → <· ) LESS-THAN WITH DOT → LESS-THAN SIGN, MIDDLE DOT\t# →ᑅ→→ᐸᐧ→\n2CB5 ;\t003C 00B7 ;\tMA\t# ( ⲵ → <· ) COPTIC SMALL LETTER OLD COPTIC AIN → LESS-THAN SIGN, MIDDLE DOT\t# →⋖→→ᑅ→→ᐸᐧ→\n2CB4 ;\t003C 00B7 ;\tMA\t# ( Ⲵ → <· ) COPTIC CAPITAL LETTER OLD COPTIC AIN → LESS-THAN SIGN, MIDDLE DOT\t# →ᑅ→→ᐸᐧ→\n1445 ;\t003C 00B7 ;\tMA\t# ( ᑅ → <· ) CANADIAN SYLLABICS WEST-CREE PWA → LESS-THAN SIGN, MIDDLE DOT\t# →ᐸᐧ→\n\n226A ;\t003C 003C ;\tMA\t#* ( ≪ → << ) MUCH LESS-THAN → LESS-THAN SIGN, LESS-THAN SIGN\t# \n\n22D8 ;\t003C 003C 003C ;\tMA\t#* ( ⋘ → <<< ) VERY MUCH LESS-THAN → LESS-THAN SIGN, LESS-THAN SIGN, LESS-THAN SIGN\t# \n\n1400 ;\t003D ;\tMA\t#* ( ᐀ → = ) CANADIAN SYLLABICS HYPHEN → EQUALS SIGN\t# \n2E40 ;\t003D ;\tMA\t#* ( ⹀ → = ) DOUBLE HYPHEN → EQUALS SIGN\t# \n30A0 ;\t003D ;\tMA\t#* ( ゠ → = ) KATAKANA-HIRAGANA DOUBLE HYPHEN → EQUALS SIGN\t# \nA4FF ;\t003D ;\tMA\t#* ( ꓿ → = ) LISU PUNCTUATION FULL STOP → EQUALS SIGN\t# \n\n225A ;\t003D 0306 ;\tMA\t#* ( ≚ → =̆ ) EQUIANGULAR TO → EQUALS SIGN, COMBINING BREVE\t# →=̌→\n\n2259 ;\t003D 0302 ;\tMA\t#* ( ≙ → =̂ ) ESTIMATES → EQUALS SIGN, COMBINING CIRCUMFLEX ACCENT\t# \n\n2257 ;\t003D 030A ;\tMA\t#* ( ≗ → =̊ ) RING EQUAL TO → EQUALS SIGN, COMBINING RING ABOVE\t# \n\n2250 ;\t003D 0307 ;\tMA\t#* ( ≐ → =̇ ) APPROACHES THE LIMIT → EQUALS SIGN, COMBINING DOT ABOVE\t# \n\n2251 ;\t003D 0307 0323 ;\tMA\t#* ( ≑ → =̣̇ ) GEOMETRICALLY EQUAL TO → EQUALS SIGN, COMBINING DOT ABOVE, COMBINING DOT BELOW\t# →≐̣→\n\n2B96 ;\t003D 1AB2 ;\tMA\t#* ( ⮖ → =᪲ ) EQUALS SIGN WITH INFINITY ABOVE → EQUALS SIGN, COMBINING INFINITY\t# \n\n2A6E ;\t003D 20F0 ;\tMA\t#* ( ⩮ → =⃰ ) EQUALS WITH ASTERISK → EQUALS SIGN, COMBINING ASTERISK ABOVE\t# \n\n2A75 ;\t003D 003D ;\tMA\t#* ( ⩵ → == ) TWO CONSECUTIVE EQUALS SIGNS → EQUALS SIGN, EQUALS SIGN\t# \n\n2A76 ;\t003D 003D 003D ;\tMA\t#* ( ⩶ → === ) THREE CONSECUTIVE EQUALS SIGNS → EQUALS SIGN, EQUALS SIGN, EQUALS SIGN\t# \n\n225E ;\t003D 036B ;\tMA\t#* ( ≞ → =ͫ ) MEASURED BY → EQUALS SIGN, COMBINING LATIN SMALL LETTER M\t# \n\n203A ;\t003E ;\tMA\t#* ( › → > ) SINGLE RIGHT-POINTING ANGLE QUOTATION MARK → GREATER-THAN SIGN\t# \n276F ;\t003E ;\tMA\t#* ( ❯ → > ) HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT → GREATER-THAN SIGN\t# →›→\n02C3 ;\t003E ;\tMA\t#* ( ˃ → > ) MODIFIER LETTER RIGHT ARROWHEAD → GREATER-THAN SIGN\t# \n1D237 ;\t003E ;\tMA\t#* ( 𝈷 → > ) GREEK INSTRUMENTAL NOTATION SYMBOL-42 → GREATER-THAN SIGN\t# \n1433 ;\t003E ;\tMA\t# ( ᐳ → > ) CANADIAN SYLLABICS PO → GREATER-THAN SIGN\t# \n16F3F ;\t003E ;\tMA\t# ( 𖼿 → > ) MIAO LETTER ARCHAIC ZZA → GREATER-THAN SIGN\t# \n\n1441 ;\t003E 00B7 ;\tMA\t# ( ᑁ → >· ) CANADIAN SYLLABICS WEST-CREE PWO → GREATER-THAN SIGN, MIDDLE DOT\t# →ᐳᐧ→\n\n2AA5 ;\t003E 003C ;\tMA\t#* ( ⪥ → >< ) GREATER-THAN BESIDE LESS-THAN → GREATER-THAN SIGN, LESS-THAN SIGN\t# \n\n226B ;\t003E 003E ;\tMA\t#* ( ≫ → >> ) MUCH GREATER-THAN → GREATER-THAN SIGN, GREATER-THAN SIGN\t# \n2A20 ;\t003E 003E ;\tMA\t#* ( ⨠ → >> ) Z NOTATION SCHEMA PIPING → GREATER-THAN SIGN, GREATER-THAN SIGN\t# →≫→\n\n22D9 ;\t003E 003E 003E ;\tMA\t#* ( ⋙ → >>> ) VERY MUCH GREATER-THAN → GREATER-THAN SIGN, GREATER-THAN SIGN, GREATER-THAN SIGN\t# \n\n2053 ;\t007E ;\tMA\t#* ( ⁓ → ~ ) SWUNG DASH → TILDE\t# \n02DC ;\t007E ;\tMA\t#* ( ˜ → ~ ) SMALL TILDE → TILDE\t# \n1FC0 ;\t007E ;\tMA\t#* ( ῀ → ~ ) GREEK PERISPOMENI → TILDE\t# →˜→\n223C ;\t007E ;\tMA\t#* ( ∼ → ~ ) TILDE OPERATOR → TILDE\t# \n\n2368 ;\t007E 0308 ;\tMA\t#* ( ⍨ → ~̈ ) APL FUNCTIONAL SYMBOL TILDE DIAERESIS → TILDE, COMBINING DIAERESIS\t# \n\n2E1E ;\t007E 0307 ;\tMA\t#* ( ⸞ → ~̇ ) TILDE WITH DOT ABOVE → TILDE, COMBINING DOT ABOVE\t# →⩪→→∼̇→→⁓̇→\n2A6A ;\t007E 0307 ;\tMA\t#* ( ⩪ → ~̇ ) TILDE OPERATOR WITH DOT ABOVE → TILDE, COMBINING DOT ABOVE\t# →∼̇→→⁓̇→\n\n2E1F ;\t007E 0323 ;\tMA\t#* ( ⸟ → ~̣ ) TILDE WITH DOT BELOW → TILDE, COMBINING DOT BELOW\t# \n\n1E8C8 ;\t2220 ;\tMA\t#* ( ‎𞣈‎ → ∠ ) MENDE KIKAKUI DIGIT TWO → ANGLE\t# \n\n22C0 ;\t2227 ;\tMA\t#* ( ⋀ → ∧ ) N-ARY LOGICAL AND → LOGICAL AND\t# \n\n222F ;\t222E 222E ;\tMA\t#* ( ∯ → ∮∮ ) SURFACE INTEGRAL → CONTOUR INTEGRAL, CONTOUR INTEGRAL\t# \n\n2230 ;\t222E 222E 222E ;\tMA\t#* ( ∰ → ∮∮∮ ) VOLUME INTEGRAL → CONTOUR INTEGRAL, CONTOUR INTEGRAL, CONTOUR INTEGRAL\t# \n\n2E2B ;\t2234 ;\tMA\t#* ( ⸫ → ∴ ) ONE DOT OVER TWO DOTS PUNCTUATION → THEREFORE\t# \n\n2E2A ;\t2235 ;\tMA\t#* ( ⸪ → ∵ ) TWO DOTS OVER ONE DOT PUNCTUATION → BECAUSE\t# \n\n2E2C ;\t2237 ;\tMA\t#* ( ⸬ → ∷ ) SQUARED FOUR DOT PUNCTUATION → PROPORTION\t# \n\n111DE ;\t2248 ;\tMA\t#* ( 𑇞 → ≈ ) SHARADA SECTION MARK-1 → ALMOST EQUAL TO\t# \n\n264E ;\t224F ;\tMA\t#* ( ♎ → ≏ ) LIBRA → DIFFERENCE BETWEEN\t# \n1F75E ;\t224F ;\tMA\t#* ( 🝞 → ≏ ) ALCHEMICAL SYMBOL FOR SUBLIMATION → DIFFERENCE BETWEEN\t# →♎→\n\n2263 ;\t2261 ;\tMA\t#* ( ≣ → ≡ ) STRICTLY EQUIVALENT TO → IDENTICAL TO\t# \n2CB7 ;\t2261 ;\tMA\t# ( ⲷ → ≡ ) COPTIC SMALL LETTER CRYPTOGRAMMIC EIE → IDENTICAL TO\t# \n\n2A03 ;\t228D ;\tMA\t#* ( ⨃ → ⊍ ) N-ARY UNION OPERATOR WITH DOT → MULTISET MULTIPLICATION\t# \n\n2A04 ;\t228E ;\tMA\t#* ( ⨄ → ⊎ ) N-ARY UNION OPERATOR WITH PLUS → MULTISET UNION\t# \n\n1D238 ;\t228F ;\tMA\t#* ( 𝈸 → ⊏ ) GREEK INSTRUMENTAL NOTATION SYMBOL-43 → SQUARE IMAGE OF\t# \n\n1D239 ;\t2290 ;\tMA\t#* ( 𝈹 → ⊐ ) GREEK INSTRUMENTAL NOTATION SYMBOL-45 → SQUARE ORIGINAL OF\t# \n\n2A05 ;\t2293 ;\tMA\t#* ( ⨅ → ⊓ ) N-ARY SQUARE INTERSECTION OPERATOR → SQUARE CAP\t# \n\n2A06 ;\t2294 ;\tMA\t#* ( ⨆ → ⊔ ) N-ARY SQUARE UNION OPERATOR → SQUARE CUP\t# \n\n2A02 ;\t2297 ;\tMA\t#* ( ⨂ → ⊗ ) N-ARY CIRCLED TIMES OPERATOR → CIRCLED TIMES\t# \n\n235F ;\t229B ;\tMA\t#* ( ⍟ → ⊛ ) APL FUNCTIONAL SYMBOL CIRCLE STAR → CIRCLED ASTERISK OPERATOR\t# \n\n1F771 ;\t22A0 ;\tMA\t#* ( 🝱 → ⊠ ) ALCHEMICAL SYMBOL FOR MONTH → SQUARED TIMES\t# \n\n1F755 ;\t22A1 ;\tMA\t#* ( 🝕 → ⊡ ) ALCHEMICAL SYMBOL FOR URINE → SQUARED DOT OPERATOR\t# \n\n25C1 ;\t22B2 ;\tMA\t#* ( ◁ → ⊲ ) WHITE LEFT-POINTING TRIANGLE → NORMAL SUBGROUP OF\t# \n\n25B7 ;\t22B3 ;\tMA\t#* ( ▷ → ⊳ ) WHITE RIGHT-POINTING TRIANGLE → CONTAINS AS NORMAL SUBGROUP\t# \n\n2363 ;\t22C6 0308 ;\tMA\t#* ( ⍣ → ⋆̈ ) APL FUNCTIONAL SYMBOL STAR DIAERESIS → STAR OPERATOR, COMBINING DIAERESIS\t# \n\nFE34 ;\t2307 ;\tMA\t# ( ︴ → ⌇ ) PRESENTATION FORM FOR VERTICAL WAVY LOW LINE → WAVY LINE\t# \n\n25E0 ;\t2312 ;\tMA\t#* ( ◠ → ⌒ ) UPPER HALF CIRCLE → ARC\t# \n\n2A3D ;\t2319 ;\tMA\t#* ( ⨽ → ⌙ ) RIGHTHAND INTERIOR PRODUCT → TURNED NOT SIGN\t# \n\n2325 ;\t2324 ;\tMA\t#* ( ⌥ → ⌤ ) OPTION KEY → UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS\t# \n\n29C7 ;\t233B ;\tMA\t#* ( ⧇ → ⌻ ) SQUARED SMALL CIRCLE → APL FUNCTIONAL SYMBOL QUAD JOT\t# \n\n25CE ;\t233E ;\tMA\t#* ( ◎ → ⌾ ) BULLSEYE → APL FUNCTIONAL SYMBOL CIRCLE JOT\t# →⦾→\n29BE ;\t233E ;\tMA\t#* ( ⦾ → ⌾ ) CIRCLED WHITE BULLET → APL FUNCTIONAL SYMBOL CIRCLE JOT\t# \n\n29C5 ;\t2342 ;\tMA\t#* ( ⧅ → ⍂ ) SQUARED FALLING DIAGONAL SLASH → APL FUNCTIONAL SYMBOL QUAD BACKSLASH\t# \n\n29B0 ;\t2349 ;\tMA\t#* ( ⦰ → ⍉ ) REVERSED EMPTY SET → APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH\t# \n\n23C3 ;\t234B ;\tMA\t#* ( ⏃ → ⍋ ) DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE → APL FUNCTIONAL SYMBOL DELTA STILE\t# \n\n23C2 ;\t234E ;\tMA\t#* ( ⏂ → ⍎ ) DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE → APL FUNCTIONAL SYMBOL DOWN TACK JOT\t# \n\n23C1 ;\t2355 ;\tMA\t#* ( ⏁ → ⍕ ) DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE → APL FUNCTIONAL SYMBOL UP TACK JOT\t# \n\n23C6 ;\t236D ;\tMA\t#* ( ⏆ → ⍭ ) DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE → APL FUNCTIONAL SYMBOL STILE TILDE\t# \n\n2638 ;\t2388 ;\tMA\t#* ( ☸ → ⎈ ) WHEEL OF DHARMA → HELM SYMBOL\t# \n\nFE35 ;\t23DC ;\tMA\t#* ( ︵ → ⏜ ) PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS → TOP PARENTHESIS\t# \n\nFE36 ;\t23DD ;\tMA\t#* ( ︶ → ⏝ ) PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS → BOTTOM PARENTHESIS\t# \n\nFE37 ;\t23DE ;\tMA\t#* ( ︷ → ⏞ ) PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET → TOP CURLY BRACKET\t# \n\nFE38 ;\t23DF ;\tMA\t#* ( ︸ → ⏟ ) PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET → BOTTOM CURLY BRACKET\t# \n\nFE39 ;\t23E0 ;\tMA\t#* ( ︹ → ⏠ ) PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET → TOP TORTOISE SHELL BRACKET\t# \n\nFE3A ;\t23E1 ;\tMA\t#* ( ︺ → ⏡ ) PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET → BOTTOM TORTOISE SHELL BRACKET\t# \n\n25B1 ;\t23E5 ;\tMA\t#* ( ▱ → ⏥ ) WHITE PARALLELOGRAM → FLATNESS\t# \n\n23FC ;\t23FB ;\tMA\t#* ( ⏼ → ⏻ ) POWER ON-OFF SYMBOL → POWER SYMBOL\t# \n\nFE31 ;\t2502 ;\tMA\t#* ( ︱ → │ ) PRESENTATION FORM FOR VERTICAL EM DASH → BOX DRAWINGS LIGHT VERTICAL\t# →｜→\nFF5C ;\t2502 ;\tMA\t#* ( ｜ → │ ) FULLWIDTH VERTICAL LINE → BOX DRAWINGS LIGHT VERTICAL\t# \n2503 ;\t2502 ;\tMA\t#* ( ┃ → │ ) BOX DRAWINGS HEAVY VERTICAL → BOX DRAWINGS LIGHT VERTICAL\t# \n\n250F ;\t250C ;\tMA\t#* ( ┏ → ┌ ) BOX DRAWINGS HEAVY DOWN AND RIGHT → BOX DRAWINGS LIGHT DOWN AND RIGHT\t# \n\n2523 ;\t251C ;\tMA\t#* ( ┣ → ├ ) BOX DRAWINGS HEAVY VERTICAL AND RIGHT → BOX DRAWINGS LIGHT VERTICAL AND RIGHT\t# \n\n2590 ;\t258C ;\tMA\t#* ( ▐ → ▌ ) RIGHT HALF BLOCK → LEFT HALF BLOCK\t# \n\n2597 ;\t2596 ;\tMA\t#* ( ▗ → ▖ ) QUADRANT LOWER RIGHT → QUADRANT LOWER LEFT\t# \n\n259D ;\t2598 ;\tMA\t#* ( ▝ → ▘ ) QUADRANT UPPER RIGHT → QUADRANT UPPER LEFT\t# \n\n2610 ;\t25A1 ;\tMA\t#* ( ☐ → □ ) BALLOT BOX → WHITE SQUARE\t# \n\nFFED ;\t25AA ;\tMA\t#* ( ￭ → ▪ ) HALFWIDTH BLACK SQUARE → BLACK SMALL SQUARE\t# \n\n25B8 ;\t25B6 ;\tMA\t#* ( ▸ → ▶ ) BLACK RIGHT-POINTING SMALL TRIANGLE → BLACK RIGHT-POINTING TRIANGLE\t# →►→\n25BA ;\t25B6 ;\tMA\t#* ( ► → ▶ ) BLACK RIGHT-POINTING POINTER → BLACK RIGHT-POINTING TRIANGLE\t# \n\n2CE9 ;\t2627 ;\tMA\t#* ( ⳩ → ☧ ) COPTIC SYMBOL KHI RO → CHI RHO\t# \n\n1F70A ;\t2629 ;\tMA\t#* ( 🜊 → ☩ ) ALCHEMICAL SYMBOL FOR VINEGAR → CROSS OF JERUSALEM\t# \n\n1F312 ;\t263D ;\tMA\t#* ( 🌒 → ☽ ) WAXING CRESCENT MOON SYMBOL → FIRST QUARTER MOON\t# \n1F319 ;\t263D ;\tMA\t#* ( 🌙 → ☽ ) CRESCENT MOON → FIRST QUARTER MOON\t# \n\n23FE ;\t263E ;\tMA\t#* ( ⏾ → ☾ ) POWER SLEEP SYMBOL → LAST QUARTER MOON\t# \n1F318 ;\t263E ;\tMA\t#* ( 🌘 → ☾ ) WANING CRESCENT MOON SYMBOL → LAST QUARTER MOON\t# \n\n29D9 ;\t299A ;\tMA\t#* ( ⧙ → ⦚ ) RIGHT WIGGLY FENCE → VERTICAL ZIGZAG LINE\t# \n\n1F73A ;\t29DF ;\tMA\t#* ( 🜺 → ⧟ ) ALCHEMICAL SYMBOL FOR ARSENIC → DOUBLE-ENDED MULTIMAP\t# \n\n2A3E ;\t2A1F ;\tMA\t#* ( ⨾ → ⨟ ) Z NOTATION RELATIONAL COMPOSITION → Z NOTATION SCHEMA COMPOSITION\t# \n\n2669 ;\t1D158 1D165 ;\tMA\t#* ( ♩ → 𝅘𝅥 ) QUARTER NOTE → MUSICAL SYMBOL NOTEHEAD BLACK, MUSICAL SYMBOL COMBINING STEM\t# \n\n266A ;\t1D158 1D165 1D16E ;\tMA\t#* ( ♪ → 𝅘𝅥𝅮 ) EIGHTH NOTE → MUSICAL SYMBOL NOTEHEAD BLACK, MUSICAL SYMBOL COMBINING STEM, MUSICAL SYMBOL COMBINING FLAG-1\t# \n\n24EA ;\t1F10D ;\tMA\t#* ( ⓪ → 🄍 ) CIRCLED DIGIT ZERO → CIRCLED ZERO WITH SLASH\t# \n\n21BA ;\t1F10E ;\tMA\t#* ( ↺ → 🄎 ) ANTICLOCKWISE OPEN CIRCLE ARROW → CIRCLED ANTICLOCKWISE ARROW\t# \n\n1CCFB ;\t1F6F8 ;\tMA\t#* ( 𜳻 → 🛸 ) FLYING SAUCER SYMBOL → FLYING SAUCER\t# \n\n02D9 ;\t0971 ;\tMA\t#* ( ˙ → ॱ ) DOT ABOVE → DEVANAGARI SIGN HIGH SPACING DOT\t# \n0D4E ;\t0971 ;\tMA\t# ( ൎ → ॱ ) MALAYALAM LETTER DOT REPH → DEVANAGARI SIGN HIGH SPACING DOT\t# →˙→\n\nFF0D ;\t30FC ;\tMA\t#* ( － → ー ) FULLWIDTH HYPHEN-MINUS → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# \n2014 ;\t30FC ;\tMA\t#* ( — → ー ) EM DASH → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →一→\n2015 ;\t30FC ;\tMA\t#* ( ― → ー ) HORIZONTAL BAR → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →—→→一→\n2500 ;\t30FC ;\tMA\t#* ( ─ → ー ) BOX DRAWINGS LIGHT HORIZONTAL → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →━→→—→→一→\n2501 ;\t30FC ;\tMA\t#* ( ━ → ー ) BOX DRAWINGS HEAVY HORIZONTAL → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →—→→一→\n31D0 ;\t30FC ;\tMA\t#* ( ㇐ → ー ) CJK STROKE H → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →一→\nA7F7 ;\t30FC ;\tMA\t# ( ꟷ → ー ) LATIN EPIGRAPHIC LETTER SIDEWAYS I → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →—→→一→\n1173 ;\t30FC ;\tMA\t# ( ᅳ → ー ) HANGUL JUNGSEONG EU → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →ㅡ→→—→→一→\n3161 ;\t30FC ;\tMA\t# ( ㅡ → ー ) HANGUL LETTER EU → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →—→→一→\n4E00 ;\t30FC ;\tMA\t# ( 一 → ー ) CJK UNIFIED IDEOGRAPH-4E00 → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# \n2F00 ;\t30FC ;\tMA\t#* ( ⼀ → ー ) KANGXI RADICAL ONE → KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →一→\n\n1196 ;\t30FC 30FC ;\tMA\t# ( ᆖ → ーー ) HANGUL JUNGSEONG EU-EU → KATAKANA-HIRAGANA PROLONGED SOUND MARK, KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →ᅳᅳ→\n\nD7B9 ;\t30FC 1161 ;\tMA\t# ( ힹ → ーᅡ ) HANGUL JUNGSEONG EU-A → KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL JUNGSEONG A\t# →ᅳᅡ→\n\nD7BA ;\t30FC 1165 ;\tMA\t# ( ힺ → ーᅥ ) HANGUL JUNGSEONG EU-EO → KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL JUNGSEONG EO\t# →ᅳᅥ→\n\nD7BB ;\t30FC 1165 4E28 ;\tMA\t# ( ힻ → ーᅥ丨 ) HANGUL JUNGSEONG EU-E → KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL JUNGSEONG EO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅳᅥᅵ→\n\nD7BC ;\t30FC 1169 ;\tMA\t# ( ힼ → ーᅩ ) HANGUL JUNGSEONG EU-O → KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL JUNGSEONG O\t# →ᅳᅩ→\n\n1195 ;\t30FC 116E ;\tMA\t# ( ᆕ → ーᅮ ) HANGUL JUNGSEONG EU-U → KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL JUNGSEONG U\t# →ᅳᅮ→\n\n1174 ;\t30FC 4E28 ;\tMA\t# ( ᅴ → ー丨 ) HANGUL JUNGSEONG YI → KATAKANA-HIRAGANA PROLONGED SOUND MARK, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅳᅵ→\n3162 ;\t30FC 4E28 ;\tMA\t# ( ㅢ → ー丨 ) HANGUL LETTER YI → KATAKANA-HIRAGANA PROLONGED SOUND MARK, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅴ→→ᅳᅵ→\n\n1197 ;\t30FC 4E28 116E ;\tMA\t# ( ᆗ → ー丨ᅮ ) HANGUL JUNGSEONG YI-U → KATAKANA-HIRAGANA PROLONGED SOUND MARK, CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG U\t# →ᅳᅵᅮ→\n\n1F10F ;\t0024 20E0 ;\tMA\t#* ( 🄏 → $⃠ ) CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH → DOLLAR SIGN, COMBINING ENCLOSING CIRCLE BACKSLASH\t# \n\n20A4 ;\t00A3 ;\tMA\t#* ( ₤ → £ ) LIRA SIGN → POUND SIGN\t# \n\n3012 ;\t20B8 ;\tMA\t#* ( 〒 → ₸ ) POSTAL MARK → TENGE SIGN\t# \n3036 ;\t20B8 ;\tMA\t#* ( 〶 → ₸ ) CIRCLED POSTAL MARK → TENGE SIGN\t# →〒→\n\n1B5C ;\t1B50 ;\tMA\t#* ( ᭜ → ᭐ ) BALINESE WINDU → BALINESE DIGIT ZERO\t# \n\nA9C6 ;\tA9D0 ;\tMA\t#* ( ꧆ → ꧐ ) JAVANESE PADA WINDU → JAVANESE DIGIT ZERO\t# \n\n114D1 ;\t09E7 ;\tMA\t# ( 𑓑 → ১ ) TIRHUTA DIGIT ONE → BENGALI DIGIT ONE\t# \n\n0CE7 ;\t0C67 ;\tMA\t# ( ೧ → ౧ ) KANNADA DIGIT ONE → TELUGU DIGIT ONE\t# \n\n1065 ;\t1041 ;\tMA\t# ( ၥ → ၁ ) MYANMAR LETTER WESTERN PWO KAREN THA → MYANMAR DIGIT ONE\t# \n\n2460 ;\t2780 ;\tMA\t#* ( ① → ➀ ) CIRCLED DIGIT ONE → DINGBAT CIRCLED SANS-SERIF DIGIT ONE\t# \n\n2469 ;\t2789 ;\tMA\t#* ( ⑩ → ➉ ) CIRCLED NUMBER TEN → DINGBAT CIRCLED SANS-SERIF NUMBER TEN\t# \n\n23E8 ;\t2081 2080 ;\tMA\t#* ( ⏨ → ₁₀ ) DECIMAL EXPONENT SYMBOL → SUBSCRIPT ONE, SUBSCRIPT ZERO\t# \n\n1CCF2 ;\t0032 ;\tMA\t# ( 𜳲 → 2 ) OUTLINED DIGIT TWO → DIGIT TWO\t# \n1D7D0 ;\t0032 ;\tMA\t# ( 𝟐 → 2 ) MATHEMATICAL BOLD DIGIT TWO → DIGIT TWO\t# \n1D7DA ;\t0032 ;\tMA\t# ( 𝟚 → 2 ) MATHEMATICAL DOUBLE-STRUCK DIGIT TWO → DIGIT TWO\t# \n1D7E4 ;\t0032 ;\tMA\t# ( 𝟤 → 2 ) MATHEMATICAL SANS-SERIF DIGIT TWO → DIGIT TWO\t# \n1D7EE ;\t0032 ;\tMA\t# ( 𝟮 → 2 ) MATHEMATICAL SANS-SERIF BOLD DIGIT TWO → DIGIT TWO\t# \n1D7F8 ;\t0032 ;\tMA\t# ( 𝟸 → 2 ) MATHEMATICAL MONOSPACE DIGIT TWO → DIGIT TWO\t# \n1FBF2 ;\t0032 ;\tMA\t# ( 🯲 → 2 ) SEGMENTED DIGIT TWO → DIGIT TWO\t# \nA75A ;\t0032 ;\tMA\t# ( Ꝛ → 2 ) LATIN CAPITAL LETTER R ROTUNDA → DIGIT TWO\t# \n01A7 ;\t0032 ;\tMA\t# ( Ƨ → 2 ) LATIN CAPITAL LETTER TONE TWO → DIGIT TWO\t# \n03E8 ;\t0032 ;\tMA\t# ( Ϩ → 2 ) COPTIC CAPITAL LETTER HORI → DIGIT TWO\t# →Ƨ→\nA644 ;\t0032 ;\tMA\t# ( Ꙅ → 2 ) CYRILLIC CAPITAL LETTER REVERSED DZE → DIGIT TWO\t# →Ƨ→\n14BF ;\t0032 ;\tMA\t# ( ᒿ → 2 ) CANADIAN SYLLABICS SAYISI M → DIGIT TWO\t# \nA6EF ;\t0032 ;\tMA\t# ( ꛯ → 2 ) BAMUM LETTER KOGHOM → DIGIT TWO\t# →Ƨ→\n\nA9CF ;\t0662 ;\tMA\t# ( ꧏ → ‎٢‎ ) JAVANESE PANGRANGKEP → ARABIC-INDIC DIGIT TWO\t# \n06F2 ;\t0662 ;\tMA\t# ( ۲ → ‎٢‎ ) EXTENDED ARABIC-INDIC DIGIT TWO → ARABIC-INDIC DIGIT TWO\t# \n\n0AE8 ;\t0968 ;\tMA\t# ( ૨ → २ ) GUJARATI DIGIT TWO → DEVANAGARI DIGIT TWO\t# \n0AB0 ;\t0968 ;\tMA\t# ( ર → २ ) GUJARATI LETTER RA → DEVANAGARI DIGIT TWO\t# →૨→\n\n114D2 ;\t09E8 ;\tMA\t# ( 𑓒 → ২ ) TIRHUTA DIGIT TWO → BENGALI DIGIT TWO\t# \n\n0CE8 ;\t0C68 ;\tMA\t# ( ೨ → ౨ ) KANNADA DIGIT TWO → TELUGU DIGIT TWO\t# \n\n2461 ;\t2781 ;\tMA\t#* ( ② → ➁ ) CIRCLED DIGIT TWO → DINGBAT CIRCLED SANS-SERIF DIGIT TWO\t# \n\n01BB ;\t0032 0335 ;\tMA\t# ( ƻ → 2̵ ) LATIN LETTER TWO WITH STROKE → DIGIT TWO, COMBINING SHORT STROKE OVERLAY\t# \n\n1F103 ;\t0032 002C ;\tMA\t#* ( 🄃 → 2, ) DIGIT TWO COMMA → DIGIT TWO, COMMA\t# \n\n2489 ;\t0032 002E ;\tMA\t#* ( ⒉ → 2. ) DIGIT TWO FULL STOP → DIGIT TWO, FULL STOP\t# \n\n33F5 ;\t0032 0032 65E5 ;\tMA\t#* ( ㏵ → 22日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO → DIGIT TWO, DIGIT TWO, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n336E ;\t0032 0032 70B9 ;\tMA\t#* ( ㍮ → 22点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO → DIGIT TWO, DIGIT TWO, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n33F6 ;\t0032 0033 65E5 ;\tMA\t#* ( ㏶ → 23日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE → DIGIT TWO, DIGIT THREE, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n336F ;\t0032 0033 70B9 ;\tMA\t#* ( ㍯ → 23点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE → DIGIT TWO, DIGIT THREE, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n33F7 ;\t0032 0034 65E5 ;\tMA\t#* ( ㏷ → 24日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR → DIGIT TWO, DIGIT FOUR, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n3370 ;\t0032 0034 70B9 ;\tMA\t#* ( ㍰ → 24点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR → DIGIT TWO, DIGIT FOUR, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n33F8 ;\t0032 0035 65E5 ;\tMA\t#* ( ㏸ → 25日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE → DIGIT TWO, DIGIT FIVE, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n33F9 ;\t0032 0036 65E5 ;\tMA\t#* ( ㏹ → 26日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX → DIGIT TWO, DIGIT SIX, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n33FA ;\t0032 0037 65E5 ;\tMA\t#* ( ㏺ → 27日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN → DIGIT TWO, DIGIT SEVEN, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n33FB ;\t0032 0038 65E5 ;\tMA\t#* ( ㏻ → 28日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT → DIGIT TWO, DIGIT EIGHT, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n33FC ;\t0032 0039 65E5 ;\tMA\t#* ( ㏼ → 29日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE → DIGIT TWO, DIGIT NINE, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n33F4 ;\t0032 006C 65E5 ;\tMA\t#* ( ㏴ → 2l日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE → DIGIT TWO, LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-65E5\t# →21日→\n\n336D ;\t0032 006C 70B9 ;\tMA\t#* ( ㍭ → 2l点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE → DIGIT TWO, LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-70B9\t# →21点→\n\n249B ;\t0032 004F 002E ;\tMA\t#* ( ⒛ → 2O. ) NUMBER TWENTY FULL STOP → DIGIT TWO, LATIN CAPITAL LETTER O, FULL STOP\t# →20.→\n\n33F3 ;\t0032 004F 65E5 ;\tMA\t#* ( ㏳ → 2O日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY → DIGIT TWO, LATIN CAPITAL LETTER O, CJK UNIFIED IDEOGRAPH-65E5\t# →20日→\n\n336C ;\t0032 004F 70B9 ;\tMA\t#* ( ㍬ → 2O点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY → DIGIT TWO, LATIN CAPITAL LETTER O, CJK UNIFIED IDEOGRAPH-70B9\t# →20点→\n\n0DE9 ;\t0DE8 0DCF ;\tMA\t# ( ෩ → ෨ා ) SINHALA LITH DIGIT THREE → SINHALA LITH DIGIT TWO, SINHALA VOWEL SIGN AELA-PILLA\t# \n\n0DEF ;\t0DE8 0DD3 ;\tMA\t# ( ෯ → ෨ී ) SINHALA LITH DIGIT NINE → SINHALA LITH DIGIT TWO, SINHALA VOWEL SIGN DIGA IS-PILLA\t# \n\n33E1 ;\t0032 65E5 ;\tMA\t#* ( ㏡ → 2日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO → DIGIT TWO, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n32C1 ;\t0032 6708 ;\tMA\t#* ( ㋁ → 2月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY → DIGIT TWO, CJK UNIFIED IDEOGRAPH-6708\t# \n\n335A ;\t0032 70B9 ;\tMA\t#* ( ㍚ → 2点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO → DIGIT TWO, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n1D206 ;\t0033 ;\tMA\t#* ( 𝈆 → 3 ) GREEK VOCAL NOTATION SYMBOL-7 → DIGIT THREE\t# \n0969 ;\t0033 ;\tMA\t# ( ३ → 3 ) DEVANAGARI DIGIT THREE → DIGIT THREE\t# →૩→\n0AE9 ;\t0033 ;\tMA\t# ( ૩ → 3 ) GUJARATI DIGIT THREE → DIGIT THREE\t# \n1CCF3 ;\t0033 ;\tMA\t# ( 𜳳 → 3 ) OUTLINED DIGIT THREE → DIGIT THREE\t# \n1D7D1 ;\t0033 ;\tMA\t# ( 𝟑 → 3 ) MATHEMATICAL BOLD DIGIT THREE → DIGIT THREE\t# \n1D7DB ;\t0033 ;\tMA\t# ( 𝟛 → 3 ) MATHEMATICAL DOUBLE-STRUCK DIGIT THREE → DIGIT THREE\t# \n1D7E5 ;\t0033 ;\tMA\t# ( 𝟥 → 3 ) MATHEMATICAL SANS-SERIF DIGIT THREE → DIGIT THREE\t# \n1D7EF ;\t0033 ;\tMA\t# ( 𝟯 → 3 ) MATHEMATICAL SANS-SERIF BOLD DIGIT THREE → DIGIT THREE\t# \n1D7F9 ;\t0033 ;\tMA\t# ( 𝟹 → 3 ) MATHEMATICAL MONOSPACE DIGIT THREE → DIGIT THREE\t# \n1FBF3 ;\t0033 ;\tMA\t# ( 🯳 → 3 ) SEGMENTED DIGIT THREE → DIGIT THREE\t# \nA7AB ;\t0033 ;\tMA\t# ( Ɜ → 3 ) LATIN CAPITAL LETTER REVERSED OPEN E → DIGIT THREE\t# \n021C ;\t0033 ;\tMA\t# ( Ȝ → 3 ) LATIN CAPITAL LETTER YOGH → DIGIT THREE\t# →Ʒ→\n01B7 ;\t0033 ;\tMA\t# ( Ʒ → 3 ) LATIN CAPITAL LETTER EZH → DIGIT THREE\t# \nA76A ;\t0033 ;\tMA\t# ( Ꝫ → 3 ) LATIN CAPITAL LETTER ET → DIGIT THREE\t# \n2C9C ;\t0033 ;\tMA\t# ( Ⲝ → 3 ) COPTIC CAPITAL LETTER KSI → DIGIT THREE\t# →Ʒ→\n2CC4 ;\t0033 ;\tMA\t# ( Ⳅ → 3 ) COPTIC CAPITAL LETTER OLD COPTIC SHEI → DIGIT THREE\t# →Ʒ→\n2CCC ;\t0033 ;\tMA\t# ( Ⳍ → 3 ) COPTIC CAPITAL LETTER OLD COPTIC HORI → DIGIT THREE\t# →Ȝ→→Ʒ→\n0417 ;\t0033 ;\tMA\t# ( З → 3 ) CYRILLIC CAPITAL LETTER ZE → DIGIT THREE\t# \n04E0 ;\t0033 ;\tMA\t# ( Ӡ → 3 ) CYRILLIC CAPITAL LETTER ABKHASIAN DZE → DIGIT THREE\t# →Ʒ→\n16F3B ;\t0033 ;\tMA\t# ( 𖼻 → 3 ) MIAO LETTER ZA → DIGIT THREE\t# →Ʒ→\n118CA ;\t0033 ;\tMA\t# ( 𑣊 → 3 ) WARANG CITI SMALL LETTER ANG → DIGIT THREE\t# \n\n06F3 ;\t0663 ;\tMA\t# ( ۳ → ‎٣‎ ) EXTENDED ARABIC-INDIC DIGIT THREE → ARABIC-INDIC DIGIT THREE\t# \n1E8C9 ;\t0663 ;\tMA\t#* ( ‎𞣉‎ → ‎٣‎ ) MENDE KIKAKUI DIGIT THREE → ARABIC-INDIC DIGIT THREE\t# \n\n2462 ;\t2782 ;\tMA\t#* ( ③ → ➂ ) CIRCLED DIGIT THREE → DINGBAT CIRCLED SANS-SERIF DIGIT THREE\t# \n\n0498 ;\t0033 0326 ;\tMA\t# ( Ҙ → 3̦ ) CYRILLIC CAPITAL LETTER ZE WITH DESCENDER → DIGIT THREE, COMBINING COMMA BELOW\t# →З̧→\n\n1F104 ;\t0033 002C ;\tMA\t#* ( 🄄 → 3, ) DIGIT THREE COMMA → DIGIT THREE, COMMA\t# \n\n248A ;\t0033 002E ;\tMA\t#* ( ⒊ → 3. ) DIGIT THREE FULL STOP → DIGIT THREE, FULL STOP\t# \n\n33FE ;\t0033 006C 65E5 ;\tMA\t#* ( ㏾ → 3l日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE → DIGIT THREE, LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-65E5\t# →31日→\n\n33FD ;\t0033 004F 65E5 ;\tMA\t#* ( ㏽ → 3O日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY → DIGIT THREE, LATIN CAPITAL LETTER O, CJK UNIFIED IDEOGRAPH-65E5\t# →30日→\n\n33E2 ;\t0033 65E5 ;\tMA\t#* ( ㏢ → 3日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE → DIGIT THREE, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n32C2 ;\t0033 6708 ;\tMA\t#* ( ㋂ → 3月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH → DIGIT THREE, CJK UNIFIED IDEOGRAPH-6708\t# \n\n335B ;\t0033 70B9 ;\tMA\t#* ( ㍛ → 3点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE → DIGIT THREE, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n1CCF4 ;\t0034 ;\tMA\t# ( 𜳴 → 4 ) OUTLINED DIGIT FOUR → DIGIT FOUR\t# \n1D7D2 ;\t0034 ;\tMA\t# ( 𝟒 → 4 ) MATHEMATICAL BOLD DIGIT FOUR → DIGIT FOUR\t# \n1D7DC ;\t0034 ;\tMA\t# ( 𝟜 → 4 ) MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR → DIGIT FOUR\t# \n1D7E6 ;\t0034 ;\tMA\t# ( 𝟦 → 4 ) MATHEMATICAL SANS-SERIF DIGIT FOUR → DIGIT FOUR\t# \n1D7F0 ;\t0034 ;\tMA\t# ( 𝟰 → 4 ) MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR → DIGIT FOUR\t# \n1D7FA ;\t0034 ;\tMA\t# ( 𝟺 → 4 ) MATHEMATICAL MONOSPACE DIGIT FOUR → DIGIT FOUR\t# \n1FBF4 ;\t0034 ;\tMA\t# ( 🯴 → 4 ) SEGMENTED DIGIT FOUR → DIGIT FOUR\t# \n13CE ;\t0034 ;\tMA\t# ( Ꮞ → 4 ) CHEROKEE LETTER SE → DIGIT FOUR\t# \n118AF ;\t0034 ;\tMA\t# ( 𑢯 → 4 ) WARANG CITI CAPITAL LETTER UC → DIGIT FOUR\t# \n\n06F4 ;\t0664 ;\tMA\t# ( ۴ → ‎٤‎ ) EXTENDED ARABIC-INDIC DIGIT FOUR → ARABIC-INDIC DIGIT FOUR\t# \n\n0AEA ;\t096A ;\tMA\t# ( ૪ → ४ ) GUJARATI DIGIT FOUR → DEVANAGARI DIGIT FOUR\t# \n\n2463 ;\t2783 ;\tMA\t#* ( ④ → ➃ ) CIRCLED DIGIT FOUR → DINGBAT CIRCLED SANS-SERIF DIGIT FOUR\t# \n\n1F105 ;\t0034 002C ;\tMA\t#* ( 🄅 → 4, ) DIGIT FOUR COMMA → DIGIT FOUR, COMMA\t# \n\n248B ;\t0034 002E ;\tMA\t#* ( ⒋ → 4. ) DIGIT FOUR FULL STOP → DIGIT FOUR, FULL STOP\t# \n\n1530 ;\t0034 00B7 ;\tMA\t# ( ᔰ → 4· ) CANADIAN SYLLABICS WEST-CREE YWE → DIGIT FOUR, MIDDLE DOT\t# →4ᐧ→\n\n33E3 ;\t0034 65E5 ;\tMA\t#* ( ㏣ → 4日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR → DIGIT FOUR, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n32C3 ;\t0034 6708 ;\tMA\t#* ( ㋃ → 4月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL → DIGIT FOUR, CJK UNIFIED IDEOGRAPH-6708\t# \n\n335C ;\t0034 70B9 ;\tMA\t#* ( ㍜ → 4点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR → DIGIT FOUR, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n1CCF5 ;\t0035 ;\tMA\t# ( 𜳵 → 5 ) OUTLINED DIGIT FIVE → DIGIT FIVE\t# \n1D7D3 ;\t0035 ;\tMA\t# ( 𝟓 → 5 ) MATHEMATICAL BOLD DIGIT FIVE → DIGIT FIVE\t# \n1D7DD ;\t0035 ;\tMA\t# ( 𝟝 → 5 ) MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE → DIGIT FIVE\t# \n1D7E7 ;\t0035 ;\tMA\t# ( 𝟧 → 5 ) MATHEMATICAL SANS-SERIF DIGIT FIVE → DIGIT FIVE\t# \n1D7F1 ;\t0035 ;\tMA\t# ( 𝟱 → 5 ) MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE → DIGIT FIVE\t# \n1D7FB ;\t0035 ;\tMA\t# ( 𝟻 → 5 ) MATHEMATICAL MONOSPACE DIGIT FIVE → DIGIT FIVE\t# \n1FBF5 ;\t0035 ;\tMA\t# ( 🯵 → 5 ) SEGMENTED DIGIT FIVE → DIGIT FIVE\t# \n01BC ;\t0035 ;\tMA\t# ( Ƽ → 5 ) LATIN CAPITAL LETTER TONE FIVE → DIGIT FIVE\t# \n118BB ;\t0035 ;\tMA\t# ( 𑢻 → 5 ) WARANG CITI CAPITAL LETTER HORR → DIGIT FIVE\t# \n\n2464 ;\t2784 ;\tMA\t#* ( ⑤ → ➄ ) CIRCLED DIGIT FIVE → DINGBAT CIRCLED SANS-SERIF DIGIT FIVE\t# \n\n1F106 ;\t0035 002C ;\tMA\t#* ( 🄆 → 5, ) DIGIT FIVE COMMA → DIGIT FIVE, COMMA\t# \n\n248C ;\t0035 002E ;\tMA\t#* ( ⒌ → 5. ) DIGIT FIVE FULL STOP → DIGIT FIVE, FULL STOP\t# \n\n33E4 ;\t0035 65E5 ;\tMA\t#* ( ㏤ → 5日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE → DIGIT FIVE, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n32C4 ;\t0035 6708 ;\tMA\t#* ( ㋄ → 5月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY → DIGIT FIVE, CJK UNIFIED IDEOGRAPH-6708\t# \n\n335D ;\t0035 70B9 ;\tMA\t#* ( ㍝ → 5点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE → DIGIT FIVE, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n1CCF6 ;\t0036 ;\tMA\t# ( 𜳶 → 6 ) OUTLINED DIGIT SIX → DIGIT SIX\t# \n1D7D4 ;\t0036 ;\tMA\t# ( 𝟔 → 6 ) MATHEMATICAL BOLD DIGIT SIX → DIGIT SIX\t# \n1D7DE ;\t0036 ;\tMA\t# ( 𝟞 → 6 ) MATHEMATICAL DOUBLE-STRUCK DIGIT SIX → DIGIT SIX\t# \n1D7E8 ;\t0036 ;\tMA\t# ( 𝟨 → 6 ) MATHEMATICAL SANS-SERIF DIGIT SIX → DIGIT SIX\t# \n1D7F2 ;\t0036 ;\tMA\t# ( 𝟲 → 6 ) MATHEMATICAL SANS-SERIF BOLD DIGIT SIX → DIGIT SIX\t# \n1D7FC ;\t0036 ;\tMA\t# ( 𝟼 → 6 ) MATHEMATICAL MONOSPACE DIGIT SIX → DIGIT SIX\t# \n1FBF6 ;\t0036 ;\tMA\t# ( 🯶 → 6 ) SEGMENTED DIGIT SIX → DIGIT SIX\t# \n2CD3 ;\t0036 ;\tMA\t# ( ⳓ → 6 ) COPTIC SMALL LETTER OLD COPTIC HEI → DIGIT SIX\t# \n2CD2 ;\t0036 ;\tMA\t# ( Ⳓ → 6 ) COPTIC CAPITAL LETTER OLD COPTIC HEI → DIGIT SIX\t# \n03EC ;\t0036 ;\tMA\t# ( Ϭ → 6 ) COPTIC CAPITAL LETTER SHIMA → DIGIT SIX\t# \n2CDC ;\t0036 ;\tMA\t# ( Ⳝ → 6 ) COPTIC CAPITAL LETTER OLD NUBIAN SHIMA → DIGIT SIX\t# →Ϭ→\n0431 ;\t0036 ;\tMA\t# ( б → 6 ) CYRILLIC SMALL LETTER BE → DIGIT SIX\t# \n13EE ;\t0036 ;\tMA\t# ( Ꮾ → 6 ) CHEROKEE LETTER WV → DIGIT SIX\t# \n118D5 ;\t0036 ;\tMA\t# ( 𑣕 → 6 ) WARANG CITI SMALL LETTER AT → DIGIT SIX\t# \n\n06F6 ;\t0666 ;\tMA\t# ( ۶ → ‎٦‎ ) EXTENDED ARABIC-INDIC DIGIT SIX → ARABIC-INDIC DIGIT SIX\t# \n\n114D6 ;\t09EC ;\tMA\t# ( 𑓖 → ৬ ) TIRHUTA DIGIT SIX → BENGALI DIGIT SIX\t# \n\n2465 ;\t2785 ;\tMA\t#* ( ⑥ → ➅ ) CIRCLED DIGIT SIX → DINGBAT CIRCLED SANS-SERIF DIGIT SIX\t# \n\n1F107 ;\t0036 002C ;\tMA\t#* ( 🄇 → 6, ) DIGIT SIX COMMA → DIGIT SIX, COMMA\t# \n\n248D ;\t0036 002E ;\tMA\t#* ( ⒍ → 6. ) DIGIT SIX FULL STOP → DIGIT SIX, FULL STOP\t# \n\n33E5 ;\t0036 65E5 ;\tMA\t#* ( ㏥ → 6日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX → DIGIT SIX, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n32C5 ;\t0036 6708 ;\tMA\t#* ( ㋅ → 6月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE → DIGIT SIX, CJK UNIFIED IDEOGRAPH-6708\t# \n\n335E ;\t0036 70B9 ;\tMA\t#* ( ㍞ → 6点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX → DIGIT SIX, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n1D212 ;\t0037 ;\tMA\t#* ( 𝈒 → 7 ) GREEK VOCAL NOTATION SYMBOL-19 → DIGIT SEVEN\t# \n1CCF7 ;\t0037 ;\tMA\t# ( 𜳷 → 7 ) OUTLINED DIGIT SEVEN → DIGIT SEVEN\t# \n1D7D5 ;\t0037 ;\tMA\t# ( 𝟕 → 7 ) MATHEMATICAL BOLD DIGIT SEVEN → DIGIT SEVEN\t# \n1D7DF ;\t0037 ;\tMA\t# ( 𝟟 → 7 ) MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN → DIGIT SEVEN\t# \n1D7E9 ;\t0037 ;\tMA\t# ( 𝟩 → 7 ) MATHEMATICAL SANS-SERIF DIGIT SEVEN → DIGIT SEVEN\t# \n1D7F3 ;\t0037 ;\tMA\t# ( 𝟳 → 7 ) MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN → DIGIT SEVEN\t# \n1D7FD ;\t0037 ;\tMA\t# ( 𝟽 → 7 ) MATHEMATICAL MONOSPACE DIGIT SEVEN → DIGIT SEVEN\t# \n1FBF7 ;\t0037 ;\tMA\t# ( 🯷 → 7 ) SEGMENTED DIGIT SEVEN → DIGIT SEVEN\t# \n104D2 ;\t0037 ;\tMA\t# ( 𐓒 → 7 ) OSAGE CAPITAL LETTER ZA → DIGIT SEVEN\t# \n118C6 ;\t0037 ;\tMA\t# ( 𑣆 → 7 ) WARANG CITI SMALL LETTER II → DIGIT SEVEN\t# \n\n2466 ;\t2786 ;\tMA\t#* ( ⑦ → ➆ ) CIRCLED DIGIT SEVEN → DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN\t# \n\n1F108 ;\t0037 002C ;\tMA\t#* ( 🄈 → 7, ) DIGIT SEVEN COMMA → DIGIT SEVEN, COMMA\t# \n\n248E ;\t0037 002E ;\tMA\t#* ( ⒎ → 7. ) DIGIT SEVEN FULL STOP → DIGIT SEVEN, FULL STOP\t# \n\n33E6 ;\t0037 65E5 ;\tMA\t#* ( ㏦ → 7日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN → DIGIT SEVEN, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n32C6 ;\t0037 6708 ;\tMA\t#* ( ㋆ → 7月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY → DIGIT SEVEN, CJK UNIFIED IDEOGRAPH-6708\t# \n\n335F ;\t0037 70B9 ;\tMA\t#* ( ㍟ → 7点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN → DIGIT SEVEN, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n0B03 ;\t0038 ;\tMA\t# ( ଃ → 8 ) ORIYA SIGN VISARGA → DIGIT EIGHT\t# \n09EA ;\t0038 ;\tMA\t# ( ৪ → 8 ) BENGALI DIGIT FOUR → DIGIT EIGHT\t# \n0A6A ;\t0038 ;\tMA\t# ( ੪ → 8 ) GURMUKHI DIGIT FOUR → DIGIT EIGHT\t# \n1E8CB ;\t0038 ;\tMA\t#* ( ‎𞣋‎ → 8 ) MENDE KIKAKUI DIGIT FIVE → DIGIT EIGHT\t# \n1CCF8 ;\t0038 ;\tMA\t# ( 𜳸 → 8 ) OUTLINED DIGIT EIGHT → DIGIT EIGHT\t# \n1D7D6 ;\t0038 ;\tMA\t# ( 𝟖 → 8 ) MATHEMATICAL BOLD DIGIT EIGHT → DIGIT EIGHT\t# \n1D7E0 ;\t0038 ;\tMA\t# ( 𝟠 → 8 ) MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT → DIGIT EIGHT\t# \n1D7EA ;\t0038 ;\tMA\t# ( 𝟪 → 8 ) MATHEMATICAL SANS-SERIF DIGIT EIGHT → DIGIT EIGHT\t# \n1D7F4 ;\t0038 ;\tMA\t# ( 𝟴 → 8 ) MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT → DIGIT EIGHT\t# \n1D7FE ;\t0038 ;\tMA\t# ( 𝟾 → 8 ) MATHEMATICAL MONOSPACE DIGIT EIGHT → DIGIT EIGHT\t# \n1FBF8 ;\t0038 ;\tMA\t# ( 🯸 → 8 ) SEGMENTED DIGIT EIGHT → DIGIT EIGHT\t# \n0223 ;\t0038 ;\tMA\t# ( ȣ → 8 ) LATIN SMALL LETTER OU → DIGIT EIGHT\t# \n0222 ;\t0038 ;\tMA\t# ( Ȣ → 8 ) LATIN CAPITAL LETTER OU → DIGIT EIGHT\t# \n1031A ;\t0038 ;\tMA\t# ( 𐌚 → 8 ) OLD ITALIC LETTER EF → DIGIT EIGHT\t# \n\n0AEE ;\t096E ;\tMA\t# ( ૮ → ८ ) GUJARATI DIGIT EIGHT → DEVANAGARI DIGIT EIGHT\t# \n\n2467 ;\t2787 ;\tMA\t#* ( ⑧ → ➇ ) CIRCLED DIGIT EIGHT → DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT\t# \n\n1F109 ;\t0038 002C ;\tMA\t#* ( 🄉 → 8, ) DIGIT EIGHT COMMA → DIGIT EIGHT, COMMA\t# \n\n248F ;\t0038 002E ;\tMA\t#* ( ⒏ → 8. ) DIGIT EIGHT FULL STOP → DIGIT EIGHT, FULL STOP\t# \n\n33E7 ;\t0038 65E5 ;\tMA\t#* ( ㏧ → 8日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT → DIGIT EIGHT, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n32C7 ;\t0038 6708 ;\tMA\t#* ( ㋇ → 8月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST → DIGIT EIGHT, CJK UNIFIED IDEOGRAPH-6708\t# \n\n3360 ;\t0038 70B9 ;\tMA\t#* ( ㍠ → 8点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT → DIGIT EIGHT, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n0A67 ;\t0039 ;\tMA\t# ( ੧ → 9 ) GURMUKHI DIGIT ONE → DIGIT NINE\t# \n0B68 ;\t0039 ;\tMA\t# ( ୨ → 9 ) ORIYA DIGIT TWO → DIGIT NINE\t# \n09ED ;\t0039 ;\tMA\t# ( ৭ → 9 ) BENGALI DIGIT SEVEN → DIGIT NINE\t# \n0D6D ;\t0039 ;\tMA\t# ( ൭ → 9 ) MALAYALAM DIGIT SEVEN → DIGIT NINE\t# \n1CCF9 ;\t0039 ;\tMA\t# ( 𜳹 → 9 ) OUTLINED DIGIT NINE → DIGIT NINE\t# \n1D7D7 ;\t0039 ;\tMA\t# ( 𝟗 → 9 ) MATHEMATICAL BOLD DIGIT NINE → DIGIT NINE\t# \n1D7E1 ;\t0039 ;\tMA\t# ( 𝟡 → 9 ) MATHEMATICAL DOUBLE-STRUCK DIGIT NINE → DIGIT NINE\t# \n1D7EB ;\t0039 ;\tMA\t# ( 𝟫 → 9 ) MATHEMATICAL SANS-SERIF DIGIT NINE → DIGIT NINE\t# \n1D7F5 ;\t0039 ;\tMA\t# ( 𝟵 → 9 ) MATHEMATICAL SANS-SERIF BOLD DIGIT NINE → DIGIT NINE\t# \n1D7FF ;\t0039 ;\tMA\t# ( 𝟿 → 9 ) MATHEMATICAL MONOSPACE DIGIT NINE → DIGIT NINE\t# \n1FBF9 ;\t0039 ;\tMA\t# ( 🯹 → 9 ) SEGMENTED DIGIT NINE → DIGIT NINE\t# \nA76E ;\t0039 ;\tMA\t# ( Ꝯ → 9 ) LATIN CAPITAL LETTER CON → DIGIT NINE\t# \n2CCB ;\t0039 ;\tMA\t# ( ⳋ → 9 ) COPTIC SMALL LETTER DIALECT-P HORI → DIGIT NINE\t# \n2CCA ;\t0039 ;\tMA\t# ( Ⳋ → 9 ) COPTIC CAPITAL LETTER DIALECT-P HORI → DIGIT NINE\t# \n118CC ;\t0039 ;\tMA\t# ( 𑣌 → 9 ) WARANG CITI SMALL LETTER KO → DIGIT NINE\t# \n118AC ;\t0039 ;\tMA\t# ( 𑢬 → 9 ) WARANG CITI CAPITAL LETTER KO → DIGIT NINE\t# \n118D6 ;\t0039 ;\tMA\t# ( 𑣖 → 9 ) WARANG CITI SMALL LETTER AM → DIGIT NINE\t# \n\n0967 ;\t0669 ;\tMA\t# ( १ → ‎٩‎ ) DEVANAGARI DIGIT ONE → ARABIC-INDIC DIGIT NINE\t# \n118E4 ;\t0669 ;\tMA\t# ( 𑣤 → ‎٩‎ ) WARANG CITI DIGIT FOUR → ARABIC-INDIC DIGIT NINE\t# \n06F9 ;\t0669 ;\tMA\t# ( ۹ → ‎٩‎ ) EXTENDED ARABIC-INDIC DIGIT NINE → ARABIC-INDIC DIGIT NINE\t# \n\n0CEF ;\t0C6F ;\tMA\t# ( ೯ → ౯ ) KANNADA DIGIT NINE → TELUGU DIGIT NINE\t# \n\n2468 ;\t2788 ;\tMA\t#* ( ⑨ → ➈ ) CIRCLED DIGIT NINE → DINGBAT CIRCLED SANS-SERIF DIGIT NINE\t# \n\n1F10A ;\t0039 002C ;\tMA\t#* ( 🄊 → 9, ) DIGIT NINE COMMA → DIGIT NINE, COMMA\t# \n\n2490 ;\t0039 002E ;\tMA\t#* ( ⒐ → 9. ) DIGIT NINE FULL STOP → DIGIT NINE, FULL STOP\t# \n\n33E8 ;\t0039 65E5 ;\tMA\t#* ( ㏨ → 9日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE → DIGIT NINE, CJK UNIFIED IDEOGRAPH-65E5\t# \n\n32C8 ;\t0039 6708 ;\tMA\t#* ( ㋈ → 9月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER → DIGIT NINE, CJK UNIFIED IDEOGRAPH-6708\t# \n\n3361 ;\t0039 70B9 ;\tMA\t#* ( ㍡ → 9点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE → DIGIT NINE, CJK UNIFIED IDEOGRAPH-70B9\t# \n\n237A ;\t0061 ;\tMA\t#* ( ⍺ → a ) APL FUNCTIONAL SYMBOL ALPHA → LATIN SMALL LETTER A\t# →α→\nFF41 ;\t0061 ;\tMA\t# ( ａ → a ) FULLWIDTH LATIN SMALL LETTER A → LATIN SMALL LETTER A\t# →а→\n1D41A ;\t0061 ;\tMA\t# ( 𝐚 → a ) MATHEMATICAL BOLD SMALL A → LATIN SMALL LETTER A\t# \n1D44E ;\t0061 ;\tMA\t# ( 𝑎 → a ) MATHEMATICAL ITALIC SMALL A → LATIN SMALL LETTER A\t# \n1D482 ;\t0061 ;\tMA\t# ( 𝒂 → a ) MATHEMATICAL BOLD ITALIC SMALL A → LATIN SMALL LETTER A\t# \n1D4B6 ;\t0061 ;\tMA\t# ( 𝒶 → a ) MATHEMATICAL SCRIPT SMALL A → LATIN SMALL LETTER A\t# \n1D4EA ;\t0061 ;\tMA\t# ( 𝓪 → a ) MATHEMATICAL BOLD SCRIPT SMALL A → LATIN SMALL LETTER A\t# \n1D51E ;\t0061 ;\tMA\t# ( 𝔞 → a ) MATHEMATICAL FRAKTUR SMALL A → LATIN SMALL LETTER A\t# \n1D552 ;\t0061 ;\tMA\t# ( 𝕒 → a ) MATHEMATICAL DOUBLE-STRUCK SMALL A → LATIN SMALL LETTER A\t# \n1D586 ;\t0061 ;\tMA\t# ( 𝖆 → a ) MATHEMATICAL BOLD FRAKTUR SMALL A → LATIN SMALL LETTER A\t# \n1D5BA ;\t0061 ;\tMA\t# ( 𝖺 → a ) MATHEMATICAL SANS-SERIF SMALL A → LATIN SMALL LETTER A\t# \n1D5EE ;\t0061 ;\tMA\t# ( 𝗮 → a ) MATHEMATICAL SANS-SERIF BOLD SMALL A → LATIN SMALL LETTER A\t# \n1D622 ;\t0061 ;\tMA\t# ( 𝘢 → a ) MATHEMATICAL SANS-SERIF ITALIC SMALL A → LATIN SMALL LETTER A\t# \n1D656 ;\t0061 ;\tMA\t# ( 𝙖 → a ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A → LATIN SMALL LETTER A\t# \n1D68A ;\t0061 ;\tMA\t# ( 𝚊 → a ) MATHEMATICAL MONOSPACE SMALL A → LATIN SMALL LETTER A\t# \n0251 ;\t0061 ;\tMA\t# ( ɑ → a ) LATIN SMALL LETTER ALPHA → LATIN SMALL LETTER A\t# \n03B1 ;\t0061 ;\tMA\t# ( α → a ) GREEK SMALL LETTER ALPHA → LATIN SMALL LETTER A\t# \n1D6C2 ;\t0061 ;\tMA\t# ( 𝛂 → a ) MATHEMATICAL BOLD SMALL ALPHA → LATIN SMALL LETTER A\t# →α→\n1D6FC ;\t0061 ;\tMA\t# ( 𝛼 → a ) MATHEMATICAL ITALIC SMALL ALPHA → LATIN SMALL LETTER A\t# →α→\n1D736 ;\t0061 ;\tMA\t# ( 𝜶 → a ) MATHEMATICAL BOLD ITALIC SMALL ALPHA → LATIN SMALL LETTER A\t# →α→\n1D770 ;\t0061 ;\tMA\t# ( 𝝰 → a ) MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA → LATIN SMALL LETTER A\t# →α→\n1D7AA ;\t0061 ;\tMA\t# ( 𝞪 → a ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA → LATIN SMALL LETTER A\t# →α→\n0430 ;\t0061 ;\tMA\t# ( а → a ) CYRILLIC SMALL LETTER A → LATIN SMALL LETTER A\t# \n\n2DF6 ;\t0363 ;\tMA\t# ( ⷶ → ͣ ) COMBINING CYRILLIC LETTER A → COMBINING LATIN SMALL LETTER A\t# \n\nFF21 ;\t0041 ;\tMA\t# ( Ａ → A ) FULLWIDTH LATIN CAPITAL LETTER A → LATIN CAPITAL LETTER A\t# →А→\n1CCD6 ;\t0041 ;\tMA\t#* ( 𜳖 → A ) OUTLINED LATIN CAPITAL LETTER A → LATIN CAPITAL LETTER A\t# \n1D400 ;\t0041 ;\tMA\t# ( 𝐀 → A ) MATHEMATICAL BOLD CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D434 ;\t0041 ;\tMA\t# ( 𝐴 → A ) MATHEMATICAL ITALIC CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D468 ;\t0041 ;\tMA\t# ( 𝑨 → A ) MATHEMATICAL BOLD ITALIC CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D49C ;\t0041 ;\tMA\t# ( 𝒜 → A ) MATHEMATICAL SCRIPT CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D4D0 ;\t0041 ;\tMA\t# ( 𝓐 → A ) MATHEMATICAL BOLD SCRIPT CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D504 ;\t0041 ;\tMA\t# ( 𝔄 → A ) MATHEMATICAL FRAKTUR CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D538 ;\t0041 ;\tMA\t# ( 𝔸 → A ) MATHEMATICAL DOUBLE-STRUCK CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D56C ;\t0041 ;\tMA\t# ( 𝕬 → A ) MATHEMATICAL BOLD FRAKTUR CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D5A0 ;\t0041 ;\tMA\t# ( 𝖠 → A ) MATHEMATICAL SANS-SERIF CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D5D4 ;\t0041 ;\tMA\t# ( 𝗔 → A ) MATHEMATICAL SANS-SERIF BOLD CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D608 ;\t0041 ;\tMA\t# ( 𝘈 → A ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D63C ;\t0041 ;\tMA\t# ( 𝘼 → A ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A → LATIN CAPITAL LETTER A\t# \n1D670 ;\t0041 ;\tMA\t# ( 𝙰 → A ) MATHEMATICAL MONOSPACE CAPITAL A → LATIN CAPITAL LETTER A\t# \n0391 ;\t0041 ;\tMA\t# ( Α → A ) GREEK CAPITAL LETTER ALPHA → LATIN CAPITAL LETTER A\t# \n1D6A8 ;\t0041 ;\tMA\t# ( 𝚨 → A ) MATHEMATICAL BOLD CAPITAL ALPHA → LATIN CAPITAL LETTER A\t# →𝐀→\n1D6E2 ;\t0041 ;\tMA\t# ( 𝛢 → A ) MATHEMATICAL ITALIC CAPITAL ALPHA → LATIN CAPITAL LETTER A\t# →Α→\n1D71C ;\t0041 ;\tMA\t# ( 𝜜 → A ) MATHEMATICAL BOLD ITALIC CAPITAL ALPHA → LATIN CAPITAL LETTER A\t# →Α→\n1D756 ;\t0041 ;\tMA\t# ( 𝝖 → A ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA → LATIN CAPITAL LETTER A\t# →Α→\n1D790 ;\t0041 ;\tMA\t# ( 𝞐 → A ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA → LATIN CAPITAL LETTER A\t# →Α→\n0410 ;\t0041 ;\tMA\t# ( А → A ) CYRILLIC CAPITAL LETTER A → LATIN CAPITAL LETTER A\t# \n13AA ;\t0041 ;\tMA\t# ( Ꭺ → A ) CHEROKEE LETTER GO → LATIN CAPITAL LETTER A\t# \n15C5 ;\t0041 ;\tMA\t# ( ᗅ → A ) CANADIAN SYLLABICS CARRIER GHO → LATIN CAPITAL LETTER A\t# \nA4EE ;\t0041 ;\tMA\t# ( ꓮ → A ) LISU LETTER A → LATIN CAPITAL LETTER A\t# \n16F40 ;\t0041 ;\tMA\t# ( 𖽀 → A ) MIAO LETTER ZZYA → LATIN CAPITAL LETTER A\t# \n102A0 ;\t0041 ;\tMA\t# ( 𐊠 → A ) CARIAN LETTER A → LATIN CAPITAL LETTER A\t# \n\n2376 ;\t0061 0332 ;\tMA\t#* ( ⍶ → a̲ ) APL FUNCTIONAL SYMBOL ALPHA UNDERBAR → LATIN SMALL LETTER A, COMBINING LOW LINE\t# →α̲→→ɑ̲→\n\n01CE ;\t0103 ;\tMA\t# ( ǎ → ă ) LATIN SMALL LETTER A WITH CARON → LATIN SMALL LETTER A WITH BREVE\t# \n\n01CD ;\t0102 ;\tMA\t# ( Ǎ → Ă ) LATIN CAPITAL LETTER A WITH CARON → LATIN CAPITAL LETTER A WITH BREVE\t# \n\n0227 ;\t00E5 ;\tMA\t# ( ȧ → å ) LATIN SMALL LETTER A WITH DOT ABOVE → LATIN SMALL LETTER A WITH RING ABOVE\t# \n\n0226 ;\t00C5 ;\tMA\t# ( Ȧ → Å ) LATIN CAPITAL LETTER A WITH DOT ABOVE → LATIN CAPITAL LETTER A WITH RING ABOVE\t# \n\n1E9A ;\t1EA3 ;\tMA\t# ( ẚ → ả ) LATIN SMALL LETTER A WITH RIGHT HALF RING → LATIN SMALL LETTER A WITH HOOK ABOVE\t# \n\n2100 ;\t0061 002F 0063 ;\tMA\t#* ( ℀ → a/c ) ACCOUNT OF → LATIN SMALL LETTER A, SOLIDUS, LATIN SMALL LETTER C\t# \n\n2101 ;\t0061 002F 0073 ;\tMA\t#* ( ℁ → a/s ) ADDRESSED TO THE SUBJECT → LATIN SMALL LETTER A, SOLIDUS, LATIN SMALL LETTER S\t# \n\nA733 ;\t0061 0061 ;\tMA\t# ( ꜳ → aa ) LATIN SMALL LETTER AA → LATIN SMALL LETTER A, LATIN SMALL LETTER A\t# \n\nA732 ;\t0041 0041 ;\tMA\t# ( Ꜳ → AA ) LATIN CAPITAL LETTER AA → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER A\t# \n\n00E6 ;\t0061 0065 ;\tMA\t# ( æ → ae ) LATIN SMALL LETTER AE → LATIN SMALL LETTER A, LATIN SMALL LETTER E\t# \n04D5 ;\t0061 0065 ;\tMA\t# ( ӕ → ae ) CYRILLIC SMALL LIGATURE A IE → LATIN SMALL LETTER A, LATIN SMALL LETTER E\t# →ае→\n\n00C6 ;\t0041 0045 ;\tMA\t# ( Æ → AE ) LATIN CAPITAL LETTER AE → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER E\t# \n04D4 ;\t0041 0045 ;\tMA\t# ( Ӕ → AE ) CYRILLIC CAPITAL LIGATURE A IE → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER E\t# →Æ→\n\nA735 ;\t0061 006F ;\tMA\t# ( ꜵ → ao ) LATIN SMALL LETTER AO → LATIN SMALL LETTER A, LATIN SMALL LETTER O\t# \n\nA734 ;\t0041 004F ;\tMA\t# ( Ꜵ → AO ) LATIN CAPITAL LETTER AO → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER O\t# \n\n1F707 ;\t0041 0052 ;\tMA\t#* ( 🜇 → AR ) ALCHEMICAL SYMBOL FOR AQUA REGIA-2 → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER R\t# \n\nA737 ;\t0061 0075 ;\tMA\t# ( ꜷ → au ) LATIN SMALL LETTER AU → LATIN SMALL LETTER A, LATIN SMALL LETTER U\t# \n\nA736 ;\t0041 0055 ;\tMA\t# ( Ꜷ → AU ) LATIN CAPITAL LETTER AU → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER U\t# \n\nA739 ;\t0061 0076 ;\tMA\t# ( ꜹ → av ) LATIN SMALL LETTER AV → LATIN SMALL LETTER A, LATIN SMALL LETTER V\t# \nA73B ;\t0061 0076 ;\tMA\t# ( ꜻ → av ) LATIN SMALL LETTER AV WITH HORIZONTAL BAR → LATIN SMALL LETTER A, LATIN SMALL LETTER V\t# \n\nA738 ;\t0041 0056 ;\tMA\t# ( Ꜹ → AV ) LATIN CAPITAL LETTER AV → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER V\t# \nA73A ;\t0041 0056 ;\tMA\t# ( Ꜻ → AV ) LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER V\t# \n\nA73D ;\t0061 0079 ;\tMA\t# ( ꜽ → ay ) LATIN SMALL LETTER AY → LATIN SMALL LETTER A, LATIN SMALL LETTER Y\t# \n\nA73C ;\t0041 0059 ;\tMA\t# ( Ꜽ → AY ) LATIN CAPITAL LETTER AY → LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER Y\t# \n\nAB7A ;\t1D00 ;\tMA\t# ( ꭺ → ᴀ ) CHEROKEE SMALL LETTER GO → LATIN LETTER SMALL CAPITAL A\t# \n\n2200 ;\t2C6F ;\tMA\t#* ( ∀ → Ɐ ) FOR ALL → LATIN CAPITAL LETTER TURNED A\t# \n1D217 ;\t2C6F ;\tMA\t#* ( 𝈗 → Ɐ ) GREEK VOCAL NOTATION SYMBOL-24 → LATIN CAPITAL LETTER TURNED A\t# \n15C4 ;\t2C6F ;\tMA\t# ( ᗄ → Ɐ ) CANADIAN SYLLABICS CARRIER GHU → LATIN CAPITAL LETTER TURNED A\t# →∀→\nA4EF ;\t2C6F ;\tMA\t# ( ꓯ → Ɐ ) LISU LETTER AE → LATIN CAPITAL LETTER TURNED A\t# \n\n1041F ;\t2C70 ;\tMA\t# ( 𐐟 → Ɒ ) DESERET CAPITAL LETTER ESH → LATIN CAPITAL LETTER TURNED ALPHA\t# \n\n1D41B ;\t0062 ;\tMA\t# ( 𝐛 → b ) MATHEMATICAL BOLD SMALL B → LATIN SMALL LETTER B\t# \n1D44F ;\t0062 ;\tMA\t# ( 𝑏 → b ) MATHEMATICAL ITALIC SMALL B → LATIN SMALL LETTER B\t# \n1D483 ;\t0062 ;\tMA\t# ( 𝒃 → b ) MATHEMATICAL BOLD ITALIC SMALL B → LATIN SMALL LETTER B\t# \n1D4B7 ;\t0062 ;\tMA\t# ( 𝒷 → b ) MATHEMATICAL SCRIPT SMALL B → LATIN SMALL LETTER B\t# \n1D4EB ;\t0062 ;\tMA\t# ( 𝓫 → b ) MATHEMATICAL BOLD SCRIPT SMALL B → LATIN SMALL LETTER B\t# \n1D51F ;\t0062 ;\tMA\t# ( 𝔟 → b ) MATHEMATICAL FRAKTUR SMALL B → LATIN SMALL LETTER B\t# \n1D553 ;\t0062 ;\tMA\t# ( 𝕓 → b ) MATHEMATICAL DOUBLE-STRUCK SMALL B → LATIN SMALL LETTER B\t# \n1D587 ;\t0062 ;\tMA\t# ( 𝖇 → b ) MATHEMATICAL BOLD FRAKTUR SMALL B → LATIN SMALL LETTER B\t# \n1D5BB ;\t0062 ;\tMA\t# ( 𝖻 → b ) MATHEMATICAL SANS-SERIF SMALL B → LATIN SMALL LETTER B\t# \n1D5EF ;\t0062 ;\tMA\t# ( 𝗯 → b ) MATHEMATICAL SANS-SERIF BOLD SMALL B → LATIN SMALL LETTER B\t# \n1D623 ;\t0062 ;\tMA\t# ( 𝘣 → b ) MATHEMATICAL SANS-SERIF ITALIC SMALL B → LATIN SMALL LETTER B\t# \n1D657 ;\t0062 ;\tMA\t# ( 𝙗 → b ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B → LATIN SMALL LETTER B\t# \n1D68B ;\t0062 ;\tMA\t# ( 𝚋 → b ) MATHEMATICAL MONOSPACE SMALL B → LATIN SMALL LETTER B\t# \n0184 ;\t0062 ;\tMA\t# ( Ƅ → b ) LATIN CAPITAL LETTER TONE SIX → LATIN SMALL LETTER B\t# \n042C ;\t0062 ;\tMA\t# ( Ь → b ) CYRILLIC CAPITAL LETTER SOFT SIGN → LATIN SMALL LETTER B\t# →Ƅ→\n13CF ;\t0062 ;\tMA\t# ( Ꮟ → b ) CHEROKEE LETTER SI → LATIN SMALL LETTER B\t# \n1472 ;\t0062 ;\tMA\t# ( ᑲ → b ) CANADIAN SYLLABICS KA → LATIN SMALL LETTER B\t# \n15AF ;\t0062 ;\tMA\t# ( ᖯ → b ) CANADIAN SYLLABICS AIVILIK B → LATIN SMALL LETTER B\t# \n16EB6 ;\t0062 ;\tMA\t# ( 𖺶 → b ) BERIA ERFE CAPITAL LETTER UI → LATIN SMALL LETTER B\t# →Ь→→Ƅ→\n\nFF22 ;\t0042 ;\tMA\t# ( Ｂ → B ) FULLWIDTH LATIN CAPITAL LETTER B → LATIN CAPITAL LETTER B\t# →Β→\n212C ;\t0042 ;\tMA\t# ( ℬ → B ) SCRIPT CAPITAL B → LATIN CAPITAL LETTER B\t# \n1CCD7 ;\t0042 ;\tMA\t#* ( 𜳗 → B ) OUTLINED LATIN CAPITAL LETTER B → LATIN CAPITAL LETTER B\t# \n1D401 ;\t0042 ;\tMA\t# ( 𝐁 → B ) MATHEMATICAL BOLD CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D435 ;\t0042 ;\tMA\t# ( 𝐵 → B ) MATHEMATICAL ITALIC CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D469 ;\t0042 ;\tMA\t# ( 𝑩 → B ) MATHEMATICAL BOLD ITALIC CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D4D1 ;\t0042 ;\tMA\t# ( 𝓑 → B ) MATHEMATICAL BOLD SCRIPT CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D505 ;\t0042 ;\tMA\t# ( 𝔅 → B ) MATHEMATICAL FRAKTUR CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D539 ;\t0042 ;\tMA\t# ( 𝔹 → B ) MATHEMATICAL DOUBLE-STRUCK CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D56D ;\t0042 ;\tMA\t# ( 𝕭 → B ) MATHEMATICAL BOLD FRAKTUR CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D5A1 ;\t0042 ;\tMA\t# ( 𝖡 → B ) MATHEMATICAL SANS-SERIF CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D5D5 ;\t0042 ;\tMA\t# ( 𝗕 → B ) MATHEMATICAL SANS-SERIF BOLD CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D609 ;\t0042 ;\tMA\t# ( 𝘉 → B ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D63D ;\t0042 ;\tMA\t# ( 𝘽 → B ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B → LATIN CAPITAL LETTER B\t# \n1D671 ;\t0042 ;\tMA\t# ( 𝙱 → B ) MATHEMATICAL MONOSPACE CAPITAL B → LATIN CAPITAL LETTER B\t# \nA7B4 ;\t0042 ;\tMA\t# ( Ꞵ → B ) LATIN CAPITAL LETTER BETA → LATIN CAPITAL LETTER B\t# \n0392 ;\t0042 ;\tMA\t# ( Β → B ) GREEK CAPITAL LETTER BETA → LATIN CAPITAL LETTER B\t# \n1D6A9 ;\t0042 ;\tMA\t# ( 𝚩 → B ) MATHEMATICAL BOLD CAPITAL BETA → LATIN CAPITAL LETTER B\t# →Β→\n1D6E3 ;\t0042 ;\tMA\t# ( 𝛣 → B ) MATHEMATICAL ITALIC CAPITAL BETA → LATIN CAPITAL LETTER B\t# →Β→\n1D71D ;\t0042 ;\tMA\t# ( 𝜝 → B ) MATHEMATICAL BOLD ITALIC CAPITAL BETA → LATIN CAPITAL LETTER B\t# →Β→\n1D757 ;\t0042 ;\tMA\t# ( 𝝗 → B ) MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA → LATIN CAPITAL LETTER B\t# →Β→\n1D791 ;\t0042 ;\tMA\t# ( 𝞑 → B ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA → LATIN CAPITAL LETTER B\t# →Β→\n2C82 ;\t0042 ;\tMA\t# ( Ⲃ → B ) COPTIC CAPITAL LETTER VIDA → LATIN CAPITAL LETTER B\t# \n0412 ;\t0042 ;\tMA\t# ( В → B ) CYRILLIC CAPITAL LETTER VE → LATIN CAPITAL LETTER B\t# \n13F4 ;\t0042 ;\tMA\t# ( Ᏼ → B ) CHEROKEE LETTER YV → LATIN CAPITAL LETTER B\t# \n15F7 ;\t0042 ;\tMA\t# ( ᗷ → B ) CANADIAN SYLLABICS CARRIER KHE → LATIN CAPITAL LETTER B\t# \nA4D0 ;\t0042 ;\tMA\t# ( ꓐ → B ) LISU LETTER BA → LATIN CAPITAL LETTER B\t# \n10282 ;\t0042 ;\tMA\t# ( 𐊂 → B ) LYCIAN LETTER B → LATIN CAPITAL LETTER B\t# \n102A1 ;\t0042 ;\tMA\t# ( 𐊡 → B ) CARIAN LETTER P2 → LATIN CAPITAL LETTER B\t# \n10301 ;\t0042 ;\tMA\t# ( 𐌁 → B ) OLD ITALIC LETTER BE → LATIN CAPITAL LETTER B\t# \n\n0253 ;\t0062 0314 ;\tMA\t# ( ɓ → b̔ ) LATIN SMALL LETTER B WITH HOOK → LATIN SMALL LETTER B, COMBINING REVERSED COMMA ABOVE\t# \n\n1473 ;\t0062 0307 ;\tMA\t# ( ᑳ → ḃ ) CANADIAN SYLLABICS KAA → LATIN SMALL LETTER B, COMBINING DOT ABOVE\t# \n\n0183 ;\t0062 0304 ;\tMA\t# ( ƃ → b̄ ) LATIN SMALL LETTER B WITH TOPBAR → LATIN SMALL LETTER B, COMBINING MACRON\t# \n0182 ;\t0062 0304 ;\tMA\t# ( Ƃ → b̄ ) LATIN CAPITAL LETTER B WITH TOPBAR → LATIN SMALL LETTER B, COMBINING MACRON\t# \n0411 ;\t0062 0304 ;\tMA\t# ( Б → b̄ ) CYRILLIC CAPITAL LETTER BE → LATIN SMALL LETTER B, COMBINING MACRON\t# →Ƃ→\n\n0180 ;\t0062 0335 ;\tMA\t# ( ƀ → b̵ ) LATIN SMALL LETTER B WITH STROKE → LATIN SMALL LETTER B, COMBINING SHORT STROKE OVERLAY\t# \n048D ;\t0062 0335 ;\tMA\t# ( ҍ → b̵ ) CYRILLIC SMALL LETTER SEMISOFT SIGN → LATIN SMALL LETTER B, COMBINING SHORT STROKE OVERLAY\t# →ѣ→→Ь̵→\n048C ;\t0062 0335 ;\tMA\t# ( Ҍ → b̵ ) CYRILLIC CAPITAL LETTER SEMISOFT SIGN → LATIN SMALL LETTER B, COMBINING SHORT STROKE OVERLAY\t# →Ѣ→→Ь̵→\n0463 ;\t0062 0335 ;\tMA\t# ( ѣ → b̵ ) CYRILLIC SMALL LETTER YAT → LATIN SMALL LETTER B, COMBINING SHORT STROKE OVERLAY\t# →Ь̵→\n0462 ;\t0062 0335 ;\tMA\t# ( Ѣ → b̵ ) CYRILLIC CAPITAL LETTER YAT → LATIN SMALL LETTER B, COMBINING SHORT STROKE OVERLAY\t# →Ь̵→\n\n147F ;\t0062 00B7 ;\tMA\t# ( ᑿ → b· ) CANADIAN SYLLABICS WEST-CREE KWA → LATIN SMALL LETTER B, MIDDLE DOT\t# →ᑲᐧ→\n\n1481 ;\t0062 0307 00B7 ;\tMA\t# ( ᒁ → ḃ· ) CANADIAN SYLLABICS WEST-CREE KWAA → LATIN SMALL LETTER B, COMBINING DOT ABOVE, MIDDLE DOT\t# →ᑳᐧ→\n\n1488 ;\t0062 0027 ;\tMA\t# ( ᒈ → b' ) CANADIAN SYLLABICS SOUTH-SLAVEY KAH → LATIN SMALL LETTER B, APOSTROPHE\t# →ᑲᑊ→\n\n042B ;\t0062 006C ;\tMA\t# ( Ы → bl ) CYRILLIC CAPITAL LETTER YERU → LATIN SMALL LETTER B, LATIN SMALL LETTER L\t# →ЬІ→→Ь1→\n\n2C83 ;\t0299 ;\tMA\t# ( ⲃ → ʙ ) COPTIC SMALL LETTER VIDA → LATIN LETTER SMALL CAPITAL B\t# →в→\n0432 ;\t0299 ;\tMA\t# ( в → ʙ ) CYRILLIC SMALL LETTER VE → LATIN LETTER SMALL CAPITAL B\t# \n13FC ;\t0299 ;\tMA\t# ( ᏼ → ʙ ) CHEROKEE SMALL LETTER YV → LATIN LETTER SMALL CAPITAL B\t# \n\nFF43 ;\t0063 ;\tMA\t# ( ｃ → c ) FULLWIDTH LATIN SMALL LETTER C → LATIN SMALL LETTER C\t# →с→\n217D ;\t0063 ;\tMA\t# ( ⅽ → c ) SMALL ROMAN NUMERAL ONE HUNDRED → LATIN SMALL LETTER C\t# \n1D41C ;\t0063 ;\tMA\t# ( 𝐜 → c ) MATHEMATICAL BOLD SMALL C → LATIN SMALL LETTER C\t# \n1D450 ;\t0063 ;\tMA\t# ( 𝑐 → c ) MATHEMATICAL ITALIC SMALL C → LATIN SMALL LETTER C\t# \n1D484 ;\t0063 ;\tMA\t# ( 𝒄 → c ) MATHEMATICAL BOLD ITALIC SMALL C → LATIN SMALL LETTER C\t# \n1D4B8 ;\t0063 ;\tMA\t# ( 𝒸 → c ) MATHEMATICAL SCRIPT SMALL C → LATIN SMALL LETTER C\t# \n1D4EC ;\t0063 ;\tMA\t# ( 𝓬 → c ) MATHEMATICAL BOLD SCRIPT SMALL C → LATIN SMALL LETTER C\t# \n1D520 ;\t0063 ;\tMA\t# ( 𝔠 → c ) MATHEMATICAL FRAKTUR SMALL C → LATIN SMALL LETTER C\t# \n1D554 ;\t0063 ;\tMA\t# ( 𝕔 → c ) MATHEMATICAL DOUBLE-STRUCK SMALL C → LATIN SMALL LETTER C\t# \n1D588 ;\t0063 ;\tMA\t# ( 𝖈 → c ) MATHEMATICAL BOLD FRAKTUR SMALL C → LATIN SMALL LETTER C\t# \n1D5BC ;\t0063 ;\tMA\t# ( 𝖼 → c ) MATHEMATICAL SANS-SERIF SMALL C → LATIN SMALL LETTER C\t# \n1D5F0 ;\t0063 ;\tMA\t# ( 𝗰 → c ) MATHEMATICAL SANS-SERIF BOLD SMALL C → LATIN SMALL LETTER C\t# \n1D624 ;\t0063 ;\tMA\t# ( 𝘤 → c ) MATHEMATICAL SANS-SERIF ITALIC SMALL C → LATIN SMALL LETTER C\t# \n1D658 ;\t0063 ;\tMA\t# ( 𝙘 → c ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C → LATIN SMALL LETTER C\t# \n1D68C ;\t0063 ;\tMA\t# ( 𝚌 → c ) MATHEMATICAL MONOSPACE SMALL C → LATIN SMALL LETTER C\t# \n1D04 ;\t0063 ;\tMA\t# ( ᴄ → c ) LATIN LETTER SMALL CAPITAL C → LATIN SMALL LETTER C\t# \n03F2 ;\t0063 ;\tMA\t# ( ϲ → c ) GREEK LUNATE SIGMA SYMBOL → LATIN SMALL LETTER C\t# \n2CA5 ;\t0063 ;\tMA\t# ( ⲥ → c ) COPTIC SMALL LETTER SIMA → LATIN SMALL LETTER C\t# →ϲ→\n0441 ;\t0063 ;\tMA\t# ( с → c ) CYRILLIC SMALL LETTER ES → LATIN SMALL LETTER C\t# \n1004 ;\t0063 ;\tMA\t# ( င → c ) MYANMAR LETTER NGA → LATIN SMALL LETTER C\t# \n105A ;\t0063 ;\tMA\t# ( ၚ → c ) MYANMAR LETTER MON NGA → LATIN SMALL LETTER C\t# →င→\nABAF ;\t0063 ;\tMA\t# ( ꮯ → c ) CHEROKEE SMALL LETTER TLI → LATIN SMALL LETTER C\t# →ᴄ→\n1043D ;\t0063 ;\tMA\t# ( 𐐽 → c ) DESERET SMALL LETTER CHEE → LATIN SMALL LETTER C\t# \n\n2DED ;\t0368 ;\tMA\t# ( ⷭ → ͨ ) COMBINING CYRILLIC LETTER ES → COMBINING LATIN SMALL LETTER C\t# \n\n1F74C ;\t0043 ;\tMA\t#* ( 🝌 → C ) ALCHEMICAL SYMBOL FOR CALX → LATIN CAPITAL LETTER C\t# \n118E9 ;\t0043 ;\tMA\t# ( 𑣩 → C ) WARANG CITI DIGIT NINE → LATIN CAPITAL LETTER C\t# \n118F2 ;\t0043 ;\tMA\t#* ( 𑣲 → C ) WARANG CITI NUMBER NINETY → LATIN CAPITAL LETTER C\t# \nFF23 ;\t0043 ;\tMA\t# ( Ｃ → C ) FULLWIDTH LATIN CAPITAL LETTER C → LATIN CAPITAL LETTER C\t# →С→\n216D ;\t0043 ;\tMA\t# ( Ⅽ → C ) ROMAN NUMERAL ONE HUNDRED → LATIN CAPITAL LETTER C\t# \n2102 ;\t0043 ;\tMA\t# ( ℂ → C ) DOUBLE-STRUCK CAPITAL C → LATIN CAPITAL LETTER C\t# \n212D ;\t0043 ;\tMA\t# ( ℭ → C ) BLACK-LETTER CAPITAL C → LATIN CAPITAL LETTER C\t# \n1CCD8 ;\t0043 ;\tMA\t#* ( 𜳘 → C ) OUTLINED LATIN CAPITAL LETTER C → LATIN CAPITAL LETTER C\t# \n1D402 ;\t0043 ;\tMA\t# ( 𝐂 → C ) MATHEMATICAL BOLD CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D436 ;\t0043 ;\tMA\t# ( 𝐶 → C ) MATHEMATICAL ITALIC CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D46A ;\t0043 ;\tMA\t# ( 𝑪 → C ) MATHEMATICAL BOLD ITALIC CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D49E ;\t0043 ;\tMA\t# ( 𝒞 → C ) MATHEMATICAL SCRIPT CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D4D2 ;\t0043 ;\tMA\t# ( 𝓒 → C ) MATHEMATICAL BOLD SCRIPT CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D56E ;\t0043 ;\tMA\t# ( 𝕮 → C ) MATHEMATICAL BOLD FRAKTUR CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D5A2 ;\t0043 ;\tMA\t# ( 𝖢 → C ) MATHEMATICAL SANS-SERIF CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D5D6 ;\t0043 ;\tMA\t# ( 𝗖 → C ) MATHEMATICAL SANS-SERIF BOLD CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D60A ;\t0043 ;\tMA\t# ( 𝘊 → C ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D63E ;\t0043 ;\tMA\t# ( 𝘾 → C ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C → LATIN CAPITAL LETTER C\t# \n1D672 ;\t0043 ;\tMA\t# ( 𝙲 → C ) MATHEMATICAL MONOSPACE CAPITAL C → LATIN CAPITAL LETTER C\t# \n03F9 ;\t0043 ;\tMA\t# ( Ϲ → C ) GREEK CAPITAL LUNATE SIGMA SYMBOL → LATIN CAPITAL LETTER C\t# \n2CA4 ;\t0043 ;\tMA\t# ( Ⲥ → C ) COPTIC CAPITAL LETTER SIMA → LATIN CAPITAL LETTER C\t# →Ϲ→\n0421 ;\t0043 ;\tMA\t# ( С → C ) CYRILLIC CAPITAL LETTER ES → LATIN CAPITAL LETTER C\t# \n13DF ;\t0043 ;\tMA\t# ( Ꮯ → C ) CHEROKEE LETTER TLI → LATIN CAPITAL LETTER C\t# \nA4DA ;\t0043 ;\tMA\t# ( ꓚ → C ) LISU LETTER CA → LATIN CAPITAL LETTER C\t# \n102A2 ;\t0043 ;\tMA\t# ( 𐊢 → C ) CARIAN LETTER D → LATIN CAPITAL LETTER C\t# \n10302 ;\t0043 ;\tMA\t# ( 𐌂 → C ) OLD ITALIC LETTER KE → LATIN CAPITAL LETTER C\t# \n10415 ;\t0043 ;\tMA\t# ( 𐐕 → C ) DESERET CAPITAL LETTER CHEE → LATIN CAPITAL LETTER C\t# \n1051C ;\t0043 ;\tMA\t# ( 𐔜 → C ) ELBASAN LETTER SHE → LATIN CAPITAL LETTER C\t# \n\n00A2 ;\t0063 0338 ;\tMA\t#* ( ¢ → c̸ ) CENT SIGN → LATIN SMALL LETTER C, COMBINING LONG SOLIDUS OVERLAY\t# \n023C ;\t0063 0338 ;\tMA\t# ( ȼ → c̸ ) LATIN SMALL LETTER C WITH STROKE → LATIN SMALL LETTER C, COMBINING LONG SOLIDUS OVERLAY\t# →¢→\n\n20A1 ;\t0043 20EB ;\tMA\t#* ( ₡ → C⃫ ) COLON SIGN → LATIN CAPITAL LETTER C, COMBINING LONG DOUBLE SOLIDUS OVERLAY\t# \n\n1F16E ;\t0043 20E0 ;\tMA\t#* ( 🅮 → C⃠ ) CIRCLED C WITH OVERLAID BACKSLASH → LATIN CAPITAL LETTER C, COMBINING ENCLOSING CIRCLE BACKSLASH\t# \n\n00E7 ;\t0063 0326 ;\tMA\t# ( ç → c̦ ) LATIN SMALL LETTER C WITH CEDILLA → LATIN SMALL LETTER C, COMBINING COMMA BELOW\t# →ҫ→→с̡→\n04AB ;\t0063 0326 ;\tMA\t# ( ҫ → c̦ ) CYRILLIC SMALL LETTER ES WITH DESCENDER → LATIN SMALL LETTER C, COMBINING COMMA BELOW\t# →с̡→\n\n00C7 ;\t0043 0326 ;\tMA\t# ( Ç → C̦ ) LATIN CAPITAL LETTER C WITH CEDILLA → LATIN CAPITAL LETTER C, COMBINING COMMA BELOW\t# →Ҫ→→С̡→\n04AA ;\t0043 0326 ;\tMA\t# ( Ҫ → C̦ ) CYRILLIC CAPITAL LETTER ES WITH DESCENDER → LATIN CAPITAL LETTER C, COMBINING COMMA BELOW\t# →С̡→\n\n0187 ;\t0043 0027 ;\tMA\t# ( Ƈ → C' ) LATIN CAPITAL LETTER C WITH HOOK → LATIN CAPITAL LETTER C, APOSTROPHE\t# →Cʽ→\n\n2105 ;\t0063 002F 006F ;\tMA\t#* ( ℅ → c/o ) CARE OF → LATIN SMALL LETTER C, SOLIDUS, LATIN SMALL LETTER O\t# \n\n2106 ;\t0063 002F 0075 ;\tMA\t#* ( ℆ → c/u ) CADA UNA → LATIN SMALL LETTER C, SOLIDUS, LATIN SMALL LETTER U\t# \n\n1F16D ;\t33C4 0009 20DD ;\tMA\t#* ( 🅭 →  ) CIRCLED CC → SQUARE CC, <CHARACTER TABULATION>, COMBINING ENCLOSING CIRCLE\t# \n\n22F4 ;\tA793 ;\tMA\t#* ( ⋴ → ꞓ ) SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE → LATIN SMALL LETTER C WITH BAR\t# →ɛ→→є→\n025B ;\tA793 ;\tMA\t# ( ɛ → ꞓ ) LATIN SMALL LETTER OPEN E → LATIN SMALL LETTER C WITH BAR\t# →є→\n03B5 ;\tA793 ;\tMA\t# ( ε → ꞓ ) GREEK SMALL LETTER EPSILON → LATIN SMALL LETTER C WITH BAR\t# →є→\n03F5 ;\tA793 ;\tMA\t# ( ϵ → ꞓ ) GREEK LUNATE EPSILON SYMBOL → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D6C6 ;\tA793 ;\tMA\t# ( 𝛆 → ꞓ ) MATHEMATICAL BOLD SMALL EPSILON → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D6DC ;\tA793 ;\tMA\t# ( 𝛜 → ꞓ ) MATHEMATICAL BOLD EPSILON SYMBOL → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D700 ;\tA793 ;\tMA\t# ( 𝜀 → ꞓ ) MATHEMATICAL ITALIC SMALL EPSILON → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D716 ;\tA793 ;\tMA\t# ( 𝜖 → ꞓ ) MATHEMATICAL ITALIC EPSILON SYMBOL → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D73A ;\tA793 ;\tMA\t# ( 𝜺 → ꞓ ) MATHEMATICAL BOLD ITALIC SMALL EPSILON → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D750 ;\tA793 ;\tMA\t# ( 𝝐 → ꞓ ) MATHEMATICAL BOLD ITALIC EPSILON SYMBOL → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D774 ;\tA793 ;\tMA\t# ( 𝝴 → ꞓ ) MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D78A ;\tA793 ;\tMA\t# ( 𝞊 → ꞓ ) MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D7AE ;\tA793 ;\tMA\t# ( 𝞮 → ꞓ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n1D7C4 ;\tA793 ;\tMA\t# ( 𝟄 → ꞓ ) MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n2C89 ;\tA793 ;\tMA\t# ( ⲉ → ꞓ ) COPTIC SMALL LETTER EIE → LATIN SMALL LETTER C WITH BAR\t# →є→\n0454 ;\tA793 ;\tMA\t# ( є → ꞓ ) CYRILLIC SMALL LETTER UKRAINIAN IE → LATIN SMALL LETTER C WITH BAR\t# \n0511 ;\tA793 ;\tMA\t# ( ԑ → ꞓ ) CYRILLIC SMALL LETTER REVERSED ZE → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\nAB9B ;\tA793 ;\tMA\t# ( ꮛ → ꞓ ) CHEROKEE SMALL LETTER QUV → LATIN SMALL LETTER C WITH BAR\t# →ɛ→→є→\n118CE ;\tA793 ;\tMA\t# ( 𑣎 → ꞓ ) WARANG CITI SMALL LETTER YUJ → LATIN SMALL LETTER C WITH BAR\t# →ε→→є→\n10429 ;\tA793 ;\tMA\t# ( 𐐩 → ꞓ ) DESERET SMALL LETTER LONG E → LATIN SMALL LETTER C WITH BAR\t# →ɛ→→є→\n\n20AC ;\tA792 ;\tMA\t#* ( € → Ꞓ ) EURO SIGN → LATIN CAPITAL LETTER C WITH BAR\t# →Є→\n2C88 ;\tA792 ;\tMA\t# ( Ⲉ → Ꞓ ) COPTIC CAPITAL LETTER EIE → LATIN CAPITAL LETTER C WITH BAR\t# →Є→\n0404 ;\tA792 ;\tMA\t# ( Є → Ꞓ ) CYRILLIC CAPITAL LETTER UKRAINIAN IE → LATIN CAPITAL LETTER C WITH BAR\t# \n\n2377 ;\tA793 0332 ;\tMA\t#* ( ⍷ → ꞓ̲ ) APL FUNCTIONAL SYMBOL EPSILON UNDERBAR → LATIN SMALL LETTER C WITH BAR, COMBINING LOW LINE\t# →ε̲→\n\n037D ;\tA73F ;\tMA\t# ( ͽ → ꜿ ) GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL → LATIN SMALL LETTER REVERSED C WITH DOT\t# \n\n03FF ;\tA73E ;\tMA\t# ( Ͽ → Ꜿ ) GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL → LATIN CAPITAL LETTER REVERSED C WITH DOT\t# \n\n217E ;\t0064 ;\tMA\t# ( ⅾ → d ) SMALL ROMAN NUMERAL FIVE HUNDRED → LATIN SMALL LETTER D\t# \n2146 ;\t0064 ;\tMA\t# ( ⅆ → d ) DOUBLE-STRUCK ITALIC SMALL D → LATIN SMALL LETTER D\t# \n1D41D ;\t0064 ;\tMA\t# ( 𝐝 → d ) MATHEMATICAL BOLD SMALL D → LATIN SMALL LETTER D\t# \n1D451 ;\t0064 ;\tMA\t# ( 𝑑 → d ) MATHEMATICAL ITALIC SMALL D → LATIN SMALL LETTER D\t# \n1D485 ;\t0064 ;\tMA\t# ( 𝒅 → d ) MATHEMATICAL BOLD ITALIC SMALL D → LATIN SMALL LETTER D\t# \n1D4B9 ;\t0064 ;\tMA\t# ( 𝒹 → d ) MATHEMATICAL SCRIPT SMALL D → LATIN SMALL LETTER D\t# \n1D4ED ;\t0064 ;\tMA\t# ( 𝓭 → d ) MATHEMATICAL BOLD SCRIPT SMALL D → LATIN SMALL LETTER D\t# \n1D521 ;\t0064 ;\tMA\t# ( 𝔡 → d ) MATHEMATICAL FRAKTUR SMALL D → LATIN SMALL LETTER D\t# \n1D555 ;\t0064 ;\tMA\t# ( 𝕕 → d ) MATHEMATICAL DOUBLE-STRUCK SMALL D → LATIN SMALL LETTER D\t# \n1D589 ;\t0064 ;\tMA\t# ( 𝖉 → d ) MATHEMATICAL BOLD FRAKTUR SMALL D → LATIN SMALL LETTER D\t# \n1D5BD ;\t0064 ;\tMA\t# ( 𝖽 → d ) MATHEMATICAL SANS-SERIF SMALL D → LATIN SMALL LETTER D\t# \n1D5F1 ;\t0064 ;\tMA\t# ( 𝗱 → d ) MATHEMATICAL SANS-SERIF BOLD SMALL D → LATIN SMALL LETTER D\t# \n1D625 ;\t0064 ;\tMA\t# ( 𝘥 → d ) MATHEMATICAL SANS-SERIF ITALIC SMALL D → LATIN SMALL LETTER D\t# \n1D659 ;\t0064 ;\tMA\t# ( 𝙙 → d ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D → LATIN SMALL LETTER D\t# \n1D68D ;\t0064 ;\tMA\t# ( 𝚍 → d ) MATHEMATICAL MONOSPACE SMALL D → LATIN SMALL LETTER D\t# \n0501 ;\t0064 ;\tMA\t# ( ԁ → d ) CYRILLIC SMALL LETTER KOMI DE → LATIN SMALL LETTER D\t# \n13E7 ;\t0064 ;\tMA\t# ( Ꮷ → d ) CHEROKEE LETTER TSU → LATIN SMALL LETTER D\t# \n146F ;\t0064 ;\tMA\t# ( ᑯ → d ) CANADIAN SYLLABICS KO → LATIN SMALL LETTER D\t# \nA4D2 ;\t0064 ;\tMA\t# ( ꓒ → d ) LISU LETTER PHA → LATIN SMALL LETTER D\t# \n\n216E ;\t0044 ;\tMA\t# ( Ⅾ → D ) ROMAN NUMERAL FIVE HUNDRED → LATIN CAPITAL LETTER D\t# \n2145 ;\t0044 ;\tMA\t# ( ⅅ → D ) DOUBLE-STRUCK ITALIC CAPITAL D → LATIN CAPITAL LETTER D\t# \n1CCD9 ;\t0044 ;\tMA\t#* ( 𜳙 → D ) OUTLINED LATIN CAPITAL LETTER D → LATIN CAPITAL LETTER D\t# \n1D403 ;\t0044 ;\tMA\t# ( 𝐃 → D ) MATHEMATICAL BOLD CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D437 ;\t0044 ;\tMA\t# ( 𝐷 → D ) MATHEMATICAL ITALIC CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D46B ;\t0044 ;\tMA\t# ( 𝑫 → D ) MATHEMATICAL BOLD ITALIC CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D49F ;\t0044 ;\tMA\t# ( 𝒟 → D ) MATHEMATICAL SCRIPT CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D4D3 ;\t0044 ;\tMA\t# ( 𝓓 → D ) MATHEMATICAL BOLD SCRIPT CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D507 ;\t0044 ;\tMA\t# ( 𝔇 → D ) MATHEMATICAL FRAKTUR CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D53B ;\t0044 ;\tMA\t# ( 𝔻 → D ) MATHEMATICAL DOUBLE-STRUCK CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D56F ;\t0044 ;\tMA\t# ( 𝕯 → D ) MATHEMATICAL BOLD FRAKTUR CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D5A3 ;\t0044 ;\tMA\t# ( 𝖣 → D ) MATHEMATICAL SANS-SERIF CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D5D7 ;\t0044 ;\tMA\t# ( 𝗗 → D ) MATHEMATICAL SANS-SERIF BOLD CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D60B ;\t0044 ;\tMA\t# ( 𝘋 → D ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D63F ;\t0044 ;\tMA\t# ( 𝘿 → D ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D → LATIN CAPITAL LETTER D\t# \n1D673 ;\t0044 ;\tMA\t# ( 𝙳 → D ) MATHEMATICAL MONOSPACE CAPITAL D → LATIN CAPITAL LETTER D\t# \n13A0 ;\t0044 ;\tMA\t# ( Ꭰ → D ) CHEROKEE LETTER A → LATIN CAPITAL LETTER D\t# \n15DE ;\t0044 ;\tMA\t# ( ᗞ → D ) CANADIAN SYLLABICS CARRIER THE → LATIN CAPITAL LETTER D\t# \n15EA ;\t0044 ;\tMA\t# ( ᗪ → D ) CANADIAN SYLLABICS CARRIER PE → LATIN CAPITAL LETTER D\t# →ᗞ→\nA4D3 ;\t0044 ;\tMA\t# ( ꓓ → D ) LISU LETTER DA → LATIN CAPITAL LETTER D\t# \n\n0257 ;\t0064 0314 ;\tMA\t# ( ɗ → d̔ ) LATIN SMALL LETTER D WITH HOOK → LATIN SMALL LETTER D, COMBINING REVERSED COMMA ABOVE\t# \n\n0256 ;\t0064 0328 ;\tMA\t# ( ɖ → d̨ ) LATIN SMALL LETTER D WITH TAIL → LATIN SMALL LETTER D, COMBINING OGONEK\t# →d̢→\n\n018C ;\t0064 0304 ;\tMA\t# ( ƌ → d̄ ) LATIN SMALL LETTER D WITH TOPBAR → LATIN SMALL LETTER D, COMBINING MACRON\t# \n\n0111 ;\t0064 0335 ;\tMA\t# ( đ → d̵ ) LATIN SMALL LETTER D WITH STROKE → LATIN SMALL LETTER D, COMBINING SHORT STROKE OVERLAY\t# \n\n0110 ;\t0044 0335 ;\tMA\t# ( Đ → D̵ ) LATIN CAPITAL LETTER D WITH STROKE → LATIN CAPITAL LETTER D, COMBINING SHORT STROKE OVERLAY\t# \n00D0 ;\t0044 0335 ;\tMA\t# ( Ð → D̵ ) LATIN CAPITAL LETTER ETH → LATIN CAPITAL LETTER D, COMBINING SHORT STROKE OVERLAY\t# →Đ→\n0189 ;\t0044 0335 ;\tMA\t# ( Ɖ → D̵ ) LATIN CAPITAL LETTER AFRICAN D → LATIN CAPITAL LETTER D, COMBINING SHORT STROKE OVERLAY\t# →Đ→\n\n20AB ;\t0064 0335 0331 ;\tMA\t#* ( ₫ → ḏ̵ ) DONG SIGN → LATIN SMALL LETTER D, COMBINING SHORT STROKE OVERLAY, COMBINING MACRON BELOW\t# →đ̱→\n\nA77A ;\tA779 ;\tMA\t# ( ꝺ → Ꝺ ) LATIN SMALL LETTER INSULAR D → LATIN CAPITAL LETTER INSULAR D\t# \n\n147B ;\t0064 00B7 ;\tMA\t# ( ᑻ → d· ) CANADIAN SYLLABICS WEST-CREE KWO → LATIN SMALL LETTER D, MIDDLE DOT\t# →ᑯᐧ→\n\n1487 ;\t0064 0027 ;\tMA\t# ( ᒇ → d' ) CANADIAN SYLLABICS SOUTH-SLAVEY KOH → LATIN SMALL LETTER D, APOSTROPHE\t# →ᑯᑊ→\n\n02A4 ;\t0064 021D ;\tMA\t# ( ʤ → dȝ ) LATIN SMALL LETTER DEZH DIGRAPH → LATIN SMALL LETTER D, LATIN SMALL LETTER YOGH\t# →dʒ→\n\n01F3 ;\t0064 007A ;\tMA\t# ( ǳ → dz ) LATIN SMALL LETTER DZ → LATIN SMALL LETTER D, LATIN SMALL LETTER Z\t# \n02A3 ;\t0064 007A ;\tMA\t# ( ʣ → dz ) LATIN SMALL LETTER DZ DIGRAPH → LATIN SMALL LETTER D, LATIN SMALL LETTER Z\t# \n\n01F2 ;\t0044 007A ;\tMA\t# ( ǲ → Dz ) LATIN CAPITAL LETTER D WITH SMALL LETTER Z → LATIN CAPITAL LETTER D, LATIN SMALL LETTER Z\t# \n\n01F1 ;\t0044 005A ;\tMA\t# ( Ǳ → DZ ) LATIN CAPITAL LETTER DZ → LATIN CAPITAL LETTER D, LATIN CAPITAL LETTER Z\t# \n\n01C6 ;\t0064 017E ;\tMA\t# ( ǆ → dž ) LATIN SMALL LETTER DZ WITH CARON → LATIN SMALL LETTER D, LATIN SMALL LETTER Z WITH CARON\t# \n\n01C5 ;\t0044 017E ;\tMA\t# ( ǅ → Dž ) LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON → LATIN CAPITAL LETTER D, LATIN SMALL LETTER Z WITH CARON\t# \n\n01C4 ;\t0044 017D ;\tMA\t# ( Ǆ → DŽ ) LATIN CAPITAL LETTER DZ WITH CARON → LATIN CAPITAL LETTER D, LATIN CAPITAL LETTER Z WITH CARON\t# \n\n02A5 ;\t0064 0291 ;\tMA\t# ( ʥ → dʑ ) LATIN SMALL LETTER DZ DIGRAPH WITH CURL → LATIN SMALL LETTER D, LATIN SMALL LETTER Z WITH CURL\t# \n\nAB70 ;\t1D05 ;\tMA\t# ( ꭰ → ᴅ ) CHEROKEE SMALL LETTER A → LATIN LETTER SMALL CAPITAL D\t# \n\n2E39 ;\t1E9F ;\tMA\t#* ( ⸹ → ẟ ) TOP HALF SECTION SIGN → LATIN SMALL LETTER DELTA\t# →δ→\n03B4 ;\t1E9F ;\tMA\t# ( δ → ẟ ) GREEK SMALL LETTER DELTA → LATIN SMALL LETTER DELTA\t# \n1D6C5 ;\t1E9F ;\tMA\t# ( 𝛅 → ẟ ) MATHEMATICAL BOLD SMALL DELTA → LATIN SMALL LETTER DELTA\t# →δ→\n1D6FF ;\t1E9F ;\tMA\t# ( 𝛿 → ẟ ) MATHEMATICAL ITALIC SMALL DELTA → LATIN SMALL LETTER DELTA\t# →δ→\n1D739 ;\t1E9F ;\tMA\t# ( 𝜹 → ẟ ) MATHEMATICAL BOLD ITALIC SMALL DELTA → LATIN SMALL LETTER DELTA\t# →δ→\n1D773 ;\t1E9F ;\tMA\t# ( 𝝳 → ẟ ) MATHEMATICAL SANS-SERIF BOLD SMALL DELTA → LATIN SMALL LETTER DELTA\t# →δ→\n1D7AD ;\t1E9F ;\tMA\t# ( 𝞭 → ẟ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA → LATIN SMALL LETTER DELTA\t# →δ→\n2CDD ;\t1E9F ;\tMA\t# ( ⳝ → ẟ ) COPTIC SMALL LETTER OLD NUBIAN SHIMA → LATIN SMALL LETTER DELTA\t# →δ→\n056E ;\t1E9F ;\tMA\t# ( ծ → ẟ ) ARMENIAN SMALL LETTER CA → LATIN SMALL LETTER DELTA\t# →δ→\n1577 ;\t1E9F ;\tMA\t# ( ᕷ → ẟ ) CANADIAN SYLLABICS NUNAVIK HO → LATIN SMALL LETTER DELTA\t# →δ→\n\n212E ;\t0065 ;\tMA\t# ( ℮ → e ) ESTIMATED SYMBOL → LATIN SMALL LETTER E\t# \nFF45 ;\t0065 ;\tMA\t# ( ｅ → e ) FULLWIDTH LATIN SMALL LETTER E → LATIN SMALL LETTER E\t# →е→\n212F ;\t0065 ;\tMA\t# ( ℯ → e ) SCRIPT SMALL E → LATIN SMALL LETTER E\t# \n2147 ;\t0065 ;\tMA\t# ( ⅇ → e ) DOUBLE-STRUCK ITALIC SMALL E → LATIN SMALL LETTER E\t# \n1D41E ;\t0065 ;\tMA\t# ( 𝐞 → e ) MATHEMATICAL BOLD SMALL E → LATIN SMALL LETTER E\t# \n1D452 ;\t0065 ;\tMA\t# ( 𝑒 → e ) MATHEMATICAL ITALIC SMALL E → LATIN SMALL LETTER E\t# \n1D486 ;\t0065 ;\tMA\t# ( 𝒆 → e ) MATHEMATICAL BOLD ITALIC SMALL E → LATIN SMALL LETTER E\t# \n1D4EE ;\t0065 ;\tMA\t# ( 𝓮 → e ) MATHEMATICAL BOLD SCRIPT SMALL E → LATIN SMALL LETTER E\t# \n1D522 ;\t0065 ;\tMA\t# ( 𝔢 → e ) MATHEMATICAL FRAKTUR SMALL E → LATIN SMALL LETTER E\t# \n1D556 ;\t0065 ;\tMA\t# ( 𝕖 → e ) MATHEMATICAL DOUBLE-STRUCK SMALL E → LATIN SMALL LETTER E\t# \n1D58A ;\t0065 ;\tMA\t# ( 𝖊 → e ) MATHEMATICAL BOLD FRAKTUR SMALL E → LATIN SMALL LETTER E\t# \n1D5BE ;\t0065 ;\tMA\t# ( 𝖾 → e ) MATHEMATICAL SANS-SERIF SMALL E → LATIN SMALL LETTER E\t# \n1D5F2 ;\t0065 ;\tMA\t# ( 𝗲 → e ) MATHEMATICAL SANS-SERIF BOLD SMALL E → LATIN SMALL LETTER E\t# \n1D626 ;\t0065 ;\tMA\t# ( 𝘦 → e ) MATHEMATICAL SANS-SERIF ITALIC SMALL E → LATIN SMALL LETTER E\t# \n1D65A ;\t0065 ;\tMA\t# ( 𝙚 → e ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E → LATIN SMALL LETTER E\t# \n1D68E ;\t0065 ;\tMA\t# ( 𝚎 → e ) MATHEMATICAL MONOSPACE SMALL E → LATIN SMALL LETTER E\t# \nAB32 ;\t0065 ;\tMA\t# ( ꬲ → e ) LATIN SMALL LETTER BLACKLETTER E → LATIN SMALL LETTER E\t# \n0435 ;\t0065 ;\tMA\t# ( е → e ) CYRILLIC SMALL LETTER IE → LATIN SMALL LETTER E\t# \n04BD ;\t0065 ;\tMA\t# ( ҽ → e ) CYRILLIC SMALL LETTER ABKHASIAN CHE → LATIN SMALL LETTER E\t# \n\n2DF7 ;\t0364 ;\tMA\t# ( ⷷ → ͤ ) COMBINING CYRILLIC LETTER IE → COMBINING LATIN SMALL LETTER E\t# \n\n22FF ;\t0045 ;\tMA\t#* ( ⋿ → E ) Z NOTATION BAG MEMBERSHIP → LATIN CAPITAL LETTER E\t# \nFF25 ;\t0045 ;\tMA\t# ( Ｅ → E ) FULLWIDTH LATIN CAPITAL LETTER E → LATIN CAPITAL LETTER E\t# →Ε→\n2130 ;\t0045 ;\tMA\t# ( ℰ → E ) SCRIPT CAPITAL E → LATIN CAPITAL LETTER E\t# \n1CCDA ;\t0045 ;\tMA\t#* ( 𜳚 → E ) OUTLINED LATIN CAPITAL LETTER E → LATIN CAPITAL LETTER E\t# \n1D404 ;\t0045 ;\tMA\t# ( 𝐄 → E ) MATHEMATICAL BOLD CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D438 ;\t0045 ;\tMA\t# ( 𝐸 → E ) MATHEMATICAL ITALIC CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D46C ;\t0045 ;\tMA\t# ( 𝑬 → E ) MATHEMATICAL BOLD ITALIC CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D4D4 ;\t0045 ;\tMA\t# ( 𝓔 → E ) MATHEMATICAL BOLD SCRIPT CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D508 ;\t0045 ;\tMA\t# ( 𝔈 → E ) MATHEMATICAL FRAKTUR CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D53C ;\t0045 ;\tMA\t# ( 𝔼 → E ) MATHEMATICAL DOUBLE-STRUCK CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D570 ;\t0045 ;\tMA\t# ( 𝕰 → E ) MATHEMATICAL BOLD FRAKTUR CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D5A4 ;\t0045 ;\tMA\t# ( 𝖤 → E ) MATHEMATICAL SANS-SERIF CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D5D8 ;\t0045 ;\tMA\t# ( 𝗘 → E ) MATHEMATICAL SANS-SERIF BOLD CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D60C ;\t0045 ;\tMA\t# ( 𝘌 → E ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D640 ;\t0045 ;\tMA\t# ( 𝙀 → E ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E → LATIN CAPITAL LETTER E\t# \n1D674 ;\t0045 ;\tMA\t# ( 𝙴 → E ) MATHEMATICAL MONOSPACE CAPITAL E → LATIN CAPITAL LETTER E\t# \n0395 ;\t0045 ;\tMA\t# ( Ε → E ) GREEK CAPITAL LETTER EPSILON → LATIN CAPITAL LETTER E\t# \n1D6AC ;\t0045 ;\tMA\t# ( 𝚬 → E ) MATHEMATICAL BOLD CAPITAL EPSILON → LATIN CAPITAL LETTER E\t# →𝐄→\n1D6E6 ;\t0045 ;\tMA\t# ( 𝛦 → E ) MATHEMATICAL ITALIC CAPITAL EPSILON → LATIN CAPITAL LETTER E\t# →Ε→\n1D720 ;\t0045 ;\tMA\t# ( 𝜠 → E ) MATHEMATICAL BOLD ITALIC CAPITAL EPSILON → LATIN CAPITAL LETTER E\t# →Ε→\n1D75A ;\t0045 ;\tMA\t# ( 𝝚 → E ) MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON → LATIN CAPITAL LETTER E\t# →Ε→\n1D794 ;\t0045 ;\tMA\t# ( 𝞔 → E ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON → LATIN CAPITAL LETTER E\t# →Ε→\n0415 ;\t0045 ;\tMA\t# ( Е → E ) CYRILLIC CAPITAL LETTER IE → LATIN CAPITAL LETTER E\t# \n2D39 ;\t0045 ;\tMA\t# ( ⴹ → E ) TIFINAGH LETTER YADD → LATIN CAPITAL LETTER E\t# \n13AC ;\t0045 ;\tMA\t# ( Ꭼ → E ) CHEROKEE LETTER GV → LATIN CAPITAL LETTER E\t# \nA4F0 ;\t0045 ;\tMA\t# ( ꓰ → E ) LISU LETTER E → LATIN CAPITAL LETTER E\t# \n118A6 ;\t0045 ;\tMA\t# ( 𑢦 → E ) WARANG CITI CAPITAL LETTER II → LATIN CAPITAL LETTER E\t# \n118AE ;\t0045 ;\tMA\t# ( 𑢮 → E ) WARANG CITI CAPITAL LETTER YUJ → LATIN CAPITAL LETTER E\t# \n10286 ;\t0045 ;\tMA\t# ( 𐊆 → E ) LYCIAN LETTER I → LATIN CAPITAL LETTER E\t# \n\n011B ;\t0115 ;\tMA\t# ( ě → ĕ ) LATIN SMALL LETTER E WITH CARON → LATIN SMALL LETTER E WITH BREVE\t# \n\n011A ;\t0114 ;\tMA\t# ( Ě → Ĕ ) LATIN CAPITAL LETTER E WITH CARON → LATIN CAPITAL LETTER E WITH BREVE\t# \n\n0247 ;\t0065 0338 ;\tMA\t# ( ɇ → e̸ ) LATIN SMALL LETTER E WITH STROKE → LATIN SMALL LETTER E, COMBINING LONG SOLIDUS OVERLAY\t# →e̷→\n\n0246 ;\t0045 0338 ;\tMA\t# ( Ɇ → E̸ ) LATIN CAPITAL LETTER E WITH STROKE → LATIN CAPITAL LETTER E, COMBINING LONG SOLIDUS OVERLAY\t# \n\n04BF ;\t0065 0328 ;\tMA\t# ( ҿ → ę ) CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER → LATIN SMALL LETTER E, COMBINING OGONEK\t# →ҽ̢→\n\nAB7C ;\t1D07 ;\tMA\t# ( ꭼ → ᴇ ) CHEROKEE SMALL LETTER GV → LATIN LETTER SMALL CAPITAL E\t# \n\n0259 ;\t01DD ;\tMA\t# ( ə → ǝ ) LATIN SMALL LETTER SCHWA → LATIN SMALL LETTER TURNED E\t# \n04D9 ;\t01DD ;\tMA\t# ( ә → ǝ ) CYRILLIC SMALL LETTER SCHWA → LATIN SMALL LETTER TURNED E\t# \n\n2203 ;\t018E ;\tMA\t#* ( ∃ → Ǝ ) THERE EXISTS → LATIN CAPITAL LETTER REVERSED E\t# \n2D3A ;\t018E ;\tMA\t# ( ⴺ → Ǝ ) TIFINAGH LETTER YADDH → LATIN CAPITAL LETTER REVERSED E\t# \nA4F1 ;\t018E ;\tMA\t# ( ꓱ → Ǝ ) LISU LETTER EU → LATIN CAPITAL LETTER REVERSED E\t# \n\n025A ;\t01DD 02DE ;\tMA\t# ( ɚ → ǝ˞ ) LATIN SMALL LETTER SCHWA WITH HOOK → LATIN SMALL LETTER TURNED E, MODIFIER LETTER RHOTIC HOOK\t# →ə˞→\n\n1D14 ;\t01DD 006F ;\tMA\t# ( ᴔ → ǝo ) LATIN SMALL LETTER TURNED OE → LATIN SMALL LETTER TURNED E, LATIN SMALL LETTER O\t# →əo→\n\nAB41 ;\t01DD 006F 0338 ;\tMA\t# ( ꭁ → ǝo̸ ) LATIN SMALL LETTER TURNED OE WITH STROKE → LATIN SMALL LETTER TURNED E, LATIN SMALL LETTER O, COMBINING LONG SOLIDUS OVERLAY\t# →ǝø→\n\nAB42 ;\t01DD 006F 0335 ;\tMA\t# ( ꭂ → ǝo̵ ) LATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKE → LATIN SMALL LETTER TURNED E, LATIN SMALL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →ǝɵ→\n\n04D8 ;\t018F ;\tMA\t# ( Ә → Ə ) CYRILLIC CAPITAL LETTER SCHWA → LATIN CAPITAL LETTER SCHWA\t# \n\n1D221 ;\t0190 ;\tMA\t#* ( 𝈡 → Ɛ ) GREEK INSTRUMENTAL NOTATION SYMBOL-7 → LATIN CAPITAL LETTER OPEN E\t# \n2107 ;\t0190 ;\tMA\t# ( ℇ → Ɛ ) EULER CONSTANT → LATIN CAPITAL LETTER OPEN E\t# \n0510 ;\t0190 ;\tMA\t# ( Ԑ → Ɛ ) CYRILLIC CAPITAL LETTER REVERSED ZE → LATIN CAPITAL LETTER OPEN E\t# \n13CB ;\t0190 ;\tMA\t# ( Ꮛ → Ɛ ) CHEROKEE LETTER QUV → LATIN CAPITAL LETTER OPEN E\t# \n16F2D ;\t0190 ;\tMA\t# ( 𖼭 → Ɛ ) MIAO LETTER NYHA → LATIN CAPITAL LETTER OPEN E\t# \n10401 ;\t0190 ;\tMA\t# ( 𐐁 → Ɛ ) DESERET CAPITAL LETTER LONG E → LATIN CAPITAL LETTER OPEN E\t# \n\n1D9F ;\t1D4B ;\tMA\t# ( ᶟ → ᵋ ) MODIFIER LETTER SMALL REVERSED OPEN E → MODIFIER LETTER SMALL OPEN E\t# \n\n1D08 ;\t025C ;\tMA\t# ( ᴈ → ɜ ) LATIN SMALL LETTER TURNED OPEN E → LATIN SMALL LETTER REVERSED OPEN E\t# \n0437 ;\t025C ;\tMA\t# ( з → ɜ ) CYRILLIC SMALL LETTER ZE → LATIN SMALL LETTER REVERSED OPEN E\t# \n\n0499 ;\t025C 0326 ;\tMA\t# ( ҙ → ɜ̦ ) CYRILLIC SMALL LETTER ZE WITH DESCENDER → LATIN SMALL LETTER REVERSED OPEN E, COMBINING COMMA BELOW\t# →з̡→\n\n10442 ;\t025E ;\tMA\t# ( 𐑂 → ɞ ) DESERET SMALL LETTER VEE → LATIN SMALL LETTER CLOSED REVERSED OPEN E\t# \n\nA79D ;\t029A ;\tMA\t# ( ꞝ → ʚ ) LATIN SMALL LETTER VOLAPUK OE → LATIN SMALL LETTER CLOSED OPEN E\t# \n1042A ;\t029A ;\tMA\t# ( 𐐪 → ʚ ) DESERET SMALL LETTER LONG A → LATIN SMALL LETTER CLOSED OPEN E\t# \n\n1D41F ;\t0066 ;\tMA\t# ( 𝐟 → f ) MATHEMATICAL BOLD SMALL F → LATIN SMALL LETTER F\t# \n1D453 ;\t0066 ;\tMA\t# ( 𝑓 → f ) MATHEMATICAL ITALIC SMALL F → LATIN SMALL LETTER F\t# \n1D487 ;\t0066 ;\tMA\t# ( 𝒇 → f ) MATHEMATICAL BOLD ITALIC SMALL F → LATIN SMALL LETTER F\t# \n1D4BB ;\t0066 ;\tMA\t# ( 𝒻 → f ) MATHEMATICAL SCRIPT SMALL F → LATIN SMALL LETTER F\t# \n1D4EF ;\t0066 ;\tMA\t# ( 𝓯 → f ) MATHEMATICAL BOLD SCRIPT SMALL F → LATIN SMALL LETTER F\t# \n1D523 ;\t0066 ;\tMA\t# ( 𝔣 → f ) MATHEMATICAL FRAKTUR SMALL F → LATIN SMALL LETTER F\t# \n1D557 ;\t0066 ;\tMA\t# ( 𝕗 → f ) MATHEMATICAL DOUBLE-STRUCK SMALL F → LATIN SMALL LETTER F\t# \n1D58B ;\t0066 ;\tMA\t# ( 𝖋 → f ) MATHEMATICAL BOLD FRAKTUR SMALL F → LATIN SMALL LETTER F\t# \n1D5BF ;\t0066 ;\tMA\t# ( 𝖿 → f ) MATHEMATICAL SANS-SERIF SMALL F → LATIN SMALL LETTER F\t# \n1D5F3 ;\t0066 ;\tMA\t# ( 𝗳 → f ) MATHEMATICAL SANS-SERIF BOLD SMALL F → LATIN SMALL LETTER F\t# \n1D627 ;\t0066 ;\tMA\t# ( 𝘧 → f ) MATHEMATICAL SANS-SERIF ITALIC SMALL F → LATIN SMALL LETTER F\t# \n1D65B ;\t0066 ;\tMA\t# ( 𝙛 → f ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F → LATIN SMALL LETTER F\t# \n1D68F ;\t0066 ;\tMA\t# ( 𝚏 → f ) MATHEMATICAL MONOSPACE SMALL F → LATIN SMALL LETTER F\t# \nAB35 ;\t0066 ;\tMA\t# ( ꬵ → f ) LATIN SMALL LETTER LENIS F → LATIN SMALL LETTER F\t# \nA799 ;\t0066 ;\tMA\t# ( ꞙ → f ) LATIN SMALL LETTER F WITH STROKE → LATIN SMALL LETTER F\t# \n0192 ;\t0066 ;\tMA\t# ( ƒ → f ) LATIN SMALL LETTER F WITH HOOK → LATIN SMALL LETTER F\t# \n017F ;\t0066 ;\tMA\t# ( ſ → f ) LATIN SMALL LETTER LONG S → LATIN SMALL LETTER F\t# \n1E9D ;\t0066 ;\tMA\t# ( ẝ → f ) LATIN SMALL LETTER LONG S WITH HIGH STROKE → LATIN SMALL LETTER F\t# \n0584 ;\t0066 ;\tMA\t# ( ք → f ) ARMENIAN SMALL LETTER KEH → LATIN SMALL LETTER F\t# \n\n1D213 ;\t0046 ;\tMA\t#* ( 𝈓 → F ) GREEK VOCAL NOTATION SYMBOL-20 → LATIN CAPITAL LETTER F\t# →Ϝ→\n2131 ;\t0046 ;\tMA\t# ( ℱ → F ) SCRIPT CAPITAL F → LATIN CAPITAL LETTER F\t# \n1CCDB ;\t0046 ;\tMA\t#* ( 𜳛 → F ) OUTLINED LATIN CAPITAL LETTER F → LATIN CAPITAL LETTER F\t# \n1D405 ;\t0046 ;\tMA\t# ( 𝐅 → F ) MATHEMATICAL BOLD CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D439 ;\t0046 ;\tMA\t# ( 𝐹 → F ) MATHEMATICAL ITALIC CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D46D ;\t0046 ;\tMA\t# ( 𝑭 → F ) MATHEMATICAL BOLD ITALIC CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D4D5 ;\t0046 ;\tMA\t# ( 𝓕 → F ) MATHEMATICAL BOLD SCRIPT CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D509 ;\t0046 ;\tMA\t# ( 𝔉 → F ) MATHEMATICAL FRAKTUR CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D53D ;\t0046 ;\tMA\t# ( 𝔽 → F ) MATHEMATICAL DOUBLE-STRUCK CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D571 ;\t0046 ;\tMA\t# ( 𝕱 → F ) MATHEMATICAL BOLD FRAKTUR CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D5A5 ;\t0046 ;\tMA\t# ( 𝖥 → F ) MATHEMATICAL SANS-SERIF CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D5D9 ;\t0046 ;\tMA\t# ( 𝗙 → F ) MATHEMATICAL SANS-SERIF BOLD CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D60D ;\t0046 ;\tMA\t# ( 𝘍 → F ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D641 ;\t0046 ;\tMA\t# ( 𝙁 → F ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F → LATIN CAPITAL LETTER F\t# \n1D675 ;\t0046 ;\tMA\t# ( 𝙵 → F ) MATHEMATICAL MONOSPACE CAPITAL F → LATIN CAPITAL LETTER F\t# \nA798 ;\t0046 ;\tMA\t# ( Ꞙ → F ) LATIN CAPITAL LETTER F WITH STROKE → LATIN CAPITAL LETTER F\t# \n03DC ;\t0046 ;\tMA\t# ( Ϝ → F ) GREEK LETTER DIGAMMA → LATIN CAPITAL LETTER F\t# \n1D7CA ;\t0046 ;\tMA\t# ( 𝟊 → F ) MATHEMATICAL BOLD CAPITAL DIGAMMA → LATIN CAPITAL LETTER F\t# →Ϝ→\n15B4 ;\t0046 ;\tMA\t# ( ᖴ → F ) CANADIAN SYLLABICS BLACKFOOT WE → LATIN CAPITAL LETTER F\t# \nA4DD ;\t0046 ;\tMA\t# ( ꓝ → F ) LISU LETTER TSA → LATIN CAPITAL LETTER F\t# \n118C2 ;\t0046 ;\tMA\t# ( 𑣂 → F ) WARANG CITI SMALL LETTER WI → LATIN CAPITAL LETTER F\t# \n118A2 ;\t0046 ;\tMA\t# ( 𑢢 → F ) WARANG CITI CAPITAL LETTER WI → LATIN CAPITAL LETTER F\t# \n10287 ;\t0046 ;\tMA\t# ( 𐊇 → F ) LYCIAN LETTER W → LATIN CAPITAL LETTER F\t# \n102A5 ;\t0046 ;\tMA\t# ( 𐊥 → F ) CARIAN LETTER R → LATIN CAPITAL LETTER F\t# \n10525 ;\t0046 ;\tMA\t# ( 𐔥 → F ) ELBASAN LETTER GHE → LATIN CAPITAL LETTER F\t# \n\n0191 ;\t0046 0326 ;\tMA\t# ( Ƒ → F̦ ) LATIN CAPITAL LETTER F WITH HOOK → LATIN CAPITAL LETTER F, COMBINING COMMA BELOW\t# →F̡→\n\n1D6E ;\t0066 0334 ;\tMA\t# ( ᵮ → f̴ ) LATIN SMALL LETTER F WITH MIDDLE TILDE → LATIN SMALL LETTER F, COMBINING TILDE OVERLAY\t# \n\n213B ;\t0046 0041 0058 ;\tMA\t#* ( ℻ → FAX ) FACSIMILE SIGN → LATIN CAPITAL LETTER F, LATIN CAPITAL LETTER A, LATIN CAPITAL LETTER X\t# \n\nFB00 ;\t0066 0066 ;\tMA\t# ( ﬀ → ff ) LATIN SMALL LIGATURE FF → LATIN SMALL LETTER F, LATIN SMALL LETTER F\t# \n\nFB03 ;\t0066 0066 0069 ;\tMA\t# ( ﬃ → ffi ) LATIN SMALL LIGATURE FFI → LATIN SMALL LETTER F, LATIN SMALL LETTER F, LATIN SMALL LETTER I\t# \n\nFB04 ;\t0066 0066 006C ;\tMA\t# ( ﬄ → ffl ) LATIN SMALL LIGATURE FFL → LATIN SMALL LETTER F, LATIN SMALL LETTER F, LATIN SMALL LETTER L\t# \n\nFB01 ;\t0066 0069 ;\tMA\t# ( ﬁ → fi ) LATIN SMALL LIGATURE FI → LATIN SMALL LETTER F, LATIN SMALL LETTER I\t# \n\nFB02 ;\t0066 006C ;\tMA\t# ( ﬂ → fl ) LATIN SMALL LIGATURE FL → LATIN SMALL LETTER F, LATIN SMALL LETTER L\t# \n\n02A9 ;\t0066 006E 0329 ;\tMA\t# ( ʩ → fn̩ ) LATIN SMALL LETTER FENG DIGRAPH → LATIN SMALL LETTER F, LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →fŋ→\n\n15B5 ;\t2132 ;\tMA\t# ( ᖵ → Ⅎ ) CANADIAN SYLLABICS BLACKFOOT WI → TURNED CAPITAL F\t# \nA4DE ;\t2132 ;\tMA\t# ( ꓞ → Ⅎ ) LISU LETTER TSHA → TURNED CAPITAL F\t# \n\n1D230 ;\tA7FB ;\tMA\t#* ( 𝈰 → ꟻ ) GREEK INSTRUMENTAL NOTATION SYMBOL-30 → LATIN EPIGRAPHIC LETTER REVERSED F\t# \n15B7 ;\tA7FB ;\tMA\t# ( ᖷ → ꟻ ) CANADIAN SYLLABICS BLACKFOOT WA → LATIN EPIGRAPHIC LETTER REVERSED F\t# \n\nFF47 ;\t0067 ;\tMA\t# ( ｇ → g ) FULLWIDTH LATIN SMALL LETTER G → LATIN SMALL LETTER G\t# →ɡ→\n210A ;\t0067 ;\tMA\t# ( ℊ → g ) SCRIPT SMALL G → LATIN SMALL LETTER G\t# \n1D420 ;\t0067 ;\tMA\t# ( 𝐠 → g ) MATHEMATICAL BOLD SMALL G → LATIN SMALL LETTER G\t# \n1D454 ;\t0067 ;\tMA\t# ( 𝑔 → g ) MATHEMATICAL ITALIC SMALL G → LATIN SMALL LETTER G\t# \n1D488 ;\t0067 ;\tMA\t# ( 𝒈 → g ) MATHEMATICAL BOLD ITALIC SMALL G → LATIN SMALL LETTER G\t# \n1D4F0 ;\t0067 ;\tMA\t# ( 𝓰 → g ) MATHEMATICAL BOLD SCRIPT SMALL G → LATIN SMALL LETTER G\t# \n1D524 ;\t0067 ;\tMA\t# ( 𝔤 → g ) MATHEMATICAL FRAKTUR SMALL G → LATIN SMALL LETTER G\t# \n1D558 ;\t0067 ;\tMA\t# ( 𝕘 → g ) MATHEMATICAL DOUBLE-STRUCK SMALL G → LATIN SMALL LETTER G\t# \n1D58C ;\t0067 ;\tMA\t# ( 𝖌 → g ) MATHEMATICAL BOLD FRAKTUR SMALL G → LATIN SMALL LETTER G\t# \n1D5C0 ;\t0067 ;\tMA\t# ( 𝗀 → g ) MATHEMATICAL SANS-SERIF SMALL G → LATIN SMALL LETTER G\t# \n1D5F4 ;\t0067 ;\tMA\t# ( 𝗴 → g ) MATHEMATICAL SANS-SERIF BOLD SMALL G → LATIN SMALL LETTER G\t# \n1D628 ;\t0067 ;\tMA\t# ( 𝘨 → g ) MATHEMATICAL SANS-SERIF ITALIC SMALL G → LATIN SMALL LETTER G\t# \n1D65C ;\t0067 ;\tMA\t# ( 𝙜 → g ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G → LATIN SMALL LETTER G\t# \n1D690 ;\t0067 ;\tMA\t# ( 𝚐 → g ) MATHEMATICAL MONOSPACE SMALL G → LATIN SMALL LETTER G\t# \n0261 ;\t0067 ;\tMA\t# ( ɡ → g ) LATIN SMALL LETTER SCRIPT G → LATIN SMALL LETTER G\t# \n1D83 ;\t0067 ;\tMA\t# ( ᶃ → g ) LATIN SMALL LETTER G WITH PALATAL HOOK → LATIN SMALL LETTER G\t# \n018D ;\t0067 ;\tMA\t# ( ƍ → g ) LATIN SMALL LETTER TURNED DELTA → LATIN SMALL LETTER G\t# \n0581 ;\t0067 ;\tMA\t# ( ց → g ) ARMENIAN SMALL LETTER CO → LATIN SMALL LETTER G\t# \n\n1CCDC ;\t0047 ;\tMA\t#* ( 𜳜 → G ) OUTLINED LATIN CAPITAL LETTER G → LATIN CAPITAL LETTER G\t# \n1D406 ;\t0047 ;\tMA\t# ( 𝐆 → G ) MATHEMATICAL BOLD CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D43A ;\t0047 ;\tMA\t# ( 𝐺 → G ) MATHEMATICAL ITALIC CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D46E ;\t0047 ;\tMA\t# ( 𝑮 → G ) MATHEMATICAL BOLD ITALIC CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D4A2 ;\t0047 ;\tMA\t# ( 𝒢 → G ) MATHEMATICAL SCRIPT CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D4D6 ;\t0047 ;\tMA\t# ( 𝓖 → G ) MATHEMATICAL BOLD SCRIPT CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D50A ;\t0047 ;\tMA\t# ( 𝔊 → G ) MATHEMATICAL FRAKTUR CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D53E ;\t0047 ;\tMA\t# ( 𝔾 → G ) MATHEMATICAL DOUBLE-STRUCK CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D572 ;\t0047 ;\tMA\t# ( 𝕲 → G ) MATHEMATICAL BOLD FRAKTUR CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D5A6 ;\t0047 ;\tMA\t# ( 𝖦 → G ) MATHEMATICAL SANS-SERIF CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D5DA ;\t0047 ;\tMA\t# ( 𝗚 → G ) MATHEMATICAL SANS-SERIF BOLD CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D60E ;\t0047 ;\tMA\t# ( 𝘎 → G ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D642 ;\t0047 ;\tMA\t# ( 𝙂 → G ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G → LATIN CAPITAL LETTER G\t# \n1D676 ;\t0047 ;\tMA\t# ( 𝙶 → G ) MATHEMATICAL MONOSPACE CAPITAL G → LATIN CAPITAL LETTER G\t# \n050C ;\t0047 ;\tMA\t# ( Ԍ → G ) CYRILLIC CAPITAL LETTER KOMI SJE → LATIN CAPITAL LETTER G\t# \n13C0 ;\t0047 ;\tMA\t# ( Ꮐ → G ) CHEROKEE LETTER NAH → LATIN CAPITAL LETTER G\t# \n13F3 ;\t0047 ;\tMA\t# ( Ᏻ → G ) CHEROKEE LETTER YU → LATIN CAPITAL LETTER G\t# \nA4D6 ;\t0047 ;\tMA\t# ( ꓖ → G ) LISU LETTER GA → LATIN CAPITAL LETTER G\t# \n\n1DA2 ;\t1D4D ;\tMA\t# ( ᶢ → ᵍ ) MODIFIER LETTER SMALL SCRIPT G → MODIFIER LETTER SMALL G\t# \n\n0260 ;\t0067 0314 ;\tMA\t# ( ɠ → g̔ ) LATIN SMALL LETTER G WITH HOOK → LATIN SMALL LETTER G, COMBINING REVERSED COMMA ABOVE\t# \n\n01E7 ;\t011F ;\tMA\t# ( ǧ → ğ ) LATIN SMALL LETTER G WITH CARON → LATIN SMALL LETTER G WITH BREVE\t# \n\n01E6 ;\t011E ;\tMA\t# ( Ǧ → Ğ ) LATIN CAPITAL LETTER G WITH CARON → LATIN CAPITAL LETTER G WITH BREVE\t# \n\n01F5 ;\t0123 ;\tMA\t# ( ǵ → ģ ) LATIN SMALL LETTER G WITH ACUTE → LATIN SMALL LETTER G WITH CEDILLA\t# \n\n01E5 ;\t0067 0335 ;\tMA\t# ( ǥ → g̵ ) LATIN SMALL LETTER G WITH STROKE → LATIN SMALL LETTER G, COMBINING SHORT STROKE OVERLAY\t# \n\n01E4 ;\t0047 0335 ;\tMA\t# ( Ǥ → G̵ ) LATIN CAPITAL LETTER G WITH STROKE → LATIN CAPITAL LETTER G, COMBINING SHORT STROKE OVERLAY\t# \n\n0193 ;\t0047 0027 ;\tMA\t# ( Ɠ → G' ) LATIN CAPITAL LETTER G WITH HOOK → LATIN CAPITAL LETTER G, APOSTROPHE\t# →Gʽ→\n\n050D ;\t0262 ;\tMA\t# ( ԍ → ɢ ) CYRILLIC SMALL LETTER KOMI SJE → LATIN LETTER SMALL CAPITAL G\t# \nAB90 ;\t0262 ;\tMA\t# ( ꮐ → ɢ ) CHEROKEE SMALL LETTER NAH → LATIN LETTER SMALL CAPITAL G\t# \n13FB ;\t0262 ;\tMA\t# ( ᏻ → ɢ ) CHEROKEE SMALL LETTER YU → LATIN LETTER SMALL CAPITAL G\t# \n\nFF48 ;\t0068 ;\tMA\t# ( ｈ → h ) FULLWIDTH LATIN SMALL LETTER H → LATIN SMALL LETTER H\t# →һ→\n210E ;\t0068 ;\tMA\t# ( ℎ → h ) PLANCK CONSTANT → LATIN SMALL LETTER H\t# \n1D421 ;\t0068 ;\tMA\t# ( 𝐡 → h ) MATHEMATICAL BOLD SMALL H → LATIN SMALL LETTER H\t# \n1D489 ;\t0068 ;\tMA\t# ( 𝒉 → h ) MATHEMATICAL BOLD ITALIC SMALL H → LATIN SMALL LETTER H\t# \n1D4BD ;\t0068 ;\tMA\t# ( 𝒽 → h ) MATHEMATICAL SCRIPT SMALL H → LATIN SMALL LETTER H\t# \n1D4F1 ;\t0068 ;\tMA\t# ( 𝓱 → h ) MATHEMATICAL BOLD SCRIPT SMALL H → LATIN SMALL LETTER H\t# \n1D525 ;\t0068 ;\tMA\t# ( 𝔥 → h ) MATHEMATICAL FRAKTUR SMALL H → LATIN SMALL LETTER H\t# \n1D559 ;\t0068 ;\tMA\t# ( 𝕙 → h ) MATHEMATICAL DOUBLE-STRUCK SMALL H → LATIN SMALL LETTER H\t# \n1D58D ;\t0068 ;\tMA\t# ( 𝖍 → h ) MATHEMATICAL BOLD FRAKTUR SMALL H → LATIN SMALL LETTER H\t# \n1D5C1 ;\t0068 ;\tMA\t# ( 𝗁 → h ) MATHEMATICAL SANS-SERIF SMALL H → LATIN SMALL LETTER H\t# \n1D5F5 ;\t0068 ;\tMA\t# ( 𝗵 → h ) MATHEMATICAL SANS-SERIF BOLD SMALL H → LATIN SMALL LETTER H\t# \n1D629 ;\t0068 ;\tMA\t# ( 𝘩 → h ) MATHEMATICAL SANS-SERIF ITALIC SMALL H → LATIN SMALL LETTER H\t# \n1D65D ;\t0068 ;\tMA\t# ( 𝙝 → h ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H → LATIN SMALL LETTER H\t# \n1D691 ;\t0068 ;\tMA\t# ( 𝚑 → h ) MATHEMATICAL MONOSPACE SMALL H → LATIN SMALL LETTER H\t# \n04BB ;\t0068 ;\tMA\t# ( һ → h ) CYRILLIC SMALL LETTER SHHA → LATIN SMALL LETTER H\t# \n0570 ;\t0068 ;\tMA\t# ( հ → h ) ARMENIAN SMALL LETTER HO → LATIN SMALL LETTER H\t# \n13C2 ;\t0068 ;\tMA\t# ( Ꮒ → h ) CHEROKEE LETTER NI → LATIN SMALL LETTER H\t# \n\nFF28 ;\t0048 ;\tMA\t# ( Ｈ → H ) FULLWIDTH LATIN CAPITAL LETTER H → LATIN CAPITAL LETTER H\t# →Η→\n210B ;\t0048 ;\tMA\t# ( ℋ → H ) SCRIPT CAPITAL H → LATIN CAPITAL LETTER H\t# \n210C ;\t0048 ;\tMA\t# ( ℌ → H ) BLACK-LETTER CAPITAL H → LATIN CAPITAL LETTER H\t# \n210D ;\t0048 ;\tMA\t# ( ℍ → H ) DOUBLE-STRUCK CAPITAL H → LATIN CAPITAL LETTER H\t# \n1CCDD ;\t0048 ;\tMA\t#* ( 𜳝 → H ) OUTLINED LATIN CAPITAL LETTER H → LATIN CAPITAL LETTER H\t# \n1D407 ;\t0048 ;\tMA\t# ( 𝐇 → H ) MATHEMATICAL BOLD CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D43B ;\t0048 ;\tMA\t# ( 𝐻 → H ) MATHEMATICAL ITALIC CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D46F ;\t0048 ;\tMA\t# ( 𝑯 → H ) MATHEMATICAL BOLD ITALIC CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D4D7 ;\t0048 ;\tMA\t# ( 𝓗 → H ) MATHEMATICAL BOLD SCRIPT CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D573 ;\t0048 ;\tMA\t# ( 𝕳 → H ) MATHEMATICAL BOLD FRAKTUR CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D5A7 ;\t0048 ;\tMA\t# ( 𝖧 → H ) MATHEMATICAL SANS-SERIF CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D5DB ;\t0048 ;\tMA\t# ( 𝗛 → H ) MATHEMATICAL SANS-SERIF BOLD CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D60F ;\t0048 ;\tMA\t# ( 𝘏 → H ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D643 ;\t0048 ;\tMA\t# ( 𝙃 → H ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H → LATIN CAPITAL LETTER H\t# \n1D677 ;\t0048 ;\tMA\t# ( 𝙷 → H ) MATHEMATICAL MONOSPACE CAPITAL H → LATIN CAPITAL LETTER H\t# \n0397 ;\t0048 ;\tMA\t# ( Η → H ) GREEK CAPITAL LETTER ETA → LATIN CAPITAL LETTER H\t# \n1D6AE ;\t0048 ;\tMA\t# ( 𝚮 → H ) MATHEMATICAL BOLD CAPITAL ETA → LATIN CAPITAL LETTER H\t# →Η→\n1D6E8 ;\t0048 ;\tMA\t# ( 𝛨 → H ) MATHEMATICAL ITALIC CAPITAL ETA → LATIN CAPITAL LETTER H\t# →Η→\n1D722 ;\t0048 ;\tMA\t# ( 𝜢 → H ) MATHEMATICAL BOLD ITALIC CAPITAL ETA → LATIN CAPITAL LETTER H\t# →𝑯→\n1D75C ;\t0048 ;\tMA\t# ( 𝝜 → H ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA → LATIN CAPITAL LETTER H\t# →Η→\n1D796 ;\t0048 ;\tMA\t# ( 𝞖 → H ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA → LATIN CAPITAL LETTER H\t# →Η→\n2C8E ;\t0048 ;\tMA\t# ( Ⲏ → H ) COPTIC CAPITAL LETTER HATE → LATIN CAPITAL LETTER H\t# →Η→\n041D ;\t0048 ;\tMA\t# ( Н → H ) CYRILLIC CAPITAL LETTER EN → LATIN CAPITAL LETTER H\t# \n13BB ;\t0048 ;\tMA\t# ( Ꮋ → H ) CHEROKEE LETTER MI → LATIN CAPITAL LETTER H\t# \n157C ;\t0048 ;\tMA\t# ( ᕼ → H ) CANADIAN SYLLABICS NUNAVUT H → LATIN CAPITAL LETTER H\t# \nA4E7 ;\t0048 ;\tMA\t# ( ꓧ → H ) LISU LETTER XA → LATIN CAPITAL LETTER H\t# \n102CF ;\t0048 ;\tMA\t# ( 𐋏 → H ) CARIAN LETTER E2 → LATIN CAPITAL LETTER H\t# \n\n1D78 ;\t1D34 ;\tMA\t# ( ᵸ → ᴴ ) MODIFIER LETTER CYRILLIC EN → MODIFIER LETTER CAPITAL H\t# \n\n0266 ;\t0068 0314 ;\tMA\t# ( ɦ → h̔ ) LATIN SMALL LETTER H WITH HOOK → LATIN SMALL LETTER H, COMBINING REVERSED COMMA ABOVE\t# \nA695 ;\t0068 0314 ;\tMA\t# ( ꚕ → h̔ ) CYRILLIC SMALL LETTER HWE → LATIN SMALL LETTER H, COMBINING REVERSED COMMA ABOVE\t# →ɦ→\n13F2 ;\t0068 0314 ;\tMA\t# ( Ᏺ → h̔ ) CHEROKEE LETTER YO → LATIN SMALL LETTER H, COMBINING REVERSED COMMA ABOVE\t# \n\n2C67 ;\t0048 0329 ;\tMA\t# ( Ⱨ → H̩ ) LATIN CAPITAL LETTER H WITH DESCENDER → LATIN CAPITAL LETTER H, COMBINING VERTICAL LINE BELOW\t# →Ң→→Н̩→\n04A2 ;\t0048 0329 ;\tMA\t# ( Ң → H̩ ) CYRILLIC CAPITAL LETTER EN WITH DESCENDER → LATIN CAPITAL LETTER H, COMBINING VERTICAL LINE BELOW\t# →Н̩→\n\n0127 ;\t0068 0335 ;\tMA\t# ( ħ → h̵ ) LATIN SMALL LETTER H WITH STROKE → LATIN SMALL LETTER H, COMBINING SHORT STROKE OVERLAY\t# \n210F ;\t0068 0335 ;\tMA\t# ( ℏ → h̵ ) PLANCK CONSTANT OVER TWO PI → LATIN SMALL LETTER H, COMBINING SHORT STROKE OVERLAY\t# →ħ→\n045B ;\t0068 0335 ;\tMA\t# ( ћ → h̵ ) CYRILLIC SMALL LETTER TSHE → LATIN SMALL LETTER H, COMBINING SHORT STROKE OVERLAY\t# →ħ→\n\n0126 ;\t0048 0335 ;\tMA\t# ( Ħ → H̵ ) LATIN CAPITAL LETTER H WITH STROKE → LATIN CAPITAL LETTER H, COMBINING SHORT STROKE OVERLAY\t# \n\n04C9 ;\t0048 0326 ;\tMA\t# ( Ӊ → H̦ ) CYRILLIC CAPITAL LETTER EN WITH TAIL → LATIN CAPITAL LETTER H, COMBINING COMMA BELOW\t# →Н̡→\n04C7 ;\t0048 0326 ;\tMA\t# ( Ӈ → H̦ ) CYRILLIC CAPITAL LETTER EN WITH HOOK → LATIN CAPITAL LETTER H, COMBINING COMMA BELOW\t# →Н̡→\n\n2C8F ;\t029C ;\tMA\t# ( ⲏ → ʜ ) COPTIC SMALL LETTER HATE → LATIN LETTER SMALL CAPITAL H\t# →н→\n043D ;\t029C ;\tMA\t# ( н → ʜ ) CYRILLIC SMALL LETTER EN → LATIN LETTER SMALL CAPITAL H\t# \nAB8B ;\t029C ;\tMA\t# ( ꮋ → ʜ ) CHEROKEE SMALL LETTER MI → LATIN LETTER SMALL CAPITAL H\t# \n\n04A3 ;\t029C 0329 ;\tMA\t# ( ң → ʜ̩ ) CYRILLIC SMALL LETTER EN WITH DESCENDER → LATIN LETTER SMALL CAPITAL H, COMBINING VERTICAL LINE BELOW\t# →н̩→\n\n04CA ;\t029C 0326 ;\tMA\t# ( ӊ → ʜ̦ ) CYRILLIC SMALL LETTER EN WITH TAIL → LATIN LETTER SMALL CAPITAL H, COMBINING COMMA BELOW\t# →н̡→\n04C8 ;\t029C 0326 ;\tMA\t# ( ӈ → ʜ̦ ) CYRILLIC SMALL LETTER EN WITH HOOK → LATIN LETTER SMALL CAPITAL H, COMBINING COMMA BELOW\t# →н̡→\n\n050A ;\t01F6 ;\tMA\t# ( Ԋ → Ƕ ) CYRILLIC CAPITAL LETTER KOMI NJE → LATIN CAPITAL LETTER HWAIR\t# \n\nAB80 ;\t2C76 ;\tMA\t# ( ꮀ → ⱶ ) CHEROKEE SMALL LETTER HO → LATIN SMALL LETTER HALF H\t# \n\n0370 ;\t2C75 ;\tMA\t# ( Ͱ → Ⱶ ) GREEK CAPITAL LETTER HETA → LATIN CAPITAL LETTER HALF H\t# →Ꮀ→\n13A8 ;\t2C75 ;\tMA\t# ( Ꭸ → Ⱶ ) CHEROKEE LETTER GE → LATIN CAPITAL LETTER HALF H\t# →Ͱ→→Ꮀ→\n13B0 ;\t2C75 ;\tMA\t# ( Ꮀ → Ⱶ ) CHEROKEE LETTER HO → LATIN CAPITAL LETTER HALF H\t# \nA6B1 ;\t2C75 ;\tMA\t# ( ꚱ → Ⱶ ) BAMUM LETTER NDAA → LATIN CAPITAL LETTER HALF H\t# →Ͱ→→Ꮀ→\n\nA795 ;\tA727 ;\tMA\t# ( ꞕ → ꜧ ) LATIN SMALL LETTER H WITH PALATAL HOOK → LATIN SMALL LETTER HENG\t# \n\n02DB ;\t0069 ;\tMA\t#* ( ˛ → i ) OGONEK → LATIN SMALL LETTER I\t# →ͺ→→ι→→ι→\n2373 ;\t0069 ;\tMA\t#* ( ⍳ → i ) APL FUNCTIONAL SYMBOL IOTA → LATIN SMALL LETTER I\t# →ɩ→\nFF49 ;\t0069 ;\tMA\t# ( ｉ → i ) FULLWIDTH LATIN SMALL LETTER I → LATIN SMALL LETTER I\t# →і→\n2170 ;\t0069 ;\tMA\t# ( ⅰ → i ) SMALL ROMAN NUMERAL ONE → LATIN SMALL LETTER I\t# \n2139 ;\t0069 ;\tMA\t# ( ℹ → i ) INFORMATION SOURCE → LATIN SMALL LETTER I\t# \n2148 ;\t0069 ;\tMA\t# ( ⅈ → i ) DOUBLE-STRUCK ITALIC SMALL I → LATIN SMALL LETTER I\t# \n1D422 ;\t0069 ;\tMA\t# ( 𝐢 → i ) MATHEMATICAL BOLD SMALL I → LATIN SMALL LETTER I\t# \n1D456 ;\t0069 ;\tMA\t# ( 𝑖 → i ) MATHEMATICAL ITALIC SMALL I → LATIN SMALL LETTER I\t# \n1D48A ;\t0069 ;\tMA\t# ( 𝒊 → i ) MATHEMATICAL BOLD ITALIC SMALL I → LATIN SMALL LETTER I\t# \n1D4BE ;\t0069 ;\tMA\t# ( 𝒾 → i ) MATHEMATICAL SCRIPT SMALL I → LATIN SMALL LETTER I\t# \n1D4F2 ;\t0069 ;\tMA\t# ( 𝓲 → i ) MATHEMATICAL BOLD SCRIPT SMALL I → LATIN SMALL LETTER I\t# \n1D526 ;\t0069 ;\tMA\t# ( 𝔦 → i ) MATHEMATICAL FRAKTUR SMALL I → LATIN SMALL LETTER I\t# \n1D55A ;\t0069 ;\tMA\t# ( 𝕚 → i ) MATHEMATICAL DOUBLE-STRUCK SMALL I → LATIN SMALL LETTER I\t# \n1D58E ;\t0069 ;\tMA\t# ( 𝖎 → i ) MATHEMATICAL BOLD FRAKTUR SMALL I → LATIN SMALL LETTER I\t# \n1D5C2 ;\t0069 ;\tMA\t# ( 𝗂 → i ) MATHEMATICAL SANS-SERIF SMALL I → LATIN SMALL LETTER I\t# \n1D5F6 ;\t0069 ;\tMA\t# ( 𝗶 → i ) MATHEMATICAL SANS-SERIF BOLD SMALL I → LATIN SMALL LETTER I\t# \n1D62A ;\t0069 ;\tMA\t# ( 𝘪 → i ) MATHEMATICAL SANS-SERIF ITALIC SMALL I → LATIN SMALL LETTER I\t# \n1D65E ;\t0069 ;\tMA\t# ( 𝙞 → i ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I → LATIN SMALL LETTER I\t# \n1D692 ;\t0069 ;\tMA\t# ( 𝚒 → i ) MATHEMATICAL MONOSPACE SMALL I → LATIN SMALL LETTER I\t# \n0131 ;\t0069 ;\tMA\t# ( ı → i ) LATIN SMALL LETTER DOTLESS I → LATIN SMALL LETTER I\t# \n1D6A4 ;\t0069 ;\tMA\t# ( 𝚤 → i ) MATHEMATICAL ITALIC SMALL DOTLESS I → LATIN SMALL LETTER I\t# →ı→\n026A ;\t0069 ;\tMA\t# ( ɪ → i ) LATIN LETTER SMALL CAPITAL I → LATIN SMALL LETTER I\t# →ı→\n0269 ;\t0069 ;\tMA\t# ( ɩ → i ) LATIN SMALL LETTER IOTA → LATIN SMALL LETTER I\t# \n03B9 ;\t0069 ;\tMA\t# ( ι → i ) GREEK SMALL LETTER IOTA → LATIN SMALL LETTER I\t# \n1FBE ;\t0069 ;\tMA\t# ( ι → i ) GREEK PROSGEGRAMMENI → LATIN SMALL LETTER I\t# →ι→\n037A ;\t0069 ;\tMA\t#* ( ͺ → i ) GREEK YPOGEGRAMMENI → LATIN SMALL LETTER I\t# →ι→→ι→\n1D6CA ;\t0069 ;\tMA\t# ( 𝛊 → i ) MATHEMATICAL BOLD SMALL IOTA → LATIN SMALL LETTER I\t# →ι→\n1D704 ;\t0069 ;\tMA\t# ( 𝜄 → i ) MATHEMATICAL ITALIC SMALL IOTA → LATIN SMALL LETTER I\t# →ι→\n1D73E ;\t0069 ;\tMA\t# ( 𝜾 → i ) MATHEMATICAL BOLD ITALIC SMALL IOTA → LATIN SMALL LETTER I\t# →ι→\n1D778 ;\t0069 ;\tMA\t# ( 𝝸 → i ) MATHEMATICAL SANS-SERIF BOLD SMALL IOTA → LATIN SMALL LETTER I\t# →ι→\n1D7B2 ;\t0069 ;\tMA\t# ( 𝞲 → i ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA → LATIN SMALL LETTER I\t# →ι→\n2C93 ;\t0069 ;\tMA\t# ( ⲓ → i ) COPTIC SMALL LETTER IAUDA → LATIN SMALL LETTER I\t# →ı→\n0456 ;\t0069 ;\tMA\t# ( і → i ) CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I → LATIN SMALL LETTER I\t# \nA647 ;\t0069 ;\tMA\t# ( ꙇ → i ) CYRILLIC SMALL LETTER IOTA → LATIN SMALL LETTER I\t# →ι→\n0582 ;\t0069 ;\tMA\t# ( ւ → i ) ARMENIAN SMALL LETTER YIWN → LATIN SMALL LETTER I\t# →ı→\nAB75 ;\t0069 ;\tMA\t# ( ꭵ → i ) CHEROKEE SMALL LETTER V → LATIN SMALL LETTER I\t# \n13A5 ;\t0069 ;\tMA\t# ( Ꭵ → i ) CHEROKEE LETTER V → LATIN SMALL LETTER I\t# \n118C3 ;\t0069 ;\tMA\t# ( 𑣃 → i ) WARANG CITI SMALL LETTER YU → LATIN SMALL LETTER I\t# →ι→\n\n24DB ;\t24BE ;\tMA\t#* ( ⓛ → Ⓘ ) CIRCLED LATIN SMALL LETTER L → CIRCLED LATIN CAPITAL LETTER I\t# \n\n2378 ;\t0069 0332 ;\tMA\t#* ( ⍸ → i̲ ) APL FUNCTIONAL SYMBOL IOTA UNDERBAR → LATIN SMALL LETTER I, COMBINING LOW LINE\t# →ι̲→\n\n01D0 ;\t012D ;\tMA\t# ( ǐ → ĭ ) LATIN SMALL LETTER I WITH CARON → LATIN SMALL LETTER I WITH BREVE\t# \n\n01CF ;\t012C ;\tMA\t# ( Ǐ → Ĭ ) LATIN CAPITAL LETTER I WITH CARON → LATIN CAPITAL LETTER I WITH BREVE\t# \n\n0268 ;\t0069 0335 ;\tMA\t# ( ɨ → i̵ ) LATIN SMALL LETTER I WITH STROKE → LATIN SMALL LETTER I, COMBINING SHORT STROKE OVERLAY\t# \n1D7B ;\t0069 0335 ;\tMA\t# ( ᵻ → i̵ ) LATIN SMALL CAPITAL LETTER I WITH STROKE → LATIN SMALL LETTER I, COMBINING SHORT STROKE OVERLAY\t# →ɪ̵→\n1D7C ;\t0069 0335 ;\tMA\t# ( ᵼ → i̵ ) LATIN SMALL LETTER IOTA WITH STROKE → LATIN SMALL LETTER I, COMBINING SHORT STROKE OVERLAY\t# →ɩ̵→\n\n2171 ;\t0069 0069 ;\tMA\t# ( ⅱ → ii ) SMALL ROMAN NUMERAL TWO → LATIN SMALL LETTER I, LATIN SMALL LETTER I\t# \n\n2172 ;\t0069 0069 0069 ;\tMA\t# ( ⅲ → iii ) SMALL ROMAN NUMERAL THREE → LATIN SMALL LETTER I, LATIN SMALL LETTER I, LATIN SMALL LETTER I\t# \n\n0133 ;\t0069 006A ;\tMA\t# ( ĳ → ij ) LATIN SMALL LIGATURE IJ → LATIN SMALL LETTER I, LATIN SMALL LETTER J\t# \n\n2173 ;\t0069 0076 ;\tMA\t# ( ⅳ → iv ) SMALL ROMAN NUMERAL FOUR → LATIN SMALL LETTER I, LATIN SMALL LETTER V\t# \n\n2178 ;\t0069 0078 ;\tMA\t# ( ⅸ → ix ) SMALL ROMAN NUMERAL NINE → LATIN SMALL LETTER I, LATIN SMALL LETTER X\t# \n\nFF4A ;\t006A ;\tMA\t# ( ｊ → j ) FULLWIDTH LATIN SMALL LETTER J → LATIN SMALL LETTER J\t# →ϳ→\n2149 ;\t006A ;\tMA\t# ( ⅉ → j ) DOUBLE-STRUCK ITALIC SMALL J → LATIN SMALL LETTER J\t# \n1D423 ;\t006A ;\tMA\t# ( 𝐣 → j ) MATHEMATICAL BOLD SMALL J → LATIN SMALL LETTER J\t# \n1D457 ;\t006A ;\tMA\t# ( 𝑗 → j ) MATHEMATICAL ITALIC SMALL J → LATIN SMALL LETTER J\t# \n1D48B ;\t006A ;\tMA\t# ( 𝒋 → j ) MATHEMATICAL BOLD ITALIC SMALL J → LATIN SMALL LETTER J\t# \n1D4BF ;\t006A ;\tMA\t# ( 𝒿 → j ) MATHEMATICAL SCRIPT SMALL J → LATIN SMALL LETTER J\t# \n1D4F3 ;\t006A ;\tMA\t# ( 𝓳 → j ) MATHEMATICAL BOLD SCRIPT SMALL J → LATIN SMALL LETTER J\t# \n1D527 ;\t006A ;\tMA\t# ( 𝔧 → j ) MATHEMATICAL FRAKTUR SMALL J → LATIN SMALL LETTER J\t# \n1D55B ;\t006A ;\tMA\t# ( 𝕛 → j ) MATHEMATICAL DOUBLE-STRUCK SMALL J → LATIN SMALL LETTER J\t# \n1D58F ;\t006A ;\tMA\t# ( 𝖏 → j ) MATHEMATICAL BOLD FRAKTUR SMALL J → LATIN SMALL LETTER J\t# \n1D5C3 ;\t006A ;\tMA\t# ( 𝗃 → j ) MATHEMATICAL SANS-SERIF SMALL J → LATIN SMALL LETTER J\t# \n1D5F7 ;\t006A ;\tMA\t# ( 𝗷 → j ) MATHEMATICAL SANS-SERIF BOLD SMALL J → LATIN SMALL LETTER J\t# \n1D62B ;\t006A ;\tMA\t# ( 𝘫 → j ) MATHEMATICAL SANS-SERIF ITALIC SMALL J → LATIN SMALL LETTER J\t# \n1D65F ;\t006A ;\tMA\t# ( 𝙟 → j ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J → LATIN SMALL LETTER J\t# \n1D693 ;\t006A ;\tMA\t# ( 𝚓 → j ) MATHEMATICAL MONOSPACE SMALL J → LATIN SMALL LETTER J\t# \n03F3 ;\t006A ;\tMA\t# ( ϳ → j ) GREEK LETTER YOT → LATIN SMALL LETTER J\t# \n0458 ;\t006A ;\tMA\t# ( ј → j ) CYRILLIC SMALL LETTER JE → LATIN SMALL LETTER J\t# \n\nFF2A ;\t004A ;\tMA\t# ( Ｊ → J ) FULLWIDTH LATIN CAPITAL LETTER J → LATIN CAPITAL LETTER J\t# →Ј→\n1CCDF ;\t004A ;\tMA\t#* ( 𜳟 → J ) OUTLINED LATIN CAPITAL LETTER J → LATIN CAPITAL LETTER J\t# \n1D409 ;\t004A ;\tMA\t# ( 𝐉 → J ) MATHEMATICAL BOLD CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D43D ;\t004A ;\tMA\t# ( 𝐽 → J ) MATHEMATICAL ITALIC CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D471 ;\t004A ;\tMA\t# ( 𝑱 → J ) MATHEMATICAL BOLD ITALIC CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D4A5 ;\t004A ;\tMA\t# ( 𝒥 → J ) MATHEMATICAL SCRIPT CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D4D9 ;\t004A ;\tMA\t# ( 𝓙 → J ) MATHEMATICAL BOLD SCRIPT CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D50D ;\t004A ;\tMA\t# ( 𝔍 → J ) MATHEMATICAL FRAKTUR CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D541 ;\t004A ;\tMA\t# ( 𝕁 → J ) MATHEMATICAL DOUBLE-STRUCK CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D575 ;\t004A ;\tMA\t# ( 𝕵 → J ) MATHEMATICAL BOLD FRAKTUR CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D5A9 ;\t004A ;\tMA\t# ( 𝖩 → J ) MATHEMATICAL SANS-SERIF CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D5DD ;\t004A ;\tMA\t# ( 𝗝 → J ) MATHEMATICAL SANS-SERIF BOLD CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D611 ;\t004A ;\tMA\t# ( 𝘑 → J ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D645 ;\t004A ;\tMA\t# ( 𝙅 → J ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J → LATIN CAPITAL LETTER J\t# \n1D679 ;\t004A ;\tMA\t# ( 𝙹 → J ) MATHEMATICAL MONOSPACE CAPITAL J → LATIN CAPITAL LETTER J\t# \nA7B2 ;\t004A ;\tMA\t# ( Ʝ → J ) LATIN CAPITAL LETTER J WITH CROSSED-TAIL → LATIN CAPITAL LETTER J\t# \n037F ;\t004A ;\tMA\t# ( Ϳ → J ) GREEK CAPITAL LETTER YOT → LATIN CAPITAL LETTER J\t# \n0408 ;\t004A ;\tMA\t# ( Ј → J ) CYRILLIC CAPITAL LETTER JE → LATIN CAPITAL LETTER J\t# \n13AB ;\t004A ;\tMA\t# ( Ꭻ → J ) CHEROKEE LETTER GU → LATIN CAPITAL LETTER J\t# \n148D ;\t004A ;\tMA\t# ( ᒍ → J ) CANADIAN SYLLABICS CO → LATIN CAPITAL LETTER J\t# \nA4D9 ;\t004A ;\tMA\t# ( ꓙ → J ) LISU LETTER JA → LATIN CAPITAL LETTER J\t# \n\n0249 ;\t006A 0335 ;\tMA\t# ( ɉ → j̵ ) LATIN SMALL LETTER J WITH STROKE → LATIN SMALL LETTER J, COMBINING SHORT STROKE OVERLAY\t# \n\n0248 ;\t004A 0335 ;\tMA\t# ( Ɉ → J̵ ) LATIN CAPITAL LETTER J WITH STROKE → LATIN CAPITAL LETTER J, COMBINING SHORT STROKE OVERLAY\t# \n\n1499 ;\t004A 00B7 ;\tMA\t# ( ᒙ → J· ) CANADIAN SYLLABICS WEST-CREE CWO → LATIN CAPITAL LETTER J, MIDDLE DOT\t# →ᒍᐧ→\n\n1D6A5 ;\t0237 ;\tMA\t# ( 𝚥 → ȷ ) MATHEMATICAL ITALIC SMALL DOTLESS J → LATIN SMALL LETTER DOTLESS J\t# \n0575 ;\t0237 ;\tMA\t# ( յ → ȷ ) ARMENIAN SMALL LETTER YI → LATIN SMALL LETTER DOTLESS J\t# \n\nAB7B ;\t1D0A ;\tMA\t# ( ꭻ → ᴊ ) CHEROKEE SMALL LETTER GU → LATIN LETTER SMALL CAPITAL J\t# \n\n1D424 ;\t006B ;\tMA\t# ( 𝐤 → k ) MATHEMATICAL BOLD SMALL K → LATIN SMALL LETTER K\t# \n1D458 ;\t006B ;\tMA\t# ( 𝑘 → k ) MATHEMATICAL ITALIC SMALL K → LATIN SMALL LETTER K\t# \n1D48C ;\t006B ;\tMA\t# ( 𝒌 → k ) MATHEMATICAL BOLD ITALIC SMALL K → LATIN SMALL LETTER K\t# \n1D4C0 ;\t006B ;\tMA\t# ( 𝓀 → k ) MATHEMATICAL SCRIPT SMALL K → LATIN SMALL LETTER K\t# \n1D4F4 ;\t006B ;\tMA\t# ( 𝓴 → k ) MATHEMATICAL BOLD SCRIPT SMALL K → LATIN SMALL LETTER K\t# \n1D528 ;\t006B ;\tMA\t# ( 𝔨 → k ) MATHEMATICAL FRAKTUR SMALL K → LATIN SMALL LETTER K\t# \n1D55C ;\t006B ;\tMA\t# ( 𝕜 → k ) MATHEMATICAL DOUBLE-STRUCK SMALL K → LATIN SMALL LETTER K\t# \n1D590 ;\t006B ;\tMA\t# ( 𝖐 → k ) MATHEMATICAL BOLD FRAKTUR SMALL K → LATIN SMALL LETTER K\t# \n1D5C4 ;\t006B ;\tMA\t# ( 𝗄 → k ) MATHEMATICAL SANS-SERIF SMALL K → LATIN SMALL LETTER K\t# \n1D5F8 ;\t006B ;\tMA\t# ( 𝗸 → k ) MATHEMATICAL SANS-SERIF BOLD SMALL K → LATIN SMALL LETTER K\t# \n1D62C ;\t006B ;\tMA\t# ( 𝘬 → k ) MATHEMATICAL SANS-SERIF ITALIC SMALL K → LATIN SMALL LETTER K\t# \n1D660 ;\t006B ;\tMA\t# ( 𝙠 → k ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K → LATIN SMALL LETTER K\t# \n1D694 ;\t006B ;\tMA\t# ( 𝚔 → k ) MATHEMATICAL MONOSPACE SMALL K → LATIN SMALL LETTER K\t# \n\n212A ;\t004B ;\tMA\t# ( K → K ) KELVIN SIGN → LATIN CAPITAL LETTER K\t# \nFF2B ;\t004B ;\tMA\t# ( Ｋ → K ) FULLWIDTH LATIN CAPITAL LETTER K → LATIN CAPITAL LETTER K\t# →Κ→\n1CCE0 ;\t004B ;\tMA\t#* ( 𜳠 → K ) OUTLINED LATIN CAPITAL LETTER K → LATIN CAPITAL LETTER K\t# \n1D40A ;\t004B ;\tMA\t# ( 𝐊 → K ) MATHEMATICAL BOLD CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D43E ;\t004B ;\tMA\t# ( 𝐾 → K ) MATHEMATICAL ITALIC CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D472 ;\t004B ;\tMA\t# ( 𝑲 → K ) MATHEMATICAL BOLD ITALIC CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D4A6 ;\t004B ;\tMA\t# ( 𝒦 → K ) MATHEMATICAL SCRIPT CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D4DA ;\t004B ;\tMA\t# ( 𝓚 → K ) MATHEMATICAL BOLD SCRIPT CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D50E ;\t004B ;\tMA\t# ( 𝔎 → K ) MATHEMATICAL FRAKTUR CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D542 ;\t004B ;\tMA\t# ( 𝕂 → K ) MATHEMATICAL DOUBLE-STRUCK CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D576 ;\t004B ;\tMA\t# ( 𝕶 → K ) MATHEMATICAL BOLD FRAKTUR CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D5AA ;\t004B ;\tMA\t# ( 𝖪 → K ) MATHEMATICAL SANS-SERIF CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D5DE ;\t004B ;\tMA\t# ( 𝗞 → K ) MATHEMATICAL SANS-SERIF BOLD CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D612 ;\t004B ;\tMA\t# ( 𝘒 → K ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D646 ;\t004B ;\tMA\t# ( 𝙆 → K ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K → LATIN CAPITAL LETTER K\t# \n1D67A ;\t004B ;\tMA\t# ( 𝙺 → K ) MATHEMATICAL MONOSPACE CAPITAL K → LATIN CAPITAL LETTER K\t# \n039A ;\t004B ;\tMA\t# ( Κ → K ) GREEK CAPITAL LETTER KAPPA → LATIN CAPITAL LETTER K\t# \n1D6B1 ;\t004B ;\tMA\t# ( 𝚱 → K ) MATHEMATICAL BOLD CAPITAL KAPPA → LATIN CAPITAL LETTER K\t# →Κ→\n1D6EB ;\t004B ;\tMA\t# ( 𝛫 → K ) MATHEMATICAL ITALIC CAPITAL KAPPA → LATIN CAPITAL LETTER K\t# →𝐾→\n1D725 ;\t004B ;\tMA\t# ( 𝜥 → K ) MATHEMATICAL BOLD ITALIC CAPITAL KAPPA → LATIN CAPITAL LETTER K\t# →𝑲→\n1D75F ;\t004B ;\tMA\t# ( 𝝟 → K ) MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA → LATIN CAPITAL LETTER K\t# →Κ→\n1D799 ;\t004B ;\tMA\t# ( 𝞙 → K ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA → LATIN CAPITAL LETTER K\t# →Κ→\n2C94 ;\t004B ;\tMA\t# ( Ⲕ → K ) COPTIC CAPITAL LETTER KAPA → LATIN CAPITAL LETTER K\t# →Κ→\n041A ;\t004B ;\tMA\t# ( К → K ) CYRILLIC CAPITAL LETTER KA → LATIN CAPITAL LETTER K\t# \n13E6 ;\t004B ;\tMA\t# ( Ꮶ → K ) CHEROKEE LETTER TSO → LATIN CAPITAL LETTER K\t# \n16D5 ;\t004B ;\tMA\t# ( ᛕ → K ) RUNIC LETTER OPEN-P → LATIN CAPITAL LETTER K\t# \nA4D7 ;\t004B ;\tMA\t# ( ꓗ → K ) LISU LETTER KA → LATIN CAPITAL LETTER K\t# \n10518 ;\t004B ;\tMA\t# ( 𐔘 → K ) ELBASAN LETTER QE → LATIN CAPITAL LETTER K\t# \n\n0199 ;\t006B 0314 ;\tMA\t# ( ƙ → k̔ ) LATIN SMALL LETTER K WITH HOOK → LATIN SMALL LETTER K, COMBINING REVERSED COMMA ABOVE\t# \n\n2C69 ;\t004B 0329 ;\tMA\t# ( Ⱪ → K̩ ) LATIN CAPITAL LETTER K WITH DESCENDER → LATIN CAPITAL LETTER K, COMBINING VERTICAL LINE BELOW\t# →Қ→→К̩→\n049A ;\t004B 0329 ;\tMA\t# ( Қ → K̩ ) CYRILLIC CAPITAL LETTER KA WITH DESCENDER → LATIN CAPITAL LETTER K, COMBINING VERTICAL LINE BELOW\t# →К̩→\n\n20AD ;\t004B 0335 ;\tMA\t#* ( ₭ → K̵ ) KIP SIGN → LATIN CAPITAL LETTER K, COMBINING SHORT STROKE OVERLAY\t# →K̶→\nA740 ;\t004B 0335 ;\tMA\t# ( Ꝁ → K̵ ) LATIN CAPITAL LETTER K WITH STROKE → LATIN CAPITAL LETTER K, COMBINING SHORT STROKE OVERLAY\t# →Ҟ→→К̵→\n049E ;\t004B 0335 ;\tMA\t# ( Ҟ → K̵ ) CYRILLIC CAPITAL LETTER KA WITH STROKE → LATIN CAPITAL LETTER K, COMBINING SHORT STROKE OVERLAY\t# →К̵→\n\n0198 ;\t004B 0027 ;\tMA\t# ( Ƙ → K' ) LATIN CAPITAL LETTER K WITH HOOK → LATIN CAPITAL LETTER K, APOSTROPHE\t# →Kʽ→\n\n05C0 ;\t006C ;\tMA\t#* ( ‎׀‎ → l ) HEBREW PUNCTUATION PASEQ → LATIN SMALL LETTER L\t# →|→\n007C ;\t006C ;\tMA\t#* ( | → l ) VERTICAL LINE → LATIN SMALL LETTER L\t# \n2223 ;\t006C ;\tMA\t#* ( ∣ → l ) DIVIDES → LATIN SMALL LETTER L\t# →ǀ→\n23FD ;\t006C ;\tMA\t#* ( ⏽ → l ) POWER ON SYMBOL → LATIN SMALL LETTER L\t# →I→\nFFE8 ;\t006C ;\tMA\t#* ( ￨ → l ) HALFWIDTH FORMS LIGHT VERTICAL → LATIN SMALL LETTER L\t# →|→\n0031 ;\t006C ;\tMA\t# ( 1 → l ) DIGIT ONE → LATIN SMALL LETTER L\t# \n0661 ;\t006C ;\tMA\t# ( ‎١‎ → l ) ARABIC-INDIC DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n06F1 ;\t006C ;\tMA\t# ( ۱ → l ) EXTENDED ARABIC-INDIC DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n10320 ;\t006C ;\tMA\t#* ( 𐌠 → l ) OLD ITALIC NUMERAL ONE → LATIN SMALL LETTER L\t# →𐌉→→I→\n1E8C7 ;\t006C ;\tMA\t#* ( ‎𞣇‎ → l ) MENDE KIKAKUI DIGIT ONE → LATIN SMALL LETTER L\t# \n1CCF1 ;\t006C ;\tMA\t# ( 𜳱 → l ) OUTLINED DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n1D7CF ;\t006C ;\tMA\t# ( 𝟏 → l ) MATHEMATICAL BOLD DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n1D7D9 ;\t006C ;\tMA\t# ( 𝟙 → l ) MATHEMATICAL DOUBLE-STRUCK DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n1D7E3 ;\t006C ;\tMA\t# ( 𝟣 → l ) MATHEMATICAL SANS-SERIF DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n1D7ED ;\t006C ;\tMA\t# ( 𝟭 → l ) MATHEMATICAL SANS-SERIF BOLD DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n1D7F7 ;\t006C ;\tMA\t# ( 𝟷 → l ) MATHEMATICAL MONOSPACE DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n1FBF1 ;\t006C ;\tMA\t# ( 🯱 → l ) SEGMENTED DIGIT ONE → LATIN SMALL LETTER L\t# →1→\n0049 ;\t006C ;\tMA\t# ( I → l ) LATIN CAPITAL LETTER I → LATIN SMALL LETTER L\t# \nFF29 ;\t006C ;\tMA\t# ( Ｉ → l ) FULLWIDTH LATIN CAPITAL LETTER I → LATIN SMALL LETTER L\t# →Ӏ→\n2160 ;\t006C ;\tMA\t# ( Ⅰ → l ) ROMAN NUMERAL ONE → LATIN SMALL LETTER L\t# →Ӏ→\n2110 ;\t006C ;\tMA\t# ( ℐ → l ) SCRIPT CAPITAL I → LATIN SMALL LETTER L\t# →I→\n2111 ;\t006C ;\tMA\t# ( ℑ → l ) BLACK-LETTER CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1CCDE ;\t006C ;\tMA\t#* ( 𜳞 → l ) OUTLINED LATIN CAPITAL LETTER I → LATIN SMALL LETTER L\t# →I→\n1D408 ;\t006C ;\tMA\t# ( 𝐈 → l ) MATHEMATICAL BOLD CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D43C ;\t006C ;\tMA\t# ( 𝐼 → l ) MATHEMATICAL ITALIC CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D470 ;\t006C ;\tMA\t# ( 𝑰 → l ) MATHEMATICAL BOLD ITALIC CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D4D8 ;\t006C ;\tMA\t# ( 𝓘 → l ) MATHEMATICAL BOLD SCRIPT CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D540 ;\t006C ;\tMA\t# ( 𝕀 → l ) MATHEMATICAL DOUBLE-STRUCK CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D574 ;\t006C ;\tMA\t# ( 𝕴 → l ) MATHEMATICAL BOLD FRAKTUR CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D5A8 ;\t006C ;\tMA\t# ( 𝖨 → l ) MATHEMATICAL SANS-SERIF CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D5DC ;\t006C ;\tMA\t# ( 𝗜 → l ) MATHEMATICAL SANS-SERIF BOLD CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D610 ;\t006C ;\tMA\t# ( 𝘐 → l ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D644 ;\t006C ;\tMA\t# ( 𝙄 → l ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I → LATIN SMALL LETTER L\t# →I→\n1D678 ;\t006C ;\tMA\t# ( 𝙸 → l ) MATHEMATICAL MONOSPACE CAPITAL I → LATIN SMALL LETTER L\t# →I→\n0196 ;\t006C ;\tMA\t# ( Ɩ → l ) LATIN CAPITAL LETTER IOTA → LATIN SMALL LETTER L\t# \nFF4C ;\t006C ;\tMA\t# ( ｌ → l ) FULLWIDTH LATIN SMALL LETTER L → LATIN SMALL LETTER L\t# →Ⅰ→→Ӏ→\n217C ;\t006C ;\tMA\t# ( ⅼ → l ) SMALL ROMAN NUMERAL FIFTY → LATIN SMALL LETTER L\t# \n2113 ;\t006C ;\tMA\t# ( ℓ → l ) SCRIPT SMALL L → LATIN SMALL LETTER L\t# \n1D425 ;\t006C ;\tMA\t# ( 𝐥 → l ) MATHEMATICAL BOLD SMALL L → LATIN SMALL LETTER L\t# \n1D459 ;\t006C ;\tMA\t# ( 𝑙 → l ) MATHEMATICAL ITALIC SMALL L → LATIN SMALL LETTER L\t# \n1D48D ;\t006C ;\tMA\t# ( 𝒍 → l ) MATHEMATICAL BOLD ITALIC SMALL L → LATIN SMALL LETTER L\t# \n1D4C1 ;\t006C ;\tMA\t# ( 𝓁 → l ) MATHEMATICAL SCRIPT SMALL L → LATIN SMALL LETTER L\t# \n1D4F5 ;\t006C ;\tMA\t# ( 𝓵 → l ) MATHEMATICAL BOLD SCRIPT SMALL L → LATIN SMALL LETTER L\t# \n1D529 ;\t006C ;\tMA\t# ( 𝔩 → l ) MATHEMATICAL FRAKTUR SMALL L → LATIN SMALL LETTER L\t# \n1D55D ;\t006C ;\tMA\t# ( 𝕝 → l ) MATHEMATICAL DOUBLE-STRUCK SMALL L → LATIN SMALL LETTER L\t# \n1D591 ;\t006C ;\tMA\t# ( 𝖑 → l ) MATHEMATICAL BOLD FRAKTUR SMALL L → LATIN SMALL LETTER L\t# \n1D5C5 ;\t006C ;\tMA\t# ( 𝗅 → l ) MATHEMATICAL SANS-SERIF SMALL L → LATIN SMALL LETTER L\t# \n1D5F9 ;\t006C ;\tMA\t# ( 𝗹 → l ) MATHEMATICAL SANS-SERIF BOLD SMALL L → LATIN SMALL LETTER L\t# \n1D62D ;\t006C ;\tMA\t# ( 𝘭 → l ) MATHEMATICAL SANS-SERIF ITALIC SMALL L → LATIN SMALL LETTER L\t# \n1D661 ;\t006C ;\tMA\t# ( 𝙡 → l ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L → LATIN SMALL LETTER L\t# \n1D695 ;\t006C ;\tMA\t# ( 𝚕 → l ) MATHEMATICAL MONOSPACE SMALL L → LATIN SMALL LETTER L\t# \n01C0 ;\t006C ;\tMA\t# ( ǀ → l ) LATIN LETTER DENTAL CLICK → LATIN SMALL LETTER L\t# \n0399 ;\t006C ;\tMA\t# ( Ι → l ) GREEK CAPITAL LETTER IOTA → LATIN SMALL LETTER L\t# \n1D6B0 ;\t006C ;\tMA\t# ( 𝚰 → l ) MATHEMATICAL BOLD CAPITAL IOTA → LATIN SMALL LETTER L\t# →Ι→\n1D6EA ;\t006C ;\tMA\t# ( 𝛪 → l ) MATHEMATICAL ITALIC CAPITAL IOTA → LATIN SMALL LETTER L\t# →Ι→\n1D724 ;\t006C ;\tMA\t# ( 𝜤 → l ) MATHEMATICAL BOLD ITALIC CAPITAL IOTA → LATIN SMALL LETTER L\t# →Ι→\n1D75E ;\t006C ;\tMA\t# ( 𝝞 → l ) MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA → LATIN SMALL LETTER L\t# →Ι→\n1D798 ;\t006C ;\tMA\t# ( 𝞘 → l ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA → LATIN SMALL LETTER L\t# →Ι→\n2C92 ;\t006C ;\tMA\t# ( Ⲓ → l ) COPTIC CAPITAL LETTER IAUDA → LATIN SMALL LETTER L\t# →Ӏ→\n0406 ;\t006C ;\tMA\t# ( І → l ) CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I → LATIN SMALL LETTER L\t# \n04CF ;\t006C ;\tMA\t# ( ӏ → l ) CYRILLIC SMALL LETTER PALOCHKA → LATIN SMALL LETTER L\t# →I→\n04C0 ;\t006C ;\tMA\t# ( Ӏ → l ) CYRILLIC LETTER PALOCHKA → LATIN SMALL LETTER L\t# \n05D5 ;\t006C ;\tMA\t# ( ‎ו‎ → l ) HEBREW LETTER VAV → LATIN SMALL LETTER L\t# \n05DF ;\t006C ;\tMA\t# ( ‎ן‎ → l ) HEBREW LETTER FINAL NUN → LATIN SMALL LETTER L\t# \n0627 ;\t006C ;\tMA\t# ( ‎ا‎ → l ) ARABIC LETTER ALEF → LATIN SMALL LETTER L\t# →1→\n1EE00 ;\t006C ;\tMA\t# ( ‎𞸀‎ → l ) ARABIC MATHEMATICAL ALEF → LATIN SMALL LETTER L\t# →‎ا‎→→1→\n1EE80 ;\t006C ;\tMA\t# ( ‎𞺀‎ → l ) ARABIC MATHEMATICAL LOOPED ALEF → LATIN SMALL LETTER L\t# →‎ا‎→→1→\nFE8E ;\t006C ;\tMA\t# ( ‎ﺎ‎ → l ) ARABIC LETTER ALEF FINAL FORM → LATIN SMALL LETTER L\t# →‎ا‎→→1→\nFE8D ;\t006C ;\tMA\t# ( ‎ﺍ‎ → l ) ARABIC LETTER ALEF ISOLATED FORM → LATIN SMALL LETTER L\t# →‎ا‎→→1→\n07CA ;\t006C ;\tMA\t# ( ‎ߊ‎ → l ) NKO LETTER A → LATIN SMALL LETTER L\t# →∣→→ǀ→\n2D4F ;\t006C ;\tMA\t# ( ⵏ → l ) TIFINAGH LETTER YAN → LATIN SMALL LETTER L\t# →Ӏ→\n16C1 ;\t006C ;\tMA\t# ( ᛁ → l ) RUNIC LETTER ISAZ IS ISS I → LATIN SMALL LETTER L\t# →I→\nA4F2 ;\t006C ;\tMA\t# ( ꓲ → l ) LISU LETTER I → LATIN SMALL LETTER L\t# →I→\n16F28 ;\t006C ;\tMA\t# ( 𖼨 → l ) MIAO LETTER GHA → LATIN SMALL LETTER L\t# →I→\n1028A ;\t006C ;\tMA\t# ( 𐊊 → l ) LYCIAN LETTER J → LATIN SMALL LETTER L\t# →I→\n10309 ;\t006C ;\tMA\t# ( 𐌉 → l ) OLD ITALIC LETTER I → LATIN SMALL LETTER L\t# →I→\n11DDA ;\t006C ;\tMA\t# ( 𑷚 → l ) TOLONG SIKI SIGN HECAKA → LATIN SMALL LETTER L\t# →|→\n11DE1 ;\t006C ;\tMA\t# ( 𑷡 → l ) TOLONG SIKI DIGIT ONE → LATIN SMALL LETTER L\t# →|→\n16EAA ;\t006C ;\tMA\t# ( 𖺪 → l ) BERIA ERFE CAPITAL LETTER LAKKO → LATIN SMALL LETTER L\t# →I→\n\n1D22A ;\t004C ;\tMA\t#* ( 𝈪 → L ) GREEK INSTRUMENTAL NOTATION SYMBOL-23 → LATIN CAPITAL LETTER L\t# \n216C ;\t004C ;\tMA\t# ( Ⅼ → L ) ROMAN NUMERAL FIFTY → LATIN CAPITAL LETTER L\t# \n2112 ;\t004C ;\tMA\t# ( ℒ → L ) SCRIPT CAPITAL L → LATIN CAPITAL LETTER L\t# \n1CCE1 ;\t004C ;\tMA\t#* ( 𜳡 → L ) OUTLINED LATIN CAPITAL LETTER L → LATIN CAPITAL LETTER L\t# \n1D40B ;\t004C ;\tMA\t# ( 𝐋 → L ) MATHEMATICAL BOLD CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D43F ;\t004C ;\tMA\t# ( 𝐿 → L ) MATHEMATICAL ITALIC CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D473 ;\t004C ;\tMA\t# ( 𝑳 → L ) MATHEMATICAL BOLD ITALIC CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D4DB ;\t004C ;\tMA\t# ( 𝓛 → L ) MATHEMATICAL BOLD SCRIPT CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D50F ;\t004C ;\tMA\t# ( 𝔏 → L ) MATHEMATICAL FRAKTUR CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D543 ;\t004C ;\tMA\t# ( 𝕃 → L ) MATHEMATICAL DOUBLE-STRUCK CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D577 ;\t004C ;\tMA\t# ( 𝕷 → L ) MATHEMATICAL BOLD FRAKTUR CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D5AB ;\t004C ;\tMA\t# ( 𝖫 → L ) MATHEMATICAL SANS-SERIF CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D5DF ;\t004C ;\tMA\t# ( 𝗟 → L ) MATHEMATICAL SANS-SERIF BOLD CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D613 ;\t004C ;\tMA\t# ( 𝘓 → L ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D647 ;\t004C ;\tMA\t# ( 𝙇 → L ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L → LATIN CAPITAL LETTER L\t# \n1D67B ;\t004C ;\tMA\t# ( 𝙻 → L ) MATHEMATICAL MONOSPACE CAPITAL L → LATIN CAPITAL LETTER L\t# \n2CD0 ;\t004C ;\tMA\t# ( Ⳑ → L ) COPTIC CAPITAL LETTER L-SHAPED HA → LATIN CAPITAL LETTER L\t# \n13DE ;\t004C ;\tMA\t# ( Ꮮ → L ) CHEROKEE LETTER TLE → LATIN CAPITAL LETTER L\t# \n14AA ;\t004C ;\tMA\t# ( ᒪ → L ) CANADIAN SYLLABICS MA → LATIN CAPITAL LETTER L\t# \nA4E1 ;\t004C ;\tMA\t# ( ꓡ → L ) LISU LETTER LA → LATIN CAPITAL LETTER L\t# \n16F16 ;\t004C ;\tMA\t# ( 𖼖 → L ) MIAO LETTER LA → LATIN CAPITAL LETTER L\t# \n118A3 ;\t004C ;\tMA\t# ( 𑢣 → L ) WARANG CITI CAPITAL LETTER YU → LATIN CAPITAL LETTER L\t# \n118B2 ;\t004C ;\tMA\t# ( 𑢲 → L ) WARANG CITI CAPITAL LETTER TTE → LATIN CAPITAL LETTER L\t# \n1041B ;\t004C ;\tMA\t# ( 𐐛 → L ) DESERET CAPITAL LETTER ETH → LATIN CAPITAL LETTER L\t# \n10526 ;\t004C ;\tMA\t# ( 𐔦 → L ) ELBASAN LETTER GHAMMA → LATIN CAPITAL LETTER L\t# \n\nFD3C ;\t006C 030B ;\tMA\t# ( ‎ﴼ‎ → l̋ ) ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM → LATIN SMALL LETTER L, COMBINING DOUBLE ACUTE ACCENT\t# →‎اً‎→\nFD3D ;\t006C 030B ;\tMA\t# ( ‎ﴽ‎ → l̋ ) ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM → LATIN SMALL LETTER L, COMBINING DOUBLE ACUTE ACCENT\t# →‎اً‎→\n\n0142 ;\t006C 0338 ;\tMA\t# ( ł → l̸ ) LATIN SMALL LETTER L WITH STROKE → LATIN SMALL LETTER L, COMBINING LONG SOLIDUS OVERLAY\t# →l̷→\n\n0141 ;\t004C 0338 ;\tMA\t# ( Ł → L̸ ) LATIN CAPITAL LETTER L WITH STROKE → LATIN CAPITAL LETTER L, COMBINING LONG SOLIDUS OVERLAY\t# →L̷→\n\n026D ;\t006C 0328 ;\tMA\t# ( ɭ → l̨ ) LATIN SMALL LETTER L WITH RETROFLEX HOOK → LATIN SMALL LETTER L, COMBINING OGONEK\t# →l̢→\n\n0197 ;\t006C 0335 ;\tMA\t# ( Ɨ → l̵ ) LATIN CAPITAL LETTER I WITH STROKE → LATIN SMALL LETTER L, COMBINING SHORT STROKE OVERLAY\t# →ƚ→\n019A ;\t006C 0335 ;\tMA\t# ( ƚ → l̵ ) LATIN SMALL LETTER L WITH BAR → LATIN SMALL LETTER L, COMBINING SHORT STROKE OVERLAY\t# \n\n026B ;\t006C 0334 ;\tMA\t# ( ɫ → l̴ ) LATIN SMALL LETTER L WITH MIDDLE TILDE → LATIN SMALL LETTER L, COMBINING TILDE OVERLAY\t# \n\n0625 ;\t006C 0655 ;\tMA\t# ( ‎إ‎ → lٕ ) ARABIC LETTER ALEF WITH HAMZA BELOW → LATIN SMALL LETTER L, ARABIC HAMZA BELOW\t# →‎ٳ‎→→‎اٟ‎→\nFE88 ;\t006C 0655 ;\tMA\t# ( ‎ﺈ‎ → lٕ ) ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM → LATIN SMALL LETTER L, ARABIC HAMZA BELOW\t# →‎إ‎→→‎ٳ‎→→‎اٟ‎→\nFE87 ;\t006C 0655 ;\tMA\t# ( ‎ﺇ‎ → lٕ ) ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM → LATIN SMALL LETTER L, ARABIC HAMZA BELOW\t# →‎إ‎→→‎ٳ‎→→‎اٟ‎→\n0673 ;\t006C 0655 ;\tMA\t# ( ‎ٳ‎ → lٕ ) ARABIC LETTER ALEF WITH WAVY HAMZA BELOW → LATIN SMALL LETTER L, ARABIC HAMZA BELOW\t# →‎اٟ‎→\n\n0140 ;\t006C 00B7 ;\tMA\t# ( ŀ → l· ) LATIN SMALL LETTER L WITH MIDDLE DOT → LATIN SMALL LETTER L, MIDDLE DOT\t# \n013F ;\t006C 00B7 ;\tMA\t# ( Ŀ → l· ) LATIN CAPITAL LETTER L WITH MIDDLE DOT → LATIN SMALL LETTER L, MIDDLE DOT\t# →L·→→ᒪ·→→ᒪᐧ→→ᒷ→→1ᐧ→\n14B7 ;\t006C 00B7 ;\tMA\t# ( ᒷ → l· ) CANADIAN SYLLABICS WEST-CREE MWA → LATIN SMALL LETTER L, MIDDLE DOT\t# →1ᐧ→\n\n1F102 ;\t006C 002C ;\tMA\t#* ( 🄂 → l, ) DIGIT ONE COMMA → LATIN SMALL LETTER L, COMMA\t# →1,→\n\n2488 ;\t006C 002E ;\tMA\t#* ( ⒈ → l. ) DIGIT ONE FULL STOP → LATIN SMALL LETTER L, FULL STOP\t# →1.→\n\n05F1 ;\t006C 0027 ;\tMA\t# ( ‎ױ‎ → l' ) HEBREW LIGATURE YIDDISH VAV YOD → LATIN SMALL LETTER L, APOSTROPHE\t# →‎וי‎→\n\n2493 ;\t006C 0032 002E ;\tMA\t#* ( ⒓ → l2. ) NUMBER TWELVE FULL STOP → LATIN SMALL LETTER L, DIGIT TWO, FULL STOP\t# →12.→\n\n33EB ;\t006C 0032 65E5 ;\tMA\t#* ( ㏫ → l2日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE → LATIN SMALL LETTER L, DIGIT TWO, CJK UNIFIED IDEOGRAPH-65E5\t# →12日→\n\n32CB ;\t006C 0032 6708 ;\tMA\t#* ( ㋋ → l2月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER → LATIN SMALL LETTER L, DIGIT TWO, CJK UNIFIED IDEOGRAPH-6708\t# →12月→\n\n3364 ;\t006C 0032 70B9 ;\tMA\t#* ( ㍤ → l2点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE → LATIN SMALL LETTER L, DIGIT TWO, CJK UNIFIED IDEOGRAPH-70B9\t# →12点→\n\n2494 ;\t006C 0033 002E ;\tMA\t#* ( ⒔ → l3. ) NUMBER THIRTEEN FULL STOP → LATIN SMALL LETTER L, DIGIT THREE, FULL STOP\t# →13.→\n\n33EC ;\t006C 0033 65E5 ;\tMA\t#* ( ㏬ → l3日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN → LATIN SMALL LETTER L, DIGIT THREE, CJK UNIFIED IDEOGRAPH-65E5\t# →13日→\n\n3365 ;\t006C 0033 70B9 ;\tMA\t#* ( ㍥ → l3点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN → LATIN SMALL LETTER L, DIGIT THREE, CJK UNIFIED IDEOGRAPH-70B9\t# →13点→\n\n2495 ;\t006C 0034 002E ;\tMA\t#* ( ⒕ → l4. ) NUMBER FOURTEEN FULL STOP → LATIN SMALL LETTER L, DIGIT FOUR, FULL STOP\t# →14.→\n\n33ED ;\t006C 0034 65E5 ;\tMA\t#* ( ㏭ → l4日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN → LATIN SMALL LETTER L, DIGIT FOUR, CJK UNIFIED IDEOGRAPH-65E5\t# →14日→\n\n3366 ;\t006C 0034 70B9 ;\tMA\t#* ( ㍦ → l4点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN → LATIN SMALL LETTER L, DIGIT FOUR, CJK UNIFIED IDEOGRAPH-70B9\t# →14点→\n\n2496 ;\t006C 0035 002E ;\tMA\t#* ( ⒖ → l5. ) NUMBER FIFTEEN FULL STOP → LATIN SMALL LETTER L, DIGIT FIVE, FULL STOP\t# →15.→\n\n33EE ;\t006C 0035 65E5 ;\tMA\t#* ( ㏮ → l5日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN → LATIN SMALL LETTER L, DIGIT FIVE, CJK UNIFIED IDEOGRAPH-65E5\t# →15日→\n\n3367 ;\t006C 0035 70B9 ;\tMA\t#* ( ㍧ → l5点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN → LATIN SMALL LETTER L, DIGIT FIVE, CJK UNIFIED IDEOGRAPH-70B9\t# →15点→\n\n2497 ;\t006C 0036 002E ;\tMA\t#* ( ⒗ → l6. ) NUMBER SIXTEEN FULL STOP → LATIN SMALL LETTER L, DIGIT SIX, FULL STOP\t# →16.→\n\n33EF ;\t006C 0036 65E5 ;\tMA\t#* ( ㏯ → l6日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN → LATIN SMALL LETTER L, DIGIT SIX, CJK UNIFIED IDEOGRAPH-65E5\t# →16日→\n\n3368 ;\t006C 0036 70B9 ;\tMA\t#* ( ㍨ → l6点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN → LATIN SMALL LETTER L, DIGIT SIX, CJK UNIFIED IDEOGRAPH-70B9\t# →16点→\n\n2498 ;\t006C 0037 002E ;\tMA\t#* ( ⒘ → l7. ) NUMBER SEVENTEEN FULL STOP → LATIN SMALL LETTER L, DIGIT SEVEN, FULL STOP\t# →17.→\n\n33F0 ;\t006C 0037 65E5 ;\tMA\t#* ( ㏰ → l7日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN → LATIN SMALL LETTER L, DIGIT SEVEN, CJK UNIFIED IDEOGRAPH-65E5\t# →17日→\n\n3369 ;\t006C 0037 70B9 ;\tMA\t#* ( ㍩ → l7点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN → LATIN SMALL LETTER L, DIGIT SEVEN, CJK UNIFIED IDEOGRAPH-70B9\t# →17点→\n\n2499 ;\t006C 0038 002E ;\tMA\t#* ( ⒙ → l8. ) NUMBER EIGHTEEN FULL STOP → LATIN SMALL LETTER L, DIGIT EIGHT, FULL STOP\t# →18.→\n\n33F1 ;\t006C 0038 65E5 ;\tMA\t#* ( ㏱ → l8日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN → LATIN SMALL LETTER L, DIGIT EIGHT, CJK UNIFIED IDEOGRAPH-65E5\t# →18日→\n\n336A ;\t006C 0038 70B9 ;\tMA\t#* ( ㍪ → l8点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN → LATIN SMALL LETTER L, DIGIT EIGHT, CJK UNIFIED IDEOGRAPH-70B9\t# →18点→\n\n249A ;\t006C 0039 002E ;\tMA\t#* ( ⒚ → l9. ) NUMBER NINETEEN FULL STOP → LATIN SMALL LETTER L, DIGIT NINE, FULL STOP\t# →19.→\n\n33F2 ;\t006C 0039 65E5 ;\tMA\t#* ( ㏲ → l9日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN → LATIN SMALL LETTER L, DIGIT NINE, CJK UNIFIED IDEOGRAPH-65E5\t# →19日→\n\n336B ;\t006C 0039 70B9 ;\tMA\t#* ( ㍫ → l9点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN → LATIN SMALL LETTER L, DIGIT NINE, CJK UNIFIED IDEOGRAPH-70B9\t# →19点→\n\n01C9 ;\t006C 006A ;\tMA\t# ( ǉ → lj ) LATIN SMALL LETTER LJ → LATIN SMALL LETTER L, LATIN SMALL LETTER J\t# \n\n0132 ;\t006C 004A ;\tMA\t# ( Ĳ → lJ ) LATIN CAPITAL LIGATURE IJ → LATIN SMALL LETTER L, LATIN CAPITAL LETTER J\t# →IJ→\n\n01C8 ;\t004C 006A ;\tMA\t# ( ǈ → Lj ) LATIN CAPITAL LETTER L WITH SMALL LETTER J → LATIN CAPITAL LETTER L, LATIN SMALL LETTER J\t# \n\n01C7 ;\t004C 004A ;\tMA\t# ( Ǉ → LJ ) LATIN CAPITAL LETTER LJ → LATIN CAPITAL LETTER L, LATIN CAPITAL LETTER J\t# \n\n2016 ;\t006C 006C ;\tMA\t#* ( ‖ → ll ) DOUBLE VERTICAL LINE → LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →∥→→||→\n2225 ;\t006C 006C ;\tMA\t#* ( ∥ → ll ) PARALLEL TO → LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →||→\n2161 ;\t006C 006C ;\tMA\t# ( Ⅱ → ll ) ROMAN NUMERAL TWO → LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →II→\n01C1 ;\t006C 006C ;\tMA\t# ( ǁ → ll ) LATIN LETTER LATERAL CLICK → LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →‖→→∥→→||→\n05F0 ;\t006C 006C ;\tMA\t# ( ‎װ‎ → ll ) HEBREW LIGATURE YIDDISH DOUBLE VAV → LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →‎וו‎→\n\n10199 ;\t006C 0335 006C 0335 ;\tMA\t#* ( 𐆙 → l̵l̵ ) ROMAN DUPONDIUS SIGN → LATIN SMALL LETTER L, COMBINING SHORT STROKE OVERLAY, LATIN SMALL LETTER L, COMBINING SHORT STROKE OVERLAY\t# →I̶I̶→\n\n2492 ;\t006C 006C 002E ;\tMA\t#* ( ⒒ → ll. ) NUMBER ELEVEN FULL STOP → LATIN SMALL LETTER L, LATIN SMALL LETTER L, FULL STOP\t# →11.→\n\n2162 ;\t006C 006C 006C ;\tMA\t# ( Ⅲ → lll ) ROMAN NUMERAL THREE → LATIN SMALL LETTER L, LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →III→\n\n10198 ;\t006C 0335 006C 0335 0053 0335 ;\tMA\t#* ( 𐆘 → l̵l̵S̵ ) ROMAN SESTERTIUS SIGN → LATIN SMALL LETTER L, COMBINING SHORT STROKE OVERLAY, LATIN SMALL LETTER L, COMBINING SHORT STROKE OVERLAY, LATIN CAPITAL LETTER S, COMBINING SHORT STROKE OVERLAY\t# →I̶I̶S̶→\n\n33EA ;\t006C 006C 65E5 ;\tMA\t#* ( ㏪ → ll日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN → LATIN SMALL LETTER L, LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-65E5\t# →11日→\n\n32CA ;\t006C 006C 6708 ;\tMA\t#* ( ㋊ → ll月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER → LATIN SMALL LETTER L, LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-6708\t# →11月→\n\n3363 ;\t006C 006C 70B9 ;\tMA\t#* ( ㍣ → ll点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN → LATIN SMALL LETTER L, LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-70B9\t# →11点→\n\n042E ;\t006C 004F ;\tMA\t# ( Ю → lO ) CYRILLIC CAPITAL LETTER YU → LATIN SMALL LETTER L, LATIN CAPITAL LETTER O\t# →IO→\n\n2491 ;\t006C 004F 002E ;\tMA\t#* ( ⒑ → lO. ) NUMBER TEN FULL STOP → LATIN SMALL LETTER L, LATIN CAPITAL LETTER O, FULL STOP\t# →10.→\n\n33E9 ;\t006C 004F 65E5 ;\tMA\t#* ( ㏩ → lO日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN → LATIN SMALL LETTER L, LATIN CAPITAL LETTER O, CJK UNIFIED IDEOGRAPH-65E5\t# →10日→\n\n32C9 ;\t006C 004F 6708 ;\tMA\t#* ( ㋉ → lO月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER → LATIN SMALL LETTER L, LATIN CAPITAL LETTER O, CJK UNIFIED IDEOGRAPH-6708\t# →10月→\n\n3362 ;\t006C 004F 70B9 ;\tMA\t#* ( ㍢ → lO点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN → LATIN SMALL LETTER L, LATIN CAPITAL LETTER O, CJK UNIFIED IDEOGRAPH-70B9\t# →10点→\n\n02AA ;\t006C 0073 ;\tMA\t# ( ʪ → ls ) LATIN SMALL LETTER LS DIGRAPH → LATIN SMALL LETTER L, LATIN SMALL LETTER S\t# \n\n20B6 ;\t006C 0074 ;\tMA\t#* ( ₶ → lt ) LIVRE TOURNOIS SIGN → LATIN SMALL LETTER L, LATIN SMALL LETTER T\t# \n\n2163 ;\t006C 0056 ;\tMA\t# ( Ⅳ → lV ) ROMAN NUMERAL FOUR → LATIN SMALL LETTER L, LATIN CAPITAL LETTER V\t# →IV→\n\n2168 ;\t006C 0058 ;\tMA\t# ( Ⅸ → lX ) ROMAN NUMERAL NINE → LATIN SMALL LETTER L, LATIN CAPITAL LETTER X\t# →IX→\n\n026E ;\t006C 021D ;\tMA\t# ( ɮ → lȝ ) LATIN SMALL LETTER LEZH → LATIN SMALL LETTER L, LATIN SMALL LETTER YOGH\t# →lʒ→\n\n02AB ;\t006C 007A ;\tMA\t# ( ʫ → lz ) LATIN SMALL LETTER LZ DIGRAPH → LATIN SMALL LETTER L, LATIN SMALL LETTER Z\t# \n\n0675 ;\t006C 0674 ;\tMA\t# ( ‎ٵ‎ → ‎lٴ‎ ) ARABIC LETTER HIGH HAMZA ALEF → LATIN SMALL LETTER L, ARABIC LETTER HIGH HAMZA\t# →‎اٴ‎→\n0623 ;\t006C 0674 ;\tMA\t# ( ‎أ‎ → ‎lٴ‎ ) ARABIC LETTER ALEF WITH HAMZA ABOVE → LATIN SMALL LETTER L, ARABIC LETTER HIGH HAMZA\t# →‎ٵ‎→→‎اٴ‎→\nFE84 ;\t006C 0674 ;\tMA\t# ( ‎ﺄ‎ → ‎lٴ‎ ) ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM → LATIN SMALL LETTER L, ARABIC LETTER HIGH HAMZA\t# →‎أ‎→→‎ٵ‎→→‎اٴ‎→\nFE83 ;\t006C 0674 ;\tMA\t# ( ‎ﺃ‎ → ‎lٴ‎ ) ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM → LATIN SMALL LETTER L, ARABIC LETTER HIGH HAMZA\t# →‎ٵ‎→→‎اٴ‎→\n0672 ;\t006C 0674 ;\tMA\t# ( ‎ٲ‎ → ‎lٴ‎ ) ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE → LATIN SMALL LETTER L, ARABIC LETTER HIGH HAMZA\t# →‎أ‎→→‎ٵ‎→→‎اٴ‎→\n\nFDF3 ;\t006C 0643 0628 0631 ;\tMA\t# ( ‎ﷳ‎ → ‎lكبر‎ ) ARABIC LIGATURE AKBAR ISOLATED FORM → LATIN SMALL LETTER L, ARABIC LETTER KAF, ARABIC LETTER BEH, ARABIC LETTER REH\t# →‎اكبر‎→\n\nFDF2 ;\t006C 0644 0644 0651 0670 006F ;\tMA\t# ( ‎ﷲ‎ → ‎lللّٰo‎ ) ARABIC LIGATURE ALLAH ISOLATED FORM → LATIN SMALL LETTER L, ARABIC LETTER LAM, ARABIC LETTER LAM, ARABIC SHADDA, ARABIC LETTER SUPERSCRIPT ALEF, LATIN SMALL LETTER O\t# →‎اللّٰه‎→\n\n33E0 ;\t006C 65E5 ;\tMA\t#* ( ㏠ → l日 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE → LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-65E5\t# →1日→\n\n32C0 ;\t006C 6708 ;\tMA\t#* ( ㋀ → l月 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY → LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-6708\t# →1月→\n\n3359 ;\t006C 70B9 ;\tMA\t#* ( ㍙ → l点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE → LATIN SMALL LETTER L, CJK UNIFIED IDEOGRAPH-70B9\t# →1点→\n\n2CD1 ;\t029F ;\tMA\t# ( ⳑ → ʟ ) COPTIC SMALL LETTER L-SHAPED HA → LATIN LETTER SMALL CAPITAL L\t# \nABAE ;\t029F ;\tMA\t# ( ꮮ → ʟ ) CHEROKEE SMALL LETTER TLE → LATIN LETTER SMALL CAPITAL L\t# \n10443 ;\t029F ;\tMA\t# ( 𐑃 → ʟ ) DESERET SMALL LETTER ETH → LATIN LETTER SMALL CAPITAL L\t# \n\nFF2D ;\t004D ;\tMA\t# ( Ｍ → M ) FULLWIDTH LATIN CAPITAL LETTER M → LATIN CAPITAL LETTER M\t# →Μ→\n216F ;\t004D ;\tMA\t# ( Ⅿ → M ) ROMAN NUMERAL ONE THOUSAND → LATIN CAPITAL LETTER M\t# \n2133 ;\t004D ;\tMA\t# ( ℳ → M ) SCRIPT CAPITAL M → LATIN CAPITAL LETTER M\t# \n1CCE2 ;\t004D ;\tMA\t#* ( 𜳢 → M ) OUTLINED LATIN CAPITAL LETTER M → LATIN CAPITAL LETTER M\t# \n1D40C ;\t004D ;\tMA\t# ( 𝐌 → M ) MATHEMATICAL BOLD CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D440 ;\t004D ;\tMA\t# ( 𝑀 → M ) MATHEMATICAL ITALIC CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D474 ;\t004D ;\tMA\t# ( 𝑴 → M ) MATHEMATICAL BOLD ITALIC CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D4DC ;\t004D ;\tMA\t# ( 𝓜 → M ) MATHEMATICAL BOLD SCRIPT CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D510 ;\t004D ;\tMA\t# ( 𝔐 → M ) MATHEMATICAL FRAKTUR CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D544 ;\t004D ;\tMA\t# ( 𝕄 → M ) MATHEMATICAL DOUBLE-STRUCK CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D578 ;\t004D ;\tMA\t# ( 𝕸 → M ) MATHEMATICAL BOLD FRAKTUR CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D5AC ;\t004D ;\tMA\t# ( 𝖬 → M ) MATHEMATICAL SANS-SERIF CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D5E0 ;\t004D ;\tMA\t# ( 𝗠 → M ) MATHEMATICAL SANS-SERIF BOLD CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D614 ;\t004D ;\tMA\t# ( 𝘔 → M ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D648 ;\t004D ;\tMA\t# ( 𝙈 → M ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M → LATIN CAPITAL LETTER M\t# \n1D67C ;\t004D ;\tMA\t# ( 𝙼 → M ) MATHEMATICAL MONOSPACE CAPITAL M → LATIN CAPITAL LETTER M\t# \n039C ;\t004D ;\tMA\t# ( Μ → M ) GREEK CAPITAL LETTER MU → LATIN CAPITAL LETTER M\t# \n1D6B3 ;\t004D ;\tMA\t# ( 𝚳 → M ) MATHEMATICAL BOLD CAPITAL MU → LATIN CAPITAL LETTER M\t# →𝐌→\n1D6ED ;\t004D ;\tMA\t# ( 𝛭 → M ) MATHEMATICAL ITALIC CAPITAL MU → LATIN CAPITAL LETTER M\t# →𝑀→\n1D727 ;\t004D ;\tMA\t# ( 𝜧 → M ) MATHEMATICAL BOLD ITALIC CAPITAL MU → LATIN CAPITAL LETTER M\t# →𝑴→\n1D761 ;\t004D ;\tMA\t# ( 𝝡 → M ) MATHEMATICAL SANS-SERIF BOLD CAPITAL MU → LATIN CAPITAL LETTER M\t# →Μ→\n1D79B ;\t004D ;\tMA\t# ( 𝞛 → M ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU → LATIN CAPITAL LETTER M\t# →Μ→\n03FA ;\t004D ;\tMA\t# ( Ϻ → M ) GREEK CAPITAL LETTER SAN → LATIN CAPITAL LETTER M\t# \n2C98 ;\t004D ;\tMA\t# ( Ⲙ → M ) COPTIC CAPITAL LETTER MI → LATIN CAPITAL LETTER M\t# \n041C ;\t004D ;\tMA\t# ( М → M ) CYRILLIC CAPITAL LETTER EM → LATIN CAPITAL LETTER M\t# \n13B7 ;\t004D ;\tMA\t# ( Ꮇ → M ) CHEROKEE LETTER LU → LATIN CAPITAL LETTER M\t# \n15F0 ;\t004D ;\tMA\t# ( ᗰ → M ) CANADIAN SYLLABICS CARRIER GO → LATIN CAPITAL LETTER M\t# \n16D6 ;\t004D ;\tMA\t# ( ᛖ → M ) RUNIC LETTER EHWAZ EH E → LATIN CAPITAL LETTER M\t# \nA4DF ;\t004D ;\tMA\t# ( ꓟ → M ) LISU LETTER MA → LATIN CAPITAL LETTER M\t# \n102B0 ;\t004D ;\tMA\t# ( 𐊰 → M ) CARIAN LETTER S → LATIN CAPITAL LETTER M\t# \n10311 ;\t004D ;\tMA\t# ( 𐌑 → M ) OLD ITALIC LETTER SHE → LATIN CAPITAL LETTER M\t# \n\n04CD ;\t004D 0326 ;\tMA\t# ( Ӎ → M̦ ) CYRILLIC CAPITAL LETTER EM WITH TAIL → LATIN CAPITAL LETTER M, COMBINING COMMA BELOW\t# →М̡→\n\n1F76B ;\t004D 0042 ;\tMA\t#* ( 🝫 → MB ) ALCHEMICAL SYMBOL FOR BATH OF MARY → LATIN CAPITAL LETTER M, LATIN CAPITAL LETTER B\t# \n\n2DE8 ;\t1DDF ;\tMA\t# ( ⷨ → ᷟ ) COMBINING CYRILLIC LETTER EM → COMBINING LATIN LETTER SMALL CAPITAL M\t# \n\n1D427 ;\t006E ;\tMA\t# ( 𝐧 → n ) MATHEMATICAL BOLD SMALL N → LATIN SMALL LETTER N\t# \n1D45B ;\t006E ;\tMA\t# ( 𝑛 → n ) MATHEMATICAL ITALIC SMALL N → LATIN SMALL LETTER N\t# \n1D48F ;\t006E ;\tMA\t# ( 𝒏 → n ) MATHEMATICAL BOLD ITALIC SMALL N → LATIN SMALL LETTER N\t# \n1D4C3 ;\t006E ;\tMA\t# ( 𝓃 → n ) MATHEMATICAL SCRIPT SMALL N → LATIN SMALL LETTER N\t# \n1D4F7 ;\t006E ;\tMA\t# ( 𝓷 → n ) MATHEMATICAL BOLD SCRIPT SMALL N → LATIN SMALL LETTER N\t# \n1D52B ;\t006E ;\tMA\t# ( 𝔫 → n ) MATHEMATICAL FRAKTUR SMALL N → LATIN SMALL LETTER N\t# \n1D55F ;\t006E ;\tMA\t# ( 𝕟 → n ) MATHEMATICAL DOUBLE-STRUCK SMALL N → LATIN SMALL LETTER N\t# \n1D593 ;\t006E ;\tMA\t# ( 𝖓 → n ) MATHEMATICAL BOLD FRAKTUR SMALL N → LATIN SMALL LETTER N\t# \n1D5C7 ;\t006E ;\tMA\t# ( 𝗇 → n ) MATHEMATICAL SANS-SERIF SMALL N → LATIN SMALL LETTER N\t# \n1D5FB ;\t006E ;\tMA\t# ( 𝗻 → n ) MATHEMATICAL SANS-SERIF BOLD SMALL N → LATIN SMALL LETTER N\t# \n1D62F ;\t006E ;\tMA\t# ( 𝘯 → n ) MATHEMATICAL SANS-SERIF ITALIC SMALL N → LATIN SMALL LETTER N\t# \n1D663 ;\t006E ;\tMA\t# ( 𝙣 → n ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N → LATIN SMALL LETTER N\t# \n1D697 ;\t006E ;\tMA\t# ( 𝚗 → n ) MATHEMATICAL MONOSPACE SMALL N → LATIN SMALL LETTER N\t# \n0578 ;\t006E ;\tMA\t# ( ո → n ) ARMENIAN SMALL LETTER VO → LATIN SMALL LETTER N\t# \n057C ;\t006E ;\tMA\t# ( ռ → n ) ARMENIAN SMALL LETTER RA → LATIN SMALL LETTER N\t# \n\nFF2E ;\t004E ;\tMA\t# ( Ｎ → N ) FULLWIDTH LATIN CAPITAL LETTER N → LATIN CAPITAL LETTER N\t# →Ν→\n2115 ;\t004E ;\tMA\t# ( ℕ → N ) DOUBLE-STRUCK CAPITAL N → LATIN CAPITAL LETTER N\t# \n1CCE3 ;\t004E ;\tMA\t#* ( 𜳣 → N ) OUTLINED LATIN CAPITAL LETTER N → LATIN CAPITAL LETTER N\t# \n1D40D ;\t004E ;\tMA\t# ( 𝐍 → N ) MATHEMATICAL BOLD CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D441 ;\t004E ;\tMA\t# ( 𝑁 → N ) MATHEMATICAL ITALIC CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D475 ;\t004E ;\tMA\t# ( 𝑵 → N ) MATHEMATICAL BOLD ITALIC CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D4A9 ;\t004E ;\tMA\t# ( 𝒩 → N ) MATHEMATICAL SCRIPT CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D4DD ;\t004E ;\tMA\t# ( 𝓝 → N ) MATHEMATICAL BOLD SCRIPT CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D511 ;\t004E ;\tMA\t# ( 𝔑 → N ) MATHEMATICAL FRAKTUR CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D579 ;\t004E ;\tMA\t# ( 𝕹 → N ) MATHEMATICAL BOLD FRAKTUR CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D5AD ;\t004E ;\tMA\t# ( 𝖭 → N ) MATHEMATICAL SANS-SERIF CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D5E1 ;\t004E ;\tMA\t# ( 𝗡 → N ) MATHEMATICAL SANS-SERIF BOLD CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D615 ;\t004E ;\tMA\t# ( 𝘕 → N ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D649 ;\t004E ;\tMA\t# ( 𝙉 → N ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N → LATIN CAPITAL LETTER N\t# \n1D67D ;\t004E ;\tMA\t# ( 𝙽 → N ) MATHEMATICAL MONOSPACE CAPITAL N → LATIN CAPITAL LETTER N\t# \n039D ;\t004E ;\tMA\t# ( Ν → N ) GREEK CAPITAL LETTER NU → LATIN CAPITAL LETTER N\t# \n1D6B4 ;\t004E ;\tMA\t# ( 𝚴 → N ) MATHEMATICAL BOLD CAPITAL NU → LATIN CAPITAL LETTER N\t# →𝐍→\n1D6EE ;\t004E ;\tMA\t# ( 𝛮 → N ) MATHEMATICAL ITALIC CAPITAL NU → LATIN CAPITAL LETTER N\t# →𝑁→\n1D728 ;\t004E ;\tMA\t# ( 𝜨 → N ) MATHEMATICAL BOLD ITALIC CAPITAL NU → LATIN CAPITAL LETTER N\t# →𝑵→\n1D762 ;\t004E ;\tMA\t# ( 𝝢 → N ) MATHEMATICAL SANS-SERIF BOLD CAPITAL NU → LATIN CAPITAL LETTER N\t# →Ν→\n1D79C ;\t004E ;\tMA\t# ( 𝞜 → N ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU → LATIN CAPITAL LETTER N\t# →Ν→\n2C9A ;\t004E ;\tMA\t# ( Ⲛ → N ) COPTIC CAPITAL LETTER NI → LATIN CAPITAL LETTER N\t# \nA4E0 ;\t004E ;\tMA\t# ( ꓠ → N ) LISU LETTER NA → LATIN CAPITAL LETTER N\t# \n10513 ;\t004E ;\tMA\t# ( 𐔓 → N ) ELBASAN LETTER NE → LATIN CAPITAL LETTER N\t# \n\n1018E ;\t004E 030A ;\tMA\t#* ( 𐆎 → N̊ ) NOMISMA SIGN → LATIN CAPITAL LETTER N, COMBINING RING ABOVE\t# →Νͦ→\n\n0273 ;\t006E 0328 ;\tMA\t# ( ɳ → n̨ ) LATIN SMALL LETTER N WITH RETROFLEX HOOK → LATIN SMALL LETTER N, COMBINING OGONEK\t# →n̢→\n\n019E ;\t006E 0329 ;\tMA\t# ( ƞ → n̩ ) LATIN SMALL LETTER N WITH LONG RIGHT LEG → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# \n014B ;\t006E 0329 ;\tMA\t# ( ŋ → n̩ ) LATIN SMALL LETTER ENG → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →η→→ƞ→\n03B7 ;\t006E 0329 ;\tMA\t# ( η → n̩ ) GREEK SMALL LETTER ETA → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →ƞ→\n1D6C8 ;\t006E 0329 ;\tMA\t# ( 𝛈 → n̩ ) MATHEMATICAL BOLD SMALL ETA → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →η→→ƞ→\n1D702 ;\t006E 0329 ;\tMA\t# ( 𝜂 → n̩ ) MATHEMATICAL ITALIC SMALL ETA → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →η→→ƞ→\n1D73C ;\t006E 0329 ;\tMA\t# ( 𝜼 → n̩ ) MATHEMATICAL BOLD ITALIC SMALL ETA → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →η→→ƞ→\n1D776 ;\t006E 0329 ;\tMA\t# ( 𝝶 → n̩ ) MATHEMATICAL SANS-SERIF BOLD SMALL ETA → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →η→→ƞ→\n1D7B0 ;\t006E 0329 ;\tMA\t# ( 𝞰 → n̩ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →η→→ƞ→\n0572 ;\t006E 0329 ;\tMA\t# ( ղ → n̩ ) ARMENIAN SMALL LETTER GHAD → LATIN SMALL LETTER N, COMBINING VERTICAL LINE BELOW\t# →η→→ƞ→\n\n019D ;\t004E 0326 ;\tMA\t# ( Ɲ → N̦ ) LATIN CAPITAL LETTER N WITH LEFT HOOK → LATIN CAPITAL LETTER N, COMBINING COMMA BELOW\t# →N̡→\n\n1D70 ;\t006E 0334 ;\tMA\t# ( ᵰ → n̴ ) LATIN SMALL LETTER N WITH MIDDLE TILDE → LATIN SMALL LETTER N, COMBINING TILDE OVERLAY\t# \n\n01CC ;\t006E 006A ;\tMA\t# ( ǌ → nj ) LATIN SMALL LETTER NJ → LATIN SMALL LETTER N, LATIN SMALL LETTER J\t# \n\n01CB ;\t004E 006A ;\tMA\t# ( ǋ → Nj ) LATIN CAPITAL LETTER N WITH SMALL LETTER J → LATIN CAPITAL LETTER N, LATIN SMALL LETTER J\t# \n\n01CA ;\t004E 004A ;\tMA\t# ( Ǌ → NJ ) LATIN CAPITAL LETTER NJ → LATIN CAPITAL LETTER N, LATIN CAPITAL LETTER J\t# \n\n2116 ;\t004E 006F ;\tMA\t#* ( № → No ) NUMERO SIGN → LATIN CAPITAL LETTER N, LATIN SMALL LETTER O\t# \n\n2C9B ;\t0274 ;\tMA\t# ( ⲛ → ɴ ) COPTIC SMALL LETTER NI → LATIN LETTER SMALL CAPITAL N\t# \n\n0377 ;\t1D0E ;\tMA\t# ( ͷ → ᴎ ) GREEK SMALL LETTER PAMPHYLIAN DIGAMMA → LATIN LETTER SMALL CAPITAL REVERSED N\t# →и→\n0438 ;\t1D0E ;\tMA\t# ( и → ᴎ ) CYRILLIC SMALL LETTER I → LATIN LETTER SMALL CAPITAL REVERSED N\t# \n1044D ;\t1D0E ;\tMA\t# ( 𐑍 → ᴎ ) DESERET SMALL LETTER ENG → LATIN LETTER SMALL CAPITAL REVERSED N\t# →и→\n\n0146 ;\t0272 ;\tMA\t# ( ņ → ɲ ) LATIN SMALL LETTER N WITH CEDILLA → LATIN SMALL LETTER N WITH LEFT HOOK\t# \n\n0C02 ;\t006F ;\tMA\t# ( ం → o ) TELUGU SIGN ANUSVARA → LATIN SMALL LETTER O\t# \n0C82 ;\t006F ;\tMA\t# ( ಂ → o ) KANNADA SIGN ANUSVARA → LATIN SMALL LETTER O\t# \n0D02 ;\t006F ;\tMA\t# ( ം → o ) MALAYALAM SIGN ANUSVARA → LATIN SMALL LETTER O\t# \n0D82 ;\t006F ;\tMA\t# ( ං → o ) SINHALA SIGN ANUSVARAYA → LATIN SMALL LETTER O\t# \n0966 ;\t006F ;\tMA\t# ( ० → o ) DEVANAGARI DIGIT ZERO → LATIN SMALL LETTER O\t# \n09E6 ;\t006F ;\tMA\t# ( ০ → o ) BENGALI DIGIT ZERO → LATIN SMALL LETTER O\t# \n0A66 ;\t006F ;\tMA\t# ( ੦ → o ) GURMUKHI DIGIT ZERO → LATIN SMALL LETTER O\t# \n0AE6 ;\t006F ;\tMA\t# ( ૦ → o ) GUJARATI DIGIT ZERO → LATIN SMALL LETTER O\t# \n0B66 ;\t006F ;\tMA\t# ( ୦ → o ) ORIYA DIGIT ZERO → LATIN SMALL LETTER O\t# \n0BE6 ;\t006F ;\tMA\t# ( ௦ → o ) TAMIL DIGIT ZERO → LATIN SMALL LETTER O\t# \n0C66 ;\t006F ;\tMA\t# ( ౦ → o ) TELUGU DIGIT ZERO → LATIN SMALL LETTER O\t# \n0D66 ;\t006F ;\tMA\t# ( ൦ → o ) MALAYALAM DIGIT ZERO → LATIN SMALL LETTER O\t# \n0E50 ;\t006F ;\tMA\t# ( ๐ → o ) THAI DIGIT ZERO → LATIN SMALL LETTER O\t# \n0ED0 ;\t006F ;\tMA\t# ( ໐ → o ) LAO DIGIT ZERO → LATIN SMALL LETTER O\t# \n1040 ;\t006F ;\tMA\t# ( ၀ → o ) MYANMAR DIGIT ZERO → LATIN SMALL LETTER O\t# \n17E0 ;\t006F ;\tMA\t# ( ០ → o ) KHMER DIGIT ZERO → LATIN SMALL LETTER O\t# \n114D0 ;\t006F ;\tMA\t# ( 𑓐 → o ) TIRHUTA DIGIT ZERO → LATIN SMALL LETTER O\t# →০→\n0665 ;\t006F ;\tMA\t# ( ‎٥‎ → o ) ARABIC-INDIC DIGIT FIVE → LATIN SMALL LETTER O\t# \n06F5 ;\t006F ;\tMA\t# ( ۵ → o ) EXTENDED ARABIC-INDIC DIGIT FIVE → LATIN SMALL LETTER O\t# →‎٥‎→\nFF4F ;\t006F ;\tMA\t# ( ｏ → o ) FULLWIDTH LATIN SMALL LETTER O → LATIN SMALL LETTER O\t# →о→\n2134 ;\t006F ;\tMA\t# ( ℴ → o ) SCRIPT SMALL O → LATIN SMALL LETTER O\t# \n1D428 ;\t006F ;\tMA\t# ( 𝐨 → o ) MATHEMATICAL BOLD SMALL O → LATIN SMALL LETTER O\t# \n1D45C ;\t006F ;\tMA\t# ( 𝑜 → o ) MATHEMATICAL ITALIC SMALL O → LATIN SMALL LETTER O\t# \n1D490 ;\t006F ;\tMA\t# ( 𝒐 → o ) MATHEMATICAL BOLD ITALIC SMALL O → LATIN SMALL LETTER O\t# \n1D4F8 ;\t006F ;\tMA\t# ( 𝓸 → o ) MATHEMATICAL BOLD SCRIPT SMALL O → LATIN SMALL LETTER O\t# \n1D52C ;\t006F ;\tMA\t# ( 𝔬 → o ) MATHEMATICAL FRAKTUR SMALL O → LATIN SMALL LETTER O\t# \n1D560 ;\t006F ;\tMA\t# ( 𝕠 → o ) MATHEMATICAL DOUBLE-STRUCK SMALL O → LATIN SMALL LETTER O\t# \n1D594 ;\t006F ;\tMA\t# ( 𝖔 → o ) MATHEMATICAL BOLD FRAKTUR SMALL O → LATIN SMALL LETTER O\t# \n1D5C8 ;\t006F ;\tMA\t# ( 𝗈 → o ) MATHEMATICAL SANS-SERIF SMALL O → LATIN SMALL LETTER O\t# \n1D5FC ;\t006F ;\tMA\t# ( 𝗼 → o ) MATHEMATICAL SANS-SERIF BOLD SMALL O → LATIN SMALL LETTER O\t# \n1D630 ;\t006F ;\tMA\t# ( 𝘰 → o ) MATHEMATICAL SANS-SERIF ITALIC SMALL O → LATIN SMALL LETTER O\t# \n1D664 ;\t006F ;\tMA\t# ( 𝙤 → o ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O → LATIN SMALL LETTER O\t# \n1D698 ;\t006F ;\tMA\t# ( 𝚘 → o ) MATHEMATICAL MONOSPACE SMALL O → LATIN SMALL LETTER O\t# \n1D0F ;\t006F ;\tMA\t# ( ᴏ → o ) LATIN LETTER SMALL CAPITAL O → LATIN SMALL LETTER O\t# \n1D11 ;\t006F ;\tMA\t# ( ᴑ → o ) LATIN SMALL LETTER SIDEWAYS O → LATIN SMALL LETTER O\t# \nAB3D ;\t006F ;\tMA\t# ( ꬽ → o ) LATIN SMALL LETTER BLACKLETTER O → LATIN SMALL LETTER O\t# \n03BF ;\t006F ;\tMA\t# ( ο → o ) GREEK SMALL LETTER OMICRON → LATIN SMALL LETTER O\t# \n1D6D0 ;\t006F ;\tMA\t# ( 𝛐 → o ) MATHEMATICAL BOLD SMALL OMICRON → LATIN SMALL LETTER O\t# →𝐨→\n1D70A ;\t006F ;\tMA\t# ( 𝜊 → o ) MATHEMATICAL ITALIC SMALL OMICRON → LATIN SMALL LETTER O\t# →𝑜→\n1D744 ;\t006F ;\tMA\t# ( 𝝄 → o ) MATHEMATICAL BOLD ITALIC SMALL OMICRON → LATIN SMALL LETTER O\t# →𝒐→\n1D77E ;\t006F ;\tMA\t# ( 𝝾 → o ) MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON → LATIN SMALL LETTER O\t# →ο→\n1D7B8 ;\t006F ;\tMA\t# ( 𝞸 → o ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON → LATIN SMALL LETTER O\t# →ο→\n03C3 ;\t006F ;\tMA\t# ( σ → o ) GREEK SMALL LETTER SIGMA → LATIN SMALL LETTER O\t# \n1D6D4 ;\t006F ;\tMA\t# ( 𝛔 → o ) MATHEMATICAL BOLD SMALL SIGMA → LATIN SMALL LETTER O\t# →σ→\n1D70E ;\t006F ;\tMA\t# ( 𝜎 → o ) MATHEMATICAL ITALIC SMALL SIGMA → LATIN SMALL LETTER O\t# →σ→\n1D748 ;\t006F ;\tMA\t# ( 𝝈 → o ) MATHEMATICAL BOLD ITALIC SMALL SIGMA → LATIN SMALL LETTER O\t# →σ→\n1D782 ;\t006F ;\tMA\t# ( 𝞂 → o ) MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA → LATIN SMALL LETTER O\t# →σ→\n1D7BC ;\t006F ;\tMA\t# ( 𝞼 → o ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA → LATIN SMALL LETTER O\t# →σ→\n2C9F ;\t006F ;\tMA\t# ( ⲟ → o ) COPTIC SMALL LETTER O → LATIN SMALL LETTER O\t# \n03ED ;\t006F ;\tMA\t# ( ϭ → o ) COPTIC SMALL LETTER SHIMA → LATIN SMALL LETTER O\t# →σ→\n043E ;\t006F ;\tMA\t# ( о → o ) CYRILLIC SMALL LETTER O → LATIN SMALL LETTER O\t# \n10FF ;\t006F ;\tMA\t# ( ჿ → o ) GEORGIAN LETTER LABIAL SIGN → LATIN SMALL LETTER O\t# \n0585 ;\t006F ;\tMA\t# ( օ → o ) ARMENIAN SMALL LETTER OH → LATIN SMALL LETTER O\t# \n05E1 ;\t006F ;\tMA\t# ( ‎ס‎ → o ) HEBREW LETTER SAMEKH → LATIN SMALL LETTER O\t# \n0647 ;\t006F ;\tMA\t# ( ‎ه‎ → o ) ARABIC LETTER HEH → LATIN SMALL LETTER O\t# \n1EE24 ;\t006F ;\tMA\t# ( ‎𞸤‎ → o ) ARABIC MATHEMATICAL INITIAL HEH → LATIN SMALL LETTER O\t# →‎ه‎→\n1EE64 ;\t006F ;\tMA\t# ( ‎𞹤‎ → o ) ARABIC MATHEMATICAL STRETCHED HEH → LATIN SMALL LETTER O\t# →‎ه‎→\n1EE84 ;\t006F ;\tMA\t# ( ‎𞺄‎ → o ) ARABIC MATHEMATICAL LOOPED HEH → LATIN SMALL LETTER O\t# →‎ه‎→\nFEEB ;\t006F ;\tMA\t# ( ‎ﻫ‎ → o ) ARABIC LETTER HEH INITIAL FORM → LATIN SMALL LETTER O\t# →‎ه‎→\nFEEC ;\t006F ;\tMA\t# ( ‎ﻬ‎ → o ) ARABIC LETTER HEH MEDIAL FORM → LATIN SMALL LETTER O\t# →‎ه‎→\nFEEA ;\t006F ;\tMA\t# ( ‎ﻪ‎ → o ) ARABIC LETTER HEH FINAL FORM → LATIN SMALL LETTER O\t# →‎ه‎→\nFEE9 ;\t006F ;\tMA\t# ( ‎ﻩ‎ → o ) ARABIC LETTER HEH ISOLATED FORM → LATIN SMALL LETTER O\t# →‎ه‎→\n06BE ;\t006F ;\tMA\t# ( ‎ھ‎ → o ) ARABIC LETTER HEH DOACHASHMEE → LATIN SMALL LETTER O\t# →‎ه‎→\nFBAC ;\t006F ;\tMA\t# ( ‎ﮬ‎ → o ) ARABIC LETTER HEH DOACHASHMEE INITIAL FORM → LATIN SMALL LETTER O\t# →‎ﻫ‎→→‎ه‎→\nFBAD ;\t006F ;\tMA\t# ( ‎ﮭ‎ → o ) ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM → LATIN SMALL LETTER O\t# →‎ﻬ‎→→‎ه‎→\nFBAB ;\t006F ;\tMA\t# ( ‎ﮫ‎ → o ) ARABIC LETTER HEH DOACHASHMEE FINAL FORM → LATIN SMALL LETTER O\t# →‎ﻪ‎→→‎ه‎→\nFBAA ;\t006F ;\tMA\t# ( ‎ﮪ‎ → o ) ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM → LATIN SMALL LETTER O\t# →‎ه‎→\n06C1 ;\t006F ;\tMA\t# ( ‎ہ‎ → o ) ARABIC LETTER HEH GOAL → LATIN SMALL LETTER O\t# →‎ه‎→\nFBA8 ;\t006F ;\tMA\t# ( ‎ﮨ‎ → o ) ARABIC LETTER HEH GOAL INITIAL FORM → LATIN SMALL LETTER O\t# →‎ہ‎→→‎ه‎→\nFBA9 ;\t006F ;\tMA\t# ( ‎ﮩ‎ → o ) ARABIC LETTER HEH GOAL MEDIAL FORM → LATIN SMALL LETTER O\t# →‎ہ‎→→‎ه‎→\nFBA7 ;\t006F ;\tMA\t# ( ‎ﮧ‎ → o ) ARABIC LETTER HEH GOAL FINAL FORM → LATIN SMALL LETTER O\t# →‎ہ‎→→‎ه‎→\nFBA6 ;\t006F ;\tMA\t# ( ‎ﮦ‎ → o ) ARABIC LETTER HEH GOAL ISOLATED FORM → LATIN SMALL LETTER O\t# →‎ه‎→\n06D5 ;\t006F ;\tMA\t# ( ‎ە‎ → o ) ARABIC LETTER AE → LATIN SMALL LETTER O\t# →‎ه‎→\n0D20 ;\t006F ;\tMA\t# ( ഠ → o ) MALAYALAM LETTER TTHA → LATIN SMALL LETTER O\t# \n101D ;\t006F ;\tMA\t# ( ဝ → o ) MYANMAR LETTER WA → LATIN SMALL LETTER O\t# \n104EA ;\t006F ;\tMA\t# ( 𐓪 → o ) OSAGE SMALL LETTER O → LATIN SMALL LETTER O\t# \n118C8 ;\t006F ;\tMA\t# ( 𑣈 → o ) WARANG CITI SMALL LETTER E → LATIN SMALL LETTER O\t# \n118D7 ;\t006F ;\tMA\t# ( 𑣗 → o ) WARANG CITI SMALL LETTER BU → LATIN SMALL LETTER O\t# \n1042C ;\t006F ;\tMA\t# ( 𐐬 → o ) DESERET SMALL LETTER LONG O → LATIN SMALL LETTER O\t# \n\n0030 ;\t004F ;\tMA\t# ( 0 → O ) DIGIT ZERO → LATIN CAPITAL LETTER O\t# \n07C0 ;\t004F ;\tMA\t# ( ‎߀‎ → O ) NKO DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n0CE6 ;\t004F ;\tMA\t# ( ೦ → O ) KANNADA DIGIT ZERO → LATIN CAPITAL LETTER O\t# \n3007 ;\t004F ;\tMA\t# ( 〇 → O ) IDEOGRAPHIC NUMBER ZERO → LATIN CAPITAL LETTER O\t# \n118E0 ;\t004F ;\tMA\t# ( 𑣠 → O ) WARANG CITI DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n1CCF0 ;\t004F ;\tMA\t# ( 𜳰 → O ) OUTLINED DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n1D7CE ;\t004F ;\tMA\t# ( 𝟎 → O ) MATHEMATICAL BOLD DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n1D7D8 ;\t004F ;\tMA\t# ( 𝟘 → O ) MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n1D7E2 ;\t004F ;\tMA\t# ( 𝟢 → O ) MATHEMATICAL SANS-SERIF DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n1D7EC ;\t004F ;\tMA\t# ( 𝟬 → O ) MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n1D7F6 ;\t004F ;\tMA\t# ( 𝟶 → O ) MATHEMATICAL MONOSPACE DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n1FBF0 ;\t004F ;\tMA\t# ( 🯰 → O ) SEGMENTED DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\nFF2F ;\t004F ;\tMA\t# ( Ｏ → O ) FULLWIDTH LATIN CAPITAL LETTER O → LATIN CAPITAL LETTER O\t# →О→\n1CCE4 ;\t004F ;\tMA\t#* ( 𜳤 → O ) OUTLINED LATIN CAPITAL LETTER O → LATIN CAPITAL LETTER O\t# \n1D40E ;\t004F ;\tMA\t# ( 𝐎 → O ) MATHEMATICAL BOLD CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D442 ;\t004F ;\tMA\t# ( 𝑂 → O ) MATHEMATICAL ITALIC CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D476 ;\t004F ;\tMA\t# ( 𝑶 → O ) MATHEMATICAL BOLD ITALIC CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D4AA ;\t004F ;\tMA\t# ( 𝒪 → O ) MATHEMATICAL SCRIPT CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D4DE ;\t004F ;\tMA\t# ( 𝓞 → O ) MATHEMATICAL BOLD SCRIPT CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D512 ;\t004F ;\tMA\t# ( 𝔒 → O ) MATHEMATICAL FRAKTUR CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D546 ;\t004F ;\tMA\t# ( 𝕆 → O ) MATHEMATICAL DOUBLE-STRUCK CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D57A ;\t004F ;\tMA\t# ( 𝕺 → O ) MATHEMATICAL BOLD FRAKTUR CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D5AE ;\t004F ;\tMA\t# ( 𝖮 → O ) MATHEMATICAL SANS-SERIF CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D5E2 ;\t004F ;\tMA\t# ( 𝗢 → O ) MATHEMATICAL SANS-SERIF BOLD CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D616 ;\t004F ;\tMA\t# ( 𝘖 → O ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D64A ;\t004F ;\tMA\t# ( 𝙊 → O ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O → LATIN CAPITAL LETTER O\t# \n1D67E ;\t004F ;\tMA\t# ( 𝙾 → O ) MATHEMATICAL MONOSPACE CAPITAL O → LATIN CAPITAL LETTER O\t# \n039F ;\t004F ;\tMA\t# ( Ο → O ) GREEK CAPITAL LETTER OMICRON → LATIN CAPITAL LETTER O\t# \n1D6B6 ;\t004F ;\tMA\t# ( 𝚶 → O ) MATHEMATICAL BOLD CAPITAL OMICRON → LATIN CAPITAL LETTER O\t# →𝐎→\n1D6F0 ;\t004F ;\tMA\t# ( 𝛰 → O ) MATHEMATICAL ITALIC CAPITAL OMICRON → LATIN CAPITAL LETTER O\t# →𝑂→\n1D72A ;\t004F ;\tMA\t# ( 𝜪 → O ) MATHEMATICAL BOLD ITALIC CAPITAL OMICRON → LATIN CAPITAL LETTER O\t# →𝑶→\n1D764 ;\t004F ;\tMA\t# ( 𝝤 → O ) MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON → LATIN CAPITAL LETTER O\t# →Ο→\n1D79E ;\t004F ;\tMA\t# ( 𝞞 → O ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON → LATIN CAPITAL LETTER O\t# →Ο→\n2C9E ;\t004F ;\tMA\t# ( Ⲟ → O ) COPTIC CAPITAL LETTER O → LATIN CAPITAL LETTER O\t# \n041E ;\t004F ;\tMA\t# ( О → O ) CYRILLIC CAPITAL LETTER O → LATIN CAPITAL LETTER O\t# \n0555 ;\t004F ;\tMA\t# ( Օ → O ) ARMENIAN CAPITAL LETTER OH → LATIN CAPITAL LETTER O\t# \n2D54 ;\t004F ;\tMA\t# ( ⵔ → O ) TIFINAGH LETTER YAR → LATIN CAPITAL LETTER O\t# \n12D0 ;\t004F ;\tMA\t# ( ዐ → O ) ETHIOPIC SYLLABLE PHARYNGEAL A → LATIN CAPITAL LETTER O\t# →Օ→\n0B20 ;\t004F ;\tMA\t# ( ଠ → O ) ORIYA LETTER TTHA → LATIN CAPITAL LETTER O\t# \n104C2 ;\t004F ;\tMA\t# ( 𐓂 → O ) OSAGE CAPITAL LETTER O → LATIN CAPITAL LETTER O\t# \nA4F3 ;\t004F ;\tMA\t# ( ꓳ → O ) LISU LETTER O → LATIN CAPITAL LETTER O\t# \n118B5 ;\t004F ;\tMA\t# ( 𑢵 → O ) WARANG CITI CAPITAL LETTER AT → LATIN CAPITAL LETTER O\t# \n10292 ;\t004F ;\tMA\t# ( 𐊒 → O ) LYCIAN LETTER U → LATIN CAPITAL LETTER O\t# \n102AB ;\t004F ;\tMA\t# ( 𐊫 → O ) CARIAN LETTER O → LATIN CAPITAL LETTER O\t# \n10404 ;\t004F ;\tMA\t# ( 𐐄 → O ) DESERET CAPITAL LETTER LONG O → LATIN CAPITAL LETTER O\t# \n10516 ;\t004F ;\tMA\t# ( 𐔖 → O ) ELBASAN LETTER O → LATIN CAPITAL LETTER O\t# \n11DE0 ;\t004F ;\tMA\t# ( 𑷠 → O ) TOLONG SIKI DIGIT ZERO → LATIN CAPITAL LETTER O\t# →0→\n\n2070 ;\t00BA ;\tMA\t#* ( ⁰ → º ) SUPERSCRIPT ZERO → MASCULINE ORDINAL INDICATOR\t# \n1D52 ;\t00BA ;\tMA\t# ( ᵒ → º ) MODIFIER LETTER SMALL O → MASCULINE ORDINAL INDICATOR\t# →⁰→\n\n01D2 ;\t014F ;\tMA\t# ( ǒ → ŏ ) LATIN SMALL LETTER O WITH CARON → LATIN SMALL LETTER O WITH BREVE\t# \n\n01D1 ;\t014E ;\tMA\t# ( Ǒ → Ŏ ) LATIN CAPITAL LETTER O WITH CARON → LATIN CAPITAL LETTER O WITH BREVE\t# \n\n06FF ;\t006F 0302 ;\tMA\t# ( ‎ۿ‎ → ô ) ARABIC LETTER HEH WITH INVERTED V → LATIN SMALL LETTER O, COMBINING CIRCUMFLEX ACCENT\t# →‎ھٛ‎→\n\n0150 ;\t00D6 ;\tMA\t# ( Ő → Ö ) LATIN CAPITAL LETTER O WITH DOUBLE ACUTE → LATIN CAPITAL LETTER O WITH DIAERESIS\t# \n\n00F8 ;\t006F 0338 ;\tMA\t# ( ø → o̸ ) LATIN SMALL LETTER O WITH STROKE → LATIN SMALL LETTER O, COMBINING LONG SOLIDUS OVERLAY\t# →o̷→\nAB3E ;\t006F 0338 ;\tMA\t# ( ꬾ → o̸ ) LATIN SMALL LETTER BLACKLETTER O WITH STROKE → LATIN SMALL LETTER O, COMBINING LONG SOLIDUS OVERLAY\t# →ø→→o̷→\n\n00D8 ;\t004F 0338 ;\tMA\t# ( Ø → O̸ ) LATIN CAPITAL LETTER O WITH STROKE → LATIN CAPITAL LETTER O, COMBINING LONG SOLIDUS OVERLAY\t# \n2D41 ;\t004F 0338 ;\tMA\t# ( ⵁ → O̸ ) TIFINAGH LETTER BERBER ACADEMY YAH → LATIN CAPITAL LETTER O, COMBINING LONG SOLIDUS OVERLAY\t# →Ø→\n\n01FE ;\t004F 0338 0301 ;\tMA\t# ( Ǿ → Ó̸ ) LATIN CAPITAL LETTER O WITH STROKE AND ACUTE → LATIN CAPITAL LETTER O, COMBINING LONG SOLIDUS OVERLAY, COMBINING ACUTE ACCENT\t# \n\n0275 ;\t006F 0335 ;\tMA\t# ( ɵ → o̵ ) LATIN SMALL LETTER BARRED O → LATIN SMALL LETTER O, COMBINING SHORT STROKE OVERLAY\t# \nA74B ;\t006F 0335 ;\tMA\t# ( ꝋ → o̵ ) LATIN SMALL LETTER O WITH LONG STROKE OVERLAY → LATIN SMALL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →o̶→\n2C91 ;\t006F 0335 ;\tMA\t# ( ⲑ → o̵ ) COPTIC SMALL LETTER THETHE → LATIN SMALL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →ɵ→\n04E9 ;\t006F 0335 ;\tMA\t# ( ө → o̵ ) CYRILLIC SMALL LETTER BARRED O → LATIN SMALL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →ѳ→\n0473 ;\t006F 0335 ;\tMA\t# ( ѳ → o̵ ) CYRILLIC SMALL LETTER FITA → LATIN SMALL LETTER O, COMBINING SHORT STROKE OVERLAY\t# \nAB8E ;\t006F 0335 ;\tMA\t# ( ꮎ → o̵ ) CHEROKEE SMALL LETTER NA → LATIN SMALL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →ɵ→\nABBB ;\t006F 0335 ;\tMA\t# ( ꮻ → o̵ ) CHEROKEE SMALL LETTER WI → LATIN SMALL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →ѳ→\n\n2296 ;\t004F 0335 ;\tMA\t#* ( ⊖ → O̵ ) CIRCLED MINUS → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n229D ;\t004F 0335 ;\tMA\t#* ( ⊝ → O̵ ) CIRCLED DASH → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →⊖→→θ→→Ꮎ→\n236C ;\t004F 0335 ;\tMA\t#* ( ⍬ → O̵ ) APL FUNCTIONAL SYMBOL ZILDE → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D21A ;\t004F 0335 ;\tMA\t#* ( 𝈚 → O̵ ) GREEK VOCAL NOTATION SYMBOL-52 → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Ꝋ→→O̶→\n1F714 ;\t004F 0335 ;\tMA\t#* ( 🜔 → O̵ ) ALCHEMICAL SYMBOL FOR SALT → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Ɵ→→O̶→\n019F ;\t004F 0335 ;\tMA\t# ( Ɵ → O̵ ) LATIN CAPITAL LETTER O WITH MIDDLE TILDE → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →O̶→\nA74A ;\t004F 0335 ;\tMA\t# ( Ꝋ → O̵ ) LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →O̶→\n03B8 ;\t004F 0335 ;\tMA\t# ( θ → O̵ ) GREEK SMALL LETTER THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Ꮎ→\n03D1 ;\t004F 0335 ;\tMA\t# ( ϑ → O̵ ) GREEK THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D6C9 ;\t004F 0335 ;\tMA\t# ( 𝛉 → O̵ ) MATHEMATICAL BOLD SMALL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D6DD ;\t004F 0335 ;\tMA\t# ( 𝛝 → O̵ ) MATHEMATICAL BOLD THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D703 ;\t004F 0335 ;\tMA\t# ( 𝜃 → O̵ ) MATHEMATICAL ITALIC SMALL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D717 ;\t004F 0335 ;\tMA\t# ( 𝜗 → O̵ ) MATHEMATICAL ITALIC THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D73D ;\t004F 0335 ;\tMA\t# ( 𝜽 → O̵ ) MATHEMATICAL BOLD ITALIC SMALL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D751 ;\t004F 0335 ;\tMA\t# ( 𝝑 → O̵ ) MATHEMATICAL BOLD ITALIC THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D777 ;\t004F 0335 ;\tMA\t# ( 𝝷 → O̵ ) MATHEMATICAL SANS-SERIF BOLD SMALL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D78B ;\t004F 0335 ;\tMA\t# ( 𝞋 → O̵ ) MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D7B1 ;\t004F 0335 ;\tMA\t# ( 𝞱 → O̵ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n1D7C5 ;\t004F 0335 ;\tMA\t# ( 𝟅 → O̵ ) MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →θ→→Ꮎ→\n0398 ;\t004F 0335 ;\tMA\t# ( Θ → O̵ ) GREEK CAPITAL LETTER THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Ꮎ→\n03F4 ;\t004F 0335 ;\tMA\t# ( ϴ → O̵ ) GREEK CAPITAL THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Ѳ→→О̵→\n1D6AF ;\t004F 0335 ;\tMA\t# ( 𝚯 → O̵ ) MATHEMATICAL BOLD CAPITAL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D6B9 ;\t004F 0335 ;\tMA\t# ( 𝚹 → O̵ ) MATHEMATICAL BOLD CAPITAL THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D6E9 ;\t004F 0335 ;\tMA\t# ( 𝛩 → O̵ ) MATHEMATICAL ITALIC CAPITAL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D6F3 ;\t004F 0335 ;\tMA\t# ( 𝛳 → O̵ ) MATHEMATICAL ITALIC CAPITAL THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D723 ;\t004F 0335 ;\tMA\t# ( 𝜣 → O̵ ) MATHEMATICAL BOLD ITALIC CAPITAL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D72D ;\t004F 0335 ;\tMA\t# ( 𝜭 → O̵ ) MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D75D ;\t004F 0335 ;\tMA\t# ( 𝝝 → O̵ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D767 ;\t004F 0335 ;\tMA\t# ( 𝝧 → O̵ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D797 ;\t004F 0335 ;\tMA\t# ( 𝞗 → O̵ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n1D7A1 ;\t004F 0335 ;\tMA\t# ( 𝞡 → O̵ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Θ→→Ꮎ→\n2C90 ;\t004F 0335 ;\tMA\t# ( Ⲑ → O̵ ) COPTIC CAPITAL LETTER THETHE → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →ϴ→→Ѳ→→О̵→\n04E8 ;\t004F 0335 ;\tMA\t# ( Ө → O̵ ) CYRILLIC CAPITAL LETTER BARRED O → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Ѳ→→О̵→\n0472 ;\t004F 0335 ;\tMA\t# ( Ѳ → O̵ ) CYRILLIC CAPITAL LETTER FITA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →О̵→\n2D31 ;\t004F 0335 ;\tMA\t# ( ⴱ → O̵ ) TIFINAGH LETTER YAB → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Ɵ→→O̶→\n13BE ;\t004F 0335 ;\tMA\t# ( Ꮎ → O̵ ) CHEROKEE LETTER NA → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# \n13EB ;\t004F 0335 ;\tMA\t# ( Ꮻ → O̵ ) CHEROKEE LETTER WI → LATIN CAPITAL LETTER O, COMBINING SHORT STROKE OVERLAY\t# →Ѳ→→О̵→\n\nAB74 ;\t006F 031B ;\tMA\t# ( ꭴ → ơ ) CHEROKEE SMALL LETTER U → LATIN SMALL LETTER O, COMBINING HORN\t# \n\nFCD9 ;\t006F 0670 ;\tMA\t# ( ‎ﳙ‎ → oٰ ) ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM → LATIN SMALL LETTER O, ARABIC LETTER SUPERSCRIPT ALEF\t# →‎هٰ‎→\n\n1F101 ;\t004F 002C ;\tMA\t#* ( 🄁 → O, ) DIGIT ZERO COMMA → LATIN CAPITAL LETTER O, COMMA\t# →0,→\n\n1F100 ;\t004F 002E ;\tMA\t#* ( 🄀 → O. ) DIGIT ZERO FULL STOP → LATIN CAPITAL LETTER O, FULL STOP\t# →0.→\n\n01A1 ;\t006F 0027 ;\tMA\t# ( ơ → o' ) LATIN SMALL LETTER O WITH HORN → LATIN SMALL LETTER O, APOSTROPHE\t# →oʼ→\n\n01A0 ;\t004F 0027 ;\tMA\t# ( Ơ → O' ) LATIN CAPITAL LETTER O WITH HORN → LATIN CAPITAL LETTER O, APOSTROPHE\t# →Oʼ→\n13A4 ;\t004F 0027 ;\tMA\t# ( Ꭴ → O' ) CHEROKEE LETTER U → LATIN CAPITAL LETTER O, APOSTROPHE\t# →Ơ→→Oʼ→\n\n0025 ;\t00BA 002F 2080 ;\tMA\t#* ( % → º/₀ ) PERCENT SIGN → MASCULINE ORDINAL INDICATOR, SOLIDUS, SUBSCRIPT ZERO\t# →⁰/₀→\n066A ;\t00BA 002F 2080 ;\tMA\t#* ( ٪ → º/₀ ) ARABIC PERCENT SIGN → MASCULINE ORDINAL INDICATOR, SOLIDUS, SUBSCRIPT ZERO\t# →%→→⁰/₀→\n2052 ;\t00BA 002F 2080 ;\tMA\t#* ( ⁒ → º/₀ ) COMMERCIAL MINUS SIGN → MASCULINE ORDINAL INDICATOR, SOLIDUS, SUBSCRIPT ZERO\t# →%→→⁰/₀→\n\n2030 ;\t00BA 002F 2080 2080 ;\tMA\t#* ( ‰ → º/₀₀ ) PER MILLE SIGN → MASCULINE ORDINAL INDICATOR, SOLIDUS, SUBSCRIPT ZERO, SUBSCRIPT ZERO\t# →⁰/₀₀→\n0609 ;\t00BA 002F 2080 2080 ;\tMA\t#* ( ؉ → º/₀₀ ) ARABIC-INDIC PER MILLE SIGN → MASCULINE ORDINAL INDICATOR, SOLIDUS, SUBSCRIPT ZERO, SUBSCRIPT ZERO\t# →‰→→⁰/₀₀→\n\n2031 ;\t00BA 002F 2080 2080 2080 ;\tMA\t#* ( ‱ → º/₀₀₀ ) PER TEN THOUSAND SIGN → MASCULINE ORDINAL INDICATOR, SOLIDUS, SUBSCRIPT ZERO, SUBSCRIPT ZERO, SUBSCRIPT ZERO\t# →⁰/₀₀₀→\n060A ;\t00BA 002F 2080 2080 2080 ;\tMA\t#* ( ؊ → º/₀₀₀ ) ARABIC-INDIC PER TEN THOUSAND SIGN → MASCULINE ORDINAL INDICATOR, SOLIDUS, SUBSCRIPT ZERO, SUBSCRIPT ZERO, SUBSCRIPT ZERO\t# →‱→→⁰/₀₀₀→\n\n0153 ;\t006F 0065 ;\tMA\t# ( œ → oe ) LATIN SMALL LIGATURE OE → LATIN SMALL LETTER O, LATIN SMALL LETTER E\t# \n\n0152 ;\t004F 0045 ;\tMA\t# ( Œ → OE ) LATIN CAPITAL LIGATURE OE → LATIN CAPITAL LETTER O, LATIN CAPITAL LETTER E\t# \n\n0276 ;\t006F 1D07 ;\tMA\t# ( ɶ → oᴇ ) LATIN LETTER SMALL CAPITAL OE → LATIN SMALL LETTER O, LATIN LETTER SMALL CAPITAL E\t# \n\n221E ;\t006F 006F ;\tMA\t#* ( ∞ → oo ) INFINITY → LATIN SMALL LETTER O, LATIN SMALL LETTER O\t# →ꝏ→\nA74F ;\t006F 006F ;\tMA\t# ( ꝏ → oo ) LATIN SMALL LETTER OO → LATIN SMALL LETTER O, LATIN SMALL LETTER O\t# \nA699 ;\t006F 006F ;\tMA\t# ( ꚙ → oo ) CYRILLIC SMALL LETTER DOUBLE O → LATIN SMALL LETTER O, LATIN SMALL LETTER O\t# \n\nA74E ;\t004F 004F ;\tMA\t# ( Ꝏ → OO ) LATIN CAPITAL LETTER OO → LATIN CAPITAL LETTER O, LATIN CAPITAL LETTER O\t# \nA698 ;\t004F 004F ;\tMA\t# ( Ꚙ → OO ) CYRILLIC CAPITAL LETTER DOUBLE O → LATIN CAPITAL LETTER O, LATIN CAPITAL LETTER O\t# \n\nFCD7 ;\t006F 062C ;\tMA\t# ( ‎ﳗ‎ → ‎oج‎ ) ARABIC LIGATURE HEH WITH JEEM INITIAL FORM → LATIN SMALL LETTER O, ARABIC LETTER JEEM\t# →‎هج‎→\nFC51 ;\t006F 062C ;\tMA\t# ( ‎ﱑ‎ → ‎oج‎ ) ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM → LATIN SMALL LETTER O, ARABIC LETTER JEEM\t# →‎هج‎→\n\nFCD8 ;\t006F 0645 ;\tMA\t# ( ‎ﳘ‎ → ‎oم‎ ) ARABIC LIGATURE HEH WITH MEEM INITIAL FORM → LATIN SMALL LETTER O, ARABIC LETTER MEEM\t# →‎هم‎→\nFC52 ;\t006F 0645 ;\tMA\t# ( ‎ﱒ‎ → ‎oم‎ ) ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM → LATIN SMALL LETTER O, ARABIC LETTER MEEM\t# →‎هم‎→\n\nFD93 ;\t006F 0645 062C ;\tMA\t# ( ‎ﶓ‎ → ‎oمج‎ ) ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM → LATIN SMALL LETTER O, ARABIC LETTER MEEM, ARABIC LETTER JEEM\t# →‎همج‎→\n\nFD94 ;\t006F 0645 0645 ;\tMA\t# ( ‎ﶔ‎ → ‎oمم‎ ) ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM → LATIN SMALL LETTER O, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# →‎همم‎→\n\nFC53 ;\t006F 0649 ;\tMA\t# ( ‎ﱓ‎ → ‎oى‎ ) ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM → LATIN SMALL LETTER O, ARABIC LETTER ALEF MAKSURA\t# →‎هى‎→\nFC54 ;\t006F 0649 ;\tMA\t# ( ‎ﱔ‎ → ‎oى‎ ) ARABIC LIGATURE HEH WITH YEH ISOLATED FORM → LATIN SMALL LETTER O, ARABIC LETTER ALEF MAKSURA\t# →‎هي‎→\n\n0D5F ;\t006F 0D30 006F ;\tMA\t# ( ൟ → oരo ) MALAYALAM LETTER ARCHAIC II → LATIN SMALL LETTER O, MALAYALAM LETTER RA, LATIN SMALL LETTER O\t# →ംരം→\n\n10D7 ;\t006F 102C ;\tMA\t# ( თ → oာ ) GEORGIAN LETTER TAN → LATIN SMALL LETTER O, MYANMAR VOWEL SIGN AA\t# →တ→→ဝာ→\n1010 ;\t006F 102C ;\tMA\t# ( တ → oာ ) MYANMAR LETTER TA → LATIN SMALL LETTER O, MYANMAR VOWEL SIGN AA\t# →ဝာ→\n\n3358 ;\t004F 70B9 ;\tMA\t#* ( ㍘ → O点 ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO → LATIN CAPITAL LETTER O, CJK UNIFIED IDEOGRAPH-70B9\t# →0点→\n\n2184 ;\t0254 ;\tMA\t# ( ↄ → ɔ ) LATIN SMALL LETTER REVERSED C → LATIN SMALL LETTER OPEN O\t# \n1D10 ;\t0254 ;\tMA\t# ( ᴐ → ɔ ) LATIN LETTER SMALL CAPITAL OPEN O → LATIN SMALL LETTER OPEN O\t# \n037B ;\t0254 ;\tMA\t# ( ͻ → ɔ ) GREEK SMALL REVERSED LUNATE SIGMA SYMBOL → LATIN SMALL LETTER OPEN O\t# \n1044B ;\t0254 ;\tMA\t# ( 𐑋 → ɔ ) DESERET SMALL LETTER EM → LATIN SMALL LETTER OPEN O\t# \n\n2183 ;\t0186 ;\tMA\t# ( Ↄ → Ɔ ) ROMAN NUMERAL REVERSED ONE HUNDRED → LATIN CAPITAL LETTER OPEN O\t# \n03FD ;\t0186 ;\tMA\t# ( Ͻ → Ɔ ) GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL → LATIN CAPITAL LETTER OPEN O\t# \nA4DB ;\t0186 ;\tMA\t# ( ꓛ → Ɔ ) LISU LETTER CHA → LATIN CAPITAL LETTER OPEN O\t# \n10423 ;\t0186 ;\tMA\t# ( 𐐣 → Ɔ ) DESERET CAPITAL LETTER EM → LATIN CAPITAL LETTER OPEN O\t# \n\nAB3F ;\t0254 0338 ;\tMA\t# ( ꬿ → ɔ̸ ) LATIN SMALL LETTER OPEN O WITH STROKE → LATIN SMALL LETTER OPEN O, COMBINING LONG SOLIDUS OVERLAY\t# \n\nAB62 ;\t0254 0065 ;\tMA\t# ( ꭢ → ɔe ) LATIN SMALL LETTER OPEN OE → LATIN SMALL LETTER OPEN O, LATIN SMALL LETTER E\t# \n\n1043F ;\t0277 ;\tMA\t# ( 𐐿 → ɷ ) DESERET SMALL LETTER KAY → LATIN SMALL LETTER CLOSED OMEGA\t# \n\n2374 ;\t0070 ;\tMA\t#* ( ⍴ → p ) APL FUNCTIONAL SYMBOL RHO → LATIN SMALL LETTER P\t# →ρ→\nFF50 ;\t0070 ;\tMA\t# ( ｐ → p ) FULLWIDTH LATIN SMALL LETTER P → LATIN SMALL LETTER P\t# →р→\n1D429 ;\t0070 ;\tMA\t# ( 𝐩 → p ) MATHEMATICAL BOLD SMALL P → LATIN SMALL LETTER P\t# \n1D45D ;\t0070 ;\tMA\t# ( 𝑝 → p ) MATHEMATICAL ITALIC SMALL P → LATIN SMALL LETTER P\t# \n1D491 ;\t0070 ;\tMA\t# ( 𝒑 → p ) MATHEMATICAL BOLD ITALIC SMALL P → LATIN SMALL LETTER P\t# \n1D4C5 ;\t0070 ;\tMA\t# ( 𝓅 → p ) MATHEMATICAL SCRIPT SMALL P → LATIN SMALL LETTER P\t# \n1D4F9 ;\t0070 ;\tMA\t# ( 𝓹 → p ) MATHEMATICAL BOLD SCRIPT SMALL P → LATIN SMALL LETTER P\t# \n1D52D ;\t0070 ;\tMA\t# ( 𝔭 → p ) MATHEMATICAL FRAKTUR SMALL P → LATIN SMALL LETTER P\t# \n1D561 ;\t0070 ;\tMA\t# ( 𝕡 → p ) MATHEMATICAL DOUBLE-STRUCK SMALL P → LATIN SMALL LETTER P\t# \n1D595 ;\t0070 ;\tMA\t# ( 𝖕 → p ) MATHEMATICAL BOLD FRAKTUR SMALL P → LATIN SMALL LETTER P\t# \n1D5C9 ;\t0070 ;\tMA\t# ( 𝗉 → p ) MATHEMATICAL SANS-SERIF SMALL P → LATIN SMALL LETTER P\t# \n1D5FD ;\t0070 ;\tMA\t# ( 𝗽 → p ) MATHEMATICAL SANS-SERIF BOLD SMALL P → LATIN SMALL LETTER P\t# \n1D631 ;\t0070 ;\tMA\t# ( 𝘱 → p ) MATHEMATICAL SANS-SERIF ITALIC SMALL P → LATIN SMALL LETTER P\t# \n1D665 ;\t0070 ;\tMA\t# ( 𝙥 → p ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P → LATIN SMALL LETTER P\t# \n1D699 ;\t0070 ;\tMA\t# ( 𝚙 → p ) MATHEMATICAL MONOSPACE SMALL P → LATIN SMALL LETTER P\t# \n00FE ;\t0070 ;\tMA\t# ( þ → p ) LATIN SMALL LETTER THORN → LATIN SMALL LETTER P\t# →ƿ→\n01BF ;\t0070 ;\tMA\t# ( ƿ → p ) LATIN LETTER WYNN → LATIN SMALL LETTER P\t# \n03C1 ;\t0070 ;\tMA\t# ( ρ → p ) GREEK SMALL LETTER RHO → LATIN SMALL LETTER P\t# \n03F1 ;\t0070 ;\tMA\t# ( ϱ → p ) GREEK RHO SYMBOL → LATIN SMALL LETTER P\t# →ρ→\n1D6D2 ;\t0070 ;\tMA\t# ( 𝛒 → p ) MATHEMATICAL BOLD SMALL RHO → LATIN SMALL LETTER P\t# →ρ→\n1D6E0 ;\t0070 ;\tMA\t# ( 𝛠 → p ) MATHEMATICAL BOLD RHO SYMBOL → LATIN SMALL LETTER P\t# →ρ→\n1D70C ;\t0070 ;\tMA\t# ( 𝜌 → p ) MATHEMATICAL ITALIC SMALL RHO → LATIN SMALL LETTER P\t# →ρ→\n1D71A ;\t0070 ;\tMA\t# ( 𝜚 → p ) MATHEMATICAL ITALIC RHO SYMBOL → LATIN SMALL LETTER P\t# →ρ→\n1D746 ;\t0070 ;\tMA\t# ( 𝝆 → p ) MATHEMATICAL BOLD ITALIC SMALL RHO → LATIN SMALL LETTER P\t# →ρ→\n1D754 ;\t0070 ;\tMA\t# ( 𝝔 → p ) MATHEMATICAL BOLD ITALIC RHO SYMBOL → LATIN SMALL LETTER P\t# →ρ→\n1D780 ;\t0070 ;\tMA\t# ( 𝞀 → p ) MATHEMATICAL SANS-SERIF BOLD SMALL RHO → LATIN SMALL LETTER P\t# →ρ→\n1D78E ;\t0070 ;\tMA\t# ( 𝞎 → p ) MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL → LATIN SMALL LETTER P\t# →ρ→\n1D7BA ;\t0070 ;\tMA\t# ( 𝞺 → p ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO → LATIN SMALL LETTER P\t# →ρ→\n1D7C8 ;\t0070 ;\tMA\t# ( 𝟈 → p ) MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL → LATIN SMALL LETTER P\t# →ρ→\n03F8 ;\t0070 ;\tMA\t# ( ϸ → p ) GREEK SMALL LETTER SHO → LATIN SMALL LETTER P\t# →þ→→ƿ→\n2CA3 ;\t0070 ;\tMA\t# ( ⲣ → p ) COPTIC SMALL LETTER RO → LATIN SMALL LETTER P\t# →ρ→\n2CCF ;\t0070 ;\tMA\t# ( ⳏ → p ) COPTIC SMALL LETTER OLD COPTIC HA → LATIN SMALL LETTER P\t# \n0440 ;\t0070 ;\tMA\t# ( р → p ) CYRILLIC SMALL LETTER ER → LATIN SMALL LETTER P\t# \n\nFF30 ;\t0050 ;\tMA\t# ( Ｐ → P ) FULLWIDTH LATIN CAPITAL LETTER P → LATIN CAPITAL LETTER P\t# →Р→\n2119 ;\t0050 ;\tMA\t# ( ℙ → P ) DOUBLE-STRUCK CAPITAL P → LATIN CAPITAL LETTER P\t# \n1CCE5 ;\t0050 ;\tMA\t#* ( 𜳥 → P ) OUTLINED LATIN CAPITAL LETTER P → LATIN CAPITAL LETTER P\t# \n1D40F ;\t0050 ;\tMA\t# ( 𝐏 → P ) MATHEMATICAL BOLD CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D443 ;\t0050 ;\tMA\t# ( 𝑃 → P ) MATHEMATICAL ITALIC CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D477 ;\t0050 ;\tMA\t# ( 𝑷 → P ) MATHEMATICAL BOLD ITALIC CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D4AB ;\t0050 ;\tMA\t# ( 𝒫 → P ) MATHEMATICAL SCRIPT CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D4DF ;\t0050 ;\tMA\t# ( 𝓟 → P ) MATHEMATICAL BOLD SCRIPT CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D513 ;\t0050 ;\tMA\t# ( 𝔓 → P ) MATHEMATICAL FRAKTUR CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D57B ;\t0050 ;\tMA\t# ( 𝕻 → P ) MATHEMATICAL BOLD FRAKTUR CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D5AF ;\t0050 ;\tMA\t# ( 𝖯 → P ) MATHEMATICAL SANS-SERIF CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D5E3 ;\t0050 ;\tMA\t# ( 𝗣 → P ) MATHEMATICAL SANS-SERIF BOLD CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D617 ;\t0050 ;\tMA\t# ( 𝘗 → P ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D64B ;\t0050 ;\tMA\t# ( 𝙋 → P ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P → LATIN CAPITAL LETTER P\t# \n1D67F ;\t0050 ;\tMA\t# ( 𝙿 → P ) MATHEMATICAL MONOSPACE CAPITAL P → LATIN CAPITAL LETTER P\t# \n03A1 ;\t0050 ;\tMA\t# ( Ρ → P ) GREEK CAPITAL LETTER RHO → LATIN CAPITAL LETTER P\t# \n1D6B8 ;\t0050 ;\tMA\t# ( 𝚸 → P ) MATHEMATICAL BOLD CAPITAL RHO → LATIN CAPITAL LETTER P\t# →𝐏→\n1D6F2 ;\t0050 ;\tMA\t# ( 𝛲 → P ) MATHEMATICAL ITALIC CAPITAL RHO → LATIN CAPITAL LETTER P\t# →Ρ→\n1D72C ;\t0050 ;\tMA\t# ( 𝜬 → P ) MATHEMATICAL BOLD ITALIC CAPITAL RHO → LATIN CAPITAL LETTER P\t# →Ρ→\n1D766 ;\t0050 ;\tMA\t# ( 𝝦 → P ) MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO → LATIN CAPITAL LETTER P\t# →Ρ→\n1D7A0 ;\t0050 ;\tMA\t# ( 𝞠 → P ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO → LATIN CAPITAL LETTER P\t# →Ρ→\n2CA2 ;\t0050 ;\tMA\t# ( Ⲣ → P ) COPTIC CAPITAL LETTER RO → LATIN CAPITAL LETTER P\t# \n2CCE ;\t0050 ;\tMA\t# ( Ⳏ → P ) COPTIC CAPITAL LETTER OLD COPTIC HA → LATIN CAPITAL LETTER P\t# \n0420 ;\t0050 ;\tMA\t# ( Р → P ) CYRILLIC CAPITAL LETTER ER → LATIN CAPITAL LETTER P\t# \n13E2 ;\t0050 ;\tMA\t# ( Ꮲ → P ) CHEROKEE LETTER TLV → LATIN CAPITAL LETTER P\t# \n146D ;\t0050 ;\tMA\t# ( ᑭ → P ) CANADIAN SYLLABICS KI → LATIN CAPITAL LETTER P\t# \nA4D1 ;\t0050 ;\tMA\t# ( ꓑ → P ) LISU LETTER PA → LATIN CAPITAL LETTER P\t# \n10295 ;\t0050 ;\tMA\t# ( 𐊕 → P ) LYCIAN LETTER R → LATIN CAPITAL LETTER P\t# \n\n01A5 ;\t0070 0314 ;\tMA\t# ( ƥ → p̔ ) LATIN SMALL LETTER P WITH HOOK → LATIN SMALL LETTER P, COMBINING REVERSED COMMA ABOVE\t# \n\n1D7D ;\t0070 0335 ;\tMA\t# ( ᵽ → p̵ ) LATIN SMALL LETTER P WITH STROKE → LATIN SMALL LETTER P, COMBINING SHORT STROKE OVERLAY\t# \n\n1477 ;\t0070 00B7 ;\tMA\t# ( ᑷ → p· ) CANADIAN SYLLABICS WEST-CREE KWI → LATIN SMALL LETTER P, MIDDLE DOT\t# →pᐧ→\n\n1486 ;\t0050 0027 ;\tMA\t# ( ᒆ → P' ) CANADIAN SYLLABICS SOUTH-SLAVEY KIH → LATIN CAPITAL LETTER P, APOSTROPHE\t# →ᑭᑊ→\n\n1D29 ;\t1D18 ;\tMA\t# ( ᴩ → ᴘ ) GREEK LETTER SMALL CAPITAL RHO → LATIN LETTER SMALL CAPITAL P\t# \nABB2 ;\t1D18 ;\tMA\t# ( ꮲ → ᴘ ) CHEROKEE SMALL LETTER TLV → LATIN LETTER SMALL CAPITAL P\t# \n\n03C6 ;\t0278 ;\tMA\t# ( φ → ɸ ) GREEK SMALL LETTER PHI → LATIN SMALL LETTER PHI\t# \n03D5 ;\t0278 ;\tMA\t# ( ϕ → ɸ ) GREEK PHI SYMBOL → LATIN SMALL LETTER PHI\t# \n1D6D7 ;\t0278 ;\tMA\t# ( 𝛗 → ɸ ) MATHEMATICAL BOLD SMALL PHI → LATIN SMALL LETTER PHI\t# →φ→\n1D6DF ;\t0278 ;\tMA\t# ( 𝛟 → ɸ ) MATHEMATICAL BOLD PHI SYMBOL → LATIN SMALL LETTER PHI\t# →φ→\n1D711 ;\t0278 ;\tMA\t# ( 𝜑 → ɸ ) MATHEMATICAL ITALIC SMALL PHI → LATIN SMALL LETTER PHI\t# →φ→\n1D719 ;\t0278 ;\tMA\t# ( 𝜙 → ɸ ) MATHEMATICAL ITALIC PHI SYMBOL → LATIN SMALL LETTER PHI\t# →φ→\n1D74B ;\t0278 ;\tMA\t# ( 𝝋 → ɸ ) MATHEMATICAL BOLD ITALIC SMALL PHI → LATIN SMALL LETTER PHI\t# →φ→\n1D753 ;\t0278 ;\tMA\t# ( 𝝓 → ɸ ) MATHEMATICAL BOLD ITALIC PHI SYMBOL → LATIN SMALL LETTER PHI\t# →φ→\n1D785 ;\t0278 ;\tMA\t# ( 𝞅 → ɸ ) MATHEMATICAL SANS-SERIF BOLD SMALL PHI → LATIN SMALL LETTER PHI\t# →φ→\n1D78D ;\t0278 ;\tMA\t# ( 𝞍 → ɸ ) MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL → LATIN SMALL LETTER PHI\t# →φ→\n1D7BF ;\t0278 ;\tMA\t# ( 𝞿 → ɸ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI → LATIN SMALL LETTER PHI\t# →φ→\n1D7C7 ;\t0278 ;\tMA\t# ( 𝟇 → ɸ ) MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL → LATIN SMALL LETTER PHI\t# →φ→\n2CAB ;\t0278 ;\tMA\t# ( ⲫ → ɸ ) COPTIC SMALL LETTER FI → LATIN SMALL LETTER PHI\t# →ϕ→\n2CE1 ;\t0278 ;\tMA\t# ( ⳡ → ɸ ) COPTIC SMALL LETTER OLD NUBIAN NYI → LATIN SMALL LETTER PHI\t# →φ→\n2CE0 ;\t0278 ;\tMA\t# ( Ⳡ → ɸ ) COPTIC CAPITAL LETTER OLD NUBIAN NYI → LATIN SMALL LETTER PHI\t# →φ→\n0444 ;\t0278 ;\tMA\t# ( ф → ɸ ) CYRILLIC SMALL LETTER EF → LATIN SMALL LETTER PHI\t# \n\n1D42A ;\t0071 ;\tMA\t# ( 𝐪 → q ) MATHEMATICAL BOLD SMALL Q → LATIN SMALL LETTER Q\t# \n1D45E ;\t0071 ;\tMA\t# ( 𝑞 → q ) MATHEMATICAL ITALIC SMALL Q → LATIN SMALL LETTER Q\t# \n1D492 ;\t0071 ;\tMA\t# ( 𝒒 → q ) MATHEMATICAL BOLD ITALIC SMALL Q → LATIN SMALL LETTER Q\t# \n1D4C6 ;\t0071 ;\tMA\t# ( 𝓆 → q ) MATHEMATICAL SCRIPT SMALL Q → LATIN SMALL LETTER Q\t# \n1D4FA ;\t0071 ;\tMA\t# ( 𝓺 → q ) MATHEMATICAL BOLD SCRIPT SMALL Q → LATIN SMALL LETTER Q\t# \n1D52E ;\t0071 ;\tMA\t# ( 𝔮 → q ) MATHEMATICAL FRAKTUR SMALL Q → LATIN SMALL LETTER Q\t# \n1D562 ;\t0071 ;\tMA\t# ( 𝕢 → q ) MATHEMATICAL DOUBLE-STRUCK SMALL Q → LATIN SMALL LETTER Q\t# \n1D596 ;\t0071 ;\tMA\t# ( 𝖖 → q ) MATHEMATICAL BOLD FRAKTUR SMALL Q → LATIN SMALL LETTER Q\t# \n1D5CA ;\t0071 ;\tMA\t# ( 𝗊 → q ) MATHEMATICAL SANS-SERIF SMALL Q → LATIN SMALL LETTER Q\t# \n1D5FE ;\t0071 ;\tMA\t# ( 𝗾 → q ) MATHEMATICAL SANS-SERIF BOLD SMALL Q → LATIN SMALL LETTER Q\t# \n1D632 ;\t0071 ;\tMA\t# ( 𝘲 → q ) MATHEMATICAL SANS-SERIF ITALIC SMALL Q → LATIN SMALL LETTER Q\t# \n1D666 ;\t0071 ;\tMA\t# ( 𝙦 → q ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q → LATIN SMALL LETTER Q\t# \n1D69A ;\t0071 ;\tMA\t# ( 𝚚 → q ) MATHEMATICAL MONOSPACE SMALL Q → LATIN SMALL LETTER Q\t# \n051B ;\t0071 ;\tMA\t# ( ԛ → q ) CYRILLIC SMALL LETTER QA → LATIN SMALL LETTER Q\t# \n0563 ;\t0071 ;\tMA\t# ( գ → q ) ARMENIAN SMALL LETTER GIM → LATIN SMALL LETTER Q\t# \n0566 ;\t0071 ;\tMA\t# ( զ → q ) ARMENIAN SMALL LETTER ZA → LATIN SMALL LETTER Q\t# \n\n211A ;\t0051 ;\tMA\t# ( ℚ → Q ) DOUBLE-STRUCK CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1CCE6 ;\t0051 ;\tMA\t#* ( 𜳦 → Q ) OUTLINED LATIN CAPITAL LETTER Q → LATIN CAPITAL LETTER Q\t# \n1D410 ;\t0051 ;\tMA\t# ( 𝐐 → Q ) MATHEMATICAL BOLD CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D444 ;\t0051 ;\tMA\t# ( 𝑄 → Q ) MATHEMATICAL ITALIC CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D478 ;\t0051 ;\tMA\t# ( 𝑸 → Q ) MATHEMATICAL BOLD ITALIC CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D4AC ;\t0051 ;\tMA\t# ( 𝒬 → Q ) MATHEMATICAL SCRIPT CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D4E0 ;\t0051 ;\tMA\t# ( 𝓠 → Q ) MATHEMATICAL BOLD SCRIPT CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D514 ;\t0051 ;\tMA\t# ( 𝔔 → Q ) MATHEMATICAL FRAKTUR CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D57C ;\t0051 ;\tMA\t# ( 𝕼 → Q ) MATHEMATICAL BOLD FRAKTUR CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D5B0 ;\t0051 ;\tMA\t# ( 𝖰 → Q ) MATHEMATICAL SANS-SERIF CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D5E4 ;\t0051 ;\tMA\t# ( 𝗤 → Q ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D618 ;\t0051 ;\tMA\t# ( 𝘘 → Q ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D64C ;\t0051 ;\tMA\t# ( 𝙌 → Q ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n1D680 ;\t0051 ;\tMA\t# ( 𝚀 → Q ) MATHEMATICAL MONOSPACE CAPITAL Q → LATIN CAPITAL LETTER Q\t# \n2D55 ;\t0051 ;\tMA\t# ( ⵕ → Q ) TIFINAGH LETTER YARR → LATIN CAPITAL LETTER Q\t# \n\n02A0 ;\t0071 0314 ;\tMA\t# ( ʠ → q̔ ) LATIN SMALL LETTER Q WITH HOOK → LATIN SMALL LETTER Q, COMBINING REVERSED COMMA ABOVE\t# \n\n1F700 ;\t0051 0045 ;\tMA\t#* ( 🜀 → QE ) ALCHEMICAL SYMBOL FOR QUINTESSENCE → LATIN CAPITAL LETTER Q, LATIN CAPITAL LETTER E\t# \n\n1D90 ;\t024B ;\tMA\t# ( ᶐ → ɋ ) LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK → LATIN SMALL LETTER Q WITH HOOK TAIL\t# \n\n1D0B ;\t0138 ;\tMA\t# ( ᴋ → ĸ ) LATIN LETTER SMALL CAPITAL K → LATIN SMALL LETTER KRA\t# \n03BA ;\t0138 ;\tMA\t# ( κ → ĸ ) GREEK SMALL LETTER KAPPA → LATIN SMALL LETTER KRA\t# \n03F0 ;\t0138 ;\tMA\t# ( ϰ → ĸ ) GREEK KAPPA SYMBOL → LATIN SMALL LETTER KRA\t# →κ→\n1D6CB ;\t0138 ;\tMA\t# ( 𝛋 → ĸ ) MATHEMATICAL BOLD SMALL KAPPA → LATIN SMALL LETTER KRA\t# →κ→\n1D6DE ;\t0138 ;\tMA\t# ( 𝛞 → ĸ ) MATHEMATICAL BOLD KAPPA SYMBOL → LATIN SMALL LETTER KRA\t# →κ→\n1D705 ;\t0138 ;\tMA\t# ( 𝜅 → ĸ ) MATHEMATICAL ITALIC SMALL KAPPA → LATIN SMALL LETTER KRA\t# →κ→\n1D718 ;\t0138 ;\tMA\t# ( 𝜘 → ĸ ) MATHEMATICAL ITALIC KAPPA SYMBOL → LATIN SMALL LETTER KRA\t# →κ→\n1D73F ;\t0138 ;\tMA\t# ( 𝜿 → ĸ ) MATHEMATICAL BOLD ITALIC SMALL KAPPA → LATIN SMALL LETTER KRA\t# →κ→\n1D752 ;\t0138 ;\tMA\t# ( 𝝒 → ĸ ) MATHEMATICAL BOLD ITALIC KAPPA SYMBOL → LATIN SMALL LETTER KRA\t# →κ→\n1D779 ;\t0138 ;\tMA\t# ( 𝝹 → ĸ ) MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA → LATIN SMALL LETTER KRA\t# →κ→\n1D78C ;\t0138 ;\tMA\t# ( 𝞌 → ĸ ) MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL → LATIN SMALL LETTER KRA\t# →κ→\n1D7B3 ;\t0138 ;\tMA\t# ( 𝞳 → ĸ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA → LATIN SMALL LETTER KRA\t# →κ→\n1D7C6 ;\t0138 ;\tMA\t# ( 𝟆 → ĸ ) MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL → LATIN SMALL LETTER KRA\t# →κ→\n2C95 ;\t0138 ;\tMA\t# ( ⲕ → ĸ ) COPTIC SMALL LETTER KAPA → LATIN SMALL LETTER KRA\t# →κ→\n043A ;\t0138 ;\tMA\t# ( к → ĸ ) CYRILLIC SMALL LETTER KA → LATIN SMALL LETTER KRA\t# \nABB6 ;\t0138 ;\tMA\t# ( ꮶ → ĸ ) CHEROKEE SMALL LETTER TSO → LATIN SMALL LETTER KRA\t# →ᴋ→\n\n049B ;\t0138 0329 ;\tMA\t# ( қ → ĸ̩ ) CYRILLIC SMALL LETTER KA WITH DESCENDER → LATIN SMALL LETTER KRA, COMBINING VERTICAL LINE BELOW\t# →к̩→\n\n049F ;\t0138 0335 ;\tMA\t# ( ҟ → ĸ̵ ) CYRILLIC SMALL LETTER KA WITH STROKE → LATIN SMALL LETTER KRA, COMBINING SHORT STROKE OVERLAY\t# →к̵→\n\n1D42B ;\t0072 ;\tMA\t# ( 𝐫 → r ) MATHEMATICAL BOLD SMALL R → LATIN SMALL LETTER R\t# \n1D45F ;\t0072 ;\tMA\t# ( 𝑟 → r ) MATHEMATICAL ITALIC SMALL R → LATIN SMALL LETTER R\t# \n1D493 ;\t0072 ;\tMA\t# ( 𝒓 → r ) MATHEMATICAL BOLD ITALIC SMALL R → LATIN SMALL LETTER R\t# \n1D4C7 ;\t0072 ;\tMA\t# ( 𝓇 → r ) MATHEMATICAL SCRIPT SMALL R → LATIN SMALL LETTER R\t# \n1D4FB ;\t0072 ;\tMA\t# ( 𝓻 → r ) MATHEMATICAL BOLD SCRIPT SMALL R → LATIN SMALL LETTER R\t# \n1D52F ;\t0072 ;\tMA\t# ( 𝔯 → r ) MATHEMATICAL FRAKTUR SMALL R → LATIN SMALL LETTER R\t# \n1D563 ;\t0072 ;\tMA\t# ( 𝕣 → r ) MATHEMATICAL DOUBLE-STRUCK SMALL R → LATIN SMALL LETTER R\t# \n1D597 ;\t0072 ;\tMA\t# ( 𝖗 → r ) MATHEMATICAL BOLD FRAKTUR SMALL R → LATIN SMALL LETTER R\t# \n1D5CB ;\t0072 ;\tMA\t# ( 𝗋 → r ) MATHEMATICAL SANS-SERIF SMALL R → LATIN SMALL LETTER R\t# \n1D5FF ;\t0072 ;\tMA\t# ( 𝗿 → r ) MATHEMATICAL SANS-SERIF BOLD SMALL R → LATIN SMALL LETTER R\t# \n1D633 ;\t0072 ;\tMA\t# ( 𝘳 → r ) MATHEMATICAL SANS-SERIF ITALIC SMALL R → LATIN SMALL LETTER R\t# \n1D667 ;\t0072 ;\tMA\t# ( 𝙧 → r ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R → LATIN SMALL LETTER R\t# \n1D69B ;\t0072 ;\tMA\t# ( 𝚛 → r ) MATHEMATICAL MONOSPACE SMALL R → LATIN SMALL LETTER R\t# \nAB47 ;\t0072 ;\tMA\t# ( ꭇ → r ) LATIN SMALL LETTER R WITHOUT HANDLE → LATIN SMALL LETTER R\t# \nAB48 ;\t0072 ;\tMA\t# ( ꭈ → r ) LATIN SMALL LETTER DOUBLE R → LATIN SMALL LETTER R\t# \n1D26 ;\t0072 ;\tMA\t# ( ᴦ → r ) GREEK LETTER SMALL CAPITAL GAMMA → LATIN SMALL LETTER R\t# →г→\n2C85 ;\t0072 ;\tMA\t# ( ⲅ → r ) COPTIC SMALL LETTER GAMMA → LATIN SMALL LETTER R\t# →г→\n0433 ;\t0072 ;\tMA\t# ( г → r ) CYRILLIC SMALL LETTER GHE → LATIN SMALL LETTER R\t# \nAB81 ;\t0072 ;\tMA\t# ( ꮁ → r ) CHEROKEE SMALL LETTER HU → LATIN SMALL LETTER R\t# →ᴦ→→г→\n\n1D216 ;\t0052 ;\tMA\t#* ( 𝈖 → R ) GREEK VOCAL NOTATION SYMBOL-23 → LATIN CAPITAL LETTER R\t# \n211B ;\t0052 ;\tMA\t# ( ℛ → R ) SCRIPT CAPITAL R → LATIN CAPITAL LETTER R\t# \n211C ;\t0052 ;\tMA\t# ( ℜ → R ) BLACK-LETTER CAPITAL R → LATIN CAPITAL LETTER R\t# \n211D ;\t0052 ;\tMA\t# ( ℝ → R ) DOUBLE-STRUCK CAPITAL R → LATIN CAPITAL LETTER R\t# \n1CCE7 ;\t0052 ;\tMA\t#* ( 𜳧 → R ) OUTLINED LATIN CAPITAL LETTER R → LATIN CAPITAL LETTER R\t# \n1D411 ;\t0052 ;\tMA\t# ( 𝐑 → R ) MATHEMATICAL BOLD CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D445 ;\t0052 ;\tMA\t# ( 𝑅 → R ) MATHEMATICAL ITALIC CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D479 ;\t0052 ;\tMA\t# ( 𝑹 → R ) MATHEMATICAL BOLD ITALIC CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D4E1 ;\t0052 ;\tMA\t# ( 𝓡 → R ) MATHEMATICAL BOLD SCRIPT CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D57D ;\t0052 ;\tMA\t# ( 𝕽 → R ) MATHEMATICAL BOLD FRAKTUR CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D5B1 ;\t0052 ;\tMA\t# ( 𝖱 → R ) MATHEMATICAL SANS-SERIF CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D5E5 ;\t0052 ;\tMA\t# ( 𝗥 → R ) MATHEMATICAL SANS-SERIF BOLD CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D619 ;\t0052 ;\tMA\t# ( 𝘙 → R ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D64D ;\t0052 ;\tMA\t# ( 𝙍 → R ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R → LATIN CAPITAL LETTER R\t# \n1D681 ;\t0052 ;\tMA\t# ( 𝚁 → R ) MATHEMATICAL MONOSPACE CAPITAL R → LATIN CAPITAL LETTER R\t# \n01A6 ;\t0052 ;\tMA\t# ( Ʀ → R ) LATIN LETTER YR → LATIN CAPITAL LETTER R\t# \n13A1 ;\t0052 ;\tMA\t# ( Ꭱ → R ) CHEROKEE LETTER E → LATIN CAPITAL LETTER R\t# \n13D2 ;\t0052 ;\tMA\t# ( Ꮢ → R ) CHEROKEE LETTER SV → LATIN CAPITAL LETTER R\t# \n104B4 ;\t0052 ;\tMA\t# ( 𐒴 → R ) OSAGE CAPITAL LETTER BRA → LATIN CAPITAL LETTER R\t# →Ʀ→\n1587 ;\t0052 ;\tMA\t# ( ᖇ → R ) CANADIAN SYLLABICS TLHI → LATIN CAPITAL LETTER R\t# \nA4E3 ;\t0052 ;\tMA\t# ( ꓣ → R ) LISU LETTER ZHA → LATIN CAPITAL LETTER R\t# \n16F35 ;\t0052 ;\tMA\t# ( 𖼵 → R ) MIAO LETTER ZHA → LATIN CAPITAL LETTER R\t# \n\n027D ;\t0072 0328 ;\tMA\t# ( ɽ → r̨ ) LATIN SMALL LETTER R WITH TAIL → LATIN SMALL LETTER R, COMBINING OGONEK\t# \n\n027C ;\t0072 0329 ;\tMA\t# ( ɼ → r̩ ) LATIN SMALL LETTER R WITH LONG LEG → LATIN SMALL LETTER R, COMBINING VERTICAL LINE BELOW\t# \n\n024D ;\t0072 0335 ;\tMA\t# ( ɍ → r̵ ) LATIN SMALL LETTER R WITH STROKE → LATIN SMALL LETTER R, COMBINING SHORT STROKE OVERLAY\t# \n0493 ;\t0072 0335 ;\tMA\t# ( ғ → r̵ ) CYRILLIC SMALL LETTER GHE WITH STROKE → LATIN SMALL LETTER R, COMBINING SHORT STROKE OVERLAY\t# →г̵→\n\n1D72 ;\t0072 0334 ;\tMA\t# ( ᵲ → r̴ ) LATIN SMALL LETTER R WITH MIDDLE TILDE → LATIN SMALL LETTER R, COMBINING TILDE OVERLAY\t# \n\n0491 ;\t0072 0027 ;\tMA\t# ( ґ → r' ) CYRILLIC SMALL LETTER GHE WITH UPTURN → LATIN SMALL LETTER R, APOSTROPHE\t# →гˈ→\n\n118E3 ;\t0072 006E ;\tMA\t# ( 𑣣 → rn ) WARANG CITI DIGIT THREE → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n006D ;\t0072 006E ;\tMA\t# ( m → rn ) LATIN SMALL LETTER M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# \n217F ;\t0072 006E ;\tMA\t# ( ⅿ → rn ) SMALL ROMAN NUMERAL ONE THOUSAND → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D426 ;\t0072 006E ;\tMA\t# ( 𝐦 → rn ) MATHEMATICAL BOLD SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D45A ;\t0072 006E ;\tMA\t# ( 𝑚 → rn ) MATHEMATICAL ITALIC SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D48E ;\t0072 006E ;\tMA\t# ( 𝒎 → rn ) MATHEMATICAL BOLD ITALIC SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D4C2 ;\t0072 006E ;\tMA\t# ( 𝓂 → rn ) MATHEMATICAL SCRIPT SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D4F6 ;\t0072 006E ;\tMA\t# ( 𝓶 → rn ) MATHEMATICAL BOLD SCRIPT SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D52A ;\t0072 006E ;\tMA\t# ( 𝔪 → rn ) MATHEMATICAL FRAKTUR SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D55E ;\t0072 006E ;\tMA\t# ( 𝕞 → rn ) MATHEMATICAL DOUBLE-STRUCK SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D592 ;\t0072 006E ;\tMA\t# ( 𝖒 → rn ) MATHEMATICAL BOLD FRAKTUR SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D5C6 ;\t0072 006E ;\tMA\t# ( 𝗆 → rn ) MATHEMATICAL SANS-SERIF SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D5FA ;\t0072 006E ;\tMA\t# ( 𝗺 → rn ) MATHEMATICAL SANS-SERIF BOLD SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D62E ;\t0072 006E ;\tMA\t# ( 𝘮 → rn ) MATHEMATICAL SANS-SERIF ITALIC SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D662 ;\t0072 006E ;\tMA\t# ( 𝙢 → rn ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n1D696 ;\t0072 006E ;\tMA\t# ( 𝚖 → rn ) MATHEMATICAL MONOSPACE SMALL M → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n11700 ;\t0072 006E ;\tMA\t# ( 𑜀 → rn ) AHOM LETTER KA → LATIN SMALL LETTER R, LATIN SMALL LETTER N\t# →m→\n\n20A5 ;\t0072 006E 0338 ;\tMA\t#* ( ₥ → rn̸ ) MILL SIGN → LATIN SMALL LETTER R, LATIN SMALL LETTER N, COMBINING LONG SOLIDUS OVERLAY\t# →m̷→\n\n0271 ;\t0072 006E 0326 ;\tMA\t# ( ɱ → rn̦ ) LATIN SMALL LETTER M WITH HOOK → LATIN SMALL LETTER R, LATIN SMALL LETTER N, COMBINING COMMA BELOW\t# →m̡→\n\n1D6F ;\t0072 006E 0334 ;\tMA\t# ( ᵯ → rn̴ ) LATIN SMALL LETTER M WITH MIDDLE TILDE → LATIN SMALL LETTER R, LATIN SMALL LETTER N, COMBINING TILDE OVERLAY\t# →m̴→\n\n20A8 ;\t0052 0073 ;\tMA\t#* ( ₨ → Rs ) RUPEE SIGN → LATIN CAPITAL LETTER R, LATIN SMALL LETTER S\t# \n\nAB71 ;\t0280 ;\tMA\t# ( ꭱ → ʀ ) CHEROKEE SMALL LETTER E → LATIN LETTER SMALL CAPITAL R\t# \nABA2 ;\t0280 ;\tMA\t# ( ꮢ → ʀ ) CHEROKEE SMALL LETTER SV → LATIN LETTER SMALL CAPITAL R\t# \n\n044F ;\t1D19 ;\tMA\t# ( я → ᴙ ) CYRILLIC SMALL LETTER YA → LATIN LETTER SMALL CAPITAL REVERSED R\t# \n\n1D73 ;\t027E 0334 ;\tMA\t# ( ᵳ → ɾ̴ ) LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE → LATIN SMALL LETTER R WITH FISHHOOK, COMBINING TILDE OVERLAY\t# \n\n2129 ;\t027F ;\tMA\t#* ( ℩ → ɿ ) TURNED GREEK SMALL LETTER IOTA → LATIN SMALL LETTER REVERSED R WITH FISHHOOK\t# \n\nFF53 ;\t0073 ;\tMA\t# ( ｓ → s ) FULLWIDTH LATIN SMALL LETTER S → LATIN SMALL LETTER S\t# →ѕ→\n1D42C ;\t0073 ;\tMA\t# ( 𝐬 → s ) MATHEMATICAL BOLD SMALL S → LATIN SMALL LETTER S\t# \n1D460 ;\t0073 ;\tMA\t# ( 𝑠 → s ) MATHEMATICAL ITALIC SMALL S → LATIN SMALL LETTER S\t# \n1D494 ;\t0073 ;\tMA\t# ( 𝒔 → s ) MATHEMATICAL BOLD ITALIC SMALL S → LATIN SMALL LETTER S\t# \n1D4C8 ;\t0073 ;\tMA\t# ( 𝓈 → s ) MATHEMATICAL SCRIPT SMALL S → LATIN SMALL LETTER S\t# \n1D4FC ;\t0073 ;\tMA\t# ( 𝓼 → s ) MATHEMATICAL BOLD SCRIPT SMALL S → LATIN SMALL LETTER S\t# \n1D530 ;\t0073 ;\tMA\t# ( 𝔰 → s ) MATHEMATICAL FRAKTUR SMALL S → LATIN SMALL LETTER S\t# \n1D564 ;\t0073 ;\tMA\t# ( 𝕤 → s ) MATHEMATICAL DOUBLE-STRUCK SMALL S → LATIN SMALL LETTER S\t# \n1D598 ;\t0073 ;\tMA\t# ( 𝖘 → s ) MATHEMATICAL BOLD FRAKTUR SMALL S → LATIN SMALL LETTER S\t# \n1D5CC ;\t0073 ;\tMA\t# ( 𝗌 → s ) MATHEMATICAL SANS-SERIF SMALL S → LATIN SMALL LETTER S\t# \n1D600 ;\t0073 ;\tMA\t# ( 𝘀 → s ) MATHEMATICAL SANS-SERIF BOLD SMALL S → LATIN SMALL LETTER S\t# \n1D634 ;\t0073 ;\tMA\t# ( 𝘴 → s ) MATHEMATICAL SANS-SERIF ITALIC SMALL S → LATIN SMALL LETTER S\t# \n1D668 ;\t0073 ;\tMA\t# ( 𝙨 → s ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S → LATIN SMALL LETTER S\t# \n1D69C ;\t0073 ;\tMA\t# ( 𝚜 → s ) MATHEMATICAL MONOSPACE SMALL S → LATIN SMALL LETTER S\t# \nA731 ;\t0073 ;\tMA\t# ( ꜱ → s ) LATIN LETTER SMALL CAPITAL S → LATIN SMALL LETTER S\t# \n01BD ;\t0073 ;\tMA\t# ( ƽ → s ) LATIN SMALL LETTER TONE FIVE → LATIN SMALL LETTER S\t# \n0455 ;\t0073 ;\tMA\t# ( ѕ → s ) CYRILLIC SMALL LETTER DZE → LATIN SMALL LETTER S\t# \n0D1F ;\t0073 ;\tMA\t# ( ട → s ) MALAYALAM LETTER TTA → LATIN SMALL LETTER S\t# \nABAA ;\t0073 ;\tMA\t# ( ꮪ → s ) CHEROKEE SMALL LETTER DU → LATIN SMALL LETTER S\t# →ꜱ→\n118C1 ;\t0073 ;\tMA\t# ( 𑣁 → s ) WARANG CITI SMALL LETTER A → LATIN SMALL LETTER S\t# \n10448 ;\t0073 ;\tMA\t# ( 𐑈 → s ) DESERET SMALL LETTER ZHEE → LATIN SMALL LETTER S\t# \n\nFF33 ;\t0053 ;\tMA\t# ( Ｓ → S ) FULLWIDTH LATIN CAPITAL LETTER S → LATIN CAPITAL LETTER S\t# →Ѕ→\n1CCE8 ;\t0053 ;\tMA\t#* ( 𜳨 → S ) OUTLINED LATIN CAPITAL LETTER S → LATIN CAPITAL LETTER S\t# \n1D412 ;\t0053 ;\tMA\t# ( 𝐒 → S ) MATHEMATICAL BOLD CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D446 ;\t0053 ;\tMA\t# ( 𝑆 → S ) MATHEMATICAL ITALIC CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D47A ;\t0053 ;\tMA\t# ( 𝑺 → S ) MATHEMATICAL BOLD ITALIC CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D4AE ;\t0053 ;\tMA\t# ( 𝒮 → S ) MATHEMATICAL SCRIPT CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D4E2 ;\t0053 ;\tMA\t# ( 𝓢 → S ) MATHEMATICAL BOLD SCRIPT CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D516 ;\t0053 ;\tMA\t# ( 𝔖 → S ) MATHEMATICAL FRAKTUR CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D54A ;\t0053 ;\tMA\t# ( 𝕊 → S ) MATHEMATICAL DOUBLE-STRUCK CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D57E ;\t0053 ;\tMA\t# ( 𝕾 → S ) MATHEMATICAL BOLD FRAKTUR CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D5B2 ;\t0053 ;\tMA\t# ( 𝖲 → S ) MATHEMATICAL SANS-SERIF CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D5E6 ;\t0053 ;\tMA\t# ( 𝗦 → S ) MATHEMATICAL SANS-SERIF BOLD CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D61A ;\t0053 ;\tMA\t# ( 𝘚 → S ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D64E ;\t0053 ;\tMA\t# ( 𝙎 → S ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S → LATIN CAPITAL LETTER S\t# \n1D682 ;\t0053 ;\tMA\t# ( 𝚂 → S ) MATHEMATICAL MONOSPACE CAPITAL S → LATIN CAPITAL LETTER S\t# \n0405 ;\t0053 ;\tMA\t# ( Ѕ → S ) CYRILLIC CAPITAL LETTER DZE → LATIN CAPITAL LETTER S\t# \n054F ;\t0053 ;\tMA\t# ( Տ → S ) ARMENIAN CAPITAL LETTER TIWN → LATIN CAPITAL LETTER S\t# \n13D5 ;\t0053 ;\tMA\t# ( Ꮥ → S ) CHEROKEE LETTER DE → LATIN CAPITAL LETTER S\t# \n13DA ;\t0053 ;\tMA\t# ( Ꮪ → S ) CHEROKEE LETTER DU → LATIN CAPITAL LETTER S\t# \nA4E2 ;\t0053 ;\tMA\t# ( ꓢ → S ) LISU LETTER SA → LATIN CAPITAL LETTER S\t# \n16F3A ;\t0053 ;\tMA\t# ( 𖼺 → S ) MIAO LETTER SA → LATIN CAPITAL LETTER S\t# \n10296 ;\t0053 ;\tMA\t# ( 𐊖 → S ) LYCIAN LETTER S → LATIN CAPITAL LETTER S\t# \n10420 ;\t0053 ;\tMA\t# ( 𐐠 → S ) DESERET CAPITAL LETTER ZHEE → LATIN CAPITAL LETTER S\t# \n\n0282 ;\t0073 0328 ;\tMA\t# ( ʂ → s̨ ) LATIN SMALL LETTER S WITH HOOK → LATIN SMALL LETTER S, COMBINING OGONEK\t# \n\n1D74 ;\t0073 0334 ;\tMA\t# ( ᵴ → s̴ ) LATIN SMALL LETTER S WITH MIDDLE TILDE → LATIN SMALL LETTER S, COMBINING TILDE OVERLAY\t# \n\nA7B5 ;\t00DF ;\tMA\t# ( ꞵ → ß ) LATIN SMALL LETTER BETA → LATIN SMALL LETTER SHARP S\t# →β→\n1E9E ;\t00DF ;\tMA\t# ( ẞ → ß ) LATIN CAPITAL LETTER SHARP S → LATIN SMALL LETTER SHARP S\t# \nA7D6 ;\t00DF ;\tMA\t# ( Ꟗ → ß ) LATIN CAPITAL LETTER MIDDLE SCOTS S → LATIN SMALL LETTER SHARP S\t# →β→\n03B2 ;\t00DF ;\tMA\t# ( β → ß ) GREEK SMALL LETTER BETA → LATIN SMALL LETTER SHARP S\t# \n03D0 ;\t00DF ;\tMA\t# ( ϐ → ß ) GREEK BETA SYMBOL → LATIN SMALL LETTER SHARP S\t# →β→\n1D6C3 ;\t00DF ;\tMA\t# ( 𝛃 → ß ) MATHEMATICAL BOLD SMALL BETA → LATIN SMALL LETTER SHARP S\t# →β→\n1D6FD ;\t00DF ;\tMA\t# ( 𝛽 → ß ) MATHEMATICAL ITALIC SMALL BETA → LATIN SMALL LETTER SHARP S\t# →β→\n1D737 ;\t00DF ;\tMA\t# ( 𝜷 → ß ) MATHEMATICAL BOLD ITALIC SMALL BETA → LATIN SMALL LETTER SHARP S\t# →β→\n1D771 ;\t00DF ;\tMA\t# ( 𝝱 → ß ) MATHEMATICAL SANS-SERIF BOLD SMALL BETA → LATIN SMALL LETTER SHARP S\t# →β→\n1D7AB ;\t00DF ;\tMA\t# ( 𝞫 → ß ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA → LATIN SMALL LETTER SHARP S\t# →β→\n13F0 ;\t00DF ;\tMA\t# ( Ᏸ → ß ) CHEROKEE LETTER YE → LATIN SMALL LETTER SHARP S\t# →β→\n\n1F75C ;\t0073 0073 0073 ;\tMA\t#* ( 🝜 → sss ) ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM → LATIN SMALL LETTER S, LATIN SMALL LETTER S, LATIN SMALL LETTER S\t# \n\nFB06 ;\t0073 0074 ;\tMA\t# ( ﬆ → st ) LATIN SMALL LIGATURE ST → LATIN SMALL LETTER S, LATIN SMALL LETTER T\t# \n\n222B ;\t0283 ;\tMA\t#* ( ∫ → ʃ ) INTEGRAL → LATIN SMALL LETTER ESH\t# \nAB4D ;\t0283 ;\tMA\t# ( ꭍ → ʃ ) LATIN SMALL LETTER BASELINE ESH → LATIN SMALL LETTER ESH\t# \n\n2211 ;\t01A9 ;\tMA\t#* ( ∑ → Ʃ ) N-ARY SUMMATION → LATIN CAPITAL LETTER ESH\t# \n2140 ;\t01A9 ;\tMA\t#* ( ⅀ → Ʃ ) DOUBLE-STRUCK N-ARY SUMMATION → LATIN CAPITAL LETTER ESH\t# →∑→\n03A3 ;\t01A9 ;\tMA\t# ( Σ → Ʃ ) GREEK CAPITAL LETTER SIGMA → LATIN CAPITAL LETTER ESH\t# \n1D6BA ;\t01A9 ;\tMA\t# ( 𝚺 → Ʃ ) MATHEMATICAL BOLD CAPITAL SIGMA → LATIN CAPITAL LETTER ESH\t# →Σ→\n1D6F4 ;\t01A9 ;\tMA\t# ( 𝛴 → Ʃ ) MATHEMATICAL ITALIC CAPITAL SIGMA → LATIN CAPITAL LETTER ESH\t# →Σ→\n1D72E ;\t01A9 ;\tMA\t# ( 𝜮 → Ʃ ) MATHEMATICAL BOLD ITALIC CAPITAL SIGMA → LATIN CAPITAL LETTER ESH\t# →Σ→\n1D768 ;\t01A9 ;\tMA\t# ( 𝝨 → Ʃ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA → LATIN CAPITAL LETTER ESH\t# →Σ→\n1D7A2 ;\t01A9 ;\tMA\t# ( 𝞢 → Ʃ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA → LATIN CAPITAL LETTER ESH\t# →Σ→\n2D49 ;\t01A9 ;\tMA\t# ( ⵉ → Ʃ ) TIFINAGH LETTER YI → LATIN CAPITAL LETTER ESH\t# \n\n222C ;\t0283 0283 ;\tMA\t#* ( ∬ → ʃʃ ) DOUBLE INTEGRAL → LATIN SMALL LETTER ESH, LATIN SMALL LETTER ESH\t# →∫∫→\n\n222D ;\t0283 0283 0283 ;\tMA\t#* ( ∭ → ʃʃʃ ) TRIPLE INTEGRAL → LATIN SMALL LETTER ESH, LATIN SMALL LETTER ESH, LATIN SMALL LETTER ESH\t# →∫∫∫→\n\n2A0C ;\t0283 0283 0283 0283 ;\tMA\t#* ( ⨌ → ʃʃʃʃ ) QUADRUPLE INTEGRAL OPERATOR → LATIN SMALL LETTER ESH, LATIN SMALL LETTER ESH, LATIN SMALL LETTER ESH, LATIN SMALL LETTER ESH\t# →∫∫∫∫→\n\n1D42D ;\t0074 ;\tMA\t# ( 𝐭 → t ) MATHEMATICAL BOLD SMALL T → LATIN SMALL LETTER T\t# \n1D461 ;\t0074 ;\tMA\t# ( 𝑡 → t ) MATHEMATICAL ITALIC SMALL T → LATIN SMALL LETTER T\t# \n1D495 ;\t0074 ;\tMA\t# ( 𝒕 → t ) MATHEMATICAL BOLD ITALIC SMALL T → LATIN SMALL LETTER T\t# \n1D4C9 ;\t0074 ;\tMA\t# ( 𝓉 → t ) MATHEMATICAL SCRIPT SMALL T → LATIN SMALL LETTER T\t# \n1D4FD ;\t0074 ;\tMA\t# ( 𝓽 → t ) MATHEMATICAL BOLD SCRIPT SMALL T → LATIN SMALL LETTER T\t# \n1D531 ;\t0074 ;\tMA\t# ( 𝔱 → t ) MATHEMATICAL FRAKTUR SMALL T → LATIN SMALL LETTER T\t# \n1D565 ;\t0074 ;\tMA\t# ( 𝕥 → t ) MATHEMATICAL DOUBLE-STRUCK SMALL T → LATIN SMALL LETTER T\t# \n1D599 ;\t0074 ;\tMA\t# ( 𝖙 → t ) MATHEMATICAL BOLD FRAKTUR SMALL T → LATIN SMALL LETTER T\t# \n1D5CD ;\t0074 ;\tMA\t# ( 𝗍 → t ) MATHEMATICAL SANS-SERIF SMALL T → LATIN SMALL LETTER T\t# \n1D601 ;\t0074 ;\tMA\t# ( 𝘁 → t ) MATHEMATICAL SANS-SERIF BOLD SMALL T → LATIN SMALL LETTER T\t# \n1D635 ;\t0074 ;\tMA\t# ( 𝘵 → t ) MATHEMATICAL SANS-SERIF ITALIC SMALL T → LATIN SMALL LETTER T\t# \n1D669 ;\t0074 ;\tMA\t# ( 𝙩 → t ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T → LATIN SMALL LETTER T\t# \n1D69D ;\t0074 ;\tMA\t# ( 𝚝 → t ) MATHEMATICAL MONOSPACE SMALL T → LATIN SMALL LETTER T\t# \n\n22A4 ;\t0054 ;\tMA\t#* ( ⊤ → T ) DOWN TACK → LATIN CAPITAL LETTER T\t# \n27D9 ;\t0054 ;\tMA\t#* ( ⟙ → T ) LARGE DOWN TACK → LATIN CAPITAL LETTER T\t# \n1F768 ;\t0054 ;\tMA\t#* ( 🝨 → T ) ALCHEMICAL SYMBOL FOR CRUCIBLE-4 → LATIN CAPITAL LETTER T\t# \nFF34 ;\t0054 ;\tMA\t# ( Ｔ → T ) FULLWIDTH LATIN CAPITAL LETTER T → LATIN CAPITAL LETTER T\t# →Т→\n1CCE9 ;\t0054 ;\tMA\t#* ( 𜳩 → T ) OUTLINED LATIN CAPITAL LETTER T → LATIN CAPITAL LETTER T\t# \n1D413 ;\t0054 ;\tMA\t# ( 𝐓 → T ) MATHEMATICAL BOLD CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D447 ;\t0054 ;\tMA\t# ( 𝑇 → T ) MATHEMATICAL ITALIC CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D47B ;\t0054 ;\tMA\t# ( 𝑻 → T ) MATHEMATICAL BOLD ITALIC CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D4AF ;\t0054 ;\tMA\t# ( 𝒯 → T ) MATHEMATICAL SCRIPT CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D4E3 ;\t0054 ;\tMA\t# ( 𝓣 → T ) MATHEMATICAL BOLD SCRIPT CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D517 ;\t0054 ;\tMA\t# ( 𝔗 → T ) MATHEMATICAL FRAKTUR CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D54B ;\t0054 ;\tMA\t# ( 𝕋 → T ) MATHEMATICAL DOUBLE-STRUCK CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D57F ;\t0054 ;\tMA\t# ( 𝕿 → T ) MATHEMATICAL BOLD FRAKTUR CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D5B3 ;\t0054 ;\tMA\t# ( 𝖳 → T ) MATHEMATICAL SANS-SERIF CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D5E7 ;\t0054 ;\tMA\t# ( 𝗧 → T ) MATHEMATICAL SANS-SERIF BOLD CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D61B ;\t0054 ;\tMA\t# ( 𝘛 → T ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D64F ;\t0054 ;\tMA\t# ( 𝙏 → T ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T → LATIN CAPITAL LETTER T\t# \n1D683 ;\t0054 ;\tMA\t# ( 𝚃 → T ) MATHEMATICAL MONOSPACE CAPITAL T → LATIN CAPITAL LETTER T\t# \n03A4 ;\t0054 ;\tMA\t# ( Τ → T ) GREEK CAPITAL LETTER TAU → LATIN CAPITAL LETTER T\t# \n1D6BB ;\t0054 ;\tMA\t# ( 𝚻 → T ) MATHEMATICAL BOLD CAPITAL TAU → LATIN CAPITAL LETTER T\t# →Τ→\n1D6F5 ;\t0054 ;\tMA\t# ( 𝛵 → T ) MATHEMATICAL ITALIC CAPITAL TAU → LATIN CAPITAL LETTER T\t# →Τ→\n1D72F ;\t0054 ;\tMA\t# ( 𝜯 → T ) MATHEMATICAL BOLD ITALIC CAPITAL TAU → LATIN CAPITAL LETTER T\t# →Τ→\n1D769 ;\t0054 ;\tMA\t# ( 𝝩 → T ) MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU → LATIN CAPITAL LETTER T\t# →Τ→\n1D7A3 ;\t0054 ;\tMA\t# ( 𝞣 → T ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU → LATIN CAPITAL LETTER T\t# →Τ→\n2CA6 ;\t0054 ;\tMA\t# ( Ⲧ → T ) COPTIC CAPITAL LETTER TAU → LATIN CAPITAL LETTER T\t# \n0422 ;\t0054 ;\tMA\t# ( Т → T ) CYRILLIC CAPITAL LETTER TE → LATIN CAPITAL LETTER T\t# \n13A2 ;\t0054 ;\tMA\t# ( Ꭲ → T ) CHEROKEE LETTER I → LATIN CAPITAL LETTER T\t# \nA4D4 ;\t0054 ;\tMA\t# ( ꓔ → T ) LISU LETTER TA → LATIN CAPITAL LETTER T\t# \n16F0A ;\t0054 ;\tMA\t# ( 𖼊 → T ) MIAO LETTER TA → LATIN CAPITAL LETTER T\t# \n118BC ;\t0054 ;\tMA\t# ( 𑢼 → T ) WARANG CITI CAPITAL LETTER HAR → LATIN CAPITAL LETTER T\t# \n10297 ;\t0054 ;\tMA\t# ( 𐊗 → T ) LYCIAN LETTER T → LATIN CAPITAL LETTER T\t# \n102B1 ;\t0054 ;\tMA\t# ( 𐊱 → T ) CARIAN LETTER C-18 → LATIN CAPITAL LETTER T\t# \n10315 ;\t0054 ;\tMA\t# ( 𐌕 → T ) OLD ITALIC LETTER TE → LATIN CAPITAL LETTER T\t# \n\n01AD ;\t0074 0314 ;\tMA\t# ( ƭ → t̔ ) LATIN SMALL LETTER T WITH HOOK → LATIN SMALL LETTER T, COMBINING REVERSED COMMA ABOVE\t# \n\n2361 ;\t0054 0308 ;\tMA\t#* ( ⍡ → T̈ ) APL FUNCTIONAL SYMBOL UP TACK DIAERESIS → LATIN CAPITAL LETTER T, COMBINING DIAERESIS\t# →⊤̈→\n\n023E ;\t0054 0338 ;\tMA\t# ( Ⱦ → T̸ ) LATIN CAPITAL LETTER T WITH DIAGONAL STROKE → LATIN CAPITAL LETTER T, COMBINING LONG SOLIDUS OVERLAY\t# \n\n021A ;\t0162 ;\tMA\t# ( Ț → Ţ ) LATIN CAPITAL LETTER T WITH COMMA BELOW → LATIN CAPITAL LETTER T WITH CEDILLA\t# \n\n01AE ;\t0054 0328 ;\tMA\t# ( Ʈ → T̨ ) LATIN CAPITAL LETTER T WITH RETROFLEX HOOK → LATIN CAPITAL LETTER T, COMBINING OGONEK\t# \n\n04AC ;\t0054 0329 ;\tMA\t# ( Ҭ → T̩ ) CYRILLIC CAPITAL LETTER TE WITH DESCENDER → LATIN CAPITAL LETTER T, COMBINING VERTICAL LINE BELOW\t# →Т̩→\n\n20AE ;\t0054 20EB ;\tMA\t#* ( ₮ → T⃫ ) TUGRIK SIGN → LATIN CAPITAL LETTER T, COMBINING LONG DOUBLE SOLIDUS OVERLAY\t# →Т⃫→\n\n0167 ;\t0074 0335 ;\tMA\t# ( ŧ → t̵ ) LATIN SMALL LETTER T WITH STROKE → LATIN SMALL LETTER T, COMBINING SHORT STROKE OVERLAY\t# \n\n0166 ;\t0054 0335 ;\tMA\t# ( Ŧ → T̵ ) LATIN CAPITAL LETTER T WITH STROKE → LATIN CAPITAL LETTER T, COMBINING SHORT STROKE OVERLAY\t# \n\n1D75 ;\t0074 0334 ;\tMA\t# ( ᵵ → t̴ ) LATIN SMALL LETTER T WITH MIDDLE TILDE → LATIN SMALL LETTER T, COMBINING TILDE OVERLAY\t# \n\n10A0 ;\tA786 ;\tMA\t# ( Ⴀ → Ꞇ ) GEORGIAN CAPITAL LETTER AN → LATIN CAPITAL LETTER INSULAR T\t# \n\nA728 ;\t0054 0033 ;\tMA\t# ( Ꜩ → T3 ) LATIN CAPITAL LETTER TZ → LATIN CAPITAL LETTER T, DIGIT THREE\t# →TƷ→\n\n02A8 ;\t0074 0255 ;\tMA\t# ( ʨ → tɕ ) LATIN SMALL LETTER TC DIGRAPH WITH CURL → LATIN SMALL LETTER T, LATIN SMALL LETTER C WITH CURL\t# \n\n2121 ;\t0054 0045 004C ;\tMA\t#* ( ℡ → TEL ) TELEPHONE SIGN → LATIN CAPITAL LETTER T, LATIN CAPITAL LETTER E, LATIN CAPITAL LETTER L\t# \n\nA777 ;\t0074 0066 ;\tMA\t# ( ꝷ → tf ) LATIN SMALL LETTER TUM → LATIN SMALL LETTER T, LATIN SMALL LETTER F\t# \n\n02A6 ;\t0074 0073 ;\tMA\t# ( ʦ → ts ) LATIN SMALL LETTER TS DIGRAPH → LATIN SMALL LETTER T, LATIN SMALL LETTER S\t# \n\n02A7 ;\t0074 0283 ;\tMA\t# ( ʧ → tʃ ) LATIN SMALL LETTER TESH DIGRAPH → LATIN SMALL LETTER T, LATIN SMALL LETTER ESH\t# \n\nA729 ;\t0074 021D ;\tMA\t# ( ꜩ → tȝ ) LATIN SMALL LETTER TZ → LATIN SMALL LETTER T, LATIN SMALL LETTER YOGH\t# \n\n03C4 ;\t1D1B ;\tMA\t# ( τ → ᴛ ) GREEK SMALL LETTER TAU → LATIN LETTER SMALL CAPITAL T\t# \n1D6D5 ;\t1D1B ;\tMA\t# ( 𝛕 → ᴛ ) MATHEMATICAL BOLD SMALL TAU → LATIN LETTER SMALL CAPITAL T\t# \n1D70F ;\t1D1B ;\tMA\t# ( 𝜏 → ᴛ ) MATHEMATICAL ITALIC SMALL TAU → LATIN LETTER SMALL CAPITAL T\t# \n1D749 ;\t1D1B ;\tMA\t# ( 𝝉 → ᴛ ) MATHEMATICAL BOLD ITALIC SMALL TAU → LATIN LETTER SMALL CAPITAL T\t# \n1D783 ;\t1D1B ;\tMA\t# ( 𝞃 → ᴛ ) MATHEMATICAL SANS-SERIF BOLD SMALL TAU → LATIN LETTER SMALL CAPITAL T\t# \n1D7BD ;\t1D1B ;\tMA\t# ( 𝞽 → ᴛ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU → LATIN LETTER SMALL CAPITAL T\t# \n2CA7 ;\t1D1B ;\tMA\t# ( ⲧ → ᴛ ) COPTIC SMALL LETTER TAU → LATIN LETTER SMALL CAPITAL T\t# →т→\n0442 ;\t1D1B ;\tMA\t# ( т → ᴛ ) CYRILLIC SMALL LETTER TE → LATIN LETTER SMALL CAPITAL T\t# \nAB72 ;\t1D1B ;\tMA\t# ( ꭲ → ᴛ ) CHEROKEE SMALL LETTER I → LATIN LETTER SMALL CAPITAL T\t# \n\n04AD ;\t1D1B 0329 ;\tMA\t# ( ҭ → ᴛ̩ ) CYRILLIC SMALL LETTER TE WITH DESCENDER → LATIN LETTER SMALL CAPITAL T, COMBINING VERTICAL LINE BELOW\t# →т̩→\n\n0163 ;\t01AB ;\tMA\t# ( ţ → ƫ ) LATIN SMALL LETTER T WITH CEDILLA → LATIN SMALL LETTER T WITH PALATAL HOOK\t# \n021B ;\t01AB ;\tMA\t# ( ț → ƫ ) LATIN SMALL LETTER T WITH COMMA BELOW → LATIN SMALL LETTER T WITH PALATAL HOOK\t# →ţ→\n13BF ;\t01AB ;\tMA\t# ( Ꮏ → ƫ ) CHEROKEE LETTER HNA → LATIN SMALL LETTER T WITH PALATAL HOOK\t# \n\n1D42E ;\t0075 ;\tMA\t# ( 𝐮 → u ) MATHEMATICAL BOLD SMALL U → LATIN SMALL LETTER U\t# \n1D462 ;\t0075 ;\tMA\t# ( 𝑢 → u ) MATHEMATICAL ITALIC SMALL U → LATIN SMALL LETTER U\t# \n1D496 ;\t0075 ;\tMA\t# ( 𝒖 → u ) MATHEMATICAL BOLD ITALIC SMALL U → LATIN SMALL LETTER U\t# \n1D4CA ;\t0075 ;\tMA\t# ( 𝓊 → u ) MATHEMATICAL SCRIPT SMALL U → LATIN SMALL LETTER U\t# \n1D4FE ;\t0075 ;\tMA\t# ( 𝓾 → u ) MATHEMATICAL BOLD SCRIPT SMALL U → LATIN SMALL LETTER U\t# \n1D532 ;\t0075 ;\tMA\t# ( 𝔲 → u ) MATHEMATICAL FRAKTUR SMALL U → LATIN SMALL LETTER U\t# \n1D566 ;\t0075 ;\tMA\t# ( 𝕦 → u ) MATHEMATICAL DOUBLE-STRUCK SMALL U → LATIN SMALL LETTER U\t# \n1D59A ;\t0075 ;\tMA\t# ( 𝖚 → u ) MATHEMATICAL BOLD FRAKTUR SMALL U → LATIN SMALL LETTER U\t# \n1D5CE ;\t0075 ;\tMA\t# ( 𝗎 → u ) MATHEMATICAL SANS-SERIF SMALL U → LATIN SMALL LETTER U\t# \n1D602 ;\t0075 ;\tMA\t# ( 𝘂 → u ) MATHEMATICAL SANS-SERIF BOLD SMALL U → LATIN SMALL LETTER U\t# \n1D636 ;\t0075 ;\tMA\t# ( 𝘶 → u ) MATHEMATICAL SANS-SERIF ITALIC SMALL U → LATIN SMALL LETTER U\t# \n1D66A ;\t0075 ;\tMA\t# ( 𝙪 → u ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U → LATIN SMALL LETTER U\t# \n1D69E ;\t0075 ;\tMA\t# ( 𝚞 → u ) MATHEMATICAL MONOSPACE SMALL U → LATIN SMALL LETTER U\t# \nA79F ;\t0075 ;\tMA\t# ( ꞟ → u ) LATIN SMALL LETTER VOLAPUK UE → LATIN SMALL LETTER U\t# \n1D1C ;\t0075 ;\tMA\t# ( ᴜ → u ) LATIN LETTER SMALL CAPITAL U → LATIN SMALL LETTER U\t# \nAB4E ;\t0075 ;\tMA\t# ( ꭎ → u ) LATIN SMALL LETTER U WITH SHORT RIGHT LEG → LATIN SMALL LETTER U\t# \nAB52 ;\t0075 ;\tMA\t# ( ꭒ → u ) LATIN SMALL LETTER U WITH LEFT HOOK → LATIN SMALL LETTER U\t# \n028B ;\t0075 ;\tMA\t# ( ʋ → u ) LATIN SMALL LETTER V WITH HOOK → LATIN SMALL LETTER U\t# \n03C5 ;\t0075 ;\tMA\t# ( υ → u ) GREEK SMALL LETTER UPSILON → LATIN SMALL LETTER U\t# →ʋ→\n1D6D6 ;\t0075 ;\tMA\t# ( 𝛖 → u ) MATHEMATICAL BOLD SMALL UPSILON → LATIN SMALL LETTER U\t# →υ→→ʋ→\n1D710 ;\t0075 ;\tMA\t# ( 𝜐 → u ) MATHEMATICAL ITALIC SMALL UPSILON → LATIN SMALL LETTER U\t# →υ→→ʋ→\n1D74A ;\t0075 ;\tMA\t# ( 𝝊 → u ) MATHEMATICAL BOLD ITALIC SMALL UPSILON → LATIN SMALL LETTER U\t# →υ→→ʋ→\n1D784 ;\t0075 ;\tMA\t# ( 𝞄 → u ) MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON → LATIN SMALL LETTER U\t# →υ→→ʋ→\n1D7BE ;\t0075 ;\tMA\t# ( 𝞾 → u ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON → LATIN SMALL LETTER U\t# →υ→→ʋ→\n057D ;\t0075 ;\tMA\t# ( ս → u ) ARMENIAN SMALL LETTER SEH → LATIN SMALL LETTER U\t# \n104F6 ;\t0075 ;\tMA\t# ( 𐓶 → u ) OSAGE SMALL LETTER U → LATIN SMALL LETTER U\t# →ᴜ→\n118D8 ;\t0075 ;\tMA\t# ( 𑣘 → u ) WARANG CITI SMALL LETTER PU → LATIN SMALL LETTER U\t# →υ→→ʋ→\n\n222A ;\t0055 ;\tMA\t#* ( ∪ → U ) UNION → LATIN CAPITAL LETTER U\t# →ᑌ→\n22C3 ;\t0055 ;\tMA\t#* ( ⋃ → U ) N-ARY UNION → LATIN CAPITAL LETTER U\t# →∪→→ᑌ→\n1CCEA ;\t0055 ;\tMA\t#* ( 𜳪 → U ) OUTLINED LATIN CAPITAL LETTER U → LATIN CAPITAL LETTER U\t# \n1D414 ;\t0055 ;\tMA\t# ( 𝐔 → U ) MATHEMATICAL BOLD CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D448 ;\t0055 ;\tMA\t# ( 𝑈 → U ) MATHEMATICAL ITALIC CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D47C ;\t0055 ;\tMA\t# ( 𝑼 → U ) MATHEMATICAL BOLD ITALIC CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D4B0 ;\t0055 ;\tMA\t# ( 𝒰 → U ) MATHEMATICAL SCRIPT CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D4E4 ;\t0055 ;\tMA\t# ( 𝓤 → U ) MATHEMATICAL BOLD SCRIPT CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D518 ;\t0055 ;\tMA\t# ( 𝔘 → U ) MATHEMATICAL FRAKTUR CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D54C ;\t0055 ;\tMA\t# ( 𝕌 → U ) MATHEMATICAL DOUBLE-STRUCK CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D580 ;\t0055 ;\tMA\t# ( 𝖀 → U ) MATHEMATICAL BOLD FRAKTUR CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D5B4 ;\t0055 ;\tMA\t# ( 𝖴 → U ) MATHEMATICAL SANS-SERIF CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D5E8 ;\t0055 ;\tMA\t# ( 𝗨 → U ) MATHEMATICAL SANS-SERIF BOLD CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D61C ;\t0055 ;\tMA\t# ( 𝘜 → U ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D650 ;\t0055 ;\tMA\t# ( 𝙐 → U ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U → LATIN CAPITAL LETTER U\t# \n1D684 ;\t0055 ;\tMA\t# ( 𝚄 → U ) MATHEMATICAL MONOSPACE CAPITAL U → LATIN CAPITAL LETTER U\t# \n054D ;\t0055 ;\tMA\t# ( Ս → U ) ARMENIAN CAPITAL LETTER SEH → LATIN CAPITAL LETTER U\t# \n1200 ;\t0055 ;\tMA\t# ( ሀ → U ) ETHIOPIC SYLLABLE HA → LATIN CAPITAL LETTER U\t# →Ս→\n104CE ;\t0055 ;\tMA\t# ( 𐓎 → U ) OSAGE CAPITAL LETTER U → LATIN CAPITAL LETTER U\t# \n144C ;\t0055 ;\tMA\t# ( ᑌ → U ) CANADIAN SYLLABICS TE → LATIN CAPITAL LETTER U\t# \nA4F4 ;\t0055 ;\tMA\t# ( ꓴ → U ) LISU LETTER U → LATIN CAPITAL LETTER U\t# \n16F42 ;\t0055 ;\tMA\t# ( 𖽂 → U ) MIAO LETTER WA → LATIN CAPITAL LETTER U\t# \n118B8 ;\t0055 ;\tMA\t# ( 𑢸 → U ) WARANG CITI CAPITAL LETTER PU → LATIN CAPITAL LETTER U\t# \n\n01D4 ;\t016D ;\tMA\t# ( ǔ → ŭ ) LATIN SMALL LETTER U WITH CARON → LATIN SMALL LETTER U WITH BREVE\t# \n\n01D3 ;\t016C ;\tMA\t# ( Ǔ → Ŭ ) LATIN CAPITAL LETTER U WITH CARON → LATIN CAPITAL LETTER U WITH BREVE\t# \n\n045F ;\t0075 0329 ;\tMA\t# ( џ → u̩ ) CYRILLIC SMALL LETTER DZHE → LATIN SMALL LETTER U, COMBINING VERTICAL LINE BELOW\t# \n\n1D7E ;\t0075 0335 ;\tMA\t# ( ᵾ → u̵ ) LATIN SMALL CAPITAL LETTER U WITH STROKE → LATIN SMALL LETTER U, COMBINING SHORT STROKE OVERLAY\t# →ᴜ̵→\nAB9C ;\t0075 0335 ;\tMA\t# ( ꮜ → u̵ ) CHEROKEE SMALL LETTER SA → LATIN SMALL LETTER U, COMBINING SHORT STROKE OVERLAY\t# →ᴜ̵→\n\n0244 ;\t0055 0335 ;\tMA\t# ( Ʉ → U̵ ) LATIN CAPITAL LETTER U BAR → LATIN CAPITAL LETTER U, COMBINING SHORT STROKE OVERLAY\t# →U̶→\n13CC ;\t0055 0335 ;\tMA\t# ( Ꮜ → U̵ ) CHEROKEE LETTER SA → LATIN CAPITAL LETTER U, COMBINING SHORT STROKE OVERLAY\t# →Ʉ→→U̶→\n\n1458 ;\t0055 00B7 ;\tMA\t# ( ᑘ → U· ) CANADIAN SYLLABICS WEST-CREE TWE → LATIN CAPITAL LETTER U, MIDDLE DOT\t# →ᑌᐧ→→ᑌ·→\n\n1467 ;\t0055 0027 ;\tMA\t# ( ᑧ → U' ) CANADIAN SYLLABICS TTE → LATIN CAPITAL LETTER U, APOSTROPHE\t# →ᑌᑊ→→ᑌ'→\n\n1D6B ;\t0075 0065 ;\tMA\t# ( ᵫ → ue ) LATIN SMALL LETTER UE → LATIN SMALL LETTER U, LATIN SMALL LETTER E\t# \n\nAB63 ;\t0075 006F ;\tMA\t# ( ꭣ → uo ) LATIN SMALL LETTER UO → LATIN SMALL LETTER U, LATIN SMALL LETTER O\t# \n\n1E43 ;\tAB51 ;\tMA\t# ( ṃ → ꭑ ) LATIN SMALL LETTER M WITH DOT BELOW → LATIN SMALL LETTER TURNED UI\t# \n\n057A ;\t0270 ;\tMA\t# ( պ → ɰ ) ARMENIAN SMALL LETTER PEH → LATIN SMALL LETTER TURNED M WITH LONG LEG\t# \n1223 ;\t0270 ;\tMA\t# ( ሣ → ɰ ) ETHIOPIC SYLLABLE SZAA → LATIN SMALL LETTER TURNED M WITH LONG LEG\t# →պ→\n\n2127 ;\t01B1 ;\tMA\t#* ( ℧ → Ʊ ) INVERTED OHM SIGN → LATIN CAPITAL LETTER UPSILON\t# \n162E ;\t01B1 ;\tMA\t# ( ᘮ → Ʊ ) CANADIAN SYLLABICS CARRIER LHU → LATIN CAPITAL LETTER UPSILON\t# →℧→\n1634 ;\t01B1 ;\tMA\t# ( ᘴ → Ʊ ) CANADIAN SYLLABICS CARRIER TLHU → LATIN CAPITAL LETTER UPSILON\t# →ᘮ→→℧→\n\n1D7F ;\t028A 0335 ;\tMA\t# ( ᵿ → ʊ̵ ) LATIN SMALL LETTER UPSILON WITH STROKE → LATIN SMALL LETTER UPSILON, COMBINING SHORT STROKE OVERLAY\t# \n\n2228 ;\t0076 ;\tMA\t#* ( ∨ → v ) LOGICAL OR → LATIN SMALL LETTER V\t# \n22C1 ;\t0076 ;\tMA\t#* ( ⋁ → v ) N-ARY LOGICAL OR → LATIN SMALL LETTER V\t# →∨→\nFF56 ;\t0076 ;\tMA\t# ( ｖ → v ) FULLWIDTH LATIN SMALL LETTER V → LATIN SMALL LETTER V\t# →ν→\n2174 ;\t0076 ;\tMA\t# ( ⅴ → v ) SMALL ROMAN NUMERAL FIVE → LATIN SMALL LETTER V\t# \n1D42F ;\t0076 ;\tMA\t# ( 𝐯 → v ) MATHEMATICAL BOLD SMALL V → LATIN SMALL LETTER V\t# \n1D463 ;\t0076 ;\tMA\t# ( 𝑣 → v ) MATHEMATICAL ITALIC SMALL V → LATIN SMALL LETTER V\t# \n1D497 ;\t0076 ;\tMA\t# ( 𝒗 → v ) MATHEMATICAL BOLD ITALIC SMALL V → LATIN SMALL LETTER V\t# \n1D4CB ;\t0076 ;\tMA\t# ( 𝓋 → v ) MATHEMATICAL SCRIPT SMALL V → LATIN SMALL LETTER V\t# \n1D4FF ;\t0076 ;\tMA\t# ( 𝓿 → v ) MATHEMATICAL BOLD SCRIPT SMALL V → LATIN SMALL LETTER V\t# \n1D533 ;\t0076 ;\tMA\t# ( 𝔳 → v ) MATHEMATICAL FRAKTUR SMALL V → LATIN SMALL LETTER V\t# \n1D567 ;\t0076 ;\tMA\t# ( 𝕧 → v ) MATHEMATICAL DOUBLE-STRUCK SMALL V → LATIN SMALL LETTER V\t# \n1D59B ;\t0076 ;\tMA\t# ( 𝖛 → v ) MATHEMATICAL BOLD FRAKTUR SMALL V → LATIN SMALL LETTER V\t# \n1D5CF ;\t0076 ;\tMA\t# ( 𝗏 → v ) MATHEMATICAL SANS-SERIF SMALL V → LATIN SMALL LETTER V\t# \n1D603 ;\t0076 ;\tMA\t# ( 𝘃 → v ) MATHEMATICAL SANS-SERIF BOLD SMALL V → LATIN SMALL LETTER V\t# \n1D637 ;\t0076 ;\tMA\t# ( 𝘷 → v ) MATHEMATICAL SANS-SERIF ITALIC SMALL V → LATIN SMALL LETTER V\t# \n1D66B ;\t0076 ;\tMA\t# ( 𝙫 → v ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V → LATIN SMALL LETTER V\t# \n1D69F ;\t0076 ;\tMA\t# ( 𝚟 → v ) MATHEMATICAL MONOSPACE SMALL V → LATIN SMALL LETTER V\t# \n1D20 ;\t0076 ;\tMA\t# ( ᴠ → v ) LATIN LETTER SMALL CAPITAL V → LATIN SMALL LETTER V\t# \n03BD ;\t0076 ;\tMA\t# ( ν → v ) GREEK SMALL LETTER NU → LATIN SMALL LETTER V\t# \n1D6CE ;\t0076 ;\tMA\t# ( 𝛎 → v ) MATHEMATICAL BOLD SMALL NU → LATIN SMALL LETTER V\t# →ν→\n1D708 ;\t0076 ;\tMA\t# ( 𝜈 → v ) MATHEMATICAL ITALIC SMALL NU → LATIN SMALL LETTER V\t# →ν→\n1D742 ;\t0076 ;\tMA\t# ( 𝝂 → v ) MATHEMATICAL BOLD ITALIC SMALL NU → LATIN SMALL LETTER V\t# →ν→\n1D77C ;\t0076 ;\tMA\t# ( 𝝼 → v ) MATHEMATICAL SANS-SERIF BOLD SMALL NU → LATIN SMALL LETTER V\t# →ν→\n1D7B6 ;\t0076 ;\tMA\t# ( 𝞶 → v ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU → LATIN SMALL LETTER V\t# →ν→\n0475 ;\t0076 ;\tMA\t# ( ѵ → v ) CYRILLIC SMALL LETTER IZHITSA → LATIN SMALL LETTER V\t# \n05D8 ;\t0076 ;\tMA\t# ( ‎ט‎ → v ) HEBREW LETTER TET → LATIN SMALL LETTER V\t# \n11706 ;\t0076 ;\tMA\t# ( 𑜆 → v ) AHOM LETTER PA → LATIN SMALL LETTER V\t# \nABA9 ;\t0076 ;\tMA\t# ( ꮩ → v ) CHEROKEE SMALL LETTER DO → LATIN SMALL LETTER V\t# →ᴠ→\n118C0 ;\t0076 ;\tMA\t# ( 𑣀 → v ) WARANG CITI SMALL LETTER NGAA → LATIN SMALL LETTER V\t# \n\n1D20D ;\t0056 ;\tMA\t#* ( 𝈍 → V ) GREEK VOCAL NOTATION SYMBOL-14 → LATIN CAPITAL LETTER V\t# \n0667 ;\t0056 ;\tMA\t# ( ‎٧‎ → V ) ARABIC-INDIC DIGIT SEVEN → LATIN CAPITAL LETTER V\t# \n06F7 ;\t0056 ;\tMA\t# ( ۷ → V ) EXTENDED ARABIC-INDIC DIGIT SEVEN → LATIN CAPITAL LETTER V\t# →‎٧‎→\n2164 ;\t0056 ;\tMA\t# ( Ⅴ → V ) ROMAN NUMERAL FIVE → LATIN CAPITAL LETTER V\t# \n1CCEB ;\t0056 ;\tMA\t#* ( 𜳫 → V ) OUTLINED LATIN CAPITAL LETTER V → LATIN CAPITAL LETTER V\t# \n1D415 ;\t0056 ;\tMA\t# ( 𝐕 → V ) MATHEMATICAL BOLD CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D449 ;\t0056 ;\tMA\t# ( 𝑉 → V ) MATHEMATICAL ITALIC CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D47D ;\t0056 ;\tMA\t# ( 𝑽 → V ) MATHEMATICAL BOLD ITALIC CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D4B1 ;\t0056 ;\tMA\t# ( 𝒱 → V ) MATHEMATICAL SCRIPT CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D4E5 ;\t0056 ;\tMA\t# ( 𝓥 → V ) MATHEMATICAL BOLD SCRIPT CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D519 ;\t0056 ;\tMA\t# ( 𝔙 → V ) MATHEMATICAL FRAKTUR CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D54D ;\t0056 ;\tMA\t# ( 𝕍 → V ) MATHEMATICAL DOUBLE-STRUCK CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D581 ;\t0056 ;\tMA\t# ( 𝖁 → V ) MATHEMATICAL BOLD FRAKTUR CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D5B5 ;\t0056 ;\tMA\t# ( 𝖵 → V ) MATHEMATICAL SANS-SERIF CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D5E9 ;\t0056 ;\tMA\t# ( 𝗩 → V ) MATHEMATICAL SANS-SERIF BOLD CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D61D ;\t0056 ;\tMA\t# ( 𝘝 → V ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D651 ;\t0056 ;\tMA\t# ( 𝙑 → V ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V → LATIN CAPITAL LETTER V\t# \n1D685 ;\t0056 ;\tMA\t# ( 𝚅 → V ) MATHEMATICAL MONOSPACE CAPITAL V → LATIN CAPITAL LETTER V\t# \n0474 ;\t0056 ;\tMA\t# ( Ѵ → V ) CYRILLIC CAPITAL LETTER IZHITSA → LATIN CAPITAL LETTER V\t# \n2D38 ;\t0056 ;\tMA\t# ( ⴸ → V ) TIFINAGH LETTER YADH → LATIN CAPITAL LETTER V\t# \n13D9 ;\t0056 ;\tMA\t# ( Ꮩ → V ) CHEROKEE LETTER DO → LATIN CAPITAL LETTER V\t# \n142F ;\t0056 ;\tMA\t# ( ᐯ → V ) CANADIAN SYLLABICS PE → LATIN CAPITAL LETTER V\t# \nA6DF ;\t0056 ;\tMA\t# ( ꛟ → V ) BAMUM LETTER KO → LATIN CAPITAL LETTER V\t# \nA4E6 ;\t0056 ;\tMA\t# ( ꓦ → V ) LISU LETTER HA → LATIN CAPITAL LETTER V\t# \n16F08 ;\t0056 ;\tMA\t# ( 𖼈 → V ) MIAO LETTER VA → LATIN CAPITAL LETTER V\t# \n118A0 ;\t0056 ;\tMA\t# ( 𑢠 → V ) WARANG CITI CAPITAL LETTER NGAA → LATIN CAPITAL LETTER V\t# \n1051D ;\t0056 ;\tMA\t# ( 𐔝 → V ) ELBASAN LETTER TE → LATIN CAPITAL LETTER V\t# \n\n10197 ;\t0056 0335 ;\tMA\t#* ( 𐆗 → V̵ ) ROMAN QUINARIUS SIGN → LATIN CAPITAL LETTER V, COMBINING SHORT STROKE OVERLAY\t# →V̶→\n\n143B ;\t0056 00B7 ;\tMA\t# ( ᐻ → V· ) CANADIAN SYLLABICS WEST-CREE PWE → LATIN CAPITAL LETTER V, MIDDLE DOT\t# →ᐯᐧ→\n\n1F76C ;\t0056 0042 ;\tMA\t#* ( 🝬 → VB ) ALCHEMICAL SYMBOL FOR BATH OF VAPOURS → LATIN CAPITAL LETTER V, LATIN CAPITAL LETTER B\t# \n\n2175 ;\t0076 0069 ;\tMA\t# ( ⅵ → vi ) SMALL ROMAN NUMERAL SIX → LATIN SMALL LETTER V, LATIN SMALL LETTER I\t# \n\n2176 ;\t0076 0069 0069 ;\tMA\t# ( ⅶ → vii ) SMALL ROMAN NUMERAL SEVEN → LATIN SMALL LETTER V, LATIN SMALL LETTER I, LATIN SMALL LETTER I\t# \n\n2177 ;\t0076 0069 0069 0069 ;\tMA\t# ( ⅷ → viii ) SMALL ROMAN NUMERAL EIGHT → LATIN SMALL LETTER V, LATIN SMALL LETTER I, LATIN SMALL LETTER I, LATIN SMALL LETTER I\t# \n\n2165 ;\t0056 006C ;\tMA\t# ( Ⅵ → Vl ) ROMAN NUMERAL SIX → LATIN CAPITAL LETTER V, LATIN SMALL LETTER L\t# →VI→\n\n2166 ;\t0056 006C 006C ;\tMA\t# ( Ⅶ → Vll ) ROMAN NUMERAL SEVEN → LATIN CAPITAL LETTER V, LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →VII→\n\n2167 ;\t0056 006C 006C 006C ;\tMA\t# ( Ⅷ → Vlll ) ROMAN NUMERAL EIGHT → LATIN CAPITAL LETTER V, LATIN SMALL LETTER L, LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →VIII→\n\n1F708 ;\t0056 1DE4 ;\tMA\t#* ( 🜈 → Vᷤ ) ALCHEMICAL SYMBOL FOR AQUA VITAE → LATIN CAPITAL LETTER V, COMBINING LATIN SMALL LETTER S\t# \n\n1D27 ;\t028C ;\tMA\t# ( ᴧ → ʌ ) GREEK LETTER SMALL CAPITAL LAMDA → LATIN SMALL LETTER TURNED V\t# \n2C97 ;\t028C ;\tMA\t# ( ⲗ → ʌ ) COPTIC SMALL LETTER LAULA → LATIN SMALL LETTER TURNED V\t# \n104D8 ;\t028C ;\tMA\t# ( 𐓘 → ʌ ) OSAGE SMALL LETTER A → LATIN SMALL LETTER TURNED V\t# \n\n0668 ;\t0245 ;\tMA\t# ( ‎٨‎ → Ʌ ) ARABIC-INDIC DIGIT EIGHT → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n06F8 ;\t0245 ;\tMA\t# ( ۸ → Ʌ ) EXTENDED ARABIC-INDIC DIGIT EIGHT → LATIN CAPITAL LETTER TURNED V\t# →‎٨‎→→Λ→\nA7DA ;\t0245 ;\tMA\t# ( Ꟛ → Ʌ ) LATIN CAPITAL LETTER LAMBDA → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n039B ;\t0245 ;\tMA\t# ( Λ → Ʌ ) GREEK CAPITAL LETTER LAMDA → LATIN CAPITAL LETTER TURNED V\t# \n1D6B2 ;\t0245 ;\tMA\t# ( 𝚲 → Ʌ ) MATHEMATICAL BOLD CAPITAL LAMDA → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n1D6EC ;\t0245 ;\tMA\t# ( 𝛬 → Ʌ ) MATHEMATICAL ITALIC CAPITAL LAMDA → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n1D726 ;\t0245 ;\tMA\t# ( 𝜦 → Ʌ ) MATHEMATICAL BOLD ITALIC CAPITAL LAMDA → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n1D760 ;\t0245 ;\tMA\t# ( 𝝠 → Ʌ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n1D79A ;\t0245 ;\tMA\t# ( 𝞚 → Ʌ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n041B ;\t0245 ;\tMA\t# ( Л → Ʌ ) CYRILLIC CAPITAL LETTER EL → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n2D37 ;\t0245 ;\tMA\t# ( ⴷ → Ʌ ) TIFINAGH LETTER YAD → LATIN CAPITAL LETTER TURNED V\t# \n104B0 ;\t0245 ;\tMA\t# ( 𐒰 → Ʌ ) OSAGE CAPITAL LETTER A → LATIN CAPITAL LETTER TURNED V\t# \n1431 ;\t0245 ;\tMA\t# ( ᐱ → Ʌ ) CANADIAN SYLLABICS PI → LATIN CAPITAL LETTER TURNED V\t# \nA6CE ;\t0245 ;\tMA\t# ( ꛎ → Ʌ ) BAMUM LETTER MI → LATIN CAPITAL LETTER TURNED V\t# →Λ→\nA4E5 ;\t0245 ;\tMA\t# ( ꓥ → Ʌ ) LISU LETTER NGA → LATIN CAPITAL LETTER TURNED V\t# \n16F3D ;\t0245 ;\tMA\t# ( 𖼽 → Ʌ ) MIAO LETTER ZZA → LATIN CAPITAL LETTER TURNED V\t# \n1028D ;\t0245 ;\tMA\t# ( 𐊍 → Ʌ ) LYCIAN LETTER L → LATIN CAPITAL LETTER TURNED V\t# →Λ→\n\nA7DC ;\t0245 0338 ;\tMA\t# ( Ƛ → Ʌ̸ ) LATIN CAPITAL LETTER LAMBDA WITH STROKE → LATIN CAPITAL LETTER TURNED V, COMBINING LONG SOLIDUS OVERLAY\t# →Λ̷→\n\n04C5 ;\t0245 0326 ;\tMA\t# ( Ӆ → Ʌ̦ ) CYRILLIC CAPITAL LETTER EL WITH TAIL → LATIN CAPITAL LETTER TURNED V, COMBINING COMMA BELOW\t# →Л̡→\n\n143D ;\t0245 00B7 ;\tMA\t# ( ᐽ → Ʌ· ) CANADIAN SYLLABICS WEST-CREE PWI → LATIN CAPITAL LETTER TURNED V, MIDDLE DOT\t# →ᐱᐧ→→ᐱ·→\n\n026F ;\t0077 ;\tMA\t# ( ɯ → w ) LATIN SMALL LETTER TURNED M → LATIN SMALL LETTER W\t# \n1D430 ;\t0077 ;\tMA\t# ( 𝐰 → w ) MATHEMATICAL BOLD SMALL W → LATIN SMALL LETTER W\t# \n1D464 ;\t0077 ;\tMA\t# ( 𝑤 → w ) MATHEMATICAL ITALIC SMALL W → LATIN SMALL LETTER W\t# \n1D498 ;\t0077 ;\tMA\t# ( 𝒘 → w ) MATHEMATICAL BOLD ITALIC SMALL W → LATIN SMALL LETTER W\t# \n1D4CC ;\t0077 ;\tMA\t# ( 𝓌 → w ) MATHEMATICAL SCRIPT SMALL W → LATIN SMALL LETTER W\t# \n1D500 ;\t0077 ;\tMA\t# ( 𝔀 → w ) MATHEMATICAL BOLD SCRIPT SMALL W → LATIN SMALL LETTER W\t# \n1D534 ;\t0077 ;\tMA\t# ( 𝔴 → w ) MATHEMATICAL FRAKTUR SMALL W → LATIN SMALL LETTER W\t# \n1D568 ;\t0077 ;\tMA\t# ( 𝕨 → w ) MATHEMATICAL DOUBLE-STRUCK SMALL W → LATIN SMALL LETTER W\t# \n1D59C ;\t0077 ;\tMA\t# ( 𝖜 → w ) MATHEMATICAL BOLD FRAKTUR SMALL W → LATIN SMALL LETTER W\t# \n1D5D0 ;\t0077 ;\tMA\t# ( 𝗐 → w ) MATHEMATICAL SANS-SERIF SMALL W → LATIN SMALL LETTER W\t# \n1D604 ;\t0077 ;\tMA\t# ( 𝘄 → w ) MATHEMATICAL SANS-SERIF BOLD SMALL W → LATIN SMALL LETTER W\t# \n1D638 ;\t0077 ;\tMA\t# ( 𝘸 → w ) MATHEMATICAL SANS-SERIF ITALIC SMALL W → LATIN SMALL LETTER W\t# \n1D66C ;\t0077 ;\tMA\t# ( 𝙬 → w ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W → LATIN SMALL LETTER W\t# \n1D6A0 ;\t0077 ;\tMA\t# ( 𝚠 → w ) MATHEMATICAL MONOSPACE SMALL W → LATIN SMALL LETTER W\t# \n1D21 ;\t0077 ;\tMA\t# ( ᴡ → w ) LATIN LETTER SMALL CAPITAL W → LATIN SMALL LETTER W\t# \n2CBD ;\t0077 ;\tMA\t# ( ⲽ → w ) COPTIC SMALL LETTER CRYPTOGRAMMIC NI → LATIN SMALL LETTER W\t# →ш→\n0461 ;\t0077 ;\tMA\t# ( ѡ → w ) CYRILLIC SMALL LETTER OMEGA → LATIN SMALL LETTER W\t# \n0448 ;\t0077 ;\tMA\t# ( ш → w ) CYRILLIC SMALL LETTER SHA → LATIN SMALL LETTER W\t# \n051D ;\t0077 ;\tMA\t# ( ԝ → w ) CYRILLIC SMALL LETTER WE → LATIN SMALL LETTER W\t# \n0561 ;\t0077 ;\tMA\t# ( ա → w ) ARMENIAN SMALL LETTER AYB → LATIN SMALL LETTER W\t# →ɯ→\n1170A ;\t0077 ;\tMA\t# ( 𑜊 → w ) AHOM LETTER JA → LATIN SMALL LETTER W\t# \n1170E ;\t0077 ;\tMA\t# ( 𑜎 → w ) AHOM LETTER LA → LATIN SMALL LETTER W\t# \n1170F ;\t0077 ;\tMA\t# ( 𑜏 → w ) AHOM LETTER SA → LATIN SMALL LETTER W\t# \nAB83 ;\t0077 ;\tMA\t# ( ꮃ → w ) CHEROKEE SMALL LETTER LA → LATIN SMALL LETTER W\t# →ᴡ→\n\n118E6 ;\t0057 ;\tMA\t# ( 𑣦 → W ) WARANG CITI DIGIT SIX → LATIN CAPITAL LETTER W\t# \n118EF ;\t0057 ;\tMA\t#* ( 𑣯 → W ) WARANG CITI NUMBER SIXTY → LATIN CAPITAL LETTER W\t# \n1CCEC ;\t0057 ;\tMA\t#* ( 𜳬 → W ) OUTLINED LATIN CAPITAL LETTER W → LATIN CAPITAL LETTER W\t# \n1D416 ;\t0057 ;\tMA\t# ( 𝐖 → W ) MATHEMATICAL BOLD CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D44A ;\t0057 ;\tMA\t# ( 𝑊 → W ) MATHEMATICAL ITALIC CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D47E ;\t0057 ;\tMA\t# ( 𝑾 → W ) MATHEMATICAL BOLD ITALIC CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D4B2 ;\t0057 ;\tMA\t# ( 𝒲 → W ) MATHEMATICAL SCRIPT CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D4E6 ;\t0057 ;\tMA\t# ( 𝓦 → W ) MATHEMATICAL BOLD SCRIPT CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D51A ;\t0057 ;\tMA\t# ( 𝔚 → W ) MATHEMATICAL FRAKTUR CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D54E ;\t0057 ;\tMA\t# ( 𝕎 → W ) MATHEMATICAL DOUBLE-STRUCK CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D582 ;\t0057 ;\tMA\t# ( 𝖂 → W ) MATHEMATICAL BOLD FRAKTUR CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D5B6 ;\t0057 ;\tMA\t# ( 𝖶 → W ) MATHEMATICAL SANS-SERIF CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D5EA ;\t0057 ;\tMA\t# ( 𝗪 → W ) MATHEMATICAL SANS-SERIF BOLD CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D61E ;\t0057 ;\tMA\t# ( 𝘞 → W ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D652 ;\t0057 ;\tMA\t# ( 𝙒 → W ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W → LATIN CAPITAL LETTER W\t# \n1D686 ;\t0057 ;\tMA\t# ( 𝚆 → W ) MATHEMATICAL MONOSPACE CAPITAL W → LATIN CAPITAL LETTER W\t# \n051C ;\t0057 ;\tMA\t# ( Ԝ → W ) CYRILLIC CAPITAL LETTER WE → LATIN CAPITAL LETTER W\t# \n13B3 ;\t0057 ;\tMA\t# ( Ꮃ → W ) CHEROKEE LETTER LA → LATIN CAPITAL LETTER W\t# \n13D4 ;\t0057 ;\tMA\t# ( Ꮤ → W ) CHEROKEE LETTER TA → LATIN CAPITAL LETTER W\t# \nA4EA ;\t0057 ;\tMA\t# ( ꓪ → W ) LISU LETTER WA → LATIN CAPITAL LETTER W\t# \n\n047D ;\t0077 0486 0487 ;\tMA\t# ( ѽ → w҆҇ ) CYRILLIC SMALL LETTER OMEGA WITH TITLO → LATIN SMALL LETTER W, COMBINING CYRILLIC PSILI PNEUMATA, COMBINING CYRILLIC POKRYTIE\t# →ѡ҆҇→\n\n114C5 ;\t0077 0307 ;\tMA\t# ( 𑓅 → ẇ ) TIRHUTA GVANG → LATIN SMALL LETTER W, COMBINING DOT ABOVE\t# \n\n20A9 ;\t0057 0335 ;\tMA\t#* ( ₩ → W̵ ) WON SIGN → LATIN CAPITAL LETTER W, COMBINING SHORT STROKE OVERLAY\t# \n\nA761 ;\t0077 0326 ;\tMA\t# ( ꝡ → w̦ ) LATIN SMALL LETTER VY → LATIN SMALL LETTER W, COMBINING COMMA BELOW\t# →w̡→\n\n1D0D ;\t028D ;\tMA\t# ( ᴍ → ʍ ) LATIN LETTER SMALL CAPITAL M → LATIN SMALL LETTER TURNED W\t# →м→\n2C99 ;\t028D ;\tMA\t# ( ⲙ → ʍ ) COPTIC SMALL LETTER MI → LATIN SMALL LETTER TURNED W\t# →ᴍ→→м→\n043C ;\t028D ;\tMA\t# ( м → ʍ ) CYRILLIC SMALL LETTER EM → LATIN SMALL LETTER TURNED W\t# \nAB87 ;\t028D ;\tMA\t# ( ꮇ → ʍ ) CHEROKEE SMALL LETTER LU → LATIN SMALL LETTER TURNED W\t# →ᴍ→→м→\n\n04CE ;\t028D 0326 ;\tMA\t# ( ӎ → ʍ̦ ) CYRILLIC SMALL LETTER EM WITH TAIL → LATIN SMALL LETTER TURNED W, COMBINING COMMA BELOW\t# →м̡→\n\n166E ;\t0078 ;\tMA\t#* ( ᙮ → x ) CANADIAN SYLLABICS FULL STOP → LATIN SMALL LETTER X\t# \n00D7 ;\t0078 ;\tMA\t#* ( × → x ) MULTIPLICATION SIGN → LATIN SMALL LETTER X\t# \n292B ;\t0078 ;\tMA\t#* ( ⤫ → x ) RISING DIAGONAL CROSSING FALLING DIAGONAL → LATIN SMALL LETTER X\t# \n292C ;\t0078 ;\tMA\t#* ( ⤬ → x ) FALLING DIAGONAL CROSSING RISING DIAGONAL → LATIN SMALL LETTER X\t# \n2A2F ;\t0078 ;\tMA\t#* ( ⨯ → x ) VECTOR OR CROSS PRODUCT → LATIN SMALL LETTER X\t# →×→\nFF58 ;\t0078 ;\tMA\t# ( ｘ → x ) FULLWIDTH LATIN SMALL LETTER X → LATIN SMALL LETTER X\t# →х→\n2179 ;\t0078 ;\tMA\t# ( ⅹ → x ) SMALL ROMAN NUMERAL TEN → LATIN SMALL LETTER X\t# \n1D431 ;\t0078 ;\tMA\t# ( 𝐱 → x ) MATHEMATICAL BOLD SMALL X → LATIN SMALL LETTER X\t# \n1D465 ;\t0078 ;\tMA\t# ( 𝑥 → x ) MATHEMATICAL ITALIC SMALL X → LATIN SMALL LETTER X\t# \n1D499 ;\t0078 ;\tMA\t# ( 𝒙 → x ) MATHEMATICAL BOLD ITALIC SMALL X → LATIN SMALL LETTER X\t# \n1D4CD ;\t0078 ;\tMA\t# ( 𝓍 → x ) MATHEMATICAL SCRIPT SMALL X → LATIN SMALL LETTER X\t# \n1D501 ;\t0078 ;\tMA\t# ( 𝔁 → x ) MATHEMATICAL BOLD SCRIPT SMALL X → LATIN SMALL LETTER X\t# \n1D535 ;\t0078 ;\tMA\t# ( 𝔵 → x ) MATHEMATICAL FRAKTUR SMALL X → LATIN SMALL LETTER X\t# \n1D569 ;\t0078 ;\tMA\t# ( 𝕩 → x ) MATHEMATICAL DOUBLE-STRUCK SMALL X → LATIN SMALL LETTER X\t# \n1D59D ;\t0078 ;\tMA\t# ( 𝖝 → x ) MATHEMATICAL BOLD FRAKTUR SMALL X → LATIN SMALL LETTER X\t# \n1D5D1 ;\t0078 ;\tMA\t# ( 𝗑 → x ) MATHEMATICAL SANS-SERIF SMALL X → LATIN SMALL LETTER X\t# \n1D605 ;\t0078 ;\tMA\t# ( 𝘅 → x ) MATHEMATICAL SANS-SERIF BOLD SMALL X → LATIN SMALL LETTER X\t# \n1D639 ;\t0078 ;\tMA\t# ( 𝘹 → x ) MATHEMATICAL SANS-SERIF ITALIC SMALL X → LATIN SMALL LETTER X\t# \n1D66D ;\t0078 ;\tMA\t# ( 𝙭 → x ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X → LATIN SMALL LETTER X\t# \n1D6A1 ;\t0078 ;\tMA\t# ( 𝚡 → x ) MATHEMATICAL MONOSPACE SMALL X → LATIN SMALL LETTER X\t# \n0445 ;\t0078 ;\tMA\t# ( х → x ) CYRILLIC SMALL LETTER HA → LATIN SMALL LETTER X\t# \n1541 ;\t0078 ;\tMA\t# ( ᕁ → x ) CANADIAN SYLLABICS SAYISI YI → LATIN SMALL LETTER X\t# →᙮→\n157D ;\t0078 ;\tMA\t# ( ᕽ → x ) CANADIAN SYLLABICS HK → LATIN SMALL LETTER X\t# →ᕁ→→᙮→\n\n2DEF ;\t036F ;\tMA\t# ( ⷯ → ͯ ) COMBINING CYRILLIC LETTER HA → COMBINING LATIN SMALL LETTER X\t# \n\n166D ;\t0058 ;\tMA\t#* ( ᙭ → X ) CANADIAN SYLLABICS CHI SIGN → LATIN CAPITAL LETTER X\t# \n2573 ;\t0058 ;\tMA\t#* ( ╳ → X ) BOX DRAWINGS LIGHT DIAGONAL CROSS → LATIN CAPITAL LETTER X\t# \n10322 ;\t0058 ;\tMA\t#* ( 𐌢 → X ) OLD ITALIC NUMERAL TEN → LATIN CAPITAL LETTER X\t# →𐌗→\n118EC ;\t0058 ;\tMA\t#* ( 𑣬 → X ) WARANG CITI NUMBER THIRTY → LATIN CAPITAL LETTER X\t# \nFF38 ;\t0058 ;\tMA\t# ( Ｘ → X ) FULLWIDTH LATIN CAPITAL LETTER X → LATIN CAPITAL LETTER X\t# →Х→\n2169 ;\t0058 ;\tMA\t# ( Ⅹ → X ) ROMAN NUMERAL TEN → LATIN CAPITAL LETTER X\t# \n1CCED ;\t0058 ;\tMA\t#* ( 𜳭 → X ) OUTLINED LATIN CAPITAL LETTER X → LATIN CAPITAL LETTER X\t# \n1D417 ;\t0058 ;\tMA\t# ( 𝐗 → X ) MATHEMATICAL BOLD CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D44B ;\t0058 ;\tMA\t# ( 𝑋 → X ) MATHEMATICAL ITALIC CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D47F ;\t0058 ;\tMA\t# ( 𝑿 → X ) MATHEMATICAL BOLD ITALIC CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D4B3 ;\t0058 ;\tMA\t# ( 𝒳 → X ) MATHEMATICAL SCRIPT CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D4E7 ;\t0058 ;\tMA\t# ( 𝓧 → X ) MATHEMATICAL BOLD SCRIPT CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D51B ;\t0058 ;\tMA\t# ( 𝔛 → X ) MATHEMATICAL FRAKTUR CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D54F ;\t0058 ;\tMA\t# ( 𝕏 → X ) MATHEMATICAL DOUBLE-STRUCK CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D583 ;\t0058 ;\tMA\t# ( 𝖃 → X ) MATHEMATICAL BOLD FRAKTUR CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D5B7 ;\t0058 ;\tMA\t# ( 𝖷 → X ) MATHEMATICAL SANS-SERIF CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D5EB ;\t0058 ;\tMA\t# ( 𝗫 → X ) MATHEMATICAL SANS-SERIF BOLD CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D61F ;\t0058 ;\tMA\t# ( 𝘟 → X ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D653 ;\t0058 ;\tMA\t# ( 𝙓 → X ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X → LATIN CAPITAL LETTER X\t# \n1D687 ;\t0058 ;\tMA\t# ( 𝚇 → X ) MATHEMATICAL MONOSPACE CAPITAL X → LATIN CAPITAL LETTER X\t# \nA7B3 ;\t0058 ;\tMA\t# ( Ꭓ → X ) LATIN CAPITAL LETTER CHI → LATIN CAPITAL LETTER X\t# \n03A7 ;\t0058 ;\tMA\t# ( Χ → X ) GREEK CAPITAL LETTER CHI → LATIN CAPITAL LETTER X\t# \n1D6BE ;\t0058 ;\tMA\t# ( 𝚾 → X ) MATHEMATICAL BOLD CAPITAL CHI → LATIN CAPITAL LETTER X\t# →Χ→\n1D6F8 ;\t0058 ;\tMA\t# ( 𝛸 → X ) MATHEMATICAL ITALIC CAPITAL CHI → LATIN CAPITAL LETTER X\t# →Χ→\n1D732 ;\t0058 ;\tMA\t# ( 𝜲 → X ) MATHEMATICAL BOLD ITALIC CAPITAL CHI → LATIN CAPITAL LETTER X\t# →𝑿→\n1D76C ;\t0058 ;\tMA\t# ( 𝝬 → X ) MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI → LATIN CAPITAL LETTER X\t# →Χ→\n1D7A6 ;\t0058 ;\tMA\t# ( 𝞦 → X ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI → LATIN CAPITAL LETTER X\t# →Χ→\n2CAC ;\t0058 ;\tMA\t# ( Ⲭ → X ) COPTIC CAPITAL LETTER KHI → LATIN CAPITAL LETTER X\t# →Х→\n0425 ;\t0058 ;\tMA\t# ( Х → X ) CYRILLIC CAPITAL LETTER HA → LATIN CAPITAL LETTER X\t# \n2D5D ;\t0058 ;\tMA\t# ( ⵝ → X ) TIFINAGH LETTER YATH → LATIN CAPITAL LETTER X\t# \n16B7 ;\t0058 ;\tMA\t# ( ᚷ → X ) RUNIC LETTER GEBO GYFU G → LATIN CAPITAL LETTER X\t# \nA4EB ;\t0058 ;\tMA\t# ( ꓫ → X ) LISU LETTER SHA → LATIN CAPITAL LETTER X\t# \n10290 ;\t0058 ;\tMA\t# ( 𐊐 → X ) LYCIAN LETTER MM → LATIN CAPITAL LETTER X\t# \n102B4 ;\t0058 ;\tMA\t# ( 𐊴 → X ) CARIAN LETTER X → LATIN CAPITAL LETTER X\t# \n10317 ;\t0058 ;\tMA\t# ( 𐌗 → X ) OLD ITALIC LETTER EKS → LATIN CAPITAL LETTER X\t# \n10527 ;\t0058 ;\tMA\t# ( 𐔧 → X ) ELBASAN LETTER KHE → LATIN CAPITAL LETTER X\t# \n\n2A30 ;\t0078 0307 ;\tMA\t#* ( ⨰ → ẋ ) MULTIPLICATION SIGN WITH DOT ABOVE → LATIN SMALL LETTER X, COMBINING DOT ABOVE\t# →×̇→\n\n04B2 ;\t0058 0329 ;\tMA\t# ( Ҳ → X̩ ) CYRILLIC CAPITAL LETTER HA WITH DESCENDER → LATIN CAPITAL LETTER X, COMBINING VERTICAL LINE BELOW\t# →Х̩→\n\n10196 ;\t0058 0335 ;\tMA\t#* ( 𐆖 → X̵ ) ROMAN DENARIUS SIGN → LATIN CAPITAL LETTER X, COMBINING SHORT STROKE OVERLAY\t# →X̶→\n\n217A ;\t0078 0069 ;\tMA\t# ( ⅺ → xi ) SMALL ROMAN NUMERAL ELEVEN → LATIN SMALL LETTER X, LATIN SMALL LETTER I\t# \n\n217B ;\t0078 0069 0069 ;\tMA\t# ( ⅻ → xii ) SMALL ROMAN NUMERAL TWELVE → LATIN SMALL LETTER X, LATIN SMALL LETTER I, LATIN SMALL LETTER I\t# \n\n216A ;\t0058 006C ;\tMA\t# ( Ⅺ → Xl ) ROMAN NUMERAL ELEVEN → LATIN CAPITAL LETTER X, LATIN SMALL LETTER L\t# →XI→\n\n216B ;\t0058 006C 006C ;\tMA\t# ( Ⅻ → Xll ) ROMAN NUMERAL TWELVE → LATIN CAPITAL LETTER X, LATIN SMALL LETTER L, LATIN SMALL LETTER L\t# →XII→\n\n0263 ;\t0079 ;\tMA\t# ( ɣ → y ) LATIN SMALL LETTER GAMMA → LATIN SMALL LETTER Y\t# →γ→\n1D8C ;\t0079 ;\tMA\t# ( ᶌ → y ) LATIN SMALL LETTER V WITH PALATAL HOOK → LATIN SMALL LETTER Y\t# \nFF59 ;\t0079 ;\tMA\t# ( ｙ → y ) FULLWIDTH LATIN SMALL LETTER Y → LATIN SMALL LETTER Y\t# →у→\n1D432 ;\t0079 ;\tMA\t# ( 𝐲 → y ) MATHEMATICAL BOLD SMALL Y → LATIN SMALL LETTER Y\t# \n1D466 ;\t0079 ;\tMA\t# ( 𝑦 → y ) MATHEMATICAL ITALIC SMALL Y → LATIN SMALL LETTER Y\t# \n1D49A ;\t0079 ;\tMA\t# ( 𝒚 → y ) MATHEMATICAL BOLD ITALIC SMALL Y → LATIN SMALL LETTER Y\t# \n1D4CE ;\t0079 ;\tMA\t# ( 𝓎 → y ) MATHEMATICAL SCRIPT SMALL Y → LATIN SMALL LETTER Y\t# \n1D502 ;\t0079 ;\tMA\t# ( 𝔂 → y ) MATHEMATICAL BOLD SCRIPT SMALL Y → LATIN SMALL LETTER Y\t# \n1D536 ;\t0079 ;\tMA\t# ( 𝔶 → y ) MATHEMATICAL FRAKTUR SMALL Y → LATIN SMALL LETTER Y\t# \n1D56A ;\t0079 ;\tMA\t# ( 𝕪 → y ) MATHEMATICAL DOUBLE-STRUCK SMALL Y → LATIN SMALL LETTER Y\t# \n1D59E ;\t0079 ;\tMA\t# ( 𝖞 → y ) MATHEMATICAL BOLD FRAKTUR SMALL Y → LATIN SMALL LETTER Y\t# \n1D5D2 ;\t0079 ;\tMA\t# ( 𝗒 → y ) MATHEMATICAL SANS-SERIF SMALL Y → LATIN SMALL LETTER Y\t# \n1D606 ;\t0079 ;\tMA\t# ( 𝘆 → y ) MATHEMATICAL SANS-SERIF BOLD SMALL Y → LATIN SMALL LETTER Y\t# \n1D63A ;\t0079 ;\tMA\t# ( 𝘺 → y ) MATHEMATICAL SANS-SERIF ITALIC SMALL Y → LATIN SMALL LETTER Y\t# \n1D66E ;\t0079 ;\tMA\t# ( 𝙮 → y ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y → LATIN SMALL LETTER Y\t# \n1D6A2 ;\t0079 ;\tMA\t# ( 𝚢 → y ) MATHEMATICAL MONOSPACE SMALL Y → LATIN SMALL LETTER Y\t# \n028F ;\t0079 ;\tMA\t# ( ʏ → y ) LATIN LETTER SMALL CAPITAL Y → LATIN SMALL LETTER Y\t# →ү→→γ→\n1EFF ;\t0079 ;\tMA\t# ( ỿ → y ) LATIN SMALL LETTER Y WITH LOOP → LATIN SMALL LETTER Y\t# \nAB5A ;\t0079 ;\tMA\t# ( ꭚ → y ) LATIN SMALL LETTER Y WITH SHORT RIGHT LEG → LATIN SMALL LETTER Y\t# \n03B3 ;\t0079 ;\tMA\t# ( γ → y ) GREEK SMALL LETTER GAMMA → LATIN SMALL LETTER Y\t# \n213D ;\t0079 ;\tMA\t# ( ℽ → y ) DOUBLE-STRUCK SMALL GAMMA → LATIN SMALL LETTER Y\t# →γ→\n1D6C4 ;\t0079 ;\tMA\t# ( 𝛄 → y ) MATHEMATICAL BOLD SMALL GAMMA → LATIN SMALL LETTER Y\t# →γ→\n1D6FE ;\t0079 ;\tMA\t# ( 𝛾 → y ) MATHEMATICAL ITALIC SMALL GAMMA → LATIN SMALL LETTER Y\t# →γ→\n1D738 ;\t0079 ;\tMA\t# ( 𝜸 → y ) MATHEMATICAL BOLD ITALIC SMALL GAMMA → LATIN SMALL LETTER Y\t# →γ→\n1D772 ;\t0079 ;\tMA\t# ( 𝝲 → y ) MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA → LATIN SMALL LETTER Y\t# →γ→\n1D7AC ;\t0079 ;\tMA\t# ( 𝞬 → y ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA → LATIN SMALL LETTER Y\t# →γ→\n2CA9 ;\t0079 ;\tMA\t# ( ⲩ → y ) COPTIC SMALL LETTER UA → LATIN SMALL LETTER Y\t# →γ→\n0443 ;\t0079 ;\tMA\t# ( у → y ) CYRILLIC SMALL LETTER U → LATIN SMALL LETTER Y\t# \n04AF ;\t0079 ;\tMA\t# ( ү → y ) CYRILLIC SMALL LETTER STRAIGHT U → LATIN SMALL LETTER Y\t# →γ→\n10E7 ;\t0079 ;\tMA\t# ( ყ → y ) GEORGIAN LETTER QAR → LATIN SMALL LETTER Y\t# \n118DC ;\t0079 ;\tMA\t# ( 𑣜 → y ) WARANG CITI SMALL LETTER HAR → LATIN SMALL LETTER Y\t# →ɣ→→γ→\n\nFF39 ;\t0059 ;\tMA\t# ( Ｙ → Y ) FULLWIDTH LATIN CAPITAL LETTER Y → LATIN CAPITAL LETTER Y\t# →Υ→\n1CCEE ;\t0059 ;\tMA\t#* ( 𜳮 → Y ) OUTLINED LATIN CAPITAL LETTER Y → LATIN CAPITAL LETTER Y\t# \n1D418 ;\t0059 ;\tMA\t# ( 𝐘 → Y ) MATHEMATICAL BOLD CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D44C ;\t0059 ;\tMA\t# ( 𝑌 → Y ) MATHEMATICAL ITALIC CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D480 ;\t0059 ;\tMA\t# ( 𝒀 → Y ) MATHEMATICAL BOLD ITALIC CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D4B4 ;\t0059 ;\tMA\t# ( 𝒴 → Y ) MATHEMATICAL SCRIPT CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D4E8 ;\t0059 ;\tMA\t# ( 𝓨 → Y ) MATHEMATICAL BOLD SCRIPT CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D51C ;\t0059 ;\tMA\t# ( 𝔜 → Y ) MATHEMATICAL FRAKTUR CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D550 ;\t0059 ;\tMA\t# ( 𝕐 → Y ) MATHEMATICAL DOUBLE-STRUCK CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D584 ;\t0059 ;\tMA\t# ( 𝖄 → Y ) MATHEMATICAL BOLD FRAKTUR CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D5B8 ;\t0059 ;\tMA\t# ( 𝖸 → Y ) MATHEMATICAL SANS-SERIF CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D5EC ;\t0059 ;\tMA\t# ( 𝗬 → Y ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D620 ;\t0059 ;\tMA\t# ( 𝘠 → Y ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D654 ;\t0059 ;\tMA\t# ( 𝙔 → Y ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n1D688 ;\t0059 ;\tMA\t# ( 𝚈 → Y ) MATHEMATICAL MONOSPACE CAPITAL Y → LATIN CAPITAL LETTER Y\t# \n03A5 ;\t0059 ;\tMA\t# ( Υ → Y ) GREEK CAPITAL LETTER UPSILON → LATIN CAPITAL LETTER Y\t# \n03D2 ;\t0059 ;\tMA\t# ( ϒ → Y ) GREEK UPSILON WITH HOOK SYMBOL → LATIN CAPITAL LETTER Y\t# \n1D6BC ;\t0059 ;\tMA\t# ( 𝚼 → Y ) MATHEMATICAL BOLD CAPITAL UPSILON → LATIN CAPITAL LETTER Y\t# →Υ→\n1D6F6 ;\t0059 ;\tMA\t# ( 𝛶 → Y ) MATHEMATICAL ITALIC CAPITAL UPSILON → LATIN CAPITAL LETTER Y\t# →Υ→\n1D730 ;\t0059 ;\tMA\t# ( 𝜰 → Y ) MATHEMATICAL BOLD ITALIC CAPITAL UPSILON → LATIN CAPITAL LETTER Y\t# →Υ→\n1D76A ;\t0059 ;\tMA\t# ( 𝝪 → Y ) MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON → LATIN CAPITAL LETTER Y\t# →Υ→\n1D7A4 ;\t0059 ;\tMA\t# ( 𝞤 → Y ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON → LATIN CAPITAL LETTER Y\t# →Υ→\n2CA8 ;\t0059 ;\tMA\t# ( Ⲩ → Y ) COPTIC CAPITAL LETTER UA → LATIN CAPITAL LETTER Y\t# \n0423 ;\t0059 ;\tMA\t# ( У → Y ) CYRILLIC CAPITAL LETTER U → LATIN CAPITAL LETTER Y\t# \n04AE ;\t0059 ;\tMA\t# ( Ү → Y ) CYRILLIC CAPITAL LETTER STRAIGHT U → LATIN CAPITAL LETTER Y\t# \n13A9 ;\t0059 ;\tMA\t# ( Ꭹ → Y ) CHEROKEE LETTER GI → LATIN CAPITAL LETTER Y\t# \n13BD ;\t0059 ;\tMA\t# ( Ꮍ → Y ) CHEROKEE LETTER MU → LATIN CAPITAL LETTER Y\t# →Ꭹ→\nA4EC ;\t0059 ;\tMA\t# ( ꓬ → Y ) LISU LETTER YA → LATIN CAPITAL LETTER Y\t# \n16F43 ;\t0059 ;\tMA\t# ( 𖽃 → Y ) MIAO LETTER AH → LATIN CAPITAL LETTER Y\t# \n118A4 ;\t0059 ;\tMA\t# ( 𑢤 → Y ) WARANG CITI CAPITAL LETTER YA → LATIN CAPITAL LETTER Y\t# \n102B2 ;\t0059 ;\tMA\t# ( 𐊲 → Y ) CARIAN LETTER U → LATIN CAPITAL LETTER Y\t# \n\n01B4 ;\t0079 0314 ;\tMA\t# ( ƴ → y̔ ) LATIN SMALL LETTER Y WITH HOOK → LATIN SMALL LETTER Y, COMBINING REVERSED COMMA ABOVE\t# \n\n024F ;\t0079 0335 ;\tMA\t# ( ɏ → y̵ ) LATIN SMALL LETTER Y WITH STROKE → LATIN SMALL LETTER Y, COMBINING SHORT STROKE OVERLAY\t# \n04B1 ;\t0079 0335 ;\tMA\t# ( ұ → y̵ ) CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE → LATIN SMALL LETTER Y, COMBINING SHORT STROKE OVERLAY\t# →ү̵→\n\n00A5 ;\t0059 0335 ;\tMA\t#* ( ¥ → Y̵ ) YEN SIGN → LATIN CAPITAL LETTER Y, COMBINING SHORT STROKE OVERLAY\t# \n024E ;\t0059 0335 ;\tMA\t# ( Ɏ → Y̵ ) LATIN CAPITAL LETTER Y WITH STROKE → LATIN CAPITAL LETTER Y, COMBINING SHORT STROKE OVERLAY\t# \n04B0 ;\t0059 0335 ;\tMA\t# ( Ұ → Y̵ ) CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE → LATIN CAPITAL LETTER Y, COMBINING SHORT STROKE OVERLAY\t# →Ү̵→\n\n0292 ;\t021D ;\tMA\t# ( ʒ → ȝ ) LATIN SMALL LETTER EZH → LATIN SMALL LETTER YOGH\t# \nA76B ;\t021D ;\tMA\t# ( ꝫ → ȝ ) LATIN SMALL LETTER ET → LATIN SMALL LETTER YOGH\t# \n2CC5 ;\t021D ;\tMA\t# ( ⳅ → ȝ ) COPTIC SMALL LETTER OLD COPTIC SHEI → LATIN SMALL LETTER YOGH\t# →ʒ→\n2CCD ;\t021D ;\tMA\t# ( ⳍ → ȝ ) COPTIC SMALL LETTER OLD COPTIC HORI → LATIN SMALL LETTER YOGH\t# \n04E1 ;\t021D ;\tMA\t# ( ӡ → ȝ ) CYRILLIC SMALL LETTER ABKHASIAN DZE → LATIN SMALL LETTER YOGH\t# →ʒ→\n10F3 ;\t021D ;\tMA\t# ( ჳ → ȝ ) GEORGIAN LETTER WE → LATIN SMALL LETTER YOGH\t# →ʒ→\n\n1D433 ;\t007A ;\tMA\t# ( 𝐳 → z ) MATHEMATICAL BOLD SMALL Z → LATIN SMALL LETTER Z\t# \n1D467 ;\t007A ;\tMA\t# ( 𝑧 → z ) MATHEMATICAL ITALIC SMALL Z → LATIN SMALL LETTER Z\t# \n1D49B ;\t007A ;\tMA\t# ( 𝒛 → z ) MATHEMATICAL BOLD ITALIC SMALL Z → LATIN SMALL LETTER Z\t# \n1D4CF ;\t007A ;\tMA\t# ( 𝓏 → z ) MATHEMATICAL SCRIPT SMALL Z → LATIN SMALL LETTER Z\t# \n1D503 ;\t007A ;\tMA\t# ( 𝔃 → z ) MATHEMATICAL BOLD SCRIPT SMALL Z → LATIN SMALL LETTER Z\t# \n1D537 ;\t007A ;\tMA\t# ( 𝔷 → z ) MATHEMATICAL FRAKTUR SMALL Z → LATIN SMALL LETTER Z\t# \n1D56B ;\t007A ;\tMA\t# ( 𝕫 → z ) MATHEMATICAL DOUBLE-STRUCK SMALL Z → LATIN SMALL LETTER Z\t# \n1D59F ;\t007A ;\tMA\t# ( 𝖟 → z ) MATHEMATICAL BOLD FRAKTUR SMALL Z → LATIN SMALL LETTER Z\t# \n1D5D3 ;\t007A ;\tMA\t# ( 𝗓 → z ) MATHEMATICAL SANS-SERIF SMALL Z → LATIN SMALL LETTER Z\t# \n1D607 ;\t007A ;\tMA\t# ( 𝘇 → z ) MATHEMATICAL SANS-SERIF BOLD SMALL Z → LATIN SMALL LETTER Z\t# \n1D63B ;\t007A ;\tMA\t# ( 𝘻 → z ) MATHEMATICAL SANS-SERIF ITALIC SMALL Z → LATIN SMALL LETTER Z\t# \n1D66F ;\t007A ;\tMA\t# ( 𝙯 → z ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z → LATIN SMALL LETTER Z\t# \n1D6A3 ;\t007A ;\tMA\t# ( 𝚣 → z ) MATHEMATICAL MONOSPACE SMALL Z → LATIN SMALL LETTER Z\t# \n1D22 ;\t007A ;\tMA\t# ( ᴢ → z ) LATIN LETTER SMALL CAPITAL Z → LATIN SMALL LETTER Z\t# \nAB93 ;\t007A ;\tMA\t# ( ꮓ → z ) CHEROKEE SMALL LETTER NO → LATIN SMALL LETTER Z\t# →ᴢ→\n118C4 ;\t007A ;\tMA\t# ( 𑣄 → z ) WARANG CITI SMALL LETTER YA → LATIN SMALL LETTER Z\t# \n\n118E5 ;\t005A ;\tMA\t# ( 𑣥 → Z ) WARANG CITI DIGIT FIVE → LATIN CAPITAL LETTER Z\t# \n102F5 ;\t005A ;\tMA\t#* ( 𐋵 → Z ) COPTIC EPACT NUMBER THREE HUNDRED → LATIN CAPITAL LETTER Z\t# \nFF3A ;\t005A ;\tMA\t# ( Ｚ → Z ) FULLWIDTH LATIN CAPITAL LETTER Z → LATIN CAPITAL LETTER Z\t# →Ζ→\n2124 ;\t005A ;\tMA\t# ( ℤ → Z ) DOUBLE-STRUCK CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n2128 ;\t005A ;\tMA\t# ( ℨ → Z ) BLACK-LETTER CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1CCEF ;\t005A ;\tMA\t#* ( 𜳯 → Z ) OUTLINED LATIN CAPITAL LETTER Z → LATIN CAPITAL LETTER Z\t# \n1D419 ;\t005A ;\tMA\t# ( 𝐙 → Z ) MATHEMATICAL BOLD CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D44D ;\t005A ;\tMA\t# ( 𝑍 → Z ) MATHEMATICAL ITALIC CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D481 ;\t005A ;\tMA\t# ( 𝒁 → Z ) MATHEMATICAL BOLD ITALIC CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D4B5 ;\t005A ;\tMA\t# ( 𝒵 → Z ) MATHEMATICAL SCRIPT CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D4E9 ;\t005A ;\tMA\t# ( 𝓩 → Z ) MATHEMATICAL BOLD SCRIPT CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D585 ;\t005A ;\tMA\t# ( 𝖅 → Z ) MATHEMATICAL BOLD FRAKTUR CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D5B9 ;\t005A ;\tMA\t# ( 𝖹 → Z ) MATHEMATICAL SANS-SERIF CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D5ED ;\t005A ;\tMA\t# ( 𝗭 → Z ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D621 ;\t005A ;\tMA\t# ( 𝘡 → Z ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D655 ;\t005A ;\tMA\t# ( 𝙕 → Z ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n1D689 ;\t005A ;\tMA\t# ( 𝚉 → Z ) MATHEMATICAL MONOSPACE CAPITAL Z → LATIN CAPITAL LETTER Z\t# \n0396 ;\t005A ;\tMA\t# ( Ζ → Z ) GREEK CAPITAL LETTER ZETA → LATIN CAPITAL LETTER Z\t# \n1D6AD ;\t005A ;\tMA\t# ( 𝚭 → Z ) MATHEMATICAL BOLD CAPITAL ZETA → LATIN CAPITAL LETTER Z\t# →Ζ→\n1D6E7 ;\t005A ;\tMA\t# ( 𝛧 → Z ) MATHEMATICAL ITALIC CAPITAL ZETA → LATIN CAPITAL LETTER Z\t# →𝑍→\n1D721 ;\t005A ;\tMA\t# ( 𝜡 → Z ) MATHEMATICAL BOLD ITALIC CAPITAL ZETA → LATIN CAPITAL LETTER Z\t# →Ζ→\n1D75B ;\t005A ;\tMA\t# ( 𝝛 → Z ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA → LATIN CAPITAL LETTER Z\t# →Ζ→\n1D795 ;\t005A ;\tMA\t# ( 𝞕 → Z ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA → LATIN CAPITAL LETTER Z\t# →Ζ→\n13C3 ;\t005A ;\tMA\t# ( Ꮓ → Z ) CHEROKEE LETTER NO → LATIN CAPITAL LETTER Z\t# \nA4DC ;\t005A ;\tMA\t# ( ꓜ → Z ) LISU LETTER DZA → LATIN CAPITAL LETTER Z\t# \n118A9 ;\t005A ;\tMA\t# ( 𑢩 → Z ) WARANG CITI CAPITAL LETTER O → LATIN CAPITAL LETTER Z\t# \n\n0290 ;\t007A 0328 ;\tMA\t# ( ʐ → z̨ ) LATIN SMALL LETTER Z WITH RETROFLEX HOOK → LATIN SMALL LETTER Z, COMBINING OGONEK\t# →z̢→\n\n01B6 ;\t007A 0335 ;\tMA\t# ( ƶ → z̵ ) LATIN SMALL LETTER Z WITH STROKE → LATIN SMALL LETTER Z, COMBINING SHORT STROKE OVERLAY\t# \n\n01B5 ;\t005A 0335 ;\tMA\t# ( Ƶ → Z̵ ) LATIN CAPITAL LETTER Z WITH STROKE → LATIN CAPITAL LETTER Z, COMBINING SHORT STROKE OVERLAY\t# \n\n0225 ;\t007A 0326 ;\tMA\t# ( ȥ → z̦ ) LATIN SMALL LETTER Z WITH HOOK → LATIN SMALL LETTER Z, COMBINING COMMA BELOW\t# →z̡→\n\n0224 ;\t005A 0326 ;\tMA\t# ( Ȥ → Z̦ ) LATIN CAPITAL LETTER Z WITH HOOK → LATIN CAPITAL LETTER Z, COMBINING COMMA BELOW\t# →Z̧→\n\n1D76 ;\t007A 0334 ;\tMA\t# ( ᵶ → z̴ ) LATIN SMALL LETTER Z WITH MIDDLE TILDE → LATIN SMALL LETTER Z, COMBINING TILDE OVERLAY\t# \n\n2C8D ;\t2C6C ;\tMA\t# ( ⲍ → ⱬ ) COPTIC SMALL LETTER ZATA → LATIN SMALL LETTER Z WITH DESCENDER\t# \n\n2C8C ;\t2C6B ;\tMA\t# ( Ⲍ → Ⱬ ) COPTIC CAPITAL LETTER ZATA → LATIN CAPITAL LETTER Z WITH DESCENDER\t# \n\n2C9D ;\t0293 ;\tMA\t# ( ⲝ → ʓ ) COPTIC SMALL LETTER KSI → LATIN SMALL LETTER EZH WITH CURL\t# \n\n03F7 ;\t00DE ;\tMA\t# ( Ϸ → Þ ) GREEK CAPITAL LETTER SHO → LATIN CAPITAL LETTER THORN\t# \n104C4 ;\t00DE ;\tMA\t# ( 𐓄 → Þ ) OSAGE CAPITAL LETTER PA → LATIN CAPITAL LETTER THORN\t# \n\nA7D2 ;\tA7D3 ;\tMA\t# ( ꟒ → ꟓ ) LATIN CAPITAL LETTER DOUBLE THORN → LATIN SMALL LETTER DOUBLE THORN\t# \n\nA7D4 ;\tA7D5 ;\tMA\t# ( ꟔ → ꟕ ) LATIN CAPITAL LETTER DOUBLE WYNN → LATIN SMALL LETTER DOUBLE WYNN\t# \n\n2079 ;\tA770 ;\tMA\t#* ( ⁹ → ꝰ ) SUPERSCRIPT NINE → MODIFIER LETTER US\t# \n\n1D24 ;\t01A8 ;\tMA\t# ( ᴤ → ƨ ) LATIN LETTER VOICED LARYNGEAL SPIRANT → LATIN SMALL LETTER TONE TWO\t# \n03E9 ;\t01A8 ;\tMA\t# ( ϩ → ƨ ) COPTIC SMALL LETTER HORI → LATIN SMALL LETTER TONE TWO\t# \nA645 ;\t01A8 ;\tMA\t# ( ꙅ → ƨ ) CYRILLIC SMALL LETTER REVERSED DZE → LATIN SMALL LETTER TONE TWO\t# \n\n044C ;\t0185 ;\tMA\t# ( ь → ƅ ) CYRILLIC SMALL LETTER SOFT SIGN → LATIN SMALL LETTER TONE SIX\t# \nAB9F ;\t0185 ;\tMA\t# ( ꮟ → ƅ ) CHEROKEE SMALL LETTER SI → LATIN SMALL LETTER TONE SIX\t# →ь→\n16ED1 ;\t0185 ;\tMA\t# ( 𖻑 → ƅ ) BERIA ERFE SMALL LETTER UI → LATIN SMALL LETTER TONE SIX\t# →ь→\n\n044B ;\t0185 0069 ;\tMA\t# ( ы → ƅi ) CYRILLIC SMALL LETTER YERU → LATIN SMALL LETTER TONE SIX, LATIN SMALL LETTER I\t# →ьı→\n\nAB7E ;\t0242 ;\tMA\t# ( ꭾ → ɂ ) CHEROKEE SMALL LETTER HE → LATIN SMALL LETTER GLOTTAL STOP\t# \n\n02E4 ;\t02C1 ;\tMA\t# ( ˤ → ˁ ) MODIFIER LETTER SMALL REVERSED GLOTTAL STOP → MODIFIER LETTER REVERSED GLOTTAL STOP\t# \n\nA6CD ;\t02A1 ;\tMA\t# ( ꛍ → ʡ ) BAMUM LETTER LU → LATIN LETTER GLOTTAL STOP WITH STROKE\t# \n\n256A ;\t01C2 ;\tMA\t#* ( ╪ → ǂ ) BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE → LATIN LETTER ALVEOLAR CLICK\t# \n\n2299 ;\t0298 ;\tMA\t#* ( ⊙ → ʘ ) CIRCLED DOT OPERATOR → LATIN LETTER BILABIAL CLICK\t# \n2609 ;\t0298 ;\tMA\t#* ( ☉ → ʘ ) SUN → LATIN LETTER BILABIAL CLICK\t# →⊙→\n2A00 ;\t0298 ;\tMA\t#* ( ⨀ → ʘ ) N-ARY CIRCLED DOT OPERATOR → LATIN LETTER BILABIAL CLICK\t# →⊙→\nA668 ;\t0298 ;\tMA\t# ( Ꙩ → ʘ ) CYRILLIC CAPITAL LETTER MONOCULAR O → LATIN LETTER BILABIAL CLICK\t# \n2D59 ;\t0298 ;\tMA\t# ( ⵙ → ʘ ) TIFINAGH LETTER YAS → LATIN LETTER BILABIAL CLICK\t# →⊙→\n104C3 ;\t0298 ;\tMA\t# ( 𐓃 → ʘ ) OSAGE CAPITAL LETTER OIN → LATIN LETTER BILABIAL CLICK\t# →Ꙩ→\n\n213E ;\t0393 ;\tMA\t# ( ℾ → Γ ) DOUBLE-STRUCK CAPITAL GAMMA → GREEK CAPITAL LETTER GAMMA\t# \n1D6AA ;\t0393 ;\tMA\t# ( 𝚪 → Γ ) MATHEMATICAL BOLD CAPITAL GAMMA → GREEK CAPITAL LETTER GAMMA\t# \n1D6E4 ;\t0393 ;\tMA\t# ( 𝛤 → Γ ) MATHEMATICAL ITALIC CAPITAL GAMMA → GREEK CAPITAL LETTER GAMMA\t# \n1D71E ;\t0393 ;\tMA\t# ( 𝜞 → Γ ) MATHEMATICAL BOLD ITALIC CAPITAL GAMMA → GREEK CAPITAL LETTER GAMMA\t# \n1D758 ;\t0393 ;\tMA\t# ( 𝝘 → Γ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA → GREEK CAPITAL LETTER GAMMA\t# \n1D792 ;\t0393 ;\tMA\t# ( 𝞒 → Γ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA → GREEK CAPITAL LETTER GAMMA\t# \n2C84 ;\t0393 ;\tMA\t# ( Ⲅ → Γ ) COPTIC CAPITAL LETTER GAMMA → GREEK CAPITAL LETTER GAMMA\t# \n0413 ;\t0393 ;\tMA\t# ( Г → Γ ) CYRILLIC CAPITAL LETTER GHE → GREEK CAPITAL LETTER GAMMA\t# \n13B1 ;\t0393 ;\tMA\t# ( Ꮁ → Γ ) CHEROKEE LETTER HU → GREEK CAPITAL LETTER GAMMA\t# \n14A5 ;\t0393 ;\tMA\t# ( ᒥ → Γ ) CANADIAN SYLLABICS MI → GREEK CAPITAL LETTER GAMMA\t# \n16F07 ;\t0393 ;\tMA\t# ( 𖼇 → Γ ) MIAO LETTER FA → GREEK CAPITAL LETTER GAMMA\t# \n\n0492 ;\t0393 0335 ;\tMA\t# ( Ғ → Γ̵ ) CYRILLIC CAPITAL LETTER GHE WITH STROKE → GREEK CAPITAL LETTER GAMMA, COMBINING SHORT STROKE OVERLAY\t# →Г̵→\n\n14AF ;\t0393 00B7 ;\tMA\t# ( ᒯ → Γ· ) CANADIAN SYLLABICS WEST-CREE MWI → GREEK CAPITAL LETTER GAMMA, MIDDLE DOT\t# →ᒥᐧ→→ᒥ·→\n\n0490 ;\t0393 0027 ;\tMA\t# ( Ґ → Γ' ) CYRILLIC CAPITAL LETTER GHE WITH UPTURN → GREEK CAPITAL LETTER GAMMA, APOSTROPHE\t# →Гˈ→\n\n2206 ;\t0394 ;\tMA\t#* ( ∆ → Δ ) INCREMENT → GREEK CAPITAL LETTER DELTA\t# \n25B3 ;\t0394 ;\tMA\t#* ( △ → Δ ) WHITE UP-POINTING TRIANGLE → GREEK CAPITAL LETTER DELTA\t# \n1F702 ;\t0394 ;\tMA\t#* ( 🜂 → Δ ) ALCHEMICAL SYMBOL FOR FIRE → GREEK CAPITAL LETTER DELTA\t# →△→\n1D6AB ;\t0394 ;\tMA\t# ( 𝚫 → Δ ) MATHEMATICAL BOLD CAPITAL DELTA → GREEK CAPITAL LETTER DELTA\t# \n1D6E5 ;\t0394 ;\tMA\t# ( 𝛥 → Δ ) MATHEMATICAL ITALIC CAPITAL DELTA → GREEK CAPITAL LETTER DELTA\t# \n1D71F ;\t0394 ;\tMA\t# ( 𝜟 → Δ ) MATHEMATICAL BOLD ITALIC CAPITAL DELTA → GREEK CAPITAL LETTER DELTA\t# \n1D759 ;\t0394 ;\tMA\t# ( 𝝙 → Δ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA → GREEK CAPITAL LETTER DELTA\t# \n1D793 ;\t0394 ;\tMA\t# ( 𝞓 → Δ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA → GREEK CAPITAL LETTER DELTA\t# \n2C86 ;\t0394 ;\tMA\t# ( Ⲇ → Δ ) COPTIC CAPITAL LETTER DALDA → GREEK CAPITAL LETTER DELTA\t# \n2D60 ;\t0394 ;\tMA\t# ( ⵠ → Δ ) TIFINAGH LETTER YAV → GREEK CAPITAL LETTER DELTA\t# \n1403 ;\t0394 ;\tMA\t# ( ᐃ → Δ ) CANADIAN SYLLABICS I → GREEK CAPITAL LETTER DELTA\t# \n16F1A ;\t0394 ;\tMA\t# ( 𖼚 → Δ ) MIAO LETTER TLHA → GREEK CAPITAL LETTER DELTA\t# \n10285 ;\t0394 ;\tMA\t# ( 𐊅 → Δ ) LYCIAN LETTER D → GREEK CAPITAL LETTER DELTA\t# \n102A3 ;\t0394 ;\tMA\t# ( 𐊣 → Δ ) CARIAN LETTER L → GREEK CAPITAL LETTER DELTA\t# \n\n2359 ;\t0394 0332 ;\tMA\t#* ( ⍙ → Δ̲ ) APL FUNCTIONAL SYMBOL DELTA UNDERBAR → GREEK CAPITAL LETTER DELTA, COMBINING LOW LINE\t# \n\n140F ;\t0394 00B7 ;\tMA\t# ( ᐏ → Δ· ) CANADIAN SYLLABICS WEST-CREE WI → GREEK CAPITAL LETTER DELTA, MIDDLE DOT\t# →ᐃᐧ→\n\n142C ;\t0394 1420 ;\tMA\t# ( ᐬ → Δᐠ ) CANADIAN SYLLABICS IN → GREEK CAPITAL LETTER DELTA, CANADIAN SYLLABICS FINAL GRAVE\t# →ᐃᐠ→\n\n1D7CB ;\t03DD ;\tMA\t# ( 𝟋 → ϝ ) MATHEMATICAL BOLD SMALL DIGAMMA → GREEK SMALL LETTER DIGAMMA\t# \n\n1D6C7 ;\t03B6 ;\tMA\t# ( 𝛇 → ζ ) MATHEMATICAL BOLD SMALL ZETA → GREEK SMALL LETTER ZETA\t# \n1D701 ;\t03B6 ;\tMA\t# ( 𝜁 → ζ ) MATHEMATICAL ITALIC SMALL ZETA → GREEK SMALL LETTER ZETA\t# \n1D73B ;\t03B6 ;\tMA\t# ( 𝜻 → ζ ) MATHEMATICAL BOLD ITALIC SMALL ZETA → GREEK SMALL LETTER ZETA\t# \n1D775 ;\t03B6 ;\tMA\t# ( 𝝵 → ζ ) MATHEMATICAL SANS-SERIF BOLD SMALL ZETA → GREEK SMALL LETTER ZETA\t# \n1D7AF ;\t03B6 ;\tMA\t# ( 𝞯 → ζ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA → GREEK SMALL LETTER ZETA\t# \n\n2CE4 ;\t03D7 ;\tMA\t# ( ⳤ → ϗ ) COPTIC SYMBOL KAI → GREEK KAI SYMBOL\t# \n\nA7DB ;\t03BB ;\tMA\t# ( ꟛ → λ ) LATIN SMALL LETTER LAMBDA → GREEK SMALL LETTER LAMDA\t# \n1D6CC ;\t03BB ;\tMA\t# ( 𝛌 → λ ) MATHEMATICAL BOLD SMALL LAMDA → GREEK SMALL LETTER LAMDA\t# \n1D706 ;\t03BB ;\tMA\t# ( 𝜆 → λ ) MATHEMATICAL ITALIC SMALL LAMDA → GREEK SMALL LETTER LAMDA\t# \n1D740 ;\t03BB ;\tMA\t# ( 𝝀 → λ ) MATHEMATICAL BOLD ITALIC SMALL LAMDA → GREEK SMALL LETTER LAMDA\t# \n1D77A ;\t03BB ;\tMA\t# ( 𝝺 → λ ) MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA → GREEK SMALL LETTER LAMDA\t# \n1D7B4 ;\t03BB ;\tMA\t# ( 𝞴 → λ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA → GREEK SMALL LETTER LAMDA\t# \n2C96 ;\t03BB ;\tMA\t# ( Ⲗ → λ ) COPTIC CAPITAL LETTER LAULA → GREEK SMALL LETTER LAMDA\t# \n104DB ;\t03BB ;\tMA\t# ( 𐓛 → λ ) OSAGE SMALL LETTER AH → GREEK SMALL LETTER LAMDA\t# \n\n019B ;\t03BB 0338 ;\tMA\t# ( ƛ → λ̸ ) LATIN SMALL LETTER LAMBDA WITH STROKE → GREEK SMALL LETTER LAMDA, COMBINING LONG SOLIDUS OVERLAY\t# →λ̷→\n\n00B5 ;\t03BC ;\tMA\t# ( µ → μ ) MICRO SIGN → GREEK SMALL LETTER MU\t# \n1D6CD ;\t03BC ;\tMA\t# ( 𝛍 → μ ) MATHEMATICAL BOLD SMALL MU → GREEK SMALL LETTER MU\t# \n1D707 ;\t03BC ;\tMA\t# ( 𝜇 → μ ) MATHEMATICAL ITALIC SMALL MU → GREEK SMALL LETTER MU\t# \n1D741 ;\t03BC ;\tMA\t# ( 𝝁 → μ ) MATHEMATICAL BOLD ITALIC SMALL MU → GREEK SMALL LETTER MU\t# \n1D77B ;\t03BC ;\tMA\t# ( 𝝻 → μ ) MATHEMATICAL SANS-SERIF BOLD SMALL MU → GREEK SMALL LETTER MU\t# \n1D7B5 ;\t03BC ;\tMA\t# ( 𝞵 → μ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU → GREEK SMALL LETTER MU\t# \n\n1D6CF ;\t03BE ;\tMA\t# ( 𝛏 → ξ ) MATHEMATICAL BOLD SMALL XI → GREEK SMALL LETTER XI\t# \n1D709 ;\t03BE ;\tMA\t# ( 𝜉 → ξ ) MATHEMATICAL ITALIC SMALL XI → GREEK SMALL LETTER XI\t# \n1D743 ;\t03BE ;\tMA\t# ( 𝝃 → ξ ) MATHEMATICAL BOLD ITALIC SMALL XI → GREEK SMALL LETTER XI\t# \n1D77D ;\t03BE ;\tMA\t# ( 𝝽 → ξ ) MATHEMATICAL SANS-SERIF BOLD SMALL XI → GREEK SMALL LETTER XI\t# \n1D7B7 ;\t03BE ;\tMA\t# ( 𝞷 → ξ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI → GREEK SMALL LETTER XI\t# \n\n2630 ;\t039E ;\tMA\t#* ( ☰ → Ξ ) TRIGRAM FOR HEAVEN → GREEK CAPITAL LETTER XI\t# →Ⲷ→\n1D6B5 ;\t039E ;\tMA\t# ( 𝚵 → Ξ ) MATHEMATICAL BOLD CAPITAL XI → GREEK CAPITAL LETTER XI\t# \n1D6EF ;\t039E ;\tMA\t# ( 𝛯 → Ξ ) MATHEMATICAL ITALIC CAPITAL XI → GREEK CAPITAL LETTER XI\t# \n1D729 ;\t039E ;\tMA\t# ( 𝜩 → Ξ ) MATHEMATICAL BOLD ITALIC CAPITAL XI → GREEK CAPITAL LETTER XI\t# \n1D763 ;\t039E ;\tMA\t# ( 𝝣 → Ξ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL XI → GREEK CAPITAL LETTER XI\t# \n1D79D ;\t039E ;\tMA\t# ( 𝞝 → Ξ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI → GREEK CAPITAL LETTER XI\t# \n2CB6 ;\t039E ;\tMA\t# ( Ⲷ → Ξ ) COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE → GREEK CAPITAL LETTER XI\t# \n\n03D6 ;\t03C0 ;\tMA\t# ( ϖ → π ) GREEK PI SYMBOL → GREEK SMALL LETTER PI\t# \n213C ;\t03C0 ;\tMA\t# ( ℼ → π ) DOUBLE-STRUCK SMALL PI → GREEK SMALL LETTER PI\t# \n1D6D1 ;\t03C0 ;\tMA\t# ( 𝛑 → π ) MATHEMATICAL BOLD SMALL PI → GREEK SMALL LETTER PI\t# \n1D6E1 ;\t03C0 ;\tMA\t# ( 𝛡 → π ) MATHEMATICAL BOLD PI SYMBOL → GREEK SMALL LETTER PI\t# \n1D70B ;\t03C0 ;\tMA\t# ( 𝜋 → π ) MATHEMATICAL ITALIC SMALL PI → GREEK SMALL LETTER PI\t# \n1D71B ;\t03C0 ;\tMA\t# ( 𝜛 → π ) MATHEMATICAL ITALIC PI SYMBOL → GREEK SMALL LETTER PI\t# \n1D745 ;\t03C0 ;\tMA\t# ( 𝝅 → π ) MATHEMATICAL BOLD ITALIC SMALL PI → GREEK SMALL LETTER PI\t# \n1D755 ;\t03C0 ;\tMA\t# ( 𝝕 → π ) MATHEMATICAL BOLD ITALIC PI SYMBOL → GREEK SMALL LETTER PI\t# \n1D77F ;\t03C0 ;\tMA\t# ( 𝝿 → π ) MATHEMATICAL SANS-SERIF BOLD SMALL PI → GREEK SMALL LETTER PI\t# \n1D78F ;\t03C0 ;\tMA\t# ( 𝞏 → π ) MATHEMATICAL SANS-SERIF BOLD PI SYMBOL → GREEK SMALL LETTER PI\t# \n1D7B9 ;\t03C0 ;\tMA\t# ( 𝞹 → π ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI → GREEK SMALL LETTER PI\t# \n1D7C9 ;\t03C0 ;\tMA\t# ( 𝟉 → π ) MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL → GREEK SMALL LETTER PI\t# \n1D28 ;\t03C0 ;\tMA\t# ( ᴨ → π ) GREEK LETTER SMALL CAPITAL PI → GREEK SMALL LETTER PI\t# →п→\n2CA1 ;\t03C0 ;\tMA\t# ( ⲡ → π ) COPTIC SMALL LETTER PI → GREEK SMALL LETTER PI\t# →п→\n043F ;\t03C0 ;\tMA\t# ( п → π ) CYRILLIC SMALL LETTER PE → GREEK SMALL LETTER PI\t# \n16EC1 ;\t03C0 ;\tMA\t# ( 𖻁 → π ) BERIA ERFE SMALL LETTER HIRDEABO → GREEK SMALL LETTER PI\t# →п→\n\n220F ;\t03A0 ;\tMA\t#* ( ∏ → Π ) N-ARY PRODUCT → GREEK CAPITAL LETTER PI\t# \n213F ;\t03A0 ;\tMA\t# ( ℿ → Π ) DOUBLE-STRUCK CAPITAL PI → GREEK CAPITAL LETTER PI\t# \n1D6B7 ;\t03A0 ;\tMA\t# ( 𝚷 → Π ) MATHEMATICAL BOLD CAPITAL PI → GREEK CAPITAL LETTER PI\t# \n1D6F1 ;\t03A0 ;\tMA\t# ( 𝛱 → Π ) MATHEMATICAL ITALIC CAPITAL PI → GREEK CAPITAL LETTER PI\t# \n1D72B ;\t03A0 ;\tMA\t# ( 𝜫 → Π ) MATHEMATICAL BOLD ITALIC CAPITAL PI → GREEK CAPITAL LETTER PI\t# \n1D765 ;\t03A0 ;\tMA\t# ( 𝝥 → Π ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PI → GREEK CAPITAL LETTER PI\t# \n1D79F ;\t03A0 ;\tMA\t# ( 𝞟 → Π ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI → GREEK CAPITAL LETTER PI\t# \n2CA0 ;\t03A0 ;\tMA\t# ( Ⲡ → Π ) COPTIC CAPITAL LETTER PI → GREEK CAPITAL LETTER PI\t# \n041F ;\t03A0 ;\tMA\t# ( П → Π ) CYRILLIC CAPITAL LETTER PE → GREEK CAPITAL LETTER PI\t# \nA6DB ;\t03A0 ;\tMA\t# ( ꛛ → Π ) BAMUM LETTER NA → GREEK CAPITAL LETTER PI\t# \n16EA6 ;\t03A0 ;\tMA\t# ( 𖺦 → Π ) BERIA ERFE CAPITAL LETTER HIRDEABO → GREEK CAPITAL LETTER PI\t# →П→\n\n102AD ;\t03D8 ;\tMA\t# ( 𐊭 → Ϙ ) CARIAN LETTER T → GREEK LETTER ARCHAIC KOPPA\t# \n10312 ;\t03D8 ;\tMA\t# ( 𐌒 → Ϙ ) OLD ITALIC LETTER KU → GREEK LETTER ARCHAIC KOPPA\t# \n\n2CC1 ;\t03FC ;\tMA\t# ( ⳁ → ϼ ) COPTIC SMALL LETTER SAMPI → GREEK RHO WITH STROKE SYMBOL\t# \n\n03DB ;\t03C2 ;\tMA\t# ( ϛ → ς ) GREEK SMALL LETTER STIGMA → GREEK SMALL LETTER FINAL SIGMA\t# \n1D6D3 ;\t03C2 ;\tMA\t# ( 𝛓 → ς ) MATHEMATICAL BOLD SMALL FINAL SIGMA → GREEK SMALL LETTER FINAL SIGMA\t# \n1D70D ;\t03C2 ;\tMA\t# ( 𝜍 → ς ) MATHEMATICAL ITALIC SMALL FINAL SIGMA → GREEK SMALL LETTER FINAL SIGMA\t# \n1D747 ;\t03C2 ;\tMA\t# ( 𝝇 → ς ) MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA → GREEK SMALL LETTER FINAL SIGMA\t# \n1D781 ;\t03C2 ;\tMA\t# ( 𝞁 → ς ) MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA → GREEK SMALL LETTER FINAL SIGMA\t# \n1D7BB ;\t03C2 ;\tMA\t# ( 𝞻 → ς ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA → GREEK SMALL LETTER FINAL SIGMA\t# \n2C8B ;\t03C2 ;\tMA\t# ( ⲋ → ς ) COPTIC SMALL LETTER SOU → GREEK SMALL LETTER FINAL SIGMA\t# \n\n1D6BD ;\t03A6 ;\tMA\t# ( 𝚽 → Φ ) MATHEMATICAL BOLD CAPITAL PHI → GREEK CAPITAL LETTER PHI\t# \n1D6F7 ;\t03A6 ;\tMA\t# ( 𝛷 → Φ ) MATHEMATICAL ITALIC CAPITAL PHI → GREEK CAPITAL LETTER PHI\t# \n1D731 ;\t03A6 ;\tMA\t# ( 𝜱 → Φ ) MATHEMATICAL BOLD ITALIC CAPITAL PHI → GREEK CAPITAL LETTER PHI\t# \n1D76B ;\t03A6 ;\tMA\t# ( 𝝫 → Φ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI → GREEK CAPITAL LETTER PHI\t# \n1D7A5 ;\t03A6 ;\tMA\t# ( 𝞥 → Φ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI → GREEK CAPITAL LETTER PHI\t# \n2CAA ;\t03A6 ;\tMA\t# ( Ⲫ → Φ ) COPTIC CAPITAL LETTER FI → GREEK CAPITAL LETTER PHI\t# \n0424 ;\t03A6 ;\tMA\t# ( Ф → Φ ) CYRILLIC CAPITAL LETTER EF → GREEK CAPITAL LETTER PHI\t# \n0553 ;\t03A6 ;\tMA\t# ( Փ → Φ ) ARMENIAN CAPITAL LETTER PIWR → GREEK CAPITAL LETTER PHI\t# \n1240 ;\t03A6 ;\tMA\t# ( ቀ → Φ ) ETHIOPIC SYLLABLE QA → GREEK CAPITAL LETTER PHI\t# →Փ→\n16F0 ;\t03A6 ;\tMA\t# ( ᛰ → Φ ) RUNIC BELGTHOR SYMBOL → GREEK CAPITAL LETTER PHI\t# \n102B3 ;\t03A6 ;\tMA\t# ( 𐊳 → Φ ) CARIAN LETTER NN → GREEK CAPITAL LETTER PHI\t# \n\nAB53 ;\t03C7 ;\tMA\t# ( ꭓ → χ ) LATIN SMALL LETTER CHI → GREEK SMALL LETTER CHI\t# \nAB55 ;\t03C7 ;\tMA\t# ( ꭕ → χ ) LATIN SMALL LETTER CHI WITH LOW LEFT SERIF → GREEK SMALL LETTER CHI\t# \n1D6D8 ;\t03C7 ;\tMA\t# ( 𝛘 → χ ) MATHEMATICAL BOLD SMALL CHI → GREEK SMALL LETTER CHI\t# \n1D712 ;\t03C7 ;\tMA\t# ( 𝜒 → χ ) MATHEMATICAL ITALIC SMALL CHI → GREEK SMALL LETTER CHI\t# \n1D74C ;\t03C7 ;\tMA\t# ( 𝝌 → χ ) MATHEMATICAL BOLD ITALIC SMALL CHI → GREEK SMALL LETTER CHI\t# \n1D786 ;\t03C7 ;\tMA\t# ( 𝞆 → χ ) MATHEMATICAL SANS-SERIF BOLD SMALL CHI → GREEK SMALL LETTER CHI\t# \n1D7C0 ;\t03C7 ;\tMA\t# ( 𝟀 → χ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI → GREEK SMALL LETTER CHI\t# \n2CAD ;\t03C7 ;\tMA\t# ( ⲭ → χ ) COPTIC SMALL LETTER KHI → GREEK SMALL LETTER CHI\t# \n\n1D6D9 ;\t03C8 ;\tMA\t# ( 𝛙 → ψ ) MATHEMATICAL BOLD SMALL PSI → GREEK SMALL LETTER PSI\t# \n1D713 ;\t03C8 ;\tMA\t# ( 𝜓 → ψ ) MATHEMATICAL ITALIC SMALL PSI → GREEK SMALL LETTER PSI\t# \n1D74D ;\t03C8 ;\tMA\t# ( 𝝍 → ψ ) MATHEMATICAL BOLD ITALIC SMALL PSI → GREEK SMALL LETTER PSI\t# \n1D787 ;\t03C8 ;\tMA\t# ( 𝞇 → ψ ) MATHEMATICAL SANS-SERIF BOLD SMALL PSI → GREEK SMALL LETTER PSI\t# \n1D7C1 ;\t03C8 ;\tMA\t# ( 𝟁 → ψ ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI → GREEK SMALL LETTER PSI\t# \n2CAF ;\t03C8 ;\tMA\t# ( ⲯ → ψ ) COPTIC SMALL LETTER PSI → GREEK SMALL LETTER PSI\t# \n0471 ;\t03C8 ;\tMA\t# ( ѱ → ψ ) CYRILLIC SMALL LETTER PSI → GREEK SMALL LETTER PSI\t# \n104F9 ;\t03C8 ;\tMA\t# ( 𐓹 → ψ ) OSAGE SMALL LETTER GHA → GREEK SMALL LETTER PSI\t# \n\n1D6BF ;\t03A8 ;\tMA\t# ( 𝚿 → Ψ ) MATHEMATICAL BOLD CAPITAL PSI → GREEK CAPITAL LETTER PSI\t# \n1D6F9 ;\t03A8 ;\tMA\t# ( 𝛹 → Ψ ) MATHEMATICAL ITALIC CAPITAL PSI → GREEK CAPITAL LETTER PSI\t# \n1D733 ;\t03A8 ;\tMA\t# ( 𝜳 → Ψ ) MATHEMATICAL BOLD ITALIC CAPITAL PSI → GREEK CAPITAL LETTER PSI\t# \n1D76D ;\t03A8 ;\tMA\t# ( 𝝭 → Ψ ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI → GREEK CAPITAL LETTER PSI\t# \n1D7A7 ;\t03A8 ;\tMA\t# ( 𝞧 → Ψ ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI → GREEK CAPITAL LETTER PSI\t# \n2CAE ;\t03A8 ;\tMA\t# ( Ⲯ → Ψ ) COPTIC CAPITAL LETTER PSI → GREEK CAPITAL LETTER PSI\t# \n0470 ;\t03A8 ;\tMA\t# ( Ѱ → Ψ ) CYRILLIC CAPITAL LETTER PSI → GREEK CAPITAL LETTER PSI\t# \n104D1 ;\t03A8 ;\tMA\t# ( 𐓑 → Ψ ) OSAGE CAPITAL LETTER GHA → GREEK CAPITAL LETTER PSI\t# \n16D8 ;\t03A8 ;\tMA\t# ( ᛘ → Ψ ) RUNIC LETTER LONG-BRANCH-MADR M → GREEK CAPITAL LETTER PSI\t# \n102B5 ;\t03A8 ;\tMA\t# ( 𐊵 → Ψ ) CARIAN LETTER N → GREEK CAPITAL LETTER PSI\t# \n\n2375 ;\t03C9 ;\tMA\t#* ( ⍵ → ω ) APL FUNCTIONAL SYMBOL OMEGA → GREEK SMALL LETTER OMEGA\t# \nA7B7 ;\t03C9 ;\tMA\t# ( ꞷ → ω ) LATIN SMALL LETTER OMEGA → GREEK SMALL LETTER OMEGA\t# \n1D6DA ;\t03C9 ;\tMA\t# ( 𝛚 → ω ) MATHEMATICAL BOLD SMALL OMEGA → GREEK SMALL LETTER OMEGA\t# \n1D714 ;\t03C9 ;\tMA\t# ( 𝜔 → ω ) MATHEMATICAL ITALIC SMALL OMEGA → GREEK SMALL LETTER OMEGA\t# \n1D74E ;\t03C9 ;\tMA\t# ( 𝝎 → ω ) MATHEMATICAL BOLD ITALIC SMALL OMEGA → GREEK SMALL LETTER OMEGA\t# \n1D788 ;\t03C9 ;\tMA\t# ( 𝞈 → ω ) MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA → GREEK SMALL LETTER OMEGA\t# \n1D7C2 ;\t03C9 ;\tMA\t# ( 𝟂 → ω ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA → GREEK SMALL LETTER OMEGA\t# \n2CB1 ;\t03C9 ;\tMA\t# ( ⲱ → ω ) COPTIC SMALL LETTER OOU → GREEK SMALL LETTER OMEGA\t# \nA64D ;\t03C9 ;\tMA\t# ( ꙍ → ω ) CYRILLIC SMALL LETTER BROAD OMEGA → GREEK SMALL LETTER OMEGA\t# →ꞷ→\n\n2126 ;\t03A9 ;\tMA\t# ( Ω → Ω ) OHM SIGN → GREEK CAPITAL LETTER OMEGA\t# \n1D6C0 ;\t03A9 ;\tMA\t# ( 𝛀 → Ω ) MATHEMATICAL BOLD CAPITAL OMEGA → GREEK CAPITAL LETTER OMEGA\t# \n1D6FA ;\t03A9 ;\tMA\t# ( 𝛺 → Ω ) MATHEMATICAL ITALIC CAPITAL OMEGA → GREEK CAPITAL LETTER OMEGA\t# \n1D734 ;\t03A9 ;\tMA\t# ( 𝜴 → Ω ) MATHEMATICAL BOLD ITALIC CAPITAL OMEGA → GREEK CAPITAL LETTER OMEGA\t# \n1D76E ;\t03A9 ;\tMA\t# ( 𝝮 → Ω ) MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA → GREEK CAPITAL LETTER OMEGA\t# \n1D7A8 ;\t03A9 ;\tMA\t# ( 𝞨 → Ω ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA → GREEK CAPITAL LETTER OMEGA\t# \n162F ;\t03A9 ;\tMA\t# ( ᘯ → Ω ) CANADIAN SYLLABICS CARRIER LHO → GREEK CAPITAL LETTER OMEGA\t# \n1635 ;\t03A9 ;\tMA\t# ( ᘵ → Ω ) CANADIAN SYLLABICS CARRIER TLHO → GREEK CAPITAL LETTER OMEGA\t# →ᘯ→\n102B6 ;\t03A9 ;\tMA\t# ( 𐊶 → Ω ) CARIAN LETTER TT2 → GREEK CAPITAL LETTER OMEGA\t# \n\n2379 ;\t03C9 0332 ;\tMA\t#* ( ⍹ → ω̲ ) APL FUNCTIONAL SYMBOL OMEGA UNDERBAR → GREEK SMALL LETTER OMEGA, COMBINING LOW LINE\t# \n\n1F7D ;\t1FF4 ;\tMA\t# ( ώ → ῴ ) GREEK SMALL LETTER OMEGA WITH OXIA → GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI\t# \n\n0497 ;\t0436 0329 ;\tMA\t# ( җ → ж̩ ) CYRILLIC SMALL LETTER ZHE WITH DESCENDER → CYRILLIC SMALL LETTER ZHE, COMBINING VERTICAL LINE BELOW\t# \n\n0496 ;\t0416 0329 ;\tMA\t# ( Җ → Ж̩ ) CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER → CYRILLIC CAPITAL LETTER ZHE, COMBINING VERTICAL LINE BELOW\t# \n\n1D20B ;\t0418 ;\tMA\t#* ( 𝈋 → И ) GREEK VOCAL NOTATION SYMBOL-12 → CYRILLIC CAPITAL LETTER I\t# →Ͷ→\n0376 ;\t0418 ;\tMA\t# ( Ͷ → И ) GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA → CYRILLIC CAPITAL LETTER I\t# \nA6A1 ;\t0418 ;\tMA\t# ( ꚡ → И ) BAMUM LETTER KA → CYRILLIC CAPITAL LETTER I\t# →Ͷ→\n10425 ;\t0418 ;\tMA\t# ( 𐐥 → И ) DESERET CAPITAL LETTER ENG → CYRILLIC CAPITAL LETTER I\t# \n\n0419 ;\t040D ;\tMA\t# ( Й → Ѝ ) CYRILLIC CAPITAL LETTER SHORT I → CYRILLIC CAPITAL LETTER I WITH GRAVE\t# \n\n048A ;\t040D 0326 ;\tMA\t# ( Ҋ → Ѝ̦ ) CYRILLIC CAPITAL LETTER SHORT I WITH TAIL → CYRILLIC CAPITAL LETTER I WITH GRAVE, COMBINING COMMA BELOW\t# →Й̡→\n\n045D ;\t0439 ;\tMA\t# ( ѝ → й ) CYRILLIC SMALL LETTER I WITH GRAVE → CYRILLIC SMALL LETTER SHORT I\t# \n\n048B ;\t0439 0326 ;\tMA\t# ( ҋ → й̦ ) CYRILLIC SMALL LETTER SHORT I WITH TAIL → CYRILLIC SMALL LETTER SHORT I, COMBINING COMMA BELOW\t# →й̡→\n\n104BC ;\t04C3 ;\tMA\t# ( 𐒼 → Ӄ ) OSAGE CAPITAL LETTER KA → CYRILLIC CAPITAL LETTER KA WITH HOOK\t# \n\n1D2B ;\t043B ;\tMA\t# ( ᴫ → л ) CYRILLIC LETTER SMALL CAPITAL EL → CYRILLIC SMALL LETTER EL\t# \n\n04C6 ;\t043B 0326 ;\tMA\t# ( ӆ → л̦ ) CYRILLIC SMALL LETTER EL WITH TAIL → CYRILLIC SMALL LETTER EL, COMBINING COMMA BELOW\t# →л̡→\n\nAB60 ;\t0459 ;\tMA\t# ( ꭠ → љ ) LATIN SMALL LETTER SAKHA YAT → CYRILLIC SMALL LETTER LJE\t# \n\n104EB ;\tA669 ;\tMA\t# ( 𐓫 → ꙩ ) OSAGE SMALL LETTER OIN → CYRILLIC SMALL LETTER MONOCULAR O\t# \n\n1DEE ;\t2DEC ;\tMA\t# ( ᷮ → ⷬ ) COMBINING LATIN SMALL LETTER P → COMBINING CYRILLIC LETTER ER\t# \n\n104CD ;\t040B ;\tMA\t# ( 𐓍 → Ћ ) OSAGE CAPITAL LETTER DHA → CYRILLIC CAPITAL LETTER TSHE\t# \n\n1D202 ;\t04FE ;\tMA\t#* ( 𝈂 → Ӿ ) GREEK VOCAL NOTATION SYMBOL-3 → CYRILLIC CAPITAL LETTER HA WITH STROKE\t# \n\n1D222 ;\t0460 ;\tMA\t#* ( 𝈢 → Ѡ ) GREEK INSTRUMENTAL NOTATION SYMBOL-8 → CYRILLIC CAPITAL LETTER OMEGA\t# \n13C7 ;\t0460 ;\tMA\t# ( Ꮗ → Ѡ ) CHEROKEE LETTER QUE → CYRILLIC CAPITAL LETTER OMEGA\t# \n15EF ;\t0460 ;\tMA\t# ( ᗯ → Ѡ ) CANADIAN SYLLABICS CARRIER GU → CYRILLIC CAPITAL LETTER OMEGA\t# \n\n047C ;\t0460 0486 0487 ;\tMA\t# ( Ѽ → Ѡ҆҇ ) CYRILLIC CAPITAL LETTER OMEGA WITH TITLO → CYRILLIC CAPITAL LETTER OMEGA, COMBINING CYRILLIC PSILI PNEUMATA, COMBINING CYRILLIC POKRYTIE\t# \n\n18ED ;\t0460 00B7 ;\tMA\t# ( ᣭ → Ѡ· ) CANADIAN SYLLABICS CARRIER GWU → CYRILLIC CAPITAL LETTER OMEGA, MIDDLE DOT\t# →ᗯᐧ→\n\nA7B6 ;\tA64C ;\tMA\t# ( Ꞷ → Ꙍ ) LATIN CAPITAL LETTER OMEGA → CYRILLIC CAPITAL LETTER BROAD OMEGA\t# \n2CB0 ;\tA64C ;\tMA\t# ( Ⲱ → Ꙍ ) COPTIC CAPITAL LETTER OOU → CYRILLIC CAPITAL LETTER BROAD OMEGA\t# \n\n0AEB ;\t0447 ;\tMA\t# ( ૫ → ч ) GUJARATI DIGIT FIVE → CYRILLIC SMALL LETTER CHE\t# \n03E5 ;\t0447 ;\tMA\t# ( ϥ → ч ) COPTIC SMALL LETTER FEI → CYRILLIC SMALL LETTER CHE\t# \n0AAA ;\t0447 ;\tMA\t# ( પ → ч ) GUJARATI LETTER PA → CYRILLIC SMALL LETTER CHE\t# →૫→\n\n03E4 ;\t0427 ;\tMA\t# ( Ϥ → Ч ) COPTIC CAPITAL LETTER FEI → CYRILLIC CAPITAL LETTER CHE\t# \n\n04CC ;\t04B7 ;\tMA\t# ( ӌ → ҷ ) CYRILLIC SMALL LETTER KHAKASSIAN CHE → CYRILLIC SMALL LETTER CHE WITH DESCENDER\t# \n\n04CB ;\t04B6 ;\tMA\t# ( Ӌ → Ҷ ) CYRILLIC CAPITAL LETTER KHAKASSIAN CHE → CYRILLIC CAPITAL LETTER CHE WITH DESCENDER\t# \n\n04BE ;\t04BC 0328 ;\tMA\t# ( Ҿ → Ҽ̨ ) CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER → CYRILLIC CAPITAL LETTER ABKHASIAN CHE, COMBINING OGONEK\t# \n\n2CBC ;\t0428 ;\tMA\t# ( Ⲽ → Ш ) COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI → CYRILLIC CAPITAL LETTER SHA\t# \n\nA650 ;\t042A 006C ;\tMA\t# ( Ꙑ → Ъl ) CYRILLIC CAPITAL LETTER YERU WITH BACK YER → CYRILLIC CAPITAL LETTER HARD SIGN, LATIN SMALL LETTER L\t# →ЪІ→\n\n2108 ;\t042D ;\tMA\t#* ( ℈ → Э ) SCRUPLE → CYRILLIC CAPITAL LETTER E\t# \n\n1F701 ;\tA658 ;\tMA\t#* ( 🜁 → Ꙙ ) ALCHEMICAL SYMBOL FOR AIR → CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS\t# \n16F1C ;\tA658 ;\tMA\t# ( 𖼜 → Ꙙ ) MIAO LETTER TLHYA → CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS\t# \n\nA992 ;\t2C3F ;\tMA\t# ( ꦒ → ⰿ ) JAVANESE LETTER GA → GLAGOLITIC SMALL LETTER MYSLITE\t# \n\n0587 ;\t0565 0069 ;\tMA\t# ( և → եi ) ARMENIAN SMALL LIGATURE ECH YIWN → ARMENIAN SMALL LETTER ECH, LATIN SMALL LETTER I\t# →եւ→\n\n1294 ;\t0571 ;\tMA\t# ( ኔ → ձ ) ETHIOPIC SYLLABLE NEE → ARMENIAN SMALL LETTER JA\t# \n\nFB14 ;\t0574 0565 ;\tMA\t# ( ﬔ → մե ) ARMENIAN SMALL LIGATURE MEN ECH → ARMENIAN SMALL LETTER MEN, ARMENIAN SMALL LETTER ECH\t# \n\nFB15 ;\t0574 056B ;\tMA\t# ( ﬕ → մի ) ARMENIAN SMALL LIGATURE MEN INI → ARMENIAN SMALL LETTER MEN, ARMENIAN SMALL LETTER INI\t# \n\nFB17 ;\t0574 056D ;\tMA\t# ( ﬗ → մխ ) ARMENIAN SMALL LIGATURE MEN XEH → ARMENIAN SMALL LETTER MEN, ARMENIAN SMALL LETTER XEH\t# \n\nFB13 ;\t0574 0576 ;\tMA\t# ( ﬓ → մն ) ARMENIAN SMALL LIGATURE MEN NOW → ARMENIAN SMALL LETTER MEN, ARMENIAN SMALL LETTER NOW\t# \n\n2229 ;\t0548 ;\tMA\t#* ( ∩ → Ո ) INTERSECTION → ARMENIAN CAPITAL LETTER VO\t# →ᑎ→\n22C2 ;\t0548 ;\tMA\t#* ( ⋂ → Ո ) N-ARY INTERSECTION → ARMENIAN CAPITAL LETTER VO\t# →∩→→ᑎ→\n1D245 ;\t0548 ;\tMA\t#* ( 𝉅 → Ո ) GREEK MUSICAL LEIMMA → ARMENIAN CAPITAL LETTER VO\t# →∩→→ᑎ→\n1260 ;\t0548 ;\tMA\t# ( በ → Ո ) ETHIOPIC SYLLABLE BA → ARMENIAN CAPITAL LETTER VO\t# \n144E ;\t0548 ;\tMA\t# ( ᑎ → Ո ) CANADIAN SYLLABICS TI → ARMENIAN CAPITAL LETTER VO\t# \nA4F5 ;\t0548 ;\tMA\t# ( ꓵ → Ո ) LISU LETTER UE → ARMENIAN CAPITAL LETTER VO\t# →∩→→ᑎ→\n\n145A ;\t0548 00B7 ;\tMA\t# ( ᑚ → Ո· ) CANADIAN SYLLABICS WEST-CREE TWI → ARMENIAN CAPITAL LETTER VO, MIDDLE DOT\t# →ᑎᐧ→→ᑎ·→\n\n1468 ;\t0548 0027 ;\tMA\t# ( ᑨ → Ո' ) CANADIAN SYLLABICS TTI → ARMENIAN CAPITAL LETTER VO, APOSTROPHE\t# →ᑎᑊ→→ᑎ'→\n\nFB16 ;\t057E 0576 ;\tMA\t# ( ﬖ → վն ) ARMENIAN SMALL LIGATURE VEW NOW → ARMENIAN SMALL LETTER VEW, ARMENIAN SMALL LETTER NOW\t# \n\n2CE8 ;\t0554 ;\tMA\t#* ( ⳨ → Ք ) COPTIC SYMBOL TAU RO → ARMENIAN CAPITAL LETTER KEH\t# →₽→\n101A0 ;\t0554 ;\tMA\t#* ( 𐆠 → Ք ) GREEK SYMBOL TAU RHO → ARMENIAN CAPITAL LETTER KEH\t# →⳨→→₽→\n20BD ;\t0554 ;\tMA\t#* ( ₽ → Ք ) RUBLE SIGN → ARMENIAN CAPITAL LETTER KEH\t# \n2CC0 ;\t0554 ;\tMA\t# ( Ⳁ → Ք ) COPTIC CAPITAL LETTER SAMPI → ARMENIAN CAPITAL LETTER KEH\t# →₽→\n\n02D3 ;\t0559 ;\tMA\t#* ( ˓ → ՙ ) MODIFIER LETTER CENTRED LEFT HALF RING → ARMENIAN MODIFIER LETTER LEFT HALF RING\t# \n02BF ;\t0559 ;\tMA\t# ( ʿ → ՙ ) MODIFIER LETTER LEFT HALF RING → ARMENIAN MODIFIER LETTER LEFT HALF RING\t# \n\n2135 ;\t05D0 ;\tMA\t# ( ℵ → ‎א‎ ) ALEF SYMBOL → HEBREW LETTER ALEF\t# \nFB21 ;\t05D0 ;\tMA\t# ( ‎ﬡ‎ → ‎א‎ ) HEBREW LETTER WIDE ALEF → HEBREW LETTER ALEF\t# \n\nFB2F ;\tFB2E ;\tMA\t# ( ‎אָ‎ → ‎אַ‎ ) HEBREW LETTER ALEF WITH QAMATS → HEBREW LETTER ALEF WITH PATAH\t# \nFB30 ;\tFB2E ;\tMA\t# ( ‎אּ‎ → ‎אַ‎ ) HEBREW LETTER ALEF WITH MAPIQ → HEBREW LETTER ALEF WITH PATAH\t# \n\nFB4F ;\t05D0 05DC ;\tMA\t# ( ‎ﭏ‎ → ‎אל‎ ) HEBREW LIGATURE ALEF LAMED → HEBREW LETTER ALEF, HEBREW LETTER LAMED\t# \n\n2136 ;\t05D1 ;\tMA\t# ( ℶ → ‎ב‎ ) BET SYMBOL → HEBREW LETTER BET\t# \n\n2137 ;\t05D2 ;\tMA\t# ( ℷ → ‎ג‎ ) GIMEL SYMBOL → HEBREW LETTER GIMEL\t# \n\n2138 ;\t05D3 ;\tMA\t# ( ℸ → ‎ד‎ ) DALET SYMBOL → HEBREW LETTER DALET\t# \nFB22 ;\t05D3 ;\tMA\t# ( ‎ﬢ‎ → ‎ד‎ ) HEBREW LETTER WIDE DALET → HEBREW LETTER DALET\t# \n\nFB23 ;\t05D4 ;\tMA\t# ( ‎ﬣ‎ → ‎ה‎ ) HEBREW LETTER WIDE HE → HEBREW LETTER HE\t# \n\nFB39 ;\tFB1D ;\tMA\t# ( ‎יּ‎ → ‎יִ‎ ) HEBREW LETTER YOD WITH DAGESH → HEBREW LETTER YOD WITH HIRIQ\t# \n\nFB24 ;\t05DB ;\tMA\t# ( ‎ﬤ‎ → ‎כ‎ ) HEBREW LETTER WIDE KAF → HEBREW LETTER KAF\t# \n\nFB25 ;\t05DC ;\tMA\t# ( ‎ﬥ‎ → ‎ל‎ ) HEBREW LETTER WIDE LAMED → HEBREW LETTER LAMED\t# \n\nFB26 ;\t05DD ;\tMA\t# ( ‎ﬦ‎ → ‎ם‎ ) HEBREW LETTER WIDE FINAL MEM → HEBREW LETTER FINAL MEM\t# \n\nFB20 ;\t05E2 ;\tMA\t# ( ‎ﬠ‎ → ‎ע‎ ) HEBREW LETTER ALTERNATIVE AYIN → HEBREW LETTER AYIN\t# \n\nFB27 ;\t05E8 ;\tMA\t# ( ‎ﬧ‎ → ‎ר‎ ) HEBREW LETTER WIDE RESH → HEBREW LETTER RESH\t# \n\nFB2B ;\tFB2A ;\tMA\t# ( ‎שׂ‎ → ‎שׁ‎ ) HEBREW LETTER SHIN WITH SIN DOT → HEBREW LETTER SHIN WITH SHIN DOT\t# \nFB49 ;\tFB2A ;\tMA\t# ( ‎שּ‎ → ‎שׁ‎ ) HEBREW LETTER SHIN WITH DAGESH → HEBREW LETTER SHIN WITH SHIN DOT\t# \n\nFB2D ;\tFB2C ;\tMA\t# ( ‎שּׂ‎ → ‎שּׁ‎ ) HEBREW LETTER SHIN WITH DAGESH AND SIN DOT → HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT\t# \n\nFB28 ;\t05EA ;\tMA\t# ( ‎ﬨ‎ → ‎ת‎ ) HEBREW LETTER WIDE TAV → HEBREW LETTER TAV\t# \n\nFE80 ;\t0621 ;\tMA\t# ( ‎ﺀ‎ → ‎ء‎ ) ARABIC LETTER HAMZA ISOLATED FORM → ARABIC LETTER HAMZA\t# \n\n06FD ;\t0621 10EFA ;\tMA\t#* ( ‎۽‎ → ‎ء𐻺‎ ) ARABIC SIGN SINDHI AMPERSAND → ARABIC LETTER HAMZA, ARABIC DOUBLE VERTICAL BAR BELOW\t# \n\nFE82 ;\t0622 ;\tMA\t# ( ‎ﺂ‎ → ‎آ‎ ) ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM → ARABIC LETTER ALEF WITH MADDA ABOVE\t# \nFE81 ;\t0622 ;\tMA\t# ( ‎ﺁ‎ → ‎آ‎ ) ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM → ARABIC LETTER ALEF WITH MADDA ABOVE\t# \n\nFB51 ;\t0671 ;\tMA\t# ( ‎ﭑ‎ → ‎ٱ‎ ) ARABIC LETTER ALEF WASLA FINAL FORM → ARABIC LETTER ALEF WASLA\t# \nFB50 ;\t0671 ;\tMA\t# ( ‎ﭐ‎ → ‎ٱ‎ ) ARABIC LETTER ALEF WASLA ISOLATED FORM → ARABIC LETTER ALEF WASLA\t# \n\n1EE01 ;\t0628 ;\tMA\t# ( ‎𞸁‎ → ‎ب‎ ) ARABIC MATHEMATICAL BEH → ARABIC LETTER BEH\t# \n1EE21 ;\t0628 ;\tMA\t# ( ‎𞸡‎ → ‎ب‎ ) ARABIC MATHEMATICAL INITIAL BEH → ARABIC LETTER BEH\t# \n1EE61 ;\t0628 ;\tMA\t# ( ‎𞹡‎ → ‎ب‎ ) ARABIC MATHEMATICAL STRETCHED BEH → ARABIC LETTER BEH\t# \n1EE81 ;\t0628 ;\tMA\t# ( ‎𞺁‎ → ‎ب‎ ) ARABIC MATHEMATICAL LOOPED BEH → ARABIC LETTER BEH\t# \n1EEA1 ;\t0628 ;\tMA\t# ( ‎𞺡‎ → ‎ب‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK BEH → ARABIC LETTER BEH\t# \nFE91 ;\t0628 ;\tMA\t# ( ‎ﺑ‎ → ‎ب‎ ) ARABIC LETTER BEH INITIAL FORM → ARABIC LETTER BEH\t# \nFE92 ;\t0628 ;\tMA\t# ( ‎ﺒ‎ → ‎ب‎ ) ARABIC LETTER BEH MEDIAL FORM → ARABIC LETTER BEH\t# \nFE90 ;\t0628 ;\tMA\t# ( ‎ﺐ‎ → ‎ب‎ ) ARABIC LETTER BEH FINAL FORM → ARABIC LETTER BEH\t# \nFE8F ;\t0628 ;\tMA\t# ( ‎ﺏ‎ → ‎ب‎ ) ARABIC LETTER BEH ISOLATED FORM → ARABIC LETTER BEH\t# \n\n0751 ;\t0628 06DB ;\tMA\t# ( ‎ݑ‎ → ‎بۛ‎ ) ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE → ARABIC LETTER BEH, ARABIC SMALL HIGH THREE DOTS\t# \n\n08B6 ;\t0628 06E2 ;\tMA\t# ( ‎ࢶ‎ → ‎بۢ‎ ) ARABIC LETTER BEH WITH SMALL MEEM ABOVE → ARABIC LETTER BEH, ARABIC SMALL HIGH MEEM ISOLATED FORM\t# \n\n08A1 ;\t0628 0654 ;\tMA\t# ( ‎ࢡ‎ → ‎بٔ‎ ) ARABIC LETTER BEH WITH HAMZA ABOVE → ARABIC LETTER BEH, ARABIC HAMZA ABOVE\t# \n\nFCA0 ;\t0628 006F ;\tMA\t# ( ‎ﲠ‎ → ‎بo‎ ) ARABIC LIGATURE BEH WITH HEH INITIAL FORM → ARABIC LETTER BEH, LATIN SMALL LETTER O\t# →‎به‎→\nFCE2 ;\t0628 006F ;\tMA\t# ( ‎ﳢ‎ → ‎بo‎ ) ARABIC LIGATURE BEH WITH HEH MEDIAL FORM → ARABIC LETTER BEH, LATIN SMALL LETTER O\t# →‎به‎→\n\nFC9C ;\t0628 062C ;\tMA\t# ( ‎ﲜ‎ → ‎بج‎ ) ARABIC LIGATURE BEH WITH JEEM INITIAL FORM → ARABIC LETTER BEH, ARABIC LETTER JEEM\t# \nFC05 ;\t0628 062C ;\tMA\t# ( ‎ﰅ‎ → ‎بج‎ ) ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM → ARABIC LETTER BEH, ARABIC LETTER JEEM\t# \n\nFC9D ;\t0628 062D ;\tMA\t# ( ‎ﲝ‎ → ‎بح‎ ) ARABIC LIGATURE BEH WITH HAH INITIAL FORM → ARABIC LETTER BEH, ARABIC LETTER HAH\t# \nFC06 ;\t0628 062D ;\tMA\t# ( ‎ﰆ‎ → ‎بح‎ ) ARABIC LIGATURE BEH WITH HAH ISOLATED FORM → ARABIC LETTER BEH, ARABIC LETTER HAH\t# \n\nFDC2 ;\t0628 062D 0649 ;\tMA\t# ( ‎ﷂ‎ → ‎بحى‎ ) ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM → ARABIC LETTER BEH, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎بحي‎→\n\nFC9E ;\t0628 062E ;\tMA\t# ( ‎ﲞ‎ → ‎بخ‎ ) ARABIC LIGATURE BEH WITH KHAH INITIAL FORM → ARABIC LETTER BEH, ARABIC LETTER KHAH\t# \nFC07 ;\t0628 062E ;\tMA\t# ( ‎ﰇ‎ → ‎بخ‎ ) ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM → ARABIC LETTER BEH, ARABIC LETTER KHAH\t# \nFCD2 ;\t0628 062E ;\tMA\t# ( ‎ﳒ‎ → ‎بخ‎ ) ARABIC LIGATURE NOON WITH JEEM INITIAL FORM → ARABIC LETTER BEH, ARABIC LETTER KHAH\t# →‎ﲞ‎→\nFC4B ;\t0628 062E ;\tMA\t# ( ‎ﱋ‎ → ‎بخ‎ ) ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM → ARABIC LETTER BEH, ARABIC LETTER KHAH\t# →‎نج‎→→‎ﳒ‎→→‎ﲞ‎→\n\nFD9E ;\t0628 062E 0649 ;\tMA\t# ( ‎ﶞ‎ → ‎بخى‎ ) ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM → ARABIC LETTER BEH, ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# →‎بخي‎→\n\nFC6A ;\t0628 0631 ;\tMA\t# ( ‎ﱪ‎ → ‎بر‎ ) ARABIC LIGATURE BEH WITH REH FINAL FORM → ARABIC LETTER BEH, ARABIC LETTER REH\t# \n\nFC6B ;\t0628 0632 ;\tMA\t# ( ‎ﱫ‎ → ‎بز‎ ) ARABIC LIGATURE BEH WITH ZAIN FINAL FORM → ARABIC LETTER BEH, ARABIC LETTER ZAIN\t# \n\nFC9F ;\t0628 0645 ;\tMA\t# ( ‎ﲟ‎ → ‎بم‎ ) ARABIC LIGATURE BEH WITH MEEM INITIAL FORM → ARABIC LETTER BEH, ARABIC LETTER MEEM\t# \nFCE1 ;\t0628 0645 ;\tMA\t# ( ‎ﳡ‎ → ‎بم‎ ) ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM → ARABIC LETTER BEH, ARABIC LETTER MEEM\t# \nFC6C ;\t0628 0645 ;\tMA\t# ( ‎ﱬ‎ → ‎بم‎ ) ARABIC LIGATURE BEH WITH MEEM FINAL FORM → ARABIC LETTER BEH, ARABIC LETTER MEEM\t# \nFC08 ;\t0628 0645 ;\tMA\t# ( ‎ﰈ‎ → ‎بم‎ ) ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM → ARABIC LETTER BEH, ARABIC LETTER MEEM\t# \n\nFC6D ;\t0628 0646 ;\tMA\t# ( ‎ﱭ‎ → ‎بن‎ ) ARABIC LIGATURE BEH WITH NOON FINAL FORM → ARABIC LETTER BEH, ARABIC LETTER NOON\t# \n\nFC6E ;\t0628 0649 ;\tMA\t# ( ‎ﱮ‎ → ‎بى‎ ) ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER BEH, ARABIC LETTER ALEF MAKSURA\t# \nFC09 ;\t0628 0649 ;\tMA\t# ( ‎ﰉ‎ → ‎بى‎ ) ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER BEH, ARABIC LETTER ALEF MAKSURA\t# \nFC6F ;\t0628 0649 ;\tMA\t# ( ‎ﱯ‎ → ‎بى‎ ) ARABIC LIGATURE BEH WITH YEH FINAL FORM → ARABIC LETTER BEH, ARABIC LETTER ALEF MAKSURA\t# →‎بي‎→\nFC0A ;\t0628 0649 ;\tMA\t# ( ‎ﰊ‎ → ‎بى‎ ) ARABIC LIGATURE BEH WITH YEH ISOLATED FORM → ARABIC LETTER BEH, ARABIC LETTER ALEF MAKSURA\t# →‎بي‎→\n\nFB54 ;\t067B ;\tMA\t# ( ‎ﭔ‎ → ‎ٻ‎ ) ARABIC LETTER BEEH INITIAL FORM → ARABIC LETTER BEEH\t# \nFB55 ;\t067B ;\tMA\t# ( ‎ﭕ‎ → ‎ٻ‎ ) ARABIC LETTER BEEH MEDIAL FORM → ARABIC LETTER BEEH\t# \nFB53 ;\t067B ;\tMA\t# ( ‎ﭓ‎ → ‎ٻ‎ ) ARABIC LETTER BEEH FINAL FORM → ARABIC LETTER BEEH\t# \nFB52 ;\t067B ;\tMA\t# ( ‎ﭒ‎ → ‎ٻ‎ ) ARABIC LETTER BEEH ISOLATED FORM → ARABIC LETTER BEEH\t# \n06D0 ;\t067B ;\tMA\t# ( ‎ې‎ → ‎ٻ‎ ) ARABIC LETTER E → ARABIC LETTER BEEH\t# \nFBE6 ;\t067B ;\tMA\t# ( ‎ﯦ‎ → ‎ٻ‎ ) ARABIC LETTER E INITIAL FORM → ARABIC LETTER BEEH\t# →‎ې‎→\nFBE7 ;\t067B ;\tMA\t# ( ‎ﯧ‎ → ‎ٻ‎ ) ARABIC LETTER E MEDIAL FORM → ARABIC LETTER BEEH\t# →‎ې‎→\nFBE5 ;\t067B ;\tMA\t# ( ‎ﯥ‎ → ‎ٻ‎ ) ARABIC LETTER E FINAL FORM → ARABIC LETTER BEEH\t# →‎ې‎→\nFBE4 ;\t067B ;\tMA\t# ( ‎ﯤ‎ → ‎ٻ‎ ) ARABIC LETTER E ISOLATED FORM → ARABIC LETTER BEEH\t# →‎ې‎→\n\nFB5C ;\t0680 ;\tMA\t# ( ‎ﭜ‎ → ‎ڀ‎ ) ARABIC LETTER BEHEH INITIAL FORM → ARABIC LETTER BEHEH\t# \nFB5D ;\t0680 ;\tMA\t# ( ‎ﭝ‎ → ‎ڀ‎ ) ARABIC LETTER BEHEH MEDIAL FORM → ARABIC LETTER BEHEH\t# \nFB5B ;\t0680 ;\tMA\t# ( ‎ﭛ‎ → ‎ڀ‎ ) ARABIC LETTER BEHEH FINAL FORM → ARABIC LETTER BEHEH\t# \nFB5A ;\t0680 ;\tMA\t# ( ‎ﭚ‎ → ‎ڀ‎ ) ARABIC LETTER BEHEH ISOLATED FORM → ARABIC LETTER BEHEH\t# \n10EC7 ;\t0680 ;\tMA\t# ( ‎𐻇‎ → ‎ڀ‎ ) ARABIC LETTER YEH WITH FOUR DOTS BELOW → ARABIC LETTER BEHEH\t# \n\n08A9 ;\t0754 ;\tMA\t# ( ‎ࢩ‎ → ‎ݔ‎ ) ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE → ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE\t# \n0767 ;\t0754 ;\tMA\t# ( ‎ݧ‎ → ‎ݔ‎ ) ARABIC LETTER NOON WITH TWO DOTS BELOW → ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE\t# \n\n2365 ;\t0629 ;\tMA\t#* ( ⍥ → ‎ة‎ ) APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS → ARABIC LETTER TEH MARBUTA\t# →ö→\n00F6 ;\t0629 ;\tMA\t# ( ö → ‎ة‎ ) LATIN SMALL LETTER O WITH DIAERESIS → ARABIC LETTER TEH MARBUTA\t# \nFE94 ;\t0629 ;\tMA\t# ( ‎ﺔ‎ → ‎ة‎ ) ARABIC LETTER TEH MARBUTA FINAL FORM → ARABIC LETTER TEH MARBUTA\t# \nFE93 ;\t0629 ;\tMA\t# ( ‎ﺓ‎ → ‎ة‎ ) ARABIC LETTER TEH MARBUTA ISOLATED FORM → ARABIC LETTER TEH MARBUTA\t# \n06C3 ;\t0629 ;\tMA\t# ( ‎ۃ‎ → ‎ة‎ ) ARABIC LETTER TEH MARBUTA GOAL → ARABIC LETTER TEH MARBUTA\t# \n\n1EE15 ;\t062A ;\tMA\t# ( ‎𞸕‎ → ‎ت‎ ) ARABIC MATHEMATICAL TEH → ARABIC LETTER TEH\t# \n1EE35 ;\t062A ;\tMA\t# ( ‎𞸵‎ → ‎ت‎ ) ARABIC MATHEMATICAL INITIAL TEH → ARABIC LETTER TEH\t# \n1EE75 ;\t062A ;\tMA\t# ( ‎𞹵‎ → ‎ت‎ ) ARABIC MATHEMATICAL STRETCHED TEH → ARABIC LETTER TEH\t# \n1EE95 ;\t062A ;\tMA\t# ( ‎𞺕‎ → ‎ت‎ ) ARABIC MATHEMATICAL LOOPED TEH → ARABIC LETTER TEH\t# \n1EEB5 ;\t062A ;\tMA\t# ( ‎𞺵‎ → ‎ت‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK TEH → ARABIC LETTER TEH\t# \nFE97 ;\t062A ;\tMA\t# ( ‎ﺗ‎ → ‎ت‎ ) ARABIC LETTER TEH INITIAL FORM → ARABIC LETTER TEH\t# \nFE98 ;\t062A ;\tMA\t# ( ‎ﺘ‎ → ‎ت‎ ) ARABIC LETTER TEH MEDIAL FORM → ARABIC LETTER TEH\t# \nFE96 ;\t062A ;\tMA\t# ( ‎ﺖ‎ → ‎ت‎ ) ARABIC LETTER TEH FINAL FORM → ARABIC LETTER TEH\t# \nFE95 ;\t062A ;\tMA\t# ( ‎ﺕ‎ → ‎ت‎ ) ARABIC LETTER TEH ISOLATED FORM → ARABIC LETTER TEH\t# \n067A ;\t062A ;\tMA\t# ( ‎ٺ‎ → ‎ت‎ ) ARABIC LETTER TTEHEH → ARABIC LETTER TEH\t# \nFB60 ;\t062A ;\tMA\t# ( ‎ﭠ‎ → ‎ت‎ ) ARABIC LETTER TTEHEH INITIAL FORM → ARABIC LETTER TEH\t# →‎ٺ‎→\nFB61 ;\t062A ;\tMA\t# ( ‎ﭡ‎ → ‎ت‎ ) ARABIC LETTER TTEHEH MEDIAL FORM → ARABIC LETTER TEH\t# →‎ٺ‎→\nFB5F ;\t062A ;\tMA\t# ( ‎ﭟ‎ → ‎ت‎ ) ARABIC LETTER TTEHEH FINAL FORM → ARABIC LETTER TEH\t# →‎ٺ‎→\nFB5E ;\t062A ;\tMA\t# ( ‎ﭞ‎ → ‎ت‎ ) ARABIC LETTER TTEHEH ISOLATED FORM → ARABIC LETTER TEH\t# →‎ٺ‎→\n\n08BF ;\t062A 0306 ;\tMA\t# ( ‎ࢿ‎ → ‎ت̆‎ ) ARABIC LETTER TEH WITH SMALL V → ARABIC LETTER TEH, COMBINING BREVE\t# →‎تٚ‎→\n\nFCA5 ;\t062A 006F ;\tMA\t# ( ‎ﲥ‎ → ‎تo‎ ) ARABIC LIGATURE TEH WITH HEH INITIAL FORM → ARABIC LETTER TEH, LATIN SMALL LETTER O\t# →‎ته‎→\nFCE4 ;\t062A 006F ;\tMA\t# ( ‎ﳤ‎ → ‎تo‎ ) ARABIC LIGATURE TEH WITH HEH MEDIAL FORM → ARABIC LETTER TEH, LATIN SMALL LETTER O\t# →‎ته‎→\n\nFCA1 ;\t062A 062C ;\tMA\t# ( ‎ﲡ‎ → ‎تج‎ ) ARABIC LIGATURE TEH WITH JEEM INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER JEEM\t# \nFC0B ;\t062A 062C ;\tMA\t# ( ‎ﰋ‎ → ‎تج‎ ) ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM → ARABIC LETTER TEH, ARABIC LETTER JEEM\t# \n\nFD50 ;\t062A 062C 0645 ;\tMA\t# ( ‎ﵐ‎ → ‎تجم‎ ) ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \n\nFDA0 ;\t062A 062C 0649 ;\tMA\t# ( ‎ﶠ‎ → ‎تجى‎ ) ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# \nFD9F ;\t062A 062C 0649 ;\tMA\t# ( ‎ﶟ‎ → ‎تجى‎ ) ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎تجي‎→\n\nFCA2 ;\t062A 062D ;\tMA\t# ( ‎ﲢ‎ → ‎تح‎ ) ARABIC LIGATURE TEH WITH HAH INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER HAH\t# \nFC0C ;\t062A 062D ;\tMA\t# ( ‎ﰌ‎ → ‎تح‎ ) ARABIC LIGATURE TEH WITH HAH ISOLATED FORM → ARABIC LETTER TEH, ARABIC LETTER HAH\t# \n\nFD52 ;\t062A 062D 062C ;\tMA\t# ( ‎ﵒ‎ → ‎تحج‎ ) ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER HAH, ARABIC LETTER JEEM\t# \nFD51 ;\t062A 062D 062C ;\tMA\t# ( ‎ﵑ‎ → ‎تحج‎ ) ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER HAH, ARABIC LETTER JEEM\t# \n\nFD53 ;\t062A 062D 0645 ;\tMA\t# ( ‎ﵓ‎ → ‎تحم‎ ) ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER HAH, ARABIC LETTER MEEM\t# \n\nFCA3 ;\t062A 062E ;\tMA\t# ( ‎ﲣ‎ → ‎تخ‎ ) ARABIC LIGATURE TEH WITH KHAH INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER KHAH\t# \nFC0D ;\t062A 062E ;\tMA\t# ( ‎ﰍ‎ → ‎تخ‎ ) ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM → ARABIC LETTER TEH, ARABIC LETTER KHAH\t# \n\nFD54 ;\t062A 062E 0645 ;\tMA\t# ( ‎ﵔ‎ → ‎تخم‎ ) ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \n\nFDA2 ;\t062A 062E 0649 ;\tMA\t# ( ‎ﶢ‎ → ‎تخى‎ ) ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# \nFDA1 ;\t062A 062E 0649 ;\tMA\t# ( ‎ﶡ‎ → ‎تخى‎ ) ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# →‎تخي‎→\n\nFC70 ;\t062A 0631 ;\tMA\t# ( ‎ﱰ‎ → ‎تر‎ ) ARABIC LIGATURE TEH WITH REH FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER REH\t# \n\nFC71 ;\t062A 0632 ;\tMA\t# ( ‎ﱱ‎ → ‎تز‎ ) ARABIC LIGATURE TEH WITH ZAIN FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER ZAIN\t# \n\nFCA4 ;\t062A 0645 ;\tMA\t# ( ‎ﲤ‎ → ‎تم‎ ) ARABIC LIGATURE TEH WITH MEEM INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM\t# \nFCE3 ;\t062A 0645 ;\tMA\t# ( ‎ﳣ‎ → ‎تم‎ ) ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM\t# \nFC72 ;\t062A 0645 ;\tMA\t# ( ‎ﱲ‎ → ‎تم‎ ) ARABIC LIGATURE TEH WITH MEEM FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM\t# \nFC0E ;\t062A 0645 ;\tMA\t# ( ‎ﰎ‎ → ‎تم‎ ) ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM\t# \n\nFD55 ;\t062A 0645 062C ;\tMA\t# ( ‎ﵕ‎ → ‎تمج‎ ) ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM, ARABIC LETTER JEEM\t# \n\nFD56 ;\t062A 0645 062D ;\tMA\t# ( ‎ﵖ‎ → ‎تمح‎ ) ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \n\nFD57 ;\t062A 0645 062E ;\tMA\t# ( ‎ﵗ‎ → ‎تمخ‎ ) ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM, ARABIC LETTER KHAH\t# \n\nFDA4 ;\t062A 0645 0649 ;\tMA\t# ( ‎ﶤ‎ → ‎تمى‎ ) ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# \nFDA3 ;\t062A 0645 0649 ;\tMA\t# ( ‎ﶣ‎ → ‎تمى‎ ) ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎تمي‎→\n\nFC73 ;\t062A 0646 ;\tMA\t# ( ‎ﱳ‎ → ‎تن‎ ) ARABIC LIGATURE TEH WITH NOON FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER NOON\t# \n\nFC74 ;\t062A 0649 ;\tMA\t# ( ‎ﱴ‎ → ‎تى‎ ) ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER ALEF MAKSURA\t# \nFC0F ;\t062A 0649 ;\tMA\t# ( ‎ﰏ‎ → ‎تى‎ ) ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER TEH, ARABIC LETTER ALEF MAKSURA\t# \nFC75 ;\t062A 0649 ;\tMA\t# ( ‎ﱵ‎ → ‎تى‎ ) ARABIC LIGATURE TEH WITH YEH FINAL FORM → ARABIC LETTER TEH, ARABIC LETTER ALEF MAKSURA\t# →‎تي‎→\nFC10 ;\t062A 0649 ;\tMA\t# ( ‎ﰐ‎ → ‎تى‎ ) ARABIC LIGATURE TEH WITH YEH ISOLATED FORM → ARABIC LETTER TEH, ARABIC LETTER ALEF MAKSURA\t# →‎تي‎→\n\nFB64 ;\t067F ;\tMA\t# ( ‎ﭤ‎ → ‎ٿ‎ ) ARABIC LETTER TEHEH INITIAL FORM → ARABIC LETTER TEHEH\t# \nFB65 ;\t067F ;\tMA\t# ( ‎ﭥ‎ → ‎ٿ‎ ) ARABIC LETTER TEHEH MEDIAL FORM → ARABIC LETTER TEHEH\t# \nFB63 ;\t067F ;\tMA\t# ( ‎ﭣ‎ → ‎ٿ‎ ) ARABIC LETTER TEHEH FINAL FORM → ARABIC LETTER TEHEH\t# \nFB62 ;\t067F ;\tMA\t# ( ‎ﭢ‎ → ‎ٿ‎ ) ARABIC LETTER TEHEH ISOLATED FORM → ARABIC LETTER TEHEH\t# \n\n1EE02 ;\t062C ;\tMA\t# ( ‎𞸂‎ → ‎ج‎ ) ARABIC MATHEMATICAL JEEM → ARABIC LETTER JEEM\t# \n1EE22 ;\t062C ;\tMA\t# ( ‎𞸢‎ → ‎ج‎ ) ARABIC MATHEMATICAL INITIAL JEEM → ARABIC LETTER JEEM\t# \n1EE42 ;\t062C ;\tMA\t# ( ‎𞹂‎ → ‎ج‎ ) ARABIC MATHEMATICAL TAILED JEEM → ARABIC LETTER JEEM\t# \n1EE62 ;\t062C ;\tMA\t# ( ‎𞹢‎ → ‎ج‎ ) ARABIC MATHEMATICAL STRETCHED JEEM → ARABIC LETTER JEEM\t# \n1EE82 ;\t062C ;\tMA\t# ( ‎𞺂‎ → ‎ج‎ ) ARABIC MATHEMATICAL LOOPED JEEM → ARABIC LETTER JEEM\t# \n1EEA2 ;\t062C ;\tMA\t# ( ‎𞺢‎ → ‎ج‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM → ARABIC LETTER JEEM\t# \nFE9F ;\t062C ;\tMA\t# ( ‎ﺟ‎ → ‎ج‎ ) ARABIC LETTER JEEM INITIAL FORM → ARABIC LETTER JEEM\t# \nFEA0 ;\t062C ;\tMA\t# ( ‎ﺠ‎ → ‎ج‎ ) ARABIC LETTER JEEM MEDIAL FORM → ARABIC LETTER JEEM\t# \nFE9E ;\t062C ;\tMA\t# ( ‎ﺞ‎ → ‎ج‎ ) ARABIC LETTER JEEM FINAL FORM → ARABIC LETTER JEEM\t# \nFE9D ;\t062C ;\tMA\t# ( ‎ﺝ‎ → ‎ج‎ ) ARABIC LETTER JEEM ISOLATED FORM → ARABIC LETTER JEEM\t# \n\nFCA7 ;\t062C 062D ;\tMA\t# ( ‎ﲧ‎ → ‎جح‎ ) ARABIC LIGATURE JEEM WITH HAH INITIAL FORM → ARABIC LETTER JEEM, ARABIC LETTER HAH\t# \nFC15 ;\t062C 062D ;\tMA\t# ( ‎ﰕ‎ → ‎جح‎ ) ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM → ARABIC LETTER JEEM, ARABIC LETTER HAH\t# \n\nFDA6 ;\t062C 062D 0649 ;\tMA\t# ( ‎ﶦ‎ → ‎جحى‎ ) ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER JEEM, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# \nFDBE ;\t062C 062D 0649 ;\tMA\t# ( ‎ﶾ‎ → ‎جحى‎ ) ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM → ARABIC LETTER JEEM, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎جحي‎→\n\nFDFB ;\t062C 0644 0020 062C 0644 006C 0644 006F ;\tMA\t#* ( ‎ﷻ‎ → ‎جل جلlلo‎ ) ARABIC LIGATURE JALLAJALALOUHOU → ARABIC LETTER JEEM, ARABIC LETTER LAM, SPACE, ARABIC LETTER JEEM, ARABIC LETTER LAM, LATIN SMALL LETTER L, ARABIC LETTER LAM, LATIN SMALL LETTER O\t# →‎جل جلاله‎→\n\nFCA8 ;\t062C 0645 ;\tMA\t# ( ‎ﲨ‎ → ‎جم‎ ) ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM → ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \nFC16 ;\t062C 0645 ;\tMA\t# ( ‎ﰖ‎ → ‎جم‎ ) ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM → ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \n\nFD59 ;\t062C 0645 062D ;\tMA\t# ( ‎ﵙ‎ → ‎جمح‎ ) ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM → ARABIC LETTER JEEM, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \nFD58 ;\t062C 0645 062D ;\tMA\t# ( ‎ﵘ‎ → ‎جمح‎ ) ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM → ARABIC LETTER JEEM, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \n\nFDA7 ;\t062C 0645 0649 ;\tMA\t# ( ‎ﶧ‎ → ‎جمى‎ ) ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER JEEM, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# \nFDA5 ;\t062C 0645 0649 ;\tMA\t# ( ‎ﶥ‎ → ‎جمى‎ ) ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER JEEM, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎جمي‎→\n\nFD1D ;\t062C 0649 ;\tMA\t# ( ‎ﴝ‎ → ‎جى‎ ) ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# \nFD01 ;\t062C 0649 ;\tMA\t# ( ‎ﴁ‎ → ‎جى‎ ) ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# \nFD1E ;\t062C 0649 ;\tMA\t# ( ‎ﴞ‎ → ‎جى‎ ) ARABIC LIGATURE JEEM WITH YEH FINAL FORM → ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎جي‎→\nFD02 ;\t062C 0649 ;\tMA\t# ( ‎ﴂ‎ → ‎جى‎ ) ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM → ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎جي‎→\n\nFB78 ;\t0683 ;\tMA\t# ( ‎ﭸ‎ → ‎ڃ‎ ) ARABIC LETTER NYEH INITIAL FORM → ARABIC LETTER NYEH\t# \nFB79 ;\t0683 ;\tMA\t# ( ‎ﭹ‎ → ‎ڃ‎ ) ARABIC LETTER NYEH MEDIAL FORM → ARABIC LETTER NYEH\t# \nFB77 ;\t0683 ;\tMA\t# ( ‎ﭷ‎ → ‎ڃ‎ ) ARABIC LETTER NYEH FINAL FORM → ARABIC LETTER NYEH\t# \nFB76 ;\t0683 ;\tMA\t# ( ‎ﭶ‎ → ‎ڃ‎ ) ARABIC LETTER NYEH ISOLATED FORM → ARABIC LETTER NYEH\t# \n\nFB74 ;\t0684 ;\tMA\t# ( ‎ﭴ‎ → ‎ڄ‎ ) ARABIC LETTER DYEH INITIAL FORM → ARABIC LETTER DYEH\t# \nFB75 ;\t0684 ;\tMA\t# ( ‎ﭵ‎ → ‎ڄ‎ ) ARABIC LETTER DYEH MEDIAL FORM → ARABIC LETTER DYEH\t# \nFB73 ;\t0684 ;\tMA\t# ( ‎ﭳ‎ → ‎ڄ‎ ) ARABIC LETTER DYEH FINAL FORM → ARABIC LETTER DYEH\t# \nFB72 ;\t0684 ;\tMA\t# ( ‎ﭲ‎ → ‎ڄ‎ ) ARABIC LETTER DYEH ISOLATED FORM → ARABIC LETTER DYEH\t# \n\nFB7C ;\t0686 ;\tMA\t# ( ‎ﭼ‎ → ‎چ‎ ) ARABIC LETTER TCHEH INITIAL FORM → ARABIC LETTER TCHEH\t# \nFB7D ;\t0686 ;\tMA\t# ( ‎ﭽ‎ → ‎چ‎ ) ARABIC LETTER TCHEH MEDIAL FORM → ARABIC LETTER TCHEH\t# \nFB7B ;\t0686 ;\tMA\t# ( ‎ﭻ‎ → ‎چ‎ ) ARABIC LETTER TCHEH FINAL FORM → ARABIC LETTER TCHEH\t# \nFB7A ;\t0686 ;\tMA\t# ( ‎ﭺ‎ → ‎چ‎ ) ARABIC LETTER TCHEH ISOLATED FORM → ARABIC LETTER TCHEH\t# \n\n08C1 ;\t0686 0306 ;\tMA\t# ( ‎ࣁ‎ → ‎چ̆‎ ) ARABIC LETTER TCHEH WITH SMALL V → ARABIC LETTER TCHEH, COMBINING BREVE\t# →‎چٚ‎→\n\nFB80 ;\t0687 ;\tMA\t# ( ‎ﮀ‎ → ‎ڇ‎ ) ARABIC LETTER TCHEHEH INITIAL FORM → ARABIC LETTER TCHEHEH\t# \nFB81 ;\t0687 ;\tMA\t# ( ‎ﮁ‎ → ‎ڇ‎ ) ARABIC LETTER TCHEHEH MEDIAL FORM → ARABIC LETTER TCHEHEH\t# \nFB7F ;\t0687 ;\tMA\t# ( ‎ﭿ‎ → ‎ڇ‎ ) ARABIC LETTER TCHEHEH FINAL FORM → ARABIC LETTER TCHEHEH\t# \nFB7E ;\t0687 ;\tMA\t# ( ‎ﭾ‎ → ‎ڇ‎ ) ARABIC LETTER TCHEHEH ISOLATED FORM → ARABIC LETTER TCHEHEH\t# \n\n1EE07 ;\t062D ;\tMA\t# ( ‎𞸇‎ → ‎ح‎ ) ARABIC MATHEMATICAL HAH → ARABIC LETTER HAH\t# \n1EE27 ;\t062D ;\tMA\t# ( ‎𞸧‎ → ‎ح‎ ) ARABIC MATHEMATICAL INITIAL HAH → ARABIC LETTER HAH\t# \n1EE47 ;\t062D ;\tMA\t# ( ‎𞹇‎ → ‎ح‎ ) ARABIC MATHEMATICAL TAILED HAH → ARABIC LETTER HAH\t# \n1EE67 ;\t062D ;\tMA\t# ( ‎𞹧‎ → ‎ح‎ ) ARABIC MATHEMATICAL STRETCHED HAH → ARABIC LETTER HAH\t# \n1EE87 ;\t062D ;\tMA\t# ( ‎𞺇‎ → ‎ح‎ ) ARABIC MATHEMATICAL LOOPED HAH → ARABIC LETTER HAH\t# \n1EEA7 ;\t062D ;\tMA\t# ( ‎𞺧‎ → ‎ح‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK HAH → ARABIC LETTER HAH\t# \nFEA3 ;\t062D ;\tMA\t# ( ‎ﺣ‎ → ‎ح‎ ) ARABIC LETTER HAH INITIAL FORM → ARABIC LETTER HAH\t# \nFEA4 ;\t062D ;\tMA\t# ( ‎ﺤ‎ → ‎ح‎ ) ARABIC LETTER HAH MEDIAL FORM → ARABIC LETTER HAH\t# \nFEA2 ;\t062D ;\tMA\t# ( ‎ﺢ‎ → ‎ح‎ ) ARABIC LETTER HAH FINAL FORM → ARABIC LETTER HAH\t# \nFEA1 ;\t062D ;\tMA\t# ( ‎ﺡ‎ → ‎ح‎ ) ARABIC LETTER HAH ISOLATED FORM → ARABIC LETTER HAH\t# \n\n0685 ;\t062D 06DB ;\tMA\t# ( ‎څ‎ → ‎حۛ‎ ) ARABIC LETTER HAH WITH THREE DOTS ABOVE → ARABIC LETTER HAH, ARABIC SMALL HIGH THREE DOTS\t# \n\n0681 ;\t062D 0654 ;\tMA\t# ( ‎ځ‎ → ‎حٔ‎ ) ARABIC LETTER HAH WITH HAMZA ABOVE → ARABIC LETTER HAH, ARABIC HAMZA ABOVE\t# \n0772 ;\t062D 0654 ;\tMA\t# ( ‎ݲ‎ → ‎حٔ‎ ) ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE → ARABIC LETTER HAH, ARABIC HAMZA ABOVE\t# \n\nFCA9 ;\t062D 062C ;\tMA\t# ( ‎ﲩ‎ → ‎حج‎ ) ARABIC LIGATURE HAH WITH JEEM INITIAL FORM → ARABIC LETTER HAH, ARABIC LETTER JEEM\t# \nFC17 ;\t062D 062C ;\tMA\t# ( ‎ﰗ‎ → ‎حج‎ ) ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM → ARABIC LETTER HAH, ARABIC LETTER JEEM\t# \n\nFDBF ;\t062D 062C 0649 ;\tMA\t# ( ‎ﶿ‎ → ‎حجى‎ ) ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM → ARABIC LETTER HAH, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎حجي‎→\n\nFCAA ;\t062D 0645 ;\tMA\t# ( ‎ﲪ‎ → ‎حم‎ ) ARABIC LIGATURE HAH WITH MEEM INITIAL FORM → ARABIC LETTER HAH, ARABIC LETTER MEEM\t# \nFC18 ;\t062D 0645 ;\tMA\t# ( ‎ﰘ‎ → ‎حم‎ ) ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM → ARABIC LETTER HAH, ARABIC LETTER MEEM\t# \n\nFD5B ;\t062D 0645 0649 ;\tMA\t# ( ‎ﵛ‎ → ‎حمى‎ ) ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER HAH, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# \nFD5A ;\t062D 0645 0649 ;\tMA\t# ( ‎ﵚ‎ → ‎حمى‎ ) ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER HAH, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎حمي‎→\n\nFD1B ;\t062D 0649 ;\tMA\t# ( ‎ﴛ‎ → ‎حى‎ ) ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# \nFCFF ;\t062D 0649 ;\tMA\t# ( ‎ﳿ‎ → ‎حى‎ ) ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# \nFD1C ;\t062D 0649 ;\tMA\t# ( ‎ﴜ‎ → ‎حى‎ ) ARABIC LIGATURE HAH WITH YEH FINAL FORM → ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎حي‎→\nFD00 ;\t062D 0649 ;\tMA\t# ( ‎ﴀ‎ → ‎حى‎ ) ARABIC LIGATURE HAH WITH YEH ISOLATED FORM → ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎حي‎→\n\n1EE17 ;\t062E ;\tMA\t# ( ‎𞸗‎ → ‎خ‎ ) ARABIC MATHEMATICAL KHAH → ARABIC LETTER KHAH\t# \n1EE37 ;\t062E ;\tMA\t# ( ‎𞸷‎ → ‎خ‎ ) ARABIC MATHEMATICAL INITIAL KHAH → ARABIC LETTER KHAH\t# \n1EE57 ;\t062E ;\tMA\t# ( ‎𞹗‎ → ‎خ‎ ) ARABIC MATHEMATICAL TAILED KHAH → ARABIC LETTER KHAH\t# \n1EE77 ;\t062E ;\tMA\t# ( ‎𞹷‎ → ‎خ‎ ) ARABIC MATHEMATICAL STRETCHED KHAH → ARABIC LETTER KHAH\t# \n1EE97 ;\t062E ;\tMA\t# ( ‎𞺗‎ → ‎خ‎ ) ARABIC MATHEMATICAL LOOPED KHAH → ARABIC LETTER KHAH\t# \n1EEB7 ;\t062E ;\tMA\t# ( ‎𞺷‎ → ‎خ‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH → ARABIC LETTER KHAH\t# \nFEA7 ;\t062E ;\tMA\t# ( ‎ﺧ‎ → ‎خ‎ ) ARABIC LETTER KHAH INITIAL FORM → ARABIC LETTER KHAH\t# \nFEA8 ;\t062E ;\tMA\t# ( ‎ﺨ‎ → ‎خ‎ ) ARABIC LETTER KHAH MEDIAL FORM → ARABIC LETTER KHAH\t# \nFEA6 ;\t062E ;\tMA\t# ( ‎ﺦ‎ → ‎خ‎ ) ARABIC LETTER KHAH FINAL FORM → ARABIC LETTER KHAH\t# \nFEA5 ;\t062E ;\tMA\t# ( ‎ﺥ‎ → ‎خ‎ ) ARABIC LETTER KHAH ISOLATED FORM → ARABIC LETTER KHAH\t# \n\nFCAB ;\t062E 062C ;\tMA\t# ( ‎ﲫ‎ → ‎خج‎ ) ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM → ARABIC LETTER KHAH, ARABIC LETTER JEEM\t# \nFC19 ;\t062E 062C ;\tMA\t# ( ‎ﰙ‎ → ‎خج‎ ) ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM → ARABIC LETTER KHAH, ARABIC LETTER JEEM\t# \n\nFC1A ;\t062E 062D ;\tMA\t# ( ‎ﰚ‎ → ‎خح‎ ) ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM → ARABIC LETTER KHAH, ARABIC LETTER HAH\t# \n\nFCAC ;\t062E 0645 ;\tMA\t# ( ‎ﲬ‎ → ‎خم‎ ) ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM → ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \nFC1B ;\t062E 0645 ;\tMA\t# ( ‎ﰛ‎ → ‎خم‎ ) ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM → ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \n\nFD1F ;\t062E 0649 ;\tMA\t# ( ‎ﴟ‎ → ‎خى‎ ) ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# \nFD03 ;\t062E 0649 ;\tMA\t# ( ‎ﴃ‎ → ‎خى‎ ) ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# \nFD20 ;\t062E 0649 ;\tMA\t# ( ‎ﴠ‎ → ‎خى‎ ) ARABIC LIGATURE KHAH WITH YEH FINAL FORM → ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# →‎خي‎→\nFD04 ;\t062E 0649 ;\tMA\t# ( ‎ﴄ‎ → ‎خى‎ ) ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM → ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# →‎خي‎→\n\n102E1 ;\t062F ;\tMA\t#* ( 𐋡 → ‎د‎ ) COPTIC EPACT DIGIT ONE → ARABIC LETTER DAL\t# \n1EE03 ;\t062F ;\tMA\t# ( ‎𞸃‎ → ‎د‎ ) ARABIC MATHEMATICAL DAL → ARABIC LETTER DAL\t# \n1EE83 ;\t062F ;\tMA\t# ( ‎𞺃‎ → ‎د‎ ) ARABIC MATHEMATICAL LOOPED DAL → ARABIC LETTER DAL\t# \n1EEA3 ;\t062F ;\tMA\t# ( ‎𞺣‎ → ‎د‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK DAL → ARABIC LETTER DAL\t# \nFEAA ;\t062F ;\tMA\t# ( ‎ﺪ‎ → ‎د‎ ) ARABIC LETTER DAL FINAL FORM → ARABIC LETTER DAL\t# \nFEA9 ;\t062F ;\tMA\t# ( ‎ﺩ‎ → ‎د‎ ) ARABIC LETTER DAL ISOLATED FORM → ARABIC LETTER DAL\t# \n\n0688 ;\t062F 0615 ;\tMA\t# ( ‎ڈ‎ → ‎دؕ‎ ) ARABIC LETTER DDAL → ARABIC LETTER DAL, ARABIC SMALL HIGH TAH\t# \nFB89 ;\t062F 0615 ;\tMA\t# ( ‎ﮉ‎ → ‎دؕ‎ ) ARABIC LETTER DDAL FINAL FORM → ARABIC LETTER DAL, ARABIC SMALL HIGH TAH\t# →‎ڈ‎→\nFB88 ;\t062F 0615 ;\tMA\t# ( ‎ﮈ‎ → ‎دؕ‎ ) ARABIC LETTER DDAL ISOLATED FORM → ARABIC LETTER DAL, ARABIC SMALL HIGH TAH\t# →‎ڈ‎→\n\n068E ;\t062F 06DB ;\tMA\t# ( ‎ڎ‎ → ‎دۛ‎ ) ARABIC LETTER DUL → ARABIC LETTER DAL, ARABIC SMALL HIGH THREE DOTS\t# \nFB87 ;\t062F 06DB ;\tMA\t# ( ‎ﮇ‎ → ‎دۛ‎ ) ARABIC LETTER DUL FINAL FORM → ARABIC LETTER DAL, ARABIC SMALL HIGH THREE DOTS\t# →‎ڎ‎→\nFB86 ;\t062F 06DB ;\tMA\t# ( ‎ﮆ‎ → ‎دۛ‎ ) ARABIC LETTER DUL ISOLATED FORM → ARABIC LETTER DAL, ARABIC SMALL HIGH THREE DOTS\t# →‎ڎ‎→\n068F ;\t062F 06DB ;\tMA\t# ( ‎ڏ‎ → ‎دۛ‎ ) ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS → ARABIC LETTER DAL, ARABIC SMALL HIGH THREE DOTS\t# →‎ڎ‎→\n\n06EE ;\t062F 0302 ;\tMA\t# ( ‎ۮ‎ → ‎د̂‎ ) ARABIC LETTER DAL WITH INVERTED V → ARABIC LETTER DAL, COMBINING CIRCUMFLEX ACCENT\t# →‎دٛ‎→\n\n08AE ;\t062F 0324 0323 ;\tMA\t# ( ‎ࢮ‎ → ‎د̤̣‎ ) ARABIC LETTER DAL WITH THREE DOTS BELOW → ARABIC LETTER DAL, COMBINING DIAERESIS BELOW, COMBINING DOT BELOW\t# →‎د࣮࣭‎→\n\n1EE18 ;\t0630 ;\tMA\t# ( ‎𞸘‎ → ‎ذ‎ ) ARABIC MATHEMATICAL THAL → ARABIC LETTER THAL\t# \n1EE98 ;\t0630 ;\tMA\t# ( ‎𞺘‎ → ‎ذ‎ ) ARABIC MATHEMATICAL LOOPED THAL → ARABIC LETTER THAL\t# \n1EEB8 ;\t0630 ;\tMA\t# ( ‎𞺸‎ → ‎ذ‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK THAL → ARABIC LETTER THAL\t# \nFEAC ;\t0630 ;\tMA\t# ( ‎ﺬ‎ → ‎ذ‎ ) ARABIC LETTER THAL FINAL FORM → ARABIC LETTER THAL\t# \nFEAB ;\t0630 ;\tMA\t# ( ‎ﺫ‎ → ‎ذ‎ ) ARABIC LETTER THAL ISOLATED FORM → ARABIC LETTER THAL\t# \n\nFC5B ;\t0630 0670 ;\tMA\t# ( ‎ﱛ‎ → ‎ذٰ‎ ) ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM → ARABIC LETTER THAL, ARABIC LETTER SUPERSCRIPT ALEF\t# \n\n068B ;\t068A 0615 ;\tMA\t# ( ‎ڋ‎ → ‎ڊؕ‎ ) ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH → ARABIC LETTER DAL WITH DOT BELOW, ARABIC SMALL HIGH TAH\t# \n\nFB85 ;\t068C ;\tMA\t# ( ‎ﮅ‎ → ‎ڌ‎ ) ARABIC LETTER DAHAL FINAL FORM → ARABIC LETTER DAHAL\t# \nFB84 ;\t068C ;\tMA\t# ( ‎ﮄ‎ → ‎ڌ‎ ) ARABIC LETTER DAHAL ISOLATED FORM → ARABIC LETTER DAHAL\t# \n\nFB83 ;\t068D ;\tMA\t# ( ‎ﮃ‎ → ‎ڍ‎ ) ARABIC LETTER DDAHAL FINAL FORM → ARABIC LETTER DDAHAL\t# \nFB82 ;\t068D ;\tMA\t# ( ‎ﮂ‎ → ‎ڍ‎ ) ARABIC LETTER DDAHAL ISOLATED FORM → ARABIC LETTER DDAHAL\t# \n\n1EE13 ;\t0631 ;\tMA\t# ( ‎𞸓‎ → ‎ر‎ ) ARABIC MATHEMATICAL REH → ARABIC LETTER REH\t# \n1EE93 ;\t0631 ;\tMA\t# ( ‎𞺓‎ → ‎ر‎ ) ARABIC MATHEMATICAL LOOPED REH → ARABIC LETTER REH\t# \n1EEB3 ;\t0631 ;\tMA\t# ( ‎𞺳‎ → ‎ر‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK REH → ARABIC LETTER REH\t# \nFEAE ;\t0631 ;\tMA\t# ( ‎ﺮ‎ → ‎ر‎ ) ARABIC LETTER REH FINAL FORM → ARABIC LETTER REH\t# \nFEAD ;\t0631 ;\tMA\t# ( ‎ﺭ‎ → ‎ر‎ ) ARABIC LETTER REH ISOLATED FORM → ARABIC LETTER REH\t# \n\n0691 ;\t0631 0615 ;\tMA\t# ( ‎ڑ‎ → ‎رؕ‎ ) ARABIC LETTER RREH → ARABIC LETTER REH, ARABIC SMALL HIGH TAH\t# \nFB8D ;\t0631 0615 ;\tMA\t# ( ‎ﮍ‎ → ‎رؕ‎ ) ARABIC LETTER RREH FINAL FORM → ARABIC LETTER REH, ARABIC SMALL HIGH TAH\t# →‎ڑ‎→\nFB8C ;\t0631 0615 ;\tMA\t# ( ‎ﮌ‎ → ‎رؕ‎ ) ARABIC LETTER RREH ISOLATED FORM → ARABIC LETTER REH, ARABIC SMALL HIGH TAH\t# →‎ڑ‎→\n\n0698 ;\t0631 06DB ;\tMA\t# ( ‎ژ‎ → ‎رۛ‎ ) ARABIC LETTER JEH → ARABIC LETTER REH, ARABIC SMALL HIGH THREE DOTS\t# \nFB8B ;\t0631 06DB ;\tMA\t# ( ‎ﮋ‎ → ‎رۛ‎ ) ARABIC LETTER JEH FINAL FORM → ARABIC LETTER REH, ARABIC SMALL HIGH THREE DOTS\t# →‎ژ‎→\nFB8A ;\t0631 06DB ;\tMA\t# ( ‎ﮊ‎ → ‎رۛ‎ ) ARABIC LETTER JEH ISOLATED FORM → ARABIC LETTER REH, ARABIC SMALL HIGH THREE DOTS\t# →‎ژ‎→\n\n0692 ;\t0631 0306 ;\tMA\t# ( ‎ڒ‎ → ‎ر̆‎ ) ARABIC LETTER REH WITH SMALL V → ARABIC LETTER REH, COMBINING BREVE\t# →‎رٚ‎→\n\n08B9 ;\t0631 0306 0307 ;\tMA\t# ( ‎ࢹ‎ → ‎ر̆̇‎ ) ARABIC LETTER REH WITH SMALL NOON ABOVE → ARABIC LETTER REH, COMBINING BREVE, COMBINING DOT ABOVE\t# →‎رۨ‎→\n\n06EF ;\t0631 0302 ;\tMA\t# ( ‎ۯ‎ → ‎ر̂‎ ) ARABIC LETTER REH WITH INVERTED V → ARABIC LETTER REH, COMBINING CIRCUMFLEX ACCENT\t# →‎رٛ‎→\n\n076C ;\t0631 0654 ;\tMA\t# ( ‎ݬ‎ → ‎رٔ‎ ) ARABIC LETTER REH WITH HAMZA ABOVE → ARABIC LETTER REH, ARABIC HAMZA ABOVE\t# \n\nFC5C ;\t0631 0670 ;\tMA\t# ( ‎ﱜ‎ → ‎رٰ‎ ) ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM → ARABIC LETTER REH, ARABIC LETTER SUPERSCRIPT ALEF\t# \n\nFDF6 ;\t0631 0633 0648 0644 ;\tMA\t# ( ‎ﷶ‎ → ‎رسول‎ ) ARABIC LIGATURE RASOUL ISOLATED FORM → ARABIC LETTER REH, ARABIC LETTER SEEN, ARABIC LETTER WAW, ARABIC LETTER LAM\t# \n\nFDFC ;\t0631 0649 006C 0644 ;\tMA\t#* ( ‎﷼‎ → ‎رىlل‎ ) RIAL SIGN → ARABIC LETTER REH, ARABIC LETTER ALEF MAKSURA, LATIN SMALL LETTER L, ARABIC LETTER LAM\t# →‎ریال‎→\n20C1 ;\t0631 0649 006C 0644 ;\tMA\t#* ( ⃁ → ‎رىlل‎ ) SAUDI RIYAL SIGN → ARABIC LETTER REH, ARABIC LETTER ALEF MAKSURA, LATIN SMALL LETTER L, ARABIC LETTER LAM\t# →‎﷼‎→→‎ریال‎→\n\n1EE06 ;\t0632 ;\tMA\t# ( ‎𞸆‎ → ‎ز‎ ) ARABIC MATHEMATICAL ZAIN → ARABIC LETTER ZAIN\t# \n1EE86 ;\t0632 ;\tMA\t# ( ‎𞺆‎ → ‎ز‎ ) ARABIC MATHEMATICAL LOOPED ZAIN → ARABIC LETTER ZAIN\t# \n1EEA6 ;\t0632 ;\tMA\t# ( ‎𞺦‎ → ‎ز‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN → ARABIC LETTER ZAIN\t# \nFEB0 ;\t0632 ;\tMA\t# ( ‎ﺰ‎ → ‎ز‎ ) ARABIC LETTER ZAIN FINAL FORM → ARABIC LETTER ZAIN\t# \nFEAF ;\t0632 ;\tMA\t# ( ‎ﺯ‎ → ‎ز‎ ) ARABIC LETTER ZAIN ISOLATED FORM → ARABIC LETTER ZAIN\t# \n\n08B2 ;\t0632 0302 ;\tMA\t# ( ‎ࢲ‎ → ‎ز̂‎ ) ARABIC LETTER ZAIN WITH INVERTED V ABOVE → ARABIC LETTER ZAIN, COMBINING CIRCUMFLEX ACCENT\t# →‎زٛ‎→\n\n0771 ;\t0697 0615 ;\tMA\t# ( ‎ݱ‎ → ‎ڗؕ‎ ) ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS → ARABIC LETTER REH WITH TWO DOTS ABOVE, ARABIC SMALL HIGH TAH\t# \n\n1EE0E ;\t0633 ;\tMA\t# ( ‎𞸎‎ → ‎س‎ ) ARABIC MATHEMATICAL SEEN → ARABIC LETTER SEEN\t# \n1EE2E ;\t0633 ;\tMA\t# ( ‎𞸮‎ → ‎س‎ ) ARABIC MATHEMATICAL INITIAL SEEN → ARABIC LETTER SEEN\t# \n1EE4E ;\t0633 ;\tMA\t# ( ‎𞹎‎ → ‎س‎ ) ARABIC MATHEMATICAL TAILED SEEN → ARABIC LETTER SEEN\t# \n1EE6E ;\t0633 ;\tMA\t# ( ‎𞹮‎ → ‎س‎ ) ARABIC MATHEMATICAL STRETCHED SEEN → ARABIC LETTER SEEN\t# \n1EE8E ;\t0633 ;\tMA\t# ( ‎𞺎‎ → ‎س‎ ) ARABIC MATHEMATICAL LOOPED SEEN → ARABIC LETTER SEEN\t# \n1EEAE ;\t0633 ;\tMA\t# ( ‎𞺮‎ → ‎س‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN → ARABIC LETTER SEEN\t# \nFEB3 ;\t0633 ;\tMA\t# ( ‎ﺳ‎ → ‎س‎ ) ARABIC LETTER SEEN INITIAL FORM → ARABIC LETTER SEEN\t# \nFEB4 ;\t0633 ;\tMA\t# ( ‎ﺴ‎ → ‎س‎ ) ARABIC LETTER SEEN MEDIAL FORM → ARABIC LETTER SEEN\t# \nFEB2 ;\t0633 ;\tMA\t# ( ‎ﺲ‎ → ‎س‎ ) ARABIC LETTER SEEN FINAL FORM → ARABIC LETTER SEEN\t# \nFEB1 ;\t0633 ;\tMA\t# ( ‎ﺱ‎ → ‎س‎ ) ARABIC LETTER SEEN ISOLATED FORM → ARABIC LETTER SEEN\t# \n\n0634 ;\t0633 06DB ;\tMA\t# ( ‎ش‎ → ‎سۛ‎ ) ARABIC LETTER SHEEN → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# \n1EE14 ;\t0633 06DB ;\tMA\t# ( ‎𞸔‎ → ‎سۛ‎ ) ARABIC MATHEMATICAL SHEEN → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\n1EE34 ;\t0633 06DB ;\tMA\t# ( ‎𞸴‎ → ‎سۛ‎ ) ARABIC MATHEMATICAL INITIAL SHEEN → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\n1EE54 ;\t0633 06DB ;\tMA\t# ( ‎𞹔‎ → ‎سۛ‎ ) ARABIC MATHEMATICAL TAILED SHEEN → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\n1EE74 ;\t0633 06DB ;\tMA\t# ( ‎𞹴‎ → ‎سۛ‎ ) ARABIC MATHEMATICAL STRETCHED SHEEN → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\n1EE94 ;\t0633 06DB ;\tMA\t# ( ‎𞺔‎ → ‎سۛ‎ ) ARABIC MATHEMATICAL LOOPED SHEEN → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\n1EEB4 ;\t0633 06DB ;\tMA\t# ( ‎𞺴‎ → ‎سۛ‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\nFEB7 ;\t0633 06DB ;\tMA\t# ( ‎ﺷ‎ → ‎سۛ‎ ) ARABIC LETTER SHEEN INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\nFEB8 ;\t0633 06DB ;\tMA\t# ( ‎ﺸ‎ → ‎سۛ‎ ) ARABIC LETTER SHEEN MEDIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\nFEB6 ;\t0633 06DB ;\tMA\t# ( ‎ﺶ‎ → ‎سۛ‎ ) ARABIC LETTER SHEEN FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\nFEB5 ;\t0633 06DB ;\tMA\t# ( ‎ﺵ‎ → ‎سۛ‎ ) ARABIC LETTER SHEEN ISOLATED FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS\t# →‎ش‎→\n\n077E ;\t0633 0302 ;\tMA\t# ( ‎ݾ‎ → ‎س̂‎ ) ARABIC LETTER SEEN WITH INVERTED V → ARABIC LETTER SEEN, COMBINING CIRCUMFLEX ACCENT\t# →‎سٛ‎→\n\nFD31 ;\t0633 006F ;\tMA\t# ( ‎ﴱ‎ → ‎سo‎ ) ARABIC LIGATURE SEEN WITH HEH INITIAL FORM → ARABIC LETTER SEEN, LATIN SMALL LETTER O\t# →‎سه‎→\nFCE8 ;\t0633 006F ;\tMA\t# ( ‎ﳨ‎ → ‎سo‎ ) ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM → ARABIC LETTER SEEN, LATIN SMALL LETTER O\t# →‎سه‎→\n\nFD32 ;\t0633 06DB 006F ;\tMA\t# ( ‎ﴲ‎ → ‎سۛo‎ ) ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, LATIN SMALL LETTER O\t# →‎شه‎→\nFCEA ;\t0633 06DB 006F ;\tMA\t# ( ‎ﳪ‎ → ‎سۛo‎ ) ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, LATIN SMALL LETTER O\t# →‎شه‎→\n\nFCAD ;\t0633 062C ;\tMA\t# ( ‎ﲭ‎ → ‎سج‎ ) ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER JEEM\t# \nFD34 ;\t0633 062C ;\tMA\t# ( ‎ﴴ‎ → ‎سج‎ ) ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER JEEM\t# \nFC1C ;\t0633 062C ;\tMA\t# ( ‎ﰜ‎ → ‎سج‎ ) ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM → ARABIC LETTER SEEN, ARABIC LETTER JEEM\t# \n\nFD2D ;\t0633 06DB 062C ;\tMA\t# ( ‎ﴭ‎ → ‎سۛج‎ ) ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER JEEM\t# →‎شج‎→\nFD37 ;\t0633 06DB 062C ;\tMA\t# ( ‎ﴷ‎ → ‎سۛج‎ ) ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER JEEM\t# →‎شج‎→\nFD25 ;\t0633 06DB 062C ;\tMA\t# ( ‎ﴥ‎ → ‎سۛج‎ ) ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER JEEM\t# →‎شج‎→\nFD09 ;\t0633 06DB 062C ;\tMA\t# ( ‎ﴉ‎ → ‎سۛج‎ ) ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER JEEM\t# →‎شج‎→\n\nFD5D ;\t0633 062C 062D ;\tMA\t# ( ‎ﵝ‎ → ‎سجح‎ ) ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER JEEM, ARABIC LETTER HAH\t# \n\nFD5E ;\t0633 062C 0649 ;\tMA\t# ( ‎ﵞ‎ → ‎سجى‎ ) ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER SEEN, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# \n\nFD69 ;\t0633 06DB 062C 0649 ;\tMA\t# ( ‎ﵩ‎ → ‎سۛجى‎ ) ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎شجي‎→\n\nFCAE ;\t0633 062D ;\tMA\t# ( ‎ﲮ‎ → ‎سح‎ ) ARABIC LIGATURE SEEN WITH HAH INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER HAH\t# \nFD35 ;\t0633 062D ;\tMA\t# ( ‎ﴵ‎ → ‎سح‎ ) ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER HAH\t# \nFC1D ;\t0633 062D ;\tMA\t# ( ‎ﰝ‎ → ‎سح‎ ) ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM → ARABIC LETTER SEEN, ARABIC LETTER HAH\t# \n\nFD2E ;\t0633 06DB 062D ;\tMA\t# ( ‎ﴮ‎ → ‎سۛح‎ ) ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER HAH\t# →‎شح‎→\nFD38 ;\t0633 06DB 062D ;\tMA\t# ( ‎ﴸ‎ → ‎سۛح‎ ) ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER HAH\t# →‎شح‎→\nFD26 ;\t0633 06DB 062D ;\tMA\t# ( ‎ﴦ‎ → ‎سۛح‎ ) ARABIC LIGATURE SHEEN WITH HAH FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER HAH\t# →‎شح‎→\nFD0A ;\t0633 06DB 062D ;\tMA\t# ( ‎ﴊ‎ → ‎سۛح‎ ) ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER HAH\t# →‎شح‎→\n\nFD5C ;\t0633 062D 062C ;\tMA\t# ( ‎ﵜ‎ → ‎سحج‎ ) ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER HAH, ARABIC LETTER JEEM\t# \n\nFD68 ;\t0633 06DB 062D 0645 ;\tMA\t# ( ‎ﵨ‎ → ‎سۛحم‎ ) ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER HAH, ARABIC LETTER MEEM\t# →‎شحم‎→\nFD67 ;\t0633 06DB 062D 0645 ;\tMA\t# ( ‎ﵧ‎ → ‎سۛحم‎ ) ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER HAH, ARABIC LETTER MEEM\t# →‎شحم‎→\n\nFDAA ;\t0633 06DB 062D 0649 ;\tMA\t# ( ‎ﶪ‎ → ‎سۛحى‎ ) ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎شحي‎→\n\nFCAF ;\t0633 062E ;\tMA\t# ( ‎ﲯ‎ → ‎سخ‎ ) ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER KHAH\t# \nFD36 ;\t0633 062E ;\tMA\t# ( ‎ﴶ‎ → ‎سخ‎ ) ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER KHAH\t# \nFC1E ;\t0633 062E ;\tMA\t# ( ‎ﰞ‎ → ‎سخ‎ ) ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM → ARABIC LETTER SEEN, ARABIC LETTER KHAH\t# \n\nFD2F ;\t0633 06DB 062E ;\tMA\t# ( ‎ﴯ‎ → ‎سۛخ‎ ) ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER KHAH\t# →‎شخ‎→\nFD39 ;\t0633 06DB 062E ;\tMA\t# ( ‎ﴹ‎ → ‎سۛخ‎ ) ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER KHAH\t# →‎شخ‎→\nFD27 ;\t0633 06DB 062E ;\tMA\t# ( ‎ﴧ‎ → ‎سۛخ‎ ) ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER KHAH\t# →‎شخ‎→\nFD0B ;\t0633 06DB 062E ;\tMA\t# ( ‎ﴋ‎ → ‎سۛخ‎ ) ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER KHAH\t# →‎شخ‎→\n\nFDA8 ;\t0633 062E 0649 ;\tMA\t# ( ‎ﶨ‎ → ‎سخى‎ ) ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER SEEN, ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# \nFDC6 ;\t0633 062E 0649 ;\tMA\t# ( ‎ﷆ‎ → ‎سخى‎ ) ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM → ARABIC LETTER SEEN, ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# →‎سخي‎→\n\nFD2A ;\t0633 0631 ;\tMA\t# ( ‎ﴪ‎ → ‎سر‎ ) ARABIC LIGATURE SEEN WITH REH FINAL FORM → ARABIC LETTER SEEN, ARABIC LETTER REH\t# \nFD0E ;\t0633 0631 ;\tMA\t# ( ‎ﴎ‎ → ‎سر‎ ) ARABIC LIGATURE SEEN WITH REH ISOLATED FORM → ARABIC LETTER SEEN, ARABIC LETTER REH\t# \n\nFD29 ;\t0633 06DB 0631 ;\tMA\t# ( ‎ﴩ‎ → ‎سۛر‎ ) ARABIC LIGATURE SHEEN WITH REH FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER REH\t# →‎شر‎→\nFD0D ;\t0633 06DB 0631 ;\tMA\t# ( ‎ﴍ‎ → ‎سۛر‎ ) ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER REH\t# →‎شر‎→\n\nFCB0 ;\t0633 0645 ;\tMA\t# ( ‎ﲰ‎ → ‎سم‎ ) ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER MEEM\t# \nFCE7 ;\t0633 0645 ;\tMA\t# ( ‎ﳧ‎ → ‎سم‎ ) ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER MEEM\t# \nFC1F ;\t0633 0645 ;\tMA\t# ( ‎ﰟ‎ → ‎سم‎ ) ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM → ARABIC LETTER SEEN, ARABIC LETTER MEEM\t# \n\nFD30 ;\t0633 06DB 0645 ;\tMA\t# ( ‎ﴰ‎ → ‎سۛم‎ ) ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM\t# →‎شم‎→\nFCE9 ;\t0633 06DB 0645 ;\tMA\t# ( ‎ﳩ‎ → ‎سۛم‎ ) ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM\t# →‎شم‎→\nFD28 ;\t0633 06DB 0645 ;\tMA\t# ( ‎ﴨ‎ → ‎سۛم‎ ) ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM\t# →‎شم‎→\nFD0C ;\t0633 06DB 0645 ;\tMA\t# ( ‎ﴌ‎ → ‎سۛم‎ ) ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM\t# →‎شم‎→\n\nFD61 ;\t0633 0645 062C ;\tMA\t# ( ‎ﵡ‎ → ‎سمج‎ ) ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER MEEM, ARABIC LETTER JEEM\t# \n\nFD60 ;\t0633 0645 062D ;\tMA\t# ( ‎ﵠ‎ → ‎سمح‎ ) ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \nFD5F ;\t0633 0645 062D ;\tMA\t# ( ‎ﵟ‎ → ‎سمح‎ ) ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM → ARABIC LETTER SEEN, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \n\nFD6B ;\t0633 06DB 0645 062E ;\tMA\t# ( ‎ﵫ‎ → ‎سۛمخ‎ ) ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM, ARABIC LETTER KHAH\t# →‎شمخ‎→\nFD6A ;\t0633 06DB 0645 062E ;\tMA\t# ( ‎ﵪ‎ → ‎سۛمخ‎ ) ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM, ARABIC LETTER KHAH\t# →‎شمخ‎→\n\nFD63 ;\t0633 0645 0645 ;\tMA\t# ( ‎ﵣ‎ → ‎سمم‎ ) ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \nFD62 ;\t0633 0645 0645 ;\tMA\t# ( ‎ﵢ‎ → ‎سمم‎ ) ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM → ARABIC LETTER SEEN, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \n\nFD6D ;\t0633 06DB 0645 0645 ;\tMA\t# ( ‎ﵭ‎ → ‎سۛمم‎ ) ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# →‎شمم‎→\nFD6C ;\t0633 06DB 0645 0645 ;\tMA\t# ( ‎ﵬ‎ → ‎سۛمم‎ ) ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# →‎شمم‎→\n\nFD17 ;\t0633 0649 ;\tMA\t# ( ‎ﴗ‎ → ‎سى‎ ) ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER SEEN, ARABIC LETTER ALEF MAKSURA\t# \nFCFB ;\t0633 0649 ;\tMA\t# ( ‎ﳻ‎ → ‎سى‎ ) ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER SEEN, ARABIC LETTER ALEF MAKSURA\t# \nFD18 ;\t0633 0649 ;\tMA\t# ( ‎ﴘ‎ → ‎سى‎ ) ARABIC LIGATURE SEEN WITH YEH FINAL FORM → ARABIC LETTER SEEN, ARABIC LETTER ALEF MAKSURA\t# →‎سي‎→\nFCFC ;\t0633 0649 ;\tMA\t# ( ‎ﳼ‎ → ‎سى‎ ) ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM → ARABIC LETTER SEEN, ARABIC LETTER ALEF MAKSURA\t# →‎سي‎→\n\nFD19 ;\t0633 06DB 0649 ;\tMA\t# ( ‎ﴙ‎ → ‎سۛى‎ ) ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ALEF MAKSURA\t# →‎شى‎→\nFCFD ;\t0633 06DB 0649 ;\tMA\t# ( ‎ﳽ‎ → ‎سۛى‎ ) ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ALEF MAKSURA\t# →‎شى‎→\nFD1A ;\t0633 06DB 0649 ;\tMA\t# ( ‎ﴚ‎ → ‎سۛى‎ ) ARABIC LIGATURE SHEEN WITH YEH FINAL FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ALEF MAKSURA\t# →‎شي‎→\nFCFE ;\t0633 06DB 0649 ;\tMA\t# ( ‎ﳾ‎ → ‎سۛى‎ ) ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM → ARABIC LETTER SEEN, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ALEF MAKSURA\t# →‎شي‎→\n\n102F2 ;\t0635 ;\tMA\t#* ( 𐋲 → ‎ص‎ ) COPTIC EPACT NUMBER NINETY → ARABIC LETTER SAD\t# \n1EE11 ;\t0635 ;\tMA\t# ( ‎𞸑‎ → ‎ص‎ ) ARABIC MATHEMATICAL SAD → ARABIC LETTER SAD\t# \n1EE31 ;\t0635 ;\tMA\t# ( ‎𞸱‎ → ‎ص‎ ) ARABIC MATHEMATICAL INITIAL SAD → ARABIC LETTER SAD\t# \n1EE51 ;\t0635 ;\tMA\t# ( ‎𞹑‎ → ‎ص‎ ) ARABIC MATHEMATICAL TAILED SAD → ARABIC LETTER SAD\t# \n1EE71 ;\t0635 ;\tMA\t# ( ‎𞹱‎ → ‎ص‎ ) ARABIC MATHEMATICAL STRETCHED SAD → ARABIC LETTER SAD\t# \n1EE91 ;\t0635 ;\tMA\t# ( ‎𞺑‎ → ‎ص‎ ) ARABIC MATHEMATICAL LOOPED SAD → ARABIC LETTER SAD\t# \n1EEB1 ;\t0635 ;\tMA\t# ( ‎𞺱‎ → ‎ص‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK SAD → ARABIC LETTER SAD\t# \nFEBB ;\t0635 ;\tMA\t# ( ‎ﺻ‎ → ‎ص‎ ) ARABIC LETTER SAD INITIAL FORM → ARABIC LETTER SAD\t# \nFEBC ;\t0635 ;\tMA\t# ( ‎ﺼ‎ → ‎ص‎ ) ARABIC LETTER SAD MEDIAL FORM → ARABIC LETTER SAD\t# \nFEBA ;\t0635 ;\tMA\t# ( ‎ﺺ‎ → ‎ص‎ ) ARABIC LETTER SAD FINAL FORM → ARABIC LETTER SAD\t# \nFEB9 ;\t0635 ;\tMA\t# ( ‎ﺹ‎ → ‎ص‎ ) ARABIC LETTER SAD ISOLATED FORM → ARABIC LETTER SAD\t# \n\n069E ;\t0635 06DB ;\tMA\t# ( ‎ڞ‎ → ‎صۛ‎ ) ARABIC LETTER SAD WITH THREE DOTS ABOVE → ARABIC LETTER SAD, ARABIC SMALL HIGH THREE DOTS\t# \n\n08AF ;\t0635 0324 0323 ;\tMA\t# ( ‎ࢯ‎ → ‎ص̤̣‎ ) ARABIC LETTER SAD WITH THREE DOTS BELOW → ARABIC LETTER SAD, COMBINING DIAERESIS BELOW, COMBINING DOT BELOW\t# →‎ص࣮࣭‎→\n\nFCB1 ;\t0635 062D ;\tMA\t# ( ‎ﲱ‎ → ‎صح‎ ) ARABIC LIGATURE SAD WITH HAH INITIAL FORM → ARABIC LETTER SAD, ARABIC LETTER HAH\t# \nFC20 ;\t0635 062D ;\tMA\t# ( ‎ﰠ‎ → ‎صح‎ ) ARABIC LIGATURE SAD WITH HAH ISOLATED FORM → ARABIC LETTER SAD, ARABIC LETTER HAH\t# \n\nFD65 ;\t0635 062D 062D ;\tMA\t# ( ‎ﵥ‎ → ‎صحح‎ ) ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM → ARABIC LETTER SAD, ARABIC LETTER HAH, ARABIC LETTER HAH\t# \nFD64 ;\t0635 062D 062D ;\tMA\t# ( ‎ﵤ‎ → ‎صحح‎ ) ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM → ARABIC LETTER SAD, ARABIC LETTER HAH, ARABIC LETTER HAH\t# \n\nFDA9 ;\t0635 062D 0649 ;\tMA\t# ( ‎ﶩ‎ → ‎صحى‎ ) ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM → ARABIC LETTER SAD, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎صحي‎→\n\nFCB2 ;\t0635 062E ;\tMA\t# ( ‎ﲲ‎ → ‎صخ‎ ) ARABIC LIGATURE SAD WITH KHAH INITIAL FORM → ARABIC LETTER SAD, ARABIC LETTER KHAH\t# \n\nFD2B ;\t0635 0631 ;\tMA\t# ( ‎ﴫ‎ → ‎صر‎ ) ARABIC LIGATURE SAD WITH REH FINAL FORM → ARABIC LETTER SAD, ARABIC LETTER REH\t# \nFD0F ;\t0635 0631 ;\tMA\t# ( ‎ﴏ‎ → ‎صر‎ ) ARABIC LIGATURE SAD WITH REH ISOLATED FORM → ARABIC LETTER SAD, ARABIC LETTER REH\t# \n\nFDF5 ;\t0635 0644 0639 0645 ;\tMA\t# ( ‎ﷵ‎ → ‎صلعم‎ ) ARABIC LIGATURE SALAM ISOLATED FORM → ARABIC LETTER SAD, ARABIC LETTER LAM, ARABIC LETTER AIN, ARABIC LETTER MEEM\t# \n\nFDF9 ;\t0635 0644 0649 ;\tMA\t# ( ‎ﷹ‎ → ‎صلى‎ ) ARABIC LIGATURE SALLA ISOLATED FORM → ARABIC LETTER SAD, ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA\t# \nFDF0 ;\t0635 0644 0649 ;\tMA\t# ( ‎ﷰ‎ → ‎صلى‎ ) ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM → ARABIC LETTER SAD, ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA\t# →‎صلے‎→\n\nFDFA ;\t0635 0644 0649 0020 006C 0644 0644 006F 0020 0639 0644 0649 006F 0020 0648 0633 0644 0645 ;\tMA\t#* ( ‎ﷺ‎ → ‎صلى lللo علىo وسلم‎ ) ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM → ARABIC LETTER SAD, ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA, SPACE, LATIN SMALL LETTER L, ARABIC LETTER LAM, ARABIC LETTER LAM, LATIN SMALL LETTER O, SPACE, ARABIC LETTER AIN, ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA, LATIN SMALL LETTER O, SPACE, ARABIC LETTER WAW, ARABIC LETTER SEEN, ARABIC LETTER LAM, ARABIC LETTER MEEM\t# →‎صلى الله عليه وسلم‎→\n\nFCB3 ;\t0635 0645 ;\tMA\t# ( ‎ﲳ‎ → ‎صم‎ ) ARABIC LIGATURE SAD WITH MEEM INITIAL FORM → ARABIC LETTER SAD, ARABIC LETTER MEEM\t# \nFC21 ;\t0635 0645 ;\tMA\t# ( ‎ﰡ‎ → ‎صم‎ ) ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM → ARABIC LETTER SAD, ARABIC LETTER MEEM\t# \n\nFDC5 ;\t0635 0645 0645 ;\tMA\t# ( ‎ﷅ‎ → ‎صمم‎ ) ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM → ARABIC LETTER SAD, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \nFD66 ;\t0635 0645 0645 ;\tMA\t# ( ‎ﵦ‎ → ‎صمم‎ ) ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM → ARABIC LETTER SAD, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \n\nFD21 ;\t0635 0649 ;\tMA\t# ( ‎ﴡ‎ → ‎صى‎ ) ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER SAD, ARABIC LETTER ALEF MAKSURA\t# \nFD05 ;\t0635 0649 ;\tMA\t# ( ‎ﴅ‎ → ‎صى‎ ) ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER SAD, ARABIC LETTER ALEF MAKSURA\t# \nFD22 ;\t0635 0649 ;\tMA\t# ( ‎ﴢ‎ → ‎صى‎ ) ARABIC LIGATURE SAD WITH YEH FINAL FORM → ARABIC LETTER SAD, ARABIC LETTER ALEF MAKSURA\t# →‎صي‎→\nFD06 ;\t0635 0649 ;\tMA\t# ( ‎ﴆ‎ → ‎صى‎ ) ARABIC LIGATURE SAD WITH YEH ISOLATED FORM → ARABIC LETTER SAD, ARABIC LETTER ALEF MAKSURA\t# →‎صي‎→\n\n1EE19 ;\t0636 ;\tMA\t# ( ‎𞸙‎ → ‎ض‎ ) ARABIC MATHEMATICAL DAD → ARABIC LETTER DAD\t# \n1EE39 ;\t0636 ;\tMA\t# ( ‎𞸹‎ → ‎ض‎ ) ARABIC MATHEMATICAL INITIAL DAD → ARABIC LETTER DAD\t# \n1EE59 ;\t0636 ;\tMA\t# ( ‎𞹙‎ → ‎ض‎ ) ARABIC MATHEMATICAL TAILED DAD → ARABIC LETTER DAD\t# \n1EE79 ;\t0636 ;\tMA\t# ( ‎𞹹‎ → ‎ض‎ ) ARABIC MATHEMATICAL STRETCHED DAD → ARABIC LETTER DAD\t# \n1EE99 ;\t0636 ;\tMA\t# ( ‎𞺙‎ → ‎ض‎ ) ARABIC MATHEMATICAL LOOPED DAD → ARABIC LETTER DAD\t# \n1EEB9 ;\t0636 ;\tMA\t# ( ‎𞺹‎ → ‎ض‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK DAD → ARABIC LETTER DAD\t# \nFEBF ;\t0636 ;\tMA\t# ( ‎ﺿ‎ → ‎ض‎ ) ARABIC LETTER DAD INITIAL FORM → ARABIC LETTER DAD\t# \nFEC0 ;\t0636 ;\tMA\t# ( ‎ﻀ‎ → ‎ض‎ ) ARABIC LETTER DAD MEDIAL FORM → ARABIC LETTER DAD\t# \nFEBE ;\t0636 ;\tMA\t# ( ‎ﺾ‎ → ‎ض‎ ) ARABIC LETTER DAD FINAL FORM → ARABIC LETTER DAD\t# \nFEBD ;\t0636 ;\tMA\t# ( ‎ﺽ‎ → ‎ض‎ ) ARABIC LETTER DAD ISOLATED FORM → ARABIC LETTER DAD\t# \n\nFCB4 ;\t0636 062C ;\tMA\t# ( ‎ﲴ‎ → ‎ضج‎ ) ARABIC LIGATURE DAD WITH JEEM INITIAL FORM → ARABIC LETTER DAD, ARABIC LETTER JEEM\t# \nFC22 ;\t0636 062C ;\tMA\t# ( ‎ﰢ‎ → ‎ضج‎ ) ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM → ARABIC LETTER DAD, ARABIC LETTER JEEM\t# \n\nFCB5 ;\t0636 062D ;\tMA\t# ( ‎ﲵ‎ → ‎ضح‎ ) ARABIC LIGATURE DAD WITH HAH INITIAL FORM → ARABIC LETTER DAD, ARABIC LETTER HAH\t# \nFC23 ;\t0636 062D ;\tMA\t# ( ‎ﰣ‎ → ‎ضح‎ ) ARABIC LIGATURE DAD WITH HAH ISOLATED FORM → ARABIC LETTER DAD, ARABIC LETTER HAH\t# \n\nFD6E ;\t0636 062D 0649 ;\tMA\t# ( ‎ﵮ‎ → ‎ضحى‎ ) ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER DAD, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# \nFDAB ;\t0636 062D 0649 ;\tMA\t# ( ‎ﶫ‎ → ‎ضحى‎ ) ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM → ARABIC LETTER DAD, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎ضحي‎→\n\nFCB6 ;\t0636 062E ;\tMA\t# ( ‎ﲶ‎ → ‎ضخ‎ ) ARABIC LIGATURE DAD WITH KHAH INITIAL FORM → ARABIC LETTER DAD, ARABIC LETTER KHAH\t# \nFC24 ;\t0636 062E ;\tMA\t# ( ‎ﰤ‎ → ‎ضخ‎ ) ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM → ARABIC LETTER DAD, ARABIC LETTER KHAH\t# \n\nFD70 ;\t0636 062E 0645 ;\tMA\t# ( ‎ﵰ‎ → ‎ضخم‎ ) ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM → ARABIC LETTER DAD, ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \nFD6F ;\t0636 062E 0645 ;\tMA\t# ( ‎ﵯ‎ → ‎ضخم‎ ) ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM → ARABIC LETTER DAD, ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \n\nFD2C ;\t0636 0631 ;\tMA\t# ( ‎ﴬ‎ → ‎ضر‎ ) ARABIC LIGATURE DAD WITH REH FINAL FORM → ARABIC LETTER DAD, ARABIC LETTER REH\t# \nFD10 ;\t0636 0631 ;\tMA\t# ( ‎ﴐ‎ → ‎ضر‎ ) ARABIC LIGATURE DAD WITH REH ISOLATED FORM → ARABIC LETTER DAD, ARABIC LETTER REH\t# \n\nFCB7 ;\t0636 0645 ;\tMA\t# ( ‎ﲷ‎ → ‎ضم‎ ) ARABIC LIGATURE DAD WITH MEEM INITIAL FORM → ARABIC LETTER DAD, ARABIC LETTER MEEM\t# \nFC25 ;\t0636 0645 ;\tMA\t# ( ‎ﰥ‎ → ‎ضم‎ ) ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM → ARABIC LETTER DAD, ARABIC LETTER MEEM\t# \n\nFD23 ;\t0636 0649 ;\tMA\t# ( ‎ﴣ‎ → ‎ضى‎ ) ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER DAD, ARABIC LETTER ALEF MAKSURA\t# \nFD07 ;\t0636 0649 ;\tMA\t# ( ‎ﴇ‎ → ‎ضى‎ ) ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER DAD, ARABIC LETTER ALEF MAKSURA\t# \nFD24 ;\t0636 0649 ;\tMA\t# ( ‎ﴤ‎ → ‎ضى‎ ) ARABIC LIGATURE DAD WITH YEH FINAL FORM → ARABIC LETTER DAD, ARABIC LETTER ALEF MAKSURA\t# →‎ضي‎→\nFD08 ;\t0636 0649 ;\tMA\t# ( ‎ﴈ‎ → ‎ضى‎ ) ARABIC LIGATURE DAD WITH YEH ISOLATED FORM → ARABIC LETTER DAD, ARABIC LETTER ALEF MAKSURA\t# →‎ضي‎→\n\n102E8 ;\t0637 ;\tMA\t#* ( 𐋨 → ‎ط‎ ) COPTIC EPACT DIGIT EIGHT → ARABIC LETTER TAH\t# \n1EE08 ;\t0637 ;\tMA\t# ( ‎𞸈‎ → ‎ط‎ ) ARABIC MATHEMATICAL TAH → ARABIC LETTER TAH\t# \n1EE68 ;\t0637 ;\tMA\t# ( ‎𞹨‎ → ‎ط‎ ) ARABIC MATHEMATICAL STRETCHED TAH → ARABIC LETTER TAH\t# \n1EE88 ;\t0637 ;\tMA\t# ( ‎𞺈‎ → ‎ط‎ ) ARABIC MATHEMATICAL LOOPED TAH → ARABIC LETTER TAH\t# \n1EEA8 ;\t0637 ;\tMA\t# ( ‎𞺨‎ → ‎ط‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK TAH → ARABIC LETTER TAH\t# \nFEC3 ;\t0637 ;\tMA\t# ( ‎ﻃ‎ → ‎ط‎ ) ARABIC LETTER TAH INITIAL FORM → ARABIC LETTER TAH\t# \nFEC4 ;\t0637 ;\tMA\t# ( ‎ﻄ‎ → ‎ط‎ ) ARABIC LETTER TAH MEDIAL FORM → ARABIC LETTER TAH\t# \nFEC2 ;\t0637 ;\tMA\t# ( ‎ﻂ‎ → ‎ط‎ ) ARABIC LETTER TAH FINAL FORM → ARABIC LETTER TAH\t# \nFEC1 ;\t0637 ;\tMA\t# ( ‎ﻁ‎ → ‎ط‎ ) ARABIC LETTER TAH ISOLATED FORM → ARABIC LETTER TAH\t# \n\n069F ;\t0637 06DB ;\tMA\t# ( ‎ڟ‎ → ‎طۛ‎ ) ARABIC LETTER TAH WITH THREE DOTS ABOVE → ARABIC LETTER TAH, ARABIC SMALL HIGH THREE DOTS\t# \n\nFCB8 ;\t0637 062D ;\tMA\t# ( ‎ﲸ‎ → ‎طح‎ ) ARABIC LIGATURE TAH WITH HAH INITIAL FORM → ARABIC LETTER TAH, ARABIC LETTER HAH\t# \nFC26 ;\t0637 062D ;\tMA\t# ( ‎ﰦ‎ → ‎طح‎ ) ARABIC LIGATURE TAH WITH HAH ISOLATED FORM → ARABIC LETTER TAH, ARABIC LETTER HAH\t# \n\nFD33 ;\t0637 0645 ;\tMA\t# ( ‎ﴳ‎ → ‎طم‎ ) ARABIC LIGATURE TAH WITH MEEM INITIAL FORM → ARABIC LETTER TAH, ARABIC LETTER MEEM\t# \nFD3A ;\t0637 0645 ;\tMA\t# ( ‎ﴺ‎ → ‎طم‎ ) ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM → ARABIC LETTER TAH, ARABIC LETTER MEEM\t# \nFC27 ;\t0637 0645 ;\tMA\t# ( ‎ﰧ‎ → ‎طم‎ ) ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM → ARABIC LETTER TAH, ARABIC LETTER MEEM\t# \n\nFD72 ;\t0637 0645 062D ;\tMA\t# ( ‎ﵲ‎ → ‎طمح‎ ) ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM → ARABIC LETTER TAH, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \nFD71 ;\t0637 0645 062D ;\tMA\t# ( ‎ﵱ‎ → ‎طمح‎ ) ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM → ARABIC LETTER TAH, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \n\nFD73 ;\t0637 0645 0645 ;\tMA\t# ( ‎ﵳ‎ → ‎طمم‎ ) ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM → ARABIC LETTER TAH, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \n\nFD74 ;\t0637 0645 0649 ;\tMA\t# ( ‎ﵴ‎ → ‎طمى‎ ) ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER TAH, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎طمي‎→\n\nFD11 ;\t0637 0649 ;\tMA\t# ( ‎ﴑ‎ → ‎طى‎ ) ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER TAH, ARABIC LETTER ALEF MAKSURA\t# \nFCF5 ;\t0637 0649 ;\tMA\t# ( ‎ﳵ‎ → ‎طى‎ ) ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER TAH, ARABIC LETTER ALEF MAKSURA\t# \nFD12 ;\t0637 0649 ;\tMA\t# ( ‎ﴒ‎ → ‎طى‎ ) ARABIC LIGATURE TAH WITH YEH FINAL FORM → ARABIC LETTER TAH, ARABIC LETTER ALEF MAKSURA\t# →‎طي‎→\nFCF6 ;\t0637 0649 ;\tMA\t# ( ‎ﳶ‎ → ‎طى‎ ) ARABIC LIGATURE TAH WITH YEH ISOLATED FORM → ARABIC LETTER TAH, ARABIC LETTER ALEF MAKSURA\t# →‎طي‎→\n\n1EE1A ;\t0638 ;\tMA\t# ( ‎𞸚‎ → ‎ظ‎ ) ARABIC MATHEMATICAL ZAH → ARABIC LETTER ZAH\t# \n1EE7A ;\t0638 ;\tMA\t# ( ‎𞹺‎ → ‎ظ‎ ) ARABIC MATHEMATICAL STRETCHED ZAH → ARABIC LETTER ZAH\t# \n1EE9A ;\t0638 ;\tMA\t# ( ‎𞺚‎ → ‎ظ‎ ) ARABIC MATHEMATICAL LOOPED ZAH → ARABIC LETTER ZAH\t# \n1EEBA ;\t0638 ;\tMA\t# ( ‎𞺺‎ → ‎ظ‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH → ARABIC LETTER ZAH\t# \nFEC7 ;\t0638 ;\tMA\t# ( ‎ﻇ‎ → ‎ظ‎ ) ARABIC LETTER ZAH INITIAL FORM → ARABIC LETTER ZAH\t# \nFEC8 ;\t0638 ;\tMA\t# ( ‎ﻈ‎ → ‎ظ‎ ) ARABIC LETTER ZAH MEDIAL FORM → ARABIC LETTER ZAH\t# \nFEC6 ;\t0638 ;\tMA\t# ( ‎ﻆ‎ → ‎ظ‎ ) ARABIC LETTER ZAH FINAL FORM → ARABIC LETTER ZAH\t# \nFEC5 ;\t0638 ;\tMA\t# ( ‎ﻅ‎ → ‎ظ‎ ) ARABIC LETTER ZAH ISOLATED FORM → ARABIC LETTER ZAH\t# \n\nFCB9 ;\t0638 0645 ;\tMA\t# ( ‎ﲹ‎ → ‎ظم‎ ) ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM → ARABIC LETTER ZAH, ARABIC LETTER MEEM\t# \nFD3B ;\t0638 0645 ;\tMA\t# ( ‎ﴻ‎ → ‎ظم‎ ) ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM → ARABIC LETTER ZAH, ARABIC LETTER MEEM\t# \nFC28 ;\t0638 0645 ;\tMA\t# ( ‎ﰨ‎ → ‎ظم‎ ) ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM → ARABIC LETTER ZAH, ARABIC LETTER MEEM\t# \n\n060F ;\t0639 ;\tMA\t#* ( ؏ → ‎ع‎ ) ARABIC SIGN MISRA → ARABIC LETTER AIN\t# \n1EE0F ;\t0639 ;\tMA\t# ( ‎𞸏‎ → ‎ع‎ ) ARABIC MATHEMATICAL AIN → ARABIC LETTER AIN\t# \n1EE2F ;\t0639 ;\tMA\t# ( ‎𞸯‎ → ‎ع‎ ) ARABIC MATHEMATICAL INITIAL AIN → ARABIC LETTER AIN\t# \n1EE4F ;\t0639 ;\tMA\t# ( ‎𞹏‎ → ‎ع‎ ) ARABIC MATHEMATICAL TAILED AIN → ARABIC LETTER AIN\t# \n1EE6F ;\t0639 ;\tMA\t# ( ‎𞹯‎ → ‎ع‎ ) ARABIC MATHEMATICAL STRETCHED AIN → ARABIC LETTER AIN\t# \n1EE8F ;\t0639 ;\tMA\t# ( ‎𞺏‎ → ‎ع‎ ) ARABIC MATHEMATICAL LOOPED AIN → ARABIC LETTER AIN\t# \n1EEAF ;\t0639 ;\tMA\t# ( ‎𞺯‎ → ‎ع‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK AIN → ARABIC LETTER AIN\t# \nFECB ;\t0639 ;\tMA\t# ( ‎ﻋ‎ → ‎ع‎ ) ARABIC LETTER AIN INITIAL FORM → ARABIC LETTER AIN\t# \nFECC ;\t0639 ;\tMA\t# ( ‎ﻌ‎ → ‎ع‎ ) ARABIC LETTER AIN MEDIAL FORM → ARABIC LETTER AIN\t# \nFECA ;\t0639 ;\tMA\t# ( ‎ﻊ‎ → ‎ع‎ ) ARABIC LETTER AIN FINAL FORM → ARABIC LETTER AIN\t# \nFEC9 ;\t0639 ;\tMA\t# ( ‎ﻉ‎ → ‎ع‎ ) ARABIC LETTER AIN ISOLATED FORM → ARABIC LETTER AIN\t# \n\nFCBA ;\t0639 062C ;\tMA\t# ( ‎ﲺ‎ → ‎عج‎ ) ARABIC LIGATURE AIN WITH JEEM INITIAL FORM → ARABIC LETTER AIN, ARABIC LETTER JEEM\t# \nFC29 ;\t0639 062C ;\tMA\t# ( ‎ﰩ‎ → ‎عج‎ ) ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM → ARABIC LETTER AIN, ARABIC LETTER JEEM\t# \n\nFDC4 ;\t0639 062C 0645 ;\tMA\t# ( ‎ﷄ‎ → ‎عجم‎ ) ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM → ARABIC LETTER AIN, ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \nFD75 ;\t0639 062C 0645 ;\tMA\t# ( ‎ﵵ‎ → ‎عجم‎ ) ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM → ARABIC LETTER AIN, ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \n\nFDF7 ;\t0639 0644 0649 006F ;\tMA\t# ( ‎ﷷ‎ → ‎علىo‎ ) ARABIC LIGATURE ALAYHE ISOLATED FORM → ARABIC LETTER AIN, ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA, LATIN SMALL LETTER O\t# →‎عليه‎→\n\nFCBB ;\t0639 0645 ;\tMA\t# ( ‎ﲻ‎ → ‎عم‎ ) ARABIC LIGATURE AIN WITH MEEM INITIAL FORM → ARABIC LETTER AIN, ARABIC LETTER MEEM\t# \nFC2A ;\t0639 0645 ;\tMA\t# ( ‎ﰪ‎ → ‎عم‎ ) ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM → ARABIC LETTER AIN, ARABIC LETTER MEEM\t# \n\nFD77 ;\t0639 0645 0645 ;\tMA\t# ( ‎ﵷ‎ → ‎عمم‎ ) ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM → ARABIC LETTER AIN, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \nFD76 ;\t0639 0645 0645 ;\tMA\t# ( ‎ﵶ‎ → ‎عمم‎ ) ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM → ARABIC LETTER AIN, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \n\nFD78 ;\t0639 0645 0649 ;\tMA\t# ( ‎ﵸ‎ → ‎عمى‎ ) ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER AIN, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# \nFDB6 ;\t0639 0645 0649 ;\tMA\t# ( ‎ﶶ‎ → ‎عمى‎ ) ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER AIN, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎عمي‎→\n\nFD13 ;\t0639 0649 ;\tMA\t# ( ‎ﴓ‎ → ‎عى‎ ) ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER AIN, ARABIC LETTER ALEF MAKSURA\t# \nFCF7 ;\t0639 0649 ;\tMA\t# ( ‎ﳷ‎ → ‎عى‎ ) ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER AIN, ARABIC LETTER ALEF MAKSURA\t# \nFD14 ;\t0639 0649 ;\tMA\t# ( ‎ﴔ‎ → ‎عى‎ ) ARABIC LIGATURE AIN WITH YEH FINAL FORM → ARABIC LETTER AIN, ARABIC LETTER ALEF MAKSURA\t# →‎عي‎→\nFCF8 ;\t0639 0649 ;\tMA\t# ( ‎ﳸ‎ → ‎عى‎ ) ARABIC LIGATURE AIN WITH YEH ISOLATED FORM → ARABIC LETTER AIN, ARABIC LETTER ALEF MAKSURA\t# →‎عي‎→\n\n1EE1B ;\t063A ;\tMA\t# ( ‎𞸛‎ → ‎غ‎ ) ARABIC MATHEMATICAL GHAIN → ARABIC LETTER GHAIN\t# \n1EE3B ;\t063A ;\tMA\t# ( ‎𞸻‎ → ‎غ‎ ) ARABIC MATHEMATICAL INITIAL GHAIN → ARABIC LETTER GHAIN\t# \n1EE5B ;\t063A ;\tMA\t# ( ‎𞹛‎ → ‎غ‎ ) ARABIC MATHEMATICAL TAILED GHAIN → ARABIC LETTER GHAIN\t# \n1EE7B ;\t063A ;\tMA\t# ( ‎𞹻‎ → ‎غ‎ ) ARABIC MATHEMATICAL STRETCHED GHAIN → ARABIC LETTER GHAIN\t# \n1EE9B ;\t063A ;\tMA\t# ( ‎𞺛‎ → ‎غ‎ ) ARABIC MATHEMATICAL LOOPED GHAIN → ARABIC LETTER GHAIN\t# \n1EEBB ;\t063A ;\tMA\t# ( ‎𞺻‎ → ‎غ‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN → ARABIC LETTER GHAIN\t# \nFECF ;\t063A ;\tMA\t# ( ‎ﻏ‎ → ‎غ‎ ) ARABIC LETTER GHAIN INITIAL FORM → ARABIC LETTER GHAIN\t# \nFED0 ;\t063A ;\tMA\t# ( ‎ﻐ‎ → ‎غ‎ ) ARABIC LETTER GHAIN MEDIAL FORM → ARABIC LETTER GHAIN\t# \nFECE ;\t063A ;\tMA\t# ( ‎ﻎ‎ → ‎غ‎ ) ARABIC LETTER GHAIN FINAL FORM → ARABIC LETTER GHAIN\t# \nFECD ;\t063A ;\tMA\t# ( ‎ﻍ‎ → ‎غ‎ ) ARABIC LETTER GHAIN ISOLATED FORM → ARABIC LETTER GHAIN\t# \n\nFCBC ;\t063A 062C ;\tMA\t# ( ‎ﲼ‎ → ‎غج‎ ) ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM → ARABIC LETTER GHAIN, ARABIC LETTER JEEM\t# \nFC2B ;\t063A 062C ;\tMA\t# ( ‎ﰫ‎ → ‎غج‎ ) ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM → ARABIC LETTER GHAIN, ARABIC LETTER JEEM\t# \n\nFCBD ;\t063A 0645 ;\tMA\t# ( ‎ﲽ‎ → ‎غم‎ ) ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM → ARABIC LETTER GHAIN, ARABIC LETTER MEEM\t# \nFC2C ;\t063A 0645 ;\tMA\t# ( ‎ﰬ‎ → ‎غم‎ ) ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM → ARABIC LETTER GHAIN, ARABIC LETTER MEEM\t# \n\nFD79 ;\t063A 0645 0645 ;\tMA\t# ( ‎ﵹ‎ → ‎غمم‎ ) ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM → ARABIC LETTER GHAIN, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \n\nFD7B ;\t063A 0645 0649 ;\tMA\t# ( ‎ﵻ‎ → ‎غمى‎ ) ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER GHAIN, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# \nFD7A ;\t063A 0645 0649 ;\tMA\t# ( ‎ﵺ‎ → ‎غمى‎ ) ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER GHAIN, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎غمي‎→\n\nFD15 ;\t063A 0649 ;\tMA\t# ( ‎ﴕ‎ → ‎غى‎ ) ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER GHAIN, ARABIC LETTER ALEF MAKSURA\t# \nFCF9 ;\t063A 0649 ;\tMA\t# ( ‎ﳹ‎ → ‎غى‎ ) ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER GHAIN, ARABIC LETTER ALEF MAKSURA\t# \nFD16 ;\t063A 0649 ;\tMA\t# ( ‎ﴖ‎ → ‎غى‎ ) ARABIC LIGATURE GHAIN WITH YEH FINAL FORM → ARABIC LETTER GHAIN, ARABIC LETTER ALEF MAKSURA\t# →‎غي‎→\nFCFA ;\t063A 0649 ;\tMA\t# ( ‎ﳺ‎ → ‎غى‎ ) ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM → ARABIC LETTER GHAIN, ARABIC LETTER ALEF MAKSURA\t# →‎غي‎→\n\n1EE10 ;\t0641 ;\tMA\t# ( ‎𞸐‎ → ‎ف‎ ) ARABIC MATHEMATICAL FEH → ARABIC LETTER FEH\t# \n1EE30 ;\t0641 ;\tMA\t# ( ‎𞸰‎ → ‎ف‎ ) ARABIC MATHEMATICAL INITIAL FEH → ARABIC LETTER FEH\t# \n1EE70 ;\t0641 ;\tMA\t# ( ‎𞹰‎ → ‎ف‎ ) ARABIC MATHEMATICAL STRETCHED FEH → ARABIC LETTER FEH\t# \n1EE90 ;\t0641 ;\tMA\t# ( ‎𞺐‎ → ‎ف‎ ) ARABIC MATHEMATICAL LOOPED FEH → ARABIC LETTER FEH\t# \n1EEB0 ;\t0641 ;\tMA\t# ( ‎𞺰‎ → ‎ف‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK FEH → ARABIC LETTER FEH\t# \nFED3 ;\t0641 ;\tMA\t# ( ‎ﻓ‎ → ‎ف‎ ) ARABIC LETTER FEH INITIAL FORM → ARABIC LETTER FEH\t# \nFED4 ;\t0641 ;\tMA\t# ( ‎ﻔ‎ → ‎ف‎ ) ARABIC LETTER FEH MEDIAL FORM → ARABIC LETTER FEH\t# \nFED2 ;\t0641 ;\tMA\t# ( ‎ﻒ‎ → ‎ف‎ ) ARABIC LETTER FEH FINAL FORM → ARABIC LETTER FEH\t# \nFED1 ;\t0641 ;\tMA\t# ( ‎ﻑ‎ → ‎ف‎ ) ARABIC LETTER FEH ISOLATED FORM → ARABIC LETTER FEH\t# \n06A7 ;\t0641 ;\tMA\t# ( ‎ڧ‎ → ‎ف‎ ) ARABIC LETTER QAF WITH DOT ABOVE → ARABIC LETTER FEH\t# \n\nFCBE ;\t0641 062C ;\tMA\t# ( ‎ﲾ‎ → ‎فج‎ ) ARABIC LIGATURE FEH WITH JEEM INITIAL FORM → ARABIC LETTER FEH, ARABIC LETTER JEEM\t# \nFC2D ;\t0641 062C ;\tMA\t# ( ‎ﰭ‎ → ‎فج‎ ) ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM → ARABIC LETTER FEH, ARABIC LETTER JEEM\t# \n\nFCBF ;\t0641 062D ;\tMA\t# ( ‎ﲿ‎ → ‎فح‎ ) ARABIC LIGATURE FEH WITH HAH INITIAL FORM → ARABIC LETTER FEH, ARABIC LETTER HAH\t# \nFC2E ;\t0641 062D ;\tMA\t# ( ‎ﰮ‎ → ‎فح‎ ) ARABIC LIGATURE FEH WITH HAH ISOLATED FORM → ARABIC LETTER FEH, ARABIC LETTER HAH\t# \n\nFCC0 ;\t0641 062E ;\tMA\t# ( ‎ﳀ‎ → ‎فخ‎ ) ARABIC LIGATURE FEH WITH KHAH INITIAL FORM → ARABIC LETTER FEH, ARABIC LETTER KHAH\t# \nFC2F ;\t0641 062E ;\tMA\t# ( ‎ﰯ‎ → ‎فخ‎ ) ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM → ARABIC LETTER FEH, ARABIC LETTER KHAH\t# \n\nFD7D ;\t0641 062E 0645 ;\tMA\t# ( ‎ﵽ‎ → ‎فخم‎ ) ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM → ARABIC LETTER FEH, ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \nFD7C ;\t0641 062E 0645 ;\tMA\t# ( ‎ﵼ‎ → ‎فخم‎ ) ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM → ARABIC LETTER FEH, ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \n\nFCC1 ;\t0641 0645 ;\tMA\t# ( ‎ﳁ‎ → ‎فم‎ ) ARABIC LIGATURE FEH WITH MEEM INITIAL FORM → ARABIC LETTER FEH, ARABIC LETTER MEEM\t# \nFC30 ;\t0641 0645 ;\tMA\t# ( ‎ﰰ‎ → ‎فم‎ ) ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM → ARABIC LETTER FEH, ARABIC LETTER MEEM\t# \n\nFDC1 ;\t0641 0645 0649 ;\tMA\t# ( ‎ﷁ‎ → ‎فمى‎ ) ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER FEH, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎فمي‎→\n\nFC7C ;\t0641 0649 ;\tMA\t# ( ‎ﱼ‎ → ‎فى‎ ) ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER FEH, ARABIC LETTER ALEF MAKSURA\t# \nFC31 ;\t0641 0649 ;\tMA\t# ( ‎ﰱ‎ → ‎فى‎ ) ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER FEH, ARABIC LETTER ALEF MAKSURA\t# \nFC7D ;\t0641 0649 ;\tMA\t# ( ‎ﱽ‎ → ‎فى‎ ) ARABIC LIGATURE FEH WITH YEH FINAL FORM → ARABIC LETTER FEH, ARABIC LETTER ALEF MAKSURA\t# →‎في‎→\nFC32 ;\t0641 0649 ;\tMA\t# ( ‎ﰲ‎ → ‎فى‎ ) ARABIC LIGATURE FEH WITH YEH ISOLATED FORM → ARABIC LETTER FEH, ARABIC LETTER ALEF MAKSURA\t# →‎في‎→\n\n1EE1E ;\t06A1 ;\tMA\t# ( ‎𞸞‎ → ‎ڡ‎ ) ARABIC MATHEMATICAL DOTLESS FEH → ARABIC LETTER DOTLESS FEH\t# \n1EE7E ;\t06A1 ;\tMA\t# ( ‎𞹾‎ → ‎ڡ‎ ) ARABIC MATHEMATICAL STRETCHED DOTLESS FEH → ARABIC LETTER DOTLESS FEH\t# \n08BB ;\t06A1 ;\tMA\t# ( ‎ࢻ‎ → ‎ڡ‎ ) ARABIC LETTER AFRICAN FEH → ARABIC LETTER DOTLESS FEH\t# \n066F ;\t06A1 ;\tMA\t# ( ‎ٯ‎ → ‎ڡ‎ ) ARABIC LETTER DOTLESS QAF → ARABIC LETTER DOTLESS FEH\t# \n1EE1F ;\t06A1 ;\tMA\t# ( ‎𞸟‎ → ‎ڡ‎ ) ARABIC MATHEMATICAL DOTLESS QAF → ARABIC LETTER DOTLESS FEH\t# →‎ٯ‎→\n1EE5F ;\t06A1 ;\tMA\t# ( ‎𞹟‎ → ‎ڡ‎ ) ARABIC MATHEMATICAL TAILED DOTLESS QAF → ARABIC LETTER DOTLESS FEH\t# →‎ٯ‎→\n08BC ;\t06A1 ;\tMA\t# ( ‎ࢼ‎ → ‎ڡ‎ ) ARABIC LETTER AFRICAN QAF → ARABIC LETTER DOTLESS FEH\t# →‎ٯ‎→\n\n06A4 ;\t06A1 06DB ;\tMA\t# ( ‎ڤ‎ → ‎ڡۛ‎ ) ARABIC LETTER VEH → ARABIC LETTER DOTLESS FEH, ARABIC SMALL HIGH THREE DOTS\t# \nFB6C ;\t06A1 06DB ;\tMA\t# ( ‎ﭬ‎ → ‎ڡۛ‎ ) ARABIC LETTER VEH INITIAL FORM → ARABIC LETTER DOTLESS FEH, ARABIC SMALL HIGH THREE DOTS\t# →‎ڤ‎→\nFB6D ;\t06A1 06DB ;\tMA\t# ( ‎ﭭ‎ → ‎ڡۛ‎ ) ARABIC LETTER VEH MEDIAL FORM → ARABIC LETTER DOTLESS FEH, ARABIC SMALL HIGH THREE DOTS\t# →‎ڤ‎→\nFB6B ;\t06A1 06DB ;\tMA\t# ( ‎ﭫ‎ → ‎ڡۛ‎ ) ARABIC LETTER VEH FINAL FORM → ARABIC LETTER DOTLESS FEH, ARABIC SMALL HIGH THREE DOTS\t# →‎ڤ‎→\nFB6A ;\t06A1 06DB ;\tMA\t# ( ‎ﭪ‎ → ‎ڡۛ‎ ) ARABIC LETTER VEH ISOLATED FORM → ARABIC LETTER DOTLESS FEH, ARABIC SMALL HIGH THREE DOTS\t# →‎ڤ‎→\n06A8 ;\t06A1 06DB ;\tMA\t# ( ‎ڨ‎ → ‎ڡۛ‎ ) ARABIC LETTER QAF WITH THREE DOTS ABOVE → ARABIC LETTER DOTLESS FEH, ARABIC SMALL HIGH THREE DOTS\t# →‎ڤ‎→\n\n08A4 ;\t06A2 06DB ;\tMA\t# ( ‎ࢤ‎ → ‎ڢۛ‎ ) ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE → ARABIC LETTER FEH WITH DOT MOVED BELOW, ARABIC SMALL HIGH THREE DOTS\t# \n\nFB70 ;\t06A6 ;\tMA\t# ( ‎ﭰ‎ → ‎ڦ‎ ) ARABIC LETTER PEHEH INITIAL FORM → ARABIC LETTER PEHEH\t# \nFB71 ;\t06A6 ;\tMA\t# ( ‎ﭱ‎ → ‎ڦ‎ ) ARABIC LETTER PEHEH MEDIAL FORM → ARABIC LETTER PEHEH\t# \nFB6F ;\t06A6 ;\tMA\t# ( ‎ﭯ‎ → ‎ڦ‎ ) ARABIC LETTER PEHEH FINAL FORM → ARABIC LETTER PEHEH\t# \nFB6E ;\t06A6 ;\tMA\t# ( ‎ﭮ‎ → ‎ڦ‎ ) ARABIC LETTER PEHEH ISOLATED FORM → ARABIC LETTER PEHEH\t# \n\n1EE12 ;\t0642 ;\tMA\t# ( ‎𞸒‎ → ‎ق‎ ) ARABIC MATHEMATICAL QAF → ARABIC LETTER QAF\t# \n1EE32 ;\t0642 ;\tMA\t# ( ‎𞸲‎ → ‎ق‎ ) ARABIC MATHEMATICAL INITIAL QAF → ARABIC LETTER QAF\t# \n1EE52 ;\t0642 ;\tMA\t# ( ‎𞹒‎ → ‎ق‎ ) ARABIC MATHEMATICAL TAILED QAF → ARABIC LETTER QAF\t# \n1EE72 ;\t0642 ;\tMA\t# ( ‎𞹲‎ → ‎ق‎ ) ARABIC MATHEMATICAL STRETCHED QAF → ARABIC LETTER QAF\t# \n1EE92 ;\t0642 ;\tMA\t# ( ‎𞺒‎ → ‎ق‎ ) ARABIC MATHEMATICAL LOOPED QAF → ARABIC LETTER QAF\t# \n1EEB2 ;\t0642 ;\tMA\t# ( ‎𞺲‎ → ‎ق‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK QAF → ARABIC LETTER QAF\t# \nFED7 ;\t0642 ;\tMA\t# ( ‎ﻗ‎ → ‎ق‎ ) ARABIC LETTER QAF INITIAL FORM → ARABIC LETTER QAF\t# \nFED8 ;\t0642 ;\tMA\t# ( ‎ﻘ‎ → ‎ق‎ ) ARABIC LETTER QAF MEDIAL FORM → ARABIC LETTER QAF\t# \nFED6 ;\t0642 ;\tMA\t# ( ‎ﻖ‎ → ‎ق‎ ) ARABIC LETTER QAF FINAL FORM → ARABIC LETTER QAF\t# \nFED5 ;\t0642 ;\tMA\t# ( ‎ﻕ‎ → ‎ق‎ ) ARABIC LETTER QAF ISOLATED FORM → ARABIC LETTER QAF\t# \n\nFCC2 ;\t0642 062D ;\tMA\t# ( ‎ﳂ‎ → ‎قح‎ ) ARABIC LIGATURE QAF WITH HAH INITIAL FORM → ARABIC LETTER QAF, ARABIC LETTER HAH\t# \nFC33 ;\t0642 062D ;\tMA\t# ( ‎ﰳ‎ → ‎قح‎ ) ARABIC LIGATURE QAF WITH HAH ISOLATED FORM → ARABIC LETTER QAF, ARABIC LETTER HAH\t# \n\nFDF1 ;\t0642 0644 0649 ;\tMA\t# ( ‎ﷱ‎ → ‎قلى‎ ) ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM → ARABIC LETTER QAF, ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA\t# →‎قلے‎→\n\nFCC3 ;\t0642 0645 ;\tMA\t# ( ‎ﳃ‎ → ‎قم‎ ) ARABIC LIGATURE QAF WITH MEEM INITIAL FORM → ARABIC LETTER QAF, ARABIC LETTER MEEM\t# \nFC34 ;\t0642 0645 ;\tMA\t# ( ‎ﰴ‎ → ‎قم‎ ) ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM → ARABIC LETTER QAF, ARABIC LETTER MEEM\t# \n\nFDB4 ;\t0642 0645 062D ;\tMA\t# ( ‎ﶴ‎ → ‎قمح‎ ) ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM → ARABIC LETTER QAF, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \nFD7E ;\t0642 0645 062D ;\tMA\t# ( ‎ﵾ‎ → ‎قمح‎ ) ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM → ARABIC LETTER QAF, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \n\nFD7F ;\t0642 0645 0645 ;\tMA\t# ( ‎ﵿ‎ → ‎قمم‎ ) ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM → ARABIC LETTER QAF, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \n\nFDB2 ;\t0642 0645 0649 ;\tMA\t# ( ‎ﶲ‎ → ‎قمى‎ ) ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER QAF, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎قمي‎→\n\nFC7E ;\t0642 0649 ;\tMA\t# ( ‎ﱾ‎ → ‎قى‎ ) ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER QAF, ARABIC LETTER ALEF MAKSURA\t# \nFC35 ;\t0642 0649 ;\tMA\t# ( ‎ﰵ‎ → ‎قى‎ ) ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER QAF, ARABIC LETTER ALEF MAKSURA\t# \nFC7F ;\t0642 0649 ;\tMA\t# ( ‎ﱿ‎ → ‎قى‎ ) ARABIC LIGATURE QAF WITH YEH FINAL FORM → ARABIC LETTER QAF, ARABIC LETTER ALEF MAKSURA\t# →‎قي‎→\nFC36 ;\t0642 0649 ;\tMA\t# ( ‎ﰶ‎ → ‎قى‎ ) ARABIC LIGATURE QAF WITH YEH ISOLATED FORM → ARABIC LETTER QAF, ARABIC LETTER ALEF MAKSURA\t# →‎قي‎→\n\n1EE0A ;\t0643 ;\tMA\t# ( ‎𞸊‎ → ‎ك‎ ) ARABIC MATHEMATICAL KAF → ARABIC LETTER KAF\t# \n1EE2A ;\t0643 ;\tMA\t# ( ‎𞸪‎ → ‎ك‎ ) ARABIC MATHEMATICAL INITIAL KAF → ARABIC LETTER KAF\t# \n1EE6A ;\t0643 ;\tMA\t# ( ‎𞹪‎ → ‎ك‎ ) ARABIC MATHEMATICAL STRETCHED KAF → ARABIC LETTER KAF\t# \nFEDB ;\t0643 ;\tMA\t# ( ‎ﻛ‎ → ‎ك‎ ) ARABIC LETTER KAF INITIAL FORM → ARABIC LETTER KAF\t# \nFEDC ;\t0643 ;\tMA\t# ( ‎ﻜ‎ → ‎ك‎ ) ARABIC LETTER KAF MEDIAL FORM → ARABIC LETTER KAF\t# \nFEDA ;\t0643 ;\tMA\t# ( ‎ﻚ‎ → ‎ك‎ ) ARABIC LETTER KAF FINAL FORM → ARABIC LETTER KAF\t# \nFED9 ;\t0643 ;\tMA\t# ( ‎ﻙ‎ → ‎ك‎ ) ARABIC LETTER KAF ISOLATED FORM → ARABIC LETTER KAF\t# \n06A9 ;\t0643 ;\tMA\t# ( ‎ک‎ → ‎ك‎ ) ARABIC LETTER KEHEH → ARABIC LETTER KAF\t# \nFB90 ;\t0643 ;\tMA\t# ( ‎ﮐ‎ → ‎ك‎ ) ARABIC LETTER KEHEH INITIAL FORM → ARABIC LETTER KAF\t# →‎ک‎→\nFB91 ;\t0643 ;\tMA\t# ( ‎ﮑ‎ → ‎ك‎ ) ARABIC LETTER KEHEH MEDIAL FORM → ARABIC LETTER KAF\t# →‎ک‎→\nFB8F ;\t0643 ;\tMA\t# ( ‎ﮏ‎ → ‎ك‎ ) ARABIC LETTER KEHEH FINAL FORM → ARABIC LETTER KAF\t# →‎ک‎→\nFB8E ;\t0643 ;\tMA\t# ( ‎ﮎ‎ → ‎ك‎ ) ARABIC LETTER KEHEH ISOLATED FORM → ARABIC LETTER KAF\t# →‎ک‎→\n06AA ;\t0643 ;\tMA\t# ( ‎ڪ‎ → ‎ك‎ ) ARABIC LETTER SWASH KAF → ARABIC LETTER KAF\t# \n\n06AD ;\t0643 06DB ;\tMA\t# ( ‎ڭ‎ → ‎كۛ‎ ) ARABIC LETTER NG → ARABIC LETTER KAF, ARABIC SMALL HIGH THREE DOTS\t# \nFBD5 ;\t0643 06DB ;\tMA\t# ( ‎ﯕ‎ → ‎كۛ‎ ) ARABIC LETTER NG INITIAL FORM → ARABIC LETTER KAF, ARABIC SMALL HIGH THREE DOTS\t# →‎ڭ‎→\nFBD6 ;\t0643 06DB ;\tMA\t# ( ‎ﯖ‎ → ‎كۛ‎ ) ARABIC LETTER NG MEDIAL FORM → ARABIC LETTER KAF, ARABIC SMALL HIGH THREE DOTS\t# →‎ڭ‎→\nFBD4 ;\t0643 06DB ;\tMA\t# ( ‎ﯔ‎ → ‎كۛ‎ ) ARABIC LETTER NG FINAL FORM → ARABIC LETTER KAF, ARABIC SMALL HIGH THREE DOTS\t# →‎ڭ‎→\nFBD3 ;\t0643 06DB ;\tMA\t# ( ‎ﯓ‎ → ‎كۛ‎ ) ARABIC LETTER NG ISOLATED FORM → ARABIC LETTER KAF, ARABIC SMALL HIGH THREE DOTS\t# →‎ڭ‎→\n0763 ;\t0643 06DB ;\tMA\t# ( ‎ݣ‎ → ‎كۛ‎ ) ARABIC LETTER KEHEH WITH THREE DOTS ABOVE → ARABIC LETTER KAF, ARABIC SMALL HIGH THREE DOTS\t# →‎ڭ‎→\n\n08C2 ;\t0643 0306 ;\tMA\t# ( ‎ࣂ‎ → ‎ك̆‎ ) ARABIC LETTER KEHEH WITH SMALL V → ARABIC LETTER KAF, COMBINING BREVE\t# →‎کٚ‎→\n\nFC80 ;\t0643 006C ;\tMA\t# ( ‎ﲀ‎ → ‎كl‎ ) ARABIC LIGATURE KAF WITH ALEF FINAL FORM → ARABIC LETTER KAF, LATIN SMALL LETTER L\t# →‎كا‎→\nFC37 ;\t0643 006C ;\tMA\t# ( ‎ﰷ‎ → ‎كl‎ ) ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM → ARABIC LETTER KAF, LATIN SMALL LETTER L\t# →‎كا‎→\n\nFCC4 ;\t0643 062C ;\tMA\t# ( ‎ﳄ‎ → ‎كج‎ ) ARABIC LIGATURE KAF WITH JEEM INITIAL FORM → ARABIC LETTER KAF, ARABIC LETTER JEEM\t# \nFC38 ;\t0643 062C ;\tMA\t# ( ‎ﰸ‎ → ‎كج‎ ) ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM → ARABIC LETTER KAF, ARABIC LETTER JEEM\t# \n\nFCC5 ;\t0643 062D ;\tMA\t# ( ‎ﳅ‎ → ‎كح‎ ) ARABIC LIGATURE KAF WITH HAH INITIAL FORM → ARABIC LETTER KAF, ARABIC LETTER HAH\t# \nFC39 ;\t0643 062D ;\tMA\t# ( ‎ﰹ‎ → ‎كح‎ ) ARABIC LIGATURE KAF WITH HAH ISOLATED FORM → ARABIC LETTER KAF, ARABIC LETTER HAH\t# \n\nFCC6 ;\t0643 062E ;\tMA\t# ( ‎ﳆ‎ → ‎كخ‎ ) ARABIC LIGATURE KAF WITH KHAH INITIAL FORM → ARABIC LETTER KAF, ARABIC LETTER KHAH\t# \nFC3A ;\t0643 062E ;\tMA\t# ( ‎ﰺ‎ → ‎كخ‎ ) ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM → ARABIC LETTER KAF, ARABIC LETTER KHAH\t# \n\nFCC7 ;\t0643 0644 ;\tMA\t# ( ‎ﳇ‎ → ‎كل‎ ) ARABIC LIGATURE KAF WITH LAM INITIAL FORM → ARABIC LETTER KAF, ARABIC LETTER LAM\t# \nFCEB ;\t0643 0644 ;\tMA\t# ( ‎ﳫ‎ → ‎كل‎ ) ARABIC LIGATURE KAF WITH LAM MEDIAL FORM → ARABIC LETTER KAF, ARABIC LETTER LAM\t# \nFC81 ;\t0643 0644 ;\tMA\t# ( ‎ﲁ‎ → ‎كل‎ ) ARABIC LIGATURE KAF WITH LAM FINAL FORM → ARABIC LETTER KAF, ARABIC LETTER LAM\t# \nFC3B ;\t0643 0644 ;\tMA\t# ( ‎ﰻ‎ → ‎كل‎ ) ARABIC LIGATURE KAF WITH LAM ISOLATED FORM → ARABIC LETTER KAF, ARABIC LETTER LAM\t# \n\nFCC8 ;\t0643 0645 ;\tMA\t# ( ‎ﳈ‎ → ‎كم‎ ) ARABIC LIGATURE KAF WITH MEEM INITIAL FORM → ARABIC LETTER KAF, ARABIC LETTER MEEM\t# \nFCEC ;\t0643 0645 ;\tMA\t# ( ‎ﳬ‎ → ‎كم‎ ) ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM → ARABIC LETTER KAF, ARABIC LETTER MEEM\t# \nFC82 ;\t0643 0645 ;\tMA\t# ( ‎ﲂ‎ → ‎كم‎ ) ARABIC LIGATURE KAF WITH MEEM FINAL FORM → ARABIC LETTER KAF, ARABIC LETTER MEEM\t# \nFC3C ;\t0643 0645 ;\tMA\t# ( ‎ﰼ‎ → ‎كم‎ ) ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM → ARABIC LETTER KAF, ARABIC LETTER MEEM\t# \n\nFDC3 ;\t0643 0645 0645 ;\tMA\t# ( ‎ﷃ‎ → ‎كمم‎ ) ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM → ARABIC LETTER KAF, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \nFDBB ;\t0643 0645 0645 ;\tMA\t# ( ‎ﶻ‎ → ‎كمم‎ ) ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM → ARABIC LETTER KAF, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \n\nFDB7 ;\t0643 0645 0649 ;\tMA\t# ( ‎ﶷ‎ → ‎كمى‎ ) ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER KAF, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎كمي‎→\n\nFC83 ;\t0643 0649 ;\tMA\t# ( ‎ﲃ‎ → ‎كى‎ ) ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER KAF, ARABIC LETTER ALEF MAKSURA\t# \nFC3D ;\t0643 0649 ;\tMA\t# ( ‎ﰽ‎ → ‎كى‎ ) ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER KAF, ARABIC LETTER ALEF MAKSURA\t# \nFC84 ;\t0643 0649 ;\tMA\t# ( ‎ﲄ‎ → ‎كى‎ ) ARABIC LIGATURE KAF WITH YEH FINAL FORM → ARABIC LETTER KAF, ARABIC LETTER ALEF MAKSURA\t# →‎كي‎→\nFC3E ;\t0643 0649 ;\tMA\t# ( ‎ﰾ‎ → ‎كى‎ ) ARABIC LIGATURE KAF WITH YEH ISOLATED FORM → ARABIC LETTER KAF, ARABIC LETTER ALEF MAKSURA\t# →‎كي‎→\n\n0762 ;\t06AC ;\tMA\t# ( ‎ݢ‎ → ‎ڬ‎ ) ARABIC LETTER KEHEH WITH DOT ABOVE → ARABIC LETTER KAF WITH DOT ABOVE\t# \n\nFB94 ;\t06AF ;\tMA\t# ( ‎ﮔ‎ → ‎گ‎ ) ARABIC LETTER GAF INITIAL FORM → ARABIC LETTER GAF\t# \nFB95 ;\t06AF ;\tMA\t# ( ‎ﮕ‎ → ‎گ‎ ) ARABIC LETTER GAF MEDIAL FORM → ARABIC LETTER GAF\t# \nFB93 ;\t06AF ;\tMA\t# ( ‎ﮓ‎ → ‎گ‎ ) ARABIC LETTER GAF FINAL FORM → ARABIC LETTER GAF\t# \nFB92 ;\t06AF ;\tMA\t# ( ‎ﮒ‎ → ‎گ‎ ) ARABIC LETTER GAF ISOLATED FORM → ARABIC LETTER GAF\t# \n08B0 ;\t06AF ;\tMA\t# ( ‎ࢰ‎ → ‎گ‎ ) ARABIC LETTER GAF WITH INVERTED STROKE → ARABIC LETTER GAF\t# \n\n06B4 ;\t06AF 06DB ;\tMA\t# ( ‎ڴ‎ → ‎گۛ‎ ) ARABIC LETTER GAF WITH THREE DOTS ABOVE → ARABIC LETTER GAF, ARABIC SMALL HIGH THREE DOTS\t# \n\nFB9C ;\t06B1 ;\tMA\t# ( ‎ﮜ‎ → ‎ڱ‎ ) ARABIC LETTER NGOEH INITIAL FORM → ARABIC LETTER NGOEH\t# \nFB9D ;\t06B1 ;\tMA\t# ( ‎ﮝ‎ → ‎ڱ‎ ) ARABIC LETTER NGOEH MEDIAL FORM → ARABIC LETTER NGOEH\t# \nFB9B ;\t06B1 ;\tMA\t# ( ‎ﮛ‎ → ‎ڱ‎ ) ARABIC LETTER NGOEH FINAL FORM → ARABIC LETTER NGOEH\t# \nFB9A ;\t06B1 ;\tMA\t# ( ‎ﮚ‎ → ‎ڱ‎ ) ARABIC LETTER NGOEH ISOLATED FORM → ARABIC LETTER NGOEH\t# \n\nFB98 ;\t06B3 ;\tMA\t# ( ‎ﮘ‎ → ‎ڳ‎ ) ARABIC LETTER GUEH INITIAL FORM → ARABIC LETTER GUEH\t# \nFB99 ;\t06B3 ;\tMA\t# ( ‎ﮙ‎ → ‎ڳ‎ ) ARABIC LETTER GUEH MEDIAL FORM → ARABIC LETTER GUEH\t# \nFB97 ;\t06B3 ;\tMA\t# ( ‎ﮗ‎ → ‎ڳ‎ ) ARABIC LETTER GUEH FINAL FORM → ARABIC LETTER GUEH\t# \nFB96 ;\t06B3 ;\tMA\t# ( ‎ﮖ‎ → ‎ڳ‎ ) ARABIC LETTER GUEH ISOLATED FORM → ARABIC LETTER GUEH\t# \n\n1EE0B ;\t0644 ;\tMA\t# ( ‎𞸋‎ → ‎ل‎ ) ARABIC MATHEMATICAL LAM → ARABIC LETTER LAM\t# \n1EE2B ;\t0644 ;\tMA\t# ( ‎𞸫‎ → ‎ل‎ ) ARABIC MATHEMATICAL INITIAL LAM → ARABIC LETTER LAM\t# \n1EE4B ;\t0644 ;\tMA\t# ( ‎𞹋‎ → ‎ل‎ ) ARABIC MATHEMATICAL TAILED LAM → ARABIC LETTER LAM\t# \n1EE8B ;\t0644 ;\tMA\t# ( ‎𞺋‎ → ‎ل‎ ) ARABIC MATHEMATICAL LOOPED LAM → ARABIC LETTER LAM\t# \n1EEAB ;\t0644 ;\tMA\t# ( ‎𞺫‎ → ‎ل‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK LAM → ARABIC LETTER LAM\t# \nFEDF ;\t0644 ;\tMA\t# ( ‎ﻟ‎ → ‎ل‎ ) ARABIC LETTER LAM INITIAL FORM → ARABIC LETTER LAM\t# \nFEE0 ;\t0644 ;\tMA\t# ( ‎ﻠ‎ → ‎ل‎ ) ARABIC LETTER LAM MEDIAL FORM → ARABIC LETTER LAM\t# \nFEDE ;\t0644 ;\tMA\t# ( ‎ﻞ‎ → ‎ل‎ ) ARABIC LETTER LAM FINAL FORM → ARABIC LETTER LAM\t# \nFEDD ;\t0644 ;\tMA\t# ( ‎ﻝ‎ → ‎ل‎ ) ARABIC LETTER LAM ISOLATED FORM → ARABIC LETTER LAM\t# \n\n06B7 ;\t0644 06DB ;\tMA\t# ( ‎ڷ‎ → ‎لۛ‎ ) ARABIC LETTER LAM WITH THREE DOTS ABOVE → ARABIC LETTER LAM, ARABIC SMALL HIGH THREE DOTS\t# \n\n06B5 ;\t0644 0306 ;\tMA\t# ( ‎ڵ‎ → ‎ل̆‎ ) ARABIC LETTER LAM WITH SMALL V → ARABIC LETTER LAM, COMBINING BREVE\t# →‎لٚ‎→\n\nFEFC ;\t0644 006C ;\tMA\t# ( ‎ﻼ‎ → ‎لl‎ ) ARABIC LIGATURE LAM WITH ALEF FINAL FORM → ARABIC LETTER LAM, LATIN SMALL LETTER L\t# →‎لا‎→\nFEFB ;\t0644 006C ;\tMA\t# ( ‎ﻻ‎ → ‎لl‎ ) ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM → ARABIC LETTER LAM, LATIN SMALL LETTER L\t# →‎لا‎→\n\nFEFA ;\t0644 006C 0655 ;\tMA\t# ( ‎ﻺ‎ → ‎لlٕ‎ ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM → ARABIC LETTER LAM, LATIN SMALL LETTER L, ARABIC HAMZA BELOW\t# →‎لإ‎→\nFEF9 ;\t0644 006C 0655 ;\tMA\t# ( ‎ﻹ‎ → ‎لlٕ‎ ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM → ARABIC LETTER LAM, LATIN SMALL LETTER L, ARABIC HAMZA BELOW\t# →‎لإ‎→\n\nFEF8 ;\t0644 006C 0674 ;\tMA\t# ( ‎ﻸ‎ → ‎لlٴ‎ ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM → ARABIC LETTER LAM, LATIN SMALL LETTER L, ARABIC LETTER HIGH HAMZA\t# →‎لأ‎→\nFEF7 ;\t0644 006C 0674 ;\tMA\t# ( ‎ﻷ‎ → ‎لlٴ‎ ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM → ARABIC LETTER LAM, LATIN SMALL LETTER L, ARABIC LETTER HIGH HAMZA\t# →‎لأ‎→\n\nFCCD ;\t0644 006F ;\tMA\t# ( ‎ﳍ‎ → ‎لo‎ ) ARABIC LIGATURE LAM WITH HEH INITIAL FORM → ARABIC LETTER LAM, LATIN SMALL LETTER O\t# →‎له‎→\n\nFEF6 ;\t0644 0622 ;\tMA\t# ( ‎ﻶ‎ → ‎لآ‎ ) ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER ALEF WITH MADDA ABOVE\t# \nFEF5 ;\t0644 0622 ;\tMA\t# ( ‎ﻵ‎ → ‎لآ‎ ) ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM → ARABIC LETTER LAM, ARABIC LETTER ALEF WITH MADDA ABOVE\t# \n\nFCC9 ;\t0644 062C ;\tMA\t# ( ‎ﳉ‎ → ‎لج‎ ) ARABIC LIGATURE LAM WITH JEEM INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER JEEM\t# \nFC3F ;\t0644 062C ;\tMA\t# ( ‎ﰿ‎ → ‎لج‎ ) ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM → ARABIC LETTER LAM, ARABIC LETTER JEEM\t# \n\nFD83 ;\t0644 062C 062C ;\tMA\t# ( ‎ﶃ‎ → ‎لجج‎ ) ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER JEEM, ARABIC LETTER JEEM\t# \nFD84 ;\t0644 062C 062C ;\tMA\t# ( ‎ﶄ‎ → ‎لجج‎ ) ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER JEEM, ARABIC LETTER JEEM\t# \n\nFDBA ;\t0644 062C 0645 ;\tMA\t# ( ‎ﶺ‎ → ‎لجم‎ ) ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \nFDBC ;\t0644 062C 0645 ;\tMA\t# ( ‎ﶼ‎ → ‎لجم‎ ) ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \n\nFDAC ;\t0644 062C 0649 ;\tMA\t# ( ‎ﶬ‎ → ‎لجى‎ ) ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎لجي‎→\n\nFCCA ;\t0644 062D ;\tMA\t# ( ‎ﳊ‎ → ‎لح‎ ) ARABIC LIGATURE LAM WITH HAH INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER HAH\t# \nFC40 ;\t0644 062D ;\tMA\t# ( ‎ﱀ‎ → ‎لح‎ ) ARABIC LIGATURE LAM WITH HAH ISOLATED FORM → ARABIC LETTER LAM, ARABIC LETTER HAH\t# \n\nFDB5 ;\t0644 062D 0645 ;\tMA\t# ( ‎ﶵ‎ → ‎لحم‎ ) ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER HAH, ARABIC LETTER MEEM\t# \nFD80 ;\t0644 062D 0645 ;\tMA\t# ( ‎ﶀ‎ → ‎لحم‎ ) ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER HAH, ARABIC LETTER MEEM\t# \n\nFD82 ;\t0644 062D 0649 ;\tMA\t# ( ‎ﶂ‎ → ‎لحى‎ ) ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# \nFD81 ;\t0644 062D 0649 ;\tMA\t# ( ‎ﶁ‎ → ‎لحى‎ ) ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎لحي‎→\n\nFCCB ;\t0644 062E ;\tMA\t# ( ‎ﳋ‎ → ‎لخ‎ ) ARABIC LIGATURE LAM WITH KHAH INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER KHAH\t# \nFC41 ;\t0644 062E ;\tMA\t# ( ‎ﱁ‎ → ‎لخ‎ ) ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM → ARABIC LETTER LAM, ARABIC LETTER KHAH\t# \n\nFD86 ;\t0644 062E 0645 ;\tMA\t# ( ‎ﶆ‎ → ‎لخم‎ ) ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \nFD85 ;\t0644 062E 0645 ;\tMA\t# ( ‎ﶅ‎ → ‎لخم‎ ) ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \n\nFCCC ;\t0644 0645 ;\tMA\t# ( ‎ﳌ‎ → ‎لم‎ ) ARABIC LIGATURE LAM WITH MEEM INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER MEEM\t# \nFCED ;\t0644 0645 ;\tMA\t# ( ‎ﳭ‎ → ‎لم‎ ) ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM → ARABIC LETTER LAM, ARABIC LETTER MEEM\t# \nFC85 ;\t0644 0645 ;\tMA\t# ( ‎ﲅ‎ → ‎لم‎ ) ARABIC LIGATURE LAM WITH MEEM FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER MEEM\t# \nFC42 ;\t0644 0645 ;\tMA\t# ( ‎ﱂ‎ → ‎لم‎ ) ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM → ARABIC LETTER LAM, ARABIC LETTER MEEM\t# \n\nFD88 ;\t0644 0645 062D ;\tMA\t# ( ‎ﶈ‎ → ‎لمح‎ ) ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM → ARABIC LETTER LAM, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \nFD87 ;\t0644 0645 062D ;\tMA\t# ( ‎ﶇ‎ → ‎لمح‎ ) ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \n\nFDAD ;\t0644 0645 0649 ;\tMA\t# ( ‎ﶭ‎ → ‎لمى‎ ) ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎لمي‎→\n\nFC86 ;\t0644 0649 ;\tMA\t# ( ‎ﲆ‎ → ‎لى‎ ) ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA\t# \nFC43 ;\t0644 0649 ;\tMA\t# ( ‎ﱃ‎ → ‎لى‎ ) ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA\t# \nFC87 ;\t0644 0649 ;\tMA\t# ( ‎ﲇ‎ → ‎لى‎ ) ARABIC LIGATURE LAM WITH YEH FINAL FORM → ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA\t# →‎لي‎→\nFC44 ;\t0644 0649 ;\tMA\t# ( ‎ﱄ‎ → ‎لى‎ ) ARABIC LIGATURE LAM WITH YEH ISOLATED FORM → ARABIC LETTER LAM, ARABIC LETTER ALEF MAKSURA\t# →‎لي‎→\n\n1EE0C ;\t0645 ;\tMA\t# ( ‎𞸌‎ → ‎م‎ ) ARABIC MATHEMATICAL MEEM → ARABIC LETTER MEEM\t# \n1EE2C ;\t0645 ;\tMA\t# ( ‎𞸬‎ → ‎م‎ ) ARABIC MATHEMATICAL INITIAL MEEM → ARABIC LETTER MEEM\t# \n1EE6C ;\t0645 ;\tMA\t# ( ‎𞹬‎ → ‎م‎ ) ARABIC MATHEMATICAL STRETCHED MEEM → ARABIC LETTER MEEM\t# \n1EE8C ;\t0645 ;\tMA\t# ( ‎𞺌‎ → ‎م‎ ) ARABIC MATHEMATICAL LOOPED MEEM → ARABIC LETTER MEEM\t# \n1EEAC ;\t0645 ;\tMA\t# ( ‎𞺬‎ → ‎م‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM → ARABIC LETTER MEEM\t# \nFEE3 ;\t0645 ;\tMA\t# ( ‎ﻣ‎ → ‎م‎ ) ARABIC LETTER MEEM INITIAL FORM → ARABIC LETTER MEEM\t# \nFEE4 ;\t0645 ;\tMA\t# ( ‎ﻤ‎ → ‎م‎ ) ARABIC LETTER MEEM MEDIAL FORM → ARABIC LETTER MEEM\t# \nFEE2 ;\t0645 ;\tMA\t# ( ‎ﻢ‎ → ‎م‎ ) ARABIC LETTER MEEM FINAL FORM → ARABIC LETTER MEEM\t# \nFEE1 ;\t0645 ;\tMA\t# ( ‎ﻡ‎ → ‎م‎ ) ARABIC LETTER MEEM ISOLATED FORM → ARABIC LETTER MEEM\t# \n\n08A7 ;\t0645 06DB ;\tMA\t# ( ‎ࢧ‎ → ‎مۛ‎ ) ARABIC LETTER MEEM WITH THREE DOTS ABOVE → ARABIC LETTER MEEM, ARABIC SMALL HIGH THREE DOTS\t# \n\nFC88 ;\t0645 006C ;\tMA\t# ( ‎ﲈ‎ → ‎مl‎ ) ARABIC LIGATURE MEEM WITH ALEF FINAL FORM → ARABIC LETTER MEEM, LATIN SMALL LETTER L\t# →‎ما‎→\n\nFCCE ;\t0645 062C ;\tMA\t# ( ‎ﳎ‎ → ‎مج‎ ) ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER JEEM\t# \nFC45 ;\t0645 062C ;\tMA\t# ( ‎ﱅ‎ → ‎مج‎ ) ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM → ARABIC LETTER MEEM, ARABIC LETTER JEEM\t# \n\nFD8C ;\t0645 062C 062D ;\tMA\t# ( ‎ﶌ‎ → ‎مجح‎ ) ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER JEEM, ARABIC LETTER HAH\t# \n\nFD92 ;\t0645 062C 062E ;\tMA\t# ( ‎ﶒ‎ → ‎مجخ‎ ) ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER JEEM, ARABIC LETTER KHAH\t# \n\nFD8D ;\t0645 062C 0645 ;\tMA\t# ( ‎ﶍ‎ → ‎مجم‎ ) ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \n\nFDC0 ;\t0645 062C 0649 ;\tMA\t# ( ‎ﷀ‎ → ‎مجى‎ ) ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM → ARABIC LETTER MEEM, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎مجي‎→\n\nFCCF ;\t0645 062D ;\tMA\t# ( ‎ﳏ‎ → ‎مح‎ ) ARABIC LIGATURE MEEM WITH HAH INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \nFC46 ;\t0645 062D ;\tMA\t# ( ‎ﱆ‎ → ‎مح‎ ) ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM → ARABIC LETTER MEEM, ARABIC LETTER HAH\t# \n\nFD89 ;\t0645 062D 062C ;\tMA\t# ( ‎ﶉ‎ → ‎محج‎ ) ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER HAH, ARABIC LETTER JEEM\t# \n\nFD8A ;\t0645 062D 0645 ;\tMA\t# ( ‎ﶊ‎ → ‎محم‎ ) ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER HAH, ARABIC LETTER MEEM\t# \n\nFDF4 ;\t0645 062D 0645 062F ;\tMA\t# ( ‎ﷴ‎ → ‎محمد‎ ) ARABIC LIGATURE MOHAMMAD ISOLATED FORM → ARABIC LETTER MEEM, ARABIC LETTER HAH, ARABIC LETTER MEEM, ARABIC LETTER DAL\t# \n\nFD8B ;\t0645 062D 0649 ;\tMA\t# ( ‎ﶋ‎ → ‎محى‎ ) ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM → ARABIC LETTER MEEM, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎محي‎→\n\nFCD0 ;\t0645 062E ;\tMA\t# ( ‎ﳐ‎ → ‎مخ‎ ) ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER KHAH\t# \nFC47 ;\t0645 062E ;\tMA\t# ( ‎ﱇ‎ → ‎مخ‎ ) ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM → ARABIC LETTER MEEM, ARABIC LETTER KHAH\t# \n\nFD8E ;\t0645 062E 062C ;\tMA\t# ( ‎ﶎ‎ → ‎مخج‎ ) ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER KHAH, ARABIC LETTER JEEM\t# \n\nFD8F ;\t0645 062E 0645 ;\tMA\t# ( ‎ﶏ‎ → ‎مخم‎ ) ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER KHAH, ARABIC LETTER MEEM\t# \n\nFDB9 ;\t0645 062E 0649 ;\tMA\t# ( ‎ﶹ‎ → ‎مخى‎ ) ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM → ARABIC LETTER MEEM, ARABIC LETTER KHAH, ARABIC LETTER ALEF MAKSURA\t# →‎مخي‎→\n\nFCD1 ;\t0645 0645 ;\tMA\t# ( ‎ﳑ‎ → ‎مم‎ ) ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM → ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \nFC89 ;\t0645 0645 ;\tMA\t# ( ‎ﲉ‎ → ‎مم‎ ) ARABIC LIGATURE MEEM WITH MEEM FINAL FORM → ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \nFC48 ;\t0645 0645 ;\tMA\t# ( ‎ﱈ‎ → ‎مم‎ ) ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM → ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# \n\nFDB1 ;\t0645 0645 0649 ;\tMA\t# ( ‎ﶱ‎ → ‎ممى‎ ) ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER MEEM, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎ممي‎→\n\nFC49 ;\t0645 0649 ;\tMA\t# ( ‎ﱉ‎ → ‎مى‎ ) ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# \nFC4A ;\t0645 0649 ;\tMA\t# ( ‎ﱊ‎ → ‎مى‎ ) ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM → ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎مي‎→\n\n06FE ;\t0645 10EFA ;\tMA\t#* ( ‎۾‎ → ‎م𐻺‎ ) ARABIC SIGN SINDHI POSTPOSITION MEN → ARABIC LETTER MEEM, ARABIC DOUBLE VERTICAL BAR BELOW\t# \n\n1EE0D ;\t0646 ;\tMA\t# ( ‎𞸍‎ → ‎ن‎ ) ARABIC MATHEMATICAL NOON → ARABIC LETTER NOON\t# \n1EE2D ;\t0646 ;\tMA\t# ( ‎𞸭‎ → ‎ن‎ ) ARABIC MATHEMATICAL INITIAL NOON → ARABIC LETTER NOON\t# \n1EE4D ;\t0646 ;\tMA\t# ( ‎𞹍‎ → ‎ن‎ ) ARABIC MATHEMATICAL TAILED NOON → ARABIC LETTER NOON\t# \n1EE6D ;\t0646 ;\tMA\t# ( ‎𞹭‎ → ‎ن‎ ) ARABIC MATHEMATICAL STRETCHED NOON → ARABIC LETTER NOON\t# \n1EE8D ;\t0646 ;\tMA\t# ( ‎𞺍‎ → ‎ن‎ ) ARABIC MATHEMATICAL LOOPED NOON → ARABIC LETTER NOON\t# \n1EEAD ;\t0646 ;\tMA\t# ( ‎𞺭‎ → ‎ن‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK NOON → ARABIC LETTER NOON\t# \nFEE7 ;\t0646 ;\tMA\t# ( ‎ﻧ‎ → ‎ن‎ ) ARABIC LETTER NOON INITIAL FORM → ARABIC LETTER NOON\t# \nFEE8 ;\t0646 ;\tMA\t# ( ‎ﻨ‎ → ‎ن‎ ) ARABIC LETTER NOON MEDIAL FORM → ARABIC LETTER NOON\t# \nFEE6 ;\t0646 ;\tMA\t# ( ‎ﻦ‎ → ‎ن‎ ) ARABIC LETTER NOON FINAL FORM → ARABIC LETTER NOON\t# \nFEE5 ;\t0646 ;\tMA\t# ( ‎ﻥ‎ → ‎ن‎ ) ARABIC LETTER NOON ISOLATED FORM → ARABIC LETTER NOON\t# \n10EC6 ;\t0646 ;\tMA\t# ( ‎𐻆‎ → ‎ن‎ ) ARABIC LETTER THIN NOON → ARABIC LETTER NOON\t# \n\n0768 ;\t0646 0615 ;\tMA\t# ( ‎ݨ‎ → ‎نؕ‎ ) ARABIC LETTER NOON WITH SMALL TAH → ARABIC LETTER NOON, ARABIC SMALL HIGH TAH\t# \n\n0769 ;\t0646 0306 ;\tMA\t# ( ‎ݩ‎ → ‎ن̆‎ ) ARABIC LETTER NOON WITH SMALL V → ARABIC LETTER NOON, COMBINING BREVE\t# →‎نٚ‎→\n\nFCD6 ;\t0646 006F ;\tMA\t# ( ‎ﳖ‎ → ‎نo‎ ) ARABIC LIGATURE NOON WITH HEH INITIAL FORM → ARABIC LETTER NOON, LATIN SMALL LETTER O\t# →‎نه‎→\nFCEF ;\t0646 006F ;\tMA\t# ( ‎ﳯ‎ → ‎نo‎ ) ARABIC LIGATURE NOON WITH HEH MEDIAL FORM → ARABIC LETTER NOON, LATIN SMALL LETTER O\t# →‎نه‎→\n\nFDB8 ;\t0646 062C 062D ;\tMA\t# ( ‎ﶸ‎ → ‎نجح‎ ) ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM → ARABIC LETTER NOON, ARABIC LETTER JEEM, ARABIC LETTER HAH\t# \nFDBD ;\t0646 062C 062D ;\tMA\t# ( ‎ﶽ‎ → ‎نجح‎ ) ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER JEEM, ARABIC LETTER HAH\t# \n\nFD98 ;\t0646 062C 0645 ;\tMA\t# ( ‎ﶘ‎ → ‎نجم‎ ) ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM → ARABIC LETTER NOON, ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \nFD97 ;\t0646 062C 0645 ;\tMA\t# ( ‎ﶗ‎ → ‎نجم‎ ) ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER JEEM, ARABIC LETTER MEEM\t# \n\nFD99 ;\t0646 062C 0649 ;\tMA\t# ( ‎ﶙ‎ → ‎نجى‎ ) ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# \nFDC7 ;\t0646 062C 0649 ;\tMA\t# ( ‎ﷇ‎ → ‎نجى‎ ) ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎نجي‎→\n\nFCD3 ;\t0646 062D ;\tMA\t# ( ‎ﳓ‎ → ‎نح‎ ) ARABIC LIGATURE NOON WITH HAH INITIAL FORM → ARABIC LETTER NOON, ARABIC LETTER HAH\t# \nFC4C ;\t0646 062D ;\tMA\t# ( ‎ﱌ‎ → ‎نح‎ ) ARABIC LIGATURE NOON WITH HAH ISOLATED FORM → ARABIC LETTER NOON, ARABIC LETTER HAH\t# \n\nFD95 ;\t0646 062D 0645 ;\tMA\t# ( ‎ﶕ‎ → ‎نحم‎ ) ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM → ARABIC LETTER NOON, ARABIC LETTER HAH, ARABIC LETTER MEEM\t# \n\nFD96 ;\t0646 062D 0649 ;\tMA\t# ( ‎ﶖ‎ → ‎نحى‎ ) ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# \nFDB3 ;\t0646 062D 0649 ;\tMA\t# ( ‎ﶳ‎ → ‎نحى‎ ) ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎نحي‎→\n\nFCD4 ;\t0646 062E ;\tMA\t# ( ‎ﳔ‎ → ‎نخ‎ ) ARABIC LIGATURE NOON WITH KHAH INITIAL FORM → ARABIC LETTER NOON, ARABIC LETTER KHAH\t# \nFC4D ;\t0646 062E ;\tMA\t# ( ‎ﱍ‎ → ‎نخ‎ ) ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM → ARABIC LETTER NOON, ARABIC LETTER KHAH\t# \n\nFC8A ;\t0646 0631 ;\tMA\t# ( ‎ﲊ‎ → ‎نر‎ ) ARABIC LIGATURE NOON WITH REH FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER REH\t# \n\nFC8B ;\t0646 0632 ;\tMA\t# ( ‎ﲋ‎ → ‎نز‎ ) ARABIC LIGATURE NOON WITH ZAIN FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER ZAIN\t# \n\nFCD5 ;\t0646 0645 ;\tMA\t# ( ‎ﳕ‎ → ‎نم‎ ) ARABIC LIGATURE NOON WITH MEEM INITIAL FORM → ARABIC LETTER NOON, ARABIC LETTER MEEM\t# \nFCEE ;\t0646 0645 ;\tMA\t# ( ‎ﳮ‎ → ‎نم‎ ) ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM → ARABIC LETTER NOON, ARABIC LETTER MEEM\t# \nFC8C ;\t0646 0645 ;\tMA\t# ( ‎ﲌ‎ → ‎نم‎ ) ARABIC LIGATURE NOON WITH MEEM FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER MEEM\t# \nFC4E ;\t0646 0645 ;\tMA\t# ( ‎ﱎ‎ → ‎نم‎ ) ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM → ARABIC LETTER NOON, ARABIC LETTER MEEM\t# \n\nFD9B ;\t0646 0645 0649 ;\tMA\t# ( ‎ﶛ‎ → ‎نمى‎ ) ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# \nFD9A ;\t0646 0645 0649 ;\tMA\t# ( ‎ﶚ‎ → ‎نمى‎ ) ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎نمي‎→\n\nFC8D ;\t0646 0646 ;\tMA\t# ( ‎ﲍ‎ → ‎نن‎ ) ARABIC LIGATURE NOON WITH NOON FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER NOON\t# \n\nFC8E ;\t0646 0649 ;\tMA\t# ( ‎ﲎ‎ → ‎نى‎ ) ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER ALEF MAKSURA\t# \nFC4F ;\t0646 0649 ;\tMA\t# ( ‎ﱏ‎ → ‎نى‎ ) ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER NOON, ARABIC LETTER ALEF MAKSURA\t# \nFC8F ;\t0646 0649 ;\tMA\t# ( ‎ﲏ‎ → ‎نى‎ ) ARABIC LIGATURE NOON WITH YEH FINAL FORM → ARABIC LETTER NOON, ARABIC LETTER ALEF MAKSURA\t# →‎ني‎→\nFC50 ;\t0646 0649 ;\tMA\t# ( ‎ﱐ‎ → ‎نى‎ ) ARABIC LIGATURE NOON WITH YEH ISOLATED FORM → ARABIC LETTER NOON, ARABIC LETTER ALEF MAKSURA\t# →‎ني‎→\n\n06C2 ;\t06C0 ;\tMA\t# ( ‎ۂ‎ → ‎ۀ‎ ) ARABIC LETTER HEH GOAL WITH HAMZA ABOVE → ARABIC LETTER HEH WITH YEH ABOVE\t# →‎ﮤ‎→\nFBA5 ;\t06C0 ;\tMA\t# ( ‎ﮥ‎ → ‎ۀ‎ ) ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM → ARABIC LETTER HEH WITH YEH ABOVE\t# \nFBA4 ;\t06C0 ;\tMA\t# ( ‎ﮤ‎ → ‎ۀ‎ ) ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM → ARABIC LETTER HEH WITH YEH ABOVE\t# \n\n102E4 ;\t0648 ;\tMA\t#* ( 𐋤 → ‎و‎ ) COPTIC EPACT DIGIT FOUR → ARABIC LETTER WAW\t# \n1EE05 ;\t0648 ;\tMA\t# ( ‎𞸅‎ → ‎و‎ ) ARABIC MATHEMATICAL WAW → ARABIC LETTER WAW\t# \n1EE85 ;\t0648 ;\tMA\t# ( ‎𞺅‎ → ‎و‎ ) ARABIC MATHEMATICAL LOOPED WAW → ARABIC LETTER WAW\t# \n1EEA5 ;\t0648 ;\tMA\t# ( ‎𞺥‎ → ‎و‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK WAW → ARABIC LETTER WAW\t# \nFEEE ;\t0648 ;\tMA\t# ( ‎ﻮ‎ → ‎و‎ ) ARABIC LETTER WAW FINAL FORM → ARABIC LETTER WAW\t# \nFEED ;\t0648 ;\tMA\t# ( ‎ﻭ‎ → ‎و‎ ) ARABIC LETTER WAW ISOLATED FORM → ARABIC LETTER WAW\t# \n08B1 ;\t0648 ;\tMA\t# ( ‎ࢱ‎ → ‎و‎ ) ARABIC LETTER STRAIGHT WAW → ARABIC LETTER WAW\t# \n\n06CB ;\t0648 06DB ;\tMA\t# ( ‎ۋ‎ → ‎وۛ‎ ) ARABIC LETTER VE → ARABIC LETTER WAW, ARABIC SMALL HIGH THREE DOTS\t# \nFBDF ;\t0648 06DB ;\tMA\t# ( ‎ﯟ‎ → ‎وۛ‎ ) ARABIC LETTER VE FINAL FORM → ARABIC LETTER WAW, ARABIC SMALL HIGH THREE DOTS\t# →‎ۋ‎→\nFBDE ;\t0648 06DB ;\tMA\t# ( ‎ﯞ‎ → ‎وۛ‎ ) ARABIC LETTER VE ISOLATED FORM → ARABIC LETTER WAW, ARABIC SMALL HIGH THREE DOTS\t# →‎ۋ‎→\n\n06C7 ;\t0648 0313 ;\tMA\t# ( ‎ۇ‎ → ‎و̓‎ ) ARABIC LETTER U → ARABIC LETTER WAW, COMBINING COMMA ABOVE\t# →‎وُ‎→\nFBD8 ;\t0648 0313 ;\tMA\t# ( ‎ﯘ‎ → ‎و̓‎ ) ARABIC LETTER U FINAL FORM → ARABIC LETTER WAW, COMBINING COMMA ABOVE\t# →‎ۇ‎→→‎وُ‎→\nFBD7 ;\t0648 0313 ;\tMA\t# ( ‎ﯗ‎ → ‎و̓‎ ) ARABIC LETTER U ISOLATED FORM → ARABIC LETTER WAW, COMBINING COMMA ABOVE\t# →‎ۇ‎→→‎وُ‎→\n\n06C6 ;\t0648 0306 ;\tMA\t# ( ‎ۆ‎ → ‎و̆‎ ) ARABIC LETTER OE → ARABIC LETTER WAW, COMBINING BREVE\t# →‎وٚ‎→\nFBDA ;\t0648 0306 ;\tMA\t# ( ‎ﯚ‎ → ‎و̆‎ ) ARABIC LETTER OE FINAL FORM → ARABIC LETTER WAW, COMBINING BREVE\t# →‎ۆ‎→→‎وٚ‎→\nFBD9 ;\t0648 0306 ;\tMA\t# ( ‎ﯙ‎ → ‎و̆‎ ) ARABIC LETTER OE ISOLATED FORM → ARABIC LETTER WAW, COMBINING BREVE\t# →‎ۆ‎→→‎وٚ‎→\n\n06C9 ;\t0648 0302 ;\tMA\t# ( ‎ۉ‎ → ‎و̂‎ ) ARABIC LETTER KIRGHIZ YU → ARABIC LETTER WAW, COMBINING CIRCUMFLEX ACCENT\t# →‎وٛ‎→\nFBE3 ;\t0648 0302 ;\tMA\t# ( ‎ﯣ‎ → ‎و̂‎ ) ARABIC LETTER KIRGHIZ YU FINAL FORM → ARABIC LETTER WAW, COMBINING CIRCUMFLEX ACCENT\t# →‎ۉ‎→→‎وٛ‎→\nFBE2 ;\t0648 0302 ;\tMA\t# ( ‎ﯢ‎ → ‎و̂‎ ) ARABIC LETTER KIRGHIZ YU ISOLATED FORM → ARABIC LETTER WAW, COMBINING CIRCUMFLEX ACCENT\t# →‎ۉ‎→→‎وٛ‎→\n\n06C8 ;\t0648 0670 ;\tMA\t# ( ‎ۈ‎ → ‎وٰ‎ ) ARABIC LETTER YU → ARABIC LETTER WAW, ARABIC LETTER SUPERSCRIPT ALEF\t# \nFBDC ;\t0648 0670 ;\tMA\t# ( ‎ﯜ‎ → ‎وٰ‎ ) ARABIC LETTER YU FINAL FORM → ARABIC LETTER WAW, ARABIC LETTER SUPERSCRIPT ALEF\t# →‎ۈ‎→\nFBDB ;\t0648 0670 ;\tMA\t# ( ‎ﯛ‎ → ‎وٰ‎ ) ARABIC LETTER YU ISOLATED FORM → ARABIC LETTER WAW, ARABIC LETTER SUPERSCRIPT ALEF\t# →‎ۈ‎→\n\n0676 ;\t0648 0674 ;\tMA\t# ( ‎ٶ‎ → ‎وٴ‎ ) ARABIC LETTER HIGH HAMZA WAW → ARABIC LETTER WAW, ARABIC LETTER HIGH HAMZA\t# \n0624 ;\t0648 0674 ;\tMA\t# ( ‎ؤ‎ → ‎وٴ‎ ) ARABIC LETTER WAW WITH HAMZA ABOVE → ARABIC LETTER WAW, ARABIC LETTER HIGH HAMZA\t# →‎ٶ‎→\nFE86 ;\t0648 0674 ;\tMA\t# ( ‎ﺆ‎ → ‎وٴ‎ ) ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM → ARABIC LETTER WAW, ARABIC LETTER HIGH HAMZA\t# →‎ٶ‎→\nFE85 ;\t0648 0674 ;\tMA\t# ( ‎ﺅ‎ → ‎وٴ‎ ) ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM → ARABIC LETTER WAW, ARABIC LETTER HIGH HAMZA\t# →‎ٶ‎→\n\n0677 ;\t0648 0313 0674 ;\tMA\t# ( ‎ٷ‎ → ‎و̓ٴ‎ ) ARABIC LETTER U WITH HAMZA ABOVE → ARABIC LETTER WAW, COMBINING COMMA ABOVE, ARABIC LETTER HIGH HAMZA\t# →‎ۇٴ‎→\nFBDD ;\t0648 0313 0674 ;\tMA\t# ( ‎ﯝ‎ → ‎و̓ٴ‎ ) ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM → ARABIC LETTER WAW, COMBINING COMMA ABOVE, ARABIC LETTER HIGH HAMZA\t# →‎ۇٴ‎→\n\nFDF8 ;\t0648 0633 0644 0645 ;\tMA\t# ( ‎ﷸ‎ → ‎وسلم‎ ) ARABIC LIGATURE WASALLAM ISOLATED FORM → ARABIC LETTER WAW, ARABIC LETTER SEEN, ARABIC LETTER LAM, ARABIC LETTER MEEM\t# \n\nFBE1 ;\t06C5 ;\tMA\t# ( ‎ﯡ‎ → ‎ۅ‎ ) ARABIC LETTER KIRGHIZ OE FINAL FORM → ARABIC LETTER KIRGHIZ OE\t# \nFBE0 ;\t06C5 ;\tMA\t# ( ‎ﯠ‎ → ‎ۅ‎ ) ARABIC LETTER KIRGHIZ OE ISOLATED FORM → ARABIC LETTER KIRGHIZ OE\t# \n\n066E ;\t0649 ;\tMA\t# ( ‎ٮ‎ → ‎ى‎ ) ARABIC LETTER DOTLESS BEH → ARABIC LETTER ALEF MAKSURA\t# \n1EE1C ;\t0649 ;\tMA\t# ( ‎𞸜‎ → ‎ى‎ ) ARABIC MATHEMATICAL DOTLESS BEH → ARABIC LETTER ALEF MAKSURA\t# →‎ٮ‎→\n1EE7C ;\t0649 ;\tMA\t# ( ‎𞹼‎ → ‎ى‎ ) ARABIC MATHEMATICAL STRETCHED DOTLESS BEH → ARABIC LETTER ALEF MAKSURA\t# →‎ٮ‎→\n06BA ;\t0649 ;\tMA\t# ( ‎ں‎ → ‎ى‎ ) ARABIC LETTER NOON GHUNNA → ARABIC LETTER ALEF MAKSURA\t# \n1EE1D ;\t0649 ;\tMA\t# ( ‎𞸝‎ → ‎ى‎ ) ARABIC MATHEMATICAL DOTLESS NOON → ARABIC LETTER ALEF MAKSURA\t# →‎ں‎→\n1EE5D ;\t0649 ;\tMA\t# ( ‎𞹝‎ → ‎ى‎ ) ARABIC MATHEMATICAL TAILED DOTLESS NOON → ARABIC LETTER ALEF MAKSURA\t# →‎ں‎→\nFB9F ;\t0649 ;\tMA\t# ( ‎ﮟ‎ → ‎ى‎ ) ARABIC LETTER NOON GHUNNA FINAL FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ں‎→\nFB9E ;\t0649 ;\tMA\t# ( ‎ﮞ‎ → ‎ى‎ ) ARABIC LETTER NOON GHUNNA ISOLATED FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ں‎→\n08BD ;\t0649 ;\tMA\t# ( ‎ࢽ‎ → ‎ى‎ ) ARABIC LETTER AFRICAN NOON → ARABIC LETTER ALEF MAKSURA\t# →‎ں‎→\nFBE8 ;\t0649 ;\tMA\t# ( ‎ﯨ‎ → ‎ى‎ ) ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM → ARABIC LETTER ALEF MAKSURA\t# \nFBE9 ;\t0649 ;\tMA\t# ( ‎ﯩ‎ → ‎ى‎ ) ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM → ARABIC LETTER ALEF MAKSURA\t# \nFEF0 ;\t0649 ;\tMA\t# ( ‎ﻰ‎ → ‎ى‎ ) ARABIC LETTER ALEF MAKSURA FINAL FORM → ARABIC LETTER ALEF MAKSURA\t# \nFEEF ;\t0649 ;\tMA\t# ( ‎ﻯ‎ → ‎ى‎ ) ARABIC LETTER ALEF MAKSURA ISOLATED FORM → ARABIC LETTER ALEF MAKSURA\t# \n064A ;\t0649 ;\tMA\t# ( ‎ي‎ → ‎ى‎ ) ARABIC LETTER YEH → ARABIC LETTER ALEF MAKSURA\t# \n1EE09 ;\t0649 ;\tMA\t# ( ‎𞸉‎ → ‎ى‎ ) ARABIC MATHEMATICAL YEH → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\n1EE29 ;\t0649 ;\tMA\t# ( ‎𞸩‎ → ‎ى‎ ) ARABIC MATHEMATICAL INITIAL YEH → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\n1EE49 ;\t0649 ;\tMA\t# ( ‎𞹉‎ → ‎ى‎ ) ARABIC MATHEMATICAL TAILED YEH → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\n1EE69 ;\t0649 ;\tMA\t# ( ‎𞹩‎ → ‎ى‎ ) ARABIC MATHEMATICAL STRETCHED YEH → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\n1EE89 ;\t0649 ;\tMA\t# ( ‎𞺉‎ → ‎ى‎ ) ARABIC MATHEMATICAL LOOPED YEH → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\n1EEA9 ;\t0649 ;\tMA\t# ( ‎𞺩‎ → ‎ى‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK YEH → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\nFEF3 ;\t0649 ;\tMA\t# ( ‎ﻳ‎ → ‎ى‎ ) ARABIC LETTER YEH INITIAL FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\nFEF4 ;\t0649 ;\tMA\t# ( ‎ﻴ‎ → ‎ى‎ ) ARABIC LETTER YEH MEDIAL FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\nFEF2 ;\t0649 ;\tMA\t# ( ‎ﻲ‎ → ‎ى‎ ) ARABIC LETTER YEH FINAL FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\nFEF1 ;\t0649 ;\tMA\t# ( ‎ﻱ‎ → ‎ى‎ ) ARABIC LETTER YEH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\n06CC ;\t0649 ;\tMA\t# ( ‎ی‎ → ‎ى‎ ) ARABIC LETTER FARSI YEH → ARABIC LETTER ALEF MAKSURA\t# \nFBFE ;\t0649 ;\tMA\t# ( ‎ﯾ‎ → ‎ى‎ ) ARABIC LETTER FARSI YEH INITIAL FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ی‎→\nFBFF ;\t0649 ;\tMA\t# ( ‎ﯿ‎ → ‎ى‎ ) ARABIC LETTER FARSI YEH MEDIAL FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ی‎→\nFBFD ;\t0649 ;\tMA\t# ( ‎ﯽ‎ → ‎ى‎ ) ARABIC LETTER FARSI YEH FINAL FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ﻰ‎→\nFBFC ;\t0649 ;\tMA\t# ( ‎ﯼ‎ → ‎ى‎ ) ARABIC LETTER FARSI YEH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA\t# \n06D2 ;\t0649 ;\tMA\t# ( ‎ے‎ → ‎ى‎ ) ARABIC LETTER YEH BARREE → ARABIC LETTER ALEF MAKSURA\t# →‎ي‎→\nFBAF ;\t0649 ;\tMA\t# ( ‎ﮯ‎ → ‎ى‎ ) ARABIC LETTER YEH BARREE FINAL FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ے‎→→‎ي‎→\nFBAE ;\t0649 ;\tMA\t# ( ‎ﮮ‎ → ‎ى‎ ) ARABIC LETTER YEH BARREE ISOLATED FORM → ARABIC LETTER ALEF MAKSURA\t# →‎ے‎→→‎ي‎→\n\n0679 ;\t0649 0615 ;\tMA\t# ( ‎ٹ‎ → ‎ىؕ‎ ) ARABIC LETTER TTEH → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ٮؕ‎→\nFB68 ;\t0649 0615 ;\tMA\t# ( ‎ﭨ‎ → ‎ىؕ‎ ) ARABIC LETTER TTEH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ٹ‎→→‎ٮؕ‎→\nFB69 ;\t0649 0615 ;\tMA\t# ( ‎ﭩ‎ → ‎ىؕ‎ ) ARABIC LETTER TTEH MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ٹ‎→→‎ٮؕ‎→\nFB67 ;\t0649 0615 ;\tMA\t# ( ‎ﭧ‎ → ‎ىؕ‎ ) ARABIC LETTER TTEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ٹ‎→→‎ٮؕ‎→\nFB66 ;\t0649 0615 ;\tMA\t# ( ‎ﭦ‎ → ‎ىؕ‎ ) ARABIC LETTER TTEH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ٹ‎→→‎ٮؕ‎→\n06BB ;\t0649 0615 ;\tMA\t# ( ‎ڻ‎ → ‎ىؕ‎ ) ARABIC LETTER RNOON → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ںؕ‎→\nFBA2 ;\t0649 0615 ;\tMA\t# ( ‎ﮢ‎ → ‎ىؕ‎ ) ARABIC LETTER RNOON INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ڻ‎→→‎ںؕ‎→\nFBA3 ;\t0649 0615 ;\tMA\t# ( ‎ﮣ‎ → ‎ىؕ‎ ) ARABIC LETTER RNOON MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ڻ‎→→‎ںؕ‎→\nFBA1 ;\t0649 0615 ;\tMA\t# ( ‎ﮡ‎ → ‎ىؕ‎ ) ARABIC LETTER RNOON FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ڻ‎→→‎ںؕ‎→\nFBA0 ;\t0649 0615 ;\tMA\t# ( ‎ﮠ‎ → ‎ىؕ‎ ) ARABIC LETTER RNOON ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH\t# →‎ڻ‎→→‎ںؕ‎→\n\n067E ;\t0649 06DB ;\tMA\t# ( ‎پ‎ → ‎ىۛ‎ ) ARABIC LETTER PEH → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ڽ‎→→‎ںۛ‎→\nFB58 ;\t0649 06DB ;\tMA\t# ( ‎ﭘ‎ → ‎ىۛ‎ ) ARABIC LETTER PEH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎پ‎→→‎ڽ‎→→‎ںۛ‎→\nFB59 ;\t0649 06DB ;\tMA\t# ( ‎ﭙ‎ → ‎ىۛ‎ ) ARABIC LETTER PEH MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎پ‎→→‎ڽ‎→→‎ںۛ‎→\nFB57 ;\t0649 06DB ;\tMA\t# ( ‎ﭗ‎ → ‎ىۛ‎ ) ARABIC LETTER PEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎پ‎→→‎ڽ‎→→‎ںۛ‎→\nFB56 ;\t0649 06DB ;\tMA\t# ( ‎ﭖ‎ → ‎ىۛ‎ ) ARABIC LETTER PEH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎پ‎→→‎ڽ‎→→‎ںۛ‎→\n0752 ;\t0649 06DB ;\tMA\t# ( ‎ݒ‎ → ‎ىۛ‎ ) ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎پ‎→→‎ڽ‎→→‎ںۛ‎→\n062B ;\t0649 06DB ;\tMA\t# ( ‎ث‎ → ‎ىۛ‎ ) ARABIC LETTER THEH → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ٮۛ‎→\n1EE16 ;\t0649 06DB ;\tMA\t# ( ‎𞸖‎ → ‎ىۛ‎ ) ARABIC MATHEMATICAL THEH → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\n1EE36 ;\t0649 06DB ;\tMA\t# ( ‎𞸶‎ → ‎ىۛ‎ ) ARABIC MATHEMATICAL INITIAL THEH → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\n1EE76 ;\t0649 06DB ;\tMA\t# ( ‎𞹶‎ → ‎ىۛ‎ ) ARABIC MATHEMATICAL STRETCHED THEH → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\n1EE96 ;\t0649 06DB ;\tMA\t# ( ‎𞺖‎ → ‎ىۛ‎ ) ARABIC MATHEMATICAL LOOPED THEH → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\n1EEB6 ;\t0649 06DB ;\tMA\t# ( ‎𞺶‎ → ‎ىۛ‎ ) ARABIC MATHEMATICAL DOUBLE-STRUCK THEH → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\nFE9B ;\t0649 06DB ;\tMA\t# ( ‎ﺛ‎ → ‎ىۛ‎ ) ARABIC LETTER THEH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\nFE9C ;\t0649 06DB ;\tMA\t# ( ‎ﺜ‎ → ‎ىۛ‎ ) ARABIC LETTER THEH MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\nFE9A ;\t0649 06DB ;\tMA\t# ( ‎ﺚ‎ → ‎ىۛ‎ ) ARABIC LETTER THEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\nFE99 ;\t0649 06DB ;\tMA\t# ( ‎ﺙ‎ → ‎ىۛ‎ ) ARABIC LETTER THEH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ث‎→→‎ٮۛ‎→\n06BD ;\t0649 06DB ;\tMA\t# ( ‎ڽ‎ → ‎ىۛ‎ ) ARABIC LETTER NOON WITH THREE DOTS ABOVE → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎ںۛ‎→\n06D1 ;\t0649 06DB ;\tMA\t# ( ‎ۑ‎ → ‎ىۛ‎ ) ARABIC LETTER YEH WITH THREE DOTS BELOW → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎پ‎→→‎ڽ‎→→‎ںۛ‎→\n063F ;\t0649 06DB ;\tMA\t# ( ‎ؿ‎ → ‎ىۛ‎ ) ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS\t# →‎یۛ‎→\n\n08B7 ;\t0649 06DB 06E2 ;\tMA\t# ( ‎ࢷ‎ → ‎ىۛۢ‎ ) ARABIC LETTER PEH WITH SMALL MEEM ABOVE → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC SMALL HIGH MEEM ISOLATED FORM\t# →‎پۢ‎→\n\n0756 ;\t0649 0306 ;\tMA\t# ( ‎ݖ‎ → ‎ى̆‎ ) ARABIC LETTER BEH WITH SMALL V → ARABIC LETTER ALEF MAKSURA, COMBINING BREVE\t# →‎ٮٚ‎→\n06CE ;\t0649 0306 ;\tMA\t# ( ‎ێ‎ → ‎ى̆‎ ) ARABIC LETTER YEH WITH SMALL V → ARABIC LETTER ALEF MAKSURA, COMBINING BREVE\t# →‎یٚ‎→\n\n08C0 ;\t0649 0615 0306 ;\tMA\t# ( ‎ࣀ‎ → ‎ىؕ̆‎ ) ARABIC LETTER TTEH WITH SMALL V → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH TAH, COMBINING BREVE\t# →‎ٹٚ‎→\n\n08BE ;\t0649 06DB 0306 ;\tMA\t# ( ‎ࢾ‎ → ‎ىۛ̆‎ ) ARABIC LETTER PEH WITH SMALL V → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, COMBINING BREVE\t# →‎پٚ‎→\n\n08BA ;\t0649 0306 0307 ;\tMA\t# ( ‎ࢺ‎ → ‎ى̆̇‎ ) ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE → ARABIC LETTER ALEF MAKSURA, COMBINING BREVE, COMBINING DOT ABOVE\t# →‎يۨ‎→\n\n063D ;\t0649 0302 ;\tMA\t# ( ‎ؽ‎ → ‎ى̂‎ ) ARABIC LETTER FARSI YEH WITH INVERTED V → ARABIC LETTER ALEF MAKSURA, COMBINING CIRCUMFLEX ACCENT\t# →‎یٛ‎→\n\n088F ;\t0649 030A ;\tMA\t# ( ‎࢏‎ → ‎ى̊‎ ) ARABIC LETTER NOON WITH RING ABOVE → ARABIC LETTER ALEF MAKSURA, COMBINING RING ABOVE\t# →‎ں̊‎→\n\n08A8 ;\t0649 0654 ;\tMA\t# ( ‎ࢨ‎ → ‎ىٔ‎ ) ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE → ARABIC LETTER ALEF MAKSURA, ARABIC HAMZA ABOVE\t# →‎ئ‎→\n\nFC90 ;\t0649 0670 ;\tMA\t# ( ‎ﲐ‎ → ‎ىٰ‎ ) ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER SUPERSCRIPT ALEF\t# \nFC5D ;\t0649 0670 ;\tMA\t# ( ‎ﱝ‎ → ‎ىٰ‎ ) ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER SUPERSCRIPT ALEF\t# \n\nFCDE ;\t0649 006F ;\tMA\t# ( ‎ﳞ‎ → ‎ىo‎ ) ARABIC LIGATURE YEH WITH HEH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, LATIN SMALL LETTER O\t# →‎يه‎→\nFCF1 ;\t0649 006F ;\tMA\t# ( ‎ﳱ‎ → ‎ىo‎ ) ARABIC LIGATURE YEH WITH HEH MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, LATIN SMALL LETTER O\t# →‎يه‎→\n\nFCE6 ;\t0649 06DB 006F ;\tMA\t# ( ‎ﳦ‎ → ‎ىۛo‎ ) ARABIC LIGATURE THEH WITH HEH MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, LATIN SMALL LETTER O\t# →‎ثه‎→\n\n0678 ;\t0649 0674 ;\tMA\t# ( ‎ٸ‎ → ‎ىٴ‎ ) ARABIC LETTER HIGH HAMZA YEH → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA\t# →‎يٴ‎→\n0626 ;\t0649 0674 ;\tMA\t# ( ‎ئ‎ → ‎ىٴ‎ ) ARABIC LETTER YEH WITH HAMZA ABOVE → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA\t# →‎ٸ‎→→‎يٴ‎→\nFE8B ;\t0649 0674 ;\tMA\t# ( ‎ﺋ‎ → ‎ىٴ‎ ) ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA\t# →‎ئ‎→→‎ٸ‎→→‎يٴ‎→\nFE8C ;\t0649 0674 ;\tMA\t# ( ‎ﺌ‎ → ‎ىٴ‎ ) ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA\t# →‎ئ‎→→‎ٸ‎→→‎يٴ‎→\nFE8A ;\t0649 0674 ;\tMA\t# ( ‎ﺊ‎ → ‎ىٴ‎ ) ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA\t# →‎ئ‎→→‎ٸ‎→→‎يٴ‎→\nFE89 ;\t0649 0674 ;\tMA\t# ( ‎ﺉ‎ → ‎ىٴ‎ ) ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA\t# →‎ٸ‎→→‎يٴ‎→\n\nFBEB ;\t0649 0674 006C ;\tMA\t# ( ‎ﯫ‎ → ‎ىٴl‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, LATIN SMALL LETTER L\t# →‎ئا‎→\nFBEA ;\t0649 0674 006C ;\tMA\t# ( ‎ﯪ‎ → ‎ىٴl‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, LATIN SMALL LETTER L\t# →‎ئا‎→\n\nFC9B ;\t0649 0674 006F ;\tMA\t# ( ‎ﲛ‎ → ‎ىٴo‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, LATIN SMALL LETTER O\t# →‎ئه‎→\nFCE0 ;\t0649 0674 006F ;\tMA\t# ( ‎ﳠ‎ → ‎ىٴo‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, LATIN SMALL LETTER O\t# →‎ئه‎→\nFBED ;\t0649 0674 006F ;\tMA\t# ( ‎ﯭ‎ → ‎ىٴo‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, LATIN SMALL LETTER O\t# →‎ئە‎→→‎ٴىo‎→→‎ئه‎→\nFBEC ;\t0649 0674 006F ;\tMA\t# ( ‎ﯬ‎ → ‎ىٴo‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, LATIN SMALL LETTER O\t# →‎ئە‎→→‎ٴىo‎→→‎ئه‎→\n\nFBF8 ;\t0649 0674 067B ;\tMA\t# ( ‎ﯸ‎ → ‎ىٴٻ‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER BEEH\t# →‎ئې‎→\nFBF7 ;\t0649 0674 067B ;\tMA\t# ( ‎ﯷ‎ → ‎ىٴٻ‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER BEEH\t# →‎ئې‎→\nFBF6 ;\t0649 0674 067B ;\tMA\t# ( ‎ﯶ‎ → ‎ىٴٻ‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER BEEH\t# →‎ئې‎→\n\nFC97 ;\t0649 0674 062C ;\tMA\t# ( ‎ﲗ‎ → ‎ىٴج‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER JEEM\t# →‎ئج‎→\nFC00 ;\t0649 0674 062C ;\tMA\t# ( ‎ﰀ‎ → ‎ىٴج‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER JEEM\t# →‎ئج‎→\n\nFC98 ;\t0649 0674 062D ;\tMA\t# ( ‎ﲘ‎ → ‎ىٴح‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER HAH\t# →‎ئح‎→\nFC01 ;\t0649 0674 062D ;\tMA\t# ( ‎ﰁ‎ → ‎ىٴح‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER HAH\t# →‎ئح‎→\n\nFC99 ;\t0649 0674 062E ;\tMA\t# ( ‎ﲙ‎ → ‎ىٴخ‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER KHAH\t# →‎ئخ‎→\n\nFC64 ;\t0649 0674 0631 ;\tMA\t# ( ‎ﱤ‎ → ‎ىٴر‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER REH\t# →‎ئر‎→\n\nFC65 ;\t0649 0674 0632 ;\tMA\t# ( ‎ﱥ‎ → ‎ىٴز‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER ZAIN\t# →‎ئز‎→\n\nFC9A ;\t0649 0674 0645 ;\tMA\t# ( ‎ﲚ‎ → ‎ىٴم‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER MEEM\t# →‎ئم‎→\nFCDF ;\t0649 0674 0645 ;\tMA\t# ( ‎ﳟ‎ → ‎ىٴم‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER MEEM\t# →‎ئم‎→\nFC66 ;\t0649 0674 0645 ;\tMA\t# ( ‎ﱦ‎ → ‎ىٴم‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER MEEM\t# →‎ئم‎→\nFC02 ;\t0649 0674 0645 ;\tMA\t# ( ‎ﰂ‎ → ‎ىٴم‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER MEEM\t# →‎ئم‎→\n\nFC67 ;\t0649 0674 0646 ;\tMA\t# ( ‎ﱧ‎ → ‎ىٴن‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER NOON\t# →‎ئن‎→\n\nFBEF ;\t0649 0674 0648 ;\tMA\t# ( ‎ﯯ‎ → ‎ىٴو‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER WAW\t# →‎ئو‎→\nFBEE ;\t0649 0674 0648 ;\tMA\t# ( ‎ﯮ‎ → ‎ىٴو‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER WAW\t# →‎ئو‎→\n\nFBF1 ;\t0649 0674 0648 0313 ;\tMA\t# ( ‎ﯱ‎ → ‎ىٴو̓‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER WAW, COMBINING COMMA ABOVE\t# →‎ئۇ‎→\nFBF0 ;\t0649 0674 0648 0313 ;\tMA\t# ( ‎ﯰ‎ → ‎ىٴو̓‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER WAW, COMBINING COMMA ABOVE\t# →‎ئۇ‎→\n\nFBF3 ;\t0649 0674 0648 0306 ;\tMA\t# ( ‎ﯳ‎ → ‎ىٴو̆‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER WAW, COMBINING BREVE\t# →‎ئۆ‎→\nFBF2 ;\t0649 0674 0648 0306 ;\tMA\t# ( ‎ﯲ‎ → ‎ىٴو̆‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER WAW, COMBINING BREVE\t# →‎ئۆ‎→\n\nFBF5 ;\t0649 0674 0648 0670 ;\tMA\t# ( ‎ﯵ‎ → ‎ىٴوٰ‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER WAW, ARABIC LETTER SUPERSCRIPT ALEF\t# →‎ئۈ‎→\nFBF4 ;\t0649 0674 0648 0670 ;\tMA\t# ( ‎ﯴ‎ → ‎ىٴوٰ‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER WAW, ARABIC LETTER SUPERSCRIPT ALEF\t# →‎ئۈ‎→\n\nFBFB ;\t0649 0674 0649 ;\tMA\t# ( ‎ﯻ‎ → ‎ىٴى‎ ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER ALEF MAKSURA\t# →‎ئى‎→\nFBFA ;\t0649 0674 0649 ;\tMA\t# ( ‎ﯺ‎ → ‎ىٴى‎ ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER ALEF MAKSURA\t# →‎ئى‎→\nFC68 ;\t0649 0674 0649 ;\tMA\t# ( ‎ﱨ‎ → ‎ىٴى‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER ALEF MAKSURA\t# →‎ئى‎→\nFBF9 ;\t0649 0674 0649 ;\tMA\t# ( ‎ﯹ‎ → ‎ىٴى‎ ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER ALEF MAKSURA\t# →‎ئى‎→\nFC03 ;\t0649 0674 0649 ;\tMA\t# ( ‎ﰃ‎ → ‎ىٴى‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER ALEF MAKSURA\t# →‎ئى‎→\nFC69 ;\t0649 0674 0649 ;\tMA\t# ( ‎ﱩ‎ → ‎ىٴى‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER ALEF MAKSURA\t# →‎ئي‎→→‎ٴىى‎→→‎ئى‎→\nFC04 ;\t0649 0674 0649 ;\tMA\t# ( ‎ﰄ‎ → ‎ىٴى‎ ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HIGH HAMZA, ARABIC LETTER ALEF MAKSURA\t# →‎ئي‎→→‎ٴىى‎→→‎ئى‎→\n\nFCDA ;\t0649 062C ;\tMA\t# ( ‎ﳚ‎ → ‎ىج‎ ) ARABIC LIGATURE YEH WITH JEEM INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER JEEM\t# →‎يج‎→\nFC55 ;\t0649 062C ;\tMA\t# ( ‎ﱕ‎ → ‎ىج‎ ) ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER JEEM\t# →‎يج‎→\n\nFC11 ;\t0649 06DB 062C ;\tMA\t# ( ‎ﰑ‎ → ‎ىۛج‎ ) ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER JEEM\t# →‎ثج‎→\n\nFDAF ;\t0649 062C 0649 ;\tMA\t# ( ‎ﶯ‎ → ‎ىجى‎ ) ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER JEEM, ARABIC LETTER ALEF MAKSURA\t# →‎يجي‎→\n\nFCDB ;\t0649 062D ;\tMA\t# ( ‎ﳛ‎ → ‎ىح‎ ) ARABIC LIGATURE YEH WITH HAH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HAH\t# →‎يح‎→\nFC56 ;\t0649 062D ;\tMA\t# ( ‎ﱖ‎ → ‎ىح‎ ) ARABIC LIGATURE YEH WITH HAH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HAH\t# →‎يح‎→\n\nFDAE ;\t0649 062D 0649 ;\tMA\t# ( ‎ﶮ‎ → ‎ىحى‎ ) ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER HAH, ARABIC LETTER ALEF MAKSURA\t# →‎يحي‎→\n\nFCDC ;\t0649 062E ;\tMA\t# ( ‎ﳜ‎ → ‎ىخ‎ ) ARABIC LIGATURE YEH WITH KHAH INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER KHAH\t# →‎يخ‎→\nFC57 ;\t0649 062E ;\tMA\t# ( ‎ﱗ‎ → ‎ىخ‎ ) ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER KHAH\t# →‎يخ‎→\n\nFC91 ;\t0649 0631 ;\tMA\t# ( ‎ﲑ‎ → ‎ىر‎ ) ARABIC LIGATURE YEH WITH REH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER REH\t# →‎ير‎→\n\nFC76 ;\t0649 06DB 0631 ;\tMA\t# ( ‎ﱶ‎ → ‎ىۛر‎ ) ARABIC LIGATURE THEH WITH REH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER REH\t# →‎ثر‎→\n\nFC92 ;\t0649 0632 ;\tMA\t# ( ‎ﲒ‎ → ‎ىز‎ ) ARABIC LIGATURE YEH WITH ZAIN FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER ZAIN\t# →‎يز‎→\n\nFC77 ;\t0649 06DB 0632 ;\tMA\t# ( ‎ﱷ‎ → ‎ىۛز‎ ) ARABIC LIGATURE THEH WITH ZAIN FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ZAIN\t# →‎ثز‎→\n\nFCDD ;\t0649 0645 ;\tMA\t# ( ‎ﳝ‎ → ‎ىم‎ ) ARABIC LIGATURE YEH WITH MEEM INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER MEEM\t# →‎يم‎→\nFCF0 ;\t0649 0645 ;\tMA\t# ( ‎ﳰ‎ → ‎ىم‎ ) ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER MEEM\t# →‎يم‎→\nFC93 ;\t0649 0645 ;\tMA\t# ( ‎ﲓ‎ → ‎ىم‎ ) ARABIC LIGATURE YEH WITH MEEM FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER MEEM\t# →‎يم‎→\nFC58 ;\t0649 0645 ;\tMA\t# ( ‎ﱘ‎ → ‎ىم‎ ) ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER MEEM\t# →‎يم‎→\n\nFCA6 ;\t0649 06DB 0645 ;\tMA\t# ( ‎ﲦ‎ → ‎ىۛم‎ ) ARABIC LIGATURE THEH WITH MEEM INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM\t# →‎ثم‎→\nFCE5 ;\t0649 06DB 0645 ;\tMA\t# ( ‎ﳥ‎ → ‎ىۛم‎ ) ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM\t# →‎ثم‎→\nFC78 ;\t0649 06DB 0645 ;\tMA\t# ( ‎ﱸ‎ → ‎ىۛم‎ ) ARABIC LIGATURE THEH WITH MEEM FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM\t# →‎ثم‎→\nFC12 ;\t0649 06DB 0645 ;\tMA\t# ( ‎ﰒ‎ → ‎ىۛم‎ ) ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER MEEM\t# →‎ثم‎→\n\nFD9D ;\t0649 0645 0645 ;\tMA\t# ( ‎ﶝ‎ → ‎ىمم‎ ) ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# →‎يمم‎→\nFD9C ;\t0649 0645 0645 ;\tMA\t# ( ‎ﶜ‎ → ‎ىمم‎ ) ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER MEEM, ARABIC LETTER MEEM\t# →‎يمم‎→\n\nFDB0 ;\t0649 0645 0649 ;\tMA\t# ( ‎ﶰ‎ → ‎ىمى‎ ) ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER MEEM, ARABIC LETTER ALEF MAKSURA\t# →‎يمي‎→\n\nFC94 ;\t0649 0646 ;\tMA\t# ( ‎ﲔ‎ → ‎ىن‎ ) ARABIC LIGATURE YEH WITH NOON FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER NOON\t# →‎ين‎→\n\nFC79 ;\t0649 06DB 0646 ;\tMA\t# ( ‎ﱹ‎ → ‎ىۛن‎ ) ARABIC LIGATURE THEH WITH NOON FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER NOON\t# →‎ثن‎→\n\nFC95 ;\t0649 0649 ;\tMA\t# ( ‎ﲕ‎ → ‎ىى‎ ) ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER ALEF MAKSURA\t# →‎يى‎→\nFC59 ;\t0649 0649 ;\tMA\t# ( ‎ﱙ‎ → ‎ىى‎ ) ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER ALEF MAKSURA\t# →‎يى‎→\nFC96 ;\t0649 0649 ;\tMA\t# ( ‎ﲖ‎ → ‎ىى‎ ) ARABIC LIGATURE YEH WITH YEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER ALEF MAKSURA\t# →‎يي‎→\nFC5A ;\t0649 0649 ;\tMA\t# ( ‎ﱚ‎ → ‎ىى‎ ) ARABIC LIGATURE YEH WITH YEH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC LETTER ALEF MAKSURA\t# →‎يي‎→\n\nFC7A ;\t0649 06DB 0649 ;\tMA\t# ( ‎ﱺ‎ → ‎ىۛى‎ ) ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ALEF MAKSURA\t# →‎ثى‎→\nFC13 ;\t0649 06DB 0649 ;\tMA\t# ( ‎ﰓ‎ → ‎ىۛى‎ ) ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ALEF MAKSURA\t# →‎ثى‎→\nFC7B ;\t0649 06DB 0649 ;\tMA\t# ( ‎ﱻ‎ → ‎ىۛى‎ ) ARABIC LIGATURE THEH WITH YEH FINAL FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ALEF MAKSURA\t# →‎ثي‎→\nFC14 ;\t0649 06DB 0649 ;\tMA\t# ( ‎ﰔ‎ → ‎ىۛى‎ ) ARABIC LIGATURE THEH WITH YEH ISOLATED FORM → ARABIC LETTER ALEF MAKSURA, ARABIC SMALL HIGH THREE DOTS, ARABIC LETTER ALEF MAKSURA\t# →‎ثي‎→\n\nFBB1 ;\t06D3 ;\tMA\t# ( ‎ﮱ‎ → ‎ۓ‎ ) ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM → ARABIC LETTER YEH BARREE WITH HAMZA ABOVE\t# \nFBB0 ;\t06D3 ;\tMA\t# ( ‎ﮰ‎ → ‎ۓ‎ ) ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM → ARABIC LETTER YEH BARREE WITH HAMZA ABOVE\t# \n\n102B8 ;\t2D40 ;\tMA\t# ( 𐊸 → ⵀ ) CARIAN LETTER SS → TIFINAGH LETTER YAH\t# \n\n205E ;\t2D42 ;\tMA\t#* ( ⁞ → ⵂ ) VERTICAL FOUR DOTS → TIFINAGH LETTER TUAREG YAH\t# \n2E3D ;\t2D42 ;\tMA\t#* ( ⸽ → ⵂ ) VERTICAL SIX DOTS → TIFINAGH LETTER TUAREG YAH\t# →⁞→\n2999 ;\t2D42 ;\tMA\t#* ( ⦙ → ⵂ ) DOTTED FENCE → TIFINAGH LETTER TUAREG YAH\t# →⁞→\n1CEEF ;\t2D42 ;\tMA\t#* ( 𜻯 → ⵂ ) GEOMANTIC FIGURE VIA → TIFINAGH LETTER TUAREG YAH\t# →⁞→\n\nFE19 ;\t2D57 ;\tMA\t#* ( ︙ → ⵗ ) PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS → TIFINAGH LETTER TUAREG YAGH\t# →⁝→\n205D ;\t2D57 ;\tMA\t#* ( ⁝ → ⵗ ) TRICOLON → TIFINAGH LETTER TUAREG YAGH\t# \n22EE ;\t2D57 ;\tMA\t#* ( ⋮ → ⵗ ) VERTICAL ELLIPSIS → TIFINAGH LETTER TUAREG YAGH\t# →︙→→⁝→\n\n0544 ;\t1206 ;\tMA\t# ( Մ → ሆ ) ARMENIAN CAPITAL LETTER MEN → ETHIOPIC SYLLABLE HO\t# \n\n054C ;\t1261 ;\tMA\t# ( Ռ → ቡ ) ARMENIAN CAPITAL LETTER RA → ETHIOPIC SYLLABLE BU\t# \n\n053B ;\t12AE ;\tMA\t# ( Ի → ኮ ) ARMENIAN CAPITAL LETTER INI → ETHIOPIC SYLLABLE KO\t# \n\n054A ;\t1323 ;\tMA\t# ( Պ → ጣ ) ARMENIAN CAPITAL LETTER PEH → ETHIOPIC SYLLABLE THAA\t# \n\n0972 ;\t0905 0306 ;\tMA\t# ( ॲ → अ̆ ) DEVANAGARI LETTER CANDRA A → DEVANAGARI LETTER A, COMBINING BREVE\t# →अॅ→\n\n0906 ;\t0905 093E ;\tMA\t# ( आ → अा ) DEVANAGARI LETTER AA → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA\t# \n\n0911 ;\t0905 093E 0306 ;\tMA\t# ( ऑ → अा̆ ) DEVANAGARI LETTER CANDRA O → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA, COMBINING BREVE\t# →अॉ→\n\n0974 ;\t0905 093E 093A ;\tMA\t# ( ॴ → अाऺ ) DEVANAGARI LETTER OOE → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA, DEVANAGARI VOWEL SIGN OE\t# →अऻ→\n\n0912 ;\t0905 093E 0946 ;\tMA\t# ( ऒ → अाॆ ) DEVANAGARI LETTER SHORT O → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA, DEVANAGARI VOWEL SIGN SHORT E\t# →अॊ→→आॆ→\n\n0914 ;\t0905 093E 0948 ;\tMA\t# ( औ → अाै ) DEVANAGARI LETTER AU → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA, DEVANAGARI VOWEL SIGN AI\t# →अौ→→आै→\n\n0913 ;\t0905 093E 11B64 ;\tMA\t# ( ओ → अा𑭤 ) DEVANAGARI LETTER O → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA, SHARADA VOWEL SIGN SHORT E\t# →अो→→आे→\n\n0973 ;\t0905 093A ;\tMA\t# ( ॳ → अऺ ) DEVANAGARI LETTER OE → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OE\t# \n\n0975 ;\t0905 094F ;\tMA\t# ( ॵ → अॏ ) DEVANAGARI LETTER AW → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AW\t# \n\n0904 ;\t0905 0946 ;\tMA\t# ( ऄ → अॆ ) DEVANAGARI LETTER SHORT A → DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT E\t# \n\n0A24 ;\t0909 ;\tMA\t# ( ਤ → उ ) GURMUKHI LETTER TA → DEVANAGARI LETTER U\t# \n\n090D ;\t090F 0306 ;\tMA\t# ( ऍ → ए̆ ) DEVANAGARI LETTER CANDRA E → DEVANAGARI LETTER E, COMBINING BREVE\t# →एॅ→\n\n090E ;\t090F 0946 ;\tMA\t# ( ऎ → एॆ ) DEVANAGARI LETTER SHORT E → DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN SHORT E\t# \n\n0910 ;\t090F 11B64 ;\tMA\t# ( ऐ → ए𑭤 ) DEVANAGARI LETTER AI → DEVANAGARI LETTER E, SHARADA VOWEL SIGN SHORT E\t# →एे→\n\n0A1F ;\t091F ;\tMA\t# ( ਟ → ट ) GURMUKHI LETTER TTA → DEVANAGARI LETTER TTA\t# \n\n0A20 ;\t0920 ;\tMA\t# ( ਠ → ठ ) GURMUKHI LETTER TTHA → DEVANAGARI LETTER TTHA\t# \n\n0A2B ;\t0922 ;\tMA\t# ( ਫ → ढ ) GURMUKHI LETTER PHA → DEVANAGARI LETTER DDHA\t# \n\n0A1C ;\t0924 094D 0924 ;\tMA\t# ( ਜ → त्त ) GURMUKHI LETTER JA → DEVANAGARI LETTER TA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER TA\t# \n\n0A27 ;\t092A ;\tMA\t# ( ਧ → प ) GURMUKHI LETTER DHA → DEVANAGARI LETTER PA\t# \n\n0A72 ;\t092A 094D 091F ;\tMA\t# ( ੲ → प्ट ) GURMUKHI IRI → DEVANAGARI LETTER PA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER TTA\t# \n\n0A07 ;\t092A 094D 091F 09BF ;\tMA\t# ( ਇ → प्टি ) GURMUKHI LETTER I → DEVANAGARI LETTER PA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER TTA, BENGALI VOWEL SIGN I\t# →ੲਿ→\n\n0A08 ;\t092A 094D 091F 0A40 ;\tMA\t# ( ਈ → प्टੀ ) GURMUKHI LETTER II → DEVANAGARI LETTER PA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER TTA, GURMUKHI VOWEL SIGN II\t# →ੲੀ→\n\n0A0F ;\t092A 094D 091F 11B64 ;\tMA\t# ( ਏ → प्ट𑭤 ) GURMUKHI LETTER EE → DEVANAGARI LETTER PA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER TTA, SHARADA VOWEL SIGN SHORT E\t# →ੲੇ→\n\n0A2E ;\t092D ;\tMA\t# ( ਮ → भ ) GURMUKHI LETTER MA → DEVANAGARI LETTER BHA\t# \n\n0A38 ;\t092E ;\tMA\t# ( ਸ → म ) GURMUKHI LETTER SA → DEVANAGARI LETTER MA\t# \n\n0908 ;\t0930 094D 0907 ;\tMA\t# ( ई → र्इ ) DEVANAGARI LETTER II → DEVANAGARI LETTER RA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER I\t# \n\n0A15 ;\t0935 ;\tMA\t# ( ਕ → व ) GURMUKHI LETTER KA → DEVANAGARI LETTER VA\t# \n\n0A35 ;\t0939 ;\tMA\t# ( ਵ → ह ) GURMUKHI LETTER VA → DEVANAGARI LETTER HA\t# \n\n0ABD ;\t093D ;\tMA\t# ( ઽ → ऽ ) GUJARATI SIGN AVAGRAHA → DEVANAGARI SIGN AVAGRAHA\t# \n\n111DC ;\tA8FB ;\tMA\t# ( 𑇜 → ꣻ ) SHARADA HEADSTROKE → DEVANAGARI HEADSTROKE\t# \n\n0949 ;\t093E 0306 ;\tMA\t# ( ॉ → ा̆ ) DEVANAGARI VOWEL SIGN CANDRA O → DEVANAGARI VOWEL SIGN AA, COMBINING BREVE\t# →ाॅ→\n\n093B ;\t093E 093A ;\tMA\t# ( ऻ → ाऺ ) DEVANAGARI VOWEL SIGN OOE → DEVANAGARI VOWEL SIGN AA, DEVANAGARI VOWEL SIGN OE\t# \n\n111CB ;\t093A ;\tMA\t# ( 𑇋 → ऺ ) SHARADA VOWEL MODIFIER MARK → DEVANAGARI VOWEL SIGN OE\t# \n11B60 ;\t093A ;\tMA\t# ( 𑭠 → ऺ ) SHARADA VOWEL SIGN OE → DEVANAGARI VOWEL SIGN OE\t# \n\n0AC1 ;\t0941 ;\tMA\t# ( ુ → ु ) GUJARATI VOWEL SIGN U → DEVANAGARI VOWEL SIGN U\t# \n\n0AC2 ;\t0942 ;\tMA\t# ( ૂ → ू ) GUJARATI VOWEL SIGN UU → DEVANAGARI VOWEL SIGN UU\t# \n\n0A4B ;\t0946 ;\tMA\t# ( ੋ → ॆ ) GURMUKHI VOWEL SIGN OO → DEVANAGARI VOWEL SIGN SHORT E\t# \n\n0A48 ;\t0948 ;\tMA\t# ( ੈ → ै ) GURMUKHI VOWEL SIGN AI → DEVANAGARI VOWEL SIGN AI\t# \n\n0A4D ;\t094D ;\tMA\t# ( ੍ → ् ) GURMUKHI SIGN VIRAMA → DEVANAGARI SIGN VIRAMA\t# \n0ACD ;\t094D ;\tMA\t# ( ્ → ् ) GUJARATI SIGN VIRAMA → DEVANAGARI SIGN VIRAMA\t# \n\n0986 ;\t0985 09BE ;\tMA\t# ( আ → অা ) BENGALI LETTER AA → BENGALI LETTER A, BENGALI VOWEL SIGN AA\t# \n\n09E0 ;\t098B 09C3 ;\tMA\t# ( ৠ → ঋৃ ) BENGALI LETTER VOCALIC RR → BENGALI LETTER VOCALIC R, BENGALI VOWEL SIGN VOCALIC R\t# \n09E1 ;\t098B 09C3 ;\tMA\t# ( ৡ → ঋৃ ) BENGALI LETTER VOCALIC LL → BENGALI LETTER VOCALIC R, BENGALI VOWEL SIGN VOCALIC R\t# →ঌৢ→→ৠ→\n\n11492 ;\t0998 ;\tMA\t# ( 𑒒 → ঘ ) TIRHUTA LETTER GHA → BENGALI LETTER GHA\t# \n\n11494 ;\t099A ;\tMA\t# ( 𑒔 → চ ) TIRHUTA LETTER CA → BENGALI LETTER CA\t# \n\n11496 ;\t099C ;\tMA\t# ( 𑒖 → জ ) TIRHUTA LETTER JA → BENGALI LETTER JA\t# \n\n11498 ;\t099E ;\tMA\t# ( 𑒘 → ঞ ) TIRHUTA LETTER NYA → BENGALI LETTER NYA\t# \n\n11499 ;\t099F ;\tMA\t# ( 𑒙 → ট ) TIRHUTA LETTER TTA → BENGALI LETTER TTA\t# \n\n1149B ;\t09A1 ;\tMA\t# ( 𑒛 → ড ) TIRHUTA LETTER DDA → BENGALI LETTER DDA\t# \n\n114AA ;\t09A3 ;\tMA\t# ( 𑒪 → ণ ) TIRHUTA LETTER LA → BENGALI LETTER NNA\t# \n\n1149E ;\t09A4 ;\tMA\t# ( 𑒞 → ত ) TIRHUTA LETTER TA → BENGALI LETTER TA\t# \n\n1149F ;\t09A5 ;\tMA\t# ( 𑒟 → থ ) TIRHUTA LETTER THA → BENGALI LETTER THA\t# \n\n114A0 ;\t09A6 ;\tMA\t# ( 𑒠 → দ ) TIRHUTA LETTER DA → BENGALI LETTER DA\t# \n\n114A1 ;\t09A7 ;\tMA\t# ( 𑒡 → ধ ) TIRHUTA LETTER DHA → BENGALI LETTER DHA\t# \n\n114A2 ;\t09A8 ;\tMA\t# ( 𑒢 → ন ) TIRHUTA LETTER NA → BENGALI LETTER NA\t# \n\n114A3 ;\t09AA ;\tMA\t# ( 𑒣 → প ) TIRHUTA LETTER PA → BENGALI LETTER PA\t# \n\n114A9 ;\t09AC ;\tMA\t# ( 𑒩 → ব ) TIRHUTA LETTER RA → BENGALI LETTER BA\t# \n\n114A7 ;\t09AE ;\tMA\t# ( 𑒧 → ম ) TIRHUTA LETTER MA → BENGALI LETTER MA\t# \n\n114A8 ;\t09AF ;\tMA\t# ( 𑒨 → য ) TIRHUTA LETTER YA → BENGALI LETTER YA\t# \n\n09F0 ;\t09B0 ;\tMA\t# ( ৰ → র ) BENGALI LETTER RA WITH MIDDLE DIAGONAL → BENGALI LETTER RA\t# \n114AB ;\t09B0 ;\tMA\t# ( 𑒫 → র ) TIRHUTA LETTER VA → BENGALI LETTER RA\t# \n\n1149D ;\t09B2 ;\tMA\t# ( 𑒝 → ল ) TIRHUTA LETTER NNA → BENGALI LETTER LA\t# \n\n114AD ;\t09B7 ;\tMA\t# ( 𑒭 → ষ ) TIRHUTA LETTER SSA → BENGALI LETTER SSA\t# \n\n114AE ;\t09B8 ;\tMA\t# ( 𑒮 → স ) TIRHUTA LETTER SA → BENGALI LETTER SA\t# \n\n114C4 ;\t09BD ;\tMA\t# ( 𑓄 → ঽ ) TIRHUTA SIGN AVAGRAHA → BENGALI SIGN AVAGRAHA\t# \n\n114B0 ;\t09BE ;\tMA\t# ( 𑒰 → া ) TIRHUTA VOWEL SIGN AA → BENGALI VOWEL SIGN AA\t# \n\n093F ;\t09BF ;\tMA\t# ( ि → ি ) DEVANAGARI VOWEL SIGN I → BENGALI VOWEL SIGN I\t# \n0A3F ;\t09BF ;\tMA\t# ( ਿ → ি ) GURMUKHI VOWEL SIGN I → BENGALI VOWEL SIGN I\t# →ि→\n114B1 ;\t09BF ;\tMA\t# ( 𑒱 → ি ) TIRHUTA VOWEL SIGN I → BENGALI VOWEL SIGN I\t# \n\n114B9 ;\t09C7 ;\tMA\t# ( 𑒹 → ে ) TIRHUTA VOWEL SIGN E → BENGALI VOWEL SIGN E\t# \n\n114BC ;\t09CB ;\tMA\t# ( 𑒼 → ো ) TIRHUTA VOWEL SIGN O → BENGALI VOWEL SIGN O\t# \n\n114BE ;\t09CC ;\tMA\t# ( 𑒾 → ৌ ) TIRHUTA VOWEL SIGN AU → BENGALI VOWEL SIGN AU\t# \n\n114C2 ;\t09CD ;\tMA\t# ( 𑓂 → ্ ) TIRHUTA SIGN VIRAMA → BENGALI SIGN VIRAMA\t# \n\n114BD ;\t09D7 ;\tMA\t# ( 𑒽 → ৗ ) TIRHUTA VOWEL SIGN SHORT O → BENGALI AU LENGTH MARK\t# \n\n0A09 ;\t0A73 11B62 ;\tMA\t# ( ਉ → ੳ𑭢 ) GURMUKHI LETTER U → GURMUKHI URA, SHARADA VOWEL SIGN UE\t# →ੳੁ→\n\n0A0A ;\t0A73 11B63 ;\tMA\t# ( ਊ → ੳ𑭣 ) GURMUKHI LETTER UU → GURMUKHI URA, SHARADA VOWEL SIGN UUE\t# →ੳੂ→\n\n0A10 ;\t0A05 0948 ;\tMA\t# ( ਐ → ਅै ) GURMUKHI LETTER AI → GURMUKHI LETTER A, DEVANAGARI VOWEL SIGN AI\t# →ਅੈ→\n\n0A06 ;\t0A05 0A3E ;\tMA\t# ( ਆ → ਅਾ ) GURMUKHI LETTER AA → GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AA\t# \n\n0A14 ;\t0A05 0A4C ;\tMA\t# ( ਔ → ਅੌ ) GURMUKHI LETTER AU → GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AU\t# \n\n0A86 ;\t0A85 0ABE ;\tMA\t# ( આ → અા ) GUJARATI LETTER AA → GUJARATI LETTER A, GUJARATI VOWEL SIGN AA\t# \n\n0A91 ;\t0A85 0ABE 0AC5 ;\tMA\t# ( ઑ → અાૅ ) GUJARATI VOWEL CANDRA O → GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN CANDRA E\t# →અૉ→→આૅ→\n\n0A93 ;\t0A85 0ABE 0AC7 ;\tMA\t# ( ઓ → અાે ) GUJARATI LETTER O → GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN E\t# →અો→→આે→\n\n0A94 ;\t0A85 0ABE 0AC8 ;\tMA\t# ( ઔ → અાૈ ) GUJARATI LETTER AU → GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN AI\t# →અૌ→→આૈ→\n\n0A8D ;\t0A85 0AC5 ;\tMA\t# ( ઍ → અૅ ) GUJARATI VOWEL CANDRA E → GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA E\t# \n\n0A8F ;\t0A85 0AC7 ;\tMA\t# ( એ → અે ) GUJARATI LETTER E → GUJARATI LETTER A, GUJARATI VOWEL SIGN E\t# \n\n0A90 ;\t0A85 0AC8 ;\tMA\t# ( ઐ → અૈ ) GUJARATI LETTER AI → GUJARATI LETTER A, GUJARATI VOWEL SIGN AI\t# \n\n0B06 ;\t0B05 0B3E ;\tMA\t# ( ଆ → ଅା ) ORIYA LETTER AA → ORIYA LETTER A, ORIYA VOWEL SIGN AA\t# \n\n1031 ;\t0B47 ;\tMA\t# ( ေ → େ ) MYANMAR VOWEL SIGN E → ORIYA VOWEL SIGN E\t# \n\n0BEE ;\t0B85 ;\tMA\t# ( ௮ → அ ) TAMIL DIGIT EIGHT → TAMIL LETTER A\t# \n\n0BB0 ;\t0B88 ;\tMA\t# ( ர → ஈ ) TAMIL LETTER RA → TAMIL LETTER II\t# →ா→\n0BBE ;\t0B88 ;\tMA\t# ( ா → ஈ ) TAMIL VOWEL SIGN AA → TAMIL LETTER II\t# \n\n0BEB ;\t0B88 0BC1 ;\tMA\t# ( ௫ → ஈு ) TAMIL DIGIT FIVE → TAMIL LETTER II, TAMIL VOWEL SIGN U\t# →ரு→\n\n0BE8 ;\t0B89 ;\tMA\t# ( ௨ → உ ) TAMIL DIGIT TWO → TAMIL LETTER U\t# \n0D09 ;\t0B89 ;\tMA\t# ( ഉ → உ ) MALAYALAM LETTER U → TAMIL LETTER U\t# \n\n0B8A ;\t0B89 0BB3 ;\tMA\t# ( ஊ → உள ) TAMIL LETTER UU → TAMIL LETTER U, TAMIL LETTER LLA\t# \n\n0D0A ;\t0B89 0D57 ;\tMA\t# ( ഊ → உൗ ) MALAYALAM LETTER UU → TAMIL LETTER U, MALAYALAM AU LENGTH MARK\t# →ഉൗ→\n\n0BED ;\t0B8E ;\tMA\t# ( ௭ → எ ) TAMIL DIGIT SEVEN → TAMIL LETTER E\t# \n\n0BF7 ;\t0B8E 0BB5 ;\tMA\t#* ( ௷ → எவ ) TAMIL CREDIT SIGN → TAMIL LETTER E, TAMIL LETTER VA\t# \n\n0B9C ;\t0B90 ;\tMA\t# ( ஜ → ஐ ) TAMIL LETTER JA → TAMIL LETTER AI\t# \n0D1C ;\t0B90 ;\tMA\t# ( ജ → ஐ ) MALAYALAM LETTER JA → TAMIL LETTER AI\t# →ஜ→\n\n0B94 ;\t0B92 0BB3 ;\tMA\t# ( ஔ → ஒள ) TAMIL LETTER AU → TAMIL LETTER O, TAMIL LETTER LLA\t# \n\n0BE7 ;\t0B95 ;\tMA\t# ( ௧ → க ) TAMIL DIGIT ONE → TAMIL LETTER KA\t# \n\n0BEA ;\t0B9A ;\tMA\t# ( ௪ → ச ) TAMIL DIGIT FOUR → TAMIL LETTER CA\t# \n\n0BEC ;\t0B9A 0BC1 ;\tMA\t# ( ௬ → சு ) TAMIL DIGIT SIX → TAMIL LETTER CA, TAMIL VOWEL SIGN U\t# \n\n0BF2 ;\t0B9A 0BC2 ;\tMA\t#* ( ௲ → சூ ) TAMIL NUMBER ONE THOUSAND → TAMIL LETTER CA, TAMIL VOWEL SIGN UU\t# \n\n0D3A ;\t0B9F 0BBF ;\tMA\t# ( ഺ → டி ) MALAYALAM LETTER TTTA → TAMIL LETTER TTA, TAMIL VOWEL SIGN I\t# \n\n0D23 ;\t0BA3 ;\tMA\t# ( ണ → ண ) MALAYALAM LETTER NNA → TAMIL LETTER NNA\t# \n\n0D7A ;\t0BA3 0D4D ;\tMA\t# ( ൺ → ண് ) MALAYALAM LETTER CHILLU NN → TAMIL LETTER NNA, MALAYALAM SIGN VIRAMA\t# →ണ്→\n\n0BFA ;\t0BA8 0BC0 ;\tMA\t#* ( ௺ → நீ ) TAMIL NUMBER SIGN → TAMIL LETTER NA, TAMIL VOWEL SIGN II\t# \n\n0D25 ;\t0BAE ;\tMA\t# ( ഥ → ம ) MALAYALAM LETTER THA → TAMIL LETTER MA\t# \n\n0BF4 ;\t0BAE 0BC0 ;\tMA\t#* ( ௴ → மீ ) TAMIL MONTH SIGN → TAMIL LETTER MA, TAMIL VOWEL SIGN II\t# \n\n0BF0 ;\t0BAF ;\tMA\t#* ( ௰ → ய ) TAMIL NUMBER TEN → TAMIL LETTER YA\t# \n\n0D16 ;\t0BB5 ;\tMA\t# ( ഖ → வ ) MALAYALAM LETTER KHA → TAMIL LETTER VA\t# \n\n0D34 ;\t0BB4 ;\tMA\t# ( ഴ → ழ ) MALAYALAM LETTER LLLA → TAMIL LETTER LLLA\t# \n\n0BD7 ;\t0BB3 ;\tMA\t# ( ௗ → ள ) TAMIL AU LENGTH MARK → TAMIL LETTER LLA\t# \n\n0BC8 ;\t0BA9 ;\tMA\t# ( ை → ன ) TAMIL VOWEL SIGN AI → TAMIL LETTER NNNA\t# \n\n0BB8 ;\t0BB6 ;\tMA\t# ( ஸ → ஶ ) TAMIL LETTER SA → TAMIL LETTER SHA\t# \n0D36 ;\t0BB6 ;\tMA\t# ( ശ → ஶ ) MALAYALAM LETTER SHA → TAMIL LETTER SHA\t# \n\n0BF8 ;\t0BB7 ;\tMA\t#* ( ௸ → ஷ ) TAMIL AS ABOVE SIGN → TAMIL LETTER SSA\t# \n\n0D3F ;\t0BBF ;\tMA\t# ( ി → ி ) MALAYALAM VOWEL SIGN I → TAMIL VOWEL SIGN I\t# \n0D40 ;\t0BBF ;\tMA\t# ( ീ → ி ) MALAYALAM VOWEL SIGN II → TAMIL VOWEL SIGN I\t# \n\n0D46 ;\t0BC6 ;\tMA\t# ( െ → ெ ) MALAYALAM VOWEL SIGN E → TAMIL VOWEL SIGN E\t# \n\n0BCA ;\t0BC6 0B88 ;\tMA\t# ( ொ → ெஈ ) TAMIL VOWEL SIGN O → TAMIL VOWEL SIGN E, TAMIL LETTER II\t# →ெர→\n\n0BCC ;\t0BC6 0BB3 ;\tMA\t# ( ௌ → ெள ) TAMIL VOWEL SIGN AU → TAMIL VOWEL SIGN E, TAMIL LETTER LLA\t# \n\n0D48 ;\t0BC6 0BC6 ;\tMA\t# ( ൈ → ெெ ) MALAYALAM VOWEL SIGN AI → TAMIL VOWEL SIGN E, TAMIL VOWEL SIGN E\t# →െെ→\n\n0D10 ;\t0BC6 0D0E ;\tMA\t# ( ഐ → ெഎ ) MALAYALAM LETTER AI → TAMIL VOWEL SIGN E, MALAYALAM LETTER E\t# →െഎ→\n\n0D47 ;\t0BC7 ;\tMA\t# ( േ → ே ) MALAYALAM VOWEL SIGN EE → TAMIL VOWEL SIGN EE\t# \n\n0BCB ;\t0BC7 0B88 ;\tMA\t# ( ோ → ேஈ ) TAMIL VOWEL SIGN OO → TAMIL VOWEL SIGN EE, TAMIL LETTER II\t# →ேர→\n\n0C85 ;\t0C05 ;\tMA\t# ( ಅ → అ ) KANNADA LETTER A → TELUGU LETTER A\t# \n\n0C86 ;\t0C06 ;\tMA\t# ( ಆ → ఆ ) KANNADA LETTER AA → TELUGU LETTER AA\t# \n\n0C87 ;\t0C07 ;\tMA\t# ( ಇ → ఇ ) KANNADA LETTER I → TELUGU LETTER I\t# \n\n0C60 ;\t0C0B 0C3E ;\tMA\t# ( ౠ → ఋా ) TELUGU LETTER VOCALIC RR → TELUGU LETTER VOCALIC R, TELUGU VOWEL SIGN AA\t# \n\n0C61 ;\t0C0C 0C3E ;\tMA\t# ( ౡ → ఌా ) TELUGU LETTER VOCALIC LL → TELUGU LETTER VOCALIC L, TELUGU VOWEL SIGN AA\t# \n\n0C90 ;\t0C10 ;\tMA\t# ( ಐ → ఐ ) KANNADA LETTER AI → TELUGU LETTER AI\t# \n\n0C92 ;\t0C12 ;\tMA\t# ( ಒ → ఒ ) KANNADA LETTER O → TELUGU LETTER O\t# \n\n0C14 ;\t0C12 0C4C ;\tMA\t# ( ఔ → ఒౌ ) TELUGU LETTER AU → TELUGU LETTER O, TELUGU VOWEL SIGN AU\t# \n0C94 ;\t0C12 0C4C ;\tMA\t# ( ಔ → ఒౌ ) KANNADA LETTER AU → TELUGU LETTER O, TELUGU VOWEL SIGN AU\t# →ఔ→\n\n0C13 ;\t0C12 0C55 ;\tMA\t# ( ఓ → ఒౕ ) TELUGU LETTER OO → TELUGU LETTER O, TELUGU LENGTH MARK\t# \n0C93 ;\t0C12 0C55 ;\tMA\t# ( ಓ → ఒౕ ) KANNADA LETTER OO → TELUGU LETTER O, TELUGU LENGTH MARK\t# →ఓ→\n\n0C97 ;\t0C17 ;\tMA\t# ( ಗ → గ ) KANNADA LETTER GA → TELUGU LETTER GA\t# \n\n0C9C ;\t0C1C ;\tMA\t# ( ಜ → జ ) KANNADA LETTER JA → TELUGU LETTER JA\t# \n\n0C9D ;\t0C1D ;\tMA\t# ( ಝ → ఝ ) KANNADA LETTER JHA → TELUGU LETTER JHA\t# \n\n0C9E ;\t0C1E ;\tMA\t# ( ಞ → ఞ ) KANNADA LETTER NYA → TELUGU LETTER NYA\t# \n\n0C9F ;\t0C1F ;\tMA\t# ( ಟ → ట ) KANNADA LETTER TTA → TELUGU LETTER TTA\t# \n\n0C22 ;\t0C21 0323 ;\tMA\t# ( ఢ → డ̣ ) TELUGU LETTER DDHA → TELUGU LETTER DDA, COMBINING DOT BELOW\t# \n\n0CA3 ;\t0C23 ;\tMA\t# ( ಣ → ణ ) KANNADA LETTER NNA → TELUGU LETTER NNA\t# \n\n0CA6 ;\t0C26 ;\tMA\t# ( ದ → ద ) KANNADA LETTER DA → TELUGU LETTER DA\t# \n\n0C25 ;\t0C27 05BC ;\tMA\t# ( థ → ధּ ) TELUGU LETTER THA → TELUGU LETTER DHA, HEBREW POINT DAGESH OR MAPIQ\t# \n\n0CA8 ;\t0C28 ;\tMA\t# ( ನ → న ) KANNADA LETTER NA → TELUGU LETTER NA\t# \n\n0C2D ;\t0C2C 0323 ;\tMA\t# ( భ → బ̣ ) TELUGU LETTER BHA → TELUGU LETTER BA, COMBINING DOT BELOW\t# \n\n0CAF ;\t0C2F ;\tMA\t# ( ಯ → య ) KANNADA LETTER YA → TELUGU LETTER YA\t# \n\n0CB0 ;\t0C30 ;\tMA\t# ( ರ → ర ) KANNADA LETTER RA → TELUGU LETTER RA\t# \n\n0C20 ;\t0C30 05BC ;\tMA\t# ( ఠ → రּ ) TELUGU LETTER TTHA → TELUGU LETTER RA, HEBREW POINT DAGESH OR MAPIQ\t# \n\n0CB1 ;\t0C31 ;\tMA\t# ( ಱ → ఱ ) KANNADA LETTER RRA → TELUGU LETTER RRA\t# \n\n0CB2 ;\t0C32 ;\tMA\t# ( ಲ → ల ) KANNADA LETTER LA → TELUGU LETTER LA\t# \n\n0C37 ;\t0C35 0323 ;\tMA\t# ( ష → వ̣ ) TELUGU LETTER SSA → TELUGU LETTER VA, COMBINING DOT BELOW\t# \n\n0C39 ;\t0C35 0C3E ;\tMA\t# ( హ → వా ) TELUGU LETTER HA → TELUGU LETTER VA, TELUGU VOWEL SIGN AA\t# \n\n0C2E ;\t0C35 0C41 ;\tMA\t# ( మ → వు ) TELUGU LETTER MA → TELUGU LETTER VA, TELUGU VOWEL SIGN U\t# \n\n0CB3 ;\t0C33 ;\tMA\t# ( ಳ → ళ ) KANNADA LETTER LLA → TELUGU LETTER LLA\t# \n\n0CBF ;\t0C3F ;\tMA\t# ( ಿ → ి ) KANNADA VOWEL SIGN I → TELUGU VOWEL SIGN I\t# \n\n0CC1 ;\t0C41 ;\tMA\t# ( ು → ు ) KANNADA VOWEL SIGN U → TELUGU VOWEL SIGN U\t# \n\n0C42 ;\t0C41 0C3E ;\tMA\t# ( ూ → ుా ) TELUGU VOWEL SIGN UU → TELUGU VOWEL SIGN U, TELUGU VOWEL SIGN AA\t# \n\n0CC3 ;\t0C43 ;\tMA\t# ( ೃ → ృ ) KANNADA VOWEL SIGN VOCALIC R → TELUGU VOWEL SIGN VOCALIC R\t# \n\n0C44 ;\t0C43 0C3E ;\tMA\t# ( ౄ → ృా ) TELUGU VOWEL SIGN VOCALIC RR → TELUGU VOWEL SIGN VOCALIC R, TELUGU VOWEL SIGN AA\t# \n\n0CE1 ;\t0C8C 0CBE ;\tMA\t# ( ೡ → ಌಾ ) KANNADA LETTER VOCALIC LL → KANNADA LETTER VOCALIC L, KANNADA VOWEL SIGN AA\t# \n\n0C16 ;\t0C96 0323 ;\tMA\t# ( ఖ → ಖ̣ ) TELUGU LETTER KHA → KANNADA LETTER KHA, COMBINING DOT BELOW\t# \n\n0D08 ;\t0D07 0D57 ;\tMA\t# ( ഈ → ഇൗ ) MALAYALAM LETTER II → MALAYALAM LETTER I, MALAYALAM AU LENGTH MARK\t# \n\n0D13 ;\t0D12 0D3E ;\tMA\t# ( ഓ → ഒാ ) MALAYALAM LETTER OO → MALAYALAM LETTER O, MALAYALAM VOWEL SIGN AA\t# \n\n0D14 ;\t0D12 0D57 ;\tMA\t# ( ഔ → ഒൗ ) MALAYALAM LETTER AU → MALAYALAM LETTER O, MALAYALAM AU LENGTH MARK\t# \n\n0D61 ;\t0D1E ;\tMA\t# ( ൡ → ഞ ) MALAYALAM LETTER VOCALIC LL → MALAYALAM LETTER NYA\t# \n\n0D6B ;\t0D26 0D4D 0D30 ;\tMA\t# ( ൫ → ദ്ര ) MALAYALAM DIGIT FIVE → MALAYALAM LETTER DA, MALAYALAM SIGN VIRAMA, MALAYALAM LETTER RA\t# \n\n0D79 ;\t0D28 0D41 ;\tMA\t#* ( ൹ → നു ) MALAYALAM DATE MARK → MALAYALAM LETTER NA, MALAYALAM VOWEL SIGN U\t# \n0D0C ;\t0D28 0D41 ;\tMA\t# ( ഌ → നു ) MALAYALAM LETTER VOCALIC L → MALAYALAM LETTER NA, MALAYALAM VOWEL SIGN U\t# \n0D19 ;\t0D28 0D41 ;\tMA\t# ( ങ → നു ) MALAYALAM LETTER NGA → MALAYALAM LETTER NA, MALAYALAM VOWEL SIGN U\t# →ഌ→\n\n0D6F ;\t0D28 0D4D ;\tMA\t# ( ൯ → ന് ) MALAYALAM DIGIT NINE → MALAYALAM LETTER NA, MALAYALAM SIGN VIRAMA\t# \n0D7B ;\t0D28 0D4D ;\tMA\t# ( ൻ → ന് ) MALAYALAM LETTER CHILLU N → MALAYALAM LETTER NA, MALAYALAM SIGN VIRAMA\t# →൯→\n\n0D6C ;\t0D28 0D4D 0D28 ;\tMA\t# ( ൬ → ന്ന ) MALAYALAM DIGIT SIX → MALAYALAM LETTER NA, MALAYALAM SIGN VIRAMA, MALAYALAM LETTER NA\t# \n\n0D5A ;\t0D28 0D4D 0D2E ;\tMA\t#* ( ൚ → ന്മ ) MALAYALAM FRACTION THREE EIGHTIETHS → MALAYALAM LETTER NA, MALAYALAM SIGN VIRAMA, MALAYALAM LETTER MA\t# \n\n10D8 ;\t0D30 ;\tMA\t# ( ი → ര ) GEORGIAN LETTER IN → MALAYALAM LETTER RA\t# →റ→\n0D31 ;\t0D30 ;\tMA\t# ( റ → ര ) MALAYALAM LETTER RRA → MALAYALAM LETTER RA\t# \n1002 ;\t0D30 ;\tMA\t# ( ဂ → ര ) MYANMAR LETTER GA → MALAYALAM LETTER RA\t# →റ→\n\n0D6A ;\t0D30 0D4D ;\tMA\t# ( ൪ → ര് ) MALAYALAM DIGIT FOUR → MALAYALAM LETTER RA, MALAYALAM SIGN VIRAMA\t# \n0D7C ;\t0D30 0D4D ;\tMA\t# ( ർ → ര് ) MALAYALAM LETTER CHILLU RR → MALAYALAM LETTER RA, MALAYALAM SIGN VIRAMA\t# →൪→\n\n1081 ;\t0D30 103E ;\tMA\t# ( ႁ → രှ ) MYANMAR LETTER SHAN HA → MALAYALAM LETTER RA, MYANMAR CONSONANT SIGN MEDIAL HA\t# →ဂှ→\n\n1000 ;\t0D30 102C ;\tMA\t# ( က → രာ ) MYANMAR LETTER KA → MALAYALAM LETTER RA, MYANMAR VOWEL SIGN AA\t# →ဂာ→\n\n1023 ;\t0D30 102C 1039 0D30 102C ;\tMA\t# ( ဣ → രာ္രာ ) MYANMAR LETTER I → MALAYALAM LETTER RA, MYANMAR VOWEL SIGN AA, MYANMAR SIGN VIRAMA, MALAYALAM LETTER RA, MYANMAR VOWEL SIGN AA\t# →က္က→\n\n0D7D ;\t0D32 0D4D ;\tMA\t# ( ൽ → ല് ) MALAYALAM LETTER CHILLU L → MALAYALAM LETTER LA, MALAYALAM SIGN VIRAMA\t# \n\n0D6E ;\t0D35 0D4D 0D30 ;\tMA\t# ( ൮ → വ്ര ) MALAYALAM DIGIT EIGHT → MALAYALAM LETTER VA, MALAYALAM SIGN VIRAMA, MALAYALAM LETTER RA\t# \n\n0D76 ;\t0D39 0D4D 0D2E ;\tMA\t#* ( ൶ → ഹ്മ ) MALAYALAM FRACTION ONE SIXTEENTH → MALAYALAM LETTER HA, MALAYALAM SIGN VIRAMA, MALAYALAM LETTER MA\t# \n\n0D7E ;\t0D33 0D4D ;\tMA\t# ( ൾ → ള് ) MALAYALAM LETTER CHILLU LL → MALAYALAM LETTER LLA, MALAYALAM SIGN VIRAMA\t# \n\n0D42 ;\t0D41 ;\tMA\t# ( ൂ → ു ) MALAYALAM VOWEL SIGN UU → MALAYALAM VOWEL SIGN U\t# \n0D43 ;\t0D41 ;\tMA\t# ( ൃ → ു ) MALAYALAM VOWEL SIGN VOCALIC R → MALAYALAM VOWEL SIGN U\t# →ൂ→\n\n0DB5 ;\t0D91 ;\tMA\t# ( ඵ → එ ) SINHALA LETTER MAHAAPRAANA PAYANNA → SINHALA LETTER EYANNA\t# \n\n0D93 ;\t0D91 0DD9 ;\tMA\t# ( ඓ → එෙ ) SINHALA LETTER AIYANNA → SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA\t# \n\n0D92 ;\t0D91 0DCA ;\tMA\t# ( ඒ → එ් ) SINHALA LETTER EEYANNA → SINHALA LETTER EYANNA, SINHALA SIGN AL-LAKUNA\t# \n\n0DB9 ;\t0D94 ;\tMA\t# ( ඹ → ඔ ) SINHALA LETTER AMBA BAYANNA → SINHALA LETTER OYANNA\t# \n\n0DB6 ;\t0D9B ;\tMA\t# ( බ → ඛ ) SINHALA LETTER ALPAPRAANA BAYANNA → SINHALA LETTER MAHAAPRAANA KAYANNA\t# \n\n0DC0 ;\t0DA0 ;\tMA\t# ( ව → ච ) SINHALA LETTER VAYANNA → SINHALA LETTER ALPAPRAANA CAYANNA\t# \n\n0DEA ;\t0DA2 ;\tMA\t# ( ෪ → ජ ) SINHALA LITH DIGIT FOUR → SINHALA LETTER ALPAPRAANA JAYANNA\t# \n\n0DEB ;\t0DAF ;\tMA\t# ( ෫ → ද ) SINHALA LITH DIGIT FIVE → SINHALA LETTER ALPAPRAANA DAYANNA\t# \n\n0DC4 ;\t0DB7 ;\tMA\t# ( හ → භ ) SINHALA LETTER HAYANNA → SINHALA LETTER MAHAAPRAANA BAYANNA\t# \n\n0D8D ;\t0DC3 0DD8 ;\tMA\t# ( ඍ → සෘ ) SINHALA LETTER IRUYANNA → SINHALA LETTER DANTAJA SAYANNA, SINHALA VOWEL SIGN GAETTA-PILLA\t# \n\n11413 ;\t11434 11442 11412 ;\tMA\t# ( 𑐓 → 𑐴𑑂𑐒 ) NEWA LETTER NGHA → NEWA LETTER HA, NEWA SIGN VIRAMA, NEWA LETTER NGA\t# \n\n11419 ;\t11434 11442 11418 ;\tMA\t# ( 𑐙 → 𑐴𑑂𑐘 ) NEWA LETTER NYHA → NEWA LETTER HA, NEWA SIGN VIRAMA, NEWA LETTER NYA\t# \n\n11424 ;\t11434 11442 11423 ;\tMA\t# ( 𑐤 → 𑐴𑑂𑐣 ) NEWA LETTER NHA → NEWA LETTER HA, NEWA SIGN VIRAMA, NEWA LETTER NA\t# \n\n1142A ;\t11434 11442 11429 ;\tMA\t# ( 𑐪 → 𑐴𑑂𑐩 ) NEWA LETTER MHA → NEWA LETTER HA, NEWA SIGN VIRAMA, NEWA LETTER MA\t# \n\n1142D ;\t11434 11442 1142C ;\tMA\t# ( 𑐭 → 𑐴𑑂𑐬 ) NEWA LETTER RHA → NEWA LETTER HA, NEWA SIGN VIRAMA, NEWA LETTER RA\t# \n\n1142F ;\t11434 11442 1142E ;\tMA\t# ( 𑐯 → 𑐴𑑂𑐮 ) NEWA LETTER LHA → NEWA LETTER HA, NEWA SIGN VIRAMA, NEWA LETTER LA\t# \n\n115D8 ;\t11582 ;\tMA\t# ( 𑗘 → 𑖂 ) SIDDHAM LETTER THREE-CIRCLE ALTERNATE I → SIDDHAM LETTER I\t# \n115D9 ;\t11582 ;\tMA\t# ( 𑗙 → 𑖂 ) SIDDHAM LETTER TWO-CIRCLE ALTERNATE I → SIDDHAM LETTER I\t# \n\n115DA ;\t11583 ;\tMA\t# ( 𑗚 → 𑖃 ) SIDDHAM LETTER TWO-CIRCLE ALTERNATE II → SIDDHAM LETTER II\t# \n\n115DB ;\t11584 ;\tMA\t# ( 𑗛 → 𑖄 ) SIDDHAM LETTER ALTERNATE U → SIDDHAM LETTER U\t# \n\n115DC ;\t115B2 ;\tMA\t# ( 𑗜 → 𑖲 ) SIDDHAM VOWEL SIGN ALTERNATE U → SIDDHAM VOWEL SIGN U\t# \n\n115DD ;\t115B3 ;\tMA\t# ( 𑗝 → 𑖳 ) SIDDHAM VOWEL SIGN ALTERNATE UU → SIDDHAM VOWEL SIGN UU\t# \n\n0E03 ;\t0E02 ;\tMA\t# ( ฃ → ข ) THAI CHARACTER KHO KHUAT → THAI CHARACTER KHO KHAI\t# \n\n0E14 ;\t0E04 ;\tMA\t# ( ด → ค ) THAI CHARACTER DO DEK → THAI CHARACTER KHO KHWAI\t# \n0E15 ;\t0E04 ;\tMA\t# ( ต → ค ) THAI CHARACTER TO TAO → THAI CHARACTER KHO KHWAI\t# →ด→\n\n0E21 ;\t0E06 ;\tMA\t# ( ม → ฆ ) THAI CHARACTER MO MA → THAI CHARACTER KHO RAKHANG\t# \n\n0E88 ;\t0E08 ;\tMA\t# ( ຈ → จ ) LAO LETTER CO → THAI CHARACTER CHO CHAN\t# \n\n0E0B ;\t0E0A ;\tMA\t# ( ซ → ช ) THAI CHARACTER SO SO → THAI CHARACTER CHO CHANG\t# \n\n0E0F ;\t0E0E ;\tMA\t# ( ฏ → ฎ ) THAI CHARACTER TO PATAK → THAI CHARACTER DO CHADA\t# \n\n0E17 ;\t0E11 ;\tMA\t# ( ท → ฑ ) THAI CHARACTER THO THAHAN → THAI CHARACTER THO NANGMONTHO\t# \n\n0E9A ;\t0E1A ;\tMA\t# ( ບ → บ ) LAO LETTER BO → THAI CHARACTER BO BAIMAI\t# \n\n0E9B ;\t0E1B ;\tMA\t# ( ປ → ป ) LAO LETTER PO → THAI CHARACTER PO PLA\t# \n\n0E9D ;\t0E1D ;\tMA\t# ( ຝ → ฝ ) LAO LETTER FO TAM → THAI CHARACTER FO FA\t# \n\n0E9E ;\t0E1E ;\tMA\t# ( ພ → พ ) LAO LETTER PHO TAM → THAI CHARACTER PHO PHAN\t# \n\n0E9F ;\t0E1F ;\tMA\t# ( ຟ → ฟ ) LAO LETTER FO SUNG → THAI CHARACTER FO FAN\t# \n\n0E26 ;\t0E20 ;\tMA\t# ( ฦ → ภ ) THAI CHARACTER LU → THAI CHARACTER PHO SAMPHAO\t# \n\n0E8D ;\t0E22 ;\tMA\t# ( ຍ → ย ) LAO LETTER NYO → THAI CHARACTER YO YAK\t# \n\n17D4 ;\t0E2F ;\tMA\t#* ( ។ → ฯ ) KHMER SIGN KHAN → THAI CHARACTER PAIYANNOI\t# \n\n0E45 ;\t0E32 ;\tMA\t# ( ๅ → า ) THAI CHARACTER LAKKHANGYAO → THAI CHARACTER SARA AA\t# \n\n0E33 ;\t030A 0E32 ;\tMA\t# ( ำ → ̊า ) THAI CHARACTER SARA AM → COMBINING RING ABOVE, THAI CHARACTER SARA AA\t# →ํา→\n\n17B7 ;\t0E34 ;\tMA\t# ( ិ → ิ ) KHMER VOWEL SIGN I → THAI CHARACTER SARA I\t# \n\n17B8 ;\t0E35 ;\tMA\t# ( ី → ี ) KHMER VOWEL SIGN II → THAI CHARACTER SARA II\t# \n\n17B9 ;\t0E36 ;\tMA\t# ( ឹ → ึ ) KHMER VOWEL SIGN Y → THAI CHARACTER SARA UE\t# \n\n17BA ;\t0E37 ;\tMA\t# ( ឺ → ื ) KHMER VOWEL SIGN YY → THAI CHARACTER SARA UEE\t# \n\n0EB8 ;\t0E38 ;\tMA\t# ( ຸ → ุ ) LAO VOWEL SIGN U → THAI CHARACTER SARA U\t# \n\n0EB9 ;\t0E39 ;\tMA\t# ( ູ → ู ) LAO VOWEL SIGN UU → THAI CHARACTER SARA UU\t# \n\n0E41 ;\t0E40 0E40 ;\tMA\t# ( แ → เเ ) THAI CHARACTER SARA AE → THAI CHARACTER SARA E, THAI CHARACTER SARA E\t# \n\n0EDC ;\t0EAB 0E99 ;\tMA\t# ( ໜ → ຫນ ) LAO HO NO → LAO LETTER HO SUNG, LAO LETTER NO\t# \n\n0EDD ;\t0EAB 0EA1 ;\tMA\t# ( ໝ → ຫມ ) LAO HO MO → LAO LETTER HO SUNG, LAO LETTER MO\t# \n\n0EB3 ;\t030A 0EB2 ;\tMA\t# ( ຳ → ̊າ ) LAO VOWEL SIGN AM → COMBINING RING ABOVE, LAO VOWEL SIGN AA\t# →ໍາ→\n\n0F02 ;\t0F60 0F74 0F82 0F7F ;\tMA\t#* ( ༂ → འུྂཿ ) TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA → TIBETAN LETTER -A, TIBETAN VOWEL SIGN U, TIBETAN SIGN NYI ZLA NAA DA, TIBETAN SIGN RNAM BCAD\t# \n\n0F03 ;\t0F60 0F74 0F82 0F14 ;\tMA\t#* ( ༃ → འུྂ༔ ) TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA → TIBETAN LETTER -A, TIBETAN VOWEL SIGN U, TIBETAN SIGN NYI ZLA NAA DA, TIBETAN MARK GTER TSHEG\t# \n\n0F6A ;\t0F62 ;\tMA\t# ( ཪ → ར ) TIBETAN LETTER FIXED-FORM RA → TIBETAN LETTER RA\t# \n\n0F00 ;\t0F68 0F7C 0F7E ;\tMA\t# ( ༀ → ཨོཾ ) TIBETAN SYLLABLE OM → TIBETAN LETTER A, TIBETAN VOWEL SIGN O, TIBETAN SIGN RJES SU NGA RO\t# \n\n0F77 ;\t0FB2 0F71 0F80 ;\tMA\t# ( ཷ → ྲཱྀ ) TIBETAN VOWEL SIGN VOCALIC RR → TIBETAN SUBJOINED LETTER RA, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN REVERSED I\t# \n\n0F79 ;\t0FB3 0F71 0F80 ;\tMA\t# ( ཹ → ླཱྀ ) TIBETAN VOWEL SIGN VOCALIC LL → TIBETAN SUBJOINED LETTER LA, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN REVERSED I\t# \n\n0F7B ;\t0F7A 0F7A ;\tMA\t# ( ཻ → ེེ ) TIBETAN VOWEL SIGN EE → TIBETAN VOWEL SIGN E, TIBETAN VOWEL SIGN E\t# \n\n0F7D ;\t0F7C 0F7C ;\tMA\t# ( ཽ → ོོ ) TIBETAN VOWEL SIGN OO → TIBETAN VOWEL SIGN O, TIBETAN VOWEL SIGN O\t# \n\n11CB2 ;\t11CAA ;\tMA\t# ( 𑲲 → 𑲪 ) MARCHEN VOWEL SIGN U → MARCHEN SUBJOINED LETTER RA\t# \n\n1734 ;\t1715 ;\tMA\t# ( ᜴ → ᜕ ) HANUNOO SIGN PAMUDPOD → TAGALOG SIGN PAMUDPOD\t# \n\n1070 ;\t1003 103E ;\tMA\t# ( ၰ → ဃှ ) MYANMAR LETTER EASTERN PWO KAREN GHWA → MYANMAR LETTER GHA, MYANMAR CONSONANT SIGN MEDIAL HA\t# \n\n1066 ;\t1015 103E ;\tMA\t# ( ၦ → ပှ ) MYANMAR LETTER WESTERN PWO KAREN PWA → MYANMAR LETTER PA, MYANMAR CONSONANT SIGN MEDIAL HA\t# \n\n101F ;\t1015 102C ;\tMA\t# ( ဟ → ပာ ) MYANMAR LETTER HA → MYANMAR LETTER PA, MYANMAR VOWEL SIGN AA\t# \n\n106F ;\t1015 102C 103E ;\tMA\t# ( ၯ → ပာှ ) MYANMAR LETTER EASTERN PWO KAREN YWA → MYANMAR LETTER PA, MYANMAR VOWEL SIGN AA, MYANMAR CONSONANT SIGN MEDIAL HA\t# →ဟှ→\n\n107E ;\t107D 103E ;\tMA\t# ( ၾ → ၽှ ) MYANMAR LETTER SHAN FA → MYANMAR LETTER SHAN PHA, MYANMAR CONSONANT SIGN MEDIAL HA\t# \n\n1061 ;\t101B 103E ;\tMA\t# ( ၡ → ရှ ) MYANMAR LETTER SGAW KAREN SHA → MYANMAR LETTER RA, MYANMAR CONSONANT SIGN MEDIAL HA\t# \n\n1029 ;\t101E 103C ;\tMA\t# ( ဩ → သြ ) MYANMAR LETTER O → MYANMAR LETTER SA, MYANMAR CONSONANT SIGN MEDIAL RA\t# \n\n102A ;\t101E 103C 0B47 102C 103A ;\tMA\t# ( ဪ → သြେာ် ) MYANMAR LETTER AU → MYANMAR LETTER SA, MYANMAR CONSONANT SIGN MEDIAL RA, ORIYA VOWEL SIGN E, MYANMAR VOWEL SIGN AA, MYANMAR SIGN ASAT\t# →ဩော်→\n\n109E ;\t1083 030A ;\tMA\t#* ( ႞ → ႃ̊ ) MYANMAR SYMBOL SHAN ONE → MYANMAR VOWEL SIGN SHAN AA, COMBINING RING ABOVE\t# →ႃံ→\n\n178F ;\t178A ;\tMA\t# ( ត → ដ ) KHMER LETTER TA → KHMER LETTER DA\t# \n\n17A3 ;\t17A2 ;\tMA\t# ( ឣ → អ ) KHMER INDEPENDENT VOWEL QAQ → KHMER LETTER QA\t# \n\n19D0 ;\t199E ;\tMA\t# ( ᧐ → ᦞ ) NEW TAI LUE DIGIT ZERO → NEW TAI LUE LETTER LOW VA\t# \n\n19D1 ;\t19B1 ;\tMA\t# ( ᧑ → ᦱ ) NEW TAI LUE DIGIT ONE → NEW TAI LUE VOWEL SIGN AA\t# \n\n1A80 ;\t1A45 ;\tMA\t# ( ᪀ → ᩅ ) TAI THAM HORA DIGIT ZERO → TAI THAM LETTER WA\t# \n1A90 ;\t1A45 ;\tMA\t# ( ᪐ → ᩅ ) TAI THAM THAM DIGIT ZERO → TAI THAM LETTER WA\t# \n\nAA53 ;\tAA01 ;\tMA\t# ( ꩓ → ꨁ ) CHAM DIGIT THREE → CHAM LETTER I\t# \n\nAA56 ;\tAA23 ;\tMA\t# ( ꩖ → ꨣ ) CHAM DIGIT SIX → CHAM LETTER RA\t# \n\n1B52 ;\t1B0D ;\tMA\t# ( ᭒ → ᬍ ) BALINESE DIGIT TWO → BALINESE LETTER LA LENGA\t# \n\n1B53 ;\t1B11 ;\tMA\t# ( ᭓ → ᬑ ) BALINESE DIGIT THREE → BALINESE LETTER OKARA\t# \n\n1B58 ;\t1B28 ;\tMA\t# ( ᭘ → ᬨ ) BALINESE DIGIT EIGHT → BALINESE LETTER PA KAPAL\t# \n\nA9A3 ;\tA99D ;\tMA\t# ( ꦣ → ꦝ ) JAVANESE LETTER DA MAHAPRANA → JAVANESE LETTER DDA\t# \n\n1896 ;\t185C ;\tMA\t# ( ᢖ → ᡜ ) MONGOLIAN LETTER ALI GALI ZA → MONGOLIAN LETTER TODO DZA\t# \n\n1855 ;\t1835 ;\tMA\t# ( ᡕ → ᠵ ) MONGOLIAN LETTER TODO YA → MONGOLIAN LETTER JA\t# \n\n1FF6 ;\t13EF ;\tMA\t# ( ῶ → Ꮿ ) GREEK SMALL LETTER OMEGA WITH PERISPOMENI → CHEROKEE LETTER YA\t# \n\n140D ;\t1401 00B7 ;\tMA\t# ( ᐍ → ᐁ· ) CANADIAN SYLLABICS WEST-CREE WE → CANADIAN SYLLABICS E, MIDDLE DOT\t# →ᐁᐧ→\n\n142B ;\t1401 1420 ;\tMA\t# ( ᐫ → ᐁᐠ ) CANADIAN SYLLABICS EN → CANADIAN SYLLABICS E, CANADIAN SYLLABICS FINAL GRAVE\t# \n\n1411 ;\t1404 00B7 ;\tMA\t# ( ᐑ → ᐄ· ) CANADIAN SYLLABICS WEST-CREE WII → CANADIAN SYLLABICS II, MIDDLE DOT\t# →ᐄᐧ→\n\n1413 ;\t1405 00B7 ;\tMA\t# ( ᐓ → ᐅ· ) CANADIAN SYLLABICS WEST-CREE WO → CANADIAN SYLLABICS O, MIDDLE DOT\t# →ᐅᐧ→\n\n142D ;\t1405 1420 ;\tMA\t# ( ᐭ → ᐅᐠ ) CANADIAN SYLLABICS ON → CANADIAN SYLLABICS O, CANADIAN SYLLABICS FINAL GRAVE\t# \n\n1415 ;\t1406 00B7 ;\tMA\t# ( ᐕ → ᐆ· ) CANADIAN SYLLABICS WEST-CREE WOO → CANADIAN SYLLABICS OO, MIDDLE DOT\t# →ᐆᐧ→\n\n1418 ;\t140A 00B7 ;\tMA\t# ( ᐘ → ᐊ· ) CANADIAN SYLLABICS WEST-CREE WA → CANADIAN SYLLABICS A, MIDDLE DOT\t# →ᐊᐧ→\n\n142E ;\t140A 1420 ;\tMA\t# ( ᐮ → ᐊᐠ ) CANADIAN SYLLABICS AN → CANADIAN SYLLABICS A, CANADIAN SYLLABICS FINAL GRAVE\t# \n\n141A ;\t140B 00B7 ;\tMA\t# ( ᐚ → ᐋ· ) CANADIAN SYLLABICS WEST-CREE WAA → CANADIAN SYLLABICS AA, MIDDLE DOT\t# →ᐋᐧ→\n\n18DD ;\t141E 18DF ;\tMA\t# ( ᣝ → ᐞᣟ ) CANADIAN SYLLABICS WESTERN W → CANADIAN SYLLABICS GLOTTAL STOP, CANADIAN SYLLABICS FINAL RAISED DOT\t# \n\n14D1 ;\t1421 ;\tMA\t# ( ᓑ → ᐡ ) CANADIAN SYLLABICS CARRIER NG → CANADIAN SYLLABICS FINAL BOTTOM HALF RING\t# \n\n1540 ;\t1429 ;\tMA\t# ( ᕀ → ᐩ ) CANADIAN SYLLABICS WEST-CREE Y → CANADIAN SYLLABICS FINAL PLUS\t# \n\n143F ;\t1432 00B7 ;\tMA\t# ( ᐿ → ᐲ· ) CANADIAN SYLLABICS WEST-CREE PWII → CANADIAN SYLLABICS PII, MIDDLE DOT\t# →ᐲᐧ→\n\n1443 ;\t1434 00B7 ;\tMA\t# ( ᑃ → ᐴ· ) CANADIAN SYLLABICS WEST-CREE PWOO → CANADIAN SYLLABICS POO, MIDDLE DOT\t# →ᐴᐧ→\n\n2369 ;\t1435 ;\tMA\t#* ( ⍩ → ᐵ ) APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS → CANADIAN SYLLABICS Y-CREE POO\t# \n\n1447 ;\t1439 00B7 ;\tMA\t# ( ᑇ → ᐹ· ) CANADIAN SYLLABICS WEST-CREE PWAA → CANADIAN SYLLABICS PAA, MIDDLE DOT\t# →ᐹᐧ→\n\n145C ;\t144F 00B7 ;\tMA\t# ( ᑜ → ᑏ· ) CANADIAN SYLLABICS WEST-CREE TWII → CANADIAN SYLLABICS TII, MIDDLE DOT\t# →ᑏᐧ→\n\n2E27 ;\t1450 ;\tMA\t#* ( ⸧ → ᑐ ) RIGHT SIDEWAYS U BRACKET → CANADIAN SYLLABICS TO\t# →⊃→\n2283 ;\t1450 ;\tMA\t#* ( ⊃ → ᑐ ) SUPERSET OF → CANADIAN SYLLABICS TO\t# \n\n145E ;\t1450 00B7 ;\tMA\t# ( ᑞ → ᑐ· ) CANADIAN SYLLABICS WEST-CREE TWO → CANADIAN SYLLABICS TO, MIDDLE DOT\t# →ᑐᐧ→\n\n1469 ;\t1450 0027 ;\tMA\t# ( ᑩ → ᑐ' ) CANADIAN SYLLABICS TTO → CANADIAN SYLLABICS TO, APOSTROPHE\t# →ᑐᑊ→\n\n27C9 ;\t1450 002F ;\tMA\t#* ( ⟉ → ᑐ/ ) SUPERSET PRECEDING SOLIDUS → CANADIAN SYLLABICS TO, SOLIDUS\t# →⊃/→\n\n2AD7 ;\t1450 1455 ;\tMA\t#* ( ⫗ → ᑐᑕ ) SUPERSET BESIDE SUBSET → CANADIAN SYLLABICS TO, CANADIAN SYLLABICS TA\t# →⊃⊂→\n\n1460 ;\t1451 00B7 ;\tMA\t# ( ᑠ → ᑑ· ) CANADIAN SYLLABICS WEST-CREE TWOO → CANADIAN SYLLABICS TOO, MIDDLE DOT\t# →ᑑᐧ→\n\n2E26 ;\t1455 ;\tMA\t#* ( ⸦ → ᑕ ) LEFT SIDEWAYS U BRACKET → CANADIAN SYLLABICS TA\t# →⊂→\n2282 ;\t1455 ;\tMA\t#* ( ⊂ → ᑕ ) SUBSET OF → CANADIAN SYLLABICS TA\t# \n\n1462 ;\t1455 00B7 ;\tMA\t# ( ᑢ → ᑕ· ) CANADIAN SYLLABICS WEST-CREE TWA → CANADIAN SYLLABICS TA, MIDDLE DOT\t# →ᑕᐧ→\n\n146A ;\t1455 0027 ;\tMA\t# ( ᑪ → ᑕ' ) CANADIAN SYLLABICS TTA → CANADIAN SYLLABICS TA, APOSTROPHE\t# →ᑕᑊ→\n\n1464 ;\t1456 00B7 ;\tMA\t# ( ᑤ → ᑖ· ) CANADIAN SYLLABICS WEST-CREE TWAA → CANADIAN SYLLABICS TAA, MIDDLE DOT\t# →ᑖᐧ→\n\n1475 ;\t146B 00B7 ;\tMA\t# ( ᑵ → ᑫ· ) CANADIAN SYLLABICS WEST-CREE KWE → CANADIAN SYLLABICS KE, MIDDLE DOT\t# →ᑫᐧ→\n\n1485 ;\t146B 0027 ;\tMA\t# ( ᒅ → ᑫ' ) CANADIAN SYLLABICS SOUTH-SLAVEY KEH → CANADIAN SYLLABICS KE, APOSTROPHE\t# →ᑫᑊ→\n\n1479 ;\t146E 00B7 ;\tMA\t# ( ᑹ → ᑮ· ) CANADIAN SYLLABICS WEST-CREE KWII → CANADIAN SYLLABICS KII, MIDDLE DOT\t# →ᑮᐧ→\n\n147D ;\t1470 00B7 ;\tMA\t# ( ᑽ → ᑰ· ) CANADIAN SYLLABICS WEST-CREE KWOO → CANADIAN SYLLABICS KOO, MIDDLE DOT\t# →ᑰᐧ→\n\n1603 ;\t1489 ;\tMA\t# ( ᘃ → ᒉ ) CANADIAN SYLLABICS CARRIER NO → CANADIAN SYLLABICS CE\t# \n\n1493 ;\t1489 00B7 ;\tMA\t# ( ᒓ → ᒉ· ) CANADIAN SYLLABICS WEST-CREE CWE → CANADIAN SYLLABICS CE, MIDDLE DOT\t# →ᒉᐧ→\n\n1495 ;\t148B 00B7 ;\tMA\t# ( ᒕ → ᒋ· ) CANADIAN SYLLABICS WEST-CREE CWI → CANADIAN SYLLABICS CI, MIDDLE DOT\t# →ᒋᐧ→\n\n1497 ;\t148C 00B7 ;\tMA\t# ( ᒗ → ᒌ· ) CANADIAN SYLLABICS WEST-CREE CWII → CANADIAN SYLLABICS CII, MIDDLE DOT\t# →ᒌᐧ→\n\n149B ;\t148E 00B7 ;\tMA\t# ( ᒛ → ᒎ· ) CANADIAN SYLLABICS WEST-CREE CWOO → CANADIAN SYLLABICS COO, MIDDLE DOT\t# →ᒎᐧ→\n\n1602 ;\t1490 ;\tMA\t# ( ᘂ → ᒐ ) CANADIAN SYLLABICS CARRIER NU → CANADIAN SYLLABICS CA\t# \n\n149D ;\t1490 00B7 ;\tMA\t# ( ᒝ → ᒐ· ) CANADIAN SYLLABICS WEST-CREE CWA → CANADIAN SYLLABICS CA, MIDDLE DOT\t# →ᒐᐧ→\n\n149F ;\t1491 00B7 ;\tMA\t# ( ᒟ → ᒑ· ) CANADIAN SYLLABICS WEST-CREE CWAA → CANADIAN SYLLABICS CAA, MIDDLE DOT\t# →ᒑᐧ→\n\n14AD ;\t14A3 00B7 ;\tMA\t# ( ᒭ → ᒣ· ) CANADIAN SYLLABICS WEST-CREE MWE → CANADIAN SYLLABICS ME, MIDDLE DOT\t# →ᒣᐧ→\n\n14B1 ;\t14A6 00B7 ;\tMA\t# ( ᒱ → ᒦ· ) CANADIAN SYLLABICS WEST-CREE MWII → CANADIAN SYLLABICS MII, MIDDLE DOT\t# →ᒦᐧ→\n\n14B3 ;\t14A7 00B7 ;\tMA\t# ( ᒳ → ᒧ· ) CANADIAN SYLLABICS WEST-CREE MWO → CANADIAN SYLLABICS MO, MIDDLE DOT\t# →ᒧᐧ→\n\n14B5 ;\t14A8 00B7 ;\tMA\t# ( ᒵ → ᒨ· ) CANADIAN SYLLABICS WEST-CREE MWOO → CANADIAN SYLLABICS MOO, MIDDLE DOT\t# →ᒨᐧ→\n\n14B9 ;\t14AB 00B7 ;\tMA\t# ( ᒹ → ᒫ· ) CANADIAN SYLLABICS WEST-CREE MWAA → CANADIAN SYLLABICS MAA, MIDDLE DOT\t# →ᒫᐧ→\n\n14CA ;\t14C0 00B7 ;\tMA\t# ( ᓊ → ᓀ· ) CANADIAN SYLLABICS WEST-CREE NWE → CANADIAN SYLLABICS NE, MIDDLE DOT\t# →ᓀᐧ→\n\n18C7 ;\t14C2 00B7 ;\tMA\t# ( ᣇ → ᓂ· ) CANADIAN SYLLABICS OJIBWAY NWI → CANADIAN SYLLABICS NI, MIDDLE DOT\t# →ᓂᐧ→\n\n18C9 ;\t14C3 00B7 ;\tMA\t# ( ᣉ → ᓃ· ) CANADIAN SYLLABICS OJIBWAY NWII → CANADIAN SYLLABICS NII, MIDDLE DOT\t# →ᓃᐧ→\n\n18CB ;\t14C4 00B7 ;\tMA\t# ( ᣋ → ᓄ· ) CANADIAN SYLLABICS OJIBWAY NWO → CANADIAN SYLLABICS NO, MIDDLE DOT\t# →ᓄᐧ→\n\n18CD ;\t14C5 00B7 ;\tMA\t# ( ᣍ → ᓅ· ) CANADIAN SYLLABICS OJIBWAY NWOO → CANADIAN SYLLABICS NOO, MIDDLE DOT\t# →ᓅᐧ→\n\n14CC ;\t14C7 00B7 ;\tMA\t# ( ᓌ → ᓇ· ) CANADIAN SYLLABICS WEST-CREE NWA → CANADIAN SYLLABICS NA, MIDDLE DOT\t# →ᓇᐧ→\n\n14CE ;\t14C8 00B7 ;\tMA\t# ( ᓎ → ᓈ· ) CANADIAN SYLLABICS WEST-CREE NWAA → CANADIAN SYLLABICS NAA, MIDDLE DOT\t# →ᓈᐧ→\n\n1604 ;\t14D3 ;\tMA\t# ( ᘄ → ᓓ ) CANADIAN SYLLABICS CARRIER NE → CANADIAN SYLLABICS LE\t# \n\n14DD ;\t14D3 00B7 ;\tMA\t# ( ᓝ → ᓓ· ) CANADIAN SYLLABICS WEST-CREE LWE → CANADIAN SYLLABICS LE, MIDDLE DOT\t# →ᓓᐧ→\n\n14DF ;\t14D5 00B7 ;\tMA\t# ( ᓟ → ᓕ· ) CANADIAN SYLLABICS WEST-CREE LWI → CANADIAN SYLLABICS LI, MIDDLE DOT\t# →ᓕᐧ→\n\n14E1 ;\t14D6 00B7 ;\tMA\t# ( ᓡ → ᓖ· ) CANADIAN SYLLABICS WEST-CREE LWII → CANADIAN SYLLABICS LII, MIDDLE DOT\t# →ᓖᐧ→\n\n14E3 ;\t14D7 00B7 ;\tMA\t# ( ᓣ → ᓗ· ) CANADIAN SYLLABICS WEST-CREE LWO → CANADIAN SYLLABICS LO, MIDDLE DOT\t# →ᓗᐧ→\n\n14E5 ;\t14D8 00B7 ;\tMA\t# ( ᓥ → ᓘ· ) CANADIAN SYLLABICS WEST-CREE LWOO → CANADIAN SYLLABICS LOO, MIDDLE DOT\t# →ᓘᐧ→\n\n1607 ;\t14DA ;\tMA\t# ( ᘇ → ᓚ ) CANADIAN SYLLABICS CARRIER NA → CANADIAN SYLLABICS LA\t# \n\n14E7 ;\t14DA 00B7 ;\tMA\t# ( ᓧ → ᓚ· ) CANADIAN SYLLABICS WEST-CREE LWA → CANADIAN SYLLABICS LA, MIDDLE DOT\t# →ᓚᐧ→\n\n14E9 ;\t14DB 00B7 ;\tMA\t# ( ᓩ → ᓛ· ) CANADIAN SYLLABICS WEST-CREE LWAA → CANADIAN SYLLABICS LAA, MIDDLE DOT\t# →ᓛᐧ→\n\n14F7 ;\t14ED 00B7 ;\tMA\t# ( ᓷ → ᓭ· ) CANADIAN SYLLABICS WEST-CREE SWE → CANADIAN SYLLABICS SE, MIDDLE DOT\t# →ᓭᐧ→\n\n14F9 ;\t14EF 00B7 ;\tMA\t# ( ᓹ → ᓯ· ) CANADIAN SYLLABICS WEST-CREE SWI → CANADIAN SYLLABICS SI, MIDDLE DOT\t# →ᓯᐧ→\n\n14FB ;\t14F0 00B7 ;\tMA\t# ( ᓻ → ᓰ· ) CANADIAN SYLLABICS WEST-CREE SWII → CANADIAN SYLLABICS SII, MIDDLE DOT\t# →ᓰᐧ→\n\n14FD ;\t14F1 00B7 ;\tMA\t# ( ᓽ → ᓱ· ) CANADIAN SYLLABICS WEST-CREE SWO → CANADIAN SYLLABICS SO, MIDDLE DOT\t# →ᓱᐧ→\n\n14FF ;\t14F2 00B7 ;\tMA\t# ( ᓿ → ᓲ· ) CANADIAN SYLLABICS WEST-CREE SWOO → CANADIAN SYLLABICS SOO, MIDDLE DOT\t# →ᓲᐧ→\n\n1501 ;\t14F4 00B7 ;\tMA\t# ( ᔁ → ᓴ· ) CANADIAN SYLLABICS WEST-CREE SWA → CANADIAN SYLLABICS SA, MIDDLE DOT\t# →ᓴᐧ→\n\n1503 ;\t14F5 00B7 ;\tMA\t# ( ᔃ → ᓵ· ) CANADIAN SYLLABICS WEST-CREE SWAA → CANADIAN SYLLABICS SAA, MIDDLE DOT\t# →ᓵᐧ→\n\n150C ;\t150B 003C ;\tMA\t# ( ᔌ → ᔋ< ) CANADIAN SYLLABICS NASKAPI SPWA → CANADIAN SYLLABICS NASKAPI S-W, LESS-THAN SIGN\t# →ᔋᐸ→\n\n150E ;\t150B 0062 ;\tMA\t# ( ᔎ → ᔋb ) CANADIAN SYLLABICS NASKAPI SKWA → CANADIAN SYLLABICS NASKAPI S-W, LATIN SMALL LETTER B\t# →ᔋᑲ→\n\n150D ;\t150B 1455 ;\tMA\t# ( ᔍ → ᔋᑕ ) CANADIAN SYLLABICS NASKAPI STWA → CANADIAN SYLLABICS NASKAPI S-W, CANADIAN SYLLABICS TA\t# \n\n150F ;\t150B 1490 ;\tMA\t# ( ᔏ → ᔋᒐ ) CANADIAN SYLLABICS NASKAPI SCWA → CANADIAN SYLLABICS NASKAPI S-W, CANADIAN SYLLABICS CA\t# \n\n1518 ;\t1510 00B7 ;\tMA\t# ( ᔘ → ᔐ· ) CANADIAN SYLLABICS WEST-CREE SHWE → CANADIAN SYLLABICS SHE, MIDDLE DOT\t# →ᔐᐧ→\n\n151A ;\t1511 00B7 ;\tMA\t# ( ᔚ → ᔑ· ) CANADIAN SYLLABICS WEST-CREE SHWI → CANADIAN SYLLABICS SHI, MIDDLE DOT\t# →ᔑᐧ→\n\n151C ;\t1512 00B7 ;\tMA\t# ( ᔜ → ᔒ· ) CANADIAN SYLLABICS WEST-CREE SHWII → CANADIAN SYLLABICS SHII, MIDDLE DOT\t# →ᔒᐧ→\n\n151E ;\t1513 00B7 ;\tMA\t# ( ᔞ → ᔓ· ) CANADIAN SYLLABICS WEST-CREE SHWO → CANADIAN SYLLABICS SHO, MIDDLE DOT\t# →ᔓᐧ→\n\n1520 ;\t1514 00B7 ;\tMA\t# ( ᔠ → ᔔ· ) CANADIAN SYLLABICS WEST-CREE SHWOO → CANADIAN SYLLABICS SHOO, MIDDLE DOT\t# →ᔔᐧ→\n\n1522 ;\t1515 00B7 ;\tMA\t# ( ᔢ → ᔕ· ) CANADIAN SYLLABICS WEST-CREE SHWA → CANADIAN SYLLABICS SHA, MIDDLE DOT\t# →ᔕᐧ→\n\n1524 ;\t1516 00B7 ;\tMA\t# ( ᔤ → ᔖ· ) CANADIAN SYLLABICS WEST-CREE SHWAA → CANADIAN SYLLABICS SHAA, MIDDLE DOT\t# →ᔖᐧ→\n\n1532 ;\t1528 00B7 ;\tMA\t# ( ᔲ → ᔨ· ) CANADIAN SYLLABICS WEST-CREE YWI → CANADIAN SYLLABICS YI, MIDDLE DOT\t# →ᔨᐧ→\n\n1534 ;\t1529 00B7 ;\tMA\t# ( ᔴ → ᔩ· ) CANADIAN SYLLABICS WEST-CREE YWII → CANADIAN SYLLABICS YII, MIDDLE DOT\t# →ᔩᐧ→\n\n1536 ;\t152A 00B7 ;\tMA\t# ( ᔶ → ᔪ· ) CANADIAN SYLLABICS WEST-CREE YWO → CANADIAN SYLLABICS YO, MIDDLE DOT\t# →ᔪᐧ→\n\n1538 ;\t152B 00B7 ;\tMA\t# ( ᔸ → ᔫ· ) CANADIAN SYLLABICS WEST-CREE YWOO → CANADIAN SYLLABICS YOO, MIDDLE DOT\t# →ᔫᐧ→\n\n153A ;\t152D 00B7 ;\tMA\t# ( ᔺ → ᔭ· ) CANADIAN SYLLABICS WEST-CREE YWA → CANADIAN SYLLABICS YA, MIDDLE DOT\t# →ᔭᐧ→\n\n153C ;\t152E 00B7 ;\tMA\t# ( ᔼ → ᔮ· ) CANADIAN SYLLABICS WEST-CREE YWAA → CANADIAN SYLLABICS YAA, MIDDLE DOT\t# →ᔮᐧ→\n\n1622 ;\t1543 ;\tMA\t# ( ᘢ → ᕃ ) CANADIAN SYLLABICS CARRIER LU → CANADIAN SYLLABICS R-CREE RE\t# \n\n18E0 ;\t1543 00B7 ;\tMA\t# ( ᣠ → ᕃ· ) CANADIAN SYLLABICS R-CREE RWE → CANADIAN SYLLABICS R-CREE RE, MIDDLE DOT\t# →ᕃᐧ→\n\n1623 ;\t1546 ;\tMA\t# ( ᘣ → ᕆ ) CANADIAN SYLLABICS CARRIER LO → CANADIAN SYLLABICS RI\t# \n\n1624 ;\t154A ;\tMA\t# ( ᘤ → ᕊ ) CANADIAN SYLLABICS CARRIER LE → CANADIAN SYLLABICS WEST-CREE LO\t# \n\n154F ;\t154C 00B7 ;\tMA\t# ( ᕏ → ᕌ· ) CANADIAN SYLLABICS WEST-CREE RWAA → CANADIAN SYLLABICS RAA, MIDDLE DOT\t# →ᕌᐧ→\n\n1583 ;\t1550 0062 ;\tMA\t# ( ᖃ → ᕐb ) CANADIAN SYLLABICS QA → CANADIAN SYLLABICS R, LATIN SMALL LETTER B\t# →ᕐᑲ→\n\n1584 ;\t1550 0062 0307 ;\tMA\t# ( ᖄ → ᕐḃ ) CANADIAN SYLLABICS QAA → CANADIAN SYLLABICS R, LATIN SMALL LETTER B, COMBINING DOT ABOVE\t# →ᕐᑳ→\n\n1581 ;\t1550 0064 ;\tMA\t# ( ᖁ → ᕐd ) CANADIAN SYLLABICS QO → CANADIAN SYLLABICS R, LATIN SMALL LETTER D\t# →ᕐᑯ→\n\n157F ;\t1550 0050 ;\tMA\t# ( ᕿ → ᕐP ) CANADIAN SYLLABICS QI → CANADIAN SYLLABICS R, LATIN CAPITAL LETTER P\t# →ᕐᑭ→\n\n166F ;\t1550 146B ;\tMA\t# ( ᙯ → ᕐᑫ ) CANADIAN SYLLABICS QAI → CANADIAN SYLLABICS R, CANADIAN SYLLABICS KE\t# \n\n157E ;\t1550 146C ;\tMA\t# ( ᕾ → ᕐᑬ ) CANADIAN SYLLABICS QAAI → CANADIAN SYLLABICS R, CANADIAN SYLLABICS KAAI\t# \n\n1580 ;\t1550 146E ;\tMA\t# ( ᖀ → ᕐᑮ ) CANADIAN SYLLABICS QII → CANADIAN SYLLABICS R, CANADIAN SYLLABICS KII\t# \n\n1582 ;\t1550 1470 ;\tMA\t# ( ᖂ → ᕐᑰ ) CANADIAN SYLLABICS QOO → CANADIAN SYLLABICS R, CANADIAN SYLLABICS KOO\t# \n\n1585 ;\t1550 1483 ;\tMA\t# ( ᖅ → ᕐᒃ ) CANADIAN SYLLABICS Q → CANADIAN SYLLABICS R, CANADIAN SYLLABICS K\t# \n\n155C ;\t155A 00B7 ;\tMA\t# ( ᕜ → ᕚ· ) CANADIAN SYLLABICS WEST-CREE FWAA → CANADIAN SYLLABICS FAA, MIDDLE DOT\t# →ᕚᐧ→\n\n18E3 ;\t155E 00B7 ;\tMA\t# ( ᣣ → ᕞ· ) CANADIAN SYLLABICS THWE → CANADIAN SYLLABICS THE, MIDDLE DOT\t# →ᕞᐧ→\n\n18E4 ;\t1566 00B7 ;\tMA\t# ( ᣤ → ᕦ· ) CANADIAN SYLLABICS THWA → CANADIAN SYLLABICS THA, MIDDLE DOT\t# →ᕦᐧ→\n\n1569 ;\t1567 00B7 ;\tMA\t# ( ᕩ → ᕧ· ) CANADIAN SYLLABICS WEST-CREE THWAA → CANADIAN SYLLABICS THAA, MIDDLE DOT\t# →ᕧᐧ→\n\n18E5 ;\t156B 00B7 ;\tMA\t# ( ᣥ → ᕫ· ) CANADIAN SYLLABICS TTHWE → CANADIAN SYLLABICS TTHE, MIDDLE DOT\t# →ᕫᐧ→\n\n18E8 ;\t1586 00B7 ;\tMA\t# ( ᣨ → ᖆ· ) CANADIAN SYLLABICS TLHWE → CANADIAN SYLLABICS TLHE, MIDDLE DOT\t# →ᖆᐧ→\n\n1591 ;\t1595 004A ;\tMA\t# ( ᖑ → ᖕJ ) CANADIAN SYLLABICS NGO → CANADIAN SYLLABICS NG, LATIN CAPITAL LETTER J\t# →ᖕᒍ→\n\n1670 ;\t1595 1489 ;\tMA\t# ( ᙰ → ᖕᒉ ) CANADIAN SYLLABICS NGAI → CANADIAN SYLLABICS NG, CANADIAN SYLLABICS CE\t# \n\n158E ;\t1595 148A ;\tMA\t# ( ᖎ → ᖕᒊ ) CANADIAN SYLLABICS NGAAI → CANADIAN SYLLABICS NG, CANADIAN SYLLABICS CAAI\t# \n\n158F ;\t1595 148B ;\tMA\t# ( ᖏ → ᖕᒋ ) CANADIAN SYLLABICS NGI → CANADIAN SYLLABICS NG, CANADIAN SYLLABICS CI\t# \n\n1590 ;\t1595 148C ;\tMA\t# ( ᖐ → ᖕᒌ ) CANADIAN SYLLABICS NGII → CANADIAN SYLLABICS NG, CANADIAN SYLLABICS CII\t# \n\n1592 ;\t1595 148E ;\tMA\t# ( ᖒ → ᖕᒎ ) CANADIAN SYLLABICS NGOO → CANADIAN SYLLABICS NG, CANADIAN SYLLABICS COO\t# \n\n1593 ;\t1595 1490 ;\tMA\t# ( ᖓ → ᖕᒐ ) CANADIAN SYLLABICS NGA → CANADIAN SYLLABICS NG, CANADIAN SYLLABICS CA\t# \n\n1594 ;\t1595 1491 ;\tMA\t# ( ᖔ → ᖕᒑ ) CANADIAN SYLLABICS NGAA → CANADIAN SYLLABICS NG, CANADIAN SYLLABICS CAA\t# \n\n1673 ;\t1596 004A ;\tMA\t# ( ᙳ → ᖖJ ) CANADIAN SYLLABICS NNGO → CANADIAN SYLLABICS NNG, LATIN CAPITAL LETTER J\t# →ᖖᒍ→\n\n1671 ;\t1596 148B ;\tMA\t# ( ᙱ → ᖖᒋ ) CANADIAN SYLLABICS NNGI → CANADIAN SYLLABICS NNG, CANADIAN SYLLABICS CI\t# \n\n1672 ;\t1596 148C ;\tMA\t# ( ᙲ → ᖖᒌ ) CANADIAN SYLLABICS NNGII → CANADIAN SYLLABICS NNG, CANADIAN SYLLABICS CII\t# \n\n1674 ;\t1596 148E ;\tMA\t# ( ᙴ → ᖖᒎ ) CANADIAN SYLLABICS NNGOO → CANADIAN SYLLABICS NNG, CANADIAN SYLLABICS COO\t# \n\n1675 ;\t1596 1490 ;\tMA\t# ( ᙵ → ᖖᒐ ) CANADIAN SYLLABICS NNGA → CANADIAN SYLLABICS NNG, CANADIAN SYLLABICS CA\t# \n\n1676 ;\t1596 1491 ;\tMA\t# ( ᙶ → ᖖᒑ ) CANADIAN SYLLABICS NNGAA → CANADIAN SYLLABICS NNG, CANADIAN SYLLABICS CAA\t# \n\n18EA ;\t1597 00B7 ;\tMA\t# ( ᣪ → ᖗ· ) CANADIAN SYLLABICS SAYISI SHWE → CANADIAN SYLLABICS SAYISI SHE, MIDDLE DOT\t# →ᖗᐧ→\n\n1677 ;\t15A7 00B7 ;\tMA\t# ( ᙷ → ᖧ· ) CANADIAN SYLLABICS WOODS-CREE THWEE → CANADIAN SYLLABICS TH-CREE THE, MIDDLE DOT\t# →ᖧᐧ→\n\n1678 ;\t15A8 00B7 ;\tMA\t# ( ᙸ → ᖨ· ) CANADIAN SYLLABICS WOODS-CREE THWI → CANADIAN SYLLABICS TH-CREE THI, MIDDLE DOT\t# →ᖨᐧ→\n\n1679 ;\t15A9 00B7 ;\tMA\t# ( ᙹ → ᖩ· ) CANADIAN SYLLABICS WOODS-CREE THWII → CANADIAN SYLLABICS TH-CREE THII, MIDDLE DOT\t# →ᖩᐧ→\n\n167A ;\t15AA 00B7 ;\tMA\t# ( ᙺ → ᖪ· ) CANADIAN SYLLABICS WOODS-CREE THWO → CANADIAN SYLLABICS TH-CREE THO, MIDDLE DOT\t# →ᖪᐧ→\n\n167B ;\t15AB 00B7 ;\tMA\t# ( ᙻ → ᖫ· ) CANADIAN SYLLABICS WOODS-CREE THWOO → CANADIAN SYLLABICS TH-CREE THOO, MIDDLE DOT\t# →ᖫᐧ→\n\n167C ;\t15AC 00B7 ;\tMA\t# ( ᙼ → ᖬ· ) CANADIAN SYLLABICS WOODS-CREE THWA → CANADIAN SYLLABICS TH-CREE THA, MIDDLE DOT\t# →ᖬᐧ→\n\n167D ;\t15AD 00B7 ;\tMA\t# ( ᙽ → ᖭ· ) CANADIAN SYLLABICS WOODS-CREE THWAA → CANADIAN SYLLABICS TH-CREE THAA, MIDDLE DOT\t# →ᖭᐧ→\n\n2AAB ;\t15D2 ;\tMA\t#* ( ⪫ → ᗒ ) LARGER THAN → CANADIAN SYLLABICS CARRIER WE\t# \n\n2AAA ;\t15D5 ;\tMA\t#* ( ⪪ → ᗕ ) SMALLER THAN → CANADIAN SYLLABICS CARRIER WA\t# \n\nA4F7 ;\t15E1 ;\tMA\t# ( ꓷ → ᗡ ) LISU LETTER OE → CANADIAN SYLLABICS CARRIER THA\t# \n\n18F0 ;\t15F4 00B7 ;\tMA\t# ( ᣰ → ᗴ· ) CANADIAN SYLLABICS CARRIER GWA → CANADIAN SYLLABICS CARRIER GA, MIDDLE DOT\t# →ᗴᐧ→\n\n18F2 ;\t161B 00B7 ;\tMA\t# ( ᣲ → ᘛ· ) CANADIAN SYLLABICS CARRIER JWA → CANADIAN SYLLABICS CARRIER JA, MIDDLE DOT\t# →ᘛᐧ→\n\n1DBB ;\t1646 ;\tMA\t# ( ᶻ → ᙆ ) MODIFIER LETTER SMALL Z → CANADIAN SYLLABICS CARRIER Z\t# \n\nA4ED ;\t1660 ;\tMA\t# ( ꓭ → ᙠ ) LISU LETTER GHA → CANADIAN SYLLABICS CARRIER TSA\t# \n\n1DBA ;\t18D4 ;\tMA\t# ( ᶺ → ᣔ ) MODIFIER LETTER SMALL TURNED V → CANADIAN SYLLABICS OJIBWAY P\t# \n\n1D3E ;\t18D6 ;\tMA\t# ( ᴾ → ᣖ ) MODIFIER LETTER CAPITAL P → CANADIAN SYLLABICS OJIBWAY K\t# \n\n18DC ;\t18DF 141E ;\tMA\t# ( ᣜ → ᣟᐞ ) CANADIAN SYLLABICS EASTERN W → CANADIAN SYLLABICS FINAL RAISED DOT, CANADIAN SYLLABICS GLOTTAL STOP\t# \n\n02E1 ;\t18F3 ;\tMA\t# ( ˡ → ᣳ ) MODIFIER LETTER SMALL L → CANADIAN SYLLABICS BEAVER DENE L\t# \n\n02B3 ;\t18F4 ;\tMA\t# ( ʳ → ᣴ ) MODIFIER LETTER SMALL R → CANADIAN SYLLABICS BEAVER DENE R\t# \n\n02E2 ;\t18F5 ;\tMA\t# ( ˢ → ᣵ ) MODIFIER LETTER SMALL S → CANADIAN SYLLABICS CARRIER DENTAL S\t# \n18DB ;\t18F5 ;\tMA\t# ( ᣛ → ᣵ ) CANADIAN SYLLABICS OJIBWAY SH → CANADIAN SYLLABICS CARRIER DENTAL S\t# →ˢ→\nA7F1 ;\t18F5 ;\tMA\t# ( ꟱ → ᣵ ) MODIFIER LETTER CAPITAL S → CANADIAN SYLLABICS CARRIER DENTAL S\t# →ˢ→\n\nA6B0 ;\t16B9 ;\tMA\t# ( ꚰ → ᚹ ) BAMUM LETTER TAA → RUNIC LETTER WUNJO WYNN W\t# \n\n16E1 ;\t16BC ;\tMA\t# ( ᛡ → ᚼ ) RUNIC LETTER IOR → RUNIC LETTER LONG-BRANCH-HAGALL H\t# \n\n237F ;\t16BD ;\tMA\t#* ( ⍿ → ᚽ ) VERTICAL LINE WITH MIDDLE DOT → RUNIC LETTER SHORT-TWIG-HAGALL H\t# →ᛂ→\n16C2 ;\t16BD ;\tMA\t# ( ᛂ → ᚽ ) RUNIC LETTER E → RUNIC LETTER SHORT-TWIG-HAGALL H\t# \n\n1D23F ;\t16CB ;\tMA\t#* ( 𝈿 → ᛋ ) GREEK INSTRUMENTAL NOTATION SYMBOL-52 → RUNIC LETTER SIGEL LONG-BRANCH-SOL S\t# \n\n2191 ;\t16CF ;\tMA\t#* ( ↑ → ᛏ ) UPWARDS ARROW → RUNIC LETTER TIWAZ TIR TYR T\t# \n\n21BF ;\t16D0 ;\tMA\t#* ( ↿ → ᛐ ) UPWARDS HARPOON WITH BARB LEFTWARDS → RUNIC LETTER SHORT-TWIG-TYR T\t# \n\n296E ;\t16D0 21C2 ;\tMA\t#* ( ⥮ → ᛐ⇂ ) UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT → RUNIC LETTER SHORT-TWIG-TYR T, DOWNWARDS HARPOON WITH BARB RIGHTWARDS\t# →↿⇂→\n\n2963 ;\t16D0 16DA ;\tMA\t#* ( ⥣ → ᛐᛚ ) UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT → RUNIC LETTER SHORT-TWIG-TYR T, RUNIC LETTER LAUKAZ LAGU LOGR L\t# →↿↾→\n\n2D63 ;\t16EF ;\tMA\t# ( ⵣ → ᛯ ) TIFINAGH LETTER YAZ → RUNIC TVIMADUR SYMBOL\t# \n\n21BE ;\t16DA ;\tMA\t#* ( ↾ → ᛚ ) UPWARDS HARPOON WITH BARB RIGHTWARDS → RUNIC LETTER LAUKAZ LAGU LOGR L\t# \n2A21 ;\t16DA ;\tMA\t#* ( ⨡ → ᛚ ) Z NOTATION SCHEMA PROJECTION → RUNIC LETTER LAUKAZ LAGU LOGR L\t# →↾→\n\n22C4 ;\t16DC ;\tMA\t#* ( ⋄ → ᛜ ) DIAMOND OPERATOR → RUNIC LETTER INGWAZ\t# →◇→\n25C7 ;\t16DC ;\tMA\t#* ( ◇ → ᛜ ) WHITE DIAMOND → RUNIC LETTER INGWAZ\t# \n25CA ;\t16DC ;\tMA\t#* ( ◊ → ᛜ ) LOZENGE → RUNIC LETTER INGWAZ\t# →⋄→→◇→\n2662 ;\t16DC ;\tMA\t#* ( ♢ → ᛜ ) WHITE DIAMOND SUIT → RUNIC LETTER INGWAZ\t# →◊→→⋄→→◇→\n1F754 ;\t16DC ;\tMA\t#* ( 🝔 → ᛜ ) ALCHEMICAL SYMBOL FOR SOAP → RUNIC LETTER INGWAZ\t# →◇→\n118B7 ;\t16DC ;\tMA\t# ( 𑢷 → ᛜ ) WARANG CITI CAPITAL LETTER BU → RUNIC LETTER INGWAZ\t# →◇→\n10294 ;\t16DC ;\tMA\t# ( 𐊔 → ᛜ ) LYCIAN LETTER KK → RUNIC LETTER INGWAZ\t# →◇→\n\n235A ;\t16DC 0332 ;\tMA\t#* ( ⍚ → ᛜ̲ ) APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR → RUNIC LETTER INGWAZ, COMBINING LOW LINE\t# →◇̲→\n\n22C8 ;\t16DE ;\tMA\t#* ( ⋈ → ᛞ ) BOWTIE → RUNIC LETTER DAGAZ DAEG D\t# \n2A1D ;\t16DE ;\tMA\t#* ( ⨝ → ᛞ ) JOIN → RUNIC LETTER DAGAZ DAEG D\t# →⋈→\n\n104D0 ;\t16E6 ;\tMA\t# ( 𐓐 → ᛦ ) OSAGE CAPITAL LETTER KHA → RUNIC LETTER LONG-BRANCH-YR\t# \n\n2195 ;\t16E8 ;\tMA\t#* ( ↕ → ᛨ ) UP DOWN ARROW → RUNIC LETTER ICELANDIC-YR\t# \n\n10CFC ;\t10C82 ;\tMA\t#* ( ‎𐳼‎ → ‎𐲂‎ ) OLD HUNGARIAN NUMBER TEN → OLD HUNGARIAN CAPITAL LETTER EB\t# \n\n10CFA ;\t10CA5 ;\tMA\t#* ( ‎𐳺‎ → ‎𐲥‎ ) OLD HUNGARIAN NUMBER ONE → OLD HUNGARIAN CAPITAL LETTER ESZ\t# \n\n3131 ;\t1100 ;\tMA\t# ( ㄱ → ᄀ ) HANGUL LETTER KIYEOK → HANGUL CHOSEONG KIYEOK\t# \n11A8 ;\t1100 ;\tMA\t# ( ᆨ → ᄀ ) HANGUL JONGSEONG KIYEOK → HANGUL CHOSEONG KIYEOK\t# \n\n1101 ;\t1100 1100 ;\tMA\t# ( ᄁ → ᄀᄀ ) HANGUL CHOSEONG SSANGKIYEOK → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG KIYEOK\t# \n3132 ;\t1100 1100 ;\tMA\t# ( ㄲ → ᄀᄀ ) HANGUL LETTER SSANGKIYEOK → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG KIYEOK\t# →ᄁ→\n11A9 ;\t1100 1100 ;\tMA\t# ( ᆩ → ᄀᄀ ) HANGUL JONGSEONG SSANGKIYEOK → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG KIYEOK\t# →ᄁ→\n\n11FA ;\t1100 1102 ;\tMA\t# ( ᇺ → ᄀᄂ ) HANGUL JONGSEONG KIYEOK-NIEUN → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG NIEUN\t# →ᆨᆫ→\n\n115A ;\t1100 1103 ;\tMA\t# ( ᅚ → ᄀᄃ ) HANGUL CHOSEONG KIYEOK-TIKEUT → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG TIKEUT\t# \n\n11C3 ;\t1100 1105 ;\tMA\t# ( ᇃ → ᄀᄅ ) HANGUL JONGSEONG KIYEOK-RIEUL → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG RIEUL\t# →ᆨᆯ→\n\n11FB ;\t1100 1107 ;\tMA\t# ( ᇻ → ᄀᄇ ) HANGUL JONGSEONG KIYEOK-PIEUP → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG PIEUP\t# →ᆨᆸ→\n\n11AA ;\t1100 1109 ;\tMA\t# ( ᆪ → ᄀᄉ ) HANGUL JONGSEONG KIYEOK-SIOS → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG SIOS\t# →ᆨᆺ→\n3133 ;\t1100 1109 ;\tMA\t# ( ㄳ → ᄀᄉ ) HANGUL LETTER KIYEOK-SIOS → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG SIOS\t# →ᆪ→→ᆨᆺ→\n\n11C4 ;\t1100 1109 1100 ;\tMA\t# ( ᇄ → ᄀᄉᄀ ) HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KIYEOK\t# →ᆨᆺᆨ→\n\n11FC ;\t1100 110E ;\tMA\t# ( ᇼ → ᄀᄎ ) HANGUL JONGSEONG KIYEOK-CHIEUCH → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG CHIEUCH\t# →ᆨᆾ→\n\n11FD ;\t1100 110F ;\tMA\t# ( ᇽ → ᄀᄏ ) HANGUL JONGSEONG KIYEOK-KHIEUKH → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG KHIEUKH\t# →ᆨᆿ→\n\n11FE ;\t1100 1112 ;\tMA\t# ( ᇾ → ᄀᄒ ) HANGUL JONGSEONG KIYEOK-HIEUH → HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG HIEUH\t# →ᆨᇂ→\n\n3134 ;\t1102 ;\tMA\t# ( ㄴ → ᄂ ) HANGUL LETTER NIEUN → HANGUL CHOSEONG NIEUN\t# \n11AB ;\t1102 ;\tMA\t# ( ᆫ → ᄂ ) HANGUL JONGSEONG NIEUN → HANGUL CHOSEONG NIEUN\t# \n\n1113 ;\t1102 1100 ;\tMA\t# ( ᄓ → ᄂᄀ ) HANGUL CHOSEONG NIEUN-KIYEOK → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG KIYEOK\t# \n11C5 ;\t1102 1100 ;\tMA\t# ( ᇅ → ᄂᄀ ) HANGUL JONGSEONG NIEUN-KIYEOK → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG KIYEOK\t# →ᄓ→\n\n1114 ;\t1102 1102 ;\tMA\t# ( ᄔ → ᄂᄂ ) HANGUL CHOSEONG SSANGNIEUN → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG NIEUN\t# \n3165 ;\t1102 1102 ;\tMA\t# ( ㅥ → ᄂᄂ ) HANGUL LETTER SSANGNIEUN → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG NIEUN\t# →ᄔ→\n11FF ;\t1102 1102 ;\tMA\t# ( ᇿ → ᄂᄂ ) HANGUL JONGSEONG SSANGNIEUN → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG NIEUN\t# →ᆫᆫ→\n\n1115 ;\t1102 1103 ;\tMA\t# ( ᄕ → ᄂᄃ ) HANGUL CHOSEONG NIEUN-TIKEUT → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG TIKEUT\t# \n3166 ;\t1102 1103 ;\tMA\t# ( ㅦ → ᄂᄃ ) HANGUL LETTER NIEUN-TIKEUT → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG TIKEUT\t# →ᄕ→\n11C6 ;\t1102 1103 ;\tMA\t# ( ᇆ → ᄂᄃ ) HANGUL JONGSEONG NIEUN-TIKEUT → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG TIKEUT\t# →ᄕ→\n\nD7CB ;\t1102 1105 ;\tMA\t# ( ퟋ → ᄂᄅ ) HANGUL JONGSEONG NIEUN-RIEUL → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG RIEUL\t# →ᆫᆯ→\n\n1116 ;\t1102 1107 ;\tMA\t# ( ᄖ → ᄂᄇ ) HANGUL CHOSEONG NIEUN-PIEUP → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG PIEUP\t# \n\n115B ;\t1102 1109 ;\tMA\t# ( ᅛ → ᄂᄉ ) HANGUL CHOSEONG NIEUN-SIOS → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG SIOS\t# \n11C7 ;\t1102 1109 ;\tMA\t# ( ᇇ → ᄂᄉ ) HANGUL JONGSEONG NIEUN-SIOS → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG SIOS\t# →ᆫᆺ→\n3167 ;\t1102 1109 ;\tMA\t# ( ㅧ → ᄂᄉ ) HANGUL LETTER NIEUN-SIOS → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG SIOS\t# →ᇇ→→ᆫᆺ→\n\n115C ;\t1102 110C ;\tMA\t# ( ᅜ → ᄂᄌ ) HANGUL CHOSEONG NIEUN-CIEUC → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG CIEUC\t# \n11AC ;\t1102 110C ;\tMA\t# ( ᆬ → ᄂᄌ ) HANGUL JONGSEONG NIEUN-CIEUC → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG CIEUC\t# →ᆫᆽ→\n3135 ;\t1102 110C ;\tMA\t# ( ㄵ → ᄂᄌ ) HANGUL LETTER NIEUN-CIEUC → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG CIEUC\t# →ᆬ→→ᆫᆽ→\n\nD7CC ;\t1102 110E ;\tMA\t# ( ퟌ → ᄂᄎ ) HANGUL JONGSEONG NIEUN-CHIEUCH → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG CHIEUCH\t# →ᆫᆾ→\n\n11C9 ;\t1102 1110 ;\tMA\t# ( ᇉ → ᄂᄐ ) HANGUL JONGSEONG NIEUN-THIEUTH → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG THIEUTH\t# →ᆫᇀ→\n\n115D ;\t1102 1112 ;\tMA\t# ( ᅝ → ᄂᄒ ) HANGUL CHOSEONG NIEUN-HIEUH → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG HIEUH\t# \n11AD ;\t1102 1112 ;\tMA\t# ( ᆭ → ᄂᄒ ) HANGUL JONGSEONG NIEUN-HIEUH → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG HIEUH\t# →ᆫᇂ→\n3136 ;\t1102 1112 ;\tMA\t# ( ㄶ → ᄂᄒ ) HANGUL LETTER NIEUN-HIEUH → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG HIEUH\t# →ᆭ→→ᆫᇂ→\n\n11C8 ;\t1102 1140 ;\tMA\t# ( ᇈ → ᄂᅀ ) HANGUL JONGSEONG NIEUN-PANSIOS → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG PANSIOS\t# →ᆫᇫ→\n3168 ;\t1102 1140 ;\tMA\t# ( ㅨ → ᄂᅀ ) HANGUL LETTER NIEUN-PANSIOS → HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG PANSIOS\t# →ᇈ→→ᆫᇫ→\n\n723F ;\t1102 116E 4E28 ;\tMA\t# ( 爿 → 누丨 ) CJK UNIFIED IDEOGRAPH-723F → HANGUL CHOSEONG NIEUN, HANGUL JUNGSEONG U, CJK UNIFIED IDEOGRAPH-4E28\t# →뉘→→누ᅵ→\n2F59 ;\t1102 116E 4E28 ;\tMA\t#* ( ⽙ → 누丨 ) KANGXI RADICAL HALF TREE TRUNK → HANGUL CHOSEONG NIEUN, HANGUL JUNGSEONG U, CJK UNIFIED IDEOGRAPH-4E28\t# →爿→→뉘→→누ᅵ→\n\n3137 ;\t1103 ;\tMA\t# ( ㄷ → ᄃ ) HANGUL LETTER TIKEUT → HANGUL CHOSEONG TIKEUT\t# \n11AE ;\t1103 ;\tMA\t# ( ᆮ → ᄃ ) HANGUL JONGSEONG TIKEUT → HANGUL CHOSEONG TIKEUT\t# \n\n1117 ;\t1103 1100 ;\tMA\t# ( ᄗ → ᄃᄀ ) HANGUL CHOSEONG TIKEUT-KIYEOK → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG KIYEOK\t# \n11CA ;\t1103 1100 ;\tMA\t# ( ᇊ → ᄃᄀ ) HANGUL JONGSEONG TIKEUT-KIYEOK → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG KIYEOK\t# →ᄗ→\n\n1104 ;\t1103 1103 ;\tMA\t# ( ᄄ → ᄃᄃ ) HANGUL CHOSEONG SSANGTIKEUT → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG TIKEUT\t# \n3138 ;\t1103 1103 ;\tMA\t# ( ㄸ → ᄃᄃ ) HANGUL LETTER SSANGTIKEUT → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG TIKEUT\t# →ᄄ→\nD7CD ;\t1103 1103 ;\tMA\t# ( ퟍ → ᄃᄃ ) HANGUL JONGSEONG SSANGTIKEUT → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG TIKEUT\t# →ᆮᆮ→\n\nD7CE ;\t1103 1103 1107 ;\tMA\t# ( ퟎ → ᄃᄃᄇ ) HANGUL JONGSEONG SSANGTIKEUT-PIEUP → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG PIEUP\t# →ᆮᆮᆸ→\n\n115E ;\t1103 1105 ;\tMA\t# ( ᅞ → ᄃᄅ ) HANGUL CHOSEONG TIKEUT-RIEUL → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG RIEUL\t# \n11CB ;\t1103 1105 ;\tMA\t# ( ᇋ → ᄃᄅ ) HANGUL JONGSEONG TIKEUT-RIEUL → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG RIEUL\t# →ᆮᆯ→\n\nA960 ;\t1103 1106 ;\tMA\t# ( ꥠ → ᄃᄆ ) HANGUL CHOSEONG TIKEUT-MIEUM → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG MIEUM\t# \n\nA961 ;\t1103 1107 ;\tMA\t# ( ꥡ → ᄃᄇ ) HANGUL CHOSEONG TIKEUT-PIEUP → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG PIEUP\t# \nD7CF ;\t1103 1107 ;\tMA\t# ( ퟏ → ᄃᄇ ) HANGUL JONGSEONG TIKEUT-PIEUP → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG PIEUP\t# →ᆮᆸ→\n\nA962 ;\t1103 1109 ;\tMA\t# ( ꥢ → ᄃᄉ ) HANGUL CHOSEONG TIKEUT-SIOS → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG SIOS\t# \nD7D0 ;\t1103 1109 ;\tMA\t# ( ퟐ → ᄃᄉ ) HANGUL JONGSEONG TIKEUT-SIOS → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG SIOS\t# →ᆮᆺ→\n\nD7D1 ;\t1103 1109 1100 ;\tMA\t# ( ퟑ → ᄃᄉᄀ ) HANGUL JONGSEONG TIKEUT-SIOS-KIYEOK → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KIYEOK\t# →ᆮᆺᆨ→\n\nA963 ;\t1103 110C ;\tMA\t# ( ꥣ → ᄃᄌ ) HANGUL CHOSEONG TIKEUT-CIEUC → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG CIEUC\t# \nD7D2 ;\t1103 110C ;\tMA\t# ( ퟒ → ᄃᄌ ) HANGUL JONGSEONG TIKEUT-CIEUC → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG CIEUC\t# →ᆮᆽ→\n\nD7D3 ;\t1103 110E ;\tMA\t# ( ퟓ → ᄃᄎ ) HANGUL JONGSEONG TIKEUT-CHIEUCH → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG CHIEUCH\t# →ᆮᆾ→\n\nD7D4 ;\t1103 1110 ;\tMA\t# ( ퟔ → ᄃᄐ ) HANGUL JONGSEONG TIKEUT-THIEUTH → HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG THIEUTH\t# →ᆮᇀ→\n\n3139 ;\t1105 ;\tMA\t# ( ㄹ → ᄅ ) HANGUL LETTER RIEUL → HANGUL CHOSEONG RIEUL\t# \n11AF ;\t1105 ;\tMA\t# ( ᆯ → ᄅ ) HANGUL JONGSEONG RIEUL → HANGUL CHOSEONG RIEUL\t# \n\nA964 ;\t1105 1100 ;\tMA\t# ( ꥤ → ᄅᄀ ) HANGUL CHOSEONG RIEUL-KIYEOK → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KIYEOK\t# \n11B0 ;\t1105 1100 ;\tMA\t# ( ᆰ → ᄅᄀ ) HANGUL JONGSEONG RIEUL-KIYEOK → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KIYEOK\t# →ᆯᆨ→\n313A ;\t1105 1100 ;\tMA\t# ( ㄺ → ᄅᄀ ) HANGUL LETTER RIEUL-KIYEOK → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KIYEOK\t# →ᆰ→→ᆯᆨ→\n\nA965 ;\t1105 1100 1100 ;\tMA\t# ( ꥥ → ᄅᄀᄀ ) HANGUL CHOSEONG RIEUL-SSANGKIYEOK → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG KIYEOK\t# \nD7D5 ;\t1105 1100 1100 ;\tMA\t# ( ퟕ → ᄅᄀᄀ ) HANGUL JONGSEONG RIEUL-SSANGKIYEOK → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG KIYEOK\t# →ᆯᆨᆨ→\n\n11CC ;\t1105 1100 1109 ;\tMA\t# ( ᇌ → ᄅᄀᄉ ) HANGUL JONGSEONG RIEUL-KIYEOK-SIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG SIOS\t# →ᆯᆨᆺ→\n3169 ;\t1105 1100 1109 ;\tMA\t# ( ㅩ → ᄅᄀᄉ ) HANGUL LETTER RIEUL-KIYEOK-SIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG SIOS\t# →ᇌ→→ᆯᆨᆺ→\n\nD7D6 ;\t1105 1100 1112 ;\tMA\t# ( ퟖ → ᄅᄀᄒ ) HANGUL JONGSEONG RIEUL-KIYEOK-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG HIEUH\t# →ᆯᆨᇂ→\n\n1118 ;\t1105 1102 ;\tMA\t# ( ᄘ → ᄅᄂ ) HANGUL CHOSEONG RIEUL-NIEUN → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG NIEUN\t# \n11CD ;\t1105 1102 ;\tMA\t# ( ᇍ → ᄅᄂ ) HANGUL JONGSEONG RIEUL-NIEUN → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG NIEUN\t# →ᄘ→\n\nA966 ;\t1105 1103 ;\tMA\t# ( ꥦ → ᄅᄃ ) HANGUL CHOSEONG RIEUL-TIKEUT → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG TIKEUT\t# \n11CE ;\t1105 1103 ;\tMA\t# ( ᇎ → ᄅᄃ ) HANGUL JONGSEONG RIEUL-TIKEUT → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG TIKEUT\t# →ᆯᆮ→\n316A ;\t1105 1103 ;\tMA\t# ( ㅪ → ᄅᄃ ) HANGUL LETTER RIEUL-TIKEUT → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG TIKEUT\t# →ᇎ→→ᆯᆮ→\n\nA967 ;\t1105 1103 1103 ;\tMA\t# ( ꥧ → ᄅᄃᄃ ) HANGUL CHOSEONG RIEUL-SSANGTIKEUT → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG TIKEUT\t# \n\n11CF ;\t1105 1103 1112 ;\tMA\t# ( ᇏ → ᄅᄃᄒ ) HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG TIKEUT, HANGUL CHOSEONG HIEUH\t# →ᆯᆮᇂ→\n\n1119 ;\t1105 1105 ;\tMA\t# ( ᄙ → ᄅᄅ ) HANGUL CHOSEONG SSANGRIEUL → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG RIEUL\t# \n11D0 ;\t1105 1105 ;\tMA\t# ( ᇐ → ᄅᄅ ) HANGUL JONGSEONG SSANGRIEUL → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG RIEUL\t# →ᄙ→\n\nD7D7 ;\t1105 1105 110F ;\tMA\t# ( ퟗ → ᄅᄅᄏ ) HANGUL JONGSEONG SSANGRIEUL-KHIEUKH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KHIEUKH\t# →ᆯᆯᆿ→\n\nA968 ;\t1105 1106 ;\tMA\t# ( ꥨ → ᄅᄆ ) HANGUL CHOSEONG RIEUL-MIEUM → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG MIEUM\t# \n11B1 ;\t1105 1106 ;\tMA\t# ( ᆱ → ᄅᄆ ) HANGUL JONGSEONG RIEUL-MIEUM → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG MIEUM\t# →ᆯᆷ→\n313B ;\t1105 1106 ;\tMA\t# ( ㄻ → ᄅᄆ ) HANGUL LETTER RIEUL-MIEUM → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG MIEUM\t# →ᆱ→→ᆯᆷ→\n\n11D1 ;\t1105 1106 1100 ;\tMA\t# ( ᇑ → ᄅᄆᄀ ) HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG KIYEOK\t# →ᆯᆷᆨ→\n\n11D2 ;\t1105 1106 1109 ;\tMA\t# ( ᇒ → ᄅᄆᄉ ) HANGUL JONGSEONG RIEUL-MIEUM-SIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG SIOS\t# →ᆯᆷᆺ→\n\nD7D8 ;\t1105 1106 1112 ;\tMA\t# ( ퟘ → ᄅᄆᄒ ) HANGUL JONGSEONG RIEUL-MIEUM-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG HIEUH\t# →ᆯᆷᇂ→\n\nA969 ;\t1105 1107 ;\tMA\t# ( ꥩ → ᄅᄇ ) HANGUL CHOSEONG RIEUL-PIEUP → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP\t# \n11B2 ;\t1105 1107 ;\tMA\t# ( ᆲ → ᄅᄇ ) HANGUL JONGSEONG RIEUL-PIEUP → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP\t# →ᆯᆸ→\n313C ;\t1105 1107 ;\tMA\t# ( ㄼ → ᄅᄇ ) HANGUL LETTER RIEUL-PIEUP → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP\t# →ᆲ→→ᆯᆸ→\n\nD7D9 ;\t1105 1107 1103 ;\tMA\t# ( ퟙ → ᄅᄇᄃ ) HANGUL JONGSEONG RIEUL-PIEUP-TIKEUT → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG TIKEUT\t# →ᆯᆸᆮ→\n\nA96A ;\t1105 1107 1107 ;\tMA\t# ( ꥪ → ᄅᄇᄇ ) HANGUL CHOSEONG RIEUL-SSANGPIEUP → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PIEUP\t# \n\n11D3 ;\t1105 1107 1109 ;\tMA\t# ( ᇓ → ᄅᄇᄉ ) HANGUL JONGSEONG RIEUL-PIEUP-SIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS\t# →ᆯᆸᆺ→\n316B ;\t1105 1107 1109 ;\tMA\t# ( ㅫ → ᄅᄇᄉ ) HANGUL LETTER RIEUL-PIEUP-SIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS\t# →ᇓ→→ᆯᆸᆺ→\n\nA96B ;\t1105 1107 110B ;\tMA\t# ( ꥫ → ᄅᄇᄋ ) HANGUL CHOSEONG RIEUL-KAPYEOUNPIEUP → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# \n11D5 ;\t1105 1107 110B ;\tMA\t# ( ᇕ → ᄅᄇᄋ ) HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# →ᆯᆸᆼ→\n\nD7DA ;\t1105 1107 1111 ;\tMA\t# ( ퟚ → ᄅᄇᄑ ) HANGUL JONGSEONG RIEUL-PIEUP-PHIEUPH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PHIEUPH\t# →ᆯᆸᇁ→\n\n11D4 ;\t1105 1107 1112 ;\tMA\t# ( ᇔ → ᄅᄇᄒ ) HANGUL JONGSEONG RIEUL-PIEUP-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG HIEUH\t# →ᆯᆸᇂ→\n\nA96C ;\t1105 1109 ;\tMA\t# ( ꥬ → ᄅᄉ ) HANGUL CHOSEONG RIEUL-SIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG SIOS\t# \n11B3 ;\t1105 1109 ;\tMA\t# ( ᆳ → ᄅᄉ ) HANGUL JONGSEONG RIEUL-SIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG SIOS\t# →ᆯᆺ→\n313D ;\t1105 1109 ;\tMA\t# ( ㄽ → ᄅᄉ ) HANGUL LETTER RIEUL-SIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG SIOS\t# →ᆳ→→ᆯᆺ→\n\n11D6 ;\t1105 1109 1109 ;\tMA\t# ( ᇖ → ᄅᄉᄉ ) HANGUL JONGSEONG RIEUL-SSANGSIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS\t# →ᆯᆺᆺ→\n\n111B ;\t1105 110B ;\tMA\t# ( ᄛ → ᄅᄋ ) HANGUL CHOSEONG KAPYEOUNRIEUL → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG IEUNG\t# \nD7DD ;\t1105 110B ;\tMA\t# ( ퟝ → ᄅᄋ ) HANGUL JONGSEONG KAPYEOUNRIEUL → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG IEUNG\t# →ᆯᆼ→\n\nA96D ;\t1105 110C ;\tMA\t# ( ꥭ → ᄅᄌ ) HANGUL CHOSEONG RIEUL-CIEUC → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG CIEUC\t# \n\nA96E ;\t1105 110F ;\tMA\t# ( ꥮ → ᄅᄏ ) HANGUL CHOSEONG RIEUL-KHIEUKH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KHIEUKH\t# \n11D8 ;\t1105 110F ;\tMA\t# ( ᇘ → ᄅᄏ ) HANGUL JONGSEONG RIEUL-KHIEUKH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG KHIEUKH\t# →ᆯᆿ→\n\n11B4 ;\t1105 1110 ;\tMA\t# ( ᆴ → ᄅᄐ ) HANGUL JONGSEONG RIEUL-THIEUTH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG THIEUTH\t# →ᆯᇀ→\n313E ;\t1105 1110 ;\tMA\t# ( ㄾ → ᄅᄐ ) HANGUL LETTER RIEUL-THIEUTH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG THIEUTH\t# →ᆴ→→ᆯᇀ→\n\n11B5 ;\t1105 1111 ;\tMA\t# ( ᆵ → ᄅᄑ ) HANGUL JONGSEONG RIEUL-PHIEUPH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PHIEUPH\t# →ᆯᇁ→\n313F ;\t1105 1111 ;\tMA\t# ( ㄿ → ᄅᄑ ) HANGUL LETTER RIEUL-PHIEUPH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PHIEUPH\t# →ᆵ→→ᆯᇁ→\n\n111A ;\t1105 1112 ;\tMA\t# ( ᄚ → ᄅᄒ ) HANGUL CHOSEONG RIEUL-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG HIEUH\t# \n3140 ;\t1105 1112 ;\tMA\t# ( ㅀ → ᄅᄒ ) HANGUL LETTER RIEUL-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG HIEUH\t# →ᄚ→\n113B ;\t1105 1112 ;\tMA\t# ( ᄻ → ᄅᄒ ) HANGUL CHOSEONG SIOS-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG HIEUH\t# →ᄚ→\n11B6 ;\t1105 1112 ;\tMA\t# ( ᆶ → ᄅᄒ ) HANGUL JONGSEONG RIEUL-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG HIEUH\t# →ᄚ→\nD7F2 ;\t1105 1112 ;\tMA\t# ( ퟲ → ᄅᄒ ) HANGUL JONGSEONG SIOS-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG HIEUH\t# →ᆺᇂ→→ᄉᄒ→→ᄻ→→ᄚ→\n\n11D7 ;\t1105 1140 ;\tMA\t# ( ᇗ → ᄅᅀ ) HANGUL JONGSEONG RIEUL-PANSIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PANSIOS\t# →ᆯᇫ→\n316C ;\t1105 1140 ;\tMA\t# ( ㅬ → ᄅᅀ ) HANGUL LETTER RIEUL-PANSIOS → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PANSIOS\t# →ᇗ→→ᆯᇫ→\n\nD7DB ;\t1105 114C ;\tMA\t# ( ퟛ → ᄅᅌ ) HANGUL JONGSEONG RIEUL-YESIEUNG → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG YESIEUNG\t# →ᆯᇰ→\n\n11D9 ;\t1105 1159 ;\tMA\t# ( ᇙ → ᄅᅙ ) HANGUL JONGSEONG RIEUL-YEORINHIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG YEORINHIEUH\t# →ᆯᇹ→\n316D ;\t1105 1159 ;\tMA\t# ( ㅭ → ᄅᅙ ) HANGUL LETTER RIEUL-YEORINHIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG YEORINHIEUH\t# →ᇙ→→ᆯᇹ→\n\nD7DC ;\t1105 1159 1112 ;\tMA\t# ( ퟜ → ᄅᅙᄒ ) HANGUL JONGSEONG RIEUL-YEORINHIEUH-HIEUH → HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG YEORINHIEUH, HANGUL CHOSEONG HIEUH\t# →ᆯᇹᇂ→\n\n3141 ;\t1106 ;\tMA\t# ( ㅁ → ᄆ ) HANGUL LETTER MIEUM → HANGUL CHOSEONG MIEUM\t# \n11B7 ;\t1106 ;\tMA\t# ( ᆷ → ᄆ ) HANGUL JONGSEONG MIEUM → HANGUL CHOSEONG MIEUM\t# \n\nA96F ;\t1106 1100 ;\tMA\t# ( ꥯ → ᄆᄀ ) HANGUL CHOSEONG MIEUM-KIYEOK → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG KIYEOK\t# \n11DA ;\t1106 1100 ;\tMA\t# ( ᇚ → ᄆᄀ ) HANGUL JONGSEONG MIEUM-KIYEOK → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG KIYEOK\t# →ᆷᆨ→\n\nD7DE ;\t1106 1102 ;\tMA\t# ( ퟞ → ᄆᄂ ) HANGUL JONGSEONG MIEUM-NIEUN → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG NIEUN\t# →ᆷᆫ→\n\nD7DF ;\t1106 1102 1102 ;\tMA\t# ( ퟟ → ᄆᄂᄂ ) HANGUL JONGSEONG MIEUM-SSANGNIEUN → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG NIEUN\t# →ᆷᆫᆫ→\n\nA970 ;\t1106 1103 ;\tMA\t# ( ꥰ → ᄆᄃ ) HANGUL CHOSEONG MIEUM-TIKEUT → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG TIKEUT\t# \n\n11DB ;\t1106 1105 ;\tMA\t# ( ᇛ → ᄆᄅ ) HANGUL JONGSEONG MIEUM-RIEUL → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG RIEUL\t# →ᆷᆯ→\n\nD7E0 ;\t1106 1106 ;\tMA\t# ( ퟠ → ᄆᄆ ) HANGUL JONGSEONG SSANGMIEUM → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG MIEUM\t# →ᆷᆷ→\n\n111C ;\t1106 1107 ;\tMA\t# ( ᄜ → ᄆᄇ ) HANGUL CHOSEONG MIEUM-PIEUP → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG PIEUP\t# \n316E ;\t1106 1107 ;\tMA\t# ( ㅮ → ᄆᄇ ) HANGUL LETTER MIEUM-PIEUP → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG PIEUP\t# →ᄜ→\n11DC ;\t1106 1107 ;\tMA\t# ( ᇜ → ᄆᄇ ) HANGUL JONGSEONG MIEUM-PIEUP → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG PIEUP\t# →ᄜ→\n\nD7E1 ;\t1106 1107 1109 ;\tMA\t# ( ퟡ → ᄆᄇᄉ ) HANGUL JONGSEONG MIEUM-PIEUP-SIOS → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS\t# →ᆷᆸᆺ→\n\nA971 ;\t1106 1109 ;\tMA\t# ( ꥱ → ᄆᄉ ) HANGUL CHOSEONG MIEUM-SIOS → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG SIOS\t# \n11DD ;\t1106 1109 ;\tMA\t# ( ᇝ → ᄆᄉ ) HANGUL JONGSEONG MIEUM-SIOS → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG SIOS\t# →ᆷᆺ→\n316F ;\t1106 1109 ;\tMA\t# ( ㅯ → ᄆᄉ ) HANGUL LETTER MIEUM-SIOS → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG SIOS\t# →ᇝ→→ᆷᆺ→\n\n11DE ;\t1106 1109 1109 ;\tMA\t# ( ᇞ → ᄆᄉᄉ ) HANGUL JONGSEONG MIEUM-SSANGSIOS → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS\t# →ᆷᆺᆺ→\n\n111D ;\t1106 110B ;\tMA\t# ( ᄝ → ᄆᄋ ) HANGUL CHOSEONG KAPYEOUNMIEUM → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG IEUNG\t# \n3171 ;\t1106 110B ;\tMA\t# ( ㅱ → ᄆᄋ ) HANGUL LETTER KAPYEOUNMIEUM → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG IEUNG\t# →ᄝ→\n11E2 ;\t1106 110B ;\tMA\t# ( ᇢ → ᄆᄋ ) HANGUL JONGSEONG KAPYEOUNMIEUM → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG IEUNG\t# →ᄝ→\n\nD7E2 ;\t1106 110C ;\tMA\t# ( ퟢ → ᄆᄌ ) HANGUL JONGSEONG MIEUM-CIEUC → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG CIEUC\t# →ᆷᆽ→\n\n11E0 ;\t1106 110E ;\tMA\t# ( ᇠ → ᄆᄎ ) HANGUL JONGSEONG MIEUM-CHIEUCH → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG CHIEUCH\t# →ᆷᆾ→\n\n11E1 ;\t1106 1112 ;\tMA\t# ( ᇡ → ᄆᄒ ) HANGUL JONGSEONG MIEUM-HIEUH → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG HIEUH\t# →ᆷᇂ→\n\n11DF ;\t1106 1140 ;\tMA\t# ( ᇟ → ᄆᅀ ) HANGUL JONGSEONG MIEUM-PANSIOS → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG PANSIOS\t# →ᆷᇫ→\n3170 ;\t1106 1140 ;\tMA\t# ( ㅰ → ᄆᅀ ) HANGUL LETTER MIEUM-PANSIOS → HANGUL CHOSEONG MIEUM, HANGUL CHOSEONG PANSIOS\t# →ᇟ→→ᆷᇫ→\n\n535F ;\t1106 1161 ;\tMA\t# ( 卟 → 마 ) CJK UNIFIED IDEOGRAPH-535F → HANGUL CHOSEONG MIEUM, HANGUL JUNGSEONG A\t# \n\n3142 ;\t1107 ;\tMA\t# ( ㅂ → ᄇ ) HANGUL LETTER PIEUP → HANGUL CHOSEONG PIEUP\t# \n11B8 ;\t1107 ;\tMA\t# ( ᆸ → ᄇ ) HANGUL JONGSEONG PIEUP → HANGUL CHOSEONG PIEUP\t# \n\n111E ;\t1107 1100 ;\tMA\t# ( ᄞ → ᄇᄀ ) HANGUL CHOSEONG PIEUP-KIYEOK → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG KIYEOK\t# \n3172 ;\t1107 1100 ;\tMA\t# ( ㅲ → ᄇᄀ ) HANGUL LETTER PIEUP-KIYEOK → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG KIYEOK\t# →ᄞ→\n\n111F ;\t1107 1102 ;\tMA\t# ( ᄟ → ᄇᄂ ) HANGUL CHOSEONG PIEUP-NIEUN → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG NIEUN\t# \n\n1120 ;\t1107 1103 ;\tMA\t# ( ᄠ → ᄇᄃ ) HANGUL CHOSEONG PIEUP-TIKEUT → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG TIKEUT\t# \n3173 ;\t1107 1103 ;\tMA\t# ( ㅳ → ᄇᄃ ) HANGUL LETTER PIEUP-TIKEUT → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG TIKEUT\t# →ᄠ→\nD7E3 ;\t1107 1103 ;\tMA\t# ( ퟣ → ᄇᄃ ) HANGUL JONGSEONG PIEUP-TIKEUT → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG TIKEUT\t# →ᆸᆮ→\n\n11E3 ;\t1107 1105 ;\tMA\t# ( ᇣ → ᄇᄅ ) HANGUL JONGSEONG PIEUP-RIEUL → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG RIEUL\t# →ᆸᆯ→\n\nD7E4 ;\t1107 1105 1111 ;\tMA\t# ( ퟤ → ᄇᄅᄑ ) HANGUL JONGSEONG PIEUP-RIEUL-PHIEUPH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG RIEUL, HANGUL CHOSEONG PHIEUPH\t# →ᆸᆯᇁ→\n\nD7E5 ;\t1107 1106 ;\tMA\t# ( ퟥ → ᄇᄆ ) HANGUL JONGSEONG PIEUP-MIEUM → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG MIEUM\t# →ᆸᆷ→\n\n1108 ;\t1107 1107 ;\tMA\t# ( ᄈ → ᄇᄇ ) HANGUL CHOSEONG SSANGPIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PIEUP\t# \n3143 ;\t1107 1107 ;\tMA\t# ( ㅃ → ᄇᄇ ) HANGUL LETTER SSANGPIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PIEUP\t# →ᄈ→\nD7E6 ;\t1107 1107 ;\tMA\t# ( ퟦ → ᄇᄇ ) HANGUL JONGSEONG SSANGPIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PIEUP\t# →ᆸᆸ→\n\n112C ;\t1107 1107 110B ;\tMA\t# ( ᄬ → ᄇᄇᄋ ) HANGUL CHOSEONG KAPYEOUNSSANGPIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# \n3179 ;\t1107 1107 110B ;\tMA\t# ( ㅹ → ᄇᄇᄋ ) HANGUL LETTER KAPYEOUNSSANGPIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# →ᄬ→\n\n1121 ;\t1107 1109 ;\tMA\t# ( ᄡ → ᄇᄉ ) HANGUL CHOSEONG PIEUP-SIOS → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS\t# \n3144 ;\t1107 1109 ;\tMA\t# ( ㅄ → ᄇᄉ ) HANGUL LETTER PIEUP-SIOS → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS\t# →ᄡ→\n11B9 ;\t1107 1109 ;\tMA\t# ( ᆹ → ᄇᄉ ) HANGUL JONGSEONG PIEUP-SIOS → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS\t# →ᄡ→\n\n1122 ;\t1107 1109 1100 ;\tMA\t# ( ᄢ → ᄇᄉᄀ ) HANGUL CHOSEONG PIEUP-SIOS-KIYEOK → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KIYEOK\t# \n3174 ;\t1107 1109 1100 ;\tMA\t# ( ㅴ → ᄇᄉᄀ ) HANGUL LETTER PIEUP-SIOS-KIYEOK → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KIYEOK\t# →ᄢ→\n\n1123 ;\t1107 1109 1103 ;\tMA\t# ( ᄣ → ᄇᄉᄃ ) HANGUL CHOSEONG PIEUP-SIOS-TIKEUT → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG TIKEUT\t# \n3175 ;\t1107 1109 1103 ;\tMA\t# ( ㅵ → ᄇᄉᄃ ) HANGUL LETTER PIEUP-SIOS-TIKEUT → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG TIKEUT\t# →ᄣ→\nD7E7 ;\t1107 1109 1103 ;\tMA\t# ( ퟧ → ᄇᄉᄃ ) HANGUL JONGSEONG PIEUP-SIOS-TIKEUT → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG TIKEUT\t# →ᆸᆺᆮ→\n\n1124 ;\t1107 1109 1107 ;\tMA\t# ( ᄤ → ᄇᄉᄇ ) HANGUL CHOSEONG PIEUP-SIOS-PIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PIEUP\t# \n\n1125 ;\t1107 1109 1109 ;\tMA\t# ( ᄥ → ᄇᄉᄉ ) HANGUL CHOSEONG PIEUP-SSANGSIOS → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS\t# \n\n1126 ;\t1107 1109 110C ;\tMA\t# ( ᄦ → ᄇᄉᄌ ) HANGUL CHOSEONG PIEUP-SIOS-CIEUC → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG CIEUC\t# \n\nA972 ;\t1107 1109 1110 ;\tMA\t# ( ꥲ → ᄇᄉᄐ ) HANGUL CHOSEONG PIEUP-SIOS-THIEUTH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG THIEUTH\t# \n\n112B ;\t1107 110B ;\tMA\t# ( ᄫ → ᄇᄋ ) HANGUL CHOSEONG KAPYEOUNPIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# \n3178 ;\t1107 110B ;\tMA\t# ( ㅸ → ᄇᄋ ) HANGUL LETTER KAPYEOUNPIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# →ᄫ→\n11E6 ;\t1107 110B ;\tMA\t# ( ᇦ → ᄇᄋ ) HANGUL JONGSEONG KAPYEOUNPIEUP → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# →ᄫ→\n\n1127 ;\t1107 110C ;\tMA\t# ( ᄧ → ᄇᄌ ) HANGUL CHOSEONG PIEUP-CIEUC → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG CIEUC\t# \n3176 ;\t1107 110C ;\tMA\t# ( ㅶ → ᄇᄌ ) HANGUL LETTER PIEUP-CIEUC → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG CIEUC\t# →ᄧ→\nD7E8 ;\t1107 110C ;\tMA\t# ( ퟨ → ᄇᄌ ) HANGUL JONGSEONG PIEUP-CIEUC → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG CIEUC\t# →ᆸᆽ→\n\n1128 ;\t1107 110E ;\tMA\t# ( ᄨ → ᄇᄎ ) HANGUL CHOSEONG PIEUP-CHIEUCH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG CHIEUCH\t# \nD7E9 ;\t1107 110E ;\tMA\t# ( ퟩ → ᄇᄎ ) HANGUL JONGSEONG PIEUP-CHIEUCH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG CHIEUCH\t# →ᆸᆾ→\n\nA973 ;\t1107 110F ;\tMA\t# ( ꥳ → ᄇᄏ ) HANGUL CHOSEONG PIEUP-KHIEUKH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG KHIEUKH\t# \n\n1129 ;\t1107 1110 ;\tMA\t# ( ᄩ → ᄇᄐ ) HANGUL CHOSEONG PIEUP-THIEUTH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG THIEUTH\t# \n3177 ;\t1107 1110 ;\tMA\t# ( ㅷ → ᄇᄐ ) HANGUL LETTER PIEUP-THIEUTH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG THIEUTH\t# →ᄩ→\n\n112A ;\t1107 1111 ;\tMA\t# ( ᄪ → ᄇᄑ ) HANGUL CHOSEONG PIEUP-PHIEUPH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PHIEUPH\t# \n11E4 ;\t1107 1111 ;\tMA\t# ( ᇤ → ᄇᄑ ) HANGUL JONGSEONG PIEUP-PHIEUPH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PHIEUPH\t# →ᄪ→\n\nA974 ;\t1107 1112 ;\tMA\t# ( ꥴ → ᄇᄒ ) HANGUL CHOSEONG PIEUP-HIEUH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG HIEUH\t# \n11E5 ;\t1107 1112 ;\tMA\t# ( ᇥ → ᄇᄒ ) HANGUL JONGSEONG PIEUP-HIEUH → HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG HIEUH\t# →ᆸᇂ→\n\n3145 ;\t1109 ;\tMA\t# ( ㅅ → ᄉ ) HANGUL LETTER SIOS → HANGUL CHOSEONG SIOS\t# \n11BA ;\t1109 ;\tMA\t# ( ᆺ → ᄉ ) HANGUL JONGSEONG SIOS → HANGUL CHOSEONG SIOS\t# \n\n4ECA ;\t1109 30FC 1100 ;\tMA\t# ( 今 → ᄉーᄀ ) CJK UNIFIED IDEOGRAPH-4ECA → HANGUL CHOSEONG SIOS, KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL CHOSEONG KIYEOK\t# →슥→→스ᄀ→\n\n5408 ;\t1109 30FC 1106 ;\tMA\t# ( 合 → ᄉーᄆ ) CJK UNIFIED IDEOGRAPH-5408 → HANGUL CHOSEONG SIOS, KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL CHOSEONG MIEUM\t# →슴→→스ᄆ→\n\n112D ;\t1109 1100 ;\tMA\t# ( ᄭ → ᄉᄀ ) HANGUL CHOSEONG SIOS-KIYEOK → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KIYEOK\t# \n317A ;\t1109 1100 ;\tMA\t# ( ㅺ → ᄉᄀ ) HANGUL LETTER SIOS-KIYEOK → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KIYEOK\t# →ᄭ→\n11E7 ;\t1109 1100 ;\tMA\t# ( ᇧ → ᄉᄀ ) HANGUL JONGSEONG SIOS-KIYEOK → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KIYEOK\t# →ᄭ→\n\n112E ;\t1109 1102 ;\tMA\t# ( ᄮ → ᄉᄂ ) HANGUL CHOSEONG SIOS-NIEUN → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG NIEUN\t# \n317B ;\t1109 1102 ;\tMA\t# ( ㅻ → ᄉᄂ ) HANGUL LETTER SIOS-NIEUN → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG NIEUN\t# →ᄮ→\n\n112F ;\t1109 1103 ;\tMA\t# ( ᄯ → ᄉᄃ ) HANGUL CHOSEONG SIOS-TIKEUT → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG TIKEUT\t# \n317C ;\t1109 1103 ;\tMA\t# ( ㅼ → ᄉᄃ ) HANGUL LETTER SIOS-TIKEUT → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG TIKEUT\t# →ᄯ→\n11E8 ;\t1109 1103 ;\tMA\t# ( ᇨ → ᄉᄃ ) HANGUL JONGSEONG SIOS-TIKEUT → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG TIKEUT\t# →ᄯ→\n\n1130 ;\t1109 1105 ;\tMA\t# ( ᄰ → ᄉᄅ ) HANGUL CHOSEONG SIOS-RIEUL → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG RIEUL\t# \n11E9 ;\t1109 1105 ;\tMA\t# ( ᇩ → ᄉᄅ ) HANGUL JONGSEONG SIOS-RIEUL → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG RIEUL\t# →ᄰ→\n\n1131 ;\t1109 1106 ;\tMA\t# ( ᄱ → ᄉᄆ ) HANGUL CHOSEONG SIOS-MIEUM → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG MIEUM\t# \nD7EA ;\t1109 1106 ;\tMA\t# ( ퟪ → ᄉᄆ ) HANGUL JONGSEONG SIOS-MIEUM → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG MIEUM\t# →ᆺᆷ→\n\n1132 ;\t1109 1107 ;\tMA\t# ( ᄲ → ᄉᄇ ) HANGUL CHOSEONG SIOS-PIEUP → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PIEUP\t# \n317D ;\t1109 1107 ;\tMA\t# ( ㅽ → ᄉᄇ ) HANGUL LETTER SIOS-PIEUP → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PIEUP\t# →ᄲ→\n11EA ;\t1109 1107 ;\tMA\t# ( ᇪ → ᄉᄇ ) HANGUL JONGSEONG SIOS-PIEUP → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PIEUP\t# →ᄲ→\n\n1133 ;\t1109 1107 1100 ;\tMA\t# ( ᄳ → ᄉᄇᄀ ) HANGUL CHOSEONG SIOS-PIEUP-KIYEOK → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG KIYEOK\t# \n\nD7EB ;\t1109 1107 110B ;\tMA\t# ( ퟫ → ᄉᄇᄋ ) HANGUL JONGSEONG SIOS-KAPYEOUNPIEUP → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# →ᆺᆸᆼ→\n\n110A ;\t1109 1109 ;\tMA\t# ( ᄊ → ᄉᄉ ) HANGUL CHOSEONG SSANGSIOS → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS\t# \n3146 ;\t1109 1109 ;\tMA\t# ( ㅆ → ᄉᄉ ) HANGUL LETTER SSANGSIOS → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS\t# →ᄊ→\n11BB ;\t1109 1109 ;\tMA\t# ( ᆻ → ᄉᄉ ) HANGUL JONGSEONG SSANGSIOS → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS\t# →ᄊ→\n\n4E1B ;\t1109 1109 30FC ;\tMA\t# ( 丛 → ᄉᄉー ) CJK UNIFIED IDEOGRAPH-4E1B → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS, KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →쓰→→ᄉ스→\n\nD7EC ;\t1109 1109 1100 ;\tMA\t# ( ퟬ → ᄉᄉᄀ ) HANGUL JONGSEONG SSANGSIOS-KIYEOK → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KIYEOK\t# →ᆺᆺᆨ→\n\nD7ED ;\t1109 1109 1103 ;\tMA\t# ( ퟭ → ᄉᄉᄃ ) HANGUL JONGSEONG SSANGSIOS-TIKEUT → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG TIKEUT\t# →ᆺᆺᆮ→\n\nA975 ;\t1109 1109 1107 ;\tMA\t# ( ꥵ → ᄉᄉᄇ ) HANGUL CHOSEONG SSANGSIOS-PIEUP → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PIEUP\t# \n\n1134 ;\t1109 1109 1109 ;\tMA\t# ( ᄴ → ᄉᄉᄉ ) HANGUL CHOSEONG SIOS-SSANGSIOS → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS, HANGUL CHOSEONG SIOS\t# \n\n1135 ;\t1109 110B ;\tMA\t# ( ᄵ → ᄉᄋ ) HANGUL CHOSEONG SIOS-IEUNG → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG IEUNG\t# \n\n1136 ;\t1109 110C ;\tMA\t# ( ᄶ → ᄉᄌ ) HANGUL CHOSEONG SIOS-CIEUC → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG CIEUC\t# \n317E ;\t1109 110C ;\tMA\t# ( ㅾ → ᄉᄌ ) HANGUL LETTER SIOS-CIEUC → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG CIEUC\t# →ᄶ→\nD7EF ;\t1109 110C ;\tMA\t# ( ퟯ → ᄉᄌ ) HANGUL JONGSEONG SIOS-CIEUC → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG CIEUC\t# →ᆺᆽ→\n\n1137 ;\t1109 110E ;\tMA\t# ( ᄷ → ᄉᄎ ) HANGUL CHOSEONG SIOS-CHIEUCH → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG CHIEUCH\t# \nD7F0 ;\t1109 110E ;\tMA\t# ( ퟰ → ᄉᄎ ) HANGUL JONGSEONG SIOS-CHIEUCH → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG CHIEUCH\t# →ᆺᆾ→\n\n1138 ;\t1109 110F ;\tMA\t# ( ᄸ → ᄉᄏ ) HANGUL CHOSEONG SIOS-KHIEUKH → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG KHIEUKH\t# \n\n1139 ;\t1109 1110 ;\tMA\t# ( ᄹ → ᄉᄐ ) HANGUL CHOSEONG SIOS-THIEUTH → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG THIEUTH\t# \nD7F1 ;\t1109 1110 ;\tMA\t# ( ퟱ → ᄉᄐ ) HANGUL JONGSEONG SIOS-THIEUTH → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG THIEUTH\t# →ᆺᇀ→\n\n113A ;\t1109 1111 ;\tMA\t# ( ᄺ → ᄉᄑ ) HANGUL CHOSEONG SIOS-PHIEUPH → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PHIEUPH\t# \n\nD7EE ;\t1109 1140 ;\tMA\t# ( ퟮ → ᄉᅀ ) HANGUL JONGSEONG SIOS-PANSIOS → HANGUL CHOSEONG SIOS, HANGUL CHOSEONG PANSIOS\t# →ᆺᇫ→\n\n3147 ;\t110B ;\tMA\t# ( ㅇ → ᄋ ) HANGUL LETTER IEUNG → HANGUL CHOSEONG IEUNG\t# \n11BC ;\t110B ;\tMA\t# ( ᆼ → ᄋ ) HANGUL JONGSEONG IEUNG → HANGUL CHOSEONG IEUNG\t# \n\n1141 ;\t110B 1100 ;\tMA\t# ( ᅁ → ᄋᄀ ) HANGUL CHOSEONG IEUNG-KIYEOK → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG KIYEOK\t# \n11EC ;\t110B 1100 ;\tMA\t# ( ᇬ → ᄋᄀ ) HANGUL JONGSEONG IEUNG-KIYEOK → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG KIYEOK\t# →ᅁ→\n\n11ED ;\t110B 1100 1100 ;\tMA\t# ( ᇭ → ᄋᄀᄀ ) HANGUL JONGSEONG IEUNG-SSANGKIYEOK → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG KIYEOK, HANGUL CHOSEONG KIYEOK\t# →ᆼᆨᆨ→\n\n1142 ;\t110B 1103 ;\tMA\t# ( ᅂ → ᄋᄃ ) HANGUL CHOSEONG IEUNG-TIKEUT → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG TIKEUT\t# \n\nA976 ;\t110B 1105 ;\tMA\t# ( ꥶ → ᄋᄅ ) HANGUL CHOSEONG IEUNG-RIEUL → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG RIEUL\t# \n\n1143 ;\t110B 1106 ;\tMA\t# ( ᅃ → ᄋᄆ ) HANGUL CHOSEONG IEUNG-MIEUM → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG MIEUM\t# \n\n1144 ;\t110B 1107 ;\tMA\t# ( ᅄ → ᄋᄇ ) HANGUL CHOSEONG IEUNG-PIEUP → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG PIEUP\t# \n\n1145 ;\t110B 1109 ;\tMA\t# ( ᅅ → ᄋᄉ ) HANGUL CHOSEONG IEUNG-SIOS → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG SIOS\t# \n11F1 ;\t110B 1109 ;\tMA\t# ( ᇱ → ᄋᄉ ) HANGUL JONGSEONG YESIEUNG-SIOS → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG SIOS\t# →ᅅ→\n3182 ;\t110B 1109 ;\tMA\t# ( ㆂ → ᄋᄉ ) HANGUL LETTER YESIEUNG-SIOS → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG SIOS\t# →ᇱ→→ᅅ→\n\n1147 ;\t110B 110B ;\tMA\t# ( ᅇ → ᄋᄋ ) HANGUL CHOSEONG SSANGIEUNG → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG IEUNG\t# \n3180 ;\t110B 110B ;\tMA\t# ( ㆀ → ᄋᄋ ) HANGUL LETTER SSANGIEUNG → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG IEUNG\t# →ᅇ→\n11EE ;\t110B 110B ;\tMA\t# ( ᇮ → ᄋᄋ ) HANGUL JONGSEONG SSANGIEUNG → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG IEUNG\t# →ᅇ→\n\n1148 ;\t110B 110C ;\tMA\t# ( ᅈ → ᄋᄌ ) HANGUL CHOSEONG IEUNG-CIEUC → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG CIEUC\t# \n\n1149 ;\t110B 110E ;\tMA\t# ( ᅉ → ᄋᄎ ) HANGUL CHOSEONG IEUNG-CHIEUCH → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG CHIEUCH\t# \n\n11EF ;\t110B 110F ;\tMA\t# ( ᇯ → ᄋᄏ ) HANGUL JONGSEONG IEUNG-KHIEUKH → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG KHIEUKH\t# →ᆼᆿ→\n\n114A ;\t110B 1110 ;\tMA\t# ( ᅊ → ᄋᄐ ) HANGUL CHOSEONG IEUNG-THIEUTH → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG THIEUTH\t# \n\n114B ;\t110B 1111 ;\tMA\t# ( ᅋ → ᄋᄑ ) HANGUL CHOSEONG IEUNG-PHIEUPH → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG PHIEUPH\t# \n\nA977 ;\t110B 1112 ;\tMA\t# ( ꥷ → ᄋᄒ ) HANGUL CHOSEONG IEUNG-HIEUH → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG HIEUH\t# \n\n1146 ;\t110B 1140 ;\tMA\t# ( ᅆ → ᄋᅀ ) HANGUL CHOSEONG IEUNG-PANSIOS → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG PANSIOS\t# \n11F2 ;\t110B 1140 ;\tMA\t# ( ᇲ → ᄋᅀ ) HANGUL JONGSEONG YESIEUNG-PANSIOS → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG PANSIOS\t# →ᅆ→\n3183 ;\t110B 1140 ;\tMA\t# ( ㆃ → ᄋᅀ ) HANGUL LETTER YESIEUNG-PANSIOS → HANGUL CHOSEONG IEUNG, HANGUL CHOSEONG PANSIOS\t# →ᇲ→→ᅆ→\n\n3148 ;\t110C ;\tMA\t# ( ㅈ → ᄌ ) HANGUL LETTER CIEUC → HANGUL CHOSEONG CIEUC\t# \n11BD ;\t110C ;\tMA\t# ( ᆽ → ᄌ ) HANGUL JONGSEONG CIEUC → HANGUL CHOSEONG CIEUC\t# \n\nD7F7 ;\t110C 1107 ;\tMA\t# ( ퟷ → ᄌᄇ ) HANGUL JONGSEONG CIEUC-PIEUP → HANGUL CHOSEONG CIEUC, HANGUL CHOSEONG PIEUP\t# →ᆽᆸ→\n\nD7F8 ;\t110C 1107 1107 ;\tMA\t# ( ퟸ → ᄌᄇᄇ ) HANGUL JONGSEONG CIEUC-SSANGPIEUP → HANGUL CHOSEONG CIEUC, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG PIEUP\t# →ᆽᆸᆸ→\n\n114D ;\t110C 110B ;\tMA\t# ( ᅍ → ᄌᄋ ) HANGUL CHOSEONG CIEUC-IEUNG → HANGUL CHOSEONG CIEUC, HANGUL CHOSEONG IEUNG\t# \n\n110D ;\t110C 110C ;\tMA\t# ( ᄍ → ᄌᄌ ) HANGUL CHOSEONG SSANGCIEUC → HANGUL CHOSEONG CIEUC, HANGUL CHOSEONG CIEUC\t# \n3149 ;\t110C 110C ;\tMA\t# ( ㅉ → ᄌᄌ ) HANGUL LETTER SSANGCIEUC → HANGUL CHOSEONG CIEUC, HANGUL CHOSEONG CIEUC\t# →ᄍ→\nD7F9 ;\t110C 110C ;\tMA\t# ( ퟹ → ᄌᄌ ) HANGUL JONGSEONG SSANGCIEUC → HANGUL CHOSEONG CIEUC, HANGUL CHOSEONG CIEUC\t# →ᆽᆽ→\n\nA978 ;\t110C 110C 1112 ;\tMA\t# ( ꥸ → ᄌᄌᄒ ) HANGUL CHOSEONG SSANGCIEUC-HIEUH → HANGUL CHOSEONG CIEUC, HANGUL CHOSEONG CIEUC, HANGUL CHOSEONG HIEUH\t# \n\n4E15 ;\t110C 1169 ;\tMA\t# ( 丕 → 조 ) CJK UNIFIED IDEOGRAPH-4E15 → HANGUL CHOSEONG CIEUC, HANGUL JUNGSEONG O\t# \n\n314A ;\t110E ;\tMA\t# ( ㅊ → ᄎ ) HANGUL LETTER CHIEUCH → HANGUL CHOSEONG CHIEUCH\t# \n11BE ;\t110E ;\tMA\t# ( ᆾ → ᄎ ) HANGUL JONGSEONG CHIEUCH → HANGUL CHOSEONG CHIEUCH\t# \n\n1152 ;\t110E 110F ;\tMA\t# ( ᅒ → ᄎᄏ ) HANGUL CHOSEONG CHIEUCH-KHIEUKH → HANGUL CHOSEONG CHIEUCH, HANGUL CHOSEONG KHIEUKH\t# \n\n1153 ;\t110E 1112 ;\tMA\t# ( ᅓ → ᄎᄒ ) HANGUL CHOSEONG CHIEUCH-HIEUH → HANGUL CHOSEONG CHIEUCH, HANGUL CHOSEONG HIEUH\t# \n\n314B ;\t110F ;\tMA\t# ( ㅋ → ᄏ ) HANGUL LETTER KHIEUKH → HANGUL CHOSEONG KHIEUKH\t# \n11BF ;\t110F ;\tMA\t# ( ᆿ → ᄏ ) HANGUL JONGSEONG KHIEUKH → HANGUL CHOSEONG KHIEUKH\t# \n\n314C ;\t1110 ;\tMA\t# ( ㅌ → ᄐ ) HANGUL LETTER THIEUTH → HANGUL CHOSEONG THIEUTH\t# \n11C0 ;\t1110 ;\tMA\t# ( ᇀ → ᄐ ) HANGUL JONGSEONG THIEUTH → HANGUL CHOSEONG THIEUTH\t# \n\n9577 ;\t1110 30FC 1102 110C ;\tMA\t# ( 長 → ᄐーᄂᄌ ) CJK UNIFIED IDEOGRAPH-9577 → HANGUL CHOSEONG THIEUTH, KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG CIEUC\t# →튽→→트ᄂᄌ→\n2ED1 ;\t1110 30FC 1102 110C ;\tMA\t#* ( ⻑ → ᄐーᄂᄌ ) CJK RADICAL LONG ONE → HANGUL CHOSEONG THIEUTH, KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG CIEUC\t# →長→→튽→→트ᄂᄌ→\n2FA7 ;\t1110 30FC 1102 110C ;\tMA\t#* ( ⾧ → ᄐーᄂᄌ ) KANGXI RADICAL LONG → HANGUL CHOSEONG THIEUTH, KATAKANA-HIRAGANA PROLONGED SOUND MARK, HANGUL CHOSEONG NIEUN, HANGUL CHOSEONG CIEUC\t# →長→→튽→→트ᄂᄌ→\n\nA979 ;\t1110 1110 ;\tMA\t# ( ꥹ → ᄐᄐ ) HANGUL CHOSEONG SSANGTHIEUTH → HANGUL CHOSEONG THIEUTH, HANGUL CHOSEONG THIEUTH\t# \n\n314D ;\t1111 ;\tMA\t# ( ㅍ → ᄑ ) HANGUL LETTER PHIEUPH → HANGUL CHOSEONG PHIEUPH\t# \n11C1 ;\t1111 ;\tMA\t# ( ᇁ → ᄑ ) HANGUL JONGSEONG PHIEUPH → HANGUL CHOSEONG PHIEUPH\t# \n\n1156 ;\t1111 1107 ;\tMA\t# ( ᅖ → ᄑᄇ ) HANGUL CHOSEONG PHIEUPH-PIEUP → HANGUL CHOSEONG PHIEUPH, HANGUL CHOSEONG PIEUP\t# \n11F3 ;\t1111 1107 ;\tMA\t# ( ᇳ → ᄑᄇ ) HANGUL JONGSEONG PHIEUPH-PIEUP → HANGUL CHOSEONG PHIEUPH, HANGUL CHOSEONG PIEUP\t# →ᅖ→\n\nD7FA ;\t1111 1109 ;\tMA\t# ( ퟺ → ᄑᄉ ) HANGUL JONGSEONG PHIEUPH-SIOS → HANGUL CHOSEONG PHIEUPH, HANGUL CHOSEONG SIOS\t# →ᇁᆺ→\n\n1157 ;\t1111 110B ;\tMA\t# ( ᅗ → ᄑᄋ ) HANGUL CHOSEONG KAPYEOUNPHIEUPH → HANGUL CHOSEONG PHIEUPH, HANGUL CHOSEONG IEUNG\t# \n3184 ;\t1111 110B ;\tMA\t# ( ㆄ → ᄑᄋ ) HANGUL LETTER KAPYEOUNPHIEUPH → HANGUL CHOSEONG PHIEUPH, HANGUL CHOSEONG IEUNG\t# →ᅗ→\n11F4 ;\t1111 110B ;\tMA\t# ( ᇴ → ᄑᄋ ) HANGUL JONGSEONG KAPYEOUNPHIEUPH → HANGUL CHOSEONG PHIEUPH, HANGUL CHOSEONG IEUNG\t# →ᅗ→\n\nD7FB ;\t1111 1110 ;\tMA\t# ( ퟻ → ᄑᄐ ) HANGUL JONGSEONG PHIEUPH-THIEUTH → HANGUL CHOSEONG PHIEUPH, HANGUL CHOSEONG THIEUTH\t# →ᇁᇀ→\n\nA97A ;\t1111 1112 ;\tMA\t# ( ꥺ → ᄑᄒ ) HANGUL CHOSEONG PHIEUPH-HIEUH → HANGUL CHOSEONG PHIEUPH, HANGUL CHOSEONG HIEUH\t# \n\n314E ;\t1112 ;\tMA\t# ( ㅎ → ᄒ ) HANGUL LETTER HIEUH → HANGUL CHOSEONG HIEUH\t# \n11C2 ;\t1112 ;\tMA\t# ( ᇂ → ᄒ ) HANGUL JONGSEONG HIEUH → HANGUL CHOSEONG HIEUH\t# \n\n11F5 ;\t1112 1102 ;\tMA\t# ( ᇵ → ᄒᄂ ) HANGUL JONGSEONG HIEUH-NIEUN → HANGUL CHOSEONG HIEUH, HANGUL CHOSEONG NIEUN\t# →ᇂᆫ→\n\n11F6 ;\t1112 1105 ;\tMA\t# ( ᇶ → ᄒᄅ ) HANGUL JONGSEONG HIEUH-RIEUL → HANGUL CHOSEONG HIEUH, HANGUL CHOSEONG RIEUL\t# →ᇂᆯ→\n\n11F7 ;\t1112 1106 ;\tMA\t# ( ᇷ → ᄒᄆ ) HANGUL JONGSEONG HIEUH-MIEUM → HANGUL CHOSEONG HIEUH, HANGUL CHOSEONG MIEUM\t# →ᇂᆷ→\n\n11F8 ;\t1112 1107 ;\tMA\t# ( ᇸ → ᄒᄇ ) HANGUL JONGSEONG HIEUH-PIEUP → HANGUL CHOSEONG HIEUH, HANGUL CHOSEONG PIEUP\t# →ᇂᆸ→\n\nA97B ;\t1112 1109 ;\tMA\t# ( ꥻ → ᄒᄉ ) HANGUL CHOSEONG HIEUH-SIOS → HANGUL CHOSEONG HIEUH, HANGUL CHOSEONG SIOS\t# \n\n1158 ;\t1112 1112 ;\tMA\t# ( ᅘ → ᄒᄒ ) HANGUL CHOSEONG SSANGHIEUH → HANGUL CHOSEONG HIEUH, HANGUL CHOSEONG HIEUH\t# \n3185 ;\t1112 1112 ;\tMA\t# ( ㆅ → ᄒᄒ ) HANGUL LETTER SSANGHIEUH → HANGUL CHOSEONG HIEUH, HANGUL CHOSEONG HIEUH\t# →ᅘ→\n\n113D ;\t113C 113C ;\tMA\t# ( ᄽ → ᄼᄼ ) HANGUL CHOSEONG CHITUEUMSSANGSIOS → HANGUL CHOSEONG CHITUEUMSIOS, HANGUL CHOSEONG CHITUEUMSIOS\t# \n\n113F ;\t113E 113E ;\tMA\t# ( ᄿ → ᄾᄾ ) HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS → HANGUL CHOSEONG CEONGCHIEUMSIOS, HANGUL CHOSEONG CEONGCHIEUMSIOS\t# \n\n317F ;\t1140 ;\tMA\t# ( ㅿ → ᅀ ) HANGUL LETTER PANSIOS → HANGUL CHOSEONG PANSIOS\t# \n11EB ;\t1140 ;\tMA\t# ( ᇫ → ᅀ ) HANGUL JONGSEONG PANSIOS → HANGUL CHOSEONG PANSIOS\t# \n\nD7F3 ;\t1140 1107 ;\tMA\t# ( ퟳ → ᅀᄇ ) HANGUL JONGSEONG PANSIOS-PIEUP → HANGUL CHOSEONG PANSIOS, HANGUL CHOSEONG PIEUP\t# →ᇫᆸ→\n\nD7F4 ;\t1140 1107 110B ;\tMA\t# ( ퟴ → ᅀᄇᄋ ) HANGUL JONGSEONG PANSIOS-KAPYEOUNPIEUP → HANGUL CHOSEONG PANSIOS, HANGUL CHOSEONG PIEUP, HANGUL CHOSEONG IEUNG\t# →ᇫᆸᆼ→\n\n3181 ;\t114C ;\tMA\t# ( ㆁ → ᅌ ) HANGUL LETTER YESIEUNG → HANGUL CHOSEONG YESIEUNG\t# \n11F0 ;\t114C ;\tMA\t# ( ᇰ → ᅌ ) HANGUL JONGSEONG YESIEUNG → HANGUL CHOSEONG YESIEUNG\t# \n\nD7F5 ;\t114C 1106 ;\tMA\t# ( ퟵ → ᅌᄆ ) HANGUL JONGSEONG YESIEUNG-MIEUM → HANGUL CHOSEONG YESIEUNG, HANGUL CHOSEONG MIEUM\t# →ᇰᆷ→\n\nD7F6 ;\t114C 1112 ;\tMA\t# ( ퟶ → ᅌᄒ ) HANGUL JONGSEONG YESIEUNG-HIEUH → HANGUL CHOSEONG YESIEUNG, HANGUL CHOSEONG HIEUH\t# →ᇰᇂ→\n\n114F ;\t114E 114E ;\tMA\t# ( ᅏ → ᅎᅎ ) HANGUL CHOSEONG CHITUEUMSSANGCIEUC → HANGUL CHOSEONG CHITUEUMCIEUC, HANGUL CHOSEONG CHITUEUMCIEUC\t# \n\n1151 ;\t1150 1150 ;\tMA\t# ( ᅑ → ᅐᅐ ) HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC → HANGUL CHOSEONG CEONGCHIEUMCIEUC, HANGUL CHOSEONG CEONGCHIEUMCIEUC\t# \n\n3186 ;\t1159 ;\tMA\t# ( ㆆ → ᅙ ) HANGUL LETTER YEORINHIEUH → HANGUL CHOSEONG YEORINHIEUH\t# \n11F9 ;\t1159 ;\tMA\t# ( ᇹ → ᅙ ) HANGUL JONGSEONG YEORINHIEUH → HANGUL CHOSEONG YEORINHIEUH\t# \n\nA97C ;\t1159 1159 ;\tMA\t# ( ꥼ → ᅙᅙ ) HANGUL CHOSEONG SSANGYEORINHIEUH → HANGUL CHOSEONG YEORINHIEUH, HANGUL CHOSEONG YEORINHIEUH\t# \n\n3164 ;\t1160 ;\tMA\t# (  →  ) HANGUL FILLER → HANGUL JUNGSEONG FILLER\t# \n\n314F ;\t1161 ;\tMA\t# ( ㅏ → ᅡ ) HANGUL LETTER A → HANGUL JUNGSEONG A\t# \n\n11A3 ;\t1161 30FC ;\tMA\t# ( ᆣ → ᅡー ) HANGUL JUNGSEONG A-EU → HANGUL JUNGSEONG A, KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →ᅡᅳ→\n\n1176 ;\t1161 1169 ;\tMA\t# ( ᅶ → ᅡᅩ ) HANGUL JUNGSEONG A-O → HANGUL JUNGSEONG A, HANGUL JUNGSEONG O\t# \n\n1177 ;\t1161 116E ;\tMA\t# ( ᅷ → ᅡᅮ ) HANGUL JUNGSEONG A-U → HANGUL JUNGSEONG A, HANGUL JUNGSEONG U\t# \n\n1162 ;\t1161 4E28 ;\tMA\t# ( ᅢ → ᅡ丨 ) HANGUL JUNGSEONG AE → HANGUL JUNGSEONG A, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅡᅵ→\n3150 ;\t1161 4E28 ;\tMA\t# ( ㅐ → ᅡ丨 ) HANGUL LETTER AE → HANGUL JUNGSEONG A, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅢ→→ᅡᅵ→\n\n3151 ;\t1163 ;\tMA\t# ( ㅑ → ᅣ ) HANGUL LETTER YA → HANGUL JUNGSEONG YA\t# \n\n1178 ;\t1163 1169 ;\tMA\t# ( ᅸ → ᅣᅩ ) HANGUL JUNGSEONG YA-O → HANGUL JUNGSEONG YA, HANGUL JUNGSEONG O\t# \n\n1179 ;\t1163 116D ;\tMA\t# ( ᅹ → ᅣᅭ ) HANGUL JUNGSEONG YA-YO → HANGUL JUNGSEONG YA, HANGUL JUNGSEONG YO\t# \n\n11A4 ;\t1163 116E ;\tMA\t# ( ᆤ → ᅣᅮ ) HANGUL JUNGSEONG YA-U → HANGUL JUNGSEONG YA, HANGUL JUNGSEONG U\t# \n\n1164 ;\t1163 4E28 ;\tMA\t# ( ᅤ → ᅣ丨 ) HANGUL JUNGSEONG YAE → HANGUL JUNGSEONG YA, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅣᅵ→\n3152 ;\t1163 4E28 ;\tMA\t# ( ㅒ → ᅣ丨 ) HANGUL LETTER YAE → HANGUL JUNGSEONG YA, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅤ→→ᅣᅵ→\n\n3153 ;\t1165 ;\tMA\t# ( ㅓ → ᅥ ) HANGUL LETTER EO → HANGUL JUNGSEONG EO\t# \n\n117C ;\t1165 30FC ;\tMA\t# ( ᅼ → ᅥー ) HANGUL JUNGSEONG EO-EU → HANGUL JUNGSEONG EO, KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →ᅥᅳ→\n\n117A ;\t1165 1169 ;\tMA\t# ( ᅺ → ᅥᅩ ) HANGUL JUNGSEONG EO-O → HANGUL JUNGSEONG EO, HANGUL JUNGSEONG O\t# \n\n117B ;\t1165 116E ;\tMA\t# ( ᅻ → ᅥᅮ ) HANGUL JUNGSEONG EO-U → HANGUL JUNGSEONG EO, HANGUL JUNGSEONG U\t# \n\n1166 ;\t1165 4E28 ;\tMA\t# ( ᅦ → ᅥ丨 ) HANGUL JUNGSEONG E → HANGUL JUNGSEONG EO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅥᅵ→\n3154 ;\t1165 4E28 ;\tMA\t# ( ㅔ → ᅥ丨 ) HANGUL LETTER E → HANGUL JUNGSEONG EO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅦ→→ᅥᅵ→\n\n3155 ;\t1167 ;\tMA\t# ( ㅕ → ᅧ ) HANGUL LETTER YEO → HANGUL JUNGSEONG YEO\t# \n\n11A5 ;\t1167 1163 ;\tMA\t# ( ᆥ → ᅧᅣ ) HANGUL JUNGSEONG YEO-YA → HANGUL JUNGSEONG YEO, HANGUL JUNGSEONG YA\t# \n\n117D ;\t1167 1169 ;\tMA\t# ( ᅽ → ᅧᅩ ) HANGUL JUNGSEONG YEO-O → HANGUL JUNGSEONG YEO, HANGUL JUNGSEONG O\t# \n\n117E ;\t1167 116E ;\tMA\t# ( ᅾ → ᅧᅮ ) HANGUL JUNGSEONG YEO-U → HANGUL JUNGSEONG YEO, HANGUL JUNGSEONG U\t# \n\n1168 ;\t1167 4E28 ;\tMA\t# ( ᅨ → ᅧ丨 ) HANGUL JUNGSEONG YE → HANGUL JUNGSEONG YEO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅧᅵ→\n3156 ;\t1167 4E28 ;\tMA\t# ( ㅖ → ᅧ丨 ) HANGUL LETTER YE → HANGUL JUNGSEONG YEO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅨ→→ᅧᅵ→\n\n3157 ;\t1169 ;\tMA\t# ( ㅗ → ᅩ ) HANGUL LETTER O → HANGUL JUNGSEONG O\t# \n\n116A ;\t1169 1161 ;\tMA\t# ( ᅪ → ᅩᅡ ) HANGUL JUNGSEONG WA → HANGUL JUNGSEONG O, HANGUL JUNGSEONG A\t# \n3158 ;\t1169 1161 ;\tMA\t# ( ㅘ → ᅩᅡ ) HANGUL LETTER WA → HANGUL JUNGSEONG O, HANGUL JUNGSEONG A\t# →ᅪ→\n\n116B ;\t1169 1161 4E28 ;\tMA\t# ( ᅫ → ᅩᅡ丨 ) HANGUL JUNGSEONG WAE → HANGUL JUNGSEONG O, HANGUL JUNGSEONG A, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅩᅡᅵ→\n3159 ;\t1169 1161 4E28 ;\tMA\t# ( ㅙ → ᅩᅡ丨 ) HANGUL LETTER WAE → HANGUL JUNGSEONG O, HANGUL JUNGSEONG A, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅫ→→ᅩᅡᅵ→\n\n11A6 ;\t1169 1163 ;\tMA\t# ( ᆦ → ᅩᅣ ) HANGUL JUNGSEONG O-YA → HANGUL JUNGSEONG O, HANGUL JUNGSEONG YA\t# \n\n11A7 ;\t1169 1163 4E28 ;\tMA\t# ( ᆧ → ᅩᅣ丨 ) HANGUL JUNGSEONG O-YAE → HANGUL JUNGSEONG O, HANGUL JUNGSEONG YA, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅩᅣᅵ→\n\n117F ;\t1169 1165 ;\tMA\t# ( ᅿ → ᅩᅥ ) HANGUL JUNGSEONG O-EO → HANGUL JUNGSEONG O, HANGUL JUNGSEONG EO\t# \n\n1180 ;\t1169 1165 4E28 ;\tMA\t# ( ᆀ → ᅩᅥ丨 ) HANGUL JUNGSEONG O-E → HANGUL JUNGSEONG O, HANGUL JUNGSEONG EO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅩᅥᅵ→\n\nD7B0 ;\t1169 1167 ;\tMA\t# ( ힰ → ᅩᅧ ) HANGUL JUNGSEONG O-YEO → HANGUL JUNGSEONG O, HANGUL JUNGSEONG YEO\t# \n\n1181 ;\t1169 1167 4E28 ;\tMA\t# ( ᆁ → ᅩᅧ丨 ) HANGUL JUNGSEONG O-YE → HANGUL JUNGSEONG O, HANGUL JUNGSEONG YEO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅩᅧᅵ→\n\n1182 ;\t1169 1169 ;\tMA\t# ( ᆂ → ᅩᅩ ) HANGUL JUNGSEONG O-O → HANGUL JUNGSEONG O, HANGUL JUNGSEONG O\t# \n\nD7B1 ;\t1169 1169 4E28 ;\tMA\t# ( ힱ → ᅩᅩ丨 ) HANGUL JUNGSEONG O-O-I → HANGUL JUNGSEONG O, HANGUL JUNGSEONG O, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅩᅩᅵ→\n\n1183 ;\t1169 116E ;\tMA\t# ( ᆃ → ᅩᅮ ) HANGUL JUNGSEONG O-U → HANGUL JUNGSEONG O, HANGUL JUNGSEONG U\t# \n\n116C ;\t1169 4E28 ;\tMA\t# ( ᅬ → ᅩ丨 ) HANGUL JUNGSEONG OE → HANGUL JUNGSEONG O, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅩᅵ→\n315A ;\t1169 4E28 ;\tMA\t# ( ㅚ → ᅩ丨 ) HANGUL LETTER OE → HANGUL JUNGSEONG O, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅬ→→ᅩᅵ→\n\n315B ;\t116D ;\tMA\t# ( ㅛ → ᅭ ) HANGUL LETTER YO → HANGUL JUNGSEONG YO\t# \n\nD7B2 ;\t116D 1161 ;\tMA\t# ( ힲ → ᅭᅡ ) HANGUL JUNGSEONG YO-A → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG A\t# \n\nD7B3 ;\t116D 1161 4E28 ;\tMA\t# ( ힳ → ᅭᅡ丨 ) HANGUL JUNGSEONG YO-AE → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG A, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅭᅡᅵ→\n\n1184 ;\t116D 1163 ;\tMA\t# ( ᆄ → ᅭᅣ ) HANGUL JUNGSEONG YO-YA → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG YA\t# \n3187 ;\t116D 1163 ;\tMA\t# ( ㆇ → ᅭᅣ ) HANGUL LETTER YO-YA → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG YA\t# →ᆄ→\n1186 ;\t116D 1163 ;\tMA\t# ( ᆆ → ᅭᅣ ) HANGUL JUNGSEONG YO-YEO → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG YA\t# →ᆄ→\n\n1185 ;\t116D 1163 4E28 ;\tMA\t# ( ᆅ → ᅭᅣ丨 ) HANGUL JUNGSEONG YO-YAE → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG YA, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅭᅣᅵ→\n3188 ;\t116D 1163 4E28 ;\tMA\t# ( ㆈ → ᅭᅣ丨 ) HANGUL LETTER YO-YAE → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG YA, CJK UNIFIED IDEOGRAPH-4E28\t# →ᆅ→→ᅭᅣᅵ→\n\nD7B4 ;\t116D 1165 ;\tMA\t# ( ힴ → ᅭᅥ ) HANGUL JUNGSEONG YO-EO → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG EO\t# \n\n1187 ;\t116D 1169 ;\tMA\t# ( ᆇ → ᅭᅩ ) HANGUL JUNGSEONG YO-O → HANGUL JUNGSEONG YO, HANGUL JUNGSEONG O\t# \n\n1188 ;\t116D 4E28 ;\tMA\t# ( ᆈ → ᅭ丨 ) HANGUL JUNGSEONG YO-I → HANGUL JUNGSEONG YO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅭᅵ→\n3189 ;\t116D 4E28 ;\tMA\t# ( ㆉ → ᅭ丨 ) HANGUL LETTER YO-I → HANGUL JUNGSEONG YO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᆈ→→ᅭᅵ→\n\n315C ;\t116E ;\tMA\t# ( ㅜ → ᅮ ) HANGUL LETTER U → HANGUL JUNGSEONG U\t# \n\n1189 ;\t116E 1161 ;\tMA\t# ( ᆉ → ᅮᅡ ) HANGUL JUNGSEONG U-A → HANGUL JUNGSEONG U, HANGUL JUNGSEONG A\t# \n\n118A ;\t116E 1161 4E28 ;\tMA\t# ( ᆊ → ᅮᅡ丨 ) HANGUL JUNGSEONG U-AE → HANGUL JUNGSEONG U, HANGUL JUNGSEONG A, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅮᅡᅵ→\n\n116F ;\t116E 1165 ;\tMA\t# ( ᅯ → ᅮᅥ ) HANGUL JUNGSEONG WEO → HANGUL JUNGSEONG U, HANGUL JUNGSEONG EO\t# \n315D ;\t116E 1165 ;\tMA\t# ( ㅝ → ᅮᅥ ) HANGUL LETTER WEO → HANGUL JUNGSEONG U, HANGUL JUNGSEONG EO\t# →ᅯ→\n\n118B ;\t116E 1165 30FC ;\tMA\t# ( ᆋ → ᅮᅥー ) HANGUL JUNGSEONG U-EO-EU → HANGUL JUNGSEONG U, HANGUL JUNGSEONG EO, KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →ᅮᅥᅳ→\n\n1170 ;\t116E 1165 4E28 ;\tMA\t# ( ᅰ → ᅮᅥ丨 ) HANGUL JUNGSEONG WE → HANGUL JUNGSEONG U, HANGUL JUNGSEONG EO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅮᅥᅵ→\n315E ;\t116E 1165 4E28 ;\tMA\t# ( ㅞ → ᅮᅥ丨 ) HANGUL LETTER WE → HANGUL JUNGSEONG U, HANGUL JUNGSEONG EO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅰ→→ᅮᅥᅵ→\n\nD7B5 ;\t116E 1167 ;\tMA\t# ( ힵ → ᅮᅧ ) HANGUL JUNGSEONG U-YEO → HANGUL JUNGSEONG U, HANGUL JUNGSEONG YEO\t# \n\n118C ;\t116E 1167 4E28 ;\tMA\t# ( ᆌ → ᅮᅧ丨 ) HANGUL JUNGSEONG U-YE → HANGUL JUNGSEONG U, HANGUL JUNGSEONG YEO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅮᅧᅵ→\n\n118D ;\t116E 116E ;\tMA\t# ( ᆍ → ᅮᅮ ) HANGUL JUNGSEONG U-U → HANGUL JUNGSEONG U, HANGUL JUNGSEONG U\t# \n\n1171 ;\t116E 4E28 ;\tMA\t# ( ᅱ → ᅮ丨 ) HANGUL JUNGSEONG WI → HANGUL JUNGSEONG U, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅮᅵ→\n315F ;\t116E 4E28 ;\tMA\t# ( ㅟ → ᅮ丨 ) HANGUL LETTER WI → HANGUL JUNGSEONG U, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅱ→→ᅮᅵ→\n\nD7B6 ;\t116E 4E28 4E28 ;\tMA\t# ( ힶ → ᅮ丨丨 ) HANGUL JUNGSEONG U-I-I → HANGUL JUNGSEONG U, CJK UNIFIED IDEOGRAPH-4E28, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅮᅵᅵ→\n\n3160 ;\t1172 ;\tMA\t# ( ㅠ → ᅲ ) HANGUL LETTER YU → HANGUL JUNGSEONG YU\t# \n\n118E ;\t1172 1161 ;\tMA\t# ( ᆎ → ᅲᅡ ) HANGUL JUNGSEONG YU-A → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG A\t# \n\nD7B7 ;\t1172 1161 4E28 ;\tMA\t# ( ힷ → ᅲᅡ丨 ) HANGUL JUNGSEONG YU-AE → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG A, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅲᅡᅵ→\n\n118F ;\t1172 1165 ;\tMA\t# ( ᆏ → ᅲᅥ ) HANGUL JUNGSEONG YU-EO → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG EO\t# \n\n1190 ;\t1172 1165 4E28 ;\tMA\t# ( ᆐ → ᅲᅥ丨 ) HANGUL JUNGSEONG YU-E → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG EO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅲᅥᅵ→\n\n1191 ;\t1172 1167 ;\tMA\t# ( ᆑ → ᅲᅧ ) HANGUL JUNGSEONG YU-YEO → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG YEO\t# \n318A ;\t1172 1167 ;\tMA\t# ( ㆊ → ᅲᅧ ) HANGUL LETTER YU-YEO → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG YEO\t# →ᆑ→\n\n1192 ;\t1172 1167 4E28 ;\tMA\t# ( ᆒ → ᅲᅧ丨 ) HANGUL JUNGSEONG YU-YE → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG YEO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅲᅧᅵ→\n318B ;\t1172 1167 4E28 ;\tMA\t# ( ㆋ → ᅲᅧ丨 ) HANGUL LETTER YU-YE → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG YEO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᆒ→→ᅲᅧᅵ→\n\nD7B8 ;\t1172 1169 ;\tMA\t# ( ힸ → ᅲᅩ ) HANGUL JUNGSEONG YU-O → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG O\t# \n\n1193 ;\t1172 116E ;\tMA\t# ( ᆓ → ᅲᅮ ) HANGUL JUNGSEONG YU-U → HANGUL JUNGSEONG YU, HANGUL JUNGSEONG U\t# \n\n1194 ;\t1172 4E28 ;\tMA\t# ( ᆔ → ᅲ丨 ) HANGUL JUNGSEONG YU-I → HANGUL JUNGSEONG YU, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅲᅵ→\n318C ;\t1172 4E28 ;\tMA\t# ( ㆌ → ᅲ丨 ) HANGUL LETTER YU-I → HANGUL JUNGSEONG YU, CJK UNIFIED IDEOGRAPH-4E28\t# →ᆔ→→ᅲᅵ→\n\n318D ;\t119E ;\tMA\t# ( ㆍ → ᆞ ) HANGUL LETTER ARAEA → HANGUL JUNGSEONG ARAEA\t# \n\nD7C5 ;\t119E 1161 ;\tMA\t# ( ퟅ → ᆞᅡ ) HANGUL JUNGSEONG ARAEA-A → HANGUL JUNGSEONG ARAEA, HANGUL JUNGSEONG A\t# \n\n119F ;\t119E 1165 ;\tMA\t# ( ᆟ → ᆞᅥ ) HANGUL JUNGSEONG ARAEA-EO → HANGUL JUNGSEONG ARAEA, HANGUL JUNGSEONG EO\t# \n\nD7C6 ;\t119E 1165 4E28 ;\tMA\t# ( ퟆ → ᆞᅥ丨 ) HANGUL JUNGSEONG ARAEA-E → HANGUL JUNGSEONG ARAEA, HANGUL JUNGSEONG EO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᆞᅥᅵ→\n\n11A0 ;\t119E 116E ;\tMA\t# ( ᆠ → ᆞᅮ ) HANGUL JUNGSEONG ARAEA-U → HANGUL JUNGSEONG ARAEA, HANGUL JUNGSEONG U\t# \n\n11A2 ;\t119E 119E ;\tMA\t# ( ᆢ → ᆞᆞ ) HANGUL JUNGSEONG SSANGARAEA → HANGUL JUNGSEONG ARAEA, HANGUL JUNGSEONG ARAEA\t# \n\n11A1 ;\t119E 4E28 ;\tMA\t# ( ᆡ → ᆞ丨 ) HANGUL JUNGSEONG ARAEA-I → HANGUL JUNGSEONG ARAEA, CJK UNIFIED IDEOGRAPH-4E28\t# →ᆞᅵ→\n318E ;\t119E 4E28 ;\tMA\t# ( ㆎ → ᆞ丨 ) HANGUL LETTER ARAEAE → HANGUL JUNGSEONG ARAEA, CJK UNIFIED IDEOGRAPH-4E28\t# →ᆡ→→ᆞᅵ→\n\n30D8 ;\t3078 ;\tMA\t# ( ヘ → へ ) KATAKANA LETTER HE → HIRAGANA LETTER HE\t# \n\n2341 ;\t303C ;\tMA\t#* ( ⍁ → 〼 ) APL FUNCTIONAL SYMBOL QUAD SLASH → MASU MARK\t# →⧄→\n29C4 ;\t303C ;\tMA\t#* ( ⧄ → 〼 ) SQUARED RISING DIAGONAL SLASH → MASU MARK\t# \n\n4E8E ;\t1B122 ;\tMA\t# ( 于 → 𛄢 ) CJK UNIFIED IDEOGRAPH-4E8E → KATAKANA LETTER ARCHAIC WU\t# \n\nA49E ;\tA04A ;\tMA\t#* ( ꒞ → ꁊ ) YI RADICAL PUT → YI SYLLABLE PUT\t# \n\nA4AC ;\tA050 ;\tMA\t#* ( ꒬ → ꁐ ) YI RADICAL PYT → YI SYLLABLE PYT\t# \n\nA49C ;\tA0C0 ;\tMA\t#* ( ꒜ → ꃀ ) YI RADICAL MOP → YI SYLLABLE MOP\t# \n\nA4A8 ;\tA132 ;\tMA\t#* ( ꒨ → ꄲ ) YI RADICAL TU → YI SYLLABLE TU\t# \n\nA4BF ;\tA259 ;\tMA\t#* ( ꒿ → ꉙ ) YI RADICAL HXOP → YI SYLLABLE HXOP\t# \n\nA4BE ;\tA2B1 ;\tMA\t#* ( ꒾ → ꊱ ) YI RADICAL CIP → YI SYLLABLE CIP\t# \n\nA494 ;\tA2CD ;\tMA\t#* ( ꒔ → ꋍ ) YI RADICAL CYP → YI SYLLABLE CYP\t# \n\nA4C0 ;\tA3AB ;\tMA\t#* ( ꓀ → ꎫ ) YI RADICAL SHAT → YI SYLLABLE SHAT\t# \n\nA4C2 ;\tA3B5 ;\tMA\t#* ( ꓂ → ꎵ ) YI RADICAL SHOP → YI SYLLABLE SHOP\t# \n\nA4BA ;\tA3BF ;\tMA\t#* ( ꒺ → ꎿ ) YI RADICAL SHUR → YI SYLLABLE SHUR\t# \n\nA4B0 ;\tA3C2 ;\tMA\t#* ( ꒰ → ꏂ ) YI RADICAL SHY → YI SYLLABLE SHY\t# \n\nA4A7 ;\tA458 ;\tMA\t#* ( ꒧ → ꑘ ) YI RADICAL NYOP → YI SYLLABLE NYOP\t# \n\n22A5 ;\tA4D5 ;\tMA\t#* ( ⊥ → ꓕ ) UP TACK → LISU LETTER THA\t# \n27C2 ;\tA4D5 ;\tMA\t#* ( ⟂ → ꓕ ) PERPENDICULAR → LISU LETTER THA\t# →⊥→\n1D21C ;\tA4D5 ;\tMA\t#* ( 𝈜 → ꓕ ) GREEK VOCAL NOTATION SYMBOL-54 → LISU LETTER THA\t# →Ʇ→\nA7B1 ;\tA4D5 ;\tMA\t# ( Ʇ → ꓕ ) LATIN CAPITAL LETTER TURNED T → LISU LETTER THA\t# \n\nA79E ;\tA4E4 ;\tMA\t# ( Ꞟ → ꓤ ) LATIN CAPITAL LETTER VOLAPUK UE → LISU LETTER ZA\t# \n\n2141 ;\tA4E8 ;\tMA\t#* ( ⅁ → ꓨ ) TURNED SANS-SERIF CAPITAL G → LISU LETTER HHA\t# \n\n2142 ;\tA4F6 ;\tMA\t#* ( ⅂ → ꓶ ) TURNED SANS-SERIF CAPITAL L → LISU LETTER UH\t# \n1D215 ;\tA4F6 ;\tMA\t#* ( 𝈕 → ꓶ ) GREEK VOCAL NOTATION SYMBOL-22 → LISU LETTER UH\t# →⅂→\n1D22B ;\tA4F6 ;\tMA\t#* ( 𝈫 → ꓶ ) GREEK INSTRUMENTAL NOTATION SYMBOL-24 → LISU LETTER UH\t# →𝈕→→⅂→\n16F26 ;\tA4F6 ;\tMA\t# ( 𖼦 → ꓶ ) MIAO LETTER HA → LISU LETTER UH\t# →⅂→\n10411 ;\tA4F6 ;\tMA\t# ( 𐐑 → ꓶ ) DESERET CAPITAL LETTER PEE → LISU LETTER UH\t# →⅂→\n\n2143 ;\t16F00 ;\tMA\t#* ( ⅃ → 𖼀 ) REVERSED SANS-SERIF CAPITAL L → MIAO LETTER PA\t# \n\n11AE6 ;\t11AE5 11AEF ;\tMA\t# ( 𑫦 → 𑫥𑫯 ) PAU CIN HAU RISING TONE → PAU CIN HAU RISING TONE LONG, PAU CIN HAU MID-LEVEL TONE\t# \n\n11AE8 ;\t11AE5 11AE5 ;\tMA\t# ( 𑫨 → 𑫥𑫥 ) PAU CIN HAU RISING TONE LONG FINAL → PAU CIN HAU RISING TONE LONG, PAU CIN HAU RISING TONE LONG\t# \n\n11AE9 ;\t11AE5 11AE5 11AEF ;\tMA\t# ( 𑫩 → 𑫥𑫥𑫯 ) PAU CIN HAU RISING TONE FINAL → PAU CIN HAU RISING TONE LONG, PAU CIN HAU RISING TONE LONG, PAU CIN HAU MID-LEVEL TONE\t# →𑫥𑫦→\n\n11AEA ;\t11AE5 11AE5 11AF0 ;\tMA\t# ( 𑫪 → 𑫥𑫥𑫰 ) PAU CIN HAU SANDHI GLOTTAL STOP FINAL → PAU CIN HAU RISING TONE LONG, PAU CIN HAU RISING TONE LONG, PAU CIN HAU GLOTTAL STOP VARIANT\t# →𑫥𑫧→\n\n11AE7 ;\t11AE5 11AF0 ;\tMA\t# ( 𑫧 → 𑫥𑫰 ) PAU CIN HAU SANDHI GLOTTAL STOP → PAU CIN HAU RISING TONE LONG, PAU CIN HAU GLOTTAL STOP VARIANT\t# \n\n11AF4 ;\t11AF3 11AEF ;\tMA\t# ( 𑫴 → 𑫳𑫯 ) PAU CIN HAU LOW-FALLING TONE → PAU CIN HAU LOW-FALLING TONE LONG, PAU CIN HAU MID-LEVEL TONE\t# \n\n11AF6 ;\t11AF3 11AF3 ;\tMA\t# ( 𑫶 → 𑫳𑫳 ) PAU CIN HAU LOW-FALLING TONE LONG FINAL → PAU CIN HAU LOW-FALLING TONE LONG, PAU CIN HAU LOW-FALLING TONE LONG\t# \n\n11AF7 ;\t11AF3 11AF3 11AEF ;\tMA\t# ( 𑫷 → 𑫳𑫳𑫯 ) PAU CIN HAU LOW-FALLING TONE FINAL → PAU CIN HAU LOW-FALLING TONE LONG, PAU CIN HAU LOW-FALLING TONE LONG, PAU CIN HAU MID-LEVEL TONE\t# →𑫳𑫴→\n\n11AF8 ;\t11AF3 11AF3 11AF0 ;\tMA\t# ( 𑫸 → 𑫳𑫳𑫰 ) PAU CIN HAU GLOTTAL STOP FINAL → PAU CIN HAU LOW-FALLING TONE LONG, PAU CIN HAU LOW-FALLING TONE LONG, PAU CIN HAU GLOTTAL STOP VARIANT\t# →𑫳𑫵→\n\n11AF5 ;\t11AF3 11AF0 ;\tMA\t# ( 𑫵 → 𑫳𑫰 ) PAU CIN HAU GLOTTAL STOP → PAU CIN HAU LOW-FALLING TONE LONG, PAU CIN HAU GLOTTAL STOP VARIANT\t# \n\n11AEC ;\t11AEB 11AEF ;\tMA\t# ( 𑫬 → 𑫫𑫯 ) PAU CIN HAU SANDHI TONE → PAU CIN HAU SANDHI TONE LONG, PAU CIN HAU MID-LEVEL TONE\t# \n\n11AED ;\t11AEB 11AEB ;\tMA\t# ( 𑫭 → 𑫫𑫫 ) PAU CIN HAU SANDHI TONE LONG FINAL → PAU CIN HAU SANDHI TONE LONG, PAU CIN HAU SANDHI TONE LONG\t# \n\n11AEE ;\t11AEB 11AEB 11AEF ;\tMA\t# ( 𑫮 → 𑫫𑫫𑫯 ) PAU CIN HAU SANDHI TONE FINAL → PAU CIN HAU SANDHI TONE LONG, PAU CIN HAU SANDHI TONE LONG, PAU CIN HAU MID-LEVEL TONE\t# →𑫫𑫬→\n\n2295 ;\t102A8 ;\tMA\t#* ( ⊕ → 𐊨 ) CIRCLED PLUS → CARIAN LETTER Q\t# \n2A01 ;\t102A8 ;\tMA\t#* ( ⨁ → 𐊨 ) N-ARY CIRCLED PLUS OPERATOR → CARIAN LETTER Q\t# →⊕→\n1F728 ;\t102A8 ;\tMA\t#* ( 🜨 → 𐊨 ) ALCHEMICAL SYMBOL FOR VERDIGRIS → CARIAN LETTER Q\t# →⊕→\nA69A ;\t102A8 ;\tMA\t# ( Ꚛ → 𐊨 ) CYRILLIC CAPITAL LETTER CROSSED O → CARIAN LETTER Q\t# →⊕→\n\n25BD ;\t102BC ;\tMA\t#* ( ▽ → 𐊼 ) WHITE DOWN-POINTING TRIANGLE → CARIAN LETTER K\t# \n1D214 ;\t102BC ;\tMA\t#* ( 𝈔 → 𐊼 ) GREEK VOCAL NOTATION SYMBOL-21 → CARIAN LETTER K\t# →▽→\n1F704 ;\t102BC ;\tMA\t#* ( 🜄 → 𐊼 ) ALCHEMICAL SYMBOL FOR WATER → CARIAN LETTER K\t# →▽→\n\n29D6 ;\t102C0 ;\tMA\t#* ( ⧖ → 𐋀 ) WHITE HOURGLASS → CARIAN LETTER G\t# \n\nA79B ;\t1043A ;\tMA\t# ( ꞛ → 𐐺 ) LATIN SMALL LETTER VOLAPUK AE → DESERET SMALL LETTER BEE\t# \n\nA79A ;\t10412 ;\tMA\t# ( Ꞛ → 𐐒 ) LATIN CAPITAL LETTER VOLAPUK AE → DESERET CAPITAL LETTER BEE\t# \n\n104A0 ;\t10486 ;\tMA\t# ( 𐒠 → 𐒆 ) OSMANYA DIGIT ZERO → OSMANYA LETTER DEEL\t# \n\n103D1 ;\t10382 ;\tMA\t# ( 𐏑 → 𐎂 ) OLD PERSIAN NUMBER ONE → UGARITIC LETTER GAMLA\t# \n\n103D3 ;\t10393 ;\tMA\t# ( 𐏓 → 𐎓 ) OLD PERSIAN NUMBER TEN → UGARITIC LETTER AIN\t# \n\n12038 ;\t1039A ;\tMA\t# ( 𒀸 → 𐎚 ) CUNEIFORM SIGN ASH → UGARITIC LETTER TO\t# \n\n2625 ;\t1099E ;\tMA\t#* ( ☥ → ‎𐦞‎ ) ANKH → MEROITIC HIEROGLYPHIC SYMBOL VIDJ\t# \n132F9 ;\t1099E ;\tMA\t# ( 𓋹 → ‎𐦞‎ ) EGYPTIAN HIEROGLYPH S034 → MEROITIC HIEROGLYPHIC SYMBOL VIDJ\t# →☥→\n\n3039 ;\t5344 ;\tMA\t# ( 〹 → 卄 ) HANGZHOU NUMERAL TWENTY → CJK UNIFIED IDEOGRAPH-5344\t# \n\nF967 ;\t4E0D ;\tMA\t# ( 不 → 不 ) CJK COMPATIBILITY IDEOGRAPH-F967 → CJK UNIFIED IDEOGRAPH-4E0D\t# \n\n2F800 ;\t4E3D ;\tMA\t# ( 丽 → 丽 ) CJK COMPATIBILITY IDEOGRAPH-2F800 → CJK UNIFIED IDEOGRAPH-4E3D\t# \n\nFA70 ;\t4E26 ;\tMA\t# ( 並 → 並 ) CJK COMPATIBILITY IDEOGRAPH-FA70 → CJK UNIFIED IDEOGRAPH-4E26\t# \n\n239C ;\t4E28 ;\tMA\t#* ( ⎜ → 丨 ) LEFT PARENTHESIS EXTENSION → CJK UNIFIED IDEOGRAPH-4E28\t# →⎥→→⎮→\n239F ;\t4E28 ;\tMA\t#* ( ⎟ → 丨 ) RIGHT PARENTHESIS EXTENSION → CJK UNIFIED IDEOGRAPH-4E28\t# →⎥→→⎮→\n23A2 ;\t4E28 ;\tMA\t#* ( ⎢ → 丨 ) LEFT SQUARE BRACKET EXTENSION → CJK UNIFIED IDEOGRAPH-4E28\t# →⎥→→⎮→\n23A5 ;\t4E28 ;\tMA\t#* ( ⎥ → 丨 ) RIGHT SQUARE BRACKET EXTENSION → CJK UNIFIED IDEOGRAPH-4E28\t# →⎮→\n23AA ;\t4E28 ;\tMA\t#* ( ⎪ → 丨 ) CURLY BRACKET EXTENSION → CJK UNIFIED IDEOGRAPH-4E28\t# →⎥→→⎮→\n23AE ;\t4E28 ;\tMA\t#* ( ⎮ → 丨 ) INTEGRAL EXTENSION → CJK UNIFIED IDEOGRAPH-4E28\t# \n31D1 ;\t4E28 ;\tMA\t#* ( ㇑ → 丨 ) CJK STROKE S → CJK UNIFIED IDEOGRAPH-4E28\t# \n1175 ;\t4E28 ;\tMA\t# ( ᅵ → 丨 ) HANGUL JUNGSEONG I → CJK UNIFIED IDEOGRAPH-4E28\t# →ㅣ→\n3163 ;\t4E28 ;\tMA\t# ( ㅣ → 丨 ) HANGUL LETTER I → CJK UNIFIED IDEOGRAPH-4E28\t# \n2F01 ;\t4E28 ;\tMA\t#* ( ⼁ → 丨 ) KANGXI RADICAL LINE → CJK UNIFIED IDEOGRAPH-4E28\t# \n\n119C ;\t4E28 30FC ;\tMA\t# ( ᆜ → 丨ー ) HANGUL JUNGSEONG I-EU → CJK UNIFIED IDEOGRAPH-4E28, KATAKANA-HIRAGANA PROLONGED SOUND MARK\t# →ᅵᅳ→\n\n1198 ;\t4E28 1161 ;\tMA\t# ( ᆘ → 丨ᅡ ) HANGUL JUNGSEONG I-A → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG A\t# →ᅵᅡ→\n\n1199 ;\t4E28 1163 ;\tMA\t# ( ᆙ → 丨ᅣ ) HANGUL JUNGSEONG I-YA → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG YA\t# →ᅵᅣ→\n\nD7BD ;\t4E28 1163 1169 ;\tMA\t# ( ힽ → 丨ᅣᅩ ) HANGUL JUNGSEONG I-YA-O → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG YA, HANGUL JUNGSEONG O\t# →ᅵᅣᅩ→\n\nD7BE ;\t4E28 1163 4E28 ;\tMA\t# ( ힾ → 丨ᅣ丨 ) HANGUL JUNGSEONG I-YAE → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG YA, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅵᅣᅵ→\n\nD7BF ;\t4E28 1167 ;\tMA\t# ( ힿ → 丨ᅧ ) HANGUL JUNGSEONG I-YEO → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG YEO\t# →ᅵᅧ→\n\nD7C0 ;\t4E28 1167 4E28 ;\tMA\t# ( ퟀ → 丨ᅧ丨 ) HANGUL JUNGSEONG I-YE → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG YEO, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅵᅧᅵ→\n\n119A ;\t4E28 1169 ;\tMA\t# ( ᆚ → 丨ᅩ ) HANGUL JUNGSEONG I-O → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG O\t# →ᅵᅩ→\n\nD7C1 ;\t4E28 1169 4E28 ;\tMA\t# ( ퟁ → 丨ᅩ丨 ) HANGUL JUNGSEONG I-O-I → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG O, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅵᅩᅵ→\n\nD7C2 ;\t4E28 116D ;\tMA\t# ( ퟂ → 丨ᅭ ) HANGUL JUNGSEONG I-YO → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG YO\t# →ᅵᅭ→\n\n119B ;\t4E28 116E ;\tMA\t# ( ᆛ → 丨ᅮ ) HANGUL JUNGSEONG I-U → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG U\t# →ᅵᅮ→\n\nD7C3 ;\t4E28 1172 ;\tMA\t# ( ퟃ → 丨ᅲ ) HANGUL JUNGSEONG I-YU → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG YU\t# →ᅵᅲ→\n\n119D ;\t4E28 119E ;\tMA\t# ( ᆝ → 丨ᆞ ) HANGUL JUNGSEONG I-ARAEA → CJK UNIFIED IDEOGRAPH-4E28, HANGUL JUNGSEONG ARAEA\t# →ᅵᆞ→\n\nD7C4 ;\t4E28 4E28 ;\tMA\t# ( ퟄ → 丨丨 ) HANGUL JUNGSEONG I-I → CJK UNIFIED IDEOGRAPH-4E28, CJK UNIFIED IDEOGRAPH-4E28\t# →ᅵᅵ→\n\nF905 ;\t4E32 ;\tMA\t# ( 串 → 串 ) CJK COMPATIBILITY IDEOGRAPH-F905 → CJK UNIFIED IDEOGRAPH-4E32\t# \n\n2F801 ;\t4E38 ;\tMA\t# ( 丸 → 丸 ) CJK COMPATIBILITY IDEOGRAPH-2F801 → CJK UNIFIED IDEOGRAPH-4E38\t# \n\nF95E ;\t4E39 ;\tMA\t# ( 丹 → 丹 ) CJK COMPATIBILITY IDEOGRAPH-F95E → CJK UNIFIED IDEOGRAPH-4E39\t# \n\n2F802 ;\t4E41 ;\tMA\t# ( 乁 → 乁 ) CJK COMPATIBILITY IDEOGRAPH-2F802 → CJK UNIFIED IDEOGRAPH-4E41\t# \n\n31E0 ;\t4E59 ;\tMA\t#* ( ㇠ → 乙 ) CJK STROKE HXWG → CJK UNIFIED IDEOGRAPH-4E59\t# \n2F04 ;\t4E59 ;\tMA\t#* ( ⼄ → 乙 ) KANGXI RADICAL SECOND → CJK UNIFIED IDEOGRAPH-4E59\t# \n\n31DF ;\t4E5A ;\tMA\t#* ( ㇟ → 乚 ) CJK STROKE SWG → CJK UNIFIED IDEOGRAPH-4E5A\t# \n2E83 ;\t4E5A ;\tMA\t#* ( ⺃ → 乚 ) CJK RADICAL SECOND TWO → CJK UNIFIED IDEOGRAPH-4E5A\t# \n\n31D6 ;\t4E5B ;\tMA\t#* ( ㇖ → 乛 ) CJK STROKE HG → CJK UNIFIED IDEOGRAPH-4E5B\t# \n2E82 ;\t4E5B ;\tMA\t#* ( ⺂ → 乛 ) CJK RADICAL SECOND ONE → CJK UNIFIED IDEOGRAPH-4E5B\t# →㇖→\n\n2EF2 ;\t4E80 ;\tMA\t#* ( ⻲ → 亀 ) CJK RADICAL J-SIMPLIFIED TURTLE → CJK UNIFIED IDEOGRAPH-4E80\t# \n\nF91B ;\t4E82 ;\tMA\t# ( 亂 → 亂 ) CJK COMPATIBILITY IDEOGRAPH-F91B → CJK UNIFIED IDEOGRAPH-4E82\t# \n\n31DA ;\t4E85 ;\tMA\t#* ( ㇚ → 亅 ) CJK STROKE SG → CJK UNIFIED IDEOGRAPH-4E85\t# \n2F05 ;\t4E85 ;\tMA\t#* ( ⼅ → 亅 ) KANGXI RADICAL HOOK → CJK UNIFIED IDEOGRAPH-4E85\t# \n\nF9BA ;\t4E86 ;\tMA\t# ( 了 → 了 ) CJK COMPATIBILITY IDEOGRAPH-F9BA → CJK UNIFIED IDEOGRAPH-4E86\t# \n\n30CB ;\t4E8C ;\tMA\t# ( ニ → 二 ) KATAKANA LETTER NI → CJK UNIFIED IDEOGRAPH-4E8C\t# \n2F06 ;\t4E8C ;\tMA\t#* ( ⼆ → 二 ) KANGXI RADICAL TWO → CJK UNIFIED IDEOGRAPH-4E8C\t# \n\n2F803 ;\t20122 ;\tMA\t# ( 𠄢 → 𠄢 ) CJK COMPATIBILITY IDEOGRAPH-2F803 → CJK UNIFIED IDEOGRAPH-20122\t# \n\n2F07 ;\t4EA0 ;\tMA\t#* ( ⼇ → 亠 ) KANGXI RADICAL LID → CJK UNIFIED IDEOGRAPH-4EA0\t# \n\nF977 ;\t4EAE ;\tMA\t# ( 亮 → 亮 ) CJK COMPATIBILITY IDEOGRAPH-F977 → CJK UNIFIED IDEOGRAPH-4EAE\t# \n\n2F08 ;\t4EBA ;\tMA\t#* ( ⼈ → 人 ) KANGXI RADICAL MAN → CJK UNIFIED IDEOGRAPH-4EBA\t# \n\n30A4 ;\t4EBB ;\tMA\t# ( イ → 亻 ) KATAKANA LETTER I → CJK UNIFIED IDEOGRAPH-4EBB\t# →⺅→\n2E85 ;\t4EBB ;\tMA\t#* ( ⺅ → 亻 ) CJK RADICAL PERSON → CJK UNIFIED IDEOGRAPH-4EBB\t# \n\nF9FD ;\t4EC0 ;\tMA\t# ( 什 → 什 ) CJK COMPATIBILITY IDEOGRAPH-F9FD → CJK UNIFIED IDEOGRAPH-4EC0\t# \n\n2F819 ;\t4ECC ;\tMA\t# ( 仌 → 仌 ) CJK COMPATIBILITY IDEOGRAPH-2F819 → CJK UNIFIED IDEOGRAPH-4ECC\t# \n\nF9A8 ;\t4EE4 ;\tMA\t# ( 令 → 令 ) CJK COMPATIBILITY IDEOGRAPH-F9A8 → CJK UNIFIED IDEOGRAPH-4EE4\t# \n\n2F804 ;\t4F60 ;\tMA\t# ( 你 → 你 ) CJK COMPATIBILITY IDEOGRAPH-2F804 → CJK UNIFIED IDEOGRAPH-4F60\t# \n\n5002 ;\t4F75 ;\tMA\t# ( 倂 → 併 ) CJK UNIFIED IDEOGRAPH-5002 → CJK UNIFIED IDEOGRAPH-4F75\t# \n2F807 ;\t4F75 ;\tMA\t# ( 倂 → 併 ) CJK COMPATIBILITY IDEOGRAPH-2F807 → CJK UNIFIED IDEOGRAPH-4F75\t# →倂→\n\nFA73 ;\t4F80 ;\tMA\t# ( 侀 → 侀 ) CJK COMPATIBILITY IDEOGRAPH-FA73 → CJK UNIFIED IDEOGRAPH-4F80\t# \n\nF92D ;\t4F86 ;\tMA\t# ( 來 → 來 ) CJK COMPATIBILITY IDEOGRAPH-F92D → CJK UNIFIED IDEOGRAPH-4F86\t# \n\nF9B5 ;\t4F8B ;\tMA\t# ( 例 → 例 ) CJK COMPATIBILITY IDEOGRAPH-F9B5 → CJK UNIFIED IDEOGRAPH-4F8B\t# \n\nFA30 ;\t4FAE ;\tMA\t# ( 侮 → 侮 ) CJK COMPATIBILITY IDEOGRAPH-FA30 → CJK UNIFIED IDEOGRAPH-4FAE\t# \n2F805 ;\t4FAE ;\tMA\t# ( 侮 → 侮 ) CJK COMPATIBILITY IDEOGRAPH-2F805 → CJK UNIFIED IDEOGRAPH-4FAE\t# \n\n2F806 ;\t4FBB ;\tMA\t# ( 侻 → 侻 ) CJK COMPATIBILITY IDEOGRAPH-2F806 → CJK UNIFIED IDEOGRAPH-4FBB\t# \n\nF965 ;\t4FBF ;\tMA\t# ( 便 → 便 ) CJK COMPATIBILITY IDEOGRAPH-F965 → CJK UNIFIED IDEOGRAPH-4FBF\t# \n\n503C ;\t5024 ;\tMA\t# ( 值 → 値 ) CJK UNIFIED IDEOGRAPH-503C → CJK UNIFIED IDEOGRAPH-5024\t# \n\nF9D4 ;\t502B ;\tMA\t# ( 倫 → 倫 ) CJK COMPATIBILITY IDEOGRAPH-F9D4 → CJK UNIFIED IDEOGRAPH-502B\t# \n\n2F808 ;\t507A ;\tMA\t# ( 偺 → 偺 ) CJK COMPATIBILITY IDEOGRAPH-2F808 → CJK UNIFIED IDEOGRAPH-507A\t# \n\n2F809 ;\t5099 ;\tMA\t# ( 備 → 備 ) CJK COMPATIBILITY IDEOGRAPH-2F809 → CJK UNIFIED IDEOGRAPH-5099\t# \n\n2F80B ;\t50CF ;\tMA\t# ( 像 → 像 ) CJK COMPATIBILITY IDEOGRAPH-2F80B → CJK UNIFIED IDEOGRAPH-50CF\t# \n\nF9BB ;\t50DA ;\tMA\t# ( 僚 → 僚 ) CJK COMPATIBILITY IDEOGRAPH-F9BB → CJK UNIFIED IDEOGRAPH-50DA\t# \n\nFA31 ;\t50E7 ;\tMA\t# ( 僧 → 僧 ) CJK COMPATIBILITY IDEOGRAPH-FA31 → CJK UNIFIED IDEOGRAPH-50E7\t# \n2F80A ;\t50E7 ;\tMA\t# ( 僧 → 僧 ) CJK COMPATIBILITY IDEOGRAPH-2F80A → CJK UNIFIED IDEOGRAPH-50E7\t# \n\n2F80C ;\t349E ;\tMA\t# ( 㒞 → 㒞 ) CJK COMPATIBILITY IDEOGRAPH-2F80C → CJK UNIFIED IDEOGRAPH-349E\t# \n\n3126 ;\t513F ;\tMA\t# ( ㄦ → 儿 ) BOPOMOFO LETTER ER → CJK UNIFIED IDEOGRAPH-513F\t# \n2F09 ;\t513F ;\tMA\t#* ( ⼉ → 儿 ) KANGXI RADICAL LEGS → CJK UNIFIED IDEOGRAPH-513F\t# \n16FF2 ;\t513F ;\tMA\t# ( 𖿲 → 儿 ) CHINESE SMALL SIMPLIFIED ER → CJK UNIFIED IDEOGRAPH-513F\t# \n\nFA0C ;\t5140 ;\tMA\t# ( 兀 → 兀 ) CJK COMPATIBILITY IDEOGRAPH-FA0C → CJK UNIFIED IDEOGRAPH-5140\t# \n2E8E ;\t5140 ;\tMA\t#* ( ⺎ → 兀 ) CJK RADICAL LAME ONE → CJK UNIFIED IDEOGRAPH-5140\t# \n\nFA74 ;\t5145 ;\tMA\t# ( 充 → 充 ) CJK COMPATIBILITY IDEOGRAPH-FA74 → CJK UNIFIED IDEOGRAPH-5145\t# \n\nFA32 ;\t514D ;\tMA\t# ( 免 → 免 ) CJK COMPATIBILITY IDEOGRAPH-FA32 → CJK UNIFIED IDEOGRAPH-514D\t# \n2F80E ;\t514D ;\tMA\t# ( 免 → 免 ) CJK COMPATIBILITY IDEOGRAPH-2F80E → CJK UNIFIED IDEOGRAPH-514D\t# \n\n2F80F ;\t5154 ;\tMA\t# ( 兔 → 兔 ) CJK COMPATIBILITY IDEOGRAPH-2F80F → CJK UNIFIED IDEOGRAPH-5154\t# \n\n2F810 ;\t5164 ;\tMA\t# ( 兤 → 兤 ) CJK COMPATIBILITY IDEOGRAPH-2F810 → CJK UNIFIED IDEOGRAPH-5164\t# \n\n2F0A ;\t5165 ;\tMA\t#* ( ⼊ → 入 ) KANGXI RADICAL ENTER → CJK UNIFIED IDEOGRAPH-5165\t# \n\n2F814 ;\t5167 ;\tMA\t# ( 內 → 內 ) CJK COMPATIBILITY IDEOGRAPH-2F814 → CJK UNIFIED IDEOGRAPH-5167\t# \n\nFA72 ;\t5168 ;\tMA\t# ( 全 → 全 ) CJK COMPATIBILITY IDEOGRAPH-FA72 → CJK UNIFIED IDEOGRAPH-5168\t# \n\nF978 ;\t5169 ;\tMA\t# ( 兩 → 兩 ) CJK COMPATIBILITY IDEOGRAPH-F978 → CJK UNIFIED IDEOGRAPH-5169\t# \n\n30CF ;\t516B ;\tMA\t# ( ハ → 八 ) KATAKANA LETTER HA → CJK UNIFIED IDEOGRAPH-516B\t# \n2F0B ;\t516B ;\tMA\t#* ( ⼋ → 八 ) KANGXI RADICAL EIGHT → CJK UNIFIED IDEOGRAPH-516B\t# \n\nF9D1 ;\t516D ;\tMA\t# ( 六 → 六 ) CJK COMPATIBILITY IDEOGRAPH-F9D1 → CJK UNIFIED IDEOGRAPH-516D\t# \n\n2F811 ;\t5177 ;\tMA\t# ( 具 → 具 ) CJK COMPATIBILITY IDEOGRAPH-2F811 → CJK UNIFIED IDEOGRAPH-5177\t# \n\n2F812 ;\t2051C ;\tMA\t# ( 𠔜 → 𠔜 ) CJK COMPATIBILITY IDEOGRAPH-2F812 → CJK UNIFIED IDEOGRAPH-2051C\t# \n\n2F91B ;\t20525 ;\tMA\t# ( 𠔥 → 𠔥 ) CJK COMPATIBILITY IDEOGRAPH-2F91B → CJK UNIFIED IDEOGRAPH-20525\t# \n\nFA75 ;\t5180 ;\tMA\t# ( 冀 → 冀 ) CJK COMPATIBILITY IDEOGRAPH-FA75 → CJK UNIFIED IDEOGRAPH-5180\t# \n\n2F813 ;\t34B9 ;\tMA\t# ( 㒹 → 㒹 ) CJK COMPATIBILITY IDEOGRAPH-2F813 → CJK UNIFIED IDEOGRAPH-34B9\t# \n\n2F0C ;\t5182 ;\tMA\t#* ( ⼌ → 冂 ) KANGXI RADICAL DOWN BOX → CJK UNIFIED IDEOGRAPH-5182\t# \n\n2F815 ;\t518D ;\tMA\t# ( 再 → 再 ) CJK COMPATIBILITY IDEOGRAPH-2F815 → CJK UNIFIED IDEOGRAPH-518D\t# \n\n2F816 ;\t2054B ;\tMA\t# ( 𠕋 → 𠕋 ) CJK COMPATIBILITY IDEOGRAPH-2F816 → CJK UNIFIED IDEOGRAPH-2054B\t# \n\n2F8D2 ;\t5192 ;\tMA\t# ( 冒 → 冒 ) CJK COMPATIBILITY IDEOGRAPH-2F8D2 → CJK UNIFIED IDEOGRAPH-5192\t# \n\n2F8D3 ;\t5195 ;\tMA\t# ( 冕 → 冕 ) CJK COMPATIBILITY IDEOGRAPH-2F8D3 → CJK UNIFIED IDEOGRAPH-5195\t# \n\n2F9CA ;\t34BB ;\tMA\t# ( 㒻 → 㒻 ) CJK COMPATIBILITY IDEOGRAPH-2F9CA → CJK UNIFIED IDEOGRAPH-34BB\t# \n\n2F8D4 ;\t6700 ;\tMA\t# ( 最 → 最 ) CJK COMPATIBILITY IDEOGRAPH-2F8D4 → CJK UNIFIED IDEOGRAPH-6700\t# \n\n2F0D ;\t5196 ;\tMA\t#* ( ⼍ → 冖 ) KANGXI RADICAL COVER → CJK UNIFIED IDEOGRAPH-5196\t# \n\n2F817 ;\t5197 ;\tMA\t# ( 冗 → 冗 ) CJK COMPATIBILITY IDEOGRAPH-2F817 → CJK UNIFIED IDEOGRAPH-5197\t# \n\n2F818 ;\t51A4 ;\tMA\t# ( 冤 → 冤 ) CJK COMPATIBILITY IDEOGRAPH-2F818 → CJK UNIFIED IDEOGRAPH-51A4\t# \n\n2F0E ;\t51AB ;\tMA\t#* ( ⼎ → 冫 ) KANGXI RADICAL ICE → CJK UNIFIED IDEOGRAPH-51AB\t# \n\n2F81A ;\t51AC ;\tMA\t# ( 冬 → 冬 ) CJK COMPATIBILITY IDEOGRAPH-2F81A → CJK UNIFIED IDEOGRAPH-51AC\t# \n\nFA71 ;\t51B5 ;\tMA\t# ( 况 → 况 ) CJK COMPATIBILITY IDEOGRAPH-FA71 → CJK UNIFIED IDEOGRAPH-51B5\t# \n2F81B ;\t51B5 ;\tMA\t# ( 况 → 况 ) CJK COMPATIBILITY IDEOGRAPH-2F81B → CJK UNIFIED IDEOGRAPH-51B5\t# \n\nF92E ;\t51B7 ;\tMA\t# ( 冷 → 冷 ) CJK COMPATIBILITY IDEOGRAPH-F92E → CJK UNIFIED IDEOGRAPH-51B7\t# \n\nF979 ;\t51C9 ;\tMA\t# ( 凉 → 凉 ) CJK COMPATIBILITY IDEOGRAPH-F979 → CJK UNIFIED IDEOGRAPH-51C9\t# \n\nF955 ;\t51CC ;\tMA\t# ( 凌 → 凌 ) CJK COMPATIBILITY IDEOGRAPH-F955 → CJK UNIFIED IDEOGRAPH-51CC\t# \n\nF954 ;\t51DC ;\tMA\t# ( 凜 → 凜 ) CJK COMPATIBILITY IDEOGRAPH-F954 → CJK UNIFIED IDEOGRAPH-51DC\t# \n\nFA15 ;\t51DE ;\tMA\t# ( 凞 → 凞 ) CJK COMPATIBILITY IDEOGRAPH-FA15 → CJK UNIFIED IDEOGRAPH-51DE\t# \n\n2F0F ;\t51E0 ;\tMA\t#* ( ⼏ → 几 ) KANGXI RADICAL TABLE → CJK UNIFIED IDEOGRAPH-51E0\t# \n\n2F80D ;\t2063A ;\tMA\t# ( 𠘺 → 𠘺 ) CJK COMPATIBILITY IDEOGRAPH-2F80D → CJK UNIFIED IDEOGRAPH-2063A\t# \n\n2F81D ;\t51F5 ;\tMA\t# ( 凵 → 凵 ) CJK COMPATIBILITY IDEOGRAPH-2F81D → CJK UNIFIED IDEOGRAPH-51F5\t# \n2F10 ;\t51F5 ;\tMA\t#* ( ⼐ → 凵 ) KANGXI RADICAL OPEN BOX → CJK UNIFIED IDEOGRAPH-51F5\t# \n20674 ;\t51F5 ;\tMA\t# ( 𠙴 → 凵 ) CJK UNIFIED IDEOGRAPH-20674 → CJK UNIFIED IDEOGRAPH-51F5\t# →凵→\n\n2F11 ;\t5200 ;\tMA\t#* ( ⼑ → 刀 ) KANGXI RADICAL KNIFE → CJK UNIFIED IDEOGRAPH-5200\t# \n\n2E89 ;\t5202 ;\tMA\t#* ( ⺉ → 刂 ) CJK RADICAL KNIFE TWO → CJK UNIFIED IDEOGRAPH-5202\t# \n\n2F81E ;\t5203 ;\tMA\t# ( 刃 → 刃 ) CJK COMPATIBILITY IDEOGRAPH-2F81E → CJK UNIFIED IDEOGRAPH-5203\t# \n\nFA00 ;\t5207 ;\tMA\t# ( 切 → 切 ) CJK COMPATIBILITY IDEOGRAPH-FA00 → CJK UNIFIED IDEOGRAPH-5207\t# \n2F850 ;\t5207 ;\tMA\t# ( 切 → 切 ) CJK COMPATIBILITY IDEOGRAPH-2F850 → CJK UNIFIED IDEOGRAPH-5207\t# \n\nF99C ;\t5217 ;\tMA\t# ( 列 → 列 ) CJK COMPATIBILITY IDEOGRAPH-F99C → CJK UNIFIED IDEOGRAPH-5217\t# \n\nF9DD ;\t5229 ;\tMA\t# ( 利 → 利 ) CJK COMPATIBILITY IDEOGRAPH-F9DD → CJK UNIFIED IDEOGRAPH-5229\t# \n\n2F81F ;\t34DF ;\tMA\t# ( 㓟 → 㓟 ) CJK COMPATIBILITY IDEOGRAPH-2F81F → CJK UNIFIED IDEOGRAPH-34DF\t# \n\nF9FF ;\t523A ;\tMA\t# ( 刺 → 刺 ) CJK COMPATIBILITY IDEOGRAPH-F9FF → CJK UNIFIED IDEOGRAPH-523A\t# \n\n2F820 ;\t523B ;\tMA\t# ( 刻 → 刻 ) CJK COMPATIBILITY IDEOGRAPH-2F820 → CJK UNIFIED IDEOGRAPH-523B\t# \n\n2F821 ;\t5246 ;\tMA\t# ( 剆 → 剆 ) CJK COMPATIBILITY IDEOGRAPH-2F821 → CJK UNIFIED IDEOGRAPH-5246\t# \n\n2F822 ;\t5272 ;\tMA\t# ( 割 → 割 ) CJK COMPATIBILITY IDEOGRAPH-2F822 → CJK UNIFIED IDEOGRAPH-5272\t# \n\n2F823 ;\t5277 ;\tMA\t# ( 剷 → 剷 ) CJK COMPATIBILITY IDEOGRAPH-2F823 → CJK UNIFIED IDEOGRAPH-5277\t# \n\nF9C7 ;\t5289 ;\tMA\t# ( 劉 → 劉 ) CJK COMPATIBILITY IDEOGRAPH-F9C7 → CJK UNIFIED IDEOGRAPH-5289\t# \n\n2F9D9 ;\t20804 ;\tMA\t# ( 𠠄 → 𠠄 ) CJK COMPATIBILITY IDEOGRAPH-2F9D9 → CJK UNIFIED IDEOGRAPH-20804\t# \n\n30AB ;\t529B ;\tMA\t# ( カ → 力 ) KATAKANA LETTER KA → CJK UNIFIED IDEOGRAPH-529B\t# →⼒→\nF98A ;\t529B ;\tMA\t# ( 力 → 力 ) CJK COMPATIBILITY IDEOGRAPH-F98A → CJK UNIFIED IDEOGRAPH-529B\t# \n2F12 ;\t529B ;\tMA\t#* ( ⼒ → 力 ) KANGXI RADICAL POWER → CJK UNIFIED IDEOGRAPH-529B\t# \n\nF99D ;\t52A3 ;\tMA\t# ( 劣 → 劣 ) CJK COMPATIBILITY IDEOGRAPH-F99D → CJK UNIFIED IDEOGRAPH-52A3\t# \n\n2F824 ;\t3515 ;\tMA\t# ( 㔕 → 㔕 ) CJK COMPATIBILITY IDEOGRAPH-2F824 → CJK UNIFIED IDEOGRAPH-3515\t# \n\n2F992 ;\t52B3 ;\tMA\t# ( 劳 → 劳 ) CJK COMPATIBILITY IDEOGRAPH-2F992 → CJK UNIFIED IDEOGRAPH-52B3\t# \n\nFA76 ;\t52C7 ;\tMA\t# ( 勇 → 勇 ) CJK COMPATIBILITY IDEOGRAPH-FA76 → CJK UNIFIED IDEOGRAPH-52C7\t# \n2F825 ;\t52C7 ;\tMA\t# ( 勇 → 勇 ) CJK COMPATIBILITY IDEOGRAPH-2F825 → CJK UNIFIED IDEOGRAPH-52C7\t# \n\nFA33 ;\t52C9 ;\tMA\t# ( 勉 → 勉 ) CJK COMPATIBILITY IDEOGRAPH-FA33 → CJK UNIFIED IDEOGRAPH-52C9\t# \n2F826 ;\t52C9 ;\tMA\t# ( 勉 → 勉 ) CJK COMPATIBILITY IDEOGRAPH-2F826 → CJK UNIFIED IDEOGRAPH-52C9\t# \n\nF952 ;\t52D2 ;\tMA\t# ( 勒 → 勒 ) CJK COMPATIBILITY IDEOGRAPH-F952 → CJK UNIFIED IDEOGRAPH-52D2\t# \n\nF92F ;\t52DE ;\tMA\t# ( 勞 → 勞 ) CJK COMPATIBILITY IDEOGRAPH-F92F → CJK UNIFIED IDEOGRAPH-52DE\t# \n\nFA34 ;\t52E4 ;\tMA\t# ( 勤 → 勤 ) CJK COMPATIBILITY IDEOGRAPH-FA34 → CJK UNIFIED IDEOGRAPH-52E4\t# \n2F827 ;\t52E4 ;\tMA\t# ( 勤 → 勤 ) CJK COMPATIBILITY IDEOGRAPH-2F827 → CJK UNIFIED IDEOGRAPH-52E4\t# \n\nF97F ;\t52F5 ;\tMA\t# ( 勵 → 勵 ) CJK COMPATIBILITY IDEOGRAPH-F97F → CJK UNIFIED IDEOGRAPH-52F5\t# \n\n2F13 ;\t52F9 ;\tMA\t#* ( ⼓ → 勹 ) KANGXI RADICAL WRAP → CJK UNIFIED IDEOGRAPH-52F9\t# \n\nFA77 ;\t52FA ;\tMA\t# ( 勺 → 勺 ) CJK COMPATIBILITY IDEOGRAPH-FA77 → CJK UNIFIED IDEOGRAPH-52FA\t# \n2F828 ;\t52FA ;\tMA\t# ( 勺 → 勺 ) CJK COMPATIBILITY IDEOGRAPH-2F828 → CJK UNIFIED IDEOGRAPH-52FA\t# \n\n2F829 ;\t5305 ;\tMA\t# ( 包 → 包 ) CJK COMPATIBILITY IDEOGRAPH-2F829 → CJK UNIFIED IDEOGRAPH-5305\t# \n\n2F82A ;\t5306 ;\tMA\t# ( 匆 → 匆 ) CJK COMPATIBILITY IDEOGRAPH-2F82A → CJK UNIFIED IDEOGRAPH-5306\t# \n\n2F9DD ;\t208DE ;\tMA\t# ( 𠣞 → 𠣞 ) CJK COMPATIBILITY IDEOGRAPH-2F9DD → CJK UNIFIED IDEOGRAPH-208DE\t# \n\n2F14 ;\t5315 ;\tMA\t#* ( ⼔ → 匕 ) KANGXI RADICAL SPOON → CJK UNIFIED IDEOGRAPH-5315\t# \n\nF963 ;\t5317 ;\tMA\t# ( 北 → 北 ) CJK COMPATIBILITY IDEOGRAPH-F963 → CJK UNIFIED IDEOGRAPH-5317\t# \n2F82B ;\t5317 ;\tMA\t# ( 北 → 北 ) CJK COMPATIBILITY IDEOGRAPH-2F82B → CJK UNIFIED IDEOGRAPH-5317\t# \n\n2F15 ;\t531A ;\tMA\t#* ( ⼕ → 匚 ) KANGXI RADICAL RIGHT OPEN BOX → CJK UNIFIED IDEOGRAPH-531A\t# \n\n2F16 ;\t5338 ;\tMA\t#* ( ⼖ → 匸 ) KANGXI RADICAL HIDING ENCLOSURE → CJK UNIFIED IDEOGRAPH-5338\t# \n\nF9EB ;\t533F ;\tMA\t# ( 匿 → 匿 ) CJK COMPATIBILITY IDEOGRAPH-F9EB → CJK UNIFIED IDEOGRAPH-533F\t# \n\n2F17 ;\t5341 ;\tMA\t#* ( ⼗ → 十 ) KANGXI RADICAL TEN → CJK UNIFIED IDEOGRAPH-5341\t# \n3038 ;\t5341 ;\tMA\t# ( 〸 → 十 ) HANGZHOU NUMERAL TEN → CJK UNIFIED IDEOGRAPH-5341\t# \n\n303A ;\t5345 ;\tMA\t# ( 〺 → 卅 ) HANGZHOU NUMERAL THIRTY → CJK UNIFIED IDEOGRAPH-5345\t# \n\n2F82C ;\t5349 ;\tMA\t# ( 卉 → 卉 ) CJK COMPATIBILITY IDEOGRAPH-2F82C → CJK UNIFIED IDEOGRAPH-5349\t# \n\n0FD6 ;\t534D ;\tMA\t#* ( ࿖ → 卍 ) LEFT-FACING SVASTI SIGN → CJK UNIFIED IDEOGRAPH-534D\t# \n\n0FD5 ;\t5350 ;\tMA\t#* ( ࿕ → 卐 ) RIGHT-FACING SVASTI SIGN → CJK UNIFIED IDEOGRAPH-5350\t# \n\nFA35 ;\t5351 ;\tMA\t# ( 卑 → 卑 ) CJK COMPATIBILITY IDEOGRAPH-FA35 → CJK UNIFIED IDEOGRAPH-5351\t# \n2F82D ;\t5351 ;\tMA\t# ( 卑 → 卑 ) CJK COMPATIBILITY IDEOGRAPH-2F82D → CJK UNIFIED IDEOGRAPH-5351\t# \n2D161 ;\t5351 ;\tMA\t# ( 𭅡 → 卑 ) CJK UNIFIED IDEOGRAPH-2D161 → CJK UNIFIED IDEOGRAPH-5351\t# →卑→\n\n2F82E ;\t535A ;\tMA\t# ( 博 → 博 ) CJK COMPATIBILITY IDEOGRAPH-2F82E → CJK UNIFIED IDEOGRAPH-535A\t# \n\n30C8 ;\t535C ;\tMA\t# ( ト → 卜 ) KATAKANA LETTER TO → CJK UNIFIED IDEOGRAPH-535C\t# →⼘→\n2F18 ;\t535C ;\tMA\t#* ( ⼘ → 卜 ) KANGXI RADICAL DIVINATION → CJK UNIFIED IDEOGRAPH-535C\t# \n\n2F19 ;\t5369 ;\tMA\t#* ( ⼙ → 卩 ) KANGXI RADICAL SEAL → CJK UNIFIED IDEOGRAPH-5369\t# \n\n2E8B ;\t353E ;\tMA\t#* ( ⺋ → 㔾 ) CJK RADICAL SEAL → CJK UNIFIED IDEOGRAPH-353E\t# \n\n2F82F ;\t5373 ;\tMA\t# ( 即 → 即 ) CJK COMPATIBILITY IDEOGRAPH-2F82F → CJK UNIFIED IDEOGRAPH-5373\t# \n\nF91C ;\t5375 ;\tMA\t# ( 卵 → 卵 ) CJK COMPATIBILITY IDEOGRAPH-F91C → CJK UNIFIED IDEOGRAPH-5375\t# \n\n2F830 ;\t537D ;\tMA\t# ( 卽 → 卽 ) CJK COMPATIBILITY IDEOGRAPH-2F830 → CJK UNIFIED IDEOGRAPH-537D\t# \n\n2F831 ;\t537F ;\tMA\t# ( 卿 → 卿 ) CJK COMPATIBILITY IDEOGRAPH-2F831 → CJK UNIFIED IDEOGRAPH-537F\t# \n2F832 ;\t537F ;\tMA\t# ( 卿 → 卿 ) CJK COMPATIBILITY IDEOGRAPH-2F832 → CJK UNIFIED IDEOGRAPH-537F\t# \n2F833 ;\t537F ;\tMA\t# ( 卿 → 卿 ) CJK COMPATIBILITY IDEOGRAPH-2F833 → CJK UNIFIED IDEOGRAPH-537F\t# \n\n2F1A ;\t5382 ;\tMA\t#* ( ⼚ → 厂 ) KANGXI RADICAL CLIFF → CJK UNIFIED IDEOGRAPH-5382\t# \n\n2F834 ;\t20A2C ;\tMA\t# ( 𠨬 → 𠨬 ) CJK COMPATIBILITY IDEOGRAPH-2F834 → CJK UNIFIED IDEOGRAPH-20A2C\t# \n\n2F1B ;\t53B6 ;\tMA\t#* ( ⼛ → 厶 ) KANGXI RADICAL PRIVATE → CJK UNIFIED IDEOGRAPH-53B6\t# \n\nF96B ;\t53C3 ;\tMA\t# ( 參 → 參 ) CJK COMPATIBILITY IDEOGRAPH-F96B → CJK UNIFIED IDEOGRAPH-53C3\t# \n\n2F1C ;\t53C8 ;\tMA\t#* ( ⼜ → 又 ) KANGXI RADICAL AGAIN → CJK UNIFIED IDEOGRAPH-53C8\t# \n\n2F836 ;\t53CA ;\tMA\t# ( 及 → 及 ) CJK COMPATIBILITY IDEOGRAPH-2F836 → CJK UNIFIED IDEOGRAPH-53CA\t# \n\n2F837 ;\t53DF ;\tMA\t# ( 叟 → 叟 ) CJK COMPATIBILITY IDEOGRAPH-2F837 → CJK UNIFIED IDEOGRAPH-53DF\t# \n\n2F838 ;\t20B63 ;\tMA\t# ( 𠭣 → 𠭣 ) CJK COMPATIBILITY IDEOGRAPH-2F838 → CJK UNIFIED IDEOGRAPH-20B63\t# \n\n30ED ;\t53E3 ;\tMA\t# ( ロ → 口 ) KATAKANA LETTER RO → CJK UNIFIED IDEOGRAPH-53E3\t# →⼞→→⼝→\n2F1D ;\t53E3 ;\tMA\t#* ( ⼝ → 口 ) KANGXI RADICAL MOUTH → CJK UNIFIED IDEOGRAPH-53E3\t# \n56D7 ;\t53E3 ;\tMA\t# ( 囗 → 口 ) CJK UNIFIED IDEOGRAPH-56D7 → CJK UNIFIED IDEOGRAPH-53E3\t# →⼞→→⼝→\n2F1E ;\t53E3 ;\tMA\t#* ( ⼞ → 口 ) KANGXI RADICAL ENCLOSURE → CJK UNIFIED IDEOGRAPH-53E3\t# →⼝→\n\nF906 ;\t53E5 ;\tMA\t# ( 句 → 句 ) CJK COMPATIBILITY IDEOGRAPH-F906 → CJK UNIFIED IDEOGRAPH-53E5\t# \n\n2F839 ;\t53EB ;\tMA\t# ( 叫 → 叫 ) CJK COMPATIBILITY IDEOGRAPH-2F839 → CJK UNIFIED IDEOGRAPH-53EB\t# \n\n2F83A ;\t53F1 ;\tMA\t# ( 叱 → 叱 ) CJK COMPATIBILITY IDEOGRAPH-2F83A → CJK UNIFIED IDEOGRAPH-53F1\t# \n\n2F83B ;\t5406 ;\tMA\t# ( 吆 → 吆 ) CJK COMPATIBILITY IDEOGRAPH-2F83B → CJK UNIFIED IDEOGRAPH-5406\t# \n\nF9DE ;\t540F ;\tMA\t# ( 吏 → 吏 ) CJK COMPATIBILITY IDEOGRAPH-F9DE → CJK UNIFIED IDEOGRAPH-540F\t# \n\nF9ED ;\t541D ;\tMA\t# ( 吝 → 吝 ) CJK COMPATIBILITY IDEOGRAPH-F9ED → CJK UNIFIED IDEOGRAPH-541D\t# \n\n2F83D ;\t5438 ;\tMA\t# ( 吸 → 吸 ) CJK COMPATIBILITY IDEOGRAPH-2F83D → CJK UNIFIED IDEOGRAPH-5438\t# \n\nF980 ;\t5442 ;\tMA\t# ( 呂 → 呂 ) CJK COMPATIBILITY IDEOGRAPH-F980 → CJK UNIFIED IDEOGRAPH-5442\t# \n\n2F83E ;\t5448 ;\tMA\t# ( 呈 → 呈 ) CJK COMPATIBILITY IDEOGRAPH-2F83E → CJK UNIFIED IDEOGRAPH-5448\t# \n\n2F83F ;\t5468 ;\tMA\t# ( 周 → 周 ) CJK COMPATIBILITY IDEOGRAPH-2F83F → CJK UNIFIED IDEOGRAPH-5468\t# \n\n2F83C ;\t549E ;\tMA\t# ( 咞 → 咞 ) CJK COMPATIBILITY IDEOGRAPH-2F83C → CJK UNIFIED IDEOGRAPH-549E\t# \n\n2F840 ;\t54A2 ;\tMA\t# ( 咢 → 咢 ) CJK COMPATIBILITY IDEOGRAPH-2F840 → CJK UNIFIED IDEOGRAPH-54A2\t# \n\nF99E ;\t54BD ;\tMA\t# ( 咽 → 咽 ) CJK COMPATIBILITY IDEOGRAPH-F99E → CJK UNIFIED IDEOGRAPH-54BD\t# \n\n439B ;\t3588 ;\tMA\t# ( 䎛 → 㖈 ) CJK UNIFIED IDEOGRAPH-439B → CJK UNIFIED IDEOGRAPH-3588\t# \n\n2F841 ;\t54F6 ;\tMA\t# ( 哶 → 哶 ) CJK COMPATIBILITY IDEOGRAPH-2F841 → CJK UNIFIED IDEOGRAPH-54F6\t# \n\n2F842 ;\t5510 ;\tMA\t# ( 唐 → 唐 ) CJK COMPATIBILITY IDEOGRAPH-2F842 → CJK UNIFIED IDEOGRAPH-5510\t# \n\n2F843 ;\t5553 ;\tMA\t# ( 啓 → 啓 ) CJK COMPATIBILITY IDEOGRAPH-2F843 → CJK UNIFIED IDEOGRAPH-5553\t# \n555F ;\t5553 ;\tMA\t# ( 啟 → 啓 ) CJK UNIFIED IDEOGRAPH-555F → CJK UNIFIED IDEOGRAPH-5553\t# \n\nFA79 ;\t5555 ;\tMA\t# ( 啕 → 啕 ) CJK COMPATIBILITY IDEOGRAPH-FA79 → CJK UNIFIED IDEOGRAPH-5555\t# \n\n2F844 ;\t5563 ;\tMA\t# ( 啣 → 啣 ) CJK COMPATIBILITY IDEOGRAPH-2F844 → CJK UNIFIED IDEOGRAPH-5563\t# \n\n2F845 ;\t5584 ;\tMA\t# ( 善 → 善 ) CJK COMPATIBILITY IDEOGRAPH-2F845 → CJK UNIFIED IDEOGRAPH-5584\t# \n2F846 ;\t5584 ;\tMA\t# ( 善 → 善 ) CJK COMPATIBILITY IDEOGRAPH-2F846 → CJK UNIFIED IDEOGRAPH-5584\t# \n\nF90B ;\t5587 ;\tMA\t# ( 喇 → 喇 ) CJK COMPATIBILITY IDEOGRAPH-F90B → CJK UNIFIED IDEOGRAPH-5587\t# \n\nFA7A ;\t5599 ;\tMA\t# ( 喙 → 喙 ) CJK COMPATIBILITY IDEOGRAPH-FA7A → CJK UNIFIED IDEOGRAPH-5599\t# \n2F847 ;\t5599 ;\tMA\t# ( 喙 → 喙 ) CJK COMPATIBILITY IDEOGRAPH-2F847 → CJK UNIFIED IDEOGRAPH-5599\t# \n\nFA36 ;\t559D ;\tMA\t# ( 喝 → 喝 ) CJK COMPATIBILITY IDEOGRAPH-FA36 → CJK UNIFIED IDEOGRAPH-559D\t# \nFA78 ;\t559D ;\tMA\t# ( 喝 → 喝 ) CJK COMPATIBILITY IDEOGRAPH-FA78 → CJK UNIFIED IDEOGRAPH-559D\t# \n\n2F848 ;\t55AB ;\tMA\t# ( 喫 → 喫 ) CJK COMPATIBILITY IDEOGRAPH-2F848 → CJK UNIFIED IDEOGRAPH-55AB\t# \n\n2F849 ;\t55B3 ;\tMA\t# ( 喳 → 喳 ) CJK COMPATIBILITY IDEOGRAPH-2F849 → CJK UNIFIED IDEOGRAPH-55B3\t# \n\nFA0D ;\t55C0 ;\tMA\t# ( 嗀 → 嗀 ) CJK COMPATIBILITY IDEOGRAPH-FA0D → CJK UNIFIED IDEOGRAPH-55C0\t# \n\n2F84A ;\t55C2 ;\tMA\t# ( 嗂 → 嗂 ) CJK COMPATIBILITY IDEOGRAPH-2F84A → CJK UNIFIED IDEOGRAPH-55C2\t# \n\nFA7B ;\t55E2 ;\tMA\t# ( 嗢 → 嗢 ) CJK COMPATIBILITY IDEOGRAPH-FA7B → CJK UNIFIED IDEOGRAPH-55E2\t# \n\nFA37 ;\t5606 ;\tMA\t# ( 嘆 → 嘆 ) CJK COMPATIBILITY IDEOGRAPH-FA37 → CJK UNIFIED IDEOGRAPH-5606\t# \n2F84C ;\t5606 ;\tMA\t# ( 嘆 → 嘆 ) CJK COMPATIBILITY IDEOGRAPH-2F84C → CJK UNIFIED IDEOGRAPH-5606\t# \n\n2F84E ;\t5651 ;\tMA\t# ( 噑 → 噑 ) CJK COMPATIBILITY IDEOGRAPH-2F84E → CJK UNIFIED IDEOGRAPH-5651\t# \n\n2F84F ;\t5674 ;\tMA\t# ( 噴 → 噴 ) CJK COMPATIBILITY IDEOGRAPH-2F84F → CJK UNIFIED IDEOGRAPH-5674\t# \n\nFA38 ;\t5668 ;\tMA\t# ( 器 → 器 ) CJK COMPATIBILITY IDEOGRAPH-FA38 → CJK UNIFIED IDEOGRAPH-5668\t# \n\nF9A9 ;\t56F9 ;\tMA\t# ( 囹 → 囹 ) CJK COMPATIBILITY IDEOGRAPH-F9A9 → CJK UNIFIED IDEOGRAPH-56F9\t# \n\n2F84B ;\t5716 ;\tMA\t# ( 圖 → 圖 ) CJK COMPATIBILITY IDEOGRAPH-2F84B → CJK UNIFIED IDEOGRAPH-5716\t# \n\n2F84D ;\t5717 ;\tMA\t# ( 圗 → 圗 ) CJK COMPATIBILITY IDEOGRAPH-2F84D → CJK UNIFIED IDEOGRAPH-5717\t# \n\n2F1F ;\t571F ;\tMA\t#* ( ⼟ → 土 ) KANGXI RADICAL EARTH → CJK UNIFIED IDEOGRAPH-571F\t# \n58EB ;\t571F ;\tMA\t# ( 士 → 土 ) CJK UNIFIED IDEOGRAPH-58EB → CJK UNIFIED IDEOGRAPH-571F\t# →⼠→→⼟→\n2F20 ;\t571F ;\tMA\t#* ( ⼠ → 土 ) KANGXI RADICAL SCHOLAR → CJK UNIFIED IDEOGRAPH-571F\t# →⼟→\n\n2F855 ;\t578B ;\tMA\t# ( 型 → 型 ) CJK COMPATIBILITY IDEOGRAPH-2F855 → CJK UNIFIED IDEOGRAPH-578B\t# \n\n2F852 ;\t57CE ;\tMA\t# ( 城 → 城 ) CJK COMPATIBILITY IDEOGRAPH-2F852 → CJK UNIFIED IDEOGRAPH-57CE\t# \n\n39B3 ;\t363D ;\tMA\t# ( 㦳 → 㘽 ) CJK UNIFIED IDEOGRAPH-39B3 → CJK UNIFIED IDEOGRAPH-363D\t# \n\n2F853 ;\t57F4 ;\tMA\t# ( 埴 → 埴 ) CJK COMPATIBILITY IDEOGRAPH-2F853 → CJK UNIFIED IDEOGRAPH-57F4\t# \n\n2F854 ;\t580D ;\tMA\t# ( 堍 → 堍 ) CJK COMPATIBILITY IDEOGRAPH-2F854 → CJK UNIFIED IDEOGRAPH-580D\t# \n\n2F857 ;\t5831 ;\tMA\t# ( 報 → 報 ) CJK COMPATIBILITY IDEOGRAPH-2F857 → CJK UNIFIED IDEOGRAPH-5831\t# \n\n2F856 ;\t5832 ;\tMA\t# ( 堲 → 堲 ) CJK COMPATIBILITY IDEOGRAPH-2F856 → CJK UNIFIED IDEOGRAPH-5832\t# \n\nFA39 ;\t5840 ;\tMA\t# ( 塀 → 塀 ) CJK COMPATIBILITY IDEOGRAPH-FA39 → CJK UNIFIED IDEOGRAPH-5840\t# \n\nFA10 ;\t585A ;\tMA\t# ( 塚 → 塚 ) CJK COMPATIBILITY IDEOGRAPH-FA10 → CJK UNIFIED IDEOGRAPH-585A\t# \nFA7C ;\t585A ;\tMA\t# ( 塚 → 塚 ) CJK COMPATIBILITY IDEOGRAPH-FA7C → CJK UNIFIED IDEOGRAPH-585A\t# \n\nF96C ;\t585E ;\tMA\t# ( 塞 → 塞 ) CJK COMPATIBILITY IDEOGRAPH-F96C → CJK UNIFIED IDEOGRAPH-585E\t# \n\n586B ;\t5861 ;\tMA\t# ( 填 → 塡 ) CJK UNIFIED IDEOGRAPH-586B → CJK UNIFIED IDEOGRAPH-5861\t# \n\n58FF ;\t58AB ;\tMA\t# ( 壿 → 墫 ) CJK UNIFIED IDEOGRAPH-58FF → CJK UNIFIED IDEOGRAPH-58AB\t# \n\n2F858 ;\t58AC ;\tMA\t# ( 墬 → 墬 ) CJK COMPATIBILITY IDEOGRAPH-2F858 → CJK UNIFIED IDEOGRAPH-58AC\t# \n\nFA7D ;\t58B3 ;\tMA\t# ( 墳 → 墳 ) CJK COMPATIBILITY IDEOGRAPH-FA7D → CJK UNIFIED IDEOGRAPH-58B3\t# \n\nF94A ;\t58D8 ;\tMA\t# ( 壘 → 壘 ) CJK COMPATIBILITY IDEOGRAPH-F94A → CJK UNIFIED IDEOGRAPH-58D8\t# \n\nF942 ;\t58DF ;\tMA\t# ( 壟 → 壟 ) CJK COMPATIBILITY IDEOGRAPH-F942 → CJK UNIFIED IDEOGRAPH-58DF\t# \n\n2F859 ;\t214E4 ;\tMA\t# ( 𡓤 → 𡓤 ) CJK COMPATIBILITY IDEOGRAPH-2F859 → CJK UNIFIED IDEOGRAPH-214E4\t# \n\n2F851 ;\t58EE ;\tMA\t# ( 壮 → 壮 ) CJK COMPATIBILITY IDEOGRAPH-2F851 → CJK UNIFIED IDEOGRAPH-58EE\t# \n\n2F85A ;\t58F2 ;\tMA\t# ( 売 → 売 ) CJK COMPATIBILITY IDEOGRAPH-2F85A → CJK UNIFIED IDEOGRAPH-58F2\t# \n\n2F85B ;\t58F7 ;\tMA\t# ( 壷 → 壷 ) CJK COMPATIBILITY IDEOGRAPH-2F85B → CJK UNIFIED IDEOGRAPH-58F7\t# \n21533 ;\t58F7 ;\tMA\t# ( 𡔳 → 壷 ) CJK UNIFIED IDEOGRAPH-21533 → CJK UNIFIED IDEOGRAPH-58F7\t# →壷→\n\n2F21 ;\t5902 ;\tMA\t#* ( ⼡ → 夂 ) KANGXI RADICAL GO → CJK UNIFIED IDEOGRAPH-5902\t# \n\n2F85C ;\t5906 ;\tMA\t# ( 夆 → 夆 ) CJK COMPATIBILITY IDEOGRAPH-2F85C → CJK UNIFIED IDEOGRAPH-5906\t# \n\n2F22 ;\t590A ;\tMA\t#* ( ⼢ → 夊 ) KANGXI RADICAL GO SLOWLY → CJK UNIFIED IDEOGRAPH-590A\t# \n\n30BF ;\t5915 ;\tMA\t# ( タ → 夕 ) KATAKANA LETTER TA → CJK UNIFIED IDEOGRAPH-5915\t# →⼣→\n2F23 ;\t5915 ;\tMA\t#* ( ⼣ → 夕 ) KANGXI RADICAL EVENING → CJK UNIFIED IDEOGRAPH-5915\t# \n\n2F85D ;\t591A ;\tMA\t# ( 多 → 多 ) CJK COMPATIBILITY IDEOGRAPH-2F85D → CJK UNIFIED IDEOGRAPH-591A\t# \n21587 ;\t591A ;\tMA\t# ( 𡖇 → 多 ) CJK UNIFIED IDEOGRAPH-21587 → CJK UNIFIED IDEOGRAPH-591A\t# →多→\n\n2F85E ;\t5922 ;\tMA\t# ( 夢 → 夢 ) CJK COMPATIBILITY IDEOGRAPH-2F85E → CJK UNIFIED IDEOGRAPH-5922\t# \n\n2F24 ;\t5927 ;\tMA\t#* ( ⼤ → 大 ) KANGXI RADICAL BIG → CJK UNIFIED IDEOGRAPH-5927\t# \n\nFA7E ;\t5944 ;\tMA\t# ( 奄 → 奄 ) CJK COMPATIBILITY IDEOGRAPH-FA7E → CJK UNIFIED IDEOGRAPH-5944\t# \n\nF90C ;\t5948 ;\tMA\t# ( 奈 → 奈 ) CJK COMPATIBILITY IDEOGRAPH-F90C → CJK UNIFIED IDEOGRAPH-5948\t# \n\nFA7F ;\t5954 ;\tMA\t# ( 奔 → 奔 ) CJK COMPATIBILITY IDEOGRAPH-FA7F → CJK UNIFIED IDEOGRAPH-5954\t# \n\nF909 ;\t5951 ;\tMA\t# ( 契 → 契 ) CJK COMPATIBILITY IDEOGRAPH-F909 → CJK UNIFIED IDEOGRAPH-5951\t# \n\n2F85F ;\t5962 ;\tMA\t# ( 奢 → 奢 ) CJK COMPATIBILITY IDEOGRAPH-2F85F → CJK UNIFIED IDEOGRAPH-5962\t# \n\nF981 ;\t5973 ;\tMA\t# ( 女 → 女 ) CJK COMPATIBILITY IDEOGRAPH-F981 → CJK UNIFIED IDEOGRAPH-5973\t# \n2F25 ;\t5973 ;\tMA\t#* ( ⼥ → 女 ) KANGXI RADICAL WOMAN → CJK UNIFIED IDEOGRAPH-5973\t# \n\n216A7 ;\t216A8 ;\tMA\t# ( 𡚧 → 𡚨 ) CJK UNIFIED IDEOGRAPH-216A7 → CJK UNIFIED IDEOGRAPH-216A8\t# →𡚨→\n2F860 ;\t216A8 ;\tMA\t# ( 𡚨 → 𡚨 ) CJK COMPATIBILITY IDEOGRAPH-2F860 → CJK UNIFIED IDEOGRAPH-216A8\t# \n\n2F861 ;\t216EA ;\tMA\t# ( 𡛪 → 𡛪 ) CJK COMPATIBILITY IDEOGRAPH-2F861 → CJK UNIFIED IDEOGRAPH-216EA\t# \n\n2F865 ;\t59D8 ;\tMA\t# ( 姘 → 姘 ) CJK COMPATIBILITY IDEOGRAPH-2F865 → CJK UNIFIED IDEOGRAPH-59D8\t# \n\n2F862 ;\t59EC ;\tMA\t# ( 姬 → 姬 ) CJK COMPATIBILITY IDEOGRAPH-2F862 → CJK UNIFIED IDEOGRAPH-59EC\t# \n\n2F863 ;\t5A1B ;\tMA\t# ( 娛 → 娛 ) CJK COMPATIBILITY IDEOGRAPH-2F863 → CJK UNIFIED IDEOGRAPH-5A1B\t# \n\n2F864 ;\t5A27 ;\tMA\t# ( 娧 → 娧 ) CJK COMPATIBILITY IDEOGRAPH-2F864 → CJK UNIFIED IDEOGRAPH-5A27\t# \n\nFA80 ;\t5A62 ;\tMA\t# ( 婢 → 婢 ) CJK COMPATIBILITY IDEOGRAPH-FA80 → CJK UNIFIED IDEOGRAPH-5A62\t# \n\n2F866 ;\t5A66 ;\tMA\t# ( 婦 → 婦 ) CJK COMPATIBILITY IDEOGRAPH-2F866 → CJK UNIFIED IDEOGRAPH-5A66\t# \n\n5B00 ;\t5AAF ;\tMA\t# ( 嬀 → 媯 ) CJK UNIFIED IDEOGRAPH-5B00 → CJK UNIFIED IDEOGRAPH-5AAF\t# \n\n2F867 ;\t36EE ;\tMA\t# ( 㛮 → 㛮 ) CJK COMPATIBILITY IDEOGRAPH-2F867 → CJK UNIFIED IDEOGRAPH-36EE\t# \n\n2F868 ;\t36FC ;\tMA\t# ( 㛼 → 㛼 ) CJK COMPATIBILITY IDEOGRAPH-2F868 → CJK UNIFIED IDEOGRAPH-36FC\t# \n\n2F986 ;\t5AB5 ;\tMA\t# ( 媵 → 媵 ) CJK COMPATIBILITY IDEOGRAPH-2F986 → CJK UNIFIED IDEOGRAPH-5AB5\t# \n\n2F869 ;\t5B08 ;\tMA\t# ( 嬈 → 嬈 ) CJK COMPATIBILITY IDEOGRAPH-2F869 → CJK UNIFIED IDEOGRAPH-5B08\t# \n\nFA81 ;\t5B28 ;\tMA\t# ( 嬨 → 嬨 ) CJK COMPATIBILITY IDEOGRAPH-FA81 → CJK UNIFIED IDEOGRAPH-5B28\t# \n\n2F86A ;\t5B3E ;\tMA\t# ( 嬾 → 嬾 ) CJK COMPATIBILITY IDEOGRAPH-2F86A → CJK UNIFIED IDEOGRAPH-5B3E\t# \n2F86B ;\t5B3E ;\tMA\t# ( 嬾 → 嬾 ) CJK COMPATIBILITY IDEOGRAPH-2F86B → CJK UNIFIED IDEOGRAPH-5B3E\t# \n\n2F26 ;\t5B50 ;\tMA\t#* ( ⼦ → 子 ) KANGXI RADICAL CHILD → CJK UNIFIED IDEOGRAPH-5B50\t# \n\n2F27 ;\t5B80 ;\tMA\t#* ( ⼧ → 宀 ) KANGXI RADICAL ROOF → CJK UNIFIED IDEOGRAPH-5B80\t# \n\nFA04 ;\t5B85 ;\tMA\t# ( 宅 → 宅 ) CJK COMPATIBILITY IDEOGRAPH-FA04 → CJK UNIFIED IDEOGRAPH-5B85\t# \n\n2F86C ;\t219C8 ;\tMA\t# ( 𡧈 → 𡧈 ) CJK COMPATIBILITY IDEOGRAPH-2F86C → CJK UNIFIED IDEOGRAPH-219C8\t# \n\n2F86D ;\t5BC3 ;\tMA\t# ( 寃 → 寃 ) CJK COMPATIBILITY IDEOGRAPH-2F86D → CJK UNIFIED IDEOGRAPH-5BC3\t# \n\n2F86E ;\t5BD8 ;\tMA\t# ( 寘 → 寘 ) CJK COMPATIBILITY IDEOGRAPH-2F86E → CJK UNIFIED IDEOGRAPH-5BD8\t# \n\nF95F ;\t5BE7 ;\tMA\t# ( 寧 → 寧 ) CJK COMPATIBILITY IDEOGRAPH-F95F → CJK UNIFIED IDEOGRAPH-5BE7\t# \nF9AA ;\t5BE7 ;\tMA\t# ( 寧 → 寧 ) CJK COMPATIBILITY IDEOGRAPH-F9AA → CJK UNIFIED IDEOGRAPH-5BE7\t# \n2F86F ;\t5BE7 ;\tMA\t# ( 寧 → 寧 ) CJK COMPATIBILITY IDEOGRAPH-2F86F → CJK UNIFIED IDEOGRAPH-5BE7\t# \n\nF9BC ;\t5BEE ;\tMA\t# ( 寮 → 寮 ) CJK COMPATIBILITY IDEOGRAPH-F9BC → CJK UNIFIED IDEOGRAPH-5BEE\t# \n\n2F870 ;\t5BF3 ;\tMA\t# ( 寳 → 寳 ) CJK COMPATIBILITY IDEOGRAPH-2F870 → CJK UNIFIED IDEOGRAPH-5BF3\t# \n\n2F871 ;\t21B18 ;\tMA\t# ( 𡬘 → 𡬘 ) CJK COMPATIBILITY IDEOGRAPH-2F871 → CJK UNIFIED IDEOGRAPH-21B18\t# \n\n2F28 ;\t5BF8 ;\tMA\t#* ( ⼨ → 寸 ) KANGXI RADICAL INCH → CJK UNIFIED IDEOGRAPH-5BF8\t# \n\n2F872 ;\t5BFF ;\tMA\t# ( 寿 → 寿 ) CJK COMPATIBILITY IDEOGRAPH-2F872 → CJK UNIFIED IDEOGRAPH-5BFF\t# \n\n2F873 ;\t5C06 ;\tMA\t# ( 将 → 将 ) CJK COMPATIBILITY IDEOGRAPH-2F873 → CJK UNIFIED IDEOGRAPH-5C06\t# \n\n2F29 ;\t5C0F ;\tMA\t#* ( ⼩ → 小 ) KANGXI RADICAL SMALL → CJK UNIFIED IDEOGRAPH-5C0F\t# \n\n2F875 ;\t5C22 ;\tMA\t# ( 尢 → 尢 ) CJK COMPATIBILITY IDEOGRAPH-2F875 → CJK UNIFIED IDEOGRAPH-5C22\t# \n2E90 ;\t5C22 ;\tMA\t#* ( ⺐ → 尢 ) CJK RADICAL LAME THREE → CJK UNIFIED IDEOGRAPH-5C22\t# \n2F2A ;\t5C22 ;\tMA\t#* ( ⼪ → 尢 ) KANGXI RADICAL LAME → CJK UNIFIED IDEOGRAPH-5C22\t# \n\n2E8F ;\t5C23 ;\tMA\t#* ( ⺏ → 尣 ) CJK RADICAL LAME TWO → CJK UNIFIED IDEOGRAPH-5C23\t# \n\n2F876 ;\t3781 ;\tMA\t# ( 㞁 → 㞁 ) CJK COMPATIBILITY IDEOGRAPH-2F876 → CJK UNIFIED IDEOGRAPH-3781\t# \n\n2F2B ;\t5C38 ;\tMA\t#* ( ⼫ → 尸 ) KANGXI RADICAL CORPSE → CJK UNIFIED IDEOGRAPH-5C38\t# \n\nF9BD ;\t5C3F ;\tMA\t# ( 尿 → 尿 ) CJK COMPATIBILITY IDEOGRAPH-F9BD → CJK UNIFIED IDEOGRAPH-5C3F\t# \n\n2F877 ;\t5C60 ;\tMA\t# ( 屠 → 屠 ) CJK COMPATIBILITY IDEOGRAPH-2F877 → CJK UNIFIED IDEOGRAPH-5C60\t# \n\nF94B ;\t5C62 ;\tMA\t# ( 屢 → 屢 ) CJK COMPATIBILITY IDEOGRAPH-F94B → CJK UNIFIED IDEOGRAPH-5C62\t# \n\nFA3B ;\t5C64 ;\tMA\t# ( 層 → 層 ) CJK COMPATIBILITY IDEOGRAPH-FA3B → CJK UNIFIED IDEOGRAPH-5C64\t# \n\nF9DF ;\t5C65 ;\tMA\t# ( 履 → 履 ) CJK COMPATIBILITY IDEOGRAPH-F9DF → CJK UNIFIED IDEOGRAPH-5C65\t# \n\nFA3C ;\t5C6E ;\tMA\t# ( 屮 → 屮 ) CJK COMPATIBILITY IDEOGRAPH-FA3C → CJK UNIFIED IDEOGRAPH-5C6E\t# \n2F878 ;\t5C6E ;\tMA\t# ( 屮 → 屮 ) CJK COMPATIBILITY IDEOGRAPH-2F878 → CJK UNIFIED IDEOGRAPH-5C6E\t# \n2F2C ;\t5C6E ;\tMA\t#* ( ⼬ → 屮 ) KANGXI RADICAL SPROUT → CJK UNIFIED IDEOGRAPH-5C6E\t# \n\n2F8F8 ;\t21D0B ;\tMA\t# ( 𡴋 → 𡴋 ) CJK COMPATIBILITY IDEOGRAPH-2F8F8 → CJK UNIFIED IDEOGRAPH-21D0B\t# \n\n2F2D ;\t5C71 ;\tMA\t#* ( ⼭ → 山 ) KANGXI RADICAL MOUNTAIN → CJK UNIFIED IDEOGRAPH-5C71\t# \n\n2F879 ;\t5CC0 ;\tMA\t# ( 峀 → 峀 ) CJK COMPATIBILITY IDEOGRAPH-2F879 → CJK UNIFIED IDEOGRAPH-5CC0\t# \n2B73A ;\t5CC0 ;\tMA\t# ( 𫜺 → 峀 ) CJK UNIFIED IDEOGRAPH-2B73A → CJK UNIFIED IDEOGRAPH-5CC0\t# \n\n2F87A ;\t5C8D ;\tMA\t# ( 岍 → 岍 ) CJK COMPATIBILITY IDEOGRAPH-2F87A → CJK UNIFIED IDEOGRAPH-5C8D\t# \n\n2F87B ;\t21DE4 ;\tMA\t# ( 𡷤 → 𡷤 ) CJK COMPATIBILITY IDEOGRAPH-2F87B → CJK UNIFIED IDEOGRAPH-21DE4\t# \n\n2F87D ;\t21DE6 ;\tMA\t# ( 𡷦 → 𡷦 ) CJK COMPATIBILITY IDEOGRAPH-2F87D → CJK UNIFIED IDEOGRAPH-21DE6\t# \n\nF9D5 ;\t5D19 ;\tMA\t# ( 崙 → 崙 ) CJK COMPATIBILITY IDEOGRAPH-F9D5 → CJK UNIFIED IDEOGRAPH-5D19\t# \n\n2F87C ;\t5D43 ;\tMA\t# ( 嵃 → 嵃 ) CJK COMPATIBILITY IDEOGRAPH-2F87C → CJK UNIFIED IDEOGRAPH-5D43\t# \n\nF921 ;\t5D50 ;\tMA\t# ( 嵐 → 嵐 ) CJK COMPATIBILITY IDEOGRAPH-F921 → CJK UNIFIED IDEOGRAPH-5D50\t# \n\n2F87F ;\t5D6B ;\tMA\t# ( 嵫 → 嵫 ) CJK COMPATIBILITY IDEOGRAPH-2F87F → CJK UNIFIED IDEOGRAPH-5D6B\t# \n\n2F87E ;\t5D6E ;\tMA\t# ( 嵮 → 嵮 ) CJK COMPATIBILITY IDEOGRAPH-2F87E → CJK UNIFIED IDEOGRAPH-5D6E\t# \n\n2F880 ;\t5D7C ;\tMA\t# ( 嵼 → 嵼 ) CJK COMPATIBILITY IDEOGRAPH-2F880 → CJK UNIFIED IDEOGRAPH-5D7C\t# \n\n2F9F4 ;\t5DB2 ;\tMA\t# ( 嶲 → 嶲 ) CJK COMPATIBILITY IDEOGRAPH-2F9F4 → CJK UNIFIED IDEOGRAPH-5DB2\t# \n\nF9AB ;\t5DBA ;\tMA\t# ( 嶺 → 嶺 ) CJK COMPATIBILITY IDEOGRAPH-F9AB → CJK UNIFIED IDEOGRAPH-5DBA\t# \n\n2F2E ;\t5DDB ;\tMA\t#* ( ⼮ → 巛 ) KANGXI RADICAL RIVER → CJK UNIFIED IDEOGRAPH-5DDB\t# \n\n2F882 ;\t5DE2 ;\tMA\t# ( 巢 → 巢 ) CJK COMPATIBILITY IDEOGRAPH-2F882 → CJK UNIFIED IDEOGRAPH-5DE2\t# \n\n30A8 ;\t5DE5 ;\tMA\t# ( エ → 工 ) KATAKANA LETTER E → CJK UNIFIED IDEOGRAPH-5DE5\t# →⼯→\n2F2F ;\t5DE5 ;\tMA\t#* ( ⼯ → 工 ) KANGXI RADICAL WORK → CJK UNIFIED IDEOGRAPH-5DE5\t# \n\n2F30 ;\t5DF1 ;\tMA\t#* ( ⼰ → 己 ) KANGXI RADICAL ONESELF → CJK UNIFIED IDEOGRAPH-5DF1\t# \n\n2E92 ;\t5DF3 ;\tMA\t#* ( ⺒ → 巳 ) CJK RADICAL SNAKE → CJK UNIFIED IDEOGRAPH-5DF3\t# \n\n2F883 ;\t382F ;\tMA\t# ( 㠯 → 㠯 ) CJK COMPATIBILITY IDEOGRAPH-2F883 → CJK UNIFIED IDEOGRAPH-382F\t# \n\n2F884 ;\t5DFD ;\tMA\t# ( 巽 → 巽 ) CJK COMPATIBILITY IDEOGRAPH-2F884 → CJK UNIFIED IDEOGRAPH-5DFD\t# \n\n2F31 ;\t5DFE ;\tMA\t#* ( ⼱ → 巾 ) KANGXI RADICAL TURBAN → CJK UNIFIED IDEOGRAPH-5DFE\t# \n\n5E32 ;\t5E21 ;\tMA\t# ( 帲 → 帡 ) CJK UNIFIED IDEOGRAPH-5E32 → CJK UNIFIED IDEOGRAPH-5E21\t# \n\n2F885 ;\t5E28 ;\tMA\t# ( 帨 → 帨 ) CJK COMPATIBILITY IDEOGRAPH-2F885 → CJK UNIFIED IDEOGRAPH-5E28\t# \n\n2F886 ;\t5E3D ;\tMA\t# ( 帽 → 帽 ) CJK COMPATIBILITY IDEOGRAPH-2F886 → CJK UNIFIED IDEOGRAPH-5E3D\t# \n\n2F887 ;\t5E69 ;\tMA\t# ( 幩 → 幩 ) CJK COMPATIBILITY IDEOGRAPH-2F887 → CJK UNIFIED IDEOGRAPH-5E69\t# \n\n2F888 ;\t3862 ;\tMA\t# ( 㡢 → 㡢 ) CJK COMPATIBILITY IDEOGRAPH-2F888 → CJK UNIFIED IDEOGRAPH-3862\t# \n\n2F889 ;\t22183 ;\tMA\t# ( 𢆃 → 𢆃 ) CJK COMPATIBILITY IDEOGRAPH-2F889 → CJK UNIFIED IDEOGRAPH-22183\t# \n\n2F32 ;\t5E72 ;\tMA\t#* ( ⼲ → 干 ) KANGXI RADICAL DRY → CJK UNIFIED IDEOGRAPH-5E72\t# \n\nF98E ;\t5E74 ;\tMA\t# ( 年 → 年 ) CJK COMPATIBILITY IDEOGRAPH-F98E → CJK UNIFIED IDEOGRAPH-5E74\t# \n\n2F939 ;\t2219F ;\tMA\t# ( 𢆟 → 𢆟 ) CJK COMPATIBILITY IDEOGRAPH-2F939 → CJK UNIFIED IDEOGRAPH-2219F\t# \n\n2E93 ;\t5E7A ;\tMA\t#* ( ⺓ → 幺 ) CJK RADICAL THREAD → CJK UNIFIED IDEOGRAPH-5E7A\t# \n2F33 ;\t5E7A ;\tMA\t#* ( ⼳ → 幺 ) KANGXI RADICAL SHORT THREAD → CJK UNIFIED IDEOGRAPH-5E7A\t# \n\n2F34 ;\t5E7F ;\tMA\t#* ( ⼴ → 广 ) KANGXI RADICAL DOTTED CLIFF → CJK UNIFIED IDEOGRAPH-5E7F\t# \n\nFA01 ;\t5EA6 ;\tMA\t# ( 度 → 度 ) CJK COMPATIBILITY IDEOGRAPH-FA01 → CJK UNIFIED IDEOGRAPH-5EA6\t# \n\n2F88A ;\t387C ;\tMA\t# ( 㡼 → 㡼 ) CJK COMPATIBILITY IDEOGRAPH-2F88A → CJK UNIFIED IDEOGRAPH-387C\t# \n\n2F88B ;\t5EB0 ;\tMA\t# ( 庰 → 庰 ) CJK COMPATIBILITY IDEOGRAPH-2F88B → CJK UNIFIED IDEOGRAPH-5EB0\t# \n\n2F88C ;\t5EB3 ;\tMA\t# ( 庳 → 庳 ) CJK COMPATIBILITY IDEOGRAPH-2F88C → CJK UNIFIED IDEOGRAPH-5EB3\t# \n\n2F88D ;\t5EB6 ;\tMA\t# ( 庶 → 庶 ) CJK COMPATIBILITY IDEOGRAPH-2F88D → CJK UNIFIED IDEOGRAPH-5EB6\t# \n\nF928 ;\t5ECA ;\tMA\t# ( 廊 → 廊 ) CJK COMPATIBILITY IDEOGRAPH-F928 → CJK UNIFIED IDEOGRAPH-5ECA\t# \n2F88E ;\t5ECA ;\tMA\t# ( 廊 → 廊 ) CJK COMPATIBILITY IDEOGRAPH-2F88E → CJK UNIFIED IDEOGRAPH-5ECA\t# \n\nF9A2 ;\t5EC9 ;\tMA\t# ( 廉 → 廉 ) CJK COMPATIBILITY IDEOGRAPH-F9A2 → CJK UNIFIED IDEOGRAPH-5EC9\t# \n\nFA82 ;\t5ED2 ;\tMA\t# ( 廒 → 廒 ) CJK COMPATIBILITY IDEOGRAPH-FA82 → CJK UNIFIED IDEOGRAPH-5ED2\t# \n\nFA0B ;\t5ED3 ;\tMA\t# ( 廓 → 廓 ) CJK COMPATIBILITY IDEOGRAPH-FA0B → CJK UNIFIED IDEOGRAPH-5ED3\t# \n\nFA83 ;\t5ED9 ;\tMA\t# ( 廙 → 廙 ) CJK COMPATIBILITY IDEOGRAPH-FA83 → CJK UNIFIED IDEOGRAPH-5ED9\t# \n\nF982 ;\t5EEC ;\tMA\t# ( 廬 → 廬 ) CJK COMPATIBILITY IDEOGRAPH-F982 → CJK UNIFIED IDEOGRAPH-5EEC\t# \n\n2F35 ;\t5EF4 ;\tMA\t#* ( ⼵ → 廴 ) KANGXI RADICAL LONG STRIDE → CJK UNIFIED IDEOGRAPH-5EF4\t# \n\n2F890 ;\t5EFE ;\tMA\t# ( 廾 → 廾 ) CJK COMPATIBILITY IDEOGRAPH-2F890 → CJK UNIFIED IDEOGRAPH-5EFE\t# \n2F36 ;\t5EFE ;\tMA\t#* ( ⼶ → 廾 ) KANGXI RADICAL TWO HANDS → CJK UNIFIED IDEOGRAPH-5EFE\t# \n\n2F891 ;\t22331 ;\tMA\t# ( 𢌱 → 𢌱 ) CJK COMPATIBILITY IDEOGRAPH-2F891 → CJK UNIFIED IDEOGRAPH-22331\t# \n2F892 ;\t22331 ;\tMA\t# ( 𢌱 → 𢌱 ) CJK COMPATIBILITY IDEOGRAPH-2F892 → CJK UNIFIED IDEOGRAPH-22331\t# \n\nF943 ;\t5F04 ;\tMA\t# ( 弄 → 弄 ) CJK COMPATIBILITY IDEOGRAPH-F943 → CJK UNIFIED IDEOGRAPH-5F04\t# \n\n2F37 ;\t5F0B ;\tMA\t#* ( ⼷ → 弋 ) KANGXI RADICAL SHOOT → CJK UNIFIED IDEOGRAPH-5F0B\t# \n\n2F38 ;\t5F13 ;\tMA\t#* ( ⼸ → 弓 ) KANGXI RADICAL BOW → CJK UNIFIED IDEOGRAPH-5F13\t# \n\n2F894 ;\t5F22 ;\tMA\t# ( 弢 → 弢 ) CJK COMPATIBILITY IDEOGRAPH-2F894 → CJK UNIFIED IDEOGRAPH-5F22\t# \n2F895 ;\t5F22 ;\tMA\t# ( 弢 → 弢 ) CJK COMPATIBILITY IDEOGRAPH-2F895 → CJK UNIFIED IDEOGRAPH-5F22\t# \n\n2F39 ;\t5F50 ;\tMA\t#* ( ⼹ → 彐 ) KANGXI RADICAL SNOUT → CJK UNIFIED IDEOGRAPH-5F50\t# \n\n2E94 ;\t5F51 ;\tMA\t#* ( ⺔ → 彑 ) CJK RADICAL SNOUT ONE → CJK UNIFIED IDEOGRAPH-5F51\t# \n\n2F874 ;\t5F53 ;\tMA\t# ( 当 → 当 ) CJK COMPATIBILITY IDEOGRAPH-2F874 → CJK UNIFIED IDEOGRAPH-5F53\t# \n\n2F896 ;\t38C7 ;\tMA\t# ( 㣇 → 㣇 ) CJK COMPATIBILITY IDEOGRAPH-2F896 → CJK UNIFIED IDEOGRAPH-38C7\t# \n\n2F3A ;\t5F61 ;\tMA\t#* ( ⼺ → 彡 ) KANGXI RADICAL BRISTLE → CJK UNIFIED IDEOGRAPH-5F61\t# \n\n2F899 ;\t5F62 ;\tMA\t# ( 形 → 形 ) CJK COMPATIBILITY IDEOGRAPH-2F899 → CJK UNIFIED IDEOGRAPH-5F62\t# \n\nFA84 ;\t5F69 ;\tMA\t# ( 彩 → 彩 ) CJK COMPATIBILITY IDEOGRAPH-FA84 → CJK UNIFIED IDEOGRAPH-5F69\t# \n\n2F89A ;\t5F6B ;\tMA\t# ( 彫 → 彫 ) CJK COMPATIBILITY IDEOGRAPH-2F89A → CJK UNIFIED IDEOGRAPH-5F6B\t# \n\n2F3B ;\t5F73 ;\tMA\t#* ( ⼻ → 彳 ) KANGXI RADICAL STEP → CJK UNIFIED IDEOGRAPH-5F73\t# \n\nF9D8 ;\t5F8B ;\tMA\t# ( 律 → 律 ) CJK COMPATIBILITY IDEOGRAPH-F9D8 → CJK UNIFIED IDEOGRAPH-5F8B\t# \n\n2F89B ;\t38E3 ;\tMA\t# ( 㣣 → 㣣 ) CJK COMPATIBILITY IDEOGRAPH-2F89B → CJK UNIFIED IDEOGRAPH-38E3\t# \n\n22505 ;\t5F9A ;\tMA\t# ( 𢔅 → 徚 ) CJK UNIFIED IDEOGRAPH-22505 → CJK UNIFIED IDEOGRAPH-5F9A\t# →徚→\n2F89C ;\t5F9A ;\tMA\t# ( 徚 → 徚 ) CJK COMPATIBILITY IDEOGRAPH-2F89C → CJK UNIFIED IDEOGRAPH-5F9A\t# \n\nF966 ;\t5FA9 ;\tMA\t# ( 復 → 復 ) CJK COMPATIBILITY IDEOGRAPH-F966 → CJK UNIFIED IDEOGRAPH-5FA9\t# \n\nFA85 ;\t5FAD ;\tMA\t# ( 徭 → 徭 ) CJK COMPATIBILITY IDEOGRAPH-FA85 → CJK UNIFIED IDEOGRAPH-5FAD\t# \n\n2F3C ;\t5FC3 ;\tMA\t#* ( ⼼ → 心 ) KANGXI RADICAL HEART → CJK UNIFIED IDEOGRAPH-5FC3\t# \n\n2E96 ;\t5FC4 ;\tMA\t#* ( ⺖ → 忄 ) CJK RADICAL HEART ONE → CJK UNIFIED IDEOGRAPH-5FC4\t# \n\n2E97 ;\t38FA ;\tMA\t#* ( ⺗ → 㣺 ) CJK RADICAL HEART TWO → CJK UNIFIED IDEOGRAPH-38FA\t# \n\n2F89D ;\t5FCD ;\tMA\t# ( 忍 → 忍 ) CJK COMPATIBILITY IDEOGRAPH-2F89D → CJK UNIFIED IDEOGRAPH-5FCD\t# \n\n2F89E ;\t5FD7 ;\tMA\t# ( 志 → 志 ) CJK COMPATIBILITY IDEOGRAPH-2F89E → CJK UNIFIED IDEOGRAPH-5FD7\t# \n\nF9A3 ;\t5FF5 ;\tMA\t# ( 念 → 念 ) CJK COMPATIBILITY IDEOGRAPH-F9A3 → CJK UNIFIED IDEOGRAPH-5FF5\t# \n\n2F89F ;\t5FF9 ;\tMA\t# ( 忹 → 忹 ) CJK COMPATIBILITY IDEOGRAPH-2F89F → CJK UNIFIED IDEOGRAPH-5FF9\t# \n\nF960 ;\t6012 ;\tMA\t# ( 怒 → 怒 ) CJK COMPATIBILITY IDEOGRAPH-F960 → CJK UNIFIED IDEOGRAPH-6012\t# \n\nF9AC ;\t601C ;\tMA\t# ( 怜 → 怜 ) CJK COMPATIBILITY IDEOGRAPH-F9AC → CJK UNIFIED IDEOGRAPH-601C\t# \n\nFA6B ;\t6075 ;\tMA\t# ( 恵 → 恵 ) CJK COMPATIBILITY IDEOGRAPH-FA6B → CJK UNIFIED IDEOGRAPH-6075\t# \n\n2F8A2 ;\t391C ;\tMA\t# ( 㤜 → 㤜 ) CJK COMPATIBILITY IDEOGRAPH-2F8A2 → CJK UNIFIED IDEOGRAPH-391C\t# \n\n2F8A1 ;\t393A ;\tMA\t# ( 㤺 → 㤺 ) CJK COMPATIBILITY IDEOGRAPH-2F8A1 → CJK UNIFIED IDEOGRAPH-393A\t# \n\n2F8A0 ;\t6081 ;\tMA\t# ( 悁 → 悁 ) CJK COMPATIBILITY IDEOGRAPH-2F8A0 → CJK UNIFIED IDEOGRAPH-6081\t# \n\nFA3D ;\t6094 ;\tMA\t# ( 悔 → 悔 ) CJK COMPATIBILITY IDEOGRAPH-FA3D → CJK UNIFIED IDEOGRAPH-6094\t# \n2F8A3 ;\t6094 ;\tMA\t# ( 悔 → 悔 ) CJK COMPATIBILITY IDEOGRAPH-2F8A3 → CJK UNIFIED IDEOGRAPH-6094\t# \n\n2F8A5 ;\t60C7 ;\tMA\t# ( 惇 → 惇 ) CJK COMPATIBILITY IDEOGRAPH-2F8A5 → CJK UNIFIED IDEOGRAPH-60C7\t# \n\nFA86 ;\t60D8 ;\tMA\t# ( 惘 → 惘 ) CJK COMPATIBILITY IDEOGRAPH-FA86 → CJK UNIFIED IDEOGRAPH-60D8\t# \n\nF9B9 ;\t60E1 ;\tMA\t# ( 惡 → 惡 ) CJK COMPATIBILITY IDEOGRAPH-F9B9 → CJK UNIFIED IDEOGRAPH-60E1\t# \n\n2F8A4 ;\t226D4 ;\tMA\t# ( 𢛔 → 𢛔 ) CJK COMPATIBILITY IDEOGRAPH-2F8A4 → CJK UNIFIED IDEOGRAPH-226D4\t# \n\nFA88 ;\t6108 ;\tMA\t# ( 愈 → 愈 ) CJK COMPATIBILITY IDEOGRAPH-FA88 → CJK UNIFIED IDEOGRAPH-6108\t# \n\nFA3E ;\t6168 ;\tMA\t# ( 慨 → 慨 ) CJK COMPATIBILITY IDEOGRAPH-FA3E → CJK UNIFIED IDEOGRAPH-6168\t# \n\nF9D9 ;\t6144 ;\tMA\t# ( 慄 → 慄 ) CJK COMPATIBILITY IDEOGRAPH-F9D9 → CJK UNIFIED IDEOGRAPH-6144\t# \n\n2F8A6 ;\t6148 ;\tMA\t# ( 慈 → 慈 ) CJK COMPATIBILITY IDEOGRAPH-2F8A6 → CJK UNIFIED IDEOGRAPH-6148\t# \n\n2F8A7 ;\t614C ;\tMA\t# ( 慌 → 慌 ) CJK COMPATIBILITY IDEOGRAPH-2F8A7 → CJK UNIFIED IDEOGRAPH-614C\t# \n2F8A9 ;\t614C ;\tMA\t# ( 慌 → 慌 ) CJK COMPATIBILITY IDEOGRAPH-2F8A9 → CJK UNIFIED IDEOGRAPH-614C\t# \n\nFA87 ;\t614E ;\tMA\t# ( 慎 → 慎 ) CJK COMPATIBILITY IDEOGRAPH-FA87 → CJK UNIFIED IDEOGRAPH-614E\t# \n2F8A8 ;\t614E ;\tMA\t# ( 慎 → 慎 ) CJK COMPATIBILITY IDEOGRAPH-2F8A8 → CJK UNIFIED IDEOGRAPH-614E\t# \n\nFA8A ;\t6160 ;\tMA\t# ( 慠 → 慠 ) CJK COMPATIBILITY IDEOGRAPH-FA8A → CJK UNIFIED IDEOGRAPH-6160\t# \n\n2F8AA ;\t617A ;\tMA\t# ( 慺 → 慺 ) CJK COMPATIBILITY IDEOGRAPH-2F8AA → CJK UNIFIED IDEOGRAPH-617A\t# \n\nFA3F ;\t618E ;\tMA\t# ( 憎 → 憎 ) CJK COMPATIBILITY IDEOGRAPH-FA3F → CJK UNIFIED IDEOGRAPH-618E\t# \nFA89 ;\t618E ;\tMA\t# ( 憎 → 憎 ) CJK COMPATIBILITY IDEOGRAPH-FA89 → CJK UNIFIED IDEOGRAPH-618E\t# \n2F8AB ;\t618E ;\tMA\t# ( 憎 → 憎 ) CJK COMPATIBILITY IDEOGRAPH-2F8AB → CJK UNIFIED IDEOGRAPH-618E\t# \n\nF98F ;\t6190 ;\tMA\t# ( 憐 → 憐 ) CJK COMPATIBILITY IDEOGRAPH-F98F → CJK UNIFIED IDEOGRAPH-6190\t# \n\n2F8AD ;\t61A4 ;\tMA\t# ( 憤 → 憤 ) CJK COMPATIBILITY IDEOGRAPH-2F8AD → CJK UNIFIED IDEOGRAPH-61A4\t# \n\n2F8AE ;\t61AF ;\tMA\t# ( 憯 → 憯 ) CJK COMPATIBILITY IDEOGRAPH-2F8AE → CJK UNIFIED IDEOGRAPH-61AF\t# \n\n2F8AC ;\t61B2 ;\tMA\t# ( 憲 → 憲 ) CJK COMPATIBILITY IDEOGRAPH-2F8AC → CJK UNIFIED IDEOGRAPH-61B2\t# \n\nFAD0 ;\t22844 ;\tMA\t# ( 𢡄 → 𢡄 ) CJK COMPATIBILITY IDEOGRAPH-FAD0 → CJK UNIFIED IDEOGRAPH-22844\t# \n\nFACF ;\t2284A ;\tMA\t# ( 𢡊 → 𢡊 ) CJK COMPATIBILITY IDEOGRAPH-FACF → CJK UNIFIED IDEOGRAPH-2284A\t# \n\n2F8AF ;\t61DE ;\tMA\t# ( 懞 → 懞 ) CJK COMPATIBILITY IDEOGRAPH-2F8AF → CJK UNIFIED IDEOGRAPH-61DE\t# \n\nFA40 ;\t61F2 ;\tMA\t# ( 懲 → 懲 ) CJK COMPATIBILITY IDEOGRAPH-FA40 → CJK UNIFIED IDEOGRAPH-61F2\t# \nFA8B ;\t61F2 ;\tMA\t# ( 懲 → 懲 ) CJK COMPATIBILITY IDEOGRAPH-FA8B → CJK UNIFIED IDEOGRAPH-61F2\t# \n2F8B0 ;\t61F2 ;\tMA\t# ( 懲 → 懲 ) CJK COMPATIBILITY IDEOGRAPH-2F8B0 → CJK UNIFIED IDEOGRAPH-61F2\t# \n\nF90D ;\t61F6 ;\tMA\t# ( 懶 → 懶 ) CJK COMPATIBILITY IDEOGRAPH-F90D → CJK UNIFIED IDEOGRAPH-61F6\t# \n2F8B1 ;\t61F6 ;\tMA\t# ( 懶 → 懶 ) CJK COMPATIBILITY IDEOGRAPH-2F8B1 → CJK UNIFIED IDEOGRAPH-61F6\t# \n\nF990 ;\t6200 ;\tMA\t# ( 戀 → 戀 ) CJK COMPATIBILITY IDEOGRAPH-F990 → CJK UNIFIED IDEOGRAPH-6200\t# \n\n2F3D ;\t6208 ;\tMA\t#* ( ⼽ → 戈 ) KANGXI RADICAL HALBERD → CJK UNIFIED IDEOGRAPH-6208\t# \n\n2F8B2 ;\t6210 ;\tMA\t# ( 成 → 成 ) CJK COMPATIBILITY IDEOGRAPH-2F8B2 → CJK UNIFIED IDEOGRAPH-6210\t# \n\n2F8B3 ;\t621B ;\tMA\t# ( 戛 → 戛 ) CJK COMPATIBILITY IDEOGRAPH-2F8B3 → CJK UNIFIED IDEOGRAPH-621B\t# \n\nF9D2 ;\t622E ;\tMA\t# ( 戮 → 戮 ) CJK COMPATIBILITY IDEOGRAPH-F9D2 → CJK UNIFIED IDEOGRAPH-622E\t# \n\nFA8C ;\t6234 ;\tMA\t# ( 戴 → 戴 ) CJK COMPATIBILITY IDEOGRAPH-FA8C → CJK UNIFIED IDEOGRAPH-6234\t# \n\n2F3E ;\t6236 ;\tMA\t#* ( ⼾ → 戶 ) KANGXI RADICAL DOOR → CJK UNIFIED IDEOGRAPH-6236\t# \n6238 ;\t6236 ;\tMA\t# ( 戸 → 戶 ) CJK UNIFIED IDEOGRAPH-6238 → CJK UNIFIED IDEOGRAPH-6236\t# →⼾→\n\n2F3F ;\t624B ;\tMA\t#* ( ⼿ → 手 ) KANGXI RADICAL HAND → CJK UNIFIED IDEOGRAPH-624B\t# \n\n2E98 ;\t624C ;\tMA\t#* ( ⺘ → 扌 ) CJK RADICAL HAND → CJK UNIFIED IDEOGRAPH-624C\t# \n\n2F8B4 ;\t625D ;\tMA\t# ( 扝 → 扝 ) CJK COMPATIBILITY IDEOGRAPH-2F8B4 → CJK UNIFIED IDEOGRAPH-625D\t# \n\n2F8B5 ;\t62B1 ;\tMA\t# ( 抱 → 抱 ) CJK COMPATIBILITY IDEOGRAPH-2F8B5 → CJK UNIFIED IDEOGRAPH-62B1\t# \n\nF925 ;\t62C9 ;\tMA\t# ( 拉 → 拉 ) CJK COMPATIBILITY IDEOGRAPH-F925 → CJK UNIFIED IDEOGRAPH-62C9\t# \n\nF95B ;\t62CF ;\tMA\t# ( 拏 → 拏 ) CJK COMPATIBILITY IDEOGRAPH-F95B → CJK UNIFIED IDEOGRAPH-62CF\t# \n\nFA02 ;\t62D3 ;\tMA\t# ( 拓 → 拓 ) CJK COMPATIBILITY IDEOGRAPH-FA02 → CJK UNIFIED IDEOGRAPH-62D3\t# \n\n2F8B6 ;\t62D4 ;\tMA\t# ( 拔 → 拔 ) CJK COMPATIBILITY IDEOGRAPH-2F8B6 → CJK UNIFIED IDEOGRAPH-62D4\t# \n\n2F8BA ;\t62FC ;\tMA\t# ( 拼 → 拼 ) CJK COMPATIBILITY IDEOGRAPH-2F8BA → CJK UNIFIED IDEOGRAPH-62FC\t# \n\nF973 ;\t62FE ;\tMA\t# ( 拾 → 拾 ) CJK COMPATIBILITY IDEOGRAPH-F973 → CJK UNIFIED IDEOGRAPH-62FE\t# \n\n2F8B8 ;\t22B0C ;\tMA\t# ( 𢬌 → 𢬌 ) CJK COMPATIBILITY IDEOGRAPH-2F8B8 → CJK UNIFIED IDEOGRAPH-22B0C\t# \n\n2F8B9 ;\t633D ;\tMA\t# ( 挽 → 挽 ) CJK COMPATIBILITY IDEOGRAPH-2F8B9 → CJK UNIFIED IDEOGRAPH-633D\t# \n\n2F8B7 ;\t6350 ;\tMA\t# ( 捐 → 捐 ) CJK COMPATIBILITY IDEOGRAPH-2F8B7 → CJK UNIFIED IDEOGRAPH-6350\t# \n\n2F8BB ;\t6368 ;\tMA\t# ( 捨 → 捨 ) CJK COMPATIBILITY IDEOGRAPH-2F8BB → CJK UNIFIED IDEOGRAPH-6368\t# \n\nF9A4 ;\t637B ;\tMA\t# ( 捻 → 捻 ) CJK COMPATIBILITY IDEOGRAPH-F9A4 → CJK UNIFIED IDEOGRAPH-637B\t# \n\n2F8BC ;\t6383 ;\tMA\t# ( 掃 → 掃 ) CJK COMPATIBILITY IDEOGRAPH-2F8BC → CJK UNIFIED IDEOGRAPH-6383\t# \n\nF975 ;\t63A0 ;\tMA\t# ( 掠 → 掠 ) CJK COMPATIBILITY IDEOGRAPH-F975 → CJK UNIFIED IDEOGRAPH-63A0\t# \n\n2F8C1 ;\t63A9 ;\tMA\t# ( 掩 → 掩 ) CJK COMPATIBILITY IDEOGRAPH-2F8C1 → CJK UNIFIED IDEOGRAPH-63A9\t# \n\nFA8D ;\t63C4 ;\tMA\t# ( 揄 → 揄 ) CJK COMPATIBILITY IDEOGRAPH-FA8D → CJK UNIFIED IDEOGRAPH-63C4\t# \n\n2F8BD ;\t63E4 ;\tMA\t# ( 揤 → 揤 ) CJK COMPATIBILITY IDEOGRAPH-2F8BD → CJK UNIFIED IDEOGRAPH-63E4\t# \n\nFA8E ;\t641C ;\tMA\t# ( 搜 → 搜 ) CJK COMPATIBILITY IDEOGRAPH-FA8E → CJK UNIFIED IDEOGRAPH-641C\t# \n\n2F8BE ;\t22BF1 ;\tMA\t# ( 𢯱 → 𢯱 ) CJK COMPATIBILITY IDEOGRAPH-2F8BE → CJK UNIFIED IDEOGRAPH-22BF1\t# \n\n2F8BF ;\t6422 ;\tMA\t# ( 搢 → 搢 ) CJK COMPATIBILITY IDEOGRAPH-2F8BF → CJK UNIFIED IDEOGRAPH-6422\t# \n\n2F8C0 ;\t63C5 ;\tMA\t# ( 揅 → 揅 ) CJK COMPATIBILITY IDEOGRAPH-2F8C0 → CJK UNIFIED IDEOGRAPH-63C5\t# \n\nFA8F ;\t6452 ;\tMA\t# ( 摒 → 摒 ) CJK COMPATIBILITY IDEOGRAPH-FA8F → CJK UNIFIED IDEOGRAPH-6452\t# \n\n2F8C3 ;\t6469 ;\tMA\t# ( 摩 → 摩 ) CJK COMPATIBILITY IDEOGRAPH-2F8C3 → CJK UNIFIED IDEOGRAPH-6469\t# \n\n2F8C6 ;\t6477 ;\tMA\t# ( 摷 → 摷 ) CJK COMPATIBILITY IDEOGRAPH-2F8C6 → CJK UNIFIED IDEOGRAPH-6477\t# \n\n2F8C4 ;\t647E ;\tMA\t# ( 摾 → 摾 ) CJK COMPATIBILITY IDEOGRAPH-2F8C4 → CJK UNIFIED IDEOGRAPH-647E\t# \n\n2F8C2 ;\t3A2E ;\tMA\t# ( 㨮 → 㨮 ) CJK COMPATIBILITY IDEOGRAPH-2F8C2 → CJK UNIFIED IDEOGRAPH-3A2E\t# \n\n6409 ;\t3A41 ;\tMA\t# ( 搉 → 㩁 ) CJK UNIFIED IDEOGRAPH-6409 → CJK UNIFIED IDEOGRAPH-3A41\t# \n\nF991 ;\t649A ;\tMA\t# ( 撚 → 撚 ) CJK COMPATIBILITY IDEOGRAPH-F991 → CJK UNIFIED IDEOGRAPH-649A\t# \n\n2F8C5 ;\t649D ;\tMA\t# ( 撝 → 撝 ) CJK COMPATIBILITY IDEOGRAPH-2F8C5 → CJK UNIFIED IDEOGRAPH-649D\t# \n\nF930 ;\t64C4 ;\tMA\t# ( 擄 → 擄 ) CJK COMPATIBILITY IDEOGRAPH-F930 → CJK UNIFIED IDEOGRAPH-64C4\t# \n\n2F8C7 ;\t3A6C ;\tMA\t# ( 㩬 → 㩬 ) CJK COMPATIBILITY IDEOGRAPH-2F8C7 → CJK UNIFIED IDEOGRAPH-3A6C\t# \n\n2F40 ;\t652F ;\tMA\t#* ( ⽀ → 支 ) KANGXI RADICAL BRANCH → CJK UNIFIED IDEOGRAPH-652F\t# \n\n2F41 ;\t6534 ;\tMA\t#* ( ⽁ → 攴 ) KANGXI RADICAL RAP → CJK UNIFIED IDEOGRAPH-6534\t# \n\n2E99 ;\t6535 ;\tMA\t#* ( ⺙ → 攵 ) CJK RADICAL RAP → CJK UNIFIED IDEOGRAPH-6535\t# \n\nFA41 ;\t654F ;\tMA\t# ( 敏 → 敏 ) CJK COMPATIBILITY IDEOGRAPH-FA41 → CJK UNIFIED IDEOGRAPH-654F\t# \n2F8C8 ;\t654F ;\tMA\t# ( 敏 → 敏 ) CJK COMPATIBILITY IDEOGRAPH-2F8C8 → CJK UNIFIED IDEOGRAPH-654F\t# \n\nFA90 ;\t6556 ;\tMA\t# ( 敖 → 敖 ) CJK COMPATIBILITY IDEOGRAPH-FA90 → CJK UNIFIED IDEOGRAPH-6556\t# \n\n2F8C9 ;\t656C ;\tMA\t# ( 敬 → 敬 ) CJK COMPATIBILITY IDEOGRAPH-2F8C9 → CJK UNIFIED IDEOGRAPH-656C\t# \n\nF969 ;\t6578 ;\tMA\t# ( 數 → 數 ) CJK COMPATIBILITY IDEOGRAPH-F969 → CJK UNIFIED IDEOGRAPH-6578\t# \n\n2F8CA ;\t2300A ;\tMA\t# ( 𣀊 → 𣀊 ) CJK COMPATIBILITY IDEOGRAPH-2F8CA → CJK UNIFIED IDEOGRAPH-2300A\t# \n\n2F42 ;\t6587 ;\tMA\t#* ( ⽂ → 文 ) KANGXI RADICAL SCRIPT → CJK UNIFIED IDEOGRAPH-6587\t# \n\n2EEB ;\t6589 ;\tMA\t#* ( ⻫ → 斉 ) CJK RADICAL J-SIMPLIFIED EVEN → CJK UNIFIED IDEOGRAPH-6589\t# \n\n2F43 ;\t6597 ;\tMA\t#* ( ⽃ → 斗 ) KANGXI RADICAL DIPPER → CJK UNIFIED IDEOGRAPH-6597\t# \n\nF9BE ;\t6599 ;\tMA\t# ( 料 → 料 ) CJK COMPATIBILITY IDEOGRAPH-F9BE → CJK UNIFIED IDEOGRAPH-6599\t# \n\n2F44 ;\t65A4 ;\tMA\t#* ( ⽄ → 斤 ) KANGXI RADICAL AXE → CJK UNIFIED IDEOGRAPH-65A4\t# \n\n2F45 ;\t65B9 ;\tMA\t#* ( ⽅ → 方 ) KANGXI RADICAL SQUARE → CJK UNIFIED IDEOGRAPH-65B9\t# \n\nF983 ;\t65C5 ;\tMA\t# ( 旅 → 旅 ) CJK COMPATIBILITY IDEOGRAPH-F983 → CJK UNIFIED IDEOGRAPH-65C5\t# \n\n2F46 ;\t65E0 ;\tMA\t#* ( ⽆ → 无 ) KANGXI RADICAL NOT → CJK UNIFIED IDEOGRAPH-65E0\t# \n\n2E9B ;\t65E1 ;\tMA\t#* ( ⺛ → 旡 ) CJK RADICAL CHOKE → CJK UNIFIED IDEOGRAPH-65E1\t# \n\nFA42 ;\t65E2 ;\tMA\t# ( 既 → 既 ) CJK COMPATIBILITY IDEOGRAPH-FA42 → CJK UNIFIED IDEOGRAPH-65E2\t# \n\n2F8CB ;\t65E3 ;\tMA\t# ( 旣 → 旣 ) CJK COMPATIBILITY IDEOGRAPH-2F8CB → CJK UNIFIED IDEOGRAPH-65E3\t# \n\n2F47 ;\t65E5 ;\tMA\t#* ( ⽇ → 日 ) KANGXI RADICAL SUN → CJK UNIFIED IDEOGRAPH-65E5\t# \n\nF9E0 ;\t6613 ;\tMA\t# ( 易 → 易 ) CJK COMPATIBILITY IDEOGRAPH-F9E0 → CJK UNIFIED IDEOGRAPH-6613\t# \n\n66F6 ;\t3ADA ;\tMA\t# ( 曶 → 㫚 ) CJK UNIFIED IDEOGRAPH-66F6 → CJK UNIFIED IDEOGRAPH-3ADA\t# \n\n2F8D1 ;\t3AE4 ;\tMA\t# ( 㫤 → 㫤 ) CJK COMPATIBILITY IDEOGRAPH-2F8D1 → CJK UNIFIED IDEOGRAPH-3AE4\t# \n\n2F8CD ;\t6649 ;\tMA\t# ( 晉 → 晉 ) CJK COMPATIBILITY IDEOGRAPH-2F8CD → CJK UNIFIED IDEOGRAPH-6649\t# \n\n6669 ;\t665A ;\tMA\t# ( 晩 → 晚 ) CJK UNIFIED IDEOGRAPH-6669 → CJK UNIFIED IDEOGRAPH-665A\t# \n\nFA12 ;\t6674 ;\tMA\t# ( 晴 → 晴 ) CJK COMPATIBILITY IDEOGRAPH-FA12 → CJK UNIFIED IDEOGRAPH-6674\t# \nFA91 ;\t6674 ;\tMA\t# ( 晴 → 晴 ) CJK COMPATIBILITY IDEOGRAPH-FA91 → CJK UNIFIED IDEOGRAPH-6674\t# \n\nFA43 ;\t6691 ;\tMA\t# ( 暑 → 暑 ) CJK COMPATIBILITY IDEOGRAPH-FA43 → CJK UNIFIED IDEOGRAPH-6691\t# \n2F8CF ;\t6691 ;\tMA\t# ( 暑 → 暑 ) CJK COMPATIBILITY IDEOGRAPH-2F8CF → CJK UNIFIED IDEOGRAPH-6691\t# \n\nF9C5 ;\t6688 ;\tMA\t# ( 暈 → 暈 ) CJK COMPATIBILITY IDEOGRAPH-F9C5 → CJK UNIFIED IDEOGRAPH-6688\t# \n\n2F8D0 ;\t3B08 ;\tMA\t# ( 㬈 → 㬈 ) CJK COMPATIBILITY IDEOGRAPH-2F8D0 → CJK UNIFIED IDEOGRAPH-3B08\t# \n\n2F8D5 ;\t669C ;\tMA\t# ( 暜 → 暜 ) CJK COMPATIBILITY IDEOGRAPH-2F8D5 → CJK UNIFIED IDEOGRAPH-669C\t# \n\nFA06 ;\t66B4 ;\tMA\t# ( 暴 → 暴 ) CJK COMPATIBILITY IDEOGRAPH-FA06 → CJK UNIFIED IDEOGRAPH-66B4\t# \n\nF98B ;\t66C6 ;\tMA\t# ( 曆 → 曆 ) CJK COMPATIBILITY IDEOGRAPH-F98B → CJK UNIFIED IDEOGRAPH-66C6\t# \n\n2F8CE ;\t3B19 ;\tMA\t# ( 㬙 → 㬙 ) CJK COMPATIBILITY IDEOGRAPH-2F8CE → CJK UNIFIED IDEOGRAPH-3B19\t# \n\n2F897 ;\t232B8 ;\tMA\t# ( 𣊸 → 𣊸 ) CJK COMPATIBILITY IDEOGRAPH-2F897 → CJK UNIFIED IDEOGRAPH-232B8\t# \n\n2F48 ;\t66F0 ;\tMA\t#* ( ⽈ → 曰 ) KANGXI RADICAL SAY → CJK UNIFIED IDEOGRAPH-66F0\t# \n\nF901 ;\t66F4 ;\tMA\t# ( 更 → 更 ) CJK COMPATIBILITY IDEOGRAPH-F901 → CJK UNIFIED IDEOGRAPH-66F4\t# \n\n2F8CC ;\t66F8 ;\tMA\t# ( 書 → 書 ) CJK COMPATIBILITY IDEOGRAPH-2F8CC → CJK UNIFIED IDEOGRAPH-66F8\t# \n\n2F49 ;\t6708 ;\tMA\t#* ( ⽉ → 月 ) KANGXI RADICAL MOON → CJK UNIFIED IDEOGRAPH-6708\t# \n\n2F980 ;\t2335F ;\tMA\t# ( 𣍟 → 𣍟 ) CJK COMPATIBILITY IDEOGRAPH-2F980 → CJK UNIFIED IDEOGRAPH-2335F\t# \n2B73E ;\t2335F ;\tMA\t# ( 𫜾 → 𣍟 ) CJK UNIFIED IDEOGRAPH-2B73E → CJK UNIFIED IDEOGRAPH-2335F\t# \n\n80A6 ;\t670C ;\tMA\t# ( 肦 → 朌 ) CJK UNIFIED IDEOGRAPH-80A6 → CJK UNIFIED IDEOGRAPH-670C\t# \n\n80D0 ;\t670F ;\tMA\t# ( 胐 → 朏 ) CJK UNIFIED IDEOGRAPH-80D0 → CJK UNIFIED IDEOGRAPH-670F\t# \n\n80CA ;\t6710 ;\tMA\t# ( 胊 → 朐 ) CJK UNIFIED IDEOGRAPH-80CA → CJK UNIFIED IDEOGRAPH-6710\t# \n\n8101 ;\t6713 ;\tMA\t# ( 脁 → 朓 ) CJK UNIFIED IDEOGRAPH-8101 → CJK UNIFIED IDEOGRAPH-6713\t# \n\n80F6 ;\t3B35 ;\tMA\t# ( 胶 → 㬵 ) CJK UNIFIED IDEOGRAPH-80F6 → CJK UNIFIED IDEOGRAPH-3B35\t# \n\nF929 ;\t6717 ;\tMA\t# ( 朗 → 朗 ) CJK COMPATIBILITY IDEOGRAPH-F929 → CJK UNIFIED IDEOGRAPH-6717\t# \nFA92 ;\t6717 ;\tMA\t# ( 朗 → 朗 ) CJK COMPATIBILITY IDEOGRAPH-FA92 → CJK UNIFIED IDEOGRAPH-6717\t# \n2F8D8 ;\t6717 ;\tMA\t# ( 朗 → 朗 ) CJK COMPATIBILITY IDEOGRAPH-2F8D8 → CJK UNIFIED IDEOGRAPH-6717\t# \n\n8127 ;\t6718 ;\tMA\t# ( 脧 → 朘 ) CJK UNIFIED IDEOGRAPH-8127 → CJK UNIFIED IDEOGRAPH-6718\t# \n\nFA93 ;\t671B ;\tMA\t# ( 望 → 望 ) CJK COMPATIBILITY IDEOGRAPH-FA93 → CJK UNIFIED IDEOGRAPH-671B\t# \n2F8D9 ;\t671B ;\tMA\t# ( 望 → 望 ) CJK COMPATIBILITY IDEOGRAPH-2F8D9 → CJK UNIFIED IDEOGRAPH-671B\t# \n\n5E50 ;\t3B3A ;\tMA\t# ( 幐 → 㬺 ) CJK UNIFIED IDEOGRAPH-5E50 → CJK UNIFIED IDEOGRAPH-3B3A\t# \n\n4420 ;\t3B3B ;\tMA\t# ( 䐠 → 㬻 ) CJK UNIFIED IDEOGRAPH-4420 → CJK UNIFIED IDEOGRAPH-3B3B\t# \n\n2F989 ;\t23393 ;\tMA\t# ( 𣎓 → 𣎓 ) CJK COMPATIBILITY IDEOGRAPH-2F989 → CJK UNIFIED IDEOGRAPH-23393\t# \n\n81A7 ;\t6723 ;\tMA\t# ( 膧 → 朣 ) CJK UNIFIED IDEOGRAPH-81A7 → CJK UNIFIED IDEOGRAPH-6723\t# \n\n2F98A ;\t2339C ;\tMA\t# ( 𣎜 → 𣎜 ) CJK COMPATIBILITY IDEOGRAPH-2F98A → CJK UNIFIED IDEOGRAPH-2339C\t# \n\n2F4A ;\t6728 ;\tMA\t#* ( ⽊ → 木 ) KANGXI RADICAL TREE → CJK UNIFIED IDEOGRAPH-6728\t# \n\nF9E1 ;\t674E ;\tMA\t# ( 李 → 李 ) CJK COMPATIBILITY IDEOGRAPH-F9E1 → CJK UNIFIED IDEOGRAPH-674E\t# \n\n2F8DC ;\t6753 ;\tMA\t# ( 杓 → 杓 ) CJK COMPATIBILITY IDEOGRAPH-2F8DC → CJK UNIFIED IDEOGRAPH-6753\t# \n\nFA94 ;\t6756 ;\tMA\t# ( 杖 → 杖 ) CJK COMPATIBILITY IDEOGRAPH-FA94 → CJK UNIFIED IDEOGRAPH-6756\t# \n\n2F8DB ;\t675E ;\tMA\t# ( 杞 → 杞 ) CJK COMPATIBILITY IDEOGRAPH-2F8DB → CJK UNIFIED IDEOGRAPH-675E\t# \n\n2F8DD ;\t233C3 ;\tMA\t# ( 𣏃 → 𣏃 ) CJK COMPATIBILITY IDEOGRAPH-2F8DD → CJK UNIFIED IDEOGRAPH-233C3\t# \n\n67FF ;\t676E ;\tMA\t# ( 柿 → 杮 ) CJK UNIFIED IDEOGRAPH-67FF → CJK UNIFIED IDEOGRAPH-676E\t# \n\nF9C8 ;\t677B ;\tMA\t# ( 杻 → 杻 ) CJK COMPATIBILITY IDEOGRAPH-F9C8 → CJK UNIFIED IDEOGRAPH-677B\t# \n\n2F8E0 ;\t6785 ;\tMA\t# ( 枅 → 枅 ) CJK COMPATIBILITY IDEOGRAPH-2F8E0 → CJK UNIFIED IDEOGRAPH-6785\t# \n\nF9F4 ;\t6797 ;\tMA\t# ( 林 → 林 ) CJK COMPATIBILITY IDEOGRAPH-F9F4 → CJK UNIFIED IDEOGRAPH-6797\t# \n\n2F8DE ;\t3B49 ;\tMA\t# ( 㭉 → 㭉 ) CJK COMPATIBILITY IDEOGRAPH-2F8DE → CJK UNIFIED IDEOGRAPH-3B49\t# \n\nFAD1 ;\t233D5 ;\tMA\t# ( 𣏕 → 𣏕 ) CJK COMPATIBILITY IDEOGRAPH-FAD1 → CJK UNIFIED IDEOGRAPH-233D5\t# \n\nF9C9 ;\t67F3 ;\tMA\t# ( 柳 → 柳 ) CJK COMPATIBILITY IDEOGRAPH-F9C9 → CJK UNIFIED IDEOGRAPH-67F3\t# \n\n2F8DF ;\t67FA ;\tMA\t# ( 柺 → 柺 ) CJK COMPATIBILITY IDEOGRAPH-2F8DF → CJK UNIFIED IDEOGRAPH-67FA\t# \n\nF9DA ;\t6817 ;\tMA\t# ( 栗 → 栗 ) CJK COMPATIBILITY IDEOGRAPH-F9DA → CJK UNIFIED IDEOGRAPH-6817\t# \n\n2F8E5 ;\t681F ;\tMA\t# ( 栟 → 栟 ) CJK COMPATIBILITY IDEOGRAPH-2F8E5 → CJK UNIFIED IDEOGRAPH-681F\t# \n\n2F8E1 ;\t6852 ;\tMA\t# ( 桒 → 桒 ) CJK COMPATIBILITY IDEOGRAPH-2F8E1 → CJK UNIFIED IDEOGRAPH-6852\t# \n\n2F8E3 ;\t2346D ;\tMA\t# ( 𣑭 → 𣑭 ) CJK COMPATIBILITY IDEOGRAPH-2F8E3 → CJK UNIFIED IDEOGRAPH-2346D\t# \n\nF97A ;\t6881 ;\tMA\t# ( 梁 → 梁 ) CJK COMPATIBILITY IDEOGRAPH-F97A → CJK UNIFIED IDEOGRAPH-6881\t# \n\nFA44 ;\t6885 ;\tMA\t# ( 梅 → 梅 ) CJK COMPATIBILITY IDEOGRAPH-FA44 → CJK UNIFIED IDEOGRAPH-6885\t# \n2F8E2 ;\t6885 ;\tMA\t# ( 梅 → 梅 ) CJK COMPATIBILITY IDEOGRAPH-2F8E2 → CJK UNIFIED IDEOGRAPH-6885\t# \n\n2F8E4 ;\t688E ;\tMA\t# ( 梎 → 梎 ) CJK COMPATIBILITY IDEOGRAPH-2F8E4 → CJK UNIFIED IDEOGRAPH-688E\t# \n\nF9E2 ;\t68A8 ;\tMA\t# ( 梨 → 梨 ) CJK COMPATIBILITY IDEOGRAPH-F9E2 → CJK UNIFIED IDEOGRAPH-68A8\t# \n\n2F8E6 ;\t6914 ;\tMA\t# ( 椔 → 椔 ) CJK COMPATIBILITY IDEOGRAPH-2F8E6 → CJK UNIFIED IDEOGRAPH-6914\t# \n\n2F8E8 ;\t6942 ;\tMA\t# ( 楂 → 楂 ) CJK COMPATIBILITY IDEOGRAPH-2F8E8 → CJK UNIFIED IDEOGRAPH-6942\t# \n\nFAD2 ;\t3B9D ;\tMA\t# ( 㮝 → 㮝 ) CJK COMPATIBILITY IDEOGRAPH-FAD2 → CJK UNIFIED IDEOGRAPH-3B9D\t# \n2F8E7 ;\t3B9D ;\tMA\t# ( 㮝 → 㮝 ) CJK COMPATIBILITY IDEOGRAPH-2F8E7 → CJK UNIFIED IDEOGRAPH-3B9D\t# \n\n69E9 ;\t3BA3 ;\tMA\t# ( 槩 → 㮣 ) CJK UNIFIED IDEOGRAPH-69E9 → CJK UNIFIED IDEOGRAPH-3BA3\t# \n\n6A27 ;\t699D ;\tMA\t# ( 樧 → 榝 ) CJK UNIFIED IDEOGRAPH-6A27 → CJK UNIFIED IDEOGRAPH-699D\t# \n\n2F8E9 ;\t69A3 ;\tMA\t# ( 榣 → 榣 ) CJK COMPATIBILITY IDEOGRAPH-2F8E9 → CJK UNIFIED IDEOGRAPH-69A3\t# \n\n2F8EA ;\t69EA ;\tMA\t# ( 槪 → 槪 ) CJK COMPATIBILITY IDEOGRAPH-2F8EA → CJK UNIFIED IDEOGRAPH-69EA\t# \n\nF914 ;\t6A02 ;\tMA\t# ( 樂 → 樂 ) CJK COMPATIBILITY IDEOGRAPH-F914 → CJK UNIFIED IDEOGRAPH-6A02\t# \nF95C ;\t6A02 ;\tMA\t# ( 樂 → 樂 ) CJK COMPATIBILITY IDEOGRAPH-F95C → CJK UNIFIED IDEOGRAPH-6A02\t# \nF9BF ;\t6A02 ;\tMA\t# ( 樂 → 樂 ) CJK COMPATIBILITY IDEOGRAPH-F9BF → CJK UNIFIED IDEOGRAPH-6A02\t# \n\nF94C ;\t6A13 ;\tMA\t# ( 樓 → 樓 ) CJK COMPATIBILITY IDEOGRAPH-F94C → CJK UNIFIED IDEOGRAPH-6A13\t# \n\n2F8EC ;\t236A3 ;\tMA\t# ( 𣚣 → 𣚣 ) CJK COMPATIBILITY IDEOGRAPH-2F8EC → CJK UNIFIED IDEOGRAPH-236A3\t# \n\n2F8EB ;\t6AA8 ;\tMA\t# ( 檨 → 檨 ) CJK COMPATIBILITY IDEOGRAPH-2F8EB → CJK UNIFIED IDEOGRAPH-6AA8\t# \n\nF931 ;\t6AD3 ;\tMA\t# ( 櫓 → 櫓 ) CJK COMPATIBILITY IDEOGRAPH-F931 → CJK UNIFIED IDEOGRAPH-6AD3\t# \n\n2F8ED ;\t6ADB ;\tMA\t# ( 櫛 → 櫛 ) CJK COMPATIBILITY IDEOGRAPH-2F8ED → CJK UNIFIED IDEOGRAPH-6ADB\t# \n\nF91D ;\t6B04 ;\tMA\t# ( 欄 → 欄 ) CJK COMPATIBILITY IDEOGRAPH-F91D → CJK UNIFIED IDEOGRAPH-6B04\t# \n\n2F8EE ;\t3C18 ;\tMA\t# ( 㰘 → 㰘 ) CJK COMPATIBILITY IDEOGRAPH-2F8EE → CJK UNIFIED IDEOGRAPH-3C18\t# \n\n2F4B ;\t6B20 ;\tMA\t#* ( ⽋ → 欠 ) KANGXI RADICAL LACK → CJK UNIFIED IDEOGRAPH-6B20\t# \n\n2F8EF ;\t6B21 ;\tMA\t# ( 次 → 次 ) CJK COMPATIBILITY IDEOGRAPH-2F8EF → CJK UNIFIED IDEOGRAPH-6B21\t# \n\n2F8F0 ;\t238A7 ;\tMA\t# ( 𣢧 → 𣢧 ) CJK COMPATIBILITY IDEOGRAPH-2F8F0 → CJK UNIFIED IDEOGRAPH-238A7\t# \n\n2F8F1 ;\t6B54 ;\tMA\t# ( 歔 → 歔 ) CJK COMPATIBILITY IDEOGRAPH-2F8F1 → CJK UNIFIED IDEOGRAPH-6B54\t# \n\n2F8F2 ;\t3C4E ;\tMA\t# ( 㱎 → 㱎 ) CJK COMPATIBILITY IDEOGRAPH-2F8F2 → CJK UNIFIED IDEOGRAPH-3C4E\t# \n\n2F4C ;\t6B62 ;\tMA\t#* ( ⽌ → 止 ) KANGXI RADICAL STOP → CJK UNIFIED IDEOGRAPH-6B62\t# \n\n2EED ;\t6B6F ;\tMA\t#* ( ⻭ → 歯 ) CJK RADICAL J-SIMPLIFIED TOOTH → CJK UNIFIED IDEOGRAPH-6B6F\t# \n\n2F8F3 ;\t6B72 ;\tMA\t# ( 歲 → 歲 ) CJK COMPATIBILITY IDEOGRAPH-2F8F3 → CJK UNIFIED IDEOGRAPH-6B72\t# \n\nF98C ;\t6B77 ;\tMA\t# ( 歷 → 歷 ) CJK COMPATIBILITY IDEOGRAPH-F98C → CJK UNIFIED IDEOGRAPH-6B77\t# \n\nFA95 ;\t6B79 ;\tMA\t# ( 歹 → 歹 ) CJK COMPATIBILITY IDEOGRAPH-FA95 → CJK UNIFIED IDEOGRAPH-6B79\t# \n2F4D ;\t6B79 ;\tMA\t#* ( ⽍ → 歹 ) KANGXI RADICAL DEATH → CJK UNIFIED IDEOGRAPH-6B79\t# \n\n2E9E ;\t6B7A ;\tMA\t#* ( ⺞ → 歺 ) CJK RADICAL DEATH → CJK UNIFIED IDEOGRAPH-6B7A\t# \n\n2F8F4 ;\t6B9F ;\tMA\t# ( 殟 → 殟 ) CJK COMPATIBILITY IDEOGRAPH-2F8F4 → CJK UNIFIED IDEOGRAPH-6B9F\t# \n\nF9A5 ;\t6BAE ;\tMA\t# ( 殮 → 殮 ) CJK COMPATIBILITY IDEOGRAPH-F9A5 → CJK UNIFIED IDEOGRAPH-6BAE\t# \n\n2F4E ;\t6BB3 ;\tMA\t#* ( ⽎ → 殳 ) KANGXI RADICAL WEAPON → CJK UNIFIED IDEOGRAPH-6BB3\t# \n\nF970 ;\t6BBA ;\tMA\t# ( 殺 → 殺 ) CJK COMPATIBILITY IDEOGRAPH-F970 → CJK UNIFIED IDEOGRAPH-6BBA\t# \nFA96 ;\t6BBA ;\tMA\t# ( 殺 → 殺 ) CJK COMPATIBILITY IDEOGRAPH-FA96 → CJK UNIFIED IDEOGRAPH-6BBA\t# \n2F8F5 ;\t6BBA ;\tMA\t# ( 殺 → 殺 ) CJK COMPATIBILITY IDEOGRAPH-2F8F5 → CJK UNIFIED IDEOGRAPH-6BBA\t# \n\n2F8F6 ;\t6BBB ;\tMA\t# ( 殻 → 殻 ) CJK COMPATIBILITY IDEOGRAPH-2F8F6 → CJK UNIFIED IDEOGRAPH-6BBB\t# \n\n2F8F7 ;\t23A8D ;\tMA\t# ( 𣪍 → 𣪍 ) CJK COMPATIBILITY IDEOGRAPH-2F8F7 → CJK UNIFIED IDEOGRAPH-23A8D\t# \n\n2F4F ;\t6BCB ;\tMA\t#* ( ⽏ → 毋 ) KANGXI RADICAL DO NOT → CJK UNIFIED IDEOGRAPH-6BCB\t# \n\n2E9F ;\t6BCD ;\tMA\t#* ( ⺟ → 母 ) CJK RADICAL MOTHER → CJK UNIFIED IDEOGRAPH-6BCD\t# \n\n2F8F9 ;\t23AFA ;\tMA\t# ( 𣫺 → 𣫺 ) CJK COMPATIBILITY IDEOGRAPH-2F8F9 → CJK UNIFIED IDEOGRAPH-23AFA\t# \n\n2F50 ;\t6BD4 ;\tMA\t#* ( ⽐ → 比 ) KANGXI RADICAL COMPARE → CJK UNIFIED IDEOGRAPH-6BD4\t# \n\n2F51 ;\t6BDB ;\tMA\t#* ( ⽑ → 毛 ) KANGXI RADICAL FUR → CJK UNIFIED IDEOGRAPH-6BDB\t# \n\n2F52 ;\t6C0F ;\tMA\t#* ( ⽒ → 氏 ) KANGXI RADICAL CLAN → CJK UNIFIED IDEOGRAPH-6C0F\t# \n\n2EA0 ;\t6C11 ;\tMA\t#* ( ⺠ → 民 ) CJK RADICAL CIVILIAN → CJK UNIFIED IDEOGRAPH-6C11\t# \n\n2F53 ;\t6C14 ;\tMA\t#* ( ⽓ → 气 ) KANGXI RADICAL STEAM → CJK UNIFIED IDEOGRAPH-6C14\t# \n\n2F54 ;\t6C34 ;\tMA\t#* ( ⽔ → 水 ) KANGXI RADICAL WATER → CJK UNIFIED IDEOGRAPH-6C34\t# \n\n2EA1 ;\t6C35 ;\tMA\t#* ( ⺡ → 氵 ) CJK RADICAL WATER ONE → CJK UNIFIED IDEOGRAPH-6C35\t# \n\n2EA2 ;\t6C3A ;\tMA\t#* ( ⺢ → 氺 ) CJK RADICAL WATER TWO → CJK UNIFIED IDEOGRAPH-6C3A\t# \n\n2F8FA ;\t6C4E ;\tMA\t# ( 汎 → 汎 ) CJK COMPATIBILITY IDEOGRAPH-2F8FA → CJK UNIFIED IDEOGRAPH-6C4E\t# \n\n2F8FE ;\t6C67 ;\tMA\t# ( 汧 → 汧 ) CJK COMPATIBILITY IDEOGRAPH-2F8FE → CJK UNIFIED IDEOGRAPH-6C67\t# \n\nF972 ;\t6C88 ;\tMA\t# ( 沈 → 沈 ) CJK COMPATIBILITY IDEOGRAPH-F972 → CJK UNIFIED IDEOGRAPH-6C88\t# \n\n2F8FC ;\t6CBF ;\tMA\t# ( 沿 → 沿 ) CJK COMPATIBILITY IDEOGRAPH-2F8FC → CJK UNIFIED IDEOGRAPH-6CBF\t# \n\nF968 ;\t6CCC ;\tMA\t# ( 泌 → 泌 ) CJK COMPATIBILITY IDEOGRAPH-F968 → CJK UNIFIED IDEOGRAPH-6CCC\t# \n\n2F8FD ;\t6CCD ;\tMA\t# ( 泍 → 泍 ) CJK COMPATIBILITY IDEOGRAPH-2F8FD → CJK UNIFIED IDEOGRAPH-6CCD\t# \n\nF9E3 ;\t6CE5 ;\tMA\t# ( 泥 → 泥 ) CJK COMPATIBILITY IDEOGRAPH-F9E3 → CJK UNIFIED IDEOGRAPH-6CE5\t# \n\n2F8FB ;\t23CBC ;\tMA\t# ( 𣲼 → 𣲼 ) CJK COMPATIBILITY IDEOGRAPH-2F8FB → CJK UNIFIED IDEOGRAPH-23CBC\t# \n\nF915 ;\t6D1B ;\tMA\t# ( 洛 → 洛 ) CJK COMPATIBILITY IDEOGRAPH-F915 → CJK UNIFIED IDEOGRAPH-6D1B\t# \n\nFA05 ;\t6D1E ;\tMA\t# ( 洞 → 洞 ) CJK COMPATIBILITY IDEOGRAPH-FA05 → CJK UNIFIED IDEOGRAPH-6D1E\t# \n\n2F907 ;\t6D34 ;\tMA\t# ( 洴 → 洴 ) CJK COMPATIBILITY IDEOGRAPH-2F907 → CJK UNIFIED IDEOGRAPH-6D34\t# \n\n2F900 ;\t6D3E ;\tMA\t# ( 派 → 派 ) CJK COMPATIBILITY IDEOGRAPH-2F900 → CJK UNIFIED IDEOGRAPH-6D3E\t# \n\nF9CA ;\t6D41 ;\tMA\t# ( 流 → 流 ) CJK COMPATIBILITY IDEOGRAPH-F9CA → CJK UNIFIED IDEOGRAPH-6D41\t# \nFA97 ;\t6D41 ;\tMA\t# ( 流 → 流 ) CJK COMPATIBILITY IDEOGRAPH-FA97 → CJK UNIFIED IDEOGRAPH-6D41\t# \n2F902 ;\t6D41 ;\tMA\t# ( 流 → 流 ) CJK COMPATIBILITY IDEOGRAPH-2F902 → CJK UNIFIED IDEOGRAPH-6D41\t# \n\n2F8FF ;\t6D16 ;\tMA\t# ( 洖 → 洖 ) CJK COMPATIBILITY IDEOGRAPH-2F8FF → CJK UNIFIED IDEOGRAPH-6D16\t# \n\n2F903 ;\t6D69 ;\tMA\t# ( 浩 → 浩 ) CJK COMPATIBILITY IDEOGRAPH-2F903 → CJK UNIFIED IDEOGRAPH-6D69\t# \n\nF92A ;\t6D6A ;\tMA\t# ( 浪 → 浪 ) CJK COMPATIBILITY IDEOGRAPH-F92A → CJK UNIFIED IDEOGRAPH-6D6A\t# \n\nFA45 ;\t6D77 ;\tMA\t# ( 海 → 海 ) CJK COMPATIBILITY IDEOGRAPH-FA45 → CJK UNIFIED IDEOGRAPH-6D77\t# \n2F901 ;\t6D77 ;\tMA\t# ( 海 → 海 ) CJK COMPATIBILITY IDEOGRAPH-2F901 → CJK UNIFIED IDEOGRAPH-6D77\t# \n\n2F904 ;\t6D78 ;\tMA\t# ( 浸 → 浸 ) CJK COMPATIBILITY IDEOGRAPH-2F904 → CJK UNIFIED IDEOGRAPH-6D78\t# \n\n2F905 ;\t6D85 ;\tMA\t# ( 涅 → 涅 ) CJK COMPATIBILITY IDEOGRAPH-2F905 → CJK UNIFIED IDEOGRAPH-6D85\t# \n23D40 ;\t6D85 ;\tMA\t# ( 𣵀 → 涅 ) CJK UNIFIED IDEOGRAPH-23D40 → CJK UNIFIED IDEOGRAPH-6D85\t# →涅→\n\n2F906 ;\t23D1E ;\tMA\t# ( 𣴞 → 𣴞 ) CJK COMPATIBILITY IDEOGRAPH-2F906 → CJK UNIFIED IDEOGRAPH-23D1E\t# \n\nF9F5 ;\t6DCB ;\tMA\t# ( 淋 → 淋 ) CJK COMPATIBILITY IDEOGRAPH-F9F5 → CJK UNIFIED IDEOGRAPH-6DCB\t# \n\nF94D ;\t6DDA ;\tMA\t# ( 淚 → 淚 ) CJK COMPATIBILITY IDEOGRAPH-F94D → CJK UNIFIED IDEOGRAPH-6DDA\t# \n\nF9D6 ;\t6DEA ;\tMA\t# ( 淪 → 淪 ) CJK COMPATIBILITY IDEOGRAPH-F9D6 → CJK UNIFIED IDEOGRAPH-6DEA\t# \n\n2F90E ;\t6DF9 ;\tMA\t# ( 淹 → 淹 ) CJK COMPATIBILITY IDEOGRAPH-2F90E → CJK UNIFIED IDEOGRAPH-6DF9\t# \n\nFA46 ;\t6E1A ;\tMA\t# ( 渚 → 渚 ) CJK COMPATIBILITY IDEOGRAPH-FA46 → CJK UNIFIED IDEOGRAPH-6E1A\t# \n\n2F908 ;\t6E2F ;\tMA\t# ( 港 → 港 ) CJK COMPATIBILITY IDEOGRAPH-2F908 → CJK UNIFIED IDEOGRAPH-6E2F\t# \n\n2F909 ;\t6E6E ;\tMA\t# ( 湮 → 湮 ) CJK COMPATIBILITY IDEOGRAPH-2F909 → CJK UNIFIED IDEOGRAPH-6E6E\t# \n\n6F59 ;\t6E88 ;\tMA\t# ( 潙 → 溈 ) CJK UNIFIED IDEOGRAPH-6F59 → CJK UNIFIED IDEOGRAPH-6E88\t# \n\nFA99 ;\t6ECB ;\tMA\t# ( 滋 → 滋 ) CJK COMPATIBILITY IDEOGRAPH-FA99 → CJK UNIFIED IDEOGRAPH-6ECB\t# \n2F90B ;\t6ECB ;\tMA\t# ( 滋 → 滋 ) CJK COMPATIBILITY IDEOGRAPH-2F90B → CJK UNIFIED IDEOGRAPH-6ECB\t# \n\nF9CB ;\t6E9C ;\tMA\t# ( 溜 → 溜 ) CJK COMPATIBILITY IDEOGRAPH-F9CB → CJK UNIFIED IDEOGRAPH-6E9C\t# \n\nF9EC ;\t6EBA ;\tMA\t# ( 溺 → 溺 ) CJK COMPATIBILITY IDEOGRAPH-F9EC → CJK UNIFIED IDEOGRAPH-6EBA\t# \n\n2F90C ;\t6EC7 ;\tMA\t# ( 滇 → 滇 ) CJK COMPATIBILITY IDEOGRAPH-2F90C → CJK UNIFIED IDEOGRAPH-6EC7\t# \n\nF904 ;\t6ED1 ;\tMA\t# ( 滑 → 滑 ) CJK COMPATIBILITY IDEOGRAPH-F904 → CJK UNIFIED IDEOGRAPH-6ED1\t# \n\nFA98 ;\t6EDB ;\tMA\t# ( 滛 → 滛 ) CJK COMPATIBILITY IDEOGRAPH-FA98 → CJK UNIFIED IDEOGRAPH-6EDB\t# \n\n2F90A ;\t3D33 ;\tMA\t# ( 㴳 → 㴳 ) CJK COMPATIBILITY IDEOGRAPH-2F90A → CJK UNIFIED IDEOGRAPH-3D33\t# \n\nF94E ;\t6F0F ;\tMA\t# ( 漏 → 漏 ) CJK COMPATIBILITY IDEOGRAPH-F94E → CJK UNIFIED IDEOGRAPH-6F0F\t# \n\nFA47 ;\t6F22 ;\tMA\t# ( 漢 → 漢 ) CJK COMPATIBILITY IDEOGRAPH-FA47 → CJK UNIFIED IDEOGRAPH-6F22\t# \nFA9A ;\t6F22 ;\tMA\t# ( 漢 → 漢 ) CJK COMPATIBILITY IDEOGRAPH-FA9A → CJK UNIFIED IDEOGRAPH-6F22\t# \n\nF992 ;\t6F23 ;\tMA\t# ( 漣 → 漣 ) CJK COMPATIBILITY IDEOGRAPH-F992 → CJK UNIFIED IDEOGRAPH-6F23\t# \n\n2F90D ;\t23ED1 ;\tMA\t# ( 𣻑 → 𣻑 ) CJK COMPATIBILITY IDEOGRAPH-2F90D → CJK UNIFIED IDEOGRAPH-23ED1\t# \n\n2F90F ;\t6F6E ;\tMA\t# ( 潮 → 潮 ) CJK COMPATIBILITY IDEOGRAPH-2F90F → CJK UNIFIED IDEOGRAPH-6F6E\t# \n\n2F910 ;\t23F5E ;\tMA\t# ( 𣽞 → 𣽞 ) CJK COMPATIBILITY IDEOGRAPH-2F910 → CJK UNIFIED IDEOGRAPH-23F5E\t# \n\n2F911 ;\t23F8E ;\tMA\t# ( 𣾎 → 𣾎 ) CJK COMPATIBILITY IDEOGRAPH-2F911 → CJK UNIFIED IDEOGRAPH-23F8E\t# \n\n2F912 ;\t6FC6 ;\tMA\t# ( 濆 → 濆 ) CJK COMPATIBILITY IDEOGRAPH-2F912 → CJK UNIFIED IDEOGRAPH-6FC6\t# \n\nF922 ;\t6FEB ;\tMA\t# ( 濫 → 濫 ) CJK COMPATIBILITY IDEOGRAPH-F922 → CJK UNIFIED IDEOGRAPH-6FEB\t# \n\nF984 ;\t6FFE ;\tMA\t# ( 濾 → 濾 ) CJK COMPATIBILITY IDEOGRAPH-F984 → CJK UNIFIED IDEOGRAPH-6FFE\t# \n\n2F915 ;\t701B ;\tMA\t# ( 瀛 → 瀛 ) CJK COMPATIBILITY IDEOGRAPH-2F915 → CJK UNIFIED IDEOGRAPH-701B\t# \n\nFA9B ;\t701E ;\tMA\t# ( 瀞 → 瀞 ) CJK COMPATIBILITY IDEOGRAPH-FA9B → CJK UNIFIED IDEOGRAPH-701E\t# \n2F914 ;\t701E ;\tMA\t# ( 瀞 → 瀞 ) CJK COMPATIBILITY IDEOGRAPH-2F914 → CJK UNIFIED IDEOGRAPH-701E\t# \n\n2F913 ;\t7039 ;\tMA\t# ( 瀹 → 瀹 ) CJK COMPATIBILITY IDEOGRAPH-2F913 → CJK UNIFIED IDEOGRAPH-7039\t# \n\n2F917 ;\t704A ;\tMA\t# ( 灊 → 灊 ) CJK COMPATIBILITY IDEOGRAPH-2F917 → CJK UNIFIED IDEOGRAPH-704A\t# \n\n2F916 ;\t3D96 ;\tMA\t# ( 㶖 → 㶖 ) CJK COMPATIBILITY IDEOGRAPH-2F916 → CJK UNIFIED IDEOGRAPH-3D96\t# \n\n2F55 ;\t706B ;\tMA\t#* ( ⽕ → 火 ) KANGXI RADICAL FIRE → CJK UNIFIED IDEOGRAPH-706B\t# \n\n2EA3 ;\t706C ;\tMA\t#* ( ⺣ → 灬 ) CJK RADICAL FIRE → CJK UNIFIED IDEOGRAPH-706C\t# \n\n2F835 ;\t7070 ;\tMA\t# ( 灰 → 灰 ) CJK COMPATIBILITY IDEOGRAPH-2F835 → CJK UNIFIED IDEOGRAPH-7070\t# \n\n2F919 ;\t7077 ;\tMA\t# ( 灷 → 灷 ) CJK COMPATIBILITY IDEOGRAPH-2F919 → CJK UNIFIED IDEOGRAPH-7077\t# \n\n2F918 ;\t707D ;\tMA\t# ( 災 → 災 ) CJK COMPATIBILITY IDEOGRAPH-2F918 → CJK UNIFIED IDEOGRAPH-707D\t# \n\nF9FB ;\t7099 ;\tMA\t# ( 炙 → 炙 ) CJK COMPATIBILITY IDEOGRAPH-F9FB → CJK UNIFIED IDEOGRAPH-7099\t# \n\n2F91A ;\t70AD ;\tMA\t# ( 炭 → 炭 ) CJK COMPATIBILITY IDEOGRAPH-2F91A → CJK UNIFIED IDEOGRAPH-70AD\t# \n\nF99F ;\t70C8 ;\tMA\t# ( 烈 → 烈 ) CJK COMPATIBILITY IDEOGRAPH-F99F → CJK UNIFIED IDEOGRAPH-70C8\t# \n\nF916 ;\t70D9 ;\tMA\t# ( 烙 → 烙 ) CJK COMPATIBILITY IDEOGRAPH-F916 → CJK UNIFIED IDEOGRAPH-70D9\t# \n\nFA48 ;\t716E ;\tMA\t# ( 煮 → 煮 ) CJK COMPATIBILITY IDEOGRAPH-FA48 → CJK UNIFIED IDEOGRAPH-716E\t# \nFA9C ;\t716E ;\tMA\t# ( 煮 → 煮 ) CJK COMPATIBILITY IDEOGRAPH-FA9C → CJK UNIFIED IDEOGRAPH-716E\t# \n\n2F91D ;\t24263 ;\tMA\t# ( 𤉣 → 𤉣 ) CJK COMPATIBILITY IDEOGRAPH-2F91D → CJK UNIFIED IDEOGRAPH-24263\t# \n\n2F91C ;\t7145 ;\tMA\t# ( 煅 → 煅 ) CJK COMPATIBILITY IDEOGRAPH-2F91C → CJK UNIFIED IDEOGRAPH-7145\t# \n\nF993 ;\t7149 ;\tMA\t# ( 煉 → 煉 ) CJK COMPATIBILITY IDEOGRAPH-F993 → CJK UNIFIED IDEOGRAPH-7149\t# \n\nFA6C ;\t242EE ;\tMA\t# ( 𤋮 → 𤋮 ) CJK COMPATIBILITY IDEOGRAPH-FA6C → CJK UNIFIED IDEOGRAPH-242EE\t# \n\n2F91E ;\t719C ;\tMA\t# ( 熜 → 熜 ) CJK COMPATIBILITY IDEOGRAPH-2F91E → CJK UNIFIED IDEOGRAPH-719C\t# \n\nF9C0 ;\t71CE ;\tMA\t# ( 燎 → 燎 ) CJK COMPATIBILITY IDEOGRAPH-F9C0 → CJK UNIFIED IDEOGRAPH-71CE\t# \n\nF9EE ;\t71D0 ;\tMA\t# ( 燐 → 燐 ) CJK COMPATIBILITY IDEOGRAPH-F9EE → CJK UNIFIED IDEOGRAPH-71D0\t# \n\n2F91F ;\t243AB ;\tMA\t# ( 𤎫 → 𤎫 ) CJK COMPATIBILITY IDEOGRAPH-2F91F → CJK UNIFIED IDEOGRAPH-243AB\t# \n\nF932 ;\t7210 ;\tMA\t# ( 爐 → 爐 ) CJK COMPATIBILITY IDEOGRAPH-F932 → CJK UNIFIED IDEOGRAPH-7210\t# \n\nF91E ;\t721B ;\tMA\t# ( 爛 → 爛 ) CJK COMPATIBILITY IDEOGRAPH-F91E → CJK UNIFIED IDEOGRAPH-721B\t# \n\n2F920 ;\t7228 ;\tMA\t# ( 爨 → 爨 ) CJK COMPATIBILITY IDEOGRAPH-2F920 → CJK UNIFIED IDEOGRAPH-7228\t# \n\n2F56 ;\t722A ;\tMA\t#* ( ⽖ → 爪 ) KANGXI RADICAL CLAW → CJK UNIFIED IDEOGRAPH-722A\t# \n\nFA49 ;\t722B ;\tMA\t# ( 爫 → 爫 ) CJK COMPATIBILITY IDEOGRAPH-FA49 → CJK UNIFIED IDEOGRAPH-722B\t# \n2EA4 ;\t722B ;\tMA\t#* ( ⺤ → 爫 ) CJK RADICAL PAW ONE → CJK UNIFIED IDEOGRAPH-722B\t# \n\nFA9E ;\t7235 ;\tMA\t# ( 爵 → 爵 ) CJK COMPATIBILITY IDEOGRAPH-FA9E → CJK UNIFIED IDEOGRAPH-7235\t# \n2F921 ;\t7235 ;\tMA\t# ( 爵 → 爵 ) CJK COMPATIBILITY IDEOGRAPH-2F921 → CJK UNIFIED IDEOGRAPH-7235\t# \n\n2F57 ;\t7236 ;\tMA\t#* ( ⽗ → 父 ) KANGXI RADICAL FATHER → CJK UNIFIED IDEOGRAPH-7236\t# \n\n2F58 ;\t723B ;\tMA\t#* ( ⽘ → 爻 ) KANGXI RADICAL DOUBLE X → CJK UNIFIED IDEOGRAPH-723B\t# \n\n2EA6 ;\t4E2C ;\tMA\t#* ( ⺦ → 丬 ) CJK RADICAL SIMPLIFIED HALF TREE TRUNK → CJK UNIFIED IDEOGRAPH-4E2C\t# \n\n2F5A ;\t7247 ;\tMA\t#* ( ⽚ → 片 ) KANGXI RADICAL SLICE → CJK UNIFIED IDEOGRAPH-7247\t# \n\n2F922 ;\t7250 ;\tMA\t# ( 牐 → 牐 ) CJK COMPATIBILITY IDEOGRAPH-2F922 → CJK UNIFIED IDEOGRAPH-7250\t# \n\n2F5B ;\t7259 ;\tMA\t#* ( ⽛ → 牙 ) KANGXI RADICAL FANG → CJK UNIFIED IDEOGRAPH-7259\t# \n\n2F923 ;\t24608 ;\tMA\t# ( 𤘈 → 𤘈 ) CJK COMPATIBILITY IDEOGRAPH-2F923 → CJK UNIFIED IDEOGRAPH-24608\t# \n\n2F5C ;\t725B ;\tMA\t#* ( ⽜ → 牛 ) KANGXI RADICAL COW → CJK UNIFIED IDEOGRAPH-725B\t# \n\nF946 ;\t7262 ;\tMA\t# ( 牢 → 牢 ) CJK COMPATIBILITY IDEOGRAPH-F946 → CJK UNIFIED IDEOGRAPH-7262\t# \n\n2F924 ;\t7280 ;\tMA\t# ( 犀 → 犀 ) CJK COMPATIBILITY IDEOGRAPH-2F924 → CJK UNIFIED IDEOGRAPH-7280\t# \n\n2F925 ;\t7295 ;\tMA\t# ( 犕 → 犕 ) CJK COMPATIBILITY IDEOGRAPH-2F925 → CJK UNIFIED IDEOGRAPH-7295\t# \n\n2F5D ;\t72AC ;\tMA\t#* ( ⽝ → 犬 ) KANGXI RADICAL DOG → CJK UNIFIED IDEOGRAPH-72AC\t# \n\n2EA8 ;\t72AD ;\tMA\t#* ( ⺨ → 犭 ) CJK RADICAL DOG → CJK UNIFIED IDEOGRAPH-72AD\t# \n\nFA9F ;\t72AF ;\tMA\t# ( 犯 → 犯 ) CJK COMPATIBILITY IDEOGRAPH-FA9F → CJK UNIFIED IDEOGRAPH-72AF\t# \n\nF9FA ;\t72C0 ;\tMA\t# ( 狀 → 狀 ) CJK COMPATIBILITY IDEOGRAPH-F9FA → CJK UNIFIED IDEOGRAPH-72C0\t# \n\n2F926 ;\t24735 ;\tMA\t# ( 𤜵 → 𤜵 ) CJK COMPATIBILITY IDEOGRAPH-2F926 → CJK UNIFIED IDEOGRAPH-24735\t# \n\nF92B ;\t72FC ;\tMA\t# ( 狼 → 狼 ) CJK COMPATIBILITY IDEOGRAPH-F92B → CJK UNIFIED IDEOGRAPH-72FC\t# \n\nFA16 ;\t732A ;\tMA\t# ( 猪 → 猪 ) CJK COMPATIBILITY IDEOGRAPH-FA16 → CJK UNIFIED IDEOGRAPH-732A\t# \nFAA0 ;\t732A ;\tMA\t# ( 猪 → 猪 ) CJK COMPATIBILITY IDEOGRAPH-FAA0 → CJK UNIFIED IDEOGRAPH-732A\t# \n\n2AEC5 ;\t24814 ;\tMA\t# ( 𪻅 → 𤠔 ) CJK UNIFIED IDEOGRAPH-2AEC5 → CJK UNIFIED IDEOGRAPH-24814\t# →𤠔→\n2F927 ;\t24814 ;\tMA\t# ( 𤠔 → 𤠔 ) CJK COMPATIBILITY IDEOGRAPH-2F927 → CJK UNIFIED IDEOGRAPH-24814\t# \n\nF9A7 ;\t7375 ;\tMA\t# ( 獵 → 獵 ) CJK COMPATIBILITY IDEOGRAPH-F9A7 → CJK UNIFIED IDEOGRAPH-7375\t# \n\n2F928 ;\t737A ;\tMA\t# ( 獺 → 獺 ) CJK COMPATIBILITY IDEOGRAPH-2F928 → CJK UNIFIED IDEOGRAPH-737A\t# \n\n2F5E ;\t7384 ;\tMA\t#* ( ⽞ → 玄 ) KANGXI RADICAL PROFOUND → CJK UNIFIED IDEOGRAPH-7384\t# \n\nF961 ;\t7387 ;\tMA\t# ( 率 → 率 ) CJK COMPATIBILITY IDEOGRAPH-F961 → CJK UNIFIED IDEOGRAPH-7387\t# \nF9DB ;\t7387 ;\tMA\t# ( 率 → 率 ) CJK COMPATIBILITY IDEOGRAPH-F9DB → CJK UNIFIED IDEOGRAPH-7387\t# \n\n2F5F ;\t7389 ;\tMA\t#* ( ⽟ → 玉 ) KANGXI RADICAL JADE → CJK UNIFIED IDEOGRAPH-7389\t# \n\n2F929 ;\t738B ;\tMA\t# ( 王 → 王 ) CJK COMPATIBILITY IDEOGRAPH-2F929 → CJK UNIFIED IDEOGRAPH-738B\t# \n\n2F92A ;\t3EAC ;\tMA\t# ( 㺬 → 㺬 ) CJK COMPATIBILITY IDEOGRAPH-2F92A → CJK UNIFIED IDEOGRAPH-3EAC\t# \n\n2F92B ;\t73A5 ;\tMA\t# ( 玥 → 玥 ) CJK COMPATIBILITY IDEOGRAPH-2F92B → CJK UNIFIED IDEOGRAPH-73A5\t# \n248FD ;\t73A5 ;\tMA\t# ( 𤣽 → 玥 ) CJK UNIFIED IDEOGRAPH-248FD → CJK UNIFIED IDEOGRAPH-73A5\t# →玥→\n\nF9AD ;\t73B2 ;\tMA\t# ( 玲 → 玲 ) CJK COMPATIBILITY IDEOGRAPH-F9AD → CJK UNIFIED IDEOGRAPH-73B2\t# \n\n2F92C ;\t3EB8 ;\tMA\t# ( 㺸 → 㺸 ) CJK COMPATIBILITY IDEOGRAPH-2F92C → CJK UNIFIED IDEOGRAPH-3EB8\t# \n2F92D ;\t3EB8 ;\tMA\t# ( 㺸 → 㺸 ) CJK COMPATIBILITY IDEOGRAPH-2F92D → CJK UNIFIED IDEOGRAPH-3EB8\t# \n\nF917 ;\t73DE ;\tMA\t# ( 珞 → 珞 ) CJK COMPATIBILITY IDEOGRAPH-F917 → CJK UNIFIED IDEOGRAPH-73DE\t# \n\nF9CC ;\t7409 ;\tMA\t# ( 琉 → 琉 ) CJK COMPATIBILITY IDEOGRAPH-F9CC → CJK UNIFIED IDEOGRAPH-7409\t# \n\nF9E4 ;\t7406 ;\tMA\t# ( 理 → 理 ) CJK COMPATIBILITY IDEOGRAPH-F9E4 → CJK UNIFIED IDEOGRAPH-7406\t# \n\nFA4A ;\t7422 ;\tMA\t# ( 琢 → 琢 ) CJK COMPATIBILITY IDEOGRAPH-FA4A → CJK UNIFIED IDEOGRAPH-7422\t# \n\n2F92E ;\t7447 ;\tMA\t# ( 瑇 → 瑇 ) CJK COMPATIBILITY IDEOGRAPH-2F92E → CJK UNIFIED IDEOGRAPH-7447\t# \n\n2F92F ;\t745C ;\tMA\t# ( 瑜 → 瑜 ) CJK COMPATIBILITY IDEOGRAPH-2F92F → CJK UNIFIED IDEOGRAPH-745C\t# \n\nF9AE ;\t7469 ;\tMA\t# ( 瑩 → 瑩 ) CJK COMPATIBILITY IDEOGRAPH-F9AE → CJK UNIFIED IDEOGRAPH-7469\t# \n\nFAA1 ;\t7471 ;\tMA\t# ( 瑱 → 瑱 ) CJK COMPATIBILITY IDEOGRAPH-FAA1 → CJK UNIFIED IDEOGRAPH-7471\t# \n2F930 ;\t7471 ;\tMA\t# ( 瑱 → 瑱 ) CJK COMPATIBILITY IDEOGRAPH-2F930 → CJK UNIFIED IDEOGRAPH-7471\t# \n\n2F931 ;\t7485 ;\tMA\t# ( 璅 → 璅 ) CJK COMPATIBILITY IDEOGRAPH-2F931 → CJK UNIFIED IDEOGRAPH-7485\t# \n\nF994 ;\t7489 ;\tMA\t# ( 璉 → 璉 ) CJK COMPATIBILITY IDEOGRAPH-F994 → CJK UNIFIED IDEOGRAPH-7489\t# \n\nF9EF ;\t7498 ;\tMA\t# ( 璘 → 璘 ) CJK COMPATIBILITY IDEOGRAPH-F9EF → CJK UNIFIED IDEOGRAPH-7498\t# \n\n2F932 ;\t74CA ;\tMA\t# ( 瓊 → 瓊 ) CJK COMPATIBILITY IDEOGRAPH-2F932 → CJK UNIFIED IDEOGRAPH-74CA\t# \n\n2F60 ;\t74DC ;\tMA\t#* ( ⽠ → 瓜 ) KANGXI RADICAL MELON → CJK UNIFIED IDEOGRAPH-74DC\t# \n\n2F61 ;\t74E6 ;\tMA\t#* ( ⽡ → 瓦 ) KANGXI RADICAL TILE → CJK UNIFIED IDEOGRAPH-74E6\t# \n\n2F933 ;\t3F1B ;\tMA\t# ( 㼛 → 㼛 ) CJK COMPATIBILITY IDEOGRAPH-2F933 → CJK UNIFIED IDEOGRAPH-3F1B\t# \n\nFAA2 ;\t7506 ;\tMA\t# ( 甆 → 甆 ) CJK COMPATIBILITY IDEOGRAPH-FAA2 → CJK UNIFIED IDEOGRAPH-7506\t# \n\n2F62 ;\t7518 ;\tMA\t#* ( ⽢ → 甘 ) KANGXI RADICAL SWEET → CJK UNIFIED IDEOGRAPH-7518\t# \n\n2F63 ;\t751F ;\tMA\t#* ( ⽣ → 生 ) KANGXI RADICAL LIFE → CJK UNIFIED IDEOGRAPH-751F\t# \n\n2F934 ;\t7524 ;\tMA\t# ( 甤 → 甤 ) CJK COMPATIBILITY IDEOGRAPH-2F934 → CJK UNIFIED IDEOGRAPH-7524\t# \n\n2F64 ;\t7528 ;\tMA\t#* ( ⽤ → 用 ) KANGXI RADICAL USE → CJK UNIFIED IDEOGRAPH-7528\t# \n\n2F65 ;\t7530 ;\tMA\t#* ( ⽥ → 田 ) KANGXI RADICAL FIELD → CJK UNIFIED IDEOGRAPH-7530\t# \n\nFAA3 ;\t753B ;\tMA\t# ( 画 → 画 ) CJK COMPATIBILITY IDEOGRAPH-FAA3 → CJK UNIFIED IDEOGRAPH-753B\t# \n\n2F936 ;\t753E ;\tMA\t# ( 甾 → 甾 ) CJK COMPATIBILITY IDEOGRAPH-2F936 → CJK UNIFIED IDEOGRAPH-753E\t# \n\n2F935 ;\t24C36 ;\tMA\t# ( 𤰶 → 𤰶 ) CJK COMPATIBILITY IDEOGRAPH-2F935 → CJK UNIFIED IDEOGRAPH-24C36\t# \n\nF9CD ;\t7559 ;\tMA\t# ( 留 → 留 ) CJK COMPATIBILITY IDEOGRAPH-F9CD → CJK UNIFIED IDEOGRAPH-7559\t# \n\nF976 ;\t7565 ;\tMA\t# ( 略 → 略 ) CJK COMPATIBILITY IDEOGRAPH-F976 → CJK UNIFIED IDEOGRAPH-7565\t# \n\nF962 ;\t7570 ;\tMA\t# ( 異 → 異 ) CJK COMPATIBILITY IDEOGRAPH-F962 → CJK UNIFIED IDEOGRAPH-7570\t# \n2F938 ;\t7570 ;\tMA\t# ( 異 → 異 ) CJK COMPATIBILITY IDEOGRAPH-2F938 → CJK UNIFIED IDEOGRAPH-7570\t# \n\n2F937 ;\t24C92 ;\tMA\t# ( 𤲒 → 𤲒 ) CJK COMPATIBILITY IDEOGRAPH-2F937 → CJK UNIFIED IDEOGRAPH-24C92\t# \n\n2F66 ;\t758B ;\tMA\t#* ( ⽦ → 疋 ) KANGXI RADICAL BOLT OF CLOTH → CJK UNIFIED IDEOGRAPH-758B\t# \n\n2F67 ;\t7592 ;\tMA\t#* ( ⽧ → 疒 ) KANGXI RADICAL SICKNESS → CJK UNIFIED IDEOGRAPH-7592\t# \n\nF9E5 ;\t75E2 ;\tMA\t# ( 痢 → 痢 ) CJK COMPATIBILITY IDEOGRAPH-F9E5 → CJK UNIFIED IDEOGRAPH-75E2\t# \n\n2F93A ;\t7610 ;\tMA\t# ( 瘐 → 瘐 ) CJK COMPATIBILITY IDEOGRAPH-2F93A → CJK UNIFIED IDEOGRAPH-7610\t# \n\nFAA5 ;\t761F ;\tMA\t# ( 瘟 → 瘟 ) CJK COMPATIBILITY IDEOGRAPH-FAA5 → CJK UNIFIED IDEOGRAPH-761F\t# \n\nFAA4 ;\t761D ;\tMA\t# ( 瘝 → 瘝 ) CJK COMPATIBILITY IDEOGRAPH-FAA4 → CJK UNIFIED IDEOGRAPH-761D\t# \n\nF9C1 ;\t7642 ;\tMA\t# ( 療 → 療 ) CJK COMPATIBILITY IDEOGRAPH-F9C1 → CJK UNIFIED IDEOGRAPH-7642\t# \n\nF90E ;\t7669 ;\tMA\t# ( 癩 → 癩 ) CJK COMPATIBILITY IDEOGRAPH-F90E → CJK UNIFIED IDEOGRAPH-7669\t# \n\n2F68 ;\t7676 ;\tMA\t#* ( ⽨ → 癶 ) KANGXI RADICAL DOTTED TENT → CJK UNIFIED IDEOGRAPH-7676\t# \n\n2F69 ;\t767D ;\tMA\t#* ( ⽩ → 白 ) KANGXI RADICAL WHITE → CJK UNIFIED IDEOGRAPH-767D\t# \n\n2F93B ;\t24FA1 ;\tMA\t# ( 𤾡 → 𤾡 ) CJK COMPATIBILITY IDEOGRAPH-2F93B → CJK UNIFIED IDEOGRAPH-24FA1\t# \n\n2F93C ;\t24FB8 ;\tMA\t# ( 𤾸 → 𤾸 ) CJK COMPATIBILITY IDEOGRAPH-2F93C → CJK UNIFIED IDEOGRAPH-24FB8\t# \n\n2F6A ;\t76AE ;\tMA\t#* ( ⽪ → 皮 ) KANGXI RADICAL SKIN → CJK UNIFIED IDEOGRAPH-76AE\t# \n\n2F6B ;\t76BF ;\tMA\t#* ( ⽫ → 皿 ) KANGXI RADICAL DISH → CJK UNIFIED IDEOGRAPH-76BF\t# \n\n2F93D ;\t25044 ;\tMA\t# ( 𥁄 → 𥁄 ) CJK COMPATIBILITY IDEOGRAPH-2F93D → CJK UNIFIED IDEOGRAPH-25044\t# \n\n2F93E ;\t3FFC ;\tMA\t# ( 㿼 → 㿼 ) CJK COMPATIBILITY IDEOGRAPH-2F93E → CJK UNIFIED IDEOGRAPH-3FFC\t# \n\nFA17 ;\t76CA ;\tMA\t# ( 益 → 益 ) CJK COMPATIBILITY IDEOGRAPH-FA17 → CJK UNIFIED IDEOGRAPH-76CA\t# \nFAA6 ;\t76CA ;\tMA\t# ( 益 → 益 ) CJK COMPATIBILITY IDEOGRAPH-FAA6 → CJK UNIFIED IDEOGRAPH-76CA\t# \n\nFAA7 ;\t76DB ;\tMA\t# ( 盛 → 盛 ) CJK COMPATIBILITY IDEOGRAPH-FAA7 → CJK UNIFIED IDEOGRAPH-76DB\t# \n\nF933 ;\t76E7 ;\tMA\t# ( 盧 → 盧 ) CJK COMPATIBILITY IDEOGRAPH-F933 → CJK UNIFIED IDEOGRAPH-76E7\t# \n\n2F93F ;\t4008 ;\tMA\t# ( 䀈 → 䀈 ) CJK COMPATIBILITY IDEOGRAPH-2F93F → CJK UNIFIED IDEOGRAPH-4008\t# \n\n2F6C ;\t76EE ;\tMA\t#* ( ⽬ → 目 ) KANGXI RADICAL EYE → CJK UNIFIED IDEOGRAPH-76EE\t# \n\nFAA8 ;\t76F4 ;\tMA\t# ( 直 → 直 ) CJK COMPATIBILITY IDEOGRAPH-FAA8 → CJK UNIFIED IDEOGRAPH-76F4\t# \n2F940 ;\t76F4 ;\tMA\t# ( 直 → 直 ) CJK COMPATIBILITY IDEOGRAPH-2F940 → CJK UNIFIED IDEOGRAPH-76F4\t# \n\n2F942 ;\t250F2 ;\tMA\t# ( 𥃲 → 𥃲 ) CJK COMPATIBILITY IDEOGRAPH-2F942 → CJK UNIFIED IDEOGRAPH-250F2\t# \n\n2F941 ;\t250F3 ;\tMA\t# ( 𥃳 → 𥃳 ) CJK COMPATIBILITY IDEOGRAPH-2F941 → CJK UNIFIED IDEOGRAPH-250F3\t# \n\nF96D ;\t7701 ;\tMA\t# ( 省 → 省 ) CJK COMPATIBILITY IDEOGRAPH-F96D → CJK UNIFIED IDEOGRAPH-7701\t# \n\nFAD3 ;\t4018 ;\tMA\t# ( 䀘 → 䀘 ) CJK COMPATIBILITY IDEOGRAPH-FAD3 → CJK UNIFIED IDEOGRAPH-4018\t# \n\n2F943 ;\t25119 ;\tMA\t# ( 𥄙 → 𥄙 ) CJK COMPATIBILITY IDEOGRAPH-2F943 → CJK UNIFIED IDEOGRAPH-25119\t# \n2511A ;\t25119 ;\tMA\t# ( 𥄚 → 𥄙 ) CJK UNIFIED IDEOGRAPH-2511A → CJK UNIFIED IDEOGRAPH-25119\t# →𥄙→\n\n2F945 ;\t771E ;\tMA\t# ( 眞 → 眞 ) CJK COMPATIBILITY IDEOGRAPH-2F945 → CJK UNIFIED IDEOGRAPH-771E\t# \n\n2F946 ;\t771F ;\tMA\t# ( 真 → 真 ) CJK COMPATIBILITY IDEOGRAPH-2F946 → CJK UNIFIED IDEOGRAPH-771F\t# \n2F947 ;\t771F ;\tMA\t# ( 真 → 真 ) CJK COMPATIBILITY IDEOGRAPH-2F947 → CJK UNIFIED IDEOGRAPH-771F\t# \n\n2F944 ;\t25133 ;\tMA\t# ( 𥄳 → 𥄳 ) CJK COMPATIBILITY IDEOGRAPH-2F944 → CJK UNIFIED IDEOGRAPH-25133\t# \n\nFAAA ;\t7740 ;\tMA\t# ( 着 → 着 ) CJK COMPATIBILITY IDEOGRAPH-FAAA → CJK UNIFIED IDEOGRAPH-7740\t# \n\nFAA9 ;\t774A ;\tMA\t# ( 睊 → 睊 ) CJK COMPATIBILITY IDEOGRAPH-FAA9 → CJK UNIFIED IDEOGRAPH-774A\t# \n2F948 ;\t774A ;\tMA\t# ( 睊 → 睊 ) CJK COMPATIBILITY IDEOGRAPH-2F948 → CJK UNIFIED IDEOGRAPH-774A\t# \n\n9FC3 ;\t4039 ;\tMA\t# ( 鿃 → 䀹 ) CJK UNIFIED IDEOGRAPH-9FC3 → CJK UNIFIED IDEOGRAPH-4039\t# →䀹→\nFAD4 ;\t4039 ;\tMA\t# ( 䀹 → 䀹 ) CJK COMPATIBILITY IDEOGRAPH-FAD4 → CJK UNIFIED IDEOGRAPH-4039\t# \n2F949 ;\t4039 ;\tMA\t# ( 䀹 → 䀹 ) CJK COMPATIBILITY IDEOGRAPH-2F949 → CJK UNIFIED IDEOGRAPH-4039\t# \n\n6663 ;\t403F ;\tMA\t# ( 晣 → 䀿 ) CJK UNIFIED IDEOGRAPH-6663 → CJK UNIFIED IDEOGRAPH-403F\t# \n\n2F94B ;\t4046 ;\tMA\t# ( 䁆 → 䁆 ) CJK COMPATIBILITY IDEOGRAPH-2F94B → CJK UNIFIED IDEOGRAPH-4046\t# \n\n2F94A ;\t778B ;\tMA\t# ( 瞋 → 瞋 ) CJK COMPATIBILITY IDEOGRAPH-2F94A → CJK UNIFIED IDEOGRAPH-778B\t# \n\nFAD5 ;\t25249 ;\tMA\t# ( 𥉉 → 𥉉 ) CJK COMPATIBILITY IDEOGRAPH-FAD5 → CJK UNIFIED IDEOGRAPH-25249\t# \n\nFA9D ;\t77A7 ;\tMA\t# ( 瞧 → 瞧 ) CJK COMPATIBILITY IDEOGRAPH-FA9D → CJK UNIFIED IDEOGRAPH-77A7\t# \n\n2F6D ;\t77DB ;\tMA\t#* ( ⽭ → 矛 ) KANGXI RADICAL SPEAR → CJK UNIFIED IDEOGRAPH-77DB\t# \n\n2F6E ;\t77E2 ;\tMA\t#* ( ⽮ → 矢 ) KANGXI RADICAL ARROW → CJK UNIFIED IDEOGRAPH-77E2\t# \n\n2F6F ;\t77F3 ;\tMA\t#* ( ⽯ → 石 ) KANGXI RADICAL STONE → CJK UNIFIED IDEOGRAPH-77F3\t# \n\n2F94C ;\t4096 ;\tMA\t# ( 䂖 → 䂖 ) CJK COMPATIBILITY IDEOGRAPH-2F94C → CJK UNIFIED IDEOGRAPH-4096\t# \n\n2F94D ;\t2541D ;\tMA\t# ( 𥐝 → 𥐝 ) CJK COMPATIBILITY IDEOGRAPH-2F94D → CJK UNIFIED IDEOGRAPH-2541D\t# \n\n784F ;\t7814 ;\tMA\t# ( 硏 → 研 ) CJK UNIFIED IDEOGRAPH-784F → CJK UNIFIED IDEOGRAPH-7814\t# \n\n2F94E ;\t784E ;\tMA\t# ( 硎 → 硎 ) CJK COMPATIBILITY IDEOGRAPH-2F94E → CJK UNIFIED IDEOGRAPH-784E\t# \n\nF9CE ;\t786B ;\tMA\t# ( 硫 → 硫 ) CJK COMPATIBILITY IDEOGRAPH-F9CE → CJK UNIFIED IDEOGRAPH-786B\t# \n\nF93B ;\t788C ;\tMA\t# ( 碌 → 碌 ) CJK COMPATIBILITY IDEOGRAPH-F93B → CJK UNIFIED IDEOGRAPH-788C\t# \n2F94F ;\t788C ;\tMA\t# ( 碌 → 碌 ) CJK COMPATIBILITY IDEOGRAPH-2F94F → CJK UNIFIED IDEOGRAPH-788C\t# \n\nFA4B ;\t7891 ;\tMA\t# ( 碑 → 碑 ) CJK COMPATIBILITY IDEOGRAPH-FA4B → CJK UNIFIED IDEOGRAPH-7891\t# \n\nF947 ;\t78CA ;\tMA\t# ( 磊 → 磊 ) CJK COMPATIBILITY IDEOGRAPH-F947 → CJK UNIFIED IDEOGRAPH-78CA\t# \n\nFAAB ;\t78CC ;\tMA\t# ( 磌 → 磌 ) CJK COMPATIBILITY IDEOGRAPH-FAAB → CJK UNIFIED IDEOGRAPH-78CC\t# \n2F950 ;\t78CC ;\tMA\t# ( 磌 → 磌 ) CJK COMPATIBILITY IDEOGRAPH-2F950 → CJK UNIFIED IDEOGRAPH-78CC\t# \n\nF964 ;\t78FB ;\tMA\t# ( 磻 → 磻 ) CJK COMPATIBILITY IDEOGRAPH-F964 → CJK UNIFIED IDEOGRAPH-78FB\t# \n\n2F951 ;\t40E3 ;\tMA\t# ( 䃣 → 䃣 ) CJK COMPATIBILITY IDEOGRAPH-2F951 → CJK UNIFIED IDEOGRAPH-40E3\t# \n\nF985 ;\t792A ;\tMA\t# ( 礪 → 礪 ) CJK COMPATIBILITY IDEOGRAPH-F985 → CJK UNIFIED IDEOGRAPH-792A\t# \n\n2F70 ;\t793A ;\tMA\t#* ( ⽰ → 示 ) KANGXI RADICAL SPIRIT → CJK UNIFIED IDEOGRAPH-793A\t# \n\n2EAD ;\t793B ;\tMA\t#* ( ⺭ → 礻 ) CJK RADICAL SPIRIT TWO → CJK UNIFIED IDEOGRAPH-793B\t# \n\nFA18 ;\t793C ;\tMA\t# ( 礼 → 礼 ) CJK COMPATIBILITY IDEOGRAPH-FA18 → CJK UNIFIED IDEOGRAPH-793C\t# \n\nFA4C ;\t793E ;\tMA\t# ( 社 → 社 ) CJK COMPATIBILITY IDEOGRAPH-FA4C → CJK UNIFIED IDEOGRAPH-793E\t# \n\nFA4E ;\t7948 ;\tMA\t# ( 祈 → 祈 ) CJK COMPATIBILITY IDEOGRAPH-FA4E → CJK UNIFIED IDEOGRAPH-7948\t# \n\nFA4D ;\t7949 ;\tMA\t# ( 祉 → 祉 ) CJK COMPATIBILITY IDEOGRAPH-FA4D → CJK UNIFIED IDEOGRAPH-7949\t# \n\n2F952 ;\t25626 ;\tMA\t# ( 𥘦 → 𥘦 ) CJK COMPATIBILITY IDEOGRAPH-2F952 → CJK UNIFIED IDEOGRAPH-25626\t# \n\nFA4F ;\t7950 ;\tMA\t# ( 祐 → 祐 ) CJK COMPATIBILITY IDEOGRAPH-FA4F → CJK UNIFIED IDEOGRAPH-7950\t# \n\nFA50 ;\t7956 ;\tMA\t# ( 祖 → 祖 ) CJK COMPATIBILITY IDEOGRAPH-FA50 → CJK UNIFIED IDEOGRAPH-7956\t# \n2F953 ;\t7956 ;\tMA\t# ( 祖 → 祖 ) CJK COMPATIBILITY IDEOGRAPH-2F953 → CJK UNIFIED IDEOGRAPH-7956\t# \n\nFA51 ;\t795D ;\tMA\t# ( 祝 → 祝 ) CJK COMPATIBILITY IDEOGRAPH-FA51 → CJK UNIFIED IDEOGRAPH-795D\t# \n\nFA19 ;\t795E ;\tMA\t# ( 神 → 神 ) CJK COMPATIBILITY IDEOGRAPH-FA19 → CJK UNIFIED IDEOGRAPH-795E\t# \n\nFA1A ;\t7965 ;\tMA\t# ( 祥 → 祥 ) CJK COMPATIBILITY IDEOGRAPH-FA1A → CJK UNIFIED IDEOGRAPH-7965\t# \n\nFA61 ;\t8996 ;\tMA\t# ( 視 → 視 ) CJK COMPATIBILITY IDEOGRAPH-FA61 → CJK UNIFIED IDEOGRAPH-8996\t# \nFAB8 ;\t8996 ;\tMA\t# ( 視 → 視 ) CJK COMPATIBILITY IDEOGRAPH-FAB8 → CJK UNIFIED IDEOGRAPH-8996\t# \n\nF93C ;\t797F ;\tMA\t# ( 祿 → 祿 ) CJK COMPATIBILITY IDEOGRAPH-F93C → CJK UNIFIED IDEOGRAPH-797F\t# \n\n2F954 ;\t2569A ;\tMA\t# ( 𥚚 → 𥚚 ) CJK COMPATIBILITY IDEOGRAPH-2F954 → CJK UNIFIED IDEOGRAPH-2569A\t# \n\nFA52 ;\t798D ;\tMA\t# ( 禍 → 禍 ) CJK COMPATIBILITY IDEOGRAPH-FA52 → CJK UNIFIED IDEOGRAPH-798D\t# \n\nFA53 ;\t798E ;\tMA\t# ( 禎 → 禎 ) CJK COMPATIBILITY IDEOGRAPH-FA53 → CJK UNIFIED IDEOGRAPH-798E\t# \n\nFA1B ;\t798F ;\tMA\t# ( 福 → 福 ) CJK COMPATIBILITY IDEOGRAPH-FA1B → CJK UNIFIED IDEOGRAPH-798F\t# \n2F956 ;\t798F ;\tMA\t# ( 福 → 福 ) CJK COMPATIBILITY IDEOGRAPH-2F956 → CJK UNIFIED IDEOGRAPH-798F\t# \n\n2F955 ;\t256C5 ;\tMA\t# ( 𥛅 → 𥛅 ) CJK COMPATIBILITY IDEOGRAPH-2F955 → CJK UNIFIED IDEOGRAPH-256C5\t# \n\nF9B6 ;\t79AE ;\tMA\t# ( 禮 → 禮 ) CJK COMPATIBILITY IDEOGRAPH-F9B6 → CJK UNIFIED IDEOGRAPH-79AE\t# \n\n2F71 ;\t79B8 ;\tMA\t#* ( ⽱ → 禸 ) KANGXI RADICAL TRACK → CJK UNIFIED IDEOGRAPH-79B8\t# \n\n2F72 ;\t79BE ;\tMA\t#* ( ⽲ → 禾 ) KANGXI RADICAL GRAIN → CJK UNIFIED IDEOGRAPH-79BE\t# \n\nF995 ;\t79CA ;\tMA\t# ( 秊 → 秊 ) CJK COMPATIBILITY IDEOGRAPH-F995 → CJK UNIFIED IDEOGRAPH-79CA\t# \n\n2F958 ;\t412F ;\tMA\t# ( 䄯 → 䄯 ) CJK COMPATIBILITY IDEOGRAPH-2F958 → CJK UNIFIED IDEOGRAPH-412F\t# \n\n2F957 ;\t79EB ;\tMA\t# ( 秫 → 秫 ) CJK COMPATIBILITY IDEOGRAPH-2F957 → CJK UNIFIED IDEOGRAPH-79EB\t# \n\nF956 ;\t7A1C ;\tMA\t# ( 稜 → 稜 ) CJK COMPATIBILITY IDEOGRAPH-F956 → CJK UNIFIED IDEOGRAPH-7A1C\t# \n\n2F95A ;\t7A4A ;\tMA\t# ( 穊 → 穊 ) CJK COMPATIBILITY IDEOGRAPH-2F95A → CJK UNIFIED IDEOGRAPH-7A4A\t# \n\nFA54 ;\t7A40 ;\tMA\t# ( 穀 → 穀 ) CJK COMPATIBILITY IDEOGRAPH-FA54 → CJK UNIFIED IDEOGRAPH-7A40\t# \n2F959 ;\t7A40 ;\tMA\t# ( 穀 → 穀 ) CJK COMPATIBILITY IDEOGRAPH-2F959 → CJK UNIFIED IDEOGRAPH-7A40\t# \n\n2F95B ;\t7A4F ;\tMA\t# ( 穏 → 穏 ) CJK COMPATIBILITY IDEOGRAPH-2F95B → CJK UNIFIED IDEOGRAPH-7A4F\t# \n\n2F73 ;\t7A74 ;\tMA\t#* ( ⽳ → 穴 ) KANGXI RADICAL CAVE → CJK UNIFIED IDEOGRAPH-7A74\t# \n\nFA55 ;\t7A81 ;\tMA\t# ( 突 → 突 ) CJK COMPATIBILITY IDEOGRAPH-FA55 → CJK UNIFIED IDEOGRAPH-7A81\t# \n\n2F95C ;\t2597C ;\tMA\t# ( 𥥼 → 𥥼 ) CJK COMPATIBILITY IDEOGRAPH-2F95C → CJK UNIFIED IDEOGRAPH-2597C\t# \n\nFAAC ;\t7AB1 ;\tMA\t# ( 窱 → 窱 ) CJK COMPATIBILITY IDEOGRAPH-FAAC → CJK UNIFIED IDEOGRAPH-7AB1\t# \n\nF9F7 ;\t7ACB ;\tMA\t# ( 立 → 立 ) CJK COMPATIBILITY IDEOGRAPH-F9F7 → CJK UNIFIED IDEOGRAPH-7ACB\t# \n2F74 ;\t7ACB ;\tMA\t#* ( ⽴ → 立 ) KANGXI RADICAL STAND → CJK UNIFIED IDEOGRAPH-7ACB\t# \n\n2EEF ;\t7ADC ;\tMA\t#* ( ⻯ → 竜 ) CJK RADICAL J-SIMPLIFIED DRAGON → CJK UNIFIED IDEOGRAPH-7ADC\t# \n\n2F95D ;\t25AA7 ;\tMA\t# ( 𥪧 → 𥪧 ) CJK COMPATIBILITY IDEOGRAPH-2F95D → CJK UNIFIED IDEOGRAPH-25AA7\t# \n2F95E ;\t25AA7 ;\tMA\t# ( 𥪧 → 𥪧 ) CJK COMPATIBILITY IDEOGRAPH-2F95E → CJK UNIFIED IDEOGRAPH-25AA7\t# \n\n2F95F ;\t7AEE ;\tMA\t# ( 竮 → 竮 ) CJK COMPATIBILITY IDEOGRAPH-2F95F → CJK UNIFIED IDEOGRAPH-7AEE\t# \n\n2F75 ;\t7AF9 ;\tMA\t#* ( ⽵ → 竹 ) KANGXI RADICAL BAMBOO → CJK UNIFIED IDEOGRAPH-7AF9\t# \n\nF9F8 ;\t7B20 ;\tMA\t# ( 笠 → 笠 ) CJK COMPATIBILITY IDEOGRAPH-F9F8 → CJK UNIFIED IDEOGRAPH-7B20\t# \n\nFA56 ;\t7BC0 ;\tMA\t# ( 節 → 節 ) CJK COMPATIBILITY IDEOGRAPH-FA56 → CJK UNIFIED IDEOGRAPH-7BC0\t# \nFAAD ;\t7BC0 ;\tMA\t# ( 節 → 節 ) CJK COMPATIBILITY IDEOGRAPH-FAAD → CJK UNIFIED IDEOGRAPH-7BC0\t# \n\n2F960 ;\t4202 ;\tMA\t# ( 䈂 → 䈂 ) CJK COMPATIBILITY IDEOGRAPH-2F960 → CJK UNIFIED IDEOGRAPH-4202\t# \n\n2F961 ;\t25BAB ;\tMA\t# ( 𥮫 → 𥮫 ) CJK COMPATIBILITY IDEOGRAPH-2F961 → CJK UNIFIED IDEOGRAPH-25BAB\t# \n\n2F962 ;\t7BC6 ;\tMA\t# ( 篆 → 篆 ) CJK COMPATIBILITY IDEOGRAPH-2F962 → CJK UNIFIED IDEOGRAPH-7BC6\t# \n\n2F964 ;\t4227 ;\tMA\t# ( 䈧 → 䈧 ) CJK COMPATIBILITY IDEOGRAPH-2F964 → CJK UNIFIED IDEOGRAPH-4227\t# \n\n2F963 ;\t7BC9 ;\tMA\t# ( 築 → 築 ) CJK COMPATIBILITY IDEOGRAPH-2F963 → CJK UNIFIED IDEOGRAPH-7BC9\t# \n\n2F965 ;\t25C80 ;\tMA\t# ( 𥲀 → 𥲀 ) CJK COMPATIBILITY IDEOGRAPH-2F965 → CJK UNIFIED IDEOGRAPH-25C80\t# \n\nFAD6 ;\t25CD0 ;\tMA\t# ( 𥳐 → 𥳐 ) CJK COMPATIBILITY IDEOGRAPH-FAD6 → CJK UNIFIED IDEOGRAPH-25CD0\t# \n\nF9A6 ;\t7C3E ;\tMA\t# ( 簾 → 簾 ) CJK COMPATIBILITY IDEOGRAPH-F9A6 → CJK UNIFIED IDEOGRAPH-7C3E\t# \n\nF944 ;\t7C60 ;\tMA\t# ( 籠 → 籠 ) CJK COMPATIBILITY IDEOGRAPH-F944 → CJK UNIFIED IDEOGRAPH-7C60\t# \n\n2F76 ;\t7C73 ;\tMA\t#* ( ⽶ → 米 ) KANGXI RADICAL RICE → CJK UNIFIED IDEOGRAPH-7C73\t# \n\nFAAE ;\t7C7B ;\tMA\t# ( 类 → 类 ) CJK COMPATIBILITY IDEOGRAPH-FAAE → CJK UNIFIED IDEOGRAPH-7C7B\t# \n\nF9F9 ;\t7C92 ;\tMA\t# ( 粒 → 粒 ) CJK COMPATIBILITY IDEOGRAPH-F9F9 → CJK UNIFIED IDEOGRAPH-7C92\t# \n\nFA1D ;\t7CBE ;\tMA\t# ( 精 → 精 ) CJK COMPATIBILITY IDEOGRAPH-FA1D → CJK UNIFIED IDEOGRAPH-7CBE\t# \n\n2F966 ;\t7CD2 ;\tMA\t# ( 糒 → 糒 ) CJK COMPATIBILITY IDEOGRAPH-2F966 → CJK UNIFIED IDEOGRAPH-7CD2\t# \n\nFA03 ;\t7CD6 ;\tMA\t# ( 糖 → 糖 ) CJK COMPATIBILITY IDEOGRAPH-FA03 → CJK UNIFIED IDEOGRAPH-7CD6\t# \n\n2F968 ;\t7CE8 ;\tMA\t# ( 糨 → 糨 ) CJK COMPATIBILITY IDEOGRAPH-2F968 → CJK UNIFIED IDEOGRAPH-7CE8\t# \n\n2F967 ;\t42A0 ;\tMA\t# ( 䊠 → 䊠 ) CJK COMPATIBILITY IDEOGRAPH-2F967 → CJK UNIFIED IDEOGRAPH-42A0\t# \n\n2F969 ;\t7CE3 ;\tMA\t# ( 糣 → 糣 ) CJK COMPATIBILITY IDEOGRAPH-2F969 → CJK UNIFIED IDEOGRAPH-7CE3\t# \n\nF97B ;\t7CE7 ;\tMA\t# ( 糧 → 糧 ) CJK COMPATIBILITY IDEOGRAPH-F97B → CJK UNIFIED IDEOGRAPH-7CE7\t# \n\n2F77 ;\t7CF8 ;\tMA\t#* ( ⽷ → 糸 ) KANGXI RADICAL SILK → CJK UNIFIED IDEOGRAPH-7CF8\t# \n\n2EAF ;\t7CF9 ;\tMA\t#* ( ⺯ → 糹 ) CJK RADICAL SILK → CJK UNIFIED IDEOGRAPH-7CF9\t# \n\n2F96B ;\t25F86 ;\tMA\t# ( 𥾆 → 𥾆 ) CJK COMPATIBILITY IDEOGRAPH-2F96B → CJK UNIFIED IDEOGRAPH-25F86\t# \n\n2F96A ;\t7D00 ;\tMA\t# ( 紀 → 紀 ) CJK COMPATIBILITY IDEOGRAPH-2F96A → CJK UNIFIED IDEOGRAPH-7D00\t# \n\nF9CF ;\t7D10 ;\tMA\t# ( 紐 → 紐 ) CJK COMPATIBILITY IDEOGRAPH-F9CF → CJK UNIFIED IDEOGRAPH-7D10\t# \n\nF96A ;\t7D22 ;\tMA\t# ( 索 → 索 ) CJK COMPATIBILITY IDEOGRAPH-F96A → CJK UNIFIED IDEOGRAPH-7D22\t# \n\nF94F ;\t7D2F ;\tMA\t# ( 累 → 累 ) CJK COMPATIBILITY IDEOGRAPH-F94F → CJK UNIFIED IDEOGRAPH-7D2F\t# \n\n7D76 ;\t7D55 ;\tMA\t# ( 絶 → 絕 ) CJK UNIFIED IDEOGRAPH-7D76 → CJK UNIFIED IDEOGRAPH-7D55\t# \n\n2F96C ;\t7D63 ;\tMA\t# ( 絣 → 絣 ) CJK COMPATIBILITY IDEOGRAPH-2F96C → CJK UNIFIED IDEOGRAPH-7D63\t# \n\nFAAF ;\t7D5B ;\tMA\t# ( 絛 → 絛 ) CJK COMPATIBILITY IDEOGRAPH-FAAF → CJK UNIFIED IDEOGRAPH-7D5B\t# \n\nF93D ;\t7DA0 ;\tMA\t# ( 綠 → 綠 ) CJK COMPATIBILITY IDEOGRAPH-F93D → CJK UNIFIED IDEOGRAPH-7DA0\t# \n\nF957 ;\t7DBE ;\tMA\t# ( 綾 → 綾 ) CJK COMPATIBILITY IDEOGRAPH-F957 → CJK UNIFIED IDEOGRAPH-7DBE\t# \n\n2F96E ;\t7DC7 ;\tMA\t# ( 緇 → 緇 ) CJK COMPATIBILITY IDEOGRAPH-2F96E → CJK UNIFIED IDEOGRAPH-7DC7\t# \n31E7C ;\t7DC7 ;\tMA\t# ( 𱹼 → 緇 ) CJK UNIFIED IDEOGRAPH-31E7C → CJK UNIFIED IDEOGRAPH-7DC7\t# →緇→\n\nF996 ;\t7DF4 ;\tMA\t# ( 練 → 練 ) CJK COMPATIBILITY IDEOGRAPH-F996 → CJK UNIFIED IDEOGRAPH-7DF4\t# \nFA57 ;\t7DF4 ;\tMA\t# ( 練 → 練 ) CJK COMPATIBILITY IDEOGRAPH-FA57 → CJK UNIFIED IDEOGRAPH-7DF4\t# \nFAB0 ;\t7DF4 ;\tMA\t# ( 練 → 練 ) CJK COMPATIBILITY IDEOGRAPH-FAB0 → CJK UNIFIED IDEOGRAPH-7DF4\t# \n\n2F96F ;\t7E02 ;\tMA\t# ( 縂 → 縂 ) CJK COMPATIBILITY IDEOGRAPH-2F96F → CJK UNIFIED IDEOGRAPH-7E02\t# \n\n2F96D ;\t4301 ;\tMA\t# ( 䌁 → 䌁 ) CJK COMPATIBILITY IDEOGRAPH-2F96D → CJK UNIFIED IDEOGRAPH-4301\t# \n\nFA58 ;\t7E09 ;\tMA\t# ( 縉 → 縉 ) CJK COMPATIBILITY IDEOGRAPH-FA58 → CJK UNIFIED IDEOGRAPH-7E09\t# \n\nF950 ;\t7E37 ;\tMA\t# ( 縷 → 縷 ) CJK COMPATIBILITY IDEOGRAPH-F950 → CJK UNIFIED IDEOGRAPH-7E37\t# \n\nFA59 ;\t7E41 ;\tMA\t# ( 繁 → 繁 ) CJK COMPATIBILITY IDEOGRAPH-FA59 → CJK UNIFIED IDEOGRAPH-7E41\t# \n\n2F970 ;\t7E45 ;\tMA\t# ( 繅 → 繅 ) CJK COMPATIBILITY IDEOGRAPH-2F970 → CJK UNIFIED IDEOGRAPH-7E45\t# \n\n2F898 ;\t261DA ;\tMA\t# ( 𦇚 → 𦇚 ) CJK COMPATIBILITY IDEOGRAPH-2F898 → CJK UNIFIED IDEOGRAPH-261DA\t# \n\n2F971 ;\t4334 ;\tMA\t# ( 䌴 → 䌴 ) CJK COMPATIBILITY IDEOGRAPH-2F971 → CJK UNIFIED IDEOGRAPH-4334\t# \n\n2F78 ;\t7F36 ;\tMA\t#* ( ⽸ → 缶 ) KANGXI RADICAL JAR → CJK UNIFIED IDEOGRAPH-7F36\t# \n\n2F972 ;\t26228 ;\tMA\t# ( 𦈨 → 𦈨 ) CJK COMPATIBILITY IDEOGRAPH-2F972 → CJK UNIFIED IDEOGRAPH-26228\t# \n\nFAB1 ;\t7F3E ;\tMA\t# ( 缾 → 缾 ) CJK COMPATIBILITY IDEOGRAPH-FAB1 → CJK UNIFIED IDEOGRAPH-7F3E\t# \n\n2F973 ;\t26247 ;\tMA\t# ( 𦉇 → 𦉇 ) CJK COMPATIBILITY IDEOGRAPH-2F973 → CJK UNIFIED IDEOGRAPH-26247\t# \n\n2F79 ;\t7F51 ;\tMA\t#* ( ⽹ → 网 ) KANGXI RADICAL NET → CJK UNIFIED IDEOGRAPH-7F51\t# \n\n2EAB ;\t7F52 ;\tMA\t#* ( ⺫ → 罒 ) CJK RADICAL EYE → CJK UNIFIED IDEOGRAPH-7F52\t# \n2EB2 ;\t7F52 ;\tMA\t#* ( ⺲ → 罒 ) CJK RADICAL NET TWO → CJK UNIFIED IDEOGRAPH-7F52\t# \n\n2EB1 ;\t7F53 ;\tMA\t#* ( ⺱ → 罓 ) CJK RADICAL NET ONE → CJK UNIFIED IDEOGRAPH-7F53\t# \n\n2F974 ;\t4359 ;\tMA\t# ( 䍙 → 䍙 ) CJK COMPATIBILITY IDEOGRAPH-2F974 → CJK UNIFIED IDEOGRAPH-4359\t# \n\nFA5A ;\t7F72 ;\tMA\t# ( 署 → 署 ) CJK COMPATIBILITY IDEOGRAPH-FA5A → CJK UNIFIED IDEOGRAPH-7F72\t# \n\n2F975 ;\t262D9 ;\tMA\t# ( 𦋙 → 𦋙 ) CJK COMPATIBILITY IDEOGRAPH-2F975 → CJK UNIFIED IDEOGRAPH-262D9\t# \n\nF9E6 ;\t7F79 ;\tMA\t# ( 罹 → 罹 ) CJK COMPATIBILITY IDEOGRAPH-F9E6 → CJK UNIFIED IDEOGRAPH-7F79\t# \n\n2F976 ;\t7F7A ;\tMA\t# ( 罺 → 罺 ) CJK COMPATIBILITY IDEOGRAPH-2F976 → CJK UNIFIED IDEOGRAPH-7F7A\t# \n\nF90F ;\t7F85 ;\tMA\t# ( 羅 → 羅 ) CJK COMPATIBILITY IDEOGRAPH-F90F → CJK UNIFIED IDEOGRAPH-7F85\t# \n\n2F977 ;\t2633E ;\tMA\t# ( 𦌾 → 𦌾 ) CJK COMPATIBILITY IDEOGRAPH-2F977 → CJK UNIFIED IDEOGRAPH-2633E\t# \n\n2F7A ;\t7F8A ;\tMA\t#* ( ⽺ → 羊 ) KANGXI RADICAL SHEEP → CJK UNIFIED IDEOGRAPH-7F8A\t# \n\n2F978 ;\t7F95 ;\tMA\t# ( 羕 → 羕 ) CJK COMPATIBILITY IDEOGRAPH-2F978 → CJK UNIFIED IDEOGRAPH-7F95\t# \n\nF9AF ;\t7F9A ;\tMA\t# ( 羚 → 羚 ) CJK COMPATIBILITY IDEOGRAPH-F9AF → CJK UNIFIED IDEOGRAPH-7F9A\t# \n\nFA1E ;\t7FBD ;\tMA\t# ( 羽 → 羽 ) CJK COMPATIBILITY IDEOGRAPH-FA1E → CJK UNIFIED IDEOGRAPH-7FBD\t# \n2F7B ;\t7FBD ;\tMA\t#* ( ⽻ → 羽 ) KANGXI RADICAL FEATHER → CJK UNIFIED IDEOGRAPH-7FBD\t# \n\n2F979 ;\t7FFA ;\tMA\t# ( 翺 → 翺 ) CJK COMPATIBILITY IDEOGRAPH-2F979 → CJK UNIFIED IDEOGRAPH-7FFA\t# \n\nF934 ;\t8001 ;\tMA\t# ( 老 → 老 ) CJK COMPATIBILITY IDEOGRAPH-F934 → CJK UNIFIED IDEOGRAPH-8001\t# \n2F7C ;\t8001 ;\tMA\t#* ( ⽼ → 老 ) KANGXI RADICAL OLD → CJK UNIFIED IDEOGRAPH-8001\t# \n\n2EB9 ;\t8002 ;\tMA\t#* ( ⺹ → 耂 ) CJK RADICAL OLD → CJK UNIFIED IDEOGRAPH-8002\t# \n\nFA5B ;\t8005 ;\tMA\t# ( 者 → 者 ) CJK COMPATIBILITY IDEOGRAPH-FA5B → CJK UNIFIED IDEOGRAPH-8005\t# \nFAB2 ;\t8005 ;\tMA\t# ( 者 → 者 ) CJK COMPATIBILITY IDEOGRAPH-FAB2 → CJK UNIFIED IDEOGRAPH-8005\t# \n2F97A ;\t8005 ;\tMA\t# ( 者 → 者 ) CJK COMPATIBILITY IDEOGRAPH-2F97A → CJK UNIFIED IDEOGRAPH-8005\t# \n\n2F7D ;\t800C ;\tMA\t#* ( ⽽ → 而 ) KANGXI RADICAL AND → CJK UNIFIED IDEOGRAPH-800C\t# \n\n2F97B ;\t264DA ;\tMA\t# ( 𦓚 → 𦓚 ) CJK COMPATIBILITY IDEOGRAPH-2F97B → CJK UNIFIED IDEOGRAPH-264DA\t# \n\n2F7E ;\t8012 ;\tMA\t#* ( ⽾ → 耒 ) KANGXI RADICAL PLOW → CJK UNIFIED IDEOGRAPH-8012\t# \n\n2F97C ;\t26523 ;\tMA\t# ( 𦔣 → 𦔣 ) CJK COMPATIBILITY IDEOGRAPH-2F97C → CJK UNIFIED IDEOGRAPH-26523\t# \n\n2F7F ;\t8033 ;\tMA\t#* ( ⽿ → 耳 ) KANGXI RADICAL EAR → CJK UNIFIED IDEOGRAPH-8033\t# \n\nF9B0 ;\t8046 ;\tMA\t# ( 聆 → 聆 ) CJK COMPATIBILITY IDEOGRAPH-F9B0 → CJK UNIFIED IDEOGRAPH-8046\t# \n\n2F97D ;\t8060 ;\tMA\t# ( 聠 → 聠 ) CJK COMPATIBILITY IDEOGRAPH-2F97D → CJK UNIFIED IDEOGRAPH-8060\t# \n\n2659D ;\t265A8 ;\tMA\t# ( 𦖝 → 𦖨 ) CJK UNIFIED IDEOGRAPH-2659D → CJK UNIFIED IDEOGRAPH-265A8\t# →𦖨→\n2F97E ;\t265A8 ;\tMA\t# ( 𦖨 → 𦖨 ) CJK COMPATIBILITY IDEOGRAPH-2F97E → CJK UNIFIED IDEOGRAPH-265A8\t# \n\nF997 ;\t806F ;\tMA\t# ( 聯 → 聯 ) CJK COMPATIBILITY IDEOGRAPH-F997 → CJK UNIFIED IDEOGRAPH-806F\t# \n\n2F97F ;\t8070 ;\tMA\t# ( 聰 → 聰 ) CJK COMPATIBILITY IDEOGRAPH-2F97F → CJK UNIFIED IDEOGRAPH-8070\t# \n\nF945 ;\t807E ;\tMA\t# ( 聾 → 聾 ) CJK COMPATIBILITY IDEOGRAPH-F945 → CJK UNIFIED IDEOGRAPH-807E\t# \n\n2F80 ;\t807F ;\tMA\t#* ( ⾀ → 聿 ) KANGXI RADICAL BRUSH → CJK UNIFIED IDEOGRAPH-807F\t# \n\n2EBA ;\t8080 ;\tMA\t#* ( ⺺ → 肀 ) CJK RADICAL BRUSH ONE → CJK UNIFIED IDEOGRAPH-8080\t# \n\n2F81 ;\t8089 ;\tMA\t#* ( ⾁ → 肉 ) KANGXI RADICAL MEAT → CJK UNIFIED IDEOGRAPH-8089\t# \n\nF953 ;\t808B ;\tMA\t# ( 肋 → 肋 ) CJK COMPATIBILITY IDEOGRAPH-F953 → CJK UNIFIED IDEOGRAPH-808B\t# \n\n2F8D6 ;\t80AD ;\tMA\t# ( 肭 → 肭 ) CJK COMPATIBILITY IDEOGRAPH-2F8D6 → CJK UNIFIED IDEOGRAPH-80AD\t# \n\n2F982 ;\t80B2 ;\tMA\t# ( 育 → 育 ) CJK COMPATIBILITY IDEOGRAPH-2F982 → CJK UNIFIED IDEOGRAPH-80B2\t# \n\n2F981 ;\t43D5 ;\tMA\t# ( 䏕 → 䏕 ) CJK COMPATIBILITY IDEOGRAPH-2F981 → CJK UNIFIED IDEOGRAPH-43D5\t# \n\n2F8D7 ;\t43D9 ;\tMA\t# ( 䏙 → 䏙 ) CJK COMPATIBILITY IDEOGRAPH-2F8D7 → CJK UNIFIED IDEOGRAPH-43D9\t# \n\n8141 ;\t80FC ;\tMA\t# ( 腁 → 胼 ) CJK UNIFIED IDEOGRAPH-8141 → CJK UNIFIED IDEOGRAPH-80FC\t# \n\n2F983 ;\t8103 ;\tMA\t# ( 脃 → 脃 ) CJK COMPATIBILITY IDEOGRAPH-2F983 → CJK UNIFIED IDEOGRAPH-8103\t# \n\n2F985 ;\t813E ;\tMA\t# ( 脾 → 脾 ) CJK COMPATIBILITY IDEOGRAPH-2F985 → CJK UNIFIED IDEOGRAPH-813E\t# \n\n2F984 ;\t440B ;\tMA\t# ( 䐋 → 䐋 ) CJK COMPATIBILITY IDEOGRAPH-2F984 → CJK UNIFIED IDEOGRAPH-440B\t# \n\n2F8DA ;\t6721 ;\tMA\t# ( 朡 → 朡 ) CJK COMPATIBILITY IDEOGRAPH-2F8DA → CJK UNIFIED IDEOGRAPH-6721\t# \n\n2F987 ;\t267A7 ;\tMA\t# ( 𦞧 → 𦞧 ) CJK COMPATIBILITY IDEOGRAPH-2F987 → CJK UNIFIED IDEOGRAPH-267A7\t# \n\n2F988 ;\t267B5 ;\tMA\t# ( 𦞵 → 𦞵 ) CJK COMPATIBILITY IDEOGRAPH-2F988 → CJK UNIFIED IDEOGRAPH-267B5\t# \n\n6726 ;\t4443 ;\tMA\t# ( 朦 → 䑃 ) CJK UNIFIED IDEOGRAPH-6726 → CJK UNIFIED IDEOGRAPH-4443\t# \n\nF926 ;\t81D8 ;\tMA\t# ( 臘 → 臘 ) CJK COMPATIBILITY IDEOGRAPH-F926 → CJK UNIFIED IDEOGRAPH-81D8\t# \n\n2F82 ;\t81E3 ;\tMA\t#* ( ⾂ → 臣 ) KANGXI RADICAL MINISTER → CJK UNIFIED IDEOGRAPH-81E3\t# \n\nF9F6 ;\t81E8 ;\tMA\t# ( 臨 → 臨 ) CJK COMPATIBILITY IDEOGRAPH-F9F6 → CJK UNIFIED IDEOGRAPH-81E8\t# \n\n2F83 ;\t81EA ;\tMA\t#* ( ⾃ → 自 ) KANGXI RADICAL SELF → CJK UNIFIED IDEOGRAPH-81EA\t# \n\nFA5C ;\t81ED ;\tMA\t# ( 臭 → 臭 ) CJK COMPATIBILITY IDEOGRAPH-FA5C → CJK UNIFIED IDEOGRAPH-81ED\t# \n\n2F84 ;\t81F3 ;\tMA\t#* ( ⾄ → 至 ) KANGXI RADICAL ARRIVE → CJK UNIFIED IDEOGRAPH-81F3\t# \n\n2F85 ;\t81FC ;\tMA\t#* ( ⾅ → 臼 ) KANGXI RADICAL MORTAR → CJK UNIFIED IDEOGRAPH-81FC\t# \n\n2F893 ;\t8201 ;\tMA\t# ( 舁 → 舁 ) CJK COMPATIBILITY IDEOGRAPH-2F893 → CJK UNIFIED IDEOGRAPH-8201\t# \n2F98B ;\t8201 ;\tMA\t# ( 舁 → 舁 ) CJK COMPATIBILITY IDEOGRAPH-2F98B → CJK UNIFIED IDEOGRAPH-8201\t# \n\n2F98C ;\t8204 ;\tMA\t# ( 舄 → 舄 ) CJK COMPATIBILITY IDEOGRAPH-2F98C → CJK UNIFIED IDEOGRAPH-8204\t# \n\n2F86 ;\t820C ;\tMA\t#* ( ⾆ → 舌 ) KANGXI RADICAL TONGUE → CJK UNIFIED IDEOGRAPH-820C\t# \n\nFA6D ;\t8218 ;\tMA\t# ( 舘 → 舘 ) CJK COMPATIBILITY IDEOGRAPH-FA6D → CJK UNIFIED IDEOGRAPH-8218\t# \n\n2F87 ;\t821B ;\tMA\t#* ( ⾇ → 舛 ) KANGXI RADICAL OPPOSE → CJK UNIFIED IDEOGRAPH-821B\t# \n\n2F88 ;\t821F ;\tMA\t#* ( ⾈ → 舟 ) KANGXI RADICAL BOAT → CJK UNIFIED IDEOGRAPH-821F\t# \n\n2F98E ;\t446B ;\tMA\t# ( 䑫 → 䑫 ) CJK COMPATIBILITY IDEOGRAPH-2F98E → CJK UNIFIED IDEOGRAPH-446B\t# \n\n2F89 ;\t826E ;\tMA\t#* ( ⾉ → 艮 ) KANGXI RADICAL STOPPING → CJK UNIFIED IDEOGRAPH-826E\t# \n\nF97C ;\t826F ;\tMA\t# ( 良 → 良 ) CJK COMPATIBILITY IDEOGRAPH-F97C → CJK UNIFIED IDEOGRAPH-826F\t# \n\n2F8A ;\t8272 ;\tMA\t#* ( ⾊ → 色 ) KANGXI RADICAL COLOR → CJK UNIFIED IDEOGRAPH-8272\t# \n\n2F8B ;\t8278 ;\tMA\t#* ( ⾋ → 艸 ) KANGXI RADICAL GRASS → CJK UNIFIED IDEOGRAPH-8278\t# \n\nFA5D ;\t8279 ;\tMA\t# ( 艹 → 艹 ) CJK COMPATIBILITY IDEOGRAPH-FA5D → CJK UNIFIED IDEOGRAPH-8279\t# \nFA5E ;\t8279 ;\tMA\t# ( 艹 → 艹 ) CJK COMPATIBILITY IDEOGRAPH-FA5E → CJK UNIFIED IDEOGRAPH-8279\t# \n2EBE ;\t8279 ;\tMA\t#* ( ⺾ → 艹 ) CJK RADICAL GRASS ONE → CJK UNIFIED IDEOGRAPH-8279\t# \n2EBF ;\t8279 ;\tMA\t#* ( ⺿ → 艹 ) CJK RADICAL GRASS TWO → CJK UNIFIED IDEOGRAPH-8279\t# →艹→\n2EC0 ;\t8279 ;\tMA\t#* ( ⻀ → 艹 ) CJK RADICAL GRASS THREE → CJK UNIFIED IDEOGRAPH-8279\t# →艹→\n\n2F990 ;\t828B ;\tMA\t# ( 芋 → 芋 ) CJK COMPATIBILITY IDEOGRAPH-2F990 → CJK UNIFIED IDEOGRAPH-828B\t# \n\n2F98F ;\t8291 ;\tMA\t# ( 芑 → 芑 ) CJK COMPATIBILITY IDEOGRAPH-2F98F → CJK UNIFIED IDEOGRAPH-8291\t# \n\n2F991 ;\t829D ;\tMA\t# ( 芝 → 芝 ) CJK COMPATIBILITY IDEOGRAPH-2F991 → CJK UNIFIED IDEOGRAPH-829D\t# \n\n2F993 ;\t82B1 ;\tMA\t# ( 花 → 花 ) CJK COMPATIBILITY IDEOGRAPH-2F993 → CJK UNIFIED IDEOGRAPH-82B1\t# \n\n2F994 ;\t82B3 ;\tMA\t# ( 芳 → 芳 ) CJK COMPATIBILITY IDEOGRAPH-2F994 → CJK UNIFIED IDEOGRAPH-82B3\t# \n\n2F995 ;\t82BD ;\tMA\t# ( 芽 → 芽 ) CJK COMPATIBILITY IDEOGRAPH-2F995 → CJK UNIFIED IDEOGRAPH-82BD\t# \n\nF974 ;\t82E5 ;\tMA\t# ( 若 → 若 ) CJK COMPATIBILITY IDEOGRAPH-F974 → CJK UNIFIED IDEOGRAPH-82E5\t# \n2F998 ;\t82E5 ;\tMA\t# ( 若 → 若 ) CJK COMPATIBILITY IDEOGRAPH-2F998 → CJK UNIFIED IDEOGRAPH-82E5\t# \n\n2F996 ;\t82E6 ;\tMA\t# ( 苦 → 苦 ) CJK COMPATIBILITY IDEOGRAPH-2F996 → CJK UNIFIED IDEOGRAPH-82E6\t# \n\n2F997 ;\t26B3C ;\tMA\t# ( 𦬼 → 𦬼 ) CJK COMPATIBILITY IDEOGRAPH-2F997 → CJK UNIFIED IDEOGRAPH-26B3C\t# \n\nF9FE ;\t8336 ;\tMA\t# ( 茶 → 茶 ) CJK COMPATIBILITY IDEOGRAPH-F9FE → CJK UNIFIED IDEOGRAPH-8336\t# \n\nFAB3 ;\t8352 ;\tMA\t# ( 荒 → 荒 ) CJK COMPATIBILITY IDEOGRAPH-FAB3 → CJK UNIFIED IDEOGRAPH-8352\t# \n\n2F99A ;\t8363 ;\tMA\t# ( 荣 → 荣 ) CJK COMPATIBILITY IDEOGRAPH-2F99A → CJK UNIFIED IDEOGRAPH-8363\t# \n\n2F999 ;\t831D ;\tMA\t# ( 茝 → 茝 ) CJK COMPATIBILITY IDEOGRAPH-2F999 → CJK UNIFIED IDEOGRAPH-831D\t# \n\n2F99C ;\t8323 ;\tMA\t# ( 茣 → 茣 ) CJK COMPATIBILITY IDEOGRAPH-2F99C → CJK UNIFIED IDEOGRAPH-8323\t# \n\n2F99D ;\t83BD ;\tMA\t# ( 莽 → 莽 ) CJK COMPATIBILITY IDEOGRAPH-2F99D → CJK UNIFIED IDEOGRAPH-83BD\t# \n\n2F9A0 ;\t8353 ;\tMA\t# ( 荓 → 荓 ) CJK COMPATIBILITY IDEOGRAPH-2F9A0 → CJK UNIFIED IDEOGRAPH-8353\t# \n\nF93E ;\t83C9 ;\tMA\t# ( 菉 → 菉 ) CJK COMPATIBILITY IDEOGRAPH-F93E → CJK UNIFIED IDEOGRAPH-83C9\t# \n\n2F9A1 ;\t83CA ;\tMA\t# ( 菊 → 菊 ) CJK COMPATIBILITY IDEOGRAPH-2F9A1 → CJK UNIFIED IDEOGRAPH-83CA\t# \n\n2F9A2 ;\t83CC ;\tMA\t# ( 菌 → 菌 ) CJK COMPATIBILITY IDEOGRAPH-2F9A2 → CJK UNIFIED IDEOGRAPH-83CC\t# \n\n2F9A3 ;\t83DC ;\tMA\t# ( 菜 → 菜 ) CJK COMPATIBILITY IDEOGRAPH-2F9A3 → CJK UNIFIED IDEOGRAPH-83DC\t# \n\n2F99E ;\t83E7 ;\tMA\t# ( 菧 → 菧 ) CJK COMPATIBILITY IDEOGRAPH-2F99E → CJK UNIFIED IDEOGRAPH-83E7\t# \n\nFAB4 ;\t83EF ;\tMA\t# ( 華 → 華 ) CJK COMPATIBILITY IDEOGRAPH-FAB4 → CJK UNIFIED IDEOGRAPH-83EF\t# \n\nF958 ;\t83F1 ;\tMA\t# ( 菱 → 菱 ) CJK COMPATIBILITY IDEOGRAPH-F958 → CJK UNIFIED IDEOGRAPH-83F1\t# \n\nFA5F ;\t8457 ;\tMA\t# ( 著 → 著 ) CJK COMPATIBILITY IDEOGRAPH-FA5F → CJK UNIFIED IDEOGRAPH-8457\t# \n2F99F ;\t8457 ;\tMA\t# ( 著 → 著 ) CJK COMPATIBILITY IDEOGRAPH-2F99F → CJK UNIFIED IDEOGRAPH-8457\t# \n\n2F9A4 ;\t26C36 ;\tMA\t# ( 𦰶 → 𦰶 ) CJK COMPATIBILITY IDEOGRAPH-2F9A4 → CJK UNIFIED IDEOGRAPH-26C36\t# \n26D06 ;\t26C36 ;\tMA\t# ( 𦴆 → 𦰶 ) CJK UNIFIED IDEOGRAPH-26D06 → CJK UNIFIED IDEOGRAPH-26C36\t# →𦰶→\n\n2F99B ;\t83AD ;\tMA\t# ( 莭 → 莭 ) CJK COMPATIBILITY IDEOGRAPH-2F99B → CJK UNIFIED IDEOGRAPH-83AD\t# \n\nF918 ;\t843D ;\tMA\t# ( 落 → 落 ) CJK COMPATIBILITY IDEOGRAPH-F918 → CJK UNIFIED IDEOGRAPH-843D\t# \n\nF96E ;\t8449 ;\tMA\t# ( 葉 → 葉 ) CJK COMPATIBILITY IDEOGRAPH-F96E → CJK UNIFIED IDEOGRAPH-8449\t# \n\n853F ;\t848D ;\tMA\t# ( 蔿 → 蒍 ) CJK UNIFIED IDEOGRAPH-853F → CJK UNIFIED IDEOGRAPH-848D\t# \n\n2F9A6 ;\t26CD5 ;\tMA\t# ( 𦳕 → 𦳕 ) CJK COMPATIBILITY IDEOGRAPH-2F9A6 → CJK UNIFIED IDEOGRAPH-26CD5\t# \n\n2F9A5 ;\t26D6B ;\tMA\t# ( 𦵫 → 𦵫 ) CJK COMPATIBILITY IDEOGRAPH-2F9A5 → CJK UNIFIED IDEOGRAPH-26D6B\t# \n\nF999 ;\t84EE ;\tMA\t# ( 蓮 → 蓮 ) CJK COMPATIBILITY IDEOGRAPH-F999 → CJK UNIFIED IDEOGRAPH-84EE\t# \n\n2F9A8 ;\t84F1 ;\tMA\t# ( 蓱 → 蓱 ) CJK COMPATIBILITY IDEOGRAPH-2F9A8 → CJK UNIFIED IDEOGRAPH-84F1\t# \n\n2F9A9 ;\t84F3 ;\tMA\t# ( 蓳 → 蓳 ) CJK COMPATIBILITY IDEOGRAPH-2F9A9 → CJK UNIFIED IDEOGRAPH-84F3\t# \n\nF9C2 ;\t84FC ;\tMA\t# ( 蓼 → 蓼 ) CJK COMPATIBILITY IDEOGRAPH-F9C2 → CJK UNIFIED IDEOGRAPH-84FC\t# \n\n2F9AA ;\t8516 ;\tMA\t# ( 蔖 → 蔖 ) CJK COMPATIBILITY IDEOGRAPH-2F9AA → CJK UNIFIED IDEOGRAPH-8516\t# \n\n2F9A7 ;\t452B ;\tMA\t# ( 䔫 → 䔫 ) CJK COMPATIBILITY IDEOGRAPH-2F9A7 → CJK UNIFIED IDEOGRAPH-452B\t# \n\n2F9AC ;\t8564 ;\tMA\t# ( 蕤 → 蕤 ) CJK COMPATIBILITY IDEOGRAPH-2F9AC → CJK UNIFIED IDEOGRAPH-8564\t# \n\n2F9AD ;\t26F2C ;\tMA\t# ( 𦼬 → 𦼬 ) CJK COMPATIBILITY IDEOGRAPH-2F9AD → CJK UNIFIED IDEOGRAPH-26F2C\t# \n\nF923 ;\t85CD ;\tMA\t# ( 藍 → 藍 ) CJK COMPATIBILITY IDEOGRAPH-F923 → CJK UNIFIED IDEOGRAPH-85CD\t# \n\n2F9AE ;\t455D ;\tMA\t# ( 䕝 → 䕝 ) CJK COMPATIBILITY IDEOGRAPH-2F9AE → CJK UNIFIED IDEOGRAPH-455D\t# \n\n2F9B0 ;\t26FB1 ;\tMA\t# ( 𦾱 → 𦾱 ) CJK COMPATIBILITY IDEOGRAPH-2F9B0 → CJK UNIFIED IDEOGRAPH-26FB1\t# \n\n2F9AF ;\t4561 ;\tMA\t# ( 䕡 → 䕡 ) CJK COMPATIBILITY IDEOGRAPH-2F9AF → CJK UNIFIED IDEOGRAPH-4561\t# \n\nF9F0 ;\t85FA ;\tMA\t# ( 藺 → 藺 ) CJK COMPATIBILITY IDEOGRAPH-F9F0 → CJK UNIFIED IDEOGRAPH-85FA\t# \n\nF935 ;\t8606 ;\tMA\t# ( 蘆 → 蘆 ) CJK COMPATIBILITY IDEOGRAPH-F935 → CJK UNIFIED IDEOGRAPH-8606\t# \n\n2F9B2 ;\t456B ;\tMA\t# ( 䕫 → 䕫 ) CJK COMPATIBILITY IDEOGRAPH-2F9B2 → CJK UNIFIED IDEOGRAPH-456B\t# \n\nFA20 ;\t8612 ;\tMA\t# ( 蘒 → 蘒 ) CJK COMPATIBILITY IDEOGRAPH-FA20 → CJK UNIFIED IDEOGRAPH-8612\t# \n\nF91F ;\t862D ;\tMA\t# ( 蘭 → 蘭 ) CJK COMPATIBILITY IDEOGRAPH-F91F → CJK UNIFIED IDEOGRAPH-862D\t# \n\n2F9B1 ;\t270D2 ;\tMA\t# ( 𧃒 → 𧃒 ) CJK COMPATIBILITY IDEOGRAPH-2F9B1 → CJK UNIFIED IDEOGRAPH-270D2\t# \n\n8641 ;\t8637 ;\tMA\t# ( 虁 → 蘷 ) CJK UNIFIED IDEOGRAPH-8641 → CJK UNIFIED IDEOGRAPH-8637\t# \n\nF910 ;\t863F ;\tMA\t# ( 蘿 → 蘿 ) CJK COMPATIBILITY IDEOGRAPH-F910 → CJK UNIFIED IDEOGRAPH-863F\t# \n\n2F8C ;\t864D ;\tMA\t#* ( ⾌ → 虍 ) KANGXI RADICAL TIGER → CJK UNIFIED IDEOGRAPH-864D\t# \n\n2EC1 ;\t864E ;\tMA\t#* ( ⻁ → 虎 ) CJK RADICAL TIGER → CJK UNIFIED IDEOGRAPH-864E\t# \n\n2F9B3 ;\t8650 ;\tMA\t# ( 虐 → 虐 ) CJK COMPATIBILITY IDEOGRAPH-2F9B3 → CJK UNIFIED IDEOGRAPH-8650\t# \n\nF936 ;\t865C ;\tMA\t# ( 虜 → 虜 ) CJK COMPATIBILITY IDEOGRAPH-F936 → CJK UNIFIED IDEOGRAPH-865C\t# \n2F9B4 ;\t865C ;\tMA\t# ( 虜 → 虜 ) CJK COMPATIBILITY IDEOGRAPH-2F9B4 → CJK UNIFIED IDEOGRAPH-865C\t# \n\n2F9B5 ;\t8667 ;\tMA\t# ( 虧 → 虧 ) CJK COMPATIBILITY IDEOGRAPH-2F9B5 → CJK UNIFIED IDEOGRAPH-8667\t# \n\n2F9B6 ;\t8669 ;\tMA\t# ( 虩 → 虩 ) CJK COMPATIBILITY IDEOGRAPH-2F9B6 → CJK UNIFIED IDEOGRAPH-8669\t# \n\n2F8D ;\t866B ;\tMA\t#* ( ⾍ → 虫 ) KANGXI RADICAL INSECT → CJK UNIFIED IDEOGRAPH-866B\t# \n\n2F9B7 ;\t86A9 ;\tMA\t# ( 蚩 → 蚩 ) CJK COMPATIBILITY IDEOGRAPH-2F9B7 → CJK UNIFIED IDEOGRAPH-86A9\t# \n\n2F9B8 ;\t8688 ;\tMA\t# ( 蚈 → 蚈 ) CJK COMPATIBILITY IDEOGRAPH-2F9B8 → CJK UNIFIED IDEOGRAPH-8688\t# \n\n2F9BA ;\t86E2 ;\tMA\t# ( 蛢 → 蛢 ) CJK COMPATIBILITY IDEOGRAPH-2F9BA → CJK UNIFIED IDEOGRAPH-86E2\t# \n\n2F9B9 ;\t870E ;\tMA\t# ( 蜎 → 蜎 ) CJK COMPATIBILITY IDEOGRAPH-2F9B9 → CJK UNIFIED IDEOGRAPH-870E\t# \n\n2F9BC ;\t8728 ;\tMA\t# ( 蜨 → 蜨 ) CJK COMPATIBILITY IDEOGRAPH-2F9BC → CJK UNIFIED IDEOGRAPH-8728\t# \n\n2F9BD ;\t876B ;\tMA\t# ( 蝫 → 蝫 ) CJK COMPATIBILITY IDEOGRAPH-2F9BD → CJK UNIFIED IDEOGRAPH-876B\t# \n\n2F9C0 ;\t87E1 ;\tMA\t# ( 蟡 → 蟡 ) CJK COMPATIBILITY IDEOGRAPH-2F9C0 → CJK UNIFIED IDEOGRAPH-87E1\t# \n\nFAB5 ;\t8779 ;\tMA\t# ( 蝹 → 蝹 ) CJK COMPATIBILITY IDEOGRAPH-FAB5 → CJK UNIFIED IDEOGRAPH-8779\t# \n2F9BB ;\t8779 ;\tMA\t# ( 蝹 → 蝹 ) CJK COMPATIBILITY IDEOGRAPH-2F9BB → CJK UNIFIED IDEOGRAPH-8779\t# \n\n2F9BE ;\t8786 ;\tMA\t# ( 螆 → 螆 ) CJK COMPATIBILITY IDEOGRAPH-2F9BE → CJK UNIFIED IDEOGRAPH-8786\t# \n\n2F9BF ;\t45D7 ;\tMA\t# ( 䗗 → 䗗 ) CJK COMPATIBILITY IDEOGRAPH-2F9BF → CJK UNIFIED IDEOGRAPH-45D7\t# \n\n2F9AB ;\t273CA ;\tMA\t# ( 𧏊 → 𧏊 ) CJK COMPATIBILITY IDEOGRAPH-2F9AB → CJK UNIFIED IDEOGRAPH-273CA\t# \n\nF911 ;\t87BA ;\tMA\t# ( 螺 → 螺 ) CJK COMPATIBILITY IDEOGRAPH-F911 → CJK UNIFIED IDEOGRAPH-87BA\t# \n\n2F9C1 ;\t8801 ;\tMA\t# ( 蠁 → 蠁 ) CJK COMPATIBILITY IDEOGRAPH-2F9C1 → CJK UNIFIED IDEOGRAPH-8801\t# \n\n2F9C2 ;\t45F9 ;\tMA\t# ( 䗹 → 䗹 ) CJK COMPATIBILITY IDEOGRAPH-2F9C2 → CJK UNIFIED IDEOGRAPH-45F9\t# \n\nF927 ;\t881F ;\tMA\t# ( 蠟 → 蠟 ) CJK COMPATIBILITY IDEOGRAPH-F927 → CJK UNIFIED IDEOGRAPH-881F\t# \n\n2F8E ;\t8840 ;\tMA\t#* ( ⾎ → 血 ) KANGXI RADICAL BLOOD → CJK UNIFIED IDEOGRAPH-8840\t# \n\nFA08 ;\t884C ;\tMA\t# ( 行 → 行 ) CJK COMPATIBILITY IDEOGRAPH-FA08 → CJK UNIFIED IDEOGRAPH-884C\t# \n2F8F ;\t884C ;\tMA\t#* ( ⾏ → 行 ) KANGXI RADICAL WALK ENCLOSURE → CJK UNIFIED IDEOGRAPH-884C\t# \n\n2F9C3 ;\t8860 ;\tMA\t# ( 衠 → 衠 ) CJK COMPATIBILITY IDEOGRAPH-2F9C3 → CJK UNIFIED IDEOGRAPH-8860\t# \n\n2F9C4 ;\t8863 ;\tMA\t# ( 衣 → 衣 ) CJK COMPATIBILITY IDEOGRAPH-2F9C4 → CJK UNIFIED IDEOGRAPH-8863\t# \n2F90 ;\t8863 ;\tMA\t#* ( ⾐ → 衣 ) KANGXI RADICAL CLOTHES → CJK UNIFIED IDEOGRAPH-8863\t# \n\n2EC2 ;\t8864 ;\tMA\t#* ( ⻂ → 衤 ) CJK RADICAL CLOTHES → CJK UNIFIED IDEOGRAPH-8864\t# \n\nF9A0 ;\t88C2 ;\tMA\t# ( 裂 → 裂 ) CJK COMPATIBILITY IDEOGRAPH-F9A0 → CJK UNIFIED IDEOGRAPH-88C2\t# \n\n2F9C5 ;\t27667 ;\tMA\t# ( 𧙧 → 𧙧 ) CJK COMPATIBILITY IDEOGRAPH-2F9C5 → CJK UNIFIED IDEOGRAPH-27667\t# \n\nF9E7 ;\t88CF ;\tMA\t# ( 裏 → 裏 ) CJK COMPATIBILITY IDEOGRAPH-F9E7 → CJK UNIFIED IDEOGRAPH-88CF\t# \n\n2F9C6 ;\t88D7 ;\tMA\t# ( 裗 → 裗 ) CJK COMPATIBILITY IDEOGRAPH-2F9C6 → CJK UNIFIED IDEOGRAPH-88D7\t# \n\n2F9C7 ;\t88DE ;\tMA\t# ( 裞 → 裞 ) CJK COMPATIBILITY IDEOGRAPH-2F9C7 → CJK UNIFIED IDEOGRAPH-88DE\t# \n\nF9E8 ;\t88E1 ;\tMA\t# ( 裡 → 裡 ) CJK COMPATIBILITY IDEOGRAPH-F9E8 → CJK UNIFIED IDEOGRAPH-88E1\t# \n\nF912 ;\t88F8 ;\tMA\t# ( 裸 → 裸 ) CJK COMPATIBILITY IDEOGRAPH-F912 → CJK UNIFIED IDEOGRAPH-88F8\t# \n\n2F9C9 ;\t88FA ;\tMA\t# ( 裺 → 裺 ) CJK COMPATIBILITY IDEOGRAPH-2F9C9 → CJK UNIFIED IDEOGRAPH-88FA\t# \n\n2F9C8 ;\t4635 ;\tMA\t# ( 䘵 → 䘵 ) CJK COMPATIBILITY IDEOGRAPH-2F9C8 → CJK UNIFIED IDEOGRAPH-4635\t# \n\nFA60 ;\t8910 ;\tMA\t# ( 褐 → 褐 ) CJK COMPATIBILITY IDEOGRAPH-FA60 → CJK UNIFIED IDEOGRAPH-8910\t# \n\nFAB6 ;\t8941 ;\tMA\t# ( 襁 → 襁 ) CJK COMPATIBILITY IDEOGRAPH-FAB6 → CJK UNIFIED IDEOGRAPH-8941\t# \n\nF924 ;\t8964 ;\tMA\t# ( 襤 → 襤 ) CJK COMPATIBILITY IDEOGRAPH-F924 → CJK UNIFIED IDEOGRAPH-8964\t# \n\n2F91 ;\t897E ;\tMA\t#* ( ⾑ → 襾 ) KANGXI RADICAL WEST → CJK UNIFIED IDEOGRAPH-897E\t# \n\n2EC4 ;\t897F ;\tMA\t#* ( ⻄ → 西 ) CJK RADICAL WEST TWO → CJK UNIFIED IDEOGRAPH-897F\t# \n\n2EC3 ;\t8980 ;\tMA\t#* ( ⻃ → 覀 ) CJK RADICAL WEST ONE → CJK UNIFIED IDEOGRAPH-8980\t# \n\nFAB7 ;\t8986 ;\tMA\t# ( 覆 → 覆 ) CJK COMPATIBILITY IDEOGRAPH-FAB7 → CJK UNIFIED IDEOGRAPH-8986\t# \n\nFA0A ;\t898B ;\tMA\t# ( 見 → 見 ) CJK COMPATIBILITY IDEOGRAPH-FA0A → CJK UNIFIED IDEOGRAPH-898B\t# \n2F92 ;\t898B ;\tMA\t#* ( ⾒ → 見 ) KANGXI RADICAL SEE → CJK UNIFIED IDEOGRAPH-898B\t# \n\n2EC5 ;\t89C1 ;\tMA\t#* ( ⻅ → 见 ) CJK RADICAL C-SIMPLIFIED SEE → CJK UNIFIED IDEOGRAPH-89C1\t# \n\n4695 ;\t278AE ;\tMA\t# ( 䚕 → 𧢮 ) CJK UNIFIED IDEOGRAPH-4695 → CJK UNIFIED IDEOGRAPH-278AE\t# →𧢮→\n2F9CB ;\t278AE ;\tMA\t# ( 𧢮 → 𧢮 ) CJK COMPATIBILITY IDEOGRAPH-2F9CB → CJK UNIFIED IDEOGRAPH-278AE\t# \n\n2F93 ;\t89D2 ;\tMA\t#* ( ⾓ → 角 ) KANGXI RADICAL HORN → CJK UNIFIED IDEOGRAPH-89D2\t# \n\n2F94 ;\t8A00 ;\tMA\t#* ( ⾔ → 言 ) KANGXI RADICAL SPEECH → CJK UNIFIED IDEOGRAPH-8A00\t# \n\n2EC8 ;\t8BA0 ;\tMA\t#* ( ⻈ → 讠 ) CJK RADICAL C-SIMPLIFIED SPEECH → CJK UNIFIED IDEOGRAPH-8BA0\t# \n\n2F9CC ;\t27966 ;\tMA\t# ( 𧥦 → 𧥦 ) CJK COMPATIBILITY IDEOGRAPH-2F9CC → CJK UNIFIED IDEOGRAPH-27966\t# \n\n8A7D ;\t8A2E ;\tMA\t# ( 詽 → 訮 ) CJK UNIFIED IDEOGRAPH-8A7D → CJK UNIFIED IDEOGRAPH-8A2E\t# \n\n8A1E ;\t46B6 ;\tMA\t# ( 訞 → 䚶 ) CJK UNIFIED IDEOGRAPH-8A1E → CJK UNIFIED IDEOGRAPH-46B6\t# \n\n2F9CD ;\t46BE ;\tMA\t# ( 䚾 → 䚾 ) CJK COMPATIBILITY IDEOGRAPH-2F9CD → CJK UNIFIED IDEOGRAPH-46BE\t# \n\n2F9CE ;\t46C7 ;\tMA\t# ( 䛇 → 䛇 ) CJK COMPATIBILITY IDEOGRAPH-2F9CE → CJK UNIFIED IDEOGRAPH-46C7\t# \n\n2F9CF ;\t8AA0 ;\tMA\t# ( 誠 → 誠 ) CJK COMPATIBILITY IDEOGRAPH-2F9CF → CJK UNIFIED IDEOGRAPH-8AA0\t# \n\nF96F ;\t8AAA ;\tMA\t# ( 說 → 說 ) CJK COMPATIBILITY IDEOGRAPH-F96F → CJK UNIFIED IDEOGRAPH-8AAA\t# \nF9A1 ;\t8AAA ;\tMA\t# ( 說 → 說 ) CJK COMPATIBILITY IDEOGRAPH-F9A1 → CJK UNIFIED IDEOGRAPH-8AAA\t# \n\nFAB9 ;\t8ABF ;\tMA\t# ( 調 → 調 ) CJK COMPATIBILITY IDEOGRAPH-FAB9 → CJK UNIFIED IDEOGRAPH-8ABF\t# \n\nFABB ;\t8ACB ;\tMA\t# ( 請 → 請 ) CJK COMPATIBILITY IDEOGRAPH-FABB → CJK UNIFIED IDEOGRAPH-8ACB\t# \n\nF97D ;\t8AD2 ;\tMA\t# ( 諒 → 諒 ) CJK COMPATIBILITY IDEOGRAPH-F97D → CJK UNIFIED IDEOGRAPH-8AD2\t# \n\nF941 ;\t8AD6 ;\tMA\t# ( 論 → 論 ) CJK COMPATIBILITY IDEOGRAPH-F941 → CJK UNIFIED IDEOGRAPH-8AD6\t# \n\nFABE ;\t8AED ;\tMA\t# ( 諭 → 諭 ) CJK COMPATIBILITY IDEOGRAPH-FABE → CJK UNIFIED IDEOGRAPH-8AED\t# \n2F9D0 ;\t8AED ;\tMA\t# ( 諭 → 諭 ) CJK COMPATIBILITY IDEOGRAPH-2F9D0 → CJK UNIFIED IDEOGRAPH-8AED\t# \n\nFA22 ;\t8AF8 ;\tMA\t# ( 諸 → 諸 ) CJK COMPATIBILITY IDEOGRAPH-FA22 → CJK UNIFIED IDEOGRAPH-8AF8\t# \nFABA ;\t8AF8 ;\tMA\t# ( 諸 → 諸 ) CJK COMPATIBILITY IDEOGRAPH-FABA → CJK UNIFIED IDEOGRAPH-8AF8\t# \n\nF95D ;\t8AFE ;\tMA\t# ( 諾 → 諾 ) CJK COMPATIBILITY IDEOGRAPH-F95D → CJK UNIFIED IDEOGRAPH-8AFE\t# \nFABD ;\t8AFE ;\tMA\t# ( 諾 → 諾 ) CJK COMPATIBILITY IDEOGRAPH-FABD → CJK UNIFIED IDEOGRAPH-8AFE\t# \n\nFA62 ;\t8B01 ;\tMA\t# ( 謁 → 謁 ) CJK COMPATIBILITY IDEOGRAPH-FA62 → CJK UNIFIED IDEOGRAPH-8B01\t# \nFABC ;\t8B01 ;\tMA\t# ( 謁 → 謁 ) CJK COMPATIBILITY IDEOGRAPH-FABC → CJK UNIFIED IDEOGRAPH-8B01\t# \n\nFA63 ;\t8B39 ;\tMA\t# ( 謹 → 謹 ) CJK COMPATIBILITY IDEOGRAPH-FA63 → CJK UNIFIED IDEOGRAPH-8B39\t# \nFABF ;\t8B39 ;\tMA\t# ( 謹 → 謹 ) CJK COMPATIBILITY IDEOGRAPH-FABF → CJK UNIFIED IDEOGRAPH-8B39\t# \n\nF9FC ;\t8B58 ;\tMA\t# ( 識 → 識 ) CJK COMPATIBILITY IDEOGRAPH-F9FC → CJK UNIFIED IDEOGRAPH-8B58\t# \n\nF95A ;\t8B80 ;\tMA\t# ( 讀 → 讀 ) CJK COMPATIBILITY IDEOGRAPH-F95A → CJK UNIFIED IDEOGRAPH-8B80\t# \n\n8B8F ;\t8B86 ;\tMA\t# ( 讏 → 讆 ) CJK UNIFIED IDEOGRAPH-8B8F → CJK UNIFIED IDEOGRAPH-8B86\t# \n\nFAC0 ;\t8B8A ;\tMA\t# ( 變 → 變 ) CJK COMPATIBILITY IDEOGRAPH-FAC0 → CJK UNIFIED IDEOGRAPH-8B8A\t# \n2F9D1 ;\t8B8A ;\tMA\t# ( 變 → 變 ) CJK COMPATIBILITY IDEOGRAPH-2F9D1 → CJK UNIFIED IDEOGRAPH-8B8A\t# \n\n2F95 ;\t8C37 ;\tMA\t#* ( ⾕ → 谷 ) KANGXI RADICAL VALLEY → CJK UNIFIED IDEOGRAPH-8C37\t# \n\n2F96 ;\t8C46 ;\tMA\t#* ( ⾖ → 豆 ) KANGXI RADICAL BEAN → CJK UNIFIED IDEOGRAPH-8C46\t# \n\nF900 ;\t8C48 ;\tMA\t# ( 豈 → 豈 ) CJK COMPATIBILITY IDEOGRAPH-F900 → CJK UNIFIED IDEOGRAPH-8C48\t# \n\n2F9D2 ;\t8C55 ;\tMA\t# ( 豕 → 豕 ) CJK COMPATIBILITY IDEOGRAPH-2F9D2 → CJK UNIFIED IDEOGRAPH-8C55\t# \n2F97 ;\t8C55 ;\tMA\t#* ( ⾗ → 豕 ) KANGXI RADICAL PIG → CJK UNIFIED IDEOGRAPH-8C55\t# \n\n8C63 ;\t8C5C ;\tMA\t# ( 豣 → 豜 ) CJK UNIFIED IDEOGRAPH-8C63 → CJK UNIFIED IDEOGRAPH-8C5C\t# \n\n2F98 ;\t8C78 ;\tMA\t#* ( ⾘ → 豸 ) KANGXI RADICAL BADGER → CJK UNIFIED IDEOGRAPH-8C78\t# \n\n2F9D3 ;\t27CA8 ;\tMA\t# ( 𧲨 → 𧲨 ) CJK COMPATIBILITY IDEOGRAPH-2F9D3 → CJK UNIFIED IDEOGRAPH-27CA8\t# \n\n2F99 ;\t8C9D ;\tMA\t#* ( ⾙ → 貝 ) KANGXI RADICAL SHELL → CJK UNIFIED IDEOGRAPH-8C9D\t# \n\n2EC9 ;\t8D1D ;\tMA\t#* ( ⻉ → 贝 ) CJK RADICAL C-SIMPLIFIED SHELL → CJK UNIFIED IDEOGRAPH-8D1D\t# \n\n2F9D4 ;\t8CAB ;\tMA\t# ( 貫 → 貫 ) CJK COMPATIBILITY IDEOGRAPH-2F9D4 → CJK UNIFIED IDEOGRAPH-8CAB\t# \n\n2F9D5 ;\t8CC1 ;\tMA\t# ( 賁 → 賁 ) CJK COMPATIBILITY IDEOGRAPH-2F9D5 → CJK UNIFIED IDEOGRAPH-8CC1\t# \n\nF948 ;\t8CC2 ;\tMA\t# ( 賂 → 賂 ) CJK COMPATIBILITY IDEOGRAPH-F948 → CJK UNIFIED IDEOGRAPH-8CC2\t# \n\nF903 ;\t8CC8 ;\tMA\t# ( 賈 → 賈 ) CJK COMPATIBILITY IDEOGRAPH-F903 → CJK UNIFIED IDEOGRAPH-8CC8\t# \n\nFA64 ;\t8CD3 ;\tMA\t# ( 賓 → 賓 ) CJK COMPATIBILITY IDEOGRAPH-FA64 → CJK UNIFIED IDEOGRAPH-8CD3\t# \n\nFA65 ;\t8D08 ;\tMA\t# ( 贈 → 贈 ) CJK COMPATIBILITY IDEOGRAPH-FA65 → CJK UNIFIED IDEOGRAPH-8D08\t# \nFAC1 ;\t8D08 ;\tMA\t# ( 贈 → 贈 ) CJK COMPATIBILITY IDEOGRAPH-FAC1 → CJK UNIFIED IDEOGRAPH-8D08\t# \n\n25AD4 ;\t8D1B ;\tMA\t# ( 𥫔 → 贛 ) CJK UNIFIED IDEOGRAPH-25AD4 → CJK UNIFIED IDEOGRAPH-8D1B\t# →贛→\n2F9D6 ;\t8D1B ;\tMA\t# ( 贛 → 贛 ) CJK COMPATIBILITY IDEOGRAPH-2F9D6 → CJK UNIFIED IDEOGRAPH-8D1B\t# \n\n2F9A ;\t8D64 ;\tMA\t#* ( ⾚ → 赤 ) KANGXI RADICAL RED → CJK UNIFIED IDEOGRAPH-8D64\t# \n\n2F9B ;\t8D70 ;\tMA\t#* ( ⾛ → 走 ) KANGXI RADICAL RUN → CJK UNIFIED IDEOGRAPH-8D70\t# \n\n2F9D7 ;\t8D77 ;\tMA\t# ( 起 → 起 ) CJK COMPATIBILITY IDEOGRAPH-2F9D7 → CJK UNIFIED IDEOGRAPH-8D77\t# \n\n8D86 ;\t8D7F ;\tMA\t# ( 趆 → 赿 ) CJK UNIFIED IDEOGRAPH-8D86 → CJK UNIFIED IDEOGRAPH-8D7F\t# \n\nFAD7 ;\t27ED3 ;\tMA\t# ( 𧻓 → 𧻓 ) CJK COMPATIBILITY IDEOGRAPH-FAD7 → CJK UNIFIED IDEOGRAPH-27ED3\t# \n\n2F9D8 ;\t27F2F ;\tMA\t# ( 𧼯 → 𧼯 ) CJK COMPATIBILITY IDEOGRAPH-2F9D8 → CJK UNIFIED IDEOGRAPH-27F2F\t# \n\n2F9C ;\t8DB3 ;\tMA\t#* ( ⾜ → 足 ) KANGXI RADICAL FOOT → CJK UNIFIED IDEOGRAPH-8DB3\t# \n\n2F9DA ;\t8DCB ;\tMA\t# ( 跋 → 跋 ) CJK COMPATIBILITY IDEOGRAPH-2F9DA → CJK UNIFIED IDEOGRAPH-8DCB\t# \n\n2F9DB ;\t8DBC ;\tMA\t# ( 趼 → 趼 ) CJK COMPATIBILITY IDEOGRAPH-2F9DB → CJK UNIFIED IDEOGRAPH-8DBC\t# \n\n8DFA ;\t8DE5 ;\tMA\t# ( 跺 → 跥 ) CJK UNIFIED IDEOGRAPH-8DFA → CJK UNIFIED IDEOGRAPH-8DE5\t# \n\nF937 ;\t8DEF ;\tMA\t# ( 路 → 路 ) CJK COMPATIBILITY IDEOGRAPH-F937 → CJK UNIFIED IDEOGRAPH-8DEF\t# \n\n2F9DC ;\t8DF0 ;\tMA\t# ( 跰 → 跰 ) CJK COMPATIBILITY IDEOGRAPH-2F9DC → CJK UNIFIED IDEOGRAPH-8DF0\t# \n\n8E9B ;\t8E97 ;\tMA\t# ( 躛 → 躗 ) CJK UNIFIED IDEOGRAPH-8E9B → CJK UNIFIED IDEOGRAPH-8E97\t# \n\n2F9D ;\t8EAB ;\tMA\t#* ( ⾝ → 身 ) KANGXI RADICAL BODY → CJK UNIFIED IDEOGRAPH-8EAB\t# \n\nF902 ;\t8ECA ;\tMA\t# ( 車 → 車 ) CJK COMPATIBILITY IDEOGRAPH-F902 → CJK UNIFIED IDEOGRAPH-8ECA\t# \n2F9E ;\t8ECA ;\tMA\t#* ( ⾞ → 車 ) KANGXI RADICAL CART → CJK UNIFIED IDEOGRAPH-8ECA\t# \n\n2ECB ;\t8F66 ;\tMA\t#* ( ⻋ → 车 ) CJK RADICAL C-SIMPLIFIED CART → CJK UNIFIED IDEOGRAPH-8F66\t# \n\n2F9DE ;\t8ED4 ;\tMA\t# ( 軔 → 軔 ) CJK COMPATIBILITY IDEOGRAPH-2F9DE → CJK UNIFIED IDEOGRAPH-8ED4\t# \n\n8F27 ;\t8EFF ;\tMA\t# ( 輧 → 軿 ) CJK UNIFIED IDEOGRAPH-8F27 → CJK UNIFIED IDEOGRAPH-8EFF\t# \n\nF998 ;\t8F26 ;\tMA\t# ( 輦 → 輦 ) CJK COMPATIBILITY IDEOGRAPH-F998 → CJK UNIFIED IDEOGRAPH-8F26\t# \n\nF9D7 ;\t8F2A ;\tMA\t# ( 輪 → 輪 ) CJK COMPATIBILITY IDEOGRAPH-F9D7 → CJK UNIFIED IDEOGRAPH-8F2A\t# \n\nFAC2 ;\t8F38 ;\tMA\t# ( 輸 → 輸 ) CJK COMPATIBILITY IDEOGRAPH-FAC2 → CJK UNIFIED IDEOGRAPH-8F38\t# \n2F9DF ;\t8F38 ;\tMA\t# ( 輸 → 輸 ) CJK COMPATIBILITY IDEOGRAPH-2F9DF → CJK UNIFIED IDEOGRAPH-8F38\t# \n\nFA07 ;\t8F3B ;\tMA\t# ( 輻 → 輻 ) CJK COMPATIBILITY IDEOGRAPH-FA07 → CJK UNIFIED IDEOGRAPH-8F3B\t# \n\nF98D ;\t8F62 ;\tMA\t# ( 轢 → 轢 ) CJK COMPATIBILITY IDEOGRAPH-F98D → CJK UNIFIED IDEOGRAPH-8F62\t# \n\n2F9F ;\t8F9B ;\tMA\t#* ( ⾟ → 辛 ) KANGXI RADICAL BITTER → CJK UNIFIED IDEOGRAPH-8F9B\t# \n\n2F98D ;\t8F9E ;\tMA\t# ( 辞 → 辞 ) CJK COMPATIBILITY IDEOGRAPH-2F98D → CJK UNIFIED IDEOGRAPH-8F9E\t# \n\nF971 ;\t8FB0 ;\tMA\t# ( 辰 → 辰 ) CJK COMPATIBILITY IDEOGRAPH-F971 → CJK UNIFIED IDEOGRAPH-8FB0\t# \n2FA0 ;\t8FB0 ;\tMA\t#* ( ⾠ → 辰 ) KANGXI RADICAL MORNING → CJK UNIFIED IDEOGRAPH-8FB0\t# \n\n2FA1 ;\t8FB5 ;\tMA\t#* ( ⾡ → 辵 ) KANGXI RADICAL WALK → CJK UNIFIED IDEOGRAPH-8FB5\t# \n\nFA66 ;\t8FB6 ;\tMA\t# ( 辶 → 辶 ) CJK COMPATIBILITY IDEOGRAPH-FA66 → CJK UNIFIED IDEOGRAPH-8FB6\t# \n2ECC ;\t8FB6 ;\tMA\t#* ( ⻌ → 辶 ) CJK RADICAL SIMPLIFIED WALK → CJK UNIFIED IDEOGRAPH-8FB6\t# \n2ECD ;\t8FB6 ;\tMA\t#* ( ⻍ → 辶 ) CJK RADICAL WALK ONE → CJK UNIFIED IDEOGRAPH-8FB6\t# \n\n2F881 ;\t5DE1 ;\tMA\t# ( 巡 → 巡 ) CJK COMPATIBILITY IDEOGRAPH-2F881 → CJK UNIFIED IDEOGRAPH-5DE1\t# \n\nF99A ;\t9023 ;\tMA\t# ( 連 → 連 ) CJK COMPATIBILITY IDEOGRAPH-F99A → CJK UNIFIED IDEOGRAPH-9023\t# \n\nFA25 ;\t9038 ;\tMA\t# ( 逸 → 逸 ) CJK COMPATIBILITY IDEOGRAPH-FA25 → CJK UNIFIED IDEOGRAPH-9038\t# \nFA67 ;\t9038 ;\tMA\t# ( 逸 → 逸 ) CJK COMPATIBILITY IDEOGRAPH-FA67 → CJK UNIFIED IDEOGRAPH-9038\t# \n\nFAC3 ;\t9072 ;\tMA\t# ( 遲 → 遲 ) CJK COMPATIBILITY IDEOGRAPH-FAC3 → CJK UNIFIED IDEOGRAPH-9072\t# \n\nF9C3 ;\t907C ;\tMA\t# ( 遼 → 遼 ) CJK COMPATIBILITY IDEOGRAPH-F9C3 → CJK UNIFIED IDEOGRAPH-907C\t# \n\n2F9E0 ;\t285D2 ;\tMA\t# ( 𨗒 → 𨗒 ) CJK COMPATIBILITY IDEOGRAPH-2F9E0 → CJK UNIFIED IDEOGRAPH-285D2\t# \n\n2F9E1 ;\t285ED ;\tMA\t# ( 𨗭 → 𨗭 ) CJK COMPATIBILITY IDEOGRAPH-2F9E1 → CJK UNIFIED IDEOGRAPH-285ED\t# \n\nF913 ;\t908F ;\tMA\t# ( 邏 → 邏 ) CJK COMPATIBILITY IDEOGRAPH-F913 → CJK UNIFIED IDEOGRAPH-908F\t# \n\n2FA2 ;\t9091 ;\tMA\t#* ( ⾢ → 邑 ) KANGXI RADICAL CITY → CJK UNIFIED IDEOGRAPH-9091\t# \n\n2F9E2 ;\t9094 ;\tMA\t# ( 邔 → 邔 ) CJK COMPATIBILITY IDEOGRAPH-2F9E2 → CJK UNIFIED IDEOGRAPH-9094\t# \n\nF92C ;\t90CE ;\tMA\t# ( 郎 → 郎 ) CJK COMPATIBILITY IDEOGRAPH-F92C → CJK UNIFIED IDEOGRAPH-90CE\t# \n90DE ;\t90CE ;\tMA\t# ( 郞 → 郎 ) CJK UNIFIED IDEOGRAPH-90DE → CJK UNIFIED IDEOGRAPH-90CE\t# →郎→\nFA2E ;\t90CE ;\tMA\t# ( 郞 → 郎 ) CJK COMPATIBILITY IDEOGRAPH-FA2E → CJK UNIFIED IDEOGRAPH-90CE\t# →郞→→郎→\n\n2F9E3 ;\t90F1 ;\tMA\t# ( 郱 → 郱 ) CJK COMPATIBILITY IDEOGRAPH-2F9E3 → CJK UNIFIED IDEOGRAPH-90F1\t# \n\nFA26 ;\t90FD ;\tMA\t# ( 都 → 都 ) CJK COMPATIBILITY IDEOGRAPH-FA26 → CJK UNIFIED IDEOGRAPH-90FD\t# \n\n2F9E5 ;\t2872E ;\tMA\t# ( 𨜮 → 𨜮 ) CJK COMPATIBILITY IDEOGRAPH-2F9E5 → CJK UNIFIED IDEOGRAPH-2872E\t# \n\n2F9E4 ;\t9111 ;\tMA\t# ( 鄑 → 鄑 ) CJK COMPATIBILITY IDEOGRAPH-2F9E4 → CJK UNIFIED IDEOGRAPH-9111\t# \n\n2F9E6 ;\t911B ;\tMA\t# ( 鄛 → 鄛 ) CJK COMPATIBILITY IDEOGRAPH-2F9E6 → CJK UNIFIED IDEOGRAPH-911B\t# \n\n2FA3 ;\t9149 ;\tMA\t#* ( ⾣ → 酉 ) KANGXI RADICAL WINE → CJK UNIFIED IDEOGRAPH-9149\t# \n\nF919 ;\t916A ;\tMA\t# ( 酪 → 酪 ) CJK COMPATIBILITY IDEOGRAPH-F919 → CJK UNIFIED IDEOGRAPH-916A\t# \n\nFAC4 ;\t9199 ;\tMA\t# ( 醙 → 醙 ) CJK COMPATIBILITY IDEOGRAPH-FAC4 → CJK UNIFIED IDEOGRAPH-9199\t# \n\nF9B7 ;\t91B4 ;\tMA\t# ( 醴 → 醴 ) CJK COMPATIBILITY IDEOGRAPH-F9B7 → CJK UNIFIED IDEOGRAPH-91B4\t# \n\n2FA4 ;\t91C6 ;\tMA\t#* ( ⾤ → 釆 ) KANGXI RADICAL DISTINGUISH → CJK UNIFIED IDEOGRAPH-91C6\t# \n\nF9E9 ;\t91CC ;\tMA\t# ( 里 → 里 ) CJK COMPATIBILITY IDEOGRAPH-F9E9 → CJK UNIFIED IDEOGRAPH-91CC\t# \n2FA5 ;\t91CC ;\tMA\t#* ( ⾥ → 里 ) KANGXI RADICAL VILLAGE → CJK UNIFIED IDEOGRAPH-91CC\t# \n\nF97E ;\t91CF ;\tMA\t# ( 量 → 量 ) CJK COMPATIBILITY IDEOGRAPH-F97E → CJK UNIFIED IDEOGRAPH-91CF\t# \n\nF90A ;\t91D1 ;\tMA\t# ( 金 → 金 ) CJK COMPATIBILITY IDEOGRAPH-F90A → CJK UNIFIED IDEOGRAPH-91D1\t# \n2FA6 ;\t91D1 ;\tMA\t#* ( ⾦ → 金 ) KANGXI RADICAL GOLD → CJK UNIFIED IDEOGRAPH-91D1\t# \n\n2ED0 ;\t9485 ;\tMA\t#* ( ⻐ → 钅 ) CJK RADICAL C-SIMPLIFIED GOLD → CJK UNIFIED IDEOGRAPH-9485\t# \n\nF9B1 ;\t9234 ;\tMA\t# ( 鈴 → 鈴 ) CJK COMPATIBILITY IDEOGRAPH-F9B1 → CJK UNIFIED IDEOGRAPH-9234\t# \n\n2F9E7 ;\t9238 ;\tMA\t# ( 鈸 → 鈸 ) CJK COMPATIBILITY IDEOGRAPH-2F9E7 → CJK UNIFIED IDEOGRAPH-9238\t# \n\nFAC5 ;\t9276 ;\tMA\t# ( 鉶 → 鉶 ) CJK COMPATIBILITY IDEOGRAPH-FAC5 → CJK UNIFIED IDEOGRAPH-9276\t# \n\n2F9E8 ;\t92D7 ;\tMA\t# ( 鋗 → 鋗 ) CJK COMPATIBILITY IDEOGRAPH-2F9E8 → CJK UNIFIED IDEOGRAPH-92D7\t# \n\n2F9E9 ;\t92D8 ;\tMA\t# ( 鋘 → 鋘 ) CJK COMPATIBILITY IDEOGRAPH-2F9E9 → CJK UNIFIED IDEOGRAPH-92D8\t# \n\n2F9EA ;\t927C ;\tMA\t# ( 鉼 → 鉼 ) CJK COMPATIBILITY IDEOGRAPH-2F9EA → CJK UNIFIED IDEOGRAPH-927C\t# \n\nF93F ;\t9304 ;\tMA\t# ( 錄 → 錄 ) CJK COMPATIBILITY IDEOGRAPH-F93F → CJK UNIFIED IDEOGRAPH-9304\t# \n\nF99B ;\t934A ;\tMA\t# ( 鍊 → 鍊 ) CJK COMPATIBILITY IDEOGRAPH-F99B → CJK UNIFIED IDEOGRAPH-934A\t# \n\n93AE ;\t93AD ;\tMA\t# ( 鎮 → 鎭 ) CJK UNIFIED IDEOGRAPH-93AE → CJK UNIFIED IDEOGRAPH-93AD\t# \n\n2F9EB ;\t93F9 ;\tMA\t# ( 鏹 → 鏹 ) CJK COMPATIBILITY IDEOGRAPH-2F9EB → CJK UNIFIED IDEOGRAPH-93F9\t# \n\n2F9EC ;\t9415 ;\tMA\t# ( 鐕 → 鐕 ) CJK COMPATIBILITY IDEOGRAPH-2F9EC → CJK UNIFIED IDEOGRAPH-9415\t# \n\n2F9ED ;\t28BFA ;\tMA\t# ( 𨯺 → 𨯺 ) CJK COMPATIBILITY IDEOGRAPH-2F9ED → CJK UNIFIED IDEOGRAPH-28BFA\t# \n\n2ED2 ;\t9578 ;\tMA\t#* ( ⻒ → 镸 ) CJK RADICAL LONG TWO → CJK UNIFIED IDEOGRAPH-9578\t# \n\n2ED3 ;\t957F ;\tMA\t#* ( ⻓ → 长 ) CJK RADICAL C-SIMPLIFIED LONG → CJK UNIFIED IDEOGRAPH-957F\t# \n\n2FA8 ;\t9580 ;\tMA\t#* ( ⾨ → 門 ) KANGXI RADICAL GATE → CJK UNIFIED IDEOGRAPH-9580\t# \n\n2ED4 ;\t95E8 ;\tMA\t#* ( ⻔ → 门 ) CJK RADICAL C-SIMPLIFIED GATE → CJK UNIFIED IDEOGRAPH-95E8\t# \n\n2F9EE ;\t958B ;\tMA\t# ( 開 → 開 ) CJK COMPATIBILITY IDEOGRAPH-2F9EE → CJK UNIFIED IDEOGRAPH-958B\t# \n\n2F9EF ;\t4995 ;\tMA\t# ( 䦕 → 䦕 ) CJK COMPATIBILITY IDEOGRAPH-2F9EF → CJK UNIFIED IDEOGRAPH-4995\t# \n\nF986 ;\t95AD ;\tMA\t# ( 閭 → 閭 ) CJK COMPATIBILITY IDEOGRAPH-F986 → CJK UNIFIED IDEOGRAPH-95AD\t# \n\n2F9F0 ;\t95B7 ;\tMA\t# ( 閷 → 閷 ) CJK COMPATIBILITY IDEOGRAPH-2F9F0 → CJK UNIFIED IDEOGRAPH-95B7\t# \n\n2F9F1 ;\t28D77 ;\tMA\t# ( 𨵷 → 𨵷 ) CJK COMPATIBILITY IDEOGRAPH-2F9F1 → CJK UNIFIED IDEOGRAPH-28D77\t# \n\n2FA9 ;\t961C ;\tMA\t#* ( ⾩ → 阜 ) KANGXI RADICAL MOUND → CJK UNIFIED IDEOGRAPH-961C\t# \n\n2ECF ;\t961D ;\tMA\t#* ( ⻏ → 阝 ) CJK RADICAL CITY → CJK UNIFIED IDEOGRAPH-961D\t# \n2ED6 ;\t961D ;\tMA\t#* ( ⻖ → 阝 ) CJK RADICAL MOUND TWO → CJK UNIFIED IDEOGRAPH-961D\t# \n\nF9C6 ;\t962E ;\tMA\t# ( 阮 → 阮 ) CJK COMPATIBILITY IDEOGRAPH-F9C6 → CJK UNIFIED IDEOGRAPH-962E\t# \n\nF951 ;\t964B ;\tMA\t# ( 陋 → 陋 ) CJK COMPATIBILITY IDEOGRAPH-F951 → CJK UNIFIED IDEOGRAPH-964B\t# \n\nFA09 ;\t964D ;\tMA\t# ( 降 → 降 ) CJK COMPATIBILITY IDEOGRAPH-FA09 → CJK UNIFIED IDEOGRAPH-964D\t# \n\nF959 ;\t9675 ;\tMA\t# ( 陵 → 陵 ) CJK COMPATIBILITY IDEOGRAPH-F959 → CJK UNIFIED IDEOGRAPH-9675\t# \n\nF9D3 ;\t9678 ;\tMA\t# ( 陸 → 陸 ) CJK COMPATIBILITY IDEOGRAPH-F9D3 → CJK UNIFIED IDEOGRAPH-9678\t# \n\nFAC6 ;\t967C ;\tMA\t# ( 陼 → 陼 ) CJK COMPATIBILITY IDEOGRAPH-FAC6 → CJK UNIFIED IDEOGRAPH-967C\t# \n\nF9DC ;\t9686 ;\tMA\t# ( 隆 → 隆 ) CJK COMPATIBILITY IDEOGRAPH-F9DC → CJK UNIFIED IDEOGRAPH-9686\t# \n\nF9F1 ;\t96A3 ;\tMA\t# ( 隣 → 隣 ) CJK COMPATIBILITY IDEOGRAPH-F9F1 → CJK UNIFIED IDEOGRAPH-96A3\t# \n\n2F9F2 ;\t49E6 ;\tMA\t# ( 䧦 → 䧦 ) CJK COMPATIBILITY IDEOGRAPH-2F9F2 → CJK UNIFIED IDEOGRAPH-49E6\t# \n\n2FAA ;\t96B6 ;\tMA\t#* ( ⾪ → 隶 ) KANGXI RADICAL SLAVE → CJK UNIFIED IDEOGRAPH-96B6\t# \n\nFA2F ;\t96B7 ;\tMA\t# ( 隷 → 隷 ) CJK COMPATIBILITY IDEOGRAPH-FA2F → CJK UNIFIED IDEOGRAPH-96B7\t# \n96B8 ;\t96B7 ;\tMA\t# ( 隸 → 隷 ) CJK UNIFIED IDEOGRAPH-96B8 → CJK UNIFIED IDEOGRAPH-96B7\t# →隸→\nF9B8 ;\t96B7 ;\tMA\t# ( 隸 → 隷 ) CJK COMPATIBILITY IDEOGRAPH-F9B8 → CJK UNIFIED IDEOGRAPH-96B7\t# \n\n2FAB ;\t96B9 ;\tMA\t#* ( ⾫ → 隹 ) KANGXI RADICAL SHORT TAILED BIRD → CJK UNIFIED IDEOGRAPH-96B9\t# \n\n2F9F3 ;\t96C3 ;\tMA\t# ( 雃 → 雃 ) CJK COMPATIBILITY IDEOGRAPH-2F9F3 → CJK UNIFIED IDEOGRAPH-96C3\t# \n\nF9EA ;\t96E2 ;\tMA\t# ( 離 → 離 ) CJK COMPATIBILITY IDEOGRAPH-F9EA → CJK UNIFIED IDEOGRAPH-96E2\t# \n\nFA68 ;\t96E3 ;\tMA\t# ( 難 → 難 ) CJK COMPATIBILITY IDEOGRAPH-FA68 → CJK UNIFIED IDEOGRAPH-96E3\t# \nFAC7 ;\t96E3 ;\tMA\t# ( 難 → 難 ) CJK COMPATIBILITY IDEOGRAPH-FAC7 → CJK UNIFIED IDEOGRAPH-96E3\t# \n\n2FAC ;\t96E8 ;\tMA\t#* ( ⾬ → 雨 ) KANGXI RADICAL RAIN → CJK UNIFIED IDEOGRAPH-96E8\t# \n\nF9B2 ;\t96F6 ;\tMA\t# ( 零 → 零 ) CJK COMPATIBILITY IDEOGRAPH-F9B2 → CJK UNIFIED IDEOGRAPH-96F6\t# \n\nF949 ;\t96F7 ;\tMA\t# ( 雷 → 雷 ) CJK COMPATIBILITY IDEOGRAPH-F949 → CJK UNIFIED IDEOGRAPH-96F7\t# \n\n2F9F5 ;\t9723 ;\tMA\t# ( 霣 → 霣 ) CJK COMPATIBILITY IDEOGRAPH-2F9F5 → CJK UNIFIED IDEOGRAPH-9723\t# \n\n2F9F6 ;\t29145 ;\tMA\t# ( 𩅅 → 𩅅 ) CJK COMPATIBILITY IDEOGRAPH-2F9F6 → CJK UNIFIED IDEOGRAPH-29145\t# \n\nF938 ;\t9732 ;\tMA\t# ( 露 → 露 ) CJK COMPATIBILITY IDEOGRAPH-F938 → CJK UNIFIED IDEOGRAPH-9732\t# \n\nF9B3 ;\t9748 ;\tMA\t# ( 靈 → 靈 ) CJK COMPATIBILITY IDEOGRAPH-F9B3 → CJK UNIFIED IDEOGRAPH-9748\t# \n\n2FAD ;\t9751 ;\tMA\t#* ( ⾭ → 靑 ) KANGXI RADICAL BLUE → CJK UNIFIED IDEOGRAPH-9751\t# \n\n2ED8 ;\t9752 ;\tMA\t#* ( ⻘ → 青 ) CJK RADICAL BLUE → CJK UNIFIED IDEOGRAPH-9752\t# \n\nFA1C ;\t9756 ;\tMA\t# ( 靖 → 靖 ) CJK COMPATIBILITY IDEOGRAPH-FA1C → CJK UNIFIED IDEOGRAPH-9756\t# \nFAC8 ;\t9756 ;\tMA\t# ( 靖 → 靖 ) CJK COMPATIBILITY IDEOGRAPH-FAC8 → CJK UNIFIED IDEOGRAPH-9756\t# \n\n2F81C ;\t291DF ;\tMA\t# ( 𩇟 → 𩇟 ) CJK COMPATIBILITY IDEOGRAPH-2F81C → CJK UNIFIED IDEOGRAPH-291DF\t# \n\n2FAE ;\t975E ;\tMA\t#* ( ⾮ → 非 ) KANGXI RADICAL WRONG → CJK UNIFIED IDEOGRAPH-975E\t# \n\n2FAF ;\t9762 ;\tMA\t#* ( ⾯ → 面 ) KANGXI RADICAL FACE → CJK UNIFIED IDEOGRAPH-9762\t# \n\n2F9F7 ;\t2921A ;\tMA\t# ( 𩈚 → 𩈚 ) CJK COMPATIBILITY IDEOGRAPH-2F9F7 → CJK UNIFIED IDEOGRAPH-2921A\t# \n\n2FB0 ;\t9769 ;\tMA\t#* ( ⾰ → 革 ) KANGXI RADICAL LEATHER → CJK UNIFIED IDEOGRAPH-9769\t# \n\n2F9F8 ;\t4A6E ;\tMA\t# ( 䩮 → 䩮 ) CJK COMPATIBILITY IDEOGRAPH-2F9F8 → CJK UNIFIED IDEOGRAPH-4A6E\t# \n\n2F9F9 ;\t4A76 ;\tMA\t# ( 䩶 → 䩶 ) CJK COMPATIBILITY IDEOGRAPH-2F9F9 → CJK UNIFIED IDEOGRAPH-4A76\t# \n\n2FB1 ;\t97CB ;\tMA\t#* ( ⾱ → 韋 ) KANGXI RADICAL TANNED LEATHER → CJK UNIFIED IDEOGRAPH-97CB\t# \n\n2ED9 ;\t97E6 ;\tMA\t#* ( ⻙ → 韦 ) CJK RADICAL C-SIMPLIFIED TANNED LEATHER → CJK UNIFIED IDEOGRAPH-97E6\t# \n\nFAC9 ;\t97DB ;\tMA\t# ( 韛 → 韛 ) CJK COMPATIBILITY IDEOGRAPH-FAC9 → CJK UNIFIED IDEOGRAPH-97DB\t# \n\n2F9FA ;\t97E0 ;\tMA\t# ( 韠 → 韠 ) CJK COMPATIBILITY IDEOGRAPH-2F9FA → CJK UNIFIED IDEOGRAPH-97E0\t# \n\n2FB2 ;\t97ED ;\tMA\t#* ( ⾲ → 韭 ) KANGXI RADICAL LEEK → CJK UNIFIED IDEOGRAPH-97ED\t# \n\n2F9FB ;\t2940A ;\tMA\t# ( 𩐊 → 𩐊 ) CJK COMPATIBILITY IDEOGRAPH-2F9FB → CJK UNIFIED IDEOGRAPH-2940A\t# \n\n2FB3 ;\t97F3 ;\tMA\t#* ( ⾳ → 音 ) KANGXI RADICAL SOUND → CJK UNIFIED IDEOGRAPH-97F3\t# \n\nFA69 ;\t97FF ;\tMA\t# ( 響 → 響 ) CJK COMPATIBILITY IDEOGRAPH-FA69 → CJK UNIFIED IDEOGRAPH-97FF\t# \nFACA ;\t97FF ;\tMA\t# ( 響 → 響 ) CJK COMPATIBILITY IDEOGRAPH-FACA → CJK UNIFIED IDEOGRAPH-97FF\t# \n\n2FB4 ;\t9801 ;\tMA\t#* ( ⾴ → 頁 ) KANGXI RADICAL LEAF → CJK UNIFIED IDEOGRAPH-9801\t# \n\n2EDA ;\t9875 ;\tMA\t#* ( ⻚ → 页 ) CJK RADICAL C-SIMPLIFIED LEAF → CJK UNIFIED IDEOGRAPH-9875\t# \n\n2F9FC ;\t4AB2 ;\tMA\t# ( 䪲 → 䪲 ) CJK COMPATIBILITY IDEOGRAPH-2F9FC → CJK UNIFIED IDEOGRAPH-4AB2\t# \n\nFACB ;\t980B ;\tMA\t# ( 頋 → 頋 ) CJK COMPATIBILITY IDEOGRAPH-FACB → CJK UNIFIED IDEOGRAPH-980B\t# \n2F9FE ;\t980B ;\tMA\t# ( 頋 → 頋 ) CJK COMPATIBILITY IDEOGRAPH-2F9FE → CJK UNIFIED IDEOGRAPH-980B\t# \n2F9FF ;\t980B ;\tMA\t# ( 頋 → 頋 ) CJK COMPATIBILITY IDEOGRAPH-2F9FF → CJK UNIFIED IDEOGRAPH-980B\t# \n\nF9B4 ;\t9818 ;\tMA\t# ( 領 → 領 ) CJK COMPATIBILITY IDEOGRAPH-F9B4 → CJK UNIFIED IDEOGRAPH-9818\t# \n\n2FA00 ;\t9829 ;\tMA\t# ( 頩 → 頩 ) CJK COMPATIBILITY IDEOGRAPH-2FA00 → CJK UNIFIED IDEOGRAPH-9829\t# \n\n2F9FD ;\t29496 ;\tMA\t# ( 𩒖 → 𩒖 ) CJK COMPATIBILITY IDEOGRAPH-2F9FD → CJK UNIFIED IDEOGRAPH-29496\t# \n\nFA6A ;\t983B ;\tMA\t# ( 頻 → 頻 ) CJK COMPATIBILITY IDEOGRAPH-FA6A → CJK UNIFIED IDEOGRAPH-983B\t# \nFACC ;\t983B ;\tMA\t# ( 頻 → 頻 ) CJK COMPATIBILITY IDEOGRAPH-FACC → CJK UNIFIED IDEOGRAPH-983B\t# \n\nF9D0 ;\t985E ;\tMA\t# ( 類 → 類 ) CJK COMPATIBILITY IDEOGRAPH-F9D0 → CJK UNIFIED IDEOGRAPH-985E\t# \n\n2FB5 ;\t98A8 ;\tMA\t#* ( ⾵ → 風 ) KANGXI RADICAL WIND → CJK UNIFIED IDEOGRAPH-98A8\t# \n\n2EDB ;\t98CE ;\tMA\t#* ( ⻛ → 风 ) CJK RADICAL C-SIMPLIFIED WIND → CJK UNIFIED IDEOGRAPH-98CE\t# \n\n2FA01 ;\t295B6 ;\tMA\t# ( 𩖶 → 𩖶 ) CJK COMPATIBILITY IDEOGRAPH-2FA01 → CJK UNIFIED IDEOGRAPH-295B6\t# \n\n2FB6 ;\t98DB ;\tMA\t#* ( ⾶ → 飛 ) KANGXI RADICAL FLY → CJK UNIFIED IDEOGRAPH-98DB\t# \n\n2EDC ;\t98DE ;\tMA\t#* ( ⻜ → 飞 ) CJK RADICAL C-SIMPLIFIED FLY → CJK UNIFIED IDEOGRAPH-98DE\t# \n\n2EDD ;\t98DF ;\tMA\t#* ( ⻝ → 食 ) CJK RADICAL EAT ONE → CJK UNIFIED IDEOGRAPH-98DF\t# \n2FB7 ;\t98DF ;\tMA\t#* ( ⾷ → 食 ) KANGXI RADICAL EAT → CJK UNIFIED IDEOGRAPH-98DF\t# \n\n2EDF ;\t98E0 ;\tMA\t#* ( ⻟ → 飠 ) CJK RADICAL EAT THREE → CJK UNIFIED IDEOGRAPH-98E0\t# \n\n2EE0 ;\t9963 ;\tMA\t#* ( ⻠ → 饣 ) CJK RADICAL C-SIMPLIFIED EAT → CJK UNIFIED IDEOGRAPH-9963\t# \n\n2FA02 ;\t98E2 ;\tMA\t# ( 飢 → 飢 ) CJK COMPATIBILITY IDEOGRAPH-2FA02 → CJK UNIFIED IDEOGRAPH-98E2\t# \n\nFA2A ;\t98EF ;\tMA\t# ( 飯 → 飯 ) CJK COMPATIBILITY IDEOGRAPH-FA2A → CJK UNIFIED IDEOGRAPH-98EF\t# \n\nFA2B ;\t98FC ;\tMA\t# ( 飼 → 飼 ) CJK COMPATIBILITY IDEOGRAPH-FA2B → CJK UNIFIED IDEOGRAPH-98FC\t# \n\n2FA03 ;\t4B33 ;\tMA\t# ( 䬳 → 䬳 ) CJK COMPATIBILITY IDEOGRAPH-2FA03 → CJK UNIFIED IDEOGRAPH-4B33\t# \n\nFA2C ;\t9928 ;\tMA\t# ( 館 → 館 ) CJK COMPATIBILITY IDEOGRAPH-FA2C → CJK UNIFIED IDEOGRAPH-9928\t# \n\n2FA04 ;\t9929 ;\tMA\t# ( 餩 → 餩 ) CJK COMPATIBILITY IDEOGRAPH-2FA04 → CJK UNIFIED IDEOGRAPH-9929\t# \n\n2FB8 ;\t9996 ;\tMA\t#* ( ⾸ → 首 ) KANGXI RADICAL HEAD → CJK UNIFIED IDEOGRAPH-9996\t# \n\n2FB9 ;\t9999 ;\tMA\t#* ( ⾹ → 香 ) KANGXI RADICAL FRAGRANT → CJK UNIFIED IDEOGRAPH-9999\t# \n\n2FA05 ;\t99A7 ;\tMA\t# ( 馧 → 馧 ) CJK COMPATIBILITY IDEOGRAPH-2FA05 → CJK UNIFIED IDEOGRAPH-99A7\t# \n\n2FBA ;\t99AC ;\tMA\t#* ( ⾺ → 馬 ) KANGXI RADICAL HORSE → CJK UNIFIED IDEOGRAPH-99AC\t# \n\n2EE2 ;\t9A6C ;\tMA\t#* ( ⻢ → 马 ) CJK RADICAL C-SIMPLIFIED HORSE → CJK UNIFIED IDEOGRAPH-9A6C\t# \n\n2FA06 ;\t99C2 ;\tMA\t# ( 駂 → 駂 ) CJK COMPATIBILITY IDEOGRAPH-2FA06 → CJK UNIFIED IDEOGRAPH-99C2\t# \n\nF91A ;\t99F1 ;\tMA\t# ( 駱 → 駱 ) CJK COMPATIBILITY IDEOGRAPH-F91A → CJK UNIFIED IDEOGRAPH-99F1\t# \n\n2FA07 ;\t99FE ;\tMA\t# ( 駾 → 駾 ) CJK COMPATIBILITY IDEOGRAPH-2FA07 → CJK UNIFIED IDEOGRAPH-99FE\t# \n\nF987 ;\t9A6A ;\tMA\t# ( 驪 → 驪 ) CJK COMPATIBILITY IDEOGRAPH-F987 → CJK UNIFIED IDEOGRAPH-9A6A\t# \n\n2FBB ;\t9AA8 ;\tMA\t#* ( ⾻ → 骨 ) KANGXI RADICAL BONE → CJK UNIFIED IDEOGRAPH-9AA8\t# \n\n2FA08 ;\t4BCE ;\tMA\t# ( 䯎 → 䯎 ) CJK COMPATIBILITY IDEOGRAPH-2FA08 → CJK UNIFIED IDEOGRAPH-4BCE\t# \n\n2FBC ;\t9AD8 ;\tMA\t#* ( ⾼ → 高 ) KANGXI RADICAL TALL → CJK UNIFIED IDEOGRAPH-9AD8\t# \n\n2FBD ;\t9ADF ;\tMA\t#* ( ⾽ → 髟 ) KANGXI RADICAL HAIR → CJK UNIFIED IDEOGRAPH-9ADF\t# \n\n2FA09 ;\t29B30 ;\tMA\t# ( 𩬰 → 𩬰 ) CJK COMPATIBILITY IDEOGRAPH-2FA09 → CJK UNIFIED IDEOGRAPH-29B30\t# \n\nFACD ;\t9B12 ;\tMA\t# ( 鬒 → 鬒 ) CJK COMPATIBILITY IDEOGRAPH-FACD → CJK UNIFIED IDEOGRAPH-9B12\t# \n2FA0A ;\t9B12 ;\tMA\t# ( 鬒 → 鬒 ) CJK COMPATIBILITY IDEOGRAPH-2FA0A → CJK UNIFIED IDEOGRAPH-9B12\t# \n\n2FBE ;\t9B25 ;\tMA\t#* ( ⾾ → 鬥 ) KANGXI RADICAL FIGHT → CJK UNIFIED IDEOGRAPH-9B25\t# \n\n2FBF ;\t9B2F ;\tMA\t#* ( ⾿ → 鬯 ) KANGXI RADICAL SACRIFICIAL WINE → CJK UNIFIED IDEOGRAPH-9B2F\t# \n\n2FC0 ;\t9B32 ;\tMA\t#* ( ⿀ → 鬲 ) KANGXI RADICAL CAULDRON → CJK UNIFIED IDEOGRAPH-9B32\t# \n\n2FC1 ;\t9B3C ;\tMA\t#* ( ⿁ → 鬼 ) KANGXI RADICAL GHOST → CJK UNIFIED IDEOGRAPH-9B3C\t# \n2EE4 ;\t9B3C ;\tMA\t#* ( ⻤ → 鬼 ) CJK RADICAL GHOST → CJK UNIFIED IDEOGRAPH-9B3C\t# \n\n2FC2 ;\t9B5A ;\tMA\t#* ( ⿂ → 魚 ) KANGXI RADICAL FISH → CJK UNIFIED IDEOGRAPH-9B5A\t# \n\n2EE5 ;\t9C7C ;\tMA\t#* ( ⻥ → 鱼 ) CJK RADICAL C-SIMPLIFIED FISH → CJK UNIFIED IDEOGRAPH-9C7C\t# \n\nF939 ;\t9B6F ;\tMA\t# ( 魯 → 魯 ) CJK COMPATIBILITY IDEOGRAPH-F939 → CJK UNIFIED IDEOGRAPH-9B6F\t# \n\n2FA0B ;\t9C40 ;\tMA\t# ( 鱀 → 鱀 ) CJK COMPATIBILITY IDEOGRAPH-2FA0B → CJK UNIFIED IDEOGRAPH-9C40\t# \n\nF9F2 ;\t9C57 ;\tMA\t# ( 鱗 → 鱗 ) CJK COMPATIBILITY IDEOGRAPH-F9F2 → CJK UNIFIED IDEOGRAPH-9C57\t# \n\n2FC3 ;\t9CE5 ;\tMA\t#* ( ⿃ → 鳥 ) KANGXI RADICAL BIRD → CJK UNIFIED IDEOGRAPH-9CE5\t# \n\n2FA0C ;\t9CFD ;\tMA\t# ( 鳽 → 鳽 ) CJK COMPATIBILITY IDEOGRAPH-2FA0C → CJK UNIFIED IDEOGRAPH-9CFD\t# \n\n2FA0D ;\t4CCE ;\tMA\t# ( 䳎 → 䳎 ) CJK COMPATIBILITY IDEOGRAPH-2FA0D → CJK UNIFIED IDEOGRAPH-4CCE\t# \n\n9E43 ;\t9E42 ;\tMA\t# ( 鹃 → 鹂 ) CJK UNIFIED IDEOGRAPH-9E43 → CJK UNIFIED IDEOGRAPH-9E42\t# \n\n2FA0F ;\t9D67 ;\tMA\t# ( 鵧 → 鵧 ) CJK COMPATIBILITY IDEOGRAPH-2FA0F → CJK UNIFIED IDEOGRAPH-9D67\t# \n\n2FA0E ;\t4CED ;\tMA\t# ( 䳭 → 䳭 ) CJK COMPATIBILITY IDEOGRAPH-2FA0E → CJK UNIFIED IDEOGRAPH-4CED\t# \n\n2FA10 ;\t2A0CE ;\tMA\t# ( 𪃎 → 𪃎 ) CJK COMPATIBILITY IDEOGRAPH-2FA10 → CJK UNIFIED IDEOGRAPH-2A0CE\t# \n\nFA2D ;\t9DB4 ;\tMA\t# ( 鶴 → 鶴 ) CJK COMPATIBILITY IDEOGRAPH-FA2D → CJK UNIFIED IDEOGRAPH-9DB4\t# \n\n2FA12 ;\t2A105 ;\tMA\t# ( 𪄅 → 𪄅 ) CJK COMPATIBILITY IDEOGRAPH-2FA12 → CJK UNIFIED IDEOGRAPH-2A105\t# \n\n2FA11 ;\t4CF8 ;\tMA\t# ( 䳸 → 䳸 ) CJK COMPATIBILITY IDEOGRAPH-2FA11 → CJK UNIFIED IDEOGRAPH-4CF8\t# \n\nF93A ;\t9DFA ;\tMA\t# ( 鷺 → 鷺 ) CJK COMPATIBILITY IDEOGRAPH-F93A → CJK UNIFIED IDEOGRAPH-9DFA\t# \n\n2FA13 ;\t2A20E ;\tMA\t# ( 𪈎 → 𪈎 ) CJK COMPATIBILITY IDEOGRAPH-2FA13 → CJK UNIFIED IDEOGRAPH-2A20E\t# \n\nF920 ;\t9E1E ;\tMA\t# ( 鸞 → 鸞 ) CJK COMPATIBILITY IDEOGRAPH-F920 → CJK UNIFIED IDEOGRAPH-9E1E\t# \n\n2FC4 ;\t9E75 ;\tMA\t#* ( ⿄ → 鹵 ) KANGXI RADICAL SALT → CJK UNIFIED IDEOGRAPH-9E75\t# \n\nF940 ;\t9E7F ;\tMA\t# ( 鹿 → 鹿 ) CJK COMPATIBILITY IDEOGRAPH-F940 → CJK UNIFIED IDEOGRAPH-9E7F\t# \n2FC5 ;\t9E7F ;\tMA\t#* ( ⿅ → 鹿 ) KANGXI RADICAL DEER → CJK UNIFIED IDEOGRAPH-9E7F\t# \n\n2FA14 ;\t2A291 ;\tMA\t# ( 𪊑 → 𪊑 ) CJK COMPATIBILITY IDEOGRAPH-2FA14 → CJK UNIFIED IDEOGRAPH-2A291\t# \n\nF988 ;\t9E97 ;\tMA\t# ( 麗 → 麗 ) CJK COMPATIBILITY IDEOGRAPH-F988 → CJK UNIFIED IDEOGRAPH-9E97\t# \n\nF9F3 ;\t9E9F ;\tMA\t# ( 麟 → 麟 ) CJK COMPATIBILITY IDEOGRAPH-F9F3 → CJK UNIFIED IDEOGRAPH-9E9F\t# \n\n2FC6 ;\t9EA5 ;\tMA\t#* ( ⿆ → 麥 ) KANGXI RADICAL WHEAT → CJK UNIFIED IDEOGRAPH-9EA5\t# \n\n2EE8 ;\t9EA6 ;\tMA\t#* ( ⻨ → 麦 ) CJK RADICAL SIMPLIFIED WHEAT → CJK UNIFIED IDEOGRAPH-9EA6\t# \n\n2FA15 ;\t9EBB ;\tMA\t# ( 麻 → 麻 ) CJK COMPATIBILITY IDEOGRAPH-2FA15 → CJK UNIFIED IDEOGRAPH-9EBB\t# \n2FC7 ;\t9EBB ;\tMA\t#* ( ⿇ → 麻 ) KANGXI RADICAL HEMP → CJK UNIFIED IDEOGRAPH-9EBB\t# \n\n2F88F ;\t2A392 ;\tMA\t# ( 𪎒 → 𪎒 ) CJK COMPATIBILITY IDEOGRAPH-2F88F → CJK UNIFIED IDEOGRAPH-2A392\t# \n\n2FC8 ;\t9EC3 ;\tMA\t#* ( ⿈ → 黃 ) KANGXI RADICAL YELLOW → CJK UNIFIED IDEOGRAPH-9EC3\t# \n\n2EE9 ;\t9EC4 ;\tMA\t#* ( ⻩ → 黄 ) CJK RADICAL SIMPLIFIED YELLOW → CJK UNIFIED IDEOGRAPH-9EC4\t# \n\n2FC9 ;\t9ECD ;\tMA\t#* ( ⿉ → 黍 ) KANGXI RADICAL MILLET → CJK UNIFIED IDEOGRAPH-9ECD\t# \n\nF989 ;\t9ECE ;\tMA\t# ( 黎 → 黎 ) CJK COMPATIBILITY IDEOGRAPH-F989 → CJK UNIFIED IDEOGRAPH-9ECE\t# \n\n2FA16 ;\t4D56 ;\tMA\t# ( 䵖 → 䵖 ) CJK COMPATIBILITY IDEOGRAPH-2FA16 → CJK UNIFIED IDEOGRAPH-4D56\t# \n\n2FCA ;\t9ED1 ;\tMA\t#* ( ⿊ → 黑 ) KANGXI RADICAL BLACK → CJK UNIFIED IDEOGRAPH-9ED1\t# \n9ED2 ;\t9ED1 ;\tMA\t# ( 黒 → 黑 ) CJK UNIFIED IDEOGRAPH-9ED2 → CJK UNIFIED IDEOGRAPH-9ED1\t# →⿊→\n\nFA3A ;\t58A8 ;\tMA\t# ( 墨 → 墨 ) CJK COMPATIBILITY IDEOGRAPH-FA3A → CJK UNIFIED IDEOGRAPH-58A8\t# \n\n2FA17 ;\t9EF9 ;\tMA\t# ( 黹 → 黹 ) CJK COMPATIBILITY IDEOGRAPH-2FA17 → CJK UNIFIED IDEOGRAPH-9EF9\t# \n2FCB ;\t9EF9 ;\tMA\t#* ( ⿋ → 黹 ) KANGXI RADICAL EMBROIDERY → CJK UNIFIED IDEOGRAPH-9EF9\t# \n\n2FCC ;\t9EFD ;\tMA\t#* ( ⿌ → 黽 ) KANGXI RADICAL FROG → CJK UNIFIED IDEOGRAPH-9EFD\t# \n\n2FA18 ;\t9EFE ;\tMA\t# ( 黾 → 黾 ) CJK COMPATIBILITY IDEOGRAPH-2FA18 → CJK UNIFIED IDEOGRAPH-9EFE\t# \n\n2FA19 ;\t9F05 ;\tMA\t# ( 鼅 → 鼅 ) CJK COMPATIBILITY IDEOGRAPH-2FA19 → CJK UNIFIED IDEOGRAPH-9F05\t# \n\n2FCD ;\t9F0E ;\tMA\t#* ( ⿍ → 鼎 ) KANGXI RADICAL TRIPOD → CJK UNIFIED IDEOGRAPH-9F0E\t# \n\n2FA1A ;\t9F0F ;\tMA\t# ( 鼏 → 鼏 ) CJK COMPATIBILITY IDEOGRAPH-2FA1A → CJK UNIFIED IDEOGRAPH-9F0F\t# \n\n2FCE ;\t9F13 ;\tMA\t#* ( ⿎ → 鼓 ) KANGXI RADICAL DRUM → CJK UNIFIED IDEOGRAPH-9F13\t# \n\n2FA1B ;\t9F16 ;\tMA\t# ( 鼖 → 鼖 ) CJK COMPATIBILITY IDEOGRAPH-2FA1B → CJK UNIFIED IDEOGRAPH-9F16\t# \n\n2FCF ;\t9F20 ;\tMA\t#* ( ⿏ → 鼠 ) KANGXI RADICAL RAT → CJK UNIFIED IDEOGRAPH-9F20\t# \n\n2FA1C ;\t9F3B ;\tMA\t# ( 鼻 → 鼻 ) CJK COMPATIBILITY IDEOGRAPH-2FA1C → CJK UNIFIED IDEOGRAPH-9F3B\t# \n2FD0 ;\t9F3B ;\tMA\t#* ( ⿐ → 鼻 ) KANGXI RADICAL NOSE → CJK UNIFIED IDEOGRAPH-9F3B\t# \n\nFAD8 ;\t9F43 ;\tMA\t# ( 齃 → 齃 ) CJK COMPATIBILITY IDEOGRAPH-FAD8 → CJK UNIFIED IDEOGRAPH-9F43\t# \n\n2FD1 ;\t9F4A ;\tMA\t#* ( ⿑ → 齊 ) KANGXI RADICAL EVEN → CJK UNIFIED IDEOGRAPH-9F4A\t# \n\n2EEC ;\t9F50 ;\tMA\t#* ( ⻬ → 齐 ) CJK RADICAL C-SIMPLIFIED EVEN → CJK UNIFIED IDEOGRAPH-9F50\t# \n\n2FD2 ;\t9F52 ;\tMA\t#* ( ⿒ → 齒 ) KANGXI RADICAL TOOTH → CJK UNIFIED IDEOGRAPH-9F52\t# \n\n2EEE ;\t9F7F ;\tMA\t#* ( ⻮ → 齿 ) CJK RADICAL C-SIMPLIFIED TOOTH → CJK UNIFIED IDEOGRAPH-9F7F\t# \n\n2FA1D ;\t2A600 ;\tMA\t# ( 𪘀 → 𪘀 ) CJK COMPATIBILITY IDEOGRAPH-2FA1D → CJK UNIFIED IDEOGRAPH-2A600\t# \n\nF9C4 ;\t9F8D ;\tMA\t# ( 龍 → 龍 ) CJK COMPATIBILITY IDEOGRAPH-F9C4 → CJK UNIFIED IDEOGRAPH-9F8D\t# \n2FD3 ;\t9F8D ;\tMA\t#* ( ⿓ → 龍 ) KANGXI RADICAL DRAGON → CJK UNIFIED IDEOGRAPH-9F8D\t# \n\n2EF0 ;\t9F99 ;\tMA\t#* ( ⻰ → 龙 ) CJK RADICAL C-SIMPLIFIED DRAGON → CJK UNIFIED IDEOGRAPH-9F99\t# \n\nFAD9 ;\t9F8E ;\tMA\t# ( 龎 → 龎 ) CJK COMPATIBILITY IDEOGRAPH-FAD9 → CJK UNIFIED IDEOGRAPH-9F8E\t# \n\nF907 ;\t9F9C ;\tMA\t# ( 龜 → 龜 ) CJK COMPATIBILITY IDEOGRAPH-F907 → CJK UNIFIED IDEOGRAPH-9F9C\t# \nF908 ;\t9F9C ;\tMA\t# ( 龜 → 龜 ) CJK COMPATIBILITY IDEOGRAPH-F908 → CJK UNIFIED IDEOGRAPH-9F9C\t# \nFACE ;\t9F9C ;\tMA\t# ( 龜 → 龜 ) CJK COMPATIBILITY IDEOGRAPH-FACE → CJK UNIFIED IDEOGRAPH-9F9C\t# \n2FD4 ;\t9F9C ;\tMA\t#* ( ⿔ → 龜 ) KANGXI RADICAL TURTLE → CJK UNIFIED IDEOGRAPH-9F9C\t# \n\n2EF3 ;\t9F9F ;\tMA\t#* ( ⻳ → 龟 ) CJK RADICAL C-SIMPLIFIED TURTLE → CJK UNIFIED IDEOGRAPH-9F9F\t# \n\n2FD5 ;\t9FA0 ;\tMA\t#* ( ⿕ → 龠 ) KANGXI RADICAL FLUTE → CJK UNIFIED IDEOGRAPH-9FA0\t# \n\n0CDC ;\t0C5C ;\tMA\t# ( ೜ → ౜ ) KANNADA ARCHAIC SHRII → TELUGU ARCHAIC SHRII\t# \n\n1DE8 ;\t1ADA ;\tMA\t# ( ᷨ → ᫚ ) COMBINING LATIN SMALL LETTER B → COMBINING FLAT SIGN\t# \n\n2DEE ;\t1ADB ;\tMA\t# ( ⷮ → ᫛ ) COMBINING CYRILLIC LETTER TE → COMBINING DOWN TACK ABOVE\t# \n\n1AE7 ;\t1AE5 ;\tMA\t# ( ᫧ → ᫥ ) COMBINING DOUBLE ARCH ABOVE → COMBINING SEAGULL ABOVE\t# \n\n031A ;\t1AE9 ;\tMA\t# ( ̚ → ᫩ ) COMBINING LEFT ANGLE ABOVE → COMBINING LEFT ANGLE CENTRED ABOVE\t# \n\n0295 ;\tA7CE ;\tMA\t# ( ʕ → ꟎ ) LATIN LETTER PHARYNGEAL VOICED FRICATIVE → LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE\t# \nA7CF ;\tA7CE ;\tMA\t# ( ꟏ → ꟎ ) LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE → LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE\t# →ʕ→\n\n0348 ;\t10EFA ;\tMA\t# ( ͈ → 𐻺 ) COMBINING DOUBLE VERTICAL LINE BELOW → ARABIC DOUBLE VERTICAL BAR BELOW\t# \n\n0956 ;\t11B62 ;\tMA\t# ( ॖ → 𑭢 ) DEVANAGARI VOWEL SIGN UE → SHARADA VOWEL SIGN UE\t# \n0A41 ;\t11B62 ;\tMA\t# ( ੁ → 𑭢 ) GURMUKHI VOWEL SIGN U → SHARADA VOWEL SIGN UE\t# →ॖ→\n\n0957 ;\t11B63 ;\tMA\t# ( ॗ → 𑭣 ) DEVANAGARI VOWEL SIGN UUE → SHARADA VOWEL SIGN UUE\t# \n0A42 ;\t11B63 ;\tMA\t# ( ੂ → 𑭣 ) GURMUKHI VOWEL SIGN UU → SHARADA VOWEL SIGN UUE\t# →ॗ→\n\n0947 ;\t11B64 ;\tMA\t# ( े → 𑭤 ) DEVANAGARI VOWEL SIGN E → SHARADA VOWEL SIGN SHORT E\t# \n0A47 ;\t11B64 ;\tMA\t# ( ੇ → 𑭤 ) GURMUKHI VOWEL SIGN EE → SHARADA VOWEL SIGN SHORT E\t# →े→\n\n5152 ;\t16FF3 ;\tMA\t# ( 兒 → 𖿳 ) CJK UNIFIED IDEOGRAPH-5152 → CHINESE SMALL TRADITIONAL ER\t# \n\n1F40D ;\t1CCFA ;\tMA\t#* ( 🐍 → 𜳺 ) SNAKE → SNAKE SYMBOL\t# \n\n1F443 ;\t1CCFC ;\tMA\t#* ( 👃 → 𜳼 ) NOSE → NOSE SYMBOL\t# \n\n1F377 ;\t1CEBA ;\tMA\t#* ( 🍷 → 𜺺 ) WINE GLASS → FRAGILE SYMBOL\t# \n\n1F3E2 ;\t1CEBB ;\tMA\t#* ( 🏢 → 𜺻 ) OFFICE BUILDING → OFFICE BUILDING SYMBOL\t# \n\n1F333 ;\t1CEBC ;\tMA\t#* ( 🌳 → 𜺼 ) DECIDUOUS TREE → TREE SYMBOL\t# \n\n1F34E ;\t1CEBD ;\tMA\t#* ( 🍎 → 𜺽 ) RED APPLE → APPLE SYMBOL\t# \n1F34F ;\t1CEBD ;\tMA\t#* ( 🍏 → 𜺽 ) GREEN APPLE → APPLE SYMBOL\t# \n\n1F352 ;\t1CEBE ;\tMA\t#* ( 🍒 → 𜺾 ) CHERRIES → CHERRY SYMBOL\t# \n\n1F353 ;\t1CEBF ;\tMA\t#* ( 🍓 → 𜺿 ) STRAWBERRY → STRAWBERRY SYMBOL\t# \n\n28FF ;\t1CEE0 ;\tMA\t#* ( ⣿ → 𜻠 ) BRAILLE PATTERN DOTS-12345678 → GEOMANTIC FIGURE POPULUS\t# \n\n29B5 ;\t1CEF0 ;\tMA\t#* ( ⦵ → 𜻰 ) CIRCLE WITH HORIZONTAL BAR → MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR\t# \n\n21C4 ;\t1F8D0 ;\tMA\t#* ( ⇄ → 🣐 ) RIGHTWARDS ARROW OVER LEFTWARDS ARROW → LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW\t# \n\n21CC ;\t1F8D1 ;\tMA\t#* ( ⇌ → 🣑 ) RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON → LONG RIGHTWARDS HARPOON OVER LONG LEFTWARDS HARPOON\t# \n\n2657 ;\t1FA55 ;\tMA\t#* ( ♗ → 🩕 ) WHITE CHESS BISHOP → WHITE CHESS ALFIL\t# \n\n265D ;\t1FA57 ;\tMA\t#* ( ♝ → 🩗 ) BLACK CHESS BISHOP → BLACK CHESS ALFIL\t# \n\n1F514 ;\t1FBFA ;\tMA\t#* ( 🔔 → 🯺 ) BELL → ALARM BELL SYMBOL\t# \n\n6138 ;\t2B73F ;\tMA\t# ( 愸 → 𫜿 ) CJK UNIFIED IDEOGRAPH-6138 → CJK UNIFIED IDEOGRAPH-2B73F\t# \n\n# total: 6565\n\n"
  },
  {
    "path": "lib/elixir/unicode/security.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule String.Tokenizer.Security do\n  @moduledoc false\n\n  # UTS39 security checks that operate on all tokens in a file,\n  # like Confusables. If we add whole-file mixed-script-confusable-characters\n  # checks we can add them to the list of lints here\n  def unicode_lint_warnings(tokens) do\n    for warning <- confusables(tokens),\n        do: format_warning(warning)\n  end\n\n  defp format_warning({token, reason}) do\n    {_, {line, col, _}, _} = token\n    {{line, col}, to_charlist(reason)}\n  end\n\n  ## Confusables\n\n  defp confusables(tokens) do\n    {_, warnings} =\n      for token <- tokens, reduce: {%{}, []} do\n        {skeletons, warnings} ->\n          case check_token_for_confusability(token, skeletons) do\n            {:ok, skeletons} -> {skeletons, warnings}\n            {:warn, reason} -> {skeletons, [{token, reason} | warnings]}\n          end\n      end\n\n    warnings\n  end\n\n  @identifiers [\n    :identifier,\n    :op_identifier,\n    :kw_identifier,\n    :paren_identifier,\n    :bracket_identifier,\n    :alias,\n    :atom\n  ]\n\n  defp check_token_for_confusability(\n         {kind, {_line, _column, [_ | _] = name} = info, _},\n         skeletons\n       )\n       when kind in @identifiers do\n    skeleton = confusable_skeleton(name)\n\n    case skeletons[skeleton] do\n      {_, _, ^name} ->\n        {:ok, skeletons}\n\n      {line, _, previous_name} when name != previous_name ->\n        {:warn,\n         \"confusable identifier: '#{name}' looks like '#{previous_name}' on line #{line}, \" <>\n           \"but they are written using different characters\" <> dir_compare(name, previous_name)}\n\n      _ ->\n        {:ok, Map.put(skeletons, skeleton, info)}\n    end\n  end\n\n  defp check_token_for_confusability(_token, skeletons), do: {:ok, skeletons}\n\n  # AAAA ;   BBBB CCCC DDDDD ;\n  # ^ char   ^ prototypical char or sequence of chars it can be confused with\n  confusables_path = \"confusables.txt\"\n\n  lines =\n    Path.join(__DIR__, confusables_path)\n    |> File.read!()\n    |> String.split([\"\\r\\n\", \"\\n\"], trim: true)\n\n  regex = ~r/^((?:[0-9A-F]+ )+);\\t((?:[0-9A-F]+ )+);/u\n  matches = Enum.map(lines, &Regex.run(regex, &1, capture: :all_but_first))\n\n  confusable_prototype_lookup =\n    for [confusable_str, prototype_str] <- matches, reduce: %{} do\n      acc ->\n        confusable = String.to_integer(String.trim(confusable_str), 16)\n\n        if Map.has_key?(acc, confusable) or\n             confusable in ?A..?Z or confusable in ?a..?z or confusable in ?0..?9 do\n          acc\n        else\n          prototype =\n            prototype_str\n            |> String.split(\" \", trim: true)\n            |> Enum.map(&String.to_integer(&1, 16))\n\n          Map.put(acc, confusable, prototype)\n        end\n    end\n\n  for {confusable, prototype} <- confusable_prototype_lookup do\n    defp confusable_prototype(unquote(confusable)) do\n      unquote(prototype)\n    end\n  end\n\n  defp confusable_prototype(other), do: <<other::utf8>>\n\n  def confusable_skeleton(s) do\n    # \"- Convert X to NFD format, as described in [UAX15].\n    #  - Concatenate the prototypes for each character in X according to\n    #    the specified data, producing a string of exemplar characters.\n    #  - Reapply NFD.\" (UTS 39 section 4, skeleton definition)\n    :unicode.characters_to_nfd_list(s)\n    |> bidi_skeleton()\n    |> :unicode.characters_to_nfd_list()\n  end\n\n  # Unicode 15 adds bidiSkeleton because, w/RTL codepoints, idents that\n  # aren't confusable LTR *are* confusable in most places human review\n  # occurs (editors/browsers, thanks to bidi algo, UAX9).\n  #\n  # The solution is to detect spans with reversed visual direction,\n  # and reverse those, so that the input we check for confusability\n  # matches the perceived sequence instead of the byte sequence.\n  #\n  # (we need this regardless of script mixing, because direction-neutral\n  # chars like _ or 0..9 can mix w/RTL chars).\n  def bidi_skeleton(s) do\n    # UTS39-28 4:\n    #\n    # Bidirectional confusability is costlier to check than\n    # confusability, as [unicode bidi algo] must be applied.\n    # [...] a fast path can be used: [...] if X has no characters\n    # w/bidi classes R or AL, bidiSkeleton(X) = skeleton(X)\n    if match?([_, _ | _], s) and any_rtl?(s) do\n      unbidify(s) |> Enum.map(&confusable_prototype/1)\n    else\n      Enum.map(s, &confusable_prototype/1)\n    end\n  end\n\n  defp any_rtl?(s), do: Enum.any?(s, &(:rtl == String.Tokenizer.dir(&1)))\n\n  defp dir_compare(a, b) do\n    \"\"\"\n    #{if any_rtl?(a), do: \"\\n\\n\" <> dir_breakdown(a)}\n    #{if any_rtl?(b), do: dir_breakdown(b)}\n    \"\"\"\n  end\n\n  defp dir_breakdown(s) do\n    init = \"'#{s}' includes right-to-left characters:\\n\"\n\n    init <>\n      for codepoint <- s, into: \"\" do\n        hex = :io_lib.format(~c\"~4.16.0B\", [codepoint])\n        \"  \\\\u#{hex} #{[codepoint]} #{String.Tokenizer.dir(codepoint)}\\n\"\n      end\n  end\n\n  # make charlist match visual order by reversing spans of {rtl, neutral}\n  # and attaching neutral characters and weak number types according to uax9\n  #\n  #  UTS39-28 4: '[...] if the strings are known not to contain explicit\n  #   directional formatting characters[...], the algorithm can\n  #   be drastically simplified, [...], obviating the need for\n  #   the [...] stack of the [unicode bidi algo]'\n  def unbidify(chars) when is_list(chars) do\n    {neutrals, direction, last_part, acc} =\n      Enum.reduce(chars, {[], :ltr, [], []}, fn head, {neutrals, part_dir, part, acc} ->\n        # https://www.unicode.org/reports/tr9/#W2\n        case String.Tokenizer.dir(head) do\n          :weak_number ->\n            {[], part_dir, [head] ++ neutrals ++ part, acc}\n\n          :neutral ->\n            {[head | neutrals], part_dir, part, acc}\n\n          ^part_dir ->\n            {[], part_dir, [head | neutrals] ++ part, acc}\n\n          :ltr when part_dir == :rtl ->\n            {[], :ltr, [head | neutrals], Enum.reverse(part, acc)}\n\n          :rtl when part_dir == :ltr ->\n            {[], :rtl, [head], neutrals ++ part ++ acc}\n        end\n      end)\n\n    case direction do\n      :ltr -> Enum.reverse(acc, Enum.reverse(neutrals ++ last_part))\n      :rtl -> Enum.reverse(acc, neutrals ++ last_part)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/unicode/tokenizer.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule String.Tokenizer do\n  @moduledoc false\n\n  ## Custom normalization definitions\n  #\n  # These codepoints will be normalized from => to, and their\n  # scriptset will be the union of both. If one of the two\n  # codepoints is Script='Common|Inherited', this means both\n  # codepoints can be used anywhere without unsafe script mixing;\n  # similarly, they are exempted from the Restricted list.\n  #\n  start_normalizations = %{\n    # NFKC-based automatic normalizations\n    # U+00B5 => U+03BC\n    ?µ => ?μ\n  }\n\n  normalizations = start_normalizations\n\n  ##\n  ## First let's load all characters that we will allow in identifiers\n  ##\n\n  range_to_codepoints = fn range ->\n    case :binary.split(String.trim(range), \"..\") do\n      [a] -> [String.to_integer(a, 16)]\n      [a, b] -> Enum.to_list(String.to_integer(a, 16)..String.to_integer(b, 16))\n    end\n  end\n\n  {letter_uptitlecase, start, continue, dir_rtls, dir_neutrals, _} =\n    Path.join(__DIR__, \"UnicodeData.txt\")\n    |> File.read!()\n    |> String.split([\"\\r\\n\", \"\\n\"], trim: true)\n    |> Enum.reduce({[], [], [], [], [], nil}, fn line, acc ->\n      {letter_uptitlecase, start, continue, rtls, neutrals, first} = acc\n\n      # https://www.unicode.org/reports/tr44/tr44-32.html#UnicodeData.txt\n      [codepoint, line] = :binary.split(line, \";\")\n      [name, line] = :binary.split(line, \";\")\n      [category, line] = :binary.split(line, \";\")\n      [_canonical_combining, line] = :binary.split(line, \";\")\n      [bidi, _] = :binary.split(line, \";\")\n\n      {codepoints, first} =\n        case name do\n          \"<\" <> _ when is_integer(first) ->\n            last = String.to_integer(codepoint, 16)\n            {Enum.to_list(last..first//-1), nil}\n\n          \"<\" <> _ ->\n            first = String.to_integer(codepoint, 16)\n            {[first], first + 1}\n\n          _ ->\n            {[String.to_integer(codepoint, 16)], nil}\n        end\n\n      {rtls, neutrals} =\n        cond do\n          bidi in ~w(R AL)s -> {codepoints ++ rtls, neutrals}\n          bidi in ~w(WS ON CS EN ES ET NSM)s -> {rtls, codepoints ++ neutrals}\n          true -> {rtls, neutrals}\n        end\n\n      cond do\n        category in ~w(Lu Lt) ->\n          {codepoints ++ letter_uptitlecase, start, continue, rtls, neutrals, first}\n\n        category in ~w(Ll Lm Lo Nl) ->\n          {letter_uptitlecase, codepoints ++ start, continue, rtls, neutrals, first}\n\n        category in ~w(Mn Mc Nd Pc) ->\n          {letter_uptitlecase, start, codepoints ++ continue, rtls, neutrals, first}\n\n        true ->\n          {letter_uptitlecase, start, continue, rtls, neutrals, first}\n      end\n    end)\n\n  # Each character is classified accordingly\n\n  {start, continue, patterns} =\n    Path.join(__DIR__, \"PropList.txt\")\n    |> File.read!()\n    |> String.split([\"\\r\\n\", \"\\n\"], trim: true)\n    |> Enum.reduce({start, continue, []}, fn line, acc ->\n      [range | category] = :binary.split(line, \";\")\n\n      pos =\n        case category do\n          [\" Other_ID_Start\" <> _] -> 0\n          [\" Other_ID_Continue\" <> _] -> 1\n          [\" Pattern_White_Space\" <> _] -> 2\n          [\" Pattern_Syntax\" <> _] -> 2\n          _ -> -1\n        end\n\n      if pos >= 0 do\n        put_elem(acc, pos, range_to_codepoints.(range) ++ elem(acc, pos))\n      else\n        acc\n      end\n    end)\n\n  # Also restrict characters for security purposes according to UTS 39\n\n  restricted =\n    Path.join(__DIR__, \"IdentifierType.txt\")\n    |> File.read!()\n    |> String.split([\"\\r\\n\", \"\\n\"], trim: true)\n    |> Enum.flat_map(fn line ->\n      with [range, type_with_comments] <- :binary.split(line, \";\"),\n           [types, _comments] <- :binary.split(type_with_comments, \"#\"),\n           types = String.split(types, \" \", trim: true),\n           false <- \"Inclusion\" in types or \"Recommended\" in types do\n        range_to_codepoints.(range)\n      else\n        _ -> []\n      end\n    end)\n\n  id_upper = (letter_uptitlecase -- patterns) -- restricted\n  id_start = (start -- patterns) -- restricted\n  id_continue = (continue -- patterns) -- restricted\n\n  unicode_upper = Enum.filter(id_upper, &(&1 > 127))\n  unicode_start = Enum.filter(id_start, &(&1 > 127))\n  unicode_continue = Enum.filter(id_continue, &(&1 > 127))\n\n  unicode_all = Map.from_keys(unicode_upper ++ unicode_start ++ unicode_continue, [])\n\n  IO.puts(:stderr, \"[Unicode] Tokenizing #{map_size(unicode_all)} non-ascii codepoints\")\n\n  ##\n  ## Compute scriptsets for all characters above\n  ##\n\n  # 3 text files from UAX24 (Scripts):\n  #\n  # 1. Scripts.txt               codepoint => primary script (by full name)\n  # 2. ScriptExtensions.txt      codepoint => N scripts, (by short names)\n  # 3. PropertyValueAliases.txt  short names <=> long names mapping\n\n  # First we'll build a lookup of short <=> long names, starting with\n  # names that we will make part of the highly restricted set later.\n  script_aliases =\n    Path.join(__DIR__, \"PropertyValueAliases.txt\")\n    |> File.read!()\n    |> String.split([\"\\r\\n\", \"\\n\"], trim: true)\n    |> Enum.flat_map(fn line ->\n      case String.split(line, [\";\", \" \"], trim: true) do\n        [\"sc\", short, long | _] -> [{short, long}]\n        _ -> []\n      end\n    end)\n    |> Map.new()\n\n  # Now we will compute all used scriptsets as well as\n  # a mapping from codepoint to scriptsets.\n  codepoints_to_scriptset = fn file, aliases ->\n    Path.join(__DIR__, file)\n    |> File.read!()\n    |> String.split([\"\\r\\n\", \"\\n\"], trim: true)\n    |> Enum.flat_map(fn line ->\n      with [range, scripts_with_comments] <- :binary.split(line, \";\"),\n           [scripts, _comments] <- :binary.split(scripts_with_comments, \"#\"),\n           scripts =\n             scripts |> String.split(\" \", trim: true) |> Enum.map(&Map.get(aliases, &1, &1)) do\n        for codepoint <- range_to_codepoints.(range),\n            Map.has_key?(unicode_all, codepoint) and\n              \"Common\" not in scripts and \"Inherited\" not in scripts,\n            do: {codepoint, scripts}\n      else\n        _ -> []\n      end\n    end)\n  end\n\n  scripts = codepoints_to_scriptset.(\"Scripts.txt\", %{})\n  script_extensions = codepoints_to_scriptset.(\"ScriptExtensions.txt\", script_aliases)\n  all_codepoints_to_scriptset = scripts ++ script_extensions\n\n  all_scriptsets =\n    all_codepoints_to_scriptset\n    |> Enum.flat_map(&elem(&1, 1))\n    |> Enum.uniq()\n    |> then(&([\"Han with Bopomofo\", \"Japanese\", \"Korean\"] ++ &1))\n\n  # We will represent scriptsets using a bitmap. So let's define\n  # a separate module for said operations. We will also sort the\n  # scriptsets and make Latin the first one for convenience.\n\n  defmodule ScriptSet do\n    @moduledoc false\n    def from_index(idx), do: :erlang.bsl(1, idx)\n    def lattices(size), do: {0, trunc(:math.pow(2, size)) - 1}\n    def union(left, right), do: :erlang.bor(left, right)\n\n    def to_indexes(set) do\n      for {?1, index} <- set |> Integer.to_charlist(2) |> Enum.reverse() |> Enum.with_index() do\n        index\n      end\n    end\n  end\n\n  sorted_scriptsets = [\"Latin\" | all_scriptsets |> List.delete(\"Latin\") |> Enum.sort()]\n\n  scriptset_masks =\n    sorted_scriptsets\n    |> Enum.with_index(fn scriptset, index ->\n      {scriptset, ScriptSet.from_index(index)}\n    end)\n    |> Map.new()\n\n  # Some scriptsets must be augmented according to the rules below,\n  # see https://www.unicode.org/reports/tr39/\n  #\n  # Note, however, Bopo(mofo) characters are not actually tokenized,\n  # as it is not in the list of recommended scriptsets.\n  augmentation_rules = %{\n    \"Han\" => [\"Han with Bopomofo\", \"Japanese\", \"Korean\"],\n    \"Hiragana\" => [\"Japanese\"],\n    \"Katakana\" => [\"Japanese\"],\n    \"Hangul\" => [\"Korean\"],\n    \"Bopomofo\" => [\"Han with Bopomofo\"]\n  }\n\n  scriptset_masks =\n    for {key, additions} <- augmentation_rules, reduce: scriptset_masks do\n      acc ->\n        Map.update!(acc, key, fn value ->\n          additions\n          |> Enum.map(&Map.fetch!(acc, &1))\n          |> Enum.reduce(value, &ScriptSet.union/2)\n        end)\n    end\n\n  {bottom, top} = ScriptSet.lattices(map_size(scriptset_masks))\n  IO.puts(:stderr, \"[Unicode] Tokenizing #{map_size(scriptset_masks)} scriptsets\")\n\n  codepoints_to_mask =\n    for {codepoint, scriptsets} <- all_codepoints_to_scriptset, into: %{} do\n      {codepoint,\n       scriptsets\n       |> Enum.map(&Map.fetch!(scriptset_masks, &1))\n       |> Enum.reduce(bottom, &ScriptSet.union/2)}\n    end\n\n  # Add our custom normalizations\n\n  codepoints_to_mask =\n    for {from, to} <- normalizations, reduce: codepoints_to_mask do\n      acc ->\n        ss = ScriptSet.union(Map.get(acc, from, top), Map.get(acc, to, top))\n        Map.put(acc, to, ss)\n    end\n\n  ##\n  ## Define functions and module attributes to access characters and their scriptsets\n  ##\n\n  # bottom of bitmap == all bits are 0, no scripts in the scriptset\n  @bottom bottom\n  @latin 1\n  # top of bitmap (all bits are 1) is ALL in UTS39 ('Common', 'Inherited');\n  # a scriptset that will intersect with other all non-empty scriptsets\n  @top top\n  @indexed_scriptsets sorted_scriptsets |> Enum.with_index(&{&2, &1}) |> Map.new()\n\n  # ScriptSet helpers. Inline instead of dispatching to ScriptSet for performance\n\n  @compile {:inline, ss_latin: 1, ss_intersect: 2}\n  defp ss_latin(ss), do: :erlang.band(ss, @latin)\n  defp ss_intersect(left, right), do: :erlang.band(left, right)\n\n  # Ascii helpers\n\n  @compile {:inline, ascii_upper?: 1, ascii_lower?: 1, ascii_continue?: 1}\n  defp ascii_upper?(entry), do: entry >= ?A and entry <= ?Z\n  defp ascii_lower?(entry), do: entry >= ?a and entry <= ?z\n  defp ascii_continue?(entry), do: entry >= ?0 and entry <= ?9\n\n  # Unicode helpers\n  # We use ranges whenever possible to reduce bytecode size.\n\n  unicode_upper = Enum.map(unicode_upper, &{&1, Map.get(codepoints_to_mask, &1, top)})\n  unicode_start = Enum.map(unicode_start, &{&1, Map.get(codepoints_to_mask, &1, top)})\n  unicode_continue = Enum.map(unicode_continue, &{&1, Map.get(codepoints_to_mask, &1, top)})\n\n  rangify = fn [{head, scriptset} | tail] ->\n    {first, last, scriptset, acc} =\n      Enum.reduce(tail, {head, head, scriptset, []}, fn\n        {number, scriptset}, {first, last, scriptset, acc} when number == first - 1 ->\n          {number, last, scriptset, acc}\n\n        {number, scriptset}, {first, last, range_scriptset, acc} ->\n          {number, number, scriptset, [{first, last, range_scriptset} | acc]}\n      end)\n\n    [{first, last, scriptset} | acc]\n  end\n\n  for {first, last, scriptset} <- rangify.(unicode_upper) do\n    if first == last do\n      defp unicode_upper(unquote(first)), do: unquote(scriptset)\n    else\n      defp unicode_upper(entry) when entry in unquote(first)..unquote(last),\n        do: unquote(scriptset)\n    end\n  end\n\n  defp unicode_upper(_), do: @bottom\n\n  for {first, last, scriptset} <- rangify.(unicode_start) do\n    if first == last do\n      defp unicode_start(unquote(first)), do: unquote(scriptset)\n    else\n      defp unicode_start(entry) when entry in unquote(first)..unquote(last),\n        do: unquote(scriptset)\n    end\n  end\n\n  defp unicode_start(_), do: @bottom\n\n  for {first, last, scriptset} <- rangify.(unicode_continue) do\n    if first == last do\n      defp unicode_continue(unquote(first)), do: unquote(scriptset)\n    else\n      defp unicode_continue(entry) when entry in unquote(first)..unquote(last),\n        do: unquote(scriptset)\n    end\n  end\n\n  defp unicode_continue(_), do: @bottom\n\n  # subset of direction-changing/neutral characters valid in idents\n  id_all = id_upper ++ id_start ++ id_continue\n  dir_rtls = for c <- dir_rtls, c in id_all, do: {c, :rtl}\n  dir_neutrals = for c <- dir_neutrals, c not in 48..57, c in id_all, do: {c, :neutral}\n  dir_ranges = rangify.(dir_rtls) ++ rangify.(dir_neutrals)\n\n  # direction of a codepoint. (rtl, neutral, weak, ltr fallback)\n  # weaks are pulled towards previous directional spans,\n  # but the only weaks allowed in idents are numbers 0..9\n  def dir(i) when i in 48..57, do: :weak_number\n\n  for {first, last, direction} <- dir_ranges do\n    if first == last do\n      def dir(unquote(first)), do: unquote(direction)\n    else\n      def dir(i) when i in unquote(first)..unquote(last), do: unquote(direction)\n    end\n  end\n\n  def dir(i) when is_integer(i), do: :ltr\n\n  # Hard-coded normalizations. Also split by upper, start, continue.\n\n  for {from, to} <- start_normalizations do\n    mask = Map.fetch!(codepoints_to_mask, to)\n    defp normalize_start(unquote(from)), do: {unquote(to), unquote(mask)}\n  end\n\n  defp normalize_start(_codepoint), do: @bottom\n\n  ##\n  ## Now we are ready to tokenize!\n  ##\n\n  def tokenize([head | tail]) do\n    cond do\n      ascii_upper?(head) ->\n        validate(continue(tail, [head], 1, true, @latin, []), :alias)\n\n      ascii_lower?(head) ->\n        validate(continue(tail, [head], 1, true, @latin, []), :identifier)\n\n      head == ?_ ->\n        validate(continue(tail, [head], 1, true, @top, []), :identifier)\n\n      true ->\n        case unicode_upper(head) do\n          @bottom ->\n            case unicode_start(head) do\n              @bottom ->\n                case normalize_start(head) do\n                  @bottom ->\n                    {:error, :empty}\n\n                  {head, scriptset} ->\n                    validate(continue(tail, [head], 1, false, scriptset, [:nfkc]), :identifier)\n                end\n\n              scriptset ->\n                validate(continue(tail, [head], 1, false, scriptset, []), :identifier)\n            end\n\n          scriptset ->\n            validate(continue(tail, [head], 1, false, scriptset, []), :atom)\n        end\n    end\n  end\n\n  def tokenize([]) do\n    {:error, :empty}\n  end\n\n  defp continue([?! | tail], acc, length, ascii_letters?, scriptset, special) do\n    {[?! | acc], tail, length + 1, ascii_letters?, scriptset, [:punctuation | special]}\n  end\n\n  defp continue([?? | tail], acc, length, ascii_letters?, scriptset, special) do\n    {[?? | acc], tail, length + 1, ascii_letters?, scriptset, [:punctuation | special]}\n  end\n\n  defp continue([?@ | tail], acc, length, ascii_letters?, scriptset, special) do\n    special = [:at | List.delete(special, :at)]\n    continue(tail, [?@ | acc], length + 1, ascii_letters?, scriptset, special)\n  end\n\n  defp continue([head | tail] = list, acc, length, ascii_letters?, scriptset, special) do\n    cond do\n      ascii_lower?(head) or ascii_upper?(head) ->\n        continue(tail, [head | acc], length + 1, ascii_letters?, ss_latin(scriptset), special)\n\n      head == ?_ or ascii_continue?(head) ->\n        continue(tail, [head | acc], length + 1, ascii_letters?, scriptset, special)\n\n      # Pattern is used for performance and to not mark ascii tokens as unicode\n      # ' \\\\\\t\\n\\r!\"#$%&\\'()*+,-./:;<=>?@[]^`{|}~'\n      head <= 127 ->\n        {acc, list, length, ascii_letters?, scriptset, special}\n\n      true ->\n        with @bottom <- unicode_start(head),\n             @bottom <- unicode_upper(head),\n             @bottom <- unicode_continue(head) do\n          case normalize_start(head) do\n            @bottom ->\n              {:error, {:unexpected_token, :lists.reverse([head | acc])}}\n\n            {head, ss} ->\n              ss = ss_intersect(scriptset, ss)\n              special = [:nfkc | List.delete(special, :nfkc)]\n              continue(tail, [head | acc], length + 1, false, ss, special)\n          end\n        else\n          ss ->\n            ss = ss_intersect(scriptset, ss)\n            continue(tail, [head | acc], length + 1, false, ss, special)\n        end\n    end\n  end\n\n  defp continue([], acc, length, ascii_letters?, scriptset, special) do\n    {acc, [], length, ascii_letters?, scriptset, special}\n  end\n\n  defp validate({:error, _} = error, _kind) do\n    error\n  end\n\n  defp validate({acc, rest, length, true, _scriptset, special}, kind) do\n    {kind, :lists.reverse(acc), rest, length, true, special}\n  end\n\n  defp validate({original_acc, rest, length, false, scriptset, special}, kind) do\n    original_acc = :lists.reverse(original_acc)\n    acc = :unicode.characters_to_nfc_list(original_acc)\n\n    special =\n      if original_acc == acc do\n        special\n      else\n        [:nfkc | List.delete(special, :nfkc)]\n      end\n\n    if scriptset != @bottom or chunks_single?(acc) do\n      {kind, acc, rest, length, false, special}\n    else\n      breakdown =\n        for codepoint <- acc do\n          scriptsets =\n            case codepoint_to_scriptset(codepoint) do\n              @top ->\n                \"\"\n\n              scriptset ->\n                scriptset\n                |> ScriptSet.to_indexes()\n                |> Enum.map(&Map.fetch!(@indexed_scriptsets, &1))\n                |> then(&(\" {\" <> Enum.join(&1, \",\") <> \"}\"))\n            end\n\n          hex = :io_lib.format(~c\"~4.16.0B\", [codepoint])\n          \"  \\\\u#{hex} #{[codepoint]}#{scriptsets}\\n\"\n        end\n\n      prefix = ~c\"invalid mixed-script identifier found: \"\n\n      suffix = ~c\"\"\"\n\n\n      Mixed-script identifiers are not supported for security reasons. \\\n      '#{acc}' is made of the following scripts:\\n\n      #{breakdown}\n      Characters in identifiers from different scripts must be separated \\\n      by underscore (_).\n      \"\"\"\n\n      {:error, {:mixed_script, acc, {prefix, suffix}}}\n    end\n  end\n\n  # Support script mixing via chunked identifiers (UTS 55-5's strong recommends).\n  # Each chunk in an ident like foo_bar_baz should pass checks.\n  defp chunks_single?(acc),\n    do: chunks_single?(acc, @top)\n\n  defp chunks_single?([?_ | rest], acc),\n    do: acc != @bottom and chunks_single?(rest, @top)\n\n  defp chunks_single?([head | rest], acc),\n    do: chunks_single?(rest, ss_intersect(codepoint_to_scriptset(head), acc))\n\n  defp chunks_single?([], acc),\n    do: acc != @bottom\n\n  defp codepoint_to_scriptset(head) do\n    cond do\n      ascii_lower?(head) or ascii_upper?(head) ->\n        @latin\n\n      head == ?_ or ascii_continue?(head) ->\n        @top\n\n      true ->\n        with @bottom <- unicode_start(head),\n             @bottom <- unicode_upper(head),\n             @bottom <- unicode_continue(head),\n             do: @top\n    end\n  end\nend\n"
  },
  {
    "path": "lib/elixir/unicode/unicode.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# How to update the Unicode files\n#\n# Unicode files can be found in https://www.unicode.org/Public/VERSION_NUMBER/ where\n# VERSION_NUMBER is the current Unicode version.\n#\n# 1. Replace UnicodeData.txt by copying original\n# 2. Replace PropertyValueAliases.txt by copying original\n# 3. Replace PropList.txt by copying original\n# 4. Replace ScriptExtensions.txt by copying original\n# 5. Replace Scripts.txt by copying original\n# 6. Replace SpecialCasing.txt by copying original\n# 7. Replace confusables.txt by copying original\n#    (from https://www.unicode.org/Public/security/VERSION_NUMBER/)\n# 8. Replace IdentifierType.txt by copying original\n#    (from https://www.unicode.org/Public/security/VERSION_NUMBER/)\n# 9. Update String.Unicode.version/0 and on String module docs (version and link)\n# 10. make unicode\n\ndata_path = Path.join(__DIR__, \"UnicodeData.txt\")\n\nto_binary = fn\n  \"\" ->\n    nil\n\n  codepoints ->\n    codepoints\n    |> :binary.split(\" \", [:global])\n    |> Enum.map(&<<String.to_integer(&1, 16)::utf8>>)\n    |> IO.iodata_to_binary()\nend\n\nrangify = fn [head | tail] ->\n  {first, last, acc} =\n    Enum.reduce(tail, {head, head, []}, fn\n      number, {first, last, acc} when number == first - 1 ->\n        {number, last, acc}\n\n      number, {first, last, acc} ->\n        {number, number, [{first, last} | acc]}\n    end)\n\n  [{first, last} | acc]\nend\n\n# A character is case ignorable if:\n#\n#    Word_Break(C) = MidLetter or MidNumLet or Single_Quote, or\n#    General_Category(C) = Nonspacing_Mark (Mn), Enclosing_Mark (Me), Format (Cf),\n#                          Modifier_Letter (Lm), or Modifier_Symbol (Sk).\n#\n# Word breaks are defined below based on TR29 (https://unicode.org/reports/tr29/).\n# The categories are computed later.\ncase_ignorable = [\n  0x0027,\n  0x002E,\n  0x2018,\n  0x2019,\n  0x2024,\n  0xFE52,\n  0xFF07,\n  0xFF0E,\n  0x00B7,\n  0x0387,\n  0x05F4,\n  0x2027,\n  0x003A,\n  0xFE13,\n  0xFE55,\n  0xFF1A\n]\n\nacc = {[], [], case_ignorable, [], %{}, %{}}\ncased_letter_categories = :binary.compile_pattern([\"Ll\", \"Lt\", \"Lu\"])\ncase_ignorable_categories = :binary.compile_pattern([\"Mn\", \"Me\", \"Cf\", \"Lm\", \"Sk\"])\n\n{codes, cased_letters, case_ignorable, non_breakable, decompositions, combining_classes} =\n  data_path\n  |> File.read!()\n  |> String.split([\"\\r\\n\", \"\\n\"], trim: true)\n  |> Enum.reduce(acc, fn line, {cacc, lacc, iacc, wacc, dacc, kacc} ->\n    [\n      codepoint,\n      _name,\n      category,\n      class,\n      _bidi,\n      decomposition,\n      _numeric_1,\n      _numeric_2,\n      _numeric_3,\n      _bidi_mirror,\n      _unicode_1,\n      _iso,\n      upper,\n      lower,\n      _title\n    ] = :binary.split(line, \";\", [:global])\n\n    cacc =\n      if upper != \"\" or lower != \"\" do\n        [{to_binary.(codepoint), to_binary.(upper), to_binary.(lower)} | cacc]\n      else\n        cacc\n      end\n\n    cased_letter_categories = :binary.compile_pattern([\"Ll\", \"Lt\", \"Lu\"])\n    case_ignorable_categories = :binary.compile_pattern([\"Mn\", \"Me\", \"Cf\", \"Lm\", \"Sk\"])\n\n    {lacc, iacc} =\n      cond do\n        match?({0, _}, :binary.match(category, cased_letter_categories)) ->\n          {[String.to_integer(codepoint, 16) | lacc], iacc}\n\n        match?({0, _}, :binary.match(category, case_ignorable_categories)) ->\n          {lacc, [String.to_integer(codepoint, 16) | iacc]}\n\n        true ->\n          {lacc, iacc}\n      end\n\n    wacc =\n      case decomposition do\n        \"<noBreak>\" <> _ -> [to_binary.(codepoint) | wacc]\n        _ -> wacc\n      end\n\n    dacc =\n      case decomposition do\n        # Decomposition\n        <<h, _::binary>> when h != ?< ->\n          decomposition =\n            decomposition\n            |> :binary.split(\" \", [:global])\n            |> Enum.map(&String.to_integer(&1, 16))\n\n          :maps.put(String.to_integer(codepoint, 16), decomposition, dacc)\n\n        _ ->\n          dacc\n      end\n\n    kacc =\n      case String.to_integer(class) do\n        0 -> kacc\n        n -> :maps.put(String.to_integer(codepoint, 16), n, kacc)\n      end\n\n    {cacc, lacc, iacc, wacc, dacc, kacc}\n  end)\n\ndefmodule String.Unicode do\n  @moduledoc false\n  def version, do: {17, 0, 0}\n\n  [unconditional_mappings, _conditional_mappings] =\n    Path.join(__DIR__, \"SpecialCasing.txt\")\n    |> File.read!()\n    |> :binary.split(\"# Conditional Mappings\")\n\n  codes =\n    unconditional_mappings\n    |> String.split([\"\\r\\n\", \"\\n\"], trim: true)\n    |> Enum.reduce(codes, fn\n      \"\", acc ->\n        acc\n\n      \"#\" <> _, acc ->\n        acc\n\n      line, acc ->\n        [codepoint, lower, _title, upper, _] = :binary.split(line, \"; \", [:global])\n        key = to_binary.(codepoint)\n\n        :lists.keystore(\n          key,\n          1,\n          acc,\n          {key, to_binary.(upper), to_binary.(lower)}\n        )\n    end)\n\n  # The function computes byte lookups based on the prefix. For example,\n  # Á, É, etc all have the same prefix <<195>>, so they are lumped\n  # together for lookup and then we just do a byte lookup later. We\n  # tried doing the byte lookup on 64-element tuple (since the byte\n  # is always within 0b10000000 and 0b10111111) but that's slower,\n  # especially because we need to check the byte range for invalid\n  # Unicode, instead the last byte lookup is a case. Grouping the\n  # top-level lookup makes the cost of a miss 3x cheaper albeit a\n  # hit is 10% more expensive) and reduces bytecode size.\n  compute_lookup = fn key_values ->\n    prefixes =\n      Enum.reduce(key_values, %{}, fn {codepoint, result}, acc ->\n        prefix_size = bit_size(codepoint) - 8\n        <<prefix::size(^prefix_size)-bits, byte>> = codepoint\n        Map.update(acc, prefix, [{byte, result}], &[{byte, result} | &1])\n      end)\n\n    {singles, tables} =\n      Enum.reduce(Map.delete(prefixes, \"\"), {[], []}, fn {prefix, pairs}, {singles, tables} ->\n        case pairs do\n          [{byte, result}] ->\n            {[{prefix <> <<byte>>, result} | singles], tables}\n\n          _ ->\n            clauses =\n              Enum.flat_map(pairs, fn {byte, result} ->\n                quote do\n                  unquote(byte) -> unquote(result)\n                end\n              end)\n\n            clauses = clauses ++ quote do: (byte -> <<unquote(prefix), byte>>)\n            {singles, [{prefix, clauses} | tables]}\n        end\n      end)\n\n    {Enum.sort(singles), Enum.sort_by(tables, &(-byte_size(elem(&1, 0))))}\n  end\n\n  # Sigma variants for Greek\n  @letter_sigma <<0x03A3::utf8>>\n  @letter_small_sigma_final <<0x03C2::utf8>>\n  @letter_small_sigma <<0x03C3::utf8>>\n\n  # Letter I variants for Turkic languages\n  @letter_I <<0x0049::utf8>>\n  @dotless_letter_i <<0x0131::utf8>>\n  @letter_i <<0x0069::utf8>>\n  @letter_I_dot_above <<0x0130::utf8>>\n  @combining_dot_above <<0x0307::utf8>>\n\n  # Downcase\n\n  # Turkic İ -> i\n  def downcase(<<unquote(@letter_I_dot_above), rest::bits>>, acc, mode) do\n    char = if mode == :turkic, do: @letter_i, else: <<@letter_i, @combining_dot_above>>\n    downcase(rest, [char | acc], mode)\n  end\n\n  def downcase(<<@letter_I, @combining_dot_above, rest::bits>>, acc, mode) do\n    char = if mode == :turkic, do: @letter_i, else: <<@letter_i, @combining_dot_above>>\n    downcase(rest, [char | acc], mode)\n  end\n\n  # Turkic I -> ı\n  def downcase(<<@letter_I, rest::bits>>, acc, mode) do\n    char = if mode == :turkic, do: @dotless_letter_i, else: @letter_i\n    downcase(rest, [char | acc], mode)\n  end\n\n  # Greek sigma\n  def downcase(<<@letter_sigma, rest::bits>>, acc, mode) do\n    downcased =\n      if mode == :greek and cased_letter_list?(acc) and not cased_letter_binary?(rest) do\n        @letter_small_sigma_final\n      else\n        @letter_small_sigma\n      end\n\n    downcase(rest, [downcased | acc], mode)\n  end\n\n  conditional_downcase = [@letter_I, @letter_I_dot_above, @letter_sigma]\n\n  {singles, tables} =\n    compute_lookup.(\n      for {codepoint, _upper, lower} <- codes,\n          lower && lower != codepoint,\n          codepoint not in conditional_downcase,\n          do: {codepoint, lower}\n    )\n\n  for {codepoint, lower} <- singles do\n    def downcase(<<unquote(codepoint), rest::bits>>, acc, mode) do\n      downcase(rest, [unquote(lower) | acc], mode)\n    end\n  end\n\n  for {prefix, clauses} <- tables do\n    def downcase(<<unquote(prefix), byte, rest::bits>>, acc, mode) do\n      value = case byte, do: unquote(clauses)\n      downcase(rest, [value | acc], mode)\n    end\n  end\n\n  def downcase(<<byte, rest::bits>>, acc, mode) do\n    if byte >= ?A and byte <= ?Z do\n      downcase(rest, [byte + 32 | acc], mode)\n    else\n      downcase(rest, [byte | acc], mode)\n    end\n  end\n\n  def downcase(\"\", acc, _mode), do: IO.iodata_to_binary(:lists.reverse(acc))\n\n  # Sigma handling\n\n  defp cased_letter_binary?(<<codepoint::utf8, rest::bits>>) do\n    if case_ignorable?(codepoint) do\n      cased_letter_binary?(rest)\n    else\n      cased_letter?(codepoint)\n    end\n  end\n\n  defp cased_letter_binary?(_), do: false\n\n  defp cased_letter_list?([<<codepoint::utf8>> | rest]) do\n    if case_ignorable?(codepoint) do\n      cased_letter_list?(rest)\n    else\n      cased_letter?(codepoint)\n    end\n  end\n\n  defp cased_letter_list?(_), do: false\n\n  for {first, last} <- rangify.(cased_letters) do\n    if first == last do\n      defp cased_letter?(unquote(first)), do: true\n    else\n      defp cased_letter?(codepoint)\n           when codepoint >= unquote(first) and codepoint <= unquote(last),\n           do: true\n    end\n  end\n\n  defp cased_letter?(_), do: false\n\n  for {first, last} <- rangify.(case_ignorable) do\n    if first == last do\n      defp case_ignorable?(unquote(first)), do: true\n    else\n      defp case_ignorable?(codepoint)\n           when codepoint >= unquote(first) and codepoint <= unquote(last),\n           do: true\n    end\n  end\n\n  defp case_ignorable?(_), do: false\n\n  # Upcase\n\n  # Turkic i -> İ\n  def upcase(<<@letter_i, rest::bits>>, acc, mode) do\n    char = if mode == :turkic, do: @letter_I_dot_above, else: @letter_I\n    upcase(rest, [char | acc], mode)\n  end\n\n  conditional_upcase = [@letter_i]\n\n  {singles, tables} =\n    compute_lookup.(\n      for {codepoint, upper, _lower} <- codes,\n          upper && upper != codepoint,\n          codepoint not in conditional_upcase,\n          do: {codepoint, upper}\n    )\n\n  for {codepoint, upper} <- singles do\n    def upcase(<<unquote(codepoint), rest::bits>>, acc, mode) do\n      upcase(rest, [unquote(upper) | acc], mode)\n    end\n  end\n\n  for {prefix, clauses} <- tables do\n    def upcase(<<unquote(prefix), byte, rest::bits>>, acc, mode) do\n      value = case byte, do: unquote(clauses)\n      upcase(rest, [value | acc], mode)\n    end\n  end\n\n  def upcase(<<byte, rest::bits>>, acc, mode) do\n    if byte >= ?a and byte <= ?z do\n      upcase(rest, [byte - 32 | acc], mode)\n    else\n      upcase(rest, [byte | acc], mode)\n    end\n  end\n\n  def upcase(\"\", acc, _mode), do: IO.iodata_to_binary(:lists.reverse(acc))\nend\n\ndefmodule String.Break do\n  @moduledoc false\n  @whitespace_max_size 3\n\n  prop_path = Path.join(__DIR__, \"PropList.txt\")\n\n  whitespace =\n    prop_path\n    |> File.read!()\n    |> String.split([\"\\r\\n\", \"\\n\"])\n    |> Enum.reduce([], fn line, acc ->\n      case :binary.split(line, \";\") do\n        [<<first::4-bytes, \"..\", last::4-bytes, _::binary>>, <<\" White_Space\", _::binary>>] ->\n          first = String.to_integer(first, 16)\n          last = String.to_integer(last, 16)\n          Enum.map(first..last, fn int -> <<int::utf8>> end) ++ acc\n\n        [<<single::4-bytes, _::binary>>, <<\" White_Space\", _::binary>>] ->\n          [<<String.to_integer(single, 16)::utf8>> | acc]\n\n        _ ->\n          acc\n      end\n    end)\n\n  IO.puts(:stderr, \"[Unicode] Break on #{length(whitespace)} whitespace codepoints\")\n\n  # trim_leading\n\n  def trim_leading(string) when is_binary(string) do\n    do_trim_leading(string)\n  end\n\n  for codepoint <- whitespace do\n    def do_trim_leading(<<unquote(codepoint), rest::bits>>), do: do_trim_leading(rest)\n  end\n\n  def do_trim_leading(<<rest::bits>>), do: rest\n\n  # trim_trailing\n\n  for cp <- whitespace do\n    # We need to increment @whitespace_max_size as well\n    # as the small table (_s) if we add a new entry here.\n    case byte_size(cp) do\n      3 ->\n        defp do_trim_trailing_l(unquote(cp)), do: -3\n\n      2 ->\n        defp do_trim_trailing_l(<<_, unquote(cp)>>), do: -2\n        defp do_trim_trailing_s(unquote(cp)), do: <<>>\n\n      1 ->\n        defp do_trim_trailing_l(<<unquote(cp), unquote(cp), unquote(cp)>>), do: -3\n        defp do_trim_trailing_l(<<_, unquote(cp), unquote(cp)>>), do: -2\n        defp do_trim_trailing_l(<<_, _, unquote(cp)>>), do: -1\n\n        defp do_trim_trailing_s(<<x, unquote(cp)>>), do: do_trim_trailing_s(<<x>>)\n        defp do_trim_trailing_s(unquote(cp)), do: <<>>\n    end\n  end\n\n  defp do_trim_trailing_l(_), do: 0\n  defp do_trim_trailing_s(o), do: o\n\n  def trim_trailing(string) when is_binary(string) do\n    trim_trailing(string, byte_size(string))\n  end\n\n  defp trim_trailing(string, size) when size < @whitespace_max_size do\n    do_trim_trailing_s(string)\n  end\n\n  defp trim_trailing(string, size) do\n    trail = binary_part(string, size, -@whitespace_max_size)\n\n    case do_trim_trailing_l(trail) do\n      0 -> string\n      x -> trim_trailing(binary_part(string, 0, size + x), size + x)\n    end\n  end\n\n  # Split\n\n  def split(string) do\n    :binary.split(string, unquote(whitespace -- non_breakable), [:global, :trim_all])\n  end\n\n  # Decompose\n\n  def decompose(entries, map) do\n    for entry <- entries do\n      case map do\n        %{^entry => match} -> decompose(match, map)\n        %{} -> <<entry::utf8>>\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/examples/difference.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Run it from root as: make compile && bin/elixir lib/ex_unit/examples/difference.exs\nExUnit.start(seed: 0)\n\ndefmodule Difference do\n  @moduledoc \"\"\"\n  This module contains failing tests to see\n  difference highlighting in action.\n  \"\"\"\n  use ExUnit.Case\n\n  defmodule User do\n    defstruct [:age]\n  end\n\n  defmacrop one, do: 1\n\n  describe \"regular context\" do\n    test \"integers\" do\n      assert 491_512_235 == 490_512_035\n    end\n\n    test \"floats\" do\n      assert 42.0 == 43.0\n    end\n\n    test \"strings\" do\n      string1 = \"fox hops over \\\"the dog\"\n      string2 = \"fox  jumps over the lazy cat\"\n      assert string1 == string2\n    end\n\n    test \"whitespace\" do\n      list1 = [%{a: \"abc \"}, %{a: \"def\"}, %{c: \"gh\"}]\n      list2 = [%{a: \"abc\"}, %{a: \" def\"}, %{c: \"hi\"}]\n      assert list1 == list2\n    end\n\n    test \"large strings\" do\n      string1 = \"short\"\n      string2 = \"really long string that should not emit diff\"\n      assert string1 == string2\n    end\n\n    test \"large strings; inner\" do\n      tuple1 = {\"short\"}\n      tuple2 = {\"really long string that should not emit diff\"}\n      assert tuple1 == tuple2\n    end\n\n    test \"lists\" do\n      list1 = [\"Tvo\", make_ref(), :ok, {}]\n      list2 = [\"Two\", :ok, self(), {true}]\n      assert list1 == list2\n    end\n\n    test \"lists; missing entries\" do\n      assert [] == [1, 2, 3]\n    end\n\n    test \"lists; surplus entries\" do\n      assert [1, 2, 3] == []\n    end\n\n    test \"improper lists\" do\n      list1 = [1 | \"b\"]\n      list2 = [1, \"a\"]\n      assert list1 == list2\n    end\n\n    test \"charlists\" do\n      charlist1 = ~c\"fox hops over 'the dog\"\n      charlist2 = ~c\"fox jumps over the lazy cat\"\n      assert charlist1 == charlist2\n    end\n\n    test \"keyword lists\" do\n      assert [file: \"nofile\", line: 12] == [file: nil, lime: 10]\n    end\n\n    test \"keyword lists; reverse order\" do\n      keyword1 = [port: 4000, max_connections: 1000]\n      keyword2 = [max_connections: 1000, port: 4000]\n      assert keyword1 == keyword2\n    end\n\n    test \"tuples\" do\n      tuple1 = {:hex, \"0.1\", [{:ex_doc}]}\n      tuple2 = {:hex, \"1.1\"}\n      assert tuple1 == tuple2\n    end\n\n    test \"maps; mixed diff\" do\n      map1 = Enum.into(1..15, %{}, &{&1, &1}) |> Map.delete(13)\n      map2 = Enum.reduce(5..10, map1, &Map.delete(&2, &1)) |> Map.put(13, 13) |> Map.put(12, 32)\n      assert map1 == map2\n    end\n\n    test \"maps; missing pairs\" do\n      map1 = %{baz: 12}\n      map2 = %{foo: 12, bar: 12, baz: 12}\n      assert map1 == map2\n    end\n\n    test \"maps; surplus pairs\" do\n      map1 = %{foo: 12, bar: 12, baz: 12}\n      map2 = %{baz: 12}\n      assert map1 == map2\n    end\n\n    test \"maps; missing pair\" do\n      assert %{} == %{baz: 12}\n    end\n\n    test \"maps; surplus pair\" do\n      assert %{baz: 12} == %{}\n    end\n\n    test \"structs\" do\n      assert %User{age: 16} == %User{age: 21}\n    end\n  end\n\n  describe \"match context\" do\n    test \"pins\" do\n      x = 1\n      assert ^x = 2\n    end\n\n    test \"vars\" do\n      assert {x, x} = {1, 2}\n    end\n\n    test \"strings; concat\" do\n      assert \"fox hops over the\" <> x = \"fox jumps over the lazy cat\"\n    end\n\n    test \"lists; head and tail\" do\n      assert [\"Tvo\", 1 | [:ok, {}]] = [\"Two\", :ok, self(), {true}]\n    end\n\n    test \"lists; concat\" do\n      assert [\"Tvo\", 1] ++ [:ok, {}] = [\"Two\", :ok, self(), {true}]\n    end\n\n    test \"maps\" do\n      assert %{baz: 12} = %{foo: 13, bar: 13, baz: 13}\n    end\n\n    test \"macro\" do\n      assert one() = 2\n    end\n\n    test \"underscore\" do\n      assert {_, 1} = {1, 2}\n    end\n  end\n\n  describe \"receive\" do\n    test \"no messages in the mailbox\" do\n      assert_received x when x == :hello\n    end\n\n    test \"only 1 message in the mailbox\" do\n      send(self(), {:message, 1})\n\n      assert_received x when x == :hello\n    end\n\n    test \"more than 1 messages in the mailbox\" do\n      for i <- 1..2, do: send(self(), {:message, i})\n\n      assert_received x when x == :hello\n    end\n\n    test \"more than 10 messages in the mailbox\" do\n      for i <- 1..11, do: send(self(), {:message, i})\n\n      assert_received x when x == :hello\n    end\n\n    test \"macro\" do\n      send(self(), 12)\n\n      assert_received one()\n    end\n  end\n\n  test \"only one side with metadata\" do\n    assert \"one\" != \"one\"\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/examples/one_of_each.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Run it from root as: make compile && bin/elixir lib/ex_unit/examples/one_of_each.exs\nExUnit.start(seed: 0)\n\ndefmodule TestOneOfEach do\n  @moduledoc \"\"\"\n  This module contains one of each type of failing test.\n  It is used simply to document the style of each.\n  \"\"\"\n  use ExUnit.Case\n\n  @one 1\n  @two 2\n\n  @long_data_1 [field1: \"one\", field2: {:two1, :two2}, field3: ~c\"three\", field4: [1, 2, 3, 4]]\n  @long_data_2 [field1: \"one\", field2: {:two1, :two3}, field3: ~c\"three\", field4: [1, 2, 3, 4]]\n\n  setup do\n    {:ok, user_id: 1, post_id: 2, many_ids: Enum.to_list(1..50)}\n  end\n\n  test \"1. assert with a match\" do\n    assert [@one] = [@two]\n  end\n\n  test \"2. assert with a binary operator\" do\n    assert @one * 4 > @two * 3\n  end\n\n  test \"3. assert match with a long argument\" do\n    assert @long_data_1 = @long_data_2\n  end\n\n  test \"4. assert equality with a long argument\" do\n    assert @long_data_1 == @long_data_2\n  end\n\n  test \"5. refute with a match\" do\n    refute [@one] = [@one]\n  end\n\n  test \"6. refute with a binary operator\" do\n    refute @one * 6 > @two * 2\n  end\n\n  test \"7. refute match with a long argument\" do\n    refute @long_data_1 = @long_data_1\n  end\n\n  test \"8. refute equality with a long argument\" do\n    refute @long_data_1 == @long_data_1\n  end\n\n  test \"9. assert of an expression with a message\" do\n    assert 1 > 2, \"is one greater than two?\"\n  end\n\n  test \"10. assert with explicit expected and actual values\" do\n    assert @one > @two, left: @one, right: @two, message: \"one should be greater than two\"\n  end\n\n  test \"11. assert that a message is ready to be received\" do\n    assert_received :no_message_there\n  end\n\n  test \"12. assert that a message is received within a timeout\" do\n    send(self(), {:ok, 1})\n    send(self(), :message_in_my_inbox)\n    send(self(), {:ok, 2})\n    send(self(), :another_message)\n    assert_receive :no_message_after_timeout\n  end\n\n  test \"13. assert an exception with a given message is raised, but no exception\" do\n    assert_raise(SomeException, \"some message\", fn -> nil end)\n  end\n\n  test \"14. assert an exception with a given message is raised\" do\n    assert_raise(SomeException, \"some message\", fn ->\n      raise \"other exception\"\n    end)\n  end\n\n  test \"15. assert an exception with a given message is raised, but the message is wrong\" do\n    assert_raise(RuntimeError, \"some message\", fn ->\n      raise \"other error\"\n    end)\n  end\n\n  test \"16. assert an exception is raised\" do\n    assert_raise(SomeException, fn -> nil end)\n  end\n\n  test \"17. assert two values are within some delta\" do\n    assert_in_delta 3.1415926, 22.0 / 7, 0.001\n  end\n\n  test \"18. refute a value with a message\" do\n    refute @one != @two, \"one should equal two\"\n  end\n\n  test \"19. refute a message is received within a timeout\" do\n    send(self(), {:hello, \"Dave\"})\n    refute_receive {:hello, _}, 100\n  end\n\n  test \"20. refute a message is ready to be received\" do\n    send(self(), :hello_again)\n    refute_received :hello_again\n  end\n\n  test \"21. refute two values are within delta\" do\n    refute_in_delta @one, @two, 1.5\n  end\n\n  test \"22. refute two values are within delta with message\" do\n    refute_in_delta @one, @two, 1.5, \"they shouldn't be this close\"\n  end\n\n  test \"23. flunk\" do\n    flunk(\"we failed. totally\")\n  end\n\n  test \"24. exception raised while running test\" do\n    assert blows_up()\n  end\n\n  test \"25. error due to exit\" do\n    spawn_link(fn -> raise \"oops\" end)\n\n    receive do\n    end\n  end\n\n  test \"26. multi error\" do\n    error1 =\n      try do\n        assert [@one] = [@two]\n      rescue\n        e in ExUnit.AssertionError ->\n          {:error, e, __STACKTRACE__}\n      end\n\n    error2 =\n      try do\n        assert @one * 4 > @two * 3\n      rescue\n        e in ExUnit.AssertionError ->\n          {:error, e, __STACKTRACE__}\n      end\n\n    raise ExUnit.MultiError, errors: [error1, error2]\n  end\n\n  @tag capture_log: true\n  test \"27. log capturing\" do\n    require Logger\n    Logger.debug(\"this will be logged\")\n    flunk(\"oops\")\n  end\n\n  test \"28. function clause error\" do\n    Access.fetch(:foo, :bar)\n  end\n\n  test \"29. function call arguments\" do\n    assert some_vars(1 + 2, 3 + 4)\n  end\n\n  @tag :capture_log\n  test \"30. linked assertion error\" do\n    Task.async(fn -> assert 1 == 2 end) |> Task.await()\n  end\n\n  @tag :capture_log\n  test \"31. linked function clause error\" do\n    Task.async(fn -> Access.fetch(:foo, :bar) end) |> Task.await()\n  end\n\n  @tag :capture_log\n  test \"32. trapped assertion error\" do\n    Process.flag(:trap_exit, true)\n    Task.async(fn -> assert 1 == 2 end) |> Task.await()\n  end\n\n  @tag :capture_log\n  test \"33. trapped function clause error\" do\n    Process.flag(:trap_exit, true)\n    Task.async(fn -> Access.fetch(:foo, :bar) end) |> Task.await()\n  end\n\n  defp some_vars(_a, _b) do\n    false\n  end\n\n  defp blows_up do\n    ignite(0) + 1\n  end\n\n  defp ignite(val) do\n    1 / val\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/assertions.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.AssertionError do\n  @moduledoc \"\"\"\n  Raised to signal an assertion error.\n\n  This is used by macros such as `ExUnit.Assertions.assert/1`.\n  \"\"\"\n\n  @no_value :ex_unit_no_meaningful_value\n\n  @typedoc since: \"1.16.0\"\n  @type t :: %__MODULE__{\n          left: any,\n          right: any,\n          message: any,\n          expr: any,\n          args: any,\n          doctest: any,\n          context: any\n        }\n\n  defexception left: @no_value,\n               right: @no_value,\n               message: @no_value,\n               expr: @no_value,\n               args: @no_value,\n               doctest: @no_value,\n               context: :==\n\n  @doc \"\"\"\n  Indicates no meaningful value for a field.\n  \"\"\"\n  @spec no_value :: atom\n  def no_value do\n    @no_value\n  end\n\n  @impl true\n  def exception(message) when is_binary(message) do\n    %ExUnit.AssertionError{message: message}\n  end\n\n  def exception(opts) do\n    with {:ok, message} when not is_binary(message) <- Keyword.fetch(opts, :message) do\n      raise ArgumentError,\n            \":message in ExUnit.Assertion must be a binary, got: #{inspect(message)}\"\n    end\n\n    struct(__MODULE__, opts)\n  end\n\n  @impl true\n  def message(exception) do\n    \"\\n\\n\" <> ExUnit.Formatter.format_assertion_error(exception)\n  end\nend\n\ndefmodule ExUnit.MultiError do\n  @moduledoc \"\"\"\n  Raised to signal multiple errors happened in a test case.\n  \"\"\"\n\n  @typedoc since: \"1.16.0\"\n  @type t :: %__MODULE__{\n          errors: [{Exception.kind(), any, Exception.stacktrace()}]\n        }\n\n  defexception errors: []\n\n  @impl true\n  def message(%{errors: errors}) do\n    \"got the following errors:\\n\\n\" <>\n      Enum.map_join(errors, \"\\n\\n\", fn {kind, error, stack} ->\n        Exception.format_banner(kind, error, stack)\n      end)\n  end\nend\n\ndefmodule ExUnit.Assertions do\n  @moduledoc \"\"\"\n  This module contains a set of assertion functions that are\n  imported by default into your test cases.\n\n  In general, a developer will want to use the general\n  `assert` macro in tests. This macro introspects your code\n  and provides good reporting whenever there is a failure.\n  For example, `assert some_fun() == 10` will fail (assuming\n  `some_fun()` returns `13`):\n\n      Comparison (using ==) failed in:\n      code:  assert some_fun() == 10\n      left:  13\n      right: 10\n\n  This module also provides other convenience functions\n  like `assert_in_delta` and `assert_raise` to easily handle\n  other common cases such as checking a floating-point number\n  or handling exceptions.\n  \"\"\"\n\n  @doc \"\"\"\n  Asserts its argument is a truthy value.\n\n  `assert` introspects the underlying expression and provides\n  good reporting whenever there is a failure. For example,\n  if the expression uses the comparison operator, the message\n  will show the values of the two sides. The assertion\n\n      assert 1 + 2 + 3 + 4 > 15\n\n   will fail with the message:\n\n      Assertion with > failed\n      code:  assert 1 + 2 + 3 + 4 > 15\n      left:  10\n      right: 15\n\n  Similarly, if a match expression is given, it will report\n  any failure in terms of that match. Given\n\n      assert [1] = [2]\n\n  you'll see:\n\n      match (=) failed\n      code:  assert [1] = [2]\n      left: [1]\n      right: [2]\n\n  Keep in mind that `assert` does not change its semantics\n  based on the expression. In other words, the expression\n  is still required to return a truthy value. For example,\n  the following will fail:\n\n      assert nil = some_function_that_returns_nil()\n\n  Even though the match works, `assert` still expects a truth\n  value. In such cases, simply use `==/2` or `match?/2`.\n\n  If you need more complex pattern matching using guards, you\n  need to use `match?/2`:\n\n      assert match?([%{id: id} | _] when is_integer(id), records)\n\n  \"\"\"\n  defmacro assert({:=, meta, [left, right]} = assertion) do\n    code = escape_quoted(:assert, meta, mark_as_generated(assertion))\n\n    check =\n      quote generated: true do\n        if right do\n          :ok\n        else\n          raise ExUnit.AssertionError,\n            expr: expr,\n            message: \"Expected truthy, got #{inspect(right)}\"\n        end\n      end\n\n    {left, right} = move_match(left, right)\n    __match__(left, right, code, check, __CALLER__)\n  end\n\n  defmacro assert({:match?, meta, [left, right]} = assertion) do\n    code = escape_quoted(:assert, meta, mark_as_generated(assertion))\n    match? = {:match?, meta, [left, Macro.var(:right, __MODULE__)]}\n\n    left = __expand_pattern__(left, __CALLER__)\n    pins = collect_pins_from_pattern(left, Macro.Env.vars(__CALLER__))\n\n    quote do\n      right = unquote(right)\n      left = unquote(Macro.escape(left))\n\n      ExUnit.Assertions.assert(unquote(match?),\n        right: right,\n        left: left,\n        expr: unquote(code),\n        message: \"match (match?) failed\" <> ExUnit.Assertions.__pins__(unquote(pins)),\n        context: {:match, unquote(pins)}\n      )\n    end\n  end\n\n  defmacro assert(assertion) do\n    if translated = translate_assertion(:assert, assertion, __CALLER__) do\n      translated\n    else\n      {args, value} = extract_args(assertion, __CALLER__)\n\n      quote generated: true do\n        if value = unquote(value) do\n          value\n        else\n          raise ExUnit.AssertionError,\n            args: unquote(args),\n            expr: unquote(escape_quoted(:assert, [], assertion)),\n            message: \"Expected truthy, got #{inspect(value)}\"\n        end\n      end\n    end\n  end\n\n  @doc \"\"\"\n  A negative assertion, expects the expression to be `false` or `nil`.\n\n  Keep in mind that `refute` does not change the semantics of\n  the given expression. In other words, the following will fail:\n\n      refute {:ok, _} = some_function_that_returns_error_tuple()\n\n  The code above will fail because the `=` operator always fails\n  when the sides do not match and `refute/2` does not change it.\n\n  The correct way to write the refutation above is to use `match?/2`:\n\n      refute match?({:ok, _}, some_function_that_returns_error_tuple())\n\n  ## Examples\n\n      refute age < 0\n\n  \"\"\"\n  defmacro refute({:match?, meta, [left, right]} = assertion) do\n    code = escape_quoted(:refute, meta, assertion)\n    match? = {:match?, meta, [left, Macro.var(:right, __MODULE__)]}\n\n    left = __expand_pattern__(left, __CALLER__)\n    pins = collect_pins_from_pattern(left, Macro.Env.vars(__CALLER__))\n\n    quote do\n      right = unquote(right)\n      left = unquote(Macro.escape(left))\n\n      refute unquote(match?),\n        right: right,\n        left: left,\n        expr: unquote(code),\n        message:\n          \"match (match?) succeeded, but should have failed\" <>\n            ExUnit.Assertions.__pins__(unquote(pins)),\n        context: {:match, unquote(pins)}\n    end\n  end\n\n  defmacro refute(assertion) do\n    if translated = translate_assertion(:refute, assertion, __CALLER__) do\n      {:!, [generated: true], [translated]}\n    else\n      {args, value} = extract_args(assertion, __CALLER__)\n\n      quote generated: true do\n        if value = unquote(value) do\n          raise ExUnit.AssertionError,\n            args: unquote(args),\n            expr: unquote(escape_quoted(:refute, [], assertion)),\n            message: \"Expected false or nil, got #{inspect(value)}\"\n        else\n          value\n        end\n      end\n    end\n  end\n\n  ## START HELPERS\n\n  @operator [:==, :<, :>, :<=, :>=, :===, :=~, :!==, :!=, :in]\n\n  defp translate_assertion(:assert, {operator, meta, [_, _]} = expr, caller)\n       when operator in @operator do\n    if match?([{_, Kernel}], Macro.Env.lookup_import(caller, {operator, 2})) do\n      left = Macro.var(:left, __MODULE__)\n      right = Macro.var(:right, __MODULE__)\n      call = {operator, meta, [left, right]}\n      equality_check? = operator in [:<, :>, :!==, :!=]\n      message = \"Assertion with #{operator} failed\"\n      translate_operator(:assert, expr, call, message, equality_check?, caller)\n    end\n  end\n\n  defp translate_assertion(:refute, {operator, meta, [_, _]} = expr, caller)\n       when operator in @operator do\n    if match?([{_, Kernel}], Macro.Env.lookup_import(caller, {operator, 2})) do\n      left = Macro.var(:left, __MODULE__)\n      right = Macro.var(:right, __MODULE__)\n      call = {:not, meta, [{operator, meta, [left, right]}]}\n      equality_check? = operator in [:<=, :>=, :===, :==, :=~]\n      message = \"Refute with #{operator} failed\"\n      translate_operator(:refute, expr, call, message, equality_check?, caller)\n    end\n  end\n\n  defp translate_assertion(_kind, _expected, _caller) do\n    nil\n  end\n\n  defp translate_operator(kind, {op, meta, [left, right]} = expr, call, message, true, _caller) do\n    expr = escape_quoted(kind, meta, expr)\n    context = if op in [:===, :!==], do: :===, else: :==\n\n    quote do\n      left = unquote(left)\n      right = unquote(right)\n      expr = unquote(expr)\n      message = unquote(message)\n\n      if ExUnit.Assertions.__equal__?(left, right) do\n        ExUnit.Assertions.assert(false,\n          left: left,\n          expr: expr,\n          message: message <> \", both sides are exactly equal\"\n        )\n      else\n        ExUnit.Assertions.assert(unquote(call),\n          left: left,\n          right: right,\n          expr: expr,\n          message: message,\n          context: unquote(context)\n        )\n      end\n    end\n  end\n\n  defp translate_operator(kind, {op, meta, [left, right]} = expr, call, message, false, _caller) do\n    expr = escape_quoted(kind, meta, expr)\n    context = if op in [:===, :!==], do: :===, else: :==\n\n    quote do\n      left = unquote(left)\n      right = unquote(right)\n\n      ExUnit.Assertions.assert(unquote(call),\n        left: left,\n        right: right,\n        expr: unquote(expr),\n        message: unquote(message),\n        context: unquote(context)\n      )\n    end\n  end\n\n  @doc false\n  def __equal__?(left, right) do\n    left === right\n  end\n\n  defp escape_quoted(kind, meta, expr) do\n    Macro.escape({kind, meta, [expr]}, prune_metadata: true)\n  end\n\n  defp extract_args({root, meta, [_ | _] = args} = expr, env) do\n    arity = length(args)\n\n    reserved? =\n      is_atom(root) and (Macro.special_form?(root, arity) or Macro.operator?(root, arity))\n\n    all_quoted_literals? = Enum.all?(args, &Macro.quoted_literal?/1)\n\n    case Macro.expand_once(expr, env) do\n      ^expr when not reserved? and not all_quoted_literals? ->\n        vars = for i <- 1..arity, do: Macro.var(:\"arg#{i}\", __MODULE__)\n\n        quoted =\n          quote do\n            {unquote_splicing(vars)} = {unquote_splicing(args)}\n            unquote({root, meta, vars})\n          end\n\n        {vars, quoted}\n\n      other ->\n        {ExUnit.AssertionError.no_value(), other}\n    end\n  end\n\n  defp extract_args(expr, _env) do\n    {ExUnit.AssertionError.no_value(), expr}\n  end\n\n  defp move_match(left, {:=, meta, [middle, right]}),\n    do: move_match({:=, meta, [left, middle]}, right)\n\n  defp move_match(left, right),\n    do: {left, right}\n\n  @doc false\n  def __match__({:when, _, _} = left, right, _, _, _) do\n    suggestion =\n      quote do\n        assert match?(unquote(left), unquote(right))\n      end\n\n    raise ArgumentError, \"\"\"\n    invalid pattern in assert/1:\n\n    #{Macro.to_string(left) |> Inspect.Error.pad(2)}\n\n    To assert with guards, use match?/2:\n\n    #{Macro.to_string(suggestion) |> Inspect.Error.pad(2)}\n    \"\"\"\n  end\n\n  def __match__(left, right, code, check, caller) do\n    left = __expand_pattern__(left, caller)\n    vars = collect_vars_from_pattern(left)\n    pins = collect_pins_from_pattern(left, Macro.Env.vars(caller))\n\n    match_expr =\n      suppress_warning(\n        quote do\n          case right do\n            unquote(left) ->\n              unquote(check)\n              {unquote_splicing(mark_as_generated(vars))}\n\n            _ ->\n              left = unquote(Macro.escape(left))\n\n              raise ExUnit.AssertionError,\n                left: left,\n                right: right,\n                expr: expr,\n                message: \"match (=) failed\" <> ExUnit.Assertions.__pins__(unquote(pins)),\n                context: {:match, unquote(pins)}\n          end\n        end\n      )\n\n    quote do\n      right = unquote(right)\n      expr = unquote(code)\n      {unquote_splicing(vars)} = unquote(match_expr)\n      right\n    end\n  end\n\n  ## END HELPERS\n\n  @doc \"\"\"\n  Asserts `value` is truthy, displaying the given `message` otherwise.\n\n  ## Examples\n\n      assert false, \"it will never be true\"\n\n      assert x == :foo, \"expected x to be foo\"\n\n      assert match?({:ok, _}, x), \"expected x to match {:ok, _}\"\n\n  \"\"\"\n  def assert(value, message) when is_binary(message) do\n    assert(value, message: message)\n  end\n\n  def assert(value, opts) when is_list(opts) do\n    if !value, do: raise(ExUnit.AssertionError, opts)\n    true\n  end\n\n  @doc \"\"\"\n  Asserts that a message matching `pattern` was or is going to be received\n  within the `timeout` period, specified in milliseconds.\n\n  Unlike `assert_received`, it has a configurable timeout.\n  The default timeout duration is determined by the `assert_receive_timeout` option,\n  which can be set using `ExUnit.configure/1`. This option defaults to 100 milliseconds.\n\n  The `pattern` argument must be a match pattern.\n\n  Flunks with `failure_message` if a message matching `pattern` is not received.\n  If a message matches, it is also removed from the process mailbox.\n\n  ## Examples\n\n      assert_receive :hello\n\n  Asserts against a larger timeout:\n\n      assert_receive :hello, 20_000\n\n  You can also match against specific patterns:\n\n      assert_receive {:hello, _}\n\n      x = 5\n      assert_receive {:count, ^x}\n\n  \"\"\"\n  defmacro assert_receive(pattern, timeout \\\\ nil, failure_message \\\\ nil) do\n    code = escape_quoted(:assert_receive, [], pattern)\n    assert_receive(pattern, timeout, failure_message, __CALLER__, code)\n  end\n\n  @doc \"\"\"\n  Asserts that a message matching `pattern` was received and is in the\n  current process' mailbox.\n\n  The `pattern` argument must be a match pattern.\n\n  Flunks with `failure_message` if a message matching `pattern` was not received.\n  If a message matches, it is also removed from the process mailbox.\n\n  Timeout is set to `0`, so there is no waiting time.\n\n  ## Examples\n\n      send(self(), :hello)\n      assert_received :hello\n\n      send(self(), :bye)\n      assert_received :hello, \"Oh No!\"\n      ** (ExUnit.AssertionError) Oh No!\n\n  You can also match against specific patterns:\n\n      send(self(), {:hello, \"world\"})\n      assert_received {:hello, _}\n\n  \"\"\"\n  defmacro assert_received(pattern, failure_message \\\\ nil) do\n    code = escape_quoted(:assert_received, [], pattern)\n    assert_receive(pattern, 0, failure_message, __CALLER__, code)\n  end\n\n  defp assert_receive(pattern, timeout, failure_message, caller, code) do\n    # Expand before extracting metadata\n    expanded_pattern = __expand_pattern__(pattern, caller)\n    vars = collect_vars_from_pattern(expanded_pattern)\n    pins = collect_pins_from_pattern(expanded_pattern, Macro.Env.vars(caller))\n\n    pattern =\n      case expanded_pattern do\n        {:when, meta, [left, right]} ->\n          {:when, meta, [quote(do: unquote(left) = received), right]}\n\n        left ->\n          quote(do: unquote(left) = received)\n      end\n\n    quoted_pattern =\n      quote do\n        case message do\n          unquote(pattern) ->\n            _ = unquote(mark_as_generated(vars))\n            true\n\n          _ ->\n            false\n        end\n      end\n\n    pattern_finder =\n      quote do\n        fn message ->\n          unquote(suppress_warning(quoted_pattern))\n        end\n      end\n\n    on_timeout =\n      if failure_message do\n        quote do\n          flunk(unquote(failure_message))\n        end\n      else\n        quote do\n          ExUnit.Assertions.__timeout__(\n            unquote(Macro.escape(expanded_pattern)),\n            unquote(code),\n            unquote(pins),\n            unquote(pattern_finder),\n            timeout\n          )\n        end\n      end\n\n    quote do\n      timeout = ExUnit.Assertions.__timeout__(unquote(timeout), :assert_receive_timeout)\n\n      {received, unquote(vars)} =\n        receive do\n          unquote(pattern) -> {received, unquote(mark_as_generated(vars))}\n        after\n          timeout -> unquote(on_timeout)\n        end\n\n      received\n    end\n  end\n\n  @indent \"\\n  \"\n  @max_mailbox_length 10\n\n  @doc false\n  def __timeout__(timeout, _) when is_integer(timeout) and timeout >= 0, do: timeout\n\n  def __timeout__(nil, key), do: Application.fetch_env!(:ex_unit, key)\n\n  def __timeout__(timeout, _),\n    do: raise(ArgumentError, \"timeout must be a non-negative integer, got: #{inspect(timeout)}\")\n\n  @doc false\n  def __timeout__(pattern, code, pins, pattern_finder, timeout) do\n    {:messages, messages} = Process.info(self(), :messages)\n\n    if Enum.any?(messages, pattern_finder) do\n      raise ExUnit.AssertionError,\n        expr: code,\n        message: \"\"\"\n        Found message matching #{Macro.to_string(pattern)} after #{timeout}ms.\n\n        This means the message was delivered too close to the timeout value, you may want to either:\n\n          1. Give an increased timeout to `assert_receive/2`\n          2. Increase the default timeout to all `assert_receive` in your\n             test_helper.exs by setting ExUnit.configure(assert_receive_timeout: ...)\n        \"\"\"\n    else\n      {message, mailbox} = format_mailbox(messages)\n\n      # The error contains a special `context` that will be transformed\n      # into `{:match, pins}` by the formatter to execute a diff for each\n      # message in the `mailbox`\n      raise ExUnit.AssertionError,\n        left: pattern,\n        expr: code,\n        message:\n          \"Assertion failed, no matching message after #{timeout}ms\" <>\n            ExUnit.Assertions.__pins__(pins) <> message,\n        context: {:mailbox, pins, mailbox}\n    end\n  end\n\n  @doc false\n  def __pins__(pins) do\n    pins\n    |> Enum.filter(fn {{_, ctx}, _} -> ctx == nil end)\n    |> Enum.sort()\n    |> Enum.map_join(@indent, fn {{name, _}, var} -> \"#{name} = #{inspect(var)}\" end)\n    |> case do\n      \"\" ->\n        \"\"\n\n      pinned ->\n        \"\\nThe following variables were pinned:\" <> @indent <> pinned\n    end\n  end\n\n  defp format_mailbox(messages) do\n    length = length(messages)\n    mailbox = Enum.take(messages, -@max_mailbox_length)\n\n    {mailbox_message(length), mailbox}\n  end\n\n  defp mailbox_message(0), do: \"\\nThe process mailbox is empty.\"\n\n  defp mailbox_message(1) do\n    \"\\nShowing 1 of 1 message in the mailbox\"\n  end\n\n  defp mailbox_message(length) when length > @max_mailbox_length do\n    \"\\nShowing #{@max_mailbox_length} of #{length} messages in the mailbox\"\n  end\n\n  defp mailbox_message(length) do\n    \"\\nShowing #{length} of #{length} messages in the mailbox\"\n  end\n\n  defp collect_pins_from_pattern(expr, vars) do\n    {_, pins} =\n      Macro.prewalk(expr, %{}, fn\n        {:quote, _, [_]}, acc ->\n          {:ok, acc}\n\n        {:quote, _, [_, _]}, acc ->\n          {:ok, acc}\n\n        {:^, _, [var]}, acc ->\n          identifier = var_context(var)\n\n          if identifier in vars do\n            {:ok, Map.put(acc, var_context(var), var)}\n          else\n            {:ok, acc}\n          end\n\n        form, acc ->\n          {form, acc}\n      end)\n\n    Enum.to_list(pins)\n  end\n\n  defp var_context({name, meta, context}) do\n    {name, meta[:counter] || context}\n  end\n\n  defp collect_vars_from_pattern({:when, _, [left, right]}) do\n    pattern = collect_vars_from_pattern(left)\n\n    vars =\n      for {name, _, context} = var <- collect_vars_from_pattern(right),\n          has_var?(pattern, name, context),\n          do: var\n\n    pattern ++ vars\n  end\n\n  defp collect_vars_from_pattern(expr) do\n    Macro.prewalk(expr, [], fn\n      {:\"::\", _, [left, right]}, acc ->\n        {[left], collect_vars_from_binary(right, acc)}\n\n      {skip, _, [_]}, acc when skip in [:^, :@, :quote] ->\n        {:ok, acc}\n\n      {skip, _, [_, _]}, acc when skip in [:quote] ->\n        {:ok, acc}\n\n      {:_, _, context}, acc when is_atom(context) ->\n        {:ok, acc}\n\n      {name, meta, context}, acc when is_atom(name) and is_atom(context) ->\n        {:ok, [{name, meta, context} | acc]}\n\n      node, acc ->\n        {node, acc}\n    end)\n    |> elem(1)\n  end\n\n  defp collect_vars_from_binary(right, original_acc) do\n    Macro.prewalk(right, original_acc, fn\n      {mode, _, [{name, meta, context}]}, acc\n      when is_atom(mode) and is_atom(name) and is_atom(context) ->\n        if has_var?(original_acc, name, context) do\n          {:ok, [{name, meta, context} | acc]}\n        else\n          {:ok, acc}\n        end\n\n      node, acc ->\n        {node, acc}\n    end)\n    |> elem(1)\n  end\n\n  defp has_var?(pattern, name, context), do: Enum.any?(pattern, &match?({^name, _, ^context}, &1))\n\n  defp mark_as_generated(vars) when is_list(vars) do\n    Enum.map(vars, fn {name, meta, context} -> {name, [generated: true] ++ meta, context} end)\n  end\n\n  defp mark_as_generated({name, meta, context}), do: {name, [generated: true] ++ meta, context}\n  defp mark_as_generated(other), do: other\n\n  @doc false\n  def __expand_pattern__({:when, meta, [left, right]}, caller) do\n    left = expand_pattern(left, Macro.Env.to_match(caller))\n    right = expand_pattern(right, %{caller | context: :guard})\n    {:when, meta, [left, right]}\n  end\n\n  def __expand_pattern__(expr, caller) do\n    expand_pattern(expr, Macro.Env.to_match(caller))\n  end\n\n  defp expand_pattern({:quote, _, [_]} = expr, _caller), do: expr\n  defp expand_pattern({:quote, _, [_, _]} = expr, _caller), do: expr\n  defp expand_pattern({:__aliases__, _, _} = expr, caller), do: Macro.expand(expr, caller)\n\n  defp expand_pattern({:@, _, [{attribute, _, _}]}, caller) do\n    caller.module |> Module.get_attribute(attribute) |> Macro.escape()\n  end\n\n  defp expand_pattern({left, meta, right} = expr, caller) do\n    case Macro.expand(expr, caller) do\n      ^expr ->\n        {expand_pattern(left, caller), meta, expand_pattern(right, caller)}\n\n      {left, meta, right} ->\n        {expand_pattern(left, caller), [original: expr] ++ meta, expand_pattern(right, caller)}\n\n      other ->\n        other\n    end\n  end\n\n  defp expand_pattern({left, right}, caller) do\n    {expand_pattern(left, caller), expand_pattern(right, caller)}\n  end\n\n  defp expand_pattern([_ | _] = list, caller) do\n    Enum.map(list, &expand_pattern(&1, caller))\n  end\n\n  defp expand_pattern(other, _caller), do: other\n\n  defp suppress_warning({name, meta, [expr, [do: clauses]]}) do\n    clauses =\n      Enum.map(clauses, fn {:->, meta, args} ->\n        {:->, [generated: true] ++ meta, args}\n      end)\n\n    {name, meta, [expr, [do: clauses]]}\n  end\n\n  @doc ~S\"\"\"\n  Asserts the `exception` is raised during `function` execution with\n  the expected `message`, which can be a `Regex` or an exact `String`.\n  Returns the rescued exception, fails otherwise.\n\n  ## Examples\n\n      assert_raise ArithmeticError, \"bad argument in arithmetic expression\", fn ->\n        1 / 0\n      end\n\n      assert_raise RuntimeError, ~r/^today's lucky number is 0\\.\\d+!$/, fn ->\n        raise \"today's lucky number is #{:rand.uniform()}!\"\n      end\n\n  \"\"\"\n  def assert_raise(exception, message, function) when is_function(function) do\n    error = assert_raise(exception, function)\n\n    match? =\n      cond do\n        is_binary(message) -> Exception.message(error) == message\n        is_struct(message, Regex) -> Exception.message(error) =~ message\n      end\n\n    message =\n      \"Wrong message for #{inspect(exception)}\\n\" <>\n        \"expected:\\n  #{inspect(message)}\\n\" <>\n        \"actual:\\n\" <> \"  #{inspect(Exception.message(error))}\"\n\n    if not match?, do: flunk(message)\n\n    error\n  end\n\n  @doc \"\"\"\n  Asserts the `exception` is raised during `function` execution.\n  Returns the rescued exception, fails otherwise.\n\n  ## Examples\n\n      assert_raise ArithmeticError, fn ->\n        1 + \"test\"\n      end\n\n      assert_raise RuntimeError, fn ->\n        raise \"assertion will pass due to this raise\"\n      end\n\n  \"\"\"\n  def assert_raise(exception, function) when is_function(function) do\n    try do\n      function.()\n    rescue\n      error ->\n        name = error.__struct__\n\n        cond do\n          name == exception ->\n            check_error_message(name, error)\n            error\n\n          name == ExUnit.AssertionError ->\n            reraise(error, __STACKTRACE__)\n\n          true ->\n            message =\n              \"Expected exception #{inspect(exception)} \" <>\n                \"but got #{inspect(name)} (#{Exception.message(error)})\"\n\n            reraise ExUnit.AssertionError, [message: message], __STACKTRACE__\n        end\n    else\n      _ -> flunk(\"Expected exception #{inspect(exception)} but nothing was raised\")\n    end\n  end\n\n  defp check_error_message(module, error) do\n    module.message(error)\n  catch\n    kind, reason ->\n      message =\n        \"Got exception #{inspect(module)} but it failed to produce a message with:\\n\\n\" <>\n          Exception.format(kind, reason, __STACKTRACE__)\n\n      flunk(message)\n  end\n\n  @doc \"\"\"\n  Asserts that `value1` and `value2` differ by no more than `delta`.\n\n  This difference is inclusive, so the test will pass if the difference\n  and the `delta` are equal.\n\n  ## Examples\n\n      assert_in_delta 1.1, 1.5, 0.2\n      assert_in_delta 10, 15, 2\n      assert_in_delta 10, 15, 5\n\n  \"\"\"\n  def assert_in_delta(value1, value2, delta, message \\\\ nil)\n\n  def assert_in_delta(_, _, delta, _) when delta < 0 do\n    raise ArgumentError, \"delta must always be a positive number, got: #{inspect(delta)}\"\n  end\n\n  def assert_in_delta(value1, value2, delta, message) do\n    diff = abs(value1 - value2)\n\n    message =\n      message ||\n        \"Expected the difference between #{inspect(value1)} and \" <>\n          \"#{inspect(value2)} (#{inspect(diff)}) to be less than or equal to #{inspect(delta)}\"\n\n    assert diff <= delta, message\n  end\n\n  @doc \"\"\"\n  Asserts `expression` will throw a value.\n\n  Returns the thrown value or fails otherwise.\n\n  ## Examples\n\n      assert catch_throw(throw(1)) == 1\n\n  \"\"\"\n  defmacro catch_throw(expression) do\n    do_catch(:throw, expression)\n  end\n\n  @doc \"\"\"\n  Asserts `expression` will exit.\n\n  Returns the exit status/message of the current process or fails otherwise.\n\n  ## Examples\n\n      assert catch_exit(exit(1)) == 1\n\n  To assert exits from linked processes started from the test, trap exits\n  with `Process.flag/2` and assert the exit message with `assert_receive/2`.\n\n      Process.flag(:trap_exit, true)\n      pid = spawn_link(fn -> Process.exit(self(), :normal) end)\n      assert_receive {:EXIT, ^pid, :normal}\n\n  \"\"\"\n  defmacro catch_exit(expression) do\n    do_catch(:exit, expression)\n  end\n\n  @doc \"\"\"\n  Asserts `expression` will cause an error.\n\n  Returns the error or fails otherwise.\n\n  ## Examples\n\n      assert catch_error(error(1)) == 1\n\n  \"\"\"\n  defmacro catch_error(expression) do\n    do_catch(:error, expression)\n  end\n\n  defp do_catch(kind, expr) do\n    quote do\n      try do\n        _ = unquote(mark_as_generated(expr))\n        flunk(\"Expected to catch #{unquote(kind)}, got nothing\")\n      rescue\n        e in [ExUnit.AssertionError] ->\n          reraise(e, __STACKTRACE__)\n      catch\n        unquote(kind), we_got -> we_got\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Asserts `value` is `nil` or `false` (that is, `value` is not truthy).\n\n  ## Examples\n\n      refute true, \"This will obviously fail\"\n\n  \"\"\"\n  def refute(value, message) do\n    not assert(!value, message)\n  end\n\n  @doc \"\"\"\n  Asserts that a message matching `pattern` was not received (and won't be received)\n  within the `timeout` period, specified in milliseconds.\n\n  The `pattern` argument must be a match pattern. Flunks with `failure_message`\n  if a message matching `pattern` is received.\n\n  ## Examples\n\n      refute_receive :bye\n\n  Refute received with an explicit timeout:\n\n      refute_receive :bye, 1000\n\n  \"\"\"\n  defmacro refute_receive(pattern, timeout \\\\ nil, failure_message \\\\ nil) do\n    do_refute_receive(pattern, timeout, failure_message)\n  end\n\n  @doc \"\"\"\n  Asserts a message matching `pattern` was not received (i.e. it is not in the\n  current process' mailbox).\n\n  The `pattern` argument must be a match pattern. Flunks with `failure_message`\n  if a message matching `pattern` was received.\n\n  Timeout is set to `0`, so there is no waiting time.\n\n  ## Examples\n\n      send(self(), :hello)\n      refute_received :bye\n\n      send(self(), :hello)\n      refute_received :hello, \"Oh No!\"\n      ** (ExUnit.AssertionError) Oh No!\n\n  \"\"\"\n  defmacro refute_received(pattern, failure_message \\\\ nil) do\n    do_refute_receive(pattern, 0, failure_message)\n  end\n\n  defp do_refute_receive(pattern, timeout, failure_message) do\n    receive_clause = refute_receive_clause(pattern, failure_message)\n\n    quote do\n      timeout = ExUnit.Assertions.__timeout__(unquote(timeout), :refute_receive_timeout)\n\n      receive do\n        unquote(receive_clause)\n      after\n        timeout -> false\n      end\n    end\n  end\n\n  defp refute_receive_clause(pattern, nil) do\n    binary = Macro.to_string(pattern)\n\n    quote do\n      unquote(pattern) = actual ->\n        flunk(\n          \"Unexpectedly received message #{inspect(actual)} (which matched #{unquote(binary)})\"\n        )\n    end\n  end\n\n  defp refute_receive_clause(pattern, failure_message) do\n    quote do\n      unquote(pattern) -> flunk(unquote(failure_message))\n    end\n  end\n\n  @doc \"\"\"\n  Asserts `value1` and `value2` are not within `delta`.\n\n  This difference is exclusive, so the test will fail if the difference\n  and the delta are equal.\n\n  If you supply `message`, information about the values will\n  automatically be appended to it.\n\n  ## Examples\n\n      refute_in_delta 1.1, 1.2, 0.2\n      refute_in_delta 10, 11, 2\n\n  \"\"\"\n  def refute_in_delta(value1, value2, delta, message \\\\ nil) do\n    diff = abs(value1 - value2)\n\n    message =\n      if message do\n        message <>\n          \" (difference between #{inspect(value1)} \" <>\n          \"and #{inspect(value2)} is less than #{inspect(delta)})\"\n      else\n        \"Expected the difference between #{inspect(value1)} and \" <>\n          \"#{inspect(value2)} (#{inspect(diff)}) to be more than #{inspect(delta)}\"\n      end\n\n    refute diff < delta, message\n  end\n\n  @doc \"\"\"\n  Fails with a message.\n\n  ## Examples\n\n      flunk(\"This should raise an error\")\n\n  \"\"\"\n  @spec flunk :: no_return\n  @spec flunk(String.t()) :: no_return\n  def flunk(message \\\\ \"Flunked!\") when is_binary(message) do\n    raise ExUnit.AssertionError, message\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/callbacks.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.Callbacks do\n  @moduledoc ~S\"\"\"\n  Defines ExUnit callbacks.\n\n  This module defines the `setup/1`, `setup/2`, `setup_all/1`, and\n  `setup_all/2` macros, as well as process lifecycle and management\n  functions, such as `on_exit/2`, `start_supervised/2`, `stop_supervised/1`\n  and `start_link_supervised!/2`.\n\n  The setup callbacks may be used to define [test fixtures](https://en.wikipedia.org/wiki/Test_fixture#Software)\n  and run any initialization code which help bring the system into a known\n  state. They are defined via macros and each one can optionally receive a map\n  with test state and metadata, usually referred to as the `context`.\n  Optionally, the context to be used in the tests can be extended by the\n  setup callbacks by returning a properly structured value (see below).\n\n  The `setup_all` callbacks are invoked only once per module, before any\n  test is run. All `setup` callbacks are run before each test. No callback\n  is run if the test case has no tests or all tests have been filtered out.\n\n  `setup` and `setup_all` callbacks can be defined by either a block, an atom\n  naming a local function, a `{module, function}` tuple, or a list of atoms/tuples.\n\n  Both can opt to receive the current context by specifying it\n  as a parameter if defined by a block. Functions used to define a test\n  setup must accept the context as a single argument.\n\n  A test module can define multiple `setup` and `setup_all` callbacks,\n  and they are invoked in order of appearance.\n\n  `start_supervised/2` is used to start processes under a supervisor. The\n  supervisor is linked to the current test process. The supervisor as well\n  as all child processes are guaranteed to terminate before any `on_exit/2`\n  callback runs.\n\n  `on_exit/2` callbacks are registered on demand, usually to undo an action\n  performed by a setup callback. `on_exit/2` may also take a reference,\n  allowing the callback to be overridden in the future. A registered `on_exit/2`\n  callback will always run, while failures in `setup` and `setup_all` will stop\n  all remaining setup callbacks from executing.\n\n  Finally, `setup_all` callbacks run in a separate process per module, while\n  all `setup` callbacks run in the same process as the test itself. `on_exit/2`\n  callbacks always run in a separate process, as implied by their name. The\n  test process always exits with reason `:shutdown`, which means any process\n  linked to the test process will also exit, although asynchronously. Therefore\n  it is preferred to use `start_supervised/2` to guarantee synchronous termination.\n\n  Here is a rundown of the life cycle of the test process:\n\n    1. the test process is spawned\n    2. it runs `setup/2` callbacks\n    3. it runs the test itself\n    4. it stops all supervised processes\n    5. the test process exits with reason `:shutdown`\n    6. `on_exit/2` callbacks are executed in a separate process\n\n  ## Context\n\n  `setup_all` or `setup` may return one of:\n\n    * the atom `:ok`\n    * a keyword list or map\n    * a tuple in the shape of `{:ok, keyword() | map()}`\n\n  If a keyword list or map is returned, it will be merged into the current context\n  and will be available in all subsequent `setup_all`, `setup`, and the `test`\n  itself.\n\n  Returning anything else from `setup_all` will force all tests to fail,\n  while a bad response from `setup` causes the current test to fail.\n\n  ## Examples\n\n      defmodule AssertionTest do\n        use ExUnit.Case, async: true\n\n        # \"setup_all\" is called once per module before any test runs\n        setup_all do\n          IO.puts(\"Starting AssertionTest\")\n\n          # Context is not updated here\n          :ok\n        end\n\n        # \"setup\" is called before each test\n        setup do\n          IO.puts(\"This is a setup callback for #{inspect(self())}\")\n\n          on_exit(fn ->\n            IO.puts(\"This is invoked once the test is done. Process: #{inspect(self())}\")\n          end)\n\n          # Returns extra metadata to be merged into context.\n          # Any of the following would also work:\n          #\n          #     {:ok, %{hello: \"world\"}}\n          #     {:ok, [hello: \"world\"]}\n          #     %{hello: \"world\"}\n          #\n          [hello: \"world\"]\n        end\n\n        # Same as above, but receives the context as argument\n        setup context do\n          IO.puts(\"Setting up: #{context.test}\")\n\n          # We can simply return :ok when we don't want to add any extra metadata\n          :ok\n        end\n\n        # Setups can also invoke a local or imported function that returns a context\n        setup :invoke_local_or_imported_function\n\n        test \"always pass\" do\n          assert true\n        end\n\n        test \"uses metadata from setup\", context do\n          assert context[:hello] == \"world\"\n          assert context[:from_named_setup] == true\n        end\n\n        defp invoke_local_or_imported_function(context) do\n          [from_named_setup: true]\n        end\n      end\n\n  It is also common to define your setup as a series of functions,\n  which are put together by calling `setup` or `setup_all` with a\n  list of function names. Each of these functions receive the context and can\n  return any of the values allowed in `setup` blocks:\n\n      defmodule ExampleContextTest do\n        use ExUnit.Case\n\n        setup [:step1, :step2, :step3, {OtherModule, :step4}]\n\n        defp step1(_context), do: [step_one: true]\n        defp step2(_context), do: {:ok, step_two: true} # return values with shape of {:ok, keyword() | map()} allowed\n        defp step3(_context), do: :ok # Context not modified\n\n        test \"context was modified\", context do\n          assert context[:step_one] == true\n          assert context[:step_two] == true\n        end\n      end\n\n  Finally, as discussed in the `ExUnit.Case` documentation, remember\n  that the initial context metadata can also be set via `@tag`s, which\n  can then be accessed in the `setup` block:\n\n      defmodule ExampleTagModificationTest do\n        use ExUnit.Case\n\n        setup %{login_as: username} do\n          {:ok, current_user: username}\n        end\n\n        @tag login_as: \"max\"\n        test \"tags modify context\", context do\n          assert context[:login_as] == \"max\"\n          assert context[:current_user] == \"max\"\n        end\n      end\n  \"\"\"\n\n  @type child_spec_overrides :: Supervisor.child_spec_overrides()\n\n  @doc false\n  def __register__(module) do\n    Module.put_attribute(module, :ex_unit_describe, nil)\n    Module.put_attribute(module, :ex_unit_setup, [])\n    Module.put_attribute(module, :ex_unit_setup_all, [])\n    Module.put_attribute(module, :ex_unit_used_describes, %{})\n  end\n\n  @doc false\n  def __callbacks__(module) do\n    setup = Module.get_attribute(module, :ex_unit_setup)\n    setup_all = Module.get_attribute(module, :ex_unit_setup_all)\n    used_describes = Module.get_attribute(module, :ex_unit_used_describes)\n\n    code =\n      quote do\n        unquote(compile_setup(:setup, setup, used_describes))\n        unquote(compile_setup(:setup_all, setup_all, %{}))\n      end\n\n    {setup_all != [], code}\n  end\n\n  @doc false\n  defmacro __before_compile__(%{module: module}) do\n    __callbacks__(module)\n  end\n\n  @doc \"\"\"\n  Defines a callback to be run before each test in a case.\n\n  Accepts one of these:\n\n    * a block\n    * an atom naming a local function\n    * a `{module, function}` tuple\n    * a list of atoms and `{module, function}` tuples\n\n  Can return values to be merged into the context, to set up the state for\n  tests. For more details, see the \"Context\" section shown above.\n\n  `setup/1` callbacks are executed in the same process as the test process.\n\n  ## Examples\n\n      defp clean_up_tmp_directory(context) do\n        # perform setup\n        :ok\n      end\n\n      setup :clean_up_tmp_directory\n\n      setup [:clean_up_tmp_directory, :another_setup]\n\n      setup do\n        [conn: Plug.Conn.build_conn()]\n      end\n\n      setup {MyModule, :my_setup_function}\n\n  \"\"\"\n  defmacro setup(block_or_functions) do\n    if Keyword.keyword?(block_or_functions) do\n      do_setup(quote(do: _), block_or_functions)\n    else\n      quote do\n        ExUnit.Callbacks.__setup__(__MODULE__, unquote(block_or_functions))\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Defines a callback to be run before each test in a case.\n\n  This is similar to `setup/1`, but the first argument is the context.\n  The `block` argument can only be a block.\n\n  For more details, see the \"Context\" section shown above.\n\n  ## Examples\n\n      setup context do\n        [conn: Plug.Conn.build_conn()]\n      end\n\n  \"\"\"\n  defmacro setup(context, block) do\n    if not (Keyword.keyword?(block) and Keyword.has_key?(block, :do)) do\n      raise ArgumentError,\n            \"setup/2 requires a block as the second argument after the context, got: #{Macro.to_string(block)}\"\n    end\n\n    do_setup(context, block)\n  end\n\n  defp do_setup(context, block) do\n    quote bind_quoted: [context: escape(context), block: escape(block)] do\n      name = ExUnit.Callbacks.__setup__(__MODULE__)\n      defp unquote(name)(unquote(context)), unquote(block)\n    end\n  end\n\n  @doc false\n  def __setup__(module, callbacks) do\n    setup = Module.get_attribute(module, :ex_unit_setup)\n\n    Module.put_attribute(\n      module,\n      :ex_unit_setup,\n      Enum.reverse(validate_callbacks!(callbacks), setup)\n    )\n  end\n\n  @doc false\n  def __setup__(module) do\n    setup = Module.get_attribute(module, :ex_unit_setup)\n\n    name =\n      case Module.get_attribute(module, :ex_unit_describe) do\n        {_line, _message, counter} -> :\"__ex_unit_setup_#{counter}_#{length(setup)}\"\n        nil -> :\"__ex_unit_setup_#{length(setup)}\"\n      end\n\n    Module.put_attribute(module, :ex_unit_setup, [name | setup])\n    name\n  end\n\n  @doc \"\"\"\n  Defines a callback to be run before all tests in a case.\n\n  Accepts one of these:\n\n    * a block\n    * an atom naming a local function\n    * a `{module, function}` tuple\n    * a list of atoms and `{module, function}` tuples\n\n  Can return values to be merged into the `context`, to set up the state for\n  tests. For more details, see the \"Context\" section shown above.\n\n  `setup_all/1` callbacks are executed in a separate process than tests.\n  All `setup_all/1` callbacks are executed in order in the same process.\n\n  ## On-Exit Handlers\n\n  On-exit handlers that you register inside `setup_all/1` callbacks\n  are executed at once after all tests in the module have been run.\n  They are all executed *in the same process*, which is a separate\n  process dedicated to running these handlers. These handlers are\n  executed in the reverse order of their respective `setup_all/1`\n  callbacks.\n\n  ## Examples\n\n      # One-arity function name\n      setup_all :clean_up_tmp_directory\n\n      # A module and function\n      setup_all {MyModule, :my_setup_function}\n\n      # A list of one-arity functions and module/function tuples\n      setup_all [:clean_up_tmp_directory, {MyModule, :my_setup_function}]\n\n      defp clean_up_tmp_directory(_context) do\n        # perform setup\n        :ok\n      end\n\n      # A block\n      setup_all do\n        [conn: Plug.Conn.build_conn()]\n      end\n\n  The context returned by `setup_all/1` will be available in all subsequent\n  `setup_all`, `setup`, and the `test` itself. For instance, the `conn` from\n  the previous example can be accessed as:\n\n      test \"fetches current users\", %{conn: conn} do\n        # ...\n      end\n\n  ### Handlers\n\n  You can define \"global\" on-exit handlers in `setup_all/1` callbacks:\n\n      setup_all do\n        Database.create_table_for(__MODULE__)\n\n        on_exit(fn ->\n          Database.drop_table_for(__MODULE__)\n        end)\n\n        :ok\n      end\n\n  The handler in the example above will be executed only once, after\n  running all tests in the module.\n  \"\"\"\n  defmacro setup_all(block) do\n    if Keyword.keyword?(block) do\n      do_setup_all(quote(do: _), block)\n    else\n      quote do\n        ExUnit.Callbacks.__setup_all__(__MODULE__, unquote(block))\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Defines a callback to be run before all tests in a case.\n\n  Similar as `setup_all/1` but also takes a context. The second argument\n  must be a block. See the \"Context\" section in the module documentation.\n\n  ## Examples\n\n      setup_all _context do\n        [conn: Plug.Conn.build_conn()]\n      end\n\n  \"\"\"\n  defmacro setup_all(context, block) do\n    if not (Keyword.keyword?(block) and Keyword.has_key?(block, :do)) do\n      raise ArgumentError,\n            \"setup_all/2 requires a block as the second argument after the context, got: #{Macro.to_string(block)}\"\n    end\n\n    do_setup_all(context, block)\n  end\n\n  defp do_setup_all(context, block) do\n    quote bind_quoted: [context: escape(context), block: escape(block)] do\n      name = ExUnit.Callbacks.__setup_all__(__MODULE__)\n      defp unquote(name)(unquote(context)), unquote(block)\n    end\n  end\n\n  @doc false\n  def __setup_all__(module, callbacks) do\n    no_describe!(module)\n    setup_all = Module.get_attribute(module, :ex_unit_setup_all)\n\n    Module.put_attribute(\n      module,\n      :ex_unit_setup_all,\n      Enum.reverse(validate_callbacks!(callbacks), setup_all)\n    )\n  end\n\n  @doc false\n  def __setup_all__(module) do\n    no_describe!(module)\n    setup_all = Module.get_attribute(module, :ex_unit_setup_all)\n    name = :\"__ex_unit_setup_all_#{length(setup_all)}\"\n    Module.put_attribute(module, :ex_unit_setup_all, [name | setup_all])\n    name\n  end\n\n  defp no_describe!(module) do\n    if Module.get_attribute(module, :ex_unit_describe) do\n      raise \"cannot invoke setup_all/1-2 inside describe as setup_all \" <>\n              \"always applies to all tests in a module\"\n    end\n  end\n\n  defp validate_callbacks!(callbacks) do\n    for k <- List.wrap(callbacks) do\n      case k do\n        {mod, fun} when is_atom(mod) and is_atom(fun) ->\n          {mod, fun}\n\n        name when is_atom(name) ->\n          name\n\n        invalid ->\n          raise ArgumentError,\n                \"setup/setup_all expect a callback as an atom, \" <>\n                  \"a {module, function} tuple or a list of callbacks, got: \" <>\n                  inspect(invalid)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Registers a callback that runs once the test exits.\n\n  `callback` is a function that receives no arguments and\n  runs in a separate process than the caller. Its return\n  value is irrelevant and is discarded.\n\n  `on_exit/2` is usually called from `setup/1` and `setup_all/1`\n  callbacks, often to undo the action performed during the setup.\n\n  However, `on_exit/2` may also be called dynamically. An \"ID\" (the\n  `name_or_ref` argument) can be used to guarantee that the callback\n  will be invoked only once. ExUnit uses this term to identify an\n  `on_exit/2` handler: if you want to override a previous handler, for\n  example, use the same `name_or_ref` across multiple `on_exit/2`\n  calls.\n\n  If `on_exit/2` is called inside `setup/1` or inside a test, it's\n  executed in a blocking fashion after the test exits and *before\n  running the next test*. This means that no other test from the same\n  test case will be running while the `on_exit/2` callback for a\n  previous test is running. `on_exit/2` is executed in a different\n  process than the test process. On the other hand, if `on_exit/2` is\n  called inside a `setup_all/1` callback then `callback` is executed\n  after running *all tests* (see `setup_all/1` for more information).\n\n  ## Examples\n\n      setup do\n        File.write!(\"fixture.json\", \"{}\")\n        on_exit(fn -> File.rm!(\"fixture.json\") end)\n      end\n\n  You can use the same `name_or_ref` across multiple `on_exit/2` calls\n  to \"override\" the registered handler:\n\n      setup do\n        on_exit(:drop_table, fn ->\n          Database.drop_table()\n        end)\n      end\n\n      test \"a test that shouldn't drop the table\" do\n        on_exit(:drop_table, fn -> :ok end)\n      end\n\n  Relying too much on overriding callbacks like this can lead to test\n  cases that are hard to understand and with too many layers of\n  indirection. However, it can be useful in some cases or for library\n  authors, for example.\n  \"\"\"\n  @spec on_exit(term, (-> term)) :: :ok\n  def on_exit(name_or_ref \\\\ make_ref(), callback) when is_function(callback, 0) do\n    case ExUnit.OnExitHandler.add(self(), name_or_ref, callback) do\n      :ok ->\n        :ok\n\n      :error ->\n        raise ArgumentError, \"on_exit/2 callback can only be invoked from the test process\"\n    end\n  end\n\n  @doc \"\"\"\n  Starts a child process under the test supervisor.\n\n  It expects a child specification or a module, similar to the ones\n  given to `Supervisor.start_link/2`. For example, if your application\n  starts a supervision tree by running:\n\n      Supervisor.start_link([MyServer, {OtherSupervisor, ...}], ...)\n\n  You can start those processes under test in isolation by running:\n\n      start_supervised(MyServer)\n      start_supervised({OtherSupervisor, :initial_value})\n\n  A keyword list can also be given if there is a need to change\n  the child specification for the given child process:\n\n      start_supervised({MyServer, :initial_value}, restart: :temporary)\n\n  See the `Supervisor` module for a discussion on child specifications\n  and the available specification keys.\n\n  The started process is not linked to the test process and a crash will\n  not necessarily fail the test. To start and link a process to guarantee\n  that any crash would also fail the test use `start_link_supervised!/2`.\n\n  This function returns `{:ok, pid}` in case of success, otherwise it\n  returns `{:error, reason}`.\n\n  The advantage of starting a process under the test supervisor is that\n  it is guaranteed to exit before the next test starts. Therefore, you\n  don't need to remove the process at the end of your tests via\n  `stop_supervised/1`. You only need to use `stop_supervised/1 ` if you\n  want to remove a process from the supervision tree in the middle of a\n  test, as simply shutting down the process would cause it to be restarted\n  according to its `:restart` value.\n\n  Finally, since Elixir v1.17.0, the test supervisor has both `$ancestors`\n  and `$callers` key in its process dictionary pointing to the test process.\n  This means developers can invoke `Process.get(:\"$callers\", [])` in their\n  `start_link` function and forward it to the spawned process, which may set\n  `Process.put(:\"$callers\", callers)` during its initialization. This may be\n  useful in projects who track process ownership during tests. You can learn\n  more about these keys in [the `Task` module](`Task#module-ancestor-and-caller-tracking`).\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec start_supervised(Supervisor.child_spec() | module | {module, term}, child_spec_overrides) ::\n          Supervisor.on_start_child()\n  def start_supervised(child_spec_or_module, opts \\\\ []) do\n    sup =\n      case ExUnit.fetch_test_supervisor() do\n        {:ok, sup} ->\n          sup\n\n        :error ->\n          raise ArgumentError, \"start_supervised/2 can only be invoked from the test process\"\n      end\n\n    child_spec = Supervisor.child_spec(child_spec_or_module, opts)\n    Supervisor.start_child(sup, child_spec)\n  end\n\n  @doc \"\"\"\n  Same as `start_supervised/2` but returns the PID on success and raises if\n  not started properly.\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec start_supervised!(Supervisor.child_spec() | module | {module, term}, child_spec_overrides) ::\n          pid\n  def start_supervised!(child_spec_or_module, opts \\\\ []) do\n    case start_supervised(child_spec_or_module, opts) do\n      {:ok, pid} ->\n        pid\n\n      {:ok, pid, _info} ->\n        pid\n\n      {:error, reason} ->\n        raise \"failed to start child with the spec #{inspect(child_spec_or_module)}.\\n\" <>\n                \"Reason: #{start_supervised_error(reason)}\"\n    end\n  end\n\n  defp start_supervised_error({{:EXIT, reason}, info}) when is_tuple(info),\n    do: Exception.format_exit(reason)\n\n  defp start_supervised_error({reason, info}) when is_tuple(info),\n    do: Exception.format_exit(reason)\n\n  defp start_supervised_error(reason), do: Exception.format_exit({:start_spec, reason})\n\n  @doc \"\"\"\n  Same as `start_supervised!/2` but links the started process to the test process.\n\n  If the process that was started crashes, the crash is propagated to the test process,\n  failing the test and printing the cause of the crash.\n\n  Note that if the started process terminates before it is linked to the test process,\n  this function will exit with reason `:noproc`.\n\n  > #### To link or not to link {: .warning}\n  >\n  > When using `start_link_supervised!/2`, the test process will be linked to the\n  > spawned processes. When the test process exits, it exits with reason `:shutdown`,\n  > and the crash signal propagates to all linked processes virtually simultaneously,\n  > which can lead to processes terminating in an unpredictable order if they are not\n  > trapping exits. This is particularly problematic when you have processes that the\n  > test starts with `start_link_supervised!/2` and that depend on each other.\n  >\n  > If you need guaranteed shutdown order, use `start_supervised!/2`. This way the\n  > test process exiting does not affect the started processes, and they will be shut down\n  > *by the test supervisor* in reverse order, ensuring graceful termination.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec start_link_supervised!(\n          Supervisor.child_spec() | module | {module, term},\n          child_spec_overrides\n        ) ::\n          pid\n  def start_link_supervised!(child_spec_or_module, opts \\\\ []) do\n    pid = start_supervised!(child_spec_or_module, opts)\n    Process.link(pid)\n    pid\n  end\n\n  @doc \"\"\"\n  Stops a child process started via `start_supervised/2`.\n\n  This function expects the `id` in the child specification.\n  For example:\n\n      {:ok, _} = start_supervised(MyServer)\n      :ok = stop_supervised(MyServer)\n\n  It returns `:ok` if there is a supervised process with such\n  `id`, `{:error, :not_found}` otherwise.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec stop_supervised(id :: term()) :: :ok | {:error, :not_found}\n  def stop_supervised(id) do\n    case ExUnit.OnExitHandler.get_supervisor(self()) do\n      {:ok, nil} ->\n        {:error, :not_found}\n\n      {:ok, sup} ->\n        pid = pid_for_child(sup, id)\n\n        if pid do\n          Process.unlink(pid)\n        end\n\n        with :ok <- Supervisor.terminate_child(sup, id) do\n          # If the terminated child was temporary, delete_child returns {:error, :not_found}.\n          # Since the child was successfully terminated, we treat this result as a success.\n          true = Supervisor.delete_child(sup, id) in [:ok, {:error, :not_found}]\n          :ok\n        end\n\n      :error ->\n        raise ArgumentError, \"stop_supervised/1 can only be invoked from the test process\"\n    end\n  end\n\n  defp pid_for_child(sup, id) do\n    children = Supervisor.which_children(sup)\n\n    with {_id, pid, _type, _modules} <- List.keyfind(children, id, 0) do\n      pid\n    end\n  end\n\n  @doc \"\"\"\n  Same as `stop_supervised/1` but raises if it cannot be stopped.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec stop_supervised!(id :: term()) :: :ok\n  def stop_supervised!(id) do\n    case stop_supervised(id) do\n      :ok ->\n        :ok\n\n      {:error, :not_found} ->\n        raise \"could not stop child ID #{inspect(id)} because it was not found\"\n    end\n  end\n\n  ## Helpers\n\n  @reserved [:case, :file, :line, :test, :async, :registered, :describe]\n\n  @doc false\n  def __callback__(callback, describe) do\n    for k <- List.wrap(callback) do\n      if not is_atom(k) do\n        raise ArgumentError,\n              \"setup/setup_all expect a callback name as an atom or \" <>\n                \"a list of callback names, got: #{inspect(k)}\"\n      end\n\n      {k, describe}\n    end\n    |> Enum.reverse()\n  end\n\n  @doc false\n  def __merge__(_mod, _kind, context, :ok) do\n    context\n  end\n\n  def __merge__(mod, kind, context, {:ok, value}) do\n    unwrapped_merge(mod, kind, context, value, {:ok, value})\n  end\n\n  def __merge__(mod, kind, context, value) do\n    unwrapped_merge(mod, kind, context, value, value)\n  end\n\n  defp unwrapped_merge(mod, kind, _context, %_{}, original_value) do\n    raise_merge_failed!(mod, kind, original_value)\n  end\n\n  defp unwrapped_merge(mod, kind, context, data, _original_value) when is_list(data) do\n    context_merge(mod, kind, context, Map.new(data))\n  end\n\n  defp unwrapped_merge(mod, kind, context, data, _original_value) when is_map(data) do\n    context_merge(mod, kind, context, data)\n  end\n\n  defp unwrapped_merge(mod, kind, _, _return_value, original_value) do\n    raise_merge_failed!(mod, kind, original_value)\n  end\n\n  defp context_merge(mod, kind, context, data) do\n    Map.merge(context, data, fn\n      k, v1, v2 when k in @reserved ->\n        if v1 == v2, do: v1, else: raise_merge_reserved!(mod, kind, k, v2)\n\n      _, _, v ->\n        v\n    end)\n  end\n\n  defp raise_merge_failed!(mod, kind, return_value) do\n    raise \"expected ExUnit #{kind} callback in #{inspect(mod)} to \" <>\n            \"return the atom :ok, a keyword, or a map, got #{inspect(return_value)} instead\"\n  end\n\n  defp raise_merge_reserved!(mod, kind, key, value) do\n    raise \"ExUnit #{kind} callback in #{inspect(mod)} is trying to set \" <>\n            \"reserved field #{inspect(key)} to #{inspect(value)}\"\n  end\n\n  defp escape(contents) do\n    Macro.escape(contents, unquote: true)\n  end\n\n  @doc false\n  def __describe__(module, line, message, fun) do\n    if Module.get_attribute(module, :ex_unit_describe) do\n      raise \"cannot call \\\"describe\\\" inside another \\\"describe\\\". See the documentation \" <>\n              \"for ExUnit.Case.describe/2 on named setups and how to handle hierarchies\"\n    end\n\n    used_describes = Module.get_attribute(module, :ex_unit_used_describes)\n\n    cond do\n      not is_binary(message) ->\n        raise ArgumentError, \"describe name must be a string, got: #{inspect(message)}\"\n\n      is_map_key(used_describes, message) ->\n        raise ArgumentError,\n              \"describe #{inspect(message)} is already defined in #{inspect(module)}\"\n\n      true ->\n        :ok\n    end\n\n    if Module.get_attribute(module, :describetag) != [] do\n      raise \"@describetag must be set inside describe/2 blocks\"\n    end\n\n    if Module.get_attribute(module, :tag) != [] do\n      IO.warn(\"found unused @tag before \\\"describe\\\", did you mean to use @describetag?\")\n    end\n\n    setup = Module.get_attribute(module, :ex_unit_setup)\n    Module.put_attribute(module, :ex_unit_setup, [])\n    Module.put_attribute(module, :ex_unit_describe, {line, message, map_size(used_describes)})\n\n    try do\n      fun.(message, used_describes)\n    after\n      Module.put_attribute(module, :ex_unit_describe, nil)\n      Module.put_attribute(module, :ex_unit_setup, setup)\n      Module.delete_attribute(module, :describetag)\n\n      for attribute <- Module.get_attribute(module, :ex_unit_registered_describe_attributes) do\n        Module.delete_attribute(module, attribute)\n      end\n    end\n  end\n\n  @doc false\n  def __describe__(module, message, used_describes) do\n    {name, body} =\n      case Module.get_attribute(module, :ex_unit_setup) do\n        [] ->\n          {nil, nil}\n\n        callbacks ->\n          {:\"__ex_unit_describe_#{map_size(used_describes)}\", compile_setup(callbacks, :setup)}\n      end\n\n    used_describes = Map.put(used_describes, message, name)\n    Module.put_attribute(module, :ex_unit_used_describes, used_describes)\n    {name, body}\n  end\n\n  defp compile_setup(kind, value, describes) do\n    calls = compile_setup(value, kind)\n\n    describe_clauses =\n      for {describe, callback} <- describes,\n          callback != nil,\n          clause <- quote(do: (unquote(describe) -> unquote(callback)(var!(context)))),\n          do: clause\n\n    body =\n      if describe_clauses == [] do\n        calls\n      else\n        describe_clauses =\n          describe_clauses ++\n            quote do\n              _ -> var!(context)\n            end\n\n        quote do\n          var!(context) = unquote(calls)\n          case Map.get(var!(context), :describe, nil), do: unquote(describe_clauses)\n        end\n      end\n\n    quote do\n      def __ex_unit__(unquote(kind), var!(context)), do: unquote(body)\n    end\n  end\n\n  defp compile_setup([], _kind) do\n    quote(do: var!(context))\n  end\n\n  defp compile_setup(callbacks, kind) do\n    [h | t] = Enum.reverse(callbacks)\n\n    Enum.reduce(t, compile_setup_call(h, kind), fn callback, acc ->\n      quote do\n        var!(context) = unquote(acc)\n        unquote(compile_setup_call(callback, kind))\n      end\n    end)\n  end\n\n  defp compile_setup_call(callback, kind) when is_atom(callback) do\n    quote do\n      result =\n        unquote(__MODULE__).__merge__(\n          __MODULE__,\n          unquote(kind),\n          var!(context),\n          unquote(callback)(var!(context))\n        )\n\n      ExUnit.Callbacks.__noop__()\n      result\n    end\n  end\n\n  defp compile_setup_call({module, callback}, kind) do\n    quote do\n      result =\n        unquote(__MODULE__).__merge__(\n          __MODULE__,\n          unquote(kind),\n          var!(context),\n          unquote(module).unquote(callback)(var!(context))\n        )\n\n      ExUnit.Callbacks.__noop__()\n      result\n    end\n  end\n\n  # We inject this into compiled setup/setup_all calls, to avoid tail-call optimization and get\n  # better stacktraces. See the comments in https://github.com/elixir-lang/elixir/pull/12382.\n  @doc false\n  def __noop__, do: :noop\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/capture_io.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.CaptureIO do\n  @moduledoc ~S\"\"\"\n  Functionality to capture IO for testing.\n\n  ## Examples\n\n      defmodule AssertionTest do\n        use ExUnit.Case\n\n        import ExUnit.CaptureIO\n\n        test \"example\" do\n          assert capture_io(fn -> IO.puts(\"a\") end) == \"a\\n\"\n        end\n\n        test \"another example\" do\n          assert with_io(fn ->\n            IO.puts(\"a\")\n            IO.puts(\"b\")\n            2 + 2\n          end) == {4, \"a\\nb\\n\"}\n        end\n      end\n\n  \"\"\"\n\n  @type capture_io_opts :: [\n          input: String.t(),\n          capture_prompt: boolean(),\n          encoding: :unicode | :latin1\n        ]\n\n  @doc \"\"\"\n  Captures IO generated when evaluating `fun`.\n\n  Returns the binary which is the captured output.\n\n  By default, `capture_io` replaces the `Process.group_leader/0` of the current\n  process, which is the process used by default for all IO operations. Capturing\n  the group leader of the current process is safe to run concurrently, under\n  `async: true` tests. You may also explicitly capture the group leader of\n  another process, however that is not safe to do concurrently.\n\n  You may also capture any other named IO device, such as `:stderr`. This is\n  also safe to run concurrently but, if several tests are writing to the same\n  device at once, captured output may include output from a different test.\n\n  A developer can set a string as an input. The default input is an empty\n  string. If capturing a named device asynchronously, an input can only be given\n  to the first capture. Any further capture that is given to a capture on that\n  device will raise an exception and would indicate that the test should be run\n  synchronously.\n\n  Similarly, once a capture on a named device has begun, the encoding on that\n  device cannot be changed in a subsequent concurrent capture. An error will\n  be raised in this case.\n\n  ## IO devices\n\n  You may capture the IO of the group leader of any process, by passing a `pid`\n  as argument, or from any registered IO device given as an `atom`. Here are\n  some example values:\n\n    * `:stdio`, `:standard_io` - a shortcut for capturing the group leader\n      of the current process. It is equivalent to passing `self()` as the\n      first argument. This is safe to run concurrently and captures only\n      the of the current process or any child process spawned inside the\n      given function\n\n    * `:stderr`, `:standard_error` - captures all IO to standard error\n      (represented internally by an Erlang process named `:standard_error`).\n      This is safe to run concurrently but it will capture the output\n      of any other test writing to the same named device\n\n    * any other atom - captures all IO to the given device given by the\n      atom. This is safe to run concurrently but it will capture the output\n      of any other test writing to the same named device\n\n    * any other pid (since v1.17.0) - captures all IO to the group leader\n      of the given process. This option is not safe to run concurrently\n      if the pid is not `self()`. Tests using this value must set `async: true`\n\n  ## Options\n\n    * `:input` - An input to the IO device, defaults to `\"\"`.\n\n    * `:capture_prompt` - Define if prompts (specified as arguments to\n      `IO.get*` functions) should be captured. Defaults to `true`. For\n      IO devices other than `:stdio`, the option is ignored.\n\n    * `:encoding` (since v1.10.0) - encoding of the IO device. Allowed\n      values are `:unicode` (default) and `:latin1`.\n\n  ## Examples\n\n  To capture the standard io:\n\n      iex> capture_io(fn -> IO.write(\"john\") end) == \"john\"\n      true\n\n      iex> capture_io(\"this is input\", fn ->\n      ...>   input = IO.gets(\"> \")\n      ...>   IO.write(input)\n      ...> end) == \"> this is input\"\n      true\n\n      iex> capture_io([input: \"this is input\", capture_prompt: false], fn ->\n      ...>   input = IO.gets(\"> \")\n      ...>   IO.write(input)\n      ...> end) == \"this is input\"\n      true\n\n  Note it is fine to use `==` with `:stdio` (the default IO device), because\n  the content is captured per test process. However, `:stderr` is shared\n  across all tests, so you will want to use `=~` instead of `==` for assertions\n  on `:stderr` if your tests are async:\n\n      iex> capture_io(:stderr, fn -> IO.write(:stderr, \"john\") end) =~ \"john\"\n      true\n\n      iex> capture_io(:standard_error, fn -> IO.write(:stderr, \"john\") end) =~ \"john\"\n      true\n\n  In particular, avoid empty captures on `:stderr` with async tests:\n\n      iex> capture_io(:stderr, fn -> :nothing end) == \"\"\n      true\n\n  Otherwise, if the standard error of any other test is captured, the test will\n  fail.\n\n  To capture the IO from another process, you can pass a `pid`:\n\n      capture_io(GenServer.whereis(MyServer), fn ->\n        GenServer.call(MyServer, :do_something)\n      end)\n\n  Tests that directly capture a PID cannot run concurrently.\n\n  ## Returning values\n\n  As seen in the examples above, `capture_io` returns the captured output.\n  If you want to also capture the result of the function executed,\n  use `with_io/2`.\n  \"\"\"\n  @spec capture_io((-> any())) :: String.t()\n  def capture_io(fun) when is_function(fun, 0) do\n    {_result, capture} = with_io(fun)\n    capture\n  end\n\n  @doc \"\"\"\n  Captures IO generated when evaluating `fun`.\n\n  See `capture_io/1` for more information.\n  \"\"\"\n  @spec capture_io(atom() | pid() | String.t() | capture_io_opts, (-> any())) :: String.t()\n  def capture_io(device_pid_input_or_options, fun)\n\n  def capture_io(device_or_pid, fun)\n      when (is_atom(device_or_pid) or is_pid(device_or_pid)) and is_function(fun, 0) do\n    {_result, capture} = with_io(device_or_pid, fun)\n    capture\n  end\n\n  def capture_io(input_or_options, fun)\n      when (is_binary(input_or_options) or is_list(input_or_options)) and is_function(fun, 0) do\n    {_result, capture} = with_io(input_or_options, fun)\n    capture\n  end\n\n  @doc \"\"\"\n  Captures IO generated when evaluating `fun`.\n\n  See `capture_io/1` for more information.\n  \"\"\"\n  @spec capture_io(atom() | pid(), String.t() | capture_io_opts, (-> any())) :: String.t()\n  def capture_io(device_or_pid, input_or_options, fun)\n      when (is_atom(device_or_pid) or is_pid(device_or_pid)) and\n             (is_binary(input_or_options) or is_list(input_or_options)) and is_function(fun, 0) do\n    {_result, capture} = with_io(device_or_pid, input_or_options, fun)\n    capture\n  end\n\n  @doc ~S\"\"\"\n  Invokes the given `fun` and returns the result and captured output.\n\n  It accepts the same arguments and options as `capture_io/1`.\n\n  ## Examples\n\n      {result, output} =\n        with_io(fn ->\n          IO.puts(\"a\")\n          IO.puts(\"b\")\n          2 + 2\n        end)\n\n      assert result == 4\n      assert output == \"a\\nb\\n\"\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec with_io((-> any())) :: {any(), String.t()}\n  def with_io(fun) when is_function(fun, 0) do\n    with_io(:stdio, [], fun)\n  end\n\n  @doc \"\"\"\n  Invokes the given `fun` and returns the result and captured output.\n\n  See `with_io/1` for more information.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec with_io(atom() | pid() | String.t() | capture_io_opts, (-> any())) :: {any(), String.t()}\n  def with_io(device_pid_input_or_options, fun)\n\n  def with_io(device, fun) when is_atom(device) and is_function(fun, 0) do\n    with_io(device, [], fun)\n  end\n\n  def with_io(pid, fun) when is_pid(pid) and is_function(fun, 0) do\n    with_io(pid, [], fun)\n  end\n\n  def with_io(input, fun) when is_binary(input) and is_function(fun, 0) do\n    with_io(:stdio, [input: input], fun)\n  end\n\n  def with_io(options, fun) when is_list(options) and is_function(fun, 0) do\n    with_io(:stdio, options, fun)\n  end\n\n  @doc \"\"\"\n  Invokes the given `fun` and returns the result and captured output.\n\n  See `with_io/1` for more information.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec with_io(atom() | pid(), String.t() | capture_io_opts, (-> any())) :: {any(), String.t()}\n  def with_io(device_or_pid, input_or_options, fun)\n\n  def with_io(device, input, fun)\n      when is_atom(device) and is_binary(input) and is_function(fun, 0) do\n    do_with_io(map_dev(device), [input: input], fun)\n  end\n\n  def with_io(device, options, fun)\n      when is_atom(device) and is_list(options) and is_function(fun, 0) do\n    do_with_io(map_dev(device), options, fun)\n  end\n\n  def with_io(pid, input, fun)\n      when is_pid(pid) and is_binary(input) and is_function(fun, 0) do\n    do_with_io(pid, [input: input], fun)\n  end\n\n  def with_io(pid, options, fun)\n      when is_pid(pid) and is_list(options) and is_function(fun, 0) do\n    do_with_io(pid, options, fun)\n  end\n\n  defp map_dev(:standard_io), do: self()\n  defp map_dev(:stdio), do: self()\n  defp map_dev(:stderr), do: :standard_error\n  defp map_dev(other), do: other\n\n  defp do_with_io(pid, options, fun) when is_pid(pid) do\n    prompt_config = Keyword.get(options, :capture_prompt, true)\n    encoding = Keyword.get(options, :encoding, :unicode)\n    input = Keyword.get(options, :input, \"\")\n\n    {:group_leader, original_gl} =\n      Process.info(pid, :group_leader) || {:group_leader, Process.group_leader()}\n\n    {:ok, capture_gl} = StringIO.open(input, capture_prompt: prompt_config, encoding: encoding)\n\n    try do\n      Process.group_leader(pid, capture_gl)\n      do_capture_gl(capture_gl, fun)\n    after\n      Process.group_leader(pid, original_gl)\n    end\n  end\n\n  defp do_with_io(device, options, fun) when is_atom(device) do\n    input = Keyword.get(options, :input, \"\")\n    encoding = Keyword.get(options, :encoding, :unicode)\n\n    case ExUnit.CaptureServer.device_capture_on(device, encoding, input) do\n      {:ok, ref} ->\n        try do\n          result = fun.()\n          {result, ExUnit.CaptureServer.device_output(device, ref)}\n        after\n          ExUnit.CaptureServer.device_capture_off(ref)\n        end\n\n      {:error, :no_device} ->\n        raise \"could not find IO device registered at #{inspect(device)}\"\n\n      {:error, {:changed_encoding, current_encoding}} ->\n        raise ArgumentError, \"\"\"\n        attempted to change the encoding for a currently captured device #{inspect(device)}.\n\n        Currently set as: #{inspect(current_encoding)}\n        Given: #{inspect(encoding)}\n\n        If you need to use multiple encodings on a captured device, you cannot \\\n        run your test asynchronously\n        \"\"\"\n\n      {:error, :input_on_already_captured_device} ->\n        raise ArgumentError,\n              \"attempted multiple captures on device #{inspect(device)} with input. \" <>\n                \"If you need to give an input to a captured device, you cannot run your test asynchronously\"\n    end\n  end\n\n  defp do_capture_gl(string_io, fun) do\n    try do\n      fun.()\n    catch\n      kind, reason ->\n        _ = StringIO.close(string_io)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      result ->\n        {:ok, {_input, output}} = StringIO.close(string_io)\n        {result, output}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/capture_log.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.CaptureLog do\n  @moduledoc ~S\"\"\"\n  Functionality to capture logs for testing.\n\n  ## Examples\n\n      defmodule AssertionTest do\n        use ExUnit.Case\n\n        import ExUnit.CaptureLog\n        require Logger\n\n        test \"example\" do\n          {result, log} =\n            with_log(fn ->\n              Logger.error(\"log msg\")\n              2 + 2\n            end)\n\n          assert result == 4\n          assert log =~ \"log msg\"\n        end\n\n        test \"check multiple captures concurrently\" do\n          fun = fn ->\n            for msg <- [\"hello\", \"hi\"] do\n              assert capture_log(fn -> Logger.error(msg) end) =~ msg\n            end\n\n            Logger.debug(\"testing\")\n          end\n\n          assert capture_log(fun) =~ \"hello\"\n          assert capture_log(fun) =~ \"testing\"\n        end\n      end\n\n  \"\"\"\n\n  @compile {:no_warn_undefined, Logger}\n\n  @type capture_log_opts :: [\n          {:level, Logger.level() | nil}\n          | {:formatter, {module(), term()} | nil}\n        ]\n\n  @doc \"\"\"\n  Captures Logger messages generated when evaluating `fun`.\n\n  Returns the binary which is the captured output. The captured log\n  messages will be formatted using `Logger.default_formatter/1` by\n  default. Any option, besides `:level` or `formatter`, will be\n  forwarded as an override to the default formatter.\n\n  This function mutes the default logger handler and captures any log\n  messages sent to Logger from the calling processes. It is possible\n  to ensure explicit log messages from other processes are captured\n  by waiting for their exit or monitor signal.\n\n  Note that when the `async` is set to `true` on `use ExUnit.Case`,\n  messages from other tests might be captured. This is OK as long\n  you consider such cases in your assertions, typically by using\n  the `=~/2` operator to perform partial matches.\n\n  It is possible to configure the level to capture with `:level`,\n  which will set the capturing level for the duration of the\n  capture, for instance, if the log level is set to `:error`, then\n  any message with the lower level will be ignored.\n  The default level is `nil`, which will capture all messages.\n  Note this setting does not override the overall `Logger.level/0` value.\n  Therefore, if `Logger.level/0` is set to a higher level than the one\n  configured in this function, no message will be captured.\n  The behaviour is undetermined if async tests change Logger level.\n\n  It is possible to use an alternative log formatter with `:formatter`,\n  which must be provided as `{module, config}`. If `:formatter` is not\n  provided, the formatter configuration from `Logger.default_formatter/1`\n  will be used.\n\n  To get the result of the evaluation along with the captured log,\n  use `with_log/2`.\n  \"\"\"\n  @spec capture_log(capture_log_opts, (-> any)) :: String.t()\n  def capture_log(opts \\\\ [], fun) do\n    {_, log} = with_log(opts, fun)\n    log\n  end\n\n  @doc \"\"\"\n  Invokes the given `fun` and returns the result and captured log.\n\n  It accepts the same arguments and options as `capture_log/2`.\n\n  ## Examples\n\n      {result, log} =\n        with_log(fn ->\n          Logger.error(\"log msg\")\n          2 + 2\n        end)\n\n      assert result == 4\n      assert log =~ \"log msg\"\n\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec with_log(capture_log_opts, (-> result)) :: {result, log :: String.t()} when result: any\n  def with_log(opts \\\\ [], fun) when is_list(opts) do\n    opts =\n      if opts[:level] == :warn do\n        IO.warn(\"level: :warn is deprecated, please use :warning instead\")\n        Keyword.put(opts, :level, :warning)\n      else\n        opts\n      end\n\n    {:ok, string_io} = StringIO.open(\"\")\n\n    try do\n      ref = ExUnit.CaptureServer.log_capture_on(self(), string_io, opts)\n\n      try do\n        fun.()\n      after\n        :ok = Logger.flush()\n        :ok = ExUnit.CaptureServer.log_capture_off(ref)\n      end\n    catch\n      kind, reason ->\n        _ = StringIO.close(string_io)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      result ->\n        {:ok, {_input, output}} = StringIO.close(string_io)\n        {result, output}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/capture_server.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.CaptureServer do\n  @moduledoc false\n  @compile {:no_warn_undefined, Logger}\n  @timeout :infinity\n  @name __MODULE__\n  @ets __MODULE__\n\n  use GenServer\n\n  def start_link(_opts) do\n    GenServer.start_link(__MODULE__, :ok, name: @name)\n  end\n\n  def device_capture_on(name, encoding, input) do\n    GenServer.call(@name, {:device_capture_on, name, encoding, input}, @timeout)\n  end\n\n  def device_output(name, ref) do\n    GenServer.call(@name, {:device_output, name, ref}, @timeout)\n  end\n\n  def device_capture_off(ref) do\n    GenServer.call(@name, {:device_capture_off, ref}, @timeout)\n  end\n\n  def log_capture_on(pid, string_io, opts) do\n    GenServer.call(@name, {:log_capture_on, pid, string_io, opts}, @timeout)\n  end\n\n  def log_capture_off(ref) do\n    GenServer.call(@name, {:log_capture_off, ref}, @timeout)\n  end\n\n  ## Callbacks\n\n  @impl true\n  def init(:ok) do\n    :ets.new(@name, [:named_table, :public, :set])\n\n    state = %{\n      devices: %{},\n      log_captures: %{},\n      log_status: :error\n    }\n\n    {:ok, state}\n  end\n\n  @impl true\n  def handle_call(call, from, state)\n\n  def handle_call({:device_capture_on, name, encoding, input}, {caller, _}, config) do\n    capture_device(name, encoding, input, config, caller)\n  end\n\n  def handle_call({:device_output, name, ref}, _from, config) do\n    device = Map.fetch!(config.devices, name)\n    {_, output} = StringIO.contents(device.pid)\n    total = byte_size(output)\n    {_pid, offset} = Map.fetch!(device.refs, ref)\n    output_size = total - offset\n    {:reply, binary_part(output, offset, output_size), config}\n  end\n\n  def handle_call({:device_capture_off, ref}, _from, config) do\n    {:reply, :ok, release_device(ref, config)}\n  end\n\n  def handle_call({:log_capture_on, pid, string_io, opts}, _from, config) do\n    ref = Process.monitor(pid)\n    refs = Map.put(config.log_captures, ref, true)\n\n    {level, opts} = Keyword.pop(opts, :level)\n\n    {formatter_mod, formatter_config} =\n      Keyword.get_lazy(opts, :formatter, fn -> Logger.default_formatter(opts) end)\n\n    true = :ets.insert(@ets, {ref, string_io, level || :all, formatter_mod, formatter_config})\n\n    if map_size(refs) == 1 do\n      :ok = :logger.add_handler(@name, __MODULE__, %{})\n\n      status =\n        with {:ok, config} <- :logger.get_handler_config(:default),\n             :ok <- :logger.remove_handler(:default) do\n          {:ok, config}\n        else\n          _ -> :error\n        end\n\n      {:reply, ref, %{config | log_captures: refs, log_status: status}}\n    else\n      {:reply, ref, %{config | log_captures: refs}}\n    end\n  end\n\n  def handle_call({:log_capture_off, ref}, _from, config) do\n    Process.demonitor(ref, [:flush])\n    config = remove_log_capture(ref, config)\n    {:reply, :ok, config}\n  end\n\n  @impl true\n  def handle_info({:DOWN, ref, _, _, _}, config) do\n    config = remove_log_capture(ref, config)\n    config = release_device(ref, config)\n    {:noreply, config}\n  end\n\n  defp capture_device(name, encoding, input, config, caller) do\n    case config.devices do\n      %{^name => device} ->\n        dead_refs = for {ref, {pid, _}} <- device.refs, not Process.alive?(pid), do: ref\n\n        case dead_refs do\n          [] ->\n            capture_existing_device(name, encoding, input, config, caller)\n\n          _ ->\n            config = Enum.reduce(dead_refs, config, &release_device/2)\n            capture_device(name, encoding, input, config, caller)\n        end\n\n      %{} ->\n        capture_new_device(name, encoding, input, config, caller)\n    end\n  end\n\n  defp capture_existing_device(name, encoding, input, config, caller) do\n    case Map.fetch!(config.devices, name) do\n      %{input?: input?} when input? or input != \"\" ->\n        {:reply, {:error, :input_on_already_captured_device}, config}\n\n      %{encoding: ^encoding} = device ->\n        {_, output} = StringIO.contents(device.pid)\n        ref = Process.monitor(caller)\n        config = put_in(config.devices[name].refs[ref], {caller, byte_size(output)})\n        {:reply, {:ok, ref}, config}\n\n      %{encoding: other_encoding} ->\n        {:reply, {:error, {:changed_encoding, other_encoding}}, config}\n    end\n  end\n\n  defp capture_new_device(name, encoding, input, config, caller) do\n    {:ok, pid} = StringIO.open(input, encoding: encoding)\n    original_pid = Process.whereis(name)\n\n    try do\n      Process.unregister(name)\n      Process.register(pid, name)\n    rescue\n      ArgumentError ->\n        {:reply, {:error, :no_device}, config}\n    else\n      _ ->\n        ref = Process.monitor(caller)\n\n        device = %{\n          original_pid: original_pid,\n          pid: pid,\n          refs: %{ref => {caller, 0}},\n          encoding: encoding,\n          input?: input != \"\"\n        }\n\n        {:reply, {:ok, ref}, put_in(config.devices[name], device)}\n    end\n  end\n\n  defp release_device(ref, %{devices: devices} = config) do\n    Process.demonitor(ref, [:flush])\n\n    case Enum.find(devices, fn {_, device} -> Map.has_key?(device.refs, ref) end) do\n      {name, device} ->\n        case Map.delete(device.refs, ref) do\n          refs when map_size(refs) == 0 ->\n            revert_device_to_original_pid(name, device.original_pid)\n            close_string_io(device.pid)\n            %{config | devices: Map.delete(devices, name)}\n\n          refs ->\n            put_in(config.devices[name].refs, refs)\n        end\n\n      _ ->\n        config\n    end\n  end\n\n  defp revert_device_to_original_pid(name, pid) do\n    Process.unregister(name)\n  rescue\n    ArgumentError -> nil\n  after\n    Process.register(pid, name)\n  end\n\n  defp close_string_io(pid) do\n    StringIO.close(pid)\n  rescue\n    ArgumentError -> nil\n  end\n\n  defp remove_log_capture(ref, %{log_captures: refs} = config) do\n    true = :ets.delete(@ets, ref)\n\n    case Map.pop(refs, ref, false) do\n      {true, refs} ->\n        maybe_revert_to_default_handler(refs, config.log_status)\n        %{config | log_captures: refs}\n\n      {false, _refs} ->\n        config\n    end\n  end\n\n  defp maybe_revert_to_default_handler(refs, status) when map_size(refs) == 0 do\n    :logger.remove_handler(@name)\n\n    with {:ok, %{module: module} = config} <- status do\n      :logger.add_handler(:default, module, config)\n    end\n  end\n\n  defp maybe_revert_to_default_handler(_refs, _config) do\n    :ok\n  end\n\n  ## :logger handler callback.\n\n  def log(event, _config) do\n    {:trap_exit, trapping_exits?} = Process.info(self(), :trap_exit)\n\n    tasks =\n      :ets.tab2list(@ets)\n      |> Enum.filter(fn {_ref, _string_io, level, _formatter_mod, _formatter_config} ->\n        :logger.compare_levels(event.level, level) in [:gt, :eq]\n      end)\n      |> Enum.group_by(\n        fn {_ref, _string_io, _level, formatter_mod, formatter_config} ->\n          {formatter_mod, formatter_config}\n        end,\n        fn {_ref, string_io, _level, _formatter_mod, _formatter_config} ->\n          string_io\n        end\n      )\n      |> Enum.map(fn {{formatter_mod, formatter_config}, string_ios} ->\n        Task.async(fn ->\n          chardata = formatter_mod.format(event, formatter_config)\n\n          # Simply send, do not wait for reply\n          for string_io <- string_ios do\n            send(string_io, {:io_request, self(), make_ref(), {:put_chars, :unicode, chardata}})\n          end\n        end)\n      end)\n\n    Task.await_many(tasks)\n\n    if trapping_exits? do\n      for %{pid: pid} <- tasks do\n        receive do\n          {:EXIT, ^pid, _} -> :ok\n        end\n      end\n    end\n\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/case.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.Case do\n  @moduledoc \"\"\"\n  Helpers for defining test cases.\n\n  This module must be used in other modules as a way to configure\n  and prepare them for testing.\n\n  When used, it accepts the following options:\n\n    * `:async` - configures tests in this module to run concurrently with\n      tests in other modules. Tests in the same module never run concurrently\n      (with the exception of tests run via the `:parameterize` option - see below).\n      It should be enabled only if tests do not change any global state.\n      Defaults to `false`.\n\n    * `:group` (since v1.18.0) - configures the **group** this module belongs to.\n      Tests in the same group never run concurrently. Tests from different\n      groups (or with no groups) can run concurrently when `async: true`\n      is given. By default, this module belongs to no group (defaults to `nil`).\n\n    * `:register` - when `false`, does not register this module within\n      ExUnit server. This means the module won't run when ExUnit suite runs.\n\n    * `:parameterize` (since v1.18.0) - a list of maps to parameterize tests.\n      If both `:async` and `:parameterize` are given, the different parameters\n      run concurrently. See the \"Parameterized tests\" section below for more\n      information.\n\n  > #### `use ExUnit.Case` {: .info}\n  >\n  > When you `use ExUnit.Case`, it will import the functionality\n  > from `ExUnit.Assertions`, `ExUnit.Callbacks`, `ExUnit.DocTest`,\n  > and this module itself.\n\n  ## Examples\n\n      defmodule AssertionTest do\n        # Use the module\n        use ExUnit.Case, async: true\n\n        # The \"test\" macro is imported by ExUnit.Case\n        test \"always pass\" do\n          assert true\n        end\n      end\n\n  ## Context\n\n  All tests receive a context as an argument. The context is particularly\n  useful for sharing information between callbacks and tests:\n\n      defmodule KVTest do\n        use ExUnit.Case\n\n        setup do\n          {:ok, pid} = KV.start_link()\n          {:ok, pid: pid}\n        end\n\n        test \"stores key-value pairs\", context do\n          assert KV.put(context[:pid], :hello, :world) == :ok\n          assert KV.get(context[:pid], :hello) == :world\n        end\n      end\n\n  As the context is a map, it can be pattern matched on to extract\n  information:\n\n      test \"stores key-value pairs\", %{pid: pid} = _context do\n        assert KV.put(pid, :hello, :world) == :ok\n        assert KV.get(pid, :hello) == :world\n      end\n\n  ## Tags\n\n  The context is used to pass information from the callbacks to\n  the test. In order to pass information from the test to the\n  callback, ExUnit provides tags.\n\n  By tagging a test, the tag value can be accessed in the context,\n  allowing the developer to customize the test. Let's see an\n  example:\n\n      defmodule FileTest do\n        # Changing directory cannot be async\n        use ExUnit.Case, async: false\n\n        setup context do\n          # Read the :cd tag value\n          if cd = context[:cd] do\n            prev_cd = File.cwd!()\n            File.cd!(cd)\n            on_exit(fn -> File.cd!(prev_cd) end)\n          end\n\n          :ok\n        end\n\n        @tag cd: \"fixtures\"\n        test \"reads UTF-8 fixtures\" do\n          File.read(\"README.md\")\n        end\n      end\n\n  In the example above, we have defined a tag called `:cd` that is\n  read in the setup callback to configure the working directory the\n  test is going to run on.\n\n  Tags are also very effective when used with case templates\n  (`ExUnit.CaseTemplate`) allowing callbacks in the case template\n  to customize the test behaviour.\n\n  Note a tag can be set in two different ways:\n\n      @tag key: value\n      @tag :key       # equivalent to setting @tag key: true\n\n  If a tag is given more than once, the last value wins.\n\n  ### Module and describe tags\n\n  A tag can be set for all tests in a module or describe block by\n  setting `@moduletag` or `@describetag` inside each context\n  respectively:\n\n      defmodule ApiTest do\n        use ExUnit.Case\n        @moduletag :external\n\n        describe \"makes calls to the right endpoint\" do\n          @describetag :endpoint\n\n          # ...\n        end\n      end\n\n  If you are setting a `@moduletag` or `@describetag` attribute, you must\n  set them after your call to `use ExUnit.Case` otherwise you will see\n  compilation errors.\n\n  If the same key is set via `@tag`, the `@tag` value has higher\n  precedence.\n\n  The `setup_all` blocks only receive tags that are set using `@moduletag`.\n\n  ### Known tags\n\n  The following tags are set automatically by ExUnit and are\n  therefore reserved:\n\n    * `:async` - if the test case is in async mode\n\n    * `:file` - the file on which the test was defined\n\n    * `:line` - the line on which the test was defined\n\n    * `:module` - the module on which the test was defined\n\n    * `:registered` - used for `ExUnit.Case.register_attribute/3` values\n\n    * `:test` - the test name\n\n    * `:test_group` - the group the test belongs to\n\n    * `:test_pid` - the PID of the testing process\n\n    * `:test_type` - the test type used when printing test results. It can also\n      be used for filtering. It is set by ExUnit to `:test`, `:doctest`, or\n      the equivalent type given to `register_test/6`\n\n    * `:describe` - the describe block the test belongs to (if in a describe)\n\n    * `:describe_line` - the line the describe block begins on (if in a describe).\n      It can be used to run all tests in the describe block given by line\n\n    * `:doctest` - the module or the file being doctested (if a doctest)\n\n    * `:doctest_data` - additional metadata about doctests stored in a map,\n      such as the `:end_line`, available for reflection purposes (if a doctest)\n\n    * `:doctest_line` - the line the doctest was defined (if a doctest).\n      It can be used to run a doctest defined at the given source line\n\n  The following tags customize how tests behave:\n\n    * `:capture_log` - see the \"Log Capture\" section below\n\n    * `:skip` - skips the test with the given reason\n\n    * `:timeout` - customizes the test timeout in milliseconds (defaults to `60_000`).\n      Accepts `:infinity` as a timeout value.\n\n    * `:tmp_dir` - (since v1.11.0) see the \"Tmp Dir\" section below\n\n  ## Filters\n\n  Tags can also be used to identify specific tests, which can then\n  be included or excluded using filters. The most common functionality\n  is to exclude some particular tests from running, which can be done\n  via `ExUnit.configure/1`:\n\n      # Exclude all external tests from running\n      ExUnit.configure(exclude: [external: true])\n\n  From now on, ExUnit will not run any test that has the `:external` option\n  set to `true`. This behaviour can be reversed with the `:include` option\n  which is usually passed through the command line:\n\n      $ mix test --include external:true\n\n  Run `mix help test` for more information on how to run filters via Mix.\n\n  Another use case for tags and filters is to exclude all tests that have\n  a particular tag by default, regardless of its value, and include only\n  a certain subset:\n\n      ExUnit.configure(exclude: :os, include: [os: :unix])\n\n  A given include/exclude filter can be given more than once:\n\n      ExUnit.configure(exclude: [os: :unix, os: :windows])\n\n  Keep in mind that all tests are included by default, so unless they are\n  excluded first, the `include` option has no effect.\n\n  ## Parameterized tests\n\n  Sometimes you want to run the same tests but with different parameters.\n  In ExUnit, it is possible to do so by passing a `:parameterize` key to\n  `ExUnit.Case`. The value must be a list of maps which will be the\n  parameters merged into the test context.\n\n  For example, Elixir has a module called `Registry`, which can have type\n  `:unique` or `:duplicate`, and can control its concurrency factor using\n  the `:partitions` option. If you have a number of tests that *behave the\n  same* across all of those values, you can parameterize those tests with:\n\n      use ExUnit.Case,\n        async: true,\n        parameterize:\n          for(kind <- [:unique, :duplicate],\n              partitions <- [1, 8],\n              do: %{kind: kind, partitions: partitions})\n\n  Then, in your tests, you can access the parameters as part of the context:\n\n      test \"starts a registry\", %{kind: kind, partitions: partitions} do\n        ...\n      end\n\n  Use parameterized tests with care:\n\n    * Although parameterized tests run concurrently when `async: true` is also given,\n      abuse of parameterized tests may make your test suite slower\n\n    * If you use parameterized tests and then find yourself adding conditionals\n      in your tests to deal with different parameters, then parameterized tests\n      may be the wrong solution to your problem. Consider creating separated\n      tests and sharing logic between them using regular functions\n\n  ## Log Capture\n\n  ExUnit can optionally suppress printing of log messages that are generated\n  during a test. Log messages generated while running a test are captured and\n  only if the test fails are they printed to aid with debugging.\n\n  You can opt into this behaviour for individual tests by tagging them with\n  `:capture_log` or enable log capture for all tests in the ExUnit configuration:\n\n      ExUnit.start(capture_log: true)\n\n  This default can be overridden by `@tag capture_log: false` or\n  `@moduletag capture_log: false`.\n\n  Since `setup_all` blocks don't belong to a specific test, log messages generated\n  in them (or between tests) are never captured. If you want to suppress these\n  messages as well, remove the console backend globally by setting:\n\n      config :logger, :default_handler, false\n\n  ## Tmp Dir\n\n  ExUnit automatically creates a temporary directory for tests tagged with\n  `:tmp_dir` and puts the path to that directory into the test context.\n  The directory is removed before being created to ensure we start with a blank\n  slate.\n\n  The temporary directory path is unique (includes the test module and test name)\n  and thus appropriate for running tests concurrently. You can customize the path\n  further by setting the tag to a string, e.g.: `tmp_dir: \"my_path\"`, which would\n  make the final path to be: `tmp/<module>/<test>/my_path`.\n\n  Example:\n\n      defmodule MyTest do\n        use ExUnit.Case, async: true\n\n        @tag :tmp_dir\n        test \"with tmp_dir\", %{tmp_dir: tmp_dir} do\n          assert tmp_dir =~ \"with tmp_dir\"\n          assert File.dir?(tmp_dir)\n        end\n      end\n\n  As with other tags, `:tmp_dir` can also be set as `@moduletag` and\n  `@describetag`.\n\n  ## Process Architecture\n\n  An ExUnit test case uses several processes when it runs. These are illustrated below.\n\n  ```mermaid\n  sequenceDiagram\n    participant runner as ExUnit Case\n    runner->>runner: Run setup_all callbacks\n\n    loop Each test\n      create participant test as Test Process\n      runner->>test: Spawn\n      test->>test: Run setup callbacks\n      test->>test: Run test\n      destroy test\n      test-xrunner: Exits\n      runner->>runner: Run on_exit callbacks\n    end\n  ```\n\n    1. First, all `ExUnit.Callbacks.setup_all/1` callbacks run in a single process, sequentially,\n       in the order they were defined.\n\n    2. Then, a new process is spawned for the test itself. In this process, first all\n       `ExUnit.Callbacks.setup/1` callbacks run, in the order they were defined. Then,\n       the test itself is executed.\n\n    3. After the test exits, a new process is spawned to run all `ExUnit.Callbacks.on_exit/2`,\n       in the reverse order they were defined.\n\n  \"\"\"\n\n  @type env :: module() | Macro.Env.t()\n\n  @type register_attribute_opts :: [\n          accumulate: boolean(),\n          persist: boolean()\n        ]\n  @compile {:no_warn_undefined, [IEx.Pry]}\n  @reserved [:module, :file, :line, :test, :async, :registered, :describe]\n\n  @doc false\n  defmacro __using__(opts) do\n    quote do\n      ExUnit.Case.__register__(__MODULE__, unquote(opts))\n\n      import ExUnit.Callbacks\n      import ExUnit.Assertions\n      import ExUnit.Case, only: [describe: 2, test: 1, test: 2, test: 3]\n      import ExUnit.DocTest\n    end\n  end\n\n  @keys [:async, :group, :parameterize, :register]\n\n  @doc false\n  def __keys__(opts), do: Keyword.take(opts, @keys)\n\n  @doc false\n  def __register__(module, opts) do\n    if not Keyword.keyword?(opts) do\n      raise ArgumentError,\n            ~s(the argument passed to \"use ExUnit.Case\" must be a list of options, ) <>\n              ~s(got: #{inspect(opts)})\n    end\n\n    {register?, opts} = Keyword.pop(opts, :register, true)\n    {next_opts, opts} = Keyword.split(opts, @keys)\n\n    if opts != [] do\n      IO.warn(\"unknown options given to ExUnit.Case: #{inspect(opts)}\")\n    end\n\n    if not Module.has_attribute?(module, :ex_unit_tests) do\n      tag_check = Enum.any?([:moduletag, :describetag, :tag], &Module.has_attribute?(module, &1))\n\n      if tag_check do\n        raise \"you must set @tag, @describetag, and @moduletag after the call to \\\"use ExUnit.Case\\\"\"\n      end\n\n      accumulate_attributes = [\n        :ex_unit_tests,\n        :tag,\n        :describetag,\n        :moduletag,\n        :ex_unit_registered_test_attributes,\n        :ex_unit_registered_describe_attributes,\n        :ex_unit_registered_module_attributes\n      ]\n\n      Enum.each(accumulate_attributes, &Module.register_attribute(module, &1, accumulate: true))\n\n      if register? do\n        Module.put_attribute(module, :after_compile, ExUnit.Case)\n      end\n\n      ExUnit.Callbacks.__register__(module)\n      Module.put_attribute(module, :before_compile, ExUnit.Case)\n    end\n\n    past_opts = Module.get_attribute(module, :ex_unit_module, [])\n    Module.put_attribute(module, :ex_unit_module, Keyword.merge(past_opts, next_opts))\n    :ok\n  end\n\n  @doc \"\"\"\n  Defines a test with `message`.\n\n  The test may also define a pattern, which will be matched\n  against the test context. For more information on contexts, see\n  `ExUnit.Callbacks`.\n\n  ## Examples\n\n      test \"true is equal to true\" do\n        assert true == true\n      end\n\n  \"\"\"\n  defmacro test(message, var \\\\ quote(do: _), contents) do\n    if not is_tuple(var) do\n      IO.warn(\n        \"test context is always a map. The pattern \" <>\n          \"#{inspect(Macro.to_string(var))} will never match\",\n        Macro.Env.stacktrace(__CALLER__)\n      )\n    end\n\n    contents =\n      case annotate_test(contents, __CALLER__) do\n        [do: block] ->\n          quote do\n            unquote(block)\n            :ok\n          end\n\n        contents ->\n          quote do\n            try(unquote(contents))\n            :ok\n          end\n      end\n\n    %{module: mod, file: file, line: line} = __CALLER__\n\n    name =\n      quote do\n        name =\n          ExUnit.Case.register_test(\n            unquote(mod),\n            unquote(file),\n            unquote(line),\n            :test,\n            unquote(message),\n            []\n          )\n      end\n\n    def =\n      {:def, [],\n       [\n         {{:unquote, [], [quote(do: name)]}, [], [var]},\n         [do: contents]\n       ]}\n\n    {:__block__, [], [name, def]}\n  end\n\n  defp annotate_test(contents, caller) do\n    if Application.get_env(:ex_unit, :breakpoints, false) and Keyword.keyword?(contents) do\n      for {key, expr} <- contents do\n        {key, IEx.Pry.annotate_quoted(expr, true, caller)}\n      end\n    else\n      contents\n    end\n  end\n\n  @doc \"\"\"\n  Defines a not implemented test with a string.\n\n  Provides a convenient macro that allows a test to be defined\n  with a string, but not yet implemented. The resulting test will\n  always fail and print a \"Not implemented\" error message. The\n  resulting test case is also tagged with `:not_implemented`.\n\n  ## Examples\n\n      test \"this will be a test in future\"\n\n  \"\"\"\n  defmacro test(message) do\n    %{module: mod, file: file, line: line} = __CALLER__\n\n    quote bind_quoted: binding() do\n      name = ExUnit.Case.register_test(mod, file, line, :test, message, [:not_implemented])\n      def unquote(name)(_), do: flunk(\"Not implemented\")\n    end\n  end\n\n  @doc \"\"\"\n  Describes tests together.\n\n  Every describe block receives a name which is used as prefix for\n  upcoming tests. Inside a block, `ExUnit.Callbacks.setup/1` may be\n  invoked and it will define a setup callback to run only for the\n  current block. The describe name is also added as a tag, allowing\n  developers to run tests for specific blocks.\n\n  ## Examples\n\n      defmodule StringTest do\n        use ExUnit.Case, async: true\n\n        describe \"String.downcase/1\" do\n          test \"with ascii characters\" do\n            assert String.downcase(\"HELLO\") == \"hello\"\n          end\n\n          test \"with Unicode\" do\n            assert String.downcase(\"HÉLLÒ\") == \"héllò\"\n          end\n        end\n      end\n\n  When using Mix, you can run all tests in a describe block by name:\n\n      $ mix test --only describe:\"String.downcase/1\"\n\n  or by passing the exact line the describe block starts on:\n\n      $ mix test path/to/file:123\n\n  Note describe blocks cannot be nested. Instead of relying on hierarchy\n  for composition, developers should build on top of named setups. For\n  example:\n\n      defmodule UserManagementTest do\n        use ExUnit.Case, async: true\n\n        describe \"when user is logged in and is an admin\" do\n          setup [:log_user_in, :set_type_to_admin]\n\n          test ...\n        end\n\n        describe \"when user is logged in and is a manager\" do\n          setup [:log_user_in, :set_type_to_manager]\n\n          test ...\n        end\n\n        defp log_user_in(context) do\n          # ...\n        end\n      end\n\n  By forbidding hierarchies in favor of named setups, it is straightforward\n  for the developer to glance at each describe block and know exactly the\n  setup steps involved.\n  \"\"\"\n  @doc since: \"1.3.0\"\n  defmacro describe(message, do: block) do\n    definition =\n      quote unquote: false do\n        defp unquote(name)(var!(context)), do: unquote(body)\n      end\n\n    quote do\n      ExUnit.Callbacks.__describe__(__MODULE__, __ENV__.line, unquote(message), fn\n        message, describes ->\n          res = unquote(block)\n\n          case ExUnit.Callbacks.__describe__(__MODULE__, message, describes) do\n            {nil, nil} -> :ok\n            {name, body} -> unquote(definition)\n          end\n\n          res\n      end)\n    end\n  end\n\n  @doc false\n  defmacro __before_compile__(%{module: module}) do\n    tests =\n      module\n      |> Module.get_attribute(:ex_unit_tests)\n      |> Enum.reverse()\n      |> Macro.escape()\n\n    moduletag = Module.get_attribute(module, :moduletag)\n\n    tags =\n      moduletag\n      |> normalize_tags()\n      |> validate_tags()\n      |> Map.new()\n\n    opts = Module.get_attribute(module, :ex_unit_module, [])\n    async? = Keyword.get(opts, :async, false)\n    group = Keyword.get(opts, :group, nil)\n    parameterize = Keyword.get(opts, :parameterize, nil)\n\n    if not is_boolean(async?) do\n      raise ArgumentError, \":async must be a boolean, got: #{inspect(async?)}\"\n    end\n\n    if not (parameterize == nil or (is_list(parameterize) and Enum.all?(parameterize, &is_map/1))) do\n      raise ArgumentError, \":parameterize must be a list of maps, got: #{inspect(parameterize)}\"\n    end\n\n    {setup_all?, callbacks} = ExUnit.Callbacks.__callbacks__(module)\n\n    quote do\n      unquote(callbacks)\n\n      def __ex_unit__ do\n        %ExUnit.TestModule{\n          file: __ENV__.file,\n          name: __MODULE__,\n          setup_all?: unquote(setup_all?),\n          tags: unquote(Macro.escape(tags)),\n          tests: unquote(tests)\n        }\n      end\n\n      def __ex_unit__(:config) do\n        %{\n          async?: unquote(async?),\n          group: unquote(Macro.escape(group)),\n          parameterize: unquote(Macro.escape(parameterize))\n        }\n      end\n    end\n  end\n\n  @doc false\n  def __after_compile__(%{module: module}, _) do\n    cond do\n      Process.whereis(ExUnit.Server) ->\n        ExUnit.Server.add_module(module, module.__ex_unit__(:config))\n\n      Code.can_await_module_compilation?() ->\n        :ok\n\n      true ->\n        raise \"cannot use ExUnit.Case without starting the ExUnit application, \" <>\n                \"please call ExUnit.start() or explicitly start the :ex_unit app\"\n    end\n  end\n\n  @doc \"\"\"\n  Registers a function to run as a test for this module.\n\n  This is used by third-party projects to implement macros like\n  `property/3` that works like `test` but instead defines a property.\n  See `test/3` implementation for an example of invoking this function.\n\n  The test type will be converted to a string and pluralized for\n  display. You can use `ExUnit.plural_rule/2` to set a custom\n  pluralization.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  def register_test(mod, file, line, test_type, name, tags) do\n    if not Module.has_attribute?(mod, :ex_unit_tests) do\n      raise \"cannot define #{test_type}. Please make sure you have invoked \" <>\n              \"\\\"use ExUnit.Case\\\" in the current module\"\n    end\n\n    registered_attribute_keys = [\n      :ex_unit_registered_module_attributes,\n      :ex_unit_registered_describe_attributes,\n      :ex_unit_registered_test_attributes\n    ]\n\n    registered =\n      for key <- registered_attribute_keys,\n          attribute <- Module.get_attribute(mod, key),\n          into: %{} do\n        {attribute, Module.get_attribute(mod, attribute)}\n      end\n\n    moduletag = Module.get_attribute(mod, :moduletag)\n    tag = Module.delete_attribute(mod, :tag)\n\n    {name, describe, describe_line, describetag} =\n      case Module.get_attribute(mod, :ex_unit_describe) do\n        {line, describe, _counter} ->\n          test_name = validate_test_name(\"#{test_type} #{describe} #{name}\")\n          {test_name, describe, line, Module.get_attribute(mod, :describetag)}\n\n        nil ->\n          test_name = validate_test_name(\"#{test_type} #{name}\")\n          {test_name, nil, nil, []}\n      end\n\n    if Module.defines?(mod, {name, 1}) do\n      raise ArgumentError, ~s(\"#{name}\" is already defined in #{inspect(mod)})\n    end\n\n    tags =\n      (tags ++ tag ++ describetag ++ moduletag)\n      |> normalize_tags()\n      |> validate_tags()\n      |> Map.merge(%{\n        line: line,\n        file: file,\n        registered: registered,\n        describe: describe,\n        describe_line: describe_line,\n        test_type: test_type\n      })\n\n    test = %ExUnit.Test{name: name, case: mod, tags: tags, module: mod}\n    Module.put_attribute(mod, :ex_unit_tests, test)\n\n    for attribute <- Module.get_attribute(mod, :ex_unit_registered_test_attributes) do\n      Module.delete_attribute(mod, attribute)\n    end\n\n    name\n  end\n\n  @doc \"\"\"\n  Registers a test with the given environment.\n\n  This function is deprecated in favor of `register_test/6` which performs\n  better under tight loops by avoiding `__ENV__`.\n  \"\"\"\n  # TODO: Remove me Elixir v2.0\n  @deprecated \"Use register_test/6 instead\"\n  @doc since: \"1.3.0\"\n  def register_test(%{module: mod, file: file, line: line}, test_type, name, tags) do\n    register_test(mod, file, line, test_type, name, tags)\n  end\n\n  @doc \"\"\"\n  Registers a new attribute to be used during `ExUnit.Case` tests.\n\n  The attribute values will be available through `context.registered`.\n  Registered values are cleared after each `test/3` similar\n  to `@tag`.\n\n  This function takes the same options as `Module.register_attribute/3`.\n\n  ## Examples\n\n      defmodule MyTest do\n        use ExUnit.Case\n\n        ExUnit.Case.register_attribute(__MODULE__, :fixtures, accumulate: true)\n\n        @fixtures :user\n        @fixtures {:post, insert: false}\n        test \"using custom attribute\", context do\n          assert context.registered.fixtures == [{:post, insert: false}, :user]\n        end\n\n        test \"custom attributes are cleared per test\", context do\n          assert context.registered.fixtures == []\n        end\n      end\n\n  \"\"\"\n  @doc since: \"1.3.0\"\n  @spec register_attribute(env, atom, register_attribute_opts) :: :ok\n  def register_attribute(env, name, opts \\\\ [])\n  def register_attribute(%{module: mod}, name, opts), do: register_attribute(mod, name, opts)\n\n  def register_attribute(mod, name, opts) when is_atom(mod) and is_atom(name) and is_list(opts) do\n    register_attribute(:ex_unit_registered_test_attributes, mod, name, opts)\n  end\n\n  @doc \"\"\"\n  Registers a new describe attribute to be used during `ExUnit.Case` tests.\n\n  The attribute values will be available through `context.registered`.\n  Registered values are cleared after each `describe/2` similar\n  to `@describetag`.\n\n  This function takes the same options as `Module.register_attribute/3`.\n\n  ## Examples\n\n      defmodule MyTest do\n        use ExUnit.Case\n\n        ExUnit.Case.register_describe_attribute(__MODULE__, :describe_fixtures, accumulate: true)\n\n        describe \"using custom attribute\" do\n          @describe_fixtures :user\n          @describe_fixtures {:post, insert: false}\n\n          test \"has attribute\", context do\n            assert context.registered.describe_fixtures == [{:post, insert: false}, :user]\n          end\n        end\n\n        describe \"custom attributes are cleared per describe\" do\n          test \"doesn't have attributes\", context do\n            assert context.registered.describe_fixtures == []\n          end\n        end\n      end\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec register_describe_attribute(env, atom, register_attribute_opts) :: :ok\n  def register_describe_attribute(env, name, opts \\\\ [])\n\n  def register_describe_attribute(%{module: mod}, name, opts) do\n    register_describe_attribute(mod, name, opts)\n  end\n\n  def register_describe_attribute(mod, name, opts)\n      when is_atom(mod) and is_atom(name) and is_list(opts) do\n    register_attribute(:ex_unit_registered_describe_attributes, mod, name, opts)\n  end\n\n  @doc \"\"\"\n  Registers a new module attribute to be used during `ExUnit.Case` tests.\n\n  The attribute values will be available through `context.registered`.\n\n  This function takes the same options as `Module.register_attribute/3`.\n\n  ## Examples\n\n      defmodule MyTest do\n        use ExUnit.Case\n\n        ExUnit.Case.register_module_attribute(__MODULE__, :module_fixtures, accumulate: true)\n\n        @module_fixtures :user\n        @module_fixtures {:post, insert: false}\n\n        test \"using custom attribute\", context do\n          assert context.registered.module_fixtures == [{:post, insert: false}, :user]\n        end\n\n        test \"still using custom attribute\", context do\n          assert context.registered.module_fixtures == [{:post, insert: false}, :user]\n        end\n      end\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec register_module_attribute(env, atom, register_attribute_opts) :: :ok\n  def register_module_attribute(env, name, opts \\\\ [])\n\n  def register_module_attribute(%{module: mod}, name, opts) do\n    register_module_attribute(mod, name, opts)\n  end\n\n  def register_module_attribute(mod, name, opts)\n      when is_atom(mod) and is_atom(name) and is_list(opts) do\n    register_attribute(:ex_unit_registered_module_attributes, mod, name, opts)\n  end\n\n  defp register_attribute(type, mod, name, opts) do\n    validate_registered_attribute!(type, mod, name)\n    Module.register_attribute(mod, name, opts)\n    Module.put_attribute(mod, type, name)\n  end\n\n  defp validate_registered_attribute!(type, mod, name) do\n    registered_attribute_keys = [\n      :ex_unit_registered_module_attributes,\n      :ex_unit_registered_describe_attributes,\n      :ex_unit_registered_test_attributes\n    ]\n\n    for key <- registered_attribute_keys,\n        type != key and name in Module.get_attribute(mod, key) do\n      raise ArgumentError, \"cannot register attribute #{inspect(name)} multiple times\"\n    end\n\n    if Module.has_attribute?(mod, name) do\n      raise \"you must set @#{name} after it has been registered\"\n    end\n  end\n\n  @doc \"\"\"\n  Returns the most recently registered test case as an `%ExUnit.Test{}`\n  struct.\n\n  This is used by third-party utilities to allow compile-time configuration\n  using test tags without having to explicitly pass the test context at\n  run-time. It is intended to be invoked in macros before the test module\n  is compiled.\n\n  Raises if called with a module that has already been compiled.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec get_last_registered_test(env) :: ExUnit.Test.t() | nil\n  def get_last_registered_test(%{module: mod}) do\n    get_last_registered_test(mod)\n  end\n\n  def get_last_registered_test(mod) when is_atom(mod) do\n    Module.get_last_attribute(mod, :ex_unit_tests)\n  end\n\n  defp validate_tags(tags) do\n    for tag <- @reserved, Map.has_key?(tags, tag) do\n      raise \"cannot set tag #{inspect(tag)} because it is reserved by ExUnit\"\n    end\n\n    if not is_atom(tags[:test_type]) do\n      raise(\"value for tag \\\":test_type\\\" must be an atom\")\n    end\n\n    tags\n  end\n\n  defp validate_test_name(name) do\n    try do\n      String.to_atom(name)\n    rescue\n      SystemLimitError ->\n        raise SystemLimitError, \"\"\"\n        the computed name of a test (which includes its type, the name of its parent describe \\\n        block if present, and the test name itself) must be shorter than 255 characters, \\\n        got: #{inspect(name)}\n        \"\"\"\n    end\n  end\n\n  defp normalize_tags(tags) do\n    Enum.reduce(Enum.reverse(tags), %{}, fn\n      {key, value}, acc ->\n        Map.put(acc, key, value)\n\n      tag, acc when is_atom(tag) ->\n        Map.put(acc, tag, true)\n\n      tag, acc ->\n        if Keyword.keyword?(tag) do\n          Enum.into(tag, acc)\n        else\n          raise \"an invalid value for a tag was used. \" <>\n                  \"Expected an atom or a keyword list, got: #{inspect(tag)}\"\n        end\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/case_template.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.CaseTemplate do\n  @moduledoc \"\"\"\n  Defines a module template to be used throughout your test suite.\n\n  This is useful when there are a set of setup callbacks or a set\n  of functions that should be shared between test modules.\n\n  Let's imagine that you create a `MyCase` module that calls `use\n  ExUnit.CaseTemplate`. When a test case module calls `use MyCase`, the\n  following things hold true:\n\n    * All the functionality that `MyCase` would have had available from\n      `use ExUnit.Case` is available (same as if `MyCase` called `use\n      ExUnit.Case` directly)\n\n    * The `setup` and `setup_all` callbacks that you define in `MyCase`\n      get used in the test case module\n\n  The options that you pass to `use MyCase` get also passed to `use\n  ExUnit.Case` under the hood. This means you can do things like `use\n  MyCase, async: true`. You can also access this options in `using/2`.\n\n  > #### `use ExUnit.CaseTemplate` {: .info}\n  >\n  > When you `use ExUnit.CaseTemplate`, it will import the functionality\n  > from `ExUnit.Assertions`, `ExUnit.Callbacks`, and this module itself.\n  > It will also define a `__using__` callback, so the module itself can\n  > be used as a template instead of `ExUnit.Case`.\n\n  ## Example\n\n      defmodule MyCase do\n        use ExUnit.CaseTemplate\n\n        setup do\n          IO.puts(\"This will run before each test that uses this case\")\n        end\n      end\n\n      defmodule MyTest do\n        use MyCase, async: true\n\n        test \"truth\" do\n          assert true\n        end\n      end\n\n  If you need to \"hook\" into `use MyCase` and do other things as well,\n  you can use the `using/2` macro. See its documentation for more\n  information and examples.\n\n      defmodule MyCase do\n        use ExUnit.CaseTemplate\n\n        using do\n          quote do\n            import MyApp.TestHelpers\n          end\n        end\n      end\n\n  \"\"\"\n\n  @doc false\n  defmacro __using__(_) do\n    quote do\n      ExUnit.Callbacks.__register__(__MODULE__)\n      @before_compile ExUnit.Callbacks\n      import ExUnit.Callbacks\n\n      import ExUnit.Assertions\n      import unquote(__MODULE__)\n\n      defmacro __using__(opts) do\n        unquote(__MODULE__).__proxy__(__MODULE__, opts)\n      end\n\n      defoverridable __using__: 1\n    end\n  end\n\n  @doc false\n  # We inject this code in the module that calls \"use MyTemplate\".\n  def __proxy__(module, opts) do\n    quote do\n      use ExUnit.Case, ExUnit.Case.__keys__(unquote(opts))\n\n      setup_all context do\n        unquote(module).__ex_unit__(:setup_all, context)\n      end\n\n      setup context do\n        unquote(module).__ex_unit__(:setup, context)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Allows a developer to customize the using block\n  when the case template is used.\n\n  You can use an optional `var` argument when calling `using/2`. ExUnit\n  will pass whatever argument you pass to `use MyCase` as this `var` argument. See the examples below for clarification.\n\n  ## Example\n\n      defmodule MyCase do\n        use ExUnit.CaseTemplate\n\n        using do\n          quote do\n            # This code is injected into every case that calls \"use MyCase\"\n            alias MyApp.FunModule\n          end\n        end\n      end\n\n  You can specify an argument to `using/2`:\n\n      defmodule MyCase do\n        use ExUnit.CaseTemplate\n\n        using options do\n          quote do\n            if unquote(options)[:import_helpers] do\n              import MyApp.TestHelpers\n            end\n          end\n        end\n      end\n\n  The second argument passed to `use MyCase` gets forwarded to `using/2` too:\n\n      defmodule SomeTestCase do\n        use MyCase, async: true, import_helpers: true\n\n        test \"the truth\" do\n          # truth/0 comes from MyApp.TestHelpers:\n          assert truth()\n        end\n      end\n\n  > #### Sharing options with `use ExUnit.Case` {: .warning}\n  >\n  > The second argument that you pass to `use MyCase` is *also* passed\n  > as the second argument to `use ExUnit.Case`.\n\n  \"\"\"\n  defmacro using(var \\\\ quote(do: _), do: block) do\n    quote do\n      defmacro __using__(unquote(var) = opts) do\n        parent = unquote(__MODULE__).__proxy__(__MODULE__, opts)\n        result = unquote(block)\n        {:__block__, [], [parent, result]}\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/cli_formatter.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.CLIFormatter do\n  @moduledoc false\n  use GenServer\n\n  import ExUnit.Formatter,\n    only: [format_times: 1, format_filters: 2, format_test_failure: 5, format_test_all_failure: 5]\n\n  ## Callbacks\n\n  def init(opts) do\n    IO.puts(\"Running ExUnit with seed: #{opts[:seed]}, max_cases: #{opts[:max_cases]}\")\n    print_filters(opts, :exclude)\n    print_filters(opts, :include)\n    IO.puts(\"\")\n\n    config = %{\n      dry_run: opts[:dry_run],\n      trace: opts[:trace],\n      colors: colors(opts),\n      width: get_terminal_width(),\n      slowest: opts[:slowest],\n      slowest_modules: opts[:slowest_modules],\n      test_counter: %{},\n      test_timings: [],\n      failure_counter: 0,\n      failure_type_counter: %{},\n      skipped_counter: 0,\n      excluded_counter: 0,\n      invalid_counter: 0\n    }\n\n    {:ok, config}\n  end\n\n  def handle_cast({:suite_started, _opts}, config) do\n    if config.dry_run, do: IO.puts(extra_info(\"Tests that would be executed:\", config))\n\n    {:noreply, config}\n  end\n\n  def handle_cast({:suite_finished, times_us}, config) do\n    test_counter = collect_test_counter(config)\n\n    if test_counter == 0 and config.excluded_counter > 0 do\n      IO.puts(invalid(\"All tests have been excluded.\", config))\n    end\n\n    IO.write(\"\\n\")\n    IO.puts(format_times(times_us))\n\n    if config.slowest > 0 do\n      IO.puts(format_slowest_tests(config, times_us.run))\n    end\n\n    if config.slowest_modules > 0 do\n      IO.puts(format_slowest_modules(config, times_us.run))\n    end\n\n    print_summary(config, false)\n    {:noreply, config}\n  end\n\n  def handle_cast({:test_started, %ExUnit.Test{} = test}, config) do\n    if config.trace, do: IO.write(\"#{trace_test_started(test)} [#{trace_test_line(test)}]\")\n    {:noreply, config}\n  end\n\n  def handle_cast({:test_finished, %ExUnit.Test{state: nil} = test}, config) do\n    if config.trace do\n      IO.puts(success(trace_test_result(test), config))\n    else\n      IO.write(success(\".\", config))\n    end\n\n    config = %{config | test_counter: update_test_counter(config.test_counter, test)}\n    {:noreply, update_test_timings(config, test)}\n  end\n\n  def handle_cast({:test_finished, %ExUnit.Test{state: {:excluded, reason}} = test}, config)\n      when is_binary(reason) do\n    if config.trace, do: IO.puts(trace_test_excluded(test))\n    config = %{config | excluded_counter: config.excluded_counter + 1}\n    {:noreply, config}\n  end\n\n  def handle_cast({:test_finished, %ExUnit.Test{state: {:skipped, reason}} = test}, config)\n      when is_binary(reason) do\n    if config.trace do\n      IO.puts(skipped(trace_test_skipped(test), config))\n    else\n      IO.write(skipped(\"*\", config))\n    end\n\n    {:noreply, %{config | skipped_counter: config.skipped_counter + 1}}\n  end\n\n  def handle_cast(\n        {:test_finished,\n         %ExUnit.Test{state: {:invalid, %ExUnit.TestModule{state: {:failed, _}}}} = test},\n        config\n      ) do\n    if config.trace do\n      IO.puts(invalid(trace_test_result(test), config))\n    else\n      IO.write(invalid(\"?\", config))\n    end\n\n    {:noreply, %{config | invalid_counter: config.invalid_counter + 1}}\n  end\n\n  def handle_cast({:test_finished, %ExUnit.Test{state: {:failed, failures}} = test}, config) do\n    if config.trace do\n      IO.puts(failure(trace_test_result(test), config))\n    end\n\n    formatted =\n      format_test_failure(\n        test,\n        failures,\n        config.failure_counter + 1,\n        config.width,\n        &formatter(&1, &2, config)\n      )\n\n    print_failure(formatted, config)\n    print_logs(test.logs)\n\n    test_counter = update_test_counter(config.test_counter, test)\n    failure_counter = config.failure_counter + 1\n    failure_type_counter = update_test_counter(config.failure_type_counter, test)\n\n    config = %{\n      config\n      | test_counter: test_counter,\n        failure_counter: failure_counter,\n        failure_type_counter: failure_type_counter\n    }\n\n    {:noreply, update_test_timings(config, test)}\n  end\n\n  def handle_cast({:module_started, %ExUnit.TestModule{} = module}, config) do\n    if config.trace do\n      %{name: name, file: file, parameters: parameters} = module\n      IO.puts(\"\\n#{inspect(name)} [#{Path.relative_to_cwd(file)}]\")\n\n      if parameters != %{} do\n        IO.puts(\"Parameters: #{inspect(parameters)}\")\n      end\n    end\n\n    {:noreply, config}\n  end\n\n  def handle_cast({:module_finished, %ExUnit.TestModule{state: nil} = module}, config) do\n    if config.dry_run do\n      file_path = Path.relative_to_cwd(module.file)\n\n      Enum.each(module.tests, fn test ->\n        IO.puts(\"#{file_path}:#{test.tags.line}\")\n      end)\n    end\n\n    {:noreply, config}\n  end\n\n  def handle_cast(\n        {:module_finished, %ExUnit.TestModule{state: {:failed, failures}} = test_module},\n        config\n      ) do\n    # The failed tests have already contributed to the counter,\n    # so we should only add the successful tests to the count\n    config =\n      Enum.reduce(test_module.tests, config, fn\n        %{state: nil} = test, acc ->\n          %{\n            acc\n            | failure_counter: acc.failure_counter + 1,\n              failure_type_counter: update_test_counter(acc.failure_type_counter, test)\n          }\n\n        _test, acc ->\n          acc\n      end)\n\n    formatted =\n      format_test_all_failure(\n        test_module,\n        failures,\n        config.failure_counter,\n        config.width,\n        &formatter(&1, &2, config)\n      )\n\n    print_failure(formatted, config)\n\n    {:noreply, config}\n  end\n\n  def handle_cast(:max_failures_reached, config) do\n    IO.write(failure(\"--max-failures reached, aborting test suite\", config))\n    {:noreply, config}\n  end\n\n  def handle_cast({:sigquit, current}, config) do\n    IO.write(\"\\n\\n\")\n\n    if current == [] do\n      IO.write(failure(\"Aborting test suite, showing results so far...\\n\\n\", config))\n    else\n      IO.write(failure(\"Aborting test suite, the following have not completed:\\n\\n\", config))\n      Enum.each(current, &IO.puts(trace_aborted(&1)))\n      IO.write(failure(\"\\nShowing results so far...\\n\\n\", config))\n    end\n\n    print_summary(config, true)\n    {:noreply, config}\n  end\n\n  def handle_cast(_, config) do\n    {:noreply, config}\n  end\n\n  ## Tracing\n\n  defp trace_test_time(%ExUnit.Test{time: time}) do\n    \"#{format_us(time)}ms\"\n  end\n\n  defp trace_test_line(%ExUnit.Test{tags: tags}) do\n    \"L##{tags.line}\"\n  end\n\n  defp trace_test_file_line(%ExUnit.Test{tags: tags}) do\n    \"#{Path.relative_to_cwd(tags.file)}:#{tags.line}\"\n  end\n\n  defp trace_test_started(test) do\n    String.replace(\"  * #{test.name}\", \"\\n\", \" \")\n  end\n\n  defp trace_test_result(test) do\n    \"\\r#{trace_test_started(test)} (#{trace_test_time(test)}) [#{trace_test_line(test)}]\"\n  end\n\n  defp trace_test_excluded(test) do\n    \"\\r#{trace_test_started(test)} (excluded) [#{trace_test_line(test)}]\"\n  end\n\n  defp trace_test_skipped(test) do\n    \"\\r#{trace_test_started(test)} (skipped) [#{trace_test_line(test)}]\"\n  end\n\n  defp trace_aborted(%ExUnit.Test{} = test) do\n    \"* #{test.name} [#{trace_test_file_line(test)}]\"\n  end\n\n  defp trace_aborted(%ExUnit.TestModule{name: name, file: file}) do\n    \"* #{inspect(name)} [#{Path.relative_to_cwd(file)}]\"\n  end\n\n  defp normalize_us(us) do\n    div(us, 1000)\n  end\n\n  defp format_us(us) do\n    us = div(us, 10)\n\n    if us < 10 do\n      \"0.0#{us}\"\n    else\n      us = div(us, 10)\n      \"#{div(us, 10)}.#{rem(us, 10)}\"\n    end\n  end\n\n  defp update_test_counter(test_counter, %{tags: %{test_type: test_type}}) do\n    Map.update(test_counter, test_type, 1, &(&1 + 1))\n  end\n\n  ## Slowest\n\n  defp format_slowest_tests(%{slowest: slowest, test_timings: timings}, run_us) do\n    slowest_tests =\n      timings\n      |> Enum.sort_by(fn %{time: time} -> -time end)\n      |> Enum.take(slowest)\n\n    slowest_us = Enum.reduce(slowest_tests, 0, &(&1.time + &2))\n    slowest_time = slowest_us |> normalize_us() |> format_us()\n    percentage = Float.round(slowest_us / run_us * 100, 1)\n\n    [\n      \"\\nTop #{slowest} slowest (#{slowest_time}s), #{percentage}% of total time:\\n\\n\"\n      | Enum.map(slowest_tests, &format_slow_test/1)\n    ]\n  end\n\n  defp format_slowest_modules(%{slowest_modules: slowest, test_timings: timings}, run_us) do\n    slowest_tests =\n      timings\n      |> Enum.group_by(\n        fn %{module: module, tags: tags} ->\n          {module, tags.file}\n        end,\n        fn %{time: time} -> time end\n      )\n      |> Enum.into([], fn {{module, trace_test_file_line}, timings} ->\n        {module, trace_test_file_line, Enum.sum(timings)}\n      end)\n      |> Enum.sort_by(fn {_module, _, sum_timings} -> sum_timings end, :desc)\n      |> Enum.take(slowest)\n\n    slowest_us =\n      Enum.reduce(slowest_tests, 0, fn {_module, _, sum_timings}, acc ->\n        acc + sum_timings\n      end)\n\n    slowest_time = slowest_us |> normalize_us() |> format_us()\n    percentage = Float.round(slowest_us / run_us * 100, 1)\n\n    [\n      \"\\nTop #{slowest} slowest (#{slowest_time}s), #{percentage}% of total time:\\n\\n\"\n      | Enum.map(slowest_tests, &format_slow_module/1)\n    ]\n  end\n\n  defp format_slow_test(%ExUnit.Test{time: time, module: module} = test) do\n    \"#{trace_test_started(test)} (#{inspect(module)}) (#{format_us(time)}ms) \" <>\n      \"[#{trace_test_file_line(test)}]\\n\"\n  end\n\n  defp format_slow_module({module, test_file_path, timings}) do\n    \"#{inspect(module)} (#{format_us(timings)}ms)\\n [#{Path.relative_to_cwd(test_file_path)}]\\n\"\n  end\n\n  defp update_test_timings(\n         %{slowest: slowest, slowest_modules: slowest_modules} = config,\n         %ExUnit.Test{} = test\n       ) do\n    if slowest > 0 or slowest_modules > 0 do\n      # Do not store logs, as they are not used for timings and consume memory.\n      update_in(config.test_timings, &[%{test | logs: \"\"} | &1])\n    else\n      config\n    end\n  end\n\n  ## Printing\n\n  defp print_summary(config, force_failures?) do\n    test_counter = collect_test_counter(config)\n    passed_counter = test_counter - config.failure_counter\n\n    # Passed line: \"Result: 447/455 passed (53/54 doctests, 393/403 tests)\" or\n    # \"Result: 455 passed (70 tests, 14 properties)\" when all pass\n    all_passed? = config.failure_counter == 0\n\n    passed_breakdown =\n      format_passed_breakdown(config.test_counter, config.failure_type_counter, all_passed?)\n\n    passed_line =\n      cond do\n        test_counter == 0 -> \"Result: 0 tests\"\n        all_passed? -> \"Result: #{passed_counter} passed\"\n        true -> \"Result: #{passed_counter}/#{test_counter} passed\"\n      end <> passed_breakdown\n\n    # Failed line: \"Failed: 8 tests, 1 property\"\n    failed_line =\n      if config.failure_counter > 0 do\n        failed_breakdown = format_type_counts(config.failure_type_counter)\n        \"\\n\" <> failure(\"Failed: #{failed_breakdown}\", config)\n      else\n        \"\"\n      end\n\n    message =\n      (\"\\n\" <> passed_line)\n      |> if_true(\n        config.invalid_counter > 0,\n        &(&1 <> \", #{config.invalid_counter} invalid\")\n      )\n      |> if_true(\n        config.skipped_counter > 0,\n        &(&1 <> \", \" <> skipped(\"#{config.skipped_counter} skipped\", config))\n      )\n      |> if_true(\n        config.excluded_counter > 0,\n        &(&1 <> \", #{config.excluded_counter} excluded\")\n      )\n\n    cond do\n      config.failure_counter > 0 or force_failures? ->\n        IO.puts(message <> failed_line)\n\n      config.invalid_counter > 0 ->\n        IO.puts(invalid(message, config))\n\n      test_counter > 0 && config.excluded_counter == test_counter ->\n        IO.puts(invalid(message, config))\n\n      true ->\n        IO.puts(success(message, config))\n    end\n  end\n\n  defp if_true(value, false, _fun), do: value\n  defp if_true(value, true, fun), do: fun.(value)\n\n  defp print_filters(opts, key) do\n    case opts[key] do\n      [] -> :ok\n      filters -> IO.puts(format_filters(filters, key))\n    end\n  end\n\n  defp print_failure(formatted, config) do\n    cond do\n      config.trace -> IO.puts(\"\")\n      true -> IO.puts(\"\\n\")\n    end\n\n    IO.puts(formatted)\n  end\n\n  defp format_type_counts(type_counter) do\n    type_counter\n    |> Enum.sort()\n    |> Enum.map(fn {test_type, count} ->\n      \"#{count} #{pluralize_type(count, test_type)}\"\n    end)\n    |> Enum.join(\", \")\n  end\n\n  defp format_passed_breakdown(test_counter, failure_type_counter, all_passed?) do\n    # If there are no different test types, we just print \"Result: N/N passed\" without the type.\n    if map_size(test_counter) in 0..1 do\n      \"\"\n    else\n      entries =\n        test_counter\n        |> Map.keys()\n        |> Enum.sort()\n        |> Enum.map_join(\", \", fn type ->\n          total = Map.fetch!(test_counter, type)\n\n          if all_passed? do\n            \"#{total} #{pluralize_type(total, type)}\"\n          else\n            failed = Map.get(failure_type_counter, type, 0)\n            passed = total - failed\n            \"#{passed}/#{total} #{pluralize_type(total, type)}\"\n          end\n        end)\n\n      \" (\" <> entries <> \")\"\n    end\n  end\n\n  defp pluralize_type(count, type) do\n    pluralize(count, type, ExUnit.plural_rule(to_string(type)))\n  end\n\n  defp collect_test_counter(%{test_counter: test_counter} = _config) do\n    Enum.reduce(test_counter, 0, fn {_, count}, acc ->\n      acc + count\n    end)\n  end\n\n  # Color styles\n\n  defp colorize(key, string, %{colors: colors}) do\n    if escape = colors[:enabled] && colors[key] do\n      [escape, string, :reset]\n      |> IO.ANSI.format_fragment(true)\n      |> IO.iodata_to_binary()\n    else\n      string\n    end\n  end\n\n  defp colorize_doc(escape, doc, %{colors: colors}) do\n    if colors[:enabled] do\n      Inspect.Algebra.color_doc(doc, escape, %Inspect.Opts{syntax_colors: colors})\n    else\n      doc\n    end\n  end\n\n  defp success(msg, config) do\n    colorize(:success, msg, config)\n  end\n\n  defp invalid(msg, config) do\n    colorize(:invalid, msg, config)\n  end\n\n  defp skipped(msg, config) do\n    colorize(:skipped, msg, config)\n  end\n\n  defp failure(msg, config) do\n    colorize(:failure, msg, config)\n  end\n\n  defp extra_info(msg, config) do\n    colorize(:extra_info, msg, config)\n  end\n\n  # Diff formatting\n\n  defp formatter(:diff_enabled?, _, %{colors: colors}),\n    do: colors[:enabled]\n\n  defp formatter(:diff_delete, doc, config),\n    do: colorize_doc(:diff_delete, doc, config)\n\n  defp formatter(:diff_delete_whitespace, doc, config),\n    do: colorize_doc(:diff_delete_whitespace, doc, config)\n\n  defp formatter(:diff_insert, doc, config),\n    do: colorize_doc(:diff_insert, doc, config)\n\n  defp formatter(:diff_insert_whitespace, doc, config),\n    do: colorize_doc(:diff_insert_whitespace, doc, config)\n\n  defp formatter(:blame_diff, msg, %{colors: colors} = config) do\n    if colors[:enabled] do\n      colorize(:diff_delete, msg, config)\n    else\n      \"-\" <> msg <> \"-\"\n    end\n  end\n\n  defp formatter(key, msg, config), do: colorize(key, msg, config)\n\n  defp pluralize(1, singular, _plural), do: singular\n  defp pluralize(_, _singular, plural), do: plural\n\n  defp get_terminal_width do\n    case :io.columns() do\n      {:ok, width} -> max(40, width)\n      _ -> 80\n    end\n  end\n\n  @default_colors [\n    diff_delete: :red,\n    diff_delete_whitespace: IO.ANSI.color_background(2, 0, 0),\n    diff_insert: :green,\n    diff_insert_whitespace: IO.ANSI.color_background(0, 2, 0),\n\n    # CLI formatter\n    success: :green,\n    invalid: :yellow,\n    skipped: :yellow,\n    failure: :red,\n    error_info: :red,\n    extra_info: :cyan,\n    location_info: [:bright, :black]\n  ]\n\n  defp colors(opts) do\n    @default_colors\n    |> Keyword.merge(opts[:colors])\n    |> Keyword.put_new(:enabled, IO.ANSI.enabled?())\n  end\n\n  defp print_logs(\"\"), do: nil\n\n  defp print_logs(output) do\n    indent = \"\\n     \"\n    output = String.replace(output, \"\\n\", indent)\n    IO.puts([\"     The following output was logged:\", indent | output])\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/diff.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.Diff do\n  @moduledoc false\n\n  # A Diff struct and functions.\n  #\n  # The Diff struct contains the fields `:equivalent?`, `:left`, `:right`.\n  # The `:equivalent?` field represents if the `:left` and `:right` side are\n  # equivalents and contain no diffs. The `:left` and `:right` represent the\n  # sides of the comparison as ASTs.\n  #\n  # The ASTs may be wrapped in blocks with two special metas:\n  #\n  #   * `:diff` - when `true`, the AST inside of it has no equivalent\n  #     on the other side and should be rendered in a different color\n  #\n  #   * `:delimiter` - that particular block should be rendered with\n  #     a delimiter\n  #\n  # Given blocks are do not appear on the left side or right, it is\n  # safe to perform such wrapping.\n\n  alias Inspect.Algebra\n\n  defstruct equivalent?: true,\n            left: nil,\n            right: nil\n\n  @doc \"\"\"\n  Returns the diff between `left` and `right` and env after the comparison.\n\n  The `left` side can be a literal or an AST, the `right` should always be a\n  value. The `context` should be `{:match, pins}` for pattern matching and\n  `==` and `===` for comparison cases.\n  \"\"\"\n  def compute(left, right, context) do\n    diff(left, right, context_to_env(context))\n  catch\n    :undiffable -> nil\n  end\n\n  defp context_to_env({:match, pins}),\n    do: %{pins: Map.new(pins), context: :match, current_vars: %{}, hints: []}\n\n  defp context_to_env(op) when op in [:==, :===],\n    do: %{pins: %{}, context: op, current_vars: %{}, hints: []}\n\n  # Main entry point for recursive diff\n\n  defp diff(left, right, %{context: :match} = env) do\n    case left do\n      {_, [original: original] ++ _, _} ->\n        diff_quoted(original, right, left, env)\n\n      _ ->\n        diff_quoted(left, right, nil, env)\n    end\n  end\n\n  defp diff(left, right, env), do: diff_value(left, right, env)\n\n  # diff quoted\n\n  defp diff_quoted({:_, _, context} = left, right, _expanded, env) when is_atom(context) do\n    diff_right = escape(right)\n    diff = %__MODULE__{equivalent?: true, left: left, right: diff_right}\n    {diff, env}\n  end\n\n  defp diff_quoted({:^, _, [{name, _, context}]} = left, right, _expanded, env)\n       when is_atom(name) and is_atom(context) do\n    diff_pin(left, right, env)\n  end\n\n  defp diff_quoted({name, _, context} = left, right, _expanded, env)\n       when is_atom(name) and is_atom(context) and\n              name not in [:__MODULE__, :__DIR__, :__STACKTRACE__, :__ENV__, :__CALLER__] do\n    diff_var(left, right, env)\n  end\n\n  defp diff_quoted({:-, _, [number]}, right, _expanded, env) when is_number(number) do\n    diff_quoted(-number, right, nil, env)\n  end\n\n  defp diff_quoted({:+, _, [number]}, right, _expanded, env) when is_number(number) do\n    diff_quoted(number, right, nil, env)\n  end\n\n  defp diff_quoted({:++, meta, [prefix, suffix]}, right, _expanded, env) when is_list(right) do\n    diff_maybe_improper_list({:++, meta, [prefix, suffix]}, right, env)\n  end\n\n  defp diff_quoted({:{}, _, left}, right, _expanded, env) when is_tuple(right) do\n    diff_tuple(left, Tuple.to_list(right), env)\n  end\n\n  defp diff_quoted({_, _} = left, right, _expanded, env) when is_tuple(right) do\n    diff_tuple(Tuple.to_list(left), Tuple.to_list(right), env)\n  end\n\n  defp diff_quoted({:%, _, [struct, {:%{}, _, kw}]}, %{} = right, _expanded, env)\n       when is_list(kw) do\n    diff_quoted_struct([__struct__: struct] ++ kw, right, env)\n  end\n\n  defp diff_quoted({:%{}, _, kw}, %{} = right, _expanded, env) when is_list(kw) do\n    diff_quoted_struct(kw, right, env)\n  end\n\n  defp diff_quoted({:<>, _, [literal, _]} = left, right, _expanded, env)\n       when is_binary(literal) and is_binary(right) do\n    diff_string_concat(left, right, env)\n  end\n\n  defp diff_quoted({:<<>>, _, parts} = left, right, _expanded, env) do\n    if Enum.all?(parts, &is_binary/1) do\n      equivalent? = IO.iodata_to_binary(parts) == right\n      diff_left = update_diff_meta(left, not equivalent?)\n      diff_right = escape(right) |> update_diff_meta(not equivalent?)\n      diff = %__MODULE__{equivalent?: equivalent?, left: diff_left, right: diff_right}\n      {diff, env}\n    else\n      throw(:undiffable)\n    end\n  end\n\n  defp diff_quoted({:when, _, [_, _]} = left, right, _expanded, env) do\n    diff_guard(left, right, env)\n  end\n\n  defp diff_quoted({_, _, _} = left, right, expanded, env) when expanded != nil do\n    expanded = Macro.update_meta(expanded, &Keyword.delete(&1, :original))\n    {diff, post_env} = diff(expanded, right, env)\n    diff_left = update_diff_meta(left, !diff.equivalent?)\n    {%{diff | left: diff_left}, post_env}\n  end\n\n  defp diff_quoted(left, right, _expanded, env) when is_list(left) and is_list(right) do\n    diff_maybe_list(left, right, env)\n  end\n\n  defp diff_quoted(left, right, _expanded, env)\n       when is_atom(left) or is_number(left) or is_reference(left) or\n              is_pid(left) or is_function(left) or is_binary(left) do\n    diff_value(left, right, env)\n  end\n\n  defp diff_quoted(left, right, _expanded, %{context: :match} = env) do\n    diff_left = update_diff_meta(left, true)\n    diff_right = escape(right) |> update_diff_meta(true)\n    diff = %__MODULE__{equivalent?: false, left: diff_left, right: diff_right}\n    {diff, env}\n  end\n\n  ## diff_value\n\n  defp diff_value(literal, literal, env)\n       when is_atom(literal) or is_number(literal) or is_reference(literal) or\n              is_pid(literal) or is_function(literal) do\n    {%__MODULE__{equivalent?: true, left: literal, right: literal}, env}\n  end\n\n  defp diff_value(left, right, %{context: :==} = env) when left == right and is_number(left) do\n    {%__MODULE__{equivalent?: true, left: left, right: right}, env}\n  end\n\n  defp diff_value(left, right, env) when is_number(left) and is_number(right) do\n    diff_number(left, right, env)\n  end\n\n  defp diff_value(left, right, env) when is_list(left) and is_list(right) do\n    diff_maybe_list(left, right, env)\n  end\n\n  defp diff_value(left, right, env) when is_tuple(left) and is_tuple(right) do\n    diff_tuple(Tuple.to_list(left), Tuple.to_list(right), env)\n  end\n\n  defp diff_value(%left_struct{} = left, %right_struct{} = right, env) do\n    diff_struct(\n      left,\n      Map.to_list(left),\n      right,\n      left_struct,\n      right_struct,\n      env\n    )\n  end\n\n  defp diff_value(%{} = left, %{} = right, env) do\n    diff_map(Map.to_list(left), right, maybe_struct(left), maybe_struct(right), env)\n  end\n\n  defp diff_value(left, right, env) when is_binary(left) and is_binary(right) do\n    diff_string(left, right, ?\", env)\n  end\n\n  defp diff_value(left, right, env) when is_function(left) and is_function(right) do\n    # If they are local functions in the same module and same name,\n    # then they have different environment, which we compare.\n    if Function.info(left, :type) == {:type, :local} and\n         Function.info(right, :type) == {:type, :local} and\n         Function.info(left, :module) == Function.info(right, :module) and\n         Function.info(left, :new_uniq) == Function.info(right, :new_uniq) and\n         Function.info(left, :new_index) == Function.info(right, :new_index) do\n      {:env, left_env} = Function.info(left, :env)\n      {:env, right_env} = Function.info(right, :env)\n      {diff, env} = diff_maybe_improper_list(left_env, right_env, env)\n\n      diff = %{\n        diff\n        | left: %{custom: &function_env_to_algebra(left, diff.left, &1)},\n          right: %{custom: &function_env_to_algebra(right, diff.right, &1)}\n      }\n\n      {diff, env}\n    else\n      non_recursive_diff_value(left, right, env)\n    end\n  end\n\n  defp diff_value(left, right, env) do\n    non_recursive_diff_value(left, right, env)\n  end\n\n  defp non_recursive_diff_value(left, right, env) do\n    diff_left = escape(left) |> update_diff_meta(true)\n    diff_right = escape(right) |> update_diff_meta(true)\n    diff = %__MODULE__{equivalent?: false, left: diff_left, right: diff_right}\n    {diff, env}\n  end\n\n  # Guards\n\n  defp diff_guard({:when, _, [expression, clause]}, right, env) do\n    {diff, post_env} = diff_quoted(expression, right, nil, env)\n\n    {guard_clause, guard_equivalent?} =\n      if diff.equivalent? do\n        bindings = Map.merge(post_env.pins, post_env.current_vars)\n        diff_guard_clause(clause, bindings)\n      else\n        {clause, false}\n      end\n\n    diff = %{\n      diff\n      | left: {:when, [], [diff.left, guard_clause]},\n        equivalent?: guard_equivalent?\n    }\n\n    {diff, post_env}\n  end\n\n  defp diff_guard_clause(quoted, bindings) do\n    case original_or_current(quoted) do\n      {op, _, [clause1, clause2]} when op in [:and, :or, :when] ->\n        {diff_clause1, clause1_equivalent?} = diff_guard_clause(clause1, bindings)\n        {diff_clause2, clause2_equivalent?} = diff_guard_clause(clause2, bindings)\n\n        equivalent? =\n          case op do\n            :and -> clause1_equivalent? and clause2_equivalent?\n            _other -> clause1_equivalent? or clause2_equivalent?\n          end\n\n        diff = {op, [], [diff_clause1, diff_clause2]}\n        {diff, equivalent?}\n\n      _ ->\n        {original, valid?} =\n          Macro.postwalk(quoted, true, fn\n            {_, [original: original] ++ _, _}, valid? ->\n              {original, valid?}\n\n            {var, _, context} = expr, valid? when is_atom(var) and is_atom(context) ->\n              if Map.has_key?(bindings, var_context(expr)) do\n                {expr, valid?}\n              else\n                {expr, false}\n              end\n\n            other, valid? ->\n              {other, valid?}\n          end)\n\n        if valid? do\n          {equivalent?, _bindings} = Code.eval_quoted(quoted, Map.to_list(bindings))\n          {update_diff_meta(original, equivalent? != true), equivalent? == true}\n        else\n          {original, false}\n        end\n    end\n  end\n\n  defp original_or_current({_, [original: original] ++ _, _}), do: original\n  defp original_or_current(current), do: current\n\n  # Pins\n\n  defp diff_pin({:^, _, [var]} = pin, right, %{pins: pins} = env) do\n    identifier = var_context(var)\n    %{^identifier => pin_value} = pins\n    {diff, post_env} = diff_value(pin_value, right, %{env | context: :===})\n\n    diff_left = update_diff_meta(pin, not diff.equivalent?)\n    {%{diff | left: diff_left}, %{post_env | context: :match}}\n  end\n\n  # Vars\n\n  defp diff_var(left, right, env) do\n    identifier = var_context(left)\n\n    case env.current_vars do\n      %{^identifier => ^right} ->\n        diff_right = escape(right)\n        diff = %__MODULE__{equivalent?: true, left: left, right: diff_right}\n        {diff, env}\n\n      %{^identifier => _} ->\n        diff_left = update_diff_meta(left, true)\n        diff_right = escape(right) |> update_diff_meta(true)\n        diff = %__MODULE__{equivalent?: false, left: diff_left, right: diff_right}\n        {diff, env}\n\n      current_vars = %{} ->\n        updated_vars = Map.put(current_vars, identifier, right)\n        diff_right = escape(right)\n        diff = %__MODULE__{equivalent?: true, left: left, right: diff_right}\n        {diff, %{env | current_vars: updated_vars}}\n    end\n  end\n\n  # Tuples\n\n  defp diff_tuple(list_left, list_right, env) do\n    diff_tuple(list_left, list_right, true, [], [], env)\n  end\n\n  defp diff_tuple([left | tleft], [right | tright], acc_equivalent?, acc_left, acc_right, env) do\n    {diff, env} = diff(left, right, env)\n    acc_equivalent? = acc_equivalent? and diff.equivalent?\n    acc_left = [diff.left | acc_left]\n    acc_right = [diff.right | acc_right]\n    diff_tuple(tleft, tright, acc_equivalent?, acc_left, acc_right, env)\n  end\n\n  defp diff_tuple(remaining_left, remaining_right, acc_equivalent?, acc_left, acc_right, env) do\n    remaining_left =\n      Enum.map(remaining_left, &(&1 |> maybe_escape(env) |> update_diff_meta(true)))\n\n    remaining_right = Enum.map(remaining_right, &(&1 |> escape() |> update_diff_meta(true)))\n\n    equivalent? = acc_equivalent? and remaining_left == [] and remaining_right == []\n    diff_left = {:{}, [], Enum.reverse(acc_left, remaining_left)}\n    diff_right = {:{}, [], Enum.reverse(acc_right, remaining_right)}\n    {%__MODULE__{equivalent?: equivalent?, left: diff_left, right: diff_right}, env}\n  end\n\n  # Lists\n\n  defp diff_maybe_list([], [], env) do\n    {%__MODULE__{equivalent?: true, left: [], right: []}, env}\n  end\n\n  defp diff_maybe_list(left, right, env) do\n    if List.ascii_printable?(left) and List.ascii_printable?(right) do\n      {diff, env} = diff_string(List.to_string(left), List.to_string(right), ?\", env)\n\n      diff = %{\n        diff\n        | left: %{custom: &charlist_to_algebra(diff.left, &1)},\n          right: %{custom: &charlist_to_algebra(diff.right, &1)}\n      }\n\n      {diff, env}\n    else\n      diff_maybe_improper_list(left, right, env)\n    end\n  end\n\n  # Compare two lists, removing all the operators (`|` and `++`) from the left\n  # side before and adding them back in the end. Improper lists on the left side\n  # are handled as quoted expressions. Improper lists on the right side are\n  # handled as runtime improper lists.\n  defp diff_maybe_improper_list(left, right, env) do\n    {parsed_left, improper_left, operators_left, length_left} =\n      split_left_list(left, 0, env.context)\n\n    element_limit = if improper_left == [], do: -1, else: length_left\n    {parsed_right, improper_right} = split_right_list(right, element_limit, [])\n\n    {parsed_diff, parsed_post_env} = myers_difference_list(parsed_left, parsed_right, env)\n\n    {improper_diff, improper_post_env} =\n      diff_improper(improper_left, improper_right, parsed_post_env)\n\n    diff =\n      merge_diff(parsed_diff, improper_diff, fn left1, left2, right1, right2 ->\n        improper_left =\n          cond do\n            improper_left != [] -> {:improper, left2}\n            improper_right != [] -> :tail\n            true -> :nothing\n          end\n\n        left = rebuild_left_list(left1, improper_left, operators_left, env)\n        right = rebuild_right_list(right1, right2)\n        {left, right}\n      end)\n\n    {diff, improper_post_env}\n  end\n\n  defp diff_improper([], right, env) when is_list(right) do\n    equivalent? = right == []\n    right = right |> escape() |> update_diff_meta(not equivalent?)\n    {%__MODULE__{equivalent?: equivalent?, right: right, left: []}, env}\n  end\n\n  defp diff_improper(left, right, env) do\n    diff(left, right, env)\n  end\n\n  defp split_right_list([head | tail], length, acc) when length != 0,\n    do: split_right_list(tail, length - 1, [head | acc])\n\n  defp split_right_list(rest, _length, acc),\n    do: {Enum.reverse(acc), rest}\n\n  defp rebuild_right_list(left, right) do\n    left = Enum.reverse(left)\n\n    case extract_diff_meta(right) do\n      # Outer was escaped. Copy its diff? to its inner element and potentially escape it.\n      {{unescaped}, diff?} ->\n        rebuild_maybe_improper(unescaped, left, &(&1 |> escape() |> update_diff_meta(diff?)))\n\n      # We have a proper list, if there are any diffs, they will be inside, so copy as is.\n      {[_ | _] = list, false} ->\n        rebuild_maybe_improper(list, left, & &1)\n\n      # The right itself is improper, so just add it as is.\n      {_, _} ->\n        rebuild_maybe_improper(right, left, & &1)\n    end\n  end\n\n  defp rebuild_maybe_improper([head | tail], acc, fun),\n    do: rebuild_maybe_improper(tail, [fun.(head) | acc], fun)\n\n  defp rebuild_maybe_improper([], acc, _fun),\n    do: Enum.reverse(acc)\n\n  defp rebuild_maybe_improper(other, [prev | acc], fun),\n    do: Enum.reverse([{:|, [], [prev, fun.(other)]} | acc])\n\n  defp split_left_list([], _index, _context) do\n    {[], [], nil, 0}\n  end\n\n  defp split_left_list({:++, _, [left, right]}, _index, :match) do\n    {parsed_left, [], operators_left, length_left} = split_left_list(left, 0, :match)\n\n    case split_left_list(right, 0, :match) do\n      {:improper, improper} ->\n        operators = {:++, length_left, [operators_left, nil]}\n        {parsed_left, improper, operators, length_left}\n\n      {parsed_right, improper_right, operators_right, length_right} ->\n        operators = {:++, length_left, [operators_left, operators_right]}\n        length = length_right + length_left\n        {parsed_left ++ parsed_right, improper_right, operators, length}\n    end\n  end\n\n  defp split_left_list([{:|, _, [head, tail]}], index, :match) do\n    case split_left_list(tail, 0, :match) do\n      {:improper, improper} ->\n        operator = {:|, index, [nil]}\n        {[head], improper, operator, 1}\n\n      {parsed_tail, improper_tail, operators_tail, length_tail} ->\n        operators = {:|, index, [operators_tail]}\n        {[head | parsed_tail], improper_tail, operators, length_tail + 1}\n    end\n  end\n\n  defp split_left_list([head | tail], index, context) do\n    case split_left_list(tail, index + 1, context) do\n      {:improper, improper} ->\n        operator = {:|, index, [nil]}\n        {[head], improper, operator, 1}\n\n      {parsed_tail, improper_tail, operators_tail, length_tail} ->\n        {[head | parsed_tail], improper_tail, operators_tail, length_tail + 1}\n    end\n  end\n\n  defp split_left_list(element, _index, _) do\n    {:improper, element}\n  end\n\n  defp rebuild_left_list([], {:improper, improper}, _operators = nil, _env), do: improper\n  defp rebuild_left_list(list, _, _operators = nil, _env), do: list\n\n  defp rebuild_left_list(list, :tail, {:|, index, [operators]}, env) do\n    {left, [head | tail]} = Enum.split(list, index)\n    rebuilt_tail = rebuild_left_list(tail, :nothing, operators, env)\n    rebuilt_tail = rebuilt_tail |> update_diff_meta(true)\n    left ++ [{:|, [], [head, rebuilt_tail]}]\n  end\n\n  defp rebuild_left_list(list, improper, {:|, index, [operators]}, env) do\n    {left, [head | tail]} = Enum.split(list, index)\n    rebuilt_tail = rebuild_left_list(tail, improper, operators, env)\n    left ++ [{:|, [], [head, rebuilt_tail]}]\n  end\n\n  defp rebuild_left_list(list, improper, {:++, index, operators}, env) do\n    [operators_left, operators_right] = operators\n    {left, right} = Enum.split(list, index)\n\n    rebuilt_left = rebuild_left_list(left, :nothing, operators_left, env)\n    rebuilt_right = rebuild_left_list(right, improper, operators_right, env)\n\n    {:++, [], [rebuilt_left, rebuilt_right]}\n  end\n\n  defp myers_difference_list(left, right, env) do\n    path = {0, left, right, {[], [], env}}\n    find_diff(0, length(left) + length(right), [path])\n  end\n\n  defp find_diff(envelope, max, paths) do\n    case each_diagonal(-envelope, envelope, paths, []) do\n      {:done, {edit1, edit2, env}} ->\n        list_script_to_diff(Enum.reverse(edit1), Enum.reverse(edit2), true, [], [], env)\n\n      {:next, paths} ->\n        find_diff(envelope + 1, max, paths)\n    end\n  end\n\n  defp each_diagonal(diag, limit, _paths, next_paths) when diag > limit do\n    {:next, Enum.reverse(next_paths)}\n  end\n\n  defp each_diagonal(diag, limit, paths, next_paths) do\n    {path, rest} = proceed_path(diag, limit, paths)\n\n    case follow_snake(path) do\n      {:cont, path} -> each_diagonal(diag + 2, limit, rest, [path | next_paths])\n      {:done, edits} -> {:done, edits}\n    end\n  end\n\n  defp proceed_path(0, 0, [path]), do: {path, []}\n\n  defp proceed_path(diag, limit, [path | _] = paths) when diag == -limit do\n    {move_down(path), paths}\n  end\n\n  defp proceed_path(diag, limit, [path]) when diag == limit do\n    {move_right(path), []}\n  end\n\n  defp proceed_path(_diag, _limit, [path1, path2 | rest]) do\n    if elem(path1, 0) > elem(path2, 0) do\n      {move_right(path1), [path2 | rest]}\n    else\n      {move_down(path2), [path2 | rest]}\n    end\n  end\n\n  defp move_right({y, list1, [elem2 | rest2], {edit1, edit2, env}}) do\n    {y, list1, rest2, {edit1, [{:ins, elem2} | edit2], env}}\n  end\n\n  defp move_right({y, list1, [], edits}) do\n    {y, list1, [], edits}\n  end\n\n  defp move_down({y, [elem1 | rest1], list2, {edit1, edit2, env}}) do\n    {y + 1, rest1, list2, {[{:del, elem1} | edit1], edit2, env}}\n  end\n\n  defp move_down({y, [], list2, edits}) do\n    {y + 1, [], list2, edits}\n  end\n\n  defp follow_snake({y, [elem1 | rest1], [elem2 | rest2], {edit1, edit2, env}} = path) do\n    {diff, post_env} = diff(elem1, elem2, env)\n\n    if diff.equivalent? do\n      new_edit1 = [{:eq, diff.left} | edit1]\n      new_edit2 = [{:eq, diff.right} | edit2]\n\n      follow_snake({y + 1, rest1, rest2, {new_edit1, new_edit2, post_env}})\n    else\n      {:cont, path}\n    end\n  end\n\n  defp follow_snake({_y, [], [], edits}) do\n    {:done, edits}\n  end\n\n  defp follow_snake(path) do\n    {:cont, path}\n  end\n\n  defp list_script_to_diff([], [], equivalent?, left, right, env) do\n    diff = %__MODULE__{\n      equivalent?: equivalent?,\n      left: Enum.reverse(left),\n      right: Enum.reverse(right)\n    }\n\n    {diff, env}\n  end\n\n  defp list_script_to_diff(\n         [{:del, elem1} | rest1],\n         [{:ins, elem2} | rest2],\n         equivalent?,\n         left,\n         right,\n         env\n       ) do\n    {diff, env} = diff(elem1, elem2, env)\n    equivalent? = equivalent? and diff.equivalent?\n    list_script_to_diff(rest1, rest2, equivalent?, [diff.left | left], [diff.right | right], env)\n  end\n\n  defp list_script_to_diff([{:del, elem1} | rest1], rest2, _, left, right, env) do\n    diff_left = elem1 |> maybe_escape(env) |> update_diff_meta(true)\n    list_script_to_diff(rest1, rest2, false, [diff_left | left], right, env)\n  end\n\n  defp list_script_to_diff(rest1, [{:ins, elem2} | rest2], _, left, right, env) do\n    diff_right = elem2 |> escape() |> update_diff_meta(true)\n    list_script_to_diff(rest1, rest2, false, left, [diff_right | right], env)\n  end\n\n  defp list_script_to_diff(\n         [{:eq, elem1} | rest1],\n         [{:eq, elem2} | rest2],\n         equivalent?,\n         left,\n         right,\n         env\n       ) do\n    list_script_to_diff(rest1, rest2, equivalent?, [elem1 | left], [elem2 | right], env)\n  end\n\n  # Maps\n\n  # Compare items based on the keys of `left_items` and add the `:diff` meta to\n  # the element that it wasn't able to compare.\n  defp diff_map(left_items, right, struct1, struct2, env) do\n    {equivalent?, left, right, env} = diff_map_by_key(left_items, right, env)\n    left = build_map_or_struct(left, struct1)\n    right = build_map_or_struct(right, struct2)\n    {%__MODULE__{equivalent?: equivalent?, left: left, right: right}, env}\n  end\n\n  defp diff_map_by_key(items, right, env) do\n    {acc_equivalent?, acc_left, acc_right, pending_left, pending_right, env} =\n      Enum.reduce(items, {true, [], [], [], right, env}, fn\n        {left_key, left_value},\n        {acc_equivalent?, acc_left, acc_right, pending_left, pending_right, env} ->\n          right_key = literal_key(left_key, env)\n\n          case pending_right do\n            %{^right_key => right_value} ->\n              pending_right = Map.delete(pending_right, right_key)\n              {diff, env} = diff(left_value, right_value, env)\n              acc_equivalent? = acc_equivalent? and diff.equivalent?\n              acc_left = [{maybe_escape(left_key, env), diff.left} | acc_left]\n              acc_right = [{escape(right_key), diff.right} | acc_right]\n              {acc_equivalent?, acc_left, acc_right, pending_left, pending_right, env}\n\n            %{} ->\n              pair = {maybe_escape(left_key, env), maybe_escape(left_value, env)}\n              pair_diff = update_diff_meta(pair, true)\n              {false, acc_left, acc_right, [pair_diff | pending_left], pending_right, env}\n          end\n      end)\n\n    # It may be a struct, so make sure we convert it to a list before calling Enum\n    pending_right = Map.to_list(pending_right)\n\n    {pending_right, equivalent?} =\n      if env.context == :match do\n        {Enum.map(pending_right, &escape_pair/1), acc_equivalent?}\n      else\n        pending_right = Enum.map(pending_right, &(&1 |> escape_pair() |> update_diff_meta(true)))\n        {pending_right, acc_equivalent? and pending_right == []}\n      end\n\n    left = Enum.sort(acc_left) ++ Enum.sort(pending_left)\n    right = Enum.sort(acc_right) ++ Enum.sort(pending_right)\n\n    {equivalent?, left, right, env}\n  end\n\n  defp literal_key({:^, _, [var]}, %{pins: pins}) do\n    identifier = var_context(var)\n    %{^identifier => pin_value} = pins\n    pin_value\n  end\n\n  defp literal_key(literal, _env) do\n    literal\n  end\n\n  # Structs\n\n  defp diff_quoted_struct(kw, right, env) do\n    if struct = struct_module(kw) do\n      with true <- Macro.quoted_literal?(kw),\n           {eval_kw, []} <- safe_eval(kw),\n           {:ok, data} <- load_struct(struct, eval_kw) do\n        diff_quoted_struct(data, kw, right, struct, env)\n      else\n        _ -> diff_map(kw, right, struct, maybe_struct(right), env)\n      end\n    else\n      diff_map(kw, right, nil, maybe_struct(right), env)\n    end\n  end\n\n  defp diff_quoted_struct(left, kw, %struct2{} = right, struct1, env) do\n    diff_struct(left, kw, right, struct1, struct2, env)\n  end\n\n  defp diff_quoted_struct(_left, kw, right, struct1, env) do\n    diff_map(kw, right, struct1, nil, env)\n  end\n\n  defp diff_struct(left, kw, right, struct1, struct2, env) do\n    with true <- Inspect.impl_for(left) not in [Inspect.Any, Inspect.Map],\n         {:ok, inspect_left} <- safe_inspect(left),\n         {:ok, inspect_right} <- safe_inspect(right) do\n      if inspect_left != inspect_right do\n        diff_string(inspect_left, inspect_right, nil, env)\n      else\n        # If they are equivalent, still use their inspected form\n        case diff_map(kw, right, struct1, struct2, env) do\n          {%{equivalent?: true}, ctx} ->\n            {%__MODULE__{equivalent?: true, left: left, right: right}, ctx}\n\n          diff_ctx ->\n            diff_ctx\n        end\n      end\n    else\n      _ -> diff_map(kw, right, struct1, struct2, env)\n    end\n  end\n\n  defp struct_module(kw) do\n    {struct, struct_kw} = Keyword.pop(kw, :__struct__)\n\n    info =\n      is_atom(struct) and struct != nil and\n        Code.ensure_loaded?(struct) and function_exported?(struct, :__info__, 1) and\n        struct.__info__(:struct)\n\n    if info && Enum.all?(struct_kw, fn {k, _} -> Enum.any?(info, &(&1.field == k)) end) do\n      struct\n    end\n  end\n\n  defp load_struct(struct, kw) do\n    {:ok, struct!(struct, kw)}\n  rescue\n    _ -> :error\n  end\n\n  defp maybe_struct(%name{}), do: name\n  defp maybe_struct(_), do: nil\n\n  defp build_map_or_struct(items, nil) do\n    {:%{}, [], items}\n  end\n\n  defp build_map_or_struct(items, _struct) do\n    {struct, items} = pop_struct(items, [])\n    {:%, [], [struct, {:%{}, [], items}]}\n  end\n\n  defp pop_struct([{:__block__, meta, [{:__struct__, struct}]} | tail], acc),\n    do: {{:__block__, meta, [struct]}, Enum.reverse(acc, tail)}\n\n  defp pop_struct([{:__struct__, struct} | tail], acc),\n    do: {struct, Enum.reverse(acc, tail)}\n\n  defp pop_struct([head | rest], acc),\n    do: pop_struct(rest, [head | acc])\n\n  # Strings\n\n  defp diff_string(left, right, delimiter, env) do\n    {escaped_left, _} = Code.Identifier.escape(left, delimiter)\n    {escaped_right, _} = Code.Identifier.escape(right, delimiter)\n    left = IO.iodata_to_binary(escaped_left)\n    right = IO.iodata_to_binary(escaped_right)\n\n    cond do\n      left == right ->\n        {string_script_to_diff([eq: left], delimiter, true, [], []), env}\n\n      diff_string?(left, right) ->\n        diff =\n          String.myers_difference(left, right)\n          |> string_script_to_diff(delimiter, true, [], [])\n\n        env =\n          if String.equivalent?(left, right) do\n            add_hint(env, :equivalent_but_different_strings)\n          else\n            env\n          end\n\n        {diff, env}\n\n      true ->\n        {string_script_to_diff([del: left, ins: right], delimiter, true, [], []), env}\n    end\n  end\n\n  # Concat all the literals on `left` and split `right` based on the size of\n  # that, comparing them and the remaining AST from `left` and the remaining\n  # string from `right`.\n  defp diff_string_concat(left, right, env) do\n    {parsed_left, quoted, indexes, parsed_left_length} = parse_string(left)\n\n    diff_string_concat(parsed_left, quoted, indexes, parsed_left_length, right, env)\n  end\n\n  defp diff_string_concat(left, nil, indexes, _left_length, right, env) do\n    {diff, parsed_post_env} = diff_string(left, right, ?\", env)\n    left_diff = rebuild_concat_string(diff.left, nil, indexes)\n\n    diff = %{diff | left: left_diff}\n    {diff, parsed_post_env}\n  end\n\n  defp diff_string_concat(left, quoted, indexes, left_length, right, env) do\n    {parsed_right, continue_right} = String.split_at(right, left_length)\n    {parsed_diff, parsed_post_env} = diff_string(left, parsed_right, ?\", env)\n    {quoted_diff, quoted_post_env} = diff(quoted, continue_right, parsed_post_env)\n\n    diff =\n      merge_diff(parsed_diff, quoted_diff, fn left1, left2, right1, right2 ->\n        new_left = rebuild_concat_string(left1, left2, indexes)\n        new_right = rebuild_split_strings(right1, right2)\n        {new_left, new_right}\n      end)\n\n    {diff, quoted_post_env}\n  end\n\n  defp diff_string?(left, right) do\n    String.bag_distance(left, right) > 0.4\n  end\n\n  defp parse_string({:<>, _, [literal, rest]}) when is_binary(literal) do\n    {parsed, quoted, indexes, parsed_length} = parse_string(rest)\n    literal_length = String.length(literal)\n    length = literal_length + parsed_length\n    {literal <> parsed, quoted, [literal_length | indexes], length}\n  end\n\n  defp parse_string(literal) when is_binary(literal) do\n    {literal, nil, [], String.length(literal)}\n  end\n\n  defp parse_string(pattern) do\n    {\"\", pattern, [], 0}\n  end\n\n  defp rebuild_split_strings(left, \"\") do\n    left\n  end\n\n  defp rebuild_split_strings(\n         %{contents: left, delimiter: delimiter},\n         %{contents: right, delimiter: delimiter}\n       ) do\n    %{contents: left ++ right, delimiter: delimiter}\n  end\n\n  defp rebuild_split_strings(%{contents: contents, delimiter: delimiter}, right) do\n    {new_right, diff} = extract_diff_meta(right)\n    %{contents: contents ++ [{diff, new_right}], delimiter: delimiter}\n  end\n\n  defp rebuild_concat_string(literal, nil, []) do\n    literal\n  end\n\n  defp rebuild_concat_string(_literal, quoted, []) do\n    quoted\n  end\n\n  defp rebuild_concat_string(literal, quoted, [index | rest]) do\n    {next, continue} = next_concat_result(literal, index)\n    rebuilt_right = rebuild_concat_string(continue, quoted, rest)\n    {:<>, [], [next, rebuilt_right]}\n  end\n\n  defp next_concat_result(%{contents: contents, delimiter: delimiter}, index) do\n    {next, continue} = next_concat_result(contents, index)\n    {%{contents: next, delimiter: delimiter}, %{contents: continue, delimiter: delimiter}}\n  end\n\n  defp next_concat_result([{diff?, head} | tail], index) do\n    length = String.length(head)\n\n    cond do\n      length > index ->\n        {next, continue} = String.split_at(head, index)\n        {[{diff?, next}], [{diff?, continue} | tail]}\n\n      length < index ->\n        {next, continue} = next_concat_result(tail, index - length)\n        {[{diff?, head} | next], continue}\n\n      true ->\n        {[{diff?, head}], tail}\n    end\n  end\n\n  defp string_script_to_diff([], delimiter, equivalent?, left, right) do\n    left = %{delimiter: delimiter, contents: Enum.reverse(left)}\n    right = %{delimiter: delimiter, contents: Enum.reverse(right)}\n    %__MODULE__{equivalent?: equivalent?, left: left, right: right}\n  end\n\n  defp string_script_to_diff([{:eq, string} | tail], delimiter, equivalent?, left, right) do\n    string_script_to_diff(\n      tail,\n      delimiter,\n      equivalent?,\n      [{false, string} | left],\n      [{false, string} | right]\n    )\n  end\n\n  defp string_script_to_diff([{:del, string} | tail], delimiter, _equivalent?, left, right) do\n    string_script_to_diff(tail, delimiter, false, [{true, string} | left], right)\n  end\n\n  defp string_script_to_diff([{:ins, string} | tail], delimiter, _equivalent?, left, right) do\n    string_script_to_diff(tail, delimiter, false, left, [{true, string} | right])\n  end\n\n  # Numbers\n\n  defp diff_number(left, right, env) do\n    diff_string(inspect(left), inspect(right), nil, env)\n  end\n\n  # Algebra\n\n  @doc \"\"\"\n  Converts a diff to an algebra document.\n  \"\"\"\n  def to_algebra(quoted, diff_wrapper) do\n    wrap_on_diff(quoted, &safe_to_algebra/2, diff_wrapper)\n  end\n\n  defp safe_to_algebra(list, diff_wrapper) when is_list(list) do\n    container_to_algebra(\"[\", list, \"]\", diff_wrapper, select_list_item_algebra(list))\n  end\n\n  defp safe_to_algebra({op, _, [left, right]}, diff_wrapper)\n       when op in [:<>, :++, :|, :when, :and, :or] do\n    to_algebra(left, diff_wrapper)\n    |> Algebra.concat(\" #{op} \")\n    |> Algebra.concat(to_algebra(right, diff_wrapper))\n  end\n\n  defp safe_to_algebra({:{}, _, args}, diff_wrapper) do\n    container_to_algebra(\"{\", args, \"}\", diff_wrapper, &to_algebra/2)\n  end\n\n  defp safe_to_algebra({a, b}, diff_wrapper) do\n    container_to_algebra(\"{\", [a, b], \"}\", diff_wrapper, &to_algebra/2)\n  end\n\n  defp safe_to_algebra({:%, _, [{:_, _, _}, {:%{}, _, list}]}, diff_wrapper) do\n    open = Algebra.concat([\"%\", \"_\", \"{\"])\n    container_to_algebra(open, list, \"}\", diff_wrapper, select_map_item_to_algebra(list))\n  end\n\n  defp safe_to_algebra({:%, _, [struct, {:%{}, _, list}]}, diff_wrapper) do\n    open = Algebra.concat([\"%\", struct_to_algebra(struct, diff_wrapper), \"{\"])\n    container_to_algebra(open, list, \"}\", diff_wrapper, select_map_item_to_algebra(list))\n  end\n\n  defp safe_to_algebra({:%{}, _, list}, diff_wrapper) do\n    container_to_algebra(\"%{\", list, \"}\", diff_wrapper, select_map_item_to_algebra(list))\n  end\n\n  defp safe_to_algebra({_, meta, args} = quoted, _diff_wrapper)\n       when is_list(meta) and (is_list(args) or is_atom(args)) do\n    Macro.to_string(quoted)\n  end\n\n  defp safe_to_algebra({escaped}, _diff_wrapper) do\n    inspect(escaped)\n  end\n\n  # Custom encoding for delimiters+contents\n  defp safe_to_algebra(%{delimiter: delimiter, contents: contents}, diff_wrapper) do\n    content_docs =\n      for {diff?, content} <- contents do\n        if diff?, do: diff_wrapper.(content), else: content\n      end\n\n    if delimiter do\n      delimiter = List.to_string([delimiter])\n      Algebra.concat([delimiter, Algebra.concat(content_docs), delimiter])\n    else\n      Algebra.concat(content_docs)\n    end\n  end\n\n  # Custom encoding for functions\n  defp safe_to_algebra(%{custom: literal}, diff_wrapper) do\n    literal.(diff_wrapper)\n  end\n\n  defp safe_to_algebra(literal, _diff_wrapper) do\n    inspect(literal)\n  end\n\n  defp keyword_to_algebra(quoted, diff_wrapper) do\n    wrap_on_diff(quoted, &safe_keyword_to_algebra/2, diff_wrapper)\n  end\n\n  defp safe_keyword_to_algebra({:{}, _, [key, value]}, diff_wrapper) do\n    keyword_to_algebra({key, value}, diff_wrapper)\n  end\n\n  defp safe_keyword_to_algebra({key, value}, diff_wrapper) do\n    key_to_algebra(key, diff_wrapper)\n    |> Algebra.concat(\" \")\n    |> Algebra.concat(to_algebra(value, diff_wrapper))\n  end\n\n  defp key_to_algebra(quoted, diff_wrapper) do\n    wrap_on_diff(quoted, &safe_key_to_algebra/2, diff_wrapper)\n  end\n\n  defp safe_key_to_algebra(key, _diff_wrapper) do\n    Macro.inspect_atom(:key, key)\n  end\n\n  defp map_item_to_algebra(quoted, diff_wrapper) do\n    wrap_on_diff(quoted, &safe_map_item_to_algebra/2, diff_wrapper)\n  end\n\n  defp safe_map_item_to_algebra({:{}, _, [key, value]}, diff_wrapper) do\n    safe_map_item_to_algebra({key, value}, diff_wrapper)\n  end\n\n  defp safe_map_item_to_algebra({key, value}, diff_wrapper) do\n    to_algebra(key, diff_wrapper)\n    |> Algebra.concat(\" => \")\n    |> Algebra.concat(to_algebra(value, diff_wrapper))\n  end\n\n  defp container_to_algebra(open, list, close, diff_wrapper, item_to_algebra) do\n    docs =\n      list\n      |> Enum.map(&item_to_algebra.(&1, diff_wrapper))\n      |> Algebra.fold(&join_docs/2)\n\n    open\n    |> Algebra.glue(\"\", docs)\n    |> Algebra.nest(2)\n    |> Algebra.glue(\"\", close)\n    |> Algebra.group()\n  end\n\n  defp join_docs(doc1, doc2) do\n    doc1\n    |> Algebra.concat(\",\")\n    |> Algebra.glue(doc2)\n  end\n\n  defp struct_to_algebra(quoted, diff_wrapper) do\n    wrap_on_diff(quoted, &safe_struct_to_algebra/2, diff_wrapper)\n  end\n\n  defp safe_struct_to_algebra({:^, _, _} = name, _diff_wrapper) do\n    Macro.to_string(name)\n  end\n\n  defp safe_struct_to_algebra(name, _diff_wrapper) do\n    Macro.inspect_atom(:literal, name)\n  end\n\n  defp select_list_item_algebra(list) do\n    short? = Enum.all?(list, &keyword?/1)\n    if short?, do: &keyword_to_algebra/2, else: &to_algebra/2\n  end\n\n  defp select_map_item_to_algebra(list) do\n    short? = Enum.all?(list, &keyword?/1)\n    if short?, do: &keyword_to_algebra/2, else: &map_item_to_algebra/2\n  end\n\n  defp wrap_on_diff(quoted, fun, wrapper) do\n    case extract_diff_meta(quoted) do\n      {expr, true} -> fun.(expr, & &1) |> wrapper.()\n      {expr, false} -> fun.(expr, wrapper)\n    end\n  end\n\n  defp charlist_to_algebra(%{contents: contents}, diff_wrapper) do\n    content_doc =\n      for {diff, content} <- contents do\n        if diff, do: diff_wrapper.(content), else: content\n      end\n\n    Algebra.concat([\"~c\\\"\", Algebra.concat(content_doc), \"\\\"\"])\n  end\n\n  defp function_env_to_algebra(function, ast, diff_wrapper) do\n    \"#Function<\" <> contents = inspect(function)\n\n    Algebra.concat([\n      \"#Function<\",\n      Algebra.nest(\n        Algebra.concat([\n          Algebra.line(),\n          binary_slice(contents, 0..-2//1),\n          Algebra.line(),\n          to_algebra(ast, diff_wrapper)\n        ]),\n        2\n      ),\n      Algebra.line(),\n      \">\"\n    ])\n  end\n\n  # Diff helpers\n\n  defp add_hint(%{hints: hints} = env, hint) do\n    if hint in hints, do: env, else: %{env | hints: [hint | hints]}\n  end\n\n  defp maybe_escape(other, %{context: :match}), do: other\n  defp maybe_escape(other, _env), do: escape(other)\n\n  # We escape container types to make a distinction between AST and values that\n  # should be inspected. Maps and structs without custom inspect implementation\n  # should not be inspected, convert it to ast.\n  # All other values have no special AST representation, so we can keep them as is.\n  defp escape(other) when is_map(other) do\n    struct = maybe_struct(other)\n\n    if struct && Inspect.impl_for(other) not in [Inspect.Any, Inspect.Map] do\n      other\n    else\n      other\n      |> Map.to_list()\n      |> Enum.sort()\n      |> Enum.map(&escape_pair/1)\n      |> build_map_or_struct(struct)\n    end\n  end\n\n  defp escape(other) when is_list(other) or is_tuple(other), do: {other}\n  defp escape(other), do: other\n\n  defp escape_pair({key, value}), do: {escape(key), escape(value)}\n\n  defp merge_diff(%__MODULE__{} = result1, %__MODULE__{} = result2, fun) do\n    {left, right} = fun.(result1.left, result2.left, result1.right, result2.right)\n\n    %__MODULE__{\n      equivalent?: result1.equivalent? && result2.equivalent?,\n      left: left,\n      right: right\n    }\n  end\n\n  defp update_diff_meta({left, meta, right}, false) when is_list(meta),\n    do: {left, Keyword.delete(meta, :diff), right}\n\n  defp update_diff_meta({left, meta, right}, true) when is_list(meta),\n    do: {left, Keyword.put(meta, :diff, true), right}\n\n  defp update_diff_meta(literal, false),\n    do: literal\n\n  defp update_diff_meta(literal, true),\n    do: {:__block__, [diff: true], [literal]}\n\n  defp extract_diff_meta({:__block__, [diff: true], [literal]}),\n    do: {literal, true}\n\n  defp extract_diff_meta({left, meta, right}) when is_list(meta),\n    do: {{left, meta, right}, !!meta[:diff]}\n\n  defp extract_diff_meta(other), do: {other, false}\n\n  defp keyword?(quoted) do\n    {pair, _} = extract_diff_meta(quoted)\n    safe_keyword?(pair)\n  end\n\n  defp safe_keyword?({key, _value}), do: key_is_atom?(key)\n  defp safe_keyword?({:{}, _meta, [key, _value]}), do: key_is_atom?(key)\n  defp safe_keyword?(_other), do: false\n\n  defp key_is_atom?(quoted) do\n    {key, _} = extract_diff_meta(quoted)\n    is_atom(key)\n  end\n\n  defp var_context({name, meta, context}) do\n    {name, meta[:counter] || context}\n  end\n\n  defp safe_eval(expr) do\n    Code.eval_quoted(expr, [])\n  rescue\n    _ -> :error\n  end\n\n  defp safe_inspect(value) do\n    {:ok, inspect(value, safe: false)}\n  rescue\n    _ -> :error\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/doc_test.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.DocTest do\n  @moduledoc ~S\"\"\"\n  Extract test cases from the documentation.\n\n  Doctests allow us to generate tests from code examples found\n  in `@moduledoc` and `@doc` attributes. To do this, invoke the\n  `doctest/1` macro from within your test case and ensure your\n  code examples are written according to the syntax and guidelines\n  below.\n\n  ## Syntax\n\n  Every new test starts on a new line, with an `iex>` prefix.\n  Multiline expressions can be used by prefixing subsequent lines\n  with either `...>` (recommended) or `iex>`.\n\n  The expected result should start the line after the `iex>`\n  and `...>` line(s) and be terminated by a newline.\n\n  ## Examples\n\n  To run doctests include them in an ExUnit case with a `doctest` macro:\n\n      defmodule MyModuleTest do\n        use ExUnit.Case, async: true\n        doctest MyModule\n      end\n\n  The `doctest` macro loops through all functions and\n  macros defined in `MyModule`, parsing their documentation in\n  search of code examples.\n\n  A very basic example is:\n\n      iex> 1 + 1\n      2\n\n  Expressions on multiple lines are also supported:\n\n      iex> Enum.map([1, 2, 3], fn x ->\n      ...>   x * 2\n      ...> end)\n      [2, 4, 6]\n\n  Multiple results can be checked within the same test:\n\n      iex> a = 1\n      1\n      iex> a + 1\n      2\n\n  If you want to keep any two tests separate,\n  add an empty line between them:\n\n      iex> a = 1\n      1\n\n      iex> a + 1 # will fail with a `undefined variable \"a\"` error\n      2\n\n  If you don't want to assert for every result in a doctest, you can omit\n  the result. You can do so between expressions:\n\n      iex> pid = spawn(fn -> :ok end)\n      iex> is_pid(pid)\n      true\n\n  As well as at the end:\n\n      iex> Mod.do_a_call_that_should_not_raise!(...)\n\n  This is useful when the result is something variable (like a PID in the\n  example above) or when the result is a complicated data structure and you\n  don't want to show it all, but just parts of it or some of its properties.\n\n  Similarly to IEx you can use numbers in your \"prompts\":\n\n      iex(1)> [1 + 2,\n      ...(1)>  3]\n      [3, 3]\n\n  This is useful in two cases:\n\n    * being able to refer to specific numbered scenarios\n    * copy-pasting examples from an actual IEx session\n\n  You can also select or skip functions when calling\n  `doctest`. See the documentation on the `:except` and `:only` options below\n  for more information.\n\n  ## Opaque types\n\n  Some types' internal structures are kept hidden and instead show a\n  user-friendly structure when inspected. The idiom in\n  Elixir is to print those data types in the format `#Name<...>`. Because those\n  values are treated as comments in Elixir code due to the leading\n  `#` sign, they require special care when being used in doctests.\n\n  Imagine you have a map that contains a `DateTime` and is printed as:\n\n      %{datetime: #DateTime<2023-06-26 09:30:00+09:00 JST Asia/Tokyo>}\n\n  If you try to match on such an expression, `doctest` will fail to compile.\n  There are two ways to resolve this.\n\n  The first is to rely on the fact that doctest can compare internal\n  structures as long as they are at the root. So one could write:\n\n      iex> map = %{datetime: DateTime.from_naive!(~N[2023-06-26T09:30:00], \"Asia/Tokyo\")}\n      iex> map.datetime\n      #DateTime<2023-06-26 09:30:00+09:00 JST Asia/Tokyo>\n\n  Whenever a doctest starts with \"#Name<\", `doctest` will perform a string\n  comparison. For example, the above test will perform the following match:\n\n      inspect(map.datetime) == \"#DateTime<2023-06-26 09:30:00+09:00 JST Asia/Tokyo>\"\n\n  You can also control `doctest` to use certain inspect options. See the\n  documentation on the `:inspect_opts` option below.\n\n  Alternatively, since doctest results are actually evaluated, you can have\n  the `DateTime` building expression as the doctest result:\n\n      iex> %{datetime: DateTime.from_naive!(~N[2023-06-26T09:30:00], \"Asia/Tokyo\")}\n      %{datetime: DateTime.from_naive!(~N[2023-06-26T09:30:00], \"Asia/Tokyo\")}\n\n  The downside of this approach is that the doctest result is not really\n  what users would see in the terminal.\n\n  ## Exceptions\n\n  You can also showcase expressions raising an exception, for example:\n\n      iex> raise \"some error\"\n      ** (RuntimeError) some error\n\n  Doctest will look for a line starting with `** (` and it will parse it\n  accordingly to extract the exception name and message. The exception parser\n  will consider all following lines part of the exception message until there\n  is an empty line or there is a new expression prefixed with `iex>`.\n  Therefore, it is possible to match on multiline messages as long as there\n  are no empty lines on the message itself.\n\n  Asserting on the full exception message might not be possible because it is\n  non-deterministic, or it might result in brittle tests if the exact message\n  changes and gets more detailed.\n  Since Elixir 1.19.0, doctests allow the use of an ellipsis (`...`) at the\n  end of messages:\n\n      iex> raise \"some error in pid: #{inspect(self())}\"\n      ** (RuntimeError) some error in pid: ...\n\n      iex> raise \"some error in pid:\\n#{inspect(self())}\"\n      ** (RuntimeError) some error in pid:\n      ...\n\n  ## When not to use doctest\n\n  In general, doctests are not recommended when your code examples contain\n  side effects. For example, if a doctest prints to standard output, doctest\n  will not try to capture the output.\n\n  Similarly, doctests do not run in any kind of sandbox. So any module\n  defined in a code example is going to linger throughout the whole test\n  suite run.\n  \"\"\"\n\n  defmodule Error do\n    @moduledoc \"\"\"\n    Exception raised when there's an error with the syntax or semantics of a doctest.\n    \"\"\"\n\n    @typedoc since: \"1.16.0\"\n    @type t :: %__MODULE__{message: String.t()}\n    defexception [:message]\n\n    @impl true\n    def exception(opts) do\n      module = Keyword.fetch!(opts, :module)\n      message = Keyword.fetch!(opts, :message)\n\n      message =\n        if source = module.module_info(:compile)[:source] do\n          file_line = Exception.format_file_line(Path.relative_to_cwd(source), opts[:line])\n          file_line <> \" \" <> message\n        else\n          message\n        end\n\n      %__MODULE__{message: message}\n    end\n  end\n\n  @doc \"\"\"\n  Generate test cases from module documentation.\n\n  Calling `doctest(Module)` will generate tests for all doctests found\n  in the `module`.\n\n  ## Options\n\n    * `:except` - generates tests for all functions except those listed\n      (list of `{function, arity}` tuples, and/or `:moduledoc`).\n\n    * `:only` - generates tests only for functions listed\n      (list of `{function, arity}` tuples, and/or `:moduledoc`).\n\n    * `:import` - when `true`, one can test a function defined in the module\n      without referring to the module name. However, this is not feasible when\n      there is a clash with a module like `Kernel`. In these cases, `:import`\n      should be set to `false` and `Module.function(...)` should be used instead.\n\n    * `:tags` - a list of tags to apply to all generated doctests.\n\n    * `:inspect_opts` - A keyword list with options for `inspect/2` on opaque\n      types. This is useful when inspection output on opaque types utilizes\n      pretty printing and to keep the doctests more readable.\n\n  ## Examples\n\n      defmodule MyModuleTest do\n        use ExUnit.Case\n        doctest MyModule, except: [:moduledoc, trick_fun: 1]\n      end\n\n  This macro is auto-imported with every `ExUnit.Case`.\n  \"\"\"\n  defmacro doctest(module, opts \\\\ []) do\n    caller = __CALLER__\n\n    require =\n      if is_atom(Macro.expand(module, caller)) do\n        quote do\n          require unquote(module)\n        end\n      end\n\n    tests =\n      quote bind_quoted: [\n              module: module,\n              opts: opts,\n              env_line: caller.line,\n              env_file: caller.file\n            ] do\n        file = ExUnit.DocTest.__file__(module)\n\n        for {name, test, tags} <- ExUnit.DocTest.__doctests__(module, opts) do\n          @file file\n          doc = ExUnit.Case.register_test(__MODULE__, env_file, env_line, :doctest, name, tags)\n          def unquote(doc)(_), do: unquote(test)\n        end\n      end\n\n    [require, tests]\n  end\n\n  @doc \"\"\"\n  Generate test cases from a markdown file.\n\n  ## Options\n\n    * `:tags` - a list of tags to apply to all generated doctests.\n\n    * `:inspect_opts` - A keyword list with options for `inspect/2` on opaque\n      types. This is useful when inspection output on opaque types utilizes\n      pretty printing and to keep the doctests more readable.\n\n  ## Examples\n\n      defmodule ReadmeTest do\n        use ExUnit.Case\n        doctest_file \"README.md\"\n      end\n\n  This macro is auto-imported with every `ExUnit.Case`.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  defmacro doctest_file(file, opts \\\\ []) do\n    caller = __CALLER__\n\n    tests =\n      quote bind_quoted: [file: file, opts: opts, env_line: caller.line, env_file: caller.file] do\n        for {name, test, tags} <- ExUnit.DocTest.__doctest_file__(file, __MODULE__, opts) do\n          doc = ExUnit.Case.register_test(__MODULE__, env_file, env_line, :doctest, name, tags)\n          def unquote(doc)(_), do: unquote(test)\n        end\n      end\n\n    tests\n  end\n\n  @doc false\n  def __doctest_file__(file, module, opts) do\n    doc = File.read!(file)\n    file = Path.relative_to_cwd(file)\n    tags = [doctest: file] ++ Keyword.get(opts, :tags, [])\n    inspect_opts = Keyword.get(opts, :inspect_opts, [])\n\n    extract_tests(1, doc, module, :moduledoc)\n    |> Enum.with_index(fn test, acc ->\n      {\n        \"#{file} (#{acc + 1})\",\n        test_content(test, module, false, file, inspect_opts),\n        test_tags(test, tags)\n      }\n    end)\n  end\n\n  @doc false\n  def __file__(module) do\n    info =\n      if source = module.module_info(:compile)[:source] do\n        Path.relative_to_cwd(source)\n      else\n        inspect(module)\n      end\n\n    \"(for doctest at) \" <> info\n  end\n\n  @doc false\n  def __doctests__(module, opts) do\n    tags = [doctest: module] ++ Keyword.get(opts, :tags, [])\n    import = Keyword.get(opts, :import, false)\n    inspect_opts = Keyword.get(opts, :inspect_opts, [])\n\n    maybe_source =\n      if source = module.module_info(:compile)[:source] do\n        Path.relative_to_cwd(source)\n      end\n\n    extract(module)\n    |> filter_by_opts(module, opts)\n    |> Enum.sort_by(& &1.line)\n    |> Enum.with_index(fn test, index ->\n      compile_test(test, module, import, index + 1, maybe_source, tags, inspect_opts)\n    end)\n  end\n\n  defp filter_by_opts(tests, module, opts) do\n    except = Keyword.get(opts, :except, [])\n\n    case Keyword.fetch(opts, :only) do\n      {:ok, []} -> []\n      {:ok, only} -> filter_tests(module, tests, except, only)\n      :error -> Stream.reject(tests, &(&1.fun_arity in except))\n    end\n  end\n\n  defp filter_tests(module, tests, except, only) do\n    {filtered_tests, fun_arities} =\n      for test <- tests,\n          test.fun_arity not in except,\n          test.fun_arity in only,\n          reduce: {[], []} do\n        {tests, fun_arities} -> {[test | tests], [test.fun_arity | fun_arities]}\n      end\n\n    case only -- [:moduledoc | fun_arities] do\n      [] ->\n        filtered_tests\n\n      undefined_fun_arities ->\n        pluralized = pluralize_list_name(\"function\", undefined_fun_arities)\n\n        functions =\n          Enum.map_join(undefined_fun_arities, \"\\n    \", fn {fun, arity} ->\n            Exception.format_mfa(module, fun, arity)\n          end)\n\n        raise Error,\n          module: module,\n          message: \"undefined or private #{pluralized} given to doctest:\\n\\n    #{functions}\\n\\n\"\n    end\n  end\n\n  defp pluralize_list_name(name, [_]), do: name\n  defp pluralize_list_name(name, _), do: ExUnit.plural_rule(name)\n\n  ## Compilation of extracted tests\n\n  defp compile_test(test, module, do_import, n, maybe_source, tags, inspect_opts) do\n    {\n      test_name(test, module, n),\n      test_content(test, module, do_import, maybe_source, inspect_opts),\n      test_tags(test, tags)\n    }\n  end\n\n  defp test_name(%{fun_arity: :moduledoc}, m, n) do\n    \"module #{inspect(m)} (#{n})\"\n  end\n\n  defp test_name(%{fun_arity: {f, a}}, m, n) do\n    \"#{inspect(m)}.#{f}/#{a} (#{n})\"\n  end\n\n  defp test_content(%{exprs: exprs, line: line}, module, do_import, maybe_source, inspect_opts) do\n    if multiple_exceptions?(exprs) do\n      raise Error,\n        line: line,\n        module: module,\n        message:\n          \"multiple exceptions in the same doctest example are not supported, \" <>\n            \"please separate your iex> prompts by multiple newlines to start new examples\"\n    end\n\n    tests =\n      Enum.map(exprs, fn expr -> test_case_content(expr, module, maybe_source, inspect_opts) end)\n\n    {:__block__, [], test_import(module, do_import) ++ tests}\n  end\n\n  defp test_tags(test, tags) do\n    [doctest_line: test.line, doctest_data: %{end_line: test.end_line}] ++ tags\n  end\n\n  defp multiple_exceptions?(exprs) do\n    Enum.count(exprs, fn\n      %{expected: {:error, _, _}} -> true\n      _ -> false\n    end) > 1\n  end\n\n  defp test_case_content(%{expected: :test} = data, module, maybe_source, _inspect_opts) do\n    %{expr: expr, expr_line: expr_line, doctest: doctest} = data\n    string_to_quoted(module, maybe_source, expr_line, expr, doctest) |> insert_assertions()\n  end\n\n  defp test_case_content(\n         %{expected: {:test, expected}} = data,\n         module,\n         maybe_source,\n         _inspect_opts\n       ) do\n    %{expr: expr, expr_line: expr_line, expected_line: expected_line, doctest: doctest} = data\n\n    expr_ast =\n      string_to_quoted(module, maybe_source, expr_line, expr, doctest) |> insert_assertions()\n\n    expected_ast = string_to_quoted(module, maybe_source, expected_line, expected, doctest)\n    last_expr = Macro.to_string(last_expr(expr_ast))\n\n    quote do\n      # `expr_ast` may introduce variables that may be used\n      # within `expected_ast` so it needs to be unquoted here.\n      value = unquote(expr_ast)\n\n      ExUnit.DocTest.__test__(\n        value,\n        unquote(expected_ast),\n        unquote(doctest),\n        unquote(last_expr),\n        unquote(expected),\n        unquote(module),\n        unquote(maybe_source),\n        unquote(expr_line)\n      )\n    end\n  end\n\n  defp test_case_content(\n         %{expected: {:inspect, expected}} = data,\n         module,\n         maybe_source,\n         inspect_opts\n       ) do\n    %{expr: expr, expr_line: expr_line, doctest: doctest} = data\n\n    expr_ast =\n      string_to_quoted(module, maybe_source, expr_line, expr, doctest) |> insert_assertions()\n\n    last_expr = Macro.to_string(last_expr(expr_ast))\n\n    quote do\n      ExUnit.DocTest.__inspect__(\n        unquote(expr_ast),\n        unquote(expected),\n        unquote(doctest),\n        unquote(last_expr),\n        unquote(inspect(expected)),\n        unquote(module),\n        unquote(maybe_source),\n        unquote(expr_line),\n        unquote(inspect_opts)\n      )\n    end\n  end\n\n  defp test_case_content(\n         %{expected: {:error, exception, message}} = data,\n         module,\n         maybe_source,\n         _inspect_opts\n       ) do\n    %{expr: expr, expr_line: expr_line, doctest: doctest} = data\n    expr_ast = string_to_quoted(module, maybe_source, expr_line, expr, doctest)\n\n    quote do\n      ExUnit.DocTest.__error__(\n        fn -> unquote(expr_ast) end,\n        unquote(message),\n        unquote(exception),\n        unquote(doctest),\n        unquote(module),\n        unquote(maybe_source),\n        unquote(expr_line)\n      )\n    end\n  end\n\n  @doc false\n  def __test__(value, expected, doctest, last_expr, expected_expr, module, maybe_source, line) do\n    case value do\n      ^expected ->\n        {:ok, value}\n\n      _ ->\n        error = [\n          message: \"Doctest failed\",\n          doctest: doctest,\n          expr: \"#{last_expr} === #{String.trim(expected_expr)}\",\n          left: value,\n          right: expected\n        ]\n\n        reraise ExUnit.AssertionError, error, stack(module, maybe_source, line)\n    end\n  end\n\n  @doc false\n  def __inspect__(\n        value,\n        expected,\n        doctest,\n        last_expr,\n        expected_expr,\n        module,\n        maybe_source,\n        line,\n        inspect_opts\n      ) do\n    result =\n      try do\n        inspect(value, Keyword.put(inspect_opts, :safe, false))\n      rescue\n        e ->\n          stack = Enum.drop(__STACKTRACE__, 1)\n          {[message: Exception.message(e)], ExUnit.Runner.prune_stacktrace(stack)}\n      else\n        ^expected -> :ok\n        actual -> {[left: actual, right: expected, message: \"Doctest failed\"], []}\n      end\n\n    case result do\n      :ok ->\n        {:ok, value}\n\n      {extra, stack} ->\n        expr = \"inspect(#{last_expr}) === #{String.trim(expected_expr)}\"\n        error = [doctest: doctest, expr: expr] ++ extra\n        reraise ExUnit.AssertionError, error, stack ++ stack(module, maybe_source, line)\n    end\n  end\n\n  @doc false\n  def __error__(fun, message, exception, doctest, module, maybe_source, line) do\n    try do\n      fun.()\n    rescue\n      error ->\n        actual_exception = error.__struct__\n        actual_message = Exception.message(error)\n\n        failed =\n          cond do\n            actual_exception != exception ->\n              \"Doctest failed: expected exception #{inspect(exception)} but got \" <>\n                \"#{inspect(actual_exception)} with message #{inspect(actual_message)}\"\n\n            not error_message_matches?(actual_message, message) ->\n              \"Doctest failed: wrong message for #{inspect(actual_exception)}\\n\" <>\n                \"expected:\\n\" <>\n                \"  #{inspect(message)}\\n\" <>\n                \"actual:\\n\" <> \"  #{inspect(actual_message)}\"\n\n            true ->\n              nil\n          end\n\n        if failed do\n          reraise ExUnit.AssertionError,\n                  [message: failed, doctest: doctest],\n                  stack(module, maybe_source, line)\n        end\n    else\n      _ ->\n        failed = \"Doctest failed: expected exception #{inspect(exception)} but nothing was raised\"\n        error = [message: failed, doctest: doctest]\n        reraise ExUnit.AssertionError, error, stack(module, maybe_source, line)\n    end\n  end\n\n  defp error_message_matches?(actual, expected) when actual == expected, do: true\n\n  defp error_message_matches?(actual, expected) do\n    if String.ends_with?(expected, \"...\") do\n      ellipsis_removed = binary_slice(expected, 0..-4//1)\n      String.starts_with?(actual, ellipsis_removed)\n    else\n      false\n    end\n  end\n\n  defp test_import(_mod, false), do: []\n  defp test_import(mod, _), do: [quote(do: import(unquote(mod)))]\n\n  defp string_to_quoted(module, maybe_source, line, expr, doctest) when is_binary(expr) do\n    try do\n      Code.string_to_quoted!(expr, file: maybe_source || inspect(module), line: line)\n    rescue\n      e ->\n        ex_message = \"(#{inspect(e.__struct__)}) #{Exception.message(e)}\"\n        message = \"Doctest did not compile, got: #{ex_message}\"\n\n        message =\n          if e.__struct__ == TokenMissingError and expr =~ ~r/#[\\w\\.]+</ do\n            message <>\n              \"\"\"\n              \\nIf you are planning to assert on the result of an iex> expression \\\n              which contains a value inspected as #Name<...>, please make sure \\\n              the inspected value is placed at the beginning of the expression, \\\n              otherwise Elixir will treat it as a comment due to the leading sign #.\\\n              \"\"\"\n          else\n            message\n          end\n\n        opts =\n          if String.valid?(doctest) do\n            [message: message, doctest: doctest]\n          else\n            [message: message]\n          end\n\n        quote do\n          reraise ExUnit.AssertionError,\n                  unquote(opts),\n                  unquote(Macro.escape(stack(module, maybe_source, line)))\n        end\n    end\n  end\n\n  defp stack(module, file, line) do\n    file_info = if file, do: [file: String.to_charlist(file)], else: []\n    [{module, :__MODULE__, 0, [line: line] ++ file_info}]\n  end\n\n  ## Extraction of the tests\n\n  defp extract(module) do\n    case Code.fetch_docs(module) do\n      {:docs_v1, annotation, _, _, moduledoc, _, docs} ->\n        extract_from_moduledoc(annotation, moduledoc, module) ++\n          extract_from_docs(Enum.sort(docs), module)\n\n      {:error, reason} ->\n        raise Error,\n          module: module,\n          message:\n            \"could not retrieve the documentation for module #{inspect(module)}. \" <>\n              explain_docs_error(reason)\n    end\n  end\n\n  defp explain_docs_error(:module_not_found),\n    do: \"The BEAM file of the module cannot be accessed\"\n\n  defp explain_docs_error(:chunk_not_found),\n    do: \"The module was not compiled with documentation\"\n\n  defp explain_docs_error({:invalid_chunk, _}),\n    do: \"The documentation chunk in the module is invalid\"\n\n  defp extract_from_moduledoc(annotation, %{\"en\" => doc}, module) do\n    extract_tests(:erl_anno.line(annotation), doc, module, :moduledoc)\n  end\n\n  defp extract_from_moduledoc(_, _doc, _module), do: []\n\n  defp extract_from_docs(docs, module) do\n    for doc <- docs, doc <- extract_from_doc(doc, module), do: doc\n  end\n\n  defp extract_from_doc({{_, name, arity}, annotation, _, %{\"en\" => doc}, _}, module) do\n    line = :erl_anno.line(annotation)\n    extract_tests(line, doc, module, {name, arity})\n  end\n\n  defp extract_from_doc(_doc, _module),\n    do: []\n\n  @iex_prompt [\"iex>\", \"iex(\"]\n  @dot_prompt [\"...>\", \"...(\"]\n  @fences [\"```\", \"~~~\"]\n\n  defp adjust_indent(lines, line_no, module) do\n    adjust_text(lines, line_no, [], module)\n  end\n\n  defp adjust_text([], line_no, adjusted_lines, _module) do\n    {Enum.reverse(adjusted_lines), line_no - 1}\n  end\n\n  defp adjust_text([line | rest], line_no, adjusted_lines, module) do\n    case String.starts_with?(String.trim_leading(line), @iex_prompt) do\n      true ->\n        {indent, _len} = :binary.match(line, \"iex\")\n        adjust_code(:prompt, [line | rest], line_no, adjusted_lines, indent, module)\n\n      false ->\n        adjust_text(rest, line_no + 1, adjusted_lines, module)\n    end\n  end\n\n  defp adjust_code(_kind, [], line_no, adjusted_lines, _indent, _module) do\n    {Enum.reverse(adjusted_lines), line_no - 1}\n  end\n\n  defp adjust_code(kind, [line | rest], line_no, adjusted_lines, indent, module) do\n    stripped_line = strip_indent(line, indent)\n    trimmed_line = String.trim_leading(line)\n    done? = stripped_line == \"\" or String.starts_with?(stripped_line, @fences)\n\n    overrun? =\n      if kind == :code,\n        do: not done? and byte_size(trimmed_line) > byte_size(stripped_line),\n        else: byte_size(trimmed_line) != byte_size(stripped_line)\n\n    if overrun? do\n      n_spaces = if indent == 1, do: \"#{indent} space\", else: \"#{indent} spaces\"\n\n      raise Error,\n        line: line_no,\n        module: module,\n        message: \"\"\"\n        indentation level mismatch on doctest line: #{inspect(line)}\n\n        If you are planning to assert on the result of an `iex>` expression, \\\n        make sure the result is indented at the same level as `iex>`, which \\\n        in this case is exactly #{n_spaces}.\n\n        If instead you have an `iex>` expression that spans over multiple lines, \\\n        please make sure that each line after the first one begins with `...>`.\n        \"\"\"\n    end\n\n    cond do\n      done? ->\n        adjusted_lines = [{\"\", line_no} | adjusted_lines]\n        adjust_text(rest, line_no + 1, adjusted_lines, module)\n\n      kind == :prompt or String.starts_with?(trimmed_line, @iex_prompt) or\n          (kind == :maybe_prompt and String.starts_with?(trimmed_line, @dot_prompt)) ->\n        line = {adjust_prompt(stripped_line, line_no, module), line_no}\n        adjust_code(:maybe_prompt, rest, line_no + 1, [line | adjusted_lines], indent, module)\n\n      true ->\n        adjusted_lines = [{stripped_line, line_no} | adjusted_lines]\n        adjust_code(:code, rest, line_no + 1, adjusted_lines, indent, module)\n    end\n  end\n\n  defp strip_indent(line, indent) do\n    length = byte_size(line) - indent\n\n    if length > 0 do\n      binary_part(line, indent, length)\n    else\n      \"\"\n    end\n  end\n\n  defp adjust_prompt(\"iex(\" <> rest = line, line_no, module),\n    do: \"iex>\" <> skip_iex_number(rest, line_no, module, line)\n\n  defp adjust_prompt(\"...(\" <> rest = line, line_no, module),\n    do: \"...>\" <> skip_iex_number(rest, line_no, module, line)\n\n  defp adjust_prompt(line, _line_no, _module),\n    do: line\n\n  defp skip_iex_number(string, line_no, module, line) do\n    case :binary.split(string, \")>\") do\n      [_pre, post] ->\n        post\n\n      [_] ->\n        message =\n          \"unknown IEx prompt: #{inspect(line)}.\\nAccepted formats are: iex>, iex(1)>, ...>, ...(1)>}\"\n\n        raise Error, line: line_no, module: module, message: message\n    end\n  end\n\n  defp chunk_tests(lines, acc, last_no) do\n    case lines\n         |> Enum.drop_while(&(not test_started?(&1)))\n         |> Enum.split_while(&(not test_finished?(&1))) do\n      {[], []} -> Enum.reverse(acc)\n      {chunk, []} -> Enum.reverse([{chunk, last_no} | acc])\n      {[], [_empty_line | lines]} -> chunk_tests(lines, acc, last_no)\n      {chunk, [{_, line_no} | lines]} -> chunk_tests(lines, [{chunk, line_no} | acc], last_no)\n    end\n  end\n\n  defp test_started?({\"iex>\" <> _, _}), do: true\n  defp test_started?(_), do: false\n\n  defp test_finished?({\"\", _}), do: true\n  defp test_finished?(_), do: false\n\n  defp extract_tests(line_no, doc, module, fun_arity) do\n    {lines, last_line} =\n      doc\n      |> String.split([\"\\r\\n\", \"\\n\"], trim: false)\n      |> adjust_indent(line_no + 1, module)\n\n    lines\n    |> chunk_tests([], last_line)\n    |> Enum.map(&build_test(&1, fun_arity))\n  end\n\n  defp build_test({[{\"iex>\" <> string = line, line_no} | lines], end_line_no}, fun_arity) do\n    exprs = build_test(lines, [string], [], [line], [], line_no)\n    %{line: line_no, end_line: end_line_no - 1, exprs: Enum.reverse(exprs), fun_arity: fun_arity}\n  end\n\n  # Started a new expression.\n  defp build_test(\n         [{\"iex>\" <> _, new_line_no} | _] = list,\n         [_ | _] = expr,\n         [_ | _] = expected,\n         formatted,\n         acc,\n         line_no\n       ) do\n    acc = add_expr(acc, expr, expected, formatted, line_no)\n    build_test(list, [], [], [], acc, new_line_no)\n  end\n\n  # Continuation of an expression.\n  defp build_test(\n         [{\"iex>\" <> string = line, _} | lines],\n         expr,\n         expected,\n         formatted,\n         acc,\n         line_no\n       ) do\n    expr = add_line(expr, string)\n    formatted = add_line(formatted, line)\n    build_test(lines, expr, expected, formatted, acc, line_no)\n  end\n\n  # Continuation of an expression.\n  defp build_test(\n         [{\"...>\" <> string = line, _} | lines],\n         expr,\n         expected,\n         formatted,\n         acc,\n         line_no\n       ) do\n    expr = add_line(expr, string)\n    formatted = add_line(formatted, line)\n    build_test(lines, expr, expected, formatted, acc, line_no)\n  end\n\n  # Expected lines.\n  defp build_test([{line, _} | lines], expr, expected, formatted, acc, line_no) do\n    build_test(lines, expr, add_line(expected, line), formatted, acc, line_no)\n  end\n\n  # We are done.\n  defp build_test([], [_ | _] = expr, expected, formatted, acc, line_no) do\n    add_expr(acc, expr, expected, formatted, line_no)\n  end\n\n  defp add_line([], line), do: [line]\n  defp add_line(acc, line), do: [acc, [?\\n, line]]\n\n  defp add_expr(exprs, expr_lines, expected_lines, formatted_lines, line_no) do\n    expected = IO.iodata_to_binary(expected_lines)\n    doctest = IO.iodata_to_binary([?\\n, formatted_lines, ?\\n, expected])\n\n    expr = %{\n      expr: IO.iodata_to_binary(expr_lines),\n      expr_line: line_no,\n      expected: tag_expected(expected),\n      expected_line: line_no + length(expr_lines),\n      doctest: doctest\n    }\n\n    [expr | exprs]\n  end\n\n  defp tag_expected(expected) do\n    case expected do\n      \"\" ->\n        :test\n\n      \"** (\" <> error ->\n        [mod, message] = :binary.split(error, \")\")\n        {:error, Module.concat([mod]), String.trim_leading(message)}\n\n      _ ->\n        if inspectable?(expected) do\n          {:inspect, expected}\n        else\n          {:test, expected}\n        end\n    end\n  end\n\n  defp inspectable?(<<?#, char, rest::binary>>) when char in ?A..?Z, do: inspectable_end?(rest)\n  defp inspectable?(_), do: false\n\n  defp inspectable_end?(<<?., char, rest::binary>>) when char in ?A..?Z,\n    do: inspectable_end?(rest)\n\n  defp inspectable_end?(<<char, rest::binary>>)\n       when char in ?A..?Z\n       when char in ?a..?z\n       when char in ?0..?9\n       when char == ?_,\n       do: inspectable_end?(rest)\n\n  defp inspectable_end?(<<?<, _::binary>>), do: true\n  defp inspectable_end?(_), do: false\n\n  defp last_expr({:__block__, _, [_ | _] = block}), do: block |> List.last() |> last_expr()\n  defp last_expr(other), do: other\n\n  defp insert_assertions({:__block__, meta, block}),\n    do: {:__block__, meta, Enum.map(block, &insert_match_assertion/1)}\n\n  defp insert_assertions(ast),\n    do: insert_match_assertion(ast)\n\n  defp insert_match_assertion({:=, _, [{var, _, context}, _]} = ast)\n       when is_atom(var) and is_atom(context),\n       do: ast\n\n  defp insert_match_assertion({:=, meta, [left, right]}),\n    do: {{:., meta, [__MODULE__, :__assert__]}, meta, [{:=, meta, [left, right]}]}\n\n  defp insert_match_assertion(ast),\n    do: ast\n\n  @doc false\n  defmacro __assert__({:=, _, [left, right]} = assertion) do\n    {left, right} = move_match(left, right)\n    code = Macro.escape(assertion, prune_metadata: true)\n    ExUnit.Assertions.__match__(left, right, code, :ok, __CALLER__)\n  end\n\n  defp move_match(left, {:=, meta, [middle, right]}),\n    do: move_match({:=, meta, [left, middle]}, right)\n\n  defp move_match(left, right),\n    do: {left, right}\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/event_manager.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.EventManager do\n  @moduledoc false\n  @timeout :infinity\n\n  @typep manager :: {supervisor_manager :: pid, event_manager :: pid}\n\n  @doc \"\"\"\n  Starts an event manager that publishes events during the suite run.\n\n  This is what power formatters as well as the\n  internal statistics server for ExUnit.\n  \"\"\"\n  @spec start_link() :: {:ok, manager}\n  def start_link() do\n    {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n    {:ok, event} = :gen_event.start_link()\n    {:ok, {sup, event}}\n  end\n\n  def stop({sup, event}) do\n    for {_, pid, _, _} <- DynamicSupervisor.which_children(sup) do\n      GenServer.stop(pid, :normal, @timeout)\n    end\n\n    DynamicSupervisor.stop(sup)\n    :gen_event.stop(event)\n  end\n\n  def add_handler({sup, event}, handler, opts) do\n    if Code.ensure_loaded?(handler) and function_exported?(handler, :handle_call, 2) do\n      IO.warn(\n        \"passing GenEvent handlers (#{inspect(handler)} in this case) in \" <>\n          \"the :formatters option of ExUnit is deprecated, please pass a \" <>\n          \"GenServer instead. Check the documentation for the ExUnit.Formatter \" <>\n          \"module for more information\"\n      )\n\n      :gen_event.add_handler(event, handler, opts)\n    else\n      DynamicSupervisor.start_child(sup, %{\n        id: GenServer,\n        start: {GenServer, :start_link, [handler, opts]},\n        restart: :temporary\n      })\n    end\n  end\n\n  def suite_started(manager, opts) do\n    notify(manager, {:suite_started, opts})\n  end\n\n  def suite_finished(manager, times_us) do\n    notify(manager, {:suite_finished, times_us})\n  end\n\n  def module_started(manager, test_module) do\n    # TODO: Remove case_started on v2.0\n    notify(manager, {:case_started, Map.put(test_module, :__struct__, ExUnit.TestCase)})\n    notify(manager, {:module_started, test_module})\n  end\n\n  def module_finished(manager, test_module) do\n    # TODO: Remove case_finished on v2.0\n    notify(manager, {:case_finished, Map.put(test_module, :__struct__, ExUnit.TestCase)})\n    notify(manager, {:module_finished, test_module})\n  end\n\n  def sigquit(manager, current) do\n    notify(manager, {:sigquit, current})\n  end\n\n  def test_started(manager, test) do\n    notify(manager, {:test_started, test})\n  end\n\n  def test_finished(manager, test) do\n    notify(manager, {:test_finished, test})\n  end\n\n  def max_failures_reached(manager) do\n    notify(manager, :max_failures_reached)\n  end\n\n  defp notify({sup, event}, msg) do\n    :gen_event.notify(event, msg)\n\n    for {_, pid, _, _} <- Supervisor.which_children(sup) do\n      GenServer.cast(pid, msg)\n    end\n\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/failures_manifest.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.FailuresManifest do\n  @moduledoc false\n\n  @opaque t :: %{optional(ExUnit.test_id()) => test_file :: Path.t()}\n\n  @manifest_vsn 1\n\n  @spec new() :: t\n  def new, do: %{}\n\n  @spec put_test(t, ExUnit.Test.t()) :: t\n  def put_test(%{} = manifest, %ExUnit.Test{state: {ignored_state, _}})\n      when ignored_state in [:skipped, :excluded],\n      do: manifest\n\n  def put_test(%{} = manifest, %ExUnit.Test{state: nil} = test) do\n    Map.delete(manifest, {test.module, test.name})\n  end\n\n  def put_test(%{} = manifest, %ExUnit.Test{state: {failed_state, _}} = test)\n      when failed_state in [:failed, :invalid] do\n    Map.put(manifest, {test.module, test.name}, test.tags.file)\n  end\n\n  @spec write!(t, Path.t()) :: :ok\n  def write!(manifest, file) when is_binary(file) do\n    manifest = prune_deleted_tests(manifest)\n    binary = :erlang.term_to_binary({@manifest_vsn, manifest})\n    Path.dirname(file) |> File.mkdir_p!()\n    File.write!(file, binary)\n  end\n\n  @spec fail_all!(Path.t()) :: :ok\n  def fail_all!(file) when is_binary(file) do\n    binary = :erlang.term_to_binary({@manifest_vsn, :all})\n    Path.dirname(file) |> File.mkdir_p!()\n    File.write!(file, binary)\n  end\n\n  @spec read(Path.t()) :: t\n  def read(file) when is_binary(file) do\n    with {:ok, binary} <- File.read(file),\n         {:ok, {@manifest_vsn, %{} = manifest}} <- safe_binary_to_term(binary) do\n      manifest\n    else\n      _ -> new()\n    end\n  end\n\n  @spec info(Path.t()) :: {MapSet.t(Path.t()), MapSet.t(ExUnit.test_id())} | :all\n  def info(file) when is_binary(file) do\n    with {:ok, binary} <- File.read(file),\n         {:ok, {@manifest_vsn, manifest}} <- safe_binary_to_term(binary) do\n      case manifest do\n        :all ->\n          :all\n\n        %{} ->\n          {manifest |> Map.values() |> MapSet.new(), manifest |> Map.keys() |> MapSet.new()}\n      end\n    else\n      _ -> {MapSet.new(), MapSet.new()}\n    end\n  end\n\n  defp safe_binary_to_term(binary) do\n    {:ok, :erlang.binary_to_term(binary)}\n  rescue\n    ArgumentError -> :error\n  end\n\n  defp prune_deleted_tests(manifest) do\n    Map.drop(manifest, find_deleted_tests(Enum.to_list(manifest), %{}, []))\n  end\n\n  defp find_deleted_tests([], _file_existence, deleted_tests), do: deleted_tests\n\n  defp find_deleted_tests([{{mod, name} = id, file} | rest] = all, file_existence, acc) do\n    file_exists = Map.fetch(file_existence, file)\n\n    cond do\n      file_exists == :error ->\n        # This is the first time we've looked up the existence of the file.\n        # Cache the result and try again.\n        file_existence = Map.put(file_existence, file, File.regular?(file))\n        find_deleted_tests(all, file_existence, acc)\n\n      file_exists == {:ok, false} ->\n        # The file does not exist, so the test has been deleted.\n        find_deleted_tests(rest, file_existence, [id | acc])\n\n      Code.loaded?(mod) and not function_exported?(mod, name, 1) ->\n        # The test module has been loaded, but the test no longer exists.\n        find_deleted_tests(rest, file_existence, [id | acc])\n\n      true ->\n        # The file exists and the test module was not loaded (which means the test\n        # *might* still exist) or the function is exported (which means the test\n        # *definitely* still exists). Either way, we do not want to prune it.\n        find_deleted_tests(rest, file_existence, acc)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/filters.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.Filters do\n  @moduledoc \"\"\"\n  Conveniences for parsing and evaluating filters.\n  \"\"\"\n  alias ExUnit.FailuresManifest\n\n  @type t :: list({atom, Regex.t() | String.Chars.t()} | atom)\n  @type location :: {:location, {String.t(), pos_integer | [pos_integer, ...]}}\n  @type ex_unit_opts :: [exclude: [:test], include: [location, ...]] | []\n\n  # TODO: Remove me on Elixir v2.0\n  @doc false\n  @deprecated \"Use parse_paths/1 instead\"\n  def parse_path(file_path) do\n    {[parsed_path], ex_unit_opts} = parse_paths([file_path])\n    {parsed_path, ex_unit_opts}\n  end\n\n  @doc \"\"\"\n  Parses filters out of a path.\n\n  Determines whether a given file path (supplied to ExUnit/Mix as arguments\n  on the command line) includes a line number filter, and if so returns the\n  appropriate ExUnit configuration options.\n  \"\"\"\n  @spec parse_paths([String.t()]) :: {[String.t()], ex_unit_opts}\n  def parse_paths(file_paths) do\n    {parsed_paths, {lines?, locations}} =\n      Enum.map_reduce(file_paths, {false, []}, fn file_path, {lines?, locations} ->\n        {path, location} = extract_location(file_path)\n        {path, {lines? or is_tuple(location), [{:location, location} | locations]}}\n      end)\n\n    ex_unit_opts =\n      if lines?, do: [exclude: [:test], include: Enum.reverse(locations)], else: []\n\n    {parsed_paths, ex_unit_opts}\n  end\n\n  defp extract_location(file_path) do\n    case Path.relative_to_cwd(file_path) |> String.split(\":\") do\n      [path] ->\n        {path, path}\n\n      [path | parts] ->\n        {path_parts, line_numbers} = Enum.split_while(parts, &(to_line_number(&1) == nil))\n        path = Enum.join([path | path_parts], \":\") |> Path.split() |> Path.join()\n        lines = for n <- line_numbers, valid_number = validate_line_number(n), do: valid_number\n\n        case lines do\n          [] -> {path, path}\n          [line] -> {path, {path, line}}\n          lines -> {path, {path, lines}}\n        end\n    end\n  end\n\n  defp to_line_number(str) do\n    case Integer.parse(str) do\n      {x, \"\"} when x > 0 -> x\n      _ -> nil\n    end\n  end\n\n  defp validate_line_number(str) do\n    number = to_line_number(str)\n    number == nil && IO.warn(\"invalid line number given as ExUnit filter: #{str}\", [])\n    number\n  end\n\n  @doc \"\"\"\n  Normalizes `include` and `exclude` filters to remove duplicates\n  and keep precedence.\n\n  ## Examples\n\n      iex> ExUnit.Filters.normalize(nil, nil)\n      {[], []}\n\n      iex> ExUnit.Filters.normalize([:foo, :bar, :bar], [:foo, :baz])\n      {[:foo, :bar], [:baz]}\n\n      iex> ExUnit.Filters.normalize([foo: \"true\"], [:foo])\n      {[foo: \"true\"], [:foo]}\n\n      iex> ExUnit.Filters.normalize([:foo], [foo: \"true\"])\n      {[:foo], []}\n\n      iex> ExUnit.Filters.normalize([foo: \"true\"], [foo: true])\n      {[foo: \"true\"], []}\n\n      iex> ExUnit.Filters.normalize([foo: true], [foo: \"true\"])\n      {[foo: true], []}\n\n      iex> ExUnit.Filters.normalize([foo: 1, foo: 1, foo: 2], [])\n      {[foo: 1, foo: 2], []}\n\n      iex> ExUnit.Filters.normalize([], [foo: 1, foo: 1, foo: 2])\n      {[], [foo: 1, foo: 2]}\n\n  \"\"\"\n  @spec normalize(t | nil, t | nil) :: {t, t}\n  def normalize(include, exclude) do\n    {include_atoms, include_tags} =\n      include |> List.wrap() |> Enum.uniq() |> Enum.split_with(&is_atom/1)\n\n    {exclude_atoms, exclude_tags} =\n      exclude |> List.wrap() |> Enum.uniq() |> Enum.split_with(&is_atom/1)\n\n    exclude_tags_map = Map.new(exclude_tags)\n\n    exclude_included =\n      for include_tag <- include_tags, key = has_tag(include_tag, exclude_tags_map), do: key\n\n    exclude_tags = exclude_tags |> Keyword.drop(include_atoms) |> Keyword.drop(exclude_included)\n\n    {include_atoms ++ include_tags, (exclude_atoms -- include_atoms) ++ exclude_tags}\n  end\n\n  @doc \"\"\"\n  Parses the given filters, as one would receive from the command line.\n\n  ## Examples\n\n      iex> ExUnit.Filters.parse([\"foo:bar\", \"baz\", \"line:9\", \"bool:true\"])\n      [{:foo, \"bar\"}, :baz, {:line, 9}, {:bool, \"true\"}]\n\n  \"\"\"\n  @spec parse([String.t()]) :: t\n  def parse(filters) do\n    Enum.map(filters, fn filter ->\n      case :binary.split(filter, \":\") do\n        [key, value] -> parse_kv(String.to_atom(key), value)\n        [key] -> String.to_atom(key)\n      end\n    end)\n  end\n\n  defp parse_kv(:line, line) when is_binary(line),\n    do: {:line, String.to_integer(line)}\n\n  defp parse_kv(:location, loc) when is_binary(loc),\n    do: {:location, extract_location(loc) |> elem(1)}\n\n  defp parse_kv(key, value), do: {key, value}\n\n  @doc \"\"\"\n  Returns failure information from the manifest file.\n\n  It returns either `:all`, meaning all tests should be considered as stale,\n  or a tuple containing:\n\n    * A set of files that contain tests that failed the last time they ran.\n      The paths are absolute paths.\n\n    * A set of test IDs that failed the last time they ran\n\n  \"\"\"\n  @spec failure_info(Path.t()) :: {MapSet.t(Path.t()), MapSet.t(ExUnit.test_id())} | :all\n  def failure_info(manifest_file) do\n    FailuresManifest.info(manifest_file)\n  end\n\n  @doc \"\"\"\n  Marks the whole suite as failed in the manifest.\n\n  This is useful when the test suite cannot be loaded\n  and there is a desire to make all tests fail.\n  \"\"\"\n  @spec fail_all!(Path.t()) :: :ok\n  def fail_all!(manifest_file) do\n    FailuresManifest.fail_all!(manifest_file)\n  end\n\n  @doc \"\"\"\n  Evaluates the `include` and `exclude` filters against the given `tags` to\n  determine if tests should be skipped or excluded.\n\n  Some filters, like `:line`, may require the whole test `collection` to\n  find the closest line, that's why it must also be passed as an argument.\n\n  Filters can either be a regular expression or any data structure\n  that implements the `String.Chars` protocol, which is invoked before comparing\n  the filter with the `:tag` value.\n\n  ## Precedence\n\n  Tests are first excluded, then included, and then skipped (if any left).\n\n  If a `:skip` tag is found in `tags`, `{:skipped, message}` is returned if the test\n  remains after the `exclude` and `include` filters. However, if skipped tests are\n  specifically included, then they will always run.\n\n  ## Examples\n\n      iex> ExUnit.Filters.eval([foo: \"bar\"], [:foo], %{foo: \"bar\"}, [])\n      :ok\n\n      iex> ExUnit.Filters.eval([foo: \"bar\"], [:foo], %{foo: \"baz\"}, [])\n      {:excluded, \"due to foo filter\"}\n\n  \"\"\"\n  @spec eval(t, t, map, [ExUnit.Test.t()]) ::\n          :ok | {:excluded, String.t()} | {:skipped, String.t()}\n  def eval(include, exclude, tags, collection) when is_map(tags) do\n    cond do\n      Enum.any?(include, &has_tag(&1, tags, collection)) ->\n        maybe_skipped(include, tags, collection)\n\n      excluded = Enum.find_value(exclude, &has_tag(&1, tags, collection)) ->\n        {:excluded, \"due to #{excluded} filter\"}\n\n      true ->\n        maybe_skipped(include, tags, collection)\n    end\n  end\n\n  defp maybe_skipped(include, tags, collection) do\n    case tags do\n      %{skip: skip} when is_binary(skip) or skip == true ->\n        skip_tags = %{skip: skip}\n        skip_included_explicitly? = Enum.any?(include, &has_tag(&1, skip_tags, collection))\n\n        cond do\n          skip_included_explicitly? -> :ok\n          is_binary(skip) -> {:skipped, skip}\n          skip -> {:skipped, \"due to skip tag\"}\n        end\n\n      _ ->\n        :ok\n    end\n  end\n\n  defp has_tag({:location, path}, %{file: file}, _collection) when is_binary(path) do\n    String.ends_with?(file, path)\n  end\n\n  defp has_tag({:location, {path, lines}}, %{line: _, describe_line: _} = tags, collection)\n       when is_binary(path) do\n    String.ends_with?(tags.file, path) and\n      lines |> List.wrap() |> Enum.any?(&has_tag({:line, &1}, tags, collection))\n  end\n\n  defp has_tag({:line, line}, %{line: _, describe_line: _} = tags, collection)\n       when is_integer(line) do\n    cond do\n      tags.describe_line == line ->\n        true\n\n      describe_block?(line, collection) ->\n        false\n\n      true ->\n        tags.line <= line and closest_test_before_line(line, collection).tags.line == tags.line\n    end\n  end\n\n  defp has_tag(pair, tags, _collection) do\n    has_tag(pair, tags)\n  end\n\n  defp has_tag({key, %Regex{} = value}, tags) when is_atom(key) do\n    case Map.fetch(tags, key) do\n      {:ok, tag} -> to_string(tag) =~ value and key\n      _ -> false\n    end\n  end\n\n  defp has_tag({key, value}, tags) when is_atom(key) do\n    case Map.fetch(tags, key) do\n      {:ok, ^value} -> key\n      {:ok, tag} -> compare(to_string(tag), to_string(value)) and key\n      _ -> false\n    end\n  end\n\n  defp has_tag(key, tags) when is_atom(key), do: Map.has_key?(tags, key) and key\n\n  defp compare(\"Elixir.\" <> tag1, tag2), do: compare(tag1, tag2)\n  defp compare(tag1, \"Elixir.\" <> tag2), do: compare(tag1, tag2)\n  defp compare(tag, tag), do: true\n  defp compare(_, _), do: false\n\n  defp describe_block?(line, collection) do\n    Enum.any?(collection, fn %ExUnit.Test{tags: %{describe_line: describe_line}} ->\n      line == describe_line\n    end)\n  end\n\n  defp closest_test_before_line(line, collection) do\n    Enum.min_by(collection, fn %ExUnit.Test{tags: %{line: test_line}} ->\n      if line - test_line >= 0 do\n        line - test_line\n      else\n        :infinity\n      end\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/formatter.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.Formatter do\n  @moduledoc \"\"\"\n  Helper functions for formatting and the formatting protocols.\n\n  Formatters are `GenServer`s specified during ExUnit configuration\n  that receive a series of events as casts.\n\n  The following events are possible:\n\n    * `{:suite_started, opts}` -\n      the suite has started with the specified options to the runner.\n\n    * `{:suite_finished, times_us}` -\n      the suite has finished. Returns several measurements in microseconds\n      for running the suite. See `t:times_us/0` for more information.\n\n    * `{:module_started, test_module}` -\n      a test module has started. See `ExUnit.TestModule` for details.\n\n    * `{:module_finished, test_module}` -\n      a test module has finished. See `ExUnit.TestModule` for details.\n\n    * `{:test_started, test}` -\n      a test has started. See `ExUnit.Test` for details.\n\n    * `{:test_finished, test}` -\n      a test has finished. See `ExUnit.Test` for details.\n\n    * `{:sigquit, [test | test_module]}` -\n      the VM is going to shutdown. It receives the test cases (or test\n      module in case of `setup_all`) still running.\n\n    * `:max_failures_reached` -\n      the test run has been aborted due to reaching max failures limit set\n      with `:max_failures` option.\n\n  The formatter will also receive the following events but they are deprecated\n  and should be ignored:\n\n    * `{:case_started, test_module}` -\n      a test module has started. See `ExUnit.TestModule` for details.\n\n    * `{:case_finished, test_module}` -\n      a test module has finished. See `ExUnit.TestModule` for details.\n\n  The full ExUnit configuration is passed as the argument to `c:GenServer.init/1`\n  callback when the formatters are started. If you need to do runtime configuration\n  of a formatter, you can add any configuration needed by using `ExUnit.configure/1`\n  or `ExUnit.start/1`, and this will then be included in the options passed to\n  the `c:GenServer.init/1` callback.\n  \"\"\"\n\n  @type id :: term\n  @type test :: ExUnit.Test.t()\n\n  @typedoc \"\"\"\n  The times spent on several parts of the test suite.\n\n  The following properties can be computed:\n\n      sync = run - (async || 0)\n      total = run + (load || 0)\n\n  `async` is nil when there are no async tests.\n  `load` is nil when the test suite is running and loading\n  tests concurrently.\n  \"\"\"\n  @type times_us :: %{\n          run: pos_integer,\n          async: pos_integer | nil,\n          load: pos_integer | nil\n        }\n\n  @typedoc \"\"\"\n  Key passed to a formatter callback to format a diff.\n\n  See `t:formatter_callback/0`.\n  \"\"\"\n  @typedoc since: \"1.16.0\"\n  @type formatter_callback_diff_key ::\n          :diff_delete\n          | :diff_delete_whitespace\n          | :diff_insert\n          | :diff_insert_whitespace\n\n  @typedoc \"\"\"\n  Key passed to a formatter callback to format information.\n\n  See `t:formatter_callback/0`.\n  \"\"\"\n  @typedoc since: \"1.16.0\"\n  @type formatter_callback_info_key ::\n          :extra_info\n          | :error_info\n          | :test_module_info\n          | :test_info\n          | :parameters_info\n          | :location_info\n          | :stacktrace_info\n          | :blame_diff\n\n  @typedoc \"\"\"\n  A function that this module calls to format various things.\n\n  You can pass this functions to various functions in this module, and use it\n  to customize the formatting of the output. For example, ExUnit's CLI formatter\n  uses this callback to colorize output.\n\n  ## Keys\n\n  The possible keys are:\n\n    * `:diff_enabled?` - whether diffing is enabled. It receives a boolean\n      indicating whether diffing is enabled by default and returns a boolean\n      indicating whether diffing should be enabled for the current test.\n\n    * `:diff_delete` and `:diff_delete_whitespace` - Should format a diff deletion,\n      with or without whitespace respectively.\n\n    * `:diff_insert` and `:diff_insert_whitespace` - Should format a diff insertion,\n      with or without whitespace respectively.\n\n    * `:extra_info` - Should format optional extra labels, such as the `\"code: \"` label\n      that precedes code to show.\n\n    * `:error_info` - Should format error information.\n\n    * `:test_module_info` - Should format test module information. The message returned\n    when this key is passed precedes messages such as `\"failure on setup_all callback [...]\"`.\n\n    * `:test_info` - Should format test information.\n\n    * `:parameters_info` - Should format test parameters.\n\n    * `:location_info` - Should format test location information.\n\n    * `:stacktrace_info` - Should format stacktrace information.\n\n    * `:blame_diff` - Should format a string of code.\n\n  ## Examples\n\n  For example, to format errors as *red strings* and everything else as is, you could define\n  a formatter callback function like this:\n\n      formatter_callback = fn\n        :error_info, msg -> [:red, msg, :reset] |> IO.ANSI.format() |> IO.iodata_to_binary()\n        _key, value -> value\n      end\n\n  \"\"\"\n  @typedoc since: \"1.16.0\"\n  @type formatter_callback ::\n          (:diff_enabled?, boolean -> boolean)\n          | (formatter_callback_diff_key, Inspect.Algebra.t() -> Inspect.Algebra.t())\n          | (formatter_callback_info_key, String.t() -> String.t())\n\n  @typedoc \"\"\"\n  Width for formatting.\n\n  For example, see `format_assertion_diff/4`.\n  \"\"\"\n  @typedoc since: \"1.16.0\"\n  @type width :: non_neg_integer | :infinity\n\n  import Exception, only: [format_stacktrace_entry: 1, format_file_line: 3]\n\n  alias ExUnit.Diff\n  alias Inspect.Algebra\n\n  @counter_padding \"     \"\n  @mailbox_label_padding @counter_padding <> \"  \"\n  @formatter_exceptions [ExUnit.AssertionError, FunctionClauseError]\n  @no_value ExUnit.AssertionError.no_value()\n\n  @doc \"\"\"\n  Formats time taken running the test suite.\n\n  ## Examples\n\n      iex> format_times(%{run: 10_000, async: nil, load: nil})\n      \"Finished in 0.01 seconds (0.00s async, 0.01s sync)\"\n\n      iex> format_times(%{run: 10_000, async: nil, load: 20_000})\n      \"Finished in 0.03 seconds (0.02s on load, 0.00s async, 0.01s sync)\"\n\n      iex> format_times(%{run: 10_000, async: nil, load: 200_000})\n      \"Finished in 0.2 seconds (0.2s on load, 0.00s async, 0.01s sync)\"\n\n      iex> format_times(%{run: 100_000, async: 50_000, load: 200_000})\n      \"Finished in 0.3 seconds (0.2s on load, 0.05s async, 0.05s sync)\"\n\n  \"\"\"\n  @spec format_times(times_us) :: String.t()\n  def format_times(times) do\n    run_us = normalize_us(times.run)\n    load_us = normalize_us(times.load)\n    async_us = normalize_us(times.async)\n    sync_us = run_us - async_us\n    total_us = run_us + load_us\n\n    maybe_load =\n      if times.load do\n        \"#{format_us(load_us)}s on load, \"\n      else\n        \"\"\n      end\n\n    \"Finished in #{format_us(total_us)} seconds \" <>\n      \"(#{maybe_load}#{format_us(async_us)}s async, #{format_us(sync_us)}s sync)\"\n  end\n\n  defp normalize_us(nil), do: 0\n  defp normalize_us(us), do: div(us, 10_000)\n\n  defp format_us(us) do\n    if us < 10 do\n      \"0.0#{us}\"\n    else\n      us = div(us, 10)\n      \"#{div(us, 10)}.#{rem(us, 10)}\"\n    end\n  end\n\n  @doc false\n  @deprecated \"Use format_times/1 instead\"\n  def format_time(run, load) do\n    format_times(%{run: run, load: load, async: nil})\n  end\n\n  @doc \"\"\"\n  Formats filters used to constrain cases to be run.\n\n  ## Examples\n\n      iex> format_filters([run: true, slow: false], :include)\n      \"Including tags: [run: true, slow: false]\"\n\n      iex> format_filters([list: [61, 62, 63]], :exclude)\n      \"Excluding tags: [list: [61, 62, 63]]\"\n\n  \"\"\"\n  @spec format_filters(keyword, atom) :: String.t()\n  def format_filters(filters, type) do\n    case type do\n      :exclude -> \"Excluding tags: #{inspect(filters, charlists: :as_lists)}\"\n      :include -> \"Including tags: #{inspect(filters, charlists: :as_lists)}\"\n    end\n  end\n\n  @doc ~S\"\"\"\n  Receives a test and formats its failures.\n\n  ## Examples\n\n      iex> failure = {:error, catch_error(raise \"oops\"), _stacktrace = []}\n      iex> formatter_cb = fn _key, value -> value end\n      iex> test = %ExUnit.Test{name: :\"it works\", module: MyTest, tags: %{file: \"file.ex\", line: 7}}\n      iex> format_test_failure(test, [failure], 1, 80, formatter_cb)\n      \"  1) it works (MyTest)\\n     file.ex:7\\n     ** (RuntimeError) oops\\n\"\n\n  \"\"\"\n  @spec format_test_failure(\n          test,\n          [failure],\n          non_neg_integer,\n          width,\n          formatter_callback\n        ) :: String.t()\n        when failure: {atom, term, Exception.stacktrace()}\n  def format_test_failure(test, failures, counter, width, formatter) do\n    %ExUnit.Test{name: name, module: module, tags: tags, parameters: parameters} = test\n\n    test_info(with_counter(counter, \"#{name} (#{inspect(module)})\"), formatter) <>\n      test_parameters(parameters, formatter) <>\n      test_location(with_location(tags), formatter) <>\n      Enum.map_join(Enum.with_index(failures), \"\", fn {{kind, reason, stack}, index} ->\n        {text, stack} = format_kind_reason(test, kind, reason, stack, width, formatter)\n\n        failure_header(failures, index) <>\n          text <> format_stacktrace(stack, module, name, formatter)\n      end)\n  end\n\n  @doc false\n  @deprecated \"Use ExUnit.Formatter.format_test_all_failure/5 instead\"\n  def format_test_case_failure(test_case, failures, counter, width, formatter) do\n    format_test_all_failure(test_case, failures, counter, width, formatter)\n  end\n\n  @doc ~S\"\"\"\n  Receives a test module and formats its failure.\n\n  ## Examples\n\n      iex> failure = {:error, catch_error(raise \"oops\"), _stacktrace = []}\n      iex> formatter_cb = fn _key, value -> value end\n      iex> test_module = %ExUnit.TestModule{name: Hello}\n      iex> format_test_all_failure(test_module, [failure], 1, 80, formatter_cb)\n      \"  1) Hello: failure on setup_all callback, all tests have been invalidated\\n     ** (RuntimeError) oops\\n\"\n\n  \"\"\"\n  @spec format_test_all_failure(\n          ExUnit.TestModule.t(),\n          [failure],\n          non_neg_integer,\n          width,\n          formatter_callback\n        ) :: String.t()\n        when failure: {atom, term, Exception.stacktrace()}\n  def format_test_all_failure(test_module, failures, counter, width, formatter) do\n    %{name: name, parameters: parameters} = test_module\n\n    test_module_info(with_counter(counter, \"#{inspect(name)}: \"), formatter) <>\n      test_parameters(parameters, formatter) <>\n      Enum.map_join(Enum.with_index(failures), \"\", fn {{kind, reason, stack}, index} ->\n        {text, stack} = format_kind_reason(test_module, kind, reason, stack, width, formatter)\n        failure_header(failures, index) <> text <> format_stacktrace(stack, name, nil, formatter)\n      end)\n  end\n\n  ## kind/reason formatting\n\n  defp format_kind_reason(test, :error, %mod{} = struct, stack, width, formatter)\n       when mod in @formatter_exceptions do\n    format_exception(test, struct, stack, width, formatter, @counter_padding)\n  end\n\n  defp format_kind_reason(test, kind, reason, stack, width, formatter) do\n    case linked_or_trapped_exit(kind, reason) do\n      {header, wrapped_reason, wrapped_stack} ->\n        struct = Exception.normalize(:error, wrapped_reason, wrapped_stack)\n\n        {formatted_reason, wrapped_stack} =\n          format_exception(test, struct, wrapped_stack, width, formatter, @counter_padding)\n\n        formatted_stack = format_stacktrace(wrapped_stack, test, formatter)\n\n        {error_info(header, formatter) <> pad(formatted_reason <> formatted_stack), stack}\n\n      :error ->\n        {reason, stack} = Exception.blame(kind, reason, stack)\n        message = error_info(Exception.format_banner(kind, reason), formatter)\n        {message <> format_code(test, stack, formatter), stack}\n    end\n  end\n\n  defp linked_or_trapped_exit({:EXIT, pid}, {reason, [_ | _] = stack})\n       when reason.__struct__ in @formatter_exceptions\n       when reason == :function_clause do\n    {\"** (EXIT from #{inspect(pid)}) an exception was raised:\\n\", reason, stack}\n  end\n\n  defp linked_or_trapped_exit(:exit, {{reason, [_ | _] = stack}, {mod, fun, args}})\n       when is_atom(mod) and is_atom(fun) and is_list(args) and\n              reason.__struct__ in @formatter_exceptions\n       when is_atom(mod) and is_atom(fun) and is_list(args) and reason == :function_clause do\n    {\n      \"** (exit) exited in: #{Exception.format_mfa(mod, fun, args)}\\n   ** (EXIT) an exception was raised:\",\n      reason,\n      stack\n    }\n  end\n\n  defp linked_or_trapped_exit(_kind, _reason), do: :error\n\n  defp format_exception(test, %ExUnit.AssertionError{} = struct, stack, width, formatter, pad) do\n    label_padding_size = if has_value?(struct.right), do: 7, else: 6\n    padding_size = label_padding_size + byte_size(@counter_padding)\n\n    code_multiline =\n      if struct.doctest != @no_value,\n        do: &pad_multiline(&1, padding_size),\n        else: &code_multiline(&1, padding_size)\n\n    formatted =\n      [\n        message: if_value(struct.message, &format_message(&1, formatter)),\n        doctest: if_value(struct.doctest, &pad_multiline(&1, 2 + byte_size(@counter_padding))),\n        code: if_value(struct.expr, code_multiline, fn -> get_code(test, stack) || @no_value end),\n        arguments: if_value(struct.args, &format_args(&1, width))\n      ]\n      |> Kernel.++(format_assertion_diff(struct, padding_size, width, formatter))\n      |> format_meta(formatter, pad, label_padding_size)\n      |> IO.iodata_to_binary()\n\n    {formatted, stack}\n  end\n\n  defp format_exception(test, %FunctionClauseError{} = struct, stack, _width, formatter, _pad) do\n    {blamed, stack} = Exception.blame(:error, struct, stack)\n    banner = Exception.format_banner(:error, struct)\n    blamed = FunctionClauseError.blame(blamed, &inspect/1, &blame_match(&1, formatter))\n    message = error_info(banner, formatter) <> \"\\n\" <> pad(String.trim_leading(blamed, \"\\n\"))\n    {message <> format_code(test, stack, formatter), stack}\n  end\n\n  ## Assertion error and diffing\n\n  @doc false\n  def format_assertion_error(%ExUnit.AssertionError{} = struct) do\n    format_exception(%{}, struct, [], :infinity, fn _, msg -> msg end, \"\") |> elem(0)\n  end\n\n  @doc \"\"\"\n  Formats `ExUnit.AssertionError` diff.\n\n  It returns a keyword list with diffing information\n  from the left and right side of the assertion, if\n  any exists.\n\n  It expects the assertion error, the `padding_size`\n  for formatted content, the width (may be `:infinity`),\n  and the formatter callback function.\n\n  ## Examples\n\n      iex> error = assert_raise ExUnit.AssertionError, fn -> assert [1, 2] == [1, 3] end\n      iex> formatter_cb = fn\n      ...>   :diff_enabled?, _ -> true\n      ...>   _key, value -> value\n      ...> end\n      iex> keyword = format_assertion_diff(error, 5, 80, formatter_cb)\n      iex> for {key, val} <- keyword, do: {key, IO.iodata_to_binary(val)}\n      [left: \"[1, 2]\", right: \"[1, 3]\"]\n\n  \"\"\"\n  @spec format_assertion_diff(\n          ExUnit.AssertionError.t(),\n          non_neg_integer,\n          width,\n          formatter_callback\n        ) :: keyword\n  def format_assertion_diff(assert_error, padding_size, width, formatter)\n\n  def format_assertion_diff(%ExUnit.AssertionError{context: {:mailbox, _pins, []}}, _, _, _) do\n    []\n  end\n\n  def format_assertion_diff(\n        %ExUnit.AssertionError{left: left, context: {:mailbox, pins, mailbox}},\n        padding_size,\n        width,\n        formatter\n      ) do\n    formatted_mailbox =\n      for message <- mailbox do\n        {pattern, value, _warnings} =\n          format_sides(left, message, {:match, pins}, formatter, padding_size + 5, width)\n\n        [\n          \"\\n\",\n          @mailbox_label_padding,\n          format_label(:pattern, formatter, 9),\n          pattern,\n          \"\\n\",\n          @mailbox_label_padding,\n          format_label(:value, formatter, 9),\n          value\n        ]\n      end\n\n    [mailbox: Enum.join(formatted_mailbox, \"\\n\")]\n  end\n\n  def format_assertion_diff(\n        %ExUnit.AssertionError{left: left, right: right, context: context},\n        padding_size,\n        width,\n        formatter\n      ) do\n    {left, right, extras} = format_sides(left, right, context, formatter, padding_size, width)\n    for {k, v} <- [left: left, right: right] ++ extras, has_value?(v), do: {k, v}\n  end\n\n  defp format_sides(left, right, context, formatter, padding_size, width) do\n    inspect = &inspect_multiline(&1, padding_size, width)\n    content_width = if width == :infinity, do: width, else: width - padding_size\n\n    case format_diff(left, right, context, formatter) do\n      {nil, hints} when is_atom(context) ->\n        {if_value(left, inspect), if_value(right, inspect), hints}\n\n      {nil, hints} ->\n        left =\n          Macro.prewalk(left, fn\n            {_, [original: original], _} -> original\n            other -> other\n          end)\n\n        {if_value(left, &code_multiline(&1, padding_size)), if_value(right, inspect), hints}\n\n      {result, hints} ->\n        left =\n          result.left\n          |> Diff.to_algebra(&colorize_diff_delete(&1, formatter))\n          |> Algebra.nest(padding_size)\n          |> Algebra.format(content_width)\n\n        right =\n          result.right\n          |> Diff.to_algebra(&colorize_diff_insert(&1, formatter))\n          |> Algebra.nest(padding_size)\n          |> Algebra.format(content_width)\n\n        {left, right, hints}\n    end\n  end\n\n  defp format_diff(left, right, context, formatter) do\n    if has_value?(left) and has_value?(right) do\n      case find_diff(left, right, context) do\n        {result, env} ->\n          result = if formatter.(:diff_enabled?, false), do: result\n          hints = Enum.map(env.hints, &{:hint, format_hint(&1)})\n          {result, hints}\n\n        nil ->\n          {nil, []}\n      end\n    else\n      {nil, []}\n    end\n  end\n\n  defp format_hint(:equivalent_but_different_strings) do\n    \"you are comparing strings that have the same visual representation but are made of different Unicode codepoints\"\n  end\n\n  defp colorize_diff_delete(doc, formatter) do\n    format = colorize_format(doc, :diff_delete, :diff_delete_whitespace)\n    formatter.(format, doc)\n  end\n\n  defp colorize_diff_insert(doc, formatter) do\n    format = colorize_format(doc, :diff_insert, :diff_insert_whitespace)\n    formatter.(format, doc)\n  end\n\n  defp colorize_format(content, normal, whitespace) when is_binary(content) do\n    if String.trim_leading(content) == \"\", do: whitespace, else: normal\n  end\n\n  defp colorize_format(_doc, normal, _whitespace) do\n    normal\n  end\n\n  defp find_diff(left, right, context) do\n    task = Task.async(Diff, :compute, [left, right, context])\n\n    case Task.yield(task, 1500) || Task.shutdown(task, :brutal_kill) do\n      {:ok, diff} -> diff\n      nil -> nil\n    end\n  end\n\n  ## Helpers\n\n  defp format_code(test, stack, formatter) do\n    if snippet = get_code(test, stack) do\n      \"     \" <> formatter.(:extra_info, \"code: \") <> snippet <> \"\\n\"\n    else\n      \"\"\n    end\n  end\n\n  defp get_code(%{module: module, name: name}, stack) do\n    info =\n      Enum.find_value(stack, fn\n        {^module, ^name, _, info} -> info\n        _ -> nil\n      end)\n\n    file = info[:file]\n    line = info[:line]\n\n    if line > 0 && file && File.exists?(file) do\n      file |> File.stream!() |> Enum.at(line - 1) |> String.trim()\n    end\n  rescue\n    _ -> nil\n  end\n\n  defp get_code(%{}, _) do\n    nil\n  end\n\n  defp blame_match(%{match?: true, node: node}, _formatter),\n    do: Macro.to_string(node)\n\n  defp blame_match(%{match?: false, node: node}, formatter),\n    do: formatter.(:blame_diff, Macro.to_string(node))\n\n  defp format_meta(fields, formatter, padding, padding_size) do\n    for {label, value} <- fields, has_value?(value) do\n      [padding, format_label(label, formatter, padding_size), value, \"\\n\"]\n    end\n  end\n\n  defp if_value(value, fun) do\n    if has_value?(value) do\n      fun.(value)\n    else\n      value\n    end\n  end\n\n  defp if_value(value, do_fun, else_fun) do\n    if has_value?(value) do\n      do_fun.(value)\n    else\n      else_fun.()\n    end\n  end\n\n  defp has_value?(value) do\n    value != @no_value\n  end\n\n  defp format_label(:message, _formatter, _padding_size), do: \"\"\n\n  defp format_label(label, formatter, padding_size) do\n    formatter.(:extra_info, String.pad_trailing(\"#{label}:\", padding_size))\n  end\n\n  defp format_message(value, formatter) do\n    value = pad_multiline(value, 5)\n\n    if String.contains?(value, IO.ANSI.reset()) do\n      value\n    else\n      formatter.(:error_info, value)\n    end\n  end\n\n  defp format_args(args, width) do\n    entries =\n      for {arg, i} <- Enum.with_index(args, 1) do\n        \"\"\"\n\n                 # #{i}\n                 #{inspect_multiline(arg, 9, width)}\n        \"\"\"\n      end\n\n    [\"\\n\" | entries]\n  end\n\n  @assertions [\n    :assert,\n    :assert_raise,\n    :assert_receive,\n    :assert_received,\n    :refute,\n    :refute_receive,\n    :refute_received\n  ]\n\n  defp code_multiline({fun, _, [expr]}, padding_size) when fun in @assertions do\n    pad_multiline(Atom.to_string(fun) <> \" \" <> Macro.to_string(expr), padding_size)\n  end\n\n  defp code_multiline(expr, padding_size) do\n    pad_multiline(Macro.to_string(expr), padding_size)\n  end\n\n  defp inspect_multiline(expr, padding_size, width) do\n    width = if width == :infinity, do: width, else: width - padding_size\n\n    expr\n    |> Algebra.to_doc(%Inspect.Opts{width: width})\n    |> Algebra.group()\n    |> Algebra.nest(padding_size)\n    |> Algebra.format(width)\n  end\n\n  defp format_stacktrace(stack, %{module: module, name: name}, color),\n    do: format_stacktrace(stack, module, name, color)\n\n  defp format_stacktrace(stack, %{name: name}, color),\n    do: format_stacktrace(stack, name, nil, color)\n\n  defp format_stacktrace([], _module, _test, _color) do\n    \"\"\n  end\n\n  defp format_stacktrace(stacktrace, module, test, color) do\n    extra_info(\"stacktrace:\", color) <>\n      Enum.map_join(stacktrace, fn entry ->\n        stacktrace_info(format_stacktrace_entry(entry, module, test), color)\n      end)\n  end\n\n  defp format_stacktrace_entry({module, test, _, location}, module, test) do\n    format_file_line(location[:file], location[:line], \" (test)\")\n  end\n\n  defp format_stacktrace_entry(entry, _module, _test) do\n    format_stacktrace_entry(entry)\n  end\n\n  defp with_location(tags) do\n    path = \"#{Path.relative_to_cwd(tags[:file])}:#{tags[:line]}\"\n\n    if prefix = Application.get_env(:ex_unit, :test_location_relative_path) do\n      Path.join(prefix, path)\n    else\n      path\n    end\n  end\n\n  defp failure_header([_], _), do: \"\"\n  defp failure_header(_, i), do: \"\\n#{@counter_padding}Failure ##{i + 1}\\n\"\n\n  defp with_counter(counter, msg) when counter < 10 do\n    \"  #{counter}) #{msg}\"\n  end\n\n  defp with_counter(counter, msg) when counter < 100 do\n    \" #{counter}) #{msg}\"\n  end\n\n  defp with_counter(counter, msg) do\n    \"#{counter}) #{msg}\"\n  end\n\n  defp test_module_info(msg, nil),\n    do: msg <> \"failure on setup_all callback, all tests have been invalidated\\n\"\n\n  defp test_module_info(msg, formatter),\n    do: test_module_info(formatter.(:test_module_info, msg), nil)\n\n  defp test_info(msg, nil), do: msg <> \"\\n\"\n  defp test_info(msg, formatter), do: test_info(formatter.(:test_info, msg), nil)\n\n  defp test_parameters(params, _formatter) when params == %{}, do: \"\"\n  defp test_parameters(params, nil) when is_binary(params), do: \"     \" <> params <> \"\\n\"\n\n  defp test_parameters(params, nil) when is_map(params),\n    do: test_parameters(\"Parameters: #{inspect(params)}\", nil)\n\n  defp test_parameters(params, formatter),\n    do: test_parameters(formatter.(:parameters_info, params), nil)\n\n  defp test_location(msg, nil), do: \"     \" <> msg <> \"\\n\"\n  defp test_location(msg, formatter), do: test_location(formatter.(:location_info, msg), nil)\n\n  defp pad(msg) do\n    \"     \" <> pad_multiline(msg, 5) <> \"\\n\"\n  end\n\n  defp pad_multiline(expr, padding_size) when is_binary(expr) do\n    expr\n    |> String.split(\"\\n\")\n    |> pad_line(\"\\n\" <> String.duplicate(\" \", padding_size))\n    |> IO.iodata_to_binary()\n  end\n\n  defp pad_line([last], _padding), do: [last]\n  defp pad_line([first, \"\" | rest], padding), do: [first, \"\\n\" | pad_line([\"\" | rest], padding)]\n  defp pad_line([first | rest], padding), do: [first, padding | pad_line(rest, padding)]\n\n  defp error_info(msg, nil), do: pad(msg)\n  defp error_info(msg, formatter), do: pad(formatter.(:error_info, msg))\n\n  defp extra_info(msg, nil), do: pad(msg)\n  defp extra_info(msg, formatter), do: pad(formatter.(:extra_info, msg))\n\n  defp stacktrace_info(\"\", _formatter), do: \"\"\n  defp stacktrace_info(msg, nil), do: \"       \" <> msg <> \"\\n\"\n\n  defp stacktrace_info(msg, formatter),\n    do: stacktrace_info(formatter.(:stacktrace_info, msg), nil)\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/on_exit_handler/supervisor.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule ExUnit.OnExitHandler.Supervisor do\n  @moduledoc false\n  use Supervisor\n\n  def start_link(children) do\n    Supervisor.start_link(__MODULE__, {children, get_callers(self())})\n  end\n\n  @impl true\n  def init({children, callers}) do\n    put_callers(callers)\n    Supervisor.init(children, strategy: :one_for_one, max_restarts: 1_000_000, max_seconds: 1)\n  end\n\n  defp get_callers(owner) do\n    case :erlang.get(:\"$callers\") do\n      [_ | _] = list -> [owner | list]\n      _ -> [owner]\n    end\n  end\n\n  defp put_callers(callers) do\n    :erlang.put(:\"$callers\", callers)\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/on_exit_handler.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.OnExitHandler do\n  @moduledoc false\n\n  # ETS table name stored in ExUnit.Server\n  @name ExUnit.Server\n\n  # ETS column numbers\n  @supervisor 2\n  @on_exit 3\n\n  @spec register(pid) :: :ok\n  def register(pid) when is_pid(pid) do\n    :ets.insert(@name, {pid, nil, []})\n    :ok\n  end\n\n  @spec add(pid, term, (-> term)) :: :ok | :error\n  def add(pid, name_or_ref, callback) when is_pid(pid) and is_function(callback, 0) do\n    try do\n      :ets.lookup_element(@name, pid, @on_exit)\n    rescue\n      _ -> :error\n    else\n      entries ->\n        entries = List.keystore(entries, name_or_ref, 0, {name_or_ref, callback})\n        true = :ets.update_element(@name, pid, {@on_exit, entries})\n        :ok\n    end\n  end\n\n  @spec get_supervisor(pid) :: {:ok, pid | nil} | :error\n  def get_supervisor(pid) when is_pid(pid) do\n    try do\n      {:ok, :ets.lookup_element(@name, pid, @supervisor)}\n    rescue\n      _ -> :error\n    end\n  end\n\n  @spec put_supervisor(pid, pid) :: :ok | :error\n  def put_supervisor(pid, sup) when is_pid(pid) and is_pid(sup) do\n    case :ets.update_element(@name, pid, {@supervisor, sup}) do\n      true -> :ok\n      false -> :error\n    end\n  end\n\n  @spec run(pid, timeout) :: :ok | {Exception.kind(), term, Exception.stacktrace()}\n  def run(pid, timeout) when is_pid(pid) do\n    [{^pid, sup, callbacks}] = :ets.take(@name, pid)\n    error = terminate_supervisor(sup, timeout)\n    exec_on_exit_callbacks(Enum.reverse(callbacks), timeout, error)\n  end\n\n  defp terminate_supervisor(nil, _timeout), do: nil\n\n  defp terminate_supervisor(sup, timeout) do\n    ref = Process.monitor(sup)\n\n    receive do\n      {:DOWN, ^ref, _, _, _} -> nil\n    after\n      timeout ->\n        {:error, ExUnit.TimeoutError.exception(timeout: timeout, type: \"supervisor shutdown\"), []}\n    end\n  end\n\n  defp exec_on_exit_callbacks(callbacks, timeout, error) do\n    {runner_pid, runner_monitor, error} =\n      Enum.reduce(callbacks, {nil, nil, error}, &exec_on_exit_callback(&1, timeout, &2))\n\n    if is_pid(runner_pid) and Process.alive?(runner_pid) do\n      Process.exit(runner_pid, :shutdown)\n\n      receive do\n        {:DOWN, ^runner_monitor, :process, ^runner_pid, _error} -> :ok\n      end\n    end\n\n    error || :ok\n  end\n\n  defp exec_on_exit_callback({_name_or_ref, callback}, timeout, runner) do\n    {runner_pid, runner_monitor, error} = runner\n    {runner_pid, runner_monitor} = ensure_alive_callback_runner(runner_pid, runner_monitor)\n    send(runner_pid, {:run, self(), callback})\n    receive_runner_reply(runner_pid, runner_monitor, error, timeout)\n  end\n\n  defp receive_runner_reply(runner_pid, runner_monitor, error, timeout) do\n    receive do\n      {^runner_pid, reason} ->\n        {runner_pid, runner_monitor, error || reason}\n\n      {:DOWN, ^runner_monitor, :process, ^runner_pid, reason} ->\n        {nil, nil, error || {{:EXIT, runner_pid}, reason, []}}\n    after\n      timeout ->\n        case Process.info(runner_pid, :current_stacktrace) do\n          {:current_stacktrace, stacktrace} ->\n            Process.exit(runner_pid, :kill)\n\n            receive do\n              {:DOWN, ^runner_monitor, :process, ^runner_pid, _} -> :ok\n            end\n\n            exception = ExUnit.TimeoutError.exception(timeout: timeout, type: \"on_exit callback\")\n            {nil, nil, error || {:error, exception, stacktrace}}\n\n          nil ->\n            receive_runner_reply(runner_pid, runner_monitor, error, timeout)\n        end\n    end\n  end\n\n  ## Runner\n\n  @doc false\n  def on_exit_runner_loop do\n    receive do\n      {:run, from, fun} ->\n        send(from, {self(), exec_callback(fun)})\n        on_exit_runner_loop()\n    end\n  end\n\n  defp ensure_alive_callback_runner(nil, nil) do\n    spawn_monitor(__MODULE__, :on_exit_runner_loop, [])\n  end\n\n  defp ensure_alive_callback_runner(runner_pid, runner_monitor) do\n    {runner_pid, runner_monitor}\n  end\n\n  defp exec_callback(callback) do\n    callback.()\n    nil\n  catch\n    kind, error ->\n      {kind, error, __STACKTRACE__}\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/runner.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.Runner do\n  @moduledoc false\n\n  alias ExUnit.EventManager, as: EM\n\n  @current_key __MODULE__\n\n  def run(opts, load_us) when (is_integer(load_us) or is_nil(load_us)) and is_list(opts) do\n    runner = self()\n    id = {__MODULE__, runner}\n\n    try do\n      # It may fail on Windows, so we ignore the result.\n      _ =\n        System.trap_signal(:sigquit, id, fn ->\n          ref = Process.monitor(runner)\n          send(runner, {ref, self(), :sigquit})\n\n          receive do\n            ^ref -> :ok\n            {:DOWN, ^ref, _, _, _} -> :ok\n          after\n            5_000 -> :ok\n          end\n\n          Process.demonitor(ref, [:flush])\n          :ok\n        end)\n\n      run_with_trap(opts, load_us)\n    after\n      System.untrap_signal(:sigquit, id)\n    end\n  end\n\n  defp run_with_trap(opts, load_us) do\n    opts = normalize_opts(opts)\n    {:ok, manager} = EM.start_link()\n    {:ok, stats_pid} = EM.add_handler(manager, ExUnit.RunnerStats, opts)\n    config = configure(opts, manager, self(), stats_pid)\n    :erlang.system_flag(:backtrace_depth, Keyword.fetch!(opts, :stacktrace_depth))\n\n    start_time = System.monotonic_time()\n    EM.suite_started(config.manager, opts)\n\n    modules_to_restore =\n      if Keyword.fetch!(opts, :repeat_until_failure) > 0, do: {[], []}, else: nil\n\n    {async_stop_time, modules_to_restore} = async_loop(config, %{}, false, modules_to_restore)\n    stop_time = System.monotonic_time()\n\n    if max_failures_reached?(config) do\n      EM.max_failures_reached(config.manager)\n    end\n\n    async_us =\n      async_stop_time &&\n        System.convert_time_unit(async_stop_time - start_time, :native, :microsecond)\n\n    run_us = System.convert_time_unit(stop_time - start_time, :native, :microsecond)\n    times_us = %{async: async_us, load: load_us, run: run_us}\n    EM.suite_finished(config.manager, times_us)\n\n    stats = ExUnit.RunnerStats.stats(stats_pid)\n    EM.stop(config.manager)\n    after_suite_callbacks = Application.fetch_env!(:ex_unit, :after_suite)\n    Enum.each(after_suite_callbacks, fn callback -> callback.(stats) end)\n    {stats, modules_to_restore}\n  end\n\n  defp configure(opts, manager, runner_pid, stats_pid) do\n    Enum.each(opts[:formatters], &EM.add_handler(manager, &1, opts))\n\n    %{\n      capture_log: opts[:capture_log],\n      exclude: opts[:exclude],\n      include: opts[:include],\n      manager: manager,\n      max_cases: opts[:max_cases],\n      max_failures: opts[:max_failures],\n      only_test_ids: opts[:only_test_ids],\n      rand_algorithm: opts[:rand_algorithm],\n      runner_pid: runner_pid,\n      seed: opts[:seed],\n      stats_pid: stats_pid,\n      timeout: opts[:timeout],\n      trace: opts[:trace],\n      dry_run: opts[:dry_run]\n    }\n  end\n\n  defp normalize_opts(opts) do\n    {include, exclude} = ExUnit.Filters.normalize(opts[:include], opts[:exclude])\n\n    opts\n    |> Keyword.put(:exclude, exclude)\n    |> Keyword.put(:include, include)\n  end\n\n  defp async_loop(config, running, async_once?, modules_to_restore) do\n    available = config.max_cases - map_size(running)\n\n    cond do\n      # No modules available, wait for one\n      available <= 0 ->\n        running = wait_until_available(config, running)\n        async_loop(config, running, async_once?, modules_to_restore)\n\n      # Slots are available, start with async modules\n      async_modules = ExUnit.Server.take_async_modules(available) ->\n        running = spawn_modules(config, async_modules, true, running)\n        modules_to_restore = maybe_store_modules(modules_to_restore, :async, async_modules)\n        async_loop(config, running, true, modules_to_restore)\n\n      true ->\n        sync_modules = ExUnit.Server.take_sync_modules()\n        modules_to_restore = maybe_store_modules(modules_to_restore, :sync, sync_modules)\n\n        # Wait for all async modules\n        0 =\n          running\n          |> Enum.reduce(running, fn _, acc -> wait_until_available(config, acc) end)\n          |> map_size()\n\n        async_stop_time = if async_once?, do: System.monotonic_time(), else: nil\n\n        # Run all sync modules directly\n        for pair <- sync_modules do\n          running = spawn_modules(config, [{nil, [pair]}], false, %{})\n          running != %{} and wait_until_available(config, running)\n        end\n\n        {async_stop_time, modules_to_restore}\n    end\n  end\n\n  # Expect down messages from the spawned modules.\n  #\n  # We first look at the sigquit signal because we don't want\n  # to spawn new test cases when we know we will have to handle\n  # sigquit next.\n  #\n  # Otherwise, whenever a module has finished executing, update\n  # the running modules and attempt to spawn new ones.\n  defp wait_until_available(config, running) do\n    receive do\n      {ref, pid, :sigquit} ->\n        sigquit(config, ref, pid, running)\n    after\n      0 ->\n        receive do\n          {ref, pid, :sigquit} ->\n            sigquit(config, ref, pid, running)\n\n          {:DOWN, ref, _, _, _} when is_map_key(running, ref) ->\n            Map.delete(running, ref)\n        end\n    end\n  end\n\n  defp spawn_modules(_config, [], _async, running) do\n    running\n  end\n\n  defp spawn_modules(config, [{group, modules} | groups], async?, running) do\n    cond do\n      max_failures_reached?(config) ->\n        running\n\n      modules == [] ->\n        spawn_modules(config, groups, async?, running)\n\n      true ->\n        {pid, ref} =\n          spawn_monitor(fn ->\n            Enum.each(modules, fn {module, params} ->\n              run_module(config, module, async?, group, params)\n            end)\n          end)\n\n        spawn_modules(config, groups, async?, Map.put(running, ref, pid))\n    end\n  end\n\n  defp maybe_store_modules(nil, _type, _modules), do: nil\n  defp maybe_store_modules({async, sync}, :async, modules), do: {async ++ modules, sync}\n  defp maybe_store_modules({async, sync}, :sync, modules), do: {async, sync ++ modules}\n\n  ## Stacktrace\n\n  # Assertions can pop-up in the middle of the stack\n  def prune_stacktrace([{ExUnit.Assertions, _, _, _} | t]), do: prune_stacktrace(t)\n\n  # As soon as we see a Runner, it is time to ignore the stacktrace\n  def prune_stacktrace([{ExUnit.Runner, _, _, _} | _]), do: []\n\n  # All other cases\n  def prune_stacktrace([h | t]), do: [h | prune_stacktrace(t)]\n  def prune_stacktrace([]), do: []\n\n  ## sigquit\n\n  defp sigquit(config, ref, pid, running) do\n    # Stop all child processes from running and get their current state.\n    # We need to stop these processes because they may invoke the event\n    # manager and we must stop the event manager to guarantee the sigquit\n    # data has been flushed.\n    current =\n      Enum.map(running, fn {ref, pid} ->\n        current = safe_pdict_current(pid)\n        Process.exit(pid, :shutdown)\n\n        receive do\n          {:DOWN, ^ref, _, _, _} -> current\n        end\n      end)\n\n    EM.sigquit(config.manager, Enum.reject(current, &is_nil/1))\n    EM.stop(config.manager)\n\n    # Reply to the event manager and wait until it shuts down the VM.\n    send(pid, ref)\n    Process.sleep(:infinity)\n  end\n\n  defp safe_pdict_current(pid) do\n    with {:dictionary, dictionary} <- Process.info(pid, :dictionary),\n         {@current_key, current} <- List.keyfind(dictionary, @current_key, 0),\n         do: current\n  rescue\n    _ -> nil\n  end\n\n  ## Running modules\n\n  defp run_module(config, module, async?, group, params) do\n    test_module = %{module.__ex_unit__() | parameters: params}\n    EM.module_started(config.manager, test_module)\n\n    # Prepare tests, selecting which ones should be run or skipped\n    {to_run_tests, excluded_and_skipped_tests} =\n      prepare_tests(config, async?, group, test_module.tests)\n\n    for excluded_or_skipped_test <- excluded_and_skipped_tests do\n      EM.test_started(config.manager, excluded_or_skipped_test)\n      EM.test_finished(config.manager, excluded_or_skipped_test)\n    end\n\n    {test_module, invalid_tests, finished_tests} =\n      run_module_tests(config, test_module, async?, to_run_tests)\n\n    pending_tests =\n      case process_max_failures(config, test_module) do\n        :no ->\n          invalid_tests\n\n        {:reached, n} ->\n          Enum.take(invalid_tests, n)\n\n        :surpassed ->\n          nil\n      end\n\n    # If pending_tests is [], EM.module_finished is still called.\n    # Only if process_max_failures/2 returns :surpassed it is not.\n    if pending_tests do\n      for pending_test <- pending_tests do\n        EM.test_started(config.manager, pending_test)\n        EM.test_finished(config.manager, pending_test)\n      end\n\n      test_module = %{test_module | tests: Enum.reverse(finished_tests, pending_tests)}\n      EM.module_finished(config.manager, test_module)\n    end\n  end\n\n  defp prepare_tests(config, async?, group, tests) do\n    tests = shuffle(config, tests)\n    include = config.include\n    exclude = config.exclude\n    test_ids = config.only_test_ids\n\n    {to_run, to_skip} =\n      for test <- tests, include_test?(test_ids, test), reduce: {[], []} do\n        {to_run, to_skip} ->\n          tags =\n            Map.merge(test.tags, %{\n              test: test.name,\n              module: test.module,\n              async: async?,\n              test_group: group\n            })\n\n          case ExUnit.Filters.eval(include, exclude, tags, tests) do\n            :ok -> {[%{test | tags: tags} | to_run], to_skip}\n            excluded_or_skipped -> {to_run, [%{test | state: excluded_or_skipped} | to_skip]}\n          end\n      end\n\n    {Enum.reverse(to_run), Enum.reverse(to_skip)}\n  end\n\n  defp include_test?(test_ids, test) do\n    test_ids == nil or MapSet.member?(test_ids, {test.module, test.name})\n  end\n\n  defp run_module_tests(_config, test_module, _async?, []) do\n    {test_module, [], []}\n  end\n\n  defp run_module_tests(%{dry_run: true}, test_module, _async?, tests) do\n    {test_module, [], tests}\n  end\n\n  defp run_module_tests(config, test_module, async?, tests) do\n    Process.put(@current_key, test_module)\n    %ExUnit.TestModule{name: module, tags: tags, parameters: params} = test_module\n    context = tags |> Map.merge(params) |> Map.merge(%{module: module, async: async?})\n\n    config\n    |> run_setup_all(test_module, context, fn context ->\n      if max_failures_reached?(config),\n        do: [],\n        else: run_tests(config, tests, test_module.parameters, context)\n    end)\n    |> case do\n      {{:ok, finished_tests}, test_module} ->\n        {test_module, [], finished_tests}\n\n      {:error, test_module} ->\n        {test_module, Enum.map(tests, &%{&1 | state: {:invalid, test_module}}), []}\n    end\n  end\n\n  defp run_setup_all(\n         _config,\n         %ExUnit.TestModule{setup_all?: false} = test_module,\n         context,\n         callback\n       ) do\n    {{:ok, callback.(context)}, test_module}\n  end\n\n  defp run_setup_all(config, %ExUnit.TestModule{name: module} = test_module, context, callback) do\n    parent_pid = self()\n\n    {module_pid, module_ref} =\n      spawn_monitor(fn ->\n        ExUnit.OnExitHandler.register(self())\n\n        result =\n          try do\n            {:ok, module.__ex_unit__(:setup_all, context)}\n          catch\n            kind, error ->\n              failed = failed(kind, error, prune_stacktrace(__STACKTRACE__))\n              {:error, %{test_module | state: failed}}\n          end\n\n        send(parent_pid, {self(), :setup_all, result})\n\n        # We keep the process alive so all of its resources\n        # stay alive until we run all tests in this case.\n        ref = Process.monitor(parent_pid)\n\n        receive do\n          {^parent_pid, :exit} -> :ok\n          {:DOWN, ^ref, _, _, _} -> :ok\n        end\n      end)\n\n    {ok_or_error, test_module} =\n      receive do\n        {^module_pid, :setup_all, {:ok, context}} ->\n          finished_tests = callback.(context)\n          :ok = exit_setup_all(module_pid, module_ref)\n          {{:ok, finished_tests}, test_module}\n\n        {^module_pid, :setup_all, {:error, test_module}} ->\n          :ok = exit_setup_all(module_pid, module_ref)\n          {:error, test_module}\n\n        {:DOWN, ^module_ref, :process, ^module_pid, error} ->\n          {:error, %{test_module | state: failed({:EXIT, module_pid}, error, [])}}\n      end\n\n    timeout = get_timeout(config, %{})\n    {ok_or_error, exec_on_exit(test_module, module_pid, timeout)}\n  end\n\n  defp exit_setup_all(pid, ref) do\n    send(pid, {self(), :exit})\n\n    receive do\n      {:DOWN, ^ref, _, _, _} -> :ok\n    end\n  end\n\n  defp run_tests(config, tests, params, context) do\n    Enum.reduce_while(tests, [], fn test, acc ->\n      test = %{test | parameters: params}\n      Process.put(@current_key, test)\n\n      case run_test(config, test, context) do\n        {:ok, test} -> {:cont, [test | acc]}\n        :max_failures_reached -> {:halt, acc}\n      end\n    end)\n  end\n\n  defp run_test(config, test, context) do\n    EM.test_started(config.manager, test)\n    test = spawn_test(config, test, context)\n\n    case process_max_failures(config, test) do\n      :no ->\n        EM.test_finished(config.manager, test)\n        {:ok, test}\n\n      {:reached, 1} ->\n        EM.test_finished(config.manager, test)\n        :max_failures_reached\n\n      :surpassed ->\n        :max_failures_reached\n    end\n  end\n\n  defp spawn_test(config, test, context) do\n    parent_pid = self()\n    timeout = get_timeout(config, test.tags)\n    {test_pid, test_ref} = spawn_test_monitor(config, test, parent_pid, context)\n    test = receive_test_reply(test, test_pid, test_ref, timeout)\n    exec_on_exit(test, test_pid, timeout)\n  end\n\n  defp spawn_test_monitor(\n         %{seed: seed, capture_log: capture_log, rand_algorithm: rand_algorithm},\n         test,\n         parent_pid,\n         context\n       ) do\n    spawn_monitor(fn ->\n      Process.set_label({test.case, test.name})\n      ExUnit.OnExitHandler.register(self())\n      generate_test_seed(seed, test, rand_algorithm)\n      context = context |> Map.merge(test.tags) |> Map.put(:test_pid, self())\n      capture_log = Map.get(context, :capture_log, capture_log)\n\n      {time, test} =\n        :timer.tc(\n          maybe_capture_log(capture_log, test, fn ->\n            context = maybe_create_tmp_dir(context, test)\n\n            case exec_test_setup(test, context) do\n              {:ok, context} -> exec_test(test, context)\n              {:error, test} -> test\n            end\n          end)\n        )\n\n      send(parent_pid, {self(), :test_finished, %{test | time: time}})\n      exit(:shutdown)\n    end)\n  end\n\n  defp maybe_capture_log(true, test, fun) do\n    maybe_capture_log([], test, fun)\n  end\n\n  defp maybe_capture_log(false, _test, fun) do\n    fun\n  end\n\n  defp maybe_capture_log(capture_log_opts, test, fun) do\n    fn ->\n      try do\n        ExUnit.CaptureLog.with_log(capture_log_opts, fun)\n      catch\n        :exit, :noproc ->\n          message =\n            \"could not run test, it uses @tag :capture_log\" <>\n              \" but the :logger application is not running\"\n\n          %{test | state: failed(:error, RuntimeError.exception(message), [])}\n      else\n        {test, logs} -> %{test | logs: logs}\n      end\n    end\n  end\n\n  defp receive_test_reply(test, test_pid, test_ref, timeout) do\n    receive do\n      {^test_pid, :test_finished, test} ->\n        Process.demonitor(test_ref, [:flush])\n        test\n\n      {:DOWN, ^test_ref, :process, ^test_pid, error} ->\n        %{test | state: failed({:EXIT, test_pid}, error, [])}\n    after\n      timeout ->\n        case Process.info(test_pid, :current_stacktrace) do\n          {:current_stacktrace, stacktrace} ->\n            Process.demonitor(test_ref, [:flush])\n            Process.exit(test_pid, :kill)\n\n            exception =\n              ExUnit.TimeoutError.exception(\n                timeout: timeout,\n                type: Atom.to_string(test.tags.test_type)\n              )\n\n            %{test | state: failed(:error, exception, stacktrace)}\n\n          nil ->\n            receive_test_reply(test, test_pid, test_ref, timeout)\n        end\n    end\n  end\n\n  defp exec_test_setup(%ExUnit.Test{module: module} = test, context) do\n    {:ok, module.__ex_unit__(:setup, context)}\n  catch\n    kind, error ->\n      {:error, %{test | state: failed(kind, error, prune_stacktrace(__STACKTRACE__))}}\n  end\n\n  defp exec_test(%ExUnit.Test{module: module, name: name} = test, context) do\n    apply(module, name, [context])\n    test\n  catch\n    kind, error ->\n      %{test | state: failed(kind, error, prune_stacktrace(__STACKTRACE__))}\n  end\n\n  defp exec_on_exit(test_or_case, pid, timeout) do\n    case ExUnit.OnExitHandler.run(pid, timeout) do\n      :ok ->\n        test_or_case\n\n      {kind, reason, stack} ->\n        state = test_or_case.state || failed(kind, reason, prune_stacktrace(stack))\n        %{test_or_case | state: state}\n    end\n  end\n\n  ## Helpers\n\n  defp generate_test_seed(seed, %ExUnit.Test{module: module, name: name}, rand_algorithm) do\n    :rand.seed(rand_algorithm, {:erlang.phash2(module), :erlang.phash2(name), seed})\n  end\n\n  defp process_max_failures(%{max_failures: :infinity}, _), do: :no\n\n  defp process_max_failures(config, %ExUnit.TestModule{state: {:failed, _}, tests: tests}) do\n    process_max_failures(config.stats_pid, config.max_failures, length(tests))\n  end\n\n  defp process_max_failures(config, %ExUnit.Test{state: {:failed, _}}) do\n    process_max_failures(config.stats_pid, config.max_failures, 1)\n  end\n\n  defp process_max_failures(config, _test_module_or_test) do\n    if max_failures_reached?(config), do: :surpassed, else: :no\n  end\n\n  defp process_max_failures(stats_pid, max_failures, bump) do\n    previous = ExUnit.RunnerStats.increment_failure_counter(stats_pid, bump)\n\n    cond do\n      previous >= max_failures -> :surpassed\n      previous + bump < max_failures -> :no\n      true -> {:reached, max_failures - previous}\n    end\n  end\n\n  defp max_failures_reached?(%{stats_pid: stats_pid, max_failures: max_failures}) do\n    max_failures != :infinity and\n      ExUnit.RunnerStats.get_failure_counter(stats_pid) >= max_failures\n  end\n\n  defp get_timeout(config, tags) do\n    if config.trace do\n      :infinity\n    else\n      Map.get(tags, :timeout, config.timeout)\n    end\n  end\n\n  defp shuffle(%{seed: 0}, list) do\n    list\n  end\n\n  defp shuffle(%{seed: seed, rand_algorithm: rand_algorithm}, list) do\n    _ = :rand.seed(rand_algorithm, {seed, seed, seed})\n    Enum.shuffle(list)\n  end\n\n  defp failed(:error, %ExUnit.MultiError{errors: errors}, _stack) do\n    errors =\n      Enum.map(errors, fn {kind, reason, stack} ->\n        {kind, Exception.normalize(kind, reason, stack), prune_stacktrace(stack)}\n      end)\n\n    {:failed, errors}\n  end\n\n  defp failed(kind, reason, stack) do\n    {:failed, [{kind, Exception.normalize(kind, reason, stack), stack}]}\n  end\n\n  ## Tmp dir handling\n\n  defp maybe_create_tmp_dir(%{tmp_dir: true} = tags, test) do\n    create_tmp_dir!(test, \"\", tags)\n  end\n\n  defp maybe_create_tmp_dir(%{tmp_dir: path} = tags, test) when is_binary(path) do\n    create_tmp_dir!(test, path, tags)\n  end\n\n  defp maybe_create_tmp_dir(%{tmp_dir: other}, _test) when other != false do\n    raise ArgumentError, \"expected :tmp_dir to be a boolean or a string, got: #{inspect(other)}\"\n  end\n\n  defp maybe_create_tmp_dir(tags, _test) do\n    tags\n  end\n\n  defp short_hash(module, test_name, parameters) do\n    suffix = if parameters == %{}, do: \"\", else: :erlang.term_to_binary(parameters)\n\n    (module <> \"/\" <> test_name <> suffix)\n    |> :erlang.md5()\n    |> Base.encode16(case: :lower)\n    |> binary_slice(0..7)\n  end\n\n  defp create_tmp_dir!(test, extra_path, tags) do\n    module_string = inspect(test.module)\n    name_string = to_string(test.name)\n\n    module = escape_path(module_string)\n    name = escape_path(name_string)\n    short_hash = short_hash(module_string, name_string, test.parameters)\n\n    path = [\"tmp\", module, \"#{name}-#{short_hash}\", extra_path] |> Path.join() |> Path.expand()\n    File.rm_rf!(path)\n    File.mkdir_p!(path)\n    Map.put(tags, :tmp_dir, path)\n  end\n\n  @escape Enum.map(~c\" [~#%&*{}\\\\:<>?/+|\\\"]\", &<<&1::utf8>>)\n\n  defp escape_path(path) do\n    String.replace(path, @escape, \"-\")\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/runner_stats.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.RunnerStats do\n  @moduledoc false\n\n  use GenServer\n  alias ExUnit.{FailuresManifest, Test}\n\n  @typep counter :: non_neg_integer\n\n  @spec stats(pid) :: %{\n          excluded: counter,\n          failures: counter,\n          skipped: counter,\n          total: counter\n        }\n  def stats(pid) when is_pid(pid) do\n    GenServer.call(pid, :stats, :infinity)\n  end\n\n  @spec get_failure_counter(pid) :: counter\n  def get_failure_counter(sup) when is_pid(sup) do\n    GenServer.call(sup, :get_failure_counter)\n  end\n\n  @spec increment_failure_counter(pid) :: pos_integer\n  def increment_failure_counter(sup, increment \\\\ 1)\n      when is_pid(sup) and is_integer(increment) and increment >= 1 do\n    GenServer.call(sup, {:increment_failure_counter, increment})\n  end\n\n  # Callbacks\n\n  def init(opts) do\n    state = %{\n      total: 0,\n      passed: 0,\n      failures: 0,\n      skipped: 0,\n      excluded: 0,\n      failures_manifest_path: opts[:failures_manifest_path],\n      failures_manifest: FailuresManifest.new(),\n      failure_counter: 0,\n      pids: []\n    }\n\n    {:ok, state}\n  end\n\n  def handle_call(:stats, _from, state) do\n    stats = Map.take(state, [:total, :failures, :skipped, :excluded])\n    {:reply, stats, state}\n  end\n\n  def handle_call(:get_failure_counter, _from, state) do\n    {:reply, state.failure_counter, state}\n  end\n\n  def handle_call({:increment_failure_counter, increment}, _from, state) do\n    %{failure_counter: failure_counter} = state\n    {:reply, failure_counter, %{state | failure_counter: failure_counter + increment}}\n  end\n\n  def handle_cast({:test_finished, %Test{} = test}, state) do\n    state =\n      state\n      |> Map.update!(:failures_manifest, &FailuresManifest.put_test(&1, test))\n      |> Map.update!(:total, &(&1 + 1))\n      |> increment_status_counter(test.state)\n\n    {:noreply, state}\n  end\n\n  def handle_cast({:suite_started, _opts}, %{failures_manifest_path: file} = state)\n      when is_binary(file) do\n    state = %{state | failures_manifest: FailuresManifest.read(file)}\n    {:noreply, state}\n  end\n\n  def handle_cast({:suite_finished, _}, %{failures_manifest_path: file} = state)\n      when is_binary(file) do\n    FailuresManifest.write!(state.failures_manifest, file)\n    {:noreply, state}\n  end\n\n  def handle_cast(\n        {:module_finished, %ExUnit.TestModule{state: {:failed, _}} = test_module},\n        state\n      ) do\n    # The failed tests have already been added to the manifest,\n    # so we should only invalidate the successful tests\n    successful_tests = Enum.filter(test_module.tests, &is_nil(&1.state))\n\n    state =\n      Enum.reduce(successful_tests, state, fn test, acc ->\n        acc\n        |> Map.update!(:failures_manifest, &FailuresManifest.put_test(&1, test))\n        |> Map.update!(:failures, &(&1 + 1))\n        |> Map.update!(:passed, &(&1 - 1))\n      end)\n\n    {:noreply, state}\n  end\n\n  def handle_cast(_, state) do\n    {:noreply, state}\n  end\n\n  defp increment_status_counter(state, tag) when tag in [nil, :passed] do\n    Map.update!(state, :passed, &(&1 + 1))\n  end\n\n  defp increment_status_counter(state, {:skipped, _}) do\n    Map.update!(state, :skipped, &(&1 + 1))\n  end\n\n  defp increment_status_counter(state, {:excluded, _}) do\n    Map.update!(state, :excluded, &(&1 + 1))\n  end\n\n  defp increment_status_counter(state, {tag, _}) when tag in [:failed, :invalid] do\n    Map.update!(state, :failures, &(&1 + 1))\n  end\n\n  defp increment_status_counter(state, _), do: state\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit/server.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.Server do\n  @moduledoc false\n  @name __MODULE__\n  @timeout :infinity\n\n  use GenServer\n\n  def start_link(_opts) do\n    GenServer.start_link(__MODULE__, :ok, name: @name)\n  end\n\n  def add_module(name, config) do\n    %{\n      async?: async?,\n      group: group,\n      parameterize: parameterize\n    } = config\n\n    modules =\n      if parameterize do\n        Enum.map(parameterize, &{name, &1})\n      else\n        [{name, %{}}]\n      end\n\n    case GenServer.call(@name, {:add, async?, group, modules}, @timeout) do\n      :ok ->\n        :ok\n\n      :already_running ->\n        raise \"cannot add module named #{inspect(name)} to test suite after the suite starts running\"\n    end\n  end\n\n  def modules_loaded(uniq?) do\n    GenServer.call(@name, {:modules_loaded, uniq?}, @timeout)\n  end\n\n  def take_async_modules(count) do\n    GenServer.call(@name, {:take_async_modules, count}, @timeout)\n  end\n\n  def take_sync_modules() do\n    GenServer.call(@name, :take_sync_modules, @timeout)\n  end\n\n  def restore_modules(async_modules, sync_modules) do\n    GenServer.call(@name, {:restore_modules, async_modules, sync_modules}, @timeout)\n  end\n\n  ## Callbacks\n\n  def init(:ok) do\n    # Table used by OnExitHandler\n    :ets.new(__MODULE__, [:public, :named_table, read_concurrency: true, write_concurrency: true])\n\n    state = %{\n      loaded: System.monotonic_time(),\n      waiting: nil,\n      groups: %{},\n      async_groups: [],\n      async_modules: :queue.new(),\n      sync_modules: []\n    }\n\n    {:ok, state}\n  end\n\n  # Called on demand until we are signaled all modules are loaded.\n  def handle_call({:take_async_modules, count}, from, %{waiting: nil} = state) do\n    {:noreply, take_modules(%{state | waiting: {from, count}})}\n  end\n\n  # Called once after all async modules have been sent and reverts the state.\n  def handle_call(:take_sync_modules, _from, state) do\n    %{waiting: nil, loaded: :done, async_groups: []} = state\n    true = :queue.is_empty(state.async_modules)\n\n    {:reply, state.sync_modules, %{state | sync_modules: [], loaded: System.monotonic_time()}}\n  end\n\n  # Called by the runner when --repeat-until-failure is used.\n  def handle_call({:restore_modules, async_modules, sync_modules}, _from, state) do\n    {async_modules, async_groups, groups} =\n      Enum.reduce(async_modules, {[], [], []}, fn\n        {nil, [module]}, {async_modules, async_groups, groups} ->\n          {[module | async_modules], async_groups, groups}\n\n        {group, group_modules}, {async_modules, async_groups, groups} ->\n          {async_modules, [group | async_groups], [{group, group_modules} | groups]}\n      end)\n\n    {:reply, :ok,\n     %{\n       state\n       | loaded: :done,\n         groups: Map.new(groups),\n         async_groups: async_groups,\n         async_modules: :queue.from_list(async_modules),\n         sync_modules: sync_modules\n     }}\n  end\n\n  def handle_call({:modules_loaded, _}, _from, %{loaded: :done} = state) do\n    {:reply, 0, state}\n  end\n\n  def handle_call({:modules_loaded, uniq?}, _from, %{loaded: loaded} = state)\n      when is_integer(loaded) do\n    state =\n      if uniq? do\n        groups = Map.new(state.groups, fn {group, modules} -> {group, Enum.uniq(modules)} end)\n        async_groups = state.async_groups |> Enum.uniq() |> Enum.reverse()\n        async_modules = :queue.to_list(state.async_modules) |> Enum.uniq() |> :queue.from_list()\n        sync_modules = state.sync_modules |> Enum.uniq() |> Enum.reverse()\n\n        %{\n          state\n          | groups: groups,\n            async_groups: async_groups,\n            async_modules: async_modules,\n            sync_modules: sync_modules\n        }\n      else\n        %{\n          state\n          | async_groups: Enum.reverse(state.async_groups),\n            sync_modules: Enum.reverse(state.sync_modules)\n        }\n      end\n\n    diff = System.convert_time_unit(System.monotonic_time() - loaded, :native, :microsecond)\n    {:reply, diff, take_modules(%{state | loaded: :done})}\n  end\n\n  def handle_call({:add, false = _async, _group, names}, _from, %{loaded: loaded} = state)\n      when is_integer(loaded) do\n    state = update_in(state.sync_modules, &Enum.reverse(names, &1))\n    {:reply, :ok, state}\n  end\n\n  def handle_call({:add, true = _async, nil = _group, names}, _from, %{loaded: loaded} = state)\n      when is_integer(loaded) do\n    state =\n      update_in(\n        state.async_modules,\n        &Enum.reduce(names, &1, fn name, q -> :queue.in(name, q) end)\n      )\n\n    {:reply, :ok, take_modules(state)}\n  end\n\n  def handle_call({:add, true = _async, group, names}, _from, %{loaded: loaded} = state)\n      when is_integer(loaded) do\n    {groups, async_groups} =\n      case state.groups do\n        %{^group => entries} = groups ->\n          {%{groups | group => Enum.reverse(names, entries)}, state.async_groups}\n\n        %{} = groups ->\n          {Map.put(groups, group, names), [group | state.async_groups]}\n      end\n\n    {:reply, :ok, take_modules(%{state | groups: groups, async_groups: async_groups})}\n  end\n\n  def handle_call({:add, _async?, _group, _names}, _from, state) do\n    {:reply, :already_running, state}\n  end\n\n  defp take_modules(%{waiting: nil} = state) do\n    state\n  end\n\n  defp take_modules(%{waiting: {from, count}} = state) do\n    cond do\n      not :queue.is_empty(state.async_modules) ->\n        {reply, remaining_modules} = take_until(count, state.async_modules)\n        GenServer.reply(from, reply)\n        %{state | async_modules: remaining_modules, waiting: nil}\n\n      state.async_groups != [] and state.loaded == :done ->\n        {groups, remaining_groups} = Enum.split(state.async_groups, count)\n\n        {reply, groups} =\n          Enum.map_reduce(groups, state.groups, fn group, acc ->\n            {entries, acc} = Map.pop!(acc, group)\n            {{group, Enum.reverse(entries)}, acc}\n          end)\n\n        GenServer.reply(from, reply)\n        %{state | groups: groups, async_groups: remaining_groups, waiting: nil}\n\n      state.loaded == :done ->\n        GenServer.reply(from, nil)\n        %{state | waiting: nil}\n\n      true ->\n        state\n    end\n  end\n\n  # :queue.split fails if the provided count is larger than the queue size.\n  # We also want to return the values as tuples of shape {group, [modules]}.\n  defp take_until(n, queue), do: take_until(n, queue, [])\n\n  defp take_until(0, queue, acc), do: {Enum.reverse(acc), queue}\n\n  defp take_until(n, queue, acc) do\n    case :queue.out(queue) do\n      {{:value, item}, queue} -> take_until(n - 1, queue, [{nil, [item]} | acc])\n      {:empty, queue} -> {Enum.reverse(acc), queue}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/lib/ex_unit.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit do\n  @moduledoc \"\"\"\n  Unit testing framework for Elixir.\n\n  ## Example\n\n  A basic setup for ExUnit is shown below:\n\n      # File: assertion_test.exs\n\n      # 1) Start ExUnit.\n      ExUnit.start()\n\n      # 2) Create a new test module and use \"ExUnit.Case\".\n      defmodule AssertionTest do\n        # 3) Note that we pass \"async: true\", this runs the tests in the\n        #    test module concurrently with other test modules. The\n        #    individual tests within each test module are still run serially.\n        use ExUnit.Case, async: true\n\n        # 4) Use the \"test\" macro instead of \"def\" for clarity.\n        test \"the truth\" do\n          assert true\n        end\n      end\n\n  To run the tests above, run the file using `elixir` from the\n  command line. Assuming you named the file `assertion_test.exs`,\n  you can run it as:\n\n      $ elixir assertion_test.exs\n\n  ## Case, Callbacks and Assertions\n\n  See `ExUnit.Case` and `ExUnit.Callbacks` for more information\n  about defining test cases and setting up callbacks.\n\n  The `ExUnit.Assertions` module contains a set of macros to\n  generate assertions with appropriate error messages.\n\n  ## Integration with Mix\n\n  Mix is the project management and build tool for Elixir. Invoking `mix test`\n  from the command line will run the tests in each file matching the pattern\n  `*_test.exs` found in the `test` directory of your project.\n\n  You must create a `test_helper.exs` file inside the\n  `test` directory and put the code common to all tests there.\n\n  The minimum example of a `test_helper.exs` file would be:\n\n      # test/test_helper.exs\n      ExUnit.start()\n\n  Mix will load the `test_helper.exs` file before executing the tests.\n  It is not necessary to `require` the `test_helper.exs` file in your test\n  files. Run `mix help test` for more information.\n  \"\"\"\n\n  @typedoc \"\"\"\n  All tests start with a state of `nil`.\n\n  A finished test can be in one of five states:\n\n    1. Passed (also represented by `nil`)\n    2. Failed\n    3. Skipped (via @tag :skip)\n    4. Excluded (via :exclude filters)\n    5. Invalid (when setup_all fails)\n\n  \"\"\"\n  @type state ::\n          nil\n          | {:excluded, binary}\n          | {:failed, failed}\n          | {:invalid, ExUnit.TestModule.t()}\n          | {:skipped, binary}\n\n  @typedoc \"The error state returned by `ExUnit.Test` and `ExUnit.TestModule`\"\n  @type failed :: [{Exception.kind(), reason :: term, Exception.stacktrace()}]\n\n  @typedoc \"A map representing the results of running a test suite\"\n  @type suite_result :: %{\n          excluded: non_neg_integer,\n          failures: non_neg_integer,\n          skipped: non_neg_integer,\n          total: non_neg_integer\n        }\n\n  @type test_id :: {module, name :: atom}\n\n  @typedoc \"\"\"\n  Configuration options for ExUnit.\n\n  See `configure/1` for detailed documentation of each option.\n  \"\"\"\n  @type configure_opts :: [\n          {:assert_receive_timeout, non_neg_integer()}\n          | {:autorun, boolean()}\n          | {:capture_log, boolean() | [level: Logger.level()]}\n          | {:colors,\n             [\n               enabled: boolean(),\n               success: atom(),\n               invalid: atom(),\n               skipped: atom(),\n               failure: atom(),\n               error_info: atom(),\n               extra_info: atom(),\n               location_info: [atom()],\n               diff_insert: atom(),\n               diff_insert_whitespace: IO.ANSI.ansidata(),\n               diff_delete: atom(),\n               diff_delete_whitespace: IO.ANSI.ansidata()\n             ]}\n          | {:exclude, atom() | [atom() | {atom(), any()}]}\n          | {:exit_status, non_neg_integer()}\n          | {:failures_manifest_path, String.t()}\n          | {:formatters, [module()]}\n          | {:include, atom() | [atom() | {atom(), any()}]}\n          | {:max_cases, pos_integer()}\n          | {:max_failures, pos_integer() | :infinity}\n          | {:only_test_ids, [test_id()]}\n          | {:rand_algorithm, atom()}\n          | {:refute_receive_timeout, non_neg_integer()}\n          | {:seed, non_neg_integer()}\n          | {:slowest, non_neg_integer()}\n          | {:slowest_modules, non_neg_integer()}\n          | {:stacktrace_depth, non_neg_integer()}\n          | {:timeout, pos_integer()}\n          | {:trace, boolean()}\n          | {:test_location_relative_path, String.t()}\n          | {atom(), term()}\n        ]\n\n  defmodule Test do\n    @moduledoc \"\"\"\n    A struct that keeps information about the test.\n\n    It is received by formatters and contains the following fields:\n\n      * `:name` - the test name\n      * `:module` - the test module\n      * `:state` - the finished test state (see `t:ExUnit.state/0`)\n      * `:time` - the duration in microseconds of the test's runtime\n      * `:tags` - the test tags\n      * `:logs` - the captured logs\n      * `:parameters` - the test parameters\n\n    \"\"\"\n    defstruct [:name, :case, :module, :state, time: 0, tags: %{}, logs: \"\", parameters: %{}]\n\n    # TODO: Remove the `:case` field on v2.0\n    @type t :: %__MODULE__{\n            name: atom,\n            case: module,\n            module: module,\n            state: ExUnit.state(),\n            time: non_neg_integer,\n            tags: map,\n            logs: String.t(),\n            parameters: map\n          }\n  end\n\n  defmodule TestModule do\n    @moduledoc \"\"\"\n    A struct that keeps information about the test module.\n\n    It is received by formatters and contains the following fields:\n\n      * `:file` - (since v1.11.0) the file of the test module\n\n      * `:name` - the test module name\n\n      * `:parameters` - (since v1.18.0) the test module parameters\n\n      * `:setup_all?` - (since v1.18.0) if the test module requires a setup all\n\n      * `:state` - the test error state (see `t:ExUnit.state/0`)\n\n      * `:tags` - all tags in this module\n\n      * `:tests` - all tests in this module\n\n    \"\"\"\n    defstruct [:file, :name, :setup_all?, :state, parameters: %{}, tags: %{}, tests: []]\n\n    @type t :: %__MODULE__{\n            file: binary(),\n            name: module,\n            parameters: map(),\n            setup_all?: boolean(),\n            state: ExUnit.state(),\n            tags: map,\n            tests: [ExUnit.Test.t()]\n          }\n  end\n\n  defmodule TestCase do\n    # TODO: Remove this module on v2.0 (it has been replaced by TestModule)\n    @moduledoc false\n    defstruct [:name, :state, tests: []]\n\n    @type t :: %__MODULE__{name: module, state: ExUnit.state(), tests: [ExUnit.Test.t()]}\n  end\n\n  defmodule TimeoutError do\n    @moduledoc \"\"\"\n    Exception raised when a test times out.\n    \"\"\"\n\n    @typedoc since: \"1.16.0\"\n    @type t :: %__MODULE__{\n            timeout: non_neg_integer,\n            type: String.t()\n          }\n\n    defexception [:timeout, :type]\n\n    @impl true\n    def message(%{timeout: timeout, type: type}) do\n      \"\"\"\n      #{type} timed out after #{timeout}ms. You can change the timeout:\n\n        1. per test by setting \"@tag timeout: x\" (accepts :infinity)\n        2. per test module by setting \"@moduletag timeout: x\" (accepts :infinity)\n        3. globally via \"ExUnit.start(timeout: x)\" configuration\n        4. by running \"mix test --timeout x\" which sets timeout\n        5. or by running \"mix test --trace\" which sets timeout to infinity\n           (useful when using IEx.pry/0)\n\n      where \"x\" is the timeout given as integer in milliseconds (defaults to 60_000).\n      \"\"\"\n    end\n  end\n\n  use Application\n\n  @doc false\n  def start(_type, []) do\n    children = [\n      ExUnit.Server,\n      ExUnit.CaptureServer\n    ]\n\n    opts = [strategy: :one_for_one, name: ExUnit.Supervisor]\n    Supervisor.start_link(children, opts)\n  end\n\n  @doc \"\"\"\n  Starts ExUnit and automatically runs tests right before the\n  VM terminates.\n\n  It accepts a set of `options` to configure `ExUnit`\n  (the same ones accepted by `configure/1`).\n\n  If you want to run tests manually, you can set the `:autorun` option\n  to `false` and use `run/0` to run tests.\n  \"\"\"\n  @spec start(configure_opts()) :: :ok\n  def start(options \\\\ []) do\n    {:ok, _} = Application.ensure_all_started(:ex_unit)\n\n    configure(options)\n\n    if Application.fetch_env!(:ex_unit, :autorun) do\n      Application.put_env(:ex_unit, :autorun, false)\n\n      System.at_exit(fn\n        0 ->\n          time = ExUnit.Server.modules_loaded(false)\n          seed = Application.get_env(:ex_unit, :seed)\n          options = persist_defaults(configuration())\n          %{failures: failures} = maybe_repeated_run(options, seed, time)\n\n          if failures > 0 do\n            System.at_exit(fn _ -> exit({:shutdown, Keyword.fetch!(options, :exit_status)}) end)\n          end\n\n        _ ->\n          :ok\n      end)\n    else\n      :ok\n    end\n  end\n\n  @doc \"\"\"\n  Configures ExUnit.\n\n  ## Options\n\n  ExUnit supports the following options:\n\n    * `:assert_receive_timeout` - the timeout to be used on `assert_receive`\n      calls in milliseconds, defaults to `100`;\n\n    * `:autorun` - if ExUnit should run by default on exit. Defaults to `true`;\n\n    * `:capture_log` - if ExUnit should default to keeping track of log messages\n      and print them on test failure. Can be overridden for individual tests via\n      `@tag capture_log: false`. This can also be configured to a specific level\n      with `capture_log: [level: LEVEL]`, to capture all logs but only keep those\n      above `LEVEL`. Note that `on_exit` and `setup_all` callbacks may still log,\n      as they run outside of the testing process. To silent those, you can use\n      `ExUnit.CaptureLog.capture_log/2` or consider disabling logging altogether.\n\n    * `:colors` - a keyword list of color options to be used by some formatters:\n      * `:enabled` - boolean option to enable colors, defaults to `IO.ANSI.enabled?/0`;\n\n      * `:success` - success message (defaults to `:green`)\n      * `:invalid` - invalid test message (defaults to `:yellow`)\n      * `:skipped` - skipped test message (defaults to `:yellow`)\n      * `:failure` - failed test message (defaults to `:red`)\n      * `:error_info` - display of actual error (defaults to `:red`)\n      * `:extra_info` - additional information (defaults to `:cyan`)\n      * `:location_info` - filename and tags (defaults to `[:bright, :black]`)\n      * `:diff_insert` - color of the insertions on diffs, defaults to `:green`;\n      * `:diff_insert_whitespace` - color of the whitespace insertions on diffs,\n        defaults to `IO.ANSI.color_background(2, 0, 0)`;\n      * `:diff_delete` - color of the deletions on diffs, defaults to `:red`;\n      * `:diff_delete_whitespace` - color of the whitespace deletions on diffs,\n        defaults to `IO.ANSI.color_background(0, 2, 0)`;\n\n    * `:exclude` - specifies which tests are run by skipping tests that match the\n      filter. For more information, see the \"Tags\" and \"Filters\" sections in the\n      documentation for `ExUnit.Case`;\n\n    * `:exit_status` - specifies an alternate exit status to use when the test\n      suite fails. Defaults to `2`;\n\n    * `:failures_manifest_path` - specifies a path to the file used to store failures\n      between runs;\n\n    * `:formatters` - the formatters that will print results,\n      defaults to `[ExUnit.CLIFormatter]`;\n\n    * `:include` - specifies which tests are run by skipping tests that do not\n      match the filter. Keep in mind that all tests are included by default, so unless they are\n      excluded first, the `:include` option has no effect. To only run the tests\n      that match the `:include` filter, exclude the `:test` tag first.\n      For more information, see the \"Tags\" and \"Filters\" sections in the\n      documentation for `ExUnit.Case`;\n\n    * `:max_cases` - maximum number of tests to run in parallel. Only tests from\n      different modules run in parallel. It defaults to `System.schedulers_online * 2`\n      to optimize both CPU-bound and IO-bound tests;\n\n    * `:max_failures` - the suite stops evaluating tests when this number of test failures\n      is reached. All tests within a module that fail when using the\n      [`setup_all/1,2`](`ExUnit.Callbacks.setup_all/1`) callbacks\n      are counted as failures. Defaults to `:infinity`;\n\n    * `:only_test_ids` - a list of `{module_name, test_name}` tuples that limits\n      what tests get run. This is typically used by Mix to filter which tests\n      should run;\n\n    * `:rand_algorithm` - algorithm to be used when generating the test seed.\n      Available algorithms can be found in Erlang's\n      [`:rand`](`:rand`) documentation (see\n      [`:rand.builting_arg/0`](https://www.erlang.org/doc/apps/stdlib/rand.html#t:builtin_alg/0)).\n      Available since v1.16.0. Before v1.16.0, the algorithm was hard-coded to\n      `:exs1024`. On Elixir v1.16.0 and after, the default changed to `:exsss`;\n\n    * `:refute_receive_timeout` - the timeout to be used on `refute_receive`\n      calls in milliseconds, defaults to `100`;\n\n    * `:seed` - an integer seed value to randomize the test suite. This seed\n      is also mixed with the test module and name to create a new unique seed\n      on every test, which is automatically fed into the [`:rand`](`:rand`) module.\n      This provides randomness between tests, but predictable and reproducible\n      results. A `:seed` of `0` will disable randomization and the tests in each\n      file will always run in the order that they were defined in;\n\n    * `:slowest` - prints timing information for the N slowest tests. Running\n      ExUnit with slow test reporting automatically runs in `trace` mode. It\n      is disabled by default;\n\n    * `:slowest_modules` - prints timing information for the N slowest test modules. Running\n      ExUnit with slow test reporting automatically runs in `trace` mode. It\n      is disabled by default;\n\n    * `:stacktrace_depth` - configures the stacktrace depth to be used\n      on formatting and reporters, defaults to `20`;\n\n    * `:timeout` - sets the timeout for the tests in milliseconds, defaults to `60_000`;\n\n    * `:trace` - sets ExUnit into trace mode, this sets `:max_cases` to `1` and\n      prints each test case and test while running. Note that in trace mode test\n      timeouts will be ignored as timeout is set to `:infinity`;\n\n    * `:test_location_relative_path` - the test location is the file:line information\n      printed by tests as a shortcut to run a given test. When this value is set,\n      the value is used as a prefix for the test itself. This is typically used by\n      Mix to properly set-up umbrella projects;\n\n  Any arbitrary configuration can also be passed to `configure/1` or `start/1`,\n  and these options can then be used in places such as custom formatters. These\n  other options will be ignored by ExUnit itself.\n  \"\"\"\n  @spec configure(configure_opts()) :: :ok\n  def configure(options) when is_list(options) do\n    Enum.each(options, fn {k, v} ->\n      Application.put_env(:ex_unit, k, v)\n    end)\n  end\n\n  @doc \"\"\"\n  Returns ExUnit configuration.\n\n  For the available configuration options, see `configure/1`.\n  \"\"\"\n  @spec configuration() :: Keyword.t()\n  def configuration do\n    Application.get_all_env(:ex_unit)\n    |> put_seed()\n    |> put_slowest()\n    |> put_max_cases()\n  end\n\n  @doc \"\"\"\n  Returns the pluralization for `word`.\n\n  If one is not registered, returns the word appended with an \"s\".\n  \"\"\"\n  @spec plural_rule(binary) :: binary\n  def plural_rule(word) when is_binary(word) do\n    Application.get_env(:ex_unit, :plural_rules, %{})\n    |> Map.get(word, \"#{word}s\")\n  end\n\n  @doc \"\"\"\n  Registers a `pluralization` for `word`.\n\n  If one is already registered, it is replaced.\n  \"\"\"\n  @spec plural_rule(binary, binary) :: :ok\n  def plural_rule(word, pluralization) when is_binary(word) and is_binary(pluralization) do\n    plural_rules =\n      Application.get_env(:ex_unit, :plural_rules, %{})\n      |> Map.put(word, pluralization)\n\n    configure(plural_rules: plural_rules)\n  end\n\n  @doc \"\"\"\n  Runs the tests. It is invoked automatically\n  if ExUnit is started via `start/1`.\n\n  From Elixir v1.14, it accepts an optional list of modules to run\n  as part of the suite. This is often used to rerun modules already\n  loaded in memory.\n\n  Returns a map containing the total number of tests, the number\n  of failures, the number of excluded tests and the number of skipped tests.\n  \"\"\"\n  @spec run([module()]) :: suite_result()\n  def run(additional_modules \\\\ []) do\n    for module <- additional_modules do\n      if Code.ensure_loaded?(module) and function_exported?(module, :__ex_unit__, 1) do\n        ExUnit.Server.add_module(module, module.__ex_unit__(:config))\n      else\n        raise(ArgumentError, \"#{inspect(module)} is not a ExUnit.Case module\")\n      end\n    end\n\n    _ = ExUnit.Server.modules_loaded(additional_modules != [])\n    seed = Application.get_env(:ex_unit, :seed)\n    options = persist_defaults(configuration())\n    maybe_repeated_run(options, seed, nil)\n  end\n\n  @doc \"\"\"\n  Starts tests asynchronously while test cases are still loading.\n\n  It returns a task that must be given to `await_run/0` when a result\n  is desired.\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec async_run() :: Task.t()\n  def async_run() do\n    seed = Application.get_env(:ex_unit, :seed)\n    options = persist_defaults(configuration())\n\n    Task.async(fn ->\n      maybe_repeated_run(options, seed, nil)\n    end)\n  end\n\n  @doc \"\"\"\n  Awaits for a test suite that has been started with `async_run/0`.\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec await_run(Task.t()) :: suite_result()\n  def await_run(task) do\n    ExUnit.Server.modules_loaded(false)\n    Task.await(task, :infinity)\n  end\n\n  @doc \"\"\"\n  Sets a callback to be executed after the completion of a test suite.\n\n  Callbacks set with `after_suite/1` must accept a single argument, which is a\n  map containing the results of the test suite's execution.\n\n  If `after_suite/1` is called multiple times, the callbacks will be called in\n  reverse order. In other words, the last callback set will be the first to be\n  called.\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec after_suite((suite_result() -> any)) :: :ok\n  def after_suite(function) when is_function(function) do\n    current_callbacks = Application.fetch_env!(:ex_unit, :after_suite)\n    configure(after_suite: [function | current_callbacks])\n  end\n\n  @doc \"\"\"\n  Fetches the test supervisor for the current test.\n\n  Returns `{:ok, supervisor_pid}` or `:error` if not called from the test process.\n\n  This is the same supervisor as used by `ExUnit.Callbacks.start_supervised/2`\n  and similar, see `ExUnit.Callbacks` module documentation for more information.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec fetch_test_supervisor() :: {:ok, pid()} | :error\n  def fetch_test_supervisor() do\n    case ExUnit.OnExitHandler.get_supervisor(self()) do\n      {:ok, nil} ->\n        {:ok, sup} = ExUnit.OnExitHandler.Supervisor.start_link([])\n        ExUnit.OnExitHandler.put_supervisor(self(), sup)\n        {:ok, sup}\n\n      {:ok, _} = ok ->\n        ok\n\n      :error ->\n        :error\n    end\n  end\n\n  # Persists default values in application\n  # environment before the test suite starts.\n  defp persist_defaults(config) do\n    config |> Keyword.take([:max_cases, :seed, :trace]) |> configure()\n    config\n  end\n\n  defp maybe_repeated_run(options, seed, load_us) do\n    repeat = Keyword.fetch!(options, :repeat_until_failure)\n    maybe_repeated_run(options, seed, load_us, repeat)\n  end\n\n  defp maybe_repeated_run(options, seed, load_us, repeat) do\n    case ExUnit.Runner.run(options, load_us) do\n      {%{failures: 0}, {async_modules, sync_modules}}\n      when repeat > 0 and (sync_modules != [] or async_modules != []) ->\n        ExUnit.Server.restore_modules(async_modules, sync_modules)\n\n        # Clear the seed if it was generated\n        if seed == nil do\n          Application.delete_env(:ex_unit, :seed)\n        end\n\n        # Re-run configuration\n        options = persist_defaults(configuration())\n        maybe_repeated_run(options, seed, load_us, repeat - 1)\n\n      {stats, _} ->\n        stats\n    end\n  end\n\n  defp put_seed(opts) do\n    Keyword.put_new_lazy(opts, :seed, fn ->\n      # We're using `rem System.system_time()` here\n      # instead of directly using :os.timestamp or using the\n      # :microsecond argument because the VM on Windows has odd\n      # precision. Calling with :microsecond will give us a multiple\n      # of 1000. Calling without it gives actual microsecond precision.\n      System.system_time()\n      |> System.convert_time_unit(:native, :microsecond)\n      |> rem(1_000_000)\n    end)\n  end\n\n  defp put_max_cases(opts) do\n    Keyword.put(opts, :max_cases, max_cases(opts))\n  end\n\n  defp put_slowest(opts) do\n    if opts[:slowest] > 0 or opts[:slowest_modules] > 0 do\n      Keyword.put(opts, :trace, true)\n    else\n      opts\n    end\n  end\n\n  defp max_cases(opts) do\n    cond do\n      opts[:trace] -> 1\n      max = opts[:max_cases] -> max\n      true -> System.schedulers_online() * 2\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/mix.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule ExUnit.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :ex_unit,\n      version: System.version(),\n      build_per_environment: false\n    ]\n  end\n\n  def application do\n    [\n      registered: [ExUnit.CaptureServer, ExUnit.OnExitHandler, ExUnit.Server, ExUnit.Supervisor],\n      mod: {ExUnit, []},\n      env: [\n        # Calculated on demand\n        # max_cases: System.schedulers_online * 2,\n        # seed: rand(),\n\n        assert_receive_timeout: 100,\n        autorun: true,\n        capture_log: false,\n        colors: [],\n        exclude: [],\n        exit_status: 2,\n        formatters: [ExUnit.CLIFormatter],\n        include: [],\n        max_failures: :infinity,\n        rand_algorithm: :exsss,\n        refute_receive_timeout: 100,\n        slowest: 0,\n        slowest_modules: 0,\n        stacktrace_depth: 20,\n        timeout: 60_000,\n        trace: false,\n        after_suite: [],\n        repeat_until_failure: 0,\n        dry_run: false\n      ]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/assertions_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.AssertionsTest.Value do\n  def tuple, do: {2, 1}\n  def falsy, do: nil\n  def truthy, do: :truthy\n  def binary, do: <<5, \"Frank the Walrus\">>\nend\n\ndefmodule ExUnit.AssertionsTest.BrokenError do\n  defexception [:message]\n\n  @impl true\n  def message(_) do\n    raise \"error\"\n  end\nend\n\ndefmodule ExUnit.AssertionsTest.OverrideOperator do\n  import Kernel, except: [{:=~, 2}]\n\n  defmacro __using__(_) do\n    quote do\n      import Kernel, except: [{:=~, 2}]\n      import ExUnit.AssertionsTest.OverrideOperator\n    end\n  end\n\n  defmacro left =~ right do\n    quote do\n      match?(unquote(left), unquote(right))\n    end\n  end\nend\n\nalias ExUnit.AssertionsTest.{BrokenError, Value}\n\ndefmodule ExUnit.AssertionsTest do\n  use ExUnit.Case, async: true\n\n  defmacro sigil_l({:<<>>, _, [string]}, _), do: Code.string_to_quoted!(string, [])\n  defmacro argless_macro(), do: raise(\"should not be invoked\")\n\n  defmacrop assert_ok(arg) do\n    quote do\n      assert {:ok, val} = ok(unquote(arg))\n    end\n  end\n\n  defmacrop assert_ok_with_pin_from_quoted_var(arg) do\n    quote do\n      kind = :ok\n      assert {^kind, value} = unquote(arg)\n    end\n  end\n\n  require Record\n  Record.defrecordp(:vec, x: 0, y: 0, z: 0)\n\n  defguardp is_zero(zero) when zero == 0\n\n  test \"direct raise\" do\n    try do\n      raise ExUnit.AssertionError, \"This is a test\"\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"This is a test\" = error.message\n    end\n  end\n\n  test \"assert inside macro\" do\n    assert_ok(42)\n  end\n\n  test \"assert inside macro with pins\" do\n    try do\n      assert_ok_with_pin_from_quoted_var({:error, :oops})\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (=) failed\" = error.message\n    end\n  end\n\n  test \"assert with truthy value\" do\n    :truthy = assert Value.truthy()\n  end\n\n  test \"assert with message when value is falsy\" do\n    try do\n      assert Value.falsy(), \"This should be truthy\"\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"This should be truthy\" = error.message\n    end\n  end\n\n  test \"assert when value evaluates to falsy\" do\n    try do\n      assert Value.falsy()\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"assert Value.falsy()\" = error.expr |> Macro.to_string()\n        \"Expected truthy, got nil\" = error.message\n    end\n  end\n\n  test \"assert arguments in special form\" do\n    true =\n      assert (case :ok do\n                :ok -> true\n              end)\n  end\n\n  test \"assert arguments semantics on function call\" do\n    x = 1\n    true = assert not_equal(x = 2, x)\n    2 = x\n  end\n\n  test \"assert arguments are not kept for operators\" do\n    try do\n      assert !Process.get(:unused, Value.truthy())\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        false = is_list(error.args)\n    end\n  end\n\n  test \"assert with equality\" do\n    try do\n      assert 1 + 1 == 1\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        1 = error.right\n        2 = error.left\n        \"assert 1 + 1 == 1\" = error.expr |> Macro.to_string()\n    end\n  end\n\n  test \"assert with equality in reverse\" do\n    try do\n      assert 1 == 1 + 1\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        1 = error.left\n        2 = error.right\n        \"assert 1 == 1 + 1\" = error.expr |> Macro.to_string()\n    end\n  end\n\n  test \"assert exposes nested macro variables in matches\" do\n    assert ~l(a) = 1\n    assert a == 1\n\n    assert {~l(b), ~l(c)} = {2, 3}\n    assert b == 2\n    assert c == 3\n  end\n\n  test \"assert does not expand variables\" do\n    assert argless_macro = 1\n    assert argless_macro == 1\n  end\n\n  defmodule OperatorOverrideTest do\n    use ExUnit.Case\n    use ExUnit.AssertionsTest.OverrideOperator\n\n    test \"assert when operator be overrode\" do\n      assert [_a, _b] =~ [1, 2]\n    end\n  end\n\n  test \"refute when value is falsy\" do\n    false = refute false\n    nil = refute Value.falsy()\n  end\n\n  test \"refute when value evaluates to truthy\" do\n    try do\n      refute Value.truthy()\n      raise \"refute was supposed to fail\"\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"refute Value.truthy()\" = Macro.to_string(error.expr)\n        \"Expected false or nil, got :truthy\" = error.message\n    end\n  end\n\n  test \"assert match when equal\" do\n    {2, 1} = assert {2, 1} = Value.tuple()\n\n    # With dup vars\n    assert {tuple, tuple} = {Value.tuple(), Value.tuple()}\n    assert <<name_size::size(8), _::binary-size(name_size), \" the \", _::binary>> = Value.binary()\n  end\n\n  test \"assert match with unused var\" do\n    assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n             Code.eval_string(\"\"\"\n             defmodule ExSample do\n               import ExUnit.Assertions\n\n               def run do\n                 {2, 1} = assert {2, var} = ExUnit.AssertionsTest.Value.tuple()\n               end\n             end\n             \"\"\")\n           end) =~ \"variable \\\"var\\\" is unused\"\n  after\n    :code.purge(ExSample)\n    :code.delete(ExSample)\n  end\n\n  test \"assert match with quote on left-side\" do\n    assert quote(do: x in Alias) = quote(do: x in Alias)\n  end\n\n  defmacro quote_like(ast), do: Macro.escape(ast, prune_metadata: true)\n\n  test \"assert match with quote-like on left-side\" do\n    assert quote_like(x in Alias) = quote_like(x in Alias)\n  end\n\n  test \"assert match expands argument in match context\" do\n    {x, y, z} = {1, 2, 3}\n    assert vec(x: ^x, y: ^y) = vec(x: x, y: y, z: z)\n  end\n\n  @test_mod_attribute %{key: :value}\n  test \"assert match with module attribute\" do\n    try do\n      assert {@test_mod_attribute, 1} = Value.tuple()\n    rescue\n      error in [ExUnit.AssertionError] ->\n        assert \"{%{key: :value}, 1}\" == Macro.to_string(error.left)\n    end\n  end\n\n  test \"assert parallel match\" do\n    assert %URI{} = uri = apply(URI, :parse, [\"/foo\"])\n    # This should not warn\n    assert %URI{uri | path: \"/bar\"}.path == \"/bar\"\n\n    assert uri = %URI{} = apply(URI, :parse, [\"/foo\"])\n    # This should not warn\n    assert %URI{uri | path: \"/bar\"}.path == \"/bar\"\n  end\n\n  test \"assert match with pinned variable\" do\n    a = 1\n    {2, 1} = assert {2, ^a} = Value.tuple()\n\n    try do\n      assert {^a, 1} = Value.tuple()\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (=) failed\\n\" <> \"The following variables were pinned:\\n\" <> \"  a = 1\" =\n          error.message\n\n        \"assert {^a, 1} = Value.tuple()\" = Macro.to_string(error.expr)\n    end\n  end\n\n  test \"assert match with pinned variable from another context\" do\n    var!(a, Elixir) = 1\n    {2, 1} = assert {2, ^var!(a, Elixir)} = Value.tuple()\n\n    try do\n      assert {^var!(a, Elixir), 1} = Value.tuple()\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (=) failed\" = error.message\n        \"assert {^var!(a, Elixir), 1} = Value.tuple()\" = Macro.to_string(error.expr)\n    end\n  end\n\n  test \"assert match with `when` in the pattern fails\" do\n    message = \"\"\"\n    invalid pattern in assert\\/1:\n\n      x when is_map(x)\n\n    To assert with guards, use match?/2:\n\n      assert match?(x when is_map(x), %{})\n    \"\"\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_string(\"\"\"\n      defmodule AssertGuard do\n        import ExUnit.Assertions\n\n        def run do\n          assert (x when is_map(x)) = %{}\n        end\n      end\n      \"\"\")\n    end\n  after\n    :code.purge(AssertGuard)\n    :code.delete(AssertGuard)\n  end\n\n  test \"assert match with __ENV__ in the pattern\" do\n    message =\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        assert_raise CompileError, fn ->\n          Code.eval_string(\"\"\"\n          defmodule EnvMatch do\n            import ExUnit.Assertions\n\n            def run do\n              assert __ENV__ = %{}\n            end\n          end\n          \"\"\")\n        end\n      end)\n\n    assert message =~ \"invalid pattern in match, __ENV__ is not allowed in matches\"\n  after\n    :code.purge(EnvMatch)\n    :code.delete(EnvMatch)\n  end\n\n  test \"assert match?\" do\n    true = assert match?({2, 1}, Value.tuple())\n\n    try do\n      assert match?({:ok, _}, Process.get(:unused, :ok))\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (match?) failed\" = error.message\n        \"assert match?({:ok, _}, Process.get(:unused, :ok))\" = Macro.to_string(error.expr)\n        \":ok\" = Macro.to_string(error.right)\n    end\n  end\n\n  test \"assert match? with guards\" do\n    true = assert match?(tuple when is_tuple(tuple), Value.tuple())\n\n    try do\n      assert match?(tuple when not is_tuple(tuple), error(true))\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (match?) failed\" = error.message\n\n        \"assert match?(tuple when not is_tuple(tuple), error(true))\" = Macro.to_string(error.expr)\n\n        \"{:error, true}\" = Macro.to_string(error.right)\n    end\n  end\n\n  test \"refute match?\" do\n    false = refute match?({1, 1}, Value.tuple())\n\n    try do\n      refute match?({:error, _}, error(true))\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (match?) succeeded, but should have failed\" = error.message\n        \"refute match?({:error, _}, error(true))\" = Macro.to_string(error.expr)\n        \"{:error, true}\" = Macro.to_string(error.right)\n    end\n  end\n\n  test \"assert match? with pinned variable\" do\n    a = 1\n\n    try do\n      assert(match?({^a, 1}, Value.tuple()))\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (match?) failed\\nThe following variables were pinned:\\n  a = 1\" = error.message\n\n        \"assert match?({^a, 1}, Value.tuple())\" = Macro.to_string(error.expr)\n    end\n  end\n\n  test \"refute match? with pinned variable\" do\n    a = 2\n\n    try do\n      refute(match?({^a, 1}, Value.tuple()))\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"\"\"\n        match (match?) succeeded, but should have failed\n        The following variables were pinned:\n          a = 2\\\n        \"\"\" = error.message\n\n        \"refute match?({^a, 1}, Value.tuple())\" = Macro.to_string(error.expr)\n    end\n  end\n\n  test \"assert receive waits\" do\n    parent = self()\n    spawn(fn -> send(parent, :hello) end)\n    :hello = assert_receive :hello\n  end\n\n  @string \"hello\"\n\n  test \"assert receive with interpolated compile-time string\" do\n    parent = self()\n    spawn(fn -> send(parent, \"string: hello\") end)\n    \"string: #{@string}\" = assert_receive \"string: #{@string}\"\n  end\n\n  test \"assert receive accepts custom failure message\" do\n    send(self(), :hello)\n    assert_receive message, 0, \"failure message\"\n    :hello = message\n  end\n\n  test \"assert receive with message in mailbox after timeout, but before reading mailbox tells user to increase timeout\" do\n    parent = self()\n    # This is testing a race condition, so it's not\n    # guaranteed this works under all loads of the system\n    timeout = 100\n    spawn(fn -> Process.send_after(parent, :hello, timeout) end)\n\n    try do\n      assert_receive :hello, timeout\n    rescue\n      error in [ExUnit.AssertionError] ->\n        true =\n          error.message =~ \"Found message matching :hello after 100ms\" or\n            error.message =~ \"no matching message after 100ms\"\n    end\n  end\n\n  test \"assert_receive exposes nested macro variables\" do\n    send(self(), {:hello})\n    assert_receive {~l(a)}, 0, \"failure message\"\n\n    assert a == :hello\n  end\n\n  test \"assert_receive raises on invalid timeout\" do\n    timeout = ok(1)\n\n    try do\n      assert_receive {~l(_a)}, timeout\n    rescue\n      error in [ArgumentError] ->\n        \"timeout must be a non-negative integer, got: {:ok, 1}\" = error.message\n    end\n  end\n\n  test \"assert_receive expands argument in match context\" do\n    {x, y, z} = {1, 2, 3}\n    send(self(), vec(x: x, y: y, z: z))\n    assert_receive vec(x: ^x, y: ^y)\n  end\n\n  test \"assert_receive expands argument in guard context\" do\n    send(self(), {:ok, 0, :other})\n    assert_receive {:ok, val, atom} when is_zero(val) and is_atom(atom)\n  end\n\n  test \"assert received does not wait\" do\n    send(self(), :hello)\n    :hello = assert_received :hello\n  end\n\n  @received :hello\n\n  test \"assert received with module attribute\" do\n    send(self(), :hello)\n    :hello = assert_received @received\n  end\n\n  test \"assert received with pinned variable\" do\n    status = :valid\n    send(self(), {:status, :invalid})\n\n    try do\n      assert_received {:status, ^status}\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"\"\"\n        Assertion failed, no matching message after 0ms\n        The following variables were pinned:\n          status = :valid\n        Showing 1 of 1 message in the mailbox\\\n        \"\"\" = error.message\n\n        \"assert_received {:status, ^status}\" = Macro.to_string(error.expr)\n        \"{:status, ^status}\" = Macro.to_string(error.left)\n    end\n  end\n\n  test \"assert received with multiple identical pinned variables\" do\n    status = :valid\n    send(self(), {:status, :invalid, :invalid})\n\n    try do\n      assert_received {:status, ^status, ^status}\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"\"\"\n        Assertion failed, no matching message after 0ms\n        The following variables were pinned:\n          status = :valid\n        Showing 1 of 1 message in the mailbox\\\n        \"\"\" = error.message\n\n        \"assert_received {:status, ^status, ^status}\" = Macro.to_string(error.expr)\n        \"{:status, ^status, ^status}\" = Macro.to_string(error.left)\n        \"\\n\\nAssertion failed\" <> _ = Exception.message(error)\n    end\n  end\n\n  test \"assert received with multiple unique pinned variables\" do\n    status = :valid\n    other_status = :invalid\n    send(self(), {:status, :invalid, :invalid})\n\n    try do\n      assert_received {:status, ^status, ^other_status}\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"\"\"\n        Assertion failed, no matching message after 0ms\n        The following variables were pinned:\n          other_status = :invalid\n          status = :valid\n        Showing 1 of 1 message in the mailbox\\\n        \"\"\" = error.message\n\n        \"assert_received {:status, ^status, ^other_status}\" = Macro.to_string(error.expr)\n        \"{:status, ^status, ^other_status}\" = Macro.to_string(error.left)\n    end\n  end\n\n  test \"assert received when empty mailbox\" do\n    try do\n      assert_received :hello\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"Assertion failed, no matching message after 0ms\\nThe process mailbox is empty.\" =\n          error.message\n\n        \"assert_received :hello\" = Macro.to_string(error.expr)\n    end\n  end\n\n  test \"assert received when different message\" do\n    send(self(), {:message, :not_expected, :at_all})\n\n    try do\n      assert_received :hello\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"\"\"\n        Assertion failed, no matching message after 0ms\n        Showing 1 of 1 message in the mailbox\\\n        \"\"\" = error.message\n\n        \"assert_received :hello\" = Macro.to_string(error.expr)\n        \":hello\" = Macro.to_string(error.left)\n    end\n  end\n\n  test \"assert received when different message having more than 10 on mailbox\" do\n    for i <- 1..11, do: send(self(), {:message, i})\n\n    try do\n      assert_received x when x == :hello\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"\"\"\n        Assertion failed, no matching message after 0ms\n        Showing 10 of 11 messages in the mailbox\\\n        \"\"\" = error.message\n\n        \"assert_received x when x == :hello\" = Macro.to_string(error.expr)\n        \"x when x == :hello\" = Macro.to_string(error.left)\n    end\n  end\n\n  test \"assert received binds variables\" do\n    send(self(), {:hello, :world})\n    assert_received {:hello, world}\n    :world = world\n  end\n\n  test \"assert received does not leak external variables used in guards\" do\n    send(self(), {:hello, :world})\n    guard_world = :world\n    assert_received {:hello, world} when world == guard_world\n    :world = world\n  end\n\n  test \"refute received does not wait\" do\n    false = refute_received :hello\n  end\n\n  test \"refute receive waits\" do\n    false = refute_receive :hello, 100\n  end\n\n  test \"refute received when equal\" do\n    send(self(), :hello)\n\n    try do\n      refute_received :hello\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"Unexpectedly received message :hello (which matched :hello)\" = error.message\n    end\n  end\n\n  test \"assert in when member\" do\n    true = assert ~c\"foo\" in [~c\"foo\", ~c\"bar\"]\n  end\n\n  test \"assert in when is not member\" do\n    try do\n      assert ~c\"foo\" in ~c\"bar\"\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        ~c\"foo\" = error.left\n        ~c\"bar\" = error.right\n        ~S(assert ~c\"foo\" in ~c\"bar\") = Macro.to_string(error.expr)\n    end\n  end\n\n  test \"refute in when is not member\" do\n    false = refute ~c\"baz\" in [~c\"foo\", ~c\"bar\"]\n  end\n\n  test \"refute in when is member\" do\n    try do\n      refute ~c\"foo\" in [~c\"foo\", ~c\"bar\"]\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        ~c\"foo\" = error.left\n        [~c\"foo\", ~c\"bar\"] = error.right\n        ~S(refute ~c\"foo\" in [~c\"foo\", ~c\"bar\"]) = Macro.to_string(error.expr)\n    end\n  end\n\n  test \"assert match\" do\n    {:ok, true} = assert {:ok, _} = ok(true)\n  end\n\n  test \"assert match with bitstrings\" do\n    \"foobar\" = assert \"foo\" <> bar = \"foobar\"\n    \"bar\" = bar\n  end\n\n  test \"assert match when no match\" do\n    try do\n      assert {:ok, _} = error(true)\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (=) failed\" = error.message\n        \"assert {:ok, _} = error(true)\" = Macro.to_string(error.expr)\n        \"{:error, true}\" = Macro.to_string(error.right)\n    end\n  end\n\n  test \"assert match when falsy but not match\" do\n    try do\n      assert {:ok, _x} = nil\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"match (=) failed\" = error.message\n        \"assert {:ok, _x} = nil\" = Macro.to_string(error.expr)\n        \"nil\" = Macro.to_string(error.right)\n    end\n  end\n\n  test \"assert match when falsy\" do\n    try do\n      assert _x = nil\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"Expected truthy, got nil\" = error.message\n        \"assert _x = nil\" = Macro.to_string(error.expr)\n    end\n  end\n\n  test \"refute match when no match\" do\n    try do\n      refute _ = ok(true)\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"refute _ = ok(true)\" = Macro.to_string(error.expr)\n        \"Expected false or nil, got {:ok, true}\" = error.message\n    end\n  end\n\n  test \"assert regex match\" do\n    true = assert \"foo\" =~ ~r/o/\n  end\n\n  test \"assert regex match when no match\" do\n    try do\n      assert \"foo\" =~ ~r/a/\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"foo\" = error.left\n        %Regex{} = error.right\n    end\n  end\n\n  test \"refute regex match\" do\n    false = refute \"foo\" =~ ~r/a/\n  end\n\n  test \"refute regex match when match\" do\n    try do\n      refute \"foo\" =~ ~r/o/\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"foo\" = error.left\n        %Regex{} = error.right\n    end\n  end\n\n  test \"assert raise with no error\" do\n    assert_raise ArgumentError, fn -> nil end\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Expected exception ArgumentError but nothing was raised\" = error.message\n  end\n\n  test \"assert raise with error\" do\n    error = assert_raise ArgumentError, fn -> raise ArgumentError, \"test error\" end\n    \"test error\" = error.message\n  end\n\n  @compile {:no_warn_undefined, Not.Defined}\n\n  test \"assert raise with some other error\" do\n    assert_raise ArgumentError, fn -> Not.Defined.function(1, 2, 3) end\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Expected exception ArgumentError but got UndefinedFunctionError \" <>\n        \"(function Not.Defined.function/3 is undefined (module Not.Defined is not available))\" =\n        error.message\n  end\n\n  test \"assert raise with some other error includes stacktrace from original error\" do\n    assert_raise ArgumentError, fn -> Not.Defined.function(1, 2, 3) end\n    flunk(\"This should never be tested\")\n  rescue\n    ExUnit.AssertionError ->\n      [{Not.Defined, :function, [1, 2, 3], _} | _] = __STACKTRACE__\n  end\n\n  test \"assert raise with Erlang error\" do\n    assert_raise SyntaxError, fn ->\n      List.flatten(1)\n    end\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Expected exception SyntaxError but got FunctionClauseError (no function clause matching in :lists.flatten/1)\" =\n        error.message\n  end\n\n  test \"assert raise comparing messages (for equality)\" do\n    assert_raise RuntimeError, \"foo\", fn ->\n      raise RuntimeError, \"bar\"\n    end\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"\"\"\n      Wrong message for RuntimeError\n      expected:\n        \"foo\"\n      actual:\n        \"bar\"\\\n      \"\"\" = error.message\n  end\n\n  test \"assert raise comparing messages (with a regex)\" do\n    assert_raise RuntimeError, ~r/ba[zk]/, fn ->\n      raise RuntimeError, \"bar\"\n    end\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"\"\"\n      Wrong message for RuntimeError\n      expected:\n        ~r/ba[zk]/\n      actual:\n        \"bar\"\\\n      \"\"\" = error.message\n  end\n\n  test \"assert raise with an exception with bad message/1 implementation\" do\n    assert_raise BrokenError, fn ->\n      raise BrokenError\n    end\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"\"\"\n      Got exception ExUnit.AssertionsTest.BrokenError but it failed to produce a message with:\n\n      ** (RuntimeError) error\n      \"\"\" <> _ = error.message\n  end\n\n  test \"assert greater-than operator\" do\n    true = assert 2 > 1\n  end\n\n  test \"assert greater-than operator error\" do\n    assert 1 > 2\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      1 = error.left\n      2 = error.right\n      \"assert 1 > 2\" = Macro.to_string(error.expr)\n  end\n\n  test \"assert less or equal than operator\" do\n    true = assert 1 <= 2\n  end\n\n  test \"assert less or equal than operator error\" do\n    assert 2 <= 1\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"assert 2 <= 1\" = Macro.to_string(error.expr)\n      2 = error.left\n      1 = error.right\n  end\n\n  test \"assert operator with expressions\" do\n    greater = 5\n    true = assert 1 + 2 < greater\n  end\n\n  test \"assert operator with custom message\" do\n    assert 1 > 2, \"assertion\"\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"assertion\" = error.message\n  end\n\n  test \"assert operator with custom options\" do\n    assert 1 > 2, message: \"assertion\"\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"assertion\" = error.message\n  end\n\n  test \"assert operator with invalid options\" do\n    assert 1 > 2, message: 123\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ArgumentError] ->\n      \":message in ExUnit.Assertion must be a binary, got: 123\" = error.message\n  end\n\n  test \"assert lack of equality\" do\n    try do\n      assert \"one\" != \"one\"\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"Assertion with != failed, both sides are exactly equal\" = error.message\n        \"one\" = error.left\n    end\n\n    try do\n      assert 2 != 2.0\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"Assertion with != failed\" = error.message\n        2 = error.left\n        2.0 = error.right\n    end\n  end\n\n  test \"refute equality\" do\n    try do\n      refute \"one\" == \"one\"\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"Refute with == failed, both sides are exactly equal\" = error.message\n        \"one\" = error.left\n    end\n\n    try do\n      refute 2 == 2.0\n      flunk(\"This should never be tested\")\n    rescue\n      error in [ExUnit.AssertionError] ->\n        \"Refute with == failed\" = error.message\n        2 = error.left\n        2.0 = error.right\n    end\n  end\n\n  test \"assert in delta\" do\n    true = assert_in_delta(1.1, 1.2, 0.2)\n  end\n\n  test \"assert in delta raises when passing a negative delta\" do\n    assert_raise ArgumentError, fn ->\n      assert_in_delta(1.1, 1.2, -0.2)\n    end\n  end\n\n  test \"assert in delta works with equal values and a delta of zero\" do\n    assert_in_delta(10, 10, 0)\n  end\n\n  test \"assert in delta error\" do\n    assert_in_delta(10, 12, 1)\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Expected the difference between 10 and 12 (2) to be less than or equal to 1\" =\n        error.message\n  end\n\n  test \"assert in delta with message\" do\n    assert_in_delta(10, 12, 1, \"test message\")\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"test message\" = error.message\n  end\n\n  test \"refute in delta\" do\n    false = refute_in_delta(1.1, 1.5, 0.2)\n  end\n\n  test \"refute in delta error\" do\n    refute_in_delta(10, 11, 2)\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Expected the difference between 10 and 11 (1) to be more than 2\" = error.message\n  end\n\n  test \"refute in delta with message\" do\n    refute_in_delta(10, 11, 2, \"test message\")\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"test message (difference between 10 and 11 is less than 2)\" = error.message\n  end\n\n  test \"catch_throw with no throw\" do\n    catch_throw(1)\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Expected to catch throw, got nothing\" = error.message\n  end\n\n  test \"catch_error with no error\" do\n    catch_error(1)\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Expected to catch error, got nothing\" = error.message\n  end\n\n  test \"catch_exit with no exit\" do\n    catch_exit(1)\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Expected to catch exit, got nothing\" = error.message\n  end\n\n  test \"catch_throw with throw\" do\n    1 = catch_throw(throw(1))\n  end\n\n  test \"catch_exit with exit\" do\n    1 = catch_exit(exit(1))\n  end\n\n  test \"catch_error with error\" do\n    :function_clause = catch_error(List.flatten(1))\n  end\n\n  test \"flunk\" do\n    flunk()\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"Flunked!\" = error.message\n  end\n\n  test \"flunk with message\" do\n    flunk(\"This should raise an error\")\n    flunk(\"This should never be tested\")\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"This should raise an error\" = error.message\n  end\n\n  test \"AssertionError.message/1 is nicely formatted\" do\n    assert :a = :b\n  rescue\n    error in [ExUnit.AssertionError] ->\n      \"\"\"\n\n\n      match (=) failed\n      code:  assert :a = :b\n      left:  :a\n      right: :b\n      \"\"\" = Exception.message(error)\n  end\n\n  defp ok(val), do: Process.get(:unused, {:ok, val})\n  defp error(val), do: Process.get(:unused, {:error, val})\n  defp not_equal(left, right), do: left != right\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/callbacks_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.CallbacksTest do\n  use ExUnit.Case\n\n  import ExUnit.CaptureIO\n\n  def start_counter(_) do\n    [counter: []]\n  end\n\n  test \"callbacks run custom code with context\" do\n    defmodule CallbacksTest do\n      use ExUnit.Case\n\n      setup_all do\n        [context: :setup_all]\n      end\n\n      setup do\n        %{initial_setup: true}\n      end\n\n      setup context do\n        assert context[:initial_setup]\n        assert context[:context] == :setup_all\n        {:ok, [context: :setup]}\n      end\n\n      test \"callbacks\", context do\n        assert context[:context] == :setup\n      end\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Result: 1 passed\"\n  end\n\n  test \"named callbacks run custom code in order\" do\n    defmodule NamedCallbacksTest do\n      use ExUnit.Case\n\n      import ExUnit.CallbacksTest\n      setup_all :start_counter\n\n      setup :store_1\n      setup [:store_2, :store_3]\n\n      setup context do\n        [counter: [4 | context.counter]]\n      end\n\n      setup :store_5\n\n      test \"callbacks\", context do\n        assert context[:counter] == [5, 4, 3, 2, 1]\n      end\n\n      defp store(context, number), do: [counter: [number | context.counter]]\n      defp store_1(context), do: store(context, 1)\n      defp store_2(context), do: store(context, 2)\n      defp store_3(context), do: store(context, 3)\n      defp store_5(context), do: store(context, 5)\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Result: 1 passed\"\n  end\n\n  test \"named callbacks support {module, function} tuples\" do\n    defmodule NamedCallbacksTupleTest do\n      use ExUnit.Case\n\n      setup_all {__MODULE__, :setup_1}\n      setup [{__MODULE__, :setup_2}, {__MODULE__, :setup_3}]\n\n      test \"callbacks\", context do\n        assert context[:setup_1]\n        assert context[:setup_2]\n        assert context[:setup_3]\n      end\n\n      def setup_1(_), do: [setup_1: true]\n      def setup_2(_), do: [setup_2: true]\n      def setup_3(_), do: [setup_3: true]\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Result: 1 passed\"\n  end\n\n  test \"doesn't choke on setup errors\" do\n    defmodule SetupTest do\n      use ExUnit.Case\n\n      setup _ do\n        :ok = error()\n      end\n\n      test \"ok\" do\n        :ok\n      end\n\n      defp error, do: :error\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~\n             \"** (MatchError) no match of right hand side value:\"\n  end\n\n  test \"doesn't choke on setup_all errors\" do\n    defmodule SetupAllTest do\n      use ExUnit.Case\n\n      setup_all _ do\n        :ok = error()\n      end\n\n      test \"ok\" do\n        :ok\n      end\n\n      defp error, do: :error\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~\n             \"** (MatchError) no match of right hand side value:\"\n  end\n\n  test \"doesn't choke on setup_all exits\" do\n    defmodule SetupAllExitTest do\n      use ExUnit.Case\n\n      setup_all _ do\n        Process.exit(self(), :error)\n      end\n\n      test \"ok\" do\n        assert true\n      end\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Result: 0 tests\"\n  end\n\n  test \"doesn't choke on dead supervisor\" do\n    defmodule StartSupervisedErrorTest do\n      use ExUnit.Case\n\n      @tag timeout: 500\n      test \"ok\" do\n        fun = fn ->\n          Process.flag(:trap_exit, true)\n          Process.sleep(:infinity)\n        end\n\n        start_supervised({Task, fun})\n      end\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \"supervisor shutdown timed out after 500ms\"\n  end\n\n  test \"doesn't choke on on_exit errors\" do\n    defmodule OnExitErrorTest do\n      use ExUnit.Case\n\n      test \"ok\" do\n        on_exit(fn -> :ok = error() end)\n        :ok\n      end\n\n      defp error, do: :error\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~\n             \"** (MatchError) no match of right hand side value:\"\n  end\n\n  test \"doesn't choke when on_exit exits\" do\n    defmodule OnExitExitTest do\n      use ExUnit.Case, async: false\n\n      test \"ok\" do\n        on_exit(fn -> Process.exit(self(), :kill) end)\n        :ok\n      end\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \">) killed\"\n  end\n\n  test \"invalidates all tests when on_exit errors within setup_all\" do\n    defmodule InvalidatesTestsOnExitErrorTest do\n      use ExUnit.Case\n\n      setup_all do\n        on_exit(fn -> raise \"boom\" end)\n        :ok\n      end\n\n      test \"succeeds\" do\n        assert true\n      end\n\n      test \"fails\" do\n        assert false\n      end\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Failed: 2 tests\"\n  end\n\n  defp no_formatters! do\n    ExUnit.configure(formatters: [])\n    on_exit(fn -> ExUnit.configure(formatters: [ExUnit.CLIFormatter]) end)\n  end\n\n  test \"exits with shutdown reason\" do\n    defmodule OnExitAliveTest do\n      use ExUnit.Case\n\n      setup do\n        parent = self()\n\n        pid =\n          spawn_link(fn ->\n            Process.flag(:trap_exit, true)\n            send(parent, :ready)\n\n            receive do\n              {:EXIT, ^parent, :shutdown} ->\n                receive do: ({:on_exit, pid} -> send(pid, :done))\n            end\n          end)\n\n        receive do: (:ready -> :ok)\n\n        on_exit(fn ->\n          send(pid, {:on_exit, self()})\n          assert_receive :done\n          IO.puts(\"on_exit run\")\n        end)\n\n        :ok\n      end\n\n      test \"ok\" do\n        :ok\n      end\n    end\n\n    output = capture_io(fn -> ExUnit.run() end)\n    assert output =~ \"on_exit run\"\n    assert output =~ \"Result: 1 passed\"\n  end\n\n  test \"runs multiple on_exit exits and overrides by ref\" do\n    defmodule OnExitSuccessTest do\n      use ExUnit.Case\n\n      setup do\n        on_exit(fn ->\n          IO.puts(\"on_exit setup run\")\n        end)\n\n        on_exit({:overridden, 1}, fn ->\n          IO.puts(\"on_exit 1 overridden -> not run\")\n        end)\n\n        :ok\n      end\n\n      setup_all do\n        on_exit(fn ->\n          IO.puts(\"on_exit setup_all run\")\n        end)\n\n        :ok\n      end\n\n      test \"ok\" do\n        on_exit(fn ->\n          IO.puts(\"simple on_exit run\")\n        end)\n\n        on_exit({:overridden, 2}, fn ->\n          IO.puts(\"on_exit 2 overridden -> not run\")\n        end)\n\n        on_exit({:overridden, 2}, fn ->\n          IO.puts(\"on_exit 2 overrides -> run\")\n        end)\n\n        on_exit({:overridden, 1}, fn ->\n          IO.puts(\"on_exit 1 overrides -> run\")\n        end)\n\n        :ok\n      end\n    end\n\n    no_formatters!()\n    output = capture_io(fn -> ExUnit.run() end)\n\n    assert output =~ \"\"\"\n           on_exit 2 overrides -> run\n           simple on_exit run\n           on_exit 1 overrides -> run\n           on_exit setup run\n           on_exit setup_all run\n           \"\"\"\n\n    refute output =~ \"not run\"\n  end\n\n  test \"runs multiple on_exit on failure\" do\n    defmodule OnExitFailureTest do\n      use ExUnit.Case\n\n      setup do\n        on_exit(fn ->\n          IO.puts(\"on_exit setup run\")\n        end)\n\n        :ok\n      end\n\n      setup_all do\n        on_exit(fn ->\n          IO.puts(\"on_exit setup_all run\")\n        end)\n\n        :ok\n      end\n\n      test \"ok\" do\n        on_exit(fn ->\n          IO.puts(\"simple on_exit run\")\n        end)\n\n        flunk(\"oops\")\n      end\n    end\n\n    no_formatters!()\n    output = capture_io(fn -> ExUnit.run() end)\n\n    assert output =~ \"\"\"\n           simple on_exit run\n           on_exit setup run\n           on_exit setup_all run\n           \"\"\"\n  end\n\n  test \"raises an error when using setup/2 with something other than a block\" do\n    message =\n      \"setup/2 requires a block as the second argument after the context, got: :start_counter\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_quoted(\n        quote do\n          defmodule SetupWithoutBlockTest do\n            use ExUnit.Case\n            setup context, :start_counter\n          end\n        end\n      )\n    end\n  end\n\n  test \"raises an error when using setup_all/2 with something other than a block\" do\n    message =\n      \"setup_all/2 requires a block as the second argument after the context, got: :start_counter\"\n\n    assert_raise ArgumentError, message, fn ->\n      Code.eval_quoted(\n        quote do\n          defmodule SetupWithoutBlockTest do\n            use ExUnit.Case\n            setup_all context, :start_counter\n          end\n        end\n      )\n    end\n  end\n\n  test \"raises an error when setting an invalid callback in setup\" do\n    defmodule SetupErrorTest do\n      use ExUnit.Case\n\n      setup do: {:ok, \"foo\"}\n      test \"ok\", do: :ok\n    end\n\n    output = capture_io(fn -> ExUnit.run() end)\n\n    assert output =~\n             \"** (RuntimeError) expected ExUnit setup callback in \" <>\n               \"ExUnit.CallbacksTest.SetupErrorTest to return the atom :ok, a keyword, or a map, \" <>\n               \"got {:ok, \\\"foo\\\"} instead\"\n\n    # Make sure that at least the right file where the setup/setup_all call is defined is included\n    # in the stacktrace.\n    assert output =~ ~r/.*callbacks_test\\.exs:\\d+/\n  end\n\n  test \"raises an error when setting an invalid callback in setup_all\" do\n    defmodule SetupAllErrorTest do\n      use ExUnit.Case\n\n      setup_all do: {:ok, \"foo\"}\n      test \"ok\", do: :ok\n    end\n\n    output = capture_io(fn -> ExUnit.run() end)\n\n    assert output =~\n             \"** (RuntimeError) expected ExUnit setup_all callback in \" <>\n               \"ExUnit.CallbacksTest.SetupAllErrorTest to return the atom :ok, a keyword, or a map, \" <>\n               \"got {:ok, \\\"foo\\\"} instead\"\n\n    # Make sure that at least the right file where the setup/setup_all call is defined is included\n    # in the stacktrace.\n    assert output =~ ~r/.*callbacks_test\\.exs:\\d+/\n  end\n\n  test \"raises an error when overriding a reserved callback key in setup\" do\n    defmodule SetupReservedTest do\n      use ExUnit.Case\n\n      setup do\n        {:ok, file: \"foo\"}\n      end\n\n      test \"ok\" do\n        :ok\n      end\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~\n             \"** (RuntimeError) ExUnit setup callback in \" <>\n               \"ExUnit.CallbacksTest.SetupReservedTest is \" <>\n               \"trying to set reserved field :file to \\\"foo\\\"\"\n  end\nend\n\ndefmodule ExUnit.CallbacksNoTests do\n  use ExUnit.Case, async: true\n\n  setup_all do\n    if :rand.uniform() >= 0 do\n      raise \"never run\"\n    end\n  end\n\n  setup do\n    if :rand.uniform() >= 0 do\n      raise \"never run\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/capture_io_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.CaptureIOTest do\n  use ExUnit.Case\n\n  defmodule GetUntil do\n    def until_new_line(_, :eof, _) do\n      {:done, :eof, []}\n    end\n\n    def until_new_line(this_far, chars, stop_char) do\n      case Enum.split_while(chars, fn c -> c != stop_char end) do\n        {l, []} ->\n          {:more, this_far ++ l}\n\n        {l, [stop_char | rest]} ->\n          {:done, this_far ++ l ++ [stop_char], rest}\n      end\n    end\n\n    def get_line(device \\\\ Process.group_leader()) do\n      request = {:get_until, :unicode, \"\", __MODULE__, :until_new_line, [?\\n]}\n      send(device, {:io_request, self(), device, request})\n\n      receive do\n        {:io_reply, _, data} -> data\n      end\n    end\n  end\n\n  defmodule MockProc do\n    use GenServer\n\n    def start_link(gl) do\n      GenServer.start_link(__MODULE__, gl)\n    end\n\n    @impl GenServer\n    def init(gl) do\n      Process.group_leader(self(), gl)\n      {:ok, nil}\n    end\n\n    @impl GenServer\n    def handle_call({:stdio, message}, _from, state) do\n      IO.puts(message)\n      {:reply, :ok, state}\n    end\n\n    @impl GenServer\n    def handle_call({:prompt, prompt}, _from, state) do\n      prompt\n      |> IO.gets()\n      |> IO.puts()\n\n      {:reply, :ok, state}\n    end\n\n    @impl GenServer\n    def handle_call({:stderr, message}, _from, state) do\n      IO.puts(:stderr, message)\n      {:reply, :ok, state}\n    end\n  end\n\n  import ExUnit.CaptureIO\n  doctest ExUnit.CaptureIO, import: true\n\n  describe \"I/O protocol\" do\n    test \"with put chars\" do\n      assert capture_io(fn ->\n               :io.put_chars(\"\")\n             end) == \"\"\n\n      assert capture_io(fn ->\n               :io.put_chars(\"a\")\n               :io.put_chars(\"b\")\n             end) == \"ab\"\n\n      assert capture_io(fn ->\n               :io.put_chars(\"josé\")\n             end) == \"josé\"\n\n      assert capture_io(fn ->\n               spawn(fn -> :io.put_chars(\"a\") end)\n               Process.sleep(10)\n             end) == \"a\"\n\n      assert capture_io(fn ->\n               assert :io.put_chars(\"a\") == :ok\n             end)\n    end\n\n    test \"with fwrite\" do\n      assert capture_io(fn ->\n               :io.fwrite(<<127, 128>>)\n             end) == <<127, 194, 128>>\n\n      assert capture_io([encoding: :latin1], fn ->\n               :io.fwrite(<<127, 128>>)\n             end) == <<127, 128>>\n    end\n\n    test \"with get chars\" do\n      assert capture_io(fn ->\n               :io.get_chars(\">\", 3)\n             end) == \">\"\n\n      assert capture_io([capture_prompt: false], fn ->\n               :io.get_chars(\">\", 3)\n             end) == \"\"\n\n      capture_io(fn ->\n        assert :io.get_chars(\">\", 3) == :eof\n      end)\n\n      capture_io(\"\", fn ->\n        assert :io.get_chars(\">\", 3) == :eof\n      end)\n\n      capture_io(\"abc\\ndef\", fn ->\n        assert :io.get_chars(\">\", 3) == \"abc\"\n        assert :io.get_chars(\">\", 5) == \"\\ndef\"\n        assert :io.get_chars(\">\", 7) == :eof\n      end)\n\n      capture_io(\"あいう\", fn ->\n        assert :io.get_chars(\">\", 2) == \"あい\"\n        assert :io.get_chars(\">\", 1) == \"う\"\n        assert :io.get_chars(\">\", 1) == :eof\n      end)\n    end\n\n    test \"with get line\" do\n      assert capture_io(fn ->\n               :io.get_line(\">\")\n             end) == \">\"\n\n      assert capture_io([capture_prompt: false], fn ->\n               :io.get_line(\">\")\n             end) == \"\"\n\n      capture_io(fn ->\n        assert :io.get_line(\">\") == :eof\n      end)\n\n      capture_io(\"\", fn ->\n        assert :io.get_line(\">\") == :eof\n      end)\n\n      capture_io(\"\\n\", fn ->\n        assert :io.get_line(\">\") == \"\\n\"\n        assert :io.get_line(\">\") == :eof\n      end)\n\n      capture_io(\"a\", fn ->\n        assert :io.get_line(\">\") == \"a\"\n        assert :io.get_line(\">\") == :eof\n      end)\n\n      capture_io(\"a\\n\", fn ->\n        assert :io.get_line(\">\") == \"a\\n\"\n        assert :io.get_line(\">\") == :eof\n      end)\n\n      capture_io(\"a\\nb\", fn ->\n        assert :io.get_line(\">\") == \"a\\n\"\n        assert :io.get_line(\">\") == \"b\"\n        assert :io.get_line(\">\") == :eof\n      end)\n\n      capture_io(\"あい\\nう\", fn ->\n        assert :io.get_line(\">\") == \"あい\\n\"\n        assert :io.get_line(\">\") == \"う\"\n        assert :io.get_line(\">\") == :eof\n      end)\n    end\n\n    test \"with get password\" do\n      capture_io(fn ->\n        assert :io.get_password(Process.group_leader()) == :eof\n      end)\n\n      capture_io(\"\", fn ->\n        assert :io.get_password(Process.group_leader()) == :eof\n      end)\n\n      capture_io(\"abc\", fn ->\n        assert :io.get_password(Process.group_leader()) == \"abc\"\n        assert :io.get_password(Process.group_leader()) == :eof\n      end)\n\n      capture_io(\"abc\\n\", fn ->\n        assert :io.get_password(Process.group_leader()) == \"abc\\n\"\n        assert :io.get_password(Process.group_leader()) == :eof\n      end)\n\n      capture_io(\"\\n\", fn ->\n        assert :io.get_password(Process.group_leader()) == \"\\n\"\n        assert :io.get_password(Process.group_leader()) == :eof\n      end)\n\n      capture_io(\"a\\nb\", fn ->\n        assert :io.get_password(Process.group_leader()) == \"a\\n\"\n        assert :io.get_password(Process.group_leader()) == \"b\"\n        assert :io.get_password(Process.group_leader()) == :eof\n      end)\n\n      capture_io(\"あい\\nう\", fn ->\n        assert :io.get_password(Process.group_leader()) == \"あい\\n\"\n        assert :io.get_password(Process.group_leader()) == \"う\"\n        assert :io.get_password(Process.group_leader()) == :eof\n      end)\n    end\n\n    test \"with get until\" do\n      assert capture_io(fn ->\n               :io.scan_erl_form(~c\">\")\n             end) == \">\"\n\n      assert capture_io(\"1.\\n\", fn ->\n               :io.scan_erl_form(~c\">\")\n             end) == \">\"\n\n      assert capture_io(\"1\\n.\\n\", fn ->\n               :io.scan_erl_form(~c\">\")\n             end) == \">>\"\n\n      assert capture_io([capture_prompt: false], fn ->\n               :io.scan_erl_form(~c\">\")\n             end) == \"\"\n\n      capture_io(fn ->\n        assert :io.scan_erl_form(~c\">\") == {:eof, 1}\n      end)\n\n      capture_io(\"1\", fn ->\n        assert :io.scan_erl_form(~c\">\") == {:ok, [{:integer, 1, 1}], 1}\n        assert :io.scan_erl_form(~c\">\") == {:eof, 1}\n      end)\n\n      capture_io(\"1\\n.\", fn ->\n        assert :io.scan_erl_form(~c\">\") == {:ok, [{:integer, 1, 1}, {:dot, 2}], 2}\n        assert :io.scan_erl_form(~c\">\") == {:eof, 1}\n      end)\n\n      capture_io(\"1.\\n.\", fn ->\n        assert :io.scan_erl_form(~c\">\") == {:ok, [{:integer, 1, 1}, {:dot, 1}], 2}\n        assert :io.scan_erl_form(~c\">\") == {:ok, [dot: 1], 1}\n        assert :io.scan_erl_form(~c\">\") == {:eof, 1}\n      end)\n\n      capture_io(\"\\\"a\", fn ->\n        expected_error = {1, :erl_scan, {:unterminated, :string, ~c\"a\"}}\n\n        assert :io.scan_erl_form(~c\">\") == {:error, expected_error, 1}\n        assert :io.scan_erl_form(~c\">\") == {:eof, 1}\n      end)\n\n      capture_io(\"\\\"a\\n\\\"\", fn ->\n        assert :io.scan_erl_form(~c\">\") == {:ok, [{:string, 1, ~c\"a\\n\"}], 2}\n        assert :io.scan_erl_form(~c\">\") == {:eof, 1}\n      end)\n\n      capture_io(\":erl. mof*,,l\", fn ->\n        assert :io.scan_erl_form(~c\">\") == {:ok, [{:\":\", 1}, {:atom, 1, :erl}, {:dot, 1}], 1}\n\n        expected_tokens = [{:atom, 1, :mof}, {:*, 1}, {:\",\", 1}, {:\",\", 1}, {:atom, 1, :l}]\n        assert :io.scan_erl_form(~c\">\") == {:ok, expected_tokens, 1}\n\n        assert :io.scan_erl_form(~c\">\") == {:eof, 1}\n      end)\n\n      capture_io(\"a\\nb\\nc\", fn ->\n        assert GetUntil.get_line() == \"a\\n\"\n        assert GetUntil.get_line() == \"b\\n\"\n        assert GetUntil.get_line() == :eof\n      end)\n    end\n\n    test \"with setopts\" do\n      assert capture_io(fn ->\n               assert :io.setopts({:encoding, :latin1}) == {:error, :enotsup}\n             end) == \"\"\n    end\n\n    test \"with getopts\" do\n      assert capture_io(fn ->\n               assert :io.getopts() == [binary: true, encoding: :unicode]\n             end) == \"\"\n    end\n\n    test \"with columns\" do\n      assert capture_io(fn ->\n               :io.columns()\n             end) == \"\"\n\n      capture_io(fn ->\n        assert :io.columns() == {:error, :enotsup}\n      end)\n    end\n\n    test \"with rows\" do\n      assert capture_io(fn ->\n               :io.rows()\n             end) == \"\"\n\n      capture_io(fn ->\n        assert :io.rows() == {:error, :enotsup}\n      end)\n    end\n\n    test \"with multiple requests\" do\n      requests = [{:put_chars, :unicode, \"a\"}, {:put_chars, :unicode, \"b\"}]\n\n      assert capture_io(fn ->\n               send_and_receive_io({:requests, requests})\n             end) == \"ab\"\n\n      capture_io(fn ->\n        assert send_and_receive_io({:requests, requests}) == :ok\n      end)\n    end\n\n    test \"with unknown request\" do\n      assert capture_io(fn ->\n               send_and_receive_io(:unknown)\n             end) == \"\"\n\n      capture_io(fn ->\n        assert send_and_receive_io(:unknown) == {:error, :request}\n      end)\n    end\n  end\n\n  describe \"stdin\" do\n    test \"double capture from the same process\" do\n      assert capture_io(fn ->\n               IO.puts(\"hello\")\n               assert capture_io(fn -> IO.puts(\"middle\") end) == \"middle\\n\"\n               IO.puts(\"world\")\n             end) == \"hello\\nworld\\n\"\n    end\n\n    test \"no leakage on failures\" do\n      group_leader = Process.group_leader()\n\n      test = self()\n\n      assert_raise ArgumentError, fn ->\n        capture_io(fn ->\n          send(test, {:string_io, Process.group_leader()})\n          raise ArgumentError\n        end)\n      end\n\n      receive do\n        {:string_io, pid} ->\n          ref = Process.monitor(pid)\n          assert_receive {:DOWN, ^ref, _, _, _}\n      end\n\n      assert Process.group_leader() == group_leader\n    end\n  end\n\n  describe \"stderr\" do\n    test \"supports writes\" do\n      assert capture_io(:stderr, fn ->\n               :io.put_chars(:standard_error, \"a\")\n             end) == \"a\"\n    end\n\n    test \"double capture from the same process\" do\n      assert capture_io(:stderr, fn ->\n               IO.puts(:stderr, \"hello\")\n               assert capture_io(:stderr, fn -> IO.puts(:stderr, \"middle\") end) == \"middle\\n\"\n               IO.puts(:stderr, \"world\")\n             end) == \"hello\\nmiddle\\nworld\\n\"\n    end\n\n    test \"supports async capture_io\" do\n      parent = self()\n\n      [pid1, pid2, pid3] =\n        for num <- 1..3 do\n          pid =\n            spawn_link(fn ->\n              captured =\n                capture_io(:stderr, fn ->\n                  :io.put_chars(:standard_error, \"before:#{num}\\n\")\n                  send(parent, {self(), :logged})\n                  assert_receive :continue\n                  :io.put_chars(:standard_error, \"after:#{num}\\n\")\n                end)\n\n              send(parent, captured)\n            end)\n\n          assert_receive {^pid, :logged}\n          pid\n        end\n\n      send(pid3, :continue)\n      assert_receive \"before:3\\nafter:3\\n\"\n\n      send(pid2, :continue)\n      assert_receive \"before:2\\nbefore:3\\nafter:3\\nafter:2\\n\"\n\n      send(pid1, :continue)\n      assert_receive \"before:1\\nbefore:2\\nbefore:3\\nafter:3\\nafter:2\\nafter:1\\n\"\n    end\n\n    test \"raises when async capturing a named device with a different encoding than the first\" do\n      parent = self()\n\n      pid =\n        spawn_link(fn ->\n          output =\n            capture_io(:stderr, [encoding: :latin1], fn ->\n              :io.put_chars(:standard_error, \"a\")\n              send(parent, {self(), :logged})\n              assert_receive :continue\n            end)\n\n          send(parent, output)\n        end)\n\n      assert_receive {^pid, :logged}\n\n      assert_raise ArgumentError,\n                   ~r\"attempted to change the encoding for a currently captured device :standard_error\",\n                   fn ->\n                     capture_io(:stderr, [encoding: :unicode], fn ->\n                       :io.put_chars(:standard_error, \"b\")\n                     end)\n                   end\n\n      assert capture_io(:stderr, [encoding: :latin1], fn ->\n               :io.put_chars(:standard_error, \"c\")\n             end) == \"c\"\n\n      send(pid, :continue)\n      assert_receive \"ac\"\n    end\n\n    test \"raises when async capturing a named device with an input given to an already captured device\" do\n      parent = self()\n\n      pid =\n        spawn_link(fn ->\n          capture_io(:stderr, [input: \"first\"], fn ->\n            send(parent, {self(), :logged})\n            Process.sleep(:infinity)\n          end)\n        end)\n\n      assert_receive {^pid, :logged}\n\n      message =\n        \"attempted multiple captures on device :standard_error with input. If you need to give an input to a captured device, you cannot run your test asynchronously\"\n\n      assert_raise ArgumentError, message, fn ->\n        capture_io(:stderr, [input: \"second\"], fn ->\n          :io.put_chars(:standard_error, \"b\")\n        end)\n      end\n\n      assert_raise ArgumentError, message, fn ->\n        capture_io(:stderr, [input: \"\"], fn ->\n          :io.put_chars(:standard_error, \"b\")\n        end)\n      end\n    end\n\n    test \"no leakage on failures\" do\n      parent = self()\n\n      pid =\n        spawn(fn ->\n          capture_io(:stderr, [input: \"a\"], fn ->\n            send(parent, :ready)\n            Process.sleep(:infinity)\n          end)\n        end)\n\n      assert_receive :ready\n\n      ref = Process.monitor(pid)\n\n      # Kill the process and make sure the capture is released\n      Process.exit(pid, :shutdown)\n\n      # Make sure the process has exited before we try and start a new capture\n      assert_receive {:DOWN, ^ref, _, _, _}\n\n      assert capture_io(:stderr, [input: \"b\"], fn -> :ok end)\n    end\n  end\n\n  test \"capture_io with a separate process\" do\n    {:ok, gl} = StringIO.open(\"\")\n    pid = start_supervised!({MockProc, gl})\n\n    assert Process.info(pid, :group_leader) == {:group_leader, gl}\n\n    assert capture_io(pid, fn ->\n             GenServer.call(pid, {:stdio, \"a\"})\n           end) == \"a\\n\"\n\n    assert capture_io(pid, [input: \"b\"], fn ->\n             GenServer.call(pid, {:prompt, \"> \"})\n           end) == \"> b\\n\"\n\n    assert capture_io(pid, \"c\", fn ->\n             GenServer.call(pid, {:prompt, \"> \"})\n           end) == \"> c\\n\"\n\n    assert capture_io(pid, [input: \"d\", capture_prompt: false], fn ->\n             GenServer.call(pid, {:prompt, \"> \"})\n           end) == \"d\\n\"\n\n    assert capture_io(:stderr, fn ->\n             GenServer.call(pid, {:stderr, \"uhoh\"})\n           end) == \"uhoh\\n\"\n\n    assert Process.info(pid, :group_leader) == {:group_leader, gl}\n    assert StringIO.contents(gl) == {\"\", \"\"}\n  end\n\n  test \"with_io\" do\n    assert with_io(fn ->\n             :io.put_chars(\"xyz\")\n             2 + 2\n           end) == {4, \"xyz\"}\n  end\n\n  defp send_and_receive_io(req) do\n    pid = self()\n    send(:erlang.group_leader(), {:io_request, pid, pid, req})\n\n    receive do\n      {:io_reply, ^pid, res} -> res\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/capture_log_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.CaptureLogTest do\n  use ExUnit.Case\n\n  require Logger\n  import ExUnit.CaptureLog\n\n  test \"no output\" do\n    assert capture_log(fn -> nil end) == \"\"\n  end\n\n  test \"assert inside\" do\n    group_leader = Process.group_leader()\n\n    try do\n      capture_log(fn ->\n        assert false\n      end)\n    rescue\n      error in [ExUnit.AssertionError] ->\n        assert error.message == \"Expected truthy, got false\"\n    end\n\n    # Ensure no leakage on failures\n    assert group_leader == Process.group_leader()\n    refute_received {:gen_event_EXIT, _, _}\n  end\n\n  test \"level aware\" do\n    assert capture_log([level: :warning], fn ->\n             Logger.info(\"here\")\n           end) == \"\"\n  end\n\n  @tag timeout: 2000\n  test \"capture removal on exit\" do\n    {_pid, ref} =\n      spawn_monitor(fn ->\n        capture_log(fn ->\n          spawn_link(Kernel, :exit, [:shutdown])\n          Process.sleep(:infinity)\n        end)\n      end)\n\n    assert_receive {:DOWN, ^ref, _, _, :shutdown}\n    wait_capture_removal()\n  end\n\n  test \"log tracking\" do\n    logged =\n      capture_log(fn ->\n        Logger.info(\"one\")\n\n        logged = capture_log(fn -> Logger.error(\"one\") end)\n        send(test = self(), {:nested, logged})\n\n        Logger.warning(\"two\")\n\n        spawn(fn ->\n          Logger.debug(\"three\")\n          send(test, :done)\n        end)\n\n        receive do: (:done -> :ok)\n      end)\n\n    assert logged\n    assert logged =~ \"[info] one\"\n    assert logged =~ \"[warning] two\"\n    assert logged =~ \"[debug] three\"\n    assert logged =~ \"[error] one\"\n\n    receive do\n      {:nested, logged} ->\n        assert logged =~ \"[error] one\"\n        refute logged =~ \"[warning] two\"\n    end\n  end\n\n  test \"deprecated log level\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      output =\n        capture_log([level: :warn], fn ->\n          Logger.log(:warn, \"ABC\")\n          Logger.log(:warning, \"DEF\")\n        end)\n\n      assert output =~ \"ABC\"\n      assert output =~ \"DEF\"\n    end)\n  end\n\n  test \"exits don't leak\" do\n    Process.flag(:trap_exit, true)\n\n    capture_log(fn ->\n      Logger.error(\"oh no!\")\n    end)\n\n    refute_receive {:EXIT, _, _}, 100\n  end\n\n  describe \"with_log/2\" do\n    test \"returns the result and the log\" do\n      {result, log} =\n        with_log(fn ->\n          Logger.error(\"calculating...\")\n          2 + 2\n        end)\n\n      assert result == 4\n      assert log =~ \"calculating...\"\n    end\n\n    test \"respects the :format, :metadata, and :colors options\" do\n      options = [format: \"$metadata| $message\", metadata: [:id], colors: [enabled: false]]\n\n      assert {4, log} =\n               with_log(options, fn ->\n                 Logger.info(\"hello\", id: 123)\n                 2 + 2\n               end)\n\n      assert log == \"id=123 | hello\"\n    end\n\n    @tag capture_log: true\n    test \"respect options with capture_log: true\" do\n      options = [format: \"$metadata| $message\", metadata: [:id], colors: [enabled: false]]\n\n      assert {4, log} =\n               with_log(options, fn ->\n                 Logger.info(\"hello\", id: 123)\n                 2 + 2\n               end)\n\n      assert log == \"id=123 | hello\"\n    end\n  end\n\n  defmodule CustomFormatter do\n    def new do\n      {_, opts} =\n        Logger.Formatter.new(\n          format: \"$metadata| $message\",\n          metadata: [:id],\n          colors: [enabled: false]\n        )\n\n      {__MODULE__, opts}\n    end\n\n    def format(event, config) do\n      event\n      |> wrap()\n      |> Logger.Formatter.format(config)\n    end\n\n    defp wrap(event) do\n      msg =\n        event\n        |> Logger.Formatter.format_event(:infinity)\n        |> to_string()\n\n      %{event | msg: {:string, [\"[CUSTOM]\", msg, \"[/CUSTOM]\"]}}\n    end\n  end\n\n  test \"uses the formatter from the `:formatter` option\" do\n    log =\n      capture_log([formatter: CustomFormatter.new()], fn ->\n        Logger.info(\"hello\", id: 123)\n        2 + 2\n      end)\n\n    assert log == \"id=123 | [CUSTOM]hello[/CUSTOM]\"\n  end\n\n  defp wait_capture_removal() do\n    if ExUnit.CaptureServer in Enum.map(:logger.get_handler_config(), & &1.id) do\n      Process.sleep(20)\n      wait_capture_removal()\n    else\n      :ok\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/case_template_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.SampleCase do\n  use ExUnit.CaseTemplate\n\n  using _ do\n    quote do\n      import unquote(__MODULE__)\n    end\n  end\n\n  def hello do\n    \"world\"\n  end\n\n  setup_all do\n    {:ok, [context: :setup_all, setup_all: 1]}\n  end\n\n  setup context do\n    assert context[:context] == :setup_all\n    {:ok, [context: :setup, setup: 1]}\n  end\nend\n\ndefmodule ExUnit.NestedCase do\n  use ExUnit.CaseTemplate\n\n  setup_all context do\n    {:ok, [setup_all: context[:setup_all] + 1]}\n  end\n\n  setup context do\n    {:ok, [setup: context[:setup] + 1]}\n  end\nend\n\ndefmodule ExUnit.CaseTemplateTest do\n  use ExUnit.SampleCase, async: true, another_option: 123\n  use ExUnit.NestedCase\n\n  two = 2\n\n  test \"unquoting the value #{two}\" do\n    assert 2 == unquote(two)\n  end\n\n  test \"receives context from parent case\", %{context: context} do\n    assert context == :setup\n  end\n\n  test \"runs both templates setup\", context do\n    assert context[:setup] == 2\n  end\n\n  test \"runs both templates setup_all\", context do\n    assert context[:setup_all] == 2\n  end\n\n  test \"using code is executed\" do\n    assert hello() == \"world\"\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/case_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.CaseTest do\n  use ExUnit.Case, async: true, group: :group_foo\n\n  ExUnit.Case.register_attribute(__MODULE__, :foo)\n  ExUnit.Case.register_attribute(__MODULE__, :bar, accumulate: true)\n  ExUnit.Case.register_attribute(__MODULE__, :baz)\n  ExUnit.Case.register_describe_attribute(__MODULE__, :describe_foo)\n  ExUnit.Case.register_describe_attribute(__MODULE__, :describe_bar, accumulate: true)\n  ExUnit.Case.register_describe_attribute(__MODULE__, :describe_baz)\n  ExUnit.Case.register_module_attribute(__MODULE__, :module_foo)\n  ExUnit.Case.register_module_attribute(__MODULE__, :module_bar, accumulate: true)\n  ExUnit.Case.register_module_attribute(__MODULE__, :module_baz)\n\n  @moduletag :moduletag\n  @module_foo :hello\n  @module_bar :world\n\n  test \"defines __ex_unit__\" do\n    assert %ExUnit.TestModule{name: __MODULE__, tests: tests} = __ex_unit__()\n    assert length(tests) > 0\n  end\n\n  @tag hello: false\n  @tag :hello\n  @tag world: :bad\n  @tag world: :good\n  test \"tags\", context do\n    line = __ENV__.line - 1\n    assert context[:async] == true\n    assert context[:line] == line\n    assert context[:module] == __MODULE__\n    assert context[:test] == __ENV__.function |> elem(0)\n    assert context[:test_pid] == self()\n    assert context[:test_type] == :test\n    assert context[:hello] == true\n    assert context[:world] == :good\n    assert context[:test_group] == :group_foo\n  end\n\n  test \"reset tags\", context do\n    assert is_nil(context[:hello])\n    assert is_nil(context[:world])\n  end\n\n  # tags are passed to setup_all\n  setup_all context do\n    assert context.async\n    assert context.module == __MODULE__\n    %{moduletag_from_setup_all: context[:moduletag]}\n  end\n\n  test \"module tags\", context do\n    assert context[:moduletag] == true\n    assert context[:moduletag_from_setup_all] == true\n  end\n\n  @tag moduletag: :overridden\n  test \"module tags can be overridden\", context do\n    assert context[:moduletag] == :overridden\n  end\n\n  @foo :hello\n  @bar :world\n  test \"registered attributes are in context\", context do\n    assert context.registered.foo == :hello\n    assert context.registered.bar == [:world]\n    assert context.registered.baz == nil\n  end\n\n  test \"registered attributes are set per test\", context do\n    assert context.registered.foo == nil\n    assert context.registered.bar == []\n  end\n\n  describe \"with attributes\" do\n    @describe_foo :hello\n    @describe_bar :world\n\n    test \"registered subscribe attributes are in context\", context do\n      assert context.registered.describe_foo == :hello\n      assert context.registered.describe_bar == [:world]\n      assert context.registered.describe_baz == nil\n    end\n  end\n\n  describe \"without attributes\" do\n    test \"registered subscribe attributes are set per subscribe\", context do\n      assert context.registered.describe_foo == nil\n      assert context.registered.describe_bar == []\n    end\n  end\n\n  test \"registered module attributes are in context\", context do\n    assert context.registered.module_foo == :hello\n    assert context.registered.module_bar == [:world]\n    assert context.registered.module_baz == nil\n  end\n\n  test \"registered module attributes stay in context\", context do\n    assert context.registered.module_foo == :hello\n    assert context.registered.module_bar == [:world]\n  end\n\n  test \"raises when same name is registered twice\" do\n    assert_raise ArgumentError, \"cannot register attribute :foo multiple times\", fn ->\n      defmodule AcrossLevelDoubleRegisterTest do\n        use ExUnit.Case\n        ExUnit.Case.register_attribute(__MODULE__, :foo)\n        ExUnit.Case.register_module_attribute(__MODULE__, :foo)\n      end\n    end\n  end\n\n  test \"raises when attribute is set before being registered\" do\n    assert_raise RuntimeError, \"you must set @foo after it has been registered\", fn ->\n      defmodule SetBeforeRegisterTest do\n        use ExUnit.Case\n        @foo true\n        ExUnit.Case.register_attribute(__MODULE__, :foo, accumulate: true)\n      end\n    end\n  end\n\n  test \"raises when name is longer than 255 characters\" do\n    assert_raise SystemLimitError,\n                 ~r/must be shorter than 255 characters, got: \"test a{256}\"/,\n                 fn ->\n                   defmodule LongNameTest do\n                     use ExUnit.Case\n\n                     test String.duplicate(\"a\", 256)\n                   end\n                 end\n\n    assert_raise SystemLimitError,\n                 ~r/must be shorter than 255 characters, got: \"test a{100} a{156}\"/,\n                 fn ->\n                   defmodule LongDescribeNameTest do\n                     use ExUnit.Case\n\n                     describe String.duplicate(\"a\", 100) do\n                       test String.duplicate(\"a\", 156)\n                     end\n                   end\n                 end\n  end\n\n  test \"warns when using @tag outside of describe\" do\n    stderr =\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        defmodule TagOutsideOfDescribe do\n          use ExUnit.Case, register: false\n\n          @tag :foo\n          describe \"bar\" do\n            test \"baz\" do\n            end\n          end\n        end\n      end)\n\n    assert stderr =~ \"found unused @tag before \\\"describe\\\", did you mean to use @describetag?\"\n  end\nend\n\ndefmodule ExUnit.DoubleCaseTestAsyncFirst do\n  use ExUnit.Case, async: true\n  use ExUnit.Case\n\n  test \"async must be true\", context do\n    assert context.async\n  end\nend\n\ndefmodule ExUnit.DoubleCaseTestAsyncLast do\n  use ExUnit.Case\n  use ExUnit.Case, async: true\n\n  test \"async must be true\", context do\n    assert context.async\n  end\nend\n\ndefmodule ExUnit.CaseTest.TmpDir do\n  use ExUnit.Case\n\n  @moduletag :tmp_dir\n\n  defp ends_with_short_hash?(string) do\n    string\n    |> binary_slice(-9..-1)\n    |> String.starts_with?(\"-\")\n  end\n\n  defp ends_with_short_hash_and_extra_path?(string, extra_path) do\n    extra_path = \"/\" <> extra_path\n    extra_path_length = String.length(extra_path)\n\n    case String.split_at(string, -extra_path_length) do\n      {tmp_dir_base, extra_path_new} when extra_path_new == extra_path ->\n        ends_with_short_hash?(tmp_dir_base)\n\n      _ ->\n        false\n    end\n  end\n\n  defp starts_with_path?(tmp_dir, path) do\n    String.starts_with?(tmp_dir, Path.expand(path))\n  end\n\n  test \"default path\", context do\n    assert starts_with_path?(context.tmp_dir, \"tmp/ExUnit.CaseTest.TmpDir/test-default-path-\")\n    assert ends_with_short_hash?(context.tmp_dir)\n    assert File.ls!(context.tmp_dir) == []\n  end\n\n  test \"escapes foo?/0\", context do\n    assert starts_with_path?(context.tmp_dir, \"tmp/ExUnit.CaseTest.TmpDir/test-escapes-foo--0-\")\n    assert ends_with_short_hash?(context.tmp_dir)\n  end\n\n  @tag tmp_dir: \"foo/bar\"\n  test \"custom path\", context do\n    assert starts_with_path?(context.tmp_dir, \"tmp/ExUnit.CaseTest.TmpDir/test-custom-path-\")\n    assert ends_with_short_hash_and_extra_path?(context.tmp_dir, \"foo/bar\")\n  end\n\n  @tag tmp_dir: false\n  test \"disabled\", context do\n    refute context[:tmp_dir]\n  end\n\n  describe \"colliding test names\" do\n    test \"foo-bar\", context do\n      assert starts_with_path?(\n               context.tmp_dir,\n               \"tmp/ExUnit.CaseTest.TmpDir/test-colliding-test-names-foo-bar-\"\n             )\n\n      assert String.ends_with?(context.tmp_dir, \"-2489e2ce\")\n    end\n\n    test \"foo+bar\", context do\n      assert starts_with_path?(\n               context.tmp_dir,\n               \"tmp/ExUnit.CaseTest.TmpDir/test-colliding-test-names-foo-bar-\"\n             )\n\n      assert String.ends_with?(context.tmp_dir, \"-9633ed5f\")\n    end\n  end\nend\n\ndefmodule ExUnit.BadOptsCase do\n  use ExUnit.Case, async: true\n\n  test \"raises if passed something other than options\" do\n    assert_raise ArgumentError, ~r/must be a list of options, got: \"not a list of options\"/, fn ->\n      defmodule MyBadCase do\n        use ExUnit.Case, \"not a list of options\"\n      end\n    end\n  end\nend\n\ndefmodule ExUnit.CaseTest.GetLastRegisteredTestHelper do\n  defmacro escaped_get_last_registered_test do\n    Macro.escape(ExUnit.Case.get_last_registered_test(__CALLER__))\n  end\nend\n\ndefmodule ExUnit.CaseTest.GetLastRegisteredTestTest do\n  use ExUnit.Case, async: true\n  import ExUnit.CaseTest.GetLastRegisteredTestHelper\n\n  last = ExUnit.Case.get_last_registered_test(__MODULE__)\n\n  test \"returns nil if called before any test has been registered\" do\n    assert unquote(last) == nil\n  end\n\n  test \"returns the current test if call is within test body\", %{test: name} do\n    assert %ExUnit.Test{\n             name: ^name,\n             module: __MODULE__,\n             state: nil,\n             time: 0\n           } = escaped_get_last_registered_test()\n  end\n\n  last = ExUnit.Case.get_last_registered_test(__MODULE__)\n\n  test \"returns the previous test if call is outside test body\" do\n    assert %ExUnit.Test{name: :\"test returns the current test if call is within test body\"} =\n             unquote(Macro.escape(last))\n  end\n\n  test \"raises if given module is already compiled\" do\n    assert_raise ArgumentError, ~r/could not call Module\\.get_last_attribute\\/2/, fn ->\n      ExUnit.Case.get_last_registered_test(__MODULE__)\n    end\n  end\n\n  @moduletag tag1: :foo\n  describe \"tags\" do\n    @describetag tag2: :bar\n\n    @tag tag3: :baz\n    test \"includes data available in test context\", context do\n      assert %ExUnit.Test{tags: %{tag1: :foo, tag2: :bar, tag3: :baz} = tags} =\n               escaped_get_last_registered_test()\n\n      assert tags == Map.take(context, Map.keys(tags))\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/describe_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.DescribeTest do\n  use ExUnit.Case, async: true\n\n  @moduletag [attribute_tag: :from_module]\n\n  setup _ do\n    [setup_tag: :from_module]\n  end\n\n  describe \"tags\" do\n    @describetag attribute_tag: :from_describe\n\n    test \"from describe have higher precedence\", context do\n      assert context.attribute_tag == :from_describe\n    end\n\n    @tag attribute_tag: :from_test\n    test \"from test have higher precedence\", context do\n      assert context.attribute_tag == :from_test\n    end\n  end\n\n  describe \"setup\" do\n    setup _ do\n      [setup_tag: :from_describe]\n    end\n\n    test \"from describe runs later\", context do\n      assert context.setup_tag == :from_describe\n    end\n  end\n\n  describe \"setup from import\" do\n    import Map\n    setup :to_list\n\n    test \"is expanded within describe block\", context do\n      assert context.setup_tag == :from_module\n    end\n  end\n\n  describe \"failures\" do\n    test \"when using setup_all inside describe\" do\n      assert_raise RuntimeError, ~r\"cannot invoke setup_all/1-2 inside describe\", fn ->\n        defmodule Sample do\n          use ExUnit.Case\n\n          describe \"hello\" do\n            setup_all do\n              [hello: \"world\"]\n            end\n          end\n        end\n      end\n    end\n\n    test \"when using describe inside describe\" do\n      regex = ~r{cannot call \"describe\" inside another \"describe\"}\n\n      assert_raise RuntimeError, regex, fn ->\n        defmodule Sample do\n          use ExUnit.Case\n\n          describe \"hello\" do\n            describe \"another\" do\n            end\n          end\n        end\n      end\n    end\n\n    test \"when using non-string describe name\" do\n      assert_raise ArgumentError, ~r\"describe name must be a string, got: :not_allowed\", fn ->\n        defmodule Sample do\n          use ExUnit.Case\n\n          describe :not_allowed do\n          end\n        end\n      end\n    end\n\n    test \"when using the same name for two describe blocks\" do\n      message =\n        ~s(describe \"some tests\" is already defined in ExUnit.DescribeTest.DescribeWithSameNames)\n\n      assert_raise ArgumentError, message, fn ->\n        defmodule DescribeWithSameNames do\n          use ExUnit.Case\n\n          describe \"some tests\" do\n          end\n\n          describe \"some tests\" do\n          end\n        end\n      end\n    end\n  end\n\n  test \"when @describetag is used outside of a describe block\" do\n    message = ~s(@describetag must be set inside describe/2 blocks)\n\n    assert_raise RuntimeError, message, fn ->\n      defmodule DescribetagOutsideOfDescribeBlock do\n        use ExUnit.Case\n\n        @describetag :integration\n\n        describe \"some tests\" do\n        end\n      end\n    end\n  end\n\n  describe \"test names\" do\n    test \"merge describe information\", context do\n      assert context.test == :\"test test names merge describe information\"\n    end\n  end\n\n  test \"attributes from outside describe\", context do\n    assert context.attribute_tag == :from_module\n    assert context.setup_tag == :from_module\n    assert context.test == :\"test attributes from outside describe\"\n  end\n\n  describe \"describe block\" do\n    test \"sets describe_line\", context do\n      assert context.describe_line == __ENV__.line - 2\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/diff_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.DiffTest do\n  use ExUnit.Case, async: true\n\n  alias Inspect.Algebra\n  alias ExUnit.{Assertions, Diff}\n\n  defmodule User do\n    defstruct [:name, :age]\n  end\n\n  defmodule Customer do\n    defstruct [:address, :age, :first_name, :language, :last_name, :notifications]\n  end\n\n  defmodule Person do\n    defstruct [:age]\n  end\n\n  defmodule Opaque do\n    defstruct [:data]\n\n    defimpl Inspect do\n      def inspect(%{data: data}, _) when is_tuple(data) or is_map(data),\n        do: \"#Opaque<data: #{inspect(data)}>\"\n\n      def inspect(_, _),\n        do: \"#Opaque<???>\"\n    end\n  end\n\n  defmodule HTML do\n    defstruct [:string]\n\n    defimpl Inspect do\n      def inspect(%{string: string}, _) do\n        \"~HTML[#{string}]\"\n      end\n    end\n  end\n\n  defmacro sigil_HTML({:<<>>, _, [string]}, []) do\n    Macro.escape(%HTML{string: string})\n  end\n\n  defmacrop one, do: 1\n\n  defmacrop tuple(a, b) do\n    quote do\n      {unquote(a), unquote(b)}\n    end\n  end\n\n  defmacrop pin_x do\n    x = Macro.var(:x, nil)\n    quote(do: ^unquote(x))\n  end\n\n  defmacrop block_head({:__block__, _, [head | _]}) do\n    head\n  end\n\n  defmacrop assert_diff(expr, expected_binding, pins \\\\ [])\n\n  defmacrop assert_diff({:=, _, [left, right]}, expected_binding, pins) do\n    left = Assertions.__expand_pattern__(left, __CALLER__) |> Macro.escape()\n\n    quote do\n      assert_diff(\n        unquote(left),\n        unquote(right),\n        unquote(expected_binding),\n        {:match, unquote(pins)}\n      )\n    end\n  end\n\n  defmacrop assert_diff({op, _, [left, right]}, [], []) when op in [:==, :===] do\n    quote do\n      assert_diff(unquote(left), unquote(right), [], unquote(op))\n    end\n  end\n\n  defmacrop refute_diff(expr, expected_left, expected_right, pins \\\\ [])\n\n  defmacrop refute_diff({:=, _, [left, right]}, expected_left, expected_right, pins) do\n    left = Assertions.__expand_pattern__(left, __CALLER__) |> Macro.escape()\n\n    quote do\n      refute_diff(\n        unquote(left),\n        unquote(right),\n        unquote(expected_left),\n        unquote(expected_right),\n        {:match, unquote(pins)}\n      )\n    end\n  end\n\n  defmacrop refute_diff({op, _, [left, right]}, expected_left, expected_right, [])\n            when op in [:==, :===] do\n    quote do\n      refute_diff(\n        unquote(left),\n        unquote(right),\n        unquote(expected_left),\n        unquote(expected_right),\n        unquote(op)\n      )\n    end\n  end\n\n  defp refute_diff(left, right, expected_left, expected_right, context) do\n    {diff, _env} = Diff.compute(left, right, context)\n    assert diff.equivalent? == false\n\n    diff_left = to_diff(diff.left, \"-\")\n    assert diff_left =~ expected_left\n\n    diff_right = to_diff(diff.right, \"+\")\n    assert diff_right =~ expected_right\n  end\n\n  defp assert_diff(left, right, expected_binding, context) do\n    {diff, env} = Diff.compute(left, right, context)\n    env_binding = for {{name, _}, value} <- env.current_vars, do: {name, value}\n\n    assert diff.equivalent? == true\n    assert env_binding == expected_binding\n  end\n\n  @terminal_width 80\n  defp to_diff(side, sign) do\n    side\n    |> Diff.to_algebra(&diff_wrapper(&1, sign))\n    |> Algebra.format(@terminal_width)\n    |> IO.iodata_to_binary()\n  end\n\n  defp diff_wrapper(doc, side) do\n    Algebra.concat([side, doc, side])\n  end\n\n  test \"atoms\" do\n    assert_diff(:a = :a, [])\n    assert_diff(:a = :a, [])\n    assert_diff(:\"$a\" = :\"$a\", [])\n\n    refute_diff(:a = :b, \"-:a-\", \"+:b+\")\n    refute_diff(:a = :aa, \"-:a-\", \"+:aa+\")\n\n    refute_diff(:\"$\" = :\"$a\", ~s[-:\"$\"-], ~s[+:\"$a\"+])\n    refute_diff(:\"$a\" = :\"$b\", ~s[-:\"$a\"-], ~s[+:\"$b\"+])\n\n    refute_diff(:bar = 42, \"-:bar-\", \"+42+\")\n    refute_diff(42 = :bar, \"-42-\", \"+:bar+\")\n\n    pins = %{{:a, nil} => :a, {:b, nil} => :b}\n    assert_diff(x = :a, [x: :a], pins)\n    assert_diff(^a = :a, [], pins)\n    assert_diff(^b = :b, [], pins)\n\n    refute_diff(^a = :b, \"-^a-\", \"+:b+\", pins)\n    refute_diff(^b = :a, \"-^b-\", \"+:a+\", pins)\n  end\n\n  test \"pseudo vars\" do\n    assert_diff(__MODULE__ = ExUnit.DiffTest, [])\n    refute_diff(__MODULE__ = SomethingElse, \"-ExUnit.DiffTest-\", \"+SomethingElse+\")\n  end\n\n  test \"integers\" do\n    assert_diff(123 = 123, [])\n    assert_diff(-123 = -123, [])\n    assert_diff(123 = +123, [])\n    assert_diff(+123 = 123, [])\n\n    refute_diff(12 = 13, \"1-2-\", \"1+3+\")\n    refute_diff(12345 = 123, \"123-45-\", \"123\")\n    refute_diff(123 = 12345, \"123\", \"123+45+\")\n    refute_diff(12345 = 345, \"-12-345\", \"345\")\n    refute_diff(345 = 12345, \"345\", \"+12+345\")\n    refute_diff(123 = -123, \"123\", \"+-+123\")\n    refute_diff(-123 = 123, \"---123\", \"123\")\n    refute_diff(491_512_235 = 490_512_035, \"49-1-512-2-35\", \"49+0+512+0+35\")\n\n    assert_diff(0xF = 15, [])\n    refute_diff(0xF = 16, \"1-5-\", \"1+6+\")\n    refute_diff(123 = :a, \"-123-\", \"+:a+\")\n  end\n\n  test \"floats\" do\n    assert_diff(123.0 = 123.0, [])\n    assert_diff(-123.0 = -123.0, [])\n    assert_diff(123.0 = +123.0, [])\n    assert_diff(+123.0 = 123.0, [])\n\n    refute_diff(1.2 = 1.3, \"1.-2-\", \"1.+3+\")\n    refute_diff(12.345 = 12.3, \"12.3-45-\", \"12.3\")\n    refute_diff(12.3 = 12.345, \"12.3\", \"12.3+45+\")\n    refute_diff(123.45 = 3.45, \"-12-3.45\", \"3.45\")\n    refute_diff(3.45 = 123.45, \"3.45\", \"+12+3.45\")\n    refute_diff(1.23 = -1.23, \"1.23\", \"+-+1.23\")\n    refute_diff(-1.23 = 1.23, \"---1.23\", \"1.23\")\n    refute_diff(123.0 = :a, \"-123.0-\", \"+:a+\")\n    refute_diff(123.0 = 123_512_235, \"-123.0-\", \"+123512235+\")\n  end\n\n  test \"== / ===\" do\n    refute_diff(\n      %{a: 1, b: 2} == %{a: 1.0, b: :two},\n      \"%{a: 1, b: -2-}\",\n      \"%{a: 1.0, b: +:two+}\"\n    )\n\n    refute_diff(\n      %{a: 1, b: 2} === %{a: 1.0, b: :two},\n      \"%{a: -1-, b: -2-}\",\n      \"%{a: +1.0+, b: +:two+}\"\n    )\n  end\n\n  test \"lists\" do\n    assert_diff([] = [], [])\n\n    assert_diff([:a] = [:a], [])\n    assert_diff([:a, :b, :c] = [:a, :b, :c], [])\n\n    refute_diff([] = [:a], \"[]\", \"[+:a+]\")\n    refute_diff([:a] = [], \"[-:a-]\", \"[]\")\n    refute_diff([:a] = [:b], \"[-:a-]\", \"[+:b+]\")\n    refute_diff([:a, :b, :c] = [:a, :b, :x], \"[:a, :b, -:c-]\", \"[:a, :b, +:x+]\")\n    refute_diff([:a, :x, :c] = [:a, :b, :c], \"[:a, -:x-, :c]\", \"[:a, +:b+, :c]\")\n    refute_diff([:a, :d, :b, :c] = [:a, :b, :c, :d], \"[:a, -:d-, :b, :c]\", \"[:a, :b, :c, +:d+]\")\n    refute_diff([:b, :c] = [:a, :b, :c], \"[:b, :c]\", \"[+:a+, :b, :c]\")\n\n    refute_diff([:a, :b, :c] = [:a, :b, []], \"[:a, :b, -:c-]\", \"[:a, :b, +[]+]\")\n    refute_diff([:a, :b, []] = [:a, :b, :c], \"[:a, :b, -[]-]\", \"[:a, :b, +:c+]\")\n    refute_diff([:a, :b, :c] = [:a, :b], \"[:a, :b, -:c-]\", \"[:a, :b]\")\n    refute_diff([:a, :b] = [:a, :b, :c], \"[:a, :b]\", \"[:a, :b, +:c+]\")\n    refute_diff([:a, :b, :c, :d, :e] = [:a, :b], \"[:a, :b, -:c-, -:d-, -:e-]\", \"[:a, :b]\")\n    refute_diff([:a, :b] = [:a, :b, :c, :d, :e], \"[:a, :b]\", \"[:a, :b, +:c+, +:d+, +:e+]\")\n\n    refute_diff(\n      [:a, [:d, :b, :c]] = [:a, [:b, :c, :d]],\n      \"[:a, [-:d-, :b, :c]]\",\n      \"[:a, [:b, :c, +:d+]]\"\n    )\n\n    refute_diff(\n      [:e, :a, :b, :c, :d] = [:a, :b, :c, :d, :e],\n      \"[-:e-, :a, :b, :c, :d]\",\n      \"[:a, :b, :c, :d, +:e+]\"\n    )\n\n    refute_diff([:a, [:c, :b]] = [:a, [:b, :c]], \"[:a, [-:c-, :b]]\", \"[:a, [:b, +:c+]]\")\n    refute_diff(:a = [:a, [:b, :c]], \"-:a-\", \"+[:a, [:b, :c]]+\")\n\n    pins = %{\n      {:a, nil} => :a,\n      {:b, nil} => :b,\n      {:list_ab, nil} => [:a, :b],\n      {:list_tuple, nil} => [{:foo}]\n    }\n\n    assert_diff(x = [], [x: []], pins)\n    assert_diff(x = [:a, :b], [x: [:a, :b]], pins)\n    assert_diff([x] = [:a], [x: :a], pins)\n    assert_diff([x, :b, :c] = [:a, :b, :c], [x: :a], pins)\n    assert_diff([x, y, z] = [:a, :b, :c], [x: :a, y: :b, z: :c], pins)\n    assert_diff([x, x, :c] = [:a, :a, :c], [x: :a], pins)\n\n    refute_diff([x] = [], \"[-x-]\", \"[]\")\n    refute_diff([x, :b, :c] = [:a, :b, :x], \"[x, :b, -:c-]\", \"[:a, :b, +:x+]\")\n    refute_diff([x, x, :c] = [:a, :b, :c], \"[x, -x-, :c]\", \"[:a, +:b+, :c]\")\n\n    assert_diff(^list_ab = [:a, :b], [], pins)\n    assert_diff([^a, :b, :c] = [:a, :b, :c], [], pins)\n    assert_diff([^a, ^b, :c] = [:a, :b, :c], [], pins)\n    assert_diff([^a, a, :c] = [:a, :b, :c], [a: :b], pins)\n    assert_diff([b, ^b, :c] = [:a, :b, :c], [b: :a], pins)\n\n    refute_diff(^list_ab = [:x, :b], \"-^list_ab-\", \"[+:x+, :b]\", pins)\n    refute_diff([^a, :b, :c] = [:a, :b, :x], \"[^a, :b, -:c-]\", \"[:a, :b, +:x+]\", pins)\n    refute_diff([:a, ^a, :c] = [:a, :b, :c], \"[:a, -^a-, :c]\", \"[:a, +:b+, :c]\", pins)\n\n    refute_diff(\n      [x, :a, :b, :c, :d] = [:a, :b, :c, :d, :e],\n      \"[x, -:a-, :b, :c, :d]\",\n      \"[:a, :b, :c, :d, +:e+]\"\n    )\n\n    refute_diff([:a, :b] = :a, \"-[:a, :b]-\", \"+:a+\")\n    refute_diff([:foo] = [:foo, {:a, :b, :c}], \"[:foo]\", \"[:foo, +{:a, :b, :c}+]\")\n\n    refute_diff([{:foo}] = [{:bar}], \"[{-:foo-}]\", \"[{+:bar+}]\")\n    refute_diff(^list_tuple = [{:bar}], \"-^list_tuple-\", \"[{+:bar+}]\", pins)\n  end\n\n  test \"improper lists\" do\n    assert_diff([:a | :b] = [:a | :b], [])\n    assert_diff([:a, :b | :c] = [:a, :b | :c], [])\n\n    refute_diff([:a | :b] = [:b | :a], \"[-:a- | -:b-]\", \"[+:b+ | +:a+]\")\n    refute_diff([:a | :b] = [:a | :x], \"[:a | -:b-]\", \"[:a | +:x+]\")\n    refute_diff([:a, :b | :c] = [:a, :b | :x], \"[:a, :b | -:c-]\", \"[:a, :b | +:x+]\")\n    refute_diff([:a, :x | :c] = [:a, :b | :c], \"[:a, -:x- | :c]\", \"[:a, +:b+ | :c]\")\n    refute_diff([:x, :b | :c] = [:a, :b | :c], \"[-:x-, :b | :c]\", \"[+:a+, :b | :c]\")\n    refute_diff([:c, :a | :b] = [:a, :b | :c], \"[-:c-, :a | -:b-]\", \"[:a, +:b+ | +:c+]\")\n\n    refute_diff(\n      [:a, :c, :x | :b] = [:a, :b, :c | :d],\n      \"[:a, :c, -:x- | -:b-]\",\n      \"[:a, +:b+, :c | +:d+]\"\n    )\n\n    refute_diff([:a | :d] = [:a, :b, :c | :d], \"[:a | -:d-]\", \"[:a, +:b+, +:c+ | +:d+]\")\n\n    refute_diff(\n      [[:a | :x], :x | :d] = [[:a | :b], :c | :d],\n      \"[[:a | -:x-], -:x- | :d]\",\n      \"[[:a | +:b+], +:c+ | :d]\"\n    )\n\n    assert_diff([:a | x] = [:a | :b], x: :b)\n\n    refute_diff(\n      [[[[], \"Hello, \"] | \"world\"] | \"!\"] ==\n        [[[[], \"Hello \"] | \"world\"] | \"!\"],\n      \"[[[[], \\\"Hello-,- \\\"] | \\\"world\\\"] | \\\"!\\\"]\",\n      \"[[[[], \\\"Hello \\\"] | \\\"world\\\"] | \\\"!\\\"]\"\n    )\n\n    refute_diff(:foo = %{bar: [:a | :b]}, \"\", \"\")\n  end\n\n  test \"proper lists\" do\n    assert_diff([:a | [:b]] = [:a, :b], [])\n    assert_diff([:a | [:b, :c]] = [:a, :b, :c], [])\n\n    refute_diff([:a | [:b]] = [:a, :x], \"[:a | [-:b-]]\", \"[:a, +:x+]\")\n\n    refute_diff([:a, :b | [:c]] = [:a, :b, :x], \"[:a, :b | [-:c-]]\", \"[:a, :b, +:x+]\")\n    refute_diff([:a, :x | [:c]] = [:a, :b, :c], \"[:a, -:x- | [:c]]\", \"[:a, +:b+, :c]\")\n    refute_diff([:a | [:b, :c]] = [:a, :b, :x], \"[:a | [:b, -:c-]]\", \"[:a, :b, +:x+]\")\n    refute_diff([:a | [:b, :c]] = [:x, :b, :c], \"[-:a- | [:b, :c]]\", \"[+:x+, :b, :c]\")\n\n    refute_diff(\n      [:a, :c, :x | [:b, :c]] = [:a, :b, :c, :d, :e],\n      \"[:a, -:c-, -:x- | [:b, :c]]\",\n      \"[:a, :b, :c, +:d+, +:e+]\"\n    )\n\n    refute_diff([:a, :b | [:c]] = [:a, :b], \"[:a, :b | [-:c-]]\", \"[:a, :b]\")\n    refute_diff([:a, :b | []] = [:a, :b, :c], \"[:a, :b | []]\", \"[:a, :b, +:c+]\")\n    refute_diff([:a, :b | [:c, :d]] = [:a, :b, :c], \"[:a, :b | [:c, -:d-]]\", \"[:a, :b, :c]\")\n    refute_diff([:a, :b | [:c, :d]] = [:a], \"[:a, -:b- | [-:c-, -:d-]]\", \"[:a]\")\n\n    refute_diff(\n      [:a, [:b, :c] | [:d, :e]] = [:a, [:x, :y], :d, :e],\n      \"[:a, [-:b-, -:c-] | [:d, :e]]\",\n      \"[:a, [+:x+, +:y+], :d, :e]\"\n    )\n\n    refute_diff(\n      [:a, [:b, :c] | [:d, :e]] = [:a, [:x, :c], :d, :e],\n      \"[:a, [-:b-, :c] | [:d, :e]]\",\n      \"[:a, [+:x+, :c], :d, :e]\"\n    )\n\n    assert_diff([:a | x] = [:a, :b], x: [:b])\n    assert_diff([:a | x] = [:a, :b, :c], x: [:b, :c])\n    assert_diff([:a | x] = [:a, :b | :c], x: [:b | :c])\n\n    pins = %{{:list_bc, nil} => [:b, :c]}\n    assert_diff([:a | ^list_bc] = [:a, :b, :c], [], pins)\n    refute_diff([:a | ^list_bc] = [:x, :x, :c], \"[-:a- | -^list_bc-]\", \"[+:x+, +:x+, :c]\", pins)\n    refute_diff([:a | ^list_bc] = [:a, :x, :c], \"[:a | -^list_bc-]\", \"[:a, +:x+, :c]\", pins)\n  end\n\n  test \"concat lists\" do\n    assert_diff([:a] ++ [:b] = [:a, :b], [])\n    assert_diff([:a, :b] ++ [] = [:a, :b], [])\n    assert_diff([] ++ [:a, :b] = [:a, :b], [])\n\n    refute_diff([:a, :b] ++ [:c] = [:a, :b], \"[:a, :b] ++ [-:c-]\", \"[:a, :b]\")\n    refute_diff([:a, :c] ++ [:b] = [:a, :b], \"[:a, -:c-] ++ [:b]\", \"[:a, :b]\")\n    refute_diff([:a] ++ [:b] ++ [:c] = [:a, :b], \"[:a] ++ [:b] ++ [-:c-]\", \"[:a, :b]\")\n\n    assert_diff([:a] ++ :b = [:a | :b], [])\n    assert_diff([:a] ++ x = [:a, :b], x: [:b])\n\n    refute_diff([:a, :b] ++ :c = [:a, :b, :c], \"[:a, :b] ++ -:c-\", \"[:a, :b, +:c+]\")\n    refute_diff([:a] ++ [:b] ++ :c = [:a, :b, :c], \"[:a] ++ [:b] ++ -:c-\", \"[:a, :b, +:c+]\")\n    refute_diff([:a] ++ [:b] = :a, \"-[:a] ++ [:b]-\", \"+:a+\")\n  end\n\n  @a [:a]\n  test \"concat lists with module attributes\" do\n    assert_diff(@a ++ [:b] = [:a, :b], [])\n    refute_diff(@a ++ [:b] = [:a], \"[:a] ++ [-:b-]\", \"[:a]\")\n    refute_diff(@a ++ [:b] = [:b], \"[-:a-] ++ [:b]\", \"[:b]\")\n  end\n\n  test \"mixed lists\" do\n    refute_diff([:a | :b] = [:a, :b], \"[:a | -:b-]\", \"[:a, +:b+]\")\n    refute_diff([:a, :b] = [:a | :b], \"[:a, -:b-]\", \"[:a | +:b+]\")\n    refute_diff([:a | [:b]] = [:a | :b], \"[:a | -[:b]-]\", \"[:a | +:b+]\")\n    refute_diff([:a | [:b | [:c]]] = [:a | :c], \"[:a | -[:b | [:c]]-]\", \"[:a | +:c+]\")\n    refute_diff([:a | :b] = [:a, :b, :c], \"[:a | -:b-]\", \"[:a, +:b+, +:c+]\")\n    refute_diff([:a, :b, :c] = [:a | :b], \"[:a, -:b-, -:c-]\", \"[:a | +:b+]\")\n\n    refute_diff([:a | [:b] ++ [:c]] = [:a, :b], \"[:a | [:b] ++ [-:c-]]\", \"[:a, :b]\")\n\n    refute_diff(\n      [:a | [:b] ++ [:c]] ++ [:d | :e] = [:a, :b | :e],\n      \"[:a | [:b] ++ [-:c-]] ++ [-:d- | :e]\",\n      \"[:a, :b | :e]\"\n    )\n  end\n\n  test \"lists outside of match context\" do\n    refute_diff(\n      [%_{i_will: :fail}, %_{i_will: :fail_too}] = [],\n      \"[-%_{i_will: :fail}-, -%_{i_will: :fail_too}-]\",\n      \"[]\"\n    )\n\n    refute_diff(\n      [:a, {:|, [], [:b, :c]}] == [:a, :b | :c],\n      \"[:a, -{:|, [], [:b, :c]}-]\",\n      \"[:a, +:b+ | +:c+]\"\n    )\n\n    refute_diff([:foo] == [:foo, {:a, :b, :c}], \"[:foo]\", \"[:foo, +{:a, :b, :c}+]\")\n    refute_diff([:foo, {:a, :b, :c}] == [:foo], \"[:foo, -{:a, :b, :c}-]\", \"[:foo]\")\n\n    refute_diff([:foo] == [:foo | {:a, :b, :c}], \"[:foo]\", \"[:foo | +{:a, :b, :c}+]\")\n    refute_diff([:foo | {:a, :b, :c}] == [:foo], \"[:foo | -{:a, :b, :c}-]\", \"[:foo]\")\n    refute_diff([:foo] == [{:a, :b, :c} | :foo], \"[-:foo-]\", \"[+{:a, :b, :c}+ | +:foo+]\")\n    refute_diff([{:a, :b, :c} | :foo] == [:foo], \"[-{:a, :b, :c}- | -:foo-]\", \"[+:foo+]\")\n  end\n\n  test \"keyword lists\" do\n    assert_diff([file: \"nofile\", line: 1] = [file: \"nofile\", line: 1], [])\n\n    refute_diff(\n      [file: \"nofile\", line: 1] = [file: nil, lime: 1],\n      ~s/[file: -\"nofile\"-, -line:- 1]/,\n      \"[file: +nil+, +lime:+ 1]\"\n    )\n\n    refute_diff(\n      [file: nil, line: 1] = [file: \"nofile\"],\n      \"[file: -nil-, -line: 1-]\",\n      ~s/[file: +\"nofile\"+]/\n    )\n\n    refute_diff(\n      [\"foo-bar\": 1] = [],\n      ~s/[-\"foo-bar\": 1-]/,\n      \"[]\"\n    )\n\n    refute_diff(\n      [file: nil] = [{:line, 1}, {1, :foo}],\n      \"[-file:- -nil-]\",\n      \"[{+:line+, +1+}, +{1, :foo}+]\"\n    )\n  end\n\n  test \"tuples\" do\n    assert_diff({:a, :b} = {:a, :b}, [])\n\n    refute_diff({:a, :b} = {:a, :x}, \"{:a, -:b-}\", \"{:a, +:x+}\")\n    refute_diff({:a, :b} = {:x, :x}, \"{-:a-, -:b-}\", \"{+:x+, +:x+}\")\n    refute_diff({:a, :b, :c} = {:a, :b, :x}, \"{:a, :b, -:c-}\", \"{:a, :b, +:x+}\")\n\n    refute_diff({:a} = {:a, :b}, \"{:a}\", \"{:a, +:b+}\")\n    refute_diff({:a, :b} = {:a}, \"{:a, -:b-}\", \"{:a}\")\n\n    refute_diff({:ok, value} = {:error, :fatal}, \"{-:ok-, value}\", \"{+:error+, :fatal}\")\n    refute_diff({:a, :b} = :a, \"-{:a, :b}-\", \"+:a+\")\n\n    refute_diff({:foo} = {:foo, {:a, :b, :c}}, \"{:foo}\", \"{:foo, +{:a, :b, :c}+}\")\n  end\n\n  test \"tuples outside of match context\" do\n    assert_diff({:a, :b} == {:a, :b}, [])\n\n    refute_diff({:a} == {:a, :b}, \"{:a}\", \"{:a, +:b+}\")\n    refute_diff({:a, :b} == {:a}, \"{:a, -:b-}\", \"{:a}\")\n\n    refute_diff({:{}, [], [:a]} == {:a}, \"{-:{}-, -[]-, -[:a]-}\", \"{+:a+}\")\n    refute_diff({:{}, [], [:a]} == :a, \"-{:{}, [], [:a]}-\", \"+:a+\")\n    refute_diff({:a, :b, :c} == {:a, :b, :x}, \"{:a, :b, -:c-}\", \"{:a, :b, +:x+}\")\n\n    refute_diff({:foo} == {:foo, {:a, :b, :c}}, \"{:foo}\", \"{:foo, +{:a, :b, :c}+}\")\n    refute_diff({:foo, {:a, :b, :c}} == {:foo}, \"{:foo, -{:a, :b, :c}-}\", \"{:foo}\")\n  end\n\n  test \"maps\" do\n    assert_diff(%{a: 1} = %{a: 1}, [])\n    assert_diff(%{a: 1} = %{a: 1, b: 2}, [])\n    assert_diff(%{a: 1, b: 2} = %{a: 1, b: 2}, [])\n    assert_diff(%{b: 2, a: 1} = %{a: 1, b: 2}, [])\n    assert_diff(%{a: 1, b: 2, c: 3} = %{a: 1, b: 2, c: 3}, [])\n    assert_diff(%{c: 3, b: 2, a: 1} = %{a: 1, b: 2, c: 3}, [])\n\n    refute_diff(%{a: 1, b: 2} = %{a: 1}, \"%{a: 1, -b: 2-}\", \"%{a: 1}\")\n    refute_diff(%{a: 1, b: 2} = %{a: 1, b: 12}, \"%{a: 1, b: 2}\", \"%{a: 1, b: +1+2}\")\n    refute_diff(%{a: 1, b: 2} = %{a: 1, c: 2}, \"%{a: 1, -b: 2-}\", \"%{a: 1, c: 2}\")\n    refute_diff(%{a: 1, b: 2, c: 3} = %{a: 1, b: 12}, \"%{a: 1, b: 2, -c: 3-}\", \"%{a: 1, b: +1+2}\")\n    refute_diff(%{a: 1, b: 2, c: 3} = %{a: 1, c: 2}, \"%{a: 1, c: -3-, -b: 2-}\", \"%{a: 1, c: +2+}\")\n    refute_diff(%{a: 1} = %{a: 2, b: 2, c: 3}, \"%{a: -1-}\", \"%{a: +2+, b: 2, c: 3}\")\n\n    refute_diff(\n      %{1 => :a, 2 => :b} = %{1 => :a, 12 => :b},\n      \"%{1 => :a, -2 => :b-}\",\n      \"%{1 => :a, 12 => :b}\"\n    )\n\n    refute_diff(\n      %{1 => :a, 2 => :b} = %{1 => :a, :b => 2},\n      \"%{1 => :a, -2 => :b-}\",\n      \"%{1 => :a, :b => 2}\"\n    )\n\n    pins = %{{:a, nil} => :a, {:b, nil} => :b}\n    assert_diff(%{^a => 1} = %{a: 1}, [], pins)\n    assert_diff(%{^a => x} = %{a: 1}, [x: 1], pins)\n\n    refute_diff(%{^a => 1, :a => 2} = %{a: 1}, \"%{^a => 1, -:a => 2-}\", \"%{a: 1}\", pins)\n\n    refute_diff(\n      %{^a => x, ^b => x} = %{a: 1, b: 2},\n      \"%{^a => x, ^b => -x-}\",\n      \"%{a: 1, b: +2+}\",\n      pins\n    )\n\n    refute_diff(%{a: 1} = :a, \"-%{a: 1}-\", \"+:a+\")\n  end\n\n  test \"maps as pinned map value\" do\n    user = %{\"id\" => 13, \"name\" => \"john\"}\n\n    notification = %{\n      \"user\" => user,\n      \"subtitle\" => \"foo\"\n    }\n\n    assert_diff(\n      %{\n        \"user\" => ^user,\n        \"subtitle\" => \"foo\"\n      } = notification,\n      [],\n      %{{:user, nil} => user}\n    )\n\n    refute_diff(\n      %{\n        \"user\" => ^user,\n        \"subtitle\" => \"bar\"\n      } = notification,\n      ~s|%{\"subtitle\" => \"-bar-\", \"user\" => ^user}|,\n      ~s|%{\"subtitle\" => \"+foo+\", \"user\" => %{\"id\" => 13, \"name\" => \"john\"}}|,\n      %{{:user, nil} => user}\n    )\n  end\n\n  test \"maps outside match context\" do\n    assert_diff(%{a: 1} == %{a: 1}, [])\n    assert_diff(%{a: 1, b: 2} == %{a: 1, b: 2}, [])\n    assert_diff(%{b: 2, a: 1} == %{a: 1, b: 2}, [])\n    assert_diff(%{a: 1, b: 2, c: 3} == %{a: 1, b: 2, c: 3}, [])\n    assert_diff(%{c: 3, b: 2, a: 1} == %{a: 1, b: 2, c: 3}, [])\n\n    refute_diff(%{a: 1} == %{a: 1, b: 2}, \"%{a: 1}\", \"%{a: 1, +b: 2+}\")\n    refute_diff(%{a: 1, b: 2} == %{a: 1}, \"%{a: 1, -b: 2-}\", \"%{a: 1}\")\n    refute_diff(%{a: 1, b: 12} == %{a: 1, b: 2}, \"%{a: 1, b: -1-2}\", \"%{a: 1, b: 2}\")\n    refute_diff(%{a: 1, b: 2} == %{a: 1, b: 12}, \"%{a: 1, b: 2}\", \"%{a: 1, b: +1+2}\")\n    refute_diff(%{a: 1, b: 2} == %{a: 1, c: 2}, \"%{a: 1, -b: 2-}\", \"%{a: 1, +c: 2+}\")\n\n    refute_diff(\n      %{name: {:a, :b, :c}} == :error,\n      \"-%{name: {:a, :b, :c}}\",\n      \"+:error+\"\n    )\n  end\n\n  test \"structs\" do\n    assert_diff(%User{age: 16} = %User{age: 16}, [])\n    assert_diff(%{age: 16, __struct__: User} = %User{age: 16}, [])\n\n    refute_diff(\n      %User{age: 16} = %User{age: 21},\n      \"%ExUnit.DiffTest.User{age: 1-6-}\",\n      \"%ExUnit.DiffTest.User{age: +2+1, name: nil}\"\n    )\n\n    refute_diff(\n      %User{age: 16} = %Person{age: 21},\n      \"%-ExUnit.DiffTest.User-{age: 1-6-}\",\n      \"%+ExUnit.DiffTest.Person+{age: +2+1}\"\n    )\n\n    refute_diff(\n      %User{age: 16} = %Person{age: 21},\n      \"%-ExUnit.DiffTest.User-{age: 1-6-}\",\n      \"%+ExUnit.DiffTest.Person+{age: +2+1}\"\n    )\n\n    refute_diff(\n      %User{age: 16} = %{age: 16},\n      \"%-ExUnit.DiffTest.User-{age: 16}\",\n      \"%{age: 16}\"\n    )\n\n    refute_diff(\n      %User{age: 16} = %{age: 21},\n      \"%-ExUnit.DiffTest.User-{age: 1-6-}\",\n      \"%{age: +2+1}\"\n    )\n\n    refute_diff(\n      %{age: 16, __struct__: Person} = %User{age: 16},\n      \"%-ExUnit.DiffTest.Person-{age: 16}\",\n      \"%+ExUnit.DiffTest.User+{age: 16, name: nil}\"\n    )\n\n    pins = %{{:twenty_one, nil} => 21}\n    assert_diff(%User{age: ^twenty_one} = %User{age: 21}, [], pins)\n    assert_diff(%User{age: age} = %User{age: 21}, [age: 21], pins)\n    refute_diff(%User{age: 21} = :a, \"-%ExUnit.DiffTest.User{age: 21}-\", \"+:a+\", pins)\n  end\n\n  test \"structs outside of match context\" do\n    assert_diff(%User{age: 16} == %User{age: 16}, [])\n    assert_diff(%{age: 16, __struct__: User, name: nil} == %User{age: 16}, [])\n\n    refute_diff(\n      %User{age: 16} == %{age: 16},\n      \"%-ExUnit.DiffTest.User-{age: 16, -name: nil-}\",\n      \"%{age: 16}\"\n    )\n\n    refute_diff(\n      %User{age: 16} == %User{age: 21},\n      \"%ExUnit.DiffTest.User{age: 1-6-, name: nil}\",\n      \"%ExUnit.DiffTest.User{age: +2+1, name: nil}\"\n    )\n\n    refute_diff(\n      %User{age: 16} == %Person{age: 21},\n      \"%-ExUnit.DiffTest.User-{age: 1-6-, -name: nil-}\",\n      \"%+ExUnit.DiffTest.Person+{age: +2+1}\"\n    )\n  end\n\n  test \"structs with inspect\" do\n    refute_diff(\n      ~D[2017-10-01] = ~D[2017-10-02],\n      ~s/-~D[2017-10-01]-/,\n      \"~D[2017-10-0+2+]\"\n    )\n\n    refute_diff(\n      \"2017-10-01\" = ~D[2017-10-02],\n      ~s/-\"2017-10-01\"-/,\n      \"+~D[2017-10-02]+\"\n    )\n\n    refute_diff(\n      ~D[2017-10-02] = \"2017-10-01\",\n      ~s/-~D[2017-10-02]-/,\n      ~s/+\"2017-10-01\"+/\n    )\n\n    refute_diff(\n      ~HTML[hi] = ~HTML[bye],\n      \"-~HTML[hi]-\",\n      \"~HTML[+bye+]\"\n    )\n  end\n\n  test \"structs with missing keys on match\" do\n    struct = %User{\n      age: ~U[2020-07-30 13:49:59.253158Z]\n    }\n\n    assert_diff(%User{age: %DateTime{}} = struct, [])\n\n    refute_diff(\n      %User{age: %Date{}} = struct,\n      ~s/%ExUnit.DiffTest.User{age: %-Date-{}}/,\n      \"\"\"\n      %ExUnit.DiffTest.User{\n        age: %+DateTime+{\n          calendar: Calendar.ISO,\n          day: 30,\n          hour: 13,\n          microsecond: {253158, 6},\n          minute: 49,\n          month: 7,\n          second: 59,\n          std_offset: 0,\n          time_zone: \"Etc\\/UTC\",\n          utc_offset: 0,\n          year: 2020,\n          zone_abbr: \"UTC\"\n        },\n        name: nil\n      }\\\n      \"\"\"\n    )\n\n    refute_diff(\n      %{age: %Date{}} = struct,\n      ~s/%{age: %-Date-{}}/,\n      \"\"\"\n      %ExUnit.DiffTest.User{\n        age: %+DateTime+{\n          calendar: Calendar.ISO,\n          day: 30,\n          hour: 13,\n          microsecond: {253158, 6},\n          minute: 49,\n          month: 7,\n          second: 59,\n          std_offset: 0,\n          time_zone: \\\"Etc/UTC\\\",\n          utc_offset: 0,\n          year: 2020,\n          zone_abbr: \\\"UTC\\\"\n        },\n        name: nil\n      }\\\n      \"\"\"\n    )\n  end\n\n  test \"structs with inspect outside match context\" do\n    refute_diff(\n      ~D[2017-10-01] == ~D[2017-10-02],\n      \"~D[2017-10-0-1-]\",\n      \"~D[2017-10-0+2+]\"\n    )\n\n    refute_diff(\n      \"2017-10-01\" == ~D[2017-10-02],\n      ~s/-\"2017-10-01\"-/,\n      \"+~D[2017-10-02]+\"\n    )\n\n    refute_diff(\n      ~D[2017-10-02] == \"2017-10-01\",\n      ~s/-~D[2017-10-02]-/,\n      ~s/+\"2017-10-01\"+/\n    )\n\n    refute_diff(\n      ~HTML[hi] == ~HTML[bye],\n      \"~HTML[-hi-]\",\n      \"~HTML[+bye+]\"\n    )\n  end\n\n  test \"structs with same inspect but different inside match\" do\n    refute_diff(\n      %Opaque{data: 1} = %Opaque{data: 2},\n      \"%ExUnit.DiffTest.Opaque{data: -1-}\",\n      \"%ExUnit.DiffTest.Opaque{data: +2+}\"\n    )\n\n    refute_diff(\n      %Opaque{data: %{hello: :world}} = %Opaque{data: %{hello: \"world\"}},\n      \"#Opaque<data: %{hello: -:-world}>\",\n      \"#Opaque<data: %{hello: +\\\"+world+\\\"+}>\"\n    )\n  end\n\n  test \"structs with same inspect but different outside match\" do\n    refute_diff(\n      %Opaque{data: 1} == %Opaque{data: 2},\n      \"%ExUnit.DiffTest.Opaque{data: -1-}\",\n      \"%ExUnit.DiffTest.Opaque{data: +2+}\"\n    )\n\n    refute_diff(\n      %Opaque{data: %{hello: :world}} == %Opaque{data: %{hello: \"world\"}},\n      \"#Opaque<data: %{hello: -:-world}>\",\n      \"#Opaque<data: %{hello: +\\\"+world+\\\"+}>\"\n    )\n  end\n\n  test \"structs with inspect in a list\" do\n    refute_diff(\n      Enum.sort([~D[2019-03-31], ~D[2019-04-01]]) == [~D[2019-03-31], ~D[2019-04-01]],\n      \"[-~D[2019-04-01]-, ~D[2019-03-31]]\",\n      \"[~D[2019-03-31], +~D[2019-04-01]+]\"\n    )\n  end\n\n  test \"structs with matched type\" do\n    pins = %{{:type, nil} => User, {:age, nil} => 33}\n\n    # pin on __struct__\n    assert_diff(\n      %{__struct__: ^type, age: ^age, name: \"john\"} = %User{name: \"john\", age: 33},\n      [],\n      pins\n    )\n\n    refute_diff(\n      %{__struct__: ^type, age: ^age, name: \"john\"} = %User{name: \"jane\", age: 33},\n      \"%{__struct__: ^type, age: ^age, name: \\\"j-oh-n\\\"}\",\n      \"%ExUnit.DiffTest.User{age: 33, name: \\\"j+a+n+e+\\\"}\",\n      pins\n    )\n\n    refute_diff(\n      %{__struct__: ^type, age: ^age, name: \"john\"} = %User{name: \"john\", age: 35},\n      \"%{__struct__: ^type, age: -^age-, name: \\\"john\\\"}\",\n      \"%ExUnit.DiffTest.User{age: 3+5+, name: \\\"john\\\"}\",\n      pins\n    )\n\n    refute_diff(\n      %{__struct__: ^type, age: ^age, name: \"john\"} = ~D[2020-01-01],\n      \"%{__struct__: -^type-, -age: ^age-, -name: \\\"john\\\"-}\",\n      \"%+Date+{calendar: Calendar.ISO, day: 1, month: 1, year: 2020}\",\n      pins\n    )\n\n    # pin on %\n    assert_diff(\n      %^type{age: ^age, name: \"john\"} = %User{name: \"john\", age: 33},\n      [],\n      pins\n    )\n\n    refute_diff(\n      %^type{age: ^age, name: \"john\"} = %User{name: \"jane\", age: 33},\n      \"%{__struct__: ^type, age: ^age, name: \\\"j-oh-n\\\"}\",\n      \"%ExUnit.DiffTest.User{age: 33, name: \\\"j+a+n+e+\\\"}\",\n      pins\n    )\n\n    refute_diff(\n      %^type{age: ^age, name: \"john\"} = %User{name: \"john\", age: 35},\n      \"%{__struct__: ^type, age: -^age-, name: \\\"john\\\"}\",\n      \"%ExUnit.DiffTest.User{age: 3+5+, name: \\\"john\\\"}\",\n      pins\n    )\n\n    refute_diff(\n      %^type{age: ^age, name: \"john\"} = ~D[2020-01-01],\n      \"%{__struct__: -^type-, -age: ^age-, -name: \\\"john\\\"-}\",\n      \"%+Date+{calendar: Calendar.ISO, day: 1, month: 1, year: 2020}\",\n      pins\n    )\n\n    # right side is not map-like\n    refute_diff(\n      %^type{age: ^age, name: \"john\"} = nil,\n      \"-%^type{age: ^age, name: \\\"john\\\"}-\",\n      \"+nil+\",\n      pins\n    )\n  end\n\n  test \"invalid structs\" do\n    refute_diff(\n      %{__struct__: Unknown} = %{},\n      \"%{-__struct__: Unknown-}\",\n      \"%{}\"\n    )\n\n    refute_diff(\n      %{__struct__: Date, unknown: :field} = %{},\n      \"%{-__struct__: Date-, -unknown: :field-}\",\n      \"%{}\"\n    )\n  end\n\n  test \"maps in lists\" do\n    map = %{\n      \"address\" => %{\n        \"street\" => \"123 Main St\",\n        \"zip\" => \"62701\"\n      },\n      \"age\" => 30,\n      \"first_name\" => \"John\",\n      \"language\" => \"en-US\",\n      \"last_name\" => \"Doe\",\n      \"notifications\" => true\n    }\n\n    refute_diff(\n      [map] == [],\n      \"\"\"\n      [\n        -%{\n          \"address\" => %{\"street\" => \"123 Main St\", \"zip\" => \"62701\"},\n          \"age\" => 30,\n          \"first_name\" => \"John\",\n          \"language\" => \"en-US\",\n          \"last_name\" => \"Doe\",\n          \"notifications\" => true\n        }-\n      ]\\\n      \"\"\",\n      \"[]\"\n    )\n\n    refute_diff(\n      [] == [map],\n      \"[]\",\n      \"\"\"\n      [\n        +%{\n          \"address\" => %{\"street\" => \"123 Main St\", \"zip\" => \"62701\"},\n          \"age\" => 30,\n          \"first_name\" => \"John\",\n          \"language\" => \"en-US\",\n          \"last_name\" => \"Doe\",\n          \"notifications\" => true\n        }+\n      ]\\\n      \"\"\"\n    )\n\n    assert_diff([map] == [map], [])\n  end\n\n  test \"structs in lists\" do\n    customer = %Customer{\n      address: %{\n        \"street\" => \"123 Main St\",\n        \"zip\" => \"62701\"\n      },\n      age: 30,\n      first_name: \"John\",\n      language: \"en-US\",\n      last_name: \"Doe\",\n      notifications: true\n    }\n\n    refute_diff(\n      [customer] == [],\n      \"\"\"\n      [\n        -%ExUnit.DiffTest.Customer{\n          address: %{\"street\" => \"123 Main St\", \"zip\" => \"62701\"},\n          age: 30,\n          first_name: \"John\",\n          language: \"en-US\",\n          last_name: \"Doe\",\n          notifications: true\n        }-\n      ]\\\n      \"\"\",\n      \"[]\"\n    )\n\n    refute_diff(\n      [] == [customer],\n      \"[]\",\n      \"\"\"\n      [\n        +%ExUnit.DiffTest.Customer{\n          address: %{\"street\" => \"123 Main St\", \"zip\" => \"62701\"},\n          age: 30,\n          first_name: \"John\",\n          language: \"en-US\",\n          last_name: \"Doe\",\n          notifications: true\n        }+\n      ]\\\n      \"\"\"\n    )\n\n    assert_diff([customer] == [customer], [])\n  end\n\n  test \"maps and structs with escaped values\" do\n    refute_diff(\n      %User{age: {1, 2, 3}} = %User{age: {1, 2, 4}},\n      \"%ExUnit.DiffTest.User{age: {1, 2, -3-}}\",\n      \"%ExUnit.DiffTest.User{age: {1, 2, +4+}, name: nil}\"\n    )\n\n    refute_diff(\n      %User{age: {1, 2, 3}, name: name} = %User{age: {1, 2, 4}},\n      \"%ExUnit.DiffTest.User{age: {1, 2, -3-}, name: name}\",\n      \"%ExUnit.DiffTest.User{age: {1, 2, +4+}, name: nil}\"\n    )\n\n    refute_diff(\n      %User{name: :foo} = %User{name: :bar, age: {1, 2, 3}},\n      \"%ExUnit.DiffTest.User{name: -:foo-}\",\n      \"%ExUnit.DiffTest.User{name: +:bar+, age: {1, 2, 3}}\"\n    )\n\n    refute_diff(\n      %User{age: {1, 2, 3}} == %User{age: {1, 2, 4}},\n      \"%ExUnit.DiffTest.User{age: {1, 2, -3-}, name: nil}\",\n      \"%ExUnit.DiffTest.User{age: {1, 2, +4+}, name: nil}\"\n    )\n\n    refute_diff(\n      %User{age: {1, 2, 4}} == %User{age: {1, 2, 3}},\n      \"%ExUnit.DiffTest.User{age: {1, 2, -4-}, name: nil}\",\n      \"%ExUnit.DiffTest.User{age: {1, 2, +3+}, name: nil}\"\n    )\n\n    refute_diff(\n      %{name: :foo} == %{name: :foo, age: {1, 2, 3}},\n      \"%{name: :foo}\",\n      \"%{name: :foo, +age: {1, 2, 3}+}\"\n    )\n\n    refute_diff(\n      %{name: :foo, age: {1, 2, 3}} == %{name: :foo},\n      \"%{name: :foo, -age: {1, 2, 3}-}\",\n      \"%{name: :foo}\"\n    )\n  end\n\n  test \"strings\" do\n    assert_diff(\"\" = \"\", [])\n    assert_diff(\"fox hops over the dog\" = \"fox hops over the dog\", [])\n\n    refute_diff(\"fox\" = \"foo\", \"fo-x-\", \"fo+o+\")\n\n    refute_diff(\n      \"fox hops over \\\"the dog\" = \"fox  jumps over the  lazy cat\",\n      ~s/\"fox -ho-ps over -\\\\\\\"-the -dog-\"/,\n      ~s/\"fox + jum+ps over the + lazy cat+\"/\n    )\n\n    refute_diff(\n      \"short\" = \"really long string that should not emit diff against short\",\n      ~s/\"-short-\"/,\n      ~s/\"+really long string that should not emit diff against short+\"/\n    )\n\n    refute_diff(\"foo\" = :a, ~s/-\"foo\"-/, \"+:a+\")\n  end\n\n  test \"strings outside match context\" do\n    assert_diff(\"\" == \"\", [])\n    assert_diff(\"fox hops over the dog\" == \"fox hops over the dog\", [])\n    refute_diff(\"fox\" == \"foo\", \"fo-x-\", \"fo+o+\")\n\n    refute_diff(\n      \"{\\\"foo\\\":1,\\\"barbaz\\\":[1,2,3]}\" == \"4\",\n      ~s/\"-{\\\\\\\"foo\\\\\\\":1,\\\\\\\"barbaz\\\\\\\":[1,2,3]}-\"/,\n      ~s/\"+4+\"/\n    )\n  end\n\n  test \"concat binaries\" do\n    assert_diff(\"fox hops\" <> _ = \"fox hops over the dog\", [])\n    assert_diff(\"fox hops\" <> \" over the dog\" = \"fox hops over the dog\", [])\n    assert_diff(\"fox hops \" <> \"over \" <> \"the dog\" = \"fox hops over the dog\", [])\n\n    refute_diff(\n      \"fox hops\" <> _ = \"dog hops over the fox\",\n      ~s/\"-f-o-x- hops\" <> _/,\n      ~s/+d+o+g+ hops over the fox/\n    )\n\n    refute_diff(\n      \"fox hops\" <> \" under the dog\" = \"fox hops over the dog\",\n      ~s/\"fox hops\" <> \" -und-er the dog\"/,\n      ~s/\"fox hops +ov+er the dog\"/\n    )\n\n    refute_diff(\n      \"fox hops over\" <> \" the dog\" = \"fox hops over\",\n      ~s/\"fox hops over\" <> \"- the dog-\"/,\n      ~s/\"fox hops over\"/\n    )\n\n    refute_diff(\n      \"fox hops\" <> \" over the dog\" = \"fox\",\n      ~s/\"-fox hops-\" <> \"- over the dog-\"/,\n      ~s/\"+fox+\"/\n    )\n\n    refute_diff(\n      \"fox\" <> \" hops\" = \"fox h\",\n      ~s/\"fox\" <> \" h-ops-\"/,\n      ~s/\"fox h\"/\n    )\n\n    refute_diff(\n      \"fox hops \" <> \"hover \" <> \"the dog\" = \"fox hops over the dog\",\n      ~s/\"fox hops \" <> \"-h-over \" <> \"the dog\"/,\n      ~s/\"fox hops over the dog\"/\n    )\n\n    refute_diff(\"fox\" <> \" hops\" = :a, ~s/-\"fox\" <> \" hops\"-/, \"+:a+\")\n  end\n\n  test \"concat binaries with pin\" do\n    pins = %{{:x, nil} => \" over the dog\"}\n\n    assert_diff(\"fox hops\" <> x = \"fox hops over the dog\", x: \" over the dog\")\n    assert_diff(\"fox hops \" <> \"over \" <> x = \"fox hops over the dog\", x: \"the dog\")\n    assert_diff(\"fox hops\" <> ^x = \"fox hops over the dog\", [], pins)\n\n    refute_diff(\n      \"fox hops \" <> \"hover \" <> x = \"fox hops over the dog\",\n      ~s/\"fox hops \" <> \"-h-over \" <> x/,\n      ~s/\"fox hops over +t+he dog\"/\n    )\n\n    refute_diff(\n      \"fox hops \" <> \"hover \" <> ^x = \"fox hops over the dog\",\n      ~s/\"fox hops \" <> \"-h-over \" <> -^x-/,\n      ~s/\"fox hops over +t+he dog\"/,\n      pins\n    )\n  end\n\n  test \"underscore\" do\n    assert_diff(_ = :a, [])\n    assert_diff({_, _} = {:a, :b}, [])\n\n    refute_diff({_, :a} = {:b, :b}, \"{_, -:a-}\", \"{:b, +:b+}\")\n  end\n\n  test \"macros\" do\n    assert_diff(one() = 1, [])\n    assert_diff(tuple(x, x) = {1, 1}, x: 1)\n\n    refute_diff(one() = 2, \"-1-\", \"+2+\")\n    refute_diff(tuple(x, x) = {1, 2}, \"{x, -x-}\", \"{1, +2+}\")\n\n    pins = %{{:x, nil} => 1}\n    assert_diff(pin_x() = 1, [], pins)\n    refute_diff(pin_x() = 2, \"-pin_x()-\", \"+2+\", pins)\n  end\n\n  test \"guards\" do\n    assert_diff((x when x == 0) = 0, x: 0)\n    assert_diff((x when x == 0 and is_integer(x)) = 0, x: 0)\n    assert_diff((x when x == 0 or x == 1) = 0, x: 0)\n    assert_diff((x when x == 0 when x == 1) = 0, x: 0)\n    assert_diff((x when one() == 1) = 0, x: 0)\n\n    refute_diff((x when x == 1) = 0, \"x when -x == 1-\", \"0\")\n    refute_diff((x when x == 0 and x == 1) = 0, \"x when x == 0 and -x == 1-\", \"0\")\n    refute_diff((x when x == 1 and x == 2) = 0, \"x when -x == 1- and -x == 2-\", \"0\")\n    refute_diff((x when x == 1 or x == 2) = 0, \"x when -x == 1- or -x == 2-\", \"0\")\n    refute_diff((x when x == 1 when x == 2) = 0, \"x when -x == 1- when -x == 2-\", \"0\")\n    refute_diff((x when x in [1, 2]) = 0, \"x when -x in [1, 2]-\", \"0\")\n    refute_diff(({:ok, x} when x == 1) = :error, \"-{:ok, x}- when x == 1\", \"+:error+\")\n\n    refute_diff((x when x == z) = 0, \"x when x == z\", \"0\", z: 1)\n  end\n\n  test \"blocks\" do\n    refute_diff(\n      block_head(\n        (\n          1\n          2\n        )\n      ) = 3,\n      \"1\",\n      \"3\"\n    )\n\n    refute_diff(\n      [\"foo\" | {:__block__, [], [1]}] = [\"bar\" | {:__block__, [], [2]}],\n      \"[\\\"-foo-\\\" | {:__block__, [], [-1-]}]\",\n      \"[\\\"+bar+\\\" | {:__block__, [], [+2+]}]\"\n    )\n\n    refute_diff(\n      [\"foo\" | {:__block__, [], [1]}] == [\"bar\" | {:__block__, [], [2]}],\n      \"[\\\"-foo-\\\" | {:__block__, [], [-1-]}]\",\n      \"[\\\"+bar+\\\" | {:__block__, [], [+2+]}]\"\n    )\n  end\n\n  test \"charlists\" do\n    refute_diff(\n      ~c\"fox hops over 'the dog\" = ~c\"fox jumps over the lazy cat\",\n      \"~c\\\"fox -ho-ps over -'-the -dog-\\\"\",\n      \"~c\\\"fox +jum+ps over the +lazy cat+\\\"\"\n    )\n\n    refute_diff({[], :ok} = {[], [], :ok}, \"{[], -:ok-}\", \"{[], +[]+, +:ok+}\")\n    refute_diff({[], :ok} = {~c\"foo\", [], :ok}, \"{~c\\\"--\\\", -:ok-}\", \"{~c\\\"+foo+\\\", +[]+, +:ok+}\")\n    refute_diff({~c\"foo\", :ok} = {[], [], :ok}, \"{~c\\\"-foo-\\\", -:ok-}\", \"{~c\\\"++\\\", +[]+, +:ok+}\")\n\n    refute_diff(\n      {~c\"foo\", :ok} = {~c\"bar\", [], :ok},\n      \"{~c\\\"-foo-\\\", -:ok-}\",\n      \"{~c\\\"+bar+\\\", +[]+, +:ok+}\"\n    )\n  end\n\n  test \"refs\" do\n    ref1 = make_ref()\n    ref2 = make_ref()\n\n    inspect_ref1 = inspect(ref1)\n    inspect_ref2 = inspect(ref2)\n\n    assert_diff(ref1 == ref1, [])\n    assert_diff({ref1, ref2} == {ref1, ref2}, [])\n\n    refute_diff(ref1 == ref2, \"-#{inspect_ref1}-\", \"+#{inspect_ref2}+\")\n\n    refute_diff(\n      {ref1, ref2} == {ref2, ref1},\n      \"\"\"\n      {\n        -#{inspect_ref1}-,\n        -#{inspect_ref2}-\n      }\\\n      \"\"\",\n      \"\"\"\n      {\n        +#{inspect_ref2}+,\n        +#{inspect_ref1}+\n      }\\\n      \"\"\"\n    )\n\n    refute_diff(\n      {ref1, ref2} == ref1,\n      \"-{#{inspect_ref1}, #{inspect_ref2}}-\",\n      \"+#{inspect_ref1}+\"\n    )\n\n    refute_diff(\n      ref1 == {ref1, ref2},\n      \"-#{inspect_ref1}-\",\n      \"+{#{inspect_ref1}, #{inspect_ref2}}+\"\n    )\n\n    refute_diff(ref1 == :a, \"-#{inspect_ref1}-\", \"+:a+\")\n    refute_diff({ref1, ref2} == :a, \"-{#{inspect_ref1}, #{inspect_ref2}}\", \"+:a+\")\n\n    refute_diff(\n      %{ref1 => ref2} == :a,\n      \"\"\"\n      -%{\n        #{inspect_ref1} => #{inspect_ref2}\n      }\\\n      \"\"\",\n      \"+:a+\"\n    )\n\n    refute_diff(\n      %Opaque{data: ref1} == :a,\n      \"-#Opaque<???>-\",\n      \"+:a+\"\n    )\n  end\n\n  test \"pids\" do\n    pid = self()\n    inspect_pid = inspect(pid)\n\n    assert_diff(pid == pid, [])\n    assert_diff({pid, pid} == {pid, pid}, [])\n\n    refute_diff(pid == :a, \"-#{inspect_pid}-\", \"+:a+\")\n    refute_diff({pid, pid} == :a, \"-{#{inspect_pid}, #{inspect_pid}}\", \"+:a+\")\n\n    refute_diff({pid, :a} == {:a, pid}, \"{-#{inspect_pid}-, -:a-}\", \"{+:a+, +#{inspect_pid}+}\")\n    refute_diff(%{pid => pid} == :a, \"-%{#{inspect_pid} => #{inspect_pid}}\", \"+:a+\")\n\n    refute_diff(\n      %Opaque{data: pid} == :a,\n      \"-#Opaque<???>-\",\n      \"+:a+\"\n    )\n  end\n\n  @compile {:no_warn_undefined, String}\n\n  test \"functions\" do\n    identity = & &1\n    inspect = inspect(identity)\n\n    assert_diff(identity == identity, [])\n    assert_diff({identity, identity} == {identity, identity}, [])\n\n    refute_diff(identity == :a, \"-#{inspect}-\", \"+:a+\")\n    refute_diff({identity, identity} == :a, \"-{#{inspect}, #{inspect}}\", \"+:a+\")\n    refute_diff({identity, :a} == {:a, identity}, \"{-#{inspect}-, -:a-}\", \"{+:a+, +#{inspect}+}\")\n\n    refute_diff(\n      %{identity => identity} == :a,\n      \"\"\"\n      -%{\n        #{inspect} => #{inspect}\n      }-\\\n      \"\"\",\n      \"+:a+\"\n    )\n\n    refute_diff(\n      (&String.to_charlist/1) == (&String.unknown/1),\n      \"-&String.to_charlist/1-\",\n      \"+&String.unknown/1\"\n    )\n\n    refute_diff(\n      %Opaque{data: identity} == :a,\n      \"-#Opaque<???>-\",\n      \"+:a+\"\n    )\n  end\n\n  defp closure(a), do: fn -> a end\n\n  test \"functions with closure\" do\n    closure1 = closure(1)\n    closure2 = closure(2)\n\n    fun_info = Function.info(closure1)\n    uniq = Integer.to_string(fun_info[:new_index]) <> \".\" <> Integer.to_string(fun_info[:uniq])\n\n    assert_diff(closure1 == closure1, [])\n\n    refute_diff(\n      closure1 == closure2,\n      \"#Function<\\n  #{uniq}/0 in ExUnit.DiffTest.closure/1\\n  [-1-]\\n>\",\n      \"#Function<\\n  #{uniq}/0 in ExUnit.DiffTest.closure/1\\n  [+2+]\\n>\"\n    )\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/doc_test_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.BeamHelpers do\n  # Beam files compiled on demand\n  path = Path.expand(\"../../tmp/beams\", __DIR__)\n  File.rm_rf!(path)\n  File.mkdir_p!(path)\n  Code.prepend_path(path)\n\n  def write_beam({:module, name, bin, _} = res) do\n    beam_path = Path.join(unquote(path), Atom.to_string(name) <> \".beam\")\n    File.write!(beam_path, bin)\n    res\n  end\nend\n\ndefmodule ExUnit.DocTestTest.GoodModule do\n  @doc \"\"\"\n  iex> one()\n  1\n  iex> one() + 1\n  2\n  \"\"\"\n  def one, do: 1\n\n  @doc \"\"\"\n  iex> List.flatten([])\n  \"\"\"\n  def only_call, do: :ok\n\n  @doc ~S\"\"\"\n  iex> ~S(f#{o}o)\n  \"f\\#{o}o\"\n  \"\"\"\n  def test_sigil, do: :ok\n\n  @doc \"\"\"\n  iex> a = 1\n  iex> b = a + 2\n  3\n  iex> a + b\n  4\n  \"\"\"\n  def single_context, do: :ok\n\n  @doc \"\"\"\n  iex> raise \"message\"\n  ** (RuntimeError) message\n\n  iex> raise \"message\"\n  ** (RuntimeError) message\n  \"\"\"\n  def two_exceptions, do: :ok\n\n  @doc \"\"\"\n  iex> raise \"message\"\n  ** (RuntimeError) message\n  \"\"\"\n  def exception_test, do: :ok\n\n  @doc ~S\"\"\"\n  iex> raise \"foo\\nbar\"\n  ** (RuntimeError) foo\n  bar\n  \"\"\"\n  def multiline_exception_test, do: :ok\n\n  @doc \"\"\"\n  iex> num = 1\n  iex> ExUnit.DocTestTest.GoodModule.variable_in_expectation(num)\n  num + 1\n  \"\"\"\n  def variable_in_expectation(num), do: num + 1\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.MultipleExceptions do\n  @doc \"\"\"\n  iex> 1 + \"\"\n  ** (ArithmeticError) bad argument in arithmetic expression\n  iex> 2 + \"\"\n  ** (ArithmeticError) bad argument in arithmetic expression\n  \"\"\"\n  def two_exceptions, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.SomewhatGoodModuleWithOnly do\n  @doc \"\"\"\n  iex> one()\n  1\n  iex> one() + 1\n  2\n  \"\"\"\n  def one, do: 1\n\n  @doc \"\"\"\n  iex> two()\n  2\n  iex> two() + 1\n  100\n  \"\"\"\n  def two, do: 2\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.SomewhatGoodModuleWithExcept do\n  @moduledoc \"\"\"\n  iex> 1 + 1\n  1\n  \"\"\"\n\n  @doc \"\"\"\n  iex> one()\n  1\n  iex> one() + 1\n  2\n  \"\"\"\n  def one, do: 1\n\n  @doc \"\"\"\n  iex> two()\n  2\n  iex> two() + 1\n  100\n  \"\"\"\n  def two, do: 2\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.NoImport do\n  @doc \"\"\"\n  iex> ExUnit.DocTestTest.NoImport.max(1, 2)\n  {:ok, 2}\n\n  iex> max(1, 2)\n  2\n  \"\"\"\n  def max(a, b), do: {:ok, Kernel.max(a, b)}\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.NoTrailing do\n  @doc \"    iex>1 + 2\\n    3\"\n  def no_trailing_new_line, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.Failure do\n  def starting_line, do: __ENV__.line + 2\n\n  @moduledoc \"\"\"\n\n      iex> 1 + * 1\n      1\n\n      iex> 1 + hd(List.flatten([1]))\n      3\n\n      iex> a = \"This is an egregiously long text string.\"\n      iex> b = ~r{an egregiously long}\n      iex> c = \"a slightly shorter\"\n      iex> String.replace(a, b, c)\n      \"This is a much shorter text string.\"\n\n      iex> :oops\n      #Inspect<[]>\n\n      iex> Hello.world()\n      :world\n\n      iex> raise \"oops\"\n      ** (WhatIsThis) oops\n\n      iex> raise \"oops\"\n      ** (RuntimeError) hello\n\n  \"\"\"\n\n  @doc \"\"\"\n      # This will fail to inspect\n      iex> ExUnit.DocTestTest.Haiku.new(:this, :is, {:not, :a, :haiku})\n      #Haiku<:this_wont_be_asserted>\n  \"\"\"\n  def raising_inspect, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.Invalid do\n  def starting_line, do: __ENV__.line + 2\n\n  @doc \"\"\"\n      iex> 1 + * 1\n      1\n  \"\"\"\n  def a(), do: :ok\n\n  @doc \"\"\"\n      iex> 1 + * 1\n      1\n  \"\"\"\n  defmacro b(), do: :ok\n\n  @doc ~S'''\n  ```\n  iex> 1 + 2\n  3\n    ```\n  '''\n  def indented_too_much, do: :ok\n\n  @doc \"\"\"\n      ```\n  iex> 1 + 2\n  3\n      ```\n  \"\"\"\n  def dedented_past_fence, do: :ok\n\n  @doc \"\"\"\n  iex> String.valid?(\"invalid utf8 \\xFF\")\n  false\n  \"\"\"\n  def invalid_utf8, do: :ok\n\n  @doc \"\"\"\n      iex> {:ok, :oops}\n      {:ok, #Inspect<[]>}\n  \"\"\"\n  def misplaced_opaque_type, do: :ok\n\n  @typedoc \"\"\"\n      iex> 1 + * 1\n      1\n  \"\"\"\n  @type t :: any()\n\n  @doc \"\"\"\n      iex> :foo\n      iex> :bar\n      1 + * 1\n  \"\"\"\n  def result, do: :ok\n\n  @doc \"\"\"\n      iex> 123 +\n      :mixed\n  \"\"\"\n  def mixed, do: :ok\n\n  @doc \"\"\"\n      iex> 1 + 2\n      3\n      iex> 123 +\n      :mixed\n  \"\"\"\n  def invalid_second, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.IndentationHeredocs do\n  @doc ~S'''\n  Receives a test and formats its failure.\n\n  ## Examples\n\n      iex> \"  1\\n  2\\n\"\n      \"\"\"\n        1\n        2\n      \"\"\"\n\n  '''\n  def heredocs, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.IndentationMismatchedPrompt do\n  @doc ~S'''\n    iex> foo = 1\n     iex> bar = 2\n    iex> foo + bar\n    3\n  '''\n  def mismatched, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.IndentationTooMuch do\n  @doc ~S'''\n    iex> 1 + 2\n      3\n  '''\n  def too_much, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.IndentationNotEnough do\n  @doc ~S'''\n      iex> 1 + 2\n    3\n  '''\n  def test_fun, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.FencedNotEnough do\n  @doc ~S'''\n    ```\n    iex> 1 + 2\n    3\n  ```\n  '''\n  def test_fun, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.IndentationNotEnoughMultilineCode do\n  @doc ~S'''\n      iex> \"hello\n      ...> world\"\n      \"hello\n  world\"\n  '''\n  def test_fun, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.FencedHeredocs do\n  @doc ~S'''\n  Receives a test and formats its failure.\n\n  ## Examples\n\n  ```\n  iex> 1 + 2\n  3\n  ```\n\n      ```\n      iex> 3 = 1 + 2\n      ```\n\n  ```\n      iex> 1 + 2\n      3\n  ```\n  '''\n  def heredocs, do: :ok\n\n  @doc ~S'''\n  ```\n  iex> 1 + 2\n  3\n  '''\n  def incomplete, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.FenceIncomplete do\n  @doc ~S'''\n  ```\n  iex> 1 + 2\n  3\n  '''\n  def test_fun, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.Numbered do\n  @doc \"\"\"\n  iex(1)> 1 +\n  ...(1)> 2\n  3\n  \"\"\"\n  def test_fun(), do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.Host do\n  @doc \"\"\"\n      iex(foo@bar)1> 1 +\n      ...(foo@bar)1> 2\n      3\n  \"\"\"\n  def test_fun(), do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.Haiku do\n  @moduledoc \"\"\"\n  This module describes the ancient Japanese poem form known as Haiku.\n\n  The Inspect protocol has been overridden for `%Haiku{}`\n  so that Haikus are shown in a pretty-printed fashion.\n\n  This module is part of the DocTest test suite,\n  to ensure that DocTest can handle opaque inspect types\n  which contain unicode and possibly consist of multiple lines.\n  \"\"\"\n\n  defstruct [:first_phrase, :second_phrase, :third_phrase, :author]\n\n  @doc \"\"\"\n  Creates a new Haiku.\n\n  Optionally pass in the `author` as fourth argument.\n\n  ## Examples:\n\n      # Simple Haiku, inspect output consists of multiple lines.\n      iex> ExUnit.DocTestTest.Haiku.new(\"Haikus are easy\", \"But sometimes they don't make sense\", \"Refrigerator\")\n      #Haiku<\n        Haikus are easy\n        But sometimes they don't make sense\n        Refrigerator\n      >\n\n      # Haiku with Unicode characters (Japanese Kanji, em-dash).\n      iex> ExUnit.DocTestTest.Haiku.new(\"古池や\", \"蛙飛びこむ\", \"水の音\", \"Matsuo Basho\")\n      #Haiku<\n        古池や\n        蛙飛びこむ\n        水の音\n        -- Matsuo Basho\n      >\n\n  \"\"\"\n  def new(first, second, third, author \\\\ \"\") do\n    %__MODULE__{\n      first_phrase: first,\n      second_phrase: second,\n      third_phrase: third,\n      author: author\n    }\n  end\n\n  @doc \"\"\"\n       iex> ExUnit.DocTestTest.Haiku.new(\"古池や\", \"蛙飛びこむ\", \"水の音\", \"Matsuo Basho\")\n       #Haiku<\n         古池や\n         蛙飛びこむ\n         水の音\n         -- Matsuo Basho\n       >\n       \"\"\"\n       |> String.replace(\"\\n\", \"\\r\\n\")\n  def crlf_test, do: :ok\n\n  defimpl Inspect do\n    def inspect(haiku, opts) do\n      indent = Keyword.get(opts.custom_options, :indent, 2)\n      spaces = String.duplicate(\" \", indent)\n      author = if haiku.author == \"\", do: \"\", else: \"\\n#{spaces}-- #{haiku.author}\"\n\n      \"\"\"\n      #Haiku<\n      #{spaces}#{haiku.first_phrase}\n      #{spaces}#{haiku.second_phrase}\n      #{spaces}#{haiku.third_phrase}#{author}\n      >\n      \"\"\"\n      |> String.trim_trailing(\"\\n\")\n    end\n  end\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.HaikuIndent4UsingInspectOpts do\n  @moduledoc \"\"\"\n  This module is part of the DocTest test suite,\n  to ensure that DocTest respect the `:inspect_opts` options.\n  \"\"\"\n\n  @doc \"\"\"\n      # Simple Haiku, inspect output consists of multiple lines.\n      iex> ExUnit.DocTestTest.Haiku.new(\"Haikus are easy\", \"But sometimes they don't make sense\", \"Refrigerator\")\n      #Haiku<\n          Haikus are easy\n          But sometimes they don't make sense\n          Refrigerator\n      >\n\n      # Haiku with Unicode characters (Japanese Kanji, em-dash).\n      iex> ExUnit.DocTestTest.Haiku.new(\"古池や\", \"蛙飛びこむ\", \"水の音\", \"Matsuo Basho\")\n      #Haiku<\n          古池や\n          蛙飛びこむ\n          水の音\n          -- Matsuo Basho\n      >\n\n  \"\"\"\n  def indent_4, do: :ok\n\n  @doc \"\"\"\n       iex> ExUnit.DocTestTest.Haiku.new(\"古池や\", \"蛙飛びこむ\", \"水の音\", \"Matsuo Basho\")\n       #Haiku<\n           古池や\n           蛙飛びこむ\n           水の音\n           -- Matsuo Basho\n       >\n       \"\"\"\n       |> String.replace(\"\\n\", \"\\r\\n\")\n  def crlf_test, do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.PatternMatching do\n  def starting_line, do: __ENV__.line + 2\n\n  @moduledoc \"\"\"\n  The doctests below test pattern matching failures.\n\n      iex> {1, 2}={1, 3}\n\n      iex> tuple = {1, 3}\n      iex> {1, 2} = tuple\n\n      iex> \"Hello, world\" = \"Hello world\"\n\n      iex> \"Hello, \" <> _ = \"Hello world\"\n\n      iex> [:a | _] = [:b, :a]\n\n      iex> atom = :a\n      iex> [^atom | _] = [:b, :a]\n\n      iex> %{b: _, d: :e} = %{a: :c, d: :e}\n\n      iex> %{year: 2001, day: 1} = ~D[2000-01-01]\n  \"\"\"\n\n  @doc \"\"\"\n      iex> adder = fn int -> int + 1 end\n      iex> num =\n      ...>   adder.(0)\n      iex> {^num, _, _} =\n      ...> # Comments can be here as well\n      ...>\n      ...>   {adder.(0), adder.(1), :three}\n\n      # false assertions do not accidentally raise\n      iex> false = (List.flatten([]) != [])\n  \"\"\"\n  def passing(), do: :ok\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest.Ellipsis do\n  @doc \"\"\"\n      iex> ExUnit.DocTestTest.Ellipsis.same_line_err(self())\n      ** (ArgumentError) Unexpected: ...\n  \"\"\"\n  def same_line_err(arg) do\n    raise ArgumentError, \"Unexpected: #{inspect(arg)}\"\n  end\n\n  @doc \"\"\"\n      iex> ExUnit.DocTestTest.Ellipsis.multi_line_err(self())\n      ** (ArgumentError) Unexpected:\n      ...\n  \"\"\"\n  def multi_line_err(arg) do\n    raise ArgumentError, \"Unexpected:\\n#{inspect(arg)}\"\n  end\n\n  @doc \"\"\"\n      iex> ExUnit.DocTestTest.Ellipsis.triple_dot_err(:foo)\n      ** (ArgumentError) :foo ...\n  \"\"\"\n  def triple_dot_err(arg) do\n    raise ArgumentError, \"#{inspect(arg)} ...\"\n  end\nend\n|> ExUnit.BeamHelpers.write_beam()\n\ndefmodule ExUnit.DocTestTest do\n  use ExUnit.Case\n\n  # This is intentional. The doctests in DocTest's docs\n  # fail for demonstration purposes.\n  # doctest ExUnit.DocTest\n\n  doctest ExUnit.DocTestTest.GoodModule, import: true\n  doctest ExUnit.DocTestTest.NoTrailing\n\n  doctest ExUnit.DocTestTest.SomewhatGoodModuleWithOnly,\n    only: [:moduledoc, one: 0],\n    import: true\n\n  doctest ExUnit.DocTestTest.SomewhatGoodModuleWithExcept,\n    except: [:moduledoc, two: 0],\n    import: true\n\n  doctest ExUnit.DocTestTest.NoImport\n  doctest ExUnit.DocTestTest.IndentationHeredocs\n  doctest ExUnit.DocTestTest.FencedHeredocs\n  doctest ExUnit.DocTestTest.Haiku\n\n  doctest ExUnit.DocTestTest.HaikuIndent4UsingInspectOpts,\n    inspect_opts: [custom_options: [indent: 4]]\n\n  doctest ExUnit.DocTestTest.Ellipsis\n\n  import ExUnit.CaptureIO\n\n  test \"multiple functions filtered with :only\" do\n    defmodule MultipleOnly do\n      use ExUnit.Case\n      doctest ExUnit.DocTestTest.SomewhatGoodModuleWithOnly, only: [one: 0, two: 0], import: true\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Failed: 1 doctest\"\n  end\n\n  test \"empty :only\" do\n    defmodule EmptyOnly do\n      use ExUnit.Case\n      doctest ExUnit.DocTestTest.SomewhatGoodModuleWithOnly, only: [], import: true\n    end\n\n    output = capture_io(fn -> ExUnit.run() end)\n\n    refute output =~ \"Failed:\"\n    refute output =~ \"doctest\"\n  end\n\n  test \"allows users to tag doctests with configuration options\" do\n    defmodule TaggedTests do\n      use ExUnit.Case\n      doctest ExUnit.DocTestTest.SomewhatGoodModuleWithOnly, tags: [skip: true], import: true\n    end\n\n    output = capture_io(fn -> ExUnit.run() end)\n\n    refute output =~ \"Failed:\"\n    assert output =~ \"2 skipped\"\n  end\n\n  test \"doctest failures\" do\n    # When adding or removing lines above this line, the tests below will\n    # fail because we are explicitly asserting some doctest lines from\n    # FailureCompiled in the format of \"test/ex_unit/doc_test_test.exs:<LINE>\".\n    defmodule FailureCompiled do\n      use ExUnit.Case\n      doctest ExUnit.DocTestTest.Failure\n    end\n\n    doctest_line = __ENV__.line - 3\n    starting_line = ExUnit.DocTestTest.Failure.starting_line() + 2\n\n    ExUnit.configure(seed: 0, colors: [enabled: false])\n    output = capture_io(fn -> ExUnit.run() end)\n    output = String.replace(output, [IO.ANSI.red(), IO.ANSI.reset()], \"\")\n    location = location(ExUnit.DocTestTest.Failure)\n\n    assert output =~ \"\"\"\n             1) doctest module ExUnit.DocTestTest.Failure (1) (ExUnit.DocTestTest.FailureCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (SyntaxError) invalid syntax found on #{location}:#{starting_line}:6:\n                     error: syntax error before: '*'\n                     │\n                 #{starting_line} │  1 + * 1\n                     │      ^\n                     │\n                     └─ #{location}:#{starting_line}:6\n                doctest:\n                  iex> 1 + * 1\n                  1\n                stacktrace:\n                  #{stack(starting_line)}ExUnit.DocTestTest.Failure (module)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             2) doctest module ExUnit.DocTestTest.Failure (2) (ExUnit.DocTestTest.FailureCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest failed\n                doctest:\n                  iex> 1 + hd(List.flatten([1]))\n                  3\n                code:  1 + hd(List.flatten([1])) === 3\n                left:  2\n                right: 3\n                stacktrace:\n                  #{stack(starting_line + 3)}ExUnit.DocTestTest.Failure (module)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             3) doctest module ExUnit.DocTestTest.Failure (3) (ExUnit.DocTestTest.FailureCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest failed\n                doctest:\n                  iex> a = \"This is an egregiously long text string.\"\n                  iex> b = ~r{an egregiously long}\n                  iex> c = \"a slightly shorter\"\n                  iex> String.replace(a, b, c)\n                  \"This is a much shorter text string.\"\n                code:  String.replace(a, b, c) === \"This is a much shorter text string.\"\n                left:  \"This is a slightly shorter text string.\"\n                right: \"This is a much shorter text string.\"\n                stacktrace:\n                  #{stack(starting_line + 6)}ExUnit.DocTestTest.Failure (module)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             4) doctest module ExUnit.DocTestTest.Failure (4) (ExUnit.DocTestTest.FailureCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest failed\n                doctest:\n                  iex> :oops\n                  #Inspect<[]>\n                code:  inspect(:oops) === \"#Inspect<[]>\"\n                left:  \":oops\"\n                right: \"#Inspect<[]>\"\n                stacktrace:\n                  #{stack(starting_line + 12)}ExUnit.DocTestTest.Failure (module)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             5) doctest module ExUnit.DocTestTest.Failure (5) (ExUnit.DocTestTest.FailureCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                ** (UndefinedFunctionError) function Hello.world/0 is undefined (module Hello is not available). Make sure the module name is correct and has been specified in full (or that an alias has been defined)\n                stacktrace:\n                  Hello.world()\n                  (for doctest at) #{location}:#{starting_line + 15}: (test)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             6) doctest module ExUnit.DocTestTest.Failure (6) (ExUnit.DocTestTest.FailureCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest failed: expected exception WhatIsThis but got RuntimeError with message \"oops\"\n                doctest:\n                  iex> raise \"oops\"\n                  ** (WhatIsThis) oops\n                stacktrace:\n                  #{stack(starting_line + 18)}ExUnit.DocTestTest.Failure (module)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             7) doctest module ExUnit.DocTestTest.Failure (7) (ExUnit.DocTestTest.FailureCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest failed: wrong message for RuntimeError\n                expected:\n                  \"hello\"\n                actual:\n                  \"oops\"\n                doctest:\n                  iex> raise \"oops\"\n                  ** (RuntimeError) hello\n                stacktrace:\n                  #{stack(starting_line + 21)}ExUnit.DocTestTest.Failure (module)\n           \"\"\"\n\n    assert output =~ \"8) doctest ExUnit.DocTestTest.Failure.raising_inspect/0\"\n    assert output =~ \"iex> ExUnit.DocTestTest.Haiku.new(:this, :is, {:not, :a, :haiku})\"\n\n    assert output =~\n             \"#{stack(starting_line + 28)}ExUnit.DocTestTest.Failure (module)\"\n\n    assert output =~ \"Failed: 8 doctests\"\n  end\n\n  test \"doctest invalid\" do\n    # When adding or removing lines above this line, the tests below will\n    # fail because we are explicitly asserting some doctest lines from\n    # InvalidCompiled in the format of \"test/ex_unit/doc_test_test.exs:<LINE>\".\n    defmodule InvalidCompiled do\n      use ExUnit.Case\n      doctest ExUnit.DocTestTest.Invalid\n    end\n\n    doctest_line = __ENV__.line - 3\n    starting_line = ExUnit.DocTestTest.Invalid.starting_line() + 1\n    location = location(ExUnit.DocTestTest.Invalid)\n\n    ExUnit.configure(seed: 0, colors: [enabled: false])\n    output = capture_io(fn -> ExUnit.run() end)\n    output = String.replace(output, [IO.ANSI.red(), IO.ANSI.reset()], \"\")\n\n    line = starting_line\n\n    assert output =~ \"\"\"\n             1) doctest ExUnit.DocTestTest.Invalid.a/0 (1) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (SyntaxError) invalid syntax found on #{location}:#{line}:6:\n                     error: syntax error before: '*'\n                     │\n                 #{line} │  1 + * 1\n                     │      ^\n                     │\n                     └─ #{location}:#{line}:6\n                doctest:\n                  iex> 1 + * 1\n                  1\n                stacktrace:\n                  #{stack(line)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 6\n\n    assert output =~ \"\"\"\n             2) doctest ExUnit.DocTestTest.Invalid.b/0 (2) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (SyntaxError) invalid syntax found on #{location}:#{line}:6:\n                     error: syntax error before: '*'\n                     │\n                 #{line} │  1 + * 1\n                     │      ^\n                     │\n                     └─ #{location}:#{line}:6\n                doctest:\n                  iex> 1 + * 1\n                  1\n                stacktrace:\n                  #{stack(line)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 15\n\n    assert output =~ \"\"\"\n             3) doctest ExUnit.DocTestTest.Invalid.indented_too_much/0 (3) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (SyntaxError) invalid syntax found on #{location}:#{line}:3:\n                     error: unexpected token: \"`\" (column 3, code point U+0060)\n                     │\n                 #{line} │   ```\n                     │   ^\n                     │\n                     └─ #{location}:#{line}:3\n                doctest:\n                  iex> 1 + 2\n                  3\n                    ```\n                stacktrace:\n                  #{stack(line - 1)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 23\n\n    assert output =~ \"\"\"\n             4) doctest ExUnit.DocTestTest.Invalid.dedented_past_fence/0 (4) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (SyntaxError) invalid syntax found on #{location}:#{line}:5:\n                     error: unexpected token: \"`\" (column 5, code point U+0060)\n                     │\n                 #{line} │     ```\n                     │     ^\n                     │\n                     └─ #{location}:#{line}:5\n                doctest:\n                  iex> 1 + 2\n                  3\n                      ```\n                stacktrace:\n                  #{stack(line - 1)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 28\n\n    assert output =~ \"\"\"\n             5) doctest ExUnit.DocTestTest.Invalid.invalid_utf8/0 (5) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (UnicodeConversionError) invalid encoding starting at <<255, 34, 41>>\n                stacktrace:\n                  #{stack(line)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 35\n\n    assert output =~ \"\"\"\n           6) doctest ExUnit.DocTestTest.Invalid.misplaced_opaque_type/0 (6) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (TokenMissingError) token missing on #{location}:#{line}:20:\n                     error: missing terminator: }\n                     │\n                 #{line} │ {:ok, #Inspect<[]>}\n                     │ │                  └ missing closing delimiter (expected \"}\")\n                     │ └ unclosed delimiter\n                     │\n                     └─ #{location}:#{line}:20\n                If you are planning to assert on the result of an iex> expression which contains a value inspected as #Name<...>, please make sure the inspected value is placed at the beginning of the expression, otherwise Elixir will treat it as a comment due to the leading sign #.\n                doctest:\n                  iex> {:ok, :oops}\n                  {:ok, #Inspect<[]>}\n                stacktrace:\n                  #{stack(line)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 40\n\n    assert output =~ \"\"\"\n             7) doctest ExUnit.DocTestTest.Invalid.t/0 (7) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (SyntaxError) invalid syntax found on #{location}:#{line}:6:\n                     error: syntax error before: '*'\n                     │\n                 #{line} │  1 + * 1\n                     │      ^\n                     │\n                     └─ #{location}:#{line}:6\n                doctest:\n                  iex> 1 + * 1\n                  1\n                stacktrace:\n                  #{stack(line)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 48\n\n    assert output =~ \"\"\"\n             8) doctest ExUnit.DocTestTest.Invalid.result/0 (8) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (SyntaxError) invalid syntax found on #{location}:#{line}:5:\n                     error: syntax error before: '*'\n                     │\n                 #{line} │ 1 + * 1\n                     │     ^\n                     │\n                     └─ #{location}:#{line}:5\n                doctest:\n                  iex> :foo\n                  iex> :bar\n                  1 + * 1\n                stacktrace:\n                  #{stack(line)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 53\n\n    assert output =~ \"\"\"\n             9) doctest ExUnit.DocTestTest.Invalid.mixed/0 (9) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (TokenMissingError) token missing on #{location}:#{line}:6:\n                     error: syntax error: expression is incomplete\n                     │\n                 #{line} │  123 +\n                     │      ^\n                     │\n                     └─ #{location}:#{line}:6\n                doctest:\n                  iex> 123 +\n                  :mixed\n                stacktrace:\n                  #{stack(line)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    line = starting_line + 61\n\n    assert output =~ \"\"\"\n            10) doctest ExUnit.DocTestTest.Invalid.invalid_second/0 (10) (ExUnit.DocTestTest.InvalidCompiled)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                Doctest did not compile, got: (TokenMissingError) token missing on #{location}:#{line}:6:\n                     error: syntax error: expression is incomplete\n                     │\n                 #{line} │  123 +\n                     │      ^\n                     │\n                     └─ #{location}:#{line}:6\n                doctest:\n                  iex> 123 +\n                  :mixed\n                stacktrace:\n                  #{stack(line)}ExUnit.DocTestTest.Invalid (module)\n           \"\"\"\n\n    assert output =~ \"Failed: 10 doctests\"\n  end\n\n  test \"pattern matching assertions in doctests\" do\n    defmodule PatternMatchingRunner do\n      use ExUnit.Case\n      doctest ExUnit.DocTestTest.PatternMatching, import: true\n    end\n\n    doctest_line = __ENV__.line - 3\n    starting_line = ExUnit.DocTestTest.PatternMatching.starting_line()\n    location = location(ExUnit.DocTestTest.PatternMatching)\n\n    ExUnit.configure(seed: 0, colors: [enabled: false])\n    output = capture_io(fn -> ExUnit.run() end)\n\n    assert output =~ \"\"\"\n             1) doctest module ExUnit.DocTestTest.PatternMatching (1) (ExUnit.DocTestTest.PatternMatchingRunner)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                match (=) failed\n                code:  {1, 2} = {1, 3}\n                left:  {1, 2}\n                right: {1, 3}\n                stacktrace:\n                  (for doctest at) #{location}:#{starting_line + 3}: (test)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             2) doctest module ExUnit.DocTestTest.PatternMatching (2) (ExUnit.DocTestTest.PatternMatchingRunner)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                match (=) failed\n                code:  {1, 2} = tuple\n                left:  {1, 2}\n                right: {1, 3}\n                stacktrace:\n                  (for doctest at) #{location}:#{starting_line + 6}: (test)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             3) doctest module ExUnit.DocTestTest.PatternMatching (3) (ExUnit.DocTestTest.PatternMatchingRunner)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                match (=) failed\n                code:  \"Hello, world\" = \"Hello world\"\n                left:  \"Hello, world\"\n                right: \"Hello world\"\n                stacktrace:\n                  (for doctest at) #{location}:#{starting_line + 8}: (test)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             4) doctest module ExUnit.DocTestTest.PatternMatching (4) (ExUnit.DocTestTest.PatternMatchingRunner)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                match (=) failed\n                code:  \"Hello, \" <> _ = \"Hello world\"\n                left:  \"Hello, \" <> _\n                right: \"Hello world\"\n                stacktrace:\n                  (for doctest at) #{location}:#{starting_line + 10}: (test)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             5) doctest module ExUnit.DocTestTest.PatternMatching (5) (ExUnit.DocTestTest.PatternMatchingRunner)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                match (=) failed\n                code:  [:a | _] = [:b, :a]\n                left:  [:a | _]\n                right: [:b, :a]\n                stacktrace:\n                  (for doctest at) #{location}:#{starting_line + 12}: (test)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             6) doctest module ExUnit.DocTestTest.PatternMatching (6) (ExUnit.DocTestTest.PatternMatchingRunner)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                match (=) failed\n                The following variables were pinned:\n                  atom = :a\n                code:  [^atom | _] = [:b, :a]\n                left:  [^atom | _]\n                right: [:b, :a]\n                stacktrace:\n                  (for doctest at) #{location}:#{starting_line + 15}: (test)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             7) doctest module ExUnit.DocTestTest.PatternMatching (7) (ExUnit.DocTestTest.PatternMatchingRunner)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                match (=) failed\n                code:  %{b: _, d: :e} = %{a: :c, d: :e}\n                left:  %{b: _, d: :e}\n                right: %{a: :c, d: :e}\n                stacktrace:\n                  (for doctest at) #{location}:#{starting_line + 17}: (test)\n           \"\"\"\n\n    assert output =~ \"\"\"\n             8) doctest module ExUnit.DocTestTest.PatternMatching (8) (ExUnit.DocTestTest.PatternMatchingRunner)\n                test/ex_unit/doc_test_test.exs:#{doctest_line}\n                match (=) failed\n                code:  %{year: 2001, day: 1} = ~D[2000-01-01]\n                left:  %{year: 2001, day: 1}\n                right: ~D[2000-01-01]\n                stacktrace:\n                  (for doctest at) #{location}:#{starting_line + 19}: (test)\n           \"\"\"\n\n    assert output =~ \"Failed: 8 doctests\"\n  end\n\n  test \"IEx prefix contains a number\" do\n    defmodule NumberedUsage do\n      use ExUnit.Case\n      doctest ExUnit.DocTestTest.Numbered\n    end\n\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Result: 1 passed\"\n  end\n\n  test \"IEx prompt contains host\" do\n    message =\n      ~s[unknown IEx prompt: \"iex(foo@bar)1> 1 +\".\\nAccepted formats are: iex>, iex(1)>, ...>, ...(1)>]\n\n    assert_raise ExUnit.DocTest.Error, ~r/#{Regex.escape(message)}/, fn ->\n      defmodule HostUsage do\n        use ExUnit.Case\n        doctest ExUnit.DocTestTest.Host\n      end\n    end\n  end\n\n  test \"doctests built-in tags\" do\n    alias ExUnit.DocTestTest.{NoImport, NoTrailing}\n\n    defmodule DoctestTags do\n      use ExUnit.Case, register: false\n      doctest NoImport\n      doctest NoTrailing\n    end\n\n    assert %ExUnit.TestModule{tests: [test1, test2, test3]} = DoctestTags.__ex_unit__()\n\n    assert %{\n             test_type: :doctest,\n             doctest: NoImport,\n             doctest_line: 137,\n             doctest_data: %{end_line: 138}\n           } = test1.tags\n\n    assert %{\n             test_type: :doctest,\n             doctest: NoImport,\n             doctest_line: 140,\n             doctest_data: %{end_line: 141}\n           } = test2.tags\n\n    assert %{\n             test_type: :doctest,\n             doctest: NoTrailing,\n             doctest_line: 149,\n             doctest_data: %{end_line: 149}\n           } = test3.tags\n  end\n\n  describe \"errors\" do\n    test \"multiple exceptions in one test case is not supported\" do\n      message = ~r\"multiple exceptions in the same doctest example are not supported\"\n\n      assert_raise ExUnit.DocTest.Error, message, fn ->\n        defmodule NeverCompiled do\n          import ExUnit.DocTest\n          doctest ExUnit.DocTestTest.MultipleExceptions\n        end\n      end\n    end\n\n    test \"fails on invalid module\" do\n      assert capture_io(:stderr, fn ->\n               assert_raise CompileError, fn ->\n                 defmodule NeverCompiled do\n                   import ExUnit.DocTest\n                   doctest ExUnit.DocTestTest.Unknown\n                 end\n               end\n             end) =~ \"module ExUnit.DocTestTest.Unknown is not loaded and could not be found\"\n    end\n\n    test \"fails when testing functions are not found\" do\n      message = \"\"\"\n      #{stack(0)}undefined or private functions given to doctest:\n\n          ExUnit.DocTestTest.SomewhatGoodModuleWithOnly.three/0\n          ExUnit.DocTestTest.SomewhatGoodModuleWithOnly.four/1\n\n      \"\"\"\n\n      assert_raise ExUnit.DocTest.Error, message, fn ->\n        defmodule NeverCompiled do\n          import ExUnit.DocTest\n\n          doctest ExUnit.DocTestTest.SomewhatGoodModuleWithOnly,\n            only: [three: 0, four: 1],\n            import: true\n        end\n      end\n    end\n\n    test \"fails when there are no docs\" do\n      message = ~r\"could not retrieve the documentation for module ExUnit\\.DocTestTest\"\n\n      assert_raise ExUnit.DocTest.Error, message, fn ->\n        defmodule NeverCompiled do\n          import ExUnit.DocTest\n          doctest ExUnit.DocTestTest\n        end\n      end\n    end\n\n    test \"fails in indentation mismatch\" do\n      message =\n        ~r[indentation level mismatch on doctest line: \\\"   iex> bar = 2\\\".*is exactly 2 spaces]s\n\n      assert_raise ExUnit.DocTest.Error, message, fn ->\n        defmodule NeverCompiled do\n          import ExUnit.DocTest\n          doctest ExUnit.DocTestTest.IndentationMismatchedPrompt\n        end\n      end\n\n      message = ~r[indentation level mismatch on doctest line: \\\"    3\\\".*is exactly 2 spaces]s\n\n      assert_raise ExUnit.DocTest.Error, message, fn ->\n        defmodule NeverCompiled do\n          import ExUnit.DocTest\n          doctest ExUnit.DocTestTest.IndentationTooMuch\n        end\n      end\n\n      message = ~r[indentation level mismatch on doctest line: \\\"  3\\\".*is exactly 4 spaces]s\n\n      assert_raise ExUnit.DocTest.Error, message, fn ->\n        defmodule NeverCompiled do\n          import ExUnit.DocTest\n          doctest ExUnit.DocTestTest.IndentationNotEnough\n        end\n      end\n\n      message = ~r[indentation level mismatch on doctest line: \\\"```\\\".*is exactly 2 spaces]s\n\n      assert_raise ExUnit.DocTest.Error, message, fn ->\n        defmodule NeverCompiled do\n          import ExUnit.DocTest\n          doctest ExUnit.DocTestTest.FencedNotEnough\n        end\n      end\n\n      message =\n        ~r[indentation level mismatch on doctest line: \\\"world\\\\\\\"\\\".*is exactly 4 spaces]s\n\n      assert_raise ExUnit.DocTest.Error, message, fn ->\n        defmodule NeverCompiled do\n          import ExUnit.DocTest\n          doctest ExUnit.DocTestTest.IndentationNotEnoughMultilineCode\n        end\n      end\n    end\n\n    test \"fails on invalid use\" do\n      assert_raise RuntimeError, ~r\"cannot define doctest\", fn ->\n        defmodule FunctionClashFail do\n          import ExUnit.DocTest\n          doctest ExUnit.DocTestTest.Failure\n        end\n      end\n    end\n  end\n\n  describe \"doctest_file\" do\n    test \"passing\" do\n      defmodule FilePassing do\n        use ExUnit.Case\n        doctest_file(Path.expand(\"../fixtures/passing.md\", __DIR__))\n      end\n\n      output = capture_io(fn -> ExUnit.run() end)\n      assert output =~ \"Result: 2 passed\"\n    end\n\n    test \"failing\" do\n      defmodule FileFailing do\n        use ExUnit.Case\n        doctest_file(Path.expand(\"../fixtures/failing.md\", __DIR__))\n      end\n\n      doctest_line = __ENV__.line - 3\n      ExUnit.configure(seed: 0, colors: [enabled: false])\n      output = capture_io(fn -> ExUnit.run() end)\n\n      assert output =~ \"\"\"\n               1) doctest test/fixtures/failing.md (1) (ExUnit.DocTestTest.FileFailing)\n                  test/ex_unit/doc_test_test.exs:#{doctest_line}\n                  Doctest failed\n                  doctest:\n                    iex> 1 + 2\n                    4\n                  code:  1 + 2 === 4\n                  left:  3\n                  right: 4\n                  stacktrace:\n                    test/fixtures/failing.md:4: ExUnit.DocTestTest.FileFailing (module)\n             \"\"\"\n    end\n  end\n\n  test \"doctest direct invocation\" do\n    defmodule Direct do\n      use ExUnit.Case, register: false\n      doctest ExUnit.DocTestTest.GoodModule, import: true\n    end\n\n    [head | _] = Direct.__ex_unit__().tests\n    assert apply(Direct, head.name, [%{}]) == {:ok, 2}\n  end\n\n  defp location(module) do\n    if __MODULE__.module_info(:compile)[:source] do\n      \"test/ex_unit/doc_test_test.exs\"\n    else\n      inspect(module)\n    end\n  end\n\n  defp stack(line) do\n    if __MODULE__.module_info(:compile)[:source] do\n      [Exception.format_file_line(\"test/ex_unit/doc_test_test.exs\", line), ?\\s]\n    else\n      \"\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/failures_manifest_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.FailuresManifestTest do\n  use ExUnit.Case, async: false\n\n  import ExUnit.FailuresManifest\n\n  @passed nil\n  @skipped {:skipped, \"reason\"}\n  @excluded {:excluded, \"reason\"}\n  @failed {:failed, []}\n  @invalid {:invalid, %ExUnit.TestModule{}}\n  @manifest_path \"example.manifest\"\n\n  describe \"info/1\" do\n    @tag :tmp_dir\n    test \"returns the sets of files and test IDs with failures\", context do\n      manifest =\n        new()\n        |> put_test(failed_1 = new_test(@failed, context))\n        |> put_test(failed_2 = new_test(@failed, context))\n        |> put_test(new_test(@passed, context))\n        |> put_test(invalid_1 = new_test(@invalid, context))\n\n      File.cd!(context.tmp_dir, fn ->\n        write!(manifest, @manifest_path)\n\n        assert info(@manifest_path) ==\n                 {MapSet.new([context.file]),\n                  MapSet.new([test_id(failed_1), test_id(failed_2), test_id(invalid_1)])}\n      end)\n    end\n\n    @tag :tmp_dir\n    test \"returns all when the whole suite should be considered as failed\", context do\n      File.cd!(context.tmp_dir, fn ->\n        fail_all!(@manifest_path)\n        assert info(@manifest_path) == :all\n      end)\n    end\n\n    @tag :tmp_dir\n    test \"returns no information when loading a file that does not exit\", context do\n      path = Path.join(context.tmp_dir, \"missing.manifest\")\n      refute File.exists?(path)\n      assert info(path) == {MapSet.new(), MapSet.new()}\n    end\n  end\n\n  describe \"put_test/2 when the test is not already in the manifest\" do\n    test \"ignores passed tests since we only care to store failures\" do\n      assert put_test(new(), new_test(@passed)) == new()\n    end\n\n    test \"stores failed tests\" do\n      test = new_test(@failed)\n      assert put_test(new(), test) == %{test_id(test) => file(test)}\n    end\n\n    test \"stores invalid tests\" do\n      test = new_test(@invalid)\n      assert put_test(new(), test) == %{test_id(test) => file(test)}\n    end\n\n    test \"ignores skipped tests since we know nothing about their pass/fail status\" do\n      assert put_test(new(), new_test(@skipped)) == new()\n    end\n\n    test \"ignores excluded tests since we know nothing about their pass/fail status\" do\n      assert put_test(new(), new_test(@excluded)) == new()\n    end\n  end\n\n  describe \"put_test/2 when the test is already in the manifest\" do\n    setup do\n      failed_test = new_test(@failed)\n      manifest = put_test(new(), failed_test)\n      {:ok, %{failed_test: failed_test, manifest: manifest}}\n    end\n\n    test \"removes a newly passed test, since it is no longer failing\", context do\n      test = %{context.failed_test | state: @passed}\n      assert put_test(context.manifest, test) == new()\n    end\n\n    test \"stores failed tests, updating the stored file value\", context do\n      test = %{context.failed_test | tags: %{file: \"some-other-file\"}}\n      assert put_test(context.manifest, test) == %{test_id(test) => file(test)}\n    end\n\n    test \"stores invalid tests, updating the stored file value\", context do\n      test = %{context.failed_test | tags: %{file: \"some-other-file\"}, state: @invalid}\n      assert put_test(context.manifest, test) == %{test_id(test) => file(test)}\n    end\n\n    test \"ignores skipped tests since we know nothing about their pass/fail status\", context do\n      test = %{context.failed_test | state: @skipped}\n      assert put_test(context.manifest, test) == context.manifest\n    end\n\n    test \"ignores excluded tests since we know nothing about their pass/fail status\", context do\n      test = %{context.failed_test | state: @excluded}\n      assert put_test(context.manifest, test) == context.manifest\n    end\n  end\n\n  describe \"write!/2\" do\n    @tag :tmp_dir\n    test \"stores a manifest that can later be read with read/1\", context do\n      manifest = non_blank_manifest(context)\n\n      File.cd!(context.tmp_dir, fn ->\n        assert write!(manifest, @manifest_path) == :ok\n        assert read(@manifest_path) == manifest\n      end)\n    end\n\n    @tag :tmp_dir\n    test \"prunes tests from files that no longer exist\", context do\n      test = new_test(@failed, %{context | file: \"missing_file.exs\"})\n\n      File.cd!(context.tmp_dir, fn ->\n        new()\n        |> put_test(test)\n        |> write!(@manifest_path)\n\n        assert read(@manifest_path) == new()\n      end)\n    end\n\n    @tag :tmp_dir\n    test \"keeps tests from modules that were not loaded\", context do\n      test = new_test(@failed, %{context | module: SomeUnloadedModule})\n      manifest = new() |> put_test(test)\n\n      File.cd!(context.tmp_dir, fn ->\n        write!(manifest, @manifest_path)\n        assert read(@manifest_path) == manifest\n      end)\n    end\n\n    @tag :tmp_dir\n    test \"prunes tests defined in a function that no longer exists\", context do\n      test = new_test(@failed, %{context | test: :not_a_function_anymore})\n\n      File.cd!(context.tmp_dir, fn ->\n        new()\n        |> put_test(test)\n        |> write!(@manifest_path)\n\n        assert read(@manifest_path) == new()\n      end)\n    end\n  end\n\n  describe \"read/1\" do\n    @tag :tmp_dir\n    test \"returns a blank manifest when loading a file that does not exit\", context do\n      path = Path.join(context.tmp_dir, \"missing.manifest\")\n      refute File.exists?(path)\n      assert read(path) == new()\n    end\n\n    @tag :tmp_dir\n    test \"returns a blank manifest when the file is corrupted\", context do\n      manifest = non_blank_manifest(context)\n\n      File.cd!(context.tmp_dir, fn ->\n        assert write!(manifest, @manifest_path) == :ok\n        corrupted = \"corrupted\" <> File.read!(@manifest_path)\n        File.write!(@manifest_path, corrupted)\n        assert read(@manifest_path) == new()\n      end)\n    end\n\n    @tag :tmp_dir\n    test \"returns a blank manifest when the file was saved at a prior version\", context do\n      manifest = non_blank_manifest(context)\n\n      File.cd!(context.tmp_dir, fn ->\n        assert write!(manifest, @manifest_path) == :ok\n        assert {vsn, ^manifest} = @manifest_path |> File.read!() |> :erlang.binary_to_term()\n        File.write!(@manifest_path, :erlang.term_to_binary({vsn + 1, manifest}))\n        assert read(@manifest_path) == new()\n      end)\n    end\n  end\n\n  defp new_test(state, file \\\\ \"file\")\n\n  defp new_test(state, %{} = context) do\n    %ExUnit.Test{\n      state: state,\n      module: context.module,\n      name: context.test,\n      tags: %{file: context.file}\n    }\n  end\n\n  defp new_test(state, file) do\n    %ExUnit.Test{\n      state: state,\n      module: SomeMod,\n      name: :\"test #{System.unique_integer()}\",\n      tags: %{file: file}\n    }\n  end\n\n  defp test_id(test), do: {test.module, test.name}\n\n  defp file(test), do: test.tags.file\n\n  defp non_blank_manifest(context), do: new() |> put_test(new_test(@failed, context))\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/filters_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.FiltersTest do\n  use ExUnit.Case, async: true\n\n  doctest ExUnit.Filters\n\n  describe \"filter precedence\" do\n    setup do\n      [\n        one: %{\n          one: true,\n          numeric: true,\n          test: :\"test one\",\n          test_type: :test\n        },\n        two: %{\n          skip: true,\n          numeric: true,\n          test: :\"test two\",\n          test_type: :test,\n          two: true\n        }\n      ]\n    end\n\n    test \"no filters\", tags do\n      assert ExUnit.Filters.eval([], [], tags.one, []) == :ok\n      assert ExUnit.Filters.eval([], [], tags.two, []) == {:skipped, \"due to skip tag\"}\n    end\n\n    test \"exclude tests\", tags do\n      assert ExUnit.Filters.eval([], [:two], tags.one, []) == :ok\n      assert ExUnit.Filters.eval([], [:test], tags.one, []) == {:excluded, \"due to test filter\"}\n      assert ExUnit.Filters.eval([], [:test], tags.two, []) == {:excluded, \"due to test filter\"}\n\n      assert ExUnit.Filters.eval([], [:numeric], tags.one, []) ==\n               {:excluded, \"due to numeric filter\"}\n\n      assert ExUnit.Filters.eval([], [:unknown], tags.one, []) == :ok\n      assert ExUnit.Filters.eval([], [:unknown], tags.two, []) == {:skipped, \"due to skip tag\"}\n    end\n\n    test \"explicitly exclude a test with the :skip tag\", tags do\n      # --exclude two\n      assert ExUnit.Filters.eval([], [:two], tags.two, []) == {:excluded, \"due to two filter\"}\n\n      assert ExUnit.Filters.eval([], [:two, :test], tags.two, []) ==\n               {:excluded, \"due to two filter\"}\n    end\n\n    test \"include tests\", tags do\n      # use --include, exclude is missing\n      assert ExUnit.Filters.eval([:two], [], tags.one, []) == :ok\n      assert ExUnit.Filters.eval([:unknown], [], tags.one, []) == :ok\n\n      # --only\n      assert ExUnit.Filters.eval([:one], [:test], tags.one, []) == :ok\n\n      assert ExUnit.Filters.eval([:two], [:test], tags.one, []) ==\n               {:excluded, \"due to test filter\"}\n\n      assert ExUnit.Filters.eval([:unknown], [:test], tags.one, []) ==\n               {:excluded, \"due to test filter\"}\n\n      assert ExUnit.Filters.eval([:unknown], [:test], tags.two, []) ==\n               {:excluded, \"due to test filter\"}\n    end\n\n    test \"explicitly include a test with the :skip tag\", tags do\n      # --include two, exclude is missing\n      assert ExUnit.Filters.eval([:two], [], tags.two, []) == {:skipped, \"due to skip tag\"}\n\n      # --only two\n      assert ExUnit.Filters.eval([:two], [:test], tags.two, []) == {:skipped, \"due to skip tag\"}\n    end\n\n    test \"exception to the rule: include tests with the :skip tag\", tags do\n      # --include skip, exclude is missing\n      assert ExUnit.Filters.eval([:skip], [], tags.two, []) == :ok\n      assert ExUnit.Filters.eval([:skip], [], %{tags.two | skip: \"skip me please\"}, []) == :ok\n      assert ExUnit.Filters.eval([skip: ~r/alpha/], [], %{tags.two | skip: \"alpha\"}, []) == :ok\n\n      assert ExUnit.Filters.eval([skip: ~r/alpha/], [], %{tags.two | skip: \"beta\"}, []) ==\n               {:skipped, \"beta\"}\n\n      # --only skip\n      assert ExUnit.Filters.eval([:skip], [:test], tags.two, []) == :ok\n\n      assert ExUnit.Filters.eval([:skip], [:test], %{tags.two | skip: \"skip me please\"}, []) ==\n               :ok\n\n      assert ExUnit.Filters.eval([skip: ~r/alpha/], [:test], %{tags.two | skip: \"alpha\"}, []) ==\n               :ok\n\n      assert ExUnit.Filters.eval([skip: ~r/alpha/], [:test], %{tags.two | skip: \"beta\"}, []) ==\n               {:excluded, \"due to test filter\"}\n    end\n  end\n\n  test \"evaluating filters\" do\n    assert ExUnit.Filters.eval([], [:os], %{}, []) == :ok\n    assert ExUnit.Filters.eval([], [os: :win], %{os: :unix}, []) == :ok\n    assert ExUnit.Filters.eval([], [:os], %{os: :unix}, []) == {:excluded, \"due to os filter\"}\n\n    assert ExUnit.Filters.eval([], [os: :unix], %{os: :unix}, []) ==\n             {:excluded, \"due to os filter\"}\n\n    assert ExUnit.Filters.eval([os: :win], [], %{}, []) == :ok\n    assert ExUnit.Filters.eval([os: :win], [], %{os: :unix}, []) == :ok\n    assert ExUnit.Filters.eval([os: :win], [:os], %{}, []) == :ok\n    assert ExUnit.Filters.eval([os: :win], [:os], %{os: :win}, []) == :ok\n\n    assert ExUnit.Filters.eval([os: :win, os: :unix], [:os], %{os: :win}, []) == :ok\n  end\n\n  describe \"evaluating filters with skip\" do\n    test \"regular usage\" do\n      assert ExUnit.Filters.eval([], [], %{}, []) == :ok\n      assert ExUnit.Filters.eval([], [], %{skip: true}, []) == {:skipped, \"due to skip tag\"}\n      assert ExUnit.Filters.eval([], [], %{skip: \"skipped\"}, []) == {:skipped, \"skipped\"}\n      assert ExUnit.Filters.eval([], [:os], %{skip: \"skipped\"}, []) == {:skipped, \"skipped\"}\n    end\n\n    test \"exception to the rule: explicitly including tests with the :skip tag\" do\n      assert ExUnit.Filters.eval([:skip], [], %{skip: true}, []) == :ok\n      assert ExUnit.Filters.eval([:skip], [], %{skip: \"skipped\"}, []) == :ok\n      assert ExUnit.Filters.eval([:skip], [:test], %{skip: true}, []) == :ok\n      assert ExUnit.Filters.eval([:skip], [:test], %{skip: \"skipped\"}, []) == :ok\n      assert ExUnit.Filters.eval([skip: true], [:test], %{skip: true}, []) == :ok\n\n      assert ExUnit.Filters.eval([skip: ~r/skip me/], [:test], %{skip: \"skip me please\"}, []) ==\n               :ok\n\n      assert ExUnit.Filters.eval([skip: ~r/skip me/], [:test], %{skip: \"don't skip!\"}, []) ==\n               {:skipped, \"don't skip!\"}\n    end\n  end\n\n  test \"evaluating filters matches integers\" do\n    assert ExUnit.Filters.eval([int: \"1\"], [], %{int: 1}, []) == :ok\n    assert ExUnit.Filters.eval([int: \"1\"], [int: 5], %{int: 1}, []) == :ok\n    assert ExUnit.Filters.eval([int: \"1\"], [:int], %{int: 1}, []) == :ok\n  end\n\n  test \"evaluating filter matches atoms\" do\n    assert ExUnit.Filters.eval([os: \"win\"], [], %{os: :win}, []) == :ok\n    assert ExUnit.Filters.eval([os: \"win\"], [os: :unix], %{os: :win}, []) == :ok\n    assert ExUnit.Filters.eval([os: \"win\"], [:os], %{os: :win}, []) == :ok\n    assert ExUnit.Filters.eval([module: \"Foo\"], [:os], %{module: Foo}, []) == :ok\n  end\n\n  test \"evaluating filter matches regexes\" do\n    assert ExUnit.Filters.eval([os: ~r\"win\"], [], %{os: :win}, []) == :ok\n\n    assert ExUnit.Filters.eval([os: ~r\"mac\"], [os: :unix], %{os: :unix}, []) ==\n             {:excluded, \"due to os filter\"}\n  end\n\n  test \"evaluating filter uses special rules for line\" do\n    tests = [\n      %ExUnit.Test{tags: %{line: 3, describe_line: 2}},\n      %ExUnit.Test{tags: %{line: 5, describe_line: nil}},\n      %ExUnit.Test{tags: %{line: 8, describe_line: 7}},\n      %ExUnit.Test{tags: %{line: 10, describe_line: 7}},\n      %ExUnit.Test{tags: %{line: 13, describe_line: 12}}\n    ]\n\n    assert ExUnit.Filters.eval([line: 3], [:line], %{line: 3, describe_line: 2}, tests) == :ok\n    assert ExUnit.Filters.eval([line: 4], [:line], %{line: 3, describe_line: 2}, tests) == :ok\n    assert ExUnit.Filters.eval([line: 5], [:line], %{line: 5, describe_line: nil}, tests) == :ok\n    assert ExUnit.Filters.eval([line: 6], [:line], %{line: 5, describe_line: nil}, tests) == :ok\n    assert ExUnit.Filters.eval([line: 2], [:line], %{line: 3, describe_line: 2}, tests) == :ok\n    assert ExUnit.Filters.eval([line: 7], [:line], %{line: 8, describe_line: 7}, tests) == :ok\n    assert ExUnit.Filters.eval([line: 7], [:line], %{line: 10, describe_line: 7}, tests) == :ok\n\n    assert ExUnit.Filters.eval([line: 1], [:line], %{line: 3, describe_line: 2}, tests) ==\n             {:excluded, \"due to line filter\"}\n\n    assert ExUnit.Filters.eval([line: 7], [:line], %{line: 3, describe_line: 2}, tests) ==\n             {:excluded, \"due to line filter\"}\n\n    assert ExUnit.Filters.eval([line: 7], [:line], %{line: 5, describe_line: nil}, tests) ==\n             {:excluded, \"due to line filter\"}\n  end\n\n  test \"evaluating filter uses special rules for location\" do\n    tests = [\n      %ExUnit.Test{tags: %{line: 3, describe_line: 2}},\n      %ExUnit.Test{tags: %{line: 5, describe_line: nil}}\n    ]\n\n    assert ExUnit.Filters.eval(\n             [location: \"foo_test.exs\"],\n             [:line],\n             %{line: 3, describe_line: 2, file: \"foo_test.exs\"},\n             tests\n           ) == :ok\n\n    assert ExUnit.Filters.eval(\n             [location: \"bar_test.exs\"],\n             [:line],\n             %{line: 3, describe_line: 2, file: \"foo_test.exs\"},\n             tests\n           ) == {:excluded, \"due to line filter\"}\n\n    assert ExUnit.Filters.eval(\n             [location: {\"foo_test.exs\", 3}],\n             [:line],\n             %{line: 3, describe_line: 2, file: \"foo_test.exs\"},\n             tests\n           ) == :ok\n\n    assert ExUnit.Filters.eval(\n             [location: {\"bar_test.exs\", 3}],\n             [:line],\n             %{line: 3, describe_line: 2, file: \"foo_test.exs\"},\n             tests\n           ) == {:excluded, \"due to line filter\"}\n  end\n\n  test \"parsing filters\" do\n    assert ExUnit.Filters.parse([\"run\"]) == [:run]\n    assert ExUnit.Filters.parse([\"run:true\"]) == [run: \"true\"]\n    assert ExUnit.Filters.parse([\"run:test\"]) == [run: \"test\"]\n    assert ExUnit.Filters.parse([\"line:9\"]) == [line: 9]\n    assert ExUnit.Filters.parse([\"location:foo.exs\"]) == [location: \"foo.exs\"]\n    assert ExUnit.Filters.parse([\"location:foo.exs:invalid\"]) == [location: \"foo.exs:invalid\"]\n    assert ExUnit.Filters.parse([\"location:foo.exs:9\"]) == [location: {\"foo.exs\", 9}]\n    assert ExUnit.Filters.parse([\"location:foo.exs:9:11\"]) == [location: {\"foo.exs\", [9, 11]}]\n  end\n\n  test \"file paths with line numbers\" do\n    unix_path = \"test/some/path.exs\"\n    windows_path = \"C:\\\\some\\\\path.exs\"\n    unix_path_with_dot = \"./test/some/path.exs\"\n\n    for path <- [unix_path, windows_path, unix_path_with_dot] do\n      fixed_path = path |> Path.split() |> Path.join() |> Path.relative_to_cwd()\n\n      assert ExUnit.Filters.parse_paths([\"#{path}:123\"]) ==\n               {[fixed_path], [exclude: [:test], include: [location: {fixed_path, 123}]]}\n\n      assert ExUnit.Filters.parse_paths([path]) == {[fixed_path], []}\n\n      assert ExUnit.Filters.parse_paths([\"#{path}:123notreallyalinenumber123\"]) ==\n               {[\"#{fixed_path}:123notreallyalinenumber123\"], []}\n\n      assert ExUnit.Filters.parse_paths([\"#{path}:123:456\"]) ==\n               {[fixed_path], [exclude: [:test], include: [location: {fixed_path, [123, 456]}]]}\n\n      assert ExUnit.Filters.parse_paths([\"#{path}:123notalinenumber123:456\"]) ==\n               {[\"#{fixed_path}:123notalinenumber123\"],\n                [\n                  exclude: [:test],\n                  include: [location: {\"#{fixed_path}:123notalinenumber123\", 456}]\n                ]}\n\n      output =\n        ExUnit.CaptureIO.capture_io(:stderr, fn ->\n          assert ExUnit.Filters.parse_paths([\"#{path}:123:456notalinenumber456\"]) ==\n                   {[fixed_path],\n                    [{:exclude, [:test]}, {:include, [location: {fixed_path, 123}]}]}\n\n          assert ExUnit.Filters.parse_paths([\"#{path}:123:0:-789:456\"]) ==\n                   {[fixed_path],\n                    [exclude: [:test], include: [location: {fixed_path, [123, 456]}]]}\n        end)\n\n      assert output =~ \"invalid line number given as ExUnit filter: 456notalinenumber456\"\n      assert output =~ \"invalid line number given as ExUnit filter: 0\"\n      assert output =~ \"invalid line number given as ExUnit filter: -789\"\n    end\n  end\n\n  test \"multiple file paths with line numbers\" do\n    unix_path = \"test/some/path.exs\"\n    windows_path = \"C:\\\\some\\\\path.exs\"\n    other_unix_path = \"test//some//other_path.exs\"\n    other_windows_path = \"C:\\\\some\\\\other_path.exs\"\n\n    for {path, other_path} <- [{unix_path, other_unix_path}, {windows_path, other_windows_path}] do\n      fixed_path = path |> Path.split() |> Path.join()\n      fixed_other_path = other_path |> Path.split() |> Path.join()\n\n      assert ExUnit.Filters.parse_paths([path, other_path]) ==\n               {[fixed_path, fixed_other_path], []}\n\n      assert ExUnit.Filters.parse_paths([path, \"#{other_path}:456:789\"]) ==\n               {[fixed_path, fixed_other_path],\n                [\n                  exclude: [:test],\n                  include: [location: fixed_path, location: {fixed_other_path, [456, 789]}]\n                ]}\n\n      assert ExUnit.Filters.parse_paths([\"#{path}:123\", \"#{other_path}:456\"]) ==\n               {[fixed_path, fixed_other_path],\n                [\n                  exclude: [:test],\n                  include: [location: {fixed_path, 123}, location: {fixed_other_path, 456}]\n                ]}\n\n      output =\n        ExUnit.CaptureIO.capture_io(:stderr, fn ->\n          assert ExUnit.Filters.parse_paths([\n                   \"#{path}:123:0:-789:456\",\n                   \"#{other_path}:321:0:-987:654\"\n                 ]) ==\n                   {[fixed_path, fixed_other_path],\n                    [\n                      exclude: [:test],\n                      include: [\n                        location: {fixed_path, [123, 456]},\n                        location: {fixed_other_path, [321, 654]}\n                      ]\n                    ]}\n        end)\n\n      assert output =~ \"invalid line number given as ExUnit filter: 0\"\n      assert output =~ \"invalid line number given as ExUnit filter: -789\"\n      assert output =~ \"invalid line number given as ExUnit filter: -987\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/formatter_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.FormatterTest do\n  use ExUnit.Case\n\n  import ExUnit.Formatter\n  doctest ExUnit.Formatter\n\n  defmacrop catch_assertion(expr) do\n    quote do\n      try do\n        unquote(expr)\n      rescue\n        ex -> ex\n      end\n    end\n  end\n\n  defp test_module do\n    %ExUnit.TestModule{name: Hello}\n  end\n\n  defp test do\n    %ExUnit.Test{name: :world, module: Hello, tags: %{file: __ENV__.file, line: 1}}\n  end\n\n  def falsy() do\n    false\n  end\n\n  defp formatter(_key, value), do: value\n\n  defp diff_formatter(:diff_enabled?, _default), do: true\n  defp diff_formatter(:diff_insert, value), do: Inspect.Algebra.concat([\"+\", value, \"+\"])\n  defp diff_formatter(:diff_delete, value), do: Inspect.Algebra.concat([\"-\", value, \"-\"])\n  defp diff_formatter(_key, value), do: value\n\n  defp kw_to_string(kw), do: for({k, v} <- kw, do: {k, IO.iodata_to_binary(v)})\n\n  test \"formats test case filters\" do\n    filters = [run: true, slow: false]\n    assert format_filters(filters, :exclude) =~ \"Excluding tags: [run: true, slow: false]\"\n    assert format_filters(filters, :include) =~ \"Including tags: [run: true, slow: false]\"\n  end\n\n  test \"formats test errors\" do\n    failure = [{:error, catch_error(raise \"oops\"), []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (RuntimeError) oops\n           \"\"\"\n  end\n\n  test \"formats test exits\" do\n    failure = [{:exit, 1, []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) == \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (exit) 1\n           \"\"\"\n  end\n\n  test \"formats test exits with mfa\" do\n    failure = [{:exit, {:bye, {:mod, :fun, []}}, []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) == \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (exit) exited in: :mod.fun()\n                    ** (EXIT) :bye\n           \"\"\"\n  end\n\n  test \"formats test exits with function clause mfa\" do\n    {error, stack} =\n      try do\n        Access.fetch(Process.get(:unused, :foo), :bar)\n      catch\n        :error, error -> {error, __STACKTRACE__}\n      end\n\n    failure = [{:exit, {{error, stack}, {:mod, :fun, []}}, []}]\n\n    format = trim_multiline_whitespace(format_test_failure(test(), failure, 1, 80, &formatter/2))\n\n    assert format =~\n             \"\"\"\n               1) world (Hello)\n                  test/ex_unit/formatter_test.exs:1\n                  ** (exit) exited in: :mod.fun()\n                     ** (EXIT) an exception was raised:\n                       ** (FunctionClauseError) no function clause matching in Access.fetch/2\n\n                       The following arguments were given to Access.fetch/2:\n\n                           # 1\n                           :foo\n\n                           # 2\n                           :bar\n             \"\"\"\n\n    if Access not in :cover.modules() do\n      assert format =~\n               \"\"\"\n                         Attempted function clauses (showing 5 out of 5):\n\n                             def fetch(%module{} = container, key)\n               \"\"\"\n    end\n  end\n\n  test \"formats test exits with assertion mfa\" do\n    {error, stack} =\n      try do\n        assert 1 == 2\n      rescue\n        error -> {error, __STACKTRACE__}\n      end\n\n    failure = [{:exit, {{error, stack}, {:mod, :fun, []}}, []}]\n\n    assert trim_multiline_whitespace(format_test_failure(test(), failure, 1, 80, &formatter/2)) =~\n             \"\"\"\n               1) world (Hello)\n                  test/ex_unit/formatter_test.exs:1\n                  ** (exit) exited in: :mod.fun()\n                     ** (EXIT) an exception was raised:\n                       Assertion with == failed\n                       code:  assert 1 == 2\n                       left:  1\n                       right: 2\n             \"\"\"\n  end\n\n  test \"formats test throws\" do\n    failure = [{:throw, 1, []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) == \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (throw) 1\n           \"\"\"\n  end\n\n  test \"formats test EXITs\" do\n    failure = [{{:EXIT, self()}, 1, []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) == \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (EXIT from #{inspect(self())}) 1\n           \"\"\"\n  end\n\n  test \"formats test EXITs with function clause errors\" do\n    {error, stack} =\n      try do\n        Access.fetch(Process.get(:unused, :foo), :bar)\n      catch\n        :error, error -> {error, __STACKTRACE__}\n      end\n\n    failure = [{{:EXIT, self()}, {error, stack}, []}]\n    format = trim_multiline_whitespace(format_test_failure(test(), failure, 1, 80, &formatter/2))\n\n    assert format =~\n             \"\"\"\n               1) world (Hello)\n                  test/ex_unit/formatter_test.exs:1\n                  ** (EXIT from #{inspect(self())}) an exception was raised:\n\n                       ** (FunctionClauseError) no function clause matching in Access.fetch/2\n\n                       The following arguments were given to Access.fetch/2:\n\n                           # 1\n                           :foo\n\n                           # 2\n                           :bar\n             \"\"\"\n\n    if Access not in :cover.modules() do\n      assert format =~\n               \"\"\"\n                         Attempted function clauses (showing 5 out of 5):\n\n                             def fetch(%module{} = container, key)\n               \"\"\"\n    end\n\n    assert format =~ ~r\"lib/access.ex:\\d+: Access.fetch/2\"\n  end\n\n  test \"formats test EXITs with assertion errors\" do\n    {error, stack} =\n      try do\n        assert 1 == 2\n      rescue\n        error -> {error, __STACKTRACE__}\n      end\n\n    failure = [{{:EXIT, self()}, {error, stack}, []}]\n\n    assert trim_multiline_whitespace(format_test_failure(test(), failure, 1, 80, &formatter/2)) =~\n             \"\"\"\n               1) world (Hello)\n                  test/ex_unit/formatter_test.exs:1\n                  ** (EXIT from #{inspect(self())}) an exception was raised:\n\n                       Assertion with == failed\n                       code:  assert 1 == 2\n                       left:  1\n                       right: 2\n             \"\"\"\n  end\n\n  test \"formats test errors with test_location_relative_path\" do\n    Application.put_env(:ex_unit, :test_location_relative_path, \"apps/sample\")\n    failure = [{:error, catch_error(raise \"oops\"), []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                apps/sample/test/ex_unit/formatter_test.exs:1\n                ** (RuntimeError) oops\n           \"\"\"\n  after\n    Application.delete_env(:ex_unit, :test_location_relative_path)\n  end\n\n  test \"formats test errors with code snippets\" do\n    stack = {Hello, :world, 1, [file: __ENV__.file, line: 7]}\n    failure = [{:error, catch_error(raise \"oops\"), [stack]}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (RuntimeError) oops\n                code: defmodule ExUnit.FormatterTest do\n           \"\"\"\n  end\n\n  test \"formats test errors with parameters\" do\n    failure = [{:error, catch_error(raise \"oops\"), []}]\n\n    assert format_test_failure(%{test() | parameters: %{foo: :bar}}, failure, 1, 80, &formatter/2) =~\n             \"\"\"\n               1) world (Hello)\n                  Parameters: %{foo: :bar}\n                  test/ex_unit/formatter_test.exs:1\n                  ** (RuntimeError) oops\n             \"\"\"\n\n    formatter = fn\n      :parameters_info, map -> Map.put(map, :more, :keys)\n      key, val -> formatter(key, val)\n    end\n\n    assert format_test_failure(%{test() | parameters: %{foo: :bar}}, failure, 1, 80, formatter) =~\n             \"\"\"\n               1) world (Hello)\n                  Parameters: #{inspect(%{foo: :bar, more: :keys})}\n                  test/ex_unit/formatter_test.exs:1\n                  ** (RuntimeError) oops\n             \"\"\"\n  end\n\n  test \"formats stacktraces\" do\n    stacktrace = [{Oops, :wrong, 1, [file: \"formatter_test.exs\", line: 1]}]\n    failure = [{:error, catch_error(raise \"oops\"), stacktrace}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (RuntimeError) oops\n                stacktrace:\n                  formatter_test.exs:1: Oops.wrong/1\n           \"\"\"\n  end\n\n  test \"formats assertions\" do\n    assertion_error = catch_assertion(assert ExUnit.FormatterTest.falsy())\n    failure = [{:error, assertion_error, []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                Expected truthy, got false\n                code: assert ExUnit.FormatterTest.falsy()\n           \"\"\"\n\n    assert format_assertion_diff(assertion_error, 0, :infinity, &formatter/2) == []\n  end\n\n  test \"formats assertions with patterns and values\" do\n    assertion_error = catch_assertion(assert {1, 2, 3} > {1, 2, 3})\n    failure = [{:error, assertion_error, []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                Assertion with > failed, both sides are exactly equal\n                code: assert {1, 2, 3} > {1, 2, 3}\n                left: {1, 2, 3}\n           \"\"\"\n\n    assert format_assertion_diff(assertion_error, 0, :infinity, &diff_formatter/2)\n           |> kw_to_string() ==\n             [left: \"{1, 2, 3}\"]\n\n    assertion_error = catch_assertion(assert {3, 2, 1} = {1, 2, 3})\n    failure = [{:error, assertion_error, []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                match (=) failed\n                code:  assert {3, 2, 1} = {1, 2, 3}\n                left:  {3, 2, 1}\n                right: {1, 2, 3}\n           \"\"\"\n\n    assert format_assertion_diff(assertion_error, 0, :infinity, &diff_formatter/2)\n           |> kw_to_string() ==\n             [{:left, \"{-3-, 2, -1-}\"}, {:right, \"{+1+, 2, +3+}\"}]\n  end\n\n  nfc_hello = String.normalize(\"héllo\", :nfc)\n  nfd_hello = String.normalize(\"héllo\", :nfd)\n\n  nfc_left_hello = String.normalize(\"h-é-llo\", :nfc)\n  nfd_right_hello = String.normalize(\"h+é+llo\", :nfd)\n\n  test \"formats assertions with hints\" do\n    assertion_error = catch_assertion(assert unquote(nfc_hello) == unquote(nfd_hello))\n    failure = [{:error, assertion_error, []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &diff_formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                Assertion with == failed\n                code:  assert \"#{unquote(nfc_hello)}\" == \"#{unquote(nfd_hello)}\"\n                left:  \"#{unquote(nfc_left_hello)}\"\n                right: \"#{unquote(nfd_right_hello)}\"\n                hint:  you are comparing strings that have the same visual representation but are made of different Unicode codepoints\n           \"\"\"\n\n    assert format_assertion_diff(assertion_error, 0, :infinity, &diff_formatter/2)\n           |> kw_to_string() ==\n             [\n               left: inspect(unquote(nfc_left_hello)),\n               right: inspect(unquote(nfd_right_hello)),\n               hint:\n                 \"you are comparing strings that have the same visual representation but are made of different Unicode codepoints\"\n             ]\n  end\n\n  test \"formats match error between pinned struct type and a non-struct\" do\n    failure = [\n      {:error,\n       catch_assertion do\n         expected_module = ExUnit.TestModule\n         assert %^expected_module{} = nil\n       end, []}\n    ]\n\n    assert format_test_failure(test(), failure, 1, 80, &diff_formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                match (=) failed\n                The following variables were pinned:\n                  expected_module = ExUnit.TestModule\n                code:  assert %^expected_module{} = nil\n                left:  -%^expected_module{}-\n                right: +nil+\n           \"\"\"\n  end\n\n  test \"formats multiple assertions\" do\n    failure = [\n      {:error, catch_assertion(assert ExUnit.FormatterTest.falsy()), []},\n      {:error, catch_assertion(assert 1 == 2), []}\n    ]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n\n                Failure #1\n                Expected truthy, got false\n                code: assert ExUnit.FormatterTest.falsy()\n\n                Failure #2\n                Assertion with == failed\n                code:  assert 1 == 2\n                left:  1\n                right: 2\n           \"\"\"\n  end\n\n  defp trim_multiline_whitespace(string) do\n    String.replace(string, ~r\"\\n\\s+\\n\", \"\\n\\n\")\n  end\n\n  test \"blames function clause error\" do\n    {error, stack} =\n      try do\n        Access.fetch(Process.get(:unused, :foo), :bar)\n      rescue\n        exception -> {exception, __STACKTRACE__}\n      end\n\n    failure = format_test_failure(test(), [{:error, error, [hd(stack)]}], 1, 80, &formatter/2)\n\n    assert trim_multiline_whitespace(failure) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (FunctionClauseError) no function clause matching in Access.fetch/2\n\n                The following arguments were given to Access.fetch/2:\n\n                    # 1\n                    :foo\n\n                    # 2\n                    :bar\n           \"\"\"\n\n    if Access not in :cover.modules() do\n      assert failure =~\n               \"\"\"\n                    Attempted function clauses (showing 5 out of 5):\n\n                        def fetch(%module{} = container, key)\n               \"\"\"\n    end\n\n    assert failure =~ ~r\"\\(elixir #{System.version()}\\) lib/access\\.ex:\\d+: Access\\.fetch/2\"\n  end\n\n  test \"formats setup_all errors\" do\n    failure = [{:error, catch_error(raise \"oops\"), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) Hello: failure on setup_all callback, all tests have been invalidated\n                ** (RuntimeError) oops\n           \"\"\"\n  end\n\n  test \"formats matches correctly\" do\n    failure = [{:error, catch_assertion(assert %{a: :b} = %{a: :c}), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, :infinity, &formatter/2) =~ \"\"\"\n             1) Hello: failure on setup_all callback, all tests have been invalidated\n                match (=) failed\n                code:  assert %{a: :b} = %{a: :c}\n                left:  %{a: :b}\n                right: %{a: :c}\n           \"\"\"\n  end\n\n  test \"formats setup_all exit stacktraces using module context\" do\n    stacktrace = [\n      {Hello, :setup_all, [], [file: __ENV__.file, line: 123]},\n      {Hello, :some_fun, [], [file: __ENV__.file, line: 456]}\n    ]\n\n    failure = [{{:EXIT, self()}, {:function_clause, stacktrace}, []}]\n\n    formatted =\n      format_test_all_failure(test_module(), failure, 1, 80, &formatter/2)\n\n    assert formatted =~ \"Hello.setup_all/0\"\n    assert formatted =~ \"Hello.some_fun()\"\n  end\n\n  test \"formats assertions with operators with no limit\" do\n    failure = [{:error, catch_assertion(assert [1, 2, 3] == [4, 5, 6]), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, :infinity, &formatter/2) =~ \"\"\"\n             1) Hello: failure on setup_all callback, all tests have been invalidated\n                Assertion with == failed\n                code:  assert [1, 2, 3] == [4, 5, 6]\n                left:  [1, 2, 3]\n                right: [4, 5, 6]\n           \"\"\"\n  end\n\n  test \"formats assertions with operators with column limit\" do\n    failure = [{:error, catch_assertion(assert [1, 2, 3] == [4, 5, 6]), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, 15, &formatter/2) =~ \"\"\"\n             1) Hello: failure on setup_all callback, all tests have been invalidated\n                Assertion with == failed\n                code:  assert [1, 2, 3] == [4, 5, 6]\n                left:  [1,\n                        2,\n                        3]\n                right: [4,\n                        5,\n                        6]\n           \"\"\"\n  end\n\n  test \"formats assertions with complex function call arguments\" do\n    failure = [{:error, catch_assertion(assert is_list(List.to_tuple([1, 2, 3]))), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) Hello: failure on setup_all callback, all tests have been invalidated\n                Expected truthy, got false\n                code: assert is_list(List.to_tuple([1, 2, 3]))\n                arguments:\n\n                    # 1\n                    {1, 2, 3}\n           \"\"\"\n\n    failure = [{:error, catch_assertion(assert is_list({1, 2})), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) Hello: failure on setup_all callback, all tests have been invalidated\n                Expected truthy, got false\n                code: assert is_list({1, 2})\n           \"\"\"\n  end\n\n  test \"formats assertions with message with multiple lines\" do\n    message = \"Some meaningful error:\\nuseful info\\nanother useful info\"\n    failure = [{:error, catch_assertion(assert(false, message)), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, :infinity, &formatter/2) =~ \"\"\"\n             1) Hello: failure on setup_all callback, all tests have been invalidated\n                Some meaningful error:\n                useful info\n                another useful info\n           \"\"\"\n  end\n\n  test \"formats assertions with nested improper list diffing\" do\n    failure = [{:error, catch_assertion(assert :foo = %{bar: [1 | 2]}), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, :infinity, &diff_formatter/2) =~ \"\"\"\n           match (=) failed\n                code:  assert :foo = %{bar: [1 | 2]}\n                left:  -:foo-\n                right: +%{bar: [1 | 2]}+\n           \"\"\"\n  end\n\n  test \"formats assertions with binary matching without diffing\" do\n    failure = [{:error, catch_assertion(assert %{foo: <<_>>, bar: 2} = %{foo: \"!\", bar: 3}), []}]\n\n    assert format_test_all_failure(test_module(), failure, 1, :infinity, &diff_formatter/2) =~ \"\"\"\n           match (=) failed\n                code:  assert %{foo: <<_>>, bar: 2} = %{foo: \"!\", bar: 3}\n                left:  %{foo: <<_>>, bar: 2}\n                right: %{foo: \"!\", bar: 3}\n           \"\"\"\n  end\n\n  defmodule BadInspect do\n    defstruct key: 0\n\n    defimpl Inspect do\n      def inspect(_struct, opts) when is_atom(opts) do\n        raise \"the clause above should never match\"\n      end\n    end\n  end\n\n  test \"inspect failure\" do\n    failure = [{:error, catch_assertion(assert :will_fail == struct!(BadInspect)), []}]\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ ~s'''\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                Assertion with == failed\n                code:  assert :will_fail == struct!(BadInspect)\n                left:  :will_fail\n                right: #Inspect.Error<\n             got FunctionClauseError with message:\n\n                 \"\"\"\n                 no function clause matching in Inspect.ExUnit.FormatterTest.BadInspect.inspect/2\n                 \"\"\"\n\n             while inspecting:\n\n                 #{inspect(%BadInspect{}, structs: false)}\n\n             Stacktrace:\n           '''\n  end\n\n  defmodule BadMessage do\n    defexception key: 0\n\n    @impl true\n    def message(_message) do\n      raise \"oops\"\n    end\n  end\n\n  test \"message failure\" do\n    failure = [{:error, catch_error(raise BadMessage), []}]\n\n    message =\n      \"got RuntimeError with message \\\"oops\\\" while retrieving Exception.message/1 \" <>\n        \"for %ExUnit.FormatterTest.BadMessage{key: 0}. Stacktrace:\"\n\n    assert format_test_failure(test(), failure, 1, 80, &formatter/2) =~ \"\"\"\n             1) world (Hello)\n                test/ex_unit/formatter_test.exs:1\n                ** (ExUnit.FormatterTest.BadMessage) #{message}\n           \"\"\"\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/register_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.RegisterTest do\n  use ExUnit.Case\n\n  import ExUnit.CaptureIO\n\n  test \"singular test types\" do\n    on_exit(fn ->\n      ExUnit.configure(plural_rules: %{})\n    end)\n\n    ExUnit.plural_rule(\"property\", \"properties\")\n\n    defmodule SingularTestTypeCase do\n      use ExUnit.Case\n\n      :\"property is true\" =\n        ExUnit.Case.register_test(\n          __ENV__.module,\n          __ENV__.file,\n          __ENV__.line,\n          :property,\n          \"is true\",\n          []\n        )\n\n      def unquote(:\"property is true\")(_) do\n        assert succeed()\n      end\n\n      test \"test true\" do\n        assert succeed()\n      end\n\n      defp succeed, do: true\n    end\n\n    assert capture_io(fn ->\n             assert ExUnit.run() == %{failures: 0, skipped: 0, total: 2, excluded: 0}\n           end) =~ \"Result: 2 passed (1 property, 1 test)\"\n  end\n\n  test \"plural test types\" do\n    on_exit(fn ->\n      ExUnit.configure(plural_rules: %{})\n    end)\n\n    ExUnit.plural_rule(\"property\", \"properties\")\n\n    defmodule PluralTestTypeCase do\n      use ExUnit.Case\n\n      :\"property is true\" =\n        ExUnit.Case.register_test(\n          __ENV__.module,\n          __ENV__.file,\n          __ENV__.line,\n          :property,\n          \"is true\",\n          []\n        )\n\n      def unquote(:\"property is true\")(_) do\n        assert succeed()\n      end\n\n      :\"property is also true\" =\n        ExUnit.Case.register_test(\n          __ENV__.module,\n          __ENV__.file,\n          __ENV__.line,\n          :property,\n          \"is also true\",\n          []\n        )\n\n      def unquote(:\"property is also true\")(_) do\n        assert succeed()\n      end\n\n      test \"test true\" do\n        assert succeed()\n      end\n\n      test \"test true also\" do\n        assert succeed()\n      end\n\n      defp succeed, do: true\n    end\n\n    assert capture_io(fn ->\n             assert ExUnit.run() == %{failures: 0, skipped: 0, total: 4, excluded: 0}\n           end) =~ \"Result: 4 passed (2 properties, 2 tests)\"\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/runner_stats_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.RunnerStatsTest do\n  use ExUnit.Case, async: false\n\n  alias ExUnit.{FailuresManifest, RunnerStats}\n\n  @failures_manifest_path \"ex_unit_failures_manifest.elixir\"\n\n  describe \"stats tracking\" do\n    test \"counts total, failures, skipped, and excluded tests\" do\n      stats =\n        simulate_suite([], fn formatter ->\n          simulate_test(formatter, :test_1, :passed)\n          simulate_test(formatter, :test_2, :skipped)\n          simulate_test(formatter, :test_3, :failed)\n          simulate_test(formatter, :test_4, :invalid)\n          simulate_test(formatter, :test_5, :passed)\n          simulate_test(formatter, :test_6, :passed)\n          simulate_test(formatter, :test_7, :excluded)\n          simulate_test(formatter, :test_8, :excluded)\n          simulate_test(formatter, :test_9, :excluded)\n          simulate_test(formatter, :test_10, :excluded)\n        end)\n\n      assert stats == %{total: 10, failures: 2, skipped: 1, excluded: 4}\n    end\n\n    test \"invalidates successful tests when a module fails\" do\n      module_tests_a = [\n        {:test_a1, :passed},\n        {:test_a2, :skipped},\n        {:test_a3, :failed},\n        {:test_a4, :invalid},\n        {:test_a5, :excluded}\n      ]\n\n      module_tests_b = [\n        {:test_b1, :passed},\n        {:test_b2, :failed},\n        {:test_b3, :failed},\n        {:test_b4, :passed},\n        {:test_b5, :passed}\n      ]\n\n      tests = module_tests_a ++ module_tests_b\n\n      stats =\n        simulate_suite([], fn formatter ->\n          for {test_name, status} <- tests do\n            simulate_test(formatter, test_name, status)\n          end\n\n          simulate_module_finished(\n            formatter,\n            :module_a,\n            :passed,\n            module_tests_a\n          )\n\n          simulate_module_finished(\n            formatter,\n            :module_b,\n            :failed,\n            module_tests_b\n          )\n        end)\n\n      assert stats == %{total: 10, failures: 7, skipped: 1, excluded: 1}\n    end\n  end\n\n  describe \"when no failures manifest path option is provided\" do\n    @tag :tmp_dir\n    test \"does not write a failures manifest\", %{tmp_dir: tmp_dir} do\n      File.cd!(tmp_dir, fn ->\n        simulate_suite([], fn formatter ->\n          simulate_test(formatter, :test_1, :passed)\n          simulate_test(formatter, :test_2, :failed)\n        end)\n\n        assert File.ls(\".\") == {:ok, []}\n      end)\n    end\n  end\n\n  describe \"when a failures manifest path option is provided\" do\n    @tag :tmp_dir\n    test \"records the test failures in the failures manifest file\", %{tmp_dir: tmp_dir} do\n      File.cd!(tmp_dir, fn ->\n        simulate_suite(fn formatter ->\n          simulate_test(formatter, :test_1, :passed)\n          simulate_test(formatter, :test_2, :failed)\n        end)\n\n        assert read_failures_manifest() == %{{TestModule, :test_2} => __ENV__.file}\n      end)\n    end\n\n    @tag :tmp_dir\n    test \"merges the results with the results from the prior run\", %{tmp_dir: tmp_dir} do\n      File.cd!(tmp_dir, fn ->\n        simulate_suite(&simulate_test(&1, :test_1, :failed))\n        simulate_suite(&simulate_test(&1, :test_2, :failed))\n\n        assert read_failures_manifest() == %{\n                 {TestModule, :test_1} => __ENV__.file,\n                 {TestModule, :test_2} => __ENV__.file\n               }\n      end)\n    end\n  end\n\n  defp simulate_suite(opts \\\\ [failures_manifest_path: @failures_manifest_path], fun) do\n    {:ok, pid} = GenServer.start_link(RunnerStats, opts)\n    GenServer.cast(pid, {:suite_started, opts})\n\n    fun.(pid)\n\n    GenServer.cast(pid, {:suite_finished, %{}})\n    RunnerStats.stats(pid)\n  end\n\n  defp simulate_test(formatter, test_name, status) do\n    GenServer.cast(\n      formatter,\n      {:test_finished,\n       %ExUnit.Test{\n         module: TestModule,\n         name: test_name,\n         tags: %{file: __ENV__.file},\n         state: state_for(status)\n       }}\n    )\n  end\n\n  defp simulate_module_finished(formatter, module_name, status, tests) do\n    tests =\n      for {test_name, status} <- tests do\n        %ExUnit.Test{\n          module: TestModule,\n          name: test_name,\n          tags: %{file: __ENV__.file},\n          state: state_for(status)\n        }\n      end\n\n    GenServer.cast(\n      formatter,\n      {:module_finished,\n       %ExUnit.TestModule{\n         file: __ENV__.file,\n         name: module_name,\n         state: state_for(status),\n         tests: tests\n       }}\n    )\n  end\n\n  defp state_for(:passed), do: nil\n  defp state_for(:failed), do: {:failed, []}\n  defp state_for(:invalid), do: {:invalid, %ExUnit.TestModule{}}\n  defp state_for(:skipped), do: {:skipped, \"reason\"}\n  defp state_for(:excluded), do: {:excluded, \"reason\"}\n\n  defp read_failures_manifest do\n    FailuresManifest.read(@failures_manifest_path)\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit/supervised_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule ExUnit.SupervisedTest do\n  use ExUnit.Case, async: true\n\n  defmodule MyAgent do\n    use Agent\n\n    def start_link(:error) do\n      {:error, \"some error\"}\n    end\n\n    def start_link(:exception) do\n      raise \"some exception\"\n    end\n\n    def start_link(arg) do\n      Agent.start_link(fn -> arg end, name: __MODULE__)\n    end\n  end\n\n  test \"returns error if the supervised process returns an error tuple\" do\n    {:error, error} = start_supervised({MyAgent, :error})\n    assert {\"some error\", _info} = error\n\n    message =\n      \"failed to start child with the spec {ExUnit.SupervisedTest.MyAgent, :error}.\\n\" <>\n        \"Reason: \\\"some error\\\"\"\n\n    assert_raise RuntimeError, message, fn ->\n      start_supervised!({MyAgent, :error})\n    end\n  end\n\n  test \"returns error if the supervised process raises an exception\" do\n    {:error, {{:EXIT, {exception, _}}, _}} = start_supervised({MyAgent, :exception})\n    assert exception == %RuntimeError{message: \"some exception\"}\n\n    message =\n      \"failed to start child with the spec {ExUnit.SupervisedTest.MyAgent, :exception}.\\n\" <>\n        \"Reason: an exception was raised:\\n\" <> \"    ** (RuntimeError) some exception\"\n\n    exception =\n      assert_raise RuntimeError, fn ->\n        start_supervised!({MyAgent, :exception})\n      end\n\n    assert String.starts_with?(Exception.message(exception), message)\n  end\n\n  test \"starts a supervised process that terminates before on_exit\" do\n    {:ok, pid} = start_supervised(MyAgent)\n    assert Process.alive?(pid)\n    on_exit(fn -> refute Process.alive?(pid) end)\n  end\n\n  test \"starts a supervised process that is permanent\" do\n    {:ok, _} = start_supervised({MyAgent, 0})\n    Agent.update(MyAgent, &(&1 + 1))\n    assert Agent.get(MyAgent, & &1) == 1\n    Agent.stop(MyAgent)\n    wait_until_registered(MyAgent)\n    assert Agent.get(MyAgent, & &1) == 0\n  end\n\n  test \"starts a supervised process that is temporary\" do\n    {:ok, _} = start_supervised({MyAgent, 0}, restart: :temporary)\n    Agent.update(MyAgent, &(&1 + 1))\n    assert Agent.get(MyAgent, & &1) == 1\n    Agent.stop(MyAgent)\n    refute Process.whereis(MyAgent)\n  end\n\n  test \"starts a supervised process with ID checks\" do\n    {:ok, pid} = start_supervised({MyAgent, 0})\n    assert is_pid(pid)\n\n    assert {:error, _} = start_supervised({MyAgent, 0})\n    assert {:error, _} = start_supervised({MyAgent, 0}, id: :another)\n\n    assert_raise RuntimeError, ~r\"Reason: bad child specification\", fn ->\n      start_supervised!(%{id: 1, start: :oops})\n    end\n  end\n\n  test \"starts a supervised process with correct :\\\"$callers\\\"\" do\n    test_pid = self()\n    fun = fn -> send(test_pid, {:callers, Process.get(:\"$callers\")}) end\n    {:ok, _pid} = start_supervised({Task, fun})\n\n    assert_receive {:callers, callers}\n    assert List.last(callers) == test_pid\n  end\n\n  test \"starts a supervised process with correct :\\\"$ancestors\\\"\" do\n    test_pid = self()\n    fun = fn -> send(test_pid, {:ancestors, Process.get(:\"$ancestors\")}) end\n    {:ok, _pid} = start_supervised({Task, fun})\n\n    assert_receive {:ancestors, ancestors}\n    assert List.last(ancestors) == test_pid\n  end\n\n  test \"stops a supervised process\" do\n    {:ok, pid} = start_supervised({MyAgent, 0})\n    assert stop_supervised(MyAgent) == :ok\n    refute Process.alive?(pid)\n  end\n\n  test \"stops a linked supervised process\" do\n    pid = start_link_supervised!({MyAgent, 0})\n    assert stop_supervised(MyAgent) == :ok\n    refute Process.alive?(pid)\n  end\n\n  test \"stops a temporary supervised process\" do\n    {:ok, pid} = start_supervised({MyAgent, 0}, restart: :temporary)\n    assert stop_supervised(MyAgent) == :ok\n    refute Process.alive?(pid)\n  end\n\n  test \"stops! a supervised process\" do\n    {:ok, pid} = start_supervised({MyAgent, 0})\n    assert stop_supervised!(MyAgent) == :ok\n    refute Process.alive?(pid)\n  end\n\n  test \"does not stop unknown processes\" do\n    assert stop_supervised(:unknown) == {:error, :not_found}\n    {:ok, _} = start_supervised({MyAgent, 0})\n    assert stop_supervised(:unknown) == {:error, :not_found}\n  end\n\n  test \"raises if starting or stopping outside of test process\" do\n    Task.async(fn ->\n      message = \"start_supervised/2 can only be invoked from the test process\"\n\n      assert_raise ArgumentError, message, fn ->\n        start_supervised(MyAgent)\n      end\n\n      message = \"stop_supervised/1 can only be invoked from the test process\"\n\n      assert_raise ArgumentError, message, fn ->\n        stop_supervised(MyAgent)\n      end\n    end)\n    |> Task.await()\n  end\n\n  defp wait_until_registered(name) do\n    if !Process.whereis(name) do\n      wait_until_registered(name)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/ex_unit_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule ExUnitTest do\n  use ExUnit.Case\n\n  import ExUnit.CaptureIO\n\n  test \"supports many runs and loads\" do\n    defmodule SampleTest do\n      use ExUnit.Case\n\n      test \"true\" do\n        assert false\n      end\n\n      test \"false\" do\n        assert false\n      end\n    end\n\n    configure_and_reload_on_exit([])\n\n    assert capture_io(fn ->\n             assert ExUnit.run() == %{failures: 2, skipped: 0, total: 2, excluded: 0}\n           end) =~ \"Failed: 2 tests\"\n\n    ExUnit.Server.modules_loaded(false)\n\n    assert capture_io(fn ->\n             assert ExUnit.async_run() |> ExUnit.await_run() ==\n                      %{failures: 0, skipped: 0, total: 0, excluded: 0}\n           end) =~ \"\\nResult: 0 tests\\n\"\n  end\n\n  test \"supports rerunning given modules\" do\n    defmodule SampleAsyncTest do\n      use ExUnit.Case, async: true, register: false\n\n      test \"true\" do\n        assert false\n      end\n    end\n\n    defmodule SampleSyncTest do\n      use ExUnit.Case, register: false\n\n      test \"true\" do\n        assert false\n      end\n    end\n\n    defmodule IgnoreTest do\n      use ExUnit.Case\n\n      test \"true\" do\n        assert false\n      end\n    end\n\n    configure_and_reload_on_exit([])\n\n    assert capture_io(fn ->\n             assert ExUnit.run() == %{\n                      failures: 1,\n                      skipped: 0,\n                      total: 1,\n                      excluded: 0\n                    }\n           end) =~ \"Failed: 1 test\"\n\n    sample = [SampleSyncTest, SampleAsyncTest]\n\n    assert capture_io(fn ->\n             assert ExUnit.run(sample) == %{\n                      failures: 2,\n                      skipped: 0,\n                      total: 2,\n                      excluded: 0\n                    }\n           end) =~ \"Failed: 2 tests\"\n\n    assert capture_io(fn ->\n             assert ExUnit.run(sample ++ sample) == %{\n                      failures: 2,\n                      skipped: 0,\n                      total: 2,\n                      excluded: 0\n                    }\n           end) =~ \"Failed: 2 tests\"\n  end\n\n  test \"prints aborted runs on sigquit\", config do\n    Process.register(self(), :aborted_on_sigquit)\n    line = __ENV__.line + 5\n\n    defmodule SleepOnTest do\n      use ExUnit.Case, async: true\n\n      test \"true\" do\n        send(:aborted_on_sigquit, :sleeping)\n        Process.sleep(:infinity)\n      end\n    end\n\n    defmodule SleepOnSetupAll do\n      use ExUnit.Case, async: true\n\n      setup_all do\n        send(:aborted_on_sigquit, :sleeping)\n        Process.sleep(:infinity)\n      end\n\n      test \"true\", do: :ok\n    end\n\n    configure_and_reload_on_exit(max_cases: 8)\n\n    result =\n      capture_io(fn ->\n        {pid, ref} = spawn_monitor(fn -> ExUnit.run() end)\n        assert_receive :sleeping\n        assert_receive :sleeping\n\n        # We are testing implementation details but since this involves\n        # the signal handler, it is truly the only way to test it.\n        send(pid, {ref, self(), :sigquit})\n\n        receive do\n          ^ref -> :ok\n        end\n      end)\n\n    assert result =~ \"Aborting test suite, the following have not completed:\"\n    assert result =~ ~r\"\\* ExUnitTest.SleepOnSetupAll \\[.*test/ex_unit_test.exs\\]\"\n    assert result =~ ~r\"\\* test true \\[.*test/ex_unit_test.exs:#{line}\\]\"\n\n    assert result =~ \"Showing results so far...\"\n    assert result =~ \"Result: 0 tests\"\n  end\n\n  test \"doesn't hang on exits\" do\n    defmodule EventServerTest do\n      use ExUnit.Case\n\n      test \"spawn and crash\" do\n        spawn_link(fn ->\n          exit(:foo)\n        end)\n\n        receive after: (1000 -> :ok)\n      end\n    end\n\n    configure_and_reload_on_exit([])\n\n    assert capture_io(fn ->\n             assert ExUnit.run() == %{failures: 1, skipped: 0, total: 1, excluded: 0}\n           end) =~ \"Failed: 1 test\"\n  end\n\n  test \"reports capture log crashes\" do\n    defmodule CaptureLogTest do\n      use ExUnit.Case\n\n      test \"capture log crash because logger stopped\" do\n        Logger.App.stop()\n        Logger.App.start()\n        flunk(\"this should fail\")\n      end\n    end\n\n    configure_and_reload_on_exit([])\n\n    assert capture_io(fn ->\n             assert ExUnit.run() == %{failures: 1, skipped: 0, total: 1, excluded: 0}\n           end) =~ \"Failed: 1 test\"\n  end\n\n  test \"supports timeouts\" do\n    defmodule TimeoutTest do\n      use ExUnit.Case\n\n      @tag timeout: 10\n      test \"ok\" do\n        Process.sleep(:infinity)\n      end\n    end\n\n    output = capture_io(fn -> ExUnit.run() end)\n    assert output =~ \"** (ExUnit.TimeoutError) test timed out after 10ms\"\n    assert output =~ ~r\"\\(elixir #{System.version()}\\) lib/process\\.ex:\\d+: Process\\.sleep/1\"\n  end\n\n  test \"supports configured timeout\" do\n    defmodule ConfiguredTimeoutTest do\n      use ExUnit.Case\n\n      test \"ok\" do\n        Process.sleep(:infinity)\n      end\n    end\n\n    ExUnit.configure(timeout: 5)\n    output = capture_io(fn -> ExUnit.run() end)\n    assert output =~ \"** (ExUnit.TimeoutError) test timed out after 5ms\"\n  after\n    ExUnit.configure(timeout: 60_000)\n  end\n\n  test \"reports slow tests\" do\n    defmodule SlowestTest do\n      use ExUnit.Case\n\n      test \"tardy\" do\n        refute false\n      end\n\n      test \"delayed\" do\n        Process.sleep(5)\n        assert false\n      end\n\n      test \"slowest\" do\n        Process.sleep(10)\n        refute false\n      end\n    end\n\n    configure_and_reload_on_exit(slowest: 2)\n\n    output = capture_io(fn -> ExUnit.run() end)\n    assert output =~ ~r\"Top 2 slowest \\(\\d+\\.\\d+s\\), \\d+.\\d% of total time:\"\n    assert output =~ ~r\"\\* test slowest \\(.+ms\\)\"\n    assert output =~ ~r\"\\* test delayed \\(.+ms\\)\"\n  end\n\n  test \"reports slow test modules\" do\n    defmodule SlowTestModule do\n      use ExUnit.Case\n\n      test \"slow\" do\n        refute false\n      end\n    end\n\n    defmodule SlowerTestModule do\n      use ExUnit.Case\n\n      test \"slower\" do\n        Process.sleep(5)\n        refute false\n      end\n    end\n\n    defmodule SlowestTestModule do\n      use ExUnit.Case\n\n      test \"slowest\" do\n        Process.sleep(10)\n        refute false\n      end\n    end\n\n    configure_and_reload_on_exit(slowest_modules: 2)\n\n    output = capture_io(fn -> ExUnit.run() end)\n    assert output =~ ~r\"Top 2 slowest \\(\\d+\\.\\d+s\\), \\d+.\\d% of total time:\"\n    assert output =~ ~r\"SlowestTestModule \\(.+ms\\)\"\n    assert output =~ ~r\"SlowerTestModule \\(.+ms\\)\"\n  end\n\n  test \"sets max cases to one with trace enabled\" do\n    configure_and_reload_on_exit(trace: true, max_cases: 10)\n    config = ExUnit.configuration()\n    assert config[:trace]\n    assert config[:max_cases] == 1\n    assert config[:timeout] == 60_000\n  end\n\n  test \"sets trace when slowest is enabled\" do\n    configure_and_reload_on_exit(slowest: 10, max_cases: 10)\n    config = ExUnit.configuration()\n    assert config[:trace]\n    assert config[:slowest] == 10\n    assert config[:max_cases] == 1\n  end\n\n  test \"filters to the given test IDs when the :only_test_ids option is provided\" do\n    defmodule TestIdTestModule do\n      use ExUnit.Case\n\n      test \"passing\", do: :ok\n      test \"failing\", do: assert(1 == 2)\n    end\n\n    test_ids =\n      MapSet.new([\n        {TestIdTestModule, :\"test failing\"},\n        {TestIdTestModule, :\"test missing\"},\n        {MissingModule, :\"test passing\"}\n      ])\n\n    {result, output} = run_with_filter([only_test_ids: test_ids], [])\n    assert result == %{failures: 1, skipped: 0, excluded: 0, total: 1}\n    assert output =~ \"Failed: 1 test\"\n  end\n\n  test \"filtering cases with tags\" do\n    defmodule ParityTest do\n      use ExUnit.Case\n\n      test \"zero\", do: :ok\n\n      @tag even: false\n      test \"one\", do: :ok\n\n      @tag even: true\n      test \"two\", do: assert(1 == 2)\n\n      @tag even: false\n      test \"three\", do: :ok\n    end\n\n    # Empty because it is already loaded\n    {result, output} = run_with_filter([], [])\n    assert result == %{failures: 1, skipped: 0, total: 4, excluded: 0}\n    assert output =~ \"Failed: 1 test\"\n\n    {result, output} = run_with_filter([exclude: [even: true]], [ParityTest])\n    assert result == %{failures: 0, skipped: 0, excluded: 1, total: 4}\n    assert output =~ \"Result: 3 passed\"\n\n    {result, output} = run_with_filter([exclude: :even], [ParityTest])\n    assert result == %{failures: 0, skipped: 0, excluded: 3, total: 4}\n    assert output =~ \"Result: 1 passed\"\n\n    {result, output} = run_with_filter([exclude: :even, include: [even: true]], [ParityTest])\n    assert result == %{failures: 1, skipped: 0, excluded: 2, total: 4}\n    assert output =~ \"Failed: 1 test\"\n\n    {result, output} = run_with_filter([exclude: :test, include: [even: true]], [ParityTest])\n    assert result == %{failures: 1, skipped: 0, excluded: 3, total: 4}\n    assert output =~ \"Failed: 1 test\"\n  end\n\n  test \"log capturing\" do\n    defmodule LogCapturingTest do\n      use ExUnit.Case\n      require Logger\n\n      @tag :capture_log\n      test \"one\" do\n        Logger.debug(\"one\")\n        assert 1 == 1\n      end\n\n      @tag :capture_log\n      test \"two\" do\n        Logger.debug(\"two\")\n        assert 1 == 2\n      end\n\n      @tag capture_log: []\n      test \"three\" do\n        Logger.debug(\"three\")\n        assert 1 == 2\n      end\n    end\n\n    output = capture_io(&ExUnit.run/0)\n    refute output =~ \"[debug] one\"\n    assert output =~ \"[debug] two\"\n    assert output =~ \"[debug] three\"\n  end\n\n  test \"supports multi errors\" do\n    capture_io(:stderr, fn ->\n      defmodule MultiTest do\n        use ExUnit.Case\n\n        test \"multi\" do\n          error1 =\n            try do\n              assert 1 = 2\n            rescue\n              e in ExUnit.AssertionError ->\n                {:error, e, __STACKTRACE__}\n            end\n\n          error2 =\n            try do\n              assert 3 > 4\n            rescue\n              e in ExUnit.AssertionError ->\n                {:error, e, __STACKTRACE__}\n            end\n\n          raise ExUnit.MultiError, errors: [error1, error2]\n        end\n      end\n    end)\n\n    configure_and_reload_on_exit([])\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{failures: 1, skipped: 0, total: 1, excluded: 0}\n      end)\n\n    assert output =~ \"Failed: 1 test\"\n    assert output =~ \"\\n  1) test multi (ExUnitTest.MultiTest)\\n\"\n    assert output =~ \"Failure #1\\n\"\n    assert output =~ \"Failure #2\\n\"\n\n    assert_raise ExUnit.MultiError, ~r/oops/, fn ->\n      stack =\n        try do\n          raise(\"oops\")\n        rescue\n          _ -> __STACKTRACE__\n        end\n\n      error = {:error, RuntimeError.exception(\"oops\"), stack}\n      raise ExUnit.MultiError, errors: [error]\n    end\n  end\n\n  test \"raises friendly error for duplicate test names\" do\n    message = ~S(\"test duplicate\" is already defined in ExUnitTest.TestWithSameNames)\n\n    assert_raise ArgumentError, message, fn ->\n      defmodule TestWithSameNames do\n        use ExUnit.Case\n\n        test \"duplicate\" do\n          assert true\n        end\n\n        test \"duplicate\" do\n          assert true\n        end\n      end\n    end\n  end\n\n  test \"produces error on not implemented tests\" do\n    defmodule TestNotImplemented do\n      use ExUnit.Case\n\n      setup context do\n        assert context[:not_implemented]\n        :ok\n      end\n\n      test \"this is not implemented yet\"\n    end\n\n    configure_and_reload_on_exit([])\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{failures: 1, skipped: 0, total: 1, excluded: 0}\n      end)\n\n    assert output =~ \"Not implemented\\n\"\n    assert output =~ \"Failed: 1 test\"\n  end\n\n  test \"skips tagged test with skip\" do\n    defmodule TestSkipped do\n      use ExUnit.Case\n\n      setup context do\n        assert context[:not_implemented]\n        :ok\n      end\n\n      @tag :skip\n      test \"this will raise\", do: raise(\"oops\")\n\n      @tag skip: \"won't work\"\n      test \"this will also raise\", do: raise(\"oops\")\n    end\n\n    configure_and_reload_on_exit([])\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{failures: 0, skipped: 2, total: 2, excluded: 0}\n      end)\n\n    assert output =~ \"Result: 0 tests\"\n  end\n\n  test \"filtering cases with :module tag\" do\n    defmodule FirstTestModule do\n      use ExUnit.Case\n      test \"ok\", do: :ok\n    end\n\n    defmodule SecondTestModule do\n      use ExUnit.Case\n      test \"false\", do: assert(false)\n    end\n\n    # Empty because it is already loaded\n    {result, output} = run_with_filter([exclude: :module], [])\n\n    assert result == %{failures: 0, skipped: 0, excluded: 2, total: 2}\n    assert output =~ \"Result: 0 tests\"\n\n    {result, output} =\n      [exclude: :test, include: [module: \"ExUnitTest.SecondTestModule\"]]\n      |> run_with_filter([FirstTestModule, SecondTestModule])\n\n    assert result == %{failures: 1, skipped: 0, excluded: 1, total: 2}\n    assert output =~ \"\\n  1) test false (ExUnitTest.SecondTestModule)\\n\"\n    assert output =~ \"Failed: 1 test\"\n  end\n\n  test \"raises on reserved tag :file in module\" do\n    assert_raise RuntimeError, \"cannot set tag :file because it is reserved by ExUnit\", fn ->\n      defmodule ReservedTagFile do\n        use ExUnit.Case\n\n        @tag file: \"oops\"\n        test \"sample\", do: :ok\n      end\n    end\n  end\n\n  test \"raises on reserved tag :async in module\" do\n    assert_raise RuntimeError, \"cannot set tag :async because it is reserved by ExUnit\", fn ->\n      defmodule ReservedTagAsync do\n        use ExUnit.Case\n\n        @tag async: true\n        test \"sample\", do: :ok\n      end\n    end\n  end\n\n  test \"raises on reserved tag :file in setup\" do\n    defmodule ReservedSetupTagFile do\n      use ExUnit.Case\n\n      setup do\n        {:ok, file: :foo}\n      end\n\n      test \"sample\", do: :ok\n    end\n\n    configure_and_reload_on_exit([])\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{failures: 1, skipped: 0, total: 1, excluded: 0}\n      end)\n\n    assert output =~ \"trying to set reserved field :file\"\n  end\n\n  test \"removes new lines from multiline test name (with --trace option)\" do\n    defmodule Multiline do\n      use ExUnit.Case\n\n      test \"\"\"\n      - line 1\n      - line 2\n      \"\"\" do\n        :ok\n      end\n    end\n\n    configure_and_reload_on_exit(trace: true)\n\n    output = capture_io(fn -> ExUnit.run() end)\n\n    assert output =~ \"test - line 1 - line 2\"\n  end\n\n  test \"raises on reserved tag :async in setup\" do\n    defmodule ReservedSetupTagAsync do\n      use ExUnit.Case\n\n      setup do\n        {:ok, async: true}\n      end\n\n      test \"sample\", do: :ok\n    end\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{failures: 1, skipped: 0, total: 1, excluded: 0}\n      end)\n\n    assert output =~ \"trying to set reserved field :async\"\n  end\n\n  test \"does not raise on reserved tag in setup_all (lower priority)\" do\n    defmodule ReservedSetupAllTag do\n      use ExUnit.Case\n\n      setup_all do\n        {:ok, file: :foo}\n      end\n\n      test \"sample\", do: :ok\n    end\n\n    capture_io(fn ->\n      assert ExUnit.run() == %{failures: 0, skipped: 0, total: 1, excluded: 0}\n    end)\n  end\n\n  test \"seed is predictable and different for each test\" do\n    defmodule PredictableSeedTest do\n      use ExUnit.Case, async: true\n\n      test \"generated seed is always the same in the same module and test\" do\n        assert :rand.uniform(1_000_000) == 253_740\n      end\n\n      test \"generated seed is different for other test\" do\n        assert :rand.uniform(1_000_000) == 462_665\n      end\n    end\n\n    defmodule DifferentModuleWithDifferentSeedTest do\n      use ExUnit.Case, async: true\n\n      test \"generated seed is always the same in the same module and test\" do\n        assert :rand.uniform(1_000_000) == 563_517\n      end\n    end\n\n    configure_and_reload_on_exit(seed: 1)\n\n    assert capture_io(fn ->\n             assert ExUnit.run() == %{failures: 0, skipped: 0, total: 3, excluded: 0}\n           end) =~ \"Result: 3 passed\"\n  end\n\n  # Skipped and excluded tests should be included in the stats\n  # as well as printed to stdout. On the other hand, invalid tests\n  # should be marked as failures in the stats, but still be printed\n  # as \"invalid\" to stdout.\n  #\n  # If setup_all fails, the skipped and excluded tests should not be\n  # counted as invalid or failures.\n  test \"setup_all fails and module has skipped and excluded tests\" do\n    defmodule SetupAllFailsModuleHasSkippedExcludedTest do\n      use ExUnit.Case\n\n      setup_all do\n        raise \"oops\"\n      end\n\n      @tag :skip\n      test \"skipped #{__ENV__.line}\", do: assert(false)\n\n      test \"pass #{__ENV__.line}\", do: assert(true)\n      test \"pass #{__ENV__.line}\", do: assert(true)\n      test \"fail #{__ENV__.line}\", do: assert(false)\n      test \"fail #{__ENV__.line}\", do: assert(false)\n\n      @tag :exclude\n      test \"excluded #{__ENV__.line}\", do: assert(false)\n    end\n\n    configure_and_reload_on_exit([])\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{total: 6, failures: 4, excluded: 1, skipped: 1}\n      end)\n\n    refute output =~ max_failures_reached_msg()\n    assert output =~ \"Result: 0 tests\"\n  end\n\n  test \"parameterized tests\" do\n    Process.register(self(), :parameterized_tests)\n\n    defmodule ParameterizedTests do\n      use ExUnit.Case, async: true, parameterize: [%{value: true}, %{value: false}]\n\n      @tag :tmp_dir\n      test \"hello world\", %{value: value, tmp_dir: tmp_dir} do\n        send(:parameterized_tests, {:tmp_dir, tmp_dir})\n        assert value\n      end\n    end\n\n    configure_and_reload_on_exit(trace: true)\n\n    output = capture_io(fn -> ExUnit.run() end)\n\n    assert output =~ ~r\"\"\"\n           ExUnitTest.ParameterizedTests \\[.*test/ex_unit_test.exs\\]\n           Parameters: %\\{value: false\\}\n           \"\"\"\n\n    assert output =~ \"\"\"\n             1) test hello world (ExUnitTest.ParameterizedTests)\n                Parameters: %{value: false}\n           \"\"\"\n\n    # Check that the temporary paths are different\n    assert_receive {:tmp_dir, tmp_dir1}\n    assert_receive {:tmp_dir, tmp_dir2} when tmp_dir1 != tmp_dir2\n  end\n\n  test \"empty parameterized tests\" do\n    defmodule EmptyParameterizedTests do\n      use ExUnit.Case, async: true, parameterize: []\n\n      test \"hello world\" do\n        assert false\n      end\n    end\n\n    configure_and_reload_on_exit(trace: true)\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Result: 0 tests\"\n\n    defmodule EmptyGroupedParameterizedTests do\n      use ExUnit.Case, async: true, parameterize: [], group: :example\n\n      test \"hello world\" do\n        assert false\n      end\n    end\n\n    configure_and_reload_on_exit(trace: true)\n    assert capture_io(fn -> ExUnit.run() end) =~ \"Result: 0 tests\"\n  end\n\n  describe \"after_suite/1\" do\n    test \"executes all callbacks set in reverse order\" do\n      Process.register(self(), :after_suite_test_process)\n\n      defmodule MultipleAfterSuiteTest do\n        use ExUnit.Case\n\n        test \"true\" do\n          send(:after_suite_test_process, :in_first_test)\n        end\n      end\n\n      ExUnit.after_suite(fn _ -> send(:after_suite_test_process, :first_after_suite) end)\n      ExUnit.after_suite(fn result -> send(:after_suite_test_process, result) end)\n      ExUnit.after_suite(fn _ -> send(:after_suite_test_process, :third_after_suite) end)\n\n      capture_io(fn -> ExUnit.run() end)\n\n      # Because `after_suite` is global, we need to be sure to clear out the\n      # test callbacks here, otherwise it will attempt to execute them after\n      # every subsequent call to `ExUnit.run()` in any tests run after these.\n      Application.put_env(:ex_unit, :after_suite, [])\n\n      assert next_message_in_mailbox() == :in_first_test\n      assert next_message_in_mailbox() == :third_after_suite\n      assert next_message_in_mailbox() == %{excluded: 0, failures: 0, skipped: 0, total: 1}\n      assert next_message_in_mailbox() == :first_after_suite\n      # Check to make sure the mailbox is empty after these four messages\n      refute_received _\n    end\n  end\n\n  describe \":max_failures\" do\n    test \"default value to :infinity\" do\n      configure_and_reload_on_exit([])\n      ExUnit.start(autorun: false)\n      config = ExUnit.configuration()\n      assert config[:max_failures] == :infinity\n    end\n\n    test \"sets value of :max_failures\" do\n      configure_and_reload_on_exit([])\n      ExUnit.start(max_failures: 5, autorun: false)\n      config = ExUnit.configuration()\n      assert config[:max_failures] == 5\n    end\n\n    test \":max_failures are reached\" do\n      defmodule TestMaxFailuresReached do\n        use ExUnit.Case\n\n        @tag :skip\n        test \"skipped #{__ENV__.line}\", do: assert(false)\n\n        test __ENV__.line, do: assert(true)\n        test __ENV__.line, do: assert(true)\n        test __ENV__.line, do: assert(false)\n        test __ENV__.line, do: assert(false)\n        test __ENV__.line, do: assert(true)\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(false)\n      end\n\n      configure_and_reload_on_exit(max_failures: 2)\n\n      output =\n        capture_io(fn ->\n          assert ExUnit.run() == %{total: 6, failures: 2, skipped: 1, excluded: 1}\n        end)\n\n      assert output =~ max_failures_reached_msg()\n      assert output =~ \"Failed: 2 tests\"\n    end\n\n    test \":max_failures is not reached\" do\n      defmodule TestMaxFailuresNotReached do\n        use ExUnit.Case\n\n        @tag :skip\n        test \"skipped #{__ENV__.line}\", do: assert(true)\n\n        test \"pass #{__ENV__.line}\", do: assert(true)\n        test \"fail #{__ENV__.line}\", do: assert(false)\n        test \"pass #{__ENV__.line}\", do: assert(true)\n        test \"fail #{__ENV__.line}\", do: assert(false)\n        test \"pass #{__ENV__.line}\", do: assert(true)\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(true)\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(false)\n      end\n\n      configure_and_reload_on_exit(max_failures: 3)\n\n      output =\n        capture_io(fn ->\n          assert ExUnit.run() == %{total: 8, excluded: 2, failures: 2, skipped: 1}\n        end)\n\n      refute output =~ max_failures_reached_msg()\n      assert output =~ \"Failed: 2 tests\"\n    end\n\n    test \":max_failures has been reached\" do\n      defmodule TestMaxFailuresAlreadyReached do\n        use ExUnit.Case\n\n        @tag :skip\n        test \"skipped #{__ENV__.line}\", do: assert(true)\n\n        @tag :skip\n        test \"skipped #{__ENV__.line}\", do: assert(false)\n\n        test \"pass #{__ENV__.line}\", do: assert(true)\n        test \"fail #{__ENV__.line}\", do: assert(false)\n        test \"fail #{__ENV__.line}\", do: assert(false)\n        test \"fail #{__ENV__.line}\", do: assert(false)\n        test \"pass #{__ENV__.line}\", do: assert(true)\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(true)\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(true)\n      end\n\n      configure_and_reload_on_exit(max_failures: 2)\n\n      output =\n        capture_io(fn ->\n          assert ExUnit.run() == %{total: 7, failures: 2, excluded: 2, skipped: 2}\n        end)\n\n      assert output =~ max_failures_reached_msg()\n      assert output =~ \"Failed: 2 tests\"\n    end\n\n    # Excluded and skipped tests are detected before setup_all\n    # callback is executed, therefore they are always included\n    # as part of the total number of tests in the stats.\n    test \":max_failures on setup_all errors\" do\n      defmodule TestMaxFailuresSetupAll do\n        use ExUnit.Case\n\n        setup_all do\n          raise \"oops\"\n        end\n\n        @tag :skip\n        test \"skipped #{__ENV__.line}\", do: assert(true)\n\n        test \"pass #{__ENV__.line}\", do: assert(true)\n        test \"pass #{__ENV__.line}\", do: assert(true)\n        test \"fail #{__ENV__.line}\", do: assert(false)\n        test \"fail #{__ENV__.line}\", do: assert(false)\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(false)\n      end\n\n      configure_and_reload_on_exit(max_failures: 2)\n\n      output =\n        capture_io(fn ->\n          assert ExUnit.run() == %{total: 4, failures: 2, excluded: 1, skipped: 1}\n        end)\n\n      assert output =~ max_failures_reached_msg()\n      assert output =~ \"Result: 0 tests\"\n    end\n\n    test \":max_failures flushes all async/sync cases\" do\n      defmodule TestMaxFailuresAsync1 do\n        use ExUnit.Case, async: true\n        test \"error\", do: assert(false)\n      end\n\n      defmodule TestMaxFailuresAsync2 do\n        use ExUnit.Case, async: true\n        test \"error\", do: assert(false)\n      end\n\n      defmodule TestMaxFailuresSync do\n        use ExUnit.Case\n        test \"error\", do: assert(false)\n      end\n\n      configure_and_reload_on_exit(max_failures: 1)\n\n      output =\n        capture_io(fn ->\n          assert ExUnit.run() == %{total: 1, failures: 1, excluded: 0, skipped: 0}\n        end)\n\n      assert output =~ max_failures_reached_msg()\n      assert output =~ \"Failed: 1 test\"\n\n      capture_io(fn ->\n        assert ExUnit.run() == %{total: 0, failures: 0, excluded: 0, skipped: 0}\n      end)\n    end\n\n    test \"warns and errors when context is not a map\" do\n      assert capture_io(:stderr, fn ->\n               defmodule ContextTest do\n                 use ExUnit.Case, async: true\n\n                 test \"I made a typo\", conn: conn do\n                   assert true\n                 end\n               end\n             end) =~ \"test context is always a map. The pattern \\\"[conn: conn]\\\" will never match\"\n\n      configure_and_reload_on_exit([])\n\n      assert capture_io(fn ->\n               assert ExUnit.run() == %{failures: 1, skipped: 0, total: 1, excluded: 0}\n             end) =~ \"** (FunctionClauseError) no function clause matching\"\n    end\n  end\n\n  describe \":exit_status\" do\n    test \"defaults value to 2\" do\n      configure_and_reload_on_exit([])\n      ExUnit.start(autorun: false)\n      config = ExUnit.configuration()\n      assert config[:exit_status] == 2\n    end\n\n    test \"sets value of :exit_status\" do\n      configure_and_reload_on_exit([])\n      ExUnit.start(exit_status: 5, autorun: false)\n      config = ExUnit.configuration()\n      assert config[:exit_status] == 5\n    end\n  end\n\n  describe \":repeat_until_failure\" do\n    test \"defaults to 0\" do\n      configure_and_reload_on_exit([])\n      ExUnit.start(autorun: false)\n      config = ExUnit.configuration()\n      assert config[:repeat_until_failure] == 0\n    end\n\n    test \"sets value of :repeat_until_failure\" do\n      configure_and_reload_on_exit([])\n      ExUnit.start(repeat_until_failure: 5, autorun: false)\n      config = ExUnit.configuration()\n      assert config[:repeat_until_failure] == 5\n    end\n\n    test \"repeats tests up to the configured number of times\" do\n      defmodule TestRepeatUntilFailureReached do\n        use ExUnit.Case\n\n        @tag :skip\n        test \"skipped #{__ENV__.line}\", do: assert(false)\n\n        test __ENV__.line, do: assert(true)\n        test __ENV__.line, do: assert(true)\n        test __ENV__.line, do: assert(true)\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(false)\n      end\n\n      configure_and_reload_on_exit(repeat_until_failure: 5)\n\n      output =\n        capture_io(fn ->\n          assert ExUnit.run() == %{total: 5, failures: 0, skipped: 1, excluded: 1}\n        end)\n\n      runs = String.split(output, \"Running ExUnit\", trim: true)\n      # 6 runs in total, 5 repeats\n      assert length(runs) == 6\n    end\n\n    test \"repeats tests up to the configured number of times with groups\" do\n      defmodule TestGroupedRepeatUntilFailureReached do\n        use ExUnit.Case, async: true, group: :example\n        test __ENV__.line, do: assert(true)\n      end\n\n      configure_and_reload_on_exit(repeat_until_failure: 5)\n\n      output =\n        capture_io(fn ->\n          assert ExUnit.run() == %{total: 1, failures: 0, skipped: 0, excluded: 0}\n        end)\n\n      runs = String.split(output, \"Running ExUnit\", trim: true)\n      # 6 runs in total, 5 repeats\n      assert length(runs) == 6\n    end\n\n    test \"stops on failure\" do\n      {:ok, pid} = Agent.start_link(fn -> 0 end)\n      Process.register(pid, :ex_unit_repeat_until_failure_count)\n\n      defmodule TestRepeatUntilFailureFailure do\n        use ExUnit.Case\n\n        @tag :skip\n        test \"skipped #{__ENV__.line}\", do: assert(true)\n\n        test \"maybe pass #{__ENV__.line}\" do\n          count = Agent.get(:ex_unit_repeat_until_failure_count, & &1)\n\n          if count < 3 do\n            Agent.update(:ex_unit_repeat_until_failure_count, &(&1 + 1))\n            assert(true)\n          else\n            assert(false)\n          end\n        end\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(true)\n\n        @tag :exclude\n        test \"excluded #{__ENV__.line}\", do: assert(false)\n      end\n\n      configure_and_reload_on_exit(repeat_until_failure: 5)\n\n      output =\n        capture_io(fn ->\n          assert ExUnit.run() == %{total: 4, excluded: 2, failures: 1, skipped: 1}\n        end)\n\n      runs = String.split(output, \"Running ExUnit\", trim: true)\n      # four runs in total, the first two repeats work fine, the third repeat (4th run)\n      # fails, therefore we stop\n      assert length(runs) == 4\n      assert List.last(runs) =~ \"Expected truthy, got false\"\n    end\n  end\n\n  test \"prints warning when all tests are excluded\" do\n    defmodule OnlyExcludedTests do\n      use ExUnit.Case\n\n      @tag :exclude\n      test \"excluded test\", do: assert(false)\n\n      @tag :exclude\n      test \"one more excluded test\", do: assert(false)\n    end\n\n    configure_and_reload_on_exit([])\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{total: 2, failures: 0, excluded: 2, skipped: 0}\n      end)\n\n    assert output =~ \"All tests have been excluded.\\n\"\n    assert output =~ \"Result: 0 tests\"\n  end\n\n  test \"tests are run in compile order (FIFO)\" do\n    defmodule FirstTestFIFO do\n      use ExUnit.Case\n\n      test \"first test\" do\n        assert true\n      end\n    end\n\n    defmodule SecondTestFIFO do\n      use ExUnit.Case\n\n      test \"second test\" do\n        assert true\n      end\n    end\n\n    defmodule ThirdTestFIFO do\n      use ExUnit.Case\n\n      test \"third test\" do\n        assert true\n      end\n    end\n\n    configure_and_reload_on_exit(trace: true)\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{total: 3, failures: 0, excluded: 0, skipped: 0}\n      end)\n\n    [_, first, second, third | _] = String.split(output, \"\\n\\n\")\n\n    assert first =~ \"FirstTestFIFO\"\n    assert second =~ \"SecondTestFIFO\"\n    assert third =~ \"ThirdTestFIFO\"\n  end\n\n  test \"groups are run in compile order (FIFO)\" do\n    defmodule RedOneFIFO do\n      use ExUnit.Case, async: true, group: :red\n\n      test \"red one test\" do\n        Process.sleep(5)\n        assert true\n      end\n    end\n\n    defmodule BlueOneFIFO do\n      use ExUnit.Case, async: true, group: :blue\n\n      test \"blue one test\" do\n        Process.sleep(5)\n        assert true\n      end\n    end\n\n    defmodule RedTwoFIFO do\n      use ExUnit.Case, async: true, group: :red\n\n      test \"red two test\" do\n        assert true\n      end\n    end\n\n    defmodule BlueTwoFIFO do\n      use ExUnit.Case, async: true, group: :blue\n\n      test \"blue two test\" do\n        assert true\n      end\n    end\n\n    configure_and_reload_on_exit(trace: true, max_cases: 2)\n\n    output =\n      capture_io(fn ->\n        assert ExUnit.run() == %{total: 4, failures: 0, excluded: 0, skipped: 0}\n      end)\n\n    [_, first, second, third, fourth | _] = String.split(output, \"\\n\\n\")\n\n    assert first =~ \"RedOneFIFO\"\n    assert second =~ \"RedTwoFIFO\"\n    assert third =~ \"BlueOneFIFO\"\n    assert fourth =~ \"BlueTwoFIFO\"\n  end\n\n  test \"filters async tests\" do\n    defmodule FirstTestAsyncTrue do\n      use ExUnit.Case, async: true\n\n      test \"first test\" do\n        assert true\n      end\n    end\n\n    defmodule SecondTestAsyncTrue do\n      use ExUnit.Case, async: true\n\n      test \"second test\" do\n        assert true\n      end\n    end\n\n    defmodule FirstTestAsyncFalse do\n      use ExUnit.Case, async: false\n\n      test \"first test\" do\n        assert true\n      end\n    end\n\n    assert {%{failures: 0, skipped: 0, total: 3, excluded: 1}, _} =\n             run_with_filter([include: [async: true], exclude: [:test]], [])\n\n    assert {%{failures: 0, skipped: 0, total: 3, excluded: 2}, _} =\n             run_with_filter(\n               [include: [async: false], exclude: [:test]],\n               [FirstTestAsyncTrue, SecondTestAsyncTrue, FirstTestAsyncFalse]\n             )\n  end\n\n  ##  Helpers\n\n  defp run_with_filter(filters, cases) do\n    Enum.each(cases, fn mod ->\n      ExUnit.Server.add_module(mod, mod.__ex_unit__(:config))\n    end)\n\n    ExUnit.Server.modules_loaded(false)\n\n    opts =\n      ExUnit.configuration()\n      |> Keyword.merge(filters)\n      |> Keyword.merge(colors: [enabled: false])\n\n    with_io(fn -> ExUnit.Runner.run(opts, nil) |> elem(0) end)\n  end\n\n  defp next_message_in_mailbox() do\n    receive do\n      msg -> msg\n    after\n      0 -> nil\n    end\n  end\n\n  test \"sets process label for each test\" do\n    label = :proc_lib.get_label(self())\n    assert label == {ExUnitTest, :\"test sets process label for each test\"}\n  end\n\n  defp configure_and_reload_on_exit(opts) do\n    old_opts = ExUnit.configuration()\n\n    ExUnit.configure(\n      Keyword.merge(\n        [autorun: false, seed: 0, colors: [enabled: false], exclude: [:exclude]],\n        opts\n      )\n    )\n\n    on_exit(fn -> ExUnit.configure(old_opts) end)\n  end\n\n  defp max_failures_reached_msg() do\n    \"--max-failures reached, aborting test suite\"\n  end\nend\n"
  },
  {
    "path": "lib/ex_unit/test/fixtures/failing.md",
    "content": "# Example\n\n    iex> 1 + 2\n    4\n"
  },
  {
    "path": "lib/ex_unit/test/fixtures/passing.md",
    "content": "# Example\n\n    iex> 1 + 2\n    3\n\n    iex> 2 + 3\n    5\n"
  },
  {
    "path": "lib/ex_unit/test/test_helper.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n{line_exclude, line_include} =\n  if line = System.get_env(\"LINE\"), do: {[:test], [line: line]}, else: {[], []}\n\nCode.require_file(\"../../elixir/scripts/cover_record.exs\", __DIR__)\nCoverageRecorder.maybe_record(\"ex_unit\")\n\nmaybe_seed_opt = if seed = System.get_env(\"SEED\"), do: [seed: String.to_integer(seed)], else: []\n\nex_unit_opts =\n  [\n    trace: !!System.get_env(\"TRACE\"),\n    include: line_include,\n    exclude: line_exclude,\n    assert_receive_timeout: String.to_integer(System.get_env(\"ELIXIR_ASSERT_TIMEOUT\", \"300\"))\n  ] ++ maybe_seed_opt\n\nExUnit.start(ex_unit_opts)\n"
  },
  {
    "path": "lib/iex/lib/iex/app.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.App do\n  @moduledoc false\n\n  use Application\n\n  def start(_type, _args) do\n    with :default <- Application.get_env(:stdlib, :shell_multiline_prompt, :default) do\n      Application.put_env(:stdlib, :shell_multiline_prompt, {IEx.Config, :prompt})\n    end\n\n    children = [IEx.Config, IEx.Broker, IEx.Pry]\n    Supervisor.start_link(children, strategy: :one_for_one, name: IEx.Supervisor)\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/autocomplete.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.Autocomplete do\n  @moduledoc false\n\n  @bitstring_modifiers [\n    %{kind: :variable, name: \"big\"},\n    %{kind: :variable, name: \"binary\"},\n    %{kind: :variable, name: \"bitstring\"},\n    %{kind: :variable, name: \"integer\"},\n    %{kind: :variable, name: \"float\"},\n    %{kind: :variable, name: \"little\"},\n    %{kind: :variable, name: \"native\"},\n    %{kind: :variable, name: \"signed\"},\n    %{kind: :export, name: \"size\", arity: 1},\n    %{kind: :export, name: \"unit\", arity: 1},\n    %{kind: :variable, name: \"unsigned\"},\n    %{kind: :variable, name: \"utf8\"},\n    %{kind: :variable, name: \"utf16\"},\n    %{kind: :variable, name: \"utf32\"}\n  ]\n\n  block_keywords =\n    for block_keyword <- ~w(do end after catch else rescue) do\n      %{kind: :block_keyword, name: block_keyword}\n    end\n\n  binary_operators =\n    for operator <-\n          [\"**\", \"*\", \"/\", \"+\", \"-\", \"++\", \"--\", \"+++\", \"---\", \"..\", \"<>\"] ++\n            [\"in\", \"not in\", \"|>\", \"<<<\", \">>>\", \"<<~\", \"~>>\", \"<~\", \"~>\", \"<~>\"] ++\n            [\"<\", \">\", \"<=\", \">=\", \"==\", \"!=\", \"=~\", \"===\", \"!==\"] ++\n            [\"&&\", \"&&&\", \"and\", \"||\", \"|||\", \"or\"] ++\n            [\"=\", \"=>\", \"|\", \"::\", \"when\", \"<-\", \"\\\\\\\\\"] do\n      %{kind: :export, name: operator, arity: 2}\n    end\n\n  @block_keyword_or_binary_operator block_keywords ++ Enum.sort(binary_operators)\n\n  @alias_only_atoms ~w(alias import require)a\n  @alias_only_charlists ~w(alias import require)c\n\n  @doc \"\"\"\n  Provides one helper function that is injected into connecting\n  remote nodes to properly handle autocompletion.\n  \"\"\"\n  def remsh(node) do\n    fn e ->\n      try do\n        :erpc.call(node, IEx.Autocomplete, :expand, [e, :shell.whereis()])\n      catch\n        _, _ -> {:no, ~c\"\", []}\n      end\n    end\n  end\n\n  @doc \"\"\"\n  The expansion logic.\n\n  Some of the expansion has to use the current shell\n  environment, which is found via the broker.\n  \"\"\"\n  def expand(code, shell \\\\ :shell.whereis()) do\n    case path_fragment(code) do\n      [] -> expand_code(code, shell)\n      path -> expand_path(path)\n    end\n  end\n\n  defp expand_code(code, shell) do\n    code = Enum.reverse(code)\n    helper = get_helper(code)\n\n    case Code.Fragment.cursor_context(code) do\n      {:alias, alias} ->\n        expand_aliases(List.to_string(alias), shell)\n\n      {:unquoted_atom, unquoted_atom} ->\n        expand_erlang_modules(List.to_string(unquoted_atom))\n\n      {:block_keyword_or_binary_operator, hint} ->\n        filter_and_format_expansion(@block_keyword_or_binary_operator, List.to_string(hint))\n\n      expansion when helper == ?b ->\n        expand_typespecs(expansion, shell, &get_module_callbacks/1)\n\n      expansion when helper == ?t ->\n        expand_typespecs(expansion, shell, &get_module_types/1)\n\n      {:dot, path, hint} ->\n        if alias = alias_only(path, hint, code, shell) do\n          expand_aliases(List.to_string(alias), shell)\n        else\n          expand_dot(path, List.to_string(hint), false, shell)\n        end\n\n      {:dot_arity, path, hint} ->\n        expand_dot(path, List.to_string(hint), true, shell)\n\n      {:dot_call, path, hint} ->\n        expand_dot_call(path, List.to_atom(hint), shell)\n\n      :expr ->\n        expand_container_context(code, :expr, \"\", shell) || expand_local_or_var(\"\", shell)\n\n      {:local_or_var, local_or_var} ->\n        hint = List.to_string(local_or_var)\n        expand_container_context(code, :expr, hint, shell) || expand_local_or_var(hint, shell)\n\n      {:local_arity, local} ->\n        expand_local(List.to_string(local), true, shell)\n\n      {:local_call, local} when local in @alias_only_charlists ->\n        expand_aliases(\"\", shell)\n\n      {:local_call, local} ->\n        expand_local_call(List.to_atom(local), shell)\n\n      {:operator, operator} when operator in ~w(:: -)c ->\n        expand_container_context(code, :operator, \"\", shell) ||\n          expand_local(List.to_string(operator), false, shell)\n\n      {:operator, operator} ->\n        expand_local(List.to_string(operator), false, shell)\n\n      {:operator_arity, operator} ->\n        expand_local(List.to_string(operator), true, shell)\n\n      {:operator_call, operator} when operator in ~w(|)c ->\n        expand_container_context(code, :expr, \"\", shell) || expand_local_or_var(\"\", shell)\n\n      {:operator_call, _operator} ->\n        expand_local_or_var(\"\", shell)\n\n      {:sigil, []} ->\n        expand_sigil(shell)\n\n      {:sigil, [_]} ->\n        {:yes, [], ~w|\" \"\"\" ' ''' \\( / < [ { \\||c}\n\n      {:struct, struct} when is_list(struct) ->\n        expand_structs(List.to_string(struct), shell)\n\n      {:struct, {:dot, {:alias, struct}, ~c\"\"}} when is_list(struct) ->\n        expand_structs(List.to_string(struct ++ ~c\".\"), shell)\n\n      # {:module_attribute, charlist}\n      # :none\n      _ ->\n        no()\n    end\n  end\n\n  defp get_helper(expr) do\n    with [helper | rest] when helper in ~c\"bt\" <- expr,\n         [space_or_paren, char | _] <- squeeze_spaces(rest),\n         true <-\n           space_or_paren in ~c\" (\" and\n             (char in ?A..?Z or char in ?a..?z or char in ?0..?9 or char in ~c\"_:\") do\n      helper\n    else\n      _ -> nil\n    end\n  end\n\n  defp squeeze_spaces(~c\"  \" ++ rest), do: squeeze_spaces([?\\s | rest])\n  defp squeeze_spaces(rest), do: rest\n\n  @doc false\n  def exports(mod) do\n    if ensure_loaded?(mod) and function_exported?(mod, :__info__, 1) do\n      mod.__info__(:macros) ++ (mod.__info__(:functions) -- [__info__: 1])\n    else\n      mod.module_info(:exports) -- [module_info: 0, module_info: 1]\n    end\n  end\n\n  ## Typespecs\n\n  defp expand_typespecs({:dot, path, hint}, shell, fun) do\n    hint = List.to_string(hint)\n\n    case expand_dot_path(path, shell) do\n      {:ok, mod} when is_atom(mod) ->\n        mod\n        |> fun.()\n        |> match_exports(hint, false)\n        |> format_expansion(hint)\n\n      _ ->\n        no()\n    end\n  end\n\n  defp expand_typespecs(_, _, _), do: no()\n\n  ## Expand call\n\n  defp expand_local_call(fun, shell) do\n    imports_from_env(shell)\n    |> Enum.filter(fn {_, funs} -> List.keymember?(funs, fun, 0) end)\n    |> Enum.flat_map(fn {module, _} -> get_signatures(fun, module) end)\n    |> expand_signatures(shell)\n  end\n\n  defp expand_dot_call(path, fun, shell) do\n    case expand_dot_path(path, shell) do\n      {:ok, mod} when is_atom(mod) -> get_signatures(fun, mod) |> expand_signatures(shell)\n      _ -> no()\n    end\n  end\n\n  defp get_signatures(name, module) when is_atom(module) do\n    with docs when is_list(docs) <- get_docs(module, [:function, :macro], name) do\n      Enum.map(docs, fn {_, _, signatures, _, _} -> Enum.join(signatures, \" \") end)\n    else\n      _ -> []\n    end\n  end\n\n  defp expand_signatures([_ | _] = signatures, _shell) do\n    yes(~c\"\", signatures |> Enum.map(&String.to_charlist/1) |> Enum.sort_by(&length/1))\n  end\n\n  defp expand_signatures([], shell), do: expand_local_or_var(\"\", shell)\n\n  ## Expand dot\n\n  defp expand_dot(path, hint, exact?, shell) do\n    case expand_dot_path(path, shell) do\n      {:ok, mod} when is_atom(mod) and hint == \"\" -> expand_dot_aliases(mod)\n      {:ok, mod} when is_atom(mod) -> expand_require(mod, hint, exact?)\n      {:ok, map} when is_map(map) -> expand_map_field_access(map, hint)\n      _ -> no()\n    end\n  end\n\n  defp expand_dot_path({:unquoted_atom, var}, _shell) do\n    {:ok, List.to_atom(var)}\n  end\n\n  defp expand_dot_path(path, shell) do\n    case recur_expand_dot_path(path, shell) do\n      {:ok, [_ | _] = path} -> value_from_binding(Enum.reverse(path), shell)\n      other -> other\n    end\n  end\n\n  defp recur_expand_dot_path({:var, var}, _shell) do\n    {:ok, [List.to_atom(var)]}\n  end\n\n  defp recur_expand_dot_path({:alias, var}, shell) do\n    {:ok, var |> List.to_string() |> String.split(\".\") |> value_from_alias(shell)}\n  end\n\n  defp recur_expand_dot_path({:dot, parent, call}, shell) do\n    case recur_expand_dot_path(parent, shell) do\n      {:ok, [_ | _] = path} -> {:ok, [List.to_atom(call) | path]}\n      _ -> :error\n    end\n  end\n\n  defp recur_expand_dot_path(_, _shell) do\n    :error\n  end\n\n  defp expand_map_field_access(map, hint) do\n    case match_map_fields(map, hint) do\n      [%{kind: :map_key, name: ^hint, value_is_map: false}] -> no()\n      map_fields when is_list(map_fields) -> format_expansion(map_fields, hint)\n    end\n  end\n\n  defp expand_dot_aliases(mod) do\n    all = match_elixir_modules(mod, \"\") ++ get_and_match_module_defs(mod, \"\", false)\n    format_expansion(all, \"\")\n  end\n\n  defp expand_require(mod, hint, exact?) do\n    mod\n    |> get_and_match_module_defs(hint, exact?)\n    |> format_expansion(hint)\n  end\n\n  ## Expand local or var\n\n  defp expand_local_or_var(hint, shell) do\n    format_expansion(match_var(hint, shell) ++ match_local(hint, false, shell), hint)\n  end\n\n  defp expand_local(hint, exact?, shell) do\n    format_expansion(match_local(hint, exact?, shell), hint)\n  end\n\n  defp expand_sigil(shell) do\n    sigils =\n      match_local(\"sigil_\", false, shell)\n      |> Enum.map(fn %{name: \"sigil_\" <> rest} -> %{kind: :sigil, name: rest} end)\n\n    format_expansion(match_local(\"~\", false, shell) ++ sigils, \"~\")\n  end\n\n  defp match_local(hint, exact?, shell) do\n    imports = imports_from_env(shell) |> Enum.flat_map(&elem(&1, 1))\n    module_funs = exports(Kernel.SpecialForms)\n    match_exports(imports ++ module_funs, hint, exact?)\n  end\n\n  defp match_var(hint, shell) do\n    variables_from_binding(hint, shell)\n    |> Enum.sort()\n    |> Enum.map(&%{kind: :variable, name: &1})\n  end\n\n  ## Erlang modules\n\n  defp expand_erlang_modules(hint) do\n    format_expansion(match_erlang_modules(hint), hint)\n  end\n\n  defp match_erlang_modules(hint) do\n    for mod <- match_modules(hint, false), usable_as_unquoted_module?(mod) do\n      %{kind: :module, name: mod}\n    end\n  end\n\n  ## Structs\n\n  defp expand_structs(hint, shell) do\n    aliases =\n      for {alias, mod} <- aliases_from_env(shell),\n          [name] = Module.split(alias),\n          String.starts_with?(name, hint),\n          do: {mod, name}\n\n    modules =\n      for \"Elixir.\" <> name = full_name <- match_modules(\"Elixir.\" <> hint, true),\n          String.starts_with?(name, hint),\n          mod = String.to_atom(full_name),\n          do: {mod, name}\n\n    all = aliases ++ modules\n    Code.ensure_all_loaded(Enum.map(all, &elem(&1, 0)))\n\n    refs =\n      for {mod, name} <- all,\n          function_exported?(mod, :__struct__, 1) and not function_exported?(mod, :exception, 1),\n          do: %{kind: :struct, name: name}\n\n    format_expansion(refs, hint)\n  end\n\n  defp expand_container_context(code, context, hint, shell) do\n    case container_context(code, shell) do\n      {:map, map, pairs} when context == :expr ->\n        container_context_map_fields(pairs, map, hint)\n\n      {:struct, alias, pairs} when context == :expr ->\n        map = Map.from_struct(alias.__struct__())\n        container_context_map_fields(pairs, map, hint)\n\n      :bitstring_modifier ->\n        existing =\n          code\n          |> List.to_string()\n          |> String.split(\"::\")\n          |> List.last()\n          |> String.split(\"-\")\n\n        @bitstring_modifiers\n        |> Enum.filter(&(String.starts_with?(&1.name, hint) and &1.name not in existing))\n        |> format_expansion(hint)\n\n      _ ->\n        nil\n    end\n  end\n\n  defp container_context_map_fields(pairs, map, hint) do\n    pairs =\n      Enum.reduce(pairs, map, fn {key, _}, map ->\n        Map.delete(map, key)\n      end)\n\n    entries =\n      for key when key != :__struct__ <- Map.keys(pairs),\n          name = Atom.to_string(key),\n          if(hint == \"\",\n            do: not String.starts_with?(name, \"_\"),\n            else: String.starts_with?(name, hint)\n          ),\n          do: %{kind: :keyword, name: name}\n\n    format_expansion(entries, hint)\n  end\n\n  defp container_context(code, shell) do\n    case Code.Fragment.container_cursor_to_quoted(code) do\n      {:ok, quoted} ->\n        case Macro.path(quoted, &match?({:__cursor__, _, []}, &1)) do\n          [cursor, {:%{}, _, pairs}, {:%, _, [{:__aliases__, _, aliases = [h | _]}, _map]} | _]\n          when is_atom(h) ->\n            container_context_struct(cursor, pairs, aliases, shell)\n\n          [\n            cursor,\n            pairs,\n            {:|, _, _},\n            {:%{}, _, _},\n            {:%, _, [{:__aliases__, _, aliases = [h | _]}, _map]} | _\n          ]\n          when is_atom(h) ->\n            container_context_struct(cursor, pairs, aliases, shell)\n\n          [cursor, pairs, {:|, _, [{variable, _, nil} | _]}, {:%{}, _, _} | _] ->\n            container_context_map(cursor, pairs, variable, shell)\n\n          [cursor, {special_form, _, [cursor]} | _] when special_form in @alias_only_atoms ->\n            :alias_only\n\n          [cursor | tail] ->\n            case remove_operators(tail, cursor) do\n              [{:\"::\", _, [_, _]}, {:<<>>, _, [_ | _]} | _] -> :bitstring_modifier\n              _ -> nil\n            end\n\n          _ ->\n            nil\n        end\n\n      {:error, _} ->\n        nil\n    end\n  end\n\n  defp remove_operators([{op, _, [_, previous]} = head | tail], previous) when op in [:-],\n    do: remove_operators(tail, head)\n\n  defp remove_operators(tail, _previous),\n    do: tail\n\n  defp container_context_struct(cursor, pairs, aliases, shell) do\n    with {pairs, [^cursor]} <- Enum.split(pairs, -1),\n         alias = value_from_alias(aliases, shell),\n         true <-\n           Keyword.keyword?(pairs) and ensure_loaded?(alias) and\n             function_exported?(alias, :__struct__, 1) do\n      {:struct, alias, pairs}\n    else\n      _ -> nil\n    end\n  end\n\n  defp container_context_map(cursor, pairs, variable, shell) do\n    with {pairs, [^cursor]} <- Enum.split(pairs, -1),\n         {:ok, map} when is_map(map) <- value_from_binding([variable], shell),\n         true <- Keyword.keyword?(pairs) do\n      {:map, map, pairs}\n    else\n      _ -> nil\n    end\n  end\n\n  ## Aliases and modules\n\n  defp alias_only(path, hint, code, shell) do\n    with {:alias, alias} <- path,\n         [] <- hint,\n         :alias_only <- container_context(code, shell) do\n      alias ++ [?.]\n    else\n      _ -> nil\n    end\n  end\n\n  defp expand_aliases(all, shell) do\n    case String.split(all, \".\") do\n      [hint] ->\n        all = match_aliases(hint, shell) ++ match_elixir_modules(Elixir, hint)\n        format_expansion(all, hint)\n\n      parts ->\n        hint = List.last(parts)\n        list = Enum.take(parts, length(parts) - 1)\n\n        value_from_alias(list, shell)\n        |> match_elixir_modules(hint)\n        |> format_expansion(hint)\n    end\n  end\n\n  defp value_from_alias([name | rest], shell) do\n    case Keyword.fetch(aliases_from_env(shell), Module.concat(Elixir, name)) do\n      {:ok, name} when rest == [] -> name\n      {:ok, name} -> Module.concat([name | rest])\n      :error -> Module.concat([name | rest])\n    end\n  end\n\n  defp match_aliases(hint, shell) do\n    for {alias, module} <- aliases_from_env(shell),\n        [name] = Module.split(alias),\n        String.starts_with?(name, hint) do\n      %{kind: :module, name: name, module: module}\n    end\n  end\n\n  defp match_elixir_modules(module, hint) do\n    prefix = Atom.to_string(module) <> \".\"\n    prefix_size = byte_size(prefix)\n    base = prefix <> hint\n\n    for mod <- match_modules(base, module == Elixir),\n        name = elixir_submodule_name(mod, prefix_size),\n        valid_alias_piece?(\".\" <> name),\n        uniq: true,\n        do: %{kind: :module, name: name}\n  end\n\n  defp elixir_submodule_name(mod, prefix_size) do\n    # All modules are checked to start with hint, which is larger\n    # than prefix size, so the operation below is safe.\n    rest = binary_part(mod, prefix_size, byte_size(mod) - prefix_size)\n\n    case :binary.match(rest, \".\") do\n      {pos, _} -> binary_part(rest, 0, pos)\n      :nomatch -> rest\n    end\n  end\n\n  defp valid_alias_piece?(<<?., char, rest::binary>>) when char in ?A..?Z,\n    do: valid_alias_rest?(rest)\n\n  defp valid_alias_piece?(_), do: false\n\n  defp valid_alias_rest?(<<char, rest::binary>>)\n       when char in ?A..?Z\n       when char in ?a..?z\n       when char in ?0..?9\n       when char == ?_,\n       do: valid_alias_rest?(rest)\n\n  defp valid_alias_rest?(<<>>), do: true\n  defp valid_alias_rest?(rest), do: valid_alias_piece?(rest)\n\n  ## Formatting\n\n  defp filter_and_format_expansion(results, hint) do\n    results\n    |> Enum.filter(&String.starts_with?(&1.name, hint))\n    |> format_expansion(hint)\n  end\n\n  defp format_expansion([], _) do\n    no()\n  end\n\n  defp format_expansion([uniq], hint) do\n    case to_hint(uniq, hint) do\n      ~c\"\" -> yes(~c\"\", [to_entry(uniq)])\n      hint -> yes(hint, [])\n    end\n  end\n\n  defp format_expansion([first | _] = entries, hint) do\n    binary = Enum.map(entries, & &1.name)\n    length = byte_size(hint)\n    prefix = :binary.longest_common_prefix(binary)\n\n    if prefix in [0, length] do\n      case Enum.group_by(entries, &Map.get(&1, :group, \"Exports\")) do\n        groups when map_size(groups) == 1 ->\n          yes(~c\"\", Enum.map(entries, &to_entry/1))\n\n        groups ->\n          sections =\n            groups\n            |> Enum.map(fn {group, entries} ->\n              %{\n                title: to_charlist(group),\n                options: [{:highlight_all}],\n                elems: Enum.map(entries, &to_entry/1)\n              }\n            end)\n            |> Enum.sort_by(&length(&1.elems))\n\n          yes(~c\"\", sections)\n      end\n    else\n      hint = binary_part(first.name, prefix, length - prefix)\n      yes(String.to_charlist(hint), [])\n    end\n  end\n\n  defp yes(hint, entries) when is_list(hint) and is_list(entries) do\n    {:yes, hint, entries}\n  end\n\n  defp no do\n    {:no, ~c\"\", []}\n  end\n\n  ## Helpers\n\n  defp usable_as_unquoted_module?(name) do\n    # Conversion to atom is not a problem because\n    # it is only called with existing modules names.\n    Macro.classify_atom(String.to_atom(name)) in [:identifier, :unquoted]\n  end\n\n  defp match_modules(hint, elixir_root?) do\n    modules =\n      for mod <- :erlang.loaded(),\n          str = Atom.to_string(mod),\n          String.starts_with?(str, hint),\n          do: str\n\n    modules =\n      if elixir_root? and String.starts_with?(\"Elixir.Elixir\", hint),\n        do: [\"Elixir.Elixir\" | modules],\n        else: modules\n\n    modules =\n      case :code.get_mode() do\n        :interactive -> modules ++ match_modules_from_applications(hint)\n        _otherwise -> modules\n      end\n\n    :lists.usort(modules)\n  end\n\n  defp match_modules_from_applications(hint) do\n    for [app] <- loaded_applications(),\n        {:ok, modules} = :application.get_key(app, :modules),\n        module <- modules,\n        str = Atom.to_string(module),\n        String.starts_with?(str, hint),\n        do: str\n  end\n\n  defp loaded_applications do\n    # If we invoke :application.loaded_applications/0,\n    # it can error if we don't call safe_fixtable before.\n    # Since in both cases we are reaching over the\n    # application controller internals, we choose to match\n    # for performance.\n    :ets.match(:ac_tab, {{:loaded, :\"$1\"}, :_})\n  end\n\n  defp match_map_fields(map, hint) do\n    for {key, value} when is_atom(key) <- Map.to_list(map),\n        key = Atom.to_string(key),\n        String.starts_with?(key, hint) do\n      %{kind: :map_key, name: key, value_is_map: is_map(value)}\n    end\n    |> Enum.sort_by(& &1.name)\n  end\n\n  defp match_exports(funs, hint, exact?) do\n    for {fun, arity} <- funs,\n        name = Atom.to_string(fun),\n        if(exact?, do: name == hint, else: String.starts_with?(name, hint)) do\n      %{\n        kind: :export,\n        name: name,\n        arity: arity\n      }\n    end\n    |> Enum.sort_by(&{&1.name, &1.arity})\n  end\n\n  defp get_and_match_module_defs(mod, hint, exact?) do\n    cond do\n      not ensure_loaded?(mod) ->\n        []\n\n      docs = get_docs(mod, [:function, :macro]) ->\n        exports(mod)\n        |> Enum.filter(fn {fun, _} ->\n          name = Atom.to_string(fun)\n          if exact?, do: name == hint, else: String.starts_with?(name, hint)\n        end)\n        |> Kernel.--(default_arg_functions_with_doc_false(docs))\n        |> Enum.sort()\n        |> Enum.flat_map(&decorate_definition(&1, docs))\n\n      true ->\n        mod\n        |> exports()\n        |> match_exports(hint, exact?)\n    end\n  end\n\n  defp get_module_types(mod) do\n    if ensure_loaded?(mod) do\n      case Code.Typespec.fetch_types(mod) do\n        {:ok, types} ->\n          for {kind, {name, _, args}} <- types,\n              kind in [:type, :opaque] do\n            {name, length(args)}\n          end\n\n        :error ->\n          []\n      end\n    else\n      []\n    end\n  end\n\n  defp get_module_callbacks(mod) do\n    if ensure_loaded?(mod) do\n      case Code.Typespec.fetch_callbacks(mod) do\n        {:ok, callbacks} ->\n          for {name_arity, _} <- callbacks do\n            {_kind, name, arity} = IEx.Introspection.translate_callback_name_arity(name_arity)\n\n            {name, arity}\n          end\n\n        :error ->\n          []\n      end\n    else\n      []\n    end\n  end\n\n  defp get_docs(mod, kinds, fun \\\\ nil) do\n    case Code.fetch_docs(mod) do\n      {:docs_v1, _, _, _, _, _, docs} ->\n        if is_nil(fun) do\n          for {{kind, _, _}, _, _, _, _} = doc <- docs, kind in kinds, do: doc\n        else\n          for {{kind, ^fun, _}, _, _, _, _} = doc <- docs, kind in kinds, do: doc\n        end\n\n      {:error, _} ->\n        nil\n    end\n  end\n\n  defp default_arg_functions_with_doc_false(docs) do\n    for {{_, fun_name, arity}, _, _, :hidden, %{defaults: count}} <- docs,\n        new_arity <- (arity - count)..arity,\n        do: {fun_name, new_arity}\n  end\n\n  defp decorate_definition({fun, arity}, docs) do\n    case Enum.find(docs, &match?({{_, ^fun, ^arity}, _, _, _, _}, &1)) do\n      nil ->\n        case Atom.to_string(fun) do\n          \"_\" <> _ -> []\n          name -> [%{kind: :export, name: name, arity: arity}]\n        end\n\n      {_, _, _, :hidden, _} ->\n        []\n\n      {_, _, _, _, metadata} ->\n        group = metadata[:group] || (metadata[:guard] && \"Guards\") || \"Exports\"\n        [%{kind: :export, name: Atom.to_string(fun), arity: arity, group: group}]\n    end\n  end\n\n  defp ensure_loaded?(Elixir), do: false\n  defp ensure_loaded?(mod), do: Code.ensure_loaded?(mod)\n\n  ## Ad-hoc conversions\n\n  defp to_entry(%{kind: :export, name: name, arity: arity}) do\n    ~c\"#{name}/#{arity}\"\n  end\n\n  defp to_entry(%{kind: :sigil, name: name}) do\n    ~c\"~#{name} (sigil_#{name})\"\n  end\n\n  defp to_entry(%{kind: :keyword, name: name}) do\n    ~c\"#{name}:\"\n  end\n\n  defp to_entry(%{kind: _, name: name}) do\n    String.to_charlist(name)\n  end\n\n  # Add extra character only if pressing tab when done\n  defp to_hint(%{kind: :module, name: hint}, hint) do\n    ~c\".\"\n  end\n\n  defp to_hint(%{kind: :map_key, name: hint, value_is_map: true}, hint) do\n    ~c\".\"\n  end\n\n  defp to_hint(%{kind: :file, name: hint}, hint) do\n    ~c\"\\\"\"\n  end\n\n  # Add extra character whenever possible\n  defp to_hint(%{kind: :dir, name: name}, hint) do\n    format_hint(name, hint) ++ ~c\"/\"\n  end\n\n  defp to_hint(%{kind: :struct, name: name}, hint) do\n    format_hint(name, hint) ++ ~c\"{\"\n  end\n\n  defp to_hint(%{kind: :keyword, name: name}, hint) do\n    format_hint(name, hint) ++ ~c\": \"\n  end\n\n  defp to_hint(%{kind: _, name: name}, hint) do\n    format_hint(name, hint)\n  end\n\n  defp format_hint(name, hint) do\n    hint_size = byte_size(hint)\n\n    name\n    |> binary_part(hint_size, byte_size(name) - hint_size)\n    |> String.to_charlist()\n  end\n\n  ## Evaluator interface\n\n  defp imports_from_env(shell) do\n    with {evaluator, server} <- IEx.Broker.evaluator(shell),\n         env_fields = IEx.Evaluator.fields_from_env(evaluator, server, [:functions, :macros]),\n         %{functions: funs, macros: macros} <- env_fields do\n      funs ++ macros\n    else\n      _ -> []\n    end\n  end\n\n  defp aliases_from_env(shell) do\n    with {evaluator, server} <- IEx.Broker.evaluator(shell),\n         %{aliases: aliases} <- IEx.Evaluator.fields_from_env(evaluator, server, [:aliases]) do\n      aliases\n    else\n      _ -> []\n    end\n  end\n\n  defp variables_from_binding(hint, shell) do\n    with {evaluator, server} <- IEx.Broker.evaluator(shell) do\n      IEx.Evaluator.variables_from_binding(evaluator, server, hint)\n    else\n      _ -> []\n    end\n  end\n\n  defp value_from_binding([var | path], shell) do\n    with {evaluator, server} <- IEx.Broker.evaluator(shell) do\n      IEx.Evaluator.value_from_binding(evaluator, server, var, path)\n    else\n      _ -> :error\n    end\n  end\n\n  ## Path helpers\n\n  defp path_fragment(expr), do: path_fragment(expr, [])\n  defp path_fragment([], _acc), do: []\n  defp path_fragment([?{, ?# | _rest], _acc), do: []\n  defp path_fragment([?\", ?\\\\ | t], acc), do: path_fragment(t, [?\\\\, ?\" | acc])\n\n  defp path_fragment([?/, ?:, x, ?\" | _], acc) when x in ?a..?z or x in ?A..?Z,\n    do: [x, ?:, ?/ | acc]\n\n  defp path_fragment([?/, ?., ?\" | _], acc), do: [?., ?/ | acc]\n  defp path_fragment([?/, ?\" | _], acc), do: [?/ | acc]\n  defp path_fragment([?\" | _], _acc), do: []\n  defp path_fragment([h | t], acc), do: path_fragment(t, [h | acc])\n\n  defp expand_path(path) do\n    path\n    |> List.to_string()\n    |> ls_prefix()\n    |> Enum.map(fn path ->\n      %{\n        kind: if(File.dir?(path), do: :dir, else: :file),\n        name: Path.basename(path)\n      }\n    end)\n    |> format_expansion(path_hint(path))\n  end\n\n  defp path_hint(path) do\n    if List.last(path) in [?/, ?\\\\] do\n      \"\"\n    else\n      Path.basename(path)\n    end\n  end\n\n  defp prefix_from_dir(\".\", <<c, _::binary>>) when c != ?., do: \"\"\n  defp prefix_from_dir(dir, _fragment), do: dir\n\n  defp ls_prefix(path) do\n    dir = Path.dirname(path)\n    prefix = prefix_from_dir(dir, path)\n\n    case File.ls(dir) do\n      {:ok, list} ->\n        list\n        |> Enum.map(&Path.join(prefix, &1))\n        |> Enum.filter(&String.starts_with?(&1, path))\n\n      _ ->\n        []\n    end\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/broker.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.Broker do\n  @moduledoc false\n  @name __MODULE__\n\n  @type take_ref :: {takeover_ref :: reference(), server_ref :: reference()}\n  @type shell :: pid | nil\n\n  use GenServer\n\n  ## Shell API\n\n  @doc \"\"\"\n  Finds the `:user_drv` backed shell on this node.\n\n  We don't use `:shell.whereis/0` because that uses the current group leader\n  and we want to find one regardless of the group leader.\n  \"\"\"\n  def shell() do\n    case :user_drv.whereis_group() do\n      :undefined ->\n        nil\n\n      pid ->\n        {:dictionary, dictionary} = Process.info(pid, :dictionary)\n        dictionary[:shell]\n    end\n  end\n\n  @doc \"\"\"\n  Finds the evaluator and server running on this node exclusively.\n  \"\"\"\n  @spec evaluator(shell()) :: {evaluator :: pid, server :: pid} | nil\n  def evaluator(pid \\\\ shell()) do\n    if pid do\n      {:dictionary, dictionary} = Process.info(pid, :dictionary)\n      {dictionary[:evaluator], pid}\n    end\n  end\n\n  ## Broker API\n\n  def start_link(_) do\n    GenServer.start_link(@name, :ok, name: @name)\n  end\n\n  @doc \"\"\"\n  Registers an IEx server in the broker.\n\n  All instances, except shell ones, are registered.\n  \"\"\"\n  @spec register(pid) :: :ok\n  def register(pid) do\n    GenServer.call(@name, {:register, pid})\n  end\n\n  @doc \"\"\"\n  Client responds to a takeover request.\n\n  The broker's PID is needed to support remote shells.\n  \"\"\"\n  @spec respond(pid, take_ref, integer(), boolean()) ::\n          :ok | {:error, :refused | :already_accepted}\n  def respond(broker_pid, take_ref, counter, true) do\n    GenServer.call(broker_pid, {:accept, take_ref, Process.group_leader(), counter})\n  end\n\n  def respond(broker_pid, take_ref, _counter, false) do\n    GenServer.call(broker_pid, {:refuse, take_ref})\n  end\n\n  @doc \"\"\"\n  Client requests a takeover.\n  \"\"\"\n  @spec take_over(binary, iodata, keyword) ::\n          {:ok, server :: pid, group_leader :: pid, counter :: integer}\n          | {:error, :no_iex | :refused | atom()}\n  def take_over(location, whereami, opts) do\n    case GenServer.whereis(@name) do\n      nil -> {:error, :no_iex}\n      _pid -> GenServer.call(@name, {:take_over, location, whereami, opts}, :infinity)\n    end\n  end\n\n  ## Callbacks\n\n  @impl true\n  def init(:ok) do\n    state = %{\n      servers: %{},\n      takeovers: %{}\n    }\n\n    {:ok, state}\n  end\n\n  @impl true\n  def handle_call({:take_over, location, whereami, opts}, {_, ref} = from, state) do\n    case servers(state) do\n      [] ->\n        {:reply, {:error, :no_iex}, state}\n\n      servers ->\n        server_refs =\n          for {server_ref, server_pid} <- servers do\n            send(server_pid, {:take_over, self(), {ref, server_ref}, location, whereami, opts})\n            server_ref\n          end\n\n        state = put_in(state.takeovers[ref], {from, server_refs})\n        {:noreply, state}\n    end\n  end\n\n  def handle_call({:register, pid}, _from, state) do\n    ref = Process.monitor(pid)\n    state = put_in(state.servers[ref], pid)\n    {:reply, :ok, state}\n  end\n\n  def handle_call({:accept, {ref, _server_ref}, group_leader, counter}, {server, _}, state) do\n    case pop_in(state.takeovers[ref]) do\n      {nil, state} ->\n        {:reply, {:error, :already_accepted}, state}\n\n      {{from, _}, state} ->\n        GenServer.reply(from, {:ok, server, group_leader, counter})\n        {:reply, :ok, state}\n    end\n  end\n\n  def handle_call({:refuse, {ref, server_ref}}, _from, state) do\n    if takeover = state.takeovers[ref] do\n      {:reply, {:error, :refused}, refuse(state, ref, takeover, server_ref)}\n    else\n      {:reply, {:error, :refused}, state}\n    end\n  end\n\n  @impl true\n  def handle_info({:DOWN, server_ref, _, _, _}, state) do\n    {_pid, state} = pop_in(state.servers[server_ref])\n\n    state =\n      Enum.reduce(state.takeovers, state, fn {ref, takeover}, state ->\n        refuse(state, ref, takeover, server_ref)\n      end)\n\n    {:noreply, state}\n  end\n\n  defp refuse(state, ref, {from, server_refs}, server_ref) do\n    case List.delete(server_refs, server_ref) do\n      [] ->\n        {_, state} = pop_in(state.takeovers[ref])\n        GenServer.reply(from, {:error, :refused})\n        state\n\n      server_refs ->\n        put_in(state.takeovers[ref], {from, server_refs})\n    end\n  end\n\n  defp servers(state) do\n    shells =\n      for node <- [node() | Node.list()],\n          pid = :erpc.call(node, IEx.Broker, :shell, []),\n          do: {Process.monitor(pid), pid}\n\n    shells ++ Enum.to_list(state.servers)\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/config.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.Config do\n  @moduledoc false\n  use Agent\n\n  @table __MODULE__\n  @agent __MODULE__\n  @keys [\n    :colors,\n    :inspect,\n    :history_size,\n    :default_prompt,\n    :alive_prompt,\n    :width,\n    :parser,\n    :dot_iex,\n    :auto_reload\n  ]\n\n  # Generate a continuation prompt based on IEx prompt.\n  # This is set as global configuration on app start.\n  def prompt(prompt) do\n    case Enum.split_while(prompt, &(&1 != ?()) do\n      # It is not the default Elixir shell, so we use the default prompt\n      {_, []} ->\n        List.duplicate(?\\s, max(0, :shell.prompt_width(prompt) - 3)) ++ ~c\".. \"\n\n      {left, right} ->\n        List.duplicate(?., :shell.prompt_width(left)) ++ right\n    end\n  end\n\n  # Read API\n\n  def configuration() do\n    Application.get_all_env(:iex) |> Keyword.take(@keys)\n  end\n\n  def width() do\n    columns = columns()\n    value = Application.get_env(:iex, :width) || 80\n    min(value, columns)\n  end\n\n  defp columns() do\n    case :io.columns() do\n      {:ok, width} -> width\n      {:error, _} -> 80\n    end\n  end\n\n  def started?() do\n    Process.whereis(@agent) != nil\n  end\n\n  def history_size() do\n    Application.fetch_env!(:iex, :history_size)\n  end\n\n  def default_prompt() do\n    Application.fetch_env!(:iex, :default_prompt)\n  end\n\n  def alive_prompt() do\n    Application.fetch_env!(:iex, :alive_prompt)\n  end\n\n  def parser() do\n    # Since the parser itself can be invoked from the remote node\n    # without IEx running, we cannot use fetch_env!\n    Application.get_env(:iex, :parser, {IEx.Evaluator, :parse, []})\n  end\n\n  def color(color) do\n    color(color, Application.get_env(:iex, :colors, []))\n  end\n\n  defp color(color, colors) do\n    if colors_enabled?(colors) do\n      case Keyword.fetch(colors, color) do\n        {:ok, value} -> value\n        :error -> default_color(color)\n      end\n    else\n      nil\n    end\n  end\n\n  defp colors_enabled?(colors) do\n    Keyword.get_lazy(colors, :enabled, &IO.ANSI.enabled?/0)\n  end\n\n  def dot_iex() do\n    Application.get_env(:iex, :dot_iex)\n  end\n\n  def auto_reload?() do\n    Application.fetch_env!(:iex, :auto_reload)\n  end\n\n  # Used by default on evaluation cycle\n  defp default_color(:eval_interrupt), do: [:yellow]\n  defp default_color(:eval_result), do: [:yellow]\n  defp default_color(:eval_error), do: [:red]\n  defp default_color(:eval_info), do: [:normal]\n  defp default_color(:stack_info), do: [:red]\n  defp default_color(:blame_diff), do: [:red]\n\n  # Used by ls\n  defp default_color(:ls_directory), do: [:blue]\n  defp default_color(:ls_device), do: [:green]\n\n  # Used by inspect\n  defp default_color(:syntax_colors) do\n    IO.ANSI.syntax_colors()\n  end\n\n  # Used by ansi docs\n  defp default_color(doc_color) do\n    IO.ANSI.Docs.default_options() |> Keyword.fetch!(doc_color)\n  end\n\n  def ansi_docs() do\n    colors = Application.get_env(:iex, :colors, [])\n    enabled = colors_enabled?(colors)\n    [width: width(), enabled: enabled] ++ colors\n  end\n\n  def inspect_opts() do\n    Application.get_env(:iex, :inspect, [])\n    |> Keyword.put_new_lazy(:width, &width/0)\n    |> update_syntax_colors()\n  end\n\n  defp update_syntax_colors(opts) do\n    colors = Application.get_env(:iex, :colors, [])\n\n    if syntax_colors = color(:syntax_colors, colors) do\n      reset = [:reset | List.wrap(color(:eval_result, colors))]\n      syntax_colors = [reset: reset] ++ syntax_colors\n      Keyword.update(opts, :syntax_colors, syntax_colors, &Keyword.merge(syntax_colors, &1))\n    else\n      opts\n    end\n  end\n\n  # Agent API\n\n  def start_link(_) do\n    Agent.start_link(__MODULE__, :handle_init, [], name: @agent)\n  end\n\n  def after_spawn(fun) do\n    Agent.update(@agent, __MODULE__, :handle_after_spawn, [fun])\n  end\n\n  def after_spawn() do\n    :ets.lookup_element(@table, :after_spawn, 2)\n  end\n\n  def configure(options) do\n    Agent.update(@agent, __MODULE__, :handle_configure, [options])\n  end\n\n  # Agent callbacks\n\n  def handle_init do\n    :ets.new(@table, [:named_table, :public])\n    true = :ets.insert_new(@table, after_spawn: [])\n    @table\n  end\n\n  def handle_after_spawn(tab, fun) do\n    :ets.update_element(tab, :after_spawn, {2, [fun | after_spawn()]})\n  end\n\n  def handle_configure(tab, options) do\n    Enum.each(options, &validate_option/1)\n\n    configuration()\n    |> Keyword.merge(options, &merge_option/3)\n    |> update_configuration()\n\n    tab\n  end\n\n  defp update_configuration(config) do\n    Enum.each(config, fn {key, value} when key in @keys ->\n      Application.put_env(:iex, key, value)\n    end)\n  end\n\n  defp merge_option(:colors, old, new) when is_list(new), do: Keyword.merge(old, new)\n  defp merge_option(:inspect, old, new) when is_list(new), do: Keyword.merge(old, new)\n  defp merge_option(_key, _old, new), do: new\n\n  defp validate_option({:colors, new}) when is_list(new), do: :ok\n  defp validate_option({:inspect, new}) when is_list(new), do: :ok\n  defp validate_option({:history_size, new}) when is_integer(new), do: :ok\n  defp validate_option({:default_prompt, new}) when is_binary(new), do: :ok\n  defp validate_option({:alive_prompt, new}) when is_binary(new), do: :ok\n  defp validate_option({:width, new}) when is_integer(new), do: :ok\n  defp validate_option({:parser, tuple}) when tuple_size(tuple) == 3, do: :ok\n  defp validate_option({:dot_iex, path}) when is_binary(path), do: :ok\n  defp validate_option({:auto_reload, enabled}) when is_boolean(enabled), do: :ok\n\n  defp validate_option(option) do\n    raise ArgumentError, \"invalid configuration #{inspect(option)}\"\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/evaluator.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.Evaluator do\n  @moduledoc false\n\n  alias IEx.Config\n\n  @doc \"\"\"\n  Eval loop for an IEx session. Its responsibilities include:\n\n    * loading of .iex files\n    * evaluating code\n    * trapping exceptions in the code being evaluated\n    * keeping expression history\n\n  \"\"\"\n  def init(command, server, leader, start, opts) do\n    ref = make_ref()\n    old_leader = Process.group_leader()\n    Process.group_leader(self(), leader)\n\n    old_server = Process.get(:iex_server)\n    Process.put(:iex_server, server)\n\n    old_evaluator = Process.get(:iex_evaluator)\n    Process.put(:iex_evaluator, ref)\n\n    if old_evaluator do\n      send(self(), {:done, old_evaluator, false})\n    end\n\n    state = loop_state(ref, server, IEx.History.init(start), opts)\n    command == :ack && :proc_lib.init_ack(self())\n\n    try do\n      loop(state)\n    after\n      Process.group_leader(self(), old_leader)\n\n      if old_server do\n        Process.put(:iex_server, old_server)\n      else\n        Process.delete(:iex_server)\n      end\n\n      if old_evaluator do\n        Process.put(:iex_evaluator, old_evaluator)\n      else\n        Process.delete(:iex_evaluator)\n      end\n\n      :ok\n    end\n  end\n\n  @break_trigger ~c\"#iex:break\\n\"\n\n  @op_tokens [:or_op, :and_op, :comp_op, :rel_op, :arrow_op, :in_op] ++\n               [:three_op, :concat_op, :mult_op]\n\n  @doc \"\"\"\n  Default parsing implementation with support for pipes and #iex:break.\n\n  If parsing fails, this might be a TokenMissingError which we treat in\n  a special way (to allow for continuation of an expression on the next\n  line in IEx).\n  \"\"\"\n  def parse(input, opts, parser_state)\n\n  def parse(input, opts, []), do: parse(input, opts, {[], :other})\n\n  def parse(input, opts, {buffer, last_op}) do\n    input = buffer ++ input\n    file = Keyword.get(opts, :file, \"nofile\")\n    line = Keyword.get(opts, :line, 1)\n    column = Keyword.get(opts, :column, 1)\n\n    if List.ends_with?(input, @break_trigger) do\n      triplet = {~c\"\", line, column, 0}\n      :elixir_errors.parse_error([line: line], file, \"incomplete expression\", \"\", triplet)\n    else\n      result =\n        with {:ok, tokens, warnings1} <- :elixir.string_to_tokens(input, line, column, file, opts),\n             {:ok, adjusted_tokens, adjusted_op} <-\n               adjust_operator(tokens, line, column, file, opts, last_op),\n             {:ok, forms, warnings2} <- :elixir.tokens_to_quoted(adjusted_tokens, file, opts) do\n          last_op =\n            case forms do\n              {:=, _, [_, _]} -> :match\n              _ -> :other\n            end\n\n          forms =\n            if adjusted_op != nil do\n              quote do\n                IEx.Evaluator.assert_no_error!()\n                unquote(forms)\n              end\n            else\n              forms\n            end\n\n          callback = fn ->\n            :elixir.emit_warnings(warnings1 ++ warnings2, file, opts)\n            forms\n          end\n\n          {:ok, callback, last_op}\n        end\n\n      case result do\n        {:ok, forms, last_op} ->\n          {:ok, forms, {[], last_op}}\n\n        {:error, {_, _, \"\"}} ->\n          {:incomplete, {input, last_op}}\n\n        {:error, {location, error, token}} ->\n          :elixir_errors.parse_error(\n            location,\n            file,\n            error,\n            token,\n            {input, line, column, 0}\n          )\n      end\n    end\n  end\n\n  defp adjust_operator([{op_type, _, token} | _] = _tokens, line, column, _file, _opts, :match)\n       when op_type in @op_tokens,\n       do:\n         {:error,\n          {[line: line, column: column],\n           \"pipe shorthand is not allowed immediately after a match expression in IEx. To make it work, surround the whole pipeline with parentheses \",\n           \"'#{token}'\"}}\n\n  defp adjust_operator([{op_type, _, _} | _] = tokens, line, column, file, opts, _last_op)\n       when op_type in @op_tokens do\n    {:ok, prefix, _warnings} = :elixir.string_to_tokens(~c\"v(-1)\", line, column, file, opts)\n    {:ok, prefix ++ tokens, op_type}\n  end\n\n  defp adjust_operator(tokens, _line, _column, _file, _opts, _last_op), do: {:ok, tokens, nil}\n\n  @doc \"\"\"\n  Raises an error if the last iex result was itself an error\n  \"\"\"\n  def assert_no_error!() do\n    if Process.get(:iex_error, false) do\n      message = \"skipping evaluation of expression because pipeline has failed\"\n      reraise RuntimeError.exception(message), []\n    end\n  end\n\n  @doc \"\"\"\n  Gets a value out of the binding, using the provided\n  variable name and map key path.\n  \"\"\"\n  @spec value_from_binding(pid, pid, atom, [atom]) :: {:ok, any} | :error\n  def value_from_binding(evaluator, server, var_name, map_key_path) do\n    ref = make_ref()\n    send(evaluator, {:value_from_binding, server, ref, self(), var_name, map_key_path})\n\n    receive do\n      {^ref, result} -> result\n    after\n      5000 -> :error\n    end\n  end\n\n  @doc \"\"\"\n  Gets a list of variables out of the binding that match the passed\n  variable prefix.\n  \"\"\"\n  @spec variables_from_binding(pid, pid, String.t()) :: [String.t()]\n  def variables_from_binding(evaluator, server, variable_prefix) do\n    ref = make_ref()\n    send(evaluator, {:variables_from_binding, server, ref, self(), variable_prefix})\n\n    receive do\n      {^ref, result} -> result\n    after\n      5000 -> []\n    end\n  end\n\n  @doc \"\"\"\n  Returns the named fields from the current session environment.\n  \"\"\"\n  @spec fields_from_env(pid, pid, [atom]) :: %{optional(atom) => term}\n  def fields_from_env(evaluator, server, fields) do\n    ref = make_ref()\n    send(evaluator, {:fields_from_env, server, ref, self(), fields})\n\n    receive do\n      {^ref, result} -> result\n    after\n      5000 -> %{}\n    end\n  end\n\n  defp loop(%{server: server, ref: ref} = state) do\n    receive do\n      {:reader_errored, ^server} ->\n        Process.put(:iex_error, true)\n        loop(state)\n\n      {:eval, ^server, code, counter} ->\n        {status, state} = safe_eval_and_inspect(code, counter, state)\n        send(server, {:evaled, self(), status})\n        loop(state)\n\n      {:fields_from_env, ^server, ref, receiver, fields} ->\n        send(receiver, {ref, Map.take(state.env, fields)})\n        loop(state)\n\n      {:value_from_binding, ^server, ref, receiver, var_name, map_key_path} ->\n        value = traverse_binding(state.binding, var_name, map_key_path)\n        send(receiver, {ref, value})\n        loop(state)\n\n      {:variables_from_binding, ^server, ref, receiver, var_prefix} ->\n        value = find_matched_variables(state.binding, var_prefix)\n        send(receiver, {ref, value})\n        loop(state)\n\n      {:done, ^server, next?} ->\n        {:ok, next?}\n\n      {:done, ^ref, next?} ->\n        {:ok, next?}\n    end\n  end\n\n  defp traverse_binding(binding, var_name, map_key_path) do\n    accumulator = Keyword.fetch(binding, var_name)\n\n    Enum.reduce(map_key_path, accumulator, fn\n      key, {:ok, map} when is_map(map) -> Map.fetch(map, key)\n      _key, _acc -> :error\n    end)\n  end\n\n  defp find_matched_variables(binding, var_prefix) do\n    for {var_name, _value} <- binding,\n        is_atom(var_name),\n        var_name = Atom.to_string(var_name),\n        String.starts_with?(var_name, var_prefix),\n        do: var_name\n  end\n\n  defp loop_state(ref, server, history, opts) do\n    env = opts[:env] || Code.env_for_eval(file: \"iex\")\n    {_, _, env} = Code.eval_quoted_with_env(quote(do: import(IEx.Helpers)), [], env)\n    stacktrace = opts[:stacktrace]\n    binding = opts[:binding] || []\n\n    state = %{\n      binding: binding,\n      env: env,\n      server: server,\n      history: history,\n      stacktrace: stacktrace,\n      ref: ref\n    }\n\n    dot_iex = opts[:dot_iex] || Config.dot_iex()\n\n    case dot_iex do\n      \"\" -> state\n      path -> load_dot_iex(state, path)\n    end\n  end\n\n  defp load_dot_iex(state, path) do\n    candidates =\n      if path do\n        [path]\n      else\n        # Do not assume there is a $HOME\n        for dir <- [\".\", System.get_env(\"IEX_HOME\") || System.user_home()],\n            dir != nil,\n            do: dir |> Path.join(\".iex.exs\") |> Path.expand()\n      end\n\n    path = Enum.find(candidates, &File.regular?/1)\n\n    if is_nil(path) do\n      state\n    else\n      eval_dot_iex(state, path)\n    end\n  end\n\n  defp eval_dot_iex(state, path) do\n    try do\n      code = File.read!(path)\n      quoted = :elixir.string_to_quoted!(String.to_charlist(code), 1, 1, path, [])\n      Process.put(:iex_imported_paths, MapSet.new([path]))\n\n      # Evaluate the contents in the same environment server_loop will run in\n      env = %{state.env | file: path, line: 1}\n      {_result, binding, env} = eval_expr_by_expr(quoted, state.binding, env)\n      %{state | binding: binding, env: %{env | file: \"iex\", line: 1}}\n    catch\n      kind, error ->\n        io_result(\"Error while evaluating: #{path}\")\n        print_error(kind, error, __STACKTRACE__)\n        state\n    after\n      Process.delete(:iex_imported_paths)\n    end\n  end\n\n  defp safe_eval_and_inspect(forms, counter, state) do\n    put_history(state)\n    put_whereami(state)\n    result = eval_and_inspect(forms, counter, state)\n    Process.delete(:iex_error)\n    {:ok, result}\n  catch\n    kind, error ->\n      Process.put(:iex_error, true)\n      print_error(kind, error, __STACKTRACE__)\n      {:error, state}\n  after\n    Process.delete(:iex_history)\n    Process.delete(:iex_whereami)\n  end\n\n  defp put_history(%{history: history}) do\n    Process.put(:iex_history, history)\n  end\n\n  defp put_whereami(%{env: %{file: \"iex\"}}) do\n    :ok\n  end\n\n  defp put_whereami(%{env: %{file: file, line: line}, stacktrace: stacktrace}) do\n    Process.put(:iex_whereami, {file, line, stacktrace})\n  end\n\n  defp eval_and_inspect(forms, line, state) do\n    %{env: env, binding: binding} = state\n    forms = add_if_undefined_apply_to_vars(forms, env)\n    {result, binding, env} = eval_expr_by_expr(forms, binding, env)\n\n    if result != IEx.dont_display_result() do\n      io_inspect(result)\n    end\n\n    history = IEx.History.append(state.history, {line, result}, IEx.Config.history_size())\n    %{state | env: env, binding: binding, history: history}\n  end\n\n  defp add_if_undefined_apply_to_vars(forms, env) do\n    Macro.prewalk(forms, fn\n      {var, meta, context} when is_atom(var) and is_atom(context) ->\n        if Macro.Env.lookup_import(env, {var, 0}) != [] do\n          {var, Keyword.put_new(meta, :if_undefined, :apply), context}\n        else\n          {var, meta, context}\n        end\n\n      other ->\n        other\n    end)\n  end\n\n  defp eval_expr_by_expr(expr, binding, env) do\n    case maybe_expand(expr, env) do\n      {:__block__, _, exprs} ->\n        Enum.reduce(exprs, {nil, binding, env}, fn expr, {_result, binding, env} ->\n          eval_expr_by_expr(expr, binding, env)\n        end)\n\n      expr ->\n        Code.eval_quoted_with_env(expr, binding, env)\n    end\n  end\n\n  defp maybe_expand({import_file, _, [_ | _]} = expr, env)\n       when import_file in [:import_file, :import_file_if_available],\n       do: Macro.expand(expr, env)\n\n  defp maybe_expand(expr, _env),\n    do: expr\n\n  defp io_inspect(result) do\n    io_result(inspect(result, IEx.inspect_opts()))\n  end\n\n  defp io_result(result) do\n    IO.puts(:stdio, IEx.color(:eval_result, result))\n  end\n\n  ## Error handling\n\n  defp print_error(kind, reason, stacktrace) do\n    {blamed, stacktrace} =\n      case reason do\n        %CompileError{description: \"cannot compile file (errors have been logged)\" <> _, line: 0} ->\n          {%CompileError{description: \"cannot compile code (errors have been logged)\"}, []}\n\n        _ ->\n          Exception.blame(kind, reason, stacktrace)\n      end\n\n    ansidata =\n      case blamed do\n        %FunctionClauseError{} ->\n          {_, inspect_opts} = pop_in(IEx.inspect_opts()[:syntax_colors][:reset])\n          banner = Exception.format_banner(kind, reason, stacktrace)\n          blame = FunctionClauseError.blame(blamed, &inspect(&1, inspect_opts), &blame_match/1)\n          [IEx.color(:eval_error, banner), pad(blame)]\n\n        _ ->\n          banner = Exception.format_banner(kind, blamed, stacktrace)\n          [IEx.color(:eval_error, banner)]\n      end\n\n    stackdata = Exception.format_stacktrace(prune_stacktrace(stacktrace))\n    IO.write(:stdio, [ansidata, ?\\n, IEx.color(:stack_info, stackdata)])\n  end\n\n  defp pad(string) do\n    \"    \" <> String.replace(string, \"\\n\", \"\\n    \")\n  end\n\n  defp blame_match(%{match?: true, node: node}), do: Macro.to_string(node)\n  defp blame_match(%{match?: false, node: node}), do: blame_ansi(:blame_diff, \"-\", node)\n\n  defp blame_ansi(color, no_ansi, node) do\n    case IEx.Config.color(color) do\n      nil ->\n        no_ansi <> Macro.to_string(node) <> no_ansi\n\n      ansi ->\n        [ansi | Macro.to_string(node)]\n        |> IO.ANSI.format(true)\n        |> IO.iodata_to_binary()\n    end\n  end\n\n  defp prune_stacktrace(stack) do\n    stack\n    |> Enum.reverse()\n    |> Enum.drop_while(&(elem(&1, 0) != :elixir_compiler))\n    |> Enum.reverse()\n    |> case do\n      [] -> stack\n      stack -> stack\n    end\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/helpers.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.Helpers do\n  @moduledoc \"\"\"\n  Welcome to Interactive Elixir. You are currently\n  seeing the documentation for the module `IEx.Helpers`\n  which provides many helpers to make Elixir's shell\n  more joyful to work with.\n\n  This message was triggered by invoking the helper `h()`,\n  usually referred to as `h/0` (since it expects 0 arguments).\n\n  You can use the `h/1` function to invoke the documentation\n  for any Elixir module or function:\n\n      iex> h(Enum)\n      iex> h(Enum.map)\n      iex> h(Enum.reverse/1)\n\n  You can also use the `i/1` function to introspect any value\n  you have in the shell:\n\n      iex> i(\"hello\")\n\n  There are many other helpers available, here are some examples:\n\n    * `b/1`             - prints callbacks info and docs for a given module\n    * `c/1`             - compiles a file\n    * `c/2`             - compiles a file and writes bytecode to the given path\n    * `cd/1`            - changes the current directory\n    * `clear/0`         - clears the screen\n    * `exports/1`       - shows all exports (functions + macros) in a module\n    * `flush/0`         - flushes all messages sent to the shell\n    * `h/0`             - prints this help message\n    * `h/1`             - prints help for the given module, function or macro\n    * `i/0`             - prints information about the last value\n    * `i/1`             - prints information about the given term\n    * `ls/0`            - lists the contents of the current directory\n    * `ls/1`            - lists the contents of the specified directory\n    * `open/1`          - opens the source for the given module or function in your editor\n    * `pid/1`           - creates a PID from a string\n    * `pid/3`           - creates a PID with the 3 integer arguments passed\n    * `port/1`          - creates a port from a string\n    * `port/2`          - creates a port with the 2 non-negative integers passed\n    * `process_info/1`  - returns information about the given process\n    * `pwd/0`           - prints the current working directory\n    * `r/1`             - recompiles the given module's source file\n    * `recompile/0`     - recompiles the current project\n    * `ref/1`           - creates a reference from a string\n    * `ref/4`           - creates a reference with the 4 integer arguments passed\n    * `runtime_info/0`  - prints runtime info (versions, memory usage, stats)\n    * `t/1`             - prints the types for the given module or function\n    * `v/0`             - retrieves the last value from the history\n    * `v/1`             - retrieves the nth value from the history\n\n  There are also several helpers available when debugging, such as:\n\n    * `break!/2`        - sets a breakpoint at `Module.function/arity`\n    * `breaks/0`        - prints all breakpoints to the terminal\n    * `c/0`             - a shortcut for `continue/0`\n    * `continue/0`      - continues execution of the current process\n    * `n/0`             - a shortcut for `next/0`\n    * `next/0`          - goes to the next line of the current breakpoint\n    * `remove_breaks/0` - removes all breakpoints and instrumentation from all modules\n    * `whereami/1`      - prints the current location and stacktrace in a pry session\n\n  Help for all of those functions can be consulted directly from\n  the command line using the `h/1` helper itself. Try:\n\n      iex> h(v/0)\n\n  To list all IEx helpers available, which is effectively all\n  exports (functions and macros) in the `IEx.Helpers` module:\n\n      iex> exports(IEx.Helpers)\n\n  This module also includes helpers for debugging purposes, see\n  `IEx.break!/4` for more information.\n\n  To learn more about IEx as a whole, type `h(IEx)`.\n  \"\"\"\n\n  import IEx, only: [dont_display_result: 0]\n\n  @doc \"\"\"\n  Recompiles the current Mix project or Mix install\n  dependencies.\n\n  This helper requires either `Mix.install/2` to have been\n  called within the current IEx session or for IEx to be\n  started alongside, for example, `iex -S mix`.\n\n  In the `Mix.install/1` case, it will recompile any outdated\n  path dependency declared during install. Within a project,\n  it will recompile any outdated module.\n\n  Note this function simply recompiles Elixir modules, without\n  reloading configuration or restarting applications. This means\n  any long running process may crash on recompilation, as changed\n  modules will be temporarily removed and recompiled, without\n  going through the proper code change callback.\n\n  If you want to reload a single module, consider using\n  `r(ModuleName)` instead.\n\n  This function is meant to be used for development and\n  debugging purposes. Do not depend on it in production code.\n\n  ## Options\n\n    * `:force` - when `true`, forces the application to recompile\n\n  \"\"\"\n  @spec recompile(force: boolean()) :: :ok | :error | :noop\n  def recompile(options \\\\ []) do\n    cond do\n      not mix_started?() ->\n        IO.puts(IEx.color(:eval_error, \"Mix is not running. Please start IEx with: iex -S mix\"))\n        :error\n\n      Mix.installed?() ->\n        Mix.in_install_project(fn ->\n          # TODO: remove this once Mix requires Hex with the fix from\n          # https://github.com/hexpm/hex/pull/1015\n          # Context: Mix.install/1 starts :hex if necessary and stops\n          # it afterwards. Calling compile here may require hex to be\n          # started and that should happen automatically, but because\n          # of a bug it is not (fixed in the linked PR).\n          _ = Application.ensure_all_started(:hex)\n\n          do_recompile(options)\n          # Just as with Mix.install/2 we clear all task invocations,\n          # so that we can recompile the dependencies again next time\n          Mix.Task.clear()\n          :ok\n        end)\n\n      true ->\n        project = Mix.Project.get()\n\n        if is_nil(project) or\n             project.__info__(:compile)[:source] == String.to_charlist(Path.absname(\"mix.exs\")) do\n          Mix.Project.with_build_lock(fn ->\n            purge_result = IEx.MixListener.purge()\n\n            case do_recompile(options) do\n              :noop -> purge_result\n              compile_result -> compile_result\n            end\n          end)\n        else\n          message = \"Cannot recompile because the current working directory changed\"\n          IO.puts(IEx.color(:eval_error, message))\n        end\n    end\n  end\n\n  defp do_recompile(options) do\n    config = Mix.Project.config()\n    consolidation = Mix.Project.consolidation_path(config)\n    reenable_tasks(config)\n\n    force? = Keyword.get(options, :force, false)\n    args = [\"--purge-consolidation-path-if-stale\", consolidation, \"--return-errors\"]\n    args = if force?, do: [\"--force\" | args], else: args\n\n    {result, _} = Mix.Task.run(\"compile\", args)\n    result\n  end\n\n  defp mix_started? do\n    List.keyfind(Application.started_applications(), :mix, 0) != nil\n  end\n\n  defp reenable_tasks(config) do\n    compilers = config[:compilers] || Mix.compilers()\n    Mix.Task.Compiler.reenable(compilers)\n  end\n\n  @doc \"\"\"\n  Compiles the given files.\n\n  It expects a list of files to compile and an optional path to write\n  the compiled code to. By default files are in-memory compiled.\n  To write compiled files to the current directory, `\".\"` can be given.\n\n  It returns the names of the compiled modules.\n\n  If you want to recompile an existing module, check `r/1` instead.\n\n  > #### Remote compilation {: .warning}\n  >\n  > When compiling code, warnings and errors may be printed to standard error.\n  > However, when connecting to a remote node, the standard error output is not\n  > redirected to the client. This means that compilation failures will be written\n  > to the logs or the output terminal of the machine you connect to.\n\n  ## Examples\n\n  In the example below, we pass a directory to where the `c/2` function will\n  write the compiled `.beam` files to. This directory is typically named \"ebin\"\n  in Erlang/Elixir systems:\n\n      iex> c([\"foo.ex\", \"bar.ex\"], \"ebin\")\n      [Foo, Bar]\n\n  When compiling one file, there is no need to wrap it in a list:\n\n      iex> c(\"baz.ex\")\n      [Baz]\n\n  \"\"\"\n  def c(files, path \\\\ :in_memory) when is_binary(path) or path == :in_memory do\n    files = List.wrap(files)\n\n    if not Enum.all?(files, &is_binary/1) do\n      raise ArgumentError, \"expected a binary or a list of binaries as argument\"\n    end\n\n    {found, not_found} = Enum.split_with(files, &File.exists?/1)\n\n    if not Enum.empty?(not_found) do\n      raise ArgumentError, \"could not find files #{Enum.join(not_found, \", \")}\"\n    end\n\n    {erls, exs} = Enum.split_with(found, &String.ends_with?(&1, \".erl\"))\n\n    erl_modules =\n      Enum.map(erls, fn source ->\n        {module, binary} = compile_erlang(source)\n\n        if path != :in_memory do\n          base = source |> Path.basename() |> Path.rootname()\n          File.write!(Path.join(path, base <> \".beam\"), binary)\n        end\n\n        module\n      end)\n\n    ex_modules =\n      case compile_elixir(exs, path) do\n        {:ok, modules, _} -> modules\n        {:error, _, _} -> raise CompileError\n      end\n\n    erl_modules ++ ex_modules\n  end\n\n  @doc \"\"\"\n  Clears the console screen.\n\n  This function only works if ANSI escape codes are enabled\n  on the shell, which means this function is by default\n  unavailable on Windows machines.\n  \"\"\"\n  def clear() do\n    if IO.ANSI.enabled?() do\n      IO.write([IO.ANSI.home(), IO.ANSI.clear()])\n    else\n      IO.puts(\"Cannot clear the screen because ANSI escape codes are not enabled on this shell\")\n    end\n\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  Opens the current prying location.\n\n  This command only works inside a pry session started manually\n  via `IEx.pry/0` or a breakpoint set via `IEx.break!/4`. Calling\n  this function during a regular `IEx` session will print an error.\n\n  Keep in mind the `open/0` location may not exist when prying\n  precompiled source code, such as Elixir itself.\n\n  For more information and to open any module or function, see\n  `open/1`.\n  \"\"\"\n  def open() do\n    case Process.get(:iex_whereami) do\n      {file, line, _} ->\n        IEx.Introspection.open({file, line})\n\n      _ ->\n        IO.puts(IEx.color(:eval_error, \"Pry session is not currently enabled\"))\n    end\n\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  Opens the given `module`, `module.function/arity`, or `{file, line}`.\n\n  This function uses the `ELIXIR_EDITOR` environment variable\n  and falls back to `EDITOR` if the former is not available.\n\n  By default, it attempts to open the file and line using the\n  `file:line` notation. For example, for Sublime Text you can\n  set it as:\n\n      ELIXIR_EDITOR=\"subl\"\n\n  Which will then try to open it as:\n\n      subl path/to/file:line\n\n  For Visual Studio Code, once enabled on the command line,\n  you can set it to:\n\n      ELIXIR_EDITOR=\"code --goto\"\n\n  It is important that you choose an editor command that does\n  not block nor that attempts to run an editor directly in the\n  terminal. Command-line based editors likely need extra\n  configuration so they open up the given file and line in a\n  separate window.\n\n  For more complex use cases, you can use the `__FILE__` and\n  `__LINE__` notations to explicitly interpolate the file and\n  line into the command:\n\n      ELIXIR_EDITOR=\"my_editor +__LINE__ __FILE__\"\n\n  Since this function prints the result returned by the editor,\n  `ELIXIR_EDITOR` can be set \"echo\" if you prefer to display the\n  location rather than opening it.\n\n  Keep in mind the location may not exist when opening precompiled\n  source code.\n\n  ## Examples\n\n      iex> open(MyApp)\n      iex> open(MyApp.fun/2)\n      iex> open({\"path/to/file\", 1})\n\n  \"\"\"\n  defmacro open(term) do\n    quote do\n      IEx.Introspection.open(unquote(decompose(term, __CALLER__)))\n    end\n  end\n\n  @doc \"\"\"\n  Prints the documentation for `IEx.Helpers`.\n  \"\"\"\n  def h() do\n    IEx.Introspection.h(IEx.Helpers)\n  end\n\n  @doc \"\"\"\n  Prints the documentation for the given module\n  or for the given `function/arity` pair.\n\n  ## Examples\n\n      iex> h(Enum)\n\n  It also accepts functions in the format `function/arity`\n  and `module.function/arity`, for example:\n\n      iex> h(receive/1)\n      iex> h(Enum.all?/2)\n      iex> h(Enum.all?)\n\n  \"\"\"\n  defmacro h(term) do\n    quote do\n      IEx.Introspection.h(unquote(decompose(term, __CALLER__)))\n    end\n  end\n\n  @doc \"\"\"\n  Prints the documentation for the given callback function.\n\n  It also accepts single module argument to list\n  all available behaviour callbacks.\n\n  ## Examples\n\n      iex> b(Mix.Task.run/1)\n      iex> b(Mix.Task.run)\n      iex> b(GenServer)\n\n  \"\"\"\n  defmacro b(term) do\n    quote do\n      IEx.Introspection.b(unquote(decompose(term, __CALLER__)))\n    end\n  end\n\n  @doc \"\"\"\n  Prints the types for the given module or for the given function/arity pair.\n\n  ## Examples\n\n      iex> t(Enum)\n      @type t() :: Enumerable.t()\n      @type acc() :: any()\n      @type element() :: any()\n      @type index() :: integer()\n      @type default() :: any()\n\n      iex> t(Enum.t/0)\n      @type t() :: Enumerable.t()\n\n      iex> t(Enum.t)\n      @type t() :: Enumerable.t()\n\n  \"\"\"\n  defmacro t(term) do\n    quote do\n      IEx.Introspection.t(unquote(decompose(term, __CALLER__)))\n    end\n  end\n\n  @doc \"\"\"\n  Returns the value of the `n`th expression in the history.\n\n  `n` can be a negative value: if it is, the corresponding expression value\n  relative to the current one is returned. For example, `v(-2)` returns the\n  value of the expression evaluated before the last evaluated expression. In\n  particular, `v(-1)` returns the result of the last evaluated expression and\n  `v()` does the same.\n\n  ## Examples\n\n      iex(1)> \"hello\" <> \" world\"\n      \"hello world\"\n      iex(2)> 40 + 2\n      42\n      iex(3)> v(-2)\n      \"hello world\"\n      iex(4)> v(2)\n      42\n      iex(5)> v()\n      42\n\n  \"\"\"\n  def v(n \\\\ -1) do\n    IEx.History.nth(history(), n) |> elem(1)\n  end\n\n  @doc \"\"\"\n  Recompiles and reloads the given `module` or `modules`.\n\n  Please note that all the modules defined in the same file as\n  `modules` are recompiled and reloaded. If you want to reload\n  multiple modules, it is best to reload them at the same time,\n  such as in `r [Foo, Bar]`. This is important to avoid false\n  warnings, since the module is only reloaded in memory and its\n  latest information is not persisted to disk. See the \"In-memory\n  reloading\" section below.\n\n  This function is meant to be used for development and\n  debugging purposes. Do not depend on it in production code.\n\n  ## In-memory reloading\n\n  When we reload the module in IEx, we recompile the module source\n  code, updating its contents in memory. The original `.beam` file\n  in disk, probably the one where the first definition of the module\n  came from, does not change at all.\n\n  Since docs, typespecs, and exports information are loaded from the\n  .beam file, they are not reloaded when you invoke this function.\n  \"\"\"\n  def r(module_or_modules) do\n    modules = List.wrap(module_or_modules)\n\n    sources =\n      Enum.map(modules, fn module ->\n        if not Code.ensure_loaded?(module) do\n          raise ArgumentError, \"could not load nor find module: #{inspect(module)}\"\n        end\n\n        source = source(module)\n\n        cond do\n          source == nil ->\n            raise ArgumentError, \"could not find source for module: #{inspect(module)}\"\n\n          not File.exists?(source) ->\n            raise ArgumentError,\n                  \"could not find source (#{source}) for module: #{inspect(module)}\"\n\n          true ->\n            source\n        end\n      end)\n\n    {erlang, elixir} = Enum.split_with(sources, &String.ends_with?(&1, \".erl\"))\n\n    erlang =\n      for source <- erlang do\n        compile_erlang(source) |> elem(0)\n      end\n\n    elixir =\n      if elixir != [] do\n        {:ok, modules, _warning} =\n          Kernel.ParallelCompiler.compile(elixir, return_diagnostics: true)\n\n        modules\n      else\n        []\n      end\n\n    {:reloaded, erlang ++ elixir}\n  end\n\n  @doc \"\"\"\n  Loads the given module's BEAM code (and ensures any previous\n  old version was properly purged before).\n\n  This function is useful when you know the bytecode for module\n  has been updated in the file system and you want to tell the VM\n  to load it.\n  \"\"\"\n  def l(module) when is_atom(module) do\n    :code.purge(module)\n    :code.load_file(module)\n  end\n\n  @doc \"\"\"\n  Prints information about the data type of any given term.\n\n  If no argument is given, the value of the previous expression\n  is used.\n\n  ## Examples\n\n      iex> i(1..5)\n\n  Will print:\n\n      Term\n        1..5\n      Data type\n        Range\n      Description\n        This is a struct. Structs are maps with a __struct__ key.\n      Reference modules\n        Range, Map\n\n  \"\"\"\n  def i(term \\\\ v(-1)) do\n    implemented_protocols = [{\"Implemented protocols\", all_implemented_protocols_for_term(term)}]\n    info = [{\"Term\", inspect(term)}] ++ IEx.Info.info(term) ++ implemented_protocols\n\n    for {subject, info} <- info do\n      info = info |> to_string() |> String.trim() |> String.replace(\"\\n\", \"\\n  \")\n      IO.puts(IEx.color(:eval_result, to_string(subject)))\n      IO.puts(IEx.color(:eval_info, \"  #{info}\"))\n    end\n\n    dont_display_result()\n  end\n\n  defp decompose(term, context) do\n    case IEx.Introspection.decompose(term, context) do\n      :error -> term\n      m_mf_mfa -> Macro.escape(m_mf_mfa)\n    end\n  end\n\n  # Given any \"term\", this function returns all the protocols in\n  # :code.get_path() implemented by the data structure of such term, in the form\n  # of a binary like \"Protocol1, Protocol2, Protocol3\".\n  defp all_implemented_protocols_for_term(term) do\n    :code.get_path()\n    |> Protocol.extract_protocols()\n    |> Enum.uniq()\n    |> Enum.filter(fn protocol ->\n      Code.ensure_loaded?(protocol) and function_exported?(protocol, :impl_for, 1) and\n        protocol.impl_for(term) != nil\n    end)\n    |> Enum.sort()\n    |> Enum.map_join(\", \", &inspect/1)\n  end\n\n  @runtime_info_topics [:system, :memory, :limits, :applications, :allocators]\n  @doc \"\"\"\n  Prints VM/runtime information such as versions, memory usage and statistics.\n\n  Additional topics are available via `runtime_info/1`.\n\n  For more metrics, info, and debugging facilities, see the\n  [Recon](https://github.com/ferd/recon) project.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  def runtime_info(), do: runtime_info([:system, :memory, :limits])\n\n  @doc \"\"\"\n  Just like `runtime_info/0`, except accepts topic or a list of topics.\n\n  For example, topic `:applications` will list the applications loaded.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  def runtime_info(topic) when is_atom(topic) and topic in @runtime_info_topics do\n    topic\n    |> List.wrap()\n    |> runtime_info()\n  end\n\n  def runtime_info(topics) when is_list(topics) do\n    topics\n    |> Enum.uniq()\n    |> print_runtime_info()\n  end\n\n  defp print_runtime_info(topics) do\n    Enum.each(topics, &print_runtime_info_topic/1)\n    IO.puts(\"\")\n    print_topic_info(topics)\n    IO.puts(\"\")\n    dont_display_result()\n  end\n\n  defp print_topic_info(topics) when is_list(topics) do\n    IO.write(pad_key(\"Showing topics:\"))\n    IO.puts(inspect(topics))\n    IO.write(pad_key(\"Additional topics:\"))\n    IO.puts(inspect(@runtime_info_topics -- topics))\n    IO.puts(\"\")\n    IO.puts(\"To view a specific topic call runtime_info(topic)\")\n  end\n\n  defp print_runtime_info_topic(:system) do\n    print_pane(\"System and architecture\")\n\n    print_entry(\"Elixir version\", System.version())\n    print_entry(\"Erlang/OTP version\", System.otp_release())\n    print_entry(\"ERTS version\", :erlang.system_info(:version))\n    print_entry(\"Compiled for\", :erlang.system_info(:system_architecture))\n    print_entry(\"Schedulers\", :erlang.system_info(:schedulers))\n    print_entry(\"Schedulers online\", :erlang.system_info(:schedulers_online))\n  end\n\n  defp print_runtime_info_topic(:memory) do\n    print_pane(\"Memory\")\n    print_memory(\"Atoms\", :atom)\n    print_memory(\"Binaries\", :binary)\n    print_memory(\"Code\", :code)\n    print_memory(\"ETS\", :ets)\n    print_memory(\"Processes\", :processes)\n    print_memory(\"Total\", :total)\n  end\n\n  defp print_runtime_info_topic(:limits) do\n    print_pane(\"Statistics / limits\")\n    print_uptime()\n    print_entry(\"Run queue\", :erlang.statistics(:run_queue))\n\n    print_percentage(\"Atoms\", :atom_count, :atom_limit)\n    print_percentage(\"ETS\", :ets_count, :ets_limit)\n    print_percentage(\"Ports\", :port_count, :port_limit)\n    print_percentage(\"Processes\", :process_count, :process_limit)\n  end\n\n  defp print_runtime_info_topic(:applications) do\n    print_pane(\"Loaded OTP applications\")\n    started = Application.started_applications()\n    loaded = Application.loaded_applications()\n\n    for {app, _, version} = entry <- Enum.sort(loaded) do\n      IO.write(pad_key(Atom.to_string(app)))\n      IO.write(String.pad_trailing(\"#{version}\", 20))\n\n      if entry in started do\n        IO.write(\"(started)\")\n      end\n\n      IO.puts(\"\")\n    end\n\n    :ok\n  end\n\n  @allocator_column_padding 12\n  @allocator_size_padding 19\n\n  defp print_runtime_info_topic(:allocators) do\n    allocator_sizes_map = get_allocator_sizes()\n\n    if Enum.empty?(allocator_sizes_map) do\n      IO.puts(IEx.color(:eval_error, \"Could not get allocator sizes.\"))\n    else\n      print_pane(\"Memory allocators\")\n\n      IO.puts([\n        String.duplicate(\" \", @allocator_column_padding),\n        String.pad_leading(\"Block size\", @allocator_size_padding),\n        String.pad_leading(\"Carrier size\", @allocator_size_padding),\n        String.pad_leading(\"Max carrier size\", @allocator_size_padding)\n      ])\n\n      print_allocator(\"Temporary\", allocator_sizes_map.temp_alloc)\n      print_allocator(\"Short-lived\", allocator_sizes_map.sl_alloc)\n      print_allocator(\"STD\", allocator_sizes_map.std_alloc)\n      print_allocator(\"Long-lived\", allocator_sizes_map.ll_alloc)\n      print_allocator(\"Erlang heap\", allocator_sizes_map.eheap_alloc)\n      print_allocator(\"ETS\", allocator_sizes_map.ets_alloc)\n      print_allocator(\"Fix\", allocator_sizes_map.fix_alloc)\n      print_allocator(\"Literal\", allocator_sizes_map.literal_alloc)\n      print_allocator(\"Binary\", allocator_sizes_map.binary_alloc)\n      print_allocator(\"Driver\", allocator_sizes_map.driver_alloc)\n      print_allocator(\"Total\", allocator_sizes_map.total)\n    end\n  end\n\n  defp print_pane(msg) do\n    IO.puts(IEx.color(:eval_result, [\"\\n## \", msg, \" \\n\"]))\n  end\n\n  defp print_entry(_key, nil), do: :ok\n  defp print_entry(key, value), do: IO.puts(\"#{pad_key(key)}#{value}\")\n\n  defp print_uptime() do\n    IO.write(pad_key(\"Uptime\"))\n    :c.uptime()\n  end\n\n  defp print_percentage(key, min, max) do\n    min = get_stat(min)\n    max = get_stat(max)\n    percentage = trunc(min / max * 100)\n    IO.puts(\"#{pad_key(key)}#{min} / #{max} (#{percentage}% used)\")\n  end\n\n  defp get_stat(:ets_count), do: :erlang.system_info(:ets_count)\n  defp get_stat(other), do: :erlang.system_info(other)\n\n  defp print_memory(key, memory) do\n    value = :erlang.memory(memory)\n    IO.puts(\"#{pad_key(key)}#{format_bytes(value)}\")\n  end\n\n  defp print_allocator(title, %{\n         block_size: block_size,\n         carrier_size: carriers_size,\n         max_carrier_size: max_carriers_size\n       }) do\n    IO.puts([\n      String.pad_trailing(title, @allocator_column_padding),\n      block_size |> format_bytes(:KB) |> String.pad_leading(@allocator_size_padding),\n      carriers_size |> format_bytes(:KB) |> String.pad_leading(@allocator_size_padding),\n      max_carriers_size |> format_bytes(:KB) |> String.pad_leading(@allocator_size_padding)\n    ])\n  end\n\n  defp get_allocator_sizes() do\n    alloc_util_allocators = :erlang.system_info(:alloc_util_allocators)\n\n    allocators_map =\n      Map.new(\n        [:total | alloc_util_allocators],\n        &{&1, %{block_size: 0, carrier_size: 0, max_carrier_size: 0}}\n      )\n\n    try do\n      for {allocator, allocator_instances} <-\n            :erlang.system_info({:allocator_sizes, alloc_util_allocators}),\n          {:instance, _, instance_info} <- allocator_instances,\n          {_, [{:blocks, blocks}, {:carriers_size, ccs, mcs, _}]} <-\n            instance_info,\n          reduce: allocators_map do\n        acc ->\n          cbs =\n            case blocks do\n              [{_, [{:size, bs, _, _}]}] -> bs\n              _ -> 0\n            end\n\n          %{\n            block_size: block_size,\n            carrier_size: carrier_size,\n            max_carrier_size: max_carrier_size\n          } = Map.fetch!(acc, allocator)\n\n          %{\n            block_size: total_block_size,\n            carrier_size: total_carrier_size,\n            max_carrier_size: total_max_carrier_size\n          } = Map.fetch!(acc, :total)\n\n          acc\n          |> Map.replace!(allocator, %{\n            block_size: block_size + cbs,\n            carrier_size: carrier_size + ccs,\n            max_carrier_size: max_carrier_size + mcs\n          })\n          |> Map.replace!(:total, %{\n            block_size: total_block_size + cbs,\n            carrier_size: total_carrier_size + ccs,\n            max_carrier_size: total_max_carrier_size + mcs\n          })\n      end\n    rescue\n      _ -> %{}\n    end\n  end\n\n  defp format_bytes(bytes) when is_integer(bytes) do\n    cond do\n      bytes >= memory_unit(:GB) -> format_bytes(bytes, :GB)\n      bytes >= memory_unit(:MB) -> format_bytes(bytes, :MB)\n      bytes >= memory_unit(:KB) -> format_bytes(bytes, :KB)\n      true -> format_bytes(bytes, :B)\n    end\n  end\n\n  defp format_bytes(bytes, unit) when is_integer(bytes) and unit in [:GB, :MB, :KB] do\n    value =\n      bytes\n      |> div(memory_unit(unit))\n      |> round()\n\n    \"#{value} #{unit}\"\n  end\n\n  defp format_bytes(bytes, :B) when is_integer(bytes), do: \"#{bytes} B\"\n\n  defp memory_unit(:GB), do: 1024 * 1024 * 1024\n  defp memory_unit(:MB), do: 1024 * 1024\n  defp memory_unit(:KB), do: 1024\n\n  defp pad_key(key), do: String.pad_trailing(key, 21, \" \")\n\n  @process_info_keys_and_labels [\n    {:initial_call, \"Initial call\"},\n    {:dictionary, \"Dictionary\"},\n    {:registered_name, \"Registered name\"},\n    {:current_function, \"Current function\"},\n    {:status, \"Status\"},\n    {:message_queue_len, \"Message queue length\"},\n    {:trap_exit, \"Trap exit\"},\n    {:priority, \"Priority\"},\n    {:group_leader, \"Group leader\"},\n    {:reductions, \"Reductions\"},\n    {:links, \"Links\"},\n    {:monitors, \"Monitors\"},\n    {:memory, \"Memory\"},\n    {:total_heap_size, \"Total heap size\"},\n    {:heap_size, \"Heap size\"},\n    {:stack_size, \"Stack size\"},\n    {:current_stacktrace, \"Current stacktrace\"}\n  ]\n  @process_info_keys Enum.map(@process_info_keys_and_labels, fn {key, _} -> key end)\n  @process_info_label_mapping Map.new(@process_info_keys_and_labels)\n\n  @doc \"\"\"\n  Prints information about the given process.\n\n  Includes a generic overview and details such as the linked and monitored processes,\n  the memory usage and the current stacktrace.\n\n  ## Examples\n\n      iex> process_info(self())\n      ...\n      iex> process_info({:via, Registry, {MyApp.Registry, :name}})\n      ...\n\n  \"\"\"\n  @doc since: \"1.19.0\"\n  def process_info(pid) do\n    with pid when is_pid(pid) <- GenServer.whereis(pid),\n         info when is_list(info) <-\n           :erpc.call(node(pid), :erlang, :process_info, [pid, @process_info_keys]) do\n      info = Map.new(info)\n\n      IO.puts(IEx.color(:eval_result, [\"\\n# Process \", inspect(pid)]))\n\n      print_process_overview(info)\n      print_process_links(info[:links])\n      print_process_monitors(info[:monitors])\n      print_process_memory(info)\n      print_process_stacktrace(info[:current_stacktrace])\n    else\n      _ ->\n        IO.puts(\n          IEx.color(\n            :eval_error,\n            \"Failed to get process info. Either the process was not found or is not alive.\"\n          )\n        )\n    end\n\n    dont_display_result()\n  end\n\n  defp print_process_overview(info) do\n    print_pane(\"Overview\")\n\n    for key <- [\n          :initial_call,\n          :current_function,\n          :registered_name,\n          :status,\n          :message_queue_len,\n          :group_leader,\n          :priority,\n          :trap_exit,\n          :reductions\n        ] do\n      print_entry(\n        @process_info_label_mapping[key],\n        inspect(info[key], printable_limit: 256, limit: 5)\n      )\n    end\n  end\n\n  defp print_process_links([]), do: :ok\n\n  defp print_process_links(ports_and_pids) do\n    print_pane(\"Links\")\n\n    for link <- ports_and_pids do\n      print_entry(inspect(link), pid_or_port_details(link))\n    end\n  end\n\n  defp print_process_monitors([]), do: :ok\n\n  defp print_process_monitors(monitors) do\n    print_pane(\"Monitors\")\n\n    for {_, pid_or_port} <- monitors do\n      print_entry(inspect(pid_or_port), pid_or_port_details(pid_or_port))\n    end\n  end\n\n  defp print_process_memory(info) do\n    print_pane(\"Memory\")\n\n    for key <- [:memory, :total_heap_size, :heap_size, :stack_size] do\n      print_entry(@process_info_label_mapping[key], format_bytes(info[key]))\n    end\n  end\n\n  defp print_process_stacktrace([]), do: :ok\n\n  defp print_process_stacktrace(stacktrace) do\n    print_pane(\"Current stacktrace\")\n\n    IO.puts(IEx.color(:eval_info, Exception.format_stacktrace(stacktrace)))\n  end\n\n  defp pid_or_port_details(pid) when is_pid(pid), do: to_process_details(pid)\n  defp pid_or_port_details(name) when is_atom(name), do: to_process_details(name)\n  defp pid_or_port_details(port) when is_port(port), do: to_port_details(port)\n  defp pid_or_port_details(reference) when is_reference(reference), do: reference\n\n  defp to_process_details(pid) when is_pid(pid) do\n    case Process.info(pid, [:initial_call, :dictionary, :registered_name]) do\n      [{:initial_call, initial_call}, {:dictionary, dictionary}, {:registered_name, name}] ->\n        initial_call = Keyword.get(dictionary, :\"$initial_call\", initial_call)\n\n        format_registered_name(name) ||\n          format_process_label(Keyword.get(dictionary, :\"$process_label\")) ||\n          format_initial_call(initial_call)\n\n      _ ->\n        \"-\"\n    end\n  end\n\n  defp to_process_details(name) when is_atom(name) do\n    Process.whereis(name)\n    |> to_process_details()\n  end\n\n  defp format_process_label(nil), do: nil\n  defp format_process_label(label) when is_binary(label), do: label\n  defp format_process_label(label), do: inspect(label)\n\n  defp format_registered_name([]), do: nil\n  defp format_registered_name(name), do: inspect(name)\n\n  defp format_initial_call({:supervisor, mod, arity}), do: Exception.format_mfa(mod, :init, arity)\n  defp format_initial_call({m, f, a}), do: Exception.format_mfa(m, f, a)\n  defp format_initial_call(nil), do: nil\n\n  defp to_port_details(port) when is_port(port) do\n    case Port.info(port, :name) do\n      {:name, name} -> name\n      _ -> \"-\"\n    end\n  end\n\n  @doc \"\"\"\n  Clears out all messages sent to the shell's inbox and prints them out.\n  \"\"\"\n  def flush do\n    do_flush(IEx.inspect_opts())\n  end\n\n  defp do_flush(inspect_opts) do\n    receive do\n      msg ->\n        IO.inspect(msg, inspect_opts)\n        do_flush(inspect_opts)\n    after\n      0 -> :ok\n    end\n  end\n\n  defp source(module) do\n    source = module.module_info(:compile)[:source]\n\n    case source do\n      nil -> nil\n      source -> List.to_string(source)\n    end\n  end\n\n  @doc \"\"\"\n  Prints the current working directory.\n  \"\"\"\n  def pwd do\n    IO.puts(IEx.color(:eval_info, File.cwd!()))\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  Changes the current working directory to the given path.\n  \"\"\"\n  def cd(directory) when is_binary(directory) do\n    case File.cd(expand_home(directory)) do\n      :ok ->\n        pwd()\n\n      {:error, :enoent} ->\n        IO.puts(IEx.color(:eval_error, \"No directory #{directory}\"))\n\n      {:error, reason} ->\n        IO.puts(IEx.color(:eval_error, :file.format_error(reason)))\n    end\n\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  Prints a list of all the functions and macros exported by the given module.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  def exports(module \\\\ Kernel) do\n    exports = IEx.Autocomplete.exports(module)\n\n    list =\n      Enum.map(exports, fn {name, arity} ->\n        Atom.to_string(name) <> \"/\" <> Integer.to_string(arity)\n      end)\n\n    print_table(list)\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  Prints a list of the given directory's contents.\n\n  If `path` points to a file, prints its full path.\n  \"\"\"\n  def ls(path \\\\ \".\") when is_binary(path) do\n    path = expand_home(path)\n\n    case File.ls(path) do\n      {:ok, items} ->\n        sorted_items = Enum.sort(items)\n\n        printer = fn item, width ->\n          format_item(Path.join(path, item), String.pad_trailing(item, width))\n        end\n\n        print_table(sorted_items, printer)\n\n      {:error, :enoent} ->\n        IO.puts(IEx.color(:eval_error, \"No such file or directory #{path}\"))\n\n      {:error, reason} ->\n        cond do\n          File.exists?(path) and not File.dir?(path) ->\n            IO.puts(IEx.color(:eval_info, Path.absname(path)))\n\n          reason == :enotdir ->\n            IO.puts(IEx.color(:eval_error, \"No such file or directory #{path}\"))\n\n          true ->\n            IO.puts(IEx.color(:eval_error, :file.format_error(reason)))\n        end\n    end\n\n    dont_display_result()\n  end\n\n  defp expand_home(<<?~, rest::binary>>) do\n    System.user_home!() <> rest\n  end\n\n  defp expand_home(other), do: other\n\n  defp print_table(list, printer \\\\ &String.pad_trailing/2)\n\n  defp print_table([], _printer) do\n    :ok\n  end\n\n  defp print_table(list, printer) do\n    # print items in multiple columns (2 columns in the worst case)\n    lengths = Enum.map(list, &String.length(&1))\n    max_length = max_length(lengths)\n    offset = min(max_length, 30) + 4\n    print_table(list, printer, offset)\n  end\n\n  defp print_table(list, printer, offset) do\n    Enum.reduce(list, 0, fn item, length ->\n      length =\n        if length >= 80 do\n          IO.puts(\"\")\n          0\n        else\n          length\n        end\n\n      printed = printer.(item, offset)\n      actual_offset = String.length(printed) + 1\n\n      IO.write(printed <> \" \")\n      length + actual_offset\n    end)\n\n    IO.puts(\"\")\n  end\n\n  defp max_length(list) do\n    Enum.reduce(list, 0, &max(&1, &2))\n  end\n\n  defp format_item(path, representation) do\n    case File.stat(path) do\n      {:ok, %File.Stat{type: :device}} ->\n        IEx.color(:ls_device, representation)\n\n      {:ok, %File.Stat{type: :directory}} ->\n        IEx.color(:ls_directory, representation)\n\n      _ ->\n        representation\n    end\n  end\n\n  @doc \"\"\"\n  Respawns the current shell by starting a new shell process.\n  \"\"\"\n  def respawn do\n    if iex_server = Process.get(:iex_server) do\n      send(iex_server, {:respawn, self()})\n    end\n\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  Continues execution of the current process.\n\n  This is usually called by sessions started with `IEx.pry/0`\n  or `IEx.break!/4`. This allows the current process to execute\n  until the next breakpoint, which will automatically yield control\n  back to IEx without requesting permission to pry.\n\n  If you simply want to move to the next line of the current breakpoint,\n  use `n/0` or `next/0` instead.\n\n  If the running process terminates, a new IEx session is\n  started.\n\n  While the process executes, the user will no longer have\n  control of the shell. If you would rather start a new shell,\n  use `respawn/0` instead.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  def continue do\n    if iex_server = Process.get(:iex_server) do\n      send(iex_server, {:continue, self(), false})\n    end\n\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  Goes to the next line of the current breakpoint.\n\n  This is usually called by sessions started with `IEx.break!/4`.\n  If instead of the next line you want to move to the next breakpoint,\n  call `continue/0` instead.\n\n  While the process executes, the user will no longer have\n  control of the shell. If you would rather start a new shell,\n  use `respawn/0` instead.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  def next do\n    if iex_server = Process.get(:iex_server) do\n      send(iex_server, {:continue, self(), true})\n    end\n\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  A shortcut for `next/0`.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  def n do\n    next()\n  end\n\n  @doc \"\"\"\n  A shortcut for `continue/0`.\n  \"\"\"\n  @doc since: \"1.17.0\"\n  def c do\n    continue()\n  end\n\n  @doc \"\"\"\n  Sets up a breakpoint in the AST of shape `Module.function/arity`\n  with the given number of `stops`.\n\n  See `IEx.break!/4` for a complete description of breakpoints\n  in IEx.\n\n  ## Examples\n\n      break! URI.decode_query/2\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  defmacro break!(ast, stops \\\\ 1) do\n    quote do\n      require IEx\n      IEx.break!(unquote(ast), unquote(stops))\n    end\n  end\n\n  @doc \"\"\"\n  Sets up a breakpoint in `module`, `function` and `arity`\n  with the given number of `stops`.\n\n  See `IEx.break!/4` for a complete description of breakpoints\n  in IEx.\n\n  ## Examples\n\n      break! URI, :decode_query, 2\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  defdelegate break!(module, function, arity, stops \\\\ 1), to: IEx\n\n  @doc \"\"\"\n  Prints all breakpoints to the terminal.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  def breaks do\n    breaks(IEx.Pry.breaks())\n  end\n\n  defp breaks([]) do\n    IO.puts(IEx.color(:eval_info, \"No breakpoints set\"))\n    dont_display_result()\n  end\n\n  defp breaks(breaks) do\n    entries =\n      for {id, module, {function, arity}, stops} <- breaks do\n        {\n          Integer.to_string(id),\n          Exception.format_mfa(module, function, arity),\n          Integer.to_string(stops)\n        }\n      end\n\n    entries = [{\"ID\", \"Module.function/arity\", \"Pending stops\"} | entries]\n\n    {id_max, mfa_max, stops_max} =\n      Enum.reduce(entries, {0, 0, 0}, fn {id, mfa, stops}, {id_max, mfa_max, stops_max} ->\n        {\n          max(byte_size(id), id_max),\n          max(byte_size(mfa), mfa_max),\n          max(byte_size(stops), stops_max)\n        }\n      end)\n\n    [header | entries] = entries\n\n    IO.puts(\"\")\n    print_break(header, id_max, mfa_max)\n\n    IO.puts([\n      String.duplicate(\"-\", id_max + 2),\n      ?\\s,\n      String.duplicate(\"-\", mfa_max + 2),\n      ?\\s,\n      String.duplicate(\"-\", stops_max + 2)\n    ])\n\n    Enum.each(entries, &print_break(&1, id_max, mfa_max))\n    IO.puts(\"\")\n\n    dont_display_result()\n  end\n\n  defp print_break({id, mfa, stops}, id_max, mfa_max) do\n    IO.puts([\n      ?\\s,\n      String.pad_trailing(id, id_max + 2),\n      ?\\s,\n      String.pad_trailing(mfa, mfa_max + 2),\n      ?\\s,\n      stops\n    ])\n  end\n\n  @doc \"\"\"\n  Resets the number of pending stops in the breakpoint\n  with the given `id` to zero.\n\n  Returns `:ok` if there is such breakpoint ID. `:not_found`\n  otherwise.\n\n  Note the module remains \"instrumented\" on reset. If you would\n  like to effectively remove all breakpoints and instrumentation\n  code from a module, use `remove_breaks/1` instead.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  defdelegate reset_break(id), to: IEx.Pry\n\n  @doc \"\"\"\n  Resets the number of pending stops in the given module,\n  function and arity to zero.\n\n  If the module is not instrumented or if the given function\n  does not have a breakpoint, it is a no-op and it returns\n  `:not_found`. Otherwise it returns `:ok`.\n\n  Note the module remains \"instrumented\" on reset. If you would\n  like to effectively remove all breakpoints and instrumentation\n  code from a module, use `remove_breaks/1` instead.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  defdelegate reset_break(module, function, arity), to: IEx.Pry\n\n  @doc \"\"\"\n  Removes all breakpoints and instrumentation from `module`.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  defdelegate remove_breaks(module), to: IEx.Pry\n\n  @doc \"\"\"\n  Removes all breakpoints and instrumentation from all modules.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  defdelegate remove_breaks(), to: IEx.Pry\n\n  @doc \"\"\"\n  Prints the current location and stacktrace in a pry session.\n\n  It expects a `radius` which chooses how many lines before and after\n  the current line we should print. By default the `radius` is of two\n  lines:\n\n      Location: lib/iex/lib/iex/helpers.ex:79\n\n      77:\n      78:   def recompile do\n      79:     require IEx; IEx.pry()\n      80:     if mix_started?() do\n      81:       config = Mix.Project.config\n\n      (IEx.Helpers) lib/iex/lib/iex/helpers.ex:78: IEx.Helpers.recompile/0\n\n  This command only works inside a pry session started manually\n  via `IEx.pry/0` or a breakpoint set via `IEx.break!/4`. Calling\n  this function during a regular `IEx` session will print an error.\n\n  Keep in mind the `whereami/1` location may not exist when prying\n  precompiled source code, such as Elixir itself.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  def whereami(radius \\\\ 2) do\n    case Process.get(:iex_whereami) do\n      {file, line, stacktrace} ->\n        msg = [\"Location: \", Path.relative_to_cwd(file), \":\", Integer.to_string(line)]\n        IO.puts(IEx.color(:eval_info, msg))\n\n        case IEx.Pry.whereami(file, line, radius) do\n          {:ok, lines} ->\n            IO.write([?\\n, lines, ?\\n])\n\n          :error ->\n            msg = \"Could not extract source snippet. Location is not available.\"\n            IO.puts(IEx.color(:eval_error, msg))\n        end\n\n        case stacktrace do\n          nil -> :ok\n          stacktrace -> IO.write([Exception.format_stacktrace(stacktrace), ?\\n])\n        end\n\n      _ ->\n        IO.puts(IEx.color(:eval_error, \"Pry session is not currently enabled\"))\n    end\n\n    dont_display_result()\n  end\n\n  @doc \"\"\"\n  Similar to `import_file` but only imports the file if it is available.\n\n  By default, `import_file/1` fails when the given file does not exist.\n  However, since `import_file/1` is expanded at compile-time, it's not\n  possible to conditionally import a file since the macro is always\n  expanded:\n\n      # This raises a File.Error if ~/.iex.exs doesn't exist.\n      if \"~/.iex.exs\" |> Path.expand() |> File.exists?() do\n        import_file(\"~/.iex.exs\")\n      end\n\n  This macro addresses this issue by checking if the file exists or not\n  in behalf of the user.\n  \"\"\"\n  defmacro import_file_if_available(path) when is_binary(path) do\n    import_file_if_available(path, true)\n  end\n\n  defmacro import_file_if_available(_) do\n    raise ArgumentError, \"import_file_if_available/1 expects a literal binary as its argument\"\n  end\n\n  defp import_file_if_available(path, optional?) when is_binary(path) do\n    path = Path.expand(path)\n\n    if not optional? or File.exists?(path) do\n      if imported_paths = Process.get(:iex_imported_paths) do\n        if path in imported_paths do\n          IO.warn(\"path #{path} was already imported, skipping circular file imports\", [])\n        else\n          Process.put(:iex_imported_paths, MapSet.put(imported_paths, path))\n          path |> File.read!() |> Code.string_to_quoted!(file: path)\n        end\n      else\n        path |> File.read!() |> Code.string_to_quoted!(file: path)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Injects the contents of the file at `path`.\n\n  This would be the equivalent of getting all of the file contents and\n  pasting it all at once in IEx and executing it.\n\n  By default, the contents of a `.iex.exs` file in the same directory\n  as you are starting IEx are automatically imported. See the section\n  for \".iex.exs\" in the `IEx` module docs for more information.\n\n  `path` has to be a literal string and is automatically expanded via\n  `Path.expand/1`.\n\n  ## Examples\n\n      # ~/file.exs\n      value = 13\n\n      # in the shell\n      iex(1)> import_file(\"~/file.exs\")\n      13\n      iex(2)> value\n      13\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  defmacro import_file(path) when is_binary(path) do\n    import_file_if_available(path, false)\n  end\n\n  defmacro import_file(_) do\n    raise ArgumentError, \"import_file/1 expects a literal binary as its argument\"\n  end\n\n  @doc false\n  @deprecated \"Use import_file_if_available/1 instead\"\n  defmacro import_file(path, opts) when is_binary(path) and is_list(opts) do\n    import_file_if_available(path, Keyword.get(opts, :optional, false))\n  end\n\n  @doc \"\"\"\n  Calls `import/2` with the given arguments, but only if the module is available.\n\n  This lets you put imports in `.iex.exs` files (including `~/.iex.exs`) without\n  getting compile errors if you open a console where the module is not available.\n\n  ## Example\n\n      # In ~/.iex.exs\n      import_if_available(Ecto.Query)\n\n  \"\"\"\n  defmacro import_if_available(quoted_module, opts \\\\ []) do\n    module = Macro.expand(quoted_module, __CALLER__)\n\n    if Code.ensure_loaded?(module) do\n      quote do\n        import unquote(quoted_module), unquote(opts)\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Calls `use/2` with the given arguments, but only if the module is available.\n\n  This lets you use the module in `.iex.exs` files (including `~/.iex.exs`) without\n  getting compile errors if you open a console where the module is not available.\n\n  ## Example\n\n      # In ~/.iex.exs\n      use_if_available(Phoenix.HTML)\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  defmacro use_if_available(quoted_module, opts \\\\ []) do\n    module = Macro.expand(quoted_module, __CALLER__)\n\n    if Code.ensure_loaded?(module) do\n      quote do\n        use unquote(quoted_module), unquote(opts)\n      end\n    end\n  end\n\n  defp compile_elixir(exs, :in_memory),\n    do: Kernel.ParallelCompiler.compile(exs, return_diagnostics: true)\n\n  defp compile_elixir(exs, path),\n    do: Kernel.ParallelCompiler.compile_to_path(exs, path, return_diagnostics: true)\n\n  # Compiles and loads an Erlang source file, returns {module, binary}\n  defp compile_erlang(source) do\n    source = Path.relative_to_cwd(source) |> String.to_charlist()\n\n    case :compile.file(source, [:binary, :report]) do\n      {:ok, module, binary} ->\n        :code.purge(module)\n        {:module, module} = :code.load_binary(module, source, binary)\n        {module, binary}\n\n      _ ->\n        raise CompileError\n    end\n  end\n\n  defp history, do: Process.get(:iex_history)\n\n  @doc \"\"\"\n  Creates a PID from `string` or `atom`.\n\n  ## Examples\n\n      iex> pid(\"0.21.32\")\n      #PID<0.21.32>\n\n      iex> pid(\"#PID<0.21.32>\")\n      #PID<0.21.32>\n\n      iex> pid(:init)\n      #PID<0.0.0>\n\n  \"\"\"\n  @spec pid(binary | atom) :: pid()\n  def pid(\"#PID<\" <> string) do\n    :erlang.list_to_pid(~c\"<#{string}\")\n  end\n\n  def pid(string) when is_binary(string) do\n    :erlang.list_to_pid(~c\"<#{string}>\")\n  end\n\n  def pid(name) when is_atom(name) do\n    case Process.whereis(name) do\n      p when is_pid(p) -> p\n      _ -> raise ArgumentError, \"could not find registered process with name: #{inspect(name)}\"\n    end\n  end\n\n  @doc \"\"\"\n  Creates a PID with 3 non-negative integers passed as arguments\n  to the function.\n\n  ## Examples\n\n      iex> pid(0, 21, 32)\n      #PID<0.21.32>\n      iex> pid(0, 64, 2048)\n      #PID<0.64.2048>\n\n  \"\"\"\n  @spec pid(non_neg_integer, non_neg_integer, non_neg_integer) :: pid()\n  def pid(x, y, z)\n      when is_integer(x) and x >= 0 and is_integer(y) and y >= 0 and is_integer(z) and z >= 0 do\n    :erlang.list_to_pid(\n      ~c\"<\" ++\n        Integer.to_charlist(x) ++\n        ~c\".\" ++ Integer.to_charlist(y) ++ ~c\".\" ++ Integer.to_charlist(z) ++ ~c\">\"\n    )\n  end\n\n  @doc \"\"\"\n  Creates a Port from `string`.\n\n  ## Examples\n\n      iex> port(\"0.4\")\n      #Port<0.4>\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec port(binary) :: port()\n  def port(string) when is_binary(string) do\n    :erlang.list_to_port(~c\"#Port<#{string}>\")\n  end\n\n  @doc \"\"\"\n  Creates a Port from two non-negative integers.\n\n  ## Examples\n\n      iex> port(0, 8080)\n      #Port<0.8080>\n      iex> port(0, 443)\n      #Port<0.443>\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec port(non_neg_integer, non_neg_integer) :: port()\n  def port(major, minor)\n      when is_integer(major) and major >= 0 and is_integer(minor) and minor >= 0 do\n    :erlang.list_to_port(\n      ~c\"#Port<\" ++ Integer.to_charlist(major) ++ ~c\".\" ++ Integer.to_charlist(minor) ++ ~c\">\"\n    )\n  end\n\n  @doc \"\"\"\n  Creates a Reference from `string`.\n\n  ## Examples\n\n      iex> ref(\"0.1.2.3\")\n      #Reference<0.1.2.3>\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec ref(binary) :: reference()\n  def ref(string) when is_binary(string) do\n    :erlang.list_to_ref(~c\"#Ref<#{string}>\")\n  end\n\n  @doc \"\"\"\n  Creates a Reference from its 4 non-negative integers components.\n\n  ## Examples\n\n      iex> ref(0, 1, 2, 3)\n      #Reference<0.1.2.3>\n\n  \"\"\"\n  @doc since: \"1.6.0\"\n  @spec ref(non_neg_integer, non_neg_integer, non_neg_integer, non_neg_integer) :: reference()\n  def ref(w, x, y, z)\n      when is_integer(w) and w >= 0 and is_integer(x) and x >= 0 and is_integer(y) and y >= 0 and\n             is_integer(z) and z >= 0 do\n    :erlang.list_to_ref(\n      ~c\"#Ref<\" ++\n        Integer.to_charlist(w) ++\n        ~c\".\" ++\n        Integer.to_charlist(x) ++\n        ~c\".\" ++ Integer.to_charlist(y) ++ ~c\".\" ++ Integer.to_charlist(z) ++ ~c\">\"\n    )\n  end\n\n  @doc \"\"\"\n  Deploys a given module's BEAM code to a list of nodes.\n\n  This function is useful for development and debugging when you have code that\n  has been compiled or updated locally that you want to run on other nodes.\n\n  The node list defaults to a list of all connected nodes.\n\n  Returns `{:error, :nofile}` if the object code (i.e. \".beam\" file) for the module\n  could not be found locally.\n\n  ## Examples\n\n      iex> nl(HelloWorld)\n      {:ok,\n       [\n         {:node1@easthost, :loaded, HelloWorld},\n         {:node1@westhost, :loaded, HelloWorld}\n       ]}\n\n      iex> nl(NoSuchModuleExists)\n      {:error, :nofile}\n\n  \"\"\"\n  def nl(nodes \\\\ Node.list(), module) when is_list(nodes) and is_atom(module) do\n    case get_beam_and_path(module) do\n      {bin, beam_path} ->\n        call = :erpc.multicall(nodes, :code, :load_binary, [module, beam_path, bin])\n\n        results =\n          Enum.zip_with(nodes, call, fn\n            node, {:ok, {:module, _}} -> {node, :loaded, module}\n            node, {:ok, {:error, reason}} -> {node, :error, reason}\n            node, {:error, {:erpc, reason}} -> {node, :badrpc, reason}\n          end)\n\n        {:ok, results}\n\n      _otherwise ->\n        {:error, :nofile}\n    end\n  end\n\n  defp get_beam_and_path(module) do\n    with {^module, beam, filename} <- :code.get_object_code(module),\n         info_pairs when is_list(info_pairs) <- :beam_lib.info(beam),\n         {:ok, ^module} <- Keyword.fetch(info_pairs, :module) do\n      {beam, filename}\n    else\n      _ -> :error\n    end\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/history.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.History do\n  @moduledoc false\n\n  alias IEx.History\n\n  defstruct queue: :queue.new(), size: 0, start: 1\n\n  @doc \"\"\"\n  Initializes IEx history state.\n  \"\"\"\n  def init(start), do: %History{start: start}\n\n  @doc \"\"\"\n  Appends one entry to the history.\n  \"\"\"\n  def append(%History{} = state, entry, limit) do\n    {collect?, state} =\n      state\n      |> append(entry)\n      |> prune(limit)\n\n    if collect?, do: collect_garbage()\n    state\n  end\n\n  @doc \"\"\"\n  Enumerates over all items in the history starting from the oldest one and\n  applies `fun` to each one in turn.\n  \"\"\"\n  def each(%History{} = state, fun) do\n    state\n    |> to_list()\n    |> Enum.each(fun)\n  end\n\n  @doc \"\"\"\n  Gets the nth item from the history.\n\n  If `n` < 0, the count starts from the most recent item and goes back in time.\n  \"\"\"\n  # Traverses the queue front-to-back if the index is positive.\n  def nth(%History{queue: q, size: size, start: start}, n)\n      when n - start >= 0 and n - start < size do\n    get_nth(q, n - start)\n  end\n\n  # Traverses the queue back-to-front if the index is negative.\n  def nth(%History{queue: q, size: size}, n)\n      when n < 0 and size + n >= 0 do\n    get_nth(:queue.reverse(q), abs(n) - 1)\n  end\n\n  def nth(%History{size: 0}, n) do\n    raise \"v(#{n}) is out of bounds, no entries were stored in history so far\"\n  end\n\n  def nth(%History{size: size, start: start}, n) do\n    raise \"v(#{n}) is out of bounds, the currently preserved history ranges from #{start} to #{start + size - 1} \" <>\n            \"(or use negative numbers to look from the end)\"\n  end\n\n  defp get_nth(q, 0), do: :queue.head(q)\n  defp get_nth(q, n) when n > 0, do: get_nth(:queue.tail(q), n - 1)\n\n  defp append(%{queue: q, size: size} = state, item) do\n    %{state | queue: :queue.in(item, q), size: size + 1}\n  end\n\n  defp to_list(%{queue: q}), do: :queue.to_list(q)\n\n  # Based on https://github.com/erlang/otp/blob/7dcccee4371477e983f026db9e243cb66900b1ef/lib/stdlib/src/shell.erl#L1401\n  defp collect_garbage() do\n    collect_proc_garbage(Process.whereis(:user))\n    collect_proc_garbage(Process.group_leader())\n    :erlang.garbage_collect()\n  end\n\n  defp collect_proc_garbage(process) do\n    try do\n      :erlang.garbage_collect(process)\n    catch\n      _, _ -> nil\n    end\n  end\n\n  defp prune(%{start: start} = state, limit) do\n    prune(state, start, limit, false)\n  end\n\n  defp prune(state, _, limit, _) when limit < 0 do\n    {false, state}\n  end\n\n  defp prune(%{size: size} = state, counter, limit, collect?) when size <= limit do\n    {collect?, %{state | start: counter}}\n  end\n\n  defp prune(%{queue: q, size: size} = state, counter, limit, collect?) do\n    {{:value, entry}, q} = :queue.out(q)\n    collect? = collect? || has_binary(entry)\n    prune(%{state | queue: q, size: size - 1}, counter + 1, limit, collect?)\n  end\n\n  # Checks val and each of its elements (if it is a list or a tuple)\n  # recursively to see if it has any large binaries (outside of the heap).\n  defp has_binary(val) do\n    try do\n      has_bin(val)\n    catch\n      :throw, :found -> true\n    end\n  end\n\n  defp has_bin(val) when is_tuple(val), do: has_bin(val, tuple_size(val) - 1)\n\n  defp has_bin([head | tail]) do\n    has_bin(head)\n    has_bin(tail)\n  end\n\n  defp has_bin(val) when byte_size(val) > 64, do: throw(:found)\n\n  defp has_bin(_), do: false\n\n  defp has_bin(_, -1), do: false\n\n  defp has_bin(tuple, index) do\n    has_bin(elem(tuple, index))\n    has_bin(tuple, index - 1)\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/info.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefprotocol IEx.Info do\n  @fallback_to_any true\n\n  @moduledoc \"\"\"\n  A protocol to print information in IEx about the given data structure.\n\n  `IEx.Helpers.i/1` uses this protocol to display a term-specific list\n  of information.\n\n  By default, an `Any` implementation will be used which returns\n  the `\"Data type\"`, `\"Description\"` and `\"Reference modules\"` sections.\n  \"\"\"\n\n  @doc \"\"\"\n  Returns information for the given term.\n\n  Information should be returned as a list of `info_name`-`info` tuples,\n  where `info_name` is a string-like value, such as an atom or a string\n  itself, and `info` is a string. `info_name` should be short. `info` can\n  be arbitrarily long and contain newlines.\n\n  `IEx.Helpers.i/1` will generate (and always display)\n  the 'Implemented protocols' and 'Term' sections in the result.\n\n  All other sections of information are added (and can be overridden)\n  by customized implementations of this function.\n\n  It is recommended to at least include the following sections for a\n  custom implementation:\n\n    * `\"Data type\"`: Name of the data type. Usually the name of the module\n       defining the data type.\n    * `\"Description\"`: One or a few sentences describing what the data type represents.\n    * `\"Reference modules\"`: One or a few comma-separated module names that focus\n      on working with this datatype.\n\n  Other recommended sections are:\n\n    * `\"Raw representation\"`: showing another way of writing the passed `term`.\n      This is mostly relevant for data-structures whose `String.Chars`-implementations\n      make use of sigils or other syntactic sugar.\n  \"\"\"\n  @spec info(term()) :: [{info_name :: String.Chars.t(), info :: String.t()}]\n  def info(term)\nend\n\ndefimpl IEx.Info, for: Tuple do\n  def info(_tuple) do\n    [\n      {\"Data type\", \"Tuple\"},\n      {\"Reference modules\", \"Tuple\"}\n    ]\n  end\nend\n\ndefimpl IEx.Info, for: Atom do\n  def info(atom) do\n    specific_info =\n      cond do\n        module?(atom) ->\n          info_module(atom)\n\n        match?(\"Elixir.\" <> _, Atom.to_string(atom)) ->\n          info_module_like_atom(atom)\n\n        true ->\n          info_atom(atom)\n      end\n\n    description =\n      if atom == IEx.dont_display_result() do\n        description = \"\"\"\n        This atom is returned by IEx when a function that should not print its\n        return value on screen is executed.\n        \"\"\"\n\n        [{\"Description\", description}]\n      else\n        []\n      end\n\n    [{\"Data type\", \"Atom\"}] ++ description ++ specific_info\n  end\n\n  defp module?(atom) do\n    case :code.get_object_code(atom) do\n      :error ->\n        Code.ensure_loaded?(atom)\n\n      {^atom, beam, _path} ->\n        info = :beam_lib.info(beam)\n        is_list(info) and Keyword.fetch(info, :module) == {:ok, atom}\n    end\n  end\n\n  defp info_module(mod) do\n    extra =\n      case Code.fetch_docs(mod) do\n        {:docs_v1, _, _, _, %{}, _, _} -> \"Use h(#{inspect(mod)}) to access its documentation.\\n\"\n        _ -> \"\"\n      end\n\n    mod_info = mod.module_info()\n\n    generic_info = [\n      {\"Module bytecode\", module_object_file(mod)},\n      {\"Source\", module_source_file(mod_info)},\n      {\"Version\", module_version(mod_info)},\n      {\"Compile options\", module_compile_options(mod_info)},\n      {\"Description\", \"#{extra}Call #{inspect(mod)}.module_info() to access metadata.\"}\n    ]\n\n    final_info = [\n      {\"Raw representation\", \":\" <> inspect(Atom.to_string(mod))},\n      {\"Reference modules\", \"Module, Atom\"}\n    ]\n\n    generic_info ++ protocol_info(mod) ++ final_info\n  end\n\n  defp protocol_info(mod) do\n    if function_exported?(mod, :__protocol__, 1) do\n      impls =\n        mod\n        |> Protocol.extract_impls(:code.get_path())\n        |> Enum.map_join(\", \", &inspect/1)\n\n      [{\"Protocol\", \"This module is a protocol. These data structures implement it:\\n  #{impls}\"}]\n    else\n      []\n    end\n  end\n\n  defp info_module_like_atom(atom) do\n    [\n      {\"Raw representation\", \":\" <> inspect(Atom.to_string(atom))},\n      {\"Reference modules\", \"Atom\"}\n    ]\n  end\n\n  defp info_atom(_atom) do\n    [{\"Reference modules\", \"Atom\"}]\n  end\n\n  defp module_object_file(mod) do\n    default_or_apply(:code.which(mod), fn\n      [_ | _] = path -> Path.relative_to_cwd(path)\n      atom -> inspect(atom)\n    end)\n  end\n\n  defp module_version(mod_info) do\n    default_or_apply(mod_info[:attributes][:vsn], &inspect/1)\n  end\n\n  defp module_source_file(mod_info) do\n    default_or_apply(mod_info[:compile][:source], &Path.relative_to_cwd/1)\n  end\n\n  defp module_compile_options(mod_info) do\n    default_or_apply(mod_info[:compile][:options], &inspect/1)\n  end\n\n  defp default_or_apply(nil, _), do: \"no value found\"\n  defp default_or_apply(data, fun), do: fun.(data)\nend\n\ndefimpl IEx.Info, for: List do\n  def info(list) do\n    specific_info =\n      cond do\n        list == [] -> info_list(list)\n        List.ascii_printable?(list) -> info_printable_charlist(list)\n        Keyword.keyword?(list) -> info_kw_list(list)\n        List.improper?(list) -> info_improper_list(list)\n        true -> info_list(list)\n      end\n\n    [{\"Data type\", \"List\"}] ++ specific_info\n  end\n\n  defp info_printable_charlist(charlist) do\n    description = \"\"\"\n    This is a list of integers that is printed using the `~c` sigil syntax,\n    defined by the `Kernel.sigil_c/2` macro, because all the integers in it\n    represent printable ASCII characters. Conventionally, a list of Unicode\n    code points is known as a charlist and a list of ASCII characters is a\n    subset of it.\n    \"\"\"\n\n    [\n      {\"Description\", description},\n      {\"Raw representation\", inspect(charlist, charlists: :as_lists)},\n      {\"Reference modules\", \"List\"}\n    ]\n  end\n\n  defp info_kw_list(_kw_list) do\n    description = \"\"\"\n    This is what is referred to as a \"keyword list\". A keyword list is a list\n    of two-element tuples where the first element of each tuple is an atom.\n    \"\"\"\n\n    [{\"Description\", description}, {\"Reference modules\", \"Keyword, List\"}]\n  end\n\n  defp info_improper_list(_improper_list) do\n    description = \"\"\"\n    This is what is referred to as an \"improper list\". An improper list is a\n    list whose last tail is not an empty list. For example: [1, 2, 3] is a\n    proper list, as it is equivalent to [1, 2, 3 | []], as opposed to\n    [1, 2 | 3] which is an improper list since its last tail is 3.\n    \"\"\"\n\n    [\n      {\"Description\", description},\n      {\"Reference modules\", \"List\"}\n    ]\n  end\n\n  defp info_list(_list) do\n    [{\"Reference modules\", \"List\"}]\n  end\nend\n\ndefimpl IEx.Info, for: BitString do\n  def info(bitstring) do\n    specific_info =\n      cond do\n        is_binary(bitstring) and String.printable?(bitstring) -> info_string(bitstring)\n        is_binary(bitstring) and String.valid?(bitstring) -> info_non_printable_string(bitstring)\n        is_binary(bitstring) -> info_binary(bitstring)\n        is_bitstring(bitstring) -> info_bitstring(bitstring)\n      end\n\n    [{\"Data type\", \"BitString\"}] ++ specific_info\n  end\n\n  defp info_string(bitstring) do\n    description = \"\"\"\n    This is a string: a UTF-8 encoded binary. It's printed surrounded by\n    \"double quotes\" because all UTF-8 encoded code points in it are printable.\n    \"\"\"\n\n    [\n      {\"Byte size\", byte_size(bitstring)},\n      {\"Description\", description},\n      {\"Raw representation\", inspect(bitstring, binaries: :as_binaries)},\n      {\"Reference modules\", \"String, :binary\"}\n    ]\n  end\n\n  defp info_non_printable_string(bitstring) do\n    first_non_printable = find_first_codepoint(bitstring, &(not String.printable?(&1)))\n\n    desc = \"\"\"\n    This is a string: a UTF-8 encoded binary. It's printed with the `<<>>`\n    syntax (as opposed to double quotes) because it contains non-printable\n    UTF-8 encoded code points (the first non-printable code point being\n    `#{inspect(first_non_printable)}`).\n    \"\"\"\n\n    [\n      {\"Byte size\", byte_size(bitstring)},\n      {\"Description\", desc},\n      {\"Reference modules\", \"String, :binary\"}\n    ]\n  end\n\n  defp info_binary(bitstring) do\n    first_non_valid = find_first_codepoint(bitstring, &(not String.valid?(&1)))\n\n    description = \"\"\"\n    This is a binary: a collection of bytes. It's printed with the `<<>>`\n    syntax (as opposed to double quotes) because it is not a UTF-8 encoded\n    binary (the first invalid byte being `#{inspect(first_non_valid)}`)\n    \"\"\"\n\n    [\n      {\"Byte size\", byte_size(bitstring)},\n      {\"Description\", description},\n      {\"Reference modules\", \":binary\"}\n    ]\n  end\n\n  defp info_bitstring(bitstring) do\n    description = \"\"\"\n    This is a bitstring. It's a chunk of bits that are not divisible by 8\n    (the number of bytes isn't whole).\n    \"\"\"\n\n    [{\"Bits size\", bit_size(bitstring)}, {\"Description\", description}]\n  end\n\n  defp find_first_codepoint(binary, fun) do\n    binary\n    |> String.codepoints()\n    |> Enum.find(fun)\n  end\nend\n\ndefimpl IEx.Info, for: Integer do\n  def info(_integer) do\n    [{\"Data type\", \"Integer\"}, {\"Reference modules\", \"Integer\"}]\n  end\nend\n\ndefimpl IEx.Info, for: Float do\n  def info(_float) do\n    [{\"Data type\", \"Float\"}, {\"Reference modules\", \"Float\"}]\n  end\nend\n\ndefimpl IEx.Info, for: Function do\n  def info(fun) do\n    fun_info = Function.info(fun)\n\n    specific_info =\n      if fun_info[:type] == :external and fun_info[:env] == [] do\n        info_named_fun(fun_info)\n      else\n        info_anon_fun(fun_info)\n      end\n\n    [{\"Data type\", \"Function\"}] ++ specific_info\n  end\n\n  defp info_anon_fun(fun_info) do\n    [\n      {\"Type\", to_string(fun_info[:type])},\n      {\"Arity\", fun_info[:arity]},\n      {\"Description\", \"This is an anonymous function.\"}\n    ]\n  end\n\n  defp info_named_fun(fun_info) do\n    [\n      {\"Type\", to_string(fun_info[:type])},\n      {\"Arity\", fun_info[:arity]}\n    ]\n  end\nend\n\ndefimpl IEx.Info, for: PID do\n  @keys [:registered_name, :links, :message_queue_len]\n\n  def info(pid) do\n    extra_info =\n      try do\n        :erpc.call(node(pid), :erlang, :process_info, [pid, @keys])\n      catch\n        _, _ -> [{\"Alive\", false}]\n      else\n        [_ | _] = info ->\n          [\n            {\"Alive\", true},\n            {\"Name\", process_name(info[:registered_name])},\n            {\"Links\", links(info[:links])},\n            {\"Message queue length\", info[:message_queue_len]}\n          ]\n\n        _ ->\n          [{\"Alive\", false}]\n      end\n\n    final_info = [\n      {\"Description\", \"Use Process.info/1 to get more info about this process\"},\n      {\"Reference modules\", \"Process, Node\"}\n    ]\n\n    [{\"Data type\", \"PID\"}] ++ extra_info ++ final_info\n  end\n\n  defp process_name([]), do: \"not registered\"\n  defp process_name(name), do: inspect(name)\n\n  defp links([]), do: \"none\"\n  defp links(links), do: Enum.map_join(links, \", \", &inspect/1)\nend\n\ndefimpl IEx.Info, for: Map do\n  def info(_map) do\n    [{\"Data type\", \"Map\"}, {\"Reference modules\", \"Map\"}]\n  end\nend\n\ndefimpl IEx.Info, for: Port do\n  def info(port) do\n    open? =\n      try do\n        :erpc.call(node(port), :erlang, :port_info, [port, :connected])\n      catch\n        _, _ -> false\n      else\n        {:connected, _} -> true\n        _ -> false\n      end\n\n    [\n      {\"Data type\", \"Port\"},\n      {\"Open\", open?},\n      {\"Reference modules\", \"Port\"}\n    ]\n  end\nend\n\ndefimpl IEx.Info, for: Reference do\n  def info(_ref) do\n    [{\"Data type\", \"Reference\"}]\n  end\nend\n\ndefimpl IEx.Info, for: [Date, Time, DateTime, NaiveDateTime, Regex] do\n  naive_datetime_repr = ~S{\"naive\" datetime (that is, a datetime without a time zone)}\n\n  {sigil, repr, modules} =\n    case @for do\n      Date -> {\"D\", \"date\", [Calendar, Map]}\n      Time -> {\"T\", \"time\", [Calendar, Map]}\n      DateTime -> {\"U\", \"datetime\", [Calendar, Map]}\n      NaiveDateTime -> {\"N\", naive_datetime_repr, [Calendar, Map]}\n      Regex -> {\"r\", \"regular expression\", [:re]}\n    end\n\n  def info(value) do\n    description = \"\"\"\n    This is a struct representing a #{unquote(repr)}. It is commonly\n    represented using the `~#{unquote(sigil)}` sigil syntax, that is\n    defined in the `Kernel.sigil_#{unquote(sigil)}/2` macro.\n    \"\"\"\n\n    [\n      {\"Data type\", inspect(@for)},\n      {\"Description\", description},\n      {\"Raw representation\", raw_inspect(value)},\n      {\"Reference modules\", unquote(Enum.map_join([@for | modules], \", \", &inspect/1))}\n    ]\n  end\n\n  defp raw_inspect(value) do\n    value\n    |> Inspect.Any.inspect(%Inspect.Opts{})\n    |> case do\n      {doc, %Inspect.Opts{}} -> doc\n      doc -> doc\n    end\n    |> Inspect.Algebra.format(:infinity)\n    |> IO.iodata_to_binary()\n  end\nend\n\ndefimpl IEx.Info, for: Range do\n  def info(value) do\n    description = \"\"\"\n    This is a struct representing a range of numbers. It is commonly\n    defined using the `first..last//step` syntax. The step is not\n    required and defaults to `1`.\n    \"\"\"\n\n    [\n      {\"Data type\", inspect(@for)},\n      {\"Description\", description},\n      {\"Raw representation\", raw_inspect(value)},\n      {\"Reference modules\", inspect(@for)}\n    ]\n  end\n\n  defp raw_inspect(value) do\n    value\n    |> Inspect.Any.inspect(%Inspect.Opts{})\n    |> case do\n      {doc, %Inspect.Opts{}} -> doc\n      doc -> doc\n    end\n    |> Inspect.Algebra.format(:infinity)\n    |> IO.iodata_to_binary()\n  end\nend\n\ndefimpl IEx.Info, for: Any do\n  def info(%module{}) do\n    [\n      {\"Data type\", inspect(module)},\n      {\"Description\", \"This is a struct. Structs are maps with a __struct__ key.\"},\n      {\"Reference modules\", inspect(module) <> \", Map\"}\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/introspection.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Convenience helpers for showing docs, specs, types\n# and opening modules. Invoked directly from IEx.Helpers.\ndefmodule IEx.Introspection do\n  @moduledoc false\n\n  import IEx, only: [dont_display_result: 0]\n\n  alias Code.Typespec\n\n  @doc \"\"\"\n  Decomposes an introspection call into `{mod, fun, arity}`,\n  `{mod, fun}` or `mod`.\n  \"\"\"\n  def decompose(atom, _context) when is_atom(atom), do: atom\n\n  def decompose({:__aliases__, _, _} = module, context) do\n    Macro.expand(module, context)\n  end\n\n  def decompose({:/, _, [call, arity]}, context) do\n    case Macro.decompose_call(call) do\n      {_mod, :__info__, []} when arity == 1 ->\n        {Module, :__info__, 1}\n\n      {mod, fun, []} ->\n        {Macro.expand(mod, context), fun, arity}\n\n      {fun, []} ->\n        {find_decompose_fun_arity(fun, arity, context), fun, arity}\n\n      _ ->\n        :error\n    end\n  end\n\n  def decompose(call, context) do\n    case Macro.decompose_call(call) do\n      {_mod, :__info__, []} ->\n        {Module, :__info__, 1}\n\n      {maybe_sigil, [_, _]} ->\n        case Atom.to_string(maybe_sigil) do\n          \"sigil_\" <> _ ->\n            {find_decompose_fun_arity(maybe_sigil, 2, context), maybe_sigil, 2}\n\n          _ ->\n            :error\n        end\n\n      {mod, fun, []} ->\n        {Macro.expand(mod, context), fun}\n\n      {fun, []} ->\n        {find_decompose_fun(fun, context), fun}\n\n      _ ->\n        :error\n    end\n  end\n\n  defp find_decompose_fun(fun, context) do\n    find_import(fun, context.functions) || find_import(fun, context.macros) ||\n      find_special_form(fun) || Kernel\n  end\n\n  defp find_decompose_fun_arity(fun, arity, context) do\n    pair = {fun, arity}\n\n    find_import(pair, context.functions) || find_import(pair, context.macros) ||\n      find_special_form(pair) || Kernel\n  end\n\n  defp find_import(pair, context) when is_tuple(pair) do\n    Enum.find_value(context, fn {mod, functions} ->\n      if pair in functions, do: mod\n    end)\n  end\n\n  defp find_import(fun, context) do\n    Enum.find_value(context, fn {mod, functions} ->\n      if Keyword.has_key?(functions, fun), do: mod\n    end)\n  end\n\n  defp find_special_form(pair) when is_tuple(pair) do\n    special_form_function? = pair in Kernel.SpecialForms.__info__(:functions)\n    special_form_macro? = pair in Kernel.SpecialForms.__info__(:macros)\n\n    if special_form_function? or special_form_macro?, do: Kernel.SpecialForms\n  end\n\n  defp find_special_form(fun) do\n    special_form_function? = Keyword.has_key?(Kernel.SpecialForms.__info__(:functions), fun)\n    special_form_macro? = Keyword.has_key?(Kernel.SpecialForms.__info__(:macros), fun)\n\n    if special_form_function? or special_form_macro?, do: Kernel.SpecialForms\n  end\n\n  @doc \"\"\"\n  Opens the given module, mfa, file/line, binary.\n  \"\"\"\n  def open(module) when is_atom(module) do\n    case open_mfa(module, :__info__, 1) do\n      {source, nil, _} -> open(source)\n      {_, tuple, _} -> open(tuple)\n      {:error, reason} -> puts_error(\"Could not open #{inspect(module)}, #{reason}\")\n    end\n\n    dont_display_result()\n  end\n\n  def open({module, function}) when is_atom(module) and is_atom(function) do\n    case open_mfa(module, function, :*) do\n      {_, _, nil} ->\n        puts_error(\n          \"Could not open #{inspect(module)}.#{function}, function/macro is not available\"\n        )\n\n      {_, _, tuple} ->\n        open(tuple)\n\n      {:error, reason} ->\n        puts_error(\"Could not open #{inspect(module)}.#{function}, #{reason}\")\n    end\n\n    dont_display_result()\n  end\n\n  def open({module, function, arity})\n      when is_atom(module) and is_atom(function) and is_integer(arity) do\n    case open_mfa(module, function, arity) do\n      {_, _, nil} ->\n        puts_error(\n          \"Could not open #{inspect(module)}.#{function}/#{arity}, function/macro is not available\"\n        )\n\n      {_, _, tuple} ->\n        open(tuple)\n\n      {:error, reason} ->\n        puts_error(\"Could not open #{inspect(module)}.#{function}/#{arity}, #{reason}\")\n    end\n\n    dont_display_result()\n  end\n\n  def open({file, line}) when is_binary(file) and is_integer(line) do\n    cond do\n      not File.regular?(file) ->\n        puts_error(\"Could not open #{inspect(file)}, file is not available.\")\n\n      editor = System.get_env(\"ELIXIR_EDITOR\") || System.get_env(\"EDITOR\") ->\n        command =\n          if editor =~ \"__FILE__\" or editor =~ \"__LINE__\" do\n            editor\n            |> String.replace(\"__FILE__\", inspect(file))\n            |> String.replace(\"__LINE__\", Integer.to_string(line))\n          else\n            \"#{editor} #{inspect(file)}:#{line}\"\n          end\n\n        IO.write(IEx.color(:eval_info, :os.cmd(String.to_charlist(command))))\n\n      true ->\n        puts_error(\n          \"Could not open: #{inspect(file)}. \" <>\n            \"Please set the ELIXIR_EDITOR or EDITOR environment variables with the \" <>\n            \"command line invocation of your favorite EDITOR.\"\n        )\n    end\n\n    dont_display_result()\n  end\n\n  def open(invalid) do\n    puts_error(\"Invalid arguments for open helper: #{inspect(invalid)}\")\n    dont_display_result()\n  end\n\n  defp open_mfa(module, fun, arity) do\n    case Code.ensure_loaded(module) do\n      {:module, _} ->\n        case module.module_info(:compile)[:source] do\n          [_ | _] = source ->\n            source = rewrite_source(module, source)\n            open_abstract_code(module, fun, arity, source)\n\n          _ ->\n            {:error, \"source code is not available\"}\n        end\n\n      _ ->\n        {:error, \"module is not available\"}\n    end\n  end\n\n  defp open_abstract_code(module, fun, arity, source) do\n    fun = Atom.to_string(fun)\n\n    with [_ | _] = beam <- :code.which(module),\n         {:ok, {_, [abstract_code: abstract_code]}} <- :beam_lib.chunks(beam, [:abstract_code]),\n         {:raw_abstract_v1, code} <- abstract_code do\n      {_, module_pair, fa_pair} =\n        Enum.reduce(code, {source, nil, nil}, &open_abstract_code_reduce(&1, &2, fun, arity))\n\n      {source, module_pair, fa_pair}\n    else\n      _ ->\n        {source, nil, nil}\n    end\n  end\n\n  defp open_abstract_code_reduce(entry, {file, module_pair, fa_pair}, fun, arity) do\n    case entry do\n      {:attribute, ann, :module, _} ->\n        {file, {file, :erl_anno.line(ann)}, fa_pair}\n\n      {:function, ann, ann_fun, ann_arity, _} ->\n        case Atom.to_string(ann_fun) do\n          \"MACRO-\" <> ^fun when arity == :* or ann_arity == arity + 1 ->\n            {file, module_pair, fa_pair || {file, :erl_anno.line(ann)}}\n\n          ^fun when arity == :* or ann_arity == arity ->\n            {file, module_pair, fa_pair || {file, :erl_anno.line(ann)}}\n\n          _ ->\n            {file, module_pair, fa_pair}\n        end\n\n      _ ->\n        {file, module_pair, fa_pair}\n    end\n  end\n\n  @elixir_apps ~w(eex elixir ex_unit iex logger mix)a\n  @otp_apps ~w(kernel stdlib)a\n  @apps @elixir_apps ++ @otp_apps\n\n  defp rewrite_source(module, source) do\n    case :application.get_application(module) do\n      {:ok, app} when app in @apps ->\n        Application.app_dir(app, rewrite_source(source))\n\n      _ ->\n        beam_path = :code.which(module)\n\n        if is_list(beam_path) and List.starts_with?(beam_path, :code.root_dir()) do\n          app_vsn = beam_path |> Path.dirname() |> Path.dirname() |> Path.basename()\n          Path.join([:code.root_dir(), \"lib\", app_vsn, rewrite_source(source)])\n        else\n          List.to_string(source)\n        end\n    end\n  end\n\n  defp rewrite_source(source) do\n    {in_app, [lib_or_src | _]} =\n      source\n      |> Path.split()\n      |> Enum.reverse()\n      |> Enum.split_while(&(&1 not in [\"lib\", \"src\"]))\n\n    Path.join([lib_or_src | Enum.reverse(in_app)])\n  end\n\n  @doc \"\"\"\n  Prints documentation.\n  \"\"\"\n  def h(module) when is_atom(module) do\n    case Code.ensure_loaded(module) do\n      {:module, _} ->\n        case Code.fetch_docs(module) do\n          {:docs_v1, _, _, format, doc, metadata, _} when is_map(doc) or doc == :none ->\n            print_doc([inspect(module)], [], format, doc, metadata)\n\n          {:docs_v1, _, _, _, _, _, _} ->\n            docs_not_found(inspect(module))\n\n          _ ->\n            no_docs(module)\n        end\n\n      {:error, reason} ->\n        puts_error(\"Could not load module #{inspect(module)}, got: #{reason}\")\n    end\n\n    dont_display_result()\n  end\n\n  def h({module, function}) when is_atom(module) and is_atom(function) do\n    case Code.ensure_loaded(module) do\n      {:module, _} ->\n        {_language, _format, docs} = get_docs(module, [:function, :macro])\n\n        exports =\n          cond do\n            docs ->\n              Enum.map(docs, &extract_name_and_arity/1)\n\n            function_exported?(module, :__info__, 1) ->\n              module.__info__(:functions) ++ module.__info__(:macros)\n\n            true ->\n              module.module_info(:exports)\n          end\n          |> Enum.sort()\n          |> Enum.dedup()\n\n        result =\n          for {^function, arity} <- exports,\n              (if docs do\n                 find_doc_with_content(docs, function, arity)\n               else\n                 get_spec(module, function, arity) != []\n               end) do\n            h_mod_fun_arity(module, function, arity)\n          end\n\n        cond do\n          result != [] ->\n            :ok\n\n          docs && has_callback?(module, function) ->\n            behaviour_found(\"#{inspect(module)}.#{function}\")\n\n          docs && has_type?(module, function) ->\n            type_found(\"#{inspect(module)}.#{function}\")\n\n          is_nil(docs) ->\n            no_docs(module)\n\n          true ->\n            docs_not_found(\"#{inspect(module)}.#{function}\")\n        end\n\n      {:error, reason} ->\n        puts_error(\"Could not load module #{inspect(module)}, got: #{reason}\")\n    end\n\n    dont_display_result()\n  end\n\n  def h({module, function, arity})\n      when is_atom(module) and is_atom(function) and is_integer(arity) do\n    case Code.ensure_loaded(module) do\n      {:module, _} ->\n        case h_mod_fun_arity(module, function, arity) do\n          :ok ->\n            :ok\n\n          :behaviour_found ->\n            behaviour_found(\"#{inspect(module)}.#{function}/#{arity}\")\n\n          :type_found ->\n            type_found(\"#{inspect(module)}.#{function}/#{arity}\")\n\n          :no_docs ->\n            no_docs(module)\n\n          :not_found ->\n            docs_not_found(\"#{inspect(module)}.#{function}/#{arity}\")\n        end\n\n      {:error, reason} ->\n        puts_error(\"Could not load module #{inspect(module)}, got: #{reason}\")\n    end\n\n    dont_display_result()\n  end\n\n  def h(invalid) do\n    puts_error(\n      \"The \\\"h\\\" helper expects a Module, Module.fun or Module.fun/arity, got: #{inspect(invalid)}\"\n    )\n\n    puts_error(\n      \"If instead of accessing documentation you would like more information about a value \" <>\n        \"or about the result of an expression, use the \\\"i\\\" helper instead\"\n    )\n\n    dont_display_result()\n  end\n\n  defp h_mod_fun_arity(mod, fun, arity) when is_atom(mod) do\n    {language, format, docs} = get_docs(mod, [:function, :macro])\n    spec = get_spec(mod, fun, arity)\n\n    cond do\n      doc_tuple = find_doc_with_content(docs, fun, arity) ->\n        print_fun(mod, language, format, doc_tuple, spec)\n        :ok\n\n      docs && has_callback?(mod, fun, arity) ->\n        :behaviour_found\n\n      docs && has_type?(mod, fun, arity) ->\n        :type_found\n\n      is_nil(docs) and spec != [] ->\n        en = \"Module was compiled without docs. Showing only specs.\"\n        formatted = Exception.format_mfa(mod, fun, arity)\n        print_doc([formatted], spec, \"text/markdown\", %{\"en\" => en}, %{})\n        :ok\n\n      is_nil(docs) ->\n        :no_docs\n\n      true ->\n        :not_found\n    end\n  end\n\n  defp has_callback?(mod, fun) do\n    match?([_ | _], get_callback_docs(mod, &match?({_, ^fun, _}, elem(&1, 0))))\n  end\n\n  defp has_callback?(mod, fun, arity) do\n    match?([_ | _], get_callback_docs(mod, &match?({_, ^fun, ^arity}, elem(&1, 0))))\n  end\n\n  defp has_type?(mod, fun) do\n    {_, _, docs} = get_docs(mod, [:type])\n    Enum.any?(docs, &match?({_, ^fun, _}, elem(&1, 0)))\n  end\n\n  defp has_type?(mod, fun, arity) do\n    {_, _, docs} = get_docs(mod, [:type])\n    Enum.any?(docs, &match?({_, ^fun, ^arity}, elem(&1, 0)))\n  end\n\n  defp get_docs(mod, kinds) do\n    case Code.fetch_docs(mod) do\n      {:docs_v1, _, language, format, _, _, docs} ->\n        docs = for {{kind, _, _}, _, _, _, _} = doc <- docs, kind in kinds, do: doc\n        {language, format, docs}\n\n      {:error, _} ->\n        {nil, nil, nil}\n    end\n  end\n\n  defp extract_name_and_arity({{_, name, arity}, _, _, _, _}), do: {name, arity}\n\n  defp find_doc_with_content(docs, function, arity) do\n    case find_doc(docs, function, arity) do\n      {_, _, _, :hidden, _} -> nil\n      {_, _, _, _, _} = doc -> doc\n      _ -> nil\n    end\n  end\n\n  defp find_doc(nil, _fun, _arity) do\n    nil\n  end\n\n  defp find_doc(docs, fun, arity) do\n    Enum.find(docs, &match?({_, ^fun, ^arity}, elem(&1, 0))) ||\n      find_doc_defaults(docs, fun, arity)\n  end\n\n  defp find_doc_defaults(docs, function, min) do\n    Enum.find(docs, fn\n      {{_, ^function, arity}, _, _, _, %{defaults: defaults}} when arity > min ->\n        arity <= min + defaults\n\n      _ ->\n        false\n    end)\n  end\n\n  defp print_fun(\n         mod,\n         language,\n         format,\n         {{kind, fun, arity}, _line, signature, doc, metadata},\n         spec\n       ) do\n    callback_module = doc == :none and callback_module(mod, fun, arity)\n\n    if callback_module do\n      filter = &match?({_, ^fun, ^arity}, elem(&1, 0))\n\n      case get_callback_docs(callback_module, filter) do\n        :no_beam ->\n          nil\n\n        callback_docs ->\n          en =\n            \"#{Exception.format_mfa(mod, fun, arity)} has no docs but is a callback for behaviour \" <>\n              \"#{inspect(callback_module)}. Showing callback docs instead.\"\n\n          format_signature(language, kind, signature)\n          |> print_doc(spec, format, %{\"en\" => en}, metadata)\n\n          Enum.each(callback_docs, &print_typespec/1)\n      end\n    else\n      print_doc(format_signature(language, kind, signature), spec, format, doc, metadata)\n    end\n  end\n\n  defp format_signature(:elixir, :function, signature), do: Enum.map(signature, &(\"def \" <> &1))\n  defp format_signature(:elixir, :macro, signature), do: Enum.map(signature, &(\"defmacro \" <> &1))\n  defp format_signature(_, _, signature), do: signature\n\n  defp callback_module(mod, fun, arity) do\n    mod.module_info(:attributes)\n    |> Keyword.get_values(:behaviour)\n    |> Stream.concat()\n    |> Enum.find(&has_callback?(&1, fun, arity))\n  end\n\n  defp get_spec(module, name, arity) do\n    with {:ok, all_specs} <- Typespec.fetch_specs(module),\n         {_, specs} <- List.keyfind(all_specs, {name, arity}, 0) do\n      formatted =\n        Enum.map(specs, fn spec ->\n          Typespec.spec_to_quoted(name, spec)\n          |> format_typespec(:spec, 2)\n        end)\n\n      [formatted, ?\\n]\n    else\n      _ -> []\n    end\n  end\n\n  @doc \"\"\"\n  Prints the list of behaviour callbacks or a given callback.\n  \"\"\"\n  def b(mod) when is_atom(mod) do\n    case get_callback_docs(mod, fn _ -> true end) do\n      :no_beam ->\n        no_beam(mod)\n\n      [] ->\n        puts_error(\"No callbacks for #{inspect(mod)} were found\")\n\n      docs ->\n        docs\n        |> add_optional_callback_docs(mod)\n        |> Enum.each(fn {_, definition, _, _} -> IO.puts(definition) end)\n    end\n\n    dont_display_result()\n  end\n\n  def b({mod, fun}) when is_atom(mod) and is_atom(fun) do\n    filter = &match?({_, ^fun, _}, elem(&1, 0))\n\n    case get_callback_docs(mod, filter) do\n      :no_beam -> no_beam(mod)\n      [] -> docs_not_found(\"#{inspect(mod)}.#{fun}\")\n      docs -> Enum.each(docs, &print_typespec/1)\n    end\n\n    dont_display_result()\n  end\n\n  def b({mod, fun, arity}) when is_atom(mod) and is_atom(fun) and is_integer(arity) do\n    filter = &match?({_, ^fun, ^arity}, elem(&1, 0))\n\n    case get_callback_docs(mod, filter) do\n      :no_beam -> no_beam(mod)\n      [] -> docs_not_found(\"#{inspect(mod)}.#{fun}/#{arity}\")\n      docs -> Enum.each(docs, &print_typespec/1)\n    end\n\n    dont_display_result()\n  end\n\n  def b(invalid) do\n    puts_error(\"Invalid arguments for b helper: #{inspect(invalid)}\")\n    dont_display_result()\n  end\n\n  defp get_callback_docs(mod, filter) do\n    {_, format, docs} = get_docs(mod, [:callback, :macrocallback])\n\n    case Typespec.fetch_callbacks(mod) do\n      :error ->\n        :no_beam\n\n      {:ok, callbacks} ->\n        callbacks\n        |> Enum.map(&translate_callback/1)\n        |> Enum.filter(filter)\n        |> Enum.sort()\n        |> Enum.flat_map(fn {{_, function, arity}, _specs} = callback ->\n          case find_doc(docs, function, arity) do\n            nil -> [{format, format_callback(callback), :none, %{}}]\n            {_, _, _, :hidden, _} -> []\n            {_, _, _, doc, metadata} -> [{format, format_callback(callback), doc, metadata}]\n          end\n        end)\n    end\n  end\n\n  defp translate_callback({name_arity, specs}) do\n    case translate_callback_name_arity(name_arity) do\n      {:macrocallback, _, _} = kind_name_arity ->\n        # The typespec of a macrocallback differs from the one expressed\n        # via @macrocallback:\n        #\n        #   * The function name is prefixed with \"MACRO-\"\n        #   * The arguments contain an additional first argument: the caller\n        #   * The arity is increased by 1\n        #\n        specs = Enum.map(specs, &unpack_caller/1)\n        {kind_name_arity, specs}\n\n      kind_name_arity ->\n        {kind_name_arity, specs}\n    end\n  end\n\n  defp unpack_caller({:type, line1, :fun, [{:type, line2, :product, [_ | args]} | tail]}) do\n    {:type, line1, :fun, [{:type, line2, :product, args} | tail]}\n  end\n\n  defp unpack_caller({:type, line, :bounded_fun, [head | tail]}) do\n    {:type, line, :bounded_fun, [unpack_caller(head) | tail]}\n  end\n\n  def translate_callback_name_arity({name, arity}) do\n    case Atom.to_string(name) do\n      \"MACRO-\" <> macro_name -> {:macrocallback, String.to_atom(macro_name), arity - 1}\n      _ -> {:callback, name, arity}\n    end\n  end\n\n  defp format_callback({{kind, name, _arity}, specs}) do\n    Enum.map(specs, fn spec ->\n      Typespec.spec_to_quoted(name, spec)\n      |> format_typespec(kind, 0)\n    end)\n  end\n\n  defp add_optional_callback_docs(docs, mod) do\n    optional_callbacks =\n      if Code.ensure_loaded?(mod) and function_exported?(mod, :behaviour_info, 1) do\n        mod.behaviour_info(:optional_callbacks)\n        |> Enum.map(fn name_arity ->\n          {_kind, name, arity} = translate_callback_name_arity(name_arity)\n          {name, arity}\n        end)\n        |> Enum.sort()\n      else\n        []\n      end\n\n    if optional_callbacks == [] do\n      docs\n    else\n      docs ++ [{\"text/markdown\", format_optional_callbacks(optional_callbacks), \"\", %{}}]\n    end\n  end\n\n  defp format_optional_callbacks(callbacks) do\n    format_typespec(callbacks, :optional_callbacks, 0)\n  end\n\n  @doc \"\"\"\n  Prints the types for the given module and type documentation.\n  \"\"\"\n  def t(module) when is_atom(module) do\n    case Typespec.fetch_types(module) do\n      :error ->\n        no_beam(module)\n\n      {:ok, []} ->\n        types_not_found(inspect(module))\n\n      {:ok, types} ->\n        types\n        |> Enum.sort_by(fn {_, {name, _, args}} -> {name, length(args)} end)\n        |> Enum.each(&(&1 |> format_type() |> IO.puts()))\n    end\n\n    dont_display_result()\n  end\n\n  def t({module, type}) when is_atom(module) and is_atom(type) do\n    {_, format, docs} = get_docs(module, [:type])\n\n    case Typespec.fetch_types(module) do\n      :error ->\n        no_beam(module)\n\n      {:ok, types} ->\n        types\n        |> Enum.filter(&match?({kind, {^type, _, _}} when kind in [:type, :opaque], &1))\n        |> Enum.sort_by(fn {_, {name, _, args}} -> {name, length(args)} end)\n        |> case do\n          [] ->\n            types_not_found_or_private(\"#{inspect(module)}.#{type}\")\n\n          types ->\n            Enum.map(types, fn {_, {_, _, args}} = typespec ->\n              type\n              |> type_doc(length(args), typespec, format, docs)\n              |> print_typespec()\n            end)\n        end\n    end\n\n    dont_display_result()\n  end\n\n  def t({module, type, arity}) when is_atom(module) and is_atom(type) and is_integer(arity) do\n    {_, format, docs} = get_docs(module, [:type])\n\n    case Typespec.fetch_types(module) do\n      :error ->\n        no_beam(module)\n\n      {:ok, types} ->\n        types\n        |> Enum.find(\n          &match?(\n            {kind, {^type, _, args}} when kind in [:type, :opaque] and length(args) == arity,\n            &1\n          )\n        )\n        |> case do\n          nil ->\n            types_not_found_or_private(\"#{inspect(module)}.#{type}\")\n\n          typespec ->\n            type\n            |> type_doc(arity, typespec, format, docs)\n            |> print_typespec()\n        end\n    end\n\n    dont_display_result()\n  end\n\n  def t(invalid) do\n    puts_error(\"Invalid arguments for t helper: #{inspect(invalid)}\")\n    dont_display_result()\n  end\n\n  defp type_doc(type, arity, typespec, format, docs) do\n    if docs do\n      {_, _, _, content, metadata} = Enum.find(docs, &match?({:type, ^type, ^arity}, elem(&1, 0)))\n      {format, format_type(typespec), content, metadata}\n    else\n      {format, format_type(typespec), :none, %{}}\n    end\n  end\n\n  defp format_type({:opaque, type}) do\n    {:\"::\", _, [ast, _]} = Typespec.type_to_quoted(type)\n    format_typespec(ast, :opaque, 0)\n  end\n\n  defp format_type({kind, type}) do\n    ast = Typespec.type_to_quoted(type)\n    format_typespec(ast, kind, 0)\n  end\n\n  ## Helpers\n\n  defp format_typespec(definition, kind, nesting) do\n    {:@, [], [{kind, [], [definition]}]}\n    |> Code.quoted_to_algebra()\n    |> Inspect.Algebra.format(IEx.Config.width())\n    |> IO.iodata_to_binary()\n    |> color_prefix_with_line()\n    |> indent(nesting)\n  end\n\n  defp indent(content, 0) do\n    [content, ?\\n]\n  end\n\n  defp indent(content, nesting) do\n    whitespace = String.duplicate(\" \", nesting)\n    [whitespace, String.replace(content, \"\\n\", \"\\n#{whitespace}\"), ?\\n]\n  end\n\n  defp color_prefix_with_line(string) do\n    [left, right] = :binary.split(string, \" \")\n    IEx.color(:doc_inline_code, left) <> \" \" <> right\n  end\n\n  defp print_doc(headings, types, format, doc, metadata) do\n    doc = translate_doc(doc) || \"\"\n    opts = IEx.Config.ansi_docs()\n    IO.ANSI.Docs.print_headings(headings, opts)\n    IO.write(types)\n    IO.ANSI.Docs.print_metadata(metadata, opts)\n    IO.ANSI.Docs.print(doc, format, opts)\n  end\n\n  defp print_typespec({format, types, doc, metadata}) do\n    IO.puts(types)\n    doc = translate_doc(doc)\n    opts = IEx.Config.ansi_docs()\n    IO.ANSI.Docs.print_metadata(metadata, opts)\n    doc && IO.ANSI.Docs.print(doc, format, opts)\n  end\n\n  defp translate_doc(%{\"en\" => doc}), do: doc\n  defp translate_doc(_), do: nil\n\n  defp no_beam(module) do\n    case Code.ensure_loaded(module) do\n      {:module, _} ->\n        puts_error(\n          \"Beam code not available for #{inspect(module)} or debug info is missing, cannot load typespecs\"\n        )\n\n      {:error, reason} ->\n        puts_error(\"Could not load module #{inspect(module)}, got: #{reason}\")\n    end\n  end\n\n  defp no_docs(module) do\n    puts_error(\"#{inspect(module)} was not compiled with docs\")\n  end\n\n  defp types_not_found(for), do: not_found(for, \"type information\")\n  defp docs_not_found(for), do: not_found(for, \"documentation\")\n\n  defp types_not_found_or_private(for) do\n    puts_error(\"No type information for #{for} was found or #{for} is private\")\n  end\n\n  defp behaviour_found(for) do\n    puts_error(\"\"\"\n    No documentation for function #{for} was found, but there is a callback with the same name.\n    You can view callback documentation with the b/1 helper.\n    \"\"\")\n  end\n\n  defp type_found(for) do\n    puts_error(\"\"\"\n    No documentation for function #{for} was found, but there is a type with the same name.\n    You can view type documentation with the t/1 helper.\n    \"\"\")\n  end\n\n  defp not_found(for, type) do\n    puts_error(\"No #{type} for #{for} was found\")\n  end\n\n  defp puts_error(string) do\n    IO.puts(IEx.color(:eval_error, string))\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/mix_listener.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule IEx.MixListener do\n  @moduledoc false\n\n  use GenServer\n\n  @name __MODULE__\n\n  @spec start_link(keyword) :: GenServer.on_start()\n  def start_link(_opts) do\n    GenServer.start_link(__MODULE__, {}, name: @name)\n  end\n\n  @doc \"\"\"\n  Unloads all modules invalidated by external compilations.\n\n  Returns `:noop` if there is no module to purge or if\n  the listener is not running (it may happen when connecting\n  via --remsh to a node that was started without IEx).\n  \"\"\"\n  @spec purge :: :ok | :noop\n  def purge do\n    if Process.whereis(@name) do\n      GenServer.call(@name, :purge, :infinity)\n    else\n      :noop\n    end\n  end\n\n  @impl true\n  def init({}) do\n    {:ok, %{to_purge: MapSet.new()}}\n  end\n\n  @impl true\n  def handle_call(:purge, _from, state) do\n    purge_modules(state.to_purge)\n    status = if Enum.empty?(state.to_purge), do: :noop, else: :ok\n    {:reply, status, %{state | to_purge: MapSet.new()}}\n  end\n\n  @impl true\n  def handle_info({:modules_compiled, info}, state) do\n    if info.os_pid == System.pid() do\n      # Ignore compilations from ourselves, because the modules are\n      # already updated in memory\n      {:noreply, state}\n    else\n      %{changed: changed, removed: removed} = info.modules_diff\n\n      if IEx.Config.auto_reload?() do\n        purge_modules(changed)\n        purge_modules(removed)\n        {:noreply, state}\n      else\n        state = update_in(state.to_purge, &Enum.into(changed, &1))\n        state = update_in(state.to_purge, &Enum.into(removed, &1))\n        {:noreply, state}\n      end\n    end\n  end\n\n  def handle_info(_message, state) do\n    {:noreply, state}\n  end\n\n  defp purge_modules(modules) do\n    for module <- modules do\n      :code.purge(module)\n      :code.delete(module)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/pry.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.Pry do\n  @moduledoc \"\"\"\n  The low-level API for prying sessions and setting up breakpoints.\n  \"\"\"\n\n  @doc false\n  use GenServer\n\n  @table __MODULE__\n  @server __MODULE__\n  @timeout :infinity\n  @initial_counter 1\n\n  @type id :: integer()\n  @type break :: {id, module, {function, arity}, pending :: non_neg_integer}\n  @type break_error ::\n          :recompilation_failed\n          | :no_beam_file\n          | :unknown_function_arity\n          | :missing_debug_info\n          | :outdated_debug_info\n          | :non_elixir_module\n\n  @doc \"\"\"\n  Callback for `IEx.pry/0`.\n\n  You can invoke this function directly when you are not able to invoke\n  `IEx.pry/0` as a macro. This function expects the binding (from\n  `binding/0`) and the environment (from `__ENV__/0`).\n  \"\"\"\n  def pry(binding, %Macro.Env{} = env) do\n    self = self()\n    %{file: file, line: line, module: module, function: function_arity} = env\n    {:current_stacktrace, stacktrace} = Process.info(self, :current_stacktrace)\n\n    opts = [\n      binding: binding,\n      dot_iex: \"\",\n      # Remove all tracers because the tracer code is most\n      # likely stale by the time we are prying the code.\n      env: %{env | tracers: [], lexical_tracker: nil},\n      stacktrace: prune_stacktrace(stacktrace)\n    ]\n\n    location =\n      case function_arity do\n        {function, arity} ->\n          \"#{Exception.format_mfa(module, function, arity)} (#{Path.relative_to_cwd(file)}:#{line})\"\n\n        _ ->\n          \"#{Path.relative_to_cwd(file)}:#{line}\"\n      end\n\n    whereami =\n      case whereami(file, line, 3) do\n        {:ok, lines} -> [?\\n, ?\\n, lines]\n        :error -> []\n      end\n\n    # We cannot use colors because IEx may be off\n    case IEx.Broker.take_over(location, whereami, [evaluator: self()] ++ opts) do\n      {:ok, server, group_leader, start} ->\n        IEx.Evaluator.init(:no_ack, server, group_leader, start, opts)\n\n      {:error, :no_iex} ->\n        message = \"Cannot pry #{inspect(self)} at #{location}. Is an IEx shell running?\"\n        IO.puts(:stdio, message)\n        {:error, :no_iex}\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  def pry(binding, opts) when is_list(opts) do\n    vars = for {k, _} when is_atom(k) <- binding, do: {k, nil}\n    pry(binding, opts |> Code.env_for_eval() |> :elixir_env.with_vars(vars))\n  end\n\n  @doc false\n  def __next__(next?, binding, opts_or_env) when is_boolean(next?) do\n    next? and pry(binding, opts_or_env) == {:ok, true}\n  end\n\n  @elixir_internals [:elixir, :erl_eval, IEx.Evaluator, IEx.Pry]\n\n  defp prune_stacktrace([{mod, _, _, _} | t]) when mod in @elixir_internals do\n    prune_stacktrace(t)\n  end\n\n  defp prune_stacktrace([{Process, :info, 2, _} | t]) do\n    prune_stacktrace(t)\n  end\n\n  defp prune_stacktrace([h | t]) do\n    [h | prune_stacktrace(t)]\n  end\n\n  defp prune_stacktrace([]) do\n    []\n  end\n\n  @doc \"\"\"\n  Annotate quoted expression with line-by-line `IEx.Pry` debugging steps.\n\n  It expects the `quoted` expression to annotate, a boolean `condition` that controls\n  if pry should run or not (usually is simply the boolean `true`), and the\n  caller macro environment.\n  \"\"\"\n  @doc since: \"1.17.0\"\n  @spec annotate_quoted(Macro.t(), Macro.t(), Macro.Env.t()) :: Macro.t()\n  def annotate_quoted(quoted, condition, caller) do\n    prelude =\n      quote do\n        [\n          env = unquote(Macro.escape(Macro.Env.prune_compile_info(caller))),\n          next? = unquote(condition)\n        ]\n      end\n\n    next_pry =\n      fn line, _version, _binding ->\n        quote do\n          next? = IEx.Pry.__next__(next?, binding(), %{env | line: unquote(line)})\n        end\n      end\n\n    annotate_quoted(quoted, prelude, caller.line, 0, :ok, fn _, _ -> :ok end, next_pry)\n  end\n\n  defp annotate_quoted(maybe_block, prelude, line, version, binding, next_binding, next_pry)\n       when is_list(prelude) do\n    exprs =\n      maybe_block\n      |> unwrap_block()\n      |> annotate_quoted(true, line, version, binding, {next_binding, next_pry})\n\n    {:__block__, [], prelude ++ exprs}\n  end\n\n  defp annotate_quoted([expr | exprs], force?, line, version, binding, funs) do\n    {next_binding, next_pry} = funs\n    new_binding = next_binding.(expr, binding)\n    {min_line, max_line} = line_range(expr, line)\n\n    if force? or min_line > line do\n      [\n        next_pry.(min_line, version, binding),\n        expr | annotate_quoted(exprs, false, max_line, version + 1, new_binding, funs)\n      ]\n    else\n      [expr | annotate_quoted(exprs, false, max_line, version, new_binding, funs)]\n    end\n  end\n\n  defp annotate_quoted([], _force?, _line, _version, _binding, _funs) do\n    []\n  end\n\n  @doc \"\"\"\n  Formats the location for `whereami/3` prying.\n\n  It receives the `file`, `line` and the snippet `radius` and\n  returns `{:ok, lines}`, where lines is a list of chardata\n  containing each formatted line, or `:error`.\n\n  The actual line is especially formatted in bold.\n  \"\"\"\n  @spec whereami(String.t(), non_neg_integer(), pos_integer()) :: {:ok, IO.chardata()} | :error\n  def whereami(file, line, radius)\n      when is_binary(file) and is_integer(line) and is_integer(radius) and radius > 0 do\n    with true <- File.regular?(file),\n         [_ | _] = lines <- whereami_lines(file, line, radius) do\n      {:ok, lines}\n    else\n      _ -> :error\n    end\n  end\n\n  defp whereami_lines(file, line, radius) do\n    min = max(line - radius - 1, 0)\n    max = line + radius - 1\n\n    file\n    |> File.stream!()\n    |> Enum.slice(min..max)\n    |> Enum.with_index(min + 1)\n    |> Enum.map(&whereami_format_line(&1, line))\n  end\n\n  defp whereami_format_line({line_text, line_number}, line) do\n    gutter = String.pad_leading(Integer.to_string(line_number), 5, \" \")\n\n    if line_number == line do\n      IO.ANSI.format_fragment([:bright, gutter, \": \", line_text, :normal])\n    else\n      [gutter, \": \", line_text]\n    end\n  end\n\n  @doc \"\"\"\n  Sets up a breakpoint on the given module/function/arity.\n  \"\"\"\n  @spec break(module, atom, arity, non_neg_integer) :: {:ok, id()} | {:error, break_error()}\n  def break(module, function, arity, breaks \\\\ 1)\n      when is_atom(module) and is_atom(function) and arity in 0..255 and\n             is_integer(breaks) and breaks >= 0 do\n    break_call(module, function, arity, quote(do: _), breaks)\n  end\n\n  @doc \"\"\"\n  Sets up a breakpoint on the given module/function/args with the given `guard`.\n\n  It requires an `env` to be given to make the expansion of the guards.\n  \"\"\"\n  @spec break(module, atom, [Macro.t()], Macro.t(), Macro.Env.t(), non_neg_integer) ::\n          {:ok, id()} | {:error, break_error()}\n  def break(module, function, args, guard, env, breaks \\\\ 1)\n      when is_atom(module) and is_atom(function) and is_list(args) and is_integer(breaks) and\n             breaks >= 0 do\n    condition = build_args_guard_condition(args, guard, env)\n    break_call(module, function, length(args), condition, breaks)\n  end\n\n  defp break_call(module, function, arity, condition, breaks) do\n    GenServer.call(@server, {:break, module, {function, arity}, condition, breaks}, @timeout)\n  end\n\n  @doc \"\"\"\n  Raising variant of `break/4`.\n  \"\"\"\n  @spec break!(module, atom, arity, non_neg_integer) :: id()\n  def break!(module, function, arity, breaks \\\\ 1) do\n    break_call!(module, function, arity, quote(do: _), breaks)\n  end\n\n  @doc \"\"\"\n  Raising variant of `break/6`.\n  \"\"\"\n  @spec break!(module, atom, [Macro.t()], Macro.t(), Macro.Env.t(), non_neg_integer) :: id()\n  def break!(module, function, args, guard, env, breaks \\\\ 1)\n      when is_atom(module) and is_atom(function) and is_list(args) and is_integer(breaks) and\n             breaks >= 0 do\n    condition = build_args_guard_condition(args, guard, env)\n    break_call!(module, function, length(args), condition, breaks)\n  end\n\n  defp break_call!(module, function, arity, condition, breaks) do\n    case break_call(module, function, arity, condition, breaks) do\n      {:ok, id} ->\n        id\n\n      {:error, kind} ->\n        message =\n          case kind do\n            :missing_debug_info ->\n              \"module #{inspect(module)} was not compiled with debug_info\"\n\n            :no_beam_file ->\n              \"could not find .beam file for #{inspect(module)}\"\n\n            :non_elixir_module ->\n              \"module #{inspect(module)} was not written in Elixir\"\n\n            :outdated_debug_info ->\n              \"module #{inspect(module)} was not compiled with the latest debug_info\"\n\n            :recompilation_failed ->\n              \"the module could not be compiled with breakpoints (likely an internal error)\"\n\n            :unknown_function_arity ->\n              \"unknown function/macro #{Exception.format_mfa(module, function, arity)}\"\n          end\n\n        raise \"could not set breakpoint, \" <> message\n    end\n  end\n\n  defp build_args_guard_condition(args, guards, env) do\n    pattern = {:when, [], [{:{}, [], args}, guards]}\n\n    to_expand =\n      quote do\n        case Unknown.module() do\n          unquote(pattern) -> :ok\n        end\n      end\n\n    {{:case, _, [_, [do: [{:->, [], [[condition], _]}]]]}, _, _} =\n      :elixir_expand.expand(to_expand, :elixir_env.env_to_ex(env), env)\n\n    condition\n  end\n\n  @doc \"\"\"\n  Resets the breaks on a given breakpoint ID.\n  \"\"\"\n  @spec reset_break(id) :: :ok | :not_found\n  def reset_break(id) when is_integer(id) do\n    GenServer.call(@server, {:reset_break, {id, :_, :_, :_, :_}}, @timeout)\n  end\n\n  @doc \"\"\"\n  Resets the breaks for the given `module`, `function` and `arity`.\n\n  If the `module` is not instrumented or if the given `function`\n  does not have a breakpoint, it is a no-op and it returns\n  `:not_found`. Otherwise it returns `:ok`.\n  \"\"\"\n  @spec reset_break(module, atom, arity) :: :ok | :not_found\n  def reset_break(module, function, arity) do\n    GenServer.call(@server, {:reset_break, {:_, module, {function, arity}, :_, :_}}, @timeout)\n  end\n\n  @doc \"\"\"\n  Removes all breakpoints on all modules.\n\n  This effectively loads the non-instrumented version of\n  currently instrumented modules into memory.\n  \"\"\"\n  @spec remove_breaks :: :ok\n  def remove_breaks do\n    GenServer.call(@server, :remove_breaks, @timeout)\n  end\n\n  @doc \"\"\"\n  Removes breakpoints in the given module.\n\n  This effectively loads the non-instrumented version of\n  the module into memory.\n  \"\"\"\n  @spec remove_breaks(module) :: :ok | {:error, :no_beam_file}\n  def remove_breaks(module) do\n    GenServer.call(@server, {:remove_breaks, module}, @timeout)\n  end\n\n  @doc \"\"\"\n  Returns all breakpoints.\n  \"\"\"\n  @spec breaks :: [break]\n  def breaks do\n    @server\n    |> GenServer.call(:breaks, @timeout)\n    |> Enum.sort()\n  end\n\n  ## Callbacks\n\n  @doc false\n  def start_link(_) do\n    GenServer.start_link(__MODULE__, :ok, name: @server)\n  end\n\n  @impl true\n  def init(:ok) do\n    Process.flag(:trap_exit, true)\n    :ets.new(@table, [:named_table, :public, write_concurrency: true])\n    {:ok, @initial_counter}\n  end\n\n  @impl true\n  def handle_call({:break, module, fa, condition, breaks}, _from, counter) do\n    # If there is a match for the given module and fa, we\n    # use the ref, otherwise we create a new one.\n    {ref, counter} =\n      case :ets.match_object(@table, {:_, module, fa, :_, :_}) do\n        [{ref, _, _, _, _}] -> {ref, counter}\n        [] -> {counter, counter + 1}\n      end\n\n    case fetch_elixir_debug_info_with_fa_check(module, fa) do\n      {:ok, beam, backend, elixir} ->\n        true = :ets.insert(@table, {ref, module, fa, condition, breaks})\n        entries = :ets.match_object(@table, {:_, module, :_, :_, :_})\n        {:reply, instrument(beam, backend, elixir, ref, entries), counter}\n\n      {:error, _} = error ->\n        {:reply, error, counter}\n    end\n  end\n\n  def handle_call({:reset_break, pattern}, _from, counter) do\n    reset =\n      for {ref, module, fa, condition, _} <- :ets.match_object(@table, pattern) do\n        if instrumented?(module) do\n          :ets.insert(@table, {ref, module, fa, condition, 0})\n          true\n        else\n          :ets.delete(@table, ref)\n          false\n        end\n      end\n\n    if Enum.any?(reset) do\n      {:reply, :ok, counter}\n    else\n      {:reply, :not_found, counter}\n    end\n  end\n\n  def handle_call(:breaks, _from, counter) do\n    entries =\n      for {id, module, function_arity, _condition, breaks} <- :ets.tab2list(@table),\n          keep_instrumented(id, module) == :ok do\n        {id, module, function_arity, max(breaks, 0)}\n      end\n\n    {:reply, entries, counter}\n  end\n\n  def handle_call(:remove_breaks, _from, _counter) do\n    # Make sure to deinstrument before clearing\n    # up the table to avoid race conditions.\n    @table\n    |> :ets.match({:_, :\"$1\", :_, :_, :_})\n    |> List.flatten()\n    |> Enum.uniq()\n    |> Enum.each(&deinstrument_if_instrumented/1)\n\n    true = :ets.delete_all_objects(@table)\n    {:reply, :ok, @initial_counter}\n  end\n\n  def handle_call({:remove_breaks, module}, _from, counter) do\n    # Make sure to deinstrument before clearing\n    # up the table to avoid race conditions.\n    reply = deinstrument_if_instrumented(module)\n    true = :ets.match_delete(@table, {:_, module, :_, :_, :_})\n    {:reply, reply, counter}\n  end\n\n  defp keep_instrumented(id, module) do\n    if instrumented?(module) do\n      :ok\n    else\n      :ets.delete(@table, id)\n      :error\n    end\n  end\n\n  defp deinstrument_if_instrumented(module) do\n    if instrumented?(module) do\n      deinstrument(module)\n    else\n      :ok\n    end\n  end\n\n  defp deinstrument(module) do\n    with [_ | _] = beam <- :code.which(module),\n         {:ok, binary} <- File.read(beam) do\n      :code.purge(module)\n      {:module, _} = :code.load_binary(module, beam, binary)\n      :ok\n    else\n      _ -> {:error, :no_beam_file}\n    end\n  end\n\n  defp fetch_elixir_debug_info_with_fa_check(module, fa) do\n    case :code.which(module) do\n      [_ | _] = beam ->\n        case :beam_lib.chunks(beam, [:debug_info]) do\n          {:ok, {_, [debug_info: {:debug_info_v1, backend, {:elixir_v1, map, _} = elixir}]}} ->\n            case List.keyfind(map.definitions, fa, 0) do\n              {_, _, _, _} -> {:ok, beam, backend, elixir}\n              nil -> {:error, :unknown_function_arity}\n            end\n\n          {:ok, {_, [debug_info: {:debug_info_v1, _, _}]}} ->\n            {:error, :non_elixir_module}\n\n          {:error, :beam_lib, {:missing_chunk, _, _}} ->\n            {:error, :missing_debug_info}\n\n          _ ->\n            {:error, :outdated_debug_info}\n        end\n\n      _ ->\n        {:error, :no_beam_file}\n    end\n  end\n\n  defp instrument(beam, backend, {:elixir_v1, map, specs}, counter, entries) do\n    %{attributes: attributes, definitions: definitions, module: module} = map\n\n    attributes = [{:iex_pry, true} | attributes]\n    definitions = Enum.map(definitions, &instrument_definition(&1, map, entries))\n    map = %{map | attributes: attributes, definitions: definitions}\n\n    with {:ok, forms} <- backend.debug_info(:erlang_v1, module, {:elixir_v1, map, specs}, []),\n         {:ok, _, binary, _} <- :compile.noenv_forms(forms, [:return | map.compile_opts]) do\n      :code.purge(module)\n      {:module, _} = :code.load_binary(module, beam, binary)\n      {:ok, counter}\n    else\n      _error ->\n        {:error, :recompilation_failed}\n    end\n  end\n\n  defp instrument_definition({fa, kind, meta, clauses} = definition, map, entries) do\n    case List.keyfind(entries, fa, 2) do\n      {ref, _, ^fa, condition, _} ->\n        %{module: module, file: file} = map\n\n        file =\n          case meta[:location] do\n            {file, _} -> file\n            _ -> file\n          end\n\n        opts = [module: module, file: file, function: fa]\n        clauses = Enum.map(clauses, &instrument_clause(&1, ref, condition, opts))\n        {fa, kind, meta, clauses}\n\n      nil ->\n        definition\n    end\n  end\n\n  defp instrument_clause({meta, args, guards, clause}, ref, case_pattern, opts) do\n    arity = length(args)\n\n    # Have an extra binding per argument for case matching.\n    case_vars =\n      for id <- 1..arity//1 do\n        {String.to_atom(\"arg\" <> Integer.to_string(id)), [version: -id], __MODULE__}\n      end\n\n    case_head = {:{}, [], case_vars}\n    update_op = Macro.escape({5, -1, -1, -1})\n\n    # Generate the take_over condition with the ETS lookup.\n    # Remember this is expanded AST, so no aliases allowed,\n    # no locals (such as the unary -) and so on.\n    prelude =\n      quote do\n        [\n          unquote(next_var(arity + 1)) = unquote(opts),\n          unquote(next_var(arity + 2)) =\n            case unquote(case_head) do\n              unquote(case_pattern) ->\n                :erlang.\"/=\"(\n                  # :ets.update_counter(table, key, {pos, inc, threshold, reset})\n                  :ets.update_counter(unquote(@table), unquote(ref), unquote(update_op)),\n                  unquote(-1)\n                )\n\n              _ ->\n                false\n            end\n        ]\n      end\n\n    args =\n      case_vars\n      |> Enum.zip(args)\n      |> Enum.map(fn {var, arg} -> {:=, [], [arg, var]} end)\n\n    version = arity + 2\n    binding = match_binding(args, %{})\n    line = Keyword.get(meta, :line, 1)\n    env_var = next_var(arity + 1)\n\n    clause =\n      annotate_quoted(clause, prelude, line, version, binding, &next_binding/2, fn\n        line, version, binding ->\n          quote do\n            unquote(next_var(version + 1)) =\n              :\"Elixir.IEx.Pry\".__next__(\n                unquote(next_var(version)),\n                unquote(Map.to_list(binding)),\n                [{:line, unquote(line)} | unquote(env_var)]\n              )\n          end\n      end)\n\n    {meta, args, guards, clause}\n  end\n\n  defp line_range(ast, line) do\n    # We want min_line to start from infinity because\n    # if it starts from line it will always just return line.\n    {_, {min, max}} =\n      Macro.prewalk(ast, {:infinity, line}, fn\n        {_, meta, _} = ast, {min_line, max_line} when is_list(meta) ->\n          case Keyword.fetch(meta, :line) do\n            {:ok, line} when line > 0 ->\n              {ast, {min(line, min_line), max(line, max_line)}}\n\n            _ ->\n              {ast, {min_line, max_line}}\n          end\n\n        ast, acc ->\n          {ast, acc}\n      end)\n\n    if min == :infinity, do: {line, max}, else: {min, max}\n  end\n\n  defp next_binding(ast, binding) do\n    {_, binding} =\n      Macro.prewalk(ast, binding, fn\n        {:=, _, [left, _right]}, acc ->\n          {:ok, match_binding(left, acc)}\n\n        {:case, _, [arg, _block]}, acc ->\n          {arg, acc}\n\n        {special_form, _, _}, acc\n        when special_form in [:cond, :fn, :for, :receive, :try, :with] ->\n          {:ok, acc}\n\n        expr, acc ->\n          {expr, acc}\n      end)\n\n    binding\n  end\n\n  defp match_binding(match, binding) do\n    {_, binding} =\n      Macro.prewalk(match, binding, fn\n        {name, _, nil} = var, acc when name != :_ and is_atom(name) ->\n          {var, Map.put(acc, name, var)}\n\n        # Stop traversing inside pin operators and :: in binaries\n        {special_form, _, _}, acc when special_form in [:^, :\"::\"] ->\n          {:ok, acc}\n\n        expr, acc ->\n          {expr, acc}\n      end)\n\n    binding\n  end\n\n  defp next_var(id) do\n    {:next?, [version: -id], __MODULE__}\n  end\n\n  defp instrumented?(module) do\n    module.__info__(:attributes)[:iex_pry] == [true]\n  end\n\n  defp unwrap_block(expr), do: expr |> unwrap_block([]) |> Enum.reverse()\n  defp unwrap_block({:__block__, _, exprs}, acc), do: Enum.reduce(exprs, acc, &unwrap_block/2)\n  defp unwrap_block(expr, acc), do: [expr | acc]\n\n  # IEx backend for Kernel.dbg/2.\n  @doc false\n  def dbg(ast, options, env)\n\n  def dbg({:|>, _meta, _args} = ast, options, %Macro.Env{} = env) when is_list(options) do\n    [first_ast_chunk | asts_chunks] = ast |> Macro.unpipe() |> chunk_pipeline_asts_by_line(env)\n\n    {first_line, _max_line} = line_range(ast, env.line)\n\n    prelude =\n      quote do\n        options = unquote(options)\n\n        options =\n          if IO.ANSI.enabled?() do\n            Keyword.put_new(options, :syntax_colors, IO.ANSI.syntax_colors())\n          else\n            options\n          end\n\n        value = unquote(pipe_chunk_of_asts(first_ast_chunk))\n\n        IEx.Pry.__dbg_pipe_step__(\n          value,\n          unquote(asts_chunk_to_strings(first_ast_chunk)),\n          _start_with_pipe? = false,\n          options\n        )\n      end\n\n    main_block =\n      for asts_chunk <- asts_chunks do\n        piped_asts = pipe_chunk_of_asts([{quote(do: value), _index = 0}] ++ asts_chunk)\n\n        quote do\n          value = unquote(piped_asts)\n\n          IEx.Pry.__dbg_pipe_step__(\n            value,\n            unquote(asts_chunk_to_strings(asts_chunk)),\n            _start_with_pipe? = true,\n            options\n          )\n        end\n      end\n\n    annotate_quoted({:__block__, [], [prelude | main_block]}, true, %{env | line: first_line})\n  end\n\n  def dbg(ast, options, %Macro.Env{} = env) when is_list(options) do\n    options = Keyword.put(options, :print_location, false)\n\n    quote do\n      IEx.Pry.pry(binding(), __ENV__)\n      unquote(Macro.dbg(ast, options, env))\n    end\n  end\n\n  # Made public to be called from IEx.Pry.dbg/3 to reduce the amount of generated code.\n  @doc false\n  def __dbg_pipe_step__(value, string_asts, start_with_pipe?, options) do\n    asts_string = Enum.intersperse(string_asts, [:faint, \" |> \", :reset])\n\n    asts_string =\n      if start_with_pipe? do\n        IO.ANSI.format([:faint, \"|> \", :reset, asts_string])\n      else\n        asts_string\n      end\n\n    [asts_string, :faint, \" #=> \", :reset, inspect(value, options), \"\\n\\n\"]\n    |> IO.ANSI.format()\n    |> IO.write()\n\n    value\n  end\n\n  defp chunk_pipeline_asts_by_line(asts, %Macro.Env{line: env_line}) do\n    Enum.chunk_by(asts, fn\n      {{_fun_or_var, meta, _args}, _pipe_index} -> meta[:line] || env_line\n      {_other_ast, _pipe_index} -> env_line\n    end)\n  end\n\n  defp pipe_chunk_of_asts([{first_ast, _first_index} | asts] = _ast_chunk) do\n    Enum.reduce(asts, first_ast, fn {ast, index}, acc -> Macro.pipe(acc, ast, index) end)\n  end\n\n  defp asts_chunk_to_strings(asts) do\n    Enum.map(asts, fn {ast, _pipe_index} -> Macro.to_string(ast) end)\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex/server.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.Server do\n  @moduledoc \"\"\"\n  The IEx.Server.\n\n  The server responsibilities include:\n\n    * reading input from the group leader and writing to the group leader\n    * sending messages to the evaluator\n    * taking over the evaluator process when using `IEx.pry/0` or setting up breakpoints\n\n  \"\"\"\n\n  @type run_opts :: [\n          prefix: String.t(),\n          env: Macro.Env.t(),\n          binding: keyword(),\n          on_eof: :stop_evaluator | :halt,\n          register: boolean()\n        ]\n\n  @doc false\n  defstruct parser_state: [],\n            counter: 1,\n            prefix: \"iex\",\n            on_eof: :stop_evaluator,\n            evaluator_options: [],\n            expand_fun: nil\n\n  @doc \"\"\"\n  Starts a new IEx server session.\n\n  The accepted options are:\n\n    * `:prefix` - the IEx prefix\n    * `:env` - the `Macro.Env` used for the evaluator\n    * `:binding` - an initial set of variables for the evaluator\n    * `:on_eof` - if it should `:stop_evaluator` (default) or `:halt` the system\n    * `:register` - if this shell should be registered in the broker (default is `true`)\n\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec run(run_opts) :: :ok\n  def run(opts) when is_list(opts) do\n    if Keyword.get(opts, :register, true) do\n      IEx.Broker.register(self())\n    end\n\n    run_without_registration(init_state(opts), opts, nil)\n  end\n\n  ## Private APIs\n\n  # Starts IEx to run directly from the Erlang shell.\n  #\n  # The server is spawned only after the callback is done.\n  #\n  # If there is any takeover during the callback execution\n  # we spawn a new server for it without waiting for its\n  # conclusion.\n  @doc false\n  @spec run_from_shell(keyword, {module, atom, [any]}) :: :ok\n  def run_from_shell(opts, {m, f, a}) do\n    opts[:register] && IEx.Broker.register(self())\n    Process.flag(:trap_exit, true)\n    {pid, ref} = spawn_monitor(m, f, a)\n    shell_loop(opts, pid, ref)\n  end\n\n  defp shell_loop(opts, pid, ref) do\n    receive do\n      {:take_over, take_pid, take_ref, take_location, take_whereami, take_opts} ->\n        IO.puts(IEx.color(:eval_interrupt, \"Break reached: #{take_location}#{take_whereami}\"))\n\n        if take_over?(take_pid, take_ref, 1, true) do\n          run_without_registration(init_state(opts), take_opts, nil)\n        else\n          shell_loop(opts, pid, ref)\n        end\n\n      {:DOWN, ^ref, :process, ^pid, :normal} ->\n        run_without_registration(init_state(opts), opts, nil)\n\n      {:DOWN, ^ref, :process, ^pid, _reason} ->\n        :ok\n    end\n  end\n\n  # Since we want to register only once, this function is the\n  # reentrant point for starting a new shell (instead of run/run_from_shell).\n  defp run_without_registration(state, opts, input) do\n    Process.flag(:trap_exit, true)\n    Process.link(Process.group_leader())\n\n    IO.puts(\n      \"Interactive Elixir (#{System.version()}) - press Ctrl+C to exit (type h() ENTER for help)\"\n    )\n\n    evaluator = start_evaluator(state.counter, Keyword.merge(state.evaluator_options, opts))\n    loop(state, evaluator, Process.monitor(evaluator), input)\n  end\n\n  # Starts an evaluator using the provided options.\n  # Made public but undocumented for testing.\n  @doc false\n  def start_evaluator(counter, opts) do\n    args = [:ack, self(), Process.group_leader(), counter, opts]\n    evaluator = opts[:evaluator] || :proc_lib.start(IEx.Evaluator, :init, args)\n    Process.put(:evaluator, evaluator)\n    evaluator\n  end\n\n  ## Helpers\n\n  defp stop_evaluator(evaluator, evaluator_ref) do\n    Process.delete(:evaluator)\n    Process.demonitor(evaluator_ref, [:flush])\n    send(evaluator, {:done, self(), false})\n    :ok\n  end\n\n  defp rerun(state, opts, evaluator, evaluator_ref, input) do\n    IO.puts(\"\")\n    stop_evaluator(evaluator, evaluator_ref)\n    state = reset_state(state)\n    run_without_registration(state, opts, input)\n  end\n\n  defp loop(state, evaluator, evaluator_ref, input) do\n    %{counter: counter, expand_fun: expand_fun, prefix: prefix, parser_state: parser} = state\n    :io.setopts(expand_fun: expand_fun)\n    input = input || io_get(prompt(prefix, counter), counter, parser)\n    wait_input(state, evaluator, evaluator_ref, input)\n  end\n\n  defp wait_input(state, evaluator, evaluator_ref, input) do\n    receive do\n      {:io_reply, ^input, {:ok, code_fun, parser_state}} ->\n        :io.setopts(expand_fun: fn _ -> {:yes, [], []} end)\n        send(evaluator, {:eval, self(), code_fun.(), state.counter})\n        wait_eval(%{state | parser_state: parser_state}, evaluator, evaluator_ref)\n\n      {:io_reply, ^input, :eof} ->\n        case state.on_eof do\n          :halt -> System.halt(0)\n          :stop_evaluator -> stop_evaluator(evaluator, evaluator_ref)\n        end\n\n      {:io_reply, ^input, {:error, kind, error, stacktrace}} ->\n        send(evaluator, {:reader_errored, self()})\n\n        banner = Exception.format_banner(kind, error, stacktrace)\n\n        banner =\n          if String.contains?(banner, IO.ANSI.reset()) do\n            banner\n          else\n            IEx.color(:eval_error, banner)\n          end\n\n        stackdata = Exception.format_stacktrace(stacktrace)\n        IO.write(:stdio, [banner, ?\\n, IEx.color(:stack_info, stackdata)])\n        loop(%{state | parser_state: []}, evaluator, evaluator_ref, nil)\n\n      # Triggered by pressing \"i\" as the job control switch\n      {:io_reply, ^input, {:error, :interrupted}} ->\n        io_error(\"** (EXIT) interrupted\")\n        loop(%{state | parser_state: []}, evaluator, evaluator_ref, nil)\n\n      # Unknown IO message\n      {:io_reply, ^input, msg} ->\n        io_error(\"** (EXIT) unknown IO message: #{inspect(msg)}\")\n        loop(%{state | parser_state: []}, evaluator, evaluator_ref, nil)\n\n      # Triggered when IO dies while waiting for input\n      {:DOWN, ^input, _, _, _} ->\n        stop_evaluator(evaluator, evaluator_ref)\n\n      msg ->\n        handle_common(msg, state, evaluator, evaluator_ref, input, fn state ->\n          wait_input(state, evaluator, evaluator_ref, input)\n        end)\n    end\n  end\n\n  defp wait_eval(state, evaluator, evaluator_ref) do\n    receive do\n      {:evaled, ^evaluator, status} ->\n        counter = if(status == :ok, do: state.counter + 1, else: state.counter)\n        state = %{state | counter: counter}\n        loop(state, evaluator, evaluator_ref, nil)\n\n      msg ->\n        handle_common(msg, state, evaluator, evaluator_ref, nil, fn state ->\n          wait_eval(state, evaluator, evaluator_ref)\n        end)\n    end\n  end\n\n  defp wait_common(state, evaluator, evaluator_ref, input) do\n    receive do\n      msg ->\n        handle_common(msg, state, evaluator, evaluator_ref, input, fn state ->\n          wait_common(state, evaluator, evaluator_ref, input)\n        end)\n    end\n  end\n\n  # Take process.\n  #\n  # A take process may also happen if the evaluator dies,\n  # then a new evaluator is created to replace the dead one.\n  defp handle_common(\n         {:take_over, take_pid, take_ref, take_location, take_whereami, take_opts},\n         state,\n         evaluator,\n         evaluator_ref,\n         input,\n         callback\n       ) do\n    cond do\n      evaluator == take_opts[:evaluator] ->\n        IO.puts(IEx.color(:eval_interrupt, \"Break reached: #{take_location}#{take_whereami}\"))\n\n        if take_over?(take_pid, take_ref, state.counter + 1, true) do\n          # Since we are in process, also bump the counter\n          state = reset_state(bump_counter(state))\n          loop(state, evaluator, evaluator_ref, input)\n        else\n          callback.(state)\n        end\n\n      take_over?(take_pid, take_ref, take_location, take_whereami, take_opts, state.counter) ->\n        rerun(state, take_opts, evaluator, evaluator_ref, input)\n\n      true ->\n        callback.(state)\n    end\n  end\n\n  # User did ^G while the evaluator was busy or stuck\n  defp handle_common(\n         {:EXIT, _pid, :interrupt},\n         state,\n         evaluator,\n         evaluator_ref,\n         input,\n         _callback\n       ) do\n    io_error(\"** (EXIT) interrupted\")\n    Process.exit(evaluator, :kill)\n    rerun(state, [], evaluator, evaluator_ref, input)\n  end\n\n  defp handle_common(\n         {:EXIT, pid, reason},\n         state,\n         evaluator,\n         evaluator_ref,\n         _input,\n         callback\n       ) do\n    if pid == Process.group_leader() do\n      stop_evaluator(evaluator, evaluator_ref)\n      exit(reason)\n    else\n      callback.(state)\n    end\n  end\n\n  defp handle_common({:respawn, evaluator}, state, evaluator, evaluator_ref, input, _callback) do\n    rerun(bump_counter(state), [], evaluator, evaluator_ref, input)\n  end\n\n  defp handle_common(\n         {:continue, evaluator, next?},\n         state,\n         evaluator,\n         evaluator_ref,\n         input,\n         _callback\n       ) do\n    send(evaluator, {:done, self(), next?})\n    wait_common(state, evaluator, evaluator_ref, input)\n  end\n\n  defp handle_common(\n         {:DOWN, evaluator_ref, :process, evaluator, reason},\n         state,\n         evaluator,\n         evaluator_ref,\n         input,\n         _callback\n       ) do\n    try do\n      io_error(\n        \"** (EXIT from #{inspect(evaluator)}) shell process exited with reason: \" <>\n          Exception.format_exit(reason)\n      )\n    catch\n      type, detail ->\n        io_error(\"** (IEx.Error) #{type} when printing EXIT message: #{inspect(detail)}\")\n    end\n\n    rerun(state, [], evaluator, evaluator_ref, input)\n  end\n\n  defp handle_common(_, state, _evaluator, _evaluator_ref, _input, callback) do\n    callback.(state)\n  end\n\n  defp take_over?(take_pid, take_ref, take_location, take_whereami, take_opts, counter) do\n    evaluator = take_opts[:evaluator] || self()\n    message = \"Request to pry #{inspect(evaluator)} at #{take_location}#{take_whereami}\"\n    interrupt = IEx.color(:eval_interrupt, \"#{message}\\nAllow? [Yn] \")\n    answer = yes?(IO.gets(:stdio, interrupt))\n    take_over?(take_pid, take_ref, counter, answer)\n  end\n\n  defp take_over?(take_pid, take_ref, counter, response) when is_boolean(response) do\n    case IEx.Broker.respond(take_pid, take_ref, counter, response) do\n      :ok ->\n        true\n\n      {:error, :refused} ->\n        false\n\n      {:error, :already_accepted} ->\n        io_error(\"** session was already accepted elsewhere\")\n        false\n    end\n  end\n\n  defp yes?(string) when is_binary(string),\n    do: String.trim(string) in [\"\", \"y\", \"Y\", \"yes\", \"YES\", \"Yes\"]\n\n  defp yes?(charlist) when is_list(charlist),\n    do: yes?(List.to_string(charlist))\n\n  defp yes?(_), do: false\n\n  ## State\n\n  defp init_state(opts) do\n    prefix = Keyword.get(opts, :prefix, \"iex\")\n    on_eof = Keyword.get(opts, :on_eof, :stop_evaluator)\n    gl = Process.group_leader()\n\n    expand_fun =\n      if node(gl) != node() do\n        IEx.Autocomplete.remsh(node())\n      else\n        &IEx.Autocomplete.expand/1\n      end\n\n    %IEx.Server{\n      prefix: prefix,\n      on_eof: on_eof,\n      expand_fun: expand_fun,\n      evaluator_options: Keyword.take(opts, [:dot_iex])\n    }\n  end\n\n  # For the state, reset only reset the parser state.\n  # The counter will continue going up as the input process is shared.\n  # The opts can also set \"dot_iex\" and the \"evaluator\" itself,\n  # but those are not stored: they are temporary to whatever is rerunning.\n  # Once the rerunning session restarts, we keep the same evaluator_options\n  # and rollback to a new evaluator.\n  defp reset_state(state) do\n    %{state | parser_state: []}\n  end\n\n  defp bump_counter(state) do\n    update_in(state.counter, &(&1 + 1))\n  end\n\n  ## IO\n\n  defp io_get(prompt, counter, parser_state) do\n    gl = Process.group_leader()\n    ref = Process.monitor(gl)\n    command = {:get_until, :unicode, prompt, __MODULE__, :__parse__, [{counter, parser_state}]}\n    send(gl, {:io_request, self(), ref, command})\n    ref\n  end\n\n  @doc false\n  def __parse__(_, :eof, _parser_state), do: {:done, :eof, []}\n\n  def __parse__([], chars, {counter, parser_state} = to_be_unused) do\n    __parse__({counter, parser_state, IEx.Config.parser()}, chars, to_be_unused)\n  end\n\n  def __parse__({counter, parser_state, mfa}, chars, _unused) do\n    {parser_module, parser_fun, args} = mfa\n    args = [chars, [line: counter, file: \"iex\"], parser_state | args]\n\n    case apply(parser_module, parser_fun, args) do\n      {:ok, forms, parser_state} ->\n        forms = if is_function(forms, 0), do: forms, else: fn -> forms end\n        {:done, {:ok, forms, parser_state}, []}\n\n      {:incomplete, parser_state} ->\n        {:more, {counter, parser_state, mfa}}\n    end\n  catch\n    kind, error ->\n      {:done, {:error, kind, error, __STACKTRACE__}, []}\n  end\n\n  defp prompt(prefix, counter) do\n    prompt =\n      if Node.alive?() do\n        IEx.Config.alive_prompt()\n      else\n        IEx.Config.default_prompt()\n      end\n      |> String.replace(\"%counter\", to_string(counter))\n      |> String.replace(\"%prefix\", to_string(prefix))\n      |> String.replace(\"%node\", to_string(node()))\n\n    [prompt, \" \"]\n  end\n\n  defp io_error(result) do\n    IO.puts(:stdio, IEx.color(:eval_error, result))\n  end\nend\n"
  },
  {
    "path": "lib/iex/lib/iex.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx do\n  @moduledoc ~S\"\"\"\n  Elixir's interactive shell.\n\n  Some of the functionalities described here will not be available\n  depending on your terminal. In particular, if you get a message\n  saying that the smart terminal could not be run, some of the\n  features described here won't work.\n\n  ## Helpers\n\n  IEx provides a bunch of helpers. They can be accessed by typing\n  `h()` into the shell or as a documentation for the `IEx.Helpers` module.\n\n  ## Autocomplete\n\n  To discover a module's public functions or other modules, type the module name\n  followed by a dot, then press tab to trigger autocomplete. For example:\n\n      Enum.\n\n  A module may export functions that are not meant to be used directly:\n  these functions won't be autocompleted by IEx. IEx will not autocomplete\n  functions annotated with `@doc false`, `@impl true`, or functions that\n  aren't explicitly documented and where the function name is in the form\n  of `__foo__`.\n\n  Autocomplete is available by default on Windows shells.\n\n  ## Encoding and coloring\n\n  IEx expects inputs and outputs to be in UTF-8 encoding. This is the\n  default for most Unix terminals but it may not be the case on Windows.\n  If you are running on Windows and you see incorrect values printed,\n  you may need to change the encoding of your current session by running\n  `chcp 65001` before calling `iex` (or before calling `iex.bat` if using\n  PowerShell).\n\n  Similarly, ANSI coloring is enabled by default on most Unix terminals.\n  They are also available on Windows consoles from Windows 10.\n\n  ## Shell history\n\n  It is possible to get shell history by passing some options that enable it\n  in the VM. This can be done on a per-need basis when starting IEx:\n\n      $ iex --erl \"-kernel shell_history enabled\"\n\n  If you would rather enable it on your system as a whole, you can use\n  the `ERL_AFLAGS` environment variable and make sure that it is set\n  accordingly on your terminal/shell configuration.\n\n  On Unix-like / Bash:\n\n      $ export ERL_AFLAGS=\"-kernel shell_history enabled\"\n\n  On Windows:\n\n      $ set ERL_AFLAGS \"-kernel shell_history enabled\"\n\n  On Windows 10 / PowerShell:\n\n      $ $env:ERL_AFLAGS = \"-kernel shell_history enabled\"\n\n  ## Expressions in IEx\n\n  As an interactive shell, IEx evaluates expressions. This has some\n  interesting consequences that are worth discussing.\n\n  The first one is that the code is truly evaluated and not compiled.\n  This means that any benchmarking done in the shell is going to have\n  skewed results. So never run any profiling nor benchmarks in the shell.\n\n  Second, IEx allows you to break an expression into many lines,\n  since this is common in Elixir. For example:\n\n      iex(1)> \"ab\n      ...(1)> c\"\n      \"ab\\nc\"\n\n  In the example above, the shell will be expecting more input until it\n  finds the closing quote. Sometimes it is not obvious which character\n  the shell is expecting, and the user may find themselves trapped in\n  the state of incomplete expression with no ability to terminate it other\n  than by exiting the shell.\n\n  For such cases, there is a special break-trigger (`#iex:break`) that when\n  encountered on a line by itself will force the shell to break out of any\n  pending expression and return to its normal state:\n\n      iex(1)> [\"ab\n      ...(1)> c\"\n      ...(1)> \"\n      ...(1)> ]\n      ...(1)> #iex:break\n      ** (TokenMissingError) iex:1: incomplete expression\n\n  ## Pasting multiline expressions into IEx\n\n  IEx evaluates its input line by line in an eager fashion. If at the end of a\n  line the code seen so far is a complete expression, IEx will evaluate it at\n  that point.\n\n      iex(1)> [1, [2], 3]\n      [1, [2], 3]\n\n  To prevent this behavior breaking valid code where the subsequent line\n  begins with a binary operator, such as `|>/2` or `++/2` , IEx automatically\n  treats such lines as if they were prepended with `IEx.Helpers.v/0`, which\n  returns the value of the previous expression, if available.\n\n      iex(1)> [1, [2], 3]\n      [1, [2], 3]\n      iex(2)> |> List.flatten()\n      [1, 2, 3]\n\n  The above is equivalent to:\n\n      iex(1)> [1, [2], 3]\n      [1, [2], 3]\n      iex(2)> v() |> List.flatten()\n      [1, 2, 3]\n\n  If there are no previous expressions in the history, the pipe operator will\n  fail:\n\n      iex(1)> |> List.flatten()\n      ** (RuntimeError) v(-1) is out of bounds\n\n  If the previous expression was a match operation, the pipe operator will also\n  fail, to prevent an unsolicited break of the match:\n\n      iex(1)> x = 42\n      iex(2)> |> IO.puts()\n      ** (SyntaxError) iex:2:1: pipe shorthand is not allowed immediately after a match expression in IEx. To make it work, surround the whole pipeline with parentheses ('|>')\n          |\n        2 | |> IO.puts()\n          | ^\n\n  Note, however, the above does not work for `+/2` and `-/2`, as they\n  are ambiguous with the unary `+/1` and `-/1`:\n\n      iex(1)> 1\n      1\n      iex(2)> + 2\n      2\n\n  ## The BREAK menu\n\n  Inside IEx, hitting `Ctrl+C` will open up the `BREAK` menu. In this\n  menu you can quit the shell, see process and ETS tables information\n  and much more.\n\n  ## Exiting the shell\n\n  There are a few ways to quit the IEx shell:\n\n    * via the `BREAK` menu (available via `Ctrl+C`) by typing `q`, pressing enter\n    * by hitting `Ctrl+C`, `Ctrl+C`\n    * by hitting `Ctrl+\\ `\n\n  If you are connected to remote shell, it remains alive after disconnection.\n\n  ## `dbg` and breakpoints\n\n  IEx integrates with `Kernel.dbg/2` and introduces a backend that\n  can pause code execution. To enable it, you must pass `--dbg pry`:\n\n      $ iex --dbg pry\n\n  For example, take the following function:\n\n      def my_fun(arg1, arg2) do\n        dbg(arg1 + arg2)\n        ... implementation ...\n      end\n\n  When the code is executed with `iex` (most often by calling\n  `iex --dbg pry -S mix`), it will ask you permission to use \"pry\".\n  If you agree, it will start an IEx shell in the context of the function\n  above, with access to its variables, imports, and aliases. However,\n  you can only access existing values, it is not possible to access\n  private functions nor change the execution itself (hence the name\n  \"pry\").\n\n  When using `|> dbg()` at the end of a pipeline, you can pry each\n  step of the pipeline. You can type `n` whenever you want to jump\n  into the next pipe. Type `continue` when you want to execute all\n  of the steps but stay within the pried process. Type `respawn` when\n  you want to leave the pried process and start a new shell.\n\n  Alternatively, you can start a pry session directly, without `dbg/2`\n  by calling `IEx.pry/0`.\n\n  IEx also allows you to set breakpoints to start pry sessions\n  on a given module, function, and arity you have no control of\n  via `IEx.break!/4`. Similar to pipelines in `dbg()`, `IEx.break!/4`\n  allows you to debug a function line by line and access its variables.\n  However, breakpoints do not contain information about imports and\n  aliases from the source code.\n\n  When using `dbg` or breakpoints with tests, remember to pass the\n  `--trace` to `mix test` to avoid running into timeouts:\n\n      $ iex -S mix test --trace\n      $ iex -S mix test path/to/file:line --trace\n\n  ## The User switch command\n\n  Besides the `BREAK` menu, one can type `Ctrl+G` to get to the\n  `User switch command` menu. When reached, you can type `h` to\n  get more information.\n\n  In this menu, developers are able to start new shells and\n  alternate between them. Let's give it a try:\n\n      User switch command\n       --> s iex\n       --> c\n\n  The command above will start a new shell and connect to it.\n  Create a new variable called `hello` and assign some value to it:\n\n      hello = :world\n\n  Now, let's roll back to the first shell:\n\n      User switch command\n       --> c 1\n\n  Now, try to access the `hello` variable again:\n\n      hello\n      ** (CompileError) undefined variable \"hello\"\n\n  The command above fails because we have switched shells.\n  Since shells are isolated from each other, you can't access the\n  variables defined in one shell from the other one.\n\n  The `User switch command` can also be used to terminate an existing\n  session, for example when the evaluator gets stuck in an infinite\n  loop or when you are stuck typing an expression:\n\n      User switch command\n       --> i\n       --> c\n\n  The `User switch command` menu also allows developers to connect to\n  remote shells using the `r` command. A topic which we will discuss next.\n\n  ## Remote shells\n\n  IEx allows you to connect to another node in two fashions.\n  First of all, we can only connect to a shell if we give names\n  both to the current shell and the shell we want to connect to.\n\n  Let's give it a try. First, start a new shell:\n\n      $ iex --sname foo\n      iex(foo@HOST)1>\n\n  The string between the parentheses in the prompt is the name\n  of your node. We can retrieve it by calling the `node/0`\n  function:\n\n      iex(foo@HOST)1> node()\n      :\"foo@HOST\"\n      iex(foo@HOST)2> Node.alive?()\n      true\n\n  For fun, let's define a simple module in this shell too:\n\n      iex(foo@HOST)3> defmodule Hello do\n      ...(foo@HOST)3>   def world, do: \"it works!\"\n      ...(foo@HOST)3> end\n\n  Now, let's start another shell, giving it a name as well:\n\n      $ iex --sname bar\n      iex(bar@HOST)1>\n\n  If we try to dispatch to `Hello.world/0`, it won't be available\n  as it was defined only in the other shell:\n\n      iex(bar@HOST)1> Hello.world()\n      ** (UndefinedFunctionError) undefined function Hello.world/0\n\n  However, we can connect to the other shell remotely. Open up\n  the `User switch command` prompt (Ctrl+G) and type:\n\n      User switch command\n       --> r 'foo@HOST' 'Elixir.IEx'\n       --> c\n\n  Now we are connected into the remote node, as the prompt shows us,\n  and we can access the information and modules defined over there:\n\n      iex(foo@HOST)1> Hello.world()\n      \"it works!\"\n\n  In fact, connecting to remote shells is so common that we provide\n  a shortcut via the command line as well:\n\n      $ iex --sname baz --remsh foo@HOST\n\n  Where \"remsh\" means \"remote shell\". In general, Elixir supports:\n\n    * remsh from an Elixir node to an Elixir node\n    * remsh from a plain Erlang node to an Elixir node (through the ^G menu)\n    * remsh from an Elixir node to a plain Erlang node (and get an `erl` shell there)\n\n  Connecting an Elixir shell to a remote node without Elixir is\n  **not** supported.\n\n  When remsh halts, the Elixir shell process exits with reason `:normal`.\n\n  ## The .iex.exs file\n\n  When starting, IEx looks for a configured path, then for a local `.iex.exs` file\n  (located in the current working directory), then for a global `.iex.exs` file\n  located inside the directory pointed by the `IEX_HOME` environment variable\n  (which defaults to `~`) and loads the first one it finds (if any).\n\n  The code in the chosen `.iex.exs` file is evaluated line by line in the shell's\n  context, as if each line were being typed in the shell. For instance, any modules\n  that are loaded or variables that are bound in the `.iex.exs` file will be available\n  in the shell after it has booted.\n\n  Take the following `.iex.exs` file:\n\n      # Load another \".iex.exs\" file\n      import_file(\"~/.iex.exs\")\n\n      # Import some module from lib that may not yet have been defined\n      import_if_available(MyApp.Mod)\n\n      # Print something before the shell starts\n      IO.puts(\"hello world\")\n\n      # Bind a variable that'll be accessible in the shell\n      value = 13\n\n  Running IEx in the directory where the above `.iex.exs` file is located\n  results in:\n\n      $ iex\n      Erlang/OTP 24 [...]\n\n      hello world\n      Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)\n      iex(1)> value\n      13\n\n  It is possible to load another file by configuring the `iex` application's `dot_iex`\n  value (`config :iex, dot_iex: \"PATH\"` or `IEx.configure(dot_iex: \"PATH\")`)\n  or supplying the `--dot-iex` option to IEx. See `iex --help`.\n\n  In case of remote nodes, the location of the `.iex.exs` files are taken\n  relative to the user that started the application, not to the user that\n  is connecting to the node in case of remote IEx connections.\n\n  ## Configuring the shell\n\n  There are a number of customization options provided by IEx. Take a look\n  at the docs for the `IEx.configure/1` function by typing `h IEx.configure/1`.\n\n  Those options can be configured in your project configuration file or globally\n  by calling `IEx.configure/1` from your `~/.iex.exs` file. For example:\n\n      # .iex.exs\n      IEx.configure(inspect: [limit: 3])\n\n  Now run the shell:\n\n      $ iex\n      Erlang/OTP 24 [...]\n\n      Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)\n      iex(1)> [1, 2, 3, 4, 5]\n      [1, 2, 3, ...]\n\n  \"\"\"\n\n  @typedoc \"\"\"\n  Color settings used by the IEx shell.\n  \"\"\"\n  @type colors_opts :: [\n          enabled: boolean(),\n          eval_result: IO.ANSI.ansidata(),\n          eval_info: IO.ANSI.ansidata(),\n          eval_error: IO.ANSI.ansidata(),\n          eval_interrupt: IO.ANSI.ansidata(),\n          stack_info: IO.ANSI.ansidata(),\n          blame_diff: IO.ANSI.ansidata(),\n          ls_directory: IO.ANSI.ansidata(),\n          ls_device: IO.ANSI.ansidata(),\n          doc_code: IO.ANSI.ansidata(),\n          doc_inline_code: IO.ANSI.ansidata(),\n          doc_headings: IO.ANSI.ansidata(),\n          doc_title: IO.ANSI.ansidata(),\n          doc_bold: IO.ANSI.ansidata(),\n          doc_underline: IO.ANSI.ansidata(),\n          syntax_colors: syntax_colors_opts() | false\n        ]\n\n  @typedoc \"\"\"\n  Syntax coloring settings for inspected expressions.\n  \"\"\"\n  @type syntax_colors_opts :: [\n          atom: IO.ANSI.ansidata(),\n          binary: IO.ANSI.ansidata(),\n          boolean: IO.ANSI.ansidata(),\n          charlist: IO.ANSI.ansidata(),\n          list: IO.ANSI.ansidata(),\n          map: IO.ANSI.ansidata(),\n          nil: IO.ANSI.ansidata(),\n          number: IO.ANSI.ansidata(),\n          string: IO.ANSI.ansidata(),\n          tuple: IO.ANSI.ansidata(),\n          variable: IO.ANSI.ansidata(),\n          call: IO.ANSI.ansidata(),\n          operator: IO.ANSI.ansidata(),\n          reset: IO.ANSI.ansidata()\n        ]\n\n  @typedoc \"\"\"\n  Inspect settings used by the IEx shell.\n  \"\"\"\n  @type inspect_opts :: [\n          base: :binary | :decimal | :octal | :hex,\n          binaries: :infer | :as_binaries | :as_strings,\n          charlists: :infer | :as_charlists | :as_lists,\n          custom_options: keyword(),\n          inspect_fun: (term(), Inspect.Opts.t() -> Inspect.Algebra.t()),\n          limit: pos_integer() | :infinity,\n          pretty: boolean(),\n          printable_limit: pos_integer() | :infinity,\n          safe: boolean(),\n          structs: boolean(),\n          syntax_colors: syntax_colors_opts(),\n          width: pos_integer() | :infinity\n        ]\n\n  @type configure_opts :: [\n          auto_reload: boolean(),\n          alive_prompt: String.t(),\n          colors: colors_opts(),\n          default_prompt: String.t(),\n          dot_iex: String.t() | nil,\n          history_size: integer(),\n          inspect: inspect_opts(),\n          parser: {module(), atom(), [any()]},\n          width: pos_integer()\n        ]\n\n  @doc \"\"\"\n  Configures IEx.\n\n  The supported options are:\n\n    * `:auto_reload`\n    * `:alive_prompt`\n    * `:colors`\n    * `:default_prompt`\n    * `:dot_iex`\n    * `:history_size`\n    * `:inspect`\n    * `:parser`\n    * `:width`\n\n  They are discussed individually in the sections below.\n\n  ## Colors\n\n  A keyword list that encapsulates all color settings used by the\n  shell. See documentation for the `IO.ANSI` module for the list of\n  supported colors and attributes.\n\n  List of supported keys in the keyword list:\n\n    * `:enabled` - boolean value that allows for switching the coloring on and off\n    * `:eval_result` - color for an expression's resulting value\n    * `:eval_info` - ... various informational messages\n    * `:eval_error` - ... error messages\n    * `:eval_interrupt` - ... interrupt messages\n    * `:stack_info` - ... the stacktrace color\n    * `:blame_diff` - ... when blaming source with no match\n    * `:ls_directory` - ... for directory entries (ls helper)\n    * `:ls_device` - ... device entries (ls helper)\n\n  When printing documentation, IEx will convert the Markdown\n  documentation to ANSI as well. Colors for this can be configured\n  via:\n\n    * `:doc_code`        - the attributes for code blocks (cyan, bright)\n    * `:doc_inline_code` - inline code (cyan)\n    * `:doc_headings`    - h1 and h2 (yellow, bright)\n    * `:doc_title`       - the overall heading for the output (reverse, yellow, bright)\n    * `:doc_bold`        - (bright)\n    * `:doc_underline`   - (underline)\n\n  IEx will also color inspected expressions using the `:syntax_colors`\n  option. Such can be disabled with:\n\n      IEx.configure(colors: [syntax_colors: false])\n\n  You can also configure the syntax colors, however, as desired.\n  The below will format atoms in red and remove the coloring for\n  all other data types:\n\n      IEx.configure(colors: [syntax_colors: [atom: :red]])\n\n  The default values can be found in `IO.ANSI.syntax_colors/0`.\n\n  ## Inspect\n\n  A keyword list containing inspect options used by the shell\n  when printing results of expression evaluation. Defaults to\n  pretty formatting with a limit of 50 entries.\n\n  To show all entries, configure the limit to `:infinity`:\n\n      IEx.configure(inspect: [limit: :infinity])\n\n  See `Inspect.Opts` for the full list of options.\n\n  ## Width\n\n  An integer indicating the maximum number of columns to use in output.\n  The default value is 80 columns. The actual output width is the minimum\n  of this number and result of `:io.columns`. This way you can configure IEx\n  to be your largest screen size and it should always take up the full width\n  of your current terminal screen.\n\n  ## History size\n\n  Number of expressions and their results to keep in the history.\n  The value is an integer. When it is negative, the history is unlimited.\n\n  ## Prompt\n\n  This is an option determining the prompt displayed to the user\n  when awaiting input.\n\n  The value is a keyword list with two possible keys representing prompt types:\n\n    * `:default_prompt` - used when `Node.alive?/0` returns `false`\n\n    * `:alive_prompt` - used when `Node.alive?/0` returns `true`\n\n  The following values in the prompt string will be replaced appropriately:\n\n    * `%counter` - the index of the history\n    * `%prefix`  - a prefix given by `IEx.Server`\n    * `%node`    - the name of the local node\n\n  ## Parser\n\n  This is an option determining the parser to use for IEx.\n\n  The parser is a \"mfargs\", which is a tuple with three elements:\n  the module name, the function name, and extra arguments to\n  be appended. The parser receives at least three arguments, the\n  current input as a charlist, the parsing options as a keyword list,\n  and the state. The initial state is an empty charlist. It must\n  return `{:ok, expr, state}` or `{:incomplete, state}`.\n\n  If the parser raises, the state is reset to an empty charlist.\n\n  > In earlier Elixir versions, the parser would receive the input\n  > and the initial buffer as strings. However, this behaviour\n  > changed when Erlang/OTP introduced multiline editing. If you\n  > support earlier Elixir versions, you can normalize the inputs\n  > by calling `to_charlist/1`.\n\n  ## `.iex`\n\n  Configure the file loaded into your IEx session when it starts.\n  See more information [in the `.iex.exs` documentation](`m:IEx#module-the-iex-exs-file`).\n\n  ## Auto reloading\n\n  When set to `true`, the `:auto_reload` option automatically purges\n  in-memory modules when they get invalidated by a concurrent compilation\n  happening in the Operating System.\n  \"\"\"\n  @spec configure(configure_opts) :: :ok\n  def configure(options) do\n    IEx.Config.configure(options)\n  end\n\n  @doc \"\"\"\n  Returns IEx configuration.\n  \"\"\"\n  @spec configuration() :: keyword()\n  def configuration do\n    IEx.Config.configuration()\n  end\n\n  @doc false\n  @deprecated \"The functionality is no longer supported\"\n  def after_spawn(fun) when is_function(fun) do\n    IEx.Config.after_spawn(fun)\n  end\n\n  @doc false\n  @deprecated \"The functionality is no longer supported\"\n  def after_spawn do\n    IEx.Config.after_spawn()\n  end\n\n  @doc \"\"\"\n  Returns `true` if IEx was started, `false` otherwise.\n\n  This means the IEx application was started, but not\n  that its CLI interface is running.\n  \"\"\"\n  @spec started?() :: boolean()\n  def started? do\n    IEx.Config.started?()\n  end\n\n  @doc \"\"\"\n  Returns `string` escaped using the specified `color`.\n\n  ANSI escapes in `string` are not processed in any way.\n  \"\"\"\n  @spec color(atom(), iodata()) :: iodata()\n  def color(color, string) do\n    case IEx.Config.color(color) do\n      nil ->\n        string\n\n      ansi ->\n        [ansi | string] |> IO.ANSI.format(true) |> IO.iodata_to_binary()\n    end\n  end\n\n  @doc \"\"\"\n  Returns the IEx width for printing.\n\n  Used by helpers and it has a default maximum cap of 80 chars.\n  \"\"\"\n  @spec width() :: pos_integer()\n  def width do\n    IEx.Config.width()\n  end\n\n  @doc \"\"\"\n  Returns the options used for inspecting.\n  \"\"\"\n  @spec inspect_opts() :: keyword()\n  def inspect_opts do\n    IEx.Config.inspect_opts()\n  end\n\n  @doc \"\"\"\n  Pries into the process environment.\n\n  This function is useful for debugging a particular chunk of code\n  when executed by a particular process. The process becomes\n  the evaluator of IEx commands and is temporarily changed to\n  have a custom group leader. Those values are reverted by\n  calling `IEx.Helpers.respawn/0`, which starts a new IEx shell,\n  freeing up the pried one.\n\n  When a process is pried, all code runs inside IEx and has\n  access to all imports and aliases from the original code.\n  However, you cannot change the execution of the code nor\n  access private functions of the module being pried. Module\n  functions still need to be accessed via `Mod.fun(args)`.\n\n  See also `break!/4` for others ways to pry.\n\n  > #### `dbg/0` integration\n  >\n  > By calling `iex --dbg pry`, `iex` will set this function\n  > as the default backend for `dbg/0` calls.\n\n  ## Examples\n\n  Let's suppose you want to investigate what is happening\n  with some particular function. By invoking `IEx.pry/0` from\n  the function, IEx will allow you to access its binding\n  (variables), verify its lexical information and access\n  the process information. Let's see an example:\n\n      import Enum, only: [map: 2]\n\n      defmodule Adder do\n        def add(a, b) do\n          c = a + b\n          require IEx; IEx.pry()\n        end\n      end\n\n  When invoking `Adder.add(1, 2)`, you will receive a message in\n  your shell to pry the given environment. By allowing it,\n  the shell will be reset and you gain access to all variables\n  and the lexical scope from above:\n\n      iex(1)> map([a, b, c], &IO.inspect(&1))\n      1\n      2\n      3\n\n  Keep in mind that `IEx.pry/0` runs in the caller process,\n  blocking the caller during the evaluation cycle. The caller\n  process can be freed by calling [`respawn/0`](`IEx.Helpers.respawn/0`), which starts a\n  new IEx evaluation cycle, letting this one go:\n\n      iex(2)> respawn()\n      true\n\n      Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)\n\n  Setting variables or importing modules in IEx does not\n  affect the caller's environment. However, sending and\n  receiving messages will change the process state.\n\n  ## Pry and macros\n\n  When setting up Pry inside a code defined by macros, such as:\n\n      defmacro __using__(_) do\n        quote do\n          def add(a, b) do\n            c = a + b\n            require IEx; IEx.pry()\n          end\n        end\n      end\n\n  The variables defined inside `quote` won't be available during\n  prying due to the hygiene mechanism in quoted expressions. The\n  hygiene mechanism changes the variable names in quoted expressions\n  so they don't collide with variables defined by the users of the\n  macros. Therefore the original names are not available.\n\n  ## Pry and `mix test`\n\n  To use `IEx.pry/0` during tests, you need to run `mix` inside\n  the `iex` command and pass the `--trace` to `mix test` to avoid running\n  into timeouts:\n\n      $ iex -S mix test --trace\n      $ iex -S mix test path/to/file:line --trace\n\n  \"\"\"\n  defmacro pry() do\n    quote do\n      IEx.Pry.pry(binding(), __ENV__)\n    end\n  end\n\n  @doc \"\"\"\n  Macro-based shortcut for `IEx.break!/4`.\n  \"\"\"\n  @doc since: \"1.5.0\"\n  defmacro break!(ast, stops \\\\ 1) do\n    quote do\n      IEx.__break__!(unquote(Macro.escape(ast)), unquote(Macro.escape(stops)), __ENV__)\n    end\n  end\n\n  def __break__!({:/, _, [call, arity]} = ast, stops, env) when arity in 0..255 do\n    with {module, fun, []} <- Macro.decompose_call(call),\n         module when is_atom(module) <- Macro.expand(module, env) do\n      IEx.Pry.break!(module, fun, arity, stops)\n    else\n      _ ->\n        raise_unknown_break_ast!(ast)\n    end\n  end\n\n  def __break__!({{:., _, [module, fun]}, _, args} = ast, stops, env) do\n    __break__!(ast, module, fun, args, true, stops, env)\n  end\n\n  def __break__!({:when, _, [{{:., _, [module, fun]}, _, args}, guards]} = ast, stops, env) do\n    __break__!(ast, module, fun, args, guards, stops, env)\n  end\n\n  def __break__!(ast, _stops) do\n    raise_unknown_break_ast!(ast)\n  end\n\n  defp __break__!(ast, module, fun, args, guards, stops, env) do\n    module = Macro.expand(module, env)\n\n    if not is_atom(module) do\n      raise_unknown_break_ast!(ast)\n    end\n\n    IEx.Pry.break!(module, fun, args, guards, env, stops)\n  end\n\n  defp raise_unknown_break_ast!(ast) do\n    raise ArgumentError, \"\"\"\n    unknown expression to break on, expected one of:\n\n      * Mod.fun/arity, such as: URI.parse/1\n      * Mod.fun(arg1, arg2, ...), such as: URI.parse(_)\n      * Mod.fun(arg1, arg2, ...) when guard, such as: URI.parse(var) when is_binary(var)\n\n    Got #{Macro.to_string(ast)}\n    \"\"\"\n  end\n\n  @doc \"\"\"\n  Sets up a breakpoint in `module`, `function` and `arity` with\n  the given number of `stops`.\n\n  This function will instrument the given module and load a new\n  version in memory with line by line breakpoints at the given\n  function and arity. If the module is recompiled, all breakpoints\n  are lost.\n\n  When a breakpoint is reached, IEx will ask if you want to `pry`\n  the given function and arity. In other words, this works similar\n  to `IEx.pry/0` as the running process becomes the evaluator of\n  IEx commands and is temporarily changed to have a custom group\n  leader. However, differently from `IEx.pry/0`, aliases and imports\n  from the source code won't be available in the shell.\n\n  IEx helpers includes many conveniences related to breakpoints.\n  Below they are listed with the full module, such as `IEx.Helpers.breaks/0`,\n  but remember it can be called directly as `breaks()` inside IEx.\n  They are:\n\n    * `IEx.Helpers.break!/2` - sets up a breakpoint for a given `Mod.fun/arity`\n    * `IEx.Helpers.break!/4` - sets up a breakpoint for the given module, function, arity\n    * `IEx.Helpers.breaks/0` - prints all breakpoints and their IDs\n    * `IEx.Helpers.continue/0` - continues until the next breakpoint in the same shell\n    * `IEx.Helpers.n/0` - goes to the next line of the current breakpoint\n    * `IEx.Helpers.next/0` - same as above\n    * `IEx.Helpers.open/0` - opens editor on the current breakpoint\n    * `IEx.Helpers.remove_breaks/0` - removes all breakpoints in all modules\n    * `IEx.Helpers.remove_breaks/1` - removes all breakpoints in a given module\n    * `IEx.Helpers.reset_break/1` - sets the number of stops on the given ID to zero\n    * `IEx.Helpers.reset_break/3` - sets the number of stops on the given module, function, arity to zero\n    * `IEx.Helpers.respawn/0` - starts a new shell (breakpoints will ask for permission once more)\n    * `IEx.Helpers.whereami/1` - shows the current location\n\n  By default, the number of stops in a breakpoint is 1. Any follow-up\n  call won't stop the code execution unless another breakpoint is set.\n\n  Alternatively, the number of stops can be increased by passing the `stops`\n  argument. `IEx.Helpers.reset_break/1` and `IEx.Helpers.reset_break/3`\n  can be used to reset the number back to zero. Note the module remains\n  \"instrumented\" even after all stops on all breakpoints are consumed.\n  You can remove the instrumentation in a given module by calling\n  `IEx.Helpers.remove_breaks/1` and on all modules by calling\n  `IEx.Helpers.remove_breaks/0`.\n\n  Within a breakpoint, you can call `n` to jump to the next line.\n  To exit a breakpoint, you can either invoke `continue`, which will\n  block the shell until the next breakpoint is found or the process\n  terminates, or invoke `respawn`, which starts a new IEx shell,\n  freeing up the pried one.\n\n  ## Examples\n\n  The examples below will use `break!`, assuming that you are setting\n  a breakpoint directly from your IEx shell. But you can set up a break\n  from anywhere by using the fully qualified name `IEx.break!`.\n\n  The following sets up a breakpoint on `URI.parse/1`:\n\n      break! URI, :parse, 1\n\n  This call will setup a breakpoint that stops once.\n  To set a breakpoint that will stop 10 times:\n\n      break! URI, :parse, 1, 10\n\n  `IEx.break!/2` is a convenience macro that allows breakpoints\n  to be given in the `Mod.fun/arity` format:\n\n      break! URI.parse/1\n\n  Or to set a breakpoint that will stop 10 times:\n\n      break! URI.parse/1, 10\n\n  This function returns the breakpoint ID and will raise if there\n  is an error setting up the breakpoint.\n\n  ## Patterns and guards\n\n  `IEx.break!/2` allows patterns to be given, triggering the\n  breakpoint only in some occasions. For example, to trigger\n  the breakpoint only when the first argument starts with the\n  \"https\" string:\n\n      break! URI.parse(\"https\" <> _, _)\n\n  Only a single break point can be set per function. So if you call\n  `IEx.break!` multiple times with different patterns, only the last\n  pattern is kept.\n\n  ## Macros\n\n  While it is possible to set breakpoint in macros, remember that macros\n  are generally expanded at compilation time, and therefore they may never\n  be invoked during runtime. Similarly, while patterns may be given to\n  macros, macros receive ASTs as arguments, and not values. For example,\n  if you try to break on a macro with the following pattern:\n\n      break! MyModule.some_macro(pid) when pid == self()\n\n  This breakpoint will never be reached, because a macro never receives\n  a PID. Even if you call the macro as `MyModule.some_macro(self())`,\n  the macro will receive the AST representing the `self()` call, and not\n  the PID itself.\n\n  ## Breaks and `mix test`\n\n  To use `IEx.break!/4` during tests, you need to run `mix` inside\n  the `iex` command and pass the `--trace` to `mix test` to avoid running\n  into timeouts:\n\n      $ iex -S mix test --trace\n      $ iex -S mix test path/to/file:line --trace\n\n  \"\"\"\n  @doc since: \"1.5.0\"\n  @spec break!(module, atom, arity, non_neg_integer) :: IEx.Pry.id()\n  defdelegate break!(module, function, arity, stops \\\\ 1), to: IEx.Pry\n\n  @doc false\n  def dont_display_result, do: :\"do not show this result in output\"\nend\n"
  },
  {
    "path": "lib/iex/mix.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule IEx.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :iex,\n      version: System.version(),\n      build_per_environment: false\n    ]\n  end\n\n  def application do\n    [\n      registered: [IEx.Broker, IEx.Config, IEx.Pry, IEx.Supervisor],\n      mod: {IEx.App, []},\n      env: [\n        colors: [],\n        inspect: [pretty: true],\n        history_size: 20,\n        default_prompt: \"%prefix(%counter)>\",\n        alive_prompt: \"%prefix(%node)%counter>\",\n        auto_reload: false\n      ]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/iex/test/iex/autocomplete_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule IEx.AutocompleteTest do\n  use ExUnit.Case, async: true\n\n  setup do\n    evaluator = IEx.Server.start_evaluator(1, [])\n    Process.put(:evaluator, evaluator)\n    :ok\n  end\n\n  defp eval(line) do\n    ExUnit.CaptureIO.capture_io(fn ->\n      evaluator = Process.get(:evaluator)\n      Process.group_leader(evaluator, Process.group_leader())\n      send(evaluator, {:eval, self(), Code.string_to_quoted!(line <> \"\\n\"), 1})\n      assert_receive {:evaled, _, _}\n    end)\n  end\n\n  defp expand(expr) do\n    IEx.Autocomplete.expand(Enum.reverse(expr), self())\n  end\n\n  test \"Erlang module completion\" do\n    assert expand(~c\":zl\") == {:yes, ~c\"ib\", []}\n  end\n\n  test \"Erlang module no completion\" do\n    assert expand(~c\":unknown\") == {:no, ~c\"\", []}\n  end\n\n  test \"Erlang module multiple values completion\" do\n    {:yes, ~c\"\", list} = expand(~c\":logger\")\n    assert ~c\"logger\" in list\n    assert ~c\"logger_proxy\" in list\n  end\n\n  test \"Erlang root completion\" do\n    {:yes, ~c\"\", list} = expand(~c\":\")\n    assert is_list(list)\n    assert ~c\"lists\" in list\n    assert ~c\"Elixir.List\" not in list\n  end\n\n  test \"Elixir proxy\" do\n    {:yes, ~c\"\", list} = expand(~c\"E\")\n    assert ~c\"Elixir\" in list\n  end\n\n  test \"Elixir completion\" do\n    assert expand(~c\"En\") == {:yes, ~c\"um\", []}\n    assert expand(~c\"Enumera\") == {:yes, ~c\"ble\", []}\n  end\n\n  test \"Elixir type completion\" do\n    assert expand(~c\"t :gen_ser\") == {:yes, ~c\"ver\", []}\n    assert expand(~c\"t String\") == {:yes, ~c\"\", [~c\"String\", ~c\"StringIO\"]}\n\n    assert expand(~c\"t String.\") ==\n             {:yes, ~c\"\",\n              [\n                ~c\"codepoint/0\",\n                ~c\"grapheme/0\",\n                ~c\"pattern/0\",\n                ~c\"replace_opts/0\",\n                ~c\"split_opts/0\",\n                ~c\"splitter_opts/0\",\n                ~c\"t/0\"\n              ]}\n\n    assert expand(~c\"t String.grap\") == {:yes, ~c\"heme\", []}\n    assert expand(~c\"t  String.grap\") == {:yes, ~c\"heme\", []}\n    assert {:yes, ~c\"\", [~c\"date_time/0\" | _]} = expand(~c\"t :file.\")\n    assert expand(~c\"t :file.n\") == {:yes, ~c\"ame\", []}\n  end\n\n  test \"Elixir callback completion\" do\n    assert expand(~c\"b :strin\") == {:yes, ~c\"g\", []}\n    assert expand(~c\"b String\") == {:yes, ~c\"\", [~c\"String\", ~c\"StringIO\"]}\n    assert expand(~c\"b String.\") == {:no, ~c\"\", []}\n    assert expand(~c\"b Access.\") == {:yes, ~c\"\", [~c\"fetch/2\", ~c\"get_and_update/3\", ~c\"pop/2\"]}\n    assert expand(~c\"b GenServer.term\") == {:yes, ~c\"inate\", []}\n    assert expand(~c\"b   GenServer.term\") == {:yes, ~c\"inate\", []}\n    assert expand(~c\"b :gen_server.handle_in\") == {:yes, ~c\"fo\", []}\n  end\n\n  test \"Elixir helper completion with parentheses\" do\n    assert expand(~c\"t(:gen_ser\") == {:yes, ~c\"ver\", []}\n    assert expand(~c\"t(String\") == {:yes, ~c\"\", [~c\"String\", ~c\"StringIO\"]}\n\n    assert expand(~c\"t(String.\") ==\n             {:yes, ~c\"\",\n              [\n                ~c\"codepoint/0\",\n                ~c\"grapheme/0\",\n                ~c\"pattern/0\",\n                ~c\"replace_opts/0\",\n                ~c\"split_opts/0\",\n                ~c\"splitter_opts/0\",\n                ~c\"t/0\"\n              ]}\n\n    assert expand(~c\"t(String.grap\") == {:yes, ~c\"heme\", []}\n  end\n\n  test \"Elixir completion with self\" do\n    assert expand(~c\"Enumerable\") == {:yes, ~c\".\", []}\n  end\n\n  test \"Elixir completion on modules from load path\" do\n    assert expand(~c\"Str\") == {:yes, [], [~c\"Stream\", ~c\"String\", ~c\"StringIO\"]}\n    assert expand(~c\"Ma\") == {:yes, ~c\"\", [~c\"Macro\", ~c\"Map\", ~c\"MapSet\", ~c\"MatchError\"]}\n    assert expand(~c\"Dic\") == {:yes, ~c\"t\", []}\n    assert expand(~c\"Ex\") == {:yes, [], [~c\"ExUnit\", ~c\"Exception\"]}\n  end\n\n  test \"Elixir no completion for underscored functions with no doc\" do\n    {:module, _, bytecode, _} =\n      defmodule Elixir.Sample do\n        def __foo__(), do: 0\n        @doc \"Bar doc\"\n        def __bar__(), do: 1\n      end\n\n    File.write!(\"Elixir.Sample.beam\", bytecode)\n    assert {:docs_v1, _, _, _, _, _, _} = Code.fetch_docs(Sample)\n    assert expand(~c\"Sample._\") == {:yes, ~c\"_bar__\", []}\n  after\n    File.rm(\"Elixir.Sample.beam\")\n    :code.purge(Sample)\n    :code.delete(Sample)\n  end\n\n  test \"Elixir no completion for default argument functions with doc set to false\" do\n    {:yes, ~c\"\", available} = expand(~c\"String.\")\n    refute Enum.member?(available, ~c\"rjust/2\")\n    assert Enum.member?(available, ~c\"replace/3\")\n\n    assert expand(~c\"String.r\") == {:yes, ~c\"e\", []}\n\n    {:module, _, bytecode, _} =\n      defmodule Elixir.DefaultArgumentFunctions do\n        def foo(a \\\\ :a, b, c \\\\ :c), do: {a, b, c}\n\n        def _do_fizz(a \\\\ :a, b, c \\\\ :c), do: {a, b, c}\n\n        @doc false\n        def __fizz__(a \\\\ :a, b, c \\\\ :c), do: {a, b, c}\n\n        @doc \"bar/0 doc\"\n        def bar(), do: :bar\n        @doc false\n        def bar(a \\\\ :a, b, c \\\\ :c, d \\\\ :d), do: {a, b, c, d}\n        @doc false\n        def bar(a, b, c, d, e), do: {a, b, c, d, e}\n\n        @doc false\n        def baz(a \\\\ :a), do: {a}\n\n        @doc \"biz/3 doc\"\n        def biz(a, b, c \\\\ :c), do: {a, b, c}\n      end\n\n    File.write!(\"Elixir.DefaultArgumentFunctions.beam\", bytecode)\n    assert {:docs_v1, _, _, _, _, _, _} = Code.fetch_docs(DefaultArgumentFunctions)\n\n    functions_list = [~c\"bar/0\", ~c\"biz/2\", ~c\"biz/3\", ~c\"foo/1\", ~c\"foo/2\", ~c\"foo/3\"]\n    assert expand(~c\"DefaultArgumentFunctions.\") == {:yes, ~c\"\", functions_list}\n\n    assert expand(~c\"DefaultArgumentFunctions.bi\") == {:yes, ~c\"z\", []}\n\n    assert expand(~c\"DefaultArgumentFunctions.foo\") ==\n             {:yes, ~c\"\", [~c\"foo/1\", ~c\"foo/2\", ~c\"foo/3\"]}\n  after\n    File.rm(\"Elixir.DefaultArgumentFunctions.beam\")\n    :code.purge(DefaultArgumentFunctions)\n    :code.delete(DefaultArgumentFunctions)\n  end\n\n  test \"Elixir no completion\" do\n    assert expand(~c\".\") == {:no, ~c\"\", []}\n    assert expand(~c\"Xyz\") == {:no, ~c\"\", []}\n    assert expand(~c\"x.Foo\") == {:no, ~c\"\", []}\n    assert expand(~c\"x.Foo.get_by\") == {:no, ~c\"\", []}\n    assert expand(~c\"@foo.bar\") == {:no, ~c\"\", []}\n  end\n\n  test \"Elixir root submodule completion\" do\n    assert expand(~c\"Elixir.Acce\") == {:yes, ~c\"ss\", []}\n  end\n\n  test \"Elixir submodule completion\" do\n    assert expand(~c\"String.Cha\") == {:yes, ~c\"rs\", []}\n  end\n\n  test \"Elixir submodule no completion\" do\n    assert expand(~c\"IEx.Xyz\") == {:no, ~c\"\", []}\n  end\n\n  test \"block keywords\" do\n    assert expand(~c\"if true do\") == {:yes, ~c\"\", [~c\"do\"]}\n    assert expand(~c\"if true a\") == {:yes, ~c\"\", [~c\"after\", ~c\"and/2\"]}\n    assert expand(~c\"if true d\") == {:yes, ~c\"o\", []}\n    assert expand(~c\"if true e\") == {:yes, ~c\"\", [~c\"end\", ~c\"else\"]}\n  end\n\n  test \"block keywords or operators\" do\n    {:yes, ~c\"\", hints} = expand(~c\"if true \")\n    assert ~c\"do\" in hints\n    assert ~c\"else\" in hints\n    assert ~c\"+/2\" in hints\n    assert ~c\"and/2\" in hints\n  end\n\n  test \"function completion\" do\n    assert expand(~c\"System.ve\") == {:yes, ~c\"rsion\", []}\n    assert expand(~c\":ets.fun2\") == {:yes, ~c\"ms\", []}\n  end\n\n  test \"function completion with groups\" do\n    {:yes, ~c\"\", [exports, guards]} = expand(~c\"Kernel.i\")\n    assert %{title: ~c\"Exports\", elems: [~c\"if/2\", ~c\"inspect/1\", ~c\"inspect/2\"]} = exports\n    assert %{title: ~c\"Guards\", elems: [_ | _]} = guards\n\n    {:yes, ~c\"\", [guards, exports]} = expand(~c\"Kernel.in\")\n    assert %{title: ~c\"Guards\", elems: [~c\"in/2\"]} = guards\n    assert %{title: ~c\"Exports\", elems: [~c\"inspect/1\", ~c\"inspect/2\"]} = exports\n  end\n\n  test \"function completion with arity\" do\n    assert expand(~c\"String.printable?\") == {:yes, ~c\"\", [~c\"printable?/1\", ~c\"printable?/2\"]}\n    assert expand(~c\"String.printable?/\") == {:yes, ~c\"\", [~c\"printable?/1\", ~c\"printable?/2\"]}\n\n    assert expand(~c\"Enum.count\") ==\n             {:yes, ~c\"\", [~c\"count/1\", ~c\"count/2\", ~c\"count_until/2\", ~c\"count_until/3\"]}\n\n    assert expand(~c\"Enum.count/\") == {:yes, ~c\"\", [~c\"count/1\", ~c\"count/2\"]}\n  end\n\n  test \"operator completion\" do\n    assert expand(~c\"+\") == {:yes, ~c\"\", [~c\"+/1\", ~c\"+/2\", ~c\"++/2\"]}\n    assert expand(~c\"+/\") == {:yes, ~c\"\", [~c\"+/1\", ~c\"+/2\"]}\n    assert expand(~c\"++/\") == {:yes, ~c\"\", [~c\"++/2\"]}\n  end\n\n  test \"sigil completion\" do\n    {:yes, ~c\"\", sigils} = expand(~c\"~\")\n    assert ~c\"~C (sigil_C)\" in sigils\n    {:yes, ~c\"\", sigils} = expand(~c\"~r\")\n    assert ~c\"\\\"\" in sigils\n    assert ~c\"(\" in sigils\n  end\n\n  test \"function completion using a variable bound to a module\" do\n    eval(\"mod = String\")\n    assert expand(~c\"mod.print\") == {:yes, ~c\"able?\", []}\n  end\n\n  test \"map atom key completion is supported\" do\n    eval(\"map = %{foo: 1, bar_1: 23, bar_2: 14}\")\n    assert expand(~c\"map.f\") == {:yes, ~c\"oo\", []}\n    assert expand(~c\"map.b\") == {:yes, ~c\"ar_\", []}\n    assert expand(~c\"map.bar_\") == {:yes, ~c\"\", [~c\"bar_1\", ~c\"bar_2\"]}\n    assert expand(~c\"map.c\") == {:no, ~c\"\", []}\n    assert expand(~c\"map.\") == {:yes, ~c\"\", [~c\"bar_1\", ~c\"bar_2\", ~c\"foo\"]}\n    assert expand(~c\"map.foo\") == {:no, ~c\"\", []}\n  end\n\n  test \"nested map atom key completion is supported\" do\n    eval(\"map = %{nested: %{deeply: %{foo: 1, bar_1: 23, bar_2: 14, mod: String, num: 1}}}\")\n    assert expand(~c\"map.nested.deeply.f\") == {:yes, ~c\"oo\", []}\n    assert expand(~c\"map.nested.deeply.b\") == {:yes, ~c\"ar_\", []}\n    assert expand(~c\"map.nested.deeply.bar_\") == {:yes, ~c\"\", [~c\"bar_1\", ~c\"bar_2\"]}\n\n    assert expand(~c\"map.nested.deeply.\") ==\n             {:yes, ~c\"\", [~c\"bar_1\", ~c\"bar_2\", ~c\"foo\", ~c\"mod\", ~c\"num\"]}\n\n    assert expand(~c\"map.nested.deeply.mod.print\") == {:yes, ~c\"able?\", []}\n\n    assert expand(~c\"map.nested\") == {:yes, ~c\".\", []}\n    assert expand(~c\"map.nested.deeply\") == {:yes, ~c\".\", []}\n    assert expand(~c\"map.nested.deeply.foo\") == {:no, ~c\"\", []}\n\n    assert expand(~c\"map.nested.deeply.c\") == {:no, ~c\"\", []}\n    assert expand(~c\"map.a.b.c.f\") == {:no, ~c\"\", []}\n  end\n\n  test \"map string key completion is not supported\" do\n    eval(~S(map = %{\"foo\" => 1}))\n    assert expand(~c\"map.f\") == {:no, ~c\"\", []}\n  end\n\n  test \"bound variables for modules and maps\" do\n    eval(\"num = 5; map = %{nested: %{num: 23}}\")\n    assert expand(~c\"num.print\") == {:no, ~c\"\", []}\n    assert expand(~c\"map.nested.num.f\") == {:no, ~c\"\", []}\n    assert expand(~c\"map.nested.num.key.f\") == {:no, ~c\"\", []}\n  end\n\n  test \"access syntax is not supported\" do\n    eval(\"map = %{nested: %{deeply: %{num: 23}}}\")\n    assert expand(~c\"map[:nested][:deeply].n\") == {:no, ~c\"\", []}\n    assert expand(~c\"map[:nested].deeply.n\") == {:no, ~c\"\", []}\n    assert expand(~c\"map.nested.[:deeply].n\") == {:no, ~c\"\", []}\n  end\n\n  test \"unbound variables is not supported\" do\n    eval(\"num = 5\")\n    assert expand(~c\"other_var.f\") == {:no, ~c\"\", []}\n    assert expand(~c\"a.b.c.d\") == {:no, ~c\"\", []}\n  end\n\n  test \"macro completion\" do\n    {:yes, ~c\"\", list} = expand(~c\"Kernel.is_\")\n    assert is_list(list)\n  end\n\n  test \"imports completion\" do\n    {:yes, ~c\"\", list} = expand(~c\"\")\n    assert is_list(list)\n    assert ~c\"h/1\" in list\n    assert ~c\"unquote/1\" in list\n    assert ~c\"pwd/0\" in list\n  end\n\n  test \"kernel import completion\" do\n    assert expand(~c\"defstru\") == {:yes, ~c\"ct\", []}\n    assert expand(~c\"put_\") == {:yes, ~c\"\", [~c\"put_elem/3\", ~c\"put_in/2\", ~c\"put_in/3\"]}\n  end\n\n  test \"variable name completion\" do\n    eval(\"numeral = 3; number = 3; nothing = nil\")\n    assert expand(~c\"numb\") == {:yes, ~c\"er\", []}\n    assert expand(~c\"num\") == {:yes, ~c\"\", [~c\"number\", ~c\"numeral\"]}\n    assert expand(~c\"no\") == {:yes, ~c\"\", [~c\"nothing\", ~c\"node/0\", ~c\"node/1\", ~c\"not/1\"]}\n  end\n\n  test \"completion of manually imported functions and macros\" do\n    eval(\"import Enum; import Supervisor, only: [count_children: 1]; import Protocol\")\n\n    assert expand(~c\"der\") == {:yes, ~c\"ive\", []}\n\n    assert expand(~c\"take\") ==\n             {:yes, ~c\"\", [~c\"take/2\", ~c\"take_every/2\", ~c\"take_random/2\", ~c\"take_while/2\"]}\n\n    assert expand(~c\"take/\") == {:yes, ~c\"\", [~c\"take/2\"]}\n\n    assert expand(~c\"count\") ==\n             {:yes, ~c\"\",\n              [\n                ~c\"count/1\",\n                ~c\"count/2\",\n                ~c\"count_children/1\",\n                ~c\"count_until/2\",\n                ~c\"count_until/3\"\n              ]}\n\n    assert expand(~c\"count/\") == {:yes, ~c\"\", [~c\"count/1\", ~c\"count/2\"]}\n  end\n\n  defmacro define_var do\n    quote(do: var!(my_var_1, Elixir) = 1)\n  end\n\n  test \"ignores quoted variables when performing variable completion\" do\n    eval(\"require #{__MODULE__}; #{__MODULE__}.define_var(); my_var_2 = 2\")\n    assert expand(~c\"my_var\") == {:yes, ~c\"_2\", []}\n  end\n\n  test \"kernel special form completion\" do\n    assert expand(~c\"unquote_spl\") == {:yes, ~c\"icing\", []}\n  end\n\n  test \"completion inside expression\" do\n    assert expand(~c\"1 En\") == {:yes, ~c\"um\", []}\n    assert expand(~c\"Test(En\") == {:yes, ~c\"um\", []}\n    assert expand(~c\"Test :zl\") == {:yes, ~c\"ib\", []}\n    assert expand(~c\"[:zl\") == {:yes, ~c\"ib\", []}\n    assert expand(~c\"{:zl\") == {:yes, ~c\"ib\", []}\n  end\n\n  defmodule SublevelTest.LevelA.LevelB do\n  end\n\n  test \"Elixir completion sublevel\" do\n    assert expand(~c\"IEx.AutocompleteTest.SublevelTest.\") == {:yes, ~c\"LevelA\", []}\n  end\n\n  test \"complete aliases of Elixir modules\" do\n    eval(\"alias List, as: MyList\")\n    assert expand(~c\"MyL\") == {:yes, ~c\"ist\", []}\n    assert expand(~c\"MyList\") == {:yes, ~c\".\", []}\n    assert expand(~c\"MyList.to_integer\") == {:yes, [], [~c\"to_integer/1\", ~c\"to_integer/2\"]}\n  end\n\n  test \"complete aliases of Erlang modules\" do\n    eval(\"alias :lists, as: EList\")\n    assert expand(~c\"EL\") == {:yes, ~c\"ist\", []}\n    assert expand(~c\"EList\") == {:yes, ~c\".\", []}\n    assert expand(~c\"EList.map\") == {:yes, [], [~c\"map/2\", ~c\"mapfoldl/3\", ~c\"mapfoldr/3\"]}\n  end\n\n  test \"completion for functions added when compiled module is reloaded\" do\n    {:module, _, bytecode, _} =\n      defmodule Sample do\n        def foo(), do: 0\n      end\n\n    File.write!(\"Elixir.IEx.AutocompleteTest.Sample.beam\", bytecode)\n    assert {:docs_v1, _, _, _, _, _, _} = Code.fetch_docs(Sample)\n    assert expand(~c\"IEx.AutocompleteTest.Sample.foo\") == {:yes, ~c\"\", [~c\"foo/0\"]}\n\n    Code.compiler_options(ignore_module_conflict: true)\n\n    defmodule Sample do\n      def foo(), do: 0\n      def foobar(), do: 0\n    end\n\n    assert expand(~c\"IEx.AutocompleteTest.Sample.foo\") == {:yes, ~c\"\", [~c\"foo/0\", ~c\"foobar/0\"]}\n  after\n    File.rm(\"Elixir.IEx.AutocompleteTest.Sample.beam\")\n    Code.compiler_options(ignore_module_conflict: false)\n    :code.purge(Sample)\n    :code.delete(Sample)\n  end\n\n  defmodule MyStruct do\n    defstruct [:my_val]\n  end\n\n  test \"completion for struct names\" do\n    assert {:yes, ~c\"\", entries} = expand(~c\"%\")\n    assert ~c\"URI\" in entries\n    assert ~c\"IEx.History\" in entries\n    assert ~c\"IEx.Server\" in entries\n\n    assert {:yes, ~c\"\", entries} = expand(~c\"%IEx.\")\n    assert ~c\"IEx.History\" in entries\n    assert ~c\"IEx.Server\" in entries\n\n    assert expand(~c\"%IEx.AutocompleteTe\") == {:yes, ~c\"st.MyStruct{\", []}\n    assert expand(~c\"%IEx.AutocompleteTest.MyStr\") == {:yes, ~c\"uct{\", []}\n\n    eval(\"alias IEx.AutocompleteTest.MyStruct\")\n    assert expand(~c\"%MyStr\") == {:yes, ~c\"uct{\", []}\n  end\n\n  test \"completion for struct keys\" do\n    assert {:yes, ~c\"\", entries} = expand(~c\"%URI{\")\n    assert ~c\"path:\" in entries\n    assert ~c\"query:\" in entries\n\n    assert {:yes, ~c\"\", entries} = expand(~c\"%URI{path: \\\"foo\\\",\")\n    assert ~c\"path:\" not in entries\n    assert ~c\"query:\" in entries\n\n    assert {:yes, ~c\"ry: \", []} = expand(~c\"%URI{path: \\\"foo\\\", que\")\n    assert {:no, [], []} = expand(~c\"%URI{path: \\\"foo\\\", unkno\")\n    assert {:no, [], []} = expand(~c\"%Unknown{path: \\\"foo\\\", unkno\")\n\n    assert {:yes, [], _} = expand(~c\"%__MODULE__{\")\n    assert {:yes, [], _} = expand(~c\"%__MODULE__.Some{\")\n  end\n\n  test \"completion for struct keys in update syntax\" do\n    assert {:yes, ~c\"\", entries} = expand(~c\"%URI{var | \")\n    assert ~c\"path:\" in entries\n    assert ~c\"query:\" in entries\n\n    assert {:yes, ~c\"\", entries} = expand(~c\"%URI{var | path: \\\"foo\\\",\")\n    assert ~c\"path:\" not in entries\n    assert ~c\"query:\" in entries\n\n    assert {:yes, ~c\"ry: \", []} = expand(~c\"%URI{var | path: \\\"foo\\\", que\")\n    assert {:no, [], []} = expand(~c\"%URI{var | path: \\\"foo\\\", unkno\")\n    assert {:no, [], []} = expand(~c\"%Unknown{var | path: \\\"foo\\\", unkno\")\n\n    eval(\"var = %URI{}\")\n\n    assert {:yes, ~c\"\", entries} = expand(~c\"%{var | \")\n    assert ~c\"path:\" in entries\n    assert ~c\"query:\" in entries\n\n    assert {:yes, ~c\"\", entries} = expand(~c\"%{var | path: \\\"foo\\\",\")\n    assert ~c\"path:\" not in entries\n    assert ~c\"query:\" in entries\n\n    assert {:yes, ~c\"ry: \", []} = expand(~c\"%{var | path: \\\"foo\\\", que\")\n    assert {:no, [], []} = expand(~c\"%URI{var | path: \\\"foo\\\", unkno\")\n  end\n\n  test \"completion for map keys in update syntax\" do\n    eval(\"map = %{some: 1, other: :ok, another: \\\"qwe\\\"}\")\n    assert {:yes, ~c\"\", entries} = expand(~c\"%{map | \")\n    assert ~c\"some:\" in entries\n    assert ~c\"other:\" in entries\n\n    assert {:yes, ~c\"\", entries} = expand(~c\"%{map | some: \\\"foo\\\",\")\n    assert ~c\"some:\" not in entries\n    assert ~c\"other:\" in entries\n\n    assert {:yes, ~c\"er: \", []} = expand(~c\"%{map | some: \\\"foo\\\", oth\")\n    assert {:no, [], []} = expand(~c\"%{map | some: \\\"foo\\\", unkno\")\n    assert {:no, [], []} = expand(~c\"%{unknown | some: \\\"foo\\\", unkno\")\n  end\n\n  test \"completion for struct var keys\" do\n    eval(\"struct = %IEx.AutocompleteTest.MyStruct{}\")\n    assert expand(~c\"struct.my\") == {:yes, ~c\"_val\", []}\n  end\n\n  test \"completion for bitstring modifiers\" do\n    assert {:yes, ~c\"\", entries} = expand(~c\"<<foo::\")\n    assert ~c\"integer\" in entries\n    assert ~c\"size/1\" in entries\n\n    assert {:yes, ~c\"eger\", []} = expand(~c\"<<foo::int\")\n\n    assert {:yes, ~c\"\", entries} = expand(~c\"<<foo::integer-\")\n    refute ~c\"integer\" in entries\n    assert ~c\"little\" in entries\n    assert ~c\"size/1\" in entries\n\n    assert {:yes, ~c\"\", entries} = expand(~c\"<<foo::integer-little-\")\n    refute ~c\"integer\" in entries\n    refute ~c\"little\" in entries\n    assert ~c\"size/1\" in entries\n  end\n\n  test \"completion for aliases in special forms\" do\n    assert {:yes, ~c\"\", entries} = expand(~c\"alias \")\n    assert ~c\"Atom\" in entries\n    refute ~c\"is_atom\" in entries\n\n    assert {:yes, ~c\"Range\", []} = expand(~c\"alias Date.\")\n  end\n\n  test \"ignore invalid Elixir module literals\" do\n    defmodule(:\"Elixir.IEx.AutocompleteTest.Unicodé\", do: nil)\n    assert expand(~c\"IEx.AutocompleteTest.Unicod\") == {:no, ~c\"\", []}\n  after\n    :code.purge(:\"Elixir.IEx.AutocompleteTest.Unicodé\")\n    :code.delete(:\"Elixir.IEx.AutocompleteTest.Unicodé\")\n  end\n\n  test \"signature help for functions and macros\" do\n    assert expand(~c\"String.graphemes(\") == {:yes, ~c\"\", [~c\"graphemes(string)\"]}\n    assert expand(~c\"def \") == {:yes, ~c\"\", [~c\"def(call, expr \\\\\\\\ nil)\"]}\n\n    eval(\"import Enum; import Protocol\")\n\n    assert expand(~c\"reduce(\") ==\n             {:yes, ~c\"\", [~c\"reduce(enumerable, fun)\", ~c\"reduce(enumerable, acc, fun)\"]}\n\n    assert expand(~c\"take(\") == {:yes, ~c\"\", [~c\"take(enumerable, amount)\"]}\n    assert expand(~c\"derive(\") == {:yes, ~c\"\", [~c\"derive(protocol, module, options \\\\\\\\ [])\"]}\n\n    defmodule NoDocs do\n      def sample(a), do: a\n    end\n\n    assert {:yes, [], [_ | _]} = expand(~c\"NoDocs.sample(\")\n  end\n\n  @tag :tmp_dir\n  test \"path completion inside strings\", %{tmp_dir: dir} do\n    dir |> Path.join(\"single1\") |> File.touch()\n    dir |> Path.join(\"file1\") |> File.touch()\n    dir |> Path.join(\"file2\") |> File.touch()\n    dir |> Path.join(\"dir\") |> File.mkdir()\n    dir |> Path.join(\"dir/file3\") |> File.touch()\n    dir |> Path.join(\"dir/file4\") |> File.touch()\n\n    assert expand(~c\"\\\"./\") == path_autocompletion(\".\")\n    assert expand(~c\"\\\"/\") == path_autocompletion(\"/\")\n    assert expand(~c\"\\\"./#\\{\") == expand(~c\"{\")\n    assert expand(~c\"\\\"./#\\{Str\") == expand(~c\"{Str\")\n    assert expand(~c\"Path.join(\\\"./\\\", is_\") == expand(~c\"is_\")\n\n    assert expand(~c\"\\\"#{dir}/\") == path_autocompletion(dir)\n    assert expand(~c\"\\\"#{dir}/sin\") == {:yes, ~c\"gle1\", []}\n    assert expand(~c\"\\\"#{dir}/single1\") == {:yes, ~c\"\\\"\", []}\n    assert expand(~c\"\\\"#{dir}/fi\") == {:yes, ~c\"le\", []}\n    assert expand(~c\"\\\"#{dir}/file\") == path_autocompletion(dir, \"file\")\n    assert expand(~c\"\\\"#{dir}/d\") == {:yes, ~c\"ir/\", []}\n    assert expand(~c\"\\\"#{dir}/dir\") == {:yes, ~c\"/\", []}\n    assert expand(~c\"\\\"#{dir}/dir/\") == {:yes, ~c\"file\", []}\n    assert expand(~c\"\\\"#{dir}/dir/file\") == dir |> Path.join(\"dir\") |> path_autocompletion(\"file\")\n  end\n\n  defp path_autocompletion(dir, hint \\\\ \"\") do\n    dir\n    |> File.ls!()\n    |> Stream.filter(&String.starts_with?(&1, hint))\n    |> Enum.map(&String.to_charlist/1)\n    |> case do\n      [] -> {:no, ~c\"\", []}\n      list -> {:yes, ~c\"\", list}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/iex/test/iex/config_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule IEx.ConfigTest do\n  use ExUnit.Case, async: true\n\n  import IEx.Config\n\n  describe \"prompt\" do\n    test \"converts everything before opening parens to dots\" do\n      assert prompt(~c\"iex(321)>\") == ~c\"...(321)>\"\n      assert prompt(~c\"foo-bar(321)>\") == ~c\".......(321)>\"\n    end\n\n    test \"falls back to Erlang wit no parens around\" do\n      assert prompt(~c\"foo-bar>\") == ~c\"     .. \"\n    end\n\n    test \"ignores ansi escapes\" do\n      assert prompt(~c\"#{IO.ANSI.red()}iex(foo)>\") == ~c\"...(foo)>\"\n      assert prompt(~c\"#{IO.ANSI.red()}foo-bar>\") == ~c\"     .. \"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/iex/test/iex/helpers_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule IEx.HelpersTest do\n  use IEx.Case\n\n  import IEx.Helpers\n\n  @compile {:no_warn_undefined, [:sample, Sample, Sample2]}\n\n  describe \"whereami\" do\n    test \"is disabled by default\" do\n      assert capture_iex(\"whereami()\") =~ \"Pry session is not currently enabled\"\n    end\n\n    test \"shows current location for custom envs\" do\n      whereami = capture_iex(\"whereami()\", [], env: %{__ENV__ | line: 7})\n      assert whereami =~ \"test/iex/helpers_test.exs:7\"\n      assert whereami =~ \"7: defmodule IEx.HelpersTest do\"\n    end\n\n    test \"prints message when location is not available\" do\n      whereami = capture_iex(\"whereami()\", [], env: %{__ENV__ | line: 30000})\n      assert whereami =~ \"test/iex/helpers_test.exs:30000\"\n      assert whereami =~ \"Could not extract source snippet. Location is not available.\"\n\n      whereami = capture_iex(\"whereami()\", [], env: %{__ENV__ | file: \"nofile\", line: 1})\n      assert whereami =~ \"nofile:1\"\n      assert whereami =~ \"Could not extract source snippet. Location is not available.\"\n    end\n  end\n\n  describe \"breakpoints\" do\n    setup do\n      on_exit(fn -> IEx.Pry.remove_breaks() end)\n    end\n\n    test \"sets up a breakpoint with capture syntax\" do\n      assert break!(PryExampleModule.two() / 2) == 1\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}]\n    end\n\n    test \"sets up a breakpoint with call syntax\" do\n      assert break!(PryExampleModule.two(_, %{})) == 1\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}]\n    end\n\n    test \"sets up a breakpoint with guards syntax\" do\n      assert break!(PryExampleModule.two(_, map) when is_map(map)) == 1\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}]\n    end\n\n    test \"sets up a breakpoint on the given module\" do\n      assert break!(PryExampleModule, :two, 2) == 1\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}]\n    end\n\n    test \"resets breaks on the given ID\" do\n      assert break!(PryExampleModule, :two, 2) == 1\n      assert reset_break(1) == :ok\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}]\n    end\n\n    test \"resets breaks on the given module\" do\n      assert break!(PryExampleModule, :two, 2) == 1\n      assert reset_break(PryExampleModule, :two, 2) == :ok\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}]\n    end\n\n    test \"removes breaks in the given module\" do\n      assert break!(PryExampleModule.two() / 2) == 1\n      assert remove_breaks(PryExampleModule) == :ok\n      assert IEx.Pry.breaks() == []\n    end\n\n    test \"removes breaks on all modules\" do\n      assert break!(PryExampleModule.two() / 2) == 1\n      assert remove_breaks() == :ok\n      assert IEx.Pry.breaks() == []\n    end\n\n    test \"errors when setting up a breakpoint with invalid guard\" do\n      assert capture_io(:stderr, fn ->\n               assert_raise CompileError, fn ->\n                 break!(PryExampleModule.two(_, map) when is_whatever(map))\n               end\n             end) =~ \"cannot find or invoke local is_whatever/1\"\n    end\n\n    test \"errors when setting up a break with no beam\" do\n      assert_raise RuntimeError,\n                   \"could not set breakpoint, could not find .beam file for IEx.HelpersTest\",\n                   fn -> break!(__MODULE__, :setup, 1) end\n    end\n\n    test \"errors when setting up a break for unknown function\" do\n      assert_raise RuntimeError,\n                   \"could not set breakpoint, unknown function/macro #{inspect(PryExampleModule)}.unknown/2\",\n                   fn -> break!(PryExampleModule, :unknown, 2) end\n    end\n\n    test \"errors for non-Elixir modules\" do\n      assert_raise RuntimeError,\n                   \"could not set breakpoint, module :maps was not written in Elixir\",\n                   fn -> break!(:maps, :unknown, 2) end\n    end\n\n    test \"prints table with breaks\" do\n      break!(PryExampleModule, :two, 2)\n\n      assert capture_io(fn -> breaks() end) == \"\"\"\n\n              ID   Module.function/arity    Pending stops\n             ---- ------------------------ ---------------\n              1    PryExampleModule.two/2   1\n\n             \"\"\"\n\n      assert capture_io(fn -> PryExampleModule.two(\"foo=bar\", %{}) end) != \"\"\n\n      assert capture_io(fn -> breaks() end) == \"\"\"\n\n              ID   Module.function/arity    Pending stops\n             ---- ------------------------ ---------------\n              1    PryExampleModule.two/2   0\n\n             \"\"\"\n\n      assert capture_io(fn -> PryExampleModule.two(\"foo=bar\", %{}) end) == \"\"\n\n      assert capture_io(fn -> breaks() end) == \"\"\"\n\n              ID   Module.function/arity    Pending stops\n             ---- ------------------------ ---------------\n              1    PryExampleModule.two/2   0\n\n             \"\"\"\n    end\n\n    test \"does not print table when there are no breaks\" do\n      assert capture_io(fn -> breaks() end) == \"No breakpoints set\\n\"\n    end\n  end\n\n  describe \"open\" do\n    @describetag :requires_source\n    @iex_helpers \"iex/lib/iex/helpers.ex\"\n    @elixir_erl \"elixir/src/elixir.erl\"\n    @lists_erl Application.app_dir(:stdlib, \"src/lists.erl\")\n    @httpc_erl \"src/http_client/httpc.erl\"\n    @editor System.get_env(\"ELIXIR_EDITOR\")\n    @example_module_path \"lib/iex/test/test_helper.exs\"\n\n    test \"opens __FILE__ and __LINE__\" do\n      System.put_env(\"ELIXIR_EDITOR\", \"echo __LINE__:__FILE__\")\n\n      assert capture_iex(\"open({#{inspect(__ENV__.file)}, 3})\") |> maybe_trim_quotes() ==\n               \"3:#{__ENV__.file}\"\n    after\n      System.put_env(\"ELIXIR_EDITOR\", @editor)\n    end\n\n    test \"opens Elixir module\" do\n      assert capture_iex(\"open(HelperExampleModule)\") |> maybe_trim_quotes() =~\n               ~r/#{@example_module_path}:\\d+$/\n    end\n\n    @tag :require_ast\n    test \"opens function\" do\n      assert capture_iex(\"open(h)\") |> maybe_trim_quotes() =~ ~r/#{@iex_helpers}:\\d+$/\n    end\n\n    @tag :require_ast\n    test \"opens function/arity\" do\n      assert capture_iex(\"open(b/1)\") |> maybe_trim_quotes() =~ ~r/#{@iex_helpers}:\\d+$/\n      assert capture_iex(\"open(h/0)\") |> maybe_trim_quotes() =~ ~r/#{@iex_helpers}:\\d+$/\n    end\n\n    test \"opens module.function\" do\n      assert capture_iex(\"open(HelperExampleModule.fun)\") |> maybe_trim_quotes() =~\n               ~r/#{@example_module_path}:\\d+$/\n\n      assert capture_iex(\"open(HelperExampleModule.macro)\") |> maybe_trim_quotes() =~\n               ~r/#{@example_module_path}:\\d+$/\n    end\n\n    test \"opens module.function/arity\" do\n      assert capture_iex(\"open(HelperExampleModule.fun/1)\") |> maybe_trim_quotes() =~\n               ~r/#{@example_module_path}:\\d+$/\n\n      assert capture_iex(\"open(HelperExampleModule.macro/1)\") |> maybe_trim_quotes() =~\n               ~r/#{@example_module_path}:\\d+$/\n    end\n\n    @tag :require_ast\n    test \"opens Erlang module\" do\n      assert capture_iex(\"open(:elixir)\") |> maybe_trim_quotes() =~ ~r/#{@elixir_erl}:\\d+$/\n    end\n\n    @tag :require_ast\n    test \"opens Erlang module.function\" do\n      assert capture_iex(\"open(:elixir.start)\") |> maybe_trim_quotes() =~ ~r/#{@elixir_erl}:\\d+$/\n    end\n\n    @tag :require_ast\n    test \"opens Erlang module.function/arity\" do\n      assert capture_iex(\"open(:elixir.start/2)\") |> maybe_trim_quotes() =~\n               ~r/#{@elixir_erl}:\\d+$/\n    end\n\n    # Some installations remove the source file once Erlang is compiled. See #7348.\n    if File.regular?(@lists_erl) do\n      test \"opens OTP lists module\" do\n        assert capture_iex(\"open(:lists)\") |> maybe_trim_quotes() =~ ~r/#{@lists_erl}:\\d+$/\n      end\n\n      test \"opens OTP lists module.function\" do\n        assert capture_iex(\"open(:lists.reverse)\") |> maybe_trim_quotes() =~\n                 ~r/#{@lists_erl}:\\d+$/\n      end\n\n      test \"opens OTP lists module.function/arity\" do\n        assert capture_iex(\"open(:lists.reverse/1)\") |> maybe_trim_quotes() =~\n                 ~r/#{@lists_erl}:\\d+$/\n      end\n    end\n\n    # Some installations remove the source file once Erlang is compiled. See #7348.\n    if File.regular?(@httpc_erl) do\n      test \"opens OTP httpc module\" do\n        assert capture_iex(\"open(:httpc)\") |> maybe_trim_quotes() =~ ~r/#{@httpc_erl}:\\d+$/\n      end\n\n      test \"opens OTP httpc module.function\" do\n        assert capture_iex(\"open(:httpc.request)\") |> maybe_trim_quotes() =~\n                 ~r/#{@httpc_erl}:\\d+$/\n      end\n\n      test \"opens OTP httpc module.function/arity\" do\n        assert capture_iex(\"open(:httpc.request/1)\") |> maybe_trim_quotes() =~\n                 ~r/#{@httpc_erl}:\\d+$/\n      end\n    end\n\n    test \"errors OTP preloaded module\" do\n      assert capture_iex(\"open(:init)\") =~ ~r\"(Could not open)|(Invalid arguments)\"\n    end\n\n    test \"errors if module is not available\" do\n      assert capture_iex(\"open(:unknown)\") == \"Could not open :unknown, module is not available\"\n    end\n\n    test \"errors if module.function is not available\" do\n      assert capture_iex(\"open(:unknown.unknown)\") ==\n               \"Could not open :unknown.unknown, module is not available\"\n\n      assert capture_iex(\"open(:elixir.unknown)\") ==\n               \"Could not open :elixir.unknown, function/macro is not available\"\n\n      assert capture_iex(\"open(:lists.unknown)\") ==\n               \"Could not open :lists.unknown, function/macro is not available\"\n\n      assert capture_iex(\"open(:httpc.unknown)\") ==\n               \"Could not open :httpc.unknown, function/macro is not available\"\n    end\n\n    test \"errors if module.function/arity is not available\" do\n      assert capture_iex(\"open(:unknown.start/10)\") ==\n               \"Could not open :unknown.start/10, module is not available\"\n\n      assert capture_iex(\"open(:elixir.start/10)\") ==\n               \"Could not open :elixir.start/10, function/macro is not available\"\n\n      assert capture_iex(\"open(:lists.reverse/10)\") ==\n               \"Could not open :lists.reverse/10, function/macro is not available\"\n\n      assert capture_iex(\"open(:httpc.request/10)\") ==\n               \"Could not open :httpc.request/10, function/macro is not available\"\n    end\n\n    test \"errors if module is in-memory\" do\n      assert capture_iex(\"defmodule Foo, do: nil ; open(Foo)\") =~\n               ~r\"Invalid arguments for open helper:\"\n    after\n      cleanup_modules([Foo])\n    end\n\n    test \"opens the current pry location\" do\n      assert capture_iex(\"open()\", [], env: %{__ENV__ | line: 3}) |> maybe_trim_quotes() ==\n               \"#{__ENV__.file}:3\"\n    end\n\n    test \"errors if prying is not available\" do\n      assert capture_iex(\"open()\") == \"Pry session is not currently enabled\"\n    end\n\n    test \"opens given {file, line}\" do\n      assert capture_iex(\"open({#{inspect(__ENV__.file)}, 3})\") |> maybe_trim_quotes() ==\n               \"#{__ENV__.file}:3\"\n    end\n\n    test \"errors when given {file, line} is not available\" do\n      assert capture_iex(\"open({~s[foo], 3})\") =~\n               \"Could not open \\\"foo\\\", file is not available\"\n    end\n\n    defp maybe_trim_quotes(string) do\n      case :os.type() do\n        {:win32, _} -> String.replace(string, \"\\\"\", \"\")\n        _ -> string\n      end\n    end\n  end\n\n  describe \"clear\" do\n    test \"clear the screen with ansi\" do\n      Application.put_env(:elixir, :ansi_enabled, true)\n      assert capture_iex(\"clear()\") == \"\\e[H\\e[2J\"\n\n      Application.put_env(:elixir, :ansi_enabled, false)\n\n      assert capture_iex(\"clear()\") =~\n               \"Cannot clear the screen because ANSI escape codes are not enabled on this shell\"\n    after\n      Application.delete_env(:elixir, :ansi_enabled)\n    end\n  end\n\n  describe \"runtime_info\" do\n    test \"shows VM information\" do\n      assert \"\\n## System and architecture\" <> _ = capture_io(fn -> runtime_info() end)\n\n      assert \"\\n## Loaded OTP applications\" <> _ =\n               capture_io(fn -> runtime_info([:applications]) end)\n\n      assert \"\\n## Memory allocators\" <> _ = capture_io(fn -> runtime_info([:allocators]) end)\n    end\n  end\n\n  describe \"h\" do\n    test \"shows help\" do\n      help = capture_iex(\"h()\")\n      assert help =~ \"IEx.Helpers\"\n      assert help =~ \"Welcome to Interactive Elixir\"\n    end\n\n    @tag :erlang_doc\n    test \"prints Erlang module documentation\" do\n      captured = capture_io(fn -> h(:timer) end)\n      assert captured =~ \"This module provides useful functions related to time.\"\n    end\n\n    @tag :erlang_doc\n    test \"prints Erlang module function specs\" do\n      captured = capture_io(fn -> h(:timer.sleep() / 1) end)\n\n      assert captured =~ \"sleep(Time)\"\n      assert captured =~ \"@spec sleep(time) :: :ok when time: \"\n    end\n\n    @tag :erlang_doc\n    test \"handles non-existing Erlang module function\" do\n      captured = capture_io(fn -> h(:timer.baz() / 1) end)\n\n      assert captured =~ \"No documentation for :timer.baz/1 was found\"\n    end\n\n    @tag :erlang_doc\n    test \"erlang -moduledoc\" do\n      filename = \"sample.erl\"\n\n      code = ~s'''\n      -module(sample).\n      -moduledoc \"Module documentation.\".\n      '''\n\n      with_file(filename, code, fn ->\n        assert c(filename, \".\") == [:sample]\n\n        help = capture_iex(\"h(:sample)\")\n        assert help =~ \"Module documentation.\"\n      end)\n    after\n      cleanup_modules([:sample])\n    end\n\n    @tag :erlang_doc\n    test \"erlang -doc\" do\n      filename = \"sample.erl\"\n\n      code = ~s'''\n      -module(sample).\n      -export([hello/0]).\n\n      -doc \"Function documentation.\".\n      hello() -> world.\n      '''\n\n      with_file(filename, code, fn ->\n        assert c(filename, \".\") == [:sample]\n\n        help = capture_iex(\"h(:sample.hello)\")\n        assert help =~ \"Function documentation.\"\n      end)\n    after\n      cleanup_modules([:sample])\n    end\n\n    test \"prints module documentation\" do\n      assert \"\\n                                  IEx.Helpers\\n\\nWelcome to Interactive Elixir\" <>\n               _ = capture_io(fn -> h(IEx.Helpers) end)\n\n      assert capture_io(fn -> h(:whatever) end) ==\n               \"Could not load module :whatever, got: nofile\\n\"\n    end\n\n    test \"prints function/macro documentation\" do\n      pwd_h = \"\"\"\n\n                                         def pwd()\n\n      Prints the current working directory.\n\n      \"\"\"\n\n      c_h = \"\"\"\n\n                              def c(files, path \\\\\\\\ :in_memory)\n\n      Compiles the given files.\n      \"\"\"\n\n      eq_h = \"\"\"\n\n                                     def left == right\n\n        @spec term() == term() :: boolean()\n\n      guard: true\n\n      Equal to operator. Returns `true` if the two terms are equal.\n      \"\"\"\n\n      def_h = \"\"\"\n\n                              defmacro def(call, expr \\\\\\\\ nil)\n\n      Defines a public function with the given name and body.\n      \"\"\"\n\n      assert capture_io(fn -> h(IEx.Helpers.pwd() / 0) end) =~ pwd_h\n      assert capture_io(fn -> h(IEx.Helpers.c() / 2) end) =~ c_h\n      assert capture_io(fn -> h(== / 2) end) =~ eq_h\n      assert capture_io(fn -> h(def / 2) end) =~ def_h\n\n      assert capture_io(fn -> h(IEx.Helpers.c() / 1) end) =~ c_h\n      assert capture_io(fn -> h(pwd) end) =~ pwd_h\n      assert capture_io(fn -> h(def) end) =~ def_h\n    end\n\n    test \"prints sigil documentation\" do\n      assert capture_io(fn -> h(~w//) end) =~ \"Handles the sigil `~w` for list of words\"\n    end\n\n    test \"prints __info__ documentation\" do\n      h_output_module = capture_io(fn -> h(Module.__info__()) end)\n      assert capture_io(fn -> h(Module.UnlikelyTo.Exist.__info__()) end) == h_output_module\n      assert capture_io(fn -> h(Module.UnlikelyTo.Exist.__info__() / 1) end) == h_output_module\n\n      assert capture_io(fn -> h(__info__) end) ==\n               \"No documentation for Kernel.__info__ was found\\n\"\n    end\n\n    test \"prints documentation metadata\" do\n      content = \"\"\"\n      defmodule Sample do\n        @moduledoc \"Sample module\"\n        @moduledoc deprecated: \"Use OtherSample\", since: \"1.2.3\", authors: [\"Alice\", \"Bob\"]\n        @doc \"With metadata\"\n        @doc since: \"1.2.3\", author: \"Alice\"\n        @deprecated \"Use OtherSample.with_metadata/0\"\n        def with_metadata(), do: 0\n        @doc \"Without metadata\"\n        def without_metadata(), do: 1\n      end\n      \"\"\"\n\n      filename = \"sample.ex\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [Sample]\n\n        assert capture_io(fn -> h(Sample) end) == \"\"\"\n\n                                                    Sample\n\n               deprecated: Use OtherSample\n               since: 1.2.3\n\n               Sample module\n\n               \"\"\"\n\n        assert capture_io(fn -> h(Sample.with_metadata()) end) == \"\"\"\n\n                                             def with_metadata()\n\n               deprecated: Use OtherSample.with_metadata/0\n               since: 1.2.3\n\n               With metadata\n\n               \"\"\"\n\n        assert capture_io(fn -> h(Sample.without_metadata()) end) == \"\"\"\n\n                                            def without_metadata()\n\n               Without metadata\n\n               \"\"\"\n      end)\n    after\n      cleanup_modules([Sample])\n    end\n\n    test \"considers underscored functions without docs by default\" do\n      content = \"\"\"\n      defmodule Sample do\n        def __foo__(), do: 0\n        @doc \"Bar doc\"\n        def __bar__(), do: 1\n      end\n      \"\"\"\n\n      filename = \"sample.ex\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [Sample]\n\n        assert capture_io(fn -> h(Sample.__foo__()) end) ==\n                 \"No documentation for Sample.__foo__ was found\\n\"\n\n        assert capture_io(fn -> h(Sample.__bar__()) end) == \"\"\"\n\n                                                def __bar__()\n\n               Bar doc\n\n               \"\"\"\n\n        assert capture_io(fn -> h(Sample.__foo__() / 0) end) ==\n                 \"No documentation for Sample.__foo__/0 was found\\n\"\n\n        assert capture_io(fn -> h(Sample.__bar__() / 0) end) == \"\"\"\n\n                                                def __bar__()\n\n               Bar doc\n\n               \"\"\"\n      end)\n    after\n      cleanup_modules([Sample])\n    end\n\n    test \"prints callback documentation when function docs are not available\" do\n      behaviour = \"\"\"\n      defmodule MyBehaviour do\n        @doc \"Docs for MyBehaviour.first\"\n        @callback first(integer) :: integer\n        @callback second(integer) :: integer\n        @callback second(integer, integer) :: integer\n      end\n      \"\"\"\n\n      impl = \"\"\"\n      defmodule Impl do\n        @behaviour MyBehaviour\n        @doc delegate_to: {Foo, :bar, 3}\n        def first(0), do: 0\n        @doc \"Docs for Impl.second/1\"\n        def second(0), do: 0\n        @doc \"Docs for Impl.second/2\"\n        def second(0, 0), do: 0\n      end\n      \"\"\"\n\n      files = [\"my_behaviour.ex\", \"impl.ex\"]\n\n      with_file(files, [behaviour, impl], fn ->\n        assert c(files, \".\") |> Enum.sort() == [Impl, MyBehaviour]\n\n        assert capture_io(fn -> h(Impl.first() / 1) end) == \"\"\"\n\n                                                def first(int)\n\n               delegate_to: Foo.bar/3\n\n               Impl.first/1 has no docs but is a callback for behaviour MyBehaviour. Showing\n               callback docs instead.\n\n               @callback first(integer()) :: integer()\n\n               Docs for MyBehaviour.first\n\n               \"\"\"\n\n        assert capture_io(fn -> h(Impl.second() / 1) end) == \"\"\"\n\n                                               def second(int)\n\n               Docs for Impl.second/1\n\n               \"\"\"\n\n        assert capture_io(fn -> h(Impl.second() / 2) end) == \"\"\"\n\n                                            def second(int1, int2)\n\n               Docs for Impl.second/2\n\n               \"\"\"\n\n        assert capture_io(fn -> h(Impl.first()) end) == capture_io(fn -> h(Impl.first() / 1) end)\n\n        assert capture_io(fn -> h(Impl.second()) end) == \"\"\"\n\n                                               def second(int)\n\n               Docs for Impl.second/1\n\n\n                                            def second(int1, int2)\n\n               Docs for Impl.second/2\n\n               \"\"\"\n\n        assert capture_io(fn -> h(MyBehaviour.first()) end) == \"\"\"\n               No documentation for function MyBehaviour.first was found, but there is a callback with the same name.\n               You can view callback documentation with the b/1 helper.\\n\n               \"\"\"\n\n        assert capture_io(fn -> h(MyBehaviour.second() / 2) end) == \"\"\"\n               No documentation for function MyBehaviour.second/2 was found, but there is a callback with the same name.\n               You can view callback documentation with the b/1 helper.\\n\n               \"\"\"\n\n        assert capture_io(fn -> h(MyBehaviour.second() / 3) end) ==\n                 \"No documentation for MyBehaviour.second/3 was found\\n\"\n      end)\n    after\n      cleanup_modules([Impl, MyBehaviour])\n    end\n\n    test \"prints protocol function docs\" do\n      output = capture_io(fn -> h(Enumerable.reduce()) end)\n      assert output =~ \"@spec reduce(t(), acc(), reducer()) :: result()\"\n      assert output =~ \"Reduces the `enumerable`\"\n    end\n\n    test \"prints documentation for delegates\" do\n      filename = \"delegate.ex\"\n\n      content = \"\"\"\n      defmodule Delegator do\n        defdelegate func1, to: Delegated\n        @doc \"Delegator func2 doc\"\n        defdelegate func2, to: Delegated\n      end\n      defmodule Delegated do\n        def func1, do: 1\n        def func2, do: 2\n      end\n      \"\"\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") |> Enum.sort() == [Delegated, Delegator]\n\n        assert capture_io(fn -> h(Delegator.func1()) end) == \"\"\"\n\n                                                 def func1()\n\n               delegate_to: Delegated.func1/0\n\n               \"\"\"\n\n        assert capture_io(fn -> h(Delegator.func2()) end) == \"\"\"\n\n                                                 def func2()\n\n               delegate_to: Delegated.func2/0\n\n               Delegator func2 doc\n\n               \"\"\"\n      end)\n    after\n      cleanup_modules([Delegated, Delegator])\n    end\n\n    test \"prints type documentation when function docs are not available\" do\n      content = \"\"\"\n      defmodule MyTypes do\n        @type first() :: any()\n        @type second(a, b) :: {a, b}\n      end\n      \"\"\"\n\n      filename = \"my_types.ex\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [MyTypes]\n\n        assert capture_io(fn -> h(MyTypes.first()) end) == \"\"\"\n               No documentation for function MyTypes.first was found, but there is a type with the same name.\n               You can view type documentation with the t/1 helper.\\n\n               \"\"\"\n\n        assert capture_io(fn -> h(MyTypes.second() / 2) end) == \"\"\"\n               No documentation for function MyTypes.second/2 was found, but there is a type with the same name.\n               You can view type documentation with the t/1 helper.\\n\n               \"\"\"\n      end)\n    after\n      cleanup_modules([MyTypes])\n    end\n\n    test \"prints modules compiled without docs\" do\n      Code.compiler_options(docs: false)\n\n      content = \"\"\"\n      defmodule Sample do\n        @spec foo(any()) :: any()\n        def foo(arg), do: arg\n      end\n      \"\"\"\n\n      filename = \"sample.ex\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [Sample]\n\n        assert capture_io(fn -> h(Sample.foo() / 1) end) == \"\"\"\n\n                                                 Sample.foo/1\n\n                 @spec foo(any()) :: any()\n\n               Module was compiled without docs. Showing only specs.\n\n               \"\"\"\n      end)\n    after\n      Code.compiler_options(docs: true)\n      cleanup_modules([Sample])\n    end\n\n    test \"does not print docs for @doc false functions\" do\n      # Here we assert that @doc false works and that we are not leaking\n      # IEx.Pry internal functions.\n      assert capture_io(fn -> h(IEx.Pry.child_spec()) end) ==\n               \"No documentation for IEx.Pry.child_spec was found\\n\"\n    end\n  end\n\n  describe \"b\" do\n    test \"lists all callbacks for an Elixir module\" do\n      assert capture_io(fn -> b(Mix) end) == \"No callbacks for Mix were found\\n\"\n      assert capture_io(fn -> b(NoMix) end) == \"Could not load module NoMix, got: nofile\\n\"\n\n      assert capture_io(fn -> b(Mix.SCM) end) =~ \"\"\"\n             @callback accepts_options(app :: atom(), opts()) :: opts() | nil\n\n             @callback checked_out?(opts()) :: boolean()\n             \"\"\"\n    end\n\n    test \"lists all callbacks for an Erlang module\" do\n      output = capture_io(fn -> b(:gen_server) end)\n\n      assert output =~ \"@callback init(args :: term()) ::\"\n      assert output =~ \"@callback handle_cast(\"\n      assert output =~ \"@callback handle_info(\"\n    end\n\n    test \"lists all macrocallbacks for a module\" do\n      filename = \"macrocallbacks.ex\"\n\n      content = \"\"\"\n      defmodule Macrocallbacks do\n        @macrocallback test(:foo) :: integer\n        @macrocallback test(:bar) :: var when var: integer\n      end\n      \"\"\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [Macrocallbacks]\n        callbacks = capture_io(fn -> b(Macrocallbacks) end)\n        assert callbacks =~ \"@macrocallback test(:foo) :: integer()\\n\"\n        assert callbacks =~ \"@macrocallback test(:bar) :: var when var: integer()\\n\"\n      end)\n    after\n      cleanup_modules([Macrocallbacks])\n    end\n\n    test \"lists all callbacks for a protocol\" do\n      assert capture_io(fn -> b(Enumerable) end) =~ \"\"\"\n             @callback count(t()) :: {:ok, non_neg_integer()} | {:error, module()}\n\n             @callback member?(t(), term()) :: {:ok, boolean()} | {:error, module()}\n\n             @callback reduce(t(), acc(), reducer()) :: result()\n             \"\"\"\n    end\n\n    test \"prints protocol function docs\" do\n      output = capture_io(fn -> b(Enumerable.reduce()) end)\n      assert output =~ \"@callback reduce(t(), acc(), reducer()) :: result()\"\n      assert output =~ \"Reduces the `enumerable`\"\n    end\n\n    test \"lists callback with multiple clauses\" do\n      filename = \"multiple_clauses_callback.ex\"\n\n      content = \"\"\"\n      defmodule MultipleClauseCallback do\n        @doc \"callback\"\n        @callback test(:foo) :: integer\n        @callback test(:bar) :: [integer]\n      end\n      \"\"\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [MultipleClauseCallback]\n\n        assert capture_io(fn -> b(MultipleClauseCallback) end) =~ \"\"\"\n               @callback test(:foo) :: integer()\n               @callback test(:bar) :: [integer()]\n               \"\"\"\n\n        assert capture_io(fn -> b(MultipleClauseCallback.test()) end) =~ \"\"\"\n               @callback test(:foo) :: integer()\n               @callback test(:bar) :: [integer()]\n\n               callback\n               \"\"\"\n      end)\n    after\n      cleanup_modules([MultipleClauseCallback])\n    end\n\n    test \"prints callback documentation\" do\n      assert capture_io(fn -> b(Mix.Task.stop()) end) ==\n               \"No documentation for Mix.Task.stop was found\\n\"\n\n      assert capture_io(fn -> b(Mix.Task.run()) end) =~\n               \"@callback run(command_line_args :: [binary()]) :: any()\\n\\nA task needs to implement `run`\"\n\n      assert capture_io(fn -> b(NoMix.run()) end) == \"Could not load module NoMix, got: nofile\\n\"\n\n      assert capture_io(fn -> b(Exception.message() / 1) end) =~\n               \"@callback message(t()) :: String.t()\\n\\n\"\n\n      assert capture_io(fn -> b(:gen_server.handle_cast() / 2) end) =~\n               \"@callback handle_cast(\"\n    end\n\n    test \"prints callback documentation metadata\" do\n      filename = \"callback_with_metadata.ex\"\n\n      content = \"\"\"\n      defmodule CallbackWithMetadata do\n        @doc \"callback\"\n        @doc since: \"1.2.3\", deprecated: \"Use handle_test/1\", purpose: :test\n        @callback test(:foo) :: integer\n      end\n      \"\"\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [CallbackWithMetadata]\n\n        assert capture_io(fn -> b(CallbackWithMetadata.test()) end) == \"\"\"\n               @callback test(:foo) :: integer()\n\n               deprecated: Use handle_test/1\n               since: 1.2.3\n\n               callback\n\n               \"\"\"\n      end)\n    after\n      cleanup_modules([CallbackWithMetadata])\n    end\n\n    test \"prints optional callback\" do\n      filename = \"optional_callbacks.ex\"\n\n      content = \"\"\"\n      defmodule OptionalCallbacks do\n        @doc \"callback\"\n        @callback optional_callback(:foo) :: integer\n        @macrocallback optional_macrocallback(:bar) :: atom\n        @optional_callbacks optional_callback: 1, optional_macrocallback: 1\n      end\n      \"\"\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [OptionalCallbacks]\n\n        assert capture_io(fn -> b(OptionalCallbacks) end) =~ \"\"\"\n               @callback optional_callback(:foo) :: integer()\n\n               @macrocallback optional_macrocallback(:bar) :: atom()\n\n               @optional_callbacks optional_callback: 1, optional_macrocallback: 1\n\n               \"\"\"\n      end)\n    after\n      cleanup_modules([OptionalCallbacks])\n    end\n\n    test \"does not print docs for @doc false callbacks\" do\n      filename = \"hidden_callbacks.ex\"\n\n      content = \"\"\"\n      defmodule HiddenCallbacks do\n        @doc false\n        @callback hidden_callback() :: integer\n\n        @doc false\n        @macrocallback hidden_macrocallback() :: integer\n      end\n      \"\"\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [HiddenCallbacks]\n\n        assert capture_io(fn -> b(HiddenCallbacks) end) =~\n                 \"No callbacks for HiddenCallbacks were found\\n\"\n      end)\n    after\n      cleanup_modules([HiddenCallbacks])\n    end\n  end\n\n  describe \"t\" do\n    test \"prints when there is no type information or the type is private\" do\n      assert capture_io(fn -> t(List) end) == \"No type information for List was found\\n\"\n\n      assert capture_io(fn -> t(Enum.doesnt_exist()) end) ==\n               \"No type information for Enum.doesnt_exist was found or \" <>\n                 \"Enum.doesnt_exist is private\\n\"\n\n      contents = \"\"\"\n      defmodule TypeSample do\n        @type public_so_t_doesnt_warn() :: t()\n        @typep t() :: term()\n      end\n      \"\"\"\n\n      filename = \"typesample.ex\"\n\n      with_file(filename, contents, fn ->\n        assert c(filename, \".\") == [TypeSample]\n\n        assert capture_io(fn -> t(TypeSample.t() / 0) end) ==\n                 \"No type information for TypeSample.t was found or TypeSample.t is private\\n\"\n      end)\n    after\n      cleanup_modules([TypeSample])\n    end\n\n    test \"prints all types in module\" do\n      # Test that it shows at least two types\n      assert Enum.count(capture_io(fn -> t(Enum) end) |> String.split(\"\\n\"), fn line ->\n               String.starts_with?(line, \"@type\")\n             end) >= 2\n    end\n\n    test \"prints private types\" do\n      assert capture_io(fn -> t(Date.Range) end) =~ \"@typep days\"\n    end\n\n    test \"prints type information\" do\n      assert \"@type t() ::\" <> _ = capture_io(fn -> t(Enum.t()) end)\n      assert capture_io(fn -> t(Enum.t()) end) == capture_io(fn -> t(Enum.t() / 0) end)\n      assert capture_io(fn -> t(URI.t()) end) == capture_io(fn -> t(URI.t() / 0) end)\n    end\n\n    test \"sorts types alphabetically\" do\n      unsorted =\n        capture_io(fn -> t(Enum) end)\n        |> String.split(\"\\n\")\n        |> Enum.reject(&(&1 == \"\"))\n        |> Enum.map(&String.replace(&1, ~r/@(type|opaque) /, \"\"))\n\n      assert unsorted == Enum.sort(unsorted)\n    end\n\n    test \"prints type documentation\" do\n      content = \"\"\"\n      defmodule TypeSample do\n        @typedoc \"An ID with description.\"\n        @type id_with_desc :: {number, String.t}\n        @type unquote(:\"?\")() :: :question_mark\n      end\n      \"\"\"\n\n      filename = \"typesample.ex\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [TypeSample]\n\n        assert capture_io(fn -> t(TypeSample.id_with_desc() / 0) end) == \"\"\"\n               @type id_with_desc() :: {number(), String.t()}\n\n               An ID with description.\n\n               \"\"\"\n\n        assert capture_io(fn -> t(TypeSample.id_with_desc()) end) == \"\"\"\n               @type id_with_desc() :: {number(), String.t()}\n\n               An ID with description.\n\n               \"\"\"\n\n        assert capture_io(fn -> t(TypeSample.\"?\"()) end) == \"\"\"\n               @type ?() :: :question_mark\n\n               \"\"\"\n      end)\n    after\n      cleanup_modules([TypeSample])\n    end\n\n    test \"prints type documentation metadata\" do\n      content = \"\"\"\n      defmodule TypeSample do\n        @typedoc \"An ID with description.\"\n        @typedoc since: \"1.2.3\", deprecated: \"Use t/0\", purpose: :test\n        @type id_with_desc :: {number, String.t}\n      end\n      \"\"\"\n\n      filename = \"typesample.ex\"\n\n      with_file(filename, content, fn ->\n        assert c(filename, \".\") == [TypeSample]\n\n        assert capture_io(fn -> t(TypeSample.id_with_desc()) end) == \"\"\"\n               @type id_with_desc() :: {number(), String.t()}\n\n               deprecated: Use t/0\n               since: 1.2.3\n\n               An ID with description.\n\n               \"\"\"\n      end)\n    after\n      cleanup_modules([TypeSample])\n    end\n\n    @tag :erlang_doc\n    test \"prints all types in Erlang module\" do\n      captured = capture_io(fn -> t(:queue) end)\n\n      assert captured =~ \"@type queue() :: queue(_)\"\n      assert captured =~ \"@opaque queue(item)\"\n    end\n\n    @tag :erlang_doc\n    test \"prints single type from Erlang module\" do\n      captured = capture_io(fn -> t(:erlang.iovec()) end)\n\n      assert captured =~ \"@type iovec() :: [binary()]\"\n      assert captured =~ \"A list of binaries.\"\n\n      captured = capture_io(fn -> t(:erlang.iovec() / 0) end)\n\n      assert captured =~ \"@type iovec() :: [binary()]\"\n      assert captured =~ \"A list of binaries.\"\n    end\n\n    @tag :erlang_doc\n    test \"handles non-existing types from Erlang module\" do\n      captured = capture_io(fn -> t(:erlang.foo()) end)\n      assert captured =~ \"No type information for :erlang.foo was found or :erlang.foo is private\"\n\n      captured = capture_io(fn -> t(:erlang.foo() / 1) end)\n      assert captured =~ \"No type information for :erlang.foo was found or :erlang.foo is private\"\n    end\n  end\n\n  describe \"v\" do\n    test \"returns history\" do\n      assert \"** (RuntimeError) v(0) is out of bounds\" <> _ = capture_iex(\"v(0)\")\n      assert \"** (RuntimeError) v(1) is out of bounds\" <> _ = capture_iex(\"v(1)\")\n      assert \"** (RuntimeError) v(-1) is out of bounds\" <> _ = capture_iex(\"v(-1)\")\n      assert capture_iex(\"1\\n2\\nv(2)\") == \"1\\n2\\n2\"\n      assert capture_iex(\"1\\n2\\nv(2)\") == capture_iex(\"1\\n2\\nv(-1)\")\n      assert capture_iex(\"1\\n2\\nv(2)\") == capture_iex(\"1\\n2\\nv()\")\n    end\n\n    test \"returns proper error when trying to access history out of bounds\" do\n      # We evaluate 22 statements as 20 is the current limit for iex history\n      assert capture_iex(\"\"\"\n             \\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\n             v(1)\n             \"\"\") =~\n               \"(RuntimeError) v(1) is out of bounds, the currently preserved history ranges from 3 to 22\"\n    end\n\n    test \"negative lookup works properly after crashes\" do\n      capture =\n        capture_iex(\"\"\"\n            \\n\n            \\n\n            \\n\n            Process.exit(self(), :some_reason)\\n\n            :target_value\n            v(-1)\n        \"\"\")\n\n      assert capture |> String.split(\"\\n\") |> List.last() == \":target_value\"\n    end\n  end\n\n  describe \"flush\" do\n    test \"flushes messages\" do\n      assert capture_io(fn ->\n               send(self(), :hello)\n               flush()\n             end) == \":hello\\n\"\n    end\n  end\n\n  describe \"pwd\" do\n    test \"prints the working directory\" do\n      File.cd!(iex_path(), fn ->\n        assert capture_io(fn -> pwd() end) =~ ~r\"lib[\\\\/]iex\\n$\"\n      end)\n    end\n  end\n\n  describe \"ls\" do\n    test \"lists the current directory\" do\n      File.cd!(iex_path(), fn ->\n        paths =\n          capture_io(fn -> ls() end)\n          |> String.split()\n          |> Enum.map(&String.trim/1)\n\n        assert \"ebin\" in paths\n        assert \"mix.exs\" in paths\n      end)\n    end\n\n    test \"lists the given directory\" do\n      assert capture_io(fn -> ls(\"~\") end) == capture_io(fn -> ls(System.user_home()) end)\n    end\n\n    test \"returns an existing file\" do\n      File.cd!(iex_path(), fn ->\n        assert capture_io(fn -> ls(\"mix.exs\") end) == Path.join(iex_path(), \"mix.exs\") <> \"\\n\"\n      end)\n    end\n\n    test \"prints an error if directory doesn't exist\" do\n      File.cd!(iex_path(), fn ->\n        assert capture_io(fn -> ls(\"unknown_dir\") end) ==\n                 \"No such file or directory unknown_dir\\n\"\n      end)\n    end\n\n    test \"prints an error if part of the path is not a dir (enotdir)\" do\n      File.cd!(iex_path(), fn ->\n        path = Path.join(\"mix.exs\", \"foo\")\n\n        assert capture_io(fn -> ls(path) end) ==\n                 \"No such file or directory #{path}\\n\"\n      end)\n    end\n  end\n\n  describe \"exports\" do\n    test \"prints module exports\" do\n      exports = capture_io(fn -> exports(IEx.Autocomplete) end)\n      assert exports == \"expand/1      expand/2      exports/1     remsh/1       \\n\"\n    end\n\n    test \"handles long function names\" do\n      exports = capture_io(fn -> exports(Calendar.UTCOnlyTimeZoneDatabase) end)\n\n      assert exports ==\n               \"time_zone_period_from_utc_iso_days/2 time_zone_periods_from_wall_datetime/2 \\n\"\n    end\n  end\n\n  describe \"import_file\" do\n    test \"imports a file\" do\n      with_file(\"dot-iex\", \"variable = :hello\\nimport IO\", fn ->\n        assert capture_io(:stderr, fn -> capture_iex(\"variable\") end) =~\n                 \"undefined variable \\\"variable\\\"\"\n\n        assert capture_io(:stderr, fn -> capture_iex(\"puts \\\"hi\\\"\") end) =~\n                 \"undefined function puts/1\"\n\n        assert capture_iex(\"import_file \\\"dot-iex\\\"\\nvariable\\nputs \\\"hi\\\"\") ==\n                 \"IO\\n:hello\\nhi\\n:ok\"\n      end)\n    end\n\n    test \"imports a file that imports another file\" do\n      dot = \"parent = true\\nimport_file \\\"dot-iex-1\\\"\"\n      dot_1 = \"variable = :hello\\nimport IO\"\n\n      with_file([\"dot-iex\", \"dot-iex-1\"], [dot, dot_1], fn ->\n        assert capture_io(:stderr, fn -> capture_iex(\"parent\") end) =~\n                 \"undefined variable \\\"parent\\\"\"\n\n        assert capture_io(:stderr, fn -> capture_iex(\"puts \\\"hi\\\"\") end) =~\n                 \"undefined function puts/1\"\n\n        assert capture_iex(\"import_file \\\"dot-iex\\\"\\nvariable\\nputs \\\"hi\\\"\\nparent\") ==\n                 \"IO\\n:hello\\nhi\\n:ok\\ntrue\"\n      end)\n    end\n\n    test \"raises if file is missing\" do\n      failing = capture_iex(\"import_file \\\"nonexistent\\\"\")\n      assert \"** (File.Error) could not read file\" <> _ = failing\n      assert failing =~ \"no such file or directory\"\n    end\n\n    test \"does not raise if file is missing and using import_file_if_available\" do\n      assert \"nil\" == capture_iex(\"import_file_if_available \\\"nonexistent\\\"\")\n    end\n\n    test \"circular imports\" do\n      dot_1 = \"import_file \\\"dot-iex-2\\\"\"\n      dot_2 = \"import_file \\\"dot-iex-1\\\"\"\n\n      with_file([\"dot-iex-1\", \"dot-iex-2\"], [dot_1, dot_2], fn ->\n        assert capture_io(:stderr, fn ->\n                 assert capture_iex(\":ok\", [], dot_iex: \"dot-iex-1\") == \":ok\"\n               end) =~ \"dot-iex-2 was already imported, skipping circular file imports\"\n      end)\n    end\n  end\n\n  describe \"import_if_available\" do\n    test \"imports a module only if available\" do\n      assert \"nil\" == capture_iex(\"import_if_available NoSuchModule\")\n      assert \"[1, 2, 3]\" == capture_iex(\"import_if_available Integer; digits 123\")\n\n      assert \"[1, 2, 3]\" ==\n               capture_iex(\"import_if_available Integer, only: [digits: 1]; digits 123\")\n    end\n  end\n\n  describe \"use_if_available\" do\n    test \"uses a module only if available\" do\n      assert \"nil\" == capture_iex(\"use_if_available NoSuchModule\")\n    end\n  end\n\n  describe \"iex> |> (and other binary operators)\" do\n    test \"passes previous result to the pipe\" do\n      Enum.each([:~>>, :<<~, :~>, :<~, :<~>], fn op ->\n        assert capture_io(:stderr, fn -> capture_iex(\"42\\n  #{op} IO.puts()\") end) =~\n                 \"undefined function #{op}/2\"\n      end)\n\n      assert capture_iex(\"+42\") =~ \"42\"\n      assert capture_iex(\"-42\") =~ \"-42\"\n      assert capture_iex(\"42\\n |> IO.inspect(label: \\\"foo\\\")\") =~ \"foo: 42\"\n      assert capture_iex(\"[42]\\n++ [24]\\n|> IO.inspect(label: \\\"foo\\\")\") =~ \"foo: [42, 24]\"\n      assert capture_iex(\"|> IO.puts()\") =~ \"(RuntimeError) v(-1) is out of bounds\"\n    end\n\n    test \"raises if previous expression was a match\" do\n      assert capture_iex(\"x = 42\\n|> IO.puts()\") =~\n               \"surround the whole pipeline with parentheses '|>'\"\n\n      assert capture_iex(\"%{x: x} = %{x: 42}\\n|> IO.puts()\") =~\n               \"surround the whole pipeline with parentheses '|>'\"\n\n      assert capture_iex(\"%{x: x} = map = %{x: 42}\\n|> IO.puts()\") =~\n               \"surround the whole pipeline with parentheses '|>'\"\n    end\n  end\n\n  describe \"c\" do\n    test \"compiles a file\" do\n      assert_raise UndefinedFunctionError, ~r\"function Sample\\.run/0 is undefined\", fn ->\n        Sample.run()\n      end\n\n      filename = \"sample.ex\"\n\n      with_file(filename, test_module_code(), fn ->\n        assert c(Path.expand(filename)) == [Sample]\n        refute File.exists?(\"Elixir.Sample.beam\")\n        assert Sample.run() == :run\n      end)\n    after\n      cleanup_modules([Sample])\n    end\n\n    test \"handles errors\" do\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        with_file(\"sample.ex\", \"raise \\\"oops\\\"\", fn ->\n          assert_raise CompileError, fn -> c(\"sample.ex\") end\n        end)\n      end)\n    end\n\n    test \"compiles a file with multiple modules \" do\n      assert_raise UndefinedFunctionError, ~r\"function Sample.run/0 is undefined\", fn ->\n        Sample.run()\n      end\n\n      filename = \"sample.ex\"\n\n      with_file(filename, test_module_code() <> \"\\n\" <> another_test_module(), fn ->\n        assert c(filename) |> Enum.sort() == [Sample, Sample2]\n        assert Sample.run() == :run\n        assert Sample2.hello() == :world\n      end)\n    after\n      cleanup_modules([Sample, Sample2])\n    end\n\n    test \"compiles multiple modules\" do\n      assert_raise UndefinedFunctionError, ~r\"function Sample.run/0 is undefined\", fn ->\n        Sample.run()\n      end\n\n      filenames = [\"sample1.ex\", \"sample2.ex\"]\n\n      with_file(filenames, [test_module_code(), another_test_module()], fn ->\n        assert c(filenames) |> Enum.sort() == [Sample, Sample2]\n        assert Sample.run() == :run\n        assert Sample2.hello() == :world\n      end)\n    after\n      cleanup_modules([Sample, Sample2])\n    end\n\n    test \"compiles Erlang modules\" do\n      assert_raise UndefinedFunctionError, ~r\"function :sample.hello/0 is undefined\", fn ->\n        :sample.hello()\n      end\n\n      filename = \"sample.erl\"\n\n      with_file(filename, erlang_module_code(), fn ->\n        assert c(filename) == [:sample]\n        assert :sample.hello() == :world\n        refute File.exists?(\"sample.beam\")\n      end)\n    after\n      cleanup_modules([:sample])\n    end\n\n    test \"skips unknown files\" do\n      assert_raise UndefinedFunctionError, ~r\"function :sample.hello/0 is undefined\", fn ->\n        :sample.hello()\n      end\n\n      filenames = [\"sample.erl\", \"not_found.ex\", \"sample2.ex\"]\n\n      with_file(filenames, [erlang_module_code(), \"\", another_test_module()], fn ->\n        assert c(filenames) |> Enum.sort() == [Sample2, :sample]\n        assert :sample.hello() == :world\n        assert Sample2.hello() == :world\n      end)\n    after\n      cleanup_modules([:sample, Sample2])\n    end\n\n    test \"compiles file in path\" do\n      assert_raise UndefinedFunctionError, ~r\"function Sample\\.run/0 is undefined\", fn ->\n        Sample.run()\n      end\n\n      filename = \"sample.ex\"\n\n      with_file(filename, test_module_code(), fn ->\n        assert c(filename, \".\") == [Sample]\n        assert File.exists?(\"Elixir.Sample.beam\")\n        assert Sample.run() == :run\n      end)\n    after\n      cleanup_modules([Sample])\n    end\n  end\n\n  describe \"l\" do\n    test \"returns error tuple for nonexistent modules\" do\n      assert l(:nonexistent_module) == {:error, :nofile}\n    end\n\n    test \"loads a given module\" do\n      assert_raise UndefinedFunctionError,\n                   ~r\"function Sample.run/0 is undefined\",\n                   fn -> Sample.run() end\n\n      filename = \"sample.ex\"\n\n      with_file(filename, test_module_code(), fn ->\n        assert c(filename, \".\") == [Sample]\n        assert Sample.run() == :run\n\n        File.write!(filename, \"defmodule Sample do end\")\n        elixirc([\"sample.ex\"])\n        assert l(Sample) == {:module, Sample}\n\n        assert_raise UndefinedFunctionError,\n                     ~r\"function Sample.run/0 is undefined\",\n                     fn -> Sample.run() end\n      end)\n    after\n      # Clean up the old version left over after l()\n      cleanup_modules([Sample])\n    end\n  end\n\n  describe \"nl\" do\n    @tag :capture_log\n    test \"loads a given module on the given nodes\" do\n      assert nl([node()], :lists) == {:ok, [{:nonode@nohost, :error, :sticky_directory}]}\n\n      assert nl([node()], HelperExampleModule) ==\n               {:ok, [{:nonode@nohost, :loaded, HelperExampleModule}]}\n\n      assert nl(:nonexistent_module) == {:error, :nofile}\n\n      assert nl([:nosuchnode@badhost], HelperExampleModule) ==\n               {:ok, [{:nosuchnode@badhost, :badrpc, :noconnection}]}\n    end\n  end\n\n  describe \"r\" do\n    @describetag :requires_source\n\n    test \"raises when reloading a nonexistent module\" do\n      assert_raise ArgumentError, \"could not load nor find module: :nonexistent_module\", fn ->\n        r(:nonexistent_module)\n      end\n    end\n\n    test \"reloads Elixir modules\" do\n      message = ~r\"function Sample.run/0 is undefined \\(module Sample is not available\\)\"\n\n      assert_raise UndefinedFunctionError, message, fn ->\n        Sample.run()\n      end\n\n      filename = \"sample.ex\"\n\n      with_file(filename, test_module_code(), fn ->\n        assert capture_io(:stderr, fn ->\n                 assert c(filename, \".\") == [Sample]\n                 assert Sample.run() == :run\n\n                 File.write!(filename, \"defmodule Sample do end\")\n                 assert {:reloaded, [Sample]} = r(Sample)\n                 assert {:reloaded, [Sample]} = r([Sample])\n\n                 message = \"function Sample.run/0 is undefined or private\"\n\n                 assert_raise UndefinedFunctionError, message, fn ->\n                   Sample.run()\n                 end\n               end) =~\n                 \"redefining module Sample (current version loaded from Elixir.Sample.beam)\"\n      end)\n    after\n      # Clean up old version produced by the r helper\n      cleanup_modules([Sample])\n    end\n\n    test \"reloads Erlang modules\" do\n      assert_raise UndefinedFunctionError, ~r\"function :sample.hello/0 is undefined\", fn ->\n        :sample.hello()\n      end\n\n      filename = \"sample.erl\"\n\n      with_file(filename, erlang_module_code(), fn ->\n        assert c(filename, \".\") == [:sample]\n        assert :sample.hello() == :world\n\n        File.write!(filename, other_erlang_module_code())\n        assert {:reloaded, [:sample]} = r(:sample)\n        assert {:reloaded, [:sample]} = r([:sample])\n        assert :sample.hello() == :bye\n      end)\n    after\n      cleanup_modules([:sample])\n    end\n  end\n\n  describe \"pid/1,3\" do\n    test \"builds a PID from string\" do\n      assert inspect(pid(\"0.32767.0\")) == \"#PID<0.32767.0>\"\n      assert inspect(pid(\"0.5.0\")) == \"#PID<0.5.0>\"\n\n      assert_raise ArgumentError, fn ->\n        pid(\"0.6.-6\")\n      end\n    end\n\n    test \"builds a PID from atom\" do\n      assert inspect(pid(:init)) == \"#PID<0.0.0>\"\n\n      assert_raise ArgumentError, fn ->\n        pid(:random_atom_ZM6pX6VwQx)\n      end\n    end\n\n    test \"builds a PID from integers\" do\n      assert inspect(pid(0, 32767, 0)) == \"#PID<0.32767.0>\"\n      assert inspect(pid(0, 5, 0)) == \"#PID<0.5.0>\"\n\n      assert_raise FunctionClauseError, fn ->\n        pid(0, 6, -6)\n      end\n    end\n  end\n\n  describe \"port\" do\n    test \"builds a port from string\" do\n      assert inspect(port(\"0.8080\")) == \"#Port<0.8080>\"\n      assert inspect(port(\"0.0\")) == \"#Port<0.0>\"\n\n      assert_raise ArgumentError, fn ->\n        port(\"0.-6\")\n      end\n    end\n\n    test \"builds a port from integers\" do\n      assert inspect(port(0, 8080)) == \"#Port<0.8080>\"\n      assert inspect(port(0, 0)) == \"#Port<0.0>\"\n\n      assert_raise FunctionClauseError, fn ->\n        port(-1, -6)\n      end\n    end\n  end\n\n  describe \"ref\" do\n    test \"builds a ref from string\" do\n      ref = make_ref()\n      [_, inner, _] = String.split(inspect(ref), [\"<\", \">\"])\n      assert ref(inner) == ref\n\n      assert_raise ArgumentError, fn ->\n        ref(\"0.6.6.-6\")\n      end\n    end\n\n    test \"builds a ref from integers\" do\n      ref = make_ref()\n      [_, inner, _] = String.split(inspect(ref), [\"<\", \">\"])\n      [p1, p2, p3, p4] = inner |> String.split(\".\") |> Enum.map(&String.to_integer/1)\n      assert ref(p1, p2, p3, p4) == ref\n\n      assert_raise FunctionClauseError, fn ->\n        ref(0, 6, 6, -6)\n      end\n    end\n  end\n\n  describe \"i\" do\n    test \"prints information about the data type\" do\n      assert capture_io(fn -> i(:ok) end) =~ \"\"\"\n             Term\n               :ok\n             Data type\n               Atom\n             Reference modules\n               Atom\\\n             \"\"\"\n    end\n\n    test \"handles functions that don't display result\" do\n      assert capture_io(fn -> i(IEx.dont_display_result()) end) =~ \"\"\"\n             Term\n               :\"do not show this result in output\"\n             Data type\n               Atom\n             Description\n               This atom is returned by IEx when a function that should not print its\n               return value on screen is executed.\\\n             \"\"\"\n    end\n\n    defmodule MyIExInfoModule do\n      defstruct []\n\n      defimpl IEx.Info do\n        def info(_), do: [{\"A\", \"it's A\"}, {:b, \"it's :b\"}, {~c\"c\", \"it's 'c'\"}]\n      end\n    end\n\n    test \"uses the IEx.Info protocol\" do\n      assert capture_io(fn -> i(%MyIExInfoModule{}) end) =~ \"\"\"\n             Term\n               %IEx.HelpersTest.MyIExInfoModule{}\n             A\n               it's A\n             b\n               it's :b\n             c\n               it's 'c'\n             \"\"\"\n    after\n      cleanup_modules([MyIExInfoModule])\n    end\n  end\n\n  describe \"process_info/1\" do\n    test \"returns information about a process\" do\n      result = capture_io(fn -> process_info(self()) end)\n\n      assert result =~ \"Process #{inspect(self())}\"\n      assert result =~ \"## Overview\"\n      assert result =~ \"Initial call\"\n      assert result =~ \"## Memory\"\n      assert result =~ \"## Current stacktrace\"\n      assert result =~ \"IEx.Helpers.process_info/1\"\n\n      refute result =~ \"## Links\"\n      refute result =~ \"## Monitors\"\n    end\n\n    test \"includes process links and monitors\" do\n      pid =\n        spawn_link(fn ->\n          Process.register(self(), :iex_process_info_link_test)\n          Process.sleep(:infinity)\n        end)\n\n      Process.monitor(pid)\n\n      result = capture_io(fn -> process_info(self()) end)\n      assert result =~ \"## Links\"\n      assert result =~ \"## Monitors\"\n      assert result =~ \":iex_process_info_link_test\"\n    end\n  end\n\n  defp test_module_code do\n    \"\"\"\n    defmodule Sample do\n      def run do\n        :run\n      end\n    end\n    \"\"\"\n  end\n\n  defp another_test_module do\n    \"\"\"\n    defmodule Sample2 do\n      def hello do\n        :world\n      end\n    end\n    \"\"\"\n  end\n\n  defp erlang_module_code do\n    \"\"\"\n    -module(sample).\n    -export([hello/0]).\n    hello() -> world.\n    \"\"\"\n  end\n\n  defp other_erlang_module_code do\n    \"\"\"\n    -module(sample).\n    -export([hello/0]).\n    hello() -> bye.\n    \"\"\"\n  end\n\n  defp cleanup_modules(mods) do\n    Enum.each(mods, fn mod ->\n      File.rm(\"#{mod}.beam\")\n      :code.purge(mod)\n      :code.delete(mod)\n    end)\n  end\n\n  defp with_file(names, codes, fun) when is_list(names) and is_list(codes) do\n    Enum.each(Enum.zip(names, codes), fn {name, code} ->\n      File.write!(name, code)\n    end)\n\n    try do\n      fun.()\n    after\n      Enum.each(names, &File.rm/1)\n    end\n  end\n\n  defp with_file(name, code, fun) do\n    with_file(List.wrap(name), List.wrap(code), fun)\n  end\n\n  defp elixirc(args) do\n    executable = Path.expand(\"../../../../bin/elixirc\", __DIR__)\n    System.cmd(\"#{executable}#{executable_extension()}\", args, stderr_to_stdout: true)\n  end\n\n  defp iex_path do\n    Path.expand(\"../..\", __DIR__)\n  end\n\n  if match?({:win32, _}, :os.type()) do\n    defp executable_extension, do: \".bat\"\n  else\n    defp executable_extension, do: \"\"\n  end\nend\n"
  },
  {
    "path": "lib/iex/test/iex/info_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule IEx.InfoTest do\n  use ExUnit.Case\n\n  import ExUnit.CaptureLog\n\n  alias IEx.Info\n\n  defmodule Foo do\n    defstruct [:foo]\n  end\n\n  test \"tuples\" do\n    assert Info.info({:ok, \"good!\"}) == [{\"Data type\", \"Tuple\"}, {\"Reference modules\", \"Tuple\"}]\n  end\n\n  describe \"atoms\" do\n    test \"loaded module (without docs)\" do\n      info = Info.info(Foo)\n      assert get_key(info, \"Data type\") == \"Atom\"\n\n      assert get_key(info, \"Description\") ==\n               \"Call IEx.InfoTest.Foo.module_info() to access metadata.\"\n\n      assert get_key(info, \"Raw representation\") == ~s(:\"Elixir.IEx.InfoTest.Foo\")\n    end\n\n    @tag :requires_source\n    test \"loaded module (with source)\" do\n      info = Info.info(Foo)\n      assert get_key(info, \"Source\") == Path.relative_to_cwd(__ENV__.file)\n    end\n\n    test \"loaded module (with docs)\" do\n      info = Info.info(List)\n\n      description = \"\"\"\n      Use h(List) to access its documentation.\n      Call List.module_info() to access metadata.\\\n      \"\"\"\n\n      assert get_key(info, \"Description\") == description\n    end\n\n    test \"module that is also a protocol\" do\n      info = Info.info(String.Chars)\n      protocol_info = get_key(info, \"Protocol\")\n      assert protocol_info =~ \"This module is a protocol\"\n      assert protocol_info =~ \"Atom\"\n      assert protocol_info =~ \"BitString\"\n    end\n\n    test \"module-like atom (Foo)\" do\n      info = Info.info(NonexistentModuleAtom)\n      assert get_key(info, \"Raw representation\") == ~s(:\"Elixir.NonexistentModuleAtom\")\n    end\n\n    test \"regular atom\" do\n      assert Info.info(:foo) == [{\"Data type\", \"Atom\"}, {\"Reference modules\", \"Atom\"}]\n    end\n\n    test \"do not log errors if module exists with different casing\" do\n      assert capture_log(fn -> Info.info(Datetime) end) == \"\"\n    end\n  end\n\n  describe \"lists\" do\n    test \"charlists\" do\n      info = Info.info(~c\"foo\")\n      assert get_key(info, \"Description\") =~ \"This is a list of integers that is printed\"\n      assert get_key(info, \"Raw representation\") == \"[102, 111, 111]\"\n    end\n\n    test \"keyword lists\" do\n      info = Info.info(a: 1, b: 2)\n      assert get_key(info, \"Description\") =~ \"This is what is referred to as a \\\"keyword list\\\"\"\n    end\n\n    test \"regular lists\" do\n      assert get_key(Info.info([]), \"Reference modules\") == \"List\"\n      assert get_key(Info.info([:foo, :bar, :baz]), \"Reference modules\") == \"List\"\n    end\n  end\n\n  describe \"bitstring\" do\n    test \"strings\" do\n      info = Info.info(\"føø\")\n      assert get_key(info, \"Byte size\") == 5\n      assert get_key(info, \"Description\") =~ \"This is a string: a UTF-8 encoded binary\"\n      assert get_key(info, \"Raw representation\") == \"<<102, 195, 184, 195, 184>>\"\n    end\n\n    test \"non-printable string\" do\n      info = Info.info(<<\"foo\", 0, \"bar\">>)\n      description = get_key(info, \"Description\")\n\n      assert get_key(info, \"Byte size\") == 7\n      assert description =~ \"This is a string\"\n      assert description =~ \"It's printed with the `<<>>`\"\n      assert description =~ \"the first non-printable code point being\\n`<<0>>`\"\n    end\n\n    test \"binary\" do\n      info = Info.info(<<255, 255>>)\n      assert get_key(info, \"Description\") =~ \"This is a binary: a collection of bytes\"\n    end\n\n    test \"bitstring\" do\n      info = Info.info(<<1::1>>)\n      assert get_key(info, \"Bits size\") == 1\n      assert get_key(info, \"Description\") =~ \"This is a bitstring\"\n    end\n  end\n\n  test \"integers\" do\n    assert Info.info(99) == [{\"Data type\", \"Integer\"}, {\"Reference modules\", \"Integer\"}]\n  end\n\n  test \"float\" do\n    assert Info.info(3.14) == [{\"Data type\", \"Float\"}, {\"Reference modules\", \"Float\"}]\n  end\n\n  describe \"functions\" do\n    test \"named function\" do\n      info = Info.info(&String.length/1)\n      assert get_key(info, \"Type\") == \"external\"\n      assert get_key(info, \"Arity\") == 1\n    end\n\n    test \"anonymous function\" do\n      info = Info.info(fn -> :ok end)\n      assert get_key(info, \"Type\") == \"local\"\n      assert get_key(info, \"Arity\") == 0\n      assert get_key(info, \"Description\") == \"This is an anonymous function.\"\n    end\n  end\n\n  test \"PIDs\" do\n    pid = spawn_link(fn -> Process.sleep(1000) end)\n\n    info = Info.info(pid)\n    assert get_key(info, \"Alive\") == true\n    assert get_key(info, \"Name\") == \"not registered\"\n    assert get_key(info, \"Links\") == inspect(self())\n    assert get_key(info, \"Message queue length\") == 0\n\n    Process.register(pid, :iex_info_registered_pid)\n    Process.unlink(pid)\n    send(pid, :oops)\n    info = Info.info(pid)\n    assert get_key(info, \"Name\") == \":iex_info_registered_pid\"\n    assert get_key(info, \"Links\") == \"none\"\n    assert get_key(info, \"Message queue length\") == 1\n\n    Process.exit(pid, :kill)\n    assert get_key(Info.info(pid), \"Alive\") == false\n  end\n\n  test \"ports\" do\n    {:ok, port} = :gen_udp.open(0)\n    assert get_key(Info.info(port), \"Open\") == true\n    :ok = :gen_udp.close(port)\n    assert get_key(Info.info(port), \"Open\") == false\n  end\n\n  test \"references\" do\n    assert Info.info(make_ref()) == [{\"Data type\", \"Reference\"}]\n  end\n\n  describe \"calendar types\" do\n    test \"date\" do\n      {:ok, date} = Date.new(2017, 1, 1)\n      info = Info.info(date)\n      assert get_key(info, \"Data type\") == \"Date\"\n\n      assert get_key(info, \"Raw representation\") ==\n               \"%Date{year: 2017, month: 1, day: 1, calendar: Calendar.ISO}\"\n\n      assert get_key(info, \"Reference modules\") == \"Date, Calendar, Map\"\n      assert get_key(info, \"Description\") =~ \"a date\"\n      assert get_key(info, \"Description\") =~ \"`~D`\"\n    end\n\n    test \"time\" do\n      {:ok, time} = Time.new(23, 59, 59)\n      info = Info.info(time)\n      assert get_key(info, \"Data type\") == \"Time\"\n\n      assert get_key(info, \"Raw representation\") ==\n               \"%Time{hour: 23, minute: 59, second: 59, microsecond: {0, 0}, calendar: Calendar.ISO}\"\n\n      assert get_key(info, \"Reference modules\") == \"Time, Calendar, Map\"\n      assert get_key(info, \"Description\") =~ \"a time\"\n      assert get_key(info, \"Description\") =~ \"`~T`\"\n    end\n\n    test \"datetime\" do\n      {:ok, date} = Date.new(2017, 1, 1)\n      {:ok, time} = Time.new(23, 59, 59)\n      {:ok, date_time} = DateTime.new(date, time)\n      info = Info.info(date_time)\n      assert get_key(info, \"Data type\") == \"DateTime\"\n\n      assert get_key(info, \"Raw representation\") ==\n               \"%DateTime{year: 2017, month: 1, day: 1, hour: 23, minute: 59, second: 59, time_zone: \\\"Etc/UTC\\\", zone_abbr: \\\"UTC\\\", utc_offset: 0, std_offset: 0, microsecond: {0, 0}, calendar: Calendar.ISO}\"\n\n      assert get_key(info, \"Reference modules\") == \"DateTime, Calendar, Map\"\n      assert get_key(info, \"Description\") =~ \"a datetime\"\n      assert get_key(info, \"Description\") =~ \"`~U`\"\n    end\n\n    test \"naive datetime\" do\n      {:ok, time} = NaiveDateTime.new(2017, 1, 1, 23, 59, 59)\n      info = Info.info(time)\n      assert get_key(info, \"Data type\") == \"NaiveDateTime\"\n\n      assert get_key(info, \"Raw representation\") ==\n               \"%NaiveDateTime{year: 2017, month: 1, day: 1, hour: 23, minute: 59, second: 59, microsecond: {0, 0}, calendar: Calendar.ISO}\"\n\n      assert get_key(info, \"Reference modules\") == \"NaiveDateTime, Calendar, Map\"\n\n      assert get_key(info, \"Description\") =~\n               ~S{a \"naive\" datetime (that is, a datetime without a time zone)}\n\n      assert get_key(info, \"Description\") =~ \"`~N`\"\n    end\n  end\n\n  test \"Regex\" do\n    info = Info.info(~r/(ab)+c/)\n    assert get_key(info, \"Data type\") == \"Regex\"\n    assert get_key(info, \"Description\")\n    assert get_key(info, \"Raw representation\") =~ \"%Regex{re_pattern: {:re_pattern, \"\n    assert get_key(info, \"Reference modules\") == \"Regex, :re\"\n  end\n\n  test \"Range\" do\n    info = Info.info(1..10//2)\n    assert get_key(info, \"Data type\") == \"Range\"\n    assert get_key(info, \"Description\")\n    assert get_key(info, \"Raw representation\") == \"%Range{first: 1, last: 10, step: 2}\"\n    assert get_key(info, \"Reference modules\") == \"Range\"\n  end\n\n  test \"maps\" do\n    info = Info.info(%{foo: \"bar\"})\n    assert get_key(info, \"Data type\") == \"Map\"\n    assert get_key(info, \"Reference modules\") == \"Map\"\n  end\n\n  test \"structs\" do\n    info = Info.info(%Foo{})\n    assert get_key(info, \"Data type\") == \"IEx.InfoTest.Foo\"\n\n    assert get_key(info, \"Description\") ==\n             \"This is a struct. Structs are maps with a __struct__ key.\"\n\n    assert get_key(info, \"Reference modules\") == \"IEx.InfoTest.Foo, Map\"\n  end\n\n  defp get_key(info, key) do\n    {^key, value} = List.keyfind(info, key, 0)\n    value\n  end\nend\n"
  },
  {
    "path": "lib/iex/test/iex/interaction_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule IEx.InteractionTest do\n  use IEx.Case\n\n  test \"whole output\" do\n    assert capture_io(\"IO.puts \\\"Hello world\\\"\", fn ->\n             IEx.Server.run(dot_iex: \"\")\n           end) =~\n             \"Interactive Elixir (#{System.version()}) - press Ctrl+C to exit (type h() ENTER for help)\" <>\n               \"\\niex(1)> Hello world\\n:ok\\niex(2)>\"\n  end\n\n  test \"empty input\" do\n    assert capture_iex(\"\\n\") == \"nil\"\n  end\n\n  test \"normal input\" do\n    assert capture_iex(\"1 + 2\") == \"3\"\n  end\n\n  test \"omits error color if exception has ansi reset character\" do\n    enabled? = IO.ANSI.enabled?()\n    Application.put_env(:elixir, :ansi_enabled, true)\n\n    expected = \"\"\"\n    ** (SyntaxError) invalid syntax found on iex:1:4:\n        \\e[31merror:\\e[0m syntax error before: '='\n        │\n      1 │ a += 2\n        │ \\e[31m   ^\\e[0m\n        │\n        └─ iex:1:4\n    \"\"\"\n\n    opts = [colors: [enabled: true]]\n    output = capture_iex(\"a += 2\", opts)\n\n    refute String.starts_with?(output, IO.ANSI.red())\n    assert output =~ expected\n\n    Application.put_env(:elixir, :ansi_enabled, enabled?)\n  end\n\n  test \"invalid input\" do\n    output = capture_iex(\"if true do ) false end\")\n\n    assert output =~ \"** (MismatchedDelimiterError) mismatched delimiter found on iex:1:12:\"\n    assert output =~ \"unexpected token: )\"\n    assert output =~ \"iex:1:12\"\n    assert output =~ \"if true do ) false end\"\n    assert output =~ \"└ unclosed delimiter\"\n    assert output =~ \"└ mismatched closing delimiter\"\n  end\n\n  test \"multiple vars\" do\n    code = \"\"\"\n    <<a, b, c, d, e, f, g, h, i, j :: binary>> = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>\n    <<a, b, c, d, e, f, g, h, i, x :: binary>> = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>\n    x\n    \"\"\"\n\n    assert capture_iex(code) =~ \"10\"\n  end\n\n  test \"code escape\" do\n    code = \"\"\"\n    1 \\\\\n    + 2\n    \"\"\"\n\n    assert capture_iex(code) =~ \"3\"\n  end\n\n  test \"no break\" do\n    input = \"\"\"\n      [\"a\n      b\n      c\n    \"\"\"\n\n    assert capture_iex(input) == \"\"\n  end\n\n  test \"break\" do\n    input = \"\"\"\n      [\"a\n      b\n      c\n    #iex:break\n    \"\"\"\n\n    output = capture_iex(input)\n\n    assert output =~ \"** (TokenMissingError) token missing on iex:1:\"\n    assert output =~ \"error:\"\n    assert output =~ \"incomplete expression\\n\"\n    assert output =~ \"iex:1\"\n  end\n\n  test \"module definition\" do\n    input = \"\"\"\n    defmodule Sample do\n      def foo, do: bar()\n      def bar, do: 13\n    end && Sample.foo()\n    \"\"\"\n\n    assert capture_iex(input) =~ \"13\"\n  after\n    :code.purge(Sample)\n    :code.delete(Sample)\n  end\n\n  test \"blocks\" do\n    input = \"\"\"\n    (\n      defmodule Sample do\n        def foo, do: bar()\n        def bar, do: 13\n      end\n      import Sample\n      foo()\n    )\n    \"\"\"\n\n    assert capture_iex(input) =~ \"13\"\n  after\n    :code.purge(Sample)\n    :code.delete(Sample)\n  end\n\n  test \"ExUnit.Assertions\" do\n    capture = capture_iex(\"import ExUnit.Assertions; assert 1 == 2\")\n    assert capture =~ \"** (ExUnit.AssertionError)\"\n    assert capture =~ \"assert 1 == 2\"\n  end\n\n  test \"prompt\" do\n    opts = [default_prompt: \"prompt(%counter)>\"]\n    assert capture_iex(\"1\\n\", opts, [], true) == \"prompt(1)> 1\\nprompt(2)>\"\n  end\n\n  if IO.ANSI.enabled?() do\n    test \"color\" do\n      opts = [colors: [enabled: true, eval_result: [:red]]]\n      assert capture_iex(\"1 + 2\", opts) == \"\\e[31m\\e[33m3\\e[0m\\e[31m\\e[0m\"\n      assert capture_iex(\"IO.ANSI.blue()\", opts) == \"\\e[31m\\e[32m\\\"\\\\e[34m\\\"\\e[0m\\e[31m\\e[0m\"\n\n      assert capture_iex(\"{:ok}\", opts) ==\n               \"\\e[31m\\e[39m{\\e[0m\\e[31m\\e[36m:ok\\e[0m\\e[31m\\e[39m}\\e[0m\\e[31m\\e[0m\"\n    end\n  end\n\n  test \"inspect opts\" do\n    opts = [\n      inspect: [\n        binaries: :as_binaries,\n        charlists: :as_lists,\n        structs: false,\n        limit: 4,\n        custom_options: [sort_maps: true]\n      ]\n    ]\n\n    assert capture_iex(\"<<45, 46, 47>>\\n[45, 46, 47]\\n%IO.Stream{}\", opts) ==\n             \"<<45, 46, 47>>\\n[45, 46, 47]\\n%{__struct__: IO.Stream, device: nil, line_or_bytes: :line, raw: true}\"\n  end\n\n  test \"exception\" do\n    exception = Regex.escape(\"** (ArithmeticError) bad argument in arithmetic expression\")\n\n    result = capture_iex(\"1 + :atom\\n:this_is_still_working\")\n    assert result =~ ~r/^#{exception}.+\\n:this_is_still_working$/s\n    refute result =~ ~r/erl_eval/s\n  end\n\n  test \"exception while invoking conflicting helpers\" do\n    import File, only: [open: 1], warn: false\n\n    assert capture_io(:stderr, fn ->\n             capture_iex(\"open('README.md')\", [], env: __ENV__)\n           end) =~\n             ~r\"function open/1 imported from both File and IEx.Helpers\"\n  end\n\n  test \"receive exit\" do\n    assert capture_iex(\"spawn_link(fn -> exit(:bye) end); Process.sleep(1000)\") =~\n             ~r\"\\*\\* \\(EXIT from #PID<\\d+\\.\\d+\\.\\d+>\\) shell process exited with reason: :bye\"\n\n    assert capture_iex(\"spawn_link(fn -> exit({:bye, [:world]}) end); Process.sleep(1000)\") =~\n             ~r\"\\*\\* \\(EXIT from #PID<\\d+\\.\\d+\\.\\d+>\\) shell process exited with reason: {:bye, \\[:world\\]}\"\n  end\n\n  test \"receive normal exits\" do\n    assert capture_iex(\"spawn_link(fn -> exit(:normal) end); Process.sleep(1000)\") =~ \":ok\"\n\n    assert capture_iex(\"spawn_link(fn -> exit(:shutdown) end); Process.sleep(1000)\") =~\n             ~r\"\\*\\* \\(EXIT from #PID<\\d+\\.\\d+\\.\\d+>\\) shell process exited with reason: shutdown\"\n\n    assert capture_iex(\"spawn_link(fn -> exit({:shutdown, :bye}) end); Process.sleep(1000)\") =~\n             ~r\"\\*\\* \\(EXIT from #PID<\\d+\\.\\d+\\.\\d+>\\) shell process exited with reason: shutdown: :bye\"\n  end\n\n  test \"receive exit from exception\" do\n    # use exit/1 to fake an error so that an error message\n    # is not sent to the error logger.\n    content = capture_iex(\"spawn_link(fn -> exit({%ArgumentError{},\n                           [{:not_a_real_module, :function, 0, []}]}) end);\n                           Process.sleep(1000)\")\n\n    assert content =~\n             ~r\"\\*\\* \\(EXIT from #PID<\\d+\\.\\d+\\.\\d+>\\) shell process exited with reason: an exception was raised:\\n\"\n\n    assert content =~ ~r\"\\s{4}\\*\\* \\(ArgumentError\\) argument error\\n\"\n    assert content =~ ~r\"\\s{8}:not_a_real_module\\.function/0\"\n  end\n\n  test \"receive exit due to failed call\" do\n    assert capture_iex(\"exit({:bye, {:gen_server, :call, [self(), :hello]}})\") =~\n             ~r\"\\*\\* \\(exit\\) exited in: :gen_server\\.call\\(#PID<\\d+\\.\\d+\\.\\d+>, :hello\\)\\n\\s{4}\\*\\* \\(EXIT\\) :bye\"\n  end\n\n  test \"blames function clause error\" do\n    import PathHelpers\n\n    write_beam(\n      defmodule ExampleModule do\n        def fun(:valid), do: :ok\n      end\n    )\n\n    content = capture_iex(\"IEx.InteractionTest.ExampleModule.fun(:invalid)\")\n\n    assert content =~\n             \"** (FunctionClauseError) no function clause matching in IEx.InteractionTest.ExampleModule.fun/1\"\n\n    assert content =~\n             \"The following arguments were given to IEx.InteractionTest.ExampleModule.fun/1\"\n\n    assert content =~ \":invalid\"\n    assert content =~ \"def fun(-:valid-)\"\n\n    assert content =~\n             ~r\"test/iex/interaction_test.exs:\\d+: IEx\\.InteractionTest\\.ExampleModule\\.fun/1\"\n\n    content = capture_iex(\"Access.fetch(:foo, :bar)\")\n\n    assert content =~ ~r\"\\(elixir #{System.version()}\\) lib/access\\.ex:\\d+: Access\\.fetch/2\"\n  end\n\n  test \"parser\" do\n    defmodule EchoParser do\n      def parse(input, _opts, buffer) do\n        {:ok, input, buffer}\n      end\n    end\n\n    assert capture_iex(\"foo\", parser: {EchoParser, :parse, []}) == \"~c\\\"foo\\\"\"\n  after\n    IEx.configure(parser: {IEx.Evaluator, :parse, []})\n  end\n\n  ## .iex file loading\n\n  describe \".iex\" do\n    test \"no .iex\" do\n      assert capture_io(:stderr, fn -> capture_iex(\"my_variable\") end) =~\n               \"undefined variable \\\"my_variable\\\"\"\n    end\n\n    @tag :tmp_dir\n    test \"single .iex\", %{tmp_dir: tmp_dir} do\n      path =\n        write_dot_iex!(tmp_dir, \"dot-iex\", \"\"\"\n        defmodule DotIEx do\n          def my_fun_single, do: :single\n        end\n        import DotIEx\n        my_variable = 42\n        \"\"\")\n\n      assert capture_iex(\"{my_fun_single(), my_variable}\", [], dot_iex: path) ==\n               \"{:single, 42}\"\n    end\n\n    @tag :tmp_dir\n    test \"nested .iex\", %{tmp_dir: tmp_dir} do\n      write_dot_iex!(tmp_dir, \"dot-iex-1\", \"\"\"\n      defmodule DotIExNested do\n        def my_fun_nested, do: :nested\n      end\n      import DotIExNested\n      nested_var = 42\n      \"\"\")\n\n      path =\n        write_dot_iex!(tmp_dir, \"dot-iex\", \"import_file \\\"#{tmp_dir}/dot-iex-1\\\"\\nmy_variable=13\")\n\n      input = \"nested_var\\nmy_variable\\nmy_fun_nested()\"\n      assert capture_iex(input, [], dot_iex: path) == \"42\\n13\\n:nested\"\n    end\n\n    @tag :tmp_dir\n    test \"configured .iex\", %{tmp_dir: tmp_dir} do\n      path =\n        write_dot_iex!(tmp_dir, \"configured-dot-iex\", \"\"\"\n        defmodule ConfiguredDotIEx do\n          def my_fun_single, do: :single\n        end\n        import ConfiguredDotIEx\n        my_variable = 42\n        \"\"\")\n\n      assert capture_iex(\"{my_fun_single(), my_variable}\", [dot_iex: path], dot_iex: nil) ==\n               \"{:single, 42}\"\n    end\n  end\n\n  defp write_dot_iex!(tmp_dir, name, contents) do\n    path = Path.join(tmp_dir, name)\n    File.write!(path, contents)\n    path\n  end\n\n  describe \"pipeline error safety\" do\n    test \"syntax error in pipeline prevents subsequent operations\" do\n      input = \"\"\"\n      1, 2, 3]\n      |> Enum.map(&(&1 * 2))\n      \"\"\"\n\n      output = capture_iex(input)\n      assert output =~ \"skipping evaluation of expression because pipeline has failed\"\n    end\n\n    test \"runtime error in first pipeline step prevents subsequent operations\" do\n      input = \"\"\"\n      :not_a_list\n      |> Enum.map(&(&1 * 2))\n      |> Enum.sum()\n      \"\"\"\n\n      output = capture_iex(input)\n      assert output =~ \"skipping evaluation of expression because pipeline has failed\"\n    end\n\n    test \"error state is cleared after successful evaluation\" do\n      input = \"\"\"\n      :not_a_list\n      |> Enum.map(&(&1 * 2))\n      |> Enum.sum()\n      [1, 2, 3]\n      |> Enum.sum()\n      \"\"\"\n\n      output = capture_iex(input)\n      assert output =~ \"skipping evaluation of expression because pipeline has failed\"\n      assert String.ends_with?(output, \"6\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/iex/test/iex/pry_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule IEx.PryTest do\n  use ExUnit.Case\n\n  setup do\n    on_exit(fn -> IEx.Pry.remove_breaks() end)\n  end\n\n  describe \"whereami\" do\n    test \"shows lines with radius\" do\n      Application.put_env(:elixir, :ansi_enabled, true)\n\n      {:ok, contents} = IEx.Pry.whereami(__ENV__.file, 7, 2)\n\n      assert IO.iodata_to_binary(contents) == \"\"\"\n                 5: Code.require_file(\"../test_helper.exs\", __DIR__)\n                 6:\\s\n             \\e[1m    7: defmodule IEx.PryTest do\n             \\e[22m    8:   use ExUnit.Case\n                 9:\\s\n             \"\"\"\n\n      {:ok, contents} = IEx.Pry.whereami(__ENV__.file, 7, 1)\n\n      assert IO.iodata_to_binary(contents) == \"\"\"\n                 6:\\s\n             \\e[1m    7: defmodule IEx.PryTest do\n             \\e[22m    8:   use ExUnit.Case\n             \"\"\"\n    after\n      Application.delete_env(:elixir, :ansi_enabled)\n    end\n\n    test \"returns error for unknown files\" do\n      assert IEx.Pry.whereami(\"unknown\", 3, 2) == :error\n    end\n\n    test \"returns error for out of range lines\" do\n      assert IEx.Pry.whereami(__ENV__.file, 1000, 2) == :error\n    end\n  end\n\n  describe \"break\" do\n    test \"sets up a breakpoint on the given module\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert instrumented?(PryExampleModule)\n      assert [_] = IEx.Pry.breaks()\n    end\n\n    test \"sets up multiple breakpoints in the same module\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert instrumented?(PryExampleModule)\n      assert IEx.Pry.break(PryExampleModule, :one, 1) == {:ok, 2}\n      assert instrumented?(PryExampleModule)\n      assert [_, _] = IEx.Pry.breaks()\n    end\n\n    test \"reinstruments if module has been reloaded\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert instrumented?(PryExampleModule)\n      deinstrument!(PryExampleModule)\n      refute instrumented?(PryExampleModule)\n      assert IEx.Pry.break(PryExampleModule, :one, 1) == {:ok, 2}\n      assert instrumented?(PryExampleModule)\n      assert [_, _] = IEx.Pry.breaks()\n    end\n\n    test \"returns ID when breakpoint is already set\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert [_] = IEx.Pry.breaks()\n    end\n\n    test \"returns ID even when breakpoint is already set on deinstrument\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      deinstrument!(PryExampleModule)\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert [_] = IEx.Pry.breaks()\n    end\n\n    test \"errors when setting up a break with no beam\" do\n      assert IEx.Pry.break(__MODULE__, :setup, 2) == {:error, :no_beam_file}\n    end\n\n    test \"errors when setting up a break for unknown function\" do\n      assert IEx.Pry.break(PryExampleModule, :unknown, 2) == {:error, :unknown_function_arity}\n    end\n\n    test \"errors for non-Elixir modules\" do\n      assert IEx.Pry.break(:maps, :unknown, 2) == {:error, :non_elixir_module}\n    end\n  end\n\n  describe \"breaks\" do\n    test \"returns all breaks\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}]\n\n      assert IEx.Pry.break(PryExampleModule, :two, 2, 10) == {:ok, 1}\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 10}]\n\n      assert IEx.Pry.break(PryExampleModule, :one, 1, 1) == {:ok, 2}\n\n      assert IEx.Pry.breaks() == [\n               {1, PryExampleModule, {:two, 2}, 10},\n               {2, PryExampleModule, {:one, 1}, 1}\n             ]\n    end\n\n    test \"sets negative break to 0\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      :ets.insert(IEx.Pry, {1, PryExampleModule, {:two, 2}, {[], true}, -1})\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}]\n    end\n\n    test \"do not return break points for deinstrumented modules\" do\n      assert IEx.Pry.break(PryExampleModule, :one, 1) == {:ok, 1}\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:one, 1}, 1}]\n      deinstrument!(PryExampleModule)\n      assert IEx.Pry.breaks() == []\n    end\n  end\n\n  describe \"reset_break\" do\n    test \"resets break for given ID\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert IEx.Pry.reset_break(1) == :ok\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}]\n    end\n\n    test \"resets break for given mfa\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert IEx.Pry.reset_break(PryExampleModule, :two, 2) == :ok\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 0}]\n    end\n\n    test \"returns not_found if module is deinstrumented\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      deinstrument!(PryExampleModule)\n      assert IEx.Pry.reset_break(PryExampleModule, :two, 2) == :not_found\n      assert IEx.Pry.breaks() == []\n    end\n\n    test \"returns not_found if mfa has no break\" do\n      assert IEx.Pry.reset_break(PryExampleModule, :two, 2) == :not_found\n    end\n\n    test \"returns not_found if ID is deinstrumented\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      deinstrument!(PryExampleModule)\n      assert IEx.Pry.reset_break(1) == :not_found\n      assert IEx.Pry.breaks() == []\n    end\n\n    test \"returns not_found if ID has no break\" do\n      assert IEx.Pry.reset_break(1) == :not_found\n    end\n  end\n\n  describe \"remove_breaks\" do\n    test \"removes all breaks\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert IEx.Pry.remove_breaks() == :ok\n      assert IEx.Pry.breaks() == []\n    end\n\n    test \"removes all breaks even if module is deinstrumented\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      deinstrument!(PryExampleModule)\n      assert IEx.Pry.remove_breaks() == :ok\n      assert IEx.Pry.breaks() == []\n    end\n\n    test \"remove breaks in a given module\" do\n      assert IEx.Pry.remove_breaks(PryExampleStruct) == :ok\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      assert IEx.Pry.break(PryExampleStruct, :__struct__, 1) == {:ok, 2}\n      assert IEx.Pry.remove_breaks(PryExampleStruct) == :ok\n      assert IEx.Pry.breaks() == [{1, PryExampleModule, {:two, 2}, 1}]\n    end\n\n    test \"remove breaks in a given module even if deinstrumented\" do\n      assert IEx.Pry.break(PryExampleModule, :two, 2) == {:ok, 1}\n      deinstrument!(PryExampleModule)\n      assert IEx.Pry.breaks() == []\n    end\n  end\n\n  describe \"annotate_quoted\" do\n    def annotate_quoted(block, condition \\\\ true) do\n      {:__block__, meta, [{:=, _, [{:env, _, _}, _]} | tail]} =\n        block\n        |> Code.string_to_quoted!()\n        |> IEx.Pry.annotate_quoted(condition, %{__ENV__ | line: 1})\n\n      Macro.to_string({:__block__, meta, tail})\n    end\n\n    test \"one expression, one line\" do\n      assert annotate_quoted(\"\"\"\n             x = 123\n             y = 456\n             x + y\n             \"\"\") == \"\"\"\n             next? = true\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 1})\n             x = 123\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 2})\n             y = 456\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 3})\n             x + y\\\n             \"\"\"\n    end\n\n    test \"one expression, multiple lines\" do\n      assert annotate_quoted(\"\"\"\n             (x = 123) &&\n              (y = 456)\n             x + y\n             \"\"\") == \"\"\"\n             next? = true\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 1})\n             (x = 123) && (y = 456)\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 3})\n             x + y\\\n             \"\"\"\n    end\n\n    test \"one line, multiple expressions\" do\n      assert annotate_quoted(\"\"\"\n             x = 123; y = 456\n             x + y\n             \"\"\") == \"\"\"\n             next? = true\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 1})\n             x = 123\n             y = 456\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 2})\n             x + y\\\n             \"\"\"\n    end\n\n    test \"multiple line, multiple expressions\" do\n      assert annotate_quoted(\"\"\"\n             x = 123; y =\n              456\n             x + y\n             \"\"\") == \"\"\"\n             next? = true\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 1})\n             x = 123\n             y = 456\n             next? = IEx.Pry.__next__(next?, binding(), %{env | line: 3})\n             x + y\\\n             \"\"\"\n    end\n  end\n\n  defp instrumented?(module) do\n    module.module_info(:attributes)[:iex_pry] == [true]\n  end\n\n  defp deinstrument!(module) do\n    beam = :code.which(module)\n    :code.purge(module)\n    {:module, _} = :code.load_binary(module, beam, File.read!(beam))\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/iex/test/iex/server_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule IEx.ServerTest do\n  use IEx.Case\n\n  require IEx\n\n  describe \"options\" do\n    test \"prefix\" do\n      assert capture_io(fn ->\n               IEx.Server.run(prefix: \"custom\", dot_iex: \"\")\n             end) =~ \"custom(1)> \"\n    end\n\n    test \"env\" do\n      assert capture_iex(\"__ENV__.file\", [], env: __ENV__) =~ \"server_test.exs\"\n    end\n  end\n\n  describe \"pry\" do\n    test \"inside evaluator itself\" do\n      assert capture_iex(\"require IEx; IEx.pry()\") =~ \"Break reached\"\n    end\n\n    test \"outside of the evaluator with acceptance\", config do\n      Process.register(self(), config.test)\n\n      {server, evaluator} = pry_session(config.test, \"Y\\niex_context\")\n      client = pry_request([server])\n      send(evaluator, :run)\n\n      assert Task.await(server) =~ \":inside_pry\"\n      assert Task.await(client) == {:ok, false}\n    end\n\n    test \"outside of the evaluator with refusal\", config do\n      Process.register(self(), config.test)\n\n      assert capture_io(:stderr, fn ->\n               {server, evaluator} = pry_session(config.test, \"N\\niex_context\")\n               client = pry_request([server])\n               send(evaluator, :run)\n\n               assert Task.await(client) == {:error, :refused}\n               assert Task.await(server) =~ \"cannot compile code\"\n             end) =~ \"undefined variable \\\"iex_context\\\"\"\n    end\n\n    test \"outside of the evaluator with crash\", config do\n      Process.register(self(), config.test)\n\n      {server, _evaluator} = pry_session(config.test, \"iex_context\")\n      client = pry_request([server])\n\n      _ = Task.shutdown(server, :brutal_kill)\n      assert Task.await(client) == {:error, :refused}\n    end\n\n    test \"outside of the evaluator with double acceptance\", config do\n      Process.register(self(), config.test)\n\n      assert capture_io(:stderr, fn ->\n               {server1, evaluator1} = pry_session(config.test, \"Y\\niex_context\")\n               {server2, evaluator2} = pry_session(config.test, \"Y\\niex_context\")\n               client = pry_request([server1, server2])\n\n               send(evaluator1, :run)\n               send(evaluator2, :run)\n               reply1 = Task.await(server1)\n               reply2 = Task.await(server2)\n\n               {accepted, refused} =\n                 if reply1 =~ \":inside_pry\", do: {reply1, reply2}, else: {reply2, reply1}\n\n               assert accepted =~ \":inside_pry\"\n               assert refused =~ \"** session was already accepted elsewhere\"\n\n               assert Task.await(client) == {:ok, false}\n             end) =~ \"undefined variable \\\"iex_context\\\"\"\n    end\n\n    test \"outside of the evaluator with double refusal\", config do\n      Process.register(self(), config.test)\n\n      assert capture_io(:stderr, fn ->\n               {server1, evaluator1} = pry_session(config.test, \"N\\niex_context\")\n               {server2, evaluator2} = pry_session(config.test, \"N\\niex_context\")\n               client = pry_request([server1, server2])\n\n               send(evaluator1, :run)\n               send(evaluator2, :run)\n               reply1 = Task.await(server1)\n               reply2 = Task.await(server2)\n\n               assert reply1 =~ \"cannot compile code\"\n               assert reply2 =~ \"cannot compile code\"\n\n               assert Task.await(client) == {:error, :refused}\n             end) =~ \"undefined variable \\\"iex_context\\\"\"\n    end\n\n    test \"outside of the evaluator with acceptance and then refusal\", config do\n      Process.register(self(), config.test)\n\n      assert capture_io(:stderr, fn ->\n               {server1, evaluator1} = pry_session(config.test, \"Y\\niex_context\")\n               {server2, evaluator2} = pry_session(config.test, \"N\\niex_context\")\n               client = pry_request([server1, server2])\n\n               send(evaluator1, :run)\n               send(evaluator2, :run)\n               assert Task.await(server1) =~ \":inside_pry\"\n               assert Task.await(server2) =~ \"cannot compile code\"\n\n               assert Task.await(client) == {:ok, false}\n             end) =~ \"undefined variable \\\"iex_context\\\"\"\n    end\n\n    test \"outside of the evaluator with refusal and then acceptance\", config do\n      Process.register(self(), config.test)\n\n      assert capture_io(:stderr, fn ->\n               {server1, evaluator1} = pry_session(config.test, \"N\\niex_context\")\n               {server2, evaluator2} = pry_session(config.test, \"Y\\niex_context\")\n               client = pry_request([server1, server2])\n\n               send(evaluator1, :run)\n               send(evaluator2, :run)\n               assert Task.await(server1) =~ \"cannot compile code\"\n               assert Task.await(server2) =~ \":inside_pry\"\n\n               assert Task.await(client) == {:ok, false}\n             end) =~ \"undefined variable \\\"iex_context\\\"\"\n    end\n\n    @tag :tmp_dir\n    test \"outside evaluator with .iex\", %{tmp_dir: tmp_dir} = config do\n      Process.register(self(), config.test)\n      path = Path.join(tmp_dir, \"dot-iex\")\n      File.write!(path, \"my_variable = 144\")\n\n      assert capture_io(:stderr, fn ->\n               {server, evaluator} =\n                 pry_session(config.test, \"Y\\nmy_variable\", dot_iex: path)\n\n               client = pry_request([server])\n               send(evaluator, :run)\n\n               assert Task.await(server) =~ \"** (CompileError)\"\n\n               assert Task.await(client) == {:ok, false}\n             end) =~ \"undefined variable \\\"my_variable\\\"\"\n    end\n\n    @tag :tmp_dir\n    test \"after pry outside evaluator .iex\", %{tmp_dir: tmp_dir} = config do\n      Process.register(self(), config.test)\n      path = Path.join(tmp_dir, \"dot-iex\")\n      File.write!(path, \"my_variable = 144\")\n\n      {server, evaluator} =\n        pry_session(config.test, \"Y\\ncontinue\\nmy_variable\", dot_iex: path)\n\n      client = pry_request([server])\n      send(evaluator, :run)\n\n      assert Task.await(server) =~ \"144\"\n      assert Task.await(client) == {:ok, false}\n\n      {server, evaluator} = pry_session(config.test, \"Y\\nnext\\nmy_variable\", dot_iex: path)\n\n      client = pry_request([server])\n      send(evaluator, :run)\n\n      assert Task.await(server) =~ \"144\"\n      assert Task.await(client) == {:ok, true}\n    end\n  end\n\n  # Helpers\n\n  defp pry_session(name, session, server_options \\\\ []) do\n    task =\n      Task.async(fn ->\n        capture_iex(\n          \"\"\"\n          send(#{inspect(name)}, {:running, self()}) && receive do: (:run -> :ok)\n          #{session}\n          \"\"\",\n          [],\n          server_options\n        )\n      end)\n\n    assert_receive {:running, evaluator}\n    {task, evaluator}\n  end\n\n  defp pry_request(sessions) do\n    :erlang.trace(Process.whereis(IEx.Broker), true, [:receive, tracer: self()])\n    patterns = for %{pid: pid} <- sessions, do: {[:_, pid, :_], [], []}\n    :erlang.trace_pattern(:receive, patterns, [])\n\n    task =\n      Task.async(fn ->\n        iex_context = :inside_pry\n        IEx.pry()\n      end)\n\n    for _ <- sessions do\n      assert_receive {:trace, _, :receive, {_, _, call}} when elem(call, 0) in [:accept, :refuse]\n    end\n\n    task\n  after\n    :erlang.trace(Process.whereis(IEx.Broker), false, [:receive, tracer: self()])\n  end\nend\n"
  },
  {
    "path": "lib/iex/test/test_helper.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Beam files compiled on demand\npath = Path.expand(\"../tmp/beams\", __DIR__)\nFile.rm_rf!(path)\nFile.mkdir_p!(path)\nCode.prepend_path(path)\nSystem.put_env(\"ELIXIR_EDITOR\", \"echo\")\n\n{:ok, _} = Application.ensure_all_started(:iex)\nIEx.configure(colors: [enabled: false], dot_iex: \"/path/to/unknown/file\")\n\n{line_exclude, line_include} =\n  if line = System.get_env(\"LINE\"), do: {[:test], [line: line]}, else: {[], []}\n\nerlang_doc_exclude =\n  if match?({:docs_v1, _, _, _, %{}, _, _}, Code.fetch_docs(:array)) do\n    []\n  else\n    IO.puts(\"Erlang/OTP compiled without docs, some tests are excluded...\")\n    [:erlang_doc]\n  end\n\nsource_exclude =\n  if :deterministic in :compile.env_compiler_options() do\n    [:requires_source]\n  else\n    []\n  end\n\nCode.require_file(\"../../elixir/scripts/cover_record.exs\", __DIR__)\n\ncover_exclude =\n  if CoverageRecorder.maybe_record(\"iex\") do\n    [:require_ast]\n  else\n    []\n  end\n\nmaybe_seed_opt = if seed = System.get_env(\"SEED\"), do: [seed: String.to_integer(seed)], else: []\n\nex_unit_opts =\n  [\n    trace: !!System.get_env(\"TRACE\"),\n    include: line_include,\n    exclude: line_exclude ++ erlang_doc_exclude ++ source_exclude ++ cover_exclude,\n    assert_receive_timeout: String.to_integer(System.get_env(\"ELIXIR_ASSERT_TIMEOUT\", \"300\"))\n  ] ++ maybe_seed_opt\n\nExUnit.start(ex_unit_opts)\n\ndefmodule IEx.Case do\n  use ExUnit.CaseTemplate\n  @moduledoc false\n\n  # Provides convenience functions for testing IEx-related functionality.\n  # Use this module inside your test module like this:\n  #\n  #   defmodule IEx.InteractionTest do\n  #     use IEx.Case\n  #\n  #     test \"input\" do\n  #       assert capture_iex(\"1+2\") == \"3\"\n  #     end\n  #   end\n  #\n  # The environment provided by capture_iex is mostly similar to the normal IEx\n  # session, except colors are disabled by default and .iex files are not\n  # loaded.\n  #\n  # You can provide your own IEx configuration and a path to a .iex file as\n  # additional arguments to the capture_iex function.\n\n  using do\n    quote do\n      import ExUnit.CaptureIO\n      import ExUnit.CaptureLog\n      import unquote(__MODULE__)\n    end\n  end\n\n  @keys [:default_prompt, :alive_prompt, :inspect, :colors, :history_size, :dot_iex]\n  @iex_env Application.get_all_env(:iex) |> Keyword.take(@keys)\n\n  setup do\n    on_exit(fn ->\n      env = @iex_env\n      Enum.each(@keys, &Application.delete_env(:iex, &1))\n      IEx.configure(env)\n    end)\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Starts an IEx eval loop, feeds it the provided input and returns produced\n  output. The output is stripped of the first intro line and of any trailing\n  whitespace.\n\n  Options, if provided, will be set before the eval loop is started.\n\n  If you provide server options, it will be passed to\n  IEx.Server.run to be used in the normal .iex loading process.\n  \"\"\"\n  def capture_iex(input, options \\\\ [], server_options \\\\ [], capture_prompt \\\\ false) do\n    IEx.configure(options)\n\n    ExUnit.CaptureIO.capture_io([input: input, capture_prompt: capture_prompt], fn ->\n      IEx.Server.run(server_options)\n    end)\n    |> strip_iex()\n  end\n\n  defp strip_iex(string) do\n    string\n    |> String.split(\"\\n\", parts: 2)\n    |> Enum.at(1)\n    |> String.trim()\n  end\nend\n\ndefmodule PathHelpers do\n  def write_beam({:module, name, bin, _} = res) do\n    File.mkdir_p!(unquote(path))\n    beam_path = Path.join(unquote(path), Atom.to_string(name) <> \".beam\")\n    File.write!(beam_path, bin)\n\n    :code.purge(name)\n    :code.delete(name)\n\n    res\n  end\nend\n\nPathHelpers.write_beam(\n  defmodule HelperExampleModule do\n    def fun(_arg), do: :ok\n    defmacro macro(_arg), do: :ok\n  end\n)\n\nPathHelpers.write_beam(\n  defmodule PryExampleModule do\n    def one(_arg), do: :ok\n    def two(_arg1, _arg2), do: :ok\n  end\n)\n\nPathHelpers.write_beam(\n  defmodule PryExampleStruct do\n    defstruct one: nil\n  end\n)\n"
  },
  {
    "path": "lib/logger/lib/logger/app.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.App do\n  @moduledoc false\n\n  use Application\n\n  @doc false\n  def start(_type, _args) do\n    otp_reports? = Application.fetch_env!(:logger, :handle_otp_reports)\n    sasl_reports? = Application.fetch_env!(:logger, :handle_sasl_reports)\n    translators = Application.fetch_env!(:logger, :translators)\n\n    {backends, console?} =\n      case Application.fetch_env(:logger, :backends) do\n        {:ok, backends} ->\n          IO.warn(\"\"\"\n          the :backends key for the :logger application is deprecated.\n          Here is how to proceed:\n\n          1. If you want to set it to [:console], simply remove the option.\n\n          2. If you want to disable logging, remove :backends and instead set:\n\n              config :logger, :default_handler, false\n\n          3. If you want to configure any other backend, then it is recommended\n             to add `{:logger_backends, \"~> 1.0\"}` as a dependency and call\n             `LoggerBackends.add(CustomBackend)` in your application start callback\n          \"\"\")\n\n          {List.delete(backends, :console), :console in backends}\n\n        :error ->\n          {[], true}\n      end\n\n    # TODO: Warn if :console is set on Elixir v1.20\n    default_handler =\n      if console = Application.get_env(:logger, :console) do\n        {handler, formatter} = Keyword.split(console, [:level])\n\n        with :error <- Application.fetch_env(:logger, :default_formatter) do\n          Application.put_env(:logger, :default_formatter, formatter)\n        end\n\n        handler\n      else\n        []\n      end\n\n    primary_config = :logger.get_primary_config()\n    :ok = :logger.set_primary_config(:level, default_level())\n\n    # If there is additional metadata in the :logger config, we merge it into\n    # the primary :logger metadata.\n    with [_ | _] = metadata <- Application.fetch_env!(:logger, :metadata) do\n      :ok = :logger.set_primary_config(:metadata, Enum.into(metadata, primary_config.metadata))\n    end\n\n    process_level_filter = {&Logger.Utils.process_level/2, []}\n    :ok = :logger.add_primary_filter(:logger_process_level, process_level_filter)\n\n    translator_config = %{translators: translators, otp: otp_reports?, sasl: sasl_reports?}\n    translator_filter = {&Logger.Utils.translator/2, translator_config}\n    :ok = :logger.add_primary_filter(:logger_translator, translator_filter)\n\n    revert = [{:set_primary_config, [primary_config]} | remove_erlang_handler()]\n    children = if backends != [], do: [Logger.Backends.Internal], else: []\n\n    case Supervisor.start_link(children, strategy: :one_for_one, name: Logger.Supervisor) do\n      {:ok, sup} ->\n        {:ok, sup, [add_elixir_handler(console? && default_handler) | revert]}\n\n      {:error, _} = error ->\n        redo(revert)\n        error\n    end\n  end\n\n  @doc false\n  def start do\n    Application.start(:logger)\n  end\n\n  @doc false\n  def stop(revert) do\n    # TODO: Remove this line and all of Logger.Backends.* on Elixir v2.0+\n    _ = :logger.remove_handler(Logger)\n    _ = :logger.remove_primary_filter(:logger_process_level)\n    _ = :logger.remove_primary_filter(:logger_translator)\n\n    redo(revert)\n\n    :logger.add_primary_filter(\n      :silence_logger_exit,\n      {&Logger.Utils.silence_logger_exit/2, []}\n    )\n  end\n\n  @doc false\n  def config_change(changed, _new, _removed) do\n    # All other config has already been persisted, we only need to\n    # update the level and reload the logger state.\n    Logger.configure(Keyword.take(changed, [:level]))\n  end\n\n  @doc \"\"\"\n  Stops the application without sending messages to error logger.\n  \"\"\"\n  def stop() do\n    Application.stop(:logger)\n  end\n\n  ## Helpers\n\n  defp default_level() do\n    case Application.get_env(:logger, :level, :debug) do\n      :warn ->\n        IO.warn(\n          \":logger :level has been set to :warn in config files, please use :warning instead\"\n        )\n\n        :warning\n\n      level ->\n        level\n    end\n  end\n\n  defp remove_erlang_handler() do\n    with {:ok, %{module: module} = config} <- :logger.get_handler_config(:default),\n         :ok <- :logger.remove_handler(:default) do\n      [{:add_handler, [:default, module, config]}]\n    else\n      _ -> []\n    end\n  end\n\n  defp add_elixir_handler(default_handler) do\n    if handler = Application.get_env(:logger, :default_handler, default_handler) do\n      config =\n        handler\n        |> Keyword.put_new(:filters, remote_gl: {&:logger_filters.remote_gl/2, :stop})\n        |> Keyword.put_new(:filter_default, :log)\n        |> Keyword.put_new(:module, :logger_std_h)\n        |> Keyword.put_new_lazy(:formatter, &Logger.default_formatter/0)\n        |> Keyword.replace_lazy(:config, &Map.new/1)\n        |> Map.new()\n\n      case :logger.add_handler(:default, config.module, config) do\n        :ok ->\n          [{:remove_handler, [:default]}]\n\n        {:error, error} ->\n          IO.puts(:stderr, \"Could not attach default Logger handler: #{inspect(error)}\")\n      end\n    else\n      []\n    end\n  end\n\n  defp redo(handlers) do\n    for {fun, args} <- handlers do\n      apply(:logger, fun, args)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/backends/config.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Backends.Config do\n  @moduledoc false\n\n  @behaviour :gen_event\n  @name __MODULE__\n  @update_counter_message {__MODULE__, :update_counter}\n\n  def configure(options) do\n    :gen_event.call(Logger, @name, {:configure, options})\n  end\n\n  ## Callbacks\n\n  def init(counter) do\n    state = load_state(counter)\n    state = update_counter(state, false)\n    schedule_update_counter(state)\n    {:ok, state}\n  end\n\n  defp load_state(counter) do\n    {counter, :log, Application.fetch_env!(:logger, :discard_threshold),\n     Application.fetch_env!(:logger, :discard_threshold_periodic_check)}\n  end\n\n  def handle_event(_event, state) do\n    {:ok, update_counter(state, false)}\n  end\n\n  def handle_call({:configure, options}, {counter, _, _, _}) do\n    Enum.each(options, fn {key, value} ->\n      Application.put_env(:logger, key, value)\n    end)\n\n    {:ok, :ok, load_state(counter)}\n  end\n\n  def handle_info(@update_counter_message, state) do\n    state = update_counter(state, true)\n    schedule_update_counter(state)\n    {:ok, state}\n  end\n\n  def handle_info(_, state) do\n    {:ok, state}\n  end\n\n  def terminate(_reason, _state) do\n    :ok\n  end\n\n  def code_change(_old, state, _extra) do\n    {:ok, state}\n  end\n\n  @counter_pos 1\n\n  defp update_counter({counter, log, discard_threshold, discard_period}, periodic_check?) do\n    # If length is more than the total, it means the counter is behind,\n    # due to non-log messages, so we need to increase the counter.\n    #\n    # If length is less than the total, then we either have a spike or\n    # the counter drifted due to failures.\n    #\n    # Because we always bump the counter and then we send the message,\n    # there is a chance clients have bumped the counter but they did not\n    # deliver the message yet. Those bumps will be lost. At the same time,\n    # we are careful to read the counter first here, so if the counter is\n    # bumped after we read from it, those bumps won't be lost.\n    total = :counters.get(counter, @counter_pos)\n    {:message_queue_len, length} = Process.info(self(), :message_queue_len)\n    :counters.add(counter, @counter_pos, length - total)\n\n    # In case we are logging but we reached the threshold, we log that we\n    # started discarding messages. This can only be reverted by the periodic\n    # discard check.\n    cond do\n      total >= discard_threshold ->\n        if log == :log or periodic_check? do\n          warn(\"Attempted to log #{total} messages, which is above :discard_threshold\")\n        end\n\n        {counter, :discard, discard_threshold, discard_period}\n\n      log == :discard and periodic_check? ->\n        warn(\"Attempted to log #{total} messages, which is below :discard_threshold\")\n        {counter, :log, discard_threshold, discard_period}\n\n      true ->\n        {counter, log, discard_threshold, discard_period}\n    end\n  end\n\n  defp warn(message) do\n    system_time = :os.system_time(:microsecond)\n    utc_log = Application.fetch_env!(:logger, :utc_log)\n    date_time_ms = Logger.Formatter.system_time_to_date_time_ms(system_time, utc_log)\n    event = {Logger, message, date_time_ms, pid: self()}\n    :gen_event.notify(self(), {:warning, Process.group_leader(), event})\n  end\n\n  defp schedule_update_counter({_, _, _, discard_period}) do\n    Process.send_after(self(), @update_counter_message, discard_period)\n  end\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/backends/console.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Backends.Console do\n  @moduledoc ~S\"\"\"\n  A logger backend that logs messages by printing them to the console.\n\n  This backend was typically configured as `config :logger, :console`,\n  but it has been deprecated in favor of `:default_handler` and\n  `:default_formatter`. However, for backwards compatibility, you can\n  still add it as:\n\n      config :logger, :backends, [Logger.Backends.Console]\n\n  However, if you plan to continue using Logger backends in the long\n  term, consider using the [`:logger_backends`](https://github.com/elixir-lang/logger_backends)\n  project.\n  \"\"\"\n\n  @moduledoc deprecated: \"Use LoggerBackends.Console from :logger_backends dependency\"\n  @behaviour :gen_event\n\n  defstruct buffer: [],\n            buffer_size: 0,\n            colors: nil,\n            device: nil,\n            format: nil,\n            level: nil,\n            max_buffer: nil,\n            metadata: nil,\n            output: nil,\n            ref: nil\n\n  # TODO: Deprecate me on Elixir v1.20\n  @impl true\n  def init(atom) when is_atom(atom) do\n    IO.warn(\n      \"Logger.Backends.Console is deprecated, \" <>\n        \"you should migrate to the new :console handler, \" <>\n        \"see Logger.Backends.Console docs for more information\"\n    )\n\n    config = read_env()\n    device = Keyword.get(config, :device, :user)\n\n    if Process.whereis(device) do\n      {:ok, init(config, %__MODULE__{})}\n    else\n      {:error, :ignore}\n    end\n  end\n\n  def init({__MODULE__, opts}) when is_list(opts) do\n    config = configure_merge(read_env(), opts)\n    {:ok, init(config, %__MODULE__{})}\n  end\n\n  @impl true\n  def handle_call({:configure, options}, state) do\n    {:ok, :ok, configure(options, state)}\n  end\n\n  @impl true\n  def handle_event({level, _gl, {Logger, msg, ts, md}}, state) do\n    %{level: log_level, ref: ref, buffer_size: buffer_size, max_buffer: max_buffer} = state\n\n    {:erl_level, level} = List.keyfind(md, :erl_level, 0, {:erl_level, level})\n\n    cond do\n      not meet_level?(level, log_level) ->\n        {:ok, state}\n\n      is_nil(ref) ->\n        {:ok, log_event(level, msg, ts, md, state)}\n\n      buffer_size < max_buffer ->\n        {:ok, buffer_event(level, msg, ts, md, state)}\n\n      buffer_size === max_buffer ->\n        state = buffer_event(level, msg, ts, md, state)\n        {:ok, await_io(state)}\n    end\n  end\n\n  def handle_event(:flush, state) do\n    {:ok, flush(state)}\n  end\n\n  def handle_event(_, state) do\n    {:ok, state}\n  end\n\n  @impl true\n  def handle_info({:io_reply, ref, msg}, %{ref: ref} = state) do\n    {:ok, handle_io_reply(msg, state)}\n  end\n\n  def handle_info({:DOWN, ref, _, pid, reason}, %{ref: ref}) do\n    raise \"device #{inspect(pid)} exited: \" <> Exception.format_exit(reason)\n  end\n\n  def handle_info(_, state) do\n    {:ok, state}\n  end\n\n  @impl true\n  def code_change(_old_vsn, state, _extra) do\n    {:ok, state}\n  end\n\n  @impl true\n  def terminate(_reason, _state) do\n    :ok\n  end\n\n  ## Helpers\n\n  defp meet_level?(_lvl, nil), do: true\n\n  defp meet_level?(lvl, min) do\n    Logger.compare_levels(lvl, min) != :lt\n  end\n\n  defp configure(options, state) do\n    config = configure_merge(read_env(), options)\n    Application.put_env(:logger, __MODULE__, config)\n    init(config, state)\n  end\n\n  defp init(config, state) do\n    level = Keyword.get(config, :level)\n    device = Keyword.get(config, :device, :user)\n    format = Logger.Formatter.compile(Keyword.get(config, :format))\n    colors = configure_colors(config)\n    metadata = Keyword.get(config, :metadata, []) |> configure_metadata()\n    max_buffer = Keyword.get(config, :max_buffer, 32)\n\n    %{\n      state\n      | format: format,\n        metadata: metadata,\n        level: level,\n        colors: colors,\n        device: device,\n        max_buffer: max_buffer\n    }\n  end\n\n  defp configure_metadata(:all), do: :all\n  defp configure_metadata(metadata), do: Enum.reverse(metadata)\n\n  defp configure_merge(env, options) do\n    Keyword.merge(env, options, fn\n      :colors, v1, v2 -> Keyword.merge(v1, v2)\n      _, _v1, v2 -> v2\n    end)\n  end\n\n  defp configure_colors(config) do\n    colors = Keyword.get(config, :colors, [])\n\n    warning =\n      Keyword.get_lazy(colors, :warning, fn ->\n        if warn = Keyword.get(colors, :warn) do\n          warn\n        else\n          :yellow\n        end\n      end)\n\n    %{\n      emergency: Keyword.get(colors, :error, :red),\n      alert: Keyword.get(colors, :error, :red),\n      critical: Keyword.get(colors, :error, :red),\n      error: Keyword.get(colors, :error, :red),\n      warning: warning,\n      notice: Keyword.get(colors, :info, :normal),\n      info: Keyword.get(colors, :info, :normal),\n      debug: Keyword.get(colors, :debug, :cyan),\n      enabled: Keyword.get(colors, :enabled, IO.ANSI.enabled?())\n    }\n  end\n\n  defp log_event(level, msg, ts, md, %{device: device} = state) do\n    output = format_event(level, msg, ts, md, state)\n    %{state | ref: async_io(device, output), output: output}\n  end\n\n  defp buffer_event(level, msg, ts, md, state) do\n    %{buffer: buffer, buffer_size: buffer_size} = state\n    buffer = [buffer | format_event(level, msg, ts, md, state)]\n    %{state | buffer: buffer, buffer_size: buffer_size + 1}\n  end\n\n  defp async_io(name, output) when is_atom(name) do\n    case Process.whereis(name) do\n      device when is_pid(device) ->\n        async_io(device, output)\n\n      nil ->\n        raise \"no device registered with the name #{inspect(name)}\"\n    end\n  end\n\n  defp async_io(device, output) when is_pid(device) do\n    ref = Process.monitor(device)\n    send(device, {:io_request, self(), ref, {:put_chars, :unicode, output}})\n    ref\n  end\n\n  defp await_io(%{ref: nil} = state), do: state\n\n  defp await_io(%{ref: ref} = state) do\n    receive do\n      {:io_reply, ^ref, :ok} ->\n        handle_io_reply(:ok, state)\n\n      {:io_reply, ^ref, error} ->\n        handle_io_reply(error, state)\n        |> await_io()\n\n      {:DOWN, ^ref, _, pid, reason} ->\n        raise \"device #{inspect(pid)} exited: \" <> Exception.format_exit(reason)\n    end\n  end\n\n  defp format_event(level, msg, ts, md, state) do\n    %{format: format, metadata: keys, colors: colors} = state\n\n    format\n    |> Logger.Formatter.format(level, msg, ts, take_metadata(md, keys))\n    |> color_event(level, colors, md)\n  end\n\n  defp take_metadata(metadata, :all) do\n    metadata\n  end\n\n  defp take_metadata(metadata, keys) do\n    Enum.reduce(keys, [], fn key, acc ->\n      case Keyword.fetch(metadata, key) do\n        {:ok, val} -> [{key, val} | acc]\n        :error -> acc\n      end\n    end)\n  end\n\n  defp color_event(data, _level, %{enabled: false}, _md), do: data\n\n  defp color_event(data, level, %{enabled: true} = colors, md) do\n    color = md[:ansi_color] || Map.fetch!(colors, level)\n    [IO.ANSI.format_fragment(color, true), data | IO.ANSI.reset()]\n  end\n\n  defp log_buffer(%{buffer_size: 0, buffer: []} = state), do: state\n\n  defp log_buffer(state) do\n    %{device: device, buffer: buffer} = state\n    %{state | ref: async_io(device, buffer), buffer: [], buffer_size: 0, output: buffer}\n  end\n\n  defp handle_io_reply(:ok, %{ref: ref} = state) do\n    Process.demonitor(ref, [:flush])\n    log_buffer(%{state | ref: nil, output: nil})\n  end\n\n  defp handle_io_reply({:error, {:put_chars, :unicode, _} = error}, state) do\n    retry_log(error, state)\n  end\n\n  defp handle_io_reply({:error, :put_chars}, %{output: output} = state) do\n    retry_log({:put_chars, :unicode, output}, state)\n  end\n\n  defp handle_io_reply({:error, {:no_translation, _encoding_from, _encoding_to} = error}, state) do\n    retry_log(error, state)\n  end\n\n  defp handle_io_reply({:error, error}, _) do\n    raise \"failure while logging console messages: \" <> inspect(error)\n  end\n\n  defp retry_log(error, %{device: device, ref: ref, output: dirty} = state) do\n    Process.demonitor(ref, [:flush])\n\n    try do\n      :unicode.characters_to_binary(dirty)\n    rescue\n      ArgumentError ->\n        clean = [\"failure while trying to log malformed data: \", inspect(dirty), ?\\n]\n        %{state | ref: async_io(device, clean), output: clean}\n    else\n      {_, good, bad} ->\n        clean = [good | Logger.Formatter.prune(bad)]\n        %{state | ref: async_io(device, clean), output: clean}\n\n      _ ->\n        # A well behaved IO device should not error on good data\n        raise \"failure while logging consoles messages: \" <> inspect(error)\n    end\n  end\n\n  defp flush(%{ref: nil} = state), do: state\n\n  defp flush(state) do\n    state\n    |> await_io()\n    |> flush()\n  end\n\n  defp read_env do\n    Application.get_env(:logger, __MODULE__, Application.get_env(:logger, :console, []))\n  end\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/backends/handler.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Backends.Handler do\n  @moduledoc false\n  @internal_keys [:counter]\n\n  def filesync(id) do\n    :gen_event.sync_notify(id, :flush)\n  end\n\n  ## Config management\n\n  def adding_handler(config) do\n    {:ok, update_in(config.config, &Map.merge(default_config(), &1))}\n  end\n\n  def changing_config(:update, config, %{config: :refresh}) do\n    {:ok, update_in(config.config, &Map.merge(&1, default_config()))}\n  end\n\n  def filter_config(%{config: data} = config) do\n    %{config | config: Map.drop(data, @internal_keys)}\n  end\n\n  defp default_config do\n    sync_threshold = Application.fetch_env!(:logger, :sync_threshold)\n    discard_threshold = Application.fetch_env!(:logger, :discard_threshold)\n\n    %{\n      utc_log: Application.fetch_env!(:logger, :utc_log),\n      truncate: Application.fetch_env!(:logger, :truncate),\n      thresholds: {sync_threshold, discard_threshold}\n    }\n  end\n\n  ## Main logging API\n\n  def log(%{level: erl_level, meta: metadata} = event, %{config: config}) do\n    case threshold(config) do\n      :discard ->\n        :ok\n\n      mode ->\n        %{gl: gl} = metadata\n        %{truncate: truncate, utc_log: utc_log?} = config\n        level = erlang_level_to_elixir_level(erl_level)\n        message = Logger.Formatter.format_event(event, truncate)\n\n        timestamp =\n          case metadata do\n            %{time: time} when is_integer(time) and time >= 0 -> time\n            _ -> :os.system_time(:microsecond)\n          end\n\n        date_time_ms = Logger.Formatter.system_time_to_date_time_ms(timestamp, utc_log?)\n        metadata = [erl_level: erl_level] ++ erlang_metadata_to_elixir_metadata(metadata)\n        event = {level, gl, {Logger, message, date_time_ms, metadata}}\n        notify(mode, event)\n    end\n  rescue\n    ArgumentError -> {:error, :noproc}\n  catch\n    :exit, reason -> {:error, reason}\n  end\n\n  defp notify(:sync, msg) do\n    pid = Process.whereis(Logger)\n\n    # If we are within the logger process itself,\n    #  we cannot use sync notify as that will deadlock.\n    if pid == self(), do: :gen_event.notify(pid, msg), else: :gen_event.sync_notify(pid, msg)\n  end\n\n  defp notify(:async, msg) do\n    :gen_event.notify(Logger, msg)\n  end\n\n  @counter_pos 1\n\n  defp threshold(config) do\n    %{\n      counter: counter,\n      thresholds: {sync, discard}\n    } = config\n\n    :counters.add(counter, @counter_pos, 1)\n    value = :counters.get(counter, @counter_pos)\n\n    cond do\n      value >= discard -> :discard\n      value >= sync -> :sync\n      true -> :async\n    end\n  end\n\n  ## Metadata helpers\n\n  defp erlang_metadata_to_elixir_metadata(metadata) do\n    metadata =\n      case metadata do\n        %{mfa: {mod, fun, arity}} ->\n          Map.merge(%{module: mod, function: form_fa(fun, arity)}, metadata)\n\n        %{} ->\n          metadata\n      end\n\n    metadata =\n      case metadata do\n        %{file: file} -> %{metadata | file: List.to_string(file)}\n        %{} -> metadata\n      end\n\n    Map.to_list(metadata)\n  rescue\n    _ -> Map.to_list(metadata)\n  end\n\n  defp form_fa(fun, arity) do\n    Atom.to_string(fun) <> \"/\" <> Integer.to_string(arity)\n  end\n\n  defp erlang_level_to_elixir_level(:none), do: :error\n  defp erlang_level_to_elixir_level(:emergency), do: :error\n  defp erlang_level_to_elixir_level(:alert), do: :error\n  defp erlang_level_to_elixir_level(:critical), do: :error\n  defp erlang_level_to_elixir_level(:error), do: :error\n  defp erlang_level_to_elixir_level(:warning), do: :warn\n  defp erlang_level_to_elixir_level(:notice), do: :info\n  defp erlang_level_to_elixir_level(:info), do: :info\n  defp erlang_level_to_elixir_level(:debug), do: :debug\n  defp erlang_level_to_elixir_level(:all), do: :debug\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/backends/internal.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Logger.Backends.Internal do\n  @moduledoc false\n\n  use Supervisor\n  @name __MODULE__\n  @type backend :: :gen_event.handler()\n\n  @typedoc \"\"\"\n  Configuration options for Logger backends.\n\n  These are the built-in backend options that can be configured at runtime.\n  \"\"\"\n  @type backend_config_opts :: [\n          sync_threshold: pos_integer(),\n          discard_threshold: pos_integer() | :infinity,\n          truncate: pos_integer() | :infinity,\n          utc_log: boolean()\n        ]\n\n  @typedoc \"\"\"\n  Options for `add/2` and `remove/2` operations.\n  \"\"\"\n  @type add_remove_opts :: [\n          flush: boolean()\n        ]\n\n  @doc \"\"\"\n  Apply runtime configuration to all backends.\n\n  See the module doc for more information.\n  \"\"\"\n  @backend_options [:sync_threshold, :discard_threshold, :truncate, :utc_log]\n  @spec configure(backend_config_opts) :: :ok\n  def configure(options) do\n    ensure_started()\n    Logger.Backends.Config.configure(Keyword.take(options, @backend_options))\n    :ok = :logger.update_handler_config(Logger, :config, :refresh)\n  end\n\n  @doc \"\"\"\n  Configures a given backend.\n  \"\"\"\n  @spec configure(backend, keyword) :: term\n  def configure(backend, options) when is_list(options) do\n    ensure_started()\n    :gen_event.call(Logger, backend, {:configure, options})\n  end\n\n  @doc \"\"\"\n  Adds a new backend.\n\n  Adding a backend calls the `init/1` function in that backend\n  with the name of the backend as its argument. For example,\n  calling\n\n      Logger.Backends.add(MyBackend)\n\n  will call `MyBackend.init(MyBackend)` to initialize the new\n  backend. If the backend's `init/1` callback returns `{:ok, _}`,\n  then this function returns `{:ok, pid}`. If the handler returns\n  `{:error, :ignore}` from `init/1`, this function still returns\n  `{:ok, pid}` but the handler is not started. If the handler\n  returns `{:error, reason}` from `init/1`, this function returns\n  `{:error, {reason, info}}` where `info` is more information on\n  the backend that failed to start.\n\n  Backends added by this function are not persisted. Therefore\n  if the Logger application or supervision tree is restarted,\n  the backend won't be available. If you need this guarantee,\n  then configure the backend via the application environment:\n\n      config :logger, :backends, [MyBackend]\n\n  ## Options\n\n    * `:flush` - when `true`, guarantees all messages currently sent\n      to `Logger` are processed before the backend is added\n\n  ## Examples\n\n      {:ok, _pid} = Logger.add_backend(MyBackend, flush: true)\n\n  \"\"\"\n  @spec add(backend, add_remove_opts) :: Supervisor.on_start_child()\n  def add(backend, opts \\\\ []) do\n    ensure_started()\n    _ = if opts[:flush], do: Logger.flush()\n\n    case Logger.Backends.Supervisor.add(backend) do\n      {:ok, _} = ok ->\n        ok\n\n      {:error, {:already_started, _pid}} ->\n        {:error, :already_present}\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  @doc \"\"\"\n  Removes a backend.\n\n  ## Options\n\n    * `:flush` - when `true`, guarantees all messages currently sent\n      to `Logger` are processed before the backend is removed\n\n  \"\"\"\n  @spec remove(backend, add_remove_opts) :: :ok | {:error, term}\n  def remove(backend, opts \\\\ []) do\n    ensure_started()\n    _ = if opts[:flush], do: Logger.flush()\n    Logger.Backends.Supervisor.remove(backend)\n  end\n\n  ## Supervisor callbacks\n\n  defp ensure_started() do\n    if !Process.whereis(@name) do\n      Supervisor.start_child(Logger.Supervisor, __MODULE__)\n    end\n\n    :ok\n  end\n\n  @doc false\n  def start_link(_opts) do\n    Supervisor.start_link(__MODULE__, :ok, name: @name)\n  end\n\n  @impl true\n  def init(:ok) do\n    backends = Application.get_env(:logger, :backends, []) -- [:console]\n    start_options = Application.fetch_env!(:logger, :start_options)\n    counter = :counters.new(1, [:atomics])\n\n    children = [\n      %{\n        id: :gen_event,\n        start: {:gen_event, :start_link, [{:local, Logger}, start_options]},\n        modules: :dynamic\n      },\n      {Logger.Backends.Watcher, {Logger.Backends.Config, counter}},\n      {Logger.Backends.Supervisor, backends}\n    ]\n\n    :ok =\n      :logger.add_handler(Logger, Logger.Backends.Handler, %{\n        level: :all,\n        config: %{counter: counter},\n        filter_default: :log,\n        filters: []\n      })\n\n    Supervisor.init(children, strategy: :rest_for_one)\n  end\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/backends/supervisor.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Backends.Supervisor do\n  @moduledoc false\n  use Supervisor\n\n  @name __MODULE__\n\n  def add(backend) do\n    spec = %{\n      id: backend,\n      start: {Logger.Backends.Watcher, :start_link, [{backend, backend}]},\n      restart: :transient\n    }\n\n    case Supervisor.start_child(@name, spec) do\n      {:error, :already_present} ->\n        _ = Supervisor.delete_child(@name, backend)\n        add(backend)\n\n      other ->\n        other\n    end\n  end\n\n  def remove(backend) do\n    case Supervisor.terminate_child(@name, backend) do\n      :ok ->\n        _ = Supervisor.delete_child(@name, backend)\n        :ok\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  def start_link(backends) do\n    case Supervisor.start_link(__MODULE__, [], name: @name) do\n      {:ok, _} = ok ->\n        for backend <- backends do\n          case add(backend) do\n            {:ok, _} ->\n              :ok\n\n            {:error, {{:EXIT, exit}, _spec}} ->\n              raise \"EXIT when installing backend #{inspect(backend)}: \" <>\n                      Exception.format_exit(exit)\n\n            {:error, error} ->\n              raise \"ERROR when installing backend #{inspect(backend)}: \" <>\n                      Exception.format_exit(error)\n          end\n        end\n\n        ok\n\n      {:error, _} = error ->\n        error\n    end\n  end\n\n  @impl true\n  def init(children) do\n    Supervisor.init(children, strategy: :one_for_one, max_restarts: 30, max_seconds: 3)\n  end\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/backends/watcher.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Backends.Watcher do\n  @moduledoc false\n  use GenServer\n\n  @doc false\n  def start_link(tuple) do\n    GenServer.start_link(__MODULE__, tuple)\n  end\n\n  @impl true\n  def init({handler, args}) do\n    Process.flag(:trap_exit, true)\n\n    case :gen_event.delete_handler(Logger, handler, :ok) do\n      {:error, :module_not_found} ->\n        case :gen_event.add_sup_handler(Logger, handler, args) do\n          :ok ->\n            {:ok, handler}\n\n          {:error, :ignore} ->\n            # Can't return :ignore as a transient child under a one_for_one.\n            # Instead return ok and then immediately exit normally - using a fake\n            # message.\n            send(self(), {:gen_event_EXIT, handler, :normal})\n            {:ok, handler}\n\n          {:error, reason} ->\n            {:stop, reason}\n\n          {:EXIT, _} = exit ->\n            {:stop, exit}\n        end\n\n      _ ->\n        init({handler, args})\n    end\n  end\n\n  @impl true\n  def handle_info({:gen_event_EXIT, handler, reason}, handler)\n      when reason in [:normal, :shutdown] do\n    {:stop, reason, handler}\n  end\n\n  def handle_info({:gen_event_EXIT, handler, reason}, handler) do\n    message = [\n      \":gen_event handler \",\n      inspect(handler),\n      \" installed in Logger terminating\\n\",\n      \"** (exit) \",\n      format_exit(reason)\n    ]\n\n    cond do\n      logger_has_backends?() -> :ok\n      true -> IO.puts(:stderr, message)\n    end\n\n    {:stop, reason, handler}\n  end\n\n  def handle_info(_msg, state) do\n    {:noreply, state}\n  end\n\n  defp logger_has_backends?() do\n    try do\n      :gen_event.which_handlers(Logger) != [Logger.Backends.Config]\n    catch\n      _, _ -> false\n    end\n  end\n\n  @impl true\n  def terminate(_reason, handler) do\n    # On terminate we remove the handler, this makes the\n    # process sync, allowing existing messages to be flushed\n    :gen_event.delete_handler(Logger, handler, :ok)\n    :ok\n  end\n\n  defp format_exit({:EXIT, reason}), do: Exception.format_exit(reason)\n  defp format_exit(reason), do: Exception.format_exit(reason)\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/formatter.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nimport Kernel, except: [inspect: 2]\n\ndefmodule Logger.Formatter do\n  @moduledoc ~S\"\"\"\n  Conveniences and built-in formatter for logs.\n\n  This module defines a suitable `:logger` formatter which formats\n  messages and reports as Elixir terms and also provides additional\n  functionality, such as timezone conversion, truncation, and coloring.\n  This formatter is used by default by `Logger` and you can configure it\n  using:\n\n      config :logger, :default_formatter,\n        format: \"\\n$time $metadata[$level] $message\\n\",\n        metadata: [:user_id]\n\n  You can also use `Logger.Formatter.new/1` to create your own formatter,\n  which can then be passed as a formatter to any [`:logger_handler`](`:logger_handler`).\n  See `Logger.Formatter.new/1` for all configuration options.\n\n  This module also provides several conveniences for those who wish\n  to [write their custom logger formatters](https://www.erlang.org/doc/apps/kernel/logger_chapter.html#formatters).\n\n  ## Formatting\n\n  The log messages can be controlled by a formatting string. Here is\n  an example:\n\n      config :logger, :default_formatter,\n        format: \"\\n$time $metadata[$level] $message\\n\",\n        metadata: [:user_id]\n\n  The above will print error messages as:\n\n      18:43:12.439 user_id=13 [error] Hello\\n\n\n  The valid parameters you can use are:\n\n    * `$time`     - the time the log message was sent\n    * `$date`     - the date the log message was sent\n    * `$message`  - the log message\n    * `$level`    - the log level\n    * `$node`     - the node that prints the message\n    * `$metadata` - user controlled data presented in `\"key=val key2=val2 \"` format\n\n  ### Formatting function\n\n  You can also customize the format of your log messages with\n  a `{module, function_name}` tuple if you wish to change how messages\n  are formatted but keep all other features provided by `Logger.Formatter`\n  such as truncation and coloring. However, if you want to get full\n  control of formatting, consider writing a custom\n  [`:logger` formatter](https://www.erlang.org/doc/apps/kernel/logger_chapter.html#formatters)\n  instead, which has complete access to all events and metadata.\n\n  When using a `{module, function_name}`, the function will be invoked\n  with the level, the message, the timestamp, and metadata, like this:\n\n      defmodule MyConsoleLogger do\n        @spec format(atom, chardata, Logger.Formatter.date_time_ms(), keyword()) :: IO.chardata()\n        def format(level, message, timestamp, metadata) do\n          # Custom formatting logic that must return chardata.\n          # ...\n        end\n      end\n\n  ### Metadata\n\n  Metadata to be sent to the logger can be read and written with\n  the `Logger.metadata/0` and `Logger.metadata/1` functions. For example,\n  you can set `Logger.metadata([user_id: 13])` to add user_id metadata\n  to the current process. The user can configure the backend to choose\n  which metadata it wants to print and it will replace the `$metadata`\n  value.\n\n  > #### When is user metadata printed? {: .warning}\n  >\n  > The default Logger formatter requires the user's metadata to meet\n  > one of the following conditions to be printed:\n  >\n  >   * Be a string (`is_binary/1`)\n  >   * Be a number (either `is_integer/1` or `is_float/1`)\n  >   * Be a PID\n  >   * Be an atom\n  >   * Be a reference\n  >   * Be a port\n  >   * Implement the `String.Chars` protocol (except for charlists)\n  >\n  > If none of the conditions above are `true`, the given metadata get\n  > discarded.\n  \"\"\"\n\n  @type date :: {1970..10_000, 1..12, 1..31}\n  @type time_ms :: {0..23, 0..59, 0..59, 0..999}\n  @type date_time_ms :: {date, time_ms}\n\n  @type pattern :: :date | :level | :levelpad | :message | :metadata | :node | :time\n\n  @type new_opts :: [\n          colors: [\n            enabled: boolean(),\n            debug: atom(),\n            info: atom(),\n            warning: atom(),\n            error: atom()\n          ],\n          format: String.t() | {module(), atom()},\n          metadata: :all | [atom()],\n          truncate: pos_integer() | :infinity,\n          utc_log: boolean()\n        ]\n  @valid_patterns [:time, :date, :message, :level, :node, :metadata, :levelpad]\n  @default_pattern \"\\n$time $metadata[$level] $message\\n\"\n  @replacement \"�\"\n\n  ## Formatter API\n\n  defstruct [:template, :truncate, :metadata, :colors, :utc_log?]\n\n  @doc ~S\"\"\"\n  Initializes a formatter for `:logger` handlers.\n\n  The supported options are:\n\n    * `:colors` - a keyword list of coloring options.\n\n    * `:format` - the format message used to print logs.\n      Defaults to: `\"\\n$time $metadata[$level] $message\\n\"`.\n      It may also be a `{module, function_name}` tuple that is invoked\n      with the log level, the message, the current timestamp and\n      the metadata and must return `t:IO.chardata/0`.\n      See the module docs for more information on `:format`.\n\n    * `:metadata` - a list of metadata keys to be printed by\n      `$metadata`. Defaults to an empty list (no metadata).\n      Setting `:metadata` to `:all` prints all metadata. See\n      the \"Metadata\" section in the `Logger` documentation for\n      more information.\n\n    * `:truncate` - the maximum message size to be logged (in bytes).\n      Defaults to 8192 bytes. Note this configuration is approximate.\n      Truncated messages will have `\" (truncated)\"` at the end.\n      The atom `:infinity` can be passed to disable this behavior.\n\n    * `:utc_log` - when `true`, uses UTC in logs. By default it uses\n      local time (as it defaults to `false`).\n\n  The supported keys in the `:colors` keyword list are:\n\n    * `:enabled` - boolean value that allows for switching the\n      coloring on and off. Defaults to: `IO.ANSI.enabled?/0`\n\n    * `:debug` - color for debug messages. Defaults to: `:cyan`\n\n    * `:info` - color for info and notice messages. Defaults to: `:normal`\n\n    * `:warning` - color for warning messages. Defaults to: `:yellow`\n\n    * `:error` - color for error and higher messages. Defaults to: `:red`\n\n  See the `IO.ANSI` module for a list of colors and attributes.\n  The color of the message can also be configured per message via\n  the `:ansi_color` metadata.\n  \"\"\"\n  @spec new(new_opts) :: formatter when formatter: term\n  def new(options \\\\ []) do\n    template = compile(options[:format])\n    colors = colors(options[:colors] || [])\n    truncate = options[:truncate] || Application.fetch_env!(:logger, :truncate)\n    metadata = options[:metadata] || []\n    utc_log? = Keyword.get(options, :utc_log, Application.fetch_env!(:logger, :utc_log))\n\n    {__MODULE__,\n     %__MODULE__{\n       template: template,\n       truncate: truncate,\n       metadata: metadata,\n       colors: colors,\n       utc_log?: utc_log?\n     }}\n  end\n\n  defp colors(colors) do\n    %{\n      emergency: Keyword.get(colors, :error, :red),\n      alert: Keyword.get(colors, :error, :red),\n      critical: Keyword.get(colors, :error, :red),\n      error: Keyword.get(colors, :error, :red),\n      warning: Keyword.get(colors, :warning, :yellow),\n      notice: Keyword.get(colors, :info, :normal),\n      info: Keyword.get(colors, :info, :normal),\n      debug: Keyword.get(colors, :debug, :cyan),\n      enabled: Keyword.get(colors, :enabled, &IO.ANSI.enabled?/0)\n    }\n  end\n\n  @doc false\n  def format(%{level: level, meta: meta} = event, %__MODULE__{} = config) do\n    %{\n      utc_log?: utc_log?,\n      metadata: metadata_keys,\n      template: template,\n      colors: colors,\n      truncate: truncate\n    } = config\n\n    system_time =\n      case meta do\n        %{time: time} when is_integer(time) and time >= 0 -> time\n        _ -> :os.system_time(:microsecond)\n      end\n\n    date_time_ms = system_time_to_date_time_ms(system_time, utc_log?)\n\n    meta_list =\n      case metadata_keys do\n        :all -> Map.to_list(meta)\n        keys -> for key <- keys, value = compute_meta(key, meta), do: {key, value}\n      end\n\n    chardata = format_event(event, truncate)\n\n    template\n    |> format(level, chardata, date_time_ms, meta_list)\n    |> colorize(level, colors, meta)\n  end\n\n  def format(_event, _config) do\n    raise \"invalid configuration for Logger.Formatter. \" <>\n            \"Use Logger.Formatter.new/1 to define a formatter\"\n  end\n\n  defp compute_meta(:module, %{mfa: {mod, _, _}}), do: mod\n  defp compute_meta(:function, %{mfa: {_, fun, arity}}), do: format_fa(fun, arity)\n  defp compute_meta(key, meta), do: meta[key]\n\n  defp format_fa(fun, arity), do: [Atom.to_string(fun), \"/\", Integer.to_string(arity)]\n\n  defp colorize(data, level, %{enabled: enabled} = colors, md) do\n    case if(is_function(enabled, 0), do: enabled.(), else: enabled) do\n      true ->\n        color = md[:ansi_color] || Map.fetch!(colors, level)\n        [IO.ANSI.format_fragment(color, true), add_reset(data)]\n\n      false ->\n        data\n    end\n  end\n\n  defp add_reset(binary) when is_binary(binary) do\n    size = byte_size(binary)\n\n    cond do\n      binary == \"\" ->\n        IO.ANSI.reset()\n\n      :binary.at(binary, size - 1) == ?\\n ->\n        if size > 1 and :binary.at(binary, size - 2) == ?\\r do\n          [binary_part(binary, 0, size - 2), IO.ANSI.reset() | \"\\r\\n\"]\n        else\n          [binary_part(binary, 0, size - 1), IO.ANSI.reset(), ?\\n]\n        end\n\n      true ->\n        [binary | IO.ANSI.reset()]\n    end\n  end\n\n  defp add_reset([?\\r, ?\\n]), do: [IO.ANSI.reset(), ?\\r, ?\\n]\n  defp add_reset([?\\n]), do: [IO.ANSI.reset(), ?\\n]\n  defp add_reset([last]), do: add_reset(last)\n  defp add_reset([h | t]), do: [h | add_reset(t)]\n  defp add_reset(rest), do: [rest | IO.ANSI.reset()]\n\n  @doc \"\"\"\n  Formats the message of a log event.\n  \"\"\"\n  @spec format_event(:logger.log_event(), pos_integer | :infinity) :: IO.chardata()\n  def format_event(%{msg: msg, meta: meta} = _log_event, truncate) do\n    format_message(msg, meta, truncate)\n  end\n\n  defp format_message({:string, message}, _metadata, truncate) do\n    wrapped_truncate(message, truncate)\n  end\n\n  defp format_message({:report, data}, %{report_cb: callback} = meta, truncate) do\n    cond do\n      is_function(callback, 1) and callback != (&:logger.format_otp_report/1) ->\n        format_message(callback.(data), meta, truncate)\n\n      is_function(callback, 2) ->\n        callback.(data, %{depth: :unlimited, chars_limit: truncate, single_line: false})\n\n      true ->\n        format_report(data, truncate)\n    end\n  end\n\n  defp format_message({:report, data}, _meta, truncate) do\n    format_report(data, truncate)\n  end\n\n  defp format_message({format, args}, _meta, truncate) do\n    format\n    |> Logger.Utils.scan_inspect(args, truncate)\n    |> :io_lib.build_text()\n    |> wrapped_truncate(truncate)\n  end\n\n  defp format_report(%{} = data, truncate) do\n    wrapped_truncate(Kernel.inspect(Map.to_list(data), translator_inspect_opts()), truncate)\n  end\n\n  defp format_report(data, truncate) do\n    wrapped_truncate(Kernel.inspect(data, translator_inspect_opts()), truncate)\n  end\n\n  defp translator_inspect_opts() do\n    Application.fetch_env!(:logger, :translator_inspect_opts)\n  end\n\n  defp wrapped_truncate(data, n) when is_binary(data), do: truncate(data, n)\n\n  defp wrapped_truncate(data, n) when is_list(data) do\n    truncate(data, n)\n  rescue\n    msg in ArgumentError -> Exception.message(msg)\n  end\n\n  @doc \"\"\"\n  Truncates a `chardata` into `n` bytes.\n\n  There is a chance we truncate in the middle of a grapheme\n  cluster but we never truncate in the middle of a binary\n  code point. For this reason, truncation is not exact.\n  \"\"\"\n  @spec truncate(IO.chardata(), non_neg_integer | :infinity) :: IO.chardata()\n  def truncate(chardata, :infinity) when is_binary(chardata) or is_list(chardata) do\n    chardata\n  end\n\n  def truncate(chardata, n) when n >= 0 do\n    {chardata, n} = Logger.Utils.truncate_n(chardata, n)\n    if n >= 0, do: chardata, else: [chardata, \" (truncated)\"]\n  end\n\n  @doc \"\"\"\n  Prunes invalid Unicode code points from lists and invalid UTF-8 bytes.\n\n  Typically called after formatting when the data cannot be printed.\n  \"\"\"\n  @spec prune(IO.chardata()) :: IO.chardata()\n  def prune(binary) when is_binary(binary), do: prune_binary(binary, \"\")\n  def prune([h | t]) when h in 0..1_114_111, do: [h | prune(t)]\n  def prune([h | t]), do: [prune(h) | prune(t)]\n  def prune([]), do: []\n  def prune(_), do: @replacement\n\n  defp prune_binary(<<h::utf8, t::binary>>, acc), do: prune_binary(t, <<acc::binary, h::utf8>>)\n  defp prune_binary(<<_, t::binary>>, acc), do: prune_binary(t, <<acc::binary, @replacement>>)\n  defp prune_binary(<<>>, acc), do: acc\n\n  @doc \"\"\"\n  Formats time as chardata.\n  \"\"\"\n  @spec format_time(time_ms) :: IO.chardata()\n  def format_time({hh, mi, ss, ms} = _time_ms_tuple) do\n    [pad2(hh), ?:, pad2(mi), ?:, pad2(ss), ?., pad3(ms)]\n  end\n\n  @doc \"\"\"\n  Formats date as chardata.\n  \"\"\"\n  @spec format_date(date) :: IO.chardata()\n  def format_date({yy, mm, dd} = _date_tuple) do\n    [Integer.to_string(yy), ?-, pad2(mm), ?-, pad2(dd)]\n  end\n\n  defp pad3(int) when int < 10, do: [?0, ?0, Integer.to_string(int)]\n  defp pad3(int) when int < 100, do: [?0, Integer.to_string(int)]\n  defp pad3(int), do: Integer.to_string(int)\n\n  defp pad2(int) when int < 10, do: [?0, Integer.to_string(int)]\n  defp pad2(int), do: Integer.to_string(int)\n\n  @doc \"\"\"\n  Converts the system time (in microseconds) from metadata into a `date_time_ms` tuple.\n  \"\"\"\n  @spec system_time_to_date_time_ms(integer(), boolean()) :: date_time_ms()\n  def system_time_to_date_time_ms(system_time, utc_log? \\\\ false) do\n    micro = rem(system_time, 1_000_000)\n\n    {date, {hours, minutes, seconds}} =\n      case utc_log? do\n        true -> :calendar.system_time_to_universal_time(system_time, :microsecond)\n        false -> :calendar.system_time_to_local_time(system_time, :microsecond)\n      end\n\n    {date, {hours, minutes, seconds, div(micro, 1000)}}\n  end\n\n  @doc \"\"\"\n  Compiles a pattern or function into a data structure that `format/5` can handle.\n\n  Check the module doc for documentation on the valid parameters that\n  will be interpolated in the pattern. If you pass `nil` as the pattern,\n  the pattern defaults to:\n\n      #{inspect(@default_pattern)}\n\n  If you want to customize formatting with a custom function, you can\n  pass a `{module, function_name}` tuple.\n\n  This function, alongside `format/5`, is the main building block used\n  by `Logger.Formatter.new/1` for formatting messages. It can also be used\n  by those interested in building custom formatters.\n\n  ## Examples\n\n      iex> Logger.Formatter.compile(\"$time $metadata [$level] $message\\\\n\")\n      [:time, \" \", :metadata, \" [\", :level, \"] \", :message, \"\\\\n\"]\n\n      iex> Logger.Formatter.compile({MyLoggerFormatter, :format})\n      {MyLoggerFormatter, :format}\n\n  \"\"\"\n  @spec compile(binary | nil) :: [pattern | binary]\n  @spec compile(pattern) :: pattern when pattern: {module, function :: atom}\n  def compile(pattern_or_function)\n\n  def compile(nil), do: compile(@default_pattern)\n  def compile({mod, fun}) when is_atom(mod) and is_atom(fun), do: {mod, fun}\n\n  def compile(str) when is_binary(str) do\n    regex = ~r/(?<head>)\\$[a-z]+(?<tail>)/\n\n    for part <- Regex.split(regex, str, on: [:head, :tail], trim: true) do\n      case part do\n        \"$\" <> code -> compile_code(String.to_atom(code))\n        _ -> part\n      end\n    end\n  end\n\n  defp compile_code(:levelpad) do\n    IO.warn(\"$levelpad in Logger message format is deprecated, please remove it\")\n    :levelpad\n  end\n\n  defp compile_code(key) when key in @valid_patterns, do: key\n\n  defp compile_code(key) when is_atom(key) do\n    raise ArgumentError, \"$#{key} is an invalid format pattern\"\n  end\n\n  @doc \"\"\"\n  Formats a `pattern_or_function` returned by `compile/1`.\n\n  It takes a compiled format and injects the level, timestamp, message,\n  and metadata keyword list and returns a properly formatted string.\n\n  If `pattern_or_function` is a `{module, function_name}` tuple,\n  then `module.function_name(level, message, timestamp, metadata)` is\n  invoked to get the message.\n\n  This function, alongside `compile/1`, is the main building block used\n  by `Logger.Formatter.new/1` for formatting messages. It can also be used\n  by those interested in building custom formatters.\n\n  ## Examples\n\n      iex> pattern = Logger.Formatter.compile(\"[$level] $message\")\n      iex> timestamp = {{1977, 01, 28}, {13, 29, 00, 000}}\n      iex> formatted = Logger.Formatter.format(pattern, :info, \"hello\", timestamp, [])\n      iex> IO.chardata_to_string(formatted)\n      \"[info] hello\"\n\n  \"\"\"\n  @spec format(\n          mod_and_fun | [pattern | binary],\n          Logger.level(),\n          Logger.message(),\n          date_time_ms(),\n          keyword\n        ) ::\n          IO.chardata()\n        when mod_and_fun: {atom, atom}\n  def format(pattern_or_function, level, message, timestamp, metadata)\n\n  def format({mod, fun}, level, msg, timestamp, metadata) do\n    apply(mod, fun, [level, msg, timestamp, metadata])\n  end\n\n  def format(config, level, msg, timestamp, metadata) do\n    for config_option <- config do\n      output(config_option, level, msg, timestamp, metadata)\n    end\n  end\n\n  defp output(:message, _, msg, _, _), do: msg\n  defp output(:date, _, _, {date, _time}, _), do: format_date(date)\n  defp output(:time, _, _, {_date, time}, _), do: format_time(time)\n  defp output(:level, level, _, _, _), do: Atom.to_string(level)\n  defp output(:node, _, _, _, _), do: Atom.to_string(node())\n  defp output(:metadata, _, _, _, []), do: \"\"\n  defp output(:metadata, _, _, _, meta), do: metadata(meta)\n  defp output(:levelpad, level, _, _, _), do: levelpad(level)\n  defp output(other, _, _, _, _), do: other\n\n  defp levelpad(:info), do: \" \"\n  defp levelpad(:warn), do: \" \"\n  defp levelpad(_), do: \"\"\n\n  defp metadata([{key, value} | metadata]) do\n    if formatted = metadata(key, value) do\n      [to_string(key), ?=, formatted, ?\\s | metadata(metadata)]\n    else\n      metadata(metadata)\n    end\n  end\n\n  defp metadata([]) do\n    []\n  end\n\n  defp metadata(:time, _), do: nil\n  defp metadata(:gl, _), do: nil\n  defp metadata(:report_cb, _), do: nil\n\n  defp metadata(_, nil), do: nil\n  defp metadata(_, string) when is_binary(string), do: string\n  defp metadata(_, integer) when is_integer(integer), do: Integer.to_string(integer)\n  defp metadata(_, float) when is_float(float), do: Float.to_string(float)\n  defp metadata(_, pid) when is_pid(pid), do: :erlang.pid_to_list(pid)\n\n  defp metadata(_, atom) when is_atom(atom) do\n    case Atom.to_string(atom) do\n      \"Elixir.\" <> rest -> rest\n      binary -> binary\n    end\n  end\n\n  defp metadata(_, ref) when is_reference(ref) do\n    ~c\"#Ref\" ++ rest = :erlang.ref_to_list(ref)\n    rest\n  end\n\n  defp metadata(_, port) when is_port(port) do\n    ~c\"#Port\" ++ rest = :erlang.port_to_list(port)\n    rest\n  end\n\n  defp metadata(:domain, [head | tail]) when is_atom(head) do\n    Enum.map_intersperse([head | tail], ?., &Atom.to_string/1)\n  end\n\n  defp metadata(:mfa, {mod, fun, arity})\n       when is_atom(mod) and is_atom(fun) and is_integer(arity) do\n    Exception.format_mfa(mod, fun, arity)\n  end\n\n  defp metadata(:initial_call, {mod, fun, arity})\n       when is_atom(mod) and is_atom(fun) and is_integer(arity) do\n    Exception.format_mfa(mod, fun, arity)\n  end\n\n  defp metadata(:function, function) when is_list(function), do: function\n  defp metadata(:file, file) when is_list(file), do: file\n  defp metadata(_, list) when is_list(list), do: nil\n\n  defp metadata(_, other) do\n    case String.Chars.impl_for(other) do\n      nil -> nil\n      impl -> impl.to_string(other)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/translator.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Translator do\n  @moduledoc \"\"\"\n  Default translation for Erlang log messages.\n\n  Logger allows developers to rewrite log messages provided by\n  OTP applications into a format more compatible with Elixir\n  log messages by providing a translator.\n\n  A translator is simply a tuple containing a module and a function\n  that can be added and removed via the `Logger.add_translator/1` and\n  `Logger.remove_translator/1` functions and is invoked for every Erlang\n  message above the minimum log level with four arguments:\n\n    * `min_level` - the current Logger level\n    * `level` - the level of the message being translated\n    * `kind` - if the message is a `:report` or `:format`\n    * `message` - the message to format. If it is `:report`, it is a tuple\n      with `{report_type, report_data}`, if it is `:format`, it is a\n      tuple with `{format_message, format_args}`.\n\n  The function must return:\n\n    * `{:ok, chardata, metadata}` - if the message translation with its metadata\n    * `{:ok, chardata}` - the translated message\n    * `:skip` - if the message is not meant to be translated nor logged\n    * `:none` - if there is no translation, which triggers the next translator\n\n  See the function `translate/4` in this module for an example implementation\n  and the default messages translated by Logger.\n  \"\"\"\n\n  @doc \"\"\"\n  Callback for translating a logger message.\n  \"\"\"\n  @callback translate(Logger.level(), Logger.level(), :format | :report, :logger.report()) ::\n              {:ok, iodata, keyword}\n              | {:ok, iodata}\n              | :skip\n              | :none\n\n  @doc \"\"\"\n  Built-in translation function.\n\n  This function is an implementation of the `c:translate/4` callback.\n  For arguments and return value of this function, see that callback.\n  \"\"\"\n  def translate(min_level, level, kind, message)\n\n  def translate(min_level, _level, :report, {:logger, %{label: label} = report}) do\n    case label do\n      {:gen_server, :terminate} ->\n        report_gen_server_terminate(min_level, report)\n\n      {:gen_event, :terminate} ->\n        report_gen_event_terminate(min_level, report)\n\n      {:gen_statem, :terminate} ->\n        report_gen_statem_terminate(min_level, report)\n\n      _ ->\n        :skip\n    end\n  end\n\n  def translate(min_level, _level, :report, {{:proc_lib, :crash}, data}) do\n    report_crash(min_level, data)\n  end\n\n  def translate(min_level, _level, :report, {{:supervisor, :progress}, data}) do\n    report_supervisor_progress(min_level, data)\n  end\n\n  def translate(min_level, _level, :report, {{:supervisor, _}, data}) do\n    report_supervisor(min_level, data)\n  end\n\n  def translate(\n        _min_level,\n        _level,\n        :report,\n        {{:application_controller, :progress}, [application: app, started_at: node]}\n      ) do\n    {:ok, [\"Application \", Atom.to_string(app), \" started at \" | inspect(node)]}\n  end\n\n  def translate(\n        _min_level,\n        _level,\n        :report,\n        {{:application_controller, :exit}, [application: app, exited: reason, type: _type]}\n      ) do\n    {:ok, [\"Application \", Atom.to_string(app), \" exited: \" | Application.format_error(reason)]}\n  end\n\n  def translate(\n        _min_level,\n        :error,\n        :report,\n        {{Task.Supervisor, :terminating},\n         %{\n           name: name,\n           starter: starter,\n           function: function,\n           args: args,\n           reason: reason,\n           process_label: process_label\n         }}\n      ) do\n    opts = Application.get_env(:logger, :translator_inspect_opts)\n\n    {formatted, reason} = format_reason(reason)\n    metadata = [crash_reason: reason] ++ registered_name(name)\n\n    msg =\n      [\"\\nFunction: #{inspect(function, opts)}\"] ++\n        [\"\\n    Args: #{inspect(args, opts)}\"]\n\n    msg =\n      case process_label do\n        :undefined -> msg\n        _ -> [\"\\nProcess Label: #{inspect(process_label, opts)}\"] ++ msg\n      end\n\n    msg = [\"Task #{inspect(name)} started from #{inspect(starter)} terminating\", formatted] ++ msg\n\n    {:ok, msg, metadata}\n  end\n\n  def translate(min_level, :error, :format, message) do\n    case message do\n      # This is no longer emitted by Erlang/OTP but it may be\n      # manually emitted by libraries like connection.\n      {~c\"** Generic server \" ++ _, [name, last, state, reason | client]} ->\n        opts = Application.fetch_env!(:logger, :translator_inspect_opts)\n        {formatted, reason} = format_reason(reason)\n        metadata = [crash_reason: reason] ++ registered_name(name)\n\n        msg =\n          [\"GenServer #{inspect(name)} terminating\", formatted] ++\n            [\"\\nLast message#{format_from(client)}: #{inspect(last, opts)}\"]\n\n        if min_level == :debug do\n          msg = [msg, \"\\nState: #{inspect(state, opts)}\" | format_client(client)]\n          {:ok, msg, metadata}\n        else\n          {:ok, msg, metadata}\n        end\n\n      {~c\"Error in process \" ++ _, [pid, node, {reason, stack}]} ->\n        reason = Exception.normalize(:error, reason, stack)\n\n        msg = [\n          \"Process \",\n          inspect(pid),\n          \" on node \",\n          inspect(node),\n          \" raised an exception\" | format(:error, reason, stack)\n        ]\n\n        {:ok, msg, [crash_reason: exit_reason(:error, reason, stack)]}\n\n      {~c\"Error in process \" ++ _, [pid, {reason, stack}]} ->\n        reason = Exception.normalize(:error, reason, stack)\n        msg = [\"Process \", inspect(pid), \" raised an exception\" | format(:error, reason, stack)]\n        {:ok, msg, [crash_reason: exit_reason(:error, reason, stack)]}\n\n      _ ->\n        :none\n    end\n  end\n\n  def translate(_min_level, :info, :report, {\n        :std_info,\n        [application: app, exited: reason, type: _type]\n      }) do\n    {:ok, [\"Application \", Atom.to_string(app), \" exited: \" | Application.format_error(reason)]}\n  end\n\n  def translate(min_level, :error, :report, {{:error_logger, :error_report}, data}) do\n    report_supervisor(min_level, data)\n  end\n\n  def translate(min_level, :error, :report, {:supervisor_report, data}) do\n    report_supervisor(min_level, data)\n  end\n\n  def translate(min_level, :error, :report, {:crash_report, data}) do\n    report_crash(min_level, data)\n  end\n\n  def translate(min_level, :info, :report, {:progress, [{:supervisor, _} | _] = data}) do\n    report_supervisor_progress(min_level, data)\n  end\n\n  def translate(_min_level, :info, :report, {:progress, [application: app, started_at: node]}) do\n    {:ok, [\"Application \", Atom.to_string(app), \" started at \" | inspect(node)]}\n  end\n\n  def translate(_min_level, :debug, :report, {:logger, [formatter_error: formatter] ++ data}) do\n    case data[:caught] do\n      {:throw, {:error, good, bad}, stacktrace} ->\n        message =\n          \"bad return value from Logger formatter #{inspect(formatter)}, \" <>\n            \"got #{inspect(bad)} after #{inspect(good)}\"\n\n        {:ok, Exception.format(:error, RuntimeError.exception(message), stacktrace)}\n\n      _ ->\n        :none\n    end\n  end\n\n  ## Helpers\n\n  def translate(_min_level, _level, _kind, _message) do\n    :none\n  end\n\n  defp report_gen_server_terminate(min_level, report) do\n    inspect_opts = Application.fetch_env!(:logger, :translator_inspect_opts)\n\n    %{\n      client_info: client,\n      last_message: last,\n      name: name,\n      reason: reason,\n      state: state\n    } = report\n\n    {formatted, reason} = format_reason(reason)\n    metadata = [crash_reason: reason] ++ registered_name(name)\n\n    label_msg =\n      case report do\n        %{process_label: process_label} when process_label != :undefined ->\n          [\"\\nProcess Label: \", inspect(process_label, inspect_opts)]\n\n        _ ->\n          []\n      end\n\n    msg =\n      [\"GenServer \", inspect(name), \" terminating\", formatted, label_msg] ++\n        [\"\\nLast message\", format_last_message_from(client), \": \", inspect(last, inspect_opts)]\n\n    if min_level == :debug do\n      msg = [msg, \"\\nState: \", inspect(state, inspect_opts) | format_client_info(client)]\n      {:ok, msg, metadata}\n    else\n      {:ok, msg, metadata}\n    end\n  end\n\n  defp report_gen_event_terminate(min_level, report) do\n    inspect_opts = Application.fetch_env!(:logger, :translator_inspect_opts)\n\n    %{\n      handler: handler,\n      last_message: last,\n      name: name,\n      reason: reason,\n      state: state\n    } = report\n\n    reason =\n      case reason do\n        {:EXIT, why} -> why\n        _ -> reason\n      end\n\n    {formatted, reason} = format_reason(reason)\n    metadata = [crash_reason: reason] ++ registered_name(name)\n\n    label_msg =\n      case report do\n        %{process_label: process_label} when process_label != :undefined ->\n          [\"\\nProcess Label: \", inspect(process_label, inspect_opts)]\n\n        _ ->\n          []\n      end\n\n    msg =\n      [\":gen_event handler \", inspect(handler), \" installed in \", inspect(name), \" terminating\"] ++\n        [formatted, label_msg, \"\\nLast message: \", inspect(last, inspect_opts)]\n\n    if min_level == :debug do\n      {:ok, [msg, \"\\nState: \", inspect(state, inspect_opts)], metadata}\n    else\n      {:ok, msg, metadata}\n    end\n  end\n\n  defp report_gen_statem_terminate(min_level, report) do\n    inspect_opts = Application.get_env(:logger, :translator_inspect_opts)\n\n    %{\n      client_info: client,\n      name: name,\n      reason: {kind, reason, stack},\n      state: state,\n      queue: queue,\n      postponed: postponed,\n      callback_mode: callback_mode,\n      state_enter: state_enter?\n    } = report\n\n    {reason, stack} = exit_reason(kind, reason, stack)\n    {formatted, reason} = format_reason({reason, stack})\n    metadata = [crash_reason: reason] ++ registered_name(name)\n\n    label_msg =\n      case report do\n        %{process_label: process_label} when process_label != :undefined ->\n          [\"\\nProcess Label: \", inspect(process_label, inspect_opts)]\n\n        _ ->\n          []\n      end\n\n    msg =\n      [\":gen_statem \", inspect(name), \" terminating\", formatted, label_msg] ++\n        [\"\\nQueue: #{inspect(queue, inspect_opts)}\"] ++\n        [\"\\nPostponed: #{inspect(postponed, inspect_opts)}\"]\n\n    if min_level == :debug do\n      msg = [\n        msg,\n        \"\\nState: \",\n        inspect(state, inspect_opts),\n        \"\\nCallback mode: \",\n        \"#{inspect(callback_mode, inspect_opts)}, state_enter: #{state_enter?}\"\n        | format_client_info(client)\n      ]\n\n      {:ok, msg, metadata}\n    else\n      {:ok, msg, metadata}\n    end\n  end\n\n  defp report_supervisor_progress(\n         min_level,\n         supervisor: sup,\n         started: [{:pid, pid}, {:id, id} | started]\n       ) do\n    msg =\n      [\"Child \", inspect(id), \" of Supervisor \", sup_name(sup), \" started\"] ++\n        [\"\\nPid: \", inspect(pid)] ++ child_info(min_level, started)\n\n    {:ok, msg}\n  end\n\n  defp report_supervisor_progress(\n         min_level,\n         supervisor: sup,\n         started: [{:pid, pid} | started]\n       ) do\n    msg =\n      [\"Child of Supervisor \", sup_name(sup), \" started\", \"\\nPid: \", inspect(pid)] ++\n        child_info(min_level, started)\n\n    {:ok, msg}\n  end\n\n  defp report_supervisor_progress(_min_level, _other), do: :none\n\n  defp report_supervisor(\n         min_level,\n         supervisor: sup,\n         errorContext: context,\n         reason: reason,\n         offender: [{:pid, pid}, {:id, id} | offender]\n       ) do\n    pid_info =\n      if is_pid(pid) and context != :shutdown do\n        [\"\\nPid: \", inspect(pid)]\n      else\n        []\n      end\n\n    msg =\n      [\"Child \", inspect(id), \" of Supervisor \", sup_name(sup)] ++\n        [?\\s, sup_context(context), \"\\n** (exit) \", offender_reason(reason, context)] ++\n        pid_info ++ child_info(min_level, offender)\n\n    {:ok, msg}\n  end\n\n  defp report_supervisor(\n         min_level,\n         supervisor: sup,\n         errorContext: context,\n         reason: reason,\n         offender: [{:nb_children, n}, {:id, id} | offender]\n       ) do\n    msg =\n      [\"Children \", inspect(id), \" of Supervisor \", sup_name(sup), ?\\s, sup_context(context)] ++\n        [\"\\n** (exit) \", offender_reason(reason, context), \"\\nNumber: \", Integer.to_string(n)] ++\n        child_info(min_level, offender)\n\n    {:ok, msg}\n  end\n\n  defp report_supervisor(\n         min_level,\n         supervisor: sup,\n         errorContext: context,\n         reason: reason,\n         offender: [{:pid, pid} | offender]\n       ) do\n    msg =\n      [\"Child of Supervisor \", sup_name(sup), ?\\s, sup_context(context)] ++\n        [\"\\n** (exit) \", offender_reason(reason, context), \"\\nPid: \", inspect(pid)] ++\n        child_info(min_level, offender)\n\n    {:ok, msg}\n  end\n\n  defp report_supervisor(_min_level, _other), do: :none\n\n  # If start call raises reason will be of form {:EXIT, reason}\n  defp offender_reason({:EXIT, reason}, :start_error) do\n    Exception.format_exit(reason)\n  end\n\n  defp offender_reason(reason, _context) do\n    Exception.format_exit(reason)\n  end\n\n  defp sup_name({:local, name}), do: inspect(name)\n  defp sup_name({:global, name}), do: inspect(name)\n  defp sup_name({:via, _mod, name}), do: inspect(name)\n  defp sup_name({pid, mod}), do: [inspect(pid), \" (\", inspect(mod), ?)]\n  defp sup_name(unknown_name), do: inspect(unknown_name)\n\n  defp sup_context(:start_error), do: \"failed to start\"\n  defp sup_context(:child_terminated), do: \"terminated\"\n  defp sup_context(:shutdown), do: \"caused shutdown\"\n  defp sup_context(:shutdown_error), do: \"shut down abnormally\"\n\n  defp child_info(min_level, [{:mfargs, {mod, fun, args}} | debug]) do\n    [\"\\nStart Call: \", format_mfa(mod, fun, args) | child_debug(min_level, debug)]\n  end\n\n  # Comes from bridge with MFA\n  defp child_info(min_level, [{:mfa, {mod, fun, args}} | debug]) do\n    [\"\\nStart Call: \", format_mfa(mod, fun, args) | child_debug(min_level, debug)]\n  end\n\n  # Comes from bridge with Mod\n  defp child_info(min_level, [{:mod, mod} | debug]) do\n    [\"\\nStart Module: \", inspect(mod) | child_debug(min_level, debug)]\n  end\n\n  defp child_info(_min_level, _child) do\n    []\n  end\n\n  defp child_debug(:debug, opts) do\n    for {key, value} <- opts do\n      child_debug_key(key, value)\n    end\n  end\n\n  defp child_debug(_min_level, _child) do\n    []\n  end\n\n  defp child_debug_key(:restart_type, value), do: [\"\\nRestart: \" | inspect(value)]\n  defp child_debug_key(:shutdown, value), do: [\"\\nShutdown: \" | inspect(value)]\n  defp child_debug_key(:child_type, value), do: [\"\\nType: \" | inspect(value)]\n  defp child_debug_key(:significant, value), do: if(value, do: \"\\nSignificant: true\", else: [])\n  defp child_debug_key(_, _), do: []\n\n  defp report_crash(min_level, [[{:initial_call, initial_call} | crashed], linked]) do\n    mfa = initial_call_to_mfa(initial_call)\n    report_crash(min_level, crashed, [{:initial_call, mfa}], linked)\n  end\n\n  defp report_crash(min_level, [crashed, linked]) do\n    report_crash(min_level, crashed, [], linked)\n  end\n\n  defp report_crash(min_level, crashed, extra, linked) do\n    {pid, crashed} = Keyword.pop_first(crashed, :pid)\n    {name, crashed} = Keyword.pop_first(crashed, :registered_name)\n    {{kind, reason, stack}, crashed} = Keyword.pop_first(crashed, :error_info)\n\n    dictionary = crashed[:dictionary]\n    reason = Exception.normalize(kind, reason, stack)\n\n    case Keyword.get(dictionary, :logger_enabled, true) do\n      false ->\n        :skip\n\n      true ->\n        user_metadata = Keyword.get(dictionary, :\"$logger_metadata$\", %{}) |> Map.to_list()\n\n        msg =\n          [\"Process \", crash_name(pid, name), \" terminating\", format(kind, reason, stack)] ++\n            [crash_info(min_level, extra ++ crashed, [?\\n]), crash_linked(min_level, linked)]\n\n        extra =\n          if ancestors = crashed[:ancestors], do: [{:ancestors, ancestors} | extra], else: extra\n\n        extra =\n          if callers = dictionary[:\"$callers\"], do: [{:callers, callers} | extra], else: extra\n\n        extra = [{:crash_reason, exit_reason(kind, reason, stack)} | extra]\n        {:ok, msg, registered_name(name) ++ extra ++ user_metadata}\n    end\n  end\n\n  defp initial_call_to_mfa({:supervisor, module, _}), do: {module, :init, 1}\n  defp initial_call_to_mfa({:supervisor_bridge, module, _}), do: {module, :init, 1}\n  defp initial_call_to_mfa({mod, fun, args}) when is_list(args), do: {mod, fun, length(args)}\n  defp initial_call_to_mfa(mfa), do: mfa\n\n  defp crash_name(pid, []), do: inspect(pid)\n  defp crash_name(pid, name), do: [inspect(name), \" (\", inspect(pid), ?)]\n\n  defp crash_info(min_level, [{:initial_call, {mod, fun, args}} | info], prefix) do\n    [prefix, \"Initial Call: \", crash_call(mod, fun, args) | crash_info(min_level, info, prefix)]\n  end\n\n  defp crash_info(min_level, [{:current_function, {mod, fun, args}} | info], prefix) do\n    [prefix, \"Current Call: \", crash_call(mod, fun, args) | crash_info(min_level, info, prefix)]\n  end\n\n  defp crash_info(min_level, [{:current_function, []} | info], prefix) do\n    crash_info(min_level, info, prefix)\n  end\n\n  defp crash_info(min_level, [{:ancestors, ancestors} | debug], prefix) do\n    [prefix, \"Ancestors: \", inspect(ancestors) | crash_info(min_level, debug, prefix)]\n  end\n\n  defp crash_info(min_level, [{:process_label, :undefined} | info], prefix) do\n    crash_info(min_level, info, prefix)\n  end\n\n  defp crash_info(min_level, [{:process_label, label} | debug], prefix) do\n    [prefix, \"Process Label: \", inspect(label) | crash_info(min_level, debug, prefix)]\n  end\n\n  defp crash_info(:debug, debug, prefix) do\n    for {key, value} <- debug do\n      crash_debug(key, value, prefix)\n    end\n  end\n\n  defp crash_info(_, _, _) do\n    []\n  end\n\n  defp crash_call(mod, fun, arity) when is_integer(arity) do\n    format_mfa(mod, fun, arity)\n  end\n\n  defp crash_call(mod, fun, args) do\n    format_mfa(mod, fun, length(args))\n  end\n\n  defp crash_debug(:current_stacktrace, stack, prefix) do\n    stack_prefix = [prefix | \"    \"]\n    stacktrace = Enum.map(stack, &[stack_prefix | Exception.format_stacktrace_entry(&1)])\n    [prefix, \"Current Stacktrace:\" | stacktrace]\n  end\n\n  defp crash_debug(key, value, prefix) do\n    [prefix, crash_debug_key(key), ?:, ?\\s, inspect(value)]\n  end\n\n  defp crash_debug_key(key) do\n    case key do\n      :message_queue_len -> \"Message Queue Length\"\n      :messages -> \"Messages\"\n      :links -> \"Links\"\n      :dictionary -> \"Dictionary\"\n      :trap_exit -> \"Trapping Exits\"\n      :status -> \"Status\"\n      :heap_size -> \"Heap Size\"\n      :stack_size -> \"Stack Size\"\n      :reductions -> \"Reductions\"\n    end\n  end\n\n  defp crash_linked(_min_level, []), do: []\n\n  defp crash_linked(min_level, neighbours) do\n    Enum.reduce(neighbours, \"\\nNeighbours:\", fn {:neighbour, info}, acc ->\n      [acc | crash_neighbour(min_level, info)]\n    end)\n  end\n\n  @indent \"    \"\n\n  defp crash_neighbour(min_level, [{:pid, pid}, {:registered_name, []} | info]) do\n    [?\\n, @indent, inspect(pid) | crash_info(min_level, info, [?\\n, @indent | @indent])]\n  end\n\n  defp crash_neighbour(min_level, [{:pid, pid}, {:registered_name, name} | info]) do\n    [?\\n, @indent, inspect(name), \" (\", inspect(pid), \")\"] ++\n      crash_info(min_level, info, [?\\n, @indent | @indent])\n  end\n\n  defp format_last_message_from({_, {name, _}}), do: [\" (from \", inspect(name), \")\"]\n  defp format_last_message_from({from, _}), do: [\" (from \", inspect(from), \")\"]\n  defp format_last_message_from(_), do: []\n\n  defp format_client_info({from, :dead}),\n    do: [\"\\nClient \", inspect(from), \" is dead\"]\n\n  defp format_client_info({from, :remote}),\n    do: [\"\\nClient \", inspect(from), \" is remote on node \", inspect(node(from))]\n\n  defp format_client_info({_, {name, stacktrace}}),\n    do: [\"\\nClient \", inspect(name), \" is alive\\n\" | format_stacktrace(stacktrace)]\n\n  defp format_client_info(_),\n    do: []\n\n  defp format_reason({maybe_exception, [_ | _] = maybe_stacktrace} = reason) do\n    try do\n      format_stacktrace(maybe_stacktrace)\n    catch\n      :error, _ ->\n        {format_stop(reason), {reason, []}}\n    else\n      formatted_stacktrace ->\n        {formatted, reason} = maybe_normalize(maybe_exception, maybe_stacktrace)\n        {[formatted | formatted_stacktrace], {reason, maybe_stacktrace}}\n    end\n  end\n\n  defp format_reason(reason) do\n    {format_stop(reason), {reason, []}}\n  end\n\n  defp format_stop(reason) do\n    [\"\\n** (stop) \" | Exception.format_exit(reason)]\n  end\n\n  # Erlang processes rewrite the :undef error to these reasons when logging\n  @gen_undef [:\"module could not be loaded\", :\"function not exported\"]\n\n  defp maybe_normalize(undef, [{mod, fun, args, _info} | _] = stacktrace)\n       when undef in @gen_undef and is_atom(mod) and is_atom(fun) do\n    cond do\n      is_list(args) ->\n        format_undef(mod, fun, length(args), undef, stacktrace)\n\n      is_integer(args) ->\n        format_undef(mod, fun, args, undef, stacktrace)\n\n      true ->\n        {format_stop(undef), undef}\n    end\n  end\n\n  defp maybe_normalize(reason, stacktrace) do\n    # If this is already an exception (even an ErlangError), we format it as an\n    # exception. Otherwise, we try to normalize it, and if it's normalized as an\n    # ErlangError we instead format it as an exit.\n    if is_exception(reason) do\n      {[?\\n | Exception.format_banner(:error, reason, stacktrace)], reason}\n    else\n      case Exception.normalize(:error, reason, stacktrace) do\n        %ErlangError{} ->\n          {format_stop(reason), reason}\n\n        exception ->\n          {[?\\n | Exception.format_banner(:error, exception, stacktrace)], exception}\n      end\n    end\n  end\n\n  defp format(kind, payload, stacktrace) do\n    [?\\n, Exception.format_banner(kind, payload, stacktrace) | format_stacktrace(stacktrace)]\n  end\n\n  defp format_stacktrace(stacktrace) do\n    for entry <- stacktrace do\n      [\"\\n    \" | Exception.format_stacktrace_entry(entry)]\n    end\n  end\n\n  defp registered_name(name) when is_atom(name), do: [registered_name: name]\n  defp registered_name(_name), do: []\n\n  defp format_mfa(mod, fun, :undefined),\n    do: [inspect(mod), ?., Macro.inspect_atom(:remote_call, fun) | \"/?\"]\n\n  defp format_mfa(mod, fun, args),\n    do: Exception.format_mfa(mod, fun, args)\n\n  defp exit_reason(:exit, reason, stack), do: {reason, stack}\n  defp exit_reason(:error, reason, stack), do: {reason, stack}\n  defp exit_reason(:throw, value, stack), do: {{:nocatch, value}, stack}\n\n  ## Deprecated helpers\n\n  defp format_from([]), do: \"\"\n  defp format_from([from]), do: \" (from #{inspect(from)})\"\n  defp format_from([from, stacktrace]) when is_list(stacktrace), do: \" (from #{inspect(from)})\"\n\n  defp format_from([from, node_name]) when is_atom(node_name),\n    do: \" (from #{inspect(from)} on #{inspect(node_name)})\"\n\n  defp format_client([from]) do\n    \"\\nClient #{inspect(from)} is dead\"\n  end\n\n  defp format_client([from, stacktrace]) when is_list(stacktrace) do\n    [\"\\nClient #{inspect(from)} is alive\\n\" | format_stacktrace(stacktrace)]\n  end\n\n  defp format_client(_) do\n    []\n  end\n\n  defp format_undef(mod, fun, arity, undef, stacktrace) do\n    opts = [module: mod, function: fun, arity: arity, reason: undef]\n    exception = UndefinedFunctionError.exception(opts)\n    {[?\\n | Exception.format_banner(:error, exception, stacktrace)], exception}\n  end\nend\n"
  },
  {
    "path": "lib/logger/lib/logger/utils.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Utils do\n  @moduledoc false\n\n  @doc \"\"\"\n  A filter for default translation and handling of reports.\n  \"\"\"\n  def translator(%{meta: %{domain: [:otp | _]}}, %{otp: false}), do: :stop\n  def translator(%{meta: %{domain: [:otp, :sasl | _]}}, %{sasl: false}), do: :stop\n  def translator(%{meta: %{domain: [:supervisor_report | _]}}, %{sasl: false}), do: :stop\n  def translator(%{msg: {:string, _}}, _config), do: :ignore\n\n  def translator(%{msg: msg, level: level, meta: meta} = event, %{translators: translators}) do\n    %{level: min_level} = :logger.get_primary_config()\n\n    try do\n      case msg do\n        {:report, %{label: label, report: report} = complete}\n        when map_size(complete) == 2 ->\n          translate(translators, min_level, level, :report, {label, report})\n\n        {:report, %{label: {:error_logger, _}, format: format, args: args}} ->\n          translate(translators, min_level, level, :format, {format, args})\n\n        {:report, report} ->\n          translate(translators, min_level, level, :report, {:logger, report})\n\n        {format, args} ->\n          translate(translators, min_level, level, :format, {format, args})\n      end\n    rescue\n      e ->\n        chardata = [\n          \"Failure while translating Erlang's logger event\\n\",\n          Exception.format(:error, e, __STACKTRACE__)\n        ]\n\n        %{event | msg: {:string, chardata}}\n    else\n      :none ->\n        :ignore\n\n      :skip ->\n        :stop\n\n      {:ok, chardata} ->\n        return_translated_event(event, chardata, meta)\n\n      {:ok, chardata, translation_meta} ->\n        return_translated_event(event, chardata, Enum.into(translation_meta, meta))\n    end\n  end\n\n  def translated_cb(report) do\n    {~c\"~ts\", [report[:elixir_translation]]}\n  end\n\n  defp return_translated_event(%{msg: {:report, report}} = event, translation, meta) do\n    report =\n      if is_list(report),\n        do: [elixir_translation: translation] ++ report,\n        else: Map.put(report, :elixir_translation, translation)\n\n    %{\n      event\n      | msg: {:report, report},\n        meta: Map.put(meta, :report_cb, &__MODULE__.translated_cb/1)\n    }\n  end\n\n  defp return_translated_event(event, translation, meta) do\n    %{event | msg: {:string, translation}, meta: meta}\n  end\n\n  defp translate([{mod, fun} | t], min_level, level, kind, data) do\n    with :none <- apply(mod, fun, [min_level, level, kind, data]) do\n      translate(t, min_level, level, kind, data)\n    end\n  end\n\n  defp translate([], _min_level, _level, _kind, _data) do\n    :none\n  end\n\n  @doc \"\"\"\n  A filter for removing logs if current process opted out of certain levels.\n  \"\"\"\n  def process_level(%{level: level}, _extra) do\n    process_level = Logger.get_process_level(self())\n\n    if process_level != nil and :logger.compare_levels(level, process_level) == :lt do\n      :stop\n    else\n      :ignore\n    end\n  end\n\n  @doc \"\"\"\n  A filter for logger exits which then removes itself.\n  \"\"\"\n  def silence_logger_exit(\n        %{\n          msg:\n            {:report,\n             %{\n               label: {:application_controller, :exit},\n               report: [application: :logger, exited: :stopped] ++ _\n             }}\n        },\n        _extra\n      ) do\n    :logger.remove_primary_filter(:silence_logger_exit)\n    :stop\n  end\n\n  def silence_logger_exit(_message, _extra) do\n    :ignore\n  end\n\n  @doc \"\"\"\n  Receives a format string and arguments, scans them, and then replace `~p`,\n  `~P`, `~w` and `~W` by its inspected variants.\n\n  For information about format scanning and how to consume them,\n  check `:io_lib.scan_format/2`.\n  \"\"\"\n  @spec scan_inspect(\n          atom() | binary() | charlist(),\n          list(),\n          non_neg_integer() | :infinity,\n          Inspect.Opts.t()\n        ) :: [:io_lib.format_spec()]\n  def scan_inspect(format, args, truncate, opts \\\\ %Inspect.Opts{})\n\n  def scan_inspect(format, args, truncate, opts) when is_atom(format) do\n    scan_inspect(Atom.to_charlist(format), args, truncate, opts)\n  end\n\n  def scan_inspect(format, args, truncate, opts) when is_binary(format) do\n    scan_inspect(:binary.bin_to_list(format), args, truncate, opts)\n  end\n\n  def scan_inspect(format, [], _truncate, _opts) when is_list(format) do\n    :io_lib.scan_format(format, [])\n  end\n\n  def scan_inspect(format, args, truncate, opts) when is_list(format) do\n    # A pre-pass that removes binaries from\n    # arguments according to the truncate limit.\n    {args, _} =\n      Enum.map_reduce(args, truncate, fn arg, acc ->\n        if is_binary(arg) and acc != :infinity do\n          truncate_n(arg, acc)\n        else\n          {arg, acc}\n        end\n      end)\n\n    format\n    |> :io_lib.scan_format(args)\n    |> Enum.map(&handle_format_spec(&1, opts))\n  end\n\n  @inspected_format_spec %{\n    adjust: :right,\n    args: [],\n    control_char: ?s,\n    encoding: :unicode,\n    pad_char: ?\\s,\n    precision: :none,\n    strings: true,\n    width: :none,\n    maps_order: :undefined\n  }\n\n  defp handle_format_spec(%{control_char: char} = spec, opts) when char in ~c\"wWpP\" do\n    %{args: args, width: width, strings: strings?} = spec\n\n    opts = %{\n      opts\n      | charlists: inspect_charlists(strings?, opts),\n        limit: inspect_limit(char, args, opts),\n        width: inspect_width(char, width)\n    }\n\n    %{@inspected_format_spec | args: [inspect_data(args, opts)]}\n  end\n\n  defp handle_format_spec(spec, _opts), do: spec\n\n  defp inspect_charlists(false, _), do: :as_lists\n  defp inspect_charlists(_, opts), do: opts.charlists\n\n  defp inspect_limit(char, [_, limit], _) when char in ~c\"WP\", do: limit\n  defp inspect_limit(_, _, opts), do: opts.limit\n\n  defp inspect_width(char, _) when char in ~c\"wW\", do: :infinity\n  defp inspect_width(_, width), do: width\n\n  defp inspect_data([data | _], opts) do\n    width = if opts.width == :none, do: 80, else: opts.width\n\n    data\n    |> Inspect.Algebra.to_doc(opts)\n    |> Inspect.Algebra.format(width)\n  end\n\n  @doc \"\"\"\n  Truncates `n` elements from chartdata.\n  \"\"\"\n  def truncate_n(_, n) when n < 0 do\n    {\"\", n}\n  end\n\n  def truncate_n(binary, n) when is_binary(binary) do\n    remaining = n - byte_size(binary)\n\n    if remaining < 0 do\n      # There is a chance we are cutting at the wrong\n      # place so we need to fix the binary.\n      {fix_binary(binary_part(binary, 0, n)), remaining}\n    else\n      {binary, remaining}\n    end\n  end\n\n  def truncate_n(int, n) when int in 0..127, do: {int, n - 1}\n  def truncate_n(int, n) when int in 127..0x07FF, do: {int, n - 2}\n  def truncate_n(int, n) when int in 0x800..0xFFFF, do: {int, n - 3}\n  def truncate_n(int, n) when int >= 0x10000 and is_integer(int), do: {int, n - 4}\n\n  def truncate_n(list, n) when is_list(list) do\n    truncate_n_list(list, n, [])\n  end\n\n  def truncate_n(other, _n) do\n    raise ArgumentError,\n          \"cannot truncate chardata because it contains something that is not \" <>\n            \"valid chardata: #{inspect(other)}\"\n  end\n\n  defp truncate_n_list(_, n, acc) when n < 0 do\n    {:lists.reverse(acc), n}\n  end\n\n  defp truncate_n_list([h | t], n, acc) do\n    {h, n} = truncate_n(h, n)\n    truncate_n_list(t, n, [h | acc])\n  end\n\n  defp truncate_n_list([], n, acc) do\n    {:lists.reverse(acc), n}\n  end\n\n  defp truncate_n_list(t, n, acc) do\n    {t, n} = truncate_n(t, n)\n    {:lists.reverse(acc, t), n}\n  end\n\n  defp fix_binary(binary) do\n    # Use a thirteen-bytes offset to look back in the binary.\n    # This should allow at least two code points of 6 bytes.\n    suffix_size = min(byte_size(binary), 13)\n    prefix_size = byte_size(binary) - suffix_size\n    <<prefix::binary-size(^prefix_size), suffix::binary-size(^suffix_size)>> = binary\n    prefix <> fix_binary(suffix, \"\")\n  end\n\n  defp fix_binary(<<h::utf8, t::binary>>, acc) do\n    acc <> <<h::utf8>> <> fix_binary(t, \"\")\n  end\n\n  defp fix_binary(<<h, t::binary>>, acc) do\n    fix_binary(t, <<acc::binary, h>>)\n  end\n\n  defp fix_binary(<<>>, _acc) do\n    <<>>\n  end\nend\n"
  },
  {
    "path": "lib/logger/lib/logger.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger do\n  @moduledoc ~S\"\"\"\n  A logger for Elixir applications.\n\n  This application is mostly a wrapper around Erlang's\n  [`:logger`](`:logger`) functionality, to provide message\n  translation and formatting to Elixir terms.\n\n  Overall, you will find that `Logger`:\n\n    * Provides all 8 syslog levels\n      (although debug, info, warning, and error are the most commonly used).\n\n    * Supports both message-based and structural logging.\n\n    * Integrate with Erlang's [`:logger`](`:logger`) and\n      support custom filters and handlers.\n\n    * Formats and truncates messages on the client\n      to avoid clogging `Logger` handlers.\n\n    * Provides multiple forms of [overload protection](https://www.erlang.org/doc/apps/kernel/logger_chapter.html#protecting-the-handler-from-overload):\n      * keeps track of its message queue and switches to sync mode to apply\n        back pressure or even drop messages\n      * limits the number of logs emitted defaulting to 500 per second\n      * optionally allows to terminate and restart it if the message queue length\n        or memory thresholds are exceeded\n\n    * Allows overriding the logging level for a specific module,\n      application or process.\n\n  Logging is useful for tracking when an event of interest happens in your\n  system. For example, it may be helpful to log whenever a user is deleted.\n\n      def delete_user(user) do\n        Logger.info(\"Deleting user from the system: #{inspect(user)}\")\n        # ...\n      end\n\n  The `Logger.info/2` macro emits the provided message at the `:info`\n  level. Note the arguments given to `info/2` will only be evaluated\n  if a message is logged. For instance, if the Logger level is\n  set to `:warning`, `:info` messages are never logged and therefore\n  the arguments given above won't even be executed.\n\n  There are additional macros for other levels.\n\n  Logger also allows log commands to be removed altogether via the\n  `:compile_time_purge_matching` option (see below).\n\n  For dynamically logging messages, see `bare_log/3`. But note that\n  `bare_log/3` always evaluates its arguments (unless the argument\n  is an anonymous function).\n\n  ## Levels\n\n  The supported levels, ordered by importance, are:\n\n    * `:emergency` - when system is unusable, panics\n    * `:alert` - for alerts, actions that must be taken immediately,\n      ex. corrupted database\n    * `:critical` - for critical conditions\n    * `:error` - for errors\n    * `:warning` - for warnings\n    * `:notice` - for normal, but significant, messages\n    * `:info` - for information of any kind\n    * `:debug` - for debug-related messages\n\n  For example, `:info` takes precedence over `:debug`. If your log\n  level is set to `:info`, then all `:info`, `:notice` and above will\n  be passed to handlers. If your log level is set to `:alert`, only\n  `:alert` and `:emergency` will be printed.\n\n  ## Message\n\n  Logger can be used for logging both unstructured and structured data.\n\n  Unstructured data is a string or a list of strings:\n\n      Logger.info(\"hello world!\")\n      Logger.info([\"hello \", \"world!\"])\n\n  Structured data, also known as reports, are keyword lists and maps:\n\n      Logger.info([new_user: user.id, account_type: :admin])\n      Logger.info(%{new_user: user.id, account_type: :admin})\n\n  Log functions also accept a zero-arity anonymous function as a message:\n\n      Logger.info(fn -> \"hello world!\" end)\n\n  The anonymous function can return a message or a tuple containing\n  the message and additional metadata (to be described in the next\n  section).\n\n  In all cases, the arguments given to the `Logger` macros are only\n  evaluated if required by the current log level. The exception is\n  the `bare_log/3` function, which is the raw mechanism for logging.\n\n  ## Metadata\n\n  Whenever a message is logged, additional information can be given\n  via metadata. Each log operation, such as `Logger.info/2`, allows\n  metadata to be given as an argument.\n\n  Furthermore, metadata can be set per process with `Logger.metadata/1`.\n\n  Some metadata, however, may be added automatically by Logger whenever\n  possible. Those are:\n\n    * `:application` - the current application\n\n    * `:mfa` - the current module, function and arity\n\n    * `:file` - the current file\n\n    * `:line` - the current line\n\n    * `:pid` - the current process identifier\n\n    * `:initial_call` - the initial call that started the process\n\n    * `:registered_name` - the process registered name as an atom\n\n    * `:domain` - a list of domains for the logged message. For example,\n      all Elixir reports default to `[:elixir]`. Erlang reports may start\n      with `[:otp]` or `[:sasl]`\n\n    * `:crash_reason` - a two-element tuple with the throw/error/exit reason\n      as first argument and the stacktrace as second. A throw will always be\n      `{:nocatch, term}`. An error is always an `Exception` struct. All other\n      entries are exits. The default formatter ignores this metadata by default\n      but it can be useful to certain handlers, such as the ones that report\n      errors to third-party services\n\n  There are two special metadata keys, `:module` and `:function`, which\n  extract the relevant bits from `:mfa`.\n\n  The metadata keys above may not always be available. The `:mfa`, `:file`,\n  `:line`, and similar metadata are automatically included when using `Logger`\n  macros, but not when using `Logger.bare_log/3`. Other metadata, such as\n  `:crash_reason`, `:initial_call`, and `:registered_name` are available\n  only inside behaviours such as GenServer, Supervisor, and others.\n\n  It is also possible to pass metadata on a particular Logger invocation.\n  For example, you might wish to include a custom `:error_code` metadata in\n  your logs:\n\n      Logger.error(\"We have a problem\", [error_code: :pc_load_letter])\n\n  By default, no metadata is logged. We will learn how to enable that\n  over the next sections.\n\n  ## Configuration\n\n  `Logger` supports a wide range of configurations.\n\n  This configuration is split in three categories:\n\n    * Boot configuration - this configuration is read when logger\n      starts and configures how Elixir hooks into Erlang's own logger\n\n    * Compile configuration - this must be set before your code\n      is compiled\n\n    * Runtime configuration - can be set before the `:logger`\n      application is started, but may be changed during runtime\n\n  ### Boot configuration\n\n  When `Logger` starts, it configures the `:default` log handler from\n  Erlang to translate and format Elixir terms. As a developer, you\n  are able to customize the default handler, the default formatter,\n  and many other options.\n\n  The following configuration must be set via config files (such as\n  `config/config.exs`), under the `:logger` key, before your application\n  is started:\n\n    * `:default_formatter` - a keyword list which configures the\n      default formatter used by the default handler. See `Logger.Formatter`\n      for the full list of configuration.\n\n    * `:default_handler` - this option configures the default handler\n      used for logging. The default handler is a [`:logger_std_h`](`:logger_std_h`)\n      instance which also supports file logging and log rotation.\n      You can set it to `false` to disable the default logging altogether.\n      See the examples below for more information.\n\n    * `:handle_otp_reports` - if Erlang/OTP message should be logged.\n      Defaults to `true`.\n\n    * `:handle_sasl_reports` - if supervisor, crash, and progress reports\n      should be logged. Defaults to `false`. This option only has an effect\n      if `:handle_otp_reports` is true.\n\n    * `:metadata` - key-value pairs of global primary metadata to be included\n      in all log messages. Defaults to `[]`. The default formatter writes to\n      standard out and therefore cannot print all metadata. See\n      [`Logger.Formatter`'s documentation](`m:Logger.Formatter#module-metadata`)\n      for more information.\n\n  For example, to configure `Logger` to redirect all Erlang messages using a\n  `config/config.exs` file:\n\n      config :logger,\n        handle_otp_reports: true,\n        handle_sasl_reports: true\n\n  To configure the default formatter, for example, to use a different format\n  and include some metadata:\n\n      config :logger, :default_formatter,\n        format: \"[$level] $message $metadata\\n\",\n        metadata: [:error_code, :file]\n\n  Or to configure default handler, for instance, to log into a file with\n  built-in support for log rotation and compression:\n\n      config :logger, :default_handler,\n        config: [\n          file: ~c\"system.log\",\n          filesync_repeat_interval: 5000,\n          file_check: 5000,\n          max_no_bytes: 10_000_000,\n          max_no_files: 5,\n          compress_on_rotate: true\n        ]\n\n  You can find a complete reference on all handler options\n  [on Erlang/OTP docs](`t::logger_handler.config/0`). Here is Elixir's\n  default configuration for the default handler:\n\n      [\n        # Do not log messages from other nodes\n        filters: [{&:logger_filters.remote_gl/2, :stop}],\n        filter_default: :log,\n        formatter: &Logger.default_formatter/0,\n        level: :all,\n        module: :logger_std_h\n      ]\n\n  The `:config` customizes a specific handler module. The default handler\n  is [`:logger_std_h`](`:logger_std_h`), which logs to standard IO, and you\n  can find all relevant configuration in its module documentation, including\n  information overload protection.\n\n  You may also set `:default_handler` to false to disable the default logging\n  altogether:\n\n      config :logger, :default_handler, false\n\n  How to add more handlers besides the default one is covered in later sections.\n\n  > #### Keywords or maps {: .tip}\n  >\n  > While Erlang's logger expects `:config` to be a map, Elixir's Logger\n  > allows the default handler configuration to be set with keyword lists.\n  > For example, this allows your `config/*.exs` files, such as `config/dev.exs`,\n  > to override individual keys defined in `config/config.exs`.\n  >\n  > When reading the handler configuration using Erlang's APIs,\n  > the configuration will always be read (and written) as a map.\n\n  ### Compile configuration\n\n  The following configuration must be set via config files (such as\n  `config/config.exs`) under the `:logger` application before your code\n  is compiled:\n\n    * `:always_evaluate_messages` - if messages should be *evaluated* even if\n      the log level is lower than the minimum configured level. Defaults to `false`.\n      This is useful for cases where the log level in your *test environment*\n      is high (such as `:error`), which is common in order to avoid logs mixed\n      with the test output. In such, cases, you might discover log messages\n      that contain runtime errors only when your code is deployed to production,\n      where the log level is lower (such as `:info`). These runtime errors could\n      be caused by, for example, interpolating something that doesn't implement\n      the `String.Chars` protocol in the log message, such as `\"PID: #{self()}\"`\n      (since PIDs cannot be converted to strings with `String.Chars`).\n\n    * `:compile_time_application` - sets the `:application` metadata value\n      to the configured value at compilation time. This configuration is\n      automatically set by Mix and made available as metadata when logging.\n\n    * `:compile_time_purge_matching` - purges *at compilation time* all calls\n      that match the given conditions. This means that `Logger` calls with\n      level lower than this option will be completely removed at compile time,\n      accruing no overhead at runtime. This configuration expects a list of\n      keyword lists. Each keyword list contains a metadata key and the matching\n      value that should be purged. Some special keys are supported:\n\n        * `:level_lower_than` - purges all messages with a lower logger level\n        * `:module` - purges all messages with the matching module\n        * `:function` - purges all messages with the \"function/arity\"\n\n      Remember that if you want to purge log calls from a dependency, the\n      dependency must be recompiled.\n\n  For example, to purge all calls that happen at compile time with level\n  lower than `:info` in a `config/config.exs` file:\n\n      config :logger,\n        compile_time_purge_matching: [\n          [level_lower_than: :info]\n        ]\n\n  If you want to purge all log calls from an application named `:foo` and only\n  keep errors from `Bar.foo/3`, you can set up two different matches:\n\n      config :logger,\n        compile_time_purge_matching: [\n          [application: :foo],\n          [module: Bar, function: \"foo/3\", level_lower_than: :error]\n        ]\n\n  ### Runtime Configuration\n\n  All configuration below can be set via config files (such as\n  `config/config.exs`) but also changed dynamically during runtime via\n  `Logger.configure/1`.\n\n    * `:level` - the logging level. Attempting to log any message\n      with severity less than the configured level will simply\n      cause the message to be ignored. Keep in mind that each handler\n      may have its specific level, too. In addition to levels mentioned\n      above it also supports 2 \"meta-levels\":\n\n        - `:all` - all messages will be logged, conceptually identical to\n          `:debug`\n        - `:none` - no messages will be logged at all\n\n    * `:translator_inspect_opts` - when translating OTP reports and\n      errors, the last message and state must be inspected in the\n      error reports. This configuration allow developers to change\n      how much and how the data should be inspected. See `Kernel.inspect/2`\n      for more information on the available options.\n\n  For example, to configure the `:level` options in a `config/config.exs`\n  file:\n\n      config :logger, level: :warning\n\n  Furthermore, `Logger` allows messages sent by Erlang to be translated\n  into an Elixir format via translators. Translators can be added at any\n  time with the `add_translator/1` and `remove_translator/1` APIs. Check\n  `Logger.Translator` for more information.\n\n  ## Erlang/OTP handlers\n\n  Handlers represent the ability to integrate into the logging system to\n  handle each logged message/event.\n\n  ### Built-in handlers\n\n  Elixir's Logger automatically sets a default handler based on Erlang's\n  `:logger_std_h`, which you can configure using the `:default_handler` boot\n  configuration outlined above. You may also attach additional handlers\n  when you boot your application.\n\n  To do so, you must list a series of handlers under the `:logger` key\n  of your application configuration. For example, to setup an additional\n  handler that writes to a file:\n\n      config :my_app, :logger, [\n        {:handler, :file_log, :logger_std_h, %{\n           config: %{\n             file: ~c\"system.log\",\n             filesync_repeat_interval: 5000,\n             file_check: 5000,\n             max_no_bytes: 10_000_000,\n             max_no_files: 5,\n             compress_on_rotate: true\n           },\n           formatter: Logger.Formatter.new()\n         }}\n      ]\n\n  Each handler has the shape `{:handler, name, handler_module, config_map}`.\n  Once defined, a handler can be explicitly attached in your\n  `c:Application.start/2` callback, typically in `lib/my_app/application.ex`\n  with `Logger.add_handlers/1`:\n\n      Logger.add_handlers(:my_app)\n\n  You can also add, remove, and update handlers at runtime with the help\n  of the Erlang's [`:logger`](`:logger`) module.\n\n  ### Custom handlers\n\n  You may also develop your own handlers. Handlers run in the same\n  process as the process logging the message/event. This gives developers\n  flexibility but they should avoid performing any long running action in\n  such handlers, as it may slow down the action being executed considerably.\n\n  You must implement the [`:logger_handler`](`:logger_handler`) behaviour\n  to define custom handlers, which has only one required callback:\n\n      defmodule MyApp.CustomHandler do\n        @behaviour :logger_handler\n\n        def log(event, _config) do\n          IO.inspect(event)\n        end\n      end\n\n  Then you must define the handler in your configuration file:\n\n      config :my_app, :logger, [\n        {:handler, :my_handler, MyApp.CustomHandler, _config = %{}}\n      ]\n\n  And attach it on your application start using `Logger.add_handlers/1`,\n  as in the previous section.\n\n  Note there is no built-in overload protection for Erlang handlers,\n  so it is your responsibility to implement it if necessary. One alternative is\n  to use the [`:logger_backends`](https://github.com/elixir-lang/logger_backends)\n  project, which sets up a log handler with overload protection and allows\n  incoming events to be dispatched to multiple backends, although one must be\n  careful for backends to not become a bottleneck during logging.\n\n  ### Filtering\n\n  You can add filters to any handler. For example, to filter out logs\n  that contain a particular string, you could create a module:\n\n      defmodule LogFilter do\n        def filter(log_event, _opts) do\n          case log_event do\n            %{msg: {:string, msg}} ->\n              # msg may be a charlist or a binary\n              if to_string(msg) =~ \"password\" do\n                :stop\n              else\n                :ignore\n              end\n\n            _ ->\n              :ignore\n          end\n        end\n      end\n\n  The filter may return the possibly modified event (to change the\n  event used by subsequent filters), `:stop` (to discard the event),\n  or `:ignore` (to ignore the filter and continue with the subsequent filters).\n\n  Then you can attach the filter, either as a primary filter (which\n  applies to all handlers), or to a specific handler, when you start\n  your application, such as in the `c:Application.start/2` callback:\n\n      :logger.add_primary_filter(:word_filter, {&LogFilter.filter/2, []})\n\n  ## Backends and backwards compatibility\n\n  Prior to Elixir v1.15, custom logging could be achieved with Logger\n  backends. The main API for writing Logger backends have been moved to\n  the [`:logger_backends`](https://github.com/elixir-lang/logger_backends)\n  project. However, the backends API is still part of Elixir for backwards\n  compatibility.\n\n  Important remarks:\n\n    * If the `:backends` key is set and it doesn't have the `:console` entry,\n      we assume that you want to disable the built-in logging. You can force\n      logging by setting `config :logger, :default_handler, []`\n\n    * The `:console` backend configuration is automatically mapped to the default\n      handler and default formatter. Previously, you would set:\n\n          config :logger, :console,\n            level: :error,\n            format: \"$time $message $metadata\"\n\n      This is now equivalent to:\n\n          config :logger, :default_handler,\n            level: :error\n\n          config :logger, :default_formatter,\n            format: \"$time $message $metadata\"\n\n      All previous console configuration, except for `:level`, now go under\n      `:default_formatter`.\n\n    * If you want to use the previous `:console` implementation based on Logger\n      Backends, you can still set `backends: [Logger.Backends.Console]` and place\n      the configuration under `config :logger, Logger.Backends.Console`. Although\n      consider using the [`:logger_backends`](https://github.com/elixir-lang/logger_backends)\n      project in such cases, as `Logger.Backends.Console` itself will be deprecated\n      in future releases\n\n    * `Logger.Backends` only receive `:debug`, `:info`, `:warning`, and `:error`\n      messages. `:notice` maps to `:info`. `:warn` maps to `:warnings`.\n      All others map to `:error`\n  \"\"\"\n\n  @type level ::\n          :emergency | :alert | :critical | :error | :warning | :warn | :notice | :info | :debug\n  @type report :: map() | keyword()\n  @type message :: :unicode.chardata() | String.Chars.t() | report()\n  @type metadata :: keyword()\n\n  @type configure_opts :: [\n          level: level(),\n          translator_inspect_opts: Inspect.Opts.t(),\n          sync_threshold: non_neg_integer(),\n          discard_threshold: non_neg_integer(),\n          truncate: non_neg_integer() | :infinity,\n          utc_log: boolean()\n        ]\n\n  @type formatter_opts :: [\n          colors: [\n            enabled: boolean(),\n            debug: atom(),\n            info: atom(),\n            warning: atom(),\n            error: atom()\n          ],\n          format: String.t() | {module(), atom()},\n          metadata: :all | [atom()],\n          truncate: pos_integer() | :infinity,\n          utc_log: boolean()\n        ]\n\n  @new_erlang_levels [:emergency, :alert, :critical, :warning, :notice]\n  @levels [:error, :info, :debug] ++ @new_erlang_levels\n  @metadata :logger_level\n\n  @doc ~S\"\"\"\n  Returns all the available levels.\n  \"\"\"\n  @doc since: \"1.16.0\"\n  @spec levels() :: [level(), ...]\n  def levels(), do: @levels\n\n  @doc ~S\"\"\"\n  Returns the default formatter used by Logger.\n\n  It returns a `Logger.Formatter` built on the `:default_formatter` configuration:\n\n      config :logger, :default_formatter,\n        format: \"\\n$time $metadata[$level] $message\\n\",\n        metadata: [:user_id]\n\n  In case of a list, a set of `overrides` can be given to merge into the list.\n  See `Logger.Formatter.new/1` for all options.\n\n  ## Examples\n\n  `Logger` will automatically load a default formatter into the default handler\n  on boot. However, you can use this function if you wish to programmatically replace\n  a handler formatter. For example, inside tests, you might want to change the formatter\n  settings:\n\n      setup tags do\n        formatter = Logger.default_formatter(colors: [enabled: false])\n        :logger.update_handler_config(:default, :formatter, formatter)\n\n        on_exit(fn ->\n          :logger.update_handler_config(:default, :formatter, Logger.default_formatter())\n        end)\n      end\n\n  However, note you should not invoke this function inside `config` files,\n  as this function expects `Logger` to already be configured and started.\n  To start a brand new handler with this formatter, use `Logger.Formatter.new/1`\n  instead.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec default_formatter(formatter_opts) :: {module, :logger.formatter_config()}\n  def default_formatter(overrides \\\\ []) when is_list(overrides) do\n    Application.get_env(:logger, :default_formatter, [])\n    |> Keyword.merge(overrides)\n    |> Logger.Formatter.new()\n  end\n\n  @doc \"\"\"\n  Alters the current process metadata according to the given enumerable.\n\n  This function will merge the given enumerable into the existing metadata,\n  with the exception of setting a key to `nil`, which will remove that key\n  from the metadata.\n\n  Note some metadata keys are reserved and cannot be overridden. See\n  [the module documentation](#module-metadata) for more information.\n  \"\"\"\n  @spec metadata(Enumerable.t({atom(), term()})) :: :ok\n  def metadata(enumerable) do\n    case :logger.get_process_metadata() do\n      :undefined ->\n        reset_metadata(enumerable)\n\n      map when is_map(map) ->\n        metadata =\n          Enum.reduce(enumerable, map, fn\n            {k, nil}, acc -> Map.delete(acc, k)\n            {k, v}, acc -> Map.put(acc, k, v)\n          end)\n\n        :ok = :logger.set_process_metadata(metadata)\n    end\n  end\n\n  @doc \"\"\"\n  Reads the current process metadata.\n\n  This does not return the \"global\" logger metadata (set via the `:metadata` key in the\n  `:logger` application config), but only the process metadata.\n  \"\"\"\n  @spec metadata() :: metadata\n  def metadata() do\n    case :logger.get_process_metadata() do\n      :undefined -> []\n      map when is_map(map) -> Map.to_list(map)\n    end\n  end\n\n  @doc \"\"\"\n  Resets the current process metadata to the given enumerable.\n  \"\"\"\n  @spec reset_metadata(Enumerable.t({atom(), term()})) :: :ok\n  def reset_metadata(enumerable \\\\ []) do\n    :ok = :logger.set_process_metadata(filter_out_nils(enumerable))\n  end\n\n  defp filter_out_nils(keyword) do\n    for {_k, v} = elem <- keyword, v != nil, into: %{}, do: elem\n  end\n\n  @doc \"\"\"\n  Enables logging for the current process.\n\n  Currently the only accepted PID is `self()`.\n\n  Equivalent of:\n\n      delete_process_level(pid)\n  \"\"\"\n  # TODO: Remove me on v2.0\n  @deprecated \"Use Logger.delete_process_level(pid) instead\"\n  @spec enable(pid) :: :ok\n  def enable(pid) when pid == self() do\n    delete_process_level(pid)\n  end\n\n  @doc \"\"\"\n  Disables logging for the current process.\n\n  Currently the only accepted PID is `self()`.\n\n  Equivalent of:\n\n      put_process_level(pid, :none)\n  \"\"\"\n  # TODO: Remove me on v2.0\n  @deprecated \"Use Logger.put_process_level(pid, :none) instead\"\n  @spec disable(pid) :: :ok\n  def disable(pid) when pid == self() do\n    put_process_level(pid, :none)\n  end\n\n  @doc \"\"\"\n  Returns whether the logging is enabled for a given process.\n\n  Currently the only accepted PID is `self()`.\n  \"\"\"\n  # TODO: Remove me on v2.0\n  @deprecated \"Use Logger.get_process_level(pid) instead\"\n  @spec enabled?(pid) :: boolean\n  def enabled?(pid) when pid == self() do\n    get_process_level(pid) != :none\n  end\n\n  @doc \"\"\"\n  Retrieves the `Logger` level.\n\n  The `Logger` level can be changed via `configure/1`.\n  \"\"\"\n  @spec level() :: level() | :all | :none\n  def level() do\n    %{level: level} = :logger.get_primary_config()\n\n    level\n  end\n\n  @doc \"\"\"\n  Compares log levels.\n\n  Receives two log levels and compares the `left` level\n  against the `right` level and returns:\n\n    * `:lt` if `left` is less than `right`\n    * `:eq` if `left` and `right` are equal\n    * `:gt` if `left` is greater than `right`\n\n  ## Examples\n\n      iex> Logger.compare_levels(:debug, :warning)\n      :lt\n      iex> Logger.compare_levels(:error, :info)\n      :gt\n\n  \"\"\"\n  @spec compare_levels(level, level) :: :lt | :eq | :gt\n  def compare_levels(left, right) do\n    :logger.compare_levels(\n      elixir_level_to_erlang_level(left),\n      elixir_level_to_erlang_level(right)\n    )\n  end\n\n  @doc \"\"\"\n  Configures the logger.\n\n  See the \"Runtime Configuration\" section in the `Logger` module\n  documentation for the available options. The changes done here\n  are automatically persisted to the `:logger` application\n  environment.\n  \"\"\"\n  @valid_options [\n    :always_evaluate_messages,\n    :compile_time_application,\n    :compile_time_purge_level,\n    :compile_time_purge_matching,\n    :truncate,\n    :utc_log,\n    :translator_inspect_opts\n  ]\n  @backend_options [:sync_threshold, :discard_threshold, :truncate, :utc_log]\n  @spec configure(configure_opts) :: :ok\n  def configure(options) do\n    for {k, v} <- options do\n      cond do\n        k == :level -> :logger.set_primary_config(:level, elixir_level_to_erlang_level(v))\n        k in @valid_options -> Application.put_env(:logger, k, v)\n        true -> :ok\n      end\n    end\n\n    case Keyword.take(options, @backend_options) do\n      [] ->\n        :ok\n\n      backend_options ->\n        for {key, _} <- backend_options do\n          IO.warn_once(\n            {__MODULE__, :configure, key},\n            fn ->\n              \"setting #{inspect(key)} in Logger.configure/2 is deprecated, \" <>\n                \"add the :logger_backends dependency and configure it instead\"\n            end,\n            3\n          )\n        end\n\n        Logger.Backends.Internal.configure(backend_options)\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Flushes the logger.\n\n  This guarantees all logger handlers flush to disk or storage.\n  This is useful for testing but it should be avoided in production,\n  as it could force logger handlers to drop whatever they are doing\n  and flush, even if continuing to buffer would be the most performant\n  option.\n  \"\"\"\n  @spec flush :: :ok\n  def flush do\n    for %{id: id, module: module} <- :logger.get_handler_config(),\n        function_exported?(module, :filesync, 1) do\n      try do\n        module.filesync(id)\n      catch\n        _, _ -> :ok\n      end\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Puts logging level for given module.\n\n  This will take priority over the primary level set, so it can be\n  used to increase or decrease verbosity of some parts of the project.\n\n  ## Example\n\n      defmodule Foo do\n        require Logger\n\n        def log, do: Logger.debug(\"foo\")\n      end\n\n      Logger.configure(level: :error)\n      Logger.put_module_level(Foo, :all)\n\n      Foo.log()\n      # This will print the message even if global level is :error\n\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec put_module_level(module() | [module()], level() | :all | :none) :: :ok | {:error, term()}\n  defdelegate put_module_level(mod, level), to: :logger, as: :set_module_level\n\n  @doc \"\"\"\n  Gets logging level for given module.\n\n  The returned value will be the effective value used. If no value\n  was set for a given module, then it will not be present in\n  the returned list.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec get_module_level(module() | [module()]) :: [{module(), level() | :all | :none}]\n  defdelegate get_module_level(mod), to: :logger\n\n  @doc \"\"\"\n  Resets the logging level for a given module to the primary level.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec delete_module_level(module() | [module()]) :: :ok\n  defdelegate delete_module_level(module), to: :logger, as: :unset_module_level\n\n  @doc \"\"\"\n  Resets the logging level for all modules to the primary level.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec delete_all_module_levels() :: :ok\n  defdelegate delete_all_module_levels(), to: :logger, as: :unset_module_level\n\n  @doc \"\"\"\n  Puts logging level for modules in a given application.\n\n  This will take priority over the primary level set, so it can be\n  used to increase or decrease verbosity of some parts of the project.\n\n  Equivalent of:\n\n      appname |> Application.spec(:modules) |> Logger.put_module_level(level)\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec put_application_level(atom(), level() | :all | :none) :: :ok | {:error, :not_loaded}\n  defdelegate put_application_level(appname, level), to: :logger, as: :set_application_level\n\n  @doc \"\"\"\n  Resets logging level for all modules in the given application to the primary level.\n\n  Equivalent of:\n\n      appname |> Application.spec(:modules) |> Logger.delete_module_level()\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec delete_application_level(application) :: :ok | {:error, {:not_loaded, application}}\n        when application: atom()\n  defdelegate delete_application_level(appname), to: :logger, as: :unset_application_level\n\n  @doc \"\"\"\n  Puts logging level for the current process.\n\n  Currently the only accepted PID is `self()`.\n\n  Different from `put_module_level/2`, the process level doesn't take priority\n  over the global level, but instead works alongside it. Effectively, the higher\n  logger level is used.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec put_process_level(pid(), level() | :all | :none) :: :ok\n  def put_process_level(pid, level) when pid == self() do\n    Process.put(@metadata, elixir_level_to_erlang_level(level))\n    :ok\n  end\n\n  @doc \"\"\"\n  Gets logging level for the current process.\n\n  Currently the only accepted PID is `self()`.\n\n  The returned value will be the effective value used. If no value\n  was set for a given process, then `nil` is returned.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec get_process_level(pid) :: level() | :all | :none | nil\n  def get_process_level(pid) when pid == self() do\n    Process.get(@metadata, nil)\n  end\n\n  @doc \"\"\"\n  Resets logging level for the current process to the primary level.\n\n  Currently the only accepted PID is `self()`.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec delete_process_level(pid()) :: :ok\n  def delete_process_level(pid) when pid == self() do\n    Process.delete(@metadata)\n    :ok\n  end\n\n  @doc \"\"\"\n  Adds the handlers configured in the `:logger` application parameter\n  of the given `app`.\n\n  This is used to register new handlers into the logging system.\n  See [the module documentation](#module-erlang-otp-handlers) for\n  more information.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec add_handlers(atom()) :: :ok | {:error, term}\n  def add_handlers(app) when is_atom(app) do\n    :logger.add_handlers(app)\n  end\n\n  @doc \"\"\"\n  Adds a new backend.\n  \"\"\"\n  # TODO: Remove me on v2.0\n  @deprecated \"Use LoggerBackends.add/2 from :logger_backends dependency\"\n  def add_backend(backend, opts \\\\ []) do\n    Logger.Backends.Internal.add(backend, opts)\n  end\n\n  @doc \"\"\"\n  Removes a backend.\n  \"\"\"\n  # TODO: Remove me on v2.0\n  @deprecated \"Use LoggerBackends.remove/2 from :logger_backends dependency\"\n  def remove_backend(backend, opts \\\\ []) do\n    Logger.Backends.Internal.remove(backend, opts)\n  end\n\n  @doc \"\"\"\n  Configures the given backend.\n  \"\"\"\n  # TODO: Remove me on v2.0\n  @deprecated \"Use LoggerBackends.configure/2 from :logger_backends dependency\"\n  def configure_backend(:console, options) when is_list(options) do\n    options = Keyword.merge(Application.get_env(:logger, :console, []), options)\n    Application.put_env(:logger, :console, options)\n    {with_level, without_level} = Keyword.split(options, [:level])\n    config = Map.new(with_level ++ [formatter: Logger.Formatter.new(without_level)])\n    :logger.update_handler_config(:default, config)\n  end\n\n  def configure_backend(backend, options) do\n    Logger.Backends.Internal.configure(backend, options)\n  end\n\n  @doc \"\"\"\n  Adds a new translator.\n  \"\"\"\n  @spec add_translator({module, function :: atom}) :: :ok\n  def add_translator({mod, fun} = translator) when is_atom(mod) and is_atom(fun) do\n    update_translators(&[translator | List.delete(&1, translator)])\n  end\n\n  @doc \"\"\"\n  Removes a translator.\n  \"\"\"\n  @spec remove_translator({module, function :: atom}) :: :ok\n  def remove_translator({mod, fun} = translator) when is_atom(mod) and is_atom(fun) do\n    update_translators(&List.delete(&1, translator))\n  end\n\n  defp update_translators(updater) do\n    :elixir_config.serial(fn ->\n      translators = updater.(Application.fetch_env!(:logger, :translators))\n      Application.put_env(:logger, :translators, translators)\n\n      with %{filters: filters} <- :logger.get_primary_config(),\n           {{_, {fun, config}}, filters} <- List.keytake(filters, :logger_translator, 0) do\n        config = %{config | translators: translators}\n        :ok = :logger.set_primary_config(:filters, filters ++ [logger_translator: {fun, config}])\n      end\n    end)\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Logs a message dynamically.\n\n  Opposite to `log/3`, `debug/2`, `info/2`, and friends, the arguments\n  given to `bare_log/3` are always evaluated. However, you can pass\n  anonymous functions to `bare_log/3` and they will only be evaluated\n  if there is something to be logged.\n  \"\"\"\n  @spec bare_log(level, message | (-> message | {message, keyword}), metadata) :: :ok\n  def bare_log(level, message_or_fun, metadata \\\\ []) do\n    level = elixir_level_to_erlang_level(level)\n\n    if :logger_config.allow(level) do\n      __do_log__(level, message_or_fun, %{}, Map.new(metadata))\n    end\n\n    :ok\n  end\n\n  @doc false\n  def __should_log__(level, module) do\n    level = elixir_level_to_erlang_level(level)\n\n    if :logger_config.allow(level, module) do\n      level\n    end\n  end\n\n  @doc false\n  def __evaluate_log__(data, metadata) when is_function(data, 0) do\n    case data.() do\n      {msg, new_metadata} -> {msg, Enum.into(new_metadata, metadata)}\n      data -> {data, metadata}\n    end\n  end\n\n  def __evaluate_log__(data, metadata) do\n    {data, metadata}\n  end\n\n  @doc false\n  def __do_log__(level, fun, location, metadata)\n      when is_function(fun, 0) and is_map(location) and is_map(metadata) do\n    case fun.() do\n      {msg, meta} ->\n        __do_log__(level, msg, location, Enum.into(meta, metadata))\n\n      msg ->\n        __do_log__(level, msg, location, metadata)\n    end\n  end\n\n  def __do_log__(level, msg, location, metadata)\n      when level in @levels and is_map(location) and is_map(metadata) do\n    if is_binary(msg) or is_list(msg) or is_map(msg) do\n      :logger.macro_log(location, level, msg, add_elixir_domain(metadata))\n    else\n      IO.warn(\n        \"passing #{inspect(msg)} to Logger is deprecated, expected a map, a keyword list, \" <>\n          \"a string, a list of strings, or a zero-arity anonymous function\"\n      )\n\n      :logger.macro_log(location, level, to_string(msg), add_elixir_domain(metadata))\n    end\n  end\n\n  defp add_elixir_domain(%{domain: domain} = metadata) when is_list(domain) do\n    %{metadata | domain: [:elixir | domain]}\n  end\n\n  defp add_elixir_domain(metadata), do: Map.put(metadata, :domain, [:elixir])\n\n  for level <- @levels do\n    report = [something: :reported, this: level]\n    metadata = [user_id: 42, request_id: \"xU32kFa\"]\n    article = if level in [:info, :error, :alert, :emergency], do: \"an\", else: \"a\"\n\n    @doc \"\"\"\n    Logs #{article} #{level} message.\n\n    Returns `:ok`.\n\n    ## Examples\n\n    Logging a message (string or iodata):\n\n        Logger.#{level}(\"this is #{article} #{level} message\")\n\n    Report message (maps or keywords):\n\n        # as keyword list\n        Logger.#{level}(#{inspect(report)})\n\n        # as map\n        Logger.#{level}(#{inspect(Map.new(report))})\n\n    Report message with metadata (maps or keywords):\n\n        # as a keyword list\n        Logger.#{level}(\"this is #{article} #{level} message\", #{inspect(metadata)})\n\n        # as map\n        Logger.#{level}(\"this is #{article} #{level} message\", #{inspect(Map.new(metadata))})\n    \"\"\"\n\n    # Only macros generated for the \"new\" Erlang levels are available since 1.11.0. Other\n    # ones, such as :info or :debug, are available since the early days of Elixir.\n    if level in @new_erlang_levels do\n      @doc since: \"1.11.0\"\n    end\n\n    defmacro unquote(level)(message_or_fun, metadata \\\\ []) do\n      maybe_log(unquote(level), message_or_fun, metadata, __CALLER__)\n    end\n  end\n\n  @deprecated \"Use Logger.warning/2 instead\"\n  defmacro warn(message_or_fun, metadata \\\\ []) do\n    maybe_log(:warning, message_or_fun, metadata, __CALLER__)\n  end\n\n  @doc \"\"\"\n  Logs a message with the given `level`.\n\n  Returns `:ok`.\n\n  The macros `debug/2`, `info/2`, `notice/2`, `warning/2`,\n  `error/2`, `critical/2`, `alert/2`, and `emergency/2` are\n  preferred over this macro as they can automatically eliminate\n  the call to `Logger` altogether at compile time if desired\n  (see the documentation for the `Logger` module).\n  \"\"\"\n  defmacro log(level, message_or_fun, metadata \\\\ []) do\n    macro_log(level, message_or_fun, metadata, __CALLER__)\n  end\n\n  defp macro_log(level, data, metadata, caller) do\n    {maybe_application, file} = compile_time_application_and_file(caller)\n\n    location =\n      case caller do\n        %{module: module, function: {fun, arity}, line: line} ->\n          %{mfa: {module, fun, arity}, file: file, line: line}\n\n        _ ->\n          %{}\n      end\n\n    {compile_metadata, quoted_metadata} =\n      if Keyword.keyword?(metadata) do\n        metadata = Keyword.merge(maybe_application, metadata)\n        {Map.merge(location, Map.new(metadata)), escape_metadata(metadata)}\n      else\n        {%{},\n         quote do\n           Enum.into(unquote(metadata), unquote(escape_metadata(maybe_application)))\n         end}\n      end\n\n    compile_level = if is_atom(level), do: level, else: :error\n\n    cond do\n      compile_time_purge_matching?(compile_level, compile_metadata) ->\n        no_log(data, quoted_metadata)\n\n      Application.get_env(:logger, :always_evaluate_messages, false) ->\n        quote do\n          {data, metadata} = Logger.__evaluate_log__(unquote(data), unquote(quoted_metadata))\n\n          case Logger.__should_log__(unquote(level), __MODULE__) do\n            nil -> :ok\n            level -> Logger.__do_log__(level, data, unquote(Macro.escape(location)), metadata)\n          end\n        end\n\n      true ->\n        quote do\n          case Logger.__should_log__(unquote(level), __MODULE__) do\n            nil ->\n              :ok\n\n            level ->\n              Logger.__do_log__(\n                level,\n                unquote(data),\n                unquote(Macro.escape(location)),\n                unquote(quoted_metadata)\n              )\n          end\n        end\n    end\n  end\n\n  defp escape_metadata(metadata) do\n    {_, metadata} =\n      Keyword.get_and_update(metadata, :mfa, fn\n        nil -> :pop\n        mfa -> {mfa, Macro.escape(mfa)}\n      end)\n\n    {:%{}, [], metadata}\n  end\n\n  defp compile_time_application_and_file(%{file: file}) do\n    if app = Application.get_env(:logger, :compile_time_application) do\n      {[application: app], file |> Path.relative_to_cwd() |> String.to_charlist()}\n    else\n      {[], String.to_charlist(file)}\n    end\n  end\n\n  defp compile_time_purge_matching?(level, compile_metadata) do\n    matching = Application.get_env(:logger, :compile_time_purge_matching, [])\n\n    if not is_list(matching) do\n      bad_compile_time_purge_matching!(matching)\n    end\n\n    Enum.any?(matching, fn filter ->\n      if not is_list(filter) do\n        bad_compile_time_purge_matching!(matching)\n      end\n\n      Enum.all?(filter, fn\n        {:level_lower_than, min_level} ->\n          compare_levels(level, min_level) == :lt\n\n        {:module, module} ->\n          match?({:ok, {^module, _, _}}, Map.fetch(compile_metadata, :mfa))\n\n        {:function, func} ->\n          case Map.fetch(compile_metadata, :mfa) do\n            {:ok, {_, f, a}} -> \"#{f}/#{a}\" == func\n            _ -> false\n          end\n\n        {k, v} when is_atom(k) ->\n          Map.fetch(compile_metadata, k) == {:ok, v}\n\n        _ ->\n          bad_compile_time_purge_matching!(matching)\n      end)\n    end)\n  end\n\n  defp bad_compile_time_purge_matching!(matching) do\n    raise \"expected :compile_time_purge_matching to be a list of keyword lists, \" <>\n            \"got: #{inspect(matching)}\"\n  end\n\n  defp maybe_log(level, data, metadata, caller) do\n    min_level =\n      if env_level = Application.get_env(:logger, :compile_time_purge_level) do\n        IO.warn(\n          \":compile_time_purge_level option for the :logger application is deprecated, \" <>\n            \"use :compile_time_purge_matching instead\",\n          Macro.Env.stacktrace(caller)\n        )\n\n        env_level\n      else\n        :debug\n      end\n\n    if compare_levels(level, min_level) != :lt do\n      macro_log(level, data, metadata, caller)\n    else\n      no_log(data, metadata)\n    end\n  end\n\n  defp no_log(data, metadata) do\n    if Application.get_env(:logger, :always_evaluate_messages, false) do\n      quote do\n        Logger.__evaluate_log__(unquote(data), unquote(metadata))\n        :ok\n      end\n    else\n      # We wrap the contents in an anonymous function\n      # to avoid unused variable warnings.\n      quote do\n        _ = fn -> {unquote(data), unquote(metadata)} end\n        :ok\n      end\n    end\n  end\n\n  defp elixir_level_to_erlang_level(:warn) do\n    IO.warn(\"the log level :warn is deprecated, use :warning instead\")\n    :warning\n  end\n\n  defp elixir_level_to_erlang_level(other), do: other\nend\n"
  },
  {
    "path": "lib/logger/mix.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :logger,\n      version: System.version(),\n      build_per_environment: false\n    ]\n  end\n\n  def application do\n    [\n      registered: [Logger, Logger.Supervisor],\n      mod: {Logger.App, []},\n      env: [\n        utc_log: false,\n        truncate: 8096,\n        translators: [{Logger.Translator, :translate}],\n        handle_otp_reports: true,\n        handle_sasl_reports: false,\n        always_evaluate_messages: false,\n        compile_time_purge_matching: [],\n        compile_time_application: nil,\n        translator_inspect_opts: [],\n        start_options: [],\n        sync_threshold: 20,\n        discard_threshold: 500,\n        discard_threshold_periodic_check: 30_000,\n        metadata: []\n      ]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/logger/test/logger/backends/console_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Backends.ConsoleTest do\n  use Logger.Case\n\n  require Logger\n  import ExUnit.CaptureIO\n\n  setup_all do\n    capture_io(:stderr, fn ->\n      Application.put_env(:logger, :backends, [Logger.Backends.Console])\n      Logger.App.stop()\n      Application.start(:logger)\n    end)\n\n    on_exit(fn ->\n      Application.delete_env(:logger, :backends)\n      Logger.App.stop()\n      Application.start(:logger)\n    end)\n  end\n\n  setup do\n    on_exit(fn ->\n      :ok =\n        Logger.Backends.Internal.configure(\n          Logger.Backends.Console,\n          format: nil,\n          device: :user,\n          level: nil,\n          metadata: [],\n          colors: [enabled: false]\n        )\n    end)\n  end\n\n  test \"does not start when there is no user\" do\n    :ok = Logger.Backends.Internal.remove(Logger.Backends.Console)\n    user = Process.whereis(:user)\n\n    try do\n      Process.unregister(:user)\n\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        assert :gen_event.add_handler(Logger, Logger.Backends.Console, Logger.Backends.Console) ==\n                 {:error, :ignore}\n      end)\n    after\n      Process.register(user, :user)\n    end\n  after\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      {:ok, _} = Logger.Backends.Internal.add(Logger.Backends.Console)\n    end)\n  end\n\n  test \"may use another device\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console, device: :standard_error)\n\n    assert capture_io(:standard_error, fn ->\n             Logger.debug(\"hello\")\n             Logger.flush()\n           end) =~ \"hello\"\n  end\n\n  test \"configures format\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console, format: \"$message [$level]\")\n\n    assert capture_log(fn -> Logger.debug(\"hello\") end) =~ \"hello [debug]\"\n  end\n\n  test \"configures metadata\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$metadata$message\",\n      metadata: [:user_id]\n    )\n\n    assert capture_log(fn -> Logger.debug(\"hello\") end) =~ \"hello\"\n\n    Logger.metadata(user_id: 11)\n    Logger.metadata(user_id: 13)\n    assert capture_log(fn -> Logger.debug(\"hello\") end) =~ \"user_id=13 hello\"\n  end\n\n  test \"logs initial_call as metadata\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$metadata$message\",\n      metadata: [:initial_call]\n    )\n\n    assert capture_log(fn -> Logger.debug(\"hello\", initial_call: {Foo, :bar, 3}) end) =~\n             \"initial_call=Foo.bar/3 hello\"\n  end\n\n  test \"logs domain as metadata\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$metadata$message\",\n      metadata: [:domain]\n    )\n\n    assert capture_log(fn -> Logger.debug(\"hello\", domain: [:foobar]) end) =~\n             \"domain=elixir.foobar hello\"\n  end\n\n  test \"logs mfa as metadata\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$metadata$message\",\n      metadata: [:mfa]\n    )\n\n    {function, arity} = __ENV__.function\n    mfa = Exception.format_mfa(__MODULE__, function, arity)\n\n    assert capture_log(fn -> Logger.debug(\"hello\") end) =~\n             \"mfa=#{mfa} hello\"\n  end\n\n  test \"ignores crash_reason metadata when configured with metadata: :all\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$metadata$message\",\n      metadata: :all\n    )\n\n    Logger.metadata(crash_reason: {%RuntimeError{message: \"oops\"}, []})\n    assert capture_log(fn -> Logger.debug(\"hello\") end) =~ \"hello\"\n  end\n\n  test \"configures formatter to {module, function} tuple\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console, format: {__MODULE__, :format})\n\n    assert capture_log(fn -> Logger.debug(\"hello\") end) =~ \"my_format: hello\"\n  end\n\n  def format(_level, message, _ts, _metadata) do\n    \"my_format: #{message}\"\n  end\n\n  test \"configures metadata to :all\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$metadata\",\n      metadata: :all\n    )\n\n    Logger.metadata(user_id: 11)\n    Logger.metadata(dynamic_metadata: 5)\n\n    %{module: mod, function: {name, arity}, file: file, line: line} = __ENV__\n    log = capture_log(fn -> Logger.debug(\"hello\") end)\n\n    assert log =~ \"file=#{file}\"\n    assert log =~ \"line=#{line + 1}\"\n    assert log =~ \"module=#{inspect(mod)}\"\n    assert log =~ \"function=#{name}/#{arity}\"\n    assert log =~ \"dynamic_metadata=5\"\n    assert log =~ \"user_id=11\"\n  end\n\n  test \"provides metadata defaults\" do\n    metadata = [:file, :line, :module, :function]\n\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$metadata\",\n      metadata: metadata\n    )\n\n    %{module: mod, function: {name, arity}, file: file, line: line} = __ENV__\n    log = capture_log(fn -> Logger.debug(\"hello\") end)\n\n    assert log =~ \"file=#{file} line=#{line + 1} module=#{inspect(mod)} function=#{name}/#{arity}\"\n  end\n\n  test \"configures level\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console, level: :info)\n\n    assert capture_log(fn -> Logger.debug(\"hello\") end) == \"\"\n  end\n\n  test \"filter by notice\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console, level: :notice)\n\n    assert capture_log(fn -> Logger.debug(\"hello\") end) == \"\"\n    assert capture_log(fn -> Logger.info(\"hello\") end) == \"\"\n    assert capture_log(fn -> Logger.notice(\"hello\") end) =~ \"[notice] hello\\n\"\n    assert capture_log(fn -> Logger.warning(\"hello\") end) =~ \"[warning] hello\\n\"\n    assert capture_log(fn -> Logger.critical(\"hello\") end) =~ \"[critical] hello\\n\"\n    assert capture_log(fn -> Logger.alert(\"hello\") end) =~ \"[alert] hello\\n\"\n    assert capture_log(fn -> Logger.error(\"hello\") end) =~ \"[error] hello\\n\"\n  end\n\n  test \"configures colors\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$message\",\n      colors: [enabled: true]\n    )\n\n    assert capture_log(fn -> Logger.debug(\"hello\") end) ==\n             IO.ANSI.cyan() <> \"hello\" <> IO.ANSI.reset()\n\n    Logger.Backends.Internal.configure(Logger.Backends.Console, colors: [debug: :magenta])\n\n    assert capture_log(fn -> Logger.debug(\"hello\") end) ==\n             IO.ANSI.magenta() <> \"hello\" <> IO.ANSI.reset()\n\n    assert capture_log(fn -> Logger.info(\"hello\") end) ==\n             IO.ANSI.normal() <> \"hello\" <> IO.ANSI.reset()\n\n    Logger.Backends.Internal.configure(Logger.Backends.Console, colors: [info: :cyan])\n\n    assert capture_log(fn -> Logger.info(\"hello\") end) ==\n             IO.ANSI.cyan() <> \"hello\" <> IO.ANSI.reset()\n\n    assert capture_log(fn -> Logger.warning(\"hello\") end) ==\n             IO.ANSI.yellow() <> \"hello\" <> IO.ANSI.reset()\n\n    Logger.Backends.Internal.configure(Logger.Backends.Console, colors: [warning: :magenta])\n\n    assert capture_log(fn -> Logger.warning(\"hello\") end) ==\n             IO.ANSI.magenta() <> \"hello\" <> IO.ANSI.reset()\n\n    assert capture_log(fn -> Logger.error(\"hello\") end) ==\n             IO.ANSI.red() <> \"hello\" <> IO.ANSI.reset()\n\n    Logger.Backends.Internal.configure(Logger.Backends.Console, colors: [error: :cyan])\n\n    assert capture_log(fn -> Logger.error(\"hello\") end) ==\n             IO.ANSI.cyan() <> \"hello\" <> IO.ANSI.reset()\n  end\n\n  test \"uses colors from metadata\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      format: \"$message\",\n      colors: [enabled: true]\n    )\n\n    assert capture_log(fn -> Logger.log(:error, \"hello\", ansi_color: :yellow) end) ==\n             IO.ANSI.yellow() <> \"hello\" <> IO.ANSI.reset()\n  end\nend\n"
  },
  {
    "path": "lib/logger/test/logger/backends/handler_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.Backends.HandlerTest do\n  use Logger.Case\n  @moduletag :logger\n\n  defmodule CustomTranslator do\n    def t(:debug, _level, :format, {~c\"hello: ~p\", [:ok]}) do\n      :skip\n    end\n\n    def t(:debug, _level, :format, {~c\"world: ~p\", [:ok]}) do\n      {:ok, \"rewritten\"}\n    end\n\n    def t(:debug, :info, :report, {:logger, %{hello: :ok}}) do\n      :skip\n    end\n\n    def t(:debug, :info, :report, {:logger, %{world: :ok}}) do\n      {:ok, \"rewritten\"}\n    end\n\n    def t(:debug, :info, :report, {:logger, %{error: error}}) do\n      raise(error)\n    end\n\n    def t(_, _, _, _) do\n      :none\n    end\n  end\n\n  setup_all do\n    Application.put_env(:logger, :default_handler, false)\n    Logger.App.stop()\n\n    # Explicitly use add to make sure that root is dynamically started\n    Application.start(:logger)\n\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      Logger.Backends.Internal.add(Logger.Backends.Console)\n    end)\n\n    on_exit(fn ->\n      Application.delete_env(:logger, :default_handler)\n      Logger.App.stop()\n      Application.start(:logger)\n    end)\n  end\n\n  test \"add_translator/1 and remove_translator/1 for error_logger\" do\n    assert Logger.add_translator({CustomTranslator, :t})\n\n    assert capture_log(fn ->\n             :error_logger.info_msg(~c\"hello: ~p\", [:ok])\n           end) == \"\"\n\n    assert capture_log(fn ->\n             :error_logger.info_msg(~c\"world: ~p\", [:ok])\n           end) =~ \"[notice] rewritten\"\n  after\n    assert Logger.remove_translator({CustomTranslator, :t})\n  end\n\n  test \"add_translator/1 and remove_translator/1 for logger formats\" do\n    refute {CustomTranslator, :t} in Application.fetch_env!(:logger, :translators)\n    assert Logger.add_translator({CustomTranslator, :t})\n    assert {CustomTranslator, :t} in Application.fetch_env!(:logger, :translators)\n\n    assert capture_log(fn ->\n             :logger.info(~c\"hello: ~p\", [:ok])\n           end) == \"\"\n\n    assert capture_log(fn ->\n             :logger.info(~c\"world: ~p\", [:ok])\n           end) =~ \"[info] rewritten\"\n\n    assert capture_log(fn ->\n             :logger.info(%{hello: :ok})\n           end) == \"\"\n\n    assert capture_log(fn ->\n             :logger.info(%{world: :ok})\n           end) =~ \"[info] rewritten\"\n  after\n    assert Logger.remove_translator({CustomTranslator, :t})\n  end\n\n  test \"handles translation error\" do\n    assert Logger.add_translator({CustomTranslator, :t})\n\n    message = capture_log(fn -> :logger.info(%{error: \"oops\"}) end)\n    assert message =~ \"[info] Failure while translating Erlang's logger event\\n\"\n    assert message =~ \"** (RuntimeError) oops\\n\"\n  after\n    assert Logger.remove_translator({CustomTranslator, :t})\n  end\n\n  test \"converts Erlang metadata\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console,\n      metadata: [:file, :line, :module, :function]\n    )\n\n    message =\n      capture_log(fn ->\n        :logger.info(\"ok\", %{file: ~c\"file.erl\", line: 13, mfa: {Foo, :bar, 3}})\n      end)\n\n    assert message =~ \"module=Foo\"\n    assert message =~ \"function=bar/3\"\n    assert message =~ \"file=file.erl\"\n    assert message =~ \"line=13\"\n  after\n    Logger.Backends.Internal.configure(Logger.Backends.Console, metadata: [])\n  end\n\n  test \"ignores invalid Erlang metadata\" do\n    assert capture_log(fn -> :logger.info(\"ok\", %{time: \"bad\"}) end) =~ \"ok\"\n  after\n    Logger.Backends.Internal.configure(Logger.Backends.Console, metadata: [])\n  end\n\n  test \"uses reporting callback with Elixir inspection\" do\n    assert capture_log(fn ->\n             callback = fn %{hello: :world} -> {\"~p~n\", [:formatted]} end\n             :logger.info(%{hello: :world}, %{report_cb: callback})\n           end) =~ \"[info] :formatted\"\n  end\n\n  test \"uses Erlang log levels\" do\n    assert capture_log(fn -> :logger.emergency(~c\"ok\") end) =~ \"[emergency] ok\"\n    assert capture_log(fn -> :logger.alert(~c\"ok\") end) =~ \"[alert] ok\"\n    assert capture_log(fn -> :logger.critical(~c\"ok\") end) =~ \"[critical] ok\"\n    assert capture_log(fn -> :logger.error(~c\"ok\") end) =~ \"[error] ok\"\n    assert capture_log(fn -> :logger.warning(~c\"ok\") end) =~ \"[warning] ok\"\n    assert capture_log(fn -> :logger.notice(~c\"ok\") end) =~ \"[notice] ok\"\n    assert capture_log(fn -> :logger.info(~c\"ok\") end) =~ \"[info] ok\"\n    assert capture_log(fn -> :logger.debug(~c\"ok\") end) =~ \"[debug] ok\"\n  end\n\n  test \"include Erlang severity level information\" do\n    Logger.Backends.Internal.configure(Logger.Backends.Console, metadata: [:erl_level])\n\n    assert capture_log(fn -> :logger.emergency(~c\"ok\") end) =~ \"erl_level=emergency\"\n    assert capture_log(fn -> :logger.alert(~c\"ok\") end) =~ \"erl_level=alert\"\n    assert capture_log(fn -> :logger.critical(~c\"ok\") end) =~ \"erl_level=critical\"\n    assert capture_log(fn -> :logger.error(~c\"ok\") end) =~ \"erl_level=error\"\n    assert capture_log(fn -> :logger.warning(~c\"ok\") end) =~ \"erl_level=warning\"\n    assert capture_log(fn -> :logger.info(~c\"ok\") end) =~ \"erl_level=info\"\n    assert capture_log(fn -> :logger.debug(~c\"ok\") end) =~ \"erl_level=debug\"\n\n    [:emergency, :alert, :critical, :error, :warning, :notice, :info, :debug]\n    |> Enum.each(fn level ->\n      assert capture_log(fn -> :logger.log(level, ~c\"ok\") end) =~ \"erl_level=#{level}\"\n    end)\n  after\n    Logger.Backends.Internal.configure(Logger.Backends.Console, metadata: [])\n  end\n\n  test \"respects translator_inspect_opts for reports\" do\n    Application.put_env(:logger, :translator_inspect_opts, printable_limit: 1)\n\n    assert capture_log(fn -> :logger.error(%{foo: \"bar\"}) end) =~\n             ~S([error] [foo: \"b\" <> ...])\n  after\n    Application.put_env(:logger, :translator_inspect_opts, [])\n  end\n\n  test \"calls report_cb/1 when supplied\" do\n    report = %{foo: \"bar\"}\n\n    assert capture_log(fn -> :logger.error(report, %{report_cb: &format_report/1}) end) =~\n             ~S([error] %{foo: \"bar\"})\n\n    assert_received {:format, ^report}\n  end\n\n  test \"calls report_cb/2 when supplied\" do\n    report = %{foo: \"bar\"}\n\n    assert capture_log(fn -> :logger.error(report, %{report_cb: &format_report/2}) end) =~\n             ~S([error] %{foo: \"bar\"})\n\n    assert_received {:format, ^report, opts} when is_map(opts)\n    assert %{chars_limit: 8096, depth: :unlimited, single_line: false} = opts\n  end\n\n  test \"calls report_cb/2 when passed %{label: term(), report: term()}\" do\n    report = %{label: :foo, report: %{bar: 1, baz: 2}}\n\n    assert capture_log(fn -> :logger.error(report, %{report_cb: &format_report/1}) end)\n    assert_received {:format, ^report}\n\n    assert capture_log(fn -> :logger.error(report, %{report_cb: &format_report/2}) end)\n    assert_received {:format, ^report, _opts}\n  end\n\n  defp format_report(report) do\n    send(self(), {:format, report})\n\n    {~c\"~p\", [report]}\n  end\n\n  defp format_report(report, opts) do\n    send(self(), {:format, report, opts})\n\n    inspect(report)\n  end\nend\n"
  },
  {
    "path": "lib/logger/test/logger/backends_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Logger.BackendsTest do\n  use Logger.Case\n  require Logger\n\n  import ExUnit.CaptureIO\n\n  defmodule MyBackend do\n    @behaviour :gen_event\n\n    def init({MyBackend, pid}) when is_pid(pid) do\n      {:ok, pid}\n    end\n\n    def handle_event(event, state) do\n      send(state, {:event, event})\n      {:ok, state}\n    end\n\n    def handle_call(:error, _) do\n      raise \"oops\"\n    end\n\n    def handle_info(_msg, state) do\n      {:ok, state}\n    end\n\n    def code_change(_old_vsn, state, _extra) do\n      {:ok, state}\n    end\n\n    def terminate(_reason, _state) do\n      :ok\n    end\n  end\n\n  test \"add_backend/1 and remove_backend/1\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      assert {:ok, _pid} = Logger.Backends.Internal.add(Logger.Backends.Console)\n    end)\n\n    assert Logger.Backends.Internal.add(Logger.Backends.Console) == {:error, :already_present}\n    assert :ok = Logger.Backends.Internal.remove(Logger.Backends.Console)\n    assert Logger.Backends.Internal.remove(Logger.Backends.Console) == {:error, :not_found}\n  end\n\n  test \"add_backend/1 with {module, id}\" do\n    assert {:ok, _} = Logger.Backends.Internal.add({MyBackend, self()})\n    assert {:error, :already_present} = Logger.Backends.Internal.add({MyBackend, self()})\n    assert :ok = Logger.Backends.Internal.remove({MyBackend, self()})\n  end\n\n  test \"add_backend/1 with unknown backend\" do\n    assert {:error, {{:EXIT, {:undef, [_ | _]}}, _}} =\n             Logger.Backends.Internal.add({UnknownBackend, self()})\n  end\n\n  test \"logs or writes to stderr on failed call on async mode\" do\n    assert {:ok, _} = Logger.Backends.Internal.add({MyBackend, self()})\n\n    assert capture_log(fn ->\n             ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               :gen_event.call(Logger, {MyBackend, self()}, :error)\n               wait_for_handler(Logger, {MyBackend, self()})\n             end)\n           end) =~\n             ~r\":gen_event handler {Logger.BackendsTest.MyBackend, #PID<.*>} installed in Logger terminating\"\n\n    Logger.flush()\n  after\n    Logger.Backends.Internal.remove({MyBackend, self()})\n  end\n\n  test \"logs or writes to stderr on failed call on sync mode\" do\n    capture_io(:stderr, fn ->\n      Logger.configure(sync_threshold: 0)\n    end)\n\n    assert {:ok, _} = Logger.Backends.Internal.add({MyBackend, self()})\n\n    assert capture_log(fn ->\n             ExUnit.CaptureIO.capture_io(:stderr, fn ->\n               :gen_event.call(Logger, {MyBackend, self()}, :error)\n               wait_for_handler(Logger, {MyBackend, self()})\n             end)\n           end) =~\n             ~r\":gen_event handler {Logger.BackendsTest.MyBackend, #PID<.*>} installed in Logger terminating\"\n\n    Logger.flush()\n  after\n    Logger.configure(sync_threshold: 20)\n    Logger.Backends.Internal.remove({MyBackend, :hello})\n  end\n\n  test \"logs when discarding messages\" do\n    capture_io(:stderr, fn ->\n      assert :ok = Logger.configure(discard_threshold: 5)\n    end)\n\n    Logger.Backends.Internal.add({MyBackend, self()})\n\n    capture_log(fn ->\n      :sys.suspend(Logger)\n      for _ <- 1..10, do: Logger.warning(\"warning!\")\n      :sys.resume(Logger)\n      Logger.flush()\n      send(Logger, {Logger.Backends.Config, :update_counter})\n    end)\n\n    assert_receive {:event,\n                    {:warning, _,\n                     {Logger, \"Attempted to log 0 messages, which is below :discard_threshold\",\n                      _time, _metadata}}}\n  after\n    :sys.resume(Logger)\n    Logger.Backends.Internal.remove({MyBackend, self()})\n    assert :ok = Logger.configure(discard_threshold: 500)\n  end\n\n  test \"restarts Logger.Backends.Config on Logger exits\" do\n    Logger.Backends.Internal.configure([])\n\n    capture_log(fn ->\n      Process.whereis(Logger) |> Process.exit(:kill)\n      wait_for_logger()\n      wait_for_handler(Logger, Logger.Backends.Config)\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/logger/test/logger/formatter_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.FormatterTest do\n  use Logger.Case, async: true\n\n  doctest Logger.Formatter\n  import Logger.Formatter\n\n  test \"prune/1\" do\n    assert prune(1) == \"�\"\n    assert prune(<<\"hí\", 233>>) == \"hí�\"\n    assert prune([\"hi\" | 233]) == [\"hi\" | \"�\"]\n    assert prune([233 | \"hi\"]) == [233 | \"hi\"]\n    assert prune([[] | []]) == [[]]\n  end\n\n  test \"truncate/2\" do\n    # ASCII binaries\n    assert truncate(\"foo\", 4) == \"foo\"\n    assert truncate(\"foo\", 3) == \"foo\"\n    assert truncate(\"foo\", 2) == [\"fo\", \" (truncated)\"]\n\n    # UTF-8 binaries\n    assert truncate(\"olá\", 2) == [\"ol\", \" (truncated)\"]\n    assert truncate(\"olá\", 3) == [\"ol\", \" (truncated)\"]\n    assert truncate(\"olá\", 4) == \"olá\"\n    assert truncate(\"ááááá:\", 10) == [\"ááááá\", \" (truncated)\"]\n    assert truncate(\"áááááá:\", 10) == [\"ááááá\", \" (truncated)\"]\n    assert truncate(\"𠜎𠜱𠝹𠱓\", 15) == [\"𠜎𠜱𠝹\", \" (truncated)\"]\n\n    # Charlists\n    assert truncate(~c\"olá\", 2) == [~c\"olá\", \" (truncated)\"]\n    assert truncate(~c\"olá\", 3) == [~c\"olá\", \" (truncated)\"]\n    assert truncate(~c\"olá\", 4) == ~c\"olá\"\n\n    # Chardata\n    assert truncate(~c\"ol\" ++ \"á\", 2) == [~c\"ol\" ++ \"\", \" (truncated)\"]\n    assert truncate(~c\"ol\" ++ \"á\", 3) == [~c\"ol\" ++ \"\", \" (truncated)\"]\n    assert truncate(~c\"ol\" ++ \"á\", 4) == ~c\"ol\" ++ \"á\"\n\n    # :infinity\n    long_string = String.duplicate(\"foo\", 10_000)\n    assert truncate(long_string, :infinity) == long_string\n  end\n\n  test \"format_date/1\" do\n    date = {2015, 1, 30}\n    assert format_date(date) == [\"2015\", ?-, [?0, \"1\"], ?-, \"30\"]\n  end\n\n  test \"format_time/1\" do\n    time = {12, 30, 10, 1}\n    assert format_time(time) == [\"12\", ?:, \"30\", ?:, \"10\", ?., [?0, ?0, \"1\"]]\n\n    time = {12, 30, 10, 10}\n    assert format_time(time) == [\"12\", ?:, \"30\", ?:, \"10\", ?., [?0, \"10\"]]\n  end\n\n  describe \"log\" do\n    test \"handles :module and :function\" do\n      {_, formatter} =\n        new(\n          format: \"\\n$time $metadata[$level] $message\\n\",\n          metadata: [:module, :function, :mfa],\n          colors: [enabled: false]\n        )\n\n      assert %{\n               level: :warning,\n               msg: {:string, \"foo\"},\n               meta: %{\n                 mfa: {Logger.Formatter, :compile, 1}\n               }\n             }\n             |> format(formatter)\n             |> IO.chardata_to_string() =~\n               \"module=Logger.Formatter function=compile/1 mfa=Logger.Formatter.compile/1\"\n    end\n\n    test \"handles invalid :time in metadata\" do\n      {_, formatter} =\n        new(\n          format: \"\\n$time $message\\n\",\n          colors: [enabled: false]\n        )\n\n      assert %{\n               level: :warning,\n               msg: {:string, \"message\"},\n               meta: %{\n                 mfa: {Logger.Formatter, :compile, 1},\n                 time: \"invalid\"\n               }\n             }\n             |> format(formatter)\n             |> IO.chardata_to_string() =~ ~r\"\\d\\d\\d message\"\n    end\n\n    test \"handles colorize with newlines\" do\n      {_, formatter} =\n        new(\n          format: \"$message\",\n          colors: [enabled: true]\n        )\n\n      assert %{level: :warning, msg: {:string, \"\"}, meta: %{}}\n             |> format(formatter)\n             |> IO.chardata_to_string() == \"\\e[33m\\e[0m\"\n\n      assert %{level: :warning, msg: {:string, \"s\"}, meta: %{}}\n             |> format(formatter)\n             |> IO.chardata_to_string() == \"\\e[33ms\\e[0m\"\n\n      assert %{level: :warning, msg: {:string, \"message\"}, meta: %{}}\n             |> format(formatter)\n             |> IO.chardata_to_string() == \"\\e[33mmessage\\e[0m\"\n\n      assert %{level: :warning, msg: {:string, \"message\\n\"}, meta: %{}}\n             |> format(formatter)\n             |> IO.chardata_to_string() == \"\\e[33mmessage\\e[0m\\n\"\n\n      assert %{level: :warning, msg: {:string, \"message\\r\\n\"}, meta: %{}}\n             |> format(formatter)\n             |> IO.chardata_to_string() == \"\\e[33mmessage\\e[0m\\r\\n\"\n\n      assert %{level: :warning, msg: {:string, [?é, [\"message\", [?\\n]]]}, meta: %{}}\n             |> format(formatter)\n             |> IO.chardata_to_string() == \"\\e[33mémessage\\e[0m\\n\"\n\n      assert %{level: :warning, msg: {:string, [?é, \"message\", ?\\r, ?\\n]}, meta: %{}}\n             |> format(formatter)\n             |> IO.chardata_to_string() == \"\\e[33mémessage\\e[0m\\r\\n\"\n\n      assert %{level: :warning, msg: {:string, [?é, \"message\" | \"\\r\\n\"]}, meta: %{}}\n             |> format(formatter)\n             |> IO.chardata_to_string() == \"\\e[33mémessage\\e[0m\\r\\n\"\n    end\n  end\n\n  describe \"compile + format\" do\n    defmodule CompileMod do\n      def format(_level, _msg, _ts, _md) do\n        true\n      end\n    end\n\n    test \"compile with nil\" do\n      assert compile(nil) ==\n               [\"\\n\", :time, \" \", :metadata, \"[\", :level, \"] \", :message, \"\\n\"]\n    end\n\n    test \"compile with string\" do\n      assert compile(\"$level $time $date $metadata $message $node\") ==\n               Enum.intersperse([:level, :time, :date, :metadata, :message, :node], \" \")\n\n      assert_raise ArgumentError, \"$bad is an invalid format pattern\", fn ->\n        compile(\"$bad $good\")\n      end\n    end\n\n    test \"compile with {mod, fun}\" do\n      assert compile({CompileMod, :format}) == {CompileMod, :format}\n    end\n\n    test \"format with {mod, fun}\" do\n      assert format({CompileMod, :format}, nil, nil, nil, nil) == true\n    end\n\n    test \"format with format string\" do\n      compiled = compile(\"[$level] $message\")\n      assert format(compiled, :error, \"hello\", nil, []) == [\"[\", \"error\", \"] \", \"hello\"]\n\n      compiled = compile(\"$node\")\n      assert format(compiled, :error, nil, nil, []) == [Atom.to_string(node())]\n\n      compiled = compile(\"$metadata\")\n      format = format(compiled, :error, nil, nil, meta: :data)\n      assert IO.chardata_to_string(format) == \"meta=data \"\n\n      pid = :erlang.list_to_pid(~c\"<0.123.0>\")\n      format = format(compiled, :error, nil, nil, meta: :data, pid: pid)\n      assert IO.chardata_to_string(format) == \"meta=data pid=<0.123.0> \"\n\n      # Hack to get the same predictable reference for every test run.\n      ref =\n        :erlang.binary_to_term(\n          <<131, 114, 0, 3, 100, 0, 13, 110, 111, 110, 111, 100, 101, 64, 110, 111>> <>\n            <<104, 111, 115, 116, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0>>\n        )\n\n      # Ensure the deserialization worked correctly\n      assert \"#Reference<0.0.0.80>\" == inspect(ref)\n\n      assert IO.chardata_to_string(format(compiled, :error, nil, nil, meta: :data, ref: ref)) ==\n               \"meta=data ref=<0.0.0.80> \"\n\n      port = :erlang.list_to_port(~c\"#Port<0.1234>\")\n      format = format(compiled, :error, nil, nil, meta: :data, port: port)\n      assert IO.chardata_to_string(format) == \"meta=data port=<0.1234> \"\n\n      # Also works with to_string\n      format = format(compiled, :error, nil, nil, date: ~D[2020-10-01])\n      assert IO.chardata_to_string(format) == \"date=2020-10-01 \"\n\n      # And with no metadata\n      assert IO.chardata_to_string(format(compiled, :error, nil, nil, [])) == \"\"\n\n      timestamp = {{2014, 12, 30}, {12, 6, 30, 100}}\n      compiled = compile(\"$date $time\")\n\n      assert IO.chardata_to_string(format(compiled, :error, nil, timestamp, [])) ==\n               \"2014-12-30 12:06:30.100\"\n    end\n\n    test \"format discards unknown formats\" do\n      compiled = compile(\"$metadata $message\")\n      metadata = [ancestors: [self()], crash_reason: {:some, :tuple}, foo: :bar]\n\n      assert format(compiled, :error, \"hello\", nil, metadata) ==\n               [[\"foo\", 61, \"bar\", 32], \" \", \"hello\"]\n    end\n  end\nend\n"
  },
  {
    "path": "lib/logger/test/logger/translator_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.TranslatorTest do\n  use Logger.Case\n\n  defmodule MyGenServer do\n    use GenServer\n\n    def init(args) do\n      {:ok, args}\n    end\n\n    def handle_cast(:error, _) do\n      raise \"oops\"\n    end\n\n    def handle_call(:exit, _, _) do\n      exit(:oops)\n    end\n\n    def handle_call(:error, _, _) do\n      raise \"oops\"\n    end\n\n    def handle_call({:execute, fun}, _, state) do\n      fun.()\n      {:reply, :ok, state}\n    end\n\n    def handle_call(:error_on_down, {pid, _}, _) do\n      mon = Process.monitor(pid)\n      assert_receive {:DOWN, ^mon, _, _, _}\n      raise \"oops\"\n    end\n  end\n\n  defmodule MyGenEvent do\n    @behaviour :gen_event\n\n    def init(args) do\n      {:ok, args}\n    end\n\n    def handle_event(_event, state) do\n      {:ok, state}\n    end\n\n    def handle_call(:error, _) do\n      raise \"oops\"\n    end\n\n    def handle_call({:execute, fun}, state) do\n      fun.()\n      {:ok, :ok, state}\n    end\n\n    def handle_info(_msg, state) do\n      {:ok, state}\n    end\n\n    def code_change(_old_vsn, state, _extra) do\n      {:ok, state}\n    end\n\n    def terminate(_reason, _state) do\n      :ok\n    end\n  end\n\n  defmodule MyGenStatem do\n    @behaviour :gen_statem\n\n    @impl true\n    def callback_mode, do: :state_functions\n\n    @impl true\n    def init(args) do\n      {:ok, :started, args}\n    end\n\n    def started(:cast, :error, _) do\n      raise \"oops\"\n    end\n\n    def started({:call, _}, :exit, _) do\n      exit(:oops)\n    end\n\n    def started({:call, _}, :error, _) do\n      raise \"oops\"\n    end\n\n    def started({:call, from}, {:execute, fun}, data) do\n      fun.()\n      {:keep_state_and_data, {:reply, from, {:started, data}}}\n    end\n\n    def started({:call, {pid, _}}, :error_on_down, _) do\n      mon = Process.monitor(pid)\n      assert_receive {:DOWN, ^mon, _, _, _}\n      raise \"oops\"\n    end\n  end\n\n  defmodule MyGenStatemHandleEvent do\n    @behaviour :gen_statem\n\n    @impl true\n    def callback_mode, do: :handle_event_function\n\n    @impl true\n    def init(state) do\n      {:ok, :no_state, state}\n    end\n\n    @impl true\n    def handle_event({:call, _}, :error, :no_state, _data) do\n      raise \"oops\"\n    end\n\n    @impl :gen_statem\n    def format_status(_opts, [_pdict, _, state]) do\n      state\n    end\n  end\n\n  defmodule MyBridge do\n    @behaviour :supervisor_bridge\n\n    def init(reason) do\n      {:ok, pid} = Task.start_link(Kernel, :exit, [reason])\n      {:ok, pid, pid}\n    end\n\n    def terminate(_reason, pid) do\n      Process.exit(pid, :shutdown)\n    end\n  end\n\n  setup_all do\n    config = Application.get_all_env(:logger)\n\n    config\n    |> Keyword.put(:handle_sasl_reports, true)\n    |> put_logger_config()\n\n    on_exit(fn -> restore_logger_config(config) end)\n  end\n\n  setup context do\n    test_overrides = Map.get(context, :logger_config, [])\n    existing_config = Application.get_all_env(:logger)\n\n    case Keyword.merge(existing_config, test_overrides) do\n      ^existing_config ->\n        :ok\n\n      new_config ->\n        put_logger_config(new_config)\n        on_exit(fn -> restore_logger_config(existing_config) end)\n    end\n  end\n\n  setup do\n    fun = fn event, parent ->\n      send(parent, {:event, event.msg, event.meta})\n      :ignore\n    end\n\n    :logger.add_handler_filter(:default, :forwarder, {fun, self()})\n    on_exit(fn -> :logger.remove_handler_filter(:default, :forwarder) end)\n  end\n\n  test \"translates GenServer crashes\" do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok)\n\n    assert capture_log(:info, fn ->\n             catch_exit(GenServer.call(pid, :error))\n           end) =~ \"\"\"\n           [error] GenServer #{inspect(pid)} terminating\n           ** (RuntimeError) oops\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:gen_server, :terminate}}}, gen_server_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = gen_server_metadata[:crash_reason]\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n\n    refute Map.has_key?(gen_server_metadata, :initial_call)\n    assert process_metadata[:initial_call] == {Logger.TranslatorTest.MyGenServer, :init, 1}\n\n    refute Map.has_key?(gen_server_metadata, :registered_name)\n    refute Map.has_key?(process_metadata, :registered_name)\n  end\n\n  test \"translates GenServer crashes with local name\", config do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok, name: config.test)\n    capture_log(:info, fn -> catch_exit(GenServer.call(pid, :error)) end)\n\n    assert_receive {:event, {:report, %{label: {:gen_server, :terminate}}}, gen_server_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert gen_server_metadata[:registered_name] == config.test\n    assert process_metadata[:registered_name] == config.test\n  end\n\n  test \"translates GenServer crashes with global name\", config do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok, name: {:global, config.test})\n    capture_log(:info, fn -> catch_exit(GenServer.call(pid, :error)) end)\n\n    assert_receive {:event, {:report, %{label: {:gen_server, :terminate}}}, gen_server_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert gen_server_metadata[:registered_name] == config.test\n    refute Map.has_key?(process_metadata, :registered_name)\n  end\n\n  test \"translates GenServer crashes with process label\" do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok)\n    :ok = GenServer.call(pid, {:execute, fn -> Process.set_label({:any, \"term\"}) end})\n\n    assert capture_log(:info, fn -> catch_exit(GenServer.call(pid, :error)) end) =~ ~r\"\"\"\n           \\[error\\] GenServer #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Process Label: {:any, \\\"term\\\"}\n           Last message \\(from #PID<\\d+\\.\\d+\\.\\d+>\\): :error\\\n           \"\"\"s\n  end\n\n  test \"translates GenServer crashes with custom inspect options\" do\n    {:ok, pid} = GenServer.start(MyGenServer, List.duplicate(:ok, 1000))\n    Application.put_env(:logger, :translator_inspect_opts, limit: 3)\n\n    assert capture_log(:debug, fn ->\n             catch_exit(GenServer.call(pid, :error))\n           end) =~ \"\"\"\n           [:ok, :ok, :ok, ...]\n           \"\"\"\n  after\n    Application.put_env(:logger, :translator_inspect_opts, [])\n  end\n\n  test \"translates GenServer crashes on debug\" do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok)\n\n    assert capture_log(:debug, fn ->\n             catch_exit(GenServer.call(pid, :error))\n           end) =~ ~r\"\"\"\n           \\[error\\] GenServer #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Last message \\(from #PID<\\d+\\.\\d+\\.\\d+>\\): :error\n           State: :ok\n           Client #PID<\\d+\\.\\d+\\.\\d+> is alive\n           .*\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:gen_server, :terminate}}}, gen_server_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = gen_server_metadata[:crash_reason]\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n  end\n\n  test \"translates GenServer crashes with named client on debug\" do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok)\n\n    assert capture_log(:debug, fn ->\n             Process.register(self(), :named_client)\n             catch_exit(GenServer.call(pid, :error))\n           end) =~ ~r\"\"\"\n           \\[error\\] GenServer #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Last message \\(from :named_client\\): :error\n           State: :ok\n           Client :named_client is alive\n           .*\n           \"\"\"s\n  end\n\n  test \"translates GenServer crashes with dead client on debug\" do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok)\n\n    assert capture_log(:debug, fn ->\n             mon = Process.monitor(pid)\n\n             spawn_link(fn ->\n               catch_exit(GenServer.call(pid, :error_on_down, 0))\n             end)\n\n             assert_receive {:DOWN, ^mon, _, _, _}\n           end) =~ ~r\"\"\"\n           \\[error\\] GenServer #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Last message \\(from #PID<\\d+\\.\\d+\\.\\d+>\\): :error_on_down\n           State: :ok\n           Client #PID<\\d+\\.\\d+\\.\\d+> is dead\\\n           \"\"\"s\n  end\n\n  test \"translates GenServer crashes with no client\" do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok)\n\n    assert capture_log(:debug, fn ->\n             mon = Process.monitor(pid)\n             GenServer.cast(pid, :error)\n             assert_receive {:DOWN, ^mon, _, _, _}\n           end) =~ ~r\"\"\"\n           \\[error\\] GenServer #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Last message: {:\"\\$gen_cast\", :error}\n           State: :ok\\\n           \"\"\"s\n  end\n\n  test \"translates GenServer crashes with no client on debug\" do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok)\n\n    refute capture_log(:debug, fn ->\n             mon = Process.monitor(pid)\n             GenServer.cast(pid, :error)\n             assert_receive {:DOWN, ^mon, _, _, _}\n           end) =~ \"Client\"\n\n    assert_receive {:event, {:report, %{label: {:gen_server, :terminate}}}, _gen_server_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, _process_metadata}\n  end\n\n  test \"translates :gen_event crashes\" do\n    {:ok, pid} = :gen_event.start()\n    :ok = :gen_event.add_handler(pid, MyGenEvent, :ok)\n\n    assert capture_log(:info, fn ->\n             :gen_event.call(pid, MyGenEvent, :error)\n           end) =~ \"\"\"\n           [error] :gen_event handler Logger.TranslatorTest.MyGenEvent \\\n           installed in #{inspect(pid)} terminating\n           ** (RuntimeError) oops\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:gen_event, :terminate}}}, metadata}\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = metadata[:crash_reason]\n    refute Map.has_key?(metadata, :initial_call)\n    refute Map.has_key?(metadata, :registered_name)\n  end\n\n  test \"translates :gen_event crashes with name\", config do\n    {:ok, pid} = :gen_event.start({:local, config.test})\n    :ok = :gen_event.add_handler(pid, MyGenEvent, :ok)\n\n    assert capture_log(:info, fn ->\n             :gen_event.call(pid, MyGenEvent, :error)\n           end) =~ \"\"\"\n           [error] :gen_event handler Logger.TranslatorTest.MyGenEvent \\\n           installed in #{inspect(config.test)} terminating\n           ** (RuntimeError) oops\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:gen_event, :terminate}}}, metadata}\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = metadata[:crash_reason]\n    assert metadata[:registered_name] == config.test\n  end\n\n  test \"translates :gen_event crashes with process label\" do\n    {:ok, pid} = :gen_event.start()\n    :ok = :gen_event.add_handler(pid, MyGenEvent, :ok)\n\n    fun = fn -> Process.set_label({:any, \"term\"}) end\n    :ok = :gen_event.call(pid, MyGenEvent, {:execute, fun})\n\n    assert capture_log(:info, fn ->\n             :gen_event.call(pid, MyGenEvent, :error)\n           end) =~ ~r\"\"\"\n           \\[error\\] :gen_event handler Logger.TranslatorTest.MyGenEvent installed in #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Process Label: {:any, \"term\"}\n           Last message: :error\\\n           \"\"\"s\n  end\n\n  test \"translates :gen_event crashes on debug\" do\n    {:ok, pid} = :gen_event.start()\n    :ok = :gen_event.add_handler(pid, MyGenEvent, :ok)\n\n    assert capture_log(:debug, fn ->\n             :gen_event.call(pid, MyGenEvent, :error)\n           end) =~ ~r\"\"\"\n           \\[error\\] :gen_event handler Logger.TranslatorTest.MyGenEvent installed in #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Last message: :error\n           State: :ok\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:gen_event, :terminate}}}, metadata}\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = metadata[:crash_reason]\n  end\n\n  test \"translates :gen_statem crashes\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatem, :ok, [])\n\n    assert capture_log(:info, fn ->\n             catch_exit(:gen_statem.call(pid, :error))\n           end) =~ \"\"\"\n           [error] :gen_statem #{inspect(pid)} terminating\n           ** (RuntimeError) oops\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:gen_statem, :terminate}}}, gen_statem_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = gen_statem_metadata[:crash_reason]\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n\n    refute Map.has_key?(gen_statem_metadata, :initial_call)\n    assert process_metadata[:initial_call] == {MyGenStatem, :init, 1}\n\n    refute Map.has_key?(gen_statem_metadata, :registered_name)\n    refute Map.has_key?(process_metadata, :registered_name)\n  end\n\n  test \"translates :gen_statem crashes with local name\", config do\n    {:ok, pid} = :gen_statem.start({:local, config.test}, MyGenStatem, :ok, [])\n    capture_log(:info, fn -> catch_exit(:gen_statem.call(pid, :error)) end)\n\n    assert_receive {:event, {:report, %{label: {:gen_statem, :terminate}}}, gen_statem_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert gen_statem_metadata[:registered_name] == config.test\n    assert process_metadata[:registered_name] == config.test\n  end\n\n  test \"translates :gen_statem crashes with global name\", config do\n    {:ok, pid} = :gen_statem.start({:global, config.test}, MyGenStatem, :ok, [])\n    capture_log(:info, fn -> catch_exit(:gen_statem.call(pid, :error)) end)\n\n    assert_receive {:event, {:report, %{label: {:gen_statem, :terminate}}}, gen_statem_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert gen_statem_metadata[:registered_name] == config.test\n    refute Map.has_key?(process_metadata, :registered_name)\n  end\n\n  test \"translates :gen_statem crashes with process label\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatem, :ok, [])\n\n    {:started, :ok} =\n      :gen_statem.call(pid, {:execute, fn -> Process.set_label({:any, \"term\"}) end})\n\n    assert capture_log(:info, fn -> catch_exit(:gen_statem.call(pid, :error)) end) =~ ~r\"\"\"\n           \\[error\\] :gen_statem #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Process Label: {:any, \\\"term\\\"}\n           Queue: .*\n           Postponed: \\[\\]\\\n           \"\"\"s\n  end\n\n  test \"translates :gen_statem crashes with custom inspect options\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatem, List.duplicate(:ok, 1000), [])\n    Application.put_env(:logger, :translator_inspect_opts, limit: 3)\n\n    assert capture_log(:debug, fn ->\n             catch_exit(:gen_statem.call(pid, :error))\n           end) =~ \"\"\"\n           State: {:started, [:ok, ...]}\n           \"\"\"\n  after\n    Application.put_env(:logger, :translator_inspect_opts, [])\n  end\n\n  test \"translates :gen_statem crashes on debug\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatem, :ok, [])\n\n    assert capture_log(:debug, fn ->\n             catch_exit(GenServer.call(pid, :error))\n           end) =~ ~r\"\"\"\n           \\[error\\] :gen_statem #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Queue: .*\n           Postponed: \\[\\]\n           State: {:started, :ok}\n           Callback mode: :state_functions, state_enter: false\n           Client #PID<\\d+\\.\\d+\\.\\d+> is alive\n           .*\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:gen_statem, :terminate}}}, gen_statem_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = gen_statem_metadata[:crash_reason]\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n  end\n\n  test \"translates :gen_statem crashed with named client on debug\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatem, :ok, [])\n\n    assert capture_log(:debug, fn ->\n             Process.register(self(), :named_client)\n             catch_exit(:gen_statem.call(pid, :error))\n           end) =~ ~r\"\"\"\n           \\[error\\] :gen_statem #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Queue: .*\n           Postponed: \\[\\]\n           State: {:started, :ok}\n           Callback mode: :state_functions, state_enter: false\n           Client :named_client is alive\n           .*\n           \"\"\"s\n  end\n\n  test \"translates :gen_statem crashes with dead client on debug\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatem, :ok, [])\n\n    assert capture_log(:debug, fn ->\n             mon = Process.monitor(pid)\n\n             spawn_link(fn ->\n               catch_exit(:gen_statem.call(pid, :error_on_down, 0))\n             end)\n\n             assert_receive {:DOWN, ^mon, _, _, _}\n           end) =~ ~r\"\"\"\n           \\[error\\] :gen_statem #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Queue: .*\n           Postponed: \\[\\]\n           State: {:started, :ok}\n           Callback mode: :state_functions, state_enter: false\n           Client #PID<\\d+\\.\\d+\\.\\d+> is dead\\\n           \"\"\"s\n  end\n\n  test \"translates :gen_statem crashes with no client\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatem, :ok, [])\n\n    assert capture_log(:debug, fn ->\n             mon = Process.monitor(pid)\n             :gen_statem.cast(pid, :error)\n             assert_receive {:DOWN, ^mon, _, _, _}\n           end) =~ ~r\"\"\"\n           \\[error\\] :gen_statem #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Queue: .*\n           Postponed: \\[\\]\n           State: {:started, :ok}\n           Callback mode: :state_functions, state_enter: false\\\n           \"\"\"s\n  end\n\n  test \"translates :gen_statem crashes with no client on debug\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatem, :ok, [])\n\n    refute capture_log(:debug, fn ->\n             mon = Process.monitor(pid)\n             :gen_statem.cast(pid, :error)\n             assert_receive {:DOWN, ^mon, _, _, _}\n           end) =~ \"Client\"\n\n    assert_receive {:event, {:report, %{label: {:gen_statem, :terminate}}}, _gen_statem_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, _process_metadata}\n  end\n\n  test \"translates :gen_statem crashes when callback_mode is :handle_event_function\" do\n    {:ok, pid} = :gen_statem.start(MyGenStatemHandleEvent, :ok, [])\n\n    assert capture_log(:debug, fn ->\n             catch_exit(:gen_statem.call(pid, :error))\n           end) =~ ~r\"\"\"\n           \\[error\\] :gen_statem #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Queue: .*\n           Postponed: \\[\\]\n           State: :ok\n           Callback mode: .*, state_enter: false\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:gen_statem, :terminate}}}, gen_statem_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = gen_statem_metadata[:crash_reason]\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n\n    refute Map.has_key?(gen_statem_metadata, :initial_call)\n    assert process_metadata[:initial_call] == {MyGenStatemHandleEvent, :init, 1}\n\n    refute Map.has_key?(gen_statem_metadata, :registered_name)\n    refute Map.has_key?(process_metadata, :registered_name)\n  end\n\n  test \"translates Task crashes\" do\n    {:ok, pid} = Task.start_link(__MODULE__, :task, [self()])\n    parent = self()\n\n    assert capture_log(fn ->\n             ref = Process.monitor(pid)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Task #{inspect(pid)} started from #{inspect(self())} terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Function: &Logger.TranslatorTest.task\\/1\n               Args: \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {Task.Supervisor, :terminating}}}, task_metadata}\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = task_metadata[:crash_reason]\n    assert [parent] == task_metadata[:callers]\n    refute Map.has_key?(task_metadata, :initial_call)\n  end\n\n  test \"translates Task undef module crash\" do\n    parent = self()\n\n    assert capture_log(fn ->\n             {:ok, pid} = Task.start(:module_does_not_exist, :undef, [])\n             ref = Process.monitor(pid)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Task #PID<\\d+\\.\\d+\\.\\d+> started from #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(UndefinedFunctionError\\) function :module_does_not_exist.undef/0 is undefined \\(module :module_does_not_exist is not available\\)\n           .*\n           Function: &:module_does_not_exist.undef/0\n               Args: \\[\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {Task.Supervisor, :terminating}}}, task_metadata}\n    assert [parent] == task_metadata[:callers]\n    assert {%UndefinedFunctionError{function: :undef}, [_ | _]} = task_metadata[:crash_reason]\n  end\n\n  test \"translates Task undef function crash\" do\n    parent = self()\n\n    assert capture_log(fn ->\n             {:ok, pid} = Task.start(__MODULE__, :undef, [])\n             ref = Process.monitor(pid)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Task #PID<\\d+\\.\\d+\\.\\d+> started from #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(UndefinedFunctionError\\) function Logger.TranslatorTest.undef/0 is undefined or private\n           .*\n           Function: &Logger.TranslatorTest.undef/0\n               Args: \\[\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {Task.Supervisor, :terminating}}}, task_metadata}\n    assert [parent] == task_metadata[:callers]\n    assert {%UndefinedFunctionError{function: :undef}, [_ | _]} = task_metadata[:crash_reason]\n  end\n\n  test \"translates Task raising ErlangError\" do\n    parent = self()\n\n    assert capture_log(fn ->\n             exception =\n               try do\n                 :erlang.error(:foo)\n               rescue\n                 x ->\n                   x\n               end\n\n             {:ok, pid} = Task.start(:erlang, :error, [exception])\n             ref = Process.monitor(pid)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Task #PID<\\d+\\.\\d+\\.\\d+> started from #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(ErlangError\\) Erlang error: :foo\n           .*\n           Function: &:erlang\\.error/1\n               Args: \\[%ErlangError{.*}\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {Task.Supervisor, :terminating}}}, task_metadata}\n    assert [parent] == task_metadata[:callers]\n    assert {%ErlangError{original: :foo}, [_ | _]} = task_metadata[:crash_reason]\n  end\n\n  test \"translates Task raising Erlang badarg error\" do\n    parent = self()\n\n    assert capture_log(fn ->\n             {:ok, pid} = Task.start(:erlang, :error, [:badarg])\n             ref = Process.monitor(pid)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Task #PID<\\d+\\.\\d+\\.\\d+> started from #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(ArgumentError\\) argument error\n           .*\n           Function: &:erlang\\.error/1\n               Args: \\[:badarg\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {Task.Supervisor, :terminating}}}, task_metadata}\n    assert [parent] == task_metadata[:callers]\n    assert {%ArgumentError{message: \"argument error\"}, [_ | _]} = task_metadata[:crash_reason]\n  end\n\n  test \"translates Task exiting abnormally\" do\n    parent = self()\n\n    assert capture_log(fn ->\n             {:ok, pid} = Task.start(:erlang, :exit, [:abnormal])\n             ref = Process.monitor(pid)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Task #PID<\\d+\\.\\d+\\.\\d+> started from #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(stop\\) :abnormal\n           .*\n           Function: &:erlang\\.exit/1\n               Args: \\[:abnormal\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {Task.Supervisor, :terminating}}}, task_metadata}\n    assert [parent] == task_metadata[:callers]\n    assert {:abnormal, [_ | _]} = task_metadata[:crash_reason]\n  end\n\n  test \"translates Task crashes with process label\" do\n    fun = fn ->\n      Process.set_label({:any, \"term\"})\n      raise \"oops\"\n    end\n\n    {:ok, pid} = Task.start_link(__MODULE__, :task, [self(), fun])\n\n    assert capture_log(fn ->\n             ref = Process.monitor(pid)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~\n             ~r\"\"\"\n             \\[error\\] Task #{inspect(pid)} started from #{inspect(self())} terminating\n             \\*\\* \\(RuntimeError\\) oops\n             .*\n             Process Label: {:any, \\\"term\\\"}\n             Function: &Logger.TranslatorTest.task\\/2\n                 Args: \\[#PID<\\d+\\.\\d+\\.\\d+>\\, .*]\\\n             \"\"\"s\n  end\n\n  test \"translates application start\" do\n    assert capture_log(fn ->\n             :ok = Application.start(:eex)\n             Application.stop(:eex)\n           end) =~ \"Application eex started at #{inspect(node())}\"\n  end\n\n  test \"translates application stop\" do\n    assert capture_log(fn ->\n             :ok = Application.start(:eex)\n             Application.stop(:eex)\n           end) =~ \"Application eex exited: :stopped\"\n  end\n\n  test \"translates bare process crashes\" do\n    assert capture_log(:info, fn ->\n             {_, ref} = spawn_monitor(fn -> raise \"oops\" end)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n             # Even though the monitor has been received the emulator may not have\n             # sent the message to the error logger\n             Process.sleep(200)\n           end) =~ ~r\"\"\"\n           \\[error\\] Process #PID<\\d+\\.\\d+\\.\\d+>\\ raised an exception\n           \\*\\* \\(RuntimeError\\) oops\n           \"\"\"\n\n    assert_receive {:event, {:string, [\"Process \" | _]}, process_metadata}\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n  end\n\n  test \"translates :proc_lib crashes\" do\n    fun = fn ->\n      Logger.metadata(foo: :bar)\n      raise \"oops\"\n    end\n\n    pid = :proc_lib.spawn_link(__MODULE__, :task, [self(), fun])\n\n    assert capture_log(:info, fn ->\n             ref = Process.monitor(pid)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Process #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Initial Call: Logger.TranslatorTest.task/2\n           Ancestors: \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert is_pid(process_metadata[:pid])\n    assert is_list(process_metadata[:ancestors])\n    assert process_metadata[:foo] == :bar\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n  end\n\n  test \"skips :proc_lib crashes with disabled metadata\" do\n    fun = fn ->\n      Logger.put_process_level(self(), :none)\n      raise \"oops\"\n    end\n\n    pid = :proc_lib.spawn_link(__MODULE__, :task, [self(), fun])\n\n    assert capture_log(:info, fn ->\n             ref = Process.monitor(pid)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) == \"\"\n  end\n\n  test \"translates :proc_lib crashes with name\" do\n    fun = fn ->\n      Process.register(self(), __MODULE__)\n      raise \"oops\"\n    end\n\n    pid = :proc_lib.spawn_link(__MODULE__, :task, [self(), fun])\n\n    assert capture_log(:info, fn ->\n             ref = Process.monitor(pid)\n             send(pid, :message)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Process Logger.TranslatorTest \\(#PID<\\d+\\.\\d+\\.\\d+>\\) terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Initial Call: Logger.TranslatorTest.task/2\n           Ancestors: \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n  end\n\n  test \"translates :proc_lib crashes with process label\" do\n    fun = fn ->\n      Process.set_label({:any, \"term\"})\n      raise \"oops\"\n    end\n\n    pid = :proc_lib.spawn_link(__MODULE__, :task, [self(), fun])\n\n    assert capture_log(:info, fn ->\n             ref = Process.monitor(pid)\n             send(pid, :message)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Process #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Initial Call: Logger.TranslatorTest.task/2\n           Process Label: {:any, \\\"term\\\"}\n           Ancestors: \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n  end\n\n  test \"translates :proc_lib crashes without initial call\" do\n    fun = fn ->\n      Process.delete(:\"$initial_call\")\n      raise \"oops\"\n    end\n\n    pid = :proc_lib.spawn_link(__MODULE__, :task, [self(), fun])\n\n    assert capture_log(:info, fn ->\n             ref = Process.monitor(pid)\n             send(pid, :message)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Process #PID<\\d+\\.\\d+\\.\\d+> terminating\n           \\*\\* \\(RuntimeError\\) oops\n           .*\n           Ancestors: \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n  end\n\n  test \"translates :proc_lib crashes with neighbour\" do\n    pid = :proc_lib.spawn_link(__MODULE__, :sub_task, [self()])\n\n    assert capture_log(:info, fn ->\n             ref = Process.monitor(pid)\n             send(pid, :message)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           Ancestors: \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\n           Neighbours:\n               #PID<\\d+\\.\\d+\\.\\d+>\n                   Initial Call: Logger.TranslatorTest.sleep/1\n                   Current Call: Logger.TranslatorTest.sleep/1\n                   Ancestors: \\[#PID<\\d+\\.\\d+\\.\\d+>, #PID<\\d+\\.\\d+\\.\\d+>\\]\\\n           \"\"\"\n  end\n\n  test \"translates :proc_lib crashes with neighbour with name\" do\n    fun = fn pid2 ->\n      Process.register(pid2, __MODULE__)\n      raise \"oops\"\n    end\n\n    pid = :proc_lib.spawn_link(__MODULE__, :sub_task, [self(), fun])\n\n    assert capture_log(:info, fn ->\n             ref = Process.monitor(pid)\n             send(pid, :message)\n             send(pid, :go)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           Ancestors: \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\n           Neighbours:\n               Logger.TranslatorTest \\(#PID<\\d+\\.\\d+\\.\\d+>\\)\n                   Initial Call: Logger.TranslatorTest.sleep/1\n                   Current Call: Logger.TranslatorTest.sleep/1\n                   Ancestors: \\[#PID<\\d+\\.\\d+\\.\\d+>, #PID<\\d+\\.\\d+\\.\\d+>\\]\\\n           \"\"\"\n  end\n\n  test \"translates Supervisor progress\" do\n    {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n\n    assert capture_log(:debug, fn ->\n             ref = Process.monitor(pid)\n             Supervisor.start_child(pid, worker(Task, [__MODULE__, :sleep, [self()]]))\n             Process.exit(pid, :normal)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[(debug|info)\\] Child Task of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Supervisor\\.Default\\) started\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Call: Task.start_link\\(Logger.TranslatorTest, :sleep, \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\\)\n           \"\"\"\n  end\n\n  test \"translates Supervisor progress with name\" do\n    {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one, name: __MODULE__)\n\n    assert capture_log(:debug, fn ->\n             ref = Process.monitor(pid)\n             Supervisor.start_child(pid, worker(Task, [__MODULE__, :sleep, [self()]]))\n             Process.exit(pid, :normal)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[(debug|info)\\] Child Task of Supervisor Logger.TranslatorTest started\n           \"\"\"\n\n    {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one, name: {:global, __MODULE__})\n\n    assert capture_log(:debug, fn ->\n             ref = Process.monitor(pid)\n             Supervisor.start_child(pid, worker(Task, [__MODULE__, :sleep, [self()]]))\n             Process.exit(pid, :normal)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[(debug|info)\\] Child Task of Supervisor Logger.TranslatorTest started\n           \"\"\"\n\n    {:ok, pid} =\n      Supervisor.start_link([], strategy: :one_for_one, name: {:via, :global, __MODULE__})\n\n    assert capture_log(:debug, fn ->\n             ref = Process.monitor(pid)\n             Supervisor.start_child(pid, worker(Task, [__MODULE__, :sleep, [self()]]))\n             Process.exit(pid, :normal)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[(debug|info)\\] Child Task of Supervisor Logger.TranslatorTest started\n           \"\"\"\n  end\n\n  test \"translates Supervisor progress on debug\" do\n    {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)\n\n    assert capture_log(:debug, fn ->\n             ref = Process.monitor(pid)\n             Supervisor.start_child(pid, worker(Task, [__MODULE__, :sleep, [self()]]))\n             Process.exit(pid, :normal)\n             receive do: ({:DOWN, ^ref, _, _, _} -> :ok)\n           end) =~ ~r\"\"\"\n           Start Call: Task.start_link\\(Logger.TranslatorTest, :sleep, \\[#PID<\\d+\\.\\d+\\.\\d+>\\]\\)\n           Restart: :permanent\n           Shutdown: 5000\n           Type: :worker\\\n           \"\"\"\n  end\n\n  test \"translates Supervisor reports start error\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             children = [worker(__MODULE__, [], function: :error)]\n\n             assert {:error, {:shutdown, {:failed_to_start_child, __MODULE__, :stop}}} =\n                      Supervisor.start_link(children, strategy: :one_for_one)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child Logger.TranslatorTest of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Supervisor\\.Default\\) failed to start\n           \\*\\* \\(exit\\) :stop\n           Start Call: Logger.TranslatorTest.error\\(\\)\\\n           \"\"\"\n  end\n\n  test \"translates Supervisor reports start error with raise\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             children = [worker(__MODULE__, [], function: :undef)]\n\n             assert {:error, {:shutdown, {:failed_to_start_child, __MODULE__, {:EXIT, _}}}} =\n                      Supervisor.start_link(children, strategy: :one_for_one)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child Logger.TranslatorTest of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Supervisor\\.Default\\) failed to start\n           \\*\\* \\(exit\\) an exception was raised:\n               \\*\\* \\(UndefinedFunctionError\\) function Logger.TranslatorTest.undef/0 is undefined or private\n               .*\n           Start Call: Logger.TranslatorTest.undef\\(\\)\\\n           \"\"\"s\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :start_error}}}, _child_metadata}\n  end\n\n  test \"translates Supervisor reports terminated\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             children = [worker(Task, [Kernel, :exit, [:stop]])]\n             {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one, max_restarts: 0)\n             receive do: ({:EXIT, ^pid, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child Task of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Supervisor\\.Default\\) terminated\n           \\*\\* \\(exit\\) :stop\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Call: Task.start_link\\(Kernel, :exit, \\[:stop\\]\\)\\\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {Task.Supervisor, :terminating}}}, task_metadata}\n    assert_receive {:event, {:report, %{label: {:supervisor, :shutdown}}}, _child_metadata}\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :child_terminated}}},\n                    _child_task_metadata}\n\n    assert {:stop, [_ | _]} = task_metadata[:crash_reason]\n  end\n\n  test \"translates Supervisor reports max restarts shutdown\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             children = [worker(Task, [Kernel, :exit, [:stop]])]\n             {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one, max_restarts: 0)\n             receive do: ({:EXIT, ^pid, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child Task of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Supervisor\\.Default\\) caused shutdown\n           \\*\\* \\(exit\\) :reached_max_restart_intensity\n           Start Call: Task.start_link\\(Kernel, :exit, \\[:stop\\]\\)\\\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {Task.Supervisor, :terminating}}}, task_metadata}\n    assert_receive {:event, {:report, %{label: {:supervisor, :shutdown}}}, _child_metadata}\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :child_terminated}}},\n                    _child_task_metadata}\n\n    assert {:stop, [_ | _]} = task_metadata[:crash_reason]\n  end\n\n  test \"translates Supervisor reports abnormal shutdown\" do\n    assert capture_log(:info, fn ->\n             children = [worker(__MODULE__, [], function: :abnormal)]\n             {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)\n             :ok = Supervisor.terminate_child(pid, __MODULE__)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child Logger.TranslatorTest of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Supervisor\\.Default\\) shut down abnormally\n           \\*\\* \\(exit\\) :stop\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Call: Logger.TranslatorTest.abnormal\\(\\)\\\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :shutdown_error}}}, _child_metadata}\n  end\n\n  test \"translates Supervisor reports abnormal shutdown on debug\" do\n    assert capture_log(:debug, fn ->\n             children = [\n               worker(__MODULE__, [], function: :abnormal, restart: :permanent, shutdown: 5000)\n             ]\n\n             {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)\n             :ok = Supervisor.terminate_child(pid, __MODULE__)\n           end) =~ ~r\"\"\"\n           \\*\\* \\(exit\\) :stop\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Call: Logger.TranslatorTest.abnormal\\(\\)\n           Restart: :permanent\n           Shutdown: 5000\n           Type: :worker\\\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :shutdown_error}}}, _child_metadata}\n  end\n\n  test \"translates DynamicSupervisor reports abnormal shutdown\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             child = %{id: __MODULE__, start: {__MODULE__, :abnormal, []}}\n             {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one)\n             {:ok, _pid2} = DynamicSupervisor.start_child(pid, child)\n             Process.exit(pid, :normal)\n             receive do: ({:EXIT, ^pid, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child :undefined of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Supervisor\\.Default\\) shut down abnormally\n           \\*\\* \\(exit\\) :stop\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Call: Logger.TranslatorTest.abnormal\\(\\)\\\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :shutdown_error}}}, _child_metadata}\n  end\n\n  test \"translates DynamicSupervisor reports abnormal shutdown including extra_arguments\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             {:ok, pid} =\n               DynamicSupervisor.start_link(strategy: :one_for_one, extra_arguments: [:extra])\n\n             child = %{id: __MODULE__, start: {__MODULE__, :abnormal, [:args]}}\n             {:ok, _pid2} = DynamicSupervisor.start_child(pid, child)\n             Process.exit(pid, :normal)\n             receive do: ({:EXIT, ^pid, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child :undefined of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Supervisor\\.Default\\) shut down abnormally\n           \\*\\* \\(exit\\) :stop\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Call: Logger.TranslatorTest.abnormal\\(:extra, :args\\)\\\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :shutdown_error}}}, _child_metadata}\n  end\n\n  test \"translates named DynamicSupervisor reports abnormal shutdown\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             child = %{id: __MODULE__, start: {__MODULE__, :abnormal, []}}\n             {:ok, pid} = DynamicSupervisor.start_link(strategy: :one_for_one, name: __MODULE__)\n             {:ok, _pid2} = DynamicSupervisor.start_child(pid, child)\n             Process.exit(pid, :normal)\n             receive do: ({:EXIT, ^pid, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child :undefined of Supervisor Logger.TranslatorTest shut down abnormally\n           \\*\\* \\(exit\\) :stop\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Call: Logger.TranslatorTest.abnormal\\(\\)\\\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :shutdown_error}}}, _child_metadata}\n  end\n\n  test \"translates :supervisor_bridge progress\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             {:ok, pid} = :supervisor_bridge.start_link(MyBridge, :normal)\n             receive do: ({:EXIT, ^pid, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[info\\] Child of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Logger\\.TranslatorTest\\.MyBridge\\) started\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Call: Logger.TranslatorTest.MyBridge.init\\(:normal\\)\\\n           \"\"\"\n  end\n\n  test \"translates :supervisor_bridge reports\" do\n    Process.flag(:trap_exit, true)\n\n    assert capture_log(:info, fn ->\n             {:ok, pid} = :supervisor_bridge.start_link(MyBridge, :stop)\n             receive do: ({:EXIT, ^pid, _} -> :ok)\n           end) =~ ~r\"\"\"\n           \\[error\\] Child of Supervisor #PID<\\d+\\.\\d+\\.\\d+> \\(Logger\\.TranslatorTest\\.MyBridge\\) terminated\n           \\*\\* \\(exit\\) :stop\n           Pid: #PID<\\d+\\.\\d+\\.\\d+>\n           Start Module: Logger.TranslatorTest.MyBridge\\\n           \"\"\"\n\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, task_metadata}\n    assert_receive {:event, {:report, %{label: {:gen_server, :terminate}}}, _child_metadata}\n    assert {:stop, [_ | _]} = task_metadata[:crash_reason]\n  end\n\n  test \"translates process crash with ERTS\" do\n    assert {:ok, _msg, meta} =\n             Logger.Translator.translate(\n               :error,\n               :error,\n               :format,\n               {~c\"Error in process ~p on node ~p with exit value:~n~p~n\",\n                [self(), :\"name@127.0.0.1\", {:badarith, [{:erlang, :/, [1, 0], []}]}]}\n             )\n\n    assert meta[:crash_reason]\n  end\n\n  test \"reports :undefined MFA properly\" do\n    defmodule WeirdFunctionNamesGenServer do\n      use GenServer\n\n      def unquote(:\"start link\")(), do: GenServer.start_link(__MODULE__, [])\n      def init(args), do: {:ok, args}\n      def handle_call(_call, _from, _state), do: raise(\"oops\")\n    end\n\n    start = {WeirdFunctionNamesGenServer, :\"start link\", []}\n    child = %{id: :weird, start: start, restart: :temporary}\n    {:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)\n\n    log =\n      capture_log(:info, fn ->\n        {:ok, pid} = DynamicSupervisor.start_child(sup, child)\n        catch_exit(GenServer.call(pid, :error))\n        [] = DynamicSupervisor.which_children(sup)\n      end)\n\n    assert log =~ ~s(Start Call: Logger.TranslatorTest.WeirdFunctionNamesGenServer.\"start link\"/?)\n    assert_receive {:event, {:report, %{label: {:gen_server, :terminate}}}, server_metadata}\n    assert_receive {:event, {:report, %{label: {:proc_lib, :crash}}}, process_metadata}\n\n    assert_receive {:event, {:report, %{label: {:supervisor, :child_terminated}}},\n                    _child_metadata}\n\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = server_metadata[:crash_reason]\n    assert {%RuntimeError{message: \"oops\"}, [_ | _]} = process_metadata[:crash_reason]\n  after\n    :code.purge(WeirdFunctionNamesGenServer)\n    :code.delete(WeirdFunctionNamesGenServer)\n  end\n\n  @tag logger_config: [handle_otp_reports: false]\n  test \"drops events if otp report handling is switched off\" do\n    {:ok, pid} = GenServer.start(MyGenServer, :ok)\n    catch_exit(GenServer.call(pid, :error))\n    refute_receive {:event, _, _}, 100\n  end\n\n  def task(parent, fun \\\\ fn -> raise \"oops\" end) do\n    mon = Process.monitor(parent)\n    Process.unlink(parent)\n\n    receive do\n      :go ->\n        fun.()\n\n      {:DOWN, ^mon, _, _, _} ->\n        exit(:shutdown)\n    end\n  end\n\n  def sub_task(parent, fun \\\\ fn _ -> raise \"oops\" end) do\n    mon = Process.monitor(parent)\n    Process.unlink(parent)\n    {:ok, pid} = Task.start_link(__MODULE__, :sleep, [self()])\n    receive do: (:sleeping -> :ok)\n\n    receive do\n      :go ->\n        fun.(pid)\n\n      {:DOWN, ^mon, _, _, _} ->\n        exit(:shutdown)\n    end\n  end\n\n  def sleep(pid) do\n    mon = Process.monitor(pid)\n    send(pid, :sleeping)\n    receive do: ({:DOWN, ^mon, _, _, _} -> exit(:shutdown))\n  end\n\n  def error(), do: {:error, :stop}\n\n  def abnormal() do\n    :proc_lib.start_link(__MODULE__, :abnormal_init, [])\n  end\n\n  def abnormal(:extra, :args) do\n    :proc_lib.start_link(__MODULE__, :abnormal_init, [])\n  end\n\n  def abnormal_init() do\n    Process.flag(:trap_exit, true)\n    :proc_lib.init_ack({:ok, self()})\n    receive do: ({:EXIT, _, _} -> exit(:stop))\n  end\n\n  defp worker(name, args, opts \\\\ []) do\n    Enum.into(opts, %{id: name, start: {name, opts[:function] || :start_link, args}})\n  end\n\n  defp put_logger_config(new_config) do\n    Application.put_all_env(logger: new_config)\n\n    Logger.App.stop()\n\n    # Shutdown the application\n    Logger.App.stop()\n\n    # And start it without warnings\n    Application.put_env(:logger, :level, :error)\n    Application.start(:logger)\n    Application.delete_env(:logger, :level)\n    Logger.configure(level: :debug)\n  end\n\n  defp restore_logger_config(config) do\n    Application.put_all_env(logger: config)\n    Logger.App.stop()\n    Application.start(:logger)\n  end\nend\n"
  },
  {
    "path": "lib/logger/test/logger/utils_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Logger.UtilsTest do\n  use Logger.Case, async: true\n\n  doctest Logger.Utils\n\n  defp scan_inspect(format, args, truncate \\\\ 10) do\n    format\n    |> Logger.Utils.scan_inspect(args, truncate)\n    |> :io_lib.unscan_format()\n  end\n\n  test \"formats\" do\n    assert scan_inspect(~c\"~p\", [1]) == {~c\"~ts\", [\"1\"]}\n    assert scan_inspect(\"~p\", [1]) == {~c\"~ts\", [\"1\"]}\n    assert scan_inspect(:\"~p\", [1]) == {~c\"~ts\", [\"1\"]}\n  end\n\n  test \"sigils\" do\n    assert scan_inspect(~c\"~10.10tp\", [1]) == {~c\"~ts\", [\"1\"]}\n    assert scan_inspect(~c\"~-10.10tp\", [1]) == {~c\"~ts\", [\"1\"]}\n\n    assert scan_inspect(~c\"~10.10lp\", [1]) == {~c\"~ts\", [\"1\"]}\n    assert scan_inspect(~c\"~10.10x~p~n\", [1, 2, 3]) == {~c\"~10.10x~ts~n\", [1, 2, \"3\"]}\n  end\n\n  test \"with modifier t has no effect (as it is the default)\" do\n    assert scan_inspect(~c\"~tp\", [1]) == {~c\"~ts\", [\"1\"]}\n    assert scan_inspect(~c\"~tw\", [1]) == {~c\"~ts\", [\"1\"]}\n  end\n\n  test \"with modifier l always prints lists\" do\n    assert scan_inspect(~c\"~lp\", [~c\"abc\"]) ==\n             {~c\"~ts\", [\"[97, 98, 99]\"]}\n\n    assert scan_inspect(~c\"~lw\", [~c\"abc\"]) ==\n             {~c\"~ts\", [\"[97, 98, 99]\"]}\n  end\n\n  test \"with modifier for width\" do\n    assert scan_inspect(~c\"~5lp\", [~c\"abc\"]) ==\n             {~c\"~ts\", [\"[97,\\n 98,\\n 99]\"]}\n\n    assert scan_inspect(~c\"~5lw\", [~c\"abc\"]) ==\n             {~c\"~ts\", [\"[97, 98, 99]\"]}\n  end\n\n  test \"with modifier for limit\" do\n    assert scan_inspect(~c\"~5lP\", [~c\"abc\", 2]) ==\n             {~c\"~ts\", [\"[97,\\n 98,\\n ...]\"]}\n\n    assert scan_inspect(~c\"~5lW\", [~c\"abc\", 2]) ==\n             {~c\"~ts\", [\"[97, 98, ...]\"]}\n  end\n\n  test \"truncates binaries\" do\n    assert scan_inspect(~c\"~ts\", [\"abcdeabcdeabcdeabcde\"]) == {~c\"~ts\", [\"abcdeabcde\"]}\n\n    assert scan_inspect(~c\"~ts~ts~ts\", [\"abcdeabcde\", \"abcde\", \"abcde\"]) ==\n             {~c\"~ts~ts~ts\", [\"abcdeabcde\", \"\", \"\"]}\n  end\n\n  test \"with :infinity truncate\" do\n    long_string = String.duplicate(\"foo\", 10_000)\n    assert scan_inspect(~c\"~ts\", [long_string], :infinity) == {~c\"~ts\", [long_string]}\n  end\nend\n"
  },
  {
    "path": "lib/logger/test/logger_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule LoggerTest do\n  use Logger.Case\n  require Logger\n\n  @moduletag formatter: [metadata: [:application, :module]]\n\n  setup tags do\n    :logger.update_handler_config(:default, :formatter, Logger.default_formatter(tags.formatter))\n\n    on_exit(fn ->\n      :logger.update_handler_config(:default, :formatter, Logger.default_formatter())\n    end)\n  end\n\n  defp msg_with_meta(text) do\n    msg(\"module=LoggerTest #{text}\")\n  end\n\n  test \"levels/0\" do\n    assert [_ | _] = Logger.levels()\n    assert :info in Logger.levels()\n  end\n\n  test \"level/0\" do\n    assert Logger.level() == :debug\n\n    Logger.configure(level: :all)\n    assert Logger.level() == :all\n\n    Logger.configure(level: :info)\n    assert Logger.level() == :info\n\n    Logger.configure(level: :notice)\n    assert Logger.level() == :notice\n\n    Logger.configure(level: :warning)\n    assert Logger.level() == :warning\n\n    Logger.configure(level: :error)\n    assert Logger.level() == :error\n\n    Logger.configure(level: :critical)\n    assert Logger.level() == :critical\n\n    Logger.configure(level: :alert)\n    assert Logger.level() == :alert\n\n    Logger.configure(level: :emergency)\n    assert Logger.level() == :emergency\n\n    Logger.configure(level: :none)\n    assert Logger.level() == :none\n  after\n    Logger.configure(level: :debug)\n  end\n\n  test \"per-module levels\" do\n    defmodule PerModuleLevels do\n      def debug, do: Logger.debug(\"debug_msg\")\n\n      def error, do: Logger.error(\"error_msg\")\n    end\n\n    assert capture_log(fn -> assert PerModuleLevels.debug() == :ok end) =~ \"debug_msg\"\n    assert capture_log(fn -> assert PerModuleLevels.error() == :ok end) =~ \"error_msg\"\n\n    Logger.put_module_level(PerModuleLevels, :error)\n\n    assert capture_log(fn -> assert PerModuleLevels.debug() == :ok end) == \"\"\n    assert capture_log(fn -> Logger.debug(\"outer_debug_msg\") end) =~ \"outer_debug_msg\"\n    assert capture_log(fn -> assert PerModuleLevels.error() == :ok end) =~ \"error_msg\"\n\n    Logger.put_module_level(PerModuleLevels, :debug)\n\n    assert capture_log(:error, fn -> assert PerModuleLevels.debug() == :ok end) =~ \"debug_msg\"\n    assert capture_log(:error, fn -> Logger.debug(\"outer_debug_msg\") end) == \"\"\n    assert capture_log(:error, fn -> assert PerModuleLevels.error() == :ok end) =~ \"error_msg\"\n\n    Logger.delete_module_level(PerModuleLevels)\n\n    assert capture_log(fn -> assert PerModuleLevels.debug() == :ok end) =~ \"debug_msg\"\n    assert capture_log(fn -> assert PerModuleLevels.error() == :ok end) =~ \"error_msg\"\n\n    Logger.put_module_level(PerModuleLevels, :error)\n    assert capture_log(fn -> assert PerModuleLevels.debug() == :ok end) == \"\"\n    Logger.delete_all_module_levels()\n    assert capture_log(fn -> assert PerModuleLevels.debug() == :ok end) =~ \"debug_msg\"\n  end\n\n  test \"per-modules levels\" do\n    modules =\n      for n <- 1..2 do\n        name = Module.concat([__MODULE__, PerModulesLevels, to_string(n)])\n\n        defmodule name do\n          def debug, do: Logger.debug(\"debug_msg\")\n\n          def error, do: Logger.error(\"error_msg\")\n        end\n\n        name\n      end\n\n    for module <- modules do\n      assert capture_log(fn -> assert module.debug() == :ok end) =~ \"debug_msg\"\n      assert capture_log(fn -> assert module.error() == :ok end) =~ \"error_msg\"\n    end\n\n    Logger.put_module_level(modules, :error)\n\n    for module <- modules do\n      assert capture_log(fn -> assert module.debug() == :ok end) =~ \"\"\n      assert capture_log(fn -> Logger.debug(\"outer_debug_msg\") end) =~ \"outer_debug_msg\"\n      assert capture_log(fn -> assert module.error() == :ok end) =~ \"error_msg\"\n    end\n\n    Logger.put_module_level(modules, :debug)\n\n    for module <- modules do\n      assert capture_log(:error, fn -> assert module.debug() == :ok end) =~ \"debug_msg\"\n      assert capture_log(:error, fn -> Logger.debug(\"outer_debug_msg\") end) == \"\"\n      assert capture_log(fn -> assert module.error() == :ok end) =~ \"error_msg\"\n    end\n\n    Logger.delete_module_level(modules)\n\n    for module <- modules do\n      assert capture_log(fn -> assert module.debug() == :ok end) =~ \"debug_msg\"\n      assert capture_log(fn -> assert module.error() == :ok end) =~ \"error_msg\"\n    end\n\n    Logger.put_module_level(modules, :error)\n\n    for module <- modules do\n      assert capture_log(fn -> assert module.debug() == :ok end) == \"\"\n    end\n\n    Logger.delete_all_module_levels()\n\n    for module <- modules do\n      assert capture_log(fn -> assert module.debug() == :ok end) =~ \"debug_msg\"\n    end\n  end\n\n  test \"per-application levels\" do\n    Application.load(:eex)\n    assert Logger.get_module_level(EEx) == []\n    Logger.put_application_level(:eex, :notice)\n    assert Logger.get_module_level(EEx) == [{EEx, :notice}]\n    Logger.put_module_level(EEx, :alert)\n    assert Logger.get_module_level(EEx) == [{EEx, :alert}]\n  after\n    Logger.delete_all_module_levels()\n  end\n\n  test \"per-process levels\" do\n    assert Logger.get_process_level(self()) == nil\n\n    assert capture_log(fn -> Logger.debug(\"debug_msg\") end) =~ \"debug_msg\"\n\n    Logger.put_process_level(self(), :debug)\n    assert Logger.get_process_level(self()) == :debug\n\n    assert capture_log(fn -> Logger.debug(\"debug_msg\") end) =~ \"debug_msg\"\n\n    Logger.put_process_level(self(), :error)\n\n    assert capture_log(fn -> Logger.debug(\"debug_msg\") end) == \"\"\n    assert capture_log(fn -> Logger.error(\"error_msg\") end) =~ \"error_msg\"\n\n    Logger.put_process_level(self(), :none)\n    assert Logger.get_process_level(self()) == :none\n\n    assert capture_log(fn -> Logger.debug(\"debug_msg\") end) == \"\"\n    assert capture_log(fn -> Logger.error(\"error_msg\") end) == \"\"\n\n    Logger.delete_process_level(self())\n    assert Logger.get_process_level(self()) == nil\n\n    assert capture_log(fn -> Logger.debug(\"debug_msg\") end) =~ \"debug_msg\"\n    assert capture_log(fn -> Logger.error(\"error_msg\") end) =~ \"error_msg\"\n  end\n\n  test \"process metadata\" do\n    assert Logger.metadata(data: true) == :ok\n    assert Logger.metadata() == [data: true]\n    assert Logger.metadata(data: true) == :ok\n    assert Logger.metadata() == [data: true]\n    assert Logger.metadata(%{meta: 1}) == :ok\n    assert Enum.sort(Logger.metadata()) == [data: true, meta: 1]\n    assert Logger.metadata(%{data: nil}) == :ok\n    assert Logger.metadata() == [meta: 1]\n\n    assert Logger.reset_metadata(meta: 2) == :ok\n    assert Logger.metadata() == [meta: 2]\n    assert Logger.reset_metadata(%{data: true, app: nil}) == :ok\n    assert Logger.metadata() == [data: true]\n    assert Logger.reset_metadata() == :ok\n    assert Logger.metadata() == []\n  end\n\n  test \"metadata merge\" do\n    assert Logger.metadata(module: Sample) == :ok\n\n    assert capture_log(fn ->\n             assert Logger.bare_log(:info, \"ok\", application: nil, module: LoggerTest) == :ok\n           end) =~ msg(\"module=LoggerTest [info] ok\")\n  end\n\n  test \"metadata compile-time merge\" do\n    assert Logger.metadata(mfa: {Sample, :foo, 1}) == :ok\n\n    assert capture_log(fn ->\n             assert Logger.bare_log(:info, \"ok\", application: nil, mfa: {CustomTest, :bar, 2}) ==\n                      :ok\n           end) =~ msg(\"module=CustomTest [info] ok\")\n  end\n\n  test \"metadata merge when the argument function returns metadata\" do\n    assert Logger.metadata(module: Sample) == :ok\n\n    fun = fn -> {\"ok\", [module: \"Function\"]} end\n\n    assert capture_log(fn ->\n             assert Logger.bare_log(:info, fun, application: nil, module: LoggerTest) == :ok\n           end) =~ msg(\"module=Function [info] ok\")\n  end\n\n  describe \"log with function\" do\n    test \"supports iolist\" do\n      fun = fn -> [\"ok\", ?:, ~c\"example\"] end\n\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, fun, application: nil, module: FunctionTest) == :ok\n             end) =~ msg(\"module=FunctionTest [info] ok:example\")\n    end\n\n    test \"supports binaries\" do\n      fun = fn -> \"ok:example\" end\n\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, fun, application: nil, module: FunctionTest) == :ok\n             end) =~ msg(\"module=FunctionTest [info] ok:example\")\n    end\n  end\n\n  describe \"report logging\" do\n    test \"supports maps\" do\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, %{foo: 10}, application: nil, module: FunctionTest) ==\n                        :ok\n             end) =~ msg(\"module=FunctionTest [info] [foo: 10]\")\n    end\n\n    test \"supports keyword\" do\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, foo: 10) == :ok\n             end) =~ msg(\"[info] [foo: 10]\")\n    end\n\n    test \"supports custom report_cb\" do\n      report_cb = fn %{foo: foo} -> {\"Foo is ~B\", [foo]} end\n\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, %{foo: 10}, report_cb: report_cb) == :ok\n             end) =~ msg(\"[info] Foo is 10\")\n\n      report_cb = fn %{foo: foo}, _opts -> \"Foo is #{foo}\" end\n\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, %{foo: 20}, report_cb: report_cb) == :ok\n             end) =~ msg(\"[info] Foo is 20\")\n    end\n\n    test \"supports translator_inspect_opts for reports\" do\n      Application.put_env(:logger, :translator_inspect_opts, printable_limit: 1)\n\n      assert capture_log(fn -> :logger.error(%{foo: \"bar\"}) end) =~\n               ~S([error] [foo: \"b\" <> ...])\n    after\n      Application.put_env(:logger, :translator_inspect_opts, [])\n    end\n\n    test \"supports function that return report\" do\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, fn -> %{foo: 10} end) == :ok\n             end) =~ msg(\"[info] [foo: 10]\")\n\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, fn -> {%{foo: 10}, []} end) == :ok\n             end) =~ msg(\"[info] [foo: 10]\")\n\n      assert capture_log(fn ->\n               assert Logger.bare_log(:info, fn -> {[foo: 10], []} end) == :ok\n             end) =~ msg(\"[info] [foo: 10]\")\n    end\n  end\n\n  test \"compare_levels/2\" do\n    assert Logger.compare_levels(:debug, :debug) == :eq\n    assert Logger.compare_levels(:debug, :info) == :lt\n    assert Logger.compare_levels(:debug, :notice) == :lt\n    assert Logger.compare_levels(:debug, :warning) == :lt\n    assert Logger.compare_levels(:debug, :error) == :lt\n    assert Logger.compare_levels(:debug, :critical) == :lt\n    assert Logger.compare_levels(:debug, :alert) == :lt\n    assert Logger.compare_levels(:debug, :emergency) == :lt\n\n    assert Logger.compare_levels(:info, :debug) == :gt\n    assert Logger.compare_levels(:info, :info) == :eq\n    assert Logger.compare_levels(:info, :warning) == :lt\n    assert Logger.compare_levels(:info, :error) == :lt\n\n    assert Logger.compare_levels(:warning, :debug) == :gt\n    assert Logger.compare_levels(:warning, :info) == :gt\n    assert Logger.compare_levels(:warning, :warning) == :eq\n    assert Logger.compare_levels(:warning, :error) == :lt\n\n    assert Logger.compare_levels(:error, :debug) == :gt\n    assert Logger.compare_levels(:error, :info) == :gt\n    assert Logger.compare_levels(:error, :warning) == :gt\n    assert Logger.compare_levels(:error, :error) == :eq\n  end\n\n  test \"deprecated :warn\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      assert capture_log(fn ->\n               Logger.log(:warn, \"hello\") == :ok\n             end) =~ \"[warning]\"\n\n      assert capture_log(fn ->\n               Logger.bare_log(:warn, \"hello\") == :ok\n             end) =~ \"[warning]\"\n    end)\n  end\n\n  describe \"levels\" do\n    test \"debug/2\" do\n      assert capture_log(fn ->\n               assert Logger.debug(\"hello\", []) == :ok\n             end) =~ msg_with_meta(\"[debug] hello\")\n\n      assert capture_log(:info, fn ->\n               assert Logger.debug(\"hello\", []) == :ok\n             end) == \"\"\n\n      assert capture_log(:info, fn ->\n               assert Logger.debug(send(self(), :something), []) == :ok\n             end) == \"\"\n\n      refute_received :something\n    end\n\n    test \"info/2\" do\n      assert capture_log(fn ->\n               assert Logger.info(\"hello\", []) == :ok\n             end) =~ msg_with_meta(\"[info] hello\")\n\n      assert capture_log(:notice, fn ->\n               assert Logger.info(\"hello\", []) == :ok\n             end) == \"\"\n\n      assert capture_log(:notice, fn ->\n               assert Logger.info(send(self(), :something), []) == :ok\n             end) == \"\"\n\n      refute_received :something\n    end\n\n    test \"warning/2\" do\n      assert capture_log(fn ->\n               assert Logger.warning(\"hello\", []) == :ok\n             end) =~ msg_with_meta(\"[warning] hello\")\n\n      assert capture_log(:error, fn ->\n               assert Logger.warning(\"hello\", []) == :ok\n             end) == \"\"\n\n      assert capture_log(:error, fn ->\n               assert Logger.warning(send(self(), :something), []) == :ok\n             end) == \"\"\n\n      refute_received :something\n    end\n\n    test \"error/2\" do\n      assert capture_log(fn ->\n               assert Logger.error(\"hello\", []) == :ok\n             end) =~ msg_with_meta(\"[error] hello\")\n\n      assert capture_log(:critical, fn ->\n               assert Logger.error(\"hello\", []) == :ok\n             end) == \"\"\n\n      assert capture_log(:critical, fn ->\n               assert Logger.error(send(self(), :something), []) == :ok\n             end) == \"\"\n\n      refute_received :something\n    end\n\n    test \"critical/2\" do\n      assert capture_log(fn ->\n               assert Logger.critical(\"hello\", []) == :ok\n             end) =~ msg_with_meta(\"[critical] hello\")\n\n      assert capture_log(:alert, fn ->\n               assert Logger.critical(\"hello\", []) == :ok\n             end) == \"\"\n\n      assert capture_log(:alert, fn ->\n               assert Logger.critical(send(self(), :something), []) == :ok\n             end) == \"\"\n\n      refute_received :something\n    end\n\n    test \"alert/2\" do\n      assert capture_log(fn ->\n               assert Logger.alert(\"hello\", []) == :ok\n             end) =~ msg_with_meta(\"[alert] hello\")\n\n      assert capture_log(:emergency, fn ->\n               assert Logger.alert(\"hello\", []) == :ok\n             end) == \"\"\n\n      assert capture_log(:emergency, fn ->\n               assert Logger.alert(send(self(), :something), []) == :ok\n             end) == \"\"\n\n      refute_received :something\n    end\n\n    test \"emergency/2\" do\n      assert capture_log(fn ->\n               assert Logger.emergency(\"hello\", []) == :ok\n             end) =~ msg_with_meta(\"[emergency] hello\")\n\n      assert capture_log(:none, fn ->\n               assert Logger.emergency(\"hello\", []) == :ok\n             end) == \"\"\n\n      assert capture_log(:none, fn ->\n               assert Logger.emergency(send(self(), :something), []) == :ok\n             end) == \"\"\n\n      refute_received :something\n    end\n  end\n\n  test \"remove unused calls at compile time based on matching metadata\" do\n    Logger.configure(\n      compile_time_application: :sample_app,\n      compile_time_purge_matching: [\n        [module: LoggerTest.PurgeMatching, function: \"two_filters/0\"],\n        [function: \"one_filter/0\"],\n        [custom: true],\n        [function: \"level_filter/0\", level_lower_than: :warning],\n        [application: :sample_app, level_lower_than: :info]\n      ]\n    )\n\n    defmodule PurgeMatching do\n      def two_filters do\n        Logger.debug(\"two_filters\")\n      end\n\n      def one_filter do\n        Logger.debug(\"one_filter\")\n      end\n\n      def custom_filters do\n        Logger.debug(\"custom_filters\", custom: true)\n      end\n\n      def level_filter do\n        Logger.info(\"info_filter\")\n        Logger.warning(\"warning_filter\")\n      end\n\n      def works do\n        Logger.info(\"works\")\n      end\n\n      def log(level, metadata \\\\ []) do\n        Logger.log(level, \"ok\", metadata)\n      end\n    end\n\n    assert capture_log(fn -> assert PurgeMatching.works() == :ok end) =~ \"works\"\n    assert capture_log(fn -> assert PurgeMatching.one_filter() == :ok end) == \"\"\n    assert capture_log(fn -> assert PurgeMatching.two_filters() == :ok end) == \"\"\n    assert capture_log(fn -> assert PurgeMatching.custom_filters() == :ok end) == \"\"\n    assert capture_log(fn -> assert PurgeMatching.level_filter() == :ok end) =~ \"warning_filter\"\n    refute capture_log(fn -> assert PurgeMatching.level_filter() == :ok end) =~ \"info_filter\"\n\n    capture_log(fn -> assert PurgeMatching.log(:info) == :ok end)\n    capture_log(fn -> assert PurgeMatching.log(:debug) == :ok end)\n  after\n    Logger.configure(compile_time_application: nil)\n    Logger.configure(compile_time_purge_matching: [])\n  end\n\n  test \"set application metadata at compile time\" do\n    Logger.configure(compile_time_application: nil)\n\n    defmodule SampleNoApp do\n      def info do\n        Logger.info(\"hello\")\n      end\n    end\n\n    assert capture_log(fn ->\n             assert SampleNoApp.info() == :ok\n           end) =~ msg(\"module=LoggerTest.SampleNoApp [info] hello\")\n\n    Logger.configure(compile_time_application: :sample_app)\n\n    defmodule SampleApp do\n      def info do\n        Logger.info(\"hello\")\n      end\n    end\n\n    assert capture_log(fn ->\n             assert SampleApp.info() == :ok\n           end) =~ msg(\"application=sample_app module=LoggerTest.SampleApp [info] hello\")\n  after\n    Logger.configure(compile_time_application: nil)\n  end\n\n  @tag formatter: [truncate: 4]\n  test \"log/2 truncates messages\" do\n    assert capture_log(fn -> Logger.log(:debug, \"hello\") end) =~ \"hell (truncated)\"\n  end\n\n  test \"log/2 handles bad Unicode chars\" do\n    output =\n      capture_log(fn ->\n        assert Logger.log(:debug, \"he\" <> <<185>> <> \"lo\") == :ok\n        Process.sleep(100)\n      end)\n\n    assert output =~ \"FORMATTER ERROR: bad return value\"\n    assert output =~ \"** (RuntimeError) bad return value from Logger formatter Logger.Formatter\"\n  end\n\n  test \"stops the application silently\" do\n    Logger.App.stop()\n    Application.start(:logger)\n  end\n\n  test \"starts the application with warning level\" do\n    Logger.App.stop()\n    assert %{level: :notice} = :logger.get_primary_config()\n    Application.put_env(:logger, :level, :warning)\n    Application.start(:logger)\n    assert %{level: :warning} = :logger.get_primary_config()\n  after\n    Application.delete_env(:logger, :level)\n    Logger.App.stop()\n    Application.start(:logger)\n  end\n\n  test \"starts the application without a handler\" do\n    Application.put_env(:logger, :default_handler, false)\n    Logger.App.stop()\n    Application.start(:logger)\n    assert :logger.get_handler_config() == []\n  after\n    Application.delete_env(:logger, :default_handler)\n    Logger.App.stop()\n    Application.start(:logger)\n  end\n\n  test \"starts the application with custom formatter\" do\n    Application.put_env(:logger, :default_formatter, format: \"yes--$message--yes\")\n    Logger.App.stop()\n    Application.start(:logger)\n    assert capture_log(fn -> Logger.log(:debug, \"hello\") end) =~ \"yes--hello--yes\"\n  after\n    Application.delete_env(:logger, :default_formatter)\n    Logger.App.stop()\n    Application.start(:logger)\n  end\n\n  test \"starts the application with custom handler\" do\n    Application.put_env(:logger, :default_handler,\n      level: :error,\n      formatter: Logger.Formatter.new(format: \"no--$message--no\")\n    )\n\n    Logger.App.stop()\n    Application.start(:logger)\n    assert capture_log(fn -> Logger.log(:debug, \"hello\") end) == \"\"\n    assert capture_log(fn -> Logger.log(:error, \"hello\") end) =~ \"no--hello--no\"\n  after\n    Application.delete_env(:logger, :default_handler)\n    Logger.App.stop()\n    Application.start(:logger)\n  end\n\n  test \"starts the application with global metadata\" do\n    Application.put_env(:logger, :metadata, global_meta: :yes)\n    Logger.App.stop()\n    Application.start(:logger)\n    assert :logger.get_primary_config()[:metadata] == %{global_meta: :yes}\n  after\n    Application.put_env(:logger, :metadata, [])\n    Logger.App.stop()\n    Application.start(:logger)\n  end\n\n  test \"writes to stderr on bad default handler config\" do\n    Application.put_env(:logger, :default_handler, config: %{file: 123})\n    Logger.App.stop()\n\n    assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n             Application.start(:logger)\n           end) =~\n             \"Could not attach default Logger handler: {:handler_not_added, {:callback_crashed,\"\n  after\n    Application.delete_env(:logger, :default_handler)\n    Logger.App.stop()\n    Application.start(:logger)\n  end\n\n  test \"writes to stderr on bad default handler module\" do\n    Application.put_env(:logger, :default_handler, module: :who_knows)\n    Logger.App.stop()\n\n    assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n             Application.start(:logger)\n           end) =~\n             \"Could not attach default Logger handler: {:invalid_handler, {:function_not_exported\"\n  after\n    Application.delete_env(:logger, :default_handler)\n    Logger.App.stop()\n    Application.start(:logger)\n  end\n\n  test \"configure/1 sets options\" do\n    Logger.configure(translator_inspect_opts: [limit: 3])\n    assert Application.get_env(:logger, :translator_inspect_opts) == [limit: 3]\n  after\n    Logger.configure(translator_inspect_opts: [])\n  end\n\n  @tag formatter: [metadata: [:module, :meta]]\n  test \"always evaluate messages\" do\n    Logger.configure(\n      always_evaluate_messages: true,\n      compile_time_purge_matching: [[level_lower_than: :info]],\n      level: :error\n    )\n\n    defmodule AlwaysEvaluate do\n      def compile_purged do\n        Logger.debug(send(self(), \"compile purged\"))\n      end\n\n      def runtime_purged do\n        Logger.info(send(self(), \"runtime purged\"))\n      end\n\n      def runtime_purged_anonymous_function do\n        Logger.info(fn -> send(self(), \"runtime purged anonymous function\") end)\n      end\n\n      def runtime_purged_anonymous_tuple_function do\n        Logger.info(fn ->\n          {send(self(), \"runtime purged anonymous tuple function\"), meta: true}\n        end)\n      end\n\n      def not_purged do\n        Logger.error(send(self(), \"not purged\"))\n      end\n    end\n\n    assert capture_log(fn -> AlwaysEvaluate.not_purged() end) =~ \"not purged\"\n    assert_received \"not purged\"\n\n    assert capture_log(fn ->\n             Logger.configure(level: :error)\n             AlwaysEvaluate.runtime_purged()\n           end) == \"\"\n\n    assert_received \"runtime purged\"\n\n    assert capture_log(fn ->\n             Logger.configure(level: :debug)\n             AlwaysEvaluate.runtime_purged()\n           end) =~ \"runtime purged\"\n\n    assert_received \"runtime purged\"\n\n    assert capture_log(fn ->\n             Logger.configure(level: :debug)\n             AlwaysEvaluate.runtime_purged_anonymous_function()\n           end) =~ \"runtime purged anonymous function\"\n\n    assert_received \"runtime purged anonymous function\"\n\n    log =\n      capture_log(fn ->\n        Logger.configure(level: :debug)\n        AlwaysEvaluate.runtime_purged_anonymous_tuple_function()\n      end)\n\n    assert log =~ \"module=LoggerTest.AlwaysEvaluate meta=true\"\n    assert log =~ \"runtime purged anonymous tuple function\"\n\n    assert_received \"runtime purged anonymous tuple function\"\n\n    assert capture_log(fn ->\n             Logger.configure(level: :error)\n             AlwaysEvaluate.compile_purged()\n           end) == \"\"\n\n    assert_received \"compile purged\"\n  after\n    Logger.configure(\n      level: :debug,\n      always_evaluate_messages: false,\n      compile_time_purge_matching: []\n    )\n  end\n\n  describe \"colors\" do\n    @tag formatter: [format: \"$message\", colors: [enabled: true]]\n    test \"default\" do\n      assert capture_log(fn -> Logger.debug(\"hello\", ansi_color: :yellow) end) ==\n               IO.ANSI.yellow() <> \"hello\" <> IO.ANSI.reset()\n\n      assert capture_log(fn -> Logger.debug(\"hello\") end) ==\n               IO.ANSI.cyan() <> \"hello\" <> IO.ANSI.reset()\n\n      assert capture_log(fn -> Logger.info(\"hello\") end) ==\n               IO.ANSI.normal() <> \"hello\" <> IO.ANSI.reset()\n\n      assert capture_log(fn -> Logger.warning(\"hello\") end) ==\n               IO.ANSI.yellow() <> \"hello\" <> IO.ANSI.reset()\n\n      assert capture_log(fn -> Logger.error(\"hello\") end) ==\n               IO.ANSI.red() <> \"hello\" <> IO.ANSI.reset()\n    end\n\n    @tag formatter: [\n           format: \"$message\",\n           colors: [enabled: true, debug: :magenta, info: :cyan, warning: :magenta, error: :cyan]\n         ]\n    test \"custom\" do\n      assert capture_log(fn -> Logger.debug(\"hello\") end) ==\n               IO.ANSI.magenta() <> \"hello\" <> IO.ANSI.reset()\n\n      assert capture_log(fn -> Logger.info(\"hello\") end) ==\n               IO.ANSI.cyan() <> \"hello\" <> IO.ANSI.reset()\n\n      assert capture_log(fn -> Logger.warning(\"hello\") end) ==\n               IO.ANSI.magenta() <> \"hello\" <> IO.ANSI.reset()\n\n      assert capture_log(fn -> Logger.error(\"hello\") end) ==\n               IO.ANSI.cyan() <> \"hello\" <> IO.ANSI.reset()\n    end\n  end\n\n  describe \"OTP integration\" do\n    test \"changes level in both\" do\n      assert :logger.get_primary_config().level == :debug\n      Logger.configure(level: :error)\n      assert :logger.get_primary_config().level == :error\n    after\n      Logger.configure(level: :debug)\n    end\n\n    test \"supports module level\" do\n      :logger.set_module_level(__MODULE__, :none)\n      assert capture_log(fn -> Logger.info(\"hello\") end) == \"\"\n      :logger.set_module_level(__MODULE__, :all)\n      assert capture_log(fn -> Logger.info(\"hello\") end) =~ \"hello\"\n    after\n      :logger.unset_module_level(__MODULE__)\n    end\n\n    test \"maps Erlang levels\" do\n      :logger.set_primary_config(:level, :notice)\n      assert capture_log(fn -> Logger.info(\"hello\") end) =~ \"hello\"\n\n      :logger.set_primary_config(:level, :notice)\n      assert Logger.level() == :notice\n\n      :logger.set_primary_config(:level, :emergency)\n      assert Logger.level() == :emergency\n    after\n      Logger.configure(level: :debug)\n    end\n\n    test \"metadata is synchronised\" do\n      Logger.metadata(foo: \"bar\")\n\n      assert Map.new(Logger.metadata()) == :logger.get_process_metadata()\n      :logger.set_process_metadata(%{bar: \"foo\"})\n\n      assert Map.new(Logger.metadata()) == :logger.get_process_metadata()\n    end\n  end\nend\n"
  },
  {
    "path": "lib/logger/test/test_helper.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n{line_exclude, line_include} =\n  if line = System.get_env(\"LINE\"), do: {[:test], [line: line]}, else: {[], []}\n\nCode.require_file(\"../../elixir/scripts/cover_record.exs\", __DIR__)\nCoverageRecorder.maybe_record(\"logger\")\n\nmaybe_seed_opt = if seed = System.get_env(\"SEED\"), do: [seed: String.to_integer(seed)], else: []\n\nex_unit_opts =\n  [\n    trace: !!System.get_env(\"TRACE\"),\n    include: line_include,\n    exclude: line_exclude,\n    assert_receive_timeout: String.to_integer(System.get_env(\"ELIXIR_ASSERT_TIMEOUT\", \"300\"))\n  ] ++ maybe_seed_opt\n\nExUnit.start(ex_unit_opts)\n\ndefmodule Logger.Case do\n  use ExUnit.CaseTemplate\n  import ExUnit.CaptureIO\n\n  using _ do\n    quote do\n      import Logger.Case\n    end\n  end\n\n  def msg(msg) do\n    ~r/\\d\\d\\:\\d\\d\\:\\d\\d\\.\\d\\d\\d #{Regex.escape(msg)}/\n  end\n\n  def wait_for_handler(manager, handler) do\n    if handler not in :gen_event.which_handlers(manager) do\n      Process.sleep(10)\n      wait_for_handler(manager, handler)\n    end\n  end\n\n  def wait_for_logger() do\n    try do\n      :gen_event.which_handlers(Logger)\n    catch\n      :exit, _ ->\n        Process.sleep(10)\n        wait_for_logger()\n    else\n      _ ->\n        :ok\n    end\n  end\n\n  def capture_log(level \\\\ :debug, fun) do\n    Logger.configure(level: level)\n\n    capture_io(:user, fn ->\n      fun.()\n      Logger.flush()\n    end)\n  after\n    Logger.configure(level: :debug)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/app_loader.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Mix.AppLoader do\n  @moduledoc false\n\n  @manifest_vsn 1\n  @manifest \"compile.app_cache\"\n\n  @doc \"\"\"\n  Reads the app cache.\n  \"\"\"\n  def read_cache(config \\\\ Mix.Project.config()) do\n    try do\n      manifest(config) |> File.read!() |> :erlang.binary_to_term()\n    rescue\n      _ -> []\n    else\n      {@manifest_vsn, app_to_modules} -> app_to_modules\n    end\n  end\n\n  @doc \"\"\"\n  Writes to the cache.\n  \"\"\"\n  def write_cache(manifest, contents) when is_map(contents) do\n    term = {@manifest_vsn, contents}\n    File.mkdir_p!(Path.dirname(manifest))\n    File.write!(manifest, :erlang.term_to_binary(term, [:compressed]))\n  end\n\n  @doc \"\"\"\n  Returns the path to the cache only if it is stale.\n  \"\"\"\n  def stale_cache(config \\\\ Mix.Project.config()) do\n    manifest = manifest(config)\n    modified = Mix.Utils.last_modified(manifest)\n\n    # We depend both on the lockfile via compile.lock (a build artifact) via\n    # `config_mtime` and `project_file`. Ideally we compare the `project_file`\n    # timestamp (a source artifact) against its old timestamp (instead of the\n    # manifest timestamp which is a build artifact), but at the moment there\n    # is no trivial place to store it.\n    if Mix.Utils.stale?([Mix.Project.config_mtime(), Mix.Project.project_file()], [modified]) do\n      manifest\n    else\n      List.first(\n        for %{app: app, scm: scm, opts: opts} <- Mix.Dep.cached(),\n            not scm.fetchable?(),\n            Mix.Utils.last_modified(Path.join([opts[:build], \"ebin\", \"#{app}.app\"])) >\n              modified do\n          manifest\n        end\n      )\n    end\n  end\n\n  defp manifest(config) do\n    Path.join(Mix.Project.manifest_path(config), @manifest)\n  end\n\n  @doc \"\"\"\n  Reads the given app from path in an optimized format and returns its contents.\n  \"\"\"\n  def read_app(app, app_path) do\n    case File.read(app_path) do\n      {:ok, bin} ->\n        with {:ok, tokens, _} <- :erl_scan.string(String.to_charlist(bin)),\n             {:ok, {:application, ^app, properties}} <- :erl_parse.parse_term(tokens) do\n          {:ok, properties}\n        else\n          _ -> :invalid\n        end\n\n      {:error, _} ->\n        :missing\n    end\n  end\n\n  @doc \"\"\"\n  Loads the given app from path in an optimized format and returns its contents.\n  \"\"\"\n  def load_app(app, app_path) do\n    with {:ok, properties} <- read_app(app, app_path) do\n      case :application.load({:application, app, properties}) do\n        :ok -> {:ok, properties}\n        {:error, {:already_loaded, _}} -> {:ok, properties}\n        {:error, _} -> :invalid\n      end\n    end\n  end\n\n  @doc \"\"\"\n  Loads the given applications.\n  \"\"\"\n  def load_apps(apps, deps, config, acc, fun) do\n    lib_path = to_charlist(Path.join(Mix.Project.build_path(config), \"lib\"))\n    deps_children = for dep <- deps, into: %{}, do: {dep.app, Enum.map(dep.deps, & &1.app)}\n    builtin_paths = Mix.State.builtin_apps()\n\n    (extra_apps(config) ++ apps)\n    |> traverse_apps(%{}, deps_children, builtin_paths, lib_path)\n    |> Enum.reduce(acc, fun)\n  end\n\n  defp extra_apps(config) do\n    case Keyword.get(config, :language, :elixir) do\n      :elixir -> [:ex_unit, :iex, :mix, :elixir]\n      :erlang -> [:compiler]\n    end\n  end\n\n  # We already processed this app, skip it.\n  defp traverse_apps([app | apps], seen, deps_children, builtin_paths, lib_path)\n       when is_map_key(seen, app) do\n    traverse_apps(apps, seen, deps_children, builtin_paths, lib_path)\n  end\n\n  # We haven't processed this app, emit it.\n  defp traverse_apps([app | apps], seen, deps_children, builtin_paths, lib_path) do\n    {ebin_path, dep_children} =\n      case deps_children do\n        %{^app => dep_children} -> {app_join(lib_path, app, ~c\"/ebin\"), dep_children}\n        _ -> {builtin_paths[app], []}\n      end\n\n    app_children =\n      if Application.spec(app, :vsn) do\n        app_children(app)\n      else\n        with true <- ebin_path != nil,\n             {:ok, _} <- load_app(app, app_join(ebin_path, app, ~c\".app\")) do\n          app_children(app)\n        else\n          # Optional applications won't be available\n          _ -> []\n        end\n      end\n\n    children = (dep_children -- app_children) ++ app_children\n    seen = Map.put(seen, app, true)\n    apps = children ++ apps\n    [{app, ebin_path} | traverse_apps(apps, seen, deps_children, builtin_paths, lib_path)]\n  end\n\n  # We have processed all apps.\n  defp traverse_apps([], seen, _deps_children, builtin_paths, _lib_path) do\n    # We want to keep erts in the load path but it doesn't require to be loaded.\n    case builtin_paths do\n      %{erts: path} when not is_map_key(seen, :erts) -> [{:erts, path}]\n      %{} -> []\n    end\n  end\n\n  defp app_children(app) do\n    Application.spec(app, :applications) ++ Application.spec(app, :included_applications)\n  end\n\n  defp app_join(path, app, suffix), do: path ++ ~c\"/\" ++ Atom.to_charlist(app) ++ suffix\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/cli.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.CLI do\n  @moduledoc false\n\n  @doc \"\"\"\n  Runs Mix according to the command line arguments.\n  \"\"\"\n  def main(args \\\\ System.argv(), mix_exs \\\\ System.get_env(\"MIX_EXS\") || \"mix.exs\") do\n    if env_variable_activated?(\"MIX_DEBUG\") do\n      IO.puts(\"-> Running mix CLI\")\n      {time, res} = :timer.tc(&main/3, [args, mix_exs, true])\n      IO.puts([\"<- Ran mix CLI in \", Integer.to_string(div(time, 1000)), \"ms\"])\n      res\n    else\n      main(args, mix_exs, false)\n    end\n  end\n\n  defp main(args, mix_exs, debug?) do\n    Mix.start()\n\n    if debug?, do: Mix.debug(true)\n    if env_variable_activated?(\"MIX_QUIET\"), do: Mix.shell(Mix.Shell.Quiet)\n\n    if profile = System.get_env(\"MIX_PROFILE\") do\n      flags = System.get_env(\"MIX_PROFILE_FLAGS\", \"\")\n      {opts, args} = Mix.Tasks.Profile.Tprof.parse!(OptionParser.split(flags))\n\n      if args != [] do\n        Mix.raise(\"Invalid arguments given to MIX_PROFILE_FLAGS: #{inspect(args)}\")\n      end\n\n      opts = Keyword.put_new(opts, :warmup, false)\n      Mix.State.put(:profile, {opts, String.split(profile, \",\")})\n    end\n\n    case check_for_shortcuts(args) do\n      :help ->\n        Mix.shell().info(\"Mix is a build tool for Elixir\")\n        display_usage()\n\n      :version ->\n        display_version()\n\n      nil ->\n        proceed(args, mix_exs)\n    end\n  end\n\n  defp proceed(args, mix_exs) do\n    load_dot_config()\n    load_mix_exs(args, mix_exs)\n    project = Mix.Project.get()\n    {task, args} = get_task(args, project)\n    ensure_hex(task)\n    maybe_change_env_and_target(task, project)\n    run_task(task, args)\n  end\n\n  defp load_mix_exs(args, mix_exs) do\n    if is_binary(mix_exs) and File.regular?(mix_exs) do\n      Mix.ProjectStack.post_config(state_loader: {:cli, List.first(args)})\n      old_undefined = Code.get_compiler_option(:no_warn_undefined)\n      Code.put_compiler_option(:no_warn_undefined, :all)\n      Code.compile_file(mix_exs)\n      Code.put_compiler_option(:no_warn_undefined, old_undefined)\n    end\n  end\n\n  defp get_task([\"-\" <> _ | _], project) do\n    task = \"mix #{default_task(project)}\"\n\n    Mix.shell().error(\n      \"** (Mix) Mix only recognizes the options --help and --version.\\n\" <>\n        \"You may have wanted to invoke a task instead, such as #{inspect(task)}\"\n    )\n\n    display_usage()\n    exit({:shutdown, 1})\n  end\n\n  defp get_task([h | t], _project) do\n    {h, t}\n  end\n\n  defp get_task([], nil) do\n    Mix.shell().error(\n      \"** (Mix) \\\"mix\\\" with no arguments must be executed in a directory with a mix.exs file\"\n    )\n\n    display_usage()\n    exit({:shutdown, 1})\n  end\n\n  defp get_task([], project) do\n    {default_task(project), []}\n  end\n\n  defp default_task(project) do\n    cond do\n      function_exported?(project, :cli, 0) ->\n        project.cli()[:default_task] || \"run\"\n\n      default_task = Mix.Project.config()[:default_task] ->\n        IO.warn(\"\"\"\n        setting :default_task in your mix.exs \\\"def project\\\" is deprecated, set it inside \\\"def cli\\\" instead:\n\n            def cli do\n              [default_task: #{inspect(default_task)}]\n            end\n        \"\"\")\n\n        default_task\n\n      true ->\n        \"run\"\n    end\n  end\n\n  defp run_task(name, args) do\n    try do\n      ensure_no_slashes(name)\n      # We must go through the task instead of invoking the\n      # module directly because projects like Nerves alias it.\n      Mix.Task.run(\"loadconfig\")\n      Mix.Task.run(name, args)\n    rescue\n      # We only rescue exceptions in the Mix namespace,\n      # all others pass through and raise as usual.\n      exception ->\n        case {Mix.debug?(), Map.get(exception, :mix, false)} do\n          {false, true} ->\n            simplified_exception(exception, 1)\n\n          {false, code} when code in 0..255 ->\n            simplified_exception(exception, code)\n\n          _ ->\n            reraise exception, __STACKTRACE__\n        end\n    end\n  end\n\n  defp simplified_exception(%name{} = exception, code) do\n    mod = name |> Module.split() |> hd()\n    Mix.shell().error(\"** (#{mod}) #{Exception.message(exception)}\")\n    exit({:shutdown, code})\n  end\n\n  defp env_variable_activated?(name) do\n    System.get_env(name) in ~w(1 true)\n  end\n\n  defp ensure_hex(\"local.hex\"), do: :ok\n  defp ensure_hex(_task), do: Mix.Hex.ensure_updated?()\n\n  defp ensure_no_slashes(task) do\n    if String.contains?(task, \"/\") do\n      raise Mix.NoTaskError, task: task\n    end\n  end\n\n  defp maybe_change_env_and_target(task, project) do\n    task = String.to_atom(task)\n    config = Mix.Project.config()\n\n    env = preferred_cli_env(project, task, config)\n    target = preferred_cli_target(project, task, config)\n    env && Mix.env(env)\n    target && Mix.target(target)\n\n    if env || target do\n      reload_project()\n    end\n  end\n\n  defp preferred_cli_env(project, task, config) do\n    if function_exported?(project, :cli, 0) || System.get_env(\"MIX_ENV\") do\n      nil\n    else\n      value = config[:preferred_cli_env]\n\n      if value do\n        IO.warn(\"\"\"\n        setting :preferred_cli_env in your mix.exs \\\"def project\\\" is deprecated, set it inside \\\"def cli\\\" instead:\n\n            def cli do\n              [preferred_envs: #{inspect(value)}]\n            end\n        \"\"\")\n      end\n\n      value[task] || preferred_cli_env(task)\n    end\n  end\n\n  defp preferred_cli_target(project, task, config) do\n    if function_exported?(project, :cli, 0) || System.get_env(\"MIX_TARGET\") do\n      nil\n    else\n      value = config[:preferred_cli_target]\n\n      if value do\n        IO.warn(\"\"\"\n        setting :preferred_cli_target in your mix.exs \\\"def project\\\" is deprecated, set it inside \\\"def cli\\\" instead:\n\n            def cli do\n              [preferred_targets: #{inspect(value)}]\n            end\n        \"\"\")\n      end\n\n      value[task]\n    end\n  end\n\n  @doc \"\"\"\n  Available for backwards compatibility.\n  \"\"\"\n  def preferred_cli_env(task) when is_atom(task) or is_binary(task) do\n    case Mix.Task.get(task) do\n      nil ->\n        nil\n\n      module ->\n        case List.keyfind(module.__info__(:attributes), :preferred_cli_env, 0) do\n          {:preferred_cli_env, [setting]} ->\n            IO.warn(\n              \"\"\"\n              setting @preferred_cli_env is deprecated inside Mix tasks.\n              Please remove it from #{inspect(module)} and set your preferred environment in mix.exs instead:\n\n                  def cli do\n                    [\n                      preferred_envs: [docs: \"docs\"]\n                    ]\n                  end\n              \"\"\",\n              []\n            )\n\n            setting\n\n          _ ->\n            nil\n        end\n    end\n  end\n\n  defp reload_project() do\n    if project = Mix.Project.pop() do\n      %{name: name, file: file} = project\n      Mix.Project.push(name, file)\n    end\n  end\n\n  defp load_dot_config do\n    path = Path.join(Mix.Utils.mix_config(), \"config.exs\")\n\n    if File.regular?(path) do\n      Mix.Tasks.Loadconfig.load_compile(path)\n    end\n  end\n\n  defp display_version do\n    IO.puts(:erlang.system_info(:system_version))\n    IO.puts(\"Mix \" <> System.build_info()[:build])\n  end\n\n  defp display_usage do\n    Mix.shell().info(\"\"\"\n\n    Usage: mix [task]\n\n    Examples:\n\n        mix             - Invokes the default task (mix run) in a project\n        mix new PATH    - Creates a new Elixir project at the given path\n        mix help        - Lists all available tasks\n        mix help TASK   - Prints documentation for a given task\n\n    The --help and --version options can be given instead of a task for usage and versioning information.\n    \"\"\")\n  end\n\n  # Check for --help or --version in the args\n  defp check_for_shortcuts([arg]) when arg in [\"--help\", \"-h\"], do: :help\n\n  defp check_for_shortcuts([arg]) when arg in [\"--version\", \"-v\"], do: :version\n\n  defp check_for_shortcuts(_), do: nil\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/compilers/elixir.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Compilers.Elixir do\n  @moduledoc false\n\n  @manifest_vsn 33\n  @checkpoint_vsn 4\n\n  import Record\n\n  defrecord :module, [:kind, :sources, :export, :recompile?, :timestamp]\n\n  defrecord :source,\n    size: 0,\n    mtime: 0,\n    digest: nil,\n    compile_references: [],\n    export_references: [],\n    runtime_references: [],\n    compile_env: [],\n    external: [],\n    compile_warnings: [],\n    runtime_warnings: [],\n    modules: []\n\n  @doc \"\"\"\n  Compiles stale Elixir files.\n\n  It expects a `manifest` file, the source directories, the destination\n  directory, the cache key based on compiler configuration, external\n  manifests, and external modules, followed by opts.\n\n  The `manifest` is written down with information including dependencies\n  between modules, which helps it recompile only the modules that\n  have changed at runtime.\n  \"\"\"\n  def compile(manifest, srcs, dest, new_cache_key, new_parent_manifests, new_parents, opts) do\n    Mix.ensure_application!(:crypto)\n    modified = Mix.Utils.last_modified(manifest)\n    config_mtime = Mix.Project.config_mtime()\n    project_mtime = Mix.Utils.last_modified(Mix.Project.project_file())\n    new_parents = :ordsets.from_list(new_parents)\n\n    # We fetch the time from before we read files so any future\n    # change to files are still picked up by the compiler. This\n    # timestamp is used when writing BEAM files and the manifest.\n    timestamp = System.os_time(:second)\n    all_paths = Mix.Utils.extract_files(srcs, [:ex])\n\n    {all_modules, all_sources, all_local_exports, old_parents, old_cache_key, old_cwd,\n     old_deps_config, old_project_mtime, old_config_mtime, old_protocols_and_impls} =\n      parse_manifest(manifest, dest)\n\n    # In case we aborted in the middle of a verification,\n    # we need to delete all modules that we wrote to disk.\n    # In the future, we may want to make it so we only run\n    # the verification again.\n    with {:ok, modules} <- parse_checkpoint(:verify, manifest) do\n      for module <- modules do\n        File.rm(Path.join(dest, Atom.to_string(module) <> \".beam\"))\n      end\n    end\n\n    # Prepend ourselves early because of __mix_recompile__? checks\n    # and also that, in case of nothing compiled, we already need\n    # ourselves available in the path.\n    File.mkdir_p!(dest)\n    Code.prepend_path(dest)\n\n    # If modules have been added or removed from the Erlang compiler,\n    # we need to recompile all references to old and new modules.\n    stale =\n      if old_parents != new_parents or\n           Mix.Utils.stale?(new_parent_manifests, [modified]) do\n        :ordsets.union(old_parents, new_parents)\n      else\n        []\n      end\n\n    local_deps = Enum.reject(Mix.Dep.cached(), & &1.scm.fetchable?())\n\n    # If mix.exs has changed, recompile anything that calls Mix.Project.\n    stale =\n      if project_mtime > old_project_mtime,\n        do: [Mix.Project | stale],\n        else: stale\n\n    # If the lock has changed or a local dependency was added or removed,\n    # we need to traverse lock/config files.\n    deps_changed? =\n      config_mtime > old_config_mtime or\n        local_deps_changed?(old_deps_config, local_deps)\n\n    # If a configuration is only accessed at compile-time, we don't need to\n    # track modules, only the compile env. So far this is only true for Elixir's\n    # dbg callback.\n    compile_env_apps = deps_config_compile_env_apps(old_deps_config)\n\n    {force?, stale, new_deps_config} =\n      cond do\n        !!opts[:force] or is_nil(old_deps_config) or old_cache_key != new_cache_key or\n            (Keyword.get(opts, :check_cwd, true) and old_cwd != File.cwd!()) ->\n          {true, stale, deps_config(local_deps)}\n\n        deps_changed? or compile_env_apps != [] ->\n          new_deps_config = deps_config(local_deps)\n          local_apps = merge_appset(old_deps_config.local, new_deps_config.local, [])\n          config_apps = merge_appset(old_deps_config.config, new_deps_config.config, local_apps)\n          apps = merge_appset(old_deps_config.lock, new_deps_config.lock, config_apps)\n\n          if Mix.Project.config()[:app] in apps do\n            {true, stale, new_deps_config}\n          else\n            app_modules = Mix.AppLoader.read_cache()\n\n            apps_stale =\n              apps\n              |> deps_on()\n              |> Enum.flat_map(fn {app, _} ->\n                new_modules = Application.spec(app, :modules) || []\n\n                if old_modules = app_modules[app] do\n                  :ordsets.union(old_modules, :ordsets.from_list(new_modules))\n                else\n                  new_modules\n                end\n              end)\n\n            compile_env_apps = compile_env_apps ++ config_apps\n\n            compile_env_stale =\n              for {_, source(compile_env: compile_env, modules: modules)} <- all_sources,\n                  Enum.any?(compile_env_apps, &List.keymember?(compile_env, &1, 0)),\n                  module <- modules,\n                  do: module\n\n            stale = (stale ++ compile_env_stale) ++ apps_stale\n            {false, stale, new_deps_config}\n          end\n\n        true ->\n          {false, stale, old_deps_config}\n      end\n\n    {stale_modules, stale_exports, all_local_exports, protocols_and_impls} =\n      stale_local_deps(local_deps, manifest, stale, modified, all_local_exports)\n\n    prev_paths = Map.keys(all_sources)\n    removed = prev_paths -- all_paths\n    {sources, removed_modules} = remove_removed_sources(all_sources, removed)\n\n    {modules, exports, changed, sources_stats} =\n      if force? do\n        compiler_info_from_force(manifest, all_paths, all_modules, dest)\n      else\n        compiler_info_from_updated(\n          manifest,\n          all_paths -- prev_paths,\n          all_modules,\n          all_sources,\n          removed,\n          Map.merge(stale_modules, removed_modules),\n          Map.merge(stale_exports, removed_modules),\n          dest,\n          timestamp\n        )\n      end\n\n    stale = changed -- removed\n\n    {sources, stale_exports} =\n      update_stale_sources(sources, stale, removed_modules, sources_stats)\n\n    consolidation_status =\n      if Mix.Project.umbrella?() do\n        :off\n      else\n        Mix.Compilers.Protocol.status(config_mtime > old_config_mtime, opts)\n      end\n\n    consolidate? =\n      consolidation_status == :force or (deps_changed? and consolidation_status != :off)\n\n    if stale != [] or stale_modules != %{} or removed != [] or consolidate? do\n      path = opts[:purge_consolidation_path_if_stale]\n\n      if is_binary(path) and Code.delete_path(path) do\n        purge_modules_in_path(path)\n      end\n\n      if stale != [] do\n        Mix.Utils.compiling_n(length(stale), :ex)\n      end\n\n      Mix.Project.ensure_structure()\n      previous_opts = set_compiler_opts(opts)\n\n      try do\n        consolidation = {consolidation_status, old_protocols_and_impls, protocols_and_impls}\n\n        state = %{\n          modules: %{},\n          exports: exports,\n          sources: sources,\n          changed: [],\n          pending_modules: modules,\n          stale_exports: stale_exports,\n          consolidation: consolidation\n        }\n\n        compiler_loop(manifest, stale, stale_modules, dest, timestamp, opts, state)\n      else\n        {:ok, %{runtime_warnings: runtime_warnings, compile_warnings: compile_warnings}, state} ->\n          %{\n            modules: modules,\n            sources: sources,\n            pending_modules: pending_modules,\n            consolidation: protocols_and_impls\n          } = state\n\n          previous_warnings =\n            if Keyword.get(opts, :all_warnings, true),\n              do: previous_warnings(sources, true),\n              else: []\n\n          runtime_warnings = Enum.map(runtime_warnings, &diagnostic/1)\n          compile_warnings = Enum.map(compile_warnings, &diagnostic/1)\n          sources = apply_warnings(sources, runtime_warnings, compile_warnings)\n\n          write_manifest(\n            manifest,\n            Map.merge(modules, pending_modules),\n            sources,\n            all_local_exports,\n            new_parents,\n            new_cache_key,\n            new_deps_config,\n            project_mtime,\n            config_mtime,\n            protocols_and_impls,\n            timestamp\n          )\n\n          put_compile_env(sources)\n          all_warnings = previous_warnings ++ runtime_warnings ++ compile_warnings\n\n          lazy_modules_diff = fn ->\n            modules_diff(modules, removed_modules, all_modules, timestamp)\n          end\n\n          Mix.Task.Compiler.notify_modules_compiled(lazy_modules_diff)\n          unless_warnings_as_errors(opts, {:ok, all_warnings})\n\n        {:error, errors, %{runtime_warnings: r_warnings, compile_warnings: c_warnings}, state} ->\n          {errors, warnings} =\n            if opts[:warnings_as_errors],\n              do: {errors ++ r_warnings ++ c_warnings, []},\n              else: {errors, r_warnings ++ c_warnings}\n\n          # In case of errors, we show all previous warnings and all new ones.\n          errors = Enum.map(errors, &diagnostic/1)\n          warnings = Enum.map(warnings, &diagnostic/1)\n          all_warnings = Keyword.get(opts, :all_warnings, errors == [])\n          {:error, previous_warnings(state.sources, all_warnings) ++ warnings ++ errors}\n      after\n        Code.compiler_options(previous_opts)\n      end\n    else\n      # Only the dependencies changed but nothing was recompiled,\n      # so we need to update the config_mtime configuration but\n      # keep its original timestamp so recompilation does not cascade.\n      if deps_changed? do\n        write_manifest(\n          manifest,\n          all_modules,\n          all_sources,\n          all_local_exports,\n          old_parents,\n          old_cache_key,\n          old_deps_config,\n          old_project_mtime,\n          config_mtime,\n          old_protocols_and_impls,\n          modified\n        )\n      end\n\n      all_warnings = Keyword.get(opts, :all_warnings, true)\n      previous_warnings = previous_warnings(sources, all_warnings)\n      unless_warnings_as_errors(opts, {:noop, previous_warnings})\n    end\n  end\n\n  defp deps_config(local_deps) do\n    # If you change this config, you need to bump @manifest_vsn\n    %{\n      local: Enum.sort(Enum.map(local_deps, &{&1.app, true})),\n      lock:\n        Mix.Dep.Lock.read()\n        |> Map.take(Mix.Project.deps_apps())\n        |> Enum.sort(),\n      config: Enum.sort(Mix.Tasks.Loadconfig.read_compile()),\n      dbg: Application.fetch_env!(:elixir, :dbg_callback)\n    }\n  end\n\n  defp local_deps_changed?(deps_config, local_deps) do\n    is_map(deps_config) and Enum.sort(Enum.map(local_deps, &{&1.app, true})) != deps_config.local\n  end\n\n  defp deps_config_compile_env_apps(deps_config) do\n    if deps_config[:dbg] != Application.fetch_env!(:elixir, :dbg_callback) do\n      [:elixir]\n    else\n      []\n    end\n  end\n\n  @doc \"\"\"\n  Removes compiled files for the given `manifest`.\n  \"\"\"\n  def clean(manifest, compile_path) do\n    {modules, _} = read_manifest(manifest)\n    _ = File.rm(manifest)\n\n    Enum.each(modules, fn {module, _} ->\n      File.rm(beam_path(compile_path, module))\n    end)\n  end\n\n  @doc \"\"\"\n  Reads the manifest for external consumption.\n  \"\"\"\n  def read_manifest(manifest) do\n    try do\n      manifest |> File.read!() |> :erlang.binary_to_term()\n    rescue\n      _ -> {[], []}\n    else\n      {@manifest_vsn, modules, sources, _, _, _, _, _, _, _, _} -> {modules, sources}\n      _ -> {[], []}\n    end\n  end\n\n  @doc \"\"\"\n  Retrieves all diagnostics from the given manifest.\n  \"\"\"\n  def diagnostics(manifest) do\n    {_, sources} = read_manifest(manifest)\n    previous_warnings(sources, false)\n  end\n\n  defp compiler_info_from_force(manifest, all_paths, all_modules, dest) do\n    # A config, path dependency or manifest has changed, let's just compile everything\n    for {module, _} <- all_modules,\n        do: remove_and_purge(beam_path(dest, module), module)\n\n    sources_stats =\n      for path <- all_paths,\n          into: %{},\n          do: {path, Mix.Utils.last_modified_and_size(path)}\n\n    # Now that we have deleted all beams, remember to remove the manifest.\n    # This is important in case mix compile --force fails, otherwise we\n    # would have an outdated manifest.\n    File.rm(manifest)\n\n    {%{}, %{}, all_paths, sources_stats}\n  end\n\n  # If the user does a change, compilation fails, and then they revert\n  # the change, the mtime will have changed but the .beam files will\n  # be missing and the digest is the same, so we need to check if .beam\n  # files are available. Checking the first .beam file is enough, as\n  # they would be all removed. If there are no modules, then we can rely\n  # purely on digests.\n  defp missing_beam_file?(dest, [mod | _]), do: not File.exists?(beam_path(dest, mod))\n  defp missing_beam_file?(_dest, []), do: false\n\n  defp compiler_info_from_updated(\n         manifest,\n         new_paths,\n         all_modules,\n         all_sources,\n         removed,\n         stale_modules,\n         stale_exports,\n         dest,\n         timestamp\n       ) do\n    {checkpoint_stale_modules, checkpoint_stale_exports} =\n      case parse_checkpoint(:update, manifest) do\n        {:ok, {_, _} = data} -> data\n        :error -> {%{}, %{}}\n      end\n\n    stale_modules = Map.merge(checkpoint_stale_modules, stale_modules)\n    stale_exports = Map.merge(checkpoint_stale_exports, stale_exports)\n\n    # Once we added semantic recompilation, the following can happen:\n    #\n    # 1. The user changes config/mix.exs/__mix_recompile__?\n    # 2. We detect the change, remove .beam files and start recompilation\n    # 3. Recompilation fails\n    # 4. The user reverts the change\n    # 5. The compiler no longer recompiles and the .beam files are missing\n    #\n    # Therefore, it is important for us to checkpoint any state that may\n    # have lead to a compilation and which can now be reverted.\n    if map_size(stale_modules) != map_size(checkpoint_stale_modules) or\n         map_size(stale_exports) != map_size(checkpoint_stale_exports) do\n      write_checkpoint(:update, manifest, {stale_modules, stale_exports})\n    end\n\n    # We don't need to store those in the checkpoint because\n    # these changes come from modules and, when they are stale,\n    # we remove the .beam files and touch sources.\n    modules_to_mix_check =\n      for {module, module(recompile?: true)} <- all_modules,\n          not Map.has_key?(stale_modules, module),\n          do: module\n\n    _ = Code.ensure_all_loaded(modules_to_mix_check)\n\n    modules_to_recompile =\n      for {:ok, {module, true}} <-\n            Task.async_stream(\n              modules_to_mix_check,\n              fn module ->\n                {module,\n                 function_exported?(module, :__mix_recompile__?, 0) and\n                   module.__mix_recompile__?()}\n              end,\n              ordered: false,\n              timeout: :infinity\n            ),\n          into: %{} do\n        {module, true}\n      end\n\n    sources_stats =\n      for path <- new_paths,\n          into: mtimes_and_sizes(all_sources),\n          do: {path, Mix.Utils.last_modified_and_size(path)}\n\n    # Sources that have changed on disk or\n    # any modules associated with them need to be recompiled\n    changed =\n      Enum.flat_map(all_sources, fn\n        {source,\n         source(external: external, size: size, mtime: mtime, digest: digest, modules: modules)} ->\n          {last_mtime, last_size} = Map.fetch!(sources_stats, source)\n\n          cond do\n            Enum.any?(external, &stale_external?(&1, sources_stats)) or\n                has_any_key?(modules_to_recompile, modules) ->\n              # Mark the source as changed so the combination of a timestamp\n              # plus removed beam files (which are removed by update_stale_entries)\n              # causes it to be recompiled. Note we don't raise use touch! because\n              # in case of checkpoints the file may have been removed.\n              File.touch(source, timestamp + 1)\n              [source]\n\n            size != last_size or\n              has_any_key?(stale_modules, modules) or\n                (last_mtime != mtime and\n                   (missing_beam_file?(dest, modules) or digest_changed?(source, digest))) ->\n              [source]\n\n            true ->\n              []\n          end\n      end)\n\n    changed = new_paths ++ changed\n\n    {modules, exports, changed} =\n      update_stale_entries(\n        all_modules,\n        all_sources,\n        removed ++ changed,\n        stale_modules,\n        stale_exports,\n        dest\n      )\n\n    # Now sort the files so the ones changed more recently come first.\n    # We do an optimized version of sort_by since we don't care about\n    # stable sorting.\n    changed =\n      changed\n      |> Enum.map(&{-elem(Map.fetch!(sources_stats, &1), 0), &1})\n      |> Enum.sort()\n      |> Enum.map(&elem(&1, 1))\n\n    {modules, exports, changed, sources_stats}\n  end\n\n  defp stale_external?({external, {mtime, size}, digest}, sources_stats) do\n    case sources_stats do\n      %{^external => {0, 0}} ->\n        digest != nil\n\n      %{^external => {last_mtime, last_size}} ->\n        size != last_size or (last_mtime != mtime and digest_changed?(external, digest))\n    end\n  end\n\n  defp mtimes_and_sizes(sources) do\n    Enum.reduce(sources, %{}, fn {source, source(external: external)}, map ->\n      map = Map.put_new_lazy(map, source, fn -> Mix.Utils.last_modified_and_size(source) end)\n\n      Enum.reduce(external, map, fn {file, _, _}, map ->\n        Map.put_new_lazy(map, file, fn -> Mix.Utils.last_modified_and_size(file) end)\n      end)\n    end)\n  end\n\n  defp digest_changed?(file, digest) do\n    case File.read(file) do\n      {:ok, binary} -> digest != digest_contents(binary)\n      {:error, _} -> true\n    end\n  end\n\n  defp digest_contents(contents) do\n    case :erlang.system_info(:wordsize) do\n      8 -> :crypto.hash(:blake2b, contents)\n      _ -> :crypto.hash(:blake2s, contents)\n    end\n  rescue\n    # Blake may not be available on all OpenSSL distribution\n    _ -> :erlang.md5(contents)\n  end\n\n  defp set_compiler_opts(opts) do\n    opts\n    |> Keyword.take(Code.available_compiler_options())\n    |> Code.compiler_options()\n  end\n\n  defp put_compile_env(sources) do\n    all_compile_env =\n      Enum.reduce(sources, :ordsets.new(), fn {_, source(compile_env: compile_env)}, acc ->\n        :ordsets.union(compile_env, acc)\n      end)\n\n    Mix.ProjectStack.compile_env(all_compile_env)\n  end\n\n  ## Resolution\n\n  defp remove_removed_sources(sources, removed) do\n    Enum.reduce(removed, {sources, %{}}, fn file, {acc_sources, acc_modules} ->\n      {source(modules: modules), acc_sources} = Map.pop(acc_sources, file)\n      acc_modules = Enum.reduce(modules, acc_modules, &Map.put(&2, &1, true))\n      {acc_sources, acc_modules}\n    end)\n  end\n\n  # Initial definition of empty records for changed sources\n  # as the compiler appends data. This may include new files,\n  # so we rely on sources_stats to avoid multiple FS lookups.\n  defp update_stale_sources(sources, stale, removed_modules, sources_stats) do\n    Enum.reduce(stale, {sources, removed_modules}, fn file, {acc_sources, acc_modules} ->\n      %{^file => {mtime, size}} = sources_stats\n\n      modules =\n        case acc_sources do\n          %{^file => source(modules: modules)} -> modules\n          %{} -> []\n        end\n\n      acc_modules = Enum.reduce(modules, acc_modules, &Map.put(&2, &1, true))\n      {Map.put(acc_sources, file, source(size: size, mtime: mtime)), acc_modules}\n    end)\n  end\n\n  # This function receives the manifest entries and some source\n  # files that have changed. Then it recursively figures out\n  # all the files that changed (via the module dependencies) and\n  # return the non-changed entries and the removed sources.\n  defp update_stale_entries(modules, _sources, [], stale_modules, stale_exports, _compile_path)\n       when stale_modules == %{} and stale_exports == %{} do\n    {modules, %{}, []}\n  end\n\n  defp update_stale_entries(modules, sources, changed, stale_modules, stale_exports, compile_path) do\n    changed = Map.from_keys(changed, true)\n    reducer = &remove_stale_entry(&1, &2, sources, stale_exports, compile_path)\n    remove_stale_entries(modules, %{}, changed, stale_modules, reducer)\n  end\n\n  defp remove_stale_entries(modules, exports, old_changed, old_stale, reducer) do\n    {pending_modules, exports, new_changed, new_stale} =\n      Enum.reduce(modules, {modules, exports, old_changed, old_stale}, reducer)\n\n    if map_size(new_stale) > map_size(old_stale) or map_size(new_changed) > map_size(old_changed) do\n      remove_stale_entries(pending_modules, exports, new_changed, new_stale, reducer)\n    else\n      {pending_modules, exports, Map.keys(new_changed)}\n    end\n  end\n\n  defp remove_stale_entry(entry, acc, sources, stale_exports, compile_path) do\n    {module, module(sources: source_files, export: export)} = entry\n    {pending_modules, exports, changed, stale_modules} = acc\n\n    {compile_references, export_references, runtime_references} =\n      Enum.reduce(source_files, {[], [], []}, fn file, {compile_acc, export_acc, runtime_acc} ->\n        source(\n          compile_references: compile_refs,\n          export_references: export_refs,\n          runtime_references: runtime_refs\n        ) = Map.fetch!(sources, file)\n\n        {compile_acc ++ compile_refs, export_acc ++ export_refs, runtime_acc ++ runtime_refs}\n      end)\n\n    cond do\n      # If I changed in disk or have a compile time reference to\n      # something stale or have a reference to an old export,\n      # I need to be recompiled.\n      has_any_key?(changed, source_files) or has_any_key?(stale_modules, compile_references) or\n          has_any_key?(stale_exports, export_references) ->\n        remove_and_purge(beam_path(compile_path, module), module)\n        changed = Enum.reduce(source_files, changed, &Map.put(&2, &1, true))\n\n        {Map.delete(pending_modules, module), Map.put(exports, module, export), changed,\n         Map.put(stale_modules, module, true)}\n\n      # If I have a runtime references to something stale,\n      # I am stale too.\n      has_any_key?(stale_modules, runtime_references) ->\n        {pending_modules, exports, changed, Map.put(stale_modules, module, true)}\n\n      # Otherwise, we don't store it anywhere\n      true ->\n        {pending_modules, exports, changed, stale_modules}\n    end\n  end\n\n  defp has_any_key?(map, enumerable) do\n    map != %{} and Enum.any?(enumerable, &Map.has_key?(map, &1))\n  end\n\n  defp stale_local_deps(local_deps, manifest, stale_modules, modified, deps_exports) do\n    base = Path.basename(manifest)\n\n    # The stale modules so far will become both stale_modules and stale_exports,\n    # as any export from a dependency needs to be recompiled.\n    stale_modules = Map.from_keys(stale_modules, true)\n\n    for %{app: app, opts: opts} <- local_deps,\n        manifest = Path.join([opts[:build], \".mix\", base]),\n        Mix.Utils.last_modified(manifest) > modified,\n        reduce: {stale_modules, stale_modules, deps_exports, protocols_and_impls()} do\n      {modules, exports, deps_exports, protocols_and_impls} ->\n        {manifest_modules, manifest_sources} = read_manifest(manifest)\n\n        dep_modules =\n          for {module, module(timestamp: timestamp)} <- manifest_modules,\n              timestamp > modified,\n              do: module\n\n        # If any module has a compile time dependency on a changed module\n        # within the dependency, they will be recompiled. However, export\n        # and runtime dependencies won't have recompiled so we need to\n        # propagate them to the parent app.\n        dep_modules =\n          fixpoint_non_compile_modules(manifest_sources, Map.from_keys(dep_modules, true))\n\n        old_exports = Map.get(deps_exports, app, %{})\n\n        # Update exports\n        {exports, new_exports} =\n          for {module, _} <- dep_modules, reduce: {exports, []} do\n            {exports, new_exports} ->\n              export =\n                if Code.ensure_loaded?(module) and function_exported?(module, :__info__, 1) do\n                  module.__info__(:exports_md5)\n                end\n\n              # If the exports are the same, then the API did not change,\n              # so we do not mark the export as stale. Note this has to\n              # be very conservative. If the module is not loaded or if\n              # the exports were not there, we need to consider it a stale\n              # export.\n              exports =\n                if export && old_exports[module] == export,\n                  do: exports,\n                  else: Map.put(exports, module, true)\n\n              # Then we store the new export if any\n              new_exports =\n                if export,\n                  do: [{module, export} | new_exports],\n                  else: new_exports\n\n              {exports, new_exports}\n          end\n\n        new_exports = Map.new(new_exports)\n\n        removed =\n          for {module, _} <- old_exports,\n              not is_map_key(new_exports, module),\n              do: {module, true},\n              into: %{}\n\n        modules = modules |> Map.merge(dep_modules) |> Map.merge(removed)\n        exports = Map.merge(exports, removed)\n        deps_exports = Map.put(deps_exports, app, new_exports)\n\n        protocols_and_impls =\n          protocols_and_impls_from_modules(manifest_modules, protocols_and_impls)\n\n        {modules, exports, deps_exports, protocols_and_impls}\n    end\n  end\n\n  defp fixpoint_non_compile_modules(sources, modules) when modules != %{} do\n    fixpoint_non_compile_modules(Map.to_list(sources), modules, false, [])\n  end\n\n  defp fixpoint_non_compile_modules(_sources, modules) do\n    modules\n  end\n\n  defp fixpoint_non_compile_modules(\n         [{_source_path, source_entry} = pair | sources],\n         modules,\n         new?,\n         pending_sources\n       ) do\n    source(export_references: export_refs, runtime_references: runtime_refs) = source_entry\n\n    if has_any_key?(modules, export_refs) or has_any_key?(modules, runtime_refs) do\n      new_modules = Enum.reject(source(source_entry, :modules), &Map.has_key?(modules, &1))\n      modules = Enum.reduce(new_modules, modules, &Map.put(&2, &1, true))\n      new? = new? or new_modules != []\n      fixpoint_non_compile_modules(sources, modules, new?, pending_sources)\n    else\n      pending_sources = [pair | pending_sources]\n      fixpoint_non_compile_modules(sources, modules, new?, pending_sources)\n    end\n  end\n\n  defp fixpoint_non_compile_modules([], modules, new?, pending_sources)\n       when new? == false or pending_sources == [],\n       do: modules\n\n  defp fixpoint_non_compile_modules([], modules, true, pending_sources),\n    do: fixpoint_non_compile_modules(pending_sources, modules, false, [])\n\n  defp remove_and_purge(beam, module) do\n    _ = File.rm(beam)\n\n    if Code.loaded?(module) do\n      :code.purge(module)\n      :code.delete(module)\n    end\n  end\n\n  defp purge_modules_in_path(path) do\n    with {:ok, beams} <- File.ls(path) do\n      Enum.each(beams, fn beam ->\n        module = beam |> Path.rootname() |> String.to_atom()\n\n        if Code.loaded?(module) do\n          :code.purge(module)\n          :code.delete(module)\n        end\n      end)\n    end\n  end\n\n  defp previous_warnings(sources, print?) do\n    for {_, source(compile_warnings: compile_warnings, runtime_warnings: runtime_warnings)} <-\n          sources,\n        diagnostic <- compile_warnings ++ runtime_warnings do\n      if print? do\n        Mix.shell().print_app()\n        Code.print_diagnostic(diagnostic)\n      end\n\n      diagnostic\n    end\n  end\n\n  defp apply_warnings(sources, [], []) do\n    sources\n  end\n\n  defp apply_warnings(sources, runtime_warnings, compile_warnings) do\n    cwd = File.cwd!()\n    runtime_group = Enum.group_by(runtime_warnings, & &1.source)\n    compile_group = Enum.group_by(compile_warnings, & &1.source)\n\n    for {source_path, source_entry} <- sources, into: %{} do\n      source(\n        runtime_warnings: runtime_warnings,\n        compile_warnings: compile_warnings,\n        external: external\n      ) = source_entry\n\n      keys = [\n        Path.absname(source_path, cwd)\n        | Enum.map(external, &(&1 |> elem(0) |> Path.absname(cwd)))\n      ]\n\n      runtime_warnings =\n        case Enum.flat_map(keys, &Map.get(runtime_group, &1, [])) do\n          [] -> runtime_warnings\n          runtime_warnings -> runtime_warnings\n        end\n\n      compile_warnings =\n        case Enum.flat_map(keys, &Map.get(compile_group, &1, [])) do\n          [] -> compile_warnings\n          compile_warnings -> compile_warnings\n        end\n\n      {source_path,\n       source(source_entry,\n         runtime_warnings: runtime_warnings,\n         compile_warnings: compile_warnings\n       )}\n    end\n  end\n\n  defp diagnostic(\n         %{\n           file: file,\n           position: position,\n           message: message,\n           severity: severity,\n           stacktrace: stacktrace,\n           span: span,\n           source: source\n         } = diagnostic\n       ) do\n    %Mix.Task.Compiler.Diagnostic{\n      file: file,\n      source: source,\n      position: position,\n      message: message,\n      severity: severity,\n      compiler_name: \"Elixir\",\n      stacktrace: stacktrace,\n      span: span,\n      details: Map.get(diagnostic, :details, nil)\n    }\n  end\n\n  ## Merging of lock and config files\n\n  # Value for app didn't change\n  defp merge_appset([{app, value} | old_set], [{app, value} | new_set], apps),\n    do: merge_appset(old_set, new_set, apps)\n\n  # Value for app changed\n  defp merge_appset([{app, _} | old_set], [{app, _} | new_set], apps),\n    do: merge_appset(old_set, new_set, [app | apps])\n\n  # Added value for app\n  defp merge_appset([{app1, _} | _] = old_set, [{app2, _} | new_set], apps)\n       when app1 > app2,\n       do: merge_appset(old_set, new_set, [app2 | apps])\n\n  # Removed value for app\n  defp merge_appset([{app1, _} | old_set], [{app2, _} | _] = new_set, apps)\n       when app1 < app2,\n       do: merge_appset(old_set, new_set, [app1 | apps])\n\n  # One of them is done, add the others\n  defp merge_appset(old_set, new_set, apps) do\n    apps = Enum.reduce(old_set, apps, fn {app, _}, apps -> [app | apps] end)\n    Enum.reduce(new_set, apps, fn {app, _}, apps -> [app | apps] end)\n  end\n\n  defp deps_on(apps) do\n    apps = Map.from_keys(apps, true)\n    deps_on(Mix.Dep.cached(), apps, [], false)\n  end\n\n  defp deps_on([%{app: app, deps: deps} = dep | cached_deps], apps, acc, stored?) do\n    cond do\n      # We have already seen this dep\n      Map.has_key?(apps, app) ->\n        deps_on(cached_deps, apps, acc, stored?)\n\n      # It depends on one of the apps, store it\n      Enum.any?(deps, &Map.has_key?(apps, &1.app)) ->\n        deps_on(cached_deps, Map.put(apps, app, true), acc, true)\n\n      # Otherwise we will check it later\n      true ->\n        deps_on(cached_deps, apps, [dep | acc], stored?)\n    end\n  end\n\n  defp deps_on([], apps, cached_deps, true), do: deps_on(cached_deps, apps, [], false)\n  defp deps_on([], apps, _cached_deps, false), do: apps\n\n  ## Manifest handling\n\n  @default_manifest {%{}, %{}, %{}, [], nil, nil, nil, 0, 0, {%{}, %{}}}\n\n  # Similar to read_manifest, but for internal consumption and with data migration support.\n  defp parse_manifest(manifest, compile_path) do\n    try do\n      manifest |> File.read!() |> :erlang.binary_to_term()\n    rescue\n      _ ->\n        @default_manifest\n    else\n      {@manifest_vsn, modules, sources, local_exports, parent, cache_key, cwd, deps_config,\n       project_mtime, config_mtime, protocols_and_impls} ->\n        {modules, sources, local_exports, parent, cache_key, cwd, deps_config, project_mtime,\n         config_mtime, protocols_and_impls}\n\n      # {vsn, %{module => record}, sources, ...} v22-?\n      # {vsn, [module_record], sources, ...} v5-v21\n      manifest when is_tuple(manifest) and is_integer(elem(manifest, 0)) ->\n        purge_old_manifest(compile_path, elem(manifest, 1))\n\n      # v1-v4\n      [vsn | data] when is_integer(vsn) ->\n        purge_old_manifest(compile_path, data)\n\n      _ ->\n        @default_manifest\n    end\n  end\n\n  defp purge_old_manifest(compile_path, data) do\n    try do\n      # If data is a list, we have an old manifest and\n      # we convert it to the same format as maps.\n      data =\n        if is_list(data) do\n          for entry <- data, elem(entry, 0) == :module do\n            {elem(entry, 1), entry}\n          end\n        else\n          data\n        end\n\n      for {module, _} <- data do\n        remove_and_purge(beam_path(compile_path, module), module)\n      end\n    rescue\n      _ ->\n        Mix.raise(\n          \"Cannot clean-up stale manifest, please run \\\"mix clean --deps\\\" manually before proceeding\"\n        )\n    end\n\n    @default_manifest\n  end\n\n  defp write_manifest(\n         manifest,\n         %{} = modules,\n         %{} = sources,\n         exports,\n         parents,\n         cache_key,\n         deps_config,\n         project_mtime,\n         config_mtime,\n         protocols_and_impls,\n         timestamp\n       ) do\n    File.mkdir_p!(Path.dirname(manifest))\n\n    term =\n      {@manifest_vsn, modules, sources, exports, parents, cache_key, File.cwd!(), deps_config,\n       project_mtime, config_mtime, protocols_and_impls}\n\n    manifest_data = :erlang.term_to_binary(term, [:compressed])\n    File.write!(manifest, manifest_data)\n    File.touch!(manifest, timestamp)\n    delete_checkpoints(manifest)\n\n    # Since Elixir is a dependency itself, we need to touch the lock\n    # so the current Elixir version, used to compile the files above,\n    # is properly stored.\n    config = Mix.Project.config()\n    Mix.Dep.ElixirSCM.update(config[:build_scm], config[:deps_lock])\n    :ok\n  end\n\n  defp beam_path(compile_path, module) do\n    Path.join(compile_path, Atom.to_string(module) <> \".beam\")\n  end\n\n  defp parse_checkpoint(type, manifest) when type in [:update, :verify] do\n    try do\n      (manifest <> \".#{type}.cp\") |> File.read!() |> :erlang.binary_to_term()\n    rescue\n      _ -> :error\n    else\n      {@checkpoint_vsn, data} -> {:ok, data}\n      _ -> :error\n    end\n  end\n\n  defp write_checkpoint(type, manifest, data) when type in [:update, :verify] do\n    File.mkdir_p!(Path.dirname(manifest))\n    term = {@checkpoint_vsn, data}\n    checkpoint_data = :erlang.term_to_binary(term)\n    File.write!(manifest <> \".#{type}.cp\", checkpoint_data)\n  end\n\n  defp delete_checkpoints(manifest) do\n    File.rm(manifest <> \".update.cp\")\n    File.rm(manifest <> \".verify.cp\")\n  end\n\n  defp unless_warnings_as_errors(opts, {status, all_warnings}) do\n    if all_warnings != [] and opts[:warnings_as_errors] do\n      message = \"Compilation failed due to warnings while using the --warnings-as-errors option\"\n      IO.puts(:stderr, message)\n      {:error, all_warnings}\n    else\n      {status, all_warnings}\n    end\n  end\n\n  defp modules_diff(compiled_modules, removed_modules, all_modules, timestamp) do\n    {changed, added} =\n      compiled_modules\n      |> Map.keys()\n      |> Enum.split_with(&Map.has_key?(all_modules, &1))\n\n    # Note that removed_modules may also include changed modules\n    removed =\n      for {module, _} <- removed_modules, not Map.has_key?(compiled_modules, module), do: module\n\n    %{\n      added: added,\n      changed: changed,\n      removed: removed,\n      timestamp: timestamp\n    }\n  end\n\n  ## Compiler loop\n  # The compiler is invoked in a separate process so we avoid blocking its main loop.\n\n  defp compiler_loop(manifest, stale, stale_modules, dest, timestamp, opts, state) do\n    ref = make_ref()\n    parent = self()\n    compilation_threshold = opts[:long_compilation_threshold] || 10\n    verification_threshold = opts[:long_verification_threshold] || 10\n    verbose = Keyword.get(opts, :verbose, false)\n    verification = Keyword.get(opts, :verification, true)\n    extra_opts = Keyword.take(opts, [:profile, :purge_compiler_modules])\n\n    if not verification and not Mix.debug?() do\n      Mix.shell().error(\"--no-verification flag is only recommended with MIX_DEBUG=1\")\n    end\n\n    pid =\n      spawn_link(fn ->\n        compile_opts = [\n          after_compile: fn ->\n            compiler_call(parent, ref, {:after_compile, manifest, opts})\n          end,\n          each_cycle: fn ->\n            compiler_call(parent, ref, {:each_cycle, stale_modules, dest, timestamp})\n          end,\n          each_file: fn file, lexical ->\n            compiler_call(parent, ref, {:each_file, file, lexical, verbose})\n          end,\n          each_module: fn file, module, _binary ->\n            compiler_call(parent, ref, {:each_module, file, module, System.os_time(:second)})\n          end,\n          each_long_compilation: fn file, pid ->\n            Mix.shell().info(\n              \"Compiling #{Path.relative_to(file, File.cwd!())} \" <>\n                \"(it's taking more than #{compilation_threshold}s)#{debug_stacktrace(pid)}\"\n            )\n          end,\n          each_long_verification: fn module, pid ->\n            Mix.shell().info(\n              \"Verifying #{inspect(module)} \" <>\n                \"(it's taking more than #{verification_threshold}s)#{debug_stacktrace(pid)}\"\n            )\n          end,\n          long_compilation_threshold: compilation_threshold,\n          long_verification_threshold: verification_threshold,\n          beam_timestamp: timestamp,\n          return_diagnostics: true,\n          verification: verification\n        ]\n\n        response =\n          Kernel.ParallelCompiler.compile_to_path(stale, dest, compile_opts ++ extra_opts)\n\n        send(parent, {ref, response})\n      end)\n\n    compiler_loop(ref, pid, state, File.cwd!())\n  end\n\n  defp compiler_call(parent, ref, info) do\n    send(parent, {ref, info})\n\n    receive do\n      {^ref, response} -> response\n    end\n  end\n\n  defp compiler_loop(ref, pid, state, cwd) do\n    receive do\n      {^ref, {:after_compile, manifest, opts}} ->\n        {response, state} = after_compile(manifest, state, opts)\n        send(pid, {ref, response})\n        compiler_loop(ref, pid, state, cwd)\n\n      {^ref, {:each_cycle, stale_modules, dest, timestamp}} ->\n        {response, state} = each_cycle(stale_modules, dest, timestamp, state)\n        send(pid, {ref, response})\n        compiler_loop(ref, pid, state, cwd)\n\n      {^ref, {:each_file, file, lexical, verbose}} ->\n        # Read the relevant file information and unblock the compiler\n        references = Kernel.LexicalTracker.references(lexical)\n        send(pid, {ref, :ok})\n        state = each_file(file, references, verbose, state, cwd)\n        compiler_loop(ref, pid, state, cwd)\n\n      {^ref, {:each_module, file, module, timestamp}} ->\n        # Read the relevant module information and unblock the compiler\n        kind = detect_kind(module)\n        external = Module.get_attribute(module, :external_resource)\n        new_export = Module.get_attribute(module, :exports_md5)\n        recompile? = Module.defines?(module, {:__mix_recompile__?, 0}, :def)\n        send(pid, {ref, :ok})\n\n        state =\n          each_module(file, module, kind, external, new_export, recompile?, state, timestamp, cwd)\n\n        compiler_loop(ref, pid, state, cwd)\n\n      {^ref, {:ok, _modules, info}} ->\n        {:ok, info, state}\n\n      {^ref, {:error, errors, info}} ->\n        {:error, errors, info, state}\n    end\n  end\n\n  defp after_compile(manifest, state, opts) do\n    %{modules: modules, pending_modules: pending_modules, consolidation: consolidation} = state\n    write_checkpoint(:verify, manifest, Map.keys(modules))\n    consolidation = maybe_consolidate(consolidation, modules, pending_modules, opts)\n    {:ok, %{state | consolidation: consolidation}}\n  end\n\n  defp each_cycle(stale_modules, dest, timestamp, state) do\n    %{\n      modules: modules,\n      sources: sources,\n      changed: changed,\n      pending_modules: pending_modules,\n      stale_exports: stale_exports\n    } = state\n\n    # At this point, we may have additional files to compile.\n    # There are two potential sources:\n    #\n    # * We need to go through all exports that we have confirmed that changed.\n    #   When we first compile, we store all removed/changed modules as stale\n    #   exports. Then, if they are not compiled again, or compiled with a\n    #   different exports MD5, they remain as stale, causing the next cycle.\n    #\n    # * In case a module is defined in two places, we add all sources to changed\n    {pending_modules, exports, changed} =\n      update_stale_entries(pending_modules, sources, changed, %{}, stale_exports, dest)\n\n    state = %{\n      state\n      | changed: [],\n        exports: exports,\n        pending_modules: pending_modules\n    }\n\n    # Those files have been changed transitively, so we mark them as changed\n    # in case compilation fails mid-cycle. The combination of the outdated\n    # timestamp plus the missing BEAM files (which were removed in\n    # update_stale_entries above) will cause them to be recompiled next time.\n    for file <- changed do\n      File.touch!(file, timestamp)\n    end\n\n    if changed == [] do\n      # We merge stale_modules (which is a map of %{module => true} that the user changed)\n      # into a map of modules we compiled (which is a map of %{module => record}). This is\n      # fine because we only care about the keys.\n      changed_modules = Map.merge(modules, stale_modules)\n\n      # Now we do a simple pass finding anything that directly depends on the modules that\n      # changed. We don't need to compute a fixpoint, because now only the directly affected\n      # matter.\n      {sources, runtime_modules} =\n        Enum.reduce(sources, {sources, []}, fn\n          {source_path, source_entry}, {acc_sources, acc_modules} ->\n            source(export_references: export_refs, runtime_references: runtime_refs) =\n              source_entry\n\n            if has_any_key?(changed_modules, export_refs) or\n                 has_any_key?(changed_modules, runtime_refs) do\n              acc_sources =\n                Map.replace!(acc_sources, source_path, source(source_entry, runtime_warnings: []))\n\n              new_modules =\n                Enum.reject(source(source_entry, :modules), &Map.has_key?(changed_modules, &1))\n\n              {acc_sources, new_modules ++ acc_modules}\n            else\n              {acc_sources, acc_modules}\n            end\n        end)\n\n      runtime_paths =\n        Enum.map(runtime_modules, &{&1, Path.join(dest, Atom.to_string(&1) <> \".beam\")})\n\n      state = %{state | sources: sources}\n      {{:runtime, runtime_paths, []}, state}\n    else\n      Mix.Utils.compiling_n(length(changed), :ex)\n\n      # Now we need to detect the new stale_exports.\n      # This is a simplified version of update_stale_sources.\n      {sources, %{}} =\n        Enum.reduce(changed, {sources, stale_exports}, fn file, {acc_sources, acc_modules} ->\n          source(size: size, digest: digest, modules: modules) = Map.fetch!(acc_sources, file)\n          acc_modules = Enum.reduce(modules, acc_modules, &Map.put(&2, &1, true))\n          {Map.replace!(acc_sources, file, source(size: size, digest: digest)), acc_modules}\n        end)\n\n      state = %{state | sources: sources, stale_exports: stale_exports}\n      {{:compile, changed, []}, state}\n    end\n  end\n\n  defp each_file(file, references, verbose, state, cwd) do\n    {compile_references, export_references, runtime_references, compile_env} = references\n    %{sources: sources} = state\n\n    file = Path.relative_to(file, cwd)\n\n    if verbose do\n      Mix.shell().info(\"Compiled #{file}\")\n    end\n\n    compile_references =\n      Enum.reject(compile_references, &match?(\"elixir_\" <> _, Atom.to_string(&1)))\n\n    source(modules: source_modules) = source = Map.fetch!(sources, file)\n    compile_references = compile_references -- source_modules\n    export_references = export_references -- source_modules\n    runtime_references = runtime_references -- source_modules\n\n    source =\n      source(\n        source,\n        # We preserve the digest if the file is recompiled but not changed\n        digest: source(source, :digest) || file |> File.read!() |> digest_contents(),\n        compile_references: compile_references,\n        export_references: export_references,\n        runtime_references: runtime_references,\n        compile_env: compile_env\n      )\n\n    %{state | sources: Map.replace!(sources, file, source)}\n  end\n\n  defp each_module(file, module, kind, external, new_export, recompile?, state, timestamp, cwd) do\n    %{\n      modules: modules,\n      exports: exports,\n      sources: sources,\n      changed: changed,\n      pending_modules: pending_modules,\n      stale_exports: stale_exports\n    } = state\n\n    file = Path.relative_to(file, cwd)\n    external = process_external_resources(external, cwd)\n    old_export = Map.get(exports, module)\n\n    stale_exports =\n      if old_export && old_export != new_export do\n        stale_exports\n      else\n        Map.delete(stale_exports, module)\n      end\n\n    module_sources =\n      case modules do\n        %{^module => module(sources: old_sources)} -> [file | List.delete(old_sources, file)]\n        %{} -> [file]\n      end\n\n    source =\n      Map.get(sources, file) ||\n        Mix.raise(\n          \"Could not find source for #{inspect(file)}. Make sure the :elixirc_paths configuration \" <>\n            \"is a list of relative paths to the current project or absolute paths to external directories\"\n        )\n\n    source =\n      source(\n        source,\n        external: external ++ source(source, :external),\n        modules: [module | source(source, :modules)]\n      )\n\n    entry =\n      module(\n        kind: kind,\n        sources: module_sources,\n        export: new_export,\n        timestamp: timestamp,\n        recompile?: recompile?\n      )\n\n    modules = Map.put(modules, module, entry)\n    sources = Map.replace!(sources, file, source)\n\n    # In case the module defined is pending, this is a source conflict.\n    # So we need to compile all duplicates.\n    changed =\n      case pending_modules do\n        %{^module => module(sources: sources)} -> sources ++ changed\n        %{} -> changed\n      end\n\n    %{state | modules: modules, changed: changed, sources: sources, stale_exports: stale_exports}\n  end\n\n  defp detect_kind(module) do\n    protocol_metadata = Module.get_attribute(module, :__impl__)\n\n    cond do\n      is_list(protocol_metadata) and protocol_metadata[:protocol] ->\n        {:impl, protocol_metadata[:protocol]}\n\n      is_list(Module.get_attribute(module, :__protocol__)) ->\n        :protocol\n\n      true ->\n        :module\n    end\n  end\n\n  defp process_external_resources(external, cwd) do\n    for file <- external do\n      digest =\n        case File.read(file) do\n          {:ok, binary} -> digest_contents(binary)\n          {:error, _} -> nil\n        end\n\n      {Path.relative_to(file, cwd), Mix.Utils.last_modified_and_size(file), digest}\n    end\n  end\n\n  defp debug_stacktrace(pid) do\n    with true <- Mix.debug?(),\n         {:current_stacktrace, stacktrace} <- Process.info(pid, :current_stacktrace) do\n      [?\\n, Exception.format_stacktrace(stacktrace)]\n    else\n      _ -> \"\"\n    end\n  end\n\n  ## Consolidation\n\n  @doc \"\"\"\n  Returns protocols and implementations for the given `manifest`.\n  \"\"\"\n  def protocols_and_impls_from_paths(paths) do\n    Enum.reduce(paths, protocols_and_impls(), fn path, acc ->\n      {modules, _} = read_manifest(Path.join(path, \".mix/compile.elixir\"))\n      protocols_and_impls_from_modules(modules, acc)\n    end)\n  end\n\n  defp protocols_and_impls_from_modules(modules, protocols_and_impls) do\n    Enum.reduce(modules, protocols_and_impls, fn\n      {module, module(kind: kind, timestamp: timestamp)}, {protocols, impls} ->\n        case kind do\n          :protocol -> {Map.put(protocols, module, timestamp), impls}\n          {:impl, protocol} -> {protocols, Map.put(impls, module, protocol)}\n          _ -> {protocols, impls}\n        end\n    end)\n  end\n\n  defp protocols_and_impls(), do: {%{}, %{}}\n\n  defp maybe_consolidate({:off, _, _}, _, _, _) do\n    protocols_and_impls()\n  end\n\n  defp maybe_consolidate(\n         {on_or_force, old_protocols_and_impls, protocols_and_impls},\n         modules,\n         pending_modules,\n         opts\n       ) do\n    protocols_and_impls = protocols_and_impls_from_modules(modules, protocols_and_impls)\n    protocols_and_impls = protocols_and_impls_from_modules(pending_modules, protocols_and_impls)\n\n    Mix.Compilers.Protocol.compile(\n      on_or_force == :force,\n      old_protocols_and_impls,\n      protocols_and_impls,\n      opts\n    )\n\n    protocols_and_impls\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/compilers/erlang.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Compilers.Erlang do\n  @moduledoc false\n\n  @manifest_vsn 1\n\n  @typedoc \"\"\"\n  Options for `compile/6`.\n  \"\"\"\n  @type compile_opts :: [\n          all_warnings: boolean(),\n          force: boolean(),\n          parallel: boolean() | MapSet.t(Path.t()),\n          preload: (-> term()),\n          verbose: boolean()\n        ]\n\n  @doc \"\"\"\n  Compiles the given `mappings`.\n\n  `mappings` is a list of `{src, dest}` pairs, where the source\n  extensions are compiled into the destination extension,\n  automatically invoking the callback for each stale pair (or for\n  all if `force` is `true`) and removing files that no longer have\n  a source, while keeping the `manifest` up to date.\n\n  ## Options\n\n    * `:all_warnings` - a flag to disable showing all previous warnings\n\n    * `:force` - forces compilation regardless of modification times\n\n    * `:parallel` - a mapset of files to compile in parallel\n\n    * `:preload` - any code that must be preloaded if any pending\n      entry needs to be compiled\n\n    * `:verbose` - a flag to enable verbose printing\n\n  ## Examples\n\n  For example, a simple compiler for Lisp Flavored Erlang\n  would be implemented like:\n\n      manifest = Path.join(Mix.Project.manifest_path(), \"compile.lfe\")\n      dest = Mix.Project.compile_path()\n\n      compile(manifest, [{\"src\", dest}], :lfe, :beam, opts, fn input, output ->\n        :lfe_comp.file(\n          to_erl_file(input),\n          [{:outdir, Path.dirname(output)}, :return, :report]\n        )\n      end)\n\n  The command above will:\n\n    1. look for files ending with the `lfe` extension in `src` path\n       and their `beam` counterpart in `ebin` path\n\n    2. for each stale file (or for all if `force` is `true`),\n       invoke the callback passing the calculated input\n       and output\n\n    3. update the manifest with the newly compiled outputs\n\n    4. remove any output in the manifest that does not\n       have an equivalent source\n\n  The callback must return `{:ok, term, warnings}` or\n  `{:error, errors, warnings}` in case of error. This function returns\n  `{status, diagnostics}` as specified in `Mix.Task.Compiler`.\n  \"\"\"\n  @spec compile(\n          Path.t(),\n          [{Path.t(), Path.t()}],\n          atom(),\n          atom(),\n          compile_opts,\n          (Path.t(), Path.t() -> {:ok, term(), [term()]} | {:error, [term()], [term()]})\n        ) :: {Mix.Task.Compiler.status(), [Mix.Task.Compiler.Diagnostic.t()]}\n  def compile(manifest, mappings, src_ext, dest_ext, opts, callback)\n      when is_atom(src_ext) and is_atom(dest_ext) and is_list(opts) do\n    force = opts[:force]\n\n    entries =\n      for {src, dest} <- mappings,\n          target <- extract_entries(src, src_ext, dest, dest_ext, force),\n          do: target\n\n    if preload = entries != [] && opts[:preload] do\n      preload.()\n    end\n\n    compile_entries(manifest, entries, src_ext, dest_ext, opts, callback)\n  end\n\n  # TODO: remove me on v1.22\n  @deprecated \"Use compile/6 or open an up an issue\"\n  def compile(manifest, entries, opts \\\\ [], callback) do\n    compile_entries(manifest, entries, :erl, :beam, opts, callback)\n  end\n\n  @doc false\n  def compile_entries(manifest, mappings, src_ext, dest_ext, opts, callback) do\n    stale = for {:stale, src, dest} <- mappings, do: {src, dest}\n\n    # Get the previous entries from the manifest\n    timestamp = System.os_time(:second)\n    old_entries = entries = read_manifest(manifest)\n\n    # Files to remove are the ones in the manifest but they no longer have a source\n    removed =\n      for {dest, _} <- entries, not List.keymember?(mappings, dest, 2), do: dest\n\n    # Remove manifest entries with no source\n    Enum.each(removed, &File.rm/1)\n    verbose = opts[:verbose]\n\n    # Clear stale and removed files from manifest\n    entries =\n      Enum.reject(entries, fn {dest, _warnings} ->\n        dest in removed || List.keymember?(stale, dest, 1)\n      end)\n\n    if Keyword.get(opts, :all_warnings, true), do: show_warnings(entries)\n\n    if stale == [] and removed == [] do\n      {:noop, manifest_warnings(entries)}\n    else\n      Mix.Utils.compiling_n(length(stale), src_ext)\n      Mix.Project.ensure_structure()\n\n      # Let's prepend the newly created path so compiled files\n      # can be accessed still during compilation (for behaviours\n      # and what not). Note we don't want to cache this path as\n      # we will write to it.\n      Code.prepend_path(Mix.Project.compile_path())\n\n      {parallel, serial} =\n        case opts[:parallel] || false do\n          true -> {stale, []}\n          false -> {[], stale}\n          parallel -> Enum.split_with(stale, fn {source, _target} -> source in parallel end)\n        end\n\n      serial_results = Enum.map(serial, &do_compile(&1, callback, timestamp, verbose))\n\n      parallel_results =\n        parallel\n        |> Task.async_stream(&do_compile(&1, callback, timestamp, verbose),\n          timeout: :infinity,\n          ordered: false\n        )\n        |> Enum.map(fn {:ok, result} -> result end)\n\n      # Compile stale files and print the results\n      {status, new_entries, warnings, errors} =\n        Enum.reduce(serial_results ++ parallel_results, {:ok, [], [], []}, &combine_results/2)\n\n      write_manifest(manifest, entries ++ new_entries, timestamp)\n\n      # Return status and diagnostics\n      warnings = manifest_warnings(entries) ++ to_diagnostics(warnings, :warning)\n\n      if dest_ext == :beam do\n        lazy_modules_diff = fn ->\n          {changed, added} =\n            stale\n            |> Enum.map(&elem(&1, 1))\n            |> Enum.split_with(fn dest -> List.keymember?(old_entries, dest, 0) end)\n\n          modules_diff(added, changed, removed, timestamp)\n        end\n\n        Mix.Task.Compiler.notify_modules_compiled(lazy_modules_diff)\n      end\n\n      case status do\n        :ok ->\n          {:ok, warnings}\n\n        :error ->\n          errors = to_diagnostics(errors, :error)\n          {:error, warnings ++ errors}\n      end\n    end\n  end\n\n  @deprecated \"Use Mix.ensure_application!(app) plus Application.ensure_all_started(app) instead\"\n  def ensure_application!(app, _input) do\n    Mix.ensure_application!(app)\n    {:ok, _} = Application.ensure_all_started(app)\n  end\n\n  @doc \"\"\"\n  Removes compiled files for the given `manifest`.\n  \"\"\"\n  def clean(manifest) do\n    contents = read_manifest(manifest)\n    File.rm(manifest)\n    Enum.each(contents, fn {file, _} -> File.rm(file) end)\n  end\n\n  @doc \"\"\"\n  Converts the given `file` to a format accepted by\n  the Erlang compilation tools.\n  \"\"\"\n  def to_erl_file(file) do\n    to_charlist(file)\n  end\n\n  @doc \"\"\"\n  Asserts that the `:erlc_paths` configuration option that many Mix tasks\n  rely on is valid.\n\n  Raises a `Mix.Error` exception if the option is not valid, returns `:ok`\n  otherwise.\n  \"\"\"\n  def assert_valid_erlc_paths(erlc_paths) do\n    if is_list(erlc_paths) do\n      :ok\n    else\n      Mix.raise(\":erlc_paths should be a list of paths, got: #{inspect(erlc_paths)}\")\n    end\n  end\n\n  @doc \"\"\"\n  Returns the output paths in the manifest.\n  \"\"\"\n  def outputs(manifest) do\n    manifest |> read_manifest() |> Enum.map(&elem(&1, 0))\n  end\n\n  @doc \"\"\"\n  Retrieves all diagnostics from the given manifest.\n  \"\"\"\n  def diagnostics(manifest) do\n    entries = read_manifest(manifest)\n    manifest_warnings(entries)\n  end\n\n  defp extract_entries(src_dir, src_ext, dest_dir, dest_ext, force) do\n    files = Mix.Utils.extract_files(List.wrap(src_dir), List.wrap(src_ext))\n\n    for file <- files do\n      module = module_from_artifact(file)\n      target = Path.join(dest_dir, module <> \".\" <> to_string(dest_ext))\n\n      if force || Mix.Utils.stale?([file], [target]) do\n        {:stale, file, target}\n      else\n        {:ok, file, target}\n      end\n    end\n  end\n\n  defp module_from_artifact(artifact) do\n    artifact |> Path.basename() |> Path.rootname()\n  end\n\n  # The manifest file contains a list of {dest, warnings} tuples\n  defp read_manifest(file) do\n    try do\n      file |> File.read!() |> :erlang.binary_to_term()\n    rescue\n      _ -> []\n    else\n      {@manifest_vsn, data} when is_list(data) -> data\n      _ -> []\n    end\n  end\n\n  defp write_manifest(file, entries, timestamp) do\n    File.mkdir_p!(Path.dirname(file))\n    File.write!(file, :erlang.term_to_binary({@manifest_vsn, entries}))\n    File.touch!(file, timestamp)\n  end\n\n  defp do_compile({input, output}, callback, timestamp, verbose) do\n    case callback.(input, output) do\n      {:ok, _, warnings} ->\n        File.touch!(output, timestamp)\n        verbose && Mix.shell().info(\"Compiled #{input}\")\n        {:ok, [{output, warnings}], warnings, []}\n\n      {:error, errors, warnings} ->\n        {:error, [], warnings, errors}\n\n      {:ok, _} ->\n        IO.warn(\n          \"returning {:ok, contents} in the Mix.Compilers.Erlang.compile/6 callback is deprecated \" <>\n            \"The callback should return {:ok, contents, warnings} or {:error, errors, warnings}\"\n        )\n\n        {:ok, [], [], []}\n\n      :error ->\n        IO.warn(\n          \"returning :error in the Mix.Compilers.Erlang.compile/6 callback is deprecated \" <>\n            \"The callback should return {:ok, contents, warnings} or {:error, errors, warnings}\"\n        )\n\n        {:error, [], [], []}\n    end\n  end\n\n  defp combine_results(result1, result2) do\n    {status1, new_entries1, warnings1, errors1} = result1\n    {status2, new_entries2, warnings2, errors2} = result2\n    status = if status1 == :error or status2 == :error, do: :error, else: :ok\n    {status, new_entries1 ++ new_entries2, warnings1 ++ warnings2, errors1 ++ errors2}\n  end\n\n  defp manifest_warnings(entries) do\n    Enum.flat_map(entries, fn {_, warnings} ->\n      to_diagnostics(warnings, :warning)\n    end)\n  end\n\n  defp to_diagnostics(warnings_or_errors, severity) do\n    for {file, issues} <- warnings_or_errors,\n        file = if(?/ in file, do: Path.absname(file), else: List.to_string(file)),\n        {location, module, data} <- issues do\n      %Mix.Task.Compiler.Diagnostic{\n        file: file,\n        source: file,\n        position: location_normalize(location),\n        message: to_string(module.format_error(data)),\n        severity: severity,\n        compiler_name: to_string(module),\n        details: data\n      }\n    end\n  end\n\n  defp show_warnings(entries) do\n    for {_, warnings} <- entries,\n        {file, issues} <- warnings,\n        {location, module, message} <- issues do\n      message = \"#{file}:#{location_to_string(location)} warning: #{module.format_error(message)}\"\n\n      IO.puts(:stderr, message)\n    end\n  end\n\n  defp location_normalize({line, column})\n       when is_integer(line) and line >= 1 and is_integer(column) and column >= 0,\n       do: {line, column}\n\n  defp location_normalize(line) when is_integer(line) and line >= 1, do: line\n  defp location_normalize(_), do: 0\n\n  defp location_to_string({line, column}), do: \"#{line}:#{column}:\"\n  defp location_to_string(0), do: \"\"\n  defp location_to_string(line), do: \"#{line}:\"\n\n  defp modules_diff(added, changed, removed, timestamp) do\n    %{\n      added: modules_from_paths(added),\n      changed: modules_from_paths(changed),\n      removed: modules_from_paths(removed),\n      timestamp: timestamp\n    }\n  end\n\n  defp modules_from_paths(paths) do\n    Enum.map(paths, &module_from_path/1)\n  end\n\n  defp module_from_path(path) do\n    path |> Path.basename() |> Path.rootname() |> String.to_atom()\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/compilers/protocol.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Compilers.Protocol do\n  @moduledoc false\n  @manifest \"compile.protocols\"\n  @manifest_vsn 3\n\n  ## Umbrella handling\n\n  @switches [force: :boolean, verbose: :boolean, consolidate_protocols: :boolean]\n\n  def umbrella(args, res) do\n    config = Mix.Project.config()\n    {opts, _, _} = OptionParser.parse(args, switches: @switches)\n\n    opts =\n      if \"--no-protocol-consolidation\" in args do\n        # TODO: Deprecate me on Elixir v1.23\n        Keyword.put(opts, :consolidate_protocols, false)\n      else\n        opts ++ Keyword.take(config, [:consolidate_protocols])\n      end\n\n    # Because this function is called outside of the usual compiler loop,\n    # we need a build lock.\n    Mix.Project.with_build_lock(config, fn ->\n      manifest = manifest()\n      config_mtime = Mix.Project.config_mtime()\n      {old_config_mtime, old_protocols_and_impls} = read_manifest(manifest)\n\n      case status(config_mtime > old_config_mtime, opts) do\n        :off ->\n          res\n\n        :on when res == :noop ->\n          :noop\n\n        on_or_force ->\n          deps_paths =\n            for %{scm: scm, opts: opts} <- Mix.Dep.cached(),\n                not scm.fetchable?(),\n                do: opts[:build]\n\n          protocols_and_impls = Mix.Compilers.Elixir.protocols_and_impls_from_paths(deps_paths)\n\n          case compile(on_or_force == :force, old_protocols_and_impls, protocols_and_impls, opts) do\n            :ok ->\n              write_manifest(manifest, {config_mtime, protocols_and_impls})\n              :ok\n\n            :noop ->\n              res\n          end\n      end\n    end)\n  end\n\n  defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest)\n\n  defp read_manifest(manifest) do\n    try do\n      [@manifest_vsn | metadata] = manifest |> File.read!() |> :erlang.binary_to_term()\n      metadata\n    rescue\n      _ ->\n        # If there is no manifest or it is out of date, remove old files\n        clean_consolidated()\n        {0, {%{}, %{}}}\n    end\n  end\n\n  defp write_manifest(manifest, metadata) do\n    File.mkdir_p!(Path.dirname(manifest))\n    manifest_data = :erlang.term_to_binary([@manifest_vsn | metadata], [:compressed])\n    File.write!(manifest, manifest_data)\n  end\n\n  def clean do\n    File.rm(manifest())\n    clean_consolidated()\n  end\n\n  ## General handling\n\n  def status(mtime_changed?, opts) do\n    consolidation_path = Mix.Project.consolidation_path()\n\n    cond do\n      not Keyword.get(opts, :consolidate_protocols, true) ->\n        clean_consolidated()\n        :off\n\n      # We need to reconsolidate all protocols whenever the dependency changes\n      # because we only track protocols from the current app and from local deps.\n      # We are only interested in the compile.lock from config_mtime (which is\n      # a build artifact).\n      not File.exists?(consolidation_path) or mtime_changed? ->\n        :force\n\n      true ->\n        :on\n    end\n  end\n\n  def compile(force?, old_protocols_and_impls, protocols_and_impls, opts) do\n    output = Mix.Project.consolidation_path()\n\n    res =\n      if opts[:force] || force? do\n        clean_consolidated()\n        paths = consolidation_paths()\n\n        paths\n        |> Protocol.extract_protocols()\n        |> consolidate(paths, output, opts)\n      else\n        protocols_and_impls\n        |> diff_manifest(old_protocols_and_impls, output)\n        |> consolidate(consolidation_paths(), output, opts)\n      end\n\n    Code.prepend_path(output)\n    res\n  end\n\n  defp clean_consolidated do\n    File.rm_rf(Mix.Project.consolidation_path())\n  end\n\n  defp consolidation_paths do\n    otp = :code.lib_dir()\n\n    # Pre-list the paths in each directory for performance\n    for path <- :code.get_path(), not :lists.prefix(otp, path) do\n      {path,\n       case :file.list_dir(path) do\n         {:ok, files} -> files\n         _ -> []\n       end}\n    end\n  end\n\n  defp consolidate([], _paths, output, _opts) do\n    File.mkdir_p!(output)\n\n    :noop\n  end\n\n  defp consolidate(protocols, paths, output, opts) do\n    File.mkdir_p!(output)\n\n    protocols\n    |> Enum.uniq()\n    |> Enum.map(&Task.async(fn -> consolidate_each(&1, paths, output, opts) end))\n    |> Enum.map(&Task.await(&1, :infinity))\n\n    :ok\n  end\n\n  defp consolidate_each(protocol, paths, output, opts) do\n    impls = Protocol.extract_impls(protocol, paths)\n    reload(protocol)\n\n    case Protocol.consolidate(protocol, impls) do\n      {:ok, binary} ->\n        File.write!(Path.join(output, \"#{Atom.to_string(protocol)}.beam\"), binary)\n\n        if opts[:verbose] do\n          Mix.shell().info(\"Consolidated #{inspect_protocol(protocol)}\")\n        end\n\n      # If we remove a dependency and we have implemented one of its\n      # protocols locally, we will mark the protocol as needing to be\n      # reconsolidated when the implementation is removed even though\n      # the protocol no longer exists. Although most times removing a\n      # dependency will trigger a full recompilation, such won't happen\n      # in umbrella apps with shared build.\n      {:error, :no_beam_info} ->\n        remove_consolidated(protocol, output)\n\n        if opts[:verbose] do\n          Mix.shell().info(\"Unavailable #{inspect_protocol(protocol)}\")\n        end\n    end\n  end\n\n  # We cannot use the inspect protocol while consolidating\n  # since inspect may not be available.\n  defp inspect_protocol(protocol) do\n    Macro.inspect_atom(:literal, protocol)\n  end\n\n  defp reload(module) do\n    :code.purge(module)\n    :code.delete(module)\n  end\n\n  defp diff_manifest({new_protocols, new_impls}, {old_protocols, old_impls}, output) do\n    protocols =\n      new_protocols\n      |> Enum.filter(fn {protocol, new_timestamp} ->\n        case old_protocols do\n          # There is a new version, removed the consolidated\n          %{^protocol => old_timestamp} when new_timestamp > old_timestamp ->\n            remove_consolidated(protocol, output)\n            true\n\n          # Nothing changed\n          %{^protocol => _} ->\n            false\n\n          # New protocol\n          %{} ->\n            true\n        end\n      end)\n      |> Map.new()\n\n    protocols =\n      for {impl, protocol} <- new_impls,\n          not is_map_key(old_impls, impl),\n          do: {protocol, true},\n          into: protocols\n\n    removed_protocols =\n      for {protocol, _timestamp} <- old_protocols,\n          not is_map_key(new_protocols, protocol),\n          do: remove_consolidated(protocol, output)\n\n    removed_protocols = Map.from_keys(removed_protocols, true)\n\n    protocols =\n      for {impl, protocol} <- old_impls,\n          not is_map_key(new_impls, impl),\n          not is_map_key(removed_protocols, protocol),\n          do: {protocol, true},\n          into: protocols\n\n    Map.keys(protocols)\n  end\n\n  defp remove_consolidated(protocol, output) do\n    File.rm(Path.join(output, \"#{Atom.to_string(protocol)}.beam\"))\n    protocol\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/compilers/test.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Compilers.Test do\n  @moduledoc false\n\n  require Mix.Compilers.Elixir, as: CE\n\n  import Record\n\n  defrecordp :source,\n    compile_references: [],\n    runtime_references: [],\n    external: []\n\n  # Necessary to avoid warnings during bootstrap\n  @compile {:no_warn_undefined, ExUnit}\n  @stale_manifest \"compile.test_stale\"\n  @manifest_vsn 2\n\n  @doc \"\"\"\n  Requires and runs test files.\n\n  It expects all of the test patterns, the test files that were matched for the\n  test patterns, the test paths, and the opts from the test task.\n  \"\"\"\n  def require_and_run(matched_test_files, test_paths, elixirc_opts, opts) do\n    elixirc_opts =\n      Keyword.merge([docs: false, debug_info: false, infer_signatures: false], elixirc_opts)\n\n    previous_opts = Code.compiler_options(elixirc_opts)\n\n    try do\n      require_and_run(matched_test_files, test_paths, opts)\n    after\n      Code.compiler_options(previous_opts)\n    end\n  end\n\n  defp require_and_run(matched_test_files, test_paths, opts) do\n    dry_run = Keyword.get(opts, :dry_run, false)\n    stale = Keyword.get(opts, :stale, false)\n    max_requires = opts[:max_requires]\n\n    {test_files, stale_manifest_pid, parallel_require_callbacks} =\n      if stale and not dry_run do\n        set_up_stale(matched_test_files, test_paths, opts)\n      else\n        {matched_test_files, nil, []}\n      end\n\n    shared_require_options =\n      if max_requires do\n        [max_concurrency: max_requires, return_diagnostics: true]\n      else\n        [return_diagnostics: true]\n      end\n\n    Application.ensure_all_started(:ex_unit)\n\n    cond do\n      test_files == [] ->\n        # Make sure we run the after_suite callbacks but with no feedback\n        formatters = Application.fetch_env!(:ex_unit, :formatters)\n\n        try do\n          Application.put_env(:ex_unit, :formatters, [])\n          _ = ExUnit.run()\n          :noop\n        after\n          Application.put_env(:ex_unit, :formatters, formatters)\n        end\n\n      Keyword.get(opts, :profile_require) == \"time\" ->\n        Kernel.ParallelCompiler.require(test_files, [profile: :time] ++ shared_require_options)\n        :noop\n\n      true ->\n        task = ExUnit.async_run()\n        seed = Application.fetch_env!(:ex_unit, :seed)\n        rand_algorithm = Application.fetch_env!(:ex_unit, :rand_algorithm)\n        test_files = shuffle(seed, rand_algorithm, test_files)\n\n        try do\n          parallel_require_options = shared_require_options ++ parallel_require_callbacks\n\n          warnings? =\n            case Kernel.ParallelCompiler.require(test_files, parallel_require_options) do\n              {:ok, _, %{compile_warnings: c, runtime_warnings: r}}\n              when c != [] or r != [] ->\n                true\n\n              {:ok, _, _} ->\n                false\n\n              {:error, _, _} ->\n                exit({:shutdown, 1})\n            end\n\n          %{failures: failures} = results = ExUnit.await_run(task)\n\n          if failures == 0 do\n            agent_write_manifest(stale_manifest_pid)\n          end\n\n          {:ok, Map.put(results, :warnings?, warnings?)}\n        catch\n          kind, reason ->\n            # In case there is an error, shut down the runner task\n            # before the error propagates up and trigger links.\n            Task.shutdown(task)\n            :erlang.raise(kind, reason, __STACKTRACE__)\n        after\n          agent_stop(stale_manifest_pid)\n        end\n    end\n  end\n\n  defp set_up_stale(matched_test_files, test_paths, opts) do\n    manifest = manifest()\n    modified = Mix.Utils.last_modified(manifest)\n    test_sources = read_manifest()\n\n    removed =\n      for {source, _} <- test_sources, source not in matched_test_files, do: source\n\n    test_helpers = Enum.map(test_paths, &Path.join(&1, \"test_helper.exs\"))\n    sources = [Mix.Project.config_mtime(), Mix.Project.project_file() | test_helpers]\n    force = opts[:force] || Mix.Utils.stale?(sources, [modified])\n\n    changed =\n      if force do\n        # Let's just require everything\n        matched_test_files\n      else\n        sources_mtimes = mtimes(test_sources)\n\n        # Otherwise let's start with the new sources\n        # Plus the sources that have changed in disk\n        for(\n          source <- matched_test_files,\n          not is_map_key(test_sources, source),\n          do: source\n        ) ++\n          for(\n            {source, source(external: external)} <- test_sources,\n            times = Enum.map([source | external], &Map.fetch!(sources_mtimes, &1)),\n            Mix.Utils.stale?(times, [modified]),\n            do: source\n          )\n      end\n\n    stale = MapSet.new(changed -- removed)\n    sources = update_stale_sources(test_sources, removed, changed)\n\n    test_files_to_run =\n      sources\n      |> tests_with_changed_references()\n      |> MapSet.union(stale)\n      |> MapSet.to_list()\n\n    if test_files_to_run == [] do\n      write_manifest(sources)\n      {[], nil, nil}\n    else\n      {:ok, pid} = Agent.start_link(fn -> sources end)\n      cwd = File.cwd!()\n\n      parallel_require_callbacks = [\n        each_module: &each_module(pid, cwd, &1, &2, &3),\n        each_file: &each_file(pid, cwd, &1, &2)\n      ]\n\n      {test_files_to_run, pid, parallel_require_callbacks}\n    end\n  end\n\n  defp agent_write_manifest(nil), do: :noop\n\n  defp agent_write_manifest(pid) do\n    Agent.cast(pid, fn sources ->\n      write_manifest(sources)\n      sources\n    end)\n  end\n\n  defp agent_stop(nil), do: :noop\n\n  defp agent_stop(pid) do\n    Agent.stop(pid, :normal, :infinity)\n  end\n\n  ## Setup helpers\n\n  defp mtimes(sources) do\n    Enum.reduce(sources, %{}, fn {source, source(external: external)}, map ->\n      Enum.reduce([source | external], map, fn file, map ->\n        Map.put_new_lazy(map, file, fn -> Mix.Utils.last_modified(file) end)\n      end)\n    end)\n  end\n\n  defp update_stale_sources(sources, removed, changed) do\n    sources = Map.drop(sources, removed)\n    sources = Enum.reduce(changed, sources, &Map.put(&2, &1, source()))\n    sources\n  end\n\n  ## Manifest\n\n  defp manifest, do: Path.join(Mix.Project.manifest_path(), @stale_manifest)\n\n  defp read_manifest() do\n    try do\n      [@manifest_vsn | sources] = manifest() |> File.read!() |> :erlang.binary_to_term()\n      sources\n    rescue\n      _ -> %{}\n    end\n  end\n\n  defp write_manifest(test_sources) when test_sources == %{} do\n    File.rm(manifest())\n    :ok\n  end\n\n  defp write_manifest(test_sources = %{}) do\n    manifest = manifest()\n    File.mkdir_p!(Path.dirname(manifest))\n\n    manifest_data = :erlang.term_to_binary([@manifest_vsn | test_sources], [:compressed])\n    File.write!(manifest, manifest_data)\n  end\n\n  ## Test changed dependency resolution\n\n  defp tests_with_changed_references(test_sources) do\n    test_manifest = manifest()\n    [elixir_manifest] = Mix.Tasks.Compile.Elixir.manifests()\n\n    if Mix.Utils.stale?([elixir_manifest], [test_manifest]) do\n      compile_path = Mix.Project.compile_path()\n      {elixir_modules, elixir_sources} = CE.read_manifest(elixir_manifest)\n\n      stale_modules =\n        for {module, _} <- elixir_modules,\n            beam = Path.join(compile_path, Atom.to_string(module) <> \".beam\"),\n            Mix.Utils.stale?([beam], [test_manifest]),\n            do: module,\n            into: MapSet.new()\n\n      stale_modules = find_all_dependent_on(stale_modules, elixir_modules, elixir_sources)\n\n      for {source, source(runtime_references: r, compile_references: c)} <- test_sources,\n          Enum.any?(r, &(&1 in stale_modules)) or Enum.any?(c, &(&1 in stale_modules)),\n          do: source,\n          into: MapSet.new()\n    else\n      MapSet.new()\n    end\n  end\n\n  defp find_all_dependent_on(modules, elixir_modules, elixir_sources, resolved \\\\ MapSet.new()) do\n    new_modules =\n      for module <- modules,\n          module not in resolved,\n          dependent_module <- dependent_modules(module, elixir_modules, elixir_sources),\n          do: dependent_module,\n          into: modules\n\n    if MapSet.size(new_modules) == MapSet.size(modules) do\n      new_modules\n    else\n      find_all_dependent_on(new_modules, elixir_modules, elixir_sources, modules)\n    end\n  end\n\n  defp dependent_modules(module, modules, sources) do\n    for {source,\n         CE.source(\n           runtime_references: r,\n           compile_references: c,\n           export_references: e\n         )} <- sources,\n        module in r or module in c or module in e,\n        {dependent_module, CE.module(sources: sources)} <- modules,\n        source in sources,\n        do: dependent_module\n  end\n\n  ## ParallelRequire callback\n\n  defp each_module(pid, cwd, file, module, _binary) do\n    external = get_external_resources(module, cwd)\n\n    if external != [] do\n      Agent.update(pid, fn sources ->\n        file = Path.relative_to(file, cwd)\n        source(external: current_external) = source = Map.fetch!(sources, file)\n        Map.put(sources, file, source(source, external: external ++ current_external))\n      end)\n    end\n\n    :ok\n  end\n\n  defp each_file(pid, cwd, file, lexical) do\n    Agent.update(pid, fn sources ->\n      file = Path.relative_to(file, cwd)\n\n      {compile_references, export_references, runtime_references, _compile_env} =\n        Kernel.LexicalTracker.references(lexical)\n\n      source =\n        source(\n          Map.fetch!(sources, file),\n          compile_references: compile_references ++ export_references,\n          runtime_references: runtime_references\n        )\n\n      Map.put(sources, file, source)\n    end)\n  end\n\n  defp get_external_resources(module, cwd) do\n    for file <- Module.get_attribute(module, :external_resource), do: Path.relative_to(file, cwd)\n  end\n\n  defp shuffle(_seed = 0, _rand_algorithm, list) do\n    list\n  end\n\n  defp shuffle(seed, rand_algorithm, list) do\n    _ = :rand.seed(rand_algorithm, {seed, seed, seed})\n    Enum.shuffle(list)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/config.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Config do\n  @moduledoc false\n  @moduledoc deprecated: \"Use the Config module instead\"\n\n  @deprecated \"Use the Config module instead\"\n  defmacro __using__(_) do\n    quote do\n      import Mix.Config, only: [config: 2, config: 3, import_config: 1]\n    end\n  end\n\n  @deprecated \"Use the Config module instead\"\n  defdelegate config(root_key, opts), to: Config\n\n  @deprecated \"Use the Config module instead\"\n  defdelegate config(root_key, key, opts), to: Config\n\n  @deprecated \"Use the Config module instead\"\n  defmacro import_config(path_or_wildcard) do\n    quote do\n      Mix.Config.__import__!(unquote(path_or_wildcard), __DIR__)\n    end\n  end\n\n  @doc false\n  def __import__!(path_or_wildcard, dir) do\n    path_or_wildcard = Path.expand(path_or_wildcard, dir)\n\n    paths =\n      if String.contains?(path_or_wildcard, ~w(* ? [ {)) do\n        Path.wildcard(path_or_wildcard)\n      else\n        [path_or_wildcard]\n      end\n\n    for path <- paths do\n      Config.__import__!(path)\n    end\n\n    :ok\n  end\n\n  ## Mix API\n\n  @deprecated \"Use Config.Reader.read_imports!/2 instead\"\n  def eval!(file, imported_paths \\\\ []) do\n    Config.Reader.read_imports!(file,\n      imports: imported_paths,\n      env: Mix.env(),\n      target: Mix.target()\n    )\n  end\n\n  @deprecated \"Use Config.Reader.read!/2 instead\"\n  def read!(file, imported_paths \\\\ []) do\n    Config.Reader.read!(file, imports: imported_paths, env: Mix.env(), target: Mix.target())\n  end\n\n  @deprecated \"Use Config.Reader.merge/2 instead\"\n  def merge(config1, config2) do\n    Config.__merge__(config1, config2)\n  end\n\n  @deprecated \"Use Application.put_all_env/2 instead\"\n  def persist(config) do\n    Application.put_all_env(config, persistent: true)\n  end\n\n  @deprecated \"Use the Config.Reader module instead\"\n  def read_wildcard!(path, loaded_paths \\\\ []) do\n    paths =\n      if String.contains?(path, ~w(* ? [ {)) do\n        Path.wildcard(path)\n      else\n        [path]\n      end\n\n    Enum.reduce(paths, [], &merge(&2, read!(&1, loaded_paths)))\n  end\n\n  @deprecated \"Manually validate the data instead\"\n  def validate!(config) do\n    validate!(config, \"runtime\")\n  end\n\n  defp validate!(config, file) do\n    if is_list(config) do\n      Enum.all?(config, fn\n        {app, value} when is_atom(app) ->\n          if Keyword.keyword?(value) do\n            true\n          else\n            raise ArgumentError,\n                  \"expected #{Path.relative_to_cwd(file)} config for app #{inspect(app)} \" <>\n                    \"to return keyword list, got: #{inspect(value)}\"\n          end\n\n        _ ->\n          false\n      end)\n    else\n      raise ArgumentError,\n            \"expected #{Path.relative_to_cwd(file)} config to return \" <>\n              \"keyword list, got: #{inspect(config)}\"\n    end\n\n    config\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/dep/converger.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# This module is the one responsible for converging\n# dependencies in a recursive fashion. This\n# module and its functions are private to Mix.\ndefmodule Mix.Dep.Converger do\n  @moduledoc false\n\n  @doc \"\"\"\n  Topologically sorts the given dependencies.\n  \"\"\"\n  def topological_sort(deps) do\n    graph = :digraph.new()\n\n    try do\n      Enum.each(deps, fn %Mix.Dep{app: app} ->\n        :digraph.add_vertex(graph, app)\n      end)\n\n      Enum.each(deps, fn %Mix.Dep{app: app, deps: other_deps} ->\n        Enum.each(other_deps, fn\n          %Mix.Dep{app: ^app} ->\n            Mix.raise(\"App #{app} lists itself as a dependency\")\n\n          %Mix.Dep{app: other_app} ->\n            :digraph.add_edge(graph, other_app, app)\n        end)\n      end)\n\n      if apps = :digraph_utils.topsort(graph) do\n        Enum.map(apps, fn app ->\n          Enum.find(deps, fn %Mix.Dep{app: other_app} -> app == other_app end)\n        end)\n      else\n        Mix.raise(\n          \"Could not sort dependencies. \" <>\n            \"The following dependencies form a cycle: \" <>\n            Enum.join(Mix.Utils.find_cycle!(graph), \", \")\n        )\n      end\n    after\n      :digraph.delete(graph)\n    end\n  end\n\n  @doc \"\"\"\n  Converge without lock and accumulator updates.\n\n  Note the dependencies returned from converge are not yet loaded.\n  The relevant app keys are found under `dep.opts[:app_properties]`.\n\n  See `Mix.Dep.Loader.children/1` for options.\n  \"\"\"\n  def converge(opts \\\\ []) do\n    converge(nil, nil, opts, &{&1, &2, &3}) |> elem(0)\n  end\n\n  @doc \"\"\"\n  Converges all dependencies from the current project,\n  including nested dependencies.\n\n  There is a callback that is invoked for each dependency and\n  must return an updated dependency in case some processing\n  is done.\n\n  Note the dependencies returned from converge are not yet loaded.\n  The relevant app keys are found under `dep.opts[:app_properties]`.\n\n  See `Mix.Dep.Loader.children/1` for options.\n  \"\"\"\n  def converge(acc, lock, opts, callback) do\n    {deps, acc, lock} = all(acc, lock, opts, callback)\n    if remote = Mix.RemoteConverger.get(), do: remote.post_converge()\n    sorted_deps = topological_sort(deps)\n    warn_on_unneeded_deps_overrides(sorted_deps)\n    {sorted_deps, acc, lock}\n  end\n\n  defp warn_on_unneeded_deps_overrides([%{app: app, opts: opts} = dep | rest]) do\n    override = Keyword.get(opts, :override, false)\n\n    if is_list(override) do\n      Enum.each(override, fn overridden_app ->\n        # Since we used a topological sort, if someone depends on dep, it will come after dep\n        with %{deps: deps} <- Enum.find(rest, &(&1.app == overridden_app)),\n             true <- Enum.any?(deps, &(&1.app == app)) do\n          :ok\n        else\n          _ -> warn_uneeded_override(dep, overridden_app)\n        end\n      end)\n    end\n\n    warn_on_unneeded_deps_overrides(rest)\n  end\n\n  defp warn_on_unneeded_deps_overrides([]) do\n    :ok\n  end\n\n  defp all(acc, lock, opts, callback) do\n    lock_given? = !!lock\n\n    main = Mix.Dep.Loader.children(lock_given?)\n    main = Enum.map(main, &%{&1 | top_level: true})\n    apps = Enum.map(main, & &1.app)\n    env_target = {opts[:env], opts[:target]}\n\n    # If no lock was given, let's read one to fill in the deps\n    lock = lock || Mix.Dep.Lock.read()\n\n    # Run converger for all dependencies, except remote\n    # dependencies. Since the remote converger may be\n    # lazily loaded, we need to check for it on every\n    # iteration.\n    {deps, acc, lock} =\n      init_all(main, apps, acc, lock, callback, lock_given?, env_target, fn dep ->\n        if (remote = Mix.RemoteConverger.get()) && remote.remote?(dep) do\n          {:loaded, dep}\n        else\n          {:unloaded, dep, nil}\n        end\n      end)\n\n    # Run remote converger and rerun Mix's converger with the new information.\n    # Don't run the remote if deps didn't converge, if the remote is not\n    # available or if none of the deps are handled by the remote.\n    remote = Mix.RemoteConverger.get()\n    diverged? = Enum.any?(deps, &Mix.Dep.diverged?/1)\n    use_remote? = !!remote and Enum.any?(deps, &remote.remote?/1)\n\n    if not diverged? and use_remote? do\n      # Make sure there are no cycles before calling the remote converger\n      topological_sort(deps)\n\n      # If there is a lock, it means we are doing a get/update\n      # and we need to hit the remote converger which do external\n      # requests and what not. In case of deps.loadpaths, deps and so\n      # on, there is no lock, so we won't hit this branch.\n      lock = if lock_given?, do: remote.converge(deps, lock), else: lock\n\n      cache =\n        deps\n        |> Enum.reject(&remote.remote?(&1))\n        |> Enum.into(%{}, &{&1.app, &1})\n\n      # In case no lock was given, we will use the local lock\n      # which is potentially stale. So remote.deps/2 needs to always\n      # check if the data it finds in the lock is actually valid.\n      {deps, acc, lock} =\n        init_all(main, apps, acc, lock, callback, lock_given?, env_target, fn dep ->\n          %{app: app, scm: scm} = dep\n\n          case cache do\n            # If the SCM matches, use the already cached dependency from first converger pass\n            %{^app => %{scm: ^scm} = cached} ->\n              {:loaded, cached}\n\n            # If SCM doesn't match, the remote converger resolved a new dependency but because\n            # there is conflict we return the new dependency as is for the converger to fail\n            %{^app => _cached} ->\n              {:loaded, dep}\n\n            %{} ->\n              {:unloaded, dep, remote.deps(dep, lock)}\n          end\n        end)\n\n      {reject_non_fulfilled_optional(deps), acc, lock}\n    else\n      {reject_non_fulfilled_optional(deps), acc, lock}\n    end\n  end\n\n  defp init_all(main, apps, rest, lock, callback, locked?, env_target, cache) do\n    state = %{locked?: locked?, env_target: env_target, cache: cache, callback: callback}\n    {deps, _kept, _optional, rest, lock} = all(main, nil, [], [], [], apps, [], rest, lock, state)\n    # When traversing dependencies, we keep skipped ones to\n    # find conflicts. We remove them now after traversal.\n    {deps, _} = deps |> Enum.reverse() |> Mix.Dep.Loader.split_by_env_and_target(env_target)\n    {deps, rest, lock}\n  end\n\n  # We traverse the tree of dependencies in a breadth-first\n  # fashion. The reason for this is that we converge\n  # dependencies, but allow the parent to override any\n  # dependency in the child. Consider this tree with\n  # dependencies \"a\", \"b\", \"c\", and so forth, and the order they are\n  # converged:\n  #\n  #     * project\n  #       1) a\n  #       2) b\n  #         4) d\n  #       3) c\n  #         5) e\n  #         6) f\n  #           7) d\n  #\n  # Note that the \"d\" dependency exists as a child of \"b\"\n  # and child of \"f\". In case the dependency is the same,\n  # we proceed. However, if there is a conflict, for instance\n  # different Git repositories are used as source in each, we\n  # raise an exception.\n  #\n  # In order to solve such dependencies, we allow the project\n  # to specify the same dependency, but it will be considered\n  # to have higher priority:\n  #\n  #     * project\n  #       1) a\n  #       2) b\n  #         5) d\n  #       3) c\n  #         6) e\n  #         7) f\n  #           8) d\n  #       4) d\n  #\n  # Now, since \"d\" was specified in a parent project, no\n  # exception is going to be raised since d is considered\n  # to be the authoritative source.\n  defp all([dep | t], parent, acc, kept, upper, breadths, optional, rest, lock, state) do\n    case match_deps(parent, acc, upper, dep, state.env_target) do\n      {:replace, dep, acc} ->\n        all([dep | t], parent, acc, kept, upper, breadths, optional, rest, lock, state)\n\n      {:match, acc} ->\n        all(t, parent, acc, kept, upper, breadths, optional, rest, lock, state)\n\n      :skip ->\n        # We still keep skipped dependencies around to detect conflicts.\n        # They must be rejected after every all iteration but they are not\n        # included in the list of kept dependencies.\n        all(t, parent, [dep | acc], kept, upper, breadths, optional, rest, lock, state)\n\n      :nomatch ->\n        {%{app: app, deps: deps, opts: opts} = dep, rest, lock} =\n          case state.cache.(dep) do\n            {:loaded, cached_dep} ->\n              {cached_dep, rest, lock}\n\n            {:unloaded, dep, children} ->\n              {dep, rest, lock} = state.callback.(put_lock(dep, lock), rest, lock)\n\n              dep =\n                Mix.Dep.Loader.with_system_env(dep, fn ->\n                  Mix.Dep.Loader.load(dep, children, state.locked?)\n                end)\n\n              {dep, rest, lock}\n          end\n\n        # Something that we previously ruled out as an optional dependency is\n        # no longer a dependency. Add it back for traversal.\n        {no_longer_optional, optional} = Enum.split_with(optional, &(&1.app == app))\n        t = no_longer_optional ++ t\n        acc = [dep | acc]\n\n        {acc, kept, optional, rest, lock} =\n          all(t, parent, acc, [dep.app | kept], upper, breadths, optional, rest, lock, state)\n\n        # Now traverse all parent dependencies and see if we have any optional dependency.\n        {discarded, deps} = split_non_fulfilled_optional(deps, kept, opts[:from_umbrella])\n\n        new_breadths = Enum.map(deps, & &1.app) ++ breadths\n        new_optional = discarded ++ optional\n        all(deps, app, acc, kept, breadths, new_breadths, new_optional, rest, lock, state)\n    end\n  end\n\n  defp all([], _parent, acc, kept, _upper, _current, optional, rest, lock, _state) do\n    {acc, kept, optional, rest, lock}\n  end\n\n  defp put_lock(%Mix.Dep{app: app} = dep, lock) do\n    put_in(dep.opts[:lock], lock[app])\n  end\n\n  # Look for matching and divergence in dependencies.\n  #\n  # If the same dependency is specified more than once,\n  # we need to guarantee they converge. If they don't\n  # converge, we mark them as diverged.\n  #\n  # The only exception is when the dependency that\n  # diverges is in the upper breadth, in those cases we\n  # also check for the override option and mark the dependency\n  # as overridden instead of diverged.\n  defp match_deps(parent, list, upper_breadths, %Mix.Dep{app: app} = dep, env_target) do\n    case Enum.split_while(list, &(&1.app != app)) do\n      {_, []} ->\n        if Mix.Dep.Loader.skip?(dep, env_target) do\n          :skip\n        else\n          :nomatch\n        end\n\n      {pre, [%Mix.Dep{opts: other_opts} = other | pos]} ->\n        in_upper? = app in upper_breadths\n\n        if other.top_level and dep.top_level do\n          Mix.shell().error(\n            \"warning: the dependency #{inspect(dep.app)} is \" <>\n              \"duplicated at the top level, please remove one of them\"\n          )\n        end\n\n        override = Keyword.get(other_opts, :override, false)\n\n        cond do\n          in_upper? && override == true ->\n            {:match, list}\n\n          not converge?(other, dep) ->\n            if parent_overriden?(override, parent) do\n              {:match, list}\n            else\n              tag = if in_upper?, do: :overridden, else: :diverged\n              other = %{other | status: {tag, parent, dep}}\n              {:match, pre ++ [other | pos]}\n            end\n\n          vsn = req_mismatch(other, dep) ->\n            if parent_overriden?(override, parent) do\n              {:match, list}\n            else\n              other = %{other | status: {:divergedreq, vsn, parent, dep}}\n              {:match, pre ++ [other | pos]}\n            end\n\n          not in_upper? and Mix.Dep.Loader.skip?(other, env_target) and\n              not Mix.Dep.Loader.skip?(dep, env_target) ->\n            dep\n            |> merge_manager(other, in_upper?)\n            |> with_matching_only_and_targets(other, in_upper?, override, parent, list, fn dep ->\n              {:replace, dep, pre ++ pos}\n            end)\n\n          true ->\n            other\n            |> merge_manager(dep, in_upper?)\n            |> with_matching_only_and_targets(dep, in_upper?, override, parent, list, fn other ->\n              {:match, pre ++ [other | pos]}\n            end)\n        end\n    end\n  end\n\n  defp parent_overriden?(list, app) when is_list(list), do: app in list\n  defp parent_overriden?(_list, _app), do: false\n\n  defp with_matching_only_and_targets(other, dep, in_upper?, override, parent, list, callback) do\n    %{opts: opts} = dep\n\n    if opts[:optional] do\n      maybe_warn_uneeded_override(dep, override, parent)\n      callback.(other)\n    else\n      with {:ok, other} <- with_matching(other, :only, dep, opts, in_upper?),\n           {:ok, other} <- with_matching(other, :targets, dep, opts, in_upper?) do\n        maybe_warn_uneeded_override(dep, override, parent)\n        callback.(other)\n      else\n        {:error, other} ->\n          if parent_overriden?(override, parent) do\n            {:match, list}\n          else\n            callback.(other)\n          end\n      end\n    end\n  end\n\n  defp maybe_warn_uneeded_override(dep, override, parent) do\n    if parent_overriden?(override, parent) do\n      warn_uneeded_override(dep, parent)\n    end\n  end\n\n  defp warn_uneeded_override(dep, parent) do\n    Mix.shell().error(\n      \"Dependency #{Mix.Dep.format_dep(dep)} no longer requires :override on #{inspect(parent)}\"\n    )\n  end\n\n  # When in_upper is true\n  #\n  # When a parent dependency specifies :only/:targets that is a\n  # subset of a child dependency, we are going to abort as the\n  # parent dependency must explicitly outline a superset of child\n  # dependencies.\n  #\n  # We could resolve such conflicts automatically but, since\n  # the user has likely written a :only/:targets in their mix.exs\n  # file, we decided to go with a more explicit approach of asking\n  # them to change it to avoid later surprises and headaches.\n  defp with_matching(%{opts: other_opts} = other, key, dep, opts, true) do\n    case Keyword.fetch(other_opts, key) do\n      {:ok, other_value} ->\n        case Keyword.fetch(opts, key) do\n          {:ok, value} ->\n            case List.wrap(value) -- List.wrap(other_value) do\n              [] -> {:ok, other}\n              _ -> {:error, %{other | status: {:\"diverged#{key}\", dep}}}\n            end\n\n          :error ->\n            {:error, %{other | status: {:\"diverged#{key}\", dep}}}\n        end\n\n      :error ->\n        {:ok, other}\n    end\n  end\n\n  # When in_upper is false\n  #\n  # In this case, the two dependencies do not have a common path and\n  # only solution is to merge the environments. We have decided to\n  # perform it automatically as, opposite to in_upper above, the\n  # dependencies are never really laid out in the parent tree.\n  defp with_matching(%{opts: other_opts} = other, key, _dep, opts, false) do\n    other_value = Keyword.get(other_opts, key)\n    value = Keyword.get(opts, key)\n\n    if other_value && value do\n      {:ok, put_in(other.opts[key], Enum.uniq(List.wrap(other_value) ++ List.wrap(value)))}\n    else\n      {:ok, %{other | opts: Keyword.delete(other_opts, key)}}\n    end\n  end\n\n  defp converge?(\n         %Mix.Dep{scm: scm1, opts: opts1, system_env: system_env1},\n         %Mix.Dep{scm: scm2, opts: opts2, system_env: system_env2}\n       ) do\n    scm1 == scm2 and system_env1 == system_env2 and opts_equal?(opts1, opts2) and\n      scm1.equal?(opts1, opts2)\n  end\n\n  defp opts_equal?(opts1, opts2) do\n    keys = ~w(app env compile manager)a\n    Enum.all?(keys, &(Keyword.fetch(opts1, &1) == Keyword.fetch(opts2, &1)))\n  end\n\n  defp reject_non_fulfilled_optional(deps) do\n    apps = Enum.map(deps, & &1.app)\n\n    for dep <- deps do\n      {_discarded, deps} = split_non_fulfilled_optional(dep.deps, apps, dep.opts[:from_umbrella])\n      %{dep | deps: deps}\n    end\n  end\n\n  defp split_non_fulfilled_optional(children, upper_breadths, umbrella?) do\n    Enum.split_with(children, fn %Mix.Dep{app: app, opts: opts} ->\n      opts[:optional] && app not in upper_breadths && !umbrella?\n    end)\n  end\n\n  defp merge_manager(%{manager: other_manager} = other, %{manager: manager}, in_upper?) do\n    %{other | manager: sort_manager(other_manager, manager, in_upper?)}\n  end\n\n  @managers [:mix, :rebar3, :make]\n\n  defp sort_manager(other_manager, manager, true) do\n    other_manager || manager\n  end\n\n  defp sort_manager(other_manager, manager, false) do\n    to_exclude = @managers -- (List.wrap(other_manager) ++ List.wrap(manager))\n    List.first(@managers -- to_exclude) || other_manager || manager\n  end\n\n  defp req_mismatch(%Mix.Dep{status: status}, %Mix.Dep{app: app, requirement: requirement}) do\n    with {:ok, vsn} when not is_nil(vsn) <- status,\n         true <- Mix.Dep.Loader.vsn_match(requirement, vsn, app) != {:ok, true} do\n      vsn\n    else\n      _ -> nil\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/dep/elixir_scm.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Manifest file where we treat Erlang/OTP, Elixir and SCMs as a dependency.\n# We also store the exact version this dependency was compiled for.\ndefmodule Mix.Dep.ElixirSCM do\n  @moduledoc false\n  @manifest \"compile.elixir_scm\"\n  @manifest_vsn 2\n\n  def manifest(manifest_path \\\\ Mix.Project.manifest_path()) do\n    Path.join(manifest_path, @manifest)\n  end\n\n  def update(manifest_path \\\\ Mix.Project.manifest_path(), scm, lock) do\n    File.mkdir_p!(manifest_path)\n\n    manifest_data =\n      {@manifest_vsn, {System.version(), :erlang.system_info(:otp_release)}, scm, lock}\n      |> :erlang.term_to_binary()\n\n    File.write!(manifest(manifest_path), manifest_data)\n  end\n\n  def read(manifest_path \\\\ Mix.Project.manifest_path()) do\n    case File.read(manifest(manifest_path)) do\n      {:ok, contents} ->\n        try do\n          {@manifest_vsn, vsn, scm, lock} = :erlang.binary_to_term(contents)\n          {:ok, vsn, scm, lock}\n        rescue\n          _ -> {:ok, {\"1.0.0\", ~c\"17\"}, nil, nil}\n        end\n\n      _ ->\n        :error\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/dep/fetcher.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Module responsible for fetching (getting/updating)\n# dependencies from their sources.\n#\n# The new_lock and old_lock mechanism exists to signal\n# externally which dependencies need to be updated and\n# which ones do not.\ndefmodule Mix.Dep.Fetcher do\n  @moduledoc false\n\n  import Mix.Dep, only: [format_dep: 1, check_lock: 1, available?: 1]\n\n  @doc \"\"\"\n  Fetches all dependencies.\n  \"\"\"\n  def all(old_lock, new_lock, opts) do\n    result = Mix.Dep.Converger.converge([], new_lock, opts, &do_fetch/3)\n    {apps, _deps} = do_finalize(result, old_lock, opts)\n    apps\n  end\n\n  @doc \"\"\"\n  Fetches the dependencies with the given names and their children recursively.\n  \"\"\"\n  def by_name(names, old_lock, new_lock, opts) do\n    fetcher = fetch_by_name(names, new_lock)\n    result = Mix.Dep.Converger.converge([], new_lock, opts, fetcher)\n    {apps, deps} = do_finalize(result, old_lock, opts)\n\n    # Check if all given dependencies are loaded or fail\n    _ = Mix.Dep.filter_by_name(names, deps, opts)\n    apps\n  end\n\n  defp fetch_by_name(given, lock) do\n    names = to_app_names(given)\n\n    fn %Mix.Dep{app: app} = dep, acc, new_lock ->\n      # Only fetch if dependency is in given names or if lock has\n      # been changed for dependency by remote converger or it is new\n      if app in names or lock[app] != new_lock[app] or is_nil(lock[app]) do\n        do_fetch(dep, acc, new_lock)\n      else\n        {dep, acc, new_lock}\n      end\n    end\n  end\n\n  defp do_fetch(dep, acc, lock) do\n    %Mix.Dep{app: app, scm: scm, opts: opts} = dep = check_lock(dep)\n\n    cond do\n      # Dependencies that cannot be fetched are always compiled afterwards\n      not scm.fetchable?() ->\n        if not scm.checked_out?(opts) do\n          Mix.shell().error(\"warning: missing dependency #{format_dep(dep)}\")\n        end\n\n        {dep, [app | acc], lock}\n\n      # If the dependency is not available or we have a lock mismatch\n      out_of_date?(dep) ->\n        # Mark the dependency as fetched upfront, in case updating fails,\n        # gets interrupted, or corrupted.\n        mark_as_fetched([dep])\n\n        new =\n          if scm.checked_out?(opts) do\n            Mix.shell().info(\"* Updating #{format_dep(dep)}\")\n            scm.update(opts)\n          else\n            Mix.shell().info(\"* Getting #{format_dep(dep)}\")\n            scm.checkout(opts)\n          end\n\n        if new do\n          dep = put_in(dep.opts[:lock], new)\n          {dep, [app | acc], Map.put(lock, app, new)}\n        else\n          {dep, acc, lock}\n        end\n\n      # The dependency is ok or has some other error\n      true ->\n        {dep, acc, lock}\n    end\n  end\n\n  defp out_of_date?(%Mix.Dep{status: {:lockmismatch, _}}), do: true\n  defp out_of_date?(%Mix.Dep{status: :lockoutdated}), do: true\n  defp out_of_date?(%Mix.Dep{status: :nolock}), do: true\n  defp out_of_date?(%Mix.Dep{status: {:unavailable, _}}), do: true\n  defp out_of_date?(%Mix.Dep{}), do: false\n\n  defp do_finalize({all_deps, apps, new_lock}, old_lock, opts) do\n    # Let's get the loaded versions of deps\n    deps = Mix.Dep.filter_by_name(apps, all_deps, opts)\n\n    # Note we only retrieve the parent dependencies of the updated\n    # deps if all dependencies are available. This is because if a\n    # dependency is missing, it could directly affect one of the\n    # dependencies we are trying to compile, causing the whole thing\n    # to fail.\n    parent_deps =\n      if Enum.all?(all_deps, &available?/1) do\n        Enum.uniq_by(with_depending(deps, all_deps), & &1.app)\n      else\n        []\n      end\n\n    # Mark parents as fetched before we write the lock file.\n    mark_as_fetched(parent_deps)\n\n    # Merge the new lock on top of the old to guarantee we don't\n    # leave out things that could not be fetched and save it.\n    lock = Map.merge(old_lock, new_lock)\n    Mix.Dep.Lock.write(lock, opts)\n\n    # See if any of the deps diverged and abort.\n    show_diverged!(Enum.filter(all_deps, &Mix.Dep.diverged?/1))\n\n    {apps, all_deps}\n  end\n\n  defp mark_as_fetched(deps) do\n    build_path =\n      Mix.Project.build_path()\n      |> Path.dirname()\n\n    for %Mix.Dep{app: app, scm: scm} <- deps, scm.fetchable?() do\n      build_path\n      |> Path.join(\"*/lib/#{app}/.mix/compile.elixir_scm\")\n      |> Path.wildcard(match_dot: true)\n      |> Enum.each(&File.rm/1)\n    end\n\n    :ok\n  end\n\n  defp with_depending(deps, all_deps) do\n    deps ++ do_with_depending(deps, all_deps)\n  end\n\n  defp do_with_depending([], _all_deps) do\n    []\n  end\n\n  defp do_with_depending(deps, all_deps) do\n    dep_names = Enum.map(deps, fn dep -> dep.app end)\n\n    parents =\n      Enum.filter(all_deps, fn dep ->\n        Enum.any?(dep.deps, &(&1.app in dep_names))\n      end)\n\n    do_with_depending(parents, all_deps) ++ parents\n  end\n\n  defp to_app_names(given) do\n    Enum.map(given, fn app ->\n      if is_binary(app), do: String.to_atom(app), else: app\n    end)\n  end\n\n  defp show_diverged!([]), do: :ok\n\n  defp show_diverged!(deps) do\n    shell = Mix.shell()\n    shell.error(\"Dependencies have diverged:\")\n\n    Enum.each(deps, fn dep ->\n      shell.error(\"* #{Mix.Dep.format_dep(dep)}\")\n      shell.error(\"  #{Mix.Dep.format_status(dep)}\")\n    end)\n\n    Mix.raise(\"Can't continue due to errors on dependencies\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/dep/loader.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# This module is responsible for loading dependencies\n# of the current project. This module and its functions\n# are private to Mix.\ndefmodule Mix.Dep.Loader do\n  @moduledoc false\n\n  import Mix.Dep, only: [ok?: 1, mix?: 1, rebar?: 1, make?: 1]\n\n  @doc \"\"\"\n  Gets all direct children of the current `Mix.Project`\n  as a `Mix.Dep` struct. Umbrella project dependencies\n  are included as children.\n\n  By default, it will filter all dependencies that does not match\n  current environment, behavior can be overridden via options.\n  \"\"\"\n  def children(locked?) do\n    mix_children(Mix.Project.config(), locked?, []) ++ Mix.Dep.Umbrella.unloaded()\n  end\n\n  @doc \"\"\"\n  Partitions loaded dependencies by environment.\n  \"\"\"\n  def split_by_env_and_target(deps, {nil, nil}), do: {deps, []}\n\n  def split_by_env_and_target(deps, env_target),\n    do: Enum.split_with(deps, &(not skip?(&1, env_target)))\n\n  @doc \"\"\"\n  Checks if a dependency must be skipped according to the environment.\n  \"\"\"\n  def skip?(%Mix.Dep{status: {:divergedonly, _}}, _), do: false\n  def skip?(%Mix.Dep{status: {:divergedtargets, _}}, _), do: false\n\n  def skip?(%Mix.Dep{opts: opts}, {env, target}) do\n    skip?(opts[:only], :only, env) or skip?(opts[:targets], :targets, target)\n  end\n\n  # The dependency is not filtered\n  defp skip?(nil, _key, _value), do: false\n\n  # The command is not filtered\n  defp skip?(_maybe_list_of_atoms, _key, nil), do: false\n\n  # The dependency is filtered as well as the command\n  defp skip?(maybe_list_of_atoms, key, value) do\n    wrapped = List.wrap(maybe_list_of_atoms)\n\n    for entry <- wrapped, not is_atom(entry) do\n      Mix.raise(\n        \"Expected #{inspect(key)} in dependency to be an atom or a list of atoms, \" <>\n          \"got: #{inspect(maybe_list_of_atoms)}\"\n      )\n    end\n\n    value not in wrapped\n  end\n\n  def with_system_env(%Mix.Dep{system_env: []}, callback), do: callback.()\n\n  def with_system_env(%Mix.Dep{system_env: new_env}, callback) do\n    old_env =\n      for {key, _} <- new_env do\n        key = to_string(key)\n        {key, System.get_env(key)}\n      end\n\n    try do\n      System.put_env(new_env)\n      callback.()\n    after\n      System.put_env(old_env)\n    end\n  end\n\n  @doc \"\"\"\n  Loads the given dependency information, including its\n  latest status and children.\n  \"\"\"\n  def load(%Mix.Dep{manager: manager, scm: scm, opts: opts} = dep, children, locked?) do\n    # The manager for a child dependency is set based on the following rules:\n    #   1. Set in dependency definition\n    #   2. From SCM, so that Hex dependencies of a rebar project can be compiled with mix\n    #   3. From the parent dependency, used for rebar dependencies from git\n    #   4. Inferred from files in dependency (mix.exs, rebar.config, Makefile)\n    manager = opts[:manager] || scm_manager(scm, opts) || manager || infer_manager(opts[:dest])\n    dep = %{dep | manager: manager, status: scm_status(scm, opts)}\n\n    {dep, children} =\n      cond do\n        not ok?(dep) ->\n          {dep, []}\n\n        mix?(dep) ->\n          mix_dep(dep, children, locked?)\n\n        # If not an explicit Rebar or Mix dependency\n        # but came from Rebar, assume to be a Rebar dep.\n        rebar?(dep) ->\n          rebar_dep(dep, children, manager, locked?)\n\n        make?(dep) ->\n          make_dep(dep)\n\n        true ->\n          {dep, []}\n      end\n\n    validate_app(%{dep | deps: attach_only_and_targets(children, opts)})\n  end\n\n  @doc \"\"\"\n  Checks if a requirement from a dependency matches\n  the given version.\n  \"\"\"\n  def vsn_match(nil, _actual, _app), do: {:ok, true}\n\n  def vsn_match(req, actual, app) do\n    if is_struct(req, Regex) do\n      {:ok, actual =~ req}\n    else\n      case Version.parse(actual) do\n        {:ok, version} ->\n          case Version.parse_requirement(req) do\n            {:ok, req} ->\n              {:ok, Version.match?(version, req)}\n\n            :error ->\n              Mix.raise(\"Invalid requirement #{req} for app #{app}\")\n          end\n\n        :error ->\n          {:error, :nosemver}\n      end\n    end\n  end\n\n  ## Helpers\n\n  defp to_dep(tuple, from, manager, locked?) do\n    %{with_scm_and_app(tuple, locked?) | from: from, manager: manager}\n  end\n\n  defp with_scm_and_app({app, opts} = original, locked?) when is_atom(app) and is_list(opts) do\n    with_scm_and_app(app, nil, opts, original, locked?)\n  end\n\n  defp with_scm_and_app({app, req} = original, locked?) when is_atom(app) do\n    if is_binary(req) or is_struct(req, Regex) do\n      with_scm_and_app(app, req, [], original, locked?)\n    else\n      invalid_dep_format(original)\n    end\n  end\n\n  defp with_scm_and_app({app, req, opts} = original, locked?)\n       when is_atom(app) and is_list(opts) do\n    if is_binary(req) or is_struct(req, Regex) do\n      with_scm_and_app(app, req, opts, original, locked?)\n    else\n      invalid_dep_format(original)\n    end\n  end\n\n  defp with_scm_and_app(original, _locked?) do\n    invalid_dep_format(original)\n  end\n\n  defp with_scm_and_app(app, req, opts, original, locked?) do\n    if not Keyword.keyword?(opts) do\n      invalid_dep_format(original)\n    end\n\n    bin_app = Atom.to_string(app)\n\n    config = Mix.Project.config()\n    dest = Path.join(Mix.Project.deps_path(config), bin_app)\n    build = Path.join([Mix.Project.build_path(config), \"lib\", bin_app])\n\n    opts =\n      opts\n      |> Keyword.put(:dest, dest)\n      |> Keyword.put(:build, build)\n\n    {system_env, opts} = Keyword.pop(opts, :system_env, [])\n    {scm, opts} = get_scm(app, opts)\n\n    {scm, opts} =\n      if is_nil(scm) and Mix.Hex.ensure_installed?(locked?) do\n        _ = Mix.Hex.start()\n        get_scm(app, opts)\n      else\n        {scm, opts}\n      end\n\n    if !scm do\n      Mix.raise(\n        \"Could not find an SCM for dependency #{inspect(app)} from #{inspect(Mix.Project.get())}\"\n      )\n    end\n\n    if config[:app] == app do\n      Mix.shell().error(\n        \"warning: the application name #{inspect(app)} is the same as one of its dependencies\"\n      )\n    end\n\n    %Mix.Dep{\n      scm: scm,\n      app: app,\n      requirement: req,\n      status: scm_status(scm, opts),\n      opts: Keyword.put_new(opts, :env, :prod),\n      system_env: Enum.to_list(system_env)\n    }\n  end\n\n  defp get_scm(app, opts) do\n    Enum.find_value(Mix.SCM.available(), {nil, opts}, fn scm ->\n      (new = scm.accepts_options(app, opts)) && {scm, new}\n    end)\n  end\n\n  # Note that we ignore Make dependencies because the\n  # file based heuristic will always figure it out.\n  @scm_managers ~w(mix rebar3)a\n\n  defp scm_manager(scm, opts) do\n    managers = scm.managers(opts)\n    Enum.find(@scm_managers, &(&1 in managers))\n  end\n\n  defp scm_status(scm, opts) do\n    if scm.checked_out?(opts) do\n      {:ok, nil}\n    else\n      {:unavailable, opts[:dest]}\n    end\n  end\n\n  defp infer_manager(dest) do\n    cond do\n      any_of?(dest, [\"mix.exs\"]) ->\n        :mix\n\n      any_of?(dest, [\"rebar\", \"rebar.config\", \"rebar.config.script\", \"rebar.lock\"]) ->\n        :rebar3\n\n      any_of?(dest, [\"Makefile\", \"Makefile.win\"]) ->\n        :make\n\n      true ->\n        nil\n    end\n  end\n\n  defp any_of?(dest, files) do\n    Enum.any?(files, &File.regular?(Path.join(dest, &1)))\n  end\n\n  defp invalid_dep_format(dep) do\n    Mix.raise(\"\"\"\n    Dependency specified in the wrong format:\n\n        #{inspect(dep)}\n\n    Expected:\n\n        {app, opts} | {app, requirement} | {app, requirement, opts}\n\n    Where:\n\n        app :: atom\n        requirement :: String.t | Regex.t\n        opts :: keyword\n\n    If you want to skip the requirement (not recommended), use \">= 0.0.0\".\n    \"\"\")\n  end\n\n  ## Fetching\n\n  # We need to override the dependencies so they mirror\n  # the :only and :targets requirements from the parent.\n  defp attach_only_and_targets(deps, opts) do\n    case Keyword.take(opts, [:only, :targets]) do\n      [] ->\n        deps\n\n      merge_opts ->\n        Enum.map(deps, fn %{opts: opts} = dep ->\n          %{dep | opts: Keyword.merge(merge_opts, opts)}\n        end)\n    end\n  end\n\n  defp mix_dep(%Mix.Dep{app: app, opts: opts} = dep, nil, locked?) do\n    Mix.Dep.in_dependency(dep, fn _ ->\n      config = Mix.Project.config()\n\n      opts =\n        if Mix.Project.umbrella?() do\n          Keyword.put_new(opts, :app, false)\n        else\n          opts\n        end\n\n      child_opts =\n        if opts[:from_umbrella] do\n          if config[:app] != app do\n            Mix.raise(\n              \"Umbrella app #{inspect(config[:app])} is located at \" <>\n                \"directory #{app}. Mix requires the directory to match \" <>\n                \"the application name for umbrella apps. Please rename the \" <>\n                \"directory or change the application name in the mix.exs file.\"\n            )\n          end\n\n          []\n        else\n          [env: Keyword.fetch!(opts, :env)]\n        end\n\n      deps = mix_children(config, locked?, child_opts) ++ Mix.Dep.Umbrella.unloaded()\n      {%{dep | opts: opts}, deps}\n    end)\n  end\n\n  # If we have a Mix dependency that came from a remote converger,\n  # we just use the dependencies given by the remote converger,\n  # we don't need to load the mix.exs at all. We can only do this\n  # because umbrella projects are not supported in remotes.\n  defp mix_dep(%Mix.Dep{opts: opts} = dep, children, locked?) do\n    from = Path.join(opts[:dest], \"mix.exs\")\n    deps = Enum.map(children, &to_dep(&1, from, _manager = nil, locked?))\n    {dep, deps}\n  end\n\n  defp rebar_dep(dep, children, manager, locked?) do\n    %Mix.Dep{app: app, opts: opts, extra: overrides} = dep\n\n    if locked? and not Mix.Rebar.available?(manager) do\n      Mix.Tasks.Local.Rebar.run([\"--force\"])\n    end\n\n    config = File.cd!(opts[:dest], fn -> Mix.Rebar.load_config(\".\") end)\n    config = Mix.Rebar.apply_overrides(app, config, overrides)\n\n    deps =\n      if children do\n        from = Path.join(opts[:dest], \"rebar.config\")\n        # Pass the manager because deps of a Rebar project need\n        # to default to Rebar if we cannot chose a manager from\n        # files in the dependency\n        Enum.map(children, &to_dep(&1, from, manager, locked?))\n      else\n        rebar_children(config, manager, opts[:dest], locked?)\n      end\n\n    {%{dep | extra: config}, deps}\n  end\n\n  defp make_dep(dep) do\n    {dep, []}\n  end\n\n  defp mix_children(config, locked?, opts) do\n    from = Mix.Project.project_file()\n\n    (config[:deps] || [])\n    |> Enum.map(&to_dep(&1, from, _manager = nil, locked?))\n    |> split_by_env_and_target({opts[:env], nil})\n    |> elem(0)\n  end\n\n  defp rebar_children(config, manager, dest, locked?) do\n    from = Path.absname(Path.join(dest, \"rebar.config\"))\n    overrides = overrides(manager, config)\n\n    config\n    |> Mix.Rebar.deps()\n    |> Enum.map(fn dep -> %{to_dep(dep, from, manager, locked?) | extra: overrides} end)\n  end\n\n  defp overrides(:rebar3, config), do: config[:overrides] || []\n  defp overrides(_, _config), do: []\n\n  defp validate_app(%Mix.Dep{opts: opts, requirement: req, app: app} = dep) do\n    opts_app = opts[:app]\n\n    cond do\n      not ok?(dep) ->\n        dep\n\n      opts_app == false ->\n        dep\n\n      true ->\n        path = if is_binary(opts_app), do: opts_app, else: \"ebin/#{app}.app\"\n        path = Path.expand(path, opts[:build])\n\n        case app_status(path, app, req) do\n          {:ok, vsn, app} -> %{dep | status: {:ok, vsn}, opts: [app_properties: app] ++ opts}\n          status -> %{dep | status: status}\n        end\n    end\n  end\n\n  defp app_status(app_path, app, req) do\n    case Mix.AppLoader.read_app(app, app_path) do\n      {:ok, properties} ->\n        case List.keyfind(properties, :vsn, 0) do\n          {:vsn, actual} when is_list(actual) ->\n            actual = IO.iodata_to_binary(actual)\n\n            case vsn_match(req, actual, app) do\n              {:ok, true} -> compile_env_status(actual, properties)\n              {:ok, false} -> {:nomatchvsn, actual}\n              {:error, error} -> {error, actual}\n            end\n\n          {:vsn, actual} ->\n            {:invalidvsn, actual}\n\n          nil ->\n            {:invalidvsn, nil}\n        end\n\n      :invalid ->\n        {:invalidapp, app_path}\n\n      :missing ->\n        case Path.wildcard(Path.join(Path.dirname(app_path), \"*.app\")) do\n          [other_app_path] -> {:noappfile, {app_path, other_app_path}}\n          _ -> {:noappfile, {app_path, nil}}\n        end\n    end\n  end\n\n  defp compile_env_status(vsn, properties) do\n    with [_ | _] = compile_env <- properties[:compile_env],\n         false <- Config.Provider.valid_compile_env?(compile_env) do\n      :envoutdated\n    else\n      _ -> {:ok, vsn, properties}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/dep/lock.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# This module keeps a lock file and the manifest for the lock file.\n# The lockfile keeps the latest dependency information while the\n# manifest is used whenever a dependency is affected via any of the\n# deps.* tasks. We also keep the Elixir version in the manifest file.\ndefmodule Mix.Dep.Lock do\n  @moduledoc false\n\n  @typedoc \"\"\"\n  Options for `write/2`.\n  \"\"\"\n  @type write_opts :: [\n          file: Path.t(),\n          check_locked: boolean()\n        ]\n\n  @doc \"\"\"\n  Reads the lockfile, returns a map containing\n  each app name and its current lock information.\n  \"\"\"\n  @spec read(Path.t()) :: map()\n  def read(lockfile \\\\ lockfile()) do\n    opts = [file: lockfile, emit_warnings: false]\n\n    with {:ok, contents} <- File.read(lockfile),\n         assert_no_merge_conflicts_in_lockfile(lockfile, contents),\n         {:ok, quoted} <- Code.string_to_quoted(contents, opts),\n         {%{} = lock, _binding} <- Code.eval_quoted(quoted, [], opts) do\n      lock\n    else\n      _ -> %{}\n    end\n  end\n\n  @doc \"\"\"\n  Receives a map and writes it as the latest lock.\n  \"\"\"\n  @spec write(map(), write_opts) :: :ok\n  def write(map, opts \\\\ []) do\n    lockfile = opts[:file] || lockfile()\n\n    if map != read() do\n      if Keyword.get(opts, :check_locked, false) do\n        Mix.raise(\n          \"Your #{lockfile} is out of date and must be updated without the --check-locked flag\"\n        )\n      end\n\n      lines =\n        for {app, rev} <- Enum.sort(map), rev != nil do\n          ~s(  \"#{app}\": #{inspect(rev, limit: :infinity)},\\n)\n        end\n\n      File.write!(lockfile, [\"%{\\n\", lines, \"}\\n\"])\n      Mix.Task.run(\"will_recompile\")\n    end\n\n    :ok\n  end\n\n  defp lockfile do\n    Mix.Project.config()[:lockfile]\n  end\n\n  defp assert_no_merge_conflicts_in_lockfile(lockfile, info) do\n    if String.contains?(info, ~w(<<<<<<< ======= >>>>>>>)) do\n      Mix.raise(\n        \"Your #{lockfile} contains merge conflicts. Please resolve the conflicts \" <>\n          \"and run the command again\"\n      )\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/dep/umbrella.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Dep.Umbrella do\n  @moduledoc false\n\n  @doc \"\"\"\n  Gets all umbrella dependencies in unloaded format.\n  \"\"\"\n  def unloaded do\n    config = Mix.Project.config()\n\n    if apps_paths = Mix.Project.apps_paths(config) do\n      env = Mix.env()\n      from = Path.absname(\"mix.exs\")\n      build = Mix.Project.build_path(config)\n\n      for {app, path} <- apps_paths do\n        dest_path = Path.expand(path)\n        build_path = Path.join([build, \"lib\", Atom.to_string(app)])\n\n        opts = [\n          path: path,\n          dest: dest_path,\n          from_umbrella: true,\n          env: env,\n          build: build_path\n        ]\n\n        %Mix.Dep{\n          scm: Mix.SCM.Path,\n          app: app,\n          requirement: nil,\n          manager: :mix,\n          status: {:ok, nil},\n          from: from,\n          opts: opts\n        }\n      end\n    else\n      []\n    end\n  end\n\n  @doc \"\"\"\n  Gets all umbrella dependencies in the loaded format from cache (if available).\n  \"\"\"\n  def cached do\n    if project = Mix.Project.get() do\n      key = {:umbrella_deps, Mix.env(), project}\n      Mix.State.read_cache(key) || Mix.State.write_cache(key, loaded())\n    else\n      loaded()\n    end\n  end\n\n  @doc \"\"\"\n  Gets all umbrella dependencies in the loaded format.\n  \"\"\"\n  def loaded do\n    deps = unloaded()\n    apps = Enum.map(deps, & &1.app)\n\n    Enum.map(deps, fn umbrella_dep ->\n      umbrella_dep = Mix.Dep.Loader.load(umbrella_dep, nil, false)\n\n      deps =\n        Enum.filter(umbrella_dep.deps, fn dep ->\n          Mix.Dep.available?(dep) and dep.app in apps\n        end)\n\n      %{umbrella_dep | deps: deps}\n    end)\n    |> Mix.Dep.Converger.topological_sort()\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/dep.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Dep do\n  @moduledoc false\n\n  @doc \"\"\"\n  The Mix.Dep struct keeps information about your project dependencies.\n\n  It contains:\n\n    * `scm` - a module representing the source code management tool (SCM)\n      operations\n\n    * `app` - the application name as an atom\n\n    * `requirement` - a binary or regular expression with the dependency's requirement\n\n    * `status` - the current status of the dependency, check\n      `Mix.Dep.format_status/1` for more information\n\n    * `opts` - the options given by the developer\n\n    * `deps` - dependencies of this dependency\n\n    * `top_level` - true if dependency was defined in the top-level project\n\n    * `manager` - the project management, possible values:\n      `:rebar3` | `:mix` | `:make` | `nil`\n\n    * `from` - path to the file where the dependency was defined\n\n    * `extra` - a slot for adding extra configuration based on the manager;\n      the information on this field is private to the manager and should not be\n      relied on\n\n    * `system_env` - an enumerable of key-value tuples of binaries to be set as environment variables\n      when loading or compiling the dependency\n\n  A dependency is in two specific states: loaded and unloaded.\n\n  When a dependency is unloaded, it means Mix only parsed its specification\n  and made no attempt to actually load the dependency or validate its\n  status. When the dependency is loaded, it means Mix attempted to fetch,\n  load and validate it, the status is set in the status field.\n\n  Furthermore, in the `opts` fields, Mix keeps some internal options, which\n  can be accessed by SCMs:\n\n    * `:app`   - the application name\n    * `:dest`  - the destination path for the dependency\n    * `:lock`  - the lock information retrieved from mix.lock\n    * `:build` - the build path for the dependency\n\n  \"\"\"\n  defstruct scm: nil,\n            app: nil,\n            requirement: nil,\n            status: nil,\n            opts: [],\n            deps: [],\n            top_level: false,\n            extra: [],\n            manager: nil,\n            from: nil,\n            system_env: []\n\n  @type t :: %__MODULE__{\n          scm: Mix.SCM.t(),\n          app: atom,\n          requirement: String.t() | Regex.t() | nil,\n          status: {:ok, String.t() | nil} | atom | tuple,\n          opts: keyword,\n          top_level: boolean,\n          manager: :rebar3 | :mix | :make | nil,\n          from: String.t(),\n          extra: term,\n          system_env: keyword\n        }\n\n  @doc \"\"\"\n  Returns loaded dependencies from the cache for the current environment.\n\n  If dependencies have not been cached yet, they are loaded\n  and then cached.\n\n  Because the dependencies are cached during deps.loadpaths,\n  their status may be outdated (for example, `:compile` did not\n  yet become `:ok`). Therefore it is recommended to not rely\n  on their status, also given they haven't been checked\n  against the lock.\n  \"\"\"\n  def cached() do\n    if project = Mix.Project.get() do\n      read_cached_deps(project, {Mix.env(), Mix.target()}) || load_and_cache()\n    else\n      load_and_cache()\n    end\n  end\n\n  @doc \"\"\"\n  Returns loaded dependencies recursively and caches it.\n\n  The result is cached for future `cached/0` calls.\n\n  ## Exceptions\n\n  This function raises an exception if any of the dependencies\n  provided in the project are in the wrong format.\n  \"\"\"\n  def load_and_cache() do\n    env = Mix.env()\n    target = Mix.target()\n\n    case Mix.ProjectStack.top_and_bottom() do\n      {%{name: top, config: config}, %{name: bottom}} ->\n        write_cached_deps(top, {env, target}, load_and_cache(config, top, bottom, env, target))\n\n      _ ->\n        converge_and_load(env: env, target: target)\n    end\n  end\n\n  defp load_and_cache(_config, top, top, env, target) do\n    converge_and_load(env: env, target: target)\n  end\n\n  defp load_and_cache(config, _top, bottom, _env, _target) do\n    {_, deps} =\n      Mix.State.read_cache({:cached_deps, bottom}) ||\n        raise \"cannot retrieve dependencies information because dependencies were not loaded. \" <>\n                \"Please invoke one of \\\"deps.loadpaths\\\", \\\"loadpaths\\\", or \\\"compile\\\" Mix task\"\n\n    app = Keyword.fetch!(config, :app)\n    seen = populate_seen(MapSet.new(), [app])\n    children = get_deps(deps, tl(Enum.uniq(get_children(deps, seen, [app]))))\n\n    top_level =\n      for dep <- deps,\n          dep.app == app,\n          child <- dep.deps,\n          do: {child.app, Keyword.get(child.opts, :optional, false)},\n          into: %{}\n\n    Enum.map(children, fn %{app: app, opts: opts} = dep ->\n      # optional only matters at the top level. Any non-top level dependency\n      # that is optional and is still available means it has been fulfilled.\n      case top_level do\n        %{^app => optional} ->\n          %{dep | top_level: true, opts: Keyword.put(opts, :optional, optional)}\n\n        %{} ->\n          %{dep | top_level: false, opts: Keyword.delete(opts, :optional)}\n      end\n    end)\n  end\n\n  defp converge_and_load(opts) do\n    for %{app: app, opts: opts} = dep <- Mix.Dep.Converger.converge(opts) do\n      case Keyword.pop(opts, :app_properties) do\n        {nil, _opts} ->\n          dep\n\n        {app_properties, opts} ->\n          # We don't raise because child dependencies may be missing if manually cleaned\n          :application.load({:application, app, app_properties})\n          %{dep | opts: opts}\n      end\n    end\n  end\n\n  defp read_cached_deps(project, env_target) do\n    case Mix.State.read_cache({:cached_deps, project}) do\n      {^env_target, deps} -> deps\n      _ -> nil\n    end\n  end\n\n  defp write_cached_deps(project, env_target, deps) do\n    Mix.State.write_cache({:cached_deps, project}, {env_target, deps})\n    deps\n  end\n\n  @doc \"\"\"\n  Clears loaded dependencies from the cache for the current environment.\n  \"\"\"\n  def clear_cached() do\n    if project = Mix.Project.get() do\n      key = {:cached_deps, project}\n      Mix.State.delete_cache(key)\n    end\n  end\n\n  @doc \"\"\"\n  Filters the given dependencies by name.\n\n  Raises if any of the names are missing.\n  \"\"\"\n  def filter_by_name(given, all_deps, opts \\\\ []) do\n    # Ensure all apps are atoms\n    apps = to_app_names(given)\n\n    deps =\n      if opts[:include_children] do\n        seen = populate_seen(MapSet.new(), apps)\n        get_deps(all_deps, Enum.uniq(get_children(all_deps, seen, apps)))\n      else\n        get_deps(all_deps, apps)\n      end\n\n    Enum.each(apps, fn app ->\n      if not Enum.any?(all_deps, &(&1.app == app)) do\n        Mix.raise(\"Unknown dependency #{app} for environment #{Mix.env()}\")\n      end\n    end)\n\n    deps\n  end\n\n  defp get_deps(all_deps, apps) do\n    Enum.filter(all_deps, &(&1.app in apps))\n  end\n\n  defp get_children(_all_deps, _seen, []), do: []\n\n  defp get_children(all_deps, seen, apps) do\n    children_apps =\n      for %{deps: children} <- get_deps(all_deps, apps),\n          %{app: app} <- children,\n          app not in seen,\n          do: app\n\n    apps ++ get_children(all_deps, populate_seen(seen, children_apps), children_apps)\n  end\n\n  defp populate_seen(seen, apps) do\n    Enum.reduce(apps, seen, &MapSet.put(&2, &1))\n  end\n\n  @doc \"\"\"\n  Runs the given `fun` inside the given dependency project by\n  changing the current working directory and loading the given\n  project onto the project stack.\n\n  It expects a loaded dependency as argument.\n  \"\"\"\n  def in_dependency(dep, post_config \\\\ [], fun)\n\n  def in_dependency(%Mix.Dep{app: app, opts: opts, scm: scm}, config, fun) do\n    # Set the deps_app_path to be the one stored in the dependency.\n    # This is important because the name of application in the\n    # mix.exs file can be different than the actual name and we\n    # choose to respect the one in the mix.exs\n    config =\n      Mix.Project.deps_config()\n      |> Keyword.merge(config)\n      |> Keyword.put(:build_scm, scm)\n      |> Keyword.put(:deps_app_path, opts[:build])\n\n    config =\n      if scm.fetchable?() do\n        # If the dependency is fetchable, we want to store the lock in\n        # the Elixir SCM file.\n        [deps_lock: opts[:lock]] ++ config\n      else\n        # If the dependency is not fetchable, then it is never compiled\n        # from scratch and therefore it needs the parent configuration\n        # files to know when to recompile.\n        [inherit_parent_config_files: true] ++ config\n      end\n\n    env = opts[:env] || :prod\n    old_env = Mix.env()\n\n    try do\n      Mix.env(env)\n      Mix.Project.in_project(app, opts[:dest], config, fun)\n    after\n      Mix.env(old_env)\n    end\n  end\n\n  @doc \"\"\"\n  Formats the status of a dependency.\n  \"\"\"\n  def format_status(%Mix.Dep{status: {:ok, _vsn}}) do\n    \"ok\"\n  end\n\n  def format_status(%Mix.Dep{status: {:noappfile, {path, nil}}}) do\n    \"could not find an app file at #{inspect(Path.relative_to_cwd(path))}. \" <>\n      \"This may happen if the dependency was not yet compiled \" <>\n      \"or the dependency indeed has no app file (then you can pass app: false as option)\"\n  end\n\n  def format_status(%Mix.Dep{status: {:noappfile, {path, other_path}}}) do\n    other_app = Path.rootname(Path.basename(other_path))\n\n    \"could not find an app file at #{inspect(Path.relative_to_cwd(path))}. \" <>\n      \"Another app file was found in the same directory \" <>\n      \"#{inspect(Path.relative_to_cwd(other_path))}, \" <>\n      \"try changing the dependency name to :#{other_app}\"\n  end\n\n  def format_status(%Mix.Dep{status: {:invalidapp, path}}) do\n    \"the app file at #{inspect(Path.relative_to_cwd(path))} is invalid\"\n  end\n\n  def format_status(%Mix.Dep{status: {:invalidvsn, vsn}}) do\n    \"the app file contains an invalid version: #{inspect(vsn)}\"\n  end\n\n  def format_status(%Mix.Dep{status: {:nosemver, vsn}, requirement: req}) do\n    \"the app file specified a non-Semantic Versioning format: #{inspect(vsn)}. Mix can only match the \" <>\n      \"requirement #{inspect(req)} against semantic versions. Please fix the application version \" <>\n      \"or use a regular expression as a requirement to match against any version\"\n  end\n\n  def format_status(%Mix.Dep{status: {:nomatchvsn, vsn}, requirement: req}) do\n    \"the dependency does not match the requirement #{inspect(req)}, got #{inspect(vsn)}\"\n  end\n\n  def format_status(%Mix.Dep{status: {:lockmismatch, _}}) do\n    \"lock mismatch: the dependency is out of date. To fetch locked version run \\\"mix deps.get\\\"\"\n  end\n\n  def format_status(%Mix.Dep{status: :lockoutdated}) do\n    \"lock outdated: the lock is outdated compared to the options in your mix.exs. To fetch \" <>\n      \"locked version run \\\"mix deps.get\\\"\"\n  end\n\n  def format_status(%Mix.Dep{status: :nolock}) do\n    \"the dependency is not locked. To generate the \\\"mix.lock\\\" file run \\\"mix deps.get\\\"\"\n  end\n\n  def format_status(%Mix.Dep{status: :compile}) do\n    \"the dependency build is outdated, please run \\\"#{mix_env_var()}mix deps.compile\\\"\"\n  end\n\n  def format_status(%Mix.Dep{status: :envoutdated}) do\n    \"the dependency compile environment is outdated, please run \\\"#{mix_env_var()}mix deps.compile\\\"\"\n  end\n\n  def format_status(%Mix.Dep{app: app, status: {:divergedreq, vsn, parent, other}} = dep) do\n    override = if parent, do: [parent], else: true\n\n    \"the dependency #{app} #{vsn}\\n\" <>\n      dep_status(dep) <>\n      \"\\n  does not match the requirement specified\\n\" <>\n      dep_status(other) <>\n      \"\\n  Ensure they match or specify one of the above in your deps and set \\\"override: #{inspect(override)}\\\"\"\n  end\n\n  def format_status(%Mix.Dep{app: app, status: {:divergedonly, other}} = dep) do\n    recommendation =\n      if Keyword.has_key?(other.opts, :only) do\n        \"Ensure you specify at least the same environments in :only in your dep\"\n      else\n        \"Remove the :only restriction from your dep\"\n      end\n\n    \"the :only option for dependency #{app}\\n\" <>\n      dep_status(dep) <>\n      \"\\n  does not match the :only option calculated for\\n\" <>\n      dep_status(other) <> \"\\n  #{recommendation}\"\n  end\n\n  def format_status(%Mix.Dep{app: app, status: {:divergedtargets, other}} = dep) do\n    recommendation =\n      if Keyword.has_key?(other.opts, :targets) do\n        \"Ensure you specify at least the same targets in :targets in your dep\"\n      else\n        \"Remove the :targets restriction from your dep\"\n      end\n\n    \"the :targets option for dependency #{app}\\n\" <>\n      dep_status(dep) <>\n      \"\\n  does not match the :targets option calculated for\\n\" <>\n      dep_status(other) <> \"\\n  #{recommendation}\"\n  end\n\n  def format_status(%Mix.Dep{app: app, status: {:diverged, parent, other}} = dep) do\n    \"different specs were given for the #{app} app:\\n\" <>\n      \"#{dep_status(dep)}#{dep_status(other)}\\n  \" <>\n      override_diverge_recommendation(dep, parent, other)\n  end\n\n  def format_status(%Mix.Dep{app: app, status: {:overridden, parent, other}} = dep) do\n    \"the dependency #{app} in #{Path.relative_to_cwd(dep.from)} is overriding a child dependency:\\n\" <>\n      \"#{dep_status(dep)}#{dep_status(other)}\\n  \" <>\n      override_diverge_recommendation(dep, parent, other)\n  end\n\n  def format_status(%Mix.Dep{status: {:unavailable, _}, scm: scm}) do\n    if scm.fetchable?() do\n      \"the dependency is not available, run \\\"mix deps.get\\\"\"\n    else\n      \"the dependency is not available\"\n    end\n  end\n\n  def format_status(%Mix.Dep{status: {:vsnlock, _}}) do\n    \"the dependency was built with an out-of-date Erlang/Elixir version, run \\\"#{mix_env_var()}mix deps.compile\\\"\"\n  end\n\n  def format_status(%Mix.Dep{status: {:scmlock, _}}) do\n    \"the dependency was built with another SCM, run \\\"#{mix_env_var()}mix deps.compile\\\"\"\n  end\n\n  defp override_diverge_recommendation(dep, parent, other) do\n    if dep.opts[:from_umbrella] || other.opts[:from_umbrella] do\n      \"Please remove the conflicting options from your definition\"\n    else\n      override = if parent, do: [parent], else: true\n\n      \"Ensure they match or specify one of the above in your deps \" <>\n        \"and set \\\"override: #{inspect(override)}\\\"\"\n    end\n  end\n\n  defp dep_status(%Mix.Dep{} = dep) do\n    %{\n      app: app,\n      requirement: req,\n      manager: manager,\n      opts: opts,\n      from: from,\n      system_env: system_env\n    } = dep\n\n    opts =\n      []\n      |> Kernel.++(if manager, do: [manager: manager], else: [])\n      |> Kernel.++(if system_env != [], do: [system_env: system_env], else: [])\n      |> Kernel.++(opts)\n      |> Keyword.drop([:dest, :build, :lock, :manager, :checkout, :app_properties])\n\n    info = if req, do: {app, req, opts}, else: {app, opts}\n    \"\\n  > In #{Path.relative_to_cwd(from)}:\\n    #{inspect(info)}\\n\"\n  end\n\n  @doc \"\"\"\n  Checks the lock for the given dependency and update its status accordingly.\n  \"\"\"\n  def check_lock(%Mix.Dep{scm: scm, opts: opts} = dep) do\n    if available?(dep) do\n      case scm.lock_status(opts) do\n        :mismatch ->\n          status = if rev = opts[:lock], do: {:lockmismatch, rev}, else: :nolock\n          %{dep | status: status}\n\n        :outdated ->\n          # Don't include the lock in the dependency if it is outdated\n          %{dep | status: :lockoutdated}\n\n        :ok ->\n          check_manifest(dep)\n      end\n    else\n      dep\n    end\n  end\n\n  defp check_manifest(%{scm: scm, opts: opts} = dep) do\n    vsn = {System.version(), :erlang.system_info(:otp_release)}\n    lock = opts[:lock]\n\n    case Mix.Dep.ElixirSCM.read(Path.join(opts[:build], \".mix\")) do\n      {:ok, old_vsn, _, _} when old_vsn != vsn ->\n        %{dep | status: {:vsnlock, old_vsn}}\n\n      {:ok, _, old_scm, _} when old_scm != scm ->\n        %{dep | status: {:scmlock, old_scm}}\n\n      {:ok, _, _, old_lock} when old_lock != lock ->\n        %{dep | status: :compile}\n\n      :error ->\n        if scm.fetchable?() do\n          %{dep | status: :compile}\n        else\n          dep\n        end\n\n      # If the file is missing, it is handled in the loader\n      _ ->\n        dep\n    end\n  end\n\n  @doc \"\"\"\n  Returns `true` if the dependency is ok.\n  \"\"\"\n  def ok?(%Mix.Dep{status: {:ok, _}}), do: true\n  def ok?(%Mix.Dep{}), do: false\n\n  @doc \"\"\"\n  Checks if a dependency is available.\n\n  Available dependencies are the ones that can be loaded.\n  \"\"\"\n  def available?(%Mix.Dep{status: {:unavailable, _}}), do: false\n  def available?(dep), do: not diverged?(dep)\n\n  @doc \"\"\"\n  Checks if a dependency has diverged.\n  \"\"\"\n  def diverged?(%Mix.Dep{status: {:overridden, _, _}}), do: true\n  def diverged?(%Mix.Dep{status: {:diverged, _, _}}), do: true\n  def diverged?(%Mix.Dep{status: {:divergedreq, _, _, _}}), do: true\n  def diverged?(%Mix.Dep{status: {:divergedonly, _}}), do: true\n  def diverged?(%Mix.Dep{status: {:divergedtargets, _}}), do: true\n  def diverged?(%Mix.Dep{}), do: false\n\n  @doc \"\"\"\n  Returns `true` if the dependency is compilable.\n  \"\"\"\n  def compilable?(%Mix.Dep{status: :envoutdated}), do: true\n  def compilable?(dep), do: force_compilable?(dep)\n\n  @doc \"\"\"\n  Returns `true` if the dependency is force compilable.\n\n  This is a subset of compilable. This is used in `deps.compile` to\n  clean the build path before compiling.\n  \"\"\"\n  def force_compilable?(%Mix.Dep{status: {:vsnlock, _}}), do: true\n  def force_compilable?(%Mix.Dep{status: {:noappfile, {_, _}}}), do: true\n  def force_compilable?(%Mix.Dep{status: {:scmlock, _}}), do: true\n  def force_compilable?(%Mix.Dep{status: :compile}), do: true\n  def force_compilable?(_), do: false\n\n  @doc \"\"\"\n  Formats a dependency for printing.\n  \"\"\"\n  def format_dep(%Mix.Dep{scm: scm, app: app, status: status, opts: opts}) do\n    version =\n      case status do\n        {:ok, vsn} when vsn != nil -> \"#{vsn} \"\n        _ -> \"\"\n      end\n\n    \"#{app} #{version}(#{scm.format(opts)})\"\n  end\n\n  @doc \"\"\"\n  Returns all load paths for the given dependency.\n\n  Automatically derived from source paths.\n  \"\"\"\n  def load_paths(%Mix.Dep{app: app, opts: opts}) do\n    build_path = Path.dirname(opts[:build])\n    [Path.join([build_path, Atom.to_string(app), \"ebin\"])]\n  end\n\n  @doc \"\"\"\n  Returns `true` if dependency is a Mix project.\n  \"\"\"\n  def mix?(%Mix.Dep{manager: manager}) do\n    manager == :mix\n  end\n\n  @doc \"\"\"\n  Returns `true` if dependency is a Rebar project.\n  \"\"\"\n  def rebar?(%Mix.Dep{manager: manager}) do\n    manager == :rebar3\n  end\n\n  @doc \"\"\"\n  Returns `true` if dependency is a Make project.\n  \"\"\"\n  def make?(%Mix.Dep{manager: manager}) do\n    manager == :make\n  end\n\n  ## Helpers\n\n  defp mix_env_var do\n    if Mix.env() == :dev do\n      \"\"\n    else\n      \"MIX_ENV=#{Mix.env()} \"\n    end\n  end\n\n  defp to_app_names(given) do\n    Enum.map(given, fn app ->\n      if is_binary(app), do: String.to_atom(app), else: app\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/exceptions.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.NoTaskError do\n  defexception [:task, :message, mix: true]\n\n  @impl true\n  def exception(opts) do\n    task = opts[:task]\n    %Mix.NoTaskError{task: task, message: msg(task)}\n  end\n\n  defp msg(task) do\n    msg = \"The task #{inspect(task)} could not be found\"\n\n    case did_you_mean(task) do\n      {mod, ^task, _score} ->\n        msg <>\n          \" because the module is named #{inspect(mod)} instead of \" <>\n          \"#{expected_mod_name(task)} as expected. Please rename it and try again\"\n\n      {_mod, similar, score} when score > 0.8 ->\n        msg <> \". Did you mean #{inspect(similar)}?\" <> maybe_no_project()\n\n      _otherwise ->\n        msg <> maybe_no_project()\n    end\n  end\n\n  defp maybe_no_project do\n    if Mix.Project.get() do\n      \"\"\n    else\n      \"\\nNote no mix.exs was found in the current directory\"\n    end\n  end\n\n  defp did_you_mean(task) do\n    # Ensure all tasks are loaded\n    Mix.Task.load_all()\n\n    Mix.Task.all_modules()\n    |> Enum.map(&{&1, Mix.Task.task_name(&1)})\n    |> Enum.reduce({nil, nil, 0}, &max_similar(&1, task, &2))\n  end\n\n  defp max_similar({mod, source}, target, {_, _, current} = best) do\n    score = String.jaro_distance(source, target)\n    if score < current, do: best, else: {mod, source, score}\n  end\n\n  defp expected_mod_name(task) do\n    \"Mix.Tasks.\" <> Mix.Utils.command_to_module_name(task)\n  end\nend\n\ndefmodule Mix.InvalidTaskError do\n  defexception [:task, :message, mix: true]\n\n  @impl true\n  def exception(opts) do\n    task = opts[:task]\n    %Mix.InvalidTaskError{task: task, message: \"The task #{inspect(task)} does not export run/1\"}\n  end\nend\n\ndefmodule Mix.ElixirVersionError do\n  defexception [:target, :expected, :actual, :message, mix: true]\n\n  @impl true\n  def exception(opts) do\n    target = opts[:target]\n    actual = opts[:actual]\n    expected = opts[:expected]\n\n    message =\n      \"You're trying to run #{inspect(target)} on Elixir v#{actual} but it \" <>\n        \"has declared in its mix.exs file it supports only Elixir #{expected}\"\n\n    %Mix.ElixirVersionError{target: target, expected: expected, actual: actual, message: message}\n  end\nend\n\ndefmodule Mix.NoProjectError do\n  message =\n    \"Could not find a Mix.Project, please ensure you are running Mix in a directory with a mix.exs file\"\n\n  defexception message: message, mix: true\nend\n\ndefmodule Mix.Error do\n  defexception [:message, mix: 1]\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/generator.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Generator do\n  @moduledoc \"\"\"\n  Conveniences for working with paths and generating content.\n  \"\"\"\n\n  @type generator_opts :: [\n          force: boolean(),\n          quiet: boolean(),\n          format_elixir: boolean()\n        ]\n\n  @doc ~S\"\"\"\n  Creates a file with the given contents.\n\n  If the file already exists and the contents are not the same,\n  it asks for user confirmation.\n\n  ## Options\n\n    * `:force` - forces creation without a shell prompt\n    * `:quiet` - does not log command output\n    * `:format_elixir` (since v1.18.0) - if `true`, apply formatter to the generated file\n\n  ## Examples\n\n      iex> Mix.Generator.create_file(\".gitignore\", \"_build\\ndeps\\n\")\n      * creating .gitignore\n      true\n\n  \"\"\"\n  @spec create_file(Path.t(), iodata, generator_opts) :: boolean()\n  def create_file(path, contents, opts \\\\ []) when is_binary(path) do\n    log(:green, :creating, Path.relative_to_cwd(path), opts)\n\n    if opts[:force] || overwrite?(path, contents) do\n      File.mkdir_p!(Path.dirname(path))\n\n      contents =\n        case opts[:format_elixir] do\n          true -> [Code.format_string!(contents), ?\\n]\n          _ -> contents\n        end\n\n      File.write!(path, contents)\n      true\n    else\n      false\n    end\n  end\n\n  @doc \"\"\"\n  Creates a directory if one does not exist yet.\n\n  This function does nothing if the given directory already exists; in this\n  case, it still logs the directory creation.\n\n  ## Options\n\n    * `:quiet` - does not log command output\n\n  ## Examples\n\n      iex> Mix.Generator.create_directory(\"path/to/dir\")\n      * creating path/to/dir\n      true\n\n  \"\"\"\n  @spec create_directory(Path.t(), quiet: boolean()) :: true\n  def create_directory(path, options \\\\ []) when is_binary(path) do\n    log(:green, \"creating\", Path.relative_to_cwd(path), options)\n    File.mkdir_p!(path)\n    true\n  end\n\n  @doc ~S\"\"\"\n  Copies `source` to `target`.\n\n  If `target` already exists and the contents are not the same,\n  it asks for user confirmation.\n\n  ## Options\n\n    * `:force` - forces copying without a shell prompt\n    * `:quiet` - does not log command output\n    * `:format_elixir` (since v1.18.0) - if `true`, apply formatter to the generated file\n\n  ## Examples\n\n      iex> Mix.Generator.copy_file(\"source/gitignore\", \".gitignore\")\n      * creating .gitignore\n      true\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec copy_file(Path.t(), Path.t(), generator_opts) :: boolean()\n  def copy_file(source, target, options \\\\ []) do\n    create_file(target, File.read!(source), options)\n  end\n\n  @doc ~S\"\"\"\n  Evaluates and copy templates at `source` to `target`.\n\n  The template in `source` is evaluated with the given `assigns`.\n\n  If `target` already exists and the contents are not the same,\n  it asks for user confirmation.\n\n  ## Options\n\n    * `:force` - forces copying without a shell prompt\n    * `:quiet` - does not log command output\n    * `:format_elixir` (since v1.18.0) - if `true`, apply formatter to the generated file\n\n  ## Examples\n\n      iex> assigns = [project_path: \"/Users/joe/newproject\"]\n      iex> Mix.Generator.copy_template(\"source/gitignore\", \".gitignore\", assigns)\n      * creating .gitignore\n      true\n\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec copy_template(Path.t(), Path.t(), keyword, generator_opts) :: boolean()\n  def copy_template(source, target, assigns, options \\\\ []) do\n    create_file(target, EEx.eval_file(source, assigns: assigns), options)\n  end\n\n  @doc \"\"\"\n  Prompts the user to overwrite the file if it exists.\n\n  Returns `false` if the file exists and the user forbade\n  to override it. Returns `true` otherwise.\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec overwrite?(Path.t()) :: boolean\n  def overwrite?(path) do\n    if File.exists?(path) do\n      full = Path.expand(path)\n      Mix.shell().yes?(Path.relative_to_cwd(full) <> \" already exists, overwrite?\")\n    else\n      true\n    end\n  end\n\n  @doc \"\"\"\n  Prompts the user to overwrite the file if it exists.\n\n  The contents are compared to avoid asking the user to\n  override if the contents did not change. Returns `false`\n  if the file exists and the content is the same or the\n  user forbade to override it. Returns `true` otherwise.\n  \"\"\"\n  @doc since: \"1.9.0\"\n  @spec overwrite?(Path.t(), iodata) :: boolean\n  def overwrite?(path, contents) do\n    case File.read(path) do\n      {:ok, binary} ->\n        if binary == IO.iodata_to_binary(contents) do\n          false\n        else\n          full = Path.expand(path)\n          Mix.shell().yes?(Path.relative_to_cwd(full) <> \" already exists, overwrite?\")\n        end\n\n      _ ->\n        true\n    end\n  end\n\n  defp log(color, command, message, opts) do\n    if !opts[:quiet] do\n      Mix.shell().info([color, \"* #{command} \", :reset, message])\n    end\n  end\n\n  @doc \"\"\"\n  Embeds a template given by `contents` into the current module.\n\n  It will define a private function with the `name` followed by\n  `_template` that expects assigns as arguments.\n\n  This function must be invoked passing a keyword list.\n  Each key in the keyword list can be accessed in the\n  template using the `@` macro.\n\n  For more information, check `EEx.SmartEngine`.\n\n  ## Examples\n\n      defmodule Mix.Tasks.MyTask do\n        require Mix.Generator\n        Mix.Generator.embed_template(:log, \"Log: <%= @log %>\")\n      end\n\n  \"\"\"\n  defmacro embed_template(name, contents) do\n    quote bind_quoted: binding() do\n      contents =\n        case contents do\n          [from_file: file] ->\n            @file file\n            File.read!(file)\n\n          c when is_binary(c) ->\n            @file {__ENV__.file, __ENV__.line + 1}\n            c\n\n          _ ->\n            raise ArgumentError, \"expected string or from_file: file\"\n        end\n\n      require EEx\n\n      source = \"<% _ = assigns %>\" <> contents\n      EEx.function_from_string(:defp, :\"#{name}_template\", source, [:assigns])\n    end\n  end\n\n  @doc \"\"\"\n  Embeds a text given by `contents` into the current module.\n\n  It will define a private function with the `name` followed by\n  `_text` that expects no arguments.\n\n  ## Examples\n\n      defmodule Mix.Tasks.MyTask do\n        require Mix.Generator\n        Mix.Generator.embed_text(:error, \"There was an error!\")\n      end\n\n  \"\"\"\n  defmacro embed_text(name, contents) do\n    quote bind_quoted: binding() do\n      contents =\n        case contents do\n          [from_file: f] -> File.read!(f)\n          c when is_binary(c) -> c\n          _ -> raise ArgumentError, \"expected string or from_file: file\"\n        end\n\n      defp unquote(:\"#{name}_text\")(), do: unquote(contents)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/hex.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Hex do\n  @moduledoc false\n  @compile {:no_warn_undefined, Hex}\n  @hex_requirement \">= 2.0.6\"\n  @hex_builds_url \"https://builds.hex.pm\"\n\n  @doc \"\"\"\n  Returns `true` if `Hex` is loaded or installed.\n\n  Otherwise returns `false`.\n  \"\"\"\n  @spec ensure_installed?(boolean) :: boolean\n  def ensure_installed?(force?) do\n    cond do\n      Code.ensure_loaded?(Hex) -> true\n      force? or install_hex?() -> Mix.Tasks.Local.Hex.run([\"--force\"])\n      true -> false\n    end\n  end\n\n  defp install_hex? do\n    shell = Mix.shell()\n    shell.info(\"Mix requires the Hex package manager to fetch dependencies\")\n\n    shell.yes?(\n      \"Shall I install Hex? (if running non-interactively, use \\\"mix local.hex --force\\\")\"\n    )\n  end\n\n  @doc \"\"\"\n  Returns `true` if it has the required `Hex`. If an update is performed, it then exits.\n  Otherwise returns `false` without updating anything.\n  \"\"\"\n  @spec ensure_updated?() :: boolean\n  def ensure_updated?() do\n    cond do\n      not Code.ensure_loaded?(Hex) ->\n        false\n\n      not Version.match?(Hex.version(), @hex_requirement) ->\n        Mix.shell().info(\"Mix requires Hex #{@hex_requirement} but you have #{Hex.version()}\")\n\n        if Mix.shell().yes?(\"Shall I abort the current command and update Hex?\") do\n          Mix.Tasks.Local.Hex.run([\"--force\"])\n          exit({:shutdown, 0})\n        end\n\n        false\n\n      true ->\n        true\n    end\n  end\n\n  @doc \"\"\"\n  Ensures `Hex` is started.\n  \"\"\"\n  def start do\n    try do\n      Hex.start()\n    catch\n      kind, reason ->\n        Mix.shell().error(\n          \"Could not start Hex. Try fetching a new version with \" <>\n            \"\\\"mix local.hex\\\" or uninstalling it with \\\"mix archive.uninstall hex.ez\\\"\"\n        )\n\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    end\n  end\n\n  @doc \"\"\"\n  Returns the URL to the Hex build assets.\n  \"\"\"\n  def url do\n    System.get_env(\"HEX_BUILDS_URL\") || System.get_env(\"HEX_MIRROR\") || @hex_builds_url\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/local/installer.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Local.Installer do\n  @moduledoc false\n\n  # This module implements pieces of functionality shared\n  # by the archive- and escript-related tasks.\n\n  @typedoc \"\"\"\n  Installs types supported by `Mix.Local.Installer`.\n\n    * `:project` - installs the current Mix project's artifact\n    * `:local` - installs the artifact located at `path`\n    * `:url` - installs the artifact retrievable at `url`\n    * `:fetcher` - builds and install the artifact generated by the `dep_spec`\n\n  \"\"\"\n  @type install_spec ::\n          :project\n          | {:local, path :: Path.t()}\n          | {:url, url :: binary}\n          | {:fetcher, dep_spec :: tuple}\n\n  @typedoc \"\"\"\n  Options for installer functions.\n\n  These options are used by various installer functions to control behavior\n  during installation, parsing, and uninstallation.\n  \"\"\"\n  @type installer_opts :: [\n          app: String.t(),\n          submodules: boolean(),\n          sparse: String.t(),\n          force: boolean(),\n          sha512: String.t(),\n          organization: String.t(),\n          repo: String.t(),\n          timeout: pos_integer()\n        ]\n\n  @doc \"\"\"\n  Checks that the `install_spec` and `opts` are supported by the respective module.\n  \"\"\"\n  @callback check_install_spec(install_spec, opts :: installer_opts) :: :ok | {:error, String.t()}\n\n  @doc \"\"\"\n  Returns a list of already installed version of the same artifact.\n  \"\"\"\n  @callback find_previous_versions(basename :: String.t()) :: [Path.t()]\n\n  @doc \"\"\"\n  Builds a local artifact either from a remote dependency or for\n  the current project.\n  \"\"\"\n  @callback build(install_spec, opts :: installer_opts) :: Path.t()\n\n  @doc \"\"\"\n  The installation itself.\n  \"\"\"\n  @callback install(basename :: String.t(), contents :: binary, previous :: [Path.t()]) :: :ok\n\n  @doc \"\"\"\n  Common implementation of installation for archives and escripts.\n\n  Relies on a few callbacks provided by respective callback modules\n  for customizing certain steps in the installation process.\n  \"\"\"\n  @spec install(module, OptionParser.argv(), keyword) :: boolean\n  def install(module, argv, switches) do\n    {opts, args} = OptionParser.parse!(argv, strict: switches)\n\n    install_spec =\n      case parse_args(args, opts) do\n        {:error, message} -> Mix.raise(message <> \"\\n\\n\" <> usage(module))\n        install_spec -> install_spec\n      end\n\n    case module.check_install_spec(install_spec, opts) do\n      :ok -> :noop\n      {:error, message} -> Mix.raise(message <> \"\\n\\n\" <> usage(module))\n    end\n\n    case install_spec do\n      {:fetcher, dep_spec} ->\n        if opts[:sha512] do\n          Mix.raise(\n            \"--sha512 is not supported when installing from git/github/hex\\n\\n\" <> usage(module)\n          )\n        end\n\n        fetch(dep_spec, fn _ ->\n          local_install(module, build(module, install_spec, opts), opts)\n        end)\n\n      {path_or_url, src} when path_or_url in [:local, :url] ->\n        local_install(module, src, opts)\n\n      :project ->\n        local_install(module, build(module, install_spec, opts), opts)\n    end\n  end\n\n  defp build(module, install_spec, opts) do\n    Mix.Tasks.Loadconfig.preserve_config(fn ->\n      module.build(install_spec, opts)\n    end)\n  end\n\n  defp task(module) do\n    Mix.Utils.module_name_to_command(module, 2)\n  end\n\n  defp usage(module) do\n    \"For more information run \\\"mix help #{task(module)}\\\"\"\n  end\n\n  defp local_path?(url_or_path) do\n    File.regular?(url_or_path)\n  end\n\n  defp file_url?(url_or_path) do\n    URI.parse(url_or_path).scheme in [\"http\", \"https\"]\n  end\n\n  defp local_install(module, src, opts) do\n    basename = Path.basename(URI.parse(src).path)\n    previous_files = module.find_previous_versions(basename)\n\n    if opts[:force] || should_install?(src, previous_files) do\n      case Mix.Utils.read_path(src, opts) do\n        {:ok, binary} ->\n          module.install(basename, binary, previous_files)\n\n        :badpath ->\n          Mix.raise(\"Expected #{inspect(src)} to be a local file path\")\n\n        {:local, message} ->\n          Mix.raise(message)\n\n        {kind, message} when kind in [:remote, :checksum] ->\n          Mix.raise(\"\"\"\n          #{message}\n\n          Could not run #{task(module)} for:\n\n              #{src}\n\n          Please download the file above to your current directory and run:\n\n              mix #{task(module)} ./#{basename}\n\n          You can download it either with your browser or via the command line.\n\n          On Unix-like operating systems (Linux, macOS):\n\n              wget #{src}\n\n          or\n\n              curl -o #{basename} #{src}\n\n          On Windows / PowerShell (Windows 7 or later):\n\n              powershell -Command \"Invoke-WebRequest #{src} -OutFile #{basename}\"\n\n          or\n\n              powershell -Command \"(New-Object Net.WebClient).DownloadFile('#{src}', '#{basename}')\"\n          \"\"\")\n      end\n\n      true\n    else\n      false\n    end\n  end\n\n  defp should_install?(src, previous_files) do\n    message =\n      case previous_files do\n        [] ->\n          \"Are you sure you want to install #{inspect(src)}?\"\n\n        [file] ->\n          \"Found existing entry: #{file}\\n\" <>\n            \"Are you sure you want to replace it with #{inspect(src)}?\"\n\n        files ->\n          \"Found existing entries: #{Enum.map_join(files, \", \", &Path.basename/1)}\\n\" <>\n            \"Are you sure you want to replace them with #{inspect(src)}?\"\n      end\n\n    Mix.shell().yes?(message)\n  end\n\n  @doc \"\"\"\n  Receives `argv` and `opts` from options parsing and returns an `install_spec`.\n  \"\"\"\n  @spec parse_args([String.t()], installer_opts) :: install_spec | {:error, String.t()}\n  def parse_args(argv, opts)\n\n  def parse_args([], _opts) do\n    :project\n  end\n\n  def parse_args([url_or_path], _opts) do\n    cond do\n      local_path?(url_or_path) -> {:local, url_or_path}\n      file_url?(url_or_path) -> {:url, url_or_path}\n      true -> {:error, \"Expected #{inspect(url_or_path)} to be a local file path\"}\n    end\n  end\n\n  def parse_args([\"github\" | rest], opts) do\n    [repo | rest] = rest\n    url = \"https://github.com/#{repo}.git\"\n    parse_args([\"git\", url] ++ rest, opts)\n  end\n\n  def parse_args([\"git\", url], opts) do\n    git_fetcher(url, [], opts)\n  end\n\n  def parse_args([\"git\", url, ref_type, ref], opts) do\n    case ref_to_config(ref_type, ref) do\n      {:error, error} ->\n        {:error, error}\n\n      git_config ->\n        git_fetcher(url, git_config, opts)\n    end\n  end\n\n  def parse_args([\"git\" | [_url | rest]], _opts) do\n    {:error, \"received invalid git checkout spec: #{Enum.join(rest, \" \")}\"}\n  end\n\n  def parse_args([\"hex\", package_name], opts) do\n    parse_args([\"hex\", package_name, \">= 0.0.0\"], opts)\n  end\n\n  def parse_args([\"hex\", package_name, version], opts) do\n    app_name =\n      if opts[:app] do\n        opts[:app]\n      else\n        package_name\n      end\n\n    dep_opts = [\n      hex: String.to_atom(package_name),\n      repo: hex_repo(opts)\n    ]\n\n    {:fetcher, {String.to_atom(app_name), version, dep_opts}}\n  end\n\n  def parse_args([\"hex\" | [_package_name | rest]], _opts) do\n    {:error, \"received invalid Hex package spec: #{Enum.join(rest, \" \")}\"}\n  end\n\n  defp hex_repo(opts) do\n    repo = Keyword.get(opts, :repo, \"hexpm\")\n\n    if organization = opts[:organization] do\n      repo <> \":\" <> organization\n    else\n      repo\n    end\n  end\n\n  defp git_fetcher(url, git_config, opts) do\n    git_opts = git_config ++ [git: url, submodules: opts[:submodules], sparse: opts[:sparse]]\n\n    app_name =\n      if opts[:app] do\n        opts[:app]\n      else\n        \"new package\"\n      end\n\n    {:fetcher, {String.to_atom(app_name), git_opts}}\n  end\n\n  defp ref_to_config(\"branch\", branch), do: [branch: branch]\n  defp ref_to_config(\"tag\", tag), do: [tag: tag]\n  defp ref_to_config(\"ref\", ref), do: [ref: ref]\n\n  defp ref_to_config(ref_type, _) do\n    {:error, \"expected one of \\\"branch\\\", \\\"tag\\\", or \\\"ref\\\". Got: \\\"#{ref_type}\\\"\"}\n  end\n\n  @doc \"\"\"\n  A common implementation for uninstalling archives and scripts.\n  \"\"\"\n  @spec uninstall(Path.t(), String.t(), OptionParser.argv(), keyword) :: Path.t() | nil\n  def uninstall(root, listing, argv, switches) do\n    {opts, argv} = OptionParser.parse!(argv, switches: switches)\n\n    if name = List.first(argv) do\n      found =\n        if File.exists?(Path.join(root, name)) do\n          Path.join(root, name)\n        else\n          matching_package(root, name)\n        end\n\n      cond do\n        found && should_uninstall?(found, opts) ->\n          File.rm_rf!(found)\n          found\n\n        found ->\n          nil\n\n        true ->\n          Mix.shell().error(\"Could not find a local artifact named #{inspect(name)}. We found:\")\n          Mix.Task.rerun(listing)\n          nil\n      end\n    else\n      Mix.raise(\n        \"No argument was given to uninstall command. \" <>\n          \" Use \\\"mix #{listing}.uninstall PATH\\\" or run \\\"mix help #{listing}.uninstall\\\" for more information\"\n      )\n    end\n  end\n\n  defp matching_package(root, name) do\n    root |> Path.join(name <> \"-*\") |> Path.wildcard() |> List.first()\n  end\n\n  defp should_uninstall?(path, opts) do\n    opts[:force] || Mix.shell().yes?(\"Are you sure you want to uninstall #{path}?\")\n  end\n\n  @doc \"\"\"\n  Fetches `dep_spec` with `in_fetcher` and then runs `in_package`.\n\n  Generates a new Mix project in a temporary directory with the given `dep_spec`\n  added to a mix.exs. Then, `in_fetcher` is executed in the fetcher project. By\n  default, this fetches the dependency, but you can provide an `in_fetcher`\n  during test or for other purposes. After the `in_fetcher` is executed,\n  `in_package` is executed in the now (presumably) fetched package, with the\n  package's config overridden with the deps_path and lockfile of the fetcher\n  package. Also, the Mix env is set to :prod.\n  \"\"\"\n  @spec fetch(tuple, (atom -> any), (atom -> any)) :: any\n  def fetch(dep_spec, in_fetcher \\\\ &in_fetcher/1, in_package) do\n    tmp_path = tmp_path()\n    previous_env = Mix.env()\n    deps_path = System.get_env(\"MIX_DEPS_PATH\")\n    code_path = :code.get_path()\n\n    try do\n      File.mkdir_p!(tmp_path)\n      System.delete_env(\"MIX_DEPS_PATH\")\n      Mix.env(:prod)\n\n      File.write!(Path.join(tmp_path, \"mix.exs\"), \"\"\"\n      defmodule Mix.Local.Installer.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :mix_local_installer,\n            version: \"1.0.0\",\n            deps: [#{inspect(dep_spec)}]\n          ]\n        end\n      end\n      \"\"\")\n\n      Mix.ProjectStack.on_clean_slate(fn ->\n        tmp_path =\n          Mix.Project.in_project(:mix_local_installer, tmp_path, [], fn mix_exs ->\n            in_fetcher.(mix_exs)\n\n            # The tmp_dir may have symlinks in it, so we properly resolve\n            # the directory before customizing deps_path and lockfile.\n            File.cwd!()\n          end)\n\n        {package_name, package_path} = package_name_path(dep_spec, tmp_path)\n\n        post_config = [\n          deps_path: Path.join(tmp_path, \"deps\"),\n          lockfile: Path.join(tmp_path, \"mix.lock\")\n        ]\n\n        Mix.Project.in_project(package_name, package_path, post_config, fn mix_exs ->\n          in_fetcher.(mix_exs)\n          in_package.(mix_exs)\n        end)\n      end)\n    after\n      File.rm_rf(tmp_path)\n      Mix.env(previous_env)\n      deps_path && System.put_env(\"MIX_DEPS_PATH\", deps_path)\n      :code.set_path(code_path)\n      :code.purge(Mix.Local.Installer.Fetcher)\n      :code.delete(Mix.Local.Installer.Fetcher)\n    end\n  end\n\n  defp package_name_path(dep_spec, tmp_path) do\n    package_name = elem(dep_spec, 0)\n    package_name_string = Atom.to_string(package_name)\n    package_path = Path.join([tmp_path, \"deps\", package_name_string, maybe_sparse_dir(dep_spec)])\n\n    {package_name, package_path}\n  end\n\n  defp maybe_sparse_dir({_app, opts}) when is_list(opts) do\n    if opts[:git] do\n      opts[:sparse] || \"\"\n    else\n      \"\"\n    end\n  end\n\n  defp maybe_sparse_dir(_dep_spec), do: \"\"\n\n  defp in_fetcher(_mix_exs) do\n    Mix.Task.run(\"deps.get\", [\"--only\", Atom.to_string(Mix.env())])\n  end\n\n  defp tmp_path do\n    unique = :crypto.strong_rand_bytes(4) |> Base.url_encode64(padding: false)\n    Path.join(System.tmp_dir!(), \"mix-local-installer-fetcher-\" <> unique)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/local.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Local do\n  @moduledoc false\n\n  @doc \"\"\"\n  Returns the name for an archive or an escript, based on the project config.\n\n  ## Examples\n\n      iex> Mix.Local.name_for(:archives, app: \"foo\", version: \"0.1.0\")\n      \"foo-0.1.0.ez\"\n\n      iex> Mix.Local.name_for(:escripts, escript: [name: \"foo\"])\n      \"foo\"\n\n  \"\"\"\n  @spec name_for(:archives | :escripts, keyword) :: String.t()\n  def name_for(:archives, project) do\n    version = if version = project[:version], do: \"-#{version}\"\n    \"#{project[:app]}#{version}.ez\"\n  end\n\n  def name_for(:escripts, project) do\n    case get_in(project, [:escript, :name]) do\n      nil -> project[:app]\n      name -> name\n    end\n    |> to_string()\n  end\n\n  @deprecated \"Use Mix.path_for/1 instead\"\n  def path_for(:archive), do: Mix.path_for(:archives)\n  def path_for(:escript), do: Mix.path_for(:escripts)\n\n  @doc \"\"\"\n  Appends archive paths to the Erlang code path.\n  \"\"\"\n  def append_archives do\n    for archive <- archives_ebins() do\n      check_elixir_version_in_ebin(archive)\n      Code.append_path(archive, cache: true)\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Removes archive paths from Erlang code path.\n  \"\"\"\n  def remove_archives do\n    for archive <- archives_ebins() do\n      Code.delete_path(archive)\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Appends Mix paths to the Erlang code path.\n\n  We don't cache them as they are rarely used and\n  they may be development paths.\n  \"\"\"\n  def append_paths do\n    Enum.each(mix_paths(), &Code.append_path/1)\n  end\n\n  @doc \"\"\"\n  Removes Mix paths from the Erlang code path.\n  \"\"\"\n  def remove_paths do\n    Enum.each(mix_paths(), &Code.delete_path/1)\n  end\n\n  defp mix_paths do\n    if path = System.get_env(\"MIX_PATH\") do\n      String.split(path, path_separator())\n    else\n      []\n    end\n  end\n\n  defp path_separator do\n    case :os.type() do\n      {:win32, _} -> \";\"\n      {:unix, _} -> \":\"\n    end\n  end\n\n  @doc \"\"\"\n  Returns all tasks in local archives.\n  \"\"\"\n  def archives_tasks do\n    Mix.Task.load_tasks(archives_ebins())\n  end\n\n  @doc \"\"\"\n  Returns the name of an archive given a path.\n  \"\"\"\n  def archive_name(path) do\n    path\n    |> Path.basename()\n    |> Path.rootname(\".ez\")\n  end\n\n  @doc \"\"\"\n  Returns the ebin path of an archive.\n  \"\"\"\n  def archive_ebin(path) do\n    Path.join([path, archive_name(path), \"ebin\"])\n  end\n\n  defp archives_ebins do\n    path = Mix.path_for(:archives)\n\n    case File.ls(path) do\n      {:ok, entries} -> Enum.map(entries, &archive_ebin(Path.join(path, &1)))\n      {:error, _} -> []\n    end\n  end\n\n  @doc \"\"\"\n  Checks Elixir version requirement stored in the ebin directory\n  and print a warning if it is not satisfied.\n  \"\"\"\n  def check_elixir_version_in_ebin(ebin) do\n    elixir = ebin |> Path.dirname() |> Path.join(\".elixir\") |> String.to_charlist()\n\n    case File.read(elixir) do\n      {:ok, req} ->\n        if !Version.match?(System.version(), req) do\n          archive = ebin |> Path.dirname() |> Path.basename()\n\n          Mix.shell().error(\n            \"warning: the archive #{archive} requires Elixir #{inspect(req)} \" <>\n              \"but you are running on v#{System.version()}\"\n          )\n        end\n\n        :ok\n\n      {:error, _} ->\n        :ok\n    end\n  end\n\n  @doc \"\"\"\n  Fetches the given signed CSV files, verifies and returns the matching\n  Elixir version, artifact version and artifact's checksum.\n\n  Used to install both Rebar and Hex from S3.\n  \"\"\"\n  def find_matching_versions!(name, version, path) do\n    name\n    |> read_path!(path)\n    |> parse_csv()\n    |> find_latest_eligible_version(version)\n    |> Kernel.||(Mix.raise(\"Could not find a version of #{name} matching: #{version}\"))\n  end\n\n  defp read_path!(name, path) do\n    case Mix.Utils.read_path(path) do\n      {:ok, contents} ->\n        contents\n\n      {:remote, message} ->\n        Mix.raise(\n          \"\"\"\n          #{message}\n\n          Could not install #{name} because Mix could not download metadata at #{path}.\n          \"\"\" <> suggestions(name)\n        )\n    end\n  end\n\n  defp suggestions(\"Hex\") do\n    \"\"\"\n\n    Alternatively, you can compile and install Hex directly with this command:\n\n        $ mix archive.install github hexpm/hex branch latest\n    \"\"\"\n  end\n\n  defp suggestions(_) do\n    \"\"\n  end\n\n  defp parse_csv(body) do\n    body\n    |> :binary.split(\"\\n\", [:global, :trim])\n    |> Enum.map(&:binary.split(&1, \",\", [:global, :trim]))\n  end\n\n  defp find_latest_eligible_version(entries, artifact_version) do\n    elixir_version = Version.parse!(System.version())\n    otp_release = System.otp_release()\n\n    entries\n    |> Enum.reverse()\n    |> find_version(artifact_version, elixir_version, otp_release)\n  end\n\n  defp find_version(entries, artifact_version, elixir_version, otp_release) do\n    entries =\n      if artifact_version do\n        Enum.filter(entries, &(hd(&1) == artifact_version))\n      else\n        entries\n      end\n\n    Enum.find_value(entries, &find_by_elixir_version(&1, elixir_version, otp_release))\n  end\n\n  defp find_by_elixir_version(\n         [artifact_version, digest, hex_elixir_version, hex_otp_release | _],\n         elixir_version,\n         otp_release\n       ) do\n    if Version.compare(hex_elixir_version, elixir_version) != :gt and\n         hex_otp_release <= otp_release do\n      {hex_elixir_version, artifact_version, digest, hex_otp_release}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/project.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Project do\n  @moduledoc \"\"\"\n  Defines and manipulates Mix projects.\n\n  A Mix project is defined by calling `use Mix.Project` in a module, usually\n  placed in `mix.exs`:\n\n      defmodule MyApp.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :my_app,\n            version: \"1.0.0\"\n          ]\n        end\n      end\n\n  > #### `use Mix.Project` {: .info}\n  >\n  > When you `use Mix.Project`, it notifies Mix that a new project\n  > has been defined, so all Mix tasks use your module as a starting\n  > point.\n\n  ## Configuration\n\n  In order to configure Mix, the module that calls `use Mix.Project` should export\n  a `project/0` function that returns a keyword list representing configuration\n  for the project.\n\n  This configuration can be read using `Mix.Project.config/0`. Note that\n  `config/0` won't fail if a project is not defined; this allows many Mix tasks\n  to work without a project.\n\n  If a task requires a project to be defined or needs to access a\n  special function within the project, the task can call `Mix.Project.get!/0`\n  which fails with `Mix.NoProjectError` in the case a project is not\n  defined.\n\n  There isn't a comprehensive list of all the options that can be returned by\n  `project/0` since many Mix tasks define their own options that they read from\n  this configuration. For example, look at the \"Configuration\" section in the\n  documentation for the `Mix.Tasks.Compile` task.\n\n  These are a few options that are not used by just one Mix task (and will thus\n  be documented here):\n\n    * `:build_per_environment` - if `true`, builds will be *per-environment*. If\n      `false`, builds will go in `_build/shared` regardless of the Mix\n      environment. Defaults to `true`.\n\n    * `:aliases` - a list of task aliases. For more information, check out the\n      \"Aliases\" section in the documentation for the `Mix` module. Defaults to\n      `[]`.\n\n    * `:config_path` - a string representing the path of the main config\n      file. See `config_files/0` for more information. Defaults to\n      `\"config/config.exs\"`.\n\n    * `:deps` - a list of dependencies of this project. Refer to the\n      documentation for the `Mix.Tasks.Deps` task for more information. Defaults\n      to `[]`.\n\n    * `:deps_path` - directory where dependencies are stored. Also see\n      `deps_path/1`. Defaults to `\"deps\"`.\n\n    * `:lockfile` - the name of the lockfile used by the `mix deps.*` family of\n      tasks. Defaults to `\"mix.lock\"`.\n\n  Mix tasks may require their own configuration inside `def project`. For example,\n  check the `Mix.Tasks.Compile` task and all the specific compiler tasks\n  (such as `Mix.Tasks.Compile.Elixir` or `Mix.Tasks.Compile.Erlang`).\n\n  Note that different tasks may share the same configuration option. For example,\n  the `:erlc_paths` configuration is used by `mix compile.erlang`, `mix compile.yecc`,\n  and other tasks.\n\n  > #### Keep `project/0` fast {: .warning}\n  >\n  > `project/0` is called whenever your `mix.exs` is loaded, so heavy\n  > computation should be avoided. If a task requires a potentially complex\n  > configuration value, it should allow its configuration to be set to an\n  > anonymous function or similar, so that it can be invoked only when\n  > needed by the task itself.\n\n  ## CLI configuration\n\n  Mix is most often invoked from the command line. For this purpose, you may define\n  a specific `cli/0` function which customizes default values when executed from\n  the CLI. For example:\n\n      def cli do\n        [\n          default_task: \"phx.server\",\n          preferred_envs: [docs: :docs]\n        ]\n      end\n\n  The example above sets the default task (used by `iex -S mix` and `mix`) to\n  `phx.server`. It also sets the default environment for the \"mix docs\" task to\n  be \"docs\".\n\n  The following CLI configuration are available:\n\n    * `:default_env` - the default environment to use when none is given\n      and `MIX_ENV` is not set\n\n    * `:default_target` - the default target to use when none is given\n      and `MIX_TARGET` is not set\n\n    * `:default_task` - the default task to invoke when none is given\n\n    * `:preferred_envs` - a keyword list of `{task, env}` tuples where `task`\n      is the task name as an atom (for example, `:\"deps.get\"`) and `env` is the\n      preferred environment (for example, `:test`)\n\n    * `:preferred_targets` - a keyword list of `{task, target}` tuples where\n      `task` is the task name as an atom (for example, `:test`) and `target`\n      is the preferred target (for example, `:host`)\n\n  ## Erlang projects\n\n  Mix can be used to manage Erlang projects that don't have any Elixir code. To\n  ensure Mix tasks work correctly for an Erlang project, `language: :erlang` has\n  to be part of the configuration returned by `project/0`. This setting also\n  makes sure Elixir is not added as a dependency to the generated `.app` file or\n  to the escript generated with `mix escript.build`, and so on.\n\n  ## Umbrella projects\n\n  Umbrella projects are a convenience to help you organize and manage multiple\n  applications. While it provides a degree of separation between applications,\n  those applications are not fully decoupled, as they share the same configuration\n  and the same dependencies.\n\n  In an umbrella project, you have an `apps/` folder where you store each application.\n  Then, instead of each app in the umbrella having its own configuration, build cache,\n  lockfile and so, they all point to the parent project by specifying the following\n  configuration in their `mix.exs`:\n\n      build_path: \"../../_build\",\n      config_path: \"../../config/config.exs\",\n      deps_path: \"../../deps\",\n      lockfile: \"../../mix.lock\",\n\n  The pattern of keeping multiple applications in the same repository is known as\n  [monorepo](https://en.wikipedia.org/wiki/Monorepo). Umbrella projects maximize\n  this pattern by providing conveniences to compile, test and run multiple\n  applications at once. When an umbrella application needs to depend on another\n  one, it can be done by passing the `in_umbrella: true` option to your dependency.\n  If an umbrella application `:foo` depends on its sibling `:bar`, you can specify\n  this dependency in `foo`'s `mix.exs` file as:\n\n      {:bar, in_umbrella: true}\n\n  ### Undoing umbrellas\n\n  Using umbrella projects can impact how you design and write your software and,\n  as time passes, they may turn out to be the wrong choice.\n  If you find yourself in a position where you want to use different configurations\n  in each application for the same dependency or use different dependency versions,\n  then it is likely your codebase has grown beyond what umbrellas can provide.\n\n  If you find yourself in this situation, you have two options:\n\n    1. Convert everything into a single Mix project, which can be done in steps.\n       First move all files in `lib`, `test`, `priv`, and friends into a single\n       application, while still keeping the overall umbrella structure and\n       `mix.exs` files. For example, if your umbrellas has three applications,\n       `foo`, `bar` and `baz`, where `baz` depends on both `foo` and `bar`,\n       move all source to `baz`. Then remove `foo` and `bar` one by one,\n       updating any configuration and removing references to the `:foo` and\n      `:bar` application names. Until you have only a single application.\n\n    2. Remove umbrella structure while keeping them as distinct applications.\n       This is done by moving applications outside of the umbrella\n       project's `apps/` directory and updating the projects' `mix.exs` files\n       to no longer set the `build_path`, `config_path`, `deps_path`, and\n       `lockfile` configurations, guaranteeing each of them have their own\n       build and dependency structure.\n\n  Keep in mind that umbrellas are one of many options for managing private\n  packages within your organization. You might:\n\n    1. Have multiple directories inside the same repository and using `:path`\n       dependencies (which is essentially the monorepo pattern)\n    2. Use private Git repositories and Mix' ability to fetch Git dependencies\n    3. Publishing packages to a private [Hex.pm](https://hex.pm/) organization\n\n  ## Invoking this module\n\n  This module contains many functions that return project information and\n  metadata. However, since Mix is not included nor configured during releases,\n  we recommend using the functions in this module only inside Mix tasks.\n  If you need to configure your own app, consider using the application\n  environment instead. For example, don't do this:\n\n      def some_config do\n        Mix.Project.config()[:some_config]\n      end\n\n  Nor this:\n\n      @some_config Mix.Project.config()[:some_config]\n\n  Instead, do this:\n\n      def some_config do\n        Application.get_env(:my_app, :some_config)\n      end\n\n  Or this:\n\n      @some_config Application.compile_env(:my_app, :some_config)\n\n  \"\"\"\n\n  @type build_structure_opts :: [\n          symlink_ebin: boolean(),\n          source: String.t()\n        ]\n\n  @typedoc \"\"\"\n  Options for dependency traversal functions.\n\n  These options control how dependency trees are traversed and filtered\n  in functions like `deps_scms/1`, `deps_paths/1`, and `deps_tree/1`.\n  \"\"\"\n  @type deps_traversal_opts :: [\n          depth: pos_integer(),\n          parents: [atom()]\n        ]\n\n  @doc false\n  defmacro __using__(_) do\n    quote do\n      @after_compile Mix.Project\n    end\n  end\n\n  # Invoked after each Mix.Project is compiled.\n  @doc false\n  def __after_compile__(env, _binary) do\n    push(env.module, env.file)\n  end\n\n  # Push a project onto the project stack.\n  # Only the top of the stack can be accessed.\n  @doc false\n  def push(module, file \\\\ nil, app \\\\ nil) when is_atom(module) do\n    file =\n      cond do\n        file != nil -> file\n        source = module && module.module_info(:compile)[:source] -> List.to_string(source)\n        true -> \"nofile\"\n      end\n\n    case Mix.ProjectStack.push(module, push_config(module, app), file) do\n      :ok ->\n        :ok\n\n      {:error, other} when is_binary(other) ->\n        Mix.raise(\n          \"Trying to load #{inspect(module)} from #{inspect(file)}\" <>\n            \" but another project with the same name was already defined at #{inspect(other)}\"\n        )\n    end\n  end\n\n  @preferred_envs [test: :test, \"test.coverage\": :test]\n\n  defp push_config(module, app) do\n    with {state_loader, task} <- Mix.ProjectStack.pop_post_config(:state_loader) do\n      config =\n        if function_exported?(module, state_loader, 0),\n          do: apply(module, state_loader, []),\n          else: []\n\n      task = String.to_atom(task || config[:default_task] || \"run\")\n\n      if !System.get_env(\"MIX_ENV\") do\n        if env = config[:preferred_envs][task] || @preferred_envs[task] || config[:default_env] do\n          Mix.env(env)\n        end\n      end\n\n      if !System.get_env(\"MIX_TARGET\") do\n        if target = config[:preferred_targets][task] || config[:default_target] do\n          Mix.target(target)\n        end\n      end\n    end\n\n    ([app: app] ++ default_config())\n    |> Keyword.merge(get_project_config(module))\n  end\n\n  # Pops a project from the stack.\n  @doc false\n  def pop do\n    Mix.ProjectStack.pop()\n  end\n\n  # The configuration that is pushed down to dependencies.\n  @doc false\n  def deps_config(config \\\\ config()) do\n    [\n      consolidate_protocols: false,\n      consolidation_path: consolidation_path(config),\n      deps_path: deps_path(config),\n      deps_build_path: build_path(config),\n      lockfile: Path.expand(config[:lockfile])\n    ] ++ Keyword.take(config, [:build_embedded, :build_per_environment, :prune_code_paths])\n  end\n\n  @doc \"\"\"\n  Retrieves the current project if there is one.\n\n  If there is no current project, `nil` is returned. This\n  may happen in cases there is no `mix.exs` in the current\n  directory.\n\n  If you expect a project to be defined, i.e., it is a\n  requirement of the current task, you should call\n  `get!/0` instead.\n  \"\"\"\n  @spec get() :: module | nil\n  def get do\n    case Mix.ProjectStack.peek() do\n      %{name: name} -> name\n      _ -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Same as `get/0`, but raises an exception if there is no current project.\n\n  This is usually called by tasks that need additional\n  functions on the project to be defined. Since such\n  tasks usually depend on a project being defined, this\n  function raises a `Mix.NoProjectError` exception in\n  case no project is available.\n  \"\"\"\n  @spec get!() :: module\n  def get! do\n    get() || raise Mix.NoProjectError, []\n  end\n\n  @doc \"\"\"\n  Returns the path to the file that defines the current project.\n\n  The majority of the time, it will point to a `mix.exs` file.\n  Returns `nil` if not inside a project.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec project_file() :: binary | nil\n  defdelegate project_file(), to: Mix.ProjectStack\n\n  @doc \"\"\"\n  Returns the path to the file that defines the parent umbrella project, if one.\n\n  The majority of the time, it will point to a `mix.exs` file.\n  Returns `nil` if not inside a project or not inside an umbrella.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec parent_umbrella_project_file() :: binary | nil\n  defdelegate parent_umbrella_project_file(), to: Mix.ProjectStack\n\n  @doc \"\"\"\n  Returns the project configuration.\n\n  If there is no project defined, it still returns a keyword\n  list with default values. This allows many Mix tasks to work\n  without the need for an underlying project.\n\n  Note this configuration is cached once the project is\n  pushed onto the stack. Calling it multiple times won't\n  cause it to be recomputed.\n\n  Do not use `Mix.Project.config/0` to find the runtime configuration.\n  Use it only to configure aspects of your project (like\n  compilation directories) and not your application runtime.\n  \"\"\"\n  @spec config() :: keyword\n  def config do\n    case Mix.ProjectStack.peek() do\n      %{config: config} -> config\n      _ -> default_config()\n    end\n  end\n\n  @doc \"\"\"\n  Returns a list of project configuration files for this project.\n\n  This function is usually used in compilation tasks to trigger\n  a full recompilation whenever such configuration files change.\n\n  It returns the lock manifest, and all config files in the `config`\n  directory that do not start with a leading period (for example,\n  `.my_config.exs`).\n\n  Note: before Elixir v1.13.0, the `mix.exs` file was also included\n  as a config file, but since then it has been moved to its own\n  function called `project_file/0`.\n  \"\"\"\n  @spec config_files() :: [Path.t()]\n  def config_files do\n    Mix.ProjectStack.config_files()\n  end\n\n  @doc \"\"\"\n  Returns the latest modification time from config files.\n\n  This function is usually used in compilation tasks to trigger\n  a full recompilation whenever such configuration files change.\n  For this reason, the mtime is cached to avoid file system lookups.\n\n  However, for effective used of this function, you must avoid\n  comparing source files with the `config_mtime` itself. Instead,\n  store the previous `config_mtime` and compare it with the new\n  `config_mtime` in order to detect if something is stale.\n\n  Note: before Elixir v1.13.0, the `mix.exs` file was also included\n  in the mtimes, but not anymore. You can compute its modification\n  date by calling `project_file/0`.\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec config_mtime() :: posix_mtime when posix_mtime: integer()\n  def config_mtime do\n    Mix.ProjectStack.config_mtime()\n  end\n\n  @doc \"\"\"\n  Returns `true` if `config` is the configuration for an umbrella project.\n\n  When called with no arguments, tells whether the current project is\n  an umbrella project.\n  \"\"\"\n  @spec umbrella?(keyword) :: boolean\n  def umbrella?(config \\\\ config()) do\n    config[:apps_path] != nil\n  end\n\n  @doc \"\"\"\n  Returns a map with the umbrella child applications paths.\n\n  These paths are based on the `:apps_path` and `:apps` configurations.\n\n  If the given project configuration identifies an umbrella project, the return\n  value is a map of `app => path` where `app` is a child app of the umbrella and\n  `path` is its path relative to the root of the umbrella project.\n\n  If the given project configuration does not identify an umbrella project,\n  `nil` is returned.\n\n  ## Examples\n\n      Mix.Project.apps_paths()\n      #=> %{my_app1: \"apps/my_app1\", my_app2: \"apps/my_app2\"}\n\n  \"\"\"\n  @doc since: \"1.4.0\"\n  @spec apps_paths(keyword) :: %{optional(atom) => Path.t()} | nil\n  def apps_paths(config \\\\ config()) do\n    if apps_path = config[:apps_path] do\n      key = {:apps_paths, Mix.Project.get!()}\n\n      if cache = Mix.State.read_cache(key) do\n        cache\n      else\n        cache = config[:apps] |> umbrella_apps(apps_path) |> to_apps_paths(apps_path)\n        Mix.State.write_cache(key, cache)\n      end\n    end\n  end\n\n  defp umbrella_apps(nil, apps_path) do\n    case File.ls(apps_path) do\n      {:ok, apps} -> Enum.map(apps, &String.to_atom/1)\n      {:error, _} -> []\n    end\n  end\n\n  defp umbrella_apps(apps, _apps_path) when is_list(apps) do\n    apps\n  end\n\n  defp to_apps_paths(apps, apps_path) do\n    for app <- apps,\n        path = path_with_mix_exs_otherwise_warn(app, apps_path),\n        do: {app, path},\n        into: %{}\n  end\n\n  defp path_with_mix_exs_otherwise_warn(app, apps_path) do\n    path = Path.join(apps_path, Atom.to_string(app))\n\n    cond do\n      File.regular?(Path.join(path, \"mix.exs\")) ->\n        path\n\n      File.dir?(path) ->\n        Mix.shell().error(\n          \"warning: path #{inspect(Path.relative_to_cwd(path))} is a directory but \" <>\n            \"it has no mix.exs. Mix won't consider this directory as part of your \" <>\n            \"umbrella application. Please add a \\\"mix.exs\\\" or set the \\\":apps\\\" key \" <>\n            \"in your umbrella configuration with all relevant apps names as atoms\"\n        )\n\n        nil\n\n      true ->\n        # If it is a stray file, we just ignore it.\n        nil\n    end\n  end\n\n  @doc ~S\"\"\"\n  Runs the given `fun` inside the given project.\n\n  This function changes the current working directory and\n  loads the project at the given directory onto the project\n  stack.\n\n  A `post_config` can be passed that will be merged into\n  the project configuration.\n\n  `fun` is called with the module name of the given `Mix.Project`.\n  The return value of this function is the return value of `fun`.\n\n  ## Examples\n\n      Mix.Project.in_project(:my_app, \"/path/to/my_app\", fn module ->\n        \"Mix project is: #{inspect(module)}\"\n      end)\n      #=> \"Mix project is: MyApp.MixProject\"\n\n  \"\"\"\n  @spec in_project(atom, Path.t(), keyword, (module -> result)) :: result when result: term\n  def in_project(app, path, post_config \\\\ [], fun)\n\n  def in_project(app, \".\", post_config, fun) when is_atom(app) do\n    cached =\n      try do\n        load_project(app, post_config)\n      rescue\n        any ->\n          Mix.shell().error(\"Error while loading project #{inspect(app)} at #{File.cwd!()}\")\n          reraise any, __STACKTRACE__\n      end\n\n    try do\n      fun.(cached)\n    after\n      Mix.Project.pop()\n    end\n  end\n\n  def in_project(app, path, post_config, fun) when is_atom(app) do\n    File.cd!(path, fn ->\n      in_project(app, \".\", post_config, fun)\n    end)\n  end\n\n  @doc \"\"\"\n  Returns the path where dependencies are stored for the given project.\n\n  If no configuration is given, the one for the current project is used.\n\n  The returned path will be expanded.\n\n  ## Examples\n\n      Mix.Project.deps_path()\n      #=> \"/path/to/project/deps\"\n\n  \"\"\"\n  @spec deps_path(keyword) :: Path.t()\n  def deps_path(config \\\\ config()) do\n    dir = System.get_env(\"MIX_DEPS_PATH\") || config[:deps_path]\n    Path.expand(dir)\n  end\n\n  @doc \"\"\"\n  Returns all dependencies app names.\n\n  The order they are returned is guaranteed to be sorted\n  for proper dependency resolution. For example, if A\n  depends on B, then B will listed before A.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec deps_apps() :: [atom()]\n  def deps_apps() do\n    Mix.Dep.cached() |> Enum.map(& &1.app)\n  end\n\n  @doc \"\"\"\n  Returns the SCMs of all dependencies as a map.\n\n  See `Mix.SCM` module documentation to learn more about SCMs.\n\n  ## Options\n\n    * `:depth` - only returns dependencies to the depth level,\n      a depth of `1` will only return top-level dependencies\n    * `:parents` - starts the dependency traversal from the\n      given parents instead of the application root\n\n  ## Examples\n\n      Mix.Project.deps_scms()\n      #=> %{foo: Mix.SCM.Path, bar: Mix.SCM.Git}\n\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec deps_scms(deps_traversal_opts) :: %{optional(atom) => Mix.SCM.t()}\n  def deps_scms(opts \\\\ []) when is_list(opts) do\n    traverse_deps(opts, fn %{scm: scm} -> scm end)\n  end\n\n  @doc \"\"\"\n  Returns the full path of all dependencies as a map.\n\n  ## Options\n\n    * `:depth` - only returns dependencies to the depth level,\n      a depth of `1` will only return top-level dependencies\n    * `:parents` - starts the dependency traversal from the\n      given parents instead of the application root\n\n  ## Examples\n\n      Mix.Project.deps_paths()\n      #=> %{foo: \"deps/foo\", bar: \"custom/path/dep\"}\n\n  \"\"\"\n  @spec deps_paths(deps_traversal_opts) :: %{optional(atom) => Path.t()}\n  def deps_paths(opts \\\\ []) when is_list(opts) do\n    traverse_deps(opts, fn %{opts: opts} -> opts[:dest] end)\n  end\n\n  @doc \"\"\"\n  Returns the dependencies of all dependencies as a map.\n\n  ## Options\n\n    * `:depth` - only returns dependencies to the depth level,\n      a depth of `1` will only return top-level dependencies\n    * `:parents` - starts the dependency traversal from the\n      given parents instead of the application root\n\n  ## Examples\n\n      Mix.Project.deps_tree()\n      #=> %{foo: [:bar, :baz], bar: [], baz: []}\n\n  \"\"\"\n  @doc since: \"1.15.0\"\n  @spec deps_tree(deps_traversal_opts) :: %{optional(atom) => [atom]}\n  def deps_tree(opts \\\\ []) when is_list(opts) do\n    traverse_deps(opts, fn %{deps: deps} -> Enum.map(deps, & &1.app) end)\n  end\n\n  defp traverse_deps(opts, fun) do\n    all_deps = Mix.Dep.cached()\n    parents = opts[:parents]\n    depth = opts[:depth]\n\n    if parents || depth do\n      parent_filter = if parents, do: &(&1.app in parents), else: & &1.top_level\n\n      all_deps\n      |> Enum.filter(parent_filter)\n      |> traverse_deps_map(fun)\n      |> traverse_deps_depth(all_deps, fun, 1, depth || :infinity)\n    else\n      traverse_deps_map(all_deps, fun)\n    end\n  end\n\n  defp traverse_deps_map(deps, fun) do\n    for %{app: app} = dep <- deps, do: {app, fun.(dep)}, into: %{}\n  end\n\n  defp traverse_deps_depth(deps, _all_deps, _fun, depth, depth) do\n    deps\n  end\n\n  defp traverse_deps_depth(parents, all_deps, fun, depth, target_depth) do\n    children =\n      for parent_dep <- all_deps,\n          Map.has_key?(parents, parent_dep.app),\n          %{app: app} = dep <- parent_dep.deps,\n          do: {app, fun.(dep)},\n          into: %{}\n\n    case Map.merge(parents, children) do\n      ^parents -> parents\n      new_parents -> traverse_deps_depth(new_parents, all_deps, fun, depth + 1, target_depth)\n    end\n  end\n\n  @doc \"\"\"\n  Clears the dependency for the current environment.\n\n  Useful when dependencies need to be reloaded due to change of global state.\n\n  For example, Nerves uses this function to force all dependencies to be\n  reloaded after it updates the system environment. It goes roughly like\n  this:\n\n    1. Nerves fetches all dependencies and looks for the system specific deps\n    2. Once the system specific dep is found, it loads it alongside env vars\n    3. Nerves then clears the cache, forcing dependencies to be loaded again\n    4. Dependencies are loaded again, now with an updated env environment\n\n  \"\"\"\n  @doc since: \"1.7.0\"\n  @spec clear_deps_cache() :: :ok\n  def clear_deps_cache() do\n    Mix.Dep.clear_cached()\n    :ok\n  end\n\n  @doc \"\"\"\n  Returns the build path for the given project.\n\n  The build path is built based on the `:build_path` configuration\n  (which defaults to `\"_build\"`) and a subdirectory. The subdirectory\n  is built based on two factors:\n\n    * If `:build_per_environment` is set (the default), the subdirectory\n      is the value of `Mix.env/0` (which can be set via `MIX_ENV`).\n      Otherwise it is set to \"shared\".\n\n    * If `Mix.target/0` is set (often via the `MIX_TARGET` environment\n      variable), it will be used as a prefix to the subdirectory.\n\n  The behaviour of this function can be modified by two environment\n  variables, `MIX_BUILD_ROOT` and `MIX_BUILD_PATH`, see [the Mix\n  documentation for more information](Mix.html#environment-variables).\n\n  > #### Naming differences {: .info}\n  >\n  > Ideally the configuration option `:build_path` would be called\n  > `:build_root`, as it only sets the root component of the build\n  > path but not the subdirectory. However, its name is preserved\n  > for backwards compatibility.\n\n  ## Examples\n\n      Mix.Project.build_path()\n      #=> \"/path/to/project/_build/shared\"\n\n  If `:build_per_environment` is set to `true`, it will create a new build per\n  environment:\n\n      Mix.env()\n      #=> :dev\n      Mix.Project.build_path()\n      #=> \"/path/to/project/_build/dev\"\n\n  \"\"\"\n  @spec build_path(keyword) :: Path.t()\n  def build_path(config \\\\ config()) do\n    cond do\n      deps_build_path = config[:deps_build_path] ->\n        deps_build_path\n\n      build_path = System.get_env(\"MIX_BUILD_PATH\") ->\n        Path.expand(build_path)\n\n      true ->\n        do_build_path(config)\n    end\n  end\n\n  defp do_build_path(config) do\n    dir = System.get_env(\"MIX_BUILD_ROOT\") || config[:build_path] || \"_build\"\n    subdir = build_target() <> build_per_environment(config)\n    Path.expand(dir <> \"/\" <> subdir)\n  end\n\n  defp build_target do\n    case Mix.target() do\n      :host -> \"\"\n      other -> \"#{other}_\"\n    end\n  end\n\n  defp build_per_environment(config) do\n    case config[:build_per_environment] do\n      true ->\n        Atom.to_string(Mix.env())\n\n      false ->\n        \"shared\"\n\n      other ->\n        Mix.raise(\"The :build_per_environment option should be a boolean, got: #{inspect(other)}\")\n    end\n  end\n\n  @doc \"\"\"\n  Returns the path where manifests are stored.\n\n  By default they are stored in the app path inside\n  the build directory. Umbrella applications have\n  the manifest path set to the root of the build directory.\n  Directories may be changed in future releases.\n\n  The returned path will be expanded.\n\n  ## Examples\n\n  If your project defines the app `my_app`:\n\n      Mix.Project.manifest_path()\n      #=> \"/path/to/project/_build/shared/lib/my_app/.mix\"\n\n  \"\"\"\n  @spec manifest_path(keyword) :: Path.t()\n  def manifest_path(config \\\\ config()) do\n    app_path =\n      config[:deps_app_path] ||\n        if app = config[:app] do\n          Path.join([build_path(config), \"lib\", Atom.to_string(app)])\n        else\n          build_path(config)\n        end\n\n    Path.join(app_path, \".mix\")\n  end\n\n  @doc \"\"\"\n  Returns the application path inside the build.\n\n  The returned path will be expanded.\n\n  ## Examples\n\n  If your project defines the app `my_app`:\n\n      Mix.Project.app_path()\n      #=> \"/path/to/project/_build/shared/lib/my_app\"\n\n  \"\"\"\n  @spec app_path(keyword) :: Path.t()\n  def app_path(config \\\\ config()) do\n    config[:deps_app_path] ||\n      cond do\n        app = config[:app] ->\n          Path.join([build_path(config), \"lib\", Atom.to_string(app)])\n\n        config[:apps_path] ->\n          raise \"trying to access Mix.Project.app_path/1 for an umbrella project but umbrellas have no app\"\n\n        true ->\n          Mix.raise(\n            \"Cannot access build without an application name, \" <>\n              \"please ensure you are in a directory with a mix.exs file and it defines \" <>\n              \"an :app name under the project configuration\"\n          )\n      end\n  end\n\n  @doc \"\"\"\n  Returns the paths the given project compiles to.\n\n  If no configuration is given, the one for the current project will be used.\n\n  The returned path will be expanded.\n\n  ## Examples\n\n  If your project defines the app `my_app`:\n\n      Mix.Project.compile_path()\n      #=> \"/path/to/project/_build/dev/lib/my_app/ebin\"\n\n  \"\"\"\n  @spec compile_path(keyword) :: Path.t()\n  def compile_path(config \\\\ config()) do\n    Path.join(app_path(config), \"ebin\")\n  end\n\n  @doc \"\"\"\n  Returns the path where protocol consolidations are stored.\n\n  The returned path will be expanded.\n\n  ## Examples\n\n  If your project defines the app `my_app`:\n\n      Mix.Project.consolidation_path()\n      #=> \"/path/to/project/_build/dev/lib/my_app/consolidated\"\n\n  Inside umbrellas:\n\n      Mix.Project.consolidation_path()\n      #=> \"/path/to/project/_build/dev/consolidated\"\n\n  \"\"\"\n  @spec consolidation_path(keyword) :: Path.t()\n  def consolidation_path(config \\\\ config()) do\n    config[:consolidation_path] ||\n      if umbrella?(config) do\n        Path.join(build_path(config), \"consolidated\")\n      else\n        Path.join(app_path(config), \"consolidated\")\n      end\n  end\n\n  @doc false\n  @deprecated \"Use Mix.Task.run(\\\"compile\\\", args) instead\"\n  def compile(args, _config \\\\ []) do\n    Mix.Task.run(\"compile\", args)\n  end\n\n  @doc \"\"\"\n  Builds the project structure for the given application.\n\n  ## Options\n\n    * `:symlink_ebin` - symlink ebin instead of copying it\n\n    * `:source` - the source directory to copy from.\n      Defaults to the current working directory.\n\n  \"\"\"\n  @spec build_structure(keyword, build_structure_opts) :: :ok\n  def build_structure(config \\\\ config(), opts \\\\ []) do\n    source = opts[:source] || File.cwd!()\n    target = app_path(config)\n    File.mkdir_p!(target)\n    target_ebin = Path.join(target, \"ebin\")\n\n    _ =\n      cond do\n        opts[:symlink_ebin] ->\n          _ = Mix.Utils.symlink_or_copy(Path.join(source, \"ebin\"), target_ebin)\n\n        match?({:ok, _}, :file.read_link(target_ebin)) ->\n          _ = File.rm_rf!(target_ebin)\n          File.mkdir_p!(target_ebin)\n\n        true ->\n          File.mkdir_p!(target_ebin)\n      end\n\n    for dir <- ~w(include priv) do\n      Mix.Utils.symlink_or_copy(Path.join(source, dir), Path.join(target, dir))\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Ensures the project structure for the given project exists.\n\n  In case it does exist, it is a no-op. Otherwise, it is built.\n\n  `opts` are the same options that can be passed to `build_structure/2`.\n  \"\"\"\n  @spec ensure_structure(keyword, build_structure_opts) :: :ok\n  def ensure_structure(config \\\\ config(), opts \\\\ []) do\n    if File.exists?(app_path(config)) do\n      :ok\n    else\n      build_structure(config, opts)\n    end\n  end\n\n  @deprecated \"Use Mix.Project.compile_path/1 instead\"\n  def load_paths(config \\\\ config()) do\n    if umbrella?(config) do\n      []\n    else\n      [compile_path(config)]\n    end\n  end\n\n  @doc \"\"\"\n  Acquires a lock on the project build path and runs the given function.\n\n  When another process (across all OS processes) is holding the lock,\n  a message is printed and this call blocks until the lock is acquired.\n  This function can also be called if this process already has the\n  lock. In such case the function is executed immediately.\n\n  This lock is primarily useful for compiler tasks that alter the build\n  artifacts to avoid conflicts with a concurrent compilation.\n  \"\"\"\n  @spec with_build_lock(keyword, (-> term())) :: term()\n  def with_build_lock(config \\\\ config(), fun) do\n    # To avoid duplicated compilation, we wrap compilation tasks, such\n    # as compile.all, deps.compile, compile.elixir, compile.erlang in\n    # a lock. Note that compile.all covers compile.elixir, but the\n    # latter can still be invoked directly, so we put the lock over\n    # each individual task.\n\n    build_path = build_path(config)\n\n    on_taken = fn os_pid ->\n      Mix.shell().error([\n        IO.ANSI.reset(),\n        \"Waiting for lock on the build directory (held by process #{os_pid})\"\n      ])\n    end\n\n    Mix.Sync.Lock.with_lock(build_path, fun, on_taken: on_taken)\n  end\n\n  @doc false\n  def with_deps_lock(config \\\\ config(), fun) do\n    # We wrap operations on the deps directory and on mix.lock to\n    # avoid write conflicts.\n\n    deps_path = deps_path(config)\n\n    on_taken = fn os_pid ->\n      Mix.shell().error([\n        IO.ANSI.reset(),\n        \"Waiting for lock on the deps directory (held by process #{os_pid})\"\n      ])\n    end\n\n    Mix.Sync.Lock.with_lock(deps_path, fun, on_taken: on_taken)\n  end\n\n  # Loads mix.exs in the current directory or loads the project from the\n  # mixfile cache and pushes the project onto the project stack.\n  defp load_project(app, post_config) do\n    Mix.ProjectStack.post_config(post_config)\n\n    if cached = Mix.State.read_cache({:app, app}) do\n      {project, file} = cached\n      push(project, file, app)\n      project\n    else\n      file = Path.expand(\"mix.exs\")\n      old_proj = get()\n\n      {new_proj, file} =\n        if File.regular?(file) do\n          old_undefined = Code.get_compiler_option(:no_warn_undefined)\n\n          try do\n            Code.compiler_options(relative_paths: false, no_warn_undefined: :all)\n            _ = Code.compile_file(file)\n            get()\n          else\n            ^old_proj -> Mix.raise(\"Could not find a Mix project at #{file}\")\n            new_proj -> {new_proj, file}\n          after\n            Code.compiler_options(relative_paths: true, no_warn_undefined: old_undefined)\n          end\n        else\n          push(nil, file, app)\n          {nil, \"nofile\"}\n        end\n\n      Mix.State.write_cache({:app, app}, {new_proj, file})\n      new_proj\n    end\n  end\n\n  defp default_config do\n    [\n      aliases: [],\n      build_per_environment: true,\n      build_scm: Mix.SCM.Path,\n      config_path: \"config/config.exs\",\n      consolidate_protocols: true,\n      deps: [],\n      deps_path: \"deps\",\n      elixirc_paths: [\"lib\"],\n      erlc_paths: [\"src\"],\n      erlc_include_path: \"include\",\n      erlc_options: [],\n      lockfile: \"mix.lock\",\n      start_permanent: false\n    ]\n  end\n\n  @private_config [:build_scm, :deps_app_path, :deps_build_path]\n  defp get_project_config(nil), do: []\n  defp get_project_config(atom), do: atom.project() |> Keyword.drop(@private_config)\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/project_stack.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.ProjectStack do\n  @moduledoc false\n\n  use GenServer\n  @name __MODULE__\n  @timeout :infinity\n\n  # compile.lock is not the best name, but the name is completely\n  # opaque and we keep it for backwards compatibility (just in case).\n  @manifest \"compile.lock\"\n\n  @typep file :: binary\n  @typep config :: keyword\n  @typep project :: %{name: module, config: config, file: file}\n\n  @spec start_link(keyword) :: {:ok, pid}\n  def start_link(_opts) do\n    GenServer.start_link(__MODULE__, :ok, name: @name)\n  end\n\n  @spec on_clean_slate((-> result)) :: result when result: var\n  def on_clean_slate(callback) do\n    previous_state = update_state(fn state -> {state, initial_state()} end)\n\n    try do\n      callback.()\n    after\n      update_state(fn _ -> {:ok, previous_state} end)\n    end\n  end\n\n  @spec clear_stack() :: :ok\n  def clear_stack do\n    update_state(fn _ -> {:ok, initial_state()} end)\n  end\n\n  @spec post_config(config) :: :ok\n  def post_config(config) do\n    update_state(fn {stack, post_config} ->\n      {:ok, {stack, Keyword.merge(post_config, config)}}\n    end)\n  end\n\n  @spec pop_post_config(atom) :: term\n  def pop_post_config(key) do\n    update_state(fn {stack, post_config} ->\n      {value, post_config} = Keyword.pop(post_config, key)\n      {value, {stack, post_config}}\n    end)\n  end\n\n  @spec merge_config(config) :: :ok\n  def merge_config(config) do\n    update_stack(fn\n      [h | t] -> {:ok, [update_in(h.config, &Keyword.merge(&1, config)) | t]}\n      [] -> {:ok, []}\n    end)\n  end\n\n  @spec on_recursing_root((-> result)) :: result when result: var\n  def on_recursing_root(fun) do\n    {top, file} =\n      update_stack(fn stack ->\n        {top, [mid | bottom]} = Enum.split_while(stack, &(not &1.recursing?))\n        {{top, mid.file}, [%{mid | recursing?: false} | bottom]}\n      end)\n\n    try do\n      File.cd!(Path.dirname(file), fun)\n    after\n      update_stack(fn [mid | bottom] ->\n        {:ok, top ++ [%{mid | recursing?: true} | bottom]}\n      end)\n    end\n  end\n\n  @spec loaded_config([atom], [binary()]) :: :ok\n  def loaded_config(apps, files) do\n    update_stack(fn\n      [%{config_apps: h_apps, config_files: h_files} = h | t] ->\n        h = %{\n          h\n          | config_apps: apps ++ h_apps,\n            config_files: files ++ h_files,\n            config_mtime: nil\n        }\n\n        {:ok, [h | t]}\n\n      [] ->\n        {:ok, []}\n    end)\n  end\n\n  # We include the year 2000 as a minimum value in case we\n  # don't have any config files, which would return 0 and\n  # then not trigger stale sources.\n  @minimum_mtime 946_684_800\n\n  @spec config_mtime() :: integer\n  def config_mtime() do\n    mtime_or_files =\n      get_stack(fn\n        [%{config_mtime: nil, config_files: files} | _] -> files\n        [%{config_mtime: mtime} | _] -> mtime\n        [] -> @minimum_mtime\n      end)\n\n    if is_list(mtime_or_files) do\n      mtime =\n        mtime_or_files\n        |> Enum.map(&Mix.Utils.last_modified/1)\n        |> Enum.max()\n        |> max(@minimum_mtime)\n\n      update_stack(fn [h | t] -> {mtime, [%{h | config_mtime: mtime} | t]} end)\n    else\n      mtime_or_files\n    end\n  end\n\n  @spec reset_config_mtime() :: binary\n  def reset_config_mtime() do\n    update_stack(fn\n      [h | t] -> {:ok, [%{h | config_mtime: nil} | t]}\n      [] -> {:ok, []}\n    end)\n\n    @manifest\n  end\n\n  @spec config_apps() :: [atom]\n  def config_apps() do\n    get_stack(fn\n      [h | _] -> h.config_apps\n      [] -> []\n    end)\n  end\n\n  @spec config_files() :: [binary]\n  def config_files() do\n    get_stack(fn\n      [h | _] -> h.config_files\n      [] -> []\n    end)\n  end\n\n  @spec project_file() :: binary | nil\n  def project_file() do\n    get_stack(fn\n      [h | _] -> h.file\n      [] -> nil\n    end)\n  end\n\n  @spec parent_umbrella_project_file() :: binary | nil\n  def parent_umbrella_project_file() do\n    get_stack(fn\n      [_, h | _] -> if h.config[:apps_path], do: h.file, else: nil\n      _ -> nil\n    end)\n  end\n\n  @spec compile_env([term] | nil) :: [term] | nil\n  def compile_env(compile_env) do\n    update_stack(fn\n      [h | t] -> {h.compile_env, [%{h | compile_env: compile_env} | t]}\n      [] -> {nil, []}\n    end)\n  end\n\n  @spec prepend_after_compiler(atom, fun) :: :ok\n  def prepend_after_compiler(name, fun) do\n    update_stack(fn\n      [h | t] -> {:ok, [update_in(h.after_compiler[name], &[fun | &1 || []]) | t]}\n      [] -> {:ok, []}\n    end)\n  end\n\n  @spec pop_after_compiler(atom) :: [fun]\n  def pop_after_compiler(name) do\n    update_stack(fn\n      [h | t] ->\n        {value, h} = pop_in(h.after_compiler[name])\n        {value || [], [h | t]}\n\n      [] ->\n        {[], []}\n    end)\n  end\n\n  @spec pop() :: project | nil\n  def pop do\n    update_stack(fn\n      [h | t] -> {project(h), t}\n      [] -> {nil, []}\n    end)\n  end\n\n  @spec peek() :: project | nil\n  def peek do\n    get_stack(fn\n      [h | _] -> project(h)\n      [] -> nil\n    end)\n  end\n\n  @spec top_and_bottom() :: {project, project} | nil\n  def top_and_bottom do\n    get_stack(fn\n      [h | _] = stack -> {project(h), project(List.last(stack))}\n      [] -> nil\n    end)\n  end\n\n  @spec printable_app_name() :: atom | nil\n  def printable_app_name do\n    update_stack(fn\n      [] ->\n        {nil, []}\n\n      [%{io_done: true} | _] = stack ->\n        {nil, stack}\n\n      [h | t] ->\n        h = %{h | io_done: true}\n        t = Enum.map(t, &%{&1 | io_done: false})\n        {h.config[:app], [h | t]}\n    end)\n  end\n\n  @spec recur((-> result)) :: result when result: var\n  def recur(fun) do\n    update_stack(fn [h | t] -> {:ok, [%{h | recursing?: true} | t]} end)\n\n    try do\n      fun.()\n    after\n      update_stack(fn [h | t] -> {:ok, [%{h | recursing?: false} | t]} end)\n    end\n  end\n\n  @spec recursing :: module | nil\n  def recursing do\n    get_stack(fn stack -> Enum.find_value(stack, &(&1.recursing? and &1.name)) end)\n  end\n\n  @spec push(module, config, file) :: :ok | {:error, file}\n  def push(module, config, file) do\n    update_state(fn {stack, post_config} ->\n      if existing_file = find_project_named(module, stack) do\n        {{:error, existing_file}, {stack, post_config}}\n      else\n        # Consider the first children to always have io_done\n        # because we don't need to print anything unless another\n        # project takes ahold of the shell.\n        io_done? = stack == []\n        config = Keyword.merge(config, post_config)\n        manifest_file = Path.join(Mix.Project.manifest_path(config), @manifest)\n        parent_files = peek_config_files(config[:inherit_parent_config_files], stack)\n\n        project = %{\n          name: module,\n          config: config,\n          file: file,\n          pos: length(stack),\n          recursing?: false,\n          io_done: io_done?,\n          config_apps: [],\n          config_files: [manifest_file | parent_files],\n          config_mtime: nil,\n          after_compiler: %{},\n          compile_env: nil\n        }\n\n        {:ok, {[project | stack], []}}\n      end\n    end)\n  end\n\n  defp peek_config_files(true, [%{config_files: files} | _]), do: files\n  defp peek_config_files(_, _), do: []\n\n  defp find_project_named(name, stack) do\n    name &&\n      Enum.find_value(stack, fn\n        %{name: n, file: file} when n == name -> file\n        %{} -> nil\n      end)\n  end\n\n  defp project(h) do\n    Map.take(h, [:name, :config, :file, :pos])\n  end\n\n  ## GenServer helpers and callbacks\n\n  defp get_stack(fun) do\n    GenServer.call(@name, {:get_stack, fun}, @timeout)\n  end\n\n  defp update_stack(fun) do\n    GenServer.call(@name, {:update_stack, fun}, @timeout)\n  end\n\n  defp update_state(fun) do\n    GenServer.call(@name, {:update_state, fun}, @timeout)\n  end\n\n  defp initial_state() do\n    {[], []}\n  end\n\n  @impl true\n  def init(:ok) do\n    {:ok, initial_state()}\n  end\n\n  @impl true\n  def handle_call({:get_stack, fun}, _from, {stack, post_config}) do\n    {:reply, fun.(stack), {stack, post_config}}\n  end\n\n  @impl true\n  def handle_call({:update_stack, fun}, _from, {stack, post_config}) do\n    {reply, stack} = fun.(stack)\n    {:reply, reply, {stack, post_config}}\n  end\n\n  @impl true\n  def handle_call({:update_state, fun}, _from, state) do\n    {reply, state} = fun.(state)\n    {:reply, reply, state}\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/pubsub/subscriber.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Mix.PubSub.Subscriber do\n  @moduledoc false\n\n  use GenServer\n\n  @name __MODULE__\n\n  @spec start_link(keyword) :: GenServer.on_start()\n  def start_link(_opts) do\n    GenServer.start_link(__MODULE__, {}, name: @name)\n  end\n\n  @spec flush :: :ok\n  def flush do\n    GenServer.cast(@name, :flush)\n  end\n\n  @impl true\n  def init({}) do\n    build_path = Mix.Project.build_path()\n\n    case Mix.Sync.PubSub.subscribe(build_path) do\n      :ok ->\n        {:ok, %{acc: []}}\n\n      {:error, message} ->\n        IO.warn(message, [])\n        :ignore\n    end\n  end\n\n  @impl true\n  def handle_info(message, %{acc: nil} = state) do\n    notify_listeners([message])\n    {:noreply, state}\n  end\n\n  def handle_info(message, state) do\n    # Accumulate messages until the flush\n    {:noreply, update_in(state.acc, &[message | &1])}\n  end\n\n  @impl true\n  def handle_cast(:flush, state) do\n    notify_listeners(Enum.reverse(state.acc))\n    {:noreply, %{state | acc: nil}}\n  end\n\n  defp notify_listeners(messages) do\n    children = Supervisor.which_children(Mix.PubSub.ListenerSupervisor)\n\n    for message <- messages do\n      for {_, pid, _, _} <- children, is_pid(pid) do\n        send(pid, message)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/pubsub.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Mix.PubSub do\n  @moduledoc false\n\n  # The Mix pub/sub is responsible for notifying other OS processes\n  # about relevant concurrent events.\n  #\n  # The pub/sub consists of a local subscriber process that receives\n  # events from other OS processes, and a listener supervisor, which\n  # holds all listener processes that have been configured. Whenever\n  # the subscriber receives an event, it sends a message to each of\n  # the listeners.\n  #\n  # Inherently, a compilation may be required before the listener\n  # modules are available, so we start the local subscriber process\n  # separately with `start/0`, and then start the listeners later\n  # with `start_listeners/0`. The subscriber is going to accumulate\n  # events and reply them once the listeners are started.\n\n  @spec start :: :ok\n  def start do\n    # Avoid calling the supervisor, if already started\n    if Process.whereis(Mix.PubSub) do\n      :ok\n    else\n      case Supervisor.start_child(Mix.Supervisor, Mix.PubSub) do\n        {:ok, _pid} ->\n          :ok\n\n        {:error, {:already_started, _pid}} ->\n          :ok\n\n        {:error, reason} ->\n          raise RuntimeError, \"failed to start Mix.PubSub, reason: #{inspect(reason)}\"\n      end\n    end\n  end\n\n  @spec child_spec(term) :: Supervisor.child_spec()\n  def child_spec(_opts) do\n    children = [\n      Mix.PubSub.Subscriber\n    ]\n\n    opts = [strategy: :one_for_one, name: Mix.PubSub]\n\n    %{\n      id: Mix.PubSub,\n      start: {Supervisor, :start_link, [children, opts]},\n      type: :supervisor\n    }\n  end\n\n  @spec start_listeners :: :ok\n  def start_listeners do\n    # Avoid calling the supervisor, if already started\n    if Process.whereis(Mix.PubSub.ListenerSupervisor) do\n      :ok\n    else\n      case Supervisor.start_child(Mix.PubSub, listener_supervisor()) do\n        {:ok, _pid} ->\n          Mix.PubSub.Subscriber.flush()\n          :ok\n\n        {:error, {:already_started, _pid}} ->\n          :ok\n\n        {:error, reason} ->\n          raise RuntimeError,\n                \"failed to start Mix.PubSub.ListenerSupervisor, reason: #{inspect(reason)}\"\n      end\n    end\n  end\n\n  defp listener_supervisor do\n    children = configured_listeners() ++ built_in_listeners()\n\n    children = Enum.map(children, &Supervisor.child_spec(&1, []))\n\n    opts = [strategy: :one_for_one, name: Mix.PubSub.ListenerSupervisor]\n\n    %{\n      id: Mix.PubSub.ListenerSupervisor,\n      start: {Supervisor, :start_link, [children, opts]},\n      type: :supervisor\n    }\n  end\n\n  defp configured_listeners do\n    config = Mix.Project.config()\n\n    listeners =\n      Application.get_env(:mix, :listeners, []) ++\n        Keyword.get(config, :listeners, [])\n\n    Enum.uniq(listeners)\n  end\n\n  defp built_in_listeners do\n    iex_started? = Process.whereis(IEx.Supervisor) != nil\n\n    if iex_started? do\n      [IEx.MixListener]\n    else\n      []\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/rebar.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Rebar do\n  @moduledoc false\n\n  # TODO: Remove on Elixir v1.22 because phx_new and other installers rely on it.\n  @deprecated \"Use env_rebar_path/1 instead\"\n  def global_rebar_cmd(manager) do\n    env_rebar_path(manager)\n  end\n\n  @deprecated \"Use local_rebar_path/1 instead\"\n  def local_rebar_cmd(manager) do\n    local_rebar_path(manager)\n  end\n\n  @deprecated \"Use rebar_args/2 or available?/1 instead\"\n  def rebar_cmd(manager) do\n    global_rebar_cmd(manager) || local_rebar_cmd(manager)\n  end\n\n  @doc \"\"\"\n  Returns if Rebar is available or not.\n  \"\"\"\n  def available?(manager) do\n    env_rebar_path(manager) != nil or File.regular?(local_rebar_path(manager))\n  end\n\n  @doc \"\"\"\n  Receives a Rebar executable and returns how it must be invoked.\n\n  It returns a result even if Rebar is not available.\n  \"\"\"\n  def rebar_args(:rebar3, args) do\n    rebar = env_rebar_path(:rebar3) || local_rebar_path(:rebar3)\n\n    if match?({:win32, _}, :os.type()) and not String.ends_with?(rebar, \".cmd\") do\n      {\"escript.exe\", [rebar | args]}\n    else\n      {rebar, args}\n    end\n  end\n\n  @doc \"\"\"\n  Returns the global rebar path.\n  \"\"\"\n  def env_rebar_path(:rebar3) do\n    System.get_env(\"MIX_REBAR3\")\n  end\n\n  @doc \"\"\"\n  Returns the path supposed to host the local copy of `rebar`.\n\n  The rebar3 installation is specific to the Elixir version and OTP release,\n  in order to force updates when new Elixir versions come out.\n  \"\"\"\n  def local_rebar_path(:rebar3) do\n    [major, minor | _] = String.split(System.version(), \".\")\n\n    Path.join([\n      Mix.Utils.mix_home(),\n      \"elixir\",\n      \"#{major}-#{minor}-otp-#{System.otp_release()}\",\n      \"rebar3\"\n    ])\n  end\n\n  @doc \"\"\"\n  Loads `rebar.config` and evaluates `rebar.config.script` if it\n  exists in the given directory.\n  \"\"\"\n  def load_config(dir) do\n    config_path = Path.join(dir, \"rebar.config\")\n    script_path = Path.join(dir, \"rebar.config.script\")\n\n    config =\n      case :file.consult(config_path) do\n        {:ok, config} ->\n          config\n\n        {:error, :enoent} ->\n          []\n\n        {:error, error} ->\n          reason = :file.format_error(error)\n          Mix.raise(\"Error consulting Rebar config #{inspect(config_path)}: #{reason}\")\n      end\n\n    if File.exists?(script_path) do\n      eval_script(script_path, config)\n    else\n      config\n    end\n  end\n\n  @doc \"\"\"\n  Serializes a Rebar config to a term file.\n  \"\"\"\n  def serialize_config(config) do\n    Enum.map(config, &[:io_lib.print(&1) | \".\\n\"])\n  end\n\n  @doc \"\"\"\n  Updates Rebar configuration to be more suitable for dependencies.\n  \"\"\"\n  def dependency_config(config) do\n    Enum.flat_map(config, fn\n      {:erl_opts, opts} ->\n        [{:erl_opts, List.delete(opts, :warnings_as_errors)}]\n\n      {:project_plugins, _} ->\n        []\n\n      other ->\n        [other]\n    end)\n  end\n\n  @doc \"\"\"\n  Parses the dependencies in given `rebar.config` to Mix's dependency format.\n  \"\"\"\n  def deps(config) do\n    # We don't have to handle Rebar3 profiles because dependencies\n    # are always in the default profile which cannot be customized\n    if deps = config[:deps] do\n      Enum.map(deps, &parse_dep/1)\n    else\n      []\n    end\n  end\n\n  # Translate a Rebar dependency declaration to a Mix declaration\n  # From https://www.rebar3.org/docs/configuration/dependencies/#declaring-dependencies\n  defp parse_dep(app) when is_atom(app) do\n    {app, override: true}\n  end\n\n  defp parse_dep({app, req}) when is_list(req) do\n    {app, List.to_string(req), override: true}\n  end\n\n  defp parse_dep({app, source}) when is_tuple(source) do\n    parse_dep({app, nil, source, []})\n  end\n\n  defp parse_dep({app, req, source}) do\n    parse_dep({app, req, source, []})\n  end\n\n  defp parse_dep({app, req, source, opts}) do\n    source = parse_source(source)\n    compile = if :proplists.get_value(:raw, opts, false), do: [compile: false], else: []\n    opts = [override: true] ++ source ++ compile\n\n    if req do\n      {app, compile_req(req), opts}\n    else\n      {app, opts}\n    end\n  end\n\n  defp parse_source({:pkg, pkg}) do\n    [hex: pkg]\n  end\n\n  defp parse_source(source) do\n    [scm, url | source] = Tuple.to_list(source)\n\n    {scm, additional_opts} =\n      case {scm, source} do\n        {:git_subdir, [_, sparse_dir | _]} -> {:git, [sparse: sparse_dir]}\n        {_, _} -> {:git, []}\n      end\n\n    ref =\n      case source do\n        [\"\" | _] -> [branch: \"HEAD\"]\n        [{:branch, branch} | _] -> [branch: to_string(branch)]\n        [{:tag, tag} | _] -> [tag: to_string(tag)]\n        [{:ref, ref} | _] -> [ref: to_string(ref)]\n        [ref | _] -> [ref: to_string(ref)]\n        _ -> []\n      end\n\n    [{scm, to_string(url)}] ++ ref ++ additional_opts\n  end\n\n  defp compile_req(req) do\n    req = List.to_string(req)\n\n    case Version.parse_requirement(req) do\n      {:ok, _} ->\n        req\n\n      :error ->\n        case Regex.compile(req) do\n          {:ok, re} ->\n            re\n\n          {:error, reason} ->\n            Mix.raise(\"Unable to compile version regular expression: #{inspect(req)}, #{reason}\")\n        end\n    end\n  end\n\n  defp eval_script(script_path, config) do\n    script = String.to_charlist(Path.basename(script_path))\n\n    result =\n      File.cd!(Path.dirname(script_path), fn ->\n        :file.script(script, eval_binds(CONFIG: config, SCRIPT: script))\n      end)\n\n    case result do\n      {:ok, config} ->\n        config\n\n      {:error, error} ->\n        reason = :file.format_error(error)\n        Mix.shell().error(\"Error evaluating Rebar config script #{script_path}:#{reason}\")\n\n        Mix.shell().error(\n          \"Any dependencies defined in the script won't be available \" <>\n            \"unless you add them to your Mix project\"\n        )\n\n        config\n    end\n  end\n\n  defp eval_binds(binds) do\n    Enum.reduce(binds, :erl_eval.new_bindings(), fn {k, v}, binds ->\n      :erl_eval.add_binding(k, v, binds)\n    end)\n  end\n\n  @doc \"\"\"\n  Applies the given overrides for app config.\n  \"\"\"\n  def apply_overrides(app, config, overrides) do\n    # Inefficient. We want the order we get here though.\n    config =\n      Enum.reduce(overrides, config, fn\n        {:override, overrides}, config ->\n          Enum.reduce(overrides, config, fn {key, value}, config ->\n            Keyword.put(config, key, value)\n          end)\n\n        _, config ->\n          config\n      end)\n\n    config =\n      Enum.reduce(overrides, config, fn\n        {:override, ^app, overrides}, config ->\n          Enum.reduce(overrides, config, fn {key, value}, config ->\n            Keyword.put(config, key, value)\n          end)\n\n        _, config ->\n          config\n      end)\n\n    config =\n      Enum.reduce(overrides, config, fn\n        {:add, ^app, overrides}, config ->\n          Enum.reduce(overrides, config, fn {key, value}, config ->\n            old_value = Keyword.get(config, key, [])\n            Keyword.put(config, key, value ++ old_value)\n          end)\n\n        _, config ->\n          config\n      end)\n\n    Keyword.update(config, :overrides, overrides, &(overrides ++ &1))\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/release.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Release do\n  @moduledoc \"\"\"\n  Defines the release structure and convenience for assembling releases.\n  \"\"\"\n\n  @doc \"\"\"\n  The Mix.Release struct has the following read-only fields:\n\n    * `:name` - the name of the release as an atom\n    * `:version` - the version of the release as a string\n    * `:path` - the path to the release root\n    * `:version_path` - the path to the release version inside the release\n    * `:applications` - a map of application with their definitions\n    * `:erts_source` - the ERTS source as a charlist (or nil)\n    * `:erts_version` - the ERTS version as a charlist\n\n  The following fields may be modified as long as they keep their defined types:\n\n    * `:boot_scripts` - a map of boot scripts with the boot script name\n      as key and a keyword list with **all** applications that are part of\n      it and their modes as value\n    * `:config_providers` - a list of `{config_provider, term}` tuples where the\n      first element is a module that implements the `Config.Provider` behaviour\n      and `term` is the value given to it on `c:Config.Provider.init/1`\n    * `:options` - a keyword list with all other user supplied release options\n    * `:overlays` - a list of extra files added to the release. If you have a custom\n      step adding extra files to a release, you can add these files to the `:overlays`\n      field so they are also considered on further commands, such as tar/zip. Each entry\n      in overlays is the relative path to the release root of each file\n    * `:steps` - a list of functions that receive the release and returns a release.\n      Must also contain the atom `:assemble` which is the internal assembling step.\n      May also contain the atom `:tar` to create a tarball of the release.\n\n  \"\"\"\n  defstruct [\n    :name,\n    :version,\n    :path,\n    :version_path,\n    :applications,\n    :boot_scripts,\n    :erts_source,\n    :erts_version,\n    :config_providers,\n    :options,\n    :overlays,\n    :steps\n  ]\n\n  @type mode :: :permanent | :transient | :temporary | :load | :none\n  @type application :: atom()\n  @type t :: %__MODULE__{\n          name: atom(),\n          version: String.t(),\n          path: String.t(),\n          version_path: String.t(),\n          applications: %{application() => keyword()},\n          boot_scripts: %{atom() => [{application(), mode()}]},\n          erts_version: charlist(),\n          erts_source: charlist() | nil,\n          config_providers: [{module, term}],\n          options: keyword(),\n          overlays: list(String.t()),\n          steps: [(t -> t) | :assemble, ...]\n        }\n\n  @typedoc \"\"\"\n  Options for stripping BEAM files.\n  \"\"\"\n  @type strip_beam_opts :: [\n          keep: [String.t()],\n          compress: boolean()\n        ]\n\n  @typedoc \"\"\"\n  Erlang/OTP sys.config structure.\n\n  A list of tuples where each tuple contains an application name and its\n  configuration as a keyword list. This is the standard format for Erlang\n  application configuration.\n  \"\"\"\n  @type sys_config :: [{application(), keyword()}]\n\n  @default_apps [kernel: :permanent, stdlib: :permanent, elixir: :permanent, sasl: :permanent]\n  @safe_modes [:permanent, :temporary, :transient]\n  @unsafe_modes [:load, :none]\n  @additional_chunks ~w(Attr)c\n  @copy_app_dirs [\"priv\", \"include\"]\n\n  @doc false\n  @spec from_config!(atom, keyword, keyword) :: t\n  def from_config!(name, config, overrides) do\n    {name, apps, opts} = find_release(name, config)\n\n    if not (Atom.to_string(name) =~ ~r/^[a-z][a-z0-9_]*$/) do\n      Mix.raise(\n        \"Invalid release name. A release name must start with a lowercase ASCII letter, \" <>\n          \"followed by lowercase ASCII letters, numbers, or underscores, got: #{inspect(name)}\"\n      )\n    end\n\n    opts =\n      [overwrite: false, quiet: false, strip_beams: true]\n      |> Keyword.merge(opts)\n      |> Keyword.merge(overrides)\n\n    {include_erts, opts} = Keyword.pop(opts, :include_erts, true)\n    {erts_source, erts_lib_dir, erts_version} = erts_data(include_erts)\n\n    deps_apps = Mix.Project.deps_apps()\n    loaded_apps = load_apps(apps, deps_apps, %{}, erts_lib_dir, [], apps)\n\n    # Make sure IEx is either an active part of the release or add it as none.\n    {loaded_apps, apps} =\n      if Map.has_key?(loaded_apps, :iex) do\n        {loaded_apps, apps}\n      else\n        {load_apps([iex: :none], deps_apps, loaded_apps, erts_lib_dir, [], apps),\n         apps ++ [iex: :none]}\n      end\n\n    start_boot = build_start_boot(loaded_apps, apps)\n    start_clean_boot = build_start_clean_boot(start_boot)\n\n    {path, opts} =\n      Keyword.pop_lazy(opts, :path, fn ->\n        Path.join([Mix.Project.build_path(config), \"rel\", Atom.to_string(name)])\n      end)\n\n    path = Path.absname(path)\n\n    {version, opts} =\n      Keyword.pop_lazy(opts, :version, fn ->\n        config[:version] ||\n          Mix.raise(\n            \"No :version found. Please make sure a :version is set in your project definition \" <>\n              \"or inside the release the configuration\"\n          )\n      end)\n\n    version =\n      case version do\n        {:from_app, app} ->\n          Application.load(app)\n          version = Application.spec(app, :vsn)\n\n          if !version do\n            Mix.raise(\n              \"Could not find version for #{inspect(app)}, please make sure the application exists\"\n            )\n          end\n\n          to_string(version)\n\n        \"\" ->\n          Mix.raise(\"The release :version cannot be an empty string\")\n\n        _ ->\n          version\n      end\n\n    {config_providers, opts} = Keyword.pop(opts, :config_providers, [])\n    {steps, opts} = Keyword.pop(opts, :steps, [:assemble])\n    validate_steps!(steps)\n\n    %Mix.Release{\n      name: name,\n      version: version,\n      path: path,\n      version_path: Path.join([path, \"releases\", version]),\n      erts_source: erts_source,\n      erts_version: erts_version,\n      applications: Map.delete(loaded_apps, :erts),\n      boot_scripts: %{start: start_boot, start_clean: start_clean_boot},\n      config_providers: config_providers,\n      options: opts,\n      overlays: [],\n      steps: steps\n    }\n  end\n\n  defp find_release(name, config) do\n    {name, opts_fun_or_list} = lookup_release(name, config) || infer_release(config)\n    opts = if is_function(opts_fun_or_list, 0), do: opts_fun_or_list.(), else: opts_fun_or_list\n    {apps, opts} = Keyword.pop(opts, :applications, [])\n\n    if apps == [] and Mix.Project.umbrella?(config) do\n      bad_umbrella!()\n    end\n\n    app = Keyword.get(config, :app)\n    apps = Keyword.merge(@default_apps, apps)\n\n    if is_nil(app) or Keyword.has_key?(apps, app) do\n      {name, apps, opts}\n    else\n      {name, apps ++ [{app, :permanent}], opts}\n    end\n  end\n\n  defp lookup_release(nil, config) do\n    case Keyword.get(config, :releases, []) do\n      [] ->\n        nil\n\n      [{name, opts}] ->\n        {name, opts}\n\n      [_ | _] ->\n        case Keyword.get(config, :default_release) do\n          nil ->\n            Mix.raise(\n              \"\\\"mix release\\\" was invoked without a name but there are multiple releases. \" <>\n                \"Please call \\\"mix release NAME\\\" or set :default_release in your project configuration\"\n            )\n\n          name ->\n            lookup_release(name, config)\n        end\n    end\n  end\n\n  defp lookup_release(name, config) do\n    if opts = config[:releases][name] do\n      {name, opts}\n    else\n      found = Keyword.get(config, :releases, [])\n\n      Mix.raise(\n        \"Unknown release #{inspect(name)}. \" <>\n          \"The available releases are: #{inspect(Keyword.keys(found))}\"\n      )\n    end\n  end\n\n  defp infer_release(config) do\n    if Mix.Project.umbrella?(config) do\n      bad_umbrella!()\n    else\n      {Keyword.fetch!(config, :app), []}\n    end\n  end\n\n  defp bad_umbrella! do\n    Mix.raise(\"\"\"\n    Umbrella projects require releases to be explicitly defined with \\\n    a non-empty applications key that chooses which umbrella children \\\n    should be part of the releases:\n\n        releases: [\n          foo: [\n            applications: [child_app_foo: :permanent]\n          ],\n          bar: [\n            applications: [child_app_bar: :permanent]\n          ]\n        ]\n\n    Alternatively you can perform the release from the children applications\n    \"\"\")\n  end\n\n  defp erts_data(erts_data) when is_function(erts_data) do\n    erts_data(erts_data.())\n  end\n\n  defp erts_data(false) do\n    {nil, :code.lib_dir(), :erlang.system_info(:version)}\n  end\n\n  defp erts_data(true) do\n    version = :erlang.system_info(:version)\n    {:filename.join(:code.root_dir(), ~c\"erts-#{version}\"), :code.lib_dir(), version}\n  end\n\n  defp erts_data(erts_source) when is_binary(erts_source) do\n    if File.exists?(erts_source) do\n      [_, erts_version] = erts_source |> Path.basename() |> String.split(\"-\")\n      erts_lib_dir = erts_source |> Path.dirname() |> Path.join(\"lib\") |> to_charlist()\n      {to_charlist(erts_source), erts_lib_dir, to_charlist(erts_version)}\n    else\n      Mix.raise(\"Could not find ERTS system at #{inspect(erts_source)}\")\n    end\n  end\n\n  defp load_apps(apps, deps_apps, seen, otp_root, optional, overrides) do\n    for {app, mode} <- apps, reduce: seen do\n      seen ->\n        properties = seen[app]\n\n        cond do\n          is_nil(properties) ->\n            load_app(app, overrides[app] || mode, deps_apps, seen, otp_root, optional, overrides)\n\n          Keyword.has_key?(overrides, app) ->\n            seen\n\n          new_mode = merge_mode!(app, mode, properties[:mode]) ->\n            apps =\n              properties\n              |> Keyword.get(:applications, [])\n              |> Enum.map(&{&1, new_mode})\n\n            seen = put_in(seen[app][:mode], new_mode)\n            optional = Keyword.get(properties, :optional_applications, [])\n            load_apps(apps, deps_apps, seen, otp_root, optional, overrides)\n\n          true ->\n            seen\n        end\n    end\n  end\n\n  defp merge_mode!(_app, mode, mode), do: nil\n\n  defp merge_mode!(app, left, right) do\n    if left == :included or right == :included do\n      Mix.raise(\n        \"#{inspect(app)} is listed both as a regular application and as an included application\"\n      )\n    else\n      merge_mode(left, right)\n    end\n  end\n\n  defp merge_mode(:none, other), do: other\n  defp merge_mode(other, :none), do: other\n  defp merge_mode(:load, other), do: other\n  defp merge_mode(other, :load), do: other\n  defp merge_mode(:temporary, other), do: other\n  defp merge_mode(other, :temporary), do: other\n  defp merge_mode(:transient, other), do: other\n  defp merge_mode(other, :transient), do: other\n  defp merge_mode(:permanent, other), do: other\n  defp merge_mode(other, :permanent), do: other\n\n  defp load_app(app, mode, deps_apps, seen, otp_root, optional, overrides) do\n    cond do\n      path = app not in deps_apps && otp_path(otp_root, app) ->\n        do_load_app(app, mode, path, deps_apps, seen, otp_root, true, overrides)\n\n      path = code_path(app) ->\n        do_load_app(app, mode, path, deps_apps, seen, otp_root, false, overrides)\n\n      app in optional ->\n        seen\n\n      true ->\n        Mix.raise(\"Could not find application #{inspect(app)}\")\n    end\n  end\n\n  defp otp_path(otp_root, app) do\n    path = Path.join(otp_root, \"#{app}-*\")\n\n    case Path.wildcard(path) do\n      [] -> nil\n      paths -> paths |> Enum.sort() |> List.last() |> to_charlist()\n    end\n  end\n\n  defp code_path(app) do\n    case :code.lib_dir(app) do\n      {:error, :bad_name} -> nil\n      path -> path\n    end\n  end\n\n  defp do_load_app(app, mode, path, deps_apps, seen, otp_root, otp_app?, overrides) do\n    case :file.consult(Path.join(path, \"ebin/#{app}.app\")) do\n      {:ok, terms} ->\n        [{:application, ^app, properties}] = terms\n        value = [path: path, otp_app?: otp_app?, mode: mode] ++ properties\n        seen = Map.put(seen, app, value)\n        child_mode = if mode == :included, do: :load, else: mode\n\n        applications =\n          properties\n          |> Keyword.get(:applications, [])\n          |> Enum.map(&{&1, child_mode})\n\n        optional = Keyword.get(properties, :optional_applications, [])\n        seen = load_apps(applications, deps_apps, seen, otp_root, optional, overrides)\n\n        included_applications =\n          properties\n          |> Keyword.get(:included_applications, [])\n          |> Enum.map(&{&1, :included})\n\n        load_apps(included_applications, deps_apps, seen, otp_root, [], overrides)\n\n      {:error, reason} ->\n        Mix.raise(\"Could not load #{app}.app. Reason: #{inspect(reason)}\")\n    end\n  end\n\n  defp build_start_boot(all_apps, specified_apps) do\n    specified_apps ++\n      Enum.sort(\n        for(\n          {app, props} <- all_apps,\n          not List.keymember?(specified_apps, app, 0),\n          do: {app, boot_mode(props[:mode])}\n        )\n      )\n  end\n\n  defp boot_mode(:included), do: :load\n  defp boot_mode(mode), do: mode\n\n  defp build_start_clean_boot(boot) do\n    for({app, mode} <- boot, do: {app, if(mode == :none, do: :none, else: :load)})\n    |> Keyword.put(:stdlib, :permanent)\n    |> Keyword.put(:kernel, :permanent)\n  end\n\n  defp validate_steps!(steps) do\n    valid_atoms = [:assemble, :tar]\n\n    if not is_list(steps) or Enum.any?(steps, &(&1 not in valid_atoms and not is_function(&1, 1))) do\n      Mix.raise(\"\"\"\n      The :steps option must be a list of:\n\n        * anonymous function that receives one argument\n        * the atom :assemble or :tar\n\n      Got: #{inspect(steps)}\n      \"\"\")\n    end\n\n    if Enum.count(steps, &(&1 == :assemble)) != 1 do\n      Mix.raise(\"The :steps option must contain the atom :assemble once, got: #{inspect(steps)}\")\n    end\n\n    if :assemble in Enum.drop_while(steps, &(&1 != :tar)) do\n      Mix.raise(\"The :tar step must come after :assemble\")\n    end\n\n    if Enum.count(steps, &(&1 == :tar)) > 1 do\n      Mix.raise(\"The :steps option can only contain the atom :tar once\")\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Makes the `sys.config` structure.\n\n  If there are config providers, then a value is injected into\n  the `:elixir` application configuration in `sys_config` to be\n  read during boot and trigger the providers.\n\n  It uses the following release options to customize its behavior:\n\n    * `:reboot_system_after_config`\n    * `:start_distribution_during_config`\n    * `:prune_runtime_sys_config_after_boot`\n\n  In case there are no config providers, it doesn't change `sys_config`.\n  \"\"\"\n  @spec make_sys_config(t, sys_config(), Config.Provider.config_path()) ::\n          :ok | {:error, String.t()}\n  def make_sys_config(release, sys_config, config_provider_path) do\n    {sys_config, runtime_config?} =\n      merge_provider_config(release, sys_config, config_provider_path)\n\n    case consultable_sys_config(sys_config) do\n      {:ok, contents} ->\n        path = Path.join(release.version_path, \"sys.config\")\n        args = [runtime_config?, contents]\n        format = \"%% coding: utf-8~n%% RUNTIME_CONFIG=~s~n~ts.~n\"\n        File.mkdir_p!(Path.dirname(path))\n        File.write!(path, IO.chardata_to_string(:io_lib.format(format, args)))\n        :ok\n\n      {:error, message} ->\n        {:error, message}\n    end\n  end\n\n  defp consultable_sys_config(sys_config) do\n    contents =\n      Enum.map_intersperse(sys_config, ?,, fn {app, kv} ->\n        kv =\n          Enum.map_intersperse(kv, ?,, fn {key, value} ->\n            case Mix.Utils.consultable(value) do\n              {:ok, value} -> [?{, :io_lib.print(key), ?,, value, ?}]\n              {:error, term, reason} -> throw({:error, app, key, term, reason})\n            end\n          end)\n\n        [?{, :io_lib.print(app), ?,, ?[, kv, ?], ?}]\n      end)\n\n    {:ok, [?[, contents, ?]]}\n  catch\n    {:error, app, key, value, reason} ->\n      message = \"\"\"\n      Could not write configuration file because it has invalid terms\n\n      Application: #{inspect(app)}\n      Key: #{inspect(key)}\n      Invalid value: #{inspect(value)}\n      Reason: #{reason}\n      \"\"\"\n\n      {:error, message}\n  end\n\n  defp merge_provider_config(%{config_providers: []}, sys_config, _), do: {sys_config, false}\n\n  defp merge_provider_config(release, sys_config, config_path) do\n    {reboot?, extra_config, initial_config} = start_distribution(release)\n\n    prune_runtime_sys_config_after_boot =\n      Keyword.get(release.options, :prune_runtime_sys_config_after_boot, false)\n\n    opts = [\n      extra_config: initial_config,\n      prune_runtime_sys_config_after_boot: prune_runtime_sys_config_after_boot,\n      reboot_system_after_config: reboot?,\n      validate_compile_env: validate_compile_env(release)\n    ]\n\n    init_config = Config.Provider.init(release.config_providers, config_path, opts)\n    {Config.Reader.merge(sys_config, init_config ++ extra_config), reboot?}\n  end\n\n  defp validate_compile_env(release) do\n    with true <- Keyword.get(release.options, :validate_compile_env, true),\n         [_ | _] = compile_env <- compile_env(release) do\n      compile_env\n    else\n      _ -> false\n    end\n  end\n\n  defp compile_env(release) do\n    for {_, properties} <- release.applications,\n        triplet <- Keyword.get(properties, :compile_env, []),\n        do: triplet\n  end\n\n  defp start_distribution(%{options: opts}) do\n    reboot? = Keyword.get(opts, :reboot_system_after_config, false)\n    early_distribution? = Keyword.get(opts, :start_distribution_during_config, false)\n\n    if not reboot? or early_distribution? do\n      {reboot?, [], []}\n    else\n      {true, [kernel: [start_distribution: false]], [kernel: [start_distribution: true]]}\n    end\n  end\n\n  @doc \"\"\"\n  Copies the cookie to the given path.\n\n  If a cookie option was given, we compare it with\n  the contents of the file (if any), and ask the user\n  if they want to override.\n\n  If there is no option, we generate a random one\n  the first time.\n  \"\"\"\n  @spec make_cookie(t, Path.t()) :: :ok\n  def make_cookie(release, path) do\n    cond do\n      cookie = release.options[:cookie] ->\n        force? = Keyword.get(release.options, :overwrite, false)\n        Mix.Generator.create_file(path, cookie, quiet: true, force: force?)\n        :ok\n\n      File.exists?(path) ->\n        :ok\n\n      true ->\n        File.write!(path, random_cookie())\n        :ok\n    end\n  end\n\n  defp random_cookie, do: Base.encode32(:crypto.strong_rand_bytes(32))\n\n  @doc \"\"\"\n  Makes the start_erl.data file with the\n  ERTS version and release versions.\n  \"\"\"\n  @spec make_start_erl(t, Path.t()) :: :ok\n  def make_start_erl(release, path) do\n    File.write!(path, \"#{release.erts_version} #{release.version}\")\n    :ok\n  end\n\n  @doc \"\"\"\n  Makes boot scripts.\n\n  It receives a path to the boot file, without extension, such as\n  `releases/0.1.0/start` and this command will write `start.rel`,\n  `start.boot`, and `start.script` to the given path, returning\n  `{:ok, rel_path}` or `{:error, message}`.\n\n  The boot script uses the RELEASE_LIB environment variable, which must\n  be accordingly set with `--boot-var` and point to the release lib dir.\n  \"\"\"\n  @spec make_boot_script(t, Path.t(), [{application(), mode()}], [String.t()]) ::\n          :ok | {:error, String.t()}\n  def make_boot_script(release, path, modes, prepend_paths \\\\ []) do\n    with {:ok, rel_spec} <- build_release_spec(release, modes) do\n      File.write!(path <> \".rel\", consultable(rel_spec))\n\n      sys_path = String.to_charlist(path)\n\n      sys_options = [\n        :silent,\n        :no_dot_erlang,\n        :no_warn_sasl,\n        variables: build_variables(release),\n        path: build_paths(release)\n      ]\n\n      case :systools.make_script(sys_path, sys_options) do\n        {:ok, _module, _warnings} ->\n          script_path = sys_path ++ ~c\".script\"\n          {:ok, [{:script, rel_info, instructions}]} = :file.consult(script_path)\n\n          instructions =\n            instructions\n            |> post_stdlib_applies(release)\n            |> prepend_paths_to_script(prepend_paths)\n\n          script = {:script, rel_info, instructions}\n          File.write!(script_path, consultable(script))\n          :ok = :systools.script2boot(sys_path)\n\n        {:error, module, info} ->\n          message = module.format_error(info) |> to_string() |> String.trim()\n          {:error, message}\n      end\n    end\n  end\n\n  defp build_variables(release) do\n    for {_, properties} <- release.applications,\n        not Keyword.fetch!(properties, :otp_app?),\n        uniq: true,\n        do: {~c\"RELEASE_LIB\", properties |> Keyword.fetch!(:path) |> :filename.dirname()}\n  end\n\n  defp build_paths(release) do\n    for {_, properties} <- release.applications,\n        Keyword.fetch!(properties, :otp_app?),\n        do: properties |> Keyword.fetch!(:path) |> Path.join(\"ebin\") |> to_charlist()\n  end\n\n  defp build_release_spec(release, modes) do\n    %{\n      name: name,\n      version: version,\n      erts_version: erts_version,\n      applications: apps,\n      options: options\n    } = release\n\n    skip_mode_validation_for =\n      options\n      |> Keyword.get(:skip_mode_validation_for, [])\n      |> MapSet.new()\n\n    rel_apps =\n      for {app, mode} <- modes do\n        properties = Map.get(apps, app) || throw({:error, \"Unknown application #{inspect(app)}\"})\n        children = Keyword.get(properties, :applications, [])\n        optional = Keyword.get(properties, :optional_applications, [])\n        app in skip_mode_validation_for || validate_mode!(app, mode, modes, children, optional)\n        build_app_for_release(app, mode, properties)\n      end\n\n    {:ok, {:release, {to_charlist(name), to_charlist(version)}, {:erts, erts_version}, rel_apps}}\n  catch\n    {:error, message} -> {:error, message}\n  end\n\n  defp validate_mode!(app, mode, modes, children, optional) do\n    safe_mode? = mode in @safe_modes\n\n    if not safe_mode? and mode not in @unsafe_modes do\n      throw(\n        {:error,\n         \"Unknown mode #{inspect(mode)} for #{inspect(app)}. \" <>\n           \"Valid modes are: #{inspect(@safe_modes ++ @unsafe_modes)}\"}\n      )\n    end\n\n    for child <- children do\n      child_mode = Keyword.get(modes, child)\n\n      cond do\n        is_nil(child_mode) and child not in optional ->\n          throw(\n            {:error,\n             \"Application #{inspect(app)} is listed in the release boot, \" <>\n               \"but it depends on #{inspect(child)}, which isn't\"}\n          )\n\n        safe_mode? and child_mode in @unsafe_modes ->\n          throw(\n            {:error,\n             \"\"\"\n             Application #{inspect(app)} has mode #{inspect(mode)} but it depends on \\\n             #{inspect(child)} which is set to #{inspect(child_mode)}. If you really want \\\n             to set such mode for #{inspect(child)} make sure that all applications that depend \\\n             on it are also set to :load or :none, otherwise your release will fail to boot\n             \"\"\"}\n          )\n\n        true ->\n          :ok\n      end\n    end\n  end\n\n  defp build_app_for_release(app, mode, properties) do\n    vsn = Keyword.fetch!(properties, :vsn)\n\n    case Keyword.get(properties, :included_applications, []) do\n      [] -> {app, vsn, mode}\n      included_apps -> {app, vsn, mode, included_apps}\n    end\n  end\n\n  defp post_stdlib_applies(instructions, release) do\n    {pre, [stdlib | post]} =\n      Enum.split_while(\n        instructions,\n        &(not match?({:apply, {:application, :start_boot, [:stdlib, _]}}, &1))\n      )\n\n    pre ++ [stdlib] ++ config_provider_apply(release) ++ post\n  end\n\n  defp config_provider_apply(%{config_providers: []}),\n    do: []\n\n  defp config_provider_apply(_),\n    do: [{:apply, {Config.Provider, :boot, []}}]\n\n  defp prepend_paths_to_script(instructions, []), do: instructions\n\n  defp prepend_paths_to_script(instructions, prepend_paths) do\n    prepend_paths = Enum.map(prepend_paths, &String.to_charlist/1)\n\n    Enum.map(instructions, fn\n      {:path, paths} ->\n        if Enum.any?(paths, &List.starts_with?(&1, ~c\"$RELEASE_LIB\")) do\n          {:path, prepend_paths ++ paths}\n        else\n          {:path, paths}\n        end\n\n      other ->\n        other\n    end)\n  end\n\n  defp consultable(term) do\n    IO.chardata_to_string(:io_lib.format(\"%% coding: utf-8~n~tp.~n\", [term]))\n  end\n\n  @doc \"\"\"\n  Finds a template path for the release.\n  \"\"\"\n  @spec rel_templates_path(t, Path.t()) :: binary\n  def rel_templates_path(release, path) do\n    Path.join(release.options[:rel_templates_path] || \"rel\", path)\n  end\n\n  @doc \"\"\"\n  Copies ERTS if the release is configured to do so.\n\n  Returns `true` if the release was copied, `false` otherwise.\n  \"\"\"\n  @spec copy_erts(t) :: boolean()\n  def copy_erts(%{erts_source: nil}) do\n    false\n  end\n\n  def copy_erts(release) do\n    destination = Path.join(release.path, \"erts-#{release.erts_version}/bin\")\n    File.mkdir_p!(destination)\n\n    release.erts_source\n    |> Path.join(\"bin\")\n    |> File.cp_r!(destination, on_conflict: fn _, _ -> false end)\n\n    _ = File.rm(Path.join(destination, \"erl\"))\n    _ = File.rm(Path.join(destination, \"erl.ini\"))\n\n    destination\n    |> Path.join(\"erl\")\n    |> File.write!(~S\"\"\"\n    #!/bin/sh\n    SELF=$(readlink \"$0\" || true)\n    if [ -z \"$SELF\" ]; then SELF=\"$0\"; fi\n    BINDIR=\"$(cd \"$(dirname \"$SELF\")\" && pwd -P)\"\n    ROOTDIR=\"${ERL_ROOTDIR:-\"$(dirname \"$(dirname \"$BINDIR\")\")\"}\"\n    EMU=beam\n    PROGNAME=$(echo \"$0\" | sed 's/.*\\///')\n    export EMU\n    export ROOTDIR\n    export BINDIR\n    export PROGNAME\n    exec \"$BINDIR/erlexec\" ${1+\"$@\"}\n    \"\"\")\n\n    File.chmod!(Path.join(destination, \"erl\"), 0o755)\n    true\n  end\n\n  @doc \"\"\"\n  Copies the given application specification into the release.\n\n  It assumes the application exists in the release.\n  \"\"\"\n  @spec copy_app(t, application) :: boolean()\n  def copy_app(release, app) do\n    properties = Map.fetch!(release.applications, app)\n    vsn = Keyword.fetch!(properties, :vsn)\n\n    source_app = Keyword.fetch!(properties, :path)\n    target_app = Path.join([release.path, \"lib\", \"#{app}-#{vsn}\"])\n\n    if is_nil(release.erts_source) and Keyword.fetch!(properties, :otp_app?) do\n      false\n    else\n      File.rm_rf!(target_app)\n      File.mkdir_p!(target_app)\n\n      copy_ebin(release, Path.join(source_app, \"ebin\"), Path.join(target_app, \"ebin\"))\n\n      for dir <- @copy_app_dirs do\n        source_dir = Path.join(source_app, dir)\n        target_dir = Path.join(target_app, dir)\n        File.exists?(source_dir) && File.cp_r!(source_dir, target_dir, dereference_symlinks: true)\n      end\n\n      true\n    end\n  end\n\n  @doc \"\"\"\n  Copies the ebin directory at `source` to `target`\n  respecting release options such a `:strip_beams`.\n  \"\"\"\n  @spec copy_ebin(t, Path.t(), Path.t()) :: boolean()\n  def copy_ebin(release, source, target) do\n    with {:ok, [_ | _] = files} <- File.ls(source) do\n      File.mkdir_p!(target)\n\n      strip_options =\n        release.options\n        |> Keyword.get(:strip_beams, true)\n        |> parse_strip_beams_options()\n\n      for file <- files do\n        source_file = Path.join(source, file)\n        target_file = Path.join(target, file)\n\n        case Path.extname(file) do\n          \".beam\" ->\n            process_beam_file(source_file, target_file, strip_options)\n\n          \".app\" ->\n            process_app_file(source_file, target_file)\n\n          _ ->\n            # Use File.cp!/3 to preserve file mode for any executables stored\n            # in the ebin directory.\n            File.cp!(source_file, target_file)\n        end\n      end\n\n      true\n    else\n      _ -> false\n    end\n  end\n\n  defp process_beam_file(source_file, target_file, strip_options) do\n    with true <- is_list(strip_options),\n         {:ok, binary} <- strip_beam(File.read!(source_file), strip_options) do\n      File.write!(target_file, binary)\n    else\n      _ -> File.cp!(source_file, target_file)\n    end\n  end\n\n  defp process_app_file(source_file, target_file) do\n    with {:ok, [{:application, app, info}]} <- :file.consult(source_file) do\n      File.write!(target_file, :io_lib.format(\"~tp.~n\", [{:application, app, info}]))\n    else\n      _ -> File.cp!(source_file, target_file)\n    end\n  end\n\n  @doc \"\"\"\n  Strips a beam file for a release.\n\n  This keeps only significant chunks necessary for the VM operation,\n  discarding documentation, debug info, compile information and others.\n\n  The exact chunks that are kept are not documented and may change in\n  future versions.\n\n  ## Options\n\n    * `:keep` - a list of additional chunk names (as strings) to keep in the\n      stripped BEAM file beyond those required by Erlang/Elixir\n\n    * `:compress` - when `true`, the resulting BEAM file will be compressed\n      using gzip. Defaults to `false`\n\n  ## Examples\n\n      # Strip with default options\n      Mix.Release.strip_beam(beam_binary)\n\n      # Keep additional chunks and compress\n      Mix.Release.strip_beam(beam_binary, keep: [\"Docs\", \"ChunkName\"], compress: true)\n\n  \"\"\"\n  @spec strip_beam(binary(), strip_beam_opts()) :: {:ok, binary()} | {:error, :beam_lib, term()}\n  def strip_beam(binary, options \\\\ []) when is_list(options) do\n    chunks_to_keep = options[:keep] |> List.wrap() |> Enum.map(&String.to_charlist/1)\n    all_chunks = Enum.uniq(@additional_chunks ++ :beam_lib.significant_chunks() ++ chunks_to_keep)\n    compress? = Keyword.get(options, :compress, false)\n\n    case :beam_lib.chunks(binary, all_chunks, [:allow_missing_chunks]) do\n      {:ok, {_, chunks}} ->\n        chunks = for {name, chunk} <- chunks, is_binary(chunk), do: {name, chunk}\n        {:ok, binary} = :beam_lib.build_module(chunks)\n\n        if compress? do\n          {:ok, :zlib.gzip(binary)}\n        else\n          {:ok, binary}\n        end\n\n      {:error, _, _} = error ->\n        error\n    end\n  end\n\n  defp parse_strip_beams_options(options) do\n    case options do\n      options when is_list(options) -> options\n      true -> []\n      false -> nil\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/remote_converger.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.RemoteConverger do\n  @moduledoc false\n\n  # A remote converger returns updated dependencies with\n  # extra information that can be used during Mix's converging.\n  # Useful for things like external package managers\n\n  @doc \"\"\"\n  Returns `true` if given dependency is handled by\n  remote converger.\n  \"\"\"\n  @callback remote?(Mix.Dep.t()) :: boolean\n\n  @doc \"\"\"\n  Runs the remote converger.\n\n  Return updated lock.\n  \"\"\"\n  @callback converge([Mix.Dep.t()], map) :: map\n\n  @doc \"\"\"\n  Returns child dependencies the converger has for the\n  dependency. This list should filter the loaded children.\n  \"\"\"\n  @callback deps(Mix.Dep.t(), map) :: [atom]\n\n  @doc \"\"\"\n  Called after all convergers have run so that the remote\n  converger can perform cleanup.\n  \"\"\"\n  @callback post_converge() :: any\n\n  @doc \"\"\"\n  Gets registered remote converger.\n  \"\"\"\n  def get do\n    Mix.State.get(:remote_converger)\n  end\n\n  @doc \"\"\"\n  Registers a remote converger.\n  \"\"\"\n  def register(mod) when is_atom(mod) do\n    Mix.State.put(:remote_converger, mod)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/scm/git.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.SCM.Git do\n  @behaviour Mix.SCM\n  @moduledoc false\n\n  @impl true\n  def fetchable? do\n    true\n  end\n\n  @impl true\n  def format(opts) do\n    if rev = get_opts_rev(opts) do\n      \"#{redact_uri(opts[:git])} - #{rev}\"\n    else\n      redact_uri(opts[:git])\n    end\n  end\n\n  @impl true\n  def format_lock(opts) do\n    case opts[:lock] do\n      {:git, _, lock_rev, lock_opts} ->\n        lock = String.slice(lock_rev, 0, 7)\n\n        case Enum.find_value([:ref, :branch, :tag], &List.keyfind(lock_opts, &1, 0)) do\n          {:ref, _} -> lock <> \" (ref)\"\n          {key, val} -> lock <> \" (#{key}: #{val})\"\n          nil -> lock\n        end\n\n      _ ->\n        nil\n    end\n  end\n\n  @impl true\n  def accepts_options(_app, opts) do\n    opts =\n      opts\n      |> Keyword.put(:checkout, opts[:dest])\n      |> sparse_opts()\n      |> subdir_opts()\n\n    cond do\n      gh = opts[:github] ->\n        opts\n        |> Keyword.delete(:github)\n        |> Keyword.put(:git, \"https://github.com/#{gh}.git\")\n        |> validate_git_options()\n\n      opts[:git] ->\n        opts\n        |> validate_git_options()\n\n      true ->\n        nil\n    end\n  end\n\n  @impl true\n  def checked_out?(opts) do\n    # Are we inside a Git repository?\n    opts[:checkout]\n    |> Path.join(\".git/HEAD\")\n    |> File.regular?()\n  end\n\n  @impl true\n  def lock_status(opts) do\n    lock = opts[:lock]\n\n    cond do\n      lock_rev = get_lock_rev(lock, opts) ->\n        %{origin: origin, rev: rev} = get_rev_info(opts[:checkout])\n\n        if get_lock_repo(lock) == origin and lock_rev == rev do\n          :ok\n        else\n          :mismatch\n        end\n\n      is_nil(lock) ->\n        :mismatch\n\n      true ->\n        :outdated\n    end\n  end\n\n  @impl true\n  def equal?(opts1, opts2) do\n    opts1[:git] == opts2[:git] and get_lock_opts(opts1) == get_lock_opts(opts2)\n  end\n\n  @impl true\n  def managers(_opts) do\n    []\n  end\n\n  @impl true\n  def checkout(opts) do\n    path = opts[:checkout]\n    File.rm_rf!(path)\n    File.mkdir_p!(opts[:dest])\n\n    File.cd!(path, fn ->\n      git!(~w[-c core.hooksPath='' init --quiet])\n      git!([\"--git-dir=.git\", \"remote\", \"add\", \"origin\", opts[:git]])\n      checkout(path, opts)\n    end)\n  end\n\n  @impl true\n  def update(opts) do\n    path = opts[:checkout]\n    File.cd!(path, fn -> checkout(path, opts) end)\n  end\n\n  defp checkout(_path, opts) do\n    Mix.shell().print_app()\n\n    # Set configuration\n    sparse_toggle(opts)\n    update_origin(opts[:git])\n\n    # Fetch external data\n    lock_rev = get_lock_rev(opts[:lock], opts)\n\n    [\"--git-dir=.git\", \"fetch\", \"--force\", \"--quiet\"]\n    |> Kernel.++(progress_switch(git_version()))\n    |> Kernel.++(tags_switch(opts[:tag]))\n    |> Kernel.++(depth_switch(opts[:depth]))\n    |> Kernel.++(refspec_switch(opts, lock_rev || get_opts_rev(opts)))\n    |> git!()\n\n    # Migrate the Git repo\n    rev = lock_rev || get_origin_opts_rev(opts) || default_branch()\n    git!([\"--git-dir=.git\", \"checkout\", \"--force\", \"--quiet\", rev])\n\n    if opts[:submodules] do\n      git!(~w[-c core.hooksPath='' --git-dir=.git submodule update --init --recursive])\n    end\n\n    # Get the new repo lock\n    get_lock(opts)\n  end\n\n  defp sparse_opts(opts) do\n    if opts[:sparse] do\n      dest = Path.join(opts[:dest], opts[:sparse])\n      Keyword.put(opts, :dest, dest)\n    else\n      opts\n    end\n  end\n\n  defp subdir_opts(opts) do\n    if opts[:subdir] do\n      dest = Path.join(opts[:dest], opts[:subdir])\n      Keyword.put(opts, :dest, dest)\n    else\n      opts\n    end\n  end\n\n  defp sparse_toggle(opts) do\n    cond do\n      sparse = opts[:sparse] ->\n        check_sparse_support(git_version())\n        git!([\"--git-dir=.git\", \"config\", \"core.sparsecheckout\", \"true\"])\n        File.mkdir_p!(\".git/info\")\n        File.write!(\".git/info/sparse-checkout\", sparse)\n\n      File.exists?(\".git/info/sparse-checkout\") ->\n        File.write!(\".git/info/sparse-checkout\", \"*\")\n        git!([\"--git-dir=.git\", \"read-tree\", \"-mu\", \"HEAD\"])\n        git!([\"--git-dir=.git\", \"config\", \"core.sparsecheckout\", \"false\"])\n        File.rm(\".git/info/sparse-checkout\")\n\n      true ->\n        :ok\n    end\n  end\n\n  @min_git_version_sparse {1, 7, 4}\n  @min_git_version_depth {1, 5, 0}\n  @min_git_version_progress {1, 7, 1}\n\n  defp check_sparse_support(version) do\n    ensure_feature_compatibility(version, @min_git_version_sparse, \"sparse checkout\")\n  end\n\n  defp check_depth_support(version) do\n    ensure_feature_compatibility(version, @min_git_version_depth, \"depth (shallow clone)\")\n  end\n\n  defp ensure_feature_compatibility(version, required_version, feature) do\n    if not (required_version <= version) do\n      Mix.raise(\n        \"Git >= #{format_version(required_version)} is required to use #{feature}. \" <>\n          \"You are running version #{format_version(version)}\"\n      )\n    end\n  end\n\n  defp progress_switch(version) do\n    if @min_git_version_progress <= version, do: [\"--progress\"], else: []\n  end\n\n  defp tags_switch(nil), do: []\n  defp tags_switch(_), do: [\"--tags\"]\n\n  defp depth_switch(nil), do: []\n\n  defp depth_switch(n) when is_integer(n) and n > 0 do\n    check_depth_support(git_version())\n    [\"--depth=#{n}\"]\n  end\n\n  defp refspec_switch(_opts, nil), do: []\n\n  defp refspec_switch(opts, rev) do\n    case Keyword.take(opts, [:depth, :branch, :tag]) do\n      [_ | _] -> [\"origin\", rev]\n      _ -> []\n    end\n  end\n\n  ## Helpers\n\n  defp validate_git_options(opts) do\n    opts\n    |> validate_refspec()\n    |> validate_depth()\n  end\n\n  defp validate_refspec(opts) do\n    case Keyword.take(opts, [:branch, :ref, :tag]) do\n      [] ->\n        opts\n\n      [{_refspec, value}] when is_binary(value) ->\n        opts\n\n      [{refspec, value}] ->\n        Mix.raise(\n          \"A dependency's #{refspec} must be a string, got: #{inspect(value)}. \" <>\n            \"Error on Git dependency: #{redact_uri(opts[:git])}\"\n        )\n\n      _ ->\n        Mix.raise(\n          \"You should specify only one of branch, ref or tag, and only once. \" <>\n            \"Error on Git dependency: #{redact_uri(opts[:git])}\"\n        )\n    end\n  end\n\n  @sha1_size 40\n\n  defp validate_depth(opts) do\n    case Keyword.take(opts, [:depth]) do\n      [] ->\n        opts\n\n      [{:depth, depth}] when is_integer(depth) and depth > 0 ->\n        ref = opts[:ref]\n\n        if ref && byte_size(ref) < @sha1_size do\n          Mix.raise(\n            \"When :depth is used with :ref, a full commit hash is required. \" <>\n              \"Error on Git dependency: #{redact_uri(opts[:git])}\"\n          )\n        end\n\n        opts\n\n      invalid_depth ->\n        Mix.raise(\n          \"The depth must be a positive integer, and be specified only once, got: #{inspect(invalid_depth)}. \" <>\n            \"Error on Git dependency: #{redact_uri(opts[:git])}\"\n        )\n    end\n  end\n\n  defp get_lock(opts) do\n    %{rev: rev} = get_rev_info()\n    {:git, opts[:git], rev, get_lock_opts(opts)}\n  end\n\n  defp get_lock_repo({:git, repo, _, _}), do: repo\n\n  defp get_lock_rev({:git, repo, lock, lock_opts}, opts) when is_binary(lock) do\n    if repo == opts[:git] and lock_opts == get_lock_opts(opts) do\n      lock\n    end\n  end\n\n  defp get_lock_rev(_, _), do: nil\n\n  defp get_lock_opts(opts) do\n    lock_opts = Keyword.take(opts, [:branch, :ref, :tag, :sparse, :subdir, :depth])\n\n    if opts[:submodules] do\n      lock_opts ++ [submodules: true]\n    else\n      lock_opts\n    end\n  end\n\n  defp get_opts_rev(opts) do\n    opts[:branch] || opts[:ref] || opts[:tag]\n  end\n\n  defp get_origin_opts_rev(opts) do\n    if branch = opts[:branch] do\n      \"origin/#{branch}\"\n    else\n      opts[:ref] || opts[:tag]\n    end\n  end\n\n  defp redact_uri(git) do\n    case URI.parse(git) do\n      %{userinfo: nil} -> git\n      uri -> URI.to_string(%{uri | userinfo: \"****:****\"})\n    end\n  end\n\n  defp get_rev_info(dir \\\\ nil) do\n    # These commands can fail and we don't want to raise.\n    origin_command = [\"--git-dir=.git\", \"config\", \"remote.origin.url\"]\n    rev_command = [\"--git-dir=.git\", \"rev-parse\", \"--verify\", \"--quiet\", \"HEAD\"]\n    opts = if dir, do: cmd_opts(cd: dir), else: cmd_opts([])\n\n    with {origin, 0} <- System.cmd(\"git\", origin_command, opts),\n         {rev, 0} <- System.cmd(\"git\", rev_command, opts) do\n      %{origin: String.trim(origin), rev: String.trim(rev)}\n    else\n      _ -> %{origin: nil, rev: nil}\n    end\n  end\n\n  defp update_origin(location) do\n    git!([\"--git-dir=.git\", \"config\", \"remote.origin.url\", location])\n    :ok\n  end\n\n  defp default_branch() do\n    # Note: the `set-head -a` command requires the remote reference to be\n    # fetched first.\n    git!([\"--git-dir=.git\", \"remote\", \"set-head\", \"origin\", \"-a\"])\n    \"origin/HEAD\"\n  end\n\n  defp git!(args, into \\\\ default_into()) do\n    opts = cmd_opts(into: into, stderr_to_stdout: true)\n\n    try do\n      System.cmd(\"git\", args, opts)\n    catch\n      :error, :enoent ->\n        Mix.raise(\n          \"Error fetching/updating Git repository: the \\\"git\\\" \" <>\n            \"executable is not available in your PATH. Please install \" <>\n            \"Git on this machine or pass --no-deps-check if you want to \" <>\n            \"run a previously built application on a system without Git.\"\n        )\n    else\n      {response, 0} ->\n        response\n\n      {response, _} when is_binary(response) ->\n        Mix.raise(\"Command \\\"git #{Enum.join(args, \" \")}\\\" failed with reason: #{response}\")\n\n      {_, _} ->\n        Mix.raise(\"Command \\\"git #{Enum.join(args, \" \")}\\\" failed\")\n    end\n  end\n\n  defp default_into() do\n    case Mix.shell() do\n      Mix.Shell.IO -> IO.stream()\n      _ -> \"\"\n    end\n  end\n\n  defp cmd_opts(opts) do\n    if Keyword.has_key?(opts, :cd) do\n      opts\n    else\n      # Attempt to set the current working directory by default.\n      # This addresses an issue changing the working directory when executing from\n      # within a secondary node since file I/O is done through the main node.\n      case File.cwd() do\n        {:ok, cwd} -> Keyword.put(opts, :cd, cwd)\n        _ -> opts\n      end\n    end\n  end\n\n  # Invoked by lib/mix/test/test_helper.exs\n  @doc false\n  def unsupported_options do\n    git_version = git_version()\n\n    []\n    |> Kernel.++(if git_version < @min_git_version_sparse, do: [:sparse], else: [])\n    |> Kernel.++(if git_version < @min_git_version_depth, do: [:depth], else: [])\n  end\n\n  defp git_version do\n    case Mix.State.fetch(:git_version) do\n      {:ok, version} ->\n        version\n\n      :error ->\n        version =\n          [\"--version\"]\n          |> git!(\"\")\n          |> parse_version_output()\n\n        Mix.State.put(:git_version, version)\n        version\n    end\n  end\n\n  defp parse_version_output(output) do\n    output\n    |> String.trim()\n    |> String.split(\"\\n\")\n    |> List.last()\n    |> parse_version()\n  end\n\n  defp parse_version(\"git version \" <> version) do\n    version\n    |> String.split(\".\")\n    |> Enum.take(3)\n    |> Enum.map(&to_integer/1)\n    |> List.to_tuple()\n  end\n\n  defp parse_version(other) do\n    Mix.raise(\"Unable to parse Git version from: #{inspect(other)}\")\n  end\n\n  defp format_version(version) do\n    version |> Tuple.to_list() |> Enum.join(\".\")\n  end\n\n  defp to_integer(string) do\n    {int, _} = Integer.parse(string)\n    int\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/scm/path.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.SCM.Path do\n  @behaviour Mix.SCM\n  @moduledoc false\n\n  @impl true\n  def fetchable? do\n    false\n  end\n\n  @impl true\n  def format(opts) do\n    opts[:path]\n  end\n\n  @impl true\n  def format_lock(_opts) do\n    nil\n  end\n\n  @impl true\n  def accepts_options(app, opts) do\n    cond do\n      raw = opts[:path] ->\n        Keyword.put(opts, :dest, Path.expand(raw))\n\n      opts[:in_umbrella] ->\n        if opts[:override] do\n          Mix.shell().error(\"\"\"\n          warning: in-umbrella application #{inspect(app)} has the flag :override \\\n          set to true, but the flag has no effect when running from the umbrella root\n          \"\"\")\n        end\n\n        if opts[:optional] do\n          Mix.shell().error(\"\"\"\n          warning: in-umbrella application #{inspect(app)} has the flag :optional \\\n          set to true, but the flag is not supported for umbrella dependencies\n          \"\"\")\n        end\n\n        path = \"../#{app}\"\n\n        opts\n        |> Keyword.put(:dest, Path.expand(path))\n        |> Keyword.put_new(:path, path)\n        |> Keyword.put_new(:env, Mix.env())\n\n      true ->\n        nil\n    end\n  end\n\n  @impl true\n  def checked_out?(opts) do\n    File.dir?(opts[:dest])\n  end\n\n  @impl true\n  def lock_status(_opts) do\n    :ok\n  end\n\n  @impl true\n  def equal?(opts1, opts2) do\n    opts1[:dest] == opts2[:dest]\n  end\n\n  @impl true\n  def managers(_opts) do\n    []\n  end\n\n  @impl true\n  def checkout(opts) do\n    path = Path.relative_to_cwd(opts[:dest])\n    Mix.raise(\"Cannot checkout path dependency, expected a dependency at #{path}\")\n  end\n\n  @impl true\n  def update(opts) do\n    opts[:lock]\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/scm.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.SCM do\n  @moduledoc \"\"\"\n  This module provides helper functions and defines the\n  behaviour required by any source code manager (SCM) used by Mix.\n  \"\"\"\n\n  @typedoc \"\"\"\n  A module implementing the `Mix.SCM` behaviour.\n  \"\"\"\n  @type t :: module\n\n  @type opts :: keyword\n\n  @doc \"\"\"\n  Returns a boolean if the dependency can be fetched\n  or it is meant to be previously available in the\n  file system.\n\n  Local dependencies (i.e. non-fetchable ones) are automatically\n  recompiled every time the parent project is compiled.\n  \"\"\"\n  @callback fetchable? :: boolean\n\n  @doc \"\"\"\n  Returns a string representing the SCM. This is used\n  when printing the dependency and not for inspection,\n  so the amount of information should be concise and\n  easy to spot.\n  \"\"\"\n  @callback format(opts) :: String.t()\n\n  @doc \"\"\"\n  Returns a string representing the SCM. This is used\n  when printing the dependency and not for inspection,\n  so the amount of information should be concise and\n  easy to spot.\n\n  If nil is returned, it means no lock information is available.\n  \"\"\"\n  @callback format_lock(opts) :: String.t() | nil\n\n  @doc \"\"\"\n  This behaviour function receives a keyword list of `opts`\n  and should return an updated list in case the SCM consumes\n  the available options. For example, when a developer specifies\n  a dependency:\n\n      {:foo, \"0.1.0\", github: \"foo/bar\"}\n\n  Each registered SCM will be asked if they consume this dependency,\n  receiving `[github: \"foo/bar\"]` as argument. Since this option makes\n  sense for the Git SCM, it will return an update list of options\n  while other SCMs would simply return `nil`.\n  \"\"\"\n  @callback accepts_options(app :: atom, opts) :: opts | nil\n\n  @doc \"\"\"\n  This behaviour function returns a boolean if the\n  dependency is available.\n  \"\"\"\n  @callback checked_out?(opts) :: boolean\n\n  @doc \"\"\"\n  This behaviour function checks out dependencies.\n\n  If the dependency is locked, a lock is received in `opts`\n  and the repository must be check out at the lock. Otherwise,\n  no lock is given and the repository can be checked out\n  to the latest version.\n\n  It must return the current lock.\n  \"\"\"\n  @callback checkout(opts) :: any\n\n  @doc \"\"\"\n  This behaviour function updates dependencies. It may be\n  called by `deps.get` or `deps.update`.\n\n  In the first scenario, a lock is received in `opts` and\n  the repository must be updated to the lock. In the second,\n  no lock is given and the repository can be updated freely.\n\n  It must return the current lock.\n  \"\"\"\n  @callback update(opts) :: any\n\n  @doc \"\"\"\n  This behaviour function checks the status of the lock. In\n  particular, it checks if the revision stored in the lock\n  is the same as the repository it is currently in.\n\n  It may return:\n\n    * `:mismatch` - if the lock doesn't match and we need to\n      simply move to the latest lock\n\n    * `:outdated` - the repository options are outdated in the\n      lock and we need to trigger a full update\n\n    * `:ok` - everything is fine\n\n  The lock is sent via `opts[:lock]` but it may not always be\n  available. In such cases, if the SCM requires a lock, it must\n  return `:mismatch`, otherwise simply `:ok`.\n\n  Note the lock may also belong to another SCM and as such, an\n  structural check is required. A structural mismatch should always\n  return `:outdated`.\n  \"\"\"\n  @callback lock_status(opts) :: :mismatch | :outdated | :ok\n\n  @doc \"\"\"\n  Receives two options and must return `true` if they refer to the\n  same repository. The options are guaranteed to belong to the\n  same SCM.\n  \"\"\"\n  @callback equal?(opts1 :: opts, opts2 :: opts) :: boolean\n\n  @doc \"\"\"\n  Returns the usable managers for the dependency. This can be used\n  if the SCM has extra knowledge of the dependency, otherwise it\n  should return an empty list.\n  \"\"\"\n  @callback managers(opts) :: [atom]\n\n  @doc \"\"\"\n  Returns all available SCMs. Each SCM is tried in order\n  until a matching one is found.\n  \"\"\"\n  def available do\n    Mix.State.get(:scm)\n  end\n\n  @doc \"\"\"\n  Deletes the given SCM from the list of available SCMs.\n  \"\"\"\n  @doc since: \"1.16.2\"\n  def delete(mod) when is_atom(mod) do\n    Mix.State.update(:scm, &List.delete(&1, mod))\n  end\n\n  @doc \"\"\"\n  Prepends the given SCM module to the list of available SCMs.\n  \"\"\"\n  def prepend(mod) when is_atom(mod) do\n    Mix.State.update(:scm, &[mod | List.delete(&1, mod)])\n  end\n\n  @doc \"\"\"\n  Appends the given SCM module to the list of available SCMs.\n  \"\"\"\n  def append(mod) when is_atom(mod) do\n    Mix.State.update(:scm, &(List.delete(&1, mod) ++ [mod]))\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/shell/io.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Shell.IO do\n  @moduledoc \"\"\"\n  This is Mix's default shell.\n\n  It simply prints messages to stdio and stderr.\n  \"\"\"\n\n  @behaviour Mix.Shell\n\n  @typedoc \"\"\"\n  Options for `yes?/2`.\n  \"\"\"\n  @type yes_opts :: [default: :yes | :no]\n\n  @doc \"\"\"\n  Prints the current application to the shell if it\n  was not printed yet.\n  \"\"\"\n  def print_app do\n    if name = Mix.Shell.printable_app_name() do\n      IO.puts(\"==> #{name}\")\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  Prints the given ANSI message to the shell followed by a newline.\n  \"\"\"\n  def info(message) do\n    print_app()\n    IO.puts(IO.ANSI.format(message))\n  end\n\n  @doc \"\"\"\n  Prints the given ANSI error to the shell followed by a newline.\n  \"\"\"\n  def error(message) do\n    print_app()\n    IO.puts(:stderr, IO.ANSI.format(red(message)))\n  end\n\n  @doc \"\"\"\n  Prints a message and prompts the user for input.\n\n  Input will be consumed until Enter is pressed.\n  \"\"\"\n  def prompt(message) do\n    print_app()\n\n    case IO.gets(message <> \" \") do\n      {:error, _} -> raise \"Mix.shell().prompt/1 is not supported over this device\"\n      answer -> answer\n    end\n  end\n\n  @doc \"\"\"\n  Prints a message and asks the user to confirm if they\n  want to proceed. The user must type and submit one of\n  \"y\", \"yes\", \"Y\", \"YES\" or \"Yes\".\n\n  The user may also press Enter; this can be configured\n  to either accept or reject the prompt. The latter case\n  may be useful for a potentially dangerous operation that\n  should require explicit confirmation from the user.\n\n  If the default IO device is stderr, then it will default\n  to the default value.\n\n  ## Options\n\n    * `:default` - (:yes or :no) if `:yes` pressing Enter\n      accepts the prompt; if `:no` pressing Enter rejects\n      the prompt instead. Defaults to `:yes`.\n\n  ## Examples\n\n      if Mix.shell().yes?(\"Are you sure?\") do\n        # do something...\n      end\n\n  \"\"\"\n  @spec yes?(String.t(), yes_opts) :: boolean()\n  def yes?(message, options \\\\ []) do\n    default = Keyword.get(options, :default, :yes)\n\n    if default not in [:yes, :no] do\n      raise ArgumentError,\n            \"expected :default to be either :yes or :no, got: #{inspect(default)}\"\n    end\n\n    answers = [\"y\", \"Y\", \"yes\", \"YES\", \"Yes\"]\n\n    {prompt, accepted_answers} =\n      case default do\n        :yes -> {\" [Yn] \", [\"\" | answers]}\n        :no -> {\" [yN] \", answers}\n      end\n\n    print_app()\n\n    case IO.gets(message <> prompt) do\n      {:error, _} -> default == :yes\n      answer -> is_binary(answer) and String.trim(answer) in accepted_answers\n    end\n  end\n\n  defp red(message) do\n    [:red, :bright, message]\n  end\n\n  @doc \"\"\"\n  Executes the given command and prints its output\n  to stdout as it comes.\n  \"\"\"\n  def cmd(command, opts \\\\ []) do\n    print_app? = Keyword.get(opts, :print_app, true)\n\n    Mix.Shell.cmd(command, opts, fn data ->\n      if print_app?, do: print_app()\n      IO.write(data)\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/shell/process.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Shell.Process do\n  @moduledoc \"\"\"\n  Mix shell that uses the current process mailbox for communication.\n\n  This module provides a Mix shell implementation that uses\n  the current process mailbox for communication instead of IO.\n\n  As an example, when `Mix.shell().info(\"hello\")` is called,\n  the following message will be sent to the calling process:\n\n      {:mix_shell, :info, [\"hello\"]}\n\n  This is mainly useful in tests, allowing us to assert\n  if given messages were received or not instead of performing\n  checks on some captured IO. There is also a `flush/1` function\n  responsible for flushing all `:mix_shell` related messages\n  from the process inbox.\n\n  ## Examples\n\n  The first step is to set the Mix shell to this module:\n\n      Mix.shell(Mix.Shell.Process)\n\n  Then if your Mix task calls:\n\n      Mix.shell().info(\"hello\")\n\n  You should be able to receive it in your tests as long as\n  they run in the same process:\n\n      assert_receive {:mix_shell, :info, [msg]}\n      assert msg == \"hello\"\n\n  You can respond to prompts in tests as well:\n\n      send(self(), {:mix_shell_input, :prompt, \"Pretty cool\"})\n      Mix.shell().prompt(\"How cool was that?!\")\n      #=> \"Pretty cool\"\n\n  \"\"\"\n\n  @behaviour Mix.Shell\n\n  @doc \"\"\"\n  Flushes all `:mix_shell` and `:mix_shell_input` messages from the current process.\n\n  If a callback is given, it is invoked for each received message.\n\n  ## Examples\n\n      flush(&IO.inspect/1)\n\n  \"\"\"\n  def flush(callback \\\\ fn x -> x end) do\n    receive do\n      {:mix_shell, _, _} = message ->\n        callback.(message)\n        flush(callback)\n\n      {:mix_shell_input, _, _} = message ->\n        callback.(message)\n        flush(callback)\n    after\n      0 -> :done\n    end\n  end\n\n  @doc \"\"\"\n  Prints the current application if it\n  was not printed yet.\n  \"\"\"\n  def print_app do\n    if name = Mix.Shell.printable_app_name() do\n      send(message_target(), {:mix_shell, :info, [\"==> #{name}\"]})\n    end\n  end\n\n  @doc \"\"\"\n  Forwards the message to the current process.\n  \"\"\"\n  def info(message) do\n    print_app()\n    send(message_target(), {:mix_shell, :info, [format(message)]})\n    :ok\n  end\n\n  @doc \"\"\"\n  Forwards the error to the current process.\n  \"\"\"\n  def error(message) do\n    print_app()\n    send(message_target(), {:mix_shell, :error, [format(message)]})\n    :ok\n  end\n\n  defp format(message) do\n    message |> IO.ANSI.format(false) |> IO.iodata_to_binary()\n  end\n\n  @doc \"\"\"\n  Forwards the message to the current process.\n\n  It also checks the inbox for an input message matching:\n\n      {:mix_shell_input, :prompt, value}\n\n  If one does not exist, it will abort since there was no shell\n  process inputs given. `value` must be a string.\n\n  ## Examples\n\n  The following will answer with `\"Meg\"` to the prompt\n  `\"What's your name?\"`:\n\n      # The response is sent before calling prompt/1 so that prompt/1 can read it\n      send(self(), {:mix_shell_input, :prompt, \"Meg\"})\n      Mix.shell().prompt(\"What's your name?\")\n\n  \"\"\"\n  def prompt(message) do\n    print_app()\n    send(message_target(), {:mix_shell, :prompt, [message]})\n\n    receive do\n      {:mix_shell_input, :prompt, response} -> response\n    after\n      0 -> raise \"no shell process input given for prompt/1\"\n    end\n  end\n\n  @doc \"\"\"\n  Forwards the message to the current process.\n\n  It also checks the inbox for an input message matching:\n\n      {:mix_shell_input, :yes?, value}\n\n  If one does not exist, it will abort since there was no shell\n  process inputs given. `value` must be `true` or `false`.\n\n  ## Example\n\n      # Send the response to self() first so that yes?/2 will be able to read it\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.shell().yes?(\"Are you sure you want to continue?\")\n\n  \"\"\"\n  def yes?(message, _options \\\\ []) do\n    print_app()\n    send(message_target(), {:mix_shell, :yes?, [message]})\n\n    receive do\n      {:mix_shell_input, :yes?, response} -> response\n    after\n      0 -> raise \"no shell process input given for yes?/2\"\n    end\n  end\n\n  @doc \"\"\"\n  Executes the given command and forwards its messages to\n  the current process.\n  \"\"\"\n  def cmd(command, opts \\\\ []) do\n    print_app? = Keyword.get(opts, :print_app, true)\n\n    Mix.Shell.cmd(command, opts, fn data ->\n      if print_app?, do: print_app()\n      send(message_target(), {:mix_shell, :run, [data]})\n    end)\n  end\n\n  defp message_target() do\n    case Process.get(:\"$callers\") do\n      [parent | _] -> parent\n      _ -> self()\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/shell/quiet.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Shell.Quiet do\n  @moduledoc \"\"\"\n  This is Mix's default shell when the `MIX_QUIET` environment\n  variable is set.\n\n  It's just like `Mix.Shell.IO`, but prints far less.\n  \"\"\"\n\n  @behaviour Mix.Shell\n\n  @doc \"\"\"\n  Prints the current application if it\n  was not printed yet.\n  \"\"\"\n  defdelegate print_app, to: Mix.Shell.IO\n\n  @doc \"\"\"\n  Prints nothing to the shell.\n  \"\"\"\n  def info(_message), do: :ok\n\n  @doc \"\"\"\n  Prints the error to the shell followed by a newline.\n  \"\"\"\n  defdelegate error(message), to: Mix.Shell.IO\n\n  @doc \"\"\"\n  Prints a message and prompts the user for input.\n\n  Input will be consumed until Enter is pressed.\n  \"\"\"\n  defdelegate prompt(message), to: Mix.Shell.IO\n\n  @doc \"\"\"\n  Prints a message and asks the user to confirm if they\n  want to proceed. The user must type and submit one of\n  \"y\", \"yes\", \"Y\", \"YES\" or \"Yes\".\n\n  The user may also press Enter; this can be configured\n  to either accept or reject the prompt. The latter case\n  may be useful for a potentially dangerous operation that\n  should require explicit confirmation from the user.\n\n  ## Options\n\n    * `:default` - (:yes or :no) if `:yes` pressing Enter\n      accepts the prompt; if `:no` pressing Enter rejects\n      the prompt instead. Defaults to `:yes`.\n\n  \"\"\"\n  @spec yes?(String.t(), Mix.Shell.IO.yes_opts()) :: boolean()\n  defdelegate yes?(message, options \\\\ []), to: Mix.Shell.IO\n\n  @doc \"\"\"\n  Executes the given command quietly without outputting anything.\n  \"\"\"\n  @spec cmd(String.t() | {String.t(), [String.t()]}, Mix.Shell.stream_cmd_opts()) ::\n          exit_status :: non_neg_integer\n  def cmd(command, opts \\\\ []) do\n    Mix.Shell.cmd(command, opts, fn data -> data end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/shell.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Shell do\n  @moduledoc \"\"\"\n  Defines `Mix.Shell` contract.\n  \"\"\"\n\n  @type cmd_opts :: [\n          {:print_app, boolean()}\n          | {:stderr_to_stdout, boolean()}\n          | {:quiet, boolean()}\n          | {:env, [{String.t(), String.t()}]}\n          | {:cd, String.t()}\n          | {atom(), term()}\n        ]\n\n  @type yes_opts :: [\n          {:default, :yes | :no}\n          | {atom(), term()}\n        ]\n\n  @type stream_cmd_opts :: [\n          {:cd, String.t()}\n          | {:stderr_to_stdout, boolean()}\n          | {:use_stdio, boolean()}\n          | {:env, [{String.t(), String.t()}]}\n          | {:quiet, boolean()}\n          | {atom(), term()}\n        ]\n\n  @doc false\n  defstruct [:callback]\n\n  @doc \"\"\"\n  Prints the given ANSI message to the shell.\n  \"\"\"\n  @callback info(message :: IO.ANSI.ansidata()) :: :ok\n\n  @doc \"\"\"\n  Prints the given ANSI error to the shell.\n  \"\"\"\n  @callback error(message :: IO.ANSI.ansidata()) :: :ok\n\n  @doc \"\"\"\n  Executes the given command and returns its exit status.\n\n  Shortcut for `c:cmd/2` with empty options.\n  \"\"\"\n  @callback cmd(command :: String.t()) :: integer\n\n  @doc \"\"\"\n  Executes the given command and returns its exit status.\n\n  ## Options\n\n  This callback should support the following options:\n\n    * `:print_app` - when `false`, does not print the app name\n      when the command outputs something\n\n    * `:stderr_to_stdout` - when `false`, does not redirect\n      stderr to stdout\n\n    * `:quiet` - when `true`, do not print the command output\n\n    * `:env` - environment options to the executed command\n\n    * `:cd` *(since v1.11.0)* - the directory to run the command in\n\n  All the built-in shells support these.\n  \"\"\"\n  @callback cmd(command :: String.t(), options :: cmd_opts) :: integer\n\n  @doc \"\"\"\n  Prompts the user for input.\n  \"\"\"\n  @callback prompt(message :: binary) :: binary\n\n  @doc \"\"\"\n  Prompts the user for confirmation.\n\n  Shortcut for `yes?/2` with empty options.\n  \"\"\"\n  @callback yes?(message :: binary) :: boolean\n\n  @doc \"\"\"\n  Prompts the user for confirmation.\n\n  ## Options\n\n    * `:default` - `:yes` or `:no` (the default is `:yes`)\n  \"\"\"\n  @callback yes?(message :: binary, options :: yes_opts) :: boolean\n\n  @doc \"\"\"\n  Prints the current application to the shell if\n  it was not printed yet.\n  \"\"\"\n  @callback print_app() :: :ok\n\n  @doc \"\"\"\n  Returns the printable app name.\n\n  This function returns the current application name,\n  but only if the application name should be printed.\n\n  Calling this function automatically toggles its value\n  to `false` until the current project is re-entered. The\n  goal is to avoid printing the application name\n  multiple times.\n  \"\"\"\n  @spec printable_app_name() :: atom | nil\n  def printable_app_name do\n    Mix.ProjectStack.printable_app_name()\n  end\n\n  @doc \"\"\"\n  Executes the given `command` and invokes the `callback` for the streamed response.\n\n  `command` is either a string, to be executed as a `System.shell/2` command,\n  or a `{executable, args}` to be executed via `System.cmd/3`.\n\n  `callback` takes the output data of the command. Its return value is ignored.\n\n  This function is most commonly used by `Mix.Shell` implementations but can\n  also be invoked directly.\n\n  ## Options\n\n    * `:cd` *(since v1.11.0)* - the directory to run the command in\n\n    * `:stderr_to_stdout` - redirects stderr to stdout, defaults to `true`, unless `:use_stdio` is set to `false`\n\n    * `:use_stdio` - controls whether the command should use `stdin` / `stdout` / `stderr`, defaults to `true`\n\n    * `:env` - a list of environment variables, defaults to `[]`\n\n    * `:quiet` - overrides the callback to no-op\n\n  \"\"\"\n  @spec cmd(String.t() | {String.t(), [String.t()]}, stream_cmd_opts, (binary -> term)) ::\n          exit_status :: non_neg_integer\n  def cmd(command, options \\\\ [], callback) when is_function(callback, 1) do\n    callback =\n      if options[:quiet] do\n        fn x -> x end\n      else\n        callback\n      end\n\n    use_stdio = Keyword.get(options, :use_stdio, true)\n\n    options =\n      options\n      |> Keyword.take([:cd, :stderr_to_stdout, :env, :use_stdio])\n      |> Keyword.put(:into, %Mix.Shell{callback: callback})\n      |> Keyword.put_new(:stderr_to_stdout, use_stdio)\n\n    {_, status} =\n      case command do\n        {command, args} -> System.cmd(command, args, options)\n        command when is_binary(command) -> System.shell(command, options)\n      end\n\n    status\n  end\n\n  defimpl Collectable do\n    def into(%Mix.Shell{callback: fun}) do\n      {:ok,\n       fn\n         _, {:cont, data} -> fun.(data)\n         _, _ -> :ok\n       end}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/state.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.State do\n  @moduledoc false\n  @name __MODULE__\n  @timeout :infinity\n\n  use GenServer\n\n  def start_link(_opts) do\n    GenServer.start_link(__MODULE__, :ok, name: @name)\n  end\n\n  def builtin_apps do\n    GenServer.call(@name, :builtin_apps, @timeout)\n  end\n\n  ## ETS state storage (mutable, not cleared in tests)\n\n  def fetch(key) do\n    case :ets.lookup(@name, key) do\n      [{^key, value}] -> {:ok, value}\n      [] -> :error\n    end\n  end\n\n  def get(key, default \\\\ nil) do\n    case :ets.lookup(@name, key) do\n      [{^key, value}] -> value\n      [] -> default\n    end\n  end\n\n  def put(key, value) do\n    :ets.insert(@name, {key, value})\n    :ok\n  end\n\n  def update(key, fun) do\n    :ets.insert(@name, {key, fun.(:ets.lookup_element(@name, key, 2))})\n    :ok\n  end\n\n  ## Persistent term cache (persistent, cleared in tests)\n\n  def read_cache(key, default \\\\ nil) do\n    :persistent_term.get({__MODULE__, key}, default)\n  end\n\n  def write_cache(key, value) do\n    :persistent_term.put({__MODULE__, key}, value)\n    value\n  end\n\n  def delete_cache(key) do\n    :persistent_term.erase({__MODULE__, key})\n  end\n\n  def clear_cache do\n    for {{__MODULE__, _} = key, _value} <- :persistent_term.get() do\n      :persistent_term.erase(key)\n    end\n  end\n\n  ## Callbacks\n\n  @impl true\n  def init(:ok) do\n    table = :ets.new(@name, [:public, :set, :named_table, read_concurrency: true])\n\n    :ets.insert(table,\n      shell: Mix.Shell.IO,\n      env: from_env(\"MIX_ENV\", :dev),\n      target: from_env(\"MIX_TARGET\", :host),\n      scm: [Mix.SCM.Git, Mix.SCM.Path]\n    )\n\n    state = %{\n      builtin_apps: :code.get_path()\n    }\n\n    {:ok, state}\n  end\n\n  defp from_env(varname, default) do\n    case System.get_env(varname) do\n      nil -> default\n      \"\" -> default\n      value -> String.to_atom(value)\n    end\n  end\n\n  @impl true\n  def handle_call(:builtin_apps, _from, %{builtin_apps: builtin_apps} = state) do\n    if is_map(builtin_apps) do\n      {:reply, builtin_apps, state}\n    else\n      builtin_apps =\n        for path <- builtin_apps,\n            app = app_from_code_path(path),\n            do: {app, path},\n            into: %{}\n\n      {:reply, builtin_apps, %{state | builtin_apps: builtin_apps}}\n    end\n  end\n\n  # ../elixir/ebin -> elixir\n  # ../ssl-9.6/ebin -> ssl\n  defp app_from_code_path(path) do\n    case path |> Enum.reverse() |> discard_ebin() |> collect_dir([]) do\n      [] -> nil\n      app -> List.to_atom(app)\n    end\n  end\n\n  defp discard_ebin(~c\"nibe/\" ++ path), do: path\n  defp discard_ebin(~c\"nibe\\\\\" ++ path), do: path\n  defp discard_ebin(_), do: []\n\n  defp collect_dir([?\\\\ | _], acc), do: acc\n  defp collect_dir([?/ | _], acc), do: acc\n  defp collect_dir([?- | path], _acc), do: collect_dir(path, [])\n  defp collect_dir([head | path], acc), do: collect_dir(path, [head | acc])\n  defp collect_dir([], acc), do: acc\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/sync/lock.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Mix.Sync.Lock do\n  @moduledoc false\n\n  # Lock implementation working across multiple OS processes.\n  #\n  # The lock is implemented using TCP sockets and hard links.\n  #\n  # A process holds the lock if it owns a TCP socket, whose port is\n  # written in the lock_0 file. We need to create such lock files\n  # atomically, so the process first writes its port to a port_P\n  # file and then attempts to create a hard link to it at lock_0.\n  #\n  # An inherent problem with lock files is that the lock owner may\n  # terminate abruptly, leaving a \"stale\" file. Other processes can\n  # detect a stale file by reading the port written in that file,\n  # trying to connect to that port and failing. In order for another\n  # process to link to the same path, the file needs to be replaced.\n  # However, we need to guarantee that only a single process can\n  # remove or replace the file, otherwise a concurrent process may\n  # end up removing a newly linked file.\n  #\n  # To address this problem we employ a chained locking procedure.\n  # Specifically, we attempt to link our port to lock_0, if that\n  # fails, we try to connect to the lock_0 port. If we manage to\n  # connect, it means the lock is taken, so we wait for it to close\n  # and start over. If we fail to connect, it means the lock is stale,\n  # so we want to replace it. In order to do that, we try to obtain\n  # lock_1. Again, we try to link and connect. Eventually, we should\n  # successfully link to lock_N. At that point we can clean up all\n  # the files, so we perform these steps:\n  #\n  #   * replace lock_0 content with port P\n  #   * remove all port_P files\n  #   * remove all lock_1+ files\n  #\n  # It is important to perform these steps in this order, to avoid\n  # race conditions. By moving to lock_0, we make sure that all new\n  # processes trying to lock will connect to our port. By removing\n  # all port_P files we make sure that currently paused processes\n  # that are about to link port_P at lock_N will fail to link, since\n  # the port_P file will no longer exist (once lock_N is removed).\n  #\n  # Finally, note that we do not remove the lock file in `unlock/1`.\n  # If we did that, another process could read it before removal,\n  # then it may connect and fail (once the socket is closed), in such\n  # case the process would assume the file is stale and needs to be\n  # replaced, therefore possibly replacing another process who\n  # successfully links at the empty spot. This means we effectively\n  # always leave a stale file, however, in order to shortcut the port\n  # check for future processes, we atomically replace the file content\n  # with port 0, to indicate the file is stale.\n  #\n  # The main caveat of using ephemeral TCP ports is that they are not\n  # unique. This creates a theoretical scenario where the lock holder\n  # terminates abruptly and leaves its port in lock_0, then the port\n  # is assigned to a unrelated process (unaware of the locking). To\n  # handle this scenario, when we connect to a lock_N port, we expect\n  # it to immediately send us `@probe_data`. If this does not happen\n  # within `@probe_timeout_ms`, we assume the port is taken by an\n  # unrelated process and the lock file is stale. Note that it is ok\n  # to use a long timeout, because this scenario is very unlikely.\n  # Theoretically, if an actual lock owner is not able to send the\n  # probe data within the timeout, the lock will fail, however with\n  # a high enough timeout, this should not be a problem in practice.\n\n  @loopback {127, 0, 0, 1}\n  @listen_opts [:binary, ip: @loopback, packet: :raw, nodelay: true, backlog: 128, active: false]\n  @connect_opts [:binary, packet: :raw, nodelay: true, active: false]\n  @probe_data \"mixlock\"\n  @probe_data_size byte_size(@probe_data)\n  @probe_timeout_ms 5_000\n\n  @typedoc \"\"\"\n  Options for `with_lock/3`.\n  \"\"\"\n  @type with_lock_opts :: [\n          on_taken: (String.t() -> any())\n        ]\n\n  @doc \"\"\"\n  Acquires a lock identified by the given key.\n\n  This function blocks until the lock is acquired by this process,\n  and then executes `fun`, returning its return value.\n\n  This function can also be called if this process already has the\n  lock. In such case the function is executed immediately.\n\n  When the `MIX_OS_CONCURRENCY_LOCK` environment variable is set to\n  a falsy value, the lock is ignored and the function is executed\n  immediately.\n\n  ## Options\n\n    * `:on_taken` - a one-arity function called if the lock is held\n      by a different process. The operating system PID of that process\n      is given as the first argument (as a string). This function may\n      be called multiple times, if the lock owner changes, until it\n      is successfully acquired by this process.\n\n  \"\"\"\n  @spec with_lock(iodata(), (-> term()), with_lock_opts()) :: term()\n  def with_lock(key, fun, opts \\\\ []) do\n    opts = Keyword.validate!(opts, [:on_taken])\n\n    hash = key |> :erlang.md5() |> Base.url_encode64(padding: false)\n    path = Path.join(base_path(), hash)\n\n    pdict_key = {__MODULE__, path}\n    has_lock? = Process.get(pdict_key, false)\n\n    if has_lock? or lock_disabled?() do\n      fun.()\n    else\n      lock = lock(path, opts[:on_taken])\n      Process.put(pdict_key, true)\n\n      try do\n        fun.()\n      after\n        # Unlocking will always close the socket, but it may raise,\n        # so we remove key from the dictionary first\n        Process.delete(pdict_key)\n        unlock(lock)\n      end\n    end\n  end\n\n  defp base_path do\n    # We include user in the dir to avoid permission conflicts across users\n    Path.join(System.tmp_dir!(), \"mix_lock_user#{Mix.Utils.detect_user_id!()}\")\n  end\n\n  defp lock_disabled?(), do: System.get_env(\"MIX_OS_CONCURRENCY_LOCK\") in ~w(0 false)\n\n  defp lock(path, on_taken) do\n    File.mkdir_p!(path)\n\n    case listen() do\n      {:ok, socket, port} ->\n        spawn_link(fn -> accept_loop(socket) end)\n\n        try do\n          try_lock(path, socket, port, on_taken)\n        rescue\n          exception ->\n            # Close the socket to make sure we don't block the lock\n            :gen_tcp.close(socket)\n            reraise exception, __STACKTRACE__\n        end\n\n      {:error, reason} ->\n        Mix.raise(\"failed to acquire filesystem lock using TCP, reason: #{inspect(reason)}\")\n    end\n  end\n\n  defp listen do\n    with {:ok, socket} <- :gen_tcp.listen(0, @listen_opts) do\n      case :inet.port(socket) do\n        {:ok, port} ->\n          {:ok, socket, port}\n\n        {:error, reason} ->\n          :gen_tcp.close(socket)\n          {:error, reason}\n      end\n    end\n  end\n\n  defp try_lock(path, socket, port, on_taken) do\n    port_path = Path.join(path, \"port_#{port}\")\n    os_pid = System.pid()\n\n    switch_file_create!(port_path, encode_lock_info(port, os_pid))\n\n    case grab_lock(path, port_path, 0) do\n      {:ok, 0} ->\n        # We grabbed lock_0, so all good\n        %{socket: socket, path: path}\n\n      {:ok, _n} ->\n        # We grabbed lock_1+, so we need to replace lock_0 and clean up\n        take_over(path, port, os_pid)\n        %{socket: socket, path: path}\n\n      {:taken, probe_socket, os_pid} ->\n        # Another process has the lock, wait for close and start over\n        if on_taken, do: on_taken.(os_pid)\n        await_close(probe_socket)\n        try_lock(path, socket, port, on_taken)\n\n      :invalidated ->\n        try_lock(path, socket, port, on_taken)\n    end\n  end\n\n  defp grab_lock(path, port_path, n) do\n    lock_path = Path.join(path, \"lock_#{n}\")\n\n    case File.ln(port_path, lock_path) do\n      :ok ->\n        {:ok, n}\n\n      {:error, :eexist} ->\n        case probe(lock_path) do\n          {:ok, probe_socket, os_pid} ->\n            {:taken, probe_socket, os_pid}\n\n          {:error, _reason} ->\n            grab_lock(path, port_path, n + 1)\n        end\n\n      {:error, :enoent} ->\n        :invalidated\n\n      {:error, reason} ->\n        Mix.raise(\"\"\"\n        could not create hard link from #{port_path} to \"#{lock_path}: #{:file.format_error(reason)}.\n\n        Hard link support is required for Mix compilation locking. If your system \\\n        does not support hard links, set MIX_OS_CONCURRENCY_LOCK=0\\\n        \"\"\")\n    end\n  end\n\n  defp accept_loop(listen_socket) do\n    case accept(listen_socket) do\n      {:ok, socket} ->\n        _ = :gen_tcp.send(socket, @probe_data)\n        accept_loop(listen_socket)\n\n      {:error, reason} when reason in [:closed, :einval] ->\n        :ok\n\n      {:error, reason} ->\n        raise RuntimeError,\n              \"failed to accept connection in #{inspect(__MODULE__)}.receive_event/1, reason: #{inspect(reason)}\"\n    end\n  end\n\n  defp probe(port_path) do\n    with {:ok, port, os_pid} <- fetch_probe_port(port_path),\n         {:ok, socket} <- connect(port),\n         {:ok, socket} <- await_probe_data(socket) do\n      {:ok, socket, os_pid}\n    end\n  end\n\n  defp fetch_probe_port(port_path) do\n    case switch_file_read(port_path) do\n      {:ok, data} ->\n        case decode_lock_info(data) do\n          {0, _os_pid} -> {:error, :ignore}\n          {port, os_pid} -> {:ok, port, os_pid}\n        end\n\n      {:error, reason} ->\n        {:error, reason}\n    end\n  end\n\n  defp connect(port) do\n    # On Windows connecting to an unbound port takes a few seconds to\n    # fail, so instead we shortcut the check by attempting a listen,\n    # which succeeds or fails immediately. Note that `reuseaddr` here\n    # ensures that if the listening socket closed recently, we can\n    # immediately reclaim the same port.\n    case :gen_tcp.listen(port, [reuseaddr: true] ++ @listen_opts) do\n      {:ok, socket} ->\n        :gen_tcp.close(socket)\n        # The port is free, so connecting would fail\n        {:error, :econnrefused}\n\n      {:error, _reason} ->\n        :gen_tcp.connect(@loopback, port, @connect_opts)\n    end\n  end\n\n  defp await_probe_data(socket) do\n    case recv(socket, @probe_data_size, @probe_timeout_ms) do\n      {:ok, @probe_data} ->\n        {:ok, socket}\n\n      {:ok, _data} ->\n        :gen_tcp.close(socket)\n        {:error, :unexpected_port_owner}\n\n      {:error, reason} ->\n        :gen_tcp.close(socket)\n        {:error, reason}\n    end\n  end\n\n  defp recv(socket, size, timeout \\\\ :infinity) do\n    # eintr is \"Interrupted system call\".\n    with {:error, :eintr} <- :gen_tcp.recv(socket, size, timeout) do\n      recv(socket, size, timeout)\n    end\n  end\n\n  defp accept(socket) do\n    with {:error, :eintr} <- :gen_tcp.accept(socket) do\n      accept(socket)\n    end\n  end\n\n  defp take_over(path, port, os_pid) do\n    # The operations here must happen in precise order, so if anything\n    # fails, we keep the files as is and the next process that grabs\n    # the lock will do the cleanup\n\n    lock_path = Path.join(path, \"lock_0\")\n\n    switch_file_replace!(lock_path, encode_lock_info(port, os_pid))\n\n    names = File.ls!(path)\n\n    # On Windows, removing a file may fail if the file is open, so we\n    # ignore failures just to be safe\n\n    for \"port_\" <> _ = name <- names do\n      _ = File.rm(Path.join(path, name))\n    end\n\n    for \"lock_\" <> _ = name <- names, name != \"lock_0\" do\n      _ = File.rm(Path.join(path, name))\n    end\n  end\n\n  defp await_close(socket) do\n    case recv(socket, 0) do\n      {:error, :closed} ->\n        :ok\n\n      {:error, _other} ->\n        # In case of an unexpected error, we close the socket ourselves\n        # to retry\n        :gen_tcp.close(socket)\n    end\n  end\n\n  defp unlock(lock) do\n    lock_path = Path.join(lock.path, \"lock_0\")\n\n    switch_file_replace!(lock_path, encode_lock_info(0, \"\"))\n  after\n    # Closing the socket will cause the accepting process to finish\n    # and all accepted sockets (tied to that process) will get closed\n    :gen_tcp.close(lock.socket)\n  end\n\n  defp encode_lock_info(port, os_pid) do\n    os_pid_size = byte_size(os_pid)\n\n    if os_pid_size > 32 do\n      Mix.raise(\"unexpectedly long PID: #{inspect(os_pid)}\")\n    end\n\n    # The info needs to have fixed size, so we pad os_pid to maximum\n    # of 32 bytes (we expect it to be a few bytes).\n    padding_size = 32 - os_pid_size\n    padding = :binary.copy(<<0>>, padding_size)\n\n    <<\n      port::unsigned-integer-32,\n      padding_size::unsigned-integer-8,\n      padding::binary,\n      os_pid::binary\n    >>\n  end\n\n  defp decode_lock_info(data) do\n    <<\n      port::unsigned-integer-32,\n      padding_size::unsigned-integer-8,\n      _padding::binary-size(padding_size),\n      os_pid::binary\n    >> = data\n\n    {port, os_pid}\n  end\n\n  # We need a mechanism to atomically replace file content. Typically,\n  # we could use File.rename/2 to do that, however File.rename/2 is\n  # not atomic on Windows, if the destination exists [1].\n  #\n  # As an alternative approach we use a switch-file. The file content\n  # consists of 1 switch byte (either 0 or 1) and two content segments\n  # with fixed, equal lengths. The switch byte indicates which segment\n  # is currently active. To replace the file content, we write to the\n  # non-active segment and call :file.sync/1 to ensure the segment is\n  # persisted, then we toggle the switch byte. While we cannot write\n  # multiple bytes atomically (since they may reside in multiple disk\n  # sectors), if we toggle only a single byte, there is no intermediate\n  # invalid state, which gives us the atomic replace we need.\n  #\n  # Note that file content can be replaced only by a single process\n  # at a time.\n  #\n  # [1]: https://github.com/elixir-lang/elixir/pull/14793#issuecomment-3338665065\n  defp switch_file_create!(path, content) do\n    data = <<0, content::binary, content::binary>>\n    File.write!(path, data, [:raw])\n  end\n\n  defp switch_file_replace!(path, new_content) do\n    file = File.open!(path, [:read, :write, :binary, :raw])\n\n    content_size = byte_size(new_content)\n\n    <<switch_byte>> = read_bytes!(file, 1)\n\n    try do\n      inactive_content_position =\n        case switch_byte do\n          0 -> 1 + content_size\n          1 -> 1\n        end\n\n      # Write new data\n      file_pwrite_sync!(file, inactive_content_position, new_content)\n\n      # Toggle switch byte - it's a single byte so the content changes\n      # atomically\n      file_pwrite_sync!(file, 0, <<1 - switch_byte>>)\n    after\n      File.close(file)\n    end\n  end\n\n  defp switch_file_read(path) do\n    with {:ok, data} <- File.read(path) do\n      <<switch_byte, rest::binary>> = data\n      content_size = rest |> byte_size() |> div(2)\n      <<content1::binary-size(^content_size), content2::binary-size(^content_size)>> = rest\n\n      case switch_byte do\n        0 -> {:ok, content1}\n        1 -> {:ok, content2}\n      end\n    end\n  end\n\n  defp read_bytes!(file, bytes) do\n    case :file.read(file, bytes) do\n      {:ok, data} ->\n        data\n\n      :eof ->\n        raise \"unexpected EOF of file when reading file\"\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"read file\"\n    end\n  end\n\n  defp file_pwrite_sync!(file, position, bytes) do\n    case :file.pwrite(file, position, bytes) do\n      :ok ->\n        case :file.sync(file) do\n          :ok ->\n            :ok\n\n          {:error, reason} ->\n            raise File.Error, reason: reason, action: \"sync file\"\n        end\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"write to file at position\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/sync/pubsub.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Mix.Sync.PubSub do\n  @moduledoc false\n\n  # Pub/sub implementation working across multiple OS processes.\n  #\n  # The pub/sub is implemented using TCP sockets.\n  #\n  # Every subscriber opens a TCP socket and creates a port_P file.\n  # A publisher lists the directory, connects to each port and sends\n  # the message payload. When subscriber processes terminate, the\n  # files are left behind, so whenever a publisher fails to connect\n  # to one of the ports, it removes the corresponding file.\n  #\n  # We use a single socket for all the subscriptions. We create the\n  # socket lazily on the first subscription. Since the socket is\n  # shared, we include the hashed key in the broadcast payload, so\n  # that we can determine which subscribers to notify.\n\n  use GenServer\n\n  @opaque subscription :: %{socket: :gen_tcp.socket()}\n\n  @loopback {127, 0, 0, 1}\n  @listen_opts [:binary, ip: @loopback, packet: :raw, nodelay: true, backlog: 128, active: false]\n  @connect_opts [:binary, packet: :raw, nodelay: true, active: false]\n\n  @tag_data \"mixpubsub\"\n  @tag_data_size byte_size(@tag_data)\n\n  @name __MODULE__\n\n  @doc false\n  def start_link(_opts) do\n    GenServer.start_link(__MODULE__, {}, name: @name)\n  end\n\n  @doc \"\"\"\n  Subscribes the caller to messages for `key`.\n\n  The messages are delivered to the caller's message queue.\n  \"\"\"\n  @spec subscribe(String.t()) :: :ok | {:error, String.t()}\n  def subscribe(key) do\n    GenServer.call(@name, {:subscribe, self(), key}, :infinity)\n  end\n\n  @doc \"\"\"\n  Sends `message` to all processes subscribed to `key`.\n  \"\"\"\n  @spec broadcast(String.t(), term() | (-> term())) :: :ok\n  def broadcast(key, message) do\n    hash = hash(key)\n    path = path(hash)\n\n    case File.ls(path) do\n      {:ok, []} ->\n        :ok\n\n      {:ok, names} ->\n        message =\n          case message do\n            lazy_message when is_function(lazy_message, 0) -> lazy_message.()\n            message -> message\n          end\n\n        binary = :erlang.term_to_binary(message)\n\n        for \"port_\" <> port = name <- names do\n          port = String.to_integer(port)\n          port_path = Path.join(path, name)\n          _ = send_message(port_path, port, hash, binary)\n        end\n\n        :ok\n\n      {:error, :enoent} ->\n        :ok\n\n      {:error, reason} ->\n        raise File.Error, reason: reason, action: \"list directory\", path: path\n    end\n  end\n\n  defp send_message(port_path, port, hash, binary) do\n    # On Windows connecting to an unbound port takes a few seconds to\n    # fail, so instead we shortcut the check by attempting a listen,\n    # which succeeds or fails immediately. Note that `reuseaddr` here\n    # ensures that if the listening socket closed recently, we can\n    # immediately reclaim the same port.\n    #\n    # Also, if we manage to bind, it means the port is free and the\n    # subscription is no longer active, so we remove the file. It is\n    # important we remove the file while holding onto the port, so\n    # it is not claimed by a new subscriber as we remove the file.\n    #\n    # Finally, if we fail to connect, we could attempt to bind again\n    # and remove the file, but we just leave it up to the next send\n    # attempt.\n\n    case :gen_tcp.listen(port, [reuseaddr: true] ++ @listen_opts) do\n      {:ok, socket} ->\n        _ = File.rm(port_path)\n        :gen_tcp.close(socket)\n        {:error, :econnrefused}\n\n      {:error, _reason} ->\n        with {:ok, socket} <- :gen_tcp.connect(@loopback, port, @connect_opts) do\n          size = byte_size(binary)\n\n          result =\n            :gen_tcp.send(\n              socket,\n              <<@tag_data, hash::binary, size::unsigned-integer-64, binary::binary>>\n            )\n\n          :gen_tcp.shutdown(socket, :read_write)\n          :gen_tcp.close(socket)\n\n          result\n        end\n    end\n  end\n\n  @impl true\n  def init({}) do\n    state = %{port: nil, hash_to_pids: %{}}\n    {:ok, state}\n  end\n\n  @impl true\n  def handle_call({:subscribe, pid, key}, _from, state) do\n    Process.monitor(pid)\n\n    case ensure_socket(state) do\n      {:ok, state} ->\n        hash = hash(key)\n        path = path(hash)\n\n        create_subscription_file(path, state.port)\n\n        state =\n          update_in(state.hash_to_pids, fn\n            %{^hash => pids} = hash_to_pids ->\n              %{hash_to_pids | hash => MapSet.put(pids, pid)}\n\n            %{} = hash_to_pids ->\n              Map.put(hash_to_pids, hash, MapSet.new([pid]))\n          end)\n\n        {:reply, :ok, state}\n\n      {:error, error} ->\n        {:reply, {:error, error}, state}\n    end\n  end\n\n  @impl true\n  def handle_info({:message, hash, message}, state) do\n    if pids = state.hash_to_pids[hash] do\n      for pid <- pids do\n        send(pid, message)\n      end\n    end\n\n    {:noreply, state}\n  end\n\n  def handle_info({:DOWN, _, :process, pid, _}, state) do\n    hash_to_pids =\n      for {hash, pids} <- state.hash_to_pids,\n          pids = remove_pid(pids, pid, hash, state.port),\n          into: %{},\n          do: {hash, pids}\n\n    {:noreply, %{state | hash_to_pids: hash_to_pids}}\n  end\n\n  defp remove_pid(pids, pid, hash, port) do\n    pids = MapSet.delete(pids, pid)\n\n    if Enum.empty?(pids) do\n      path = path(hash)\n      remove_subscription_file(path, port)\n      nil\n    else\n      pids\n    end\n  end\n\n  defp ensure_socket(%{port: nil} = state) do\n    case listen() do\n      {:ok, socket, port} ->\n        parent = self()\n        spawn_link(fn -> receive_message_loop(socket, parent) end)\n        {:ok, %{state | port: port}}\n\n      {:error, reason} ->\n        {:error, \"failed to subscribe to Mix events using TCP, reason: #{inspect(reason)}\"}\n    end\n  end\n\n  defp ensure_socket(state), do: {:ok, state}\n\n  defp listen do\n    with {:ok, socket} <- :gen_tcp.listen(0, @listen_opts) do\n      case :inet.port(socket) do\n        {:ok, port} ->\n          {:ok, socket, port}\n\n        {:error, reason} ->\n          :gen_tcp.close(socket)\n          {:error, reason}\n      end\n    end\n  end\n\n  defp create_subscription_file(path, port) do\n    File.mkdir_p!(path)\n    port_path = Path.join(path, \"port_#{port}\")\n    File.touch!(port_path)\n  end\n\n  defp remove_subscription_file(path, port) do\n    port_path = Path.join(path, \"port_#{port}\")\n    _ = File.rm(port_path)\n  end\n\n  defp receive_message_loop(socket, parent) do\n    {hash, message} = receive_message(socket)\n    send(parent, {:message, hash, message})\n    receive_message_loop(socket, parent)\n  end\n\n  defp receive_message(listen_socket) do\n    # Note that receive failures may happen if the sender terminates\n    # abruptly. We ignore such attempts and wait for the next message.\n    #\n    # Also, the first recv has a timeout in case an unrelated process\n    # connects to the port and doesn't send any data.\n\n    case accept(listen_socket) do\n      {:ok, socket} ->\n        with {:ok, <<@tag_data, hash::binary-size(16), size::unsigned-integer-64>>} <-\n               recv(socket, @tag_data_size + 16 + 8, 1_000),\n             {:ok, binary} <- recv(socket, size),\n             {:ok, data} <- decode_data(binary) do\n          :gen_tcp.close(socket)\n          {hash, data}\n        else\n          _other ->\n            :gen_tcp.close(socket)\n            receive_message(listen_socket)\n        end\n\n      {:error, reason} ->\n        raise RuntimeError,\n              \"failed to accept connection in #{inspect(__MODULE__)}.receive_message/1, reason: #{inspect(reason)}\"\n    end\n  end\n\n  defp decode_data(binary) do\n    try do\n      {:ok, :erlang.binary_to_term(binary)}\n    rescue\n      _error -> :error\n    end\n  end\n\n  defp hash(key), do: :erlang.md5(key)\n\n  defp path(hash) do\n    hash = Base.url_encode64(hash, padding: false)\n    Path.join(base_path(), hash)\n  end\n\n  defp base_path do\n    # We include user in the dir to avoid permission conflicts across users\n    Path.join(System.tmp_dir!(), \"mix_pubsub_user#{Mix.Utils.detect_user_id!()}\")\n  end\n\n  defp recv(socket, size, timeout \\\\ :infinity) do\n    # eintr is \"Interrupted system call\".\n    with {:error, :eintr} <- :gen_tcp.recv(socket, size, timeout) do\n      recv(socket, size)\n    end\n  end\n\n  defp accept(socket) do\n    with {:error, :eintr} <- :gen_tcp.accept(socket) do\n      accept(socket)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/task.compiler.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Task.Compiler do\n  @moduledoc \"\"\"\n  This module defines the behaviour for a Mix task that does compilation.\n\n  A Mix compiler task can be defined by simply using `Mix.Task.Compiler`\n  in a module whose name starts with `Mix.Tasks.Compile.` and defining\n  the [`run/1`](`c:run/1`) function:\n\n      defmodule Mix.Tasks.Compile.MyLanguage do\n        use Mix.Task.Compiler\n\n        def run(_args) do\n          :ok\n        end\n      end\n\n  The [`run/1`](`c:run/1`) function returns an atom indicating the status of the\n  compilation, and optionally can also return a list of \"diagnostics\"\n  such as warnings or compilation errors. Doing this enables code\n  editors to display issues inline without having to analyze the\n  command-line output.\n\n  If the compiler uses manifest files to track stale sources, it should\n  define `manifests/0`, and if it writes any output to disk it should\n  also define `clean/0`.\n\n  A compiler supports the same attributes for configuration and\n  documentation as a regular Mix task. See `Mix.Task` for more information.\n\n  ## Listening to compilation\n\n  When running a long-lived Mix task you may want to detect compilations\n  triggered in a separate OS process, for example, to reload the modules.\n  In order to do that, the Mix project may configure listeners:\n\n      def project do\n        [\n          ...,\n          listeners: [SomeDep.MixListener]\n        ]\n      end\n\n  or\n\n      config :mix, :listeners, [SomeDep.MixListener]\n\n  Each entry in the list must be either `t:Supervisor.module_spec/0` or\n  `t:Supervisor.child_spec/0`. Additionally, the listener module must\n  be defined in a dependency of the project, not the project itself.\n\n  The listener process receives the following messages:\n\n    * `{:modules_compiled, info}` - delivered after a set of modules is\n      compiled. `info` is a map with the following keys:\n\n        * `:app` - app which modules have been compiled.\n\n        * `:scm` - the SCM module of the compiled project.\n\n        * `:modules_diff` - information about the compiled modules. The\n          value is a map with keys: `:added`, `:changed`, `:removed`,\n          where each holds a list of modules. There is also a `:timestamp`\n          key, which matches the modification time of all the compiled\n          module files.\n\n        * `:os_pid` - the operating system PID of the process that run\n          the compilation. The value is a string and it can be compared\n          with `System.pid/0` to determine if compilation happened in\n          the same OS process as the listener.\n\n    * `{:dep_compiled, info}` - delivered after a dependency is compiled.\n      `info` is a map with the following keys:\n\n        * `:app` - the dependency app.\n\n        * `:scm` - the SCM module of the dependency.\n\n        * `:manager` - the dependency project management, possible values:\n          `:rebar3`, `:mix`, `:make`, `nil`.\n\n        * `:os_pid` - the operating system PID of the process that run\n          the compilation. The value is a string and it can be compared\n          with `System.pid/0` to determine if compilation happened in\n          the same OS process as the listener.\n\n  New messages may be added in the future, so the process should have\n  a catch-all clause and ignore other messages.\n\n  Note that the listener starts before any of the project apps are started.\n  \"\"\"\n\n  defmodule Diagnostic do\n    @moduledoc \"\"\"\n    Diagnostic information such as a warning or compilation error.\n\n    The file and position relate to where the diagnostic should be shown.\n    If there is a file and position, then the diagnostic is precise\n    and you can use the given file and position for generating snippets,\n    IDEs annotations, and so on. An optional span is available with\n    the line and column the diagnostic ends.\n\n    Otherwise, a stacktrace may be given, which you can place your own\n    heuristics to provide better reporting.\n\n    The source field points to the source file the compiler tracked\n    the error to. For example, a file `lib/foo.ex` may embed `.eex`\n    templates from `lib/foo/bar.eex`. A syntax error on the EEx template\n    will point to file `lib/foo/bar.eex` but the source is `lib/foo.ex`.\n    \"\"\"\n\n    @type t :: %__MODULE__{\n            file: Path.t() | nil,\n            source: Path.t() | nil,\n            severity: severity,\n            message: IO.chardata(),\n            position: Code.position(),\n            compiler_name: String.t(),\n            details: term(),\n            stacktrace: Exception.stacktrace(),\n            span: {line :: pos_integer(), column :: pos_integer()} | nil\n          }\n\n    @typedoc \"\"\"\n    Severity of a diagnostic:\n\n      * `:error` - An issue that caused compilation to fail\n\n      * `:warning` - An issue that did not cause failure but suggests the\n        programmer may have made a mistake\n\n      * `:hint` - A suggestion for style or good practices that is not as\n        severe as a warning\n\n      * `:information` - Any other information relevant to compilation that\n        does not fit into the above categories\n\n    \"\"\"\n    @type severity :: :error | :warning | :information | :hint\n\n    @enforce_keys [:file, :severity, :message, :position, :compiler_name]\n    defstruct [\n      :file,\n      :source,\n      :severity,\n      :message,\n      :position,\n      :compiler_name,\n      span: nil,\n      details: nil,\n      stacktrace: []\n    ]\n  end\n\n  @type status :: :ok | :noop | :error\n\n  @doc \"\"\"\n  Receives command-line arguments and performs compilation. If it\n  produces errors, warnings, or any other diagnostic information,\n  it should return a tuple with the status and a list of diagnostics.\n  \"\"\"\n  @callback run([binary]) :: status | {status, [Diagnostic.t()]}\n\n  @doc \"\"\"\n  Lists manifest files for the compiler.\n  \"\"\"\n  @callback manifests() :: [Path.t()]\n\n  @doc \"\"\"\n  Lists persisted diagnostics from the compiler.\n  \"\"\"\n  @callback diagnostics() :: [Diagnostic.t()]\n\n  @doc \"\"\"\n  Removes build artifacts and manifests.\n  \"\"\"\n  @callback clean() :: any\n\n  @optional_callbacks clean: 0, manifests: 0, diagnostics: 0\n\n  @doc \"\"\"\n  Adds a callback that runs after a given compiler.\n\n  The callback is invoked after the compiler runs and\n  it receives a tuple with current status and the list\n  of diagnostic. It must return the updated status and\n  diagnostics.\n\n  If the given compiler does not run (for instance,\n  because an earlier compiler in the stack has aborted),\n  the callback will not be executed.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec after_compiler(atom, ({status, [Diagnostic.t()]} -> {status, [Diagnostic.t()]})) :: :ok\n  def after_compiler(name, fun) when is_atom(name) and is_function(fun, 1) do\n    Mix.ProjectStack.prepend_after_compiler(name, fun)\n  end\n\n  @doc false\n  defmacro __using__(_opts) do\n    quote do\n      Enum.each(\n        Mix.Task.supported_attributes(),\n        &Module.register_attribute(__MODULE__, &1, persist: true)\n      )\n\n      @behaviour Mix.Task.Compiler\n    end\n  end\n\n  @doc \"\"\"\n  Returns all compilers for the current project.\n  \"\"\"\n  def compilers(config \\\\ Mix.Project.config()) do\n    compilers = config[:compilers] || Mix.compilers()\n\n    if :xref in compilers do\n      IO.warn(\n        \"the :xref compiler is deprecated, please remove it from your mix.exs :compilers options\"\n      )\n\n      List.delete(compilers, :xref)\n    else\n      compilers\n    end\n    |> maybe_prepend(:leex)\n    |> maybe_prepend(:yecc)\n  end\n\n  defp maybe_prepend(compilers, compiler) do\n    if compiler in compilers do\n      compilers\n    else\n      [compiler | compilers]\n    end\n  end\n\n  @doc \"\"\"\n  Lists manifest files for all compilers in the current project.\n  \"\"\"\n  def manifests(config \\\\ Mix.Project.config()) do\n    Enum.flat_map(compilers(config), fn compiler ->\n      module = Mix.Task.get(\"compile.#{compiler}\")\n\n      if module && function_exported?(module, :manifests, 0) do\n        module.manifests()\n      else\n        []\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Lists persisted diagnostics from all compilers in the current project.\n  \"\"\"\n  def diagnostics(config \\\\ Mix.Project.config()) do\n    Enum.flat_map(compilers(config), fn compiler ->\n      module = Mix.Task.get(\"compile.#{compiler}\")\n\n      if module && function_exported?(module, :diagnostics, 0) do\n        module.diagnostics()\n      else\n        []\n      end\n    end)\n  end\n\n  @doc \"\"\"\n  Runs the given list of compilers with the given arguments.\n\n  It returns a `{status, diagnostics}` tuple. If a compiler\n  errors, following compilers do not run.\n  \"\"\"\n  @doc since: \"1.19.0\"\n  def run(compilers, args) do\n    run(compilers, args, :noop, [])\n  end\n\n  defp run([], _, status, diagnostics) do\n    {status, diagnostics}\n  end\n\n  defp run([compiler | rest], args, status, diagnostics) do\n    {new_status, new_diagnostics} = run_compiler(compiler, args)\n    diagnostics = diagnostics ++ new_diagnostics\n\n    case new_status do\n      :error -> {:error, diagnostics}\n      :ok -> run(rest, args, :ok, diagnostics)\n      :noop -> run(rest, args, status, diagnostics)\n    end\n  end\n\n  defp run_compiler(compiler, args) do\n    args_maybe_force = maybe_prepend_force(args, compiler)\n    result = normalize(Mix.Task.run(\"compile.#{compiler}\", args_maybe_force), compiler)\n    Enum.reduce(Mix.ProjectStack.pop_after_compiler(compiler), result, & &1.(&2))\n  end\n\n  defp maybe_prepend_force(args, compiler) do\n    args\n    |> Enum.any?(fn\n      \"--force-\" <> rest -> rest == compiler |> to_string() |> String.replace(\"_\", \"-\")\n      _ -> false\n    end)\n    |> if do\n      [\"--force\" | args]\n    else\n      args\n    end\n  end\n\n  # Normalize the compiler result to a diagnostic tuple\n  defp normalize(result, name) do\n    case result do\n      {status, diagnostics} when status in [:ok, :noop, :error] and is_list(diagnostics) ->\n        {status, diagnostics}\n\n      # ok/noop can come from tasks that have already run\n      _ when result in [:ok, :noop] ->\n        {result, []}\n\n      _ ->\n        # TODO: Convert this to an error on v2.0\n        Mix.shell().error(\n          \"warning: Mix compiler #{inspect(name)} was supposed to return \" <>\n            \"{:ok | :noop | :error, [diagnostic]} but it returned #{inspect(result)}\"\n        )\n\n        {:noop, []}\n    end\n  end\n\n  @doc false\n  # Broadcast an event about a finished compilation of a set of modules.\n  @spec notify_modules_compiled((-> modules_diff)) :: :ok\n        when modules_diff: %{\n               added: [module],\n               changed: [module],\n               removed: [module],\n               timestamp: integer\n             }\n  def notify_modules_compiled(lazy_modules_diff) when is_function(lazy_modules_diff, 0) do\n    config = Mix.Project.config()\n    build_path = Mix.Project.build_path(config)\n\n    lazy_message = fn ->\n      info = %{\n        app: config[:app],\n        scm: config[:build_scm],\n        modules_diff: lazy_modules_diff.(),\n        os_pid: System.pid()\n      }\n\n      {:modules_compiled, info}\n    end\n\n    Mix.Sync.PubSub.broadcast(build_path, lazy_message)\n  end\n\n  @doc \"\"\"\n  Reenables given compilers so they can be executed again down the stack.\n\n  If an umbrella project reenables compilers, they are re-enabled for all\n  child projects.\n\n  Default is `:all` which effectively means all the compilers returned by\n  `Mix.Task.Compiler.compilers()` are to be reenabled. This task always\n  re-enables `\"compile\"` and `\"compile.all\"`.\n  \"\"\"\n  @doc since: \"1.19.0\"\n  @spec reenable(compilers) :: :ok when compilers: :all | [atom()]\n  def reenable(compilers \\\\ :all) do\n    compilers =\n      case compilers do\n        :all -> Mix.Task.Compiler.compilers()\n        list when is_list(list) -> list\n      end\n\n    Mix.Task.reenable(\"compile\")\n    Mix.Task.reenable(\"compile.all\")\n    Enum.each(compilers, &Mix.Task.reenable(\"compile.#{&1}\"))\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/task.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Task do\n  @moduledoc \"\"\"\n  Provides conveniences for creating, loading, and manipulating Mix tasks.\n\n  To create a new Mix task, you'll need to:\n\n    1. Create a module whose name begins with `Mix.Tasks.` (for example,\n       `Mix.Tasks.MyTask`).\n    2. Call `use Mix.Task` in that module.\n    3. Implement the `Mix.Task` behaviour in that module (that is,\n       implement the `c:run/1` callback).\n\n  Typically, task modules live inside the `lib/mix/tasks/` directory,\n  and their file names use dot separators instead of underscores\n  (for example, `deps.clean.ex`) - although ultimately the file name is not\n  relevant.\n\n  For example:\n\n      # lib/mix/tasks/echo.ex\n      defmodule Mix.Tasks.Echo do\n        @moduledoc \"Printed when the user requests `mix help echo`\"\n        @shortdoc \"Echoes arguments\"\n\n        use Mix.Task\n\n        @impl Mix.Task\n        def run(args) do\n          Mix.shell().info(Enum.join(args, \" \"))\n        end\n      end\n\n  The command name will correspond to the portion of the module\n  name following `Mix.Tasks.`. For example, a module name of\n  `Mix.Tasks.Deps.Clean` corresponds to a task name of `deps.clean`.\n\n  The `run/1` function will receive a list of all command line\n  arguments passed, according to the user's terminal.\n\n  For example, if the `args` in the above `echo` task were\n  inspected, you might see something like this:\n\n      $ mix echo 'A and B' C --test\n      [\"A and B\", \"C\", \"--test\"]\n\n  > #### `use Mix.Task` {: .info}\n  >\n  > When you `use Mix.Task`, the `Mix.Task` module will\n  > set `@behaviour Mix.Task` and define default values\n  > for the module attributes documented in the section\n  > below.\n\n  ## Module attributes\n\n  You can control some behavior of your Mix task by setting module\n  attributes. This section documents the available attributes.\n\n  ### `@shortdoc`\n\n  Define the `@shortdoc` attribute if you wish to make the task\n  publicly visible on `mix help`. Omit this attribute if you do\n  not want your task to be listed via `mix help`.\n\n  ### `@moduledoc`\n\n  The `@moduledoc` attribute may override `@shortdoc`. The task\n  will not appear in `mix help` if documentation for the entire\n  module is hidden with `@moduledoc false`.\n\n  ### `@requirements`\n\n  If a task has *requirements*, they can be listed using the\n  `@requirements` attribute. Requirements are other Mix\n  tasks that this task requires to have run. For example:\n\n      @requirements [\"app.config\"]\n\n  A task will typically depend on one of the following tasks:\n\n    * [\"loadpaths\"](`Mix.Tasks.Loadpaths`) - this ensures\n      dependencies are available and compiled. If you are publishing\n      a task as part of a library to be used by others, and your\n      task does not need to interact with the user code in any way,\n      this is the recommended requirement\n\n    * [\"app.config\"](`Mix.Tasks.App.Config`) - additionally compiles\n      and load the runtime configuration for the current project. If\n      you are creating a task to be used within your application or\n      as part of a library, which must invoke or interact with the\n      user code, this is the minimum recommended requirement\n\n    * [\"app.start\"](`Mix.Tasks.App.Start`) - additionally starts the\n      supervision tree of the current project and its dependencies\n\n  ### `@recursive`\n\n  Set `@recursive true` if you want the task to run\n  on each umbrella child in an umbrella project.\n\n  ### `@preferred_cli_env`\n\n  Sets the preferred Mix environment for this task. For example,\n  if your task is meant to be used for testing, you could set\n\n      @preferred_cli_env :test\n\n  ## Documentation\n\n  Users can read the documentation for public Mix tasks by\n  running `mix help my_task`. The documentation that will be\n  shown is the `@moduledoc` of the task's module.\n  \"\"\"\n\n  @typedoc \"\"\"\n  The name of a task.\n\n  For example, `\"deps.clean\"` or `:\"deps.clean\"`.\n  \"\"\"\n  @type task_name :: String.t() | atom\n\n  @typedoc \"\"\"\n  The module that implements a Mix task.\n\n  For example, `Mix.Tasks.MyTask`.\n  \"\"\"\n  @type task_module :: atom\n\n  @doc \"\"\"\n  A task needs to implement `run` which receives\n  a list of command line args.\n  \"\"\"\n  @callback run(command_line_args :: [binary]) :: any\n\n  @doc false\n  defmacro __using__(_opts) do\n    quote do\n      Enum.each(\n        Mix.Task.supported_attributes(),\n        &Module.register_attribute(__MODULE__, &1, persist: true)\n      )\n\n      @behaviour Mix.Task\n    end\n  end\n\n  @doc false\n  def supported_attributes do\n    [:shortdoc, :recursive, :preferred_cli_env, :requirements]\n  end\n\n  @doc \"\"\"\n  Loads all tasks in all code paths.\n  \"\"\"\n  @spec load_all() :: [task_module]\n  def load_all, do: load_tasks(:code.get_path())\n\n  @doc \"\"\"\n  Loads all tasks in the given `paths`.\n  \"\"\"\n  @spec load_tasks([List.Chars.t()]) :: [task_module]\n  def load_tasks(dirs) do\n    # We may get duplicate modules because we look through the\n    # entire load path so make sure we only return unique modules.\n    for dir <- dirs,\n        file <- safe_list_dir(to_charlist(dir)),\n        mod = task_from_path(file),\n        uniq: true,\n        do: mod\n  end\n\n  defp safe_list_dir(path) do\n    case File.ls(path) do\n      {:ok, paths} -> paths\n      {:error, _} -> []\n    end\n  end\n\n  @prefix_size byte_size(\"Elixir.Mix.Tasks.\")\n  @suffix_size byte_size(\".beam\")\n\n  defp task_from_path(filename) do\n    base = Path.basename(filename)\n    part = byte_size(base) - @prefix_size - @suffix_size\n\n    case base do\n      <<\"Elixir.Mix.Tasks.\", rest::binary-size(^part), \".beam\">> ->\n        mod = :\"Elixir.Mix.Tasks.#{rest}\"\n        ensure_task?(mod) && mod\n\n      _ ->\n        nil\n    end\n  end\n\n  @doc \"\"\"\n  Returns all loaded task modules.\n\n  Modules that are not yet loaded won't show up.\n  Check `load_all/0` if you want to preload all tasks.\n  \"\"\"\n  @spec all_modules() :: [task_module]\n  def all_modules do\n    for {module, _} <- :code.all_loaded(), task?(module), do: module\n  end\n\n  @doc \"\"\"\n  Gets the moduledoc for the given task `module`.\n\n  Returns the moduledoc or `nil`.\n  \"\"\"\n  @spec moduledoc(task_module) :: String.t() | nil | false\n  def moduledoc(module) when is_atom(module) do\n    case Code.fetch_docs(module) do\n      {:docs_v1, _, _, _, %{\"en\" => moduledoc}, _, _} -> moduledoc\n      {:docs_v1, _, _, _, :none, _, _} -> nil\n      _ -> false\n    end\n  end\n\n  @doc \"\"\"\n  Gets the shortdoc for the given task `module`.\n\n  Returns the shortdoc or `nil`.\n  \"\"\"\n  @spec shortdoc(task_module) :: String.t() | nil\n  def shortdoc(module) when is_atom(module) do\n    case List.keyfind(module.__info__(:attributes), :shortdoc, 0) do\n      {:shortdoc, [shortdoc]} -> shortdoc\n      _ -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Checks if the task should be run recursively for all sub-apps in\n  umbrella projects.\n\n  Returns `true` or `false`.\n  \"\"\"\n  @spec recursive(task_module) :: boolean\n  def recursive(module) when is_atom(module) do\n    case List.keyfind(module.__info__(:attributes), :recursive, 0) do\n      {:recursive, [setting]} -> setting\n      _ -> false\n    end\n  end\n\n  @doc \"\"\"\n  Indicates if the current task is recursing.\n\n  This returns `true` if a task is marked as recursive\n  and it is being executed inside an umbrella project.\n  \"\"\"\n  @doc since: \"1.8.0\"\n  @spec recursing?() :: boolean\n  def recursing?() do\n    Mix.ProjectStack.recursing() != nil\n  end\n\n  @doc \"\"\"\n  Available for backwards compatibility.\n\n  See the [CLI configuration](Mix.Project.html#module-cli-configuration)\n  section in the `Mix.Project` documentation.\n  \"\"\"\n  @deprecated \"Configure the environment in your mix.exs\"\n  defdelegate preferred_cli_env(task), to: Mix.CLI\n\n  @doc \"\"\"\n  Gets the list of requirements for the given task.\n\n  Returns a list of strings, where the string is expected\n  to be a task optionally followed by its arguments.\n  \"\"\"\n  @doc since: \"1.11.0\"\n  @spec requirements(task_module) :: []\n  def requirements(module) when is_atom(module) do\n    {:requirements, requirements} =\n      List.keyfind(module.__info__(:attributes), :requirements, 0, {:requirements, []})\n\n    requirements\n  end\n\n  @doc \"\"\"\n  Returns the task name for the given `module`.\n\n  ## Examples\n\n      iex> Mix.Task.task_name(Mix.Tasks.Test)\n      \"test\"\n\n  \"\"\"\n  @spec task_name(task_module) :: task_name\n  def task_name(module) when is_atom(module) do\n    Mix.Utils.module_name_to_command(module, 2)\n  end\n\n  @doc \"\"\"\n  Checks if the given `task` name is an alias.\n\n  Returns `false` if the given name is not an alias or if it is not a task.\n\n  For more information about task aliasing, take a look at the\n  [\"Aliases\"](https://hexdocs.pm/mix/Mix.html#module-aliases) section in the\n  docs for `Mix`.\n  \"\"\"\n  @spec alias?(task_name) :: boolean\n  def alias?(task) when is_binary(task) do\n    alias?(String.to_atom(task))\n  end\n\n  def alias?(task) when is_atom(task) do\n    Keyword.has_key?(Mix.Project.config()[:aliases], task)\n  end\n\n  @doc \"\"\"\n  Receives a task name and returns the corresponding task module if one exists.\n\n  Returns `nil` if the module cannot be found, if it is an alias, or if it is\n  not a valid `Mix.Task`.\n  \"\"\"\n  @spec get(task_name) :: task_module | nil\n  def get(task) do\n    case fetch(task) do\n      {:ok, module} -> module\n      {:error, _} -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Receives a task name and retrieves the corresponding task module.\n\n  ## Exceptions\n\n    * `Mix.NoTaskError`      - raised if the task could not be found\n    * `Mix.InvalidTaskError` - raised if the task is not a valid `Mix.Task`\n\n  \"\"\"\n  @spec get!(task_name) :: task_module\n  def get!(task) do\n    case fetch(task) do\n      {:ok, module} ->\n        module\n\n      {:error, :invalid} ->\n        raise Mix.InvalidTaskError, task: task\n\n      {:error, :not_found} ->\n        raise Mix.NoTaskError, task: task\n    end\n  end\n\n  defp fetch(task) when is_binary(task) or is_atom(task) do\n    case Mix.Utils.command_to_module(to_string(task), Mix.Tasks) do\n      {:module, module} ->\n        if task?(module), do: {:ok, module}, else: {:error, :invalid}\n\n      {:error, _} ->\n        {:error, :not_found}\n    end\n  end\n\n  @doc \"\"\"\n  Conditionally runs the task (or alias) with the given `args`.\n\n  If there exists a task matching the given task name and it has not yet been\n  invoked, this will run the task with the given `args` and return the result.\n\n  If there is an [alias](Mix.html#module-aliases) defined\n  for the given task name, the alias will be invoked instead of the original\n  task.\n\n  If the task or alias has already been invoked, subsequent calls to `run/2`\n  will _abort_ without executing and return `:noop`.\n\n  Remember: by default, tasks will only run _once_, even when called repeatedly!\n  If you need to run a task multiple times, you need to re-enable it via\n  `reenable/1` or call it using `rerun/2`.\n\n  `run/2` raises an exception if an alias or a task cannot be found or if the\n  task is invalid. See `get!/1` for more information.\n\n  ## Examples\n\n      iex> Mix.Task.run(\"format\", [\"mix.exs\"])\n      :ok\n\n  \"\"\"\n  @spec run(task_name, [any]) :: any\n  def run(task, args \\\\ []) do\n    do_run(task, args, nil)\n  end\n\n  @doc \"\"\"\n  Runs recursive tasks in the specified list of children apps for umbrella projects.\n\n  If the task is not recursive (whose purpose is to be run in children\n  applications), it runs at the project root level as usual. Calling\n  this function outside of an umbrella project root fails.\n  \"\"\"\n  @doc since: \"1.14.0\"\n  @spec run_in_apps(task_name, [atom], [any]) :: any\n  def run_in_apps(task, apps, args \\\\ []) do\n    if !Mix.Project.umbrella?() do\n      Mix.raise(\n        \"Could not run #{inspect(task)} with the --app option because this is not an umbrella project\"\n      )\n    end\n\n    do_run(task, args, apps)\n  end\n\n  defp do_run(task, args, apps) when is_atom(task) do\n    do_run(Atom.to_string(task), args, apps)\n  end\n\n  defp do_run(task, args, apps) when is_binary(task) do\n    proj = Mix.Project.get()\n    alias = Mix.Project.config()[:aliases][String.to_atom(task)]\n\n    cond do\n      alias && Mix.TasksServer.run({:alias, task, proj}) ->\n        run_alias(List.wrap(alias), args, proj, task, apps, :ok)\n\n      Mix.TasksServer.get({:task, task, proj}) ->\n        :noop\n\n      module = maybe_load_or_compile_task(proj, task) ->\n        run_task(proj, module, task, args, apps)\n\n      results = Mix.Project.umbrella?() && recur_umbrella_children_alias(task, args, apps) ->\n        results\n\n      true ->\n        # We could not find the task, let's raise\n        get!(task)\n    end\n  end\n\n  defp recur_umbrella_children_alias(task, args, apps) do\n    alias_key = String.to_atom(task)\n\n    entries =\n      Mix.ProjectStack.recur(fn ->\n        recur(\n          fn proj ->\n            alias = Mix.Project.config()[:aliases][alias_key]\n\n            cond do\n              is_nil(alias) ->\n                :error\n\n              Mix.TasksServer.run({:alias, task, proj}) ->\n                {:ok, run_alias(List.wrap(alias), args, proj, task, nil, :ok)}\n\n              true ->\n                {:ok, :noop}\n            end\n          end,\n          apps\n        )\n      end)\n\n    case for({:ok, res} <- entries, do: res) do\n      [] -> nil\n      result -> result\n    end\n  end\n\n  defp maybe_load_or_compile_task(proj, task) do\n    # 1. If the task is available, we run it.\n    # 2. Otherwise we compile and load dependencies\n    # 3. Finally, we compile the current project in hope it is available.\n    get_task_or_run(proj, task, fn -> run(\"deps.loadpaths\") end) ||\n      get_task_or_run(proj, task, fn -> run(\"compile\", []) end) ||\n      get(task)\n  end\n\n  defp run_task(proj, module, task, args, apps) do\n    recursive = recursive(module)\n\n    cond do\n      recursive && Mix.Project.umbrella?() ->\n        Mix.ProjectStack.recur(fn ->\n          recur(fn _ -> run(task, args) end, apps)\n        end)\n\n      apps && not recursive ->\n        run(task, args)\n\n      not recursive && Mix.ProjectStack.recursing() ->\n        Mix.ProjectStack.on_recursing_root(fn -> run(task, args) end)\n\n      Mix.TasksServer.run({:task, task, proj}) ->\n        run_requirements(module)\n\n        with_debug(task, args, proj, fn ->\n          try do\n            module.run(args)\n          rescue\n            e in OptionParser.ParseError ->\n              Mix.raise(\"Could not invoke task #{inspect(task)}: \" <> Exception.message(e))\n          end\n        end)\n\n      true ->\n        :noop\n    end\n  end\n\n  defp run_requirements(module) do\n    Enum.each(requirements(module), fn requirement ->\n      [task | args] = OptionParser.split(requirement)\n      run(task, args)\n    end)\n  end\n\n  defp with_debug(task, args, proj, fun) do\n    cond do\n      Mix.debug?() ->\n        shell = Mix.shell()\n        shell.info([\"-> Running mix \", task_to_string(task, args), project_to_string(proj)])\n        {time, res} = :timer.tc(fun)\n        shell.info([\"<- Ran mix \", task, \" in \", Integer.to_string(div(time, 1000)), \"ms\"])\n        res\n\n      opts = profile_opts_for(task) ->\n        shell = Mix.shell()\n        shell.info([\"-> Profiling mix \", task_to_string(task, args), project_to_string(proj)])\n        Mix.Tasks.Profile.Tprof.profile(fun, opts)\n\n      true ->\n        fun.()\n    end\n  end\n\n  defp profile_opts_for(task) do\n    {opts, tasks} = Mix.State.get(:profile, {[], []})\n\n    if task in tasks do\n      opts\n    end\n  end\n\n  defp project_to_string(nil), do: \"\"\n  defp project_to_string(proj), do: \" (inside #{inspect(proj)})\"\n\n  defp task_to_string(task, []), do: task\n  defp task_to_string(task, args), do: task <> \" \" <> Enum.join(args, \" \")\n\n  defp get_task_or_run(proj, task, fun) do\n    cond do\n      module = get(task) ->\n        module\n\n      proj ->\n        fun.()\n        nil\n\n      true ->\n        nil\n    end\n  end\n\n  defp run_alias([h | t], alias_args, proj, original_task, apps, _res) when is_binary(h) do\n    case OptionParser.split(h) do\n      [^original_task | args] ->\n        module = maybe_load_or_compile_task(proj, original_task) || get!(original_task)\n        res = run_task(proj, module, original_task, args ++ alias_args, apps)\n        run_alias(t, [], proj, original_task, apps, res)\n\n      [task | args] ->\n        res = do_run(task, join_args(args, alias_args, t), apps)\n        run_alias(t, alias_args, proj, original_task, apps, res)\n    end\n  end\n\n  defp run_alias([h | t], alias_args, proj, original_task, apps, _res)\n       when is_function(h, 1) do\n    res =\n      if apps do\n        Mix.ProjectStack.recur(fn ->\n          recur(fn _ -> h.(join_args([], alias_args, t)) end, apps)\n        end)\n      else\n        h.(join_args([], alias_args, t))\n      end\n\n    run_alias(t, alias_args, proj, original_task, apps, res)\n  end\n\n  defp run_alias([h | _], _alias_args, _proj, _original_task, _apps, _res) do\n    Mix.raise(\n      \"Invalid Mix alias format, aliases can be either a string (representing a Mix task \" <>\n        \"with arguments) or a function that takes one argument (a list of alias arguments), \" <>\n        \"got: #{inspect(h)}\"\n    )\n  end\n\n  defp run_alias([], _alias_args, proj, original_task, _apps, res) do\n    Mix.TasksServer.put({:task, original_task, proj})\n    res\n  end\n\n  defp join_args(args, alias_args, []), do: args ++ alias_args\n  defp join_args(args, _alias_args, _), do: args\n\n  @doc \"\"\"\n  Clears all invoked tasks, allowing them to be reinvoked.\n\n  This operation is not recursive.\n  \"\"\"\n  @spec clear :: :ok\n  def clear do\n    Mix.TasksServer.clear()\n  end\n\n  @doc \"\"\"\n  Reenables a given task so it can be executed again down the stack.\n\n  Both alias and the regular stack are re-enabled when this function\n  is called.\n\n  If an umbrella project reenables a task, it is re-enabled for all\n  child projects.\n  \"\"\"\n  @spec reenable(task_name) :: :ok\n  def reenable(task) when is_binary(task) or is_atom(task) do\n    task = to_string(task)\n    proj = Mix.Project.get()\n    recursive = (module = get(task)) && recursive(module)\n\n    Mix.TasksServer.delete_many([{:task, task, proj}, {:alias, task, proj}])\n\n    cond do\n      recursive && Mix.Project.umbrella?() ->\n        recur(\n          fn proj ->\n            Mix.TasksServer.delete_many([{:task, task, proj}, {:alias, task, proj}])\n          end,\n          nil\n        )\n\n      proj = !recursive && Mix.ProjectStack.recursing() ->\n        Mix.TasksServer.delete_many([{:task, task, proj}, {:alias, task, proj}])\n\n      true ->\n        :ok\n    end\n\n    :ok\n  end\n\n  defp recur(fun, nil), do: run_in_children_projects(fun, Mix.Dep.Umbrella.cached())\n\n  defp recur(fun, apps) do\n    selected_children =\n      Mix.Dep.Umbrella.cached()\n      |> Enum.filter(fn %Mix.Dep{app: app} -> app in apps end)\n\n    run_in_children_projects(fun, selected_children)\n  end\n\n  defp run_in_children_projects(fun, deps) do\n    # Get all dependency configuration but not the deps path\n    # as we leave the control of the deps path still to the\n    # umbrella child.\n    config = Mix.Project.deps_config() |> Keyword.delete(:deps_path)\n\n    for %Mix.Dep{app: app, opts: opts} <- deps do\n      Mix.Project.in_project(app, opts[:path], [inherit_parent_config_files: true] ++ config, fun)\n    end\n  end\n\n  @doc \"\"\"\n  Reruns `task` with the given arguments.\n\n  This function reruns the given task; to do that, it first re-enables the task\n  and then runs it as normal.\n  \"\"\"\n  @spec rerun(task_name, [any]) :: any\n  def rerun(task, args \\\\ []) do\n    reenable(task)\n    run(task, args)\n  end\n\n  @doc \"\"\"\n  Returns `true` if given module is a task.\n  \"\"\"\n  @spec task?(task_module) :: boolean\n  def task?(module) when is_atom(module) do\n    match?(~c\"Elixir.Mix.Tasks.\" ++ _, Atom.to_charlist(module)) and ensure_task?(module)\n  end\n\n  defp ensure_task?(module) do\n    Code.ensure_loaded?(module) and function_exported?(module, :run, 1)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/app.config.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.App.Config do\n  use Mix.Task\n\n  @shortdoc \"Configures all registered apps\"\n\n  @moduledoc \"\"\"\n  Loads and configures all registered apps.\n\n  This is done by loading `config/runtime.exs` if one exists.\n  The application will be compiled if it was not compiled before.\n\n  ## Command line options\n\n    * `--force` - forces compilation regardless of compilation times\n    * `--preload-modules` - preloads all modules defined in applications\n    * `--no-archives-check` - does not check archives\n    * `--no-app-loading` - does not load .app resource file after compilation\n    * `--no-compile` - does not compile even if files require compilation\n    * `--no-deps-check` - does not check dependencies\n    * `--no-elixir-version-check` - does not check Elixir version\n    * `--no-validate-compile-env` - does not validate the application compile environment\n\n  \"\"\"\n\n  @switches [preload_modules: :boolean]\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    Mix.Task.run(\"compile\", args)\n    {opts, _, _} = OptionParser.parse(args, switches: @switches)\n\n    config = Mix.Project.config()\n    runtime = config[:config_path] |> Path.dirname() |> Path.join(\"runtime.exs\")\n\n    if File.exists?(runtime) do\n      Mix.Tasks.Loadconfig.load_runtime(runtime)\n    end\n\n    if opts[:preload_modules] do\n      for {app, _, _} <- Application.loaded_applications() do\n        :code.ensure_modules_loaded(Application.spec(app, :modules))\n      end\n    end\n\n    # If the build path is set, we assume it is being shared\n    # (such as in an umbrella) and therefore we cannot check\n    # for applications as we may have both false positives and\n    # false negatives.\n    #\n    # Therefore we let the application that owns the build path\n    # to ultimately perform the check.\n    if !config[:build_path] do\n      check_configured()\n    end\n  end\n\n  defp check_configured() do\n    for app <- Mix.ProjectStack.config_apps(),\n        # Application.spec is a quick check that doesn't involve\n        # a separate process, so we try that first.\n        is_nil(Application.spec(app, :vsn)),\n        # Then we fallback to checking the :code.lib_dir for apps\n        # with runtime: false, which is still reasonably fast as\n        # the code server also uses a ETS table\n        :code.lib_dir(app) == {:error, :bad_name} do\n      Mix.shell().error(\"\"\"\n      You have configured application #{inspect(app)} in your configuration file,\n      but the application is not available.\n\n      This usually means one of:\n\n        1. You have not added the application as a dependency in a mix.exs file.\n\n        2. You are configuring an application that does not really exist.\n\n      Please ensure #{inspect(app)} exists or remove the configuration.\n      \"\"\")\n    end\n\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/app.start.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.App.Start do\n  use Mix.Task\n\n  @shortdoc \"Starts all registered apps\"\n\n  @moduledoc \"\"\"\n  Starts all registered apps.\n\n  First, this task guarantees that all dependencies are in place\n  and that the current project has been compiled. Then, the current\n  application is started as a temporary application, unless\n  `:start_permanent` is set to `true` in your project configuration\n  or the `--permanent` option is given. Setting it to permanent\n  guarantees the node will shut down if the application terminates\n  (typically because its root supervisor has terminated).\n\n  ## Configuration\n\n    * `:start_permanent` - the application and all of its children\n      applications are started in permanent mode. Defaults to `false`.\n\n    * `:start_concurrently` - applications are started concurrently\n      whenever possible. Defaults to `false`.\n\n  ## Command line options\n\n    * `--force` - forces compilation regardless of compilation times\n    * `--temporary` - starts the application as temporary\n    * `--permanent` - starts the application as permanent\n    * `--preload-modules` - preloads all modules defined in applications\n    * `--no-archives-check` - does not check archives\n    * `--no-compile` - does not compile even if files require compilation\n    * `--no-deps-check` - does not check dependencies\n    * `--no-elixir-version-check` - does not check Elixir version\n    * `--no-start` - does not actually start applications, only compiles and loads code\n\n  \"\"\"\n\n  @compile {:no_warn_undefined, Logger.App}\n\n  @switches [\n    permanent: :boolean,\n    temporary: :boolean\n  ]\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    Mix.Task.run(\"app.config\", args)\n    {opts, _, _} = OptionParser.parse(args, switches: @switches)\n\n    if \"--no-start\" in args do\n      Mix.Task.reenable(\"app.start\")\n    else\n      # Stop Logger when starting the application as it is up to the\n      # application to decide if it should be restarted or not.\n      #\n      # Mix should not depend directly on Logger so check that it's loaded.\n      Logger.App.stop()\n      config = Mix.Project.config()\n      type = type(config, opts)\n      mode = if config[:start_concurrently], do: :concurrent, else: :serial\n      start(apps(config), type, mode)\n    end\n\n    :ok\n  end\n\n  @doc false\n  def start(apps, type, mode) do\n    case Application.ensure_all_started(apps, type: type, mode: mode) do\n      {:ok, _} ->\n        :ok\n\n      {:error, {app, reason}} when type == :permanent ->\n        # We need to stop immediately because application_controller is\n        # shutting down all applications. Since any work we do here is prone\n        # to race conditions as whatever process we call may no longer exist,\n        # we print a quick message, and then we block by calling `System.stop/1`.\n        Mix.shell().error([\"** (Mix) \", could_not_start(app, reason)])\n        System.stop(1)\n        Process.sleep(:infinity)\n\n      {:error, {app, reason}} ->\n        Mix.raise(could_not_start(app, reason))\n    end\n\n    :ok\n  end\n\n  defp apps(config) do\n    cond do\n      Mix.Project.umbrella?(config) -> Enum.map(Mix.Dep.Umbrella.cached(), & &1.app)\n      app = config[:app] -> [app]\n      true -> []\n    end\n  end\n\n  defp could_not_start(app, reason) do\n    \"Could not start application #{app}: \" <> Application.format_error(reason)\n  end\n\n  @doc false\n  def type(config, opts) do\n    cond do\n      opts[:temporary] -> :temporary\n      opts[:permanent] -> :permanent\n      config[:start_permanent] -> :permanent\n      true -> :temporary\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/app.tree.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.App.Tree do\n  use Mix.Task\n\n  @shortdoc \"Prints the application tree\"\n  @recursive true\n\n  @moduledoc \"\"\"\n  Prints the application tree.\n\n      $ mix app.tree --exclude logger --exclude elixir\n\n  If no application is given, it uses the current application defined\n  in the `mix.exs` file.\n\n  ## Command line options\n\n    * `--exclude` - exclude applications which you do not want to see printed.\n      `kernel`, `stdlib` and `compiler` are always excluded from the tree.\n\n    * `--format` - Can be set to one of either:\n\n      * `pretty` - uses Unicode code points for formatting the tree.\n        This is the default except on Windows.\n\n      * `plain` - does not use Unicode code points for formatting the tree.\n        This is the default on Windows.\n\n      * `dot` - produces a DOT graph description of the application tree\n        in `app_tree.dot` in the current directory.\n        Warning: this will overwrite any previously generated file.\n\n  \"\"\"\n\n  @default_excluded [:kernel, :stdlib, :compiler]\n\n  @impl true\n  def run(args) do\n    Mix.Task.run(\"compile\", args)\n\n    {app, opts} =\n      case OptionParser.parse!(args, strict: [exclude: :keep, format: :string]) do\n        {opts, []} ->\n          app =\n            Mix.Project.config()[:app] ||\n              Mix.raise(\"no application given and none found in mix.exs file\")\n\n          {app, opts}\n\n        {opts, [app]} ->\n          {String.to_atom(app), opts}\n      end\n\n    excluded = Keyword.get_values(opts, :exclude) |> Enum.map(&String.to_atom/1)\n    excluded = @default_excluded ++ excluded\n\n    callback = fn {app, type} ->\n      if load(app, type) do\n        {{app, type(type)}, children_for(app, excluded)}\n      else\n        {{app, \"(optional - missing)\"}, []}\n      end\n    end\n\n    if opts[:format] == \"dot\" do\n      root = [{app, :normal}]\n      Mix.Utils.write_dot_graph!(\"app_tree.dot\", \"application tree\", root, callback, opts)\n\n      \"\"\"\n      Generated \"app_tree.dot\" in the current directory. To generate a PNG:\n\n         dot -Tpng app_tree.dot -o app_tree.png\n\n      For more options see https://www.graphviz.org/.\n      \"\"\"\n      |> String.trim_trailing()\n      |> Mix.shell().info()\n    else\n      Mix.Utils.print_tree([{app, :normal}], callback, opts)\n    end\n  end\n\n  defp load(app, type) do\n    case Application.ensure_loaded(app) do\n      :ok -> true\n      _ when type == :optional -> false\n      _ -> Mix.raise(\"could not find application #{app}\")\n    end\n  end\n\n  defp children_for(app, excluded) do\n    apps = Application.spec(app, :applications) -- excluded\n    included_apps = Application.spec(app, :included_applications) -- excluded\n    optional_apps = Application.spec(app, :optional_applications) || []\n\n    Enum.sort(\n      Enum.map(apps, &{&1, if(&1 in optional_apps, do: :optional, else: :normal)}) ++\n        Enum.map(included_apps, &{&1, :included})\n    )\n  end\n\n  defp type(:normal), do: nil\n  defp type(:included), do: \"(included)\"\n  defp type(:optional), do: \"(optional)\"\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/archive.build.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Archive.Build do\n  use Mix.Task\n\n  @shortdoc \"Archives this project into a .ez file\"\n  @recursive true\n\n  @moduledoc \"\"\"\n  Builds an archive according to the specification of the\n  [Erlang archive format](`:code`).\n\n  Archives are meant to contain small projects, usually installed\n  locally. Archives may be installed into a Mix environment by\n  running `mix archive.install`. Once installed, the archive is\n  available to all Mix projects. For this reason, the functionality\n  behind archives is limited. For instance, archives do not include\n  dependencies, as those would conflict with any dependency in a\n  Mix project after the archive is installed. In general, we recommend\n  the usage of archives to be limited for extensions of Mix, such\n  as custom SCMs, package managers, and the like. For general scripts to be\n  distributed to developers, please see `mix escript.build`.\n\n  The archive will be created in the current directory (which is\n  expected to be the project root), unless an argument `-o` is\n  provided with the file name.\n\n  By default, this command archives the current project but the `-i`\n  option can be used to archive any directory. For example,\n  `mix archive.build` with no options translates to:\n\n      $ mix archive.build -i _build/ENV/lib/APP -o APP-VERSION.ez\n\n  ## Command line options\n\n    * `-o` - specifies output file name.\n      If there is a `mix.exs`, defaults to `APP-VERSION.ez`.\n\n    * `-i` - specifies the input directory to archive.\n      If there is a `mix.exs`, defaults to the current application build.\n\n    * `--no-compile` - skips compilation.\n      Only applies when `mix.exs` is available.\n\n    * `--include-dot-files` - adds dot files from priv directory to the archive.\n\n  \"\"\"\n  @switches [\n    force: :boolean,\n    compile: :boolean,\n    output: :string,\n    input: :string,\n    deps_check: :boolean,\n    archives_check: :boolean,\n    elixir_version_check: :boolean,\n    include_dot_files: :boolean\n  ]\n\n  @impl true\n  def run(args) do\n    {opts, _} = OptionParser.parse!(args, aliases: [o: :output, i: :input], strict: @switches)\n\n    project = Mix.Project.get()\n\n    if project && Keyword.get(opts, :compile, true) do\n      # We only care about the archive ebin, so we disable protocol\n      # consolidation to avoid further changes to the environment.\n      Mix.Task.run(:compile, [\"--no-consolidate-protocols\" | args])\n    end\n\n    source =\n      cond do\n        input = opts[:input] ->\n          input\n\n        project ->\n          path = Mix.Project.app_path()\n\n          if elixir = Mix.Project.config()[:elixir] do\n            File.write(Path.join(path, \".elixir\"), elixir)\n          else\n            File.rm(Path.join(path, \".elixir\"))\n          end\n\n          path\n\n        true ->\n          Mix.raise(\"Cannot create archive without input directory, please pass -i as an option\")\n      end\n\n    project_config = Mix.Project.config()\n\n    target =\n      cond do\n        output = opts[:output] ->\n          output\n\n        project_config[:app] ->\n          Mix.Local.name_for(:archives, project_config)\n\n        true ->\n          Mix.raise(\"Cannot create archive without output file, please pass -o as an option\")\n      end\n\n    if not File.dir?(source) do\n      Mix.raise(\"Expected archive source #{inspect(source)} to be a directory\")\n    end\n\n    create(source, target, Keyword.get(opts, :include_dot_files, false))\n\n    Mix.shell().info(\"Generated archive #{inspect(target)} with MIX_ENV=#{Mix.env()}\")\n    :ok\n  end\n\n  defp create(source, target, include_dot_files?) do\n    source_path = Path.expand(source)\n    target_path = Path.expand(target)\n    dir = Mix.Local.archive_name(target_path) |> String.to_charlist()\n    file_list = files_to_add(source_path, dir, include_dot_files?)\n    {:ok, _} = :zip.create(String.to_charlist(target_path), file_list)\n    :ok\n  end\n\n  defp files_to_add(path, dir, include_dot_files?) do\n    File.cd!(path, fn ->\n      evsn = Path.wildcard(\".elixir\")\n      ebin = Path.wildcard(\"ebin/*.{beam,app}\")\n      priv = Path.wildcard(\"priv/**/*\", match_dot: include_dot_files?)\n\n      Enum.reduce(evsn ++ ebin ++ priv, [], fn f, acc ->\n        case File.read(f) do\n          {:ok, bin} ->\n            [{Path.join(dir, f) |> String.to_charlist(), bin} | acc]\n\n          {:error, _} ->\n            acc\n        end\n      end)\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/archive.check.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Archive.Check do\n  use Mix.Task\n\n  @moduledoc \"\"\"\n  Checks all archives are available.\n\n  Mix projects can specify required archives using\n  the `:archives` option:\n\n      archives: [{:foo, \"~> 1.0.0\"}]\n\n  This task guarantees this option is respected.\n  \"\"\"\n\n  @impl true\n  def run(_) do\n    archives = Mix.Project.config()[:archives] || []\n\n    Enum.each(archives, fn tuple ->\n      {archive, req} = parse_archive(tuple)\n      _ = Application.load(archive)\n      vsn = Application.spec(archive, :vsn)\n\n      cond do\n        is_nil(vsn) ->\n          Mix.raise(\n            \"Archive \\\"#{archive}\\\" could not be found. \" <>\n              \"Please make sure the archive is installed locally.\"\n          )\n\n        not Version.match?(List.to_string(vsn), req) ->\n          Mix.raise(\n            \"Archive \\\"#{archive}-#{vsn}\\\" does not match requirement #{req}. \" <>\n              \"Please update your archive version accordingly.\"\n          )\n\n        true ->\n          :ok\n      end\n    end)\n  end\n\n  defp parse_archive({archive, req}) when is_atom(archive) and is_binary(req) do\n    case Version.parse_requirement(req) do\n      {:ok, req} ->\n        {archive, req}\n\n      :error ->\n        Mix.raise(\"Invalid requirement #{req} for archive \\\"#{archive}\\\"\")\n    end\n  end\n\n  defp parse_archive(other) do\n    Mix.raise(\"\"\"\n    Expected archive to be in the format:\n\n        {app :: atom, requirement :: binary}\n\n    got:\n\n        #{inspect(other)}\n\n    \"\"\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/archive.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Archive do\n  use Mix.Task\n\n  @shortdoc \"Lists installed archives\"\n\n  @moduledoc \"\"\"\n  Lists all installed archives.\n\n  Archives are typically installed at `~/.mix/archives`\n  although the installation path can be customized by\n  setting the `MIX_ARCHIVES` environment variable.\n\n  Since archives are specific to Elixir versions, it is\n  expected from build tools to swap the `MIX_ARCHIVES`\n  variable to different locations based on a particular\n  Elixir installation.\n  \"\"\"\n\n  @impl true\n  def run(_) do\n    Mix.path_for(:archives)\n    |> Path.join(\"*\")\n    |> Path.wildcard()\n    |> Enum.map(&Path.basename/1)\n    |> print()\n  end\n\n  defp print([]) do\n    Mix.shell().info(\"No archives currently installed.\")\n  end\n\n  defp print(items) do\n    Enum.each(items, fn item -> Mix.shell().info([\"* \", item]) end)\n    Mix.shell().info(\"Archives installed at: #{Mix.path_for(:archives)}\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/archive.install.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Archive.Install do\n  use Mix.Task\n\n  @shortdoc \"Installs an archive locally\"\n\n  @moduledoc \"\"\"\n  Installs an archive locally.\n\n  If no argument is supplied but there is an archive in the project's\n  root directory (created with `mix archive.build`), then the archive\n  will be installed locally. For example:\n\n      $ mix do archive.build + archive.install\n\n  If an argument is provided, it should be a local path to a\n  prebuilt archive, a Git repository, a GitHub repository, or a Hex\n  package.\n\n      $ mix archive.install archive.ez\n      $ mix archive.install path/to/archive.ez\n      $ mix archive.install git https://path/to/git/repo\n      $ mix archive.install git https://path/to/git/repo branch git_branch\n      $ mix archive.install git https://path/to/git/repo tag git_tag\n      $ mix archive.install git https://path/to/git/repo ref git_ref\n      $ mix archive.install github user/project\n      $ mix archive.install github user/project branch git_branch\n      $ mix archive.install github user/project tag git_tag\n      $ mix archive.install github user/project ref git_ref\n      $ mix archive.install hex hex_package\n      $ mix archive.install hex hex_package 1.2.3\n\n  After installation, the tasks in the archive are available locally:\n\n      $ mix some_task\n\n  Note that installing via Git, GitHub, or Hex fetches the source\n  of the archive and builds it, while using local path uses a pre-built archive.\n\n  ## Command line options\n\n    * `--sha512` - checks the archive matches the given SHA-512 checksum. Only\n      applies to installations via a local path\n\n    * `--force` - forces installation without a shell prompt; primarily\n      intended for automation in build systems like Make\n\n    * `--submodules` - fetches repository submodules before building archive from\n      Git or GitHub\n\n    * `--sparse` - checkout a single directory inside the Git repository and use\n      it as the archive root directory\n\n    * `--app` - specifies a custom app name to be used for building the archive\n      from Git, GitHub, or Hex\n\n    * `--organization` - set this for Hex private packages belonging to an\n      organization\n\n    * `--repo` - set this for self-hosted Hex instances, defaults to `hexpm`\n\n  \"\"\"\n\n  @behaviour Mix.Local.Installer\n\n  @switches [\n    force: :boolean,\n    sha512: :string,\n    submodules: :boolean,\n    sparse: :string,\n    app: :string,\n    organization: :string,\n    repo: :string,\n    timeout: :integer\n  ]\n\n  @impl true\n  def run(argv) do\n    Mix.Local.Installer.install(__MODULE__, argv, @switches)\n  end\n\n  @impl true\n  def check_install_spec({:local, path} = _install_spec, _opts) do\n    check_extname(path)\n  end\n\n  def check_install_spec({:url, url} = _install_spec, _opts) do\n    check_extname(url)\n  end\n\n  def check_install_spec(_, _), do: :ok\n\n  defp check_extname(path_or_url) do\n    if Path.extname(path_or_url) == \".ez\" do\n      :ok\n    else\n      {:error, \"Expected a local file path ending in \\\".ez\\\".\"}\n    end\n  end\n\n  @impl true\n  def find_previous_versions(src) do\n    app =\n      src\n      |> Mix.Local.archive_name()\n      |> String.split(\"-\")\n      |> List.first()\n\n    if app do\n      archives(app) ++ archives(app <> \"-*\")\n    else\n      []\n    end\n  end\n\n  @impl true\n  def install(basename, contents, previous) do\n    ez_path = Path.join(Mix.path_for(:archives), basename)\n    dir_dest = resolve_destination(ez_path, contents)\n\n    remove_previous_versions(previous)\n\n    File.mkdir_p!(dir_dest)\n    {:ok, _} = :zip.extract(contents, cwd: to_charlist(dir_dest))\n    Mix.shell().info([:green, \"* creating \", :reset, Path.relative_to_cwd(dir_dest)])\n\n    ebin = Mix.Local.archive_ebin(dir_dest)\n    Mix.Local.check_elixir_version_in_ebin(ebin)\n    true = Code.append_path(ebin, cache: true)\n    :ok\n  end\n\n  @impl true\n  def build(_install_spec, _opts) do\n    src = Mix.Local.name_for(:archives, Mix.Project.config())\n    previous = find_previous_versions(src)\n\n    Enum.each(previous, fn path ->\n      Code.delete_path(Mix.Local.archive_ebin(path))\n    end)\n\n    Mix.Task.run(\"loadconfig\")\n    Mix.Task.run(\"archive.build\", [])\n    src\n  end\n\n  ### Private helpers\n\n  defp resolve_destination(ez_path, contents) do\n    with {:ok, [_comment, zip_first_file | _]} <- :zip.list_dir(contents),\n         {:zip_file, zip_first_path, _, _, _, _} = zip_first_file,\n         [zip_root_dir | _] = Path.split(zip_first_path) do\n      Path.join(Path.dirname(ez_path), zip_root_dir)\n    else\n      _ ->\n        Mix.raise(\"Installation failed: invalid archive file\")\n    end\n  end\n\n  defp archives(name) do\n    Mix.path_for(:archives)\n    |> Path.join(name)\n    |> Path.wildcard()\n  end\n\n  defp remove_previous_versions([]), do: :ok\n  defp remove_previous_versions(previous), do: Enum.each(previous, &File.rm_rf!/1)\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/archive.uninstall.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Archive.Uninstall do\n  use Mix.Task\n\n  @shortdoc \"Uninstalls archives\"\n\n  @moduledoc \"\"\"\n  Uninstalls local archives.\n\n      $ mix archive.uninstall archive.ez\n\n  ## Command line options\n    * `--force` - forces uninstallation without a shell prompt; primarily\n      intended for automation\n  \"\"\"\n\n  @switches [\n    force: :boolean\n  ]\n\n  @impl true\n  def run(argv) do\n    Mix.Local.Installer.uninstall(Mix.path_for(:archives), \"archive\", argv, @switches)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/clean.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Clean do\n  use Mix.Task\n\n  @shortdoc \"Deletes generated application files\"\n  @recursive true\n\n  @moduledoc \"\"\"\n  Deletes generated application files.\n\n  This command deletes all build artifacts for the current project.\n  Dependencies' sources and build files are cleaned only if the\n  `--deps` option is given.\n\n  By default this task works across all environments, unless `--only`\n  is given.\n\n  ## Command line options\n\n    * `--deps` - clean dependencies as well as the current project's files\n    * `--only` - only clean the given environment\n\n  \"\"\"\n\n  @switches [deps: :boolean, only: :string]\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    loadpaths!()\n\n    {opts, _, _} = OptionParser.parse(args, switches: @switches)\n\n    Mix.Project.with_build_lock(fn ->\n      do_run(opts)\n    end)\n  end\n\n  defp do_run(opts) do\n    # First, we get the tasks. After that, we clean them.\n    # This is to avoid a task cleaning a compiler module.\n    tasks =\n      for compiler <- Mix.Task.Compiler.compilers(),\n          module = Mix.Task.get(\"compile.#{compiler}\"),\n          function_exported?(module, :clean, 0),\n          do: module\n\n    Mix.Compilers.Protocol.clean()\n    Enum.each(tasks, & &1.clean())\n\n    build =\n      Mix.Project.build_path()\n      |> Path.dirname()\n      |> Path.join(\"*#{opts[:only]}\")\n\n    if opts[:deps] do\n      build\n      |> Path.wildcard()\n      |> Enum.each(&File.rm_rf/1)\n    else\n      build\n      |> Path.join(\"lib/#{Mix.Project.config()[:app]}\")\n      |> Path.wildcard()\n      |> Enum.each(&File.rm_rf/1)\n    end\n  end\n\n  # Loadpaths without checks because compilers may be defined in deps.\n  defp loadpaths! do\n    options = [\n      \"--no-elixir-version-check\",\n      \"--no-deps-check\",\n      \"--no-archives-check\",\n      \"--no-listeners\"\n    ]\n\n    Mix.Task.run(\"loadpaths\", options)\n    Mix.Task.reenable(\"loadpaths\")\n    Mix.Task.reenable(\"deps.loadpaths\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/cmd.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Cmd do\n  use Mix.Task\n\n  @shortdoc \"Executes the given command\"\n  @recursive true\n\n  @moduledoc \"\"\"\n  Executes the given command.\n\n  For example, you can invoke an external command such as make:\n\n      $ mix cmd make\n\n  ## Shell expansion\n\n  When you invoke `mix cmd` from the command line, environment variables,\n  glob patterns, and similar are expanded by the current shell and then\n  passed to `mix cmd`. For example, if you invoke:\n\n      $ mix cmd echo lib/*\n\n  Your shell will expand \"lib/*\" and then pass multiple arguments to\n  `mix cmd`, which in turn passes them to `echo`. Note that, `mix cmd`\n  by itself, does not perform any shell expansion. This means that,\n  if you invoke `mix cmd` programmatically, as in:\n\n      Mix.Task.run(\"cmd\", [\"echo\", \"lib/*\"])\n\n  or through a `mix.exs` alias:\n\n      alias: \"cmd echo lib/*\"\n\n  It will literally print \"lib/*\".\n\n  This behaviour is the default from Elixir v1.19. If you want\n  `mix cmd` to behave like a shell, you can pass the `--shell`\n  option before the command name:\n\n      Mix.Task.run(\"cmd\", [\"--shell\", \"echo\", \"lib/*\"])\n\n  Keep in mind however that, if `--shell` is given, quoted arguments\n  are no longer correctly propagated to the underlying command\n  (as they get expanded before hand).\n\n  This task is automatically re-enabled, so it can be called multiple times\n  with different arguments.\n\n  ## Umbrella applications and directories\n\n  This task is also useful in umbrella applications to execute a command\n  on each child app:\n\n      $ mix cmd pwd\n\n  In such cases, Mix will change the current working directory to the root\n  of each umbrella application before executing the command.\n\n  You can limit which apps the cmd runs in by using `mix do` with the `--app`\n  option:\n\n      $ mix do --app app1 --app app2 cmd pwd\n\n  Note the tasks aborts whenever a command exits with a non-zero status.\n\n  Outside of umbrella projects, you can pass the `--cd` flag before the command,\n  to specify a directory:\n\n      $ mix cmd --cd \"third-party\" make\n\n  ## Command line options\n\n    * `--cd` *(since v1.10.4)* - the directory to run the command in\n    * `--shell` *(since v1.19.0)* - perform shell expansion of the arguments\n\n  ## Orphan operating system processes\n\n  Beware that the Erlang VM does not terminate child processes\n  when it shuts down. Therefore, if you use `mix cmd` to start\n  long running processes and then shut down the VM, it is likely\n  that those child processes won't be terminated with the VM.\n\n  A solution is to make sure the child processes listen to the\n  standard input and terminate when standard input is closed.\n  We discuss this topic at length in the \"Orphan operating system processes\"\n  of the `Port` module documentation.\n  \"\"\"\n\n  @switches [\n    app: :keep,\n    cd: :string,\n    shell: :boolean\n  ]\n\n  @impl true\n  def run(args) do\n    {opts, args} = OptionParser.parse_head!(args, strict: @switches)\n\n    if args == [] do\n      Mix.raise(\"No argument was given to mix cmd. Run \\\"mix help cmd\\\" for more information\")\n    end\n\n    apps =\n      opts\n      |> Keyword.get_values(:app)\n      |> Enum.map(&String.to_atom/1)\n\n    if apps != [] do\n      IO.warn(\"the --app in mix cmd is deprecated. Use mix do --app instead.\")\n    end\n\n    if apps == [] or Mix.Project.config()[:app] in apps do\n      path = hd(args)\n      rest = tl(args)\n\n      arg =\n        cond do\n          Keyword.get(opts, :shell, false) ->\n            Enum.join([path | rest], \" \")\n\n          String.contains?(path, [\"/\", \"\\\\\"]) and Path.type(path) != :absolute ->\n            {Path.expand(path, Keyword.get(opts, :cd, \".\")), rest}\n\n          true ->\n            {path, rest}\n        end\n\n      cmd_opts = Keyword.take(opts, [:cd])\n\n      case Mix.shell().cmd(arg, cmd_opts) do\n        0 -> :ok\n        status -> exit(status)\n      end\n    end\n\n    Mix.Task.reenable(\"cmd\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/compile.all.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Compile.All do\n  use Mix.Task.Compiler\n\n  @moduledoc false\n  @compile {:no_warn_undefined, Logger}\n  @recursive true\n\n  # This is an internal task used by \"mix compile\" which\n  # is meant to be recursive and be invoked for each child\n  # project.\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n\n    config = Mix.Project.config()\n\n    Mix.Project.with_build_lock(config, fn ->\n      do_run(config, args)\n    end)\n  end\n\n  defp do_run(config, args) do\n    # Compute the app cache if it is stale and we are\n    # not compiling from a dependency.\n    app_cache =\n      if \"--from-mix-deps-compile\" not in args do\n        Mix.AppLoader.stale_cache(config)\n      end\n\n    # Make sure Mix.Dep is cached to avoid loading dependencies\n    # during compilation. This is also important because we prune\n    # the load paths before compiling, which means any SCM coming\n    # from archives will be removed from the code path.\n    deps = Mix.Dep.cached()\n    apps = compile_apps(config, args)\n\n    {loaded_paths, loaded_modules} =\n      Mix.AppLoader.load_apps(apps, deps, config, {[], []}, fn {app, path}, {paths, mods} ->\n        paths = if path, do: [path | paths], else: paths\n        mods = if app_cache, do: [{app, Application.spec(app, :modules) || []} | mods], else: mods\n        {paths, mods}\n      end)\n\n    # We compute the diff as that will be more efficient\n    # than re-adding common paths several times\n    current_paths = :code.get_path()\n\n    if Keyword.get(config, :prune_code_paths, true) and \"--no-prune-code-paths\" not in args do\n      Code.delete_paths(current_paths -- loaded_paths)\n    end\n\n    Code.prepend_paths(loaded_paths -- current_paths, cache: true)\n\n    # Add the current compilation path. compile.elixir and compile.erlang\n    # will also add this path, but only if they run, so we always add it\n    # here too. Furthermore, we don't cache it as we may still write to it.\n    compile_path = to_charlist(Mix.Project.compile_path())\n    Code.prepend_path(compile_path)\n\n    {status, diagnostics} =\n      if \"--no-compile\" in args do\n        Mix.Task.reenable(\"compile.all\")\n        {:noop, []}\n      else\n        # Build the project structure so we can write down compiled files.\n        Mix.Project.build_structure(config)\n\n        config\n        |> Mix.Task.Compiler.compilers()\n        |> Mix.Task.Compiler.run(args)\n      end\n\n    if status == :error and \"--return-errors\" not in args do\n      exit({:shutdown, 1})\n    end\n\n    if app_cache do\n      Mix.AppLoader.write_cache(app_cache, Map.new(loaded_modules))\n    end\n\n    if \"--no-app-loading\" not in args do\n      app = config[:app]\n\n      with {:ok, properties} <- Mix.AppLoader.load_app(app, \"#{compile_path}/#{app}.app\"),\n           false <- \"--no-validate-compile-env\" in args,\n           [_ | _] = compile_env <- properties[:compile_env],\n           {:error, message} <- Config.Provider.validate_compile_env(compile_env, false) do\n        Mix.raise(message)\n      end\n    end\n\n    {status, diagnostics}\n  end\n\n  @doc \"\"\"\n  Returns all apps that should be available at compile time.\n  \"\"\"\n  def compile_apps(config, args) do\n    project = Mix.Project.get!()\n\n    properties =\n      if function_exported?(project, :application, 0), do: project.application(), else: []\n\n    extra =\n      Keyword.get(properties, :included_applications, []) ++\n        Keyword.get(properties, :extra_applications, [])\n\n    {all, optional} =\n      Mix.Utils.project_apps(properties, config, extra, fn apps_opts ->\n        for {app, opts} <- apps_opts do\n          {app, if(Keyword.get(opts, :optional, false), do: :optional, else: :required)}\n        end\n      end)\n\n    if \"--no-optional-deps\" in args do\n      all -- optional\n    else\n      all\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/compile.app.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Compile.App do\n  use Mix.Task.Compiler\n\n  @recursive true\n\n  @moduledoc \"\"\"\n  Writes a `.app` file.\n\n  A `.app` file is a file containing Erlang terms that defines\n  your application. Mix automatically generates this file based on\n  your `mix.exs` configuration.\n\n  In order to generate the `.app` file, Mix expects your project\n  to have both the `:app` and `:version` keys. Furthermore, you can\n  configure the generated application by defining an `application/0`\n  function in your `mix.exs` that returns a keyword list.\n\n  The most commonly used keys are:\n\n    * `:extra_applications` - a list of OTP applications\n      your application depends on which are not included in `:deps`\n      (usually defined in `deps/0` in your `mix.exs`). For example,\n      here you can declare a dependency on applications that ship\n      with Erlang/OTP or Elixir, like `:crypto` or `:logger`.\n      Optional extra applications can be declared as a tuple, such\n      as `{:ex_unit, :optional}`. Mix guarantees all non-optional\n      applications are started before your application starts.\n\n    * `:registered` - the name of all registered processes in the\n      application. If your application defines a local GenServer\n      with name `MyServer`, it is recommended to add `MyServer`\n      to this list. It is most useful in detecting conflicts\n      between applications that register the same names.\n\n    * `:env` - the default values for the application environment.\n      The application environment is one of the most common ways\n      to configure applications. See the `Application` module for\n      mechanisms to read and write to the application environment.\n\n  For example:\n\n      def application do\n        [\n          extra_applications: [:logger, :crypto, ex_unit: :optional],\n          env: [key: :value],\n          registered: [MyServer]\n        ]\n      end\n\n  Other options include:\n\n    * `:applications` - all applications your application depends\n      on at runtime. By default, this list is automatically inferred\n      from your dependencies. Mix and other tools use the application\n      list in order to start your dependencies before starting the\n      application itself.\n\n    * `:mod` - specifies a module to invoke when the application\n      is started. It must be in the format `{Mod, args}` where\n      args is often an empty list. The module specified must\n      implement the callbacks defined by the `Application`\n      module.\n\n    * `:start_phases` - specifies a list of phases and their arguments\n      to be called after the application is started. See the \"Phases\"\n      section below.\n\n    * `:included_applications` - specifies a list of applications\n      that will be included in the application. It is the responsibility of\n      the primary application to start the supervision tree of all included\n      applications, as only the primary application will be started. A process\n      in an included application considers itself belonging to the\n      primary application.\n\n    * `:maxT` - specifies the maximum time the application is allowed to run, in\n      milliseconds. Applications are stopped if `:maxT` is reached, and their\n      top-level supervisor terminated with reason `:normal`. This threshold is\n      technically valid in any resource file, but it is only effective for\n      applications with a callback module. Defaults to `:infinity`.\n\n  Besides the options above, `.app` files also expect other options\n  like `:modules` and `:vsn`, but these are automatically added by Mix.\n  The complete list can be found on [Erlang's application\n  specification](https://www.erlang.org/doc/man/app).\n\n  From Elixir v1.17 onwards, the application .app file is also loaded\n  whenever the task runs.\n\n  ## Command line options\n\n    * `--force` - forces compilation regardless of modification times\n    * `--compile-path` - where to find `.beam` files and write the\n      resulting `.app` file, defaults to `Mix.Project.compile_path/0`\n\n  ## Configuration\n\n    * `:reliable_dir_mtime` - this task relies on the operating system\n      changing the mtime on a directory whenever a file is added or removed.\n      You can set this option to `false` if your system does not provide\n      reliable mtimes. Defaults to `false` on Windows.\n\n  ## Phases\n\n  Applications provide a start phases mechanism which will be called,\n  in order, for the application and all included applications. If a phase\n  is not defined for an included application, that application is skipped.\n\n  Let's see an example `MyApp.application/0` function:\n\n      def application do\n        [\n          start_phases: [init: [], go: [], finish: []],\n          included_applications: [:my_included_app]\n        ]\n      end\n\n  And an example `:my_included_app` defines on its `mix.exs` the function:\n\n      def application do\n        [\n          mod: {MyIncludedApp, []},\n          start_phases: [go: []]\n        ]\n      end\n\n  In this example, the order that the application callbacks are called in is:\n\n      Application.start(MyApp)\n      MyApp.start(:normal, [])\n      MyApp.start_phase(:init, :normal, [])\n      MyApp.start_phase(:go, :normal, [])\n      MyIncludedApp.start_phase(:go, :normal, [])\n      MyApp.start_phase(:finish, :normal, [])\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    {opts, _, _} = OptionParser.parse(args, switches: [force: :boolean, compile_path: :string])\n    project = Mix.Project.get!()\n    config = Mix.Project.config()\n\n    app = Keyword.get(config, :app)\n    version = Keyword.get(config, :version)\n    validate_app!(app)\n    validate_version!(version)\n\n    compile_path = Keyword.get_lazy(opts, :compile_path, &Mix.Project.compile_path/0)\n    target = Path.join(compile_path, \"#{app}.app\")\n\n    # If configurations changed, we may have changed compile_env.\n    # If compile_path changed, we may have added or removed files.\n    # If the project changed, we may have changed other properties.\n    new_mtime =\n      Mix.Project.config_mtime()\n      |> max(Mix.Utils.last_modified(Mix.Project.project_file()))\n      |> max(Mix.Utils.last_modified(compile_path))\n\n    current_properties = current_app_properties(target)\n    current_compile_env = Mix.ProjectStack.compile_env(nil)\n\n    {changed?, modules} =\n      cond do\n        opts[:force] || new_mtime > Mix.Utils.last_modified(target) ||\n            (current_compile_env != nil and\n               current_compile_env != Keyword.get(current_properties, :compile_env, [])) ->\n          {true, nil}\n\n        Keyword.get(config, :reliable_dir_mtime, fn -> not match?({:win32, _}, :os.type()) end) ->\n          {false, nil}\n\n        true ->\n          modules = modules_from(compile_path)\n          {modules != Keyword.get(current_properties, :modules, []), modules}\n      end\n\n    if changed? do\n      properties =\n        [\n          description: to_charlist(config[:description] || app),\n          registered: [],\n          vsn: to_charlist(version)\n        ]\n        |> merge_project_application(project)\n        |> handle_extra_applications(config)\n        |> add_compile_env(current_compile_env, current_properties)\n        |> add_modules(modules, compile_path)\n\n      contents =\n        case Mix.Utils.consultable({:application, app, properties}) do\n          {:ok, contents} ->\n            contents\n\n          {:error, term, reason} ->\n            Mix.raise(\n              \"\\\"def application\\\" has a term which cannot be written to .app files: #{inspect(term)} (#{reason})\"\n            )\n        end\n\n      :application.unload(app)\n      :application.load({:application, app, properties})\n\n      if opts[:force] || Map.new(current_properties) != Map.new(properties) do\n        Mix.Project.ensure_structure()\n        File.write!(target, IO.chardata_to_string([contents, ?.]))\n        File.touch!(target, new_mtime)\n\n        # If we just created the .app file, it will have touched\n        # the directory mtime, so we need to reset it.\n        if current_properties == [] do\n          File.touch!(compile_path, new_mtime)\n        end\n\n        Mix.shell().info(\"Generated #{app} app\")\n        {:ok, []}\n      else\n        File.touch!(target, new_mtime)\n        {:noop, []}\n      end\n    else\n      :application.load({:application, app, current_properties})\n      {:noop, []}\n    end\n  end\n\n  defp current_app_properties(target) do\n    case :file.consult(target) do\n      {:ok, [{:application, _app, properties}]} -> properties\n      _ -> []\n    end\n  end\n\n  defp validate_app!(app) when is_atom(app), do: :ok\n\n  defp validate_app!(app) do\n    ensure_present!(:app, app)\n    Mix.raise(\"Expected :app to be an atom, got: #{inspect(app)}\")\n  end\n\n  defp validate_version!(version) do\n    ensure_present!(:version, version)\n\n    if not (is_binary(version) and match?({:ok, _}, Version.parse(version))) do\n      Mix.raise(\n        \"Expected :version to be a valid Version, got: #{inspect(version)} (see the Version module for more information)\"\n      )\n    end\n  end\n\n  defp ensure_present!(name, nil) do\n    Mix.raise(\"Please ensure mix.exs file has the #{inspect(name)} in the project definition\")\n  end\n\n  defp ensure_present!(_name, _val), do: :ok\n\n  defp modules_from(path) do\n    case File.ls(path) do\n      {:ok, entries} ->\n        Enum.sort(\n          for entry <- entries,\n              String.ends_with?(entry, \".beam\"),\n              do: entry |> binary_part(0, byte_size(entry) - 5) |> String.to_atom()\n        )\n\n      {:error, _} ->\n        []\n    end\n  end\n\n  defp merge_project_application(best_guess, project) do\n    if function_exported?(project, :application, 0) do\n      project_application = project.application()\n\n      if not Keyword.keyword?(project_application) do\n        Mix.raise(\n          \"Application configuration returned from application/0 should be a keyword list\"\n        )\n      end\n\n      Keyword.merge(best_guess, validate_properties!(project_application))\n    else\n      best_guess\n    end\n  end\n\n  defp validate_properties!(properties) do\n    Enum.each(properties, fn\n      {:description, value} ->\n        if not is_list(value) do\n          Mix.raise(\n            \"Application description (:description) is not a character list, got: \" <>\n              inspect(value)\n          )\n        end\n\n      {:id, value} ->\n        if not is_list(value) do\n          Mix.raise(\"Application ID (:id) is not a character list, got: \" <> inspect(value))\n        end\n\n      {:vsn, value} ->\n        if not is_list(value) do\n          Mix.raise(\"Application vsn (:vsn) is not a character list, got: \" <> inspect(value))\n        end\n\n      {:maxT, value} ->\n        if not (value == :infinity or is_integer(value)) do\n          Mix.raise(\n            \"Application maximum time (:maxT) is not an integer or :infinity, got: \" <>\n              inspect(value)\n          )\n        end\n\n      {:modules, value} ->\n        if not (is_list(value) and Enum.all?(value, &is_atom(&1))) do\n          Mix.raise(\n            \"Application modules (:modules) should be a list of atoms, got: \" <> inspect(value)\n          )\n        end\n\n      {:registered, value} ->\n        if not (is_list(value) and Enum.all?(value, &is_atom(&1))) do\n          Mix.raise(\n            \"Application registered processes (:registered) should be a list of atoms, got: \" <>\n              inspect(value)\n          )\n        end\n\n      {:included_applications, value} ->\n        if not (is_list(value) and Enum.all?(value, &is_atom(&1))) do\n          Mix.raise(\n            \"Application included applications (:included_applications) should be a list of atoms, got: \" <>\n              inspect(value)\n          )\n        end\n\n      {:extra_applications, value} ->\n        if not (is_list(value) and Enum.all?(value, &typed_app?(&1))) do\n          Mix.raise(\n            \"Application extra applications (:extra_applications) should be a list of atoms or \" <>\n              \"{app, :required | :optional} pairs, got: \" <> inspect(value)\n          )\n        end\n\n      {:applications, value} ->\n        if not (is_list(value) and Enum.all?(value, &typed_app?(&1))) do\n          Mix.raise(\n            \"Application applications (:applications) should be a list of atoms or \" <>\n              \"{app, :required | :optional} pairs, got: \" <> inspect(value)\n          )\n        end\n\n      {:env, value} ->\n        if not Keyword.keyword?(value) do\n          Mix.raise(\n            \"Application environment (:env) should be a keyword list, got: \" <> inspect(value)\n          )\n        end\n\n      {:start_phases, value} ->\n        if not Keyword.keyword?(value) do\n          Mix.raise(\n            \"Application start phases (:start_phases) should be a keyword list, got: \" <>\n              inspect(value)\n          )\n        end\n\n      {:mod, []} ->\n        :ok\n\n      {:mod, {module, _args}} when is_atom(module) ->\n        :ok\n\n      {:mod, value} ->\n        Mix.raise(\n          \"Application callback module (:mod) should be either [] or {module, start_args}, got: \" <>\n            inspect(value)\n        )\n\n      _ ->\n        :ok\n    end)\n\n    properties\n  end\n\n  defp typed_app?(app) when is_atom(app), do: true\n  defp typed_app?({app, type}) when is_atom(app) and type in [:required, :optional], do: true\n  defp typed_app?(_), do: false\n\n  defp add_compile_env(properties, current_compile_env, current_properties) do\n    # If someone calls compile.elixir and then compile.app across two\n    # separate OS calls, then the compile_env won't be properly reflected.\n    # This is ok because compile_env is not used for correctness. It is\n    # simply to catch possible errors early.\n    case current_compile_env do\n      nil -> Keyword.take(current_properties, [:compile_env]) ++ properties\n      [] -> properties\n      compile_env -> Keyword.put(properties, :compile_env, compile_env)\n    end\n  end\n\n  defp add_modules(properties, modules, compile_path) do\n    Keyword.put_new_lazy(properties, :modules, fn -> modules || modules_from(compile_path) end)\n  end\n\n  defp handle_extra_applications(properties, config) do\n    {extra, properties} = Keyword.pop(properties, :extra_applications, [])\n\n    if extra != [] and Keyword.has_key?(properties, :applications) do\n      Mix.shell().error(\n        \"both :extra_applications and :applications was found in your mix.exs. \" <>\n          \"You most likely want to remove the :applications key, as all applications are derived from your dependencies\"\n      )\n    end\n\n    {all, optional} =\n      Mix.Utils.project_apps(properties, config, extra, fn apps_opts ->\n        apps_from_runtime_prod_deps(properties, apps_opts)\n      end)\n\n    properties\n    |> Keyword.put(:applications, all)\n    |> Keyword.put(:optional_applications, optional)\n  end\n\n  defp apps_from_runtime_prod_deps(properties, apps_opts) do\n    included_applications = Keyword.get(properties, :included_applications, [])\n\n    for {app, opts} <- apps_opts,\n        runtime_app?(opts),\n        app not in included_applications,\n        do: {app, if(Keyword.get(opts, :optional, false), do: :optional, else: :required)}\n  end\n\n  defp runtime_app?(opts) do\n    Keyword.get(opts, :runtime, true) and Keyword.get(opts, :app, true) and matching_only?(opts) and\n      matching_target?(opts)\n  end\n\n  defp matching_only?(opts) do\n    case Keyword.fetch(opts, :only) do\n      {:ok, value} -> Mix.env() in List.wrap(value)\n      :error -> true\n    end\n  end\n\n  defp matching_target?(opts) do\n    case Keyword.fetch(opts, :targets) do\n      {:ok, value} -> Mix.target() in List.wrap(value)\n      :error -> true\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/compile.elixir.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Compile.Elixir do\n  use Mix.Task.Compiler\n\n  @recursive true\n  @manifest \"compile.elixir\"\n\n  @moduledoc \"\"\"\n  Compiles Elixir source files.\n\n  Elixir is smart enough to recompile only files that have changed\n  and their dependencies. This means if `lib/a.ex` is invoking\n  a function defined over `lib/b.ex` at compile time, whenever\n  `lib/b.ex` changes, `lib/a.ex` is also recompiled. More details\n  about dependencies between files can be found in the documentation\n  of [`mix xref`](`Mix.Tasks.Xref`).\n\n  Note Elixir considers a file as changed if its source file has\n  changed on disk since the last compilation AND its contents are\n  no longer the same.\n\n  ## `@external_resource`\n\n  If a module depends on external files, those can be annotated\n  with the `@external_resource` module attribute. If these files\n  change, the Elixir module is automatically recompiled.\n\n  ## `__mix_recompile__?/0`\n\n  A module may export a `__mix_recompile__?/0` function that can\n  cause the module to be recompiled using custom rules. For example,\n  to recompile whenever a file is changed in a given directory, you\n  can use a combination of `@external_resource` for existing files\n  and a `__mix_recompile__?/0` check to verify when new entries are\n  added to the directory itself:\n\n      defmodule MyModule do\n        paths = Path.wildcard(\"*.txt\")\n        @paths_hash :erlang.md5(paths)\n\n        for path <- paths do\n          @external_resource path\n        end\n\n        def __mix_recompile__?() do\n          Path.wildcard(\"*.txt\") |> :erlang.md5() != @paths_hash\n        end\n      end\n\n  Compiler calls `__mix_recompile__?/0` for every module being\n  compiled (or previously compiled) and thus it is very important\n  to do there as little work as possible to not slow down the\n  compilation.\n\n  If module has `@compile {:autoload, false}`, `__mix_recompile__?/0` will\n  not be used.\n\n  ## Command line options\n\n    * `--all-warnings` (`--no-all-warnings`) - prints all warnings, including previous compilations\n      (default is true except on errors)\n    * `--docs` (`--no-docs`) - attaches (or not) documentation to compiled modules\n    * `--debug-info` (`--no-debug-info`) - attaches (or not) debug info to compiled modules.\n      Passing this flag will force a full recompilation\n    * `--force` - forces compilation regardless of modification times\n    * `--ignore-module-conflict` - does not emit warnings if a module was previously defined\n    * `--long-compilation-threshold N` - sets the \"long compilation\" threshold\n      (in seconds) to `N` (see the docs for `Kernel.ParallelCompiler.compile/2`)\n    * `--long-verification-threshold N` - sets the \"long verification\" threshold\n      (in seconds) to `N` (see the docs for `Kernel.ParallelCompiler.compile/2`)\n    * `--no-verification` - disables code verification, such as unused functions,\n      deprecation warnings, and type checking. It must be used solely for debugging\n      alongside `MIX_DEBUG=1`\n    * `--no-check-cwd` - (since v1.19.2) Elixir stores absolute paths in .beam files,\n      which means that relocating the project root triggers a full build. Pass this option\n      if you don't want the current working directory to be checked\n    * `--purge-consolidation-path-if-stale PATH` - deletes and purges modules in the\n      given protocol consolidation path if compilation is required\n    * `--purge-compiler-modules` - automatically purge compilation modules\n      after compilation (see `Code.purge_compiler_modules/0`)\n    * `--profile` - if set to `time`, outputs timing information of compilation steps\n    * `--tracer` - adds a compiler tracer in addition to any specified in the `mix.exs` file\n    * `--verbose` - prints each file being compiled\n    * `--warnings-as-errors` - exit with non-zero status if compilation has one or more warnings\n\n  ## Configuration\n\n    * `:elixirc_paths` - directories to find source files.\n      Defaults to `[\"lib\"]`.\n\n    * `:elixirc_options` - compilation options that apply to Elixir's compiler.\n      It supports many of the options above  plus the options listed in\n      `Code.put_compiler_option/2`. In case conflicting options are given,\n      the ones given through the command line are used.\n\n    * `[xref: [exclude: ...]]` - a list of `module` or `{module, function, arity}`\n      that should not be warned on in case on undefined modules or undefined\n      application warnings.\n\n  \"\"\"\n\n  @switches [\n    force: :boolean,\n    docs: :boolean,\n    consolidate_protocols: :boolean,\n    warnings_as_errors: :boolean,\n    ignore_module_conflict: :boolean,\n    debug_info: :boolean,\n    verbose: :boolean,\n    long_compilation_threshold: :integer,\n    long_verification_threshold: :integer,\n    purge_consolidation_path_if_stale: :string,\n    purge_compiler_modules: :boolean,\n    profile: :string,\n    all_warnings: :boolean,\n    verification: :boolean,\n    tracer: :keep,\n    check_cwd: :boolean\n  ]\n\n  @impl true\n  def run(args) do\n    {opts, _, _} = OptionParser.parse(args, switches: @switches)\n    {tracers, opts} = pop_tracers(opts)\n\n    project = Mix.Project.config()\n    dest = Mix.Project.compile_path(project)\n    srcs = project[:elixirc_paths]\n\n    if not (is_list(srcs) and Enum.all?(srcs, &is_binary/1)) do\n      Mix.raise(\":elixirc_paths should be a list of string paths, got: #{inspect(srcs)}\")\n    end\n\n    manifest = manifest()\n    base = xref_exclude_opts(project[:elixirc_options] || [], project)\n\n    opts =\n      base\n      |> Keyword.merge(opts)\n      |> tracers_opts(tracers)\n      |> profile_opts()\n\n    # Optional dependencies and debug info affect how artifacts are generated\n    cache_key =\n      {base, srcs, \"--no-optional-deps\" in args, \"--no-debug-info\" in args}\n\n    opts =\n      if \"--no-protocol-consolidation\" in args do\n        # TODO: Deprecate me on Elixir v1.23\n        Keyword.put(opts, :consolidate_protocols, false)\n      else\n        opts ++ Keyword.take(project, [:consolidate_protocols])\n      end\n\n    # Having compilations racing with other is most undesired,\n    # so we wrap the compiler in a lock.\n\n    with_logger_app(project, fn ->\n      Mix.Project.with_build_lock(project, fn ->\n        Mix.Compilers.Elixir.compile(\n          manifest,\n          srcs,\n          dest,\n          cache_key,\n          Mix.Tasks.Compile.Erlang.manifests(),\n          Mix.Tasks.Compile.Erlang.modules(),\n          opts\n        )\n      end)\n    end)\n  end\n\n  @impl true\n  def manifests, do: [manifest()]\n  defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest)\n\n  @impl true\n  def diagnostics do\n    Mix.Compilers.Elixir.diagnostics(manifest())\n  end\n\n  @impl true\n  def clean do\n    dest = Mix.Project.compile_path()\n    Mix.Compilers.Elixir.clean(manifest(), dest)\n  end\n\n  # Run this operation in compile.elixir as the compiler can be called directly\n  defp with_logger_app(config, fun) do\n    app = Keyword.fetch!(config, :app)\n    logger_config_app = Application.get_env(:logger, :compile_time_application)\n\n    try do\n      Application.put_env(:logger, :compile_time_application, app)\n      fun.()\n    after\n      Application.put_env(:logger, :compile_time_application, logger_config_app)\n    end\n  end\n\n  defp xref_exclude_opts(opts, project) do\n    exclude = List.wrap(project[:xref][:exclude])\n\n    if exclude == [] do\n      opts\n    else\n      Keyword.update(opts, :no_warn_undefined, exclude, &(List.wrap(&1) ++ exclude))\n    end\n  end\n\n  defp pop_tracers(opts) do\n    case Keyword.pop_values(opts, :tracer) do\n      {[], opts} ->\n        {[], opts}\n\n      {tracers, opts} ->\n        {Enum.map(tracers, &Module.concat([&1])), opts}\n    end\n  end\n\n  defp tracers_opts(opts, tracers) do\n    tracers = tracers ++ Code.get_compiler_option(:tracers)\n    Keyword.update(opts, :tracers, tracers, &(tracers ++ &1))\n  end\n\n  defp profile_opts(opts) do\n    case Keyword.fetch(opts, :profile) do\n      {:ok, \"time\"} -> Keyword.put(opts, :profile, :time)\n      {:ok, _} -> Keyword.delete(opts, :profile)\n      :error -> opts\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/compile.erlang.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Compile.Erlang do\n  use Mix.Task.Compiler\n  alias Mix.Compilers.Erlang\n\n  @recursive true\n  @manifest \"compile.erlang\"\n  @switches [force: :boolean, verbose: :boolean, all_warnings: :boolean]\n\n  @moduledoc \"\"\"\n  Compiles Erlang source files.\n\n  When this task runs, it will first check the modification times of\n  all files to be compiled and if they haven't been changed since the\n  last compilation, it will not compile them. If any of them have changed,\n  it compiles everything.\n\n  ## Command line options\n\n    * `--all-warnings` (`--no-all-warnings`) - prints all warnings, including previous compilations\n      (default is true except on errors)\n    * `--force` - forces compilation regardless of modification times\n    * `--verbose` - prints verbose output\n\n  ## Configuration\n\n    * `ERL_COMPILER_OPTIONS` - can be used to give default compile options.\n      The value must be a valid Erlang term. If the value is a list, it will\n      be used as is. If it is not a list, it will be put into a list.\n\n    * `:erlc_paths` - directories to find source files.\n      Defaults to `[\"src\"]`.\n\n    * `:erlc_include_path` - directory for adding include files.\n      Defaults to `\"include\"`.\n\n    * `:erlc_options` - compilation options that apply to Erlang's\n      compiler. Defaults to `[]`.\n\n      For a complete list of options, see `:compile.file/2`.\n      The option `:debug_info` is always added to the end of it.\n      You can disable that using:\n\n          erlc_options: [debug_info: false]\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    {opts, _, _} = OptionParser.parse(args, switches: @switches)\n\n    project = Mix.Project.config()\n\n    Mix.Project.with_build_lock(project, fn ->\n      source_paths = project[:erlc_paths]\n      Mix.Compilers.Erlang.assert_valid_erlc_paths(source_paths)\n      files = Mix.Utils.extract_files(source_paths, [:erl])\n      do_run(files, opts, project, source_paths)\n    end)\n  end\n\n  defp do_run([], _, _, _), do: {:noop, []}\n\n  defp do_run(files, opts, project, source_paths) do\n    include_path = Erlang.to_erl_file(project[:erlc_include_path])\n    compile_path = Erlang.to_erl_file(Mix.Project.compile_path(project))\n    erlc_options = project[:erlc_options] || []\n\n    if not is_list(erlc_options) do\n      Mix.raise(\":erlc_options should be a list of options, got: #{inspect(erlc_options)}\")\n    end\n\n    erlc_options =\n      erlc_options ++ [:debug_info, :return, :report, outdir: compile_path, i: include_path]\n\n    erlc_options =\n      Enum.map(erlc_options, fn\n        {kind, dir} when kind in [:i, :outdir] -> {kind, Erlang.to_erl_file(dir)}\n        opt -> opt\n      end)\n\n    compile_path = Path.relative_to(compile_path, File.cwd!())\n    erls = scan_sources(files, include_path, source_paths, compile_path, opts)\n\n    {sorted, parallel} = topsort_and_parallelize(erls, compile_path)\n    opts = [parallel: MapSet.new(parallel)] ++ opts\n\n    Erlang.compile_entries(manifest(), sorted, :erl, :beam, opts, fn input, _output ->\n      # We're purging the module because a previous compiler (for example, Phoenix)\n      # might have already loaded the previous version of it.\n      module = input |> Path.basename(\".erl\") |> String.to_atom()\n      :code.purge(module)\n      :code.delete(module)\n\n      path = Path.rootname(input, \".erl\")\n      file = Erlang.to_erl_file(path)\n\n      case :compile.file(file, erlc_options) do\n        :error ->\n          message =\n            \"Compiling Erlang file #{inspect(path)} failed, probably because of invalid :erlc_options\"\n\n          Mix.raise(message)\n\n        result ->\n          result\n      end\n    end)\n  end\n\n  @impl true\n  def manifests, do: [manifest()]\n  defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest)\n\n  @impl true\n  def diagnostics do\n    Mix.Compilers.Erlang.diagnostics(manifest())\n  end\n\n  @impl true\n  def clean do\n    Mix.Compilers.Erlang.clean(manifest())\n  end\n\n  @doc false\n  def modules do\n    for output <- Mix.Compilers.Erlang.outputs(manifest()) do\n      output\n      |> Path.basename()\n      |> Path.rootname()\n      |> String.to_atom()\n    end\n  end\n\n  ## Internal helpers\n\n  defp scan_sources(files, include_path, source_paths, compile_path, opts) do\n    include_paths = [include_path | source_paths]\n\n    files\n    |> Task.async_stream(&scan_source(&1, include_paths, compile_path, opts),\n      timeout: :infinity,\n      ordered: false\n    )\n    |> Enum.flat_map(fn\n      {:ok, {:ok, erl_file}} -> [erl_file]\n      {:ok, :error} -> []\n    end)\n  end\n\n  defp scan_source(file, include_paths, compile_path, opts) do\n    erl_file = %{\n      file: file,\n      module: module_from_artifact(file),\n      deps: [],\n      includes: [],\n      status: :ok\n    }\n\n    case :epp.parse_file(Erlang.to_erl_file(file), include_paths, []) do\n      {:ok, forms} ->\n        erl_file = List.foldl(tl(forms), erl_file, &do_form(file, &1, &2))\n        {:ok, maybe_stale(erl_file, compile_path, opts[:force])}\n\n      {:error, _error} ->\n        :error\n    end\n  end\n\n  defp do_form(file, form, erl) do\n    case form do\n      {:attribute, _, :file, {include_file, _}} when file != include_file ->\n        if File.regular?(include_file) do\n          %{erl | includes: [include_file | erl.includes]}\n        else\n          erl\n        end\n\n      {:attribute, _, :behaviour, behaviour} ->\n        %{erl | deps: [behaviour | erl.deps]}\n\n      {:attribute, _, :behavior, behaviour} ->\n        %{erl | deps: [behaviour | erl.deps]}\n\n      {:attribute, _, :compile, value} ->\n        %{erl | deps: add_parse_transforms(value, erl.deps)}\n\n      _ ->\n        erl\n    end\n  end\n\n  defp topsort_and_parallelize(erls, compile_path) do\n    graph = :digraph.new()\n\n    for %{module: module, status: status, file: file} <- erls do\n      :digraph.add_vertex(graph, module, {file, status})\n    end\n\n    for %{module: module, deps: deps} <- erls, dep <- deps do\n      # It may error if the behaviour/parse transform is not in the project,\n      # which is expected\n      :digraph.add_edge(graph, module, dep)\n    end\n\n    if vertices = :digraph_utils.topsort(graph) do\n      sorted =\n        Enum.reduce(vertices, [], fn module, acc ->\n          {_, {file, status}} = :digraph.vertex(graph, module)\n          [{status, file, Path.join(compile_path, \"#{module}.beam\")} | acc]\n        end)\n\n      parallel =\n        for %{file: file, module: module} <- erls,\n            :digraph.in_neighbours(graph, module) == [],\n            do: file\n\n      {sorted, parallel}\n    else\n      Mix.raise(\n        \"Could not compile Erlang. \" <>\n          \"The following modules form a cycle: \" <>\n          Enum.join(Mix.Utils.find_cycle!(graph), \", \")\n      )\n    end\n  end\n\n  defp add_parse_transforms(compile, deps) do\n    compile\n    |> List.wrap()\n    |> Enum.reduce(deps, fn\n      {:parse_transform, transform}, deps -> [transform | deps]\n      _, deps -> deps\n    end)\n  end\n\n  defp maybe_stale(erl, compile_path, force) do\n    beam = Path.join(compile_path, \"#{erl.module}.beam\")\n\n    if force || Mix.Utils.stale?([erl.file | erl.includes], [beam]) do\n      %{erl | status: :stale}\n    else\n      erl\n    end\n  end\n\n  defp module_from_artifact(artifact) do\n    artifact |> Path.basename() |> Path.rootname() |> String.to_atom()\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/compile.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Compile do\n  use Mix.Task\n\n  @shortdoc \"Compiles source files\"\n\n  @moduledoc ~S\"\"\"\n  The main entry point to compile source files.\n\n  It simply runs the compilers registered in your project and returns\n  a tuple with the compilation status and a list of diagnostics.\n\n  Before compiling code, it performs a series of checks to ensure all\n  dependencies are compiled and the project is up to date. Then the\n  code path of your Elixir system is pruned to only contain the dependencies\n  and applications that you have explicitly listed in your `mix.exs`.\n\n  ## Configuration\n\n    * `:compilers` - compilers to run, defaults to `Mix.compilers/0`,\n      which are `[:erlang, :elixir, :app]`.\n\n    * `:consolidate_protocols` - when `true`, runs protocol\n      consolidation after compiling Elixir. The default value is `true`.\n\n    * `:build_path` - the directory where build artifacts\n      should be written to. This option is intended only for\n      child apps within a larger umbrella application so that\n      each child app can use the common `_build` directory of\n      the parent umbrella. In a non-umbrella context, configuring\n      this has undesirable side-effects (such as skipping some\n      compiler checks) and should be avoided.\n\n    * `:prune_code_paths` - prune code paths before compilation. When true\n      (default), this prunes code paths of applications that are not listed\n      in the project file with dependencies.  When false, this keeps the\n      entirety of Erlang/OTP available when the project starts, including\n      the paths set by the code loader from the `ERL_LIBS` environment as\n      well as explicitly listed by providing `-pa` and `-pz` options\n      to Erlang.\n\n  ## Compilers\n\n  To see documentation for each specific compiler, you must\n  invoke `help` directly for the compiler command:\n\n      $ mix help compile.elixir\n      $ mix help compile.erlang\n\n  You can get a list of all compilers by running:\n\n      $ mix compile --list\n\n  ## Command line options\n\n    * `--all-warnings` (`--no-all-warnings`) - prints all warnings, including previous compilations\n      (default is true except on errors)\n    * `--erl-config` - path to an Erlang term file that will be loaded as Mix config\n    * `--force` - forces compilation. You can also specify `--force-#{compiler}` for each compiler\n      invoked to force specifically that compiler to run (it requires the compiler to respect the\n      `--force` option, which is advised)\n    * `--list` - lists all enabled compilers\n    * `--listeners` - starts Mix listeners (they are started by default,\n      unless `--no-listeners` or `--no-deps-check` are given)\n    * `--no-app-loading` - does not load .app resource file after compilation\n    * `--no-archives-check` - skips checking of archives\n    * `--no-compile` - does not actually compile, only loads code and perform checks\n    * `--no-deps-check` - skips checking of dependencies\n    * `--no-elixir-version-check` - does not check Elixir version\n    * `--no-listeners` - does not start Mix listeners\n    * `--no-optional-deps` - does not compile or load optional deps. Useful for testing\n      if a library still successfully compiles without optional dependencies (which is the\n      default case with dependencies). Passing this flag will force a full recompilation\n    * `--no-prune-code-paths` - do not prune code paths before compilation, this keeps\n      the entirety of Erlang/OTP available when the project starts\n    * `--no-protocol-consolidation` - skips protocol consolidation\n    * `--no-validate-compile-env` - does not validate the application compile environment\n    * `--return-errors` - returns error status and diagnostics instead of exiting on error\n    * `--warnings-as-errors` - exit with non-zero status if compilation has one or more\n      warnings. Only concerns compilation warnings from the project, not its dependencies.\n\n  \"\"\"\n\n  @deprecated \"Use Mix.Task.Compiler.compilers/1 instead\"\n  defdelegate compilers(config \\\\ Mix.Project.config()), to: Mix.Task.Compiler\n\n  @impl true\n  def run([\"--list\"]) do\n    # Loadpaths without checks because compilers may be defined in deps.\n    args = [\n      \"--no-elixir-version-check\",\n      \"--no-deps-check\",\n      \"--no-archives-check\",\n      \"--no-listeners\"\n    ]\n\n    Mix.Task.run(\"loadpaths\", args)\n    Mix.Task.reenable(\"loadpaths\")\n    Mix.Task.reenable(\"deps.loadpaths\")\n\n    # Compilers are tasks, so load all tasks available.\n    _ = Mix.Task.load_all()\n\n    shell = Mix.shell()\n    modules = Mix.Task.all_modules()\n\n    docs =\n      for module <- modules,\n          task = Mix.Task.task_name(module),\n          match?(\"compile.\" <> _, task),\n          doc = Mix.Task.moduledoc(module) do\n        {task, first_line(doc)}\n      end\n\n    max =\n      Enum.reduce(docs, 0, fn {task, _}, acc ->\n        max(byte_size(task), acc)\n      end)\n\n    sorted = Enum.sort(docs)\n\n    Enum.each(sorted, fn {task, doc} ->\n      shell.info(format(~c\"mix ~-#{max}s # ~ts\", [task, doc]))\n    end)\n\n    consolidate_protocols? = Mix.Project.config()[:consolidate_protocols]\n    compilers = compilers() ++ if(consolidate_protocols?, do: [:protocols], else: [])\n    shell.info(\"\\nEnabled compilers: #{Enum.join(compilers, \", \")}\")\n    :ok\n  end\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n\n    Mix.Task.run(\"loadpaths\", args)\n\n    {opts, _, _} = OptionParser.parse(args, switches: [erl_config: :string])\n    load_erl_config(opts)\n\n    {res, diagnostics} =\n      Mix.Task.run(\"compile.all\", args)\n      |> List.wrap()\n      |> Enum.map(\n        &case &1 do\n          :noop -> {:noop, []}\n          {status, diagnostics} -> {status, diagnostics}\n        end\n      )\n      |> Enum.reduce({:noop, []}, &merge_diagnostics/2)\n\n    config = Mix.Project.config()\n\n    # If we are in an umbrella project, now load paths from all children.\n    if apps_paths = Mix.Project.apps_paths(config) do\n      loaded_paths =\n        (Mix.Tasks.Compile.All.compile_apps(config, args) ++ Map.keys(apps_paths))\n        |> Mix.AppLoader.load_apps(Mix.Dep.cached(), config, [], fn\n          {_app, path}, acc -> if path, do: [path | acc], else: acc\n        end)\n\n      # We don't cache umbrella paths as we may write to them\n      Code.prepend_paths(loaded_paths -- :code.get_path())\n    end\n\n    res =\n      cond do\n        \"--no-compile\" in args ->\n          Mix.Task.reenable(\"compile\")\n          :noop\n\n        Mix.Project.umbrella?(config) ->\n          Mix.Compilers.Protocol.umbrella(args, res)\n\n        true ->\n          res\n      end\n\n    path = Mix.Project.consolidation_path(config)\n\n    with {:ok, protocols} <- File.ls(path) do\n      # We don't cache consolidation path as we may write to it\n      Code.prepend_path(path)\n      Enum.each(protocols, &load_protocol/1)\n    end\n\n    {res, diagnostics}\n  end\n\n  defp format(expression, args) do\n    :io_lib.format(expression, args) |> IO.iodata_to_binary()\n  end\n\n  defp first_line(doc) do\n    String.split(doc, \"\\n\", parts: 2) |> hd() |> String.trim() |> String.trim_trailing(\".\")\n  end\n\n  defp merge_diagnostics({status1, diagnostics1}, {status2, diagnostics2}) do\n    new_status =\n      cond do\n        status1 == :error or status2 == :error -> :error\n        status1 == :ok or status2 == :ok -> :ok\n        true -> :noop\n      end\n\n    {new_status, diagnostics1 ++ diagnostics2}\n  end\n\n  defp load_erl_config(opts) do\n    if path = opts[:erl_config] do\n      {:ok, terms} = :file.consult(path)\n      Application.put_all_env(terms, persistent: true)\n    end\n  end\n\n  @deprecated \"Use Mix.Task.Compiler.manifests/0 instead\"\n  defdelegate manifests, to: Mix.Task.Compiler\n\n  defp load_protocol(file) do\n    case file do\n      \"Elixir.\" <> _ ->\n        module = file |> Path.rootname() |> String.to_atom()\n        :code.purge(module)\n        :code.delete(module)\n\n      _ ->\n        :ok\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/compile.leex.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Compile.Leex do\n  use Mix.Task.Compiler\n  alias Mix.Compilers.Erlang\n\n  @recursive true\n  @manifest \"compile.leex\"\n  @switches [force: :boolean, verbose: :boolean, all_warnings: :boolean]\n\n  # These options can't be controlled with :leex_options.\n  @forced_opts [report: true, return: true]\n\n  @moduledoc \"\"\"\n  Compiles Leex source files.\n\n  When this task runs, it will check the modification time of every file, and\n  if it has changed, the file will be compiled. Files will be\n  compiled in the same source directory with a .erl extension.\n  You can force compilation regardless of modification times by passing\n  the `--force` option.\n\n  You must add `compilers: [:leex] ++ Mix.compilers()` to the `def project`\n  section of your `mix.exs` to run this compiler.\n\n  ## Command line options\n\n    * `--all-warnings` (`--no-all-warnings`) - prints all warnings, including previous compilations\n      (default is true except on errors)\n    * `--force` - forces compilation regardless of modification times\n    * `--verbose` - prints verbose output\n\n  ## Configuration\n\n    * `:erlc_paths` - directories to find source files. Defaults to `[\"src\"]`.\n\n    * `:leex_options` - compilation options that apply to Leex's compiler.\n\n      For a complete list of options, see `:leex.file/2`.\n      Note that the `:report`, `:return_errors`, and `:return_warnings` options\n      are overridden by this compiler, thus setting them has no effect.\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    {opts, _, _} = OptionParser.parse(args, switches: @switches)\n\n    project = Mix.Project.config()\n\n    source_paths = project[:erlc_paths]\n    Mix.Compilers.Erlang.assert_valid_erlc_paths(source_paths)\n    mappings = Enum.zip(source_paths, source_paths)\n\n    leex_options = project[:leex_options] || []\n\n    if not is_list(leex_options) do\n      Mix.raise(\":leex_options should be a list of options, got: #{inspect(leex_options)}\")\n    end\n\n    opts = [parallel: true, preload: fn -> preload(project) end] ++ opts\n\n    Erlang.compile(manifest(), mappings, :xrl, :erl, opts, fn input, output ->\n      options = leex_options ++ @forced_opts ++ [scannerfile: Erlang.to_erl_file(output)]\n      :leex.file(Erlang.to_erl_file(input), options)\n    end)\n  end\n\n  defp preload(project) do\n    # TODO: Remove me in Elixir v2.0\n    if :leex not in List.wrap(project[:compilers]) do\n      Mix.shell().error(\n        \"warning: in order to compile .xrl files, you must add \\\"compilers: [:leex] ++ Mix.compilers()\\\" to the \\\"def project\\\" section of #{project[:app]}'s mix.exs\"\n      )\n    end\n\n    Mix.ensure_application!(:parsetools)\n    {:ok, _} = Application.ensure_all_started(:parsetools)\n  end\n\n  @impl true\n  def manifests, do: [manifest()]\n  defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest)\n\n  @impl true\n  def clean do\n    Erlang.clean(manifest())\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/compile.protocols.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Compile.Protocols do\n  @moduledoc false\n  use Mix.Task\n\n  # TODO: Deprecate me on Elixir v1.23\n  def run(_args) do\n    :noop\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/compile.yecc.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Compile.Yecc do\n  use Mix.Task.Compiler\n  alias Mix.Compilers.Erlang\n\n  @recursive true\n  @manifest \"compile.yecc\"\n  @switches [force: :boolean, verbose: :boolean, all_warnings: :boolean]\n\n  # These options can't be controlled with :yecc_options.\n  @forced_opts [report: true, return: true]\n\n  @moduledoc \"\"\"\n  Compiles Yecc source files.\n\n  When this task runs, it will check the modification time of every file, and\n  if it has changed, the file will be compiled. Files will be\n  compiled in the same source directory with a .erl extension.\n  You can force compilation regardless of modification times by passing\n  the `--force` option.\n\n  You must add `compilers: [:yecc] ++ Mix.compilers()` in the\n  `def project` section of your `mix.exs` to run this compiler.\n\n  ## Command line options\n\n    * `--all-warnings` (`--no-all-warnings`) - prints all warnings, including previous compilations\n      (default is true except on errors)\n    * `--force` - forces compilation regardless of modification times\n    * `--verbose` - prints verbose output\n\n  ## Configuration\n\n    * `:erlc_paths` - directories to find source files. Defaults to `[\"src\"]`.\n\n    * `:yecc_options` - compilation options that apply\n      to Yecc's compiler.\n\n      For a complete list of options, see `:yecc.file/1`.\n      Note that the `:report`, `:return_errors`, and `:return_warnings` options\n      are overridden by this compiler, thus setting them has no effect.\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    {opts, _, _} = OptionParser.parse(args, switches: @switches)\n\n    project = Mix.Project.config()\n\n    source_paths = project[:erlc_paths]\n    Mix.Compilers.Erlang.assert_valid_erlc_paths(source_paths)\n    mappings = Enum.zip(source_paths, source_paths)\n\n    yecc_options = project[:yecc_options] || []\n\n    if not is_list(yecc_options) do\n      Mix.raise(\":yecc_options should be a list of options, got: #{inspect(yecc_options)}\")\n    end\n\n    opts = [parallel: true, preload: fn -> preload(project) end] ++ opts\n\n    Erlang.compile(manifest(), mappings, :yrl, :erl, opts, fn input, output ->\n      options = yecc_options ++ @forced_opts ++ [parserfile: Erlang.to_erl_file(output)]\n      :yecc.file(Erlang.to_erl_file(input), options)\n    end)\n  end\n\n  defp preload(project) do\n    # TODO: Remove me in Elixir v2.0\n    if :yecc not in List.wrap(project[:compilers]) do\n      Mix.shell().error(\n        \"warning: in order to compile .yrl files, you must add \\\"compilers: [:yecc] ++ Mix.compilers()\\\" to the \\\"def project\\\" section of #{project[:app]}'s mix.exs\"\n      )\n    end\n\n    Mix.ensure_application!(:parsetools)\n    {:ok, _} = Application.ensure_all_started(:parsetools)\n  end\n\n  @impl true\n  def manifests, do: [manifest()]\n  defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest)\n\n  @impl true\n  def clean do\n    Erlang.clean(manifest())\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.clean.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps.Clean do\n  use Mix.Task\n\n  @shortdoc \"Deletes the given dependencies' files\"\n\n  @moduledoc \"\"\"\n  Deletes the given dependencies' files, including build artifacts and fetched\n  sources.\n\n  Since this is a destructive action, cleaning of dependencies\n  only occurs when passing arguments/options:\n\n    * `dep1 dep2` - the names of dependencies to be deleted separated by a space\n    * `--unlock` - also unlocks the deleted dependencies\n    * `--build` - deletes only compiled files (keeps source files)\n    * `--all` - deletes all dependencies\n    * `--unused` - deletes only unused dependencies\n      (i.e. dependencies no longer mentioned in `mix.exs`)\n\n  By default this task works across all environments,\n  unless `--only` is given which will clean all dependencies\n  for the chosen environment.\n  \"\"\"\n\n  @switches [unlock: :boolean, all: :boolean, only: :string, unused: :boolean, build: :boolean]\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    {opts, apps} = OptionParser.parse!(args, strict: @switches)\n\n    build_path =\n      Mix.Project.build_path()\n      |> Path.dirname()\n      |> Path.join(\"*#{opts[:only]}/lib\")\n\n    deps_path = Mix.Project.deps_path()\n\n    loaded_opts =\n      for {switch, key} <- [only: :env, target: :target],\n          value = opts[switch],\n          do: {key, :\"#{value}\"}\n\n    loaded_deps = Mix.Dep.Converger.converge(loaded_opts)\n\n    apps_to_clean =\n      cond do\n        opts[:all] ->\n          checked_deps(build_path, deps_path)\n\n        opts[:unused] ->\n          checked_deps(build_path, deps_path) |> filter_loaded(loaded_deps)\n\n        apps != [] ->\n          apps\n\n        true ->\n          Mix.raise(\n            \"\\\"mix deps.clean\\\" expects dependencies as arguments or \" <>\n              \"an option indicating which dependencies to clean. \" <>\n              \"The --all option will clean all dependencies while \" <>\n              \"the --unused option cleans unused dependencies\"\n          )\n      end\n\n    Mix.Project.with_build_lock(fn ->\n      clean_build(apps_to_clean, build_path)\n    end)\n\n    Mix.Project.with_deps_lock(fn ->\n      clean_source(apps_to_clean, loaded_deps, deps_path, opts[:build])\n\n      if opts[:unlock] do\n        Mix.Task.run(\"deps.unlock\", args)\n      else\n        :ok\n      end\n    end)\n  end\n\n  defp checked_deps(build_path, deps_path) do\n    deps_names =\n      for root <- [deps_path, build_path],\n          path <- Path.wildcard(Path.join(root, \"*\")),\n          File.dir?(path),\n          uniq: true,\n          do: Path.basename(path)\n\n    List.delete(deps_names, to_string(Mix.Project.config()[:app]))\n  end\n\n  defp filter_loaded(apps, deps) do\n    apps -- Enum.map(deps, &Atom.to_string(&1.app))\n  end\n\n  defp maybe_warn_for_invalid_path([], dependency) do\n    Mix.shell().error(\n      \"warning: the dependency #{dependency} is not present in the build directory\"\n    )\n\n    []\n  end\n\n  defp maybe_warn_for_invalid_path(paths, _dependency) do\n    paths\n  end\n\n  defp maybe_warn_failed_file_deletion(result) do\n    with {:error, reason, file} <- result do\n      Mix.shell().error(\n        \"warning: could not delete file #{Path.relative_to_cwd(file)}, \" <>\n          \"reason: #{:file.format_error(reason)}\"\n      )\n    end\n  end\n\n  defp clean_build(apps, build_path) do\n    shell = Mix.shell()\n\n    Enum.each(apps, fn app ->\n      shell.info(\"* Cleaning #{app}\")\n\n      # Remove everything from the build directory of dependencies\n      build_path\n      |> Path.join(to_string(app))\n      |> Path.wildcard()\n      |> maybe_warn_for_invalid_path(app)\n      |> Enum.map(&(&1 |> File.rm_rf() |> maybe_warn_failed_file_deletion()))\n    end)\n  end\n\n  defp clean_source(apps, deps, deps_path, build_only?) do\n    local = for %{scm: scm, app: app} <- deps, not scm.fetchable?(), do: Atom.to_string(app)\n\n    Enum.each(apps, fn app ->\n      # Remove everything from the source directory of dependencies.\n      # Skip this step if --build option is specified or if\n      # the dependency is local, i.e., referenced using :path.\n      if build_only? || app in local do\n        :do_not_delete_source\n      else\n        deps_path\n        |> Path.join(to_string(app))\n        |> File.rm_rf()\n        |> maybe_warn_failed_file_deletion()\n      end\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.compile.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps.Compile do\n  use Mix.Task\n\n  @shortdoc \"Compiles dependencies\"\n\n  @moduledoc \"\"\"\n  Compiles dependencies.\n\n  By default, this task attempts to compile all dependencies.\n  A list of dependencies can be given to compile multiple\n  dependencies in order.\n\n  This task attempts to detect if the project contains one of\n  the following files and act accordingly:\n\n    * `mix.exs` - invokes `mix compile`\n    * `rebar.config` - invokes `rebar compile`\n    * `Makefile.win`- invokes `nmake /F Makefile.win` (only on Windows)\n    * `Makefile` - invokes `gmake` on DragonFlyBSD, FreeBSD, NetBSD, and OpenBSD,\n      invokes `make` on any other operating system (except on Windows)\n\n  The compilation can be customized by passing a `compile` option\n  in the dependency:\n\n      {:some_dependency, \"0.1.0\", compile: \"command to compile\"}\n\n  If a list of dependencies is given, Mix will attempt to compile\n  them as is. For example, if project `a` depends on `b`, calling\n  `mix deps.compile a` will compile `a` even if `b` is out of\n  date. This is to allow parts of the dependency tree to be\n  recompiled without propagating those changes upstream. To ensure\n  `b` is included in the compilation step, pass `--include-children`.\n\n  ## Compiling dependencies across multiple OS processes\n\n  If you set the environment variable `MIX_OS_DEPS_COMPILE_PARTITION_COUNT`\n  to a number greater than 1, Mix will start multiple operating system\n  processes to compile your dependencies concurrently.\n\n  While Mix and Rebar compile all files within a given project in parallel,\n  enabling this environment variable can still yield useful gains in several\n  cases, such as when compiling dependencies with native code, dependencies\n  that must download assets, or dependencies where the compilation time is not\n  evenly distributed (for example, one file takes much longer to compile than\n  all others).\n\n  While most configuration in Mix is done via command line flags, this particular\n  environment variable exists because the best number will vary per machine\n  (and often per project too). The environment variable also makes it more accessible\n  to enable concurrent compilation in CI and also during `Mix.install/2` commands.\n\n  ## Command line options\n\n    * `--force` - force compilation of deps\n    * `--skip-umbrella-children` - skips umbrella applications from compiling\n    * `--skip-local-deps` - skips non-remote dependencies, such as path deps, from compiling\n\n  \"\"\"\n\n  @switches [\n    include_children: :boolean,\n    force: :boolean,\n    skip_umbrella_children: :boolean,\n    skip_local_deps: :boolean\n  ]\n\n  @impl true\n  def run(args) do\n    if \"--no-archives-check\" not in args do\n      Mix.Task.run(\"archive.check\", args)\n    end\n\n    Mix.Project.get!()\n    config = Mix.Project.config()\n\n    Mix.Project.with_build_lock(config, fn ->\n      deps = Mix.Dep.load_and_cache()\n\n      case OptionParser.parse(args, switches: @switches) do\n        {opts, [], _} ->\n          compile(filter_available_and_local_deps(deps), opts)\n\n        {opts, tail, _} ->\n          compile(Mix.Dep.filter_by_name(tail, deps, opts), opts)\n      end\n    end)\n  end\n\n  @doc false\n  def compile(deps, options \\\\ []) do\n    Mix.Task.run(\"deps.precompile\")\n    force? = Keyword.get(options, :force, false)\n\n    deps =\n      deps\n      |> reject_umbrella_children(options)\n      |> reject_local_deps(options)\n\n    count = System.get_env(\"MIX_OS_DEPS_COMPILE_PARTITION_COUNT\", \"0\") |> String.to_integer()\n\n    # If all dependencies are local and ok, do not bother starting\n    # processes as it will likely slow everything down.\n    if count > 1 and match?([_, _ | _], deps) and\n         not Enum.all?(deps, &(Mix.Dep.ok?(&1) and not &1.scm.fetchable?())) do\n      Mix.shell().info(\"mix deps.compile running across #{count} OS processes\")\n\n      if Mix.Tasks.Deps.Partition.server(deps, count, force?) do\n        # Each partition will trigger will_recompile but we need to trigger it here too\n        Mix.Task.run(\"will_recompile\")\n      end\n    else\n      config = Mix.Project.deps_config()\n      Enum.each(deps, &compile_single(&1, force?, config))\n    end\n  end\n\n  @doc false\n  def compile_single(%Mix.Dep{} = dep, force?, config) do\n    %{app: app, status: status, opts: opts, scm: scm} = dep\n    check_unavailable!(app, scm, status)\n\n    # If a dependency was marked as fetched or with an out of date lock\n    # or missing the app file, we always compile it from scratch.\n    if force? or Mix.Dep.force_compilable?(dep) do\n      File.rm_rf!(Path.join([Mix.Project.build_path(), \"lib\", Atom.to_string(dep.app)]))\n    end\n\n    compiled? =\n      cond do\n        not is_nil(opts[:compile]) ->\n          do_compile(dep, config)\n\n        Mix.Dep.mix?(dep) ->\n          do_mix(dep, config)\n\n        Mix.Dep.make?(dep) ->\n          do_make(dep, config)\n\n        dep.manager == :rebar3 ->\n          do_rebar3(dep, config)\n\n        true ->\n          Mix.shell().error(\n            \"Could not compile #{inspect(app)}, no \\\"mix.exs\\\", \\\"rebar.config\\\" or \\\"Makefile\\\" \" <>\n              \"(pass :compile as an option to customize compilation, set it to \\\"false\\\" to do nothing)\"\n          )\n\n          false\n      end\n\n    if compiled? do\n      config\n      |> Mix.Project.build_path()\n      |> Mix.Sync.PubSub.broadcast(fn ->\n        info = %{\n          app: dep.app,\n          scm: dep.scm,\n          manager: dep.manager,\n          os_pid: System.pid()\n        }\n\n        {:dep_compiled, info}\n      end)\n    end\n\n    # We should touch fetchable dependencies even if they\n    # did not compile otherwise they will always be marked\n    # as stale, even when there is nothing to do.\n    fetchable? = touch_fetchable(scm, opts)\n\n    if compiled? and fetchable? do\n      Mix.Task.run(\"will_recompile\")\n      true\n    else\n      false\n    end\n  end\n\n  defp check_unavailable!(app, scm, {:unavailable, path}) do\n    if scm.fetchable?() do\n      Mix.raise(\n        \"Cannot compile dependency #{inspect(app)} because \" <>\n          \"it isn't available, run \\\"mix deps.get\\\" first\"\n      )\n    else\n      Mix.raise(\n        \"Cannot compile dependency #{inspect(app)} because \" <>\n          \"it isn't available, please ensure the dependency is at \" <>\n          inspect(Path.relative_to_cwd(path))\n      )\n    end\n  end\n\n  defp check_unavailable!(_, _, _) do\n    :ok\n  end\n\n  defp touch_fetchable(scm, opts) do\n    if scm.fetchable?() do\n      Mix.Dep.ElixirSCM.update(Path.join(opts[:build], \".mix\"), scm, opts[:lock])\n      true\n    else\n      false\n    end\n  end\n\n  defp do_mix(dep, _config) do\n    Mix.Dep.Loader.with_system_env(dep, fn ->\n      Mix.Dep.in_dependency(dep, fn _ ->\n        config = Mix.Project.config()\n\n        if req = old_elixir_req(config) do\n          Mix.shell().error(\n            \"warning: the dependency #{inspect(dep.app)} requires Elixir #{inspect(req)} \" <>\n              \"but you are running on v#{System.version()}\"\n          )\n        end\n\n        try do\n          options = [\n            \"--from-mix-deps-compile\",\n            \"--no-warnings-as-errors\",\n            \"--no-code-path-pruning\"\n          ]\n\n          res = Mix.Task.run(\"compile\", options)\n          match?({:ok, _}, res)\n        catch\n          kind, reason ->\n            app = dep.app\n\n            Mix.shell().error(\n              \"could not compile dependency #{inspect(app)}, \\\"mix compile\\\" failed. \" <>\n                deps_compile_feedback(app)\n            )\n\n            :erlang.raise(kind, reason, __STACKTRACE__)\n        end\n      end)\n    end)\n  end\n\n  defp do_rebar3(%Mix.Dep{opts: opts, manager: manager} = dep, config) do\n    if not Mix.Rebar.available?(manager) do\n      Mix.Tasks.Local.Rebar.run([\"--force\"])\n    end\n\n    dep_path = opts[:dest]\n    build_path = opts[:build]\n    File.mkdir_p!(build_path)\n\n    # For Rebar3, we need to copy the source/ebin to the target/ebin\n    # before we run the command given that REBAR_BARE_COMPILER_OUTPUT_DIR\n    # writes directly to _build.\n    File.cp_r(Path.join(dep_path, \"ebin\"), Path.join(build_path, \"ebin\"))\n\n    # Now establish symlinks to the remaining sources\n    for dir <- ~w(include priv src) do\n      Mix.Utils.symlink_or_copy(Path.join(dep_path, dir), Path.join(build_path, dir))\n    end\n\n    # Build the rebar config and setup the command line\n    config_path = Path.join(build_path, \"mix.rebar.config\")\n    lib_path = Path.join(config[:deps_build_path], \"lib/*/ebin\")\n    File.write!(config_path, rebar_config(dep))\n\n    env = [\n      # REBAR_BARE_COMPILER_OUTPUT_DIR is only honored by rebar3 >= 3.14\n      {\"REBAR_BARE_COMPILER_OUTPUT_DIR\", build_path},\n      {\"REBAR_SKIP_PROJECT_PLUGINS\", \"true\"},\n      {\"REBAR_CONFIG\", config_path},\n      {\"REBAR_PROFILE\", \"prod\"},\n      {\"TERM\", \"dumb\"}\n    ]\n\n    {exec, args} = Mix.Rebar.rebar_args(:rebar3, [\"bare\", \"compile\", \"--paths\", lib_path])\n\n    if Mix.shell().cmd({exec, args}, opts_for_cmd(dep, config, env)) != 0 do\n      Mix.raise(\n        \"Could not compile dependency #{inspect(dep.app)}, \\\"#{Enum.join([exec | args], \" \")}\\\" command failed. \" <>\n          deps_compile_feedback(dep.app)\n      )\n    end\n\n    # Check if we have any new symlinks after compilation\n    for dir <- ~w(include priv src),\n        File.exists?(Path.join(dep_path, dir)) and not File.exists?(Path.join(build_path, dir)) do\n      Mix.Utils.symlink_or_copy(Path.join(dep_path, dir), Path.join(build_path, dir))\n    end\n\n    Code.prepend_path(Path.join(build_path, \"ebin\"), cache: true)\n    true\n  end\n\n  defp rebar_config(dep) do\n    dep.extra\n    |> Mix.Rebar.dependency_config()\n    |> Mix.Rebar.serialize_config()\n  end\n\n  defp do_make(dep, config) do\n    command = make_command(dep)\n    shell_cmd!(dep, config, command, [{\"IS_DEP\", \"1\"}])\n    build_symlink_structure(dep, config)\n    true\n  end\n\n  defp make_command(dep) do\n    makefile_win? = makefile_win?(dep)\n\n    command =\n      case :os.type() do\n        {:win32, _} when makefile_win? ->\n          \"nmake /F Makefile.win\"\n\n        {:unix, type} when type in [:dragonfly, :freebsd, :netbsd, :openbsd] ->\n          \"gmake\"\n\n        _ ->\n          \"make\"\n      end\n\n    if erlang_mk?(dep) do\n      \"#{command} clean && #{command}\"\n    else\n      command\n    end\n  end\n\n  defp do_compile(%Mix.Dep{opts: opts} = dep, config) do\n    if command = opts[:compile] do\n      shell_cmd!(dep, config, command)\n      build_symlink_structure(dep, config)\n      true\n    else\n      false\n    end\n  end\n\n  defp shell_cmd!(%Mix.Dep{app: app} = dep, config, command, env \\\\ []) do\n    if Mix.shell().cmd(command, [print_app: true] ++ opts_for_cmd(dep, config, env)) != 0 do\n      Mix.raise(\n        \"Could not compile dependency #{inspect(app)}, \\\"#{command}\\\" command failed. \" <>\n          deps_compile_feedback(app)\n      )\n    end\n\n    :ok\n  end\n\n  defp opts_for_cmd(dep, config, env) do\n    %Mix.Dep{system_env: system_env, opts: opts} = dep\n    env = [{\"ERL_LIBS\", Path.join(config[:deps_build_path], \"lib\")} | system_env] ++ env\n    [env: env, cd: opts[:dest]]\n  end\n\n  defp build_symlink_structure(%Mix.Dep{opts: opts}, config) do\n    config = Keyword.put(config, :deps_app_path, opts[:build])\n    Mix.Project.build_structure(config, symlink_ebin: true, source: opts[:dest])\n    Code.prepend_path(Path.join(opts[:build], \"ebin\"), cache: true)\n  end\n\n  defp old_elixir_req(config) do\n    req = config[:elixir]\n\n    if req && not Version.match?(System.version(), req) do\n      req\n    end\n  end\n\n  defp erlang_mk?(%Mix.Dep{opts: opts}) do\n    File.regular?(Path.join(opts[:dest], \"erlang.mk\"))\n  end\n\n  defp makefile_win?(%Mix.Dep{opts: opts}) do\n    File.regular?(Path.join(opts[:dest], \"Makefile.win\"))\n  end\n\n  defp reject_umbrella_children(deps, options) do\n    if options[:skip_umbrella_children] do\n      Enum.reject(deps, fn %{opts: opts} -> Keyword.get(opts, :from_umbrella) == true end)\n    else\n      deps\n    end\n  end\n\n  defp filter_available_and_local_deps(deps) do\n    Enum.filter(deps, fn dep ->\n      Mix.Dep.available?(dep) or not dep.scm.fetchable?()\n    end)\n  end\n\n  defp reject_local_deps(deps, options) do\n    if options[:skip_local_deps] do\n      Enum.filter(deps, fn %{scm: scm} -> scm.fetchable?() end)\n    else\n      deps\n    end\n  end\n\n  defp deps_compile_feedback(app) do\n    if Mix.install?() do\n      \"Errors may have been logged above. You may run Mix.install/2 to try again or \" <>\n        \"change the arguments to Mix.install/2 to try another version\"\n    else\n      \"Errors may have been logged above. You can recompile this dependency with \" <>\n        \"\\\"mix deps.compile #{app} --force\\\", update it with \\\"mix deps.update #{app}\\\" or \" <>\n        \"clean it with \\\"mix deps.clean #{app}\\\"\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps do\n  use Mix.Task\n\n  import Mix.Dep, only: [format_dep: 1, format_status: 1, check_lock: 1]\n\n  @shortdoc \"Lists dependencies and their status\"\n\n  @moduledoc ~S\"\"\"\n  Lists dependencies and their status.\n\n  Dependencies must be specified in the `mix.exs` file in one of\n  the following formats:\n\n      {app, requirement}\n      {app, opts}\n      {app, requirement, opts}\n\n  Where:\n\n    * app is an atom\n    * requirement is a `Version` requirement or a regular expression\n    * opts is a keyword list of options\n\n  For example:\n\n      {:plug, \">= 0.4.0\"}\n      {:gettext, git: \"https://github.com/elixir-lang/gettext.git\", tag: \"0.1\"}\n      {:local_dependency, path: \"path/to/local_dependency\"}\n\n  By default, dependencies are fetched using the [Hex package manager](https://hex.pm/):\n\n      {:plug, \">= 0.4.0\"}\n\n  By specifying such dependencies, Mix will automatically install\n  Hex (if it wasn't previously installed) and download a package\n  suitable to your project. Note Hex expects the dependency\n  requirement to always be given and it will warn otherwise.\n\n  Mix also supports Git and path dependencies:\n\n      {:foobar, git: \"https://github.com/elixir-lang/foobar.git\", tag: \"0.1\"}\n      {:foobar, path: \"path/to/foobar\"}\n\n  And also in umbrella dependencies:\n\n      {:my_app, in_umbrella: true}\n\n  Path and in umbrella dependencies are automatically recompiled by\n  the parent project whenever they change. While fetchable dependencies,\n  like the ones using `:git`, are recompiled only when fetched/updated.\n\n  The dependencies' versions are expected to be formatted according to\n  Semantic Versioning and the requirements must be specified as defined\n  in the `Version` module.\n\n  ## Options\n\n  Below we provide a more detailed look into the available options.\n\n  ### Dependency definition options\n\n    * `:app` - when set to `false`, does not read the app file for this\n      dependency. By default, the app file is read\n\n    * `:env` - the environment (as an atom) to run the dependency on.\n      While your current project runs in `:dev` by default, dependencies\n      defaults to `:prod` (except for `:in_umbrella` dependencies, see\n      below)\n\n    * `:compile` - a command (string) to compile the dependency; defaults to a `mix`,\n      `rebar` or `make` command\n\n    * `:optional` - marks the dependency as optional. In such cases, the\n      current project will always include the optional dependency but any\n      other project that depends on the current project won't be forced to\n      use the optional dependency. However, if the other project includes\n      the optional dependency on its own, the requirements and options\n      specified here will also be applied. Optional dependencies will _not_\n      be started by the application. You should consider compiling your\n      projects with the `mix compile --no-optional-deps --warnings-as-errors`\n      during test, to ensure your project compiles without warnings even\n      if optional dependencies are missing\n\n    * `:only` - the dependency is made available only in the given environments,\n      useful when declaring dev- or test-only dependencies; by default the\n      dependency will be available in all environments. The value of this option\n      can either be a single environment (like `:dev`) or a list of environments\n      (like `[:dev, :test]`). Keep in mind that your project runs in the `:dev`\n      environment by default, however, all of your dependencies run in the `:prod`\n      environment (unless the `:env` option above is given)\n\n    * `:targets` - the dependency is made available only for the given targets.\n      By default the dependency will be available in all targets. The value\n      of this option can either be a single target (like `:host`) or a list of\n      targets (like `[:host, :rpi3]`)\n\n    * `:override` - if set to `true` the dependency will override any other\n      definitions of itself by other dependencies. From Elixir v1.20.0,\n      this option can also be a list of dependency names, which allows you to\n      override the definition of specific dependencies. If a dependency is not\n      included in the list and an override is required, it will still fail.\n      If a dependency is in the list and no longer necessary, then an error is emitted\n\n    * `:manager` - Mix can also compile Rebar3 and makefile projects\n      and can fetch sub dependencies of Rebar3 projects. Mix will\n      try to infer the type of project but it can be overridden with this\n      option by setting it to `:mix`, `:rebar3`, or `:make`. In case\n      there are conflicting definitions, the first manager in the list above\n      will be picked up. For example, if a dependency is found with `:rebar3`\n      as a manager in different part of the trees, `:rebar3` will be automatically\n      picked. You can find the manager by running `mix deps` and override it by\n      setting the `:override` option in a top-level project.\n\n    * `:runtime` - whether the dependency is part of runtime applications.\n      If the `:applications` key is not provided in `def application` in your\n      `mix.exs` file, Mix will automatically include all dependencies as a runtime\n      application, except if `runtime: false` is given. Defaults to `true`.\n\n    * `:system_env` - an enumerable of key-value tuples of binaries to be set\n      as environment variables when loading or compiling the dependency\n\n  When a project is used as a dependency, it runs by default in the `:prod`\n  environment. Therefore, if your project has dependencies that are only\n  useful in development or testing, you want to specify those dependencies with\n  the `:only` option above. You can also specify `:optional` dependencies\n  in your project, which are not enforced upon users of your library, as outlined\n  above. Finally, the [lockfile](`Mix.Project#module-configuration`) (usually\n  named `mix.lock`) is ignored when a project is used as a dependency.\n\n  ### Git options (`:git`)\n\n    * `:git` - the Git repository URI\n    * `:github` - a shortcut for specifying Git repos from GitHub, uses `:git`\n    * `:ref` - the reference to checkout (may be a branch, a commit SHA or a tag)\n    * `:branch` - the Git branch to checkout\n    * `:tag` - the Git tag to checkout\n    * `:submodules` - when `true`, initialize submodules for the repo\n    * `:sparse` - checkout a single directory inside the Git repository and use it\n      as your Mix dependency. Search \"sparse Git checkouts\" for more information.\n    * `:subdir` *(since v1.13.0)* - search for the project in the given directory\n      relative to the git checkout. This is similar to `:sparse` option but instead\n      of a doing a sparse checkout it does a full checkout.\n    * `:depth` *(since v1.17.0)* - creates a shallow clone of the Git repository,\n      limiting the history to the specified number of commits. This can significantly\n      improve clone speed for large repositories when full history is not needed.\n      The value must be a positive integer, typically `1`. When using `:depth` with\n      `:ref`, a fully spelled hex object name (a 40-character SHA-1 hash) is required.\n\n  If your Git repository requires authentication, such as basic username:password\n  HTTP authentication via URLs, it can be achieved via Git configuration, keeping\n  the access rules outside of source control.\n\n      $ git config --global url.\"https://YOUR_USER:YOUR_PASS@example.com/\".insteadOf \"https://example.com/\"\n\n  For more information, see the `git config` documentation:\n  https://git-scm.com/docs/git-config#Documentation/git-config.txt-urlltbasegtinsteadOf\n\n  ### Path options (`:path`)\n\n    * `:path` - the path for the dependency\n    * `:in_umbrella` - when `true`, sets a path dependency pointing to\n      `\"../#{app}\"`, sharing the same environment as the current application\n\n  ### Hex options (`:hex`)\n\n    * `:hex` - the name of the package, which defaults to the application name\n    * `:repo` - the repository to fetch the package from, used by remote or\n      private repositories. Defaults to the global \"hexpm\" repository\n    * `:warn_if_outdated` - warn if there is a more recent version of the package\n      published on Hex.pm\n\n  ## Deps task\n\n  The `mix deps` task lists dependencies in the following format:\n\n      APP VERSION (SCM) (MANAGER)\n      [locked at REF]\n      STATUS\n\n  For dependencies satisfied by Hex, `REF` is the package checksum.\n\n  For dependencies satisfied by git, `REF` is the commit object name,\n  and may include branch or tag information.\n\n  It supports the following options:\n\n    * `--all` - lists all dependencies, regardless of specified environment\n\n  ### Listing specific dependencies (since v1.20.0)\n\n  Pass dependency names as arguments to filter the output:\n\n      $ mix deps phoenix phoenix_live_view\n\n  This is particularly useful when you need to quickly check versions for\n  bug reports or similar tasks.\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    {opts, apps, _} = OptionParser.parse(args, switches: [all: :boolean])\n    loaded_opts = if opts[:all], do: [], else: [env: Mix.env(), target: Mix.target()]\n\n    deps = Mix.Dep.Converger.converge(loaded_opts)\n\n    apps =\n      apps\n      |> Enum.map(&String.to_atom/1)\n      |> Enum.uniq()\n\n    # Sort deps when showing all or preserve input order when filtering\n    {deps, unknown} =\n      if apps == [] do\n        {Enum.sort_by(deps, & &1.app), []}\n      else\n        filter(deps, apps)\n      end\n\n    shell = Mix.shell()\n\n    Enum.each(deps, fn dep ->\n      %Mix.Dep{scm: scm, manager: manager} = dep\n      dep = check_lock(dep)\n      extra = if manager, do: \" (#{manager})\", else: \"\"\n\n      shell.info(\"* #{format_dep(dep)}#{extra}\")\n\n      if formatted = scm.format_lock(dep.opts) do\n        shell.info(\"  locked at #{formatted}\")\n      end\n\n      shell.info(\"  #{format_status(dep)}\")\n    end)\n\n    # Warnings are displayed at the end for visibility\n    for app <- unknown do\n      shell.error(\"warning: unknown dependency #{app}\")\n    end\n  end\n\n  defp filter(deps, apps) do\n    selected_deps =\n      Enum.flat_map(apps, fn app -> List.wrap(Enum.find(deps, &(&1.app == app))) end)\n\n    unknown_apps = apps -- Enum.map(selected_deps, & &1.app)\n\n    {selected_deps, unknown_apps}\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.get.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps.Get do\n  use Mix.Task\n\n  @shortdoc \"Fetches unavailable and out of date dependencies\"\n\n  @moduledoc \"\"\"\n  Fetches unavailable and out of date dependencies.\n\n  ## Command line options\n\n    * `--check-locked` - raises if there are pending changes to the lockfile\n    * `--no-archives-check` - does not check archives before fetching deps\n    * `--only` - only fetches dependencies for given environment\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    if \"--no-archives-check\" not in args do\n      Mix.Task.run(\"archive.check\", args)\n    end\n\n    Mix.Project.get!()\n\n    {opts, _, _} =\n      OptionParser.parse(args, switches: [only: :string, target: :string, check_locked: :boolean])\n\n    Mix.Project.with_deps_lock(fn ->\n      do_run(opts)\n    end)\n  end\n\n  defp do_run(opts) do\n    fetch_opts =\n      for {switch, key} <- [only: :env, target: :target, check_locked: :check_locked],\n          value = opts[switch],\n          do: {key, :\"#{value}\"}\n\n    apps = Mix.Dep.Fetcher.all(%{}, Mix.Dep.Lock.read(), fetch_opts)\n\n    if apps == [] do\n      Mix.shell().info(\"All dependencies have been fetched\")\n    else\n      :ok\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.loadpaths.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps.Loadpaths do\n  use Mix.Task\n\n  import Mix.Dep, only: [format_dep: 1, format_status: 1, check_lock: 1]\n\n  @moduledoc \"\"\"\n  Checks, compiles, and loads dependencies.\n\n  If a dependency has been fetched/updated and not yet compiled,\n  it will be automatically compiled. If a dependency is missing\n  or is invalid, its status is printed before aborting.\n\n  Although this task does not show up in `mix help`, it is\n  part of Mix public API and can be depended on.\n\n  ## Configuration\n\n    * `:listeners` - the list of listener modules. For more details\n      see `Mix.Task.Compiler`\n\n  ## Command line options\n\n    * `--no-archives-check` - does not check archives\n    * `--no-compile` - does not compile even if files require compilation\n    * `--no-deps-check` - does not check or compile deps, only load available ones\n    * `--no-elixir-version-check` - does not check Elixir version\n    * `--no-listeners` - does not start Mix listeners\n    * `--no-optional-deps` - does not compile or load optional deps\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    # Note that we need to ensure the dependencies are compiled first,\n    # before we can start the pub/sub listeners, since those come from\n    # the dependencies. Theoretically, between compiling dependencies\n    # and starting the listeners, there may be a concurrent compilation\n    # of the dependencies, which we would miss, and we would already\n    # have modules from our compilation loaded. To avoid this race\n    # condition we start the pub/sub beforehand and we accumulate all\n    # events until the listeners are started. Alternatively we could\n    # use a lock around compilation and sterning the listeners, however\n    # the added benefit of the current approach is that we consistently\n    # receive events for all dependency compilations. Also, if we ever\n    # decide to start the listeners later (e.g. after loadspaths), the\n    # accumulation approach still works.\n    Mix.PubSub.start()\n\n    if \"--no-archives-check\" not in args do\n      Mix.Task.run(\"archive.check\", args)\n    end\n\n    config = Mix.Project.config()\n\n    if \"--no-elixir-version-check\" not in args do\n      check_elixir_version(config)\n    end\n\n    all = Mix.Dep.load_and_cache()\n\n    all =\n      if \"--no-optional-deps\" in args do\n        for dep <- all, dep.opts[:optional] != true, do: dep\n      else\n        all\n      end\n\n    if \"--no-deps-check\" not in args do\n      deps_check(config, all, \"--no-compile\" in args)\n    end\n\n    Code.prepend_paths(Enum.flat_map(all, &Mix.Dep.load_paths/1), cache: true)\n\n    # For now we only allow listeners defined in dependencies,\n    # so we start them right after adding adding deps to the path,\n    # as long as we are sure they have been compiled\n    if \"--listeners\" in args or\n         (\"--no-listeners\" not in args and \"--no-deps-check\" not in args) do\n      Mix.PubSub.start_listeners()\n    end\n\n    :ok\n  end\n\n  defp check_elixir_version(config) do\n    if req = config[:elixir] do\n      case Version.parse_requirement(req) do\n        {:ok, req} ->\n          if not Version.match?(System.version(), req) do\n            raise Mix.ElixirVersionError,\n              target: config[:app] || Mix.Project.get(),\n              expected: req,\n              actual: System.version()\n          end\n\n        :error ->\n          Mix.raise(\"Invalid Elixir version requirement #{req} in mix.exs file\")\n      end\n    end\n  end\n\n  defp deps_check(config, all, no_compile?) do\n    with {:compile, _to_compile} <- deps_check(all, no_compile?) do\n      # We need to compile, we first grab the lock, then, we check\n      # again and compile if still applicable\n      Mix.Project.with_build_lock(config, fn ->\n        all = reload_deps(all)\n\n        with {:compile, to_compile} <- deps_check(all, no_compile?) do\n          Mix.Tasks.Deps.Compile.compile(to_compile)\n\n          to_compile\n          |> reload_deps()\n          |> Enum.filter(&(not Mix.Dep.ok?(&1)))\n          |> show_not_ok!()\n        end\n      end)\n    end\n  end\n\n  defp deps_check(all, no_compile?) do\n    all =\n      all\n      |> Task.async_stream(&check_lock/1, ordered: true, timeout: :infinity)\n      |> Enum.map(fn {:ok, dep} -> dep end)\n\n    {not_ok, to_compile} = partition(all, [], [])\n\n    cond do\n      not_ok != [] ->\n        show_not_ok!(not_ok)\n\n      to_compile == [] or no_compile? ->\n        :ok\n\n      true ->\n        {:compile, to_compile}\n    end\n  end\n\n  defp partition([dep | deps], not_ok, compile) do\n    cond do\n      Mix.Dep.compilable?(dep) or (Mix.Dep.ok?(dep) and local?(dep)) ->\n        if from_umbrella?(dep) do\n          partition(deps, not_ok, compile)\n        else\n          partition(deps, not_ok, [dep | compile])\n        end\n\n      Mix.Dep.ok?(dep) ->\n        partition(deps, not_ok, compile)\n\n      true ->\n        partition(deps, [dep | not_ok], compile)\n    end\n  end\n\n  defp partition([], not_ok, compile) do\n    {Enum.reverse(not_ok), Enum.reverse(compile)}\n  end\n\n  # Children from the umbrella are compiled sequentially by the umbrella project itself.\n  # We could start compiling them as dependencies, and therefore in parallel, but because\n  # `mix compile` in an umbrella is expected to return the diagnostics of all children,\n  # we would need a pass after compilation to compite diagnostics.\n  defp from_umbrella?(dep) do\n    dep.opts[:from_umbrella]\n  end\n\n  defp reload_deps(deps) do\n    deps\n    |> Enum.map(& &1.app)\n    |> Mix.Dep.filter_by_name(Mix.Dep.load_and_cache())\n  end\n\n  # Every local dependency (i.e. that are not fetchable)\n  # are automatically recompiled if they are ok.\n  defp local?(dep) do\n    not dep.scm.fetchable?()\n  end\n\n  defp show_not_ok!([]) do\n    :ok\n  end\n\n  defp show_not_ok!(deps) do\n    shell = Mix.shell()\n    shell.error(\"Unchecked dependencies for environment #{Mix.env()}:\")\n\n    Enum.each(deps, fn dep ->\n      shell.error(\"* #{format_dep(dep)}\")\n      shell.error(\"  #{format_status(dep)}\")\n    end)\n\n    Mix.raise(\"Can't continue due to errors on dependencies\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.partition.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Mix.Tasks.Deps.Partition do\n  @moduledoc false\n  use Mix.Task\n\n  ## Server\n\n  def server(deps, count, force?) do\n    {:ok, socket} = :gen_tcp.listen(0, [:binary, packet: :line, active: false])\n\n    try do\n      server(socket, deps, count, force?)\n    after\n      :gen_tcp.close(socket)\n    end\n  end\n\n  defp server(socket, deps, count, force?) do\n    elixir =\n      System.get_env(\"MIX_OS_DEPS_COMPILE_PARTITION_ELIXIR_EXECUTABLE\") ||\n        System.find_executable(\"elixir\") ||\n        raise \"cannot find elixir executable for partition compilation\"\n\n    {:ok, {_ip, port}} = :inet.sockname(socket)\n    ansi_flag = if IO.ANSI.enabled?(), do: ~c\"--color\", else: ~c\"--no-color\"\n    force_flag = if force?, do: ~c\"--force\", else: ~c\"--no-force\"\n    config = Mix.ProjectStack.peek() |> :erlang.term_to_binary() |> Base.url_encode64()\n    tmp_dir = System.tmp_dir()\n\n    {config_flag, config_value} =\n      with true <- is_binary(tmp_dir),\n           partition_dir = Path.join(tmp_dir, \"mix_deps_partition\"),\n           :ok <- File.mkdir_p(partition_dir),\n           partition_file = Path.join(partition_dir, Base.encode32(:crypto.strong_rand_bytes(10))),\n           :ok <- File.write(partition_file, config) do\n        {~c\"--config-file\", String.to_charlist(partition_file)}\n      else\n        _ -> {~c\"--config\", String.to_charlist(config)}\n      end\n\n    args =\n      [\n        ansi_flag,\n        ~c\"-e\",\n        ~c\"Mix.Tasks.Deps.Partition.client\",\n        ~c\"--\",\n        force_flag,\n        ~c\"--port\",\n        Integer.to_charlist(port),\n        ~c\"--host\",\n        ~c\"127.0.0.1\",\n        config_flag,\n        config_value\n      ]\n\n    options = [\n      :exit_status,\n      :binary,\n      :hide,\n      :use_stdio,\n      :stderr_to_stdout,\n      line: 1_000_000,\n      env: [\n        {~c\"MIX_OS_CONCURRENCY_LOCK\", ~c\"false\"},\n        {~c\"MIX_ENV\", Atom.to_charlist(Mix.env())},\n        {~c\"MIX_TARGET\", Atom.to_charlist(Mix.target())}\n      ]\n    ]\n\n    if Mix.debug?() do\n      IO.puts(\"-> mix deps.partition args: #{Enum.join(args, \" \")}\")\n    end\n\n    ports =\n      Map.new(1..count//1, fn index ->\n        if Mix.debug?() do\n          IO.puts(\"-> Starting mix deps.partition ##{index}\")\n        end\n\n        args = args ++ [~c\"--index\", Integer.to_charlist(index)]\n        port = Port.open({:spawn_executable, String.to_charlist(elixir)}, [args: args] ++ options)\n\n        {index, port}\n      end)\n\n    clients =\n      Enum.map(1..count//1, fn _ ->\n        with {:ok, client} <- :gen_tcp.accept(socket, 15_000),\n             {:ok, message} <- :gen_tcp.recv(client, 0, 15_000) do\n          :inet.setopts(client, active: true)\n          index = message |> String.trim() |> String.to_integer()\n          %{port: Map.fetch!(ports, index), index: index, socket: client}\n        else\n          error ->\n            logs =\n              Enum.map_join(ports, \"\\n\", fn {index, port} -> close_port(port, \"#{index} >\") end)\n\n            Mix.raise(\"\"\"\n            could not start partition dependency compiler, no connection made to TCP port: #{inspect(error)}\n\n            #{logs}\n            \"\"\")\n        end\n      end)\n\n    status = Map.new(deps, &{&1.app, :pending})\n    send_deps_and_server_loop(clients, [], deps, status)\n  end\n\n  defp send_deps_and_server_loop(available, busy, deps, status) do\n    {available, busy, deps} = send_deps(available, busy, deps, status)\n    server_loop(available, busy, deps, status)\n  end\n\n  defp send_deps([client | available], busy, deps, status) do\n    case pop_with(deps, fn dep ->\n           Enum.all?(dep.deps, &(Map.get(status, &1.app, :unknown) != :pending))\n         end) do\n      :error ->\n        {[client | available], busy, deps}\n\n      {dep, deps} ->\n        if Mix.debug?() do\n          Mix.shell().info(\"-- Sending #{dep.app} to mix deps.partition #{client.index}\")\n        end\n\n        :gen_tcp.send(client.socket, \"#{dep.app}\\n\")\n        send_deps(available, [client | busy], deps, status)\n    end\n  end\n\n  defp send_deps([], busy, deps, _status) do\n    {[], busy, deps}\n  end\n\n  defp server_loop(available, _busy = [], _deps = [], status) do\n    shutdown_clients(available)\n    Enum.any?(status, &(elem(&1, 1) == true))\n  end\n\n  defp server_loop(available, busy, deps, status) do\n    receive do\n      {:tcp, socket, data} ->\n        [app, compiled?] =\n          data |> String.trim() |> String.split(\":\") |> Enum.map(&String.to_atom/1)\n\n        deps = Enum.reject(deps, &(&1.app == app))\n        status = Map.replace!(status, app, compiled?)\n        {client, busy} = pop_with(busy, &(&1.socket == socket))\n\n        if Mix.debug?() do\n          Mix.shell().info(\"-- mix deps.partition #{client.index} compiled #{app}\")\n        end\n\n        send_deps_and_server_loop([client | available], busy, deps, status)\n\n      {:tcp_closed, socket} ->\n        tcp_failed!(\"closed unexpectedly\", socket, available, busy)\n\n      {:tcp_error, socket, error} ->\n        tcp_failed!(\"errored: #{inspect(error)}\", socket, available, busy)\n\n      {port, {:data, {eol, data}}} ->\n        with %{index: index} <-\n               Enum.find(busy, &(&1.port == port)) || Enum.find(available, &(&1.port == port)) do\n          terminator = if eol == :eol, do: \"\\n\", else: \"\"\n          IO.write([Integer.to_string(index), \"> \", data, terminator])\n        end\n\n        server_loop(available, busy, deps, status)\n    end\n  end\n\n  defp pop_with(list, fun) do\n    case Enum.split_while(list, &(not fun.(&1))) do\n      {_, []} -> :error\n      {pre, [result | post]} -> {result, pre ++ post}\n    end\n  end\n\n  defp tcp_failed!(message, socket, available, busy) do\n    {%{port: port} = client, busy} = pop_with(busy, &(&1.socket == socket))\n\n    # Let's make sure it has all been written out\n    # but don't wait for more than 5 seconds if it\n    # gets stuck for some unknown reason\n    receive do\n      {^port, {:exit_status, _}} -> :ok\n    after\n      5_000 -> Mix.shell().error(\"Timed out waiting for port exit #{inspect(port)}\")\n    end\n\n    shutdown_clients(available ++ busy ++ [client])\n\n    Mix.raise(\n      \"mix deps.partition #{inspect(socket)} #{message} \" <>\n        \"(set MIX_OS_DEPS_COMPILE_PARTITION_COUNT=1 to run in serial)\"\n    )\n  end\n\n  defp shutdown_clients(clients) do\n    Enum.each(clients, fn %{socket: socket, port: port, index: index} ->\n      if Mix.debug?() do\n        IO.puts(\"-> Closing mix deps.partition ##{index}\")\n      end\n\n      _ = :gen_tcp.close(socket)\n      IO.write(close_port(port, \"#{index}> \"))\n    end)\n  end\n\n  defp close_port(port, prefix) do\n    try do\n      Port.close(port)\n    catch\n      _, _ -> :ok\n    end\n\n    loop_close_port(port, prefix)\n  end\n\n  defp loop_close_port(port, prefix) do\n    receive do\n      {^port, {:data, {:eol, data}}} -> [prefix, data, ?\\n | loop_close_port(port, prefix)]\n      {^port, {:data, {:noeol, data}}} -> [data | loop_close_port(port, prefix)]\n      {^port, {:exit_status, _}} -> loop_close_port(port, prefix)\n    after\n      0 -> []\n    end\n  end\n\n  ## Client\n\n  @switches [\n    port: :integer,\n    host: :string,\n    force: :boolean,\n    index: :string,\n    config: :string,\n    config_file: :string\n  ]\n\n  def client do\n    # If stdin closes, we shutdown the VM\n    spawn(fn ->\n      _ = IO.gets(\"\")\n      System.halt(0)\n    end)\n\n    args = System.argv()\n    {opts, []} = OptionParser.parse!(args, strict: @switches)\n\n    peek =\n      if config_file = Keyword.get(opts, :config_file) do\n        File.read!(config_file)\n      else\n        Keyword.fetch!(opts, :config)\n      end\n      |> Base.url_decode64!()\n      |> :erlang.binary_to_term()\n\n    # This is specific to Mix.install/2 and how it handles compile-time config\n    if compile_config = peek.config[:compile_config] do\n      Application.put_all_env(compile_config, persistent: true)\n    end\n\n    partition_args =\n      opts\n      |> Keyword.take([:host, :port, :index, :force])\n      |> OptionParser.to_argv()\n\n    Mix.start()\n    Mix.ProjectStack.push(peek.name, peek.config, peek.file)\n    Mix.CLI.main([\"deps.partition\" | partition_args], nil)\n  end\n\n  @impl true\n  def run(args) do\n    {opts, []} = OptionParser.parse!(args, strict: @switches)\n    host = Keyword.fetch!(opts, :host)\n    port = Keyword.fetch!(opts, :port)\n    index = Keyword.fetch!(opts, :index)\n    force? = Keyword.get(opts, :force, false)\n\n    {:ok, socket} =\n      :gen_tcp.connect(String.to_charlist(host), port, [:binary, packet: :line, active: false])\n\n    :gen_tcp.send(socket, \"#{index}\\n\")\n\n    try do\n      deps = Mix.Dep.load_and_cache()\n      client_loop(socket, deps, force?, Mix.Project.deps_config())\n    after\n      :gen_tcp.close(socket)\n    end\n  end\n\n  def client_loop(socket, deps, force?, config) do\n    case :gen_tcp.recv(socket, 0, :infinity) do\n      {:ok, app} ->\n        app = app |> String.trim() |> String.to_atom()\n\n        dep =\n          Enum.find(deps, &(&1.app == app)) || raise \"could not find dependency #{inspect(app)}\"\n\n        compiled? = Mix.Tasks.Deps.Compile.compile_single(dep, force?, config)\n        :ok = :gen_tcp.send(socket, \"#{app}:#{compiled?}\\n\")\n        client_loop(socket, deps, force?, config)\n\n      {:error, :closed} ->\n        :ok\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.precompile.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps.Precompile do\n  use Mix.Task\n\n  @moduledoc \"\"\"\n  Extension point for precompiling dependencies.\n\n  This is a task that can be aliased by projects\n  that need to execute certain tasks before\n  compiling dependencies:\n\n      aliases: [\"deps.precompile\": [\"nerves.precompile\", \"deps.precompile\"]]\n\n  \"\"\"\n\n  @impl true\n  def run(_) do\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.tree.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps.Tree do\n  use Mix.Task\n\n  @shortdoc \"Prints the dependency tree\"\n  @recursive true\n\n  @moduledoc \"\"\"\n  Prints the dependency tree.\n\n      $ mix deps.tree\n\n  If no dependency is given, it uses the tree defined in the `mix.exs` file.\n\n  ## Command line options\n\n    * `--only` - the environment to show dependencies for.\n\n    * `--target` - the target to show dependencies for.\n\n    * `--exclude` - exclude dependencies which you do not want to see printed. You can\n      pass this flag multiple times to exclude multiple dependencies.\n\n    * `--umbrella-only` *(since v1.17.0)* - only include the umbrella applications.\n      This is useful when you have an umbrella project and want to see the\n      relationship between the apps in the project.\n\n    * `--format` - can be set to one of either:\n\n      * `pretty` - uses Unicode code points for formatting the tree.\n        This is the default except on Windows.\n\n      * `plain` - does not use Unicode code points for formatting the tree.\n        This is the default on Windows.\n\n      * `dot` - produces a DOT graph description of the dependency tree\n        in `deps_tree.dot` in the current directory.\n        Warning: this will override any previously generated file.\n\n  ## Examples\n\n  Print the dependency tree for the `:test` environment:\n\n      $ mix deps.tree --only test\n\n  Exclude the `:ecto` and `:phoenix` dependencies:\n\n      $ mix deps.tree --exclude ecto --exclude phoenix\n\n  Only print the tree for the `:bandit` and `:phoenix` dependencies:\n\n      $ mix deps.tree --include bandit --include phoenix\n\n  \"\"\"\n\n  @switches [\n    only: :string,\n    target: :string,\n    exclude: :keep,\n    umbrella_only: :boolean,\n    format: :string\n  ]\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    {opts, args, _} = OptionParser.parse(args, switches: @switches)\n\n    deps_opts =\n      for {switch, key} <- [only: :env, target: :target],\n          value = opts[switch],\n          do: {key, :\"#{value}\"}\n\n    deps = Mix.Dep.Converger.converge(deps_opts)\n\n    root =\n      case args do\n        [] ->\n          Mix.Project.config()[:app] ||\n            Mix.raise(\"no application given and none found in mix.exs file\")\n\n        [app] ->\n          app = String.to_atom(app)\n          find_dep(deps, app) || Mix.raise(\"could not find dependency #{app}\")\n      end\n\n    if opts[:format] == \"dot\" do\n      callback = callback(&format_dot/1, deps, opts)\n      Mix.Utils.write_dot_graph!(\"deps_tree.dot\", \"dependency tree\", [root], callback, opts)\n\n      \"\"\"\n      Generated \"deps_tree.dot\" in the current directory. To generate a PNG:\n\n          dot -Tpng deps_tree.dot -o deps_tree.png\n\n      For more options see https://www.graphviz.org/.\n      \"\"\"\n      |> String.trim_trailing()\n      |> Mix.shell().info()\n    else\n      callback = callback(&format_tree/1, deps, opts)\n      Mix.Utils.print_tree([root], callback, opts)\n    end\n  end\n\n  defp callback(formatter, deps, opts) do\n    umbrella_only? = Keyword.get(opts, :umbrella_only, false)\n    excluded = Keyword.get_values(opts, :exclude) |> Enum.map(&String.to_atom/1)\n\n    if umbrella_only? && !Mix.Project.parent_umbrella_project_file() do\n      Mix.raise(\"The --umbrella-only option can only be used in umbrella projects\")\n    end\n\n    top_level = Enum.filter(deps, & &1.top_level)\n\n    fn\n      %Mix.Dep{app: app} = dep ->\n        # Do not show dependencies if they were\n        # already shown at the top level\n        deps =\n          if not dep.top_level && find_dep(top_level, app) do\n            []\n          else\n            find_dep(deps, app).deps\n          end\n\n        {formatter.(dep), select_and_sort(deps, excluded, umbrella_only?)}\n\n      app ->\n        {{Atom.to_string(app), nil}, select_and_sort(top_level, excluded, umbrella_only?)}\n    end\n  end\n\n  defp select_and_sort(deps, excluded, umbrella_only?) do\n    deps\n    |> filter_umbrella_only(umbrella_only?)\n    |> Enum.reject(&(&1.app in excluded))\n    |> Enum.sort_by(& &1.app)\n  end\n\n  defp filter_umbrella_only(deps, umbrella_only?) do\n    if umbrella_only? do\n      Enum.filter(deps, fn %Mix.Dep{opts: opts} -> opts[:in_umbrella] end)\n    else\n      deps\n    end\n  end\n\n  defp format_dot(%{app: app, requirement: requirement, opts: opts}) do\n    override =\n      if opts[:override] do\n        \" *override*\"\n      else\n        \"\"\n      end\n\n    requirement = requirement && requirement(requirement)\n    {app, \"#{requirement}#{override}\"}\n  end\n\n  defp format_tree(%{app: app, scm: scm, requirement: requirement, opts: opts}) do\n    override =\n      if opts[:override] do\n        IO.ANSI.format([:bright, \" *override*\"])\n      else\n        \"\"\n      end\n\n    requirement = requirement && \"#{requirement(requirement)} \"\n    {app, \"#{requirement}(#{scm.format(opts)})#{override}\"}\n  end\n\n  defp requirement(%Regex{} = regex), do: \"#{inspect(regex)}\"\n  defp requirement(binary) when is_binary(binary), do: binary\n\n  defp find_dep(deps, app) do\n    Enum.find(deps, &(&1.app == app))\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.unlock.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps.Unlock do\n  use Mix.Task\n\n  @shortdoc \"Unlocks the given dependencies\"\n\n  @moduledoc \"\"\"\n  Unlocks the given dependencies.\n\n  Since this is a destructive action, unlocking dependencies\n  only occurs when passing arguments/options:\n\n    * `dep1 dep2` - the name of dependencies to be unlocked\n    * `--all` - unlocks all dependencies\n    * `--filter` - unlocks only deps matching the given name\n    * `--unused` - unlocks only unused dependencies (no longer mentioned\n      in the `mix.exs` file)\n    * `--check-unused` - checks that the `mix.lock` file has no unused\n      dependencies. This is useful in pre-commit hooks and CI scripts\n      if you want to reject contributions with extra dependencies\n\n  \"\"\"\n\n  @switches [all: :boolean, check_unused: :boolean, unused: :boolean, filter: :string]\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    {opts, apps, _} = OptionParser.parse(args, switches: @switches)\n\n    Mix.Project.with_deps_lock(fn ->\n      do_run(opts, apps)\n    end)\n  end\n\n  defp do_run(opts, apps) do\n    cond do\n      opts[:all] ->\n        Mix.Dep.Lock.write(%{})\n\n      opts[:check_unused] ->\n        lock = Mix.Dep.Lock.read()\n        unused_apps = unused_apps(lock)\n\n        if unused_apps != [] do\n          Mix.raise(\"\"\"\n          Unused dependencies in mix.lock file:\n\n          #{Enum.map_join(unused_apps, \"\\n\", fn app -> \"  * #{inspect(app)}\" end)}\n          \"\"\")\n        end\n\n      opts[:unused] ->\n        lock = Mix.Dep.Lock.read()\n        unused_apps = unused_apps(lock)\n\n        if unused_apps != [] do\n          unlock(lock, unused_apps)\n        end\n\n      filter = opts[:filter] ->\n        lock = Mix.Dep.Lock.read()\n        apps = lock |> Map.keys() |> Enum.filter(&(Atom.to_string(&1) =~ filter))\n\n        if apps == [] do\n          Mix.shell().error(\"warning: no dependencies were matched\")\n        else\n          unlock(lock, apps)\n        end\n\n      apps != [] ->\n        lock = Mix.Dep.Lock.read()\n        apps = Enum.map(apps, &String.to_atom/1)\n        unlocked = apps -- Map.keys(lock)\n\n        for app <- unlocked do\n          Mix.shell().error(\"warning: #{app} dependency is not locked\")\n        end\n\n        unlock(lock, apps -- unlocked)\n\n      true ->\n        Mix.raise(\n          \"\\\"mix deps.unlock\\\" expects dependencies as arguments or \" <>\n            \"an option indicating which dependencies to unlock. \" <>\n            \"The --all option will unlock all dependencies while \" <>\n            \"the --unused option unlocks unused dependencies\"\n        )\n    end\n  end\n\n  defp unused_apps(lock) do\n    apps = Mix.Dep.Converger.converge([]) |> Enum.map(& &1.app)\n\n    lock\n    |> Map.drop(apps)\n    |> Map.keys()\n    |> Enum.sort()\n  end\n\n  defp unlock(lock, apps) do\n    if apps != [] do\n      lock |> Map.drop(apps) |> Mix.Dep.Lock.write()\n\n      Mix.shell().info(\"\"\"\n      Unlocked deps:\n      * #{Enum.join(apps, \"\\n* \")}\n      \"\"\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/deps.update.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Deps.Update do\n  use Mix.Task\n\n  @shortdoc \"Updates the given dependencies\"\n\n  @moduledoc \"\"\"\n  Updates the given dependencies.\n\n  The given dependencies and the projects they depend on will\n  be unlocked and updated to the latest version according to their\n  version requirements.\n\n  Since this is a destructive action, updating all dependencies\n  only occurs when the `--all` command line option is passed.\n\n  All dependencies are automatically recompiled after update.\n\n  ## mix deps.unlock + mix deps.get\n\n  Upgrading a dependency often requires the projects it depends on\n  to upgrade too. If you would rather update a single dependency and\n  not touch its children, you can explicitly unlock the single dependency\n  and run `mix deps.get`:\n\n      $ mix deps.unlock some_dep\n      $ mix deps.get\n\n  ## Command line options\n\n    * `--all` - updates all dependencies\n    * `--only` - only fetches dependencies for given environment\n    * `--target` - only fetches dependencies for given target\n    * `--no-archives-check` - does not check archives before fetching deps\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    if \"--no-archives-check\" not in args do\n      Mix.Task.run(\"archive.check\", args)\n    end\n\n    Mix.Project.get!()\n\n    {opts, rest, _} =\n      OptionParser.parse(args, switches: [all: :boolean, only: :string, target: :string])\n\n    Mix.Project.with_deps_lock(fn ->\n      do_run(opts, rest)\n    end)\n  end\n\n  defp do_run(opts, rest) do\n    fetch_opts =\n      for {switch, key} <- [only: :env, target: :target],\n          value = opts[switch],\n          do: {key, :\"#{value}\"}\n\n    cond do\n      opts[:all] ->\n        Mix.Dep.Fetcher.all(Mix.Dep.Lock.read(), %{}, fetch_opts)\n\n      rest != [] ->\n        {old, new} = Map.split(Mix.Dep.Lock.read(), to_app_names(rest))\n        Mix.Dep.Fetcher.by_name(rest, old, new, fetch_opts)\n\n      true ->\n        Mix.raise(\n          \"\\\"mix deps.update\\\" expects dependencies as arguments or \" <>\n            \"the --all option to update all dependencies\"\n        )\n    end\n  end\n\n  defp to_app_names(given) do\n    Enum.map(given, fn app ->\n      if is_binary(app), do: String.to_atom(app), else: app\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/do.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Do do\n  use Mix.Task\n\n  @shortdoc \"Executes the tasks separated by plus\"\n\n  @moduledoc \"\"\"\n  Executes the tasks separated by `+`, aborting if any task errors.\n\n  Here is an example:\n\n      $ mix do compile --list + deps\n\n  The plus should be followed by at least one space before and after.\n\n  ## Examples\n\n  The example below prints the available compilers and\n  then the list of dependencies.\n\n      $ mix do compile --list + deps\n\n  Note that the majority of Mix tasks are only executed once\n  per invocation. So for example, the following command will\n  only compile once:\n\n      $ mix do compile + some_other_command + compile\n\n  When `compile` is executed again, Mix will notice the task\n  has already ran, and skip it.\n\n  Inside umbrella projects, you can limit recursive tasks\n  (the ones that run inside every app) by selecting the\n  desired application via the `--app` flag after `do` and\n  before the first task:\n\n      $ mix do --app app1 --app app2 compile --list + deps\n\n  Elixir versions prior to v1.14 used the comma exclusively\n  to separate commands:\n\n      $ mix do compile --list, deps\n\n  Since then, the `+` operator has been introduced as a\n  separator for better support on Windows terminals.\n\n  ## Error handling\n\n  If any task in the list of tasks exits with an error,\n  no subsequent tasks will be run. For instance:\n\n      $ mix do compile + test\n\n  If the compilation step fails, the tests will not be\n  attempted.\n\n  ## Command line options\n\n    * `--app` - limit recursive tasks to the given apps.\n      This option may be given multiple times and must come\n      before any of the tasks.\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    Mix.Task.reenable(\"do\")\n\n    {apps, args} = extract_apps_from_args(args)\n    show_forgotten_apps_warning(apps)\n\n    Enum.each(gather_commands(args), fn\n      [task | args] ->\n        if apps == [] do\n          Mix.Task.run(task, args)\n        else\n          Mix.Task.run_in_apps(task, apps, args)\n        end\n\n      [] ->\n        Mix.raise(\"\"\"\n        One of the commands passed to \"mix do\" is empty. Each command passed to \"mix do\" must \\\n        have at least the task name. These are all invalid:\n\n          mix do\n          mix do my_task +\n          mix do + my_task\n\n        Run \"mix help do\" for more information.\n        \"\"\")\n    end)\n  end\n\n  defp show_forgotten_apps_warning([]), do: nil\n\n  defp show_forgotten_apps_warning(apps) do\n    config = Mix.Project.config()\n\n    if Mix.Project.umbrella?(config) do\n      known_apps = Mix.Project.apps_paths(config)\n\n      for app <- apps, not Map.has_key?(known_apps, app) do\n        Mix.shell().info([:yellow, \"warning: could not find application #{inspect(app)}\"])\n      end\n    end\n  end\n\n  defp extract_apps_from_args(args) do\n    {opts, args} = OptionParser.parse_head!(args, strict: [app: :keep])\n\n    apps =\n      opts\n      |> Keyword.get_values(:app)\n      |> Enum.map(&String.to_atom/1)\n\n    {apps, args}\n  end\n\n  @doc false\n  def gather_commands(args) do\n    gather_commands(args, [], [])\n  end\n\n  defp gather_commands([head | rest], current, acc)\n       when binary_part(head, byte_size(head), -1) == \",\" do\n    IO.warn(\n      \"using commas as separators in \\\"mix do\\\" is deprecated, use + between commands instead\"\n    )\n\n    current =\n      case binary_part(head, 0, byte_size(head) - 1) do\n        \"\" -> Enum.reverse(current)\n        part -> Enum.reverse([part | current])\n      end\n\n    gather_commands(rest, [], [current | acc])\n  end\n\n  defp gather_commands([\"+\" | rest], current, acc) do\n    gather_commands(rest, [], [Enum.reverse(current) | acc])\n  end\n\n  defp gather_commands([head | rest], current, acc) do\n    gather_commands(rest, [head | current], acc)\n  end\n\n  defp gather_commands([], current, acc) do\n    Enum.reverse([Enum.reverse(current) | acc])\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/escript.build.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Escript.Build do\n  use Mix.Task\n  import Bitwise, only: [|||: 2]\n\n  @shortdoc \"Builds an escript for the project\"\n  @recursive true\n\n  @moduledoc ~S\"\"\"\n  Builds an escript for the project.\n\n  An escript is an executable that can be invoked from the\n  command line. An escript can run on any machine that has\n  Erlang/OTP installed and by default does not require Elixir to\n  be installed, as Elixir is embedded as part of the escript.\n\n  This task guarantees the project and its dependencies are\n  compiled and packages them inside an escript. Before invoking\n  `mix escript.build`, it is only necessary to define a `:escript`\n  key with a `:main_module` option in your `mix.exs` file:\n\n      escript: [main_module: MyApp.CLI]\n\n  Escripts should be used as a mechanism to share scripts between\n  developers and not as a deployment mechanism. For running live\n  systems, consider using `mix run` or building releases. See\n  the `Application` module for more information on systems\n  life cycles.\n\n  All of the configuration defined in `config/config.exs` will\n  be included as part of the escript. `config/runtime.exs` is also\n  included for Elixir escripts. Once the configuration is loaded,\n  this task starts the current application. If this is not desired,\n  set the `:app` configuration to nil.\n\n  This task also removes documentation and debugging chunks from\n  the compiled `.beam` files to reduce the size of the escript.\n  If this is not desired, check the `:strip_beams` option.\n\n  ## Command line options\n\n  Expects the same command line options as `mix compile`.\n\n  ## Configuration\n\n  The following option must be specified in your `mix.exs`\n  under the `:escript` key:\n\n    * `:main_module` - the module to be invoked once the escript starts.\n      The module must contain a function named `main/1` that will receive the\n      command line arguments. By default the arguments are given as a list of\n      binaries, but if project is configured with `language: :erlang` it will\n      be a list of charlists.\n\n  The remaining options can be specified to further customize the escript:\n\n    * `:name` - the name of the generated escript.\n      Defaults to app name.\n\n    * `:path` - the path to write the escript to.\n      Defaults to app name.\n\n    * `:app` - the app that starts with the escript.\n      Defaults to app name. Set it to `nil` if no application should\n      be started.\n\n    * `:strip_beams` - if `true` strips BEAM code in the escript to remove chunks\n      unnecessary at runtime, such as debug information and documentation.\n      Can be set to `[keep: [\"Docs\", \"Dbgi\"]]` to strip while keeping some chunks\n      that would otherwise be stripped, like docs, and debug info, for instance.\n      Defaults to `true`.\n\n    * `:embed_elixir` - if `true` embeds Elixir and its children apps\n      (`ex_unit`, `mix`, and the like) mentioned in the `:applications` list inside the\n      `application/0` function in `mix.exs`.\n\n      Defaults to `true` for Elixir projects, `false` for Erlang projects.\n\n      Note: if you set this to `false` for an Elixir project, you will have to add paths to Elixir's\n      `ebin` directories to `ERL_LIBS` environment variable when running the resulting escript, in\n      order for the code loader to be able to find `:elixir` application and its children\n      applications (if they are used).\n\n    * `:shebang` - shebang interpreter directive used to execute the escript.\n      Defaults to `\"#! /usr/bin/env escript\\n\"`.\n\n    * `:comment` - comment line to follow shebang directive in the escript.\n      Defaults to `\"\"`.\n\n    * `:emu_args` - emulator arguments to embed in the escript file.\n      Defaults to `\"\"`.\n\n    * `:include_priv_for` - a list of application names (atoms) specifying\n      applications which priv directory should be included in the resulting\n      escript archive. Currently the expected way of accessing priv files\n      in an escript is via `:escript.extract/2`. Defaults to `[]`.\n\n  There is one project-level option that affects how the escript is generated:\n\n    * `language: :elixir | :erlang` - set it to `:erlang` for Erlang projects\n      managed by Mix. Doing so will ensure Elixir is not embedded by default.\n      Your app will still be started as part of escript loading, with the\n      config used during build.\n\n  ## Example\n\n  In your `mix.exs`:\n\n      defmodule MyApp.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :my_app,\n            version: \"0.0.1\",\n            escript: escript()\n          ]\n        end\n\n        def escript do\n          [main_module: MyApp.CLI]\n        end\n      end\n\n  Then define the entrypoint, such as the following in `lib/cli.ex`:\n\n      defmodule MyApp.CLI do\n        def main(_args) do\n          IO.puts(\"Hello from MyApp!\")\n        end\n      end\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    Mix.Task.run(\"compile\", args)\n\n    project = Mix.Project.config()\n    language = Keyword.get(project, :language, :elixir)\n    escriptize(project, language)\n  end\n\n  defp escriptize(project, language) do\n    escript_opts = project[:escript] || []\n    script_name = Mix.Local.name_for(:escripts, project)\n    filename = escript_opts[:path] || script_name\n    main = escript_opts[:main_module]\n\n    if !main do\n      error_message =\n        \"Could not generate escript, please set :main_module \" <>\n          \"in your project configuration (under :escript option) to a module that implements main/1. \" <>\n          \"Run \\\"mix help escript.build\\\" for more information\"\n\n      Mix.raise(error_message)\n    end\n\n    if not Code.ensure_loaded?(main) do\n      error_message =\n        \"Could not generate escript, module #{main} defined as \" <>\n          \":main_module could not be loaded\"\n\n      Mix.raise(error_message)\n    end\n\n    app = Keyword.get(escript_opts, :app, project[:app])\n\n    # Need to keep :strip_beam option for backward compatibility so\n    # check for correct :strip_beams, then :strip_beam, then\n    # use default true if neither are present.\n    strip_options =\n      escript_opts\n      |> Keyword.get_lazy(:strip_beams, fn ->\n        if Keyword.get(escript_opts, :strip_beam, true) do\n          true\n        else\n          IO.warn(\n            \":strip_beam option in escript.build is deprecated. Please use :strip_beams instead\"\n          )\n\n          false\n        end\n      end)\n      |> parse_strip_beams_options()\n\n    escript_mod = String.to_atom(Atom.to_string(app) <> \"_escript\")\n\n    include_priv_for = MapSet.new(escript_opts[:include_priv_for] || [])\n\n    beam_paths =\n      [\n        project_files(project, include_priv_for),\n        deps_files(include_priv_for),\n        core_files(escript_opts, language, include_priv_for)\n      ]\n      |> Stream.concat()\n      |> replace_consolidated_paths(project)\n\n    tuples = gen_main(project, escript_mod, main, app, language) ++ read_beams(beam_paths)\n    tuples = if strip_options, do: strip_beams(tuples, strip_options), else: tuples\n\n    case :zip.create(~c\"mem\", tuples, [:memory]) do\n      {:ok, {~c\"mem\", zip}} ->\n        shebang = escript_opts[:shebang] || \"#! /usr/bin/env escript\\n\"\n        comment = build_comment(escript_opts[:comment])\n        emu_args = build_emu_args(escript_opts[:emu_args], escript_mod)\n\n        script = IO.iodata_to_binary([shebang, comment, emu_args, zip])\n        File.mkdir_p!(Path.dirname(filename))\n        File.write!(filename, script)\n        set_perms(filename)\n\n      {:error, error} ->\n        Mix.raise(\"Error creating escript: #{error}\")\n    end\n\n    Mix.shell().info(\"Generated escript #{filename} with MIX_ENV=#{Mix.env()}\")\n    :ok\n  end\n\n  defp project_files(project, include_priv_for) do\n    get_files(Mix.Project.app_path(), project[:app] in include_priv_for)\n  end\n\n  defp get_files(app_path, include_priv?) do\n    paths = Path.wildcard(\"#{app_path}/ebin/*.{app,beam}\")\n\n    paths =\n      if include_priv? do\n        paths ++ (Path.wildcard(\"#{app_path}/priv/**/*\") |> Enum.filter(&File.regular?/1))\n      else\n        paths\n      end\n\n    apps_dir = Path.dirname(app_path)\n\n    for path <- paths do\n      {Path.relative_to(path, apps_dir), path}\n    end\n  end\n\n  defp set_perms(filename) do\n    stat = File.stat!(filename)\n    :ok = File.chmod(filename, stat.mode ||| 0o111)\n  end\n\n  defp deps_files(include_priv_for) do\n    deps = Mix.Dep.cached()\n    Enum.flat_map(deps, fn dep -> get_files(dep.opts[:build], dep.app in include_priv_for) end)\n  end\n\n  defp core_files(escript_opts, language, include_priv_for) do\n    if Keyword.get(escript_opts, :embed_elixir, language == :elixir) do\n      Enum.flat_map([:elixir | extra_apps()], &app_files(&1, include_priv_for))\n    else\n      []\n    end\n  end\n\n  defp extra_apps() do\n    Mix.Project.config()[:app]\n    |> extra_apps_in_app_tree()\n    |> Enum.uniq()\n  end\n\n  defp extra_apps_in_app_tree(app) when app in [:kernel, :stdlib, :elixir] do\n    []\n  end\n\n  # We include hex in here as it is always an archive and it cannot be depended on\n  defp extra_apps_in_app_tree(app) when app in [:eex, :ex_unit, :iex, :logger, :mix, :hex] do\n    [app]\n  end\n\n  defp extra_apps_in_app_tree(app) do\n    _ = Application.load(app)\n\n    case Application.spec(app) do\n      nil ->\n        []\n\n      spec ->\n        applications =\n          Keyword.get(spec, :applications, []) ++ Keyword.get(spec, :included_applications, [])\n\n        Enum.flat_map(applications, &extra_apps_in_app_tree/1)\n    end\n  end\n\n  defp app_files(app, include_priv_for) do\n    case :code.where_is_file(~c\"#{app}.app\") do\n      :non_existing -> Mix.raise(\"Could not find application #{app}\")\n      file -> get_files(Path.dirname(Path.dirname(file)), app in include_priv_for)\n    end\n  end\n\n  defp read_beams(items) do\n    Enum.map(items, fn {basename, beam_path} ->\n      {String.to_charlist(basename), File.read!(beam_path)}\n    end)\n  end\n\n  defp parse_strip_beams_options(options) do\n    case options do\n      options when is_list(options) -> options\n      true -> []\n      false -> nil\n    end\n  end\n\n  defp strip_beams(tuples, strip_options) do\n    for {basename, maybe_beam} <- tuples do\n      with \".beam\" <- Path.extname(basename),\n           {:ok, binary} <- Mix.Release.strip_beam(maybe_beam, strip_options) do\n        {basename, binary}\n      else\n        _ -> {basename, maybe_beam}\n      end\n    end\n  end\n\n  defp replace_consolidated_paths(files, config) do\n    # We could write modules to a consolidated/ directory and prepend\n    # it to code path using VM args. However, when Erlang Escript\n    # boots, it prepends all second-level ebin/ directories to the\n    # path, so the unconsolidated modules would take precedence.\n    #\n    # Instead of writing consolidated/ into the archive, we replace\n    # the protocol modules with their consolidated version in their\n    # usual location. As a side benefit, this reduces the Escript\n    # file size, since we do not include the unconsolidated modules.\n\n    if config[:consolidate_protocols] do\n      consolidation_path = Mix.Project.consolidation_path(config)\n\n      consolidated =\n        consolidation_path\n        |> Path.join(\"*\")\n        |> Path.wildcard()\n        |> Map.new(fn path -> {Path.basename(path), path} end)\n\n      for {zip_path, path} <- files do\n        {zip_path, consolidated[Path.basename(path)] || path}\n      end\n    else\n      files\n    end\n  end\n\n  defp build_comment(user_comment) do\n    \"%% #{user_comment}\\n\"\n  end\n\n  defp build_emu_args(user_args, escript_mod) do\n    \"%%! -escript main #{escript_mod} #{user_args}\\n\"\n  end\n\n  defp gen_main(project, name, module, app, language) do\n    config_path = project[:config_path]\n\n    compile_config =\n      if File.regular?(config_path) do\n        config = Config.Reader.read!(config_path, env: Mix.env(), target: Mix.target())\n        Macro.escape(config)\n      else\n        []\n      end\n\n    runtime_path = config_path |> Path.dirname() |> Path.join(\"runtime.exs\")\n\n    runtime_config =\n      if File.regular?(runtime_path) do\n        File.read!(runtime_path)\n      end\n\n    module_body =\n      quote do\n        @spec main(OptionParser.argv()) :: any\n        def main(args) do\n          unquote(main_body_for(language, module, compile_config, runtime_config))\n        end\n\n        defp load_config(config) do\n          each_fun = fn {app, kw} ->\n            set_env_fun = fn {k, v} -> :application.set_env(app, k, v, persistent: true) end\n            :lists.foreach(set_env_fun, kw)\n          end\n\n          :lists.foreach(each_fun, config)\n          :ok\n        end\n\n        defp start_app() do\n          unquote(start_app_for(app))\n        end\n\n        defp io_error(message) do\n          :io.put_chars(:standard_error, message)\n        end\n      end\n\n    {:module, ^name, binary, _} = Module.create(name, module_body, Macro.Env.location(__ENV__))\n    [{~c\"#{name}.beam\", binary}]\n  end\n\n  defp main_body_for(:elixir, module, compile_config, runtime_config) do\n    config =\n      if runtime_config do\n        quote do\n          runtime_config =\n            Config.Reader.eval!(\n              \"config/runtime.exs\",\n              unquote(runtime_config),\n              env: unquote(Mix.env()),\n              target: unquote(Mix.target()),\n              imports: :disabled\n            )\n\n          Config.Reader.merge(unquote(compile_config), runtime_config)\n        end\n      else\n        compile_config\n      end\n\n    quote do\n      case :application.ensure_all_started(:elixir) do\n        {:ok, _} ->\n          args = Enum.map(args, &List.to_string(&1))\n          System.argv(args)\n          load_config(unquote(config))\n          start_app()\n          Kernel.CLI.run(fn _ -> unquote(module).main(args) end)\n\n        error ->\n          io_error([\"ERROR! Failed to start Elixir.\\n\", :io_lib.format(~c\"error: ~p~n\", [error])])\n          :erlang.halt(1)\n      end\n    end\n  end\n\n  defp main_body_for(:erlang, module, compile_config, _runtime_config) do\n    quote do\n      load_config(unquote(compile_config))\n      start_app()\n      unquote(module).main(args)\n    end\n  end\n\n  defp start_app_for(nil) do\n    :ok\n  end\n\n  defp start_app_for(app) do\n    quote do\n      case :application.ensure_all_started(unquote(app)) do\n        {:ok, _} ->\n          :ok\n\n        {:error, {app, reason}} ->\n          formatted_error =\n            case :code.ensure_loaded(Application) do\n              {:module, Application} -> Application.format_error(reason)\n              {:error, _} -> :io_lib.format(~c\"~p\", [reason])\n            end\n\n          error_message = [\n            \"ERROR! Could not start application \",\n            :erlang.atom_to_binary(app, :utf8),\n            \": \",\n            formatted_error,\n            ?\\n\n          ]\n\n          io_error(error_message)\n          :erlang.halt(1)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/escript.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Escript do\n  use Mix.Task\n\n  @shortdoc \"Lists installed escripts\"\n\n  @moduledoc ~S\"\"\"\n  Lists all installed escripts.\n\n  Escripts are installed at `~/.mix/escripts`. Add that path to your `$PATH` environment variable\n  to be able to run installed escripts from any directory.\n  \"\"\"\n\n  import Bitwise, only: [|||: 2, &&&: 2]\n\n  @impl true\n  def run(_) do\n    escripts_path = Mix.path_for(:escripts)\n\n    escripts_path\n    |> list_dir()\n    |> Enum.filter(fn filename -> executable?(Path.join(escripts_path, filename)) end)\n    |> print()\n  end\n\n  defp list_dir(path) do\n    case File.ls(path) do\n      {:ok, list} -> list\n      _ -> []\n    end\n  end\n\n  defp executable?(path) do\n    owner_exec_bit = 0o00100\n    group_exec_bit = 0o00010\n    other_exec_bit = 0o00001\n    stat = File.stat!(path)\n\n    case :os.type() do\n      {:win32, _} ->\n        # on win32, the script itself is not executable, but the bat is\n        File.exists?(path <> \".bat\") and stat.type == :regular\n\n      _ ->\n        executable_bit = stat.mode &&& (owner_exec_bit ||| group_exec_bit ||| other_exec_bit)\n        executable_bit != 0 and stat.type == :regular and Path.extname(path) != \".bat\"\n    end\n  end\n\n  defp print([]) do\n    Mix.shell().info(\"No escripts currently installed.\")\n  end\n\n  defp print(items) do\n    Enum.each(items, fn item -> Mix.shell().info([\"* \", item]) end)\n    Mix.shell().info(\"Escripts installed at: #{Mix.path_for(:escripts)}\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/escript.install.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Escript.Install do\n  use Mix.Task\n\n  @shortdoc \"Installs an escript locally\"\n\n  @moduledoc \"\"\"\n  Installs an escript locally.\n\n  If no argument is supplied but there is an escript in the project's root directory\n  (created with `mix escript.build`), then the escript will be installed\n  locally. For example:\n\n      $ mix do escript.build + escript.install\n\n  If an argument is provided, it should be a local path to a prebuilt escript,\n  a Git repository, a GitHub repository, or a Hex package.\n\n      $ mix escript.install escript\n      $ mix escript.install path/to/escript\n      $ mix escript.install git https://path/to/git/repo\n      $ mix escript.install git https://path/to/git/repo branch git_branch\n      $ mix escript.install git https://path/to/git/repo tag git_tag\n      $ mix escript.install git https://path/to/git/repo ref git_ref\n      $ mix escript.install github user/project\n      $ mix escript.install github user/project branch git_branch\n      $ mix escript.install github user/project tag git_tag\n      $ mix escript.install github user/project ref git_ref\n      $ mix escript.install hex hex_package\n      $ mix escript.install hex hex_package 1.2.3\n\n  After installation, the escript can be invoked as\n\n      $ ~/.mix/escripts/foo\n\n  For convenience, consider adding `~/.mix/escripts` directory to your\n  `$PATH` environment variable. For more information, check the wikipedia\n  article on PATH: https://en.wikipedia.org/wiki/PATH_(variable)\n\n  ## Command line options\n\n    * `--sha512` - checks the escript matches the given SHA-512 checksum. Only\n      applies to installations via a local path\n\n    * `--force` - forces installation without a shell prompt; primarily\n      intended for automation in build systems like Make\n\n    * `--submodules` - fetches repository submodules before building escript from\n      Git or GitHub\n\n    * `--sparse` - checkout a single directory inside the Git repository and use\n      it as the escript project directory\n\n    * `--app` - specifies a custom app name to be used for building the escript\n      from Git, GitHub, or Hex\n\n    * `--organization` - set this for Hex private packages belonging to an\n      organization\n\n    * `--repo` - set this for self-hosted Hex instances, defaults to `hexpm`\n\n  \"\"\"\n\n  @behaviour Mix.Local.Installer\n\n  # only read and execute permissions\n  @escript_file_mode 0o555\n\n  @switches [\n    force: :boolean,\n    sha512: :string,\n    submodules: :boolean,\n    sparse: :string,\n    app: :string,\n    organization: :string,\n    repo: :string,\n    timeout: :integer\n  ]\n\n  @impl true\n  def run(argv) do\n    Mix.Local.Installer.install(__MODULE__, argv, @switches)\n  end\n\n  @impl true\n  def check_install_spec({:url, _}, _opts) do\n    :ok\n  end\n\n  def check_install_spec(_, _), do: :ok\n\n  @impl true\n  def find_previous_versions(basename) do\n    dst = destination(basename)\n    if File.exists?(dst), do: [dst], else: []\n  end\n\n  @impl true\n  def install(basename, binary, _previous) do\n    dst = destination(basename)\n\n    if escript?(binary) do\n      _ = File.rm(dst)\n      _ = File.rm(dst <> \".bat\")\n\n      executable = Path.basename(dst)\n      previous_executable = System.find_executable(executable)\n\n      File.mkdir_p!(Path.dirname(dst))\n      File.write!(dst, binary)\n      File.chmod!(dst, @escript_file_mode)\n      write_bat!(dst <> \".bat\", :os.type())\n\n      Mix.shell().info([:green, \"* creating \", :reset, Path.relative_to_cwd(dst)])\n      check_discoverability(dst, executable, previous_executable)\n      :ok\n    else\n      Mix.raise(\"The given path does not point to an escript, installation aborted\")\n    end\n  end\n\n  @impl true\n  def build(_spec, _opts) do\n    Mix.Task.run(\"loadconfig\")\n    Mix.Task.run(\"escript.build\", [])\n    Mix.Local.name_for(:escripts, Mix.Project.config())\n  end\n\n  # Helpers\n\n  defp destination(basename) do\n    Path.join(Mix.path_for(:escripts), basename)\n  end\n\n  defp write_bat!(path, {:win32, _}) do\n    File.write!(path, \"\"\"\n    @echo off\n    @escript \"%~dpn0\" %*\n    \"\"\")\n\n    File.chmod!(path, @escript_file_mode)\n  end\n\n  defp write_bat!(_path, _type) do\n    :ok\n  end\n\n  defp check_discoverability(dst, executable, previous_executable) do\n    current_executable = System.find_executable(executable)\n\n    cond do\n      # If existing executable was changed,\n      # it was overridden\n      previous_executable && previous_executable != current_executable ->\n        Mix.shell().error(\n          \"\\nwarning: escript #{inspect(executable)} overrides executable \" <>\n            \"#{inspect(previous_executable)} already in your PATH\\n\"\n        )\n\n      # If existing executable didn't change but it is not the one we installed,\n      # it is a conflict\n      previous_executable && previous_executable != dst ->\n        Mix.shell().error(\n          \"\\nwarning: escript #{inspect(executable)} conflicts with executable \" <>\n            \"#{inspect(previous_executable)} already in your PATH\\n\"\n        )\n\n      # If current executable is nil or does not match the one we just installed,\n      # PATH is misconfigured\n      current_executable != dst ->\n        Mix.shell().error(\n          \"\\nwarning: you must append #{inspect(Mix.path_for(:escripts))} \" <>\n            \"to your PATH if you want to invoke escripts by name\\n\"\n        )\n\n      true ->\n        :ok\n    end\n  end\n\n  defp escript?(binary) do\n    parts = String.split(binary, \"\\n\", parts: 4)\n    match?([\"#!\" <> _, _, _, <<80, 75, 3, 4, _::binary>>], parts)\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/escript.uninstall.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Escript.Uninstall do\n  use Mix.Task\n\n  @shortdoc \"Uninstalls escripts\"\n\n  @moduledoc \"\"\"\n  Uninstalls local escripts:\n\n      $ mix escript.uninstall escript_name\n\n  ## Command line options\n    * `--force` - forces uninstallation without a shell prompt; primarily\n      intended for automation\n  \"\"\"\n\n  @switches [\n    force: :boolean\n  ]\n\n  @impl true\n  def run(argv) do\n    if path = Mix.Local.Installer.uninstall(Mix.path_for(:escripts), \"escript\", argv, @switches) do\n      File.rm(path <> \".bat\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/eval.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Mix.Tasks.Eval do\n  use Mix.Task\n\n  @shortdoc \"Evaluates the given code\"\n\n  @moduledoc \"\"\"\n  Evaluates the given code within a configured application.\n\n      $ mix eval \"IO.puts(1 + 2)\"\n\n  The given code is evaluated after the current application\n  has been configured but without loading or starting them\n  (some applications may be loaded as part of booting but\n  that's not guaranteed). See `mix run` for running your\n  application and scripts within a started application.\n\n  This task is designed to mirror the `bin/my_app eval` command\n  in releases. It is typically used to invoke functions already\n  defined within your application. For example, you may have a\n  module such as:\n\n      defmodule MyApp.ReleaseTasks do\n        def migrate_database do\n          Application.load(:my_app)\n          ...\n        end\n      end\n\n  Once defined, you can invoke this function either via `mix eval` or\n  via `bin/my_app eval` inside a release as follows:\n\n      $ mix eval MyApp.ReleaseTasks.migrate_database\n      $ bin/my_app eval MyApp.ReleaseTasks.migrate_database\n\n  As you can see, the current application has to be either explicitly\n  loaded or started in your tasks, either by calling `Application.load/1`\n  or `Application.ensure_all_started/1`. This gives you full control over\n  the application booting life cycle. For more information, see the\n  `Application` module.\n\n  This task is automatically re-enabled, so it can be called multiple\n  times with different arguments.\n\n  ## Command-line options\n\n    * `--no-archives-check` - does not check archives\n    * `--no-compile` - does not compile even if files require compilation\n    * `--no-deps-check` - does not check dependencies\n    * `--no-elixir-version-check` - does not check the Elixir version from mix.exs\n    * `--no-mix-exs` - allows the command to run even if there is no mix.exs\n\n  \"\"\"\n\n  @impl true\n  def run(args) do\n    {_opts, head} =\n      OptionParser.parse_head!(\n        args,\n        strict: [\n          mix_exs: :boolean,\n          compile: :boolean,\n          deps_check: :boolean,\n          archives_check: :boolean,\n          elixir_version_check: :boolean\n        ]\n      )\n\n    case head do\n      [to_eval | argv] ->\n        cond do\n          Mix.Project.get() ->\n            Mix.Task.run(\"app.config\", [\"--no-app-loading\" | args])\n\n          \"--no-mix-exs\" in args ->\n            :ok\n\n          true ->\n            Mix.raise(\n              \"Cannot execute \\\"mix eval\\\" without a Mix.Project, \" <>\n                \"please ensure you are running Mix in a directory with a mix.exs file \" <>\n                \"or pass the --no-mix-exs option\"\n            )\n        end\n\n        old_argv = System.argv()\n\n        try do\n          System.argv(argv)\n\n          Code.eval_string(to_eval)\n          Mix.Task.reenable(\"eval\")\n        after\n          System.argv(old_argv)\n        end\n\n      _ ->\n        Mix.raise(\n          \"\\\"mix eval\\\" expects a single string to evaluate as argument. \" <>\n            \"Run \\\"mix help eval\\\" for more information\"\n        )\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/format.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Format do\n  use Mix.Task\n\n  @shortdoc \"Formats the given files/patterns\"\n\n  @moduledoc \"\"\"\n  Formats the given files and patterns.\n\n      $ mix format mix.exs \"lib/**/*.{ex,exs}\" \"test/**/*.{ex,exs}\"\n\n  If any of the files is `-`, then the input is read from stdin and the output\n  is written to stdout.\n\n  ## Formatting options\n\n  The formatter will read a `.formatter.exs` file in the current directory for\n  formatter configuration. Evaluating this file should return a keyword list.\n\n  Here is an example of a `.formatter.exs` file that works as a starting point:\n\n      [\n        inputs: [\"{mix,.formatter}.exs\", \"{config,lib,test}/**/*.{ex,exs}\"]\n      ]\n\n  Besides the options listed in `Code.format_string!/2`, the `.formatter.exs`\n  file supports the following options:\n\n    * `:inputs` (a list of paths and patterns) - specifies the default inputs\n      to be used by this task. For example, `[\"mix.exs\", \"{config,lib,test}/**/*.{ex,exs}\"]`.\n      Patterns are expanded with `Path.wildcard/2`.\n\n    * `:excludes` (a list of paths and patterns) (since v1.19.0) - specifies the files to exclude from the\n      list of inputs to this task. For example, `[\"config/runtime.exs\", \"test/**/*.{ex,exs}\"]`.\n      Patterns are expanded with `Path.wildcard/2`.\n\n    * `:plugins` (a list of modules) (since v1.13.0) - specifies a list of\n      modules to customize how the formatter works. See the \"Plugins\" section\n      below for more information.\n\n    * `:subdirectories` (a list of paths and patterns) - specifies subdirectories\n      that have their own formatting rules. Each subdirectory should have a\n      `.formatter.exs` that configures how entries in that subdirectory should be\n      formatted as. Configuration between `.formatter.exs` are not shared nor\n      inherited. If a `.formatter.exs` lists \"lib/app\" as a subdirectory, the rules\n      in `.formatter.exs` won't be available in `lib/app/.formatter.exs`.\n      Note that the parent `.formatter.exs` must not specify files inside the \"lib/app\"\n      subdirectory in its `:inputs` configuration. If this happens, the behaviour of\n      which formatter configuration will be picked is unspecified.\n\n    * `:import_deps` (a list of dependencies as atoms) - specifies a list\n       of dependencies whose formatter configuration will be imported.\n       See the \"Importing dependencies configuration\" section below for more\n       information.\n\n    * `:export` (a keyword list) - specifies formatter configuration to be exported.\n      See the \"Importing dependencies configuration\" section below.\n\n  ## Task-specific options\n\n    * `--force` - force formatting to happen on all files, instead of\n      relying on cache.\n\n    * `--check-formatted` - checks that the file is already formatted.\n      This is useful in pre-commit hooks and CI scripts if you want to\n      reject contributions with unformatted code. If the check fails,\n      the formatted contents are not written to disk. Keep in mind\n      that the formatted output may differ between Elixir versions as\n      improvements and fixes are applied to the formatter.\n\n    * `--no-exit` - only valid when used with `--check-formatted`.\n      Pass this if you don't want this Mix task to fail (and return a non-zero exit code),\n      but still want to check for format errors and print them to the console.\n\n    * `--dry-run` - does not save files after formatting.\n\n    * `--verbose` - prints the names of files that were formatted.\n\n    * `--dot-formatter` - path to the file with formatter configuration.\n      Defaults to `.formatter.exs` if one is available. See the\n      \"Formatting options\" section above for more information.\n\n    * `--stdin-filename` - path to the file being formatted on stdin.\n      This is useful if you are using plugins to support custom filetypes such\n      as `.heex`. Without passing this flag, it is assumed that the code being\n      passed via stdin is valid Elixir code. Defaults to `stdin.exs`.\n\n    * `--migrate` - enables the `:migrate` option, which should be able to\n      automatically fix some deprecation warnings but changes the AST.\n      This should be safe in typical projects, but there is a non-zero risk\n      of breaking code for meta-programming heavy projects that relied on a\n      specific AST. We recommend running this task in its separate commit and\n      reviewing its output before committing. See the \"Migration formatting\"\n      section in `Code.format_string!/2` for more information.\n\n  ## When to format code\n\n  We recommend developers to format code directly in their editors, either\n  automatically when saving a file or via an explicit command or key binding. If\n  such option is not available in your editor of choice, adding the required\n  integration is usually a matter of invoking:\n\n      $ cd $project && mix format $file\n\n  where `$file` refers to the current file and `$project` is the root of your\n  project.\n\n  It is also possible to format code across the whole project by passing a list\n  of patterns and files to `mix format`, as shown at the top of this task\n  documentation. This list can also be set in the `.formatter.exs` file under the\n  `:inputs` key.\n\n  ## Plugins\n\n  It is possible to customize how the formatter behaves. Plugins must implement\n  the `Mix.Tasks.Format` behaviour. For example, imagine that your project uses\n  Markdown in two distinct ways: via a custom `~M` sigil and via files with the\n  `.md` and `.markdown` extensions. A custom plugin would look like this:\n\n      defmodule MixMarkdownFormatter do\n        @behaviour Mix.Tasks.Format\n\n        def features(_opts) do\n          [sigils: [:M], extensions: [\".md\", \".markdown\"]]\n        end\n\n        def format(contents, opts) do\n          # logic that formats markdown\n        end\n      end\n\n  The `opts` passed to `format/2` contains all the formatting options and either:\n\n    * `:sigil` (atom) - the sigil being formatted, e.g. `:M`.\n\n    * `:modifiers` (charlist) - list of sigil modifiers.\n\n    * `:extension` (string) - the extension of the file being formatted, e.g. `\".md\"`.\n\n  Now any application can use your formatter as follows:\n\n      # .formatter.exs\n      [\n        # Define the desired plugins\n        plugins: [MixMarkdownFormatter, AnotherMarkdownFormatter],\n        # Remember to update the inputs list to include the new extensions\n        inputs: [\"{mix,.formatter}.exs\", \"{config,lib,test}/**/*.{ex,exs}\", \"posts/*.{md,markdown}\"]\n      ]\n\n  Notice that, when running the formatter with plugins, your code will be\n  compiled first.\n\n  In addition, the order by which you input your plugins is the format order.\n  So, in the above `.formatter.exs`, the `MixMarkdownFormatter` will format\n  the markdown files and sigils before `AnotherMarkdownFormatter`.\n\n  ## Importing dependencies configuration\n\n  This task supports importing formatter configuration from dependencies.\n\n  A dependency that wants to export formatter configuration needs to have a\n  `.formatter.exs` file at the root of the project. In this file, the dependency\n  can list an `:export` option with configuration to export. For now, only one\n  option is supported under `:export`: `:locals_without_parens` (whose value has\n  the same shape as the value of the `:locals_without_parens` in `Code.format_string!/2`).\n\n  The functions listed under `:locals_without_parens` in the `:export` option of\n  a dependency can be imported in a project by listing that dependency in the\n  `:import_deps` option of the formatter configuration file of the project.\n\n  For example, consider you have a project called `my_app` that depends on another one called `my_dep`.\n  `my_dep` wants to export some configuration, so `my_dep/.formatter.exs`\n  would look like this:\n\n      # my_dep/.formatter.exs\n      [\n        # Regular formatter configuration for my_dep\n        # ...\n\n        export: [\n          locals_without_parens: [some_dsl_call: 2, some_dsl_call: 3]\n        ]\n      ]\n\n  In order to import configuration, `my_app`'s `.formatter.exs` would look like\n  this:\n\n      # my_app/.formatter.exs\n      [\n        import_deps: [:my_dep]\n      ]\n\n  \"\"\"\n\n  @switches [\n    check_equivalent: :boolean,\n    check_formatted: :boolean,\n    no_exit: :boolean,\n    dot_formatter: :string,\n    dry_run: :boolean,\n    verbose: :boolean,\n    stdin_filename: :string,\n    force: :boolean,\n    migrate: :boolean\n  ]\n\n  @manifest_timestamp \"format_timestamp\"\n  @manifest_dot_formatter \"cached_dot_formatter\"\n  @manifest_vsn 2\n\n  @newline \"\\n\"\n  @blank \" \"\n\n  @separator \"|\"\n  @cr \"↵\"\n  @line_num_pad @blank\n\n  @gutter [\n    del: \" -\",\n    eq: \"  \",\n    ins: \" +\",\n    skip: \"  \"\n  ]\n\n  @colors [\n    del: [text: :red, space: :red_background],\n    ins: [text: :green, space: :green_background]\n  ]\n\n  @doc \"\"\"\n  Returns which features this plugin should plug into.\n\n  It receives all options specified in `.formatter.exs`.\n  \"\"\"\n  @callback features(keyword) :: [sigils: [atom()], extensions: [binary()]]\n\n  @doc \"\"\"\n  Receives a string to be formatted with options and returns said string.\n\n  It receives all options specified in `.formatter.exs`.\n  \"\"\"\n  @callback format(String.t(), keyword) :: String.t()\n\n  @impl true\n  def run(all_args) do\n    cwd = File.cwd!()\n    {opts, args} = OptionParser.parse!(all_args, strict: @switches)\n    {dot_formatter, formatter_opts} = eval_dot_formatter(cwd, opts)\n\n    if opts[:check_equivalent] do\n      IO.warn(\"--check-equivalent has been deprecated and has no effect\")\n    end\n\n    if opts[:no_exit] && !opts[:check_formatted] do\n      Mix.raise(\"--no-exit can only be used together with --check-formatted\")\n    end\n\n    {formatter_opts_and_subs, _sources} =\n      eval_deps_and_subdirectories(cwd, dot_formatter, formatter_opts, [dot_formatter], opts)\n\n    formatter_opts_and_subs = load_plugins(formatter_opts_and_subs, opts)\n    files = expand_args(args, cwd, dot_formatter, formatter_opts_and_subs, opts)\n\n    maybe_cache_timestamps(all_args, files, fn files ->\n      files\n      |> Task.async_stream(&format_file(&1, opts), ordered: false, timeout: :infinity)\n      |> Enum.reduce({[], []}, &collect_status/2)\n      |> check!(opts)\n    end)\n  end\n\n  defp maybe_cache_timestamps([], files, fun) do\n    if Mix.Project.get() do\n      # We fetch the time from before we read files so any future\n      # change to files are still picked up by the formatter\n      timestamp = System.os_time(:second)\n      dir = Mix.Project.manifest_path()\n      manifest_timestamp = Path.join(dir, @manifest_timestamp)\n      manifest_dot_formatter = Path.join(dir, @manifest_dot_formatter)\n      last_modified = Mix.Utils.last_modified(manifest_timestamp)\n      sources = [Mix.Project.config_mtime(), manifest_dot_formatter, \".formatter.exs\"]\n\n      files =\n        if Mix.Utils.stale?(sources, [last_modified]) do\n          files\n        else\n          Enum.filter(files, fn {file, _opts} ->\n            Mix.Utils.last_modified(file) > last_modified\n          end)\n        end\n\n      try do\n        fun.(files)\n      after\n        File.mkdir_p!(dir)\n        File.touch!(manifest_timestamp, timestamp)\n      end\n    else\n      fun.(files)\n    end\n  end\n\n  defp maybe_cache_timestamps([_ | _], files, fun), do: fun.(files)\n\n  defp load_plugins({formatter_opts, subs}, opts) do\n    plugins = Keyword.get(formatter_opts, :plugins, [])\n\n    if not is_list(plugins) do\n      Mix.raise(\"Expected :plugins to return a list of modules, got: #{inspect(plugins)}\")\n    end\n\n    plugins =\n      if plugins != [] do\n        Keyword.get(opts, :plugin_loader, &plugin_loader/1).(plugins)\n      else\n        []\n      end\n\n    for plugin <- plugins do\n      cond do\n        not Code.ensure_loaded?(plugin) ->\n          Mix.raise(\"Formatter plugin #{inspect(plugin)} cannot be found\")\n\n        not function_exported?(plugin, :features, 1) ->\n          Mix.raise(\"Formatter plugin #{inspect(plugin)} does not define features/1\")\n\n        true ->\n          :ok\n      end\n    end\n\n    sigils =\n      for plugin <- plugins,\n          sigil <- find_sigils_from_plugins(plugin, formatter_opts),\n          do: {sigil, plugin}\n\n    sigils =\n      sigils\n      |> Enum.group_by(&elem(&1, 0), &elem(&1, 1))\n      |> Enum.map(fn {sigil, plugins} ->\n        {sigil,\n         fn input, opts ->\n           Enum.reduce(plugins, input, fn plugin, input ->\n             plugin.format(input, opts ++ formatter_opts)\n           end)\n         end}\n      end)\n\n    {Keyword.put(formatter_opts, :sigils, sigils),\n     Enum.map(subs, fn {path, formatter_opts_and_subs} ->\n       {path, load_plugins(formatter_opts_and_subs, opts)}\n     end)}\n  end\n\n  defp plugin_loader(plugins) do\n    if plugins != [] do\n      Mix.Task.run(\"loadpaths\", [])\n    end\n\n    if not Enum.all?(plugins, &Code.ensure_loaded?/1) do\n      Mix.Task.run(\"compile\", [])\n    end\n\n    plugins\n  end\n\n  @typedoc \"\"\"\n  Options for `formatter_for_file/2`.\n  \"\"\"\n  @type formatter_for_file_opts :: [\n          deps_paths: %{atom() => String.t()},\n          dot_formatter: String.t(),\n          plugin_loader: ([module()] -> [module()]),\n          root: String.t()\n        ]\n\n  @doc \"\"\"\n  Returns a formatter function and the formatter options to\n  be used for the given file.\n\n  The function must be called with the contents of the file\n  to be formatted. Keep in mind that a function is always\n  returned, even if it doesn't match any of the inputs\n  specified in the `formatter.exs`. You can retrieve the\n  `:inputs` from the returned options, alongside the `:root`\n  option, to validate if the returned file matches the given\n  `:root` and `:inputs`.\n\n  ## Options\n\n    * `:deps_paths` (since v1.18.0) - the dependencies path to be used to resolve\n      `import_deps`. It defaults to `Mix.Project.deps_paths`.\n\n    * `:dot_formatter` - use the given file as the `dot_formatter`\n      root. If this option is not specified, it uses the default one.\n      The default one is cached, so use this option only if necessary.\n\n    * `:plugin_loader` (since v1.18.0) - a function that receives a list of plugins,\n      which may or may not yet be loaded, and ensures all of them are\n      loaded. It must return a list of plugins, which is recommended\n      to be the exact same list given as argument. You may choose to\n      skip plugins, but then it means the code will be partially\n      formatted (as in the plugins will be skipped). By default,\n      this function calls `mix loadpaths` and then, if not enough,\n      `mix compile`.\n\n    * `:root` - use the given root as the current working directory.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec formatter_for_file(String.t(), formatter_for_file_opts) ::\n          {(String.t() -> String.t()), keyword()}\n  def formatter_for_file(file, opts \\\\ []) do\n    cwd = Keyword.get_lazy(opts, :root, &File.cwd!/0)\n    {dot_formatter, formatter_opts} = eval_dot_formatter(cwd, opts)\n\n    {formatter_opts_and_subs, _sources} =\n      eval_deps_and_subdirectories(cwd, dot_formatter, formatter_opts, [dot_formatter], opts)\n\n    formatter_opts_and_subs = load_plugins(formatter_opts_and_subs, opts)\n\n    find_formatter_and_opts_for_file(Path.expand(file, cwd), cwd, formatter_opts_and_subs)\n  end\n\n  @doc false\n  @deprecated \"Use formatter_for_file/2 instead\"\n  def formatter_opts_for_file(file, opts \\\\ []) do\n    {_, formatter_opts} = formatter_for_file(file, opts)\n    formatter_opts\n  end\n\n  defp eval_dot_formatter(cwd, opts) do\n    {dot_formatter, format_opts} =\n      cond do\n        dot_formatter = opts[:dot_formatter] ->\n          {dot_formatter, eval_file_with_keyword_list(dot_formatter)}\n\n        File.regular?(Path.join(cwd, \".formatter.exs\")) ->\n          dot_formatter = Path.join(cwd, \".formatter.exs\")\n          {\".formatter.exs\", eval_file_with_keyword_list(dot_formatter)}\n\n        true ->\n          {\".formatter.exs\", []}\n      end\n\n    # the --migrate flag overrides settings from the dot formatter\n    {dot_formatter, Keyword.take(opts, [:migrate]) ++ format_opts}\n  end\n\n  # This function reads exported configuration from the imported\n  # dependencies and subdirectories and deals with caching the result\n  # of reading such configuration in a manifest file.\n  defp eval_deps_and_subdirectories(cwd, dot_formatter, formatter_opts, sources, opts) do\n    deps = Keyword.get(formatter_opts, :import_deps, [])\n    subs = Keyword.get(formatter_opts, :subdirectories, [])\n\n    if not is_list(deps) do\n      Mix.raise(\"Expected :import_deps to return a list of dependencies, got: #{inspect(deps)}\")\n    end\n\n    if not is_list(subs) do\n      Mix.raise(\"Expected :subdirectories to return a list of directories, got: #{inspect(subs)}\")\n    end\n\n    if deps == [] and subs == [] do\n      {{formatter_opts, []}, sources}\n    else\n      manifest = Path.join(Mix.Project.manifest_path(), @manifest_dot_formatter)\n\n      {{locals_without_parens, subdirectories}, sources} =\n        maybe_cache_in_manifest(dot_formatter, manifest, fn ->\n          {subdirectories, sources} = eval_subs_opts(subs, cwd, sources, opts)\n          {{eval_deps_opts(deps, opts), subdirectories}, sources}\n        end)\n\n      formatter_opts =\n        Keyword.update(\n          formatter_opts,\n          :locals_without_parens,\n          locals_without_parens,\n          &(locals_without_parens ++ &1)\n        )\n\n      {{formatter_opts, subdirectories}, sources}\n    end\n  end\n\n  defp maybe_cache_in_manifest(dot_formatter, manifest, fun) do\n    cond do\n      is_nil(Mix.Project.get()) or dot_formatter != \".formatter.exs\" -> fun.()\n      entry = read_manifest(manifest) -> entry\n      true -> write_manifest!(manifest, fun.())\n    end\n  end\n\n  defp read_manifest(manifest) do\n    with {:ok, binary} <- File.read(manifest),\n         {:ok, {@manifest_vsn, entry, sources}} <- safe_binary_to_term(binary),\n         expanded_sources = Enum.flat_map(sources, &Path.wildcard(&1, match_dot: true)),\n         false <- Mix.Utils.stale?([Mix.Project.config_mtime() | expanded_sources], [manifest]) do\n      {entry, sources}\n    else\n      _ -> nil\n    end\n  end\n\n  defp safe_binary_to_term(binary) do\n    {:ok, :erlang.binary_to_term(binary)}\n  rescue\n    _ -> :error\n  end\n\n  defp write_manifest!(manifest, {entry, sources}) do\n    File.mkdir_p!(Path.dirname(manifest))\n    File.write!(manifest, :erlang.term_to_binary({@manifest_vsn, entry, sources}))\n    {entry, sources}\n  end\n\n  defp eval_deps_opts([], _opts) do\n    []\n  end\n\n  defp eval_deps_opts(deps, opts) do\n    deps_paths = opts[:deps_paths] || Mix.Project.deps_paths()\n\n    if not is_map(deps_paths) do\n      Mix.raise(\n        \"Expected :deps_paths to return a map of dependency paths, got: #{inspect(deps_paths)}\"\n      )\n    end\n\n    for dep <- deps,\n        dep_path = assert_valid_dep_and_fetch_path(dep, deps_paths),\n        dep_dot_formatter = Path.join(dep_path, \".formatter.exs\"),\n        File.regular?(dep_dot_formatter),\n        dep_opts = eval_file_with_keyword_list(dep_dot_formatter),\n        parenless_call <- dep_opts[:export][:locals_without_parens] || [],\n        uniq: true,\n        do: parenless_call\n  end\n\n  defp eval_subs_opts(subs, cwd, sources, opts) do\n    {subs, sources} =\n      Enum.flat_map_reduce(subs, sources, fn sub, sources ->\n        cwd = Path.expand(sub, cwd)\n        {Path.wildcard(cwd), [Path.join(cwd, \".formatter.exs\") | sources]}\n      end)\n\n    Enum.flat_map_reduce(subs, sources, fn sub, sources ->\n      sub_formatter = Path.join(sub, \".formatter.exs\")\n\n      if File.exists?(sub_formatter) do\n        formatter_opts = eval_file_with_keyword_list(sub_formatter)\n\n        {formatter_opts_and_subs, sources} =\n          eval_deps_and_subdirectories(sub, :in_memory, formatter_opts, sources, opts)\n\n        {[{sub, formatter_opts_and_subs}], sources}\n      else\n        {[], sources}\n      end\n    end)\n  end\n\n  defp assert_valid_dep_and_fetch_path(dep, deps_paths) when is_atom(dep) do\n    with %{^dep => path} <- deps_paths,\n         true <- File.dir?(path) do\n      path\n    else\n      _ ->\n        Mix.raise(\n          \"Unknown dependency #{inspect(dep)} given to :import_deps in the formatter configuration. \" <>\n            \"Make sure the dependency is listed in your mix.exs for environment #{inspect(Mix.env())} \" <>\n            \"and you have run \\\"mix deps.get\\\"\"\n        )\n    end\n  end\n\n  defp assert_valid_dep_and_fetch_path(dep, _deps_paths) do\n    Mix.raise(\"Dependencies in :import_deps should be atoms, got: #{inspect(dep)}\")\n  end\n\n  defp eval_file_with_keyword_list(path) do\n    {opts, _} = Code.eval_file(path)\n\n    if not Keyword.keyword?(opts) do\n      Mix.raise(\"Expected #{inspect(path)} to return a keyword list, got: #{inspect(opts)}\")\n    end\n\n    opts\n  end\n\n  defp expand_args([], cwd, dot_formatter, formatter_opts_and_subs, _opts) do\n    if no_entries_in_formatter_opts?(formatter_opts_and_subs) do\n      Mix.raise(\n        \"Expected one or more files/patterns to be given to mix format \" <>\n          \"or for a .formatter.exs file to exist with an :inputs or :subdirectories key\"\n      )\n    end\n\n    dot_formatter\n    |> expand_dot_inputs(cwd, formatter_opts_and_subs, %{})\n    |> Enum.map(fn {file, {_dot_formatter, formatter_opts}} ->\n      {file, find_formatter_for_file(file, formatter_opts)}\n    end)\n  end\n\n  defp expand_args(files_and_patterns, cwd, _dot_formatter, {formatter_opts, subs}, opts) do\n    files =\n      for file_or_pattern <- files_and_patterns,\n          file <- stdin_or_wildcard(file_or_pattern),\n          uniq: true,\n          do: file\n\n    if files == [] do\n      Mix.raise(\n        \"Could not find a file to format. The files/patterns given to command line \" <>\n          \"did not point to any existing file. Got: #{inspect(files_and_patterns)}\"\n      )\n    end\n\n    for file <- files do\n      if file == :stdin do\n        stdin_filename = Path.expand(Keyword.get(opts, :stdin_filename, \"stdin.exs\"), cwd)\n\n        {formatter, _opts} =\n          find_formatter_and_opts_for_file(stdin_filename, cwd, {formatter_opts, subs})\n\n        {file, formatter}\n      else\n        {formatter, _opts} = find_formatter_and_opts_for_file(file, cwd, {formatter_opts, subs})\n        {file, formatter}\n      end\n    end\n  end\n\n  defp expand_dot_inputs(dot_formatter, cwd, {formatter_opts, subs}, acc) do\n    if no_entries_in_formatter_opts?({formatter_opts, subs}) do\n      Mix.raise(\"Expected :inputs or :subdirectories key in #{dot_formatter}\")\n    end\n\n    excluded_files =\n      formatter_opts[:excludes]\n      |> List.wrap()\n      |> Enum.flat_map(&Path.wildcard(Path.expand(&1, cwd), match_dot: true))\n      |> MapSet.new()\n\n    map =\n      for input <- List.wrap(formatter_opts[:inputs]),\n          file <- Path.wildcard(Path.expand(input, cwd), match_dot: true),\n          file not in excluded_files,\n          do: {file, {dot_formatter, formatter_opts}},\n          into: %{}\n\n    acc =\n      Map.merge(acc, map, fn file, {dot_formatter1, _}, {dot_formatter2, formatter_opts} ->\n        Mix.shell().error(\n          \"Both #{dot_formatter1} and #{dot_formatter2} specify the file #{file} in their \" <>\n            \":inputs option. To resolve the conflict, the configuration in #{dot_formatter1} \" <>\n            \"will be ignored. Please change the list of :inputs in one of the formatter files \" <>\n            \"so only one of them matches #{file}\"\n        )\n\n        {dot_formatter2, formatter_opts}\n      end)\n\n    Enum.reduce(subs, acc, fn {sub, formatter_opts_and_subs}, acc ->\n      sub_formatter = Path.join(sub, \".formatter.exs\")\n      expand_dot_inputs(sub_formatter, sub, formatter_opts_and_subs, acc)\n    end)\n  end\n\n  defp find_formatter_for_file(file, formatter_opts) do\n    ext = Path.extname(file)\n\n    cond do\n      plugins = find_plugins_for_extension(formatter_opts, ext) ->\n        fn input ->\n          Enum.reduce(plugins, input, fn plugin, input ->\n            plugin.format(input, [extension: ext, file: file] ++ formatter_opts)\n          end)\n        end\n\n      ext in ~w(.ex .exs) ->\n        &elixir_format(&1, [file: file] ++ formatter_opts)\n\n      true ->\n        & &1\n    end\n  end\n\n  defp find_plugins_for_extension(formatter_opts, ext) do\n    plugins = Keyword.get(formatter_opts, :plugins, [])\n\n    plugins =\n      Enum.filter(plugins, fn plugin ->\n        Code.ensure_loaded?(plugin) and function_exported?(plugin, :features, 1) and\n          ext in List.wrap(plugin.features(formatter_opts)[:extensions])\n      end)\n\n    if plugins != [], do: plugins, else: nil\n  end\n\n  defp find_formatter_and_opts_for_file(file, root, formatter_opts_and_subs) do\n    {formatter_opts, root} = recur_formatter_opts_for_file(file, root, formatter_opts_and_subs)\n    {find_formatter_for_file(file, formatter_opts), [root: root] ++ formatter_opts}\n  end\n\n  defp recur_formatter_opts_for_file(file, root, {formatter_opts, subs}) do\n    Enum.find_value(subs, {formatter_opts, root}, fn {sub, formatter_opts_and_subs} ->\n      size = byte_size(sub)\n\n      case file do\n        <<prefix::binary-size(^size), dir_separator, _::binary>>\n        when prefix == sub and dir_separator in [?\\\\, ?/] ->\n          recur_formatter_opts_for_file(file, sub, formatter_opts_and_subs)\n\n        _ ->\n          nil\n      end\n    end)\n  end\n\n  defp no_entries_in_formatter_opts?({formatter_opts, subs}) do\n    is_nil(formatter_opts[:inputs]) and subs == []\n  end\n\n  defp stdin_or_wildcard(\"-\"), do: [:stdin]\n\n  defp stdin_or_wildcard(path),\n    do: path |> Path.expand() |> Path.wildcard(match_dot: true) |> Enum.filter(&File.regular?/1)\n\n  defp elixir_format(content, formatter_opts) do\n    content\n    |> Code.format_string!(formatter_opts)\n    |> IO.iodata_to_binary()\n    |> case do\n      \"\" -> \"\"\n      formatted_content -> IO.iodata_to_binary([formatted_content, ?\\n])\n    end\n  end\n\n  defp find_sigils_from_plugins(plugin, formatter_opts) do\n    if Code.ensure_loaded?(plugin) and function_exported?(plugin, :features, 1) do\n      List.wrap(plugin.features(formatter_opts)[:sigils])\n    else\n      []\n    end\n  end\n\n  defp read_file(:stdin), do: IO.stream() |> Enum.to_list() |> IO.iodata_to_binary()\n  defp read_file(file), do: File.read!(file)\n\n  defp format_file({file, formatter}, task_opts) do\n    input = read_file(file)\n    output = formatter.(input)\n    check_formatted? = Keyword.get(task_opts, :check_formatted, false)\n    dry_run? = Keyword.get(task_opts, :dry_run, false)\n\n    cond do\n      check_formatted? ->\n        if input == output, do: :ok, else: {:not_formatted, {file, input, output}}\n\n      dry_run? ->\n        :ok\n\n      true ->\n        write_or_print(file, input, output, task_opts)\n    end\n  rescue\n    exception ->\n      {:exit, file, exception, __STACKTRACE__}\n  end\n\n  defp write_or_print(file, input, output, task_opts) do\n    cond do\n      file == :stdin ->\n        IO.write(output)\n\n      input == output ->\n        :ok\n\n      true ->\n        File.write!(file, output)\n\n        if task_opts[:verbose] do\n          Mix.shell().info([:green, \"* formatting \", :reset, Path.relative_to_cwd(file)])\n        end\n    end\n\n    :ok\n  end\n\n  defp collect_status({:ok, :ok}, acc), do: acc\n\n  defp collect_status({:ok, {:exit, _, _, _} = exit}, {exits, not_formatted}) do\n    {[exit | exits], not_formatted}\n  end\n\n  defp collect_status({:ok, {:not_formatted, file}}, {exits, not_formatted}) do\n    {exits, [file | not_formatted]}\n  end\n\n  defp check!({[], []}, _task_opts) do\n    :ok\n  end\n\n  defp check!({[{:exit, :stdin, exception, stacktrace} | _], _not_formatted}, _task_opts) do\n    Mix.shell().error(\"mix format failed for stdin\")\n    reraise exception, stacktrace\n  end\n\n  defp check!({[{:exit, file, exception, stacktrace} | _], _not_formatted}, _task_opts) do\n    Mix.shell().error(\"mix format failed for file: #{Path.relative_to_cwd(file)}\")\n    reraise exception, stacktrace\n  end\n\n  defp check!({_exits, [_ | _] = not_formatted}, task_opts) do\n    no_exit? = Keyword.get(task_opts, :no_exit, false)\n\n    message = \"\"\"\n    The following files are not formatted:\n\n    #{to_diffs(not_formatted)}\n    \"\"\"\n\n    if no_exit? do\n      Mix.shell().info(message)\n    else\n      Mix.raise(\"\"\"\n      mix format failed due to --check-formatted.\n      #{message}\n      \"\"\")\n    end\n  end\n\n  defp to_diffs(files) do\n    Enum.map_intersperse(files, \"\\n\", fn\n      {:stdin, unformatted, formatted} ->\n        [IO.ANSI.reset(), text_diff_format(unformatted, formatted)]\n\n      {file, unformatted, formatted} ->\n        [\n          IO.ANSI.bright(),\n          IO.ANSI.red(),\n          file,\n          \"\\n\",\n          IO.ANSI.reset(),\n          \"\\n\",\n          text_diff_format(unformatted, formatted)\n        ]\n    end)\n  end\n\n  @doc false\n  def text_diff_format(old, new, opts \\\\ [])\n\n  def text_diff_format(code, code, _opts), do: []\n\n  def text_diff_format(old, new, opts) do\n    opts = Keyword.validate!(opts, after: 2, before: 2, color: IO.ANSI.enabled?(), line: 1)\n    crs? = String.contains?(old, \"\\r\") || String.contains?(new, \"\\r\")\n\n    old = String.split(old, \"\\n\")\n    new = String.split(new, \"\\n\")\n\n    max = max(length(new), length(old))\n    line_num_digits = max |> Integer.digits() |> length()\n    opts = Keyword.put(opts, :line_num_digits, line_num_digits)\n\n    {line, opts} = Keyword.pop!(opts, :line)\n\n    old\n    |> List.myers_difference(new)\n    |> insert_cr_symbols(crs?)\n    |> diff_to_iodata({line, line}, opts)\n  end\n\n  defp diff_to_iodata(diff, line_nums, opts, iodata \\\\ [])\n\n  defp diff_to_iodata([], _line_nums, _opts, iodata), do: Enum.reverse(iodata)\n\n  defp diff_to_iodata([{:eq, [\"\"]}], _line_nums, _opts, iodata), do: Enum.reverse(iodata)\n\n  defp diff_to_iodata([{:eq, lines}], line_nums, opts, iodata) do\n    lines_after = Enum.take(lines, opts[:after])\n    iodata = lines(iodata, {:eq, lines_after}, line_nums, opts)\n\n    iodata =\n      case length(lines) > opts[:after] do\n        false -> iodata\n        true -> lines(iodata, :skip, opts)\n      end\n\n    Enum.reverse(iodata)\n  end\n\n  defp diff_to_iodata([{:eq, lines} | diff], {line, line}, opts, [] = iodata) do\n    {start, lines_before} = Enum.split(lines, opts[:before] * -1)\n\n    iodata =\n      case length(lines) > opts[:before] do\n        false -> iodata\n        true -> lines(iodata, :skip, opts)\n      end\n\n    line = line + length(start)\n    iodata = lines(iodata, {:eq, lines_before}, {line, line}, opts)\n\n    line = line + length(lines_before)\n    diff_to_iodata(diff, {line, line}, opts, iodata)\n  end\n\n  defp diff_to_iodata([{:eq, lines} | diff], line_nums, opts, iodata) do\n    case length(lines) > opts[:after] + opts[:before] do\n      true ->\n        {lines1, lines2, lines3} = split(lines, opts[:after], opts[:before] * -1)\n\n        iodata =\n          iodata\n          |> lines({:eq, lines1}, line_nums, opts)\n          |> lines(:skip, opts)\n          |> lines({:eq, lines3}, add_line_nums(line_nums, length(lines1) + length(lines2)), opts)\n\n        line_nums = add_line_nums(line_nums, length(lines))\n\n        diff_to_iodata(diff, line_nums, opts, iodata)\n\n      false ->\n        iodata = lines(iodata, {:eq, lines}, line_nums, opts)\n        line_nums = add_line_nums(line_nums, length(lines))\n\n        diff_to_iodata(diff, line_nums, opts, iodata)\n    end\n  end\n\n  defp diff_to_iodata([{:del, [del]}, {:ins, [ins]} | diff], line_nums, opts, iodata) do\n    iodata = lines(iodata, {:chg, del, ins}, line_nums, opts)\n    diff_to_iodata(diff, add_line_nums(line_nums, 1), opts, iodata)\n  end\n\n  defp diff_to_iodata([{kind, lines} | diff], line_nums, opts, iodata) do\n    iodata = lines(iodata, {kind, lines}, line_nums, opts)\n    line_nums = add_line_nums(line_nums, length(lines), kind)\n\n    diff_to_iodata(diff, line_nums, opts, iodata)\n  end\n\n  defp split(list, count1, count2) do\n    {split1, split2} = Enum.split(list, count1)\n    {split2, split3} = Enum.split(split2, count2)\n    {split1, split2, split3}\n  end\n\n  defp lines(iodata, :skip, opts) do\n    line_num = String.duplicate(@blank, opts[:line_num_digits] * 2 + 1)\n    [[line_num, @gutter[:skip], @separator, @newline] | iodata]\n  end\n\n  defp lines(iodata, {:chg, del, ins}, line_nums, opts) do\n    {del, ins} = line_diff(del, ins, opts)\n\n    [\n      [gutter(line_nums, :ins, opts), ins, @newline],\n      [gutter(line_nums, :del, opts), del, @newline]\n      | iodata\n    ]\n  end\n\n  defp lines(iodata, {kind, lines}, line_nums, opts) do\n    lines\n    |> Enum.with_index()\n    |> Enum.reduce(iodata, fn {line, offset}, iodata ->\n      line_nums = add_line_nums(line_nums, offset, kind)\n      [[gutter(line_nums, kind, opts), colorize(line, kind, false, opts), @newline] | iodata]\n    end)\n  end\n\n  defp gutter(line_nums, kind, opts) do\n    [line_num(line_nums, kind, opts), colorize(@gutter[kind], kind, false, opts), @separator]\n  end\n\n  defp line_num({line_num_old, line_num_new}, :eq, opts) do\n    old =\n      line_num_old\n      |> to_string()\n      |> String.pad_leading(opts[:line_num_digits], @line_num_pad)\n\n    new =\n      line_num_new\n      |> to_string()\n      |> String.pad_leading(opts[:line_num_digits], @line_num_pad)\n\n    [old, @blank, new]\n  end\n\n  defp line_num({line_num_old, _line_num_new}, :del, opts) do\n    old =\n      line_num_old\n      |> to_string()\n      |> String.pad_leading(opts[:line_num_digits], @line_num_pad)\n\n    new = String.duplicate(@blank, opts[:line_num_digits])\n    [old, @blank, new]\n  end\n\n  defp line_num({_line_num_old, line_num_new}, :ins, opts) do\n    old = String.duplicate(@blank, opts[:line_num_digits])\n\n    new =\n      line_num_new\n      |> to_string()\n      |> String.pad_leading(opts[:line_num_digits], @line_num_pad)\n\n    [old, @blank, new]\n  end\n\n  defp line_diff(del, ins, opts) do\n    diff = String.myers_difference(del, ins)\n\n    Enum.reduce(diff, {[], []}, fn\n      {:eq, str}, {del, ins} -> {[del | str], [ins | str]}\n      {:del, str}, {del, ins} -> {[del | colorize(str, :del, true, opts)], ins}\n      {:ins, str}, {del, ins} -> {del, [ins | colorize(str, :ins, true, opts)]}\n    end)\n  end\n\n  defp colorize(str, kind, space?, opts) do\n    if Keyword.fetch!(opts, :color) && Keyword.has_key?(@colors, kind) do\n      color = Keyword.fetch!(@colors, kind)\n\n      if space? do\n        str\n        |> String.split(~r/[\\t\\s]+/, include_captures: true)\n        |> Enum.map(fn\n          <<start::binary-size(1), _::binary>> = str when start in [\"\\t\", \"\\s\"] ->\n            IO.ANSI.format([color[:space], str])\n\n          str ->\n            IO.ANSI.format([color[:text], str])\n        end)\n      else\n        IO.ANSI.format([color[:text], str])\n      end\n    else\n      str\n    end\n  end\n\n  defp add_line_nums({line_num_old, line_num_new}, lines, kind \\\\ :eq) do\n    case kind do\n      :eq -> {line_num_old + lines, line_num_new + lines}\n      :ins -> {line_num_old, line_num_new + lines}\n      :del -> {line_num_old + lines, line_num_new}\n    end\n  end\n\n  defp insert_cr_symbols(diffs, false), do: diffs\n  defp insert_cr_symbols(diffs, true), do: do_insert_cr_symbols(diffs, [])\n\n  defp do_insert_cr_symbols([], acc), do: Enum.reverse(acc)\n\n  defp do_insert_cr_symbols([{:del, del}, {:ins, ins} | rest], acc) do\n    {del, ins} = do_insert_cr_symbols(del, ins, {[], []})\n    do_insert_cr_symbols(rest, [{:ins, ins}, {:del, del} | acc])\n  end\n\n  defp do_insert_cr_symbols([diff | rest], acc) do\n    do_insert_cr_symbols(rest, [diff | acc])\n  end\n\n  defp do_insert_cr_symbols([left | left_rest], [right | right_rest], {left_acc, right_acc}) do\n    {left, right} = insert_cr_symbol(left, right)\n    do_insert_cr_symbols(left_rest, right_rest, {[left | left_acc], [right | right_acc]})\n  end\n\n  defp do_insert_cr_symbols([], right, {left_acc, right_acc}) do\n    left = Enum.reverse(left_acc)\n    right = right_acc |> Enum.reverse() |> Enum.concat(right)\n    {left, right}\n  end\n\n  defp do_insert_cr_symbols(left, [], {left_acc, right_acc}) do\n    left = left_acc |> Enum.reverse() |> Enum.concat(left)\n    right = Enum.reverse(right_acc)\n    {left, right}\n  end\n\n  defp insert_cr_symbol(left, right) do\n    case {String.ends_with?(left, \"\\r\"), String.ends_with?(right, \"\\r\")} do\n      {bool, bool} -> {left, right}\n      {true, false} -> {String.replace(left, \"\\r\", @cr), right}\n      {false, true} -> {left, String.replace(right, \"\\r\", @cr)}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/help.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Help do\n  use Mix.Task\n\n  @shortdoc \"Prints help information for tasks, aliases, modules, and applications\"\n\n  @moduledoc \"\"\"\n  Prints documentation for tasks, aliases, modules, and applications.\n\n  ## Examples\n\n  Without an explicit argument, this task lists tasks/aliases:\n\n      $ mix help                  - prints all aliases, tasks and their short descriptions\n      $ mix help --search PATTERN - prints all tasks and aliases that contain PATTERN in the name\n      $ mix help --names          - prints all task names and aliases (useful for autocompletion)\n      $ mix help --aliases        - prints all aliases\n\n  You can access documentation for a given task/alias:\n\n      $ mix help TASK/ALIAS       - prints full docs for the given task/alias\n\n  But also for modules, functions, and applications:\n\n      $ mix help MODULE           - prints the definition for the given module\n      $ mix help MODULE.FUN       - prints the definition for the given module+function\n      $ mix help app:APP          - prints a summary of all public modules in application\n\n  ## Colors\n\n  When possible, `mix help` is going to use coloring for formatting\n  the help information. The formatting can be customized by configuring\n  the Mix application either inside your project (in `config/config.exs`)\n  or by using the local config (in `~/.mix/config.exs`).\n\n  For example, to disable color, one may use the configuration:\n\n      [mix: [colors: [enabled: false]]]\n\n  The available color options are:\n\n    * `:enabled`         - shows ANSI formatting (defaults to `IO.ANSI.enabled?/0`)\n    * `:doc_code`        - the attributes for code blocks (cyan, bright)\n    * `:doc_inline_code` - inline code (cyan)\n    * `:doc_headings`    - h1 and h2 (yellow, bright)\n    * `:doc_title`       - the overall heading for the output (reverse, yellow, bright)\n    * `:doc_bold`        - (bright)\n    * `:doc_underline`   - (underline)\n\n  \"\"\"\n\n  @impl true\n  def run(argv)\n\n  def run([]) do\n    loadpaths!()\n\n    modules = load_tasks()\n    aliases = load_aliases()\n\n    {docs, max} = build_doc_list(modules, aliases)\n\n    display_default_task_doc(max)\n    display_doc_list(docs, max)\n    display_iex_task_doc(max)\n    Mix.shell().info(\"\\nUse \\\"mix help <TASK>\\\" for more information on a particular command.\")\n  end\n\n  def run([\"--names\"]) do\n    loadpaths!()\n\n    tasks = Enum.map(load_tasks(), &Mix.Task.task_name/1)\n\n    aliases =\n      Enum.map(Mix.Project.config()[:aliases], fn {alias_name, _} ->\n        Atom.to_string(alias_name)\n      end)\n\n    for info <- Enum.sort(aliases ++ tasks) do\n      Mix.shell().info(info)\n    end\n  end\n\n  def run([\"--aliases\"]) do\n    loadpaths!()\n\n    aliases = load_aliases()\n\n    {docs, max} = build_doc_list([], aliases)\n\n    display_doc_list(docs, max)\n  end\n\n  def run([\"--search\", pattern]) do\n    loadpaths!()\n\n    modules = Enum.filter(load_tasks(), &String.contains?(Mix.Task.task_name(&1), pattern))\n    aliases = Enum.filter(load_aliases(), fn {name, _} -> String.contains?(name, pattern) end)\n\n    {docs, max} = build_doc_list(modules, aliases)\n    display_doc_list(docs, max)\n  end\n\n  def run([\"--search\"]) do\n    Mix.raise(\"Unexpected arguments, expected \\\"mix help --search PATTERN\\\"\")\n  end\n\n  @compile {:no_warn_undefined, IEx.Introspection}\n\n  def run([\"app:\" <> app]) do\n    loadpaths!()\n\n    app = String.to_atom(app)\n\n    # If the application is not available, attempt to load it from Erlang/Elixir\n    if is_nil(Application.spec(app, :vsn)) do\n      try do\n        Mix.ensure_application!(app)\n      rescue\n        _ ->\n          # Otherwise, it may be a dep or the current project not yet compiled\n          if Mix.Project.get() do\n            Mix.Task.run(\"compile\")\n          end\n      end\n    end\n\n    if modules = Application.spec(app, :modules) do\n      for module <- modules,\n          not (module |> Atom.to_string() |> String.starts_with?(\"Elixir.Mix.Tasks.\")),\n          {:docs_v1, _, _, \"text/markdown\", %{\"en\" => <<doc::binary>>}, _, _} <-\n            [Code.fetch_docs(module)] do\n        leading = doc |> String.split([\"\\n\\n\", \"\\r\\n\\r\\n\"], parts: 2) |> hd()\n        \"# #{inspect(module)}\\n#{leading}\\n\"\n      end\n      |> case do\n        [] ->\n          Mix.shell().error(\"No modules with accessible documentation found for #{app}\")\n\n        listing ->\n          docs = listing |> Enum.sort() |> Enum.join()\n          IO.ANSI.Docs.print(docs, \"text/markdown\", ansi_opts())\n      end\n    else\n      Mix.shell().error(\"Application #{app} does not exist or is not loaded\")\n    end\n  end\n\n  def run([module = <<first, _::binary>>]) when first in ?A..?Z or first == ?: do\n    loadpaths!()\n\n    iex_colors = Application.get_env(:iex, :colors, [])\n    mix_colors = Application.get_env(:mix, :colors, [])\n\n    try do\n      Application.put_env(:iex, :colors, mix_colors)\n\n      module\n      |> Code.string_to_quoted!()\n      |> IEx.Introspection.decompose(__ENV__)\n      |> case do\n        :error -> Mix.raise(\"Invalid expression: #{module}\")\n        decomposition -> decomposition\n      end\n      |> IEx.Introspection.h()\n    after\n      Application.put_env(:iex, :colors, iex_colors)\n    end\n  end\n\n  def run([task]) do\n    loadpaths!()\n    opts = ansi_opts()\n\n    for doc <- verbose_doc(task) do\n      print_doc(task, doc, opts)\n    end\n\n    :ok\n  end\n\n  def run(_) do\n    Mix.raise(\"Unexpected arguments, expected \\\"mix help\\\" or \\\"mix help TASK\\\"\")\n  end\n\n  defp ansi_opts do\n    opts = Application.get_env(:mix, :colors)\n    [width: width(), enabled: ansi_docs?(opts)] ++ opts\n  end\n\n  defp print_doc(task, {doc, location, note}, opts) do\n    IO.ANSI.Docs.print_headings([\"mix #{task}\"], opts)\n    IO.ANSI.Docs.print(doc, \"text/markdown\", opts)\n    IO.puts(\"Location: #{location}\")\n    note && IO.puts(\"\") && IO.ANSI.Docs.print(note, \"text/markdown\", opts)\n  end\n\n  # Loadpaths without checks because tasks may be defined in deps.\n  defp loadpaths! do\n    args = [\n      \"--no-elixir-version-check\",\n      \"--no-deps-check\",\n      \"--no-archives-check\",\n      \"--no-listeners\"\n    ]\n\n    Mix.Task.run(\"loadpaths\", args)\n    Mix.Task.reenable(\"loadpaths\")\n    Mix.Task.reenable(\"deps.loadpaths\")\n  end\n\n  defp load_tasks() do\n    Enum.filter(Mix.Task.load_all(), &(Mix.Task.moduledoc(&1) != false))\n  end\n\n  defp load_aliases() do\n    aliases = Mix.Project.config()[:aliases]\n\n    Map.new(aliases, fn {alias_name, alias_tasks} -> {Atom.to_string(alias_name), alias_tasks} end)\n  end\n\n  defp ansi_docs?(opts) do\n    Keyword.get(opts, :enabled, IO.ANSI.enabled?())\n  end\n\n  defp width() do\n    case :io.columns() do\n      {:ok, width} -> min(width, 80)\n      {:error, _} -> 80\n    end\n  end\n\n  defp format_task(task, max, doc) do\n    String.pad_trailing(task, max) <> \" # \" <> doc\n  end\n\n  defp where_is_file(module) do\n    case :code.where_is_file(Atom.to_charlist(module) ++ ~c\".beam\") do\n      :non_existing ->\n        \"not available\"\n\n      location ->\n        location\n        |> Path.dirname()\n        |> Path.expand()\n        |> Path.relative_to_cwd()\n    end\n  end\n\n  defp display_default_task_doc(max) do\n    project = Mix.Project.get()\n\n    default =\n      if function_exported?(project, :cli, 0) do\n        project.cli()[:default_task] || \"run\"\n      else\n        \"run\"\n      end\n\n    message = \"Runs the default task (current: \\\"mix #{default}\\\")\"\n    Mix.shell().info(format_task(\"mix\", max, message))\n  end\n\n  defp display_iex_task_doc(max) do\n    Mix.shell().info(format_task(\"iex -S mix\", max, \"Starts IEx and runs the default task\"))\n  end\n\n  defp display_doc_list(docs, max) do\n    Enum.each(Enum.sort(docs), fn {task, doc} ->\n      Mix.shell().info(format_task(task, max, doc))\n    end)\n  end\n\n  defp build_doc_list(modules, aliases) do\n    {task_docs, task_max} = build_task_doc_list(modules)\n    {alias_docs, alias_max} = build_alias_doc_list(aliases)\n    {task_docs ++ alias_docs, max(task_max, alias_max)}\n  end\n\n  defp build_task_doc_list(modules) do\n    Enum.reduce(modules, {[], 0}, fn module, {docs, max} ->\n      if doc = Mix.Task.shortdoc(module) do\n        task = \"mix \" <> Mix.Task.task_name(module)\n        {[{task, doc} | docs], max(byte_size(task), max)}\n      else\n        {docs, max}\n      end\n    end)\n  end\n\n  defp build_alias_doc_list(aliases) do\n    Enum.reduce(aliases, {[], 0}, fn {alias_name, task}, {docs, max} ->\n      doc = alias_doc(task)\n      task = \"mix \" <> alias_name\n      {[{task, doc} | docs], max(byte_size(task), max)}\n    end)\n  end\n\n  defp alias_doc(task) do\n    \"Alias for \" <> format_alias_doc(task)\n  end\n\n  defp format_alias_doc(task), do: Enum.map_join(List.wrap(task), \", \", &format_alias_task/1)\n\n  defp format_alias_task(task) when is_binary(task), do: task\n\n  defp format_alias_task(task) when is_function(task) do\n    info = Function.info(task)\n    name = Atom.to_string(info[:name])\n\n    cond do\n      info[:type] == :remote -> inspect(task)\n      info[:type] == :local and String.contains?(name, \"/\") -> \"a function\"\n      true -> \"&#{name}/#{info[:arity]}\"\n    end\n  end\n\n  # for invalid aliases\n  defp format_alias_task(task), do: inspect(task)\n\n  defp verbose_doc(task) do\n    aliases = load_aliases()\n\n    has_alias? = Map.has_key?(aliases, task)\n    has_task? = Mix.Task.get(task)\n\n    cond do\n      has_alias? and has_task? ->\n        note = \"There is also a task named \\\"#{task}\\\". The documentation is shown next.\"\n        [alias_doc(aliases[task], note), task_doc(task)]\n\n      has_alias? ->\n        [alias_doc(aliases[task], nil)]\n\n      true ->\n        [task_doc(task)]\n    end\n  end\n\n  defp alias_doc(task_name, note) do\n    alias_doc = \"\"\"\n    Alias for\n\n        #{format_alias(task_name)}\n    \"\"\"\n\n    {alias_doc, \"mix.exs\", note}\n  end\n\n  defp format_alias(task) do\n    inspect(task, pretty: true, width: 0)\n    |> String.replace(\"\\n\", \"\\n    \")\n  end\n\n  defp task_doc(task) do\n    module = Mix.Task.get!(task)\n    doc = Mix.Task.moduledoc(module) || \"There is no documentation for this task\"\n    {doc, where_is_file(module), nil}\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/iex.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Iex do\n  use Mix.Task\n\n  @moduledoc \"\"\"\n  A task that simply instructs users to run `iex -S mix`.\n  \"\"\"\n\n  @impl true\n  def run(_) do\n    Mix.raise(\"To use IEx with Mix, please run \\\"iex -S mix\\\"\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/loadconfig.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Loadconfig do\n  use Mix.Task\n\n  @shortdoc \"Loads and persists the given configuration\"\n\n  @moduledoc \"\"\"\n  Loads and persists the given configuration.\n\n      $ mix loadconfig path/to/config.exs\n\n  Any configuration file loaded with `loadconfig` is treated\n  as a compile-time configuration. This means all application\n  keys are merged into their respective applications, however\n  the values themselves are not deep merged.\n\n  `config/config.exs` is **always loaded automatically**\n  by the Mix CLI when it boots. `config/runtime.exs` is loaded\n  automatically by `mix app.config` before starting the current\n  application. Therefore there is no need to load those config\n  files directly.\n\n  This task is automatically re-enabled, so it can be called\n  multiple times to load different configs.\n  \"\"\"\n\n  @reserved_apps [:stdlib, :kernel]\n\n  @impl true\n  def run(args) do\n    Mix.Task.reenable(\"loadconfig\")\n\n    case args do\n      [] -> load_default()\n      [file] -> load_compile(file)\n    end\n  end\n\n  defp load_default do\n    config_path = Mix.Project.config()[:config_path]\n\n    if config_path != nil and (File.regular?(config_path) or config_path != \"config/config.exs\") do\n      load_compile(config_path)\n    else\n      []\n    end\n  end\n\n  @doc false\n  def read_compile() do\n    Mix.State.read_cache(__MODULE__, [])\n  end\n\n  @doc false\n  # Loads compile-time configuration, they support imports, and are not deep merged.\n  def load_compile(file) do\n    {config, files} = Config.Reader.read_imports!(file, env: Mix.env(), target: Mix.target())\n    Mix.ProjectStack.loaded_config(persist_apps(config, file), files)\n    Mix.State.write_cache(__MODULE__, config)\n  end\n\n  @doc false\n  # Loads runtime configuration, they do not support imports, and are deep merged.\n  def load_runtime(file) do\n    config = Config.Reader.read!(file, env: Mix.env(), target: Mix.target(), imports: :disabled)\n    Mix.ProjectStack.loaded_config(persist_apps(hydrate_apps(config), file), [])\n    config\n  end\n\n  @doc false\n  def preserve_config(fun) do\n    config = read_compile()\n\n    try do\n      delete_all_config(config)\n      fun.()\n    after\n      delete_all_config(read_compile())\n      Application.put_all_env(config, persistent: true)\n    end\n  end\n\n  defp delete_all_config(config) do\n    for {app, kv} <- config, Application.spec(app, :vsn) == nil, {key, _} <- kv do\n      Application.delete_env(app, key, persistent: true)\n    end\n  end\n\n  defp hydrate_apps(config) do\n    for {app, pairs} <- config do\n      hd(Config.Reader.merge([{app, Application.get_all_env(app)}], [{app, pairs}]))\n    end\n  end\n\n  defp persist_apps(config, file) do\n    Application.put_all_env(config, persistent: true)\n    apps = Keyword.keys(config)\n\n    case Enum.filter(@reserved_apps, &(&1 in apps)) do\n      [] ->\n        :ok\n\n      reserved_apps ->\n        Mix.shell().error(\"\"\"\n        Cannot configure base applications: #{inspect(reserved_apps)}\n\n        These applications are already started by the time the configuration\n        executes and these configurations have no effect.\n\n        If you want to configure these applications for a release, you can\n        specify them in your vm.args file:\n\n            -kernel config_key config_value\n\n        Alternatively, if you must configure them dynamically, you can wrap\n        them in a conditional block in your config files:\n\n            if System.get_env(\"RELEASE_MODE\") do\n              config :kernel, ...\n            end\n\n        and then configure your releases to reboot after configuration:\n\n            releases: [\n              my_app: [reboot_system_after_config: true]\n            ]\n\n        This happened when loading #{Path.relative_to_cwd(file)} or\n        one of its imports.\n        \"\"\")\n    end\n\n    apps\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/loadpaths.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Loadpaths do\n  use Mix.Task\n\n  @moduledoc \"\"\"\n  Loads the application and its dependencies paths.\n\n  This task is never directly invoked from the command line,\n  but it is rather used as building block by other tasks.\n\n  Dependencies are checked, compiled, and loaded. Each step\n  can be explicitly disabled with flags.\n\n  ## Configuration\n\n    * `:elixir` - matches the current Elixir version against the\n      given requirement\n\n  ## Command line options\n\n    * `--listeners` - starts Mix listeners (they are started by default,\n      unless `--no-listeners` or `--no-deps-check` are given)\n    * `--no-archives-check` - does not check archives\n    * `--no-compile` - does not compile dependencies, only check and load them\n    * `--no-deps-check` - does not check dependencies, only load available ones\n    * `--no-elixir-version-check` - does not check Elixir version\n    * `--no-listeners` - does not start Mix listeners\n    * `--no-optional-deps` - does not compile or load optional deps\n\n  \"\"\"\n  @impl true\n  def run(args) do\n    config = Mix.Project.config()\n\n    # --from-mix-deps-compile is used only internally to avoid\n    # recursively checking and loading dependencies that have\n    # already been loaded. It has no purpose from Mix.CLI\n    # because running a task may load deps.\n    if \"--from-mix-deps-compile\" not in args do\n      Mix.Task.run(\"deps.loadpaths\", args)\n    end\n\n    if config[:app] do\n      load_project(config)\n    end\n\n    :ok\n  end\n\n  defp load_project(config) do\n    vsn = {System.version(), :erlang.system_info(:otp_release)}\n    scm = config[:build_scm]\n\n    # Erase the app build if we have lock mismatch.\n    # We do this to force full recompilation when\n    # any of SCM or Elixir version changes. Applies\n    # to dependencies and the main project alike.\n    case Mix.Dep.ElixirSCM.read() do\n      {:ok, old_vsn, old_scm, _deps_lock} when old_vsn != vsn or old_scm != scm ->\n        if Mix.debug?() do\n          Mix.shell().info(\n            \"-- Recompiling #{inspect(config[:app])} because Erlang/OTP, Elixir, or SCM version changed\"\n          )\n        end\n\n        File.rm_rf(Mix.Project.app_path(config))\n        File.rm_rf(Mix.Project.consolidation_path(config))\n\n      _ ->\n        :ok\n    end\n\n    # We don't cache the current application as we may still write to it\n    Code.prepend_path(Mix.Project.compile_path(config))\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/local.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Local do\n  use Mix.Task\n\n  @shortdoc \"Lists tasks installed locally via archives\"\n\n  @moduledoc \"\"\"\n  Lists tasks installed locally via archives.\n  \"\"\"\n\n  @impl true\n  def run([]) do\n    shell = Mix.shell()\n    modules = Mix.Local.archives_tasks()\n\n    docs =\n      for module <- modules do\n        {Mix.Task.task_name(module), Mix.Task.shortdoc(module)}\n      end\n\n    max =\n      Enum.reduce(docs, 0, fn {task, _}, acc ->\n        max(byte_size(task), acc)\n      end)\n\n    sorted = Enum.sort(docs)\n\n    Enum.each(sorted, fn {task, doc} ->\n      shell.info(format(~c\"mix ~-#{max}s # ~ts\", [task, doc]))\n    end)\n  end\n\n  defp format(expression, args) do\n    :io_lib.format(expression, args) |> IO.iodata_to_binary()\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/local.hex.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Local.Hex do\n  use Mix.Task\n\n  @hex_list_path \"/installs/hex.csv\"\n  @hex_archive_path \"/installs/[ELIXIR_VERSION]/hex-[HEX_VERSION]-otp-[OTP_RELEASE].ez\"\n\n  @shortdoc \"Installs Hex locally\"\n\n  @moduledoc \"\"\"\n  Installs Hex locally.\n\n      $ mix local.hex [version]\n\n  By default the latest compatible version of Hex will be installed, unless\n  `version` is specified.\n\n  If installing a precompiled Hex does not work, you can compile and install\n  Hex directly with this command:\n\n      $ mix archive.install github hexpm/hex branch latest\n\n  ## Command line options\n\n    * `--force` - forces installation without a shell prompt; primarily\n      intended for automation in build systems like `make`\n\n    * `--if-missing` - performs installation only if Hex is not installed yet;\n      intended to avoid repeatedly reinstalling Hex in automation when a script\n      may be run multiple times\n\n  If both options are set, the shell prompt is skipped and Hex is not\n  re-installed if it was already installed.\n\n  ## Mirrors\n\n  If you want to change the [default mirror](https://builds.hex.pm)\n  used for fetching Hex, set the `HEX_BUILDS_URL` environment variable.\n  \"\"\"\n  @switches [if_missing: :boolean, force: :boolean]\n  @compile {:no_warn_undefined, {Hex, :version, 0}}\n\n  @impl true\n  def run(argv) do\n    {opts, args} = OptionParser.parse!(argv, switches: @switches)\n    version = List.first(args)\n\n    should_install? =\n      if Keyword.get(opts, :if_missing, false) do\n        if version do\n          not Code.ensure_loaded?(Hex) or Version.compare(Hex.version(), version) == :gt\n        else\n          not Code.ensure_loaded?(Hex)\n        end\n      else\n        true\n      end\n\n    argv =\n      if Keyword.get(opts, :force, false) do\n        [\"--force\"]\n      else\n        []\n      end\n\n    should_install? && run_install(version, argv)\n  end\n\n  defp run_install(version, argv) do\n    hex_url = Mix.Hex.url()\n\n    {elixir_version, hex_version, sha512, otp_release} =\n      Mix.Local.find_matching_versions!(\"Hex\", version, hex_url <> @hex_list_path)\n\n    url =\n      (hex_url <> @hex_archive_path)\n      |> String.replace(\"[ELIXIR_VERSION]\", elixir_version)\n      |> String.replace(\"[OTP_RELEASE]\", otp_release)\n      |> String.replace(\"[HEX_VERSION]\", hex_version)\n\n    # Unload the Hex module we loaded earlier to avoid conflicts when Hex is updated\n    # and then used without restarting the VM\n    :code.purge(Hex)\n\n    Mix.Tasks.Archive.Install.run([url, \"--sha512\", sha512 | argv])\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/local.rebar.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Local.Rebar do\n  use Mix.Task\n\n  @rebar3_list_url \"/installs/rebar.csv\"\n  @rebar3_escript_url \"/installs/[ELIXIR_VERSION]/rebar3-[REBAR_VERSION]-otp-[OTP_RELEASE]\"\n\n  @shortdoc \"Installs Rebar locally\"\n\n  @moduledoc \"\"\"\n  Fetches a copy of `rebar3` from the given path or URL.\n\n  It defaults to safely download a Rebar copy from Hex's CDN.\n  However, a URL can be given as an argument, usually for an existing\n  local copy of Rebar:\n\n      $ mix local.rebar rebar3 path/to/rebar\n\n  The local copy is stored in your `MIX_HOME` (defaults to `~/.mix`)\n  according to the current Elixir. The installed version of Rebar will\n  be used whenever required by `mix deps.compile`.\n\n  ## Command line options\n\n    * `rebar3 PATH` - specifies a path for `rebar3`\n\n    * `--sha512` - checks the Rebar script matches the given SHA-512 checksum\n\n    * `--force` - forces installation without a shell prompt; primarily\n      intended for automation in build systems like `make`\n\n    * `--if-missing` - performs installation only if not installed yet;\n      intended to avoid repeatedly reinstalling in automation when a script\n      may be run multiple times\n\n  ## Mirrors\n\n  If you want to change the [default mirror](https://builds.hex.pm)\n  to use for fetching `rebar` please set the `HEX_BUILDS_URL` environment variable.\n  \"\"\"\n\n  @switches [force: :boolean, sha512: :string, if_missing: :boolean]\n\n  @impl true\n  def run(argv) do\n    {opts, args, _} = OptionParser.parse(argv, switches: @switches)\n\n    case args do\n      [\"rebar3\", path | _] ->\n        maybe_install_from_path(:rebar3, path, opts)\n\n      [] ->\n        maybe_install_from_s3(:rebar3, @rebar3_list_url, @rebar3_escript_url, opts)\n\n      _ ->\n        Mix.raise(\n          \"Invalid arguments given to mix local.rebar: #{inspect(args)}. \" <>\n            \"To find out the proper call syntax run \\\"mix help local.rebar\\\"\"\n        )\n    end\n  end\n\n  defp maybe_install_from_path(manager, path, opts) do\n    if not skip_install?(manager, opts) do\n      install_from_path(manager, path, opts)\n    end\n  end\n\n  defp maybe_install_from_s3(manager, list_url, escript_url, opts) do\n    if not skip_install?(manager, opts) do\n      install_from_s3(manager, list_url, escript_url, opts)\n    end\n  end\n\n  defp install_from_path(manager, path, opts) do\n    local = Mix.Rebar.local_rebar_path(manager)\n\n    if opts[:force] || Mix.Generator.overwrite?(local) do\n      case Mix.Utils.read_path(path, opts) do\n        {:ok, binary} ->\n          File.mkdir_p!(Path.dirname(local))\n          File.write!(local, binary)\n          File.chmod!(local, 0o755)\n          Mix.shell().info([:green, \"* creating \", :reset, Path.relative_to_cwd(local)])\n\n        :badpath ->\n          Mix.raise(\"Expected #{inspect(path)} to be a local file path\")\n\n        {:local, message} ->\n          Mix.raise(message)\n\n        {kind, message} when kind in [:remote, :checksum] ->\n          Mix.raise(\"\"\"\n          #{message}\n\n          Could not fetch #{manager} at:\n\n              #{path}\n\n          Please download the file above manually to your current directory and run:\n\n              mix local.rebar #{manager} ./#{Path.basename(local)}\n          \"\"\")\n      end\n    end\n\n    true\n  end\n\n  defp install_from_s3(manager, list_url, escript_url, opts) do\n    hex_url = Mix.Hex.url()\n    list_url = hex_url <> list_url\n\n    {elixir_version, rebar_version, sha512, otp_release} =\n      Mix.Local.find_matching_versions!(\"Rebar\", _version = nil, list_url)\n\n    url =\n      (hex_url <> escript_url)\n      |> String.replace(\"[ELIXIR_VERSION]\", elixir_version)\n      |> String.replace(\"[REBAR_VERSION]\", rebar_version)\n      |> String.replace(\"[OTP_RELEASE]\", otp_release)\n\n    install_from_path(manager, url, Keyword.put(opts, :sha512, sha512))\n  end\n\n  defp skip_install?(manager, opts) do\n    Keyword.get(opts, :if_missing, false) and\n      manager\n      |> Mix.Rebar.local_rebar_path()\n      |> File.exists?()\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/new.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.New do\n  use Mix.Task\n  import Mix.Generator\n\n  @shortdoc \"Creates a new Elixir project\"\n\n  @moduledoc \"\"\"\n  Creates a new Elixir project.\n  It expects the path of the project as argument.\n\n      $ mix new PATH [--app APP] [--module MODULE] [--sup] [--umbrella]\n\n  A project at the given PATH will be created. The\n  application name and module name will be retrieved\n  from the path, unless `--module` or `--app` is given.\n\n  An `--app` option can be given in order to\n  name the OTP application for the project.\n\n  A `--module` option can be given in order\n  to name the modules in the generated code skeleton.\n\n  A `--sup` option can be given to generate an OTP application\n  skeleton including a supervision tree. Normally an app is\n  generated without a supervisor and without the app callback.\n\n  An `--umbrella` option can be given to generate an\n  umbrella project.\n\n  ## Examples\n\n      $ mix new hello_world\n\n  Is equivalent to:\n\n      $ mix new hello_world --module HelloWorld\n\n  To generate an app with a supervision tree and an application callback:\n\n      $ mix new hello_world --sup\n\n  To generate an umbrella application with sub applications:\n\n      $ mix new hello_world --umbrella\n      $ cd hello_world/apps\n      $ mix new child_app\n\n  \"\"\"\n\n  @switches [\n    app: :string,\n    module: :string,\n    sup: :boolean,\n    umbrella: :boolean\n  ]\n\n  @impl true\n  def run(argv) do\n    {opts, argv} = OptionParser.parse!(argv, strict: @switches)\n\n    case argv do\n      [] ->\n        Mix.raise(\n          \"Expected PATH to be given. \" <>\n            \"Use \\\"mix new PATH\\\" or run \\\"mix help new\\\" for more information\"\n        )\n\n      [path | _] ->\n        app = opts[:app] || Path.basename(Path.expand(path))\n        check_application_name!(app, !opts[:app])\n        mod = opts[:module] || Macro.camelize(app)\n        check_mod_name_validity!(mod)\n        check_mod_name_availability!(mod)\n\n        if path != \".\" do\n          check_directory_existence!(path)\n          File.mkdir_p!(path)\n        end\n\n        File.cd!(path, fn ->\n          if opts[:umbrella] do\n            generate_umbrella(app, mod, path, opts)\n          else\n            generate(app, mod, path, opts)\n          end\n        end)\n    end\n  end\n\n  defp generate(app, mod, path, opts) do\n    assigns = [\n      app: app,\n      mod: mod,\n      sup_app: sup_app(mod, !!opts[:sup]),\n      version: get_version(System.version())\n    ]\n\n    mod_filename = Macro.underscore(mod)\n\n    create_file(\"README.md\", readme_template(assigns))\n    create_file(\".formatter.exs\", formatter_template(assigns))\n    create_file(\".gitignore\", gitignore_template(assigns))\n\n    if in_umbrella?() do\n      create_file(\"mix.exs\", mix_exs_apps_template(assigns))\n    else\n      create_file(\"mix.exs\", mix_exs_template(assigns))\n    end\n\n    create_directory(\"lib\")\n    create_file(\"lib/#{mod_filename}.ex\", lib_template(assigns))\n\n    if opts[:sup] do\n      create_file(\"lib/#{mod_filename}/application.ex\", lib_app_template(assigns))\n    end\n\n    create_directory(\"test\")\n    create_file(\"test/test_helper.exs\", test_helper_template(assigns))\n    create_file(\"test/#{mod_filename}_test.exs\", test_template(assigns))\n\n    \"\"\"\n\n    Your Mix project was created successfully.\n    You can use \"mix\" to compile it, test it, and more:\n\n        #{cd_path(path)}mix test\n\n    Run \"mix help\" for more commands.\n    \"\"\"\n    |> String.trim_trailing()\n    |> Mix.shell().info()\n  end\n\n  @doc \"\"\"\n  Returns a list of reserved application names.\n  \"\"\"\n  def reserved_application_names do\n    # 1. Command line flags with multiple args can conflict with application names\n    # 2. OTP names\n    # 3. Elixir names\n    ~w(boot_var compile config configfd env pa pz path run s setcookie)a ++\n      ~w(otp asn1 common_test compiler crypto debugger dialyzer diameter\n         edoc eldap erl_docgen erl_interface erts et eunit ftp\n         inets jinterface kernel megaco mnesia observer odbc os_mon\n         parsetools public_key reltool runtime_tools sasl snmp ssh\n         ssl stdlib syntax_tools tftp toolbar tools typer wx xmerl)a ++\n      ~w(eex elixir ex_unit iex logger mix)a\n  end\n\n  defp sup_app(_mod, false), do: \"\"\n  defp sup_app(mod, true), do: \",\\n      mod: {#{mod}.Application, []}\"\n\n  defp cd_path(\".\"), do: \"\"\n  defp cd_path(path), do: \"cd #{path}\\n    \"\n\n  defp generate_umbrella(_app, mod, path, _opts) do\n    assigns = [app: nil, mod: mod]\n\n    create_file(\"README.md\", readme_template(assigns))\n    create_file(\".formatter.exs\", formatter_umbrella_template(assigns))\n    create_file(\".gitignore\", gitignore_template(assigns))\n    create_file(\"mix.exs\", mix_exs_umbrella_template(assigns))\n\n    create_directory(\"apps\")\n\n    create_directory(\"config\")\n    create_file(\"config/config.exs\", config_umbrella_template(assigns))\n\n    \"\"\"\n\n    Your umbrella project was created successfully.\n    Inside your project, you will find an apps/ directory\n    where you can create and host many apps:\n\n        #{cd_path(path)}cd apps\n        mix new my_app\n\n    Commands like \"mix compile\" and \"mix test\" when executed\n    in the umbrella project root will automatically run\n    for each application in the apps/ directory.\n    \"\"\"\n    |> String.trim_trailing()\n    |> Mix.shell().info()\n  end\n\n  defp check_application_name!(name, inferred?) do\n    if message = invalid_app(name) || reserved_app(name) do\n      Mix.raise(\n        message <>\n          if inferred? do\n            \". The application name is inferred from the path, if you'd like to \" <>\n              \"explicitly name the application then use the \\\"--app APP\\\" option\"\n          else\n            \"\"\n          end\n      )\n    end\n  end\n\n  defp invalid_app(name) do\n    if not (name =~ ~r/^[a-z][a-z0-9_]*$/) do\n      \"Application name must start with a lowercase ASCII letter, followed by \" <>\n        \"lowercase ASCII letters, numbers, or underscores, got: #{inspect(name)}\"\n    end\n  end\n\n  defp reserved_app(name) do\n    atom_name = String.to_atom(name)\n\n    if atom_name in reserved_application_names() or Application.ensure_loaded(atom_name) == :ok do\n      \"Cannot use application name #{inspect(name)} because it is already used by Erlang/OTP or Elixir\"\n    end\n  end\n\n  defp check_mod_name_validity!(name) do\n    if not (name =~ ~r/^[A-Z]\\w*(\\.[A-Z]\\w*)*$/) do\n      Mix.raise(\n        \"Module name must be a valid Elixir alias (for example: Foo.Bar), got: #{inspect(name)}\"\n      )\n    end\n  end\n\n  defp check_mod_name_availability!(name) do\n    name = Module.concat(Elixir, name)\n\n    if Code.ensure_loaded?(name) do\n      Mix.raise(\"Module name #{inspect(name)} is already taken, please choose another name\")\n    end\n  end\n\n  defp check_directory_existence!(path) do\n    msg = \"The directory #{inspect(path)} already exists. Are you sure you want to continue?\"\n\n    if File.dir?(path) and not Mix.shell().yes?(msg) do\n      Mix.raise(\"Please select another directory for installation\")\n    end\n  end\n\n  defp get_version(version) do\n    {:ok, version} = Version.parse(version)\n\n    \"#{version.major}.#{version.minor}\" <>\n      case version.pre do\n        [h | _] -> \"-#{h}\"\n        [] -> \"\"\n      end\n  end\n\n  defp in_umbrella? do\n    Mix.Project.umbrella?() or\n      (\n        apps = Path.dirname(File.cwd!())\n\n        try do\n          Mix.Project.in_project(:umbrella_check, \"../..\", fn _ ->\n            path = Mix.Project.config()[:apps_path]\n            path && Path.expand(path) == apps\n          end)\n        catch\n          _, _ -> false\n        end\n      )\n  end\n\n  embed_template(:readme, \"\"\"\n  # <%= @mod %>\n\n  **TODO: Add description**\n  <%= if @app do %>\n  ## Installation\n\n  If [available in Hex](https://hex.pm/docs/publish), the package can be installed\n  by adding `<%= @app %>` to your list of dependencies in `mix.exs`:\n\n  ```elixir\n  def deps do\n    [\n      {:<%= @app %>, \"~> 0.1.0\"}\n    ]\n  end\n  ```\n\n  Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)\n  and published on [HexDocs](https://hexdocs.pm). Once published, the docs can\n  be found at <https://hexdocs.pm/<%= @app %>>.\n  <% end %>\n  \"\"\")\n\n  embed_template(:formatter, \"\"\"\n  # Used by \"mix format\"\n  [\n    inputs: [\"{mix,.formatter}.exs\", \"{config,lib,test}/**/*.{ex,exs}\"]\n  ]\n  \"\"\")\n\n  embed_template(:formatter_umbrella, \"\"\"\n  # Used by \"mix format\"\n  [\n    inputs: [\"mix.exs\", \"config/*.exs\"],\n    subdirectories: [\"apps/*\"]\n  ]\n  \"\"\")\n\n  embed_template(:gitignore, \"\"\"\n  # The directory Mix will write compiled artifacts to.\n  /_build/\n\n  # If you run \"mix test --cover\", coverage assets end up here.\n  /cover/\n\n  # The directory Mix downloads your dependencies sources to.\n  /deps/\n\n  # Where third-party dependencies like ExDoc output generated docs.\n  /doc/\n\n  # Temporary files, for example, from tests.\n  /tmp/\n\n  # If the VM crashes, it generates a dump, let's ignore it too.\n  erl_crash.dump\n\n  # Also ignore archive artifacts (built via \"mix archive.build\").\n  *.ez\n  <%= if @app do %>\n  # Ignore package tarball (built via \"mix hex.build\").\n  <%= @app %>-*.tar\n  <% end %>\n  \"\"\")\n\n  embed_template(:mix_exs, \"\"\"\n  defmodule <%= @mod %>.MixProject do\n    use Mix.Project\n\n    def project do\n      [\n        app: :<%= @app %>,\n        version: \"0.1.0\",\n        elixir: \"~> <%= @version %>\",\n        start_permanent: Mix.env() == :prod,\n        deps: deps()\n      ]\n    end\n\n    # Run \"mix help compile.app\" to learn about applications.\n    def application do\n      [\n        extra_applications: [:logger]<%= @sup_app %>\n      ]\n    end\n\n    # Run \"mix help deps\" to learn about dependencies.\n    defp deps do\n      [\n        # {:dep_from_hexpm, \"~> 0.3.0\"},\n        # {:dep_from_git, git: \"https://github.com/elixir-lang/my_dep.git\", tag: \"0.1.0\"}\n      ]\n    end\n  end\n  \"\"\")\n\n  embed_template(:mix_exs_apps, \"\"\"\n  defmodule <%= @mod %>.MixProject do\n    use Mix.Project\n\n    def project do\n      [\n        app: :<%= @app %>,\n        version: \"0.1.0\",\n        build_path: \"../../_build\",\n        config_path: \"../../config/config.exs\",\n        deps_path: \"../../deps\",\n        lockfile: \"../../mix.lock\",\n        elixir: \"~> <%= @version %>\",\n        start_permanent: Mix.env() == :prod,\n        deps: deps()\n      ]\n    end\n\n    # Run \"mix help compile.app\" to learn about applications.\n    def application do\n      [\n        extra_applications: [:logger]<%= @sup_app %>\n      ]\n    end\n\n    # Run \"mix help deps\" to learn about dependencies.\n    defp deps do\n      [\n        # {:dep_from_hexpm, \"~> 0.3.0\"},\n        # {:dep_from_git, git: \"https://github.com/elixir-lang/my_dep.git\", tag: \"0.1.0\"},\n        # {:sibling_app_in_umbrella, in_umbrella: true}\n      ]\n    end\n  end\n  \"\"\")\n\n  embed_template(:mix_exs_umbrella, \"\"\"\n  defmodule <%= @mod %>.MixProject do\n    use Mix.Project\n\n    def project do\n      [\n        apps_path: \"apps\",\n        version: \"0.1.0\",\n        start_permanent: Mix.env() == :prod,\n        deps: deps()\n      ]\n    end\n\n    # Dependencies listed here are available only for this\n    # project and cannot be accessed from applications inside\n    # the apps folder.\n    #\n    # Run \"mix help deps\" for examples and options.\n    defp deps do\n      []\n    end\n  end\n  \"\"\")\n\n  embed_template(:config_umbrella, ~S\"\"\"\n  # This file is responsible for configuring your umbrella\n  # and **all applications** and their dependencies with the\n  # help of the Config module.\n  #\n  # Note that all applications in your umbrella share the\n  # same configuration and dependencies, which is why they\n  # all use the same configuration file. If you want different\n  # configurations or dependencies per app, it is best to\n  # move said applications out of the umbrella.\n  import Config\n\n  # Sample configuration:\n  #\n  #     config :logger, :default_handler,\n  #       level: :info\n  #\n  #     config :logger, :default_formatter,\n  #       format: \"$date $time [$level] $metadata$message\\n\",\n  #       metadata: [:user_id]\n  #\n  \"\"\")\n\n  embed_template(:lib, \"\"\"\n  defmodule <%= @mod %> do\n    @moduledoc \\\"\"\"\n    Documentation for `<%= @mod %>`.\n    \\\"\"\"\n\n    @doc \\\"\"\"\n    Hello world.\n\n    ## Examples\n\n        iex> <%= @mod %>.hello()\n        :world\n\n    \\\"\"\"\n    def hello do\n      :world\n    end\n  end\n  \"\"\")\n\n  embed_template(:lib_app, \"\"\"\n  defmodule <%= @mod %>.Application do\n    # See https://hexdocs.pm/elixir/Application.html\n    # for more information on OTP Applications\n    @moduledoc false\n\n    use Application\n\n    @impl true\n    def start(_type, _args) do\n      children = [\n        # Starts a worker by calling: <%= @mod %>.Worker.start_link(arg)\n        # {<%= @mod %>.Worker, arg}\n      ]\n\n      # See https://hexdocs.pm/elixir/Supervisor.html\n      # for other strategies and supported options\n      opts = [strategy: :one_for_one, name: <%= @mod %>.Supervisor]\n      Supervisor.start_link(children, opts)\n    end\n  end\n  \"\"\")\n\n  embed_template(:test, \"\"\"\n  defmodule <%= @mod %>Test do\n    use ExUnit.Case\n    doctest <%= @mod %>\n\n    test \"greets the world\" do\n      assert <%= @mod %>.hello() == :world\n    end\n  end\n  \"\"\")\n\n  embed_template(:test_helper, \"\"\"\n  ExUnit.start()\n  \"\"\")\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/profile.cprof.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Profile.Cprof do\n  use Mix.Task\n\n  @shortdoc \"Profiles the given file or expression with cprof\"\n\n  @moduledoc \"\"\"\n  Profiles the given file or expression using Erlang's `cprof` tool.\n\n  [`:cprof`](`:cprof`) can be useful when you want to discover the bottlenecks related\n  to function calls.\n\n  Before running the code, it invokes the `app.start` task which compiles\n  and loads your project. After that, the target expression is profiled together\n  with all matching function calls, by setting breakpoints containing\n  counters. These can only be set on BEAM code so BIFs cannot be call\n  count traced.\n\n  To profile the code, you can use syntax similar to the `mix run` task:\n\n      $ mix profile.cprof -e Hello.world\n      $ mix profile.cprof -e \"[1, 2, 3] |> Enum.reverse |> Enum.map(&Integer.to_string/1)\"\n      $ mix profile.cprof my_script.exs arg1 arg2 arg3\n\n  This task is automatically re-enabled, so you can profile multiple times\n  in the same Mix invocation.\n\n  ## Command line options\n\n    * `--matching` - only profile calls matching the given `Module.function/arity` pattern\n    * `--limit` - filters out any results with a call count less than the limit\n    * `--module` - filters out any results not pertaining to the given module\n    * `--eval`, `-e` - evaluate the given code\n    * `--require`, `-r` - requires pattern before running the command\n    * `--parallel`, `-p` - makes all requires parallel\n    * `--no-compile` - does not compile even if files require compilation\n    * `--no-deps-check` - does not check dependencies\n    * `--no-archives-check` - does not check archives\n    * `--no-halt` - does not halt the system after running the command\n    * `--no-start` - does not start applications after compilation\n    * `--no-elixir-version-check` - does not check the Elixir version from mix.exs\n\n  ## Profile output\n\n  Example output:\n                                                                           CNT\n      Total                                                                 15\n      Enum                                                                   6  <--\n        Enum.\"-map/2-lists^map/1-0-\"/2                                       4\n        Enum.reverse/1                                                       1\n        Enum.map/2                                                           1\n      :elixir_compiler                                                       4  <--\n        anonymous fn/1 in :elixir_compiler.__FILE__/1                        3\n        anonymous fn/0 in :elixir_compiler.__FILE__/1                        1\n      String.Chars.Integer                                                   3  <--\n        String.Chars.Integer.to_string/1                                     3\n      :erlang                                                                2  <--\n        :erlang.trace_pattern/3                                              2\n      Profile done over 20229 matching functions\n\n  The default output contains data gathered from all matching functions. The left\n  column structures each module and its total call count trace is presented on the right.\n  Each module has its count discriminated by function below. The `<--` symbol is meant to\n  help visualize where a new module call count begins.\n\n  The first row (Total) is the sum of all function calls. In the last row the number of\n  matching functions that were considered for profiling is presented.\n\n  When `--matching` option is specified, call count tracing will be started only for\n  the functions matching the given pattern:\n\n      String.Chars.Integer                                                   3  <--\n        String.Chars.Integer.to_string/1                                     3\n      Profile done over 1 matching functions\n\n  The pattern can be a module name, such as `String` to count all calls to that module,\n  a call without arity, such as `String.split`, to count all calls to that function\n  regardless of arity, or a call with arity, such as `String.split/3`, to count all\n  calls to that exact module, function and arity.\n\n  ## Caveats\n\n  You should be aware the profiler is stopped as soon as the code has finished running. This\n  may need special attention, when:  running asynchronous code as function calls which were\n  called before the profiler stopped will not be counted; running synchronous code as long\n  running computations and a profiler without a proper MFA trace pattern or filter may\n  lead to a result set which is difficult to comprehend.\n\n  Other caveats are the impossibility to call count trace BIFs, since breakpoints can\n  only be set on BEAM code; functions calls performed by `:cprof` are not traced; the\n  maximum size of a call counter is equal to the host machine's word size\n  (for example, `2_147_483_647` in a 32-bit host).\n  \"\"\"\n\n  @typedoc \"\"\"\n  Options for the cprof profiler.\n  \"\"\"\n  @type profile_opts :: [\n          matching: {module() | :_, atom() | :_, arity() | :_},\n          limit: non_neg_integer(),\n          module: module()\n        ]\n\n  @switches [\n    parallel: :boolean,\n    require: :keep,\n    eval: :keep,\n    config: :keep,\n    matching: :string,\n    halt: :boolean,\n    compile: :boolean,\n    deps_check: :boolean,\n    limit: :integer,\n    module: :string,\n    start: :boolean,\n    archives_check: :boolean,\n    warmup: :boolean,\n    elixir_version_check: :boolean,\n    parallel_require: :keep\n  ]\n\n  @aliases [r: :require, p: :parallel, e: :eval, c: :config]\n\n  @impl true\n  def run(args) do\n    {opts, head} = OptionParser.parse_head!(args, aliases: @aliases, strict: @switches)\n    Mix.Task.reenable(\"profile.cprof\")\n\n    Mix.Tasks.Run.run(\n      [\"--no-mix-exs\" | args],\n      opts,\n      head,\n      &profile_code(&1, opts),\n      &profile_code(File.read!(&1), opts)\n    )\n  end\n\n  defp profile_code(code_string, opts) do\n    opts = Enum.map(opts, &parse_opt/1)\n\n    content =\n      quote do\n        unquote(__MODULE__).profile(\n          fn ->\n            unquote(Code.string_to_quoted!(code_string))\n          end,\n          unquote(Macro.escape(opts))\n        )\n      end\n\n    # Use compile_quoted since it leaves less noise than eval_quoted\n    Code.compile_quoted(content)\n  end\n\n  defp parse_opt({:matching, matching}) do\n    case Mix.Utils.parse_mfa(matching) do\n      {:ok, [m, f, a]} -> {:matching, {m, f, a}}\n      {:ok, [m, f]} -> {:matching, {m, f, :_}}\n      {:ok, [m]} -> {:matching, {m, :_, :_}}\n      :error -> Mix.raise(\"Invalid matching pattern: #{matching}\")\n    end\n  end\n\n  defp parse_opt({:module, module}), do: {:module, string_to_existing_module(module)}\n  defp parse_opt(other), do: other\n\n  @doc \"\"\"\n  Allows to programmatically run the `cprof` profiler on expression in `fun`.\n\n  Returns the return value of `fun`.\n\n  ## Options\n\n    * `:matching` - only profile calls matching the given pattern in form of\n      `{module, function, arity}`, where each element may be replaced by `:_`\n      to allow any value\n    * `:limit` - filters out any results with a call count less than the limit\n    * `:module` - filters out any results not pertaining to the given module\n\n  \"\"\"\n  @spec profile((-> result), profile_opts()) :: result when result: any()\n  def profile(fun, opts \\\\ []) when is_function(fun, 0) do\n    Mix.ensure_application!(:tools)\n    {return_value, num_matched_functions, analysis_result} = profile_and_analyse(fun, opts)\n    print_output(num_matched_functions, analysis_result)\n    :cprof.stop()\n    return_value\n  end\n\n  defp profile_and_analyse(fun, opts) do\n    if Keyword.get(opts, :warmup, true) do\n      IO.puts(\"Warmup...\")\n      fun.()\n    end\n\n    num_matched_functions =\n      case Keyword.fetch(opts, :matching) do\n        {:ok, matching} -> :cprof.start(matching)\n        :error -> :cprof.start()\n      end\n\n    return_value = apply(fun, [])\n\n    :cprof.pause()\n\n    limit = Keyword.get(opts, :limit)\n    module = Keyword.get(opts, :module)\n\n    analysis_result =\n      case {limit, module} do\n        {nil, nil} ->\n          :cprof.analyse()\n\n        {limit, nil} ->\n          :cprof.analyse(limit)\n\n        {limit, module} ->\n          if limit do\n            :cprof.analyse(module, limit)\n          else\n            :cprof.analyse(module)\n          end\n      end\n\n    {return_value, num_matched_functions, analysis_result}\n  end\n\n  defp string_to_existing_module(\":\" <> module), do: String.to_existing_atom(module)\n  defp string_to_existing_module(module), do: Module.concat([module])\n\n  defp print_output(num_matched_functions, {all_call_count, mod_analysis_list}) do\n    print_total_row(all_call_count)\n    Enum.each(mod_analysis_list, &print_analysis_result/1)\n    print_number_of_matched_functions(num_matched_functions)\n  end\n\n  defp print_output(num_matched_functions, {_mod, _call_count, _mod_fun_list} = mod_analysis) do\n    print_analysis_result(mod_analysis)\n    print_number_of_matched_functions(num_matched_functions)\n  end\n\n  defp print_number_of_matched_functions(num_matched_functions) do\n    IO.puts(\"Profile done over #{num_matched_functions} matching functions\")\n  end\n\n  defp print_total_row(all_call_count) do\n    IO.puts(\"\")\n    print_row([\"s\", \"s\", \"s\"], [\"\", \"CNT\", \"\"])\n    print_row([\"s\", \"B\", \"s\"], [\"Total\", all_call_count, \"\"])\n  end\n\n  defp print_analysis_result({module, total_module_count, module_fun_list}) do\n    module\n    |> Atom.to_string()\n    |> module_name_for_printing()\n    |> print_module(total_module_count, \"\", \"<--\")\n\n    Enum.each(module_fun_list, &print_function(&1, \"  \"))\n  end\n\n  defp print_module(module, count, prefix, suffix) do\n    print_row([\"s\", \"B\", \"s\"], [\"#{prefix}#{module}\", count, suffix])\n  end\n\n  defp module_name_for_printing(\"Elixir.\" <> rest = _module_name), do: rest\n  defp module_name_for_printing(module_name), do: \":\" <> module_name\n\n  defp print_function({fun, count}, prefix, suffix \\\\ \"\") do\n    print_row([\"s\", \"B\", \"s\"], [\"#{prefix}#{function_text(fun)}\", count, suffix])\n  end\n\n  defp function_text({module, function, arity}) do\n    Exception.format_mfa(module, function, arity)\n  end\n\n  defp function_text(other), do: inspect(other)\n\n  @columns [-60, 12, 5]\n  defp print_row(formats, data) do\n    Stream.zip(@columns, formats)\n    |> Stream.map(fn {width, format} -> \"~#{width}#{format}\" end)\n    |> Enum.join()\n    |> :io.format(data)\n\n    IO.puts(\"\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/profile.eprof.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Profile.Eprof do\n  use Mix.Task\n\n  @shortdoc \"Profiles the given file or expression with eprof\"\n\n  @moduledoc \"\"\"\n  Profiles the given file or expression using Erlang's `eprof` tool.\n\n  [`:eprof`](`:eprof`) provides time information of each function call and can be useful\n  when you want to discover the bottlenecks related to this.\n\n  Before running the code, it invokes the `app.start` task which compiles\n  and loads your project. After that, the target expression is profiled together\n  with all matching function calls using the Erlang trace BIFs. The tracing of\n  the function calls for that is enabled when the profiling is begun, and\n  disabled when profiling is stopped.\n\n  To profile the code, you can use syntax similar to the `mix run` task:\n\n      $ mix profile.eprof -e Hello.world\n      $ mix profile.eprof -e \"[1, 2, 3] |> Enum.reverse |> Enum.map(&Integer.to_string/1)\"\n      $ mix profile.eprof my_script.exs arg1 arg2 arg3\n\n  This task is automatically re-enabled, so you can profile multiple times\n  in the same Mix invocation.\n\n  ## Command line options\n\n    * `--matching` - only profile calls matching the given `Module.function/arity` pattern\n    * `--calls` - filters out any results with a call count lower than this\n    * `--time` - filters out any results that took lower than specified (in µs)\n    * `--sort` - sorts the results by `time` or `calls` (default: `time`)\n    * `--eval`, `-e` - evaluates the given code\n    * `--require`, `-r` - requires pattern before running the command\n    * `--parallel`, `-p` - makes all requires parallel\n    * `--no-warmup` - skips the warmup step before profiling\n    * `--no-compile` - does not compile even if files require compilation\n    * `--no-deps-check` - does not check dependencies\n    * `--no-archives-check` - does not check archives\n    * `--no-halt` - does not halt the system after running the command\n    * `--no-start` - does not start applications after compilation\n    * `--no-elixir-version-check` - does not check the Elixir version from mix.exs\n\n  ## Profile output\n\n  Example output:\n\n      #                                               CALLS     % TIME µS/CALL\n      Total                                              24 100.0   26    1.08\n      Enum.reduce_range_inc/4                             5  3.85    1    0.20\n      :erlang.make_fun/3                                  1  7.69    2    2.00\n      Enum.each/2                                         1  7.69    2    2.00\n      anonymous fn/0 in :elixir_compiler_0.__FILE__/1     1  7.69    2    2.00\n      :erlang.integer_to_binary/1                         5 15.39    4    0.80\n      :erlang.apply/2                                     1 15.39    4    4.00\n      anonymous fn/3 in Enum.each/2                       5 19.23    5    1.00\n      String.Chars.Integer.to_string/1                    5 23.08    6    1.20\n\n      Profile done over 8 matching functions\n\n  The default output contains data gathered from all matching functions. The first\n  row after the header contains the sums of the partial results and the average time\n  for all the function calls listed. The following rows contain the function call,\n  followed by the number of times that the function was called, then by the percentage\n  of time that the call uses, then the total time for that function in microseconds,\n  and, finally, the average time per call in microseconds.\n\n  When `--matching` option is specified, call count tracing will be started only for\n  the functions matching the given pattern:\n\n      #                                               CALLS     % TIME µS/CALL\n      Total                                               5 100.0    6    1.20\n      String.Chars.Integer.to_string/1                    5 100.0    6    1.20\n\n      Profile done over 1 matching functions\n\n  The pattern can be a module name, such as `String` to count all calls to that module,\n  a call without arity, such as `String.split`, to count all calls to that function\n  regardless of arity, or a call with arity, such as `String.split/3`, to count all\n  calls to that exact module, function and arity.\n\n  ## Caveats\n\n  You should be aware that the code being profiled is running in an anonymous\n  function which is invoked by [`:eprof` module](`:eprof`).\n  Thus, you'll see some additional entries in your profile output. It is also\n  important to note that the profiler is stopped as soon as the code has finished running,\n  and this may need special attention, when: running asynchronous code as function calls which were\n  called before the profiler stopped will not be counted; running synchronous code as long\n  running computations and a profiler without a proper MFA trace pattern or filter may\n  lead to a result set which is difficult to comprehend.\n\n  You should expect a slowdown in your code execution using this tool since `:eprof` has\n  some performance impact on the execution, but the impact is considerably lower than\n  `Mix.Tasks.Profile.Fprof`. If you have a large system try to profile a limited\n  scenario or focus on the main modules or processes. Another alternative is to use\n  `Mix.Tasks.Profile.Cprof` that uses [`:cprof`](`:cprof`) and has a low performance degradation effect.\n  \"\"\"\n\n  @typedoc \"\"\"\n  Options for the eprof profiler.\n  \"\"\"\n  @type profile_opts :: [\n          matching: {module() | :_, atom() | :_, arity() | :_},\n          calls: non_neg_integer(),\n          time: non_neg_integer(),\n          sort: :time | :calls,\n          warmup: boolean(),\n          set_on_spawn: boolean()\n        ]\n\n  @switches [\n    parallel: :boolean,\n    require: :keep,\n    eval: :keep,\n    config: :keep,\n    matching: :string,\n    halt: :boolean,\n    compile: :boolean,\n    deps_check: :boolean,\n    calls: :integer,\n    time: :integer,\n    sort: :string,\n    start: :boolean,\n    archives_check: :boolean,\n    warmup: :boolean,\n    elixir_version_check: :boolean,\n    parallel_require: :keep\n  ]\n\n  @aliases [\n    r: :require,\n    p: :parallel,\n    e: :eval,\n    c: :config\n  ]\n\n  @impl true\n  def run(args) do\n    {opts, head} = OptionParser.parse_head!(args, aliases: @aliases, strict: @switches)\n    Mix.Task.reenable(\"profile.eprof\")\n\n    Mix.Tasks.Run.run(\n      [\"--no-mix-exs\" | args],\n      opts,\n      head,\n      &profile_code(&1, opts),\n      &profile_code(File.read!(&1), opts)\n    )\n  end\n\n  defp profile_code(code_string, opts) do\n    opts = Enum.map(opts, &parse_opt/1)\n\n    content =\n      quote do\n        unquote(__MODULE__).profile(\n          fn ->\n            unquote(Code.string_to_quoted!(code_string))\n          end,\n          unquote(Macro.escape(opts))\n        )\n      end\n\n    # Use compile_quoted since it leaves less noise than eval_quoted\n    Code.compile_quoted(content)\n  end\n\n  defp parse_opt({:matching, matching}) do\n    case Mix.Utils.parse_mfa(matching) do\n      {:ok, [m, f, a]} -> {:matching, {m, f, a}}\n      {:ok, [m, f]} -> {:matching, {m, f, :_}}\n      {:ok, [m]} -> {:matching, {m, :_, :_}}\n      :error -> Mix.raise(\"Invalid matching pattern: #{matching}\")\n    end\n  end\n\n  defp parse_opt({:sort, \"time\"}), do: {:sort, :time}\n  defp parse_opt({:sort, \"calls\"}), do: {:sort, :calls}\n  defp parse_opt({:sort, other}), do: Mix.raise(\"Invalid sort option: #{other}\")\n  defp parse_opt(other), do: other\n\n  @doc \"\"\"\n  Allows to programmatically run the `eprof` profiler on expression in `fun`.\n\n  Returns the return value of `fun`.\n\n  ## Options\n\n    * `:matching` - only profile calls matching the given pattern in form of\n      `{module, function, arity}`, where each element may be replaced by `:_`\n      to allow any value\n    * `:calls` - filters out any results with a call count lower than this\n    * `:time` - filters out any results that took lower than specified (in µs)\n    * `:sort` - sort the results by `:time` or `:calls` (default: `:time`)\n    * `:warmup` - if the code should be warmed up before profiling (default: `true`)\n    * `:set_on_spawn` - if newly spawned processes should be measured (default: `true`)\n\n  \"\"\"\n  @spec profile((-> result), profile_opts()) :: result when result: any()\n  def profile(fun, opts \\\\ []) when is_function(fun, 0) do\n    Mix.ensure_application!(:tools)\n    {return_value, results} = profile_and_analyse(fun, opts)\n    print_output(results)\n    return_value\n  end\n\n  defp profile_and_analyse(fun, opts) do\n    if Keyword.get(opts, :warmup, true) do\n      IO.puts(\"Warmup...\\n\")\n      fun.()\n    end\n\n    :eprof.start()\n    matching = Keyword.get(opts, :matching, {:_, :_, :_})\n    set_on_spawn = Keyword.get(opts, :set_on_spawn, true)\n    {:ok, return_value} = :eprof.profile([], fun, matching, set_on_spawn: set_on_spawn)\n\n    results =\n      Enum.map(:eprof.dump(), fn {pid, call_results} ->\n        parsed_calls =\n          call_results\n          |> filter_results(opts)\n          |> sort_results(opts)\n          |> add_totals()\n\n        {pid, parsed_calls}\n      end)\n\n    :eprof.stop()\n\n    {return_value, results}\n  end\n\n  defp filter_results(call_results, opts) do\n    calls_opt = Keyword.get(opts, :calls, 0)\n    time_opt = Keyword.get(opts, :time, 0)\n\n    Enum.filter(call_results, fn {_mfa, {count, time}} ->\n      count >= calls_opt and time >= time_opt\n    end)\n  end\n\n  defp sort_results(call_results, opts) do\n    Enum.sort_by(call_results, sort_function(Keyword.get(opts, :sort, :time)))\n  end\n\n  defp sort_function(:time), do: fn {_mfa, {_count, time}} -> time end\n  defp sort_function(:calls), do: fn {_mfa, {count, _time}} -> count end\n\n  defp add_totals(call_results) do\n    {function_count, call_count, total_time} =\n      Enum.reduce(call_results, {0, 0, 0}, fn {_, {count, time}}, acc ->\n        {function_count, call_count, total_time} = acc\n        {function_count + 1, call_count + count, total_time + time}\n      end)\n\n    {function_count, call_results, call_count, total_time}\n  end\n\n  @header [\"#\", \"CALLS\", \"%\", \"TIME\", \"µS/CALL\"]\n\n  defp print_output([]) do\n    print_function_count(0)\n  end\n\n  defp print_output(results) do\n    Enum.each(results, &print_result/1)\n  end\n\n  defp print_result({pid, {function_count, call_results, call_count, total_time}}) do\n    formatted_rows = Enum.map(call_results, &format_row(&1, total_time))\n    formatted_total = format_total(total_time, call_count)\n\n    column_lengths = column_lengths(@header, formatted_rows)\n\n    IO.puts(\"\")\n\n    print_pid_row(pid)\n    print_row(@header, column_lengths)\n    print_row(formatted_total, column_lengths)\n    Enum.each(formatted_rows, &print_row(&1, column_lengths))\n\n    IO.puts(\"\")\n\n    print_function_count(function_count)\n  end\n\n  defp print_pid_row(pid) do\n    IO.puts(\"Profile results of #{inspect(pid)}\")\n  end\n\n  defp format_row({{module, function, arity}, {count, time}}, total_time) do\n    mfa = Exception.format_mfa(module, function, arity)\n    time_percentage = :erlang.float_to_binary(100 * divide(time, total_time), [{:decimals, 2}])\n    time_per_call = :erlang.float_to_binary(divide(time, count), [{:decimals, 2}])\n    count = Integer.to_string(count)\n    time = Integer.to_string(time)\n\n    [mfa, count, time_percentage, time, time_per_call]\n  end\n\n  defp format_total(total_time, total_count) do\n    time_per_call = :erlang.float_to_binary(divide(total_time, total_count), [{:decimals, 2}])\n\n    [\n      \"Total\",\n      Integer.to_string(total_count),\n      \"100.00\",\n      Integer.to_string(total_time),\n      time_per_call\n    ]\n  end\n\n  defp divide(_, 0), do: 0.0\n  defp divide(t, n), do: t / n\n\n  defp column_lengths(header, rows) do\n    max_lengths = Enum.map(header, &String.length/1)\n\n    Enum.reduce(rows, max_lengths, fn row, max_lengths ->\n      Enum.zip_with(row, max_lengths, fn cell, length -> String.length(cell) |> max(length) end)\n    end)\n  end\n\n  @format \"~-*s ~*s ~*s ~*s ~*s~n\"\n\n  defp print_row(row, column_lengths) do\n    to_print =\n      column_lengths\n      |> Stream.zip(Stream.map(row, &String.to_charlist/1))\n      |> Enum.flat_map(&Tuple.to_list/1)\n\n    :io.format(@format, to_print)\n  end\n\n  defp print_function_count(count) do\n    IO.puts(\"Profile done over #{count} matching functions\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/profile.fprof.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Profile.Fprof do\n  use Mix.Task\n\n  @shortdoc \"Profiles the given file or expression with fprof\"\n\n  @moduledoc \"\"\"\n  Profiles the given file or expression using Erlang's `fprof` tool.\n\n  [`:fprof`](`:fprof`) can be useful when you want to discover the bottlenecks of a\n  sequential code.\n\n  Before running the code, it invokes the `app.start` task which compiles\n  and loads your project. After that, the target expression is profiled, together\n  with all processes which are spawned by it. Other processes (for example, those\n  residing in the OTP application supervision tree) are not profiled.\n\n  To profile the code, you can use syntax similar to the `mix run` task:\n\n      $ mix profile.fprof -e Hello.world\n      $ mix profile.fprof my_script.exs arg1 arg2 arg3\n\n  This task is automatically re-enabled, so you can profile multiple times\n  in the same Mix invocation.\n\n  ## Command line options\n\n    * `--callers` - prints detailed information about immediate callers and called functions\n    * `--details` - includes profile data for each profiled process\n    * `--sort key` - sorts the output by given key: `acc` (default) or `own`\n    * `--trace-to-file` - uses a file to trace. Can improve performance and memory\n      usage for larger workloads\n    * `--eval`, `-e` - evaluates the given code\n    * `--require`, `-r` - requires pattern before running the command\n    * `--parallel`, `-p` - makes all requires parallel\n    * `--no-compile`    - does not compile even if files require compilation\n    * `--no-deps-check` - does not check dependencies\n    * `--no-archives-check` - does not check archives\n    * `--no-start` - does not start applications after compilation\n    * `--no-elixir-version-check` - does not check the Elixir version from mix.exs\n    * `--no-warmup` - does not execute code once before profiling\n\n  ## Profile output\n\n  Example output:\n      #                                        CNT    ACC (ms)    OWN (ms)\n      Total                                 200279    1972.188    1964.579\n      :fprof.apply_start_stop/4                  0    1972.188       0.012\n      anonymous fn/0 in :elixir_compiler_2       1    1972.167       0.001\n      Test.run/0                                 1    1972.166       0.007\n      Test.do_something/1                        3    1972.131       0.040\n      Test.bottleneck/0                          1    1599.490       0.007\n      ...\n\n  The default output contains data gathered from all profiled processes.\n  All times are wall clock milliseconds. The columns have the following meaning:\n\n    * CNT - total number of invocations of the given function\n    * ACC - total time spent in the function\n    * OWN - time spent in the function, excluding the time of called functions\n\n  The first row (Total) is the sum of all functions executed in all profiled\n  processes. For the given output, we had a total of 200 279 function calls and spent\n  about 2 seconds running the code.\n\n  More detailed information is returned if you provide the `--callers` and\n  `--details` options.\n\n  When `--callers` option is specified, you'll see expanded function entries:\n\n      Mod.caller1/0                             3     200.000       0.017\n      Mod.caller2/0                             2     100.000       0.017\n        Mod.some_function/0                     5     300.000       0.017  <--\n          Mod.called1/0                         4     250.000       0.010\n          Mod.called2/0                         1      50.000       0.030\n\n  Here, the arrow (`<--`) indicates the __marked__ function - the function\n  described by this paragraph. You also see its immediate callers (above) and\n  called functions (below).\n\n  All the values of caller functions describe the marked function. For example,\n  the first row means that `Mod.caller1/0` invoked `Mod.some_function/0` 3 times.\n  200ms of the total time spent in `Mod.some_function/0` was spent processing\n  calls from this particular caller.\n\n  In contrast, the values for the called functions describe those functions, but\n  in the context of the marked function. For example, the last row means that\n  `Mod.called2/0` was called once by `Mod.some_function/0`, and in that case\n  the total time spent in the function was 50ms.\n\n  For a detailed explanation it's worth reading the analysis in\n  [Erlang/OTP documentation for fprof](https://www.erlang.org/doc/man/fprof.html#analysis).\n\n  ## Caveats\n\n  You should be aware that the code being profiled is running in an anonymous\n  function which is invoked by [`:fprof` module](`:fprof`).\n  Thus, you'll see some additional entries in your profile output,\n  such as `:fprof` calls, an anonymous\n  function with high ACC time, or an `:undefined` function which represents\n  the outer caller (non-profiled code which started the profiler).\n\n  Also, keep in mind that profiling might significantly increase the running time\n  of the profiled processes. This might skew your results if, for example, those\n  processes perform some I/O operations, since running time of those operations\n  will remain unchanged, while CPU bound operations of the profiled processes\n  might take significantly longer. Thus, when profiling some intensive program,\n  try to reduce such dependencies, or be aware of the resulting bias.\n\n  Finally, it's advised to profile your program with the `prod` environment, since\n  this should provide more realistic insights into bottlenecks.\n  \"\"\"\n\n  @typedoc \"\"\"\n  Options for the fprof profiler.\n  \"\"\"\n  @type profile_opts :: [\n          callers: boolean(),\n          details: boolean(),\n          sort: :acc | :own,\n          trace_to_file: boolean()\n        ]\n\n  @switches [\n    parallel: :boolean,\n    require: :keep,\n    trace_to_file: :boolean,\n    eval: :keep,\n    config: :keep,\n    compile: :boolean,\n    deps_check: :boolean,\n    start: :boolean,\n    archives_check: :boolean,\n    details: :boolean,\n    callers: :boolean,\n    sort: :string,\n    elixir_version_check: :boolean,\n    warmup: :boolean,\n    parallel_require: :keep\n  ]\n\n  @aliases [r: :require, p: :parallel, e: :eval, c: :config]\n\n  @impl true\n  def run(args) do\n    {opts, head} = OptionParser.parse_head!(args, aliases: @aliases, strict: @switches)\n    Mix.Task.reenable(\"profile.fprof\")\n\n    Mix.Tasks.Run.run(\n      [\"--no-mix-exs\" | args],\n      opts,\n      head,\n      &profile_code(&1, opts),\n      &profile_code(File.read!(&1), opts)\n    )\n  end\n\n  # Profiling functions\n\n  defp profile_code(code_string, opts) do\n    content =\n      quote do\n        unquote(__MODULE__).profile(\n          fn ->\n            unquote(Code.string_to_quoted!(code_string))\n          end,\n          unquote(Macro.escape(Enum.map(opts, &parse_opt/1)))\n        )\n      end\n\n    # Use compile_quoted since it leaves less noise than eval_quoted\n    Code.compile_quoted(content)\n  end\n\n  defp parse_opt({:sort, \"acc\"}), do: {:sort, :acc}\n  defp parse_opt({:sort, \"own\"}), do: {:sort, :own}\n  defp parse_opt({:sort, other}), do: Mix.raise(\"Invalid sort option: #{other}\")\n  defp parse_opt(other), do: other\n\n  @doc \"\"\"\n  Allows to programmatically run the `fprof` profiler on expression in `fun`.\n\n  Returns the return value of `fun`.\n\n  ## Options\n\n    * `:callers` - prints detailed information about immediate callers and called functions\n    * `:details` - includes profile data for each profiled process\n    * `:sort` - sorts the output by given key: `:acc` (default) or `:own`\n    * `:trace_to_file` - uses a file to trace. Can improve performance and memory\n      usage for larger workloads.\n\n  \"\"\"\n  @spec profile((-> result), profile_opts()) :: result when result: any()\n  def profile(fun, opts \\\\ []) when is_function(fun, 0) do\n    Mix.ensure_application!(:runtime_tools)\n    Mix.ensure_application!(:tools)\n    {return_value, analysis_output} = profile_and_analyse(fun, opts)\n    print_output(analysis_output)\n    return_value\n  end\n\n  defp profile_and_analyse(fun, opts) do\n    if Keyword.get(opts, :warmup, true) do\n      IO.puts(\"Warmup...\")\n      fun.()\n    end\n\n    {return_value, file_to_remove} =\n      if Keyword.get(opts, :trace_to_file, false) do\n        trace_file = Path.join(System.tmp_dir!(), \"fprof_trace_#{System.os_time()}\")\n\n        filename =\n          trace_file\n          |> Path.expand()\n          |> String.to_charlist()\n\n        result = :fprof.apply(fun, [], file: filename)\n        :fprof.profile(file: filename)\n        {result, trace_file}\n      else\n        {:ok, tracer} = :fprof.profile([:start])\n        {:fprof.apply(fun, [], tracer: tracer), nil}\n      end\n\n    {:ok, analyse_dest} = StringIO.open(\"\")\n\n    try do\n      :fprof.analyse(\n        dest: analyse_dest,\n        totals: true,\n        details: Keyword.get(opts, :details, false),\n        callers: Keyword.get(opts, :callers, false),\n        sort: Keyword.get(opts, :sort, :acc)\n      )\n    else\n      :ok ->\n        {_in, analysis_output} = StringIO.contents(analyse_dest)\n        {return_value, String.to_charlist(analysis_output)}\n    after\n      StringIO.close(analyse_dest)\n      if file_to_remove, do: File.rm(file_to_remove)\n    end\n  end\n\n  defp print_output(analysis_output) do\n    {_analysis_options, analysis_output} = next_term(analysis_output)\n    {total_row, analysis_output} = next_term(analysis_output)\n    print_total_row(total_row)\n\n    Stream.unfold(analysis_output, &next_term/1)\n    |> Enum.each(&print_analysis_result/1)\n  end\n\n  defp next_term(charlist) do\n    case :erl_scan.tokens([], charlist, 1) do\n      {:done, result, leftover} ->\n        case result do\n          {:ok, tokens, _} ->\n            {:ok, term} = :erl_parse.parse_term(tokens)\n            {term, leftover}\n\n          {:eof, _} ->\n            nil\n        end\n\n      _ ->\n        nil\n    end\n  end\n\n  defp print_total_row([{:totals, count, acc, own}]) do\n    IO.puts(\"\")\n    print_row([\"s\", \"s\", \"s\", \"s\", \"s\"], [\"\", \"CNT\", \"ACC (ms)\", \"OWN (ms)\", \"\"])\n    print_row([\"s\", \"B\", \".3f\", \".3f\", \"s\"], [\"Total\", count, acc, own, \"\"])\n  end\n\n  # Represents the \"PID\" entry\n  defp print_analysis_result([{pid_atom, count, :undefined, own} | info]) do\n    print_process(pid_atom, count, own)\n\n    if spawned_by = info[:spawned_by] do\n      IO.puts(\"  spawned by #{spawned_by}\")\n    end\n\n    if spawned_as = info[:spawned_as] do\n      IO.puts(\"  as #{function_text(spawned_as)}\")\n    end\n\n    if initial_calls = info[:initial_calls] do\n      IO.puts(\"  initial calls:\")\n      Enum.each(initial_calls, &IO.puts(\"    #{function_text(&1)}\"))\n    end\n\n    IO.puts(\"\")\n  end\n\n  # The function entry, when --callers option is provided\n  defp print_analysis_result({callers, function, subcalls}) do\n    IO.puts(\"\")\n    Enum.each(callers, &print_function/1)\n    print_function(function, \"  \", \"<--\")\n    Enum.each(subcalls, &print_function(&1, \"    \"))\n  end\n\n  # The function entry in the total section, and when --callers option is not\n  # provided\n  defp print_analysis_result({_fun, _count, _acc, _own} = function) do\n    print_function(function, \"\", \"\")\n  end\n\n  defp print_process(pid_atom, count, own) do\n    IO.puts([?\\n, String.duplicate(\"-\", 100)])\n    print_row([\"s\", \"B\", \"s\", \".3f\", \"s\"], [\"#{pid_atom}\", count, \"\", own, \"\"])\n  end\n\n  defp print_function({fun, count, acc, own}, prefix \\\\ \"\", suffix \\\\ \"\") do\n    text = \"#{prefix}#{function_text(fun)}\"\n    print_row([\"s\", \"B\", \".3f\", \".3f\", \"s\"], [text, count, acc, own, suffix])\n  end\n\n  defp function_text({module, function, arity}) do\n    Exception.format_mfa(module, function, arity)\n  end\n\n  defp function_text(other), do: inspect(other)\n\n  @columns [-60, 10, 12, 12, 5]\n  defp print_row(formats, data) do\n    Stream.zip(@columns, formats)\n    |> Stream.map(fn {width, format} -> \"~#{width}#{format}\" end)\n    |> Enum.join()\n    |> :io.format(data)\n\n    IO.puts(\"\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/profile.tprof.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\ndefmodule Mix.Tasks.Profile.Tprof do\n  use Mix.Task\n\n  @shortdoc \"Profiles the given file or expression with tprof\"\n\n  @moduledoc \"\"\"\n  Profiles the given file or expression using Erlang's `tprof` tool.\n\n  [`:tprof`](`:tprof`) is an experimental module introduced in Erlang/OTP 27 which\n  provides a unified API for measuring call count, time, and allocation, and aims to\n  replace [`:eprof`](`:eprof`) and [`:cprof`](`:cprof`).\n  It can be useful when you want to discover the bottlenecks related to any of these\n  measurements.\n\n  Before running the code, it invokes the `app.start` task which compiles\n  and loads your project. After that, the target expression is profiled together\n  with all matching function calls using the Erlang trace BIFs. The tracing of\n  the function calls for that is enabled when the profiling is begun, and\n  disabled when profiling is stopped.\n\n  To profile the code, you can use syntax similar to the `mix run` task:\n\n      $ mix profile.tprof -e Hello.world\n      $ mix profile.tprof -e \"[1, 2, 3] |> Enum.reverse |> Enum.map(&Integer.to_string/1)\"\n      $ mix profile.tprof my_script.exs arg1 arg2 arg3\n\n  By default, tprof uses the `time` type, but you can profile memory too:\n\n      $ mix profile.tprof -e \"Enum.map([1, 2, 3], &Integer.to_string/1)\" --type memory\n\n  Call count is present with both type `time` and `memory`, but if you only need\n  the call count information, you can use the type `calls` which has the lowest footprint:\n\n      $ mix profile.tprof -e \"Enum.map([1, 2, 3], &Integer.to_string/1)\" --type calls\n\n  This task is automatically re-enabled, so you can profile multiple times\n  in the same Mix invocation.\n\n  ## Command line options\n\n    * `--matching` - only profile calls matching the given `Module.function/arity` pattern\n    * `--type` - the type of profiling, `calls`, `time` or `memory` (default: `time`)\n    * `--calls` - filters out any results with a call count lower than this\n    * `--time` - filters out any results that took lower than specified (in µs), the `type` needs to be `time`\n    * `--memory` - filters out any results that used less memory than specified (in words), the `type` needs to be `memory`\n    * `--sort` - sorts the results by `calls`, `per_call` or by the value of `type` (default: the value of `type`)\n    * `--report` - returns the per-process breakdown when `process`, or the total for all processes when `total` (default: `process`).\n      Always `total` when `type` is `calls`.\n    * `--eval`, `-e` - evaluates the given code\n    * `--require`, `-r` - requires pattern before running the command\n    * `--parallel`, `-p` - makes all requires parallel\n    * `--no-warmup` - skips the warmup step before profiling\n    * `--no-compile` - does not compile even if files require compilation\n    * `--no-deps-check` - does not check dependencies\n    * `--no-archives-check` - does not check archives\n    * `--no-halt` - does not halt the system after running the command\n    * `--no-set-on-spawn` - does not profile spawned processes\n    * `--no-start` - does not start applications after compilation\n    * `--no-elixir-version-check` - does not check the Elixir version from mix.exs\n\n  ## Profile output\n\n  Example output (`time` type):\n\n      Profile results of #PID<0.107.0>\n      #                                               CALLS      % TIME µS/CALL\n      Total                                              20 100.00    2    0.10\n      String.Chars.Integer.to_string/1                    5   0.00    0    0.00\n      anonymous fn/0 in :elixir_compiler_1.__FILE__/1     1   0.00    0    0.00\n      Enum.each/2                                         1   0.00    0    0.00\n      Enum.reduce_range/5                                 3   0.00    0    0.00\n      :erlang.integer_to_binary/1                         5  50.00    1    0.20\n      anonymous fn/3 in Enum.each/2                       5  50.00    1    0.20\n\n      Profile done over 6 matching functions\n\n  Example output (`memory` type):\n\n      Profile results of #PID<0.107.0>\n      #                           CALLS      % WORDS PER CALL\n      Total                           6 100.00    19     3.17\n      Enum.each/2                     1  21.05     4     4.00\n      :erlang.integer_to_binary/1     5  78.95    15     3.00\n\n      Profile done over 2 matching functions\n\n  Example output (`calls` type)\n\n      Profile results over all processes\n      #                                               CALLS      %\n      Total                                              20 100.00\n      anonymous fn/0 in :elixir_compiler_1.__FILE__/1     1   5.00\n      Enum.each/2                                         1   5.00\n      Enum.reduce_range/5                                 3  15.00\n      :erlang.integer_to_binary/1                         5  25.00\n      String.Chars.Integer.to_string/1                    5  25.00\n      anonymous fn/3 in Enum.each/2                       5  25.00\n\n      Profile done over 6 matching functions\n\n  The default output contains data gathered from all matching functions. The first\n  row after the header contains the sums of the partial results and the average time\n  or memory usage for all the function calls listed.\n  The following rows contain the function call, followed by the number of times that\n  the function was called, then by the percentage of time/memory that the call uses,\n  then the total time/memory for that function in microseconds/words, and, finally,\n  the average time/memory per call in microseconds/words.\n\n  When `--matching` option is specified, call count tracing will be started only for\n  the functions matching the given pattern:\n\n      Profile results of #PID<0.106.0>\n      #                                CALLS      % TIME µS/CALL\n      Total                                5 100.00    1    0.20\n      String.Chars.Integer.to_string/1     5 100.00    1    0.20\n\n      Profile done over 1 matching functions\n\n  The pattern can be a module name, such as `String` to count all calls to that module,\n  a call without arity, such as `String.split`, to count all calls to that function\n  regardless of arity, or a call with arity, such as `String.split/3`, to count all\n  calls to that exact module, function and arity.\n\n  ## Caveats\n\n  You should be aware that the code being profiled is running in an anonymous\n  function which is invoked by [`:tprof` module](`:tprof`).\n  Thus, you'll see some additional entries in your profile output. It is also\n  important to note that the profiler is stopped as soon as the code has finished running,\n  and this may need special attention, when: running asynchronous code as function calls which were\n  called before the profiler stopped will not be counted; running synchronous code as long\n  running computations and a profiler without a proper MFA trace pattern or filter may\n  lead to a result set which is difficult to comprehend.\n\n  You should expect a slowdown in your code execution using this tool since `:tprof` has\n  some performance impact on the execution, but the impact is considerably lower than\n  `Mix.Tasks.Profile.Fprof`. If you have a large system try to profile a limited\n  scenario or focus on the main modules or processes. The `calls` type can also be used,\n  which is more limited but has a lower footprint.\n  \"\"\"\n\n  @typedoc \"\"\"\n  Options for the tprof profiler.\n  \"\"\"\n  @type profile_opts :: [\n          matching: {module() | :_, atom() | :_, arity() | :_},\n          type: :time | :memory | :calls,\n          calls: non_neg_integer(),\n          time: non_neg_integer(),\n          memory: non_neg_integer(),\n          sort: :calls | :per_call | :time | :memory,\n          report: :process | :total,\n          warmup: boolean(),\n          set_on_spawn: boolean()\n        ]\n\n  @switches [\n    parallel: :boolean,\n    require: :keep,\n    eval: :keep,\n    config: :keep,\n    matching: :string,\n    halt: :boolean,\n    compile: :boolean,\n    deps_check: :boolean,\n    type: :string,\n    calls: :integer,\n    time: :integer,\n    memory: :integer,\n    sort: :string,\n    report: :string,\n    start: :boolean,\n    archives_check: :boolean,\n    warmup: :boolean,\n    elixir_version_check: :boolean,\n    parallel_require: :keep,\n    set_on_spawn: :boolean\n  ]\n\n  @aliases [\n    r: :require,\n    p: :parallel,\n    e: :eval,\n    c: :config\n  ]\n\n  @impl true\n  def run(args) do\n    {opts, head} = parse!(args)\n    Mix.Task.reenable(\"profile.tprof\")\n\n    Mix.Tasks.Run.run(\n      [\"--no-mix-exs\" | args],\n      opts,\n      head,\n      &profile_code(&1, opts),\n      &profile_code(File.read!(&1), opts)\n    )\n  end\n\n  @doc false\n  def parse!(args) do\n    {opts, args} = OptionParser.parse!(args, aliases: @aliases, strict: @switches)\n    {Enum.map(opts, &parse_opt/1), args}\n  end\n\n  defp profile_code(code_string, opts) do\n    content =\n      quote do\n        unquote(__MODULE__).profile(\n          fn ->\n            unquote(Code.string_to_quoted!(code_string))\n          end,\n          unquote(Macro.escape(opts))\n        )\n      end\n\n    # Use compile_quoted since it leaves less noise than eval_quoted\n    Code.compile_quoted(content)\n  end\n\n  defp parse_opt({:matching, matching}) do\n    case Mix.Utils.parse_mfa(matching) do\n      {:ok, [m, f, a]} -> {:matching, {m, f, a}}\n      {:ok, [m, f]} -> {:matching, {m, f, :_}}\n      {:ok, [m]} -> {:matching, {m, :_, :_}}\n      :error -> Mix.raise(\"Invalid matching pattern: #{matching}\")\n    end\n  end\n\n  defp parse_opt({:type, \"time\"}), do: {:type, :time}\n  defp parse_opt({:type, \"calls\"}), do: {:type, :calls}\n  defp parse_opt({:type, \"memory\"}), do: {:type, :memory}\n  defp parse_opt({:type, other}), do: Mix.raise(\"Invalid type option: #{other}\")\n\n  defp parse_opt({:report, \"process\"}), do: {:report, :process}\n  defp parse_opt({:report, \"total\"}), do: {:report, :total}\n  defp parse_opt({:report, other}), do: Mix.raise(\"Invalid report option: #{other}\")\n\n  defp parse_opt({:sort, \"time\"}), do: {:sort, :time}\n  defp parse_opt({:sort, \"calls\"}), do: {:sort, :calls}\n  defp parse_opt({:sort, \"memory\"}), do: {:sort, :memory}\n  defp parse_opt({:sort, \"per_call\"}), do: {:sort, :per_call}\n  defp parse_opt({:sort, other}), do: Mix.raise(\"Invalid sort option: #{other}\")\n  defp parse_opt(other), do: other\n\n  @doc \"\"\"\n  Allows to programmatically run the `tprof` profiler on expression in `fun`.\n\n  Returns the return value of `fun`.\n\n  ## Options\n\n    * `:matching` - only profile calls matching the given pattern in form of\n      `{module, function, arity}`, where each element may be replaced by `:_`\n      to allow any value\n    * `:type` - the type of profiling, possible values are `:time`, `:memory` or `:calls`,\n      (default: `:time`), see [moduledoc](`Mix.Tasks.Profile.Tprof`) for more information\n\n    * `:calls` - filters out any results with a call count lower than this\n    * `:time` - filters out any results that took lower than specified (in µs),\n      `type` needs to be `:time`\n    * `:memory` - filters out any results that used less memory than specified (in words),\n      `type` needs to be `:memory`\n    * `:sort` - sort the results by `:calls`, `:per_call` or by the value of `type`\n      (default: the value of `type`)\n    * `:report` - returns the per-process breakdown when `:process`, or the total for all\n      processes when `:total` (default: `:process`). Always `:total` when `type` is `:calls`.\n    * `:warmup` - if the code should be warmed up before profiling (default: `true`)\n    * `:set_on_spawn` - if newly spawned processes should be measured (default: `true`)\n\n  \"\"\"\n  @spec profile((-> result), profile_opts()) :: result when result: any()\n  def profile(fun, opts \\\\ []) when is_function(fun, 0) do\n    Mix.ensure_application!(:tools)\n    {type, return_value, results} = profile_and_analyse(fun, opts)\n    print_output(type, results)\n    return_value\n  end\n\n  defp profile_and_analyse(fun, opts) do\n    if Keyword.get(opts, :warmup, true) do\n      IO.puts(\"Warmup...\\n\")\n      fun.()\n    end\n\n    matching = Keyword.get(opts, :matching, {:_, :_, :_})\n    set_on_spawn = Keyword.get(opts, :set_on_spawn, true)\n    type = Keyword.get(opts, :type, :time)\n    report = Keyword.get(opts, :report, :process)\n\n    sort_by =\n      case Keyword.get(opts, :sort) do\n        nil ->\n          :measurement\n\n        :calls ->\n          :calls\n\n        :per_call ->\n          :measurement_per_call\n\n        ^type ->\n          :measurement\n\n        other ->\n          Mix.raise(\"Incompatible sort option #{inspect(other)} with type #{inspect(type)}\")\n      end\n\n    tprof_type = to_tprof_type(type)\n\n    {return_value, {^tprof_type, traces}} =\n      :tprof.profile(fun, %{\n        set_on_spawn: set_on_spawn,\n        pattern: matching,\n        type: tprof_type,\n        report: :return\n      })\n\n    inspected = :tprof.inspect({tprof_type, traces}, report, sort_by)\n\n    results =\n      inspected\n      |> Enum.map(fn {pid, {^tprof_type, measurement_total, call_results}} ->\n        parsed_calls =\n          call_results\n          |> filter_results(type, opts)\n          |> add_totals(measurement_total)\n\n        {pid, parsed_calls}\n      end)\n\n    {type, return_value, results}\n  end\n\n  defp to_tprof_type(:calls), do: :call_count\n  defp to_tprof_type(:time), do: :call_time\n  defp to_tprof_type(:memory), do: :call_memory\n\n  defp filter_results(call_results, type, opts) do\n    calls_opt = Keyword.get(opts, :calls, 0)\n\n    measurement_opt =\n      get_filter_value!(type, Keyword.get(opts, :time), Keyword.get(opts, :memory))\n\n    Enum.filter(call_results, fn {_module, _fa, count, measurement, _, _} ->\n      count >= calls_opt and measurement >= measurement_opt\n    end)\n  end\n\n  defp get_filter_value!(type, time, _memory) when is_integer(time) and type != :time do\n    Mix.raise(\"Incompatible use of time option with type #{inspect(type)}\")\n  end\n\n  defp get_filter_value!(type, _time, memory) when is_integer(memory) and type != :memory do\n    Mix.raise(\"Incompatible use of memory option with type #{inspect(type)}\")\n  end\n\n  defp get_filter_value!(:time, time, nil) when is_integer(time), do: time\n  defp get_filter_value!(:memory, nil, memory) when is_integer(memory), do: memory\n\n  defp get_filter_value!(_, nil, nil), do: 0\n\n  defp add_totals(call_results, measurement_total) do\n    {function_count, calls} =\n      Enum.reduce(call_results, {0, 0}, fn {_mod, _fa, count, _, _, _}, acc ->\n        {function_count, calls} = acc\n        {function_count + 1, calls + count}\n      end)\n\n    {function_count, call_results, calls, measurement_total}\n  end\n\n  defp print_output(_type, []) do\n    print_function_count(0)\n  end\n\n  defp print_output(type, results) do\n    Enum.each(results, &print_result(type, &1))\n  end\n\n  defp print_result(type, {pid, {function_count, call_results, calls, total_measurement}}) do\n    header = header(type)\n\n    formatted_rows = Enum.map(call_results, &format_row/1)\n    formatted_total = format_total(total_measurement, calls)\n\n    column_lengths = column_lengths(header, [formatted_total | formatted_rows])\n\n    IO.puts(\"\")\n\n    print_pid_row(pid)\n    print_row(header, column_lengths, type)\n    print_row(formatted_total, column_lengths, type)\n    Enum.each(formatted_rows, &print_row(&1, column_lengths, type))\n\n    IO.puts(\"\")\n\n    print_function_count(function_count)\n  end\n\n  defp header(:calls), do: [\"#\", \"CALLS\", \"%\"]\n  defp header(:time), do: [\"#\", \"CALLS\", \"%\", \"TIME\", \"µS/CALL\"]\n  defp header(:memory), do: [\"#\", \"CALLS\", \"%\", \"WORDS\", \"PER CALL\"]\n\n  defp print_pid_row(:all) do\n    IO.puts(\"Profile results over all processes\")\n  end\n\n  defp print_pid_row(pid) when is_pid(pid) do\n    IO.puts(\"Profile results of #{inspect(pid)}\")\n  end\n\n  defp format_row({module, {function, arity}, count, measurement, per_call, percentage}) do\n    mfa = Exception.format_mfa(module, function, arity)\n    percentage = :erlang.float_to_binary(percentage, [{:decimals, 2}])\n    per_call = :erlang.float_to_binary(per_call, [{:decimals, 2}])\n    count = Integer.to_string(count)\n    measurement = Integer.to_string(measurement)\n\n    [mfa, count, percentage, measurement, per_call]\n  end\n\n  defp format_total(total_measurement, total_count) do\n    per_call = :erlang.float_to_binary(divide(total_measurement, total_count), [{:decimals, 2}])\n\n    [\n      \"Total\",\n      Integer.to_string(total_count),\n      \"100.00\",\n      Integer.to_string(total_measurement),\n      per_call\n    ]\n  end\n\n  defp divide(_, 0), do: 0.0\n  defp divide(t, n), do: t / n\n\n  defp column_lengths(header, rows) do\n    max_lengths = Enum.map(header, &String.length/1)\n\n    Enum.reduce(rows, max_lengths, fn row, max_lengths ->\n      Enum.zip_with(row, max_lengths, fn cell, length -> String.length(cell) |> max(length) end)\n    end)\n  end\n\n  @call_format \"~-*s ~*s ~*s~n\"\n  @measurement_format \"~-*s ~*s ~*s ~*s ~*s~n\"\n\n  defp print_row(row, column_lengths, type) do\n    to_print =\n      column_lengths\n      |> Stream.zip(Stream.map(row, &String.to_charlist/1))\n      |> Enum.flat_map(&Tuple.to_list/1)\n\n    case type do\n      :calls -> :io.format(@call_format, to_print)\n      _ -> :io.format(@measurement_format, to_print)\n    end\n  end\n\n  defp print_function_count(count) do\n    IO.puts(\"Profile done over #{count} matching functions\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/release.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Release do\n  use Mix.Task\n\n  @shortdoc \"Assembles a self-contained release\"\n\n  @moduledoc \"\"\"\n  Assembles a self-contained release for the current project:\n\n      $ MIX_ENV=prod mix release\n      $ MIX_ENV=prod mix release NAME\n\n  Once a release is assembled, it can be packaged and deployed to a\n  target, as long as the target runs on the same operating system (OS)\n  distribution and version as the machine running the `mix release`\n  command. Windows releases also require Microsoft Visual C++ Runtime.\n\n  A release can be configured in your `mix.exs` file under the `:releases`\n  key inside `def project`:\n\n      def project do\n        [\n          releases: [\n            demo: [\n              include_executables_for: [:unix],\n              applications: [runtime_tools: :permanent]\n            ],\n\n            ...\n          ]\n        ]\n      end\n\n  You can specify multiple releases where the key is the release name\n  and the value is a keyword list with the release configuration.\n  Releasing a certain name is done with:\n\n      $ MIX_ENV=prod mix release demo\n\n  If the given name does not exist, an error is raised.\n\n  If `mix release` is invoked, without specifying a release name, and\n  there are multiple releases configured, an error will be raised\n  unless you set `default_release: NAME` at the root of your project\n  configuration.\n\n  If `mix release` is invoked and there are no releases configured, a\n  release is assembled using the application name and default values.\n\n  ## Why releases?\n\n  Releases allow developers to precompile and package all of their code\n  and the runtime into a single unit. The benefits of releases are:\n\n    * Code preloading. The VM has two mechanisms for loading code:\n      interactive and embedded. By default, it runs in the interactive\n      mode which dynamically loads modules when they are used for the\n      first time. The first time your application calls `Enum.map/2`,\n      the VM will find the `Enum` module and load it. There's a downside:\n      when you start a new server in production, it may need to load\n      many other modules, causing the first requests to have an unusual\n      spike in response time. With releases, the system preloads\n      all modules and guarantees your system is ready to handle requests\n      after booting.\n\n    * Configuration and customization. Releases give developers fine\n      grained control over system configuration and the VM flags used\n      to start the system.\n\n    * Self-contained. A release does not require the source code to be\n      included in your production artifacts. All of the code is precompiled\n      and packaged. Releases do not even require Erlang or Elixir in your\n      servers, as it includes the Erlang VM and its runtime by default.\n      Furthermore, both Erlang and Elixir standard libraries are stripped\n      to bring only the parts you are actually using.\n\n    * Multiple releases. You can assemble different releases with\n      different configuration per application or even with different\n      applications altogether.\n\n    * Management scripts. Releases come with scripts to start, restart,\n      connect to the running system remotely, execute RPC calls, run as\n      daemon, run as a Windows service, and more.\n\n  ## Running the release\n\n  Once a release is assembled, you can start it by calling\n  `bin/RELEASE_NAME start` inside the release. In production, you would do:\n\n      $ MIX_ENV=prod mix release\n      $ _build/prod/rel/my_app/bin/my_app start\n\n  `bin/my_app start` will start the system connected to the current standard\n  input/output, where logs are also written to by default. This is the\n  preferred way to run the system. Many tools, such as `systemd`, platforms\n  as a service, such as Heroku, and many containers platforms, such as Docker,\n  are capable of processing the standard input/output and redirecting\n  the log contents elsewhere. Those tools and platforms also take care\n  of restarting the system in case it crashes.\n\n  You can also execute one-off commands, run the release as a daemon on\n  Unix-like system, or install it as a service on Windows. We will take a\n  look at those next. You can also list all available commands by invoking\n  `bin/RELEASE_NAME`.\n\n  ### One-off commands (eval and rpc)\n\n  If you want to invoke specific modules and functions in your release,\n  you can do so in two ways: using `eval` or `rpc`.\n\n      $ bin/RELEASE_NAME eval \"IO.puts(:hello)\"\n      $ bin/RELEASE_NAME rpc \"IO.puts(:hello)\"\n\n  The `eval` command starts its own instance of the VM but without\n  starting any of the applications in the release and without starting\n  distribution. For example, if you need to do some prep work before\n  running the actual system, like migrating your database, `eval` can\n  be a good fit. Just keep in mind any application you may use during\n  eval has to be explicitly started.\n\n  You can start an application by calling `Application.ensure_all_started/1`.\n  From Elixir v1.16, it is guaranteed the applications have been\n  at least loaded. In earlier versions, if you needed to load applications\n  but not start them, you also needed to call `Application.load/1`.\n\n  Another way to run commands is with `rpc`, which will connect to the\n  system currently running and instruct it to execute the given\n  expression. This means you need to guarantee the system was already\n  started and be careful with the instructions you are executing.\n  You can also use `remote` to connect a remote IEx session to the\n  system.\n\n  #### Helper module\n\n  As you operate your system, you may find yourself running some piece of code\n  as a one-off command quite often. You may consider creating a module to group\n  these tasks:\n\n      # lib/my_app/release_tasks.ex\n      defmodule MyApp.ReleaseTasks do\n        def eval_purge_stale_data() do\n          # Eval commands needs to start the app before\n          # Or Application.load(:my_app) if you can't start it\n          Application.ensure_all_started(:my_app)\n\n          # Code that purges stale data\n          ...\n        end\n\n        def rpc_print_connected_users() do\n          # Code that print users connected to the current running system\n          ...\n        end\n      end\n\n  In the example above, we prefixed the function names with the command\n  name used to execute them, but that is entirely optional.\n\n  And to run them:\n\n      $ bin/RELEASE_NAME eval \"MyApp.ReleaseTasks.eval_purge_stale_data()\"\n      $ bin/RELEASE_NAME rpc \"MyApp.ReleaseTasks.rpc_print_connected_users()\"\n\n  ### Daemon mode (Unix-like)\n\n  You can run the release in daemon mode with the command:\n\n      $ bin/RELEASE_NAME daemon\n\n  In daemon mode, the system is started on the background via\n  [`run_erl`](https://www.erlang.org/doc/apps/erts/run_erl_cmd.html).\n  You may also want to enable [`:heart`](`:heart`)\n  in daemon mode so it automatically restarts the system in case\n  of crashes. See the generated `releases/RELEASE_VSN/env.sh` file.\n\n  The daemon will write all of its standard output to the `tmp/log/`\n  directory in the release root. You can watch the log file by doing\n  `tail -f tmp/log/erlang.log.1` or similar. Once files get too large,\n  the index suffix will be incremented. A developer can also attach\n  to the standard input of the daemon by invoking `to_erl tmp/pipe/`\n  from the release root. However, note that attaching to the system\n  should be done with extreme care, since the usual commands for\n  exiting an Elixir system, such as hitting Ctrl+C twice or Ctrl+\\\\,\n  will actually shut down the daemon. Therefore, using\n  `bin/RELEASE_NAME remote` should be preferred, even in daemon mode.\n\n  You can customize the tmp directory used both for logging and for\n  piping in daemon mode by setting the `RELEASE_TMP` environment\n  variable. See the \"Customization\" section.\n\n  ### Services mode (Windows)\n\n  While daemons are not available on Windows, it is possible to install a\n  released system as a service on Windows with the help of\n  [`erlsrv`](https://www.erlang.org/doc/apps/erts/erlsrv_cmd.html).\n  This can be done by running:\n\n      $ bin/RELEASE_NAME install\n\n  Once installed, the service must be explicitly managed via the `erlsrv`\n  executable, which is included in the `erts-VSN/bin` directory.\n  The service is not started automatically after installing.\n\n  For example, if you have a release named `demo`, you can install\n  the service and then start it from the release root as follows:\n\n      $ bin/demo install\n      $ erts-VSN/bin/erlsrv.exe start demo_demo\n\n  The name of the service is `demo_demo` because the name is built\n  by concatenating the node name with the release name. Since Elixir\n  automatically uses the same name for both, the service will be\n  referenced as `demo_demo`.\n\n  The `install` command must be executed as an administrator.\n\n  ### `bin/RELEASE_NAME` commands\n\n  The following commands are supported by `bin/RELEASE_NAME`:\n\n  ```text\n  start        Starts the system\n  start_iex    Starts the system with IEx attached\n  daemon       Starts the system as a daemon (Unix-like only)\n  daemon_iex   Starts the system as a daemon with IEx attached (Unix-like only)\n  install      Installs this system as a Windows service (Windows only)\n  eval \"EXPR\"  Executes the given expression on a new, non-booted system\n  rpc \"EXPR\"   Executes the given expression remotely on the running system\n  remote       Connects to the running system via a remote shell\n  restart      Restarts the running system via a remote command\n  stop         Stops the running system via a remote command\n  pid          Prints the operating system PID of the running system via a remote command\n  version      Prints the release name and version to be booted\n  ```\n\n  ## Deployments\n\n  ### Requirements\n\n  A release is built on a **host**, a machine which contains Erlang, Elixir,\n  and any other dependencies needed to compile your application. A release is\n  then deployed to a **target**, potentially the same machine as the host,\n  but usually separate, and often there are many targets (either multiple\n  instances, or the release is deployed to heterogeneous environments).\n\n  To deploy straight from a host to a separate target, the following must be\n  the same between the host and the target:\n\n    * Target architecture (for example, x86_64 or ARM)\n    * Target vendor + operating system (for example, Windows, Linux, or Darwin/macOS)\n    * Target ABI (for example, musl or gnu)\n\n  This is often represented in the form of target triples, for example,\n  `x86_64-unknown-linux-gnu`, `x86_64-unknown-linux-musl`, `x86_64-apple-darwin`.\n  If you are building on a MacBook (`x86_64-apple-darwin`) and trying to deploy\n  to a typical Ubuntu machine (`x86_64-unknown-linux-gnu`), the release will not\n  work. Instead you should build the release on a `x86_64-unknown-linux-gnu` host.\n\n  Typically, different versions of Erlang VM and Elixir are available for\n  different targets via package managers, precompiled artifacts, and similar.\n  However, to deploy from a host to a separate target, you must also guarantee\n  that any dependency with NIFs (Natively-Implemented Functions) are compiled\n  for the same triplet. As we will see, this can be done in different ways,\n  such as releasing on the target itself, or by using virtual machines or\n  containers, usually as part of your release pipeline.\n\n  In addition to matching the target triple, it is also important that the\n  target has all of the system packages that your application will need at\n  runtime. A common one is the need for OpenSSL when building an application\n  that uses `:crypto` or `:ssl`, which is dynamically linked to the Erlang VM.\n  Project dependencies containing NIFs (natively-implemented functions) may\n  also dynamically link to system libraries, so check those accordingly.\n\n  Of course, some operating systems and package managers can differ between\n  versions, so if your goal is to have full compatibility between host and\n  target, it is best to ensure the operating system and system package manager\n  have the same versions on host and target. This may even be a requirement in\n  some systems, especially so with package managers that try to create fully\n  reproducible environments (Nix, Guix).\n\n  ### Using matching host and target\n\n  There are a couple of ways to guarantee that a release is built on a host with\n  the same properties as the target. A simple option is to fetch the source,\n  compile the code and assemble the release on the target itself. It would\n  be something like this:\n\n      $ git clone remote://path/to/my_app.git my_app_source\n      $ cd my_app_source\n      $ mix deps.get --only prod\n      $ MIX_ENV=prod mix release\n      $ _build/prod/rel/my_app/bin/my_app start\n\n  If you prefer, you can also compile the release to a separate directory,\n  so you can erase all source after the release is assembled:\n\n      $ git clone remote://path/to/my_app.git my_app_source\n      $ cd my_app_source\n      $ mix deps.get --only prod\n      $ MIX_ENV=prod mix release --path ../my_app_release\n      $ cd ../my_app_release\n      $ rm -rf ../my_app_source\n      $ bin/my_app start\n\n  However, this option can be expensive if you have multiple production\n  nodes or if the release assembling process is a long one, as each node\n  needs to individually assemble the release.\n\n  You can automate this process in a couple different ways. One option\n  is to make it part of your Continuous Integration (CI) / Continuous\n  Deployment (CD) pipeline. When you have a CI/CD pipeline, it is common\n  that the machines in your CI/CD pipeline run on the exact same target\n  triple as your production servers (if they don't, they should).\n  In this case, you can assemble the release at the end of your CI/CD\n  pipeline by calling `MIX_ENV=prod mix release` and push the artifact\n  to S3 or any other network storage. To perform the deployment, your\n  production machines can fetch the deployment from the network storage\n  and run `bin/my_app start`.\n\n  ### Using images\n\n  Another mechanism to automate deployments is to use images, such as\n  Amazon Machine Images, or container platforms, such as Docker.\n  For instance, you can use Docker to run locally a system with the\n  exact same target triple as your production servers. Inside the\n  container, you can invoke `MIX_ENV=prod mix release` and build\n  a complete image and/or container with the operating system, all\n  dependencies as well as the releases.\n\n  However, when building such images on your machine, those technologies\n  use emulation which may not interplay well with Erlang VM's JIT\n  (just-in time) compiler. To address this, you can set this environment\n  variable on your build stage:\n\n      ENV ERL_AFLAGS \"+JMsingle true\"\n\n  ## Shutting down\n\n  Once a system is deployed, shutting down the system can be done by\n  sending SIGINT/SIGTERM to the system, which is what most containers,\n  platforms and tools do, or by explicitly invoking `bin/RELEASE_NAME stop`.\n  Once the system receives the shutdown request, each application and\n  their respective supervision trees will stop, one by one, in the\n  opposite order that they were started.\n\n  ## Customization\n\n  There are a couple ways in which developers can customize the generated\n  artifacts inside a release.\n\n  ### Options\n\n  The following options can be set inside your `mix.exs` on each release definition:\n\n    * `:applications` - a keyword list with application names as keys and their\n      mode as value. By default `:applications` includes the current application and\n      all applications the current application depends on, recursively. You can include\n      new applications or change the mode of existing ones by listing them here.\n\n      The order of the applications given will be preserved as much as possible, with\n      only `:kernel`, `:stdlib`, `:sasl`, and `:elixir` listed before the given application\n      list. The supported values are:\n\n        * `:permanent` (default) - the application is started and the node shuts down\n          if the application terminates, regardless of reason\n        * `:transient` - the application is started and the node shuts down\n          if the application terminates abnormally\n        * `:temporary` - the application is started and the node does not\n          shut down if the application terminates\n        * `:load` - the application is only loaded\n        * `:none` - the application is part of the release but it is neither\n          loaded nor started\n\n      If you change the mode of an application, the mode will apply to all its child\n      applications. However, if an application has two parents, the mode of the parent\n      with highest priority wins (where `:permanent` has the highest priority, according\n      to the list above).\n\n    * `:strip_beams` - controls if BEAM files should have their debug information,\n      documentation chunks, and other non-essential metadata removed. Defaults to\n      `true`. May be set to `false` to disable stripping. Also accepts\n      `[keep: [\"Docs\", \"Dbgi\"]]` to keep certain chunks that are usually stripped.\n      You can also set the `:compress` option to true to enable individual\n      compression of BEAM files, although it is typically preferred to compress\n      the whole release instead.\n\n    * `:cookie` - a string representing the Erlang Distribution cookie. If this\n      option is not set, a random cookie is written to the `releases/COOKIE` file\n      when the first release is assembled. At runtime, we will first attempt\n      to fetch the cookie from the `RELEASE_COOKIE` environment variable and\n      then we'll read the `releases/COOKIE` file.\n\n      If you are setting this option manually, we recommend the cookie option\n      to be a long and randomly generated string, such as:\n      `Base.encode32(:crypto.strong_rand_bytes(40))`. We also recommend restricting\n      the characters in the cookie to only alphanumeric characters and underscore.\n\n    * `:validate_compile_env` - by default a release will match all runtime\n      configuration against any configuration that was marked at compile time\n      in your application of its dependencies via the `Application.compile_env/3`\n      function. If there is a mismatch between those, it means your system is\n      misconfigured and unable to boot. You can disable this check by setting\n      this option to false.\n\n    * `:path` - the path the release should be installed to.\n      Defaults to `\"_build/MIX_ENV/rel/RELEASE_NAME\"`.\n\n    * `:version` - the release version as a string or `{:from_app, app_name}`.\n      Defaults to the current application version. The `{:from_app, app_name}` format\n      can be used to easily reference the application version from another application.\n      This is particularly useful in umbrella applications.\n\n    * `:quiet` - a boolean that controls if releases should write steps to\n      the standard output. Defaults to `false`.\n\n    * `:include_erts` - a boolean, string, or anonymous function of arity zero.\n      If a boolean, it indicates whether the Erlang Runtime System (ERTS), which\n      includes the Erlang VM, should be included in the release. The default is\n      `true`, which is also the recommended value. If a string, it represents\n      the path to an existing ERTS installation. If an anonymous function of\n      arity zero, it's a function that returns any of the above (boolean or string).\n\n      You may also set this option to `false` if you desire to use the ERTS version installed\n      on the target. Note, however, that the ERTS version on the target must have **the\n      exact version** as the ERTS version used when the release is assembled. Setting it to\n      `false` also disables hot code upgrades. Therefore, `:include_erts` should be\n      set to `false` with caution and only if you are assembling the release on the\n      same server that runs it.\n\n    * `:include_executables_for` - a list of atoms detailing for which Operating\n      Systems executable files should be generated for. By default, it is set to\n      `[:unix, :windows]`. You can customize those as follows:\n\n          releases: [\n            demo: [\n              include_executables_for: [:unix] # Or [:windows] or []\n            ]\n          ]\n\n    * `:rel_templates_path` - the path to find template files that are copied to\n      the release, such as `vm.args.eex`, `remote.vm.args.eex`, `env.sh.eex`\n      (or `env.bat.eex`), and `overlays`. Defaults to `\"rel\"` in the project root.\n\n    * `:overlays` - a list of directories with extra files to be copied\n      as is to the release. The \"overlays\" directory at `:rel_templates_path`\n      is always included in this list by default (typically at `\"rel/overlays\"`).\n      See the \"Overlays\" section for more information.\n\n    * `:steps` - a list of steps to execute when assembling the release. See\n      the \"Steps\" section for more information.\n\n    * `:skip_mode_validation_for` - a list of application names\n      (atoms) specifying applications to skip strict validation of\n      \"unsafe\" modes. An \"unsafe\" case is when a parent application\n      mode is `:permanent` but one of the applications it depends on\n      is set to `:load`. Use this with care, as a release with\n      invalid modes may no longer boot without additional tweaks.\n      Defaults to `[]`.\n\n  Note each release definition can be given as an anonymous function. This\n  is useful if some release attributes are expensive to compute:\n\n      releases: [\n        demo: fn ->\n          [version: @version <> \"+\" <> git_ref()]\n        end\n      ]\n\n  Besides the options above, it is possible to customize the generated\n  release with custom files, by tweaking the release steps or by running\n  custom options and commands on boot. We will detail both approaches next.\n\n  ### Overlays\n\n  Often it is necessary to copy extra files to the release root after\n  the release is assembled. This can be easily done by placing such\n  files in the `rel/overlays` directory. Any file in there is copied\n  as is to the release root. For example, if you have placed a\n  `rel/overlays/Dockerfile` file, the \"Dockerfile\" will be copied as\n  is to the release root.\n\n  If you want to specify extra overlay directories, you can do so\n  with the `:overlays` option. If you need to copy files dynamically,\n  see the \"Steps\" section.\n\n  ### Steps\n\n  It is possible to add one or more steps before and after the release is\n  assembled. This can be done with the `:steps` option:\n\n      releases: [\n        demo: [\n          steps: [&set_configs/1, :assemble, &copy_extra_files/1]\n        ]\n      ]\n\n  The `:steps` option must be a list and it must always include the\n  atom `:assemble`, which does most of the release assembling. You\n  can pass anonymous functions before and after the `:assemble` to\n  customize your release assembling pipeline. Those anonymous functions\n  will receive a `Mix.Release` struct and must return the same or\n  an updated `Mix.Release` struct. It is also possible to build a tarball\n  of the release by passing the `:tar` step anywhere after `:assemble`.\n  If the release `:path` is not configured, the tarball is created in\n  `_build/MIX_ENV/RELEASE_NAME-RELEASE_VSN.tar.gz` Otherwise it is\n  created inside the configured `:path`.\n\n  See `Mix.Release` for more documentation on the struct and which\n  fields can be modified. Note that the `:steps` field itself can be\n  modified and it is updated every time a step is called. Therefore,\n  if you need to execute a command before and after assembling the\n  release, you only need to declare the first steps in your pipeline\n  and then inject the last step into the release struct. The steps\n  field can also be used to verify if the step was set before or\n  after assembling the release.\n\n  ### vm.args and env.sh (env.bat)\n\n  Developers may want to customize the VM flags and environment variables\n  given when the release starts. The simplest way to customize those files\n  is by running `mix release.init`. The Mix task will copy custom\n  `rel/vm.args.eex`, `rel/remote.vm.args.eex`,  `rel/env.sh.eex`, and\n  `rel/env.bat.eex` files to your project root. You can modify those files\n  and they will be evaluated every time you perform a new release. Those\n  files are regular EEx templates and they have a single assign, called\n  `@release`, with the `Mix.Release` struct.\n\n  The `vm.args` and `remote.vm.args` files may contain any of the VM flags\n  accepted by the [`erl` command](https://www.erlang.org/doc/man/erl.html).\n\n  The `env.sh` and `env.bat` is used to set environment variables.\n  In there, you can set vars such as `RELEASE_NODE`, `RELEASE_COOKIE`,\n  and `RELEASE_TMP` to customize your node name, cookie and tmp\n  directory respectively. Whenever `env.sh` or `env.bat` is invoked,\n  the variables `RELEASE_ROOT`, `RELEASE_NAME`, `RELEASE_VSN`, and\n  `RELEASE_COMMAND` have already been set, so you can rely on them.\n  See the section on environment variables for more information.\n\n  Furthermore, while the `vm.args` files are static, you can use\n  `env.sh` and `env.bat` to dynamically set VM options. For example,\n  if you want to make sure the Erlang Distribution listens only on\n  a given port known at runtime, you can set the following:\n\n  ```bash\n  case $RELEASE_COMMAND in\n    start*|daemon*)\n      ELIXIR_ERL_OPTIONS=\"-kernel inet_dist_listen_min $BEAM_PORT inet_dist_listen_max $BEAM_PORT\"\n      export ELIXIR_ERL_OPTIONS\n      ;;\n    *)\n      ;;\n  esac\n  ```\n\n  Note we only set the port on start/daemon commands. If you also limit\n  the port on other commands, such as `rpc`, then you will be unable\n  to establish a remote connection as the port will already be in use\n  by the node.\n\n  On Windows, your `env.bat` would look like this:\n\n  ```bash\n  IF NOT %RELEASE_COMMAND:start=%==%RELEASE_COMMAND% (\n    set ELIXIR_ERL_OPTIONS=\"-kernel inet_dist_listen_min %BEAM_PORT% inet_dist_listen_max %BEAM_PORT%\"\n  )\n  ```\n\n  Inside `env.sh` and `env.bat` files you can access command-line arguments given to release commands.\n  For example, given this `env.sh.eex`:\n\n  ```bash\n  echo $@\n  ```\n\n  or this `env.bat.eex`:\n\n  ```bash\n  echo %*\n  ```\n\n  starting the release with `bin/myapp start --foo bar baz` will print `start --foo bar baz`.\n\n  ### `epmd`-less deployment\n\n  When a distributed Erlang/Elixir node starts, it runs a separate daemon called EPMD\n  (Erlang Port Mapper Daemon) and registers the node name within EPMD. It is possible\n  to skip this additional Operating System process by setting the following flags in\n  your vm.args files:\n\n      # In vm.args.eex\n      -start_epmd false -erl_epmd_port 6789\n\n      # In remote.vm.args.eex\n      -start_epmd false -erl_epmd_port 6789 -dist_listen false\n\n  You can pick any port of your choice.\n\n  ## Application configuration\n\n  Mix provides two mechanisms for configuring the application environment\n  of your application and your dependencies: build-time and runtime. On this\n  section, we will learn how those mechanisms apply to releases. An introduction\n  to this topic can be found in the \"Configuration\" section of the `Mix` module.\n\n  ### Build-time configuration\n\n  Whenever you invoke a `mix` command, Mix loads the configuration in\n  `config/config.exs`, if said file exists. We say that this configuration\n  is a build-time configuration as it is evaluated whenever you compile your\n  code or whenever you assemble the release.\n\n  In other words, if your configuration does something like:\n\n      import Config\n      config :my_app, :secret_key, System.fetch_env!(\"MY_APP_SECRET_KEY\")\n\n  The `:secret_key` key under `:my_app` will be computed on the\n  host machine, whenever the release is built. Therefore if the machine\n  assembling the release not have access to all environment variables used\n  to run your code, loading the configuration will fail as the environment\n  variable is missing. Luckily, Mix also provides runtime configuration,\n  which should be preferred and we will see next.\n\n  ### Runtime configuration\n\n  To enable runtime configuration in your release, create a file named\n  `config/runtime.exs`:\n\n      import Config\n      config :my_app, :secret_key, System.fetch_env!(\"MY_APP_SECRET_KEY\")\n\n  This file will be executed whenever your Mix project or your release\n  starts.\n\n  Your `config/runtime.exs` file needs to follow three important rules:\n\n    * It MUST `import Config` at the top instead of the deprecated `use Mix.Config`\n    * It MUST NOT import any other configuration file via `import_config`\n    * It MUST NOT access `Mix` in any way, as `Mix` is a build tool and\n      it is not available inside releases\n\n  If a `config/runtime.exs` exists, it will be copied to your release\n  and executed early in the boot process, when only Elixir and Erlang's\n  main applications have been started.\n\n  You can change the path to the runtime configuration file by setting\n  `:runtime_config_path` inside each release configuration. This path is\n  resolved at build time as the given configuration file is always copied\n  to inside the release:\n\n      releases: [\n        demo: [\n          runtime_config_path: ...\n        ]\n      ]\n\n  By setting `:runtime_config_path` to `false` it can be used to prevent\n  a runtime configuration file to be included in the release.\n\n  ### Config providers\n\n  Releases also supports custom mechanisms, called config providers, to load\n  any sort of runtime configuration to the system while it boots. For instance,\n  if you need to access a vault or load configuration from a JSON file, it can\n  be achieved with config providers. The runtime configuration outlined in the\n  previous section is handled by the `Config.Reader` provider. See the\n  `Config.Provider` module for more information and more examples.\n\n  The following options can be set inside your releases key in your `mix.exs`\n  to control how config providers work:\n\n    * `:reboot_system_after_config` - reboot the system after configuration\n      so you can configure system applications, such as `:kernel` and `:stdlib`,\n      in your `config/runtime.exs`. Generally speaking, it is best to configure\n      `:kernel` and `:stdlib` using the `vm.args` file but this option is available\n      for those who need more complex configuration. When set to `true`, the\n      release will first boot in interactive mode to compute a config file and\n      write it to the \"tmp\" directory. Then it reboots in the configured `RELEASE_MODE`.\n      You can configure the \"tmp\" directory by setting the `RELEASE_TMP` environment\n      variable, either explicitly or inside your `releases/RELEASE_VSN/env.sh`\n      (or `env.bat` on Windows). Defaults to `true` if using the deprecated\n      `config/releases.exs`, `false` otherwise. Be careful of which libraries you\n      load when setting this option to true, if a library is loaded early during\n      configuration and it includes native code, it may not actually be able to\n      restart cleanly.\n\n    * `:prune_runtime_sys_config_after_boot` - if `:reboot_system_after_config`\n      is set, every time your system boots, the release will write a config file\n      to your tmp directory. These configuration files are generally small.\n      But if you are concerned with disk space or if you have other restrictions,\n      you can ask the system to remove said config files after boot. The downside\n      is that you will no longer be able to restart the system internally (neither\n      via `System.restart/0` nor `bin/RELEASE_NAME restart`). If you need a restart,\n      you will have to terminate the Operating System process and start a new\n      one. Defaults to `false`.\n\n    * `:start_distribution_during_config` - if `:reboot_system_after_config` is\n      set, releases only start the Erlang VM distribution features after the config\n      files are evaluated. You can set it to `true` if you need distribution during\n      configuration. Defaults to `false`.\n\n    * `:config_providers` - a list of tuples with custom config providers.\n      See `Config.Provider` for more information. Defaults to `[]`.\n\n  ### Customization and configuration summary\n\n  Generally speaking, the following files are available for customizing\n  and configuring the running system:\n\n    * `config/config.exs` (and `config/prod.exs`) - provides build-time\n      application configuration, which are executed when the release is\n      assembled\n\n    * `config/runtime.exs` - provides runtime application configuration.\n      It is executed every time your Mix project or your release boots\n      and is further extensible via config providers. If you want to\n      detect you are inside a release, you can check for release specific\n      environment variables, such as `RELEASE_NODE` or `RELEASE_MODE`\n\n    * `rel/vm.args.eex` and `rel/remote.vm.args.eex` - template files that\n      are copied into every release and provides static configuration of the\n      Erlang Virtual Machine and other runtime flags. `vm.args` runs on\n      `start`, `daemon`, and `eval` commands. `remote.vm.args` configures\n      the VM for `remote` and `rpc` commands\n\n    * `rel/env.sh.eex` and `rel/env.bat.eex` - template files that are copied\n      into every release and are executed on every command to set up environment\n      variables, including specific ones to the VM, and the general environment\n\n  ## Directory structure\n\n  A release is organized as follows:\n\n  ```text\n  bin/\n    RELEASE_NAME\n  erts-ERTS_VSN/\n  lib/\n    APP_NAME-APP_VSN/\n      ebin/\n      include/\n      priv/\n  releases/\n    RELEASE_VSN/\n      consolidated/\n      elixir\n      elixir.bat\n      env.bat\n      env.sh\n      iex\n      iex.bat\n      remote.vm.args\n      runtime.exs\n      start.boot\n      start.script\n      start_clean.boot\n      start_clean.script\n      sys.config\n      vm.args\n    COOKIE\n    start_erl.data\n  tmp/\n  ```\n\n  We document this structure for completeness. In practice, developers\n  should not modify any of those files after the release is assembled.\n  Instead use env scripts, custom config provider, overlays, and all\n  other mechanisms described here to configure how your release works.\n\n  ## Environment variables\n\n  The system sets different environment variables. The following variables\n  are set early on and can only be read by `env.sh` and `env.bat`:\n\n    * `RELEASE_ROOT` - points to the root of the release. If the system\n      includes ERTS, then it is the same as `:code.root_dir/0`. This\n      variable is always computed and it cannot be set to a custom value\n\n    * `RELEASE_COMMAND` - the command given to the release, such as `\"start\"`,\n      `\"remote\"`, `\"eval\"`, and so on. This is typically accessed inside `env.sh`\n      and `env.bat` to set different environment variables under different\n      conditions. Note, however, that `RELEASE_COMMAND` has not been\n      validated by the time `env.sh` and `env.bat` are called, so it may\n      be empty or contain invalid values. This variable is always computed\n      and it cannot be set to a custom value\n\n    * `RELEASE_NAME` - the name of the release. It can be set to a custom\n      value when invoking the release\n\n    * `RELEASE_VSN` - the version of the release, otherwise the latest\n      version is used. It can be set to a custom value when invoking the\n      release. The custom value must be an existing release version in\n      the `releases/` directory\n\n    * `RELEASE_PROG` - the command line executable used to start the release\n\n  The following variables can be set before you invoke the release or\n  inside `env.sh` and `env.bat`:\n\n    * `RELEASE_COOKIE` - the release cookie. By default uses the value\n      in `releases/COOKIE`. It can be set to a custom value\n\n    * `RELEASE_NODE` - the release node name, in the format `name` or\n      optionally `name@host` if running in distributed mode. It can be\n      set to a custom value. The name part must be made only of letters,\n      digits, underscores, and hyphens\n\n    * `RELEASE_SYS_CONFIG` - the location of the sys.config file. It can\n      be set to a custom path and it must not include the `.config` extension\n\n    * `RELEASE_VM_ARGS` - the location of the vm.args file. It can be set\n      to a custom path\n\n    * `RELEASE_REMOTE_VM_ARGS` - the location of the remote.vm.args file.\n      It can be set to a custom path\n\n    * `RELEASE_TMP` - the directory in the release to write temporary\n      files to. It can be set to a custom directory. It defaults to\n      `$RELEASE_ROOT/tmp`\n\n    * `RELEASE_MODE` - if the release should load code on demand (interactive)\n      or preload it (embedded). Defaults to \"embedded\", which increases boot\n      time but it means the runtime will respond faster as it doesn't have to\n      load code. Choose interactive if you need to decrease boot time and reduce\n      memory usage on boot. It applies only to start/daemon/install commands\n\n    * `RELEASE_DISTRIBUTION` - how do we want to run the distribution.\n      May be `name` (long names), `sname` (short names) or `none`\n      (distribution is not started automatically). Defaults to `sname`.\n      When connecting nodes across hosts, you typically want to set\n      this to `name` (required to use IPs as host names)\n\n    * `RELEASE_BOOT_SCRIPT` - the name of the boot script to use when starting\n      the release. This script is used when running commands such as `start` and\n      `daemon`. The boot script is expected to be located at the\n      path `releases/RELEASE_VSN/RELEASE_BOOT_SCRIPT.boot`. Defaults to `start`\n\n    * `RELEASE_BOOT_SCRIPT_CLEAN` - the name of the boot script used when\n      starting the release clean, without your application or its dependencies.\n      This script is used by commands such as `eval`, `rpc`, and `remote`.\n      The boot script is expected to be located at the path\n      `releases/RELEASE_VSN/RELEASE_BOOT_SCRIPT_CLEAN.boot`. Defaults\n      to `start_clean`\n\n  ## Umbrellas\n\n  Releases are well integrated with umbrella projects, allowing you to\n  release one or more subsets of your umbrella children. The only difference\n  between performing a release in the umbrella project compared to a\n  regular application is that umbrellas require you to explicitly list\n  your release and the starting point for each release. For example,\n  imagine this umbrella applications:\n\n  ```text\n  my_app_umbrella/\n    apps/\n      my_app_core/\n      my_app_event_processing/\n      my_app_web/\n  ```\n\n  where both `my_app_event_processing` and `my_app_web` depend on\n  `my_app_core` but they do not depend on each other.\n\n  Inside your umbrella, you can define multiple releases:\n\n      releases: [\n        web_and_event_processing: [\n          applications: [\n            my_app_event_processing: :permanent,\n            my_app_web: :permanent\n          ]\n        ],\n\n        web_only: [\n          applications: [my_app_web: :permanent]\n        ],\n\n        event_processing_only: [\n          applications: [my_app_event_processing: :permanent]\n        ]\n      ]\n\n  Note you don't need to define all applications in `:applications`,\n  only the entry points. Also remember that the recommended mode\n  for all applications in the system is `:permanent`.\n\n  Finally, keep in mind it is not required for you to assemble the\n  release from the umbrella root. You can also assemble the release\n  from each child application individually. Doing it from the root,\n  however, allows you to include two applications that do not depend\n  on each other as part of the same release.\n\n  ## Hot Code Upgrades\n\n  Erlang and Elixir are sometimes known for the capability of upgrading\n  a node that is running in production without shutting down that node.\n  However, this feature is not supported out of the box by Elixir releases.\n\n  The reason we don't provide hot code upgrades is because they are very\n  complicated to perform in practice, as they require careful coding of\n  your processes and applications as well as extensive testing. Given most\n  teams can use other techniques that are language agnostic to upgrade\n  their systems, such as Blue/Green deployments, Canary deployments,\n  Rolling deployments, and others, hot upgrades are rarely a viable\n  option. Let's understand why.\n\n  In a hot code upgrade, you want to update a node from version A to\n  version B. To do so, the first step is to write recipes for every application\n  that changed between those two releases, telling exactly how the application\n  changed between versions, those recipes are called `.appup` files.\n  While some of the steps in building `.appup` files can be automated,\n  not all of them can. Furthermore, each process in the application needs\n  to be explicitly coded with hot code upgrades in mind. Let's see an example.\n  Imagine your application has a counter process as a GenServer:\n\n      defmodule Counter do\n        use GenServer\n\n        def start_link(_) do\n          GenServer.start_link(__MODULE__, :ok, name: __MODULE__)\n        end\n\n        def bump do\n          GenServer.call(__MODULE__, :bump)\n        end\n\n        ## Callbacks\n\n        def init(:ok) do\n          {:ok, 0}\n        end\n\n        def handle_call(:bump, counter) do\n          {:reply, :ok, counter + 1}\n        end\n      end\n\n  You add this process as part of your supervision tree and ship version\n  0.1.0 of your system. Now let's imagine that on version 0.2.0 you added\n  two changes: instead of `bump/0`, that always increments the counter by\n  one, you introduce `bump/1` that passes the exact value to bump the\n  counter. You also change the state, because you want to store the maximum\n  bump value:\n\n      defmodule Counter do\n        use GenServer\n\n        def start_link(_) do\n          GenServer.start_link(__MODULE__, :ok, name: __MODULE__)\n        end\n\n        def bump(by) do\n          GenServer.call(__MODULE__, {:bump, by})\n        end\n\n        ## Callbacks\n\n        def init(:ok) do\n          {:ok, {0, 0}}\n        end\n\n        def handle_call({:bump, by}, {counter, max}) do\n          {:reply, :ok, {counter + by, max(max, by)}}\n        end\n      end\n\n  If you were to perform a hot code upgrade in such an application, it would\n  crash, because in the initial version the state was just a counter\n  but in the new version the state is a tuple. Furthermore, you changed\n  the format of the `call` message from `:bump` to `{:bump, by}` and\n  the process may have both old and new messages temporarily mixed, so\n  we need to handle both. The final version would be:\n\n      defmodule Counter do\n        use GenServer\n\n        def start_link(_) do\n          GenServer.start_link(__MODULE__, :ok, name: __MODULE__)\n        end\n\n        def bump(by) do\n          GenServer.call(__MODULE__, {:bump, by})\n        end\n\n        ## Callbacks\n\n        def init(:ok) do\n          {:ok, {0, 0}}\n        end\n\n        def handle_call(:bump, {counter, max}) do\n          {:reply, :ok, {counter + 1, max(max, 1)}}\n        end\n\n        def handle_call({:bump, by}, {counter, max}) do\n          {:reply, :ok, {counter + by, max(max, by)}}\n        end\n\n        def code_change(_, counter, _) do\n          {:ok, {counter, 0}}\n        end\n      end\n\n  Now you can proceed to list this process in the `.appup` file and\n  hot code upgrade it. This is one of the many steps necessary\n  to perform hot code upgrades and it must be taken into account by\n  every process and application being upgraded in the system.\n  The [`.appup` cookbook](https://www.erlang.org/doc/design_principles/appup_cookbook.html)\n  provides a good reference and more examples.\n\n  Once `.appup`s are created, the next step is to create a `.relup`\n  file with all instructions necessary to update the release itself.\n  Erlang documentation does provide a chapter on\n  [Creating and upgrading a target system](https://www.erlang.org/doc/system_principles/create_target.html).\n  [Learn You Some Erlang has a chapter on hot code upgrades](https://learnyousomeerlang.com/relups).\n\n  Overall, there are many steps, complexities and assumptions made\n  during hot code upgrades, which is ultimately why they are not\n  provided by Elixir out of the box. However, hot code upgrades can\n  still be achieved by teams who desire to implement those steps\n  on top of `mix release` in their projects or as separate libraries.\n\n  ## Command line options\n\n    * `--force` - forces recompilation\n    * `--no-archives-check` - does not check archive\n    * `--no-deps-check` - does not check dependencies\n    * `--no-elixir-version-check` - does not check Elixir version\n    * `--no-compile` - does not compile before assembling the release\n    * `--overwrite` - overwrite existing files instead of prompting the user for action\n    * `--path` - the path of the release\n    * `--quiet` - does not write progress to the standard output\n    * `--version` - the version of the release\n\n  \"\"\"\n\n  import Mix.Generator\n\n  @switches [\n    overwrite: :boolean,\n    force: :boolean,\n    quiet: :boolean,\n    path: :string,\n    version: :string,\n    compile: :boolean,\n    deps_check: :boolean,\n    archives_check: :boolean,\n    elixir_version_check: :boolean\n  ]\n\n  @aliases [\n    f: :force\n  ]\n\n  @impl true\n  def run(args) do\n    Mix.Project.get!()\n    Mix.Task.run(\"compile\", args)\n    Mix.ensure_application!(:sasl)\n    Mix.ensure_application!(:crypto)\n\n    config = Mix.Project.config()\n\n    release =\n      case OptionParser.parse!(args, strict: @switches, aliases: @aliases) do\n        {overrides, [name]} -> Mix.Release.from_config!(String.to_atom(name), config, overrides)\n        {overrides, []} -> Mix.Release.from_config!(nil, config, overrides)\n        {_, _} -> Mix.raise(\"Expected \\\"mix release\\\" or \\\"mix release NAME\\\"\")\n      end\n\n    if not File.exists?(release.version_path) or\n         yes?(release, \"Release #{release.name}-#{release.version} already exists. Overwrite?\") do\n      run_steps(release)\n    end\n  end\n\n  defp yes?(release, message) do\n    release.options[:overwrite] or Mix.shell().yes?(message)\n  end\n\n  defp run_steps(%{steps: [step | steps]} = release) when is_function(step) do\n    case step.(%{release | steps: steps}) do\n      %Mix.Release{} = release ->\n        run_steps(release)\n\n      other ->\n        Mix.raise(\n          \"Expected step #{inspect(step)} to return a Mix.Release, got: #{inspect(other)}\"\n        )\n    end\n  end\n\n  defp run_steps(%{steps: [:tar | steps]} = release) do\n    %{release | steps: steps} |> make_tar() |> run_steps()\n  end\n\n  defp run_steps(%{steps: [:assemble | steps]} = release) do\n    %{release | steps: steps} |> assemble() |> run_steps()\n  end\n\n  defp run_steps(%{steps: []} = release) do\n    announce(release)\n  end\n\n  defp assemble(release) do\n    config = Mix.Project.config()\n    message = \"#{release.name}-#{release.version} on MIX_ENV=#{Mix.env()}\"\n    info(release, [:green, \"* assembling \", :reset, message])\n\n    # releases/\n    #   VERSION/\n    #     consolidated/\n    #     NAME.rel\n    #     start.boot\n    #     start.script\n    #     start_clean.boot\n    #     start_clean.script\n    #     sys.config\n    # releases/\n    #   COOKIE\n    #   start_erl.data\n    {consolidation_path, release} = build_rel(release, config)\n\n    [\n      # erts-VSN/\n      :erts,\n      # releases/VERSION/consolidated\n      {:consolidated, consolidation_path},\n      # bin/\n      #   RELEASE_NAME\n      #   RELEASE_NAME.bat\n      #   start\n      #   start.bat\n      # releases/\n      #   VERSION/\n      #     elixir\n      #     elixir.bat\n      #     iex\n      #     iex.bat\n      {:executables, Keyword.get(release.options, :include_executables_for, [:unix, :windows])}\n      # lib/APP_NAME-APP_VSN/\n      | Map.keys(release.applications)\n    ]\n    |> Task.async_stream(&copy(&1, release), ordered: false, timeout: :infinity)\n    |> Stream.run()\n\n    copy_overlays(release)\n  end\n\n  defp make_tar(release) do\n    build_path = Mix.Project.build_path()\n\n    dir_path =\n      if release.path == Path.join([build_path, \"rel\", Atom.to_string(release.name)]) do\n        build_path\n      else\n        release.path\n      end\n\n    out_path = Path.join(dir_path, \"#{release.name}-#{release.version}.tar.gz\")\n    info(release, [:green, \"* building \", :reset, out_path])\n\n    lib_dirs =\n      Enum.reduce(release.applications, [], fn {name, app_config}, acc ->\n        vsn = Keyword.fetch!(app_config, :vsn)\n        [Path.join(\"lib\", \"#{name}-#{vsn}\") | acc]\n      end)\n\n    erts_dir =\n      case release.erts_source do\n        nil -> []\n        _ -> [\"erts-#{release.erts_version}\"]\n      end\n\n    release_files =\n      for basename <- File.ls!(Path.join(release.path, \"releases\")),\n          not File.dir?(Path.join([release.path, \"releases\", basename])),\n          do: Path.join(\"releases\", basename)\n\n    dirs =\n      [\"bin\", Path.join(\"releases\", release.version)] ++\n        erts_dir ++ lib_dirs ++ release_files\n\n    files =\n      dirs\n      |> Enum.filter(&File.exists?(Path.join(release.path, &1)))\n      |> Kernel.++(release.overlays)\n      |> Enum.map(&{String.to_charlist(&1), String.to_charlist(Path.join(release.path, &1))})\n\n    File.rm(out_path)\n    :ok = :erl_tar.create(String.to_charlist(out_path), files, [:dereference, :compressed])\n    release\n  end\n\n  # build_rel\n\n  defp build_rel(release, config) do\n    version_path = release.version_path\n    File.rm_rf!(version_path)\n    File.mkdir_p!(version_path)\n    release = maybe_add_config_reader_provider(config, release, version_path)\n\n    consolidation_path =\n      if config[:consolidate_protocols] do\n        Mix.Project.consolidation_path(config)\n      end\n\n    sys_config =\n      if File.regular?(config[:config_path]) do\n        config[:config_path] |> Config.Reader.read!(env: Mix.env(), target: Mix.target())\n      else\n        []\n      end\n\n    vm_args_path = Path.join(version_path, \"vm.args\")\n    remote_vm_args_path = Path.join(version_path, \"remote.vm.args\")\n    cookie_path = Path.join(release.path, \"releases/COOKIE\")\n    start_erl_path = Path.join(release.path, \"releases/start_erl.data\")\n    config_provider_path = {:system, \"RELEASE_SYS_CONFIG\", \".config\"}\n\n    with :ok <- make_boot_scripts(release, version_path, consolidation_path),\n         :ok <- make_vm_args(release, vm_args_path),\n         :ok <- make_vm_args(release, remote_vm_args_path),\n         :ok <- Mix.Release.make_sys_config(release, sys_config, config_provider_path),\n         :ok <- Mix.Release.make_cookie(release, cookie_path),\n         :ok <- Mix.Release.make_start_erl(release, start_erl_path) do\n      {consolidation_path, release}\n    else\n      {:error, message} ->\n        File.rm_rf!(version_path)\n        Mix.raise(message)\n    end\n  end\n\n  defp maybe_add_config_reader_provider(config, %{options: opts} = release, version_path) do\n    default_path = config[:config_path] |> Path.dirname() |> Path.join(\"runtime.exs\")\n    deprecated_path = config[:config_path] |> Path.dirname() |> Path.join(\"releases.exs\")\n\n    {path, reboot?} =\n      cond do\n        opts[:runtime_config_path] == false ->\n          {false, false}\n\n        path = opts[:runtime_config_path] ->\n          {path, false}\n\n        File.exists?(default_path) ->\n          if File.exists?(deprecated_path) do\n            IO.warn(\n              \"both #{inspect(default_path)} and #{inspect(deprecated_path)} have been \" <>\n                \"found, but only #{inspect(default_path)} will be used\"\n            )\n          end\n\n          {default_path, false}\n\n        File.exists?(deprecated_path) ->\n          IO.warn(\n            \"config/releases.exs is deprecated, use config/runtime.exs or set :runtime_config_path in your release configuration instead\"\n          )\n\n          {deprecated_path, true}\n\n        true ->\n          {nil, false}\n      end\n\n    cond do\n      path ->\n        msg = \"#{path} to configure the release at runtime\"\n        info(release, [:green, \"* using \", :reset, msg])\n        File.cp!(path, Path.join(version_path, \"runtime.exs\"))\n        init = {:system, \"RELEASE_ROOT\", \"/releases/#{release.version}/runtime.exs\"}\n        opts = [path: init, env: Mix.env(), target: Mix.target(), imports: :disabled]\n        release = update_in(release.config_providers, &[{Config.Reader, opts} | &1])\n        update_in(release.options, &Keyword.put_new(&1, :reboot_system_after_config, reboot?))\n\n      release.config_providers == [] and path != false ->\n        skipping(\"runtime configuration (#{default_path} not found)\")\n        release\n\n      true ->\n        release\n    end\n  end\n\n  defp make_boot_scripts(release, version_path, consolidation_path) do\n    prepend_paths =\n      if consolidation_path do\n        [\"$RELEASE_LIB/../releases/#{release.version}/consolidated\"]\n      else\n        []\n      end\n\n    results =\n      for {boot_name, modes} <- release.boot_scripts do\n        sys_path = Path.join(version_path, Atom.to_string(boot_name))\n\n        with :ok <- Mix.Release.make_boot_script(release, sys_path, modes, prepend_paths) do\n          if boot_name == :start do\n            rel_path = Path.join(Path.dirname(sys_path), \"#{release.name}.rel\")\n            File.rename!(sys_path <> \".rel\", rel_path)\n          else\n            File.rm(sys_path <> \".rel\")\n          end\n\n          :ok\n        end\n      end\n\n    Enum.find(results, :ok, &(&1 != :ok))\n  end\n\n  defp make_vm_args(release, path) do\n    vm_args_template = Mix.Release.rel_templates_path(release, \"#{Path.basename(path)}.eex\")\n\n    if File.exists?(vm_args_template) do\n      copy_template(vm_args_template, path, [release: release], force: true)\n    else\n      File.write!(path, vm_args_template(release: release))\n    end\n\n    :ok\n  end\n\n  defp announce(release) do\n    path = Path.relative_to_cwd(release.path)\n    cmd = \"#{path}/bin/#{release.name}\"\n\n    info(release, \"\"\"\n\n    Release created at #{path}\n\n        # To start your system\n        #{cmd} start\n\n    Once the release is running:\n\n        # To connect to it remotely\n        #{cmd} remote\n\n        # To stop it gracefully (you may also send SIGINT/SIGTERM)\n        #{cmd} stop\n\n    To list all commands:\n\n        #{cmd}\n    \"\"\")\n  end\n\n  defp info(release, message) do\n    if !release.options[:quiet] do\n      Mix.shell().info(message)\n    end\n  end\n\n  defp skipping(message) do\n    Mix.shell().info([:yellow, \"* skipping \", :reset, message])\n  end\n\n  ## Overlays\n\n  defp copy_overlays(release) do\n    target = release.path\n    default = Mix.Release.rel_templates_path(release, \"overlays\")\n\n    overlays =\n      if File.dir?(default) do\n        [default | List.wrap(release.options[:overlays])]\n      else\n        List.wrap(release.options[:overlays])\n      end\n\n    relative =\n      overlays\n      |> Enum.flat_map(&File.cp_r!(&1, target))\n      |> Enum.uniq()\n      |> List.delete(target)\n      |> Enum.map(&Path.relative_to(&1, target))\n\n    update_in(release.overlays, &(relative ++ &1))\n  end\n\n  ## Copy operations\n\n  defp copy(:erts, release) do\n    _ = Mix.Release.copy_erts(release)\n    :ok\n  end\n\n  defp copy(app, release) when is_atom(app) do\n    Mix.Release.copy_app(release, app)\n  end\n\n  defp copy({:consolidated, consolidation_path}, release) do\n    if consolidation_path do\n      consolidation_target = Path.join(release.version_path, \"consolidated\")\n      _ = Mix.Release.copy_ebin(release, consolidation_path, consolidation_target)\n    end\n\n    :ok\n  end\n\n  defp copy({:executables, include_executables_for}, release) do\n    elixir_bin_path = Application.app_dir(:elixir, \"../../bin\")\n    bin_path = Path.join(release.path, \"bin\")\n    File.mkdir_p!(bin_path)\n\n    for os <- include_executables_for do\n      {env, env_fun, clis} = cli_for(os, release)\n      env_path = Path.join(release.version_path, env)\n      env_template_path = Mix.Release.rel_templates_path(release, env <> \".eex\")\n\n      if File.exists?(env_template_path) do\n        copy_template(env_template_path, env_path, [release: release], force: true)\n      else\n        File.write!(env_path, env_fun.(release))\n      end\n\n      for {filename, contents} <- clis do\n        target = Path.join(bin_path, filename)\n        File.write!(target, contents)\n        executable!(target)\n      end\n\n      for {filename, contents_fun} <- elixir_cli_for(os, release) do\n        source = Path.join(elixir_bin_path, filename)\n\n        if File.regular?(source) do\n          target = Path.join(release.version_path, filename)\n          File.write!(target, contents_fun.(source))\n          executable!(target)\n        else\n          skipping(\"#{filename} for #{os} (bin/#{filename} not found in the Elixir installation)\")\n        end\n      end\n    end\n  end\n\n  defp cli_for(:unix, release) do\n    {\"env.sh\", &env_template(release: &1), [{\"#{release.name}\", cli_template(release: release)}]}\n  end\n\n  defp cli_for(:windows, release) do\n    {\"env.bat\", &env_bat_template(release: &1),\n     [{\"#{release.name}.bat\", cli_bat_template(release: release)}]}\n  end\n\n  defp elixir_cli_for(:unix, release) do\n    [\n      {\"elixir\",\n       &(&1\n         |> File.read!()\n         |> String.replace(\n           ~s[ -elixir_root \"$SCRIPT_PATH\"/../lib -pa \"$SCRIPT_PATH\"/../lib/elixir/ebin ],\n           \" \"\n         )\n         |> replace_erts_bin(release, ~s[\"$SCRIPT_PATH\"/../../erts-#{release.erts_version}/bin/]))},\n      {\"iex\", &File.read!/1}\n    ]\n  end\n\n  defp elixir_cli_for(:windows, release) do\n    [\n      {\"elixir.bat\",\n       &(&1\n         |> File.read!()\n         |> String.replace(\n           ~s[ -elixir_root !SCRIPT_PATH!..\\\\lib -pa !SCRIPT_PATH!..\\\\lib\\\\elixir\\\\ebin ],\n           \" \"\n         )\n         |> replace_erts_bin(release, ~s[%~dp0\\\\..\\\\..\\\\erts-#{release.erts_version}\\\\bin\\\\]))},\n      {\"iex.bat\", &File.read!/1}\n    ]\n  end\n\n  @erts_bin [~s[ERTS_BIN=\"$ERTS_BIN\"], ~s[ERTS_BIN=!ERTS_BIN!]]\n\n  defp replace_erts_bin(contents, release, new_path) do\n    if release.erts_source do\n      String.replace(contents, @erts_bin, ~s[ERTS_BIN=#{new_path}])\n    else\n      contents\n    end\n  end\n\n  defp executable!(path), do: File.chmod!(path, 0o755)\n\n  # Helper functions\n\n  defp release_mode(release, env_var) do\n    reboot? = Keyword.get(release.options, :reboot_system_after_config, false)\n\n    if reboot? and release.config_providers != [] do\n      \"-elixir config_provider_reboot_mode #{env_var}\"\n    else\n      \"-mode #{env_var}\"\n    end\n  end\n\n  embed_template(:vm_args, Mix.Tasks.Release.Init.vm_args_text(false))\n  embed_template(:env, Mix.Tasks.Release.Init.env_text())\n  embed_template(:cli, Mix.Tasks.Release.Init.cli_text())\n  embed_template(:env_bat, Mix.Tasks.Release.Init.env_bat_text())\n  embed_template(:cli_bat, Mix.Tasks.Release.Init.cli_bat_text())\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/release.init.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Release.Init do\n  use Mix.Task\n\n  @shortdoc \"Generates sample files for releases\"\n\n  @moduledoc \"\"\"\n  Generates sample files for releases.\n\n      $ mix release.init\n      * creating rel/vm.args.eex\n      * creating rel/remote.vm.args.eex\n      * creating rel/env.sh.eex\n      * creating rel/env.bat.eex\n  \"\"\"\n\n  import Mix.Generator\n\n  @switches [\n    force: :boolean,\n    quiet: :boolean\n  ]\n\n  @aliases [\n    force: :f\n  ]\n\n  @impl true\n  def run(args) do\n    {opts, args} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)\n\n    if args != [] do\n      Mix.raise(\"Expected \\\"mix release.init\\\" without arguments, got: #{inspect(args)}\")\n    end\n\n    create_file(\"rel/vm.args.eex\", vm_args_text(false), opts)\n    create_file(\"rel/remote.vm.args.eex\", vm_args_text(true), opts)\n    create_file(\"rel/env.sh.eex\", env_text(), opts)\n    create_file(\"rel/env.bat.eex\", env_bat_text(), opts)\n    :ok\n  end\n\n  @doc false\n  def vm_args_text(remote?),\n    do: \"\"\"\n    ## Customize flags given to the VM: https://www.erlang.org/doc/man/erl.html\n    ## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here\n\n    ## Increase number of concurrent ports/sockets\n    ##+Q 65536\n\n    ## Tweak GC to run more often\n    ##-env ERL_FULLSWEEP_AFTER 10\n\n    ## Enable deployment without epmd\n    ## (requires changing both vm.args and remote.vm.args)\n    ##-start_epmd false -erl_epmd_port 6789#{if(remote?, do: \" -dist_listen false\")}\n    \"\"\"\n\n  @doc false\n  def env_text,\n    do: ~S\"\"\"\n    #!/bin/sh\n\n    # # Sets and enables heart (recommended only in daemon mode)\n    # case $RELEASE_COMMAND in\n    #   daemon*)\n    #     HEART_COMMAND=\"$RELEASE_ROOT/bin/$RELEASE_NAME $RELEASE_COMMAND\"\n    #     export HEART_COMMAND\n    #     export ELIXIR_ERL_OPTIONS=\"-heart\"\n    #     ;;\n    #   *)\n    #     ;;\n    # esac\n\n    # # Set the release to load code on demand (interactive) instead of preloading (embedded).\n    # export RELEASE_MODE=interactive\n\n    # # Set the release to work across nodes.\n    # # RELEASE_DISTRIBUTION must be \"sname\" (local), \"name\" (distributed) or \"none\".\n    # export RELEASE_DISTRIBUTION=name\n    # export RELEASE_NODE=<%= @release.name %>\n    \"\"\"\n\n  @doc false\n  def cli_text,\n    do: ~S\"\"\"\n    #!/bin/sh\n    set -e\n\n    readlink_f () {\n      cd \"$(dirname \"$1\")\" > /dev/null\n      filename=\"$(basename \"$1\")\"\n      if [ -h \"$filename\" ]; then\n        readlink_f \"$(readlink \"$filename\")\"\n      else\n        echo \"$(pwd -P)/$filename\"\n      fi\n    }\n\n    SELF=$(readlink_f \"$0\")\n    RELEASE_ROOT=\"$(CDPATH='' cd \"$(dirname \"$SELF\")/..\" && pwd -P)\"\n    export RELEASE_ROOT\n    RELEASE_NAME=\"${RELEASE_NAME:-\"<%= @release.name %>\"}\"\n    export RELEASE_NAME\n    RELEASE_VSN=\"${RELEASE_VSN:-\"$(cut -d' ' -f2 \"$RELEASE_ROOT/releases/start_erl.data\")\"}\"\n    export RELEASE_VSN\n    RELEASE_COMMAND=\"$1\"\n    export RELEASE_COMMAND\n    RELEASE_PROG=\"${RELEASE_PROG:-\"$(echo \"$0\" | sed 's/.*\\///')\"}\"\n    export RELEASE_PROG\n\n    REL_VSN_DIR=\"$RELEASE_ROOT/releases/$RELEASE_VSN\"\n    . \"$REL_VSN_DIR/env.sh\"\n\n    RELEASE_COOKIE=\"${RELEASE_COOKIE:-\"$(cat \"$RELEASE_ROOT/releases/COOKIE\")\"}\"\n    export RELEASE_COOKIE\n    RELEASE_MODE=\"${RELEASE_MODE:-\"embedded\"}\"\n    export RELEASE_MODE\n    RELEASE_NODE=\"${RELEASE_NODE:-\"$RELEASE_NAME\"}\"\n    export RELEASE_NODE\n    RELEASE_TMP=\"${RELEASE_TMP:-\"$RELEASE_ROOT/tmp\"}\"\n    export RELEASE_TMP\n    RELEASE_VM_ARGS=\"${RELEASE_VM_ARGS:-\"$REL_VSN_DIR/vm.args\"}\"\n    export RELEASE_VM_ARGS\n    RELEASE_REMOTE_VM_ARGS=\"${RELEASE_REMOTE_VM_ARGS:-\"$REL_VSN_DIR/remote.vm.args\"}\"\n    export RELEASE_REMOTE_VM_ARGS\n    RELEASE_DISTRIBUTION=\"${RELEASE_DISTRIBUTION:-\"sname\"}\"\n    export RELEASE_DISTRIBUTION\n    RELEASE_BOOT_SCRIPT=\"${RELEASE_BOOT_SCRIPT:-\"start\"}\"\n    export RELEASE_BOOT_SCRIPT\n    RELEASE_BOOT_SCRIPT_CLEAN=\"${RELEASE_BOOT_SCRIPT_CLEAN:-\"start_clean\"}\"\n    export RELEASE_BOOT_SCRIPT_CLEAN\n\n    rand () {\n      dd count=1 bs=2 if=/dev/urandom 2> /dev/null | od -x | awk 'NR==1{print $2}'\n    }\n\n    release_distribution () {\n      case $RELEASE_DISTRIBUTION in\n        none)\n          ;;\n\n        name | sname)\n          echo \"--$RELEASE_DISTRIBUTION $1\"\n          ;;\n\n        *)\n          echo \"ERROR: Expected RELEASE_DISTRIBUTION to be sname, name, or none, got: $RELEASE_DISTRIBUTION\" >&2\n          exit 1\n          ;;\n      esac\n    }\n\n    rpc () {\n      exec \"$REL_VSN_DIR/elixir\" \\\n           --hidden --cookie \"$RELEASE_COOKIE\" \\\n           $(release_distribution \"rpc-$(rand)-$RELEASE_NODE\") \\\n           --boot \"$REL_VSN_DIR/$RELEASE_BOOT_SCRIPT_CLEAN\" \\\n           --boot-var RELEASE_LIB \"$RELEASE_ROOT/lib\" \\\n           --vm-args \"$RELEASE_REMOTE_VM_ARGS\" \\\n           --rpc-eval \"$RELEASE_NODE\" \"$1\"\n    }\n\n    start () {\n      export_release_sys_config\n      REL_EXEC=\"$1\"\n      shift\n      exec \"$REL_VSN_DIR/$REL_EXEC\" \\\n           --cookie \"$RELEASE_COOKIE\" \\\n           $(release_distribution \"$RELEASE_NODE\") \\\n           --erl \"<%= release_mode(@release, \"$RELEASE_MODE\") %>\" \\\n           --erl-config \"$RELEASE_SYS_CONFIG\" \\\n           --boot \"$REL_VSN_DIR/$RELEASE_BOOT_SCRIPT\" \\\n           --boot-var RELEASE_LIB \"$RELEASE_ROOT/lib\" \\\n           --vm-args \"$RELEASE_VM_ARGS\" \"$@\"\n    }\n\n    export_release_sys_config () {\n      DEFAULT_SYS_CONFIG=\"${RELEASE_SYS_CONFIG:-\"$REL_VSN_DIR/sys\"}\"\n\n      if grep -q \"RUNTIME_CONFIG=true\" \"$DEFAULT_SYS_CONFIG.config\"; then\n        RELEASE_SYS_CONFIG=\"$RELEASE_TMP/$RELEASE_NAME-$RELEASE_VSN-$(date +%Y%m%d%H%M%S)-$(rand).runtime\"\n\n        (mkdir -p \"$RELEASE_TMP\" && cat \"$DEFAULT_SYS_CONFIG.config\" >\"$RELEASE_SYS_CONFIG.config\") || (\n          echo \"ERROR: Cannot start release because it could not write $RELEASE_SYS_CONFIG.config\" >&2\n          exit 1\n        )\n      else\n        RELEASE_SYS_CONFIG=\"$DEFAULT_SYS_CONFIG\"\n      fi\n\n      export RELEASE_SYS_CONFIG\n    }\n\n    case $1 in\n      start)\n        start \"elixir\" --no-halt\n        ;;\n\n      start_iex)\n        start \"iex\"\n        ;;\n\n      daemon)\n        start \"elixir\" --no-halt --pipe-to \"${RELEASE_TMP}/pipe\" \"${RELEASE_TMP}/log\"\n        ;;\n\n      daemon_iex)\n        start \"iex\" --pipe-to \"${RELEASE_TMP}/pipe\" \"${RELEASE_TMP}/log\"\n        ;;\n\n      eval)\n        if [ -z \"$2\" ]; then\n          echo \"ERROR: EVAL expects an expression as argument\" >&2\n          exit 1\n        fi\n        script=\"$2\"\n        shift 2\n        export_release_sys_config\n        exec \"$REL_VSN_DIR/elixir\" \\\n           --cookie \"$RELEASE_COOKIE\" \\\n           --erl-config \"$RELEASE_SYS_CONFIG\" \\\n           --boot \"$REL_VSN_DIR/$RELEASE_BOOT_SCRIPT_CLEAN\" \\\n           --boot-var RELEASE_LIB \"$RELEASE_ROOT/lib\" \\\n           --vm-args \"$RELEASE_VM_ARGS\" --eval \"$script\" -- \"$@\"\n        ;;\n\n      remote)\n        exec \"$REL_VSN_DIR/iex\" \\\n             --hidden --cookie \"$RELEASE_COOKIE\" \\\n             $(release_distribution \"rem-$(rand)-$RELEASE_NODE\") \\\n             --boot \"$REL_VSN_DIR/$RELEASE_BOOT_SCRIPT_CLEAN\" \\\n             --boot-var RELEASE_LIB \"$RELEASE_ROOT/lib\" \\\n             --vm-args \"$RELEASE_REMOTE_VM_ARGS\" \\\n             --remsh \"$RELEASE_NODE\"\n        ;;\n\n      rpc)\n        if [ -z \"$2\" ]; then\n          echo \"ERROR: RPC expects an expression as argument\" >&2\n          exit 1\n        fi\n        rpc \"$2\"\n        ;;\n\n      restart|stop)\n        rpc \"System.$1()\"\n        ;;\n\n      pid)\n        rpc \"IO.puts System.pid()\"\n        ;;\n\n      version)\n        echo \"$RELEASE_NAME $RELEASE_VSN\"\n        ;;\n\n      *)\n        echo \"Usage: $(basename \"$0\") COMMAND [ARGS]\n\n    The known commands are:\n\n        start          Starts the system\n        start_iex      Starts the system with IEx attached\n        daemon         Starts the system as a daemon\n        daemon_iex     Starts the system as a daemon with IEx attached\n        eval \\\"EXPR\\\"    Executes the given expression on a new, non-booted system\n        rpc \\\"EXPR\\\"     Executes the given expression remotely on the running system\n        remote         Connects to the running system via a remote shell\n        restart        Restarts the running system via a remote command\n        stop           Stops the running system via a remote command\n        pid            Prints the operating system PID of the running system via a remote command\n        version        Prints the release name and version to be booted\n    \" >&2\n\n        if [ -n \"$1\" ]; then\n          echo \"ERROR: Unknown command $1\" >&2\n          exit 1\n        fi\n        ;;\n    esac\n    \"\"\"\n\n  @doc false\n  def env_bat_text,\n    do: ~S\"\"\"\n    @echo off\n    rem Set the release to load code on demand (interactive) instead of preloading (embedded).\n    rem set RELEASE_MODE=interactive\n\n    rem Set the release to work across nodes.\n    rem RELEASE_DISTRIBUTION must be sname (local), name (distributed) or none.\n    rem set RELEASE_DISTRIBUTION=name\n    rem set RELEASE_NODE=<%= @release.name %>\n    \"\"\"\n\n  @doc false\n  def cli_bat_text,\n    do: ~S\"\"\"\n    @echo off\n    setlocal enabledelayedexpansion\n\n    pushd .\n    pushd \"%~dp0\\..\"\n    set RELEASE_ROOT=%cd%\n    popd\n    popd\n\n    if not defined RELEASE_NAME (set RELEASE_NAME=<%= @release.name %>)\n    if not defined RELEASE_VSN (for /f \"tokens=1,2\" %%K in ('type \"!RELEASE_ROOT!\\releases\\start_erl.data\"') do (set ERTS_VSN=%%K) && (set RELEASE_VSN=%%L))\n    if not defined RELEASE_PROG (set RELEASE_PROG=%~nx0)\n    set RELEASE_COMMAND=%~1\n    set REL_VSN_DIR=!RELEASE_ROOT!\\releases\\!RELEASE_VSN!\n    call \"!REL_VSN_DIR!\\env.bat\" %*\n\n    if not defined RELEASE_COOKIE (set /p RELEASE_COOKIE=<!RELEASE_ROOT!\\releases\\COOKIE)\n    if not defined RELEASE_MODE (set RELEASE_MODE=embedded)\n    if not defined RELEASE_NODE (set RELEASE_NODE=!RELEASE_NAME!)\n    if not defined RELEASE_TMP (set RELEASE_TMP=!RELEASE_ROOT!\\tmp)\n    if not defined RELEASE_VM_ARGS (set RELEASE_VM_ARGS=!REL_VSN_DIR!\\vm.args)\n    if not defined RELEASE_REMOTE_VM_ARGS (set RELEASE_REMOTE_VM_ARGS=!REL_VSN_DIR!\\remote.vm.args)\n    if not defined RELEASE_DISTRIBUTION (set RELEASE_DISTRIBUTION=sname)\n    if not defined RELEASE_BOOT_SCRIPT (set RELEASE_BOOT_SCRIPT=start)\n    if not defined RELEASE_BOOT_SCRIPT_CLEAN (set RELEASE_BOOT_SCRIPT_CLEAN=start_clean)\n    if not defined RELEASE_SYS_CONFIG (set RELEASE_SYS_CONFIG=!REL_VSN_DIR!\\sys)\n\n    if \"!RELEASE_DISTRIBUTION!\" == \"none\" (\n      rem\n    ) else if \"!RELEASE_DISTRIBUTION!\" == \"name\" (\n      rem\n    ) else if \"!RELEASE_DISTRIBUTION!\" == \"sname\" (\n      rem\n    ) else (\n      echo ERROR: Expected RELEASE_DISTRIBUTION to be sname, name, or none, got: !RELEASE_DISTRIBUTION!\n      exit /B 1\n    )\n\n    if \"!RELEASE_MODE!\" == \"embedded\" (\n      rem\n    ) else if \"!RELEASE_MODE!\" == \"interactive\" (\n      rem\n    ) else (\n      echo ERROR: Expected RELEASE_MODE to be embedded or interactive, got: !RELEASE_MODE!\n      exit /B 1\n    )\n\n    if \"%~1\" == \"start\" (set \"REL_EXEC=elixir\" && set \"REL_EXTRA=--no-halt\" && set \"REL_GOTO=start\")\n    if \"%~1\" == \"start_iex\" (set \"REL_EXEC=iex\" && set \"REL_GOTO=start\")\n    if \"%~1\" == \"install\" (set \"REL_GOTO=install\")\n    if \"%~1\" == \"eval\" (\n      if \"%~2\" == \"\" (\n        echo ERROR: EVAL expects an expression as argument\n        exit /B 1\n      )\n      set \"REL_GOTO=eval\"\n    )\n\n    if not \"!REL_GOTO!\" == \"\" (\n      findstr \"RUNTIME_CONFIG=true\" \"!RELEASE_SYS_CONFIG!.config\" >nul 2>&1 && (\n        set DEFAULT_SYS_CONFIG=!RELEASE_SYS_CONFIG!\n        set \"TIMESTAMP=%TIME::=%\"\n        set RELEASE_SYS_CONFIG=!RELEASE_TMP!\\!RELEASE_NAME!-!RELEASE_VSN!-!TIMESTAMP!-!RANDOM!.runtime\n        mkdir \"!RELEASE_TMP!\" >nul 2>&1\n        copy /y \"!DEFAULT_SYS_CONFIG!.config\" \"!RELEASE_SYS_CONFIG!.config\" >nul || (\n          echo Cannot start release because it could not write to \"!RELEASE_SYS_CONFIG!.config\"\n          goto end\n        )\n      )\n\n      goto !REL_GOTO!\n    )\n\n    if \"%~1\" == \"remote\" (goto remote)\n    if \"%~1\" == \"version\" (goto version)\n    if \"%~1\" == \"stop\" (set \"REL_RPC=System.stop()\" && goto rpc)\n    if \"%~1\" == \"restart\" (set \"REL_RPC=System.restart()\" && goto rpc)\n    if \"%~1\" == \"pid\" (set \"REL_RPC=IO.puts(System.pid())\" && goto rpc)\n    if \"%~1\" == \"rpc\" (\n      if \"%~2\" == \"\" (\n        echo ERROR: RPC expects an expression as argument\n        exit /B 1\n      )\n      set \"REL_RPC=%~2\"\n      goto rpc\n    )\n\n    echo Usage: %~nx0 COMMAND [ARGS]\n    echo.\n    echo The known commands are:\n    echo.\n    echo    start        Starts the system\n    echo    start_iex    Starts the system with IEx attached\n    echo    install      Installs this system as a Windows service\n    echo    eval \"EXPR\"  Executes the given expression on a new, non-booted system\n    echo    rpc \"EXPR\"   Executes the given expression remotely on the running system\n    echo    remote       Connects to the running system via a remote shell\n    echo    restart      Restarts the running system via a remote command\n    echo    stop         Stops the running system via a remote command\n    echo    pid          Prints the operating system PID of the running system via a remote command\n    echo    version      Prints the release name and version to be booted\n    echo.\n    if not \"%~1\" == \"\" (\n      echo ERROR: Unknown command %~1\n      exit /B 1\n    )\n    goto end\n\n    :start\n    if \"!RELEASE_DISTRIBUTION!\" == \"none\" (\n      set RELEASE_DISTRIBUTION_FLAG=\n    ) else (\n      set RELEASE_DISTRIBUTION_FLAG=--!RELEASE_DISTRIBUTION! \"!RELEASE_NODE!\"\n    )\n\n    \"!REL_VSN_DIR!\\!REL_EXEC!.bat\" !REL_EXTRA! ^\n      --cookie \"!RELEASE_COOKIE!\" ^\n      !RELEASE_DISTRIBUTION_FLAG! ^\n      --erl \"<%= release_mode(@release, \"!RELEASE_MODE!\") %>\" ^\n      --erl-config \"!RELEASE_SYS_CONFIG!\" ^\n      --boot \"!REL_VSN_DIR!\\!RELEASE_BOOT_SCRIPT!\" ^\n      --boot-var RELEASE_LIB \"!RELEASE_ROOT!\\lib\" ^\n      --vm-args \"!RELEASE_VM_ARGS!\"\n    goto end\n\n    :eval\n    set EVAL=%~2\n    shift\n    :loop\n    shift\n    if not \"%1\"==\"\" (\n      set args=%args% %1\n      goto :loop\n    )\n    \"!REL_VSN_DIR!\\elixir.bat\" ^\n      --eval \"!EVAL!\" ^\n      --cookie \"!RELEASE_COOKIE!\" ^\n      --erl-config \"!RELEASE_SYS_CONFIG!\" ^\n      --boot \"!REL_VSN_DIR!\\!RELEASE_BOOT_SCRIPT_CLEAN!\" ^\n      --boot-var RELEASE_LIB \"!RELEASE_ROOT!\\lib\" ^\n      --vm-args \"!RELEASE_VM_ARGS!\" -- %args%\n    goto end\n\n    :remote\n    if \"!RELEASE_DISTRIBUTION!\" == \"none\" (\n      set RELEASE_DISTRIBUTION_FLAG=\n    ) else (\n      set RELEASE_DISTRIBUTION_FLAG=--!RELEASE_DISTRIBUTION! \"rem-!RANDOM!-!RELEASE_NODE!\"\n    )\n\n    \"!REL_VSN_DIR!\\iex.bat\" ^\n      --hidden --cookie \"!RELEASE_COOKIE!\" ^\n      !RELEASE_DISTRIBUTION_FLAG! ^\n      --boot \"!REL_VSN_DIR!\\!RELEASE_BOOT_SCRIPT_CLEAN!\" ^\n      --boot-var RELEASE_LIB \"!RELEASE_ROOT!\\lib\" ^\n      --vm-args \"!RELEASE_REMOTE_VM_ARGS!\" ^\n      --remsh \"!RELEASE_NODE!\"\n    goto end\n\n    :rpc\n    if \"!RELEASE_DISTRIBUTION!\" == \"none\" (\n      set RELEASE_DISTRIBUTION_FLAG=\n    ) else (\n      set RELEASE_DISTRIBUTION_FLAG=--!RELEASE_DISTRIBUTION! \"rpc-!RANDOM!-!RELEASE_NODE!\"\n    )\n\n    \"!REL_VSN_DIR!\\elixir.bat\" ^\n      --hidden --cookie \"!RELEASE_COOKIE!\" ^\n      !RELEASE_DISTRIBUTION_FLAG! ^\n      --boot \"!REL_VSN_DIR!\\!RELEASE_BOOT_SCRIPT_CLEAN!\" ^\n      --boot-var RELEASE_LIB \"!RELEASE_ROOT!\\lib\" ^\n      --vm-args \"!RELEASE_REMOTE_VM_ARGS!\" ^\n      --rpc-eval \"!RELEASE_NODE!\" \"!REL_RPC!\"\n    goto end\n\n    :version\n    echo !RELEASE_NAME! !RELEASE_VSN!\n    goto end\n\n    :install\n    if exist !RELEASE_ROOT!\\erts-!ERTS_VSN! (\n      set ERLSRV=!RELEASE_ROOT!\\erts-!ERTS_VSN!\\bin\\erlsrv.exe\n    ) else (\n      set ERLSRV=erlsrv.exe\n    )\n\n    if \"!RELEASE_DISTRIBUTION!\" == \"none\" (\n      echo ERROR: RELEASE_DISTRIBUTION is required in install command\n      exit /B 1\n    )\n\n    \"!ERLSRV!\" add \"!RELEASE_NAME!_!RELEASE_NAME!\" ^\n      -!RELEASE_DISTRIBUTION! \"!RELEASE_NODE!\" ^\n      -env RELEASE_ROOT=\"!RELEASE_ROOT!\" -env RELEASE_NAME=\"!RELEASE_NAME!\" -env RELEASE_VSN=\"!RELEASE_VSN!\" -env RELEASE_MODE=\"!RELEASE_MODE!\" -env RELEASE_COOKIE=\"!RELEASE_COOKIE!\" -env RELEASE_NODE=\"!RELEASE_NODE!\" -env RELEASE_VM_ARGS=\"!RELEASE_VM_ARGS!\" -env RELEASE_TMP=\"!RELEASE_TMP!\" -env RELEASE_SYS_CONFIG=\"!RELEASE_SYS_CONFIG!\" ^\n      -args \"-setcookie !RELEASE_COOKIE! -config \"\"!RELEASE_SYS_CONFIG!\"\" <%= release_mode(@release, \"!RELEASE_MODE!\") %> -boot \"\"!REL_VSN_DIR!\\start\"\" -boot_var RELEASE_LIB \"\"!RELEASE_ROOT!\\lib\"\" -args_file \"\"!REL_VSN_DIR!\\vm.args\\\"\"\"\n    if %ERRORLEVEL% EQU 0 (\n      echo Service installed but not started. From now on, it must be started and stopped by erlsrv:\n      echo.\n      echo     !ERLSRV! start !RELEASE_NAME!_!RELEASE_NAME!\n      echo     !ERLSRV! stop !RELEASE_NAME!_!RELEASE_NAME!\n      echo     !ERLSRV! remove !RELEASE_NAME!_!RELEASE_NAME!\n      echo     !ERLSRV! list\n      echo     !ERLSRV! help\n      echo.\n    )\n    goto end\n\n    :end\n    endlocal\n    \"\"\"\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/run.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Run do\n  use Mix.Task\n\n  @shortdoc \"Runs the current application\"\n\n  @moduledoc \"\"\"\n  Runs the current application.\n\n  `mix run` starts the current application dependencies and the\n  application itself. The application will be compiled if it has\n  not been compiled yet or it is outdated.\n\n  `mix run` may also run code in the application context through\n  additional options. For example, to run a script within the\n  current application, you may pass a filename as argument:\n\n      $ mix run my_app_script.exs arg1 arg2 arg3\n\n  Code to be executed can also be passed inline with the `-e` option:\n\n      $ mix run -e \"DbUtils.delete_old_records()\" -- arg1 arg2 arg3\n\n  In both cases, the command-line arguments for the script or expression\n  are available in `System.argv/0`. This mirrors the command line interface\n  in the `elixir` executable.\n\n  For starting long running systems, one typically passes the `--no-halt`\n  option:\n\n      $ mix run --no-halt\n\n  The `--no-start` option can also be given and neither the current application\n  nor its dependencies will be started. Alternatively, you may use\n  `mix eval` to evaluate a single expression without starting the current\n  application.\n\n  If you need to pass options to the Elixir executable at the same time\n  you use `mix run`, it can be done as follows:\n\n      $ elixir --sname hello -S mix run --no-halt\n\n  This task is automatically re-enabled, so it can be called multiple times\n  with different arguments.\n\n  ## Command-line options\n\n    * `--eval`, `-e` - evaluates the given code\n    * `--listeners` - starts Mix listeners (they are started by default,\n      unless `--no-listeners` or `--no-deps-check` are given)\n    * `--require`, `-r` - executes the given pattern/file\n    * `--parallel`, `-p` - makes all requires parallel\n    * `--preload-modules` - preloads all modules defined in applications\n    * `--no-archives-check` - does not check archives\n    * `--no-compile` - does not compile even if files require compilation\n    * `--no-deps-check` - does not check dependencies\n    * `--no-elixir-version-check` - does not check the Elixir version from mix.exs\n    * `--no-halt` - does not halt the system after running the command\n    * `--no-listeners` - does not start Mix listeners\n    * `--no-mix-exs` - allows the command to run even if there is no mix.exs\n    * `--no-start` - does not start applications after compilation\n\n  \"\"\"\n\n  @typedoc \"\"\"\n  Options for the internal `run/5` function.\n\n  These options are typically parsed from command-line arguments.\n  \"\"\"\n  @type run_opts :: [\n          {:parallel_require, String.t()}\n          | {:eval, String.t()}\n          | {:require, String.t()}\n          | {:parallel, boolean()}\n          | {:config, String.t()}\n        ]\n\n  @impl true\n  def run(args) do\n    {opts, head} =\n      OptionParser.parse_head!(\n        args,\n        aliases: [r: :require, p: :parallel, e: :eval, c: :config],\n        strict: [\n          parallel: :boolean,\n          require: :keep,\n          eval: :keep,\n          config: :keep,\n          mix_exs: :boolean,\n          halt: :boolean,\n          compile: :boolean,\n          deps_check: :boolean,\n          listeners: :boolean,\n          start: :boolean,\n          archives_check: :boolean,\n          elixir_version_check: :boolean,\n          parallel_require: :keep,\n          preload_modules: :boolean\n        ],\n        return_separator: true\n      )\n\n    run(args, opts, head, &Code.eval_string/1, &Code.require_file/1)\n    if not Keyword.get(opts, :halt, true), do: System.no_halt(true)\n    Mix.Task.reenable(\"run\")\n    :ok\n  end\n\n  @doc false\n  @spec run(\n          OptionParser.argv(),\n          run_opts,\n          OptionParser.argv(),\n          (String.t() -> term()),\n          (String.t() -> term())\n        ) :: :ok\n  def run(args, opts, head, expr_evaluator, file_evaluator) do\n    opts =\n      Enum.flat_map(opts, fn\n        {:parallel_require, value} ->\n          IO.warn(\n            \"the --parallel-require option is deprecated in favour of using \" <>\n              \"--parallel to make all requires parallel and --require VAL for requiring\"\n          )\n\n          [require: value, parallel: true]\n\n        opt ->\n          [opt]\n      end)\n\n    {file, argv} =\n      case {Keyword.has_key?(opts, :eval), head} do\n        {_, [\"--\" | rest]} -> {nil, rest}\n        {true, _} -> {nil, head}\n        {_, [head | tail]} -> {head, tail}\n        {_, []} -> {nil, []}\n      end\n\n    System.argv(argv)\n    process_config(opts)\n\n    # Start app after rewriting System.argv,\n    # but before requiring and evaling.\n    cond do\n      Mix.Project.get() ->\n        Mix.Task.run(\"app.start\", args)\n\n      \"--no-mix-exs\" in args ->\n        :ok\n\n      true ->\n        Mix.raise(\n          \"Cannot execute \\\"mix run\\\" without a Mix.Project, \" <>\n            \"please ensure you are running Mix in a directory with a mix.exs file \" <>\n            \"or pass the --no-mix-exs option\"\n        )\n    end\n\n    process_load(opts, expr_evaluator)\n\n    if file do\n      if File.regular?(file) do\n        file_evaluator.(file)\n      else\n        Mix.raise(\"No such file: #{file}\")\n      end\n    end\n\n    :ok\n  end\n\n  defp process_config(opts) do\n    for {:config, value} <- opts do\n      # TODO: Remove on v2.0.\n      IO.warn(\n        \"the --config flag is deprecated. If you need to handle multiple configurations, \" <>\n          \"it is preferable to dynamically import them in your config files\"\n      )\n\n      Mix.Tasks.Loadconfig.load_compile(value)\n    end\n\n    :ok\n  end\n\n  defp process_load(opts, expr_evaluator) do\n    require_runner =\n      if opts[:parallel] do\n        fn files ->\n          case Kernel.ParallelCompiler.require(files, return_diagnostics: true) do\n            {:ok, _, _} -> :ok\n            {:error, _, _} -> exit({:shutdown, 1})\n          end\n        end\n      else\n        fn files -> Enum.each(files, &Code.require_file/1) end\n      end\n\n    Enum.each(opts, fn\n      {:require, value} ->\n        case filter_patterns(value) do\n          [] ->\n            Mix.raise(\"No files matched pattern #{inspect(value)} given to --require\")\n\n          filtered ->\n            require_runner.(filtered)\n        end\n\n      {:eval, value} ->\n        expr_evaluator.(value)\n\n      _ ->\n        :ok\n    end)\n  end\n\n  defp filter_patterns(pattern) do\n    Enum.filter(Enum.uniq(Path.wildcard(pattern)), &File.regular?(&1))\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/test.coverage.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Test.Coverage do\n  use Mix.Task\n\n  @moduledoc \"\"\"\n  Build reports from exported test coverage.\n\n  In this moduledoc, we will describe how the default test\n  coverage works in Elixir and also explore how it is capable\n  of exporting coverage results to group reports from multiple\n  test runs.\n\n  ## Line coverage\n\n  Elixir uses Erlang's [`:cover`](`:cover`) for its default test coverage.\n  Erlang coverage is done by tracking *executable lines of code*.\n  This implies blank lines, code comments, literals (such as atoms),\n  function signatures, and patterns are not necessarily executable and\n  therefore won't be tracked in coverage reports. Code in macros defined in\n  your project are also often executed at compilation time, and therefore\n  may not be covered.\n\n  Let's see an example:\n\n      if some_condition? do\n        do_this()\n      else\n        do_that()\n      end\n\n  In the example above, if your tests exercise both `some_condition? == true`\n  and `some_condition? == false`, all branches will be covered, as they all\n  have executable code. However, the following code\n\n      if some_condition? do\n        do_this()\n      else\n        :default\n      end\n\n  won't ever mark the `:default` branch as covered, as there is no executable\n  code in the `else` branch. Note, however, this issue does not happen on `case`\n  or `cond`, as Elixir is able to mark the clause operator `->` as executable in\n  such corner cases:\n\n      case some_condition? do\n        true ->\n          do_this()\n\n        false ->\n          :default\n      end\n\n  If the code above is tested with both conditions, you should see entries\n  in both branches marked as covered.\n\n  Finally, it is worth discussing that line coverage by itself has its own\n  limitations. For example, take the following code:\n\n      do_this() || do_that()\n\n  Line coverage is not capable of expressing that both `do_this()` and\n  `do_that()` have been executed, since as soon as `do_this()` is executed,\n  the whole line is covered. Other techniques, such as branch coverage,\n  can help spot those cases, but they are not currently supported by the\n  default coverage tool.\n\n  Overall, code coverage can be a great tool for finding flaws in our\n  code (such as functions that haven't been covered) but it can also lead\n  teams into a false sense of security since 100% coverage never means all\n  different executions flows have been asserted, even with the most advanced\n  coverage techniques. It is up to you and your team to specify how much\n  emphasis you want to place on it.\n\n  ## Exporting coverage\n\n  This task can be used when you need to group the coverage\n  across multiple test runs. Let's see some examples.\n\n  ### Example: aggregating partitioned runs\n\n  If you partition your tests across multiple runs,\n  you can unify the report as shown below:\n\n      $ MIX_TEST_PARTITION=1 mix test --partitions 2 --cover\n      $ MIX_TEST_PARTITION=2 mix test --partitions 2 --cover\n      $ mix test.coverage\n\n  This works because the `--partitions` option\n  automatically exports the coverage results.\n\n  ### Example: aggregating coverage reports from all umbrella children\n\n  If you run `mix test.coverage` inside an umbrella,\n  it will automatically gather exported cover results\n  from all umbrella children - as long as the coverage\n  results have been exported, like this:\n\n      # from the umbrella root\n      $ mix test --cover --export-coverage default\n      $ mix test.coverage\n\n  Of course, if you want to actually partition the tests,\n  you can also do:\n\n      # from the umbrella root\n      $ MIX_TEST_PARTITION=1 mix test --partitions 2 --cover\n      $ MIX_TEST_PARTITION=2 mix test --partitions 2 --cover\n      $ mix test.coverage\n\n  On the other hand, if you want partitioned tests but\n  per-app reports, you can do:\n\n      # from the umbrella root\n      $ MIX_TEST_PARTITION=1 mix test --partitions 2 --cover\n      $ MIX_TEST_PARTITION=2 mix test --partitions 2 --cover\n      $ mix cmd mix test.coverage\n\n  When running `test.coverage` from the umbrella root, it\n  will use the `:test_coverage` configuration from the umbrella\n  root.\n\n  Finally, note the coverage itself is not measured across\n  the projects themselves. For example, if project B depends\n  on A, and if there is code in A that is only executed from\n  project B, those lines will not be marked as covered, which\n  is important, as those projects should be developed and tested\n  in isolation.\n\n  ### Other scenarios\n\n  There may be other scenarios where you want to export coverage.\n  For example, you may have broken your test suite into two, one\n  for unit tests and another for integration tests. In such scenarios,\n  you can explicitly use the `--export-coverage` command line option,\n  or the `:export` option under `:test_coverage` in your `mix.exs` file.\n  \"\"\"\n\n  @shortdoc \"Build report from exported test coverage\"\n  @default_threshold 90\n\n  @doc false\n  def run(_args) do\n    Mix.Task.run(\"compile\")\n    Mix.ensure_application!(:tools)\n    config = Mix.Project.config()\n    test_coverage = config[:test_coverage] || []\n    {cover_paths, compile_paths} = apps_paths(config, test_coverage)\n    pid = cover_compile(compile_paths)\n\n    case Enum.flat_map(cover_paths, &Path.wildcard(Path.join(&1, \"*.coverdata\"))) do\n      [] ->\n        Mix.shell().error(\n          \"Could not find .coverdata file in any of the paths: \" <>\n            Enum.join(cover_paths, \", \")\n        )\n\n      entries ->\n        for entry <- entries do\n          Mix.shell().info(\"Importing cover results: #{entry}\")\n          :ok = :cover.import(String.to_charlist(entry))\n        end\n\n        # Silence analyse import messages emitted by cover\n        {:ok, string_io} = StringIO.open(\"\")\n        Process.group_leader(pid, string_io)\n        Mix.shell().info(\"\")\n        generate_cover_results(test_coverage)\n    end\n  end\n\n  defp apps_paths(config, test_coverage) do\n    output = Keyword.get(test_coverage, :output, \"cover\")\n\n    if apps_paths = Mix.Project.apps_paths(config) do\n      build_path = Mix.Project.build_path(config)\n      apps_paths = Enum.sort(apps_paths)\n\n      compile_paths =\n        Enum.map(apps_paths, fn {app, _} ->\n          Path.join([build_path, \"lib\", Atom.to_string(app), \"ebin\"])\n        end)\n\n      {Enum.map(apps_paths, fn {_, path} -> Path.join(path, output) end), compile_paths}\n    else\n      {[output], [Mix.Project.compile_path(config)]}\n    end\n  end\n\n  @doc false\n  def start(compile_path, opts) do\n    Mix.shell().info(\"Cover compiling modules ...\")\n    Mix.ensure_application!(:tools)\n\n    if Keyword.get(opts, :local_only, true) do\n      :cover.local_only()\n    end\n\n    cover_compile([compile_path])\n\n    if name = opts[:export] do\n      fn ->\n        Mix.shell().info(\"\\nExporting cover results ...\\n\")\n        export_cover_results(name, opts)\n      end\n    else\n      fn ->\n        Mix.shell().info(\"\\nGenerating cover results ...\\n\")\n        generate_cover_results(opts)\n      end\n    end\n  end\n\n  defp cover_compile(compile_paths) do\n    _ = :cover.stop()\n    {:ok, pid} = :cover.start()\n\n    for compile_path <- compile_paths do\n      case :cover.compile_beam(beams(compile_path)) do\n        results when is_list(results) ->\n          :ok\n\n        {:error, reason} ->\n          Mix.raise(\n            \"Failed to cover compile directory #{inspect(Path.relative_to_cwd(compile_path))} \" <>\n              \"with reason: #{inspect(reason)}\"\n          )\n      end\n    end\n\n    pid\n  end\n\n  # Pick beams from the compile_path but if by any chance it is a protocol,\n  # gets its path from the code server (which will most likely point to\n  # the consolidation directory as long as it is enabled).\n  defp beams(dir) do\n    consolidation_dir = Mix.Project.consolidation_path()\n\n    consolidated =\n      case File.ls(consolidation_dir) do\n        {:ok, files} -> files\n        _ -> []\n      end\n\n    for file <- File.ls!(dir), Path.extname(file) == \".beam\" do\n      with true <- file in consolidated,\n           [_ | _] = path <- :code.which(file |> Path.rootname() |> String.to_atom()) do\n        path\n      else\n        _ -> String.to_charlist(Path.join(dir, file))\n      end\n    end\n  end\n\n  defp export_cover_results(name, opts) do\n    output = Keyword.get(opts, :output, \"cover\")\n    File.mkdir_p!(output)\n\n    case :cover.export(~c\"#{output}/#{name}.coverdata\") do\n      :ok ->\n        Mix.shell().info(\"Run \\\"mix test.coverage\\\" once all exports complete\")\n\n      {:error, reason} ->\n        Mix.shell().error(\"Export failed with reason: #{inspect(reason)}\")\n    end\n  end\n\n  @doc false\n  def generate_cover_results(opts) do\n    {:result, ok, _fail} = :cover.analyse(:coverage, :line)\n    ignore = opts[:ignore_modules] || []\n    modules = Enum.reject(:cover.modules(), &ignored?(&1, ignore))\n\n    if summary_opts = Keyword.get(opts, :summary, true) do\n      summary(ok, modules, summary_opts)\n    end\n\n    html(modules, opts)\n  end\n\n  defp ignored?(mod, ignores) do\n    Enum.any?(ignores, &ignored_any?(mod, &1))\n  end\n\n  defp ignored_any?(mod, %Regex{} = re), do: Regex.match?(re, inspect(mod))\n  defp ignored_any?(mod, other), do: mod == other\n\n  defp html(modules, opts) do\n    output = Keyword.get(opts, :output, \"cover\")\n    File.mkdir_p!(output)\n\n    modules\n    |> Enum.map(fn mod ->\n      pid = :cover.async_analyse_to_file(mod, ~c\"#{output}/#{mod}.html\", [:html])\n      Process.monitor(pid)\n    end)\n    |> Enum.each(fn ref ->\n      receive do\n        {:DOWN, ^ref, :process, _pid, _reason} ->\n          :ok\n      end\n    end)\n\n    Mix.shell().info(\"Generated HTML coverage results in #{inspect(output)} directory\")\n  end\n\n  defp summary(results, keep, summary_opts) do\n    {module_results, totals} = gather_coverage(results, keep)\n    module_results = Enum.sort(module_results, :desc)\n    print_summary(module_results, totals, summary_opts)\n\n    if totals < get_threshold(summary_opts) do\n      print_failed_threshold(totals, get_threshold(summary_opts))\n      System.at_exit(fn _ -> exit({:shutdown, 3}) end)\n    end\n\n    :ok\n  end\n\n  defp gather_coverage(results, keep) do\n    keep_set = MapSet.new(keep)\n\n    # When gathering coverage results, we need to skip any\n    # entry with line equal to 0 as those are generated code.\n    #\n    # We may also have multiple entries on the same line.\n    # Each line is only considered once.\n    #\n    # We use ETS for performance, to avoid working with nested maps.\n    table = :ets.new(__MODULE__, [:set, :private])\n\n    try do\n      for {{module, line}, cov} <- results, module in keep_set, line != 0 do\n        case cov do\n          {1, 0} -> :ets.insert(table, {{module, line}, true})\n          {0, 1} -> :ets.insert_new(table, {{module, line}, false})\n        end\n      end\n\n      module_results = for module <- keep, do: {read_cover_results(table, module), module}\n      {module_results, read_cover_results(table, :_)}\n    after\n      :ets.delete(table)\n    end\n  end\n\n  defp read_cover_results(table, module) do\n    covered = :ets.select_count(table, [{{{module, :_}, true}, [], [true]}])\n    not_covered = :ets.select_count(table, [{{{module, :_}, false}, [], [true]}])\n    percentage(covered, not_covered)\n  end\n\n  defp percentage(0, 0), do: 100.0\n  defp percentage(covered, not_covered), do: covered / (covered + not_covered) * 100\n\n  defp print_summary(results, totals, true), do: print_summary(results, totals, [])\n\n  defp print_summary(results, totals, opts) when is_list(opts) do\n    threshold = get_threshold(opts)\n\n    results =\n      results |> Enum.sort() |> Enum.map(fn {coverage, module} -> {coverage, inspect(module)} end)\n\n    name_max_length = results |> Enum.map(&String.length(elem(&1, 1))) |> Enum.max() |> max(10)\n    name_separator = String.duplicate(\"-\", name_max_length)\n\n    Mix.shell().info(\"| Percentage | #{String.pad_trailing(\"Module\", name_max_length)} |\")\n    Mix.shell().info(\"|------------|-#{name_separator}-|\")\n    Enum.each(results, &display(&1, threshold, name_max_length))\n    Mix.shell().info(\"|------------|-#{name_separator}-|\")\n    display({totals, \"Total\"}, threshold, name_max_length)\n    Mix.shell().info(\"\")\n  end\n\n  defp print_failed_threshold(totals, threshold) do\n    Mix.shell().info(\"Coverage test failed, threshold not met:\\n\")\n    Mix.shell().info(\"    Coverage:  #{format_number(totals, 6)}%\")\n    Mix.shell().info(\"    Threshold: #{format_number(threshold, 6)}%\")\n    Mix.shell().info(\"\")\n  end\n\n  defp display({percentage, name}, threshold, pad_length) do\n    Mix.shell().info([\n      \"| \",\n      color(percentage, threshold),\n      format_number(percentage, 9),\n      \"%\",\n      :reset,\n      \" | \",\n      String.pad_trailing(name, pad_length),\n      \" |\"\n    ])\n  end\n\n  defp color(percentage, true), do: color(percentage, @default_threshold)\n  defp color(_, false), do: \"\"\n  defp color(percentage, threshold) when percentage >= threshold, do: :green\n  defp color(_, _), do: :red\n\n  defp format_number(number, length) when is_integer(number),\n    do: format_number(number / 1, length)\n\n  defp format_number(number, length), do: :io_lib.format(\"~#{length}.2f\", [number])\n\n  defp get_threshold(true), do: @default_threshold\n  defp get_threshold(opts), do: Keyword.get(opts, :threshold, @default_threshold)\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/test.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Test do\n  use Mix.Task\n\n  alias Mix.Compilers.Test, as: CT\n\n  @compile {:no_warn_undefined, [IEx, ExUnit, ExUnit.Filters]}\n  @shortdoc \"Runs a project's tests\"\n  @recursive true\n\n  @moduledoc ~S\"\"\"\n  Runs the tests for a project.\n\n  This task starts the current application, loads up\n  `test/test_helper.exs` and then, requires all files matching the\n  `test/**/*_test.exs` pattern in parallel.\n\n  A list of files and/or directories can be given after the task\n  name in order to select the files to run:\n\n      $ mix test test/some/particular/file_test.exs\n      $ mix test test/some/particular/dir\n\n  Tests in umbrella projects can be run from the root by specifying\n  the full suite path, including `apps/my_app/test`, in which case\n  recursive tests for other child apps will be skipped completely:\n\n      # To run all tests for my_app from the umbrella root\n      $ mix test apps/my_app/test\n\n      # To run a given test file on my_app from the umbrella root\n      $ mix test apps/my_app/test/some/particular/file_test.exs\n\n  ## Understanding test results\n\n  When you run your test suite, it prints results as they run with\n  a summary at the end, as seen below:\n\n      $ mix test\n      Running ExUnit with seed: 646219, max_cases: 16\n      ...\n\n        1) test greets the world (FooTest)\n           test/foo_test.exs:5\n           Assertion with == failed\n           code:  assert Foo.hello() == :world!\n           left:  :world\n           right: :world!\n           stacktrace:\n             test/foo_test.exs:6: (test)\n\n      ........\n\n      Finished in 0.05 seconds (0.00s async, 0.05s sync)\n      1 doctest, 11 tests, 1 failure\n\n  For each test, the test suite will print a dot. Failed tests\n  are printed immediately in the format described in the next\n  section.\n\n  After all tests run, we print the suite summary. The first\n  line contains the total time spent on the suite, followed\n  by how much time was spent on async tests (defined with\n  `use ExUnit.Case, async: true`) vs sync ones:\n\n      Finished in 0.05 seconds (0.00s async, 0.05s sync)\n\n  Developers want to minimize the time spent on sync tests\n  whenever possible, as sync tests run serially and async\n  tests run concurrently.\n\n  Finally, how many tests we have run, how many of them\n  failed, how many were invalid, and so on.\n\n  ### Understanding test failures\n\n  First, it contains the failure counter, followed by the test\n  name and the module the test was defined:\n\n      1) test greets the world (FooTest)\n\n  The next line contains the exact location of the test in the\n  `FILE:LINE` format:\n\n      test/foo_test.exs:5\n\n  If you want to re-run only this test, all you need to do is to\n  copy the line above and paste it in front of `mix test`:\n\n      $ mix test test/foo_test.exs:5\n\n  Then we show the error message, code snippet, and general information\n  about the failed test:\n\n      Assertion with == failed\n      code:  assert Foo.hello() == :world!\n      left:  :world\n      right: :world!\n\n  If your terminal supports coloring (see the  \"Coloring\" section below),\n  a diff is typically shown between `left` and `right` sides. Finally,\n  we print the stacktrace of the failure:\n\n      stacktrace:\n        test/foo_test.exs:6: (test)\n\n  ## Command line options\n\n    * `--all-warnings` (`--no-all-warnings`) - prints all warnings, including previous compilations\n      (default is true except on errors)\n\n    * `-b`, `--breakpoints` *(since v1.17.0)* - sets a breakpoint at the beginning\n      of every test. The debugger goes line-by-line and can access all variables\n      and imports (but not local functions). You can press `n` for the next line\n      and `c` for the next test. This automatically sets `--trace`\n\n    * `--color` - enables color in ExUnit formatting results\n\n    * `--cover` - runs coverage tool. See \"Coverage\" section below\n\n    * `--dry-run` *(since v1.19.0)* - prints which tests would be run based on current options,\n      but does not actually run any tests. This combines with all other options\n      like `--stale`, `--only`, `--exclude`, and so on.\n\n    * `--exclude` - excludes tests that match the filter. This option may be given\n      several times to apply different filters, such as `--exclude ci --exclude slow`.\n      A value can also be provided for the filter such as `--exclude async:true` to only\n      run the sync tests.\n\n    * `--exit-status` - use an alternate exit status to use when the test suite\n      fails (default is 2).\n\n    * `--export-coverage` - the name of the file to export coverage results to.\n      Only has an effect when used with `--cover`\n\n    * `--failed` - runs only tests that failed the last time they ran\n\n    * `--force` - forces compilation regardless of modification times\n\n    * `--formatter` - sets the formatter module that will print the results.\n      Defaults to ExUnit's built-in CLI formatter\n\n    * `--include` - includes tests that match the filter. This option may be given\n      several times to apply different filters, such as `--include ci --include slow`\n\n    * `--listen-on-stdin` - runs tests, and then listens on stdin. It will\n      re-run tests once a newline is received. See the \"File system watchers\"\n      section below\n\n    * `--max-cases` - sets the maximum number of tests running asynchronously. Only tests from\n      different modules run in parallel. Defaults to twice the number of cores\n\n    * `--max-failures` - the suite stops evaluating tests when this number of test\n      failures is reached. It runs all tests if omitted\n\n    * `--max-requires` - sets the maximum number of test files to compile in parallel.\n      Setting this to `1` will compile test files sequentially.\n\n    * `-n`, `--name-pattern` *(since v1.19.0)* - only run tests with names that match\n      the given regular expression\n\n    * `--no-archives-check` - does not check archives\n\n    * `--no-color` - disables color in the output\n\n    * `--no-compile` - does not compile, even if files require compilation\n\n    * `--no-deps-check` - does not check dependencies\n\n    * `--no-elixir-version-check` - does not check the Elixir version from `mix.exs`\n\n    * `--no-start` - does not start applications after compilation\n\n    * `--only` - runs only tests that match the filter. Such as `--only ci`. A value\n      can also be provided for the filter such as `--only async:true` to only\n      run the async tests.\n\n    * `--partitions` - sets the amount of partitions to split tests in. It must be\n      a number greater than zero. If set to one, it acts a no-op. If more than one,\n      then you must also set the `MIX_TEST_PARTITION` environment variable with the\n      partition to use in the current test run. See the \"Operating system process\n      partitioning\" section for more information\n\n    * `--preload-modules` - preloads all modules defined in applications\n\n    * `--profile-require time` - profiles the time spent to require test files.\n      Used only for debugging. The test suite does not run\n\n    * `--raise` - immediately raises if the test suite fails, instead of continuing\n      the execution of other Mix tasks\n\n    * `--repeat-until-failure` *(since v1.17.0)* - sets the number of repetitions for running\n      the suite until it fails. This is useful for debugging flaky tests within the same instance\n      of the Erlang VM. For example, `--repeat-until-failure 10000` repeats the test suite\n      up to 10 000 times until the first failure. This can be combined with `--max-failures 1`\n      to immediately stop if one test fails. However, if there is any leftover global state\n      after running the tests, re-running the suite may trigger unrelated failures.\n\n    * `--seed` - seeds the random number generator used to randomize the order of tests;\n      `--seed 0` disables randomization so the tests in a single file will always be ran\n      in the same order they were defined in\n\n    * `--slowest` - prints timing information for the N slowest tests. Includes time spent in\n     `ExUnit.Callbacks.setup/1`. Automatically sets `--trace` and `--preload-modules`\n\n    * `--slowest-modules` *(since v1.17.0)* - prints timing information for the N slowest\n      modules. Includes time spent in `ExUnit.Callbacks.setup/1`. Automatically sets\n      `--trace` and `--preload-modules`\n\n    * `--stale` - runs only tests which reference modules that changed since the\n      last time tests were ran with `--stale`. You can read more about this option\n      in the \"The --stale option\" section below\n\n    * `--timeout` - sets the timeout for the tests\n\n    * `--trace` - runs tests with detailed reporting. Automatically sets `--max-cases` to `1`.\n      Note that in trace mode test timeouts will be ignored as timeout is set to `:infinity`\n\n    * `--warnings-as-errors` *(since v1.12.0)* - treats compilation warnings (from loading the\n      test suite) as errors and returns an exit status of 1 if the test suite would otherwise\n      pass. If the test suite fails and also include warnings as errors, the exit\n      status returned will be the value of the `--exit-status` option, which\n      defaults to `2`, plus one. Therefore in the default case, this will be exit status `3`.\n\n      Note that failures reported by `--warnings-as-errors` cannot be retried with the\n      `--failed` flag.\n\n      This option only applies to test files. To treat warnings as errors during compilation and\n      during tests, run:\n          MIX_ENV=test mix do compile --warnings-as-errors + test --warnings-as-errors\n\n  ## Configuration\n\n  These configurations can be set in the `def project` section of your `mix.exs`:\n\n    * `:test_coverage` - a set of options to be passed down to the coverage\n      mechanism. See the \"Coverage\" section for more information\n\n    * `:test_elixirc_options` - the compiler options to used when\n      loading/compiling test files. By default it disables the debug chunk,\n      docs chunk, and module type inference\n\n    * `:test_paths` - list of paths containing test files. Defaults to\n      `[\"test\"]` if the `test` directory exists, otherwise, it defaults to `[]`.\n      It is expected that all test paths contain a `test_helper.exs` file\n\n    * `:test_pattern` - a pattern to find potential test files. Defaults to `\"*.{ex,exs}\"`.\n\n      Once files are found, they are filtered in two ways:\n\n        * Files that match `:test_load_filters` are loaded\n        * Files that match `:test_ignore_filters` are ignored\n        * All other files emit a warning\n\n      In Elixir versions earlier than 1.19.0, this option defaulted to `*_test.exs`.\n\n    * `:test_load_filters` - a list of files, regular expressions or one-arity\n      functions to restrict which files matched by the `:test_pattern` are loaded.\n      Defaults to `[&String.ends_with?(&1, \"_test.exs\")]`. Paths are relative to\n      the project root and separated by `/`, even on Windows.\n\n    * `:test_ignore_filters` - a list of files, regular expressions or one-arity\n      functions to ignore by the loader. Any file that is not loaded and not\n      ignored will emit a warning.\n\n      Mix ignores files ending in `_helper.exs` by default, as well as any file\n      included in the project's `:elixirc_paths`.\n\n      For example, to ignore all files in a `test/support/` folder:\n\n          def project do\n            [\n              ...,\n              test_ignore_filters: [&String.starts_with?(&1, \"test/support/\")]\n            ]\n          end\n\n      You may choose to disable all warnings by ignoring all files with\n      `[fn _ -> true end]`.\n\n      Paths are relative to the project root and separated by `/`, even on Windows.\n\n  ## Coloring\n\n  Coloring is enabled by default on most Unix terminals. They are also\n  available on Windows consoles from Windows 10, although it must be\n  explicitly enabled for the current user in the registry by running\n  the following command:\n\n      $ reg add HKCU\\Console /v VirtualTerminalLevel /t REG_DWORD /d 1\n\n  After running the command above, you must restart your current console.\n\n  ## Tags and filters\n\n  ExUnit provides tags and filtering functionality that allow developers\n  to select which tests to run. The most common functionality is to exclude\n  some particular tests from running by default in your test helper file:\n\n      # Exclude all external tests from running\n      ExUnit.configure(exclude: [external: true])\n\n  Then, whenever desired, those tests could be included in the run via the\n  `--include` option:\n\n      $ mix test --include external:true\n\n  The example above will run all tests that have the external option set to\n  `true`. It is also possible to include all examples that have a given tag,\n  regardless of its value:\n\n      $ mix test --include external\n\n  Note that all tests are included by default, so unless they are excluded\n  first (either in the test helper or via the `--exclude` option) the\n  `--include` option has no effect. The order in which filters are applied\n  is also consistent: first all exclusions are computed, then the inclusions.\n\n  For convenience, Mix also provides an `--only` option that excludes all tests\n  and includes only the given ones:\n\n      $ mix test --only external\n\n  Which is similar to:\n\n      $ mix test --include external --exclude test\n\n  However, when the `--only` option is used and no tests run, the test run fails.\n\n  In case a single file is being tested, it is possible to pass one or more specific\n  line numbers to run only those given tests:\n\n      $ mix test test/some/particular/file_test.exs:12\n\n  Which is equivalent to:\n\n      $ mix test --exclude test --include line:12 test/some/particular/file_test.exs\n\n  Or:\n\n      $ mix test test/some/particular/file_test.exs:12:24\n\n  Which is equivalent to:\n\n      $ mix test --exclude test --include line:12 --include line:24 test/some/particular/file_test.exs\n\n  If a given line starts a `describe` block, that line filter includes all tests\n  within the describe. Otherwise, it runs the closest test on or before the given\n  line number.\n\n  ## Coverage\n\n  Elixir provides built-in line-based test coverage via the `--cover` flag.\n  The test coverages shows which lines of code and in which files were executed\n  during the test run.\n\n  ### Limitations\n\n  Elixir uses Erlang's [`:cover`](`:cover`) for its default test coverage.\n  Erlang coverage is done by tracking *executable lines of code*. See\n  `mix test.coverage` for details.\n\n  ### Configuration\n\n  The `:test_coverage` configures the coverage tool and the default tool\n  accepts the following options:\n\n    * `:tool` - a module specifying the coverage tool to use.\n      Defaults to `Mix.Tasks.Test.Coverage`.\n\n    * `:output` - the output directory for cover results.\n      Defaults to `\"cover\"`.\n\n    * `:summary` - at the end of each coverage run, a summary of each\n      module is printed, with results in red or green depending on whether\n      the percentage is below or above a given threshold. The task will\n      exit with status of 1 if the total coverage is below the threshold.\n      The `:summary` option allows you to customize the summary generation\n      and defaults to `[threshold: 90]`, but it may be set to `false` to\n      disable such reports.\n\n    * `:export` - a filename to export results to instead of generating\n      the coverage result on the fly. The `.coverdata` extension is\n      automatically added to the given file. This option is automatically\n      set via the `--export-coverage` option or when using process partitioning.\n      See `mix test.coverage` to compile a report from multiple exports.\n\n    * `:ignore_modules` - modules to ignore from generating reports and\n      in summaries. It is a list of module names as atoms and regular\n      expressions that are matched against the module names.\n\n    * `:local_only` - by default coverage only tracks local calls,\n      set this option to false if you plan to run coverage across nodes.\n\n  By default, a wrapper around OTP's `cover` is used as the coverage tool.\n  You can learn more about how it works in the docs for `mix test.coverage`.\n  Your tool of choice can be given as follows:\n\n      def project() do\n        [\n          ...\n          test_coverage: [tool: CoverModule]\n          ...\n        ]\n      end\n\n  `CoverModule` can be any module that exports `start/2`, receiving the\n  compilation path and the `test_coverage` options as arguments.\n  It must return either `nil` or an anonymous function of zero arity that\n  will run after the test suite is done.\n\n  ## Operating system process partitioning\n\n  While ExUnit supports the ability to run tests concurrently within the same\n  Elixir instance, it is not always possible to run all tests concurrently. For\n  example, some tests may rely on global resources.\n\n  For this reason, `mix test` supports partitioning the test files across\n  different Elixir instances. This is done by setting the `--partitions` option\n  to an integer, with the number of partitions, and setting the `MIX_TEST_PARTITION`\n  environment variable to control which test partition that particular instance\n  is running. This can also be useful if you want to distribute testing across\n  multiple machines.\n\n  For example, to split a test suite into 4 partitions and run them, you would\n  use the following commands:\n\n      $ MIX_TEST_PARTITION=1 mix test --partitions 4\n      $ MIX_TEST_PARTITION=2 mix test --partitions 4\n      $ MIX_TEST_PARTITION=3 mix test --partitions 4\n      $ MIX_TEST_PARTITION=4 mix test --partitions 4\n\n  The test files are sorted upfront in a round-robin fashion. Note the partition\n  itself is given as an environment variable so it can be accessed in config files\n  and test scripts. For example, it can be used to setup a different database instance\n  per partition in `config/test.exs`.\n\n  If partitioning is enabled and `--cover` is used, no cover reports are generated,\n  as they only contain a subset of the coverage data. Instead, the coverage data\n  is exported to files such as `cover/MIX_TEST_PARTITION.coverdata`. Once you have\n  the results of all partitions inside `cover/`, you can run `mix test.coverage` to\n  get the unified report.\n\n  ## The --stale option\n\n  The `--stale` command line option attempts to run only the test files which\n  reference modules that have changed since the last time you ran this task with\n  `--stale`.\n\n  The first time this task is run with `--stale`, all tests are run and a manifest\n  is generated. On subsequent runs, a test file is marked \"stale\" if any modules it\n  references (and any modules those modules reference, recursively) were modified\n  since the last run with `--stale`. A test file is also marked \"stale\" if it has\n  been changed since the last run with `--stale`.\n\n  The `--stale` option is extremely useful for software iteration, allowing you to\n  run only the relevant tests as you perform changes to the codebase.\n\n  ## File-system watchers\n\n  You can integrate `mix test` with file system watchers through the command line\n  via the `--listen-on-stdin` option. For example, you can use [fswatch](https://github.com/emcrisostomo/fswatch)\n  or similar to emit newlines whenever there is a change, which will cause your test\n  suite to re-run:\n\n      $ fswatch lib test | mix test --listen-on-stdin\n\n  This can be combined with the `--stale` option to re-run only the test files that\n  have changed as well as the tests that have gone stale due to changes in `lib`.\n\n  ## Aborting the suite\n\n  It is possible to abort the test suite with `Ctrl+\\ `, which sends a SIGQUIT\n  signal to the Erlang VM. ExUnit will intercept this signal to show all tests\n  that have been aborted and print the results collected so far.\n\n  This can be useful in case the suite gets stuck and you don't want to wait\n  until the timeout times passes (which defaults to 30 seconds).\n  \"\"\"\n\n  @switches [\n    all_warnings: :boolean,\n    breakpoints: :boolean,\n    force: :boolean,\n    color: :boolean,\n    cover: :boolean,\n    export_coverage: :string,\n    trace: :boolean,\n    max_cases: :integer,\n    max_failures: :integer,\n    max_requires: :integer,\n    include: :keep,\n    exclude: :keep,\n    seed: :integer,\n    name_pattern: :regex,\n    only: :keep,\n    compile: :boolean,\n    start: :boolean,\n    timeout: :integer,\n    raise: :boolean,\n    deps_check: :boolean,\n    archives_check: :boolean,\n    elixir_version_check: :boolean,\n    failed: :boolean,\n    stale: :boolean,\n    listen_on_stdin: :boolean,\n    formatter: :keep,\n    slowest: :integer,\n    slowest_modules: :integer,\n    partitions: :integer,\n    preload_modules: :boolean,\n    warnings_as_errors: :boolean,\n    profile_require: :string,\n    exit_status: :integer,\n    repeat_until_failure: :integer,\n    dry_run: :boolean\n  ]\n\n  @aliases [b: :breakpoints, n: :name_pattern]\n\n  @cover [output: \"cover\", tool: Mix.Tasks.Test.Coverage]\n\n  @impl true\n  def run(args) do\n    {opts, files} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)\n\n    if not Mix.Task.recursing?() do\n      do_run(opts, args, files)\n    else\n      parent_umbrella = Path.dirname(Mix.Project.parent_umbrella_project_file())\n\n      {files_in_apps_path, files_not_in_apps_path} =\n        files\n        |> Enum.map(&Path.expand(&1, parent_umbrella))\n        |> Enum.map(&Path.relative_to(&1, parent_umbrella))\n        |> Enum.split_with(&String.starts_with?(&1, \"apps/\"))\n\n      app = Mix.Project.config()[:app]\n      current_app_path = \"apps/#{app}/\"\n\n      files_in_current_app_path =\n        for file <- files_in_apps_path,\n            String.starts_with?(file, current_app_path) or not relative_app_file_exists?(file),\n            do: String.trim_leading(file, current_app_path)\n\n      files = files_in_current_app_path ++ files_not_in_apps_path\n\n      if files == [] and files_in_apps_path != [] do\n        :ok\n      else\n        do_run([test_location_relative_path: \"apps/#{app}\"] ++ opts, args, files)\n      end\n    end\n  end\n\n  defp relative_app_file_exists?(file) do\n    {[file], _} = ExUnit.Filters.parse_paths([file])\n    File.exists?(Path.join(\"../..\", file))\n  end\n\n  defp do_run(opts, args, files) do\n    _ = Mix.Project.get!()\n\n    if System.get_env(\"MIX_ENV\") == nil && Mix.env() != :test do\n      Mix.raise(\"\"\"\n      \"mix test\" is running in the \\\"#{Mix.env()}\\\" environment. If you are \\\n      running tests from within another command, you can either:\n\n        1. set MIX_ENV explicitly:\n\n            MIX_ENV=test mix test.another\n\n        2. set the :preferred_envs for \"def cli\" in your mix.exs:\n\n            def cli do\n              [preferred_envs: [\"test.another\": :test]]\n            end\n      \"\"\")\n    end\n\n    if opts[:listen_on_stdin] do\n      System.at_exit(fn _ ->\n        IO.gets(:stdio, \"\")\n        Mix.shell().info(\"Restarting...\")\n        System.restart()\n        Process.sleep(:infinity)\n      end)\n    end\n\n    # Load ExUnit before we compile anything in case we are compiling\n    # helper modules that depend on ExUnit.\n    Application.ensure_loaded(:ex_unit)\n\n    # --warnings-as-errors in test does not pass down to compile,\n    # if you need this, call compile explicitly before.\n    Mix.Task.run(\"compile\", args -- [\"--warnings-as-errors\"])\n\n    project = Mix.Project.config()\n\n    {partitions, opts} = Keyword.pop(opts, :partitions)\n    partitioned? = is_integer(partitions) and partitions > 1\n\n    # Start cover after we load deps but before we start the app.\n    cover =\n      if opts[:cover] do\n        compile_path = Mix.Project.compile_path(project)\n        partition = partitioned? && System.get_env(\"MIX_TEST_PARTITION\")\n\n        cover =\n          @cover\n          |> Keyword.put(:export, opts[:export_coverage] || partition)\n          |> Keyword.merge(project[:test_coverage] || [])\n\n        cover[:tool].start(compile_path, cover)\n      end\n\n    # Start the app and configure ExUnit with command line options\n    # before requiring test_helper.exs so that the configuration is\n    # available in test_helper.exs\n    Mix.shell().print_app()\n\n    app_start_args =\n      if opts[:slowest] || opts[:slowest_modules] do\n        [\"--preload-modules\" | args]\n      else\n        args\n      end\n\n    Mix.Task.run(\"app.start\", app_start_args)\n\n    # The test helper may change the Mix.shell(), so revert it whenever we raise and after suite\n    shell = Mix.shell()\n    test_elixirc_options = project[:test_elixirc_options] || []\n\n    {test_elixirc_options, opts} =\n      cond do\n        not Keyword.get(opts, :breakpoints, false) ->\n          {test_elixirc_options, opts}\n\n        IEx.started?() ->\n          {Keyword.put(test_elixirc_options, :debug_info, true), opts}\n\n        true ->\n          Mix.shell().error(\"you must run \\\"iex -S mix test\\\" when using -b/--breakpoints\")\n          {test_elixirc_options, Keyword.delete(opts, :breakpoints)}\n      end\n\n    # Configure ExUnit now and then again so the task options override test_helper.exs\n    {ex_unit_opts, allowed_files} = process_ex_unit_opts(opts)\n    ExUnit.configure(ex_unit_opts)\n\n    warnings_as_errors? = Keyword.get(opts, :warnings_as_errors, false)\n    exit_status = Keyword.fetch!(ex_unit_opts, :exit_status)\n\n    # Prepare and extract all files to require and run\n    test_paths = project[:test_paths] || default_test_paths()\n    test_pattern = project[:test_pattern] || \"*.{ex,exs}\"\n\n    # Warn of deprecated warn configuration\n    if project[:warn_test_pattern] do\n      Mix.shell().info(\"\"\"\n      warning: the `:warn_test_pattern` configuration is deprecated and will be ignored. \\\n      Use `:test_load_filters` and `:test_ignore_filters` instead.\n      \"\"\")\n    end\n\n    {test_files, test_opts} =\n      if files != [], do: ExUnit.Filters.parse_paths(files), else: {test_paths, []}\n\n    # get a list of all files in the test folders, which we filter by the test_load_filters\n    {potential_test_files, directly_included_test_files} = extract_files(test_files, test_pattern)\n\n    {load_files, _ignored_files, warn_files} =\n      classify_test_files(shell, potential_test_files, project)\n\n    # ensure that files given as direct argument to mix test are loaded,\n    # even if the test_load_filters don't match\n    load_files =\n      if files != [],\n        do: Enum.uniq(load_files ++ directly_included_test_files),\n        else: load_files\n\n    matched_test_files =\n      load_files\n      |> filter_to_allowed_files(allowed_files)\n      |> filter_by_partition(shell, partitions)\n\n    warn_files != [] && warn_misnamed_test_files(warn_files)\n\n    try do\n      helper_warned? = Enum.any?(test_paths, &require_test_helper(shell, &1))\n      # test_opts always wins because those are given via args\n      ExUnit.configure(ex_unit_opts |> merge_helper_opts() |> Keyword.merge(test_opts))\n\n      {CT.require_and_run(matched_test_files, test_paths, test_elixirc_options, opts),\n       helper_warned?}\n    catch\n      kind, reason ->\n        # Also mark the whole suite as failed\n        file = get_manifest_path(opts)\n        ExUnit.Filters.fail_all!(file)\n        :erlang.raise(kind, reason, __STACKTRACE__)\n    else\n      {{:ok, %{excluded: excluded, failures: failures, warnings?: warnings?, total: total}},\n       helper_warned?} ->\n        Mix.shell(shell)\n        cover && cover.()\n\n        cond do\n          warnings_as_errors? and (warnings? or helper_warned? or warn_files != []) and\n              failures == 0 ->\n            abort_due_to_warnings()\n\n          failures > 0 and opts[:raise] ->\n            raise_with_shell(shell, \"\\\"mix test\\\" failed\")\n\n          warnings_as_errors? and warnings? and failures > 0 ->\n            System.at_exit(fn _ ->\n              exit({:shutdown, exit_status + 1})\n            end)\n\n          failures > 0 ->\n            System.at_exit(fn _ ->\n              exit({:shutdown, exit_status})\n            end)\n\n          excluded == total and Keyword.has_key?(opts, :only) ->\n            nothing_executed(shell, \"--only\", opts)\n\n          excluded == total and Keyword.has_key?(opts, :name_pattern) ->\n            nothing_executed(shell, \"--name-pattern\", opts)\n\n          true ->\n            :ok\n        end\n\n      {:noop, _} ->\n        cond do\n          warnings_as_errors? and warn_files != [] ->\n            abort_due_to_warnings()\n\n          opts[:stale] ->\n            Mix.shell().info(\"No stale tests\")\n\n          opts[:failed] || files == [] ->\n            Mix.shell().info(\"There are no tests to run\")\n\n          true ->\n            message = \"Paths given to \\\"mix test\\\" did not match any directory/file: \"\n            raise_or_error_at_exit(shell, message <> Enum.join(files, \", \"), opts)\n        end\n\n        :ok\n    end\n  end\n\n  # similar to Mix.Utils.extract_files/2, but returns a list of directly included test files,\n  # that should be not filtered by the test_load_filters, e.g.\n  # mix test test/some_file.exs\n  defp extract_files(paths, pattern) do\n    {files, directly_included} =\n      for path <- paths, reduce: {[], []} do\n        {acc, directly_included} ->\n          case :elixir_utils.read_file_type(path) do\n            {:ok, :directory} ->\n              {[Path.wildcard(\"#{path}/**/#{pattern}\") | acc], directly_included}\n\n            {:ok, :regular} ->\n              {[path | acc], [path | directly_included]}\n\n            _ ->\n              {acc, directly_included}\n          end\n      end\n\n    files =\n      files\n      |> List.flatten()\n      |> Enum.uniq()\n\n    {files, directly_included}\n  end\n\n  defp abort_due_to_warnings() do\n    message =\n      \"\\nERROR! Test suite aborted after successful execution due to warnings while using the --warnings-as-errors option\"\n\n    IO.puts(:stderr, IO.ANSI.format([:red, message]))\n\n    System.at_exit(fn _ ->\n      exit({:shutdown, 1})\n    end)\n  end\n\n  defp raise_with_shell(shell, message) do\n    Mix.shell(shell)\n    Mix.raise(message)\n  end\n\n  defp nothing_executed(shell, option, opts) do\n    message = \"The #{option} option was given to \\\"mix test\\\" but no test was executed\"\n    raise_or_error_at_exit(shell, message, opts)\n  end\n\n  defp raise_or_error_at_exit(shell, message, opts) do\n    cond do\n      opts[:raise] ->\n        raise_with_shell(shell, message)\n\n      Mix.Task.recursing?() ->\n        Mix.shell().info(message)\n\n      true ->\n        Mix.shell().error(message)\n        System.at_exit(fn _ -> exit({:shutdown, 1}) end)\n    end\n  end\n\n  defp classify_test_files(shell, potential_test_files, project) do\n    test_load_filters = project[:test_load_filters] || [&String.ends_with?(&1, \"_test.exs\")]\n\n    test_ignore_filters = get_test_ignore_filters(shell, project)\n\n    {to_load, to_ignore, to_warn} =\n      for file <- potential_test_files, reduce: {[], [], []} do\n        {to_load, to_ignore, to_warn} ->\n          cond do\n            any_file_matches?(file, test_load_filters) ->\n              {[file | to_load], to_ignore, to_warn}\n\n            any_file_matches?(file, test_ignore_filters) ->\n              {to_load, [file | to_ignore], to_warn}\n\n            true ->\n              {to_load, to_ignore, [file | to_warn]}\n          end\n      end\n\n    # get the files back in the original order\n    {Enum.reverse(to_load), Enum.reverse(to_ignore), Enum.reverse(to_warn)}\n  end\n\n  defp get_test_ignore_filters(shell, project) do\n    elixirc_paths = project[:elixirc_paths] || []\n\n    case Keyword.get(project, :test_ignore_filters, []) do\n      list when is_list(list) ->\n        # ignore any _helper.exs files and files that are compiled (test support files)\n        [\n          &String.ends_with?(&1, \"_helper.exs\"),\n          fn file -> Enum.any?(elixirc_paths, &String.starts_with?(file, &1)) end\n        ] ++ list\n\n      other ->\n        raise_with_shell(\n          shell,\n          \"Invalid configuration for :test_ignore_filters, expected a list, got: #{inspect(other)}\"\n        )\n    end\n  end\n\n  defp any_file_matches?(file, filters) do\n    Enum.any?(filters, fn filter ->\n      case filter do\n        regex when is_struct(regex, Regex) ->\n          Regex.match?(regex, file)\n\n        binary when is_binary(binary) ->\n          file == binary\n\n        fun when is_function(fun, 1) ->\n          fun.(file)\n      end\n    end)\n  end\n\n  defp warn_misnamed_test_files(ignored) do\n    Mix.shell().info(\"\"\"\n    warning: the following files do not match any of the configured \\\n    `:test_load_filters` / `:test_ignore_filters`:\n\n    #{Enum.join(ignored, \"\\n\")}\n\n    This might indicate a typo in a test file name (for example, \\\n    using \"foo_tests.exs\" instead of \"foo_test.exs\").\n\n    See the configuration for `:test_pattern` under `mix help test` \\\n    for more information.\n    \"\"\")\n  end\n\n  @option_keys [\n    :breakpoints,\n    :trace,\n    :max_cases,\n    :max_failures,\n    :include,\n    :exclude,\n    :seed,\n    :timeout,\n    :formatters,\n    :colors,\n    :slowest,\n    :slowest_modules,\n    :failures_manifest_path,\n    :only_test_ids,\n    :test_location_relative_path,\n    :exit_status,\n    :repeat_until_failure,\n    :dry_run\n  ]\n\n  @doc false\n  def process_ex_unit_opts(opts) do\n    {opts, allowed_files} = manifest_opts(opts)\n\n    opts =\n      opts\n      |> filter_opts(:include)\n      |> filter_opts(:exclude)\n      |> filter_only_and_name_pattern()\n      |> formatter_opts()\n      |> color_opts()\n      |> exit_status_opts()\n      |> Keyword.take(@option_keys)\n      |> default_opts()\n\n    {opts, allowed_files}\n  end\n\n  defp merge_helper_opts(opts) do\n    # The only options that are additive from app env are the excludes\n    value = List.wrap(Application.get_env(:ex_unit, :exclude, []))\n\n    opts\n    |> Keyword.update(:exclude, value, &Enum.uniq(&1 ++ value))\n    |> Keyword.put_new_lazy(:failures_manifest_path, fn -> get_manifest_path([]) end)\n  end\n\n  defp default_opts(opts) do\n    # Set autorun to false because Mix automatically runs the test suite for us.\n    [autorun: false] ++ opts\n  end\n\n  defp parse_filters(opts, key) do\n    if Keyword.has_key?(opts, key) do\n      ExUnit.Filters.parse(Keyword.get_values(opts, key))\n    else\n      []\n    end\n  end\n\n  defp filter_only_and_name_pattern(opts) do\n    only = parse_filters(opts, :only)\n    name_patterns = opts |> Keyword.get_values(:name_pattern) |> Enum.map(&{:test, &1})\n\n    case only ++ name_patterns do\n      [] ->\n        opts\n\n      filters ->\n        opts\n        |> Keyword.update(:include, filters, &(filters ++ &1))\n        |> Keyword.update(:exclude, [:test], &[:test | &1])\n    end\n  end\n\n  defp filter_opts(opts, key) do\n    case parse_filters(opts, key) do\n      [] -> opts\n      filters -> Keyword.put(opts, key, filters)\n    end\n  end\n\n  defp formatter_opts(opts) do\n    if Keyword.has_key?(opts, :formatter) do\n      formatters =\n        opts\n        |> Keyword.get_values(:formatter)\n        |> Enum.map(&Module.concat([&1]))\n\n      Keyword.put(opts, :formatters, formatters)\n    else\n      opts\n    end\n  end\n\n  @manifest_file_name \".mix_test_failures\"\n\n  defp get_manifest_path(opts) do\n    opts[:failures_manifest_path] ||\n      Application.get_env(:ex_unit, :failures_manifest_path) ||\n      Path.join(Mix.Project.manifest_path(), @manifest_file_name)\n  end\n\n  defp manifest_opts(opts) do\n    manifest_file = get_manifest_path(opts)\n\n    if opts[:failed] do\n      if opts[:stale] do\n        Mix.raise(\"Combining --failed and --stale is not supported.\")\n      end\n\n      case ExUnit.Filters.failure_info(manifest_file) do\n        {allowed_files, failed_ids} ->\n          {Keyword.put(opts, :only_test_ids, failed_ids), allowed_files}\n\n        :all ->\n          {opts, nil}\n      end\n    else\n      {opts, nil}\n    end\n  end\n\n  defp filter_to_allowed_files(matched_test_files, nil), do: matched_test_files\n\n  defp filter_to_allowed_files(matched_test_files, %MapSet{} = allowed_files) do\n    Enum.filter(matched_test_files, &MapSet.member?(allowed_files, Path.expand(&1)))\n  end\n\n  defp filter_by_partition(files, _shell, total) when total in [nil, 1],\n    do: files\n\n  defp filter_by_partition(files, shell, total) when total > 1 do\n    partition = System.get_env(\"MIX_TEST_PARTITION\")\n\n    case partition && Integer.parse(partition) do\n      {partition, \"\"} when partition in 1..total//1 ->\n        partition = partition - 1\n\n        # We sort the files because Path.wildcard does not guarantee\n        # ordering, so different OSes could return a different order,\n        # meaning run across OSes on different partitions could run\n        # duplicate files.\n        for {file, index} <- Enum.with_index(Enum.sort(files)),\n            rem(index, total) == partition,\n            do: file\n\n      _ ->\n        raise_with_shell(\n          shell,\n          \"The MIX_TEST_PARTITION environment variable must be set to an integer between \" <>\n            \"1..#{total} when the --partitions option is set, got: #{inspect(partition)}\"\n        )\n    end\n  end\n\n  defp filter_by_partition(_files, shell, total) do\n    raise_with_shell(\n      shell,\n      \"--partitions : expected to be positive integer, got #{total}\"\n    )\n  end\n\n  defp color_opts(opts) do\n    case Keyword.fetch(opts, :color) do\n      {:ok, enabled?} ->\n        Keyword.put(opts, :colors, enabled: enabled?)\n\n      :error ->\n        opts\n    end\n  end\n\n  defp exit_status_opts(opts) do\n    Keyword.put_new(opts, :exit_status, 2)\n  end\n\n  defp require_test_helper(shell, dir) do\n    file = Path.join(dir, \"test_helper.exs\")\n\n    if File.exists?(file) do\n      {_result, warnings} = Code.with_diagnostics([log: true], fn -> Code.require_file(file) end)\n      warnings != []\n    else\n      raise_with_shell(\n        shell,\n        \"Cannot run tests because test helper file #{inspect(file)} does not exist\"\n      )\n    end\n  end\n\n  defp default_test_paths do\n    if File.dir?(\"test\") do\n      [\"test\"]\n    else\n      []\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/will_recompile.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.WillRecompile do\n  use Mix.Task\n  @moduledoc false\n\n  @doc \"\"\"\n  Annotates the current project will recompile.\n  \"\"\"\n  def run(_) do\n    config = Mix.Project.config()\n\n    # Slight reimplementation of `manifest_path` because we need to\n    # get manifests for root and children in umbrella case.\n    paths =\n      if Mix.Project.umbrella?(config) do\n        build = Mix.Project.build_path(config)\n\n        children =\n          Enum.map(Mix.Project.apps_paths(config), fn {app, _} ->\n            Path.join([build, \"lib\", Atom.to_string(app)])\n          end)\n\n        [build | children]\n      else\n        [Mix.Project.app_path(config)]\n      end\n\n    filename = Mix.ProjectStack.reset_config_mtime()\n\n    for path <- paths do\n      path = Path.join(path, \".mix\")\n      File.mkdir_p!(path)\n      File.touch!(Path.join(path, filename))\n    end\n\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks/xref.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.Tasks.Xref do\n  use Mix.Task\n\n  import Mix.Compilers.Elixir,\n    only: [read_manifest: 1, source: 1, source: 2, module: 1]\n\n  @shortdoc \"Prints cross reference information\"\n  @manifest \"compile.elixir\"\n\n  @moduledoc \"\"\"\n  Prints cross reference information between modules.\n\n  The `xref` task expects a mode as first argument:\n\n      $ mix xref MODE\n\n  All available modes are discussed below, after a brief\n  introduction to xref.\n\n  This task is automatically re-enabled, so you can print\n  information multiple times in the same Mix invocation.\n\n  ## A brief introduction to xref\n\n  The goal of `xref` is to analyze the dependencies between modules\n  and files. It is most commonly used to find problematic areas where\n  touching one file in a project causes a large subset of the project\n  to recompile. The most common cause of these problems are the so-called\n  \"compile-connected\" files. Those are files you depend on at compile-time\n  (for example, by invoking its macro or using it in the body of a module)\n  which also have their own dependencies.\n\n  The most harmful form of compile-connected dependencies are the ones\n  that are also in a cycle. Imagine you have files `lib/a.ex`, `lib/b.ex`,\n  and `lib/c.ex` with the following dependencies:\n\n      lib/a.ex\n      └── lib/b.ex (compile)\n            └── lib/c.ex\n                  └── lib/a.ex\n\n  Because you have a compile-time dependency, any of the files `lib/a.ex`,\n  `lib/b.ex`, and `lib/c.ex` depend on will cause `lib/a.ex` to recompile.\n  In other words, whenever you have a cycle, **a change to any file in the\n  cycle will cause all compile-time deps to recompile**. Therefore, your\n  first priority to reduce constant recompilations is to remove them.\n  You can spot them by running:\n\n      $ mix xref graph --format cycles --label compile-connected\n\n  > #### Use the --label option\n  >\n  > The job of `mix xref` is to explore relationships between files\n  > and it is expected that most of your files are either directly\n  > or indirectly connected. For this reason, it is strongly advised\n  > to pass the `--label` option to filter the amount of data,\n  > specifically with `compile-connected` (or `compile`) as values.\n\n  Whenever you find a compile-time dependency, such as `lib/a.ex` pointing\n  to `lib/b.ex`, there are two ways to remove them:\n\n    1. Run `mix xref trace lib/a.ex` to understand where and how `lib/a.ex`\n       depends on `lib/b.ex` at compile time and address it\n\n    2. Or run `mix xref trace lib/b.ex` and make sure it does not depend on\n       any other module in your project because a compile dependency makes\n       those runtime dependencies also compile time by transitivity\n\n  We outline all options for `mix xref trace` and the types of dependencies\n  over the following sections.\n\n  If you don't have compile cycles in your project, that's a good beginning,\n  but you want to avoid any compile-connected dependencies in general, as they\n  may become cycles in the future. To verify the general health of your project,\n  you may run:\n\n      $ mix xref graph --format stats --label compile-connected\n\n  This command will show general information about the project, but focus on\n  compile-connected dependencies. In the stats, you will see the following report:\n\n      Top 10 files with most incoming dependencies:\n        * lib/livebook_web.ex (97)\n        * lib/livebook/config.ex (3)\n        * proto/lib/livebook_proto/deployment_group.pb.ex (2)\n        * lib/livebook_web/plugs/memory_provider.ex (2)\n        * proto/lib/livebook_proto/user_connected.pb.ex (1)\n\n  You can see the first file, \"lib/livebook_web.ex\", is depended on by 97\n  other files and, because we are using compile-connected, it also means\n  that \"lib/livebook_web.ex\" itself has its own dependencies. We can find\n  which files depend on \"lib/livebook_web.ex\" at compile time like this:\n\n      $ mix xref graph --sink lib/livebook_web.ex --label compile --only-nodes\n\n  And you can find the files lib/livebook_web.ex depends on like this:\n\n      $ mix xref graph --source lib/livebook_web.ex --only-nodes\n\n  The trouble here is precisely that, if any of the files in the latter\n  command changes, all of the files in the first command will be recompiled,\n  because compile time dependencies are transitive. As we did with cycles,\n  you can use `mix xref trace` to understand why and how these dependencies\n  exist.\n\n  ### Dependency types\n\n  Elixir tracks three types of dependencies between modules: compile,\n  exports, and runtime. If a module has a compile time dependency on\n  another module, the caller module has to be recompiled whenever the\n  callee changes (or any dependency of the callee changes).\n  Let's see an example:\n\n      # lib/a.ex\n      defmodule A do\n        @hello B.hello()\n        def hello, do: @hello\n      end\n\n      # lib/b.ex\n      defmodule B do\n        def hello, do: \"hello\"\n        def world, do: C.world()\n      end\n\n      # lib/c.ex\n      defmodule C do\n        def world, do: \"world\"\n      end\n\n  If `C.world/0` changes, `B` is marked as stale. `B` does not need to\n  be recompiled, because it depends on `C` at runtime, but anything that\n  depends on `B` at compile-time has to recompile, and that includes `A`.\n\n  Compile-time dependencies are typically added when using macros or\n  when invoking functions in the module body (outside of functions).\n  This type of transitive compile-time dependencies, such as `A`\n  depending on `C` at compile-time through `B`, are called compile-connected.\n\n  Export dependencies are compile time dependencies on the module API,\n  namely structs and its public definitions. For example, if you import\n  a module but only use its functions, it is an export dependency. If\n  you use a struct, it is an export dependency too. Export dependencies\n  are only recompiled if the module API changes. Note, however, that compile\n  time dependencies have higher precedence than exports. Therefore if\n  you import a module and use its macros, it is a compile time dependency.\n\n  Runtime dependencies are added whenever you invoke another module\n  inside a function. Modules with runtime dependencies do not have\n  to be compiled when the callee changes, unless there is a transitive\n  compile or an outdated export time dependency between them.\n\n  Over the next sections, we will explain what which `mix xref` command\n  does in detail.\n\n  ## mix xref trace FILE\n\n  Compiles the given file listing all dependencies within the same app.\n  It includes the type and line for each one. Example:\n\n      $ mix xref trace lib/my_app/router.ex\n\n  The `--label` option may be given to keep only certain traces\n  (compile, runtime or export):\n\n      $ mix xref trace lib/my_app/router.ex --label compile\n\n  If you have an umbrella application, we also recommend using the\n  `--include-siblings` flag to see the dependencies from sibling\n  applications. The `trace` command is not currently supported at the\n  umbrella root.\n\n  ### Example\n\n  Imagine the given file lib/b.ex:\n\n      defmodule B do\n        import A\n        A.macro()\n        macro()\n        A.fun()\n        fun()\n        def calls_macro, do: A.macro()\n        def calls_fun, do: A.fun()\n        def calls_struct, do: %A{}\n      end\n\n  `mix xref trace` will print:\n\n      lib/b.ex:2: require A (export)\n      lib/b.ex:3: call A.macro/0 (compile)\n      lib/b.ex:4: import call A.macro/0 (compile)\n      lib/b.ex:5: call A.fun/0 (compile)\n      lib/b.ex:6: import call A.fun/0 (compile)\n      lib/b.ex:7: call A.macro/0 (compile)\n      lib/b.ex:8: call A.fun/0 (runtime)\n      lib/b.ex:9: struct A (export)\n\n  ## mix xref graph\n\n  Emits a file dependency graph where an edge from `A` to `B` indicates\n  that `A` (source) depends on `B` (sink).\n\n      $ mix xref graph --format stats\n\n  For any non-small project, the output of `mix xref graph` itself, without\n  any additional flags, is not useful: once your project grows, it is hard\n  to gather actionable feedback by looking at the graph as a whole. Instead,\n  `mix xref graph` is better used as a \"database\", which can help you answer\n  queries about your project.\n\n  The following options are accepted:\n\n    * `--exclude` - path to exclude. Can be repeated to exclude multiple paths.\n\n    * `--label` - only shows relationships with the given label.\n      The labels are \"compile-connected\", \"compile\", \"export\" and \"runtime\".\n      By default, the `--label` option does not change how the graph is computed,\n      it simply filters the printed graph to show only relationships with the given\n      label. However, you can pass `--only-direct` to trim the graph to only the\n      nodes that have the direct relationship given by label.\n\n    * `--group` - provide comma-separated paths to consider as a group. Dependencies\n      from and into multiple files of the group are considered a single dependency.\n      Dependencies between the group elements are ignored. This is useful when you\n      are computing compile and compile-connected dependencies and you want a\n      series of files to be treated as one. The group is printed using the first path,\n      with a `+` suffix. Can be repeated to create multiple groups.\n\n    * `--only-direct` - keeps only files with the direct relationship\n      given by `--label`\n\n    * `--only-nodes` - only shows the node names (no edges).\n      Generally useful with the `--sink` flag\n\n    * `--source` - displays all files that the given source file\n      references (directly or indirectly). Can be repeated to display\n      references from multiple sources.\n\n    * `--sink` - displays all files that reference the given file\n      (directly or indirectly). Can be repeated.\n\n    * `--min-cycle-size` - controls the minimum cycle size on formats\n      like `stats` and `cycles`\n\n    * `--min-cycle-label` - controls the minimum number of dependencies\n      with the given `--label` on a cycle\n\n    * `--format` - can be set to one of:\n\n      * `pretty` - prints the graph to the terminal using Unicode characters.\n        Each prints each file followed by the files it depends on. This is the\n        default except on Windows;\n\n      * `plain` - the same as pretty except ASCII characters are used instead of\n        Unicode characters. This is the default on Windows;\n\n      * `stats` - prints general statistics about the graph;\n\n      * `cycles` - prints all strongly connected cycles in the graph;\n\n      * `dot` - produces a DOT graph description, by default written to `xref_graph.dot`\n        in the current directory.  See the documentation for the `--output` option to\n        learn how to control where the file is written and other related details.\n\n      * `json` *(since v1.19.0)* - produces a JSON file, by default written to\n        `xref_graph.json` in the current directory.  See the documentation for the\n        `--output` option to learn how to control where the file is written and other\n        related details.\n\n        The JSON format is always a two level map of maps. The top level keys\n        specify source files, with their values containing maps whose keys specify\n        sink files and whose values specify the type of relationship, which will\n        be one of `compile`, `export` or `runtime`. Files which have no dependencies\n        will be present in the top level map, and will have empty maps for values.\n\n    * `--output` *(since v1.15.0)* - can be used to override the location of\n      the files created by the `dot` and `json` formats. It can be set to\n\n      * `-` - prints the output to standard output;\n\n      * a path - writes the output graph to the given path\n\n      If the output file already exists then it will be renamed in place\n      to have a `.bak` suffix, possibly overwriting any existing `.bak` file.\n      If this rename fails a fatal exception will be thrown.\n\n  The `--source` and `--sink` options are particularly useful when trying to understand\n  how the modules in a particular file interact with the whole system. You can combine\n  those options with `--label` and `--only-nodes` to get all files that exhibit a certain\n  property, for example:\n\n      # To show all compile-connected relationships\n      $ mix xref graph --label compile-connected\n\n      # To get the tree that depend on lib/foo.ex at compile time\n      $ mix xref graph --label compile --sink lib/foo.ex\n\n      # To get all files that depend on lib/foo.ex at compile time\n      $ mix xref graph --label compile --sink lib/foo.ex --only-nodes\n\n      # To get all paths between two files\n      $ mix xref graph --source lib/foo.ex --sink lib/bar.ex\n\n      # To show general statistics about the graph\n      $ mix xref graph --format stats\n\n      # To show all cycles with at least one compile-time dependency\n      $ mix xref graph --format cycles --label compile-connected\n\n  ### Understanding the printed graph\n\n  When `mix xref graph` runs, it will print a tree of the following\n  format. Imagine the following code:\n\n      # lib/a.ex\n      defmodule A do\n        IO.puts B.hello()\n      end\n\n      # lib/b.ex\n      defmodule B do\n        def hello, do: C.world()\n      end\n\n      # lib/c.ex\n      defmodule C do\n        def world, do: \"hello world\"\n      end\n\n  It will print:\n\n      $ mix xref graph\n      lib/a.ex\n      └── lib/b.ex (compile)\n      lib/b.ex\n      └── lib/c.ex\n      lib/c.ex\n\n  This tree means that `lib/a.ex` depends on `lib/b.ex` at compile\n  time. And `lib/b.ex` depends on `lib/c.ex` at runtime. This is often\n  problematic because if `lib/c.ex` changes, `lib/a.ex` also has to\n  recompile due to this indirect compile time dependency. When you pass\n  `--label compile`, the graph shows only the compile-time dependencies:\n\n      $ mix xref graph --label compile\n      lib/a.ex\n      └── lib/b.ex (compile)\n\n  The `--label compile` flag removes all non-compile dependencies. However,\n  this can be misleading because having direct compile time dependencies is\n  not necessarily an issue. The biggest concern are the transitive compile\n  time dependencies. You can get all compile time dependencies that cause\n  transitive compile time dependencies by using `--label compile-connected`:\n\n      $ mix xref graph --label compile-connected\n      lib/a.ex\n      └── lib/b.ex (compile)\n\n  The above says `lib/a.ex` depends on `lib/b.ex` and that causes transitive\n  compile time dependencies - as we know, `lib/a.ex` also depends on `lib/c.ex`.\n  We can retrieve those transitive dependencies by passing `lib/b.ex` as\n  `--source` to `mix xref graph`:\n\n      $ mix xref graph --source lib/b.ex\n      lib/b.ex\n      └── lib/c.ex\n\n  Similarly, you can use the `--label compile` and the `--sink` flag to find\n  all compile time dependencies that will recompile once the sink changes:\n\n      $ mix xref graph --label compile --sink lib/c.ex\n      lib/a.ex\n      └── lib/b.ex (compile)\n\n  If you have an umbrella application, we also recommend using the\n  `--include-siblings` flag to see the dependencies from sibling\n  applications. When invoked at the umbrella root, the `graph`\n  command will list all files from all umbrella children, without\n  any namespacing.\n\n  ### Understanding the printed cycle\n\n  If you run `mix xref graph --format cycles`, Elixir will print cycles\n  of shape:\n\n      Cycle of length 3:\n\n          lib/c.ex\n          lib/b.ex\n          lib/a.ex (compile)\n\n  More precisely, `xref` is printing the [strongly connected components](https://en.wikipedia.org/wiki/Strongly_connected_component)\n  in the dependency graph, which is (roughly speaking) the largest set of\n  files which are part of a dependency cycle involving these files.\n\n  For this reason, files may have multiple relationships between them, and\n  therefore the cycles are not printed in order. The label reflects the\n  highest type of relationship between the given file and any other file in\n  the cycle. In the example above, it means `lib/a.ex` depends on something\n  else in the cycle at compile-time.  Those are exactly the type of dependencies\n  we want to avoid, and you can ask `mix xref` to only print graphs with\n  with compile dependencies in them by passing the `--label` flag:\n\n      $ mix xref graph --format cycles --label compile-connected\n\n  ## Shared options\n\n  Those options are shared across all modes:\n\n    * `--fail-above` - generates a failure if the relevant metric is above the\n      given threshold. Applies to all modes except `mix xref graph --format stats`.\n\n    * `--include-siblings` - includes dependencies that have `:in_umbrella` set\n      to true in the current project in the reports. This can be used to find\n      callers or to analyze graphs between projects (it applies only to `trace`\n      subcommand)\n\n    * `--no-compile` - does not compile even if files require compilation\n\n    * `--no-deps-check` - does not check dependencies\n\n    * `--no-archives-check` - does not check archives\n\n    * `--no-elixir-version-check` - does not check the Elixir version from mix.exs\n\n  \"\"\"\n\n  @switches [\n    archives_check: :boolean,\n    compile: :boolean,\n    deps_check: :boolean,\n    elixir_version_check: :boolean,\n    exclude: :keep,\n    fail_above: :integer,\n    format: :string,\n    group: :keep,\n    include_siblings: :boolean,\n    label: :string,\n    only_nodes: :boolean,\n    only_direct: :boolean,\n    sink: :keep,\n    source: :keep,\n    min_cycle_size: :integer,\n    min_cycle_label: :integer,\n    output: :string\n  ]\n\n  @impl true\n  def run(args) do\n    Mix.Task.run(\"compile\", args)\n    Mix.Task.reenable(\"xref\")\n\n    {opts, args} = OptionParser.parse!(args, strict: @switches)\n\n    case args do\n      [\"callers\", module] ->\n        no_umbrella!(\"callers\")\n        handle_callers(module, opts)\n\n      [\"trace\", file] ->\n        no_umbrella!(\"trace\")\n        handle_trace(file, opts)\n\n      [\"graph\"] ->\n        handle_graph(opts)\n\n      # TODO: Remove on v2.0\n      [\"deprecated\"] ->\n        Mix.shell().error(\n          \"The deprecated check has been moved to the compiler and has no effect now\"\n        )\n\n      # TODO: Remove on v2.0\n      [\"unreachable\"] ->\n        Mix.shell().error(\n          \"The unreachable check has been moved to the compiler and has no effect now\"\n        )\n\n      _ ->\n        Mix.raise(\n          \"No argument was given to xref command. Run \\\"mix help xref\\\" for more information\"\n        )\n    end\n  end\n\n  defp no_umbrella!(task) do\n    if Mix.Project.umbrella?() do\n      Mix.raise(\n        \"mix xref #{task} is not supported in the umbrella root. Please run it inside the umbrella applications instead\"\n      )\n    end\n  end\n\n  @doc \"\"\"\n  Returns a list of information of all the runtime function calls in the project.\n\n  Each item in the list is a map with the following keys:\n\n    * `:callee` - a tuple containing the module, function, and arity of the call\n    * `:line` - an integer representing the line where the function is called\n    * `:file` - a binary representing the file where the function is called\n    * `:caller_module` - the module where the function is called\n\n  This function returns an empty list when used at the root of an umbrella\n  project because there is no compile manifest to extract the function call\n  information from. To get the function calls of each child in an umbrella,\n  execute the function at the root of each individual application.\n  \"\"\"\n  @deprecated \"Use compilation tracers described in the Code module\"\n  @spec calls(keyword()) :: [\n          %{\n            callee: {module(), atom(), arity()},\n            line: integer(),\n            file: String.t()\n          }\n        ]\n  def calls(opts \\\\ []) do\n    for manifest <- manifests(opts),\n        {source, source(modules: modules)} <- read_manifest(manifest) |> elem(1),\n        module <- modules,\n        call <- collect_calls(source, module),\n        do: call\n  end\n\n  defp collect_calls(source, module) do\n    with [_ | _] = path <- :code.which(module),\n         {:ok, {_, [debug_info: debug_info]}} <- :beam_lib.chunks(path, [:debug_info]),\n         {:debug_info_v1, backend, data} <- debug_info,\n         {:ok, %{definitions: defs}} <- backend.debug_info(:elixir_v1, module, data, []),\n         do: walk_definitions(module, source, defs),\n         else: (_ -> [])\n  end\n\n  defp walk_definitions(module, file, definitions) do\n    state = %{\n      file: file,\n      module: module,\n      calls: []\n    }\n\n    state = Enum.reduce(definitions, state, &walk_definition/2)\n    state.calls\n  end\n\n  defp walk_definition({_function, _kind, meta, clauses}, state) do\n    with_file_meta(state, meta, fn state ->\n      Enum.reduce(clauses, state, &walk_clause/2)\n    end)\n  end\n\n  defp with_file_meta(%{file: original_file} = state, meta, fun) do\n    case Keyword.fetch(meta, :file) do\n      {:ok, {meta_file, _}} ->\n        state = fun.(%{state | file: meta_file})\n        %{state | file: original_file}\n\n      :error ->\n        fun.(state)\n    end\n  end\n\n  defp walk_clause({_meta, args, _guards, body}, state) do\n    state = walk_expr(args, state)\n    walk_expr(body, state)\n  end\n\n  # &Mod.fun/arity\n  defp walk_expr({:&, meta, [{:/, _, [{{:., _, [module, fun]}, _, []}, arity]}]}, state)\n       when is_atom(module) and is_atom(fun) do\n    add_call(module, fun, arity, meta, state)\n  end\n\n  # Mod.fun(...)\n  defp walk_expr({{:., _, [module, fun]}, meta, args}, state)\n       when is_atom(module) and is_atom(fun) do\n    state = add_call(module, fun, length(args), meta, state)\n    walk_expr(args, state)\n  end\n\n  # %Module{...}\n  defp walk_expr({:%, meta, [module, {:%{}, _meta, args}]}, state)\n       when is_atom(module) and is_list(args) do\n    state = add_call(module, :__struct__, 0, meta, state)\n    walk_expr(args, state)\n  end\n\n  # Function call\n  defp walk_expr({left, _meta, right}, state) when is_list(right) do\n    state = walk_expr(right, state)\n    walk_expr(left, state)\n  end\n\n  # {x, y}\n  defp walk_expr({left, right}, state) do\n    state = walk_expr(right, state)\n    walk_expr(left, state)\n  end\n\n  # [...]\n  defp walk_expr(list, state) when is_list(list) do\n    Enum.reduce(list, state, &walk_expr/2)\n  end\n\n  defp walk_expr(_other, state) do\n    state\n  end\n\n  defp add_call(module, fun, arity, meta, state) do\n    call = %{\n      callee: {module, fun, arity},\n      caller_module: state.module,\n      file: state.file,\n      line: meta[:line]\n    }\n\n    %{state | calls: [call | state.calls]}\n  end\n\n  ## Modes\n\n  defp handle_callers(module, opts) do\n    module = parse_module(module)\n\n    file_callers =\n      for manifest <- manifests(opts),\n          {source_path, source_entry} <- read_manifest(manifest) |> elem(1),\n          reference = reference(module, source_entry),\n          do: {source_path, reference}\n\n    for {file, type} <- Enum.sort(file_callers) do\n      Mix.shell().info([file, \" (\", type, \")\"])\n    end\n\n    check_failure(:references, length(file_callers), opts[:fail_above])\n  end\n\n  defp handle_trace(file, opts) do\n    set =\n      for app <- apps(opts),\n          modules = Application.spec(app, :modules),\n          module <- modules,\n          into: MapSet.new(),\n          do: module\n\n    new = [ignore_already_consolidated: true, ignore_module_conflict: true, tracers: [__MODULE__]]\n    old = Code.compiler_options(new)\n    ets = :ets.new(__MODULE__, [:named_table, :duplicate_bag, :public])\n    :ets.insert(ets, [{:config, set, trace_label(opts[:label])}])\n\n    try do\n      Code.compile_file(file)\n    else\n      _ ->\n        :ets.delete(ets, :modules)\n\n        traces =\n          try do\n            print_traces(Enum.sort(:ets.lookup_element(__MODULE__, :entry, 2)))\n          rescue\n            _ -> []\n          end\n\n        check_failure(:traces, length(traces), opts[:fail_above])\n    after\n      :ets.delete(ets)\n      Code.compiler_options(old)\n    end\n  end\n\n  defp handle_graph(opts) do\n    label = label_filter(opts[:label])\n\n    {direct_filter, transitive_filter} =\n      if opts[:only_direct], do: {label, :all}, else: {:all, label}\n\n    write_graph(file_references(direct_filter, opts), transitive_filter, opts)\n  end\n\n  ## Callers\n\n  defp parse_module(module) do\n    case Mix.Utils.parse_mfa(module) do\n      {:ok, [module]} -> module\n      _ -> Mix.raise(\"xref callers MODULE expects a MODULE, got: \" <> module)\n    end\n  end\n\n  defp reference(module, source) do\n    cond do\n      module in source(source, :compile_references) -> \"compile\"\n      module in source(source, :export_references) -> \"export\"\n      module in source(source, :runtime_references) -> \"runtime\"\n      true -> nil\n    end\n  end\n\n  ## Trace\n\n  @doc false\n  def trace({:alias_reference, meta, module}, env) when env.module != module do\n    case env do\n      %{function: nil} -> add_trace(:compile, :alias, module, module, meta, env)\n      %{context: nil} -> add_trace(:runtime, :alias, module, module, meta, env)\n      %{} -> :ok\n    end\n  end\n\n  def trace({:require, meta, module, _opts}, env),\n    do: add_trace(require_mode(meta), :require, module, module, meta, env)\n\n  def trace({:struct_expansion, meta, module, _keys}, env),\n    do: add_trace(struct_mode(meta, env), :struct, module, module, meta, env)\n\n  def trace({:remote_function, meta, module, function, arity}, env),\n    do: add_trace(mode(env), :call, module, {module, function, arity}, meta, env)\n\n  def trace({:remote_macro, meta, module, function, arity}, env),\n    do: add_trace(:compile, :call, module, {module, function, arity}, meta, env)\n\n  def trace({:imported_function, meta, module, function, arity}, env),\n    do: add_trace(mode(env), :import, module, {module, function, arity}, meta, env)\n\n  def trace({:imported_macro, meta, module, function, arity}, env),\n    do: add_trace(:compile, :import, module, {module, function, arity}, meta, env)\n\n  def trace(_event, _env),\n    do: :ok\n\n  defp require_mode(meta), do: if(meta[:from_macro], do: :compile, else: :export)\n\n  defp struct_mode(meta, %{function: function}) do\n    if function != nil and meta[:operation] in [:match, :update] do\n      :runtime\n    else\n      :export\n    end\n  end\n\n  defp mode(%{function: nil}), do: :compile\n  defp mode(_), do: :runtime\n\n  defp add_trace(mode, type, module, module_or_mfa, meta, env) do\n    [{:config, modules, label}] = :ets.lookup(__MODULE__, :config)\n\n    if module in modules and (label == nil or mode == label) do\n      line = meta[:line] || env.line\n      :ets.insert(__MODULE__, {:entry, {env.file, line, module_or_mfa, mode, type}})\n    end\n\n    :ok\n  end\n\n  defp print_traces(entries) do\n    # We don't want to show aliases if there is an entry of the same type\n    non_aliases =\n      for {_file, _line, module_or_mfa, mode, type} <- entries,\n          type != :alias,\n          into: %{},\n          do: {{trace_module(module_or_mfa), mode}, []}\n\n    shell = Mix.shell()\n\n    for {file, line, module_or_mfa, mode, type} <- entries,\n        type != :alias or not Map.has_key?(non_aliases, {module_or_mfa, mode}) do\n      shell.info([\n        Exception.format_file_line(Path.relative_to_cwd(file), line),\n        ?\\s,\n        trace_type(type),\n        ?\\s,\n        format_module_or_mfa(module_or_mfa),\n        \" (#{mode})\"\n      ])\n\n      :ok\n    end\n  end\n\n  defp trace_type(:import), do: \"import call\"\n  defp trace_type(other), do: Atom.to_string(other)\n\n  defp trace_label(nil), do: nil\n  defp trace_label(\"compile\"), do: :compile\n  defp trace_label(\"export\"), do: :export\n  defp trace_label(\"runtime\"), do: :runtime\n  defp trace_label(other), do: Mix.raise(\"Unknown --label #{other} in mix xref trace\")\n\n  defp trace_module({m, _, _}), do: m\n  defp trace_module(m), do: m\n\n  defp format_module_or_mfa({m, f, a}), do: Exception.format_mfa(m, f, a)\n  defp format_module_or_mfa(m), do: inspect(m)\n\n  ## Graph\n\n  defp merge_groups(file_references, comma_separated_groups) do\n    for group_paths <- comma_separated_groups,\n        reduce: {file_references, %{}} do\n      {file_references, aliases} ->\n        group_paths\n        |> String.split(\",\", trim: true)\n        |> check_files(file_references, :group)\n        |> group(file_references, aliases)\n    end\n  end\n\n  @type_order %{\n    compile: 0,\n    export: 1,\n    nil: 2\n  }\n\n  # Group the given paths.\n  # In graph theory vocabulary, this is done by vertex identification\n  # and removal of edges between contracting vertices.\n  defp group(paths, file_references, aliases) do\n    group_name = hd(paths) <> \"+\"\n    aliases = paths |> Map.new(&{&1, group_name}) |> Map.merge(aliases)\n\n    # Merge the references *from* the paths to group\n    {from_group, file_references} = Map.split(file_references, paths)\n\n    file_references =\n      Map.put(file_references, group_name, merge_references_from_group(from_group))\n\n    # Remap the references *to* the merged group\n    file_references =\n      Map.new(file_references, fn {file, references} ->\n        {file, remap_references_to_group(references, aliases, group_name)}\n      end)\n\n    # Remove the resulting reference from the merged group to itself, if there is one\n    file_references = Map.update!(file_references, group_name, &List.keydelete(&1, group_name, 0))\n\n    {file_references, aliases}\n  end\n\n  # Calculate the references from the merged group by concatenating all the references\n  # from its components; in case of duplicates keep the one with the most important type.\n  defp merge_references_from_group(file_references_to_merge) do\n    file_references_to_merge\n    |> Map.values()\n    |> Enum.concat()\n    |> Enum.sort_by(fn {_ref, type} -> @type_order[type] end)\n    |> Enum.uniq_by(fn {ref, _type} -> ref end)\n    |> Enum.sort()\n  end\n\n  defp remap_references_to_group(references, aliases, group_name) do\n    case Enum.split_with(references, fn {ref, _type} -> Map.has_key?(aliases, ref) end) do\n      {[], _all_references} ->\n        references\n\n      {refs_to_merge, other_refs} ->\n        type =\n          refs_to_merge\n          |> Enum.map(fn {_ref, type} -> type end)\n          |> Enum.min_by(&@type_order[&1])\n\n        Enum.sort([{group_name, type} | other_refs])\n    end\n  end\n\n  defp exclude(file_references, nil), do: file_references\n\n  defp exclude(file_references, excluded) do\n    excluded_set = MapSet.new(excluded)\n\n    file_references\n    |> Map.drop(excluded)\n    |> Map.new(fn {key, list} ->\n      {key, Enum.reject(list, fn {ref, _kind} -> MapSet.member?(excluded_set, ref) end)}\n    end)\n  end\n\n  defp label_filter(nil), do: :all\n  defp label_filter(\"compile\"), do: :compile\n  defp label_filter(\"export\"), do: :export\n  defp label_filter(\"runtime\"), do: nil\n  defp label_filter(\"compile-connected\"), do: :compile_connected\n  defp label_filter(other), do: Mix.raise(\"Unknown --label #{other} in mix xref graph\")\n\n  defp file_references(:compile_connected, _opts) do\n    Mix.raise(\"Cannot use --only-direct with --label=compile-connected\")\n  end\n\n  defp file_references(filter, opts) do\n    module_sources_list =\n      for manifest_path <- manifests(opts),\n          {manifest_modules, manifest_sources} = read_manifest(manifest_path),\n          {module, module(sources: sources)} <- manifest_modules,\n          source_path <- sources,\n          source_entry = manifest_sources[source_path],\n          do: {module, {source_path, source_entry}}\n\n    module_sources = Map.new(module_sources_list)\n\n    Map.new(module_sources_list, fn {current, {file, source_entry}} ->\n      source(\n        runtime_references: runtime,\n        export_references: exports,\n        compile_references: compile\n      ) = source_entry\n\n      compile_references =\n        modules_to_nodes(compile, :compile, current, file, module_sources, filter)\n\n      export_references =\n        modules_to_nodes(exports, :export, current, file, module_sources, filter)\n\n      runtime_references =\n        modules_to_nodes(runtime, nil, current, file, module_sources, filter)\n\n      references =\n        runtime_references\n        |> Map.merge(export_references)\n        |> Map.merge(compile_references)\n        |> Enum.to_list()\n\n      {file, references}\n    end)\n  end\n\n  defp modules_to_nodes(_, label, _, _, _, filter) when filter != :all and label != filter do\n    %{}\n  end\n\n  defp modules_to_nodes(modules, label, current, file, module_sources, _filter) do\n    for module <- modules,\n        module != current,\n        {source_path, _source_entry} <- [module_sources[module]],\n        file != source_path,\n        do: {source_path, label},\n        into: %{}\n  end\n\n  @humanize_option %{\n    group: \"Group files\",\n    source: \"Sources\",\n    sink: \"Sinks\",\n    exclude: \"Excluded files\"\n  }\n\n  defp get_files(what, opts, file_references, aliases) do\n    files =\n      for file <- Keyword.get_values(opts, what) do\n        Map.get(aliases, file, file)\n      end\n\n    check_files(files, file_references, what)\n  end\n\n  defp check_files(files, file_references, what) do\n    case files -- Map.keys(file_references) do\n      [_ | _] = missing ->\n        Mix.raise(\"#{@humanize_option[what]} could not be found: #{Enum.join(missing, \", \")}\")\n\n      _ ->\n        :ok\n    end\n\n    if files == [], do: nil, else: files\n  end\n\n  defp write_graph(all_references, filter, opts) do\n    {all_references, aliases} = merge_groups(all_references, Keyword.get_values(opts, :group))\n\n    all_references =\n      exclude(all_references, get_files(:exclude, opts, all_references, aliases))\n\n    sources = get_files(:source, opts, all_references, aliases)\n    sinks = get_files(:sink, opts, all_references, aliases)\n\n    file_references =\n      cond do\n        sinks -> sink_tree(all_references, sinks)\n        sources -> source_tree(all_references, sources)\n        true -> all_references\n      end\n\n    {found, count} =\n      case opts[:format] do\n        \"dot\" ->\n          {roots, callback, count} =\n            roots_and_callback(file_references, filter, sources, sinks, opts)\n\n          file_spec =\n            Mix.Utils.write_dot_graph!(\n              \"xref_graph.dot\",\n              \"xref graph\",\n              Enum.sort(roots),\n              callback,\n              opts\n            )\n\n          if file_spec != \"-\" do\n            png_file_spec = (file_spec |> Path.rootname() |> Path.basename()) <> \".png\"\n\n            \"\"\"\n            Generated \"#{Path.relative_to_cwd(file_spec)}\". To generate a PNG:\n\n               dot -Tpng #{inspect(file_spec)} -o #{inspect(png_file_spec)}\n\n            For more options see https://www.graphviz.org/.\n            \"\"\"\n            |> String.trim_trailing()\n            |> Mix.shell().info()\n          end\n\n          {:references, count}\n\n        \"stats\" ->\n          print_stats(file_references, filter, opts)\n          {:stats, 0}\n\n        \"cycles\" ->\n          {:cycles, print_cycles(file_references, filter, opts)}\n\n        \"json\" ->\n          {roots, callback, count} =\n            roots_and_callback(file_references, filter, sources, sinks, opts)\n\n          file_spec =\n            Mix.Utils.write_json_tree!(\"xref_graph.json\", Enum.sort(roots), callback, opts)\n\n          if file_spec != \"-\" do\n            Mix.shell().info(\"Generated \\\"#{file_spec}\\\".\")\n          end\n\n          {:references, count}\n\n        other when other in [nil, \"plain\", \"pretty\"] ->\n          {roots, callback, count} =\n            roots_and_callback(file_references, filter, sources, sinks, opts)\n\n          Mix.Utils.print_tree(Enum.sort(roots), callback, opts)\n\n          if sources do\n            # We compute the tree again in case sinks are also given\n            file_references = source_tree(all_references, sources)\n            print_sources_cycles(file_references, sources, opts)\n          end\n\n          {:references, count}\n\n        other ->\n          Mix.raise(\"Unknown --format #{other} in mix xref graph\")\n      end\n\n    check_failure(found, count, opts[:fail_above])\n  end\n\n  defp source_tree(file_references, keys) do\n    keys\n    |> Enum.reduce({%{}, %{}}, fn key, {acc, seen} ->\n      source_tree(file_references, key, acc, seen)\n    end)\n    |> elem(0)\n  end\n\n  defp source_tree(file_references, key, acc, seen) do\n    nodes = file_references[key]\n\n    if is_nil(nodes) or Map.has_key?(seen, key) do\n      {acc, seen}\n    else\n      acc = Map.put(acc, key, nodes)\n      seen = Map.put(seen, key, true)\n\n      Enum.reduce(nodes, {acc, seen}, fn {key, _type}, {acc, seen} ->\n        source_tree(file_references, key, acc, seen)\n      end)\n    end\n  end\n\n  defp sink_tree(file_references, keys) do\n    file_references\n    |> invert_references()\n    |> source_tree(keys)\n    |> invert_references()\n  end\n\n  defp invert_references(file_references) do\n    Enum.reduce(file_references, %{}, fn {file, references}, acc ->\n      Enum.reduce(references, acc, fn {file_reference, type}, acc ->\n        Map.update(acc, file_reference, [{file, type}], &[{file, type} | &1])\n      end)\n    end)\n  end\n\n  defp roots_and_callback(file_references, filter, sources, sinks, opts) do\n    # Filter according to non direct label\n    file_references = transitive_filter(file_references, filter)\n\n    # If a label is given, remove empty root nodes\n    file_references =\n      if opts[:label] do\n        for {_, [_ | _]} = pair <- file_references, into: %{}, do: pair\n      else\n        file_references\n      end\n\n    roots =\n      if sources do\n        Enum.map(sources, &{&1, nil})\n      else\n        file_references\n        |> Map.drop(sinks || [])\n        |> Enum.map(&{elem(&1, 0), nil})\n      end\n\n    callback = fn {file, type} ->\n      children = if opts[:only_nodes], do: [], else: Map.get(file_references, file, [])\n      type = type && \"(#{type})\"\n      {{file, type}, Enum.sort(children)}\n    end\n\n    {roots, callback, count_references(file_references)}\n  end\n\n  defp count_references(file_references) do\n    Enum.reduce(file_references, 0, fn {_, refs}, total -> total + length(refs) end)\n  end\n\n  defp transitive_filter_fn(file_references, :compile_connected),\n    do: fn {key, type} ->\n      type == :compile and match?([_ | _], file_references[key] || [])\n    end\n\n  defp transitive_filter_fn(_file_references, filter),\n    do: fn {_key, type} -> type == filter end\n\n  defp transitive_filter(file_references, :all), do: file_references\n\n  defp transitive_filter(file_references, filter) do\n    filter_fn = transitive_filter_fn(file_references, filter)\n\n    for {key, children} <- file_references,\n        into: %{},\n        do: {key, Enum.filter(children, filter_fn)}\n  end\n\n  defp print_stats(references, filter, opts) do\n    with_digraph(references, fn graph ->\n      shell = Mix.shell()\n\n      counters =\n        Enum.reduce(references, %{compile: 0, export: 0, nil: 0}, fn {_, deps}, acc ->\n          Enum.reduce(deps, acc, fn {_, value}, acc ->\n            Map.update!(acc, value, &(&1 + 1))\n          end)\n        end)\n\n      shell.info(\"Tracked files: #{map_size(references)} (nodes)\")\n      shell.info(\"Compile dependencies: #{counters.compile} (edges)\")\n      shell.info(\"Exports dependencies: #{counters.export} (edges)\")\n      shell.info(\"Runtime dependencies: #{counters.nil} (edges)\")\n      shell.info(\"Cycles: #{length(cycles(graph, filter, opts))}\")\n\n      outgoing =\n        references\n        |> Enum.map(fn {file, _} -> {out_stats_filter(references, graph, file, filter), file} end)\n        |> Enum.sort(:desc)\n        |> Enum.take(10)\n\n      shell.info(\"\\nTop #{length(outgoing)} files with most outgoing dependencies:\")\n      for {count, file} <- outgoing, do: shell.info(\"  * #{file} (#{count})\")\n\n      incoming =\n        references\n        |> Enum.map(fn {file, _} -> {in_stats_filter(references, graph, file, filter), file} end)\n        |> Enum.sort(:desc)\n        |> Enum.take(10)\n\n      shell.info(\"\\nTop #{length(incoming)} files with most incoming dependencies:\")\n      for {count, file} <- incoming, do: shell.info(\"  * #{file} (#{count})\")\n    end)\n  end\n\n  defp out_stats_filter(_references, graph, file, :all), do: :digraph.out_degree(graph, file)\n\n  defp out_stats_filter(references, graph, file, filter) do\n    filter_fn = transitive_filter_fn(references, filter)\n\n    graph\n    |> :digraph.out_neighbours(file)\n    |> Enum.count(fn v ->\n      {_edge, _v1, _v2, label} = :digraph.edge(graph, {file, v})\n      filter_fn.({file, label})\n    end)\n  end\n\n  defp in_stats_filter(_references, graph, file, :all), do: :digraph.in_degree(graph, file)\n\n  defp in_stats_filter(references, graph, file, filter) do\n    filter_fn = transitive_filter_fn(references, filter)\n\n    graph\n    |> :digraph.in_neighbours(file)\n    |> Enum.count(fn v ->\n      {_edge, _v1, _v2, label} = :digraph.edge(graph, {v, file})\n      filter_fn.({file, label})\n    end)\n  end\n\n  defp with_digraph(references, callback) do\n    graph = :digraph.new()\n\n    try do\n      for {file, _} <- references do\n        :digraph.add_vertex(graph, file)\n      end\n\n      for {file, deps} <- references, {dep, label} <- deps do\n        :digraph.add_edge(graph, {file, dep}, file, dep, label)\n      end\n\n      callback.(graph)\n    after\n      :digraph.delete(graph)\n    end\n  end\n\n  defp cycles(graph, filter, opts) do\n    # Vertices order in cyclic_strong_components/1 return is arbitrary and changes between\n    # OTP versions, sorting is necessary to make the output stable across versions.\n    cycles =\n      graph\n      |> :digraph_utils.cyclic_strong_components()\n      |> Enum.map(&{length(&1), add_labels(&1, graph)})\n\n    cycles =\n      if min = opts[:min_cycle_size] do\n        Enum.filter(cycles, &(elem(&1, 0) >= min))\n      else\n        cycles\n      end\n\n    min_cycle_label =\n      if integer = opts[:min_cycle_label] do\n        if filter == :all do\n          Mix.raise(\"--min-cycle-label requires the --label option to be given\")\n        end\n\n        if integer <= 0 do\n          Mix.raise(\"--min-cycle-label must be greater than 0\")\n        end\n\n        integer\n      else\n        1\n      end\n\n    # :compile_connected is the same as :compile\n    if cycle_fn = cycle_filter_fn(filter) do\n      Enum.filter(cycles, fn {_length, cycle} ->\n        Enum.count_until(cycle, cycle_fn, min_cycle_label) == min_cycle_label\n      end)\n    else\n      cycles\n    end\n  end\n\n  # In cycles, a compile connected is compile\n  defp cycle_filter_fn(:all), do: nil\n  defp cycle_filter_fn(:compile_connected), do: cycle_filter_fn(:compile)\n  defp cycle_filter_fn(filter), do: fn {_node, type} -> type == filter end\n\n  defp add_labels(vertices, graph) do\n    set = MapSet.new(vertices)\n\n    vertices\n    |> Enum.map(fn v ->\n      {v,\n       graph\n       |> :digraph.out_neighbours(v)\n       |> cycle_label(set, graph, v, false)}\n    end)\n    |> Enum.sort()\n  end\n\n  defp cycle_label([out | outs], set, graph, v, export?) do\n    case out in set && :digraph.edge(graph, {v, out}) do\n      {_, _, _, :compile} -> :compile\n      {_, _, _, :export} -> cycle_label(outs, set, graph, v, true)\n      _ -> cycle_label(outs, set, graph, v, export?)\n    end\n  end\n\n  defp cycle_label([], _set, _graph, _v, export?) do\n    if export?, do: :export, else: nil\n  end\n\n  defp print_cycles(references, filter, opts) do\n    with_digraph(references, fn graph ->\n      shell = Mix.shell()\n\n      case graph |> cycles(filter, opts) |> Enum.sort(:desc) do\n        [] ->\n          shell.info(\"No cycles found\")\n          0\n\n        cycles ->\n          shell.info(\"#{length(cycles)} cycles found. Showing them in decreasing size:\\n\")\n\n          for {length, cycle} <- cycles do\n            meta =\n              cycle\n              |> Enum.reduce({0, 0}, fn\n                {_, :compile}, {compile, export} -> {compile + 1, export}\n                {_, :export}, {compile, export} -> {compile, export + 1}\n                {_, _}, {compile, export} -> {compile, export}\n              end)\n              |> case do\n                {0, 0} ->\n                  \"\"\n\n                {compile, export} ->\n                  info =\n                    if(compile > 0, do: [\"#{compile} compile\"], else: []) ++\n                      if(export > 0, do: [\"#{export} export\"], else: [])\n\n                  \" (\" <> Enum.join(info, \", \") <> \")\"\n              end\n\n            shell.info(\"Cycle of length #{length}#{meta}:\\n\")\n\n            for {node, type} <- cycle do\n              shell.info(\n                case type do\n                  :compile -> [:red, \"    #{node} (compile)\"]\n                  :export -> \"    #{node} (export)\"\n                  _ -> \"    #{node}\"\n                end\n              )\n            end\n\n            shell.info(\"\")\n          end\n\n          length(cycles)\n      end\n    end)\n  end\n\n  defp print_sources_cycles(references, sources, opts) do\n    with_digraph(references, fn graph ->\n      shell = Mix.shell()\n\n      graph\n      |> cycles(:compile, opts)\n      |> Enum.sort(:desc)\n      |> Enum.each(fn {length, cycle} ->\n        if source = Enum.find(sources, &List.keymember?(cycle, &1, 0)) do\n          shell.info(\"\"\"\n\n          WARNING: Source #{source} is part of a cycle of #{length} nodes \\\n          and this cycle has a compile dependency. Therefore source and the \\\n          whole cycle will recompile whenever any of the files they depend \\\n          on change. Run \"mix xref graph --format stats --label compile-connected\" \\\n          to print compilation cycles and \"mix help xref\" for information on \\\n          removing them\\\n          \"\"\")\n        end\n      end)\n    end)\n  end\n\n  ## Helpers\n\n  defp apps(opts) do\n    siblings =\n      if opts[:include_siblings] do\n        for %{scm: Mix.SCM.Path, opts: opts, app: app} <- Mix.Dep.cached(),\n            opts[:in_umbrella],\n            do: app\n      else\n        []\n      end\n\n    [Mix.Project.config()[:app] | siblings]\n  end\n\n  defp manifests(opts) do\n    siblings =\n      cond do\n        Mix.Project.umbrella?() ->\n          for %{opts: opts} <- Mix.Dep.Umbrella.cached(),\n              do: Path.join([opts[:build], \".mix\", @manifest])\n\n        opts[:include_siblings] ->\n          for %{scm: Mix.SCM.Path, opts: opts} <- Mix.Dep.cached(),\n              opts[:in_umbrella],\n              do: Path.join([opts[:build], \".mix\", @manifest])\n\n        true ->\n          []\n      end\n\n    [Path.join(Mix.Project.manifest_path(), @manifest) | siblings]\n  end\n\n  defp check_failure(found, count, max_count)\n       when not is_nil(max_count) and count > max_count do\n    Mix.raise(\"Too many #{found} (found: #{count}, permitted: #{max_count})\")\n  end\n\n  defp check_failure(_, _, _) do\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/tasks_server.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.TasksServer do\n  @moduledoc false\n  @name __MODULE__\n\n  use Agent\n\n  def start_link(_opts) do\n    Agent.start_link(\n      fn -> :ets.new(@name, [:public, :set, :named_table]) end,\n      name: @name\n    )\n  end\n\n  def run(tuple) do\n    :ets.insert_new(@name, {tuple})\n  end\n\n  def put(tuple) do\n    :ets.insert(@name, {tuple})\n    :ok\n  end\n\n  def get(tuple) do\n    :ets.member(@name, tuple)\n  end\n\n  def delete_many(many) do\n    Enum.each(many, &:ets.delete(@name, &1))\n  end\n\n  def clear() do\n    :ets.delete_all_objects(@name)\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix/utils.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# NOTE: As this is a utils file it should not contain hard coded files\n# everything should be parameterized.\n\ndefmodule Mix.Utils do\n  @moduledoc false\n\n  # For bootstrapping purposes\n  @compile {:no_warn_undefined, Logger}\n\n  @doc \"\"\"\n  Returns the apps of a project with no filtering.\n\n  `compile.all` calls it to extract all compile-time apps.\n  `compile.app` calls it to extract all runtime apps.\n  \"\"\"\n  def project_apps(properties, config, extra, deps_loader) do\n    apps = Keyword.get(properties, :applications) || deps_loader.(deps_opts(config))\n    {all, required, optional} = split_by_type(extra ++ apps)\n    all = Enum.uniq(language_apps(config) ++ Enum.reverse(all))\n    optional = Enum.uniq(Enum.reverse(optional -- required))\n    {all, optional}\n  end\n\n  defp split_by_type(apps) do\n    Enum.reduce(apps, {[], [], []}, fn\n      app, {all, required, optional} when is_atom(app) ->\n        {[app | all], [app | required], optional}\n\n      {app, :required}, {all, required, optional} ->\n        {[app | all], [app | required], optional}\n\n      {app, :optional}, {all, required, optional} ->\n        {[app | all], required, [app | optional]}\n    end)\n  end\n\n  defp language_apps(config) do\n    case Keyword.get(config, :language, :elixir) do\n      :elixir -> [:kernel, :stdlib, :elixir]\n      :erlang -> [:kernel, :stdlib]\n    end\n  end\n\n  defp deps_opts(config) do\n    for config_dep <- Keyword.get(config, :deps, []),\n        do: {elem(config_dep, 0), dep_opts(config_dep)}\n  end\n\n  defp dep_opts({_app, opts}) when is_list(opts), do: opts\n  defp dep_opts({_app, _req, opts}) when is_list(opts), do: opts\n  defp dep_opts(_), do: []\n\n  @doc \"\"\"\n  Gets the Mix home.\n\n  It uses the locations `MIX_HOME`, `XDG_DATA_HOME/mix`,\n  `~/.mix` with decreasing priority.\n\n  Developers should only store entries in the\n  `MIX_HOME` directory which are guaranteed to\n  work across multiple Elixir versions, as it is\n  not recommended to swap the `MIX_HOME` directory\n  as configuration and other important data may be\n  stored there.\n  \"\"\"\n  def mix_home do\n    mix_home_xdg_lookup(:user_data)\n  end\n\n  @doc \"\"\"\n  Gets possible location of global Mix configuration.\n\n  Possible locations:\n\n     * `MIX_HOME`\n     * `XDG_CONFIG_HOME/mix` (if `MIX_XDG` is set)\n     * `~/.mix`\n\n  \"\"\"\n  def mix_config do\n    mix_home_xdg_lookup(:user_config)\n  end\n\n  @doc \"\"\"\n  Gets possible location of Mix cache.\n\n  Possible locations:\n\n   * `XDG_CACHE_HOME/mix` (if `MIX_XDG` is set)\n   * `:filename.basedir(:user_cache, \"mix\")`\n\n  \"\"\"\n  def mix_cache do\n    if System.get_env(\"MIX_XDG\") in [\"1\", \"true\"] do\n      # XDG lookups are only done for linux OS\n      :filename.basedir(:user_cache, \"mix\", %{os: :linux})\n    else\n      :filename.basedir(:user_cache, \"mix\")\n    end\n  end\n\n  defp mix_home_xdg_lookup(xdg) do\n    cond do\n      dir = System.get_env(\"MIX_HOME\") ->\n        dir\n\n      System.get_env(\"MIX_XDG\") in [\"1\", \"true\"] ->\n        :filename.basedir(xdg, \"mix\", %{os: :linux})\n\n      true ->\n        Path.expand(\"~/.mix\")\n    end\n  end\n\n  @doc \"\"\"\n  Parses a string into module, function and arity.\n\n  It returns `{:ok, mfa_list}`, where a `mfa_list` is\n  `[module, function, arity]`, `[module, function]` or `[module]`,\n  or the atom `:error`.\n\n      iex> Mix.Utils.parse_mfa(\"Foo.bar/1\")\n      {:ok, [Foo, :bar, 1]}\n      iex> Mix.Utils.parse_mfa(\":foo.bar/1\")\n      {:ok, [:foo, :bar, 1]}\n      iex> Mix.Utils.parse_mfa(\":foo.bar\")\n      {:ok, [:foo, :bar]}\n      iex> Mix.Utils.parse_mfa(\":foo\")\n      {:ok, [:foo]}\n      iex> Mix.Utils.parse_mfa(\"Foo\")\n      {:ok, [Foo]}\n\n      iex> Mix.Utils.parse_mfa(\"Foo.\")\n      :error\n      iex> Mix.Utils.parse_mfa(\"Foo.bar.baz\")\n      :error\n      iex> Mix.Utils.parse_mfa(\"Foo.bar/2/2\")\n      :error\n\n  \"\"\"\n  def parse_mfa(mfa) do\n    with {:ok, quoted} <- Code.string_to_quoted(mfa),\n         [_ | _] = mfa_list <- quoted_to_mfa(quoted) do\n      {:ok, mfa_list}\n    else\n      _ -> :error\n    end\n  end\n\n  defp quoted_to_mfa({:/, _, [dispatch, arity]}) when is_integer(arity) do\n    quoted_to_mf(dispatch, [arity])\n  end\n\n  defp quoted_to_mfa(dispatch) do\n    quoted_to_mf(dispatch, [])\n  end\n\n  defp quoted_to_mf({{:., _, [module, fun]}, _, []}, acc) when is_atom(fun) do\n    quoted_to_m(module, [fun | acc])\n  end\n\n  defp quoted_to_mf(module, acc) do\n    quoted_to_m(module, acc)\n  end\n\n  defp quoted_to_m({:__aliases__, _, aliases}, acc) do\n    [Module.concat(aliases) | acc]\n  end\n\n  defp quoted_to_m(atom, acc) when is_atom(atom) do\n    [atom | acc]\n  end\n\n  defp quoted_to_m(_, _acc) do\n    []\n  end\n\n  @doc \"\"\"\n  Takes a `command` name and attempts to load a module\n  with the command name converted to a module name\n  in the given `at` scope.\n\n  Returns `{:module, module}` in case a module\n  exists and is loaded, `{:error, reason}` otherwise.\n\n  ## Examples\n\n      iex> Mix.Utils.command_to_module(\"compile\", Mix.Tasks)\n      {:module, Mix.Tasks.Compile}\n\n  \"\"\"\n  def command_to_module(command, at \\\\ Elixir) do\n    module = Module.concat(at, command_to_module_name(command))\n    Code.ensure_loaded(module)\n  end\n\n  @doc \"\"\"\n  Returns `true` if any of the `sources` are stale\n  compared to the given `targets`.\n  \"\"\"\n  def stale?(sources, targets) do\n    Enum.any?(stale_stream(sources, targets))\n  end\n\n  @doc \"\"\"\n  Extracts all stale `sources` compared to the given `targets`.\n  \"\"\"\n  def extract_stale(_sources, []), do: []\n  def extract_stale([], _targets), do: []\n\n  def extract_stale(sources, targets) do\n    stale_stream(sources, targets) |> Enum.to_list()\n  end\n\n  defp stale_stream(sources, []) do\n    sources\n  end\n\n  defp stale_stream(sources, targets) do\n    modified_target = targets |> Enum.map(&last_modified/1) |> Enum.min()\n\n    Stream.filter(sources, fn source ->\n      last_modified(source) > modified_target\n    end)\n  end\n\n  @doc \"\"\"\n  Returns the date the given path was last modified in posix time.\n\n  If the path does not exist, it returns the Unix epoch\n  (1970-01-01 00:00:00).\n  \"\"\"\n  def last_modified(path)\n\n  def last_modified(timestamp) when is_integer(timestamp) do\n    timestamp\n  end\n\n  def last_modified(path) do\n    {mtime, _size} = last_modified_and_size(path)\n    mtime\n  end\n\n  @doc \"\"\"\n  Returns the date the given path was last modified in posix time\n  and the size.\n\n  If the path does not exist, it returns the Unix epoch\n  (1970-01-01 00:00:00).\n  \"\"\"\n  def last_modified_and_size(path) do\n    now = System.os_time(:second)\n\n    case :elixir_utils.read_posix_mtime_and_size(path) do\n      {:ok, mtime, size} when mtime > now ->\n        message =\n          \"warning: mtime (modified time) for #{inspect(path)} was set to the future, resetting to now\"\n\n        Mix.shell().error(message)\n        File.touch(path, now)\n        {mtime, size}\n\n      {:ok, mtime, size} ->\n        {mtime, size}\n\n      {:error, _} ->\n        {0, 0}\n    end\n  end\n\n  @doc \"\"\"\n  Prints n files are being compiled with the given extension.\n  \"\"\"\n  def compiling_n(0, _ext), do: :ok\n  def compiling_n(1, ext), do: Mix.shell().info(\"Compiling 1 file (.#{ext})\")\n  def compiling_n(n, ext), do: Mix.shell().info(\"Compiling #{n} files (.#{ext})\")\n\n  @doc \"\"\"\n  Extracts files from a list of paths.\n\n  `exts_or_pattern` may be a list of extensions or a\n  `Path.wildcard/1` pattern.\n\n  If the path in `paths` is a file, it is included in\n  the return result. If it is a directory, it is searched\n  recursively for files with the given extensions or matching\n  the given patterns.\n  \"\"\"\n  def extract_files(paths, exts_or_pattern)\n\n  def extract_files(paths, exts) when is_list(exts) do\n    extract_files(paths, \"*.{#{Enum.join(exts, \",\")}}\")\n  end\n\n  def extract_files(paths, pattern) do\n    Enum.flat_map(paths, fn path ->\n      case :elixir_utils.read_file_type(path) do\n        {:ok, :directory} -> Path.wildcard(\"#{path}/**/#{pattern}\")\n        {:ok, :regular} -> [path]\n        _ -> []\n      end\n    end)\n    |> Enum.uniq()\n  end\n\n  @doc \"\"\"\n  Handles writing the contents to either STDOUT or to a file, as specified\n  by the :output keyword in opts, defaulting to the provided default_file_spec.\n\n  If the resolved file specification is \"-\" then the contents is written to STDOUT,\n  otherwise if the file already exists it is renamed with a \".bak\" suffix before\n  the contents is written.  The underlying IO operations will throw an exception\n  if there is an error.\n\n  Returns the name of the file written to, or \"-\" if the output was to STDOUT.\n  This function is made public mostly for testing.\n  \"\"\"\n  @spec write_according_to_opts!(Path.t(), iodata(), write_opts) :: Path.t()\n  def write_according_to_opts!(default_file_spec, contents, opts) do\n    file_spec = Keyword.get(opts, :output, default_file_spec)\n\n    if file_spec == \"-\" do\n      IO.write(contents)\n    else\n      if File.exists?(file_spec) do\n        new_file_spec = \"#{file_spec}.bak\"\n        File.rename!(file_spec, new_file_spec)\n      end\n\n      File.write!(file_spec, contents)\n    end\n\n    # return the file_spec just in case the caller has a use for it.\n    file_spec\n  end\n\n  @doc \"\"\"\n  Outputs the given tree according to the callback as a two level\n  map of maps in JSON format.\n\n  The callback will be invoked for each node and it\n  must return a `{printed, children}` tuple.\n\n  If the `:output` option is `-` then prints to standard output,\n  see write_according_to_opts!/3 for details.\n  \"\"\"\n  @spec write_json_tree!(Path.t(), [node], (node -> {formatted_node, [node]}), write_opts) ::\n          Path.t()\n        when node: term()\n  def write_json_tree!(default_file_spec, nodes, callback, opts \\\\ []) do\n    src_map = build_json_tree(_src_map = %{}, nodes, callback)\n    write_according_to_opts!(default_file_spec, JSON.encode_to_iodata!(src_map), opts)\n  end\n\n  defp build_json_tree(src_map, [], _callback), do: src_map\n\n  defp build_json_tree(src_map, nodes, callback) do\n    Enum.reduce(nodes, src_map, fn node, src_map ->\n      {{name, _}, children} = callback.(node)\n\n      if Map.has_key?(src_map, name) do\n        src_map\n      else\n        sink_map =\n          Enum.reduce(children, %{}, fn {name, info}, sink_map ->\n            info = if info == nil, do: \"runtime\", else: Atom.to_string(info)\n            Map.put(sink_map, name, info)\n          end)\n\n        Map.put(src_map, name, sink_map)\n        |> build_json_tree(children, callback)\n      end\n    end)\n  end\n\n  @type formatted_node :: {name :: String.Chars.t(), edge_info :: String.Chars.t()}\n\n  @typedoc \"\"\"\n  Options for `write_according_to_opts!/3`, `write_json_tree!/4`, and `write_dot_graph!/5`.\n  \"\"\"\n  @type write_opts :: [\n          output: String.t()\n        ]\n\n  @typedoc \"\"\"\n  Options for `print_tree/3`.\n  \"\"\"\n  @type print_tree_opts :: [\n          format: String.t()\n        ]\n\n  @typedoc \"\"\"\n  Options for `read_path/2`.\n  \"\"\"\n  @type read_path_opts :: [\n          timeout: pos_integer(),\n          sha512: String.t()\n        ]\n\n  @doc \"\"\"\n  Prints the given tree according to the callback.\n\n  The callback will be invoked for each node and it\n  must return a `{printed, children}` tuple.\n  \"\"\"\n  @spec print_tree([node], (node -> {formatted_node, [node]}), print_tree_opts) :: :ok\n        when node: term()\n  def print_tree(nodes, callback, opts \\\\ []) do\n    pretty? =\n      case Keyword.get(opts, :format) do\n        \"pretty\" -> true\n        \"plain\" -> false\n        _other -> elem(:os.type(), 0) != :win32\n      end\n\n    print_tree(nodes, _depth = [], _seen = %{}, pretty?, callback)\n    :ok\n  end\n\n  defp print_tree(nodes, depth, seen, pretty?, callback) do\n    # We perform a breadth first traversal so we always show a dependency\n    # a node with its children as high as possible in tree. This helps avoid\n    # very deep trees.\n    {nodes, seen} =\n      Enum.flat_map_reduce(nodes, seen, fn node, seen ->\n        {{name, info}, children} = callback.(node)\n\n        if Map.has_key?(seen, name) do\n          {[{name, info, []}], seen}\n        else\n          {[{name, info, children}], Map.put(seen, name, true)}\n        end\n      end)\n\n    print_each_node(nodes, depth, seen, pretty?, callback)\n  end\n\n  defp print_each_node([], _depth, seen, _pretty?, _callback) do\n    seen\n  end\n\n  defp print_each_node([{name, info, children} | nodes], depth, seen, pretty?, callback) do\n    info = if(info, do: \" #{info}\", else: \"\")\n    Mix.shell().info(\"#{depth(pretty?, depth)}#{prefix(pretty?, depth, nodes)}#{name}#{info}\")\n\n    seen = print_tree(children, [nodes != [] | depth], seen, pretty?, callback)\n    print_each_node(nodes, depth, seen, pretty?, callback)\n  end\n\n  defp depth(_pretty?, []), do: \"\"\n  defp depth(pretty?, depth), do: Enum.reverse(depth) |> tl() |> Enum.map(&entry(pretty?, &1))\n\n  defp entry(false, true), do: \"|   \"\n  defp entry(false, false), do: \"    \"\n  defp entry(true, true), do: \"│   \"\n  defp entry(true, false), do: \"    \"\n\n  defp prefix(false, [], _), do: \"\"\n  defp prefix(false, _, []), do: \"`-- \"\n  defp prefix(false, _, _), do: \"|-- \"\n  defp prefix(true, [], _), do: \"\"\n  defp prefix(true, _, []), do: \"└── \"\n  defp prefix(true, _, _), do: \"├── \"\n\n  @doc \"\"\"\n  Outputs the given tree according to the callback as a DOT graph.\n\n  The callback will be invoked for each node and it\n  must return a `{printed, children}` tuple.\n\n  If the `:output` option is `-` then prints to standard output,\n  see write_according_to_opts!/3 for details.\n  \"\"\"\n  @spec write_dot_graph!(\n          Path.t(),\n          String.t(),\n          [node],\n          (node -> {formatted_node, [node]}),\n          write_opts\n        ) :: Path.t()\n        when node: term()\n  def write_dot_graph!(default_file_spec, title, nodes, callback, opts \\\\ []) do\n    {dot, _} = build_dot_graph(make_ref(), nodes, MapSet.new(), callback)\n    contents = [\"digraph \", quoted(title), \" {\\n\", dot, \"}\\n\"]\n    write_according_to_opts!(default_file_spec, contents, opts)\n  end\n\n  defp build_dot_graph(_parent, [], seen, _callback), do: {[], seen}\n\n  defp build_dot_graph(parent, [node | nodes], seen, callback) do\n    {{name, edge_info}, children} = callback.(node)\n    key = {parent, name}\n\n    if MapSet.member?(seen, key) do\n      {[], seen}\n    else\n      seen = MapSet.put(seen, key)\n      current = build_dot_current(parent, name, edge_info)\n      {children, seen} = build_dot_graph(name, children, seen, callback)\n      {siblings, seen} = build_dot_graph(parent, nodes, seen, callback)\n      {[current, children | siblings], seen}\n    end\n  end\n\n  defp build_dot_current(parent, name, edge_info) do\n    edge_info =\n      if edge_info do\n        [\" [label=\", quoted(edge_info), \"]\"]\n      else\n        []\n      end\n\n    parent =\n      if is_reference(parent) do\n        []\n      else\n        [quoted(parent), \" -> \"]\n      end\n\n    [\"  \", parent, quoted(name), edge_info, ?\\n]\n  end\n\n  defp quoted(data) do\n    string = to_string(data)\n    escape_dot_string(string, <<?\">>)\n  end\n\n  # Escape a string for DOT format according to GraphViz specification https://graphviz.org/doc/info/lang.html\n  # - Only quotes need escaping\n  # - The ending quote should not be escaped (which requires an even of trailing backslashes)\n  defp escape_dot_string(<<?\\\\, ?\\\\, rest::binary>>, acc) do\n    escape_dot_string(rest, <<acc::binary, ?\\\\, ?\\\\>>)\n  end\n\n  defp escape_dot_string(<<?\", rest::binary>>, acc) do\n    escape_dot_string(rest, <<acc::binary, ?\\\\, ?\">>)\n  end\n\n  defp escape_dot_string(<<?\\\\>>, acc) do\n    <<acc::binary, ?\\\\, ?\\\\, ?\">>\n  end\n\n  defp escape_dot_string(<<char, rest::binary>>, acc) do\n    escape_dot_string(rest, <<acc::binary, char>>)\n  end\n\n  defp escape_dot_string(<<>>, acc) do\n    <<acc::binary, ?\">>\n  end\n\n  @doc false\n  @deprecated \"Use Macro.underscore/1 instead\"\n  def underscore(value) do\n    Macro.underscore(value)\n  end\n\n  @doc false\n  @deprecated \"Use Macro.camelize/1 instead\"\n  def camelize(value) do\n    Macro.camelize(value)\n  end\n\n  @doc \"\"\"\n  Takes a module and converts it to a command.\n\n  The nesting argument can be given in order to remove\n  the nesting of a module.\n\n  ## Examples\n\n      iex> Mix.Utils.module_name_to_command(Mix.Tasks.Compile, 2)\n      \"compile\"\n\n      iex> Mix.Utils.module_name_to_command(\"Mix.Tasks.Compile.Elixir\", 2)\n      \"compile.elixir\"\n\n  \"\"\"\n  def module_name_to_command(module, nesting \\\\ 0)\n\n  def module_name_to_command(module, nesting) when is_atom(module) do\n    module_name_to_command(inspect(module), nesting)\n  end\n\n  def module_name_to_command(module, nesting) do\n    module\n    |> to_string()\n    |> String.split(\".\")\n    |> Enum.drop(nesting)\n    |> Enum.map_join(\".\", &Macro.underscore/1)\n  end\n\n  @doc \"\"\"\n  Takes a command and converts it to the module name format.\n\n  ## Examples\n\n      iex> Mix.Utils.command_to_module_name(\"compile.elixir\")\n      \"Compile.Elixir\"\n\n  \"\"\"\n  def command_to_module_name(command) do\n    command\n    |> to_string()\n    |> String.split(\".\")\n    |> Enum.map_join(\".\", &Macro.camelize/1)\n  end\n\n  @deprecated \"Use symlink_or_copy/2\"\n  def symlink_or_copy(hard_copy?, source, target) do\n    if hard_copy? do\n      if File.exists?(source) do\n        File.rm_rf!(target)\n        File.cp_r!(source, target)\n      end\n    else\n      symlink_or_copy(source, target)\n    end\n  end\n\n  @doc \"\"\"\n  Symlinks directory `source` to `target` or copies it recursively\n  in case symlink fails.\n\n  In case of conflicts, it copies files only if they have been\n  recently touched.\n\n  Expects source and target to be absolute paths as it generates\n  a relative symlink.\n  \"\"\"\n  def symlink_or_copy(path, path) do\n    :ok\n  end\n\n  def symlink_or_copy(source, target) do\n    if File.exists?(source) do\n      # Relative symbolic links on Windows are broken\n      link =\n        case :os.type() do\n          {:win32, _} -> source\n          # We are needing the relative path to the parent dir since we are doing\n          # a symlink\n          _ -> Path.relative_to(source, Path.dirname(target), force: true)\n        end\n\n      case File.read_link(target) do\n        {:ok, ^link} ->\n          :ok\n\n        {:ok, _} ->\n          case File.rm(target) do\n            :ok ->\n              :ok\n\n            {:error, reason} ->\n              reason = IO.iodata_to_binary(:file.format_error(reason))\n\n              Mix.raise(\"\"\"\n              Cannot remove symlink #{inspect(target)} due to reason: #{reason}\"\n\n                * Make sure you have permission to access the _build directory\n                  (you may have the wrong permission if you change users or ran as admin)\n\n                * If you are using Windows, avoid using substitute drives,\n                  as they don't play well with symlinks\n\n                * In case the issue continues, consider removing the _build directory\n              \"\"\")\n          end\n\n          do_symlink_or_copy(source, target, link)\n\n        {:error, :enoent} ->\n          do_symlink_or_copy(source, target, link)\n\n        {:error, _} ->\n          if not File.dir?(target) do\n            File.rm_rf!(target)\n          end\n\n          do_symlink_or_copy(source, target, link)\n      end\n    else\n      {:error, :enoent}\n    end\n  end\n\n  defp do_symlink_or_copy(source, target, link) do\n    case File.ln_s(link, target) do\n      :ok ->\n        :ok\n\n      {:error, _} ->\n        files =\n          File.cp_r!(source, target,\n            on_conflict: fn orig, dest ->\n              {orig_mtime, orig_size} = last_modified_and_size(orig)\n              {dest_mtime, dest_size} = last_modified_and_size(dest)\n              orig_mtime > dest_mtime or orig_size != dest_size\n            end\n          )\n\n        {:ok, files}\n    end\n  end\n\n  @doc \"\"\"\n  Opens and reads content from either a URL or a local file system path.\n\n  Returns the contents as a `{:ok, binary}`, `:badpath` for invalid\n  paths or `{:local, message}` for local errors and `{:remote, message}`\n  for remote ones.\n\n  ## Options\n\n    * `:sha512` - checks against the given SHA-512 checksum. Returns\n      `{:checksum, message}` in case it fails\n\n    * `:timeout` - times out the request after the given milliseconds.\n      Returns `{:remote, timeout_message}` if it fails. Defaults to 60\n      seconds\n\n  \"\"\"\n  @spec read_path(String.t(), read_path_opts) ::\n          {:ok, binary}\n          | :badpath\n          | {:remote, String.t()}\n          | {:local, String.t()}\n          | {:checksum, String.t()}\n  def read_path(path, opts \\\\ []) do\n    cond do\n      url?(path) ->\n        task =\n          Task.async(fn ->\n            with {:ok, binary} <- read_httpc(path) do\n              checksum(binary, opts)\n            end\n          end)\n\n        timeout = Keyword.get(opts, :timeout, 60_000)\n\n        case Task.yield(task, timeout) || Task.shutdown(task, :brutal_kill) do\n          {:ok, result} -> result\n          _ -> {:remote, \"request timed out after #{timeout}ms\"}\n        end\n\n      file?(path) ->\n        with {:ok, binary} <- read_file(path) do\n          checksum(binary, opts)\n        end\n\n      true ->\n        :badpath\n    end\n  end\n\n  @checksums [:sha512]\n\n  defp checksum(binary, opts) do\n    Enum.find_value(@checksums, {:ok, binary}, fn hash ->\n      with expected when expected != nil <- opts[hash],\n           actual when actual != expected <- hexhash(binary, hash) do\n        message = \"\"\"\n        Data does not match the given SHA-512 checksum.\n\n        Expected: #{expected}\n          Actual: #{actual}\n        \"\"\"\n\n        {:checksum, message}\n      else\n        _ -> nil\n      end\n    end)\n  end\n\n  defp hexhash(binary, hash) do\n    Base.encode16(:crypto.hash(hash, binary), case: :lower)\n  end\n\n  defp read_file(path) do\n    try do\n      {:ok, File.read!(path)}\n    rescue\n      e in [File.Error] -> {:local, Exception.message(e)}\n    end\n  end\n\n  defp read_httpc(path) do\n    Mix.ensure_application!(:public_key)\n    Mix.ensure_application!(:ssl)\n    Mix.ensure_application!(:inets)\n\n    {:ok, _} = Application.ensure_all_started(:ssl)\n    {:ok, _} = Application.ensure_all_started(:inets)\n\n    # Starting an HTTP client profile allows us to scope\n    # the effects of using an HTTP proxy to this function\n    {:ok, _pid} = :inets.start(:httpc, profile: :mix)\n\n    headers = [{~c\"user-agent\", ~c\"Mix/#{System.version()}\"}]\n    request = {:binary.bin_to_list(path), headers}\n\n    # allow override of system CA certs to support running on managed networks\n    # using an SSL proxy etc. Piggy back on Hex defined environment variable\n    # rather than creating a new one, as these are almost always going to be\n    # set and used together.\n    cacert_opt =\n      case System.get_env(\"HEX_CACERTS_PATH\") do\n        nil -> {:cacerts, :public_key.cacerts_get()}\n        file -> {:cacertfile, file}\n      end\n\n    # Use the system certificates\n    ssl_options = [\n      cacert_opt,\n      verify: :verify_peer,\n      customize_hostname_check: [match_fun: :public_key.pkix_verify_hostname_match_fun(:https)]\n    ]\n\n    # We are using relaxed: true because some servers is returning a Location\n    # header with relative paths, which does not follow the spec. This would\n    # cause the request to fail with {:error, :no_scheme} unless :relaxed\n    # is given.\n    #\n    # If a proxy environment variable was supplied add a proxy to httpc.\n    http_options = [relaxed: true, ssl: ssl_options] ++ proxy_config(path)\n\n    # Silence the warning from OTP as we verify the contents\n    level = Logger.level()\n    Logger.configure(level: :error)\n\n    try do\n      case httpc_request(request, http_options) do\n        {:error, {:failed_connect, [{:to_address, _}, {inet, _, reason}]}}\n        when inet in [:inet, :inet6] and\n               reason in [:ehostunreach, :enetunreach, :eprotonosupport, :nxdomain] ->\n          :httpc.set_options([ipfamily: fallback(inet)], :mix)\n          request |> httpc_request(http_options) |> httpc_response()\n\n        {:error, {:failed_connect, [{:to_address, _}, {inet, _, reason}]}}\n        when inet in [:inet, :inet6] and elem(reason, 0) == :tls_alert ->\n          http_options = put_in(http_options, [:ssl, :middlebox_comp_mode], false)\n          request |> httpc_request(http_options) |> httpc_response()\n\n        response ->\n          httpc_response(response)\n      end\n    after\n      Logger.configure(level: level)\n      :inets.stop(:httpc, :mix)\n    end\n  end\n\n  defp fallback(:inet), do: :inet6\n  defp fallback(:inet6), do: :inet\n\n  defp httpc_request(request, http_options) do\n    :httpc.request(:get, request, http_options, [body_format: :binary], :mix)\n  end\n\n  defp httpc_response(response) do\n    case response do\n      {:ok, {{_, status, _}, _, body}} when status in 200..299 ->\n        {:ok, body}\n\n      {:ok, {{_, status, _}, _, _}} ->\n        {:remote, \"httpc request failed with: {:bad_status_code, #{status}}\"}\n\n      {:error, reason} ->\n        {:remote, \"httpc request failed with: #{inspect(reason)}\"}\n    end\n  end\n\n  defp file?(path) do\n    File.regular?(path)\n  end\n\n  defp url?(path) do\n    URI.parse(path).scheme in [\"http\", \"https\"]\n  end\n\n  def proxy_config(url) do\n    {http_proxy, https_proxy} = proxy_env()\n\n    proxy_auth(URI.parse(url), http_proxy, https_proxy)\n  end\n\n  defp proxy_env do\n    http_proxy = System.get_env(\"HTTP_PROXY\") || System.get_env(\"http_proxy\")\n    https_proxy = System.get_env(\"HTTPS_PROXY\") || System.get_env(\"https_proxy\")\n    no_proxy = no_proxy_env() |> no_proxy_list()\n\n    {proxy_setup(:http, http_proxy, no_proxy), proxy_setup(:https, https_proxy, no_proxy)}\n  end\n\n  defp no_proxy_env() do\n    System.get_env(\"NO_PROXY\") || System.get_env(\"no_proxy\")\n  end\n\n  defp no_proxy_list(nil) do\n    []\n  end\n\n  defp no_proxy_list(no_proxy) do\n    no_proxy\n    |> String.split(\",\")\n    |> Enum.map(&String.to_charlist/1)\n  end\n\n  defp proxy_setup(scheme, proxy, no_proxy) do\n    uri = URI.parse(proxy || \"\")\n\n    if uri.host && uri.port do\n      host = String.to_charlist(uri.host)\n      :httpc.set_options([{proxy_scheme(scheme), {{host, uri.port}, no_proxy}}], :mix)\n    end\n\n    uri\n  end\n\n  defp proxy_scheme(scheme) do\n    case scheme do\n      :http -> :proxy\n      :https -> :https_proxy\n    end\n  end\n\n  defp proxy_auth(%URI{scheme: \"http\"}, http_proxy, _https_proxy), do: proxy_auth(http_proxy)\n  defp proxy_auth(%URI{scheme: \"https\"}, _http_proxy, https_proxy), do: proxy_auth(https_proxy)\n\n  defp proxy_auth(nil), do: []\n  defp proxy_auth(%URI{userinfo: nil}), do: []\n\n  defp proxy_auth(%URI{userinfo: auth}) do\n    destructure [user, pass], String.split(auth, \":\", parts: 2)\n\n    user = String.to_charlist(user)\n    pass = String.to_charlist(pass || \"\")\n\n    [proxy_auth: {user, pass}]\n  end\n\n  @doc \"\"\"\n  Returns the user id of the currently running process.\n\n  The user id is obtained by creating a temporary file and checking\n  it's UID. Note that the UID may be `nil` on non-Unix systems.\n  \"\"\"\n  def detect_user_id!() do\n    case Mix.State.fetch(:user_id) do\n      {:ok, uid} ->\n        uid\n\n      :error ->\n        dir = System.tmp_dir!()\n        File.mkdir_p!(dir)\n        rand = :crypto.strong_rand_bytes(3) |> Base.url_encode64()\n        path = Path.join(dir, \"mix_user_check_#{System.os_time()}_#{rand}\")\n\n        uid =\n          try do\n            File.touch!(path)\n            File.stat!(path)\n          else\n            %{uid: :undefined} -> nil\n            %{uid: uid} -> uid\n          after\n            File.rm(path)\n          end\n\n        Mix.State.put(:user_id, uid)\n        uid\n    end\n  end\n\n  @doc \"\"\"\n  Convert the given terms to a consultable Erlang term.\n  \"\"\"\n  def consultable(term) do\n    {:ok, to_erl_term(term)}\n  catch\n    {:error, term, reason} -> {:error, term, reason}\n  end\n\n  defp to_erl_term(tuple) when is_tuple(tuple) do\n    [?{, tuple |> Tuple.to_list() |> to_erl_head(), ?}]\n  end\n\n  defp to_erl_term(list) when is_list(list) do\n    if List.ascii_printable?(list) do\n      :io_lib.print(list)\n    else\n      [?[, to_erl_head(list), ?]]\n    end\n  end\n\n  defp to_erl_term(%Regex{re_pattern: {:re_pattern, _, _, _, ref}} = regex)\n       when is_reference(ref) do\n    throw({:error, regex, \"you must use the /E modifier to store regexes\"})\n  end\n\n  defp to_erl_term(map) when is_map(map) do\n    inner =\n      Enum.map_intersperse(\n        :maps.to_list(:maps.iterator(map, :reversed)),\n        ?,,\n        fn {key, value} -> [to_erl_term(key), \"=>\", to_erl_term(value)] end\n      )\n\n    [?#, ?{, inner, ?}]\n  end\n\n  defp to_erl_term(map) when is_map(map) do\n    inner =\n      Enum.map_intersperse(\n        :maps.to_list(:maps.iterator(map, :reversed)),\n        ?,,\n        fn {key, value} -> [to_erl_term(key), \"=>\", to_erl_term(value)] end\n      )\n\n    [?#, ?{, inner, ?}]\n  end\n\n  defp to_erl_term(function) when is_function(function) do\n    fun_info = Function.info(function)\n\n    if fun_info[:type] == :external and fun_info[:env] == [] do\n      :io_lib.print(function)\n    else\n      throw({:error, function, \"only functions in the form &Mod.fun/arity are allowed\"})\n    end\n  end\n\n  defp to_erl_term(term) when is_reference(term) or is_pid(term) do\n    throw({:error, term, \"PIDs and References are not supported\"})\n  end\n\n  defp to_erl_term(term) do\n    :io_lib.print(term)\n  end\n\n  defp to_erl_head([]), do: []\n  defp to_erl_head([h | t]), do: [to_erl_term(h) | to_erl_tail(t)]\n\n  defp to_erl_tail([h | t]), do: [?,, to_erl_term(h) | to_erl_tail(t)]\n  defp to_erl_tail([]), do: []\n  defp to_erl_tail(other), do: [?|, to_erl_term(other)]\n\n  @doc \"\"\"\n  A Depth-First Search to find where is the dependency graph cycle\n  and then display the cyclic dependencies back to the developer.\n  \"\"\"\n  def find_cycle!(graph),\n    do: find_cycle(graph, :digraph.vertices(graph), MapSet.new()) || raise(\"no cycle found\")\n\n  defp find_cycle(_, [], _visited), do: nil\n\n  defp find_cycle(graph, [v | vs], visited) do\n    if v in visited do\n      visited\n    else\n      find_cycle(graph, :digraph.out_neighbours(graph, v), MapSet.put(visited, v)) ||\n        find_cycle(graph, vs, visited)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/lib/mix.ex",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix do\n  @moduledoc ~S\"\"\"\n  Mix is a build tool that provides tasks for creating, compiling,\n  and testing Elixir projects, managing its dependencies, and more.\n\n  ## `Mix.Project`\n\n  The foundation of Mix is a project. A project can be defined by using\n  `Mix.Project` in a module, usually placed in a file named `mix.exs`:\n\n      defmodule MyApp.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :my_app,\n            version: \"1.0.0\"\n          ]\n        end\n      end\n\n  See the `Mix.Project` module for detailed documentation on Mix projects.\n\n  Once the project is defined, a number of default Mix tasks can be run\n  directly from the command line:\n\n    * `mix compile` - compiles the current project\n    * `mix test` - runs tests for the given project\n    * `mix run` - runs a particular command inside the project\n\n  Each task has its own options and sometimes specific configuration\n  to be defined in the `project/0` function. You can use `mix help`\n  to list all available tasks and `mix help NAME` to show help for\n  a particular task.\n\n  The best way to get started with your first project is by calling\n  `mix new my_project` from the command line.\n\n  ## `Mix.Task`\n\n  Tasks are what make Mix extensible.\n\n  Projects can extend Mix behaviour by adding their own tasks. For\n  example, adding the task below inside your project will\n  make it available to everyone that uses your project:\n\n      defmodule Mix.Tasks.Hello do\n        use Mix.Task\n\n        def run(_) do\n          Mix.shell().info(\"Hello world\")\n        end\n      end\n\n  The task can now be invoked with `mix hello`.\n\n  See the `Mix.Task` behaviour for detailed documentation on Mix tasks.\n\n  ## Dependencies\n\n  Mix also manages your dependencies and integrates nicely with the [Hex package\n  manager](https://hex.pm).\n\n  In order to use dependencies, you need to add a `:deps` key\n  to your project configuration. We often extract the list of dependencies\n  into its own function:\n\n      defmodule MyApp.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :my_app,\n            version: \"1.0.0\",\n            deps: deps()\n          ]\n        end\n\n        defp deps do\n          [\n            {:ecto, \"~> 2.0\"},\n            {:plug, github: \"elixir-lang/plug\"}\n          ]\n        end\n      end\n\n  You can run `mix help deps` to learn more about dependencies in Mix.\n\n  ## Environments\n\n  Mix supports different environments. Environments allow developers\n  to prepare and organize their project specifically for different\n  scenarios. By default, Mix provides three environments:\n\n    * `:dev` - the default environment\n    * `:test` - the environment `mix test` runs on\n    * `:prod` - the environment your dependencies run on\n\n  The environment can be changed via the command line by setting\n  the `MIX_ENV` environment variable, for example:\n\n  ```bash\n  $ MIX_ENV=prod mix run server.exs\n  ```\n\n  You can also specify that certain dependencies are available only for\n  certain environments:\n\n      {:some_test_dependency, \"~> 1.0\", only: :test}\n\n  When running Mix via the command line, you can configure the default\n  environment or the preferred environment per task via the `def cli`\n  function in your `mix.exs`. For example:\n\n      def cli do\n        [\n          default_env: :local,\n          preferred_envs: [docs: :docs]\n        ]\n      end\n\n  The environment can be read via `Mix.env/0`.\n\n  ## Targets\n\n  Besides environments, Mix supports targets. Targets are useful when a\n  project needs to compile to different architectures and some of the\n  dependencies are only available to some of them. By default, the target\n  is `:host` but it can be set via the `MIX_TARGET` environment variable.\n\n  When running Mix via the command line, you can configure the default\n  target or the preferred target per task via the `def cli` function\n  in your `mix.exs`. For example:\n\n      def cli do\n        [\n          default_target: :local,\n          preferred_targets: [docs: :docs]\n        ]\n      end\n\n  The target can be read via `Mix.target/0`.\n\n  ## Configuration\n\n  Mix allows you to configure the application environment of your application\n  and of your dependencies. See the `Application` module to learn more about\n  the application environment. On this section, we will focus on how to configure\n  it at two distinct moments: build-time and runtime.\n\n  > #### Avoiding the application environment {: .warning}\n  >\n  > The application environment is discouraged for libraries. See Elixir's\n  > [Library Guidelines](https://hexdocs.pm/elixir/library-guidelines.html) for\n  > more information.\n\n  ### Build-time configuration\n\n  Whenever you invoke a `mix` command, Mix loads the configuration\n  in `config/config.exs`, if said file exists. It is common for the\n  `config/config.exs` file itself to import other configuration based\n  on the current `MIX_ENV`, such as `config/dev.exs`, `config/test.exs`,\n  and `config/prod.exs`, by calling `Config.import_config/1`:\n\n      import Config\n      import_config \"#{config_env()}.exs\"\n\n  We say `config/config.exs` and all imported files are build-time\n  configuration as they are evaluated whenever you compile your code.\n  In other words, if your configuration does something like:\n\n      import Config\n      config :my_app, :secret_key, System.fetch_env!(\"MY_APP_SECRET_KEY\")\n\n  The `:secret_key` key under `:my_app` will be computed on the host\n  machine before your code compiles. This can be an issue if the machine\n  compiling your code does not have access to all environment variables\n  used to run your code, as loading the config above will fail due to the\n  missing environment variable. Furthermore, even if the environment variable\n  is set, changing the environment variable will require a full recompilation\n  of your application by calling `mix compile --force` (otherwise your project\n  won't start). Luckily, Mix also provides runtime configuration, which is\n  preferred in such cases and we will see next.\n\n  ### Runtime configuration\n\n  To enable runtime configuration in your release, all you need to do is\n  to create a file named `config/runtime.exs`:\n\n      import Config\n      config :my_app, :secret_key, System.fetch_env!(\"MY_APP_SECRET_KEY\")\n\n  This file is executed whenever your project runs. If you assemble\n  a release with `mix release`, it also executes every time your release\n  starts.\n\n  ## Aliases\n\n  Aliases are shortcuts or tasks specific to the current project.\n\n  In the [Mix.Task section](#module-mix-task), we have defined a task that would be\n  available to everyone using our project as a dependency. What if\n  we wanted the task to only be available for our project? Just\n  define an alias:\n\n      defmodule MyApp.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :my_app,\n            version: \"1.0.0\",\n            aliases: aliases()\n          ]\n        end\n\n        defp aliases do\n          [\n            c: \"compile\",\n            hello: &hello/1,\n            paid_task: &paid_task/1\n          ]\n        end\n\n        defp hello(_) do\n          Mix.shell().info(\"Hello world\")\n        end\n\n        defp paid_task(_) do\n          Mix.Task.run(\"paid.task\", [\n            \"first_arg\",\n            \"second_arg\",\n            \"--license-key\",\n            System.fetch_env!(\"SOME_LICENSE_KEY\")\n          ])\n        end\n      end\n\n  In the example above, we have defined three aliases. One is `mix c`\n  which is a shortcut for `mix compile`. Another is named\n  `mix hello` and the third is named `mix paid_task`, which executes\n  the code inside a custom function to invoke the `paid.task` task\n  with several arguments, including one pulled from an environment\n  variable.\n\n  Aliases may also be lists, specifying multiple tasks to be run\n  consecutively:\n\n      [all: [&hello/1, \"deps.get --only #{Mix.env()}\", \"compile\"]]\n\n  In the example above, we have defined an alias named `mix all`,\n  that prints \"Hello world\", then fetches dependencies specific\n  to the current environment, and compiles the project.\n\n  Aliases can also be used to augment existing tasks. Let's suppose\n  you want to augment `mix clean` to clean another directory Mix does\n  not know about:\n\n      [clean: [\"clean\", &clean_extra/1]]\n\n  Where `&clean_extra/1` would be a function in your `mix.exs`\n  with extra cleanup logic.\n\n  If the alias is overriding an existing task, the arguments given\n  to the alias will be forwarded to the original task in order to\n  preserve semantics. Otherwise arguments given to the alias are\n  appended to the arguments of the last task in the list.\n\n  Another use case of aliases is to run Elixir scripts and shell\n  commands, for example:\n\n      # priv/hello1.exs\n      IO.puts(\"Hello One\")\n\n      # priv/hello2.exs\n      IO.puts(\"Hello Two\")\n\n      # priv/world.sh\n      #!/bin/sh\n      echo \"world!\"\n\n      # mix.exs\n      defp aliases do\n        [\n          some_alias: [\"hex.info\", \"run priv/hello1.exs\", \"cmd priv/world.sh\"]\n        ]\n      end\n\n  In the example above we have created the alias `some_alias` that will\n  run the task `mix hex.info`, then `mix run` to run an Elixir script,\n  then `mix cmd` to execute a command line shell script. This shows how\n  powerful aliases mixed with Mix tasks can be.\n\n  One common pitfall of aliases comes when trying to invoke the same task\n  multiple times. Mix tasks are designed to run only once. This prevents\n  the same task from being executed multiple times. For example, if there\n  are several tasks depending on `mix compile`, the code will be compiled\n  only once.\n\n  Similarly, `mix format` can only be invoked once. So if you have an alias\n  that attempts to invoke `mix format` multiple times, it won't work unless\n  it is explicitly reenabled using `Mix.Task.reenable/1`:\n\n      another_alias: [\n        \"format --check-formatted priv/hello1.exs\",\n        \"cmd priv/world.sh\",\n        fn _ -> Mix.Task.reenable(\"format\") end,\n        \"format --check-formatted priv/hello2.exs\"\n      ]\n\n  Some tasks are automatically reenabled though, as they are expected to\n  be invoked multiple times, such as: `mix cmd`, `mix do`, `mix xref`, etc.\n\n  Finally, aliases defined in the current project do not affect its\n  dependencies and aliases defined in dependencies are not accessible\n  from the current project, with the exception of umbrella projects.\n  Umbrella projects will run the aliases of its children when the\n  umbrella project itself does not define said alias and there is no\n  task with said name.\n\n  ## Environment variables\n\n  Several environment variables can be used to modify Mix's behavior.\n\n  Mix responds to the following variables:\n\n    * `MIX_ARCHIVES` - specifies the directory into which the archives should be installed\n      (default: `~/.mix/archives`)\n\n    * `MIX_BUILD_PATH` - sets the project `Mix.Project.build_path/0`, including the\n      current environment, such as \"/path/to/project/_build/dev\". This environment\n      variable is used mostly by external build tools who need enforce a build\n      directory independent of `MIX_ENV` and `MIX_TARGET`. For your CI servers,\n      you likely want to use `MIX_BUILD_ROOT` below.\n\n    * `MIX_BUILD_ROOT` - sets the root directory where build artifacts should be\n      written to. For example, \"/path/to/_build\". If `MIX_BUILD_PATH` is set,\n      this option is ignored.\n\n    * `MIX_DEBUG` - outputs debug information about each task before running it\n\n    * `MIX_DEPS_PATH` - sets the project `Mix.Project.deps_path/0` config for the\n      current project, as an absolute path, such as `/path/to/project/deps`\n\n    * `MIX_ENV` - specifies which environment should be used. See [Environments](#module-environments)\n\n    * `MIX_EXS` - changes the full path to the `mix.exs` file\n\n    * `MIX_HOME` - path to Mix's home directory, stores configuration files and scripts used by Mix\n      (default: `~/.mix`)\n\n    * `MIX_INSTALL_DIR` *(since v1.12.0)* - specifies directory where `Mix.install/2` keeps\n       install cache\n\n    * `MIX_OS_CONCURRENCY_LOCK` - when set to `0` or `false`, disables mix compilation locking.\n      While not recommended, this may be necessary in cases where hard links or TCP sockets are\n      not available. When opting for this behaviour, make sure to not start concurrent compilations\n      of the same project\n\n    * `MIX_OS_DEPS_COMPILE_PARTITION_COUNT` - when set to a number greater than 1, it enables\n      compilation of dependencies over multiple operating system processes. See `mix help deps.compile`\n      for more information\n\n    * `MIX_PATH` - appends extra code paths\n\n    * `MIX_PROFILE` - a list of comma-separated Mix tasks to profile the time spent on\n      functions by the process running the task, such as `MIX_PROFILE=compile,test`.\n      You can also set `MIX_PROFILE_FLAGS` to control the flags given to profiling,\n      see `mix profile.tprof` for all options. By default, it uses `--no-warmup`.\n\n    * `MIX_QUIET` - does not print information messages to the terminal\n\n    * `MIX_REBAR3` - path to rebar3 command that overrides the one Mix installs\n      (default: `~/.mix/rebar3`)\n\n    * `MIX_TARGET` - specifies which target should be used. See [Targets](#module-targets)\n\n    * `MIX_XDG` - asks Mix to follow the [XDG Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)\n      for its home directory and configuration files. This behavior needs to\n      be opt-in due to backwards compatibility. `MIX_HOME` has higher preference\n      than `MIX_XDG`. If none of the variables are set, the default directory\n      `~/.mix` will be used\n\n  Environment variables that are not meant to hold a value (and act basically as\n  flags) should be set to either `1` or `true`, for example:\n\n      $ MIX_DEBUG=1 mix compile\n\n  ## SSL certificates\n\n  Mix and the Hex package manager use the default operating system certificates\n  when downloading resources. In certain situations, such as when running behind\n  proxies, you want to replace those certificates.\n\n  If you simply want to change the certificates used by Mix and Hex, you may set\n  the `HEX_CACERTS_PATH` environment variable, pointing to a CA certificate file.\n  See [`mix hex.config`](https://hexdocs.pm/hex/Mix.Tasks.Hex.Config.html#module-config-keys).\n\n  From Erlang/OTP 27.2, it is also possible to change the certificates for your\n  project as a whole. To do so, you might add the following to your `config/config.exs`:\n\n      config :public_key, :cacerts_path, \"/path/to/certs.pem\"\n\n  You can also do so by setting the `ERL_AFLAGS` and `ERL_ZFLAGS` environment variables:\n\n  ```bash\n  ERL_AFLAGS=\"-public_key cacerts_path '\\\"/path/to/certs.pem\\\"'\"\n  ERL_ZFLAGS=\"-public_key cacerts_path '\\\"/path/to/certs.pem\\\"'\"\n  ```\n\n  You can verify if the configuration has been properly set by calling the following\n  inside `iex -S mix`:\n\n      Application.load(:public_key)\n      Application.get_env(:public_key, :cacerts_path)\n\n  And by loading the certificates:\n\n      :public_key.cacerts_get()\n\n  \"\"\"\n\n  @typedoc \"\"\"\n  Options for `install/2`.\n\n  See the `install/2` function documentation for detailed information about each option.\n  \"\"\"\n  @type install_opts :: [\n          force: boolean(),\n          verbose: boolean(),\n          consolidate_protocols: boolean(),\n          elixir: String.t(),\n          system_env: Enum.t(),\n          config: keyword(),\n          config_path: String.t() | atom(),\n          lockfile: String.t() | atom(),\n          start_applications: boolean(),\n          compilers: [atom()],\n          runtime_config: keyword()\n        ]\n\n  @mix_install_project Mix.InstallProject\n  @mix_install_app :mix_install\n  @mix_install_app_string Atom.to_string(@mix_install_app)\n\n  use Application\n\n  import Kernel, except: [raise: 2]\n\n  @doc false\n  def start do\n    {:ok, _} = Application.ensure_all_started(:mix)\n    :ok\n  end\n\n  @impl true\n  def start(_type, []) do\n    Mix.Local.append_archives()\n    Mix.Local.append_paths()\n    children = [Mix.Sync.PubSub, Mix.State, Mix.TasksServer, Mix.ProjectStack]\n    opts = [strategy: :one_for_one, name: Mix.Supervisor, max_restarts: 0]\n    Supervisor.start_link(children, opts)\n  end\n\n  @impl true\n  def stop(_data) do\n    Mix.Local.remove_archives()\n    Mix.Local.remove_paths()\n    :ok\n  end\n\n  @doc \"\"\"\n  Returns the current Mix environment.\n\n  This function should not be used at runtime in application code (as opposed\n  to infrastructure and build code like Mix tasks). Mix is a build tool and may\n  not be available after the code is compiled (for example in a release).\n\n  To differentiate the program behavior depending on the environment, it is\n  recommended to use application environment through `Application.get_env/3`.\n  Proper configuration can be set in config files, often per-environment\n  (see the `Config` module for more information).\n  \"\"\"\n  @spec env() :: atom()\n  def env do\n    # env is not available on bootstrapping, so set a :dev default\n    Mix.State.get(:env, :dev)\n  end\n\n  @doc \"\"\"\n  Changes the current Mix environment to `env`.\n\n  Be careful when invoking this function as any project\n  configuration won't be reloaded.\n\n  This function should not be used at runtime in application code\n  (see `env/0` for more information).\n  \"\"\"\n  @spec env(atom()) :: :ok\n  def env(env) when is_atom(env) do\n    Mix.State.put(:env, env)\n  end\n\n  @doc \"\"\"\n  Returns the Mix target.\n  \"\"\"\n  @spec target() :: atom()\n  def target do\n    # target is not available on bootstrapping, so set a :host default\n    Mix.State.get(:target, :host)\n  end\n\n  @doc \"\"\"\n  Changes the current Mix target to `target`.\n\n  Be careful when invoking this function as any project\n  configuration won't be reloaded.\n  \"\"\"\n  @spec target(atom()) :: :ok\n  def target(target) when is_atom(target) do\n    Mix.State.put(:target, target)\n  end\n\n  @doc \"\"\"\n  Returns the default compilers used by Mix.\n\n  It can be used in your `mix.exs` to prepend or\n  append new compilers to Mix:\n\n      def project do\n        [compilers: Mix.compilers() ++ [:foo, :bar]]\n      end\n\n  \"\"\"\n  @spec compilers() :: [atom()]\n  def compilers do\n    [:erlang, :elixir, :app]\n  end\n\n  @doc \"\"\"\n  Returns the current shell.\n\n  `shell/0` can be used as a wrapper for the current shell. It contains\n  conveniences for requesting information from the user, printing to the\n  shell and so forth. The Mix shell is swappable (see `shell/1`), allowing\n  developers to use a test shell that simply sends messages to the current\n  process instead of performing IO (see `Mix.Shell.Process`).\n\n  By default, this returns `Mix.Shell.IO`.\n\n  ## Examples\n\n      Mix.shell().info(\"Preparing to do something dangerous...\")\n\n      if Mix.shell().yes?(\"Are you sure?\") do\n        # do something dangerous\n      end\n\n  \"\"\"\n  @spec shell() :: module\n  def shell do\n    Mix.State.get(:shell, Mix.Shell.IO)\n  end\n\n  @doc \"\"\"\n  Sets the current shell.\n\n  As an argument you may pass `Mix.Shell.IO`, `Mix.Shell.Process`,\n  `Mix.Shell.Quiet`, or any module that implements the `Mix.Shell`\n  behaviour.\n\n  After calling this function, `shell` becomes the shell that is\n  returned by `shell/0`.\n\n  ## Examples\n\n      iex> Mix.shell(Mix.Shell.IO)\n      :ok\n\n  You can use `shell/0` and `shell/1` to temporarily switch shells,\n  for example, if you want to run a Mix Task that normally produces\n  a lot of output:\n\n      shell = Mix.shell()\n      Mix.shell(Mix.Shell.Quiet)\n\n      try do\n        Mix.Task.run(\"noisy.task\")\n      after\n        Mix.shell(shell)\n      end\n\n  \"\"\"\n  @spec shell(module) :: :ok\n  def shell(shell) do\n    Mix.State.put(:shell, shell)\n  end\n\n  @doc \"\"\"\n  Returns `true` if Mix is in debug mode, `false` otherwise.\n  \"\"\"\n  @spec debug?() :: boolean()\n  def debug? do\n    Mix.State.get(:debug, false)\n  end\n\n  @doc \"\"\"\n  Sets Mix debug mode.\n  \"\"\"\n  @spec debug(boolean()) :: :ok\n  def debug(debug) when is_boolean(debug) do\n    Mix.State.put(:debug, debug)\n  end\n\n  @doc \"\"\"\n  Raises a Mix error that is nicely formatted, defaulting to exit status `1`.\n  \"\"\"\n  @spec raise(binary) :: no_return\n  def raise(message) do\n    __MODULE__.raise(message, exit_status: 1)\n  end\n\n  @doc \"\"\"\n  Raises a Mix error that is nicely formatted.\n\n  ## Options\n\n    * `:exit_status` - defines exit status, defaults to `1`\n\n  \"\"\"\n  @doc since: \"1.12.3\"\n  @spec raise(binary, exit_status: non_neg_integer()) :: no_return\n  def raise(message, opts) when is_binary(message) and is_list(opts) do\n    status =\n      opts[:exit_status] ||\n        if exit_code = opts[:exit_code] do\n          IO.warn(\":exit_code is deprecated, use :exit_status instead\")\n          exit_code\n        else\n          1\n        end\n\n    Kernel.raise(Mix.Error, mix: status, message: message)\n  end\n\n  @doc \"\"\"\n  The path for local archives or escripts.\n  \"\"\"\n  @doc since: \"1.10.0\"\n  @spec path_for(:archives | :escripts) :: String.t()\n  def path_for(:archives) do\n    System.get_env(\"MIX_ARCHIVES\") || Path.join(Mix.Utils.mix_home(), \"archives\")\n  end\n\n  def path_for(:escripts) do\n    Path.join(Mix.Utils.mix_home(), \"escripts\")\n  end\n\n  @doc \"\"\"\n  Ensures the given application from Erlang/OTP or Elixir and its dependencies\n  are available in the path.\n\n  Generally speaking, you should list the Erlang application dependencies under\n  the `:extra_applications` section of your `mix.exs`. This must only be used by\n  Mix tasks which wish to avoid depending on Erlang/Elixir for certain reasons.\n\n  This function does not start the given applications.\n  \"\"\"\n  @doc since: \"1.15.0\"\n  def ensure_application!(app) when is_atom(app) do\n    ensure_application!(app, Mix.State.builtin_apps(), [], %{})\n    :ok\n  end\n\n  defp ensure_application!(app, builtin_apps, optional, seen) do\n    case seen do\n      %{^app => _} ->\n        seen\n\n      %{} ->\n        seen = Map.put(seen, app, true)\n\n        case builtin_apps do\n          %{^app => path} ->\n            Code.prepend_path(path, cache: true)\n            Application.load(app)\n\n            required = List.wrap(Application.spec(app, :applications))\n            optional = List.wrap(Application.spec(app, :optional_applications))\n\n            Enum.reduce(\n              required ++ optional,\n              seen,\n              &ensure_application!(&1, builtin_apps, optional, &2)\n            )\n\n          %{} ->\n            if app not in optional do\n              Mix.raise(\n                \"The application \\\"#{app}\\\" could not be found. This may happen if your \" <>\n                  \"Operating System broke Erlang into multiple packages and may be fixed \" <>\n                  \"by installing the missing \\\"erlang-dev\\\" and \\\"erlang-#{app}\\\" packages\"\n              )\n            end\n\n            seen\n        end\n    end\n  end\n\n  @doc \"\"\"\n  Installs and starts dependencies.\n\n  The given `deps` should be in the same format as defined in a regular Mix\n  project. See `mix help deps` for more information. As a shortcut, an atom\n  can be given as dependency to mean the latest version. In other words,\n  specifying `:decimal` is the same as `{:decimal, \">= 0.0.0\"}`.\n\n  After each successful installation, a given set of dependencies is cached\n  so starting another VM and calling `Mix.install/2` with the same dependencies\n  will avoid unnecessary downloads and compilations. The location of the cache\n  directory can be controlled using the `MIX_INSTALL_DIR` environment variable.\n\n  This function can only be called outside of a Mix project and only with the\n  same dependencies in the given VM.\n\n  ## Options\n\n    * `:config` *(since v1.13.0)* - a keyword list of keyword lists of compile-time\n      configuration. The configuration is part of the `Mix.install/2` cache, so\n      different configurations will lead to different apps. For this reason, you\n      want to minimize the amount of configuration set through this option.\n      Use `Application.put_all_env/2` for setting other runtime configuration.\n\n    * `:config_path` *(since v1.14.0)* - path to a configuration file. If a `runtime.exs`\n      file exists in the same directory as the given path, it is loaded too.\n\n    * `:consolidate_protocols` - if `true`, runs protocol consolidation (Default: `true`)\n\n    * `:elixir` - if set, ensures the current Elixir version matches the given\n      version requirement (Default: `nil`)\n\n    * `:force` - if `true`, runs with empty install cache. This is useful when you want\n      to update your dependencies or your install got into an inconsistent state.\n      To use this option, you can also set the `MIX_INSTALL_FORCE` environment variable.\n      (Default: `false`)\n\n    * `:lockfile` *(since v1.14.0)* - path to a lockfile to be used as a basis of\n      dependency resolution.\n\n    * `:start_applications` *(since v1.15.3)* - if `true`, ensures that installed app\n      and its dependencies are started after install (Default: `true`)\n\n    * `:stop_unused_applications` *(since v1.20.0)* - as part of the installation process,\n      Elixir may start Hex, SSL, and other applications. Those are automatically shutdown\n      after installation, but you can set this option to false so they remain running\n\n    * `:system_env` *(since v1.13.0)* - a list or a map of system environment variable\n      names with respective values as binaries. The system environment is made part\n      of the `Mix.install/2` cache, so different configurations will lead to different apps\n\n    * `:verbose` - if `true`, prints additional debugging information\n      (Default: `false`)\n\n  ## Examples\n\n  Installing `:decimal` and `:jason`:\n\n      Mix.install([\n        :decimal,\n        {:jason, \"~> 1.0\"}\n      ])\n\n  Installing `:nx` and `:exla`, and configuring the underlying applications\n  and environment variables:\n\n      Mix.install(\n        [:nx, :exla],\n        config: [\n          nx: [default_backend: EXLA]\n        ],\n        system_env: [\n          XLA_TARGET: \"cuda111\"\n        ]\n      )\n\n  Installing a Mix project as a path dependency along with its configuration\n  and deps:\n\n      # $ git clone https://github.com/hexpm/hexpm /tmp/hexpm\n      # $ cd /tmp/hexpm && mix setup\n\n      Mix.install(\n        [\n          {:hexpm, path: \"/tmp/hexpm\", env: :dev},\n        ],\n        config_path: \"/tmp/hexpm/config/config.exs\",\n        lockfile: \"/tmp/hexpm/mix.lock\"\n      )\n\n      Hexpm.Repo.query!(\"SELECT COUNT(1) from packages\")\n      #=> ...\n\n  The example above can be simplified by passing the application\n  name as an atom for `:config_path` and `:lockfile`:\n\n      Mix.install(\n        [\n          {:hexpm, path: \"/tmp/hexpm\", env: :dev},\n        ],\n        config_path: :hexpm,\n        lockfile: :hexpm\n      )\n\n  ## Limitations\n\n  There is one limitation to `Mix.install/2`, which is actually an Elixir\n  behavior. If you are installing a dependency that defines a struct or\n  macro, you cannot use the struct or macro immediately after the install\n  call. For example, this won't work:\n\n      Mix.install([:decimal])\n      %Decimal{} = Decimal.new(42)\n\n  That's because Elixir first expands all structs and all macros, and then\n  it executes the code. This means that, by the time Elixir tries to expand\n  the `%Decimal{}` struct, the dependency has not been installed yet.\n\n  Luckily this has a straightforward solution, which is to move the code\n  inside a module:\n\n      Mix.install([:decimal])\n\n      defmodule Script do\n        def run do\n          %Decimal{} = Decimal.new(42)\n        end\n      end\n\n      Script.run()\n\n  The contents inside `defmodule` will only be expanded and executed\n  after `Mix.install/2` runs, which means that any struct, macros,\n  and imports will be correctly handled.\n\n  ## Environment variables\n\n  The `MIX_INSTALL_DIR` environment variable configures the directory that\n  caches all `Mix.install/2`. It defaults to the `mix/install` folder in the\n  default user cache of your operating system. You can use `install_project_dir/0`\n  to access the directory of an existing install (alongside other installs):\n\n      iex> Mix.install([])\n      iex> Mix.install_project_dir()\n\n  The `MIX_INSTALL_FORCE` is available since Elixir v1.13.0 and forces\n  `Mix.install/2` to discard any previously cached entry of the current install.\n\n  The `MIX_INSTALL_RESTORE_PROJECT_DIR` environment variable may be specified\n  since Elixir v1.16.2. It should point to a previous installation directory,\n  which can be obtained with `Mix.install_project_dir/0` (after calling `Mix.install/2`).\n  Using a restore dir may speed up the installation, since matching dependencies\n  do not need be refetched nor recompiled. This environment variable is ignored\n  if `:force` is enabled.\n  \"\"\"\n  @doc since: \"1.12.0\"\n  @spec install(\n          [atom() | {atom(), String.t()} | {atom(), String.t(), keyword()} | {atom(), keyword()}],\n          install_opts()\n        ) :: :ok\n  def install(deps, opts \\\\ [])\n\n  def install(deps, opts) when is_list(deps) and is_list(opts) do\n    Mix.start()\n\n    if Mix.Project.get() do\n      Mix.raise(\"Mix.install/2 cannot be used inside a Mix project\")\n    end\n\n    elixir_requirement = opts[:elixir]\n    elixir_version = System.version()\n\n    if !!elixir_requirement and not Version.match?(elixir_version, elixir_requirement) do\n      Mix.raise(\n        \"Mix.install/2 declared it supports only Elixir #{elixir_requirement} \" <>\n          \"but you're running on Elixir #{elixir_version}\"\n      )\n    end\n\n    deps =\n      Enum.map(deps, fn\n        dep when is_atom(dep) ->\n          {dep, \">= 0.0.0\"}\n\n        {app, opts} when is_atom(app) and is_list(opts) ->\n          {app, maybe_expand_path_dep(opts)}\n\n        {app, requirement, opts} when is_atom(app) and is_binary(requirement) and is_list(opts) ->\n          {app, requirement, maybe_expand_path_dep(opts)}\n\n        other ->\n          other\n      end)\n\n    opts =\n      Keyword.validate!(opts,\n        config: [],\n        config_path: nil,\n        consolidate_protocols: true,\n        compilers: [:elixir],\n        elixir: nil,\n        force: false,\n        lockfile: nil,\n        runtime_config: [],\n        start_applications: true,\n        stop_unused_applications: true,\n        system_env: [],\n        verbose: false\n      )\n\n    config_path = expand_path(opts[:config_path], deps, :config_path, \"config/config.exs\")\n    config = Keyword.fetch!(opts, :config)\n    system_env = Keyword.fetch!(opts, :system_env)\n    consolidate_protocols? = Keyword.fetch!(opts, :consolidate_protocols)\n    start_applications? = Keyword.fetch!(opts, :start_applications)\n    compilers = Keyword.fetch!(opts, :compilers)\n\n    id =\n      {deps, config, system_env, consolidate_protocols?}\n      |> :erlang.term_to_binary()\n      |> :erlang.md5()\n      |> Base.url_encode64(padding: false)\n\n    force? = System.get_env(\"MIX_INSTALL_FORCE\") in [\"1\", \"true\"] or Keyword.fetch!(opts, :force)\n\n    case Mix.State.get(:installed) do\n      nil ->\n        System.put_env(system_env)\n        install_project_dir = install_project_dir(id)\n\n        if Keyword.fetch!(opts, :verbose) do\n          Mix.shell().info(\"Mix.install/2 using #{install_project_dir}\")\n        end\n\n        if force? do\n          File.rm_rf!(install_project_dir)\n        end\n\n        dynamic_config = [\n          deps: deps,\n          consolidate_protocols: consolidate_protocols?,\n          config_path: config_path,\n          compilers: compilers\n        ]\n\n        :ok =\n          Mix.ProjectStack.push(\n            @mix_install_project,\n            [compile_config: config] ++ install_project_config(dynamic_config),\n            \"nofile\"\n          )\n\n        started_apps = Application.started_applications()\n        build_dir = Path.join(install_project_dir, \"_build\")\n        external_lockfile = expand_path(opts[:lockfile], deps, :lockfile, \"mix.lock\")\n\n        try do\n          first_build? = not File.dir?(build_dir)\n\n          restore_dir = System.get_env(\"MIX_INSTALL_RESTORE_PROJECT_DIR\")\n\n          if first_build? and restore_dir != nil and not force? do\n            File.cp_r(restore_dir, install_project_dir)\n            remove_dep(install_project_dir, @mix_install_app_string)\n          end\n\n          File.mkdir_p!(install_project_dir)\n\n          File.cd!(install_project_dir, fn ->\n            # This steps need to be mirror in mix deps.partition\n            Application.put_all_env(config, persistent: true)\n            Mix.Task.rerun(\"loadconfig\")\n\n            cond do\n              external_lockfile ->\n                md5_path = Path.join(install_project_dir, \"merge.lock.md5\")\n\n                old_md5 =\n                  case File.read(md5_path) do\n                    {:ok, data} -> Base.decode64!(data)\n                    _ -> nil\n                  end\n\n                new_md5 = external_lockfile |> File.read!() |> :erlang.md5()\n\n                if old_md5 != new_md5 do\n                  lockfile = Path.join(install_project_dir, \"mix.lock\")\n                  old_lock = Mix.Dep.Lock.read(lockfile)\n                  new_lock = Mix.Dep.Lock.read(external_lockfile)\n                  Mix.Dep.Lock.write(Map.merge(old_lock, new_lock), file: lockfile)\n                  File.write!(md5_path, Base.encode64(new_md5))\n                  Mix.Task.rerun(\"deps.get\")\n                end\n\n              first_build? ->\n                Mix.Task.rerun(\"deps.get\")\n\n              true ->\n                # We already have a cache. If the user by any chance uninstalled Hex,\n                # we make sure it is installed back (which mix deps.get would do anyway)\n                Mix.Hex.ensure_installed?(true)\n                :ok\n            end\n\n            Mix.Task.rerun(\"deps.loadpaths\")\n\n            # Hex and SSL can use a good amount of memory after the registry fetching,\n            # so we stop any app started during deps resolution.\n            if Keyword.fetch!(opts, :stop_unused_applications) do\n              stop_apps(Application.started_applications() -- started_apps)\n            end\n\n            Mix.Task.rerun(\"compile\")\n\n            if config_path do\n              Mix.Task.rerun(\"app.config\")\n            end\n          end)\n\n          if start_applications? do\n            for %{app: app, opts: opts} <- Mix.Dep.cached(),\n                Keyword.get(opts, :runtime, true) and Keyword.get(opts, :app, true) do\n              Application.ensure_all_started(app)\n            end\n          end\n\n          if restore_dir do\n            remove_leftover_deps(install_project_dir)\n          end\n\n          Mix.State.put(:installed, {id, dynamic_config})\n          :ok\n        after\n          Mix.ProjectStack.pop()\n          # Clear all tasks invoked during installation, since there\n          # is no reason to keep this in memory. Additionally this\n          # allows us to rerun tasks for the dependencies later on,\n          # such as recompilation\n          Mix.Task.clear()\n        end\n\n      {^id, _dynamic_config} when not force? ->\n        :ok\n\n      _ ->\n        Mix.raise(\"Mix.install/2 can only be called with the same dependencies in the given VM\")\n    end\n  end\n\n  defp expand_path(_path = nil, _deps, _key, _), do: nil\n  defp expand_path(path, _deps, _key, _) when is_binary(path), do: Path.expand(path)\n\n  defp expand_path(app_name, deps, key, relative_path) when is_atom(app_name) do\n    app_dir =\n      case List.keyfind(deps, app_name, 0) do\n        {_, _, opts} when is_list(opts) -> opts[:path]\n        {_, opts} when is_list(opts) -> opts[:path]\n        _ -> Mix.raise(\"unknown dependency #{inspect(app_name)} given to #{inspect(key)}\")\n      end\n\n    if !app_dir do\n      Mix.raise(\"#{inspect(app_name)} given to #{inspect(key)} must be a path dependency\")\n    end\n\n    Path.join(app_dir, relative_path)\n  end\n\n  defp remove_leftover_deps(install_project_dir) do\n    build_lib_dir = Path.join([install_project_dir, \"_build\", \"dev\", \"lib\"])\n\n    deps = File.ls!(build_lib_dir)\n\n    loaded_deps =\n      for {app, _description, _version} <- Application.loaded_applications(),\n          into: MapSet.new(),\n          do: Atom.to_string(app)\n\n    # We want to keep :mix_install, but it has no application\n    loaded_deps = MapSet.put(loaded_deps, @mix_install_app_string)\n\n    for dep <- deps, not MapSet.member?(loaded_deps, dep) do\n      remove_dep(install_project_dir, dep)\n    end\n  end\n\n  defp remove_dep(install_project_dir, dep) do\n    build_lib_dir = Path.join([install_project_dir, \"_build\", \"dev\", \"lib\"])\n    deps_dir = Path.join(install_project_dir, \"deps\")\n\n    build_path = Path.join(build_lib_dir, dep)\n    File.rm_rf(build_path)\n    dep_path = Path.join(deps_dir, dep)\n    File.rm_rf(dep_path)\n  end\n\n  defp install_project_dir(cache_id) do\n    install_root =\n      System.get_env(\"MIX_INSTALL_DIR\") ||\n        Path.join(Mix.Utils.mix_cache(), \"installs\")\n\n    version = \"ex-#{System.version()}-erl-#{:erlang.system_info(:version)}\"\n    Path.join([install_root, version, cache_id])\n  end\n\n  defp install_project_config(dynamic_config) do\n    [\n      version: \"1.0.0\",\n      build_per_environment: true,\n      build_path: \"_build\",\n      lockfile: \"mix.lock\",\n      deps_path: \"deps\",\n      app: @mix_install_app,\n      erlc_paths: [],\n      elixirc_paths: [],\n      prune_code_paths: false\n    ] ++ dynamic_config\n  end\n\n  @doc false\n  def in_install_project(fun) do\n    case safe_get_installed() do\n      {id, dynamic_config} ->\n        config = install_project_config(dynamic_config)\n\n        install_project_dir = install_project_dir(id)\n\n        File.cd!(install_project_dir, fn ->\n          :ok = Mix.ProjectStack.push(@mix_install_project, config, \"nofile\")\n\n          try do\n            fun.()\n          after\n            Mix.ProjectStack.pop()\n          end\n        end)\n\n      nil ->\n        Mix.raise(\"trying to call Mix.in_install_project/1, but Mix.install/2 was never called\")\n    end\n  end\n\n  @doc \"\"\"\n  Returns the directory where the current `Mix.install/2` project\n  resides.\n  \"\"\"\n  @doc since: \"1.16.2\"\n  @spec install_project_dir() :: Path.t() | nil\n  def install_project_dir() do\n    case safe_get_installed() do\n      {id, _dynamic_config} -> install_project_dir(id)\n      nil -> nil\n    end\n  end\n\n  @doc \"\"\"\n  Returns whether `Mix.install/2` was called in the current node.\n  \"\"\"\n  @doc since: \"1.13.0\"\n  @spec installed?() :: boolean()\n  def installed? do\n    safe_get_installed() != nil\n  end\n\n  defp safe_get_installed() do\n    if mix_started?() do\n      Mix.State.get(:installed)\n    end\n  end\n\n  defp mix_started?() do\n    Process.whereis(Mix.State) != nil\n  end\n\n  defp stop_apps([]), do: :ok\n\n  defp stop_apps(apps) do\n    :logger.add_primary_filter(:silence_app_exit, {&silence_app_exit/2, []})\n    Enum.each(apps, fn {app, _, _} -> Application.stop(app) end)\n    :logger.remove_primary_filter(:silence_app_exit)\n    :ok\n  end\n\n  defp silence_app_exit(\n         %{\n           msg:\n             {:report,\n              %{\n                label: {:application_controller, :exit},\n                report: [application: _, exited: :stopped] ++ _\n              }}\n         },\n         _extra\n       ) do\n    :stop\n  end\n\n  defp silence_app_exit(_message, _extra) do\n    :ignore\n  end\n\n  defp maybe_expand_path_dep(opts) do\n    if Keyword.has_key?(opts, :path) do\n      Keyword.update!(opts, :path, &Path.expand/1)\n    else\n      opts\n    end\n  end\n\n  @doc false\n  def install?, do: Mix.Project.get() == @mix_install_project\nend\n"
  },
  {
    "path": "lib/mix/mix.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\ndefmodule Mix.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :mix,\n      build_per_environment: false,\n      version: System.version(),\n      escript: [main_module: Mix.CLI]\n    ]\n  end\n\n  def application do\n    [\n      registered: [Mix.State, Mix.TasksServer, Mix.ProjectStack],\n      mod: {Mix, []},\n      env: [colors: []]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/.gitignore",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\n# Remember to update Makefile \"clean_residual_files\" target for any modifications\n# made in this file.\n/deps_on_git_repo/\n/git_rebar/\n/git_repo/\n/git_sparse_repo/\n/archive/ebin/\n"
  },
  {
    "path": "lib/mix/test/fixtures/archive/invalid-archive-0.1.0.ez",
    "content": ""
  },
  {
    "path": "lib/mix/test/fixtures/archive/lib/local.sample.ex",
    "content": "defmodule Mix.Tasks.Local.Sample do\n  use Mix.Task\n\n  @shortdoc \"A local install sample\"\n  @moduledoc \"A local install sample\"\n\n  def run(_) do\n    Mix.shell().info(\"sample\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/archive/priv/.dot_file",
    "content": ""
  },
  {
    "path": "lib/mix/test/fixtures/compile_erlang/include/r.hrl",
    "content": "-record(r, {cell=undefined})."
  },
  {
    "path": "lib/mix/test/fixtures/compile_erlang/src/b.erl",
    "content": "-module(b).\n-export([z/0]).\n-compile({nowarn_unused_function, []}).\n\n-callback b() -> term().\n-record(br, {cell=undefined}).\n\nz() -> #br{cell=specified}.\n"
  },
  {
    "path": "lib/mix/test/fixtures/compile_erlang/src/c.erl",
    "content": "-module(c).\n-export([b/0]).\n-compile([{nowarn_unused_function, []}]).\n\n-include(\"r.hrl\").\n-behaviour(b).\n\nb() -> #r{cell=specified}.\n"
  },
  {
    "path": "lib/mix/test/fixtures/compile_erlang/src/z.erl",
    "content": "%% Have modules flowing in both directions to check for topsort\n-module(z).\n-callback z() -> term().\n"
  },
  {
    "path": "lib/mix/test/fixtures/compile_leex/src/test_ok.xrl",
    "content": "Definitions.\n\nAdd         = (\\+|-)\n\nNumber      = [0-9]\n\nRules.\n\n{Add}                    : make_token(add_op,  TokenLine, TokenChars).\n\n{Number}+                : make_token(integer, TokenLine, TokenChars, fun erlang:list_to_integer/1).\n\nErlang code.\n\nmake_token(Name, Line, Chars) when is_list(Chars) ->\n    {token, {Name, Line, list_to_atom(Chars)}};\nmake_token(Name, Line, Chars) ->\n    {token, {Name, Line, Chars}}.\n\nmake_token(Name, Line, Chars, Fun) ->\n    {token, {Name, Line, Fun(Chars)}}.\n\nendls(Chars) ->\n    lists:filter(fun (C) -> C == $\\n orelse C == $; end, Chars).\n\nis_reserved(\"if\")      -> true;\nis_reserved(_)         -> false.\n"
  },
  {
    "path": "lib/mix/test/fixtures/compile_listeners/deps/reloader/lib/reloader.ex",
    "content": "defmodule Reloader do\n  use GenServer\n\n  def start_link(_opts) do\n    GenServer.start_link(__MODULE__, {})\n  end\n\n  @impl true\n  def init({}) do\n    {:ok, {}}\n  end\n\n  @impl true\n  def handle_info({:modules_compiled, info}, state) do\n    %{\n      modules_diff: %{added: added, changed: changed, removed: removed, timestamp: _timestamp},\n      app: app,\n      scm: scm,\n      os_pid: os_pid\n    } = info\n\n    IO.write(\"\"\"\n    Received :modules_compiled with\n      added: #{inspect(Enum.sort(added))}, changed: #{inspect(Enum.sort(changed))}, removed: #{inspect(Enum.sort(removed))}\n      app: #{inspect(app)}\n      scm: #{inspect(scm)}\n      os_pid: #{inspect(os_pid)}\n    \"\"\")\n\n    {:noreply, state}\n  end\n\n  def handle_info({:dep_compiled, info}, state) do\n    %{\n      app: app,\n      scm: scm,\n      manager: manager,\n      os_pid: os_pid\n    } = info\n\n    IO.write(\"\"\"\n    Received :dep_compiled with\n      app: #{inspect(app)}\n      scm: #{inspect(scm)}\n      manager: #{inspect(manager)}\n      os_pid: #{inspect(os_pid)}\n    \"\"\")\n\n    {:noreply, state}\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/compile_listeners/deps/reloader/mix.exs",
    "content": "defmodule Reloader.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :reloader,\n      version: \"0.1.0\"\n    ]\n  end\n\n  def application do\n    [\n      extra_applications: [:logger]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/compile_yecc/src/test_ok.yrl",
    "content": "Nonterminals\n    Elements\n    Value\n    IfBlock\n    IfBraced\n    IfExpression\n    ElseBraced\n    EndIfBraced.\n\nTerminals\n    close_tag\n    endif_keyword\n    if_keyword\n    else_keyword\n    open_tag\n    not_keyword\n    text.\n\nRootsymbol\n    Elements.\n\nValue -> '$empty' : [].\n\nElements -> '$empty' : [].\nElements -> Elements text : '$1' ++ ['$2'].\nElements -> Elements IfBlock : '$1' ++ ['$2'].\n\nIfBlock -> IfBraced Elements ElseBraced Elements EndIfBraced : {ifelse, '$1', '$2', '$4'}.\nIfBlock -> IfBraced Elements EndIfBraced : {'if', '$1', '$2'}.\n\nIfBraced -> open_tag if_keyword IfExpression close_tag : '$3'.\nIfExpression -> not_keyword IfExpression : {'not', '$2'}.\nIfExpression -> Value : '$1'.\n\nElseBraced -> open_tag else_keyword close_tag.\nEndIfBraced -> open_tag endif_keyword close_tag.\n"
  },
  {
    "path": "lib/mix/test/fixtures/config.exs",
    "content": "import Config\n\nconfig :my_app, :key, :value\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_cycle/app1/mix.exs",
    "content": "defmodule App1 do\n  use Mix.Project\n\n  def project do\n    [\n      app: :app1,\n      version: \"0.1.0\",\n      deps: [\n        {:app2, \"0.1.0\", in_umbrella: true}\n      ]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_cycle/app2/mix.exs",
    "content": "defmodule App2 do\n  use Mix.Project\n\n  def project do\n    [\n      app: :app2,\n      version: \"0.1.0\",\n      deps: [\n        {:app1, \"0.1.0\", in_umbrella: true}\n      ]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/_build/dev/lib/invalidapp/ebin/invalidapp.app",
    "content": "{application, invalidsomethingelse, [\n  {vsn,\"0.1.0\"}\n]}."
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/_build/dev/lib/invalidvsn/ebin/invalidvsn.app",
    "content": "{application, invalidvsn, [\n  {vsn,ok}\n]}."
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/_build/dev/lib/nosemver/ebin/nosemver.app",
    "content": "{application, nosemver, [\n  {vsn,\"0.7\"}\n]}."
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/_build/dev/lib/ok/ebin/ok.app",
    "content": "{application, ok, [\n  {vsn,\"0.1.0\"}\n]}."
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/custom/bad_deps_repo/mix.exs",
    "content": "defmodule BadDepsRepo do\n  use Mix.Project\n\n  def project do\n    [\n      app: :bad_deps_repo,\n      version: \"0.1.0\",\n      deps: [\n        {:git_repo, \"0.0.0\", git: MixTest.Case.fixture_path(\"bad_git_repo\")}\n      ]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/custom/deps_repo/mix.exs",
    "content": "defmodule DepsRepo do\n  use Mix.Project\n\n  def project do\n    opts = Process.get(:custom_deps_git_repo_opts) || []\n\n    [\n      app: :deps_repo,\n      version: \"0.1.0\",\n      deps: [{:git_repo, \"0.1.0\", [git: MixTest.Case.fixture_path(\"git_repo\")] ++ opts}]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/custom/noscm_repo/mix.exs",
    "content": "defmodule NoSCMRepo do\n  use Mix.Project\n\n  def project do\n    [\n      app: :noscm_repo,\n      version: \"0.1.0\",\n      deps: [\n        {:git_repo, \"0.1.0\"}\n      ]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/custom/raw_repo/lib/raw_repo.ex",
    "content": "Application.compile_env(:anyapp, :anything)\n\ndefmodule RawRepo do\n  def hello do\n    \"world\"\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/custom/raw_repo/mix.exs",
    "content": "defmodule RawRepo.MixProject do\n  use Mix.Project\n\n  def project do\n    Mix.shell().info(\":raw_repo env is #{Mix.env()}\")\n    [app: :raw_repo, version: \"0.1.0\"]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/deps/invalidapp/mix.exs",
    "content": "defmodule InvalidApp.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :invalidapp,\n      version: \"1.0\"\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/deps/invalidvsn/.gitkeep",
    "content": ""
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/deps/nosemver/.gitkeep",
    "content": ""
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/deps/ok/mix.exs",
    "content": "defmodule Ok.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :ok,\n      version: \"0.1.0\"\n    ]\n  end\n\n  def application do\n    [\n      extra_applications: [:logger]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/deps_status/deps/ok/priv/sample",
    "content": "SAMPLE"
  },
  {
    "path": "lib/mix/test/fixtures/escript_test/config/config.exs",
    "content": "import Config\n\nconfig :escript_test, erl_val: \"Erlang value\"\n"
  },
  {
    "path": "lib/mix/test/fixtures/escript_test/lib/escript_test.ex",
    "content": "defmodule EscriptTest do\n  def start do\n    :ok = Application.start(:escript_test)\n  end\n\n  def main([\"--protocol\", protocol]) do\n    IO.puts(Protocol.consolidated?(Module.concat([protocol])))\n  end\n\n  def main([\"--nesting\"]) do\n    IO.inspect(Application.get_env(:foobar, :nesting, \"TEST\"))\n  end\n\n  def main([\"--app-paths\"]) do\n    elixir_path = Application.app_dir(:elixir) |> String.to_charlist()\n    escript_test_path = Application.app_dir(:escript_test) |> String.to_charlist()\n\n    IO.inspect({\n      elixir_path != escript_test_path,\n      match?({:ok, _}, :erl_prim_loader.list_dir(elixir_path)),\n      match?({:ok, _}, :erl_prim_loader.list_dir(escript_test_path))\n    })\n  end\n\n  def main([\"--list-priv\", app_name]) do\n    # Note: :erl_prim_loader usage with Escript is currently deprecated,\n    # but we use it only in tests for convenience\n\n    app = String.to_atom(app_name)\n    :erl_prim_loader.list_dir(~c\"#{:code.lib_dir(app)}/priv\") |> IO.inspect()\n  end\n\n  @parent Application.compile_env(:foobar, :parent, \"NIL\")\n\n  def main([\"--config\"]) do\n    IO.puts([\"VALUE=\", Application.get_env(:foobar, :value, \"TEST\")])\n    IO.puts([\"PARENT=\", @parent])\n  end\n\n  def main(_argv) do\n    IO.puts(Application.get_env(:foobar, :value, \"TEST\"))\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/escript_test/priv/hello/world.txt",
    "content": "Hello World"
  },
  {
    "path": "lib/mix/test/fixtures/escript_test/src/escript_test.erl",
    "content": "-module(escript_test).\n\n-export([start/0, main/1]).\n\n\nstart() ->\n    ok = application:start(escript_test).\n\nmain(Args) ->\n    io:format(\"~p\", [Args]).\n"
  },
  {
    "path": "lib/mix/test/fixtures/no_mixfile/lib/a.ex",
    "content": "defmodule A do\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/no_mixfile/lib/b.ex",
    "content": "defmodule B do\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/rebar_dep/rebar.config",
    "content": "{erl_opts, [warnings_as_errors]}.\n{project_plugins, [remove_me]}.\n"
  },
  {
    "path": "lib/mix/test/fixtures/rebar_dep/rebar.config.script",
    "content": "CFG1 = CONFIG ++\n[{'SCRIPT', SCRIPT}] ++\n[{deps, [{git_rebar, \"0.1..*\", {git, filename:absname(\"../../test/fixtures/git_rebar\"), main}}]}].\n\ncase {os:getenv(\"FILE_FROM_ENV\"), os:getenv(\"CONTENTS_FROM_ENV\")} of\n  {false, _} -> ok;\n  {File, Contents} -> file:write_file(File, [Contents])\nend,\nCFG1.\n"
  },
  {
    "path": "lib/mix/test/fixtures/rebar_dep/src/rebar_dep.app.src",
    "content": "{application, rebar_dep,\n  [\n    {vsn, \"0.1.0\"}\n  ]}.\n"
  },
  {
    "path": "lib/mix/test/fixtures/rebar_dep/src/rebar_dep.erl",
    "content": "-module(rebar_dep).\n\n-export ([any_function/0]).\n\nany_function() ->\n    ok.\n"
  },
  {
    "path": "lib/mix/test/fixtures/rebar_dep_script/rebar.config",
    "content": ""
  },
  {
    "path": "lib/mix/test/fixtures/rebar_dep_script/rebar.config.script",
    "content": "[{'dir', file:get_cwd()}].\n"
  },
  {
    "path": "lib/mix/test/fixtures/rebar_override/rebar.config.script",
    "content": "[\n  {deps, [\n    {git_rebar, {git, filename:absname(\"../../test/fixtures/git_rebar\")}}\n  ]},\n  {overrides, [\n    {override, git_rebar, [{deps, [{git_repo, {git, filename:absname(\"../../test/fixtures/git_repo\")}}]}]}\n  ]}\n].\n"
  },
  {
    "path": "lib/mix/test/fixtures/release_test/config/config.exs",
    "content": "import Config\n\nconfig :release_test, :static, :was_set\nconfig :release_test, :encoding, {:_μ, :\"£\", \"£\", ~c\"£\"}\n"
  },
  {
    "path": "lib/mix/test/fixtures/release_test/lib/release_test.ex",
    "content": "defmodule ReleaseTest do\n  use Application\n\n  def start(_type, _args) do\n    cookie = System.get_env(\"RELEASE_COOKIE\")\n    {:ok, [[sys_config]]} = :init.get_argument(:config)\n\n    info = %{\n      app_dir: Application.app_dir(:release_test),\n      cookie_env: cookie,\n      encoding: Application.get_env(:release_test, :encoding),\n      mode: :code.get_mode(),\n      node: node(),\n      protocols_consolidated?: Protocol.consolidated?(Enumerable),\n      release_name: System.get_env(\"RELEASE_NAME\"),\n      release_mode: System.get_env(\"RELEASE_MODE\"),\n      release_node: System.get_env(\"RELEASE_NODE\"),\n      release_root: System.get_env(\"RELEASE_ROOT\"),\n      release_vsn: System.get_env(\"RELEASE_VSN\"),\n      release_prog: System.get_env(\"RELEASE_PROG\"),\n      root_dir: :code.root_dir() |> to_string(),\n      runtime_config: Application.fetch_env(:release_test, :runtime),\n      static_config: Application.fetch_env(:release_test, :static),\n      sys_config_env: System.get_env(\"RELEASE_SYS_CONFIG\"),\n      sys_config_init: to_string(sys_config)\n    }\n\n    path = Path.join(System.get_env(\"RELEASE_ROOT\"), \"RELEASE_BOOTED\")\n    File.write!(path, :erlang.term_to_binary(info))\n\n    if System.get_env(\"BOOTED_ONCE\") do\n      IO.puts(\"RESTARTED!!!\")\n    else\n      System.put_env(\"BOOTED_ONCE\", \"1\")\n    end\n\n    if System.get_env(\"RELEASE_NAME\") =~ \"permanent\" do\n      Supervisor.start_link([], strategy: :one_for_one)\n    else\n      System.halt(0)\n    end\n  end\n\n  def hello_world do\n    IO.puts(\"hello world\")\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/release_test/mix.exs",
    "content": "defmodule ReleaseTest.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :release_test,\n      version: \"0.1.0\"\n    ]\n  end\n\n  def application do\n    [\n      extra_applications: [:logger, :runtime_tools],\n      mod: {ReleaseTest, []}\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/release_test/priv/hello",
    "content": "world"
  },
  {
    "path": "lib/mix/test/fixtures/test_failed/mix.exs",
    "content": "defmodule TestFailed.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :test_only_failures,\n      version: \"0.0.1\",\n      test_load_filters: [~r/.*_test_failed\\.exs/]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_failed/test/only_failing_test_failed.exs",
    "content": "defmodule OnlyFailingTest do\n  use ExUnit.Case\n\n  test \"fails\", do: assert(System.get_env(\"PASS_FAILING_TESTS\"))\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_failed/test/only_passing_test_failed.exs",
    "content": "IO.puts(\"loading OnlyPassingTest\")\n\ndefmodule OnlyPassingTest do\n  use ExUnit.Case\n\n  test \"passes\", do: assert(1 == 1)\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_failed/test/passing_and_failing_test_failed.exs",
    "content": "defmodule PassingAndFailingTest do\n  use ExUnit.Case\n\n  @tag :foo\n  test \"fails\", do: assert(System.get_env(\"PASS_FAILING_TESTS\"))\n\n  @tag :foo\n  test \"passes\", do: assert(1 == 1)\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_failed/test/test_helper.exs",
    "content": "ExUnit.start()\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_stale/lib/a.ex",
    "content": "defmodule A do\n  def f, do: :ok\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_stale/lib/b.ex",
    "content": "defmodule B do\n  def f, do: A.f()\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_stale/mix.exs",
    "content": "defmodule TestStale.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :test_stale,\n      version: \"0.0.1\",\n      test_load_filters: [fn file -> String.ends_with?(file, \"_test_stale.exs\") end]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_stale/test/a_test_stale.exs",
    "content": "defmodule ATest do\n  use ExUnit.Case\n\n  test \"f\" do\n    assert A.f() == :ok\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_stale/test/b_test_stale.exs",
    "content": "defmodule BTest do\n  use ExUnit.Case\n\n  test \"f\" do\n    assert B.f() == :ok\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/test_stale/test/test_helper.exs",
    "content": "ExUnit.start()\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_dep/deps/umbrella/apps/bar/lib/bar.ex",
    "content": "defmodule Bar do\n  def bar do\n    \"hello world\"\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_dep/deps/umbrella/apps/bar/mix.exs",
    "content": "defmodule Bar.MixProject do\n  use Mix.Project\n\n  def project do\n    Mix.shell().info(\":bar env is #{Mix.env()}\")\n\n    [\n      app: :bar,\n      version: \"0.1.0\",\n      deps: [{:foo, in_umbrella: true}]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_dep/deps/umbrella/apps/dont_error_on_files",
    "content": ""
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_dep/deps/umbrella/apps/dont_error_on_missing_mixfile/.gitkeep",
    "content": ""
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_dep/deps/umbrella/apps/foo/lib/foo.ex",
    "content": "defmodule Foo do\n  def foo do\n    \"bye world\"\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_dep/deps/umbrella/apps/foo/mix.exs",
    "content": "defmodule Foo.MixProject do\n  use Mix.Project\n\n  def project do\n    Mix.shell().info(\":foo env is #{Mix.env()}\")\n\n    [\n      app: :foo,\n      version: \"0.1.0\"\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_dep/deps/umbrella/mix.exs",
    "content": "defmodule Umbrella.MixProject do\n  use Mix.Project\n\n  def project do\n    [apps_path: \"apps\"]\n  end\n\n  def application do\n    [extra_applications: [:runtime_tools]]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_dep/mix.exs",
    "content": "defmodule UmbrellaDep.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :umbrella_dep,\n      version: \"0.1.0\",\n      deps: deps()\n    ]\n  end\n\n  defp deps do\n    [\n      {:umbrella, path: \"deps/umbrella\"}\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/apps/bar/lib/bar.ex",
    "content": "defmodule Bar do\n  def hello do\n    :world\n  end\nend\n\ndefmodule Bar.Ignore do\n  def world do\n    :hello\n  end\nend\n\ndefprotocol Bar.Protocol do\n  def to_uppercase(string)\nend\n\ndefimpl Bar.Protocol, for: BitString do\n  def to_uppercase(string), do: String.upcase(string)\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/apps/bar/mix.exs",
    "content": "defmodule Bar.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :bar,\n      version: \"0.1.0\",\n      # Choose something besides *_test.exs so that these test files don't\n      # get accidentally swept up into the actual Mix test suite.\n      test_load_filters: [~r/.*_tests\\.exs/],\n      test_coverage: [ignore_modules: [Bar, ~r/Ignore/]],\n      aliases: [mytask: fn _ -> Mix.shell().info(\"bar_running\") end]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/apps/bar/test/bar_tests.exs",
    "content": "defmodule BarTest do\n  use ExUnit.Case\n\n  test \"greets the world\" do\n    assert Bar.hello() == :world\n  end\n\n  test \"world the greets\" do\n    assert Bar.Ignore.world() == :hello\n  end\n\n  @tag :maybe_skip\n  test \"works with protocols\" do\n    assert Bar.Protocol.to_uppercase(\"foo\") == \"FOO\"\n  end\n\n  test \"protocols are consolidated\" do\n    assert Protocol.consolidated?(Bar.Protocol)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/apps/bar/test/test_helper.exs",
    "content": "ExUnit.start()\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/apps/foo/lib/foo.ex",
    "content": "defmodule Foo do\n  def hello do\n    :world\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/apps/foo/mix.exs",
    "content": "defmodule Foo.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      app: :foo,\n      version: \"0.1.0\",\n      # Choose something besides *_test.exs so that these test files don't\n      # get accidentally swept up into the actual Mix test suite.\n      test_load_filters: [~r/.*_tests\\.exs/],\n      aliases: [mytask: fn _ -> Mix.shell().info(\"foo_running\") end]\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/apps/foo/test/foo_tests.exs",
    "content": "defmodule FooTest do\n  use ExUnit.Case\n\n  test \"greets the world\" do\n    assert Foo.hello() == :world\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/apps/foo/test/test_helper.exs",
    "content": "ExUnit.start()\n"
  },
  {
    "path": "lib/mix/test/fixtures/umbrella_test/mix.exs",
    "content": "defmodule UmbrellaTest.MixProject do\n  use Mix.Project\n\n  def project do\n    [\n      apps_path: \"apps\"\n    ]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/aliases_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.AliasesTest do\n  use MixTest.Case\n\n  defmodule Aliases do\n    def project do\n      [\n        aliases: [\n          h: \"hello\",\n          p: &inspect/1,\n          compile: \"hello\",\n          cmd: &call_cmd/1,\n          help: [\"help\", \"hello\"],\n          \"nested.h\": [&Mix.shell().info(inspect(&1)), \"h foo bar\"],\n          invalid_alias: [:not_a_string_or_function]\n        ]\n      ]\n    end\n\n    defp call_cmd(args), do: Mix.Task.run(\"cmd\", args)\n  end\n\n  setup do\n    Mix.Project.push(Aliases)\n    :ok\n  end\n\n  test \"runs string aliases\" do\n    assert Mix.Task.run(\"h\", []) == \"Hello, World!\"\n    assert Mix.Task.run(\"h\", []) == :noop\n    assert Mix.Task.run(\"hello\", []) == :noop\n\n    Mix.Task.reenable(\"h\")\n    Mix.Task.reenable(\"hello\")\n    assert Mix.Task.run(\"h\", [\"foo\", \"bar\"]) == \"Hello, foo bar!\"\n  end\n\n  test \"runs function aliases\" do\n    assert Mix.Task.run(\"p\", []) == \"[]\"\n    assert Mix.Task.run(\"p\", []) == :noop\n\n    Mix.Task.reenable(\"p\")\n    assert Mix.Task.run(\"p\", [\"foo\", \"bar\"]) == \"[\\\"foo\\\", \\\"bar\\\"]\"\n  end\n\n  test \"runs list aliases\" do\n    assert Mix.Task.run(\"nested.h\", [\"baz\"]) == \"Hello, foo bar baz!\"\n    assert_received {:mix_shell, :info, [\"[]\"]}\n  end\n\n  test \"fails for invalid aliases\" do\n    assert_raise Mix.Error, ~r/Invalid Mix alias format/, fn ->\n      Mix.Task.run(\"invalid_alias\", [])\n    end\n  end\n\n  test \"run alias override\" do\n    assert Mix.Task.run(\"compile\", []) == \"Hello, World!\"\n    assert Mix.Task.run(\"compile\", []) == :noop\n  end\n\n  test \"run alias override with name-recursion\" do\n    assert Mix.Task.rerun(\"help\", []) == \"Hello, World!\"\n    assert_received {:mix_shell, :info, [\"mix test\" <> _]}\n\n    # Arguments are passed to the recursive task and not the last one.\n    assert ExUnit.CaptureIO.capture_io(fn ->\n             Mix.Task.rerun(\"help\", [\"test\"])\n           end) =~ \"mix test\"\n  end\n\n  test \"run alias override with code-recursion\" do\n    assert Mix.Task.rerun(\"cmd\", [\"echo\", \"hello\"]) == :ok\n    assert_received {:mix_shell, :run, [\"hello\" <> _]}\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/cli_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.CLITest do\n  use MixTest.Case\n\n  @moduletag :tmp_dir\n\n  test \"default task\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.write!(\"mix.exs\", \"\"\"\n      defmodule P do\n        use Mix.Project\n        def project, do: [app: :p, version: \"0.1.0\"]\n      end\n      \"\"\")\n\n      mix(~w[])\n      assert File.regular?(\"_build/dev/lib/p/ebin/Elixir.A.beam\")\n    end)\n  end\n\n  test \"custom default task\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.write!(\"mix.exs\", \"\"\"\n      defmodule P do\n        use Mix.Project\n        def cli, do: [default_task: \"oops\"]\n        def project, do: [app: :p, version: \"0.1.0\"]\n      end\n      \"\"\")\n\n      assert mix(~w[]) =~ \"The task \\\"oops\\\" could not be found\"\n    end)\n  end\n\n  test \"Mix.raise/2 can set exit status\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"mix.exs\", \"\"\"\n      defmodule MyProject do\n        use Mix.Project\n\n        def project do\n          [app: :my_project, version: \"0.0.1\", aliases: aliases()]\n        end\n\n        defp aliases do\n          [\n            custom: &error(&1, exit_status: 99),\n          ]\n        end\n\n        defp error(_args, opts), do: Mix.raise(\"oops\", opts)\n      end\n      \"\"\")\n\n      assert {_, 99} = mix_code(~w[custom])\n    end)\n  end\n\n  test \"compiles and invokes simple task from CLI\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"mix.exs\", \"\"\"\n      defmodule MyProject do\n        use Mix.Project\n\n        def project do\n          [app: :my_project, version: \"0.0.1\"]\n        end\n\n        def hello_world do\n          \"Hello from MyProject!\"\n        end\n      end\n      \"\"\")\n\n      File.write!(\"lib/hello.ex\", \"\"\"\n      defmodule Mix.Tasks.MyHello do\n        use Mix.Task\n\n        @shortdoc \"Says hello\"\n\n        def run(_) do\n          IO.puts(Mix.Project.get!().hello_world())\n          Mix.shell().info(\"This won't appear\")\n          Mix.raise(\"oops\")\n        end\n      end\n      \"\"\")\n\n      contents = mix(~w[my_hello], [{\"MIX_QUIET\", \"1\"}])\n      assert contents =~ \"Hello from MyProject!\\n\"\n      refute contents =~ \"This won't appear\"\n\n      contents = mix(~w[my_hello], [{\"MIX_QUIET\", \"0\"}])\n      assert contents =~ \"Hello from MyProject!\\n\"\n      assert contents =~ \"This won't appear\"\n\n      contents = mix(~w[my_hello], [{\"MIX_DEBUG\", \"1\"}])\n      assert contents =~ \"-> Running mix my_hello (inside MyProject)\"\n      assert contents =~ \"** (Mix.Error) oops\"\n\n      contents = mix(~w[my_hello], [{\"MIX_DEBUG\", \"0\"}])\n      refute contents =~ \"-> Running mix my_hello (inside MyProject)\"\n      refute contents =~ \"** (Mix.Error) oops\"\n    end)\n  end\n\n  test \"no task error\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      contents = mix(~w[no_task])\n      assert contents =~ \"** (Mix) The task \\\"no_task\\\" could not be found\"\n    end)\n  end\n\n  test \"tasks with slashes raise NoTaskError\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      contents = mix(~w[my/task])\n      assert contents =~ \"** (Mix) The task \\\"my/task\\\" could not be found\"\n    end)\n  end\n\n  test \"--help smoke test\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      output = mix(~w[--help])\n      assert output =~ \"Mix is a build tool for Elixir\"\n      assert output =~ \"mix help TASK\"\n    end)\n  end\n\n  test \"--version smoke test\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      output = mix(~w[--version])\n      assert output =~ ~r/Erlang.+\\n\\nMix [0-9\\.a-z]+/\n    end)\n  end\n\n  test \"env var config\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      File.write!(\"custom.exs\", \"\"\"\n      defmodule P do\n        use Mix.Project\n        def project, do: [app: :p, version: \"0.1.0\"]\n      end\n      \"\"\")\n\n      System.put_env(\"MIX_ENV\", \"prod\")\n      System.put_env(\"MIX_TARGET\", \"rpi\")\n      System.put_env(\"MIX_EXS\", \"custom.exs\")\n\n      inspect = \"IO.inspect {Mix.env(), Mix.target(), System.argv()}\"\n      output = mix([\"run\", \"-e\", inspect, \"--\", \"1\", \"2\", \"3\"])\n      assert output =~ ~s({:prod, :rpi, [\"1\", \"2\", \"3\"]})\n    end)\n  after\n    System.delete_env(\"MIX_ENV\")\n    System.delete_env(\"MIX_TARGET\")\n    System.delete_env(\"MIX_EXS\")\n  end\n\n  test \"cli config\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      File.write!(\"custom.exs\", \"\"\"\n      defmodule P do\n        use Mix.Project\n        def project, do: [app: :p, version: \"0.1.0\"]\n        def cli, do: [default_env: :prod, default_target: :rpi]\n      end\n      \"\"\")\n\n      System.put_env(\"MIX_EXS\", \"custom.exs\")\n\n      inspect = \"IO.inspect {Mix.env(), Mix.target(), System.argv()}\"\n      output = mix([\"run\", \"-e\", inspect, \"--\", \"1\", \"2\", \"3\"])\n      assert output =~ ~s({:prod, :rpi, [\"1\", \"2\", \"3\"]})\n    end)\n  after\n    System.delete_env(\"MIX_EXS\")\n  end\n\n  test \"preferred cli config\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      File.write!(\"custom.exs\", \"\"\"\n      defmodule P do\n        use Mix.Project\n\n        def cli do\n          [\n            default_env: :not_prod,\n            default_target: :not_rpi,\n            preferred_envs: [test_task: :prod],\n            preferred_targets: [test_task: :rpi]\n          ]\n        end\n\n        def project, do: [app: :p, version: \"0.1.0\"]\n      end\n\n      defmodule Mix.Tasks.TestTask do\n        use Mix.Task\n\n        def run(args) do\n          IO.inspect {Mix.env(), Mix.target(), args}\n        end\n      end\n      \"\"\")\n\n      System.put_env(\"MIX_EXS\", \"custom.exs\")\n\n      output = mix([\"test_task\", \"a\", \"b\", \"c\"])\n      assert output =~ ~s({:prod, :rpi, [\"a\", \"b\", \"c\"]})\n    end)\n  after\n    System.delete_env(\"MIX_EXS\")\n  end\n\n  test \"env config and target use defaults when empty\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      File.write!(\"custom.exs\", \"\"\"\n      defmodule P do\n        use Mix.Project\n        def project, do: [app: :p, version: \"0.1.0\"]\n      end\n      \"\"\")\n\n      System.put_env(\"MIX_ENV\", \"\")\n      System.put_env(\"MIX_TARGET\", \"\")\n      System.put_env(\"MIX_EXS\", \"custom.exs\")\n\n      inspect = \"IO.inspect {Mix.env(), Mix.target(), System.argv()}\"\n      output = mix([\"run\", \"-e\", inspect, \"--\", \"a\", \"b\"])\n      assert output =~ ~s({:dev, :host, [\"a\", \"b\"]})\n    end)\n  after\n    System.delete_env(\"MIX_ENV\")\n    System.delete_env(\"MIX_TARGET\")\n    System.delete_env(\"MIX_EXS\")\n  end\n\n  @tag :cover\n  @tag tmp_dir: \"new_with_tests\"\n  test \"new with tests and cover\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      output = mix(~w[new .])\n      assert output =~ \"* creating lib/new_with_tests.ex\"\n\n      output = mix(~w[test test/new_with_tests_test.exs --cover])\n      assert File.regular?(\"_build/test/lib/new_with_tests/ebin/Elixir.NewWithTests.beam\")\n      assert output =~ \"Result: 2 passed (1 doctest, 1 test)\"\n      assert output =~ \"Generating cover results ...\"\n      assert File.regular?(\"cover/Elixir.NewWithTests.html\")\n    end)\n  end\n\n  @tag tmp_dir: \"sup_with_tests\"\n  test \"new --sup with tests\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      output = mix(~w[new --sup .])\n      assert output =~ \"* creating lib/sup_with_tests.ex\"\n\n      output = mix(~w[test])\n      assert File.regular?(\"_build/test/lib/sup_with_tests/ebin/Elixir.SupWithTests.beam\")\n      assert output =~ \"Result: 2 passed (1 doctest, 1 test)\"\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/dep/converger_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Dep.ConvergerTest do\n  use MixTest.Case\n\n  describe \"topological_sort\" do\n    test \"raises if there is a cycle in the dependency graph\" do\n      app1 = %Mix.Dep{app: :app1}\n      app2 = %Mix.Dep{app: :app2}\n      app3 = %Mix.Dep{app: :app3}\n\n      deps = [\n        # not really part of the cycle, just depend on it\n        %Mix.Dep{app: :app5, deps: [app1, app3]},\n        %Mix.Dep{app: :app4, deps: [app2]},\n\n        # cycle\n        %{app1 | deps: [app2]},\n        %{app2 | deps: [app3]},\n        %{app3 | deps: [app1]}\n      ]\n\n      assert_raise Mix.Error,\n                   \"Could not sort dependencies. \" <>\n                     \"The following dependencies form a cycle: app1, app2, app3\",\n                   fn -> Mix.Dep.Converger.topological_sort(deps) end\n    end\n\n    test \"raises if an app depends upon itself\" do\n      app = %Mix.Dep{app: :self_dependent}\n      deps = [%{app | deps: [app]}]\n\n      assert_raise Mix.Error,\n                   \"App self_dependent lists itself as a dependency\",\n                   fn -> Mix.Dep.Converger.topological_sort(deps) end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/dep/lock_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Dep.LockTest do\n  use MixTest.Case\n\n  setup do\n    Mix.Project.push(MixTest.Case.Sample)\n    :ok\n  end\n\n  test \"creates new lock and manifest files\", context do\n    in_tmp(context.test, fn ->\n      Mix.Dep.Lock.write(%{foo: :bar})\n      assert File.regular?(\"mix.lock\")\n      assert File.regular?(\"_build/dev/lib/sample/.mix/compile.lock\")\n    end)\n  end\n\n  test \"formats each dep on its own line for better conflict handling\", context do\n    in_tmp(context.test, fn ->\n      Mix.Dep.Lock.write(%{\n        foo: {:hex, :foo, \"0.1.0\"},\n        bar: {:hex, :bar, \"0.1.0\"}\n      })\n\n      assert File.read!(\"mix.lock\") == ~S\"\"\"\n             %{\n               \"bar\": {:hex, :bar, \"0.1.0\"},\n               \"foo\": {:hex, :foo, \"0.1.0\"},\n             }\n             \"\"\"\n    end)\n  end\n\n  test \"does not touch manifest file there is no change\", context do\n    in_tmp(context.test, fn ->\n      Mix.Dep.Lock.write(%{foo: :bar, bar: :bat})\n      File.rm!(\"_build/dev/lib/sample/.mix/compile.lock\")\n\n      Mix.Dep.Lock.write(%{bar: :bat, foo: :bar})\n      refute File.regular?(\"_build/dev/lib/sample/.mix/compile.lock\")\n    end)\n  end\n\n  test \"raises a proper error if check_locked opt is true and there are changes\", context do\n    in_tmp(context.test, fn ->\n      Mix.Dep.Lock.write(%{foo: :bar})\n\n      Mix.Dep.Lock.write(%{foo: :bar}, check_locked: true)\n\n      assert_raise Mix.Error,\n                   ~r/Your mix\\.lock is out of date and must be updated without the --check-locked flag/,\n                   fn ->\n                     Mix.Dep.Lock.write(%{foo: :bar, bar: :bat}, check_locked: true)\n                   end\n    end)\n  end\n\n  test \"raises a proper error for merge conflicts\", context do\n    in_tmp(context.test, fn ->\n      File.write(\"mix.lock\", ~S\"\"\"\n      %{\n        \"dep\": {:hex, :dep, \"0.1.0\"},\n      <<<<<<< HEAD\n        \"foo\": {:hex, :foo, \"0.1.0\"},\n      =======\n        \"bar\": {:hex, :bar, \"0.1.0\"},\n      >>>>>>> foobar\n        \"baz\": {:hex, :baz, \"0.1.0\"},\n      }\n      \"\"\")\n\n      assert_raise Mix.Error, ~r/Your mix\\.lock contains merge conflicts/, fn ->\n        Mix.Dep.Lock.read()\n      end\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/dep_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.DepTest do\n  use MixTest.Case\n\n  defmodule DepsApp do\n    def project do\n      [\n        app: :deps_app,\n        deps: [\n          {:ok, \"0.1.0\", path: \"deps/ok\"},\n          {:invalidvsn, \"0.2.0\", path: \"deps/invalidvsn\"},\n          {:invalidapp, \"0.1.0\", path: \"deps/invalidapp\"},\n          {:noappfile, \"0.1.0\", path: \"deps/noappfile\"},\n          {:uncloned, git: \"https://github.com/elixir-lang/uncloned.git\"},\n          {:optional, git: \"https://github.com/elixir-lang/optional.git\", optional: true}\n        ]\n      ]\n    end\n  end\n\n  defmodule ProcessDepsApp do\n    def project do\n      [app: :process_deps_app, deps: Process.get(:mix_deps)]\n    end\n  end\n\n  defp with_deps(deps, fun) do\n    Process.put(:mix_deps, deps)\n    Mix.Project.push(ProcessDepsApp)\n    fun.()\n  after\n    Mix.Project.pop()\n  end\n\n  defp assert_wrong_dependency(deps) do\n    with_deps(deps, fn ->\n      assert_raise Mix.Error, ~r\"Dependency specified in the wrong format\", fn ->\n        Mix.Dep.Converger.converge([])\n      end\n    end)\n  end\n\n  test \"clear deps cache\" do\n    Mix.Project.push(DepsApp)\n\n    Mix.Dep.cached()\n    key = {:cached_deps, DepsApp}\n\n    {env_target, deps} = Mix.State.read_cache(key)\n    assert env_target == {Mix.env(), Mix.target()}\n    assert length(deps) == 6\n\n    Mix.Dep.clear_cached()\n    refute Mix.State.read_cache(key)\n  end\n\n  test \"extracts all dependencies from the given project\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      deps = Mix.Dep.Converger.converge([])\n      assert length(deps) == 6\n      assert Enum.find(deps, &match?(%Mix.Dep{app: :ok, status: {:ok, _}}, &1))\n      assert Enum.find(deps, &match?(%Mix.Dep{app: :invalidvsn, status: {:invalidvsn, :ok}}, &1))\n      assert Enum.find(deps, &match?(%Mix.Dep{app: :invalidapp, status: {:invalidapp, _}}, &1))\n      assert Enum.find(deps, &match?(%Mix.Dep{app: :noappfile, status: {:noappfile, {_, _}}}, &1))\n      assert Enum.find(deps, &match?(%Mix.Dep{app: :uncloned, status: {:unavailable, _}}, &1))\n      assert Enum.find(deps, &match?(%Mix.Dep{app: :optional, status: {:unavailable, _}}, &1))\n    end)\n  end\n\n  test \"extracts all dependencies paths/scms from the given project\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      apps = Mix.Project.deps_apps()\n      assert length(apps) == 6\n      assert :ok in apps\n      assert :uncloned in apps\n\n      paths = Mix.Project.deps_paths()\n      assert map_size(paths) == 6\n      assert paths[:ok] =~ \"deps/ok\"\n      assert paths[:uncloned] =~ \"deps/uncloned\"\n\n      scms = Mix.Project.deps_scms()\n      assert map_size(scms) == 6\n      assert scms[:ok] == Mix.SCM.Path\n      assert scms[:uncloned] == Mix.SCM.Git\n    end)\n  end\n\n  test \"fails on invalid dependencies\" do\n    assert_wrong_dependency([{:ok}])\n    assert_wrong_dependency([{:ok, nil}])\n    assert_wrong_dependency([{:ok, nil, []}])\n  end\n\n  test \"use requirements for dependencies\" do\n    deps = [{:ok, \"~> 0.1\", path: \"deps/ok\"}]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        deps = Mix.Dep.Converger.converge([])\n        assert Enum.find(deps, &match?(%Mix.Dep{app: :ok, status: {:ok, _}}, &1))\n      end)\n    end)\n  end\n\n  test \"raises when no SCM is specified\" do\n    deps = [{:ok, \"~> 0.1\", not_really: :ok}]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        send(self(), {:mix_shell_input, :yes?, false})\n        msg = \"Could not find an SCM for dependency :ok from Mix.DepTest.ProcessDepsApp\"\n        assert_raise Mix.Error, msg, fn -> Mix.Dep.Converger.converge([]) end\n      end)\n    end)\n  end\n\n  test \"does not set the manager before the dependency was loaded\" do\n    # It is important to not eagerly set the manager because the dependency\n    # needs to be loaded (i.e. available in the file system) in order to get\n    # the proper manager.\n    Mix.Project.push(DepsApp)\n\n    {_, true, _} =\n      Mix.Dep.Converger.converge(false, [], nil, fn dep, acc, lock ->\n        assert is_nil(dep.manager)\n        {dep, acc or true, lock}\n      end)\n  end\n\n  test \"raises on invalid deps req\" do\n    deps = [{:ok, \"+- 0.1.0\", path: \"deps/ok\"}]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        assert_raise Mix.Error, ~r\"Invalid requirement\", fn ->\n          Mix.Dep.Converger.converge([])\n        end\n      end)\n    end)\n  end\n\n  test \"nested deps come first\" do\n    deps = [{:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"}]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        assert Enum.map(Mix.Dep.Converger.converge([]), & &1.app) == [:git_repo, :deps_repo]\n      end)\n    end)\n  end\n\n  test \"nested optional deps are never added\" do\n    deps = [{:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"}]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        File.write!(\"custom/deps_repo/mix.exs\", \"\"\"\n        defmodule DepsRepo do\n          use Mix.Project\n\n          def project do\n            [app: :deps_repo,\n             version: \"0.1.0\",\n             deps: [{:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), optional: true}]]\n          end\n        end\n        \"\"\")\n\n        assert Enum.map(Mix.Dep.Converger.converge([]), & &1.app) == [:deps_repo]\n      end)\n    end)\n  end\n\n  test \"nested deps with convergence\" do\n    deps = [\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n      {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        assert Enum.map(Mix.Dep.Converger.converge([]), & &1.app) == [:git_repo, :deps_repo]\n      end)\n    end)\n  end\n\n  test \"nested deps with convergence and managers\" do\n    Process.put(:custom_deps_git_repo_opts, manager: :make)\n\n    deps = [\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", manager: :rebar3},\n      {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        [dep1, dep2] = Mix.Dep.Converger.converge([])\n        assert dep1.manager == nil\n        assert dep2.manager == :rebar3\n      end)\n    end)\n  end\n\n  test \"nested deps with optional matching\" do\n    Process.put(:custom_deps_git_repo_opts, optional: true)\n\n    # deps_repo brings git_repo but it is optional\n    deps = [\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n      {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        File.mkdir_p!(\"custom/deps_repo/lib\")\n\n        File.write!(\"custom/deps_repo/lib/a.ex\", \"\"\"\n        # Check that the child dependency is top_level and optional\n        [%Mix.Dep{app: :git_repo, top_level: true, opts: opts}] = Mix.Dep.cached()\n        true = Keyword.fetch!(opts, :optional)\n        \"\"\")\n\n        Mix.Tasks.Deps.Get.run([])\n        Mix.Tasks.Deps.Compile.run([])\n      end)\n    end)\n  end\n\n  test \"nested deps with convergence and optional dependencies\" do\n    deps = [\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n      {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        File.write!(\"custom/deps_repo/mix.exs\", \"\"\"\n        defmodule DepsRepo do\n          use Mix.Project\n\n          def project do\n            [app: :deps_repo,\n             version: \"0.1.0\",\n             deps: [{:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), optional: true}]]\n          end\n        end\n        \"\"\")\n\n        assert Enum.map(Mix.Dep.Converger.converge([]), & &1.app) == [:git_repo, :deps_repo]\n      end)\n    end)\n  end\n\n  test \"nested deps with optional dependencies and cousin conflict\" do\n    deps = [\n      {:deps_repo1, \"0.1.0\", path: \"custom/deps_repo1\"},\n      {:deps_repo2, \"0.1.0\", path: \"custom/deps_repo2\"}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        File.mkdir_p!(\"custom/deps_repo1\")\n\n        File.write!(\"custom/deps_repo1/mix.exs\", \"\"\"\n        defmodule DepsRepo1 do\n          use Mix.Project\n\n          def project do\n            [app: :deps_repo1,\n             version: \"0.1.0\",\n             deps: [{:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), optional: true}]]\n          end\n        end\n        \"\"\")\n\n        File.mkdir_p!(\"custom/deps_repo2\")\n\n        File.write!(\"custom/deps_repo2/mix.exs\", \"\"\"\n        defmodule DepsRepo2 do\n          use Mix.Project\n\n          def project do\n            [app: :deps_repo2,\n             version: \"0.1.0\",\n             deps: [{:git_repo, \"0.2.0\", path: \"somewhere\"}]]\n          end\n        end\n        \"\"\")\n\n        Mix.Tasks.Deps.run([])\n        assert_received {:mix_shell, :info, [\"* deps_repo1\" <> _]}\n        assert_received {:mix_shell, :info, [\"* deps_repo2\" <> _]}\n        assert_received {:mix_shell, :info, [\"* git_repo\" <> _]}\n\n        assert_received {:mix_shell, :info,\n                         [\"  different specs were given for the git_repo app\" <> _]}\n      end)\n    end)\n  end\n\n  test \"nested deps with optional dependencies and cousin conflict (reverse order)\" do\n    deps = [\n      {:deps_repo2, \"0.1.0\", path: \"custom/deps_repo2\"},\n      {:deps_repo1, \"0.1.0\", path: \"custom/deps_repo1\"}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        File.mkdir_p!(\"custom/deps_repo1\")\n\n        File.write!(\"custom/deps_repo1/mix.exs\", \"\"\"\n        defmodule DepsRepo1 do\n          use Mix.Project\n\n          def project do\n            [app: :deps_repo1,\n             version: \"0.1.0\",\n             deps: [{:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), optional: true}]]\n          end\n        end\n        \"\"\")\n\n        File.mkdir_p!(\"custom/deps_repo2\")\n\n        File.write!(\"custom/deps_repo2/mix.exs\", \"\"\"\n        defmodule DepsRepo2 do\n          use Mix.Project\n\n          def project do\n            [app: :deps_repo2,\n             version: \"0.1.0\",\n             deps: [{:git_repo, \"0.2.0\", path: \"somewhere\"}]]\n          end\n        end\n        \"\"\")\n\n        Mix.Tasks.Deps.run([])\n        assert_received {:mix_shell, :info, [\"* deps_repo1\" <> _]}\n        assert_received {:mix_shell, :info, [\"* deps_repo2\" <> _]}\n        assert_received {:mix_shell, :info, [\"* git_repo\" <> _]}\n\n        assert_received {:mix_shell, :info,\n                         [\"  different specs were given for the git_repo app\" <> _]}\n      end)\n    end)\n  end\n\n  @compile {:no_warn_undefined, [{A, :env, 0}]}\n  test \"mix dep with system_env set\" do\n    system_env = [{\"CONTENTS_FROM_ENV\", \"contents dep test\"}]\n    deps = [{:ok, \"~> 0.1\", path: \"deps/ok\", system_env: system_env}]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        File.mkdir_p!(\"deps/ok/lib\")\n\n        File.write!(\"deps/ok/lib/a.ex\", \"\"\"\n        defmodule A do\n          def env, do: unquote(System.fetch_env!(\"CONTENTS_FROM_ENV\"))\n        end\n        \"\"\")\n\n        Mix.Tasks.Deps.Get.run([])\n        Mix.Tasks.Deps.Compile.run([])\n        assert A.env() == \"contents dep test\"\n      end)\n    end)\n  end\n\n  test \"rebar dep with system_env set\" do\n    file_path = tmp_path(\"load dependency with env vars/dep-test\")\n    dep_path = tmp_path(\"rebar_dep\")\n\n    system_env = [{\"FILE_FROM_ENV\", file_path}, {\"CONTENTS_FROM_ENV\", \"contents dep test\"}]\n    deps = [{:rebar_dep, path: dep_path, app: false, manager: :rebar3, system_env: system_env}]\n\n    with_deps(deps, fn ->\n      in_tmp(\"load dependency with env vars\", fn ->\n        Mix.Dep.Converger.converge([])\n        assert {:ok, \"contents dep test\"} = File.read(file_path)\n      end)\n    end)\n  end\n\n  test \"diverged with system_env set\" do\n    Process.put(:custom_deps_git_repo_opts, system_env: [{\"FOO\", \"BAR\"}])\n\n    deps = [\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n      {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        [git_repo, _] = Mix.Dep.Converger.converge([])\n        %{app: :git_repo, status: {:overridden, _, _}} = git_repo\n      end)\n    end)\n  end\n\n  ## Remote converger\n\n  defmodule IdentityRemoteConverger do\n    @behaviour Mix.RemoteConverger\n\n    def remote?(%Mix.Dep{app: :deps_repo}), do: false\n    def remote?(%Mix.Dep{}), do: true\n    def deps(_dep, _lock), do: []\n    def post_converge, do: :ok\n\n    def converge(deps, lock) do\n      Process.put(:remote_converger, deps)\n      lock\n    end\n  end\n\n  test \"remote converger\" do\n    deps = [\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n      {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n    ]\n\n    with_deps(deps, fn ->\n      Mix.RemoteConverger.register(IdentityRemoteConverger)\n\n      in_fixture(\"deps_status\", fn ->\n        Mix.Tasks.Deps.Get.run([])\n\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n        assert_received {:mix_shell, :info, [^message]}\n\n        assert Process.get(:remote_converger)\n      end)\n    end)\n  after\n    Mix.RemoteConverger.register(nil)\n  end\n\n  defmodule DivergingRemoteConverger do\n    @behaviour Mix.RemoteConverger\n\n    def remote?(%Mix.Dep{app: :deps_repo, scm: Mix.SCM.Path}), do: true\n    def remote?(%Mix.Dep{app: :git_repo, scm: Mix.SCM.Path}), do: true\n    def remote?(%Mix.Dep{}), do: false\n    def deps(%Mix.Dep{app: :deps_repo}, _lock), do: [{:git_repo, path: \"custom/git_repo\"}]\n    def deps(%Mix.Dep{app: :git_repo}, _lock), do: []\n    def post_converge, do: :ok\n\n    def converge(_deps, lock) do\n      lock\n      |> Map.put(:deps_repo, :custom)\n      |> Map.put(:git_repo, :custom)\n    end\n  end\n\n  test \"converger detects diverged deps from remote converger\" do\n    deps = [\n      {:deps_on_git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"deps_on_git_repo\")},\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"}\n    ]\n\n    with_deps(deps, fn ->\n      Mix.RemoteConverger.register(DivergingRemoteConverger)\n\n      in_fixture(\"deps_status\", fn ->\n        assert_raise Mix.Error, fn ->\n          Mix.Tasks.Deps.Get.run([])\n        end\n\n        assert_received {:mix_shell, :error, [\"Dependencies have diverged:\"]}\n      end)\n    end)\n  after\n    Mix.RemoteConverger.register(nil)\n  end\n\n  test \"pass dependencies to remote converger in defined order\" do\n    deps = [\n      {:ok, \"0.1.0\", path: \"deps/ok\"},\n      {:invalidvsn, \"0.2.0\", path: \"deps/invalidvsn\"},\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n      {:invalidapp, \"0.1.0\", path: \"deps/invalidapp\"},\n      {:noappfile, \"0.1.0\", path: \"deps/noappfile\"}\n    ]\n\n    with_deps(deps, fn ->\n      Mix.RemoteConverger.register(IdentityRemoteConverger)\n\n      in_fixture(\"deps_status\", fn ->\n        Mix.Tasks.Deps.Get.run([])\n\n        deps = Process.get(:remote_converger) |> Enum.map(& &1.app)\n        assert deps == [:ok, :invalidvsn, :deps_repo, :invalidapp, :noappfile, :git_repo]\n      end)\n    end)\n  after\n    Mix.RemoteConverger.register(nil)\n  end\n\n  defmodule RaiseRemoteConverger do\n    @behaviour Mix.RemoteConverger\n\n    def remote?(_app), do: false\n    def deps(_dep, _lock), do: :ok\n    def post_converge, do: :ok\n\n    def converge(_deps, lock) do\n      Process.put(:remote_converger, true)\n      lock\n    end\n  end\n\n  test \"remote converger is not invoked if deps diverge\" do\n    deps = [\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n      {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), only: :test}\n    ]\n\n    with_deps(deps, fn ->\n      Mix.RemoteConverger.register(RaiseRemoteConverger)\n\n      in_fixture(\"deps_status\", fn ->\n        assert_raise Mix.Error, fn ->\n          Mix.Tasks.Deps.Get.run([])\n        end\n\n        assert_received {:mix_shell, :error, [\"Dependencies have diverged:\"]}\n        refute Process.get(:remote_converger)\n      end)\n    end)\n  after\n    Mix.RemoteConverger.register(nil)\n  end\n\n  test \"remote converger is not invoked if deps graph has cycles\" do\n    deps = [{:app1, \"0.1.0\", path: \"app1\"}, {:app2, \"0.1.0\", path: \"app2\"}]\n\n    with_deps(deps, fn ->\n      Mix.RemoteConverger.register(RaiseRemoteConverger)\n\n      in_fixture(\"deps_cycle\", fn ->\n        assert_raise Mix.Error, ~r/Could not sort dependencies/, fn ->\n          Mix.Tasks.Deps.Get.run([])\n        end\n\n        refute Process.get(:remote_converger)\n      end)\n    end)\n  after\n    Mix.RemoteConverger.register(nil)\n  end\n\n  defp sorted_keys(map) do\n    map |> Map.keys() |> Enum.sort()\n  end\n\n  test \"deps_paths\" do\n    deps = [\n      {:abc_repo, \"0.1.0\", path: \"custom/abc_repo\"},\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        # Both orders below are valid after topological sort\n        assert Enum.map(Mix.Dep.Converger.converge([]), & &1.app) in [\n                 [:git_repo, :abc_repo, :deps_repo],\n                 [:abc_repo, :git_repo, :deps_repo]\n               ]\n\n        assert sorted_keys(Mix.Project.deps_paths()) == [:abc_repo, :deps_repo, :git_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(depth: 1)) == [:abc_repo, :deps_repo]\n        assert sorted_keys(Mix.Project.deps_paths(depth: 2)) == [:abc_repo, :deps_repo, :git_repo]\n        assert sorted_keys(Mix.Project.deps_paths(depth: 3)) == [:abc_repo, :deps_repo, :git_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo])) == [:abc_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:deps_repo])) == [\n                 :deps_repo,\n                 :git_repo\n               ]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:git_repo])) == [:git_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo], depth: 1)) == [:abc_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:deps_repo], depth: 1)) == [\n                 :deps_repo\n               ]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:git_repo], depth: 1)) == [:git_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo], depth: 2)) == [:abc_repo]\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:git_repo], depth: 2)) == [:git_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:deps_repo], depth: 2)) ==\n                 [:deps_repo, :git_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo])) ==\n                 [:abc_repo, :deps_repo, :git_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo], depth: 1)) ==\n                 [:abc_repo, :deps_repo]\n\n        assert sorted_keys(Mix.Project.deps_paths(parents: [:abc_repo, :deps_repo], depth: 2)) ==\n                 [:abc_repo, :deps_repo, :git_repo]\n      end)\n    end)\n  end\n\n  test \"deps_tree\" do\n    deps = [\n      {:abc_repo, \"0.1.0\", path: \"custom/abc_repo\"},\n      {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"}\n    ]\n\n    with_deps(deps, fn ->\n      in_fixture(\"deps_status\", fn ->\n        # Both orders below are valid after topological sort\n        assert Enum.map(Mix.Dep.Converger.converge([]), & &1.app) in [\n                 [:git_repo, :abc_repo, :deps_repo],\n                 [:abc_repo, :git_repo, :deps_repo]\n               ]\n\n        assert %{abc_repo: [], deps_repo: [:git_repo]} = Mix.Project.deps_tree(depth: 1)\n\n        assert %{abc_repo: [], deps_repo: [:git_repo], git_repo: []} =\n                 Mix.Project.deps_tree(depth: 2)\n\n        assert %{abc_repo: [], deps_repo: [:git_repo], git_repo: []} =\n                 Mix.Project.deps_tree(depth: 3)\n\n        assert %{abc_repo: []} = Mix.Project.deps_tree(parents: [:abc_repo])\n\n        assert %{deps_repo: [:git_repo], git_repo: []} =\n                 Mix.Project.deps_tree(parents: [:deps_repo])\n\n        assert %{git_repo: []} = Mix.Project.deps_tree(parents: [:git_repo])\n\n        assert %{abc_repo: []} = Mix.Project.deps_tree(parents: [:abc_repo], depth: 1)\n        assert %{deps_repo: [:git_repo]} = Mix.Project.deps_tree(parents: [:deps_repo], depth: 1)\n      end)\n    end)\n  end\n\n  describe \"only handling\" do\n    test \"extracts deps matching environment\" do\n      deps = [\n        {:foo, github: \"elixir-lang/foo\"},\n        {:bar, github: \"elixir-lang/bar\", only: :other_env}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          deps = Mix.Dep.Converger.converge(env: :other_env)\n          assert length(deps) == 2\n\n          deps = Mix.Dep.Converger.converge([])\n          assert length(deps) == 2\n\n          assert [dep] = Mix.Dep.Converger.converge(env: :prod)\n          assert dep.app == :foo\n        end)\n      end)\n    end\n\n    test \"fetches parent deps matching specified env\" do\n      deps = [{:only, github: \"elixir-lang/only\", only: [:dev]}]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          Mix.Tasks.Deps.Get.run([\"--only\", \"prod\"])\n          refute_received {:mix_shell, :info, [\"* Getting\" <> _]}\n\n          assert_raise Mix.Error, \"Can't continue due to errors on dependencies\", fn ->\n            Mix.Tasks.Deps.Loadpaths.run([])\n          end\n\n          Mix.State.clear_cache()\n          Mix.env(:prod)\n          Mix.Tasks.Deps.Loadpaths.run([])\n        end)\n      end)\n    end\n\n    test \"selects only prod dependencies on nested deps\" do\n      Process.put(:custom_deps_git_repo_opts, only: :test)\n      deps = [{:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"}]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:deps_repo] = Enum.map(loaded, & &1.app)\n\n          loaded = Mix.Dep.Converger.converge(env: :test)\n          assert [:deps_repo] = Enum.map(loaded, & &1.app)\n        end)\n      end)\n    end\n\n    test \"conflicts on nested deps\" do\n      # deps_repo wants all git_repo, git_repo is restricted to only test\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), only: :test}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedonly: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :dev)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedonly: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :test)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedonly: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          Mix.Tasks.Deps.run([])\n          assert_received {:mix_shell, :info, [\"* deps_repo\" <> _]}\n          assert_received {:mix_shell, :info, [_]}\n          assert_received {:mix_shell, :info, [\"* git_repo\" <> _]}\n          assert_received {:mix_shell, :info, [msg]}\n          assert msg =~ \"Remove the :only restriction from your dep\"\n        end)\n      end)\n    end\n\n    test \"does not conflict with optional deps on nested deps\" do\n      Process.put(:custom_deps_git_repo_opts, optional: true)\n\n      # deps_repo wants all git_repo, git_repo is restricted to only test\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), only: :test}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :dev)\n          assert [:deps_repo] = Enum.map(loaded, & &1.app)\n          assert [noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :test)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n        end)\n      end)\n    end\n\n    test \"does not conflict with optional deps on nested deps (reverse order)\" do\n      Process.put(:custom_deps_git_repo_opts, optional: true)\n\n      # deps_repo wants all git_repo, git_repo is restricted to only test\n      deps = [\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), only: :test},\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :dev)\n          assert [:deps_repo] = Enum.map(loaded, & &1.app)\n          assert [noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :test)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n        end)\n      end)\n    end\n\n    test \"does not conflict on valid subsets on nested deps\" do\n      # deps_repo wants git_repo for prod, git_repo is restricted to only prod and test\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", only: :prod},\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), only: [:prod, :test]}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :dev)\n          assert [] = Enum.map(loaded, & &1.app)\n\n          loaded = Mix.Dep.Converger.converge(env: :test)\n          assert [:git_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :prod)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n        end)\n      end)\n    end\n\n    test \"conflicts on invalid subset on nested deps\" do\n      # deps_repo wants git_repo for dev, git_repo is restricted to only test\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", only: :dev},\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), only: [:test]}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedonly: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :dev)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedonly: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :test)\n          assert [:git_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _] = Enum.map(loaded, & &1.status)\n\n          Mix.Tasks.Deps.run([])\n          assert_received {:mix_shell, :info, [\"* deps_repo\" <> _]}\n          assert_received {:mix_shell, :info, [_]}\n          assert_received {:mix_shell, :info, [\"* git_repo\" <> _]}\n          assert_received {:mix_shell, :info, [msg]}\n          assert msg =~ \"Ensure you specify at least the same environments in :only in your dep\"\n        end)\n      end)\n    end\n\n    test \"does not conflict when valid in both parent and child on nested deps\" do\n      Process.put(:custom_deps_git_repo_opts, only: :test)\n\n      # deps_repo has environment set to test so it loads the deps_git_repo set to test too\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", env: :test, only: [:dev, :test]},\n        {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\"), only: :test}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :dev)\n          assert [:deps_repo] = Enum.map(loaded, & &1.app)\n          assert [noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :test)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(env: :prod)\n          assert [] = Enum.map(loaded, & &1.app)\n        end)\n      end)\n    end\n\n    test \"converges and diverges when not in_upper\" do\n      loaded = fn deps ->\n        with_deps(deps, fn ->\n          in_fixture(\"deps_status\", fn ->\n            File.mkdir_p!(\"custom/other_repo\")\n\n            File.write!(\"custom/other_repo/mix.exs\", \"\"\"\n            defmodule OtherRepo do\n              use Mix.Project\n\n              def project do\n                [app: :other_repo,\n                 version: \"0.1.0\",\n                 deps: [{:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}]]\n              end\n            end\n            \"\"\")\n\n            Mix.State.clear_cache()\n            loaded = Mix.Dep.Converger.converge([])\n            Enum.map(loaded, &{&1.app, &1.opts[:only]})\n          end)\n        end)\n      end\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", only: :prod},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\", only: :test}\n      ]\n\n      assert loaded.(deps) == [git_repo: [:test, :prod], other_repo: :test, deps_repo: :prod]\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\", only: :test}\n      ]\n\n      assert loaded.(deps) == [git_repo: nil, other_repo: :test, deps_repo: nil]\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", only: :prod},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\"}\n      ]\n\n      assert loaded.(deps) == [git_repo: nil, other_repo: nil, deps_repo: :prod]\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\"}\n      ]\n\n      assert loaded.(deps) == [git_repo: nil, other_repo: nil, deps_repo: nil]\n\n      Process.put(:custom_deps_git_repo_opts, optional: true)\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", only: :prod},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\", only: :test}\n      ]\n\n      assert loaded.(deps) == [git_repo: :test, other_repo: :test, deps_repo: :prod]\n    end\n\n    test \"converges and diverges when not specified\" do\n      Process.put(:custom_deps_git_repo_opts, only: :test)\n\n      deps = [\n        {:abc_repo, \"0.1.0\", path: \"custom/abc_repo\", from_umbrella: true},\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", from_umbrella: true}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          File.mkdir_p!(\"custom/abc_repo\")\n\n          File.write!(\"custom/abc_repo/mix.exs\", \"\"\"\n          defmodule OtherRepo do\n            use Mix.Project\n\n            def project do\n              [app: :abc_repo,\n               version: \"0.1.0\",\n               deps: [{:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}]]\n            end\n          end\n          \"\"\")\n\n          Mix.Tasks.Deps.Get.run([])\n          Mix.Tasks.Deps.Compile.run([])\n          refute_receive {:mix_shell, :error, [\"Could not compile :git_repo\" <> _]}, 100\n        end)\n      end)\n    end\n  end\n\n  describe \"targets handling\" do\n    test \"extracts deps matching target\" do\n      deps = [\n        {:foo, github: \"elixir-lang/foo\"},\n        {:bar, github: \"elixir-lang/bar\", targets: :rpi3}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          deps = Mix.Dep.Converger.converge(target: :rpi3)\n          assert length(deps) == 2\n\n          deps = Mix.Dep.Converger.converge([])\n          assert length(deps) == 2\n\n          assert [dep] = Mix.Dep.Converger.converge(target: :host)\n          assert dep.app == :foo\n        end)\n      end)\n    end\n\n    test \"fetches parent deps matching specified target\" do\n      deps = [{:target, github: \"elixir-lang/target\", targets: [:host]}]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          Mix.Tasks.Deps.Get.run([\"--target\", \"rpi3\"])\n          refute_received {:mix_shell, :info, [\"* Getting\" <> _]}\n\n          assert_raise Mix.Error, \"Can't continue due to errors on dependencies\", fn ->\n            Mix.Tasks.Deps.Loadpaths.run([])\n          end\n\n          Mix.State.clear_cache()\n          Mix.target(:rpi3)\n          Mix.Tasks.Deps.Loadpaths.run([])\n        end)\n      end)\n    end\n\n    test \"conflicts on nested deps\" do\n      # deps_repo wants all git_repo, git_repo is restricted to targets rpi3\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), targets: :rpi3}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedtargets: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :host)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedtargets: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :rpi3)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedtargets: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          Mix.Tasks.Deps.run([])\n          assert_received {:mix_shell, :info, [\"* deps_repo\" <> _]}\n          assert_received {:mix_shell, :info, [_]}\n          assert_received {:mix_shell, :info, [\"* git_repo\" <> _]}\n          assert_received {:mix_shell, :info, [msg]}\n          assert msg =~ \"Remove the :targets restriction from your dep\"\n        end)\n      end)\n    end\n\n    test \"does not conflict with optional deps on nested deps\" do\n      Process.put(:custom_deps_git_repo_opts, optional: true)\n\n      # deps_repo wants all git_repo, git_repo is restricted to targets rpi3\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), targets: :rpi3}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :host)\n          assert [:deps_repo] = Enum.map(loaded, & &1.app)\n          assert [noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :rpi3)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n        end)\n      end)\n    end\n\n    test \"does not conflict on valid subsets on nested deps\" do\n      # deps_repo wants git_repo for prod, git_repo is restricted to targets bbb and rpi3\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", targets: :rpi3},\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), targets: [:bbb, :rpi3]}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :host)\n          assert [] = Enum.map(loaded, & &1.app)\n\n          loaded = Mix.Dep.Converger.converge(target: :bbb)\n          assert [:git_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :rpi3)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n        end)\n      end)\n    end\n\n    test \"conflicts on invalid subset on nested deps\" do\n      # deps_repo wants git_repo for rpi3, git_repo is restricted to only test\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", targets: :host},\n        {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\"), targets: [:rpi3]}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedtargets: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :host)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [divergedtargets: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :rpi3)\n          assert [:git_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _] = Enum.map(loaded, & &1.status)\n\n          Mix.Tasks.Deps.run([])\n          assert_received {:mix_shell, :info, [\"* deps_repo\" <> _]}\n          assert_received {:mix_shell, :info, [_]}\n          assert_received {:mix_shell, :info, [\"* git_repo\" <> _]}\n          assert_received {:mix_shell, :info, [msg]}\n          assert msg =~ \"Ensure you specify at least the same targets in :targets in your dep\"\n        end)\n      end)\n    end\n\n    test \"does not conflict when in both parent and child on nested deps\" do\n      Process.put(:custom_deps_git_repo_opts, targets: :bbb)\n\n      # deps_repo has environment set to bbb so it loads the deps_git_repo set to bbb too\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", env: :test, targets: [:host, :bbb]},\n        {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\"), targets: :bbb}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          loaded = Mix.Dep.Converger.converge([])\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :host)\n          assert [:deps_repo] = Enum.map(loaded, & &1.app)\n          assert [noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :bbb)\n          assert [:git_repo, :deps_repo] = Enum.map(loaded, & &1.app)\n          assert [unavailable: _, noappfile: {_, _}] = Enum.map(loaded, & &1.status)\n\n          loaded = Mix.Dep.Converger.converge(target: :rpi3)\n          assert [] = Enum.map(loaded, & &1.app)\n        end)\n      end)\n    end\n\n    test \"converges and diverges when not in_upper\" do\n      loaded = fn deps ->\n        with_deps(deps, fn ->\n          in_fixture(\"deps_status\", fn ->\n            File.mkdir_p!(\"custom/other_repo\")\n\n            File.write!(\"custom/other_repo/mix.exs\", \"\"\"\n            defmodule OtherRepo do\n              use Mix.Project\n\n              def project do\n                [app: :other_repo,\n                 version: \"0.1.0\",\n                 deps: [{:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}]]\n              end\n            end\n            \"\"\")\n\n            Mix.State.clear_cache()\n            loaded = Mix.Dep.Converger.converge([])\n            Enum.map(loaded, &{&1.app, &1.opts[:targets]})\n          end)\n        end)\n      end\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", targets: :rpi3},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\", targets: :bbb}\n      ]\n\n      assert loaded.(deps) == [git_repo: [:bbb, :rpi3], other_repo: :bbb, deps_repo: :rpi3]\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\", targets: :bbb}\n      ]\n\n      assert loaded.(deps) == [git_repo: nil, other_repo: :bbb, deps_repo: nil]\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", targets: :rpi3},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\"}\n      ]\n\n      assert loaded.(deps) == [git_repo: nil, other_repo: nil, deps_repo: :rpi3]\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\"}\n      ]\n\n      assert loaded.(deps) == [git_repo: nil, other_repo: nil, deps_repo: nil]\n\n      Process.put(:custom_deps_git_repo_opts, optional: true)\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", targets: :rpi3},\n        {:other_repo, \"0.1.0\", path: \"custom/other_repo\", targets: :bbb}\n      ]\n\n      assert loaded.(deps) == [git_repo: :bbb, other_repo: :bbb, deps_repo: :rpi3]\n    end\n  end\n\n  describe \"overrides\" do\n    test \"are not required when there are no conflicts\" do\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          File.mkdir_p!(\"custom/deps_repo/lib\")\n\n          File.write!(\"custom/deps_repo/lib/a.ex\", \"\"\"\n          # Check that the child dependency is top_level\n          [%Mix.Dep{app: :git_repo, top_level: true}] = Mix.Dep.cached()\n          \"\"\")\n\n          Mix.Tasks.Deps.Get.run([])\n          Mix.Tasks.Deps.Compile.run([])\n        end)\n      end)\n    end\n\n    test \"are required when there are conflicts\" do\n      # deps_repo brings git_repo but it is overridden\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \">= 0.0.0\", git: MixTest.Case.fixture_path(\"git_repo\"), override: true}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          File.mkdir_p!(\"custom/deps_repo/lib\")\n\n          File.write!(\"custom/deps_repo/lib/a.ex\", \"\"\"\n          # Check that the overridden requirement shows up in the child dependency\n          [%Mix.Dep{app: :git_repo, requirement: \">= 0.0.0\"}] = Mix.Dep.cached()\n          \"\"\")\n\n          Mix.Tasks.Deps.Get.run([])\n          Mix.Tasks.Deps.Compile.run([])\n        end)\n      end)\n    end\n  end\n\n  describe \"override: [dep]\" do\n    test \"warns when overrides do not match dependency\" do\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:ok, \"0.1.0\", path: \"deps/ok\", override: [:deps_repo]}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          Mix.Task.run(\"deps.get\")\n        end)\n      end)\n\n      message = \"Dependency ok 0.1.0 (deps/ok) no longer requires :override on :deps_repo\"\n      assert_received {:mix_shell, :error, [^message]}\n    end\n\n    test \"warns when overrides are no longer needed\" do\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\"), override: [:deps_repo]}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          Mix.Task.run(\"deps.get\")\n        end)\n      end)\n\n      message =\n        \"Dependency git_repo (#{fixture_path(\"git_repo\")}) no longer requires :override on :deps_repo\"\n\n      assert_received {:mix_shell, :error, [^message]}\n    end\n\n    test \"targets divergence when app is not overridden\" do\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", targets: :host},\n        {:git_repo, \"0.2.0\",\n         git: MixTest.Case.fixture_path(\"git_repo\"), targets: [:rpi3], override: []}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          [git_repo, _] = Mix.Dep.Converger.converge([])\n          %{app: :git_repo, status: {:divergedtargets, _}} = git_repo\n        end)\n      end)\n    end\n\n    test \"targets divergence overridden per app\" do\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", targets: :host},\n        {:git_repo, \"0.2.0\",\n         git: MixTest.Case.fixture_path(\"git_repo\"), targets: [:rpi3], override: [:deps_repo]}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          [git_repo, _] = Mix.Dep.Converger.converge([])\n          %{app: :git_repo, status: {:unavailable, _}} = git_repo\n        end)\n      end)\n    end\n\n    test \"system env divergence when app is not overridden\" do\n      Process.put(:custom_deps_git_repo_opts, system_env: [{\"FOO\", \"BAR\"}])\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\"), override: []}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          [git_repo, _] = Mix.Dep.Converger.converge([])\n          %{app: :git_repo, status: {:overridden, :deps_repo, _}} = git_repo\n        end)\n      end)\n    end\n\n    test \"system env divergence overridden per app\" do\n      Process.put(:custom_deps_git_repo_opts, system_env: [{\"FOO\", \"BAR\"}])\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\"), override: [:deps_repo]}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          [git_repo, _] = Mix.Dep.Converger.converge([])\n          %{app: :git_repo, status: {:unavailable, _}} = git_repo\n        end)\n      end)\n    end\n  end\n\n  describe \"app generation\" do\n    test \"considers runtime from current app on nested deps\" do\n      Process.put(:custom_deps_git_repo_opts, runtime: false)\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n        {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          Mix.Tasks.Deps.Compile.run([])\n\n          {:ok, [{:application, :deps_repo, opts}]} =\n            :file.consult(\"_build/dev/lib/deps_repo/ebin/deps_repo.app\")\n\n          assert :git_repo not in Keyword.get(opts, :applications)\n        end)\n      end)\n    end\n\n    test \"considers only from current app on nested deps\" do\n      Process.put(:custom_deps_git_repo_opts, only: :other)\n\n      deps = [\n        {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\", from_umbrella: true},\n        {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\"), from_umbrella: true}\n      ]\n\n      with_deps(deps, fn ->\n        in_fixture(\"deps_status\", fn ->\n          Mix.Tasks.Deps.Compile.run([])\n\n          {:ok, [{:application, :deps_repo, opts}]} =\n            :file.consult(\"_build/dev/lib/deps_repo/ebin/deps_repo.app\")\n\n          assert :git_repo not in Keyword.get(opts, :applications)\n        end)\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/generator_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.GeneratorTest do\n  use MixTest.Case\n\n  import Mix.Generator\n\n  embed_text(:foo, \"foo\")\n  embed_text(:self, from_file: __ENV__.file)\n  embed_template(:bar, \"<%= @a + @b %>\")\n\n  describe \"embed_text/2\" do\n    test \"with contents\" do\n      assert foo_text() == \"foo\"\n    end\n\n    test \"from file\" do\n      assert self_text() =~ \"import Mix.Generator\"\n    end\n  end\n\n  test \"embed template\" do\n    assert bar_template(a: 1, b: 2) == \"3\"\n  end\n\n  describe \"overwrite?/1\" do\n    test \"without conflict\" do\n      in_tmp(\"overwrite\", fn ->\n        assert overwrite?(\"foo\")\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning true\" do\n      in_tmp(\"overwrite\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, true})\n\n        assert overwrite?(\"foo\")\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning false\" do\n      in_tmp(\"overwrite\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, false})\n\n        refute overwrite?(\"foo\")\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n  end\n\n  describe \"overwrite?/2\" do\n    test \"without conflict\" do\n      in_tmp(\"overwrite\", fn ->\n        assert overwrite?(\"foo\", \"HELLO\")\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with same contents\" do\n      in_tmp(\"overwrite\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        refute overwrite?(\"foo\", \"HELLO\")\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning true\" do\n      in_tmp(\"overwrite\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, true})\n\n        assert overwrite?(\"foo\", \"WORLD\")\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning false\" do\n      in_tmp(\"overwrite\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, false})\n\n        refute overwrite?(\"foo\", \"WORLD\")\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n  end\n\n  describe \"create_file/3\" do\n    test \"creates file\" do\n      in_tmp(\"create_file\", fn ->\n        create_file(\"foo\", \"HELLO\")\n        assert File.read!(\"foo\") == \"HELLO\"\n        assert_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with quiet\" do\n      in_tmp(\"create_file\", fn ->\n        create_file(\"foo\", \"HELLO\", quiet: true)\n        assert File.read!(\"foo\") == \"HELLO\"\n        refute_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with force\" do\n      in_tmp(\"create_file\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        create_file(\"foo\", \"WORLD\", force: true)\n        assert File.read!(\"foo\") == \"WORLD\"\n\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n        assert_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with same contents\" do\n      in_tmp(\"create_file\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        create_file(\"foo\", \"HELLO\")\n        assert File.read!(\"foo\") == \"HELLO\"\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning true\" do\n      in_tmp(\"create_file\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, true})\n\n        create_file(\"foo\", \"WORLD\")\n        assert File.read!(\"foo\") == \"WORLD\"\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning false\" do\n      in_tmp(\"create_file\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, false})\n\n        create_file(\"foo\", \"WORLD\")\n        assert File.read!(\"foo\") == \"HELLO\"\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with `format_elixir: true`\" do\n      in_tmp(\"create_file\", fn ->\n        create_file(\"foo\", \"%{ foo:  :bar }\", format_elixir: true)\n        assert File.read!(\"foo\") == \"%{foo: :bar}\\n\"\n      end)\n    end\n  end\n\n  describe \"copy_file/3\" do\n    test \"copies file\" do\n      in_tmp(\"copy_file\", fn ->\n        copy_file(__ENV__.file, \"foo\")\n        assert File.read!(\"foo\") =~ ~s[describe \"copy_file/3\" do]\n        assert_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with quiet\" do\n      in_tmp(\"copy_file\", fn ->\n        copy_file(__ENV__.file, \"foo\", quiet: true)\n        assert File.read!(\"foo\") =~ ~s[describe \"copy_file/3\" do]\n        refute_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with force\" do\n      in_tmp(\"copy_file\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        copy_file(__ENV__.file, \"foo\", force: true)\n        assert File.read!(\"foo\") =~ ~s[describe \"copy_file/3\" do]\n\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n        assert_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with same contents\" do\n      in_tmp(\"copy_file\", fn ->\n        copy_file(__ENV__.file, \"foo\")\n        copy_file(__ENV__.file, \"foo\")\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning true\" do\n      in_tmp(\"copy_file\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, true})\n\n        copy_file(__ENV__.file, \"foo\")\n        assert File.read!(\"foo\") =~ ~s[describe \"copy_file/3\" do]\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning false\" do\n      in_tmp(\"copy_file\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, false})\n\n        copy_file(__ENV__.file, \"foo\")\n        assert File.read!(\"foo\") == \"HELLO\"\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n  end\n\n  describe \"copy_template/4\" do\n    test \"copies template\" do\n      in_tmp(\"copy_template\", fn ->\n        copy_template(__ENV__.file, \"foo\", a: 1, b: 2)\n        assert File.read!(\"foo\") =~ ~s[embed_template(:bar, \"3\")]\n        assert_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with quiet\" do\n      in_tmp(\"copy_template\", fn ->\n        copy_template(__ENV__.file, \"foo\", [a: 1, b: 2], quiet: true)\n        assert File.read!(\"foo\") =~ ~s[embed_template(:bar, \"3\")]\n        refute_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with force\" do\n      in_tmp(\"copy_template\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        copy_template(__ENV__.file, \"foo\", [a: 1, b: 2], force: true)\n        assert File.read!(\"foo\") =~ ~s[embed_template(:bar, \"3\")]\n\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n        assert_received {:mix_shell, :info, [\"* creating foo\"]}\n      end)\n    end\n\n    test \"with same contents\" do\n      in_tmp(\"copy_template\", fn ->\n        copy_template(__ENV__.file, \"foo\", a: 1, b: 2)\n        copy_template(__ENV__.file, \"foo\", a: 1, b: 2)\n        refute_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning true\" do\n      in_tmp(\"copy_template\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, true})\n\n        copy_template(__ENV__.file, \"foo\", a: 1, b: 2)\n        assert File.read!(\"foo\") =~ ~s[embed_template(:bar, \"3\")]\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n\n    test \"with conflict returning false\" do\n      in_tmp(\"copy_template\", fn ->\n        File.write!(\"foo\", \"HELLO\")\n        send(self(), {:mix_shell_input, :yes?, false})\n\n        copy_template(__ENV__.file, \"foo\", a: 1, b: 2)\n        assert File.read!(\"foo\") == \"HELLO\"\n        assert_received {:mix_shell, :yes?, [\"foo already exists, overwrite?\"]}\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/local/installer_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Local.InstallerTest do\n  use MixTest.Case\n\n  test \"fetch\" do\n    dep_spec = {:git_repo, git: fixture_path(\"git_repo\")}\n\n    fetcher = fn mix_exs ->\n      send(self(), mix_exs)\n      Mix.Task.run(\"deps.get\", [])\n    end\n\n    config =\n      Mix.Local.Installer.fetch(dep_spec, fetcher, fn _mix_exs ->\n        assert Mix.env() == :prod\n        Mix.Project.config()\n      end)\n\n    # Fetcher should run twice\n    assert_receive Mix.Local.Installer.MixProject\n    assert_receive GitRepo.MixProject\n\n    # In package runs once\n    assert Mix.env() == :dev\n    assert config[:app] == :git_repo\n    assert config[:deps_path] =~ ~r/mix-local-installer-fetcher-.*\\/deps/\n    assert config[:lockfile] =~ ~r/mix-local-installer-fetcher-.*\\/mix.lock/\n  after\n    purge([GitRepo.MixProject, Mix.Local.Installer.MixProject])\n  end\n\n  test \"parse_args Git\" do\n    args = [\"git\", \"https://example.com/user/repo.git\"]\n    opts = [git: \"https://example.com/user/repo.git\", submodules: nil, sparse: nil]\n\n    assert Mix.Local.Installer.parse_args(args, []) == {:fetcher, {:\"new package\", opts}}\n  end\n\n  test \"parse_args Git branch\" do\n    args = [\"git\", \"https://example.com/user/repo.git\", \"branch\", \"not_main\"]\n\n    opts = [\n      branch: \"not_main\",\n      git: \"https://example.com/user/repo.git\",\n      submodules: nil,\n      sparse: nil\n    ]\n\n    assert Mix.Local.Installer.parse_args(args, []) == {:fetcher, {:\"new package\", opts}}\n  end\n\n  test \"parse_args Git ref\" do\n    args = [\"git\", \"https://example.com/user/repo.git\", \"ref\", \"not_main\"]\n\n    opts = [\n      ref: \"not_main\",\n      git: \"https://example.com/user/repo.git\",\n      submodules: nil,\n      sparse: nil\n    ]\n\n    assert Mix.Local.Installer.parse_args(args, []) == {:fetcher, {:\"new package\", opts}}\n  end\n\n  test \"parse_args Git tag\" do\n    args = [\"git\", \"https://example.com/user/repo.git\", \"tag\", \"not_main\"]\n\n    opts = [\n      tag: \"not_main\",\n      git: \"https://example.com/user/repo.git\",\n      submodules: nil,\n      sparse: nil\n    ]\n\n    assert Mix.Local.Installer.parse_args(args, []) == {:fetcher, {:\"new package\", opts}}\n  end\n\n  test \"parse_args Git submodules\" do\n    args = [\"git\", \"https://example.com/user/repo.git\"]\n    opts = [git: \"https://example.com/user/repo.git\", submodules: true, sparse: nil]\n\n    assert Mix.Local.Installer.parse_args(args, submodules: true) ==\n             {:fetcher, {:\"new package\", opts}}\n  end\n\n  test \"parse_args Git sparse\" do\n    args = [\"git\", \"https://example.com/user/repo.git\"]\n    opts = [git: \"https://example.com/user/repo.git\", submodules: nil, sparse: \"foo\"]\n\n    assert Mix.Local.Installer.parse_args(args, sparse: \"foo\") ==\n             {:fetcher, {:\"new package\", opts}}\n  end\n\n  test \"parse_args Git app\" do\n    args = [\"git\", \"https://example.com/user/repo.git\"]\n    opts = [git: \"https://example.com/user/repo.git\", submodules: nil, sparse: nil]\n\n    assert Mix.Local.Installer.parse_args(args, app: \"my_app\") == {:fetcher, {:my_app, opts}}\n  end\n\n  test \"parse_args GitHub\" do\n    args = [\"github\", \"user/repo\"]\n    opts = [git: \"https://github.com/user/repo.git\", submodules: nil, sparse: nil]\n\n    assert Mix.Local.Installer.parse_args(args, []) == {:fetcher, {:\"new package\", opts}}\n  end\n\n  test \"parse_args Hex\" do\n    assert Mix.Local.Installer.parse_args([\"hex\", \"a_package\"], []) ==\n             {:fetcher, {:a_package, \">= 0.0.0\", [hex: :a_package, repo: \"hexpm\"]}}\n  end\n\n  test \"parse_args Hex app\" do\n    assert Mix.Local.Installer.parse_args([\"hex\", \"a_package\"], app: \"my_app\") ==\n             {:fetcher, {:my_app, \">= 0.0.0\", [hex: :a_package, repo: \"hexpm\"]}}\n  end\n\n  test \"parse_args Hex version spec\" do\n    assert Mix.Local.Installer.parse_args([\"hex\", \"a_package\", \"1.0.0\"], []) ==\n             {:fetcher, {:a_package, \"1.0.0\", [hex: :a_package, repo: \"hexpm\"]}}\n  end\n\n  test \"parse_args Hex with organization\" do\n    assert Mix.Local.Installer.parse_args([\"hex\", \"a_package\"], organization: \"my_org\") ==\n             {:fetcher, {:a_package, \">= 0.0.0\", [hex: :a_package, repo: \"hexpm:my_org\"]}}\n  end\n\n  test \"parse_args Hex with repo\" do\n    assert Mix.Local.Installer.parse_args([\"hex\", \"a_package\"], repo: \"my_repo\") ==\n             {:fetcher, {:a_package, \">= 0.0.0\", [hex: :a_package, repo: \"my_repo\"]}}\n  end\n\n  test \"parse_args Hex with repo and organization\" do\n    opts = [repo: \"my_repo\", organization: \"my_org\"]\n\n    assert Mix.Local.Installer.parse_args([\"hex\", \"a_package\"], opts) ==\n             {:fetcher, {:a_package, \">= 0.0.0\", [hex: :a_package, repo: \"my_repo:my_org\"]}}\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/local_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.LocalTest do\n  use MixTest.Case\n\n  @csv \"\"\"\n  1.2.5,ABC,0.9.0,26\n  1.2.3,DEF,1.0.0,26\n  1.2.4,GHI,1.0.0,26\n  \"\"\"\n\n  @tag :tmp_dir\n  test \"select correct versions from csv\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      File.write!(\"csv\", @csv)\n\n      assert {\"1.0.0\", \"1.2.4\", \"GHI\", \"26\"} =\n               Mix.Local.find_matching_versions!(\"name\", nil, \"csv\")\n    end)\n  end\n\n  @tag :tmp_dir\n  test \"select specific version from csv\", %{tmp_dir: tmp_dir} do\n    File.cd!(tmp_dir, fn ->\n      File.write!(\"csv\", @csv)\n\n      assert {\"0.9.0\", \"1.2.5\", \"ABC\", \"26\"} =\n               Mix.Local.find_matching_versions!(\"name\", \"1.2.5\", \"csv\")\n\n      assert {\"1.0.0\", \"1.2.3\", \"DEF\", \"26\"} =\n               Mix.Local.find_matching_versions!(\"name\", \"1.2.3\", \"csv\")\n\n      assert_raise Mix.Error, \"Could not find a version of name matching: 1.3.0\", fn ->\n        Mix.Local.find_matching_versions!(\"name\", \"1.3.0\", \"csv\")\n      end\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/project_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.ProjectTest do\n  use MixTest.Case\n\n  defmodule SampleProject do\n    def project do\n      [app: :sample, hello: \"world\"]\n    end\n  end\n\n  test \"consolidation_path/1\" do\n    config = [apps_path: \"apps\", build_per_environment: true]\n\n    assert Mix.Project.consolidation_path(config) ==\n             Path.join(File.cwd!(), \"_build/dev/consolidated\")\n\n    config = [app: :sample, build_per_environment: true]\n\n    assert Mix.Project.consolidation_path(config) ==\n             Path.join(File.cwd!(), \"_build/dev/lib/sample/consolidated\")\n  end\n\n  describe \"build_path/1\" do\n    test \"considers the environment\" do\n      assert Mix.Project.build_path(build_per_environment: true) ==\n               Path.join(File.cwd!(), \"_build/dev\")\n\n      assert Mix.Project.build_path(build_per_environment: false) ==\n               Path.join(File.cwd!(), \"_build/shared\")\n    end\n\n    test \"considers the target\" do\n      Mix.target(:rpi3)\n\n      assert Mix.Project.build_path(build_per_environment: true) ==\n               Path.join(File.cwd!(), \"_build/rpi3_dev\")\n\n      assert Mix.Project.build_path(build_per_environment: false) ==\n               Path.join(File.cwd!(), \"_build/rpi3_shared\")\n    end\n\n    test \"considers MIX_BUILD_PATH\" do\n      System.put_env(\"MIX_BUILD_PATH\", \"_build\")\n      assert Mix.Project.build_path() == Path.join(File.cwd!(), \"_build\")\n    after\n      System.delete_env(\"MIX_BUILD_PATH\")\n    end\n\n    test \"considers MIX_BUILD_ROOT\" do\n      System.put_env(\"MIX_BUILD_ROOT\", \"_build_root\")\n      assert Mix.Project.build_path() == Path.join(File.cwd!(), \"_build_root/dev\")\n    after\n      System.delete_env(\"MIX_BUILD_ROOT\")\n    end\n\n    test \"considers MIX_DEPS_PATH\" do\n      System.put_env(\"MIX_DEPS_PATH\", \"test_deps_path\")\n      assert Mix.Project.deps_path() == Path.join(File.cwd!(), \"test_deps_path\")\n    after\n      System.delete_env(\"MIX_DEPS_PATH\")\n    end\n  end\n\n  test \"returns mix.exs path\" do\n    assert Mix.Project.project_file() == nil\n    Mix.Project.push(SampleProject, \"sample\")\n    assert Mix.Project.project_file() == \"sample\"\n  end\n\n  test \"push and pop projects\" do\n    refute Mix.Project.get()\n    Mix.Project.push(SampleProject, \"sample\")\n    assert Mix.Project.get() == SampleProject\n\n    assert %{name: SampleProject, config: _, file: \"sample\"} = Mix.Project.pop()\n    assert Mix.Project.pop() == nil\n  end\n\n  test \"does not allow the same project to be pushed twice\" do\n    Mix.Project.push(SampleProject, \"sample\")\n\n    assert_raise Mix.Error, ~r/Mix.ProjectTest.SampleProject from \"another\"/, fn ->\n      Mix.Project.push(SampleProject, \"another\")\n    end\n  end\n\n  test \"allows nil projects to be pushed twice\" do\n    Mix.Project.push(nil)\n    Mix.Project.push(nil)\n    assert is_map(Mix.Project.pop())\n    assert is_map(Mix.Project.pop())\n    assert is_nil(Mix.Project.pop())\n  end\n\n  test \"retrieves configuration from projects\" do\n    Mix.Project.push(SampleProject)\n    assert Mix.Project.config()[:hello] == \"world\"\n  end\n\n  test \"removes private configuration\" do\n    Mix.Project.push(SampleProject)\n    assert is_nil(Mix.Project.config()[:deps_app_path])\n  end\n\n  test \"raises an error when trying to retrieve the current project but none is set\" do\n    assert_raise Mix.NoProjectError, fn ->\n      Mix.Project.get!()\n    end\n  end\n\n  test \"builds the project structure\" do\n    in_fixture(\"archive\", fn ->\n      config = [deps_app_path: Path.expand(\"_build/archive\")]\n      assert Mix.Project.build_structure(config) == :ok\n      assert File.dir?(\"_build/archive/ebin\")\n      assert_proj_dir_linked_or_copied(\"_build/archive/priv\", \"priv\", ~c\"../../priv\")\n    end)\n  end\n\n  test \"builds the project structure without symlinks\" do\n    in_fixture(\"archive\", fn ->\n      config = [deps_app_path: Path.expand(\"_build/archive\")]\n      assert Mix.Project.build_structure(config) == :ok\n      assert File.dir?(\"_build/archive/ebin\")\n      assert {:error, _} = :file.read_link(\"_build/archive/ebin\")\n    end)\n  end\n\n  test \"builds the project structure with symlinks\" do\n    in_fixture(\"archive\", fn ->\n      config = [deps_app_path: Path.expand(\"_build/archive\")]\n      File.mkdir_p!(\"include\")\n\n      assert Mix.Project.build_structure(config, symlink_ebin: true) == :ok\n      assert_proj_dir_linked_or_copied(\"_build/archive/ebin\", \"ebin\", ~c\"../../ebin\")\n      assert_proj_dir_linked_or_copied(\"_build/archive/priv\", \"priv\", ~c\"../../priv\")\n      assert_proj_dir_linked_or_copied(\"_build/archive/include\", \"include\", ~c\"../../include\")\n\n      assert Mix.Project.build_structure(config) == :ok\n      assert File.dir?(\"_build/archive/ebin\")\n      assert_proj_dir_linked_or_copied(\"_build/archive/priv\", \"priv\", ~c\"../../priv\")\n    end)\n  end\n\n  test \"in_project pushes given configuration\", context do\n    in_tmp(context.test, fn ->\n      result =\n        Mix.Project.in_project(:foo, \".\", [hello: :world], fn _ ->\n          assert Mix.Project.config()[:app] == :foo\n          assert Mix.Project.config()[:hello] == :world\n          :result\n        end)\n\n      assert result == :result\n    end)\n  end\n\n  test \"in_project prints nice error message if fails to load file\", context do\n    in_tmp(context.test, fn ->\n      File.write(\"mix.exs\", \"\"\"\n      raise \"oops\"\n      \"\"\")\n\n      assert_raise RuntimeError, \"oops\", fn ->\n        Mix.Project.in_project(:hello, \".\", [], fn _ ->\n          :ok\n        end)\n      end\n\n      assert_receive {:mix_shell, :error, [\"Error while loading project :hello at\" <> _]}\n    end)\n  end\n\n  defp assert_proj_dir_linked_or_copied(source, target, symlink_path) do\n    case :file.read_link(source) do\n      {:ok, path} ->\n        case :os.type() do\n          # relative symlink on Windows are broken, see symlink_or_copy/2\n          {:win32, _} ->\n            assert path ==\n                     [source, ~c\"..\", symlink_path]\n                     |> Path.join()\n                     |> Path.expand()\n                     |> String.to_charlist()\n\n          _ ->\n            assert path == symlink_path\n        end\n\n      {:error, _} ->\n        assert File.ls!(source) == File.ls!(target)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/rebar_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.RebarTest do\n  use MixTest.Case\n\n  # rebar_dep and git_rebar are loaded dynamically\n  @compile {:no_warn_undefined, [:rebar_dep, :git_rebar]}\n\n  defmodule RebarAsDep do\n    def project do\n      [\n        app: :rebar_as_dep,\n        version: \"0.1.0\",\n        deps: [\n          {:rebar_dep, path: MixTest.Case.tmp_path(\"rebar_dep\"), app: false}\n        ]\n      ]\n    end\n  end\n\n  defmodule RebarAsDepWithEnv do\n    def project do\n      [\n        app: :rebar_as_dep,\n        version: \"0.1.0\",\n        deps: [\n          {\n            :rebar_dep,\n            path: MixTest.Case.tmp_path(\"rebar_dep\"),\n            app: false,\n            system_env: [{\"FILE_FROM_ENV\", \"rebar-test-rebar3\"}, {\"CONTENTS_FROM_ENV\", \"rebar3\"}]\n          }\n        ]\n      ]\n    end\n  end\n\n  defmodule RebarOverrideAsDep do\n    def project do\n      [\n        app: :rebar_as_dep,\n        version: \"0.1.0\",\n        deps: [\n          {\n            :rebar_override,\n            path: MixTest.Case.tmp_path(\"rebar_override\"), app: false\n          }\n        ]\n      ]\n    end\n  end\n\n  describe \"load_config/1\" do\n    test \"loads rebar.config\" do\n      path = MixTest.Case.fixture_path(\"rebar_dep\")\n      config = Mix.Rebar.load_config(path)\n      assert config[:erl_opts] == [:warnings_as_errors]\n      assert config[:SCRIPT] == ~c\"rebar.config.script\"\n    end\n\n    test \"loads rebar.config.script on dependency directory\" do\n      path = MixTest.Case.fixture_path(\"rebar_dep_script\")\n      config = Mix.Rebar.load_config(path)\n      assert config[:dir] == {:ok, String.to_charlist(path)}\n    end\n  end\n\n  @git_rebar_charlist ~c\"../../test/fixtures/git_rebar\"\n  @git_rebar_string \"../../test/fixtures/git_rebar\"\n\n  describe \"deps/1\" do\n    defp parse_dep(dep) do\n      [deps: [dep]] |> Mix.Rebar.deps() |> hd()\n    end\n\n    test \"parses Rebar dependencies\" do\n      assert parse_dep(:git_rebar) == {:git_rebar, override: true}\n\n      assert parse_dep({:git_rebar, ~c\"~> 1.0\"}) == {:git_rebar, \"~> 1.0\", override: true}\n\n      assert parse_dep({:git_rebar, ~c\"~> 1.0\", {:pkg, :rebar_fork}}) ==\n               {:git_rebar, \"~> 1.0\", override: true, hex: :rebar_fork}\n\n      assert parse_dep({:git_rebar, {:pkg, :rebar_fork}}) ==\n               {:git_rebar, override: true, hex: :rebar_fork}\n\n      assert parse_dep({:git_rebar, {:git, @git_rebar_charlist, :main}}) ==\n               {:git_rebar, override: true, git: @git_rebar_string, ref: \"main\"}\n\n      assert {:git_rebar, regex, override: true, git: @git_rebar_string, compile: false} =\n               parse_dep({:git_rebar, ~c\"0.1..*\", {:git, @git_rebar_charlist}, [:raw]})\n\n      assert Regex.source(regex) == \"0.1..*\"\n\n      assert {:git_rebar, regex, override: true, git: @git_rebar_string, ref: \"main\"} =\n               parse_dep({:git_rebar, ~c\"0.1..*\", {:git, @git_rebar_charlist, :main}})\n\n      assert Regex.source(regex) == \"0.1..*\"\n\n      assert {:git_rebar, regex, override: true, git: @git_rebar_string, ref: \"64691eb\"} =\n               parse_dep({:git_rebar, ~c\"\", {:git, @git_rebar_charlist, {:ref, ~c\"64691eb\"}}})\n\n      assert Regex.source(regex) == \"\"\n    end\n  end\n\n  describe \"apply_overrides/3\" do\n    test \"applies overrides\" do\n      config = [deps: {:git_rebar, ~c\"~> 2.0\"}]\n      overrides = [{:override, [deps: [{:git_rebar, ~c\"~> 1.0\"}]]}]\n\n      assert Mix.Rebar.apply_overrides(:foo, config, overrides) ==\n               [deps: [{:git_rebar, ~c\"~> 1.0\"}], overrides: overrides]\n\n      config = [deps: [{:git_rebar, ~c\"~> 2.0\"}]]\n      overrides = [{:override, :bar, [deps: [{:git_rebar, ~c\"~> 1.0\"}]]}]\n\n      assert Mix.Rebar.apply_overrides(:foo, config, overrides) ==\n               [deps: [{:git_rebar, ~c\"~> 2.0\"}], overrides: overrides]\n\n      config = [deps: [{:git_rebar, ~c\"~> 2.0\"}]]\n      overrides = [{:override, :foo, [deps: [{:git_rebar, ~c\"~> 1.0\"}]]}]\n\n      assert Mix.Rebar.apply_overrides(:foo, config, overrides) ==\n               [deps: [{:git_rebar, ~c\"~> 1.0\"}], overrides: overrides]\n\n      config = [deps: [{:git_rebar, ~c\"~> 1.0\"}]]\n      overrides = [{:add, :foo, [deps: [{:git_rebar2, ~c\"~> 2.0\"}]]}]\n\n      assert Mix.Rebar.apply_overrides(:foo, config, overrides) ==\n               [deps: [{:git_rebar2, ~c\"~> 2.0\"}, {:git_rebar, ~c\"~> 1.0\"}], overrides: overrides]\n    end\n\n    test \"concatenates overrides\" do\n      config = [deps: {:git_rebar, ~c\"~> 2.0\"}, overrides: [{:add, :bar, []}]]\n      overrides = [{:override, [deps: [{:git_rebar, ~c\"~> 1.0\"}]]}]\n\n      assert Mix.Rebar.apply_overrides(:foo, config, overrides) ==\n               [deps: [{:git_rebar, ~c\"~> 1.0\"}], overrides: overrides ++ [{:add, :bar, []}]]\n    end\n  end\n\n  describe \"dependency_config/1\" do\n    test \"converts Rebar config to dependency config\" do\n      config = Mix.Rebar.load_config(fixture_path(\"rebar_dep\"))\n      dep_config = Mix.Rebar.dependency_config(config)\n\n      assert config[:erl_opts] == [:warnings_as_errors]\n      assert config[:project_plugins] == [:remove_me]\n      assert dep_config[:erl_opts] == []\n      refute dep_config[:project_plugins]\n    end\n  end\n\n  describe \"integration with Mix\" do\n    test \"inherits Rebar manager\" do\n      Mix.Project.push(RebarAsDep)\n      deps = Mix.Dep.Converger.converge([])\n      assert Enum.all?(deps, &(&1.manager == :rebar3))\n    end\n\n    test \"parses Rebar dependencies from rebar.config\" do\n      Mix.Project.push(RebarAsDep)\n\n      deps = Mix.Dep.Converger.converge([])\n      assert Enum.all?(deps, &(&1.manager == :rebar3))\n      assert Enum.find(deps, &(&1.app == :rebar_dep))\n\n      assert Enum.find(deps, fn %Mix.Dep{app: app, opts: opts} ->\n               if app == :git_rebar do\n                 assert Enum.find(opts, &match?({:git, _}, &1))\n                 assert Enum.find(opts, &match?({:ref, \"main\"}, &1))\n                 true\n               end\n             end)\n    end\n\n    test \"handles Rebar overrides\" do\n      in_tmp(\"Rebar overrides\", fn ->\n        Mix.Project.push(RebarOverrideAsDep)\n\n        Mix.Tasks.Deps.Get.run([])\n\n        assert Mix.Dep.Converger.converge([]) |> Enum.map(& &1.app) ==\n                 [:git_repo, :git_rebar, :rebar_override]\n      end)\n    after\n      purge([GitRepo.MixProject])\n    end\n\n    # We run only on Unix because Windows has a hard time\n    # removing the Rebar executable after executed.\n    @tag :unix\n    test \"gets and compiles dependencies\" do\n      in_tmp(\"get and compile dependencies\", fn ->\n        Mix.Project.push(RebarAsDep)\n\n        Mix.Tasks.Deps.Get.run([])\n        assert_received {:mix_shell, :info, [\"* Getting git_rebar \" <> _]}\n\n        Mix.Tasks.Deps.Compile.run([])\n        assert_received {:mix_shell, :run, [\"===> Compiling git_rebar\\n\"]}\n        assert_received {:mix_shell, :run, [\"===> Compiling rebar_dep\\n\"]}\n        assert :git_rebar.any_function() == :ok\n        assert :rebar_dep.any_function() == :ok\n\n        load_paths =\n          Mix.Dep.Converger.converge([])\n          |> Enum.map(&Mix.Dep.load_paths(&1))\n          |> Enum.concat()\n\n        assert File.exists?(\"_build/dev/lib/rebar_dep/ebin/rebar_dep.beam\")\n        assert File.exists?(\"_build/dev/lib/git_rebar/ebin/git_rebar.beam\")\n\n        # Assert we have no .mix/compile.lock as a .mix/compile.lock\n        # means we check for the Elixir version on every command.\n        refute File.exists?(\"_build/dev/lib/rebar_dep/.mix/compile.lock\")\n        refute File.exists?(\"_build/dev/lib/git_rebar/.mix/compile.lock\")\n\n        assert Enum.any?(load_paths, &String.ends_with?(&1, \"git_rebar/ebin\"))\n        assert Enum.any?(load_paths, &String.ends_with?(&1, \"rebar_dep/ebin\"))\n      end)\n    end\n\n    # We run only on Unix because Windows has a hard time\n    # removing the Rebar executable after executed.\n    @tag :unix\n    test \"applies variables from :system_env option on config/compilation\" do\n      in_tmp(\"applies variables from system_env\", fn ->\n        Mix.Project.push(RebarAsDepWithEnv)\n\n        expected_file = Path.join(tmp_path(\"rebar_dep\"), \"rebar-test-rebar3\")\n        File.rm(expected_file)\n\n        Mix.Tasks.Deps.Get.run([])\n        Mix.Tasks.Deps.Compile.run([])\n\n        assert {:ok, \"rebar3\"} = File.read(expected_file)\n      end)\n    end\n\n    # We run only on Unix because Windows has a hard time\n    # removing the Rebar executable after executed.\n    @tag :unix\n    test \"gets and compiles dependencies with MIX_REBAR3 with spaces\" do\n      in_tmp(\"rebar3 env with spaces\", fn ->\n        File.cp!(Mix.Rebar.local_rebar_path(:rebar3), \"rebar3\")\n        System.put_env(\"MIX_REBAR3\", Path.absname(\"rebar3\"))\n        assert Mix.Rebar.rebar_args(:rebar3, []) |> elem(0) =~ \" \"\n\n        Mix.Project.push(RebarAsDep)\n        Mix.Tasks.Deps.Get.run([])\n        assert_received {:mix_shell, :info, [\"* Getting git_rebar \" <> _]}\n\n        Mix.Tasks.Deps.Compile.run([])\n        assert_received {:mix_shell, :run, [\"===> Compiling git_rebar\\n\"]}\n        assert_received {:mix_shell, :run, [\"===> Compiling rebar_dep\\n\"]}\n      end)\n    after\n      System.delete_env(\"MIX_REBAR3\")\n    end\n\n    test \"gets and compiles dependencies with Mix\" do\n      in_tmp(\"get and compile dependencies with Mix\", fn ->\n        Mix.Project.push(RebarAsDep)\n\n        File.write!(MixTest.Case.tmp_path(\"rebar_dep/mix.exs\"), \"\"\"\n        defmodule RebarDep.MixProject do\n          use Mix.Project\n\n          def project do\n            [app: :rebar_dep,\n             version: \"0.0.1\"]\n          end\n        end\n        \"\"\")\n\n        Mix.Tasks.Deps.Compile.run([])\n        assert_received {:mix_shell, :info, [\"==> rebar_dep\"]}\n        assert_received {:mix_shell, :info, [\"Generated rebar_dep app\"]}\n        assert File.regular?(\"_build/dev/lib/rebar_dep/ebin/rebar_dep.app\")\n      end)\n    after\n      File.rm(MixTest.Case.tmp_path(\"rebar_dep/mix.exs\"))\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/release_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.ReleaseTest do\n  use MixTest.Case\n\n  import Mix.Release\n  doctest Mix.Release\n\n  Application.ensure_loaded(:eex)\n  Application.ensure_loaded(:runtime_tools)\n\n  @erts_version :erlang.system_info(:version)\n  @erts_source Path.join(:code.root_dir(), \"erts-#{@erts_version}\")\n  @elixir_version Application.spec(:elixir, :vsn)\n  @kernel_version Application.spec(:kernel, :vsn)\n  @runtime_tools_version Application.spec(:runtime_tools, :vsn)\n  @eex_ebin Application.app_dir(:eex, \"ebin\")\n\n  setup_all do\n    Mix.ensure_application!(:sasl)\n    Mix.ensure_application!(:crypto)\n    :ok\n  end\n\n  setup do\n    File.rm_rf!(tmp_path(\"mix_release\"))\n    File.mkdir_p!(tmp_path(\"mix_release\"))\n    :ok\n  end\n\n  describe \"from_config!/3\" do\n    test \"uses default configuration if no release is specified\" do\n      assert %Mix.Release{\n               name: :mix,\n               version: \"0.1.0\",\n               path: path,\n               version_path: version_path\n             } = from_config!(nil, config(), [])\n\n      assert String.ends_with?(path, \"mix_release/_build/dev/rel/mix\")\n      assert String.ends_with?(version_path, \"mix_release/_build/dev/rel/mix/releases/0.1.0\")\n    end\n\n    test \"provides default options\" do\n      release = from_config!(nil, config(), [])\n      assert release.options == [overwrite: false, quiet: false, strip_beams: true]\n    end\n\n    test \"allows overrides\" do\n      overrides = [path: \"demo\", version: \"0.2.0\", overwrite: true, quiet: true]\n      release = from_config!(nil, config(), overrides)\n\n      assert release.path == Path.absname(\"demo\")\n      assert release.version == \"0.2.0\"\n      assert release.options[:overwrite]\n      assert release.options[:quiet]\n    end\n\n    test \"allows specifying the version from an application\" do\n      overrides = [version: {:from_app, :elixir}]\n      release = from_config!(nil, config(), overrides)\n\n      assert release.version == to_string(Application.spec(:elixir, :vsn))\n    end\n\n    test \"raises when :from_app is used with an app that doesn't exist\" do\n      overrides = [version: {:from_app, :not_valid}]\n\n      assert_raise Mix.Error,\n                   ~r\"Could not find version for :not_valid, please make sure the application exists\",\n                   fn -> from_config!(nil, config(), overrides) end\n    end\n\n    test \"includes applications\" do\n      release = from_config!(nil, config(), [])\n      assert release.applications.mix[:path] == to_charlist(Application.app_dir(:mix))\n      refute release.applications.mix[:otp_app?]\n\n      assert release.applications.kernel[:path] == to_charlist(Application.app_dir(:kernel))\n      assert release.applications.kernel[:otp_app?]\n    end\n\n    test \"does not include erts in applications\" do\n      release = from_config!(nil, config(releases: [foo: [applications: [erts: :permanent]]]), [])\n      assert release.applications[:erts] == nil\n    end\n\n    test \"allows release to be given as an anonymous function\" do\n      release = from_config!(:foo, config(releases: [foo: fn -> [version: \"0.2.0\"] end]), [])\n      assert release.name == :foo\n      assert release.version == \"0.2.0\"\n    end\n\n    test \"uses chosen release via the CLI\" do\n      release =\n        from_config!(\n          :bar,\n          config(releases: [foo: [version: \"0.2.0\"], bar: [version: \"0.3.0\"]]),\n          []\n        )\n\n      assert release.name == :bar\n      assert release.version == \"0.3.0\"\n      assert String.ends_with?(release.path, \"mix_release/_build/dev/rel/bar\")\n\n      assert String.ends_with?(\n               release.version_path,\n               \"mix_release/_build/dev/rel/bar/releases/0.3.0\"\n             )\n    end\n\n    test \"uses chosen release via the default_release\" do\n      release =\n        from_config!(\n          nil,\n          config(\n            default_release: :bar,\n            releases: [foo: [version: \"0.2.0\"], bar: [version: \"0.3.0\"]]\n          ),\n          []\n        )\n\n      assert release.name == :bar\n      assert release.version == \"0.3.0\"\n      assert String.ends_with?(release.path, \"mix_release/_build/dev/rel/bar\")\n\n      assert String.ends_with?(\n               release.version_path,\n               \"mix_release/_build/dev/rel/bar/releases/0.3.0\"\n             )\n    end\n\n    test \"raises for multiple releases and no name\" do\n      assert_raise Mix.Error,\n                   ~r\"\\\"mix release\\\" was invoked without a name but there are multiple releases\",\n                   fn -> from_config!(nil, config(releases: [foo: [], bar: []]), []) end\n    end\n\n    test \"raises for unknown release\" do\n      assert_raise Mix.Error, \"Unknown release :foo. The available releases are: []\", fn ->\n        from_config!(:foo, config(), [])\n      end\n    end\n\n    test \"uses the locked version of an app\", context do\n      in_tmp(context.test, fn ->\n        # install newer version of the app in the custom ERTS\n        custom_erts_path = Path.join([File.cwd!(), \"erts-#{@erts_version}\"])\n        File.cp_r!(@erts_source, custom_erts_path)\n\n        ebin_dir = Path.expand(Path.join([custom_erts_path, \"..\", \"lib\", \"cowboy-2.0.0\", \"ebin\"]))\n        File.mkdir_p!(ebin_dir)\n        app_resource = \"{application,cowboy,[{vsn,\\\"2.0.0\\\"},{modules,[]},{applications,[]}]}.\"\n        File.write!(Path.join(ebin_dir, \"cowboy.app\"), app_resource)\n\n        # install older version of the app in the project dependencies\n        project_path = Path.join(File.cwd!(), \"project\")\n        build_path = Path.join(project_path, \"_build\")\n        ebin_dir = Path.join([build_path, \"dev\", \"lib\", \"cowboy\", \"ebin\"])\n        File.mkdir_p!(ebin_dir)\n        app_resource = \"{application,cowboy,[{vsn,\\\"1.1.2\\\"},{modules,[]},{applications,[]}]}.\"\n        File.write!(Path.join(ebin_dir, \"cowboy.app\"), app_resource)\n\n        File.mkdir_p!(Path.join([project_path, \"deps\", \"cowboy\"]))\n        lockfile = Path.join(project_path, \"mix.lock\")\n\n        File.write!(lockfile, ~S\"\"\"\n        %{\n          \"cowboy\": {:hex, :cowboy, \"1.1.2\"},\n        }\n        \"\"\")\n\n        app_config =\n          config(\n            deps: [{:cowboy, \"~> 1.0\", path: \"deps/cowboy\"}],\n            releases: [demo: [include_erts: custom_erts_path, applications: [cowboy: :permanent]]]\n          )\n\n        Mix.Project.in_project(:mix, project_path, app_config, fn _ ->\n          Code.prepend_path(ebin_dir)\n          release = from_config!(nil, app_config, [])\n          assert release.applications.cowboy[:vsn] == ~c\"1.1.2\"\n        end)\n      end)\n    end\n\n    test \"uses the latest version of an app if it is not locked\", context do\n      in_tmp(context.test, fn ->\n        test_erts_dir = Path.join(File.cwd!(), \"erts-#{@erts_version}\")\n        test_libs_dir = Path.join(File.cwd!(), \"lib\")\n        libs_dir = Path.join(:code.root_dir(), \"lib\")\n        libs = File.ls!(libs_dir)\n\n        File.cp_r!(@erts_source, test_erts_dir)\n\n        for lib <- libs,\n            source_file <- Path.wildcard(Path.join([libs_dir, lib, \"ebin\", \"*.app\"])) do\n          target_dir = Path.join([test_libs_dir, lib, \"ebin\"])\n          target_file = Path.join(target_dir, Path.basename(source_file))\n\n          File.mkdir_p!(target_dir)\n          File.cp!(source_file, target_file)\n        end\n\n        File.mkdir_p!(Path.join(\"lib\", \"compiler-1.0\"))\n\n        release = from_config!(nil, config(releases: [demo: [include_erts: test_erts_dir]]), [])\n\n        assert Path.dirname(release.applications.compiler[:path]) == test_libs_dir\n        assert release.applications.compiler[:vsn] != \"1.0\"\n      end)\n    end\n\n    test \"raises on unknown app\" do\n      assert_raise Mix.Error, \"Could not find application :unknown\", fn ->\n        from_config!(nil, config(releases: [demo: [applications: [unknown: :none]]]), [])\n      end\n    end\n\n    test \"raises for missing version\" do\n      assert_raise Mix.Error, ~r\"No :version found\", fn ->\n        from_config!(nil, config() |> Keyword.drop([:version]), [])\n      end\n    end\n\n    test \"raises for blank version\" do\n      assert_raise Mix.Error, ~r\"The release :version cannot be an empty string\", fn ->\n        from_config!(nil, config(version: \"\"), [])\n      end\n    end\n\n    test \"raises on invalid release names\" do\n      assert_raise Mix.Error, ~r\"Invalid release name\", fn ->\n        from_config!(nil, config(releases: [\"invalid name\": []]), [])\n      end\n    end\n\n    test \"raises on bad steps\" do\n      assert_raise Mix.Error,\n                   ~r\"The :steps option must be\",\n                   fn -> release(steps: :foo) end\n\n      assert_raise Mix.Error,\n                   ~r\"The :steps option must contain the atom :assemble once, got: \\[\\]\",\n                   fn -> release(steps: []) end\n\n      assert_raise Mix.Error,\n                   ~r\"The :steps option must contain the atom :assemble once\",\n                   fn -> release(steps: [:assemble, :assemble]) end\n\n      assert_raise Mix.Error,\n                   ~r\"The :tar step must come after :assemble\",\n                   fn -> release(steps: [:tar, :assemble]) end\n\n      assert_raise Mix.Error,\n                   ~r\"The :steps option can only contain the atom :tar once\",\n                   fn -> release(steps: [:assemble, :tar, :tar]) end\n\n      assert_raise Mix.Error,\n                   ~r\"The :steps option must be\",\n                   fn -> release(steps: [:foo]) end\n    end\n  end\n\n  describe \"from_config!/3 + umbrella\" do\n    test \"cannot infer for umbrella projects\" do\n      assert_raise Mix.Error,\n                   ~r\"Umbrella projects require releases to be explicitly defined\",\n                   fn -> from_config!(nil, config(apps_path: \"apps\"), []) end\n    end\n\n    test \"requires apps for umbrella projects\" do\n      assert_raise Mix.Error,\n                   ~r\"Umbrella projects require releases to be explicitly defined\",\n                   fn -> from_config!(nil, config(apps_path: \"apps\", releases: [foo: []]), []) end\n    end\n\n    test \"builds explicit releases with applications\" do\n      config = config(apps_path: \"apps\", releases: [foo: [applications: [mix: :permanent]]])\n\n      assert %Mix.Release{\n               name: :foo,\n               version: \"0.1.0\",\n               path: _path,\n               version_path: _version_path\n             } = from_config!(nil, config, [])\n    end\n  end\n\n  describe \"from_config!/3 + boot_scripts\" do\n    test \"generates a start boot script with current application\" do\n      release = release([])\n\n      assert release.boot_scripts.start == [\n               kernel: :permanent,\n               stdlib: :permanent,\n               elixir: :permanent,\n               sasl: :permanent,\n               mix: :permanent,\n               iex: :none,\n               compiler: :permanent\n             ]\n    end\n\n    test \"includes extra application in order\" do\n      # Current app is always last\n      release = release(applications: [eex: :permanent])\n\n      assert release.boot_scripts.start == [\n               kernel: :permanent,\n               stdlib: :permanent,\n               elixir: :permanent,\n               sasl: :permanent,\n               eex: :permanent,\n               mix: :permanent,\n               iex: :none,\n               compiler: :permanent\n             ]\n\n      # Unless explicitly given\n      release = release(applications: [mix: :permanent, eex: :permanent])\n\n      assert release.boot_scripts.start == [\n               kernel: :permanent,\n               stdlib: :permanent,\n               elixir: :permanent,\n               sasl: :permanent,\n               mix: :permanent,\n               eex: :permanent,\n               iex: :none,\n               compiler: :permanent\n             ]\n    end\n\n    test \"configures other applications\" do\n      release = release(applications: [mix: :temporary])\n      assert release.boot_scripts.start[:mix] == :temporary\n\n      release = release(applications: [iex: :temporary])\n      assert release.boot_scripts.start[:iex] == :temporary\n    end\n\n    test \"configures other applications in cascade\", context do\n      in_tmp(context.test, fn ->\n        write_app!(\n          \"my_sample_mode/ebin/my_sample_mode.app\",\n          {:application, :my_sample_mode,\n           applications: [:kernel, :stdlib, :elixir, :runtime_tools, :compiler],\n           description: ~c\"my_sample_mode\",\n           modules: [],\n           vsn: ~c\"1.0.0\"}\n        )\n\n        apps = [my_sample_mode: :temporary]\n        release = release(applications: apps)\n        assert release.boot_scripts.start[:my_sample_mode] == :temporary\n        assert release.boot_scripts.start[:runtime_tools] == :temporary\n        assert release.boot_scripts.start[:compiler] == :permanent\n\n        apps = [my_sample_mode: :temporary, elixir: :permanent]\n        release = release(applications: apps)\n        assert release.boot_scripts.start[:my_sample_mode] == :temporary\n        assert release.boot_scripts.start[:runtime_tools] == :temporary\n        assert release.boot_scripts.start[:compiler] == :permanent\n\n        apps = [my_sample_mode: :temporary, runtime_tools: :none, compiler: :none]\n        release = release(applications: apps)\n        assert release.boot_scripts.start[:my_sample_mode] == :temporary\n        assert release.boot_scripts.start[:runtime_tools] == :none\n        assert release.boot_scripts.start[:compiler] == :none\n\n        apps = [my_sample_mode: :temporary, elixir: :permanent, compiler: :none]\n        release = release(applications: apps)\n        assert release.boot_scripts.start[:my_sample_mode] == :temporary\n        assert release.boot_scripts.start[:runtime_tools] == :temporary\n        assert release.boot_scripts.start[:compiler] == :none\n      end)\n    end\n\n    test \"generates a start_clean script with only kernel and stdlib starting up\" do\n      release = release([])\n\n      assert release.boot_scripts.start_clean == [\n               kernel: :permanent,\n               stdlib: :permanent,\n               elixir: :load,\n               sasl: :load,\n               mix: :load,\n               iex: :none,\n               compiler: :load\n             ]\n    end\n  end\n\n  describe \"from_config!/3 + include_erts\" do\n    test \"when true (default)\" do\n      release = release([])\n      assert release.erts_version == @erts_version\n      assert release.erts_source == to_charlist(@erts_source)\n    end\n\n    test \"when false\" do\n      release = release(include_erts: false)\n      assert release.erts_version == @erts_version\n      assert release.erts_source == nil\n    end\n\n    test \"when anonymous function\" do\n      release = release(include_erts: fn -> true end)\n      assert release.erts_version == @erts_version\n      assert release.erts_source == to_charlist(@erts_source)\n\n      release = release(include_erts: fn -> false end)\n      assert release.erts_version == @erts_version\n      assert release.erts_source == nil\n    end\n\n    test \"with valid path\" do\n      release = release(include_erts: @erts_source)\n      assert release.erts_version == @erts_version\n      assert release.erts_source == to_charlist(@erts_source)\n    end\n\n    test \"with invalid path\" do\n      assert_raise Mix.Error, \"Could not find ERTS system at \\\"bad\\\"\", fn ->\n        release(include_erts: \"bad\")\n      end\n    end\n  end\n\n  describe \"make_boot_script/4\" do\n    @boot_script_path tmp_path(\"mix_release/start\")\n\n    test \"writes .rel, .boot, and .script files\" do\n      release = release([])\n      assert make_boot_script(release, @boot_script_path, release.boot_scripts.start) == :ok\n\n      assert {:ok,\n              [\n                {:release, {~c\"demo\", ~c\"0.1.0\"}, {:erts, @erts_version},\n                 [\n                   {:kernel, _, :permanent},\n                   {:stdlib, _, :permanent},\n                   {:elixir, @elixir_version, :permanent},\n                   {:sasl, _, :permanent},\n                   {:mix, @elixir_version, :permanent},\n                   {:iex, @elixir_version, :none},\n                   {:compiler, _, :permanent}\n                 ]}\n              ]} = :file.consult(@boot_script_path <> \".rel\")\n\n      assert {:ok, [{:script, {~c\"demo\", ~c\"0.1.0\"}, instructions}]} =\n               :file.consult(@boot_script_path <> \".script\")\n\n      assert {:path, [~c\"$ROOT/lib/kernel-#{@kernel_version}/ebin\"]} in instructions\n      assert {:path, [~c\"$RELEASE_LIB/elixir-#{@elixir_version}/ebin\"]} in instructions\n\n      assert File.read!(@boot_script_path <> \".boot\") |> :erlang.binary_to_term() ==\n               {:script, {~c\"demo\", ~c\"0.1.0\"}, instructions}\n    end\n\n    test \"prepends relevant paths\" do\n      release = release([])\n\n      assert make_boot_script(\n               release,\n               @boot_script_path,\n               release.boot_scripts.start,\n               [\"$RELEASE_LIB/sample\"]\n             ) == :ok\n\n      assert {:ok, [{:script, {~c\"demo\", ~c\"0.1.0\"}, instructions}]} =\n               :file.consult(@boot_script_path <> \".script\")\n\n      assert {:path, [~c\"$ROOT/lib/kernel-#{@kernel_version}/ebin\"]} in instructions\n      refute {:path, [~c\"$RELEASE_LIB/elixir-#{@elixir_version}/ebin\"]} in instructions\n\n      assert {:path, [~c\"$RELEASE_LIB/sample\", ~c\"$RELEASE_LIB/elixir-#{@elixir_version}/ebin\"]} in instructions\n\n      assert File.read!(@boot_script_path <> \".boot\") |> :erlang.binary_to_term() ==\n               {:script, {~c\"demo\", ~c\"0.1.0\"}, instructions}\n    end\n\n    test \"works when :load/:none is set at the leaf\" do\n      release = release(applications: [mix: :none])\n      assert make_boot_script(release, @boot_script_path, release.boot_scripts.start) == :ok\n      {:ok, [{:release, _, _, rel_apps}]} = :file.consult(@boot_script_path <> \".rel\")\n      assert List.keyfind(rel_apps, :mix, 0) == {:mix, @elixir_version, :none}\n    end\n\n    test \"works when :load/:none is set at the subtree\" do\n      release = release(applications: [mix: :load, elixir: :load, iex: :load])\n      assert make_boot_script(release, @boot_script_path, release.boot_scripts.start) == :ok\n      {:ok, [{:release, _, _, rel_apps}]} = :file.consult(@boot_script_path <> \".rel\")\n      assert {:elixir, _, :load} = List.keyfind(rel_apps, :elixir, 0)\n      assert {:iex, _, :load} = List.keyfind(rel_apps, :iex, 0)\n      assert {:mix, _, :load} = List.keyfind(rel_apps, :mix, 0)\n    end\n\n    test \"raises on unknown app\" do\n      {:error, message} = make_boot_script(release([]), @boot_script_path, unknown: :permanent)\n      assert message =~ \"Unknown application :unknown\"\n    end\n\n    test \"raises on missing dependency\" do\n      {:error, message} = make_boot_script(release([]), @boot_script_path, elixir: :permanent)\n\n      assert message =~\n               \"Application :elixir is listed in the release boot, but it depends on :kernel, which isn't\"\n    end\n\n    test \"raises on unknown mode\" do\n      {:error, message} = make_boot_script(release([]), @boot_script_path, mix: :what)\n      assert message =~ \"Unknown mode :what for :mix\"\n    end\n\n    test \"raises on bad load/none\" do\n      release = release(applications: [kernel: :load])\n      {:error, message} = make_boot_script(release, @boot_script_path, release.boot_scripts.start)\n\n      assert message =~\n               \"Application :stdlib has mode :permanent but it depends on :kernel which is set to :load\"\n\n      release = release(applications: [elixir: :none])\n      {:error, message} = make_boot_script(release, @boot_script_path, release.boot_scripts.start)\n\n      assert message =~\n               \"Application :mix has mode :permanent but it depends on :elixir which is set to :none\"\n    end\n\n    test \"does not raise on child unsafe mode if parent is in `skip_mode_validation_for`\" do\n      # `:mix` is a parent that depends on `:elixir`\n      release = release(applications: [elixir: :load], skip_mode_validation_for: [:mix])\n      assert make_boot_script(release, @boot_script_path, release.boot_scripts.start) == :ok\n      assert make_boot_script(release, @boot_script_path, release.boot_scripts.start_clean) == :ok\n    end\n  end\n\n  describe \"make_cookie/1\" do\n    @cookie_path tmp_path(\"mix_release/cookie\")\n\n    test \"creates a random cookie if no cookie\" do\n      assert make_cookie(release([]), @cookie_path) == :ok\n      assert byte_size(File.read!(@cookie_path)) == 56\n    end\n\n    test \"uses the given cookie\" do\n      release = release(cookie: \"abcdefghijk\")\n      assert make_cookie(release, @cookie_path) == :ok\n      assert File.read!(@cookie_path) == \"abcdefghijk\"\n      assert make_cookie(release, @cookie_path) == :ok\n    end\n\n    test \"asks to change if the cookie changes\" do\n      assert make_cookie(release(cookie: \"abcdefghijk\"), @cookie_path) == :ok\n\n      send(self(), {:mix_shell_input, :yes?, false})\n      assert make_cookie(release(cookie: \"lmnopqrstuv\"), @cookie_path) == :ok\n      assert File.read!(@cookie_path) == \"abcdefghijk\"\n\n      send(self(), {:mix_shell_input, :yes?, true})\n      assert make_cookie(release(cookie: \"lmnopqrstuv\"), @cookie_path) == :ok\n      assert File.read!(@cookie_path) == \"lmnopqrstuv\"\n    end\n\n    test \"does not ask to change if set to overwrite\" do\n      assert make_cookie(release([]), @cookie_path) == :ok\n      send(self(), {:mix_shell_input, :yes?, false})\n      assert make_cookie(release([cookie: \"lmnopqrstuv\"], overwrite: true), @cookie_path) == :ok\n      assert File.read!(@cookie_path) == \"lmnopqrstuv\"\n    end\n  end\n\n  describe \"make_start_erl/1\" do\n    @start_erl_path tmp_path(\"mix_release/start_erl.data\")\n\n    test \"writes ERTS and release versions\" do\n      assert make_start_erl(release([]), @start_erl_path) == :ok\n      assert File.read!(@start_erl_path) == \"#{@erts_version} 0.1.0\"\n    end\n  end\n\n  describe \"make_sys_config/1\" do\n    @sys_config tmp_path(\"mix_release/_build/dev/rel/demo/releases/0.1.0/sys.config\")\n    @providers [{Config.Reader, \"/foo/bar/baz\"}]\n\n    test \"writes the given sys_config\" do\n      assert make_sys_config(release([]), [foo: [bar: :baz]], \"unused/runtime/path\") == :ok\n      contents = File.read!(@sys_config)\n      assert contents =~ \"%% RUNTIME_CONFIG=false\"\n      {:ok, contents} = :file.consult(@sys_config)\n      assert contents == [[foo: [bar: :baz]]]\n    end\n\n    test \"writes sys_config with encoding\" do\n      assert make_sys_config(\n               release([]),\n               [encoding: [key: {:_μ, :\"£\", \"£\", ~c\"£\"}]],\n               \"unused/runtime/path\"\n             ) ==\n               :ok\n\n      {:ok, contents} = :file.consult(@sys_config)\n      assert contents == [[encoding: [key: {:_μ, :\"£\", \"£\", ~c\"£\"}]]]\n    end\n\n    test \"writes the given sys_config with config providers\" do\n      release = release(config_providers: @providers, reboot_system_after_config: true)\n      assert make_sys_config(release, [kernel: [key: :value]], \"/foo/bar/bat\") == :ok\n      assert File.read!(@sys_config) =~ \"%% RUNTIME_CONFIG=true\"\n      {:ok, [config]} = :file.consult(@sys_config)\n      assert %Config.Provider{} = provider = config[:elixir][:config_provider_init]\n      refute provider.prune_runtime_sys_config_after_boot\n      assert provider.extra_config == [kernel: [start_distribution: true]]\n      assert config[:kernel] == [key: :value, start_distribution: false]\n    end\n\n    test \"writes the given sys_config without distribution and with pruning\" do\n      release =\n        release(\n          config_providers: @providers,\n          reboot_system_after_config: true,\n          start_distribution_during_config: true,\n          prune_runtime_sys_config_after_boot: true\n        )\n\n      assert make_sys_config(release, [kernel: [key: :value]], \"/foo/bar/bat\") == :ok\n      assert File.read!(@sys_config) =~ \"%% RUNTIME_CONFIG=true\"\n      {:ok, [config]} = :file.consult(@sys_config)\n      assert %Config.Provider{} = provider = config[:elixir][:config_provider_init]\n      assert provider.reboot_system_after_config\n      assert provider.prune_runtime_sys_config_after_boot\n      assert provider.extra_config == []\n      assert config[:kernel] == [key: :value]\n    end\n\n    test \"writes the given sys_config without reboot\" do\n      release = release(config_providers: @providers, reboot_system_after_config: false)\n      assert make_sys_config(release, [kernel: [key: :value]], \"/foo/bar/bat\") == :ok\n      assert File.read!(@sys_config) =~ \"%% RUNTIME_CONFIG=false\"\n      {:ok, [config]} = :file.consult(@sys_config)\n      assert %Config.Provider{} = provider = config[:elixir][:config_provider_init]\n      refute provider.reboot_system_after_config\n      assert provider.extra_config == []\n      assert config[:kernel] == [key: :value]\n    end\n\n    test \"errors on bad config\" do\n      assert {:error, \"Could not write configuration file \" <> _} =\n               make_sys_config(release([]), [foo: [bar: self()]], \"unused/runtime/path\")\n\n      env = %{__ENV__ | lexical_tracker: self()}\n\n      assert {:error, \"Could not write configuration file \" <> _} =\n               make_sys_config(release([]), [foo: [bar: env]], \"unused/runtime/path\")\n    end\n  end\n\n  describe \"copy_erts/1\" do\n    test \"copies to directory\" do\n      assert copy_erts(release(include_erts: true))\n      destination = tmp_path(\"mix_release/_build/dev/rel/demo/erts-#{@erts_version}\")\n      assert File.exists?(destination)\n\n      assert File.read!(Path.join(destination, \"bin/erl\")) =~\n               ~s|ROOTDIR=\"${ERL_ROOTDIR:-\"$(dirname \"$(dirname \"$BINDIR\")\")\"}|\n\n      if not match?({:win32, _}, :os.type()) do\n        assert File.lstat!(Path.join(destination, \"bin/erl\")).mode |> rem(0o1000) == 0o755\n      end\n\n      refute File.exists?(Path.join(destination, \"bin/erl.ini\"))\n      refute File.exists?(Path.join(destination, \"doc\"))\n\n      # Now we copy from the copy using a string and without src\n      new_destination = tmp_path(\"mix_release/_build/dev/rel/new_demo/erts-#{@erts_version}\")\n      File.rm_rf!(Path.join(destination, \"src\"))\n\n      release = from_config!(nil, config(releases: [new_demo: [include_erts: destination]]), [])\n      assert copy_erts(release)\n      assert File.exists?(new_destination)\n    end\n\n    test \"does not copy when include_erts is false\" do\n      refute copy_erts(release(include_erts: false))\n      destination = tmp_path(\"mix_release/_build/dev/rel/demo/erts-#{@erts_version}\")\n      refute File.exists?(destination)\n    end\n  end\n\n  describe \"copy_ebin/3\" do\n    test \"copies and strips beams\" do\n      assert copy_ebin(release([]), @eex_ebin, tmp_path(\"eex_ebin\"))\n\n      assert size!(Path.join(@eex_ebin, \"Elixir.EEx.beam\")) >\n               size!(tmp_path(\"eex_ebin/Elixir.EEx.beam\"))\n    end\n\n    test \"copies without stripping beams\" do\n      assert copy_ebin(release(strip_beams: false), @eex_ebin, tmp_path(\"eex_ebin\"))\n\n      assert size!(Path.join(@eex_ebin, \"Elixir.EEx.beam\")) ==\n               size!(tmp_path(\"eex_ebin/Elixir.EEx.beam\"))\n    end\n\n    test \"returns false for unknown or empty directories\" do\n      source = tmp_path(\"mix_release\")\n      refute copy_ebin(release([]), source, tmp_path(\"mix_release\"))\n      File.mkdir_p!(source)\n      refute copy_ebin(release([]), source, tmp_path(\"mix_release\"))\n    end\n\n    test \"preserves file mode\" do\n      source = tmp_path(\"source_ebin\")\n      source_so_path = Path.join(source, \"libtest_nif.so\")\n\n      File.mkdir_p!(source)\n      File.touch!(source_so_path)\n      File.chmod!(source_so_path, 0o755)\n\n      assert copy_ebin(release([]), source, tmp_path(\"mix_release\"))\n\n      assert mode!(source_so_path) == mode!(tmp_path(\"mix_release/libtest_nif.so\"))\n    end\n  end\n\n  describe \"copy_app/2\" do\n    @release_lib tmp_path(\"mix_release/_build/dev/rel/demo/lib\")\n\n    test \"copies and strips beams\" do\n      assert copy_app(release(applications: [eex: :permanent]), :eex)\n\n      assert size!(Path.join(@eex_ebin, \"Elixir.EEx.beam\")) >\n               size!(Path.join(@release_lib, \"eex-#{@elixir_version}/ebin/Elixir.EEx.beam\"))\n    end\n\n    test \"copies without stripping beams\" do\n      assert copy_app(release(strip_beams: false, applications: [eex: :permanent]), :eex)\n\n      assert size!(Path.join(@eex_ebin, \"Elixir.EEx.beam\")) ==\n               size!(Path.join(@release_lib, \"eex-#{@elixir_version}/ebin/Elixir.EEx.beam\"))\n    end\n\n    test \"copies OTP apps\" do\n      release = release(applications: [runtime_tools: :permanent])\n      assert copy_app(release, :runtime_tools)\n      assert File.exists?(Path.join(@release_lib, \"runtime_tools-#{@runtime_tools_version}/ebin\"))\n      assert File.exists?(Path.join(@release_lib, \"runtime_tools-#{@runtime_tools_version}/priv\"))\n    end\n\n    test \"does not copy OTP app if include_erts is false\" do\n      release = release(include_erts: false, applications: [runtime_tools: :permanent])\n      refute copy_app(release, :runtime_tools)\n      refute File.exists?(Path.join(@release_lib, \"runtime_tools-#{@runtime_tools_version}/ebin\"))\n      refute File.exists?(Path.join(@release_lib, \"runtime_tools-#{@runtime_tools_version}/priv\"))\n    end\n  end\n\n  describe \"strip_beam/1\" do\n    test \"excludes at least docs and dbgi chunks\" do\n      {:ok, beam} =\n        Path.join(@eex_ebin, \"Elixir.EEx.beam\")\n        |> File.read!()\n        |> strip_beam()\n\n      assert {:error, :beam_lib, {:missing_chunk, _, ~c\"Dbgi\"}} =\n               :beam_lib.chunks(beam, [~c\"Dbgi\"])\n\n      assert {:error, :beam_lib, {:missing_chunk, _, ~c\"Docs\"}} =\n               :beam_lib.chunks(beam, [~c\"Docs\"])\n    end\n\n    test \"can keep docs and debug info, if requested\" do\n      {:ok, beam} =\n        Path.join(@eex_ebin, \"Elixir.EEx.beam\")\n        |> File.read!()\n        |> strip_beam(keep: [\"Docs\", \"Dbgi\"])\n\n      assert {:ok, {EEx, [{~c\"Dbgi\", _}]}} = :beam_lib.chunks(beam, [~c\"Dbgi\"])\n      assert {:ok, {EEx, [{~c\"Docs\", _}]}} = :beam_lib.chunks(beam, [~c\"Docs\"])\n    end\n\n    test \"strip beams without compression\" do\n      {:ok, beam} =\n        Path.join(@eex_ebin, \"Elixir.EEx.beam\")\n        |> File.read!()\n        |> strip_beam(compress: false)\n\n      assert match?(<<\"FOR1\", _::binary>>, beam)\n    end\n  end\n\n  describe \"included applications\" do\n    test \"are included in the release\", context do\n      in_tmp(context.test, fn ->\n        write_app!(\n          \"my_sample1/ebin/my_sample1.app\",\n          {:application, :my_sample1,\n           applications: [:kernel, :stdlib, :elixir],\n           description: ~c\"my_sample1\",\n           modules: [],\n           vsn: ~c\"1.0.0\",\n           included_applications: [:runtime_tools]}\n        )\n\n        release = release(applications: [my_sample1: :permanent])\n        assert release.boot_scripts.start[:runtime_tools] == :load\n\n        release = release(applications: [my_sample1: :permanent, runtime_tools: :none])\n        assert release.boot_scripts.start[:runtime_tools] == :none\n      end)\n    end\n\n    test \"raise on conflict\", context do\n      in_tmp(context.test, fn ->\n        write_app!(\n          \"my_sample2/ebin/my_sample2.app\",\n          {:application, :my_sample2,\n           applications: [:kernel, :stdlib, :elixir, :runtime_tools],\n           description: ~c\"my_sample\",\n           modules: [],\n           vsn: ~c\"1.0.0\",\n           included_applications: [:runtime_tools]}\n        )\n\n        assert_raise Mix.Error,\n                     \":runtime_tools is listed both as a regular application and as an included application\",\n                     fn -> release(applications: [my_sample2: :permanent]) end\n      end)\n    end\n  end\n\n  describe \"optional applications\" do\n    test \"are ignored if not available\", context do\n      in_tmp(context.test, fn ->\n        write_app!(\n          \"my_sample3/ebin/my_sample3.app\",\n          {:application, :my_sample3,\n           applications: [:kernel, :stdlib, :elixir, :unknown],\n           optional_applications: [:unknown],\n           description: ~c\"my_sample3\",\n           modules: [],\n           vsn: ~c\"1.0.0\"}\n        )\n\n        release = release(applications: [my_sample3: :permanent])\n        assert release.boot_scripts.start[:unknown] == nil\n      end)\n    end\n\n    test \"are ignored even if mode changes\", context do\n      in_tmp(context.test, fn ->\n        write_app!(\n          \"has_optional/ebin/has_optional.app\",\n          {:application, :has_optional,\n           applications: [:kernel, :stdlib, :elixir, :unknown],\n           optional_applications: [:unknown],\n           description: ~c\"has_optional\",\n           modules: [],\n           vsn: ~c\"1.0.0\"}\n        )\n\n        write_app!(\n          \"points_as_permanent/ebin/points_as_permanent.app\",\n          {:application, :points_as_permanent,\n           applications: [:kernel, :stdlib, :elixir, :has_optional],\n           optional_applications: [:unknown],\n           description: ~c\"points_as_permanent\",\n           modules: [],\n           vsn: ~c\"1.0.0\"}\n        )\n\n        write_app!(\n          \"points_as_temporary/ebin/points_as_temporary.app\",\n          {:application, :points_as_temporary,\n           applications: [:kernel, :stdlib, :elixir, :has_optional],\n           optional_applications: [:unknown],\n           description: ~c\"points_as_temporary\",\n           modules: [],\n           vsn: ~c\"1.0.0\"}\n        )\n\n        release =\n          release(\n            applications: [points_as_permanent: :permanent, points_as_temporary: :temporary]\n          )\n\n        assert release.boot_scripts.start[:has_optional] == :permanent\n        assert release.boot_scripts.start[:unknown] == nil\n      end)\n    end\n  end\n\n  defp write_app!(path, app) do\n    dir = Path.dirname(path)\n    File.mkdir_p!(dir)\n    Code.prepend_path(dir)\n    format = :io_lib.format(\"%% coding: utf-8~n~p.~n\", [app])\n    File.write!(path, format)\n  end\n\n  defp size!(path) do\n    File.stat!(path).size\n  end\n\n  defp mode!(path) do\n    File.stat!(path).mode\n  end\n\n  defp release(config, overrides \\\\ []) do\n    from_config!(nil, config(releases: [demo: config]), overrides)\n  end\n\n  defp config(extra \\\\ []) do\n    [\n      app: :mix,\n      version: \"0.1.0\",\n      build_path: tmp_path(\"mix_release/_build\"),\n      build_per_environment: true,\n      config_path: tmp_path(\"mix_release/config/config.exs\")\n    ]\n    |> Keyword.merge(extra)\n  end\n\n  defmodule ReleaseApp do\n    def project do\n      [\n        app: :mix,\n        version: \"0.1.0\",\n        build_path: tmp_path(\"mix_release/_build\"),\n        build_per_environment: true,\n        config_path: tmp_path(\"mix_release/config/config.exs\")\n      ]\n      |> Keyword.merge(Process.get(:project))\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/scm/git_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.SCM.GitTest do\n  use MixTest.Case, async: true\n\n  test \"formats the lock\" do\n    assert Mix.SCM.Git.format_lock(lock()) == \"abcdef0\"\n    assert Mix.SCM.Git.format_lock(lock(branch: \"main\")) == \"abcdef0 (branch: main)\"\n    assert Mix.SCM.Git.format_lock(lock(tag: \"v0.12.0\")) == \"abcdef0 (tag: v0.12.0)\"\n    assert Mix.SCM.Git.format_lock(lock(ref: \"abcdef0\")) == \"abcdef0 (ref)\"\n  end\n\n  test \"considers two dep equals if the have the same Git and the same opts\" do\n    assert Mix.SCM.Git.equal?([git: \"foo\"], git: \"foo\")\n    refute Mix.SCM.Git.equal?([git: \"foo\"], git: \"bar\")\n\n    assert Mix.SCM.Git.equal?([git: \"foo\", branch: \"main\"], git: \"foo\", branch: \"main\")\n    refute Mix.SCM.Git.equal?([git: \"foo\", branch: \"main\"], git: \"foo\", branch: \"other\")\n  end\n\n  test \"lock should not be taken into account when considering deps equal as the lock is shared\" do\n    assert Mix.SCM.Git.equal?([git: \"foo\", lock: 1], git: \"foo\", lock: 2)\n  end\n\n  test \"get and update should display git checkout options along the url\" do\n    opts = [git: \"https://github.com/elixir-lang/some_dep.git\"]\n\n    assert Mix.SCM.Git.format(opts) ==\n             \"https://github.com/elixir-lang/some_dep.git\"\n\n    assert Mix.SCM.Git.format(Keyword.put(opts, :tag, \"v1\")) ==\n             \"https://github.com/elixir-lang/some_dep.git - v1\"\n\n    assert Mix.SCM.Git.format(Keyword.put(opts, :branch, \"b\")) ==\n             \"https://github.com/elixir-lang/some_dep.git - b\"\n\n    assert Mix.SCM.Git.format(Keyword.put(opts, :ref, \"abcdef\")) ==\n             \"https://github.com/elixir-lang/some_dep.git - abcdef\"\n  end\n\n  test \"redacts username password from urls\" do\n    url = \"https://username:password@github.com/elixir-lang/some_dep.git\"\n    opts = [git: url]\n\n    assert Mix.SCM.Git.format(opts) ==\n             \"https://****:****@github.com/elixir-lang/some_dep.git\"\n\n    assert_raise Mix.Error, ~r/[*]{4}:[*]{4}/, fn ->\n      Mix.SCM.Git.accepts_options(nil, git: url, branch: \"main\", branch: \"develop\")\n    end\n  end\n\n  test \"raises about conflicting Git refspec options\" do\n    assert_raise Mix.Error, ~r/You should specify only one of branch, ref or tag/, fn ->\n      Mix.SCM.Git.accepts_options(nil, git: \"/repo\", branch: \"main\", tag: \"0.1.0\")\n    end\n\n    assert_raise Mix.Error, ~r/You should specify only one of branch, ref or tag/, fn ->\n      Mix.SCM.Git.accepts_options(nil, git: \"/repo\", branch: \"main\", branch: \"develop\")\n    end\n  end\n\n  test \"raises about non-binary Git refspec options\" do\n    assert_raise Mix.Error, ~r/A dependency's branch must be a string/, fn ->\n      Mix.SCM.Git.accepts_options(nil, git: \"/repo\", branch: :main)\n    end\n\n    assert_raise Mix.Error, ~r/A dependency's tag must be a string/, fn ->\n      Mix.SCM.Git.accepts_options(nil, git: \"/repo\", tag: :stable)\n    end\n\n    assert_raise Mix.Error, ~r/A dependency's ref must be a string/, fn ->\n      Mix.SCM.Git.accepts_options(nil, git: \"/repo\", ref: :abcdef0123456789)\n    end\n  end\n\n  defp lock(opts \\\\ []) do\n    [lock: {:git, \"/repo\", \"abcdef0123456789\", opts}]\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/scm_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.SCMTest do\n  use MixTest.Case\n\n  setup do\n    available = Mix.SCM.available()\n    on_exit(fn -> Mix.State.put(:scm, available) end)\n    :ok\n  end\n\n  test \"prepends an SCM\" do\n    Mix.SCM.prepend(Hello)\n    assert Enum.at(Mix.SCM.available(), 0) == Hello\n    Mix.SCM.delete(Hello)\n    assert Hello not in Mix.SCM.available()\n  end\n\n  test \"appends an SCM\" do\n    Mix.SCM.append(Hello)\n    assert Enum.at(Mix.SCM.available(), -1) == Hello\n    Mix.SCM.delete(Hello)\n    assert Hello not in Mix.SCM.available()\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/shell/io_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Shell.IOTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n  import Mix.Shell.IO\n\n  test \"prints info message to stdio\" do\n    assert capture_io(fn ->\n             info(\"hello\")\n           end) == \"hello\\n\"\n  end\n\n  test \"prints error message to stderr\" do\n    assert capture_io(:stderr, fn ->\n             error(\"hello\")\n           end) =~ \"hello\"\n  end\n\n  test \"raises when device cannot prompt\" do\n    Process.group_leader(self(), Process.whereis(:standard_error))\n\n    assert_raise RuntimeError, \"Mix.shell().prompt/1 is not supported over this device\", fn ->\n      prompt(\"Ok?\")\n    end\n  end\n\n  test \"asks the user with yes? with implicit default option\" do\n    assert capture_io(\"\\n\", fn -> yes?(\"Ok?\") end) == \"Ok? [Yn] \"\n    assert capture_io(\"\\n\", fn -> assert yes?(\"Ok?\") end)\n    assert capture_io(\"Yes\", fn -> assert yes?(\"Ok?\") end)\n    assert capture_io(\"yes\", fn -> assert yes?(\"Ok?\") end)\n    assert capture_io(\"y\", fn -> assert yes?(\"Ok?\") end)\n\n    assert capture_io(\"n\", fn -> refute yes?(\"Ok?\") end)\n    assert capture_io(\"\", fn -> refute yes?(\"Ok?\") end)\n  end\n\n  test \"asks the user with yes? using :yes as default option\" do\n    assert capture_io(\"\\n\", fn -> yes?(\"Ok?\", default: :yes) end) == \"Ok? [Yn] \"\n    assert capture_io(\"\\n\", fn -> assert yes?(\"Ok?\", default: :yes) end)\n    assert capture_io(\"Yes\", fn -> assert yes?(\"Ok?\", default: :yes) end)\n    assert capture_io(\"yes\", fn -> assert yes?(\"Ok?\", default: :yes) end)\n    assert capture_io(\"y\", fn -> assert yes?(\"Ok?\", default: :yes) end)\n\n    assert capture_io(\"n\", fn -> refute yes?(\"Ok?\") end)\n    assert capture_io(\"\", fn -> refute yes?(\"Ok?\") end)\n  end\n\n  test \"asks the user with yes? using :no as default option\" do\n    assert capture_io(\"\\n\", fn -> yes?(\"Ok?\", default: :no) end) == \"Ok? [yN] \"\n    assert capture_io(\"Yes\", fn -> assert yes?(\"Ok?\", default: :no) end)\n    assert capture_io(\"yes\", fn -> assert yes?(\"Ok?\", default: :no) end)\n    assert capture_io(\"y\", fn -> assert yes?(\"Ok?\", default: :no) end)\n\n    assert capture_io(\"\\n\", fn -> refute yes?(\"Ok?\", default: :no) end)\n    assert capture_io(\"n\", fn -> refute yes?(\"Ok?\", default: :no) end)\n    assert capture_io(\"\", fn -> refute yes?(\"Ok?\", default: :no) end)\n  end\n\n  test \"asks the user with yes? and raise exception where default option is not valid\" do\n    message = \"expected :default to be either :yes or :no, got: :other\"\n\n    assert_raise ArgumentError, message, fn ->\n      capture_io(\"\\n\", fn -> yes?(\"Ok?\", default: :other) end)\n    end\n  end\n\n  test \"uses default when device cannot read\" do\n    Process.group_leader(self(), Process.whereis(:standard_error))\n    assert yes?(\"Ok?\")\n    refute yes?(\"Ok?\", default: :no)\n  end\n\n  test \"runs a given command\" do\n    nl = os_newline()\n\n    assert capture_io(\"\", fn -> assert cmd(\"echo hello\") == 0 end) == \"hello\" <> nl\n\n    will_print_sample()\n\n    assert capture_io(\"\", fn -> assert cmd(\"echo hello\", print_app: false) == 0 end) ==\n             \"hello\" <> nl\n\n    assert capture_io(\"\", fn -> assert cmd(\"echo hello\") == 0 end) == \"==> sample\\nhello\" <> nl\n  end\n\n  defp will_print_sample do\n    Mix.Project.push(nil)\n    Mix.Project.push(MixTest.Case.Sample)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/shell/quiet_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Shell.QuietTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n  import Mix.Shell.Quiet\n\n  test \"prints nothing to stdio when info is invoked\" do\n    assert capture_io(fn -> info(\"hello\") end) == \"\"\n  end\n\n  test \"prints error message to stderr\" do\n    assert capture_io(:stderr, fn -> error(\"hello\") end) =~ \"hello\"\n  end\n\n  test \"asks the user with yes?\" do\n    assert capture_io(\"\\n\", fn -> yes?(\"Ok?\") end) == \"Ok? [Yn] \"\n    assert capture_io(\"\\n\", fn -> assert yes?(\"Ok?\") end)\n    assert capture_io(\"Yes\", fn -> assert yes?(\"Ok?\") end)\n    assert capture_io(\"yes\", fn -> assert yes?(\"Ok?\") end)\n    assert capture_io(\"y\", fn -> assert yes?(\"Ok?\") end)\n\n    assert capture_io(\"n\", fn -> refute yes?(\"Ok?\") end)\n    assert capture_io(\"\", fn -> refute yes?(\"Ok?\") end)\n  end\n\n  test \"runs a given command\" do\n    assert capture_io(\"\", fn -> assert cmd(\"echo hello\") == 0 end) == \"\"\n\n    wont_print_sample()\n    assert capture_io(\"\", fn -> assert cmd(\"echo hello\", print_app: false) == 0 end) == \"\"\n    assert capture_io(\"\", fn -> assert cmd(\"echo hello\") == 0 end) == \"\"\n  end\n\n  defp wont_print_sample do\n    Mix.Project.push(nil)\n    Mix.Project.push(MixTest.Case.Sample)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/shell_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.ShellTest do\n  use MixTest.Case\n\n  defp capture_io(fun) do\n    fun |> ExUnit.CaptureIO.capture_io() |> String.replace(\"\\r\\n\", \"\\n\")\n  end\n\n  test \"executes cmd with expressions\" do\n    Mix.shell(Mix.Shell.IO)\n\n    assert capture_io(fn ->\n             assert Mix.shell().cmd(\"echo first && echo second\") == 0\n           end)\n           |> String.replace(\" \\n\", \"\\n\") == \"first\\nsecond\\n\"\n  after\n    Mix.shell(Mix.Shell.Process)\n  end\n\n  test \"with :cd\" do\n    Mix.shell(Mix.Shell.IO)\n    tmp_dir = System.tmp_dir()\n    File.mkdir_p!(tmp_dir)\n    {pwd, 0} = System.cmd(\"pwd\", [], cd: tmp_dir)\n\n    assert ExUnit.CaptureIO.capture_io(fn ->\n             Mix.shell().cmd(\"pwd\", cd: tmp_dir)\n           end) == pwd\n  after\n    Mix.shell(Mix.Shell.Process)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/sync/lock_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Sync.LockTest do\n  use ExUnit.Case, async: true\n\n  alias Mix.Sync.Lock\n\n  @lock_key Atom.to_string(__MODULE__)\n\n  test \"executes functions\" do\n    assert Lock.with_lock(@lock_key, fn -> :it_works! end) == :it_works!\n    assert Lock.with_lock(@lock_key, fn -> :still_works! end) == :still_works!\n  end\n\n  test \"releases lock on error\" do\n    assert_raise RuntimeError, fn ->\n      Lock.with_lock(@lock_key, fn -> raise \"oops\" end)\n    end\n\n    assert Lock.with_lock(@lock_key, fn -> :still_works! end) == :still_works!\n  end\n\n  test \"releases lock on exit\" do\n    {_pid, ref} =\n      spawn_monitor(fn ->\n        Lock.with_lock(@lock_key, fn -> Process.exit(self(), :kill) end)\n      end)\n\n    assert_receive {:DOWN, ^ref, _, _, _}\n    assert Lock.with_lock(@lock_key, fn -> :still_works! end) == :still_works!\n  end\n\n  test \"blocks until released\" do\n    parent = self()\n\n    task =\n      Task.async(fn ->\n        Lock.with_lock(@lock_key, fn ->\n          send(parent, :locked)\n          assert_receive :will_lock\n          :it_works!\n        end)\n      end)\n\n    assert_receive :locked\n    send(task.pid, :will_lock)\n    assert Lock.with_lock(@lock_key, fn -> :still_works! end) == :still_works!\n    assert Task.await(task) == :it_works!\n  end\n\n  @tag :capture_log\n  test \"blocks until released on error\" do\n    parent = self()\n\n    {pid, ref} =\n      spawn_monitor(fn ->\n        Lock.with_lock(@lock_key, fn ->\n          send(parent, :locked)\n          assert_receive :will_lock\n          raise \"oops\"\n        end)\n      end)\n\n    assert_receive :locked\n    send(pid, :will_lock)\n    assert Lock.with_lock(@lock_key, fn -> :still_works! end) == :still_works!\n    assert_receive {:DOWN, ^ref, _, _, _}\n  end\n\n  test \"blocks until released on exit\" do\n    parent = self()\n\n    {pid, ref} =\n      spawn_monitor(fn ->\n        Lock.with_lock(@lock_key, fn ->\n          send(parent, :locked)\n          assert_receive :will_not_lock\n        end)\n      end)\n\n    assert_receive :locked\n    Process.exit(pid, :kill)\n    assert Lock.with_lock(@lock_key, fn -> :still_works! end) == :still_works!\n    assert_receive {:DOWN, ^ref, _, _, _}\n  end\n\n  test \"schedules and releases on exit\" do\n    assert Lock.with_lock(@lock_key, fn ->\n             {pid, ref} =\n               spawn_monitor(fn ->\n                 Lock.with_lock(@lock_key, fn ->\n                   raise \"this will never be invoked\"\n                 end)\n               end)\n\n             Process.exit(pid, :kill)\n             assert_receive {:DOWN, ^ref, _, _, :killed}\n             :it_works!\n           end) == :it_works!\n\n    assert Lock.with_lock(@lock_key, fn -> :still_works! end) == :still_works!\n  end\n\n  @tag :tmp_dir\n  test \"property test with file access\", %{tmp_dir: tmp_dir} do\n    # Spawn N concurrent processes incrementing number in a file\n    n = 10\n    number_path = Path.join(tmp_dir, \"number.txt\")\n\n    File.write!(number_path, \"0\")\n\n    refs =\n      for _ <- 1..n do\n        spawn_monitor(fn ->\n          Lock.with_lock(@lock_key, fn ->\n            number = number_path |> File.read!() |> String.to_integer()\n            new_number = number + 1\n            File.write!(number_path, Integer.to_string(new_number))\n\n            assert File.read!(number_path) == Integer.to_string(new_number)\n\n            # Terminate without unlocking in random cases\n            case Enum.random(1..2) do\n              1 -> Process.exit(self(), :kill)\n              2 -> :ok\n            end\n          end)\n        end)\n        |> elem(1)\n      end\n\n    await_monitors(refs)\n\n    assert File.read!(number_path) == Integer.to_string(n)\n  end\n\n  test \"lock can be acquired multiple times by the same process\" do\n    {_pid, ref} =\n      spawn_monitor(fn ->\n        Lock.with_lock(@lock_key, fn ->\n          Lock.with_lock(@lock_key, fn ->\n            Process.exit(self(), :kill)\n          end)\n        end)\n      end)\n\n    assert_receive {:DOWN, ^ref, _, _, _}\n\n    assert Lock.with_lock(@lock_key, fn ->\n             Lock.with_lock(@lock_key, fn ->\n               :still_works!\n             end)\n           end) == :still_works!\n  end\n\n  test \"calls :on_taken when the lock is held by a different process\" do\n    parent = self()\n\n    {pid, ref} =\n      spawn_monitor(fn ->\n        Lock.with_lock(@lock_key, fn ->\n          send(parent, :locked)\n          assert_receive :will_lock\n        end)\n      end)\n\n    assert_receive :locked\n\n    on_taken = fn os_pid ->\n      send(pid, :will_lock)\n      send(self(), {:on_taken_called, os_pid})\n    end\n\n    assert Lock.with_lock(@lock_key, fn -> :it_works! end, on_taken: on_taken) == :it_works!\n\n    os_pid = System.pid()\n    assert_receive {:on_taken_called, ^os_pid}\n\n    assert_receive {:DOWN, ^ref, _, _, _}\n  end\n\n  defp await_monitors([]), do: :ok\n\n  defp await_monitors(refs) do\n    receive do\n      {:DOWN, ref, _, _, _} -> await_monitors(refs -- [ref])\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/sync/pubsub_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Sync.PubSubTest do\n  use ExUnit.Case, async: true\n\n  alias Mix.Sync.PubSub\n\n  @pubsub_key inspect(__MODULE__)\n\n  test \"delivers broadcast to multiple subscribers for the same key\" do\n    parent = self()\n\n    spawn_link(fn ->\n      PubSub.subscribe(@pubsub_key)\n      send(parent, :subscribed1)\n      assert_receive %{event: \"event1\"}\n      assert_receive %{event: \"event2\"}\n      send(parent, :done1)\n    end)\n\n    spawn_link(fn ->\n      PubSub.subscribe(@pubsub_key)\n      send(parent, :subscribed2)\n      assert_receive %{event: \"event1\"}\n      assert_receive %{event: \"event2\"}\n      send(parent, :done2)\n    end)\n\n    assert_receive :subscribed1\n    assert_receive :subscribed2\n\n    PubSub.broadcast(@pubsub_key, %{event: \"event1\"})\n    PubSub.broadcast(@pubsub_key, %{event: \"event2\"})\n\n    assert_receive :done1\n    assert_receive :done2\n  end\n\n  test \"delivers broadcast to subscribers for different keys\" do\n    parent = self()\n\n    spawn_link(fn ->\n      PubSub.subscribe([@pubsub_key, \"1\"])\n      send(parent, :subscribed1)\n      assert_receive %{event: \"event1\"}\n      assert_receive %{event: \"event3\"}\n      refute_received %{event: \"event2\"}\n      send(parent, :done1)\n    end)\n\n    spawn_link(fn ->\n      PubSub.subscribe([@pubsub_key, \"2\"])\n      send(parent, :subscribed2)\n      assert_receive %{event: \"event2\"}\n      assert_receive %{event: \"event3\"}\n      refute_received %{event: \"event1\"}\n      send(parent, :done2)\n    end)\n\n    assert_receive :subscribed1\n    assert_receive :subscribed2\n\n    PubSub.broadcast([@pubsub_key, \"1\"], %{event: \"event1\"})\n    PubSub.broadcast([@pubsub_key, \"2\"], %{event: \"event2\"})\n    PubSub.broadcast([@pubsub_key, \"1\"], %{event: \"event3\"})\n    PubSub.broadcast([@pubsub_key, \"2\"], %{event: \"event3\"})\n\n    assert_receive :done1\n    assert_receive :done2\n  end\n\n  test \"evaluates lazy message only if there are subscribers\" do\n    lazy_message = fn ->\n      send(self(), :lazy1)\n      %{event: \"event1\"}\n    end\n\n    PubSub.broadcast([@pubsub_key, \"lazy\"], lazy_message)\n\n    PubSub.subscribe([@pubsub_key, \"lazy\"])\n\n    lazy_message = fn ->\n      send(self(), :lazy2)\n      %{event: \"event2\"}\n    end\n\n    PubSub.broadcast([@pubsub_key, \"lazy\"], lazy_message)\n\n    refute_received :lazy1\n    assert_received :lazy2\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/task_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.TaskTest do\n  use MixTest.Case\n\n  defmodule SampleProject do\n    def project do\n      [app: :sample, version: \"0.0.1\"]\n    end\n  end\n\n  test \"run/2\" do\n    assert Mix.Task.run(\"hello\") == \"Hello, World!\"\n    assert Mix.Task.run(\"hello\") == :noop\n\n    assert_raise Mix.NoTaskError,\n                 \"The task \\\"unknown\\\" could not be found\\nNote no mix.exs was found in the current directory\",\n                 fn -> Mix.Task.run(\"unknown\") end\n\n    message =\n      \"The task \\\"helli\\\" could not be found. Did you mean \\\"hello\\\"?\\nNote no mix.exs was found in the current directory\"\n\n    assert_raise Mix.NoTaskError, message, fn ->\n      Mix.Task.run(\"helli\")\n    end\n\n    assert_raise Mix.InvalidTaskError, \"The task \\\"invalid\\\" does not export run/1\", fn ->\n      Mix.Task.run(\"invalid\")\n    end\n\n    message =\n      \"The task \\\"acronym.http\\\" could not be found because the module is named \" <>\n        \"Mix.Tasks.Acronym.HTTP instead of Mix.Tasks.Acronym.Http as expected. \" <>\n        \"Please rename it and try again\"\n\n    assert_raise Mix.NoTaskError, message, fn ->\n      Mix.Task.run(\"acronym.http\")\n    end\n  end\n\n  test \"run/2 converts OptionParser.ParseError into Mix errors\" do\n    message = ~r\"Could not invoke task \\\"hello\\\": 1 error found!\\n--unknown : Unknown option\"\n\n    assert_raise Mix.Error, message, fn ->\n      Mix.Task.run(\"hello\", [\"--parser\", \"--unknown\"])\n    end\n\n    Mix.Task.clear()\n\n    message =\n      ~r\"Could not invoke task \\\"hello\\\": 1 error found!\\n--int : Expected type integer, got \\\"foo\\\"\"\n\n    assert_raise Mix.Error, message, fn ->\n      Mix.Task.run(\"hello\", [\"--parser\", \"--int\", \"foo\"])\n    end\n  end\n\n  test \"run/2 outputs task debug info if Mix.debug? is true\" do\n    Mix.shell(Mix.Shell.IO)\n    Mix.debug(true)\n\n    assert ExUnit.CaptureIO.capture_io(fn -> Mix.Task.run(\"hello\") end) =~\n             ~r\"-> Running mix hello\\n<- Ran mix hello in \\d+ms\"\n  after\n    Mix.shell(Mix.Shell.Process)\n    Mix.debug(false)\n  end\n\n  defmodule DepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:raw_repo, \"0.1.0\", path: \"custom/raw_repo\"}\n        ]\n      ]\n    end\n  end\n\n  test \"run/2 tries to load deps if task is missing\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      assert_raise Mix.NoTaskError, fn ->\n        Mix.Task.run(\"task_hello\")\n      end\n\n      File.write!(\"custom/raw_repo/lib/task_hello.ex\", \"\"\"\n      defmodule Mix.Tasks.TaskHello do\n        use Mix.Task\n        def run(_), do: \"Hello World v1\"\n      end\n      \"\"\")\n\n      # Clean up the tasks and update task\n      Mix.Task.clear()\n\n      # Task was found from deps loadpaths\n      assert Mix.Task.run(\"task_hello\") == \"Hello World v1\"\n\n      # The compile task should not have run yet\n      assert Mix.Task.run(\"compile\") != :noop\n\n      # Clean up the tasks and update task\n      Mix.Task.clear()\n\n      File.write!(\"custom/raw_repo/lib/task_hello.ex\", \"\"\"\n      defmodule Mix.Tasks.TaskHello do\n        use Mix.Task\n        def run(_), do: \"Hello World v2\"\n      end\n      \"\"\")\n\n      # Simulate starting a new invocation\n      purge([Mix.Tasks.TaskHello])\n      Code.delete_path(\"_build/dev/lib/raw_repo/ebin\")\n      ensure_touched(\"custom/raw_repo/lib/task_hello.ex\")\n\n      # Task is recompiled to v2\n      assert Mix.Task.run(\"task_hello\") == \"Hello World v2\"\n    end)\n  end\n\n  test \"run/2 tries to compile if task is missing\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(SampleProject, \"sample\")\n\n      assert_raise Mix.NoTaskError, fn ->\n        Mix.Task.run(\"unknown\")\n      end\n\n      # Check if compile task have run\n      refute Mix.TasksServer.run({:task, \"compile\", Mix.Project.get()})\n    end)\n  end\n\n  test \"clear/0\" do\n    assert Mix.Task.run(\"hello\") == \"Hello, World!\"\n    Mix.Task.clear()\n    assert Mix.Task.run(\"hello\") == \"Hello, World!\"\n  end\n\n  test \"reenable/1\" do\n    assert Mix.Task.run(\"hello\") == \"Hello, World!\"\n    Mix.Task.reenable(\"hello\")\n    assert Mix.Task.run(\"hello\") == \"Hello, World!\"\n  end\n\n  test \"reenable/1 for recursive inside umbrella\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        assert [:ok, :ok] = Mix.Task.run(\"clean\")\n        assert [:noop, :noop] = Mix.Task.run(\"clean\")\n\n        Mix.Task.reenable(\"clean\")\n        assert [:ok, :ok] = Mix.Task.run(\"clean\")\n        assert [:noop, :noop] = Mix.Task.run(\"clean\")\n      end)\n    end)\n  end\n\n  test \"aliases considered for umbrella apps\" do\n    in_fixture(\"umbrella_test\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.mkdir_p!(\"apps/baz/lib/\")\n\n        File.write!(\"apps/baz/mix.exs\", \"\"\"\n        defmodule Baz.MixProject do\n          use Mix.Project\n\n          def project do\n            [\n              app: :baz,\n              version: \"0.1.0\",\n              aliases: [help: fn _ -> raise \"oops\" end]\n            ]\n          end\n        end\n        \"\"\")\n\n        File.write!(\"apps/baz/lib/baz.ex\", \"\"\"\n        defmodule Baz do\n          def hello do\n            :world\n          end\n        end\n        \"\"\")\n\n        Mix.Task.run(\"compile\")\n        assert_received {:mix_shell, :info, [\"==> foo\"]}\n        assert_received {:mix_shell, :info, [\"==> bar\"]}\n        assert_received {:mix_shell, :info, [\"==> baz\"]}\n        Mix.shell().flush()\n\n        # A child alias does not overlap an umbrella task\n        assert Mix.Task.run(\"help\") == :ok\n\n        # A missing umbrella alias can be found in children\n        assert [:ok, :ok] = Mix.Task.run(\"mytask\")\n        assert_received {:mix_shell, :info, [\"==> foo\"]}\n        assert_received {:mix_shell, :info, [\"foo_running\"]}\n        assert_received {:mix_shell, :info, [\"==> bar\"]}\n        assert_received {:mix_shell, :info, [\"bar_running\"]}\n        refute_received {:mix_shell, :info, [\"==> baz\"]}\n\n        # An unknown task or alias anywhere fails\n        assert_raise Mix.NoTaskError, fn ->\n          Mix.Task.run(\"completely_unknown\")\n        end\n      end)\n    end)\n  end\n\n  test \"reenable/1 for recursive inside umbrella child\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        assert [:ok, :ok] = Mix.Task.run(\"cmd\", [\"echo\", \"hello\"])\n        assert [:ok, :ok] = Mix.Task.run(\"cmd\", [\"echo\", \"world\"])\n\n        assert_received {:mix_shell, :run, [\"hello\" <> _]}\n        assert_received {:mix_shell, :run, [\"world\" <> _]}\n        assert_received {:mix_shell, :run, [\"hello\" <> _]}\n        assert_received {:mix_shell, :run, [\"world\" <> _]}\n      end)\n    end)\n  end\n\n  test \"reenable/1 for non-recursive inside umbrella\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        assert [:ok, :ok] = Mix.Task.run(\"clean\")\n        # loadpaths is not recursive\n        assert :ok = Mix.Task.run(\"loadpaths\")\n      end)\n    end)\n  end\n\n  test \"rerun/1\" do\n    assert Mix.Task.run(\"hello\") == \"Hello, World!\"\n    assert Mix.Task.rerun(\"hello\") == \"Hello, World!\"\n  end\n\n  test \"rerun/1 for umbrella\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        assert [:ok, :ok] = Mix.Task.run(\"clean\")\n        assert [:noop, :noop] = Mix.Task.run(\"clean\")\n        assert [:ok, :ok] = Mix.Task.rerun(\"clean\")\n      end)\n    end)\n  end\n\n  test \"get!\" do\n    Mix.Project.push(MixTest.Case.Sample)\n    assert Mix.Task.get!(\"hello\") == Mix.Tasks.Hello\n\n    assert_raise Mix.NoTaskError, \"The task \\\"unknown\\\" could not be found\", fn ->\n      Mix.Task.get!(\"unknown\")\n    end\n\n    assert_raise Mix.InvalidTaskError, \"The task \\\"invalid\\\" does not export run/1\", fn ->\n      Mix.Task.get!(\"invalid\")\n    end\n  end\n\n  test \"alias?/1\" do\n    assert Mix.Task.alias?(:sample) == false\n    assert Mix.Task.alias?(\"sample\") == false\n\n    Mix.Project.push(MixTest.Case.Sample)\n    assert Mix.Task.alias?(:sample) == true\n    assert Mix.Task.alias?(\"sample\") == true\n    assert Mix.Task.alias?(\"another\") == false\n  after\n    Mix.Project.pop()\n  end\n\n  test \"all_modules/0\" do\n    Mix.Task.load_all()\n    modules = Mix.Task.all_modules()\n    assert Mix.Tasks.Hello in modules\n    assert Mix.Tasks.Compile in modules\n  end\n\n  test \"moduledoc/1\" do\n    Code.prepend_path(MixTest.Case.tmp_path(\"beams\"))\n    assert Mix.Task.moduledoc(Mix.Tasks.Hello) == \"A test task.\\n\"\n  end\n\n  test \"shortdoc/1\" do\n    assert Mix.Task.shortdoc(Mix.Tasks.Hello) == \"This is short documentation, see\"\n  end\n\n  defmodule Elixir.Mix.Tasks.WithRequirement do\n    use Mix.Task\n    @shortdoc \"This is short documentation, see\"\n    @requirements \"help \\\"compile\\\"\"\n\n    @moduledoc \"\"\"\n    A test task.\n    \"\"\"\n\n    def run(_args) do\n      \"Task with requirements\"\n    end\n  end\n\n  test \"requirements/1\" do\n    assert Mix.Task.requirements(Mix.Tasks.WithRequirement) == [\"help \\\"compile\\\"\"]\n  end\n\n  test \"@requirements are running during task execution\" do\n    assert ExUnit.CaptureIO.capture_io(fn ->\n             assert Mix.Task.run(\"with_requirement\") == \"Task with requirements\"\n           end) =~ \"mix compile\"\n\n    Mix.Task.reenable(\"help\")\n\n    assert ExUnit.CaptureIO.capture_io(fn ->\n             assert Mix.Task.run(\"with_requirement\") == :noop\n           end) == \"\"\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/app.config_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.App.ConfigTest do\n  use MixTest.Case\n\n  test \"loads project configuration\" do\n    Process.put(\n      {MixTest.Case.Sample, :application},\n      env: [from_env: :env, from_compile: :env, from_runtime: :env]\n    )\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :sample, from_compile: :compile, from_runtime: :compile\n      config :sample, :nested, from_compile: :compile, from_runtime: :compile\n      \"\"\")\n\n      File.write!(\"config/runtime.exs\", \"\"\"\n      import Config\n      config :sample, from_runtime: :runtime\n      config :sample, :nested, from_compile: :compile, from_runtime: :compile\n      \"\"\")\n\n      Mix.Task.run(\"loadconfig\")\n      Mix.Task.run(\"app.config\")\n\n      assert Application.get_all_env(:sample) |> Enum.sort() == [\n               from_compile: :compile,\n               from_env: :env,\n               from_runtime: :runtime,\n               nested: [from_compile: :compile, from_runtime: :compile]\n             ]\n    end)\n  after\n    Application.delete_env(:sample, :nested, persistent: true)\n    Application.delete_env(:sample, :from_env, persistent: true)\n    Application.delete_env(:sample, :from_compile, persistent: true)\n    Application.delete_env(:sample, :from_runtime, persistent: true)\n  end\n\n  test \"sets config_env() and config_target()\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/runtime.exs\", \"\"\"\n      import Config\n      config :sample, vars: {config_env(), config_target()}\n      \"\"\")\n\n      Mix.Task.run(\"app.config\")\n      assert Application.get_all_env(:sample) == [vars: {:dev, :host}]\n    end)\n  after\n    Application.delete_env(:sample, :vars, persistent: true)\n  end\n\n  test \"warns if kernel/stdlib are configured\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/runtime.exs\", \"\"\"\n      import Config\n      config :kernel, this_wont: :work\n      \"\"\")\n\n      Mix.Task.run(\"loadconfig\")\n      Mix.Task.run(\"app.config\")\n\n      assert_received {:mix_shell, :error, [\"Cannot configure base applications: [:kernel]\" <> _]}\n    end)\n  end\n\n  test \"compiles and preloads the project\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      Mix.Task.run(\"app.config\", [\"--no-compile\"])\n      refute Code.ensure_loaded?(A)\n      refute File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      refute File.regular?(\"_build/dev/lib/sample/ebin/sample.app\")\n\n      Mix.Task.rerun(\"app.config\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/sample.app\")\n\n      assert Code.ensure_loaded?(A)\n      purge([A])\n\n      Mix.Task.rerun(\"app.config\", [])\n      refute Code.loaded?(A)\n\n      Mix.Task.rerun(\"app.config\", [\"--preload-modules\"])\n      assert Code.loaded?(A)\n    end)\n  end\n\n  test \"start checks for invalid configuration\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      :ok = :application.load({:application, :loaded_sample, [vsn: ~c\"1.0.0\", env: []]})\n      Mix.ProjectStack.loaded_config([:sample, :unknown_sample, :loaded_sample], [])\n      Mix.Tasks.App.Config.run([])\n\n      assert_received {:mix_shell, :error,\n                       [\"You have configured application :unknown_sample\" <> _]}\n\n      refute_received {:mix_shell, :error,\n                       [\"You have configured application :loaded_sample\" <> _]}\n    end)\n  end\n\n  test \"validates Elixir version requirement\", context do\n    Mix.ProjectStack.post_config(elixir: \"~> ~> 0.8.1\")\n\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      assert_raise Mix.Error, ~r\"Invalid Elixir version requirement\", fn ->\n        Mix.Tasks.App.Start.run([\"--no-start\"])\n      end\n    end)\n  end\n\n  test \"validates the Elixir version with requirement\", context do\n    Mix.ProjectStack.post_config(elixir: \"~> 0.8.1\")\n\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      assert_raise Mix.ElixirVersionError, ~r/You're trying to run :sample on Elixir/, fn ->\n        Mix.Tasks.App.Start.run([\"--no-start\"])\n      end\n    end)\n  end\n\n  test \"does not validate the Elixir version with requirement when disabled\", context do\n    Mix.ProjectStack.post_config(elixir: \"~> 0.8.1\")\n\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      Mix.Tasks.App.Start.run([\"--no-start\", \"--no-elixir-version-check\"])\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/app.start_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.App.StartTest do\n  use MixTest.Case\n\n  defmodule AppStartSample do\n    def project do\n      [app: :app_start_sample, version: \"0.1.0\"]\n    end\n\n    def application do\n      [applications: [:logger]]\n    end\n  end\n\n  @moduletag :capture_log\n\n  test \"compiles and starts the project\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(AppStartSample)\n\n      assert_raise Mix.Error, fn ->\n        Mix.Task.run(\"app.start\", [\"--no-compile\"])\n      end\n\n      refute List.keyfind(Application.started_applications(), :logger, 0)\n      Application.start(:logger)\n\n      Mix.Task.reenable(\"app.config\")\n      Mix.Task.reenable(\"app.start\")\n      Mix.Task.run(\"app.start\", [\"--no-start\"])\n      assert File.regular?(\"_build/dev/lib/app_start_sample/ebin/Elixir.A.beam\")\n      assert File.regular?(\"_build/dev/lib/app_start_sample/ebin/app_start_sample.app\")\n\n      refute Code.loaded?(A)\n      refute List.keyfind(Application.started_applications(), :app_start_sample, 0)\n      assert List.keyfind(Application.started_applications(), :logger, 0)\n\n      Mix.Task.reenable(\"app.config\")\n      Mix.Task.reenable(\"app.start\")\n      Mix.Task.run(\"app.start\", [])\n      refute Code.loaded?(A)\n      assert List.keyfind(Application.started_applications(), :app_start_sample, 0)\n      assert List.keyfind(Application.started_applications(), :logger, 0)\n    end)\n  after\n    Application.stop(:app_start_sample)\n  end\n\n  describe \"unit tests\" do\n    test \"start does nothing if no apps are given\" do\n      assert Mix.Tasks.App.Start.start([], :temporary, :serial) == :ok\n    end\n\n    test \"allows type to be configured\" do\n      assert Mix.Tasks.App.Start.type([], permanent: true) == :permanent\n      assert Mix.Tasks.App.Start.type([], temporary: true) == :temporary\n      assert Mix.Tasks.App.Start.type([start_permanent: true], []) == :permanent\n      assert Mix.Tasks.App.Start.type([], []) == :temporary\n    end\n\n    defmodule ReturnSample do\n      def project do\n        [app: :return_sample, version: \"0.1.0\"]\n      end\n\n      def application do\n        Process.get(:application_definition)\n      end\n    end\n\n    defmodule ReturnApp do\n      use Application\n\n      def start(_type, return), do: return\n    end\n\n    test \"start points to report on error\", context do\n      in_tmp(context.test, fn ->\n        Mix.Project.push(ReturnSample)\n\n        Process.put(:application_definition, mod: {ReturnApp, {:error, :bye}})\n        Mix.Tasks.Compile.run([])\n\n        message =\n          \"Could not start application return_sample: \" <>\n            \"Mix.Tasks.App.StartTest.ReturnApp.start(:normal, {:error, :bye}) \" <>\n            \"returned an error: :bye\"\n\n        assert_raise Mix.Error, message, fn ->\n          Mix.Tasks.App.Start.start([:return_sample], :temporary, :serial)\n        end\n      end)\n    end\n\n    test \"start points to report on exception error\", context do\n      in_tmp(context.test, fn ->\n        Mix.Project.push(ReturnSample)\n\n        mod = {ReturnApp, {:error, {:badarg, [{ReturnApp, :start, 2, []}]}}}\n        Process.put(:application_definition, mod: mod)\n        Mix.Tasks.Compile.run([])\n\n        message =\n          \"Could not start application return_sample: \" <>\n            \"Mix.Tasks.App.StartTest.ReturnApp.start(:normal, {:error, {:badarg, [{Mix.Tasks.App.StartTest.ReturnApp, :start, 2, []}]}}) \" <>\n            \"returned an error: an exception was raised:\\n\" <>\n            \"    ** (ArgumentError) argument error\\n\" <>\n            \"        Mix.Tasks.App.StartTest.ReturnApp.start/2\"\n\n        assert_raise Mix.Error, message, fn ->\n          Mix.Tasks.App.Start.start([:return_sample], :temporary, :serial)\n        end\n      end)\n    end\n\n    test \"start points to report on bad return\", context do\n      in_tmp(context.test, fn ->\n        Mix.Project.push(ReturnSample)\n\n        Process.put(:application_definition, mod: {ReturnApp, :bad})\n        Mix.Tasks.Compile.run([])\n\n        message =\n          \"Could not start application return_sample: \" <>\n            \"Mix.Tasks.App.StartTest.ReturnApp.start(:normal, :bad) \" <>\n            \"returned a bad value: :bad\"\n\n        assert_raise Mix.Error, message, fn ->\n          Mix.Tasks.App.Start.start([:return_sample], :temporary, :serial)\n        end\n      end)\n    end\n\n    defmodule ExitSample do\n      def project do\n        [app: :exit_sample, version: \"0.1.0\"]\n      end\n\n      def application do\n        Process.get(:application_definition)\n      end\n    end\n\n    defmodule ExitApp do\n      use Application\n\n      def start(_type, reason), do: exit(reason)\n    end\n\n    test \"start points to report on exit\", context do\n      in_tmp(context.test, fn ->\n        Mix.Project.push(ExitSample)\n\n        Process.put(:application_definition, mod: {ExitApp, :bye})\n        Mix.Tasks.Compile.run([])\n\n        message =\n          \"Could not start application exit_sample: exited in: \" <>\n            \"Mix.Tasks.App.StartTest.ExitApp.start(:normal, :bye)\\n\" <> \"    ** (EXIT) :bye\"\n\n        assert_raise Mix.Error, message, fn ->\n          Mix.Tasks.App.Start.start([:exit_sample], :temporary, :serial)\n        end\n      end)\n    end\n\n    test \"start points to report on normal exit\", context do\n      in_tmp(context.test, fn ->\n        Mix.Project.push(ExitSample)\n\n        Process.put(:application_definition, mod: {ExitApp, :normal})\n        Mix.Tasks.Compile.run([])\n\n        message =\n          \"Could not start application exit_sample: exited in: \" <>\n            \"Mix.Tasks.App.StartTest.ExitApp.start(:normal, :normal)\\n\" <> \"    ** (EXIT) normal\"\n\n        assert_raise Mix.Error, message, fn ->\n          Mix.Tasks.App.Start.start([:exit_sample], :temporary, :serial)\n        end\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/app.tree_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.App.TreeTest do\n  use MixTest.Case\n\n  defmodule AppDepsSample do\n    def project do\n      [app: :test, version: \"0.1.0\"]\n    end\n\n    def application do\n      [applications: [:logger, :app_deps_sample]]\n    end\n  end\n\n  @tag apps: [:test, :app_deps_sample, :app_deps2_sample, :app_deps3_sample, :app_deps4_sample]\n  test \"shows the application tree\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(AppDepsSample)\n\n      load_apps()\n      Mix.Tasks.App.Tree.run([\"--format\", \"pretty\"])\n\n      assert_received {:mix_shell, :info, [\"test\"]}\n      assert_received {:mix_shell, :info, [\"├── app_deps_sample\"]}\n      assert_received {:mix_shell, :info, [\"│   ├── app_deps2_sample\"]}\n      assert_received {:mix_shell, :info, [\"│   │   └── app_deps4_sample (included)\"]}\n      assert_received {:mix_shell, :info, [\"│   └── app_deps3_sample\"]}\n      assert_received {:mix_shell, :info, [\"├── elixir\"]}\n      assert_received {:mix_shell, :info, [\"└── logger\"]}\n      assert_received {:mix_shell, :info, [\"    └── elixir\"]}\n    end)\n  end\n\n  @tag apps: [:foo, :bar]\n  test \"show the application tree for umbrella apps\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Task.run(\"app.tree\", [\"--format\", \"pretty\"])\n        assert_received {:mix_shell, :info, [\"├── elixir\"]}\n        assert_received {:mix_shell, :info, [\"foo\"]}\n        assert_received {:mix_shell, :info, [\"    └── elixir\"]}\n      end)\n    end)\n  end\n\n  @tag apps: [:test, :app_deps_sample, :app_deps2_sample, :app_deps3_sample, :app_deps4_sample]\n  test \"shows the application tree with optional apps\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(AppDepsSample)\n\n      load_apps([:app_deps2_sample])\n      Mix.Tasks.App.Tree.run([\"--format\", \"pretty\"])\n      assert_received {:mix_shell, :info, [\"test\"]}\n      assert_received {:mix_shell, :info, [\"├── app_deps_sample\"]}\n      assert_received {:mix_shell, :info, [\"│   ├── app_deps2_sample (optional)\"]}\n      assert_received {:mix_shell, :info, [\"│   │   └── app_deps4_sample (included)\"]}\n      assert_received {:mix_shell, :info, [\"│   └── app_deps3_sample\"]}\n      assert_received {:mix_shell, :info, [\"├── elixir\"]}\n      assert_received {:mix_shell, :info, [\"└── logger\"]}\n      assert_received {:mix_shell, :info, [\"    └── elixir\"]}\n\n      Application.unload(:app_deps2_sample)\n      Mix.Tasks.App.Tree.run([\"--format\", \"pretty\"])\n      assert_received {:mix_shell, :info, [\"test\"]}\n      assert_received {:mix_shell, :info, [\"├── app_deps_sample\"]}\n      assert_received {:mix_shell, :info, [\"│   ├── app_deps2_sample (optional - missing)\"]}\n      assert_received {:mix_shell, :info, [\"│   └── app_deps3_sample\"]}\n      assert_received {:mix_shell, :info, [\"├── elixir\"]}\n      assert_received {:mix_shell, :info, [\"└── logger\"]}\n      assert_received {:mix_shell, :info, [\"    └── elixir\"]}\n    end)\n  end\n\n  @tag apps: [:test, :app_deps_sample, :app_deps2_sample, :app_deps3_sample, :app_deps4_sample]\n  test \"shows the given application tree\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(AppDepsSample)\n\n      assert_raise Mix.Error, \"could not find application app_deps_sample\", fn ->\n        Mix.Tasks.App.Tree.run([\"--format\", \"pretty\", \"app_deps_sample\"])\n      end\n\n      load_apps()\n      Mix.Tasks.App.Tree.run([\"--format\", \"pretty\", \"app_deps_sample\"])\n\n      assert_received {:mix_shell, :info, [\"app_deps_sample\"]}\n      assert_received {:mix_shell, :info, [\"├── app_deps2_sample\"]}\n      assert_received {:mix_shell, :info, [\"│   └── app_deps4_sample (included)\"]}\n      assert_received {:mix_shell, :info, [\"└── app_deps3_sample\"]}\n    end)\n  end\n\n  @tag apps: [:test, :app_deps_sample, :app_deps2_sample, :app_deps3_sample, :app_deps4_sample]\n  test \"shows the application dependency tree excluding applications\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(AppDepsSample)\n\n      load_apps()\n\n      exclude = [\"--exclude\", \"app_deps4_sample\", \"--exclude\", \"app_deps3_sample\"]\n      Mix.Tasks.App.Tree.run([\"--format\", \"pretty\" | exclude])\n\n      assert_received {:mix_shell, :info, [\"test\"]}\n      assert_received {:mix_shell, :info, [\"├── app_deps_sample\"]}\n      assert_received {:mix_shell, :info, [\"│   └── app_deps2_sample\"]}\n      assert_received {:mix_shell, :info, [\"├── elixir\"]}\n      assert_received {:mix_shell, :info, [\"└── logger\"]}\n      assert_received {:mix_shell, :info, [\"    └── elixir\"]}\n    end)\n  end\n\n  @tag apps: [:test, :app_deps_sample, :app_deps2_sample, :app_deps3_sample, :app_deps4_sample]\n  test \"shows the application tree in dot form\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(AppDepsSample)\n\n      load_apps()\n      Mix.Tasks.App.Tree.run([\"--format\", \"dot\"])\n\n      assert File.read!(\"app_tree.dot\") == \"\"\"\n             digraph \"application tree\" {\n               \"test\"\n               \"test\" -> \"app_deps_sample\"\n               \"app_deps_sample\" -> \"app_deps2_sample\"\n               \"app_deps2_sample\" -> \"app_deps4_sample\" [label=\"(included)\"]\n               \"app_deps_sample\" -> \"app_deps3_sample\"\n               \"test\" -> \"elixir\"\n               \"test\" -> \"logger\"\n               \"logger\" -> \"elixir\"\n             }\n             \"\"\"\n    end)\n  end\n\n  defp load_apps(optional_apps \\\\ []) do\n    :ok = :application.load({:application, :app_deps4_sample, [vsn: ~c\"1.0.0\", env: []]})\n    :ok = :application.load({:application, :app_deps3_sample, [vsn: ~c\"1.0.0\", env: []]})\n\n    opts = [vsn: ~c\"1.0.0\", env: [], included_applications: [:app_deps4_sample]]\n    :ok = :application.load({:application, :app_deps2_sample, opts})\n\n    opts = [\n      vsn: ~c\"1.0.0\",\n      env: [],\n      applications: [:app_deps2_sample, :app_deps3_sample],\n      optional_applications: optional_apps\n    ]\n\n    :ok = :application.load({:application, :app_deps_sample, opts})\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/archive_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.ArchiveTest do\n  use MixTest.Case\n\n  defmodule ArchiveProject do\n    def project do\n      [app: :archive, version: \"0.1.0\", elixir: \"~> 0.1.0\"]\n    end\n  end\n\n  defmodule ArchiveProject2 do\n    def project do\n      [app: :archive, version: \"0.2.0\"]\n    end\n  end\n\n  setup do\n    File.rm_rf!(tmp_path(\"userhome\"))\n    System.put_env(\"MIX_ARCHIVES\", tmp_path(\"userhome/.mix/archives/\"))\n    Mix.Project.push(ArchiveProject)\n\n    on_exit(fn ->\n      Mix.Local.remove_archives()\n      System.delete_env(\"MIX_ARCHIVES\")\n    end)\n  end\n\n  test \"archive build\" do\n    in_fixture(\"archive\", fn ->\n      Mix.Tasks.Archive.Build.run([\"--no-elixir-version-check\"])\n      message = \"Generated archive \\\"archive-0.1.0.ez\\\" with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n      assert File.regular?(~c\"archive-0.1.0.ez\")\n      assert to_charlist(Mix.Project.consolidation_path()) not in :code.get_path()\n\n      assert_archive_content_default()\n      refute has_in_zip_file?(~c\"archive-0.1.0.ez\", ~c\"archive-0.1.0/priv/.dot_file\")\n    end)\n  end\n\n  test \"archive build with include-dot-files\" do\n    in_fixture(\"archive\", fn ->\n      Mix.Tasks.Archive.Build.run([\"--no-elixir-version-check\", \"--include-dot-files\"])\n      message = \"Generated archive \\\"archive-0.1.0.ez\\\" with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n      assert File.regular?(~c\"archive-0.1.0.ez\")\n\n      assert_archive_content_default()\n      assert has_in_zip_file?(~c\"archive-0.1.0.ez\", ~c\"archive-0.1.0/priv/.dot_file\")\n    end)\n  end\n\n  def assert_archive_content_default() do\n    assert File.regular?(~c\"archive-0.1.0.ez\")\n    assert has_in_zip_file?(~c\"archive-0.1.0.ez\", ~c\"archive-0.1.0/.elixir\")\n    assert has_in_zip_file?(~c\"archive-0.1.0.ez\", ~c\"archive-0.1.0/priv/not_really_an.so\")\n\n    assert has_in_zip_file?(\n             ~c\"archive-0.1.0.ez\",\n             ~c\"archive-0.1.0/ebin/Elixir.Mix.Tasks.Local.Sample.beam\"\n           )\n\n    assert has_in_zip_file?(~c\"archive-0.1.0.ez\", ~c\"archive-0.1.0/ebin/archive.app\")\n  end\n\n  test \"archive install\" do\n    in_fixture(\"archive\", fn ->\n      # Build and install archive\n      Mix.Tasks.Archive.Build.run([\"--no-elixir-version-check\"])\n\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Install.run([])\n      refute File.regular?(tmp_path(\"userhome/.mix/archives/archive-0.1.0.ez\"))\n      assert File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.1.0/archive-0.1.0/ebin\"))\n\n      # Check that the version warning is printed after installation\n      version_error =\n        \"warning: the archive archive-0.1.0 requires Elixir \\\"~> 0.1.0\\\" \" <>\n          \"but you are running on v#{System.version()}\"\n\n      assert_received {:mix_shell, :error, [^version_error]}\n\n      archive = tmp_path(\"userhome/.mix/archives/archive-0.1.0/archive-0.1.0/ebin\")\n      assert to_charlist(archive) in :code.get_path()\n\n      # Loading the archive should emit warning again\n      Mix.Local.append_archives()\n      assert_received {:mix_shell, :error, [^version_error]}\n\n      # List archive\n      Mix.Tasks.Local.run([])\n      info = \"mix local.sample # A local install sample\"\n      assert_received {:mix_shell, :info, [^info]}\n\n      Mix.Tasks.Archive.run([])\n      assert_received {:mix_shell, :info, [\"* archive-0.1.0\"]}\n\n      # Run archived task\n      Mix.Task.run(\"local.sample\")\n      assert_received {:mix_shell, :info, [\"sample\"]}\n    end)\n  end\n\n  test \"archive install invalid file\" do\n    in_fixture(\"archive\", fn ->\n      file_name = \"invalid-archive-0.1.0.ez\"\n      assert File.regular?(file_name)\n\n      send(self(), {:mix_shell_input, :yes?, true})\n\n      assert_raise Mix.Error, ~r/invalid archive file/, fn ->\n        Mix.Tasks.Archive.Install.run([file_name])\n      end\n    end)\n  end\n\n  test \"archive install missing file\" do\n    message = ~r[Expected \"./unlikely-to-exist-0.1.0.ez\" to be a local file path]\n\n    assert_raise Mix.Error, message, fn ->\n      Mix.Tasks.Archive.Install.run([\"./unlikely-to-exist-0.1.0.ez\"])\n    end\n  end\n\n  test \"archive install --force\" do\n    in_fixture(\"archive\", fn ->\n      Mix.Tasks.Archive.Build.run([\"--no-elixir-version-check\"])\n      Mix.Tasks.Archive.Install.run([\"--force\"])\n\n      message = \"Generated archive \\\"archive-0.1.0.ez\\\" with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      Mix.Tasks.Archive.Uninstall.run([\"archive-0.1.0\", \"--force\"])\n      refute File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.1.0/archive-0.1.0/ebin\"))\n    end)\n  end\n\n  @compile {:no_warn_undefined, GitRepo.Archive}\n  test \"archive.install from Git\" do\n    in_fixture(\"git_repo\", fn ->\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :git_repo, :archive_config, true\n      \"\"\")\n\n      File.write!(\"lib/git_repo.ex\", \"\"\"\n      require Application\n      true = Application.compile_env!(:git_repo, :archive_config)\n\n      defmodule GitRepo.Archive do\n        @compile {:autoload, true}\n\n        def hello do\n          \"World\"\n        end\n      end\n      \"\"\")\n\n      System.cmd(\"git\", ~w[init])\n      System.cmd(\"git\", ~w[add .])\n      System.cmd(\"git\", ~w[commit -m first-commit])\n\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Install.run([\"git\", File.cwd!()])\n      assert GitRepo.Archive.hello() == \"World\"\n\n      message = \"Generated archive \\\"git_repo-0.1.0.ez\\\" with MIX_ENV=prod\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      refute File.regular?(tmp_path(\"userhome/.mix/archives/git_repo-0.1.0.ez\"))\n      assert File.dir?(tmp_path(\"userhome/.mix/archives/git_repo-0.1.0/git_repo-0.1.0/ebin\"))\n    end)\n  after\n    purge([GitRepo.Archive, GitRepo.MixProject, Mix.Local.Installer.MixProject])\n  end\n\n  test \"archive install, update, and uninstall life cycle\" do\n    in_fixture(\"archive\", fn ->\n      # Install previous version\n      Mix.Tasks.Archive.Build.run([\"--no-elixir-version-check\"])\n      assert File.regular?(\"archive-0.1.0.ez\")\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Install.run([])\n      assert_received {:mix_shell, :error, [_]}\n\n      # Build new version\n      Mix.Project.push(ArchiveProject2)\n      Mix.Tasks.Archive.Build.run([\"--no-compile\"])\n      assert File.regular?(\"archive-0.2.0.ez\")\n\n      message = \"Generated archive \\\"archive-0.2.0.ez\\\" with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      # Install new version\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Install.run([])\n      refute File.regular?(tmp_path(\"userhome/.mix/archives/archive-0.2.0.ez\"))\n      assert File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.2.0/archive-0.2.0/ebin\"))\n\n      # Re-install current version should not change system\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Install.run([])\n      refute File.regular?(tmp_path(\"userhome/.mix/archives/archive-0.2.0.ez\"))\n      assert File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.2.0/archive-0.2.0/ebin\"))\n\n      # Try to install a missing version does not remove archive\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Archive.Install.run([\"./archive-0.0.0.ez\"])\n      end\n\n      assert File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.2.0/archive-0.2.0/ebin\"))\n      refute File.regular?(tmp_path(\"userhome/.mix/archives/archive-0.1.0.ez\"))\n\n      # Load archive without warnings because there is no :elixir requirement in mix.exs\n      Mix.Local.append_archives()\n      refute_received {:mix_shell, :error, [_]}\n\n      # Check uninstall confirmation\n      send(self(), {:mix_shell_input, :yes?, false})\n      Mix.Tasks.Archive.Uninstall.run([\"archive-0.2.0\"])\n      assert File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.2.0/archive-0.2.0/ebin\"))\n\n      # Remove it!\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Uninstall.run([\"archive-0.2.0\"])\n      refute File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.2.0/archive-0.2.0/ebin\"))\n\n      # Check old paths are unloaded\n      paths = Enum.map(:code.get_path(), &List.to_string/1)\n      refute tmp_path(\"userhome/.mix/archives/archive-0.1.0/archive-0.1.0/ebin\") in paths\n    end)\n  end\n\n  test \"archive uninstall without version\" do\n    in_fixture(\"archive\", fn ->\n      Mix.Tasks.Archive.Build.run([\"--no-elixir-version-check\"])\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Install.run([])\n\n      send(self(), {:mix_shell_input, :yes?, false})\n      Mix.Tasks.Archive.Uninstall.run([\"archive\"])\n      assert File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.1.0/archive-0.1.0/ebin\"))\n\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Uninstall.run([\"archive\"])\n      refute File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.1.0/archive-0.1.0/ebin\"))\n    end)\n  end\n\n  test \"archive checksum\" do\n    in_fixture(\"archive\", fn ->\n      Mix.Tasks.Archive.Build.run([\"--no-elixir-version-check\"])\n      assert File.regular?(\"archive-0.1.0.ez\")\n      send(self(), {:mix_shell_input, :yes?, true})\n\n      # Install with wrong checksum\n      assert_raise Mix.Error, ~r\"Data does not match the given SHA-512 checksum\", fn ->\n        send(self(), {:mix_shell_input, :yes?, true})\n        Mix.Tasks.Archive.Install.run([\"--sha512\", \"wrong\"])\n      end\n\n      # Install with correct checksum\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Install.run([\"--sha512\", sha512(\"archive-0.1.0.ez\")])\n      refute File.regular?(tmp_path(\"userhome/.mix/archives/archive-0.1.0.ez\"))\n      assert File.dir?(tmp_path(\"userhome/.mix/archives/archive-0.1.0/archive-0.1.0/ebin\"))\n    end)\n  end\n\n  test \"archive check\" do\n    # Install the archive\n    in_fixture(\"archive\", fn ->\n      Mix.Tasks.Archive.Build.run([\"--no-elixir-version-check\"])\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Archive.Install.run([])\n      Application.unload(:archive)\n    end)\n\n    assert_raise Mix.Error, ~r/Expected archive to be in the format/, fn ->\n      archive_check([:archive])\n    end\n\n    assert_raise Mix.Error, ~r/Archive \"archive\" could not be found/, fn ->\n      archive_check([{:archive, \">= 1.0.0\"}])\n    end\n\n    # Load the archive\n    Mix.Local.append_archives()\n\n    message = ~r/Archive \\\"archive-0.1.0\\\" does not match requirement >= 1.0.0/\n\n    assert_raise Mix.Error, message, fn ->\n      archive_check([{:archive, \">= 1.0.0\"}])\n    end\n\n    archive_check([{:archive, \">= 0.0.0\"}])\n  end\n\n  defp archive_check(archives) do\n    Mix.Project.pop()\n    Mix.ProjectStack.post_config(archives: archives)\n    Mix.Project.push(MixTest.Case.Sample)\n    Mix.Tasks.Archive.Check.run([])\n  end\n\n  defp sha512(file) do\n    Base.encode16(:crypto.hash(:sha512, File.read!(file)), case: :lower)\n  end\n\n  defp has_in_zip_file?(archive, name) do\n    {:ok, files} = :zip.list_dir(archive)\n    Enum.find(files, &match?({:zip_file, ^name, _, _, _, _}, &1))\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/clean_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.CleanTest do\n  use MixTest.Case\n\n  defmodule Sample do\n    def project do\n      [\n        app: :sample,\n        version: \"0.1.0\",\n        deps: [\n          {:ok, \"0.1.0\", path: \"deps/ok\"},\n          {:unknown, \"0.1.0\", git: \"deps/unknown\"}\n        ]\n      ]\n    end\n  end\n\n  test \"cleans the application build\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(Sample)\n\n      File.mkdir_p!(\"_build/dev/lib/sample/consolidated\")\n      File.mkdir_p!(\"_build/dev/lib/sample\")\n      File.mkdir_p!(\"_build/test/lib/sample\")\n      File.mkdir_p!(\"_build/dev/lib/ok\")\n\n      Mix.Tasks.Clean.run([])\n      refute File.exists?(\"_build/dev/lib/sample/consolidated\")\n      refute File.exists?(\"_build/dev/lib/sample\")\n      refute File.exists?(\"_build/test/lib/sample\")\n      assert File.exists?(\"_build/dev/lib/ok\")\n    end)\n  end\n\n  test \"cleans dependencies build\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(Sample)\n\n      File.mkdir_p!(\"_build/dev/lib/ok\")\n      File.mkdir_p!(\"_build/test/lib/ok\")\n\n      Mix.Tasks.Clean.run([\"--deps\", \"--only\", \"dev\"])\n      refute File.exists?(\"_build/dev\")\n      assert File.exists?(\"_build/test\")\n\n      Mix.Tasks.Clean.run([\"--deps\"])\n      refute File.exists?(\"_build/test\")\n    end)\n  end\n\n  test \"invokes compiler hook defined in project\" do\n    Mix.ProjectStack.post_config(compilers: Mix.compilers() ++ [:testc])\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/testc.ex\", \"\"\"\n      defmodule Mix.Tasks.Compile.Testc do\n        use Mix.Task.Compiler\n\n        @impl true\n        def run(_args) do\n          Mix.shell().info(\"Compiling...\")\n          :ok\n        end\n\n        @impl true\n        def clean do\n          Mix.shell().info(\"Cleaning...\")\n          :ok\n        end\n      end\n      \"\"\")\n\n      Mix.Task.run(\"compile\")\n      assert_received {:mix_shell, :info, [\"Compiling...\"]}\n      purge([Mix.Tasks.Compile.Testc])\n\n      Mix.Task.run(\"clean\")\n      assert_received {:mix_shell, :info, [\"Cleaning...\"]}\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/cmd_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.CmdTest do\n  use MixTest.Case\n\n  test \"can be called multiple times\" do\n    Mix.Task.run(\"cmd\", [\"echo\", \"hello\"])\n    assert_received {:mix_shell, :run, [\"hello\\n\"]}\n    Mix.Task.run(\"cmd\", [\"echo\", \"hello world\"])\n    assert_received {:mix_shell, :run, [\"hello world\\n\"]}\n  end\n\n  test \"can be invoked as a shell\" do\n    nl = os_newline()\n    Mix.Task.run(\"cmd\", [\"--shell\", \"echo\", \"hello\"])\n    assert_received {:mix_shell, :run, [\"hello\" <> ^nl]}\n  end\n\n  @tag :unix\n  test \"supports relative paths\" do\n    in_tmp(\"cmd-relative\", fn ->\n      File.mkdir_p!(\"priv\")\n      File.write!(\"priv/world.sh\", \"#!/bin/sh\\necho world\")\n      File.chmod!(\"priv/world.sh\", 0o755)\n\n      Mix.Task.run(\"cmd\", [\"priv/world.sh\"])\n      assert_received {:mix_shell, :run, [\"world\\n\"]}\n\n      Mix.Task.run(\"cmd\", [\"--cd\", \"priv\", \"./world.sh\"])\n      assert_received {:mix_shell, :run, [\"world\\n\"]}\n    end)\n  end\n\n  test \"runs the command for each app\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Task.run(\"cmd\", [\"echo\", \"hello\"])\n        assert_received {:mix_shell, :info, [\"==> bar\"]}\n        assert_received {:mix_shell, :run, [\"hello\\n\"]}\n        assert_received {:mix_shell, :info, [\"==> foo\"]}\n        assert_received {:mix_shell, :run, [\"hello\\n\"]}\n      end)\n    end)\n  end\n\n  test \"runs the command for a single app specified by app flag\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n        Mix.Project.in_project(:umbrella, \".\", fn _ ->\n          Mix.Task.run(\"cmd\", [\"--app\", \"bar\", \"echo\", \"hello\"])\n          assert_received {:mix_shell, :info, [\"==> bar\"]}\n          assert_received {:mix_shell, :run, [\"hello\\n\"]}\n          refute_received {:mix_shell, :info, [\"==> foo\"]}\n          refute_received {:mix_shell, :run, [\"hello\\n\"]}\n        end)\n      end)\n    end)\n  end\n\n  test \"runs the command for each app specified by app flag\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n        Mix.Project.in_project(:umbrella, \".\", fn _ ->\n          Mix.Task.run(\"cmd\", [\"--app\", \"bar\", \"--app\", \"foo\", \"echo\", \"hello\"])\n          assert_received {:mix_shell, :info, [\"==> bar\"]}\n          assert_received {:mix_shell, :run, [\"hello\\n\"]}\n          assert_received {:mix_shell, :info, [\"==> foo\"]}\n          assert_received {:mix_shell, :run, [\"hello\\n\"]}\n        end)\n      end)\n    end)\n  end\n\n  test \"only runs the cmd for specified apps and in specific directory\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n        Mix.Project.in_project(:umbrella, \".\", fn _ ->\n          Mix.Task.run(\"cmd\", [\"--app\", \"bar\", \"--cd\", \"lib\", \"pwd\"])\n          assert_received {:mix_shell, :info, [\"==> bar\"]}\n          {pwd, 0} = System.cmd(\"pwd\", [], cd: Path.join([\"apps\", \"bar\", \"lib\"]))\n          assert_received {:mix_shell, :run, [^pwd]}\n          refute_received {:mix_shell, :info, [\"==> foo\"]}\n        end)\n      end)\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/compile.app_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Compile.AppTest do\n  use MixTest.Case\n\n  defmodule CustomDeps do\n    def project do\n      [app: :custom_deps, version: \"0.2.0\", deps: deps()]\n    end\n\n    def application do\n      [extra_applications: [:logger], included_applications: [:ok9]]\n    end\n\n    def deps do\n      [\n        {:ok1, path: \"../ok\"},\n        {:ok2, path: \"../ok\", only: :prod},\n        {:ok3, path: \"../ok\", only: :dev},\n        {:ok4, path: \"../ok\", runtime: true},\n        {:ok5, path: \"../ok\", runtime: false},\n        {:ok6, path: \"../ok\", optional: true},\n        {:ok7, path: \"../ok\", optional: false},\n        {:ok8, path: \"../ok\", app: false},\n        {:ok9, path: \"../ok\"},\n        {:ok10, path: \"../ok\", targets: [:will_never_be_listed]},\n        {:ok11, path: \"../ok\", targets: [Mix.target()]}\n      ]\n    end\n  end\n\n  defmodule CustomProject do\n    def project do\n      [\n        app: :custom_project,\n        version: \"0.3.0\",\n        description: \"Some UTF-8 dëscriptión\"\n      ]\n    end\n\n    def application do\n      Process.get(:application)\n    end\n  end\n\n  defmodule InvalidVsnProject do\n    def project do\n      [app: :invalid_vsn_project, version: \"0.3\"]\n    end\n  end\n\n  test \"generates .app file when changes happen\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      Mix.Tasks.Compile.Elixir.run([])\n      assert Mix.Tasks.Compile.App.run([]) == {:ok, []}\n\n      properties = parse_resource_file(:sample)\n      assert Application.spec(:sample, :vsn) == ~c\"0.1.0\"\n      assert properties[:vsn] == ~c\"0.1.0\"\n      assert properties[:modules] == [A, B]\n      assert properties[:applications] == [:kernel, :stdlib, :elixir]\n      refute Keyword.has_key?(properties, :compile_env)\n\n      Application.unload(:sample)\n      assert Mix.Tasks.Compile.App.run([]) == {:noop, []}\n      assert Application.spec(:sample, :vsn) == ~c\"0.1.0\"\n    end)\n  end\n\n  test \"generates .app file with compile_env\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"config\")\n      File.write!(\"config/config.exs\", \"[]\")\n      Mix.Task.run(\"loadconfig\")\n\n      reset_config = fn ->\n        Mix.ProjectStack.reset_config_mtime()\n        ensure_touched(\"config/config.exs\", \"_build/dev/lib/sample/ebin/sample.app\")\n      end\n\n      Mix.ProjectStack.compile_env([{:app, :key, :error}])\n      assert Mix.Tasks.Compile.App.run([]) == {:ok, []}\n      assert parse_resource_file(:sample)[:compile_env] == [{:app, :key, :error}]\n\n      # No-op with untouched unset compile_env\n      reset_config.()\n      assert Mix.Tasks.Compile.App.run([]) == {:noop, []}\n      assert parse_resource_file(:sample)[:compile_env] == [{:app, :key, :error}]\n\n      # Recompiles with new compile_env\n      reset_config.()\n      Mix.ProjectStack.compile_env([{:app, :another, :error}])\n      assert Mix.Tasks.Compile.App.run([]) == {:ok, []}\n      assert parse_resource_file(:sample)[:compile_env] == [{:app, :another, :error}]\n\n      # Keeps compile_env if forcing\n      reset_config.()\n      assert Mix.Tasks.Compile.App.run([\"--force\"]) == {:ok, []}\n      assert parse_resource_file(:sample)[:compile_env] == [{:app, :another, :error}]\n    end)\n  end\n\n  test \"uses custom application settings\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(CustomProject)\n      env = [foo: [:one, \"two\", 3, 4, \"฿\", &List.flatten/1], bar: [{} | %{foo: :bar}]]\n\n      Process.put(:application,\n        maxT: :infinity,\n        applications: [:example_app, mix: :optional],\n        extra_applications: [:logger, ex_unit: :optional],\n        env: env\n      )\n\n      Mix.Tasks.Compile.Elixir.run([])\n      Mix.Tasks.Compile.App.run([])\n\n      properties = parse_resource_file(:custom_project)\n      assert Application.spec(:custom_project, :vsn) == ~c\"0.3.0\"\n      assert properties[:vsn] == ~c\"0.3.0\"\n      assert properties[:maxT] == :infinity\n      assert properties[:optional_applications] == [:ex_unit, :mix]\n      assert properties[:description] == ~c\"Some UTF-8 dëscriptión\"\n\n      assert properties[:applications] ==\n               [:kernel, :stdlib, :elixir, :logger, :ex_unit, :example_app, :mix]\n\n      assert properties[:env] == [\n               foo: [:one, \"two\", 3, 4, \"฿\", &List.flatten/1],\n               bar: [{} | %{foo: :bar}]\n             ]\n\n      refute Keyword.has_key?(properties, :extra_applications)\n    end)\n  end\n\n  test \"infers applications\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(CustomDeps)\n\n      Mix.Tasks.Compile.Elixir.run([])\n      Mix.Tasks.Compile.App.run([])\n\n      properties = parse_resource_file(:custom_deps)\n\n      assert properties[:applications] ==\n               [:kernel, :stdlib, :elixir, :logger, :ok1, :ok3, :ok4, :ok6, :ok7, :ok11]\n\n      assert properties[:optional_applications] == [:ok6]\n    end)\n  end\n\n  test \"validates properties\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(CustomProject)\n\n      Process.put(:application, [:not_a_keyword, applications: []])\n      message = \"Application configuration returned from application/0 should be a keyword list\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, modules: :invalid)\n      message = \"Application modules (:modules) should be a list of atoms, got: :invalid\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, maxT: :invalid)\n      message = \"Application maximum time (:maxT) is not an integer or :infinity, got: :invalid\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, registered: [\"invalid\"])\n\n      message =\n        \"Application registered processes (:registered) should be a list of atoms, got: [\\\"invalid\\\"]\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, extra_applications: [\"invalid\"])\n\n      message =\n        \"Application extra applications (:extra_applications) should be a list of atoms or {app, :required | :optional} pairs, got: [\\\"invalid\\\"]\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, included_applications: [\"invalid\"])\n\n      message =\n        \"Application included applications (:included_applications) should be a list of atoms, got: [\\\"invalid\\\"]\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, applications: [\"invalid\"])\n\n      message =\n        \"Application applications (:applications) should be a list of atoms or {app, :required | :optional} pairs, got: [\\\"invalid\\\"]\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, applications: nil)\n\n      message =\n        \"Application applications (:applications) should be a list of atoms or {app, :required | :optional} pairs, got: nil\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, env: [:invalid])\n      message = \"Application environment (:env) should be a keyword list, got: [:invalid]\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, mod: {Mod})\n\n      message =\n        \"Application callback module (:mod) should be either [] or {module, start_args}, got: {Mod}\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, start_phases: [:invalid])\n\n      message =\n        \"Application start phases (:start_phases) should be a keyword list, got: [:invalid]\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, env: [foo: make_ref()])\n\n      message =\n        ~r\"\\\"def application\\\" has a term which cannot be written to \\.app files: #Reference\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n    end)\n  end\n\n  @tag :re_import\n  test \"accepts only regexes without a reference\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(CustomProject)\n      Process.put(:application, env: [regex: ~r/foo/])\n\n      assert_raise Mix.Error, ~r/you must use the \\/E modifier to store regexes/, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n\n      Process.put(:application, env: [exported: ~r/foo/E])\n      Mix.Tasks.Compile.Elixir.run([])\n      Mix.Tasks.Compile.App.run([])\n\n      properties = parse_resource_file(:custom_project)\n      assert properties[:env] == [exported: ~r/foo/E]\n    end)\n  end\n\n  test \".app contains description and registered (as required by systools)\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      Mix.Tasks.Compile.Elixir.run([])\n      assert Mix.Tasks.Compile.App.run([]) == {:ok, []}\n\n      properties = parse_resource_file(:sample)\n      assert properties[:registered] == []\n      assert properties[:description] == ~c\"sample\"\n      assert properties[:applications] == [:kernel, :stdlib, :elixir]\n\n      assert Mix.Tasks.Compile.App.run([]) == {:noop, []}\n    end)\n  end\n\n  test \"raises on invalid version\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(InvalidVsnProject)\n\n      message = ~r\"Expected :version to be a valid Version, got: \\\"0.3\\\"\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Compile.App.run([])\n      end\n    end)\n  end\n\n  defp parse_resource_file(app) do\n    {:ok, [term]} = :file.consult(\"_build/dev/lib/#{app}/ebin/#{app}.app\")\n    {:application, ^app, properties} = term\n    properties\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/compile.elixir_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Compile.ElixirTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n  alias Mix.Task.Compiler.Diagnostic\n\n  @old_time {{2010, 1, 1}, {0, 0, 0}}\n  @elixir_otp_version {System.version(), :erlang.system_info(:otp_release)}\n\n  def trace(event, env) do\n    send(__MODULE__, {event, env})\n    :ok\n  end\n\n  defp mtime(path) do\n    File.stat!(path).mtime\n  end\n\n  defp mark_as_old!(path) do\n    mtime = mtime(path)\n    File.touch!(path, @old_time)\n    mtime\n  end\n\n  defp purge_protocol(module) do\n    :code.del_path(:filename.absname(~c\"_build/dev/lib/sample/consolidated\"))\n    :code.purge(module)\n    :code.delete(module)\n  end\n\n  test \"compiles a project without per environment build\" do\n    Mix.ProjectStack.post_config(build_per_environment: false)\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A, do: :ok\n\n      # Also make sure that we access the ebin directory during compilation\n      true = to_charlist(Mix.Project.compile_path()) in :code.get_path()\n      \"\"\")\n\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n\n      assert File.regular?(\"_build/shared/lib/sample/ebin/Elixir.A.beam\")\n      assert File.regular?(\"_build/shared/lib/sample/ebin/Elixir.B.beam\")\n\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  end\n\n  test \"compiles a project with per environment build\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A, do: :ok\n\n      # Also make sure that we access the ebin directory during compilation\n      true = to_charlist(Mix.Project.compile_path()) in :code.get_path()\n      \"\"\")\n\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.B.beam\")\n\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  end\n\n  test \"compiles a project with custom tracer\" do\n    Process.register(self(), __MODULE__)\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Tasks.Compile.Elixir.run([\"--tracer\", \"Mix.Tasks.Compile.ElixirTest\"])\n      assert_received {{:on_module, _, :none}, %{module: A}}\n      assert_received {{:on_module, _, :none}, %{module: B}}\n    end)\n  after\n    Code.put_compiler_option(:tracers, [])\n  end\n\n  test \"compiles a project with a previously set custom tracer\" do\n    Process.register(self(), __MODULE__)\n    Code.put_compiler_option(:tracers, [__MODULE__])\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Tasks.Compile.Elixir.run([])\n      assert_received {{:on_module, _, :none}, %{module: A}}\n      assert_received {{:on_module, _, :none}, %{module: B}}\n    end)\n  after\n    Code.put_compiler_option(:tracers, [])\n  end\n\n  test \"recompiles project if elixirc_options changed\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n\n      Mix.Task.clear()\n      Mix.ProjectStack.merge_config(xref: [exclude: [Foo]])\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  end\n\n  test \"does not recompiles project if cwd changes and --no-check-cwd is given\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      Mix.Project.pop()\n\n      old_cwd = File.cwd!()\n\n      in_tmp(\"new_cwd\", fn ->\n        Mix.Project.push(MixTest.Case.Sample)\n        File.cp_r!(old_cwd, File.cwd!())\n\n        purge([A, B])\n        Mix.Task.clear()\n        assert {:noop, _} = Mix.Tasks.Compile.Elixir.run([\"--verbose\", \"--no-check-cwd\"])\n      end)\n    end)\n  end\n\n  test \"recompiles files using Mix.Project if mix.exs changes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample, __ENV__.file)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        Mix.Project.config()\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      ensure_touched(__ENV__.file, \"_build/dev/lib/sample/.mix/compile.elixir\")\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Now remove the dependency\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n      end\n      \"\"\")\n\n      ensure_touched(__ENV__.file, \"_build/dev/lib/sample/.mix/compile.elixir\")\n      File.touch!(\"_build/dev/lib/sample/.mix/compile.elixir\", @old_time)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert mtime(\"_build/dev/lib/sample/.mix/compile.elixir\") > @old_time\n\n      ensure_touched(__ENV__.file, \"_build/dev/lib/sample/.mix/compile.elixir\")\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  end\n\n  test \"recompiles files when config changes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      Process.put({MixTest.Case.Sample, :application}, extra_applications: [:logger])\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        _ = Logger.metadata()\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      recompile = fn ->\n        Mix.ProjectStack.pop()\n        Mix.Project.push(MixTest.Case.Sample)\n        ensure_touched(\"config/config.exs\", \"_build/dev/lib/sample/.mix/compile.elixir\")\n        Mix.Tasks.Loadconfig.load_compile(\"config/config.exs\")\n        Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      end\n\n      # Adding config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :logger, :level, :debug\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Changing config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :logger, :level, :info\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Removing config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # No-op does not recompile\n      assert recompile.() == {:ok, []}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Changing self fully recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :sample, :foo, :bar\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Changing an unknown dependency returns :ok but does not recompile\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :sample, :foo, :bar\n      config :unknown, :unknown, :unknown\n      \"\"\")\n    end)\n  after\n    Application.delete_env(:sample, :foo, persistent: true)\n  end\n\n  defdelegate dbg(code, options, env), to: Macro\n\n  test \"recompiles only config files when elixir config changes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def a, do: dbg(:ok)\n      end\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        def b, do: :ok\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Change the dbg_callback at runtime\n      File.touch!(\"_build/dev/lib/sample/.mix/compile.elixir\", @old_time)\n      Application.put_env(:elixir, :dbg_callback, {__MODULE__, :dbg, []})\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert mtime(\"_build/dev/lib/sample/.mix/compile.elixir\") > @old_time\n    end)\n  after\n    Application.put_env(:elixir, :dbg_callback, {Macro, :dbg, []})\n  end\n\n  test \"recompiles files on debug_info flag\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule DebugInfo.A do\n        def run, do: :ok\n      end\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule DebugInfo.B do\n        def run, do: DebugInfo.A.run()\n      end\n      \"\"\")\n\n      File.write!(\"lib/c.ex\", \"\"\"\n      defmodule DebugInfo.C do\n        @compile_time_value DebugInfo.A.run()\n        def compile_time_value, do: @compile_time_value\n        def run, do: DebugInfo.B.run()\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/c.ex\"]}\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\", \"--no-debug-info\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/c.ex\"]}\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\", \"--no-debug-info\"]) == {:noop, []}\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule DebugInfo.A do\n        def run, do: :error\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\", \"--no-debug-info\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/c.ex\"]}\n    end)\n  end\n\n  test \"recompiles files when config changes export dependencies\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      Process.put({MixTest.Case.Sample, :application}, extra_applications: [:ex_unit])\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def test_struct do\n          %ExUnit.Test{}\n        end\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      recompile = fn ->\n        Mix.ProjectStack.pop()\n        Mix.Project.push(MixTest.Case.Sample)\n        ensure_touched(\"config/config.exs\", \"_build/dev/lib/sample/.mix/compile.elixir\")\n        Mix.Tasks.Loadconfig.load_compile(\"config/config.exs\")\n        Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      end\n\n      # Adding config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :ex_unit, :some, :config\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Changing config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :ex_unit, :some, :another\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Removing config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # No-op does not recompile\n      assert recompile.() == {:ok, []}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  after\n    Application.delete_env(:ex_unit, :some, persistent: true)\n  end\n\n  test \"recompiles files when config changes with crashes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      Process.put({MixTest.Case.Sample, :application}, extra_applications: [:logger])\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        require Logger\n        def fun, do: Logger.debug(\"hello\")\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      recompile = fn ->\n        Mix.ProjectStack.pop()\n        Mix.Project.push(MixTest.Case.Sample)\n        ensure_touched(\"config/config.exs\", \"_build/dev/lib/sample/.mix/compile.elixir\")\n        Mix.Tasks.Loadconfig.load_compile(\"config/config.exs\")\n        Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      end\n\n      # Adding config recompiles due to macros\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :logger, :compile_time_purge_matching, []\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Inserting a bogus config should crash\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :logger, :compile_time_purge_matching, [level_lower_than: :debug]\n      \"\"\")\n\n      ExUnit.CaptureIO.capture_io(:stderr, fn -> assert {:error, _} = recompile.() end)\n\n      # Revering the original config should recompile\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :logger, :compile_time_purge_matching, []\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  after\n    Application.put_env(:logger, :compile_time_purge_matching, [])\n  end\n\n  test \"recompiles files when config changes via compile_env\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        _ = Application.compile_env(:logger, :level)\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      recompile = fn ->\n        Mix.ProjectStack.pop()\n        Mix.Project.push(MixTest.Case.Sample)\n        ensure_touched(\"config/config.exs\", \"_build/dev/lib/sample/.mix/compile.elixir\")\n        Mix.Tasks.Loadconfig.load_compile(\"config/config.exs\")\n        Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      end\n\n      # Adding config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :logger, :level, :debug\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Changing config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :logger, :level, :info\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Removing config recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Changing self fully recompiles\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :sample, :foo, :bar\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Changing an unknown dependency returns :ok but does not recompile\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :sample, :foo, :bar\n      config :unknown, :unknown, :unknown\n      \"\"\")\n\n      # We use ensure_touched because an outdated manifest would recompile anyway.\n      assert recompile.() == {:ok, []}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  after\n    Application.delete_env(:sample, :foo, persistent: true)\n  end\n\n  test \"recompiles files when lock changes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.ProjectStack.post_config(\n        deps: [{:git_repo, git: MixTest.Case.fixture_path(\"git_repo\")}]\n      )\n\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        _ = GitRepo.__info__(:module)\n      end\n      \"\"\")\n\n      Mix.Task.run(\"deps.get\")\n      Mix.Task.run(\"loadpaths\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      recompile = fn ->\n        Mix.ProjectStack.pop()\n        Mix.Project.push(MixTest.Case.Sample)\n        File.touch!(\"_build/dev/lib/sample/.mix/compile.elixir\", @old_time)\n        ensure_touched(\"mix.lock\")\n        ensure_touched(\"_build/dev/lib/sample/.mix/compile.lock\")\n        Mix.Tasks.WillRecompile.run([])\n        Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      end\n\n      # Adding to lock recompiles\n      File.write!(\"mix.lock\", \"\"\"\n      %{\"git_repo\": :unused}\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert mtime(\"_build/dev/lib/sample/.mix/compile.elixir\") > @old_time\n\n      # Changing lock recompiles\n      File.write!(\"mix.lock\", \"\"\"\n      %{\"git_repo\": :another}\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert mtime(\"_build/dev/lib/sample/.mix/compile.elixir\") > @old_time\n\n      # Adding to the lock does not recompile\n      File.write!(\"mix.lock\", \"\"\"\n      %{\"git_repo\": :another, \"unknown\": :unknown}\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Removing recompiles\n      File.write!(\"mix.lock\", \"\"\"\n      %{\"unknown\": :unknown}\n      \"\"\")\n\n      assert recompile.() == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert mtime(\"_build/dev/lib/sample/.mix/compile.elixir\") > @old_time\n    end)\n  end\n\n  test \"recompiles files using Erlang modules if Erlang manifest changes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"src\")\n\n      File.write!(\"src/foo.erl\", \"\"\"\n      -module(foo).\n      -export([bar/0]).\n      bar() -> ok.\n      \"\"\")\n\n      File.write!(\"src/bar.erl\", \"\"\"\n      -module(bar).\n      -export([baz/0]).\n      baz() -> ok.\n      \"\"\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        :foo.bar()\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      Mix.Task.clear()\n      File.touch!(\"_build/dev/lib/sample/.mix/compile.elixir\", @old_time)\n\n      assert Mix.Tasks.Compile.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Now remove the Erlang file, lib/a.ex must recompile\n      File.rm!(\"src/foo.erl\")\n      File.touch!(\"_build/dev/lib/sample/.mix/compile.erlang\", @old_time)\n\n      Mix.Task.clear()\n      assert Mix.Tasks.Compile.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  end\n\n  test \"recompiles project if Elixir version changes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Tasks.Compile.run([])\n      purge([A, B])\n\n      assert File.exists?(\"_build/dev/lib/sample\")\n      assert File.exists?(\"_build/dev/lib/sample/consolidated\")\n      assert Mix.Dep.ElixirSCM.read() == {:ok, @elixir_otp_version, Mix.SCM.Path, nil}\n\n      Mix.Task.clear()\n      File.write!(\"_build/dev/lib/sample/consolidated/.to_be_removed\", \"\")\n      manifest_data = :erlang.term_to_binary({:v1, \"0.0.0\", nil})\n      File.write!(\"_build/dev/lib/sample/.mix/compile.elixir_scm\", manifest_data)\n      File.touch!(\"_build/dev/lib/sample/.mix/compile.elixir_scm\", @old_time)\n\n      Mix.Tasks.Compile.run([])\n      assert Mix.Dep.ElixirSCM.read() == {:ok, @elixir_otp_version, Mix.SCM.Path, nil}\n\n      assert mtime(\"_build/dev/lib/sample/.mix/compile.elixir_scm\") > @old_time\n      refute File.exists?(\"_build/dev/lib/sample/consolidated/.to_be_removed\")\n    end)\n  end\n\n  test \"recompiles project if scm changes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Tasks.Compile.run([\"--verbose\"])\n      purge([A, B])\n\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert Mix.Dep.ElixirSCM.read() == {:ok, @elixir_otp_version, Mix.SCM.Path, nil}\n\n      Mix.Task.clear()\n      manifest_data = :erlang.term_to_binary({1, @elixir_otp_version, :another})\n      File.write!(\"_build/dev/lib/sample/.mix/compile.elixir_scm\", manifest_data)\n      File.touch!(\"_build/dev/lib/sample/.mix/compile.elixir_scm\", @old_time)\n\n      Mix.Tasks.Compile.run([])\n      assert Mix.Dep.ElixirSCM.read() == {:ok, @elixir_otp_version, Mix.SCM.Path, nil}\n\n      assert mtime(\"_build/dev/lib/sample/.mix/compile.elixir_scm\") > @old_time\n    end)\n  end\n\n  test \"recompiles project if old manifest\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Tasks.Compile.run([])\n      purge([A, B])\n\n      manifest = \"_build/dev/lib/sample/.mix/compile.elixir\"\n\n      File.read!(manifest)\n      |> :erlang.binary_to_term()\n      |> put_elem(0, 9)\n      |> :erlang.term_to_binary()\n      |> then(&File.write!(manifest, &1))\n\n      Mix.Task.clear()\n      assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  end\n\n  test \"recompiles files from path dependencies when its deps change\" do\n    # Get Git repo first revision\n    [last, first | _] = get_git_repo_revs(\"git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      File.mkdir_p!(\"path_on_git_repo/lib\")\n\n      File.write!(\"path_on_git_repo/mix.exs\", \"\"\"\n      defmodule PathOnGitRepo.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :path_on_git_repo,\n            version: \"0.1.0\",\n            deps: [{:git_repo, git: MixTest.Case.fixture_path(\"git_repo\")}]\n          ]\n        end\n      end\n      \"\"\")\n\n      File.write!(\"path_on_git_repo/lib/path_on_hello.ex\", \"\"\"\n      defmodule PathOnGitRepo.Hello do\n        IO.puts(\"GitRepo is defined: \\#{Code.ensure_loaded?(GitRepo)}\")\n      end\n      \"\"\")\n\n      File.write!(\"mix.lock\", inspect(%{git_repo: {:git, fixture_path(\"git_repo\"), first, []}}))\n      Mix.ProjectStack.post_config(deps: [{:path_on_git_repo, path: \"path_on_git_repo\"}])\n      Mix.Project.push(MixTest.Case.Sample)\n\n      Mix.Tasks.Deps.Get.run([])\n      assert capture_io(fn -> Mix.Task.run(\"compile\") end) =~ \"GitRepo is defined: false\"\n\n      Mix.Task.clear()\n      Mix.State.clear_cache()\n      purge([GitRepo.MixProject, PathOnGitRepo.MixProject, PathOnGitRepo.Hello])\n\n      Mix.Tasks.Deps.Update.run([\"--all\"])\n      assert File.read!(\"mix.lock\") =~ last\n\n      # The lock of sample (the parent app) is the one that changed\n      # but that should mirror on child path dependencies too.\n      ensure_touched(\n        \"_build/dev/lib/sample/.mix/compile.lock\",\n        \"_build/dev/lib/path_on_git_repo/.mix/compile.elixir\"\n      )\n\n      assert capture_io(fn -> Mix.Task.run(\"compile\") end) =~ \"GitRepo is defined: true\"\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"does not recompile files from path dependencies when non-child dependency change\" do\n    # Get Git repo first revision\n    [last, first | _] = get_git_repo_revs(\"git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      File.mkdir_p!(\"path_dep/lib\")\n\n      File.write!(\"path_dep/mix.exs\", \"\"\"\n      defmodule PathDep.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :path_dep,\n            version: \"0.1.0\",\n            deps: []\n          ]\n        end\n      end\n      \"\"\")\n\n      File.write!(\"path_dep/lib/path_dep_hello.ex\", \"\"\"\n      defmodule PathDep.Hello do\n      end\n      \"\"\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        PathDep.Hello.__info__(:module)\n      end\n      \"\"\")\n\n      File.write!(\"mix.lock\", inspect(%{git_repo: {:git, fixture_path(\"git_repo\"), first, []}}))\n\n      Mix.ProjectStack.post_config(\n        deps: [\n          {:git_repo, \"0.1.0\", git: fixture_path(\"git_repo\")},\n          {:path_dep, path: \"path_dep\"}\n        ]\n      )\n\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Task.run(\"deps.get\")\n      Mix.Task.run(\"compile\", [\"--verbose\"])\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n\n      Mix.Task.clear()\n      Mix.State.clear_cache()\n      purge([GitRepo.MixProject, PathDep.MixProject])\n\n      ensure_touched(\"mix.lock\", \"_build/dev/lib/sample/.mix/compile.lock\")\n      Mix.Task.run(\"deps.update\", [\"--all\"])\n      assert File.read!(\"mix.lock\") =~ last\n\n      Mix.Task.run(\"compile\", [\"--verbose\"])\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject, PathDep.MixProject])\n  end\n\n  test \"does not write BEAM files down on failures\" do\n    in_tmp(\"blank\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"lib\")\n      File.write!(\"lib/a.ex\", \"raise ~s(oops)\")\n\n      capture_io(:stderr, fn ->\n        assert {:error, [_]} = Mix.Tasks.Compile.Elixir.run([])\n      end)\n\n      refute File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n    end)\n  end\n\n  test \"removes, purges and deletes old artifacts\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      assert Code.ensure_loaded?(A)\n\n      File.rm!(\"lib/a.ex\")\n      assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n      refute File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      refute Code.ensure_loaded?(A)\n      refute String.contains?(File.read!(\"_build/dev/lib/sample/.mix/compile.elixir\"), \"Elixir.A\")\n    end)\n  end\n\n  test \"recompiles mtime changed files if content changed but not length\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      Mix.shell().flush()\n      purge([A, B])\n\n      same_length_content = \"lib/a.ex\" |> File.read!() |> String.replace(\"A\", \"Z\")\n      File.write!(\"lib/a.ex\", same_length_content)\n      future = {{2038, 1, 1}, {0, 0, 0}}\n      File.touch!(\"lib/a.ex\", future)\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n\n      message =\n        \"warning: mtime (modified time) for \\\"lib/a.ex\\\" was set to the future, resetting to now\"\n\n      assert_received {:mix_shell, :error, [^message]}\n\n      message =\n        \"warning: mtime (modified time) for \\\"lib/b.ex\\\" was set to the future, resetting to now\"\n\n      refute_received {:mix_shell, :error, [^message]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      File.touch!(\"_build/dev/lib/sample/.mix/compile.elixir\", future)\n      assert Mix.Tasks.Compile.Elixir.run([]) == {:noop, []}\n    end)\n  end\n\n  test \"does not recompile mtime changed but identical files\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      Mix.shell().flush()\n      purge([A, B])\n\n      future = {{2038, 1, 1}, {0, 0, 0}}\n      File.touch!(\"lib/a.ex\", future)\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n\n      message =\n        \"warning: mtime (modified time) for \\\"lib/a.ex\\\" was set to the future, resetting to now\"\n\n      assert_received {:mix_shell, :error, [^message]}\n\n      message =\n        \"warning: mtime (modified time) for \\\"lib/b.ex\\\" was set to the future, resetting to now\"\n\n      refute_received {:mix_shell, :error, [^message]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      File.touch!(\"_build/dev/lib/sample/.mix/compile.elixir\", future)\n      assert Mix.Tasks.Compile.Elixir.run([]) == {:noop, []}\n    end)\n  end\n\n  test \"does recompile a file restored after a compile error (and .beam file were deleted)\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      Mix.shell().flush()\n      purge([A, B])\n\n      # Compile with error\n      original_content = File.read!(\"lib/b.ex\")\n      File.write!(\"lib/b.ex\", \"this will not compile\")\n\n      assert capture_io(:stderr, fn ->\n               {:error, _} = Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n             end) =~ \"Compilation error in file lib/b.ex\"\n\n      assert_received {:mix_shell, :info, [\"Compiling 1 file (.ex)\"]}\n\n      # Revert change\n      File.write!(\"lib/b.ex\", original_content)\n      future = {{2038, 1, 1}, {0, 0, 0}}\n      File.touch!(\"lib/b.ex\", future)\n\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n\n      message =\n        \"warning: mtime (modified time) for \\\"lib/b.ex\\\" was set to the future, resetting to now\"\n\n      assert_received {:mix_shell, :error, [^message]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  end\n\n  test \"recompiles size changed files\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      past = @old_time\n      File.touch!(\"lib/a.ex\", past)\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      Mix.shell().flush()\n      purge([A, B])\n\n      File.write!(\"lib/a.ex\", File.read!(\"lib/a.ex\") <> \"\\n\")\n      File.touch!(\"lib/a.ex\", past)\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  end\n\n  test \"recompiles dependent changed modules\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.write!(\"lib/a.ex\", \"defmodule A, do: B.module_info()\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      Mix.shell().flush()\n      purge([A, B])\n\n      force_recompilation(\"lib/b.ex\")\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  end\n\n  test \"recompiles dependent changed modules without beam files\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        def a, do: A.__info__(:module)\n      end\n      \"\"\")\n\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.B.beam\")\n\n      # Compile directly so it does not point to a .beam file\n      Code.put_compiler_option(:ignore_module_conflict, true)\n      Code.compile_file(\"lib/b.ex\")\n\n      force_recompilation(\"lib/a.ex\")\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  after\n    Code.put_compiler_option(:ignore_module_conflict, false)\n  end\n\n  test \"recompiles dependent changed modules even on removal\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.write!(\"lib/a.ex\", \"defmodule A, do: B.module_info()\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      Mix.shell().flush()\n      purge([A, B])\n\n      File.rm(\"lib/b.ex\")\n      File.write!(\"lib/a.ex\", \"defmodule A, do: nil\")\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  end\n\n  test \"recompiles dependent changed on conflict\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n\n      assert capture_io(:stderr, fn ->\n               File.write!(\"lib/a.ex\", \"defmodule B, do: :not_ok\")\n               assert {:ok, [_]} = Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n               assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n               assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n               purge([A, B])\n             end) =~ \"redefining module B\"\n\n      capture_io(:stderr, fn ->\n        File.write!(\"lib/a.ex\", \"defmodule A, do: :ok\")\n        assert {:ok, []} = Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n        assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n        assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n        purge([A, B])\n      end)\n    end)\n  end\n\n  test \"recompiles dependent changed external resources\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      tmp = tmp_path(\"c.eex\")\n      File.touch!(\"lib/a.eex\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        # Listing directories as external resources\n        # is not valid but let's ensure we don't crash\n        @external_resource \"lib\"\n        @external_resource \"lib/a.eex\"\n        @external_resource #{inspect(tmp)}\n        def a, do: :ok\n\n        if System.get_env(\"RAISE_EXTERNAL_RESOURCE\") do\n          raise \"oops\"\n        end\n      end\n      \"\"\")\n\n      # Compiles with missing external resources\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:noop, []}\n      Mix.shell().flush()\n      purge([A, B])\n\n      # Update local existing resource timestamp is not enough\n      File.touch!(\"lib/a.eex\", {{2038, 1, 1}, {0, 0, 0}})\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:noop, []}\n\n      # Force recompilation but fail compilation\n      force_recompilation(\"lib/a.eex\")\n      System.put_env(\"RAISE_EXTERNAL_RESOURCE\", \"1\")\n\n      assert capture_io(:stderr, fn ->\n               assert {:error, [_]} = Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n             end) =~ \"oops\"\n\n      # Delete failure reason, it will now compile for good\n      System.delete_env(\"RAISE_EXTERNAL_RESOURCE\")\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Does not update on old existing resource\n      File.touch!(\"lib/a.eex\", @old_time)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:noop, []}\n      Mix.shell().flush()\n      purge([A, B])\n\n      # Create external resource\n      File.touch!(tmp, {{2038, 1, 1}, {0, 0, 0}})\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Recompiles once resource is deleted\n      File.rm_rf!(tmp)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Recompiles if directories are stale\n      File.touch!(\"lib\", {{2038, 1, 1}, {0, 0, 0}})\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n    end)\n  after\n    File.rm(tmp_path(\"c.eex\"))\n  end\n\n  test \"tracks warnings from external resources\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.touch!(\"lib/a.eex\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        @external_resource \"lib/a.eex\"\n        IO.warn(\"oops\", file: Path.absname(\"lib/a.eex\"), line: 13)\n      end\n      \"\"\")\n\n      # Compiles with missing external resources\n      file = Path.absname(\"lib/a.eex\")\n      source = Path.absname(\"lib/a.ex\")\n\n      assert capture_io(:stderr, fn ->\n               assert {:ok,\n                       [%Mix.Task.Compiler.Diagnostic{source: ^source, file: ^file, position: 13}]} =\n                        Mix.Tasks.Compile.Elixir.run([])\n\n               assert {:noop,\n                       [%Mix.Task.Compiler.Diagnostic{source: ^source, file: ^file, position: 13}]} =\n                        Mix.Tasks.Compile.Elixir.run([\"--all-warnings\"])\n             end) =~ \"oops\"\n\n      purge([A])\n    end)\n  end\n\n  test \"recompiles modules with exports tracking\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        defstruct [:foo]\n      end\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        def fun do\n          %A{foo: 1}\n        end\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        # Some comments\n        defstruct [:foo]\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        defstruct [:foo, :bar]\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        defstruct [:foo, bar: 1]\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        defstruct [:foo, bar: 1]\n        def some_fun, do: :ok\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n\n      # Remove all code, we should now get a compilation error\n      File.write!(\"lib/a.ex\", \"\"\"\n      \"\"\")\n\n      assert capture_io(:stderr, fn ->\n               {:error, _} = Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n             end) =~ \"A.__struct__/1 is undefined, cannot expand struct A\"\n\n      # At the code back and it should work again\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        defstruct [:foo, bar: 1]\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n\n      # Removing the file should have the same effect as removing all code\n      File.rm!(\"lib/a.ex\")\n\n      assert capture_io(:stderr, fn ->\n               {:error, _} = Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n             end) =~ \"A.__struct__/1 is undefined, cannot expand struct A\"\n    end)\n  end\n\n  test \"recompiles modules with pmap tracking\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      Kernel.ParallelCompiler.pmap([:ok], fn :ok ->\n        defmodule A do\n          def fun, do: :ok\n        end\n      end)\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        A.fun()\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n\n      force_recompilation(\"lib/a.ex\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      purge([A, B])\n    end)\n  end\n\n  test \"recompiles modules with multiple sources\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def one, do: 1\n      end\n\n      defmodule B do\n        def two, do: 2\n      end\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      B.two()\n\n      defmodule A do\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\", \"--ignore-module-conflict\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      refute Code.ensure_loaded?(A) and function_exported?(A, :one, 0)\n\n      Mix.shell().flush()\n      purge([A])\n\n      File.rm(\"lib/b.ex\")\n      Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert Code.ensure_loaded?(A) and function_exported?(A, :one, 0)\n    end)\n  end\n\n  test \"recompiles with --force\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      purge([A, B])\n\n      # Now we have a noop\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:noop, []}\n\n      # --force\n      assert Mix.Tasks.Compile.Elixir.run([\"--force\", \"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  end\n\n  test \"recompiles with --force-elixir\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      assert Mix.Task.run(\"compile\") == {:ok, []}\n      purge([A, B])\n\n      # Now we have a noop\n      Mix.Task.clear()\n      assert Mix.Task.run(\"compile\") == {:noop, []}\n\n      # --force-elixir\n      Mix.Task.clear()\n      assert Mix.Task.run(\"compile\", [\"--verbose\", \"--force-elixir\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  end\n\n  test \"compiles files with autoload disabled\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        @compile {:autoload, false}\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      purge([A, B])\n    end)\n  end\n\n  test \"does not recompile files that are empty or have no code\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.write!(\"lib/a.ex\", \"\")\n      File.write!(\"lib/b.ex\", \"# Just a comment\")\n      File.write!(\"lib/c.ex\", \"\\n\\n\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/c.ex\"]}\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:noop, []}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/c.ex\"]}\n    end)\n  end\n\n  test \"recompiles modules with __mix_recompile__ check\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def __mix_recompile__?(), do: true\n      end\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        def __mix_recompile__?(), do: false\n      end\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiling 2 files (.ex)\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n\n      # Mix recompile should work even if the compile path\n      # was removed and the module purged\n      Code.delete_path(Mix.Project.compile_path())\n      purge([A])\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiling 1 file (.ex)\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      Mix.shell().flush()\n\n      File.rm!(\"lib/a.ex\")\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      refute_received _\n    end)\n  end\n\n  test \"recompiles modules with __mix_recompile__ check with crashes\" do\n    Agent.start_link(fn -> false end, name: :mix_recompile_raise)\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def __mix_recompile__?(), do: Agent.get(:mix_recompile_raise, & &1)\n\n        if Agent.get(:mix_recompile_raise, & &1) do\n          raise \"oops\"\n        end\n      end\n      \"\"\")\n\n      File.touch!(\"lib/a.ex\", @old_time)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:noop, []}\n      assert mtime(\"lib/a.ex\") == @old_time\n\n      Agent.update(:mix_recompile_raise, fn _ -> true end)\n\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        assert {:error, _} = Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n      end)\n\n      # After failing to compile and reverting the status, it should still recompile\n      Agent.update(:mix_recompile_raise, fn _ -> false end)\n      assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  end\n\n  test \"prints warnings from non-stale files with --all-warnings\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def my_fn(unused), do: :ok\n      end\n      \"\"\")\n\n      # First compilation should print unused variable warning\n      assert capture_io(:stderr, fn ->\n               Mix.Tasks.Compile.Elixir.run([]) == :ok\n             end) =~ \"variable \\\"unused\\\" is unused\"\n\n      assert capture_io(:stderr, fn ->\n               Mix.Tasks.Compile.Elixir.run([])\n             end) =~ \"variable \\\"unused\\\" is unused\"\n\n      assert capture_io(:stderr, fn ->\n               Mix.Tasks.Compile.Elixir.run([\"--no-all-warnings\"])\n             end) == \"\"\n\n      # Should not print warning once fixed\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def my_fn(_unused), do: :ok\n      end\n      \"\"\")\n\n      assert capture_io(:stderr, fn ->\n               Mix.Tasks.Compile.Elixir.run([\"--all-warnings\"])\n             end) == \"\"\n    end)\n  end\n\n  test \"warning from --all-warnings are treated as errors with --warnings-as-errors\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def my_fn(unused), do: :ok\n      end\n      \"\"\")\n\n      message = \"variable \\\"unused\\\" is unused\"\n\n      assert capture_io(:stderr, fn ->\n               Mix.Tasks.Compile.Elixir.run([]) == :ok\n             end) =~ message\n\n      # Stale compilation fails due to warnings as errors\n      assert capture_io(:stderr, fn ->\n               catch_exit(Mix.Task.run(\"compile\", [\"--all-warnings\", \"--warnings-as-errors\"]))\n             end) =~ message\n\n      Mix.Task.clear()\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n      end\n      \"\"\")\n\n      # Recompiling a new file still fails due to warnings as errors\n      assert capture_io(:stderr, fn ->\n               catch_exit(Mix.Task.run(\"compile\", [\"--all-warnings\", \"--warnings-as-errors\"]))\n             end) =~ message\n    end)\n  end\n\n  test \"returns warning diagnostics\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def my_fn(unused), do: :ok\n      end\n      \"\"\")\n\n      file = Path.absname(\"lib/a.ex\")\n\n      message =\n        \"variable \\\"unused\\\" is unused (if the variable is not meant to be used, prefix it with an underscore)\"\n\n      capture_io(:stderr, fn ->\n        assert {:ok, [diagnostic]} = Mix.Tasks.Compile.Elixir.run([])\n\n        assert %Diagnostic{\n                 file: ^file,\n                 source: ^file,\n                 severity: :warning,\n                 position: {2, 13},\n                 compiler_name: \"Elixir\",\n                 message: ^message\n               } = diagnostic\n      end)\n\n      # Recompiling should return :noop status because nothing is stale,\n      # but also include previous warning diagnostics\n      capture_io(:stderr, fn ->\n        assert {:noop, [diagnostic]} = Mix.Tasks.Compile.Elixir.run([])\n\n        assert %Diagnostic{\n                 file: ^file,\n                 source: ^file,\n                 severity: :warning,\n                 position: {2, 13},\n                 compiler_name: \"Elixir\",\n                 message: ^message\n               } = diagnostic\n\n        assert [^diagnostic] = Mix.Tasks.Compile.Elixir.diagnostics()\n        assert [^diagnostic] = Mix.Task.Compiler.diagnostics()\n      end)\n    end)\n  end\n\n  test \"returns warning diagnostics for external files\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      IO.warn \"warning\", [{nil, nil, 0, file: ~c\"lib/foo.txt\", line: 3}]\n      \"\"\")\n\n      capture_io(:stderr, fn ->\n        assert {:ok, [diagnostic]} = Mix.Tasks.Compile.Elixir.run([])\n\n        assert %Diagnostic{\n                 file: nil,\n                 severity: :warning,\n                 position: 0,\n                 compiler_name: \"Elixir\",\n                 message: \"warning\",\n                 stacktrace: [{nil, nil, 0, [file: ~c\"lib/foo.txt\", line: 3]}]\n               } = diagnostic\n      end)\n    end)\n  end\n\n  test \"returns error diagnostics\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        def unused_var(unused_var), do: :ok\n      end\n      \"\"\")\n\n      assert capture_io(:stderr, fn ->\n               assert {:ok, [_diagnostic]} = Mix.Tasks.Compile.Elixir.run([])\n             end) =~ \"unused_var\"\n\n      file = Path.absname(\"lib/a.ex\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def my_fn(), do: $$$\n      end\n      \"\"\")\n\n      refute capture_io(:stderr, fn ->\n               purge([B])\n               assert {:error, [_warning, error]} = Mix.Tasks.Compile.Elixir.run([])\n\n               assert %Diagnostic{\n                        file: ^file,\n                        source: ^file,\n                        severity: :error,\n                        position: {2, 20},\n                        message: \"** (SyntaxError) invalid syntax found on lib/a.ex:2:\" <> _,\n                        compiler_name: \"Elixir\"\n                      } = error\n             end) =~ \"unused_var\"\n\n      assert capture_io(:stderr, fn ->\n               purge([B])\n\n               assert {:error, [_warning, _error]} =\n                        Mix.Tasks.Compile.Elixir.run([\"--all-warnings\"])\n             end) =~ \"unused_var\"\n    end)\n  end\n\n  test \"returns error diagnostics for invalid struct key\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def my_fn(), do: %Date{invalid_key: 2020}\n      end\n      \"\"\")\n\n      file = Path.absname(\"lib/a.ex\")\n\n      capture_io(:stderr, fn ->\n        assert {:error, [diagnostic]} = Mix.Tasks.Compile.Elixir.run([])\n\n        assert %Diagnostic{\n                 file: ^file,\n                 source: ^file,\n                 severity: :error,\n                 position: 2,\n                 message: \"** (KeyError) key :invalid_key not found\" <> _,\n                 compiler_name: \"Elixir\"\n               } = diagnostic\n      end)\n    end)\n  end\n\n  test \"returns error diagnostics when deadlocked\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        B.__info__(:module)\n      end\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        A.__info__(:module)\n      end\n      \"\"\")\n\n      capture_io(:stderr, fn ->\n        assert {:error, errors} = Mix.Tasks.Compile.Elixir.run([])\n        errors = Enum.sort_by(errors, &Map.get(&1, :file))\n\n        file_a = Path.absname(\"lib/a.ex\")\n        file_b = Path.absname(\"lib/b.ex\")\n\n        assert [\n                 %Diagnostic{file: ^file_a, message: \"deadlocked waiting on module B\"},\n                 %Diagnostic{file: ^file_b, message: \"deadlocked waiting on module A\"}\n               ] = errors\n      end)\n    end)\n  end\n\n  test \"verify runtime dependent modules that haven't been compiled\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def foo(), do: :ok\n      end\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        def foo(), do: A.foo()\n      end\n      \"\"\")\n\n      File.write!(\"lib/c.ex\", \"\"\"\n      defmodule C do\n        @after_verify __MODULE__\n        def foo(), do: B.foo()\n        def bar(), do: B.bar()\n        def __after_verify__(__MODULE__) do\n          IO.warn(\"AFTER_VERIFY\", __ENV__)\n        end\n      end\n      \"\"\")\n\n      output =\n        capture_io(:stderr, fn ->\n          Mix.Tasks.Compile.Elixir.run([\"--verbose\"])\n        end)\n\n      refute output =~ \"A.foo/0 is undefined or private\"\n      assert output =~ \"B.bar/0 is undefined or private\"\n      assert output =~ \"AFTER_VERIFY\"\n\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      assert_received {:mix_shell, :info, [\"Compiled lib/c.ex\"]}\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n      end\n      \"\"\")\n\n      output =\n        capture_io(:stderr, fn ->\n          Mix.Tasks.Compile.Elixir.run([\"--verbose\", \"--no-all-warnings\"])\n        end)\n\n      # Check B due to direct dependency on A\n      assert output =~ \"A.foo/0 is undefined or private\"\n      refute output =~ \"B.bar/0 is undefined or private\"\n      refute output =~ \"AFTER_VERIFY\"\n\n      # Ensure only A was recompiled\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/b.ex\"]}\n      refute_received {:mix_shell, :info, [\"Compiled lib/c.ex\"]}\n\n      # We can retrieve all warnings if desired\n      output =\n        capture_io(:stderr, fn ->\n          Mix.Tasks.Compile.Elixir.run([\"--verbose\", \"--all-warnings\"])\n        end)\n\n      assert output =~ \"A.foo/0 is undefined or private\"\n      assert output =~ \"B.bar/0 is undefined or private\"\n      assert output =~ \"AFTER_VERIFY\"\n\n      # Now we change B and it must emit an AFTER_VERIFY warning\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n      end\n      \"\"\")\n\n      output =\n        capture_io(:stderr, fn ->\n          Mix.Tasks.Compile.Elixir.run([\"--verbose\", \"--all-warnings\"])\n        end)\n\n      assert output =~ \"B.foo/0 is undefined or private\"\n      assert output =~ \"B.bar/0 is undefined or private\"\n      assert output =~ \"AFTER_VERIFY\"\n\n      # But we can also disable verification if we want to\n      output =\n        capture_io(:stderr, fn ->\n          Mix.Tasks.Compile.Elixir.run([\"--no-verification\", \"--force\"])\n        end)\n\n      refute output =~ \"B.foo/0 is undefined or private\"\n      refute output =~ \"B.bar/0 is undefined or private\"\n      refute output =~ \"AFTER_VERIFY\"\n    end)\n  end\n\n  defmodule GitApp do\n    def project do\n      [\n        app: :git_app,\n        version: \"0.1.0\",\n        deps: [\n          {:git_repo, \"0.1.0\", git: fixture_path(\"git_repo\"), optional: true}\n        ]\n      ]\n    end\n  end\n\n  test \"compiles without optional dependencies\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n      Mix.Tasks.Deps.Get.run([])\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def hello, do: GitRepo.hello()\n      end\n      \"\"\")\n\n      assert capture_io(:stderr, fn ->\n               Mix.Tasks.Compile.run([\"--no-optional-deps\"]) == :ok\n             end) =~ \"GitRepo.hello/0 is undefined\"\n\n      Mix.Task.clear()\n      assert Mix.Tasks.Compile.run([]) == {:ok, []}\n\n      purge([GitRepo])\n      Mix.Task.clear()\n\n      assert capture_io(:stderr, fn ->\n               Mix.Tasks.Compile.run([\"--no-optional-deps\"]) == :ok\n             end) =~ \"GitRepo.hello/0 is undefined\"\n\n      refute Code.ensure_loaded?(GitRepo)\n    end)\n  end\n\n  describe \"consolidation protocols\" do\n    test \"with local protocols\", context do\n      in_tmp(context.test, fn ->\n        Mix.Project.push(MixTest.Case.Sample)\n\n        File.mkdir_p!(\"lib\")\n        assert Mix.Task.run(\"compile\")\n\n        # Define a local protocol\n        File.write!(\"lib/protocol.ex\", \"\"\"\n        defprotocol Compile.Protocol do\n          def foo(a, b)\n        end\n        \"\"\")\n\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n        mark_as_old!(\"_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam\")\n\n        # Implement a local protocol\n        File.write!(\"lib/impl.ex\", \"\"\"\n        defimpl Compile.Protocol, for: Integer do\n          def foo(a, b), do: a + b\n        end\n        \"\"\")\n\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n\n        assert mark_as_old!(\"_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam\") !=\n                 @old_time\n\n        # Delete a local implementation\n        File.rm!(\"lib/impl.ex\")\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n\n        assert mark_as_old!(\"_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam\") !=\n                 @old_time\n\n        # Delete a local protocol\n        File.rm!(\"lib/protocol.ex\")\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n        refute File.regular?(\"_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam\")\n      end)\n    end\n\n    test \"compiles after converting a protocol into a standard module\", context do\n      in_tmp(context.test, fn ->\n        Mix.Project.push(MixTest.Case.Sample)\n\n        File.mkdir_p!(\"lib\")\n        Mix.Task.run(\"compile\")\n        purge_protocol(Compile.Protocol)\n\n        # Define a local protocol\n        File.write!(\"lib/protocol.ex\", \"\"\"\n        defprotocol Compile.Protocol do\n          def foo(a)\n        end\n\n        defimpl Compile.Protocol, for: Integer do\n          def foo(a), do: a\n        end\n        \"\"\")\n\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n        mark_as_old!(\"_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam\")\n        File.rm!(\"lib/protocol.ex\")\n\n        # Define a standard module\n        File.write!(\"lib/protocol.ex\", \"\"\"\n        defmodule Compile.Protocol do\n        end\n        \"\"\")\n\n        purge_protocol(Compile.Protocol)\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n\n        # Delete a local protocol\n        File.rm!(\"lib/protocol.ex\")\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n        refute File.regular?(\"_build/dev/lib/sample/consolidated/Elixir.Compile.Protocol.beam\")\n      end)\n    end\n\n    test \"with deps protocols\", context do\n      in_tmp(context.test, fn ->\n        Mix.Project.push(MixTest.Case.Sample)\n\n        File.mkdir_p!(\"lib\")\n        Mix.Task.run(\"compile\")\n        purge_protocol(String.Chars)\n        mark_as_old!(\"_build/dev/lib/sample/consolidated/Elixir.String.Chars.beam\")\n\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:noop, []}\n        assert mtime(\"_build/dev/lib/sample/consolidated/Elixir.String.Chars.beam\") == @old_time\n\n        # Implement a deps protocol\n        File.write!(\"lib/struct.ex\", \"\"\"\n        defmodule Compile.Protocol.Struct do\n          defstruct a: nil\n          defimpl String.Chars do\n            def to_string(_), do: \"ok\"\n          end\n        end\n        \"\"\")\n\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n\n        assert mark_as_old!(\"_build/dev/lib/sample/consolidated/Elixir.String.Chars.beam\") !=\n                 @old_time\n\n        # Delete the local implementation\n        File.rm!(\"lib/struct.ex\")\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:ok, []}\n\n        assert mark_as_old!(\"_build/dev/lib/sample/consolidated/Elixir.String.Chars.beam\") !=\n                 @old_time\n      end)\n    end\n\n    test \"keep relative path to their source\" do\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(MixTest.Case.Sample)\n        Mix.Task.run(\"compile\")\n\n        # Load consolidated\n        :code.add_patha(~c\"_build/dev/lib/sample/consolidated\")\n        :code.purge(Enumerable)\n        :code.delete(Enumerable)\n\n        try do\n          Enumerable.impl_for!(:oops)\n        rescue\n          Protocol.UndefinedError ->\n            assert [{_, _, _, [file: ~c\"lib/enum.ex\"] ++ _} | _] = __STACKTRACE__\n        else\n          _ ->\n            flunk(\"Enumerable.impl_for!/1 should have failed\")\n        after\n          purge_protocol(Enumerable)\n        end\n      end)\n    end\n\n    test \"purges consolidation path if asked\" do\n      in_fixture(\"no_mixfile\", fn ->\n        File.write!(\"lib/a.ex\", \"\"\"\n        defmodule A do\n          defstruct []\n        end\n\n        defimpl Collectable, for: A do\n          def into(_), do: fn _, _  -> raise \"oops\" end\n        end\n        \"\"\")\n\n        Mix.Project.push(MixTest.Case.Sample)\n\n        # At this point, it may or may not emit warnings, but we don't care,\n        # we validate both scenarios next.\n        assert {:ok, _} = Mix.Tasks.Compile.run([])\n        assert is_function(Collectable.into(struct(A, [])), 2)\n\n        purge([A, B, Collectable.A])\n        Mix.Task.clear()\n\n        assert capture_io(:stderr, fn ->\n                 {:ok, [_]} = Mix.Tasks.Compile.run([\"--force\"])\n               end) =~\n                 \"the Collectable protocol has already been consolidated\"\n\n        purge([A, B, Collectable.A])\n        Mix.Task.clear()\n        consolidation = Mix.Project.consolidation_path()\n        args = [\"--force\", \"--purge-consolidation-path-if-stale\", consolidation]\n        assert Mix.Tasks.Compile.run(args) == {:ok, []}\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/compile.erlang_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Compile.ErlangTest do\n  use MixTest.Case\n  import ExUnit.CaptureIO\n\n  defmacro position(line, column), do: {line, column}\n\n  setup config do\n    erlc_options = Map.get(config, :erlc_options, [])\n    Mix.ProjectStack.post_config(erlc_options: erlc_options)\n    Mix.Project.push(MixTest.Case.Sample)\n    :ok\n  end\n\n  @tag erlc_options: [{:d, ~c\"foo\", ~c\"bar\"}]\n  test \"raises on invalid erlc_options\" do\n    in_fixture(\"compile_erlang\", fn ->\n      assert_raise Mix.Error, ~r/Compiling Erlang file \".*\" failed/, fn ->\n        capture_io(fn ->\n          Mix.Tasks.Compile.Erlang.run([])\n        end)\n      end\n    end)\n  end\n\n  test \"compiles and cleans src/b.erl, src/c.erl, and src/z.erl\" do\n    in_fixture(\"compile_erlang\", fn ->\n      assert Mix.Tasks.Compile.Erlang.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled src/b.erl\"]}\n      assert_received {:mix_shell, :info, [\"Compiled src/c.erl\"]}\n      assert_received {:mix_shell, :info, [\"Compiled src/z.erl\"]}\n\n      assert File.regular?(\"_build/dev/lib/sample/ebin/b.beam\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/c.beam\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/z.beam\")\n\n      assert Mix.Tasks.Compile.Erlang.run([\"--verbose\"]) == {:noop, []}\n      refute_received {:mix_shell, :info, [\"Compiled src/b.erl\"]}\n\n      assert Mix.Tasks.Compile.Erlang.run([\"--force\", \"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled src/b.erl\"]}\n      assert_received {:mix_shell, :info, [\"Compiled src/c.erl\"]}\n      assert_received {:mix_shell, :info, [\"Compiled src/z.erl\"]}\n\n      assert Mix.Tasks.Compile.Erlang.clean()\n      refute File.regular?(\"_build/dev/lib/sample/ebin/b.beam\")\n      refute File.regular?(\"_build/dev/lib/sample/ebin/c.beam\")\n      refute File.regular?(\"_build/dev/lib/sample/ebin/z.beam\")\n    end)\n  end\n\n  test \"removes old artifact files\" do\n    in_fixture(\"compile_erlang\", fn ->\n      assert Mix.Tasks.Compile.Erlang.run([]) == {:ok, []}\n      assert File.regular?(\"_build/dev/lib/sample/ebin/b.beam\")\n\n      File.rm!(\"src/b.erl\")\n      assert Mix.Tasks.Compile.Erlang.run([]) == {:ok, []}\n      refute File.regular?(\"_build/dev/lib/sample/ebin/b.beam\")\n    end)\n  end\n\n  test \"compilation purges the module\" do\n    in_fixture(\"compile_erlang\", fn ->\n      # Create the first version of the module.\n      defmodule :purge_test do\n        def version, do: :v1\n      end\n\n      assert :v1 == :purge_test.version()\n\n      # Create the second version of the module (this time as Erlang source).\n      File.write!(\"src/purge_test.erl\", \"\"\"\n      -module(purge_test).\n      -export([version/0]).\n      version() -> v2.\n      \"\"\")\n\n      assert Mix.Tasks.Compile.Erlang.run([]) == {:ok, []}\n\n      # If the module was not purged on recompilation, this would fail.\n      assert :v2 == :purge_test.version()\n    end)\n  end\n\n  test \"continues even if one file fails to compile\" do\n    in_fixture(\"compile_erlang\", fn ->\n      file = Path.absname(\"src/zzz.erl\")\n      source = deterministic_source(file)\n\n      File.write!(file, \"\"\"\n      -module(zzz).\n      def zzz(), do: b\n      \"\"\")\n\n      capture_io(fn ->\n        assert {:error, [diagnostic]} = Mix.Tasks.Compile.Erlang.run([])\n\n        assert %Mix.Task.Compiler.Diagnostic{\n                 compiler_name: \"erl_parse\",\n                 file: ^source,\n                 source: ^source,\n                 message: \"syntax error before: zzz\",\n                 position: position(2, 5),\n                 severity: :error\n               } = diagnostic\n      end)\n\n      assert File.regular?(\"_build/dev/lib/sample/ebin/b.beam\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/c.beam\")\n    end)\n  end\n\n  test \"saves warnings between builds\" do\n    in_fixture(\"compile_erlang\", fn ->\n      file = Path.absname(\"src/has_warning.erl\")\n      source = deterministic_source(file)\n\n      File.write!(file, \"\"\"\n      -module(has_warning).\n      my_fn() -> ok.\n      \"\"\")\n\n      capture_io(fn ->\n        assert {:ok, [diagnostic]} = Mix.Tasks.Compile.Erlang.run([])\n\n        assert %Mix.Task.Compiler.Diagnostic{\n                 file: ^source,\n                 source: ^source,\n                 compiler_name: \"erl_lint\",\n                 message: \"function my_fn/0 is unused\",\n                 position: position(2, 1),\n                 severity: :warning\n               } = diagnostic\n\n        capture_io(:stderr, fn ->\n          # Should return warning without recompiling file\n          assert {:noop, [^diagnostic]} = Mix.Tasks.Compile.Erlang.run([\"--verbose\"])\n          refute_received {:mix_shell, :info, [\"Compiled src/has_warning.erl\"]}\n\n          assert [^diagnostic] = Mix.Tasks.Compile.Erlang.diagnostics()\n          assert [^diagnostic] = Mix.Task.Compiler.diagnostics()\n\n          # Should not return warning after changing file\n          File.write!(file, \"\"\"\n          -module(has_warning).\n          -export([my_fn/0]).\n          my_fn() -> ok.\n          \"\"\")\n\n          ensure_touched(file)\n          assert {:ok, []} = Mix.Tasks.Compile.Erlang.run([])\n        end)\n      end)\n    end)\n  end\n\n  test \"prints warnings from stale files with --all-warnings\" do\n    in_fixture(\"compile_erlang\", fn ->\n      file = Path.absname(\"src/has_warning.erl\")\n\n      File.write!(file, \"\"\"\n      -module(has_warning).\n      my_fn() -> ok.\n      \"\"\")\n\n      capture_io(fn -> Mix.Tasks.Compile.Erlang.run([]) end)\n\n      assert capture_io(:stderr, fn ->\n               assert {:noop, _} = Mix.Tasks.Compile.Erlang.run([])\n             end) =~ ~r\"has_warning.erl:2:(1:)? warning: function my_fn/0 is unused\\n\"\n\n      assert capture_io(:stderr, fn ->\n               assert {:noop, _} = Mix.Tasks.Compile.Erlang.run([])\n             end) =~ ~r\"has_warning.erl:2:(1:)? warning: function my_fn/0 is unused\\n\"\n\n      # Should not print old warnings after fixing\n      File.write!(file, \"\"\"\n      -module(has_warning).\n      \"\"\")\n\n      ensure_touched(file)\n\n      assert capture_io(fn ->\n               Mix.Tasks.Compile.Erlang.run([\"--all-warnings\"])\n             end) == \"\"\n    end)\n  end\n\n  @tag erlc_options: [{:warnings_as_errors, true}]\n  test \"adds :debug_info to erlc_options by default\" do\n    in_fixture(\"compile_erlang\", fn ->\n      Mix.Tasks.Compile.Erlang.run([])\n      binary = File.read!(\"_build/dev/lib/sample/ebin/b.beam\")\n\n      {:ok, {_, [debug_info: {:debug_info_v1, _, {debug_info, _}}]}} =\n        :beam_lib.chunks(binary, [:debug_info])\n\n      assert debug_info != :none\n    end)\n  end\n\n  if :deterministic in :compile.env_compiler_options() do\n    defp deterministic_source(file), do: Path.basename(file)\n  else\n    defp deterministic_source(file), do: file\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/compile.leex_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Compile.LeexTest do\n  use MixTest.Case\n  import ExUnit.CaptureIO\n\n  setup do\n    Mix.ProjectStack.post_config(compilers: [:leex | Mix.compilers()])\n    Mix.Project.push(MixTest.Case.Sample)\n    :ok\n  end\n\n  test \"compilation continues if one file fails to compile\" do\n    in_fixture(\"compile_leex\", fn ->\n      file = Path.absname(\"src/zzz.xrl\")\n\n      File.write!(file, \"\"\"\n      oops.\n      \"\"\")\n\n      capture_io(fn ->\n        assert {:error, [diagnostic]} = Mix.Tasks.Compile.Leex.run([\"--force\"])\n\n        assert %Mix.Task.Compiler.Diagnostic{\n                 compiler_name: \"leex\",\n                 file: ^file,\n                 source: ^file,\n                 message: \"missing Definitions\",\n                 position: 1,\n                 severity: :error\n               } = diagnostic\n      end)\n\n      assert File.regular?(\"src/test_ok.erl\")\n    end)\n  end\n\n  test \"compiles src/test_ok.xrl\" do\n    in_fixture(\"compile_leex\", fn ->\n      assert Mix.Tasks.Compile.Leex.run([\"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled src/test_ok.xrl\"]}\n      assert File.regular?(\"src/test_ok.erl\")\n\n      assert Mix.Tasks.Compile.Leex.run([\"--verbose\"]) == {:noop, []}\n      refute_received {:mix_shell, :info, [\"Compiled src/test_ok.xrl\"]}\n\n      assert Mix.Tasks.Compile.Leex.run([\"--force\", \"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled src/test_ok.xrl\"]}\n    end)\n  end\n\n  test \"removes old artifact files\" do\n    in_fixture(\"compile_leex\", fn ->\n      assert Mix.Tasks.Compile.Leex.run([]) == {:ok, []}\n      assert File.regular?(\"src/test_ok.erl\")\n\n      File.rm!(\"src/test_ok.xrl\")\n      assert Mix.Tasks.Compile.Leex.run([]) == {:ok, []}\n      refute File.regular?(\"src/test_ok.erl\")\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/compile.yecc_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Compile.YeccTest do\n  use MixTest.Case\n  import ExUnit.CaptureIO\n\n  defmacro position(line, column), do: {line, column}\n\n  setup do\n    Mix.ProjectStack.post_config(compilers: [:yecc | Mix.compilers()])\n    Mix.Project.push(MixTest.Case.Sample)\n    :ok\n  end\n\n  test \"compilation continues if one file fails to compile\" do\n    in_fixture(\"compile_yecc\", fn ->\n      file = Path.absname(\"src/zzz.yrl\")\n\n      File.write!(file, \"\"\"\n      oops.\n      \"\"\")\n\n      capture_io(fn ->\n        assert {:error, [diagnostic]} = Mix.Tasks.Compile.Yecc.run([\"--force\"])\n\n        assert %Mix.Task.Compiler.Diagnostic{\n                 compiler_name: \"yecc\",\n                 file: ^file,\n                 source: ^file,\n                 message: message,\n                 position: position(1, 5),\n                 severity: :error\n               } = diagnostic\n\n        assert message =~ \"syntax error before: \"\n      end)\n\n      assert File.regular?(\"src/test_ok.erl\")\n    end)\n  end\n\n  test \"returns warning diagnostics on conflicts\" do\n    in_fixture(\"compile_yecc\", fn ->\n      file = Path.absname(\"src/conflict.yrl\")\n\n      File.write!(file, \"\"\"\n      Nonterminals exp.\n      Terminals number '+'.\n      Rootsymbol exp.\n      exp -> exp '+' exp.\n      exp -> number.\n      \"\"\")\n\n      capture_io(fn ->\n        assert {:ok, [diagnostic]} = Mix.Tasks.Compile.Yecc.run([\"--force\"])\n\n        assert %Mix.Task.Compiler.Diagnostic{\n                 compiler_name: \"yecc\",\n                 file: ^file,\n                 source: ^file,\n                 message: \"conflicts: 1 shift/reduce, 0 reduce/reduce\",\n                 position: 0,\n                 severity: :warning\n               } = diagnostic\n      end)\n\n      # Removing parse tools re-add it later even if only to show warnings\n      :code.del_path(:parsetools)\n      purge([:yecc])\n      refute Code.ensure_loaded?(:yecc)\n\n      capture_io(fn ->\n        assert {:noop, [diagnostic]} = Mix.Tasks.Compile.Yecc.run([])\n\n        assert %Mix.Task.Compiler.Diagnostic{\n                 compiler_name: \"yecc\",\n                 file: ^file,\n                 source: ^file,\n                 message: \"conflicts: 1 shift/reduce, 0 reduce/reduce\",\n                 position: 0,\n                 severity: :warning\n               } = diagnostic\n      end)\n    end)\n  end\n\n  test \"compiles src/test_ok.yrl\" do\n    in_fixture(\"compile_yecc\", fn ->\n      assert Mix.Tasks.Compile.Yecc.run([\"--verbose\"]) == {:ok, []}\n\n      assert_received {:mix_shell, :info, [\"Compiled src/test_ok.yrl\"]}\n      assert File.regular?(\"src/test_ok.erl\")\n\n      assert Mix.Tasks.Compile.Yecc.run([\"--verbose\"]) == {:noop, []}\n      refute_received {:mix_shell, :info, [\"Compiled src/test_ok.yrl\"]}\n\n      assert Mix.Tasks.Compile.Yecc.run([\"--force\", \"--verbose\"]) == {:ok, []}\n      assert_received {:mix_shell, :info, [\"Compiled src/test_ok.yrl\"]}\n    end)\n  end\n\n  test \"removes old artifact files\" do\n    in_fixture(\"compile_yecc\", fn ->\n      assert Mix.Tasks.Compile.Yecc.run([]) == {:ok, []}\n      assert File.regular?(\"src/test_ok.erl\")\n\n      File.rm!(\"src/test_ok.yrl\")\n      assert Mix.Tasks.Compile.Yecc.run([]) == {:ok, []}\n      refute File.regular?(\"src/test_ok.erl\")\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/compile_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.CompileTest do\n  use MixTest.Case\n\n  defmacro position(line, column), do: {line, column}\n\n  defmodule DepsApp do\n    def project do\n      [app: :deps_app, version: \"0.1.0\", deps: [{:ok, \"0.1.0\", path: \"deps/ok\"}]]\n    end\n  end\n\n  defmodule WrongPath do\n    def project do\n      [app: :apps_path_bug, apps_path: \"this_path_does_not_exist\"]\n    end\n  end\n\n  setup tags do\n    Mix.ProjectStack.post_config(Map.get(tags, :project, []))\n    Mix.Project.push(MixTest.Case.Sample)\n    :ok\n  end\n\n  test \"compiles --list with mixfile\" do\n    Mix.Task.run(\"compile\", [\"--list\"])\n\n    msg = \"\\nEnabled compilers: yecc, leex, erlang, elixir, app, protocols\"\n    assert_received {:mix_shell, :info, [^msg]}\n\n    assert_received {:mix_shell, :info, [\"mix compile.elixir # \" <> _]}\n  end\n\n  @tag project: [compilers: [:elixir, :app, :custom]]\n  test \"compiles --list with custom mixfile\" do\n    Mix.Task.run(\"compile\", [\"--list\"])\n\n    assert_received {:mix_shell, :info,\n                     [\"\\nEnabled compilers: yecc, leex, elixir, app, custom, protocols\"]}\n  end\n\n  @tag project: [compilers: [:elixir, :app, :custom]]\n  test \"compiles does not require all compilers available on manifest\" do\n    assert Mix.Task.Compiler.manifests() |> Enum.map(&Path.basename/1) ==\n             [\"compile.yecc\", \"compile.leex\", \"compile.elixir\"]\n  end\n\n  test \"compiles a project with mixfile\" do\n    in_fixture(\"no_mixfile\", fn ->\n      assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:ok, []}\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/sample.app\")\n      assert_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n      assert_received {:mix_shell, :info, [\"Generated sample app\"]}\n      assert File.regular?(\"_build/dev/lib/sample/consolidated/Elixir.Enumerable.beam\")\n\n      Mix.Task.clear()\n      assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:noop, []}\n      refute_received {:mix_shell, :info, [\"Compiled lib/a.ex\"]}\n    end)\n  end\n\n  test \"compiles a project with cached deps information\" do\n    Mix.Project.pop()\n\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      root = File.cwd!()\n      File.cd!(\"lib\", fn ->\n        %{ok: path} = Mix.Project.deps_paths()\n\n        if Path.relative_to(path, root) != \"deps/ok\" do\n          raise \"non cached path\"\n        end\n      end)\n      \"\"\")\n\n      assert Mix.Task.run(\"compile\", [\"--force\", \"--from-mix-deps-compile\"]) == {:ok, []}\n    end)\n  end\n\n  @tag project: [compilers: Mix.compilers() ++ [:my_custom_compiler]]\n  test \"compiles a project with custom in-project compiler\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule Mix.Tasks.Compile.MyCustomCompiler do\n        use Mix.Task.Compiler\n\n        @impl true\n        def run(_args) do\n          Mix.shell().info(\"Compiling...\")\n          :ok\n        end\n      end\n      \"\"\")\n\n      assert Mix.Task.run(\"compile\") == {:ok, []}\n      assert_receive {:mix_shell, :info, [\"Compiling...\"]}\n      Code.delete_path(Mix.Project.compile_path())\n      purge([Mix.Tasks.Compile.MyCustomCompiler])\n      false = Code.ensure_loaded?(Mix.Tasks.Compile.MyCustomCompiler)\n\n      Mix.Task.clear()\n      assert Mix.Task.rerun(\"compile\")\n    end)\n  end\n\n  test \"reenables compilers\" do\n    in_fixture(\"no_mixfile\", fn ->\n      assert Mix.Tasks.Compile.run([\"--verbose\"]) == {:ok, []}\n      Mix.shell().flush()\n\n      File.mkdir_p!(\"lib/foo\")\n\n      File.write!(\"lib/foo/z1.ex\", \"\"\"\n      defmodule Z1 do\n        def ok, do: :ok\n      end\n      \"\"\")\n\n      assert :ok = Mix.Task.reenable(\"compile\")\n      assert {:noop, []} = Mix.Task.run(\"compile\")\n      refute File.regular?(\"_build/dev/lib/sample/ebin/Elixir.Z1.beam\")\n\n      assert :ok = Mix.Task.Compiler.reenable([])\n      assert {:noop, []} = Mix.Task.run(\"compile\")\n      refute File.regular?(\"_build/dev/lib/sample/ebin/Elixir.Z1.beam\")\n\n      assert :ok = Mix.Task.Compiler.reenable([\"erlang\"])\n      assert {:noop, []} = Mix.Task.run(\"compile\")\n      refute File.regular?(\"_build/dev/lib/sample/ebin/Elixir.Z1.beam\")\n\n      assert :ok = Mix.Task.Compiler.reenable()\n      assert {:ok, []} = Mix.Task.run(\"compile\")\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.Z1.beam\")\n\n      File.write!(\"lib/foo/z2.ex\", \"\"\"\n      defmodule Z2 do\n        def ko, do: :ko\n      end\n      \"\"\")\n\n      assert :ok = Mix.Task.Compiler.reenable([:erlang])\n      assert {:noop, []} = Mix.Task.run(\"compile\")\n      refute File.regular?(\"_build/dev/lib/sample/ebin/Elixir.Z2.beam\")\n\n      assert :ok = Mix.Task.Compiler.reenable([:elixir])\n      assert {:ok, []} = Mix.Task.run(:compile)\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.Z2.beam\")\n    end)\n  end\n\n  test \"recompiles app cache if manifest changes\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Tasks.Compile.run([\"--force\"])\n      purge([A, B])\n\n      File.rm!(\"_build/dev/lib/sample/.mix/compile.app_cache\")\n      Mix.Task.clear()\n\n      Mix.Tasks.Compile.run([\"--force\"])\n      assert File.exists?(\"_build/dev/lib/sample/.mix/compile.app_cache\")\n    end)\n  end\n\n  # A.info/0 is loaded dynamically\n  @compile {:no_warn_undefined, {A, :info, 0}}\n\n  test \"adds Logger application metadata\" do\n    import ExUnit.CaptureLog\n\n    in_fixture(\"no_mixfile\", fn ->\n      Process.put({MixTest.Case.Sample, :application}, extra_applications: [:logger])\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n      require Logger\n      def info, do: Logger.info(\"hello\")\n      end\n      \"\"\")\n\n      assert Mix.Task.run(\"compile\", []) == {:ok, []}\n\n      try do\n        assert capture_log([metadata: [:application]], &A.info/0) =~ \"application=sample\"\n      after\n        purge([A])\n      end\n    end)\n  end\n\n  test \"returns errors from compilers when --return-errors is set\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        def my_fn(), do: $$$\n      end\n      \"\"\")\n\n      file = Path.absname(\"lib/a.ex\")\n\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        assert {:error, [diagnostic]} = Mix.Task.run(\"compile\", [\"--return-errors\"])\n\n        assert %Mix.Task.Compiler.Diagnostic{\n                 file: ^file,\n                 source: ^file,\n                 severity: :error,\n                 position: {2, 20},\n                 message: \"** (SyntaxError) invalid syntax found on lib/a.ex:2:\" <> _,\n                 compiler_name: \"Elixir\",\n                 details: {:error, %SyntaxError{}}\n               } = diagnostic\n      end)\n    end)\n  end\n\n  test \"calling raise inside a macro returns a diagnostic with a position\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        defmacro custom_macro do\n          raise \"error\"\n        end\n      end\n      \"\"\")\n\n      File.write!(\"lib/b.ex\", \"\"\"\n      defmodule B do\n        require A\n        A.custom_macro()\n      end\n      \"\"\")\n\n      file = Path.absname(\"lib/b.ex\")\n\n      ExUnit.CaptureIO.capture_io(:stderr, fn ->\n        assert {:error, [diagnostic]} = Mix.Task.run(\"compile\", [\"--return-errors\"])\n\n        assert %Mix.Task.Compiler.Diagnostic{\n                 file: ^file,\n                 source: ^file,\n                 severity: :error,\n                 position: 3,\n                 message: \"** (RuntimeError) error\\n    expanding macro: A.custom_macro/0\" <> _,\n                 compiler_name: \"Elixir\"\n               } = diagnostic\n      end)\n    end)\n  end\n\n  test \"skip protocol consolidation when --no-protocol-consolidation\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.rm(\"_build/dev/lib/sample/.mix/compile.protocols\")\n      assert Mix.Task.run(\"compile\", [\"--no-protocol-consolidation\"]) == {:ok, []}\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      refute File.regular?(\"_build/dev/lib/sample/consolidated/Elixir.Enumerable.beam\")\n    end)\n  end\n\n  test \"loads consolidated protocols even on --no-compile\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.rm(\"_build/dev/lib/sample/.mix/compile.protocols\")\n      consolidated = \"_build/dev/lib/sample/consolidated\" |> Path.expand() |> to_charlist()\n\n      assert Mix.Task.run(\"compile\") == {:ok, []}\n      assert File.regular?(\"_build/dev/lib/sample/consolidated/Elixir.Enumerable.beam\")\n      assert consolidated in :code.get_path()\n\n      Code.delete_path(\"_build/dev/lib/sample/consolidated\")\n      assert Mix.Task.rerun(\"compile\", [\"--no-compile\"]) == {:noop, []}\n      assert consolidated in :code.get_path()\n    end)\n  end\n\n  test \"loads Mix config with --erl-config\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.write!(\"mix.config\", \"{erl_config_app, [{value, true}]}.\")\n      assert Mix.Task.run(\"compile\", [\"--erl-config\", \"mix.config\"]) == {:ok, []}\n      assert File.regular?(\"_build/dev/lib/sample/ebin/Elixir.A.beam\")\n      assert Application.get_env(:erl_config_app, :value)\n    end)\n  after\n    Application.delete_env(:erl_config_app, :value)\n  end\n\n  test \"runs after_compiler callback once\" do\n    in_fixture(\"no_mixfile\", fn ->\n      callback = fn result -> send(self(), result) end\n\n      assert Mix.Task.Compiler.after_compiler(:elixir, callback) == :ok\n      assert Mix.Task.rerun(\"compile\", []) == {:ok, []}\n      assert_received {:ok, []}\n\n      Mix.Task.clear()\n      assert Mix.Task.rerun(\"compile\", []) == {:noop, []}\n      refute_received {:noop, []}\n\n      Mix.Task.clear()\n      assert Mix.Task.Compiler.after_compiler(:elixir, callback) == :ok\n      assert Mix.Task.run(\"compile\", []) == {:noop, []}\n      assert_received {:noop, []}\n    end)\n  end\n\n  test \"does not crash on a project with bad path\" do\n    Mix.Project.pop()\n    Mix.Project.push(WrongPath)\n\n    ExUnit.CaptureIO.capture_io(fn ->\n      assert Mix.Task.run(\"compile\", [\"--no-protocol-consolidation\"]) == {:noop, []}\n    end)\n  end\n\n  test \"validates compile_env\" do\n    in_fixture(\"no_mixfile\", fn ->\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :sample, :hello, System.get_env(\"MIX_SAMPLE_HELLO\")\n      \"\"\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      defmodule A do\n        require Application\n        _ = Application.compile_env(:sample, :hello)\n      end\n      \"\"\")\n\n      System.put_env(\"MIX_SAMPLE_HELLO\", \"compile\")\n      Mix.Tasks.Loadconfig.run([])\n      assert Mix.Tasks.Compile.All.run([]) == {:ok, []}\n\n      System.put_env(\"MIX_SAMPLE_HELLO\", \"runtime\")\n      Mix.Tasks.Loadconfig.run([])\n      Application.unload(:sample)\n\n      assert_raise Mix.Error,\n                   ~r/the application :sample has a different value set for key :hello during runtime compared to compile time/,\n                   fn -> Mix.Tasks.Compile.All.run([]) end\n\n      # Can start if compile env matches\n      System.put_env(\"MIX_SAMPLE_HELLO\", \"compile\")\n      Mix.Tasks.Loadconfig.run([])\n      assert Mix.Tasks.App.Start.run([]) == :ok\n    end)\n  after\n    System.delete_env(\"MIX_SAMPLE_HELLO\")\n    Application.delete_env(:sample, :hello, persistent: true)\n  end\n\n  test \"code path pruning\" do\n    Mix.ensure_application!(:parsetools)\n    otp_docs? = match?({:docs_v1, _, _, _, _, _, _}, Code.fetch_docs(:zlib))\n\n    in_fixture(\"no_mixfile\", fn ->\n      assert Mix.Task.run(\"compile\", []) == {:ok, []}\n      assert :code.where_is_file(~c\"parsetools.app\") == :non_existing\n\n      # Make sure erts is also kept but not loaded\n      assert Application.spec(:erts, :vsn) == nil\n\n      if otp_docs? do\n        assert {:docs_v1, _, _, _, _, _, _} = Code.fetch_docs(:zlib)\n      else\n        IO.warn(\"Erlang/OTP was not compiled with docs, skipping assertion\")\n      end\n    end)\n  end\n\n  test \"code path pruning disabled\" do\n    Mix.ensure_application!(:parsetools)\n\n    in_fixture(\"no_mixfile\", fn ->\n      assert Mix.Task.run(\"compile\", [\"--no-prune-code-paths\"]) == {:ok, []}\n      assert is_list(:code.where_is_file(~c\"parsetools.app\"))\n    end)\n  end\n\n  test \"listening to concurrent compilations\" do\n    timeout = 2_000\n\n    Mix.Project.pop()\n\n    in_fixture(\"compile_listeners\", fn ->\n      File.write!(\"mix.exs\", \"\"\"\n        defmodule WithReloader do\n          use Mix.Project\n\n          def project do\n            [\n              app: :with_reloader,\n              version: \"0.1.0\",\n              deps: [{:reloader, \"0.1.0\", path: \"deps/reloader\"}],\n              # Register a listener from a dependency\n              listeners: [Reloader]\n            ]\n          end\n        end\n      \"\"\")\n\n      File.mkdir_p!(\"config\")\n\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/a.ex\", \"defmodule A do end\")\n      File.write!(\"lib/b.ex\", \"defmodule B do end\")\n      File.write!(\"lib/c.ex\", \"defmodule C do end\")\n\n      File.mkdir_p!(\"src\")\n\n      File.write!(\"src/a.erl\", \"-module(a).\")\n      File.write!(\"src/b.erl\", \"-module(b).\")\n      File.write!(\"src/c.erl\", \"-module(c).\")\n\n      # Ensure we can boot without compilation and listeners if desired\n      assert mix([\"loadpaths\", \"--no-compile\", \"--no-listeners\"]) == \"\"\n\n      # Ensure we can boot only with --no-deps-check if desired\n      assert mix([\"loadpaths\", \"--no-deps-check\"]) == \"\"\n\n      # Now setup dependencies\n      mix([\"deps.compile\"])\n\n      parent = self()\n\n      spawn_link(fn ->\n        port =\n          mix_port([\n            \"run\",\n            \"--no-halt\",\n            \"--no-compile\",\n            \"--no-start\",\n            \"--eval\",\n            ~s/IO.puts(\"ok\"); IO.gets(\"\"); System.halt()/\n          ])\n\n        assert_receive {^port, {:data, \"ok\\n\"}}, timeout\n        send(parent, :mix_started)\n\n        send_port_outputs_to(port, parent)\n      end)\n\n      assert_receive :mix_started, timeout\n\n      # Project compilation\n\n      output = mix([\"do\", \"compile\", \"+\", \"eval\", \"IO.write System.pid\"])\n      os_pid = output |> String.split(\"\\n\") |> List.last()\n\n      assert_receive {:output, output}, timeout\n\n      assert output == \"\"\"\n             Received :modules_compiled with\n               added: [:a, :b, :c], changed: [], removed: []\n               app: :with_reloader\n               scm: Mix.SCM.Path\n               os_pid: \"#{os_pid}\"\n             \"\"\"\n\n      assert_receive {:output, output}, timeout\n\n      assert output == \"\"\"\n             Received :modules_compiled with\n               added: [A, B, C], changed: [], removed: []\n               app: :with_reloader\n               scm: Mix.SCM.Path\n               os_pid: \"#{os_pid}\"\n             \"\"\"\n\n      # Changed\n      File.write!(\"lib/a.ex\", \"defmodule A do @moduledoc false end\")\n      File.write!(\"src/a.erl\", \"-module(a). -export([a/0]). a() -> ok.\")\n      File.touch!(\"src/a.erl\", System.os_time(:second) + 10)\n      # Removed\n      File.rm!(\"lib/b.ex\")\n      File.rm!(\"src/b.erl\")\n      # New\n      File.write!(\"lib/d.ex\", \"defmodule D do end\")\n      File.write!(\"src/d.erl\", \"-module(d).\")\n\n      # Project recompilation\n\n      output = mix([\"do\", \"compile\", \"+\", \"eval\", \"IO.write System.pid\"])\n      os_pid = output |> String.split(\"\\n\") |> List.last()\n\n      assert_receive {:output, output}, timeout\n\n      assert output == \"\"\"\n             Received :modules_compiled with\n               added: [:d], changed: [:a], removed: [:b]\n               app: :with_reloader\n               scm: Mix.SCM.Path\n               os_pid: \"#{os_pid}\"\n             \"\"\"\n\n      assert_receive {:output, output}, timeout\n\n      assert output == \"\"\"\n             Received :modules_compiled with\n               added: [D], changed: [A], removed: [B]\n               app: :with_reloader\n               scm: Mix.SCM.Path\n               os_pid: \"#{os_pid}\"\n             \"\"\"\n\n      # Dependency recompilation\n\n      output = mix([\"do\", \"deps.compile\", \"--force\", \"+\", \"eval\", \"IO.write System.pid\"])\n      os_pid = output |> String.split(\"\\n\") |> List.last()\n\n      assert_receive {:output, output}, timeout\n\n      assert output == \"\"\"\n             Received :modules_compiled with\n               added: [Reloader], changed: [], removed: []\n               app: :reloader\n               scm: Mix.SCM.Path\n               os_pid: \"#{os_pid}\"\n             \"\"\"\n\n      assert_receive {:output, output}, timeout\n\n      assert output == \"\"\"\n             Received :dep_compiled with\n               app: :reloader\n               scm: Mix.SCM.Path\n               manager: :mix\n               os_pid: \"#{os_pid}\"\n             \"\"\"\n    end)\n  end\n\n  defp send_port_outputs_to(port, pid) do\n    receive do\n      {^port, {:data, output}} ->\n        send(pid, {:output, output})\n        send_port_outputs_to(port, pid)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/deps.git_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.DepsGitTest do\n  use MixTest.Case\n\n  defmodule DepsOnGitApp do\n    def project do\n      [\n        app: :deps_on_git_app,\n        version: \"0.1.0\",\n        deps: [\n          {:deps_on_git_repo, \"0.2.0\", git: fixture_path(\"deps_on_git_repo\")}\n        ]\n      ]\n    end\n  end\n\n  defmodule GitApp do\n    def project do\n      opts = Process.get(:git_repo_opts) || []\n\n      [\n        app: :git_app,\n        version: \"0.1.0\",\n        deps: [\n          {:git_repo, \"0.1.0\", [git: fixture_path(\"git_repo\")] ++ opts}\n        ]\n      ]\n    end\n  end\n\n  defmodule GitSubmodulesApp do\n    def project do\n      [\n        app: :git_app,\n        version: \"0.1.0\",\n        deps: [\n          {:git_repo, \"0.1.0\", git: fixture_path(\"git_repo\"), submodules: true}\n        ]\n      ]\n    end\n  end\n\n  defmodule GitErrorApp do\n    def project do\n      [\n        deps: [\n          {:git_repo, \"0.1.0\", git: fixture_path(\"not_git_repo\")}\n        ]\n      ]\n    end\n  end\n\n  test \"gets and updates Git repos with compilation\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      assert File.read!(\"mix.lock\") =~\n               ~r/\"git_repo\": {:git, #{inspect(fixture_path(\"git_repo\"))}, \"[a-f0-9]+\", \\[\\]}/\n\n      Mix.Tasks.Deps.Update.run([\"--all\"])\n      message = \"* Updating git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n    end)\n  end\n\n  test \"gets Git repos with git trace enabled\" do\n    on_exit(fn ->\n      System.delete_env(\"GIT_TRACE\")\n      :ets.delete(Mix.State, :git_version)\n    end)\n\n    System.put_env(\"GIT_TRACE\", \"1\")\n    :ets.delete(Mix.State, :git_version)\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      assert File.read!(\"mix.lock\") =~\n               ~r/\"git_repo\": {:git, #{inspect(fixture_path(\"git_repo\"))}, \"[a-f0-9]+\", \\[\\]}/\n    end)\n  end\n\n  test \"gets and updates Git repos with submodules\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitSubmodulesApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n      assert File.read!(\"mix.lock\") =~ \"submodules: true\"\n    end)\n  end\n\n  test \"gets with short ref\" do\n    [<<short_sha1::binary-size(8), _::binary>>, _ | _] = get_git_repo_revs(\"git_repo\")\n    Process.put(:git_repo_opts, ref: short_sha1)\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")} - #{short_sha1})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      refute_received {:mix_shell, :error, _}\n    end)\n  end\n\n  @tag :git_sparse\n  test \"gets and updates Git repos with sparse checkout\" do\n    Process.put(:git_repo_opts, sparse: \"sparse_dir\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n      refute File.exists?(\"deps/git_repo/mix.exs\")\n      assert File.exists?(\"deps/git_repo/sparse_dir/mix.exs\")\n      assert File.read!(\"mix.lock\") =~ \"sparse: \\\"sparse_dir\\\"\"\n    end)\n  end\n\n  test \"gets and updates Git repos with subdir\" do\n    Process.put(:git_repo_opts, subdir: \"subdir\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n      assert File.read!(\"mix.lock\") =~ \"subdir: \\\"subdir\\\"\"\n    end)\n  end\n\n  test \"handles invalid .git directory\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      File.mkdir_p!(\"deps/git_repo/.git\")\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n    end)\n  end\n\n  test \"handles missing .git directory\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n      File.rm_rf!(\"deps/git_repo/.git\")\n\n      assert_raise Mix.Error, \"Can't continue due to errors on dependencies\", fn ->\n        Mix.Tasks.Deps.Loadpaths.run([\"git_repo\"])\n      end\n    end)\n  end\n\n  test \"gets and updates many levels deep dependencies\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(DepsOnGitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      message = \"* Getting deps_on_git_repo (#{fixture_path(\"deps_on_git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      assert File.exists?(\"deps/deps_on_git_repo/mix.exs\")\n      assert File.exists?(\"deps/git_repo/mix.exs\")\n\n      # Compile the dependencies\n      Mix.Tasks.Deps.Compile.run([])\n      assert File.exists?(\"_build/dev/lib/deps_on_git_repo/.mix/compile.elixir_scm\")\n      assert File.exists?(\"_build/dev/lib/git_repo/.mix/compile.elixir_scm\")\n\n      # Now update children and make sure it propagates\n      Mix.Tasks.Deps.Update.run([\"git_repo\"])\n      refute File.exists?(\"_build/dev/lib/deps_on_git_repo/.mix/compile.elixir_scm\")\n      refute File.exists?(\"_build/dev/lib/git_repo/.mix/compile.elixir_scm\")\n\n      # Clear tasks to recompile Git repo but unload it so...\n      purge([GitRepo])\n      Mix.Task.clear()\n      Mix.Tasks.Deps.Compile.run([\"git_repo\"])\n      assert File.exists?(\"_build/dev/lib/git_repo/ebin\")\n      Code.delete_path(\"_build/dev/lib/git_repo/ebin\")\n\n      # Deps on Git repo loads it automatically on compile\n      Mix.Task.reenable(\"deps.loadpaths\")\n      Mix.Tasks.Deps.Compile.run([\"deps_on_git_repo\"])\n      assert File.exists?(\"_build/dev/lib/deps_on_git_repo/ebin\")\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"compiles many levels deep dependencies\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(DepsOnGitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      refute File.exists?(\"_build/dev/lib/deps_on_git_repo\")\n      refute File.exists?(\"_build/dev/lib/git_repo\")\n\n      # Compile the parent with children\n      Mix.Tasks.Deps.Compile.run([\"deps_on_git_repo\", \"--include-children\"])\n      assert File.exists?(\"_build/dev/lib/deps_on_git_repo\")\n      assert File.exists?(\"_build/dev/lib/git_repo\")\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"all dependencies have been fetched\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      Mix.Tasks.Deps.Get.run([])\n      assert_received {:mix_shell, :info, [\"All dependencies have been fetched\"]}\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"updates the lock when the repo updates\" do\n    Mix.Project.push(GitApp)\n\n    # Get Git repo first revision\n    [last, first | _] = get_git_repo_revs(\"git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), first, []}})\n\n      Mix.Tasks.Deps.Get.run([])\n      refute File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ first\n\n      Mix.Tasks.Deps.Update.run([\"git_repo\"])\n      assert File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ last\n\n      Mix.Tasks.Deps.Clean.run([\"--all\"])\n      refute File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ last\n\n      Mix.Tasks.Deps.Clean.run([\"--unlock\", \"--all\"])\n      refute File.read!(\"mix.lock\") =~ last\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"updates the repo when the lock updates\" do\n    Mix.Project.push(GitApp)\n    [last, first | _] = get_git_repo_revs(\"git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), first, []}})\n\n      Mix.Tasks.Deps.Get.run([])\n      refute File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ first\n\n      # Update the lock and now we should get an error\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), last, []}})\n\n      assert_raise Mix.Error, fn -> Mix.Tasks.Deps.Loadpaths.run([]) end\n\n      # Flush the errors we got, move to a clean slate\n      Mix.shell().flush()\n      Mix.Task.clear()\n\n      # Calling get should update the dependency\n      Mix.Tasks.Deps.Get.run([])\n      assert File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ last\n\n      message = \"* Updating git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      # Check we got no error\n      refute_received {:mix_shell, :error, _}\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  @tag :git_sparse\n  test \"updates the repo when sparse is turned off\" do\n    Process.put(:git_repo_opts, sparse: \"sparse_dir\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      refute File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n\n      # Flush the errors we got, move to a clean slate\n      Mix.shell().flush()\n      Mix.Task.clear()\n      Process.delete(:git_repo_opts)\n      Mix.Project.pop()\n      Mix.Project.push(GitApp)\n\n      # Calling get should update the dependency\n      Mix.Tasks.Deps.Get.run([])\n      refute File.read!(\"mix.lock\") =~ \"sparse_dir\"\n      assert File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n\n      message = \"* Updating git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      # Check we got no error\n      refute_received {:mix_shell, :error, _}\n    end)\n  end\n\n  @tag :git_sparse\n  test \"updates the repo when sparse is turned on\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      assert File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n\n      # Flush the errors we got, move to a clean slate\n      Mix.shell().flush()\n      Mix.Task.clear()\n      Process.put(:git_repo_opts, sparse: \"sparse_dir\")\n      Mix.Project.pop()\n      Mix.Project.push(GitApp)\n\n      # Calling get should update the dependency\n      Mix.Tasks.Deps.Get.run([])\n      assert File.read!(\"mix.lock\") =~ \"sparse_dir\"\n      refute File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n\n      message = \"* Updating git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      # Check we got no error\n      refute_received {:mix_shell, :error, _}\n    end)\n  end\n\n  test \"updates the repo and the lock when the mixfile updates\" do\n    Mix.Project.push(GitApp)\n    [last, first | _] = get_git_repo_revs(\"git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      # Move to the first version\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), first, []}})\n\n      Mix.Tasks.Deps.Get.run([])\n      assert File.read!(\"mix.lock\") =~ first\n\n      # Update the project configuration. It should force an update.\n      refresh(deps: [{:git_repo, \"0.1.0\", git: fixture_path(\"git_repo\"), ref: last}])\n\n      Mix.Tasks.Deps.run([])\n\n      msg =\n        \"  lock outdated: the lock is outdated compared to the options in your mix.exs. To fetch locked version run \\\"mix deps.get\\\"\"\n\n      assert_received {:mix_shell, :info, [^msg]}\n\n      # Check an update was triggered\n      Mix.Tasks.Deps.Get.run([])\n      assert File.read!(\"mix.lock\") =~ last\n\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      # Check we got no error\n      refute_received {:mix_shell, :error, _}\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"fetches children on updates\" do\n    Mix.Project.push(DepsOnGitApp)\n\n    # Get Git repo first revision\n    [last, first | _] = get_git_repo_revs(\"deps_on_git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Dep.Lock.write(%{deps_on_git_repo: {:git, fixture_path(\"deps_on_git_repo\"), first, []}})\n\n      Mix.Tasks.Deps.Get.run([])\n      assert File.exists?(\"deps/deps_on_git_repo/mix.exs\")\n      refute File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ first\n\n      Mix.Task.clear()\n      Mix.State.clear_cache()\n      purge([DepsOnGitRepo.MixProject])\n\n      # Write to the checkout location to ensure it is replaced\n      File.mkdir_p!(\"deps/deps_on_git_repo/lib\")\n      File.write!(\"deps/deps_on_git_repo/lib/deps_on_git_repo.ex\", \"# WILL BE OVERRIDDEN\")\n\n      Mix.Tasks.Deps.Update.run([\"deps_on_git_repo\"])\n      assert File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ last\n      assert File.read!(\"deps/deps_on_git_repo/lib/deps_on_git_repo.ex\") =~ \"GitRepo.hello()\"\n      refute File.exists?(\"_build/dev/lib/git_repo/.mix/compile.elixir_scm\")\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"fetches children on get\" do\n    Mix.Project.push(DepsOnGitApp)\n\n    # Get Git repo first revision\n    [last, first | _] = get_git_repo_revs(\"deps_on_git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Dep.Lock.write(%{deps_on_git_repo: {:git, fixture_path(\"deps_on_git_repo\"), first, []}})\n\n      Mix.Tasks.Deps.Get.run([])\n      assert File.exists?(\"deps/deps_on_git_repo/mix.exs\")\n      refute File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ first\n\n      Mix.Task.clear()\n      Mix.State.clear_cache()\n      purge([DepsOnGitRepo.MixProject])\n\n      # Write to the checkout location to ensure it is replaced\n      File.mkdir_p!(\"deps/deps_on_git_repo/lib\")\n      File.write!(\"deps/deps_on_git_repo/lib/deps_on_git_repo.ex\", \"# WILL BE OVERRIDDEN\")\n\n      Mix.Dep.Lock.write(%{deps_on_git_repo: {:git, fixture_path(\"deps_on_git_repo\"), last, []}})\n      Mix.Tasks.Deps.Get.run([])\n      assert File.exists?(\"deps/git_repo/lib/git_repo.ex\")\n      assert File.read!(\"mix.lock\") =~ last\n      assert File.read!(\"deps/deps_on_git_repo/lib/deps_on_git_repo.ex\") =~ \"GitRepo.hello()\"\n      refute File.exists?(\"_build/dev/lib/git_repo/.mix/compile.elixir_scm\")\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"does not attempt to compile projects that could not be retrieved\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitErrorApp)\n\n      exception = assert_raise Mix.Error, fn -> Mix.Tasks.Deps.Get.run([]) end\n\n      assert Exception.message(exception) =~ \"Command \\\"git --git-dir=.git fetch\"\n    end)\n  end\n\n  test \"does not load bad mixfiles on get\" do\n    Mix.Project.push(GitApp)\n    [last, _, bad | _] = get_git_repo_revs(\"git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), bad, []}})\n      catch_error(Mix.Tasks.Deps.Get.run([]))\n\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), last, []}})\n      Mix.Tasks.Deps.Get.run([])\n      assert File.read!(\"mix.lock\") =~ last\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"updates on Git opts change\" do\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Project.push(GitApp)\n\n      Process.put(:git_repo_opts, tag: \"without_module\")\n      refresh([])\n      Mix.Tasks.Deps.Get.run([])\n      refute File.regular?(\"deps/git_repo/lib/git_repo.ex\")\n\n      Process.put(:git_repo_opts, tag: \"with_module\")\n      refresh([])\n      Mix.Tasks.Deps.Get.run([])\n      assert File.regular?(\"deps/git_repo/lib/git_repo.ex\")\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"does not load bad mixfiles on update\" do\n    Mix.Project.push(GitApp)\n    [last, _, bad | _] = get_git_repo_revs(\"git_repo\")\n\n    in_fixture(\"no_mixfile\", fn ->\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), bad, []}})\n      catch_error(Mix.Tasks.Deps.Get.run([]))\n\n      Mix.Tasks.Deps.Update.run([\"git_repo\"])\n      Mix.Tasks.Deps.Compile.run([\"git_repo\"])\n      assert File.read!(\"mix.lock\") =~ last\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  describe \"Git depth option\" do\n    @describetag :git_depth\n\n    test \"gets and updates Git repos with depth option\" do\n      Process.put(:git_repo_opts, depth: 1)\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n\n        # Expand depth\n        update_dep(depth: 2)\n        Mix.Tasks.Deps.Get.run([])\n        assert_shallow(\"deps/git_repo\", 2)\n\n        # Reduce depth\n        update_dep(depth: 1)\n        Mix.Tasks.Deps.Get.run([])\n        assert_shallow(\"deps/git_repo\", 1)\n      end)\n    end\n\n    test \"with tag\" do\n      Process.put(:git_repo_opts, depth: 1, tag: \"with_module\")\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")} - with_module)\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n      end)\n    end\n\n    test \"with branch\" do\n      Process.put(:git_repo_opts, depth: 1, branch: \"main\")\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")} - main)\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n      end)\n    end\n\n    test \"with ref\" do\n      [sha1, _ | _] = get_git_repo_revs(\"git_repo\")\n\n      Process.put(:git_repo_opts, depth: 1, ref: sha1)\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")} - #{sha1})\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n      end)\n    end\n\n    test \"raises with short ref\" do\n      # When fetching, Git requires a fully spelled hex object name. We prevent\n      # this failure mode by validating the ref length.\n      #\n      # If Git ever changes such that it can resolve a short ref in a shallow\n      # fetch, we can update our docs and this test to reflect that.\n      #\n      # https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt-ltrefspecgt\n      # https://stackoverflow.com/a/43136160\n      [<<short_sha1::binary-size(8), _::binary>>, _ | _] = get_git_repo_revs(\"git_repo\")\n\n      Process.put(:git_repo_opts, depth: 1, ref: short_sha1)\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n        exception = assert_raise Mix.Error, fn -> Mix.Tasks.Deps.Get.run([]) end\n        assert Exception.message(exception) =~ \"a full commit hash is required\"\n      end)\n    end\n\n    test \"changing refspec updates retaining depth\" do\n      [last, first | _] = get_git_repo_revs(\"git_repo\")\n\n      Process.put(:git_repo_opts, ref: first, depth: 1)\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")} - #{first})\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n        assert File.read!(\"mix.lock\") =~ first\n\n        # Change refspec\n        update_dep(ref: last, depth: 1)\n        Mix.Tasks.Deps.Get.run([])\n        assert_shallow(\"deps/git_repo\", 1)\n        assert File.read!(\"mix.lock\") =~ last\n      end)\n    end\n\n    test \"removing depth retains shallow repository\" do\n      # For compatibility and simplicity, we follow Git's behavior and do not\n      # attempt to unshallow an existing repository. This should not be a\n      # problem, because all we guarantee is that the correct source code is\n      # available whenever mix.exs or mix.lock change. If one wanted to have a\n      # full clone, they can always run `deps.clean` and `deps.get` again.\n      Process.put(:git_repo_opts, depth: 1)\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n\n        # Remove depth\n        update_dep([])\n        Mix.Tasks.Deps.Get.run([])\n        refute File.read!(\"mix.lock\") =~ \"depth:\"\n        assert File.exists?(\"deps/git_repo/.git/shallow\")\n\n        assert System.cmd(\"git\", ~w[--git-dir=deps/git_repo/.git rev-list --count HEAD]) ==\n                 {\"1\\n\", 0}\n      end)\n    end\n\n    @tag :git_sparse\n    test \"with sparse checkout\" do\n      Process.put(:git_repo_opts, sparse: \"sparse_dir\", depth: 1)\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n\n        refute File.exists?(\"deps/git_repo/mix.exs\")\n        assert File.exists?(\"deps/git_repo/sparse_dir/mix.exs\")\n        assert File.read!(\"mix.lock\") =~ \"sparse: \\\"sparse_dir\\\"\"\n      end)\n    end\n\n    test \"with subdir\" do\n      Process.put(:git_repo_opts, subdir: \"sparse_dir\", depth: 1)\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n\n        assert File.exists?(\"deps/git_repo/mix.exs\")\n        assert File.exists?(\"deps/git_repo/sparse_dir/mix.exs\")\n        assert File.read!(\"mix.lock\") =~ \"subdir: \\\"sparse_dir\\\"\"\n      end)\n    end\n\n    test \"does not affect submodules depth\" do\n      # The expectation is that we can add an explicit option in the future,\n      # just like git-clone has `--shallow-submodules`.\n      Process.put(:git_repo_opts, submodules: true, depth: 1)\n\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Project.push(GitApp)\n\n        Mix.Tasks.Deps.Get.run([])\n        message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n        assert_received {:mix_shell, :info, [^message]}\n        assert_shallow(\"deps/git_repo\", 1)\n\n        assert File.read!(\"mix.lock\") =~ \"submodules: true\"\n        # TODO: assert submodule is not shallow. This would likely require\n        # changes to the fixtures. Apparently, not even the submodules-specific\n        # tests check that the cloned repo contains submodules as expected.\n      end)\n    end\n\n    defp update_dep(git_repo_opts) do\n      # Flush the errors we got, move to a clean slate\n      Mix.shell().flush()\n      Mix.Task.clear()\n      Process.put(:git_repo_opts, git_repo_opts)\n      Mix.Project.pop()\n      Mix.Project.push(GitApp)\n    end\n\n    defp assert_shallow(repo_path, depth) do\n      assert File.read!(\"mix.lock\") =~ \"depth: #{depth}\"\n\n      # Check if the repository is a shallow clone\n      assert File.exists?(repo_path <> \"/.git/shallow\")\n\n      # Check the number of commits in the current branch.\n      #\n      # We could consider all branches with `git rev-list --count --all`, as in\n      # practice there should be only a single branch. However, the test fixture\n      # sets up two branches, and that brings us to an interesting situation:\n      # instead of guaranteeing that the `:depth` option would keep the\n      # repository lean even after refspec changes, we only guarantee the number\n      # of commits in the current branch, perhaps leaving more objects around\n      # than strictly necessary. This allows us to keep the implementation\n      # simple, while still providing a reasonable guarantee.\n      assert System.cmd(\"git\", ~w[--git-dir=#{repo_path}/.git rev-list --count HEAD]) ==\n               {\"#{depth}\\n\", 0}\n    end\n  end\n\n  defp refresh(post_config) do\n    %{name: name, file: file} = Mix.Project.pop()\n    Mix.ProjectStack.post_config(post_config)\n    Mix.Project.push(name, file)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/deps.path_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.DepsPathTest do\n  use MixTest.Case\n\n  defmodule DepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:raw_repo, \"0.1.0\", path: \"custom/raw_repo\"}\n        ]\n      ]\n    end\n  end\n\n  defmodule MismatchDepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:cooked_repo, \"0.1.0\", path: \"custom/raw_repo\"}\n        ]\n      ]\n    end\n  end\n\n  @tag apps: [:raw_sample]\n  test \"compiles and runs even if lock does not match\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Dep.Lock.write(%{raw_repo: \"abcdef\"})\n      Mix.Tasks.Run.run([\"-e\", \"Mix.shell().info RawRepo.hello()\"])\n      assert_received {:mix_shell, :info, [\"==> raw_repo\"]}\n      assert_received {:mix_shell, :info, [\"world\"]}\n    end)\n  end\n\n  @tag apps: [:raw_sample]\n  test \"uses the name of the app, not the path basename\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(MismatchDepsApp)\n\n      Mix.Tasks.Deps.Compile.run([])\n      assert File.exists?(\"_build/dev/lib/cooked_repo/ebin\")\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/deps.tree_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Deps.TreeTest do\n  use MixTest.Case\n\n  defmodule ConvergedDepsApp do\n    def project do\n      [\n        app: :sample,\n        version: \"0.1.0\",\n        deps: [\n          {:deps_on_git_repo, \"0.2.0\", git: fixture_path(\"deps_on_git_repo\")},\n          {:git_repo, \">= 0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n        ]\n      ]\n    end\n  end\n\n  defmodule OverriddenDepsApp do\n    def project do\n      [\n        app: :sample,\n        version: \"0.1.0\",\n        deps: [\n          {:deps_on_git_repo, ~r\"0.2.0\", git: fixture_path(\"deps_on_git_repo\"), only: :test},\n          {:git_repo, git: MixTest.Case.fixture_path(\"git_repo\"), override: true}\n        ]\n      ]\n    end\n  end\n\n  defmodule UmbrellaApp do\n    def project do\n      [\n        app: :sample,\n        version: \"0.1.0\",\n        deps: [\n          {:umbrella_dep, in_umbrella: true}\n        ]\n      ]\n    end\n  end\n\n  test \"shows the dependency tree\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(ConvergedDepsApp)\n\n      Mix.Tasks.Deps.Tree.run([\"--format\", \"pretty\"])\n      assert_received {:mix_shell, :info, [\"sample\"]}\n      assert_received {:mix_shell, :info, [\"├── deps_on_git_repo 0.2.0 (\" <> _]}\n      assert_received {:mix_shell, :info, [\"└── git_repo >= 0.1.0 (\" <> _]}\n\n      Mix.Tasks.Deps.Get.run([])\n      Mix.Tasks.Deps.Tree.run([\"--format\", \"pretty\"])\n      assert_received {:mix_shell, :info, [\"sample\"]}\n      assert_received {:mix_shell, :info, [\"├── deps_on_git_repo 0.2.0 (\" <> _]}\n      assert_received {:mix_shell, :info, [\"│   └── git_repo (\" <> _]}\n      assert_received {:mix_shell, :info, [\"└── git_repo >= 0.1.0 (\" <> _]}\n    end)\n  after\n    purge([DepsOnGitRepo.MixProject, GitRepo.MixProject])\n  end\n\n  test \"show the dependency tree for umbrella apps\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Task.run(\"deps.tree\", [\"--format\", \"pretty\"])\n        assert_received {:mix_shell, :info, [\"foo\"]}\n        assert_received {:mix_shell, :info, [\"bar\"]}\n        assert_received {:mix_shell, :info, [\"└── foo (../foo)\"]}\n      end)\n    end)\n  end\n\n  test \"filters umbrella deps only with --umbrella-only\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Task.run(\"deps.tree\", [\"--format\", \"pretty\", \"--umbrella-only\"])\n        assert_received {:mix_shell, :info, [\"foo\"]}\n        assert_received {:mix_shell, :info, [\"bar\"]}\n        assert_received {:mix_shell, :info, [\"└── foo (../foo)\"]}\n      end)\n    end)\n  end\n\n  test \"shows the given dependency\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(ConvergedDepsApp)\n\n      assert_raise Mix.Error, \"could not find dependency unknown\", fn ->\n        Mix.Tasks.Deps.Tree.run([\"--format\", \"pretty\", \"unknown\"])\n      end\n\n      Mix.Tasks.Deps.Tree.run([\"--format\", \"pretty\", \"deps_on_git_repo\"])\n      assert_received {:mix_shell, :info, [\"deps_on_git_repo 0.2.0 (\" <> _]}\n      refute_received {:mix_shell, :info, [\"└── git_repo (\" <> _]}\n    end)\n  end\n\n  test \"shows overridden deps\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(OverriddenDepsApp)\n\n      Mix.Tasks.Deps.Tree.run([\"--format\", \"pretty\"])\n      assert_received {:mix_shell, :info, [\"sample\"]}\n      assert_received {:mix_shell, :info, [\"└── git_repo (\" <> msg]}\n      assert_received {:mix_shell, :info, [\"├── deps_on_git_repo ~r/0.2.0/ (\" <> _]}\n      assert msg =~ \"*override*\"\n    end)\n  end\n\n  test \"excludes the given deps\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(OverriddenDepsApp)\n\n      Mix.Tasks.Deps.Tree.run([\"--format\", \"pretty\", \"--exclude\", \"deps_on_git_repo\"])\n      assert_received {:mix_shell, :info, [\"sample\"]}\n      assert_received {:mix_shell, :info, [\"└── git_repo (\" <> _]}\n      refute_received {:mix_shell, :info, [\"└── deps_on_git_repo ~r/0.2.0/ (\" <> _]}\n    end)\n  end\n\n  test \"shows a particular environment\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(OverriddenDepsApp)\n\n      Mix.Tasks.Deps.Tree.run([\"--format\", \"pretty\", \"--only\", \"prod\"])\n      assert_received {:mix_shell, :info, [\"sample\"]}\n      assert_received {:mix_shell, :info, [\"└── git_repo (\" <> _]}\n      refute_received {:mix_shell, :info, [\"└── deps_on_git_repo ~r/0.2.0/ (\" <> _]}\n    end)\n  end\n\n  test \"shows the dependency tree in DOT graph format\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(ConvergedDepsApp)\n\n      Mix.Tasks.Deps.Tree.run([\"--format\", \"dot\"])\n\n      assert File.read!(\"deps_tree.dot\") == \"\"\"\n             digraph \"dependency tree\" {\n               \"sample\"\n               \"sample\" -> \"deps_on_git_repo\" [label=\"0.2.0\"]\n               \"sample\" -> \"git_repo\" [label=\">= 0.1.0\"]\n             }\n             \"\"\"\n\n      Mix.Tasks.Deps.Get.run([])\n      Mix.Tasks.Deps.Tree.run([\"--format\", \"dot\"])\n\n      assert File.read!(\"deps_tree.dot\") == \"\"\"\n             digraph \"dependency tree\" {\n               \"sample\"\n               \"sample\" -> \"deps_on_git_repo\" [label=\"0.2.0\"]\n               \"deps_on_git_repo\" -> \"git_repo\" [label=\"\"]\n               \"sample\" -> \"git_repo\" [label=\">= 0.1.0\"]\n             }\n             \"\"\"\n    end)\n  after\n    purge([DepsOnGitRepo.MixProject, GitRepo.MixProject])\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/deps_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.DepsTest do\n  use MixTest.Case\n\n  defmodule DepsApp do\n    def project do\n      [\n        app: :deps,\n        version: \"0.1.0\",\n        deps: [\n          {:ok, \"0.1.0\", github: \"elixir-lang/ok\"},\n          {:invalidvsn, \"0.2.0\", path: \"deps/invalidvsn\"},\n          {:invalidapp, \"0.1.0\", path: \"deps/invalidapp\"},\n          {:noappfile, \"0.1.0\", path: \"deps/noappfile\"},\n          {:nosemver, \"~> 0.1\", path: \"deps/nosemver\"}\n        ]\n      ]\n    end\n  end\n\n  defmodule SuccessfulDepsApp do\n    def project do\n      [\n        app: :sample,\n        version: \"0.1.0\",\n        deps: [\n          {:ok, \"0.1.0\", path: \"deps/ok\"}\n        ]\n      ]\n    end\n  end\n\n  defmodule ReqDepsApp do\n    def project do\n      [\n        app: :req_deps,\n        version: \"0.1.0\",\n        deps: [\n          {:ok, \">= 2.0.0\", path: \"deps/ok\"},\n          {:noappfile, path: \"deps/noappfile\", app: false},\n          {:apppath, path: \"deps/noappfile\", app: \"../deps/ok/ebin/ok.app\"}\n        ]\n      ]\n    end\n  end\n\n  defmodule MissingLocalDepsApp do\n    def project do\n      [\n        app: :missing_local_deps,\n        version: \"0.1.0\",\n        deps: [\n          {:ok, path: \"missing/dep\"}\n        ]\n      ]\n    end\n  end\n\n  defmodule RawRepoDepApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:raw_repo, \"0.1.0\", path: \"custom/raw_repo\"}\n        ]\n      ]\n    end\n  end\n\n  ## deps\n\n  test \"prints list of dependencies and their status alphabetically\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n      Mix.Tasks.Deps.run([])\n\n      invalid_app_file =\n        \"  the app file at \\\"_build/dev/lib/invalidapp/ebin/invalidapp.app\\\" is invalid\"\n\n      assert {:messages,\n              [\n                {:mix_shell, :info, [\"* invalidapp (deps/invalidapp) (mix)\"]},\n                {:mix_shell, :info, [^invalid_app_file]},\n                {:mix_shell, :info, [\"* invalidvsn (deps/invalidvsn)\"]},\n                {:mix_shell, :info, [\"  the app file contains an invalid version: :ok\"]},\n                {:mix_shell, :info, [\"* noappfile (deps/noappfile)\"]},\n                {:mix_shell, :info, [\"  could not find an app file at \" <> _]},\n                {:mix_shell, :info, [\"* nosemver (deps/nosemver)\"]},\n                {:mix_shell, :info, [\"  the app file specified a non-Semantic\" <> _]},\n                {:mix_shell, :info, [\"* ok (https://github.com/elixir-lang/ok.git) (mix)\"]},\n                {:mix_shell, :info, [\"  the dependency is not available, run \\\"mix deps.get\\\"\"]}\n              ]} = Process.info(self(), :messages)\n    end)\n  end\n\n  test \"filters dependencies by name\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Tasks.Deps.run([\"ok\"])\n\n      assert_received {:mix_shell, :info, [\"* ok (https://github.com/elixir-lang/ok.git) (mix)\"]}\n      refute_received {:mix_shell, :info, [\"* invalidvsn\" <> _]}\n      refute_received {:mix_shell, :info, [\"* invalidapp\" <> _]}\n      refute_received {:mix_shell, :info, [\"* noappfile\" <> _]}\n      refute_received {:mix_shell, :info, [\"* nosemver\" <> _]}\n    end)\n  end\n\n  test \"warns when filtering for unknown dependencies\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Tasks.Deps.run([\"ok\", \"unknowndep\"])\n\n      assert_received {:mix_shell, :info, [\"* ok (https://github.com/elixir-lang/ok.git) (mix)\"]}\n      assert_received {:mix_shell, :error, [\"warning: unknown dependency unknowndep\"]}\n    end)\n  end\n\n  test \"filters dependencies and deals with duplicates\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Tasks.Deps.run([\n        \"nosemver\",\n        \"unknowndep2\",\n        \"ok\",\n        \"ok\",\n        \"unknowndep1\",\n        \"invalidapp\",\n        \"ok\"\n      ])\n\n      assert {:messages,\n              [\n                {:mix_shell, :info, [\"* nosemver (deps/nosemver)\"]},\n                {:mix_shell, :info, [\"  the app file specified a non-Semantic\" <> _]},\n                {:mix_shell, :info, [\"* ok (https://github.com/elixir-lang/ok.git) (mix)\"]},\n                {:mix_shell, :info, [\"  the dependency is not available, run \\\"mix deps.get\\\"\"]},\n                {:mix_shell, :info, [\"* invalidapp (deps/invalidapp) (mix)\"]},\n                {:mix_shell, :info, [\"  the app file at \" <> _]},\n                {:mix_shell, :error, [\"warning: unknown dependency unknowndep2\"]},\n                {:mix_shell, :error, [\"warning: unknown dependency unknowndep1\"]}\n              ]} = Process.info(self(), :messages)\n    end)\n  end\n\n  test \"prints list of dependencies and their status, including req mismatches and custom apps\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(ReqDepsApp)\n\n      Mix.Tasks.Deps.run([])\n\n      assert_received {:mix_shell, :info, [\"* ok (deps/ok) (mix)\"]}\n      msg = \"  the dependency does not match the requirement \\\">= 2.0.0\\\", got \\\"0.1.0\\\"\"\n      assert_received {:mix_shell, :info, [^msg]}\n\n      assert_received {:mix_shell, :info, [\"* apppath (deps/noappfile)\"]}\n      refute_received {:mix_shell, :info, [\"  could not find app file at \" <> _]}\n\n      assert_received {:mix_shell, :info, [\"* noappfile (deps/noappfile)\"]}\n      refute_received {:mix_shell, :info, [\"  could not find app file at \" <> _]}\n    end)\n  end\n\n  test \"prints misspelled dependency name hint\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      other_app_path = Path.join(Mix.Project.build_path(), \"lib/noappfile/ebin/other_app.app\")\n      File.mkdir_p!(Path.dirname(other_app_path))\n      File.write!(other_app_path, \"\")\n\n      Mix.Tasks.Deps.run([])\n\n      message =\n        \"  could not find an app file at \\\"_build/dev/lib/noappfile/ebin/noappfile.app\\\". \" <>\n          \"Another app file was found in the same directory \" <>\n          \"\\\"_build/dev/lib/noappfile/ebin/other_app.app\\\", \" <>\n          \"try changing the dependency name to :other_app\"\n\n      assert_received {:mix_shell, :info, [\"* noappfile (deps/noappfile)\"]}\n      assert_received {:mix_shell, :info, [^message]}\n    end)\n  end\n\n  test \"prints Elixir req mismatches\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(ReqDepsApp)\n\n      File.write!(\"deps/ok/mix.exs\", \"\"\"\n      defmodule Deps.OkApp do\n        use Mix.Project\n\n        def project do\n          [elixir: \"~> 0.1.0\", app: :ok, version: \"2.0.0\"]\n        end\n      end\n      \"\"\")\n\n      Mix.Tasks.Deps.Compile.run([:ok])\n\n      msg =\n        \"warning: the dependency :ok requires Elixir \\\"~> 0.1.0\\\" \" <>\n          \"but you are running on v#{System.version()}\"\n\n      assert_received {:mix_shell, :error, [^msg]}\n\n      Mix.Tasks.Deps.Compile.run([])\n    end)\n  end\n\n  test \"prints list of dependencies and their lock status\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      File.cd!(\"deps/ok\", fn ->\n        System.cmd(\"git\", ~w[-c core.hooksPath='' init])\n      end)\n\n      Mix.Tasks.Deps.run([])\n      assert_received {:mix_shell, :info, [\"* ok (https://github.com/elixir-lang/ok.git) (mix)\"]}\n\n      msg =\n        \"  the dependency is not locked. To generate the \\\"mix.lock\\\" file run \\\"mix deps.get\\\"\"\n\n      assert_received {:mix_shell, :info, [^msg]}\n\n      Mix.Dep.Lock.write(%{ok: {:git, \"https://github.com/elixir-lang/ok.git\", \"abcdefghi\", []}})\n      Mix.Tasks.Deps.run([])\n\n      assert_received {:mix_shell, :info, [\"* ok (https://github.com/elixir-lang/ok.git) (mix)\"]}\n      assert_received {:mix_shell, :info, [\"  locked at abcdefg\"]}\n\n      msg =\n        \"  lock mismatch: the dependency is out of date. To fetch locked version run \\\"mix deps.get\\\"\"\n\n      assert_received {:mix_shell, :info, [^msg]}\n\n      Mix.Dep.Lock.write(%{\n        ok: {:git, \"git://github.com/elixir-lang/another.git\", \"abcdefghi\", []}\n      })\n\n      Mix.Tasks.Deps.run([])\n\n      assert_received {:mix_shell, :info, [\"* ok (https://github.com/elixir-lang/ok.git) (mix)\"]}\n\n      msg =\n        \"  lock outdated: the lock is outdated compared to the options in your mix.exs. To fetch locked version run \\\"mix deps.get\\\"\"\n\n      assert_received {:mix_shell, :info, [^msg]}\n    end)\n  end\n\n  test \"cleans and recompiles artifacts if --force is given\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(SuccessfulDepsApp)\n\n      Mix.Tasks.Deps.Compile.run([])\n      File.touch!(\"_build/dev/lib/ok/clean-me\")\n\n      Mix.Tasks.Deps.Compile.run([\"--force\"])\n      refute File.exists?(\"_build/dev/lib/ok/clean-me\")\n    end)\n  end\n\n  test \"compiles deps using os partitions\" do\n    System.put_env(\"MIX_OS_DEPS_COMPILE_PARTITION_COUNT\", \"2\")\n\n    in_fixture(\"deps_status\", fn ->\n      File.write!(\"mix.exs\", \"\"\"\n      defmodule ParDepsApp do\n        use Mix.Project\n\n        def project do\n          [\n            app: :par_sample,\n            version: \"0.1.0\",\n            deps: [\n              {:raw_repo, \"0.1.0\", path: \"custom/raw_repo\"},\n              {:git_repo, \"0.1.0\", path: #{inspect(fixture_path(\"git_repo\"))}}\n            ]\n          ]\n        end\n      end\n      \"\"\")\n\n      Mix.Project.in_project(:par_sample, \".\", fn _ ->\n        output = ExUnit.CaptureIO.capture_io(fn -> Mix.Tasks.Deps.Compile.run([]) end)\n        assert output =~ ~r/\\d> Generated git_repo app/\n        assert output =~ ~r/\\d> Generated raw_repo app/\n        assert_received {:mix_shell, :info, [\"mix deps.compile running across 2 OS processes\"]}\n      end)\n    end)\n  after\n    System.delete_env(\"MIX_OS_DEPS_COMPILE_PARTITION_COUNT\")\n  end\n\n  test \"doesn't compile any umbrella apps if --skip-umbrella-children is given\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Tasks.Deps.Compile.run([\"--skip-umbrella-children\"])\n        refute File.exists?(\"_build/dev/lib/foo/ebin\")\n        refute File.exists?(\"_build/dev/lib/bar/ebin\")\n      end)\n    end)\n  end\n\n  test \"doesn't compile any path deps if --skip-local-deps is given\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(SuccessfulDepsApp)\n\n      File.rm_rf!(\"_build/dev/lib/ok/ebin\")\n      Mix.Tasks.Deps.Compile.run([\"--skip-local-deps\"])\n      refute File.exists?(\"_build/dev/lib/ok/ebin\")\n    end)\n  end\n\n  test \"checks if local dependencies are available before compiling\" do\n    Mix.Project.push(MissingLocalDepsApp)\n\n    error_message =\n      \"Cannot compile dependency :ok because it isn't available, please ensure the dependency \" <>\n        \"is at \\\"missing/dep\\\"\"\n\n    assert_raise Mix.Error, error_message, fn ->\n      Mix.Tasks.Deps.Compile.run([])\n    end\n  end\n\n  ## deps.loadpaths\n\n  test \"checks list of dependencies and their status with success\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(SuccessfulDepsApp)\n\n      Mix.Tasks.Deps.Loadpaths.run([])\n    end)\n  end\n\n  test \"checks list of dependencies and their status on failure\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DepsApp)\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Deps.Loadpaths.run([])\n      end\n\n      assert_received {:mix_shell, :error, [\"* ok (https://github.com/elixir-lang/ok.git)\"]}\n      msg = \"  the dependency is not available, run \\\"mix deps.get\\\"\"\n      assert_received {:mix_shell, :error, [^msg]}\n\n      assert_received {:mix_shell, :error, [\"* invalidvsn (deps/invalidvsn)\"]}\n      assert_received {:mix_shell, :error, [\"  the app file contains an invalid version: :ok\"]}\n\n      assert_received {:mix_shell, :error, [\"* invalidapp (deps/invalidapp)\"]}\n      msg = \"  the app file at \\\"_build/dev/lib/invalidapp/ebin/invalidapp.app\\\" is invalid\"\n      assert_received {:mix_shell, :error, [^msg]}\n\n      # This one is compiled automatically\n      refute_received {:mix_shell, :error, [\"* noappfile (deps/noappfile)\"]}\n      refute_received {:mix_shell, :error, [\"  could not find an app file at \" <> _]}\n    end)\n  end\n\n  ## deps.unlock\n\n  test \"unlocks all deps\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Dep.Lock.write(%{git_repo: \"abcdef\"})\n      assert Mix.Dep.Lock.read() == %{git_repo: \"abcdef\"}\n      Mix.Tasks.Deps.Unlock.run([\"--all\"])\n      assert Mix.Dep.Lock.read() == %{}\n    end)\n  end\n\n  test \"checks lock file has unused deps with --check-unused\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Dep.Lock.write(%{whatever: \"0.2.0\", something_else: \"1.2.3\", ok: \"0.1.0\"})\n      assert Mix.Dep.Lock.read() == %{whatever: \"0.2.0\", something_else: \"1.2.3\", ok: \"0.1.0\"}\n\n      error = \"\"\"\n      Unused dependencies in mix.lock file:\n\n        * :something_else\n        * :whatever\n      \"\"\"\n\n      assert_raise Mix.Error, error, fn ->\n        Mix.Tasks.Deps.Unlock.run([\"--check-unused\"])\n      end\n\n      assert Mix.Dep.Lock.read() == %{whatever: \"0.2.0\", something_else: \"1.2.3\", ok: \"0.1.0\"}\n\n      Mix.Tasks.Deps.Unlock.run([\"--unused\"])\n      Mix.Tasks.Deps.Unlock.run([\"--check-unused\"])\n      assert Mix.Dep.Lock.read() == %{ok: \"0.1.0\"}\n    end)\n  end\n\n  test \"unlocks unused deps\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Dep.Lock.write(%{whatever: \"abcdef\", ok: \"abcdef\"})\n      assert Mix.Dep.Lock.read() == %{whatever: \"abcdef\", ok: \"abcdef\"}\n      Mix.Tasks.Deps.Unlock.run([\"--unused\"])\n      assert Mix.Dep.Lock.read() == %{ok: \"abcdef\"}\n\n      output = \"\"\"\n      Unlocked deps:\n      * whatever\n      \"\"\"\n\n      assert_received {:mix_shell, :info, [^output]}\n    end)\n  end\n\n  test \"unlocking a dep that is not locked is a no-op\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(DepsApp)\n      Mix.Tasks.Deps.Unlock.run([\"unlocked_dep\"])\n\n      assert_received {:mix_shell, :error, [\"warning: unlocked_dep dependency is not locked\"]}\n      refute_received {:mix_shell, :info, [_]}\n    end)\n  end\n\n  test \"unlocks specific deps\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Dep.Lock.write(%{git_repo: \"abcdef\", another: \"hash\"})\n      Mix.Tasks.Deps.Unlock.run([\"git_repo\", \"unknown\"])\n      assert Mix.Dep.Lock.read() == %{another: \"hash\"}\n      error = \"warning: unknown dependency is not locked\"\n      assert_received {:mix_shell, :error, [^error]}\n\n      output = \"\"\"\n      Unlocked deps:\n      * git_repo\n      \"\"\"\n\n      assert_received {:mix_shell, :info, [^output]}\n    end)\n  end\n\n  test \"unlocks filtered deps\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(DepsApp)\n\n      Mix.Dep.Lock.write(%{git_repo: \"abcdef\", another: \"hash\", another_one: \"hash\"})\n      Mix.Tasks.Deps.Unlock.run([\"--filter\", \"another\"])\n      assert Mix.Dep.Lock.read() == %{git_repo: \"abcdef\"}\n\n      output = \"\"\"\n      Unlocked deps:\n      * another\n      * another_one\n      \"\"\"\n\n      assert_received {:mix_shell, :info, [^output]}\n    end)\n  end\n\n  test \"fails with message on missing dependencies\" do\n    Mix.Project.push(DepsApp)\n\n    assert_raise Mix.Error, ~r/\"mix deps\\.unlock\" expects dependencies as arguments/, fn ->\n      Mix.Tasks.Deps.Unlock.run([])\n    end\n  end\n\n  ## Deps environment\n\n  defmodule CustomDepsEnvApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:raw_repo, \"0.1.0\", path: \"custom/raw_repo\", env: :dev}\n        ]\n      ]\n    end\n  end\n\n  test \"sets deps env to prod by default\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(RawRepoDepApp)\n\n      Mix.Tasks.Deps.Update.run([\"--all\"])\n      assert_received {:mix_shell, :info, [\":raw_repo env is prod\"]}\n    end)\n  end\n\n  test \"can customize environment\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(CustomDepsEnvApp)\n\n      Mix.Tasks.Deps.Update.run([\"--all\"])\n      assert_received {:mix_shell, :info, [\":raw_repo env is dev\"]}\n    end)\n  end\n\n  ## Nested dependencies\n\n  defmodule ConflictDepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:git_repo, \"0.1.0\", path: \"custom/raw_repo\"},\n          {:bad_deps_repo, \"0.1.0\", path: \"custom/bad_deps_repo\"}\n        ]\n      ]\n    end\n  end\n\n  defmodule DivergedDepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n          {:bad_deps_repo, \"0.1.0\", path: \"custom/bad_deps_repo\"}\n        ]\n      ]\n    end\n  end\n\n  defmodule ConvergedDepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:deps_repo, \"0.1.0\", path: \"custom/deps_repo\"},\n          {:git_repo, \">= 0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n        ]\n      ]\n    end\n  end\n\n  defmodule OverriddenDepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:bad_deps_repo, \"0.1.0\", path: \"custom/bad_deps_repo\"},\n          {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\"), override: true}\n        ]\n      ]\n    end\n  end\n\n  defmodule NonOverriddenDepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:bad_deps_repo, \"0.1.0\", path: \"custom/bad_deps_repo\"},\n          {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n        ]\n      ]\n    end\n  end\n\n  test \"fails on missing dependencies\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(SuccessfulDepsApp)\n\n      assert_raise Mix.Error, ~r/Unknown dependency invalid for environment dev/, fn ->\n        Mix.Tasks.Deps.Update.run([\"invalid\"])\n      end\n    end)\n  end\n\n  @overriding_msg \"  the dependency git_repo in mix.exs is overriding a child dependency\"\n\n  test \"fails on diverged dependencies on get/update\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(ConflictDepsApp, \"mix.exs\")\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Deps.Loadpaths.run([])\n      end\n\n      assert_received {:mix_shell, :error, [@overriding_msg <> _]}\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Deps.Get.run([])\n      end\n\n      assert_received {:mix_shell, :error, [@overriding_msg <> _]}\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Deps.Update.run([\"--all\"])\n      end\n\n      assert_received {:mix_shell, :error, [@overriding_msg <> _]}\n    end)\n  end\n\n  test \"fails on diverged dependencies on check\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(DivergedDepsApp)\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Deps.Loadpaths.run([])\n      end\n\n      assert_received {:mix_shell, :error, [\"  different specs were given\" <> _ = received_msg]}\n      assert received_msg =~ \"In custom/deps_repo/mix.exs:\"\n\n      assert received_msg =~\n               \"{:git_repo, \\\"0.1.0\\\", [env: :prod, git: #{inspect(fixture_path(\"git_repo\"))}]}\"\n    end)\n  end\n\n  test \"fails on diverged dependencies by requirement\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(ConvergedDepsApp)\n\n      File.write!(\"custom/deps_repo/mix.exs\", \"\"\"\n      defmodule DepsRepo do\n        use Mix.Project\n\n        def project do\n          [\n            app: :deps_repo,\n            version: \"0.1.0\",\n            deps: [\n              {:git_repo, \"0.2.0\", git: MixTest.Case.fixture_path(\"git_repo\")}\n            ]\n          ]\n        end\n      end\n      \"\"\")\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Deps.Get.run([])\n        Mix.Tasks.Deps.Loadpaths.run([])\n      end\n\n      assert_received {:mix_shell, :error, [\"  the dependency git_repo 0.1.0\" <> _ = msg]}\n      assert msg =~ \"In custom/deps_repo/mix.exs:\"\n\n      assert msg =~\n               \"{:git_repo, \\\"0.2.0\\\", [env: :prod, git: #{inspect(fixture_path(\"git_repo\"))}]}\"\n    end)\n  end\n\n  @overriding_msg \"  the dependency git_repo in custom/deps_repo/mix.exs is overriding\"\n\n  test \"fails on diverged dependencies even when optional\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(ConvergedDepsApp, \"custom/deps_repo/mix.exs\")\n\n      File.write!(\"custom/deps_repo/mix.exs\", \"\"\"\n      defmodule DepsRepo do\n        use Mix.Project\n\n        def project do\n          [\n            app: :deps_repo,\n            version: \"0.1.0\",\n            deps: [\n              {:git_repo, git: MixTest.Case.fixture_path(\"bad_git_repo\"), branch: \"omg\"}\n            ]\n          ]\n        end\n      end\n      \"\"\")\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Deps.Get.run([])\n        Mix.Tasks.Deps.Loadpaths.run([])\n      end\n\n      assert_received {:mix_shell, :error, [@overriding_msg <> _]}\n    end)\n  end\n\n  test \"works with converged dependencies\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(ConvergedDepsApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      # Make sure retriever uses converger,\n      # so the message appears just once\n      refute_received {:mix_shell, :info, [^message]}\n\n      Mix.Task.clear()\n      Mix.Tasks.Deps.Update.run([\"--all\"])\n\n      message = \"* Updating git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"does not check dependencies if --no-deps-check is provided\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(SuccessfulDepsApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      File.rm_rf!(\"deps/ok\")\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Compile.run([])\n      end\n\n      Mix.Tasks.Compile.run([\"--no-deps-check\"])\n    end)\n  end\n\n  test \"works with overridden dependencies\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(OverriddenDepsApp)\n\n      Mix.Tasks.Deps.Get.run([])\n      message = \"* Getting git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      # Make sure retriever uses converger,\n      # so the message appears just once\n      refute_received {:mix_shell, :info, [^message]}\n\n      Mix.Task.clear()\n      Mix.Tasks.Deps.Update.run([\"--all\"])\n\n      message = \"* Updating git_repo (#{fixture_path(\"git_repo\")})\"\n      assert_received {:mix_shell, :info, [^message]}\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"converged dependencies errors if not overriding\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(NonOverriddenDepsApp, \"custom_mix.exs\")\n\n      assert_raise Mix.Error, fn ->\n        Mix.Tasks.Deps.Loadpaths.run([])\n      end\n\n      receive do\n        {:mix_shell, :error, [\"  the dependency git_repo in custom_mix.exs\" <> _ = msg]} ->\n          assert msg =~ \"In custom_mix.exs:\"\n\n          assert msg =~\n                   \"{:git_repo, \\\"0.1.0\\\", [env: :prod, git: #{inspect(fixture_path(\"git_repo\"))}]}\"\n      after\n        0 -> flunk(\"expected overriding error message\")\n      end\n    end)\n  after\n    purge([GitRepo, GitRepo.MixProject])\n  end\n\n  test \"checks if dependencies are using old Elixir version\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(SuccessfulDepsApp)\n\n      Mix.Tasks.Deps.Compile.run([])\n      Mix.Tasks.Deps.Loadpaths.run([])\n\n      File.mkdir_p!(\"_build/dev/lib/ok/ebin\")\n      File.mkdir_p!(\"_build/dev/lib/ok/.mix\")\n      manifest_data = :erlang.term_to_binary({:v1, \"the_future\", :scm})\n      File.write!(\"_build/dev/lib/ok/.mix/compile.elixir_scm\", manifest_data)\n      Mix.Task.clear()\n\n      msg =\n        \"  the dependency was built with an out-of-date Erlang/Elixir version, run \\\"mix deps.compile\\\"\"\n\n      Mix.Tasks.Deps.run([])\n      assert_received {:mix_shell, :info, [^msg]}\n\n      # deps.loadpaths will automatically recompile it\n      Mix.Tasks.Deps.Loadpaths.run([])\n\n      Mix.Tasks.Deps.run([])\n      refute_received {:mix_shell, :info, [^msg]}\n    end)\n  end\n\n  test \"checks if dependencies are using old scm version\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(SuccessfulDepsApp)\n\n      Mix.Tasks.Deps.Compile.run([])\n      Mix.Tasks.Deps.Loadpaths.run([])\n\n      File.mkdir_p!(\"_build/dev/lib/ok/ebin\")\n      File.mkdir_p!(\"_build/dev/lib/ok/.mix\")\n\n      manifest_data =\n        :erlang.term_to_binary(\n          {2, {System.version(), :erlang.system_info(:otp_release)}, :scm, nil}\n        )\n\n      File.write!(\"_build/dev/lib/ok/.mix/compile.elixir_scm\", manifest_data)\n      Mix.Task.clear()\n\n      msg = \"  the dependency was built with another SCM, run \\\"mix deps.compile\\\"\"\n      Mix.Tasks.Deps.run([])\n      assert_received {:mix_shell, :info, [^msg]}\n\n      # deps.loadpaths will automatically recompile it\n      Mix.Tasks.Deps.Loadpaths.run([])\n\n      Mix.Tasks.Deps.run([])\n      refute_received {:mix_shell, :info, [^msg]}\n    end)\n  end\n\n  test \"checks if compile env changed\" do\n    in_fixture(\"deps_status\", fn ->\n      # Write another file, it should not be recompiled upon compiled env change.\n      File.write!(\"custom/raw_repo/lib/foo.ex\", \"\"\"\n      defmodule RawRepo.Foo do\n      end\n      \"\"\")\n\n      Mix.Project.push(RawRepoDepApp)\n      Mix.Tasks.Deps.Loadpaths.run([])\n      assert_receive {:mix_shell, :info, [\"Compiling 2 files (.ex)\"]}\n      assert_receive {:mix_shell, :info, [\"Generated raw_repo app\"]}\n      assert Application.spec(:raw_repo, :vsn)\n\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/config.exs\", \"\"\"\n      import Config\n      config :anyapp, :anything, :anyvalue\n      \"\"\")\n\n      Application.unload(:raw_repo)\n      Mix.ProjectStack.pop()\n      Mix.Task.clear()\n      Mix.Project.push(RawRepoDepApp)\n      purge([RawRepo])\n      Mix.Tasks.Loadconfig.load_compile(\"config/config.exs\")\n\n      Mix.Tasks.Deps.run([])\n\n      assert_receive {:mix_shell, :info,\n                      [\n                        \"  the dependency compile environment is outdated, please run \\\"mix deps.compile\\\"\"\n                      ]}\n\n      Mix.shell().flush()\n\n      Mix.Tasks.Deps.Loadpaths.run([])\n\n      assert_receive {:mix_shell, :info, [\"Compiling 1 file (.ex)\"]}\n      assert_receive {:mix_shell, :info, [\"Generated raw_repo app\"]}\n      assert Application.spec(:raw_repo, :vsn)\n    end)\n  after\n    Application.delete_env(:raw_repo, :compile_env, persistent: true)\n  end\n\n  test \"does not compile deps that have explicit option\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.ProjectStack.post_config(\n        deps: [\n          {:git_repo, \"0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\"), compile: false}\n        ]\n      )\n\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Tasks.Deps.Compile.run([])\n      refute_received {:mix_shell, :info, [\"==> git_repo\"]}\n    end)\n  end\n\n  test \"warns and converges duplicated deps at the same level\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.ProjectStack.post_config(\n        deps: [\n          # Simulate dependencies gathered together from umbrella\n          {:ok, \"0.1.0\", path: \"deps/ok\"},\n          {:ok, \"0.1.0\", path: \"deps/ok\"}\n        ]\n      )\n\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Tasks.Deps.run([])\n\n      msg =\n        \"warning: the dependency :ok is duplicated at the top level, please remove one of them\"\n\n      assert_received {:mix_shell, :error, [^msg]}\n\n      msg = \"* ok 0.1.0 (deps/ok) (mix)\"\n      assert_received {:mix_shell, :info, [^msg]}\n      refute_received {:mix_shell, :info, [^msg]}\n    end)\n  end\n\n  test \"warns when project app name matches a dependency\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.ProjectStack.post_config(\n        app: :ok,\n        deps: [{:ok, \"0.1.0\", path: \"deps/ok\"}]\n      )\n\n      Mix.Project.push(MixTest.Case.Sample)\n      Mix.Tasks.Deps.Get.run([])\n\n      msg =\n        \"warning: the application name :ok is the same as one of its dependencies\"\n\n      assert_received {:mix_shell, :error, [^msg]}\n    end)\n  end\n\n  ## deps.clean\n\n  defmodule CleanDepsApp do\n    def project do\n      [\n        app: :raw_sample,\n        version: \"0.1.0\",\n        deps: [\n          {:git_repo, \">= 0.1.0\", git: MixTest.Case.fixture_path(\"git_repo\")},\n          {:ok, \">= 2.0.0\", path: \"deps/ok\"}\n        ]\n      ]\n    end\n  end\n\n  test \"cleans dependencies\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(CleanDepsApp)\n\n      File.mkdir_p!(\"_build/dev/lib/raw_sample\")\n      File.mkdir_p!(\"_build/dev/lib/git_repo\")\n      File.mkdir_p!(\"_build/test/lib/git_repo\")\n      File.mkdir_p!(\"_build/dev/lib/ok\")\n      File.mkdir_p!(\"_build/test/lib/ok\")\n\n      message =\n        \"\\\"mix deps.clean\\\" expects dependencies as arguments or \" <>\n          \"an option indicating which dependencies to clean. \" <>\n          \"The --all option will clean all dependencies while \" <>\n          \"the --unused option cleans unused dependencies\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Deps.Clean.run([])\n      end\n\n      Mix.Tasks.Deps.Clean.run([\"--only\", \"dev\", \"--all\"])\n      refute File.exists?(\"_build/dev/lib/git_repo\")\n      refute File.exists?(\"_build/dev/lib/ok\")\n      assert File.exists?(\"_build/test/lib/git_repo\")\n      assert File.exists?(\"_build/dev/lib/raw_sample\")\n\n      Mix.Tasks.Deps.Clean.run([\"--all\"])\n      refute File.exists?(\"_build/dev/lib/git_repo\")\n      refute File.exists?(\"_build/test/lib/git_repo\")\n      assert File.exists?(\"_build/dev/lib/raw_sample\")\n    end)\n  end\n\n  test \"cleans unused dependencies\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(CleanDepsApp)\n\n      File.mkdir_p!(\"_build/dev/lib/raw_sample\")\n      File.mkdir_p!(\"deps/git_repo\")\n      File.mkdir_p!(\"_build/dev/lib/git_repo\")\n      File.mkdir_p!(\"deps/git_repo_unused\")\n      File.mkdir_p!(\"_build/dev/lib/git_repo_unused\")\n\n      Mix.Tasks.Deps.Clean.run([\"--unused\"])\n      assert File.exists?(\"deps/git_repo\")\n      assert File.exists?(\"_build/dev/lib/git_repo\")\n      refute File.exists?(\"deps/git_repo_unused\")\n      refute File.exists?(\"_build/dev/lib/git_repo_unused\")\n      assert File.exists?(\"_build/dev/lib/raw_sample\")\n    end)\n  end\n\n  test \"cleans dependencies build\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(CleanDepsApp)\n\n      File.mkdir_p!(\"deps/raw_sample\")\n      File.mkdir_p!(\"_build/dev/lib/raw_sample\")\n\n      Mix.Tasks.Deps.Clean.run([\"raw_sample\", \"--build\"])\n      assert File.exists?(\"deps/raw_sample\")\n      refute File.exists?(\"_build/dev/lib/raw_sample\")\n    end)\n  end\n\n  test \"warns on invalid path on clean dependencies\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(CleanDepsApp)\n\n      File.mkdir_p!(\"deps/raw_sample\")\n      File.mkdir_p!(\"_build/dev/lib/raw_sample\")\n\n      Mix.Tasks.Deps.Clean.run([\"raw_sample_with_a_typo\"])\n      assert File.exists?(\"deps/raw_sample\")\n\n      msg = \"warning: the dependency raw_sample_with_a_typo is not present in the build directory\"\n      assert_received {:mix_shell, :error, [^msg]}\n    end)\n  end\n\n  test \"does not remove dependency source when using :path\" do\n    in_fixture(\"deps_status\", fn ->\n      Mix.Project.push(CleanDepsApp)\n\n      assert File.exists?(\"deps/ok\")\n\n      Mix.Tasks.Deps.Clean.run([\"raw_sample\", \"--all\"])\n      refute File.exists?(\"_build/dev/lib/ok\")\n      refute File.exists?(\"_build/test/lib/ok\")\n      assert File.exists?(\"deps/ok\")\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/do_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.DoTest do\n  use MixTest.Case\n\n  import Mix.Tasks.Do, only: [gather_commands: 1]\n\n  test \"runs given tasks\", context do\n    in_tmp(context.test, fn ->\n      Mix.Tasks.Do.run([\"compile\", \"--list\", \"+\", \"help\"])\n      assert_received {:mix_shell, :info, [\"mix help\" <> _]}\n      assert_received {:mix_shell, :info, [\"mix compile.app\" <> _]}\n    end)\n  end\n\n  test \"raises if a task is empty\" do\n    for args <- [~w(), ~w(+), ~w(help +), ~w(+ help)] do\n      assert_raise Mix.Error, ~r\"^One of the commands passed to \\\"mix do\\\" is empty\", fn ->\n        Mix.Tasks.Do.run(args)\n      end\n    end\n  end\n\n  test \"gather_command returns a list of commands\" do\n    assert gather_commands([\"help\", \"+\", \"compile\"]) ==\n             [[\"help\"], [\"compile\"]]\n\n    assert gather_commands([\"help\", \"+\", \"compile\", \"--list\"]) ==\n             [[\"help\"], [\"compile\", \"--list\"]]\n\n    assert gather_commands([\"help\", \"--list\", \"+\", \"compile\", \"--list\"]) ==\n             [[\"help\", \"--list\"], [\"compile\", \"--list\"]]\n  end\n\n  test \"gather_command supports deprecated comma commands\" do\n    ExUnit.CaptureIO.capture_io(:stderr, fn ->\n      assert gather_commands([\"compile\", \"--list,\", \"help\"]) == [[\"compile\", \"--list\"], [\"help\"]]\n      assert gather_commands([\"help,\", \"compile\", \"--list\"]) == [[\"help\"], [\"compile\", \"--list\"]]\n\n      assert gather_commands([\"compile,\", \"run\", \"-e\", \"IO.puts :hello\"]) ==\n               [[\"compile\"], [\"run\", \"-e\", \"IO.puts :hello\"]]\n\n      assert gather_commands([\"compile,\", \"run\", \"-e\", \"[1, 2]\"]) ==\n               [[\"compile\"], [\"run\", \"-e\", \"[1, 2]\"]]\n\n      assert gather_commands([\"test\", \",\", \"help\"]) == [[\"test\"], [\"help\"]]\n    end)\n  end\n\n  test \"runs given tasks for a single app specified by app flag\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Tasks.Do.run(~w(--app bar compile --list + cmd echo hello))\n\n        assert_received {:mix_shell, :info, [\"==> bar\"]}\n        assert_received {:mix_shell, :run, [\"hello\\n\"]}\n        refute_received {:mix_shell, :info, [\"==> foo\"]}\n        refute_received {:mix_shell, :run, [\"hello\\n\"]}\n      end)\n    end)\n  end\n\n  test \"runs given tasks for each app specified by app flag\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Tasks.Do.run(~w(--app bar --app foo compile --list + cmd echo hello))\n\n        assert_received {:mix_shell, :info, [\"==> bar\"]}\n        assert_received {:mix_shell, :run, [\"hello\\n\"]}\n        assert_received {:mix_shell, :info, [\"==> foo\"]}\n        assert_received {:mix_shell, :run, [\"hello\\n\"]}\n      end)\n    end)\n  end\n\n  test \"runs non-recursive tasks at project root level\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Tasks.Do.run(~w(--app bar --app foo compile --list + help))\n\n        assert_received {:mix_shell, :info, [\"mix help\" <> _]}\n        assert_received {:mix_shell, :info, [\"mix compile.app\" <> _]}\n      end)\n    end)\n  end\n\n  test \"raises when -app is given but the project is not an umbrella\" do\n    assert_raise Mix.Error,\n                 \"Could not run \\\"cmd\\\" with the --app option because this is not an umbrella project\",\n                 fn ->\n                   Mix.Tasks.Do.run(~w(--app bar --app foo cmd echo hello))\n                 end\n  end\n\n  test \"runs given aliases for each app specified by app flag\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      aliases = [\n        e: [\"cmd echo hello\"],\n        p: fn val -> Mix.shell().info(inspect(val)) end\n      ]\n\n      Mix.Project.in_project(:umbrella, \".\", [aliases: aliases], fn _ ->\n        Mix.Tasks.Do.run([\"compile\"])\n        Mix.Tasks.Do.run([\"--app\", \"bar\", \"--app\", \"foo\", \"e\", \"+\", \"p\", \"Foo\"])\n\n        assert_received {:mix_shell, :info, [\"==> bar\"]}\n        assert_received {:mix_shell, :run, [\"hello\\n\"]}\n        assert_received {:mix_shell, :info, [\"[\\\"Foo\\\"]\"]}\n\n        assert_received {:mix_shell, :info, [\"==> foo\"]}\n        assert_received {:mix_shell, :run, [\"hello\\n\"]}\n        assert_received {:mix_shell, :info, [\"[\\\"Foo\\\"]\"]}\n      end)\n    end)\n  end\n\n  test \"runs non-recursive aliases at project root level\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      aliases = [\n        h: \"help\"\n      ]\n\n      Mix.Project.in_project(:umbrella, \".\", [aliases: aliases], fn _ ->\n        Mix.Tasks.Do.run([\"--app\", \"bar\", \"--app\", \"foo\", \"h\"])\n\n        assert_received {:mix_shell, :info, [\"mix help\" <> _]}\n      end)\n    end)\n  end\n\n  test \"raise with aliases when -app is given but the project is not an umbrella\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      aliases = [\n        e: [\"cmd echo hello\"],\n        p: fn val -> Mix.shell().info(inspect(val)) end\n      ]\n\n      Mix.Project.in_project(:foo, \"apps/foo\", [aliases: aliases], fn _ ->\n        assert_raise Mix.Error,\n                     \"Could not run \\\"e\\\" with the --app option because this is not an umbrella project\",\n                     fn ->\n                       Mix.Tasks.Do.run(~w(--app bar --app foo e + p Foo))\n                     end\n      end)\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/escript_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.EscriptTest do\n  use MixTest.Case\n\n  defmodule Escript do\n    def project do\n      [\n        app: :escript_test,\n        version: \"0.0.1\",\n        escript: [main_module: EscriptTest, name: \"escript_test\", embed_elixir: true]\n      ]\n    end\n  end\n\n  defmodule EscriptErlangWithDeps do\n    def project do\n      [\n        app: :escript_test,\n        version: \"0.0.1\",\n        language: :erlang,\n        escript: [main_module: :escript_test],\n        deps: [{:ok, path: fixture_path(\"deps_status/deps/ok\")}]\n      ]\n    end\n\n    def application do\n      [applications: [], extra_applications: [:crypto, elixir: :optional]]\n    end\n  end\n\n  test \"generate escript\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript)\n\n      Mix.Tasks.Escript.Build.run([])\n      assert_received {:mix_shell, :info, [\"Generated escript escript_test with MIX_ENV=dev\"]}\n      assert System.cmd(\"escript\", [\"escript_test\"]) == {\"TEST\\n\", 0}\n      assert count_abstract_code(\"escript_test\") == 0\n\n      # Consolidates protocols\n      assert System.cmd(\"escript\", [\"escript_test\", \"--protocol\", \"Enumerable\"]) == {\"true\\n\", 0}\n\n      # Each app has a distinct, valid path\n      assert System.cmd(\"escript\", [\"escript_test\", \"--app-paths\"]) == {\"{true, true, true}\\n\", 0}\n\n      # Does not include priv by default\n      assert System.cmd(\"escript\", [\"escript_test\", \"--list-priv\", \"escript_test\"]) ==\n               {\":error\\n\", 0}\n    end)\n  end\n\n  test \"generate escript without protocol consolidation\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript, consolidate_protocols: false)\n\n      Mix.Tasks.Escript.Build.run([])\n      assert_received {:mix_shell, :info, [\"Generated escript escript_test with MIX_ENV=dev\"]}\n      assert System.cmd(\"escript\", [\"escript_test\"]) == {\"TEST\\n\", 0}\n      assert count_abstract_code(\"escript_test\") == 0\n\n      # Does not consolidate protocols\n      assert System.cmd(\"escript\", [\"escript_test\", \"--protocol\", \"Enumerable\"]) == {\"false\\n\", 0}\n    end)\n  end\n\n  test \"generate escript with --no-compile option\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript)\n\n      Mix.Tasks.Compile.run([])\n      purge([EscriptTest])\n\n      Mix.Tasks.Escript.Build.run([\"--no-compile\"])\n      assert_received {:mix_shell, :info, [\"Generated escript escript_test with MIX_ENV=dev\"]}\n    end)\n  end\n\n  test \"generate escript with compile config\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript)\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/config.exs\", ~S\"\"\"\n      import Config\n      config :foobar, :value, \"COMPILE #{config_env()} TARGET #{config_target()}\"\n      \"\"\")\n\n      Mix.Tasks.Escript.Build.run([])\n      assert_received {:mix_shell, :info, [\"Generated escript escript_test with MIX_ENV=dev\"]}\n\n      assert System.cmd(\"escript\", [\"escript_test\"]) == {\"COMPILE dev TARGET host\\n\", 0}\n    end)\n  end\n\n  test \"generate escript with runtime config\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript)\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/config.exs\", \"\"\"\n      [foobar: [value: \"OLD\", nesting: [config: true, runtime: false]]]\n      \"\"\")\n\n      File.write!(\"config/runtime.exs\", ~S\"\"\"\n      import Config\n      config :foobar, :value, \"RUNTIME #{config_env()} TARGET #{config_target()} ARGV #{System.argv()}\"\n      config :foobar, :nesting, runtime: true\n      \"\"\")\n\n      Mix.Tasks.Escript.Build.run([])\n      assert_received {:mix_shell, :info, [\"Generated escript escript_test with MIX_ENV=dev\"]}\n\n      assert System.cmd(\"escript\", [\"escript_test\", \"--foo\", \"--bar\"]) ==\n               {\"RUNTIME dev TARGET host ARGV --foo--bar\\n\", 0}\n\n      assert System.cmd(\"escript\", [\"escript_test\", \"--nesting\"]) ==\n               {\"[config: true, runtime: true]\\n\", 0}\n    end)\n  end\n\n  test \"generate escript with debug information\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript, escript: [main_module: EscriptTest, strip_beams: false])\n      Mix.Tasks.Escript.Build.run([])\n\n      msg = \"Generated escript escript_test with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^msg]}\n\n      assert System.cmd(\"escript\", [\"escript_test\"]) == {\"TEST\\n\", 0}\n      assert count_abstract_code(\"escript_test\") > 0\n    end)\n  end\n\n  defp count_abstract_code(escript_filename) do\n    escript_filename\n    |> read_beams()\n    |> Enum.count(fn {_, beam} -> get_abstract_code(beam) end)\n  end\n\n  defp read_beams(escript_filename) do\n    # :zip.unzip/2 cannot unzip an escript unless we remove the escript header\n    zip_data = remove_escript_header(File.read!(escript_filename))\n    {:ok, tuples} = :zip.unzip(zip_data, [:memory])\n\n    for {filename, beam} <- tuples, Path.extname(filename) == \".beam\" do\n      {filename, beam}\n    end\n  end\n\n  defp remove_escript_header(escript_data) do\n    {offset, _length} = :binary.match(escript_data, \"\\nPK\")\n    zip_start = offset + 1\n    binary_part(escript_data, zip_start, byte_size(escript_data) - zip_start)\n  end\n\n  defp get_abstract_code(beam) do\n    case :beam_lib.chunks(beam, [:abstract_code]) do\n      {:ok, {_, [{:abstract_code, {_, abstract_code}}]}} -> abstract_code\n      _ -> nil\n    end\n  end\n\n  test \"generate escript with path\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript,\n        escript: [\n          app: nil,\n          embed_elixir: true,\n          main_module: EscriptTest,\n          path: Path.join(\"ebin\", \"escript_test\")\n        ]\n      )\n\n      Mix.Tasks.Escript.Build.run([])\n\n      message = \"Generated escript ebin/escript_test with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      assert System.cmd(\"escript\", [\"ebin/escript_test\"]) == {\"TEST\\n\", 0}\n    end)\n  end\n\n  test \"generate escript with deps\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript,\n        escript: [main_module: EscriptTest],\n        deps: [{:ok, path: fixture_path(\"deps_status/deps/ok\")}]\n      )\n\n      Mix.Tasks.Escript.Build.run([])\n\n      message = \"Generated escript escript_test with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      assert System.cmd(\"escript\", [\"escript_test\"]) == {\"TEST\\n\", 0}\n\n      # Does not include priv for deps by default\n      assert System.cmd(\"escript\", [\"escript_test\", \"--list-priv\", \"ok\"]) == {\":error\\n\", 0}\n    end)\n  after\n    purge([Ok.MixProject])\n  end\n\n  test \"generate escript with Erlang and deps\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(EscriptErlangWithDeps)\n      Mix.Tasks.Escript.Build.run([])\n\n      message = \"Generated escript escript_test with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      assert System.cmd(\"escript\", [\"escript_test\", \"arg1\", \"arg2\"]) ==\n               {~s([\"arg1\",\"arg2\"]), 0}\n    end)\n  after\n    purge([Ok.MixProject])\n  end\n\n  test \"generate escript with Erlang main module\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript, escript: [main_module: :escript_test])\n\n      Mix.Tasks.Escript.Build.run([])\n\n      message = \"Generated escript escript_test with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      assert System.cmd(\"escript\", [\"escript_test\", \"arg1\", \"arg2\"]) ==\n               {~s([<<\"arg1\">>,<<\"arg2\">>]), 0}\n    end)\n  after\n    purge([Ok.MixProject])\n  end\n\n  test \"generate escript with priv\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript,\n        escript: [main_module: EscriptTest, include_priv_for: [:escript_test, :ok]],\n        deps: [{:ok, path: fixture_path(\"deps_status/deps/ok\")}]\n      )\n\n      Mix.Tasks.Escript.Build.run([])\n\n      message = \"Generated escript escript_test with MIX_ENV=dev\"\n      assert_received {:mix_shell, :info, [^message]}\n\n      assert System.cmd(\"escript\", [\"escript_test\", \"--list-priv\", \"escript_test\"]) ==\n               {~s/{:ok, [~c\"hello\"]}\\n/, 0}\n\n      assert System.cmd(\"escript\", [\"escript_test\", \"--list-priv\", \"ok\"]) ==\n               {~s/{:ok, [~c\"sample\"]}\\n/, 0}\n    end)\n  end\n\n  test \"escript install and uninstall\" do\n    escripts = tmp_path(\".mix/escripts\")\n    File.rm_rf!(escripts)\n\n    # Configuration in the parent should not impact the escript\n    in_tmp(\"config\", fn ->\n      File.mkdir_p!(\"config\")\n\n      File.write!(\"config/config.exs\", ~S\"\"\"\n      import Config\n      config :foobar, :parent, \"SET_ON_PARENT\"\n      \"\"\")\n\n      Mix.Tasks.Loadconfig.run([])\n    end)\n\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript)\n\n      # check that no escripts are installed\n      Mix.Tasks.Escript.run([])\n      assert_received {:mix_shell, :info, [\"No escripts currently installed.\"]}\n\n      # build and install our escript\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Escript.Install.run([])\n\n      # execute the script\n      assert System.cmd(\"escript\", [Path.join(escripts, \"escript_test\"), \"--config\"]) ==\n               {\"VALUE=TEST\\nPARENT=NIL\\n\", 0}\n\n      # check that it shows in the list\n      Mix.Tasks.Escript.run([])\n      assert_received {:mix_shell, :info, [\"* escript_test\"]}\n      refute_received {:mix_shell, :info, [\"* escript_test.bat\"]}\n\n      # check uninstall confirmation\n      send(self(), {:mix_shell_input, :yes?, false})\n      Mix.Tasks.Escript.Uninstall.run([\"escript_test\"])\n      assert File.regular?(tmp_path(\".mix/escripts/escript_test\"))\n\n      # uninstall the escript\n      send(self(), {:mix_shell_input, :yes?, true})\n      Mix.Tasks.Escript.Uninstall.run([\"escript_test\"])\n      refute File.regular?(tmp_path(\".mix/escripts/escript_test\"))\n      refute File.regular?(tmp_path(\".mix/escripts/escript_test.bat\"))\n\n      # check that no escripts remain\n      Mix.Tasks.Escript.run([])\n      assert_received {:mix_shell, :info, [\"No escripts currently installed.\"]}\n    end)\n  end\n\n  test \"escript install and uninstall --force\" do\n    File.rm_rf!(tmp_path(\".mix/escripts\"))\n\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript)\n\n      Mix.Tasks.Escript.Install.run([\"--force\"])\n\n      # check that it shows in the list\n      Mix.Tasks.Escript.run([])\n      assert_received {:mix_shell, :info, [\"* escript_test\"]}\n      refute_received {:mix_shell, :info, [\"* escript_test.bat\"]}\n\n      # uninstall the escript\n      Mix.Tasks.Escript.Uninstall.run([\"escript_test\", \"--force\"])\n\n      # check that no escripts remain\n      Mix.Tasks.Escript.run([])\n      assert_received {:mix_shell, :info, [\"No escripts currently installed.\"]}\n    end)\n  end\n\n  test \"escript invalid install\" do\n    # Install our escript\n    send(self(), {:mix_shell_input, :yes?, true})\n    message = \"The given path does not point to an escript, installation aborted\"\n\n    assert_raise Mix.Error, message, fn ->\n      Mix.Tasks.Escript.Install.run([__ENV__.file])\n    end\n  end\n\n  test \"escript invalid main module\" do\n    in_fixture(\"escript_test\", fn ->\n      push_project_with_config(Escript, escript: [main_module: BogusEscriptTest])\n\n      message =\n        \"Could not generate escript, module Elixir.BogusEscriptTest defined as :main_module could not be loaded\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Escript.Build.run([])\n      end\n    end)\n  end\n\n  for count <- [1, 2] do\n    test \"escript.install from Git (with MIX_OS_DEPS_COMPILE_PARTITION_COUNT=#{count})\" do\n      System.put_env(\"MIX_OS_DEPS_COMPILE_PARTITION_COUNT\", \"#{unquote(count)}\")\n\n      in_fixture(\"deps_status\", fn ->\n        File.mkdir_p!(\"config\")\n        File.mkdir_p!(\"lib\")\n\n        File.write!(\"config/config.exs\", \"\"\"\n        import Config\n        config :source_repo, :escript_config, true\n        \"\"\")\n\n        File.write!(\"lib/source_repo.ex\", \"\"\"\n        require Application\n        true = Application.compile_env!(:source_repo, :escript_config)\n\n        defmodule SourceRepo.Escript do\n          def main(_argv) do\n            IO.puts(\"TEST\")\n          end\n        end\n        \"\"\")\n\n        File.write!(\"mix.exs\", \"\"\"\n        defmodule SourceRepo.MixProject do\n          use Mix.Project\n\n          def project do\n            [\n              app: :source_repo,\n              version: \"0.1.0\",\n              escript: [main_module: SourceRepo.Escript],\n              deps: [\n                {:git_repo, path: \"#{MixTest.Case.fixture_path(\"git_repo\")}\"},\n                {:git_rebar, path: \"#{MixTest.Case.fixture_path(\"git_rebar\")}\", manager: :rebar3},\n                {:ok, path: \"deps/ok\"},\n              ]\n            ]\n          end\n        end\n        \"\"\")\n\n        System.cmd(\"git\", ~w[init])\n        System.cmd(\"git\", ~w[add .])\n        System.cmd(\"git\", ~w[commit -m \"ok\"])\n\n        ExUnit.CaptureIO.capture_io(fn ->\n          send(self(), {:mix_shell_input, :yes?, true})\n          Mix.Tasks.Escript.Install.run([\"git\", File.cwd!()])\n        end)\n\n        assert_received {:mix_shell, :info, [\"Generated escript source_repo with MIX_ENV=prod\"]}\n\n        escript_path = Path.join([tmp_path(\".mix\"), \"escripts\", \"source_repo\"])\n        assert System.cmd(\"escript\", [escript_path]) == {\"TEST\\n\", 0}\n      end)\n    after\n      System.delete_env(\"MIX_OS_DEPS_COMPILE_PARTITION_COUNT\")\n      purge([GitRepo, SourceRepo.Escript, SourceRepo.MixProject, Mix.Local.Installer.MixProject])\n    end\n  end\n\n  defp push_project_with_config(module, config \\\\ []) do\n    Mix.ProjectStack.post_config(config)\n    Mix.Project.push(module)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/eval_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.EvalTest do\n  use MixTest.Case\n\n  setup do\n    Mix.Project.push(MixTest.Case.Sample)\n  end\n\n  test \"does not start applications\", context do\n    in_tmp(context.test, fn ->\n      expr = \"send self(), {:apps, Application.started_applications()}\"\n      Mix.Tasks.Eval.run([expr])\n      assert_received {:apps, apps}\n      refute List.keyfind(apps, :sample, 0)\n    end)\n  end\n\n  test \"runs multiple commands\", context do\n    in_tmp(context.test, fn ->\n      Mix.Tasks.Eval.run([\"send self(), {:eval, :foo}\"])\n      assert_received {:eval, :foo}\n\n      Mix.Tasks.Eval.run([\"send self(), {:eval, :bar}\"])\n      assert_received {:eval, :bar}\n    end)\n  end\n\n  test \"accepts arguments\", context do\n    in_tmp(context.test, fn ->\n      Mix.Tasks.Eval.run([\"send self(), {:argv, System.argv()}\", \"bar\", \"baz\"])\n      assert_received {:argv, ~w[bar baz]}\n    end)\n  end\n\n  test \"resets argv to previous value\", context do\n    argv = System.argv()\n\n    try do\n      in_tmp(context.test, fn ->\n        System.argv([\"foo\"])\n\n        Mix.Tasks.Eval.run([\"send self(), {:argv, System.argv()}\", \"bar\", \"baz\"])\n        assert_received {:argv, ~w[bar baz]}\n\n        assert [\"foo\"] == System.argv()\n      end)\n    after\n      System.argv(argv)\n    end\n  end\n\n  test \"runs without mix.exs\" do\n    Mix.Project.pop()\n\n    assert_raise Mix.Error, ~r/Cannot execute \"mix eval\" without a Mix.Project/, fn ->\n      Mix.Tasks.Eval.run([\"send self(), {:eval, :foo}\"])\n    end\n\n    Mix.Tasks.Eval.run([\"--no-mix-exs\", \"send self(), {:eval, :foo}\"])\n    assert_received {:eval, :foo}\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/format_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.FormatTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n\n  defmodule FormatWithDepsApp do\n    def project do\n      [\n        app: :format_with_deps,\n        version: \"0.1.0\",\n        deps: [{:my_dep, \"0.1.0\", path: \"deps/my_dep\"}]\n      ]\n    end\n  end\n\n  test \"doesn't format empty files into line breaks\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.exs\", \"\")\n      Mix.Tasks.Format.run([\"a.exs\"])\n      assert File.read!(\"a.exs\") == \"\"\n\n      File.write!(\"b.exs\", \"  \\n  \\n\")\n      Mix.Tasks.Format.run([\"b.exs\"])\n      assert File.read!(\"b.exs\") == \"\"\n    end)\n  end\n\n  test \"formats the given files\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      Mix.Tasks.Format.run([\"a.ex\"])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo(bar)\n             \"\"\"\n    end)\n  end\n\n  test \"formats the given pattern\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      Mix.Tasks.Format.run([\"*.ex\", \"a.ex\"])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo(bar)\n             \"\"\"\n    end)\n  end\n\n  test \"is a no-op if the file is already formatted\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      foo(bar)\n      \"\"\")\n\n      File.touch!(\"a.ex\", {{2010, 1, 1}, {0, 0, 0}})\n      Mix.Tasks.Format.run([\"a.ex\"])\n      assert File.stat!(\"a.ex\").mtime == {{2010, 1, 1}, {0, 0, 0}}\n    end)\n  end\n\n  test \"does not write file to disk on dry-run\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      Mix.Tasks.Format.run([\"a.ex\", \"--dry-run\"])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo bar\n             \"\"\"\n    end)\n  end\n\n  test \"prints formatted file names with --verbose\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      File.write!(\"b.ex\", \"\"\"\n      foo(bar)\n      \"\"\")\n\n      Mix.Tasks.Format.run([\"a.ex\", \"b.ex\", \"--verbose\"])\n\n      assert_received {:mix_shell, :info, [\"* formatting a.ex\"]}\n      refute_received {:mix_shell, :info, [\"* formatting b.ex\"]}\n    end)\n  end\n\n  test \"does not print formatted file names by default\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      Mix.Tasks.Format.run([\"a.ex\"])\n\n      refute_received {:mix_shell, :info, [\"* formatting a.ex\"]}\n    end)\n  end\n\n  test \"does not try to format a directory that matches a given pattern\", context do\n    in_tmp(context.test, fn ->\n      File.mkdir_p!(\"a.ex\")\n\n      assert_raise Mix.Error, ~r\"Could not find a file to format\", fn ->\n        Mix.Tasks.Format.run([\"*.ex\"])\n      end\n    end)\n  end\n\n  test \"reads file from stdin and prints to stdout\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      output =\n        capture_io(\"foo( )\", fn ->\n          Mix.Tasks.Format.run([\"a.ex\", \"-\"])\n        end)\n\n      assert output == \"\"\"\n             foo()\n             \"\"\"\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo(bar)\n             \"\"\"\n    end)\n  end\n\n  test \"reads file from stdin and prints to stdout with formatter\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [locals_without_parens: [foo: 1]]\n      \"\"\")\n\n      output =\n        capture_io(\"foo :bar\", fn ->\n          Mix.Tasks.Format.run([\"-\"])\n        end)\n\n      assert output == \"\"\"\n             foo :bar\n             \"\"\"\n    end)\n  end\n\n  test \"checks if file is formatted with --check-formatted\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      assert_raise Mix.Error, ~r\"mix format failed due to --check-formatted\", fn ->\n        Mix.Tasks.Format.run([\"a.ex\", \"--check-formatted\"])\n      end\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo bar\n             \"\"\"\n\n      assert Mix.Tasks.Format.run([\"a.ex\"]) == :ok\n      assert Mix.Tasks.Format.run([\"a.ex\", \"--check-formatted\"]) == :ok\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo(bar)\n             \"\"\"\n    end)\n  end\n\n  test \"checks if stdin is formatted with --check-formatted\" do\n    assert_raise Mix.Error, ~r\"mix format failed due to --check-formatted\", fn ->\n      capture_io(\"foo( )\", fn ->\n        Mix.Tasks.Format.run([\"--check-formatted\", \"-\"])\n      end)\n    end\n\n    output =\n      capture_io(\"foo()\\n\", fn ->\n        Mix.Tasks.Format.run([\"--check-formatted\", \"-\"])\n      end)\n\n    assert output == \"\"\n  end\n\n  test \"checks that no error is raised with --check-formatted and --no-exit\" do\n    capture_io(\"foo( )\", fn ->\n      Mix.Tasks.Format.run([\"--check-formatted\", \"--no-exit\", \"-\"])\n    end)\n\n    assert_received {:mix_shell, :info, [\"The following files are not formatted\" <> _]}\n  end\n\n  test \"raises an error if --no-exit is passed without --check-formatted\" do\n    assert_raise Mix.Error, ~r\"--no-exit can only be used together\", fn ->\n      Mix.Tasks.Format.run([\"--no-exit\", \"-\"])\n    end\n  end\n\n  test \"uses inputs and configuration from .formatter.exs\", context do\n    in_tmp(context.test, fn ->\n      # We need a project in order to enable caching\n      Mix.Project.push(__MODULE__.FormatWithDepsApp)\n\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.ex\"],\n        locals_without_parens: [foo: 1]\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      foo bar baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo bar(baz)\n             \"\"\"\n\n      File.write!(\".formatter.exs\", \"\"\"\n      [inputs: [\"a.ex\"]]\n      \"\"\")\n\n      ensure_touched(\".formatter.exs\", \"_build/dev/lib/format_with_deps/.mix/format_timestamp\")\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo(bar(baz))\n             \"\"\"\n    end)\n  end\n\n  test \"does not cache inputs from .formatter.exs\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: Path.wildcard(\"{a,b}.ex\"),\n        locals_without_parens: [foo: 1]\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      foo bar baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo bar(baz)\n             \"\"\"\n\n      File.write!(\"b.ex\", \"\"\"\n      bar baz bat\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"b.ex\") == \"\"\"\n             bar(baz(bat))\n             \"\"\"\n    end)\n  end\n\n  test \"expands patterns in inputs from .formatter.exs\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"{a,.b}.ex\"]\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      File.write!(\".b.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo(bar)\n             \"\"\"\n\n      assert File.read!(\".b.ex\") == \"\"\"\n             foo(bar)\n             \"\"\"\n    end)\n  end\n\n  test \"ignores expanded patterns in excludes from .formatter.exs\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"{a,.b}.ex\"],\n        excludes: [\".*.{ex,exs}\"]\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      File.write!(\".b.ex\", \"\"\"\n      foo bar\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo(bar)\n             \"\"\"\n\n      assert File.read!(\".b.ex\") == \"\"\"\n             foo bar\n             \"\"\"\n    end)\n  end\n\n  defmodule Elixir.SigilWPlugin do\n    @behaviour Mix.Tasks.Format\n\n    def features(opts) do\n      assert opts[:from_formatter_exs] == :yes\n      [sigils: [:W]]\n    end\n\n    def format(contents, opts) do\n      assert opts[:from_formatter_exs] == :yes\n      assert opts[:sigil] == :W\n      assert opts[:modifiers] == ~c\"abc\"\n      assert opts[:line] == 2\n      assert opts[:file] =~ ~r/\\/a\\.ex$/\n      contents |> String.split(~r/\\s/) |> Enum.join(\"\\n\")\n    end\n  end\n\n  test \"uses sigil plugins from .formatter.exs\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.ex\"],\n        plugins: [SigilWPlugin],\n        from_formatter_exs: :yes\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      if true do\n        ~W'''\n        foo bar baz\n        '''abc\n      end\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             if true do\n               ~W'''\n               foo\n               bar\n               baz\n               '''abc\n             end\n             \"\"\"\n\n      {formatter_function, _options} = Mix.Tasks.Format.formatter_for_file(\"a.ex\")\n\n      assert formatter_function.(\"\"\"\n             if true do\n               ~W'''\n               foo bar baz\n               '''abc\n             end\n             \"\"\") == \"\"\"\n             if true do\n               ~W'''\n               foo\n               bar\n               baz\n               '''abc\n             end\n             \"\"\"\n    end)\n  end\n\n  defmodule Elixir.ExtensionWPlugin do\n    @behaviour Mix.Tasks.Format\n\n    def features(opts) do\n      assert opts[:from_formatter_exs] == :yes\n      [extensions: ~w(.w), sigils: [:W]]\n    end\n\n    def format(contents, opts) do\n      assert opts[:from_formatter_exs] == :yes\n      assert opts[:extension] == \".w\"\n      assert opts[:file] =~ ~r/\\/a\\.w$/\n      assert [W: sigil_fun] = opts[:sigils]\n      assert is_function(sigil_fun, 2)\n      contents |> String.split(~r/\\s/) |> Enum.join(\"\\n\")\n    end\n  end\n\n  defmodule Elixir.NewlineToDotPlugin do\n    @behaviour Mix.Tasks.Format\n\n    def features(opts) do\n      assert opts[:from_formatter_exs] == :yes\n      [extensions: ~w(.w), sigils: [:W]]\n    end\n\n    def format(contents, opts) do\n      assert opts[:from_formatter_exs] == :yes\n\n      cond do\n        opts[:extension] ->\n          assert opts[:extension] == \".w\"\n          assert opts[:file] =~ ~r/\\/a\\.w$/\n          assert [W: sigil_fun] = opts[:sigils]\n          assert is_function(sigil_fun, 2)\n\n        opts[:sigil] ->\n          assert opts[:sigil] == :W\n          assert opts[:inputs] == [\"a.ex\"]\n          assert opts[:modifiers] == ~c\"abc\"\n\n        true ->\n          flunk(\"Plugin not loading in correctly.\")\n      end\n\n      contents |> String.replace(\"\\n\", \".\")\n    end\n  end\n\n  test \"uses extension plugins from .formatter.exs\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.w\"],\n        plugins: [ExtensionWPlugin],\n        from_formatter_exs: :yes\n      ]\n      \"\"\")\n\n      File.write!(\"a.w\", \"\"\"\n      foo bar baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.w\") == \"\"\"\n             foo\n             bar\n             baz\n             \"\"\"\n    end)\n  end\n\n  test \"uses multiple plugins from .formatter.exs targeting the same file extension\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.w\"],\n        plugins: [ExtensionWPlugin, NewlineToDotPlugin],\n        from_formatter_exs: :yes\n      ]\n      \"\"\")\n\n      File.write!(\"a.w\", \"\"\"\n      foo bar baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.w\") == \"foo.bar.baz.\"\n    end)\n  end\n\n  test \"uses multiple plugins from .formatter.exs with the same file extension in declared order\",\n       context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.w\"],\n        plugins: [NewlineToDotPlugin, ExtensionWPlugin],\n        from_formatter_exs: :yes\n      ]\n      \"\"\")\n\n      File.write!(\"a.w\", \"\"\"\n      foo bar baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.w\") == \"foo\\nbar\\nbaz.\"\n    end)\n  end\n\n  test \"uses multiple plugins from .formatter.exs targeting the same sigil\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.ex\"],\n        plugins: [NewlineToDotPlugin, SigilWPlugin],\n        from_formatter_exs: :yes\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      def sigil_test(assigns) do\n        ~W\"foo bar baz\\n\"abc\n      end\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             def sigil_test(assigns) do\n               ~W\"foo\\nbar\\nbaz.\"abc\n             end\n             \"\"\"\n    end)\n  end\n\n  test \"uses multiple plugins from .formatter.exs with the same sigil in declared order\",\n       context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.ex\"],\n        plugins: [SigilWPlugin, NewlineToDotPlugin],\n        from_formatter_exs: :yes\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      def sigil_test(assigns) do\n        ~W\"foo bar baz\"abc\n      end\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             def sigil_test(assigns) do\n               ~W\"foo.bar.baz\"abc\n             end\n             \"\"\"\n    end)\n  end\n\n  test \"customizes plugin loading\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.ex\"],\n        plugins: [UnknownPlugin],\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      foo bar baz\n      \"\"\")\n\n      assert_raise Mix.NoProjectError, fn ->\n        Mix.Tasks.Format.formatter_for_file(\"a.ex\")\n      end\n\n      assert_raise Mix.Error, \"Formatter plugin UnknownPlugin cannot be found\", fn ->\n        Mix.Tasks.Format.formatter_for_file(\"a.ex\", plugin_loader: fn plugins -> plugins end)\n      end\n\n      assert Mix.Tasks.Format.formatter_for_file(\"a.ex\", plugin_loader: fn _plugins -> [] end)\n    end)\n  end\n\n  test \"uses extension plugins with --stdin-filename\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.w\"],\n        plugins: [ExtensionWPlugin],\n        from_formatter_exs: :yes\n      ]\n      \"\"\")\n\n      output =\n        capture_io(\"foo bar baz\", fn ->\n          Mix.Tasks.Format.run([\"--stdin-filename\", Path.join(File.cwd!(), \"a.w\"), \"-\"])\n        end)\n\n      assert output ==\n               String.trim(\"\"\"\n               foo\n               bar\n               baz\n               \"\"\")\n    end)\n  end\n\n  test \"respects the --migrate flag\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"unless foo, do: 'bar'\\n\")\n\n      Mix.Tasks.Format.run([\"a.ex\"])\n      assert File.read!(\"a.ex\") == \"unless foo, do: 'bar'\\n\"\n\n      Mix.Tasks.Format.run([\"a.ex\", \"--migrate\"])\n      assert File.read!(\"a.ex\") == \"if !foo, do: ~c\\\"bar\\\"\\n\"\n    end)\n  end\n\n  test \"uses inputs and configuration from --dot-formatter\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"custom_formatter.exs\", \"\"\"\n      [\n        inputs: [\"a.ex\"],\n        locals_without_parens: [foo: 1]\n      ]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      foo bar baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([\"--dot-formatter\", \"custom_formatter.exs\"])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             foo bar(baz)\n             \"\"\"\n    end)\n  end\n\n  test \"uses inputs and configuration from :root path\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [\n        locals_without_parens: [foo: 1]\n      ]\n      \"\"\")\n\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      foo bar baz\n      \"\"\")\n\n      root = File.cwd!()\n\n      {formatter_function, options} =\n        File.cd!(\"lib\", fn ->\n          Mix.Tasks.Format.formatter_for_file(\"lib/a.ex\", root: root)\n        end)\n\n      assert formatter_function.(\"\"\"\n             foo bar baz\n             \"\"\") == \"\"\"\n             foo bar(baz)\n             \"\"\"\n\n      assert options[:root] == root\n    end)\n  end\n\n  test \"reads exported configuration from subdirectories\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [subdirectories: [\"li\", \"lib\"]]\n      \"\"\")\n\n      # We also create a directory called li to ensure files\n      # from lib won't accidentally match on li.\n      File.mkdir_p!(\"li\")\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"li/.formatter.exs\", \"\"\"\n      [inputs: \"**/*\", locals_without_parens: [other_fun: 2]]\n      \"\"\")\n\n      File.write!(\"lib/.formatter.exs\", \"\"\"\n      [inputs: \"a.ex\", locals_without_parens: [my_fun: 2]]\n      \"\"\")\n\n      # Should hit the formatter\n      {formatter, formatter_opts} = Mix.Tasks.Format.formatter_for_file(\"lib/extra/a.ex\")\n      assert formatter_opts[:root] == Path.expand(\"lib\")\n      assert formatter_opts[:locals_without_parens] == [my_fun: 2]\n      assert formatter.(\"my_fun 1, 2\") == \"my_fun 1, 2\\n\"\n\n      # Another directory should not hit the formatter\n      {formatter, formatter_opts} = Mix.Tasks.Format.formatter_for_file(\"test/a.ex\")\n      assert formatter_opts[:root] == Path.expand(\".\")\n      assert formatter_opts[:locals_without_parens] == []\n      assert formatter.(\"my_fun 1, 2\") == \"my_fun(1, 2)\\n\"\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      my_fun :foo, :bar\n      other_fun :baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"lib/a.ex\") == \"\"\"\n             my_fun :foo, :bar\n             other_fun(:baz)\n             \"\"\"\n\n      Mix.Tasks.Format.run([\"lib/a.ex\"])\n\n      assert File.read!(\"lib/a.ex\") == \"\"\"\n             my_fun :foo, :bar\n             other_fun(:baz)\n             \"\"\"\n\n      # No caching without a project\n      manifest_path = Path.join(Mix.Project.manifest_path(), \"cached_dot_formatter\")\n      refute File.regular?(manifest_path)\n\n      # Caching with a project\n      Mix.Project.push(__MODULE__.FormatWithDepsApp)\n      Mix.Tasks.Format.run([\"lib/a.ex\"])\n      manifest_path = Path.join(Mix.Project.manifest_path(), \"cached_dot_formatter\")\n      assert File.regular?(manifest_path)\n\n      # Let's check that the manifest gets updated if it's stale.\n      File.touch!(manifest_path, {{2010, 1, 1}, {0, 0, 0}})\n\n      Mix.Tasks.Format.run([\"lib/a.ex\"])\n      assert File.stat!(manifest_path).mtime > {{2010, 1, 1}, {0, 0, 0}}\n    end)\n  end\n\n  test \"reads exported configuration from dependencies\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(__MODULE__.FormatWithDepsApp)\n\n      File.write!(\".formatter.exs\", \"\"\"\n      [import_deps: [:my_dep]]\n      \"\"\")\n\n      File.write!(\"a.ex\", \"\"\"\n      my_fun :foo, :bar\n      \"\"\")\n\n      File.mkdir_p!(\"deps/my_dep/\")\n\n      File.write!(\"deps/my_dep/.formatter.exs\", \"\"\"\n      [export: [locals_without_parens: [my_fun: 2]]]\n      \"\"\")\n\n      Mix.Tasks.Format.run([\"a.ex\"])\n\n      assert File.read!(\"a.ex\") == \"\"\"\n             my_fun :foo, :bar\n             \"\"\"\n\n      manifest_path = Path.join(Mix.Project.manifest_path(), \"cached_dot_formatter\")\n      assert File.regular?(manifest_path)\n\n      # Let's check that the manifest gets updated if it's stale.\n      File.touch!(manifest_path, {{2010, 1, 1}, {0, 0, 0}})\n\n      {_, formatter_opts} = Mix.Tasks.Format.formatter_for_file(\"a.ex\")\n      assert [my_fun: 2] = formatter_opts[:locals_without_parens]\n\n      # Check the deps_path option is respected\n      assert_raise Mix.Error, ~r\"Unknown dependency :my_dep given to :import_deps\", fn ->\n        # Let's check that the manifest gets updated if it's stale.\n        File.touch!(manifest_path, {{2010, 1, 1}, {0, 0, 0}})\n        Mix.Tasks.Format.formatter_for_file(\"a.ex\", deps_paths: %{})\n      end\n\n      Mix.Tasks.Format.run([\"a.ex\"])\n      assert File.stat!(manifest_path).mtime > {{2010, 1, 1}, {0, 0, 0}}\n    end)\n  end\n\n  test \"reads exported configuration from dependencies and subdirectories\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(__MODULE__.FormatWithDepsApp)\n      format_timestamp = \"_build/dev/lib/format_with_deps/.mix/format_timestamp\"\n\n      File.mkdir_p!(\"deps/my_dep/\")\n\n      File.write!(\"deps/my_dep/.formatter.exs\", \"\"\"\n      [export: [locals_without_parens: [my_fun: 2]]]\n      \"\"\")\n\n      File.mkdir_p!(\"lib/sub\")\n      File.mkdir_p!(\"lib/not_used_and_wont_raise\")\n\n      File.write!(\".formatter.exs\", \"\"\"\n      [subdirectories: [\"lib\"]]\n      \"\"\")\n\n      File.write!(\"lib/.formatter.exs\", \"\"\"\n      [subdirectories: [\"*\"]]\n      \"\"\")\n\n      File.write!(\"lib/sub/.formatter.exs\", \"\"\"\n      [inputs: \"a.ex\", import_deps: [:my_dep]]\n      \"\"\")\n\n      File.write!(\"lib/sub/a.ex\", \"\"\"\n      my_fun :foo, :bar\n      other_fun :baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"lib/sub/a.ex\") == \"\"\"\n             my_fun :foo, :bar\n             other_fun(:baz)\n             \"\"\"\n\n      Mix.Tasks.Format.run([\"lib/sub/a.ex\"])\n\n      assert File.read!(\"lib/sub/a.ex\") == \"\"\"\n             my_fun :foo, :bar\n             other_fun(:baz)\n             \"\"\"\n\n      # Update .formatter.exs, check that file is updated\n      File.write!(\"lib/sub/.formatter.exs\", \"\"\"\n      [inputs: \"a.ex\"]\n      \"\"\")\n\n      File.touch!(\"lib/sub/.formatter.exs\", {{2038, 1, 1}, {0, 0, 0}})\n      File.touch!(format_timestamp, {{2010, 1, 1}, {0, 0, 0}})\n\n      Mix.Tasks.Format.run([])\n\n      assert File.read!(\"lib/sub/a.ex\") == \"\"\"\n             my_fun(:foo, :bar)\n             other_fun(:baz)\n             \"\"\"\n\n      # Add a new entry to \"lib\" and it also gets picked.\n      File.mkdir_p!(\"lib/extra\")\n\n      File.write!(\"lib/extra/.formatter.exs\", \"\"\"\n      [inputs: \"a.ex\", locals_without_parens: [other_fun: 1]]\n      \"\"\")\n\n      File.write!(\"lib/extra/a.ex\", \"\"\"\n      my_fun :foo, :bar\n      other_fun :baz\n      \"\"\")\n\n      File.touch!(\"lib/extra/.formatter.exs\", {{2038, 1, 1}, {0, 0, 0}})\n      File.touch!(format_timestamp, {{2010, 1, 1}, {0, 0, 0}})\n\n      Mix.Tasks.Format.run([])\n\n      {_, formatter_opts} = Mix.Tasks.Format.formatter_for_file(\"lib/extra/a.ex\")\n      assert formatter_opts[:root] == Path.expand(\"lib/extra\")\n      assert formatter_opts[:locals_without_parens] == [other_fun: 1]\n\n      assert File.read!(\"lib/extra/a.ex\") == \"\"\"\n             my_fun(:foo, :bar)\n             other_fun :baz\n             \"\"\"\n    end)\n  end\n\n  test \"validates subdirectories in :subdirectories\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [subdirectories: \"oops\"]\n      \"\"\")\n\n      message = \"Expected :subdirectories to return a list of directories, got: \\\"oops\\\"\"\n      assert_raise Mix.Error, message, fn -> Mix.Tasks.Format.run([]) end\n\n      File.write!(\".formatter.exs\", \"\"\"\n      [subdirectories: [\"lib\"]]\n      \"\"\")\n\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/.formatter.exs\", \"\"\"\n      []\n      \"\"\")\n\n      message = \"Expected :inputs or :subdirectories key in #{Path.expand(\"lib/.formatter.exs\")}\"\n      assert_raise Mix.Error, message, fn -> Mix.Tasks.Format.run([]) end\n    end)\n  end\n\n  test \"validates dependencies in :import_deps\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(__MODULE__.FormatWithDepsApp)\n\n      File.write!(\".formatter.exs\", \"\"\"\n      [import_deps: [:my_dep]]\n      \"\"\")\n\n      message =\n        ~r\"Unknown dependency :my_dep given to :import_deps in the formatter configuration\"\n\n      assert_raise Mix.Error, message, fn -> Mix.Tasks.Format.run([]) end\n\n      File.write!(\".formatter.exs\", \"\"\"\n      [import_deps: [:nonexistent_dep]]\n      \"\"\")\n\n      message =\n        ~r\"Unknown dependency :nonexistent_dep given to :import_deps in the formatter configuration\"\n\n      assert_raise Mix.Error, message, fn -> Mix.Tasks.Format.run([]) end\n    end)\n  end\n\n  test \"prints an error on conflicting .formatter.exs files\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\".formatter.exs\", \"\"\"\n      [inputs: \"lib/**/*.{ex,exs}\", subdirectories: [\"lib\", \"foo\"]]\n      \"\"\")\n\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/.formatter.exs\", \"\"\"\n      [inputs: \"a.ex\", locals_without_parens: [my_fun: 2]]\n      \"\"\")\n\n      File.mkdir_p!(\"foo\")\n\n      File.write!(\"foo/.formatter.exs\", \"\"\"\n      [inputs: \"../lib/a.ex\", locals_without_parens: [my_fun: 2]]\n      \"\"\")\n\n      File.write!(\"lib/a.ex\", \"\"\"\n      my_fun :foo, :bar\n      other_fun :baz\n      \"\"\")\n\n      Mix.Tasks.Format.run([])\n\n      message1 =\n        \"Both .formatter.exs and #{Path.expand(\"lib/.formatter.exs\")} specify the file \" <>\n          \"#{Path.expand(\"lib/a.ex\")} in their :inputs option. To resolve the conflict, \" <>\n          \"the configuration in .formatter.exs will be ignored. Please change the list of \" <>\n          \":inputs in one of the formatter files so only one of them matches #{Path.expand(\"lib/a.ex\")}\"\n\n      message2 =\n        \"Both #{Path.expand(\"lib/.formatter.exs\")} and #{Path.expand(\"foo/.formatter.exs\")} \" <>\n          \"specify the file #{Path.expand(\"lib/a.ex\")} in their :inputs option. To resolve \" <>\n          \"the conflict, the configuration in #{Path.expand(\"lib/.formatter.exs\")} \" <>\n          \"will be ignored. Please change the list of :inputs in one of the formatter files \" <>\n          \"so only one of them matches #{Path.expand(\"lib/a.ex\")}\"\n\n      assert_received {:mix_shell, :error, [^message1]}\n      assert_received {:mix_shell, :error, [^message2]}\n    end)\n  end\n\n  test \"raises on invalid arguments\", context do\n    in_tmp(context.test, fn ->\n      assert_raise Mix.Error, ~r\"Expected one or more files\\/patterns to be given\", fn ->\n        Mix.Tasks.Format.run([])\n      end\n\n      assert_raise Mix.Error, ~r\"Could not find a file to format\", fn ->\n        Mix.Tasks.Format.run([\"unknown.whatever\"])\n      end\n    end)\n  end\n\n  test \"raises SyntaxError when parsing invalid source file\", context do\n    in_tmp(context.test, fn ->\n      File.write!(\"a.ex\", \"\"\"\n      defmodule <%= module %>.Bar do end\n      \"\"\")\n\n      messages = [\n        \"invalid syntax found on a.ex:1:13:\",\n        \"defmodule <%= module %>.Bar do end\",\n        \"^\",\n        \"syntax error before: '='\"\n      ]\n\n      e =\n        assert_raise SyntaxError, fn ->\n          Mix.Tasks.Format.run([\"a.ex\"])\n        end\n\n      output = Exception.format(:error, e, [])\n\n      for msg <- messages do\n        assert output =~ msg\n      end\n\n      assert_received {:mix_shell, :error, [\"mix format failed for file: a.ex\"]}\n    end)\n  end\n\n  test \"raises SyntaxError when parsing invalid stdin\", context do\n    in_tmp(context.test, fn ->\n      e =\n        assert_raise SyntaxError, fn ->\n          capture_io(\"defmodule <%= module %>.Bar do end\", fn ->\n            Mix.Tasks.Format.run([\"-\"])\n          end)\n        end\n\n      messages = [\n        \"invalid syntax found on stdin.exs:1:13:\",\n        \"defmodule <%= module %>.Bar do end\",\n        \"^\",\n        \"syntax error before: '='\"\n      ]\n\n      output = Exception.format(:error, e, [])\n\n      for msg <- messages do\n        assert output =~ msg\n      end\n\n      assert_received {:mix_shell, :error, [\"mix format failed for stdin\"]}\n    end)\n  end\n\n  describe \"text_diff_format/3\" do\n    defp text_diff_format(old, new, opts \\\\ []) do\n      Mix.Tasks.Format.text_diff_format(old, new, opts) |> IO.iodata_to_binary()\n    end\n\n    test \"with unchanged texts\" do\n      assert text_diff_format(\"abc\", \"abc\") == \"\"\n    end\n\n    test \"with one deleted line\" do\n      old = \"del\"\n      new = \"\"\n\n      assert output = text_diff_format(old, new)\n\n      if IO.ANSI.enabled?() do\n        assert output == \"1  \\e[31m -\\e[0m|\\e[31mdel\\e[0m\\n  1\\e[32m +\\e[0m|\\n\"\n      end\n\n      assert text_diff_format(old, new, color: false) == \"\"\"\n             1   -|del\n               1 +|\n             \"\"\"\n    end\n\n    test \"with one changed line\" do\n      old = \"one three two\"\n      new = \"one two three\"\n\n      assert output = text_diff_format(old, new)\n\n      if IO.ANSI.enabled?() do\n        assert output ==\n                 \"\"\"\n                 1  \\e[31m -\\e[0m|one three\\e[31m\\e[0m\\e[41m \\e[0m\\e[31mtwo\\e[0m\n                   1\\e[32m +\\e[0m|one t\\e[32mwo\\e[0m\\e[42m \\e[0m\\e[32mt\\e[0mhree\n                 \"\"\"\n      end\n\n      assert text_diff_format(old, new, color: false) == \"\"\"\n             1   -|one three two\n               1 +|one two three\n             \"\"\"\n    end\n\n    test \"with one deleted line in the middle\" do\n      old = \"\"\"\n      aaa\n      bbb\n      ccc\n      ddd\n      eee\n      fff\n      ggg\n      \"\"\"\n\n      new = \"\"\"\n      aaa\n      bbb\n      ccc\n      eee\n      fff\n      ggg\n      \"\"\"\n\n      exp = \"\"\"\n           |\n      2 2  |bbb\n      3 3  |ccc\n      4   -|ddd\n      5 4  |eee\n      6 5  |fff\n           |\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false) == exp\n    end\n\n    test \"with multiple deleted lines\" do\n      old = \"\"\"\n      aaa\n      bbb\n      ccc\n      ddd\n      eee\n      fff\n      ggg\\\n      \"\"\"\n\n      new = \"\"\"\n      aaa\n      ggg\\\n      \"\"\"\n\n      exp = \"\"\"\n      1 1  |aaa\n      2   -|bbb\n      3   -|ccc\n      4   -|ddd\n      5   -|eee\n      6   -|fff\n      7 2  |ggg\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false) == exp\n    end\n\n    test \"with one added line in the middle\" do\n      old = \"\"\"\n      aaa\n      bbb\n      ccc\n      eee\n      fff\n      ggg\n      \"\"\"\n\n      new = \"\"\"\n      aaa\n      bbb\n      ccc\n      ddd\n      eee\n      fff\n      ggg\n      \"\"\"\n\n      exp = \"\"\"\n           |\n      2 2  |bbb\n      3 3  |ccc\n        4 +|ddd\n      4 5  |eee\n      5 6  |fff\n           |\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false) == exp\n    end\n\n    test \"with changed first line\" do\n      old = \"\"\"\n      aaa\n      bbb\n      ccc\n      ddd\n      \"\"\"\n\n      new = \"\"\"\n      axa\n      bbb\n      ccc\n      ddd\n      \"\"\"\n\n      exp = \"\"\"\n      1   -|aaa\n        1 +|axa\n      2 2  |bbb\n      3 3  |ccc\n           |\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false) == exp\n    end\n\n    test \"with changed last line\" do\n      old = \"\"\"\n      aaa\n      bbb\n      ccc\n      ddd\n      \"\"\"\n\n      new = \"\"\"\n      aaa\n      bbb\n      ccc\n      dxd\n      \"\"\"\n\n      exp = \"\"\"\n           |\n      2 2  |bbb\n      3 3  |ccc\n      4   -|ddd\n        4 +|dxd\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false) == exp\n    end\n\n    test \"with changed first and last line\" do\n      old = \"\"\"\n      aaa\n      bbb\n      ccc\n      ddd\n      eee\n      \"\"\"\n\n      new = \"\"\"\n      axa\n      bbb\n      ccc\n      ddd\n      exe\n      \"\"\"\n\n      exp = \"\"\"\n      1   -|aaa\n        1 +|axa\n      2 2  |bbb\n           |\n      4 4  |ddd\n      5   -|eee\n        5 +|exe\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false, before: 1, after: 1) == exp\n    end\n\n    test \"with changed second and second last line\" do\n      old = \"\"\"\n      aaa\n      bbb\n      ccc\n      ddd\n      eee\n      fff\n      ggg\n      hhh\n      iii\\\n      \"\"\"\n\n      new = \"\"\"\n      aaa\n      bXb\n      ccc\n      ddd\n      eee\n      fff\n      ggg\n      hXh\n      iii\\\n      \"\"\"\n\n      exp = \"\"\"\n      1 1  |aaa\n      2   -|bbb\n        2 +|bXb\n      3 3  |ccc\n           |\n      7 7  |ggg\n      8   -|hhh\n        8 +|hXh\n      9 9  |iii\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false, before: 1, after: 1) == exp\n    end\n\n    test \"colorized added tab\" do\n      assert output = text_diff_format(\"ab\", \"a\\tb\")\n\n      if IO.ANSI.enabled?() do\n        assert output =~ \"\\e[42m\\t\"\n      end\n    end\n\n    test \"colorized deleted tab\" do\n      assert output = text_diff_format(\"a\\tb\", \"ab\")\n\n      if IO.ANSI.enabled?() do\n        assert output =~ \"\\e[41m\\t\"\n      end\n    end\n\n    test \"shows added CR\" do\n      old = \"\"\"\n      aaa\n      bbb\n      \"\"\"\n\n      new = \"\"\"\n      aaa\\r\n      bbb\n      \"\"\"\n\n      exp = \"\"\"\n      1   -|aaa\n        1 +|aaa↵\n      2 2  |bbb\n           |\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false, before: 1, after: 1) == exp\n    end\n\n    test \"shows multiple added CRs\" do\n      old = \"\"\"\n      aaa\n      bbb\n      \"\"\"\n\n      new = \"\"\"\n      aaa\\r\n      bbb\\r\n      ccc\\r\n      \"\"\"\n\n      exp = \"\"\"\n      1   -|aaa\n      2   -|bbb\n        1 +|aaa↵\n        2 +|bbb↵\n        3 +|ccc\\r\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false, before: 1, after: 1) == exp\n    end\n\n    test \"shows deleted CR\" do\n      old = \"\"\"\n      aaa\\r\n      bbb\n      \"\"\"\n\n      new = \"\"\"\n      aaa\n      bbb\n      \"\"\"\n\n      exp = \"\"\"\n      1   -|aaa↵\n        1 +|aaa\n      2 2  |bbb\n           |\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false, before: 1, after: 1) == exp\n    end\n\n    test \"shows multiple deleted CRs\" do\n      old = \"\"\"\n      aaa\\r\n      bbb\\r\n      \"\"\"\n\n      new = \"\"\"\n      aaa\n      bbb\n      ccc\n      \"\"\"\n\n      exp = \"\"\"\n      1   -|aaa↵\n      2   -|bbb↵\n        1 +|aaa\n        2 +|bbb\n        3 +|ccc\n      \"\"\"\n\n      assert text_diff_format(old, new)\n      assert text_diff_format(old, new, color: false) == exp\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/help_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.HelpTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n\n  test \"help lists all tasks\", context do\n    in_tmp(context.test, fn ->\n      Mix.Tasks.Help.run([])\n      assert_received {:mix_shell, :info, [\"mix\" <> _]}\n      assert_received {:mix_shell, :info, [\"mix help\" <> _]}\n      assert_received {:mix_shell, :info, [\"mix compile\" <> _]}\n    end)\n  end\n\n  test \"help list default task\", context do\n    in_tmp(context.test, fn ->\n      Mix.Tasks.Help.run([])\n\n      assert_received {:mix_shell, :info, [output]}\n      assert output =~ ~r/^mix\\s+# Runs the default task \\(current: \\\"mix run\\\"\\)/m\n    end)\n  end\n\n  defmodule Aliases do\n    def project do\n      [aliases: [h: \"hello\", c: \"compile\"]]\n    end\n  end\n\n  test \"help --names\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(Aliases)\n\n      Mix.Tasks.Help.run([\"--names\"])\n      assert_received {:mix_shell, :info, [\"c\"]}\n      assert_received {:mix_shell, :info, [\"compile\"]}\n      assert_received {:mix_shell, :info, [\"h\"]}\n      assert_received {:mix_shell, :info, [\"help\"]}\n      assert_received {:mix_shell, :info, [\"escript.build\"]}\n      refute_received {:mix_shell, :info, [\"compile.all\"]}\n    end)\n  end\n\n  defmodule ComplexAliases do\n    def project do\n      [\n        aliases: [\n          h: \"hello\",\n          p: &inspect/1,\n          foo: &foo/1,\n          bar: fn _ -> :ok end,\n          help: [\"help\", \"hello\"],\n          \"nested.h\": [&Mix.shell().info(inspect(&1)), \"h foo bar\"],\n          other: [\n            \"format --check-formatted\",\n            fn _ -> :ok end,\n            &foo/1,\n            \"help\"\n          ]\n        ]\n      ]\n    end\n\n    defp foo(_), do: :ok\n  end\n\n  test \"help lists all aliases\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(ComplexAliases)\n\n      Mix.Tasks.Help.run([])\n\n      assert_received {:mix_shell, :info, [\"mix h\" <> message]}\n      assert message =~ ~r/# Alias for hello/\n\n      assert_received {:mix_shell, :info, [\"mix p\" <> message]}\n      assert message =~ ~r/# Alias for &inspect\\/1/\n\n      assert_received {:mix_shell, :info, [\"mix foo\" <> message]}\n      assert message =~ ~r/# Alias for &foo\\/1/\n\n      assert_received {:mix_shell, :info, [\"mix bar\" <> message]}\n      assert message =~ ~r/# Alias for a function/\n\n      assert_received {:mix_shell, :info, [\"mix help\" <> message]}\n      assert message =~ ~r/# Alias for help, hello/\n\n      assert_received {:mix_shell, :info, [\"mix nested.h\" <> message]}\n      assert message =~ ~r/# Alias for a function, h foo bar/\n\n      assert_received {:mix_shell, :info, [\"mix other\" <> message]}\n      assert message =~ ~r/# Alias for format --check-formatted, a function, &foo\\/1, help/\n    end)\n  end\n\n  test \"help ALIAS\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(ComplexAliases)\n\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"h\"])\n        end)\n\n      assert output =~ \"mix h\\n\\n\"\n      assert output =~ \"Alias for\\n\\n\"\n      assert output =~ \"    \\\"hello\\\"\\n\"\n      assert output =~ ~r/^Location: mix.exs/m\n\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"p\"])\n        end)\n\n      assert output =~ \"mix p\\n\\n\"\n      assert output =~ \"Alias for\\n\\n\"\n      assert output =~ \"    &Kernel.inspect/1\\n\"\n      assert output =~ ~r/^Location: mix.exs/m\n\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"help\"])\n        end)\n\n      assert output =~ \"mix help\\n\\n\"\n      assert output =~ \"Alias for\\n\\n\"\n      assert output =~ \"    [\\\"help\\\",\\n\"\n      assert output =~ \"    \\\"hello\\\"]\\n\"\n      assert output =~ ~r/^Location: mix.exs/m\n\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"nested.h\"])\n        end)\n\n      assert output =~ \"mix nested.h\\n\\n\"\n      assert output =~ \"Alias for\\n\\n\"\n      assert output =~ ~r/    \\[#Function/\n      assert output =~ ~r/^Location: mix.exs/m\n    end)\n  end\n\n  test \"help TASK\", context do\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"compile\"])\n        end)\n\n      assert output =~ \"mix compile\\n\"\n      assert output =~ \"## Command line options\"\n      assert output =~ ~r/^Location:/m\n\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"compile.all\"])\n        end)\n\n      assert output =~ \"mix compile.all\\n\"\n      assert output =~ \"There is no documentation for this task\"\n    end)\n  end\n\n  defmodule ShadowedAliases do\n    def project do\n      [aliases: [compile: \"compile\"]]\n    end\n  end\n\n  test \"help TASK && ALIAS\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(ShadowedAliases)\n\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"compile\"])\n        end)\n\n      assert output =~ \"mix compile\\n\\n\"\n      assert output =~ \"Alias for\\n\\n\"\n      assert output =~ \"\\\"compile\\\"\\n\"\n      assert output =~ ~r/^Location: mix.exs/m\n\n      assert output =~\n               \"\\nThere is also a task named \\\"compile\\\". The documentation is shown next.\\n\"\n\n      assert output =~ \"## Command line options\"\n      assert output =~ ~r/^Location:/m\n    end)\n  end\n\n  test \"help app:APP\", context do\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"app:iex\"])\n        end)\n\n      assert output =~ \"# IEx\\n\\nElixir's interactive shell.\"\n\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"app:parsetools\"])\n        end)\n\n      assert output =~ \"# :leex\"\n    end)\n  end\n\n  test \"help app:UNKNOWN\", context do\n    in_tmp(context.test, fn ->\n      Mix.Tasks.Help.run([\"app:foobar\"])\n      assert_received {:mix_shell, :error, [\"Application foobar does not exist or is not loaded\"]}\n    end)\n  end\n\n  test \"help app:APP for current project\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n      File.mkdir_p!(\"lib\")\n\n      File.write!(\"lib/example.ex\", ~s'''\n      defmodule Example do\n        @moduledoc \"\"\"\n        This is an example module.\n        \"\"\"\n      end\n      ''')\n\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"app:sample\"])\n        end)\n\n      assert output =~ \"\"\"\n             # Example\n\n             This is an example module.\n             \"\"\"\n    end)\n  after\n    purge([Example])\n  end\n\n  test \"help Elixir MODULE\", context do\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"Mix\"])\n        end)\n\n      assert output =~\n               \"Mix is a build tool that provides tasks for creating, compiling, and testing\\nElixir projects, managing its dependencies, and more.\"\n    end)\n  end\n\n  test \"help Elixir NESTED MODULE\", context do\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"IO.ANSI\"])\n        end)\n\n      assert output =~ \"Functionality to render ANSI escape sequences.\"\n    end)\n  end\n\n  test \"help Erlang MODULE\", context do\n    otp_docs? = match?({:docs_v1, _, _, _, _, _, _}, Code.fetch_docs(:math))\n\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\":math\"])\n        end)\n\n      if otp_docs? do\n        assert output =~\n                 \"This module provides an interface to a number of mathematical\"\n      else\n        assert output =~ \":math was not compiled with docs\"\n      end\n    end)\n  end\n\n  test \"help FUNCTION/0\", context do\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"DateTime.utc_now()\"])\n        end)\n\n      assert output =~ \"Returns the current datetime in UTC\"\n    end)\n  end\n\n  test \"help FUNCTION/1\", context do\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"Enum.all?/1\"])\n        end)\n\n      assert output =~ \"Returns `true` if all elements in `enumerable` are truthy.\"\n    end)\n  end\n\n  test \"help NESTED MODULE FUNCTION/3\", context do\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"IO.ANSI.color/3\"])\n        end)\n\n      assert output =~ \"Sets the foreground color from individual RGB values\"\n    end)\n  end\n\n  test \"help ERROR\" do\n    assert_raise Mix.Error, \"Invalid expression: Foo.bar(~s[baz])\", fn ->\n      Mix.Tasks.Help.run([\"Foo.bar(~s[baz])\"])\n    end\n  end\n\n  test \"help --search PATTERN\", context do\n    in_tmp(context.test, fn ->\n      Mix.Tasks.Help.run([\"--search\", \"deps\"])\n      assert_received {:mix_shell, :info, [\"mix deps\" <> _]}\n      assert_received {:mix_shell, :info, [\"mix deps.clean\" <> _]}\n    end)\n\n    in_tmp(context.test, fn ->\n      Mix.Project.push(Aliases)\n\n      Mix.Tasks.Help.run([\"--search\", \"h\"])\n      assert_received {:mix_shell, :info, [\"mix h\" <> message]}\n      assert message =~ ~r/# Alias for hello/\n    end)\n  end\n\n  test \"help --search without pattern\" do\n    assert_raise Mix.Error, \"Unexpected arguments, expected \\\"mix help --search PATTERN\\\"\", fn ->\n      Mix.Tasks.Help.run([\"--search\"])\n    end\n  end\n\n  test \"help --search without results\", context do\n    in_tmp(context.test, fn ->\n      output =\n        capture_io(fn ->\n          Mix.Tasks.Help.run([\"--search\", \"foo\"])\n        end)\n\n      assert output == \"\"\n    end)\n  end\n\n  test \"help --aliases\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(Aliases)\n\n      Mix.Tasks.Help.run([\"--aliases\"])\n      assert_received {:mix_shell, :info, [\"mix h\" <> message]}\n      assert message =~ ~r/# Alias for hello/\n\n      assert_received {:mix_shell, :info, [\"mix c\" <> message]}\n      assert message =~ ~r/# Alias for compile/\n\n      refute_received {:mix_shell, :info, [\"mix deps\" <> _]}\n    end)\n  end\n\n  test \"bad arguments\" do\n    message = \"Unexpected arguments, expected \\\"mix help\\\" or \\\"mix help TASK\\\"\"\n\n    assert_raise Mix.Error, message, fn ->\n      Mix.Tasks.Help.run([\"foo\", \"bar\"])\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/iex_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.IExTest do\n  use MixTest.Case, async: true\n\n  test \"raises error message about correct usage\", context do\n    in_tmp(context.test, fn ->\n      msg = \"To use IEx with Mix, please run \\\"iex -S mix\\\"\"\n\n      assert_raise Mix.Error, msg, fn ->\n        Mix.Tasks.Iex.run([])\n      end\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/loadconfig_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.LoadconfigTest do\n  use MixTest.Case\n\n  test \"reads and persists project configuration\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      write_config(\"\"\"\n      [my_app: [key: :project]]\n      \"\"\")\n\n      assert Application.fetch_env(:my_app, :key) == :error\n      Mix.Task.run(\"loadconfig\", [])\n      assert Application.fetch_env(:my_app, :key) == {:ok, :project}\n\n      # App configuration should have lower precedence\n      :ok = :application.load({:application, :my_app, [vsn: ~c\"1.0.0\", env: [key: :app]]})\n      assert Application.fetch_env(:my_app, :key) == {:ok, :project}\n\n      # loadconfig can be called multiple times\n      # Later values should have higher precedence\n      Mix.Task.run(\"loadconfig\", [fixture_path(\"config.exs\")])\n      assert Application.fetch_env(:my_app, :key) == {:ok, :value}\n    end)\n  end\n\n  test \"sets config_env() and config_target()\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      write_config(\"\"\"\n      import Config\n      config :opts_app, :key, {config_env(), config_target()}\n      \"\"\")\n\n      assert Application.fetch_env(:opts_app, :key) == :error\n      Mix.Task.run(\"loadconfig\", [])\n      assert Application.fetch_env(:opts_app, :key) == {:ok, {:dev, :host}}\n    end)\n  end\n\n  test \"reads from custom config_path\", context do\n    Mix.ProjectStack.post_config(config_path: \"fresh.config\")\n\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      write_config(\"fresh.config\", \"\"\"\n      [config_app: [key: :value]]\n      \"\"\")\n\n      assert Application.fetch_env(:config_app, :key) == :error\n      Mix.Task.run(\"loadconfig\", [])\n      assert Application.fetch_env(:config_app, :key) == {:ok, :value}\n\n      File.rm(\"fresh.config\")\n\n      assert_raise File.Error, ~r\"could not read file .*/fresh\\.config\", fn ->\n        Mix.Task.run(\"loadconfig\", [])\n      end\n    end)\n  end\n\n  test \"is a no-op with nil custom config_path\" do\n    Mix.ProjectStack.post_config(config_path: nil)\n    assert Mix.Task.run(\"loadconfig\", []) == []\n  end\n\n  test \"updates config files and config mtime\", context do\n    in_tmp(context.test, fn ->\n      Mix.Project.push(MixTest.Case.Sample)\n\n      mtime = Mix.Project.config_mtime()\n      config = Path.expand(\"config/config.exs\")\n      refute config in Mix.Project.config_files()\n\n      write_config(config, \"[]\")\n      Mix.Task.run(\"loadconfig\", [config])\n      assert config in Mix.Project.config_files()\n      assert Mix.Project.config_mtime() > mtime\n\n      # Touching it should not have any deadlocks\n      File.touch!(config, {{2038, 1, 1}, {0, 0, 0}})\n      Mix.Task.run(\"loadconfig\", [config])\n      assert config in Mix.Project.config_files()\n      assert Mix.Project.config_mtime() > mtime\n    end)\n  end\n\n  defp write_config(path \\\\ \"config/config.exs\", contents) do\n    File.mkdir_p!(Path.dirname(path))\n    File.write!(path, contents)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/local_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.LocalTest do\n  use MixTest.Case\n\n  test \"MIX_PATH\" do\n    File.rm_rf!(tmp_path(\"mixpath\"))\n    System.put_env(\"MIX_PATH\", tmp_path(\"mixpath/ebin\"))\n\n    File.mkdir_p!(tmp_path(\"mixpath/ebin\"))\n    Mix.Local.append_paths()\n\n    # Install on MIX_PATH manually\n    File.copy!(\n      fixture_path(\"archive/ebin/Elixir.Mix.Tasks.Local.Sample.beam\"),\n      tmp_path(\"mixpath/ebin/Elixir.Mix.Tasks.Local.Sample.beam\")\n    )\n\n    # Run it\n    Mix.Task.run(\"local.sample\")\n    assert_received {:mix_shell, :info, [\"sample\"]}\n  after\n    purge([Mix.Tasks.Local.Sample])\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/new_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.NewTest do\n  use MixTest.Case\n\n  test \"new\" do\n    in_tmp(\"new\", fn ->\n      Mix.Tasks.New.run([\"hello_world\"])\n\n      assert_file(\"hello_world/mix.exs\", fn file ->\n        assert file =~ \"app: :hello_world\"\n        assert file =~ \"version: \\\"0.1.0\\\"\"\n      end)\n\n      assert_file(\"hello_world/README.md\", ~r/# HelloWorld\\n/)\n      assert_file(\"hello_world/.gitignore\")\n\n      assert_file(\"hello_world/lib/hello_world.ex\", ~r/defmodule HelloWorld do/)\n      assert_file(\"hello_world/test/test_helper.exs\", ~r/ExUnit.start()/)\n\n      assert_file(\"hello_world/test/hello_world_test.exs\", fn file ->\n        assert file =~ ~r/defmodule HelloWorldTest do/\n        assert file =~ \"assert HelloWorld.hello() == :world\"\n      end)\n\n      assert_received {:mix_shell, :info, [\"* creating mix.exs\"]}\n      assert_received {:mix_shell, :info, [\"* creating lib/hello_world.ex\"]}\n\n      # Ensure formatting is setup and consistent.\n      File.cd!(\"hello_world\", fn ->\n        Mix.Tasks.Format.run([\"--check-formatted\"])\n      end)\n    end)\n  end\n\n  test \"new with --sup\" do\n    in_tmp(\"new sup\", fn ->\n      Mix.Tasks.New.run([\"hello_world\", \"--sup\"])\n\n      assert_file(\"hello_world/mix.exs\", fn file ->\n        assert file =~ \"app: :hello_world\"\n        assert file =~ \"version: \\\"0.1.0\\\"\"\n        assert file =~ \"mod: {HelloWorld.Application, []}\"\n      end)\n\n      assert_file(\"hello_world/README.md\", ~r/# HelloWorld\\n/)\n      assert_file(\"hello_world/.gitignore\")\n\n      assert_file(\"hello_world/lib/hello_world.ex\", fn file ->\n        assert file =~ \"defmodule HelloWorld do\"\n        assert file =~ \"def hello do\"\n      end)\n\n      assert_file(\"hello_world/lib/hello_world/application.ex\", fn file ->\n        assert file =~ \"defmodule HelloWorld.Application do\"\n        assert file =~ \"use Application\"\n        assert file =~ \"@impl true\"\n        assert file =~ \"Supervisor.start_link(children, opts)\"\n      end)\n\n      assert_file(\"hello_world/test/test_helper.exs\", ~r/ExUnit.start()/)\n      assert_file(\"hello_world/test/hello_world_test.exs\", ~r/defmodule HelloWorldTest do/)\n\n      assert_received {:mix_shell, :info, [\"* creating mix.exs\"]}\n      assert_received {:mix_shell, :info, [\"* creating lib/hello_world.ex\"]}\n\n      # Ensure formatting is setup and consistent.\n      File.cd!(\"hello_world\", fn ->\n        Mix.Tasks.Format.run([\"--check-formatted\"])\n      end)\n    end)\n  end\n\n  test \"new with --module uses the module name also for naming the files in lib and test\" do\n    in_tmp(\"new_with_module\", fn ->\n      Mix.Tasks.New.run([\"hello_world\", \"--module\", \"MyTestModule\"])\n      assert_file(\"hello_world/lib/my_test_module.ex\", ~r/defmodule MyTestModule do/)\n      assert_file(\"hello_world/test/my_test_module_test.exs\", ~r/defmodule MyTestModuleTest do/)\n    end)\n  end\n\n  test \"new with --app\" do\n    in_tmp(\"new app\", fn ->\n      Mix.Tasks.New.run([\"HELLO_WORLD\", \"--app\", \"hello_world\"])\n\n      assert_file(\"HELLO_WORLD/mix.exs\", fn file ->\n        assert file =~ \"app: :hello_world\"\n        assert file =~ \"version: \\\"0.1.0\\\"\"\n      end)\n\n      assert_file(\"HELLO_WORLD/README.md\", ~r/# HelloWorld\\n/)\n      assert_file(\"HELLO_WORLD/.gitignore\")\n\n      assert_file(\"HELLO_WORLD/lib/hello_world.ex\", ~r/defmodule HelloWorld do/)\n\n      assert_file(\"HELLO_WORLD/test/test_helper.exs\", ~r/ExUnit.start()/)\n      assert_file(\"HELLO_WORLD/test/hello_world_test.exs\", ~r/defmodule HelloWorldTest do/)\n\n      assert_received {:mix_shell, :info, [\"* creating mix.exs\"]}\n      assert_received {:mix_shell, :info, [\"* creating lib/hello_world.ex\"]}\n\n      # Ensure formatting is setup and consistent.\n      File.cd!(\"HELLO_WORLD\", fn ->\n        Mix.Tasks.Format.run([\"--check-formatted\"])\n      end)\n    end)\n  end\n\n  test \"new with --umbrella\" do\n    in_tmp(\"new umbrella\", fn ->\n      Mix.Tasks.New.run([\"hello_world\", \"--umbrella\"])\n\n      assert_file(\"hello_world/mix.exs\", fn file ->\n        assert file =~ \"apps_path: \\\"apps\\\"\"\n      end)\n\n      assert_file(\"hello_world/README.md\", ~r/# HelloWorld\\n/)\n      assert_file(\"hello_world/.gitignore\")\n\n      assert_received {:mix_shell, :info, [\"* creating mix.exs\"]}\n\n      # Ensure formatting is setup and consistent.\n      File.cd!(\"hello_world\", fn ->\n        Mix.Tasks.Format.run([\"--check-formatted\"])\n      end)\n    end)\n  end\n\n  test \"new inside umbrella root\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Tasks.New.run([\"apps/hello_world\"])\n\n      assert_file(\"apps/hello_world/mix.exs\", fn file ->\n        assert file =~ \"deps_path: \\\"../../deps\\\"\"\n        assert file =~ \"lockfile: \\\"../../mix.lock\\\"\"\n      end)\n\n      # Ensure formatting is setup and consistent.\n      File.cd!(\"apps/hello_world\", fn ->\n        Mix.Tasks.Format.run([\"--check-formatted\"])\n      end)\n    end)\n  end\n\n  test \"new inside umbrella apps\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      File.cd!(\"apps\", fn ->\n        Mix.Tasks.New.run([\"hello_world\"])\n\n        assert_file(\"hello_world/mix.exs\", fn file ->\n          assert file =~ \"deps_path: \\\"../../deps\\\"\"\n          assert file =~ \"lockfile: \\\"../../mix.lock\\\"\"\n        end)\n\n        # Ensure formatting is setup and consistent.\n        File.cd!(\"hello_world\", fn ->\n          Mix.Tasks.Format.run([\"--check-formatted\"])\n        end)\n      end)\n    end)\n  end\n\n  test \"new with dot\" do\n    in_tmp(\"new_with_dot\", fn ->\n      Mix.Tasks.New.run([\".\"])\n      assert_file(\"lib/new_with_dot.ex\", ~r/defmodule NewWithDot do/)\n    end)\n  end\n\n  test \"new with invalid args\" do\n    in_tmp(\"new with an invalid application name\", fn ->\n      assert_raise Mix.Error,\n                   ~r\"Application name must start with a lowercase ASCII letter\",\n                   fn ->\n                     Mix.Tasks.New.run([\"007invalid\"])\n                   end\n\n      assert_raise Mix.Error,\n                   ~r\"Cannot use application name \\\"tools\\\" because it is already used by Erlang/OTP or Elixir\",\n                   fn ->\n                     Mix.Tasks.New.run([\"tools\"])\n                   end\n\n      assert_raise Mix.Error,\n                   ~r\"Cannot use application name \\\"pa\\\" because it is already used by Erlang/OTP or Elixir\",\n                   fn ->\n                     Mix.Tasks.New.run([\"pa\"])\n                   end\n\n      assert_raise Mix.Error,\n                   ~r\"followed by lowercase ASCII letters, numbers, or underscores\",\n                   fn ->\n                     Mix.Tasks.New.run([\"invAlid\"])\n                   end\n\n      assert_raise Mix.Error,\n                   ~r\"followed by lowercase ASCII letters, numbers, or underscores\",\n                   fn ->\n                     Mix.Tasks.New.run([\"inválido\"])\n                   end\n    end)\n\n    in_tmp(\"new with an invalid application name from the app option\", fn ->\n      assert_raise Mix.Error, ~r\"Application name must start with a lowercase ASCII letter\", fn ->\n        Mix.Tasks.New.run([\"valid\", \"--app\", \"007invalid\"])\n      end\n    end)\n\n    in_tmp(\"new with an invalid module name from the module options\", fn ->\n      assert_raise Mix.Error, ~r\"Module name must be a valid Elixir alias\", fn ->\n        Mix.Tasks.New.run([\"valid\", \"--module\", \"not.valid\"])\n      end\n    end)\n\n    in_tmp(\"new with an already taken module name from the module options\", fn ->\n      assert_raise Mix.Error, ~r\"Module name \\w+ is already taken\", fn ->\n        Mix.Tasks.New.run([\"valid\", \"--module\", \"Mix\"])\n      end\n    end)\n\n    in_tmp(\"new without a specified path\", fn ->\n      assert_raise Mix.Error,\n                   \"Expected PATH to be given. Use \\\"mix new PATH\\\" or run \\\"mix help new\\\" for more information\",\n                   fn ->\n                     Mix.Tasks.New.run([])\n                   end\n    end)\n  end\n\n  test \"new with existent directory\" do\n    in_tmp(\"new_with_existent_directory\", fn ->\n      File.mkdir_p!(\"my_app\")\n      send(self(), {:mix_shell_input, :yes?, false})\n\n      assert_raise Mix.Error, \"Please select another directory for installation\", fn ->\n        Mix.Tasks.New.run([\"my_app\"])\n      end\n    end)\n  end\n\n  defp assert_file(file) do\n    assert File.regular?(file), \"Expected #{file} to exist, but does not\"\n  end\n\n  defp assert_file(file, match) do\n    cond do\n      is_struct(match, Regex) ->\n        assert_file(file, &assert(&1 =~ match))\n\n      is_function(match, 1) ->\n        assert_file(file)\n        match.(File.read!(file))\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/profile.cprof_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Profile.CprofTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n  alias Mix.Tasks.Profile.Cprof\n\n  @expr \"Enum.each(1..5, &String.Chars.Integer.to_string/1)\"\n\n  test \"profiles evaluated expression\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Cprof.run([\"-e\", @expr])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1 *\\d/\n    end)\n  end\n\n  test \"profiles the script\", context do\n    in_tmp(context.test, fn ->\n      profile_script_name = \"profile_script.ex\"\n\n      File.write!(profile_script_name, @expr)\n\n      assert capture_io(fn ->\n               Cprof.run([profile_script_name])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1 *\\d/\n    end)\n  end\n\n  test \"filters based on limit\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Cprof.run([\"--limit\", \"5\", \"-e\", @expr])\n             end) =~ ~r/:erlang\\.trace_pattern\\/3 *\\d/\n    end)\n  end\n\n  test \"filters based on module\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Cprof.run([\"--module\", \"Enum\", \"-e\", @expr])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1 *\\d/\n    end)\n  end\n\n  test \"Module matching\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Cprof.run([\"--matching\", \"Enum\", \"-e\", @expr])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1 *\\d/\n    end)\n  end\n\n  test \"Module.function matching\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Cprof.run([\"--matching\", \"Enum.each\", \"-e\", @expr])\n             end) =~ ~r/anonymous fn\\/3 in Enum\\.each\\/2 *\\d/\n    end)\n  end\n\n  test \"Module.function/arity matching\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Cprof.run([\"--matching\", \"Enum.each/8\", \"-e\", @expr])\n             end) =~ ~r/Profile done over 0 matching functions/\n    end)\n  end\n\n  test \"errors on missing files\", context do\n    in_tmp(context.test, fn ->\n      msg = \"No files matched pattern \\\"non-existent\\\" given to --require\"\n\n      assert_raise Mix.Error, msg, fn ->\n        capture_io(fn -> Cprof.run([\"-r\", \"non-existent\"]) end)\n      end\n\n      assert_raise Mix.Error, msg, fn ->\n        capture_io(fn -> Cprof.run([\"-pr\", \"non-existent\"]) end)\n      end\n\n      assert_raise Mix.Error, \"No such file: non-existent\", fn ->\n        capture_io(fn -> Cprof.run([\"non-existent\"]) end)\n      end\n\n      File.mkdir_p!(\"lib\")\n\n      assert_raise Mix.Error, \"No such file: lib\", fn ->\n        capture_io(fn -> Cprof.run([\"lib\"]) end)\n      end\n    end)\n  end\n\n  test \"warmup\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Cprof.run([\"-e\", @expr])\n             end) =~ \"Warmup...\"\n\n      refute capture_io(fn ->\n               Cprof.run([\"-e\", \"Enum.each(1..5, fn(_) -> MapSet.new() end)\", \"--no-warmup\"])\n             end) =~ \"Warmup...\"\n    end)\n  end\n\n  describe \".profile/2\" do\n    test \"returns the return value of the function call\" do\n      capture_io(fn ->\n        assert 42 == Cprof.profile(fn -> 42 end)\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/profile.eprof_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Profile.EprofTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n  alias Mix.Tasks.Profile.Eprof\n\n  @expr \"Enum.each(1..5, &String.Chars.Integer.to_string/1)\"\n\n  test \"profiles evaluated expression\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Eprof.run([\"-e\", @expr])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1\\s+\\d/\n    end)\n  end\n\n  test \"profiles evaluated expression in multiple processes\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Eprof.run([\"-e\", \"spawn(fn -> #{@expr} end)\"])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1\\s+\\d/\n    end)\n  end\n\n  test \"profiles the script\", context do\n    in_tmp(context.test, fn ->\n      profile_script_name = \"profile_script.ex\"\n      File.write!(profile_script_name, @expr)\n\n      assert capture_io(fn ->\n               Eprof.run([profile_script_name])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1\\s+\\d/\n    end)\n  end\n\n  test \"filters based on count\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Eprof.run([\"--calls\", \"5\", \"-e\", @expr])\n             end) =~ \":erlang.apply/2\"\n    end)\n  end\n\n  test \"sorts based on the calls count\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Eprof.run([\"--sort\", \"calls\", \"-e\", @expr])\n             end) =~ ~r/erlang\\.apply\\/2.*String\\.Chars\\.Integer\\.to_string\\/1/s\n    end)\n  end\n\n  test \"Module matching\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Eprof.run([\"--matching\", \"Enum\", \"-e\", @expr])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1/\n    end)\n  end\n\n  test \"Module.function matching\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Eprof.run([\"--matching\", \"Enum.each\", \"-e\", @expr])\n             end) =~ ~r/anonymous fn\\/3 in Enum\\.each\\/2/\n    end)\n  end\n\n  test \"Module.function/arity matching\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Eprof.run([\"--matching\", \"Enum.each/8\", \"-e\", @expr])\n             end) =~ ~r/Profile done over 0 matching functions/\n    end)\n  end\n\n  test \"errors on missing files\", context do\n    in_tmp(context.test, fn ->\n      message = \"No files matched pattern \\\"non-existent\\\" given to --require\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Eprof.run([\"-r\", \"non-existent\"]) end)\n      end\n\n      message = \"No files matched pattern \\\"non-existent\\\" given to --require\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Eprof.run([\"-pr\", \"non-existent\"]) end)\n      end\n\n      assert_raise Mix.Error, \"No such file: non-existent\", fn ->\n        capture_io(fn -> Eprof.run([\"non-existent\"]) end)\n      end\n\n      File.mkdir_p!(\"lib\")\n\n      assert_raise Mix.Error, \"No such file: lib\", fn ->\n        capture_io(fn -> Eprof.run([\"lib\"]) end)\n      end\n    end)\n  end\n\n  test \"warmup\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Eprof.run([\"-e\", @expr])\n             end) =~ \"Warmup...\"\n\n      refute capture_io(fn ->\n               Eprof.run([\"-e\", @expr, \"--no-warmup\"])\n             end) =~ \"Warmup...\"\n    end)\n  end\n\n  describe \".profile/2\" do\n    test \"returns the return value of the function call\" do\n      capture_io(fn ->\n        assert 42 == Eprof.profile(fn -> 42 end)\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/profile.fprof_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Profile.FprofTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n  alias Mix.Tasks.Profile.Fprof\n\n  test \"profiles evaluated expression\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Fprof.run([\"-e\", \"Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\"])\n             end) =~ ~r(MapSet\\.new/1 *5 *\\d+\\.\\d{3} *\\d+\\.\\d{3})\n    end)\n  end\n\n  test \"profiles the script\", context do\n    in_tmp(context.test, fn ->\n      profile_script_name = \"profile_script.ex\"\n\n      File.write!(profile_script_name, \"\"\"\n      Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\n      \"\"\")\n\n      assert capture_io(fn ->\n               Fprof.run([profile_script_name])\n             end) =~ ~r(MapSet\\.new/1 *5 *\\d+\\.\\d{3} *\\d+\\.\\d{3})\n    end)\n  end\n\n  test \"expands callers\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Fprof.run([\"-e\", \"Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\", \"--callers\"])\n             end) =~ ~r(MapSet\\.new/1 *5 *\\d+\\.\\d{3} *\\d+\\.\\d{3} +<--)\n    end)\n  end\n\n  test \"writes traces to file\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               expr = \"Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\"\n               Fprof.run([\"-e\", expr, \"--trace-to-file\"])\n             end) =~ ~r(MapSet\\.new/1 *5 *\\d+\\.\\d{3} *\\d+\\.\\d{3})\n    end)\n  end\n\n  test \"expands processes\", context do\n    in_tmp(context.test, fn ->\n      expr =\n        \"spawn(fn -> Process.sleep(:infinity) end); Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\"\n\n      output = capture_io(fn -> Fprof.run([\"-e\", expr, \"--details\"]) end)\n      assert output =~ ~r/#{:erlang.pid_to_list(self())} +\\d+ +\\d+\\.\\d{3}/\n      assert output =~ ~r/spawned by #{:erlang.pid_to_list(self())}/\n      assert output =~ ~r/as :erlang.apply/\n      assert output =~ ~r/initial calls:/\n    end)\n  end\n\n  test \"sort options\", context do\n    in_tmp(context.test, fn ->\n      expr = \"Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\"\n\n      assert capture_io(fn -> Fprof.run([\"-e\", expr, \"--sort\", \"acc\"]) end) =~\n               ~r(MapSet\\.new/1 *5 *\\d+\\.\\d{3} *\\d+\\.\\d{3})\n\n      expr = \"Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\"\n\n      assert capture_io(fn -> Fprof.run([\"-e\", expr, \"--sort\", \"own\"]) end) =~\n               ~r(MapSet\\.new/1 *5 *\\d+\\.\\d{3} *\\d+\\.\\d{3})\n    end)\n  end\n\n  test \"errors on missing files\", context do\n    in_tmp(context.test, fn ->\n      message = \"No files matched pattern \\\"non-existent\\\" given to --require\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Fprof.run([\"-r\", \"non-existent\"]) end)\n      end\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Fprof.run([\"-pr\", \"non-existent\"]) end)\n      end\n\n      assert_raise Mix.Error, \"No such file: non-existent\", fn ->\n        capture_io(fn -> Fprof.run([\"non-existent\"]) end)\n      end\n\n      File.mkdir_p!(\"lib\")\n\n      assert_raise Mix.Error, \"No such file: lib\", fn ->\n        capture_io(fn -> Fprof.run([\"lib\"]) end)\n      end\n    end)\n  end\n\n  test \"warmup\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Fprof.run([\"-e\", \"Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\"])\n             end) =~ \"Warmup...\"\n\n      refute capture_io(fn ->\n               Fprof.run([\"-e\", \"Enum.each(1..5, fn(_) -> MapSet.new(1..3) end)\", \"--no-warmup\"])\n             end) =~ \"Warmup...\"\n    end)\n  end\n\n  describe \".profile/2\" do\n    test \"returns the return value of the function call\" do\n      capture_io(fn ->\n        assert 42 == Fprof.profile(fn -> 42 end)\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/profile.tprof_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Profile.TprofTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n  alias Mix.Tasks.Profile.Tprof\n\n  @expr \"Enum.each(1..5, &String.Chars.Integer.to_string/1)\"\n\n  test \"profiles evaluated expression\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Tprof.run([\"-e\", @expr])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1\\s+\\d/\n    end)\n  end\n\n  test \"profiles evaluated expression in multiple processes\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Tprof.run([\"-e\", \"spawn(fn -> #{@expr} end)\"])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1\\s+\\d/\n    end)\n  end\n\n  test \"profiles the script\", context do\n    in_tmp(context.test, fn ->\n      profile_script_name = \"profile_script.ex\"\n      File.write!(profile_script_name, @expr)\n\n      assert capture_io(fn ->\n               Tprof.run([profile_script_name])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1\\s+\\d/\n    end)\n  end\n\n  test \"filters based on calls count\", context do\n    in_tmp(context.test, fn ->\n      result =\n        capture_io(fn ->\n          Tprof.run([\"--calls\", \"5\", \"-e\", @expr])\n        end)\n\n      assert result =~ \"\\nString.Chars.Integer.to_string/1\"\n      refute result =~ \"\\nEnum.each/2\"\n    end)\n  end\n\n  test \"filters based on memory\", context do\n    in_tmp(context.test, fn ->\n      result =\n        capture_io(fn ->\n          Tprof.run([\"--type\", \"memory\", \"--memory\", \"10\", \"-e\", @expr])\n        end)\n\n      assert result =~ \"\\n:erlang.integer_to_binary/1\"\n      refute result =~ \"\\nEnum.each/2\"\n    end)\n  end\n\n  test \"sorts based on calls count\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Tprof.run([\"--sort\", \"calls\", \"-e\", @expr])\n             end) =~ ~r/\\nEnum\\.each\\/2.*\\nString\\.Chars\\.Integer\\.to_string\\/1/s\n    end)\n  end\n\n  test \"sorts based on memory usage\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Tprof.run([\"--type\", \"memory\", \"--sort\", \"calls\", \"-e\", @expr])\n             end) =~ ~r/\\nEnum\\.each\\/2.*\\n:erlang\\.integer_to_binary\\/1/s\n    end)\n  end\n\n  test \"aggregates totals over all processes\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Tprof.run([\"--report\", \"total\", \"-e\", @expr])\n             end) =~ \"Profile results over all processes\"\n    end)\n  end\n\n  test \"Module matching\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Tprof.run([\"--matching\", \"Enum\", \"-e\", @expr])\n             end) =~ ~r/String\\.Chars\\.Integer\\.to_string\\/1/\n    end)\n  end\n\n  test \"Module.function matching\", context do\n    in_tmp(context.test, fn ->\n      refute capture_io(fn ->\n               Tprof.run([\"--matching\", \"Enum.each\", \"-e\", @expr])\n             end) =~ ~r/anonymous fn\\/3 in Enum\\.each\\/2/\n    end)\n  end\n\n  test \"Module.function/arity matching\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Tprof.run([\"--matching\", \"Enum.each/8\", \"-e\", @expr])\n             end) =~ ~r/Profile done over 0 matching functions/\n    end)\n  end\n\n  test \"errors on missing files\", context do\n    in_tmp(context.test, fn ->\n      message = \"No files matched pattern \\\"non-existent\\\" given to --require\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Tprof.run([\"-r\", \"non-existent\"]) end)\n      end\n\n      message = \"No files matched pattern \\\"non-existent\\\" given to --require\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Tprof.run([\"-pr\", \"non-existent\"]) end)\n      end\n\n      assert_raise Mix.Error, \"No such file: non-existent\", fn ->\n        capture_io(fn -> Tprof.run([\"non-existent\"]) end)\n      end\n\n      File.mkdir_p!(\"lib\")\n\n      assert_raise Mix.Error, \"No such file: lib\", fn ->\n        capture_io(fn -> Tprof.run([\"lib\"]) end)\n      end\n    end)\n  end\n\n  test \"warmup\", context do\n    in_tmp(context.test, fn ->\n      assert capture_io(fn ->\n               Tprof.run([\"-e\", @expr])\n             end) =~ \"Warmup...\"\n\n      refute capture_io(fn ->\n               Tprof.run([\"-e\", @expr, \"--no-warmup\"])\n             end) =~ \"Warmup...\"\n    end)\n  end\n\n  test \"errors on incompatible options\", context do\n    in_tmp(context.test, fn ->\n      message = \"Incompatible sort option :memory with type :time\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Tprof.run([\"-e\", @expr, \"--sort\", \"memory\"]) end)\n      end\n\n      message = \"Incompatible sort option :time with type :calls\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Tprof.run([\"-e\", @expr, \"--type\", \"calls\", \"--sort\", \"time\"]) end)\n      end\n\n      message = \"Incompatible use of memory option with type :time\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Tprof.run([\"-e\", @expr, \"--time\", \"1\", \"--memory\", \"2\"]) end)\n      end\n\n      message = \"Incompatible use of time option with type :calls\"\n\n      assert_raise Mix.Error, message, fn ->\n        capture_io(fn -> Tprof.run([\"-e\", @expr, \"--type\", \"calls\", \"--time\", \"1\"]) end)\n      end\n    end)\n  end\n\n  describe \".profile/2\" do\n    test \"returns the return value of the function call\" do\n      capture_io(fn ->\n        assert 42 == Tprof.profile(fn -> 42 end)\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/release.init_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Release.InitTest do\n  use MixTest.Case\n\n  test \"copies templates as is\" do\n    in_tmp(\"release_init\", fn ->\n      Mix.Task.run(\"release.init\", [])\n      assert_received {:mix_shell, :info, [\"* creating rel/vm.args.eex\"]}\n      assert_received {:mix_shell, :info, [\"* creating rel/remote.vm.args.eex\"]}\n      assert_received {:mix_shell, :info, [\"* creating rel/env.sh.eex\"]}\n      assert_received {:mix_shell, :info, [\"* creating rel/env.bat.eex\"]}\n\n      assert File.exists?(\"rel/vm.args.eex\")\n      assert File.exists?(\"rel/remote.vm.args.eex\")\n      assert File.exists?(\"rel/env.sh.eex\")\n      assert File.exists?(\"rel/env.bat.eex\")\n    end)\n  end\n\n  test \"can be set to --force and --quiet\" do\n    in_tmp(\"release_init\", fn ->\n      Mix.Task.run(\"release.init\", [\"--force\", \"--quiet\"])\n      Mix.Task.run(\"release.init\", [\"--force\", \"--quiet\"])\n      refute_received {:mix_shell, :info, [\"* creating rel/vm.args.eex\"]}\n      refute_received {:mix_shell, :info, [\"* creating rel/remote.vm.args.eex\"]}\n      refute_received {:mix_shell, :info, [\"* creating rel/env.sh.eex\"]}\n      refute_received {:mix_shell, :info, [\"* creating rel/env.bat.eex\"]}\n    end)\n  end\n\n  test \"raises on bad input\" do\n    assert_raise OptionParser.ParseError,\n                 ~r\"--unknown : Unknown option\",\n                 fn -> Mix.Tasks.Release.Init.run([\"--unknown\"]) end\n\n    assert_raise Mix.Error,\n                 ~r/Expected \"mix release.init\" without arguments, got: \\[\"foo\", \"bar\"\\]/,\n                 fn -> Mix.Tasks.Release.Init.run([\"foo\", \"bar\"]) end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/release_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.ReleaseTest do\n  use MixTest.Case\n\n  @erts_version :erlang.system_info(:version)\n  @hostname :inet_db.gethostname()\n\n  defmacrop release_node(name), do: :\"#{name}@#{@hostname}\"\n\n  describe \"customize\" do\n    test \"env, vm.args and overlays templates\" do\n      in_fixture(\"release_test\", fn ->\n        Mix.Project.in_project(:release_test, \".\", fn _ ->\n          File.mkdir_p!(\"rel/overlays/empty/directory\")\n          File.write!(\"rel/overlays/hello\", \"world\")\n\n          for file <- ~w(rel/vm.args.eex rel/remote.vm.args.eex rel/env.sh.eex rel/env.bat.eex) do\n            File.write!(file, \"\"\"\n            #{file} FOR <%= @release.name %>\n            \"\"\")\n          end\n\n          root = Path.absname(\"_build/dev/rel/release_test\")\n          Mix.Task.run(\"release\")\n          assert_received {:mix_shell, :info, [\"* assembling release_test-0.1.0 on MIX_ENV=dev\"]}\n\n          assert root |> Path.join(\"releases/0.1.0/env.sh\") |> File.read!() ==\n                   \"rel/env.sh.eex FOR release_test\\n\"\n\n          assert root |> Path.join(\"releases/0.1.0/env.bat\") |> File.read!() ==\n                   \"rel/env.bat.eex FOR release_test\\n\"\n\n          assert root |> Path.join(\"releases/0.1.0/vm.args\") |> File.read!() ==\n                   \"rel/vm.args.eex FOR release_test\\n\"\n\n          assert root |> Path.join(\"releases/0.1.0/remote.vm.args\") |> File.read!() ==\n                   \"rel/remote.vm.args.eex FOR release_test\\n\"\n\n          assert root |> Path.join(\"empty/directory\") |> File.dir?()\n          assert root |> Path.join(\"hello\") |> File.read!() == \"world\"\n        end)\n      end)\n    end\n\n    test \"env, vm.args and overlays templates with custom rel_templates_path\" do\n      in_fixture(\"release_test\", fn ->\n        config = [\n          releases: [\n            release_test: [rel_templates_path: \"custom_rel\"]\n          ]\n        ]\n\n        Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n          File.mkdir_p!(\"custom_rel/overlays/empty/directory\")\n          File.write!(\"custom_rel/overlays/hello\", \"world\")\n\n          for file <-\n                ~w(custom_rel/vm.args.eex custom_rel/remote.vm.args.eex custom_rel/env.sh.eex custom_rel/env.bat.eex) do\n            File.write!(file, \"\"\"\n            #{file} FOR <%= @release.name %>\n            \"\"\")\n          end\n\n          root = Path.absname(\"_build/dev/rel/release_test\")\n          Mix.Task.run(\"release\")\n          assert_received {:mix_shell, :info, [\"* assembling release_test-0.1.0 on MIX_ENV=dev\"]}\n\n          assert root |> Path.join(\"releases/0.1.0/env.sh\") |> File.read!() ==\n                   \"custom_rel/env.sh.eex FOR release_test\\n\"\n\n          assert root |> Path.join(\"releases/0.1.0/env.bat\") |> File.read!() ==\n                   \"custom_rel/env.bat.eex FOR release_test\\n\"\n\n          assert root |> Path.join(\"releases/0.1.0/vm.args\") |> File.read!() ==\n                   \"custom_rel/vm.args.eex FOR release_test\\n\"\n\n          assert root |> Path.join(\"releases/0.1.0/remote.vm.args\") |> File.read!() ==\n                   \"custom_rel/remote.vm.args.eex FOR release_test\\n\"\n\n          assert root |> Path.join(\"empty/directory\") |> File.dir?()\n          assert root |> Path.join(\"hello\") |> File.read!() == \"world\"\n        end)\n      end)\n    end\n\n    test \"custom overlays\" do\n      in_fixture(\"release_test\", fn ->\n        config = [releases: [release_test: [overlays: \"rel/another\"]]]\n\n        Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n          File.mkdir_p!(\"rel/overlays\")\n          File.write!(\"rel/overlays/hello\", \"world\")\n          File.write!(\"rel/overlays/original\", \"kept\")\n\n          File.mkdir_p!(\"rel/another/empty/directory\")\n          File.write!(\"rel/another/hello\", \"override\")\n\n          root = Path.absname(\"_build/dev/rel/release_test\")\n          Mix.Task.rerun(\"release\", [\"--overwrite\"])\n\n          assert root |> Path.join(\"empty/directory\") |> File.dir?()\n          assert root |> Path.join(\"hello\") |> File.read!() == \"override\"\n          assert root |> Path.join(\"original\") |> File.read!() == \"kept\"\n        end)\n      end)\n    end\n\n    test \"steps\" do\n      in_fixture(\"release_test\", fn ->\n        last_step = fn release ->\n          send(self(), {:last_step, release})\n          release\n        end\n\n        first_step = fn release ->\n          send(self(), {:first_step, release})\n          update_in(release.steps, &(&1 ++ [last_step]))\n        end\n\n        config = [releases: [demo: [steps: [first_step, :assemble]]]]\n\n        Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n          Mix.Task.run(\"release\")\n          assert_received {:mix_shell, :info, [\"* assembling demo-0.1.0 on MIX_ENV=dev\"]}\n\n          # Discard info messages from inbox for upcoming assertions\n          Mix.shell().flush(& &1)\n\n          {:messages,\n           [\n             {:first_step, %Mix.Release{steps: [:assemble]}},\n             {:last_step, %Mix.Release{steps: []}}\n           ]} = Process.info(self(), :messages)\n        end)\n      end)\n    end\n\n    test \"include_executables_for and strip_beams\" do\n      in_fixture(\"release_test\", fn ->\n        config = [\n          releases: [\n            release_test: [\n              include_executables_for: [],\n              strip_beams: [keep: \"Docs\"]\n            ]\n          ]\n        ]\n\n        Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n          root = Path.absname(\"_build/dev/rel/release_test\")\n          Mix.Task.run(\"release\")\n          assert_received {:mix_shell, :info, [\"* assembling release_test-0.1.0 on MIX_ENV=dev\"]}\n\n          beam =\n            File.read!(Path.join(root, \"lib/release_test-0.1.0/ebin/Elixir.ReleaseTest.beam\"))\n\n          assert {:ok, {_, [{~c\"Docs\", _}]}} = :beam_lib.chunks(beam, [~c\"Docs\"])\n          assert {:error, _, _} = :beam_lib.chunks(beam, [~c\"Dbgi\"])\n\n          refute root |> Path.join(\"bin/start\") |> File.exists?()\n          refute root |> Path.join(\"bin/start.bat\") |> File.exists?()\n          refute root |> Path.join(\"releases/0.1.0/elixir\") |> File.exists?()\n          refute root |> Path.join(\"releases/0.1.0/elixir.bat\") |> File.exists?()\n          refute root |> Path.join(\"releases/0.1.0/iex\") |> File.exists?()\n          refute root |> Path.join(\"releases/0.1.0/iex.bat\") |> File.exists?()\n        end)\n      end)\n    end\n  end\n\n  describe \"errors\" do\n    test \"requires a matching name\" do\n      in_fixture(\"release_test\", fn ->\n        Mix.Project.in_project(:release_test, \".\", fn _ ->\n          assert_raise Mix.Error, ~r\"Unknown release :unknown\", fn ->\n            Mix.Task.run(\"release\", [\"unknown\"])\n          end\n        end)\n      end)\n    end\n  end\n\n  describe \"tar\" do\n    test \"with default options\" do\n      in_fixture(\"release_test\", fn ->\n        config = [releases: [demo: [steps: [:assemble, :tar]]]]\n\n        Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n          root = Path.absname(\"_build/#{Mix.env()}/rel/demo\")\n\n          ignored_app_path = Path.join([root, \"lib\", \"ignored_app-0.1.0\", \"ebin\"])\n          File.mkdir_p!(ignored_app_path)\n          File.touch(Path.join(ignored_app_path, \"ignored_app.app\"))\n\n          ignored_release_path = Path.join([root, \"releases\", \"ignored_dir\"])\n          File.mkdir_p!(ignored_release_path)\n          File.touch(Path.join(ignored_release_path, \"ignored\"))\n\n          # Overlays\n          File.mkdir_p!(\"rel/overlays/empty/directory\")\n          File.write!(\"rel/overlays/hello\", \"world\")\n\n          Mix.Task.run(\"release\")\n          tar_path = Path.expand(Path.join([root, \"..\", \"..\", \"demo-0.1.0.tar.gz\"]))\n          message = \"* building #{tar_path}\"\n          assert_received {:mix_shell, :info, [^message]}\n          assert File.exists?(tar_path)\n\n          {:ok, files} = String.to_charlist(tar_path) |> :erl_tar.table([:compressed])\n\n          files = Enum.map(files, &to_string/1)\n          files_with_versions = File.ls!(Path.join(root, \"lib\"))\n\n          assert \"bin/demo\" in files\n          assert \"releases/0.1.0/sys.config\" in files\n          assert \"releases/0.1.0/vm.args\" in files\n          assert \"releases/0.1.0/remote.vm.args\" in files\n          assert \"releases/COOKIE\" in files\n          assert \"releases/start_erl.data\" in files\n          assert \"hello\" in files\n          assert \"empty/directory\" in files\n          assert Enum.any?(files, &(&1 =~ \"erts\"))\n          assert Enum.any?(files, &(&1 =~ \"stdlib\"))\n\n          for dir <- files_with_versions -- [\"ignored_app-0.1.0\"] do\n            [name | _] = String.split(dir, \"-\")\n            assert \"lib/#{dir}/ebin/#{name}.app\" in files\n          end\n\n          refute \"lib/ignored_app-0.1.0/ebin/ignored_app.app\" in files\n          refute \"releases/ignored_dir/ignored\" in files\n        end)\n      end)\n    end\n\n    test \"without ERTS and custom path\" do\n      in_fixture(\"release_test\", fn ->\n        config = [\n          releases: [demo: [include_erts: false, path: \"tmp/rel\", steps: [:assemble, :tar]]]\n        ]\n\n        Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n          Mix.Task.run(\"release\")\n          tar_path = Path.expand(Path.join([\"tmp\", \"rel\", \"demo-0.1.0.tar.gz\"]))\n          message = \"* building #{tar_path}\"\n          assert_received {:mix_shell, :info, [^message]}\n          assert File.exists?(tar_path)\n\n          {:ok, files} = String.to_charlist(tar_path) |> :erl_tar.table([:compressed])\n          files = Enum.map(files, &to_string/1)\n\n          assert \"bin/demo\" in files\n          refute Enum.any?(files, &(&1 =~ \"erts\"))\n          refute Enum.any?(files, &(&1 =~ \"stdlib\"))\n        end)\n      end)\n    end\n\n    test \"without ERTS when a previous build included ERTS\" do\n      in_fixture(\"release_test\", fn ->\n        config = [releases: [demo: [include_erts: false, steps: [:assemble, :tar]]]]\n\n        Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n          root = Path.absname(\"_build/#{Mix.env()}/rel/demo\")\n\n          erts_dir_from_previous_build =\n            Path.absname(\"_build/#{Mix.env()}/rel/demo/erts-#{@erts_version}\")\n\n          File.mkdir_p!(erts_dir_from_previous_build)\n\n          Mix.Task.run(\"release\")\n          tar_path = Path.expand(Path.join([root, \"..\", \"..\", \"demo-0.1.0.tar.gz\"]))\n          message = \"* building #{tar_path}\"\n          assert_received {:mix_shell, :info, [^message]}\n          assert File.exists?(tar_path)\n\n          {:ok, files} = String.to_charlist(tar_path) |> :erl_tar.table([:compressed])\n          files = Enum.map(files, &to_string/1)\n\n          assert \"bin/demo\" in files\n          refute Enum.any?(files, &(&1 =~ \"erts\"))\n          refute Enum.any?(files, &(&1 =~ \"stdlib\"))\n        end)\n      end)\n    end\n  end\n\n  test \"assembles a bootable release with ERTS\" do\n    in_fixture(\"release_test\", fn ->\n      Mix.Project.in_project(:release_test, \".\", fn _ ->\n        root = Path.absname(\"_build/dev/rel/release_test\")\n\n        # Assert command\n        Mix.Task.run(\"release\")\n        assert_received {:mix_shell, :info, [\"* assembling release_test-0.1.0 on MIX_ENV=dev\"]}\n\n        assert_received {:mix_shell, :info,\n                         [\"\\nRelease created at _build/dev/rel/release_test\\n\" <> _]}\n\n        assert_received {:mix_shell, :info, [\"* skipping runtime configuration\" <> _]}\n\n        # Assert structure\n        assert root |> Path.join(\"erts-#{@erts_version}\") |> File.exists?()\n        assert root |> Path.join(\"lib/release_test-0.1.0/ebin\") |> File.exists?()\n        assert root |> Path.join(\"lib/release_test-0.1.0/priv/hello\") |> File.exists?()\n        assert root |> Path.join(\"releases/COOKIE\") |> File.exists?()\n        assert root |> Path.join(\"releases/start_erl.data\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.1.0/release_test.rel\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.1.0/sys.config\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.1.0/env.sh\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.1.0/env.bat\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.1.0/vm.args\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.1.0/remote.vm.args\") |> File.exists?()\n\n        assert root\n               |> Path.join(\"releases/0.1.0/sys.config\")\n               |> File.read!() =~ \"RUNTIME_CONFIG=false\"\n\n        assert root\n               |> Path.join(\"lib/release_test-0.1.0/priv\")\n               |> File.read_link()\n               |> elem(0) == :error\n\n        cookie = File.read!(Path.join(root, \"releases/COOKIE\"))\n\n        # Assert runtime\n        open_port(Path.join(root, \"bin/release_test\"), [~c\"start\"])\n\n        assert %{\n                 app_dir: app_dir,\n                 cookie_env: ^cookie,\n                 encoding: {:_μ, :\"£\", \"£\", ~c\"£\"},\n                 mode: :embedded,\n                 node: release_node(\"release_test\"),\n                 protocols_consolidated?: true,\n                 release_name: \"release_test\",\n                 release_node: \"release_test\",\n                 release_prog: \"release_test\" <> ext,\n                 release_root: release_root,\n                 release_vsn: \"0.1.0\",\n                 root_dir: root_dir,\n                 runtime_config: :error,\n                 static_config: {:ok, :was_set},\n                 sys_config_env: sys_config_env,\n                 sys_config_init: sys_config_init\n               } = wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n\n        if match?({:win32, _}, :os.type()) do\n          # `RELEAS~1` is the DOS path name (8 character) for the `release_test` directory\n          assert app_dir =~ ~r\"_build/dev/rel/(release_test|RELEAS~1)/lib/release_test-0\\.1\\.0$\"\n          assert release_root =~ ~r\"_build\\\\dev\\\\rel\\\\(release_test|RELEAS~1)$\"\n          assert root_dir =~ ~r\"_build/dev/rel/(release_test|RELEAS~1)$\"\n          assert String.ends_with?(sys_config_env, \"releases\\\\0.1.0\\\\sys\")\n          assert String.ends_with?(sys_config_init, \"releases\\\\0.1.0\\\\sys\")\n          assert ext == \".bat\"\n        else\n          assert app_dir == Path.join(root, \"lib/release_test-0.1.0\")\n          assert release_root == root\n          assert root_dir == root\n          assert sys_config_env == Path.join(root, \"releases/0.1.0/sys\")\n          assert sys_config_init == Path.join(root, \"releases/0.1.0/sys\")\n          assert ext == \"\"\n        end\n      end)\n    end)\n  end\n\n  test \"assembles a rebootable release with runtime configuration\" do\n    in_fixture(\"release_test\", fn ->\n      config = [releases: [runtime_config: [reboot_system_after_config: true]]]\n\n      Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n        File.write!(\"config/config.exs\", \"\"\"\n        #{File.read!(\"config/config.exs\")}\n        config :release_test, :runtime, keep: :static, override: :static\n        \"\"\")\n\n        File.write!(\"config/runtime.exs\", \"\"\"\n        import Config\n\n        if System.get_env(\"RELEASE_MODE\") == nil do\n          raise \"file should not be loaded while assembling release\"\n        end\n\n        # Ensure app has been loaded\n        [_ | _] = Application.spec(:release_test, :modules)\n\n        config :release_test, :runtime,\n          override: :runtime,\n          config_env: config_env(),\n          config_target: config_target(),\n          mode: :code.get_mode()\n\n        config :release_test, :encoding, {:runtime, :_μ, :\"£\", \"£\", ~c\"£\"}\n        \"\"\")\n\n        root = Path.absname(\"_build/dev/rel/runtime_config\")\n\n        # Assert command\n        Mix.Task.run(\"release\", [\"runtime_config\"])\n        assert_received {:mix_shell, :info, [\"* assembling runtime_config-0.1.0 on MIX_ENV=dev\"]}\n\n        assert_received {:mix_shell, :info,\n                         [\"* using config/runtime.exs to configure the release at runtime\"]}\n\n        # Assert structure\n        assert root\n               |> Path.join(\"releases/0.1.0/sys.config\")\n               |> File.read!() =~ \"RUNTIME_CONFIG=true\"\n\n        # Make sys.config read-only and it should still boot\n        assert root\n               |> Path.join(\"releases/0.1.0/sys.config\")\n               |> File.chmod(0o555) == :ok\n\n        # Assert runtime\n        open_port(Path.join(root, \"bin/runtime_config\"), [~c\"start\"])\n\n        assert %{\n                 encoding: {:runtime, :_μ, :\"£\", \"£\", ~c\"£\"},\n                 mode: :embedded,\n                 node: release_node(\"runtime_config\"),\n                 protocols_consolidated?: true,\n                 release_name: \"runtime_config\",\n                 release_mode: \"embedded\",\n                 release_node: \"runtime_config\",\n                 release_prog: \"runtime_config\" <> ext,\n                 release_vsn: \"0.1.0\",\n                 runtime_config:\n                   {:ok,\n                    [\n                      keep: :static,\n                      override: :runtime,\n                      config_env: :dev,\n                      config_target: :host,\n                      mode: :interactive\n                    ]},\n                 static_config: {:ok, :was_set},\n                 sys_config_env: sys_config_env,\n                 sys_config_init: sys_config_init\n               } = wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n\n        if match?({:win32, _}, :os.type()) do\n          assert sys_config_env =~ \"tmp\\\\runtime_config-0.1.0\"\n          assert sys_config_init =~ \"tmp\\\\runtime_config-0.1.0\"\n          assert ext == \".bat\"\n        else\n          assert sys_config_env =~ \"tmp/runtime_config-0.1.0\"\n          assert sys_config_init =~ \"tmp/runtime_config-0.1.0\"\n          assert ext == \"\"\n        end\n      end)\n    end)\n  end\n\n  test \"assembles a bootable release without distribution\" do\n    in_fixture(\"release_test\", fn ->\n      config = [releases: [no_dist: []]]\n\n      Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n        root = Path.absname(\"_build/dev/rel/no_dist\")\n        Mix.Task.run(\"release\", [\"no_dist\"])\n\n        open_port(Path.join(root, \"bin/no_dist\"), [~c\"start\"], [\n          {~c\"RELEASE_DISTRIBUTION\", ~c\"none\"}\n        ])\n\n        assert %{\n                 mode: :embedded,\n                 node: :nonode@nohost,\n                 protocols_consolidated?: true,\n                 release_name: \"no_dist\",\n                 release_node: \"no_dist\",\n                 release_vsn: \"0.1.0\"\n               } = wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n      end)\n    end)\n  end\n\n  test \"assembles a release without ERTS and with custom options\" do\n    in_fixture(\"release_test\", fn ->\n      config = [releases: [demo: [include_erts: false, cookie: \"abcdefghijk\"]]]\n\n      Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n        root = Path.absname(\"demo\")\n\n        Mix.Task.run(\"release\", [\"demo\", \"--path\", \"demo\", \"--version\", \"0.2.0\", \"--quiet\"])\n        refute_received {:mix_shell, :info, [\"* assembling \" <> _]}\n        refute_received {:mix_shell, :info, [\"\\nRelease created \" <> _]}\n\n        # Assert structure\n        assert root |> Path.join(\"bin/demo\") |> File.exists?()\n        refute root |> Path.join(\"erts-#{@erts_version}\") |> File.exists?()\n        assert root |> Path.join(\"lib/release_test-0.1.0/ebin\") |> File.exists?()\n        assert root |> Path.join(\"lib/release_test-0.1.0/priv/hello\") |> File.exists?()\n        assert root |> Path.join(\"releases/COOKIE\") |> File.exists?()\n        assert root |> Path.join(\"releases/start_erl.data\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.2.0/demo.rel\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.2.0/sys.config\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.2.0/vm.args\") |> File.exists?()\n        assert root |> Path.join(\"releases/0.2.0/remote.vm.args\") |> File.exists?()\n\n        # Assert runtime\n        open_port(Path.join(root, \"bin/demo\"), [~c\"start\"])\n\n        assert %{\n                 app_dir: app_dir,\n                 cookie_env: \"abcdefghijk\",\n                 mode: :embedded,\n                 node: release_node(\"demo\"),\n                 protocols_consolidated?: true,\n                 release_name: \"demo\",\n                 release_node: \"demo\",\n                 release_prog: \"demo\" <> ext,\n                 release_root: release_root,\n                 release_vsn: \"0.2.0\",\n                 root_dir: root_dir,\n                 runtime_config: :error,\n                 static_config: {:ok, :was_set}\n               } = wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n\n        if match?({:win32, _}, :os.type()) do\n          assert String.ends_with?(app_dir, \"demo/lib/release_test-0.1.0\")\n          assert String.ends_with?(release_root, \"demo\")\n          assert ext == \".bat\"\n        else\n          assert app_dir == Path.join(root, \"lib/release_test-0.1.0\")\n          assert release_root == root\n          assert ext == \"\"\n        end\n\n        assert root_dir == :code.root_dir() |> to_string()\n      end)\n    end)\n  end\n\n  test \"validates compile_env\" do\n    in_fixture(\"release_test\", fn ->\n      # Let's also use a non standard config_path.\n      config = [releases: [compile_env_config: []], config_path: \"different_config/config.exs\"]\n\n      File.write!(\"lib/compile_env.ex\", \"\"\"\n      require Application\n      _ = Application.compile_env(:release_test, :static)\n      \"\"\")\n\n      File.mkdir_p!(\"different_config\")\n      File.cp!(\"config/config.exs\", \"different_config/config.exs\")\n\n      File.write!(\"different_config/runtime.exs\", \"\"\"\n      import Config\n      config :release_test, :static, String.to_atom(System.get_env(\"RELEASE_STATIC\"))\n      \"\"\")\n\n      Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n        Mix.Task.run(\"loadconfig\", [])\n\n        root = Path.absname(\"_build/dev/rel/compile_env_config\")\n        Mix.Task.run(\"release\", [\"compile_env_config\"])\n\n        assert {output, _} =\n                 System.cmd(Path.join(root, \"bin/compile_env_config\"), [\"start\"],\n                   stderr_to_stdout: true,\n                   env: [{\"RELEASE_STATIC\", \"runtime\"}]\n                 )\n\n        assert output =~\n                 \"ERROR! the application :release_test has a different value set for key :static during runtime compared to compile time\"\n\n        # But now it does\n        env = [{~c\"RELEASE_STATIC\", ~c\"was_set\"}]\n        open_port(Path.join(root, \"bin/compile_env_config\"), [~c\"start\"], env)\n        assert %{} = wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n      end)\n    end)\n  end\n\n  test \"does not validate compile_env if opted out\" do\n    in_fixture(\"release_test\", fn ->\n      config = [releases: [no_compile_env_config: [validate_compile_env: false]]]\n\n      File.write!(\"lib/compile_env.ex\", \"\"\"\n      require Application\n      _ = Application.compile_env(:release_test, :static)\n      \"\"\")\n\n      Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n        Mix.Task.run(\"loadconfig\", [])\n\n        File.write!(\"config/runtime.exs\", \"\"\"\n        import Config\n        config :release_test, :static, String.to_atom(System.get_env(\"RELEASE_STATIC\"))\n        config :release_test, :runtime, mode: :code.get_mode()\n        \"\"\")\n\n        root = Path.absname(\"_build/dev/rel/no_compile_env_config\")\n        Mix.Task.run(\"release\", [\"no_compile_env_config\"])\n\n        # It boots with mismatched config\n        env = [{~c\"RELEASE_STATIC\", ~c\"runtime\"}]\n        open_port(Path.join(root, \"bin/no_compile_env_config\"), [~c\"start\"], env)\n\n        assert %{\n                 mode: :embedded,\n                 runtime_config: {:ok, [mode: :embedded]},\n                 static_config: {:ok, :runtime}\n               } =\n                 wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n      end)\n    end)\n  end\n\n  @tag :epmd\n  test \"executes rpc instructions\" do\n    in_fixture(\"release_test\", fn ->\n      config = [releases: [permanent1: [include_erts: false]]]\n\n      # We write the compile env to guarantee rpc still works\n      File.write!(\"lib/compile_env.ex\", \"\"\"\n      require Application\n      _ = Application.compile_env(:release_test, :static)\n      \"\"\")\n\n      Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n        Mix.Task.run(\"loadconfig\", [])\n\n        # For compile env to be validated, we need a config/runtime.exs\n        File.write!(\"config/runtime.exs\", \"\"\"\n        import Config\n        \"\"\")\n\n        root = Path.absname(\"_build/dev/rel/permanent1\")\n        Mix.Task.run(\"release\")\n        script = Path.join(root, \"bin/permanent1\")\n\n        env = [{\"RELEASE_DISTRIBUTION\", \"name\"}, {\"RELEASE_NODE\", \"permanent1@127.0.0.1\"}]\n        open_port(script, [~c\"start\"], env)\n        wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n\n        assert System.cmd(script, [\"rpc\", \"ReleaseTest.hello_world()\"], env: env) ==\n                 {\"hello world\\n\", 0}\n\n        assert {pid, 0} = System.cmd(script, [\"pid\"], env: env)\n        assert pid != \"\\n\"\n\n        assert System.cmd(script, [\"stop\"], env: env) == {\"\", 0}\n      end)\n    end)\n  end\n\n  test \"runs eval and version commands\" do\n    # In some Windows setups (mostly with Docker), `System.cmd/3` fails because\n    # the path to the command/executable and one or more arguments contain spaces.\n    tmp_dir = Path.join(inspect(__MODULE__), \"runs_eval_and_version_commands\")\n\n    in_fixture(\"release_test\", tmp_dir, fn ->\n      config = [releases: [eval: [include_erts: false, cookie: \"abcdefghij\"]]]\n\n      Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n        File.write!(\"config/runtime.exs\", \"\"\"\n        import Config\n\n        config :release_test, :runtime, [mode: :code.get_mode()]\n\n        # Ensure app has been loaded\n        [_ | _] = Application.spec(:release_test, :modules)\n        \"\"\")\n\n        root = Path.absname(\"_build/dev/rel/eval\")\n        Mix.Task.run(\"release\")\n\n        script = Path.join(root, \"bin/eval\")\n        {version, 0} = System.cmd(script, [\"version\"])\n        assert String.trim_trailing(version) == \"eval 0.1.0\"\n        refute File.exists?(Path.join(root, \"RELEASE_BOOTED\"))\n\n        {hello_world, 0} = System.cmd(script, [\"eval\", \"IO.puts :hello_world\"])\n        assert String.trim_trailing(hello_world) == \"hello_world\"\n        refute File.exists?(Path.join(root, \"RELEASE_BOOTED\"))\n\n        {hello_world, 0} =\n          System.cmd(script, [\"eval\", \"IO.inspect(System.argv( ))\", \"a\", \"b\", \"c\"])\n\n        assert String.trim_trailing(hello_world) == ~S([\"a\", \"b\", \"c\"])\n        refute File.exists?(Path.join(root, \"RELEASE_BOOTED\"))\n\n        open_port(script, [~c\"eval\", ~c\"Application.ensure_all_started(:release_test)\"])\n\n        assert %{\n                 cookie_env: \"abcdefghij\",\n                 mode: :interactive,\n                 node: :nonode@nohost,\n                 protocols_consolidated?: true,\n                 release_name: \"eval\",\n                 release_node: \"eval\",\n                 release_prog: \"eval\" <> ext,\n                 release_root: release_root,\n                 release_vsn: \"0.1.0\",\n                 runtime_config: {:ok, [mode: :interactive]},\n                 static_config: {:ok, :was_set}\n               } = wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n\n        if match?({:win32, _}, :os.type()) do\n          assert String.ends_with?(release_root, \"eval\")\n          assert ext == \".bat\"\n        else\n          assert release_root == root\n          assert ext == \"\"\n        end\n      end)\n    end)\n  end\n\n  @tag :unix\n  test \"runs in daemon mode\" do\n    in_fixture(\"release_test\", fn ->\n      config = [releases: [permanent2: [include_erts: false, cookie: \"abcdefghij\"]]]\n\n      Mix.Project.in_project(:release_test, \".\", config, fn _ ->\n        root = Path.absname(\"_build/dev/rel/permanent2\")\n        Mix.Task.run(\"release\")\n\n        script = Path.join(root, \"bin/permanent2\")\n        env = [{\"RELEASE_DISTRIBUTION\", \"name\"}, {\"RELEASE_NODE\", \"permanent2@127.0.0.1\"}]\n        open_port(script, [~c\"daemon_iex\"], env)\n\n        assert %{\n                 app_dir: app_dir,\n                 cookie_env: \"abcdefghij\",\n                 mode: :embedded,\n                 node: :\"permanent2@127.0.0.1\",\n                 protocols_consolidated?: true,\n                 release_name: \"permanent2\",\n                 release_node: \"permanent2@127.0.0.1\",\n                 release_root: ^root,\n                 release_vsn: \"0.1.0\",\n                 root_dir: root_dir,\n                 runtime_config: :error,\n                 static_config: {:ok, :was_set},\n                 sys_config_env: sys_config_env,\n                 sys_config_init: sys_config_init\n               } = wait_until_decoded(Path.join(root, \"RELEASE_BOOTED\"))\n\n        assert app_dir == Path.join(root, \"lib/release_test-0.1.0\")\n        assert root_dir == :code.root_dir() |> to_string()\n        assert sys_config_env == Path.join(root, \"releases/0.1.0/sys\")\n        assert sys_config_init == Path.join(root, \"releases/0.1.0/sys\")\n\n        assert wait_until(fn ->\n                 File.read!(Path.join(root, \"tmp/log/erlang.log.1\")) =~\n                   \"iex(permanent2@127.0.0.1)1> \"\n               end)\n\n        assert System.cmd(script, [\"rpc\", \"ReleaseTest.hello_world()\"], env: env) ==\n                 {\"hello world\\n\", 0}\n\n        assert System.cmd(script, [\"restart\"], env: env) == {\"\", 0}\n\n        assert wait_until(fn ->\n                 File.read!(Path.join(root, \"tmp/log/erlang.log.1\")) =~\n                   \"RESTARTED!!!\"\n               end)\n\n        assert System.cmd(script, [\"stop\"], env: env) == {\"\", 0}\n      end)\n    end)\n  end\n\n  test \"requires confirmation if release already exists unless overwriting\" do\n    in_fixture(\"release_test\", fn ->\n      Mix.Project.in_project(:release_test, \".\", fn _ ->\n        Mix.Task.rerun(\"release\")\n        assert_received {:mix_shell, :info, [\"* assembling release_test-0.1.0 on MIX_ENV=dev\"]}\n\n        send(self(), {:mix_shell_input, :yes?, false})\n        Mix.Task.rerun(\"release\")\n        refute_received {:mix_shell, :info, [\"* assembling release_test-0.1.0 on MIX_ENV=dev\"]}\n\n        assert_received {:mix_shell, :yes?,\n                         [\"Release release_test-0.1.0 already exists. Overwrite?\"]}\n\n        Mix.Task.rerun(\"release\", [\"--overwrite\"])\n        assert_received {:mix_shell, :info, [\"* assembling release_test-0.1.0 on MIX_ENV=dev\"]}\n      end)\n    end)\n  end\n\n  @tag :unix\n  test \"works properly with an absolute symlink to release\" do\n    in_fixture(\"release_test\", fn ->\n      Mix.Project.in_project(:release_test, \".\", fn _ ->\n        Mix.Task.run(\"release\")\n\n        File.ln_s!(\n          Path.absname(\"_build/#{Mix.env()}/rel/release_test/bin/release_test\"),\n          Path.absname(\"release_test\")\n        )\n\n        script = Path.absname(\"release_test\")\n        {hello_world, 0} = System.cmd(script, [\"eval\", \"IO.puts :hello_world\"])\n        assert String.trim_trailing(hello_world) == \"hello_world\"\n      end)\n    end)\n  end\n\n  @tag :unix\n  test \"works properly with a relative symlink to release\" do\n    in_fixture(\"release_test\", fn ->\n      Mix.Project.in_project(:release_test, \".\", fn _ ->\n        Mix.Task.run(\"release\")\n\n        File.mkdir!(\"bin\")\n        File.ln_s!(\"../_build/#{Mix.env()}/rel/release_test/bin/release_test\", \"bin/release_test\")\n\n        script = Path.absname(\"bin/release_test\")\n        {hello_world, 0} = System.cmd(script, [\"eval\", \"IO.puts :hello_world\"])\n        assert String.trim_trailing(hello_world) == \"hello_world\"\n      end)\n    end)\n  end\n\n  defp open_port(command, args, env \\\\ []) do\n    env = for {k, v} <- env, do: {to_charlist(k), to_charlist(v)}\n    Port.open({:spawn_executable, to_charlist(command)}, [:hide, args: args, env: env])\n  end\n\n  defp wait_until_decoded(file) do\n    wait_until(fn ->\n      case File.read(file) do\n        {:ok, bin} when byte_size(bin) > 0 -> :erlang.binary_to_term(bin)\n        _ -> nil\n      end\n    end)\n  end\n\n  defp wait_until(fun) do\n    if value = fun.() do\n      value\n    else\n      Process.sleep(10)\n      wait_until(fun)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/run_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.RunTest do\n  use MixTest.Case\n\n  setup do\n    Mix.Project.push(MixTest.Case.Sample)\n  end\n\n  test \"run requires files before evaling commands\", context do\n    git_repo = fixture_path(\"git_repo/lib/git_repo.ex\")\n\n    in_tmp(context.test, fn ->\n      Mix.Tasks.Run.run([\"-r\", git_repo, \"-e\", \"send self(), {:hello, GitRepo.hello()}\"])\n      assert_received {:hello, \"World\"}\n\n      Mix.Tasks.Run.run([\"-pr\", git_repo, \"-e\", \"send self(), {:hello, GitRepo.hello()}\"])\n      assert_received {:hello, \"World\"}\n    end)\n  after\n    purge([GitRepo])\n  end\n\n  test \"does not start applications on --no-start\", context do\n    in_tmp(context.test, fn ->\n      expr = \"send self(), {:apps, Application.started_applications()}\"\n      Mix.Tasks.Run.run([\"--no-start\", \"-e\", expr])\n\n      assert_received {:apps, apps}\n      refute List.keyfind(apps, :sample, 0)\n      Mix.Task.clear()\n\n      Mix.Tasks.Run.run([\"-e\", expr])\n      assert_received {:apps, apps}\n      assert List.keyfind(apps, :sample, 0)\n    end)\n  end\n\n  test \"run errors on missing files\", context do\n    in_tmp(context.test, fn ->\n      message = \"No files matched pattern \\\"non-existent\\\" given to --require\"\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Run.run([\"-r\", \"non-existent\"])\n      end\n\n      assert_raise Mix.Error, message, fn ->\n        Mix.Tasks.Run.run([\"-pr\", \"non-existent\"])\n      end\n\n      assert_raise Mix.Error, \"No such file: non-existent\", fn ->\n        Mix.Tasks.Run.run([\"non-existent\"])\n      end\n\n      File.mkdir_p!(\"lib\")\n\n      assert_raise Mix.Error, \"No such file: lib\", fn ->\n        Mix.Tasks.Run.run([\"lib\"])\n      end\n    end)\n  after\n    purge([GitRepo])\n  end\n\n  test \"run rewrites System.argv\", context do\n    in_tmp(context.test, fn ->\n      file = \"argv.exs\"\n      expr = \"send self(), {:argv, System.argv()}\"\n\n      File.write!(file, expr)\n\n      unload_file = fn ->\n        Code.unrequire_files([Path.expand(file)])\n      end\n\n      Mix.Tasks.Run.run([file])\n      assert_received {:argv, []}\n\n      unload_file.()\n      Mix.Tasks.Run.run([file, \"foo\", \"-e\", \"bar\"])\n      assert_received {:argv, [\"foo\", \"-e\", \"bar\"]}\n\n      unload_file.()\n      Mix.Tasks.Run.run([file, \"foo\", \"--\", \"bar\"])\n      assert_received {:argv, [\"foo\", \"--\", \"bar\"]}\n\n      unload_file.()\n      Mix.Tasks.Run.run([file, \"--custom-opt\", \"foo\", \"--\", \"bar\"])\n      assert_received {:argv, [\"--custom-opt\", \"foo\", \"--\", \"bar\"]}\n\n      unload_file.()\n      Mix.Tasks.Run.run([\"-e\", expr, file, \"foo\", \"-x\", \"bar\"])\n      assert_received {:argv, [^file, \"foo\", \"-x\", \"bar\"]}\n\n      unload_file.()\n\n      send_evaled = \"send self(), :evaled\"\n      Mix.Tasks.Run.run([\"-e\", send_evaled, \"-e\", expr, \"--no-compile\", file, \"-x\", \"bar\"])\n\n      assert_received :evaled\n      assert_received {:argv, [^file, \"-x\", \"bar\"]}\n    end)\n  end\n\n  defmodule AppArgvSample do\n    def project do\n      [app: :app_argv_sample, version: \"0.1.0\"]\n    end\n\n    def application do\n      send(self(), {:argv, System.argv()})\n      [extra_applications: [:logger]]\n    end\n  end\n\n  describe \"rewrite System.argv without file arg\" do\n    setup do\n      Mix.Project.pop()\n      Mix.Project.push(AppArgvSample)\n      :ok\n    end\n\n    test \"no args\" do\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Tasks.Run.run([\"--\"])\n        assert_received {:argv, []}\n      end)\n    end\n\n    test \"multiple args\" do\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Tasks.Run.run([\"--\", \"foo\", \"bar\"])\n        assert_received {:argv, [\"foo\", \"bar\"]}\n      end)\n    end\n\n    test \"with opts\" do\n      in_fixture(\"no_mixfile\", fn ->\n        Mix.Tasks.Run.run([\"--no-start\", \"--\", \"foo\", \"bar\"])\n        assert_received {:argv, [\"foo\", \"bar\"]}\n      end)\n    end\n\n    test \"with eval\" do\n      in_fixture(\"no_mixfile\", fn ->\n        expr = \"send self(), {:test, :argv}\"\n        Mix.Tasks.Run.run([\"-e\", expr, \"--\", \"foo\"])\n        assert_received {:argv, [\"foo\"]}\n        assert_received {:test, :argv}\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/test_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.TestTest do\n  use MixTest.Case\n\n  describe \"ex_unit_opts/1\" do\n    test \"returns ex unit options\" do\n      assert filtered_ex_unit_opts(unknown: \"ok\", seed: 13) == [seed: 13]\n    end\n\n    test \"returns includes and excludes\" do\n      included = [include: [:focus, key: \"val\"]]\n      assert filtered_ex_unit_opts(include: \"focus\", include: \"key:val\") == included\n\n      excluded = [exclude: [:focus, key: \"val\"]]\n      assert filtered_ex_unit_opts(exclude: \"focus\", exclude: \"key:val\") == excluded\n    end\n\n    test \"translates :only into includes and excludes\" do\n      assert filtered_ex_unit_opts(only: \"focus\") == [include: [:focus], exclude: [:test]]\n\n      only = [include: [:focus, :special], exclude: [:test]]\n      assert filtered_ex_unit_opts(only: \"focus\", include: \"special\") == only\n    end\n\n    test \"translates :name_pattern into includes and excludes\" do\n      assert [include: [test: hello_regex, test: world_regex], exclude: [:test]] =\n               filtered_ex_unit_opts(name_pattern: ~r/hello/, name_pattern: ~r/world/)\n\n      assert Regex.match?(hello_regex, \"hello\")\n      refute Regex.match?(hello_regex, \"world\")\n      refute Regex.match?(world_regex, \"hello\")\n      assert Regex.match?(world_regex, \"world\")\n    end\n\n    test \"translates :color into list containing an enabled key-value pair\" do\n      assert filtered_ex_unit_opts(color: false) == [colors: [enabled: false]]\n      assert filtered_ex_unit_opts(color: true) == [colors: [enabled: true]]\n    end\n\n    test \"translates :formatter into list of modules\" do\n      assert filtered_ex_unit_opts(formatter: \"A.B\") == [formatters: [A.B]]\n    end\n\n    test \"accepts custom :exit_status\" do\n      assert {:exit_status, 5} in ex_unit_opts(exit_status: 5, failures_manifest_path: \"foo.bar\")\n    end\n\n    test \"includes some default options\" do\n      assert ex_unit_opts(failures_manifest_path: \"foo.bar\") == [\n               autorun: false,\n               exit_status: 2,\n               failures_manifest_path: \"foo.bar\"\n             ]\n    end\n\n    defp ex_unit_opts(opts) do\n      {ex_unit_opts, _allowed_files} = Mix.Tasks.Test.process_ex_unit_opts(opts)\n      ex_unit_opts\n    end\n\n    defp filtered_ex_unit_opts(opts) do\n      opts\n      |> Keyword.put(:failures_manifest_path, \"foo.bar\")\n      |> ex_unit_opts()\n      |> Keyword.drop([:failures_manifest_path, :autorun, :exit_status])\n    end\n  end\n\n  describe \"--stale\" do\n    test \"runs all tests for first run, then none on second\" do\n      in_fixture(\"test_stale\", fn ->\n        assert_stale_run_output(\"Result: 2 passed\")\n\n        assert_stale_run_output(\"\"\"\n        No stale tests\n        \"\"\")\n      end)\n    end\n\n    test \"runs tests that depend on modified modules\" do\n      in_fixture(\"test_stale\", fn ->\n        assert_stale_run_output(\"Result: 2 passed\")\n\n        set_all_mtimes()\n        force_recompilation(\"lib/b.ex\")\n\n        assert_stale_run_output(\"Result: 1 passed\")\n\n        set_all_mtimes()\n        force_recompilation(\"lib/a.ex\")\n\n        assert_stale_run_output(\"Result: 2 passed\")\n      end)\n    end\n\n    test \"doesn't write manifest when there are failures\" do\n      in_fixture(\"test_stale\", fn ->\n        assert_stale_run_output(\"Result: 2 passed\")\n\n        set_all_mtimes()\n\n        File.write!(\"lib/b.ex\", \"\"\"\n        defmodule B do\n          def f, do: :error\n        end\n        \"\"\")\n\n        assert_stale_run_output(\"Failed: 1 test\")\n\n        assert_stale_run_output(\"Failed: 1 test\")\n      end)\n    end\n\n    test \"runs tests that have changed\" do\n      in_fixture(\"test_stale\", fn ->\n        assert_stale_run_output(\"Result: 2 passed\")\n\n        set_all_mtimes()\n        File.touch!(\"test/a_test_stale.exs\")\n\n        assert_stale_run_output(\"Result: 1 passed\")\n      end)\n    end\n\n    test \"runs tests that have changed test_helpers\" do\n      in_fixture(\"test_stale\", fn ->\n        assert_stale_run_output(\"Result: 2 passed\")\n\n        set_all_mtimes()\n        File.touch!(\"test/test_helper.exs\")\n\n        assert_stale_run_output(\"Result: 2 passed\")\n      end)\n    end\n\n    test \"runs all tests no matter what with --force\" do\n      in_fixture(\"test_stale\", fn ->\n        assert_stale_run_output(\"Result: 2 passed\")\n\n        assert_stale_run_output(~w[--force], \"Result: 2 passed\")\n      end)\n    end\n  end\n\n  describe \"--cover\" do\n    @describetag :cover\n    test \"reports the coverage of each app's modules in an umbrella\" do\n      in_fixture(\"umbrella_test\", fn ->\n        # This fixture by default results in coverage above the default threshold\n        # which should result in an exit status of 0.\n        assert {output, 0} = mix_code([\"test\", \"--cover\"])\n        assert output =~ \"Result: 4 passed\"\n\n        # For bar, we do regular --cover and also test protocols\n        assert output =~ \"\"\"\n               Generating cover results ...\n\n               | Percentage | Module                 |\n               |------------|------------------------|\n               |    100.00% | Bar.Protocol           |\n               |    100.00% | Bar.Protocol.BitString |\n               |------------|------------------------|\n               |    100.00% | Total                  |\n               \"\"\"\n\n        assert output =~ \"Result: 1 passed\"\n\n        # For foo, we do regular --cover and test it does not include bar\n        assert output =~ \"\"\"\n               Generating cover results ...\n\n               | Percentage | Module     |\n               |------------|------------|\n               |    100.00% | Foo        |\n               |------------|------------|\n               |    100.00% | Total      |\n               \"\"\"\n\n        # We skip a test in bar to force coverage below the default threshold\n        # which should result in an exit status of 1.\n        assert {output, code} = mix_code([\"test\", \"--cover\", \"--exclude\", \"maybe_skip\"])\n\n        assert output =~ \"\"\"\n               Coverage test failed, threshold not met:\n\n                   Coverage:    0.00%\n                   Threshold:  90.00%\n               \"\"\"\n\n        assert code == 3\n      end)\n    end\n\n    test \"supports unified reports by using test.coverage\" do\n      in_fixture(\"umbrella_test\", fn ->\n        assert mix([\"test\", \"--export-coverage\", \"default\", \"--cover\"]) =~\n                 \"Run \\\"mix test.coverage\\\" once all exports complete\"\n\n        assert mix([\"test.coverage\"]) =~ \"\"\"\n               Importing cover results: apps/bar/cover/default.coverdata\n               Importing cover results: apps/foo/cover/default.coverdata\n\n               | Percentage | Module                 |\n               |------------|------------------------|\n               |    100.00% | Bar                    |\n               |    100.00% | Bar.Ignore             |\n               |    100.00% | Bar.Protocol           |\n               |    100.00% | Bar.Protocol.BitString |\n               |    100.00% | Foo                    |\n               |------------|------------------------|\n               |    100.00% | Total                  |\n               \"\"\"\n      end)\n    end\n  end\n\n  describe \"--failed\" do\n    test \"loads only files with failures and runs just the failures\" do\n      in_fixture(\"test_failed\", fn ->\n        loading_only_passing_test_msg = \"loading OnlyPassingTest\"\n\n        # Run `mix test` once to record failures...\n        output = mix([\"test\"])\n        assert output =~ loading_only_passing_test_msg\n        assert output =~ \"Failed: 2 tests\"\n\n        # `mix test --failed` runs only failed tests and avoids loading files with no failures\n        output = mix([\"test\", \"--failed\"])\n        refute output =~ loading_only_passing_test_msg\n        assert output =~ \"Failed: 2 tests\"\n\n        # `mix test --failed` can be applied to a directory or file\n        output = mix([\"test\", \"test/passing_and_failing_test_failed.exs\", \"--failed\"])\n        assert output =~ \"Failed: 1 test\"\n\n        # Plus line\n        output = mix([\"test\", \"test/passing_and_failing_test_failed.exs:5\", \"--failed\"])\n        assert output =~ \"Failed: 1 test\"\n\n        if windows?() do\n          output = mix([\"test\", \"test\\\\passing_and_failing_test_failed.exs:5\", \"--failed\"])\n          assert output =~ \"Failed: 1 test\"\n        end\n\n        # `--failed` composes with an `--only` filter by running the intersection.\n        # Of the failing tests, 1 is tagged with `@tag :foo`.\n        # Of the passing tests, 1 is tagged with `@tag :foo`.\n        # But only the failing test with that tag should run.\n        output = mix([\"test\", \"--failed\", \"--only\", \"foo\"])\n        assert output =~ \"Failed: 1 test\"\n\n        # Run again to give it a chance to record as passed\n        System.put_env(\"PASS_FAILING_TESTS\", \"true\")\n        assert mix([\"test\", \"--failed\"]) =~ \"Result: 2 passed\"\n\n        # Nothing should get run if we try it again since everything is passing.\n        assert mix([\"test\", \"--failed\"]) =~ \"There are no tests to run\"\n\n        # When everything is passing and a file is passed, we return the proper message\n        output = mix([\"test\", \"test/passing_and_failing_test_failed.exs\", \"--failed\"])\n        assert output =~ \"There are no tests to run\"\n        refute output =~ \"does not match\"\n\n        # `--failed` and `--stale` cannot be combined\n        output = mix([\"test\", \"--failed\", \"--stale\"])\n        assert output =~ \"Combining --failed and --stale is not supported\"\n      end)\n    after\n      System.delete_env(\"PASS_FAILING_TESTS\")\n    end\n\n    test \"marks the whole suite as failed on compilation error\" do\n      in_fixture(\"test_failed\", fn ->\n        File.write!(\"test/passing_and_failing_test_failed.exs\", \"raise ~s(oops)\")\n\n        output = mix([\"test\"])\n        assert output =~ \"** (RuntimeError) oops\"\n\n        output = mix([\"test\", \"--failed\"])\n        assert output =~ \"** (RuntimeError) oops\"\n      end)\n    end\n  end\n\n  describe \"--listen-on-stdin\" do\n    test \"runs tests after input\" do\n      in_fixture(\"test_stale\", fn ->\n        port = mix_port(~w[test --stale --listen-on-stdin])\n\n        assert receive_until_match(port, \"Result:\", \"\") =~ \"Result: 2 passed\"\n\n        Port.command(port, \"\\n\")\n\n        assert receive_until_match(port, \"Restarting...\", \"\") =~ \"Restarting...\"\n      end)\n    end\n  end\n\n  describe \"--partitions\" do\n    @tag :cover\n    test \"splits tests into partitions (with coverage)\" do\n      in_fixture(\"test_stale\", fn ->\n        assert mix([\"test\", \"--partitions\", \"3\", \"--cover\"], [{\"MIX_TEST_PARTITION\", \"1\"}]) =~\n                 \"Result: 1 passed\"\n\n        assert mix([\"test\", \"--partitions\", \"3\", \"--cover\"], [{\"MIX_TEST_PARTITION\", \"2\"}]) =~\n                 \"Result: 1 passed\"\n\n        assert mix([\"test\", \"--partitions\", \"3\", \"--cover\"], [{\"MIX_TEST_PARTITION\", \"3\"}]) =~\n                 \"There are no tests to run\"\n\n        assert File.regular?(\"cover/1.coverdata\")\n        assert File.regular?(\"cover/2.coverdata\")\n        refute File.regular?(\"cover/3.coverdata\")\n\n        assert mix([\"test.coverage\"]) == \"\"\"\n               Importing cover results: cover/1.coverdata\n               Importing cover results: cover/2.coverdata\n\n               | Percentage | Module     |\n               |------------|------------|\n               |    100.00% | A          |\n               |    100.00% | B          |\n               |------------|------------|\n               |    100.00% | Total      |\n\n               Generated HTML coverage results in \\\"cover\\\" directory\n               \"\"\"\n      end)\n    end\n\n    test \"raises when no partition is given even with Mix.shell() change\" do\n      in_fixture(\"test_stale\", fn ->\n        File.write!(\"test/test_helper.exs\", \"\"\"\n        Mix.shell(Mix.Shell.Process)\n        ExUnit.start()\n        \"\"\")\n\n        assert_run_output(\n          [\"--partitions\", \"4\"],\n          \"The MIX_TEST_PARTITION environment variable must be set\"\n        )\n      end)\n    end\n\n    test \"do not raise if partitions flag is set to 1 and no partition given\" do\n      in_fixture(\"test_stale\", fn ->\n        assert mix([\"test\", \"--partitions\", \"1\"], []) =~\n                 \"Result: 2 passed\"\n\n        assert mix([\"test\", \"--partitions\", \"1\"], [{\"MIX_TEST_PARTITION\", \"\"}]) =~\n                 \"Result: 2 passed\"\n\n        assert mix([\"test\", \"--partitions\", \"1\"], [{\"MIX_TEST_PARTITION\", \"1\"}]) =~\n                 \"Result: 2 passed\"\n      end)\n    end\n\n    test \"raise if partitions is set to non-positive value\" do\n      in_fixture(\"test_stale\", fn ->\n        File.write!(\"test/test_helper.exs\", \"\"\"\n        Mix.shell(Mix.Shell.Process)\n        ExUnit.start()\n        \"\"\")\n\n        assert_run_output(\n          [\"--partitions\", \"0\"],\n          \"--partitions : expected to be positive integer, got 0\"\n        )\n\n        assert_run_output(\n          [\"--partitions\", \"-1\"],\n          \"--partitions : expected to be positive integer, got -1\"\n        )\n      end)\n    end\n\n    test \"runs after_suite with partitions with no tests\" do\n      in_fixture(\"test_stale\", fn ->\n        File.write!(\"test/test_helper.exs\", \"\"\"\n        ExUnit.after_suite(fn _stats -> IO.puts(\"AFTER SUITE\") end)\n        ExUnit.start()\n        \"\"\")\n\n        assert mix([\"test\", \"--partitions\", \"3\"], [{\"MIX_TEST_PARTITION\", \"3\"}]) =~ \"\"\"\n               AFTER SUITE\n               There are no tests to run\n               \"\"\"\n      end)\n    end\n  end\n\n  describe \"logs and errors\" do\n    test \"logs test absence for a project with no test paths\" do\n      in_fixture(\"test_stale\", fn ->\n        File.rm_rf!(\"test\")\n        assert_run_output(\"There are no tests to run\")\n\n        File.mkdir_p!(\"test\")\n        File.write!(\"test/test_helper.exs\", \"ExUnit.start()\")\n        assert_run_output(\"There are no tests to run\")\n      end)\n    end\n\n    test \"raises when no test runs even with Mix.shell() change\" do\n      in_fixture(\"test_stale\", fn ->\n        File.write!(\"test/test_helper.exs\", \"\"\"\n        Mix.shell(Mix.Shell.Process)\n        ExUnit.start()\n        \"\"\")\n\n        assert_run_output(\n          [\"--only\", \"unknown\"],\n          \"The --only option was given to \\\"mix test\\\" but no test was executed\"\n        )\n      end)\n    end\n\n    test \"runs multiple test files if line numbers are given\" do\n      in_fixture(\"test_stale\", fn ->\n        assert_run_output(\n          [\"test/a_test_stale.exs:2\", \"test/b_test_stale.exs:4\"],\n          \"\"\"\n          Excluding tags: [:test]\n          Including tags: [location: {\"test/a_test_stale.exs\", 2}, location: {\"test/b_test_stale.exs\", 4}]\n          \"\"\"\n        )\n      end)\n    end\n\n    test \"umbrella with file path\" do\n      in_fixture(\"umbrella_test\", fn ->\n        # Run false positive test first so at least the code is compiled\n        # and we can perform more aggressive assertions later\n        output = mix([\"test\", \"apps/unknown_app/test\"])\n\n        assert output =~ \"\"\"\n               ==> bar\n               Paths given to \"mix test\" did not match any directory/file: apps/unknown_app/test\n               \"\"\"\n\n        assert output =~ \"\"\"\n               ==> foo\n               Paths given to \"mix test\" did not match any directory/file: apps/unknown_app/test\n               \"\"\"\n\n        output = mix([\"test\", \"apps/bar/test/bar_tests.exs\"])\n\n        assert output =~ \"==> bar\"\n        assert output =~ \"....\"\n\n        refute output =~ \"==> foo\"\n        refute output =~ \"Paths given to \\\"mix test\\\" did not match any directory/file\"\n\n        output = mix([\"test\", \"./apps/bar/test/bar_tests.exs\"])\n\n        assert output =~ \"==> bar\"\n        assert output =~ \"....\"\n\n        refute output =~ \"==> foo\"\n        refute output =~ \"Paths given to \\\"mix test\\\" did not match any directory/file\"\n\n        output = mix([\"test\", Path.expand(\"apps/bar/test/bar_tests.exs\")])\n\n        assert output =~ \"==> bar\"\n        assert output =~ \"....\"\n\n        refute output =~ \"==> foo\"\n        refute output =~ \"Paths given to \\\"mix test\\\" did not match any directory/file\"\n\n        output = mix([\"test\", \"apps/bar/test/bar_tests.exs:10\"])\n\n        assert output =~ \"==> bar\"\n\n        assert output =~ \"\"\"\n               Excluding tags: [:test]\n               Including tags: [location: {\"test/bar_tests.exs\", 10}]\n\n               .\n               \"\"\"\n\n        refute output =~ \"==> foo\"\n        refute output =~ \"Paths given to \\\"mix test\\\" did not match any directory/file\"\n\n        casing =\n          if windows?() do\n            \"apps\\\\bar\\\\test\\\\bar_tests.exs:5\"\n          else\n            \"apps/bar/test/bar_tests.exs:5\"\n          end\n\n        output = mix([\"test\", \"apps/foo/test/foo_tests.exs:9\", casing])\n\n        assert output =~ \"\"\"\n               Excluding tags: [:test]\n               Including tags: [location: {\"test/foo_tests.exs\", 9}]\n               \"\"\"\n\n        assert output =~ \"Result: 1 passed\\n\"\n\n        assert output =~ \"\"\"\n               Excluding tags: [:test]\n               Including tags: [location: {\"test/bar_tests.exs\", 5}]\n               \"\"\"\n\n        assert output =~ \"Result: 1 passed, 3 excluded\\n\"\n      end)\n    end\n  end\n\n  describe \"--warnings-as-errors\" do\n    test \"fail with exit status 1 if warning in tests but tests pass\" do\n      in_fixture(\"test_stale\", fn ->\n        msg =\n          \"Test suite aborted after successful execution due to warnings while using the --warnings-as-errors option\"\n\n        refute mix([\"test\", \"--warnings-as-errors\"]) =~ msg\n\n        File.write!(\"lib/warning.ex\", \"\"\"\n        unused_compile_var = 1\n        \"\"\")\n\n        File.write!(\"test/warning_test_stale.exs\", \"\"\"\n        defmodule WarningTest do\n          use ExUnit.Case\n\n          test \"warning\" do\n            unused_test_var = 1\n          end\n        end\n        \"\"\")\n\n        {output, exit_status} =\n          mix_code([\"test\", \"--warnings-as-errors\", \"test/warning_test_stale.exs\"])\n\n        assert output =~ \"variable \\\"unused_compile_var\\\" is unused\"\n        assert output =~ \"variable \\\"unused_test_var\\\" is unused\"\n        assert output =~ msg\n        assert exit_status == 1\n      end)\n    end\n\n    test \"fail with --exit-status + 1 if warning in tests and tests fail\" do\n      in_fixture(\"test_stale\", fn ->\n        File.write!(\"test/warning_test_warnings_as_errors_and_failures.exs\", \"\"\"\n        defmodule WarningsAsErrorsAndFailuresTest do\n          use ExUnit.Case\n\n          test \"warning and failure\" do\n            unused_test_var = 1\n            assert false\n          end\n        end\n        \"\"\")\n\n        {output, exit_status} =\n          mix_code([\n            \"test\",\n            \"--warnings-as-errors\",\n            \"--exit-status\",\n            \"42\",\n            \"test/warning_test_warnings_as_errors_and_failures.exs\"\n          ])\n\n        assert output =~ \"variable \\\"unused_test_var\\\" is unused\"\n        assert output =~ \"Failed: 1 test\"\n\n        assert exit_status == 43\n      end)\n    end\n\n    test \"mark failed tests\" do\n      in_fixture(\"test_failed\", fn ->\n        File.write!(\"test/warning_test_failed.exs\", \"\"\"\n        defmodule WarningTest do\n          use ExUnit.Case\n\n          test \"warning\" do\n            unused_var = 123\n          end\n        end\n        \"\"\")\n\n        output = mix([\"test\", \"--warnings-as-errors\"])\n        assert output =~ \"Failed: 2 tests\"\n        refute output =~ \"Test suite aborted after successful execution\"\n        output = mix([\"test\", \"--failed\"])\n        assert output =~ \"Failed: 2 tests\"\n      end)\n    end\n\n    test \"fail with exit status 1 if misnamed test files with --warnings-as-errors (no tests to run)\" do\n      in_tmp(\"test_warn_as_errors_noop\", fn ->\n        File.write!(\"mix.exs\", \"\"\"\n        defmodule TestWarnAsErrorsNoop.MixProject do\n          use Mix.Project\n\n          def project do\n            [\n              app: :test_warn_as_errors_noop,\n              version: \"0.0.1\",\n              test_load_filters: [~r/.*_tests\\.exs/]\n            ]\n          end\n        end\n        \"\"\")\n\n        File.mkdir!(\"test\")\n        File.write!(\"test/test_helper.exs\", \"ExUnit.start()\")\n\n        File.touch!(\"test/a_missing.exs\")\n\n        msg =\n          \"Test suite aborted after successful execution due to warnings while using the --warnings-as-errors option\"\n\n        {output, exit_status} = mix_code([\"test\", \"--warnings-as-errors\"])\n\n        assert output =~ \"the following files do not match\"\n        assert output =~ \"test/a_missing.exs\"\n        assert output =~ msg\n        assert exit_status == 1\n      end)\n    end\n\n    test \"fail with exit status 1 if warning in test_helper.exs\" do\n      in_fixture(\"test_stale\", fn ->\n        File.write!(\"test/test_helper.exs\", \"\"\"\n        unused_var = 123\n\n        ExUnit.start()\n        \"\"\")\n\n        msg =\n          \"Test suite aborted after successful execution due to warnings while using the --warnings-as-errors option\"\n\n        {output, exit_status} = mix_code([\"test\", \"--warnings-as-errors\"])\n\n        assert output =~ \"variable \\\"unused_var\\\" is unused\"\n        assert output =~ msg\n        assert exit_status == 1\n      end)\n    end\n  end\n\n  describe \"--exit-status\" do\n    test \"returns custom exit status\" do\n      in_fixture(\"test_failed\", fn ->\n        {output, exit_status} = mix_code([\"test\", \"--exit-status\", \"5\"])\n        assert output =~ \"Failed: 2 tests\"\n        assert exit_status == 5\n      end)\n    end\n  end\n\n  describe \"--max-requires\" do\n    test \"runs tests with --max-requires 1\" do\n      # this is only a smoke test to ensure that tests run with --max-requires 1\n      # it does not test the concurrency behavior\n      in_fixture(\"test_stale\", fn ->\n        output = mix([\"test\", \"--max-requires\", \"1\"])\n        assert output =~ \"Result:\"\n      end)\n    end\n  end\n\n  describe \"test_load_filters and test_ignore_filters\" do\n    test \"warns of files that are not loaded and don't match test_ignore_filters\" do\n      in_tmp(\"test_warn\", fn ->\n        File.write!(\"mix.exs\", \"\"\"\n        defmodule TestWarn.MixProject do\n          use Mix.Project\n\n          def project do\n            [\n              app: :test_warn,\n              version: \"0.0.1\",\n              test_load_filters: [~r/.*_tests\\.exs/],\n              test_ignore_filters: [\n                \"test/test_helper.exs\",\n                ~r/ignored_regex/,\n                fn file -> file == \"test/ignored_file.exs\" end\n              ]\n            ]\n          end\n        end\n        \"\"\")\n\n        File.mkdir!(\"test\")\n\n        File.write!(\"test/a_tests.exs\", \"\"\"\n        defmodule ATests do\n          use ExUnit.Case\n\n          test \"dummy\" do\n            assert true\n          end\n        end\n        \"\"\")\n\n        File.write!(\"test/test_helper.exs\", \"ExUnit.start()\")\n        File.touch(\"test/a_missing.exs\")\n        File.touch(\"test/a_tests.ex\")\n        File.touch(\"test/ignored_file.exs\")\n        File.touch(\"test/ignored_regex.exs\")\n        File.write!(\"test/other_file.txt\", \"this is not a test file\")\n\n        output = mix([\"test\"])\n\n        # This test relies on the files present in the test_warn fixture.\n        #\n        # We test that we don't warn about a_tests.exs, as it already matches the load pattern.\n        # Similarly, we ignore the empty but present ignored_file.exs and ignored_regex.exs.\n        # other_file.txt does not match the test_pattern and is ignored from the beginning.\n        #\n        # Therefore, we expect to get a warning for a_missing.exs and a_tests.ex.\n        assert output =~ \"\"\"\n               the following files do not match any of the configured `:test_load_filters` / `:test_ignore_filters`:\n\n               test/a_missing.exs\n               test/a_tests.ex\n\n               This might indicate a typo\\\n               \"\"\"\n\n        # the dummy test ran successfully\n        assert output =~ \"Result: 1 passed\"\n      end)\n    end\n\n    test \"does not warn when test_ignore_filters are disabled\" do\n      in_tmp(\"test_warn\", fn ->\n        File.write!(\"mix.exs\", \"\"\"\n        defmodule TestWarn.MixProject do\n          use Mix.Project\n\n          def project do\n            [\n              app: :test_warn,\n              version: \"0.0.1\",\n              test_load_filters: [~r/.*_tests\\.exs/],\n              test_ignore_filters: [fn _ -> true end]\n            ]\n          end\n        end\n        \"\"\")\n\n        File.mkdir!(\"test\")\n\n        File.write!(\"test/a_tests.exs\", \"\"\"\n        defmodule ATests do\n          use ExUnit.Case\n\n          test \"dummy\" do\n            assert true\n          end\n        end\n        \"\"\")\n\n        File.write!(\"test/test_helper.exs\", \"ExUnit.start()\")\n        File.touch(\"test/a_missing.exs\")\n        File.touch(\"test/a_tests.ex\")\n        File.touch(\"test/ignored_file.exs\")\n        File.touch(\"test/ignored_regex.exs\")\n        File.write!(\"test/other_file.txt\", \"this is not a test file\")\n\n        output = mix([\"test\"])\n\n        refute output =~ \"the following files do not match\"\n\n        # the dummy test ran successfully\n        assert output =~ \"Result: 1 passed\"\n      end)\n    end\n  end\n\n  describe \"--dry-run\" do\n    test \"works with --stale\" do\n      in_fixture(\"test_stale\", fn ->\n        File.write!(\"test/dry_run_one_test_stale.exs\", \"\"\"\n        defmodule DryRunOneTest do\n          use ExUnit.Case\n\n          test \"new test\" do\n            assert true\n          end\n        end\n        \"\"\")\n\n        File.write!(\"test/dry_run_two_test_stale.exs\", \"\"\"\n        defmodule DryRunTwoTest do\n          use ExUnit.Case\n\n          @tag :skip\n          test \"skipped test\" do\n            assert true\n          end\n        end\n        \"\"\")\n\n        output = mix([\"test\", \"--dry-run\", \"--stale\"])\n        assert output =~ \"Tests that would be executed:\"\n        assert output =~ \"test/a_test_stale.exs:4\"\n        assert output =~ \"test/b_test_stale.exs:4\"\n        assert output =~ \"test/dry_run_one_test_stale.exs:4\"\n        refute output =~ \"test/dry_run_two_test_stale.exs:5\"\n        assert output =~ \"Result: 0 tests, 1 skipped\"\n\n        # Tests should still be marked as stale\n        output = mix([\"test\", \"--dry-run\", \"--stale\"])\n        assert output =~ \"Result: 0 tests, 1 skipped\"\n      end)\n    end\n\n    test \"works with --failed\" do\n      in_fixture(\"test_failed\", fn ->\n        output = mix([\"test\"])\n        assert output =~ \"Failed: 2 tests\"\n\n        output = mix([\"test\", \"--dry-run\", \"--failed\"])\n        assert output =~ \"Tests that would be executed:\"\n        assert output =~ \"test/only_failing_test_failed.exs:4\"\n        assert output =~ \"test/passing_and_failing_test_failed.exs:5\"\n        assert output =~ \"Result: 0 tests\"\n\n        # Force the tests to pass, verify dry-run doesn't actually run them\n        System.put_env(\"PASS_FAILING_TESTS\", \"true\")\n        output = mix([\"test\", \"--dry-run\", \"--failed\"])\n        assert output =~ \"Result: 0 tests\"\n      end)\n    after\n      System.delete_env(\"PASS_FAILING_TESTS\")\n    end\n  end\n\n  defp receive_until_match(port, expected, acc) do\n    receive do\n      {^port, {:data, output}} ->\n        acc = acc <> output\n\n        if output =~ expected do\n          acc\n        else\n          receive_until_match(port, expected, acc)\n        end\n    after\n      15_000 ->\n        raise \"\"\"\n        nothing received from port after 15s.\n        Expected: #{inspect(expected)}\n        Got: #{inspect(acc)}\n        \"\"\"\n    end\n  end\n\n  defp set_all_mtimes(time \\\\ {{2010, 1, 1}, {0, 0, 0}}) do\n    Enum.each(Path.wildcard(\"**\", match_dot: true), &File.touch!(&1, time))\n  end\n\n  defp assert_stale_run_output(opts \\\\ [], expected) do\n    assert_run_output([\"--stale\" | opts], expected)\n  end\n\n  defp assert_run_output(opts \\\\ [], expected) do\n    assert mix([\"test\" | opts]) =~ expected\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/will_recompile_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.WillRecompileTest do\n  use MixTest.Case\n\n  test \"marks current project to recompile\" do\n    in_fixture(\"deps_status/deps/ok\", fn ->\n      Mix.Project.in_project(:ok, \".\", fn _ ->\n        refute File.exists?(\"_build/dev/lib/ok/.mix/compile.lock\")\n        Mix.Task.run(\"will_recompile\")\n        assert File.exists?(\"_build/dev/lib/ok/.mix/compile.lock\")\n      end)\n    end)\n  end\n\n  test \"marks all projects in umbrella to recompile including the root itself\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        refute File.exists?(\"_build/dev/.mix/compile.lock\")\n        refute File.exists?(\"_build/dev/lib/foo/.mix/compile.lock\")\n        refute File.exists?(\"_build/dev/lib/bar/.mix/compile.lock\")\n        Mix.Task.run(\"will_recompile\")\n        assert File.exists?(\"_build/dev/.mix/compile.lock\")\n        assert File.exists?(\"_build/dev/lib/foo/.mix/compile.lock\")\n        assert File.exists?(\"_build/dev/lib/bar/.mix/compile.lock\")\n      end)\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/tasks/xref_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.XrefTest do\n  use MixTest.Case\n\n  import ExUnit.CaptureIO\n\n  setup_all do\n    previous = Application.get_env(:elixir, :ansi_enabled, false)\n    Application.put_env(:elixir, :ansi_enabled, false)\n    on_exit(fn -> Application.put_env(:elixir, :ansi_enabled, previous) end)\n  end\n\n  setup do\n    Mix.Project.push(MixTest.Case.Sample)\n    :ok\n  end\n\n  describe \"calls/1\" do\n    test \"returns all function calls\" do\n      files = %{\n        \"lib/a.ex\" => \"\"\"\n        defmodule A do\n          def a, do: A.a()\n          def a(arg), do: A.a(arg)\n          def c, do: B.a()\n        end\n        \"\"\",\n        \"lib/b.ex\" => \"\"\"\n        defmodule B do\n          def a, do: nil\n        end\n        \"\"\"\n      }\n\n      output = [\n        %{callee: {A, :a, 0}, caller_module: A, file: \"lib/a.ex\", line: 2},\n        %{callee: {A, :a, 1}, caller_module: A, file: \"lib/a.ex\", line: 3},\n        %{callee: {B, :a, 0}, caller_module: A, file: \"lib/a.ex\", line: 4}\n      ]\n\n      assert_all_calls(files, output)\n    end\n\n    test \"returns function call inside expanded macro\" do\n      files = %{\n        \"lib/a.ex\" => \"\"\"\n        defmodule A do\n          defmacro a_macro(x) do\n            quote do\n              A.b(unquote(x))\n            end\n          end\n          def b(x), do: x\n        end\n        \"\"\",\n        \"lib/b.ex\" => \"\"\"\n        defmodule B do\n          require A\n          def a, do: A.a_macro(1)\n        end\n        \"\"\"\n      }\n\n      output = [\n        %{callee: {A, :b, 1}, caller_module: B, file: \"lib/b.ex\", line: 3},\n        %{\n          callee: {:elixir_quote, :shallow_validate_ast, 1},\n          caller_module: A,\n          file: \"lib/a.ex\",\n          line: 4\n        }\n      ]\n\n      assert_all_calls(files, output)\n    end\n\n    defp assert_all_calls(files, expected, after_compile \\\\ fn -> :ok end) do\n      in_fixture(\"no_mixfile\", fn ->\n        generate_files(files)\n\n        Mix.Task.run(\"compile\")\n        after_compile.()\n        xref = String.to_atom(\"Elixir.Mix.Tasks.Xref\")\n        assert Enum.sort(xref.calls()) == Enum.sort(expected)\n      end)\n    end\n  end\n\n  describe \"mix xref callers MODULE\" do\n    @callers_files %{\n      \"lib/a.ex\" => \"\"\"\n      defmodule A do\n        def a, do: :ok\n      end\n      \"\"\",\n      \"lib/b.ex\" => \"\"\"\n      defmodule B do\n        def b, do: A.a()\n      end\n      \"\"\"\n    }\n\n    @callers_output \"\"\"\n    Compiling 2 files (.ex)\n    Generated sample app\n    lib/b.ex (runtime)\n    \"\"\"\n\n    test \"prints callers of specified Module\" do\n      assert_callers(\"A\", @callers_files, @callers_output)\n    end\n\n    test \"filter by compile-connected label with fail-above\" do\n      message = \"Too many references (found: 1, permitted: 0)\"\n\n      assert_raise Mix.Error, message, fn ->\n        assert_callers(~w[--fail-above 0], \"A\", @callers_files, @callers_output)\n      end\n    end\n\n    test \"handles aliases\" do\n      files = %{\n        \"lib/a.ex\" => \"\"\"\n        defmodule A do\n          alias Enum, as: E\n\n          def a(a, b), do: E.map(a, b)\n\n          @file \"lib/external_source.ex\"\n          def b() do\n            alias Enum, as: EE\n            EE.map([], &EE.flatten/1)\n          end\n        end\n        \"\"\"\n      }\n\n      output = \"\"\"\n      Compiling 2 files (.ex)\n      Generated sample app\n      lib/a.ex (runtime)\n      \"\"\"\n\n      assert_callers(\"Enum\", files, output)\n    end\n\n    test \"handles imports\" do\n      files = %{\n        \"lib/a.ex\" => ~S\"\"\"\n        defmodule A do\n          import Integer\n          &is_even/1\n        end\n        \"\"\",\n        \"lib/b.ex\" => ~S\"\"\"\n        defmodule B do\n          import Integer\n          parse(\"1\")\n        end\n        \"\"\"\n      }\n\n      output = \"\"\"\n      Compiling 2 files (.ex)\n      Generated sample app\n      lib/a.ex (compile)\n      lib/b.ex (compile)\n      \"\"\"\n\n      assert_callers(\"Integer\", files, output)\n    end\n\n    test \"no argument gives error\" do\n      in_fixture(\"no_mixfile\", fn ->\n        message =\n          \"No argument was given to xref command. Run \\\"mix help xref\\\" for more information\"\n\n        assert_raise Mix.Error, message, fn ->\n          assert Mix.Task.run(\"xref\", [\"callers\"]) == :error\n        end\n      end)\n    end\n\n    test \"callers: gives nice error for quotable but invalid callers spec\" do\n      in_fixture(\"no_mixfile\", fn ->\n        message = \"xref callers MODULE expects a MODULE, got: Module.func(arg)\"\n\n        assert_raise Mix.Error, message, fn ->\n          Mix.Task.run(\"xref\", [\"callers\", \"Module.func(arg)\"])\n        end\n      end)\n    end\n\n    test \"gives nice error for unquotable callers spec\" do\n      in_fixture(\"no_mixfile\", fn ->\n        message = \"xref callers MODULE expects a MODULE, got: %\"\n\n        assert_raise Mix.Error, message, fn ->\n          Mix.Task.run(\"xref\", [\"callers\", \"%\"])\n        end\n      end)\n    end\n\n    defp assert_callers(args \\\\ [], module, files, expected) do\n      in_fixture(\"no_mixfile\", fn ->\n        for {file, contents} <- files do\n          File.write!(file, contents)\n        end\n\n        capture_io(:stderr, fn ->\n          assert Mix.Task.run(\"xref\", args ++ [\"callers\", module]) == :ok\n        end)\n\n        assert ^expected = receive_until_no_messages([])\n      end)\n    end\n  end\n\n  describe \"mix xref trace FILE\" do\n    test \"shows labelled traces\" do\n      files = %{\n        \"lib/a.ex\" => ~S\"\"\"\n        defmodule A do\n          defstruct [:foo, :bar]\n          defmacro macro, do: :ok\n          def fun, do: :ok\n        end\n        \"\"\",\n        \"lib/b.ex\" => ~S\"\"\"\n        defmodule B do\n          import A\n          A.macro()\n          macro()\n          A.fun()\n          fun()\n          def calls_macro, do: A.macro()\n          def calls_fun, do: A.fun()\n          def calls_struct, do: %A{}\n          def matches_struct(%A{}), do: :ok\n          match?(%A{}, List.flatten([]))\n        end\n        \"\"\"\n      }\n\n      output = \"\"\"\n      Compiling 2 files (.ex)\n      Generated sample app\n      lib/b.ex:2: require A (export)\n      lib/b.ex:3: call A.macro/0 (compile)\n      lib/b.ex:4: import call A.macro/0 (compile)\n      lib/b.ex:5: call A.fun/0 (compile)\n      lib/b.ex:6: import call A.fun/0 (compile)\n      lib/b.ex:7: call A.macro/0 (compile)\n      lib/b.ex:8: call A.fun/0 (runtime)\n      lib/b.ex:9: struct A (export)\n      lib/b.ex:10: struct A (runtime)\n      lib/b.ex:11: struct A (export)\n      \"\"\"\n\n      assert_trace(\"lib/b.ex\", files, output)\n    end\n\n    test \"ignores dependencies from patterns and guards\" do\n      files = %{\n        \"lib/a.ex\" => ~S\"\"\"\n        defmodule A do\n          defstruct [:foo, :bar]\n        end\n        \"\"\",\n        \"lib/b.ex\" => ~S\"\"\"\n        defmodule B do\n          def pattern(A), do: true\n          def guard(a) when is_struct(a, A), do: true\n        end\n        \"\"\"\n      }\n\n      output = \"\"\"\n      Compiling 2 files (.ex)\n      Generated sample app\n      \"\"\"\n\n      assert_trace(\"lib/b.ex\", files, output)\n    end\n\n    test \"shows traces for module callbacks\" do\n      files = %{\n        \"lib/a.ex\" => ~S\"\"\"\n        defmodule A do\n          @before_compile :\"Elixir.B\"\n          @after_compile :\"Elixir.B\"\n          @after_verify :\"Elixir.B\"\n        end\n        \"\"\",\n        \"lib/b.ex\" => ~S\"\"\"\n        defmodule B do\n          defmacro __before_compile__(_env), do: :ok\n          defmacro __after_compile__(_env, _binary), do: :ok\n          def __after_verify__(_module), do: :ok\n        end\n        \"\"\"\n      }\n\n      output = \"\"\"\n      Compiling 2 files (.ex)\n      Generated sample app\n      lib/a.ex:1: call B.__after_compile__/2 (compile)\n      lib/a.ex:1: call B.__after_verify__/1 (compile)\n      lib/a.ex:1: call B.__before_compile__/1 (compile)\n      \"\"\"\n\n      assert_trace(\"lib/a.ex\", files, output)\n    end\n\n    test \"shows module with `@behaviour` calling `behaviour_info/1`\" do\n      files = %{\n        \"lib/a.ex\" => ~S\"\"\"\n        defmodule A do\n          @callback fun() :: integer\n        end\n        \"\"\",\n        \"lib/b.ex\" => ~S\"\"\"\n        defmodule B do\n          @behaviour :\"Elixir.A\"\n          def fun, do: 42\n        end\n        \"\"\"\n      }\n\n      output = \"\"\"\n      Compiling 2 files (.ex)\n      Generated sample app\n      lib/b.ex:1: call A.behaviour_info/1 (runtime)\n      \"\"\"\n\n      assert_trace(\"lib/b.ex\", files, output)\n    end\n\n    test \"filters per label\" do\n      files = %{\n        \"lib/a.ex\" => ~S\"\"\"\n        defmodule A do\n          defmacro macro, do: :ok\n          def fun, do: :ok\n        end\n        \"\"\",\n        \"lib/b.ex\" => ~S\"\"\"\n        defmodule B do\n          require A\n          def calls_macro, do: A.macro()\n          def calls_fun, do: A.fun()\n        end\n        \"\"\"\n      }\n\n      output = \"\"\"\n      Compiling 2 files (.ex)\n      Generated sample app\n      lib/b.ex:3: call A.macro/0 (compile)\n      \"\"\"\n\n      assert_trace(~w[--label compile], \"lib/b.ex\", files, output)\n    end\n\n    test \"fails if above limit per label\" do\n      files = %{\n        \"lib/a.ex\" => ~S\"\"\"\n        defmodule A do\n          defmacro macro, do: :ok\n          def fun, do: :ok\n        end\n        \"\"\",\n        \"lib/b.ex\" => ~S\"\"\"\n        defmodule B do\n          require A\n          def calls_macro, do: A.macro()\n          def calls_fun, do: A.fun()\n        end\n        \"\"\"\n      }\n\n      output = \"\"\"\n      Compiling 2 files (.ex)\n      Generated sample app\n      lib/b.ex:3: call A.macro/0 (compile)\n      \"\"\"\n\n      message = \"Too many traces (found: 1, permitted: 0)\"\n\n      assert_raise Mix.Error, message, fn ->\n        assert_trace(~w[--label compile --fail-above 0], \"lib/b.ex\", files, output)\n      end\n    end\n\n    defp assert_trace(args \\\\ [], file, files, expected) do\n      in_fixture(\"no_mixfile\", fn ->\n        for {file, contents} <- files do\n          File.write!(file, contents)\n        end\n\n        capture_io(:stderr, fn ->\n          assert Mix.Task.run(\"xref\", args ++ [\"trace\", file]) == :ok\n        end)\n\n        assert receive_until_no_messages([]) == expected\n      end)\n    end\n  end\n\n  describe \"mix xref graph\" do\n    test \"basic usage\" do\n      assert_graph(\"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/b.ex\n      |-- lib/a.ex\n      |-- lib/c.ex\n      `-- lib/e.ex (compile)\n      lib/c.ex\n      `-- lib/d.ex (compile)\n      lib/d.ex\n      `-- lib/e.ex\n      lib/e.ex\n      \"\"\")\n    end\n\n    test \"stats\" do\n      assert_graph([\"--format\", \"stats\"], \"\"\"\n      Tracked files: 5 (nodes)\n      Compile dependencies: 3 (edges)\n      Exports dependencies: 0 (edges)\n      Runtime dependencies: 3 (edges)\n      Cycles: 1\n\n      Top 5 files with most outgoing dependencies:\n        * lib/b.ex (3)\n        * lib/d.ex (1)\n        * lib/c.ex (1)\n        * lib/a.ex (1)\n        * lib/e.ex (0)\n\n      Top 5 files with most incoming dependencies:\n        * lib/e.ex (2)\n        * lib/d.ex (1)\n        * lib/c.ex (1)\n        * lib/b.ex (1)\n        * lib/a.ex (1)\n      \"\"\")\n    end\n\n    test \"stats with compile label\" do\n      assert_graph([\"--format\", \"stats\", \"--label\", \"compile\"], \"\"\"\n      Tracked files: 5 (nodes)\n      Compile dependencies: 3 (edges)\n      Exports dependencies: 0 (edges)\n      Runtime dependencies: 3 (edges)\n      Cycles: 1\n\n      Top 5 files with most outgoing dependencies:\n        * lib/c.ex (1)\n        * lib/b.ex (1)\n        * lib/a.ex (1)\n        * lib/e.ex (0)\n        * lib/d.ex (0)\n\n      Top 5 files with most incoming dependencies:\n        * lib/e.ex (1)\n        * lib/d.ex (1)\n        * lib/b.ex (1)\n        * lib/c.ex (0)\n        * lib/a.ex (0)\n      \"\"\")\n    end\n\n    test \"stats with compile-connected label\" do\n      assert_graph([\"--format\", \"stats\", \"--label\", \"compile-connected\"], \"\"\"\n      Tracked files: 5 (nodes)\n      Compile dependencies: 3 (edges)\n      Exports dependencies: 0 (edges)\n      Runtime dependencies: 3 (edges)\n      Cycles: 1\n\n      Top 5 files with most outgoing dependencies:\n        * lib/c.ex (1)\n        * lib/b.ex (1)\n        * lib/a.ex (1)\n        * lib/e.ex (0)\n        * lib/d.ex (0)\n\n      Top 5 files with most incoming dependencies:\n        * lib/d.ex (1)\n        * lib/b.ex (1)\n        * lib/e.ex (0)\n        * lib/c.ex (0)\n        * lib/a.ex (0)\n      \"\"\")\n    end\n\n    test \"cycles\" do\n      assert_graph([\"--format\", \"cycles\"], \"\"\"\n      1 cycles found. Showing them in decreasing size:\n\n      Cycle of length 2 (1 compile):\n\n          lib/a.ex (compile)\n          lib/b.ex\n\n      \"\"\")\n    end\n\n    test \"cycles with compile label require at least one of such type\" do\n      assert_graph([\"--format\", \"cycles\", \"--label\", \"compile\"], \"\"\"\n      1 cycles found. Showing them in decreasing size:\n\n      Cycle of length 2 (1 compile):\n\n          lib/a.ex (compile)\n          lib/b.ex\n\n      \"\"\")\n    end\n\n    test \"cycles with compile-connected label is the same as compile\" do\n      assert_graph([\"--format\", \"cycles\", \"--label\", \"compile-connected\"], \"\"\"\n      1 cycles found. Showing them in decreasing size:\n\n      Cycle of length 2 (1 compile):\n\n          lib/a.ex (compile)\n          lib/b.ex\n\n      \"\"\")\n    end\n\n    test \"cycles with `--fail-above`\" do\n      message = \"Too many cycles (found: 1, permitted: 0)\"\n\n      assert_raise Mix.Error, message, fn ->\n        assert_graph([\"--format\", \"cycles\", \"--fail-above\", \"0\"], \"\"\"\n        1 cycles found. Showing them in decreasing size:\n\n        Cycle of length 2 (1 compile):\n\n            lib/a.ex (compile)\n            lib/b.ex\n\n        \"\"\")\n      end\n    end\n\n    test \"cycles with min_cycle_label matching actual length\" do\n      assert_graph([\"--format\", \"cycles\", \"--label\", \"compile\", \"--min-cycle-label\", \"1\"], \"\"\"\n      1 cycles found. Showing them in decreasing size:\n\n      Cycle of length 2 (1 compile):\n\n          lib/a.ex (compile)\n          lib/b.ex\n\n      \"\"\")\n    end\n\n    test \"cycles with min_cycle_size matching actual length\" do\n      assert_graph([\"--format\", \"cycles\", \"--min-cycle-size\", \"2\"], \"\"\"\n      1 cycles found. Showing them in decreasing size:\n\n      Cycle of length 2 (1 compile):\n\n          lib/a.ex (compile)\n          lib/b.ex\n\n      \"\"\")\n    end\n\n    test \"cycles with min_cycle_label greater than actual length\" do\n      assert_graph([\"--format\", \"cycles\", \"--label\", \"compile\", \"--min-cycle-label\", \"2\"], \"\"\"\n      No cycles found\n      \"\"\")\n    end\n\n    test \"bad min_cycle_label\" do\n      assert_raise Mix.Error, \"--min-cycle-label must be greater than 0\", fn ->\n        assert_graph([\"--format\", \"cycles\", \"--label\", \"compile\", \"--min-cycle-label\", \"0\"], \"\")\n      end\n    end\n\n    test \"cycles with min_cycle_size greater than actual length\" do\n      assert_graph([\"--format\", \"cycles\", \"--min-cycle-size\", \"3\"], \"\"\"\n      No cycles found\n      \"\"\")\n    end\n\n    test \"unknown label\" do\n      assert_raise Mix.Error, \"Unknown --label bad in mix xref graph\", fn ->\n        assert_graph([\"--label\", \"bad\"], \"\")\n      end\n    end\n\n    test \"unknown format\" do\n      assert_raise Mix.Error, \"Unknown --format bad in mix xref graph\", fn ->\n        assert_graph([\"--format\", \"bad\"], \"\")\n      end\n    end\n\n    test \"exclude many\" do\n      assert_graph(~w[--exclude lib/c.ex --exclude lib/b.ex], \"\"\"\n      lib/a.ex\n      lib/d.ex\n      `-- lib/e.ex\n      lib/e.ex\n      \"\"\")\n    end\n\n    test \"exclude one\" do\n      assert_graph(~w[--exclude lib/d.ex], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/b.ex\n      |-- lib/a.ex\n      |-- lib/c.ex\n      `-- lib/e.ex (compile)\n      lib/c.ex\n      lib/e.ex\n      \"\"\")\n    end\n\n    @abc_linear_files %{\n      \"lib/a.ex\" => \"defmodule A, do: def(a, do: B.b())\",\n      \"lib/b.ex\" => \"defmodule B, do: def(b, do: C.c())\",\n      \"lib/c.ex\" => \"defmodule C, do: def(c, do: true)\"\n    }\n\n    test \"exclude one from linear case\" do\n      assert_graph(\n        ~w[--exclude lib/b.ex],\n        \"\"\"\n        lib/a.ex\n        lib/c.ex\n        \"\"\",\n        files: @abc_linear_files\n      )\n    end\n\n    test \"exclude one with source from linear case\" do\n      assert_graph(\n        ~w[--exclude lib/b.ex --source lib/a.ex],\n        \"\"\"\n        lib/a.ex\n        \"\"\",\n        files: @abc_linear_files\n      )\n    end\n\n    test \"invalid exclude\" do\n      assert_raise Mix.Error, \"Excluded files could not be found: lib/a2.ex, lib/a3.ex\", fn ->\n        assert_graph(~w[--exclude lib/a2.ex --exclude lib/a.ex --exclude lib/a3.ex], \"\")\n      end\n    end\n\n    test \"only nodes\" do\n      assert_graph(~w[--only-nodes], \"\"\"\n      lib/a.ex\n      lib/b.ex\n      lib/c.ex\n      lib/d.ex\n      lib/e.ex\n      \"\"\")\n    end\n\n    test \"only nodes with compile direct label\" do\n      assert_graph(~w[--label compile --only-direct --only-nodes], \"\"\"\n      lib/a.ex\n      lib/b.ex\n      lib/c.ex\n      \"\"\")\n    end\n\n    test \"filter by compile label\" do\n      assert_graph(~w[--label compile], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/b.ex\n      `-- lib/e.ex (compile)\n      lib/c.ex\n      `-- lib/d.ex (compile)\n      \"\"\")\n    end\n\n    test \"filter by compile-connected label\" do\n      assert_graph(~w[--label compile-connected], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/c.ex\n      `-- lib/d.ex (compile)\n      \"\"\")\n    end\n\n    test \"filter by compile-connected label with exclusions\" do\n      assert_graph(~w[--label compile-connected --exclude lib/e.ex], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      \"\"\")\n    end\n\n    test \"filter by compile-connected label with fail-above\" do\n      message = \"Too many references (found: 2, permitted: 1)\"\n\n      assert_raise Mix.Error, message, fn ->\n        assert_graph(~w[--label compile-connected --fail-above 1], \"\"\"\n        lib/a.ex\n        `-- lib/b.ex (compile)\n        lib/c.ex\n        `-- lib/d.ex (compile)\n        \"\"\")\n      end\n    end\n\n    test \"exclude many with fail-above\" do\n      message = \"Too many references (found: 1, permitted: 0)\"\n\n      assert_raise Mix.Error, message, fn ->\n        assert_graph(~w[--exclude lib/c.ex --exclude lib/b.ex --fail-above 0], \"\"\"\n        lib/a.ex\n        lib/d.ex\n        `-- lib/e.ex\n        lib/e.ex\n        \"\"\")\n      end\n    end\n\n    test \"filter by compile direct label\" do\n      assert_graph(~w[--label compile --only-direct], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/b.ex\n      `-- lib/e.ex (compile)\n      lib/c.ex\n      `-- lib/d.ex (compile)\n      \"\"\")\n    end\n\n    test \"filter by runtime label\" do\n      assert_graph(~w[--label runtime], \"\"\"\n      lib/b.ex\n      |-- lib/a.ex\n      `-- lib/c.ex\n      lib/d.ex\n      `-- lib/e.ex\n      \"\"\")\n    end\n\n    test \"sources\" do\n      assert_graph(\n        ~w[--source lib/a.ex --source lib/c.ex],\n        \"\"\"\n        lib/a.ex\n        `-- lib/b.ex (compile)\n            |-- lib/a.ex\n            |-- lib/c.ex\n            `-- lib/e.ex (compile)\n        lib/c.ex\n        `-- lib/d.ex (compile)\n            `-- lib/e.ex\n\n        WARNING: Source lib/a.ex is part of a cycle of 2 nodes and this cycle has a compile \\\n        dependency. Therefore source and the whole cycle will recompile whenever any of the \\\n        files they depend on change. Run \"mix xref graph --format stats --label compile-connected\" \\\n        to print compilation cycles and \"mix help xref\" for information on removing them\n        \"\"\",\n        warnings: true\n      )\n    end\n\n    test \"source with compile label\" do\n      assert_graph(~w[--source lib/a.ex --label compile], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n          `-- lib/e.ex (compile)\n      \"\"\")\n    end\n\n    test \"source with compile-connected label\" do\n      assert_graph(~w[--source lib/a.ex --label compile-connected], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      \"\"\")\n    end\n\n    test \"source with compile direct label\" do\n      assert_graph(~w[--source lib/a.ex --label compile --only-direct], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n          `-- lib/e.ex (compile)\n      \"\"\")\n    end\n\n    test \"invalid sources\" do\n      assert_raise Mix.Error, \"Sources could not be found: lib/a2.ex, lib/a3.ex\", fn ->\n        assert_graph(~w[--source lib/a2.ex --source lib/a.ex --source lib/a3.ex], \"\")\n      end\n    end\n\n    test \"sink\" do\n      assert_graph(~w[--sink lib/e.ex], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/b.ex\n      |-- lib/a.ex\n      |-- lib/c.ex\n      `-- lib/e.ex (compile)\n      lib/c.ex\n      `-- lib/d.ex (compile)\n      lib/d.ex\n      `-- lib/e.ex\n      \"\"\")\n    end\n\n    test \"sink with compile label\" do\n      assert_graph(~w[--sink lib/e.ex --label compile], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/b.ex\n      `-- lib/e.ex (compile)\n      lib/c.ex\n      `-- lib/d.ex (compile)\n      \"\"\")\n    end\n\n    test \"sink with compile-connected label\" do\n      assert_graph(~w[--sink lib/e.ex --label compile-connected], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/c.ex\n      `-- lib/d.ex (compile)\n      \"\"\")\n    end\n\n    test \"sink with compile direct label\" do\n      assert_graph(~w[--sink lib/e.ex --label compile --only-direct], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n      lib/b.ex\n      `-- lib/e.ex (compile)\n      \"\"\")\n    end\n\n    test \"multiple sinks\" do\n      assert_graph(~w[--sink lib/a.ex --sink lib/c.ex], \"\"\"\n      lib/b.ex\n      |-- lib/a.ex\n      |   `-- lib/b.ex (compile)\n      `-- lib/c.ex\n      \"\"\")\n    end\n\n    test \"multiple sinks with only nodes\" do\n      assert_graph(~w[--sink lib/a.ex --sink lib/c.ex --sink lib/e.ex --only-nodes], \"\"\"\n      lib/b.ex\n      lib/d.ex\n      \"\"\")\n    end\n\n    test \"invalid sink\" do\n      assert_raise Mix.Error, \"Sinks could not be found: lib/b2.ex, lib/b3.ex\", fn ->\n        assert_graph(~w[--sink lib/b2.ex --sink lib/b.ex --sink lib/b3.ex], \"\")\n      end\n    end\n\n    test \"sink and source\" do\n      assert_graph(~w[--source lib/a.ex --sink lib/b.ex], \"\"\"\n      lib/a.ex\n      `-- lib/b.ex (compile)\n          `-- lib/a.ex\n      \"\"\")\n    end\n\n    test \"with dynamic module\" do\n      in_fixture(\"no_mixfile\", fn ->\n        File.write!(\"lib/a.ex\", \"\"\"\n        B.define()\n        \"\"\")\n\n        File.write!(\"lib/b.ex\", \"\"\"\n        defmodule B do\n          def define do\n            defmodule A do\n            end\n          end\n        end\n        \"\"\")\n\n        assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"dot\"]) == :ok\n\n        assert File.read!(\"xref_graph.dot\") === \"\"\"\n               digraph \"xref graph\" {\n                 \"lib/a.ex\"\n                 \"lib/a.ex\" -> \"lib/b.ex\" [label=\"(compile)\"]\n                 \"lib/b.ex\"\n               }\n               \"\"\"\n\n        assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"json\", \"--output\", \"xref_graph.json\"]) ==\n                 :ok\n\n        assert File.read!(\"xref_graph.json\") ===\n                 String.trim_trailing(\"\"\"\n                 {\"lib/a.ex\":{\"lib/b.ex\":\"compile\"},\"lib/b.ex\":{}}\n                 \"\"\")\n      end)\n    end\n\n    test \"with export\" do\n      in_fixture(\"no_mixfile\", fn ->\n        File.write!(\"lib/a.ex\", \"\"\"\n        defmodule A do\n          def fun do\n            %B{}\n          end\n        end\n        \"\"\")\n\n        File.write!(\"lib/b.ex\", \"\"\"\n        defmodule B do\n          defstruct []\n        end\n        \"\"\")\n\n        assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"dot\"]) == :ok\n\n        assert File.read!(\"xref_graph.dot\") === \"\"\"\n               digraph \"xref graph\" {\n                 \"lib/a.ex\"\n                 \"lib/a.ex\" -> \"lib/b.ex\" [label=\"(export)\"]\n                 \"lib/b.ex\"\n               }\n               \"\"\"\n\n        assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"json\", \"--output\", \"xref_graph.json\"]) ==\n                 :ok\n\n        assert File.read!(\"xref_graph.json\") ===\n                 String.trim_trailing(\"\"\"\n                 {\"lib/a.ex\":{\"lib/b.ex\":\"export\"},\"lib/b.ex\":{}}\n                 \"\"\")\n      end)\n    end\n\n    test \"with export to a custom file\" do\n      in_fixture(\"no_mixfile\", fn ->\n        File.write!(\"lib/a.ex\", \"\"\"\n        defmodule A do\n          def fun, do: :ok\n        end\n        \"\"\")\n\n        File.write!(\"lib/b.ex\", \"\"\"\n        defmodule B do\n          defstruct []\n        end\n        \"\"\")\n\n        assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"dot\", \"--output\", \"custom.dot\"]) == :ok\n\n        assert File.read!(\"custom.dot\") === \"\"\"\n               digraph \"xref graph\" {\n                 \"lib/a.ex\"\n                 \"lib/b.ex\"\n               }\n               \"\"\"\n      end)\n    end\n\n    test \"with export to stdout\" do\n      in_fixture(\"no_mixfile\", fn ->\n        File.write!(\"lib/a.ex\", \"\"\"\n        defmodule A do\n          def fun, do: :ok\n        end\n        \"\"\")\n\n        File.write!(\"lib/b.ex\", \"\"\"\n        defmodule B do\n          defstruct []\n        end\n        \"\"\")\n\n        output =\n          capture_io(fn ->\n            assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"json\", \"--output\", \"-\"]) == :ok\n          end)\n\n        assert output ===\n                 String.trim_trailing(\"\"\"\n                 {\"lib/a.ex\":{},\"lib/b.ex\":{}}\n                 \"\"\")\n\n        output =\n          capture_io(fn ->\n            assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"dot\", \"--output\", \"-\"]) == :ok\n          end)\n\n        assert output === \"\"\"\n               digraph \"xref graph\" {\n                 \"lib/a.ex\"\n                 \"lib/b.ex\"\n               }\n               \"\"\"\n      end)\n    end\n\n    test \"with mixed cyclic dependencies\" do\n      in_fixture(\"no_mixfile\", fn ->\n        File.write!(\"lib/a.ex\", \"\"\"\n        defmodule A.Using do\n          defmacro __using__(_), do: 42\n        end\n\n        defmodule A do\n          B\n\n          def foo do\n            :foo\n          end\n        end\n        \"\"\")\n\n        File.write!(\"lib/b.ex\", \"\"\"\n        defmodule B do\n          # Let's also test that we track literal atom behaviours\n          use :\"Elixir.A.Using\"\n\n          def foo do\n            A.foo()\n          end\n        end\n        \"\"\")\n\n        assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"dot\"]) == :ok\n\n        assert File.read!(\"xref_graph.dot\") === \"\"\"\n               digraph \"xref graph\" {\n                 \"lib/a.ex\"\n                 \"lib/a.ex\" -> \"lib/b.ex\" [label=\"(compile)\"]\n                 \"lib/b.ex\" -> \"lib/a.ex\" [label=\"(compile)\"]\n                 \"lib/b.ex\"\n               }\n               \"\"\"\n\n        assert Mix.Task.run(\"xref\", [\"graph\", \"--format\", \"json\"]) ==\n                 :ok\n\n        assert File.read!(\"xref_graph.json\") ===\n                 String.trim_trailing(\"\"\"\n                 {\"lib/a.ex\":{\"lib/b.ex\":\"compile\"},\"lib/b.ex\":{\"lib/a.ex\":\"compile\"}}\n                 \"\"\")\n      end)\n    end\n\n    test \"generates reports from the umbrella root\" do\n      Mix.Project.pop()\n\n      in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n        Mix.Project.in_project(:umbrella, \".\", fn _ ->\n          File.write!(\"apps/bar/lib/bar.ex\", \"\"\"\n          defmodule Bar do\n            def bar do\n              Foo.foo()\n            end\n          end\n          \"\"\")\n\n          Mix.Task.run(\"compile\")\n          Mix.shell().flush()\n\n          Mix.Tasks.Xref.run([\"graph\", \"--format\", \"stats\", \"--include-siblings\"])\n\n          assert receive_until_no_messages([]) == \"\"\"\n                 Tracked files: 2 (nodes)\n                 Compile dependencies: 0 (edges)\n                 Exports dependencies: 0 (edges)\n                 Runtime dependencies: 1 (edges)\n                 Cycles: 0\n\n                 Top 2 files with most outgoing dependencies:\n                   * lib/bar.ex (1)\n                   * lib/foo.ex (0)\n\n                 Top 2 files with most incoming dependencies:\n                   * lib/foo.ex (1)\n                   * lib/bar.ex (0)\n                 \"\"\"\n        end)\n      end)\n    end\n\n    test \"generates reports considering siblings inside umbrellas\" do\n      Mix.Project.pop()\n\n      in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n        Mix.Project.in_project(:bar, \"apps/bar\", fn _ ->\n          File.write!(\"lib/bar.ex\", \"\"\"\n          defmodule Bar do\n            def bar do\n              Foo.foo()\n            end\n          end\n          \"\"\")\n\n          Mix.Task.run(\"compile\")\n          Mix.shell().flush()\n\n          Mix.Tasks.Xref.run([\"graph\", \"--format\", \"stats\", \"--include-siblings\"])\n\n          assert receive_until_no_messages([]) == \"\"\"\n                 Tracked files: 2 (nodes)\n                 Compile dependencies: 0 (edges)\n                 Exports dependencies: 0 (edges)\n                 Runtime dependencies: 1 (edges)\n                 Cycles: 0\n\n                 Top 2 files with most outgoing dependencies:\n                   * lib/bar.ex (1)\n                   * lib/foo.ex (0)\n\n                 Top 2 files with most incoming dependencies:\n                   * lib/foo.ex (1)\n                   * lib/bar.ex (0)\n                 \"\"\"\n\n          Mix.Tasks.Xref.run([\"callers\", \"Foo\"])\n\n          assert receive_until_no_messages([]) == \"\"\"\n                 lib/bar.ex (runtime)\n                 \"\"\"\n        end)\n      end)\n    end\n\n    test \"skip project compilation with --no-compile\" do\n      in_fixture(\"no_mixfile\", fn ->\n        File.write!(\"lib/a.ex\", \"\"\"\n        defmodule A do\n          def a, do: :ok\n        end\n        \"\"\")\n\n        Mix.Tasks.Xref.run([\"graph\", \"--no-compile\"])\n        refute receive_until_no_messages([]) =~ \"lib/a.ex\"\n      end)\n    end\n\n    test \"group with multiple unconnected files\" do\n      assert_graph(~w[--group lib/a.ex,lib/c.ex,lib/e.ex], \"\"\"\n      lib/a.ex+\n      |-- lib/b.ex (compile)\n      `-- lib/d.ex (compile)\n      lib/b.ex\n      `-- lib/a.ex+ (compile)\n      lib/d.ex\n      `-- lib/a.ex+\n      \"\"\")\n    end\n\n    test \"group with directly dependent files and cycle\" do\n      assert_graph([\"--group\", \"lib/a.ex,lib/b.ex,\"], \"\"\"\n      lib/a.ex+\n      |-- lib/c.ex\n      `-- lib/e.ex (compile)\n      lib/c.ex\n      `-- lib/d.ex (compile)\n      lib/d.ex\n      `-- lib/e.ex\n      lib/e.ex\n      \"\"\")\n    end\n\n    test \"multiple groups\" do\n      assert_graph(~w[--group lib/a.ex,lib/b.ex --group lib/c.ex,lib/e.ex], \"\"\"\n      lib/a.ex+\n      `-- lib/c.ex+ (compile)\n      lib/c.ex+\n      `-- lib/d.ex (compile)\n      lib/d.ex\n      `-- lib/c.ex+\n      \"\"\")\n    end\n\n    test \"group with sink\" do\n      assert_graph(~w[--group lib/a.ex,lib/c.ex,lib/e.ex --sink lib/e.ex], \"\"\"\n      lib/b.ex\n      `-- lib/a.ex+ (compile)\n          |-- lib/b.ex (compile)\n          `-- lib/d.ex (compile)\n      lib/d.ex\n      `-- lib/a.ex+\n      \"\"\")\n    end\n\n    test \"dot with cycle\" do\n      assert_graph_dot(\n        ~w[],\n        \"\"\"\n        digraph \"xref graph\" {\n          \"lib/a.ex\"\n          \"lib/a.ex\" -> \"lib/b.ex\" [label=\"(compile)\"]\n          \"lib/b.ex\" -> \"lib/a.ex\"\n          \"lib/b.ex\" -> \"lib/c.ex\"\n          \"lib/c.ex\" -> \"lib/d.ex\" [label=\"(compile)\"]\n          \"lib/d.ex\" -> \"lib/e.ex\"\n          \"lib/b.ex\" -> \"lib/e.ex\" [label=\"(compile)\"]\n          \"lib/b.ex\"\n          \"lib/c.ex\"\n          \"lib/d.ex\"\n          \"lib/e.ex\"\n        }\n        \"\"\"\n      )\n    end\n\n    test \"json with cycle\" do\n      assert_graph_json(\n        ~w[],\n        \"\"\"\n        { \"lib/a.ex\": { \"lib/b.ex\": \"compile\" },\n          \"lib/b.ex\": { \"lib/a.ex\": \"runtime\",\n                        \"lib/c.ex\": \"runtime\",\n                        \"lib/e.ex\": \"compile\" },\n          \"lib/c.ex\": { \"lib/d.ex\": \"compile\" },\n          \"lib/d.ex\": { \"lib/e.ex\": \"runtime\" },\n          \"lib/e.ex\": { } }\n        \"\"\",\n        # make it easier to read the expected output\n        strip_ws: true\n      )\n    end\n\n    @default_files %{\n      \"lib/a.ex\" => \"\"\"\n      defmodule A do\n        def a, do: :ok\n        B.b2()\n      end\n      \"\"\",\n      \"lib/b.ex\" => \"\"\"\n      defmodule B do\n        def b1, do: A.a() == C.c()\n        def b2, do: :ok\n        :e.e()\n      end\n      \"\"\",\n      \"lib/c.ex\" => \"\"\"\n      defmodule C do\n        def c, do: :ok\n        :d.d()\n      end\n      \"\"\",\n      \"lib/d.ex\" => \"\"\"\n      defmodule :d do\n        def d, do: :ok\n        def e, do: :e.e()\n      end\n      \"\"\",\n      \"lib/e.ex\" => \"\"\"\n      defmodule :e do\n        def e, do: :ok\n      end\n      \"\"\"\n    }\n\n    defp assert_graph_json(args, expected, opts) do\n      assert_graph_io(\"json\", args, expected, opts)\n    end\n\n    defp assert_graph_dot(args, expected, opts \\\\ []) do\n      assert_graph_io(\"dot\", args, expected, opts)\n    end\n\n    # note that we trim_trailing on expected and output\n    # we also support :strip_ws in opts, which removes all\n    # whitespace from expected (but not output!) before performing\n    # the test.\n    defp assert_graph_io(format, args, expected, opts) do\n      in_fixture(\"no_mixfile\", fn ->\n        Enum.each(opts[:files] || @default_files, fn {path, content} ->\n          File.write!(path, content)\n        end)\n\n        output =\n          String.trim_trailing(\n            capture_io(fn ->\n              assert Mix.Task.run(\n                       \"xref\",\n                       args ++ [\"graph\", \"--format\", format, \"--output\", \"-\"]\n                     ) == :ok\n            end)\n          )\n\n        expected =\n          if opts[:strip_ws],\n            do: Regex.replace(~r/\\s+/, expected, \"\", global: true),\n            else: String.trim_trailing(expected)\n\n        assert output === expected\n      end)\n    end\n\n    defp assert_graph(args \\\\ [], expected, opts \\\\ []) do\n      in_fixture(\"no_mixfile\", fn ->\n        nb_files =\n          Enum.count(opts[:files] || @default_files, fn {path, content} ->\n            File.write!(path, content)\n          end)\n\n        assert Mix.Task.run(\"xref\", args ++ [\"graph\"]) == :ok\n        first_line = \"Compiling #{nb_files} files (.ex)\"\n\n        assert [\n                 ^first_line,\n                 \"Generated sample app\" | result\n               ] = receive_until_no_messages([]) |> String.split(\"\\n\")\n\n        result =\n          if Keyword.get(opts, :warnings, false) do\n            result\n          else\n            Enum.take_while(result, &(not String.starts_with?(&1, \"WARNING: \")))\n          end\n\n        assert result |> Enum.join(\"\\n\") |> normalize_graph_output() == expected\n      end)\n    end\n\n    defp normalize_graph_output(graph) do\n      graph\n      |> String.replace(\"├──\", \"|--\")\n      |> String.replace(\"└──\", \"`--\")\n      |> String.replace(\"│\", \"|\")\n    end\n  end\n\n  ## Helpers\n\n  defp receive_until_no_messages(acc) do\n    receive do\n      {:mix_shell, :info, [line]} -> receive_until_no_messages([acc, line | \"\\n\"])\n    after\n      0 -> IO.iodata_to_binary(acc)\n    end\n  end\n\n  defp generate_files(files) do\n    for {file, contents} <- files do\n      File.write!(file, contents)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/umbrella_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.UmbrellaTest do\n  use MixTest.Case\n\n  test \"apps_paths and parent_umbrella_project_file\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      assert Mix.Project.apps_paths() == nil\n      assert Mix.Project.parent_umbrella_project_file() == nil\n\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        assert Mix.Project.apps_paths() == %{bar: \"apps/bar\", foo: \"apps/foo\"}\n        assert Mix.Project.parent_umbrella_project_file() == nil\n\n        assert_received {:mix_shell, :error,\n                         [\"warning: path \\\"apps/dont_error_on_missing_mixfile\\\"\" <> _]}\n\n        refute_received {:mix_shell, :error, [\"warning: path \\\"apps/dont_error_on_files\\\"\" <> _]}\n      end)\n    end)\n  end\n\n  test \"apps_paths with selection\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", [apps: [:foo, :bar]], fn _ ->\n        File.mkdir_p!(\"apps/errors\")\n        File.write!(\"apps/errors/mix.exs\", \"raise :oops\")\n        assert Mix.Project.apps_paths() == %{bar: \"apps/bar\", foo: \"apps/foo\"}\n      end)\n    end)\n  end\n\n  test \"umbrella app dir and the app name defined in mix.exs should be equal\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/bar/mix.exs\", \"\"\"\n        defmodule Bar.MixProject do\n          use Mix.Project\n\n          def project do\n            [app: :baz,\n             version: \"0.1.0\",\n             deps: []]\n          end\n        end\n        \"\"\")\n\n        assert_raise Mix.Error, ~r/^Umbrella app :baz is located at directory bar/, fn ->\n          Mix.Task.run(\"deps\")\n        end\n      end)\n    end)\n  end\n\n  test \"compiles umbrella\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Task.run(\"deps\")\n        assert_received {:mix_shell, :info, [\"* bar (apps/bar) (mix)\"]}\n        assert_received {:mix_shell, :info, [\"* foo (apps/foo) (mix)\"]}\n\n        # Ensure we can compile and run checks\n        Mix.Task.run(\"deps.compile\")\n        Mix.Task.run(\"deps.loadpaths\")\n        Mix.Task.run(\"compile\")\n\n        # Extra applications are picked even for umbrellas\n        assert :code.where_is_file(~c\"runtime_tools.app\") != :non_existing\n        assert :code.where_is_file(~c\"observer.app\") == :non_existing\n\n        assert_received {:mix_shell, :info, [\"==> bar\"]}\n        assert_received {:mix_shell, :info, [\"Generated bar app\"]}\n        assert File.regular?(\"_build/dev/lib/bar/ebin/Elixir.Bar.beam\")\n        assert_received {:mix_shell, :info, [\"==> foo\"]}\n        assert_received {:mix_shell, :info, [\"Generated foo app\"]}\n        assert File.regular?(\"_build/dev/lib/foo/ebin/Elixir.Foo.beam\")\n\n        # Ensure foo was loaded and in the same env as Mix.env\n        assert_received {:mix_shell, :info, [\":foo env is dev\"]}\n        assert_received {:mix_shell, :info, [\":bar env is dev\"]}\n\n        # Ensure we can compile --force\n        Mix.Task.clear()\n        Mix.Task.run(\"compile\", [\"--force\"])\n        assert_received {:mix_shell, :info, [\"Generated foo app\"]}\n        assert_received {:mix_shell, :info, [\"Generated bar app\"]}\n\n        # Ensure we can start even with --no-compile\n        Mix.Task.clear()\n        Mix.Task.run(\"app.start\", [\"--no-compile\"])\n      end)\n    end)\n  end\n\n  test \"compiles umbrella with protocol consolidation\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Task.run(\"compile\", [\"--verbose\"])\n        assert_received {:mix_shell, :info, [\"Generated bar app\"]}\n        assert_received {:mix_shell, :info, [\"Generated foo app\"]}\n        assert File.regular?(\"_build/dev/consolidated/Elixir.Enumerable.beam\")\n        purge([Enumerable])\n\n        assert Mix.Tasks.App.Start.run([])\n        assert Protocol.consolidated?(Enumerable)\n      end)\n    end)\n  end\n\n  test \"recursively compiles umbrella with protocol consolidation\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        defmodule Elixir.Mix.Tasks.Umbrella.Recur do\n          use Mix.Task\n          @recursive true\n\n          def run(_) do\n            assert Mix.Task.recursing?()\n            Mix.Task.run(\"compile\", [\"--verbose\"])\n          end\n        end\n\n        Mix.Task.run(\"umbrella.recur\")\n        assert_received {:mix_shell, :info, [\"Generated bar app\"]}\n        assert_received {:mix_shell, :info, [\"Generated foo app\"]}\n        assert File.regular?(\"_build/dev/consolidated/Elixir.Enumerable.beam\")\n        purge([Enumerable])\n\n        assert Mix.Tasks.App.Start.run([])\n        assert Protocol.consolidated?(Enumerable)\n      end)\n    end)\n  end\n\n  defmodule UmbrellaDeps do\n    def project do\n      [apps_path: \"apps\", deps: [{:some_dep, path: \"deps/some_dep\"}]]\n    end\n  end\n\n  test \"loads umbrella dependencies\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.push(UmbrellaDeps)\n\n      File.mkdir_p!(\"deps/some_dep/ebin\")\n      File.mkdir_p!(\"_build/dev/lib/some_dep/ebin\")\n      File.mkdir_p!(\"_build/dev/lib/foo/ebin\")\n      File.mkdir_p!(\"_build/dev/lib/bar/ebin\")\n\n      Mix.Task.run(\"loadpaths\", [\"--no-deps-check\", \"--no-elixir-version-check\"])\n      assert to_charlist(Path.expand(\"_build/dev/lib/some_dep/ebin\")) in :code.get_path()\n      assert to_charlist(Path.expand(\"_build/dev/lib/foo/ebin\")) in :code.get_path()\n      assert to_charlist(Path.expand(\"_build/dev/lib/bar/ebin\")) in :code.get_path()\n    end)\n  end\n\n  test \"loads umbrella child dependencies in all environments\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/bar/mix.exs\", \"\"\"\n        defmodule Bar.MixProject do\n          use Mix.Project\n\n          def project do\n            [app: :bar,\n             version: \"0.1.0\",\n             deps: [{:git_repo, git: MixTest.Case.fixture_path(\"git_repo\"), only: :other}]]\n          end\n        end\n        \"\"\")\n\n        # Does not fetch when filtered\n        Mix.Tasks.Deps.Get.run([\"--only\", \"dev\"])\n        refute_received {:mix_shell, :info, [\"* Getting git_repo\" <> _]}\n\n        # But works across all environments\n        Mix.Tasks.Deps.Get.run([])\n        assert_received {:mix_shell, :info, [\"* Getting git_repo\" <> _]}\n\n        # Does not show by default\n        Mix.Tasks.Deps.run([])\n        refute_received {:mix_shell, :info, [\"* git_repo\" <> _]}\n\n        # But shows on proper environment\n        Mix.env(:other)\n        Mix.Tasks.Deps.run([])\n        assert_received {:mix_shell, :info, [\"* git_repo \" <> _]}\n      end)\n    end)\n  after\n    Mix.env(:test)\n  end\n\n  test \"loads umbrella child optional dependencies\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/bar/mix.exs\", \"\"\"\n        defmodule Bar.MixProject do\n          use Mix.Project\n\n          def project do\n            [app: :bar,\n             version: \"0.1.0\",\n             deps: [{:git_repo, git: MixTest.Case.fixture_path(\"git_repo\"), optional: true}]]\n          end\n        end\n        \"\"\")\n\n        Mix.Tasks.Deps.run([])\n        assert_received {:mix_shell, :info, [\"* git_repo \" <> _]}\n      end)\n    end)\n  end\n\n  test \"loads umbrella sibling dependencies with :in_umbrella\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/bar/mix.exs\", \"\"\"\n        defmodule Bar.MixProject do\n          use Mix.Project\n\n          def project do\n            [app: :bar,\n             version: \"0.1.0\",\n             deps: [{:foo, in_umbrella: true}]]\n          end\n        end\n        \"\"\")\n\n        # Running from umbrella should not cause conflicts\n        Mix.Tasks.Deps.Get.run([])\n        Mix.Tasks.Run.run([])\n      end)\n    end)\n  end\n\n  test \"conflicts with umbrella sibling dependencies in :in_umbrella\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/bar/mix.exs\", \"\"\"\n        defmodule Bar.MixProject do\n          use Mix.Project\n\n          def project do\n            [app: :bar,\n             version: \"0.1.0\",\n             deps: [{:foo, in_umbrella: true, env: :unknown}]]\n          end\n        end\n        \"\"\")\n\n        assert_raise Mix.Error, fn ->\n          Mix.Tasks.Deps.Get.run([])\n        end\n\n        assert_received {:mix_shell, :error, [\"Dependencies have diverged:\"]}\n\n        assert_received {:mix_shell, :error,\n                         [\"  the dependency foo in mix.exs is overriding a child\" <> message]}\n\n        assert message =~ \"Please remove the conflicting options from your definition\"\n      end)\n    end)\n  end\n\n  test \"list deps for umbrella as dependency\" do\n    in_fixture(\"umbrella_dep\", fn ->\n      Mix.Project.in_project(:umbrella_dep, \".\", fn _ ->\n        Mix.Task.run(\"deps\")\n        assert_received {:mix_shell, :info, [\"* umbrella (deps/umbrella) (mix)\"]}\n        assert_received {:mix_shell, :info, [\"* foo (apps/foo) (mix)\"]}\n      end)\n    end)\n  end\n\n  # Bar.bar is loaded dynamically\n  @compile {:no_warn_undefined, {Bar, :bar, 0}}\n\n  test \"compile for umbrella as dependency\" do\n    in_fixture(\"umbrella_dep\", fn ->\n      Mix.Project.in_project(:umbrella_dep, \".\", fn _ ->\n        Mix.Task.run(\"compile\")\n        assert Bar.bar() == \"hello world\"\n      end)\n    end)\n  end\n\n  defmodule CycleDeps do\n    def project do\n      [\n        app: :umbrella_dep,\n        deps: [\n          {:bar, path: \"deps/umbrella/apps/bar\"},\n          {:umbrella, path: \"deps/umbrella\"}\n        ]\n      ]\n    end\n  end\n\n  test \"handles dependencies with cycles\" do\n    in_fixture(\"umbrella_dep\", fn ->\n      Mix.Project.push(CycleDeps)\n\n      assert Enum.map(Mix.Dep.Converger.converge([]), & &1.app) == [:foo, :bar, :umbrella]\n    end)\n  end\n\n  test \"handles dependencies with cycles and overridden deps\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/foo/mix.exs\", \"\"\"\n        defmodule Foo.MixProject do\n          use Mix.Project\n\n          def project do\n            # Ensure we have the proper environment\n            :dev = Mix.env()\n\n            [app: :foo,\n             version: \"0.1.0\",\n             deps: [{:bar, in_umbrella: true}]]\n          end\n        end\n        \"\"\")\n\n        File.write!(\"apps/bar/mix.exs\", \"\"\"\n        defmodule Bar.MixProject do\n          use Mix.Project\n\n          def project do\n            # Ensure we have the proper environment\n            :dev = Mix.env()\n\n            [app: :bar,\n             version: \"0.1.0\",\n             deps: [{:a, path: \"deps/a\"},\n                    {:b, path: \"deps/b\"}]]\n          end\n        end\n        \"\"\")\n\n        assert Enum.map(Mix.Dep.Converger.converge([]), & &1.app) == [:a, :b, :bar, :foo]\n      end)\n    end)\n  end\n\n  test \"uses dependency aliases\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/bar/mix.exs\", \"\"\"\n        defmodule Bar.MixProject do\n          use Mix.Project\n\n          def project do\n            [app: :bar,\n             version: \"0.1.0\",\n             aliases: [\"compile.elixir\": fn _ -> Mix.shell().info \"no compile bar\" end]]\n          end\n        end\n        \"\"\")\n\n        Mix.Task.run(\"compile\", [\"--verbose\"])\n        assert_receive {:mix_shell, :info, [\"no compile bar\"]}\n        refute_receive {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}, 100\n      end)\n    end)\n  end\n\n  test \"halts when sibling fails to compile\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/foo/lib/foo.ex\", \"raise ~s[oops]\")\n\n        ExUnit.CaptureIO.capture_io(:stderr, fn ->\n          assert catch_exit(Mix.Task.run(\"compile\", [\"--verbose\"]))\n        end)\n\n        refute_received {:mix_shell, :info, [\"Generated foo app\"]}\n        refute_received {:mix_shell, :info, [\"Generated bar app\"]}\n        refute Code.ensure_loaded?(Bar)\n      end)\n    end)\n  end\n\n  test \"recompiles when compile-time path dependencies change\" do\n    in_fixture(\"umbrella_dep/deps/umbrella/apps\", fn ->\n      Mix.Project.in_project(:bar, \"bar\", fn _ ->\n        Mix.Task.run(\"compile\", [])\n\n        # Add compile time dependency\n        File.write!(\"lib/bar.ex\", \"defmodule Bar, do: Foo.foo()\")\n\n        Mix.Task.clear()\n        assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:ok, []}\n        assert_receive {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n\n        # Compile-time dependencies are recompiled\n        File.write!(\"../foo/lib/foo.ex\", File.read!(\"../foo/lib/foo.ex\") <> \"\\n\")\n        ensure_touched(\"../foo/lib/foo.ex\", \"_build/dev/lib/bar/.mix/compile.elixir\")\n\n        Mix.Task.clear()\n        assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:ok, []}\n        assert_received {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n      end)\n\n      # Now let's add a new file to foo\n      Mix.Project.in_project(:foo, \"foo\", fn _ ->\n        File.write!(\"lib/foo_bar.ex\", \"\"\"\n        defmodule Foo.Bar do\n          def baz, do: \"from bar\"\n        end\n        \"\"\")\n\n        Mix.Task.clear()\n        assert Mix.Tasks.Compile.run([\"--verbose\", \"--ignore-module-conflict\"]) == {:ok, []}\n        Application.unload(:foo)\n        Application.load(:foo)\n      end)\n\n      # And bar can use it without warnings\n      Mix.Project.in_project(:bar, \"bar\", fn _ ->\n        File.write!(\"lib/bar.ex\", \"defmodule Bar, do: Foo.Bar.baz()\")\n\n        mtime = File.stat!(\"_build/dev/lib/bar/.mix/compile.elixir\").mtime\n        ensure_touched(\"_build/dev/lib/foo/.mix/compile.elixir\", mtime)\n        ensure_touched(\"_build/dev/lib/foo/ebin/foo.app\", mtime)\n        ensure_touched(\"lib/bar.ex\", mtime)\n\n        assert Mix.Tasks.Compile.Elixir.run([\"--verbose\"]) == {:ok, []}\n        assert_receive {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n      end)\n    end)\n  end\n\n  test \"recompiles after struct path dependency changes\" do\n    in_fixture(\"umbrella_dep/deps/umbrella/apps\", fn ->\n      Mix.Project.in_project(:bar, \"bar\", fn _ ->\n        File.write!(\"../foo/lib/foo.ex\", \"defmodule Foo, do: defstruct [:bar]\")\n\n        # Add struct dependency\n        File.write!(\"lib/bar.ex\", \"\"\"\n        defmodule Bar do\n          def foo_bar(), do: %Foo{bar: true}\n        end\n        \"\"\")\n\n        Mix.Task.run(\"compile\", [\"--verbose\"])\n        assert_received {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n\n        # Does not recompiles if export dependency does not change\n        File.write!(\"../foo/lib/foo.ex\", File.read!(\"../foo/lib/foo.ex\") <> \"\\n\")\n        ensure_touched(\"../foo/lib/foo.ex\", \"_build/dev/lib/bar/.mix/compile.elixir\")\n\n        Mix.Task.clear()\n        assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:ok, []}\n        refute_received {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n\n        # Recompiles if export dependency changes\n        File.write!(\"../foo/lib/foo.ex\", \"defmodule Foo, do: defstruct [:bar, :baz]\")\n        ensure_touched(\"../foo/lib/foo.ex\", \"_build/dev/lib/bar/.mix/compile.elixir\")\n\n        Mix.Task.clear()\n        assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:ok, []}\n        assert_received {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n\n        # Recompiles if export dependency is removed\n        File.write!(\"../foo/lib/foo.ex\", \"\")\n        ensure_touched(\"../foo/lib/foo.ex\", \"_build/dev/lib/bar/.mix/compile.elixir\")\n        Mix.Task.clear()\n\n        ExUnit.CaptureIO.capture_io(:stderr, fn ->\n          assert {:error, _} = Mix.Task.run(\"compile\", [\"--verbose\", \"--return-errors\"])\n        end)\n      end)\n    end)\n  end\n\n  test \"recompiles after compile through runtime path dependency changes\" do\n    in_fixture(\"umbrella_dep/deps/umbrella/apps\", fn ->\n      Mix.Project.in_project(:bar, \"bar\", fn _ ->\n        File.write!(\"../foo/lib/foo.bar.ex\", \"\"\"\n        defmodule Foo.Bar do\n          def hello, do: Foo.Baz.hello()\n        end\n        \"\"\")\n\n        File.write!(\"../foo/lib/foo.baz.ex\", \"\"\"\n        defmodule Foo.Baz do\n          def hello, do: \"from bar\"\n        end\n        \"\"\")\n\n        # Add compile time to Foo.Bar\n        File.write!(\"lib/bar.ex\", \"defmodule Bar, do: Foo.Bar.hello()\")\n        Mix.Task.run(\"compile\", [\"--verbose\"])\n        assert_received {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n\n        # Recompiles for due to compile dependency via runtime dependencies\n        File.write!(\"../foo/lib/foo.baz.ex\", File.read!(\"../foo/lib/foo.baz.ex\") <> \"\\n\")\n        ensure_touched(\"../foo/lib/foo.ex\", \"_build/dev/lib/bar/.mix/compile.elixir\")\n\n        Mix.Task.clear()\n        assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:ok, []}\n        assert_received {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n      end)\n    end)\n  end\n\n  test \"reverifies when path dependency is added\" do\n    in_fixture(\"umbrella_dep/deps/umbrella/apps\", fn ->\n      Mix.Project.in_project(:bar, \"bar\", [deps: []], fn _ ->\n        File.write!(\"lib/bar.ex\", \"\"\"\n        defmodule Bar do\n          def foo, do: Foo.foo()\n        end\n        \"\"\")\n\n        assert ExUnit.CaptureIO.capture_io(:stderr, fn ->\n                 Mix.Task.run(\"compile\", [\"--verbose\"])\n               end) =~ \"Foo.foo/0 is undefined\"\n\n        refute Code.ensure_loaded?(Foo)\n        assert_receive {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n      end)\n\n      Mix.Task.clear()\n\n      Mix.Project.in_project(:bar, \"bar\", fn _ ->\n        Mix.Task.run(\"deps.compile\")\n        assert Mix.Task.run(\"compile\", [\"--verbose\", \"--all-warnings\"]) == {:ok, []}\n      end)\n    end)\n  end\n\n  test \"reloads app in app cache if .app changes\" do\n    in_fixture(\"umbrella_dep/deps/umbrella/apps\", fn ->\n      deps = [{:foo, in_umbrella: true}]\n\n      Mix.Project.in_project(:bar, \"bar\", [deps: deps], fn _ ->\n        Mix.Task.run(\"compile\", [\"--verbose\"])\n\n        File.write!(\"../foo/lib/foo.ex\", \"\"\"\n        defmodule Foo.VeryNew do\n          def hello, do: :ok\n        end\n        \"\"\")\n\n        File.write!(\"lib/bar.ex\", \"\"\"\n        defmodule Bar.VeryNew do\n          def hello, do: Foo.VeryNew.hello()\n        end\n        \"\"\")\n\n        Mix.Task.clear()\n        Application.unload(:foo)\n        ensure_touched(\"../foo/lib/foo.ex\", \"_build/dev/lib/bar/.mix/compile.app_cache\")\n\n        assert Mix.Task.run(\"compile\", [\"--verbose\"]) == {:ok, []}\n        assert_receive {:mix_shell, :info, [\"Compiled lib/bar.ex\"]}\n      end)\n    end)\n  end\n\n  test \"reconsolidates after path dependency changes\" do\n    in_fixture(\"umbrella_dep/deps/umbrella/apps\", fn ->\n      Mix.Project.in_project(:bar, \"bar\", fn _ ->\n        # Add a protocol dependency\n        File.write!(\"../foo/lib/foo.ex\", \"\"\"\n        defprotocol Foo do\n          def foo(arg)\n        end\n        defimpl Foo, for: List do\n          def foo(list), do: list\n        end\n        \"\"\")\n\n        Mix.Task.run(\"compile\")\n        assert File.regular?(\"_build/dev/lib/bar/consolidated/Elixir.Foo.beam\")\n        assert Mix.Tasks.Compile.Elixir.run([]) == {:noop, []}\n\n        # Mark protocol as outdated\n        File.touch!(\"_build/dev/lib/bar/consolidated/Elixir.Foo.beam\", {{2010, 1, 1}, {0, 0, 0}})\n        force_recompilation(\"../foo/lib/foo.ex\")\n        ensure_touched(\"../foo/lib/foo.ex\", \"_build/dev/lib/bar/.mix/compile.elixir\")\n        Mix.Task.clear()\n        Mix.Task.run(\"compile\")\n\n        # Check new timestamp\n        mtime = File.stat!(\"_build/dev/lib/bar/consolidated/Elixir.Foo.beam\").mtime\n        assert mtime > {{2010, 1, 1}, {0, 0, 0}}\n      end)\n    end)\n  end\n\n  test \"reconsolidates using umbrella parent information on shared _build\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      File.write!(\"apps/bar/lib/bar.ex\", \"\"\"\n      defprotocol Bar do\n        def bar(arg)\n      end\n      defimpl Bar, for: List do\n        def bar(list), do: list\n      end\n      \"\"\")\n\n      Mix.Project.in_project(:foo, \"apps/foo\", [build_path: \"../../_build\"], fn _ ->\n        Mix.Task.run(\"compile.protocols\")\n        refute Code.ensure_loaded?(Bar)\n      end)\n\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Task.run(\"compile\")\n        assert Protocol.consolidated?(Bar)\n      end)\n    end)\n  end\n\n  test \"reconsolidates using umbrella child information on shared _build\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      File.write!(\"apps/bar/lib/bar.ex\", \"\"\"\n      defprotocol Bar do\n        def foo(arg)\n      end\n      defimpl Bar, for: List do\n        def foo(list), do: list\n      end\n      \"\"\")\n\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        Mix.Task.run(\"compile.protocols\")\n      end)\n\n      # Emulate the dependency being removed\n      Mix.Project.in_project(:foo, \"apps/foo\", [build_path: \"../../_build\", deps: []], fn _ ->\n        File.rm_rf(\"../../_build/dev/lib/bar\")\n        Mix.Task.run(\"compile.protocols\")\n      end)\n    end)\n  end\n\n  test \"apps cannot refer to themselves as a dep\" do\n    in_fixture(\"umbrella_dep/deps/umbrella\", fn ->\n      Mix.Project.in_project(:umbrella, \".\", fn _ ->\n        File.write!(\"apps/bar/mix.exs\", \"\"\"\n        defmodule Bar.MixProject do\n          use Mix.Project\n\n          def project do\n            [app: :bar,\n             version: \"0.1.0\",\n             deps: [{:bar, in_umbrella: true}]]\n          end\n        end\n        \"\"\")\n\n        assert_raise Mix.Error, \"App bar lists itself as a dependency\", fn ->\n          Mix.Task.run(\"deps.get\", [\"--verbose\"]) == [:ok, :ok]\n        end\n      end)\n    end)\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix/utils_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"../test_helper.exs\", __DIR__)\n\ndefmodule Mix.Tasks.Cheers do\nend\n\ndefmodule Mix.UtilsTest do\n  use MixTest.Case\n  doctest Mix.Utils\n\n  setup do\n    Mix.ensure_application!(:inets)\n\n    # Store state before test\n    mix_home = System.get_env(\"MIX_HOME\")\n\n    # Clear all variables to get a reproducible test\n    System.delete_env(\"MIX_HOME\")\n    System.delete_env(\"MIX_XDG\")\n\n    # Reset Env Variables\n    on_exit(fn ->\n      System.put_env(\"MIX_HOME\", mix_home)\n      System.delete_env(\"MIX_XDG\")\n    end)\n  end\n\n  test \"command to module\" do\n    assert Mix.Utils.command_to_module(\"cheers\", Mix.Tasks) == {:module, Mix.Tasks.Cheers}\n    assert Mix.Utils.command_to_module(\"unknown\", Mix.Tasks) == {:error, :nofile}\n  end\n\n  test \"module name to command\" do\n    assert Mix.Utils.module_name_to_command(Mix.Tasks.Foo, 2) == \"foo\"\n    assert Mix.Utils.module_name_to_command(\"Mix.Tasks.Foo\", 2) == \"foo\"\n    assert Mix.Utils.module_name_to_command(\"Mix.Tasks.Foo.Bar\", 2) == \"foo.bar\"\n    assert Mix.Utils.module_name_to_command(\"Mix.Tasks.FooBar.Bing\", 2) == \"foo_bar.bing\"\n    assert Mix.Utils.module_name_to_command(\"Mix.Tasks.FooBar.BingBang\", 2) == \"foo_bar.bing_bang\"\n  end\n\n  test \"command to module name\" do\n    assert Mix.Utils.command_to_module_name(\"foo\") == \"Foo\"\n    assert Mix.Utils.command_to_module_name(\"foo.bar\") == \"Foo.Bar\"\n    assert Mix.Utils.command_to_module_name(\"foo_bar.baz\") == \"FooBar.Baz\"\n    assert Mix.Utils.command_to_module_name(\"foo_bar.baz_bing\") == \"FooBar.BazBing\"\n  end\n\n  test \"extract files\" do\n    files = Mix.Utils.extract_files([Path.join(fixture_path(), \"archive\")], \"*.ex\")\n    assert length(files) == 1\n    assert Path.basename(hd(files)) == \"local.sample.ex\"\n  end\n\n  test \"extract files with empty string returns empty list\" do\n    assert Mix.Utils.extract_files([\"\"], \".ex\") == []\n  end\n\n  test \"extract stale\" do\n    # 2038-01-01 00:00:00\n    time = 2_145_916_800\n    assert Mix.Utils.extract_stale([__ENV__.file], [time]) == []\n\n    # 2000-01-01 00:00:00\n    time = 946_684_800\n    assert Mix.Utils.extract_stale([__ENV__.file], [time]) == [__ENV__.file]\n\n    assert Mix.Utils.extract_stale([__ENV__.file], [__ENV__.file]) == []\n  end\n\n  test \"handles missing target files\" do\n    assert Mix.Utils.stale?([__ENV__.file], []) == true\n  end\n\n  test \"symlink or copy\" do\n    in_fixture(\"archive\", fn ->\n      File.mkdir_p!(\"_build/archive\")\n      result = Mix.Utils.symlink_or_copy(Path.expand(\"ebin\"), Path.expand(\"_build/archive/ebin\"))\n      assert_ebin_symlinked_or_copied(result)\n    end)\n  end\n\n  test \"symlink or copy removes previous directories\" do\n    in_fixture(\"archive\", fn ->\n      File.mkdir_p!(\"_build/archive/ebin\")\n      result = Mix.Utils.symlink_or_copy(Path.expand(\"ebin\"), Path.expand(\"_build/archive/ebin\"))\n      assert_ebin_symlinked_or_copied(result)\n    end)\n  end\n\n  @tag :unix\n  test \"symlink or copy erases wrong symlinks\" do\n    in_fixture(\"archive\", fn ->\n      File.mkdir_p!(\"_build/archive\")\n      build_ebin = Path.expand(\"_build/archive/ebin\")\n      Mix.Utils.symlink_or_copy(Path.expand(\"priv\"), build_ebin)\n\n      result = Mix.Utils.symlink_or_copy(Path.expand(\"ebin\"), build_ebin)\n      assert_ebin_symlinked_or_copied(result)\n    end)\n  end\n\n  test \"proxy_config reads from env and returns credentials\" do\n    assert Mix.Utils.proxy_config(\"http://example.com\") == []\n\n    System.put_env(\"http_proxy\", \"http://nopass@example.com\")\n    assert Mix.Utils.proxy_config(\"http://example.com\") == [proxy_auth: {~c\"nopass\", ~c\"\"}]\n\n    System.put_env(\"HTTP_PROXY\", \"http://my:proxy@example.com\")\n    assert Mix.Utils.proxy_config(\"http://example.com\") == [proxy_auth: {~c\"my\", ~c\"proxy\"}]\n\n    System.put_env(\"https_proxy\", \"https://another:proxy@example.com\")\n    assert Mix.Utils.proxy_config(\"https://example.com\") == [proxy_auth: {~c\"another\", ~c\"proxy\"}]\n\n    System.put_env(\"HTTPS_PROXY\", \"https://example.com\")\n    assert Mix.Utils.proxy_config(\"https://example.com\") == []\n  after\n    System.delete_env(\"http_proxy\")\n    System.delete_env(\"https_proxy\")\n  end\n\n  # 10.0.0.0 is a non-routable address\n  test \"read_path timeouts requests\" do\n    # If the request finishes for a reason, it will fail due to the checksum.\n    case Mix.Utils.read_path(\"http://10.0.0.0/\", timeout: 0) do\n      {:remote, \"request timed out after 0ms\"} -> :ok\n      {:checksum, \"fetching from URIs require a checksum to be given\"} -> :ok\n    end\n  end\n\n  describe \"mix_home/0\" do\n    test \"prefers MIX_HOME over MIX_XDG\" do\n      System.put_env(\"MIX_HOME\", \"mix_home\")\n      System.put_env(\"MIX_XDG\", \"true\")\n      assert \"mix_home\" = Mix.Utils.mix_home()\n    end\n\n    @tag :unix\n    test \"falls back to XDG_DATA_HOME/mix when MIX_XDG is set\" do\n      System.put_env(\"MIX_XDG\", \"1\")\n      assert Mix.Utils.mix_home() == :filename.basedir(:user_data, \"mix\", %{os: :linux})\n    end\n\n    test \"falls back to $HOME/.mix\" do\n      assert Path.expand(\"~/.mix\") == Mix.Utils.mix_home()\n    end\n  end\n\n  describe \"mix_config/0\" do\n    test \"prefers MIX_HOME over MIX_XDG\" do\n      System.put_env(\"MIX_HOME\", \"mix_home\")\n      System.put_env(\"MIX_XDG\", \"true\")\n      assert \"mix_home\" = Mix.Utils.mix_config()\n    end\n\n    @tag :unix\n    test \"falls back to XDG_CONFIG_HOME/mix when MIX_XDG is set\" do\n      System.put_env(\"MIX_XDG\", \"1\")\n      assert Mix.Utils.mix_config() == :filename.basedir(:user_config, \"mix\", %{os: :linux})\n    end\n\n    test \"falls back to $HOME/.mix\" do\n      assert Path.expand(\"~/.mix\") == Mix.Utils.mix_config()\n    end\n  end\n\n  describe \"mix_cache/0\" do\n    @tag :unix\n    test \"prefers XDG_CACHE_HOME/mix when MIX_XDG is set\" do\n      System.put_env(\"MIX_XDG\", \"1\")\n      assert Mix.Utils.mix_cache() == :filename.basedir(:user_cache, \"mix\", %{os: :linux})\n    end\n\n    test \"falls back to user cache dir\" do\n      assert Mix.Utils.mix_cache() == :filename.basedir(:user_cache, \"mix\")\n    end\n  end\n\n  describe \"write_according_to_opts/3\" do\n    test \"verify that file writes with backups work as expected\" do\n      test_out = \"test.out\"\n      test_out_bak = \"test.out.bak\"\n      hello_world = \"Hello World!\"\n      new_hello_world = \"New Hello World!\"\n      default_out = \"default.out\"\n\n      # ignore any error from this call.\n      in_tmp(\"write to default file\", fn ->\n        # no optional override - write to the specified default file\n        assert Mix.Utils.write_according_to_opts!(test_out, [hello_world], []) == test_out\n        assert File.read!(test_out) == hello_world\n\n        # no optional override - write to the specified default file again, with old file backed up\n        assert Mix.Utils.write_according_to_opts!(test_out, [new_hello_world], []) == test_out\n        assert File.read!(test_out) == new_hello_world\n        assert File.read!(test_out_bak) == hello_world\n      end)\n\n      in_tmp(\"write to optional file override\", fn ->\n        # with optional override - write to the specified default file\n        assert Mix.Utils.write_according_to_opts!(default_out, [hello_world], output: test_out) ==\n                 test_out\n\n        assert File.read!(test_out) == hello_world\n\n        # with optional override - write to the specified default file again, with old file backed up\n        assert Mix.Utils.write_according_to_opts!(default_out, [new_hello_world],\n                 output: test_out\n               ) ==\n                 test_out\n\n        assert File.read!(test_out) == new_hello_world\n        assert File.read!(test_out_bak) == hello_world\n      end)\n    end\n\n    test \"verify that writing to STDOUT works as expected\" do\n      output =\n        ExUnit.CaptureIO.capture_io(fn ->\n          Mix.Utils.write_according_to_opts!(\"the_file.txt\", [\"some text\"], output: \"-\")\n        end)\n\n      assert output == \"some text\"\n\n      refute File.exists?(\"the_file.txt\")\n    end\n  end\n\n  describe \"write_dot_graph!/4\" do\n    test \"preserves newlines and other control characters\" do\n      in_tmp(\"dot_newlines\", fn ->\n        callback = fn node -> {{node, nil}, []} end\n\n        Mix.Utils.write_dot_graph!(\"graph.dot\", \"graph\", [\"foo \\nbar\\r\\nbaz\"], callback, [])\n\n        assert File.read!(\"graph.dot\") == \"\"\"\n               digraph \"graph\" {\n                 \"foo \n               bar\\r\n               baz\"\n               }\n               \"\"\"\n      end)\n    end\n\n    test \"quote and backslash combinations\" do\n      in_tmp(\"dot_complex\", fn ->\n        callback = fn node -> {{node, nil}, []} end\n\n        test_cases = [\n          # \"fo\"o\" -> \"fo\\\"o\"\n          {\"fo\\\"o\", \"fo\\\\\\\"o\"},\n          # \"fo\\\"o\" -> \"fo\\\\\\\"o\"\n          {\"fo\\\\\\\"o\", \"fo\\\\\\\\\\\"o\"},\n          # \"fo\\o\" -> \"fo\\o\"\n          {\"fo\\\\o\", \"fo\\\\o\"},\n          # \"fo\\\\o\" -> \"fo\\\\o\"\n          {\"fo\\\\\\\\o\", \"fo\\\\\\\\o\"},\n          # \"fo\\\\\\o\" -> \"fo\\\\\\o\"\n          {\"fo\\\\\\\\\\\\o\", \"fo\\\\\\\\\\\\o\"}\n        ]\n\n        Enum.each(test_cases, fn {input, expected} ->\n          Mix.Utils.write_dot_graph!(\"graph.dot\", \"graph\", [input], callback, [])\n          content = File.read!(\"graph.dot\")\n          assert content == \"digraph \\\"graph\\\" {\\n  \\\"#{expected}\\\"\\n}\\n\"\n        end)\n      end)\n    end\n\n    test \"escapes backslash at end of string\" do\n      in_tmp(\"dot_end_backslash\", fn ->\n        callback = fn node -> {{node, nil}, []} end\n\n        test_cases = [\n          # \"fo\\\" -> \"fo\\\\\" (add backslash)\n          {\"fo\\\\\", \"fo\\\\\\\\\"},\n          # \"fo\\\\\" -> \"fo\\\\\" (already valid)\n          {\"fo\\\\\\\\\", \"fo\\\\\\\\\"},\n          # \"fo\\\\\\\" -> \"fo\\\\\\\\\" (add backslash)\n          {\"fo\\\\\\\\\\\\\", \"fo\\\\\\\\\\\\\\\\\"}\n        ]\n\n        Enum.each(test_cases, fn {input, expected} ->\n          Mix.Utils.write_dot_graph!(\"graph.dot\", \"graph\", [input], callback, [])\n          content = File.read!(\"graph.dot\")\n          assert content == \"digraph \\\"graph\\\" {\\n  \\\"#{expected}\\\"\\n}\\n\"\n        end)\n      end)\n    end\n\n    test \"handles empty strings\" do\n      in_tmp(\"dot_empty\", fn ->\n        callback = fn node -> {{node, nil}, []} end\n\n        Mix.Utils.write_dot_graph!(\"graph.dot\", \"graph\", [\"\"], callback, [])\n\n        assert File.read!(\"graph.dot\") == \"\"\"\n               digraph \"graph\" {\n                 \"\"\n               }\n               \"\"\"\n      end)\n    end\n\n    test \"handles edge labels with escaping\" do\n      in_tmp(\"dot_edge_labels\", fn ->\n        callback = fn node -> {{node, \"edge \\\"label\\\"\"}, []} end\n\n        Mix.Utils.write_dot_graph!(\"graph.dot\", \"graph\", [\"node\"], callback, [])\n\n        assert File.read!(\"graph.dot\") == \"\"\"\n               digraph \"graph\" {\n                 \"node\" [label=\"edge \\\\\"label\\\\\"\"]\n               }\n               \"\"\"\n      end)\n    end\n  end\n\n  defp assert_ebin_symlinked_or_copied(result) do\n    case result do\n      {:ok, paths} ->\n        assert Path.expand(\"_build/archive/ebin\") in paths\n\n      :ok ->\n        expected_link =\n          case :os.type() do\n            # relative symlink on Windows are broken, see symlink_or_copy/2\n            {:win32, _} ->\n              \"ebin\" |> Path.expand() |> String.to_charlist()\n\n            _ ->\n              ~c\"../../ebin\"\n          end\n\n        {:ok, actual_link} = :file.read_link(\"_build/archive/ebin\")\n        assert actual_link == expected_link\n\n      _ ->\n        msg =\n          \"expected symlink_or_copy to return :ok or {:ok, list_of_paths}, got: #{inspect(result)}\"\n\n        flunk(msg)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/mix_test.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nCode.require_file(\"test_helper.exs\", __DIR__)\n\ndefmodule MixTest do\n  use MixTest.Case\n\n  test \"shell\" do\n    assert Mix.shell() == Mix.Shell.Process\n  end\n\n  test \"env\" do\n    assert Mix.env() == :dev\n    Mix.env(:prod)\n    assert Mix.env() == :prod\n  end\n\n  test \"debug\" do\n    refute Mix.debug?()\n    Mix.debug(true)\n    assert Mix.debug?()\n    Mix.debug(false)\n  end\n\n  describe \"install\" do\n    @describetag :tmp_dir\n\n    setup %{tmp_dir: tmp_dir} do\n      System.put_env(\"MIX_INSTALL_DIR\", Path.join(tmp_dir, \"installs\"))\n    end\n\n    setup :test_project\n\n    test \"default options\", %{tmp_dir: tmp_dir} do\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n\n      assert File.dir?(Path.join(tmp_dir, \"installs\"))\n\n      assert Protocol.consolidated?(InstallTest.Protocol)\n\n      assert_received {:mix_shell, :info, [\"==> install_test\"]}\n      assert_received {:mix_shell, :info, [\"Compiling 2 files (.ex)\"]}\n      assert_received {:mix_shell, :info, [\"Generated install_test app\"]}\n      refute_received _\n\n      assert Application.app_dir(:crypto) =~ \"crypto\"\n      assert List.keyfind(Application.started_applications(), :install_test, 0)\n      assert apply(InstallTest, :hello, []) == :world\n    end\n\n    test \"with start_applications: false\", %{tmp_dir: tmp_dir} do\n      Mix.install(\n        [\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ],\n        start_applications: false\n      )\n\n      assert List.keyfind(Application.loaded_applications(), :install_test, 0)\n      refute List.keyfind(Application.started_applications(), :install_test, 0)\n    end\n\n    test \"with runtime: false\", %{tmp_dir: tmp_dir} do\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\"), runtime: false}\n      ])\n\n      assert File.dir?(Path.join(tmp_dir, \"installs\"))\n      assert_received {:mix_shell, :info, [\"==> install_test\"]}\n      assert_received {:mix_shell, :info, [\"Compiling 2 files (.ex)\"]}\n      assert_received {:mix_shell, :info, [\"Generated install_test app\"]}\n      refute_received _\n\n      refute List.keyfind(Application.started_applications(), :install_test, 0)\n    end\n\n    test \"works with same deps twice\", %{tmp_dir: tmp_dir} do\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n    end\n\n    test \"errors on Elixir version mismatch\", %{tmp_dir: tmp_dir} do\n      assert_raise Mix.Error, ~r\"Mix.install/2 declared it supports only Elixir ~> 2.0\", fn ->\n        Mix.install(\n          [\n            {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n          ],\n          elixir: \"~> 2.0\"\n        )\n      end\n    end\n\n    test \"errors with same deps and force\", %{tmp_dir: tmp_dir} do\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n\n      assert_raise Mix.Error, ~r\"Mix.install/2 can only be called\", fn ->\n        Mix.install(\n          [\n            {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n          ],\n          force: true\n        )\n      end\n    end\n\n    test \"errors with different deps in the same VM\", %{tmp_dir: tmp_dir} do\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n\n      assert_raise Mix.Error, ~r\"Mix.install/2 can only be called\", fn ->\n        Mix.install([\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")},\n          :foo\n        ])\n      end\n    end\n\n    test \"install after errors\", %{tmp_dir: tmp_dir} do\n      assert_raise Mix.Error, \"Can't continue due to errors on dependencies\", fn ->\n        Mix.install([\n          {:bad, path: Path.join(tmp_dir, \"bad\")}\n        ])\n      end\n\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n\n      assert apply(InstallTest, :hello, []) == :world\n    end\n\n    test \"consolidate_protocols: false\", %{tmp_dir: tmp_dir} do\n      Mix.install(\n        [\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ],\n        consolidate_protocols: false\n      )\n\n      refute Protocol.consolidated?(InstallTest.Protocol)\n    end\n\n    test \":config and :system_env\", %{tmp_dir: tmp_dir} do\n      Mix.install(\n        [\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ],\n        config: [unknown_app: [foo: :bar]],\n        system_env: %{\"MIX_INSTALL_FOO\" => \"BAR\", MIX_INSTALL_BAZ: \"BAT\"}\n      )\n\n      assert Application.fetch_env!(:unknown_app, :foo) == :bar\n      assert System.fetch_env!(\"MIX_INSTALL_FOO\") == \"BAR\"\n      assert System.fetch_env!(\"MIX_INSTALL_BAZ\") == \"BAT\"\n    after\n      System.delete_env(\"MIX_INSTALL_FOO\")\n      System.delete_env(\"MIX_INSTALL_BAZ\")\n      Application.delete_env(:unknown_app, :foo, persistent: true)\n    end\n\n    test \":config_path with application name\", %{tmp_dir: tmp_dir} do\n      config_path = Path.join(tmp_dir, \"install_test/config/config.exs\")\n      config_path |> Path.dirname() |> File.mkdir_p!()\n\n      File.write!(config_path, \"\"\"\n      import Config\n      config :myapp, :foo, 1\n      \"\"\")\n\n      Mix.install(\n        [\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ],\n        config_path: :install_test\n      )\n\n      assert Application.fetch_env!(:myapp, :foo) == 1\n    after\n      Application.delete_env(:myapp, :foo)\n    end\n\n    test \":config_path\", %{tmp_dir: tmp_dir} do\n      config_path = Path.join(tmp_dir, \"config.exs\")\n\n      File.write!(config_path, \"\"\"\n      import Config\n      config :myapp, :foo, 1\n      \"\"\")\n\n      Mix.install(\n        [\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ],\n        config_path: config_path\n      )\n\n      assert Application.fetch_env!(:myapp, :foo) == 1\n    after\n      Application.delete_env(:myapp, :foo)\n    end\n\n    test \":config_path and runtime config\", %{tmp_dir: tmp_dir} do\n      config_path = Path.join(tmp_dir, \"config.exs\")\n\n      File.write!(config_path, \"\"\"\n      import Config\n      config :myapp, :foo, 1\n      \"\"\")\n\n      File.write!(Path.join(tmp_dir, \"runtime.exs\"), \"\"\"\n      import Config\n      config :myapp, :bar, 2\n      \"\"\")\n\n      Mix.install(\n        [\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ],\n        config_path: config_path\n      )\n\n      assert Application.fetch_env!(:myapp, :foo) == 1\n      assert Application.fetch_env!(:myapp, :bar) == 2\n    after\n      Application.delete_env(:myapp, :foo)\n      Application.delete_env(:myapp, :bar)\n    end\n\n    test \":config_path that does not exist\" do\n      assert_raise File.Error, ~r/bad.exs\": no such file or directory/, fn ->\n        Mix.install([], config_path: \"bad.exs\")\n      end\n    end\n\n    defmodule GitApp do\n      def project do\n        [\n          app: :git_app,\n          version: \"0.1.0\",\n          deps: [\n            {:git_repo, \"0.1.0\", [git: fixture_path(\"git_repo\")]}\n          ]\n        ]\n      end\n    end\n\n    test \":lockfile with first build\", %{tmp_dir: tmp_dir} do\n      Mix.Project.push(GitApp)\n      [_latest_rev, rev | _] = get_git_repo_revs(\"git_repo\")\n      lockfile = Path.join(tmp_dir, \"lock\")\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), rev, []}}, file: lockfile)\n      Mix.ProjectStack.pop()\n\n      Mix.install(\n        [\n          {:git_repo, git: fixture_path(\"git_repo\")}\n        ],\n        lockfile: lockfile\n      )\n\n      assert_received {:mix_shell, :info, [\"* Getting git_repo \" <> _]}\n\n      install_project_dir = Mix.install_project_dir()\n      assert File.read!(Path.join(install_project_dir, \"mix.lock\")) =~ rev\n    end\n\n    test \":lockfile merging\", %{tmp_dir: tmp_dir} do\n      [rev1, rev2 | _] = get_git_repo_revs(\"git_repo\")\n\n      Mix.install([\n        {:git_repo, git: fixture_path(\"git_repo\")}\n      ])\n\n      assert_received {:mix_shell, :info, [\"* Getting git_repo \" <> _]}\n\n      install_project_dir = Mix.install_project_dir()\n      assert File.read!(Path.join(install_project_dir, \"mix.lock\")) =~ rev1\n\n      Mix.Project.push(GitApp)\n      lockfile = Path.join(tmp_dir, \"lock\")\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), rev2, []}}, file: lockfile)\n      Mix.ProjectStack.pop()\n\n      Mix.install(\n        [\n          {:git_repo, git: fixture_path(\"git_repo\")}\n        ],\n        lockfile: lockfile\n      )\n\n      assert File.read!(Path.join(install_project_dir, \"mix.lock\")) =~ rev1\n    end\n\n    test \":lockfile with application name\", %{tmp_dir: tmp_dir} do\n      lockfile = Path.join(tmp_dir, \"install_test/mix.lock\")\n      lockfile |> Path.dirname() |> File.mkdir_p!()\n      Mix.Project.push(GitApp)\n      [_latest_rev, rev | _] = get_git_repo_revs(\"git_repo\")\n      Mix.Dep.Lock.write(%{git_repo: {:git, fixture_path(\"git_repo\"), rev, []}}, file: lockfile)\n      Mix.ProjectStack.pop()\n\n      Mix.install(\n        [\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")},\n          {:git_repo, git: fixture_path(\"git_repo\")}\n        ],\n        lockfile: :install_test\n      )\n\n      assert_received {:mix_shell, :info, [\"* Getting git_repo \" <> _]}\n      install_project_dir = Mix.install_project_dir()\n      assert File.read!(Path.join(install_project_dir, \"mix.lock\")) =~ rev\n    end\n\n    test \":lockfile that does not exist\" do\n      assert_raise File.Error, ~r/bad\": no such file or directory/, fn ->\n        Mix.install([], lockfile: \"bad\")\n      end\n    end\n\n    test \"using restore dir\", %{tmp_dir: tmp_dir} do\n      with_cleanup(fn ->\n        Mix.install([\n          {:git_repo, git: fixture_path(\"git_repo\")}\n        ])\n\n        assert_received {:mix_shell, :info, [\"* Getting git_repo \" <> _]}\n        assert_received {:mix_shell, :info, [\"==> git_repo\"]}\n        assert_received {:mix_shell, :info, [\"Compiling 1 file (.ex)\"]}\n        assert_received {:mix_shell, :info, [\"Generated git_repo app\"]}\n        refute_received _\n\n        install_project_dir = Mix.install_project_dir()\n        build_lib_path = Path.join([install_project_dir, \"_build\", \"dev\", \"lib\"])\n        deps_path = Path.join([install_project_dir, \"deps\"])\n\n        assert File.ls!(build_lib_path) |> Enum.sort() == [\"git_repo\", \"mix_install\"]\n        assert File.ls!(deps_path) == [\"git_repo\"]\n\n        System.put_env(\"MIX_INSTALL_RESTORE_PROJECT_DIR\", install_project_dir)\n      end)\n\n      # Adding a dependency\n\n      with_cleanup(fn ->\n        Mix.install([\n          {:git_repo, git: fixture_path(\"git_repo\")},\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ])\n\n        assert_received {:mix_shell, :info, [\"==> install_test\"]}\n        assert_received {:mix_shell, :info, [\"Compiling 2 files (.ex)\"]}\n        assert_received {:mix_shell, :info, [\"Generated install_test app\"]}\n        refute_received _\n\n        install_project_dir = Mix.install_project_dir()\n        build_lib_path = Path.join([install_project_dir, \"_build\", \"dev\", \"lib\"])\n        deps_path = Path.join([install_project_dir, \"deps\"])\n\n        assert File.ls!(build_lib_path) |> Enum.sort() ==\n                 [\"git_repo\", \"install_test\", \"mix_install\"]\n\n        assert File.ls!(deps_path) == [\"git_repo\"]\n\n        System.put_env(\"MIX_INSTALL_RESTORE_PROJECT_DIR\", install_project_dir)\n      end)\n\n      # Removing a dependency\n\n      with_cleanup(fn ->\n        Mix.install([\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ])\n\n        refute_received _\n\n        install_project_dir = Mix.install_project_dir()\n        build_lib_path = Path.join([install_project_dir, \"_build\", \"dev\", \"lib\"])\n        deps_path = Path.join([install_project_dir, \"deps\"])\n\n        assert File.ls!(build_lib_path) |> Enum.sort() == [\"install_test\", \"mix_install\"]\n        assert File.ls!(deps_path) == []\n      end)\n    after\n      System.delete_env(\"MIX_INSTALL_RESTORE_PROJECT_DIR\")\n    end\n\n    test \"using restore dir removes consolidated files when not needed\", %{tmp_dir: tmp_dir} do\n      with_cleanup(fn ->\n        Mix.install([\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ])\n\n        install_project_dir = Mix.install_project_dir()\n        build_lib_path = Path.join([install_project_dir, \"_build\", \"dev\", \"lib\"])\n        build_project_path = Path.join(build_lib_path, \"mix_install\")\n\n        assert File.ls!(build_project_path) |> Enum.sort() == [\".mix\", \"consolidated\", \"ebin\"]\n\n        System.put_env(\"MIX_INSTALL_RESTORE_PROJECT_DIR\", install_project_dir)\n      end)\n\n      with_cleanup(fn ->\n        Mix.install(\n          [\n            {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n          ],\n          consolidate_protocols: false\n        )\n\n        install_project_dir = Mix.install_project_dir()\n        build_lib_path = Path.join([install_project_dir, \"_build\", \"dev\", \"lib\"])\n        build_project_path = Path.join(build_lib_path, \"mix_install\")\n\n        assert File.ls!(build_project_path) |> Enum.sort() == [\".mix\", \"ebin\"]\n      end)\n    after\n      System.delete_env(\"MIX_INSTALL_RESTORE_PROJECT_DIR\")\n    end\n\n    test \"custom compilers\", %{tmp_dir: tmp_dir} do\n      File.mkdir_p!(\"#{tmp_dir}/install_test/lib/mix/tasks/compile/\")\n\n      File.write!(\"#{tmp_dir}/install_test/lib/mix/tasks/compile/install_test.ex\", \"\"\"\n      defmodule Mix.Tasks.Compile.InstallTest do\n        use Mix.Task.Compiler\n\n        def run(_args) do\n          Mix.shell().info(\"Hello from custom compiler!\")\n\n          :noop\n        end\n      end\n      \"\"\")\n\n      Mix.install(\n        [\n          {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n        ],\n        compilers: [:elixir, :install_test]\n      )\n\n      assert File.dir?(Path.join(tmp_dir, \"installs\"))\n\n      assert Protocol.consolidated?(InstallTest.Protocol)\n\n      assert_received {:mix_shell, :info, [\"==> install_test\"]}\n      assert_received {:mix_shell, :info, [\"Compiling 3 files (.ex)\"]}\n      assert_received {:mix_shell, :info, [\"Generated install_test app\"]}\n      assert_received {:mix_shell, :info, [\"==> mix_install\"]}\n      assert_received {:mix_shell, :info, [\"Hello from custom compiler!\"]}\n      refute_received _\n\n      assert List.keyfind(Application.started_applications(), :install_test, 0)\n      assert apply(InstallTest, :hello, []) == :world\n    end\n\n    test \"installed?\", %{tmp_dir: tmp_dir} do\n      refute Mix.installed?()\n\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n\n      assert Mix.installed?()\n    end\n\n    test \"in_install_project\", %{tmp_dir: tmp_dir} do\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n\n      Mix.in_install_project(fn ->\n        config = Mix.Project.config()\n        assert [{:install_test, [path: _]}] = config[:deps]\n      end)\n    end\n\n    test \"in_install_project recompile\", %{tmp_dir: tmp_dir} do\n      Mix.install([\n        {:install_test, path: Path.join(tmp_dir, \"install_test\")}\n      ])\n\n      File.write!(\"#{tmp_dir}/install_test/lib/install_test.ex\", \"\"\"\n      defmodule InstallTest do\n        def hello do\n          :universe\n        end\n      end\n      \"\"\")\n\n      Mix.in_install_project(fn ->\n        Mix.Task.run(\"compile\")\n        assert apply(InstallTest, :hello, []) == :universe\n      end)\n    end\n\n    defp test_project(%{tmp_dir: tmp_dir}) do\n      path = :code.get_path()\n\n      on_exit(fn ->\n        :code.set_path(path)\n        cleanup_deps()\n      end)\n\n      Mix.State.put(:installed, nil)\n\n      File.mkdir_p!(\"#{tmp_dir}/install_test/lib\")\n\n      File.write!(\"#{tmp_dir}/install_test/mix.exs\", \"\"\"\n      defmodule InstallTest.MixProject do\n        use Mix.Project\n\n        def project do\n          [\n            app: :install_test,\n            version: \"0.1.0\"\n          ]\n        end\n      end\n      \"\"\")\n\n      File.write!(\"#{tmp_dir}/install_test/lib/install_test.ex\", \"\"\"\n      defmodule InstallTest do\n        def hello do\n          :world\n        end\n      end\n      \"\"\")\n\n      File.write!(\"#{tmp_dir}/install_test/lib/install_test_protocol.ex\", \"\"\"\n      defprotocol InstallTest.Protocol do\n        def foo(x)\n      end\n      \"\"\")\n\n      [tmp_dir: tmp_dir]\n    end\n\n    defp with_cleanup(fun) do\n      path = :code.get_path()\n\n      try do\n        fun.()\n      after\n        :code.set_path(path)\n        cleanup_deps()\n\n        Mix.State.clear_cache()\n        Mix.State.put(:installed, nil)\n      end\n    end\n\n    defp cleanup_deps() do\n      purge([\n        GitRepo,\n        GitRepo.MixProject,\n        InstallTest,\n        InstallTest.MixProject,\n        InstallTest.Protocol\n      ])\n\n      ExUnit.CaptureLog.capture_log(fn ->\n        Application.stop(:git_repo)\n        Application.unload(:git_repo)\n\n        Application.stop(:install_test)\n        Application.unload(:install_test)\n      end)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/mix/test/test_helper.exs",
    "content": "# SPDX-License-Identifier: Apache-2.0\n# SPDX-FileCopyrightText: 2021 The Elixir Team\n# SPDX-FileCopyrightText: 2012 Plataformatec\n\nhome = Path.expand(\"../tmp/.home\", __DIR__)\nFile.mkdir_p!(home)\nSystem.put_env(\"HOME\", home)\n\nmix = Path.expand(\"../tmp/.mix\", __DIR__)\nFile.mkdir_p!(mix)\nSystem.put_env(\"MIX_HOME\", mix)\n\n# Load protocols to make sure they are not unloaded during tests\n[Collectable, Enumerable, Inspect, String.Chars, List.Chars]\n|> Enum.each(& &1.__protocol__(:module))\n\n## Setup Mix\n\nMix.start()\nMix.shell(Mix.Shell.Process)\nApplication.put_env(:mix, :colors, enabled: false)\nApplication.put_env(:logger, :default_handler, false)\n\n## Setup ExUnit\n\nos_exclude = if match?({:win32, _}, :os.type()), do: [unix: true], else: [windows: true]\nepmd_exclude = if match?({:win32, _}, :os.type()), do: [epmd: true], else: []\n\ngit_exclude =\n  Mix.SCM.Git.unsupported_options()\n  |> Enum.map(fn\n    :sparse -> {:git_sparse, true}\n    :depth -> {:git_depth, true}\n  end)\n\n{line_exclude, line_include} =\n  if line = System.get_env(\"LINE\"), do: {[:test], [line: line]}, else: {[], []}\n\ncover_exclude =\n  if :deterministic in :compile.env_compiler_options() do\n    [:cover]\n  else\n    []\n  end\n\n# OTP 28.1+\nre_import_exclude =\n  if Code.ensure_loaded?(:re) and function_exported?(:re, :import, 1) do\n    []\n  else\n    [:re_import]\n  end\n\nCode.require_file(\"../../elixir/scripts/cover_record.exs\", __DIR__)\nCoverageRecorder.maybe_record(\"mix\")\n\nmaybe_seed_opt = if seed = System.get_env(\"SEED\"), do: [seed: String.to_integer(seed)], else: []\n\nex_unit_opts =\n  [\n    trace: !!System.get_env(\"TRACE\"),\n    exclude:\n      epmd_exclude ++\n        os_exclude ++ git_exclude ++ line_exclude ++ cover_exclude ++ re_import_exclude,\n    include: line_include,\n    assert_receive_timeout: String.to_integer(System.get_env(\"ELIXIR_ASSERT_TIMEOUT\", \"300\"))\n  ] ++ maybe_seed_opt\n\nExUnit.start(ex_unit_opts)\n\ndefmodule MixTest.Case do\n  use ExUnit.CaseTemplate\n\n  defmodule Sample do\n    def project do\n      [app: :sample, version: \"0.1.0\", aliases: [sample: \"compile\"]]\n    end\n\n    def application do\n      Process.get({__MODULE__, :application}) || []\n    end\n  end\n\n  using do\n    quote do\n      import MixTest.Case\n    end\n  end\n\n  @apps Enum.map(Application.loaded_applications(), &elem(&1, 0))\n\n  setup do\n    on_exit(fn ->\n      Application.start(:logger)\n      Mix.env(:dev)\n      Mix.target(:host)\n      Mix.Task.clear()\n      Mix.Shell.Process.flush()\n      Mix.State.clear_cache()\n      Mix.ProjectStack.clear_stack()\n      delete_tmp_paths()\n\n      for {app, _, _} <- Application.loaded_applications(), app not in @apps do\n        Application.stop(app)\n        Application.unload(app)\n      end\n\n      :ok\n    end)\n\n    :ok\n  end\n\n  def fixture_path do\n    Path.expand(\"fixtures\", __DIR__)\n  end\n\n  def fixture_path(extension) do\n    Path.join(fixture_path(), remove_colons(extension))\n  end\n\n  def tmp_path do\n    Path.expand(\"../tmp\", __DIR__)\n  end\n\n  def tmp_path(extension) do\n    Path.join(tmp_path(), remove_colons(extension))\n  end\n\n  defp remove_colons(term) do\n    term\n    |> to_string()\n    |> String.replace(\":\", \"\")\n  end\n\n  def purge(modules) do\n    Enum.each(modules, fn m ->\n      :code.purge(m)\n      :code.delete(m)\n    end)\n  end\n\n  def in_tmp(which, function) do\n    path = tmp_path(which)\n    File.rm_rf!(path)\n    File.mkdir_p!(path)\n    File.cd!(path, function)\n  end\n\n  defmacro in_fixture(which, block) do\n    module = inspect(__CALLER__.module)\n\n    function =\n      case __CALLER__.function do\n        {name, _arity} -> Atom.to_string(name)\n        nil -> raise \"expected in_fixture/2 to be called from a function\"\n      end\n\n    tmp = Path.join(module, function)\n\n    quote do\n      unquote(__MODULE__).in_fixture(unquote(which), unquote(tmp), unquote(block))\n    end\n  end\n\n  def in_fixture(which, tmp, function) do\n    src = fixture_path(which)\n    dest = tmp_path(String.replace(tmp, \":\", \"_\"))\n    flag = String.to_charlist(tmp_path())\n\n    File.rm_rf!(dest)\n    File.mkdir_p!(dest)\n    File.cp_r!(src, dest)\n\n    get_path = :code.get_path()\n    previous = :code.all_loaded()\n\n    try do\n      File.cd!(dest, function)\n    after\n      :code.set_path(get_path)\n\n      for {mod, file} <- :code.all_loaded() -- previous,\n          file == [] or (is_list(file) and List.starts_with?(file, flag)) do\n        purge([mod])\n      end\n    end\n  end\n\n  def ensure_touched(file) do\n    ensure_touched(file, file)\n  end\n\n  def ensure_touched(file, current) when is_binary(current) do\n    case File.stat(current) do\n      {:ok, %{mtime: mtime}} -> ensure_touched(file, mtime)\n      {:error, _} -> File.touch!(file)\n    end\n  end\n\n  def ensure_touched(file, current) when is_tuple(current) do\n    File.touch!(file)\n    mtime = File.stat!(file).mtime\n\n    if mtime <= current do\n      seconds =\n        :calendar.datetime_to_gregorian_seconds(current) -\n          :calendar.datetime_to_gregorian_seconds(mtime)\n\n      Process.sleep(seconds * 1000)\n      ensure_touched(file, current)\n    end\n  end\n\n  if match?({:win32, _}, :os.type()) do\n    def windows?, do: true\n    def os_newline, do: \"\\r\\n\"\n  else\n    def windows?, do: false\n    def os_newline, do: \"\\n\"\n  end\n\n  def mix(args, envs \\\\ []) when is_list(args) do\n    mix_code(args, envs) |> elem(0)\n  end\n\n  def mix_code(args, envs \\\\ []) when is_list(args) do\n    args = [\"-r\", mix_executable(), \"--\" | args]\n    System.cmd(elixir_executable(), args, stderr_to_stdout: true, env: envs)\n  end\n\n  def mix_port(args, envs \\\\ []) when is_list(args) do\n    Port.open({:spawn_executable, elixir_executable()}, [\n      {:args, [\"-r\", mix_executable(), \"--\" | args]},\n      {:env, envs},\n      :binary,\n      :use_stdio,\n      :stderr_to_stdout\n    ])\n  end\n\n  def force_recompilation(file) do\n    File.write!(file, File.read!(file) <> \"\\n\")\n  end\n\n  def mix_executable do\n    Path.expand(\"../../../bin/mix\", __DIR__)\n  end\n\n  def elixir_executable do\n    Path.expand(\"../../../bin/elixir\", __DIR__)\n  end\n\n  defp delete_tmp_paths do\n    tmp = tmp_path() |> String.to_charlist()\n    for path <- :code.get_path(), :string.str(path, tmp) != 0, do: :code.del_path(path)\n  end\n\n  def get_git_repo_revs(repo) do\n    File.cd!(fixture_path(repo), fn ->\n      Regex.split(~r/\\r?\\n/, System.cmd(\"git\", [\"log\", \"--format=%H\"]) |> elem(0), trim: true)\n    end)\n  end\nend\n\n# Prepare and clear environment variables\nSystem.put_env(\n  \"MIX_OS_DEPS_COMPILE_PARTITION_ELIXIR_EXECUTABLE\",\n  MixTest.Case.elixir_executable()\n)\n\n# Clear environment variables that may affect tests\nEnum.each(\n  ~w(http_proxy https_proxy HTTP_PROXY HTTPS_PROXY) ++\n    ~w(MIX_ENV MIX_OS_DEPS_COMPILE_PARTITION_COUNT MIX_TARGET) ++\n    ~w(XDG_DATA_HOME XDG_CONFIG_HOME),\n  &System.delete_env/1\n)\n\n## Set up Rebar fixtures\n\nrebar3_source = System.get_env(\"REBAR3\") || Path.expand(\"fixtures/rebar3\", __DIR__)\n[major, minor | _] = String.split(System.version(), \".\")\nversion_dir = \"#{major}-#{minor}-otp-#{System.otp_release()}\"\nrebar3_target = Path.join([mix, \"elixir\", version_dir, \"rebar3\"])\nFile.mkdir_p!(Path.dirname(rebar3_target))\nFile.cp!(rebar3_source, rebar3_target)\n\nfixtures = ~w(rebar_dep rebar_override)\n\nEnum.each(fixtures, fn fixture ->\n  source = MixTest.Case.fixture_path(fixture)\n  dest = MixTest.Case.tmp_path(fixture)\n  File.mkdir_p!(dest)\n  File.cp_r!(source, dest)\nend)\n\n## Set up Git fixtures\n\nSystem.cmd(\"git\", ~w[config --global user.email mix@example.com])\nSystem.cmd(\"git\", ~w[config --global user.name mix-repo])\nSystem.cmd(\"git\", ~w[config --global init.defaultBranch not-main])\n\n### Git repo\ntarget = Path.expand(\"fixtures/git_repo\", __DIR__)\n\nif not File.dir?(target) do\n  File.mkdir_p!(Path.join(target, \"lib\"))\n\n  File.write!(Path.join(target, \"mix.exs\"), \"\"\"\n  ## Auto-generated fixture\n  raise \"I was not supposed to be loaded\"\n  \"\"\")\n\n  File.cd!(target, fn ->\n    System.cmd(\"git\", ~w[init])\n    System.cmd(\"git\", ~w[add .])\n    System.cmd(\"git\", ~w[commit -m \"bad\"])\n    System.cmd(\"git\", ~w[checkout -q -b main])\n    System.cmd(\"git\", ~w[symbolic-ref HEAD refs/heads/main])\n  end)\n\n  File.write!(Path.join(target, \"mix.exs\"), \"\"\"\n  ## Auto-generated fixture\n  defmodule GitRepo.MixProject do\n    use Mix.Project\n\n    def project do\n      [\n        app: :git_repo,\n        version: \"0.1.0\"\n      ]\n    end\n  end\n  \"\"\")\n\n  File.cd!(target, fn ->\n    System.cmd(\"git\", ~w[add .])\n    System.cmd(\"git\", ~w[commit -m \"ok\"])\n    System.cmd(\"git\", ~w[tag without_module])\n  end)\n\n  File.write!(Path.join(target, \"lib/git_repo.ex\"), \"\"\"\n  ## Auto-generated fixture\n  defmodule GitRepo do\n    def hello do\n      \"World\"\n    end\n  end\n  \"\"\")\n\n  ## Sparse\n  subdir = Path.join(target, \"sparse_dir\")\n  File.mkdir_p!(Path.join(subdir, \"lib\"))\n\n  File.write!(Path.join(subdir, \"mix.exs\"), \"\"\"\n  ## Auto-generated fixture\n  defmodule GitSparseRepo.MixProject do\n    use Mix.Project\n\n    def project do\n      [\n        app: :git_sparse_repo,\n        version: \"0.1.0\"\n      ]\n    end\n  end\n  \"\"\")\n\n  File.write!(Path.join(subdir, \"lib/git_sparse_repo.ex\"), \"\"\"\n  ## Auto-generated fixture\n  defmodule GitSparseRepo do\n    def hello do\n      \"World\"\n    end\n  end\n  \"\"\")\n\n  File.cd!(target, fn ->\n    System.cmd(\"git\", ~w[add .])\n    System.cmd(\"git\", ~w[commit -m \"lib\"])\n    System.cmd(\"git\", ~w[tag with_module])\n  end)\nend\n\n### Deps on Git repo\ntarget = Path.expand(\"fixtures/deps_on_git_repo\", __DIR__)\n\nif not File.dir?(target) do\n  File.mkdir_p!(Path.join(target, \"lib\"))\n\n  File.write!(Path.join(target, \"mix.exs\"), \"\"\"\n  ## Auto-generated fixture\n  defmodule DepsOnGitRepo.MixProject do\n    use Mix.Project\n\n    def project do\n      [\n        app: :deps_on_git_repo,\n        version: \"0.1.0\",\n      ]\n    end\n  end\n  \"\"\")\n\n  File.cd!(target, fn ->\n    System.cmd(\"git\", ~w[init])\n    System.cmd(\"git\", ~w[add .])\n    System.cmd(\"git\", ~w[commit -m without-dep])\n    System.cmd(\"git\", ~w[checkout -q -b main])\n    System.cmd(\"git\", ~w[symbolic-ref HEAD refs/heads/main])\n  end)\n\n  File.write!(Path.join(target, \"mix.exs\"), \"\"\"\n  ## Auto-generated fixture\n  defmodule DepsOnGitRepo.MixProject do\n    use Mix.Project\n\n    def project do\n      [\n        app: :deps_on_git_repo,\n        version: \"0.2.0\",\n        deps: [\n          {:git_repo, git: MixTest.Case.fixture_path(\"git_repo\")}\n        ]\n      ]\n    end\n  end\n  \"\"\")\n\n  File.write!(Path.join(target, \"lib/deps_on_git_repo.ex\"), \"\"\"\n  ## Auto-generated fixture\n  GitRepo.hello()\n  \"\"\")\n\n  File.cd!(target, fn ->\n    System.cmd(\"git\", ~w[add .])\n    System.cmd(\"git\", ~w[commit -m with-dep])\n  end)\nend\n\n# Git Rebar\ntarget = Path.expand(\"fixtures/git_rebar\", __DIR__)\n\nif not File.dir?(target) do\n  File.mkdir_p!(Path.join(target, \"ebin\"))\n  File.mkdir_p!(Path.join(target, \"src\"))\n\n  # This is used to test that the built-in ebin is ignored.\n  File.write!(Path.join(target, \"ebin/.unused\"), \"\"\"\n  \"\"\")\n\n  File.write!(Path.join(target, \"src/git_rebar.app.src\"), \"\"\"\n  {application, git_rebar,\n    [\n      {vsn, \"0.1.0\"}\n    ]}.\n  \"\"\")\n\n  File.write!(Path.join(target, \"src/git_rebar.erl\"), \"\"\"\n  -module(git_rebar).\n  -export([any_function/0]).\n  any_function() -> ok.\n  \"\"\")\n\n  File.cd!(target, fn ->\n    System.cmd(\"git\", ~w[init])\n    System.cmd(\"git\", ~w[add .])\n    System.cmd(\"git\", ~w[commit -m \"ok\"])\n    System.cmd(\"git\", ~w[checkout -q -b main])\n    System.cmd(\"git\", ~w[symbolic-ref HEAD refs/heads/main])\n  end)\nend\n\nEnum.each([:invalidapp, :invalidvsn, :noappfile, :nosemver, :ok], fn dep ->\n  File.mkdir_p!(Path.expand(\"fixtures/deps_status/deps/#{dep}/.git\", __DIR__))\nend)\n\n### Archive ebin\ntarget = Path.expand(\"fixtures/archive\", __DIR__)\n\nif not File.dir?(Path.join(target, \"ebin\")) do\n  File.mkdir_p!(Path.join(target, \"ebin\"))\n\n  File.write!(Path.join([target, \"ebin\", \"local_sample.app\"]), \"\"\"\n  {application,local_sample,\n    [\n      {modules,['Elixir.Mix.Tasks.Local.Sample']},\n      {applications,[kernel,stdlib,elixir]}\n    ]\n  }.\n  \"\"\")\n\n  [{name, bin}] = Code.compile_file(\"lib/local.sample.ex\", target)\n\n  File.write!(Path.join([target, \"ebin\", Atom.to_string(name) <> \".beam\"]), bin)\nend\n\n## Generate helper modules\n\npath = MixTest.Case.tmp_path(\"beams\")\nFile.rm_rf!(path)\nFile.mkdir_p!(path)\n\nwrite_beam = fn {:module, name, bin, _} ->\n  path\n  |> Path.join(Atom.to_string(name) <> \".beam\")\n  |> File.write!(bin)\nend\n\ndefmodule Mix.Tasks.Hello do\n  use Mix.Task\n  @shortdoc \"This is short documentation, see\"\n\n  @moduledoc \"\"\"\n  A test task.\n  \"\"\"\n\n  def run([]) do\n    \"Hello, World!\"\n  end\n\n  def run([\"--parser\" | args]) do\n    OptionParser.parse!(args, strict: [int: :integer])\n  end\n\n  def run(args) do\n    \"Hello, #{Enum.join(args, \" \")}!\"\n  end\nend\n|> write_beam.()\n\ndefmodule Mix.Tasks.Invalid do\nend\n|> write_beam.()\n\ndefmodule Mix.Tasks.Acronym.HTTP do\n  use Mix.Task\n  def run(_), do: \"An HTTP Task\"\nend\n|> write_beam.()\n"
  },
  {
    "path": "man/common",
    "content": ".\\\" SPDX-License-Identifier: Apache-2.0\n.\\\" SPDX-FileCopyrightText: 2021 The Elixir Team\n.\\\" SPDX-FileCopyrightText: 2012 Plataformatec\n.It Fl h , -help\nDisplays the help message to the standard error (stderr) and exits.\n.It Fl v , -version\nDisplays the Elixir version to the standard output (stdout) and exits.\n.It Fl e , -eval Ar expression\nEvaluates the specified expression\n.Pq see the Fl -rpc-eval No option .\n.It Fl r Ar file\nRequires the specified file. In other words, the file is checked for existence at the start of\n.Nm .\n.It Fl S Ar script\nRuns the specified script.\n.It Fl pa Ar directory\nAdds the specified directory to the beginning of the code path. If the directory already exists, it will be removed from its old position and put to the beginning.\n.Pp\nSee also the function\n.Sy Code.prepend_path/1 .\n.It Fl pr Ar file\nDoes the same thing as\n.Fl r\n.Pq see above\nbut in parallel.\n.It Fl pz Ar directory\nAdds the specified directory to the end of the code path. If the directory already exists, it will be neither removed from its old position nor put to the end.\n.Pp\nSee also the function\n.Sy Code.append_path/1 .\n.It Fl -app Ar application\nStarts the specified application and all its dependencies.\n.It Fl -boot Ar file\nSpecifies the name of the boot file,\n.Ar file Ns .boot, which is used to start the system. Unless File contains an absolute path, the system searches for Ar file Ns .boot in the current and $ROOT/bin directories.\n.Pp\nDefaults to $ROOT/bin/start.boot.\n.Pp\nThe option is equivalent to Erlang's\n.Fl boot .\n.It Fl -boot-var Ar var Ar dir\nIf the boot script contains a path variable\n.Ar var\nother than $ROOT, this variable is expanded to\n.Ar dir .\nUsed when applications are installed in another directory than $ROOT/lib.\n.Pp\nThe option is equivalent to Erlang's\n.Fl boot_var .\n.Pp\nSee also the function\n.Sy :systools.make_script/1,2 No in SASL .\n.It Fl -erl Ar parameters\nServes the same purpose as ELIXIR_ERL_OPTIONS\n.Pq see the Sy ENVIRONMENT No section\n.It Fl -erl-config Ar file\nSpecifies the name of a configuration file,\n.Ar file Ns .config, which is used to configure applications. Note that the configuration file must be written in Erlang.\n.Pp\nThe option is equivalent to Erlang's\n.Fl config .\n.It Fl -cookie Ar value\nSpecifies the magic cookie value. If the value isn't specified via the option when the node starts, it will be taken from the file\n.Pa ~/.erlang.cookie\n.Pq see the Sy FILES No section .\nDistributed nodes can interact with each other only when their magic cookies are equal.\n.Pp\nSee also the function\n.Sy Node.set_cookie/2 .\n.It Fl -hidden\nStarts a hidden node.\n.Pp\nConnections between nodes are transitive. For example, if node A is connected to node B, and node B is connected to node C, then node A is connected to node C. The option\n.Fl -hidden\nallows creating a node which can be connected to another node, escaping redundant connections.\n.Pp\nThe function\n.Sy Node.list/0\nallows getting the list of nodes connected to the target node; however, the list won't include hidden nodes. Depending on the input parameter, the function\n.Sy Node.list/1\nallows getting the list which contains only hidden nodes\n.Pq the parameter Ar :hidden\nor both hidden and not hidden nodes\n.Pq the parameter Ar :connected .\n.It Fl -logger-otp-reports Ar val\nEnables or disables OTP reporting\n.Pq Ar val No can be either true or false .\n.It Fl -logger-sasl-reports Ar val\nEnables or disables SASL reporting\n.Pq Ar val No can be either true or false .\n.It Fl -sname Ar name\nGives a node a short name and starts it. Short names take the form of\n.Ar name Ns\n@host, where host is the name of the target host\n.Pq Xr hostname 1\nwhich runs the node. The nodes with short names can interact with each other only in the same local network.\n.It Fl -name Ar name\nGives a node a long name and starts it. Long names take the form of\n.Ar name Ns\n@host, where host is the IP address of the host which runs the node. In contrast to the nodes with short names, the nodes with long names aren't limited by boundaries of a local network\n.Pq see above .\n.It Fl -pipe-to Ar pipedir Ar logdir\nStarts the Erlang VM as a named\n.Ar pipedir\nand\n.Ar logdir\n.Pq only for Unix-like operating systems .\n.It Fl -rpc-eval Ar node Ar expression\nEvaluates the specified expression on the specified node\n.Pq see the Fl -eval No option .\n.It Fl -vm-args Ar file\nReads the command-line arguments from\n.Ar file\nand passes them to the Erlang VM.\n.Pp\nThe option is equivalent to Erlang's\n.Fl args_file .\n"
  },
  {
    "path": "man/elixir.1.in",
    "content": ".\\\" SPDX-License-Identifier: Apache-2.0\n.\\\" SPDX-FileCopyrightText: 2021 The Elixir Team\n.\\\" SPDX-FileCopyrightText: 2012 Plataformatec\n.Dd February 3, 2019\n.Dt ELIXIR 1\n.Os\n.Sh NAME\n.Nm elixir\n.Nd The Elixir script runner\n.Sh SYNOPSIS\n.Nm\n.Op Ar OPTIONS\n.Ar\n.Sh DESCRIPTION\nThe program starts the runtime system typically for the execution of one or more scripts. It is similar to\n.Xr iex 1 ,\nbut\n.Nm\nexits when the executed script does.\n.Sh OPTIONS\nNote that many of the options mentioned here were borrowed from the Erlang shell, therefore\n.Xr erl 1\ncan be used as an additional source of information on the options.\n.Bl -tag -width Ds\n{COMMON}\n.It Fl -no-halt\nDoes not halt the Erlang VM after execution.\n.It Fl -\nSeparates the options passed to the compiler from the options passed to the executed code.\n.El\n.Sh NOTES\nThe following options can be given more than once:\n.Fl -boot-var Ns , Fl -erl-config Ns , Fl -eval Ns , Fl -rpc-eval Ns .\n.Sh ENVIRONMENT\n.Bl -tag -width Ds\n.It Ev ELIXIR_ERL_OPTIONS\nAllows passing parameters to the Erlang runtime.\n.El\n.Sh FILES\n.Bl -tag -width Ds\n.It Pa ~/.erlang.cookie\nStores the magic cookie value which is used only when it wasn't specified via the option\n.Fl -cookie\n.Pq see above .\nIf the file doesn't exist when a node starts, it will be created.\n.El\n.Sh SEE ALSO\n.Xr elixirc 1 ,\n.Xr iex 1 ,\n.Xr mix 1\n.Sh AUTHOR\n.Bl -tag -width Ds\n.It Elixir is maintained by The Elixir Team.\n.It This manual page was contributed by Evgeny Golyshev.\n.It Copyright (c) 2012 Plataformatec.\n.It Copyright (c) 2021 The Elixir Team.\n.El\n.Sh INTERNET RESOURCES\n.Bl -tag -width Ds\n.It Main website: https://elixir-lang.org\n.It Documentation: https://elixir-lang.org/docs.html\n.It Package manager: https://hex.pm\n.El\n"
  },
  {
    "path": "man/elixirc.1",
    "content": ".\\\" SPDX-License-Identifier: Apache-2.0\n.\\\" SPDX-FileCopyrightText: 2021 The Elixir Team\n.\\\" SPDX-FileCopyrightText: 2012 Plataformatec\n.Dd April 10, 2015\n.Dt ELIXIRC 1\n.Os\n.Sh NAME\n.Nm elixirc\n.Nd The Elixir compiler\n.Sh SYNOPSIS\n.Nm\n.Op Ar OPTIONS\n.Ar\n.Sh DESCRIPTION\nThe compiler is intended for compilation one or more files containing the Elixir source code. The files should have the extension\n.Em .ex .\n.Sh OPTIONS\n.Bl -tag -width Ds\n.It Fl o Ar directory\nPlaces the output file in the specified directory. If the directory is not specified via the option, the current working directory will be used for the purpose.\n.It Fl -erl Ar parameters\nServes the same purpose as ELIXIR_ERL_OPTIONS\n.Pq see the Sy ENVIRONMENT No section .\n.It Fl -ignore-module-conflict\nDisables warnings when a module was previously defined.\n.It Fl -no-debug-info\nDisables producing debugging information.\n.It Fl -no-docs\nDisables generating documentation.\n.It Fl -warnings-as-errors\nMakes all warnings into errors.\n.It Fl -verbose\nActivates verbose mode.\n.It Fl -\nSeparates the options passed to the compiler from the options passed to the executed code.\n.El\n.Sh ENVIRONMENT\n.Bl -tag -width Ds\n.It Ev ELIXIR_ERL_OPTIONS\nAllows passing parameters to the Erlang runtime.\n.It Ev ERL_COMPILER_OPTIONS\nAllows passing parameters to the Erlang compiler\n.Pq see Xr erlc 1 .\n.El\n.Sh SEE ALSO\n.Xr elixir 1 ,\n.Xr iex 1 ,\n.Xr mix 1\n.Sh AUTHOR\n.Bl -tag -width Ds\n.It Elixir is maintained by The Elixir Team.\n.It This manual page was contributed by Evgeny Golyshev.\n.It Copyright (c) 2012 Plataformatec.\n.It Copyright (c) 2021 The Elixir Team.\n.El\n.Sh INTERNET RESOURCES\n.Bl -tag -width Ds\n.It Main website: https://elixir-lang.org\n.It Documentation: https://elixir-lang.org/docs.html\n.El\n"
  },
  {
    "path": "man/iex.1.in",
    "content": ".\\\" SPDX-License-Identifier: Apache-2.0\n.\\\" SPDX-FileCopyrightText: 2021 The Elixir Team\n.\\\" SPDX-FileCopyrightText: 2012 Plataformatec\n.Dd February 3, 2019\n.Dt IEX 1\n.Os\n.Sh NAME\n.Nm iex\n.Nd The Elixir shell\n.Sh SYNOPSIS\n.Nm\n.Op Ar OPTIONS\n.Sh DESCRIPTION\nThe interactive shell is used for evaluation, debugging and introspection of the Elixir runtime system. It is also possible to use the program for testing the work of small pieces of code escaping the stage of saving the code in a file.\n.Sh OPTIONS\nNote that many of the options mentioned here were borrowed from the Erlang shell, therefore\n.Xr erl 1\ncan be used as an additional source of information on the options.\n.Bl -tag -width Ds\n{COMMON}\n.It Fl -dot-iex Ar file\nLoads the specified file instead of\n.Pa .iex.exs\n.Pq see the Sy FILES No section .\n.It Fl -remsh Ar node\nConnects to the specified node which was started with the\n.Fl -sname\nor\n.Fl -name\noptions\n.Pq see above .\n.It Fl -\nSeparates the options passed to the compiler from the options passed to the executed code.\n.El\n.Sh NOTES\nThe following options can be given more than once:\n.Fl -boot-var Ns , Fl -erl-config Ns , Fl -eval Ns , Fl -rpc-eval Ns .\n.Sh ENVIRONMENT\n.Bl -tag -width Ds\n.It Ev ELIXIR_ERL_OPTIONS\nAllows passing parameters to the Erlang runtime.\n.El\n.Sh FILES\n.Bl -tag -width Ds\n.It Pa ~/.erlang.cookie\nStores the magic cookie value which is used only when it wasn't specified via the option\n.Fl -cookie\n.Pq see above .\nIf the file doesn't exist when a node starts, it will be created.\n.It Pa .iex.exs\nAfter\n.Nm\nstarts, it seeks the file\n.Pa .iex.exs\nand, in a case of success, executes the code from the file in the context of the shell. At first the search starts in the current working directory; then, if necessary, it continues in the home directory.\n.El\n.Sh SEE ALSO\n.Xr elixir 1 ,\n.Xr elixirc 1 ,\n.Xr mix 1\n.Sh AUTHOR\n.Bl -tag -width Ds\n.It Elixir is maintained by The Elixir Team.\n.It This manual page was contributed by Evgeny Golyshev.\n.It Copyright (c) 2012 Plataformatec.\n.It Copyright (c) 2021 The Elixir Team.\n.El\n.Sh INTERNET RESOURCES\n.Bl -tag -width Ds\n.It Main website: https://elixir-lang.org\n.It Documentation: https://elixir-lang.org/docs.html\n.El\n"
  },
  {
    "path": "man/mix.1",
    "content": ".\\\" SPDX-License-Identifier: Apache-2.0\n.\\\" SPDX-FileCopyrightText: 2021 The Elixir Team\n.\\\" SPDX-FileCopyrightText: 2012 Plataformatec\n.Dd May 27, 2015\n.Dt MIX 1\n.Os\n.Sh NAME\n.Nm mix\n.Nd The software project management tool\n.Sh SYNOPSIS\n.Nm\n.Op Ar TASK\n.Op Ar project_name\n.Nm elixir\n.Op Ar OPTIONS\n.Fl S Nm\n.Op Ar TASK\n.Op Ar project_name\n.Sh DESCRIPTION\n.Nm\nis intended for both organizing code into projects and their maintenance. For the latter the tool offers some advanced features like dependency management, packaging, preparing documentation, testing and so on.\n.Pp\nHave a look at the\n.Sy SYNOPSIS\nsection and the second way of running\n.Nm\nit offers. The point is that the tool is none other than the Elixir script, therefore it can be invoked via\n.Xr elixir 1\nin the same way as any other script. It's useful when you want to run\n.Nm\nwith particular options.\n.Sh DEFINITIONS\nAll the\n.Nm\nfunctionality is represented by a set of tasks. A\n.Em task\nis a piece of code written in Elixir and intended for solving a particular problem. Like programs, many tasks accept input parameters and/or support options which slightly modify their behavior, but others do not. There are two types of tasks: those that are available after installation this or that archive\n.Pq local tasks\nand those that are offered by\n.Nm\n.Pq built-in tasks .\nThe\n.Sy run\ntask will be executed by default if none other has been specified.\n.Pp\nIn spite of the fact that the greater part of\n.Nm\nis tasks, the man page doesn't contain the help information related to each of them because\n.Nm\nis self-descriptive. Thus, using the\n.Sy help\ntask, you can get both the full list of local/built-in tasks and the information related to a particular task.\n.Pp\nAn\n.Em archive ,\nin terms of Erlang/OTP, is the ZIP file with the\n.Em .ez\nextension which contains a precompiled OTP application with all its dependencies\\~[1].\n.Pp\nAn\n.Em application\nis an entity that helps to combine sets of components into a single unit to simplify their reusing in other systems\\~[2].\n.Sh ENVIRONMENT\n.Bl -tag -width Ds\n.It Ev MIX_ARCHIVES\nAllows specifying the directory into which the archives should be installed\n.Pq see Sy mix help archive.install .\nThe\n.Em ~/.mix/archives\ndirectory is used for this purpose by default.\n.It Ev MIX_DEBUG\nWhen set, outputs debug information about each task before running it.\n.It Ev MIX_ENV\nAllows specifying which environment should be used. The\n.Em dev\nenvironment is used by default if none other has been specified.\n.Pp\nSometimes you have to use a particular set of configuration parameter values or perform particular steps when you compile or run a project\n.Pq or in some other cases .\nThe\n.Nm\nenvironments allow grouping values of configuration parameters and steps to switch between them by specifying the necessary environment via MIX_ENV.\n.It Ev MIX_TARGET\nAllows specifying which target should be used. The\n.Em host\ntarget is used by default if none other has been specified.\n.It Ev MIX_EXS\nAllows changing the full path to the\n.Em mix.exs\nfile\n.Pq see Sy FILES No section .\nThe most obvious use case is to have more than one copy of\n.Em mix.exs\nin a project, but it's worth noting that MIX_EXS should be used only if the\n.Nm\nenvironments\n.Pq see above\nare not enough to solve the problem.\n.It Ev MIX_HOME\npath to Mix's home directory, stores configuration files and scripts used by Mix\n.It MIX_INSTALL_DIR\nSpecifies directory where Mix.install/2 keeps installs cache\n.It MIX_INSTALL_FORCE\nRuns Mix.install/2 with empty install cache\n.It Ev MIX_PATH\nAllows expanding the code path. If the MIX_PATH environment variable has a value which consists of multiple paths, they must be colon-separated\n.Pq for Unix-like operating systems\nor semicolon-separated\n.Pq for Windows .\n.Pp\nAs mentioned above, there are two types of tasks: local and built-in. These tasks are always visible for\n.Nm\nbecause the directories, in which they are located, are a part of code path. If a task belongs to neither the one type nor the other, MIX_PATH helps you say to\n.Nm\nwhere it should search the task.\n.It Ev MIX_QUIET\nWhen set, does not print information messages to the terminal.\n.El\n.Sh FILES\n.Bl -tag -width Ds\n.It mix.exs\nContains the most significant information related to the project, such as its name, version, list of dependencies and so on. As a rule, the file is named\n.Em mix.exs\nand located at the top of the project's source tree, but you can change the full path to it using the MIX_EXS environment variable\n.Pq see the Sy ENVIRONMENT No section .\n.It mix.lock\nAllows locking down the project dependencies with a proper version range before performing any updates. It is useful when you know that your project is incompatible with newer versions of certain dependencies. The file is located at the top of the project's source tree as well as\n.Em mix.exs\n.Pq see above .\n.El\n.Sh REFERENCES\n.Bl -tag -width Ds\n.It [1] https://www.erlang.org/doc/man/code.html#id103620\n.It [2] https://www.erlang.org/doc/design_principles/applications.html\n.El\n.Sh SEE ALSO\n.Xr elixir 1 ,\n.Xr elixirc 1 ,\n.Xr iex 1\n.Sh AUTHOR\n.Bl -tag -width Ds\n.It Elixir is maintained by The Elixir Team.\n.It This manual page was contributed by Evgeny Golyshev.\n.It Copyright (c) 2012 Plataformatec.\n.It Copyright (c) 2021 The Elixir Team.\n.El\n.Sh INTERNET RESOURCES\n.Bl -tag -width Ds\n.It Main website: https://elixir-lang.org\n.It Documentation: https://elixir-lang.org/docs.html\n.It Package manager: https://hex.pm\n.El\n"
  },
  {
    "path": "project.spdx.yml",
    "content": "SPDXID: \"SPDXRef-DOCUMENT\"\nspdxVersion: \"SPDX-2.2\"\ncreationInfo:\n  created: \"2025-02-05T12:29:35Z\"\n  creators:\n  - \"Organization: The Elixir Team\"\n  licenseListVersion: \"3.9\"\nname: \"elixir\"\ndataLicense: \"CC0-1.0\"\ndocumentNamespace: \"https://github.com/elixir-lang/elixir\"\ndocumentDescribes:\n- \"SPDXRef-Project-elixir-lang\"\npackages:\n- SPDXID: \"SPDXRef-Project-elixir-lang\"\n  summary: \"Elixir is a dynamic, functional language for building scalable and maintainable applications\"\n  copyrightText: \"Copyright (c) 2012 Plataformatec. Copyright (c) 2021 The Elixir Team. All Rights Reserved.\"\n  downloadLocation: \"git+https://github.com/elixir-lang/elixir.git\"\n  filesAnalyzed: false\n  homepage: \"https://elixir-lang.org/\"\n  licenseConcluded: \"Apache-2.0 AND LicenseRef-scancode-unicode AND LicenseRef-elixir-trademark-policy\"\n  licenseDeclared: \"Apache-2.0 AND LicenseRef-scancode-unicode AND LicenseRef-elixir-trademark-policy\"\n  name: \"elixir-lang\"\n  originator: \"Organization: The Elixir Team\"\n  supplier: \"Organization: The Elixir Team\"\n  packageFileName: \".\"\n  externalRefs:\n    - referenceCategory: PACKAGE-MANAGER\n      referenceType: \"purl\"\n      referenceLocator: \"pkg:github/elixir-lang/elixir\"\n      comment: \"GitHub PURL\"\n  # elixir-version-insert\n- SPDXID: \"SPDXRef-Package-eex\"\n  summary: \"Elixir is a dynamic, functional language for building scalable and maintainable applications\"\n  copyrightText: \"Copyright (c) 2012 Plataformatec. Copyright (c) 2021 The Elixir Team. All Rights Reserved.\"\n  downloadLocation: \"git+https://github.com/elixir-lang/elixir.git#lib/eex\"\n  filesAnalyzed: false\n  homepage: \"https://elixir-lang.org/\"\n  licenseConcluded: \"Apache-2.0\"\n  licenseDeclared: \"Apache-2.0\"\n  name: \"eex\"\n  originator: \"Organization: The Elixir Team\"\n  supplier: \"Organization: The Elixir Team\"\n  packageFileName: \"./lib/eex\"\n  externalRefs:\n    - referenceCategory: PACKAGE-MANAGER\n      referenceType: \"purl\"\n      referenceLocator: \"pkg:otp/eex\"\n      comment: \"OTP PURL\"\n  # elixir-version-insert\n- SPDXID: \"SPDXRef-Package-elixir\"\n  summary: \"Elixir is a dynamic, functional language for building scalable and maintainable applications\"\n  copyrightText: \"Copyright (c) 2012 Plataformatec. Copyright (c) 2021 The Elixir Team. All Rights Reserved.\"\n  downloadLocation: \"git+https://github.com/elixir-lang/elixir.git#lib/elixir\"\n  filesAnalyzed: false\n  homepage: \"https://elixir-lang.org/\"\n  licenseConcluded: \"Apache-2.0 AND LicenseRef-scancode-unicode\"\n  licenseDeclared: \"Apache-2.0 AND LicenseRef-scancode-unicode\"\n  name: \"elixir\"\n  originator: \"Organization: The Elixir Team\"\n  supplier: \"Organization: The Elixir Team\"\n  packageFileName: \"./lib/elixir\"\n  externalRefs:\n    - referenceCategory: PACKAGE-MANAGER\n      referenceType: \"purl\"\n      referenceLocator: \"pkg:otp/elixir\"\n      comment: \"OTP PURL\"\n  # elixir-version-insert\n- SPDXID: \"SPDXRef-Package-exunit\"\n  summary: \"Elixir is a dynamic, functional language for building scalable and maintainable applications\"\n  copyrightText: \"Copyright (c) 2012 Plataformatec. Copyright (c) 2021 The Elixir Team. All Rights Reserved.\"\n  downloadLocation: \"git+https://github.com/elixir-lang/elixir.git#lib/ex_unit\"\n  filesAnalyzed: false\n  homepage: \"https://elixir-lang.org/\"\n  licenseConcluded: \"Apache-2.0\"\n  licenseDeclared: \"Apache-2.0\"\n  name: \"exunit\"\n  originator: \"Organization: The Elixir Team\"\n  supplier: \"Organization: The Elixir Team\"\n  packageFileName: \"./lib/ex_unit\"\n  externalRefs:\n    - referenceCategory: PACKAGE-MANAGER\n      referenceType: \"purl\"\n      referenceLocator: \"pkg:otp/ex_unit\"\n      comment: \"OTP PURL\"\n  # elixir-version-insert\n- SPDXID: \"SPDXRef-Package-iex\"\n  summary: \"Elixir is a dynamic, functional language for building scalable and maintainable applications\"\n  copyrightText: \"Copyright (c) 2012 Plataformatec. Copyright (c) 2021 The Elixir Team. All Rights Reserved.\"\n  downloadLocation: \"git+https://github.com/elixir-lang/elixir.git#lib/iex\"\n  filesAnalyzed: false\n  homepage: \"https://elixir-lang.org/\"\n  licenseConcluded: \"Apache-2.0\"\n  licenseDeclared: \"Apache-2.0\"\n  name: \"iex\"\n  originator: \"Organization: The Elixir Team\"\n  supplier: \"Organization: The Elixir Team\"\n  packageFileName: \"./lib/iex\"\n  externalRefs:\n    - referenceCategory: PACKAGE-MANAGER\n      referenceType: \"purl\"\n      referenceLocator: \"pkg:otp/iex\"\n      comment: \"OTP PURL\"\n  # elixir-version-insert\n- SPDXID: \"SPDXRef-Package-logger\"\n  summary: \"Elixir is a dynamic, functional language for building scalable and maintainable applications\"\n  copyrightText: \"Copyright (c) 2012 Plataformatec. Copyright (c) 2021 The Elixir Team. All Rights Reserved.\"\n  downloadLocation: \"git+https://github.com/elixir-lang/elixir.git/lib/logger\"\n  filesAnalyzed: false\n  homepage: \"https://elixir-lang.org/\"\n  licenseConcluded: \"Apache-2.0\"\n  licenseDeclared: \"Apache-2.0\"\n  name: \"logger\"\n  originator: \"Organization: The Elixir Team\"\n  supplier: \"Organization: The Elixir Team\"\n  packageFileName: \"./lib/logger\"\n  externalRefs:\n    - referenceCategory: PACKAGE-MANAGER\n      referenceType: \"purl\"\n      referenceLocator: \"pkg:otp/logger\"\n      comment: \"OTP PURL\"\n  # elixir-version-insert\n- SPDXID: \"SPDXRef-Package-mix\"\n  summary: \"Elixir is a dynamic, functional language for building scalable and maintainable applications\"\n  copyrightText: \"Copyright (c) 2012 Plataformatec. Copyright (c) 2021 The Elixir Team. All Rights Reserved.\"\n  downloadLocation: \"git+https://github.com/elixir-lang/elixir.git#lib/mix\"\n  filesAnalyzed: false\n  homepage: \"https://elixir-lang.org/\"\n  licenseConcluded: \"Apache-2.0\"\n  licenseDeclared: \"Apache-2.0\"\n  name: \"mix\"\n  originator: \"Organization: The Elixir Team\"\n  supplier: \"Organization: The Elixir Team\"\n  packageFileName: \"./lib/mix\"\n  externalRefs:\n    - referenceCategory: PACKAGE-MANAGER\n      referenceType: \"purl\"\n      referenceLocator: \"pkg:otp/mix\"\n      comment: \"OTP PURL\"\n  # elixir-version-insert\n- SPDXID: \"SPDXRef-Project-erlang\"\n  description: \"Erlang is a programming language and runtime system for building massively scalable soft real-time systems with requirements on high availability.\"\n  copyrightText: \"Copyright Ericsson AB 2010-2024. All Rights Reserved.\"\n  downloadLocation: \"git+https://github.com/erlang/otp.git\"\n  filesAnalyzed: false\n  homepage: \"https://www.erlang.org/\"\n  licenseConcluded: \"Apache-2.0\"\n  licenseDeclared: \"Apache-2.0\"\n  name: \"erlang\"\n  originator: \"Organization: Ericsson AB\"\n  supplier: \"Organization: Ericsson AB\"\n  externalRefs:\n    - referenceCategory: PACKAGE-MANAGER\n      referenceType: \"purl\"\n      referenceLocator: \"pkg:github/erlang/otp\"\n      comment: \"GitHub PURL\"\nrelationships:\n- spdxElementId: \"SPDXRef-Project-elixir-lang\"\n  relatedSpdxElement: \"SPDXRef-Package-eex\"\n  relationshipType: \"STATIC_LINK\" # Should be CONTAINS, issue with ORT\n- spdxElementId: \"SPDXRef-Project-elixir-lang\"\n  relatedSpdxElement: \"SPDXRef-Package-elixir\"\n  relationshipType: \"STATIC_LINK\" # Should be CONTAINS, issue with ORT\n- spdxElementId: \"SPDXRef-Project-elixir-lang\"\n  relatedSpdxElement: \"SPDXRef-Package-exunit\"\n  relationshipType: \"STATIC_LINK\" # Should be CONTAINS, issue with ORT\n- spdxElementId: \"SPDXRef-Project-elixir-lang\"\n  relatedSpdxElement: \"SPDXRef-Package-iex\"\n  relationshipType: \"STATIC_LINK\" # Should be CONTAINS, issue with ORT\n- spdxElementId: \"SPDXRef-Project-elixir-lang\"\n  relatedSpdxElement: \"SPDXRef-Package-logger\"\n  relationshipType: \"STATIC_LINK\" # Should be CONTAINS, issue with ORT\n- spdxElementId: \"SPDXRef-Project-elixir-lang\"\n  relatedSpdxElement: \"SPDXRef-Package-mix\"\n  relationshipType: \"STATIC_LINK\" # Should be CONTAINS, issue with ORT\n- spdxElementId: \"SPDXRef-Package-elixir\"\n  relatedSpdxElement: \"SPDXRef-Project-erlang\"\n  relationshipType: \"RUNTIME_DEPENDENCY_OF\"\n- spdxElementId: \"SPDXRef-Package-eex\"\n  relatedSpdxElement: \"SPDXRef-Package-elixir\"\n  relationshipType: \"STATIC_LINK\"\n- spdxElementId: \"SPDXRef-Package-exunit\"\n  relatedSpdxElement: \"SPDXRef-Package-elixir\"\n  relationshipType: \"STATIC_LINK\"\n- spdxElementId: \"SPDXRef-Package-iex\"\n  relatedSpdxElement: \"SPDXRef-Package-elixir\"\n  relationshipType: \"STATIC_LINK\"\n- spdxElementId: \"SPDXRef-Package-logger\"\n  relatedSpdxElement: \"SPDXRef-Package-elixir\"\n  relationshipType: \"STATIC_LINK\"\n- spdxElementId: \"SPDXRef-Package-mix\"\n  relatedSpdxElement: \"SPDXRef-Package-elixir\"\n  relationshipType: \"STATIC_LINK\"\n"
  }
]